aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig8
-rw-r--r--drivers/Makefile6
-rw-r--r--drivers/acorn/char/defkeymap-l7200.c2
-rw-r--r--drivers/acpi/Kconfig18
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/ac.c73
-rw-r--r--drivers/acpi/battery.c1060
-rw-r--r--drivers/acpi/bus.c37
-rw-r--r--drivers/acpi/button.c43
-rw-r--r--drivers/acpi/ec.c260
-rw-r--r--drivers/acpi/events/evevent.c6
-rw-r--r--drivers/acpi/fan.c72
-rw-r--r--drivers/acpi/hardware/hwregs.c89
-rw-r--r--drivers/acpi/hardware/hwsleep.c40
-rw-r--r--drivers/acpi/osl.c2
-rw-r--r--drivers/acpi/power.c63
-rw-r--r--drivers/acpi/processor_core.c8
-rw-r--r--drivers/acpi/processor_idle.c14
-rw-r--r--drivers/acpi/sbs.c1870
-rw-r--r--drivers/acpi/sbshc.c309
-rw-r--r--drivers/acpi/sbshc.h27
-rw-r--r--drivers/acpi/scan.c16
-rw-r--r--drivers/acpi/sleep/main.c50
-rw-r--r--drivers/acpi/sleep/proc.c66
-rw-r--r--drivers/acpi/sleep/sleep.h1
-rw-r--r--drivers/acpi/sleep/wakeup.c117
-rw-r--r--drivers/acpi/tables/tbutils.c2
-rw-r--r--drivers/acpi/thermal.c36
-rw-r--r--drivers/acpi/toshiba_acpi.c5
-rw-r--r--drivers/acpi/video.c34
-rw-r--r--drivers/amba/bus.c9
-rw-r--r--drivers/ata/Kconfig70
-rw-r--r--drivers/ata/Makefile10
-rw-r--r--drivers/ata/ahci.c783
-rw-r--r--drivers/ata/ata_generic.c16
-rw-r--r--drivers/ata/ata_piix.c149
-rw-r--r--drivers/ata/libata-acpi.c177
-rw-r--r--drivers/ata/libata-core.c1874
-rw-r--r--drivers/ata/libata-eh.c1055
-rw-r--r--drivers/ata/libata-pmp.c1191
-rw-r--r--drivers/ata/libata-scsi.c755
-rw-r--r--drivers/ata/libata-sff.c75
-rw-r--r--drivers/ata/libata.h43
-rw-r--r--drivers/ata/pata_acpi.c397
-rw-r--r--drivers/ata/pata_ali.c19
-rw-r--r--drivers/ata/pata_amd.c43
-rw-r--r--drivers/ata/pata_artop.c20
-rw-r--r--drivers/ata/pata_at32.c441
-rw-r--r--drivers/ata/pata_atiixp.c15
-rw-r--r--drivers/ata/pata_bf54x.c1624
-rw-r--r--drivers/ata/pata_cmd640.c4
-rw-r--r--drivers/ata/pata_cmd64x.c45
-rw-r--r--drivers/ata/pata_cs5520.c47
-rw-r--r--drivers/ata/pata_cs5530.c8
-rw-r--r--drivers/ata/pata_cs5535.c6
-rw-r--r--drivers/ata/pata_cs5536.c344
-rw-r--r--drivers/ata/pata_cypress.c4
-rw-r--r--drivers/ata/pata_efar.c11
-rw-r--r--drivers/ata/pata_hpt366.c4
-rw-r--r--drivers/ata/pata_hpt37x.c77
-rw-r--r--drivers/ata/pata_hpt3x2n.c11
-rw-r--r--drivers/ata/pata_hpt3x3.c10
-rw-r--r--drivers/ata/pata_icside.c73
-rw-r--r--drivers/ata/pata_isapnp.c8
-rw-r--r--drivers/ata/pata_it8213.c11
-rw-r--r--drivers/ata/pata_it821x.c21
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c24
-rw-r--r--drivers/ata/pata_jmicron.c24
-rw-r--r--drivers/ata/pata_legacy.c27
-rw-r--r--drivers/ata/pata_marvell.c12
-rw-r--r--drivers/ata/pata_mpc52xx.c10
-rw-r--r--drivers/ata/pata_mpiix.c27
-rw-r--r--drivers/ata/pata_netcell.c5
-rw-r--r--drivers/ata/pata_ns87410.c13
-rw-r--r--drivers/ata/pata_ns87415.c469
-rw-r--r--drivers/ata/pata_oldpiix.c13
-rw-r--r--drivers/ata/pata_opti.c11
-rw-r--r--drivers/ata/pata_optidma.c28
-rw-r--r--drivers/ata/pata_pcmcia.c30
-rw-r--r--drivers/ata/pata_pdc2027x.c116
-rw-r--r--drivers/ata/pata_pdc202xx_old.c27
-rw-r--r--drivers/ata/pata_platform.c51
-rw-r--r--drivers/ata/pata_qdi.c15
-rw-r--r--drivers/ata/pata_radisys.c6
-rw-r--r--drivers/ata/pata_rz1000.c13
-rw-r--r--drivers/ata/pata_sc1200.c6
-rw-r--r--drivers/ata/pata_scc.c79
-rw-r--r--drivers/ata/pata_serverworks.c19
-rw-r--r--drivers/ata/pata_sil680.c74
-rw-r--r--drivers/ata/pata_sis.c33
-rw-r--r--drivers/ata/pata_sl82c105.c11
-rw-r--r--drivers/ata/pata_triflex.c11
-rw-r--r--drivers/ata/pata_via.c22
-rw-r--r--drivers/ata/pata_winbond.c15
-rw-r--r--drivers/ata/pdc_adma.c124
-rw-r--r--drivers/ata/sata_fsl.c1395
-rw-r--r--drivers/ata/sata_inic162x.c38
-rw-r--r--drivers/ata/sata_mv.c117
-rw-r--r--drivers/ata/sata_nv.c1070
-rw-r--r--drivers/ata/sata_promise.c169
-rw-r--r--drivers/ata/sata_qstor.c134
-rw-r--r--drivers/ata/sata_sil.c64
-rw-r--r--drivers/ata/sata_sil24.c367
-rw-r--r--drivers/ata/sata_sis.c79
-rw-r--r--drivers/ata/sata_svw.c24
-rw-r--r--drivers/ata/sata_sx4.c206
-rw-r--r--drivers/ata/sata_uli.c34
-rw-r--r--drivers/ata/sata_via.c57
-rw-r--r--drivers/ata/sata_vsc.c31
-rw-r--r--drivers/atm/Makefile2
-rw-r--r--drivers/atm/ambassador.h2
-rw-r--r--drivers/atm/firestream.c4
-rw-r--r--drivers/atm/horizon.c5
-rw-r--r--drivers/atm/horizon.h2
-rw-r--r--drivers/atm/idt77252.c2
-rw-r--r--drivers/base/Kconfig8
-rw-r--r--drivers/base/base.h2
-rw-r--r--drivers/base/bus.c116
-rw-r--r--drivers/base/class.c60
-rw-r--r--drivers/base/core.c114
-rw-r--r--drivers/base/dmapool.c5
-rw-r--r--drivers/base/firmware_class.c14
-rw-r--r--drivers/base/memory.c18
-rw-r--r--drivers/base/node.c91
-rw-r--r--drivers/base/platform.c26
-rw-r--r--drivers/base/power/Makefile2
-rw-r--r--drivers/base/power/main.c344
-rw-r--r--drivers/base/power/power.h38
-rw-r--r--drivers/base/power/resume.c149
-rw-r--r--drivers/base/power/suspend.c210
-rw-r--r--drivers/base/power/trace.c2
-rw-r--r--drivers/base/sys.c73
-rw-r--r--drivers/base/topology.c11
-rw-r--r--drivers/block/DAC960.c3
-rw-r--r--drivers/block/Kconfig28
-rw-r--r--drivers/block/Makefile2
-rw-r--r--drivers/block/aoe/aoe.h9
-rw-r--r--drivers/block/aoe/aoeblk.c4
-rw-r--r--drivers/block/aoe/aoecmd.c19
-rw-r--r--drivers/block/aoe/aoedev.c4
-rw-r--r--drivers/block/aoe/aoenet.c6
-rw-r--r--drivers/block/cciss.c168
-rw-r--r--drivers/block/cciss_scsi.c14
-rw-r--r--drivers/block/cciss_scsi.h14
-rw-r--r--drivers/block/cpqarray.c9
-rw-r--r--drivers/block/cryptoloop.c17
-rw-r--r--drivers/block/floppy.c254
-rw-r--r--drivers/block/lguest_blk.c423
-rw-r--r--drivers/block/loop.c81
-rw-r--r--drivers/block/nbd.c173
-rw-r--r--drivers/block/paride/pf.c25
-rw-r--r--drivers/block/paride/pt.c2
-rw-r--r--drivers/block/pktcdvd.c41
-rw-r--r--drivers/block/ps3disk.c63
-rw-r--r--drivers/block/rd.c46
-rw-r--r--drivers/block/sunvdc.c2
-rw-r--r--drivers/block/sx8.c2
-rw-r--r--drivers/block/ub.c18
-rw-r--r--drivers/block/umem.c238
-rw-r--r--drivers/block/umem.h133
-rw-r--r--drivers/block/viodasd.c79
-rw-r--r--drivers/block/virtio_blk.c310
-rw-r--r--drivers/block/xen-blkfront.c32
-rw-r--r--drivers/block/xsysace.c278
-rw-r--r--drivers/bluetooth/Kconfig35
-rw-r--r--drivers/bluetooth/Makefile4
-rw-r--r--drivers/bluetooth/bluecard_cs.c5
-rw-r--r--drivers/bluetooth/bpa10x.c624
-rw-r--r--drivers/bluetooth/bt3c_cs.c5
-rw-r--r--drivers/bluetooth/btsdio.c406
-rw-r--r--drivers/bluetooth/btuart_cs.c5
-rw-r--r--drivers/bluetooth/btusb.c564
-rw-r--r--drivers/bluetooth/dtl1_cs.c5
-rw-r--r--drivers/bluetooth/hci_bcsp.c3
-rw-r--r--drivers/bluetooth/hci_ldisc.c8
-rw-r--r--drivers/bluetooth/hci_ll.c531
-rw-r--r--drivers/bluetooth/hci_uart.h8
-rw-r--r--drivers/cdrom/cdrom.c48
-rw-r--r--drivers/cdrom/viocd.c131
-rw-r--r--drivers/char/Kconfig14
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/agp/Kconfig6
-rw-r--r--drivers/char/agp/agp.h7
-rw-r--r--drivers/char/agp/ali-agp.c27
-rw-r--r--drivers/char/agp/amd-k7-agp.c9
-rw-r--r--drivers/char/agp/amd64-agp.c2
-rw-r--r--drivers/char/agp/backend.c12
-rw-r--r--drivers/char/agp/efficeon-agp.c11
-rw-r--r--drivers/char/agp/generic.c19
-rw-r--r--drivers/char/agp/hp-agp.c9
-rw-r--r--drivers/char/agp/i460-agp.c9
-rw-r--r--drivers/char/agp/intel-agp.c6
-rw-r--r--drivers/char/agp/parisc-agp.c7
-rw-r--r--drivers/char/apm-emulation.c2
-rw-r--r--drivers/char/consolemap.c25
-rw-r--r--drivers/char/cyclades.c771
-rw-r--r--drivers/char/defkeymap.c_shipped2
-rw-r--r--drivers/char/drm/Kconfig2
-rw-r--r--drivers/char/drm/drm.h20
-rw-r--r--drivers/char/drm/drmP.h239
-rw-r--r--drivers/char/drm/drm_agpsupport.c130
-rw-r--r--drivers/char/drm/drm_auth.c48
-rw-r--r--drivers/char/drm/drm_bufs.c205
-rw-r--r--drivers/char/drm/drm_context.c177
-rw-r--r--drivers/char/drm/drm_dma.c11
-rw-r--r--drivers/char/drm/drm_drawable.c67
-rw-r--r--drivers/char/drm/drm_drv.c188
-rw-r--r--drivers/char/drm/drm_fops.c39
-rw-r--r--drivers/char/drm/drm_hashtab.c2
-rw-r--r--drivers/char/drm/drm_hashtab.h2
-rw-r--r--drivers/char/drm/drm_ioc32.c2
-rw-r--r--drivers/char/drm/drm_ioctl.c196
-rw-r--r--drivers/char/drm/drm_irq.c98
-rw-r--r--drivers/char/drm/drm_lock.c75
-rw-r--r--drivers/char/drm/drm_mm.c2
-rw-r--r--drivers/char/drm/drm_os_linux.h20
-rw-r--r--drivers/char/drm/drm_pci.c4
-rw-r--r--drivers/char/drm/drm_pciids.h2
-rw-r--r--drivers/char/drm/drm_sarea.h2
-rw-r--r--drivers/char/drm/drm_scatter.c48
-rw-r--r--drivers/char/drm/drm_sman.c2
-rw-r--r--drivers/char/drm/drm_sman.h2
-rw-r--r--drivers/char/drm/drm_vm.c4
-rw-r--r--drivers/char/drm/i810_dma.c312
-rw-r--r--drivers/char/drm/i810_drm.h5
-rw-r--r--drivers/char/drm/i810_drv.h9
-rw-r--r--drivers/char/drm/i830_dma.c210
-rw-r--r--drivers/char/drm/i830_drv.h15
-rw-r--r--drivers/char/drm/i830_irq.c30
-rw-r--r--drivers/char/drm/i915_dma.c214
-rw-r--r--drivers/char/drm/i915_drv.h36
-rw-r--r--drivers/char/drm/i915_irq.c128
-rw-r--r--drivers/char/drm/i915_mem.c125
-rw-r--r--drivers/char/drm/mga_dma.c140
-rw-r--r--drivers/char/drm/mga_drv.h21
-rw-r--r--drivers/char/drm/mga_state.c197
-rw-r--r--drivers/char/drm/mga_warp.c8
-rw-r--r--drivers/char/drm/r128_cce.c138
-rw-r--r--drivers/char/drm/r128_drm.h18
-rw-r--r--drivers/char/drm/r128_drv.h25
-rw-r--r--drivers/char/drm/r128_state.c351
-rw-r--r--drivers/char/drm/r300_cmdbuf.c68
-rw-r--r--drivers/char/drm/radeon_cp.c151
-rw-r--r--drivers/char/drm/radeon_drv.h44
-rw-r--r--drivers/char/drm/radeon_irq.c40
-rw-r--r--drivers/char/drm/radeon_mem.c108
-rw-r--r--drivers/char/drm/radeon_state.c685
-rw-r--r--drivers/char/drm/savage_bci.c148
-rw-r--r--drivers/char/drm/savage_drv.h9
-rw-r--r--drivers/char/drm/savage_state.c200
-rw-r--r--drivers/char/drm/sis_drv.c2
-rw-r--r--drivers/char/drm/sis_drv.h5
-rw-r--r--drivers/char/drm/sis_mm.c115
-rw-r--r--drivers/char/drm/via_dma.c144
-rw-r--r--drivers/char/drm/via_dmablit.c54
-rw-r--r--drivers/char/drm/via_drv.h22
-rw-r--r--drivers/char/drm/via_irq.c47
-rw-r--r--drivers/char/drm/via_map.c14
-rw-r--r--drivers/char/drm/via_mm.c85
-rw-r--r--drivers/char/drm/via_verifier.c8
-rw-r--r--drivers/char/drm/via_verifier.h2
-rw-r--r--drivers/char/drm/via_video.c20
-rw-r--r--drivers/char/dsp56k.c6
-rw-r--r--drivers/char/ec3104_keyb.c457
-rw-r--r--drivers/char/epca.c2611
-rw-r--r--drivers/char/esp.c4
-rw-r--r--drivers/char/hvc_beat.c4
-rw-r--r--drivers/char/hvc_console.c56
-rw-r--r--drivers/char/hvc_lguest.c177
-rw-r--r--drivers/char/hw_random/omap-rng.c2
-rw-r--r--drivers/char/i8k.c18
-rw-r--r--drivers/char/ip2/ip2main.c92
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c6
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c27
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c62
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c268
-rw-r--r--drivers/char/isicom.c10
-rw-r--r--drivers/char/istallion.c8
-rw-r--r--drivers/char/keyboard.c85
-rw-r--r--drivers/char/lp.c22
-rw-r--r--drivers/char/mbcs.c1
-rw-r--r--drivers/char/mem.c134
-rw-r--r--drivers/char/moxa.c148
-rw-r--r--drivers/char/mspec.c2
-rw-r--r--drivers/char/mxser.c25
-rw-r--r--drivers/char/mxser.h3
-rw-r--r--drivers/char/mxser_new.c122
-rw-r--r--drivers/char/n_hdlc.c2
-rw-r--r--drivers/char/n_tty.c4
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c7
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c7
-rw-r--r--drivers/char/pcmcia/synclink_cs.c706
-rw-r--r--drivers/char/ppdev.c5
-rw-r--r--drivers/char/pty.c33
-rw-r--r--drivers/char/random.c8
-rw-r--r--drivers/char/raw.c5
-rw-r--r--drivers/char/rio/host.h2
-rw-r--r--drivers/char/riscom8.c16
-rw-r--r--drivers/char/riscom8.h2
-rw-r--r--drivers/char/rocket.c93
-rw-r--r--drivers/char/rocket_int.h7
-rw-r--r--drivers/char/rtc.c52
-rw-r--r--drivers/char/snsc.c3
-rw-r--r--drivers/char/sonypi.c10
-rw-r--r--drivers/char/stallion.c7
-rw-r--r--drivers/char/sx.c2
-rw-r--r--drivers/char/sx.h4
-rw-r--r--drivers/char/synclink.c4
-rw-r--r--drivers/char/synclink_gt.c8
-rw-r--r--drivers/char/sysrq.c7
-rw-r--r--drivers/char/tipar.c6
-rw-r--r--drivers/char/tpm/tpm_tis.c26
-rw-r--r--drivers/char/tty_io.c25
-rw-r--r--drivers/char/tty_ioctl.c265
-rw-r--r--drivers/char/viotape.c135
-rw-r--r--drivers/char/virtio_console.c225
-rw-r--r--drivers/char/vt.c60
-rw-r--r--drivers/char/vt_ioctl.c63
-rw-r--r--drivers/connector/connector.c21
-rw-r--r--drivers/cpufreq/Kconfig27
-rw-r--r--drivers/cpufreq/cpufreq.c36
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c172
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c22
-rw-r--r--drivers/cpufreq/cpufreq_stats.c18
-rw-r--r--drivers/crypto/Kconfig5
-rw-r--r--drivers/crypto/geode-aes.c4
-rw-r--r--drivers/crypto/padlock-aes.c4
-rw-r--r--drivers/crypto/padlock-sha.c57
-rw-r--r--drivers/dca/Kconfig7
-rw-r--r--drivers/dca/Makefile2
-rw-r--r--drivers/dca/dca-core.c200
-rw-r--r--drivers/dca/dca-sysfs.c88
-rw-r--r--drivers/dma/Kconfig61
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/dmaengine.c17
-rw-r--r--drivers/dma/ioat.c211
-rw-r--r--drivers/dma/ioat_dca.c427
-rw-r--r--drivers/dma/ioat_dma.c1383
-rw-r--r--drivers/dma/ioatdma.c817
-rw-r--r--drivers/dma/ioatdma.h69
-rw-r--r--drivers/dma/ioatdma_hw.h33
-rw-r--r--drivers/dma/ioatdma_registers.h110
-rw-r--r--drivers/dma/iop-adma.c9
-rw-r--r--drivers/edac/edac_core.h2
-rw-r--r--drivers/edac/edac_mc_sysfs.c3
-rw-r--r--drivers/edac/i5000_edac.c2
-rw-r--r--drivers/edac/pasemi_edac.c1
-rw-r--r--drivers/eisa/eisa-bus.c13
-rw-r--r--drivers/fc4/Kconfig81
-rw-r--r--drivers/fc4/Makefile9
-rw-r--r--drivers/fc4/fc-al.h27
-rw-r--r--drivers/fc4/fc.c1157
-rw-r--r--drivers/fc4/fc.h230
-rw-r--r--drivers/fc4/fc_syms.c30
-rw-r--r--drivers/fc4/fcp.h94
-rw-r--r--drivers/fc4/fcp_impl.h164
-rw-r--r--drivers/fc4/soc.c764
-rw-r--r--drivers/fc4/soc.h301
-rw-r--r--drivers/fc4/socal.c904
-rw-r--r--drivers/fc4/socal.h314
-rw-r--r--drivers/firewire/fw-cdev.c57
-rw-r--r--drivers/firewire/fw-device.c11
-rw-r--r--drivers/firewire/fw-device.h5
-rw-r--r--drivers/firewire/fw-ohci.c91
-rw-r--r--drivers/firewire/fw-ohci.h2
-rw-r--r--drivers/firewire/fw-sbp2.c650
-rw-r--r--drivers/firewire/fw-topology.c10
-rw-r--r--drivers/firewire/fw-topology.h6
-rw-r--r--drivers/firewire/fw-transaction.c14
-rw-r--r--drivers/firmware/dcdbas.h1
-rw-r--r--drivers/firmware/dmi-id.c62
-rw-r--r--drivers/firmware/dmi_scan.c57
-rw-r--r--drivers/firmware/edd.c4
-rw-r--r--drivers/firmware/efivars.c4
-rw-r--r--drivers/hid/Kconfig19
-rw-r--r--drivers/hid/Makefile2
-rw-r--r--drivers/hid/hid-core.c16
-rw-r--r--drivers/hid/hid-debug.c40
-rw-r--r--drivers/hid/hid-input.c116
-rw-r--r--drivers/hid/hidraw.c407
-rw-r--r--drivers/hid/usbhid/Kconfig11
-rw-r--r--drivers/hid/usbhid/hid-core.c54
-rw-r--r--drivers/hid/usbhid/hid-ff.c7
-rw-r--r--drivers/hid/usbhid/hid-plff.c24
-rw-r--r--drivers/hid/usbhid/hid-quirks.c41
-rw-r--r--drivers/hid/usbhid/hid-tmff.c161
-rw-r--r--drivers/hid/usbhid/hiddev.c12
-rw-r--r--drivers/hid/usbhid/usbkbd.c7
-rw-r--r--drivers/hid/usbhid/usbmouse.c12
-rw-r--r--drivers/hwmon/Kconfig92
-rw-r--r--drivers/hwmon/Makefile6
-rw-r--r--drivers/hwmon/abituguru.c12
-rw-r--r--drivers/hwmon/abituguru3.c66
-rw-r--r--drivers/hwmon/ad7418.c12
-rw-r--r--drivers/hwmon/adm1021.c373
-rw-r--r--drivers/hwmon/adm1025.c12
-rw-r--r--drivers/hwmon/adm1026.c14
-rw-r--r--drivers/hwmon/adm1029.c10
-rw-r--r--drivers/hwmon/adm1031.c10
-rw-r--r--drivers/hwmon/adm9240.c10
-rw-r--r--drivers/hwmon/adt7470.c1050
-rw-r--r--drivers/hwmon/ams/ams-input.c76
-rw-r--r--drivers/hwmon/ams/ams.h5
-rw-r--r--drivers/hwmon/applesmc.c202
-rw-r--r--drivers/hwmon/asb100.c16
-rw-r--r--drivers/hwmon/atxp1.c10
-rw-r--r--drivers/hwmon/coretemp.c25
-rw-r--r--drivers/hwmon/dme1737.c954
-rw-r--r--drivers/hwmon/ds1621.c12
-rw-r--r--drivers/hwmon/f71805f.c15
-rw-r--r--drivers/hwmon/f71882fg.c950
-rw-r--r--drivers/hwmon/f75375s.c789
-rw-r--r--drivers/hwmon/fscher.c10
-rw-r--r--drivers/hwmon/fschmd.c778
-rw-r--r--drivers/hwmon/fscpos.c10
-rw-r--r--drivers/hwmon/gl518sm.c10
-rw-r--r--drivers/hwmon/gl520sm.c14
-rw-r--r--drivers/hwmon/hdaps.c59
-rw-r--r--drivers/hwmon/hwmon-vid.c2
-rw-r--r--drivers/hwmon/hwmon.c27
-rw-r--r--drivers/hwmon/i5k_amb.c552
-rw-r--r--drivers/hwmon/ibmpex.c605
-rw-r--r--drivers/hwmon/it87.c66
-rw-r--r--drivers/hwmon/k8temp.c10
-rw-r--r--drivers/hwmon/lm63.c12
-rw-r--r--drivers/hwmon/lm70.c38
-rw-r--r--drivers/hwmon/lm75.c12
-rw-r--r--drivers/hwmon/lm75.h2
-rw-r--r--drivers/hwmon/lm77.c12
-rw-r--r--drivers/hwmon/lm78.c48
-rw-r--r--drivers/hwmon/lm80.c10
-rw-r--r--drivers/hwmon/lm83.c10
-rw-r--r--drivers/hwmon/lm85.c704
-rw-r--r--drivers/hwmon/lm87.c83
-rw-r--r--drivers/hwmon/lm90.c39
-rw-r--r--drivers/hwmon/lm92.c10
-rw-r--r--drivers/hwmon/lm93.c28
-rw-r--r--drivers/hwmon/max1619.c10
-rw-r--r--drivers/hwmon/max6650.c10
-rw-r--r--drivers/hwmon/pc87360.c12
-rw-r--r--drivers/hwmon/pc87427.c10
-rw-r--r--drivers/hwmon/sis5595.c82
-rw-r--r--drivers/hwmon/smsc47b397.c10
-rw-r--r--drivers/hwmon/smsc47m1.c14
-rw-r--r--drivers/hwmon/smsc47m192.c12
-rw-r--r--drivers/hwmon/thmc50.c68
-rw-r--r--drivers/hwmon/via686a.c14
-rw-r--r--drivers/hwmon/vt1211.c12
-rw-r--r--drivers/hwmon/vt8231.c12
-rw-r--r--drivers/hwmon/w83627ehf.c16
-rw-r--r--drivers/hwmon/w83627hf.c879
-rw-r--r--drivers/hwmon/w83781d.c207
-rw-r--r--drivers/hwmon/w83791d.c136
-rw-r--r--drivers/hwmon/w83792d.c63
-rw-r--r--drivers/hwmon/w83793.c10
-rw-r--r--drivers/hwmon/w83l785ts.c10
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c2
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c2
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c2
-rw-r--r--drivers/i2c/busses/Kconfig33
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c2
-rw-r--r--drivers/i2c/busses/i2c-au1550.c11
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c16
-rw-r--r--drivers/i2c/busses/i2c-davinci.c586
-rw-r--r--drivers/i2c/busses/i2c-elektor.c2
-rw-r--r--drivers/i2c/busses/i2c-hydra.c2
-rw-r--r--drivers/i2c/busses/i2c-i801.c5
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c11
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c8
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c83
-rw-r--r--drivers/i2c/busses/i2c-omap.c2
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c2
-rw-r--r--drivers/i2c/busses/i2c-parport.c2
-rw-r--r--drivers/i2c/busses/i2c-pasemi.c7
-rw-r--r--drivers/i2c/busses/i2c-pmcmsp.c8
-rw-r--r--drivers/i2c/busses/i2c-pnx.c2
-rw-r--r--drivers/i2c/busses/i2c-pxa.c99
-rw-r--r--drivers/i2c/busses/i2c-stub.c79
-rw-r--r--drivers/i2c/busses/i2c-via.c4
-rw-r--r--drivers/i2c/busses/i2c-viapro.c2
-rw-r--r--drivers/i2c/chips/eeprom.c37
-rw-r--r--drivers/i2c/chips/menelaus.c12
-rw-r--r--drivers/i2c/chips/pcf8574.c14
-rw-r--r--drivers/i2c/chips/tps65010.c299
-rw-r--r--drivers/i2c/i2c-core.c63
-rw-r--r--drivers/i2c/i2c-dev.c106
-rw-r--r--drivers/ide/Kconfig163
-rw-r--r--drivers/ide/arm/bast-ide.c2
-rw-r--r--drivers/ide/arm/icside.c134
-rw-r--r--drivers/ide/arm/ide_arm.c2
-rw-r--r--drivers/ide/arm/rapide.c37
-rw-r--r--drivers/ide/cris/ide-cris.c47
-rw-r--r--drivers/ide/h8300/ide-h8300.c3
-rw-r--r--drivers/ide/ide-acpi.c43
-rw-r--r--drivers/ide/ide-cd.c6
-rw-r--r--drivers/ide/ide-disk.c61
-rw-r--r--drivers/ide/ide-dma.c194
-rw-r--r--drivers/ide/ide-floppy.c52
-rw-r--r--drivers/ide/ide-io.c162
-rw-r--r--drivers/ide/ide-iops.c180
-rw-r--r--drivers/ide/ide-lib.c153
-rw-r--r--drivers/ide/ide-pnp.c3
-rw-r--r--drivers/ide/ide-probe.c127
-rw-r--r--drivers/ide/ide-proc.c2
-rw-r--r--drivers/ide/ide-tape.c3
-rw-r--r--drivers/ide/ide-taskfile.c58
-rw-r--r--drivers/ide/ide.c135
-rw-r--r--drivers/ide/legacy/Makefile2
-rw-r--r--drivers/ide/legacy/ali14xx.c23
-rw-r--r--drivers/ide/legacy/buddha.c4
-rw-r--r--drivers/ide/legacy/dtc2278.c22
-rw-r--r--drivers/ide/legacy/falconide.c2
-rw-r--r--drivers/ide/legacy/gayle.c2
-rw-r--r--drivers/ide/legacy/ht6560b.c44
-rw-r--r--drivers/ide/legacy/ide-cs.c14
-rw-r--r--drivers/ide/legacy/ide_platform.c169
-rw-r--r--drivers/ide/legacy/macide.c6
-rw-r--r--drivers/ide/legacy/q40ide.c7
-rw-r--r--drivers/ide/legacy/qd65xx.c114
-rw-r--r--drivers/ide/legacy/umc8672.c16
-rw-r--r--drivers/ide/mips/au1xxx-ide.c111
-rw-r--r--drivers/ide/mips/swarm.c14
-rw-r--r--drivers/ide/pci/aec62xx.c165
-rw-r--r--drivers/ide/pci/alim15x3.c222
-rw-r--r--drivers/ide/pci/amd74xx.c276
-rw-r--r--drivers/ide/pci/atiixp.c154
-rw-r--r--drivers/ide/pci/cmd640.c77
-rw-r--r--drivers/ide/pci/cmd64x.c167
-rw-r--r--drivers/ide/pci/cs5520.c125
-rw-r--r--drivers/ide/pci/cs5530.c134
-rw-r--r--drivers/ide/pci/cs5535.c86
-rw-r--r--drivers/ide/pci/cy82c693.c56
-rw-r--r--drivers/ide/pci/delkin_cb.c2
-rw-r--r--drivers/ide/pci/generic.c196
-rw-r--r--drivers/ide/pci/hpt34x.c91
-rw-r--r--drivers/ide/pci/hpt366.c487
-rw-r--r--drivers/ide/pci/it8213.c148
-rw-r--r--drivers/ide/pci/it821x.c185
-rw-r--r--drivers/ide/pci/jmicron.c129
-rw-r--r--drivers/ide/pci/ns87415.c17
-rw-r--r--drivers/ide/pci/opti621.c61
-rw-r--r--drivers/ide/pci/pdc202xx_new.c252
-rw-r--r--drivers/ide/pci/pdc202xx_old.c195
-rw-r--r--drivers/ide/pci/piix.c353
-rw-r--r--drivers/ide/pci/rz1000.c16
-rw-r--r--drivers/ide/pci/sc1200.c117
-rw-r--r--drivers/ide/pci/scc_pata.c105
-rw-r--r--drivers/ide/pci/serverworks.c151
-rw-r--r--drivers/ide/pci/sgiioc4.c106
-rw-r--r--drivers/ide/pci/siimage.c227
-rw-r--r--drivers/ide/pci/sis5513.c510
-rw-r--r--drivers/ide/pci/sl82c105.c88
-rw-r--r--drivers/ide/pci/slc90e66.c112
-rw-r--r--drivers/ide/pci/tc86c001.c65
-rw-r--r--drivers/ide/pci/triflex.c51
-rw-r--r--drivers/ide/pci/trm290.c21
-rw-r--r--drivers/ide/pci/via82cxxx.c161
-rw-r--r--drivers/ide/ppc/mpc8xx.c25
-rw-r--r--drivers/ide/ppc/pmac.c389
-rw-r--r--drivers/ide/setup-pci.c311
-rw-r--r--drivers/ieee1394/csr1212.c57
-rw-r--r--drivers/ieee1394/csr1212.h6
-rw-r--r--drivers/ieee1394/dma.c9
-rw-r--r--drivers/ieee1394/eth1394.c67
-rw-r--r--drivers/ieee1394/ieee1394_core.c2
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c2
-rw-r--r--drivers/ieee1394/nodemgr.c39
-rw-r--r--drivers/ieee1394/pcilynx.c29
-rw-r--r--drivers/ieee1394/sbp2.c19
-rw-r--r--drivers/infiniband/core/addr.c3
-rw-r--r--drivers/infiniband/core/cm.c51
-rw-r--r--drivers/infiniband/core/cma.c229
-rw-r--r--drivers/infiniband/core/device.c4
-rw-r--r--drivers/infiniband/core/fmr_pool.c30
-rw-r--r--drivers/infiniband/core/multicast.c2
-rw-r--r--drivers/infiniband/core/sa_query.c12
-rw-r--r--drivers/infiniband/core/sysfs.c9
-rw-r--r--drivers/infiniband/core/ucma.c74
-rw-r--r--drivers/infiniband/core/umem.c33
-rw-r--r--drivers/infiniband/core/user_mad.c151
-rw-r--r--drivers/infiniband/core/uverbs.h1
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c8
-rw-r--r--drivers/infiniband/core/uverbs_main.c16
-rw-r--r--drivers/infiniband/hw/amso1100/c2.c1
-rw-r--r--drivers/infiniband/hw/amso1100/c2_provider.c1
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c3
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c16
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c1
-rw-r--r--drivers/infiniband/hw/ehca/ehca_av.c48
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h18
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c23
-rw-r--r--drivers/infiniband/hw/ehca/ehca_eq.c6
-rw-r--r--drivers/infiniband/hw/ehca/ehca_hca.c55
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c33
-rw-r--r--drivers/infiniband/hw/ehca/ehca_iverbs.h3
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c113
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mcast.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.c147
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c196
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_sqp.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_tools.h19
-rw-r--r--drivers/infiniband/hw/ehca/ehca_uverbs.c46
-rw-r--r--drivers/infiniband/hw/ehca/hcp_if.c105
-rw-r--r--drivers/infiniband/hw/ehca/hipz_hw.h6
-rw-r--r--drivers/infiniband/hw/ehca/ipz_pt_fn.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_common.h4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_cq.c105
-rw-r--r--drivers/infiniband/hw/ipath/ipath_diag.c22
-rw-r--r--drivers/infiniband/hw/ipath/ipath_dma.c12
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c93
-rw-r--r--drivers/infiniband/hw/ipath/ipath_eeprom.c20
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c74
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c187
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c57
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6120.c18
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c82
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h12
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mad.c53
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mr.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c31
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c78
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c310
-rw-r--r--drivers/infiniband/hw/ipath/ipath_stats.c17
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sysfs.c40
-rw-r--r--drivers/infiniband/hw/ipath/ipath_uc.c98
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ud.c382
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c329
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.h45
-rw-r--r--drivers/infiniband/hw/mlx4/main.c50
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h16
-rw-r--r--drivers/infiniband/hw/mlx4/mr.c100
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c34
-rw-r--r--drivers/infiniband/hw/mlx4/srq.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c6
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cq.c53
-rw-r--r--drivers/infiniband/hw/mthca/mthca_dev.h2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_doorbell.h13
-rw-r--r--drivers/infiniband/hw/mthca/mthca_eq.c21
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c110
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.c29
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c45
-rw-r--r--drivers/infiniband/hw/mthca/mthca_srq.c19
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h47
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c152
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c121
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c122
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c44
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c2
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c2
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c77
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c1
-rw-r--r--drivers/infiniband/ulp/srp/Kconfig1
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c30
-rw-r--r--drivers/input/Kconfig22
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/evdev.c720
-rw-r--r--drivers/input/fixp-arith.h2
-rw-r--r--drivers/input/gameport/gameport.c6
-rw-r--r--drivers/input/input-polldev.c7
-rw-r--r--drivers/input/input.c732
-rw-r--r--drivers/input/joydev.c759
-rw-r--r--drivers/input/joystick/a3d.c28
-rw-r--r--drivers/input/joystick/adi.c2
-rw-r--r--drivers/input/joystick/amijoy.c7
-rw-r--r--drivers/input/joystick/analog.c2
-rw-r--r--drivers/input/joystick/cobra.c2
-rw-r--r--drivers/input/joystick/db9.c4
-rw-r--r--drivers/input/joystick/gamecon.c4
-rw-r--r--drivers/input/joystick/gf2k.c2
-rw-r--r--drivers/input/joystick/grip.c2
-rw-r--r--drivers/input/joystick/grip_mp.c2
-rw-r--r--drivers/input/joystick/guillemot.c2
-rw-r--r--drivers/input/joystick/iforce/Makefile2
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c3
-rw-r--r--drivers/input/joystick/iforce/iforce.h4
-rw-r--r--drivers/input/joystick/interact.c2
-rw-r--r--drivers/input/joystick/magellan.c2
-rw-r--r--drivers/input/joystick/sidewinder.c2
-rw-r--r--drivers/input/joystick/spaceball.c17
-rw-r--r--drivers/input/joystick/spaceorb.c2
-rw-r--r--drivers/input/joystick/stinger.c9
-rw-r--r--drivers/input/joystick/tmdc.c2
-rw-r--r--drivers/input/joystick/turbografx.c2
-rw-r--r--drivers/input/joystick/twidjoy.c2
-rw-r--r--drivers/input/joystick/warrior.c8
-rw-r--r--drivers/input/joystick/xpad.c59
-rw-r--r--drivers/input/keyboard/Kconfig40
-rw-r--r--drivers/input/keyboard/Makefile5
-rw-r--r--drivers/input/keyboard/aaed2000_kbd.c2
-rw-r--r--drivers/input/keyboard/amikbd.c2
-rw-r--r--drivers/input/keyboard/atakbd.c162
-rw-r--r--drivers/input/keyboard/atkbd.c21
-rw-r--r--drivers/input/keyboard/bf54x-keys.c381
-rw-r--r--drivers/input/keyboard/corgikbd.c3
-rw-r--r--drivers/input/keyboard/gpio_keys.c83
-rw-r--r--drivers/input/keyboard/hil_kbd.c5
-rw-r--r--drivers/input/keyboard/hilkbd.c5
-rw-r--r--drivers/input/keyboard/jornada680_kbd.c277
-rw-r--r--drivers/input/keyboard/jornada720_kbd.c185
-rw-r--r--drivers/input/keyboard/locomokbd.c2
-rw-r--r--drivers/input/keyboard/maple_keyb.c252
-rw-r--r--drivers/input/keyboard/newtonkbd.c2
-rw-r--r--drivers/input/keyboard/omap-keypad.c26
-rw-r--r--drivers/input/keyboard/pxa27x_keyboard.c30
-rw-r--r--drivers/input/keyboard/spitzkbd.c3
-rw-r--r--drivers/input/keyboard/stowaway.c2
-rw-r--r--drivers/input/keyboard/sunkbd.c8
-rw-r--r--drivers/input/keyboard/xtkbd.c2
-rw-r--r--drivers/input/misc/Kconfig6
-rw-r--r--drivers/input/misc/ati_remote.c8
-rw-r--r--drivers/input/misc/ati_remote2.c7
-rw-r--r--drivers/input/misc/atlas_btns.c2
-rw-r--r--drivers/input/misc/cobalt_btns.c2
-rw-r--r--drivers/input/misc/ixp4xx-beeper.c4
-rw-r--r--drivers/input/misc/keyspan_remote.c2
-rw-r--r--drivers/input/misc/m68kspkr.c4
-rw-r--r--drivers/input/misc/pcspkr.c9
-rw-r--r--drivers/input/misc/powermate.c9
-rw-r--r--drivers/input/misc/sparcspkr.c4
-rw-r--r--drivers/input/misc/wistron_btns.c2
-rw-r--r--drivers/input/misc/yealink.c2
-rw-r--r--drivers/input/mouse/alps.c28
-rw-r--r--drivers/input/mouse/amimouse.c7
-rw-r--r--drivers/input/mouse/appletouch.c119
-rw-r--r--drivers/input/mouse/atarimouse.c25
-rw-r--r--drivers/input/mouse/hil_ptr.c6
-rw-r--r--drivers/input/mouse/inport.c9
-rw-r--r--drivers/input/mouse/lifebook.c27
-rw-r--r--drivers/input/mouse/logibm.c9
-rw-r--r--drivers/input/mouse/pc110pad.c6
-rw-r--r--drivers/input/mouse/psmouse-base.c14
-rw-r--r--drivers/input/mouse/rpcmouse.c7
-rw-r--r--drivers/input/mouse/sermouse.c7
-rw-r--r--drivers/input/mouse/synaptics.c2
-rw-r--r--drivers/input/mouse/touchkit_ps2.c2
-rw-r--r--drivers/input/mouse/vsxxxaa.c2
-rw-r--r--drivers/input/mousedev.c762
-rw-r--r--drivers/input/serio/hp_sdc.c4
-rw-r--r--drivers/input/serio/i8042.c8
-rw-r--r--drivers/input/serio/i8042.h22
-rw-r--r--drivers/input/serio/parkbd.c2
-rw-r--r--drivers/input/serio/serio.c14
-rw-r--r--drivers/input/tablet/acecad.c12
-rw-r--r--drivers/input/tablet/gtco.c6
-rw-r--r--drivers/input/tablet/kbtab.c11
-rw-r--r--drivers/input/tablet/wacom_sys.c58
-rw-r--r--drivers/input/touchscreen/Kconfig27
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/ads7846.c8
-rw-r--r--drivers/input/touchscreen/corgi_ts.c4
-rw-r--r--drivers/input/touchscreen/elo.c4
-rw-r--r--drivers/input/touchscreen/fujitsu_ts.c4
-rw-r--r--drivers/input/touchscreen/gunze.c4
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c5
-rw-r--r--drivers/input/touchscreen/hp680_ts_input.c4
-rw-r--r--drivers/input/touchscreen/jornada720_ts.c182
-rw-r--r--drivers/input/touchscreen/mk712.c4
-rw-r--r--drivers/input/touchscreen/mtouch.c4
-rw-r--r--drivers/input/touchscreen/penmount.c4
-rw-r--r--drivers/input/touchscreen/touchright.c4
-rw-r--r--drivers/input/touchscreen/touchwin.c4
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c8
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c131
-rw-r--r--drivers/input/tsdev.c533
-rw-r--r--drivers/isdn/act2000/act2000_isa.c14
-rw-r--r--drivers/isdn/capi/capidrv.c30
-rw-r--r--drivers/isdn/capi/kcapi.c2
-rw-r--r--drivers/isdn/divert/divert_procfs.c7
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c9
-rw-r--r--drivers/isdn/gigaset/common.c3
-rw-r--r--drivers/isdn/gigaset/i4l.c12
-rw-r--r--drivers/isdn/gigaset/proc.c8
-rw-r--r--drivers/isdn/gigaset/usb-gigaset.c7
-rw-r--r--drivers/isdn/hardware/avm/b1.c28
-rw-r--r--drivers/isdn/hardware/avm/b1dma.c28
-rw-r--r--drivers/isdn/hardware/avm/c4.c16
-rw-r--r--drivers/isdn/hardware/avm/t1isa.c28
-rw-r--r--drivers/isdn/hardware/eicon/capifunc.c4
-rw-r--r--drivers/isdn/hardware/eicon/diva_didd.c5
-rw-r--r--drivers/isdn/hisax/Kconfig18
-rw-r--r--drivers/isdn/hisax/amd7930_fn.c2
-rw-r--r--drivers/isdn/hisax/avm_pci.c224
-rw-r--r--drivers/isdn/hisax/bkm_a8.c8
-rw-r--r--drivers/isdn/hisax/diva.c513
-rw-r--r--drivers/isdn/hisax/elsa.c498
-rw-r--r--drivers/isdn/hisax/enternow_pci.c18
-rw-r--r--drivers/isdn/hisax/gazel.c4
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c3
-rw-r--r--drivers/isdn/hisax/hfc_pci.c2
-rw-r--r--drivers/isdn/hisax/hfc_usb.c63
-rw-r--r--drivers/isdn/hisax/hisax.h2
-rw-r--r--drivers/isdn/hisax/hisax_if.h2
-rw-r--r--drivers/isdn/hisax/isdnhdlc.c4
-rw-r--r--drivers/isdn/hisax/isdnhdlc.h2
-rw-r--r--drivers/isdn/hisax/jade.c2
-rw-r--r--drivers/isdn/hisax/niccy.c7
-rw-r--r--drivers/isdn/hisax/nj_s.c2
-rw-r--r--drivers/isdn/hisax/sedlbauer.c276
-rw-r--r--drivers/isdn/hisax/telespci.c8
-rw-r--r--drivers/isdn/hisax/w6692.c7
-rw-r--r--drivers/isdn/hysdn/hysdn_init.c274
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c5
-rw-r--r--drivers/isdn/i4l/isdn_common.c26
-rw-r--r--drivers/isdn/i4l/isdn_net.c412
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c15
-rw-r--r--drivers/isdn/pcbit/capi.c4
-rw-r--r--drivers/isdn/sc/card.h2
-rw-r--r--drivers/isdn/sc/debug.h19
-rw-r--r--drivers/isdn/sc/includes.h1
-rw-r--r--drivers/isdn/sc/init.c5
-rw-r--r--drivers/isdn/sc/interrupt.c17
-rw-r--r--drivers/isdn/sc/packet.c2
-rw-r--r--drivers/isdn/sc/shmem.c9
-rw-r--r--drivers/kvm/Kconfig5
-rw-r--r--drivers/kvm/Makefile2
-rw-r--r--drivers/kvm/i8259.c450
-rw-r--r--drivers/kvm/ioapic.c388
-rw-r--r--drivers/kvm/irq.c98
-rw-r--r--drivers/kvm/irq.h165
-rw-r--r--drivers/kvm/kvm.h211
-rw-r--r--drivers/kvm/kvm_main.c1519
-rw-r--r--drivers/kvm/kvm_svm.h3
-rw-r--r--drivers/kvm/lapic.c1080
-rw-r--r--drivers/kvm/mmu.c54
-rw-r--r--drivers/kvm/paging_tmpl.h84
-rw-r--r--drivers/kvm/svm.c1054
-rw-r--r--drivers/kvm/vmx.c1046
-rw-r--r--drivers/kvm/vmx.h73
-rw-r--r--drivers/kvm/x86_emulate.c440
-rw-r--r--drivers/kvm/x86_emulate.h20
-rw-r--r--drivers/leds/Kconfig21
-rw-r--r--drivers/leds/Makefile4
-rw-r--r--drivers/leds/leds-cm-x270.c122
-rw-r--r--drivers/leds/leds-cobalt-qube.c102
-rw-r--r--drivers/leds/leds-cobalt-raq.c138
-rw-r--r--drivers/leds/leds-cobalt.c43
-rw-r--r--drivers/leds/leds-gpio.c20
-rw-r--r--drivers/leds/leds-s3c24xx.c2
-rw-r--r--drivers/lguest/Kconfig13
-rw-r--r--drivers/lguest/Makefile10
-rw-r--r--drivers/lguest/core.c575
-rw-r--r--drivers/lguest/hypercalls.c186
-rw-r--r--drivers/lguest/interrupts_and_traps.c160
-rw-r--r--drivers/lguest/io.c626
-rw-r--r--drivers/lguest/lg.h194
-rw-r--r--drivers/lguest/lguest.c1102
-rw-r--r--drivers/lguest/lguest_asm.S93
-rw-r--r--drivers/lguest/lguest_bus.c218
-rw-r--r--drivers/lguest/lguest_device.c377
-rw-r--r--drivers/lguest/lguest_user.c163
-rw-r--r--drivers/lguest/page_tables.c361
-rw-r--r--drivers/lguest/segments.c76
-rw-r--r--drivers/lguest/x86/core.c581
-rw-r--r--drivers/lguest/x86/switcher_32.S (renamed from drivers/lguest/switcher.S)78
-rw-r--r--drivers/macintosh/Kconfig1
-rw-r--r--drivers/macintosh/adb-iop.c1
-rw-r--r--drivers/macintosh/adbhid.c96
-rw-r--r--drivers/macintosh/ans-lcd.c3
-rw-r--r--drivers/macintosh/ans-lcd.h11
-rw-r--r--drivers/macintosh/mac_hid.c7
-rw-r--r--drivers/macintosh/mediabay.c2
-rw-r--r--drivers/macintosh/therm_adt746x.c5
-rw-r--r--drivers/macintosh/via-pmu.c4
-rw-r--r--drivers/macintosh/windfarm_core.c10
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c2
-rw-r--r--drivers/md/Kconfig12
-rw-r--r--drivers/md/Makefile6
-rw-r--r--drivers/md/bitmap.c5
-rw-r--r--drivers/md/dm-bio-list.h5
-rw-r--r--drivers/md/dm-crypt.c241
-rw-r--r--drivers/md/dm-delay.c23
-rw-r--r--drivers/md/dm-emc.c25
-rw-r--r--drivers/md/dm-hw-handler.c6
-rw-r--r--drivers/md/dm-hw-handler.h1
-rw-r--r--drivers/md/dm-io.c8
-rw-r--r--drivers/md/dm-ioctl.c40
-rw-r--r--drivers/md/dm-log.c2
-rw-r--r--drivers/md/dm-log.h3
-rw-r--r--drivers/md/dm-mpath-hp-sw.c248
-rw-r--r--drivers/md/dm-mpath-rdac.c15
-rw-r--r--drivers/md/dm-mpath.c92
-rw-r--r--drivers/md/dm-path-selector.c6
-rw-r--r--drivers/md/dm-raid1.c39
-rw-r--r--drivers/md/dm-snap.c5
-rw-r--r--drivers/md/dm-stripe.c3
-rw-r--r--drivers/md/dm-table.c41
-rw-r--r--drivers/md/dm-target.c6
-rw-r--r--drivers/md/dm-uevent.c222
-rw-r--r--drivers/md/dm-uevent.h59
-rw-r--r--drivers/md/dm-zero.c2
-rw-r--r--drivers/md/dm.c105
-rw-r--r--drivers/md/dm.h1
-rw-r--r--drivers/md/faulty.c10
-rw-r--r--drivers/md/kcopyd.c8
-rw-r--r--drivers/md/linear.c27
-rw-r--r--drivers/md/md.c86
-rw-r--r--drivers/md/multipath.c46
-rw-r--r--drivers/md/raid0.c38
-rw-r--r--drivers/md/raid1.c69
-rw-r--r--drivers/md/raid10.c65
-rw-r--r--drivers/md/raid5.c115
-rw-r--r--drivers/md/raid6algos.c4
-rw-r--r--drivers/md/raid6mmx.c2
-rw-r--r--drivers/md/raid6sse1.c2
-rw-r--r--drivers/md/raid6sse2.c4
-rw-r--r--drivers/md/raid6x86.h2
-rw-r--r--drivers/media/Kconfig71
-rw-r--r--drivers/media/common/Kconfig2
-rw-r--r--drivers/media/common/ir-functions.c1
-rw-r--r--drivers/media/common/ir-keymaps.c132
-rw-r--r--drivers/media/common/saa7146_core.c108
-rw-r--r--drivers/media/common/saa7146_fops.c5
-rw-r--r--drivers/media/common/saa7146_hlp.c2
-rw-r--r--drivers/media/common/saa7146_i2c.c23
-rw-r--r--drivers/media/common/saa7146_vbi.c9
-rw-r--r--drivers/media/common/saa7146_video.c11
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c3
-rw-r--r--drivers/media/dvb/bt8xx/bt878.h7
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c1
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c54
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c1
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c91
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c5
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c128
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h13
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c31
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c46
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig2
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700.h5
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c23
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c676
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.c28
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h26
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-init.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c2
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk-fe.c84
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.c93
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.h32
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c2
-rw-r--r--drivers/media/dvb/frontends/Kconfig33
-rw-r--r--drivers/media/dvb/frontends/Makefile4
-rw-r--r--drivers/media/dvb/frontends/bcm3510.c1
-rw-r--r--drivers/media/dvb/frontends/cx22700.c1
-rw-r--r--drivers/media/dvb/frontends/cx24110.c1
-rw-r--r--drivers/media/dvb/frontends/cx24123.c1
-rw-r--r--drivers/media/dvb/frontends/dib0070.c580
-rw-r--r--drivers/media/dvb/frontends/dib0070.h44
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c1
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c192
-rw-r--r--drivers/media/dvb/frontends/dib7000m.c727
-rw-r--r--drivers/media/dvb/frontends/dib7000p.c908
-rw-r--r--drivers/media/dvb/frontends/dib7000p.h14
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.h57
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c147
-rw-r--r--drivers/media/dvb/frontends/dvb_dummy_fe.c1
-rw-r--r--drivers/media/dvb/frontends/isl6421.c1
-rw-r--r--drivers/media/dvb/frontends/l64781.c1
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c1
-rw-r--r--drivers/media/dvb/frontends/lnbp21.c1
-rw-r--r--drivers/media/dvb/frontends/mt2060.c1
-rw-r--r--drivers/media/dvb/frontends/mt2131.c314
-rw-r--r--drivers/media/dvb/frontends/mt2131.h54
-rw-r--r--drivers/media/dvb/frontends/mt2131_priv.h49
-rw-r--r--drivers/media/dvb/frontends/mt2266.c287
-rw-r--r--drivers/media/dvb/frontends/mt2266.h37
-rw-r--r--drivers/media/dvb/frontends/mt312.c1
-rw-r--r--drivers/media/dvb/frontends/mt352.c1
-rw-r--r--drivers/media/dvb/frontends/nxt200x.c1
-rw-r--r--drivers/media/dvb/frontends/or51132.c1
-rw-r--r--drivers/media/dvb/frontends/or51211.c1
-rw-r--r--drivers/media/dvb/frontends/s5h1409.c805
-rw-r--r--drivers/media/dvb/frontends/s5h1409.h73
-rw-r--r--drivers/media/dvb/frontends/sp8870.c1
-rw-r--r--drivers/media/dvb/frontends/sp887x.c1
-rw-r--r--drivers/media/dvb/frontends/stv0297.c26
-rw-r--r--drivers/media/dvb/frontends/stv0299.c1
-rw-r--r--drivers/media/dvb/frontends/tda10021.c10
-rw-r--r--drivers/media/dvb/frontends/tda10023.c10
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c1
-rw-r--r--drivers/media/dvb/frontends/tda10086.c1
-rw-r--r--drivers/media/dvb/frontends/tda8083.c9
-rw-r--r--drivers/media/dvb/frontends/ves1820.c6
-rw-r--r--drivers/media/dvb/frontends/zl10353.c1
-rw-r--r--drivers/media/dvb/ttpci/Kconfig2
-rw-r--r--drivers/media/dvb/ttpci/av7110.c3
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.c28
-rw-r--r--drivers/media/dvb/ttpci/av7110_ir.c5
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c6
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-core.c1
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c3
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c3
-rw-r--r--drivers/media/radio/Kconfig24
-rw-r--r--drivers/media/radio/miropcm20-radio.c1
-rw-r--r--drivers/media/radio/radio-gemtek.c617
-rw-r--r--drivers/media/radio/radio-terratec.c2
-rw-r--r--drivers/media/video/Kconfig31
-rw-r--r--drivers/media/video/Makefile28
-rw-r--r--drivers/media/video/arv.c4
-rw-r--r--drivers/media/video/bt8xx/Kconfig2
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c64
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c40
-rw-r--r--drivers/media/video/bt8xx/bttv-gpio.c6
-rw-r--r--drivers/media/video/bt8xx/bttv-i2c.c8
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c1
-rw-r--r--drivers/media/video/bt8xx/bttv-risc.c35
-rw-r--r--drivers/media/video/bt8xx/bttv-vbi.c6
-rw-r--r--drivers/media/video/bt8xx/bttv.h2
-rw-r--r--drivers/media/video/bt8xx/bttvp.h4
-rw-r--r--drivers/media/video/btcx-risc.c1
-rw-r--r--drivers/media/video/bw-qcam.c19
-rw-r--r--drivers/media/video/c-qcam.c1
-rw-r--r--drivers/media/video/cafe_ccic.c27
-rw-r--r--drivers/media/video/compat_ioctl32.c5
-rw-r--r--drivers/media/video/cpia.c6
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c6
-rw-r--r--drivers/media/video/cx2341x.c19
-rw-r--r--drivers/media/video/cx23885/Kconfig20
-rw-r--r--drivers/media/video/cx23885/Makefile9
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c280
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c1526
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c213
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c375
-rw-r--r--drivers/media/video/cx23885/cx23885-reg.h431
-rw-r--r--drivers/media/video/cx23885/cx23885.h301
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c75
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c98
-rw-r--r--drivers/media/video/cx25840/cx25840-core.h6
-rw-r--r--drivers/media/video/cx88/Kconfig6
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c403
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c88
-rw-r--r--drivers/media/video/cx88/cx88-cards.c219
-rw-r--r--drivers/media/video/cx88/cx88-core.c222
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c28
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c27
-rw-r--r--drivers/media/video/cx88/cx88-input.c20
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c265
-rw-r--r--drivers/media/video/cx88/cx88-reg.h35
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c22
-rw-r--r--drivers/media/video/cx88/cx88-vbi.c13
-rw-r--r--drivers/media/video/cx88/cx88-video.c170
-rw-r--r--drivers/media/video/cx88/cx88-vp3054-i2c.c21
-rw-r--r--drivers/media/video/cx88/cx88.h63
-rw-r--r--drivers/media/video/dpc7146.c5
-rw-r--r--drivers/media/video/em28xx/Kconfig2
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c4
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c16
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c11
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c60
-rw-r--r--drivers/media/video/ir-kbd-i2c.c39
-rw-r--r--drivers/media/video/ivtv/Kconfig17
-rw-r--r--drivers/media/video/ivtv/Makefile5
-rw-r--r--drivers/media/video/ivtv/ivtv-audio.c74
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c84
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.h67
-rw-r--r--drivers/media/video/ivtv/ivtv-controls.c16
-rw-r--r--drivers/media/video/ivtv/ivtv-controls.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c343
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h692
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c205
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.c24
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.h7
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c19
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.h7
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c204
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c321
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.h27
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.c6
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.h8
-rw-r--r--drivers/media/video/ivtv/ivtv-queue.c119
-rw-r--r--drivers/media/video/ivtv/ivtv-queue.h13
-rw-r--r--drivers/media/video/ivtv/ivtv-routing.c (renamed from drivers/media/video/ivtv/ivtv-video.c)90
-rw-r--r--drivers/media/video/ivtv/ivtv-routing.h (renamed from drivers/media/video/ivtv/ivtv-audio.h)12
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c247
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.h6
-rw-r--r--drivers/media/video/ivtv/ivtv-udma.c44
-rw-r--r--drivers/media/video/ivtv/ivtv-udma.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.c283
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.h9
-rw-r--r--drivers/media/video/ivtv/ivtv-version.h7
-rw-r--r--drivers/media/video/ivtv/ivtv-video.h24
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.c193
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.h22
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c1148
-rw-r--r--drivers/media/video/meye.c3
-rw-r--r--drivers/media/video/meye.h2
-rw-r--r--drivers/media/video/msp3400-driver.c19
-rw-r--r--drivers/media/video/mt20xx.c311
-rw-r--r--drivers/media/video/mt20xx.h37
-rw-r--r--drivers/media/video/mxb.c4
-rw-r--r--drivers/media/video/ov511.c84
-rw-r--r--drivers/media/video/ov7670.c1
-rw-r--r--drivers/media/video/ovcamchip/ovcamchip_core.c1
-rw-r--r--drivers/media/video/planb.c39
-rw-r--r--drivers/media/video/pms.c1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.c6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ctrl.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debug.h53
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debugifc.c16
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.c6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h12
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c313
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h12
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c70
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-main.c7
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-std.c8
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c220
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c3
-rw-r--r--drivers/media/video/pwc/pwc-ctrl.c2
-rw-r--r--drivers/media/video/pwc/pwc-if.c137
-rw-r--r--drivers/media/video/saa5246a.c4
-rw-r--r--drivers/media/video/saa5249.c4
-rw-r--r--drivers/media/video/saa6588.c1
-rw-r--r--drivers/media/video/saa7127.c10
-rw-r--r--drivers/media/video/saa7134/Kconfig6
-rw-r--r--drivers/media/video/saa7134/saa6752hs.c111
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c19
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c61
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c242
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c23
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c30
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c8
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c30
-rw-r--r--drivers/media/video/saa7134/saa7134-oss.c43
-rw-r--r--drivers/media/video/saa7134/saa7134-ts.c30
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c35
-rw-r--r--drivers/media/video/saa7134/saa7134-vbi.c7
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c208
-rw-r--r--drivers/media/video/saa7134/saa7134.h26
-rw-r--r--drivers/media/video/se401.c1
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c114
-rw-r--r--drivers/media/video/stradis.c1
-rw-r--r--drivers/media/video/stv680.c52
-rw-r--r--drivers/media/video/tcm825x.c928
-rw-r--r--drivers/media/video/tcm825x.h199
-rw-r--r--drivers/media/video/tda8290.c517
-rw-r--r--drivers/media/video/tda8290.h54
-rw-r--r--drivers/media/video/tda9887.c62
-rw-r--r--drivers/media/video/tea5761.c187
-rw-r--r--drivers/media/video/tea5761.h47
-rw-r--r--drivers/media/video/tea5767.c203
-rw-r--r--drivers/media/video/tea5767.h47
-rw-r--r--drivers/media/video/tuner-core.c262
-rw-r--r--drivers/media/video/tuner-driver.h44
-rw-r--r--drivers/media/video/tuner-i2c.h70
-rw-r--r--drivers/media/video/tuner-simple.c397
-rw-r--r--drivers/media/video/tuner-simple.h46
-rw-r--r--drivers/media/video/tuner-types.c8
-rw-r--r--drivers/media/video/tvaudio.c1
-rw-r--r--drivers/media/video/tveeprom.c1
-rw-r--r--drivers/media/video/tvmixer.c6
-rw-r--r--drivers/media/video/tvp5150.c16
-rw-r--r--drivers/media/video/usbvideo/konicawc.c4
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c4
-rw-r--r--drivers/media/video/usbvideo/usbvideo.c1
-rw-r--r--drivers/media/video/usbvideo/vicam.c3
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c1
-rw-r--r--drivers/media/video/usbvision/usbvision-i2c.c10
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c123
-rw-r--r--drivers/media/video/v4l1-compat.c3
-rw-r--r--drivers/media/video/v4l2-common.c10
-rw-r--r--drivers/media/video/v4l2-int-device.c158
-rw-r--r--drivers/media/video/videobuf-core.c (renamed from drivers/media/video/video-buf.c)785
-rw-r--r--drivers/media/video/videobuf-dma-sg.c725
-rw-r--r--drivers/media/video/videobuf-dvb.c (renamed from drivers/media/video/video-buf-dvb.c)9
-rw-r--r--drivers/media/video/videobuf-vmalloc.c370
-rw-r--r--drivers/media/video/videocodec.c4
-rw-r--r--drivers/media/video/videodev.c81
-rw-r--r--drivers/media/video/vino.c1
-rw-r--r--drivers/media/video/vivi.c186
-rw-r--r--drivers/media/video/vp27smpx.c212
-rw-r--r--drivers/media/video/w9966.c1
-rw-r--r--drivers/media/video/w9968cf.c15
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c4
-rw-r--r--drivers/media/video/zoran_card.c74
-rw-r--r--drivers/media/video/zoran_card.h8
-rw-r--r--drivers/media/video/zoran_device.c19
-rw-r--r--drivers/media/video/zoran_driver.c37
-rw-r--r--drivers/media/video/zoran_procfs.c9
-rw-r--r--drivers/media/video/zr36016.c4
-rw-r--r--drivers/media/video/zr36050.c6
-rw-r--r--drivers/media/video/zr36060.c6
-rw-r--r--drivers/message/fusion/Kconfig26
-rw-r--r--drivers/message/fusion/lsi/mpi.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_cnfg.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_fc.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_history.txt2
-rw-r--r--drivers/message/fusion/lsi/mpi_init.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_ioc.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_lan.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_log_fc.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_log_sas.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_raid.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_sas.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_targ.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_tool.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_type.h2
-rw-r--r--drivers/message/fusion/mptbase.c602
-rw-r--r--drivers/message/fusion/mptbase.h80
-rw-r--r--drivers/message/fusion/mptctl.c364
-rw-r--r--drivers/message/fusion/mptctl.h4
-rw-r--r--drivers/message/fusion/mptfc.c149
-rw-r--r--drivers/message/fusion/mptlan.c34
-rw-r--r--drivers/message/fusion/mptlan.h8
-rw-r--r--drivers/message/fusion/mptsas.c468
-rw-r--r--drivers/message/fusion/mptsas.h158
-rw-r--r--drivers/message/fusion/mptscsih.c645
-rw-r--r--drivers/message/fusion/mptscsih.h4
-rw-r--r--drivers/message/fusion/mptspi.c211
-rw-r--r--drivers/message/i2o/README4
-rw-r--r--drivers/message/i2o/exec-osm.c98
-rw-r--r--drivers/message/i2o/i2o_block.c29
-rw-r--r--drivers/message/i2o/i2o_config.c6
-rw-r--r--drivers/message/i2o/i2o_proc.c4
-rw-r--r--drivers/message/i2o/iop.c4
-rw-r--r--drivers/message/i2o/pci.c4
-rw-r--r--drivers/mfd/Kconfig4
-rw-r--r--drivers/misc/Kconfig33
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/atmel-ssc.c174
-rw-r--r--drivers/misc/fujitsu-laptop.c355
-rw-r--r--drivers/misc/hdpuftrs/hdpu_cpustate.c107
-rw-r--r--drivers/misc/hdpuftrs/hdpu_nexus.c88
-rw-r--r--drivers/misc/ibmasm/remote.c10
-rw-r--r--drivers/misc/ioc4.c10
-rw-r--r--drivers/misc/msi-laptop.c2
-rw-r--r--drivers/misc/phantom.c97
-rw-r--r--drivers/misc/sony-laptop.c218
-rw-r--r--drivers/misc/thinkpad_acpi.c227
-rw-r--r--drivers/misc/thinkpad_acpi.h39
-rw-r--r--drivers/misc/tifm_core.c9
-rw-r--r--drivers/mmc/card/Kconfig7
-rw-r--r--drivers/mmc/card/Makefile2
-rw-r--r--drivers/mmc/card/block.c30
-rw-r--r--drivers/mmc/card/queue.c13
-rw-r--r--drivers/mmc/card/sdio_uart.c1158
-rw-r--r--drivers/mmc/core/Makefile4
-rw-r--r--drivers/mmc/core/bus.c70
-rw-r--r--drivers/mmc/core/core.c168
-rw-r--r--drivers/mmc/core/core.h2
-rw-r--r--drivers/mmc/core/host.c8
-rw-r--r--drivers/mmc/core/mmc.c135
-rw-r--r--drivers/mmc/core/mmc_ops.c219
-rw-r--r--drivers/mmc/core/mmc_ops.h3
-rw-r--r--drivers/mmc/core/sd.c126
-rw-r--r--drivers/mmc/core/sd_ops.c112
-rw-r--r--drivers/mmc/core/sdio.c395
-rw-r--r--drivers/mmc/core/sdio_bus.c263
-rw-r--r--drivers/mmc/core/sdio_bus.h22
-rw-r--r--drivers/mmc/core/sdio_cis.c346
-rw-r--r--drivers/mmc/core/sdio_cis.h23
-rw-r--r--drivers/mmc/core/sdio_io.c548
-rw-r--r--drivers/mmc/core/sdio_irq.c267
-rw-r--r--drivers/mmc/core/sdio_ops.c175
-rw-r--r--drivers/mmc/core/sdio_ops.h22
-rw-r--r--drivers/mmc/host/Kconfig30
-rw-r--r--drivers/mmc/host/Makefile2
-rw-r--r--drivers/mmc/host/at91_mci.c37
-rw-r--r--drivers/mmc/host/au1xmmc.c71
-rw-r--r--drivers/mmc/host/imxmmc.c34
-rw-r--r--drivers/mmc/host/mmc_spi.c1423
-rw-r--r--drivers/mmc/host/mmci.c27
-rw-r--r--drivers/mmc/host/mmci.h2
-rw-r--r--drivers/mmc/host/omap.c16
-rw-r--r--drivers/mmc/host/pxamci.c122
-rw-r--r--drivers/mmc/host/pxamci.h16
-rw-r--r--drivers/mmc/host/ricoh_mmc.c151
-rw-r--r--drivers/mmc/host/sdhci.c132
-rw-r--r--drivers/mmc/host/sdhci.h2
-rw-r--r--drivers/mmc/host/tifm_sd.c40
-rw-r--r--drivers/mmc/host/wbsd.c51
-rw-r--r--drivers/mtd/Kconfig8
-rw-r--r--drivers/mtd/Makefile1
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c182
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c2
-rw-r--r--drivers/mtd/chips/jedec_probe.c37
-rw-r--r--drivers/mtd/devices/Kconfig25
-rw-r--r--drivers/mtd/devices/Makefile1
-rw-r--r--drivers/mtd/devices/at91_dataflash26.c485
-rw-r--r--drivers/mtd/devices/docprobe.c4
-rw-r--r--drivers/mtd/devices/m25p80.c271
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c17
-rw-r--r--drivers/mtd/devices/pmc551.c27
-rw-r--r--drivers/mtd/inftlmount.c3
-rw-r--r--drivers/mtd/maps/Kconfig55
-rw-r--r--drivers/mtd/maps/Makefile6
-rw-r--r--drivers/mtd/maps/alchemy-flash.c14
-rw-r--r--drivers/mtd/maps/intel_vr_nor.c298
-rw-r--r--drivers/mtd/maps/lubbock-flash.c168
-rw-r--r--drivers/mtd/maps/mainstone-flash.c180
-rw-r--r--drivers/mtd/maps/nettel.c65
-rw-r--r--drivers/mtd/maps/ocelot.c175
-rw-r--r--drivers/mtd/maps/physmap_of.c350
-rw-r--r--drivers/mtd/maps/pmcmsp-flash.c22
-rw-r--r--drivers/mtd/maps/pmcmsp-ramroot.c1
-rw-r--r--drivers/mtd/maps/pq2fads.c88
-rw-r--r--drivers/mtd/maps/pxa2xx-flash.c200
-rw-r--r--drivers/mtd/maps/tqm834x.c286
-rw-r--r--drivers/mtd/mtd_blkdevs.c7
-rw-r--r--drivers/mtd/mtdchar.c3
-rw-r--r--drivers/mtd/mtdconcat.c3
-rw-r--r--drivers/mtd/mtdcore.c2
-rw-r--r--drivers/mtd/mtdcore.h11
-rw-r--r--drivers/mtd/mtdoops.c376
-rw-r--r--drivers/mtd/nand/Kconfig31
-rw-r--r--drivers/mtd/nand/Makefile2
-rw-r--r--drivers/mtd/nand/alauda.c742
-rw-r--r--drivers/mtd/nand/bf5xx_nand.c788
-rw-r--r--drivers/mtd/nand/cafe_nand.c53
-rw-r--r--drivers/mtd/nand/diskonchip.c6
-rw-r--r--drivers/mtd/nand/excite_nandflash.c1
-rw-r--r--drivers/mtd/nand/nand_base.c15
-rw-r--r--drivers/mtd/nand/nand_ecc.c2
-rw-r--r--drivers/mtd/nand/nand_ids.c1
-rw-r--r--drivers/mtd/nand/nandsim.c10
-rw-r--r--drivers/mtd/nand/ndfc.c8
-rw-r--r--drivers/mtd/nand/s3c2410.c20
-rw-r--r--drivers/mtd/onenand/Kconfig23
-rw-r--r--drivers/mtd/onenand/Makefile3
-rw-r--r--drivers/mtd/onenand/onenand_base.c696
-rw-r--r--drivers/mtd/onenand/onenand_sim.c495
-rw-r--r--drivers/mtd/rfd_ftl.c8
-rw-r--r--drivers/mtd/ubi/build.c28
-rw-r--r--drivers/mtd/ubi/debug.c37
-rw-r--r--drivers/mtd/ubi/debug.h2
-rw-r--r--drivers/mtd/ubi/eba.c134
-rw-r--r--drivers/mtd/ubi/io.c75
-rw-r--r--drivers/mtd/ubi/kapi.c9
-rw-r--r--drivers/mtd/ubi/scan.c62
-rw-r--r--drivers/mtd/ubi/scan.h8
-rw-r--r--drivers/mtd/ubi/ubi.h42
-rw-r--r--drivers/mtd/ubi/vmt.c70
-rw-r--r--drivers/mtd/ubi/vtbl.c8
-rw-r--r--drivers/mtd/ubi/wl.c138
-rw-r--r--drivers/net/3c501.c43
-rw-r--r--drivers/net/3c501.h2
-rw-r--r--drivers/net/3c503.c6
-rw-r--r--drivers/net/3c505.c79
-rw-r--r--drivers/net/3c507.c60
-rw-r--r--drivers/net/3c509.c28
-rw-r--r--drivers/net/3c515.c6
-rw-r--r--drivers/net/3c523.c23
-rw-r--r--drivers/net/3c527.c9
-rw-r--r--drivers/net/3c59x.c91
-rw-r--r--drivers/net/7990.c47
-rw-r--r--drivers/net/7990.h2
-rw-r--r--drivers/net/8139cp.c143
-rw-r--r--drivers/net/8139too.c430
-rw-r--r--drivers/net/82596.c87
-rw-r--r--drivers/net/Kconfig557
-rw-r--r--drivers/net/Makefile17
-rw-r--r--drivers/net/a2065.c58
-rw-r--r--drivers/net/ac3200.c10
-rw-r--r--drivers/net/acenic.c45
-rw-r--r--drivers/net/amd8111e.c54
-rw-r--r--drivers/net/amd8111e.h26
-rw-r--r--drivers/net/apne.c12
-rw-r--r--drivers/net/appletalk/cops.c22
-rw-r--r--drivers/net/appletalk/ipddp.c3
-rw-r--r--drivers/net/appletalk/ipddp.h2
-rw-r--r--drivers/net/appletalk/ltpc.c12
-rw-r--r--drivers/net/arcnet/Kconfig15
-rw-r--r--drivers/net/arcnet/arcnet.c18
-rw-r--r--drivers/net/arcnet/com90io.c2
-rw-r--r--drivers/net/arcnet/rfc1051.c4
-rw-r--r--drivers/net/arcnet/rfc1201.c6
-rw-r--r--drivers/net/ariadne.c47
-rw-r--r--drivers/net/ariadne.h2
-rw-r--r--drivers/net/arm/am79c961a.c10
-rw-r--r--drivers/net/arm/at91_ether.c19
-rw-r--r--drivers/net/arm/ep93xx_eth.c72
-rw-r--r--drivers/net/arm/ether1.c9
-rw-r--r--drivers/net/arm/ether3.c9
-rw-r--r--drivers/net/arm/etherh.c9
-rw-r--r--drivers/net/at1700.c45
-rw-r--r--drivers/net/atarilance.c104
-rw-r--r--drivers/net/atl1/atl1_ethtool.c14
-rw-r--r--drivers/net/atl1/atl1_hw.c2
-rw-r--r--drivers/net/atl1/atl1_main.c17
-rw-r--r--drivers/net/atp.c58
-rw-r--r--drivers/net/au1000_eth.c53
-rw-r--r--drivers/net/au1000_eth.h1
-rw-r--r--drivers/net/ax88796.c51
-rw-r--r--drivers/net/b44.c810
-rw-r--r--drivers/net/b44.h83
-rw-r--r--drivers/net/bfin_mac.c376
-rw-r--r--drivers/net/bfin_mac.h53
-rw-r--r--drivers/net/bmac.c68
-rw-r--r--drivers/net/bnx2.c357
-rw-r--r--drivers/net/bnx2.h8
-rw-r--r--drivers/net/bnx2_fw.h45
-rw-r--r--drivers/net/bnx2_fw2.h7848
-rw-r--r--drivers/net/bonding/bond_3ad.c84
-rw-r--r--drivers/net/bonding/bond_3ad.h34
-rw-r--r--drivers/net/bonding/bond_alb.c132
-rw-r--r--drivers/net/bonding/bond_alb.h6
-rw-r--r--drivers/net/bonding/bond_main.c615
-rw-r--r--drivers/net/bonding/bond_sysfs.c180
-rw-r--r--drivers/net/bonding/bonding.h31
-rw-r--r--drivers/net/cassini.c65
-rw-r--r--drivers/net/cassini.h2
-rw-r--r--drivers/net/chelsio/Makefile2
-rw-r--r--drivers/net/chelsio/common.h2
-rw-r--r--drivers/net/chelsio/cxgb2.c24
-rw-r--r--drivers/net/chelsio/mac.c368
-rw-r--r--drivers/net/chelsio/sge.c31
-rw-r--r--drivers/net/chelsio/sge.h2
-rw-r--r--drivers/net/chelsio/subr.c2
-rw-r--r--drivers/net/cpmac.c1196
-rw-r--r--drivers/net/cris/eth_v10.c450
-rw-r--r--drivers/net/cs89x0.c22
-rw-r--r--drivers/net/cxgb3/adapter.h28
-rw-r--r--drivers/net/cxgb3/common.h17
-rw-r--r--drivers/net/cxgb3/cxgb3_ctl_defs.h52
-rw-r--r--drivers/net/cxgb3/cxgb3_defs.h20
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c143
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.c79
-rw-r--r--drivers/net/cxgb3/regs.h10
-rw-r--r--drivers/net/cxgb3/sge.c205
-rw-r--r--drivers/net/cxgb3/sge_defs.h4
-rw-r--r--drivers/net/cxgb3/t3_hw.c61
-rw-r--r--drivers/net/cxgb3/version.h2
-rw-r--r--drivers/net/cxgb3/xgmac.c33
-rw-r--r--drivers/net/de600.c22
-rw-r--r--drivers/net/de600.h1
-rw-r--r--drivers/net/de620.c36
-rw-r--r--drivers/net/declance.c66
-rw-r--r--drivers/net/defxx.c3
-rw-r--r--drivers/net/depca.c55
-rw-r--r--drivers/net/dgrs.c1615
-rw-r--r--drivers/net/dgrs.h38
-rw-r--r--drivers/net/dgrs_asstruct.h37
-rw-r--r--drivers/net/dgrs_bcomm.h148
-rw-r--r--drivers/net/dgrs_es4h.h183
-rw-r--r--drivers/net/dgrs_ether.h135
-rw-r--r--drivers/net/dgrs_firmware.c9966
-rw-r--r--drivers/net/dgrs_i82596.h473
-rw-r--r--drivers/net/dgrs_plx9060.h175
-rw-r--r--drivers/net/dl2k.c39
-rw-r--r--drivers/net/dl2k.h1
-rw-r--r--drivers/net/dm9000.c45
-rw-r--r--drivers/net/dummy.c1
-rw-r--r--drivers/net/e100.c92
-rw-r--r--drivers/net/e1000/e1000.h9
-rw-r--r--drivers/net/e1000/e1000_ethtool.c56
-rw-r--r--drivers/net/e1000/e1000_hw.c29
-rw-r--r--drivers/net/e1000/e1000_hw.h2
-rw-r--r--drivers/net/e1000/e1000_main.c96
-rw-r--r--drivers/net/e1000/e1000_param.c23
-rw-r--r--drivers/net/e1000e/82571.c1351
-rw-r--r--drivers/net/e1000e/Makefile37
-rw-r--r--drivers/net/e1000e/defines.h739
-rw-r--r--drivers/net/e1000e/e1000.h513
-rw-r--r--drivers/net/e1000e/es2lan.c1232
-rw-r--r--drivers/net/e1000e/ethtool.c1791
-rw-r--r--drivers/net/e1000e/hw.h864
-rw-r--r--drivers/net/e1000e/ich8lan.c2225
-rw-r--r--drivers/net/e1000e/lib.c2493
-rw-r--r--drivers/net/e1000e/netdev.c4157
-rw-r--r--drivers/net/e1000e/param.c383
-rw-r--r--drivers/net/e1000e/phy.c1773
-rw-r--r--drivers/net/e2100.c2
-rw-r--r--drivers/net/eepro.c56
-rw-r--r--drivers/net/eepro100.c10
-rw-r--r--drivers/net/eexpress.c60
-rw-r--r--drivers/net/ehea/ehea.h16
-rw-r--r--drivers/net/ehea/ehea_ethtool.c31
-rw-r--r--drivers/net/ehea/ehea_main.c607
-rw-r--r--drivers/net/ehea/ehea_phyp.h1
-rw-r--r--drivers/net/ehea/ehea_qmr.c23
-rw-r--r--drivers/net/ehea/ehea_qmr.h4
-rw-r--r--drivers/net/epic100.c48
-rw-r--r--drivers/net/eql.c23
-rw-r--r--drivers/net/es3210.c24
-rw-r--r--drivers/net/eth16i.c52
-rw-r--r--drivers/net/ewrk3.c54
-rw-r--r--drivers/net/fealnx.c13
-rw-r--r--drivers/net/fec.c81
-rw-r--r--drivers/net/fec_8xx/fec_8xx.h2
-rw-r--r--drivers/net/fec_8xx/fec_main.c62
-rw-r--r--drivers/net/fec_8xx/fec_mii.c5
-rw-r--r--drivers/net/fec_mpc52xx.c1112
-rw-r--r--drivers/net/fec_mpc52xx.h313
-rw-r--r--drivers/net/fec_mpc52xx_phy.c198
-rw-r--r--drivers/net/forcedeth.c339
-rw-r--r--drivers/net/fs_enet/Kconfig10
-rw-r--r--drivers/net/fs_enet/Makefile15
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c522
-rw-r--r--drivers/net/fs_enet/fs_enet.h92
-rw-r--r--drivers/net/fs_enet/mac-fcc.c190
-rw-r--r--drivers/net/fs_enet/mac-fec.c81
-rw-r--r--drivers/net/fs_enet/mac-scc.c110
-rw-r--r--drivers/net/fs_enet/mii-bitbang.c458
-rw-r--r--drivers/net/fs_enet/mii-fec.c152
-rw-r--r--drivers/net/gianfar.c114
-rw-r--r--drivers/net/gianfar.h5
-rw-r--r--drivers/net/gianfar_ethtool.c21
-rw-r--r--drivers/net/hamachi.c12
-rw-r--r--drivers/net/hamradio/6pack.c45
-rw-r--r--drivers/net/hamradio/Kconfig2
-rw-r--r--drivers/net/hamradio/baycom_epp.c11
-rw-r--r--drivers/net/hamradio/baycom_par.c4
-rw-r--r--drivers/net/hamradio/bpqether.c39
-rw-r--r--drivers/net/hamradio/dmascc.c5
-rw-r--r--drivers/net/hamradio/hdlcdrv.c3
-rw-r--r--drivers/net/hamradio/mkiss.c16
-rw-r--r--drivers/net/hamradio/scc.c9
-rw-r--r--drivers/net/hamradio/yam.c8
-rw-r--r--drivers/net/hp-plus.c8
-rw-r--r--drivers/net/hp.c7
-rw-r--r--drivers/net/hp100.c15
-rw-r--r--drivers/net/hplance.c1
-rw-r--r--drivers/net/hydra.c8
-rw-r--r--drivers/net/ibm_emac/Kconfig70
-rw-r--r--drivers/net/ibm_emac/ibm_emac_core.c29
-rw-r--r--drivers/net/ibm_emac/ibm_emac_debug.c8
-rw-r--r--drivers/net/ibm_emac/ibm_emac_mal.c53
-rw-r--r--drivers/net/ibm_emac/ibm_emac_mal.h7
-rw-r--r--drivers/net/ibm_newemac/Kconfig63
-rw-r--r--drivers/net/ibm_newemac/Makefile11
-rw-r--r--drivers/net/ibm_newemac/core.c2906
-rw-r--r--drivers/net/ibm_newemac/core.h355
-rw-r--r--drivers/net/ibm_newemac/debug.c238
-rw-r--r--drivers/net/ibm_newemac/debug.h78
-rw-r--r--drivers/net/ibm_newemac/emac.h268
-rw-r--r--drivers/net/ibm_newemac/mal.c721
-rw-r--r--drivers/net/ibm_newemac/mal.h275
-rw-r--r--drivers/net/ibm_newemac/phy.c373
-rw-r--r--drivers/net/ibm_newemac/phy.h80
-rw-r--r--drivers/net/ibm_newemac/rgmii.c323
-rw-r--r--drivers/net/ibm_newemac/rgmii.h76
-rw-r--r--drivers/net/ibm_newemac/tah.c173
-rw-r--r--drivers/net/ibm_newemac/tah.h90
-rw-r--r--drivers/net/ibm_newemac/zmii.c322
-rw-r--r--drivers/net/ibm_newemac/zmii.h73
-rw-r--r--drivers/net/ibmlana.c45
-rw-r--r--drivers/net/ibmlana.h1
-rw-r--r--drivers/net/ibmveth.c475
-rw-r--r--drivers/net/ibmveth.h56
-rw-r--r--drivers/net/ifb.c24
-rw-r--r--drivers/net/ioc3-eth.c61
-rw-r--r--drivers/net/ipg.c2352
-rw-r--r--drivers/net/ipg.h836
-rw-r--r--drivers/net/irda/Kconfig26
-rw-r--r--drivers/net/irda/Makefile2
-rw-r--r--drivers/net/irda/actisys-sir.c4
-rw-r--r--drivers/net/irda/actisys.c2
-rw-r--r--drivers/net/irda/ali-ircc.c4
-rw-r--r--drivers/net/irda/au1k_ir.c11
-rw-r--r--drivers/net/irda/donauboe.c5
-rw-r--r--drivers/net/irda/girbil-sir.c2
-rw-r--r--drivers/net/irda/girbil.c2
-rw-r--r--drivers/net/irda/irda-usb.c1
-rw-r--r--drivers/net/irda/irport.c2
-rw-r--r--drivers/net/irda/irport.h2
-rw-r--r--drivers/net/irda/irtty-sir.c9
-rw-r--r--drivers/net/irda/kingsun-sir.c2
-rw-r--r--drivers/net/irda/ks959-sir.c938
-rw-r--r--drivers/net/irda/ksdazzle-sir.c832
-rw-r--r--drivers/net/irda/mcs7780.c5
-rw-r--r--drivers/net/irda/nsc-ircc.c3
-rw-r--r--drivers/net/irda/nsc-ircc.h2
-rw-r--r--drivers/net/irda/pxaficp_ir.c51
-rw-r--r--drivers/net/irda/sir_dev.c4
-rw-r--r--drivers/net/irda/smsc-ircc2.c4
-rw-r--r--drivers/net/irda/stir4200.c3
-rw-r--r--drivers/net/irda/tekram-sir.c2
-rw-r--r--drivers/net/irda/tekram.c2
-rw-r--r--drivers/net/irda/via-ircc.c3
-rw-r--r--drivers/net/irda/vlsi_ir.c2
-rw-r--r--drivers/net/irda/vlsi_ir.h6
-rw-r--r--drivers/net/irda/w83977af_ir.c3
-rw-r--r--drivers/net/irda/w83977af_ir.h2
-rw-r--r--drivers/net/isa-skeleton.c7
-rw-r--r--drivers/net/iseries_veth.c23
-rw-r--r--drivers/net/ixgb/ixgb.h8
-rw-r--r--drivers/net/ixgb/ixgb_ee.c16
-rw-r--r--drivers/net/ixgb/ixgb_ee.h28
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c27
-rw-r--r--drivers/net/ixgb/ixgb_hw.c4
-rw-r--r--drivers/net/ixgb/ixgb_hw.h4
-rw-r--r--drivers/net/ixgb/ixgb_main.c45
-rw-r--r--drivers/net/ixgb/ixgb_param.c43
-rw-r--r--drivers/net/ixgbe/Makefile36
-rw-r--r--drivers/net/ixgbe/ixgbe.h259
-rw-r--r--drivers/net/ixgbe/ixgbe_82598.c588
-rw-r--r--drivers/net/ixgbe/ixgbe_common.c1175
-rw-r--r--drivers/net/ixgbe/ixgbe_common.h86
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c948
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c2873
-rw-r--r--drivers/net/ixgbe/ixgbe_phy.c494
-rw-r--r--drivers/net/ixgbe/ixgbe_phy.h50
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h1332
-rw-r--r--drivers/net/ixp2000/enp2611.c1
-rw-r--r--drivers/net/ixp2000/ixpdev.c39
-rw-r--r--drivers/net/ixp2000/ixpdev.h2
-rw-r--r--drivers/net/jazzsonic.c73
-rw-r--r--drivers/net/lance.c7
-rw-r--r--drivers/net/lguest_net.c557
-rw-r--r--drivers/net/lib82596.c90
-rw-r--r--drivers/net/lne390.c11
-rw-r--r--drivers/net/loopback.c124
-rw-r--r--drivers/net/lp486e.c60
-rw-r--r--drivers/net/mac8390.c2
-rw-r--r--drivers/net/mac89x0.c15
-rw-r--r--drivers/net/macb.c47
-rw-r--r--drivers/net/macb.h1
-rw-r--r--drivers/net/mace.c69
-rw-r--r--drivers/net/macmace.c62
-rw-r--r--drivers/net/macsonic.c22
-rw-r--r--drivers/net/macvlan.c24
-rw-r--r--drivers/net/meth.c35
-rw-r--r--drivers/net/meth.h3
-rw-r--r--drivers/net/mipsnet.c104
-rw-r--r--drivers/net/mipsnet.h83
-rw-r--r--drivers/net/mlx4/alloc.c7
-rw-r--r--drivers/net/mlx4/cmd.c11
-rw-r--r--drivers/net/mlx4/cq.c2
-rw-r--r--drivers/net/mlx4/eq.c13
-rw-r--r--drivers/net/mlx4/fw.c4
-rw-r--r--drivers/net/mlx4/icm.c138
-rw-r--r--drivers/net/mlx4/icm.h9
-rw-r--r--drivers/net/mlx4/main.c130
-rw-r--r--drivers/net/mlx4/mcg.c2
-rw-r--r--drivers/net/mlx4/mlx4.h10
-rw-r--r--drivers/net/mlx4/mr.c242
-rw-r--r--drivers/net/mlx4/pd.c2
-rw-r--r--drivers/net/mlx4/qp.c5
-rw-r--r--drivers/net/mlx4/srq.c4
-rw-r--r--drivers/net/mv643xx_eth.c900
-rw-r--r--drivers/net/mv643xx_eth.h368
-rw-r--r--drivers/net/mvme147.c14
-rw-r--r--drivers/net/myri10ge/myri10ge.c278
-rw-r--r--drivers/net/myri10ge/myri10ge_mcp.h90
-rw-r--r--drivers/net/myri_sbus.c80
-rw-r--r--drivers/net/myri_sbus.h1
-rw-r--r--drivers/net/natsemi.c87
-rw-r--r--drivers/net/ne-h8300.c16
-rw-r--r--drivers/net/ne.c9
-rw-r--r--drivers/net/ne2.c21
-rw-r--r--drivers/net/ne2k-pci.c16
-rw-r--r--drivers/net/ne3210.c12
-rw-r--r--drivers/net/netconsole.c775
-rw-r--r--drivers/net/netx-eth.c19
-rw-r--r--drivers/net/netxen/netxen_nic.h5
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c51
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c2
-rw-r--r--drivers/net/netxen/netxen_nic_init.c7
-rw-r--r--drivers/net/netxen/netxen_nic_main.c70
-rw-r--r--drivers/net/netxen/netxen_nic_niu.c14
-rw-r--r--drivers/net/ni5010.c55
-rw-r--r--drivers/net/ni52.c2
-rw-r--r--drivers/net/ni65.c3
-rw-r--r--drivers/net/niu.c7914
-rw-r--r--drivers/net/niu.h3222
-rw-r--r--drivers/net/ns83820.c159
-rw-r--r--drivers/net/pasemi_mac.c972
-rw-r--r--drivers/net/pasemi_mac.h82
-rw-r--r--drivers/net/pci-skeleton.c84
-rw-r--r--drivers/net/pcmcia/3c574_cs.c11
-rw-r--r--drivers/net/pcmcia/3c589_cs.c13
-rw-r--r--drivers/net/pcmcia/axnet_cs.c17
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c11
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c10
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c15
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c11
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c12
-rw-r--r--drivers/net/pcnet32.c288
-rw-r--r--drivers/net/phy/Kconfig23
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/fixed.c310
-rw-r--r--drivers/net/phy/marvell.c23
-rw-r--r--drivers/net/phy/mdio-bitbang.c189
-rw-r--r--drivers/net/phy/phy.c54
-rw-r--r--drivers/net/phy/phy_device.c6
-rw-r--r--drivers/net/plip.c89
-rw-r--r--drivers/net/ppp_async.c44
-rw-r--r--drivers/net/ppp_generic.c126
-rw-r--r--drivers/net/ppp_mppe.c14
-rw-r--r--drivers/net/ppp_synctty.c37
-rw-r--r--drivers/net/pppoe.c56
-rw-r--r--drivers/net/pppol2tp.c34
-rw-r--r--drivers/net/pppox.c7
-rw-r--r--drivers/net/ps3_gelic_net.c209
-rw-r--r--drivers/net/ps3_gelic_net.h1
-rw-r--r--[-rwxr-xr-x]drivers/net/qla3xxx.c227
-rw-r--r--[-rwxr-xr-x]drivers/net/qla3xxx.h10
-rw-r--r--drivers/net/r8169.c511
-rw-r--r--drivers/net/rionet.c28
-rw-r--r--drivers/net/rrunner.c60
-rw-r--r--drivers/net/rrunner.h2
-rw-r--r--drivers/net/s2io-regs.h586
-rw-r--r--drivers/net/s2io.c1642
-rw-r--r--drivers/net/s2io.h140
-rw-r--r--drivers/net/saa9730.c102
-rw-r--r--drivers/net/saa9730.h1
-rw-r--r--drivers/net/sb1000.c20
-rw-r--r--drivers/net/sb1250-mac.c1450
-rw-r--r--drivers/net/sc92031.c15
-rw-r--r--drivers/net/seeq8005.c37
-rw-r--r--drivers/net/sgiseeq.c71
-rw-r--r--drivers/net/shaper.c81
-rw-r--r--drivers/net/sis190.c49
-rw-r--r--drivers/net/sis900.c66
-rw-r--r--drivers/net/sk98lin/skge.c1
-rw-r--r--drivers/net/skfp/drvfbi.c733
-rw-r--r--drivers/net/skfp/h/mbuf.h4
-rw-r--r--drivers/net/skfp/h/skfbi.h788
-rw-r--r--drivers/net/skfp/h/skfbiinc.h26
-rw-r--r--drivers/net/skfp/h/targethw.h33
-rw-r--r--drivers/net/skfp/hwt.c42
-rw-r--r--drivers/net/skfp/skfddi.c2
-rw-r--r--drivers/net/skfp/smt.c2
-rw-r--r--drivers/net/skfp/srf.c4
-rw-r--r--drivers/net/skge.c499
-rw-r--r--drivers/net/skge.h20
-rw-r--r--drivers/net/sky2.c554
-rw-r--r--drivers/net/sky2.h90
-rw-r--r--drivers/net/slip.c10
-rw-r--r--drivers/net/smc-mca.c9
-rw-r--r--drivers/net/smc-ultra.c10
-rw-r--r--drivers/net/smc-ultra32.c10
-rw-r--r--drivers/net/smc911x.c82
-rw-r--r--drivers/net/smc911x.h6
-rw-r--r--drivers/net/smc9194.c68
-rw-r--r--drivers/net/smc91x.c134
-rw-r--r--drivers/net/smc91x.h80
-rw-r--r--drivers/net/spider_net.c114
-rw-r--r--drivers/net/spider_net.h6
-rw-r--r--drivers/net/spider_net_ethtool.c28
-rw-r--r--drivers/net/starfire.c166
-rw-r--r--drivers/net/stnic.c1
-rw-r--r--drivers/net/sun3_82586.c1
-rw-r--r--drivers/net/sun3lance.c90
-rw-r--r--drivers/net/sunbmac.c9
-rw-r--r--drivers/net/sundance.c25
-rw-r--r--drivers/net/sungem.c70
-rw-r--r--drivers/net/sungem.h1
-rw-r--r--drivers/net/sunhme.c27
-rw-r--r--drivers/net/sunlance.c98
-rw-r--r--drivers/net/sunqe.c106
-rw-r--r--drivers/net/sunqe.h1
-rw-r--r--drivers/net/tc35815.c67
-rw-r--r--drivers/net/tehuti.c2507
-rw-r--r--drivers/net/tehuti.h564
-rw-r--r--drivers/net/tehuti_fw.h10712
-rw-r--r--drivers/net/tg3.c890
-rw-r--r--drivers/net/tg3.h190
-rw-r--r--drivers/net/tlan.c1
-rw-r--r--drivers/net/tokenring/3c359.c72
-rw-r--r--drivers/net/tokenring/abyss.c14
-rw-r--r--drivers/net/tokenring/ibmtr.c69
-rw-r--r--drivers/net/tokenring/lanstreamer.c102
-rw-r--r--drivers/net/tokenring/madgemc.c24
-rw-r--r--drivers/net/tokenring/olympic.c184
-rw-r--r--drivers/net/tokenring/proteon.c9
-rw-r--r--drivers/net/tokenring/skisa.c9
-rw-r--r--drivers/net/tokenring/smctr.c2
-rw-r--r--drivers/net/tokenring/tms380tr.c4
-rw-r--r--drivers/net/tokenring/tms380tr.h18
-rw-r--r--drivers/net/tokenring/tmspci.c15
-rw-r--r--drivers/net/tsi108_eth.c49
-rw-r--r--drivers/net/tulip/Kconfig35
-rw-r--r--drivers/net/tulip/de2104x.c24
-rw-r--r--drivers/net/tulip/de4x5.c54
-rw-r--r--drivers/net/tulip/de4x5.h2
-rw-r--r--drivers/net/tulip/dmfe.c16
-rw-r--r--drivers/net/tulip/interrupt.c54
-rw-r--r--drivers/net/tulip/tulip.h19
-rw-r--r--drivers/net/tulip/tulip_core.c42
-rw-r--r--drivers/net/tulip/uli526x.c132
-rw-r--r--drivers/net/tulip/winbond-840.c36
-rw-r--r--drivers/net/tulip/xircom_cb.c9
-rw-r--r--drivers/net/tulip/xircom_tulip_cb.c1
-rw-r--r--drivers/net/tun.c68
-rw-r--r--drivers/net/typhoon.c99
-rw-r--r--drivers/net/typhoon.h190
-rw-r--r--drivers/net/ucc_geth.c116
-rw-r--r--drivers/net/ucc_geth.h3
-rw-r--r--drivers/net/ucc_geth_ethtool.c28
-rw-r--r--drivers/net/ucc_geth_mii.c1
-rw-r--r--drivers/net/usb/Kconfig11
-rw-r--r--drivers/net/usb/asix.c1
-rw-r--r--drivers/net/usb/dm9601.c4
-rw-r--r--drivers/net/usb/kaweth.c2
-rw-r--r--drivers/net/usb/mcs7830.c16
-rw-r--r--drivers/net/usb/pegasus.c13
-rw-r--r--drivers/net/usb/rndis_host.c18
-rw-r--r--drivers/net/usb/rtl8150.c2
-rw-r--r--drivers/net/usb/usbnet.c46
-rw-r--r--drivers/net/usb/usbnet.h1
-rw-r--r--drivers/net/veth.c482
-rw-r--r--drivers/net/via-rhine.c74
-rw-r--r--drivers/net/via-velocity.c279
-rw-r--r--drivers/net/via-velocity.h207
-rw-r--r--drivers/net/virtio_net.c438
-rw-r--r--drivers/net/wan/c101.c1
-rw-r--r--drivers/net/wan/cosa.c4
-rw-r--r--drivers/net/wan/cycx_x25.c32
-rw-r--r--drivers/net/wan/dlci.c17
-rw-r--r--drivers/net/wan/dscc4.c1
-rw-r--r--drivers/net/wan/hdlc.c20
-rw-r--r--drivers/net/wan/hdlc_cisco.c10
-rw-r--r--drivers/net/wan/hdlc_ppp.c2
-rw-r--r--drivers/net/wan/hostess_sv11.c2
-rw-r--r--drivers/net/wan/lapbether.c9
-rw-r--r--drivers/net/wan/lmc/lmc_main.c56
-rw-r--r--drivers/net/wan/lmc/lmc_proto.c2
-rw-r--r--drivers/net/wan/n2.c1
-rw-r--r--drivers/net/wan/pc300too.c1
-rw-r--r--drivers/net/wan/pci200syn.c1
-rw-r--r--drivers/net/wan/sbni.c9
-rw-r--r--drivers/net/wan/sdla.c9
-rw-r--r--drivers/net/wan/syncppp.c25
-rw-r--r--drivers/net/wan/wanxl.c1
-rw-r--r--drivers/net/wan/x25_asy.c6
-rw-r--r--drivers/net/wd.c9
-rw-r--r--drivers/net/wireless/Kconfig144
-rw-r--r--drivers/net/wireless/Makefile11
-rw-r--r--drivers/net/wireless/adm8211.c2053
-rw-r--r--drivers/net/wireless/adm8211.h656
-rw-r--r--drivers/net/wireless/airo.c56
-rw-r--r--drivers/net/wireless/airport.c1
-rw-r--r--drivers/net/wireless/arlan-main.c25
-rw-r--r--drivers/net/wireless/arlan-proc.c14
-rw-r--r--drivers/net/wireless/atmel.c8
-rw-r--r--drivers/net/wireless/b43/Kconfig133
-rw-r--r--drivers/net/wireless/b43/Makefile20
-rw-r--r--drivers/net/wireless/b43/b43.h854
-rw-r--r--drivers/net/wireless/b43/debugfs.c656
-rw-r--r--drivers/net/wireless/b43/debugfs.h89
-rw-r--r--drivers/net/wireless/b43/dma.c1494
-rw-r--r--drivers/net/wireless/b43/dma.h337
-rw-r--r--drivers/net/wireless/b43/leds.c235
-rw-r--r--drivers/net/wireless/b43/leds.h64
-rw-r--r--drivers/net/wireless/b43/lo.c1261
-rw-r--r--drivers/net/wireless/b43/lo.h112
-rw-r--r--drivers/net/wireless/b43/main.c4070
-rw-r--r--drivers/net/wireless/b43/main.h125
-rw-r--r--drivers/net/wireless/b43/pcmcia.c174
-rw-r--r--drivers/net/wireless/b43/pcmcia.h20
-rw-r--r--drivers/net/wireless/b43/phy.c4381
-rw-r--r--drivers/net/wireless/b43/phy.h297
-rw-r--r--drivers/net/wireless/b43/pio.c652
-rw-r--r--drivers/net/wireless/b43/pio.h153
-rw-r--r--drivers/net/wireless/b43/rfkill.c173
-rw-r--r--drivers/net/wireless/b43/rfkill.h52
-rw-r--r--drivers/net/wireless/b43/sysfs.c236
-rw-r--r--drivers/net/wireless/b43/sysfs.h9
-rw-r--r--drivers/net/wireless/b43/tables.c375
-rw-r--r--drivers/net/wireless/b43/tables.h28
-rw-r--r--drivers/net/wireless/b43/xmit.c650
-rw-r--r--drivers/net/wireless/b43/xmit.h250
-rw-r--r--drivers/net/wireless/b43legacy/Kconfig89
-rw-r--r--drivers/net/wireless/b43legacy/Makefile14
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h832
-rw-r--r--drivers/net/wireless/b43legacy/debugfs.c505
-rw-r--r--drivers/net/wireless/b43legacy/debugfs.h89
-rw-r--r--drivers/net/wireless/b43legacy/dma.c1565
-rw-r--r--drivers/net/wireless/b43legacy/dma.h367
-rw-r--r--drivers/net/wireless/b43legacy/ilt.c336
-rw-r--r--drivers/net/wireless/b43legacy/ilt.h34
-rw-r--r--drivers/net/wireless/b43legacy/leds.c298
-rw-r--r--drivers/net/wireless/b43legacy/leds.h56
-rw-r--r--drivers/net/wireless/b43legacy/main.c3859
-rw-r--r--drivers/net/wireless/b43legacy/main.h127
-rw-r--r--drivers/net/wireless/b43legacy/phy.c2255
-rw-r--r--drivers/net/wireless/b43legacy/phy.h219
-rw-r--r--drivers/net/wireless/b43legacy/pio.c668
-rw-r--r--drivers/net/wireless/b43legacy/pio.h172
-rw-r--r--drivers/net/wireless/b43legacy/radio.c2158
-rw-r--r--drivers/net/wireless/b43legacy/radio.h98
-rw-r--r--drivers/net/wireless/b43legacy/sysfs.c238
-rw-r--r--drivers/net/wireless/b43legacy/sysfs.h9
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c642
-rw-r--r--drivers/net/wireless/b43legacy/xmit.h259
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h6
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c5
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_xmit.h2
-rw-r--r--drivers/net/wireless/hostap/hostap.h5
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_rx.c49
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_tx.c13
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c198
-rw-r--r--drivers/net/wireless/hostap/hostap_common.h6
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c7
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c32
-rw-r--r--drivers/net/wireless/hostap/hostap_info.c17
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c42
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c101
-rw-r--r--drivers/net/wireless/hostap/hostap_pci.c6
-rw-r--r--drivers/net/wireless/hostap/hostap_proc.c15
-rw-r--r--drivers/net/wireless/hostap/hostap_wlan.h7
-rw-r--r--drivers/net/wireless/ipw2100.c113
-rw-r--r--drivers/net/wireless/ipw2100.h4
-rw-r--r--drivers/net/wireless/ipw2200.c270
-rw-r--r--drivers/net/wireless/ipw2200.h4
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig128
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h118
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c1019
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.h210
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c2311
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h41
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h581
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.c2298
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-rs.h266
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c4732
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.h341
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-channel.h161
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h1734
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h152
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h336
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h255
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hw.h537
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.h470
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-priv.h308
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h229
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-spectrum.h91
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c8797
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c9392
-rw-r--r--drivers/net/wireless/iwlwifi/iwlwifi.h708
-rw-r--r--drivers/net/wireless/libertas/11d.c124
-rw-r--r--drivers/net/wireless/libertas/11d.h4
-rw-r--r--drivers/net/wireless/libertas/Makefile7
-rw-r--r--drivers/net/wireless/libertas/assoc.c147
-rw-r--r--drivers/net/wireless/libertas/assoc.h2
-rw-r--r--drivers/net/wireless/libertas/cmd.c676
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c377
-rw-r--r--drivers/net/wireless/libertas/debugfs.c147
-rw-r--r--drivers/net/wireless/libertas/decl.h19
-rw-r--r--drivers/net/wireless/libertas/defs.h159
-rw-r--r--drivers/net/wireless/libertas/dev.h81
-rw-r--r--drivers/net/wireless/libertas/ethtool.c83
-rw-r--r--drivers/net/wireless/libertas/fw.c349
-rw-r--r--drivers/net/wireless/libertas/host.h431
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h81
-rw-r--r--drivers/net/wireless/libertas/if_bootcmd.c40
-rw-r--r--drivers/net/wireless/libertas/if_cs.c972
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c1081
-rw-r--r--drivers/net/wireless/libertas/if_sdio.h45
-rw-r--r--drivers/net/wireless/libertas/if_usb.c369
-rw-r--r--drivers/net/wireless/libertas/if_usb.h8
-rw-r--r--drivers/net/wireless/libertas/join.c485
-rw-r--r--drivers/net/wireless/libertas/join.h35
-rw-r--r--drivers/net/wireless/libertas/main.c904
-rw-r--r--drivers/net/wireless/libertas/rx.c85
-rw-r--r--drivers/net/wireless/libertas/scan.c806
-rw-r--r--drivers/net/wireless/libertas/scan.h36
-rw-r--r--drivers/net/wireless/libertas/thread.h52
-rw-r--r--drivers/net/wireless/libertas/tx.c41
-rw-r--r--drivers/net/wireless/libertas/types.h67
-rw-r--r--drivers/net/wireless/libertas/wext.c392
-rw-r--r--drivers/net/wireless/libertas/wext.h9
-rw-r--r--drivers/net/wireless/net2280.h452
-rw-r--r--drivers/net/wireless/netwave_cs.c29
-rw-r--r--drivers/net/wireless/orinoco.c7
-rw-r--r--drivers/net/wireless/orinoco_cs.c1
-rw-r--r--drivers/net/wireless/orinoco_nortel.c1
-rw-r--r--drivers/net/wireless/orinoco_pci.c1
-rw-r--r--drivers/net/wireless/orinoco_plx.c1
-rw-r--r--drivers/net/wireless/orinoco_tmd.c3
-rw-r--r--drivers/net/wireless/p54.h81
-rw-r--r--drivers/net/wireless/p54common.c1019
-rw-r--r--drivers/net/wireless/p54common.h329
-rw-r--r--drivers/net/wireless/p54pci.c692
-rw-r--r--drivers/net/wireless/p54pci.h106
-rw-r--r--drivers/net/wireless/p54usb.c907
-rw-r--r--drivers/net/wireless/p54usb.h133
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c63
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c1
-rw-r--r--drivers/net/wireless/prism54/oid_mgt.c4
-rw-r--r--drivers/net/wireless/ray_cs.c86
-rw-r--r--drivers/net/wireless/ray_cs.h4
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig130
-rw-r--r--drivers/net/wireless/rt2x00/Makefile22
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c1664
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.h943
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c1971
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.h1236
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c1832
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.h798
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h840
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c205
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c368
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.h57
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c1202
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00firmware.c124
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h119
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c446
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c474
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h127
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00reg.h292
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00rfkill.c146
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00ring.h268
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c592
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.h180
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c2557
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h1457
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c2111
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h1024
-rw-r--r--drivers/net/wireless/rtl8187.h6
-rw-r--r--drivers/net/wireless/rtl8187_dev.c171
-rw-r--r--drivers/net/wireless/rtl818x.h1
-rw-r--r--drivers/net/wireless/spectrum_cs.c1
-rw-r--r--drivers/net/wireless/strip.c34
-rw-r--r--drivers/net/wireless/wavelan.c60
-rw-r--r--drivers/net/wireless/wavelan_cs.c61
-rw-r--r--drivers/net/wireless/wl3501_cs.c93
-rw-r--r--drivers/net/wireless/zd1201.c4
-rw-r--r--drivers/net/wireless/zd1211rw/Makefile2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c75
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_def.h1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.h43
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c155
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h65
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.c1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c12
-rw-r--r--drivers/net/wireless/zd1211rw/zd_util.c82
-rw-r--r--drivers/net/wireless/zd1211rw/zd_util.h29
-rw-r--r--drivers/net/xen-netfront.c136
-rw-r--r--drivers/net/yellowfin.c83
-rw-r--r--drivers/net/znet.c63
-rw-r--r--drivers/net/zorro8390.c18
-rw-r--r--drivers/of/platform.c21
-rw-r--r--drivers/oprofile/cpu_buffer.c7
-rw-r--r--drivers/oprofile/cpu_buffer.h1
-rw-r--r--drivers/oprofile/oprofile_stats.c4
-rw-r--r--drivers/parisc/ccio-dma.c1
-rw-r--r--drivers/parisc/lba_pci.c51
-rw-r--r--drivers/parisc/led.c2
-rw-r--r--drivers/parisc/pdc_stable.c11
-rw-r--r--drivers/parisc/sba_iommu.c5
-rw-r--r--drivers/parisc/superio.c4
-rw-r--r--drivers/parport/daisy.c42
-rw-r--r--drivers/parport/ieee1284.c2
-rw-r--r--drivers/parport/parport_amiga.c9
-rw-r--r--drivers/parport/parport_atari.c9
-rw-r--r--drivers/parport/parport_ax88796.c10
-rw-r--r--drivers/parport/parport_gsc.c8
-rw-r--r--drivers/parport/parport_ip32.c6
-rw-r--r--drivers/parport/parport_mfc3.c2
-rw-r--r--drivers/parport/parport_pc.c9
-rw-r--r--drivers/parport/parport_sunbpp.c8
-rw-r--r--drivers/parport/probe.c3
-rw-r--r--drivers/parport/procfs.c38
-rw-r--r--drivers/parport/share.c12
-rw-r--r--drivers/pci/Kconfig11
-rw-r--r--drivers/pci/Makefile3
-rw-r--r--drivers/pci/dmar.c329
-rw-r--r--drivers/pci/hotplug.c28
-rw-r--r--drivers/pci/hotplug/Kconfig6
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c4
-rw-r--r--drivers/pci/hotplug/cpqphp_ctrl.c90
-rw-r--r--drivers/pci/hotplug/cpqphp_pci.c2
-rw-r--r--drivers/pci/hotplug/ibmphp_core.c2
-rw-r--r--drivers/pci/hotplug/ibmphp_hpc.c57
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c62
-rw-r--r--drivers/pci/hotplug/pciehp_core.c24
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c20
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c203
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c24
-rw-r--r--drivers/pci/hotplug/rpadlpar_sysfs.c6
-rw-r--r--drivers/pci/intel-iommu.c2270
-rw-r--r--drivers/pci/intel-iommu.h325
-rw-r--r--drivers/pci/iova.c394
-rw-r--r--drivers/pci/iova.h63
-rw-r--r--drivers/pci/msi.c20
-rw-r--r--drivers/pci/pci-driver.c11
-rw-r--r--drivers/pci/pci.c22
-rw-r--r--drivers/pci/pci.h10
-rw-r--r--drivers/pci/pcie/Kconfig9
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c9
-rw-r--r--drivers/pci/probe.c67
-rw-r--r--drivers/pci/proc.c7
-rw-r--r--drivers/pci/quirks.c96
-rw-r--r--drivers/pci/search.c43
-rw-r--r--drivers/pci/setup-bus.c5
-rw-r--r--drivers/pci/setup-irq.c2
-rw-r--r--drivers/pcmcia/Kconfig13
-rw-r--r--drivers/pcmcia/Makefile2
-rw-r--r--drivers/pcmcia/au1000_xxs1500.c5
-rw-r--r--drivers/pcmcia/cistpl.c48
-rw-r--r--drivers/pcmcia/cs.c10
-rw-r--r--drivers/pcmcia/ds.c30
-rw-r--r--drivers/pcmcia/electra_cf.c377
-rw-r--r--drivers/pcmcia/i82365.c2
-rw-r--r--drivers/pcmcia/m32r_pcc.c2
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c2
-rw-r--r--drivers/pcmcia/pd6729.c2
-rw-r--r--drivers/pcmcia/pxa2xx_base.c2
-rw-r--r--drivers/pcmcia/pxa2xx_cm_x270.c175
-rw-r--r--drivers/pcmcia/pxa2xx_lubbock.c31
-rw-r--r--drivers/pcmcia/pxa2xx_mainstone.c20
-rw-r--r--drivers/pcmcia/pxa2xx_sharpsl.c2
-rw-r--r--drivers/pcmcia/tcic.c2
-rw-r--r--drivers/pnp/Makefile4
-rw-r--r--drivers/pnp/card.c71
-rw-r--r--drivers/pnp/core.c28
-rw-r--r--drivers/pnp/driver.c5
-rw-r--r--drivers/pnp/interface.c5
-rw-r--r--drivers/pnp/isapnp/core.c4
-rw-r--r--drivers/pnp/isapnp/proc.c2
-rw-r--r--drivers/pnp/manager.c58
-rw-r--r--drivers/pnp/pnpacpi/core.c16
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c18
-rw-r--r--drivers/pnp/pnpbios/core.c30
-rw-r--r--drivers/pnp/pnpbios/proc.c5
-rw-r--r--drivers/pnp/quirks.c12
-rw-r--r--drivers/pnp/resource.c4
-rw-r--r--drivers/pnp/system.c29
-rw-r--r--drivers/power/apm_power.c141
-rw-r--r--drivers/power/ds2760_battery.c2
-rw-r--r--drivers/power/power_supply.h3
-rw-r--r--drivers/power/power_supply_sysfs.c17
-rw-r--r--drivers/ps3/ps3av.c383
-rw-r--r--drivers/ps3/ps3av_cmd.c83
-rw-r--r--drivers/ps3/ps3stor_lib.c2
-rw-r--r--drivers/ps3/vuart.c2
-rw-r--r--drivers/rtc/Kconfig21
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/class.c1
-rw-r--r--drivers/rtc/hctosys.c4
-rw-r--r--drivers/rtc/interface.c122
-rw-r--r--drivers/rtc/rtc-cmos.c67
-rw-r--r--drivers/rtc/rtc-dev.c44
-rw-r--r--drivers/rtc/rtc-ds1307.c93
-rw-r--r--drivers/rtc/rtc-ds1374.c449
-rw-r--r--drivers/rtc/rtc-ds1553.c4
-rw-r--r--drivers/rtc/rtc-ds1742.c7
-rw-r--r--drivers/rtc/rtc-m48t59.c9
-rw-r--r--drivers/rtc/rtc-pcf8583.c3
-rw-r--r--drivers/rtc/rtc-pl031.c2
-rw-r--r--drivers/rtc/rtc-s3c.c2
-rw-r--r--drivers/rtc/rtc-sa1100.c2
-rw-r--r--drivers/rtc/rtc-sh.c57
-rw-r--r--drivers/rtc/rtc-stk17ta8.c2
-rw-r--r--drivers/rtc/rtc-sysfs.c29
-rw-r--r--drivers/s390/block/dasd_3990_erp.c4
-rw-r--r--drivers/s390/block/dasd_diag.c37
-rw-r--r--drivers/s390/block/dasd_eckd.c28
-rw-r--r--drivers/s390/block/dasd_fba.c28
-rw-r--r--drivers/s390/block/dasd_int.h3
-rw-r--r--drivers/s390/block/dcssblk.c13
-rw-r--r--drivers/s390/block/xpram.c6
-rw-r--r--drivers/s390/char/con3215.c3
-rw-r--r--drivers/s390/char/con3270.c3
-rw-r--r--drivers/s390/char/defkeymap.c2
-rw-r--r--drivers/s390/char/keyboard.c66
-rw-r--r--drivers/s390/char/keyboard.h4
-rw-r--r--drivers/s390/char/raw3270.c26
-rw-r--r--drivers/s390/char/sclp.c5
-rw-r--r--drivers/s390/char/sclp_cpi.c2
-rw-r--r--drivers/s390/char/tape_34xx.c32
-rw-r--r--drivers/s390/char/tape_3590.c63
-rw-r--r--drivers/s390/char/tape_class.c19
-rw-r--r--drivers/s390/char/tape_class.h4
-rw-r--r--drivers/s390/char/tty3270.c9
-rw-r--r--drivers/s390/char/tty3270.h16
-rw-r--r--drivers/s390/char/vmlogrdr.c15
-rw-r--r--drivers/s390/char/vmwatchdog.c4
-rw-r--r--drivers/s390/char/zcore.c7
-rw-r--r--drivers/s390/cio/ccwgroup.c70
-rw-r--r--drivers/s390/cio/chp.c42
-rw-r--r--drivers/s390/cio/cio.c5
-rw-r--r--drivers/s390/cio/cmf.c238
-rw-r--r--drivers/s390/cio/css.c107
-rw-r--r--drivers/s390/cio/css.h3
-rw-r--r--drivers/s390/cio/device.c107
-rw-r--r--drivers/s390/cio/device.h1
-rw-r--r--drivers/s390/cio/device_fsm.c147
-rw-r--r--drivers/s390/cio/device_ops.c241
-rw-r--r--drivers/s390/cio/idset.c2
-rw-r--r--drivers/s390/cio/qdio.c39
-rw-r--r--drivers/s390/crypto/ap_bus.c19
-rw-r--r--drivers/s390/crypto/zcrypt_mono.c4
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c9
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.h45
-rw-r--r--drivers/s390/net/claw.c3
-rw-r--r--drivers/s390/net/ctcmain.c11
-rw-r--r--drivers/s390/net/lcs.c12
-rw-r--r--drivers/s390/net/lcs.h1
-rw-r--r--drivers/s390/net/netiucv.c1
-rw-r--r--drivers/s390/net/qeth.h3
-rw-r--r--drivers/s390/net/qeth_eddp.c16
-rw-r--r--drivers/s390/net/qeth_main.c74
-rw-r--r--drivers/s390/net/smsgiucv.c4
-rw-r--r--drivers/s390/scsi/zfcp_aux.c26
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c18
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c10
-rw-r--r--drivers/s390/scsi/zfcp_def.h55
-rw-r--r--drivers/s390/scsi/zfcp_erp.c175
-rw-r--r--drivers/s390/scsi/zfcp_ext.h38
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c293
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h30
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c13
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c47
-rw-r--r--drivers/s390/scsi/zfcp_sysfs_unit.c4
-rw-r--r--drivers/sbus/char/vfc.h2
-rw-r--r--drivers/sbus/char/vfc_dev.c7
-rw-r--r--drivers/scsi/3w-9xxx.c5
-rw-r--r--drivers/scsi/3w-xxxx.c3
-rw-r--r--drivers/scsi/BusLogic.c1
-rw-r--r--drivers/scsi/FlashPoint.c83
-rw-r--r--drivers/scsi/Kconfig56
-rw-r--r--drivers/scsi/Makefile3
-rw-r--r--drivers/scsi/NCR5380.c37
-rw-r--r--drivers/scsi/NCR5380.h7
-rw-r--r--drivers/scsi/NCR53C9x.c6
-rw-r--r--drivers/scsi/NCR53c406a.c9
-rw-r--r--drivers/scsi/NCR_D700.c5
-rw-r--r--drivers/scsi/a100u2w.c1
-rw-r--r--drivers/scsi/a4000t.c7
-rw-r--r--drivers/scsi/aacraid/aachba.c10
-rw-r--r--drivers/scsi/aacraid/aacraid.h4
-rw-r--r--drivers/scsi/aacraid/commctrl.c12
-rw-r--r--drivers/scsi/aacraid/comminit.c2
-rw-r--r--drivers/scsi/aacraid/commsup.c5
-rw-r--r--drivers/scsi/aacraid/dpcsup.c2
-rw-r--r--drivers/scsi/aacraid/linit.c1
-rw-r--r--drivers/scsi/advansys.c19980
-rw-r--r--drivers/scsi/aha152x.c12
-rw-r--r--drivers/scsi/aha1542.c34
-rw-r--r--drivers/scsi/aha1740.c1
-rw-r--r--drivers/scsi/aic7xxx/aic7770.c16
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h11
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c7
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c5
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm_pci.c50
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_pci.c27
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.h11
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c5
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm_pci.c46
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_pci.c16
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l3
-rw-r--r--drivers/scsi/aic7xxx/cam.h2
-rw-r--r--drivers/scsi/aic7xxx_old.c9
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.h12
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c42
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sds.c4
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c8
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h197
-rw-r--r--drivers/scsi/arcmsr/arcmsr_attr.c73
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c2294
-rw-r--r--drivers/scsi/arm/scsi.h8
-rw-r--r--drivers/scsi/atari_NCR5380.c38
-rw-r--r--drivers/scsi/bvme6000_scsi.c7
-rw-r--r--drivers/scsi/constants.c16
-rw-r--r--drivers/scsi/dc395x.c117
-rw-r--r--drivers/scsi/dpt_i2o.c30
-rw-r--r--drivers/scsi/dtc.c16
-rw-r--r--drivers/scsi/eata.c47
-rw-r--r--drivers/scsi/eata_pio.c104
-rw-r--r--drivers/scsi/esp_scsi.c10
-rw-r--r--drivers/scsi/fcal.c317
-rw-r--r--drivers/scsi/fcal.h27
-rw-r--r--drivers/scsi/fd_mcs.c6
-rw-r--r--drivers/scsi/fdomain.c12
-rw-r--r--drivers/scsi/g_NCR5380.c2
-rw-r--r--drivers/scsi/gdth.c2943
-rw-r--r--drivers/scsi/gdth.h42
-rw-r--r--drivers/scsi/gdth_kcompat.h31
-rw-r--r--drivers/scsi/gdth_proc.c133
-rw-r--r--drivers/scsi/gdth_proc.h20
-rw-r--r--drivers/scsi/hosts.c8
-rw-r--r--drivers/scsi/hptiop.c69
-rw-r--r--drivers/scsi/hptiop.h229
-rw-r--r--drivers/scsi/ibmmca.c11
-rw-r--r--drivers/scsi/ibmvscsi/Makefile2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c101
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.h32
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c61
-rw-r--r--drivers/scsi/ibmvscsi/iseries_vscsi.c37
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c113
-rw-r--r--drivers/scsi/ide-scsi.c174
-rw-r--r--drivers/scsi/imm.c12
-rw-r--r--drivers/scsi/in2000.c34
-rw-r--r--drivers/scsi/initio.c7
-rw-r--r--drivers/scsi/ipr.c49
-rw-r--r--drivers/scsi/ips.c29
-rw-r--r--drivers/scsi/ips.h11
-rw-r--r--drivers/scsi/iscsi_tcp.c22
-rw-r--r--drivers/scsi/libsas/sas_ata.c11
-rw-r--r--drivers/scsi/libsas/sas_discover.c8
-rw-r--r--drivers/scsi/libsrp.c5
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c5
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c4
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c10
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c10
-rw-r--r--drivers/scsi/mac53c94.c1
-rw-r--r--drivers/scsi/mac_scsi.c9
-rw-r--r--drivers/scsi/megaraid.c12
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c15
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c1
-rw-r--r--drivers/scsi/mesh.c1
-rw-r--r--drivers/scsi/mvme16x_scsi.c3
-rw-r--r--drivers/scsi/ncr53c8xx.c18
-rw-r--r--drivers/scsi/ncr53c8xx.h2
-rw-r--r--drivers/scsi/nsp32.c1
-rw-r--r--drivers/scsi/nsp32.h5
-rw-r--r--drivers/scsi/oktagon_esp.c6
-rw-r--r--drivers/scsi/osst.c61
-rw-r--r--drivers/scsi/osst.h3
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c159
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.h11
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c7
-rw-r--r--drivers/scsi/pluto.c352
-rw-r--r--drivers/scsi/pluto.h47
-rw-r--r--drivers/scsi/ppa.c7
-rw-r--r--drivers/scsi/ps3rom.c30
-rw-r--r--drivers/scsi/qla1280.c76
-rw-r--r--drivers/scsi/qla1280.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c209
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c1846
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h16
-rw-r--r--drivers/scsi/qla2xxx/qla_devtbl.h7
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h6
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h9
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c6
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c40
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c6
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c96
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c64
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c40
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c182
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c245
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c2
-rw-r--r--drivers/scsi/qla4xxx/ql4_iocb.c2
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c3
-rw-r--r--drivers/scsi/qlogicfas.c3
-rw-r--r--drivers/scsi/qlogicfas408.c2
-rw-r--r--drivers/scsi/qlogicpti.c186
-rw-r--r--drivers/scsi/qlogicpti.h3
-rw-r--r--drivers/scsi/scsi.c26
-rw-r--r--drivers/scsi/scsi_debug.c30
-rw-r--r--drivers/scsi/scsi_devinfo.c1
-rw-r--r--drivers/scsi/scsi_error.c163
-rw-r--r--drivers/scsi/scsi_lib.c525
-rw-r--r--drivers/scsi/scsi_netlink.c27
-rw-r--r--drivers/scsi/scsi_priv.h1
-rw-r--r--drivers/scsi/scsi_scan.c51
-rw-r--r--drivers/scsi/scsi_sysfs.c238
-rw-r--r--drivers/scsi/scsi_tgt_if.c42
-rw-r--r--drivers/scsi/scsi_tgt_lib.c89
-rw-r--r--drivers/scsi/scsi_tgt_priv.h22
-rw-r--r--drivers/scsi/scsi_transport_fc.c35
-rw-r--r--drivers/scsi/scsi_transport_fc_internal.h26
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c84
-rw-r--r--drivers/scsi/scsi_transport_srp.c381
-rw-r--r--drivers/scsi/scsi_transport_srp_internal.h25
-rw-r--r--drivers/scsi/sd.c100
-rw-r--r--drivers/scsi/seagate.c8
-rw-r--r--drivers/scsi/sg.c307
-rw-r--r--drivers/scsi/sr.c80
-rw-r--r--drivers/scsi/st.c16
-rw-r--r--drivers/scsi/stex.c1
-rw-r--r--drivers/scsi/sun3_NCR5380.c27
-rw-r--r--drivers/scsi/sun3x_esp.c4
-rw-r--r--drivers/scsi/sym53c416.c3
-rw-r--r--drivers/scsi/sym53c8xx_2/sym53c8xx.h1
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw.c18
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw.h2
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw2.h2
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c582
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.h16
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_hipd.c159
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_hipd.h22
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_nvram.c2
-rw-r--r--drivers/scsi/tmscsim.c23
-rw-r--r--drivers/scsi/u14-34f.c47
-rw-r--r--drivers/scsi/ultrastor.c3
-rw-r--r--drivers/scsi/wd33c93.c38
-rw-r--r--drivers/scsi/wd33c93.h2
-rw-r--r--drivers/scsi/wd7000.c3
-rw-r--r--drivers/scsi/zorro7xx.c8
-rw-r--r--drivers/serial/8250_early.c4
-rw-r--r--drivers/serial/8250_pci.c125
-rw-r--r--drivers/serial/8250_pnp.c12
-rw-r--r--drivers/serial/Kconfig33
-rw-r--r--drivers/serial/amba-pl011.c26
-rw-r--r--drivers/serial/atmel_serial.c9
-rw-r--r--drivers/serial/bfin_5xx.c222
-rw-r--r--drivers/serial/cpm_uart/cpm_uart.h48
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c539
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.c18
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.h16
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.c24
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.h16
-rw-r--r--drivers/serial/crisv10.c1340
-rw-r--r--drivers/serial/crisv10.h146
-rw-r--r--drivers/serial/jsm/jsm_tty.c43
-rw-r--r--drivers/serial/m32r_sio.c2
-rw-r--r--drivers/serial/m32r_sio.h6
-rw-r--r--drivers/serial/mcf.c653
-rw-r--r--drivers/serial/mpc52xx_uart.c10
-rw-r--r--drivers/serial/pmac_zilog.c22
-rw-r--r--drivers/serial/pxa.c163
-rw-r--r--drivers/serial/s3c2410.c4
-rw-r--r--drivers/serial/serial_core.c71
-rw-r--r--drivers/serial/serial_cs.c3
-rw-r--r--drivers/serial/serial_txx9.c40
-rw-r--r--drivers/serial/sh-sci.c39
-rw-r--r--drivers/serial/sh-sci.h53
-rw-r--r--drivers/serial/uartlite.c296
-rw-r--r--drivers/sh/Makefile4
-rw-r--r--drivers/sh/maple/Makefile3
-rw-r--r--drivers/sh/maple/maple.c734
-rw-r--r--drivers/sh/superhyway/superhyway.c7
-rw-r--r--drivers/spi/Kconfig13
-rw-r--r--drivers/spi/atmel_spi.c14
-rw-r--r--drivers/spi/mpc52xx_psc_spi.c4
-rw-r--r--drivers/spi/omap2_mcspi.c4
-rw-r--r--drivers/spi/omap_uwire.c9
-rw-r--r--drivers/spi/pxa2xx_spi.c14
-rw-r--r--drivers/spi/spi.c49
-rw-r--r--drivers/spi/spi_bfin5xx.c5
-rw-r--r--drivers/spi/spi_bitbang.c2
-rw-r--r--drivers/spi/spi_imx.c17
-rw-r--r--drivers/spi/spi_lm70llp.c2
-rw-r--r--drivers/spi/spi_mpc83xx.c7
-rw-r--r--drivers/spi/spi_s3c24xx.c9
-rw-r--r--drivers/spi/spi_txx9.c42
-rw-r--r--drivers/spi/spidev.c6
-rw-r--r--drivers/spi/tle62x0.c5
-rw-r--r--drivers/ssb/Kconfig117
-rw-r--r--drivers/ssb/Makefile18
-rw-r--r--drivers/ssb/b43_pci_bridge.c48
-rw-r--r--drivers/ssb/driver_chipcommon.c445
-rw-r--r--drivers/ssb/driver_extif.c129
-rw-r--r--drivers/ssb/driver_mipscore.c224
-rw-r--r--drivers/ssb/driver_pcicore.c576
-rw-r--r--drivers/ssb/main.c1161
-rw-r--r--drivers/ssb/pci.c740
-rw-r--r--drivers/ssb/pcihost_wrapper.c104
-rw-r--r--drivers/ssb/pcmcia.c272
-rw-r--r--drivers/ssb/scan.c413
-rw-r--r--drivers/ssb/ssb_private.h136
-rw-r--r--drivers/tc/.gitignore1
-rw-r--r--drivers/tc/Makefile15
-rw-r--r--drivers/tc/lk201-map.c_shipped265
-rw-r--r--drivers/tc/lk201-map.map356
-rw-r--r--drivers/tc/lk201-remap.c172
-rw-r--r--drivers/tc/lk201.c439
-rw-r--r--drivers/tc/lk201.h125
-rw-r--r--drivers/telephony/Kconfig2
-rw-r--r--drivers/telephony/phonedev.c5
-rw-r--r--drivers/usb/Makefile22
-rw-r--r--drivers/usb/atm/cxacru.c43
-rw-r--r--drivers/usb/atm/speedtch.c5
-rw-r--r--drivers/usb/atm/ueagle-atm.c1384
-rw-r--r--drivers/usb/atm/xusbatm.c2
-rw-r--r--drivers/usb/class/cdc-acm.c34
-rw-r--r--drivers/usb/class/usblp.c116
-rw-r--r--drivers/usb/core/buffer.c1
-rw-r--r--drivers/usb/core/config.c24
-rw-r--r--drivers/usb/core/devio.c85
-rw-r--r--drivers/usb/core/driver.c119
-rw-r--r--drivers/usb/core/endpoint.c3
-rw-r--r--drivers/usb/core/generic.c26
-rw-r--r--drivers/usb/core/hcd.c719
-rw-r--r--drivers/usb/core/hcd.h46
-rw-r--r--drivers/usb/core/hub.c283
-rw-r--r--drivers/usb/core/message.c100
-rw-r--r--drivers/usb/core/quirks.c81
-rw-r--r--drivers/usb/core/sysfs.c50
-rw-r--r--drivers/usb/core/urb.c106
-rw-r--r--drivers/usb/core/usb.c44
-rw-r--r--drivers/usb/core/usb.h5
-rw-r--r--drivers/usb/gadget/Kconfig26
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/amd5536udc.c11
-rw-r--r--drivers/usb/gadget/at91_udc.c2
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c2077
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.h352
-rw-r--r--drivers/usb/gadget/config.c2
-rw-r--r--drivers/usb/gadget/dummy_hcd.c93
-rw-r--r--drivers/usb/gadget/epautoconf.c2
-rw-r--r--drivers/usb/gadget/ether.c156
-rw-r--r--drivers/usb/gadget/file_storage.c251
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.c13
-rw-r--r--drivers/usb/gadget/gmidi.c82
-rw-r--r--drivers/usb/gadget/goku_udc.c2
-rw-r--r--drivers/usb/gadget/inode.c46
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.c2
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.h2
-rw-r--r--drivers/usb/gadget/m66592-udc.c2
-rw-r--r--drivers/usb/gadget/net2280.c2
-rw-r--r--drivers/usb/gadget/omap_udc.c12
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c70
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.h1
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c2
-rw-r--r--drivers/usb/gadget/serial.c174
-rw-r--r--drivers/usb/gadget/usbstring.c2
-rw-r--r--drivers/usb/gadget/zero.c239
-rw-r--r--drivers/usb/host/Kconfig13
-rw-r--r--drivers/usb/host/ehci-au1xxx.c6
-rw-r--r--drivers/usb/host/ehci-hcd.c22
-rw-r--r--drivers/usb/host/ehci-hub.c2
-rw-r--r--drivers/usb/host/ehci-pci.c5
-rw-r--r--drivers/usb/host/ehci-ppc-soc.c6
-rw-r--r--drivers/usb/host/ehci-ps3.c2
-rw-r--r--drivers/usb/host/ehci-q.c99
-rw-r--r--drivers/usb/host/ehci-sched.c47
-rw-r--r--drivers/usb/host/isp116x-hcd.c61
-rw-r--r--drivers/usb/host/ohci-dbg.c8
-rw-r--r--drivers/usb/host/ohci-hcd.c239
-rw-r--r--drivers/usb/host/ohci-mem.c1
-rw-r--r--drivers/usb/host/ohci-pci.c22
-rw-r--r--drivers/usb/host/ohci-ppc-of.c5
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c5
-rw-r--r--drivers/usb/host/ohci-q.c187
-rw-r--r--drivers/usb/host/ohci-s3c2410.c2
-rw-r--r--drivers/usb/host/ohci-ssb.c249
-rw-r--r--drivers/usb/host/ohci.h39
-rw-r--r--drivers/usb/host/r8a66597-hcd.c172
-rw-r--r--drivers/usb/host/sl811-hcd.c76
-rw-r--r--drivers/usb/host/u132-hcd.c370
-rw-r--r--drivers/usb/host/uhci-debug.c4
-rw-r--r--drivers/usb/host/uhci-hcd.c2
-rw-r--r--drivers/usb/host/uhci-hcd.h16
-rw-r--r--drivers/usb/host/uhci-q.c89
-rw-r--r--drivers/usb/image/Kconfig2
-rw-r--r--drivers/usb/image/microtek.c37
-rw-r--r--drivers/usb/misc/adutux.c7
-rw-r--r--drivers/usb/misc/berry_charge.c7
-rw-r--r--drivers/usb/misc/cytherm.c6
-rw-r--r--drivers/usb/misc/emi26.c8
-rw-r--r--drivers/usb/misc/emi62.c8
-rw-r--r--drivers/usb/misc/ftdi-elan.c138
-rw-r--r--drivers/usb/misc/idmouse.c45
-rw-r--r--drivers/usb/misc/iowarrior.c19
-rw-r--r--drivers/usb/misc/legousbtower.c14
-rw-r--r--drivers/usb/misc/phidgetmotorcontrol.c2
-rw-r--r--drivers/usb/misc/rio500.c15
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c200
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.h130
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c63
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_init.c354
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_init.h1315
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_struct.h144
-rw-r--r--drivers/usb/misc/usblcd.c11
-rw-r--r--drivers/usb/misc/usbtest.c4
-rw-r--r--drivers/usb/misc/uss720.c4
-rw-r--r--drivers/usb/mon/mon_bin.c42
-rw-r--r--drivers/usb/mon/mon_main.c25
-rw-r--r--drivers/usb/mon/mon_text.c76
-rw-r--r--drivers/usb/mon/usb_mon.h2
-rw-r--r--drivers/usb/serial/ChangeLog.history2
-rw-r--r--drivers/usb/serial/Kconfig12
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/ark3116.c18
-rw-r--r--drivers/usb/serial/bus.c16
-rw-r--r--drivers/usb/serial/ch341.c356
-rw-r--r--drivers/usb/serial/console.c4
-rw-r--r--drivers/usb/serial/cp2101.c51
-rw-r--r--drivers/usb/serial/digi_acceleport.c16
-rw-r--r--drivers/usb/serial/empeg.c23
-rw-r--r--drivers/usb/serial/ftdi_sio.c44
-rw-r--r--drivers/usb/serial/ftdi_sio.h6
-rw-r--r--drivers/usb/serial/funsoft.c21
-rw-r--r--drivers/usb/serial/generic.c7
-rw-r--r--drivers/usb/serial/io_edgeport.c20
-rw-r--r--drivers/usb/serial/ipaq.c7
-rw-r--r--drivers/usb/serial/ipw.c18
-rw-r--r--drivers/usb/serial/ir-usb.c11
-rw-r--r--drivers/usb/serial/keyspan.c54
-rw-r--r--drivers/usb/serial/kl5kusb105.c28
-rw-r--r--drivers/usb/serial/kobil_sct.c147
-rw-r--r--drivers/usb/serial/mct_u232.c28
-rw-r--r--drivers/usb/serial/mos7720.c4
-rw-r--r--drivers/usb/serial/mos7840.c23
-rw-r--r--drivers/usb/serial/option.c5
-rw-r--r--drivers/usb/serial/oti6858.c4
-rw-r--r--drivers/usb/serial/pl2303.c13
-rw-r--r--drivers/usb/serial/pl2303.h2
-rw-r--r--drivers/usb/serial/safe_serial.c11
-rw-r--r--drivers/usb/serial/sierra.c12
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c8
-rw-r--r--drivers/usb/serial/usb-serial.c48
-rw-r--r--drivers/usb/serial/visor.c64
-rw-r--r--drivers/usb/serial/whiteheat.c11
-rw-r--r--drivers/usb/storage/Kconfig1
-rw-r--r--drivers/usb/storage/alauda.c16
-rw-r--r--drivers/usb/storage/datafab.c10
-rw-r--r--drivers/usb/storage/initializers.c14
-rw-r--r--drivers/usb/storage/initializers.h3
-rw-r--r--drivers/usb/storage/isd200.c107
-rw-r--r--drivers/usb/storage/jumpshot.c10
-rw-r--r--drivers/usb/storage/libusual.c4
-rw-r--r--drivers/usb/storage/protocol.c22
-rw-r--r--drivers/usb/storage/protocol.h2
-rw-r--r--drivers/usb/storage/sddr09.c16
-rw-r--r--drivers/usb/storage/sddr55.c16
-rw-r--r--drivers/usb/storage/shuttle_usbat.c20
-rw-r--r--drivers/usb/storage/transport.c46
-rw-r--r--drivers/usb/storage/unusual_devs.h38
-rw-r--r--drivers/usb/storage/usb.c9
-rw-r--r--drivers/usb/usb-skeleton.c1
-rw-r--r--drivers/video/Kconfig70
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/amifb.c16
-rw-r--r--drivers/video/arcfb.c2
-rw-r--r--drivers/video/atafb.c2
-rw-r--r--drivers/video/aty/ati_ids.h1
-rw-r--r--drivers/video/aty/aty128fb.c2
-rw-r--r--drivers/video/aty/atyfb.h1
-rw-r--r--drivers/video/aty/atyfb_base.c8
-rw-r--r--drivers/video/aty/mach64_cursor.c1
-rw-r--r--drivers/video/aty/radeon_base.c5
-rw-r--r--drivers/video/aty/radeon_pm.c4
-rw-r--r--drivers/video/aty/radeonfb.h4
-rw-r--r--drivers/video/au1100fb.c2
-rw-r--r--drivers/video/backlight/Kconfig23
-rw-r--r--drivers/video/backlight/Makefile2
-rw-r--r--drivers/video/backlight/backlight.c2
-rw-r--r--drivers/video/backlight/corgi_bl.c22
-rw-r--r--drivers/video/backlight/cr_bllcd.c36
-rw-r--r--drivers/video/backlight/hp680_bl.c4
-rw-r--r--drivers/video/backlight/lcd.c2
-rw-r--r--drivers/video/backlight/ltv350qv.c330
-rw-r--r--drivers/video/backlight/ltv350qv.h95
-rw-r--r--drivers/video/backlight/progear_bl.c1
-rw-r--r--drivers/video/bf54x-lq043fb.c786
-rw-r--r--drivers/video/cfbcopyarea.c103
-rw-r--r--drivers/video/cfbfillrect.c20
-rw-r--r--drivers/video/cfbimgblt.c17
-rw-r--r--drivers/video/cg6.c294
-rw-r--r--drivers/video/cirrusfb.c2052
-rw-r--r--drivers/video/clps711xfb.c2
-rw-r--r--drivers/video/console/Kconfig2
-rw-r--r--drivers/video/console/dummycon.c4
-rw-r--r--drivers/video/console/fbcon.c5
-rw-r--r--drivers/video/console/font_10x18.c14
-rw-r--r--drivers/video/console/font_6x11.c13
-rw-r--r--drivers/video/console/font_7x14.c12
-rw-r--r--drivers/video/console/font_8x16.c14
-rw-r--r--drivers/video/console/font_8x8.c12
-rw-r--r--drivers/video/console/font_acorn_8x8.c14
-rw-r--r--drivers/video/console/font_mini_4x6.c12
-rw-r--r--drivers/video/console/font_pearl_8x8.c12
-rw-r--r--drivers/video/console/font_sun12x22.c14
-rw-r--r--drivers/video/console/font_sun8x16.c14
-rw-r--r--drivers/video/console/newport_con.c20
-rw-r--r--drivers/video/console/softcursor.c1
-rw-r--r--drivers/video/console/vgacon.c58
-rw-r--r--drivers/video/cyber2000fb.c239
-rw-r--r--drivers/video/epson1355fb.c2
-rw-r--r--drivers/video/fb_defio.c1
-rw-r--r--drivers/video/fb_draw.h94
-rw-r--r--drivers/video/fb_sys_fops.c2
-rw-r--r--drivers/video/fbcmap.c3
-rw-r--r--drivers/video/fbmem.c5
-rw-r--r--drivers/video/fbmon.c4
-rw-r--r--drivers/video/ffb.c161
-rw-r--r--drivers/video/gbefb.c4
-rw-r--r--drivers/video/geode/lxfb.h2
-rw-r--r--drivers/video/geode/lxfb_core.c7
-rw-r--r--drivers/video/geode/video_gx.c2
-rw-r--r--drivers/video/gxt4500.c2
-rw-r--r--drivers/video/hecubafb.c2
-rw-r--r--drivers/video/imacfb.c2
-rw-r--r--drivers/video/imsttfb.c2
-rw-r--r--drivers/video/imxfb.c4
-rw-r--r--drivers/video/intelfb/intelfb.h17
-rw-r--r--drivers/video/intelfb/intelfb_i2c.c60
-rw-r--r--drivers/video/intelfb/intelfbdrv.c185
-rw-r--r--drivers/video/intelfb/intelfbhw.c320
-rw-r--r--drivers/video/intelfb/intelfbhw.h52
-rw-r--r--drivers/video/kyro/fbdev.c2
-rw-r--r--drivers/video/logo/logo.c17
-rw-r--r--drivers/video/matrox/matroxfb_base.c2
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.c2
-rw-r--r--drivers/video/matrox/matroxfb_g450.c1
-rw-r--r--drivers/video/matrox/matroxfb_maven.c1
-rw-r--r--drivers/video/mbx/mbxfb.c344
-rw-r--r--drivers/video/mbx/reg_bits.h87
-rw-r--r--drivers/video/mbx/regs.h2
-rw-r--r--drivers/video/modedb.c60
-rw-r--r--drivers/video/neofb.c1
-rw-r--r--drivers/video/nvidia/nv_i2c.c10
-rw-r--r--drivers/video/nvidia/nv_type.h1
-rw-r--r--drivers/video/nvidia/nvidia.c6
-rw-r--r--drivers/video/omap/Kconfig4
-rw-r--r--drivers/video/omap/blizzard.c2
-rw-r--r--drivers/video/omap/dispc.c6
-rw-r--r--drivers/video/omap/hwa742.c2
-rw-r--r--drivers/video/omap/lcd_h3.c6
-rw-r--r--drivers/video/omap/lcd_inn1610.c6
-rw-r--r--drivers/video/omap/rfbi.c4
-rw-r--r--drivers/video/output.c29
-rw-r--r--drivers/video/platinumfb.c48
-rw-r--r--drivers/video/pm2fb.c883
-rw-r--r--drivers/video/pm3fb.c557
-rw-r--r--drivers/video/pmag-ba-fb.c34
-rw-r--r--drivers/video/pmagb-b-fb.c34
-rw-r--r--drivers/video/pnx4008/pnxrgbfb.c1
-rw-r--r--drivers/video/pnx4008/sdum.h3
-rw-r--r--drivers/video/ps3fb.c513
-rw-r--r--drivers/video/pvr2fb.c6
-rw-r--r--drivers/video/pxafb.c101
-rw-r--r--drivers/video/pxafb.h3
-rw-r--r--drivers/video/s1d13xxxfb.c5
-rw-r--r--drivers/video/s3c2410fb.c787
-rw-r--r--drivers/video/s3c2410fb.h13
-rw-r--r--drivers/video/s3fb.c24
-rw-r--r--drivers/video/sa1100fb.c1
-rw-r--r--drivers/video/savage/savagefb_driver.c1
-rw-r--r--drivers/video/sis/sis_main.c5
-rw-r--r--drivers/video/skeletonfb.c2
-rw-r--r--drivers/video/sm501fb.c49
-rw-r--r--drivers/video/sstfb.c2
-rw-r--r--drivers/video/svgalib.c47
-rw-r--r--drivers/video/tdfxfb.c1255
-rw-r--r--drivers/video/tgafb.c20
-rw-r--r--drivers/video/tridentfb.c1075
-rw-r--r--drivers/video/uvesafb.c2068
-rw-r--r--drivers/video/vermilion/vermilion.c5
-rw-r--r--drivers/video/vermilion/vermilion.h2
-rw-r--r--drivers/video/vfb.c79
-rw-r--r--drivers/video/vga16fb.c2
-rw-r--r--drivers/video/xilinxfb.c353
-rw-r--r--drivers/virtio/Kconfig8
-rw-r--r--drivers/virtio/Makefile2
-rw-r--r--drivers/virtio/config.c13
-rw-r--r--drivers/virtio/virtio.c189
-rw-r--r--drivers/virtio/virtio_ring.c319
-rw-r--r--drivers/w1/Kconfig3
-rw-r--r--drivers/w1/masters/ds1wm.c2
-rw-r--r--drivers/w1/masters/ds2490.c2
-rw-r--r--drivers/w1/masters/matrox_w1.c1
-rw-r--r--drivers/w1/w1.c19
-rw-r--r--drivers/watchdog/Kconfig (renamed from drivers/char/watchdog/Kconfig)17
-rw-r--r--drivers/watchdog/Makefile (renamed from drivers/char/watchdog/Makefile)1
-rw-r--r--drivers/watchdog/acquirewdt.c (renamed from drivers/char/watchdog/acquirewdt.c)0
-rw-r--r--drivers/watchdog/advantechwdt.c (renamed from drivers/char/watchdog/advantechwdt.c)0
-rw-r--r--drivers/watchdog/alim1535_wdt.c (renamed from drivers/char/watchdog/alim1535_wdt.c)4
-rw-r--r--drivers/watchdog/alim7101_wdt.c (renamed from drivers/char/watchdog/alim7101_wdt.c)0
-rw-r--r--drivers/watchdog/ar7_wdt.c349
-rw-r--r--drivers/watchdog/at32ap700x_wdt.c (renamed from drivers/char/watchdog/at32ap700x_wdt.c)0
-rw-r--r--drivers/watchdog/at91rm9200_wdt.c (renamed from drivers/char/watchdog/at91rm9200_wdt.c)2
-rw-r--r--drivers/watchdog/bfin_wdt.c (renamed from drivers/char/watchdog/bfin_wdt.c)0
-rw-r--r--drivers/watchdog/booke_wdt.c (renamed from drivers/char/watchdog/booke_wdt.c)0
-rw-r--r--drivers/watchdog/cpu5wdt.c (renamed from drivers/char/watchdog/cpu5wdt.c)0
-rw-r--r--drivers/watchdog/davinci_wdt.c (renamed from drivers/char/watchdog/davinci_wdt.c)6
-rw-r--r--drivers/watchdog/ep93xx_wdt.c (renamed from drivers/char/watchdog/ep93xx_wdt.c)0
-rw-r--r--drivers/watchdog/eurotechwdt.c (renamed from drivers/char/watchdog/eurotechwdt.c)0
-rw-r--r--drivers/watchdog/i6300esb.c (renamed from drivers/char/watchdog/i6300esb.c)10
-rw-r--r--drivers/watchdog/iTCO_vendor_support.c (renamed from drivers/char/watchdog/iTCO_vendor_support.c)2
-rw-r--r--drivers/watchdog/iTCO_wdt.c (renamed from drivers/char/watchdog/iTCO_wdt.c)114
-rw-r--r--drivers/watchdog/ib700wdt.c (renamed from drivers/char/watchdog/ib700wdt.c)4
-rw-r--r--drivers/watchdog/ibmasr.c (renamed from drivers/char/watchdog/ibmasr.c)0
-rw-r--r--drivers/watchdog/indydog.c (renamed from drivers/char/watchdog/indydog.c)0
-rw-r--r--drivers/watchdog/iop_wdt.c (renamed from drivers/char/watchdog/iop_wdt.c)0
-rw-r--r--drivers/watchdog/ixp2000_wdt.c (renamed from drivers/char/watchdog/ixp2000_wdt.c)0
-rw-r--r--drivers/watchdog/ixp4xx_wdt.c (renamed from drivers/char/watchdog/ixp4xx_wdt.c)0
-rw-r--r--drivers/watchdog/ks8695_wdt.c (renamed from drivers/char/watchdog/ks8695_wdt.c)2
-rw-r--r--drivers/watchdog/machzwd.c (renamed from drivers/char/watchdog/machzwd.c)7
-rw-r--r--drivers/watchdog/mixcomwd.c (renamed from drivers/char/watchdog/mixcomwd.c)0
-rw-r--r--drivers/watchdog/mpc5200_wdt.c (renamed from drivers/char/watchdog/mpc5200_wdt.c)5
-rw-r--r--drivers/watchdog/mpc83xx_wdt.c (renamed from drivers/char/watchdog/mpc83xx_wdt.c)5
-rw-r--r--drivers/watchdog/mpc8xx_wdt.c (renamed from drivers/char/watchdog/mpc8xx_wdt.c)0
-rw-r--r--drivers/watchdog/mpcore_wdt.c (renamed from drivers/char/watchdog/mpcore_wdt.c)0
-rw-r--r--drivers/watchdog/mtx-1_wdt.c (renamed from drivers/char/watchdog/mtx-1_wdt.c)0
-rw-r--r--drivers/watchdog/mv64x60_wdt.c (renamed from drivers/char/watchdog/mv64x60_wdt.c)0
-rw-r--r--drivers/watchdog/omap_wdt.c (renamed from drivers/char/watchdog/omap_wdt.c)2
-rw-r--r--drivers/watchdog/omap_wdt.h (renamed from drivers/char/watchdog/omap_wdt.h)0
-rw-r--r--drivers/watchdog/pc87413_wdt.c (renamed from drivers/char/watchdog/pc87413_wdt.c)4
-rw-r--r--drivers/watchdog/pcwd.c (renamed from drivers/char/watchdog/pcwd.c)0
-rw-r--r--drivers/watchdog/pcwd_pci.c (renamed from drivers/char/watchdog/pcwd_pci.c)0
-rw-r--r--drivers/watchdog/pcwd_usb.c (renamed from drivers/char/watchdog/pcwd_usb.c)0
-rw-r--r--drivers/watchdog/pnx4008_wdt.c (renamed from drivers/char/watchdog/pnx4008_wdt.c)6
-rw-r--r--drivers/watchdog/rm9k_wdt.c (renamed from drivers/char/watchdog/rm9k_wdt.c)0
-rw-r--r--drivers/watchdog/s3c2410_wdt.c (renamed from drivers/char/watchdog/s3c2410_wdt.c)0
-rw-r--r--drivers/watchdog/sa1100_wdt.c (renamed from drivers/char/watchdog/sa1100_wdt.c)2
-rw-r--r--drivers/watchdog/sbc60xxwdt.c (renamed from drivers/char/watchdog/sbc60xxwdt.c)0
-rw-r--r--drivers/watchdog/sbc8360.c (renamed from drivers/char/watchdog/sbc8360.c)3
-rw-r--r--drivers/watchdog/sbc_epx_c3.c (renamed from drivers/char/watchdog/sbc_epx_c3.c)0
-rw-r--r--drivers/watchdog/sc1200wdt.c (renamed from drivers/char/watchdog/sc1200wdt.c)3
-rw-r--r--drivers/watchdog/sc520_wdt.c (renamed from drivers/char/watchdog/sc520_wdt.c)4
-rw-r--r--drivers/watchdog/scx200_wdt.c (renamed from drivers/char/watchdog/scx200_wdt.c)0
-rw-r--r--drivers/watchdog/shwdt.c (renamed from drivers/char/watchdog/shwdt.c)0
-rw-r--r--drivers/watchdog/smsc37b787_wdt.c (renamed from drivers/char/watchdog/smsc37b787_wdt.c)4
-rw-r--r--drivers/watchdog/softdog.c (renamed from drivers/char/watchdog/softdog.c)0
-rw-r--r--drivers/watchdog/w83627hf_wdt.c (renamed from drivers/char/watchdog/w83627hf_wdt.c)4
-rw-r--r--drivers/watchdog/w83697hf_wdt.c (renamed from drivers/char/watchdog/w83697hf_wdt.c)6
-rw-r--r--drivers/watchdog/w83877f_wdt.c (renamed from drivers/char/watchdog/w83877f_wdt.c)4
-rw-r--r--drivers/watchdog/w83977f_wdt.c (renamed from drivers/char/watchdog/w83977f_wdt.c)4
-rw-r--r--drivers/watchdog/wafer5823wdt.c (renamed from drivers/char/watchdog/wafer5823wdt.c)4
-rw-r--r--drivers/watchdog/wd501p.h (renamed from drivers/char/watchdog/wd501p.h)0
-rw-r--r--drivers/watchdog/wdrtas.c (renamed from drivers/char/watchdog/wdrtas.c)0
-rw-r--r--drivers/watchdog/wdt.c (renamed from drivers/char/watchdog/wdt.c)3
-rw-r--r--drivers/watchdog/wdt285.c (renamed from drivers/char/watchdog/wdt285.c)0
-rw-r--r--drivers/watchdog/wdt977.c (renamed from drivers/char/watchdog/wdt977.c)4
-rw-r--r--drivers/watchdog/wdt_pci.c (renamed from drivers/char/watchdog/wdt_pci.c)6
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c5
-rw-r--r--drivers/zorro/zorro.ids2
2809 files changed, 322825 insertions, 120651 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 3e1c442deff..f4076d9e990 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -58,6 +58,10 @@ source "drivers/power/Kconfig"
source "drivers/hwmon/Kconfig"
+source "drivers/watchdog/Kconfig"
+
+source "drivers/ssb/Kconfig"
+
source "drivers/mfd/Kconfig"
source "drivers/media/Kconfig"
@@ -82,11 +86,13 @@ source "drivers/rtc/Kconfig"
source "drivers/dma/Kconfig"
+source "drivers/dca/Kconfig"
+
source "drivers/auxdisplay/Kconfig"
source "drivers/kvm/Kconfig"
source "drivers/uio/Kconfig"
-source "drivers/lguest/Kconfig"
+source "drivers/virtio/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 10a9c52c910..8cb37e3557d 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -34,7 +34,6 @@ obj-$(CONFIG_NUBUS) += nubus/
obj-$(CONFIG_ATM) += atm/
obj-y += macintosh/
obj-$(CONFIG_IDE) += ide/
-obj-$(CONFIG_FC4) += fc4/
obj-$(CONFIG_SCSI) += scsi/
obj-$(CONFIG_ATA) += ata/
obj-$(CONFIG_FUSION) += message/
@@ -66,7 +65,7 @@ obj-y += i2c/
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_POWER_SUPPLY) += power/
obj-$(CONFIG_HWMON) += hwmon/
-obj-$(CONFIG_WATCHDOG) += char/watchdog/
+obj-$(CONFIG_WATCHDOG) += watchdog/
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/
@@ -86,6 +85,9 @@ obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
obj-$(CONFIG_GENERIC_TIME) += clocksource/
obj-$(CONFIG_DMA_ENGINE) += dma/
+obj-$(CONFIG_DCA) += dca/
obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_OF) += of/
+obj-$(CONFIG_SSB) += ssb/
+obj-$(CONFIG_VIRTIO) += virtio/
diff --git a/drivers/acorn/char/defkeymap-l7200.c b/drivers/acorn/char/defkeymap-l7200.c
index 9e18ce742e3..28a5fbc6aa1 100644
--- a/drivers/acorn/char/defkeymap-l7200.c
+++ b/drivers/acorn/char/defkeymap-l7200.c
@@ -346,7 +346,7 @@ char *func_table[MAX_NR_FUNC] = {
0,
};
-struct kbdiacr accent_table[MAX_DIACR] = {
+struct kbdiacruc accent_table[MAX_DIACR] = {
{'`', 'A', '\300'}, {'`', 'a', '\340'},
{'\'', 'A', '\301'}, {'\'', 'a', '\341'},
{'^', 'A', '\302'}, {'^', 'a', '\342'},
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 4875f0149eb..087a7028ae8 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig ACPI
- bool "ACPI Support (Advanced Configuration and Power Interface) Support"
+ bool "ACPI (Advanced Configuration and Power Interface) Support"
depends on !X86_NUMAQ
depends on !X86_VISWS
depends on !IA64_HP_SIM
@@ -50,9 +50,10 @@ config ACPI_SLEEP
config ACPI_PROCFS
bool "Deprecated /proc/acpi files"
depends on PROC_FS
+ default y
---help---
For backwards compatibility, this option allows
- depricated /proc/acpi/ files to exist, even when
+ deprecated /proc/acpi/ files to exist, even when
they have been replaced by functions in /sys.
The deprecated files (and their replacements) include:
@@ -60,6 +61,7 @@ config ACPI_PROCFS
/proc/acpi/info (/sys/modules/acpi/parameters/acpica_version)
/proc/acpi/dsdt (/sys/firmware/acpi/tables/DSDT)
/proc/acpi/fadt (/sys/firmware/acpi/tables/FACP)
+ /proc/acpi/battery (/sys/class/power_supply)
/proc/acpi/debug_layer (/sys/module/acpi/parameters/debug_layer)
/proc/acpi/debug_level (/sys/module/acpi/parameters/debug_level)
@@ -89,6 +91,7 @@ config ACPI_PROC_EVENT
config ACPI_AC
tristate "AC Adapter"
depends on X86
+ select POWER_SUPPLY
default y
help
This driver adds support for the AC Adapter object, which indicates
@@ -98,6 +101,7 @@ config ACPI_AC
config ACPI_BATTERY
tristate "Battery"
depends on X86
+ select POWER_SUPPLY
default y
help
This driver adds support for battery information through
@@ -117,6 +121,7 @@ config ACPI_BUTTON
config ACPI_VIDEO
tristate "Video"
depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
+ depends on INPUT
help
This driver implement the ACPI Extensions For Display Adapters
for integrated graphics devices on motherboard, as specified in
@@ -349,12 +354,11 @@ config ACPI_HOTPLUG_MEMORY
$>modprobe acpi_memhotplug
config ACPI_SBS
- tristate "Smart Battery System (EXPERIMENTAL)"
+ tristate "Smart Battery System"
depends on X86
- depends on EXPERIMENTAL
+ select POWER_SUPPLY
help
- This driver adds support for the Smart Battery System.
- A "Smart Battery" is quite old and quite rare compared
- to today's ACPI "Control Method" battery.
+ This driver adds support for the Smart Battery System, another
+ type of access to battery information, found on some laptops.
endif # ACPI
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index d4336f1730e..54e3ab0e5fc 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -60,3 +60,4 @@ obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
obj-y += cm_sbs.o
obj-$(CONFIG_ACPI_SBS) += sbs.o
+obj-$(CONFIG_ACPI_SBS) += sbshc.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 26d70702b31..30238f6ff23 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -27,8 +27,11 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
+#ifdef CONFIG_ACPI_PROCFS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#endif
+#include <linux/power_supply.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -48,12 +51,15 @@ MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION("ACPI AC Adapter Driver");
MODULE_LICENSE("GPL");
+#ifdef CONFIG_ACPI_PROCFS
extern struct proc_dir_entry *acpi_lock_ac_dir(void);
extern void *acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
+static int acpi_ac_open_fs(struct inode *inode, struct file *file);
+#endif
static int acpi_ac_add(struct acpi_device *device);
static int acpi_ac_remove(struct acpi_device *device, int type);
-static int acpi_ac_open_fs(struct inode *inode, struct file *file);
+static int acpi_ac_resume(struct acpi_device *device);
const static struct acpi_device_id ac_device_ids[] = {
{"ACPI0003", 0},
@@ -68,20 +74,45 @@ static struct acpi_driver acpi_ac_driver = {
.ops = {
.add = acpi_ac_add,
.remove = acpi_ac_remove,
+ .resume = acpi_ac_resume,
},
};
struct acpi_ac {
+ struct power_supply charger;
struct acpi_device * device;
unsigned long state;
};
+#define to_acpi_ac(x) container_of(x, struct acpi_ac, charger);
+
+#ifdef CONFIG_ACPI_PROCFS
static const struct file_operations acpi_ac_fops = {
.open = acpi_ac_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.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
@@ -105,6 +136,7 @@ static int acpi_ac_get_state(struct acpi_ac *ac)
return 0;
}
+#ifdef CONFIG_ACPI_PROCFS
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
@@ -184,6 +216,7 @@ static int acpi_ac_remove_fs(struct acpi_device *device)
return 0;
}
+#endif
/* --------------------------------------------------------------------------
Driver Model
@@ -208,6 +241,7 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
acpi_bus_generate_netlink_event(device->pnp.device_class,
device->dev.bus_id, event,
(u32) ac->state);
+ kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -241,10 +275,17 @@ static int acpi_ac_add(struct acpi_device *device)
if (result)
goto end;
+#ifdef CONFIG_ACPI_PROCFS
result = acpi_ac_add_fs(device);
+#endif
if (result)
goto end;
-
+ ac->charger.name = acpi_device_bid(device);
+ ac->charger.type = POWER_SUPPLY_TYPE_MAINS;
+ ac->charger.properties = ac_props;
+ ac->charger.num_properties = ARRAY_SIZE(ac_props);
+ ac->charger.get_property = get_ac_property;
+ power_supply_register(&ac->device->dev, &ac->charger);
status = acpi_install_notify_handler(device->handle,
ACPI_ALL_NOTIFY, acpi_ac_notify,
ac);
@@ -259,13 +300,30 @@ static int acpi_ac_add(struct acpi_device *device)
end:
if (result) {
+#ifdef CONFIG_ACPI_PROCFS
acpi_ac_remove_fs(device);
+#endif
kfree(ac);
}
return result;
}
+static int acpi_ac_resume(struct acpi_device *device)
+{
+ struct acpi_ac *ac;
+ unsigned old_state;
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+ ac = acpi_driver_data(device);
+ old_state = ac->state;
+ if (acpi_ac_get_state(ac))
+ return 0;
+ if (old_state != ac->state)
+ kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
+ return 0;
+}
+
static int acpi_ac_remove(struct acpi_device *device, int type)
{
acpi_status status = AE_OK;
@@ -279,8 +337,11 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
status = acpi_remove_notify_handler(device->handle,
ACPI_ALL_NOTIFY, acpi_ac_notify);
-
+ if (ac->charger.dev)
+ power_supply_unregister(&ac->charger);
+#ifdef CONFIG_ACPI_PROCFS
acpi_ac_remove_fs(device);
+#endif
kfree(ac);
@@ -294,13 +355,17 @@ static int __init acpi_ac_init(void)
if (acpi_disabled)
return -ENODEV;
+#ifdef CONFIG_ACPI_PROCFS
acpi_ac_dir = acpi_lock_ac_dir();
if (!acpi_ac_dir)
return -ENODEV;
+#endif
result = acpi_bus_register_driver(&acpi_ac_driver);
if (result < 0) {
+#ifdef CONFIG_ACPI_PROCFS
acpi_unlock_ac_dir(acpi_ac_dir);
+#endif
return -ENODEV;
}
@@ -312,7 +377,9 @@ static void __exit acpi_ac_exit(void)
acpi_bus_unregister_driver(&acpi_ac_driver);
+#ifdef CONFIG_ACPI_PROCFS
acpi_unlock_ac_dir(acpi_ac_dir);
+#endif
return;
}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 9b2c0f74f86..2e8e790c118 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -1,6 +1,8 @@
/*
- * acpi_battery.c - ACPI Battery Driver ($Revision: 37 $)
+ * battery.c - ACPI Battery Driver (Revision: 2.0)
*
+ * Copyright (C) 2007 Alexey Starikovskiy <astarikovskiy@suse.de>
+ * Copyright (C) 2004-2007 Vladimir Lebedev <vladimir.p.lebedev@intel.com>
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
*
@@ -27,244 +29,301 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
+#include <linux/jiffies.h>
+
+#ifdef CONFIG_ACPI_PROCFS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
+#endif
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
-#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
+#include <linux/power_supply.h>
-#define ACPI_BATTERY_FORMAT_BIF "NNNNNNNNNSSSS"
-#define ACPI_BATTERY_FORMAT_BST "NNNN"
+#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
#define ACPI_BATTERY_COMPONENT 0x00040000
#define ACPI_BATTERY_CLASS "battery"
#define ACPI_BATTERY_DEVICE_NAME "Battery"
#define ACPI_BATTERY_NOTIFY_STATUS 0x80
#define ACPI_BATTERY_NOTIFY_INFO 0x81
-#define ACPI_BATTERY_UNITS_WATTS "mW"
-#define ACPI_BATTERY_UNITS_AMPS "mA"
#define _COMPONENT ACPI_BATTERY_COMPONENT
-#define ACPI_BATTERY_UPDATE_TIME 0
-
-#define ACPI_BATTERY_NONE_UPDATE 0
-#define ACPI_BATTERY_EASY_UPDATE 1
-#define ACPI_BATTERY_INIT_UPDATE 2
-
ACPI_MODULE_NAME("battery");
MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
MODULE_DESCRIPTION("ACPI Battery Driver");
MODULE_LICENSE("GPL");
-static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME;
-
-/* 0 - every time, > 0 - by update_time */
-module_param(update_time, uint, 0644);
+static unsigned int cache_time = 1000;
+module_param(cache_time, uint, 0644);
+MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
+#ifdef CONFIG_ACPI_PROCFS
extern struct proc_dir_entry *acpi_lock_battery_dir(void);
extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
-static int acpi_battery_add(struct acpi_device *device);
-static int acpi_battery_remove(struct acpi_device *device, int type);
-static int acpi_battery_resume(struct acpi_device *device);
+enum acpi_battery_files {
+ info_tag = 0,
+ state_tag,
+ alarm_tag,
+ ACPI_BATTERY_NUMFILES,
+};
+
+#endif
static const struct acpi_device_id battery_device_ids[] = {
{"PNP0C0A", 0},
{"", 0},
};
-MODULE_DEVICE_TABLE(acpi, battery_device_ids);
-
-static struct acpi_driver acpi_battery_driver = {
- .name = "battery",
- .class = ACPI_BATTERY_CLASS,
- .ids = battery_device_ids,
- .ops = {
- .add = acpi_battery_add,
- .resume = acpi_battery_resume,
- .remove = acpi_battery_remove,
- },
-};
-struct acpi_battery_state {
- acpi_integer state;
- acpi_integer present_rate;
- acpi_integer remaining_capacity;
- acpi_integer present_voltage;
-};
-
-struct acpi_battery_info {
- acpi_integer power_unit;
- acpi_integer design_capacity;
- acpi_integer last_full_capacity;
- acpi_integer battery_technology;
- acpi_integer design_voltage;
- acpi_integer design_capacity_warning;
- acpi_integer design_capacity_low;
- acpi_integer battery_capacity_granularity_1;
- acpi_integer battery_capacity_granularity_2;
- acpi_string model_number;
- acpi_string serial_number;
- acpi_string battery_type;
- acpi_string oem_info;
-};
-
-enum acpi_battery_files{
- ACPI_BATTERY_INFO = 0,
- ACPI_BATTERY_STATE,
- ACPI_BATTERY_ALARM,
- ACPI_BATTERY_NUMFILES,
-};
+MODULE_DEVICE_TABLE(acpi, battery_device_ids);
-struct acpi_battery_flags {
- u8 battery_present_prev;
- u8 alarm_present;
- u8 init_update;
- u8 update[ACPI_BATTERY_NUMFILES];
- u8 power_unit;
-};
struct acpi_battery {
- struct mutex mutex;
+ struct mutex lock;
+ struct power_supply bat;
struct acpi_device *device;
- struct acpi_battery_flags flags;
- struct acpi_buffer bif_data;
- struct acpi_buffer bst_data;
- unsigned long alarm;
- unsigned long update_time[ACPI_BATTERY_NUMFILES];
+ unsigned long update_time;
+ int current_now;
+ int capacity_now;
+ int voltage_now;
+ int design_capacity;
+ int full_charge_capacity;
+ int technology;
+ int design_voltage;
+ int design_capacity_warning;
+ int design_capacity_low;
+ int capacity_granularity_1;
+ int capacity_granularity_2;
+ int alarm;
+ char model_number[32];
+ char serial_number[32];
+ char type[32];
+ char oem_info[32];
+ int state;
+ int power_unit;
+ u8 alarm_present;
};
+#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
+
inline int acpi_battery_present(struct acpi_battery *battery)
{
return battery->device->status.battery_present;
}
-inline char *acpi_battery_power_units(struct acpi_battery *battery)
-{
- if (battery->flags.power_unit)
- return ACPI_BATTERY_UNITS_AMPS;
- else
- return ACPI_BATTERY_UNITS_WATTS;
-}
-inline acpi_handle acpi_battery_handle(struct acpi_battery *battery)
+static int acpi_battery_technology(struct acpi_battery *battery)
{
- return battery->device->handle;
+ if (!strcasecmp("NiCd", battery->type))
+ return POWER_SUPPLY_TECHNOLOGY_NiCd;
+ if (!strcasecmp("NiMH", battery->type))
+ return POWER_SUPPLY_TECHNOLOGY_NiMH;
+ if (!strcasecmp("LION", battery->type))
+ return POWER_SUPPLY_TECHNOLOGY_LION;
+ if (!strcasecmp("LI-ION", battery->type))
+ return POWER_SUPPLY_TECHNOLOGY_LION;
+ if (!strcasecmp("LiP", battery->type))
+ return POWER_SUPPLY_TECHNOLOGY_LIPO;
+ return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
}
-/* --------------------------------------------------------------------------
- Battery Management
- -------------------------------------------------------------------------- */
+static int acpi_battery_get_state(struct acpi_battery *battery);
-static void acpi_battery_check_result(struct acpi_battery *battery, int result)
+static int acpi_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
{
- if (!battery)
- return;
+ struct acpi_battery *battery = to_acpi_battery(psy);
- if (result) {
- battery->flags.init_update = 1;
+ if (acpi_battery_present(battery)) {
+ /* run battery update only if it is present */
+ acpi_battery_get_state(battery);
+ } else if (psp != POWER_SUPPLY_PROP_PRESENT)
+ return -ENODEV;
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ if (battery->state & 0x01)
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ else if (battery->state & 0x02)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else if (battery->state == 0)
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ else
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = acpi_battery_present(battery);
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = acpi_battery_technology(battery);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+ val->intval = battery->design_voltage * 1000;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = battery->voltage_now * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = battery->current_now * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+ val->intval = battery->design_capacity * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ case POWER_SUPPLY_PROP_ENERGY_FULL:
+ val->intval = battery->full_charge_capacity * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ case POWER_SUPPLY_PROP_ENERGY_NOW:
+ val->intval = battery->capacity_now * 1000;
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = battery->model_number;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = battery->oem_info;
+ break;
+ default:
+ return -EINVAL;
}
+ return 0;
}
-static int acpi_battery_extract_package(struct acpi_battery *battery,
- union acpi_object *package,
- struct acpi_buffer *format,
- struct acpi_buffer *data,
- char *package_name)
+static enum power_supply_property charge_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static enum power_supply_property energy_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
+ POWER_SUPPLY_PROP_ENERGY_FULL,
+ POWER_SUPPLY_PROP_ENERGY_NOW,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+#ifdef CONFIG_ACPI_PROCFS
+inline char *acpi_battery_units(struct acpi_battery *battery)
{
- acpi_status status = AE_OK;
- struct acpi_buffer data_null = { 0, NULL };
+ return (battery->power_unit)?"mA":"mW";
+}
+#endif
- status = acpi_extract_package(package, format, &data_null);
- if (status != AE_BUFFER_OVERFLOW) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s",
- package_name));
- return -ENODEV;
- }
+/* --------------------------------------------------------------------------
+ Battery Management
+ -------------------------------------------------------------------------- */
+struct acpi_offsets {
+ size_t offset; /* offset inside struct acpi_sbs_battery */
+ u8 mode; /* int or string? */
+};
- if (data_null.length != data->length) {
- kfree(data->pointer);
- data->pointer = kzalloc(data_null.length, GFP_KERNEL);
- if (!data->pointer) {
- ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()"));
- return -ENOMEM;
- }
- data->length = data_null.length;
- }
+static struct acpi_offsets state_offsets[] = {
+ {offsetof(struct acpi_battery, state), 0},
+ {offsetof(struct acpi_battery, current_now), 0},
+ {offsetof(struct acpi_battery, capacity_now), 0},
+ {offsetof(struct acpi_battery, voltage_now), 0},
+};
- status = acpi_extract_package(package, format, data);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting %s",
- package_name));
- return -ENODEV;
- }
+static struct acpi_offsets info_offsets[] = {
+ {offsetof(struct acpi_battery, power_unit), 0},
+ {offsetof(struct acpi_battery, design_capacity), 0},
+ {offsetof(struct acpi_battery, full_charge_capacity), 0},
+ {offsetof(struct acpi_battery, technology), 0},
+ {offsetof(struct acpi_battery, design_voltage), 0},
+ {offsetof(struct acpi_battery, design_capacity_warning), 0},
+ {offsetof(struct acpi_battery, design_capacity_low), 0},
+ {offsetof(struct acpi_battery, capacity_granularity_1), 0},
+ {offsetof(struct acpi_battery, capacity_granularity_2), 0},
+ {offsetof(struct acpi_battery, model_number), 1},
+ {offsetof(struct acpi_battery, serial_number), 1},
+ {offsetof(struct acpi_battery, type), 1},
+ {offsetof(struct acpi_battery, oem_info), 1},
+};
+static int extract_package(struct acpi_battery *battery,
+ union acpi_object *package,
+ struct acpi_offsets *offsets, int num)
+{
+ int i;
+ union acpi_object *element;
+ if (package->type != ACPI_TYPE_PACKAGE)
+ return -EFAULT;
+ for (i = 0; i < num; ++i) {
+ if (package->package.count <= i)
+ return -EFAULT;
+ element = &package->package.elements[i];
+ if (offsets[i].mode) {
+ u8 *ptr = (u8 *)battery + offsets[i].offset;
+ if (element->type == ACPI_TYPE_STRING ||
+ element->type == ACPI_TYPE_BUFFER)
+ strncpy(ptr, element->string.pointer, 32);
+ else if (element->type == ACPI_TYPE_INTEGER) {
+ strncpy(ptr, (u8 *)&element->integer.value,
+ sizeof(acpi_integer));
+ ptr[sizeof(acpi_integer)] = 0;
+ } else return -EFAULT;
+ } else {
+ if (element->type == ACPI_TYPE_INTEGER) {
+ int *x = (int *)((u8 *)battery +
+ offsets[i].offset);
+ *x = element->integer.value;
+ } else return -EFAULT;
+ }
+ }
return 0;
}
static int acpi_battery_get_status(struct acpi_battery *battery)
{
- int result = 0;
-
- result = acpi_bus_get_status(battery->device);
- if (result) {
+ if (acpi_bus_get_status(battery->device)) {
ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA"));
return -ENODEV;
}
- return result;
+ return 0;
}
static int acpi_battery_get_info(struct acpi_battery *battery)
{
- int result = 0;
+ int result = -EFAULT;
acpi_status status = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF),
- ACPI_BATTERY_FORMAT_BIF
- };
- union acpi_object *package = NULL;
- struct acpi_buffer *data = NULL;
- struct acpi_battery_info *bif = NULL;
-
- battery->update_time[ACPI_BATTERY_INFO] = get_seconds();
if (!acpi_battery_present(battery))
return 0;
+ mutex_lock(&battery->lock);
+ status = acpi_evaluate_object(battery->device->handle, "_BIF",
+ NULL, &buffer);
+ mutex_unlock(&battery->lock);
- /* Evaluate _BIF */
-
- status =
- acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL,
- &buffer);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
return -ENODEV;
}
- package = buffer.pointer;
-
- data = &battery->bif_data;
-
- /* Extract Package Data */
-
- result =
- acpi_battery_extract_package(battery, package, &format, data,
- "_BIF");
- if (result)
- goto end;
-
- end:
-
+ result = extract_package(battery, buffer.pointer,
+ info_offsets, ARRAY_SIZE(info_offsets));
kfree(buffer.pointer);
-
- if (!result) {
- bif = data->pointer;
- battery->flags.power_unit = bif->power_unit;
- }
-
return result;
}
@@ -273,342 +332,256 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
int result = 0;
acpi_status status = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST),
- ACPI_BATTERY_FORMAT_BST
- };
- union acpi_object *package = NULL;
- struct acpi_buffer *data = NULL;
-
- battery->update_time[ACPI_BATTERY_STATE] = get_seconds();
if (!acpi_battery_present(battery))
return 0;
- /* Evaluate _BST */
+ if (battery->update_time &&
+ time_before(jiffies, battery->update_time +
+ msecs_to_jiffies(cache_time)))
+ return 0;
+
+ mutex_lock(&battery->lock);
+ status = acpi_evaluate_object(battery->device->handle, "_BST",
+ NULL, &buffer);
+ mutex_unlock(&battery->lock);
- status =
- acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL,
- &buffer);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
return -ENODEV;
}
- package = buffer.pointer;
-
- data = &battery->bst_data;
-
- /* Extract Package Data */
-
- result =
- acpi_battery_extract_package(battery, package, &format, data,
- "_BST");
- if (result)
- goto end;
-
- end:
+ result = extract_package(battery, buffer.pointer,
+ state_offsets, ARRAY_SIZE(state_offsets));
+ battery->update_time = jiffies;
kfree(buffer.pointer);
-
return result;
}
-static int acpi_battery_get_alarm(struct acpi_battery *battery)
-{
- battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
-
- return 0;
-}
-
-static int acpi_battery_set_alarm(struct acpi_battery *battery,
- unsigned long alarm)
+static int acpi_battery_set_alarm(struct acpi_battery *battery)
{
acpi_status status = 0;
- union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+ union acpi_object arg0 = { .type = ACPI_TYPE_INTEGER };
struct acpi_object_list arg_list = { 1, &arg0 };
- battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
-
- if (!acpi_battery_present(battery))
+ if (!acpi_battery_present(battery)|| !battery->alarm_present)
return -ENODEV;
- if (!battery->flags.alarm_present)
- return -ENODEV;
+ arg0.integer.value = battery->alarm;
- arg0.integer.value = alarm;
-
- status =
- acpi_evaluate_object(acpi_battery_handle(battery), "_BTP",
+ mutex_lock(&battery->lock);
+ status = acpi_evaluate_object(battery->device->handle, "_BTP",
&arg_list, NULL);
+ mutex_unlock(&battery->lock);
+
if (ACPI_FAILURE(status))
return -ENODEV;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", (u32) alarm));
-
- battery->alarm = alarm;
-
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", battery->alarm));
return 0;
}
static int acpi_battery_init_alarm(struct acpi_battery *battery)
{
- int result = 0;
acpi_status status = AE_OK;
acpi_handle handle = NULL;
- struct acpi_battery_info *bif = battery->bif_data.pointer;
- unsigned long alarm = battery->alarm;
/* See if alarms are supported, and if so, set default */
-
- status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle);
- if (ACPI_SUCCESS(status)) {
- battery->flags.alarm_present = 1;
- if (!alarm && bif) {
- alarm = bif->design_capacity_warning;
- }
- result = acpi_battery_set_alarm(battery, alarm);
- if (result)
- goto end;
- } else {
- battery->flags.alarm_present = 0;
+ status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
+ if (ACPI_FAILURE(status)) {
+ battery->alarm_present = 0;
+ return 0;
}
-
- end:
-
- return result;
+ battery->alarm_present = 1;
+ if (!battery->alarm)
+ battery->alarm = battery->design_capacity_warning;
+ return acpi_battery_set_alarm(battery);
}
-static int acpi_battery_init_update(struct acpi_battery *battery)
+static ssize_t acpi_battery_alarm_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- int result = 0;
-
- result = acpi_battery_get_status(battery);
- if (result)
- return result;
-
- battery->flags.battery_present_prev = acpi_battery_present(battery);
-
- if (acpi_battery_present(battery)) {
- result = acpi_battery_get_info(battery);
- if (result)
- return result;
- result = acpi_battery_get_state(battery);
- if (result)
- return result;
-
- acpi_battery_init_alarm(battery);
- }
-
- return result;
+ struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
+ return sprintf(buf, "%d\n", battery->alarm * 1000);
}
-static int acpi_battery_update(struct acpi_battery *battery,
- int update, int *update_result_ptr)
+static ssize_t acpi_battery_alarm_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- int result = 0;
- int update_result = ACPI_BATTERY_NONE_UPDATE;
-
- if (!acpi_battery_present(battery)) {
- update = 1;
- }
+ unsigned long x;
+ struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
+ if (sscanf(buf, "%ld\n", &x) == 1)
+ battery->alarm = x/1000;
+ if (acpi_battery_present(battery))
+ acpi_battery_set_alarm(battery);
+ return count;
+}
- if (battery->flags.init_update) {
- result = acpi_battery_init_update(battery);
- if (result)
- goto end;
- update_result = ACPI_BATTERY_INIT_UPDATE;
- } else if (update) {
- result = acpi_battery_get_status(battery);
- if (result)
- goto end;
- if ((!battery->flags.battery_present_prev & acpi_battery_present(battery))
- || (battery->flags.battery_present_prev & !acpi_battery_present(battery))) {
- result = acpi_battery_init_update(battery);
- if (result)
- goto end;
- update_result = ACPI_BATTERY_INIT_UPDATE;
- } else {
- update_result = ACPI_BATTERY_EASY_UPDATE;
- }
- }
+static struct device_attribute alarm_attr = {
+ .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE},
+ .show = acpi_battery_alarm_show,
+ .store = acpi_battery_alarm_store,
+};
- end:
+static int sysfs_add_battery(struct acpi_battery *battery)
+{
+ int result;
- battery->flags.init_update = (result != 0);
+ battery->update_time = 0;
+ result = acpi_battery_get_info(battery);
+ acpi_battery_init_alarm(battery);
+ if (result)
+ return result;
+ if (battery->power_unit) {
+ battery->bat.properties = charge_battery_props;
+ battery->bat.num_properties =
+ ARRAY_SIZE(charge_battery_props);
+ } else {
+ battery->bat.properties = energy_battery_props;
+ battery->bat.num_properties =
+ ARRAY_SIZE(energy_battery_props);
+ }
- *update_result_ptr = update_result;
+ battery->bat.name = acpi_device_bid(battery->device);
+ battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+ battery->bat.get_property = acpi_battery_get_property;
- return result;
+ result = power_supply_register(&battery->device->dev, &battery->bat);
+ if (result)
+ return result;
+ return device_create_file(battery->bat.dev, &alarm_attr);
}
-static void acpi_battery_notify_update(struct acpi_battery *battery)
+static void sysfs_remove_battery(struct acpi_battery *battery)
{
- acpi_battery_get_status(battery);
-
- if (battery->flags.init_update) {
+ if (!battery->bat.dev)
return;
- }
+ device_remove_file(battery->bat.dev, &alarm_attr);
+ power_supply_unregister(&battery->bat);
+ battery->bat.dev = NULL;
+}
- if ((!battery->flags.battery_present_prev &
- acpi_battery_present(battery)) ||
- (battery->flags.battery_present_prev &
- !acpi_battery_present(battery))) {
- battery->flags.init_update = 1;
- } else {
- battery->flags.update[ACPI_BATTERY_INFO] = 1;
- battery->flags.update[ACPI_BATTERY_STATE] = 1;
- battery->flags.update[ACPI_BATTERY_ALARM] = 1;
+static int acpi_battery_update(struct acpi_battery *battery)
+{
+ int result = acpi_battery_get_status(battery);
+ if (result)
+ return result;
+ if (!acpi_battery_present(battery)) {
+ sysfs_remove_battery(battery);
+ return 0;
}
+ if (!battery->bat.dev)
+ sysfs_add_battery(battery);
+ return acpi_battery_get_state(battery);
}
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
static struct proc_dir_entry *acpi_battery_dir;
static int acpi_battery_print_info(struct seq_file *seq, int result)
{
struct acpi_battery *battery = seq->private;
- struct acpi_battery_info *bif = NULL;
- char *units = "?";
if (result)
goto end;
- if (acpi_battery_present(battery))
- seq_printf(seq, "present: yes\n");
- else {
- seq_printf(seq, "present: no\n");
- goto end;
- }
-
- bif = battery->bif_data.pointer;
- if (!bif) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL"));
- result = -ENODEV;
+ seq_printf(seq, "present: %s\n",
+ acpi_battery_present(battery)?"yes":"no");
+ if (!acpi_battery_present(battery))
goto end;
- }
-
- /* Battery Units */
-
- units = acpi_battery_power_units(battery);
-
- if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+ if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
seq_printf(seq, "design capacity: unknown\n");
else
seq_printf(seq, "design capacity: %d %sh\n",
- (u32) bif->design_capacity, units);
+ battery->design_capacity,
+ acpi_battery_units(battery));
- if (bif->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+ if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
seq_printf(seq, "last full capacity: unknown\n");
else
seq_printf(seq, "last full capacity: %d %sh\n",
- (u32) bif->last_full_capacity, units);
+ battery->full_charge_capacity,
+ acpi_battery_units(battery));
- switch ((u32) bif->battery_technology) {
- case 0:
- seq_printf(seq, "battery technology: non-rechargeable\n");
- break;
- case 1:
- seq_printf(seq, "battery technology: rechargeable\n");
- break;
- default:
- seq_printf(seq, "battery technology: unknown\n");
- break;
- }
+ seq_printf(seq, "battery technology: %srechargeable\n",
+ (!battery->technology)?"non-":"");
- if (bif->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
+ if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
seq_printf(seq, "design voltage: unknown\n");
else
seq_printf(seq, "design voltage: %d mV\n",
- (u32) bif->design_voltage);
+ battery->design_voltage);
seq_printf(seq, "design capacity warning: %d %sh\n",
- (u32) bif->design_capacity_warning, units);
+ battery->design_capacity_warning,
+ acpi_battery_units(battery));
seq_printf(seq, "design capacity low: %d %sh\n",
- (u32) bif->design_capacity_low, units);
+ battery->design_capacity_low,
+ acpi_battery_units(battery));
seq_printf(seq, "capacity granularity 1: %d %sh\n",
- (u32) bif->battery_capacity_granularity_1, units);
+ battery->capacity_granularity_1,
+ acpi_battery_units(battery));
seq_printf(seq, "capacity granularity 2: %d %sh\n",
- (u32) bif->battery_capacity_granularity_2, units);
- seq_printf(seq, "model number: %s\n", bif->model_number);
- seq_printf(seq, "serial number: %s\n", bif->serial_number);
- seq_printf(seq, "battery type: %s\n", bif->battery_type);
- seq_printf(seq, "OEM info: %s\n", bif->oem_info);
-
+ battery->capacity_granularity_2,
+ acpi_battery_units(battery));
+ seq_printf(seq, "model number: %s\n", battery->model_number);
+ seq_printf(seq, "serial number: %s\n", battery->serial_number);
+ seq_printf(seq, "battery type: %s\n", battery->type);
+ seq_printf(seq, "OEM info: %s\n", battery->oem_info);
end:
-
if (result)
seq_printf(seq, "ERROR: Unable to read battery info\n");
-
return result;
}
static int acpi_battery_print_state(struct seq_file *seq, int result)
{
struct acpi_battery *battery = seq->private;
- struct acpi_battery_state *bst = NULL;
- char *units = "?";
if (result)
goto end;
- if (acpi_battery_present(battery))
- seq_printf(seq, "present: yes\n");
- else {
- seq_printf(seq, "present: no\n");
+ seq_printf(seq, "present: %s\n",
+ acpi_battery_present(battery)?"yes":"no");
+ if (!acpi_battery_present(battery))
goto end;
- }
- bst = battery->bst_data.pointer;
- if (!bst) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL"));
- result = -ENODEV;
- goto end;
- }
-
- /* Battery Units */
-
- units = acpi_battery_power_units(battery);
-
- if (!(bst->state & 0x04))
- seq_printf(seq, "capacity state: ok\n");
- else
- seq_printf(seq, "capacity state: critical\n");
-
- if ((bst->state & 0x01) && (bst->state & 0x02)) {
+ seq_printf(seq, "capacity state: %s\n",
+ (battery->state & 0x04)?"critical":"ok");
+ if ((battery->state & 0x01) && (battery->state & 0x02))
seq_printf(seq,
"charging state: charging/discharging\n");
- } else if (bst->state & 0x01)
+ else if (battery->state & 0x01)
seq_printf(seq, "charging state: discharging\n");
- else if (bst->state & 0x02)
+ else if (battery->state & 0x02)
seq_printf(seq, "charging state: charging\n");
- else {
+ else
seq_printf(seq, "charging state: charged\n");
- }
- if (bst->present_rate == ACPI_BATTERY_VALUE_UNKNOWN)
+ if (battery->current_now == ACPI_BATTERY_VALUE_UNKNOWN)
seq_printf(seq, "present rate: unknown\n");
else
seq_printf(seq, "present rate: %d %s\n",
- (u32) bst->present_rate, units);
+ battery->current_now, acpi_battery_units(battery));
- if (bst->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+ if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN)
seq_printf(seq, "remaining capacity: unknown\n");
else
seq_printf(seq, "remaining capacity: %d %sh\n",
- (u32) bst->remaining_capacity, units);
-
- if (bst->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
+ battery->capacity_now, acpi_battery_units(battery));
+ if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN)
seq_printf(seq, "present voltage: unknown\n");
else
seq_printf(seq, "present voltage: %d mV\n",
- (u32) bst->present_voltage);
-
+ battery->voltage_now);
end:
-
- if (result) {
+ if (result)
seq_printf(seq, "ERROR: Unable to read battery state\n");
- }
return result;
}
@@ -616,7 +589,6 @@ static int acpi_battery_print_state(struct seq_file *seq, int result)
static int acpi_battery_print_alarm(struct seq_file *seq, int result)
{
struct acpi_battery *battery = seq->private;
- char *units = "?";
if (result)
goto end;
@@ -625,189 +597,117 @@ static int acpi_battery_print_alarm(struct seq_file *seq, int result)
seq_printf(seq, "present: no\n");
goto end;
}
-
- /* Battery Units */
-
- units = acpi_battery_power_units(battery);
-
seq_printf(seq, "alarm: ");
if (!battery->alarm)
seq_printf(seq, "unsupported\n");
else
- seq_printf(seq, "%lu %sh\n", battery->alarm, units);
-
+ seq_printf(seq, "%u %sh\n", battery->alarm,
+ acpi_battery_units(battery));
end:
-
if (result)
seq_printf(seq, "ERROR: Unable to read battery alarm\n");
-
return result;
}
-static ssize_t
-acpi_battery_write_alarm(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * ppos)
+static ssize_t acpi_battery_write_alarm(struct file *file,
+ const char __user * buffer,
+ size_t count, loff_t * ppos)
{
int result = 0;
char alarm_string[12] = { '\0' };
struct seq_file *m = file->private_data;
struct acpi_battery *battery = m->private;
- int update_result = ACPI_BATTERY_NONE_UPDATE;
if (!battery || (count > sizeof(alarm_string) - 1))
return -EINVAL;
-
- mutex_lock(&battery->mutex);
-
- result = acpi_battery_update(battery, 1, &update_result);
- if (result) {
- result = -ENODEV;
- goto end;
- }
-
if (!acpi_battery_present(battery)) {
result = -ENODEV;
goto end;
}
-
if (copy_from_user(alarm_string, buffer, count)) {
result = -EFAULT;
goto end;
}
-
alarm_string[count] = '\0';
-
- result = acpi_battery_set_alarm(battery,
- simple_strtoul(alarm_string, NULL, 0));
- if (result)
- goto end;
-
+ battery->alarm = simple_strtol(alarm_string, NULL, 0);
+ result = acpi_battery_set_alarm(battery);
end:
-
- acpi_battery_check_result(battery, result);
-
if (!result)
- result = count;
-
- mutex_unlock(&battery->mutex);
-
+ return count;
return result;
}
typedef int(*print_func)(struct seq_file *seq, int result);
-typedef int(*get_func)(struct acpi_battery *battery);
-
-static struct acpi_read_mux {
- print_func print;
- get_func get;
-} acpi_read_funcs[ACPI_BATTERY_NUMFILES] = {
- {.get = acpi_battery_get_info, .print = acpi_battery_print_info},
- {.get = acpi_battery_get_state, .print = acpi_battery_print_state},
- {.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm},
+
+static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = {
+ acpi_battery_print_info,
+ acpi_battery_print_state,
+ acpi_battery_print_alarm,
};
static int acpi_battery_read(int fid, struct seq_file *seq)
{
struct acpi_battery *battery = seq->private;
- int result = 0;
- int update_result = ACPI_BATTERY_NONE_UPDATE;
- int update = 0;
-
- mutex_lock(&battery->mutex);
-
- update = (get_seconds() - battery->update_time[fid] >= update_time);
- update = (update | battery->flags.update[fid]);
-
- result = acpi_battery_update(battery, update, &update_result);
- if (result)
- goto end;
-
- if (update_result == ACPI_BATTERY_EASY_UPDATE) {
- result = acpi_read_funcs[fid].get(battery);
- if (result)
- goto end;
+ int result = acpi_battery_update(battery);
+ return acpi_print_funcs[fid](seq, result);
+}
+
+#define DECLARE_FILE_FUNCTIONS(_name) \
+static int acpi_battery_read_##_name(struct seq_file *seq, void *offset) \
+{ \
+ return acpi_battery_read(_name##_tag, seq); \
+} \
+static int acpi_battery_##_name##_open_fs(struct inode *inode, struct file *file) \
+{ \
+ return single_open(file, acpi_battery_read_##_name, PDE(inode)->data); \
+}
+
+DECLARE_FILE_FUNCTIONS(info);
+DECLARE_FILE_FUNCTIONS(state);
+DECLARE_FILE_FUNCTIONS(alarm);
+
+#undef DECLARE_FILE_FUNCTIONS
+
+#define FILE_DESCRIPTION_RO(_name) \
+ { \
+ .name = __stringify(_name), \
+ .mode = S_IRUGO, \
+ .ops = { \
+ .open = acpi_battery_##_name##_open_fs, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+ .owner = THIS_MODULE, \
+ }, \
+ }
+
+#define FILE_DESCRIPTION_RW(_name) \
+ { \
+ .name = __stringify(_name), \
+ .mode = S_IFREG | S_IRUGO | S_IWUSR, \
+ .ops = { \
+ .open = acpi_battery_##_name##_open_fs, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .write = acpi_battery_write_##_name, \
+ .release = single_release, \
+ .owner = THIS_MODULE, \
+ }, \
}
- end:
- result = acpi_read_funcs[fid].print(seq, result);
- acpi_battery_check_result(battery, result);
- battery->flags.update[fid] = result;
- mutex_unlock(&battery->mutex);
- return result;
-}
-
-static int acpi_battery_read_info(struct seq_file *seq, void *offset)
-{
- return acpi_battery_read(ACPI_BATTERY_INFO, seq);
-}
-
-static int acpi_battery_read_state(struct seq_file *seq, void *offset)
-{
- return acpi_battery_read(ACPI_BATTERY_STATE, seq);
-}
-
-static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
-{
- return acpi_battery_read(ACPI_BATTERY_ALARM, seq);
-}
-
-static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_battery_read_info, PDE(inode)->data);
-}
-
-static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_battery_read_state, PDE(inode)->data);
-}
-
-static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
-}
-
static struct battery_file {
struct file_operations ops;
mode_t mode;
char *name;
} acpi_battery_file[] = {
- {
- .name = "info",
- .mode = S_IRUGO,
- .ops = {
- .open = acpi_battery_info_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
- },
- },
- {
- .name = "state",
- .mode = S_IRUGO,
- .ops = {
- .open = acpi_battery_state_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
- },
- },
- {
- .name = "alarm",
- .mode = S_IFREG | S_IRUGO | S_IWUSR,
- .ops = {
- .open = acpi_battery_alarm_open_fs,
- .read = seq_read,
- .write = acpi_battery_write_alarm,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
- },
- },
+ FILE_DESCRIPTION_RO(info),
+ FILE_DESCRIPTION_RO(state),
+ FILE_DESCRIPTION_RW(alarm),
};
+#undef FILE_DESCRIPTION_RO
+#undef FILE_DESCRIPTION_RW
+
static int acpi_battery_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
@@ -832,25 +732,24 @@ static int acpi_battery_add_fs(struct acpi_device *device)
entry->owner = THIS_MODULE;
}
}
-
return 0;
}
-static int acpi_battery_remove_fs(struct acpi_device *device)
+static void acpi_battery_remove_fs(struct acpi_device *device)
{
int i;
- if (acpi_device_dir(device)) {
- for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
- remove_proc_entry(acpi_battery_file[i].name,
+ if (!acpi_device_dir(device))
+ return;
+ for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i)
+ remove_proc_entry(acpi_battery_file[i].name,
acpi_device_dir(device));
- }
- remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
- acpi_device_dir(device) = NULL;
- }
- return 0;
+ remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
+ acpi_device_dir(device) = NULL;
}
+#endif
+
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
@@ -858,33 +757,19 @@ static int acpi_battery_remove_fs(struct acpi_device *device)
static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
{
struct acpi_battery *battery = data;
- struct acpi_device *device = NULL;
-
+ struct acpi_device *device;
if (!battery)
return;
-
device = battery->device;
-
- switch (event) {
- case ACPI_BATTERY_NOTIFY_STATUS:
- case ACPI_BATTERY_NOTIFY_INFO:
- case ACPI_NOTIFY_BUS_CHECK:
- case ACPI_NOTIFY_DEVICE_CHECK:
- device = battery->device;
- acpi_battery_notify_update(battery);
- acpi_bus_generate_proc_event(device, event,
+ acpi_battery_update(battery);
+ acpi_bus_generate_proc_event(device, event,
+ acpi_battery_present(battery));
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ device->dev.bus_id, event,
acpi_battery_present(battery));
- acpi_bus_generate_netlink_event(device->pnp.device_class,
- device->dev.bus_id, event,
- acpi_battery_present(battery));
- break;
- default:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Unsupported event [0x%x]\n", event));
- break;
- }
-
- return;
+ /* acpi_batter_update could remove power_supply object */
+ if (battery->bat.dev)
+ kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE);
}
static int acpi_battery_add(struct acpi_device *device)
@@ -892,33 +777,22 @@ static int acpi_battery_add(struct acpi_device *device)
int result = 0;
acpi_status status = 0;
struct acpi_battery *battery = NULL;
-
if (!device)
return -EINVAL;
-
battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
if (!battery)
return -ENOMEM;
-
- mutex_init(&battery->mutex);
-
- mutex_lock(&battery->mutex);
-
battery->device = device;
strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
acpi_driver_data(device) = battery;
-
- result = acpi_battery_get_status(battery);
- if (result)
- goto end;
-
- battery->flags.init_update = 1;
-
+ mutex_init(&battery->lock);
+ acpi_battery_update(battery);
+#ifdef CONFIG_ACPI_PROCFS
result = acpi_battery_add_fs(device);
if (result)
goto end;
-
+#endif
status = acpi_install_notify_handler(device->handle,
ACPI_ALL_NOTIFY,
acpi_battery_notify, battery);
@@ -927,20 +801,16 @@ static int acpi_battery_add(struct acpi_device *device)
result = -ENODEV;
goto end;
}
-
printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
device->status.battery_present ? "present" : "absent");
-
end:
-
if (result) {
+#ifdef CONFIG_ACPI_PROCFS
acpi_battery_remove_fs(device);
+#endif
kfree(battery);
}
-
- mutex_unlock(&battery->mutex);
-
return result;
}
@@ -951,27 +821,16 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
if (!device || !acpi_driver_data(device))
return -EINVAL;
-
battery = acpi_driver_data(device);
-
- mutex_lock(&battery->mutex);
-
status = acpi_remove_notify_handler(device->handle,
ACPI_ALL_NOTIFY,
acpi_battery_notify);
-
+#ifdef CONFIG_ACPI_PROCFS
acpi_battery_remove_fs(device);
-
- kfree(battery->bif_data.pointer);
-
- kfree(battery->bst_data.pointer);
-
- mutex_unlock(&battery->mutex);
-
- mutex_destroy(&battery->mutex);
-
+#endif
+ sysfs_remove_battery(battery);
+ mutex_destroy(&battery->lock);
kfree(battery);
-
return 0;
}
@@ -979,44 +838,49 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
static int acpi_battery_resume(struct acpi_device *device)
{
struct acpi_battery *battery;
-
if (!device)
return -EINVAL;
-
- battery = device->driver_data;
-
- battery->flags.init_update = 1;
-
+ battery = acpi_driver_data(device);
+ battery->update_time = 0;
+ acpi_battery_update(battery);
return 0;
}
+static struct acpi_driver acpi_battery_driver = {
+ .name = "battery",
+ .class = ACPI_BATTERY_CLASS,
+ .ids = battery_device_ids,
+ .ops = {
+ .add = acpi_battery_add,
+ .resume = acpi_battery_resume,
+ .remove = acpi_battery_remove,
+ },
+};
+
static int __init acpi_battery_init(void)
{
- int result;
-
if (acpi_disabled)
return -ENODEV;
-
+#ifdef CONFIG_ACPI_PROCFS
acpi_battery_dir = acpi_lock_battery_dir();
if (!acpi_battery_dir)
return -ENODEV;
-
- result = acpi_bus_register_driver(&acpi_battery_driver);
- if (result < 0) {
+#endif
+ if (acpi_bus_register_driver(&acpi_battery_driver) < 0) {
+#ifdef CONFIG_ACPI_PROCFS
acpi_unlock_battery_dir(acpi_battery_dir);
+#endif
return -ENODEV;
}
-
return 0;
}
static void __exit acpi_battery_exit(void)
{
acpi_bus_unregister_driver(&acpi_battery_driver);
-
+#ifdef CONFIG_ACPI_PROCFS
acpi_unlock_battery_dir(acpi_battery_dir);
-
- return;
+#endif
}
module_init(acpi_battery_init);
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 9ba778a2b48..49d432d0a12 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -194,16 +194,14 @@ int acpi_bus_set_power(acpi_handle handle, int state)
if (!device->flags.power_manageable) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
- device->dev.kobj.name));
+ kobject_name(&device->dev.kobj)));
return -ENODEV;
}
/*
- * Get device's current power state if it's unknown
- * This means device power state isn't initialized or previous setting failed
+ * Get device's current power state
*/
- if ((device->power.state == ACPI_STATE_UNKNOWN) || device->flags.force_power_state)
- acpi_bus_get_power(device->handle, &device->power.state);
- if ((state == device->power.state) && !device->flags.force_power_state) {
+ acpi_bus_get_power(device->handle, &device->power.state);
+ if (state == device->power.state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
state));
return 0;
@@ -262,10 +260,12 @@ int acpi_bus_set_power(acpi_handle handle, int state)
printk(KERN_WARNING PREFIX
"Transitioning device [%s] to D%d\n",
device->pnp.bus_id, state);
- else
+ else {
+ device->power.state = state;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device [%s] transitioned to D%d\n",
device->pnp.bus_id, state));
+ }
return result;
}
@@ -284,15 +284,11 @@ DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);
extern int event_is_open;
-int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
+int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data)
{
- struct acpi_bus_event *event = NULL;
+ struct acpi_bus_event *event;
unsigned long flags = 0;
-
- if (!device)
- return -EINVAL;
-
/* drop event on the floor if no one's listening */
if (!event_is_open)
return 0;
@@ -301,8 +297,8 @@ int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
if (!event)
return -ENOMEM;
- strcpy(event->device_class, device->pnp.device_class);
- strcpy(event->bus_id, device->pnp.bus_id);
+ strcpy(event->device_class, device_class);
+ strcpy(event->bus_id, bus_id);
event->type = type;
event->data = data;
@@ -313,6 +309,17 @@ int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
wake_up_interruptible(&acpi_bus_event_queue);
return 0;
+
+}
+
+EXPORT_SYMBOL_GPL(acpi_bus_generate_proc_event4);
+
+int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
+{
+ if (!device)
+ return -EINVAL;
+ return acpi_bus_generate_proc_event4(device->pnp.device_class,
+ device->pnp.bus_id, type, data);
}
EXPORT_SYMBOL(acpi_bus_generate_proc_event);
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 2e79a3395ec..24a7865a57c 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -78,6 +78,7 @@ MODULE_DEVICE_TABLE(acpi, button_device_ids);
static int acpi_button_add(struct acpi_device *device);
static int acpi_button_remove(struct acpi_device *device, int type);
+static int acpi_button_resume(struct acpi_device *device);
static int acpi_button_info_open_fs(struct inode *inode, struct file *file);
static int acpi_button_state_open_fs(struct inode *inode, struct file *file);
@@ -87,6 +88,7 @@ static struct acpi_driver acpi_button_driver = {
.ids = button_device_ids,
.ops = {
.add = acpi_button_add,
+ .resume = acpi_button_resume,
.remove = acpi_button_remove,
},
};
@@ -253,6 +255,19 @@ static int acpi_button_remove_fs(struct acpi_device *device)
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
+static int acpi_lid_send_state(struct acpi_button *button)
+{
+ unsigned long state;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(button->device->handle, "_LID", NULL,
+ &state);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+ /* input layer checks if event is redundant */
+ input_report_switch(button->input, SW_LID, !state);
+ return 0;
+}
static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
{
@@ -265,15 +280,8 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
switch (event) {
case ACPI_BUTTON_NOTIFY_STATUS:
input = button->input;
-
if (button->type == ACPI_BUTTON_TYPE_LID) {
- struct acpi_handle *handle = button->device->handle;
- unsigned long state;
-
- if (!ACPI_FAILURE(acpi_evaluate_integer(handle, "_LID",
- NULL, &state)))
- input_report_switch(input, SW_LID, !state);
-
+ acpi_lid_send_state(button);
} else {
int keycode = test_bit(KEY_SLEEP, input->keybit) ?
KEY_SLEEP : KEY_POWER;
@@ -336,6 +344,17 @@ static int acpi_button_install_notify_handlers(struct acpi_button *button)
return ACPI_FAILURE(status) ? -ENODEV : 0;
}
+static int acpi_button_resume(struct acpi_device *device)
+{
+ struct acpi_button *button;
+ if (!device)
+ return -EINVAL;
+ button = acpi_driver_data(device);
+ if (button && button->type == ACPI_BUTTON_TYPE_LID)
+ return acpi_lid_send_state(button);
+ return 0;
+}
+
static void acpi_button_remove_notify_handlers(struct acpi_button *button)
{
switch (button->type) {
@@ -434,18 +453,18 @@ static int acpi_button_add(struct acpi_device *device)
switch (button->type) {
case ACPI_BUTTON_TYPE_POWER:
case ACPI_BUTTON_TYPE_POWERF:
- input->evbit[0] = BIT(EV_KEY);
+ input->evbit[0] = BIT_MASK(EV_KEY);
set_bit(KEY_POWER, input->keybit);
break;
case ACPI_BUTTON_TYPE_SLEEP:
case ACPI_BUTTON_TYPE_SLEEPF:
- input->evbit[0] = BIT(EV_KEY);
+ input->evbit[0] = BIT_MASK(EV_KEY);
set_bit(KEY_SLEEP, input->keybit);
break;
case ACPI_BUTTON_TYPE_LID:
- input->evbit[0] = BIT(EV_SW);
+ input->evbit[0] = BIT_MASK(EV_SW);
set_bit(SW_LID, input->swbit);
break;
}
@@ -453,6 +472,8 @@ static int acpi_button_add(struct acpi_device *device)
error = input_register_device(input);
if (error)
goto err_remove_handlers;
+ if (button->type == ACPI_BUTTON_TYPE_LID)
+ acpi_lid_send_state(button);
if (device->wakeup.flags.valid) {
/* Button's GPE is run-wake GPE */
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 3f7935ab0cf..d6ddb547f2d 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -65,16 +65,19 @@ enum ec_command {
/* EC events */
enum ec_event {
ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */
- ACPI_EC_EVENT_IBF_0, /* Input buffer empty */
+ ACPI_EC_EVENT_IBF_0, /* Input buffer empty */
};
#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
-static enum ec_mode {
- EC_INTR = 1, /* Output buffer full */
- EC_POLL, /* Input buffer empty */
-} acpi_ec_mode = EC_INTR;
+enum {
+ EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */
+ EC_FLAGS_QUERY_PENDING, /* Query is pending */
+ EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */
+ EC_FLAGS_NO_ADDRESS_GPE, /* Expect GPE only for non-address event */
+ EC_FLAGS_ADDRESS, /* Address is being written */
+};
static int acpi_ec_remove(struct acpi_device *device, int type);
static int acpi_ec_start(struct acpi_device *device);
@@ -116,11 +119,11 @@ static struct acpi_ec {
unsigned long command_addr;
unsigned long data_addr;
unsigned long global_lock;
+ unsigned long flags;
struct mutex lock;
- atomic_t query_pending;
- atomic_t event_count;
wait_queue_head_t wait;
struct list_head list;
+ u8 handlers_installed;
} *boot_ec, *first_ec;
/* --------------------------------------------------------------------------
@@ -147,46 +150,62 @@ static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
outb(data, ec->data_addr);
}
-static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event,
- unsigned old_count)
+static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event)
{
- u8 status = acpi_ec_read_status(ec);
- if (old_count == atomic_read(&ec->event_count))
+ if (test_bit(EC_FLAGS_WAIT_GPE, &ec->flags))
return 0;
if (event == ACPI_EC_EVENT_OBF_1) {
- if (status & ACPI_EC_FLAG_OBF)
+ if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF)
return 1;
} else if (event == ACPI_EC_EVENT_IBF_0) {
- if (!(status & ACPI_EC_FLAG_IBF))
+ if (!(acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF))
return 1;
}
return 0;
}
-static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event,
- unsigned count, int force_poll)
+static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
{
- if (unlikely(force_poll) || acpi_ec_mode == EC_POLL) {
+ int ret = 0;
+ if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) &&
+ test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags)))
+ force_poll = 1;
+ if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) &&
+ likely(!force_poll)) {
+ if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event),
+ msecs_to_jiffies(ACPI_EC_DELAY)))
+ goto end;
+ clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
+ if (acpi_ec_check_status(ec, event)) {
+ if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
+ /* miss address GPE, don't expect it anymore */
+ printk(KERN_INFO PREFIX "missing address confirmation,"
+ "don't expect it any longer.\n");
+ set_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags);
+ } else {
+ /* missing GPEs, switch back to poll mode */
+ printk(KERN_INFO PREFIX "missing confirmations,"
+ "switch off interrupt mode.\n");
+ clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+ }
+ goto end;
+ }
+ } else {
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
+ clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
while (time_before(jiffies, delay)) {
- if (acpi_ec_check_status(ec, event, 0))
- return 0;
+ if (acpi_ec_check_status(ec, event))
+ goto end;
}
- } else {
- if (wait_event_timeout(ec->wait,
- acpi_ec_check_status(ec, event, count),
- msecs_to_jiffies(ACPI_EC_DELAY)) ||
- acpi_ec_check_status(ec, event, 0)) {
- return 0;
- } else {
- printk(KERN_ERR PREFIX "acpi_ec_wait timeout,"
+ }
+ printk(KERN_ERR PREFIX "acpi_ec_wait timeout,"
" status = %d, expect_event = %d\n",
acpi_ec_read_status(ec), event);
- }
- }
-
- return -ETIME;
+ ret = -ETIME;
+ end:
+ clear_bit(EC_FLAGS_ADDRESS, &ec->flags);
+ return ret;
}
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
@@ -195,39 +214,43 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
int force_poll)
{
int result = 0;
- unsigned count = atomic_read(&ec->event_count);
+ set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
acpi_ec_write_cmd(ec, command);
for (; wdata_len > 0; --wdata_len) {
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
if (result) {
printk(KERN_ERR PREFIX
"write_cmd timeout, command = %d\n", command);
goto end;
}
- count = atomic_read(&ec->event_count);
+ /* mark the address byte written to EC */
+ if (rdata_len + wdata_len > 1)
+ set_bit(EC_FLAGS_ADDRESS, &ec->flags);
+ set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
acpi_ec_write_data(ec, *(wdata++));
}
if (!rdata_len) {
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
if (result) {
printk(KERN_ERR PREFIX
"finish-write timeout, command = %d\n", command);
goto end;
}
- } else if (command == ACPI_EC_COMMAND_QUERY) {
- atomic_set(&ec->query_pending, 0);
- }
+ } else if (command == ACPI_EC_COMMAND_QUERY)
+ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
for (; rdata_len > 0; --rdata_len) {
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, count, force_poll);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, force_poll);
if (result) {
printk(KERN_ERR PREFIX "read timeout, command = %d\n",
command);
goto end;
}
- count = atomic_read(&ec->event_count);
+ /* Don't expect GPE after last read */
+ if (rdata_len > 1)
+ set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
*(rdata++) = acpi_ec_read_data(ec);
}
end:
@@ -257,10 +280,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
}
}
- /* Make sure GPE is enabled before doing transaction */
- acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
-
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0);
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0);
if (status) {
printk(KERN_ERR PREFIX
"input buffer is not empty, aborting transaction\n");
@@ -425,7 +445,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
handler->func = func;
handler->data = data;
mutex_lock(&ec->lock);
- list_add_tail(&handler->node, &ec->list);
+ list_add(&handler->node, &ec->list);
mutex_unlock(&ec->lock);
return 0;
}
@@ -434,13 +454,12 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
{
- struct acpi_ec_query_handler *handler;
+ struct acpi_ec_query_handler *handler, *tmp;
mutex_lock(&ec->lock);
- list_for_each_entry(handler, &ec->list, node) {
+ list_for_each_entry_safe(handler, tmp, &ec->list, node) {
if (query_bit == handler->query_bit) {
list_del(&handler->node);
kfree(handler);
- break;
}
}
mutex_unlock(&ec->lock);
@@ -476,23 +495,24 @@ static void acpi_ec_gpe_query(void *ec_cxt)
static u32 acpi_ec_gpe_handler(void *data)
{
acpi_status status = AE_OK;
- u8 value;
struct acpi_ec *ec = data;
- atomic_inc(&ec->event_count);
-
- if (acpi_ec_mode == EC_INTR) {
+ clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
+ if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
wake_up(&ec->wait);
- }
- value = acpi_ec_read_status(ec);
- if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) {
- atomic_set(&ec->query_pending, 1);
- status =
- acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
+ if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) {
+ if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
+ status = acpi_os_execute(OSL_EC_BURST_HANDLER,
+ acpi_ec_gpe_query, ec);
+ } else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) {
+ /* this is non-query, must be confirmation */
+ printk(KERN_INFO PREFIX "non-query interrupt received,"
+ " switching to interrupt mode\n");
+ set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
}
- return status == AE_OK ?
+ return ACPI_SUCCESS(status) ?
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
}
@@ -641,13 +661,10 @@ static struct acpi_ec *make_acpi_ec(void)
struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
if (!ec)
return NULL;
-
- atomic_set(&ec->query_pending, 1);
- atomic_set(&ec->event_count, 1);
+ ec->flags = 1 << EC_FLAGS_QUERY_PENDING;
mutex_init(&ec->lock);
init_waitqueue_head(&ec->wait);
INIT_LIST_HEAD(&ec->list);
-
return ec;
}
@@ -680,32 +697,50 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
if (ACPI_FAILURE(status))
return status;
-
/* Find and register all query methods */
acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
acpi_ec_register_query_methods, ec, NULL);
-
/* Use the global lock for all EC transactions? */
acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
-
ec->handle = handle;
-
- printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
- ec->gpe, ec->command_addr, ec->data_addr);
-
return AE_CTRL_TERMINATE;
}
+static void ec_remove_handlers(struct acpi_ec *ec)
+{
+ if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
+ ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
+ printk(KERN_ERR PREFIX "failed to remove space handler\n");
+ if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
+ &acpi_ec_gpe_handler)))
+ printk(KERN_ERR PREFIX "failed to remove gpe handler\n");
+ ec->handlers_installed = 0;
+}
+
static int acpi_ec_add(struct acpi_device *device)
{
struct acpi_ec *ec = NULL;
if (!device)
return -EINVAL;
-
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
+ /* Check for boot EC */
+ if (boot_ec) {
+ if (boot_ec->handle == device->handle) {
+ /* Pre-loaded EC from DSDT, just move pointer */
+ ec = boot_ec;
+ boot_ec = NULL;
+ goto end;
+ } else if (boot_ec->handle == ACPI_ROOT_OBJECT) {
+ /* ECDT-based EC, time to shut it down */
+ ec_remove_handlers(boot_ec);
+ kfree(boot_ec);
+ first_ec = boot_ec = NULL;
+ }
+ }
+
ec = make_acpi_ec();
if (!ec)
return -ENOMEM;
@@ -715,25 +750,16 @@ static int acpi_ec_add(struct acpi_device *device)
kfree(ec);
return -EINVAL;
}
-
- /* Check if we found the boot EC */
- if (boot_ec) {
- if (boot_ec->gpe == ec->gpe) {
- /* We might have incorrect info for GL at boot time */
- mutex_lock(&boot_ec->lock);
- boot_ec->global_lock = ec->global_lock;
- /* Copy handlers from new ec into boot ec */
- list_splice(&ec->list, &boot_ec->list);
- mutex_unlock(&boot_ec->lock);
- kfree(ec);
- ec = boot_ec;
- }
- } else
- first_ec = ec;
ec->handle = device->handle;
+ end:
+ if (!first_ec)
+ first_ec = ec;
acpi_driver_data(device) = ec;
-
acpi_ec_add_fs(device);
+ printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
+ ec->gpe, ec->command_addr, ec->data_addr);
+ printk(KERN_INFO PREFIX "driver started in %s mode\n",
+ (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))?"interrupt":"poll");
return 0;
}
@@ -756,10 +782,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
acpi_driver_data(device) = NULL;
if (ec == first_ec)
first_ec = NULL;
-
- /* Don't touch boot EC */
- if (boot_ec != ec)
- kfree(ec);
+ kfree(ec);
return 0;
}
@@ -789,6 +812,8 @@ ec_parse_io_ports(struct acpi_resource *resource, void *context)
static int ec_install_handlers(struct acpi_ec *ec)
{
acpi_status status;
+ if (ec->handlers_installed)
+ return 0;
status = acpi_install_gpe_handler(NULL, ec->gpe,
ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler, ec);
@@ -807,6 +832,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
return -ENODEV;
}
+ ec->handlers_installed = 1;
return 0;
}
@@ -823,41 +849,22 @@ static int acpi_ec_start(struct acpi_device *device)
if (!ec)
return -EINVAL;
- /* Boot EC is already working */
- if (ec != boot_ec)
- ret = ec_install_handlers(ec);
+ ret = ec_install_handlers(ec);
/* EC is fully operational, allow queries */
- atomic_set(&ec->query_pending, 0);
-
+ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
return ret;
}
static int acpi_ec_stop(struct acpi_device *device, int type)
{
- acpi_status status;
struct acpi_ec *ec;
-
if (!device)
return -EINVAL;
-
ec = acpi_driver_data(device);
if (!ec)
return -EINVAL;
-
- /* Don't touch boot EC */
- if (ec == boot_ec)
- return 0;
-
- status = acpi_remove_address_space_handler(ec->handle,
- ACPI_ADR_SPACE_EC,
- &acpi_ec_space_handler);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- status = acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
- if (ACPI_FAILURE(status))
- return -ENODEV;
+ ec_remove_handlers(ec);
return 0;
}
@@ -877,18 +884,26 @@ int __init acpi_ec_ecdt_probe(void)
status = acpi_get_table(ACPI_SIG_ECDT, 1,
(struct acpi_table_header **)&ecdt_ptr);
if (ACPI_SUCCESS(status)) {
- printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n\n");
+ printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n");
boot_ec->command_addr = ecdt_ptr->control.address;
boot_ec->data_addr = ecdt_ptr->data.address;
boot_ec->gpe = ecdt_ptr->gpe;
boot_ec->handle = ACPI_ROOT_OBJECT;
} else {
+ /* This workaround is needed only on some broken machines,
+ * which require early EC, but fail to provide ECDT */
+ acpi_handle x;
printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n");
status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device,
boot_ec, NULL);
/* Check that acpi_get_devices actually find something */
if (ACPI_FAILURE(status) || !boot_ec->handle)
goto error;
+ /* We really need to limit this workaround, the only ASUS,
+ * which needs it, has fake EC._INI method, so use it as flag.
+ */
+ if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x)))
+ goto error;
}
ret = ec_install_handlers(boot_ec);
@@ -899,7 +914,6 @@ int __init acpi_ec_ecdt_probe(void)
error:
kfree(boot_ec);
boot_ec = NULL;
-
return -ENODEV;
}
@@ -937,20 +951,4 @@ static void __exit acpi_ec_exit(void)
return;
}
-#endif /* 0 */
-
-static int __init acpi_ec_set_intr_mode(char *str)
-{
- int intr;
-
- if (!get_option(&str, &intr))
- return 0;
-
- acpi_ec_mode = (intr) ? EC_INTR : EC_POLL;
-
- printk(KERN_NOTICE PREFIX "%s mode.\n", intr ? "interrupt" : "polling");
-
- return 1;
-}
-
-__setup("ec_intr=", acpi_ec_set_intr_mode);
+#endif /* 0 */
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index a1f87b5def2..e41287815ea 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -239,10 +239,8 @@ u32 acpi_ev_fixed_event_detect(void)
* Read the fixed feature status and enable registers, as all the cases
* depend on their values. Ignore errors here.
*/
- (void)acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1_STATUS, &fixed_status);
- (void)acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1_ENABLE, &fixed_enable);
+ (void)acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status);
+ (void)acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable);
ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
"Fixed Event Block: Enable %08X Status %08X\n",
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index c81f6bdb68b..a5a5532db26 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -47,8 +47,6 @@ MODULE_LICENSE("GPL");
static int acpi_fan_add(struct acpi_device *device);
static int acpi_fan_remove(struct acpi_device *device, int type);
-static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
-static int acpi_fan_resume(struct acpi_device *device);
static const struct acpi_device_id fan_device_ids[] = {
{"PNP0C0B", 0},
@@ -63,15 +61,9 @@ static struct acpi_driver acpi_fan_driver = {
.ops = {
.add = acpi_fan_add,
.remove = acpi_fan_remove,
- .suspend = acpi_fan_suspend,
- .resume = acpi_fan_resume,
},
};
-struct acpi_fan {
- struct acpi_device * device;
-};
-
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
@@ -80,12 +72,12 @@ static struct proc_dir_entry *acpi_fan_dir;
static int acpi_fan_read_state(struct seq_file *seq, void *offset)
{
- struct acpi_fan *fan = seq->private;
+ struct acpi_device *device = seq->private;
int state = 0;
- if (fan) {
- if (acpi_bus_get_power(fan->device->handle, &state))
+ if (device) {
+ if (acpi_bus_get_power(device->handle, &state))
seq_printf(seq, "status: ERROR\n");
else
seq_printf(seq, "status: %s\n",
@@ -105,11 +97,10 @@ acpi_fan_write_state(struct file *file, const char __user * buffer,
{
int result = 0;
struct seq_file *m = file->private_data;
- struct acpi_fan *fan = m->private;
+ struct acpi_device *device = m->private;
char state_string[12] = { '\0' };
-
- if (!fan || (count > sizeof(state_string) - 1))
+ if (count > sizeof(state_string) - 1)
return -EINVAL;
if (copy_from_user(state_string, buffer, count))
@@ -117,7 +108,7 @@ acpi_fan_write_state(struct file *file, const char __user * buffer,
state_string[count] = '\0';
- result = acpi_bus_set_power(fan->device->handle,
+ result = acpi_bus_set_power(device->handle,
simple_strtoul(state_string, NULL, 0));
if (result)
return result;
@@ -158,7 +149,7 @@ static int acpi_fan_add_fs(struct acpi_device *device)
return -ENODEV;
else {
entry->proc_fops = &acpi_fan_state_ops;
- entry->data = acpi_driver_data(device);
+ entry->data = device;
entry->owner = THIS_MODULE;
}
@@ -191,14 +182,8 @@ static int acpi_fan_add(struct acpi_device *device)
if (!device)
return -EINVAL;
- fan = kzalloc(sizeof(struct acpi_fan), GFP_KERNEL);
- if (!fan)
- return -ENOMEM;
-
- fan->device = device;
strcpy(acpi_device_name(device), "Fan");
strcpy(acpi_device_class(device), ACPI_FAN_CLASS);
- acpi_driver_data(device) = fan;
result = acpi_bus_get_power(device->handle, &state);
if (result) {
@@ -206,10 +191,6 @@ static int acpi_fan_add(struct acpi_device *device)
goto end;
}
- device->flags.force_power_state = 1;
- acpi_bus_set_power(device->handle, state);
- device->flags.force_power_state = 0;
-
result = acpi_fan_add_fs(device);
if (result)
goto end;
@@ -227,53 +208,14 @@ static int acpi_fan_add(struct acpi_device *device)
static int acpi_fan_remove(struct acpi_device *device, int type)
{
- struct acpi_fan *fan = NULL;
-
-
if (!device || !acpi_driver_data(device))
return -EINVAL;
- fan = acpi_driver_data(device);
-
acpi_fan_remove_fs(device);
- kfree(fan);
-
return 0;
}
-static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
-{
- if (!device)
- return -EINVAL;
-
- acpi_bus_set_power(device->handle, ACPI_STATE_D0);
-
- return AE_OK;
-}
-
-static int acpi_fan_resume(struct acpi_device *device)
-{
- int result = 0;
- int power_state = 0;
-
- if (!device)
- return -EINVAL;
-
- result = acpi_bus_get_power(device->handle, &power_state);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "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;
-
- return result;
-}
-
static int __init acpi_fan_init(void)
{
int result = 0;
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
index 1d371fa663f..73f9c5fb1ba 100644
--- a/drivers/acpi/hardware/hwregs.c
+++ b/drivers/acpi/hardware/hwregs.c
@@ -75,8 +75,7 @@ acpi_status acpi_hw_clear_acpi_status(void)
lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
- status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1_STATUS,
+ status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS,
ACPI_BITMASK_ALL_FIXED_STATUS);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
@@ -259,7 +258,7 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
*
******************************************************************************/
-acpi_status acpi_get_register(u32 register_id, u32 * return_value)
+acpi_status acpi_get_register_unlocked(u32 register_id, u32 * return_value)
{
u32 register_value = 0;
struct acpi_bit_register_info *bit_reg_info;
@@ -276,8 +275,7 @@ acpi_status acpi_get_register(u32 register_id, u32 * return_value)
/* Read from the register */
- status = acpi_hw_register_read(ACPI_MTX_LOCK,
- bit_reg_info->parent_register,
+ status = acpi_hw_register_read(bit_reg_info->parent_register,
&register_value);
if (ACPI_SUCCESS(status)) {
@@ -298,6 +296,16 @@ acpi_status acpi_get_register(u32 register_id, u32 * return_value)
return_ACPI_STATUS(status);
}
+acpi_status acpi_get_register(u32 register_id, u32 * return_value)
+{
+ acpi_status status;
+ acpi_cpu_flags flags;
+ flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
+ status = acpi_get_register_unlocked(register_id, return_value);
+ acpi_os_release_lock(acpi_gbl_hardware_lock, flags);
+ return status;
+}
+
ACPI_EXPORT_SYMBOL(acpi_get_register)
/*******************************************************************************
@@ -335,8 +343,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value)
/* Always do a register read first so we can insert the new bits */
- status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
- bit_reg_info->parent_register,
+ status = acpi_hw_register_read(bit_reg_info->parent_register,
&register_value);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
@@ -363,8 +370,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value)
bit_reg_info->
access_bit_mask);
if (value) {
- status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1_STATUS,
+ status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS,
(u16) value);
register_value = 0;
}
@@ -377,8 +383,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value)
bit_reg_info->access_bit_mask,
value);
- status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1_ENABLE,
+ status = acpi_hw_register_write(ACPI_REGISTER_PM1_ENABLE,
(u16) register_value);
break;
@@ -397,15 +402,13 @@ acpi_status acpi_set_register(u32 register_id, u32 value)
bit_reg_info->access_bit_mask,
value);
- status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1_CONTROL,
+ status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL,
(u16) register_value);
break;
case ACPI_REGISTER_PM2_CONTROL:
- status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM2_CONTROL,
+ status = acpi_hw_register_read(ACPI_REGISTER_PM2_CONTROL,
&register_value);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
@@ -430,8 +433,7 @@ acpi_status acpi_set_register(u32 register_id, u32 value)
xpm2_control_block.
address)));
- status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM2_CONTROL,
+ status = acpi_hw_register_write(ACPI_REGISTER_PM2_CONTROL,
(u8) (register_value));
break;
@@ -461,8 +463,7 @@ ACPI_EXPORT_SYMBOL(acpi_set_register)
*
* FUNCTION: acpi_hw_register_read
*
- * PARAMETERS: use_lock - Lock hardware? True/False
- * register_id - ACPI Register ID
+ * PARAMETERS: register_id - ACPI Register ID
* return_value - Where the register value is returned
*
* RETURN: Status and the value read.
@@ -471,19 +472,14 @@ ACPI_EXPORT_SYMBOL(acpi_set_register)
*
******************************************************************************/
acpi_status
-acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
+acpi_hw_register_read(u32 register_id, u32 * return_value)
{
u32 value1 = 0;
u32 value2 = 0;
acpi_status status;
- acpi_cpu_flags lock_flags = 0;
ACPI_FUNCTION_TRACE(hw_register_read);
- if (ACPI_MTX_LOCK == use_lock) {
- lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
- }
-
switch (register_id) {
case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
@@ -491,7 +487,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
acpi_hw_low_level_read(16, &value1,
&acpi_gbl_FADT.xpm1a_event_block);
if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ goto exit;
}
/* PM1B is optional */
@@ -507,7 +503,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
status =
acpi_hw_low_level_read(16, &value1, &acpi_gbl_xpm1a_enable);
if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ goto exit;
}
/* PM1B is optional */
@@ -523,7 +519,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
acpi_hw_low_level_read(16, &value1,
&acpi_gbl_FADT.xpm1a_control_block);
if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ goto exit;
}
status =
@@ -558,10 +554,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
break;
}
- unlock_and_exit:
- if (ACPI_MTX_LOCK == use_lock) {
- acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
- }
+ exit:
if (ACPI_SUCCESS(status)) {
*return_value = value1;
@@ -574,8 +567,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
*
* FUNCTION: acpi_hw_register_write
*
- * PARAMETERS: use_lock - Lock hardware? True/False
- * register_id - ACPI Register ID
+ * PARAMETERS: register_id - ACPI Register ID
* Value - The value to write
*
* RETURN: Status
@@ -597,28 +589,22 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
*
******************************************************************************/
-acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
+acpi_status acpi_hw_register_write(u32 register_id, u32 value)
{
acpi_status status;
- acpi_cpu_flags lock_flags = 0;
u32 read_value;
ACPI_FUNCTION_TRACE(hw_register_write);
- if (ACPI_MTX_LOCK == use_lock) {
- lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
- }
-
switch (register_id) {
case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
/* Perform a read first to preserve certain bits (per ACPI spec) */
- status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1_STATUS,
+ status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS,
&read_value);
if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ goto exit;
}
/* Insert the bits to be preserved */
@@ -632,7 +618,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
acpi_hw_low_level_write(16, value,
&acpi_gbl_FADT.xpm1a_event_block);
if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ goto exit;
}
/* PM1B is optional */
@@ -647,7 +633,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
status =
acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1a_enable);
if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ goto exit;
}
/* PM1B is optional */
@@ -661,11 +647,10 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
/*
* Perform a read first to preserve certain bits (per ACPI spec)
*/
- status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1_CONTROL,
+ status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
&read_value);
if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ goto exit;
}
/* Insert the bits to be preserved */
@@ -679,7 +664,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
acpi_hw_low_level_write(16, value,
&acpi_gbl_FADT.xpm1a_control_block);
if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ goto exit;
}
status =
@@ -728,11 +713,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
break;
}
- unlock_and_exit:
- if (ACPI_MTX_LOCK == use_lock) {
- acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
- }
-
+ exit:
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index cf69c0040a3..81b24842970 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -234,15 +234,11 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
"While executing method _SST"));
}
- /*
- * 1) Disable/Clear all GPEs
- */
+ /* Disable/Clear all GPEs */
+
status = acpi_hw_disable_all_gpes();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- return_ACPI_STATUS(AE_OK);
+ return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
@@ -313,8 +309,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
/* Get current value of PM1A control */
- status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
+ status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -341,15 +336,13 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
/* Write #1: fill in SLP_TYP data */
- status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1A_CONTROL,
+ status = acpi_hw_register_write(ACPI_REGISTER_PM1A_CONTROL,
PM1Acontrol);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1B_CONTROL,
+ status = acpi_hw_register_write(ACPI_REGISTER_PM1B_CONTROL,
PM1Bcontrol);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -364,15 +357,13 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
ACPI_FLUSH_CPU_CACHE();
- status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1A_CONTROL,
+ status = acpi_hw_register_write(ACPI_REGISTER_PM1A_CONTROL,
PM1Acontrol);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1B_CONTROL,
+ status = acpi_hw_register_write(ACPI_REGISTER_PM1B_CONTROL,
PM1Bcontrol);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -392,8 +383,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
*/
acpi_os_stall(10000000);
- status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1_CONTROL,
+ status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL,
sleep_enable_reg_info->
access_bit_mask);
if (ACPI_FAILURE(status)) {
@@ -404,7 +394,8 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
/* Wait until we enter sleep state */
do {
- status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value);
+ status = acpi_get_register_unlocked(ACPI_BITREG_WAKE_STATUS,
+ &in_value);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -520,8 +511,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
/* Get current value of PM1A control */
- status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1_CONTROL,
+ status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
&PM1Acontrol);
if (ACPI_SUCCESS(status)) {
@@ -543,11 +533,9 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
/* Just ignore any errors */
- (void)acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1A_CONTROL,
+ (void)acpi_hw_register_write(ACPI_REGISTER_PM1A_CONTROL,
PM1Acontrol);
- (void)acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1B_CONTROL,
+ (void)acpi_hw_register_write(ACPI_REGISTER_PM1B_CONTROL,
PM1Bcontrol);
}
}
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 5d14d4f10b1..aabc6ca4a81 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -1206,7 +1206,7 @@ acpi_os_validate_address (
}
#ifdef CONFIG_DMI
-static int dmi_osi_linux(struct dmi_system_id *d)
+static int dmi_osi_linux(const struct dmi_system_id *d)
{
printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
enable_osi_linux(1);
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 57b9a2998fd..af1769a20c7 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -86,7 +86,6 @@ struct acpi_power_resource {
acpi_bus_id name;
u32 system_level;
u32 order;
- int state;
struct mutex resource_lock;
struct list_head reference;
};
@@ -128,33 +127,31 @@ acpi_power_get_context(acpi_handle handle,
return 0;
}
-static int acpi_power_get_state(struct acpi_power_resource *resource)
+static int acpi_power_get_state(struct acpi_power_resource *resource, int *state)
{
acpi_status status = AE_OK;
unsigned long sta = 0;
- if (!resource)
+ if (!resource || !state)
return -EINVAL;
status = acpi_evaluate_integer(resource->device->handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
return -ENODEV;
- if (sta & 0x01)
- resource->state = ACPI_POWER_RESOURCE_STATE_ON;
- else
- resource->state = ACPI_POWER_RESOURCE_STATE_OFF;
+ *state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON:
+ ACPI_POWER_RESOURCE_STATE_OFF;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n",
- resource->name, resource->state ? "on" : "off"));
+ resource->name, state ? "on" : "off"));
return 0;
}
static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
{
- int result = 0;
+ int result = 0, state1;
struct acpi_power_resource *resource = NULL;
u32 i = 0;
@@ -168,11 +165,11 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
result = acpi_power_get_context(list->handles[i], &resource);
if (result)
return result;
- result = acpi_power_get_state(resource);
+ result = acpi_power_get_state(resource, &state1);
if (result)
return result;
- *state = resource->state;
+ *state = state1;
if (*state != ACPI_POWER_RESOURCE_STATE_ON)
break;
@@ -186,7 +183,7 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
{
- int result = 0;
+ int result = 0, state;
int found = 0;
acpi_status status = AE_OK;
struct acpi_power_resource *resource = NULL;
@@ -224,20 +221,14 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
}
mutex_unlock(&resource->resource_lock);
- if (resource->state == ACPI_POWER_RESOURCE_STATE_ON) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already on\n",
- resource->name));
- return 0;
- }
-
status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
if (ACPI_FAILURE(status))
return -ENODEV;
- result = acpi_power_get_state(resource);
+ result = acpi_power_get_state(resource, &state);
if (result)
return result;
- if (resource->state != ACPI_POWER_RESOURCE_STATE_ON)
+ if (state != ACPI_POWER_RESOURCE_STATE_ON)
return -ENOEXEC;
/* Update the power resource's _device_ power state */
@@ -250,7 +241,7 @@ static int acpi_power_on(acpi_handle handle, struct acpi_device *dev)
static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
{
- int result = 0;
+ int result = 0, state;
acpi_status status = AE_OK;
struct acpi_power_resource *resource = NULL;
struct list_head *node, *next;
@@ -281,20 +272,14 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev)
}
mutex_unlock(&resource->resource_lock);
- if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n",
- resource->name));
- return 0;
- }
-
status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL);
if (ACPI_FAILURE(status))
return -ENODEV;
- result = acpi_power_get_state(resource);
+ result = acpi_power_get_state(resource, &state);
if (result)
return result;
- if (resource->state != ACPI_POWER_RESOURCE_STATE_OFF)
+ if (state != ACPI_POWER_RESOURCE_STATE_OFF)
return -ENOEXEC;
/* Update the power resource's _device_ power state */
@@ -494,7 +479,7 @@ static struct proc_dir_entry *acpi_power_dir;
static int acpi_power_seq_show(struct seq_file *seq, void *offset)
{
int count = 0;
- int result = 0;
+ int result = 0, state;
struct acpi_power_resource *resource = NULL;
struct list_head *node, *next;
struct acpi_power_reference *ref;
@@ -505,12 +490,12 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset)
if (!resource)
goto end;
- result = acpi_power_get_state(resource);
+ result = acpi_power_get_state(resource, &state);
if (result)
goto end;
seq_puts(seq, "state: ");
- switch (resource->state) {
+ switch (state) {
case ACPI_POWER_RESOURCE_STATE_ON:
seq_puts(seq, "on\n");
break;
@@ -591,7 +576,7 @@ static int acpi_power_remove_fs(struct acpi_device *device)
static int acpi_power_add(struct acpi_device *device)
{
- int result = 0;
+ int result = 0, state;
acpi_status status = AE_OK;
struct acpi_power_resource *resource = NULL;
union acpi_object acpi_object;
@@ -622,11 +607,11 @@ static int acpi_power_add(struct acpi_device *device)
resource->system_level = acpi_object.power_resource.system_level;
resource->order = acpi_object.power_resource.resource_order;
- result = acpi_power_get_state(resource);
+ result = acpi_power_get_state(resource, &state);
if (result)
goto end;
- switch (resource->state) {
+ switch (state) {
case ACPI_POWER_RESOURCE_STATE_ON:
device->power.state = ACPI_STATE_D0;
break;
@@ -643,7 +628,7 @@ static int acpi_power_add(struct acpi_device *device)
goto end;
printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device),
- acpi_device_bid(device), resource->state ? "on" : "off");
+ acpi_device_bid(device), state ? "on" : "off");
end:
if (result)
@@ -680,7 +665,7 @@ static int acpi_power_remove(struct acpi_device *device, int type)
static int acpi_power_resume(struct acpi_device *device)
{
- int result = 0;
+ int result = 0, state;
struct acpi_power_resource *resource = NULL;
struct acpi_power_reference *ref;
@@ -689,12 +674,12 @@ static int acpi_power_resume(struct acpi_device *device)
resource = (struct acpi_power_resource *)acpi_driver_data(device);
- result = acpi_power_get_state(resource);
+ result = acpi_power_get_state(resource, &state);
if (result)
return result;
mutex_lock(&resource->resource_lock);
- if ((resource->state == ACPI_POWER_RESOURCE_STATE_OFF) &&
+ if (state == ACPI_POWER_RESOURCE_STATE_OFF &&
!list_empty(&resource->reference)) {
ref = container_of(resource->reference.next, struct acpi_power_reference, node);
mutex_unlock(&resource->resource_lock);
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index a7351084f2f..235a51e328c 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -422,12 +422,6 @@ static int map_lsapic_id(struct acpi_subtable_header *entry,
return 0;
}
-#ifdef CONFIG_IA64
-#define arch_cpu_to_apicid ia64_cpu_to_sapicid
-#else
-#define arch_cpu_to_apicid x86_cpu_to_apicid
-#endif
-
static int map_madt_entry(u32 acpi_id)
{
unsigned long madt_end, entry;
@@ -501,7 +495,7 @@ static int get_cpu_id(acpi_handle handle, u32 acpi_id)
return apic_id;
for (i = 0; i < NR_CPUS; ++i) {
- if (arch_cpu_to_apicid[i] == apic_id)
+ if (cpu_physical_id(i) == apic_id)
return i;
}
return -1;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 8904f5c82a1..7b6c20eeeaf 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -102,7 +102,7 @@ static int acpi_processor_set_power_policy(struct acpi_processor *pr);
*
* To skip this limit, boot/load with a large max_cstate limit.
*/
-static int set_max_cstate(struct dmi_system_id *id)
+static int set_max_cstate(const struct dmi_system_id *id)
{
if (max_cstate > ACPI_PROCESSOR_MAX_POWER)
return 0;
@@ -299,21 +299,12 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr,
static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
{
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
unsigned long reason;
reason = pr->power.timer_broadcast_on_state < INT_MAX ?
CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
clockevents_notify(reason, &pr->id);
-#else
- cpumask_t mask = cpumask_of_cpu(pr->id);
-
- if (pr->power.timer_broadcast_on_state < INT_MAX)
- on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);
- else
- on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);
-#endif
}
/* Power(C) State timer broadcast control */
@@ -321,8 +312,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
struct acpi_processor_cx *cx,
int broadcast)
{
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-
int state = cx - pr->power.states;
if (state >= pr->power.timer_broadcast_on_state) {
@@ -332,7 +321,6 @@ static void acpi_state_timer_broadcast(struct acpi_processor *pr,
CLOCK_EVT_NOTIFY_BROADCAST_EXIT;
clockevents_notify(reason, &pr->id);
}
-#endif
}
#else
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index a578986e321..73c1ba31429 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -1,6 +1,8 @@
/*
- * acpi_sbs.c - ACPI Smart Battery System Driver ($Revision: 1.16 $)
+ * sbs.c - ACPI Smart Battery System Driver ($Revision: 2.0 $)
*
+ * Copyright (c) 2007 Alexey Starikovskiy <astarikovskiy@suse.de>
+ * Copyright (c) 2005-2007 Vladimir Lebedev <vladimir.p.lebedev@intel.com>
* Copyright (c) 2005 Rich Townsend <rhdt@bartol.udel.edu>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -26,15 +28,22 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
+
+#ifdef CONFIG_ACPI_PROCFS
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
+#endif
+
#include <linux/acpi.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/delay.h>
-#define ACPI_SBS_COMPONENT 0x00080000
+#include <linux/power_supply.h>
+
+#include "sbshc.h"
+
#define ACPI_SBS_CLASS "sbs"
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_BATTERY_CLASS "battery"
@@ -44,836 +53,437 @@
#define ACPI_SBS_FILE_ALARM "alarm"
#define ACPI_BATTERY_DIR_NAME "BAT%i"
#define ACPI_AC_DIR_NAME "AC0"
-#define ACPI_SBC_SMBUS_ADDR 0x9
-#define ACPI_SBSM_SMBUS_ADDR 0xa
-#define ACPI_SB_SMBUS_ADDR 0xb
-#define ACPI_SBS_AC_NOTIFY_STATUS 0x80
-#define ACPI_SBS_BATTERY_NOTIFY_STATUS 0x80
-#define ACPI_SBS_BATTERY_NOTIFY_INFO 0x81
-#define _COMPONENT ACPI_SBS_COMPONENT
+enum acpi_sbs_device_addr {
+ ACPI_SBS_CHARGER = 0x9,
+ ACPI_SBS_MANAGER = 0xa,
+ ACPI_SBS_BATTERY = 0xb,
+};
-ACPI_MODULE_NAME("sbs");
+#define ACPI_SBS_NOTIFY_STATUS 0x80
+#define ACPI_SBS_NOTIFY_INFO 0x81
-MODULE_AUTHOR("Rich Townsend");
+MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
MODULE_LICENSE("GPL");
-#define xmsleep(t) msleep(t)
-
-#define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */
-
-#define ACPI_EC_SMB_STS 0x01 /* status */
-#define ACPI_EC_SMB_ADDR 0x02 /* address */
-#define ACPI_EC_SMB_CMD 0x03 /* command */
-#define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */
-#define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */
-
-#define ACPI_EC_SMB_STS_DONE 0x80
-#define ACPI_EC_SMB_STS_STATUS 0x1f
-
-#define ACPI_EC_SMB_PRTCL_WRITE 0x00
-#define ACPI_EC_SMB_PRTCL_READ 0x01
-#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08
-#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a
-
-#define ACPI_EC_SMB_TRANSACTION_SLEEP 1
-#define ACPI_EC_SMB_ACCESS_SLEEP1 1
-#define ACPI_EC_SMB_ACCESS_SLEEP2 10
-
-#define DEF_CAPACITY_UNIT 3
-#define MAH_CAPACITY_UNIT 1
-#define MWH_CAPACITY_UNIT 2
-#define CAPACITY_UNIT DEF_CAPACITY_UNIT
-
-#define REQUEST_UPDATE_MODE 1
-#define QUEUE_UPDATE_MODE 2
-
-#define DATA_TYPE_COMMON 0
-#define DATA_TYPE_INFO 1
-#define DATA_TYPE_STATE 2
-#define DATA_TYPE_ALARM 3
-#define DATA_TYPE_AC_STATE 4
+static unsigned int cache_time = 1000;
+module_param(cache_time, uint, 0644);
+MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
extern struct proc_dir_entry *acpi_lock_ac_dir(void);
extern struct proc_dir_entry *acpi_lock_battery_dir(void);
extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
-#define MAX_SBS_BAT 4
+#define MAX_SBS_BAT 4
#define ACPI_SBS_BLOCK_MAX 32
-#define ACPI_SBS_SMBUS_READ 1
-#define ACPI_SBS_SMBUS_WRITE 2
-
-#define ACPI_SBS_WORD_DATA 1
-#define ACPI_SBS_BLOCK_DATA 2
-
-#define UPDATE_DELAY 10
-
-/* 0 - every time, > 0 - by update_time */
-static unsigned int update_time = 120;
-
-static unsigned int capacity_mode = CAPACITY_UNIT;
-
-module_param(update_time, uint, 0644);
-module_param(capacity_mode, uint, 0444);
-
-static int acpi_sbs_add(struct acpi_device *device);
-static int acpi_sbs_remove(struct acpi_device *device, int type);
-static int acpi_sbs_resume(struct acpi_device *device);
-
static const struct acpi_device_id sbs_device_ids[] = {
- {"ACPI0001", 0},
- {"ACPI0005", 0},
+ {"ACPI0002", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, sbs_device_ids);
-static struct acpi_driver acpi_sbs_driver = {
- .name = "sbs",
- .class = ACPI_SBS_CLASS,
- .ids = sbs_device_ids,
- .ops = {
- .add = acpi_sbs_add,
- .remove = acpi_sbs_remove,
- .resume = acpi_sbs_resume,
- },
-};
-
-struct acpi_ac {
- int ac_present;
-};
-
-struct acpi_battery_info {
- int capacity_mode;
- s16 full_charge_capacity;
- s16 design_capacity;
- s16 design_voltage;
- int vscale;
- int ipscale;
- s16 serial_number;
- char manufacturer_name[ACPI_SBS_BLOCK_MAX + 3];
- char device_name[ACPI_SBS_BLOCK_MAX + 3];
- char device_chemistry[ACPI_SBS_BLOCK_MAX + 3];
-};
-
-struct acpi_battery_state {
- s16 voltage;
- s16 amperage;
- s16 remaining_capacity;
- s16 battery_state;
-};
-
-struct acpi_battery_alarm {
- s16 remaining_capacity;
-};
-
struct acpi_battery {
- int alive;
- int id;
- int init_state;
- int battery_present;
+ struct power_supply bat;
struct acpi_sbs *sbs;
- struct acpi_battery_info info;
- struct acpi_battery_state state;
- struct acpi_battery_alarm alarm;
- struct proc_dir_entry *battery_entry;
+#ifdef CONFIG_ACPI_PROCFS
+ struct proc_dir_entry *proc_entry;
+#endif
+ unsigned long update_time;
+ char name[8];
+ char manufacturer_name[ACPI_SBS_BLOCK_MAX];
+ char device_name[ACPI_SBS_BLOCK_MAX];
+ char device_chemistry[ACPI_SBS_BLOCK_MAX];
+ u16 alarm_capacity;
+ u16 full_charge_capacity;
+ u16 design_capacity;
+ u16 design_voltage;
+ u16 serial_number;
+ u16 cycle_count;
+ u16 temp_now;
+ u16 voltage_now;
+ s16 current_now;
+ s16 current_avg;
+ u16 capacity_now;
+ u16 state_of_charge;
+ u16 state;
+ u16 mode;
+ u16 spec;
+ u8 id;
+ u8 present:1;
+ u8 have_sysfs_alarm:1;
};
+#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
+
struct acpi_sbs {
- int base;
+ struct power_supply charger;
struct acpi_device *device;
- struct mutex mutex;
- int sbsm_present;
- int sbsm_batteries_supported;
- struct proc_dir_entry *ac_entry;
- struct acpi_ac ac;
+ struct acpi_smb_hc *hc;
+ struct mutex lock;
+#ifdef CONFIG_ACPI_PROCFS
+ struct proc_dir_entry *charger_entry;
+#endif
struct acpi_battery battery[MAX_SBS_BAT];
- int zombie;
- struct timer_list update_timer;
- int run_cnt;
- int update_proc_flg;
+ u8 batteries_supported:4;
+ u8 manager_present:1;
+ u8 charger_present:1;
};
-static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type);
-static void acpi_sbs_update_time(void *data);
+#define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger)
-union sbs_rw_data {
- u16 word;
- u8 block[ACPI_SBS_BLOCK_MAX + 2];
-};
-
-static int acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr,
- char read_write, u8 command, int size,
- union sbs_rw_data *data);
-
-/* --------------------------------------------------------------------------
- SMBus Communication
- -------------------------------------------------------------------------- */
-
-static int acpi_ec_sbs_read(struct acpi_sbs *sbs, u8 address, u8 * data)
+static inline int battery_scale(int log)
{
- u8 val;
- int err;
-
- err = ec_read(sbs->base + address, &val);
- if (!err) {
- *data = val;
- }
- xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
- return (err);
-}
-
-static int acpi_ec_sbs_write(struct acpi_sbs *sbs, u8 address, u8 data)
-{
- int err;
-
- err = ec_write(sbs->base + address, data);
- return (err);
-}
-
-static int
-acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr,
- char read_write, u8 command, int size,
- union sbs_rw_data *data)
-{
- unsigned char protocol, len = 0, temp[2] = { 0, 0 };
- int i;
-
- if (read_write == ACPI_SBS_SMBUS_READ) {
- protocol = ACPI_EC_SMB_PRTCL_READ;
- } else {
- protocol = ACPI_EC_SMB_PRTCL_WRITE;
- }
-
- switch (size) {
-
- case ACPI_SBS_WORD_DATA:
- acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command);
- if (read_write == ACPI_SBS_SMBUS_WRITE) {
- acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA, data->word);
- acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + 1,
- data->word >> 8);
- }
- protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA;
- break;
- case ACPI_SBS_BLOCK_DATA:
- acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command);
- if (read_write == ACPI_SBS_SMBUS_WRITE) {
- len = min_t(u8, data->block[0], 32);
- acpi_ec_sbs_write(sbs, ACPI_EC_SMB_BCNT, len);
- for (i = 0; i < len; i++)
- acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + i,
- data->block[i + 1]);
- }
- protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA;
- break;
- default:
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "unsupported transaction %d", size));
- return (-1);
- }
-
- acpi_ec_sbs_write(sbs, ACPI_EC_SMB_ADDR, addr << 1);
- acpi_ec_sbs_write(sbs, ACPI_EC_SMB_PRTCL, protocol);
-
- acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
-
- if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
- xmsleep(ACPI_EC_SMB_ACCESS_SLEEP1);
- acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
- }
- if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
- xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);
- acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
- }
- if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
- || (temp[0] & ACPI_EC_SMB_STS_STATUS)) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "transaction %d error", size));
- return (-1);
- }
-
- if (read_write == ACPI_SBS_SMBUS_WRITE) {
- return (0);
- }
-
- switch (size) {
-
- case ACPI_SBS_WORD_DATA:
- acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA, temp);
- acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + 1, temp + 1);
- data->word = (temp[1] << 8) | temp[0];
- break;
-
- case ACPI_SBS_BLOCK_DATA:
- len = 0;
- acpi_ec_sbs_read(sbs, ACPI_EC_SMB_BCNT, &len);
- len = min_t(u8, len, 32);
- for (i = 0; i < len; i++)
- acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + i,
- data->block + i + 1);
- data->block[0] = len;
- break;
- default:
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "unsupported transaction %d", size));
- return (-1);
- }
-
- return (0);
+ int scale = 1;
+ while (log--)
+ scale *= 10;
+ return scale;
}
-static int
-acpi_sbs_read_word(struct acpi_sbs *sbs, int addr, int func, u16 * word)
+static inline int acpi_battery_vscale(struct acpi_battery *battery)
{
- union sbs_rw_data data;
- int result = 0;
-
- result = acpi_ec_sbs_access(sbs, addr,
- ACPI_SBS_SMBUS_READ, func,
- ACPI_SBS_WORD_DATA, &data);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_ec_sbs_access() failed"));
- } else {
- *word = data.word;
- }
-
- return result;
+ return battery_scale((battery->spec & 0x0f00) >> 8);
}
-static int
-acpi_sbs_read_str(struct acpi_sbs *sbs, int addr, int func, char *str)
+static inline int acpi_battery_ipscale(struct acpi_battery *battery)
{
- union sbs_rw_data data;
- int result = 0;
-
- result = acpi_ec_sbs_access(sbs, addr,
- ACPI_SBS_SMBUS_READ, func,
- ACPI_SBS_BLOCK_DATA, &data);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_ec_sbs_access() failed"));
- } else {
- strncpy(str, (const char *)data.block + 1, data.block[0]);
- str[data.block[0]] = 0;
- }
-
- return result;
+ return battery_scale((battery->spec & 0xf000) >> 12);
}
-static int
-acpi_sbs_write_word(struct acpi_sbs *sbs, int addr, int func, int word)
+static inline int acpi_battery_mode(struct acpi_battery *battery)
{
- union sbs_rw_data data;
- int result = 0;
-
- data.word = word;
-
- result = acpi_ec_sbs_access(sbs, addr,
- ACPI_SBS_SMBUS_WRITE, func,
- ACPI_SBS_WORD_DATA, &data);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_ec_sbs_access() failed"));
- }
-
- return result;
+ return (battery->mode & 0x8000);
}
-static int sbs_zombie(struct acpi_sbs *sbs)
+static inline int acpi_battery_scale(struct acpi_battery *battery)
{
- return (sbs->zombie);
+ return (acpi_battery_mode(battery) ? 10 : 1) *
+ acpi_battery_ipscale(battery);
}
-static int sbs_mutex_lock(struct acpi_sbs *sbs)
+static int sbs_get_ac_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
{
- if (sbs_zombie(sbs)) {
- return -ENODEV;
+ struct acpi_sbs *sbs = to_acpi_sbs(psy);
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = sbs->charger_present;
+ break;
+ default:
+ return -EINVAL;
}
- mutex_lock(&sbs->mutex);
return 0;
}
-static void sbs_mutex_unlock(struct acpi_sbs *sbs)
+static int acpi_battery_technology(struct acpi_battery *battery)
{
- mutex_unlock(&sbs->mutex);
+ if (!strcasecmp("NiCd", battery->device_chemistry))
+ return POWER_SUPPLY_TECHNOLOGY_NiCd;
+ if (!strcasecmp("NiMH", battery->device_chemistry))
+ return POWER_SUPPLY_TECHNOLOGY_NiMH;
+ if (!strcasecmp("LION", battery->device_chemistry))
+ return POWER_SUPPLY_TECHNOLOGY_LION;
+ if (!strcasecmp("LiP", battery->device_chemistry))
+ return POWER_SUPPLY_TECHNOLOGY_LIPO;
+ return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
}
-/* --------------------------------------------------------------------------
- Smart Battery System Management
- -------------------------------------------------------------------------- */
-
-static int acpi_check_update_proc(struct acpi_sbs *sbs)
+static int acpi_sbs_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
{
- acpi_status status = AE_OK;
+ struct acpi_battery *battery = to_acpi_battery(psy);
- if (update_time == 0) {
- sbs->update_proc_flg = 0;
- return 0;
- }
- if (sbs->update_proc_flg == 0) {
- status = acpi_os_execute(OSL_GPE_HANDLER,
- acpi_sbs_update_time, sbs);
- if (status != AE_OK) {
- ACPI_EXCEPTION((AE_INFO, status,
- "acpi_os_execute() failed"));
- return 1;
- }
- sbs->update_proc_flg = 1;
+ if ((!battery->present) && psp != POWER_SUPPLY_PROP_PRESENT)
+ return -ENODEV;
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ if (battery->current_now < 0)
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ else if (battery->current_now > 0)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = battery->present;
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = acpi_battery_technology(battery);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+ val->intval = battery->design_voltage *
+ acpi_battery_vscale(battery) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = battery->voltage_now *
+ acpi_battery_vscale(battery) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ val->intval = abs(battery->current_now) *
+ acpi_battery_ipscale(battery) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ val->intval = abs(battery->current_avg) *
+ acpi_battery_ipscale(battery) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = battery->state_of_charge;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
+ val->intval = battery->design_capacity *
+ acpi_battery_scale(battery) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ case POWER_SUPPLY_PROP_ENERGY_FULL:
+ val->intval = battery->full_charge_capacity *
+ acpi_battery_scale(battery) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ case POWER_SUPPLY_PROP_ENERGY_NOW:
+ val->intval = battery->capacity_now *
+ acpi_battery_scale(battery) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ val->intval = battery->temp_now - 2730; // dK -> dC
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = battery->device_name;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = battery->manufacturer_name;
+ break;
+ default:
+ return -EINVAL;
}
return 0;
}
-static int acpi_sbs_generate_event(struct acpi_device *device,
- int event, int state, char *bid, char *class)
-{
- char bid_saved[5];
- char class_saved[20];
- int result = 0;
-
- strcpy(bid_saved, acpi_device_bid(device));
- strcpy(class_saved, acpi_device_class(device));
-
- strcpy(acpi_device_bid(device), bid);
- strcpy(acpi_device_class(device), class);
-
- result = acpi_bus_generate_proc_event(device, event, state);
-
- strcpy(acpi_device_bid(device), bid_saved);
- strcpy(acpi_device_class(device), class_saved);
-
- acpi_bus_generate_netlink_event(class, bid, event, state);
- return result;
-}
-
-static int acpi_battery_get_present(struct acpi_battery *battery)
-{
- s16 state;
- int result = 0;
- int is_present = 0;
-
- result = acpi_sbs_read_word(battery->sbs,
- ACPI_SBSM_SMBUS_ADDR, 0x01, &state);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- }
- if (!result) {
- is_present = (state & 0x000f) & (1 << battery->id);
- }
- battery->battery_present = is_present;
-
- return result;
-}
+static enum power_supply_property sbs_ac_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
-static int acpi_battery_select(struct acpi_battery *battery)
-{
- struct acpi_sbs *sbs = battery->sbs;
- int result = 0;
- s16 state;
- int foo;
+static enum power_supply_property sbs_charge_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
- if (sbs->sbsm_present) {
+static enum power_supply_property sbs_energy_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
+ POWER_SUPPLY_PROP_ENERGY_FULL,
+ POWER_SUPPLY_PROP_ENERGY_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
- /* Take special care not to knobble other nibbles of
- * state (aka selector_state), since
- * it causes charging to halt on SBSELs */
+/* --------------------------------------------------------------------------
+ Smart Battery System Management
+ -------------------------------------------------------------------------- */
- result =
- acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, &state);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
+struct acpi_battery_reader {
+ u8 command; /* command for battery */
+ u8 mode; /* word or block? */
+ size_t offset; /* offset inside struct acpi_sbs_battery */
+};
- foo = (state & 0x0fff) | (1 << (battery->id + 12));
- result =
- acpi_sbs_write_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, foo);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_write_word() failed"));
- goto end;
- }
- }
+static struct acpi_battery_reader info_readers[] = {
+ {0x01, SMBUS_READ_WORD, offsetof(struct acpi_battery, alarm_capacity)},
+ {0x03, SMBUS_READ_WORD, offsetof(struct acpi_battery, mode)},
+ {0x10, SMBUS_READ_WORD, offsetof(struct acpi_battery, full_charge_capacity)},
+ {0x17, SMBUS_READ_WORD, offsetof(struct acpi_battery, cycle_count)},
+ {0x18, SMBUS_READ_WORD, offsetof(struct acpi_battery, design_capacity)},
+ {0x19, SMBUS_READ_WORD, offsetof(struct acpi_battery, design_voltage)},
+ {0x1a, SMBUS_READ_WORD, offsetof(struct acpi_battery, spec)},
+ {0x1c, SMBUS_READ_WORD, offsetof(struct acpi_battery, serial_number)},
+ {0x20, SMBUS_READ_BLOCK, offsetof(struct acpi_battery, manufacturer_name)},
+ {0x21, SMBUS_READ_BLOCK, offsetof(struct acpi_battery, device_name)},
+ {0x22, SMBUS_READ_BLOCK, offsetof(struct acpi_battery, device_chemistry)},
+};
- end:
- return result;
-}
+static struct acpi_battery_reader state_readers[] = {
+ {0x08, SMBUS_READ_WORD, offsetof(struct acpi_battery, temp_now)},
+ {0x09, SMBUS_READ_WORD, offsetof(struct acpi_battery, voltage_now)},
+ {0x0a, SMBUS_READ_WORD, offsetof(struct acpi_battery, current_now)},
+ {0x0b, SMBUS_READ_WORD, offsetof(struct acpi_battery, current_avg)},
+ {0x0f, SMBUS_READ_WORD, offsetof(struct acpi_battery, capacity_now)},
+ {0x0e, SMBUS_READ_WORD, offsetof(struct acpi_battery, state_of_charge)},
+ {0x16, SMBUS_READ_WORD, offsetof(struct acpi_battery, state)},
+};
-static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
+static int acpi_manager_get_info(struct acpi_sbs *sbs)
{
int result = 0;
- s16 battery_system_info;
-
- result = acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x04,
- &battery_system_info);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
- sbs->sbsm_present = 1;
- sbs->sbsm_batteries_supported = battery_system_info & 0x000f;
-
- end:
+ u16 battery_system_info;
+ result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER,
+ 0x04, (u8 *)&battery_system_info);
+ if (!result)
+ sbs->batteries_supported = battery_system_info & 0x000f;
return result;
}
static int acpi_battery_get_info(struct acpi_battery *battery)
{
- struct acpi_sbs *sbs = battery->sbs;
- int result = 0;
- s16 battery_mode;
- s16 specification_info;
-
- result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03,
- &battery_mode);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
- battery->info.capacity_mode = (battery_mode & 0x8000) >> 15;
-
- result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x10,
- &battery->info.full_charge_capacity);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
-
- result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x18,
- &battery->info.design_capacity);
-
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
-
- result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x19,
- &battery->info.design_voltage);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
+ int i, result = 0;
+
+ for (i = 0; i < ARRAY_SIZE(info_readers); ++i) {
+ result = acpi_smbus_read(battery->sbs->hc,
+ info_readers[i].mode,
+ ACPI_SBS_BATTERY,
+ info_readers[i].command,
+ (u8 *) battery +
+ info_readers[i].offset);
+ if (result)
+ break;
}
-
- result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1a,
- &specification_info);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
-
- switch ((specification_info & 0x0f00) >> 8) {
- case 1:
- battery->info.vscale = 10;
- break;
- case 2:
- battery->info.vscale = 100;
- break;
- case 3:
- battery->info.vscale = 1000;
- break;
- default:
- battery->info.vscale = 1;
- }
-
- switch ((specification_info & 0xf000) >> 12) {
- case 1:
- battery->info.ipscale = 10;
- break;
- case 2:
- battery->info.ipscale = 100;
- break;
- case 3:
- battery->info.ipscale = 1000;
- break;
- default:
- battery->info.ipscale = 1;
- }
-
- result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1c,
- &battery->info.serial_number);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
-
- result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x20,
- battery->info.manufacturer_name);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_str() failed"));
- goto end;
- }
-
- result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x21,
- battery->info.device_name);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_str() failed"));
- goto end;
- }
-
- result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x22,
- battery->info.device_chemistry);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_str() failed"));
- goto end;
- }
-
- end:
return result;
}
static int acpi_battery_get_state(struct acpi_battery *battery)
{
- struct acpi_sbs *sbs = battery->sbs;
- int result = 0;
+ int i, result = 0;
- result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x09,
- &battery->state.voltage);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
-
- result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0a,
- &battery->state.amperage);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
-
- result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0f,
- &battery->state.remaining_capacity);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
-
- result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x16,
- &battery->state.battery_state);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
+ if (battery->update_time &&
+ time_before(jiffies, battery->update_time +
+ msecs_to_jiffies(cache_time)))
+ return 0;
+ for (i = 0; i < ARRAY_SIZE(state_readers); ++i) {
+ result = acpi_smbus_read(battery->sbs->hc,
+ state_readers[i].mode,
+ ACPI_SBS_BATTERY,
+ state_readers[i].command,
+ (u8 *)battery +
+ state_readers[i].offset);
+ if (result)
+ goto end;
}
-
end:
+ battery->update_time = jiffies;
return result;
}
static int acpi_battery_get_alarm(struct acpi_battery *battery)
{
- struct acpi_sbs *sbs = battery->sbs;
- int result = 0;
-
- result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01,
- &battery->alarm.remaining_capacity);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
-
- end:
-
- return result;
+ return acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD,
+ ACPI_SBS_BATTERY, 0x01,
+ (u8 *)&battery->alarm_capacity);
}
-static int acpi_battery_set_alarm(struct acpi_battery *battery,
- unsigned long alarm)
+static int acpi_battery_set_alarm(struct acpi_battery *battery)
{
struct acpi_sbs *sbs = battery->sbs;
- int result = 0;
- s16 battery_mode;
- int foo;
+ u16 value, sel = 1 << (battery->id + 12);
- result = acpi_battery_select(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_select() failed"));
- goto end;
- }
+ int ret;
- /* If necessary, enable the alarm */
- if (alarm > 0) {
- result =
- acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03,
- &battery_mode);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
+ if (sbs->manager_present) {
+ ret = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER,
+ 0x01, (u8 *)&value);
+ if (ret)
goto end;
- }
-
- result =
- acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01,
- battery_mode & 0xbfff);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_write_word() failed"));
+ if ((value & 0xf000) != sel) {
+ value &= 0x0fff;
+ value |= sel;
+ ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD,
+ ACPI_SBS_MANAGER,
+ 0x01, (u8 *)&value, 2);
+ if (ret)
goto end;
}
}
-
- foo = alarm / (battery->info.capacity_mode ? 10 : 1);
- result = acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, foo);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_write_word() failed"));
- goto end;
- }
-
+ ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_BATTERY,
+ 0x01, (u8 *)&battery->alarm_capacity, 2);
end:
-
- return result;
+ return ret;
}
-static int acpi_battery_set_mode(struct acpi_battery *battery)
+static int acpi_ac_get_present(struct acpi_sbs *sbs)
{
- struct acpi_sbs *sbs = battery->sbs;
- int result = 0;
- s16 battery_mode;
-
- if (capacity_mode == DEF_CAPACITY_UNIT) {
- goto end;
- }
-
- result = acpi_sbs_read_word(sbs,
- ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
-
- if (capacity_mode == MAH_CAPACITY_UNIT) {
- battery_mode &= 0x7fff;
- } else {
- battery_mode |= 0x8000;
- }
- result = acpi_sbs_write_word(sbs,
- ACPI_SB_SMBUS_ADDR, 0x03, battery_mode);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_write_word() failed"));
- goto end;
- }
-
- result = acpi_sbs_read_word(sbs,
- ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
+ int result;
+ u16 status;
- end:
+ result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_CHARGER,
+ 0x13, (u8 *) & status);
+ if (!result)
+ sbs->charger_present = (status >> 15) & 0x1;
return result;
}
-static int acpi_battery_init(struct acpi_battery *battery)
+static ssize_t acpi_battery_alarm_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- int result = 0;
-
- result = acpi_battery_select(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_select() failed"));
- goto end;
- }
-
- result = acpi_battery_set_mode(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_set_mode() failed"));
- goto end;
- }
-
- result = acpi_battery_get_info(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_get_info() failed"));
- goto end;
- }
-
- result = acpi_battery_get_state(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_get_state() failed"));
- goto end;
- }
-
- result = acpi_battery_get_alarm(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_get_alarm() failed"));
- goto end;
- }
-
- end:
- return result;
+ struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
+ acpi_battery_get_alarm(battery);
+ return sprintf(buf, "%d\n", battery->alarm_capacity *
+ acpi_battery_scale(battery) * 1000);
}
-static int acpi_ac_get_present(struct acpi_sbs *sbs)
+static ssize_t acpi_battery_alarm_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- int result = 0;
- s16 charger_status;
-
- result = acpi_sbs_read_word(sbs, ACPI_SBC_SMBUS_ADDR, 0x13,
- &charger_status);
-
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_read_word() failed"));
- goto end;
- }
-
- sbs->ac.ac_present = (charger_status & 0x8000) >> 15;
-
- end:
-
- return result;
+ unsigned long x;
+ struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
+ if (sscanf(buf, "%ld\n", &x) == 1)
+ battery->alarm_capacity = x /
+ (1000 * acpi_battery_scale(battery));
+ if (battery->present)
+ acpi_battery_set_alarm(battery);
+ return count;
}
+static struct device_attribute alarm_attr = {
+ .attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE},
+ .show = acpi_battery_alarm_show,
+ .store = acpi_battery_alarm_store,
+};
+
/* --------------------------------------------------------------------------
FS Interface (/proc/acpi)
-------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
/* Generic Routines */
-
static int
-acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
- struct proc_dir_entry *parent_dir,
- char *dir_name,
- struct file_operations *info_fops,
- struct file_operations *state_fops,
- struct file_operations *alarm_fops, void *data)
+acpi_sbs_add_fs(struct proc_dir_entry **dir,
+ struct proc_dir_entry *parent_dir,
+ char *dir_name,
+ struct file_operations *info_fops,
+ struct file_operations *state_fops,
+ struct file_operations *alarm_fops, void *data)
{
struct proc_dir_entry *entry = NULL;
if (!*dir) {
*dir = proc_mkdir(dir_name, parent_dir);
if (!*dir) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "proc_mkdir() failed"));
return -ENODEV;
}
(*dir)->owner = THIS_MODULE;
@@ -882,10 +492,7 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
/* 'info' [R] */
if (info_fops) {
entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir);
- if (!entry) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "create_proc_entry() failed"));
- } else {
+ if (entry) {
entry->proc_fops = info_fops;
entry->data = data;
entry->owner = THIS_MODULE;
@@ -895,10 +502,7 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
/* 'state' [R] */
if (state_fops) {
entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir);
- if (!entry) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "create_proc_entry() failed"));
- } else {
+ if (entry) {
entry->proc_fops = state_fops;
entry->data = data;
entry->owner = THIS_MODULE;
@@ -908,24 +512,19 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
/* 'alarm' [R/W] */
if (alarm_fops) {
entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir);
- if (!entry) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "create_proc_entry() failed"));
- } else {
+ if (entry) {
entry->proc_fops = alarm_fops;
entry->data = data;
entry->owner = THIS_MODULE;
}
}
-
return 0;
}
static void
-acpi_sbs_generic_remove_fs(struct proc_dir_entry **dir,
+acpi_sbs_remove_fs(struct proc_dir_entry **dir,
struct proc_dir_entry *parent_dir)
{
-
if (*dir) {
remove_proc_entry(ACPI_SBS_FILE_INFO, *dir);
remove_proc_entry(ACPI_SBS_FILE_STATE, *dir);
@@ -933,82 +532,52 @@ acpi_sbs_generic_remove_fs(struct proc_dir_entry **dir,
remove_proc_entry((*dir)->name, parent_dir);
*dir = NULL;
}
-
}
/* Smart Battery Interface */
-
static struct proc_dir_entry *acpi_battery_dir = NULL;
+static inline char *acpi_battery_units(struct acpi_battery *battery)
+{
+ return acpi_battery_mode(battery) ? " mWh" : " mAh";
+}
+
+
static int acpi_battery_read_info(struct seq_file *seq, void *offset)
{
struct acpi_battery *battery = seq->private;
struct acpi_sbs *sbs = battery->sbs;
- int cscale;
int result = 0;
- if (sbs_mutex_lock(sbs)) {
- return -ENODEV;
- }
-
- result = acpi_check_update_proc(sbs);
- if (result)
- goto end;
-
- if (update_time == 0) {
- result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_INFO);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_update_run() failed"));
- }
- }
+ mutex_lock(&sbs->lock);
- if (battery->battery_present) {
- seq_printf(seq, "present: yes\n");
- } else {
- seq_printf(seq, "present: no\n");
+ seq_printf(seq, "present: %s\n",
+ (battery->present) ? "yes" : "no");
+ if (!battery->present)
goto end;
- }
- if (battery->info.capacity_mode) {
- cscale = battery->info.vscale * battery->info.ipscale;
- } else {
- cscale = battery->info.ipscale;
- }
seq_printf(seq, "design capacity: %i%s\n",
- battery->info.design_capacity * cscale,
- battery->info.capacity_mode ? "0 mWh" : " mAh");
-
+ battery->design_capacity * acpi_battery_scale(battery),
+ acpi_battery_units(battery));
seq_printf(seq, "last full capacity: %i%s\n",
- battery->info.full_charge_capacity * cscale,
- battery->info.capacity_mode ? "0 mWh" : " mAh");
-
+ battery->full_charge_capacity * acpi_battery_scale(battery),
+ acpi_battery_units(battery));
seq_printf(seq, "battery technology: rechargeable\n");
-
seq_printf(seq, "design voltage: %i mV\n",
- battery->info.design_voltage * battery->info.vscale);
-
+ battery->design_voltage * acpi_battery_vscale(battery));
seq_printf(seq, "design capacity warning: unknown\n");
seq_printf(seq, "design capacity low: unknown\n");
seq_printf(seq, "capacity granularity 1: unknown\n");
seq_printf(seq, "capacity granularity 2: unknown\n");
-
- seq_printf(seq, "model number: %s\n",
- battery->info.device_name);
-
+ seq_printf(seq, "model number: %s\n", battery->device_name);
seq_printf(seq, "serial number: %i\n",
- battery->info.serial_number);
-
+ battery->serial_number);
seq_printf(seq, "battery type: %s\n",
- battery->info.device_chemistry);
-
+ battery->device_chemistry);
seq_printf(seq, "OEM info: %s\n",
- battery->info.manufacturer_name);
-
+ battery->manufacturer_name);
end:
-
- sbs_mutex_unlock(sbs);
-
+ mutex_unlock(&sbs->lock);
return result;
}
@@ -1022,73 +591,29 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
struct acpi_battery *battery = seq->private;
struct acpi_sbs *sbs = battery->sbs;
int result = 0;
- int cscale;
- int foo;
-
- if (sbs_mutex_lock(sbs)) {
- return -ENODEV;
- }
- result = acpi_check_update_proc(sbs);
- if (result)
+ mutex_lock(&sbs->lock);
+ seq_printf(seq, "present: %s\n",
+ (battery->present) ? "yes" : "no");
+ if (!battery->present)
goto end;
- if (update_time == 0) {
- result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_STATE);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_update_run() failed"));
- }
- }
-
- if (battery->battery_present) {
- seq_printf(seq, "present: yes\n");
- } else {
- seq_printf(seq, "present: no\n");
- goto end;
- }
-
- if (battery->info.capacity_mode) {
- cscale = battery->info.vscale * battery->info.ipscale;
- } else {
- cscale = battery->info.ipscale;
- }
-
- if (battery->state.battery_state & 0x0010) {
- seq_printf(seq, "capacity state: critical\n");
- } else {
- seq_printf(seq, "capacity state: ok\n");
- }
-
- foo = (s16) battery->state.amperage * battery->info.ipscale;
- if (battery->info.capacity_mode) {
- foo = foo * battery->info.design_voltage / 1000;
- }
- if (battery->state.amperage < 0) {
- seq_printf(seq, "charging state: discharging\n");
- seq_printf(seq, "present rate: %d %s\n",
- -foo, battery->info.capacity_mode ? "mW" : "mA");
- } else if (battery->state.amperage > 0) {
- seq_printf(seq, "charging state: charging\n");
- seq_printf(seq, "present rate: %d %s\n",
- foo, battery->info.capacity_mode ? "mW" : "mA");
- } else {
- seq_printf(seq, "charging state: charged\n");
- seq_printf(seq, "present rate: 0 %s\n",
- battery->info.capacity_mode ? "mW" : "mA");
- }
-
+ acpi_battery_get_state(battery);
+ seq_printf(seq, "capacity state: %s\n",
+ (battery->state & 0x0010) ? "critical" : "ok");
+ seq_printf(seq, "charging state: %s\n",
+ (battery->current_now < 0) ? "discharging" :
+ ((battery->current_now > 0) ? "charging" : "charged"));
+ seq_printf(seq, "present rate: %d mA\n",
+ abs(battery->current_now) * acpi_battery_ipscale(battery));
seq_printf(seq, "remaining capacity: %i%s\n",
- battery->state.remaining_capacity * cscale,
- battery->info.capacity_mode ? "0 mWh" : " mAh");
-
+ battery->capacity_now * acpi_battery_scale(battery),
+ acpi_battery_units(battery));
seq_printf(seq, "present voltage: %i mV\n",
- battery->state.voltage * battery->info.vscale);
+ battery->voltage_now * acpi_battery_vscale(battery));
end:
-
- sbs_mutex_unlock(sbs);
-
+ mutex_unlock(&sbs->lock);
return result;
}
@@ -1102,48 +627,25 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
struct acpi_battery *battery = seq->private;
struct acpi_sbs *sbs = battery->sbs;
int result = 0;
- int cscale;
-
- if (sbs_mutex_lock(sbs)) {
- return -ENODEV;
- }
-
- result = acpi_check_update_proc(sbs);
- if (result)
- goto end;
- if (update_time == 0) {
- result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_ALARM);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_update_run() failed"));
- }
- }
+ mutex_lock(&sbs->lock);
- if (!battery->battery_present) {
+ if (!battery->present) {
seq_printf(seq, "present: no\n");
goto end;
}
- if (battery->info.capacity_mode) {
- cscale = battery->info.vscale * battery->info.ipscale;
- } else {
- cscale = battery->info.ipscale;
- }
-
+ acpi_battery_get_alarm(battery);
seq_printf(seq, "alarm: ");
- if (battery->alarm.remaining_capacity) {
+ if (battery->alarm_capacity)
seq_printf(seq, "%i%s\n",
- battery->alarm.remaining_capacity * cscale,
- battery->info.capacity_mode ? "0 mWh" : " mAh");
- } else {
+ battery->alarm_capacity *
+ acpi_battery_scale(battery),
+ acpi_battery_units(battery));
+ else
seq_printf(seq, "disabled\n");
- }
-
end:
-
- sbs_mutex_unlock(sbs);
-
+ mutex_unlock(&sbs->lock);
return result;
}
@@ -1155,59 +657,29 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer,
struct acpi_battery *battery = seq->private;
struct acpi_sbs *sbs = battery->sbs;
char alarm_string[12] = { '\0' };
- int result, old_alarm, new_alarm;
-
- if (sbs_mutex_lock(sbs)) {
- return -ENODEV;
- }
-
- result = acpi_check_update_proc(sbs);
- if (result)
- goto end;
-
- if (!battery->battery_present) {
+ int result = 0;
+ mutex_lock(&sbs->lock);
+ if (!battery->present) {
result = -ENODEV;
goto end;
}
-
if (count > sizeof(alarm_string) - 1) {
result = -EINVAL;
goto end;
}
-
if (copy_from_user(alarm_string, buffer, count)) {
result = -EFAULT;
goto end;
}
-
alarm_string[count] = 0;
-
- old_alarm = battery->alarm.remaining_capacity;
- new_alarm = simple_strtoul(alarm_string, NULL, 0);
-
- result = acpi_battery_set_alarm(battery, new_alarm);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_set_alarm() failed"));
- acpi_battery_set_alarm(battery, old_alarm);
- goto end;
- }
- result = acpi_battery_get_alarm(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_get_alarm() failed"));
- acpi_battery_set_alarm(battery, old_alarm);
- goto end;
- }
-
+ battery->alarm_capacity = simple_strtoul(alarm_string, NULL, 0) /
+ acpi_battery_scale(battery);
+ acpi_battery_set_alarm(battery);
end:
- sbs_mutex_unlock(sbs);
-
- if (result) {
+ mutex_unlock(&sbs->lock);
+ if (result)
return result;
- } else {
- return count;
- }
+ return count;
}
static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
@@ -1246,26 +718,15 @@ static struct proc_dir_entry *acpi_ac_dir = NULL;
static int acpi_ac_read_state(struct seq_file *seq, void *offset)
{
- struct acpi_sbs *sbs = seq->private;
- int result;
- if (sbs_mutex_lock(sbs)) {
- return -ENODEV;
- }
+ struct acpi_sbs *sbs = seq->private;
- if (update_time == 0) {
- result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_AC_STATE);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_update_run() failed"));
- }
- }
+ mutex_lock(&sbs->lock);
seq_printf(seq, "state: %s\n",
- sbs->ac.ac_present ? "on-line" : "off-line");
-
- sbs_mutex_unlock(sbs);
+ sbs->charger_present ? "on-line" : "off-line");
+ mutex_unlock(&sbs->lock);
return 0;
}
@@ -1282,429 +743,211 @@ static struct file_operations acpi_ac_state_fops = {
.owner = THIS_MODULE,
};
+#endif
+
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
+static int acpi_battery_read(struct acpi_battery *battery)
+{
+ int result = 0, saved_present = battery->present;
+ u16 state;
+
+ if (battery->sbs->manager_present) {
+ result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD,
+ ACPI_SBS_MANAGER, 0x01, (u8 *)&state);
+ if (!result)
+ battery->present = state & (1 << battery->id);
+ state &= 0x0fff;
+ state |= 1 << (battery->id + 12);
+ acpi_smbus_write(battery->sbs->hc, SMBUS_WRITE_WORD,
+ ACPI_SBS_MANAGER, 0x01, (u8 *)&state, 2);
+ } else if (battery->id == 0)
+ battery->present = 1;
+ if (result || !battery->present)
+ return result;
-/* Smart Battery */
+ if (saved_present != battery->present) {
+ battery->update_time = 0;
+ result = acpi_battery_get_info(battery);
+ if (result)
+ return result;
+ }
+ result = acpi_battery_get_state(battery);
+ return result;
+}
+/* Smart Battery */
static int acpi_battery_add(struct acpi_sbs *sbs, int id)
{
- int is_present;
+ struct acpi_battery *battery = &sbs->battery[id];
int result;
- char dir_name[32];
- struct acpi_battery *battery;
-
- battery = &sbs->battery[id];
-
- battery->alive = 0;
- battery->init_state = 0;
battery->id = id;
battery->sbs = sbs;
+ result = acpi_battery_read(battery);
+ if (result)
+ return result;
- result = acpi_battery_select(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_select() failed"));
- goto end;
+ sprintf(battery->name, ACPI_BATTERY_DIR_NAME, id);
+#ifdef CONFIG_ACPI_PROCFS
+ acpi_sbs_add_fs(&battery->proc_entry, acpi_battery_dir,
+ battery->name, &acpi_battery_info_fops,
+ &acpi_battery_state_fops, &acpi_battery_alarm_fops,
+ battery);
+#endif
+ battery->bat.name = battery->name;
+ battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+ if (!acpi_battery_mode(battery)) {
+ battery->bat.properties = sbs_charge_battery_props;
+ battery->bat.num_properties =
+ ARRAY_SIZE(sbs_charge_battery_props);
+ } else {
+ battery->bat.properties = sbs_energy_battery_props;
+ battery->bat.num_properties =
+ ARRAY_SIZE(sbs_energy_battery_props);
}
-
- result = acpi_battery_get_present(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_get_present() failed"));
+ battery->bat.get_property = acpi_sbs_battery_get_property;
+ result = power_supply_register(&sbs->device->dev, &battery->bat);
+ if (result)
goto end;
- }
-
- is_present = battery->battery_present;
-
- if (is_present) {
- result = acpi_battery_init(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_init() failed"));
- goto end;
- }
- battery->init_state = 1;
- }
-
- sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
-
- result = acpi_sbs_generic_add_fs(&battery->battery_entry,
- acpi_battery_dir,
- dir_name,
- &acpi_battery_info_fops,
- &acpi_battery_state_fops,
- &acpi_battery_alarm_fops, battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_generic_add_fs() failed"));
+ result = device_create_file(battery->bat.dev, &alarm_attr);
+ if (result)
goto end;
- }
- battery->alive = 1;
-
- printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
- ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), dir_name,
- sbs->battery->battery_present ? "present" : "absent");
-
+ battery->have_sysfs_alarm = 1;
end:
+ printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
+ ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
+ battery->name, sbs->battery->present ? "present" : "absent");
return result;
}
static void acpi_battery_remove(struct acpi_sbs *sbs, int id)
{
+ struct acpi_battery *battery = &sbs->battery[id];
- if (sbs->battery[id].battery_entry) {
- acpi_sbs_generic_remove_fs(&(sbs->battery[id].battery_entry),
- acpi_battery_dir);
+ if (battery->bat.dev) {
+ if (battery->have_sysfs_alarm)
+ device_remove_file(battery->bat.dev, &alarm_attr);
+ power_supply_unregister(&battery->bat);
}
+#ifdef CONFIG_ACPI_PROCFS
+ if (battery->proc_entry)
+ acpi_sbs_remove_fs(&battery->proc_entry, acpi_battery_dir);
+#endif
}
-static int acpi_ac_add(struct acpi_sbs *sbs)
+static int acpi_charger_add(struct acpi_sbs *sbs)
{
int result;
result = acpi_ac_get_present(sbs);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_ac_get_present() failed"));
+ if (result)
goto end;
- }
-
- result = acpi_sbs_generic_add_fs(&sbs->ac_entry,
- acpi_ac_dir,
- ACPI_AC_DIR_NAME,
- NULL, &acpi_ac_state_fops, NULL, sbs);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_generic_add_fs() failed"));
+#ifdef CONFIG_ACPI_PROCFS
+ result = acpi_sbs_add_fs(&sbs->charger_entry, acpi_ac_dir,
+ ACPI_AC_DIR_NAME, NULL,
+ &acpi_ac_state_fops, NULL, sbs);
+ if (result)
goto end;
- }
-
+#endif
+ sbs->charger.name = "sbs-charger";
+ sbs->charger.type = POWER_SUPPLY_TYPE_MAINS;
+ sbs->charger.properties = sbs_ac_props;
+ sbs->charger.num_properties = ARRAY_SIZE(sbs_ac_props);
+ sbs->charger.get_property = sbs_get_ac_property;
+ power_supply_register(&sbs->device->dev, &sbs->charger);
printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n",
ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
- ACPI_AC_DIR_NAME, sbs->ac.ac_present ? "on-line" : "off-line");
-
+ ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line");
end:
-
return result;
}
-static void acpi_ac_remove(struct acpi_sbs *sbs)
+static void acpi_charger_remove(struct acpi_sbs *sbs)
{
-
- if (sbs->ac_entry) {
- acpi_sbs_generic_remove_fs(&sbs->ac_entry, acpi_ac_dir);
- }
+ if (sbs->charger.dev)
+ power_supply_unregister(&sbs->charger);
+#ifdef CONFIG_ACPI_PROCFS
+ if (sbs->charger_entry)
+ acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir);
+#endif
}
-static void acpi_sbs_update_time_run(unsigned long data)
+void acpi_sbs_callback(void *context)
{
- acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_time, (void *)data);
-}
-
-static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type)
-{
- struct acpi_battery *battery;
- int result = 0, cnt;
- int old_ac_present = -1;
- int old_battery_present = -1;
- int new_ac_present = -1;
- int new_battery_present = -1;
- int id_min = 0, id_max = MAX_SBS_BAT - 1;
- char dir_name[32];
- int do_battery_init = 0, do_ac_init = 0;
- int old_remaining_capacity = 0;
- int update_battery = 1;
- int up_tm = update_time;
-
- if (sbs_zombie(sbs)) {
- goto end;
- }
-
- if (id >= 0) {
- id_min = id_max = id;
- }
-
- if (data_type == DATA_TYPE_COMMON && up_tm > 0) {
- cnt = up_tm / (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm);
- if (sbs->run_cnt % cnt != 0) {
- update_battery = 0;
- }
- }
-
- sbs->run_cnt++;
-
- old_ac_present = sbs->ac.ac_present;
-
- result = acpi_ac_get_present(sbs);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_ac_get_present() failed"));
- }
-
- new_ac_present = sbs->ac.ac_present;
-
- do_ac_init = (old_ac_present != new_ac_present);
- if (sbs->run_cnt == 1 && data_type == DATA_TYPE_COMMON) {
- do_ac_init = 1;
- }
-
- if (do_ac_init) {
- result = acpi_sbs_generate_event(sbs->device,
- ACPI_SBS_AC_NOTIFY_STATUS,
- new_ac_present,
- ACPI_AC_DIR_NAME,
- ACPI_AC_CLASS);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_generate_event() failed"));
- }
- }
-
- if (data_type == DATA_TYPE_COMMON) {
- if (!do_ac_init && !update_battery) {
- goto end;
- }
- }
-
- if (data_type == DATA_TYPE_AC_STATE && !do_ac_init) {
- goto end;
- }
-
- for (id = id_min; id <= id_max; id++) {
- battery = &sbs->battery[id];
- if (battery->alive == 0) {
- continue;
- }
-
- old_remaining_capacity = battery->state.remaining_capacity;
-
- old_battery_present = battery->battery_present;
-
- result = acpi_battery_select(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_select() failed"));
- }
-
- result = acpi_battery_get_present(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_get_present() failed"));
- }
-
- new_battery_present = battery->battery_present;
-
- do_battery_init = ((old_battery_present != new_battery_present)
- && new_battery_present);
- if (!new_battery_present)
- goto event;
- if (do_ac_init || do_battery_init) {
- result = acpi_battery_init(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_init() "
- "failed"));
- }
- }
- if (sbs_zombie(sbs)) {
- goto end;
- }
-
- if ((data_type == DATA_TYPE_COMMON
- || data_type == DATA_TYPE_INFO)
- && new_battery_present) {
- result = acpi_battery_get_info(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_get_info() failed"));
- }
- }
- if (data_type == DATA_TYPE_INFO) {
- continue;
- }
- if (sbs_zombie(sbs)) {
- goto end;
- }
-
- if ((data_type == DATA_TYPE_COMMON
- || data_type == DATA_TYPE_STATE)
- && new_battery_present) {
- result = acpi_battery_get_state(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_get_state() failed"));
- }
- }
- if (data_type == DATA_TYPE_STATE) {
- goto event;
- }
- if (sbs_zombie(sbs)) {
- goto end;
- }
-
- if ((data_type == DATA_TYPE_COMMON
- || data_type == DATA_TYPE_ALARM)
- && new_battery_present) {
- result = acpi_battery_get_alarm(battery);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_get_alarm() "
- "failed"));
- }
- }
- if (data_type == DATA_TYPE_ALARM) {
- continue;
- }
- if (sbs_zombie(sbs)) {
- goto end;
- }
-
- event:
-
- if (old_battery_present != new_battery_present || do_ac_init ||
- old_remaining_capacity !=
- battery->state.remaining_capacity) {
- sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
- result = acpi_sbs_generate_event(sbs->device,
- ACPI_SBS_BATTERY_NOTIFY_STATUS,
- new_battery_present,
- dir_name,
- ACPI_BATTERY_CLASS);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_generate_event() "
- "failed"));
- }
+ int id;
+ struct acpi_sbs *sbs = context;
+ struct acpi_battery *bat;
+ u8 saved_charger_state = sbs->charger_present;
+ u8 saved_battery_state;
+ acpi_ac_get_present(sbs);
+ if (sbs->charger_present != saved_charger_state) {
+#ifdef CONFIG_ACPI_PROC_EVENT
+ acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME,
+ ACPI_SBS_NOTIFY_STATUS,
+ sbs->charger_present);
+#endif
+ kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE);
+ }
+ if (sbs->manager_present) {
+ for (id = 0; id < MAX_SBS_BAT; ++id) {
+ if (!(sbs->batteries_supported & (1 << id)))
+ continue;
+ bat = &sbs->battery[id];
+ saved_battery_state = bat->present;
+ acpi_battery_read(bat);
+ if (saved_battery_state == bat->present)
+ continue;
+#ifdef CONFIG_ACPI_PROC_EVENT
+ acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS,
+ bat->name,
+ ACPI_SBS_NOTIFY_STATUS,
+ bat->present);
+#endif
+ kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE);
}
}
-
- end:
-
- return result;
}
-static void acpi_sbs_update_time(void *data)
-{
- struct acpi_sbs *sbs = data;
- unsigned long delay = -1;
- int result;
- unsigned int up_tm = update_time;
-
- if (sbs_mutex_lock(sbs))
- return;
-
- result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_COMMON);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_update_run() failed"));
- }
-
- if (sbs_zombie(sbs)) {
- goto end;
- }
-
- if (!up_tm) {
- if (timer_pending(&sbs->update_timer))
- del_timer(&sbs->update_timer);
- } else {
- delay = (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm);
- delay = jiffies + HZ * delay;
- if (timer_pending(&sbs->update_timer)) {
- mod_timer(&sbs->update_timer, delay);
- } else {
- sbs->update_timer.data = (unsigned long)data;
- sbs->update_timer.function = acpi_sbs_update_time_run;
- sbs->update_timer.expires = delay;
- add_timer(&sbs->update_timer);
- }
- }
-
- end:
-
- sbs_mutex_unlock(sbs);
-}
+static int acpi_sbs_remove(struct acpi_device *device, int type);
static int acpi_sbs_add(struct acpi_device *device)
{
- struct acpi_sbs *sbs = NULL;
- int result = 0, remove_result = 0;
+ struct acpi_sbs *sbs;
+ int result = 0;
int id;
- acpi_status status = AE_OK;
- unsigned long val;
-
- status =
- acpi_evaluate_integer(device->handle, "_EC", NULL, &val);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC"));
- return -EIO;
- }
sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
if (!sbs) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR, "kzalloc() failed"));
result = -ENOMEM;
goto end;
}
- mutex_init(&sbs->mutex);
+ mutex_init(&sbs->lock);
- sbs_mutex_lock(sbs);
-
- sbs->base = 0xff & (val >> 8);
+ sbs->hc = acpi_driver_data(device->parent);
sbs->device = device;
-
strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
acpi_driver_data(device) = sbs;
- result = acpi_ac_add(sbs);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed"));
- goto end;
- }
-
- acpi_sbsm_get_info(sbs);
-
- if (!sbs->sbsm_present) {
- result = acpi_battery_add(sbs, 0);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_add() failed"));
- goto end;
- }
- } else {
- for (id = 0; id < MAX_SBS_BAT; id++) {
- if ((sbs->sbsm_batteries_supported & (1 << id))) {
- result = acpi_battery_add(sbs, id);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_battery_add() failed"));
- goto end;
- }
- }
- }
- }
-
- init_timer(&sbs->update_timer);
- result = acpi_check_update_proc(sbs);
+ result = acpi_charger_add(sbs);
if (result)
goto end;
+ result = acpi_manager_get_info(sbs);
+ if (!result) {
+ sbs->manager_present = 1;
+ for (id = 0; id < MAX_SBS_BAT; ++id)
+ if ((sbs->batteries_supported & (1 << id)))
+ acpi_battery_add(sbs, id);
+ } else
+ acpi_battery_add(sbs, 0);
+ acpi_smbus_register_callback(sbs->hc, acpi_sbs_callback, sbs);
end:
-
- sbs_mutex_unlock(sbs);
-
- if (result) {
- remove_result = acpi_sbs_remove(device, 0);
- if (remove_result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbs_remove() failed"));
- }
- }
-
+ if (result)
+ acpi_sbs_remove(device, 0);
return result;
}
@@ -1713,39 +956,25 @@ static int acpi_sbs_remove(struct acpi_device *device, int type)
struct acpi_sbs *sbs;
int id;
- if (!device) {
+ if (!device)
return -EINVAL;
- }
-
sbs = acpi_driver_data(device);
- if (!sbs) {
+ if (!sbs)
return -EINVAL;
- }
-
- sbs_mutex_lock(sbs);
-
- sbs->zombie = 1;
- del_timer_sync(&sbs->update_timer);
- acpi_os_wait_events_complete(NULL);
- del_timer_sync(&sbs->update_timer);
-
- for (id = 0; id < MAX_SBS_BAT; id++) {
+ mutex_lock(&sbs->lock);
+ acpi_smbus_unregister_callback(sbs->hc);
+ for (id = 0; id < MAX_SBS_BAT; ++id)
acpi_battery_remove(sbs, id);
- }
-
- acpi_ac_remove(sbs);
-
- sbs_mutex_unlock(sbs);
-
- mutex_destroy(&sbs->mutex);
-
+ acpi_charger_remove(sbs);
+ mutex_unlock(&sbs->lock);
+ mutex_destroy(&sbs->lock);
kfree(sbs);
-
return 0;
}
static void acpi_sbs_rmdirs(void)
{
+#ifdef CONFIG_ACPI_PROCFS
if (acpi_ac_dir) {
acpi_unlock_ac_dir(acpi_ac_dir);
acpi_ac_dir = NULL;
@@ -1754,69 +983,58 @@ static void acpi_sbs_rmdirs(void)
acpi_unlock_battery_dir(acpi_battery_dir);
acpi_battery_dir = NULL;
}
+#endif
}
static int acpi_sbs_resume(struct acpi_device *device)
{
struct acpi_sbs *sbs;
-
if (!device)
return -EINVAL;
-
sbs = device->driver_data;
-
- sbs->run_cnt = 0;
-
+ acpi_sbs_callback(sbs);
return 0;
}
+static struct acpi_driver acpi_sbs_driver = {
+ .name = "sbs",
+ .class = ACPI_SBS_CLASS,
+ .ids = sbs_device_ids,
+ .ops = {
+ .add = acpi_sbs_add,
+ .remove = acpi_sbs_remove,
+ .resume = acpi_sbs_resume,
+ },
+};
+
static int __init acpi_sbs_init(void)
{
int result = 0;
if (acpi_disabled)
return -ENODEV;
-
- if (capacity_mode != DEF_CAPACITY_UNIT
- && capacity_mode != MAH_CAPACITY_UNIT
- && capacity_mode != MWH_CAPACITY_UNIT) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "invalid capacity_mode = %d", capacity_mode));
- return -EINVAL;
- }
-
+#ifdef CONFIG_ACPI_PROCFS
acpi_ac_dir = acpi_lock_ac_dir();
- if (!acpi_ac_dir) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_lock_ac_dir() failed"));
+ if (!acpi_ac_dir)
return -ENODEV;
- }
-
acpi_battery_dir = acpi_lock_battery_dir();
if (!acpi_battery_dir) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_lock_battery_dir() failed"));
acpi_sbs_rmdirs();
return -ENODEV;
}
-
+#endif
result = acpi_bus_register_driver(&acpi_sbs_driver);
if (result < 0) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_bus_register_driver() failed"));
acpi_sbs_rmdirs();
return -ENODEV;
}
-
return 0;
}
static void __exit acpi_sbs_exit(void)
{
acpi_bus_unregister_driver(&acpi_sbs_driver);
-
acpi_sbs_rmdirs();
-
return;
}
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
new file mode 100644
index 00000000000..046d7c3ed35
--- /dev/null
+++ b/drivers/acpi/sbshc.c
@@ -0,0 +1,309 @@
+/*
+ * SMBus driver for ACPI Embedded Controller (v0.1)
+ *
+ * Copyright (c) 2007 Alexey Starikovskiy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2.
+ */
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/actypes.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "sbshc.h"
+
+#define ACPI_SMB_HC_CLASS "smbus_host_controller"
+#define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC"
+
+struct acpi_smb_hc {
+ struct acpi_ec *ec;
+ struct mutex lock;
+ wait_queue_head_t wait;
+ u8 offset;
+ u8 query_bit;
+ smbus_alarm_callback callback;
+ void *context;
+};
+
+static int acpi_smbus_hc_add(struct acpi_device *device);
+static int acpi_smbus_hc_remove(struct acpi_device *device, int type);
+
+static const struct acpi_device_id sbs_device_ids[] = {
+ {"ACPI0001", 0},
+ {"ACPI0005", 0},
+ {"", 0},
+};
+
+MODULE_DEVICE_TABLE(acpi, sbs_device_ids);
+
+static struct acpi_driver acpi_smb_hc_driver = {
+ .name = "smbus_hc",
+ .class = ACPI_SMB_HC_CLASS,
+ .ids = sbs_device_ids,
+ .ops = {
+ .add = acpi_smbus_hc_add,
+ .remove = acpi_smbus_hc_remove,
+ },
+};
+
+union acpi_smb_status {
+ u8 raw;
+ struct {
+ u8 status:5;
+ u8 reserved:1;
+ u8 alarm:1;
+ u8 done:1;
+ } fields;
+};
+
+enum acpi_smb_status_codes {
+ SMBUS_OK = 0,
+ SMBUS_UNKNOWN_FAILURE = 0x07,
+ SMBUS_DEVICE_ADDRESS_NACK = 0x10,
+ SMBUS_DEVICE_ERROR = 0x11,
+ SMBUS_DEVICE_COMMAND_ACCESS_DENIED = 0x12,
+ SMBUS_UNKNOWN_ERROR = 0x13,
+ SMBUS_DEVICE_ACCESS_DENIED = 0x17,
+ SMBUS_TIMEOUT = 0x18,
+ SMBUS_HOST_UNSUPPORTED_PROTOCOL = 0x19,
+ SMBUS_BUSY = 0x1a,
+ SMBUS_PEC_ERROR = 0x1f,
+};
+
+enum acpi_smb_offset {
+ ACPI_SMB_PROTOCOL = 0, /* protocol, PEC */
+ ACPI_SMB_STATUS = 1, /* status */
+ ACPI_SMB_ADDRESS = 2, /* address */
+ ACPI_SMB_COMMAND = 3, /* command */
+ ACPI_SMB_DATA = 4, /* 32 data registers */
+ ACPI_SMB_BLOCK_COUNT = 0x24, /* number of data bytes */
+ ACPI_SMB_ALARM_ADDRESS = 0x25, /* alarm address */
+ ACPI_SMB_ALARM_DATA = 0x26, /* 2 bytes alarm data */
+};
+
+static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data)
+{
+ return ec_read(hc->offset + address, data);
+}
+
+static inline int smb_hc_write(struct acpi_smb_hc *hc, u8 address, u8 data)
+{
+ return ec_write(hc->offset + address, data);
+}
+
+static inline int smb_check_done(struct acpi_smb_hc *hc)
+{
+ union acpi_smb_status status = {.raw = 0};
+ smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw);
+ return status.fields.done && (status.fields.status == SMBUS_OK);
+}
+
+static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout)
+{
+ if (wait_event_timeout(hc->wait, smb_check_done(hc),
+ msecs_to_jiffies(timeout)))
+ return 0;
+ else
+ return -ETIME;
+}
+
+int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol, u8 address,
+ u8 command, u8 *data, u8 length)
+{
+ int ret = -EFAULT, i;
+ u8 temp, sz = 0;
+
+ mutex_lock(&hc->lock);
+ if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp))
+ goto end;
+ if (temp) {
+ ret = -EBUSY;
+ goto end;
+ }
+ smb_hc_write(hc, ACPI_SMB_COMMAND, command);
+ smb_hc_write(hc, ACPI_SMB_COMMAND, command);
+ if (!(protocol & 0x01)) {
+ smb_hc_write(hc, ACPI_SMB_BLOCK_COUNT, length);
+ for (i = 0; i < length; ++i)
+ smb_hc_write(hc, ACPI_SMB_DATA + i, data[i]);
+ }
+ smb_hc_write(hc, ACPI_SMB_ADDRESS, address << 1);
+ smb_hc_write(hc, ACPI_SMB_PROTOCOL, protocol);
+ /*
+ * Wait for completion. Save the status code, data size,
+ * and data into the return package (if required by the protocol).
+ */
+ ret = wait_transaction_complete(hc, 1000);
+ if (ret || !(protocol & 0x01))
+ goto end;
+ switch (protocol) {
+ case SMBUS_RECEIVE_BYTE:
+ case SMBUS_READ_BYTE:
+ sz = 1;
+ break;
+ case SMBUS_READ_WORD:
+ sz = 2;
+ break;
+ case SMBUS_READ_BLOCK:
+ if (smb_hc_read(hc, ACPI_SMB_BLOCK_COUNT, &sz)) {
+ ret = -EFAULT;
+ goto end;
+ }
+ sz &= 0x1f;
+ break;
+ }
+ for (i = 0; i < sz; ++i)
+ smb_hc_read(hc, ACPI_SMB_DATA + i, &data[i]);
+ end:
+ mutex_unlock(&hc->lock);
+ return ret;
+}
+
+int acpi_smbus_read(struct acpi_smb_hc *hc, u8 protocol, u8 address,
+ u8 command, u8 *data)
+{
+ return acpi_smbus_transaction(hc, protocol, address, command, data, 0);
+}
+
+EXPORT_SYMBOL_GPL(acpi_smbus_read);
+
+int acpi_smbus_write(struct acpi_smb_hc *hc, u8 protocol, u8 address,
+ u8 command, u8 *data, u8 length)
+{
+ return acpi_smbus_transaction(hc, protocol, address, command, data, length);
+}
+
+EXPORT_SYMBOL_GPL(acpi_smbus_write);
+
+int acpi_smbus_register_callback(struct acpi_smb_hc *hc,
+ smbus_alarm_callback callback, void *context)
+{
+ mutex_lock(&hc->lock);
+ hc->callback = callback;
+ hc->context = context;
+ mutex_unlock(&hc->lock);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(acpi_smbus_register_callback);
+
+int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc)
+{
+ mutex_lock(&hc->lock);
+ hc->callback = NULL;
+ hc->context = NULL;
+ mutex_unlock(&hc->lock);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(acpi_smbus_unregister_callback);
+
+static void acpi_smbus_callback(void *context)
+{
+ struct acpi_smb_hc *hc = context;
+
+ if (hc->callback)
+ hc->callback(hc->context);
+}
+
+static int smbus_alarm(void *context)
+{
+ struct acpi_smb_hc *hc = context;
+ union acpi_smb_status status;
+ if (smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw))
+ return 0;
+ /* Check if it is only a completion notify */
+ if (status.fields.done)
+ wake_up(&hc->wait);
+ if (!status.fields.alarm)
+ return 0;
+ mutex_lock(&hc->lock);
+ smb_hc_write(hc, ACPI_SMB_STATUS, status.raw);
+ if (hc->callback)
+ acpi_os_execute(OSL_GPE_HANDLER, acpi_smbus_callback, hc);
+ mutex_unlock(&hc->lock);
+ return 0;
+}
+
+typedef int (*acpi_ec_query_func) (void *data);
+
+extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
+ acpi_handle handle, acpi_ec_query_func func,
+ void *data);
+
+static int acpi_smbus_hc_add(struct acpi_device *device)
+{
+ int status;
+ unsigned long val;
+ struct acpi_smb_hc *hc;
+
+ if (!device)
+ return -EINVAL;
+
+ status = acpi_evaluate_integer(device->handle, "_EC", NULL, &val);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "error obtaining _EC.\n");
+ return -EIO;
+ }
+
+ strcpy(acpi_device_name(device), ACPI_SMB_HC_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_SMB_HC_CLASS);
+
+ hc = kzalloc(sizeof(struct acpi_smb_hc), GFP_KERNEL);
+ if (!hc)
+ return -ENOMEM;
+ mutex_init(&hc->lock);
+ init_waitqueue_head(&hc->wait);
+
+ hc->ec = acpi_driver_data(device->parent);
+ hc->offset = (val >> 8) & 0xff;
+ hc->query_bit = val & 0xff;
+ acpi_driver_data(device) = hc;
+
+ acpi_ec_add_query_handler(hc->ec, hc->query_bit, NULL, smbus_alarm, hc);
+ printk(KERN_INFO PREFIX "SBS HC: EC = 0x%p, offset = 0x%0x, query_bit = 0x%0x\n",
+ hc->ec, hc->offset, hc->query_bit);
+
+ return 0;
+}
+
+extern void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
+
+static int acpi_smbus_hc_remove(struct acpi_device *device, int type)
+{
+ struct acpi_smb_hc *hc;
+
+ if (!device)
+ return -EINVAL;
+
+ hc = acpi_driver_data(device);
+ acpi_ec_remove_query_handler(hc->ec, hc->query_bit);
+ kfree(hc);
+ return 0;
+}
+
+static int __init acpi_smb_hc_init(void)
+{
+ int result;
+
+ result = acpi_bus_register_driver(&acpi_smb_hc_driver);
+ if (result < 0)
+ return -ENODEV;
+ return 0;
+}
+
+static void __exit acpi_smb_hc_exit(void)
+{
+ acpi_bus_unregister_driver(&acpi_smb_hc_driver);
+}
+
+module_init(acpi_smb_hc_init);
+module_exit(acpi_smb_hc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexey Starikovskiy");
+MODULE_DESCRIPTION("ACPI SMBus HC driver");
diff --git a/drivers/acpi/sbshc.h b/drivers/acpi/sbshc.h
new file mode 100644
index 00000000000..3bda3491a97
--- /dev/null
+++ b/drivers/acpi/sbshc.h
@@ -0,0 +1,27 @@
+struct acpi_smb_hc;
+enum acpi_smb_protocol {
+ SMBUS_WRITE_QUICK = 2,
+ SMBUS_READ_QUICK = 3,
+ SMBUS_SEND_BYTE = 4,
+ SMBUS_RECEIVE_BYTE = 5,
+ SMBUS_WRITE_BYTE = 6,
+ SMBUS_READ_BYTE = 7,
+ SMBUS_WRITE_WORD = 8,
+ SMBUS_READ_WORD = 9,
+ SMBUS_WRITE_BLOCK = 0xa,
+ SMBUS_READ_BLOCK = 0xb,
+ SMBUS_PROCESS_CALL = 0xc,
+ SMBUS_BLOCK_PROCESS_CALL = 0xd,
+};
+
+static const u8 SMBUS_PEC = 0x80;
+
+typedef void (*smbus_alarm_callback)(void *context);
+
+extern int acpi_smbus_read(struct acpi_smb_hc *hc, u8 protocol, u8 address,
+ u8 command, u8 * data);
+extern int acpi_smbus_write(struct acpi_smb_hc *hc, u8 protocol, u8 slave_address,
+ u8 command, u8 * data, u8 length);
+extern int acpi_smbus_register_callback(struct acpi_smb_hc *hc,
+ smbus_alarm_callback callback, void *context);
+extern int acpi_smbus_unregister_callback(struct acpi_smb_hc *hc);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 64620d66874..5b4d462117c 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -319,16 +319,18 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv)
return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
}
-static int acpi_device_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
+ int len;
- strcpy(buffer, "MODALIAS=");
- if (create_modalias(acpi_dev, buffer + 9, buffer_size - 9) > 0) {
- envp[0] = buffer;
- envp[1] = NULL;
- }
+ if (add_uevent_var(env, "MODALIAS="))
+ return -ENOMEM;
+ len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen);
+ if (len >= (sizeof(env->buf) - env->buflen))
+ return -ENOMEM;
+ env->buflen += len;
return 0;
}
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 2cbb9aabd00..2c0b6630f8b 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -44,13 +44,12 @@ int acpi_sleep_prepare(u32 acpi_state)
ACPI_FLUSH_CPU_CACHE();
acpi_enable_wakeup_device_prep(acpi_state);
#endif
- acpi_gpe_sleep_prepare(acpi_state);
acpi_enter_sleep_state_prep(acpi_state);
return 0;
}
#ifdef CONFIG_SUSPEND
-static struct pm_ops acpi_pm_ops;
+static struct platform_suspend_ops acpi_pm_ops;
extern void do_suspend_lowlevel(void);
@@ -85,13 +84,12 @@ static int acpi_pm_set_target(suspend_state_t pm_state)
/**
* acpi_pm_prepare - Do preliminary suspend work.
- * @pm_state: ignored
*
* If necessary, set the firmware waking vector and do arch-specific
* nastiness to get the wakeup code to the waking vector.
*/
-static int acpi_pm_prepare(suspend_state_t pm_state)
+static int acpi_pm_prepare(void)
{
int error = acpi_sleep_prepare(acpi_target_sleep_state);
@@ -160,18 +158,17 @@ static int acpi_pm_enter(suspend_state_t pm_state)
/**
* acpi_pm_finish - Finish up suspend sequence.
- * @pm_state: ignored
*
* This is called after we wake back up (or if entering the sleep state
* failed).
*/
-static int acpi_pm_finish(suspend_state_t pm_state)
+static void acpi_pm_finish(void)
{
u32 acpi_state = acpi_target_sleep_state;
- acpi_leave_sleep_state(acpi_state);
acpi_disable_wakeup_device(acpi_state);
+ acpi_leave_sleep_state(acpi_state);
/* reset firmware waking vector */
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
@@ -184,7 +181,6 @@ static int acpi_pm_finish(suspend_state_t pm_state)
init_8259A(0);
}
#endif
- return 0;
}
static int acpi_pm_state_valid(suspend_state_t pm_state)
@@ -203,7 +199,7 @@ static int acpi_pm_state_valid(suspend_state_t pm_state)
}
}
-static struct pm_ops acpi_pm_ops = {
+static struct platform_suspend_ops acpi_pm_ops = {
.valid = acpi_pm_state_valid,
.set_target = acpi_pm_set_target,
.prepare = acpi_pm_prepare,
@@ -215,7 +211,7 @@ static struct pm_ops acpi_pm_ops = {
* Toshiba fails to preserve interrupts over S1, reinitialization
* of 8259 is needed after S1 resume.
*/
-static int __init init_ints_after_s1(struct dmi_system_id *d)
+static int __init init_ints_after_s1(const struct dmi_system_id *d)
{
printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
init_8259A_after_S1 = 1;
@@ -233,6 +229,12 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
#endif /* CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATION
+static int acpi_hibernation_start(void)
+{
+ acpi_target_sleep_state = ACPI_STATE_S4;
+ return 0;
+}
+
static int acpi_hibernation_prepare(void)
{
return acpi_sleep_prepare(ACPI_STATE_S4);
@@ -254,13 +256,29 @@ static int acpi_hibernation_enter(void)
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
}
+static void acpi_hibernation_leave(void)
+{
+ /*
+ * If ACPI is not enabled by the BIOS and the boot kernel, we need to
+ * enable it here.
+ */
+ acpi_enable();
+}
+
static void acpi_hibernation_finish(void)
{
- acpi_leave_sleep_state(ACPI_STATE_S4);
+ /*
+ * If ACPI is not enabled by the BIOS and the boot kernel, we need to
+ * enable it here.
+ */
+ acpi_enable();
acpi_disable_wakeup_device(ACPI_STATE_S4);
+ acpi_leave_sleep_state(ACPI_STATE_S4);
/* reset firmware waking vector */
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+
+ acpi_target_sleep_state = ACPI_STATE_S0;
}
static int acpi_hibernation_pre_restore(void)
@@ -277,10 +295,13 @@ static void acpi_hibernation_restore_cleanup(void)
acpi_hw_enable_all_runtime_gpes();
}
-static struct hibernation_ops acpi_hibernation_ops = {
+static struct platform_hibernation_ops acpi_hibernation_ops = {
+ .start = acpi_hibernation_start,
+ .pre_snapshot = acpi_hibernation_prepare,
+ .finish = acpi_hibernation_finish,
.prepare = acpi_hibernation_prepare,
.enter = acpi_hibernation_enter,
- .finish = acpi_hibernation_finish,
+ .leave = acpi_hibernation_leave,
.pre_restore = acpi_hibernation_pre_restore,
.restore_cleanup = acpi_hibernation_restore_cleanup,
};
@@ -389,6 +410,7 @@ static void acpi_power_off(void)
/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
printk("%s called\n", __FUNCTION__);
local_irq_disable();
+ acpi_enable_wakeup_device(ACPI_STATE_S5);
acpi_enter_sleep_state(ACPI_STATE_S5);
}
@@ -417,7 +439,7 @@ int __init acpi_sleep_init(void)
}
}
- pm_set_ops(&acpi_pm_ops);
+ suspend_set_ops(&acpi_pm_ops);
#endif
#ifdef CONFIG_HIBERNATION
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 3839efd5eae..1538355c266 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -194,6 +194,23 @@ static int get_date_field(char **p, u32 * value)
return result;
}
+/* Read a possibly BCD register, always return binary */
+static u32 cmos_bcd_read(int offset, int rtc_control)
+{
+ u32 val = CMOS_READ(offset);
+ if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ BCD_TO_BIN(val);
+ return val;
+}
+
+/* Write binary value into possibly BCD register */
+static void cmos_bcd_write(u32 val, int offset, int rtc_control)
+{
+ if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ BIN_TO_BCD(val);
+ CMOS_WRITE(val, offset);
+}
+
static ssize_t
acpi_system_write_alarm(struct file *file,
const char __user * buffer, size_t count, loff_t * ppos)
@@ -258,35 +275,18 @@ acpi_system_write_alarm(struct file *file,
spin_lock_irq(&rtc_lock);
rtc_control = CMOS_READ(RTC_CONTROL);
- if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- BIN_TO_BCD(yr);
- BIN_TO_BCD(mo);
- BIN_TO_BCD(day);
- BIN_TO_BCD(hr);
- BIN_TO_BCD(min);
- BIN_TO_BCD(sec);
- }
if (adjust) {
- yr += CMOS_READ(RTC_YEAR);
- mo += CMOS_READ(RTC_MONTH);
- day += CMOS_READ(RTC_DAY_OF_MONTH);
- hr += CMOS_READ(RTC_HOURS);
- min += CMOS_READ(RTC_MINUTES);
- sec += CMOS_READ(RTC_SECONDS);
+ yr += cmos_bcd_read(RTC_YEAR, rtc_control);
+ mo += cmos_bcd_read(RTC_MONTH, rtc_control);
+ day += cmos_bcd_read(RTC_DAY_OF_MONTH, rtc_control);
+ hr += cmos_bcd_read(RTC_HOURS, rtc_control);
+ min += cmos_bcd_read(RTC_MINUTES, rtc_control);
+ sec += cmos_bcd_read(RTC_SECONDS, rtc_control);
}
spin_unlock_irq(&rtc_lock);
- if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- BCD_TO_BIN(yr);
- BCD_TO_BIN(mo);
- BCD_TO_BIN(day);
- BCD_TO_BIN(hr);
- BCD_TO_BIN(min);
- BCD_TO_BIN(sec);
- }
-
if (sec > 59) {
min++;
sec -= 60;
@@ -307,14 +307,6 @@ acpi_system_write_alarm(struct file *file,
yr++;
mo -= 12;
}
- if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- BIN_TO_BCD(yr);
- BIN_TO_BCD(mo);
- BIN_TO_BCD(day);
- BIN_TO_BCD(hr);
- BIN_TO_BCD(min);
- BIN_TO_BCD(sec);
- }
spin_lock_irq(&rtc_lock);
/*
@@ -326,9 +318,9 @@ acpi_system_write_alarm(struct file *file,
CMOS_READ(RTC_INTR_FLAGS);
/* write the fields the rtc knows about */
- CMOS_WRITE(hr, RTC_HOURS_ALARM);
- CMOS_WRITE(min, RTC_MINUTES_ALARM);
- CMOS_WRITE(sec, RTC_SECONDS_ALARM);
+ cmos_bcd_write(hr, RTC_HOURS_ALARM, rtc_control);
+ cmos_bcd_write(min, RTC_MINUTES_ALARM, rtc_control);
+ cmos_bcd_write(sec, RTC_SECONDS_ALARM, rtc_control);
/*
* If the system supports an enhanced alarm it will have non-zero
@@ -336,11 +328,11 @@ acpi_system_write_alarm(struct file *file,
* to the RTC area of memory.
*/
if (acpi_gbl_FADT.day_alarm)
- CMOS_WRITE(day, acpi_gbl_FADT.day_alarm);
+ cmos_bcd_write(day, acpi_gbl_FADT.day_alarm, rtc_control);
if (acpi_gbl_FADT.month_alarm)
- CMOS_WRITE(mo, acpi_gbl_FADT.month_alarm);
+ cmos_bcd_write(mo, acpi_gbl_FADT.month_alarm, rtc_control);
if (acpi_gbl_FADT.century)
- CMOS_WRITE(yr / 100, acpi_gbl_FADT.century);
+ cmos_bcd_write(yr / 100, acpi_gbl_FADT.century, rtc_control);
/* enable the rtc alarm interrupt */
rtc_control |= RTC_AIE;
CMOS_WRITE(rtc_control, RTC_CONTROL);
diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h
index ff1f8504f49..a2ea125ae2d 100644
--- a/drivers/acpi/sleep/sleep.h
+++ b/drivers/acpi/sleep/sleep.h
@@ -5,6 +5,5 @@ extern int acpi_suspend (u32 state);
extern void acpi_enable_wakeup_device_prep(u8 sleep_state);
extern void acpi_enable_wakeup_device(u8 sleep_state);
extern void acpi_disable_wakeup_device(u8 sleep_state);
-extern void acpi_gpe_sleep_prepare(u32 sleep_state);
extern int acpi_sleep_prepare(u32 acpi_state);
diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c
index 97c27ddb144..ed8e41becf0 100644
--- a/drivers/acpi/sleep/wakeup.c
+++ b/drivers/acpi/sleep/wakeup.c
@@ -64,36 +64,29 @@ void acpi_enable_wakeup_device(u8 sleep_state)
ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device");
spin_lock(&acpi_device_lock);
list_for_each_safe(node, next, &acpi_wakeup_device_list) {
- struct acpi_device *dev = container_of(node,
- struct acpi_device,
- wakeup_list);
-
+ struct acpi_device *dev =
+ container_of(node, struct acpi_device, wakeup_list);
+ if (!dev->wakeup.flags.valid)
+ continue;
/* If users want to disable run-wake GPE,
* we only disable it for wake and leave it for runtime
*/
- if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
- spin_unlock(&acpi_device_lock);
- acpi_set_gpe_type(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number,
- ACPI_GPE_TYPE_RUNTIME);
- /* Re-enable it, since set_gpe_type will disable it */
- acpi_enable_gpe(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number, ACPI_ISR);
- spin_lock(&acpi_device_lock);
+ if (!dev->wakeup.state.enabled ||
+ sleep_state > (u32) dev->wakeup.sleep_state) {
+ if (dev->wakeup.flags.run_wake) {
+ spin_unlock(&acpi_device_lock);
+ /* set_gpe_type will disable GPE, leave it like that */
+ acpi_set_gpe_type(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number,
+ ACPI_GPE_TYPE_RUNTIME);
+ spin_lock(&acpi_device_lock);
+ }
continue;
}
-
- if (!dev->wakeup.flags.valid ||
- !dev->wakeup.state.enabled ||
- (sleep_state > (u32) dev->wakeup.sleep_state))
- continue;
-
spin_unlock(&acpi_device_lock);
- /* run-wake GPE has been enabled */
if (!dev->wakeup.flags.run_wake)
acpi_enable_gpe(dev->wakeup.gpe_device,
dev->wakeup.gpe_number, ACPI_ISR);
- dev->wakeup.state.active = 1;
spin_lock(&acpi_device_lock);
}
spin_unlock(&acpi_device_lock);
@@ -112,26 +105,25 @@ void acpi_disable_wakeup_device(u8 sleep_state)
spin_lock(&acpi_device_lock);
list_for_each_safe(node, next, &acpi_wakeup_device_list) {
- struct acpi_device *dev = container_of(node,
- struct acpi_device,
- wakeup_list);
+ struct acpi_device *dev =
+ container_of(node, struct acpi_device, wakeup_list);
- if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
- spin_unlock(&acpi_device_lock);
- acpi_set_gpe_type(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number,
- ACPI_GPE_TYPE_WAKE_RUN);
- /* Re-enable it, since set_gpe_type will disable it */
- acpi_enable_gpe(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number, ACPI_NOT_ISR);
- spin_lock(&acpi_device_lock);
+ if (!dev->wakeup.flags.valid)
continue;
- }
-
- if (!dev->wakeup.flags.valid ||
- !dev->wakeup.state.active ||
- (sleep_state > (u32) dev->wakeup.sleep_state))
+ if (!dev->wakeup.state.enabled ||
+ sleep_state > (u32) dev->wakeup.sleep_state) {
+ if (dev->wakeup.flags.run_wake) {
+ spin_unlock(&acpi_device_lock);
+ acpi_set_gpe_type(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number,
+ ACPI_GPE_TYPE_WAKE_RUN);
+ /* Re-enable it, since set_gpe_type will disable it */
+ acpi_enable_gpe(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number, ACPI_NOT_ISR);
+ spin_lock(&acpi_device_lock);
+ }
continue;
+ }
spin_unlock(&acpi_device_lock);
acpi_disable_wakeup_device_power(dev);
@@ -142,7 +134,6 @@ void acpi_disable_wakeup_device(u8 sleep_state)
acpi_clear_gpe(dev->wakeup.gpe_device,
dev->wakeup.gpe_number, ACPI_NOT_ISR);
}
- dev->wakeup.state.active = 0;
spin_lock(&acpi_device_lock);
}
spin_unlock(&acpi_device_lock);
@@ -160,48 +151,20 @@ static int __init acpi_wakeup_device_init(void)
struct acpi_device *dev = container_of(node,
struct acpi_device,
wakeup_list);
-
/* In case user doesn't load button driver */
- if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
- spin_unlock(&acpi_device_lock);
- acpi_set_gpe_type(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number,
- ACPI_GPE_TYPE_WAKE_RUN);
- acpi_enable_gpe(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number, ACPI_NOT_ISR);
- dev->wakeup.state.enabled = 1;
- spin_lock(&acpi_device_lock);
- }
+ if (!dev->wakeup.flags.run_wake || dev->wakeup.state.enabled)
+ continue;
+ spin_unlock(&acpi_device_lock);
+ acpi_set_gpe_type(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number,
+ ACPI_GPE_TYPE_WAKE_RUN);
+ acpi_enable_gpe(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number, ACPI_NOT_ISR);
+ dev->wakeup.state.enabled = 1;
+ spin_lock(&acpi_device_lock);
}
spin_unlock(&acpi_device_lock);
-
return 0;
}
late_initcall(acpi_wakeup_device_init);
-
-/*
- * Disable all wakeup GPEs before entering requested sleep state.
- * @sleep_state: ACPI state
- * Since acpi_enter_sleep_state() will disable all
- * RUNTIME GPEs, we simply mark all GPES that
- * are not enabled for wakeup from requested state as RUNTIME.
- */
-void acpi_gpe_sleep_prepare(u32 sleep_state)
-{
- struct list_head *node, *next;
-
- list_for_each_safe(node, next, &acpi_wakeup_device_list) {
- struct acpi_device *dev = container_of(node,
- struct acpi_device,
- wakeup_list);
-
- /* The GPE can wakeup system from this state, don't touch it */
- if ((u32) dev->wakeup.sleep_state >= sleep_state)
- continue;
- /* acpi_set_gpe_type will automatically disable GPE */
- acpi_set_gpe_type(dev->wakeup.gpe_device,
- dev->wakeup.gpe_number,
- ACPI_GPE_TYPE_RUNTIME);
- }
-}
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index 8cc9492ffbf..5f1d85f2ffe 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -400,7 +400,7 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
u32 table_count;
struct acpi_table_header *table;
acpi_physical_address address;
- acpi_physical_address rsdt_address;
+ acpi_physical_address uninitialized_var(rsdt_address);
u32 length;
u8 *table_entry;
acpi_status status;
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index bc6d5866ef9..5f79b445121 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -195,6 +195,7 @@ struct acpi_thermal {
struct acpi_thermal_trips trips;
struct acpi_handle_list devices;
struct timer_list timer;
+ struct mutex lock;
};
static const struct file_operations acpi_thermal_state_fops = {
@@ -711,6 +712,7 @@ static void acpi_thermal_check(void *data)
int result = 0;
struct acpi_thermal *tz = data;
unsigned long sleep_time = 0;
+ unsigned long timeout_jiffies = 0;
int i = 0;
struct acpi_thermal_state state;
@@ -720,11 +722,15 @@ static void acpi_thermal_check(void *data)
return;
}
+ /* Check if someone else is already running */
+ if (!mutex_trylock(&tz->lock))
+ return;
+
state = tz->state;
result = acpi_thermal_get_temperature(tz);
if (result)
- return;
+ goto unlock;
memset(&tz->state, 0, sizeof(tz->state));
@@ -787,10 +793,13 @@ static void acpi_thermal_check(void *data)
* a thermal event occurs). Note that _TSP and _TZD values are
* given in 1/10th seconds (we must covert to milliseconds).
*/
- if (tz->state.passive)
+ if (tz->state.passive) {
sleep_time = tz->trips.passive.tsp * 100;
- else if (tz->polling_frequency > 0)
+ timeout_jiffies = jiffies + (HZ * sleep_time) / 1000;
+ } else if (tz->polling_frequency > 0) {
sleep_time = tz->polling_frequency * 100;
+ timeout_jiffies = round_jiffies(jiffies + (HZ * sleep_time) / 1000);
+ }
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n",
tz->name, tz->temperature, sleep_time));
@@ -804,17 +813,16 @@ static void acpi_thermal_check(void *data)
del_timer(&(tz->timer));
} else {
if (timer_pending(&(tz->timer)))
- mod_timer(&(tz->timer),
- jiffies + (HZ * sleep_time) / 1000);
+ mod_timer(&(tz->timer), timeout_jiffies);
else {
tz->timer.data = (unsigned long)tz;
tz->timer.function = acpi_thermal_run;
- tz->timer.expires = jiffies + (HZ * sleep_time) / 1000;
+ tz->timer.expires = timeout_jiffies;
add_timer(&(tz->timer));
}
}
-
- return;
+ unlock:
+ mutex_unlock(&tz->lock);
}
/* --------------------------------------------------------------------------
@@ -1251,7 +1259,7 @@ static int acpi_thermal_add(struct acpi_device *device)
strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
acpi_driver_data(device) = tz;
-
+ mutex_init(&tz->lock);
result = acpi_thermal_get_info(tz);
if (result)
goto end;
@@ -1321,7 +1329,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
}
acpi_thermal_remove_fs(device);
-
+ mutex_destroy(&tz->lock);
kfree(tz);
return 0;
}
@@ -1360,7 +1368,7 @@ static int acpi_thermal_resume(struct acpi_device *device)
}
#ifdef CONFIG_DMI
-static int thermal_act(struct dmi_system_id *d) {
+static int thermal_act(const struct dmi_system_id *d) {
if (act == 0) {
printk(KERN_NOTICE "ACPI: %s detected: "
@@ -1369,14 +1377,14 @@ static int thermal_act(struct dmi_system_id *d) {
}
return 0;
}
-static int thermal_nocrt(struct dmi_system_id *d) {
+static int thermal_nocrt(const struct dmi_system_id *d) {
printk(KERN_NOTICE "ACPI: %s detected: "
"disabling all critical thermal trip point actions.\n", d->ident);
nocrt = 1;
return 0;
}
-static int thermal_tzp(struct dmi_system_id *d) {
+static int thermal_tzp(const struct dmi_system_id *d) {
if (tzp == 0) {
printk(KERN_NOTICE "ACPI: %s detected: "
@@ -1385,7 +1393,7 @@ static int thermal_tzp(struct dmi_system_id *d) {
}
return 0;
}
-static int thermal_psv(struct dmi_system_id *d) {
+static int thermal_psv(const struct dmi_system_id *d) {
if (psv == 0) {
printk(KERN_NOTICE "ACPI: %s detected: "
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
index 13369b45563..9e8c20c6a0b 100644
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/acpi/toshiba_acpi.c
@@ -362,7 +362,7 @@ static unsigned long write_video(const char *buffer, unsigned long count)
int crt_out = -1;
int tv_out = -1;
u32 hci_result;
- int video_out;
+ u32 video_out;
/* scan expression. Multiple expressions may be delimited with ;
*
@@ -591,9 +591,12 @@ static int __init toshiba_acpi_init(void)
NULL,
&toshiba_backlight_data);
if (IS_ERR(toshiba_backlight_device)) {
+ int ret = PTR_ERR(toshiba_backlight_device);
+
printk(KERN_ERR "Could not register toshiba backlight device\n");
toshiba_backlight_device = NULL;
toshiba_acpi_exit();
+ return ret;
}
toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index d05891f1628..bac956b30c5 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -316,7 +316,7 @@ static int acpi_video_output_get(struct output_device *od)
{
unsigned long state;
struct acpi_video_device *vd =
- (struct acpi_video_device *)class_get_devdata(&od->class_dev);
+ (struct acpi_video_device *)dev_get_drvdata(&od->dev);
acpi_video_device_get_state(vd, &state);
return (int)state;
}
@@ -325,7 +325,7 @@ 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 *)class_get_devdata(&od->class_dev);
+ (struct acpi_video_device *)dev_get_drvdata(&od->dev);
return acpi_video_device_set_state(vd, state);
}
@@ -409,14 +409,17 @@ acpi_video_device_lcd_query_levels(struct acpi_video_device *device,
static int
acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
{
- int status;
+ int status = AE_OK;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
arg0.integer.value = level;
- status = acpi_evaluate_object(device->dev->handle, "_BCM", &args, NULL);
+ if (device->cap._BCM)
+ status = acpi_evaluate_object(device->dev->handle, "_BCM",
+ &args, NULL);
+ device->brightness->curr = level;
return status;
}
@@ -424,11 +427,11 @@ static int
acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
unsigned long *level)
{
- int status;
-
- status = acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, level);
-
- return status;
+ if (device->cap._BQC)
+ return acpi_evaluate_integer(device->dev->handle, "_BQC", NULL,
+ level);
+ *level = device->brightness->curr;
+ return AE_OK;
}
static int
@@ -1633,9 +1636,20 @@ static int
acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event)
{
- int min, max, min_above, max_below, i, l;
+ int min, max, min_above, max_below, i, l, delta = 255;
max = max_below = 0;
min = min_above = 255;
+ /* Find closest level to level_current */
+ for (i = 0; i < device->brightness->count; i++) {
+ l = device->brightness->levels[i];
+ if (abs(l - level_current) < abs(delta)) {
+ delta = l - level_current;
+ if (!delta)
+ break;
+ }
+ }
+ /* Ajust level_current to closest available level */
+ level_current += delta;
for (i = 0; i < device->brightness->count; i++) {
l = device->brightness->levels[i];
if (l < min)
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 268e301775f..6b94fb7be5f 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -44,15 +44,12 @@ static int amba_match(struct device *dev, struct device_driver *drv)
}
#ifdef CONFIG_HOTPLUG
-static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz)
+static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct amba_device *pcdev = to_amba_device(dev);
- int retval = 0, i = 0, len = 0;
+ int retval = 0;
- retval = add_uevent_var(envp, nr_env, &i,
- buf, bufsz, &len,
- "AMBA_ID=%08x", pcdev->periphid);
- envp[i] = NULL;
+ retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
return retval;
}
#else
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index d8046a113c3..ba63619ae5d 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -173,6 +173,24 @@ config SATA_INIC162X
help
This option enables support for Initio 162x Serial ATA.
+config PATA_ACPI
+ tristate "ACPI firmware driver for PATA"
+ depends on ATA_ACPI
+ help
+ This option enables an ACPI method driver which drives
+ motherboard PATA controller interfaces through the ACPI
+ firmware in the BIOS. This driver can sometimes handle
+ otherwise unsupported hardware.
+
+config SATA_FSL
+ tristate "Freescale 3.0Gbps SATA support"
+ depends on PPC_MPC837x
+ help
+ This option enables support for Freescale 3.0Gbps SATA controller.
+ It can be found on MPC837x and MPC8315.
+
+ If unsure, say N.
+
config PATA_ALI
tristate "ALi PATA support (Experimental)"
depends on PCI && EXPERIMENTAL
@@ -192,16 +210,25 @@ config PATA_AMD
If unsure, say N.
config PATA_ARTOP
- tristate "ARTOP 6210/6260 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "ARTOP 6210/6260 PATA support"
+ depends on PCI
help
This option enables support for ARTOP PATA controllers.
If unsure, say N.
+config PATA_AT32
+ tristate "Atmel AVR32 PATA support (Experimental)"
+ depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL
+ help
+ This option enables support for the IDE devices on the
+ Atmel AT32AP platform.
+
+ If unsure, say N.
+
config PATA_ATIIXP
- tristate "ATI PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "ATI PATA support"
+ depends on PCI
help
This option enables support for the ATI ATA interfaces
found on the many ATI chipsets.
@@ -219,8 +246,8 @@ config PATA_CMD640_PCI
If unsure, say N.
config PATA_CMD64X
- tristate "CMD64x PATA support (Very Experimental)"
- depends on PCI&& EXPERIMENTAL
+ tristate "CMD64x PATA support"
+ depends on PCI
help
This option enables support for the CMD64x series chips
except for the CMD640.
@@ -254,6 +281,15 @@ config PATA_CS5535
If unsure, say N.
+config PATA_CS5536
+ tristate "CS5536 PATA support (Experimental)"
+ depends on PCI && X86 && !X86_64 && EXPERIMENTAL
+ help
+ This option enables support for the AMD CS5536
+ companion chip used with the Geode LX processor family.
+
+ If unsure, say N.
+
config PATA_CYPRESS
tristate "Cypress CY82C693 PATA support (Very Experimental)"
depends on PCI && EXPERIMENTAL
@@ -282,8 +318,8 @@ config ATA_GENERIC
If unsure, say N.
config PATA_HPT366
- tristate "HPT 366/368 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "HPT 366/368 PATA support"
+ depends on PCI
help
This option enables support for the HPT 366 and 368
PATA controllers via the new ATA layer.
@@ -432,6 +468,15 @@ config PATA_NS87410
If unsure, say N.
+config PATA_NS87415
+ tristate "Nat Semi NS87415 PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the National Semiconductor
+ NS87415 PCI-IDE controller.
+
+ If unsure, say N.
+
config PATA_OPTI
tristate "OPTI621/6215 PATA support (Very Experimental)"
depends on PCI && EXPERIMENTAL
@@ -596,4 +641,13 @@ config PATA_SCC
If unsure, say N.
+config PATA_BF54X
+ tristate "Blackfin 54x ATAPI support"
+ depends on BF542 || BF548 || BF549
+ help
+ This option enables support for the built-in ATAPI controller on
+ Blackfin 54x family chips.
+
+ If unsure, say N.
+
endif # ATA
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 8149c68ac2c..b13feb2c5da 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -17,16 +17,19 @@ obj-$(CONFIG_SATA_ULI) += sata_uli.o
obj-$(CONFIG_SATA_MV) += sata_mv.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
+obj-$(CONFIG_SATA_FSL) += sata_fsl.o
obj-$(CONFIG_PATA_ALI) += pata_ali.o
obj-$(CONFIG_PATA_AMD) += pata_amd.o
obj-$(CONFIG_PATA_ARTOP) += pata_artop.o
+obj-$(CONFIG_PATA_AT32) += pata_at32.o
obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o
obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o
obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o
obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o
obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o
obj-$(CONFIG_PATA_CS5535) += pata_cs5535.o
+obj-$(CONFIG_PATA_CS5536) += pata_cs5536.o
obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o
obj-$(CONFIG_PATA_EFAR) += pata_efar.o
obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o
@@ -39,6 +42,7 @@ obj-$(CONFIG_PATA_IT8213) += pata_it8213.o
obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o
+obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o
obj-$(CONFIG_PATA_OPTI) += pata_opti.o
obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o
obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o
@@ -61,12 +65,16 @@ obj-$(CONFIG_PATA_SIS) += pata_sis.o
obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
obj-$(CONFIG_PATA_SCC) += pata_scc.o
+obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o
+# Should be last but two libata driver
+obj-$(CONFIG_PATA_ACPI) += pata_acpi.o
# Should be last but one libata driver
obj-$(CONFIG_ATA_GENERIC) += ata_generic.o
# Should be last libata driver
obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o
-libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o
+libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o \
+ libata-pmp.o
libata-$(CONFIG_ATA_ACPI) += libata-acpi.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index c16820325d7..ed9b407e42d 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -41,13 +41,17 @@
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
+#include <linux/dmi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
#define DRV_NAME "ahci"
-#define DRV_VERSION "2.3"
+#define DRV_VERSION "3.0"
+static int ahci_enable_alpm(struct ata_port *ap,
+ enum link_pm policy);
+static void ahci_disable_alpm(struct ata_port *ap);
enum {
AHCI_PCI_BAR = 5,
@@ -77,11 +81,10 @@ enum {
RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */
board_ahci = 0,
- board_ahci_pi = 1,
- board_ahci_vt8251 = 2,
- board_ahci_ign_iferr = 3,
- board_ahci_sb600 = 4,
- board_ahci_mv = 5,
+ board_ahci_vt8251 = 1,
+ board_ahci_ign_iferr = 2,
+ board_ahci_sb600 = 3,
+ board_ahci_mv = 4,
/* global controller registers */
HOST_CAP = 0x00, /* host capabilities */
@@ -97,7 +100,9 @@ enum {
/* HOST_CAP bits */
HOST_CAP_SSC = (1 << 14), /* Slumber capable */
+ HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */
+ HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */
HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
HOST_CAP_SNTF = (1 << 29), /* SNotification register */
HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
@@ -144,7 +149,8 @@ enum {
PORT_IRQ_IF_ERR |
PORT_IRQ_CONNECT |
PORT_IRQ_PHYRDY |
- PORT_IRQ_UNK_FIS,
+ PORT_IRQ_UNK_FIS |
+ PORT_IRQ_BAD_PMP,
PORT_IRQ_ERROR = PORT_IRQ_FREEZE |
PORT_IRQ_TF_ERR |
PORT_IRQ_HBUS_DATA_ERR,
@@ -153,7 +159,10 @@ enum {
PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS,
/* PORT_CMD bits */
+ PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */
+ PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */
PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */
+ PORT_CMD_PMP = (1 << 17), /* PMP attached */
PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */
PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */
PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */
@@ -167,19 +176,23 @@ enum {
PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
+ /* hpriv->flags bits */
+ AHCI_HFLAG_NO_NCQ = (1 << 0),
+ AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */
+ AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */
+ AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */
+ AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */
+ AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */
+ AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */
+ AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */
+
/* ap->flags bits */
- AHCI_FLAG_NO_NCQ = (1 << 24),
- AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */
- AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */
- AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */
- AHCI_FLAG_32BIT_ONLY = (1 << 28), /* force 32bit */
- AHCI_FLAG_MV_PATA = (1 << 29), /* PATA port */
- AHCI_FLAG_NO_MSI = (1 << 30), /* no PCI MSI */
AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY |
- ATA_FLAG_ACPI_SATA,
+ ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
+ ATA_FLAG_IPM,
+ AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY,
};
struct ahci_cmd_hdr {
@@ -198,6 +211,7 @@ struct ahci_sg {
};
struct ahci_host_priv {
+ unsigned int flags; /* AHCI_HFLAG_* */
u32 cap; /* cap to use */
u32 port_map; /* port map to use */
u32 saved_cap; /* saved initial cap */
@@ -205,6 +219,7 @@ struct ahci_host_priv {
};
struct ahci_port_priv {
+ struct ata_link *active_link;
struct ahci_cmd_hdr *cmd_slot;
dma_addr_t cmd_slot_dma;
void *cmd_tbl;
@@ -215,11 +230,12 @@ struct ahci_port_priv {
unsigned int ncq_saw_d2h:1;
unsigned int ncq_saw_dmas:1;
unsigned int ncq_saw_sdb:1;
+ u32 intr_mask; /* interrupts to enable */
};
static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
-static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static void ahci_irq_clear(struct ata_port *ap);
static int ahci_port_start(struct ata_port *ap);
@@ -229,8 +245,11 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc);
static u8 ahci_check_status(struct ata_port *ap);
static void ahci_freeze(struct ata_port *ap);
static void ahci_thaw(struct ata_port *ap);
+static void ahci_pmp_attach(struct ata_port *ap);
+static void ahci_pmp_detach(struct ata_port *ap);
static void ahci_error_handler(struct ata_port *ap);
static void ahci_vt8251_error_handler(struct ata_port *ap);
+static void ahci_p5wdh_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 unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
@@ -242,6 +261,11 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
static int ahci_pci_device_resume(struct pci_dev *pdev);
#endif
+static struct class_device_attribute *ahci_shost_attrs[] = {
+ &class_device_attr_link_power_management_policy,
+ NULL
+};
+
static struct scsi_host_template ahci_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -259,23 +283,21 @@ static struct scsi_host_template ahci_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+ .shost_attrs = ahci_shost_attrs,
};
static const struct ata_port_operations ahci_ops = {
- .port_disable = ata_port_disable,
-
.check_status = ahci_check_status,
.check_altstatus = ahci_check_status,
.dev_select = ata_noop_dev_select,
.tf_read = ahci_tf_read,
+ .qc_defer = sata_pmp_qc_defer_cmd_switch,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
.irq_clear = ahci_irq_clear,
- .irq_on = ata_dummy_irq_on,
- .irq_ack = ata_dummy_irq_ack,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
@@ -286,30 +308,32 @@ static const struct ata_port_operations ahci_ops = {
.error_handler = ahci_error_handler,
.post_internal_cmd = ahci_post_internal_cmd,
+ .pmp_attach = ahci_pmp_attach,
+ .pmp_detach = ahci_pmp_detach,
+
#ifdef CONFIG_PM
.port_suspend = ahci_port_suspend,
.port_resume = ahci_port_resume,
#endif
+ .enable_pm = ahci_enable_alpm,
+ .disable_pm = ahci_disable_alpm,
.port_start = ahci_port_start,
.port_stop = ahci_port_stop,
};
static const struct ata_port_operations ahci_vt8251_ops = {
- .port_disable = ata_port_disable,
-
.check_status = ahci_check_status,
.check_altstatus = ahci_check_status,
.dev_select = ata_noop_dev_select,
.tf_read = ahci_tf_read,
+ .qc_defer = sata_pmp_qc_defer_cmd_switch,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
.irq_clear = ahci_irq_clear,
- .irq_on = ata_dummy_irq_on,
- .irq_ack = ata_dummy_irq_ack,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
@@ -320,6 +344,43 @@ static const struct ata_port_operations ahci_vt8251_ops = {
.error_handler = ahci_vt8251_error_handler,
.post_internal_cmd = ahci_post_internal_cmd,
+ .pmp_attach = ahci_pmp_attach,
+ .pmp_detach = ahci_pmp_detach,
+
+#ifdef CONFIG_PM
+ .port_suspend = ahci_port_suspend,
+ .port_resume = ahci_port_resume,
+#endif
+
+ .port_start = ahci_port_start,
+ .port_stop = ahci_port_stop,
+};
+
+static const struct ata_port_operations ahci_p5wdh_ops = {
+ .check_status = ahci_check_status,
+ .check_altstatus = ahci_check_status,
+ .dev_select = ata_noop_dev_select,
+
+ .tf_read = ahci_tf_read,
+
+ .qc_defer = sata_pmp_qc_defer_cmd_switch,
+ .qc_prep = ahci_qc_prep,
+ .qc_issue = ahci_qc_issue,
+
+ .irq_clear = ahci_irq_clear,
+
+ .scr_read = ahci_scr_read,
+ .scr_write = ahci_scr_write,
+
+ .freeze = ahci_freeze,
+ .thaw = ahci_thaw,
+
+ .error_handler = ahci_p5wdh_error_handler,
+ .post_internal_cmd = ahci_post_internal_cmd,
+
+ .pmp_attach = ahci_pmp_attach,
+ .pmp_detach = ahci_pmp_detach,
+
#ifdef CONFIG_PM
.port_suspend = ahci_port_suspend,
.port_resume = ahci_port_resume,
@@ -329,53 +390,52 @@ static const struct ata_port_operations ahci_vt8251_ops = {
.port_stop = ahci_port_stop,
};
+#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
+
static const struct ata_port_info ahci_port_info[] = {
/* board_ahci */
{
.flags = AHCI_FLAG_COMMON,
- .pio_mask = 0x1f, /* pio0-4 */
- .udma_mask = ATA_UDMA6,
- .port_ops = &ahci_ops,
- },
- /* board_ahci_pi */
- {
- .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI,
+ .link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
/* board_ahci_vt8251 */
{
- .flags = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME |
- AHCI_FLAG_NO_NCQ,
+ AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
+ .flags = AHCI_FLAG_COMMON,
+ .link_flags = AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_vt8251_ops,
},
/* board_ahci_ign_iferr */
{
- .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR,
+ AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR),
+ .flags = AHCI_FLAG_COMMON,
+ .link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
/* board_ahci_sb600 */
{
- .flags = AHCI_FLAG_COMMON |
- AHCI_FLAG_IGN_SERR_INTERNAL |
- AHCI_FLAG_32BIT_ONLY,
+ AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
+ AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_PMP),
+ .flags = AHCI_FLAG_COMMON,
+ .link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
/* board_ahci_mv */
{
- .sht = &ahci_sht,
+ AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
+ AHCI_HFLAG_MV_PATA),
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI |
- AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI |
- AHCI_FLAG_MV_PATA,
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+ .link_flags = AHCI_LFLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
@@ -394,23 +454,25 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
- { PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */
- { PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */
- { PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */
- { PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */
- { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */
- { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
+ { PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
+ { PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
+ { PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -474,6 +536,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci }, /* MCP77 */
{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci }, /* MCP77 */
{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci }, /* MCP77 */
+ { PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */
+ { PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */
/* SiS */
{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
@@ -524,7 +594,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
/**
* ahci_save_initial_config - Save and fixup initial config values
* @pdev: target PCI device
- * @pi: associated ATA port info
* @hpriv: host private area to store config values
*
* Some registers containing configuration info might be setup by
@@ -538,7 +607,6 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap)
* None.
*/
static void ahci_save_initial_config(struct pci_dev *pdev,
- const struct ata_port_info *pi,
struct ahci_host_priv *hpriv)
{
void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
@@ -552,26 +620,22 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
/* some chips have errata preventing 64bit use */
- if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) {
+ if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
dev_printk(KERN_INFO, &pdev->dev,
"controller can't do 64bit DMA, forcing 32bit\n");
cap &= ~HOST_CAP_64;
}
- if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) {
+ if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
dev_printk(KERN_INFO, &pdev->dev,
"controller can't do NCQ, turning off CAP_NCQ\n");
cap &= ~HOST_CAP_NCQ;
}
- /* fixup zero port_map */
- if (!port_map) {
- port_map = (1 << ahci_nr_ports(cap)) - 1;
- dev_printk(KERN_WARNING, &pdev->dev,
- "PORTS_IMPL is zero, forcing 0x%x\n", port_map);
-
- /* write the fixed up value to the PI register */
- hpriv->saved_port_map = port_map;
+ if ((cap && HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "controller can't do PMP, turning off CAP_PMP\n");
+ cap &= ~HOST_CAP_PMP;
}
/*
@@ -579,7 +643,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
* is asserted through the standard AHCI port
* presence register, as bit 4 (counting from 0)
*/
- if (pi->flags & AHCI_FLAG_MV_PATA) {
+ if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
dev_printk(KERN_ERR, &pdev->dev,
"MV_AHCI HACK: port_map %x -> %x\n",
hpriv->port_map,
@@ -589,7 +653,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
}
/* cross check port_map and cap.n_ports */
- if (pi->flags & AHCI_FLAG_HONOR_PI) {
+ if (port_map) {
u32 tmp_port_map = port_map;
int n_ports = ahci_nr_ports(cap);
@@ -600,17 +664,26 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
}
}
- /* Whine if inconsistent. No need to update cap.
- * port_map is used to determine number of ports.
+ /* If n_ports and port_map are inconsistent, whine and
+ * clear port_map and let it be generated from n_ports.
*/
- if (n_ports || tmp_port_map)
+ if (n_ports || tmp_port_map) {
dev_printk(KERN_WARNING, &pdev->dev,
"nr_ports (%u) and implemented port map "
- "(0x%x) don't match\n",
+ "(0x%x) don't match, using nr_ports\n",
ahci_nr_ports(cap), port_map);
- } else {
- /* fabricate port_map from cap.nr_ports */
+ port_map = 0;
+ }
+ }
+
+ /* fabricate port_map from cap.nr_ports */
+ if (!port_map) {
port_map = (1 << ahci_nr_ports(cap)) - 1;
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "forcing PORTS_IMPL to 0x%x\n", port_map);
+
+ /* write the fixed up value to the PI register */
+ hpriv->saved_port_map = port_map;
}
/* record values to use during operation */
@@ -707,7 +780,7 @@ static int ahci_stop_engine(struct ata_port *ap)
/* wait for engine to stop. This could be as long as 500 msec */
tmp = ata_wait_register(port_mmio + PORT_CMD,
- PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
+ PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
if (tmp & PORT_CMD_LIST_ON)
return -EIO;
@@ -778,6 +851,130 @@ static void ahci_power_up(struct ata_port *ap)
writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
}
+static void ahci_disable_alpm(struct ata_port *ap)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 cmd;
+ struct ahci_port_priv *pp = ap->private_data;
+
+ /* IPM bits should be disabled by libata-core */
+ /* get the existing command bits */
+ cmd = readl(port_mmio + PORT_CMD);
+
+ /* disable ALPM and ASP */
+ cmd &= ~PORT_CMD_ASP;
+ cmd &= ~PORT_CMD_ALPE;
+
+ /* force the interface back to active */
+ cmd |= PORT_CMD_ICC_ACTIVE;
+
+ /* write out new cmd value */
+ writel(cmd, port_mmio + PORT_CMD);
+ cmd = readl(port_mmio + PORT_CMD);
+
+ /* wait 10ms to be sure we've come out of any low power state */
+ msleep(10);
+
+ /* clear out any PhyRdy stuff from interrupt status */
+ writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
+
+ /* go ahead and clean out PhyRdy Change from Serror too */
+ ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
+
+ /*
+ * Clear flag to indicate that we should ignore all PhyRdy
+ * state changes
+ */
+ hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
+
+ /*
+ * Enable interrupts on Phy Ready.
+ */
+ pp->intr_mask |= PORT_IRQ_PHYRDY;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+
+ /*
+ * don't change the link pm policy - we can be called
+ * just to turn of link pm temporarily
+ */
+}
+
+static int ahci_enable_alpm(struct ata_port *ap,
+ enum link_pm policy)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 cmd;
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 asp;
+
+ /* Make sure the host is capable of link power management */
+ if (!(hpriv->cap & HOST_CAP_ALPM))
+ return -EINVAL;
+
+ switch (policy) {
+ case MAX_PERFORMANCE:
+ case NOT_AVAILABLE:
+ /*
+ * if we came here with NOT_AVAILABLE,
+ * it just means this is the first time we
+ * have tried to enable - default to max performance,
+ * and let the user go to lower power modes on request.
+ */
+ ahci_disable_alpm(ap);
+ return 0;
+ case MIN_POWER:
+ /* configure HBA to enter SLUMBER */
+ asp = PORT_CMD_ASP;
+ break;
+ case MEDIUM_POWER:
+ /* configure HBA to enter PARTIAL */
+ asp = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Disable interrupts on Phy Ready. This keeps us from
+ * getting woken up due to spurious phy ready interrupts
+ * TBD - Hot plug should be done via polling now, is
+ * that even supported?
+ */
+ pp->intr_mask &= ~PORT_IRQ_PHYRDY;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+
+ /*
+ * Set a flag to indicate that we should ignore all PhyRdy
+ * state changes since these can happen now whenever we
+ * change link state
+ */
+ hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
+
+ /* get the existing command bits */
+ cmd = readl(port_mmio + PORT_CMD);
+
+ /*
+ * Set ASP based on Policy
+ */
+ cmd |= asp;
+
+ /*
+ * Setting this bit will instruct the HBA to aggressively
+ * enter a lower power link state when it's appropriate and
+ * based on the value set above for ASP
+ */
+ cmd |= PORT_CMD_ALPE;
+
+ /* write out new cmd value */
+ writel(cmd, port_mmio + PORT_CMD);
+ cmd = readl(port_mmio + PORT_CMD);
+
+ /* IPM bits should be set by libata-core */
+ return 0;
+}
+
#ifdef CONFIG_PM
static void ahci_power_down(struct ata_port *ap)
{
@@ -836,8 +1033,16 @@ static int ahci_reset_controller(struct ata_host *host)
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
u32 tmp;
- /* global controller reset */
+ /* we must be in AHCI mode, before using anything
+ * AHCI-specific, such as HOST_RESET.
+ */
tmp = readl(mmio + HOST_CTL);
+ if (!(tmp & HOST_AHCI_EN)) {
+ tmp |= HOST_AHCI_EN;
+ writel(tmp, mmio + HOST_CTL);
+ }
+
+ /* global controller reset */
if ((tmp & HOST_RESET) == 0) {
writel(tmp | HOST_RESET, mmio + HOST_CTL);
readl(mmio + HOST_CTL); /* flush */
@@ -904,13 +1109,14 @@ static void ahci_port_init(struct pci_dev *pdev, struct ata_port *ap,
static void ahci_init_controller(struct ata_host *host)
{
+ struct ahci_host_priv *hpriv = host->private_data;
struct pci_dev *pdev = to_pci_dev(host->dev);
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
int i;
void __iomem *port_mmio;
u32 tmp;
- if (host->ports[0]->flags & AHCI_FLAG_MV_PATA) {
+ if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
port_mmio = __ahci_port_base(host, 4);
writel(0, port_mmio + PORT_IRQ_MASK);
@@ -1042,9 +1248,10 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
return 0;
}
-static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
+static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
int pmp, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
const char *reason = NULL;
unsigned long now, msecs;
struct ata_taskfile tf;
@@ -1052,7 +1259,7 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
DPRINTK("ENTER\n");
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
DPRINTK("PHY reports no device\n");
*class = ATA_DEV_NONE;
return 0;
@@ -1061,10 +1268,10 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
/* prepare for SRST (AHCI-1.1 10.4.1) */
rc = ahci_kick_engine(ap, 1);
if (rc)
- ata_port_printk(ap, KERN_WARNING,
+ ata_link_printk(link, KERN_WARNING,
"failed to reset engine (errno=%d)", rc);
- ata_tf_init(ap->device, &tf);
+ ata_tf_init(link->device, &tf);
/* issue the first D2H Register FIS */
msecs = 0;
@@ -1087,15 +1294,8 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
tf.ctl &= ~ATA_SRST;
ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
- /* spec mandates ">= 2ms" before checking status.
- * We wait 150ms, because that was the magic delay used for
- * ATAPI devices in Hale Landis's ATADRVR, for the period of time
- * between when the ATA command register is written, and then
- * status is checked. Because waiting for "a while" before
- * checking status is fine, post SRST, we perform this magic
- * delay here as well.
- */
- msleep(150);
+ /* wait a while before checking status */
+ ata_wait_after_reset(ap, deadline);
rc = ata_wait_ready(ap, deadline);
/* link occupied, -ENODEV too is an error */
@@ -1109,19 +1309,25 @@ static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
return 0;
fail:
- ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+ ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
return rc;
}
-static int ahci_softreset(struct ata_port *ap, unsigned int *class,
+static int ahci_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
- return ahci_do_softreset(ap, class, 0, deadline);
+ int pmp = 0;
+
+ if (link->ap->flags & ATA_FLAG_PMP)
+ pmp = SATA_PMP_CTRL_PORT;
+
+ return ahci_do_softreset(link, class, pmp, deadline);
}
-static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
+static int ahci_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
@@ -1132,26 +1338,27 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
ahci_stop_engine(ap);
/* clear D2H reception area to properly wait for D2H FIS */
- ata_tf_init(ap->device, &tf);
+ ata_tf_init(link->device, &tf);
tf.command = 0x80;
ata_tf_to_fis(&tf, 0, 0, d2h_fis);
- rc = sata_std_hardreset(ap, class, deadline);
+ rc = sata_std_hardreset(link, class, deadline);
ahci_start_engine(ap);
- if (rc == 0 && ata_port_online(ap))
+ if (rc == 0 && ata_link_online(link))
*class = ahci_dev_classify(ap);
- if (*class == ATA_DEV_UNKNOWN)
+ if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN)
*class = ATA_DEV_NONE;
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
return rc;
}
-static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
+static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
u32 serror;
int rc;
@@ -1159,7 +1366,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
ahci_stop_engine(ap);
- rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context),
+ rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
deadline);
/* vt8251 needs SError cleared for the port to operate */
@@ -1176,12 +1383,60 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
return rc ?: -EAGAIN;
}
-static void ahci_postreset(struct ata_port *ap, unsigned int *class)
+static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct ahci_port_priv *pp = ap->private_data;
+ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ struct ata_taskfile tf;
+ int rc;
+
+ ahci_stop_engine(ap);
+
+ /* clear D2H reception area to properly wait for D2H FIS */
+ ata_tf_init(link->device, &tf);
+ tf.command = 0x80;
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
+
+ rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
+ deadline);
+
+ ahci_start_engine(ap);
+
+ if (rc || ata_link_offline(link))
+ return rc;
+
+ /* spec mandates ">= 2ms" before checking status */
+ msleep(150);
+
+ /* The pseudo configuration device on SIMG4726 attached to
+ * ASUS P5W-DH Deluxe doesn't send signature FIS after
+ * hardreset if no device is attached to the first downstream
+ * port && the pseudo device locks up on SRST w/ PMP==0. To
+ * work around this, wait for !BSY only briefly. If BSY isn't
+ * cleared, perform CLO and proceed to IDENTIFY (achieved by
+ * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
+ *
+ * Wait for two seconds. Devices attached to downstream port
+ * which can't process the following IDENTIFY after this will
+ * have to be reset again. For most cases, this should
+ * suffice while making probing snappish enough.
+ */
+ rc = ata_wait_ready(ap, jiffies + 2 * HZ);
+ if (rc)
+ ahci_kick_engine(ap, 0);
+
+ return 0;
+}
+
+static void ahci_postreset(struct ata_link *link, unsigned int *class)
{
+ struct ata_port *ap = link->ap;
void __iomem *port_mmio = ahci_port_base(ap);
u32 new_tmp, tmp;
- ata_std_postreset(ap, class);
+ ata_std_postreset(link, class);
/* Make sure port's ATAPI bit is set appropriately */
new_tmp = tmp = readl(port_mmio + PORT_CMD);
@@ -1195,6 +1450,12 @@ static void ahci_postreset(struct ata_port *ap, unsigned int *class)
}
}
+static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ return ahci_do_softreset(link, class, link->pmp, deadline);
+}
+
static u8 ahci_check_status(struct ata_port *ap)
{
void __iomem *mmio = ap->ioaddr.cmd_addr;
@@ -1253,7 +1514,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
*/
cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
- ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl);
+ 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);
@@ -1266,7 +1527,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
/*
* Fill in command slot information.
*/
- opts = cmd_fis_len | n_elem << 16;
+ opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
if (qc->tf.flags & ATA_TFLAG_WRITE)
opts |= AHCI_CMD_WRITE;
if (is_atapi)
@@ -1277,66 +1538,87 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp = ap->private_data;
- struct ata_eh_info *ehi = &ap->eh_info;
- unsigned int err_mask = 0, action = 0;
- struct ata_queued_cmd *qc;
+ struct ata_eh_info *host_ehi = &ap->link.eh_info;
+ struct ata_link *link = NULL;
+ struct ata_queued_cmd *active_qc;
+ struct ata_eh_info *active_ehi;
u32 serror;
- ata_ehi_clear_desc(ehi);
+ /* determine active link */
+ ata_port_for_each_link(link, ap)
+ if (ata_link_active(link))
+ break;
+ if (!link)
+ link = &ap->link;
+
+ active_qc = ata_qc_from_tag(ap, link->active_tag);
+ active_ehi = &link->eh_info;
+
+ /* record irq stat */
+ ata_ehi_clear_desc(host_ehi);
+ ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
/* AHCI needs SError cleared; otherwise, it might lock up */
ahci_scr_read(ap, SCR_ERROR, &serror);
ahci_scr_write(ap, SCR_ERROR, serror);
-
- /* analyze @irq_stat */
- ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+ host_ehi->serror |= serror;
/* some controllers set IRQ_IF_ERR on device errors, ignore it */
- if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR)
+ if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
irq_stat &= ~PORT_IRQ_IF_ERR;
if (irq_stat & PORT_IRQ_TF_ERR) {
- err_mask |= AC_ERR_DEV;
- if (ap->flags & AHCI_FLAG_IGN_SERR_INTERNAL)
- serror &= ~SERR_INTERNAL;
+ /* If qc is active, charge it; otherwise, the active
+ * link. There's no active qc on NCQ errors. It will
+ * be determined by EH by reading log page 10h.
+ */
+ if (active_qc)
+ active_qc->err_mask |= AC_ERR_DEV;
+ else
+ active_ehi->err_mask |= AC_ERR_DEV;
+
+ if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
+ host_ehi->serror &= ~SERR_INTERNAL;
+ }
+
+ if (irq_stat & PORT_IRQ_UNK_FIS) {
+ u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
+
+ active_ehi->err_mask |= AC_ERR_HSM;
+ active_ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(active_ehi,
+ "unknown FIS %08x %08x %08x %08x" ,
+ unk[0], unk[1], unk[2], unk[3]);
+ }
+
+ if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) {
+ active_ehi->err_mask |= AC_ERR_HSM;
+ active_ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(active_ehi, "incorrect PMP");
}
if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
- err_mask |= AC_ERR_HOST_BUS;
- action |= ATA_EH_SOFTRESET;
+ host_ehi->err_mask |= AC_ERR_HOST_BUS;
+ host_ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(host_ehi, "host bus error");
}
if (irq_stat & PORT_IRQ_IF_ERR) {
- err_mask |= AC_ERR_ATA_BUS;
- action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, "interface fatal error");
+ host_ehi->err_mask |= AC_ERR_ATA_BUS;
+ host_ehi->action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(host_ehi, "interface fatal error");
}
if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
- ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ?
+ ata_ehi_hotplugged(host_ehi);
+ ata_ehi_push_desc(host_ehi, "%s",
+ irq_stat & PORT_IRQ_CONNECT ?
"connection status changed" : "PHY RDY changed");
}
- if (irq_stat & PORT_IRQ_UNK_FIS) {
- u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
-
- err_mask |= AC_ERR_HSM;
- action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x",
- unk[0], unk[1], unk[2], unk[3]);
- }
-
/* okay, let's hand over to EH */
- ehi->serror |= serror;
- ehi->action |= action;
-
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc)
- qc->err_mask |= err_mask;
- else
- ehi->err_mask |= err_mask;
if (irq_stat & PORT_IRQ_FREEZE)
ata_port_freeze(ap);
@@ -1347,25 +1629,75 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
static void ahci_port_intr(struct ata_port *ap)
{
void __iomem *port_mmio = ap->ioaddr.cmd_addr;
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
u32 status, qc_active;
int rc, known_irq = 0;
status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, port_mmio + PORT_IRQ_STAT);
+ /* ignore BAD_PMP while resetting */
+ if (unlikely(resetting))
+ status &= ~PORT_IRQ_BAD_PMP;
+
+ /* If we are getting PhyRdy, this is
+ * just a power state change, we should
+ * clear out this, plus the PhyRdy/Comm
+ * Wake bits from Serror
+ */
+ if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
+ (status & PORT_IRQ_PHYRDY)) {
+ status &= ~PORT_IRQ_PHYRDY;
+ ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18)));
+ }
+
if (unlikely(status & PORT_IRQ_ERROR)) {
ahci_error_intr(ap, status);
return;
}
- if (ap->sactive)
+ if (status & PORT_IRQ_SDB_FIS) {
+ /* If SNotification is available, leave notification
+ * handling to sata_async_notification(). If not,
+ * emulate it by snooping SDB FIS RX area.
+ *
+ * Snooping FIS RX area is probably cheaper than
+ * poking SNotification but some constrollers which
+ * implement SNotification, ICH9 for example, don't
+ * store AN SDB FIS into receive area.
+ */
+ if (hpriv->cap & HOST_CAP_SNTF)
+ sata_async_notification(ap);
+ else {
+ /* If the 'N' bit in word 0 of the FIS is set,
+ * we just received asynchronous notification.
+ * Tell libata about it.
+ */
+ const __le32 *f = pp->rx_fis + RX_FIS_SDB;
+ u32 f0 = le32_to_cpu(f[0]);
+
+ if (f0 & (1 << 15))
+ sata_async_notification(ap);
+ }
+ }
+
+ /* pp->active_link is valid iff any command is in flight */
+ if (ap->qc_active && pp->active_link->sactive)
qc_active = readl(port_mmio + PORT_SCR_ACT);
else
qc_active = readl(port_mmio + PORT_CMD_ISSUE);
rc = ata_qc_complete_multiple(ap, qc_active, NULL);
+
+ /* If resetting, spurious or invalid completions are expected,
+ * return unconditionally.
+ */
+ if (resetting)
+ return;
+
if (rc > 0)
return;
if (rc < 0) {
@@ -1375,12 +1707,12 @@ static void ahci_port_intr(struct ata_port *ap)
return;
}
- /* hmmm... a spurious interupt */
+ /* hmmm... a spurious interrupt */
/* if !NCQ, ignore. No modern ATA device has broken HSM
* implementation for non-NCQ commands.
*/
- if (!ap->sactive)
+ if (!ap->link.sactive)
return;
if (status & PORT_IRQ_D2H_REG_FIS) {
@@ -1433,7 +1765,7 @@ static void ahci_port_intr(struct ata_port *ap)
if (!known_irq)
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
"(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
- status, ap->active_tag, ap->sactive);
+ status, ap->link.active_tag, ap->link.sactive);
}
static void ahci_irq_clear(struct ata_port *ap)
@@ -1460,9 +1792,9 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
if (!irq_stat)
return IRQ_NONE;
- spin_lock(&host->lock);
+ spin_lock(&host->lock);
- for (i = 0; i < host->n_ports; i++) {
+ for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap;
if (!(irq_stat & (1 << i)))
@@ -1498,6 +1830,13 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+
+ /* Keep track of the currently active link. It will be used
+ * in completion path to determine whether NCQ phase is in
+ * progress.
+ */
+ pp->active_link = qc->dev->link;
if (qc->tf.protocol == ATA_PROT_NCQ)
writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
@@ -1520,6 +1859,7 @@ static void ahci_thaw(struct ata_port *ap)
void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
+ struct ahci_port_priv *pp = ap->private_data;
/* clear IRQ */
tmp = readl(port_mmio + PORT_IRQ_STAT);
@@ -1527,7 +1867,7 @@ static void ahci_thaw(struct ata_port *ap)
writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
/* turn IRQ back on */
- writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
}
static void ahci_error_handler(struct ata_port *ap)
@@ -1539,8 +1879,10 @@ static void ahci_error_handler(struct ata_port *ap)
}
/* perform recovery */
- ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
- ahci_postreset);
+ sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset,
+ ahci_hardreset, ahci_postreset,
+ sata_pmp_std_prereset, ahci_pmp_softreset,
+ sata_pmp_std_hardreset, sata_pmp_std_postreset);
}
static void ahci_vt8251_error_handler(struct ata_port *ap)
@@ -1556,6 +1898,19 @@ static void ahci_vt8251_error_handler(struct ata_port *ap)
ahci_postreset);
}
+static void ahci_p5wdh_error_handler(struct ata_port *ap)
+{
+ if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
+ /* restart engine */
+ ahci_stop_engine(ap);
+ ahci_start_engine(ap);
+ }
+
+ /* perform recovery */
+ ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_p5wdh_hardreset,
+ ahci_postreset);
+}
+
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
@@ -1565,11 +1920,44 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
ahci_kick_engine(ap, 1);
}
+static void ahci_pmp_attach(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 cmd;
+
+ cmd = readl(port_mmio + PORT_CMD);
+ cmd |= PORT_CMD_PMP;
+ writel(cmd, port_mmio + PORT_CMD);
+
+ pp->intr_mask |= PORT_IRQ_BAD_PMP;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ahci_pmp_detach(struct ata_port *ap)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 cmd;
+
+ cmd = readl(port_mmio + PORT_CMD);
+ cmd &= ~PORT_CMD_PMP;
+ writel(cmd, port_mmio + PORT_CMD);
+
+ pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
+ writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
static int ahci_port_resume(struct ata_port *ap)
{
ahci_power_up(ap);
ahci_start_port(ap);
+ if (ap->nr_pmp_links)
+ ahci_pmp_attach(ap);
+ else
+ ahci_pmp_detach(ap);
+
return 0;
}
@@ -1681,6 +2069,12 @@ static int ahci_port_start(struct ata_port *ap)
pp->cmd_tbl = mem;
pp->cmd_tbl_dma = mem_dma;
+ /*
+ * Save off initial list of interrupts to be enabled.
+ * This could be changed later
+ */
+ pp->intr_mask = DEF_PORT_IRQ;
+
ap->private_data = pp;
/* engage engines, captain */
@@ -1765,12 +2159,12 @@ static void ahci_print_info(struct ata_host *host)
dev_printk(KERN_INFO, &pdev->dev,
"AHCI %02x%02x.%02x%02x "
"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
- ,
+ ,
- (vers >> 24) & 0xff,
- (vers >> 16) & 0xff,
- (vers >> 8) & 0xff,
- vers & 0xff,
+ (vers >> 24) & 0xff,
+ (vers >> 16) & 0xff,
+ (vers >> 8) & 0xff,
+ vers & 0xff,
((cap >> 8) & 0x1f) + 1,
(cap & 0x1f) + 1,
@@ -1782,7 +2176,7 @@ static void ahci_print_info(struct ata_host *host)
"flags: "
"%s%s%s%s%s%s%s"
"%s%s%s%s%s%s%s\n"
- ,
+ ,
cap & (1 << 31) ? "64bit " : "",
cap & (1 << 30) ? "ncq " : "",
@@ -1802,6 +2196,51 @@ static void ahci_print_info(struct ata_host *host)
);
}
+/* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
+ * hardwired to on-board SIMG 4726. The chipset is ICH8 and doesn't
+ * support PMP and the 4726 either directly exports the device
+ * attached to the first downstream port or acts as a hardware storage
+ * controller and emulate a single ATA device (can be RAID 0/1 or some
+ * other configuration).
+ *
+ * When there's no device attached to the first downstream port of the
+ * 4726, "Config Disk" appears, which is a pseudo ATA device to
+ * configure the 4726. However, ATA emulation of the device is very
+ * lame. It doesn't send signature D2H Reg FIS after the initial
+ * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
+ *
+ * The following function works around the problem by always using
+ * hardreset on the port and not depending on receiving signature FIS
+ * afterward. If signature FIS isn't received soon, ATA class is
+ * assumed without follow-up softreset.
+ */
+static void ahci_p5wdh_workaround(struct ata_host *host)
+{
+ static struct dmi_system_id sysids[] = {
+ {
+ .ident = "P5W DH Deluxe",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "ASUSTEK COMPUTER INC"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
+ },
+ },
+ { }
+ };
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+
+ if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
+ dmi_check_system(sysids)) {
+ struct ata_port *ap = host->ports[1];
+
+ dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "
+ "Deluxe on-board SIMG4726 workaround\n");
+
+ ap->ops = &ahci_p5wdh_ops;
+ ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
+ }
+}
+
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
@@ -1830,20 +2269,24 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- if ((pi.flags & AHCI_FLAG_NO_MSI) || pci_enable_msi(pdev))
- pci_intx(pdev, 1);
-
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
+ hpriv->flags |= (unsigned long)pi.private_data;
+
+ if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
+ pci_intx(pdev, 1);
/* save initial config */
- ahci_save_initial_config(pdev, &pi, hpriv);
+ ahci_save_initial_config(pdev, hpriv);
/* prepare host */
if (hpriv->cap & HOST_CAP_NCQ)
pi.flags |= ATA_FLAG_NCQ;
+ if (hpriv->cap & HOST_CAP_PMP)
+ pi.flags |= ATA_FLAG_PMP;
+
host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
if (!host)
return -ENOMEM;
@@ -1854,6 +2297,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_port *ap = host->ports[i];
void __iomem *port_mmio = ahci_port_base(ap);
+ ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
+ ata_port_pbar_desc(ap, AHCI_PCI_BAR,
+ 0x100 + ap->port_no * 0x80, "port");
+
+ /* set initial link pm policy */
+ ap->pm_policy = NOT_AVAILABLE;
+
/* standard SATA port setup */
if (hpriv->port_map & (1 << i))
ap->ioaddr.cmd_addr = port_mmio;
@@ -1863,6 +2313,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
ap->ops = &ata_dummy_port_ops;
}
+ /* apply workaround for ASUS P5W DH Deluxe mainboard */
+ ahci_p5wdh_workaround(host);
+
/* initialize adapter */
rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
if (rc)
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 94546695472..90329982bef 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -34,7 +34,7 @@
/**
* generic_set_mode - mode setting
- * @ap: interface to set up
+ * @link: link to set up
* @unused: returned device on error
*
* Use a non standard set_mode function. We don't want to be tuned.
@@ -43,24 +43,24 @@
* and respect them.
*/
-static int generic_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int generic_set_mode(struct ata_link *link, struct ata_device **unused)
{
+ struct ata_port *ap = link->ap;
int dma_enabled = 0;
- int i;
+ struct ata_device *dev;
/* Bits 5 and 6 indicate if DMA is active on master/slave */
if (ap->ioaddr.bmdma_addr)
dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
dev->dma_mode = XFER_MW_DMA_0;
/* We do need the right mode information for DMA or PIO
and this comes from the current configuration flags */
- if (dma_enabled & (1 << (5 + i))) {
+ if (dma_enabled & (1 << (5 + dev->devno))) {
ata_id_to_dma_mode(dev, XFER_MW_DMA_0);
dev->flags &= ~ATA_DFLAG_PIO;
} else {
@@ -95,7 +95,6 @@ static struct scsi_host_template generic_sht = {
static struct ata_port_operations generic_port_ops = {
.set_mode = generic_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -121,9 +120,8 @@ static struct ata_port_operations generic_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int all_generic_ide; /* Set to claim all devices */
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 6996eb5b750..328ce8a0842 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -123,7 +123,6 @@ enum {
ich_pata_33 = 1, /* ICH up to UDMA 33 only */
ich_pata_66 = 2, /* ICH up to 66 Mhz */
ich_pata_100 = 3, /* ICH up to UDMA 100 */
- ich_pata_133 = 4, /* ICH up to UDMA 133 */
ich5_sata = 5,
ich6_sata = 6,
ich6_sata_ahci = 7,
@@ -131,6 +130,7 @@ enum {
ich8_sata_ahci = 9,
piix_pata_mwdma = 10, /* PIIX3 MWDMA only */
tolapai_sata_ahci = 11,
+ ich9_2port_sata = 12,
/* constants for mapping table */
P0 = 0, /* port 0 */
@@ -157,12 +157,12 @@ struct piix_host_priv {
const int *map;
};
-static int piix_init_one (struct pci_dev *pdev,
- const struct pci_device_id *ent);
+static int piix_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
static void piix_pata_error_handler(struct ata_port *ap);
-static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
-static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
-static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev);
+static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev);
+static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev);
+static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev);
static int ich_pata_cable_detect(struct ata_port *ap);
#ifdef CONFIG_PM
static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
@@ -199,7 +199,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
{ 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* Intel ICH5 */
- { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+ { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* C-ICH (i810E2) */
{ 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* ESB (855GME/875P + 6300ESB) UDMA 100 */
@@ -207,7 +207,7 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* ICH6 (and 6) (i915) UDMA 100 */
{ 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* ICH7/7-R (i945, i975) UDMA 100*/
- { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+ { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
{ 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
/* ICH8 Mobile PATA Controller */
{ 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
@@ -239,19 +239,19 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* SATA Controller 1 IDE (ICH8) */
{ 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* SATA Controller 2 IDE (ICH8) */
- { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
/* Mobile SATA Controller IDE (ICH8M) */
{ 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* SATA Controller IDE (ICH9) */
{ 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* SATA Controller IDE (ICH9) */
- { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
/* SATA Controller IDE (ICH9) */
- { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
/* SATA Controller IDE (ICH9M) */
- { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
/* SATA Controller IDE (ICH9M) */
- { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata },
/* SATA Controller IDE (ICH9M) */
{ 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* SATA Controller IDE (Tolapai) */
@@ -290,7 +290,6 @@ static struct scsi_host_template piix_sht = {
};
static const struct ata_port_operations piix_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = piix_set_piomode,
.set_dmamode = piix_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -318,13 +317,11 @@ static const struct ata_port_operations piix_pata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static const struct ata_port_operations ich_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = piix_set_piomode,
.set_dmamode = ich_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -352,14 +349,11 @@ static const struct ata_port_operations ich_pata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static const struct ata_port_operations piix_sata_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -382,7 +376,6 @@ static const struct ata_port_operations piix_sata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -445,15 +438,27 @@ static const struct piix_map_db ich8_map_db = {
};
static const struct piix_map_db tolapai_map_db = {
- .mask = 0x3,
- .port_enable = 0x3,
- .map = {
- /* PM PS SM SS MAP */
- { P0, NA, P1, NA }, /* 00b */
- { RV, RV, RV, RV }, /* 01b */
- { RV, RV, RV, RV }, /* 10b */
- { RV, RV, RV, RV },
- },
+ .mask = 0x3,
+ .port_enable = 0x3,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, NA, P1, NA }, /* 00b */
+ { RV, RV, RV, RV }, /* 01b */
+ { RV, RV, RV, RV }, /* 10b */
+ { RV, RV, RV, RV },
+ },
+};
+
+static const struct piix_map_db ich9_2port_map_db = {
+ .mask = 0x3,
+ .port_enable = 0x3,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, NA, P1, NA }, /* 00b */
+ { RV, RV, RV, RV }, /* 01b */
+ { RV, RV, RV, RV }, /* 10b */
+ { RV, RV, RV, RV },
+ },
};
static const struct piix_map_db *piix_map_db_table[] = {
@@ -463,10 +468,11 @@ static const struct piix_map_db *piix_map_db_table[] = {
[ich6m_sata_ahci] = &ich6m_map_db,
[ich8_sata_ahci] = &ich8_map_db,
[tolapai_sata_ahci] = &tolapai_map_db,
+ [ich9_2port_sata] = &ich9_2port_map_db,
};
static struct ata_port_info piix_port_info[] = {
- /* piix_pata_33: 0: PIIX4 at 33MHz */
+ [piix_pata_33] = /* PIIX4 at 33MHz */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -476,7 +482,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_pata_ops,
},
- /* ich_pata_33: 1 ICH0 - ICH at 33Mhz*/
+ [ich_pata_33] = /* ICH0 - ICH at 33Mhz*/
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -485,7 +491,8 @@ static struct ata_port_info piix_port_info[] = {
.udma_mask = ATA_UDMA2, /* UDMA33 */
.port_ops = &ich_pata_ops,
},
- /* ich_pata_66: 2 ICH controllers up to 66MHz */
+
+ [ich_pata_66] = /* ICH controllers up to 66MHz */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -495,7 +502,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &ich_pata_ops,
},
- /* ich_pata_100: 3 */
+ [ich_pata_100] =
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
@@ -505,17 +512,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &ich_pata_ops,
},
- /* ich_pata_133: 4 ICH with full UDMA6 */
- {
- .sht = &piix_sht,
- .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
- .pio_mask = 0x1f, /* pio 0-4 */
- .mwdma_mask = 0x06, /* Check: maybe 0x07 */
- .udma_mask = ATA_UDMA6, /* UDMA133 */
- .port_ops = &ich_pata_ops,
- },
-
- /* ich5_sata: 5 */
+ [ich5_sata] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS,
@@ -525,7 +522,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* ich6_sata: 6 */
+ [ich6_sata] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR,
@@ -535,7 +532,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* ich6_sata_ahci: 7 */
+ [ich6_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -546,7 +543,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* ich6m_sata_ahci: 8 */
+ [ich6m_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -557,7 +554,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* ich8_sata_ahci: 9 */
+ [ich8_sata_ahci] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -568,7 +565,7 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_sata_ops,
},
- /* piix_pata_mwdma: 10: PIIX3 MWDMA only */
+ [piix_pata_mwdma] = /* PIIX3 MWDMA only */
{
.sht = &piix_sht,
.flags = PIIX_PATA_FLAGS,
@@ -577,7 +574,18 @@ static struct ata_port_info piix_port_info[] = {
.port_ops = &piix_pata_ops,
},
- /* tolapai_sata_ahci: 11: */
+ [tolapai_sata_ahci] =
+ {
+ .sht = &piix_sht,
+ .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
+ PIIX_FLAG_AHCI,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
+
+ [ich9_2port_sata] =
{
.sht = &piix_sht,
.flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -613,8 +621,10 @@ struct ich_laptop {
static const struct ich_laptop ich_laptop[] = {
/* devid, subvendor, subdev */
{ 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */
+ { 0x27DF, 0x1025, 0x0102 }, /* ICH7 on Acer 5602aWLMi */
{ 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
{ 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
+ { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
{ 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */
/* end marker */
{ 0, }
@@ -641,9 +651,9 @@ static int ich_pata_cable_detect(struct ata_port *ap)
while (lap->device) {
if (lap->device == pdev->device &&
lap->subvendor == pdev->subsystem_vendor &&
- lap->subdevice == pdev->subsystem_device) {
+ lap->subdevice == pdev->subsystem_device)
return ATA_CBL_PATA40_SHORT;
- }
+
lap++;
}
@@ -657,19 +667,20 @@ static int ich_pata_cable_detect(struct ata_port *ap)
/**
* piix_pata_prereset - prereset for PATA host controller
- * @ap: Target port
+ * @link: Target link
* @deadline: deadline jiffies for the operation
*
* LOCKING:
* None (inherited from caller).
*/
-static int piix_pata_prereset(struct ata_port *ap, unsigned long deadline)
+static int piix_pata_prereset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static void piix_pata_error_handler(struct ata_port *ap)
@@ -689,7 +700,7 @@ static void piix_pata_error_handler(struct ata_port *ap)
* None (inherited from caller).
*/
-static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev)
+static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
unsigned int pio = adev->pio_mode - XFER_PIO_0;
struct pci_dev *dev = to_pci_dev(ap->host->dev);
@@ -776,7 +787,7 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev)
* None (inherited from caller).
*/
-static void do_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev, int isich)
+static void do_pata_set_dmamode(struct ata_port *ap, struct ata_device *adev, int isich)
{
struct pci_dev *dev = to_pci_dev(ap->host->dev);
u8 master_port = ap->port_no ? 0x42 : 0x40;
@@ -803,7 +814,7 @@ static void do_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev, i
int u_clock, u_speed;
/*
- * UDMA is handled by a combination of clock switching and
+ * UDMA is handled by a combination of clock switching and
* selection of dividers
*
* Handy rule: Odd modes are UDMATIMx 01, even are 02
@@ -895,7 +906,7 @@ static void do_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev, i
* None (inherited from caller).
*/
-static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
do_pata_set_dmamode(ap, adev, 0);
}
@@ -911,7 +922,7 @@ static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
* None (inherited from caller).
*/
-static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
do_pata_set_dmamode(ap, adev, 1);
}
@@ -919,7 +930,7 @@ static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev)
#ifdef CONFIG_PM
static int piix_broken_suspend(void)
{
- static struct dmi_system_id sysids[] = {
+ static const struct dmi_system_id sysids[] = {
{
.ident = "TECRA M3",
.matches = {
@@ -949,6 +960,13 @@ static int piix_broken_suspend(void)
},
},
{
+ .ident = "Satellite Pro U200",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE PRO U200"),
+ },
+ },
+ {
.ident = "Satellite U205",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
@@ -1096,8 +1114,7 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
u16 cfg;
int no_piix_dma = 0;
- while((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev)) != NULL)
- {
+ while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev)) != NULL) {
/* Look for 450NX PXB. Check for problem configurations
A PCI quirk checks bit 6 already */
pci_read_config_word(pdev, 0x41, &cfg);
@@ -1137,7 +1154,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
const struct piix_map_db *map_db)
{
struct piix_host_priv *hpriv = pinfo[0].private_data;
- const unsigned int *map;
+ const int *map;
int i, invalid_map = 0;
u8 map_value;
@@ -1183,7 +1200,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
{
- static struct dmi_system_id sysids[] = {
+ static const struct dmi_system_id sysids[] = {
{
/* Clevo M570U sets IOCFG bit 18 if the cdrom
* isn't used to boot the system which
@@ -1231,7 +1248,7 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
* Zero on success, or -ERRNO value.
*/
-static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
struct device *dev = &pdev->dev;
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index c059f78ad94..545ea865ceb 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -14,6 +14,7 @@
#include <linux/acpi.h>
#include <linux/libata.h>
#include <linux/pci.h>
+#include <scsi/scsi_device.h>
#include "libata.h"
#include <acpi/acpi_bus.h>
@@ -25,7 +26,7 @@
#include <acpi/actypes.h>
#define NO_PORT_MULT 0xffff
-#define SATA_ADR(root,pmp) (((root) << 16) | (pmp))
+#define SATA_ADR(root, pmp) (((root) << 16) | (pmp))
#define REGS_PER_GTF 7
struct ata_acpi_gtf {
@@ -40,11 +41,40 @@ static int is_pci_dev(struct device *dev)
return (dev->bus == &pci_bus_type);
}
-static void ata_acpi_associate_sata_port(struct ata_port *ap)
+/**
+ * ata_acpi_associate_sata_port - associate SATA port with ACPI objects
+ * @ap: target SATA port
+ *
+ * Look up ACPI objects associated with @ap and initialize acpi_handle
+ * fields of @ap, the port and devices accordingly.
+ *
+ * LOCKING:
+ * EH context.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+void ata_acpi_associate_sata_port(struct ata_port *ap)
{
- acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+ WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA));
+
+ if (!ap->nr_pmp_links) {
+ acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+
+ ap->link.device->acpi_handle =
+ acpi_get_child(ap->host->acpi_handle, adr);
+ } else {
+ struct ata_link *link;
+
+ ap->link.device->acpi_handle = NULL;
+
+ ata_port_for_each_link(link, ap) {
+ acpi_integer adr = SATA_ADR(ap->port_no, link->pmp);
- ap->device->acpi_handle = acpi_get_child(ap->host->acpi_handle, adr);
+ link->device->acpi_handle =
+ acpi_get_child(ap->host->acpi_handle, adr);
+ }
+ }
}
static void ata_acpi_associate_ide_port(struct ata_port *ap)
@@ -60,12 +90,53 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
max_devices++;
for (i = 0; i < max_devices; i++) {
- struct ata_device *dev = &ap->device[i];
+ struct ata_device *dev = &ap->link.device[i];
dev->acpi_handle = acpi_get_child(ap->acpi_handle, i);
}
}
+static void ata_acpi_handle_hotplug(struct ata_port *ap, struct kobject *kobj,
+ u32 event)
+{
+ char event_string[12];
+ char *envp[] = { event_string, NULL };
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+
+ if (event == 0 || event == 1) {
+ unsigned long flags;
+ spin_lock_irqsave(ap->lock, flags);
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "ACPI event");
+ ata_ehi_hotplugged(ehi);
+ ata_port_freeze(ap);
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+
+ if (kobj) {
+ sprintf(event_string, "BAY_EVENT=%d", event);
+ kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
+ }
+}
+
+static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct ata_device *dev = data;
+ struct kobject *kobj = NULL;
+
+ if (dev->sdev)
+ kobj = &dev->sdev->sdev_gendev.kobj;
+
+ ata_acpi_handle_hotplug(dev->link->ap, kobj, event);
+}
+
+static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct ata_port *ap = data;
+
+ ata_acpi_handle_hotplug(ap, &ap->dev->kobj, event);
+}
+
/**
* ata_acpi_associate - associate ATA host with ACPI objects
* @host: target ATA host
@@ -81,7 +152,7 @@ static void ata_acpi_associate_ide_port(struct ata_port *ap)
*/
void ata_acpi_associate(struct ata_host *host)
{
- int i;
+ int i, j;
if (!is_pci_dev(host->dev) || libata_noacpi)
return;
@@ -97,6 +168,22 @@ void ata_acpi_associate(struct ata_host *host)
ata_acpi_associate_sata_port(ap);
else
ata_acpi_associate_ide_port(ap);
+
+ if (ap->acpi_handle)
+ acpi_install_notify_handler (ap->acpi_handle,
+ ACPI_SYSTEM_NOTIFY,
+ ata_acpi_ap_notify,
+ ap);
+
+ for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
+ struct ata_device *dev = &ap->link.device[j];
+
+ if (dev->acpi_handle)
+ acpi_install_notify_handler (dev->acpi_handle,
+ ACPI_SYSTEM_NOTIFY,
+ ata_acpi_dev_notify,
+ dev);
+ }
}
}
@@ -113,7 +200,7 @@ void ata_acpi_associate(struct ata_host *host)
* RETURNS:
* 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
*/
-static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
+int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
{
struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER };
union acpi_object *out_obj;
@@ -157,6 +244,8 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
return rc;
}
+EXPORT_SYMBOL_GPL(ata_acpi_gtm);
+
/**
* ata_acpi_stm - execute _STM
* @ap: target ATA port
@@ -170,7 +259,7 @@ static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
* RETURNS:
* 0 on success, -ENOENT if _STM doesn't exist, -errno on failure.
*/
-static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
+int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
{
acpi_status status;
struct acpi_object_list input;
@@ -182,10 +271,10 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
/* Buffers for id may need byteswapping ? */
in_params[1].type = ACPI_TYPE_BUFFER;
in_params[1].buffer.length = 512;
- in_params[1].buffer.pointer = (u8 *)ap->device[0].id;
+ in_params[1].buffer.pointer = (u8 *)ap->link.device[0].id;
in_params[2].type = ACPI_TYPE_BUFFER;
in_params[2].buffer.length = 512;
- in_params[2].buffer.pointer = (u8 *)ap->device[1].id;
+ in_params[2].buffer.pointer = (u8 *)ap->link.device[1].id;
input.count = 3;
input.pointer = in_params;
@@ -202,6 +291,8 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
return 0;
}
+EXPORT_SYMBOL_GPL(ata_acpi_stm);
+
/**
* ata_dev_get_GTF - get the drive bootup default taskfile settings
* @dev: target ATA device
@@ -221,12 +312,12 @@ static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
*
* RETURNS:
* Number of taskfiles on success, 0 if _GTF doesn't exist or doesn't
- * contain valid data. -errno on other errors.
+ * contain valid data.
*/
static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
void **ptr_to_free)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
acpi_status status;
struct acpi_buffer output;
union acpi_object *out_obj;
@@ -248,7 +339,6 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
ata_dev_printk(dev, KERN_WARNING,
"_GTF evaluation failed (AE 0x%x)\n",
status);
- rc = -EIO;
}
goto out_free;
}
@@ -268,7 +358,6 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
ata_dev_printk(dev, KERN_WARNING,
"_GTF unexpected object type 0x%x\n",
out_obj->type);
- rc = -EINVAL;
goto out_free;
}
@@ -276,7 +365,6 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
ata_dev_printk(dev, KERN_WARNING,
"unexpected _GTF length (%d)\n",
out_obj->buffer.length);
- rc = -EINVAL;
goto out_free;
}
@@ -296,6 +384,44 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
}
/**
+ * ata_acpi_cbl_80wire - Check for 80 wire cable
+ * @ap: Port to check
+ *
+ * Return 1 if the ACPI mode data for this port indicates the BIOS selected
+ * an 80wire mode.
+ */
+
+int ata_acpi_cbl_80wire(struct ata_port *ap)
+{
+ struct ata_acpi_gtm gtm;
+ int valid = 0;
+
+ /* No _GTM data, no information */
+ if (ata_acpi_gtm(ap, &gtm) < 0)
+ return 0;
+
+ /* Split timing, DMA enabled */
+ if ((gtm.flags & 0x11) == 0x11 && gtm.drive[0].dma < 55)
+ valid |= 1;
+ if ((gtm.flags & 0x14) == 0x14 && gtm.drive[1].dma < 55)
+ valid |= 2;
+ /* Shared timing, DMA enabled */
+ if ((gtm.flags & 0x11) == 0x01 && gtm.drive[0].dma < 55)
+ valid |= 1;
+ if ((gtm.flags & 0x14) == 0x04 && gtm.drive[0].dma < 55)
+ valid |= 2;
+
+ /* Drive check */
+ if ((valid & 1) && ata_dev_enabled(&ap->link.device[0]))
+ return 1;
+ if ((valid & 2) && ata_dev_enabled(&ap->link.device[1]))
+ return 1;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire);
+
+/**
* taskfile_load_raw - send taskfile registers to host controller
* @dev: target ATA device
* @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
@@ -320,7 +446,7 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
static int taskfile_load_raw(struct ata_device *dev,
const struct ata_acpi_gtf *gtf)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
struct ata_taskfile tf, rtf;
unsigned int err_mask;
@@ -349,7 +475,7 @@ static int taskfile_load_raw(struct ata_device *dev,
tf.lbal, tf.lbam, tf.lbah, tf.device);
rtf = tf;
- err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0);
+ err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0, 0);
if (err_mask) {
ata_dev_printk(dev, KERN_ERR,
"ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x failed "
@@ -382,10 +508,7 @@ static int ata_acpi_exec_tfs(struct ata_device *dev)
int gtf_count, i, rc;
/* get taskfiles */
- rc = ata_dev_get_GTF(dev, &gtf, &ptr_to_free);
- if (rc < 0)
- return rc;
- gtf_count = rc;
+ gtf_count = ata_dev_get_GTF(dev, &gtf, &ptr_to_free);
/* execute them */
for (i = 0, rc = 0; i < gtf_count; i++) {
@@ -424,7 +547,7 @@ static int ata_acpi_exec_tfs(struct ata_device *dev)
*/
static int ata_acpi_push_id(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
int err;
acpi_status status;
struct acpi_object_list input;
@@ -508,7 +631,7 @@ int ata_acpi_on_suspend(struct ata_port *ap)
*/
void ata_acpi_on_resume(struct ata_port *ap)
{
- int i;
+ struct ata_device *dev;
if (ap->acpi_handle && (ap->pflags & ATA_PFLAG_GTM_VALID)) {
BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA);
@@ -518,8 +641,8 @@ void ata_acpi_on_resume(struct ata_port *ap)
}
/* schedule _GTF */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->device[i].flags |= ATA_DFLAG_ACPI_PENDING;
+ ata_link_for_each_dev(dev, &ap->link)
+ dev->flags |= ATA_DFLAG_ACPI_PENDING;
}
/**
@@ -538,8 +661,8 @@ void ata_acpi_on_resume(struct ata_port *ap)
*/
int ata_acpi_on_devcfg(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = dev->link->ap;
+ struct ata_eh_context *ehc = &ap->link.eh_context;
int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA;
int rc;
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 772be09b468..81898036dbc 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -49,18 +49,16 @@
#include <linux/workqueue.h>
#include <linux/jiffies.h>
#include <linux/scatterlist.h>
+#include <linux/io.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
-#include <asm/io.h>
#include <asm/semaphore.h>
#include <asm/byteorder.h>
#include "libata.h"
-#define DRV_VERSION "2.21" /* must be exactly four chars */
-
/* debounce timing parameters in msecs { interval, duration, timeout } */
const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
@@ -70,6 +68,8 @@ const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 };
static unsigned int ata_dev_init_params(struct ata_device *dev,
u16 heads, u16 sectors);
static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
+static unsigned int ata_dev_set_feature(struct ata_device *dev,
+ u8 enable, u8 feature);
static void ata_dev_xfermask(struct ata_device *dev);
static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
@@ -86,21 +86,29 @@ int atapi_dmadir = 0;
module_param(atapi_dmadir, int, 0444);
MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
+int atapi_passthru16 = 1;
+module_param(atapi_passthru16, int, 0444);
+MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices; on by default (0=off, 1=on)");
+
int libata_fua = 0;
module_param_named(fua, libata_fua, int, 0444);
MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
-static int ata_ignore_hpa = 0;
+static int ata_ignore_hpa;
module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644);
MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)");
+static int libata_dma_mask = ATA_DMA_MASK_ATA|ATA_DMA_MASK_ATAPI|ATA_DMA_MASK_CFA;
+module_param_named(dma, libata_dma_mask, int, 0444);
+MODULE_PARM_DESC(dma, "DMA enable/disable (0x1==ATA, 0x2==ATAPI, 0x4==CF)");
+
static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
module_param(ata_probe_timeout, int, 0444);
MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
-int libata_noacpi = 1;
+int libata_noacpi = 0;
module_param_named(noacpi, libata_noacpi, int, 0444);
-MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in suspend/resume when set");
+MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set");
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("Library module for ATA devices");
@@ -235,7 +243,7 @@ static int ata_rwcmd_protocol(struct ata_taskfile *tf, struct ata_device *dev)
if (dev->flags & ATA_DFLAG_PIO) {
tf->protocol = ATA_PROT_PIO;
index = dev->multi_count ? 0 : 8;
- } else if (lba48 && (dev->ap->flags & ATA_FLAG_PIO_LBA48)) {
+ } else if (lba48 && (dev->link->ap->flags & ATA_FLAG_PIO_LBA48)) {
/* Unable to use DMA due to host limitation */
tf->protocol = ATA_PROT_PIO;
index = dev->multi_count ? 0 : 8;
@@ -604,7 +612,7 @@ static const char *sata_spd_string(unsigned int spd)
void ata_dev_disable(struct ata_device *dev)
{
if (ata_dev_enabled(dev)) {
- if (ata_msg_drv(dev->ap))
+ if (ata_msg_drv(dev->link->ap))
ata_dev_printk(dev, KERN_WARNING, "disabled\n");
ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 |
ATA_DNXFER_QUIET);
@@ -612,6 +620,183 @@ void ata_dev_disable(struct ata_device *dev)
}
}
+static int ata_dev_set_dipm(struct ata_device *dev, enum link_pm policy)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ u32 scontrol;
+ unsigned int err_mask;
+ int rc;
+
+ /*
+ * disallow DIPM for drivers which haven't set
+ * ATA_FLAG_IPM. This is because when DIPM is enabled,
+ * phy ready will be set in the interrupt status on
+ * state changes, which will cause some drivers to
+ * think there are errors - additionally drivers will
+ * need to disable hot plug.
+ */
+ if (!(ap->flags & ATA_FLAG_IPM) || !ata_dev_enabled(dev)) {
+ ap->pm_policy = NOT_AVAILABLE;
+ return -EINVAL;
+ }
+
+ /*
+ * For DIPM, we will only enable it for the
+ * min_power setting.
+ *
+ * Why? Because Disks are too stupid to know that
+ * If the host rejects a request to go to SLUMBER
+ * they should retry at PARTIAL, and instead it
+ * just would give up. So, for medium_power to
+ * work at all, we need to only allow HIPM.
+ */
+ rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
+ if (rc)
+ return rc;
+
+ switch (policy) {
+ case MIN_POWER:
+ /* no restrictions on IPM transitions */
+ scontrol &= ~(0x3 << 8);
+ rc = sata_scr_write(link, SCR_CONTROL, scontrol);
+ if (rc)
+ return rc;
+
+ /* enable DIPM */
+ if (dev->flags & ATA_DFLAG_DIPM)
+ err_mask = ata_dev_set_feature(dev,
+ SETFEATURES_SATA_ENABLE, SATA_DIPM);
+ break;
+ case MEDIUM_POWER:
+ /* allow IPM to PARTIAL */
+ scontrol &= ~(0x1 << 8);
+ scontrol |= (0x2 << 8);
+ rc = sata_scr_write(link, SCR_CONTROL, scontrol);
+ if (rc)
+ return rc;
+
+ /*
+ * we don't have to disable DIPM since IPM flags
+ * disallow transitions to SLUMBER, which effectively
+ * disable DIPM if it does not support PARTIAL
+ */
+ break;
+ case NOT_AVAILABLE:
+ case MAX_PERFORMANCE:
+ /* disable all IPM transitions */
+ scontrol |= (0x3 << 8);
+ rc = sata_scr_write(link, SCR_CONTROL, scontrol);
+ if (rc)
+ return rc;
+
+ /*
+ * we don't have to disable DIPM since IPM flags
+ * disallow all transitions which effectively
+ * disable DIPM anyway.
+ */
+ break;
+ }
+
+ /* FIXME: handle SET FEATURES failure */
+ (void) err_mask;
+
+ return 0;
+}
+
+/**
+ * ata_dev_enable_pm - enable SATA interface power management
+ * @dev: device to enable power management
+ * @policy: the link power management policy
+ *
+ * Enable SATA Interface power management. This will enable
+ * Device Interface Power Management (DIPM) for min_power
+ * policy, and then call driver specific callbacks for
+ * enabling Host Initiated Power management.
+ *
+ * Locking: Caller.
+ * Returns: -EINVAL if IPM is not supported, 0 otherwise.
+ */
+void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy)
+{
+ int rc = 0;
+ struct ata_port *ap = dev->link->ap;
+
+ /* set HIPM first, then DIPM */
+ if (ap->ops->enable_pm)
+ rc = ap->ops->enable_pm(ap, policy);
+ if (rc)
+ goto enable_pm_out;
+ rc = ata_dev_set_dipm(dev, policy);
+
+enable_pm_out:
+ if (rc)
+ ap->pm_policy = MAX_PERFORMANCE;
+ else
+ ap->pm_policy = policy;
+ return /* rc */; /* hopefully we can use 'rc' eventually */
+}
+
+#ifdef CONFIG_PM
+/**
+ * ata_dev_disable_pm - disable SATA interface power management
+ * @dev: device to disable power management
+ *
+ * Disable SATA Interface power management. This will disable
+ * Device Interface Power Management (DIPM) without changing
+ * policy, call driver specific callbacks for disabling Host
+ * Initiated Power management.
+ *
+ * Locking: Caller.
+ * Returns: void
+ */
+static void ata_dev_disable_pm(struct ata_device *dev)
+{
+ struct ata_port *ap = dev->link->ap;
+
+ ata_dev_set_dipm(dev, MAX_PERFORMANCE);
+ if (ap->ops->disable_pm)
+ ap->ops->disable_pm(ap);
+}
+#endif /* CONFIG_PM */
+
+void ata_lpm_schedule(struct ata_port *ap, enum link_pm policy)
+{
+ ap->pm_policy = policy;
+ ap->link.eh_info.action |= ATA_EHI_LPM;
+ ap->link.eh_info.flags |= ATA_EHI_NO_AUTOPSY;
+ ata_port_schedule_eh(ap);
+}
+
+#ifdef CONFIG_PM
+static void ata_lpm_enable(struct ata_host *host)
+{
+ struct ata_link *link;
+ struct ata_port *ap;
+ struct ata_device *dev;
+ int i;
+
+ for (i = 0; i < host->n_ports; i++) {
+ ap = host->ports[i];
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link)
+ ata_dev_disable_pm(dev);
+ }
+ }
+}
+
+static void ata_lpm_disable(struct ata_host *host)
+{
+ int i;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ ata_lpm_schedule(ap, ap->pm_policy);
+ }
+}
+#endif /* CONFIG_PM */
+
+
/**
* ata_devchk - PATA device presence detection
* @ap: ATA channel to examine
@@ -667,37 +852,57 @@ static unsigned int ata_devchk(struct ata_port *ap, unsigned int device)
* None.
*
* RETURNS:
- * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN
- * the event of failure.
+ * Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, %ATA_DEV_PMP or
+ * %ATA_DEV_UNKNOWN the event of failure.
*/
-
unsigned int ata_dev_classify(const struct ata_taskfile *tf)
{
/* Apple's open source Darwin code hints that some devices only
* put a proper signature into the LBA mid/high registers,
* So, we only check those. It's sufficient for uniqueness.
+ *
+ * ATA/ATAPI-7 (d1532v1r1: Feb. 19, 2003) specified separate
+ * signatures for ATA and ATAPI devices attached on SerialATA,
+ * 0x3c/0xc3 and 0x69/0x96 respectively. However, SerialATA
+ * spec has never mentioned about using different signatures
+ * for ATA/ATAPI devices. Then, Serial ATA II: Port
+ * Multiplier specification began to use 0x69/0x96 to identify
+ * port multpliers and 0x3c/0xc3 to identify SEMB device.
+ * ATA/ATAPI-7 dropped descriptions about 0x3c/0xc3 and
+ * 0x69/0x96 shortly and described them as reserved for
+ * SerialATA.
+ *
+ * We follow the current spec and consider that 0x69/0x96
+ * identifies a port multiplier and 0x3c/0xc3 a SEMB device.
*/
-
- if (((tf->lbam == 0) && (tf->lbah == 0)) ||
- ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) {
+ if ((tf->lbam == 0) && (tf->lbah == 0)) {
DPRINTK("found ATA device by sig\n");
return ATA_DEV_ATA;
}
- if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) ||
- ((tf->lbam == 0x69) && (tf->lbah == 0x96))) {
+ if ((tf->lbam == 0x14) && (tf->lbah == 0xeb)) {
DPRINTK("found ATAPI device by sig\n");
return ATA_DEV_ATAPI;
}
+ if ((tf->lbam == 0x69) && (tf->lbah == 0x96)) {
+ DPRINTK("found PMP device by sig\n");
+ return ATA_DEV_PMP;
+ }
+
+ if ((tf->lbam == 0x3c) && (tf->lbah == 0xc3)) {
+ printk(KERN_INFO "ata: SEMB device ignored\n");
+ return ATA_DEV_SEMB_UNSUP; /* not yet */
+ }
+
DPRINTK("unknown device\n");
return ATA_DEV_UNKNOWN;
}
/**
* ata_dev_try_classify - Parse returned ATA device signature
- * @ap: ATA channel to examine
- * @device: Device to examine (starting at zero)
+ * @dev: ATA device to classify (starting at zero)
+ * @present: device seems present
* @r_err: Value of error register on completion
*
* After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
@@ -715,15 +920,15 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
* RETURNS:
* Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
*/
-
-unsigned int
-ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
+unsigned int ata_dev_try_classify(struct ata_device *dev, int present,
+ u8 *r_err)
{
+ struct ata_port *ap = dev->link->ap;
struct ata_taskfile tf;
unsigned int class;
u8 err;
- ap->ops->dev_select(ap, device);
+ ap->ops->dev_select(ap, dev->devno);
memset(&tf, 0, sizeof(tf));
@@ -733,12 +938,12 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
*r_err = err;
/* see if device passed diags: if master then continue and warn later */
- if (err == 0 && device == 0)
+ if (err == 0 && dev->devno == 0)
/* diagnostic fail : do nothing _YET_ */
- ap->device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC;
+ dev->horkage |= ATA_HORKAGE_DIAGNOSTIC;
else if (err == 1)
/* do nothing */ ;
- else if ((device == 0) && (err == 0x81))
+ else if ((dev->devno == 0) && (err == 0x81))
/* do nothing */ ;
else
return ATA_DEV_NONE;
@@ -746,10 +951,20 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
/* determine if device is ATA or ATAPI */
class = ata_dev_classify(&tf);
- if (class == ATA_DEV_UNKNOWN)
- return ATA_DEV_NONE;
- if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
- return ATA_DEV_NONE;
+ if (class == ATA_DEV_UNKNOWN) {
+ /* If the device failed diagnostic, it's likely to
+ * have reported incorrect device signature too.
+ * Assume ATA device if the device seems present but
+ * device signature is invalid with diagnostic
+ * failure.
+ */
+ if (present && (dev->horkage & ATA_HORKAGE_DIAGNOSTIC))
+ class = ATA_DEV_ATA;
+ else
+ class = ATA_DEV_NONE;
+ } else if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
+ class = ATA_DEV_NONE;
+
return class;
}
@@ -816,6 +1031,21 @@ void ata_id_c_string(const u16 *id, unsigned char *s,
*p = '\0';
}
+static u64 ata_id_n_sectors(const u16 *id)
+{
+ if (ata_id_has_lba(id)) {
+ if (ata_id_has_lba48(id))
+ return ata_id_u64(id, 100);
+ else
+ return ata_id_u32(id, 60);
+ } else {
+ if (ata_id_current_chs_valid(id))
+ return ata_id_u32(id, 57);
+ else
+ return id[1] * id[3] * id[6];
+ }
+}
+
static u64 ata_tf_to_lba48(struct ata_taskfile *tf)
{
u64 sectors = 0;
@@ -843,129 +1073,110 @@ static u64 ata_tf_to_lba(struct ata_taskfile *tf)
}
/**
- * ata_read_native_max_address_ext - LBA48 native max query
- * @dev: Device to query
+ * ata_read_native_max_address - Read native max address
+ * @dev: target device
+ * @max_sectors: out parameter for the result native max address
*
- * Perform an LBA48 size query upon the device in question. Return the
- * actual LBA48 size or zero if the command fails.
- */
-
-static u64 ata_read_native_max_address_ext(struct ata_device *dev)
-{
- unsigned int err;
- struct ata_taskfile tf;
-
- ata_tf_init(dev, &tf);
-
- tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
- tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
- tf.protocol |= ATA_PROT_NODATA;
- tf.device |= 0x40;
-
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- return 0;
-
- return ata_tf_to_lba48(&tf);
-}
-
-/**
- * ata_read_native_max_address - LBA28 native max query
- * @dev: Device to query
+ * Perform an LBA48 or LBA28 native size query upon the device in
+ * question.
*
- * Performa an LBA28 size query upon the device in question. Return the
- * actual LBA28 size or zero if the command fails.
+ * RETURNS:
+ * 0 on success, -EACCES if command is aborted by the drive.
+ * -EIO on other errors.
*/
-
-static u64 ata_read_native_max_address(struct ata_device *dev)
+static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors)
{
- unsigned int err;
+ unsigned int err_mask;
struct ata_taskfile tf;
+ int lba48 = ata_id_has_lba48(dev->id);
ata_tf_init(dev, &tf);
- tf.command = ATA_CMD_READ_NATIVE_MAX;
+ /* always clear all address registers */
tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+
+ if (lba48) {
+ tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
+ tf.flags |= ATA_TFLAG_LBA48;
+ } else
+ tf.command = ATA_CMD_READ_NATIVE_MAX;
+
tf.protocol |= ATA_PROT_NODATA;
- tf.device |= 0x40;
+ tf.device |= ATA_LBA;
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- return 0;
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_WARNING, "failed to read native "
+ "max address (err_mask=0x%x)\n", err_mask);
+ if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED))
+ return -EACCES;
+ return -EIO;
+ }
- return ata_tf_to_lba(&tf);
+ if (lba48)
+ *max_sectors = ata_tf_to_lba48(&tf);
+ else
+ *max_sectors = ata_tf_to_lba(&tf);
+ if (dev->horkage & ATA_HORKAGE_HPA_SIZE)
+ (*max_sectors)--;
+ return 0;
}
/**
- * ata_set_native_max_address_ext - LBA48 native max set
- * @dev: Device to query
+ * ata_set_max_sectors - Set max sectors
+ * @dev: target device
* @new_sectors: new max sectors value to set for the device
*
- * Perform an LBA48 size set max upon the device in question. Return the
- * actual LBA48 size or zero if the command fails.
+ * Set max sectors of @dev to @new_sectors.
+ *
+ * RETURNS:
+ * 0 on success, -EACCES if command is aborted or denied (due to
+ * previous non-volatile SET_MAX) by the drive. -EIO on other
+ * errors.
*/
-
-static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors)
+static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors)
{
- unsigned int err;
+ unsigned int err_mask;
struct ata_taskfile tf;
+ int lba48 = ata_id_has_lba48(dev->id);
new_sectors--;
ata_tf_init(dev, &tf);
- tf.command = ATA_CMD_SET_MAX_EXT;
- tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
- tf.protocol |= ATA_PROT_NODATA;
- tf.device |= 0x40;
-
- tf.lbal = (new_sectors >> 0) & 0xff;
- tf.lbam = (new_sectors >> 8) & 0xff;
- tf.lbah = (new_sectors >> 16) & 0xff;
-
- tf.hob_lbal = (new_sectors >> 24) & 0xff;
- tf.hob_lbam = (new_sectors >> 32) & 0xff;
- tf.hob_lbah = (new_sectors >> 40) & 0xff;
-
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- return 0;
-
- return ata_tf_to_lba48(&tf);
-}
-
-/**
- * ata_set_native_max_address - LBA28 native max set
- * @dev: Device to query
- * @new_sectors: new max sectors value to set for the device
- *
- * Perform an LBA28 size set max upon the device in question. Return the
- * actual LBA28 size or zero if the command fails.
- */
+ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
-static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
-{
- unsigned int err;
- struct ata_taskfile tf;
+ if (lba48) {
+ tf.command = ATA_CMD_SET_MAX_EXT;
+ tf.flags |= ATA_TFLAG_LBA48;
- new_sectors--;
+ tf.hob_lbal = (new_sectors >> 24) & 0xff;
+ tf.hob_lbam = (new_sectors >> 32) & 0xff;
+ tf.hob_lbah = (new_sectors >> 40) & 0xff;
+ } else {
+ tf.command = ATA_CMD_SET_MAX;
- ata_tf_init(dev, &tf);
+ tf.device |= (new_sectors >> 24) & 0xf;
+ }
- tf.command = ATA_CMD_SET_MAX;
- tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
tf.protocol |= ATA_PROT_NODATA;
+ tf.device |= ATA_LBA;
tf.lbal = (new_sectors >> 0) & 0xff;
tf.lbam = (new_sectors >> 8) & 0xff;
tf.lbah = (new_sectors >> 16) & 0xff;
- tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40;
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- return 0;
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_WARNING, "failed to set "
+ "max address (err_mask=0x%x)\n", err_mask);
+ if (err_mask == AC_ERR_DEV &&
+ (tf.feature & (ATA_ABORTED | ATA_IDNF)))
+ return -EACCES;
+ return -EIO;
+ }
- return ata_tf_to_lba(&tf);
+ return 0;
}
/**
@@ -975,60 +1186,93 @@ static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
* Read the size of an LBA28 or LBA48 disk with HPA features and resize
* it if required to the full size of the media. The caller must check
* the drive has the HPA feature set enabled.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
*/
-
-static u64 ata_hpa_resize(struct ata_device *dev)
+static int ata_hpa_resize(struct ata_device *dev)
{
- u64 sectors = dev->n_sectors;
- u64 hpa_sectors;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
+ int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
+ u64 sectors = ata_id_n_sectors(dev->id);
+ u64 native_sectors;
+ int rc;
- if (ata_id_has_lba48(dev->id))
- hpa_sectors = ata_read_native_max_address_ext(dev);
- else
- hpa_sectors = ata_read_native_max_address(dev);
+ /* do we need to do it? */
+ if (dev->class != ATA_DEV_ATA ||
+ !ata_id_has_lba(dev->id) || !ata_id_hpa_enabled(dev->id) ||
+ (dev->horkage & ATA_HORKAGE_BROKEN_HPA))
+ return 0;
- if (hpa_sectors > sectors) {
- ata_dev_printk(dev, KERN_INFO,
- "Host Protected Area detected:\n"
- "\tcurrent size: %lld sectors\n"
- "\tnative size: %lld sectors\n",
- (long long)sectors, (long long)hpa_sectors);
-
- if (ata_ignore_hpa) {
- if (ata_id_has_lba48(dev->id))
- hpa_sectors = ata_set_native_max_address_ext(dev, hpa_sectors);
- else
- hpa_sectors = ata_set_native_max_address(dev,
- hpa_sectors);
-
- if (hpa_sectors) {
- ata_dev_printk(dev, KERN_INFO, "native size "
- "increased to %lld sectors\n",
- (long long)hpa_sectors);
- return hpa_sectors;
- }
+ /* read native max address */
+ rc = ata_read_native_max_address(dev, &native_sectors);
+ if (rc) {
+ /* If HPA isn't going to be unlocked, skip HPA
+ * resizing from the next try.
+ */
+ if (!ata_ignore_hpa) {
+ ata_dev_printk(dev, KERN_WARNING, "HPA support seems "
+ "broken, will skip HPA handling\n");
+ dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
+
+ /* we can continue if device aborted the command */
+ if (rc == -EACCES)
+ rc = 0;
}
- } else if (hpa_sectors < sectors)
- ata_dev_printk(dev, KERN_WARNING, "%s 1: hpa sectors (%lld) "
- "is smaller than sectors (%lld)\n", __FUNCTION__,
- (long long)hpa_sectors, (long long)sectors);
- return sectors;
-}
+ return rc;
+ }
-static u64 ata_id_n_sectors(const u16 *id)
-{
- if (ata_id_has_lba(id)) {
- if (ata_id_has_lba48(id))
- return ata_id_u64(id, 100);
- else
- return ata_id_u32(id, 60);
- } else {
- if (ata_id_current_chs_valid(id))
- return ata_id_u32(id, 57);
- else
- return id[1] * id[3] * id[6];
+ /* nothing to do? */
+ if (native_sectors <= sectors || !ata_ignore_hpa) {
+ if (!print_info || native_sectors == sectors)
+ return 0;
+
+ if (native_sectors > sectors)
+ ata_dev_printk(dev, KERN_INFO,
+ "HPA detected: current %llu, native %llu\n",
+ (unsigned long long)sectors,
+ (unsigned long long)native_sectors);
+ else if (native_sectors < sectors)
+ ata_dev_printk(dev, KERN_WARNING,
+ "native sectors (%llu) is smaller than "
+ "sectors (%llu)\n",
+ (unsigned long long)native_sectors,
+ (unsigned long long)sectors);
+ return 0;
}
+
+ /* let's unlock HPA */
+ rc = ata_set_max_sectors(dev, native_sectors);
+ if (rc == -EACCES) {
+ /* if device aborted the command, skip HPA resizing */
+ ata_dev_printk(dev, KERN_WARNING, "device aborted resize "
+ "(%llu -> %llu), skipping HPA handling\n",
+ (unsigned long long)sectors,
+ (unsigned long long)native_sectors);
+ dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
+ return 0;
+ } else if (rc)
+ return rc;
+
+ /* re-read IDENTIFY data */
+ rc = ata_dev_reread_id(dev, 0);
+ if (rc) {
+ ata_dev_printk(dev, KERN_ERR, "failed to re-read IDENTIFY "
+ "data after HPA resizing\n");
+ return rc;
+ }
+
+ if (print_info) {
+ u64 new_sectors = ata_id_n_sectors(dev->id);
+ ata_dev_printk(dev, KERN_INFO,
+ "HPA unlocked: %llu -> %llu, native %llu\n",
+ (unsigned long long)sectors,
+ (unsigned long long)new_sectors,
+ (unsigned long long)native_sectors);
+ }
+
+ return 0;
}
/**
@@ -1085,7 +1329,7 @@ void ata_id_to_dma_mode(struct ata_device *dev, u8 unknown)
* LOCKING:
* caller.
*/
-void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
+void ata_noop_dev_select(struct ata_port *ap, unsigned int device)
{
}
@@ -1105,7 +1349,7 @@ void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
* caller.
*/
-void ata_std_dev_select (struct ata_port *ap, unsigned int device)
+void ata_std_dev_select(struct ata_port *ap, unsigned int device)
{
u8 tmp;
@@ -1150,7 +1394,7 @@ void ata_dev_select(struct ata_port *ap, unsigned int device,
ap->ops->dev_select(ap, device);
if (wait) {
- if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI)
+ if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI)
msleep(150);
ata_wait_idle(ap);
}
@@ -1226,7 +1470,7 @@ static unsigned int ata_id_xfermask(const u16 *id)
*/
u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF;
if (mode < 5) /* Valid PIO range */
- pio_mask = (2 << mode) - 1;
+ pio_mask = (2 << mode) - 1;
else
pio_mask = 1;
@@ -1326,8 +1570,9 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
* @tf: Taskfile registers for the command and the result
* @cdb: CDB for packet command
* @dma_dir: Data tranfer direction of the command
- * @sg: sg list for the data buffer of the command
+ * @sgl: sg list for the data buffer of the command
* @n_elem: Number of sg entries
+ * @timeout: Timeout in msecs (0 for default)
*
* Executes libata internal command with timeout. @tf contains
* command on entry and result on return. Timeout and error
@@ -1343,14 +1588,16 @@ static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
*/
unsigned ata_exec_internal_sg(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
- int dma_dir, struct scatterlist *sg,
- unsigned int n_elem)
+ int dma_dir, struct scatterlist *sgl,
+ unsigned int n_elem, unsigned long timeout)
{
- struct ata_port *ap = dev->ap;
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
u8 command = tf->command;
struct ata_queued_cmd *qc;
unsigned int tag, preempted_tag;
u32 preempted_sactive, preempted_qc_active;
+ int preempted_nr_active_links;
DECLARE_COMPLETION_ONSTACK(wait);
unsigned long flags;
unsigned int err_mask;
@@ -1386,12 +1633,14 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
qc->dev = dev;
ata_qc_reinit(qc);
- preempted_tag = ap->active_tag;
- preempted_sactive = ap->sactive;
+ preempted_tag = link->active_tag;
+ preempted_sactive = link->sactive;
preempted_qc_active = ap->qc_active;
- ap->active_tag = ATA_TAG_POISON;
- ap->sactive = 0;
+ preempted_nr_active_links = ap->nr_active_links;
+ link->active_tag = ATA_TAG_POISON;
+ link->sactive = 0;
ap->qc_active = 0;
+ ap->nr_active_links = 0;
/* prepare & issue qc */
qc->tf = *tf;
@@ -1401,11 +1650,12 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
qc->dma_dir = dma_dir;
if (dma_dir != DMA_NONE) {
unsigned int i, buflen = 0;
+ struct scatterlist *sg;
- for (i = 0; i < n_elem; i++)
- buflen += sg[i].length;
+ for_each_sg(sgl, sg, n_elem, i)
+ buflen += sg->length;
- ata_sg_init(qc, sg, n_elem);
+ ata_sg_init(qc, sgl, n_elem);
qc->nbytes = buflen;
}
@@ -1416,7 +1666,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
spin_unlock_irqrestore(ap->lock, flags);
- rc = wait_for_completion_timeout(&wait, ata_probe_timeout);
+ if (!timeout)
+ timeout = ata_probe_timeout * 1000 / HZ;
+
+ rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout));
ata_port_flush_task(ap);
@@ -1467,9 +1720,10 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
err_mask = qc->err_mask;
ata_qc_free(qc);
- ap->active_tag = preempted_tag;
- ap->sactive = preempted_sactive;
+ link->active_tag = preempted_tag;
+ link->sactive = preempted_sactive;
ap->qc_active = preempted_qc_active;
+ ap->nr_active_links = preempted_nr_active_links;
/* XXX - Some LLDDs (sata_mv) disable port on command failure.
* Until those drivers are fixed, we detect the condition
@@ -1500,6 +1754,7 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
* @dma_dir: Data tranfer direction of the command
* @buf: Data buffer of the command
* @buflen: Length of data buffer
+ * @timeout: Timeout in msecs (0 for default)
*
* Wrapper around ata_exec_internal_sg() which takes simple
* buffer instead of sg list.
@@ -1512,7 +1767,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
*/
unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
- int dma_dir, void *buf, unsigned int buflen)
+ int dma_dir, void *buf, unsigned int buflen,
+ unsigned long timeout)
{
struct scatterlist *psg = NULL, sg;
unsigned int n_elem = 0;
@@ -1524,7 +1780,8 @@ unsigned ata_exec_internal(struct ata_device *dev,
n_elem++;
}
- return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem);
+ return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem,
+ timeout);
}
/**
@@ -1551,7 +1808,7 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
tf.flags |= ATA_TFLAG_DEVICE;
tf.protocol = ATA_PROT_NODATA;
- return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
}
/**
@@ -1566,7 +1823,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
{
/* Controller doesn't support IORDY. Probably a pointless check
as the caller should know this */
- if (adev->ap->flags & ATA_FLAG_NO_IORDY)
+ if (adev->link->ap->flags & ATA_FLAG_NO_IORDY)
return 0;
/* PIO3 and higher it is mandatory */
if (adev->pio_mode > XFER_PIO_2)
@@ -1613,6 +1870,9 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
* devices. This function also issues ATA_CMD_INIT_DEV_PARAMS
* for pre-ATA4 drives.
*
+ * FIXME: ATA_CMD_ID_ATA is optional for early drives and right
+ * now we abort if we hit that case.
+ *
* LOCKING:
* Kernel thread context (may sleep)
*
@@ -1622,7 +1882,7 @@ static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
unsigned int flags, u16 *id)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
unsigned int class = *p_class;
struct ata_taskfile tf;
unsigned int err_mask = 0;
@@ -1663,7 +1923,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
tf.flags |= ATA_TFLAG_POLLING;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
- id, sizeof(id[0]) * ATA_ID_WORDS);
+ id, sizeof(id[0]) * ATA_ID_WORDS, 0);
if (err_mask) {
if (err_mask & AC_ERR_NODEV_HINT) {
DPRINTK("ata%u.%d: NODEV after polling detection\n",
@@ -1717,12 +1977,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
* SET_FEATURES spin-up subcommand before it will accept
* anything other than the original IDENTIFY command.
*/
- ata_tf_init(dev, &tf);
- tf.command = ATA_CMD_SET_FEATURES;
- tf.feature = SETFEATURES_SPINUP;
- tf.protocol = ATA_PROT_NODATA;
- tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0);
if (err_mask && id[2] != 0x738c) {
rc = -EIO;
reason = "SPINUP failed";
@@ -1740,10 +1995,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
/*
* The exact sequence expected by certain pre-ATA4 drives is:
* SRST RESET
- * IDENTIFY
- * INITIALIZE DEVICE PARAMETERS
+ * IDENTIFY (optional in early ATA)
+ * INITIALIZE DEVICE PARAMETERS (later IDE and ATA)
* anything else..
* Some drives were very specific about that exact sequence.
+ *
+ * Note that ATA4 says lba is mandatory so the second check
+ * shoud never trigger.
*/
if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
err_mask = ata_dev_init_params(dev, id[3], id[6]);
@@ -1774,13 +2032,14 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
static inline u8 ata_dev_knobble(struct ata_device *dev)
{
- return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
+ struct ata_port *ap = dev->link->ap;
+ return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
}
static void ata_dev_config_ncq(struct ata_device *dev,
char *desc, size_t desc_sz)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
if (!ata_id_has_ncq(dev->id)) {
@@ -1817,8 +2076,8 @@ static void ata_dev_config_ncq(struct ata_device *dev,
*/
int ata_dev_configure(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = dev->link->ap;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
const u16 *id = dev->id;
unsigned int xfer_mask;
@@ -1844,6 +2103,11 @@ int ata_dev_configure(struct ata_device *dev)
if (rc)
return rc;
+ /* massage HPA, do it early as it might change IDENTIFY data */
+ rc = ata_hpa_resize(dev);
+ if (rc)
+ return rc;
+
/* print device capabilities */
if (ata_msg_probe(ap))
ata_dev_printk(dev, KERN_DEBUG,
@@ -1887,9 +2151,8 @@ int ata_dev_configure(struct ata_device *dev)
"supports DRM functions and may "
"not be fully accessable.\n");
snprintf(revbuf, 7, "CFA");
- }
- else
- snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id));
+ } else
+ snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id));
dev->n_sectors = ata_id_n_sectors(id);
@@ -1911,10 +2174,6 @@ int ata_dev_configure(struct ata_device *dev)
dev->flags |= ATA_DFLAG_FLUSH_EXT;
}
- if (!(dev->horkage & ATA_HORKAGE_BROKEN_HPA) &&
- ata_id_hpa_enabled(dev->id))
- dev->n_sectors = ata_hpa_resize(dev);
-
/* config NCQ */
ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
@@ -1963,7 +2222,9 @@ int ata_dev_configure(struct ata_device *dev)
/* ATAPI-specific feature tests */
else if (dev->class == ATA_DEV_ATAPI) {
- char *cdb_intr_string = "";
+ const char *cdb_intr_string = "";
+ const char *atapi_an_string = "";
+ u32 sntf;
rc = atapi_cdb_len(id);
if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
@@ -1975,6 +2236,29 @@ int ata_dev_configure(struct ata_device *dev)
}
dev->cdb_len = (unsigned int) rc;
+ /* Enable ATAPI AN if both the host and device have
+ * the support. If PMP is attached, SNTF is required
+ * to enable ATAPI AN to discern between PHY status
+ * changed notifications and ATAPI ANs.
+ */
+ if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
+ (!ap->nr_pmp_links ||
+ sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) {
+ unsigned int err_mask;
+
+ /* issue SET feature command to turn this on */
+ err_mask = ata_dev_set_feature(dev,
+ SETFEATURES_SATA_ENABLE, SATA_AN);
+ if (err_mask)
+ ata_dev_printk(dev, KERN_ERR,
+ "failed to enable ATAPI AN "
+ "(err_mask=0x%x)\n", err_mask);
+ else {
+ dev->flags |= ATA_DFLAG_AN;
+ atapi_an_string = ", ATAPI AN";
+ }
+ }
+
if (ata_id_cdb_intr(dev->id)) {
dev->flags |= ATA_DFLAG_CDB_INTR;
cdb_intr_string = ", CDB intr";
@@ -1983,10 +2267,10 @@ int ata_dev_configure(struct ata_device *dev)
/* print device info to dmesg */
if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO,
- "ATAPI: %s, %s, max %s%s\n",
+ "ATAPI: %s, %s, max %s%s%s\n",
modelbuf, fwrevbuf,
ata_mode_string(xfer_mask),
- cdb_intr_string);
+ cdb_intr_string, atapi_an_string);
}
/* determine max_sectors */
@@ -1994,11 +2278,18 @@ int ata_dev_configure(struct ata_device *dev)
if (dev->flags & ATA_DFLAG_LBA48)
dev->max_sectors = ATA_MAX_SECTORS_LBA48;
+ if (!(dev->horkage & ATA_HORKAGE_IPM)) {
+ if (ata_id_has_hipm(dev->id))
+ dev->flags |= ATA_DFLAG_HIPM;
+ if (ata_id_has_dipm(dev->id))
+ dev->flags |= ATA_DFLAG_DIPM;
+ }
+
if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) {
/* Let the user know. We don't want to disallow opens for
rescue purposes, or in case the vendor is just a blithering
idiot */
- if (print_info) {
+ if (print_info) {
ata_dev_printk(dev, KERN_WARNING,
"Drive reports diagnostics failure. This may indicate a drive\n");
ata_dev_printk(dev, KERN_WARNING,
@@ -2015,10 +2306,21 @@ int ata_dev_configure(struct ata_device *dev)
dev->max_sectors = ATA_MAX_SECTORS;
}
+ if ((dev->class == ATA_DEV_ATAPI) &&
+ (atapi_command_packet_set(id) == TYPE_TAPE))
+ dev->max_sectors = ATA_MAX_SECTORS_TAPE;
+
if (dev->horkage & ATA_HORKAGE_MAX_SEC_128)
dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
dev->max_sectors);
+ if (ata_dev_blacklisted(dev) & ATA_HORKAGE_IPM) {
+ dev->horkage |= ATA_HORKAGE_IPM;
+
+ /* reset link pm_policy for this port to no pm */
+ ap->pm_policy = MAX_PERFORMANCE;
+ }
+
if (ap->ops->dev_config)
ap->ops->dev_config(dev);
@@ -2103,21 +2405,38 @@ int ata_bus_probe(struct ata_port *ap)
{
unsigned int classes[ATA_MAX_DEVICES];
int tries[ATA_MAX_DEVICES];
- int i, rc;
+ int rc;
struct ata_device *dev;
ata_port_probe(ap);
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- tries[i] = ATA_PROBE_MAX_TRIES;
+ ata_link_for_each_dev(dev, &ap->link)
+ tries[dev->devno] = ATA_PROBE_MAX_TRIES;
retry:
+ ata_link_for_each_dev(dev, &ap->link) {
+ /* If we issue an SRST then an ATA drive (not ATAPI)
+ * may change configuration and be in PIO0 timing. If
+ * we do a hard reset (or are coming from power on)
+ * this is true for ATA or ATAPI. Until we've set a
+ * suitable controller mode we should not touch the
+ * bus as we may be talking too fast.
+ */
+ dev->pio_mode = XFER_PIO_0;
+
+ /* If the controller has a pio mode setup function
+ * then use it to set the chipset to rights. Don't
+ * touch the DMA setup as that will be dealt with when
+ * configuring devices.
+ */
+ if (ap->ops->set_piomode)
+ ap->ops->set_piomode(ap, dev);
+ }
+
/* reset and determine device classes */
ap->ops->phy_reset(ap);
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
+ ata_link_for_each_dev(dev, &ap->link) {
if (!(ap->flags & ATA_FLAG_DISABLED) &&
dev->class != ATA_DEV_UNKNOWN)
classes[dev->devno] = dev->class;
@@ -2129,21 +2448,13 @@ int ata_bus_probe(struct ata_port *ap)
ata_port_probe(ap);
- /* after the reset the device state is PIO 0 and the controller
- state is undefined. Record the mode */
-
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->device[i].pio_mode = XFER_PIO_0;
-
/* read IDENTIFY page and configure devices. We have to do the identify
specific sequence bass-ackwards so that PDIAG- is released by
the slave device */
- for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) {
- dev = &ap->device[i];
-
- if (tries[i])
- dev->class = classes[i];
+ ata_link_for_each_dev(dev, &ap->link) {
+ if (tries[dev->devno])
+ dev->class = classes[dev->devno];
if (!ata_dev_enabled(dev))
continue;
@@ -2158,33 +2469,42 @@ int ata_bus_probe(struct ata_port *ap)
if (ap->ops->cable_detect)
ap->cbl = ap->ops->cable_detect(ap);
+ /* We may have SATA bridge glue hiding here irrespective of the
+ reported cable types and sensed types */
+ ata_link_for_each_dev(dev, &ap->link) {
+ if (!ata_dev_enabled(dev))
+ continue;
+ /* SATA drives indicate we have a bridge. We don't know which
+ end of the link the bridge is which is a problem */
+ if (ata_id_is_sata(dev->id))
+ ap->cbl = ATA_CBL_SATA;
+ }
+
/* After the identify sequence we can now set up the devices. We do
this in the normal order so that the user doesn't get confused */
- for(i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
+ ata_link_for_each_dev(dev, &ap->link) {
if (!ata_dev_enabled(dev))
continue;
- ap->eh_context.i.flags |= ATA_EHI_PRINTINFO;
+ ap->link.eh_context.i.flags |= ATA_EHI_PRINTINFO;
rc = ata_dev_configure(dev);
- ap->eh_context.i.flags &= ~ATA_EHI_PRINTINFO;
+ ap->link.eh_context.i.flags &= ~ATA_EHI_PRINTINFO;
if (rc)
goto fail;
}
/* configure transfer mode */
- rc = ata_set_mode(ap, &dev);
+ rc = ata_set_mode(&ap->link, &dev);
if (rc)
goto fail;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (ata_dev_enabled(&ap->device[i]))
+ ata_link_for_each_dev(dev, &ap->link)
+ if (ata_dev_enabled(dev))
return 0;
/* no device present, disable port */
ata_port_disable(ap);
- ap->ops->port_disable(ap);
return -ENODEV;
fail:
@@ -2204,7 +2524,7 @@ int ata_bus_probe(struct ata_port *ap)
/* This is the last chance, better to slow
* down than lose it.
*/
- sata_down_spd_limit(ap);
+ sata_down_spd_limit(&ap->link);
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
}
}
@@ -2233,28 +2553,28 @@ void ata_port_probe(struct ata_port *ap)
/**
* sata_print_link_status - Print SATA link status
- * @ap: SATA port to printk link status about
+ * @link: SATA link to printk link status about
*
* This function prints link speed and status of a SATA link.
*
* LOCKING:
* None.
*/
-void sata_print_link_status(struct ata_port *ap)
+void sata_print_link_status(struct ata_link *link)
{
u32 sstatus, scontrol, tmp;
- if (sata_scr_read(ap, SCR_STATUS, &sstatus))
+ if (sata_scr_read(link, SCR_STATUS, &sstatus))
return;
- sata_scr_read(ap, SCR_CONTROL, &scontrol);
+ sata_scr_read(link, SCR_CONTROL, &scontrol);
- if (ata_port_online(ap)) {
+ if (ata_link_online(link)) {
tmp = (sstatus >> 4) & 0xf;
- ata_port_printk(ap, KERN_INFO,
+ ata_link_printk(link, KERN_INFO,
"SATA link up %s (SStatus %X SControl %X)\n",
sata_spd_string(tmp), sstatus, scontrol);
} else {
- ata_port_printk(ap, KERN_INFO,
+ ata_link_printk(link, KERN_INFO,
"SATA link down (SStatus %X SControl %X)\n",
sstatus, scontrol);
}
@@ -2274,32 +2594,33 @@ void sata_print_link_status(struct ata_port *ap)
*/
void __sata_phy_reset(struct ata_port *ap)
{
- u32 sstatus;
+ struct ata_link *link = &ap->link;
unsigned long timeout = jiffies + (HZ * 5);
+ u32 sstatus;
if (ap->flags & ATA_FLAG_SATA_RESET) {
/* issue phy wake/reset */
- sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+ sata_scr_write_flush(link, SCR_CONTROL, 0x301);
/* Couldn't find anything in SATA I/II specs, but
* AHCI-1.1 10.4.2 says at least 1 ms. */
mdelay(1);
}
/* phy wake/clear reset */
- sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+ sata_scr_write_flush(link, SCR_CONTROL, 0x300);
/* wait for phy to become ready, if necessary */
do {
msleep(200);
- sata_scr_read(ap, SCR_STATUS, &sstatus);
+ sata_scr_read(link, SCR_STATUS, &sstatus);
if ((sstatus & 0xf) != 1)
break;
} while (time_before(jiffies, timeout));
/* print link status */
- sata_print_link_status(ap);
+ sata_print_link_status(link);
/* TODO: phy layer with polling, timeouts, etc. */
- if (!ata_port_offline(ap))
+ if (!ata_link_offline(link))
ata_port_probe(ap);
else
ata_port_disable(ap);
@@ -2344,8 +2665,8 @@ void sata_phy_reset(struct ata_port *ap)
struct ata_device *ata_dev_pair(struct ata_device *adev)
{
- struct ata_port *ap = adev->ap;
- struct ata_device *pair = &ap->device[1 - adev->devno];
+ struct ata_link *link = adev->link;
+ struct ata_device *pair = &link->device[1 - adev->devno];
if (!ata_dev_enabled(pair))
return NULL;
return pair;
@@ -2366,16 +2687,16 @@ struct ata_device *ata_dev_pair(struct ata_device *adev)
void ata_port_disable(struct ata_port *ap)
{
- ap->device[0].class = ATA_DEV_NONE;
- ap->device[1].class = ATA_DEV_NONE;
+ ap->link.device[0].class = ATA_DEV_NONE;
+ ap->link.device[1].class = ATA_DEV_NONE;
ap->flags |= ATA_FLAG_DISABLED;
}
/**
* sata_down_spd_limit - adjust SATA spd limit downward
- * @ap: Port to adjust SATA spd limit for
+ * @link: Link to adjust SATA spd limit for
*
- * Adjust SATA spd limit of @ap downward. Note that this
+ * Adjust SATA spd limit of @link downward. Note that this
* function only adjusts the limit. The change must be applied
* using sata_set_spd().
*
@@ -2385,24 +2706,24 @@ void ata_port_disable(struct ata_port *ap)
* RETURNS:
* 0 on success, negative errno on failure
*/
-int sata_down_spd_limit(struct ata_port *ap)
+int sata_down_spd_limit(struct ata_link *link)
{
u32 sstatus, spd, mask;
int rc, highbit;
- if (!sata_scr_valid(ap))
+ if (!sata_scr_valid(link))
return -EOPNOTSUPP;
/* If SCR can be read, use it to determine the current SPD.
- * If not, use cached value in ap->sata_spd.
+ * If not, use cached value in link->sata_spd.
*/
- rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
+ rc = sata_scr_read(link, SCR_STATUS, &sstatus);
if (rc == 0)
spd = (sstatus >> 4) & 0xf;
else
- spd = ap->sata_spd;
+ spd = link->sata_spd;
- mask = ap->sata_spd_limit;
+ mask = link->sata_spd_limit;
if (mask <= 1)
return -EINVAL;
@@ -2422,35 +2743,45 @@ int sata_down_spd_limit(struct ata_port *ap)
if (!mask)
return -EINVAL;
- ap->sata_spd_limit = mask;
+ link->sata_spd_limit = mask;
- ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n",
+ ata_link_printk(link, KERN_WARNING, "limiting SATA link speed to %s\n",
sata_spd_string(fls(mask)));
return 0;
}
-static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
+static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol)
{
- u32 spd, limit;
+ struct ata_link *host_link = &link->ap->link;
+ u32 limit, target, spd;
+
+ limit = link->sata_spd_limit;
+
+ /* Don't configure downstream link faster than upstream link.
+ * It doesn't speed up anything and some PMPs choke on such
+ * configuration.
+ */
+ if (!ata_is_host_link(link) && host_link->sata_spd)
+ limit &= (1 << host_link->sata_spd) - 1;
- if (ap->sata_spd_limit == UINT_MAX)
- limit = 0;
+ if (limit == UINT_MAX)
+ target = 0;
else
- limit = fls(ap->sata_spd_limit);
+ target = fls(limit);
spd = (*scontrol >> 4) & 0xf;
- *scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4);
+ *scontrol = (*scontrol & ~0xf0) | ((target & 0xf) << 4);
- return spd != limit;
+ return spd != target;
}
/**
* sata_set_spd_needed - is SATA spd configuration needed
- * @ap: Port in question
+ * @link: Link in question
*
* Test whether the spd limit in SControl matches
- * @ap->sata_spd_limit. This function is used to determine
+ * @link->sata_spd_limit. This function is used to determine
* whether hardreset is necessary to apply SATA spd
* configuration.
*
@@ -2460,21 +2791,21 @@ static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
* RETURNS:
* 1 if SATA spd configuration is needed, 0 otherwise.
*/
-int sata_set_spd_needed(struct ata_port *ap)
+int sata_set_spd_needed(struct ata_link *link)
{
u32 scontrol;
- if (sata_scr_read(ap, SCR_CONTROL, &scontrol))
- return 0;
+ if (sata_scr_read(link, SCR_CONTROL, &scontrol))
+ return 1;
- return __sata_set_spd_needed(ap, &scontrol);
+ return __sata_set_spd_needed(link, &scontrol);
}
/**
* sata_set_spd - set SATA spd according to spd limit
- * @ap: Port to set SATA spd for
+ * @link: Link to set SATA spd for
*
- * Set SATA spd of @ap according to sata_spd_limit.
+ * Set SATA spd of @link according to sata_spd_limit.
*
* LOCKING:
* Inherited from caller.
@@ -2483,18 +2814,18 @@ int sata_set_spd_needed(struct ata_port *ap)
* 0 if spd doesn't need to be changed, 1 if spd has been
* changed. Negative errno if SCR registers are inaccessible.
*/
-int sata_set_spd(struct ata_port *ap)
+int sata_set_spd(struct ata_link *link)
{
u32 scontrol;
int rc;
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
return rc;
- if (!__sata_set_spd_needed(ap, &scontrol))
+ if (!__sata_set_spd_needed(link, &scontrol))
return 0;
- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
return rc;
return 1;
@@ -2549,8 +2880,8 @@ static const struct ata_timing ata_timing[] = {
{ 0xFF }
};
-#define ENOUGH(v,unit) (((v)-1)/(unit)+1)
-#define EZ(v,unit) ((v)?ENOUGH(v,unit):0)
+#define ENOUGH(v, unit) (((v)-1)/(unit)+1)
+#define EZ(v, unit) ((v)?ENOUGH(v, unit):0)
static void ata_timing_quantize(const struct ata_timing *t, struct ata_timing *q, int T, int UT)
{
@@ -2577,7 +2908,7 @@ void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma);
}
-static const struct ata_timing* ata_timing_find_mode(unsigned short speed)
+static const struct ata_timing *ata_timing_find_mode(unsigned short speed)
{
const struct ata_timing *t;
@@ -2609,10 +2940,10 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */
memset(&p, 0, sizeof(p));
- if(speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) {
+ if (speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) {
if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO];
else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY];
- } else if(speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) {
+ } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) {
p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN];
}
ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B);
@@ -2749,7 +3080,7 @@ int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel)
static int ata_dev_set_mode(struct ata_device *dev)
{
- struct ata_eh_context *ehc = &dev->ap->eh_context;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
unsigned int err_mask;
int rc;
@@ -2758,9 +3089,23 @@ static int ata_dev_set_mode(struct ata_device *dev)
dev->flags |= ATA_DFLAG_PIO;
err_mask = ata_dev_set_xfermode(dev);
+
/* Old CFA may refuse this command, which is just fine */
if (dev->xfer_shift == ATA_SHIFT_PIO && ata_id_is_cfa(dev->id))
- err_mask &= ~AC_ERR_DEV;
+ err_mask &= ~AC_ERR_DEV;
+
+ /* Some very old devices and some bad newer ones fail any kind of
+ SET_XFERMODE request but support PIO0-2 timings and no IORDY */
+ if (dev->xfer_shift == ATA_SHIFT_PIO && !ata_id_has_iordy(dev->id) &&
+ dev->pio_mode <= XFER_PIO_2)
+ err_mask &= ~AC_ERR_DEV;
+
+ /* Early MWDMA devices do DMA but don't allow DMA mode setting.
+ Don't fail an MWDMA0 set IFF the device indicates it is in MWDMA0 */
+ if (dev->xfer_shift == ATA_SHIFT_MWDMA &&
+ dev->dma_mode == XFER_MW_DMA_0 &&
+ (dev->id[63] >> 8) & 1)
+ err_mask &= ~AC_ERR_DEV;
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
@@ -2769,7 +3114,7 @@ static int ata_dev_set_mode(struct ata_device *dev)
}
ehc->i.flags |= ATA_EHI_POST_SETMODE;
- rc = ata_dev_revalidate(dev, 0);
+ rc = ata_dev_revalidate(dev, ATA_DEV_UNKNOWN, 0);
ehc->i.flags &= ~ATA_EHI_POST_SETMODE;
if (rc)
return rc;
@@ -2784,7 +3129,7 @@ static int ata_dev_set_mode(struct ata_device *dev)
/**
* ata_do_set_mode - Program timings and issue SET FEATURES - XFER
- * @ap: port on which timings will be programmed
+ * @link: link on which timings will be programmed
* @r_failed_dev: out paramter for failed device
*
* Standard implementation of the function used to tune and set
@@ -2799,25 +3144,36 @@ static int ata_dev_set_mode(struct ata_device *dev)
* 0 on success, negative errno otherwise
*/
-int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
{
+ struct ata_port *ap = link->ap;
struct ata_device *dev;
- int i, rc = 0, used_dma = 0, found = 0;
-
+ int rc = 0, used_dma = 0, found = 0;
/* step 1: calculate xfer_mask */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ ata_link_for_each_dev(dev, link) {
unsigned int pio_mask, dma_mask;
-
- dev = &ap->device[i];
+ unsigned int mode_mask;
if (!ata_dev_enabled(dev))
continue;
+ mode_mask = ATA_DMA_MASK_ATA;
+ if (dev->class == ATA_DEV_ATAPI)
+ mode_mask = ATA_DMA_MASK_ATAPI;
+ else if (ata_id_is_cfa(dev->id))
+ mode_mask = ATA_DMA_MASK_CFA;
+
ata_dev_xfermask(dev);
pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+
+ if (libata_dma_mask & mode_mask)
+ dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+ else
+ dma_mask = 0;
+
dev->pio_mode = ata_xfer_mask2mode(pio_mask);
dev->dma_mode = ata_xfer_mask2mode(dma_mask);
@@ -2829,8 +3185,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
goto out;
/* step 2: always set host PIO timings */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (!ata_dev_enabled(dev))
continue;
@@ -2847,9 +3202,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
}
/* step 3: set host DMA timings */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
+ ata_link_for_each_dev(dev, link) {
if (!ata_dev_enabled(dev) || !dev->dma_mode)
continue;
@@ -2860,9 +3213,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
}
/* step 4: update devices' xfer mode */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
+ ata_link_for_each_dev(dev, link) {
/* don't update suspended devices' xfer mode */
if (!ata_dev_enabled(dev))
continue;
@@ -2886,7 +3237,7 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
/**
* ata_set_mode - Program timings and issue SET FEATURES - XFER
- * @ap: port on which timings will be programmed
+ * @link: link on which timings will be programmed
* @r_failed_dev: out paramter for failed device
*
* Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If
@@ -2899,12 +3250,14 @@ int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
* RETURNS:
* 0 on success, negative errno otherwise
*/
-int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
{
+ struct ata_port *ap = link->ap;
+
/* has private set_mode? */
if (ap->ops->set_mode)
- return ap->ops->set_mode(ap, r_failed_dev);
- return ata_do_set_mode(ap, r_failed_dev);
+ return ap->ops->set_mode(link, r_failed_dev);
+ return ata_do_set_mode(link, r_failed_dev);
}
/**
@@ -2983,6 +3336,61 @@ int ata_busy_sleep(struct ata_port *ap,
}
/**
+ * ata_wait_after_reset - wait before checking status after reset
+ * @ap: port containing status register to be polled
+ * @deadline: deadline jiffies for the operation
+ *
+ * After reset, we need to pause a while before reading status.
+ * Also, certain combination of controller and device report 0xff
+ * for some duration (e.g. until SATA PHY is up and running)
+ * which is interpreted as empty port in ATA world. This
+ * function also waits for such devices to get out of 0xff
+ * status.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_wait_after_reset(struct ata_port *ap, unsigned long deadline)
+{
+ unsigned long until = jiffies + ATA_TMOUT_FF_WAIT;
+
+ if (time_before(until, deadline))
+ deadline = until;
+
+ /* Spec mandates ">= 2ms" before checking status. We wait
+ * 150ms, because that was the magic delay used for ATAPI
+ * devices in Hale Landis's ATADRVR, for the period of time
+ * between when the ATA command register is written, and then
+ * status is checked. Because waiting for "a while" before
+ * checking status is fine, post SRST, we perform this magic
+ * delay here as well.
+ *
+ * Old drivers/ide uses the 2mS rule and then waits for ready.
+ */
+ msleep(150);
+
+ /* Wait for 0xff to clear. Some SATA devices take a long time
+ * to clear 0xff after reset. For example, HHD424020F7SV00
+ * iVDR needs >= 800ms while. Quantum GoVault needs even more
+ * than that.
+ *
+ * Note that some PATA controllers (pata_ali) explode if
+ * status register is read more than once when there's no
+ * device attached.
+ */
+ if (ap->flags & ATA_FLAG_SATA) {
+ while (1) {
+ u8 status = ata_chk_status(ap);
+
+ if (status != 0xff || time_after(jiffies, deadline))
+ return;
+
+ msleep(50);
+ }
+ }
+}
+
+/**
* ata_wait_ready - sleep until BSY clears, or timeout
* @ap: port containing status register to be polled
* @deadline: deadline jiffies for the operation
@@ -3007,7 +3415,7 @@ int ata_wait_ready(struct ata_port *ap, unsigned long deadline)
if (!(status & ATA_BUSY))
return 0;
- if (!ata_port_online(ap) && status == 0xff)
+ if (!ata_link_online(&ap->link) && status == 0xff)
return -ENODEV;
if (time_after(now, deadline))
return -EBUSY;
@@ -3098,23 +3506,14 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
udelay(20); /* FIXME: flush */
iowrite8(ap->ctl, ioaddr->ctl_addr);
- /* spec mandates ">= 2ms" before checking status.
- * We wait 150ms, because that was the magic delay used for
- * ATAPI devices in Hale Landis's ATADRVR, for the period of time
- * between when the ATA command register is written, and then
- * status is checked. Because waiting for "a while" before
- * checking status is fine, post SRST, we perform this magic
- * delay here as well.
- *
- * Old drivers/ide uses the 2mS rule and then waits for ready
- */
- msleep(150);
+ /* wait a while before checking status */
+ ata_wait_after_reset(ap, deadline);
/* Before we perform post reset processing we want to see if
* the bus shows 0xFF because the odd clown forgets the D7
* pulldown resistor.
*/
- if (ata_check_status(ap) == 0xFF)
+ if (ata_chk_status(ap) == 0xFF)
return -ENODEV;
return ata_bus_post_reset(ap, devmask, deadline);
@@ -3142,6 +3541,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
void ata_bus_reset(struct ata_port *ap)
{
+ struct ata_device *device = ap->link.device;
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
u8 err;
@@ -3177,19 +3577,19 @@ void ata_bus_reset(struct ata_port *ap)
/*
* determine by signature whether we have ATA or ATAPI devices
*/
- ap->device[0].class = ata_dev_try_classify(ap, 0, &err);
+ device[0].class = ata_dev_try_classify(&device[0], dev0, &err);
if ((slave_possible) && (err != 0x81))
- ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
+ device[1].class = ata_dev_try_classify(&device[1], dev1, &err);
/* is double-select really necessary? */
- if (ap->device[1].class != ATA_DEV_NONE)
+ if (device[1].class != ATA_DEV_NONE)
ap->ops->dev_select(ap, 1);
- if (ap->device[0].class != ATA_DEV_NONE)
+ if (device[0].class != ATA_DEV_NONE)
ap->ops->dev_select(ap, 0);
/* if no devices were detected, disable this port */
- if ((ap->device[0].class == ATA_DEV_NONE) &&
- (ap->device[1].class == ATA_DEV_NONE))
+ if ((device[0].class == ATA_DEV_NONE) &&
+ (device[1].class == ATA_DEV_NONE))
goto err_out;
if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
@@ -3202,18 +3602,18 @@ void ata_bus_reset(struct ata_port *ap)
err_out:
ata_port_printk(ap, KERN_ERR, "disabling port\n");
- ap->ops->port_disable(ap);
+ ata_port_disable(ap);
DPRINTK("EXIT\n");
}
/**
- * sata_phy_debounce - debounce SATA phy status
- * @ap: ATA port to debounce SATA phy status for
+ * sata_link_debounce - debounce SATA phy status
+ * @link: ATA link to debounce SATA phy status for
* @params: timing parameters { interval, duratinon, timeout } in msec
* @deadline: deadline jiffies for the operation
*
- * Make sure SStatus of @ap reaches stable state, determined by
+* Make sure SStatus of @link reaches stable state, determined by
* holding the same value where DET is not 1 for @duration polled
* every @interval, before @timeout. Timeout constraints the
* beginning of the stable state. Because DET gets stuck at 1 on
@@ -3229,8 +3629,8 @@ err_out:
* RETURNS:
* 0 on success, -errno on failure.
*/
-int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
- unsigned long deadline)
+int sata_link_debounce(struct ata_link *link, const unsigned long *params,
+ unsigned long deadline)
{
unsigned long interval_msec = params[0];
unsigned long duration = msecs_to_jiffies(params[1]);
@@ -3242,7 +3642,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
if (time_before(t, deadline))
deadline = t;
- if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+ if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
return rc;
cur &= 0xf;
@@ -3251,7 +3651,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
while (1) {
msleep(interval_msec);
- if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+ if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
return rc;
cur &= 0xf;
@@ -3277,12 +3677,12 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
}
/**
- * sata_phy_resume - resume SATA phy
- * @ap: ATA port to resume SATA phy for
+ * sata_link_resume - resume SATA link
+ * @link: ATA link to resume SATA
* @params: timing parameters { interval, duratinon, timeout } in msec
* @deadline: deadline jiffies for the operation
*
- * Resume SATA phy of @ap and debounce it.
+ * Resume SATA phy @link and debounce it.
*
* LOCKING:
* Kernel thread context (may sleep)
@@ -3290,18 +3690,18 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
* RETURNS:
* 0 on success, -errno on failure.
*/
-int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
- unsigned long deadline)
+int sata_link_resume(struct ata_link *link, const unsigned long *params,
+ unsigned long deadline)
{
u32 scontrol;
int rc;
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
return rc;
scontrol = (scontrol & 0x0f0) | 0x300;
- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
return rc;
/* Some PHYs react badly if SStatus is pounded immediately
@@ -3309,15 +3709,15 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
*/
msleep(200);
- return sata_phy_debounce(ap, params, deadline);
+ return sata_link_debounce(link, params, deadline);
}
/**
* ata_std_prereset - prepare for reset
- * @ap: ATA port to be reset
+ * @link: ATA link to be reset
* @deadline: deadline jiffies for the operation
*
- * @ap is about to be reset. Initialize it. Failure from
+ * @link is about to be reset. Initialize it. Failure from
* prereset makes libata abort whole reset sequence and give up
* that port, so prereset should be best-effort. It does its
* best to prepare for reset sequence but if things go wrong, it
@@ -3329,37 +3729,44 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
+int ata_std_prereset(struct ata_link *link, unsigned long deadline)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
const unsigned long *timing = sata_ehc_deb_timing(ehc);
int rc;
/* handle link resume */
if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
- (ap->flags & ATA_FLAG_HRST_TO_RESUME))
+ (link->flags & ATA_LFLAG_HRST_TO_RESUME))
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ /* Some PMPs don't work with only SRST, force hardreset if PMP
+ * is supported.
+ */
+ if (ap->flags & ATA_FLAG_PMP)
ehc->i.action |= ATA_EH_HARDRESET;
/* if we're about to do hardreset, nothing more to do */
if (ehc->i.action & ATA_EH_HARDRESET)
return 0;
- /* if SATA, resume phy */
+ /* if SATA, resume link */
if (ap->flags & ATA_FLAG_SATA) {
- rc = sata_phy_resume(ap, timing, deadline);
+ rc = sata_link_resume(link, timing, deadline);
/* whine about phy resume failure but proceed */
if (rc && rc != -EOPNOTSUPP)
- ata_port_printk(ap, KERN_WARNING, "failed to resume "
+ ata_link_printk(link, KERN_WARNING, "failed to resume "
"link for reset (errno=%d)\n", rc);
}
/* Wait for !BSY if the controller can wait for the first D2H
* Reg FIS and we don't know that no device is attached.
*/
- if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) {
+ if (!(link->flags & ATA_LFLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) {
rc = ata_wait_ready(ap, deadline);
if (rc && rc != -ENODEV) {
- ata_port_printk(ap, KERN_WARNING, "device not ready "
+ ata_link_printk(link, KERN_WARNING, "device not ready "
"(errno=%d), forcing hardreset\n", rc);
ehc->i.action |= ATA_EH_HARDRESET;
}
@@ -3370,7 +3777,7 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
/**
* ata_std_softreset - reset host port via ATA SRST
- * @ap: port to reset
+ * @link: ATA link to reset
* @classes: resulting classes of attached devices
* @deadline: deadline jiffies for the operation
*
@@ -3382,9 +3789,10 @@ int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
+int ata_std_softreset(struct ata_link *link, unsigned int *classes,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
unsigned int devmask = 0;
int rc;
@@ -3392,7 +3800,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
DPRINTK("ENTER\n");
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
classes[0] = ATA_DEV_NONE;
goto out;
}
@@ -3410,15 +3818,17 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
DPRINTK("about to softreset, devmask=%x\n", devmask);
rc = ata_bus_softreset(ap, devmask, deadline);
/* if link is occupied, -ENODEV too is an error */
- if (rc && (rc != -ENODEV || sata_scr_valid(ap))) {
- ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc);
+ if (rc && (rc != -ENODEV || sata_scr_valid(link))) {
+ ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc);
return rc;
}
/* determine by signature whether we have ATA or ATAPI devices */
- classes[0] = ata_dev_try_classify(ap, 0, &err);
+ classes[0] = ata_dev_try_classify(&link->device[0],
+ devmask & (1 << 0), &err);
if (slave_possible && err != 0x81)
- classes[1] = ata_dev_try_classify(ap, 1, &err);
+ classes[1] = ata_dev_try_classify(&link->device[1],
+ devmask & (1 << 1), &err);
out:
DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
@@ -3426,12 +3836,12 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
}
/**
- * sata_port_hardreset - reset port via SATA phy reset
- * @ap: port to reset
+ * sata_link_hardreset - reset link via SATA phy reset
+ * @link: link to reset
* @timing: timing parameters { interval, duratinon, timeout } in msec
* @deadline: deadline jiffies for the operation
*
- * SATA phy-reset host port using DET bits of SControl register.
+ * SATA phy-reset @link using DET bits of SControl register.
*
* LOCKING:
* Kernel thread context (may sleep)
@@ -3439,7 +3849,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
+int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
unsigned long deadline)
{
u32 scontrol;
@@ -3447,30 +3857,30 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
DPRINTK("ENTER\n");
- if (sata_set_spd_needed(ap)) {
+ if (sata_set_spd_needed(link)) {
/* SATA spec says nothing about how to reconfigure
* spd. To be on the safe side, turn off phy during
* reconfiguration. This works for at least ICH7 AHCI
* and Sil3124.
*/
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
goto out;
scontrol = (scontrol & 0x0f0) | 0x304;
- if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+ if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
goto out;
- sata_set_spd(ap);
+ sata_set_spd(link);
}
/* issue phy wake/reset */
- if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+ if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
goto out;
scontrol = (scontrol & 0x0f0) | 0x301;
- if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol)))
+ if ((rc = sata_scr_write_flush(link, SCR_CONTROL, scontrol)))
goto out;
/* Couldn't find anything in SATA I/II specs, but AHCI-1.1
@@ -3478,8 +3888,8 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
*/
msleep(1);
- /* bring phy back */
- rc = sata_phy_resume(ap, timing, deadline);
+ /* bring link back */
+ rc = sata_link_resume(link, timing, deadline);
out:
DPRINTK("EXIT, rc=%d\n", rc);
return rc;
@@ -3487,7 +3897,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
/**
* sata_std_hardreset - reset host port via SATA phy reset
- * @ap: port to reset
+ * @link: link to reset
* @class: resulting class of attached device
* @deadline: deadline jiffies for the operation
*
@@ -3500,43 +3910,54 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
+int sata_std_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
- const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
+ struct ata_port *ap = link->ap;
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
int rc;
DPRINTK("ENTER\n");
/* do hardreset */
- rc = sata_port_hardreset(ap, timing, deadline);
+ rc = sata_link_hardreset(link, timing, deadline);
if (rc) {
- ata_port_printk(ap, KERN_ERR,
+ ata_link_printk(link, KERN_ERR,
"COMRESET failed (errno=%d)\n", rc);
return rc;
}
/* TODO: phy layer with polling, timeouts, etc. */
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
*class = ATA_DEV_NONE;
DPRINTK("EXIT, link offline\n");
return 0;
}
- /* wait a while before checking status, see SRST for more info */
- msleep(150);
+ /* wait a while before checking status */
+ ata_wait_after_reset(ap, deadline);
+
+ /* If PMP is supported, we have to do follow-up SRST. Note
+ * that some PMPs don't send D2H Reg FIS after hardreset at
+ * all if the first port is empty. Wait for it just for a
+ * second and request follow-up SRST.
+ */
+ if (ap->flags & ATA_FLAG_PMP) {
+ ata_wait_ready(ap, jiffies + HZ);
+ return -EAGAIN;
+ }
rc = ata_wait_ready(ap, deadline);
/* link occupied, -ENODEV too is an error */
if (rc) {
- ata_port_printk(ap, KERN_ERR,
+ ata_link_printk(link, KERN_ERR,
"COMRESET failed (errno=%d)\n", rc);
return rc;
}
ap->ops->dev_select(ap, 0); /* probably unnecessary */
- *class = ata_dev_try_classify(ap, 0, NULL);
+ *class = ata_dev_try_classify(link->device, 1, NULL);
DPRINTK("EXIT, class=%u\n", *class);
return 0;
@@ -3544,7 +3965,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
/**
* ata_std_postreset - standard postreset callback
- * @ap: the target ata_port
+ * @link: the target ata_link
* @classes: classes of attached devices
*
* This function is invoked after a successful reset. Note that
@@ -3554,18 +3975,19 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
* LOCKING:
* Kernel thread context (may sleep)
*/
-void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
+void ata_std_postreset(struct ata_link *link, unsigned int *classes)
{
+ struct ata_port *ap = link->ap;
u32 serror;
DPRINTK("ENTER\n");
/* print link status */
- sata_print_link_status(ap);
+ sata_print_link_status(link);
/* clear SError */
- if (sata_scr_read(ap, SCR_ERROR, &serror) == 0)
- sata_scr_write(ap, SCR_ERROR, serror);
+ if (sata_scr_read(link, SCR_ERROR, &serror) == 0)
+ sata_scr_write(link, SCR_ERROR, serror);
/* is double-select really necessary? */
if (classes[0] != ATA_DEV_NONE)
@@ -3652,7 +4074,7 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
{
unsigned int class = dev->class;
- u16 *id = (void *)dev->ap->sector_buf;
+ u16 *id = (void *)dev->link->ap->sector_buf;
int rc;
/* read ID data */
@@ -3671,6 +4093,7 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
/**
* ata_dev_revalidate - Revalidate ATA device
* @dev: device to revalidate
+ * @new_class: new class code
* @readid_flags: read ID flags
*
* Re-read IDENTIFY page, make sure @dev is still attached to the
@@ -3682,7 +4105,8 @@ int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
* RETURNS:
* 0 on success, negative errno otherwise
*/
-int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
+int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+ unsigned int readid_flags)
{
u64 n_sectors = dev->n_sectors;
int rc;
@@ -3690,6 +4114,15 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
if (!ata_dev_enabled(dev))
return -ENODEV;
+ /* fail early if !ATA && !ATAPI to avoid issuing [P]IDENTIFY to PMP */
+ if (ata_class_enabled(new_class) &&
+ new_class != ATA_DEV_ATA && new_class != ATA_DEV_ATAPI) {
+ ata_dev_printk(dev, KERN_INFO, "class mismatch %u != %u\n",
+ dev->class, new_class);
+ rc = -ENODEV;
+ goto fail;
+ }
+
/* re-read ID */
rc = ata_dev_reread_id(dev, readid_flags);
if (rc)
@@ -3758,11 +4191,11 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "SAMSUNG CD-ROM SC", NULL, ATA_HORKAGE_NODMA },
{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL,ATA_HORKAGE_NODMA },
{ "_NEC DV5800A", NULL, ATA_HORKAGE_NODMA },
- { "SAMSUNG CD-ROM SN-124","N001", ATA_HORKAGE_NODMA },
+ { "SAMSUNG CD-ROM SN-124", "N001", ATA_HORKAGE_NODMA },
{ "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA },
- { "IOMEGA ZIP 250 ATAPI", NULL, ATA_HORKAGE_NODMA }, /* temporary fix */
- { "IOMEGA ZIP 250 ATAPI Floppy",
- NULL, ATA_HORKAGE_NODMA },
+ /* Odd clown on sil3726/4726 PMPs */
+ { "Config Disk", NULL, ATA_HORKAGE_NODMA |
+ ATA_HORKAGE_SKIP_PM },
/* Weird ATAPI devices */
{ "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 },
@@ -3771,20 +4204,16 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Devices where NCQ should be avoided */
/* NCQ is slow */
- { "WDC WD740ADFD-00", NULL, ATA_HORKAGE_NONCQ },
+ { "WDC WD740ADFD-00", NULL, ATA_HORKAGE_NONCQ },
/* http://thread.gmane.org/gmane.linux.ide/14907 */
{ "FUJITSU MHT2060BH", NULL, ATA_HORKAGE_NONCQ },
/* NCQ is broken */
- { "Maxtor 6L250S0", "BANC1G10", ATA_HORKAGE_NONCQ },
- { "Maxtor 6B200M0", "BANC1BM0", ATA_HORKAGE_NONCQ },
- { "Maxtor 6B200M0", "BANC1B10", ATA_HORKAGE_NONCQ },
- { "Maxtor 7B250S0", "BANC1B70", ATA_HORKAGE_NONCQ, },
- { "Maxtor 7B300S0", "BANC1B70", ATA_HORKAGE_NONCQ },
+ { "Maxtor *", "BANC*", ATA_HORKAGE_NONCQ },
{ "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ },
- { "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI",
- ATA_HORKAGE_NONCQ },
- /* NCQ hard hangs device under heavier load, needs hard power cycle */
- { "Maxtor 6B250S0", "BANC1B70", ATA_HORKAGE_NONCQ },
+ { "HITACHI HDS7250SASUN500G*", NULL, ATA_HORKAGE_NONCQ },
+ { "HITACHI HDS7225SBSUN250G*", NULL, ATA_HORKAGE_NONCQ },
+ { "ST380817AS", "3.42", ATA_HORKAGE_NONCQ },
+
/* Blacklist entries taken from Silicon Image 3124/3132
Windows driver .inf file - also several Linux problem reports */
{ "HTS541060G9SA00", "MB3OC60D", ATA_HORKAGE_NONCQ, },
@@ -3793,12 +4222,20 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Drives which do spurious command completion */
{ "HTS541680J9SA00", "SB2IC7EP", ATA_HORKAGE_NONCQ, },
{ "HTS541612J9SA00", "SBDIC7JP", ATA_HORKAGE_NONCQ, },
+ { "HDT722516DLA380", "V43OA96A", ATA_HORKAGE_NONCQ, },
{ "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, },
+ { "Hitachi HTS542525K9SA00", "BBFOC31P", ATA_HORKAGE_NONCQ, },
{ "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, },
+ { "WDC WD3200AAJS-00RYA0", "12.01B01", ATA_HORKAGE_NONCQ, },
{ "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, },
+ { "ST9120822AS", "3.CLF", ATA_HORKAGE_NONCQ, },
{ "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, },
- { "ST3160812AS", "3.AD", ATA_HORKAGE_NONCQ, },
+ { "ST9160821AS", "3.ALD", ATA_HORKAGE_NONCQ, },
+ { "ST9160821AS", "3.CCD", ATA_HORKAGE_NONCQ, },
+ { "ST3160812AS", "3.ADJ", ATA_HORKAGE_NONCQ, },
+ { "ST980813AS", "3.ADB", ATA_HORKAGE_NONCQ, },
{ "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, },
+ { "Maxtor 7V300F0", "VA111900", ATA_HORKAGE_NONCQ, },
/* devices which puke on READ_NATIVE_MAX */
{ "HDS724040KLSA80", "KFAOA20N", ATA_HORKAGE_BROKEN_HPA, },
@@ -3806,10 +4243,41 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA },
{ "MAXTOR 6L080L4", "A93.0500", ATA_HORKAGE_BROKEN_HPA },
+ /* Devices which report 1 sector over size HPA */
+ { "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, },
+ { "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, },
+
+ /* Devices which get the IVB wrong */
+ { "QUANTUM FIREBALLlct10 05", "A03.0900", ATA_HORKAGE_IVB, },
+ { "TSSTcorp CDDVDW SH-S202J", "SB00", ATA_HORKAGE_IVB, },
+
/* End Marker */
{ }
};
+static int strn_pattern_cmp(const char *patt, const char *name, int wildchar)
+{
+ const char *p;
+ int len;
+
+ /*
+ * check for trailing wildcard: *\0
+ */
+ p = strchr(patt, wildchar);
+ if (p && ((*(p + 1)) == 0))
+ len = p - patt;
+ else {
+ len = strlen(name);
+ if (!len) {
+ if (!*patt)
+ return 0;
+ return -1;
+ }
+ }
+
+ return strncmp(patt, name, len);
+}
+
static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
{
unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -3820,10 +4288,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev));
while (ad->model_num) {
- if (!strcmp(ad->model_num, model_num)) {
+ if (!strn_pattern_cmp(ad->model_num, model_num, '*')) {
if (ad->model_rev == NULL)
return ad->horkage;
- if (!strcmp(ad->model_rev, model_rev))
+ if (!strn_pattern_cmp(ad->model_rev, model_rev, '*'))
return ad->horkage;
}
ad++;
@@ -3837,13 +4305,28 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
* DMA blacklist those ATAPI devices with CDB-intr (and use PIO)
* if the LLDD handles only interrupts in the HSM_ST_LAST state.
*/
- if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) &&
+ if ((dev->link->ap->flags & ATA_FLAG_PIO_POLLING) &&
(dev->flags & ATA_DFLAG_CDB_INTR))
return 1;
return (dev->horkage & ATA_HORKAGE_NODMA) ? 1 : 0;
}
/**
+ * ata_is_40wire - check drive side detection
+ * @dev: device
+ *
+ * Perform drive side detection decoding, allowing for device vendors
+ * who can't follow the documentation.
+ */
+
+static int ata_is_40wire(struct ata_device *dev)
+{
+ if (dev->horkage & ATA_HORKAGE_IVB)
+ return ata_drive_40wire_relaxed(dev->id);
+ return ata_drive_40wire(dev->id);
+}
+
+/**
* ata_dev_xfermask - Compute supported xfermask of the given device
* @dev: Device to compute xfermask for
*
@@ -3857,7 +4340,8 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
*/
static void ata_dev_xfermask(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
struct ata_host *host = ap->host;
unsigned long xfer_mask;
@@ -3888,7 +4372,7 @@ static void ata_dev_xfermask(struct ata_device *dev)
}
if ((host->flags & ATA_HOST_SIMPLEX) &&
- host->simplex_claimed && host->simplex_claimed != ap) {
+ host->simplex_claimed && host->simplex_claimed != ap) {
xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
ata_dev_printk(dev, KERN_WARNING, "simplex DMA is claimed by "
"other device, disabling DMA\n");
@@ -3910,11 +4394,11 @@ static void ata_dev_xfermask(struct ata_device *dev)
*/
if (xfer_mask & (0xF8 << ATA_SHIFT_UDMA))
/* UDMA/44 or higher would be available */
- if((ap->cbl == ATA_CBL_PATA40) ||
- (ata_drive_40wire(dev->id) &&
- (ap->cbl == ATA_CBL_PATA_UNK ||
- ap->cbl == ATA_CBL_PATA80))) {
- ata_dev_printk(dev, KERN_WARNING,
+ if ((ap->cbl == ATA_CBL_PATA40) ||
+ (ata_is_40wire(dev) &&
+ (ap->cbl == ATA_CBL_PATA_UNK ||
+ ap->cbl == ATA_CBL_PATA80))) {
+ ata_dev_printk(dev, KERN_WARNING,
"limited to UDMA/33 due to 40-wire cable\n");
xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
}
@@ -3955,7 +4439,43 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
tf.protocol = ATA_PROT_NODATA;
tf.nsect = dev->xfer_mode;
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+
+ DPRINTK("EXIT, err_mask=%x\n", err_mask);
+ return err_mask;
+}
+/**
+ * ata_dev_set_feature - Issue SET FEATURES - SATA FEATURES
+ * @dev: Device to which command will be sent
+ * @enable: Whether to enable or disable the feature
+ * @feature: The sector count represents the feature to set
+ *
+ * Issue SET FEATURES - SATA FEATURES command to device @dev
+ * on port @ap with sector count
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask otherwise.
+ */
+static unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable,
+ u8 feature)
+{
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ /* set up set-features taskfile */
+ DPRINTK("set features - SATA features\n");
+
+ ata_tf_init(dev, &tf);
+ tf.command = ATA_CMD_SET_FEATURES;
+ tf.feature = enable;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.nsect = feature;
+
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
@@ -3993,7 +4513,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
tf.nsect = sectors;
tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
- err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
/* A clean abort indicates an original or just out of spec drive
and we should continue as we issue the setup based on the
drive reported working geometry */
@@ -4039,10 +4559,10 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
if (qc->n_elem)
dma_unmap_sg(ap->dev, sg, qc->n_elem, dir);
/* restore last sg */
- sg[qc->orig_n_elem - 1].length += qc->pad_len;
+ sg_last(sg, qc->orig_n_elem)->length += qc->pad_len;
if (pad_buf) {
struct scatterlist *psg = &qc->pad_sgent;
- void *addr = kmap_atomic(psg->page, KM_IRQ0);
+ void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
memcpy(addr + psg->offset, pad_buf, qc->pad_len);
kunmap_atomic(addr, KM_IRQ0);
}
@@ -4141,7 +4661,7 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc)
u32 addr, offset;
u32 sg_len, len, blen;
- /* determine if physical DMA addr spans 64K boundary.
+ /* determine if physical DMA addr spans 64K boundary.
* Note h/w doesn't support 64-bit, so we unconditionally
* truncate dma_addr_t to u32.
*/
@@ -4207,6 +4727,36 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc)
}
/**
+ * ata_std_qc_defer - Check whether a qc needs to be deferred
+ * @qc: ATA command in question
+ *
+ * Non-NCQ commands cannot run with any other command, NCQ or
+ * not. As upper layer only knows the queue depth, we are
+ * responsible for maintaining exclusion. This function checks
+ * whether a new command @qc can be issued.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int ata_std_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_link *link = qc->dev->link;
+
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
+ if (!ata_tag_valid(link->active_tag))
+ return 0;
+ } else {
+ if (!ata_tag_valid(link->active_tag) && !link->sactive)
+ return 0;
+ }
+
+ return ATA_DEFER_LINK;
+}
+
+/**
* ata_qc_prep - Prepare taskfile for submission
* @qc: Metadata associated with taskfile to be prepared
*
@@ -4264,6 +4814,7 @@ void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
qc->orig_n_elem = 1;
qc->buf_virt = buf;
qc->nbytes = buflen;
+ qc->cursg = qc->__sg;
sg_init_one(&qc->sgent, buf, buflen);
}
@@ -4289,6 +4840,7 @@ void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
qc->__sg = sg;
qc->n_elem = n_elem;
qc->orig_n_elem = n_elem;
+ qc->cursg = qc->__sg;
}
/**
@@ -4378,7 +4930,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct scatterlist *sg = qc->__sg;
- struct scatterlist *lsg = &sg[qc->n_elem - 1];
+ struct scatterlist *lsg = sg_last(qc->__sg, qc->n_elem);
int n_elem, pre_n_elem, dir, trim_sg = 0;
VPRINTK("ENTER, ata%u\n", ap->print_id);
@@ -4400,11 +4952,12 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
* data in this function or read data in ata_sg_clean.
*/
offset = lsg->offset + lsg->length - qc->pad_len;
- psg->page = nth_page(lsg->page, offset >> PAGE_SHIFT);
- psg->offset = offset_in_page(offset);
+ sg_init_table(psg, 1);
+ sg_set_page(psg, nth_page(sg_page(lsg), offset >> PAGE_SHIFT),
+ qc->pad_len, offset_in_page(offset));
if (qc->tf.flags & ATA_TFLAG_WRITE) {
- void *addr = kmap_atomic(psg->page, KM_IRQ0);
+ void *addr = kmap_atomic(sg_page(psg), KM_IRQ0);
memcpy(pad_buf, addr + psg->offset, qc->pad_len);
kunmap_atomic(addr, KM_IRQ0);
}
@@ -4482,7 +5035,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
unsigned int words = buflen >> 1;
/* Transfer multiple of 2 bytes */
@@ -4542,7 +5095,6 @@ void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
static void ata_pio_sector(struct ata_queued_cmd *qc)
{
int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
- struct scatterlist *sg = qc->__sg;
struct ata_port *ap = qc->ap;
struct page *page;
unsigned int offset;
@@ -4551,8 +5103,8 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
if (qc->curbytes == qc->nbytes - qc->sect_size)
ap->hsm_task_state = HSM_ST_LAST;
- page = sg[qc->cursg].page;
- offset = sg[qc->cursg].offset + qc->cursg_ofs;
+ page = sg_page(qc->cursg);
+ offset = qc->cursg->offset + qc->cursg_ofs;
/* get the current page and offset */
page = nth_page(page, (offset >> PAGE_SHIFT));
@@ -4580,8 +5132,8 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
qc->curbytes += qc->sect_size;
qc->cursg_ofs += qc->sect_size;
- if (qc->cursg_ofs == (&sg[qc->cursg])->length) {
- qc->cursg++;
+ if (qc->cursg_ofs == qc->cursg->length) {
+ qc->cursg = sg_next(qc->cursg);
qc->cursg_ofs = 0;
}
}
@@ -4611,6 +5163,8 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
ata_pio_sector(qc);
} else
ata_pio_sector(qc);
+
+ ata_altstatus(qc->ap); /* flush */
}
/**
@@ -4665,16 +5219,18 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
{
int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
struct scatterlist *sg = qc->__sg;
+ struct scatterlist *lsg = sg_last(qc->__sg, qc->n_elem);
struct ata_port *ap = qc->ap;
struct page *page;
unsigned char *buf;
unsigned int offset, count;
+ int no_more_sg = 0;
if (qc->curbytes + bytes >= qc->nbytes)
ap->hsm_task_state = HSM_ST_LAST;
next_sg:
- if (unlikely(qc->cursg >= qc->n_elem)) {
+ if (unlikely(no_more_sg)) {
/*
* The end of qc->sg is reached and the device expects
* more data to transfer. In order not to overrun qc->sg
@@ -4691,15 +5247,15 @@ next_sg:
"%u bytes trailing data\n", bytes);
for (i = 0; i < words; i++)
- ap->ops->data_xfer(qc->dev, (unsigned char*)pad_buf, 2, do_write);
+ ap->ops->data_xfer(qc->dev, (unsigned char *)pad_buf, 2, do_write);
ap->hsm_task_state = HSM_ST_LAST;
return;
}
- sg = &qc->__sg[qc->cursg];
+ sg = qc->cursg;
- page = sg->page;
+ page = sg_page(sg);
offset = sg->offset + qc->cursg_ofs;
/* get the current page and offset */
@@ -4736,7 +5292,10 @@ next_sg:
qc->cursg_ofs += count;
if (qc->cursg_ofs == sg->length) {
- qc->cursg++;
+ if (qc->cursg == lsg)
+ no_more_sg = 1;
+
+ qc->cursg = sg_next(qc->cursg);
qc->cursg_ofs = 0;
}
@@ -4785,6 +5344,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes);
__atapi_pio_bytes(qc, bytes);
+ ata_altstatus(ap); /* flush */
return;
@@ -4956,7 +5516,6 @@ fsm_start:
*/
ap->hsm_task_state = HSM_ST;
ata_pio_sectors(qc);
- ata_altstatus(ap); /* flush */
} else
/* send CDB */
atapi_send_cdb(ap, qc);
@@ -5037,7 +5596,6 @@ fsm_start:
if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
ata_pio_sectors(qc);
- ata_altstatus(ap);
status = ata_wait_idle(ap);
}
@@ -5057,13 +5615,11 @@ fsm_start:
if (ap->hsm_task_state == HSM_ST_LAST &&
(!(qc->tf.flags & ATA_TFLAG_WRITE))) {
/* all data read */
- ata_altstatus(ap);
status = ata_wait_idle(ap);
goto fsm_start;
}
}
- ata_altstatus(ap); /* flush */
poll_next = 1;
break;
@@ -5188,7 +5744,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
struct ata_queued_cmd *qc;
qc = ata_qc_new(ap);
@@ -5231,6 +5787,7 @@ void ata_qc_free(struct ata_queued_cmd *qc)
void __ata_qc_complete(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ struct ata_link *link = qc->dev->link;
WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
@@ -5239,10 +5796,19 @@ void __ata_qc_complete(struct ata_queued_cmd *qc)
ata_sg_clean(qc);
/* command should be marked inactive atomically with qc completion */
- if (qc->tf.protocol == ATA_PROT_NCQ)
- ap->sactive &= ~(1 << qc->tag);
- else
- ap->active_tag = ATA_TAG_POISON;
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
+ link->sactive &= ~(1 << qc->tag);
+ if (!link->sactive)
+ ap->nr_active_links--;
+ } else {
+ link->active_tag = ATA_TAG_POISON;
+ ap->nr_active_links--;
+ }
+
+ /* clear exclusive status */
+ if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL &&
+ ap->excl_link == link))
+ ap->excl_link = NULL;
/* atapi: mark qc as inactive to prevent the interrupt handler
* from completing the command twice later, before the error handler
@@ -5292,6 +5858,9 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
* taken care of.
*/
if (ap->ops->error_handler) {
+ struct ata_device *dev = qc->dev;
+ struct ata_eh_info *ehi = &dev->link->eh_info;
+
WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
if (unlikely(qc->err_mask))
@@ -5310,6 +5879,27 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
if (qc->flags & ATA_QCFLAG_RESULT_TF)
fill_result_tf(qc);
+ /* Some commands need post-processing after successful
+ * completion.
+ */
+ switch (qc->tf.command) {
+ case ATA_CMD_SET_FEATURES:
+ if (qc->tf.feature != SETFEATURES_WC_ON &&
+ qc->tf.feature != SETFEATURES_WC_OFF)
+ break;
+ /* fall through */
+ case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */
+ case ATA_CMD_SET_MULTI: /* multi_count changed */
+ /* revalidate device */
+ ehi->dev_action[dev->devno] |= ATA_EH_REVALIDATE;
+ ata_port_schedule_eh(ap);
+ break;
+
+ case ATA_CMD_SLEEP:
+ dev->flags |= ATA_DFLAG_SLEEPING;
+ break;
+ }
+
__ata_qc_complete(qc);
} else {
if (qc->flags & ATA_QCFLAG_EH_SCHEDULED)
@@ -5411,19 +6001,25 @@ static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
void ata_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ struct ata_link *link = qc->dev->link;
/* Make sure only one non-NCQ command is outstanding. The
* check is skipped for old EH because it reuses active qc to
* request ATAPI sense.
*/
- WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag));
+ WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag));
if (qc->tf.protocol == ATA_PROT_NCQ) {
- WARN_ON(ap->sactive & (1 << qc->tag));
- ap->sactive |= 1 << qc->tag;
+ WARN_ON(link->sactive & (1 << qc->tag));
+
+ if (!link->sactive)
+ ap->nr_active_links++;
+ link->sactive |= 1 << qc->tag;
} else {
- WARN_ON(ap->sactive);
- ap->active_tag = qc->tag;
+ WARN_ON(link->sactive);
+
+ ap->nr_active_links++;
+ link->active_tag = qc->tag;
}
qc->flags |= ATA_QCFLAG_ACTIVE;
@@ -5441,6 +6037,14 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
qc->flags &= ~ATA_QCFLAG_DMAMAP;
}
+ /* if device is sleeping, schedule softreset and abort the link */
+ if (unlikely(qc->dev->flags & ATA_DFLAG_SLEEPING)) {
+ link->eh_info.action |= ATA_EH_SOFTRESET;
+ ata_ehi_push_desc(&link->eh_info, "waking up from sleep");
+ ata_link_abort(link);
+ return;
+ }
+
ap->ops->qc_prep(qc);
qc->err_mask |= ap->ops->qc_issue(qc);
@@ -5603,10 +6207,10 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
* One if interrupt was handled, zero if not (shared irq).
*/
-inline unsigned int ata_host_intr (struct ata_port *ap,
- struct ata_queued_cmd *qc)
+inline unsigned int ata_host_intr(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
{
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
u8 status, host_stat = 0;
VPRINTK("ata%u: protocol %d task_state %d\n",
@@ -5680,7 +6284,8 @@ idle_irq:
#ifdef ATA_IRQ_TRAP
if ((ap->stats.idle_irq % 1000) == 0) {
- ap->ops->irq_ack(ap, 0); /* debug trap */
+ ata_chk_status(ap);
+ ap->ops->irq_clear(ap);
ata_port_printk(ap, KERN_WARNING, "irq trap\n");
return 1;
}
@@ -5703,7 +6308,7 @@ idle_irq:
* IRQ_NONE or IRQ_HANDLED.
*/
-irqreturn_t ata_interrupt (int irq, void *dev_instance)
+irqreturn_t ata_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
unsigned int i;
@@ -5721,7 +6326,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance)
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
(qc->flags & ATA_QCFLAG_ACTIVE))
handled |= ata_host_intr(ap, qc);
@@ -5735,9 +6340,9 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance)
/**
* sata_scr_valid - test whether SCRs are accessible
- * @ap: ATA port to test SCR accessibility for
+ * @link: ATA link to test SCR accessibility for
*
- * Test whether SCRs are accessible for @ap.
+ * Test whether SCRs are accessible for @link.
*
* LOCKING:
* None.
@@ -5745,60 +6350,74 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance)
* RETURNS:
* 1 if SCRs are accessible, 0 otherwise.
*/
-int sata_scr_valid(struct ata_port *ap)
+int sata_scr_valid(struct ata_link *link)
{
+ struct ata_port *ap = link->ap;
+
return (ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read;
}
/**
* sata_scr_read - read SCR register of the specified port
- * @ap: ATA port to read SCR for
+ * @link: ATA link to read SCR for
* @reg: SCR to read
* @val: Place to store read value
*
- * Read SCR register @reg of @ap into *@val. This function is
- * guaranteed to succeed if the cable type of the port is SATA
- * and the port implements ->scr_read.
+ * Read SCR register @reg of @link into *@val. This function is
+ * guaranteed to succeed if @link is ap->link, the cable type of
+ * the port is SATA and the port implements ->scr_read.
*
* LOCKING:
- * None.
+ * None if @link is ap->link. Kernel thread context otherwise.
*
* RETURNS:
* 0 on success, negative errno on failure.
*/
-int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
+int sata_scr_read(struct ata_link *link, int reg, u32 *val)
{
- if (sata_scr_valid(ap))
- return ap->ops->scr_read(ap, reg, val);
- return -EOPNOTSUPP;
+ if (ata_is_host_link(link)) {
+ struct ata_port *ap = link->ap;
+
+ if (sata_scr_valid(link))
+ return ap->ops->scr_read(ap, reg, val);
+ return -EOPNOTSUPP;
+ }
+
+ return sata_pmp_scr_read(link, reg, val);
}
/**
* sata_scr_write - write SCR register of the specified port
- * @ap: ATA port to write SCR for
+ * @link: ATA link to write SCR for
* @reg: SCR to write
* @val: value to write
*
- * Write @val to SCR register @reg of @ap. This function is
- * guaranteed to succeed if the cable type of the port is SATA
- * and the port implements ->scr_read.
+ * Write @val to SCR register @reg of @link. This function is
+ * guaranteed to succeed if @link is ap->link, the cable type of
+ * the port is SATA and the port implements ->scr_read.
*
* LOCKING:
- * None.
+ * None if @link is ap->link. Kernel thread context otherwise.
*
* RETURNS:
* 0 on success, negative errno on failure.
*/
-int sata_scr_write(struct ata_port *ap, int reg, u32 val)
+int sata_scr_write(struct ata_link *link, int reg, u32 val)
{
- if (sata_scr_valid(ap))
- return ap->ops->scr_write(ap, reg, val);
- return -EOPNOTSUPP;
+ if (ata_is_host_link(link)) {
+ struct ata_port *ap = link->ap;
+
+ if (sata_scr_valid(link))
+ return ap->ops->scr_write(ap, reg, val);
+ return -EOPNOTSUPP;
+ }
+
+ return sata_pmp_scr_write(link, reg, val);
}
/**
* sata_scr_write_flush - write SCR register of the specified port and flush
- * @ap: ATA port to write SCR for
+ * @link: ATA link to write SCR for
* @reg: SCR to write
* @val: value to write
*
@@ -5806,31 +6425,36 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val)
* function performs flush after writing to the register.
*
* LOCKING:
- * None.
+ * None if @link is ap->link. Kernel thread context otherwise.
*
* RETURNS:
* 0 on success, negative errno on failure.
*/
-int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
+int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
{
- int rc;
+ if (ata_is_host_link(link)) {
+ struct ata_port *ap = link->ap;
+ int rc;
- if (sata_scr_valid(ap)) {
- rc = ap->ops->scr_write(ap, reg, val);
- if (rc == 0)
- rc = ap->ops->scr_read(ap, reg, &val);
- return rc;
+ if (sata_scr_valid(link)) {
+ rc = ap->ops->scr_write(ap, reg, val);
+ if (rc == 0)
+ rc = ap->ops->scr_read(ap, reg, &val);
+ return rc;
+ }
+ return -EOPNOTSUPP;
}
- return -EOPNOTSUPP;
+
+ return sata_pmp_scr_write(link, reg, val);
}
/**
- * ata_port_online - test whether the given port is online
- * @ap: ATA port to test
+ * ata_link_online - test whether the given link is online
+ * @link: ATA link to test
*
- * Test whether @ap is online. Note that this function returns 0
- * if online status of @ap cannot be obtained, so
- * ata_port_online(ap) != !ata_port_offline(ap).
+ * Test whether @link is online. Note that this function returns
+ * 0 if online status of @link cannot be obtained, so
+ * ata_link_online(link) != !ata_link_offline(link).
*
* LOCKING:
* None.
@@ -5838,22 +6462,23 @@ int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
* RETURNS:
* 1 if the port online status is available and online.
*/
-int ata_port_online(struct ata_port *ap)
+int ata_link_online(struct ata_link *link)
{
u32 sstatus;
- if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3)
+ if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
+ (sstatus & 0xf) == 0x3)
return 1;
return 0;
}
/**
- * ata_port_offline - test whether the given port is offline
- * @ap: ATA port to test
+ * ata_link_offline - test whether the given link is offline
+ * @link: ATA link to test
*
- * Test whether @ap is offline. Note that this function returns
- * 0 if offline status of @ap cannot be obtained, so
- * ata_port_online(ap) != !ata_port_offline(ap).
+ * Test whether @link is offline. Note that this function
+ * returns 0 if offline status of @link cannot be obtained, so
+ * ata_link_online(link) != !ata_link_offline(link).
*
* LOCKING:
* None.
@@ -5861,11 +6486,12 @@ int ata_port_online(struct ata_port *ap)
* RETURNS:
* 1 if the port offline status is available and offline.
*/
-int ata_port_offline(struct ata_port *ap)
+int ata_link_offline(struct ata_link *link)
{
u32 sstatus;
- if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
+ if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
+ (sstatus & 0xf) != 0x3)
return 1;
return 0;
}
@@ -5883,6 +6509,10 @@ int ata_flush_cache(struct ata_device *dev)
else
cmd = ATA_CMD_FLUSH;
+ /* This is wrong. On a failed flush we get back the LBA of the lost
+ sector and we should (assuming it wasn't aborted as unknown) issue
+ a further flush command to continue the writeback until it
+ does not error */
err_mask = ata_do_simple_cmd(dev, cmd);
if (err_mask) {
ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n");
@@ -5902,6 +6532,7 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
+ struct ata_link *link;
/* Previous resume operation might still be in
* progress. Wait for PM_PENDING to clear.
@@ -5921,8 +6552,10 @@ static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
}
ap->pflags |= ATA_PFLAG_PM_PENDING;
- ap->eh_info.action |= action;
- ap->eh_info.flags |= ehi_flags;
+ __ata_port_for_each_link(link, ap) {
+ link->eh_info.action |= action;
+ link->eh_info.flags |= ehi_flags;
+ }
ata_port_schedule_eh(ap);
@@ -5959,6 +6592,12 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
{
int rc;
+ /*
+ * disable link pm on all ports before requesting
+ * any pm activity
+ */
+ ata_lpm_enable(host);
+
rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1);
if (rc == 0)
host->dev->power.power_state = mesg;
@@ -5981,6 +6620,9 @@ void ata_host_resume(struct ata_host *host)
ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET,
ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
host->dev->power.power_state = PMSG_ON;
+
+ /* reenable link pm */
+ ata_lpm_disable(host);
}
#endif
@@ -6026,12 +6668,13 @@ int ata_port_start(struct ata_port *ap)
*/
void ata_dev_init(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
unsigned long flags;
/* SATA spd limit is bound to the first device */
- ap->sata_spd_limit = ap->hw_sata_spd_limit;
- ap->sata_spd = 0;
+ link->sata_spd_limit = link->hw_sata_spd_limit;
+ link->sata_spd = 0;
/* High bits of dev->flags are used to record warm plug
* requests which occur asynchronously. Synchronize using
@@ -6050,6 +6693,70 @@ void ata_dev_init(struct ata_device *dev)
}
/**
+ * ata_link_init - Initialize an ata_link structure
+ * @ap: ATA port link is attached to
+ * @link: Link structure to initialize
+ * @pmp: Port multiplier port number
+ *
+ * Initialize @link.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
+{
+ int i;
+
+ /* clear everything except for devices */
+ memset(link, 0, offsetof(struct ata_link, device[0]));
+
+ link->ap = ap;
+ link->pmp = pmp;
+ link->active_tag = ATA_TAG_POISON;
+ link->hw_sata_spd_limit = UINT_MAX;
+
+ /* can't use iterator, ap isn't initialized yet */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &link->device[i];
+
+ dev->link = link;
+ dev->devno = dev - link->device;
+ ata_dev_init(dev);
+ }
+}
+
+/**
+ * sata_link_init_spd - Initialize link->sata_spd_limit
+ * @link: Link to configure sata_spd_limit for
+ *
+ * Initialize @link->[hw_]sata_spd_limit to the currently
+ * configured value.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_link_init_spd(struct ata_link *link)
+{
+ u32 scontrol, spd;
+ int rc;
+
+ rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
+ if (rc)
+ return rc;
+
+ spd = (scontrol >> 4) & 0xf;
+ if (spd)
+ link->hw_sata_spd_limit &= (1 << spd) - 1;
+
+ link->sata_spd_limit = link->hw_sata_spd_limit;
+
+ return 0;
+}
+
+/**
* ata_port_alloc - allocate and initialize basic ATA port resources
* @host: ATA host this allocated port belongs to
*
@@ -6064,7 +6771,6 @@ void ata_dev_init(struct ata_device *dev)
struct ata_port *ata_port_alloc(struct ata_host *host)
{
struct ata_port *ap;
- unsigned int i;
DPRINTK("ENTER\n");
@@ -6079,9 +6785,6 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
ap->ctl = ATA_DEVCTL_OBS;
ap->host = host;
ap->dev = host->dev;
-
- ap->hw_sata_spd_limit = UINT_MAX;
- ap->active_tag = ATA_TAG_POISON;
ap->last_ctl = 0xFF;
#if defined(ATA_VERBOSE_DEBUG)
@@ -6104,12 +6807,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
ap->cbl = ATA_CBL_NONE;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- dev->ap = ap;
- dev->devno = i;
- ata_dev_init(dev);
- }
+ ata_link_init(ap, &ap->link, 0);
#ifdef ATA_IRQ_TRAP
ap->stats.unhandled_irq = 1;
@@ -6129,22 +6827,10 @@ static void ata_host_release(struct device *gendev, void *res)
if (!ap)
continue;
- if ((host->flags & ATA_HOST_STARTED) && ap->ops->port_stop)
- ap->ops->port_stop(ap);
- }
-
- if ((host->flags & ATA_HOST_STARTED) && host->ops->host_stop)
- host->ops->host_stop(host);
-
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
-
- if (!ap)
- continue;
-
if (ap->scsi_host)
scsi_host_put(ap->scsi_host);
+ kfree(ap->pmp_link);
kfree(ap);
host->ports[i] = NULL;
}
@@ -6255,6 +6941,7 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
ap->mwdma_mask = pi->mwdma_mask;
ap->udma_mask = pi->udma_mask;
ap->flags |= pi->flags;
+ ap->link.flags |= pi->link_flags;
ap->ops = pi->port_ops;
if (!host->ops && (pi->port_ops != &ata_dummy_port_ops))
@@ -6266,6 +6953,24 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
return host;
}
+static void ata_host_stop(struct device *gendev, void *res)
+{
+ struct ata_host *host = dev_get_drvdata(gendev);
+ int i;
+
+ WARN_ON(!(host->flags & ATA_HOST_STARTED));
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (ap->ops->port_stop)
+ ap->ops->port_stop(ap);
+ }
+
+ if (host->ops->host_stop)
+ host->ops->host_stop(host);
+}
+
/**
* ata_host_start - start and freeze ports of an ATA host
* @host: ATA host to start ports for
@@ -6284,6 +6989,8 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
*/
int ata_host_start(struct ata_host *host)
{
+ int have_stop = 0;
+ void *start_dr = NULL;
int i, rc;
if (host->flags & ATA_HOST_STARTED)
@@ -6295,6 +7002,22 @@ int ata_host_start(struct ata_host *host)
if (!host->ops && !ata_port_is_dummy(ap))
host->ops = ap->ops;
+ if (ap->ops->port_stop)
+ have_stop = 1;
+ }
+
+ if (host->ops->host_stop)
+ have_stop = 1;
+
+ if (have_stop) {
+ start_dr = devres_alloc(ata_host_stop, 0, GFP_KERNEL);
+ if (!start_dr)
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
if (ap->ops->port_start) {
rc = ap->ops->port_start(ap);
if (rc) {
@@ -6307,6 +7030,8 @@ int ata_host_start(struct ata_host *host)
ata_eh_freeze_port(ap);
}
+ if (start_dr)
+ devres_add(host->dev, start_dr);
host->flags |= ATA_HOST_STARTED;
return 0;
@@ -6317,6 +7042,7 @@ int ata_host_start(struct ata_host *host)
if (ap->ops->port_stop)
ap->ops->port_stop(ap);
}
+ devres_free(start_dr);
return rc;
}
@@ -6390,8 +7116,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
/* set cable, sata_spd_limit and report */
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- int irq_line;
- u32 scontrol;
unsigned long xfer_mask;
/* set SATA cable type if still unset */
@@ -6399,32 +7123,20 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
ap->cbl = ATA_CBL_SATA;
/* init sata_spd_limit to the current value */
- if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
- int spd = (scontrol >> 4) & 0xf;
- if (spd)
- ap->hw_sata_spd_limit &= (1 << spd) - 1;
- }
- ap->sata_spd_limit = ap->hw_sata_spd_limit;
-
- /* report the secondary IRQ for second channel legacy */
- irq_line = host->irq;
- if (i == 1 && host->irq2)
- irq_line = host->irq2;
+ sata_link_init_spd(&ap->link);
+ /* print per-port info to dmesg */
xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
ap->udma_mask);
- /* print per-port info to dmesg */
- if (!ata_port_is_dummy(ap))
- ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
- "ctl 0x%p bmdma 0x%p irq %d\n",
+ if (!ata_port_is_dummy(ap)) {
+ ata_port_printk(ap, KERN_INFO,
+ "%cATA max %s %s\n",
(ap->flags & ATA_FLAG_SATA) ? 'S' : 'P',
ata_mode_string(xfer_mask),
- ap->ioaddr.cmd_addr,
- ap->ioaddr.ctl_addr,
- ap->ioaddr.bmdma_addr,
- irq_line);
- else
+ ap->link.eh_info.desc);
+ ata_ehi_clear_desc(&ap->link.eh_info);
+ } else
ata_port_printk(ap, KERN_INFO, "DUMMY\n");
}
@@ -6436,7 +7148,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
/* probe */
if (ap->ops->error_handler) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
unsigned long flags;
ata_port_probe(ap);
@@ -6444,7 +7156,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
/* kick EH for boot probing */
spin_lock_irqsave(ap->lock, flags);
- ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+ ehi->probe_mask =
+ (1 << ata_link_max_devices(&ap->link)) - 1;
ehi->action |= ATA_EH_SOFTRESET;
ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
@@ -6478,6 +7191,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
struct ata_port *ap = host->ports[i];
ata_scsi_scan_host(ap, 1);
+ ata_lpm_schedule(ap, ap->pm_policy);
}
return 0;
@@ -6496,6 +7210,10 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
* request IRQ and register it. This helper takes necessasry
* arguments and performs the three steps in one go.
*
+ * An invalid IRQ skips the IRQ registration and expects the host to
+ * have set polling mode on the port. In this case, @irq_handler
+ * should be NULL.
+ *
* LOCKING:
* Inherited from calling layer (may sleep).
*
@@ -6506,19 +7224,25 @@ int ata_host_activate(struct ata_host *host, int irq,
irq_handler_t irq_handler, unsigned long irq_flags,
struct scsi_host_template *sht)
{
- int rc;
+ int i, rc;
rc = ata_host_start(host);
if (rc)
return rc;
+ /* Special case for polling mode */
+ if (!irq) {
+ WARN_ON(irq_handler);
+ return ata_host_register(host, sht);
+ }
+
rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags,
dev_driver_string(host->dev), host);
if (rc)
return rc;
- /* Used to print device info at probe */
- host->irq = irq;
+ for (i = 0; i < host->n_ports; i++)
+ ata_port_desc(host->ports[i], "irq %d", irq);
rc = ata_host_register(host, sht);
/* if failed, just free the IRQ and leave ports alone */
@@ -6539,10 +7263,11 @@ int ata_host_activate(struct ata_host *host, int irq,
* LOCKING:
* Kernel thread context (may sleep).
*/
-void ata_port_detach(struct ata_port *ap)
+static void ata_port_detach(struct ata_port *ap)
{
unsigned long flags;
- int i;
+ struct ata_link *link;
+ struct ata_device *dev;
if (!ap->ops->error_handler)
goto skip_eh;
@@ -6559,8 +7284,10 @@ void ata_port_detach(struct ata_port *ap)
*/
spin_lock_irqsave(ap->lock, flags);
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ata_dev_disable(&ap->device[i]);
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link)
+ ata_dev_disable(dev);
+ }
spin_unlock_irqrestore(ap->lock, flags);
@@ -6639,7 +7366,7 @@ void ata_std_ports(struct ata_ioports *ioaddr)
*/
void ata_pci_remove_one(struct pci_dev *pdev)
{
- struct device *dev = pci_dev_to_dev(pdev);
+ struct device *dev = &pdev->dev;
struct ata_host *host = dev_get_drvdata(dev);
ata_host_detach(host);
@@ -6847,7 +7574,6 @@ static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc)
}
const struct ata_port_operations ata_dummy_port_ops = {
- .port_disable = ata_port_disable,
.check_status = ata_dummy_check_status,
.check_altstatus = ata_dummy_check_status,
.dev_select = ata_noop_dev_select,
@@ -6872,7 +7598,6 @@ const struct ata_port_info ata_dummy_port_info = {
* likely to change as new drivers are added and updated.
* Do not depend on ABI/API stability.
*/
-
EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
EXPORT_SYMBOL_GPL(sata_deb_timing_long);
@@ -6909,6 +7634,7 @@ EXPORT_SYMBOL_GPL(ata_interrupt);
EXPORT_SYMBOL_GPL(ata_do_set_mode);
EXPORT_SYMBOL_GPL(ata_data_xfer);
EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
+EXPORT_SYMBOL_GPL(ata_std_qc_defer);
EXPORT_SYMBOL_GPL(ata_qc_prep);
EXPORT_SYMBOL_GPL(ata_dumb_qc_prep);
EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
@@ -6925,14 +7651,14 @@ EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd);
EXPORT_SYMBOL_GPL(ata_port_probe);
EXPORT_SYMBOL_GPL(ata_dev_disable);
EXPORT_SYMBOL_GPL(sata_set_spd);
-EXPORT_SYMBOL_GPL(sata_phy_debounce);
-EXPORT_SYMBOL_GPL(sata_phy_resume);
+EXPORT_SYMBOL_GPL(sata_link_debounce);
+EXPORT_SYMBOL_GPL(sata_link_resume);
EXPORT_SYMBOL_GPL(sata_phy_reset);
EXPORT_SYMBOL_GPL(__sata_phy_reset);
EXPORT_SYMBOL_GPL(ata_bus_reset);
EXPORT_SYMBOL_GPL(ata_std_prereset);
EXPORT_SYMBOL_GPL(ata_std_softreset);
-EXPORT_SYMBOL_GPL(sata_port_hardreset);
+EXPORT_SYMBOL_GPL(sata_link_hardreset);
EXPORT_SYMBOL_GPL(sata_std_hardreset);
EXPORT_SYMBOL_GPL(ata_std_postreset);
EXPORT_SYMBOL_GPL(ata_dev_classify);
@@ -6941,6 +7667,7 @@ EXPORT_SYMBOL_GPL(ata_port_disable);
EXPORT_SYMBOL_GPL(ata_ratelimit);
EXPORT_SYMBOL_GPL(ata_wait_register);
EXPORT_SYMBOL_GPL(ata_busy_sleep);
+EXPORT_SYMBOL_GPL(ata_wait_after_reset);
EXPORT_SYMBOL_GPL(ata_wait_ready);
EXPORT_SYMBOL_GPL(ata_port_queue_task);
EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
@@ -6953,8 +7680,8 @@ EXPORT_SYMBOL_GPL(sata_scr_valid);
EXPORT_SYMBOL_GPL(sata_scr_read);
EXPORT_SYMBOL_GPL(sata_scr_write);
EXPORT_SYMBOL_GPL(sata_scr_write_flush);
-EXPORT_SYMBOL_GPL(ata_port_online);
-EXPORT_SYMBOL_GPL(ata_port_offline);
+EXPORT_SYMBOL_GPL(ata_link_online);
+EXPORT_SYMBOL_GPL(ata_link_offline);
#ifdef CONFIG_PM
EXPORT_SYMBOL_GPL(ata_host_suspend);
EXPORT_SYMBOL_GPL(ata_host_resume);
@@ -6985,22 +7712,31 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */
+EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch);
+EXPORT_SYMBOL_GPL(sata_pmp_std_prereset);
+EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset);
+EXPORT_SYMBOL_GPL(sata_pmp_std_postreset);
+EXPORT_SYMBOL_GPL(sata_pmp_do_eh);
+
EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
+EXPORT_SYMBOL_GPL(ata_port_desc);
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL_GPL(ata_port_pbar_desc);
+#endif /* CONFIG_PCI */
EXPORT_SYMBOL_GPL(ata_eng_timeout);
EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
+EXPORT_SYMBOL_GPL(ata_link_abort);
EXPORT_SYMBOL_GPL(ata_port_abort);
EXPORT_SYMBOL_GPL(ata_port_freeze);
+EXPORT_SYMBOL_GPL(sata_async_notification);
EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
EXPORT_SYMBOL_GPL(ata_do_eh);
EXPORT_SYMBOL_GPL(ata_irq_on);
-EXPORT_SYMBOL_GPL(ata_dummy_irq_on);
-EXPORT_SYMBOL_GPL(ata_irq_ack);
-EXPORT_SYMBOL_GPL(ata_dummy_irq_ack);
EXPORT_SYMBOL_GPL(ata_dev_try_classify);
EXPORT_SYMBOL_GPL(ata_cable_40wire);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index ac6ceed4bb6..ed8813b222a 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -33,6 +33,7 @@
*/
#include <linux/kernel.h>
+#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_eh.h>
@@ -74,7 +75,6 @@ static const unsigned long ata_eh_reset_timeouts[] = {
};
static void __ata_port_freeze(struct ata_port *ap);
-static void ata_eh_finish(struct ata_port *ap);
#ifdef CONFIG_PM
static void ata_eh_handle_port_suspend(struct ata_port *ap);
static void ata_eh_handle_port_resume(struct ata_port *ap);
@@ -151,6 +151,73 @@ void ata_ehi_clear_desc(struct ata_eh_info *ehi)
ehi->desc_len = 0;
}
+/**
+ * ata_port_desc - append port description
+ * @ap: target ATA port
+ * @fmt: printf format string
+ *
+ * Format string according to @fmt and append it to port
+ * description. If port description is not empty, " " is added
+ * in-between. This function is to be used while initializing
+ * ata_host. The description is printed on host registration.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_port_desc(struct ata_port *ap, const char *fmt, ...)
+{
+ va_list args;
+
+ WARN_ON(!(ap->pflags & ATA_PFLAG_INITIALIZING));
+
+ if (ap->link.eh_info.desc_len)
+ __ata_ehi_push_desc(&ap->link.eh_info, " ");
+
+ va_start(args, fmt);
+ __ata_ehi_pushv_desc(&ap->link.eh_info, fmt, args);
+ va_end(args);
+}
+
+#ifdef CONFIG_PCI
+
+/**
+ * ata_port_pbar_desc - append PCI BAR description
+ * @ap: target ATA port
+ * @bar: target PCI BAR
+ * @offset: offset into PCI BAR
+ * @name: name of the area
+ *
+ * If @offset is negative, this function formats a string which
+ * contains the name, address, size and type of the BAR and
+ * appends it to the port description. If @offset is zero or
+ * positive, only name and offsetted address is appended.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
+ const char *name)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ char *type = "";
+ unsigned long long start, len;
+
+ if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
+ type = "m";
+ else if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
+ type = "i";
+
+ start = (unsigned long long)pci_resource_start(pdev, bar);
+ len = (unsigned long long)pci_resource_len(pdev, bar);
+
+ if (offset < 0)
+ ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start);
+ else
+ ata_port_desc(ap, "%s 0x%llx", name, start + offset);
+}
+
+#endif /* CONFIG_PCI */
+
static void ata_ering_record(struct ata_ering *ering, int is_io,
unsigned int err_mask)
{
@@ -195,28 +262,29 @@ static int ata_ering_map(struct ata_ering *ering,
static unsigned int ata_eh_dev_action(struct ata_device *dev)
{
- struct ata_eh_context *ehc = &dev->ap->eh_context;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
return ehc->i.action | ehc->i.dev_action[dev->devno];
}
-static void ata_eh_clear_action(struct ata_device *dev,
+static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
struct ata_eh_info *ehi, unsigned int action)
{
- int i;
+ struct ata_device *tdev;
if (!dev) {
ehi->action &= ~action;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehi->dev_action[i] &= ~action;
+ ata_link_for_each_dev(tdev, link)
+ ehi->dev_action[tdev->devno] &= ~action;
} else {
/* doesn't make sense for port-wide EH actions */
WARN_ON(!(action & ATA_EH_PERDEV_MASK));
/* break ehi->action into ehi->dev_action */
if (ehi->action & action) {
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehi->dev_action[i] |= ehi->action & action;
+ ata_link_for_each_dev(tdev, link)
+ ehi->dev_action[tdev->devno] |=
+ ehi->action & action;
ehi->action &= ~action;
}
@@ -261,7 +329,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
ret = EH_HANDLED;
spin_lock_irqsave(ap->lock, flags);
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc) {
WARN_ON(qc->scsicmd != cmd);
qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
@@ -290,7 +358,7 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
void ata_scsi_error(struct Scsi_Host *host)
{
struct ata_port *ap = ata_shost_to_port(host);
- int i, repeat_cnt = ATA_EH_MAX_REPEAT;
+ int i;
unsigned long flags;
DPRINTK("ENTER\n");
@@ -356,12 +424,17 @@ void ata_scsi_error(struct Scsi_Host *host)
__ata_port_freeze(ap);
spin_unlock_irqrestore(ap->lock, flags);
+
+ /* initialize eh_tries */
+ ap->eh_tries = ATA_EH_MAX_TRIES;
} else
spin_unlock_wait(ap->lock);
repeat:
/* invoke error handler */
if (ap->ops->error_handler) {
+ struct ata_link *link;
+
/* kill fast drain timer */
del_timer_sync(&ap->fastdrain_timer);
@@ -371,12 +444,15 @@ void ata_scsi_error(struct Scsi_Host *host)
/* fetch & clear EH info */
spin_lock_irqsave(ap->lock, flags);
- memset(&ap->eh_context, 0, sizeof(ap->eh_context));
- ap->eh_context.i = ap->eh_info;
- memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+ __ata_port_for_each_link(link, ap) {
+ memset(&link->eh_context, 0, sizeof(link->eh_context));
+ link->eh_context.i = link->eh_info;
+ memset(&link->eh_info, 0, sizeof(link->eh_info));
+ }
ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+ ap->excl_link = NULL; /* don't maintain exclusion over EH */
spin_unlock_irqrestore(ap->lock, flags);
@@ -396,20 +472,18 @@ void ata_scsi_error(struct Scsi_Host *host)
spin_lock_irqsave(ap->lock, flags);
if (ap->pflags & ATA_PFLAG_EH_PENDING) {
- if (--repeat_cnt) {
- ata_port_printk(ap, KERN_INFO,
- "EH pending after completion, "
- "repeating EH (cnt=%d)\n", repeat_cnt);
+ if (--ap->eh_tries) {
spin_unlock_irqrestore(ap->lock, flags);
goto repeat;
}
ata_port_printk(ap, KERN_ERR, "EH pending after %d "
- "tries, giving up\n", ATA_EH_MAX_REPEAT);
+ "tries, giving up\n", ATA_EH_MAX_TRIES);
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
}
/* this run is complete, make sure EH info is clear */
- memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+ __ata_port_for_each_link(link, ap)
+ memset(&link->eh_info, 0, sizeof(link->eh_info));
/* Clear host_eh_scheduled while holding ap->lock such
* that if exception occurs after this point but
@@ -420,7 +494,7 @@ void ata_scsi_error(struct Scsi_Host *host)
spin_unlock_irqrestore(ap->lock, flags);
} else {
- WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
+ WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL);
ap->ops->eng_timeout(ap);
}
@@ -575,7 +649,7 @@ void ata_eng_timeout(struct ata_port *ap)
{
DPRINTK("ENTER\n");
- ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
+ ata_qc_timeout(ata_qc_from_tag(ap, ap->link.active_tag));
DPRINTK("EXIT\n");
}
@@ -718,19 +792,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
DPRINTK("port EH scheduled\n");
}
-/**
- * ata_port_abort - abort all qc's on the port
- * @ap: ATA port to abort qc's for
- *
- * Abort all active qc's of @ap and schedule EH.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- *
- * RETURNS:
- * Number of aborted qc's.
- */
-int ata_port_abort(struct ata_port *ap)
+static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link)
{
int tag, nr_aborted = 0;
@@ -742,7 +804,7 @@ int ata_port_abort(struct ata_port *ap)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
- if (qc) {
+ if (qc && (!link || qc->dev->link == link)) {
qc->flags |= ATA_QCFLAG_FAILED;
ata_qc_complete(qc);
nr_aborted++;
@@ -756,6 +818,40 @@ int ata_port_abort(struct ata_port *ap)
}
/**
+ * ata_link_abort - abort all qc's on the link
+ * @link: ATA link to abort qc's for
+ *
+ * Abort all active qc's active on @link and schedule EH.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * Number of aborted qc's.
+ */
+int ata_link_abort(struct ata_link *link)
+{
+ return ata_do_link_abort(link->ap, link);
+}
+
+/**
+ * ata_port_abort - abort all qc's on the port
+ * @ap: ATA port to abort qc's for
+ *
+ * Abort all active qc's of @ap and schedule EH.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ *
+ * RETURNS:
+ * Number of aborted qc's.
+ */
+int ata_port_abort(struct ata_port *ap)
+{
+ return ata_do_link_abort(ap, NULL);
+}
+
+/**
* __ata_port_freeze - freeze port
* @ap: ATA port to freeze
*
@@ -810,6 +906,79 @@ int ata_port_freeze(struct ata_port *ap)
}
/**
+ * sata_async_notification - SATA async notification handler
+ * @ap: ATA port where async notification is received
+ *
+ * Handler to be called when async notification via SDB FIS is
+ * received. This function schedules EH if necessary.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * 1 if EH is scheduled, 0 otherwise.
+ */
+int sata_async_notification(struct ata_port *ap)
+{
+ u32 sntf;
+ int rc;
+
+ if (!(ap->flags & ATA_FLAG_AN))
+ return 0;
+
+ rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+ if (rc == 0)
+ sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+ if (!ap->nr_pmp_links || rc) {
+ /* PMP is not attached or SNTF is not available */
+ if (!ap->nr_pmp_links) {
+ /* PMP is not attached. Check whether ATAPI
+ * AN is configured. If so, notify media
+ * change.
+ */
+ struct ata_device *dev = ap->link.device;
+
+ if ((dev->class == ATA_DEV_ATAPI) &&
+ (dev->flags & ATA_DFLAG_AN))
+ ata_scsi_media_change_notify(dev);
+ return 0;
+ } else {
+ /* PMP is attached but SNTF is not available.
+ * ATAPI async media change notification is
+ * not used. The PMP must be reporting PHY
+ * status change, schedule EH.
+ */
+ ata_port_schedule_eh(ap);
+ return 1;
+ }
+ } else {
+ /* PMP is attached and SNTF is available */
+ struct ata_link *link;
+
+ /* check and notify ATAPI AN */
+ ata_port_for_each_link(link, ap) {
+ if (!(sntf & (1 << link->pmp)))
+ continue;
+
+ if ((link->device->class == ATA_DEV_ATAPI) &&
+ (link->device->flags & ATA_DFLAG_AN))
+ ata_scsi_media_change_notify(link->device);
+ }
+
+ /* If PMP is reporting that PHY status of some
+ * downstream ports has changed, schedule EH.
+ */
+ if (sntf & (1 << SATA_PMP_CTRL_PORT)) {
+ ata_port_schedule_eh(ap);
+ return 1;
+ }
+
+ return 0;
+ }
+}
+
+/**
* ata_eh_freeze_port - EH helper to freeze port
* @ap: ATA port to freeze
*
@@ -920,9 +1089,10 @@ void ata_eh_qc_retry(struct ata_queued_cmd *qc)
* LOCKING:
* None.
*/
-static void ata_eh_detach_dev(struct ata_device *dev)
+void ata_eh_detach_dev(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
unsigned long flags;
ata_dev_disable(dev);
@@ -937,31 +1107,32 @@ static void ata_eh_detach_dev(struct ata_device *dev)
}
/* clear per-dev EH actions */
- ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK);
- ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK);
+ ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK);
+ ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK);
spin_unlock_irqrestore(ap->lock, flags);
}
/**
* ata_eh_about_to_do - about to perform eh_action
- * @ap: target ATA port
+ * @link: target ATA link
* @dev: target ATA dev for per-dev action (can be NULL)
* @action: action about to be performed
*
* Called just before performing EH actions to clear related bits
- * in @ap->eh_info such that eh actions are not unnecessarily
+ * in @link->eh_info such that eh actions are not unnecessarily
* repeated.
*
* LOCKING:
* None.
*/
-static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
- unsigned int action)
+void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+ unsigned int action)
{
+ struct ata_port *ap = link->ap;
+ struct ata_eh_info *ehi = &link->eh_info;
+ struct ata_eh_context *ehc = &link->eh_context;
unsigned long flags;
- struct ata_eh_info *ehi = &ap->eh_info;
- struct ata_eh_context *ehc = &ap->eh_context;
spin_lock_irqsave(ap->lock, flags);
@@ -978,7 +1149,7 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
}
- ata_eh_clear_action(dev, ehi, action);
+ ata_eh_clear_action(link, dev, ehi, action);
if (!(ehc->i.flags & ATA_EHI_QUIET))
ap->pflags |= ATA_PFLAG_RECOVERED;
@@ -988,26 +1159,28 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
/**
* ata_eh_done - EH action complete
- * @ap: target ATA port
+* @ap: target ATA port
* @dev: target ATA dev for per-dev action (can be NULL)
* @action: action just completed
*
* Called right after performing EH actions to clear related bits
- * in @ap->eh_context.
+ * in @link->eh_context.
*
* LOCKING:
* None.
*/
-static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
- unsigned int action)
+void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+ unsigned int action)
{
+ struct ata_eh_context *ehc = &link->eh_context;
+
/* if reset is complete, clear all reset actions & reset modifier */
if (action & ATA_EH_RESET_MASK) {
action |= ATA_EH_RESET_MASK;
- ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
+ ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
}
- ata_eh_clear_action(dev, &ap->eh_context.i, action);
+ ata_eh_clear_action(link, dev, &ehc->i, action);
}
/**
@@ -1024,7 +1197,7 @@ static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
* RETURNS:
* Descriptive string for @err_mask
*/
-static const char * ata_err_string(unsigned int err_mask)
+static const char *ata_err_string(unsigned int err_mask)
{
if (err_mask & AC_ERR_HOST_BUS)
return "host bus error";
@@ -1077,7 +1250,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev,
tf.protocol = ATA_PROT_PIO;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
- buf, sectors * ATA_SECT_SIZE);
+ buf, sectors * ATA_SECT_SIZE, 0);
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
@@ -1101,7 +1274,7 @@ static unsigned int ata_read_log_page(struct ata_device *dev,
static int ata_eh_read_log_10h(struct ata_device *dev,
int *tag, struct ata_taskfile *tf)
{
- u8 *buf = dev->ap->sector_buf;
+ u8 *buf = dev->link->ap->sector_buf;
unsigned int err_mask;
u8 csum;
int i;
@@ -1155,7 +1328,7 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
{
struct ata_device *dev = qc->dev;
unsigned char *sense_buf = qc->scsicmd->sense_buffer;
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
struct ata_taskfile tf;
u8 cdb[ATAPI_CDB_LEN];
@@ -1191,12 +1364,12 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
}
return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
- sense_buf, SCSI_SENSE_BUFFERSIZE);
+ sense_buf, SCSI_SENSE_BUFFERSIZE, 0);
}
/**
* ata_eh_analyze_serror - analyze SError for a failed port
- * @ap: ATA port to analyze SError for
+ * @link: ATA link to analyze SError for
*
* Analyze SError if available and further determine cause of
* failure.
@@ -1204,11 +1377,12 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc)
* LOCKING:
* None.
*/
-static void ata_eh_analyze_serror(struct ata_port *ap)
+static void ata_eh_analyze_serror(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_eh_context *ehc = &link->eh_context;
u32 serror = ehc->i.serror;
unsigned int err_mask = 0, action = 0;
+ u32 hotplug_mask;
if (serror & SERR_PERSISTENT) {
err_mask |= AC_ERR_ATA_BUS;
@@ -1227,7 +1401,20 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
err_mask |= AC_ERR_SYSTEM;
action |= ATA_EH_HARDRESET;
}
- if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
+
+ /* Determine whether a hotplug event has occurred. Both
+ * SError.N/X are considered hotplug events for enabled or
+ * host links. For disabled PMP links, only N bit is
+ * considered as X bit is left at 1 for link plugging.
+ */
+ hotplug_mask = 0;
+
+ if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
+ hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
+ else
+ hotplug_mask = SERR_PHYRDY_CHG;
+
+ if (serror & hotplug_mask)
ata_ehi_hotplugged(&ehc->i);
ehc->i.err_mask |= err_mask;
@@ -1236,7 +1423,7 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
/**
* ata_eh_analyze_ncq_error - analyze NCQ error
- * @ap: ATA port to analyze NCQ error for
+ * @link: ATA link to analyze NCQ error for
*
* Read log page 10h, determine the offending qc and acquire
* error status TF. For NCQ device errors, all LLDDs have to do
@@ -1246,10 +1433,11 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
* LOCKING:
* Kernel thread context (may sleep).
*/
-static void ata_eh_analyze_ncq_error(struct ata_port *ap)
+static void ata_eh_analyze_ncq_error(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
- struct ata_device *dev = ap->device;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
+ struct ata_device *dev = link->device;
struct ata_queued_cmd *qc;
struct ata_taskfile tf;
int tag, rc;
@@ -1259,7 +1447,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
return;
/* is it NCQ device error? */
- if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
+ if (!link->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
return;
/* has LLDD analyzed already? */
@@ -1276,13 +1464,13 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
/* okay, this error is ours */
rc = ata_eh_read_log_10h(dev, &tag, &tf);
if (rc) {
- ata_port_printk(ap, KERN_ERR, "failed to read log page 10h "
+ ata_link_printk(link, KERN_ERR, "failed to read log page 10h "
"(errno=%d)\n", rc);
return;
}
- if (!(ap->sactive & (1 << tag))) {
- ata_port_printk(ap, KERN_ERR, "log page 10h reported "
+ if (!(link->sactive & (1 << tag))) {
+ ata_link_printk(link, KERN_ERR, "log page 10h reported "
"inactive tag %d\n", tag);
return;
}
@@ -1497,7 +1685,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
/* speed down? */
if (verdict & ATA_EH_SPDN_SPEED_DOWN) {
/* speed down SATA link speed if possible */
- if (sata_down_spd_limit(dev->ap) == 0) {
+ if (sata_down_spd_limit(dev->link) == 0) {
action |= ATA_EH_HARDRESET;
goto done;
}
@@ -1528,7 +1716,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
* SATA. Consider it only for PATA.
*/
if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) &&
- (dev->ap->cbl != ATA_CBL_SATA) &&
+ (dev->link->ap->cbl != ATA_CBL_SATA) &&
(dev->xfer_shift != ATA_SHIFT_PIO)) {
if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) {
dev->spdn_cnt = 0;
@@ -1545,19 +1733,21 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io,
}
/**
- * ata_eh_autopsy - analyze error and determine recovery action
- * @ap: ATA port to perform autopsy on
+ * ata_eh_link_autopsy - analyze error and determine recovery action
+ * @link: host link to perform autopsy on
*
- * Analyze why @ap failed and determine which recovery action is
- * needed. This function also sets more detailed AC_ERR_* values
- * and fills sense data for ATAPI CHECK SENSE.
+ * Analyze why @link failed and determine which recovery actions
+ * are needed. This function also sets more detailed AC_ERR_*
+ * values and fills sense data for ATAPI CHECK SENSE.
*
* LOCKING:
* Kernel thread context (may sleep).
*/
-static void ata_eh_autopsy(struct ata_port *ap)
+static void ata_eh_link_autopsy(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
+ struct ata_device *dev;
unsigned int all_err_mask = 0;
int tag, is_io = 0;
u32 serror;
@@ -1569,10 +1759,10 @@ static void ata_eh_autopsy(struct ata_port *ap)
return;
/* obtain and analyze SError */
- rc = sata_scr_read(ap, SCR_ERROR, &serror);
+ rc = sata_scr_read(link, SCR_ERROR, &serror);
if (rc == 0) {
ehc->i.serror |= serror;
- ata_eh_analyze_serror(ap);
+ ata_eh_analyze_serror(link);
} else if (rc != -EOPNOTSUPP) {
/* SError read failed, force hardreset and probing */
ata_ehi_schedule_probe(&ehc->i);
@@ -1581,7 +1771,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
}
/* analyze NCQ failure */
- ata_eh_analyze_ncq_error(ap);
+ ata_eh_analyze_ncq_error(link);
/* any real error trumps AC_ERR_OTHER */
if (ehc->i.err_mask & ~AC_ERR_OTHER)
@@ -1592,7 +1782,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
- if (!(qc->flags & ATA_QCFLAG_FAILED))
+ if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
continue;
/* inherit upper level err_mask */
@@ -1611,10 +1801,8 @@ static void ata_eh_autopsy(struct ata_port *ap)
qc->err_mask &= ~AC_ERR_OTHER;
/* SENSE_VALID trumps dev/unknown error and revalidation */
- if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
+ if (qc->flags & ATA_QCFLAG_SENSE_VALID)
qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
- ehc->i.action &= ~ATA_EH_REVALIDATE;
- }
/* accumulate error info */
ehc->i.dev = qc->dev;
@@ -1627,39 +1815,69 @@ static void ata_eh_autopsy(struct ata_port *ap)
if (ap->pflags & ATA_PFLAG_FROZEN ||
all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
ehc->i.action |= ATA_EH_SOFTRESET;
- else if (all_err_mask)
+ else if ((is_io && all_err_mask) ||
+ (!is_io && (all_err_mask & ~AC_ERR_DEV)))
ehc->i.action |= ATA_EH_REVALIDATE;
- /* if we have offending qcs and the associated failed device */
+ /* If we have offending qcs and the associated failed device,
+ * perform per-dev EH action only on the offending device.
+ */
if (ehc->i.dev) {
- /* speed down */
- ehc->i.action |= ata_eh_speed_down(ehc->i.dev, is_io,
- all_err_mask);
-
- /* perform per-dev EH action only on the offending device */
ehc->i.dev_action[ehc->i.dev->devno] |=
ehc->i.action & ATA_EH_PERDEV_MASK;
ehc->i.action &= ~ATA_EH_PERDEV_MASK;
}
+ /* consider speeding down */
+ dev = ehc->i.dev;
+ if (!dev && ata_link_max_devices(link) == 1 &&
+ ata_dev_enabled(link->device))
+ dev = link->device;
+
+ if (dev)
+ ehc->i.action |= ata_eh_speed_down(dev, is_io, all_err_mask);
+
DPRINTK("EXIT\n");
}
/**
- * ata_eh_report - report error handling to user
- * @ap: ATA port EH is going on
+ * ata_eh_autopsy - analyze error and determine recovery action
+ * @ap: host port to perform autopsy on
+ *
+ * Analyze all links of @ap and determine why they failed and
+ * which recovery actions are needed.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void ata_eh_autopsy(struct ata_port *ap)
+{
+ struct ata_link *link;
+
+ __ata_port_for_each_link(link, ap)
+ ata_eh_link_autopsy(link);
+}
+
+/**
+ * ata_eh_link_report - report error handling to user
+ * @link: ATA link EH is going on
*
* Report EH to user.
*
* LOCKING:
* None.
*/
-static void ata_eh_report(struct ata_port *ap)
+static void ata_eh_link_report(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
const char *frozen, *desc;
+ char tries_buf[6];
int tag, nr_failed = 0;
+ if (ehc->i.flags & ATA_EHI_QUIET)
+ return;
+
desc = NULL;
if (ehc->i.desc[0] != '\0')
desc = ehc->i.desc;
@@ -1667,7 +1885,9 @@ static void ata_eh_report(struct ata_port *ap)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
- if (!(qc->flags & ATA_QCFLAG_FAILED))
+ if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link ||
+ ((qc->flags & ATA_QCFLAG_QUIET) &&
+ qc->err_mask == AC_ERR_DEV))
continue;
if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask)
continue;
@@ -1682,22 +1902,48 @@ static void ata_eh_report(struct ata_port *ap)
if (ap->pflags & ATA_PFLAG_FROZEN)
frozen = " frozen";
+ memset(tries_buf, 0, sizeof(tries_buf));
+ if (ap->eh_tries < ATA_EH_MAX_TRIES)
+ snprintf(tries_buf, sizeof(tries_buf) - 1, " t%d",
+ ap->eh_tries);
+
if (ehc->i.dev) {
ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
- "SAct 0x%x SErr 0x%x action 0x%x%s\n",
- ehc->i.err_mask, ap->sactive, ehc->i.serror,
- ehc->i.action, frozen);
+ "SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
+ ehc->i.err_mask, link->sactive, ehc->i.serror,
+ ehc->i.action, frozen, tries_buf);
if (desc)
ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc);
} else {
- ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
- "SAct 0x%x SErr 0x%x action 0x%x%s\n",
- ehc->i.err_mask, ap->sactive, ehc->i.serror,
- ehc->i.action, frozen);
+ ata_link_printk(link, KERN_ERR, "exception Emask 0x%x "
+ "SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
+ ehc->i.err_mask, link->sactive, ehc->i.serror,
+ ehc->i.action, frozen, tries_buf);
if (desc)
- ata_port_printk(ap, KERN_ERR, "%s\n", desc);
+ ata_link_printk(link, KERN_ERR, "%s\n", desc);
}
+ if (ehc->i.serror)
+ ata_port_printk(ap, KERN_ERR,
+ "SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n",
+ ehc->i.serror & SERR_DATA_RECOVERED ? "RecovData " : "",
+ ehc->i.serror & SERR_COMM_RECOVERED ? "RecovComm " : "",
+ ehc->i.serror & SERR_DATA ? "UnrecovData " : "",
+ ehc->i.serror & SERR_PERSISTENT ? "Persist " : "",
+ ehc->i.serror & SERR_PROTOCOL ? "Proto " : "",
+ ehc->i.serror & SERR_INTERNAL ? "HostInt " : "",
+ ehc->i.serror & SERR_PHYRDY_CHG ? "PHYRdyChg " : "",
+ ehc->i.serror & SERR_PHY_INT_ERR ? "PHYInt " : "",
+ ehc->i.serror & SERR_COMM_WAKE ? "CommWake " : "",
+ ehc->i.serror & SERR_10B_8B_ERR ? "10B8B " : "",
+ ehc->i.serror & SERR_DISPARITY ? "Dispar " : "",
+ ehc->i.serror & SERR_CRC ? "BadCRC " : "",
+ ehc->i.serror & SERR_HANDSHAKE ? "Handshk " : "",
+ ehc->i.serror & SERR_LINK_SEQ_ERR ? "LinkSeq " : "",
+ ehc->i.serror & SERR_TRANS_ST_ERROR ? "TrStaTrns " : "",
+ ehc->i.serror & SERR_UNRECOG_FIS ? "UnrecFIS " : "",
+ ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : "");
+
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
static const char *dma_str[] = {
[DMA_BIDIRECTIONAL] = "bidi",
@@ -1708,7 +1954,8 @@ static void ata_eh_report(struct ata_port *ap)
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf;
- if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
+ if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+ qc->dev->link != link || !qc->err_mask)
continue;
ata_dev_printk(qc->dev, KERN_ERR,
@@ -1728,18 +1975,60 @@ static void ata_eh_report(struct ata_port *ap)
res->hob_lbal, res->hob_lbam, res->hob_lbah,
res->device, qc->err_mask, ata_err_string(qc->err_mask),
qc->err_mask & AC_ERR_NCQ ? " <F>" : "");
+
+ if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
+ ATA_ERR)) {
+ if (res->command & ATA_BUSY)
+ ata_dev_printk(qc->dev, KERN_ERR,
+ "status: { Busy }\n");
+ else
+ ata_dev_printk(qc->dev, KERN_ERR,
+ "status: { %s%s%s%s}\n",
+ res->command & ATA_DRDY ? "DRDY " : "",
+ res->command & ATA_DF ? "DF " : "",
+ res->command & ATA_DRQ ? "DRQ " : "",
+ res->command & ATA_ERR ? "ERR " : "");
+ }
+
+ if (cmd->command != ATA_CMD_PACKET &&
+ (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF |
+ ATA_ABORTED)))
+ ata_dev_printk(qc->dev, KERN_ERR,
+ "error: { %s%s%s%s}\n",
+ res->feature & ATA_ICRC ? "ICRC " : "",
+ res->feature & ATA_UNC ? "UNC " : "",
+ res->feature & ATA_IDNF ? "IDNF " : "",
+ res->feature & ATA_ABORTED ? "ABRT " : "");
}
}
-static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
+/**
+ * ata_eh_report - report error handling to user
+ * @ap: ATA port to report EH about
+ *
+ * Report EH to user.
+ *
+ * LOCKING:
+ * None.
+ */
+void ata_eh_report(struct ata_port *ap)
+{
+ struct ata_link *link;
+
+ __ata_port_for_each_link(link, ap)
+ ata_eh_link_report(link);
+}
+
+static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
unsigned int *classes, unsigned long deadline)
{
- int i, rc;
+ struct ata_device *dev;
+ int rc;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_UNKNOWN;
+ ata_link_for_each_dev(dev, link)
+ classes[dev->devno] = ATA_DEV_UNKNOWN;
- rc = reset(ap, classes, deadline);
+ rc = reset(link, classes, deadline);
if (rc)
return rc;
@@ -1747,71 +2036,109 @@ static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
* is complete and convert all ATA_DEV_UNKNOWN to
* ATA_DEV_NONE.
*/
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] != ATA_DEV_UNKNOWN)
+ ata_link_for_each_dev(dev, link)
+ if (classes[dev->devno] != ATA_DEV_UNKNOWN)
break;
- if (i < ATA_MAX_DEVICES)
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (classes[i] == ATA_DEV_UNKNOWN)
- classes[i] = ATA_DEV_NONE;
+ if (dev) {
+ ata_link_for_each_dev(dev, link) {
+ if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+ classes[dev->devno] = ATA_DEV_NONE;
+ }
+ }
return 0;
}
-static int ata_eh_followup_srst_needed(int rc, int classify,
+static int ata_eh_followup_srst_needed(struct ata_link *link,
+ int rc, int classify,
const unsigned int *classes)
{
+ if (link->flags & ATA_LFLAG_NO_SRST)
+ return 0;
if (rc == -EAGAIN)
return 1;
if (rc != 0)
return 0;
- if (classify && classes[0] == ATA_DEV_UNKNOWN)
+ if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link))
+ return 1;
+ if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) &&
+ classes[0] == ATA_DEV_UNKNOWN)
return 1;
return 0;
}
-static int ata_eh_reset(struct ata_port *ap, int classify,
- ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
- ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+int ata_eh_reset(struct ata_link *link, int classify,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ const int max_tries = ARRAY_SIZE(ata_eh_reset_timeouts);
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
unsigned int *classes = ehc->classes;
+ unsigned int lflags = link->flags;
int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
int try = 0;
- unsigned long deadline;
- unsigned int action;
+ struct ata_device *dev;
+ unsigned long deadline, now;
+ unsigned int tmp_action;
ata_reset_fn_t reset;
- int i, rc;
+ unsigned long flags;
+ u32 sstatus;
+ int rc;
/* about to reset */
- ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags |= ATA_PFLAG_RESETTING;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_eh_about_to_do(link, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+
+ ata_link_for_each_dev(dev, link) {
+ /* If we issue an SRST then an ATA drive (not ATAPI)
+ * may change configuration and be in PIO0 timing. If
+ * we do a hard reset (or are coming from power on)
+ * this is true for ATA or ATAPI. Until we've set a
+ * suitable controller mode we should not touch the
+ * bus as we may be talking too fast.
+ */
+ dev->pio_mode = XFER_PIO_0;
+
+ /* If the controller has a pio mode setup function
+ * then use it to set the chipset to rights. Don't
+ * touch the DMA setup as that will be dealt with when
+ * configuring devices.
+ */
+ if (ap->ops->set_piomode)
+ ap->ops->set_piomode(ap, dev);
+ }
/* Determine which reset to use and record in ehc->i.action.
* prereset() may examine and modify it.
*/
- action = ehc->i.action;
- ehc->i.action &= ~ATA_EH_RESET_MASK;
- if (softreset && (!hardreset || (!sata_set_spd_needed(ap) &&
- !(action & ATA_EH_HARDRESET))))
- ehc->i.action |= ATA_EH_SOFTRESET;
+ if (softreset && (!hardreset || (!(lflags & ATA_LFLAG_NO_SRST) &&
+ !sata_set_spd_needed(link) &&
+ !(ehc->i.action & ATA_EH_HARDRESET))))
+ tmp_action = ATA_EH_SOFTRESET;
else
- ehc->i.action |= ATA_EH_HARDRESET;
+ tmp_action = ATA_EH_HARDRESET;
+
+ ehc->i.action = (ehc->i.action & ~ATA_EH_RESET_MASK) | tmp_action;
if (prereset) {
- rc = prereset(ap, jiffies + ATA_EH_PRERESET_TIMEOUT);
+ rc = prereset(link, jiffies + ATA_EH_PRERESET_TIMEOUT);
if (rc) {
if (rc == -ENOENT) {
- ata_port_printk(ap, KERN_DEBUG,
+ ata_link_printk(link, KERN_DEBUG,
"port disabled. ignoring.\n");
- ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
+ ehc->i.action &= ~ATA_EH_RESET_MASK;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_NONE;
+ ata_link_for_each_dev(dev, link)
+ classes[dev->devno] = ATA_DEV_NONE;
rc = 0;
} else
- ata_port_printk(ap, KERN_ERR,
+ ata_link_printk(link, KERN_ERR,
"prereset failed (errno=%d)\n", rc);
goto out;
}
@@ -1824,8 +2151,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
reset = softreset;
else {
/* prereset told us not to reset, bang classes and return */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- classes[i] = ATA_DEV_NONE;
+ ata_link_for_each_dev(dev, link)
+ classes[dev->devno] = ATA_DEV_NONE;
rc = 0;
goto out;
}
@@ -1843,7 +2170,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
/* shut up during boot probing */
if (verbose)
- ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
+ ata_link_printk(link, KERN_INFO, "%s resetting link\n",
reset == softreset ? "soft" : "hard");
/* mark that this EH session started with reset */
@@ -1852,88 +2179,118 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
else
ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
- rc = ata_do_reset(ap, reset, classes, deadline);
+ rc = ata_do_reset(link, reset, classes, deadline);
if (reset == hardreset &&
- ata_eh_followup_srst_needed(rc, classify, classes)) {
+ ata_eh_followup_srst_needed(link, rc, classify, classes)) {
/* okay, let's do follow-up softreset */
reset = softreset;
if (!reset) {
- ata_port_printk(ap, KERN_ERR,
+ ata_link_printk(link, KERN_ERR,
"follow-up softreset required "
"but no softreset avaliable\n");
rc = -EINVAL;
- goto out;
+ goto fail;
}
- ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
- rc = ata_do_reset(ap, reset, classes, deadline);
+ ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK);
+ rc = ata_do_reset(link, reset, classes, deadline);
+ }
- if (rc == 0 && classify &&
- classes[0] == ATA_DEV_UNKNOWN) {
- ata_port_printk(ap, KERN_ERR,
+ /* -EAGAIN can happen if we skipped followup SRST */
+ if (rc && rc != -EAGAIN)
+ goto fail;
+
+ /* was classification successful? */
+ if (classify && classes[0] == ATA_DEV_UNKNOWN &&
+ !(lflags & ATA_LFLAG_ASSUME_CLASS)) {
+ if (try < max_tries) {
+ ata_link_printk(link, KERN_WARNING,
"classification failed\n");
rc = -EINVAL;
- goto out;
+ goto fail;
}
- }
-
- if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
- unsigned long now = jiffies;
- if (time_before(now, deadline)) {
- unsigned long delta = deadline - jiffies;
+ ata_link_printk(link, KERN_WARNING,
+ "classfication failed, assuming ATA\n");
+ lflags |= ATA_LFLAG_ASSUME_ATA;
+ }
- ata_port_printk(ap, KERN_WARNING, "reset failed "
- "(errno=%d), retrying in %u secs\n",
- rc, (jiffies_to_msecs(delta) + 999) / 1000);
+ ata_link_for_each_dev(dev, link) {
+ /* After the reset, the device state is PIO 0 and the
+ * controller state is undefined. Reset also wakes up
+ * drives from sleeping mode.
+ */
+ dev->pio_mode = XFER_PIO_0;
+ dev->flags &= ~ATA_DFLAG_SLEEPING;
- schedule_timeout_uninterruptible(delta);
- }
+ if (ata_link_offline(link))
+ continue;
- if (rc == -EPIPE ||
- try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
- sata_down_spd_limit(ap);
- if (hardreset)
- reset = hardreset;
- goto retry;
+ /* apply class override and convert UNKNOWN to NONE */
+ if (lflags & ATA_LFLAG_ASSUME_ATA)
+ classes[dev->devno] = ATA_DEV_ATA;
+ else if (lflags & ATA_LFLAG_ASSUME_SEMB)
+ classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */
+ else if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+ classes[dev->devno] = ATA_DEV_NONE;
}
- if (rc == 0) {
- u32 sstatus;
+ /* record current link speed */
+ if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0)
+ link->sata_spd = (sstatus >> 4) & 0xf;
- /* After the reset, the device state is PIO 0 and the
- * controller state is undefined. Record the mode.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->device[i].pio_mode = XFER_PIO_0;
+ if (postreset)
+ postreset(link, classes);
- /* record current link speed */
- if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0)
- ap->sata_spd = (sstatus >> 4) & 0xf;
+ /* reset successful, schedule revalidation */
+ ata_eh_done(link, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+ ehc->i.action |= ATA_EH_REVALIDATE;
- if (postreset)
- postreset(ap, classes);
-
- /* reset successful, schedule revalidation */
- ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
- ehc->i.action |= ATA_EH_REVALIDATE;
- }
+ rc = 0;
out:
/* clear hotplug flag */
ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
+
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags &= ~ATA_PFLAG_RESETTING;
+ spin_unlock_irqrestore(ap->lock, flags);
+
return rc;
+
+ fail:
+ if (rc == -ERESTART || try >= max_tries)
+ goto out;
+
+ now = jiffies;
+ if (time_before(now, deadline)) {
+ unsigned long delta = deadline - now;
+
+ ata_link_printk(link, KERN_WARNING, "reset failed "
+ "(errno=%d), retrying in %u secs\n",
+ rc, (jiffies_to_msecs(delta) + 999) / 1000);
+
+ while (delta)
+ delta = schedule_timeout_uninterruptible(delta);
+ }
+
+ if (rc == -EPIPE || try == max_tries - 1)
+ sata_down_spd_limit(link);
+ if (hardreset)
+ reset = hardreset;
+ goto retry;
}
-static int ata_eh_revalidate_and_attach(struct ata_port *ap,
+static int ata_eh_revalidate_and_attach(struct ata_link *link,
struct ata_device **r_failed_dev)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &link->eh_context;
struct ata_device *dev;
unsigned int new_mask = 0;
unsigned long flags;
- int i, rc = 0;
+ int rc = 0;
DPRINTK("ENTER\n");
@@ -1941,27 +2298,28 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
* be done backwards such that PDIAG- is released by the slave
* device before the master device is identified.
*/
- for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) {
- unsigned int action, readid_flags = 0;
-
- dev = &ap->device[i];
- action = ata_eh_dev_action(dev);
+ ata_link_for_each_dev_reverse(dev, link) {
+ unsigned int action = ata_eh_dev_action(dev);
+ unsigned int readid_flags = 0;
if (ehc->i.flags & ATA_EHI_DID_RESET)
readid_flags |= ATA_READID_POSTRESET;
if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
- if (ata_port_offline(ap)) {
+ WARN_ON(dev->class == ATA_DEV_PMP);
+
+ if (ata_link_offline(link)) {
rc = -EIO;
goto err;
}
- ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE);
- rc = ata_dev_revalidate(dev, readid_flags);
+ ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE);
+ rc = ata_dev_revalidate(dev, ehc->classes[dev->devno],
+ readid_flags);
if (rc)
goto err;
- ata_eh_done(ap, dev, ATA_EH_REVALIDATE);
+ ata_eh_done(link, dev, ATA_EH_REVALIDATE);
/* Configuration may have changed, reconfigure
* transfer mode.
@@ -1975,11 +2333,14 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
ata_class_enabled(ehc->classes[dev->devno])) {
dev->class = ehc->classes[dev->devno];
- rc = ata_dev_read_id(dev, &dev->class, readid_flags,
- dev->id);
+ if (dev->class == ATA_DEV_PMP)
+ rc = sata_pmp_attach(dev);
+ else
+ rc = ata_dev_read_id(dev, &dev->class,
+ readid_flags, dev->id);
switch (rc) {
case 0:
- new_mask |= 1 << i;
+ new_mask |= 1 << dev->devno;
break;
case -ENOENT:
/* IDENTIFY was issued to non-existent
@@ -1997,16 +2358,16 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
}
/* PDIAG- should have been released, ask cable type if post-reset */
- if ((ehc->i.flags & ATA_EHI_DID_RESET) && ap->ops->cable_detect)
+ if (ata_is_host_link(link) && ap->ops->cable_detect &&
+ (ehc->i.flags & ATA_EHI_DID_RESET))
ap->cbl = ap->ops->cable_detect(ap);
/* Configure new devices forward such that user doesn't see
* device detection messages backwards.
*/
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
- if (!(new_mask & (1 << i)))
+ ata_link_for_each_dev(dev, link) {
+ if (!(new_mask & (1 << dev->devno)) ||
+ dev->class == ATA_DEV_PMP)
continue;
ehc->i.flags |= ATA_EHI_PRINTINFO;
@@ -2031,40 +2392,44 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
return rc;
}
-static int ata_port_nr_enabled(struct ata_port *ap)
+static int ata_link_nr_enabled(struct ata_link *link)
{
- int i, cnt = 0;
+ struct ata_device *dev;
+ int cnt = 0;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (ata_dev_enabled(&ap->device[i]))
+ ata_link_for_each_dev(dev, link)
+ if (ata_dev_enabled(dev))
cnt++;
return cnt;
}
-static int ata_port_nr_vacant(struct ata_port *ap)
+static int ata_link_nr_vacant(struct ata_link *link)
{
- int i, cnt = 0;
+ struct ata_device *dev;
+ int cnt = 0;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- if (ap->device[i].class == ATA_DEV_UNKNOWN)
+ ata_link_for_each_dev(dev, link)
+ if (dev->class == ATA_DEV_UNKNOWN)
cnt++;
return cnt;
}
-static int ata_eh_skip_recovery(struct ata_port *ap)
+static int ata_eh_skip_recovery(struct ata_link *link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
- int i;
+ struct ata_eh_context *ehc = &link->eh_context;
+ struct ata_device *dev;
+
+ /* skip disabled links */
+ if (link->flags & ATA_LFLAG_DISABLED)
+ return 1;
/* thaw frozen port, resume link and recover failed devices */
- if ((ap->pflags & ATA_PFLAG_FROZEN) ||
- (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap))
+ if ((link->ap->pflags & ATA_PFLAG_FROZEN) ||
+ (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link))
return 0;
/* skip if class codes for all vacant slots are ATA_DEV_NONE */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
-
+ ata_link_for_each_dev(dev, link) {
if (dev->class == ATA_DEV_UNKNOWN &&
ehc->classes[dev->devno] != ATA_DEV_NONE)
return 0;
@@ -2073,10 +2438,9 @@ static int ata_eh_skip_recovery(struct ata_port *ap)
return 1;
}
-static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
+static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
{
- struct ata_port *ap = dev->ap;
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_eh_context *ehc = &dev->link->eh_context;
ehc->tries[dev->devno]--;
@@ -2088,11 +2452,11 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
/* give it just one more chance */
ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1);
case -EIO:
- if (ehc->tries[dev->devno] == 1) {
+ if (ehc->tries[dev->devno] == 1 && dev->pio_mode > XFER_PIO_0) {
/* This is the last chance, better to slow
* down than lose it.
*/
- sata_down_spd_limit(ap);
+ sata_down_spd_limit(dev->link);
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
}
}
@@ -2102,7 +2466,7 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
ata_dev_disable(dev);
/* detach if offline */
- if (ata_port_offline(ap))
+ if (ata_link_offline(dev->link))
ata_eh_detach_dev(dev);
/* probe if requested */
@@ -2115,12 +2479,16 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
ehc->did_probe_mask |= (1 << dev->devno);
ehc->i.action |= ATA_EH_SOFTRESET;
}
+
+ return 1;
} else {
/* soft didn't work? be haaaaard */
if (ehc->i.flags & ATA_EHI_DID_RESET)
ehc->i.action |= ATA_EH_HARDRESET;
else
ehc->i.action |= ATA_EH_SOFTRESET;
+
+ return 0;
}
}
@@ -2131,12 +2499,13 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
* @softreset: softreset method (can be NULL)
* @hardreset: hardreset method (can be NULL)
* @postreset: postreset method (can be NULL)
+ * @r_failed_link: out parameter for failed link
*
* This is the alpha and omega, eum and yang, heart and soul of
* libata exception handling. On entry, actions required to
- * recover the port and hotplug requests are recorded in
- * eh_context. This function executes all the operations with
- * appropriate retrials and fallbacks to resurrect failed
+ * recover each link and hotplug requests are recorded in the
+ * link's eh_context. This function executes all the operations
+ * with appropriate retrials and fallbacks to resurrect failed
* devices, detach goners and greet newcomers.
*
* LOCKING:
@@ -2145,104 +2514,175 @@ static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
* RETURNS:
* 0 on success, -errno on failure.
*/
-static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
- ata_postreset_fn_t postreset)
+int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset,
+ struct ata_link **r_failed_link)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_link *link;
struct ata_device *dev;
- int i, rc;
+ int nr_failed_devs, nr_disabled_devs;
+ int reset, rc;
+ unsigned long flags;
DPRINTK("ENTER\n");
/* prep for recovery */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
-
- ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
-
- /* collect port action mask recorded in dev actions */
- ehc->i.action |= ehc->i.dev_action[i] & ~ATA_EH_PERDEV_MASK;
- ehc->i.dev_action[i] &= ATA_EH_PERDEV_MASK;
-
- /* process hotplug request */
- if (dev->flags & ATA_DFLAG_DETACH)
- ata_eh_detach_dev(dev);
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
+
+ /* re-enable link? */
+ if (ehc->i.action & ATA_EH_ENABLE_LINK) {
+ ata_eh_about_to_do(link, NULL, ATA_EH_ENABLE_LINK);
+ spin_lock_irqsave(ap->lock, flags);
+ link->flags &= ~ATA_LFLAG_DISABLED;
+ spin_unlock_irqrestore(ap->lock, flags);
+ ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK);
+ }
- if (!ata_dev_enabled(dev) &&
- ((ehc->i.probe_mask & (1 << dev->devno)) &&
- !(ehc->did_probe_mask & (1 << dev->devno)))) {
- ata_eh_detach_dev(dev);
- ata_dev_init(dev);
- ehc->did_probe_mask |= (1 << dev->devno);
- ehc->i.action |= ATA_EH_SOFTRESET;
+ ata_link_for_each_dev(dev, link) {
+ if (link->flags & ATA_LFLAG_NO_RETRY)
+ ehc->tries[dev->devno] = 1;
+ else
+ ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+
+ /* collect port action mask recorded in dev actions */
+ ehc->i.action |= ehc->i.dev_action[dev->devno] &
+ ~ATA_EH_PERDEV_MASK;
+ ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK;
+
+ /* process hotplug request */
+ if (dev->flags & ATA_DFLAG_DETACH)
+ ata_eh_detach_dev(dev);
+
+ if (!ata_dev_enabled(dev) &&
+ ((ehc->i.probe_mask & (1 << dev->devno)) &&
+ !(ehc->did_probe_mask & (1 << dev->devno)))) {
+ ata_eh_detach_dev(dev);
+ ata_dev_init(dev);
+ ehc->did_probe_mask |= (1 << dev->devno);
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ }
}
}
retry:
rc = 0;
+ nr_failed_devs = 0;
+ nr_disabled_devs = 0;
+ reset = 0;
/* if UNLOADING, finish immediately */
if (ap->pflags & ATA_PFLAG_UNLOADING)
goto out;
- /* skip EH if possible. */
- if (ata_eh_skip_recovery(ap))
- ehc->i.action = 0;
+ /* prep for EH */
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehc->classes[i] = ATA_DEV_UNKNOWN;
+ /* skip EH if possible. */
+ if (ata_eh_skip_recovery(link))
+ ehc->i.action = 0;
- /* reset */
- if (ehc->i.action & ATA_EH_RESET_MASK) {
- ata_eh_freeze_port(ap);
+ /* do we need to reset? */
+ if (ehc->i.action & ATA_EH_RESET_MASK)
+ reset = 1;
- rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset,
- softreset, hardreset, postreset);
- if (rc) {
- ata_port_printk(ap, KERN_ERR,
- "reset failed, giving up\n");
- goto out;
+ ata_link_for_each_dev(dev, link)
+ ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
+ }
+
+ /* reset */
+ if (reset) {
+ /* if PMP is attached, this function only deals with
+ * downstream links, port should stay thawed.
+ */
+ if (!ap->nr_pmp_links)
+ ata_eh_freeze_port(ap);
+
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
+
+ if (!(ehc->i.action & ATA_EH_RESET_MASK))
+ continue;
+
+ rc = ata_eh_reset(link, ata_link_nr_vacant(link),
+ prereset, softreset, hardreset,
+ postreset);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "reset failed, giving up\n");
+ goto out;
+ }
}
- ata_eh_thaw_port(ap);
+ if (!ap->nr_pmp_links)
+ ata_eh_thaw_port(ap);
}
- /* revalidate existing devices and attach new ones */
- rc = ata_eh_revalidate_and_attach(ap, &dev);
- if (rc)
- goto dev_fail;
+ /* the rest */
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_context *ehc = &link->eh_context;
- /* configure transfer mode if necessary */
- if (ehc->i.flags & ATA_EHI_SETMODE) {
- rc = ata_set_mode(ap, &dev);
+ /* revalidate existing devices and attach new ones */
+ rc = ata_eh_revalidate_and_attach(link, &dev);
if (rc)
goto dev_fail;
- ehc->i.flags &= ~ATA_EHI_SETMODE;
- }
- goto out;
+ /* if PMP got attached, return, pmp EH will take care of it */
+ if (link->device->class == ATA_DEV_PMP) {
+ ehc->i.action = 0;
+ return 0;
+ }
+
+ /* configure transfer mode if necessary */
+ if (ehc->i.flags & ATA_EHI_SETMODE) {
+ rc = ata_set_mode(link, &dev);
+ if (rc)
+ goto dev_fail;
+ ehc->i.flags &= ~ATA_EHI_SETMODE;
+ }
- dev_fail:
- ata_eh_handle_dev_fail(dev, rc);
+ if (ehc->i.action & ATA_EHI_LPM)
+ ata_link_for_each_dev(dev, link)
+ ata_dev_enable_pm(dev, ap->pm_policy);
- if (ata_port_nr_enabled(ap)) {
- ata_port_printk(ap, KERN_WARNING, "failed to recover some "
- "devices, retrying in 5 secs\n");
- ssleep(5);
- } else {
- /* no device left, repeat fast */
- msleep(500);
+ /* this link is okay now */
+ ehc->i.flags = 0;
+ continue;
+
+dev_fail:
+ nr_failed_devs++;
+ if (ata_eh_handle_dev_fail(dev, rc))
+ nr_disabled_devs++;
+
+ if (ap->pflags & ATA_PFLAG_FROZEN) {
+ /* PMP reset requires working host port.
+ * Can't retry if it's frozen.
+ */
+ if (ap->nr_pmp_links)
+ goto out;
+ break;
+ }
}
- goto retry;
+ if (nr_failed_devs) {
+ if (nr_failed_devs != nr_disabled_devs) {
+ ata_port_printk(ap, KERN_WARNING, "failed to recover "
+ "some devices, retrying in 5 secs\n");
+ ssleep(5);
+ } else {
+ /* no device left to recover, repeat fast */
+ msleep(500);
+ }
- out:
- if (rc) {
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ata_dev_disable(&ap->device[i]);
+ goto retry;
}
+ out:
+ if (rc && r_failed_link)
+ *r_failed_link = link;
+
DPRINTK("EXIT, rc=%d\n", rc);
return rc;
}
@@ -2257,7 +2697,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
* LOCKING:
* None.
*/
-static void ata_eh_finish(struct ata_port *ap)
+void ata_eh_finish(struct ata_port *ap)
{
int tag;
@@ -2272,8 +2712,15 @@ static void ata_eh_finish(struct ata_port *ap)
/* FIXME: Once EH migration is complete,
* generate sense data in this function,
* considering both err_mask and tf.
+ *
+ * There's no point in retrying invalid
+ * (detected by libata) and non-IO device
+ * errors (rejected by device). Finish them
+ * immediately.
*/
- if (qc->err_mask & AC_ERR_INVALID)
+ if ((qc->err_mask & AC_ERR_INVALID) ||
+ (!(qc->flags & ATA_QCFLAG_IO) &&
+ qc->err_mask == AC_ERR_DEV))
ata_eh_qc_complete(qc);
else
ata_eh_qc_retry(qc);
@@ -2287,6 +2734,10 @@ static void ata_eh_finish(struct ata_port *ap)
}
}
}
+
+ /* make sure nr_active_links is zero after EH */
+ WARN_ON(ap->nr_active_links);
+ ap->nr_active_links = 0;
}
/**
@@ -2306,9 +2757,19 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset)
{
+ struct ata_device *dev;
+ int rc;
+
ata_eh_autopsy(ap);
ata_eh_report(ap);
- ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
+
+ rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset,
+ NULL);
+ if (rc) {
+ ata_link_for_each_dev(dev, &ap->link)
+ ata_dev_disable(dev);
+ }
+
ata_eh_finish(ap);
}
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
new file mode 100644
index 00000000000..c0c4dbcde09
--- /dev/null
+++ b/drivers/ata/libata-pmp.c
@@ -0,0 +1,1191 @@
+/*
+ * libata-pmp.c - libata port multiplier support
+ *
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/libata.h>
+#include "libata.h"
+
+/**
+ * sata_pmp_read - read PMP register
+ * @link: link to read PMP register for
+ * @reg: register to read
+ * @r_val: resulting value
+ *
+ * Read PMP register.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
+{
+ struct ata_port *ap = link->ap;
+ struct ata_device *pmp_dev = ap->link.device;
+ struct ata_taskfile tf;
+ unsigned int err_mask;
+
+ ata_tf_init(pmp_dev, &tf);
+ tf.command = ATA_CMD_PMP_READ;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.feature = reg;
+ tf.device = link->pmp;
+
+ err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
+ SATA_PMP_SCR_TIMEOUT);
+ if (err_mask)
+ return err_mask;
+
+ *r_val = tf.nsect | tf.lbal << 8 | tf.lbam << 16 | tf.lbah << 24;
+ return 0;
+}
+
+/**
+ * sata_pmp_write - write PMP register
+ * @link: link to write PMP register for
+ * @reg: register to write
+ * @r_val: value to write
+ *
+ * Write PMP register.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val)
+{
+ struct ata_port *ap = link->ap;
+ struct ata_device *pmp_dev = ap->link.device;
+ struct ata_taskfile tf;
+
+ ata_tf_init(pmp_dev, &tf);
+ tf.command = ATA_CMD_PMP_WRITE;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ tf.feature = reg;
+ tf.device = link->pmp;
+ tf.nsect = val & 0xff;
+ tf.lbal = (val >> 8) & 0xff;
+ tf.lbam = (val >> 16) & 0xff;
+ tf.lbah = (val >> 24) & 0xff;
+
+ return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
+ SATA_PMP_SCR_TIMEOUT);
+}
+
+/**
+ * sata_pmp_qc_defer_cmd_switch - qc_defer for command switching PMP
+ * @qc: ATA command in question
+ *
+ * A host which has command switching PMP support cannot issue
+ * commands to multiple links simultaneously.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ * RETURNS:
+ * ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc)
+{
+ struct ata_link *link = qc->dev->link;
+ struct ata_port *ap = link->ap;
+
+ if (ap->excl_link == NULL || ap->excl_link == link) {
+ if (ap->nr_active_links == 0 || ata_link_active(link)) {
+ qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+ return ata_std_qc_defer(qc);
+ }
+
+ ap->excl_link = link;
+ }
+
+ return ATA_DEFER_PORT;
+}
+
+/**
+ * sata_pmp_scr_read - read PSCR
+ * @link: ATA link to read PSCR for
+ * @reg: PSCR to read
+ * @r_val: resulting value
+ *
+ * Read PSCR @reg into @r_val for @link, to be called from
+ * ata_scr_read().
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val)
+{
+ unsigned int err_mask;
+
+ if (reg > SATA_PMP_PSCR_CONTROL)
+ return -EINVAL;
+
+ err_mask = sata_pmp_read(link, reg, r_val);
+ if (err_mask) {
+ ata_link_printk(link, KERN_WARNING, "failed to read SCR %d "
+ "(Emask=0x%x)\n", reg, err_mask);
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ * sata_pmp_scr_write - write PSCR
+ * @link: ATA link to write PSCR for
+ * @reg: PSCR to write
+ * @val: value to be written
+ *
+ * Write @val to PSCR @reg for @link, to be called from
+ * ata_scr_write() and ata_scr_write_flush().
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
+{
+ unsigned int err_mask;
+
+ if (reg > SATA_PMP_PSCR_CONTROL)
+ return -EINVAL;
+
+ err_mask = sata_pmp_write(link, reg, val);
+ if (err_mask) {
+ ata_link_printk(link, KERN_WARNING, "failed to write SCR %d "
+ "(Emask=0x%x)\n", reg, err_mask);
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ * sata_pmp_std_prereset - prepare PMP link for reset
+ * @link: link to be reset
+ * @deadline: deadline jiffies for the operation
+ *
+ * @link is about to be reset. Initialize it.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline)
+{
+ struct ata_eh_context *ehc = &link->eh_context;
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
+ int rc;
+
+ /* force HRST? */
+ if (link->flags & ATA_LFLAG_NO_SRST)
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ /* handle link resume */
+ if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
+ (link->flags & ATA_LFLAG_HRST_TO_RESUME))
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ /* if we're about to do hardreset, nothing more to do */
+ if (ehc->i.action & ATA_EH_HARDRESET)
+ return 0;
+
+ /* resume link */
+ rc = sata_link_resume(link, timing, deadline);
+ if (rc) {
+ /* phy resume failed */
+ ata_link_printk(link, KERN_WARNING, "failed to resume link "
+ "for reset (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* clear SError bits including .X which blocks the port when set */
+ rc = sata_scr_write(link, SCR_ERROR, 0xffffffff);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "failed to clear SError (errno=%d)\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * sata_pmp_std_hardreset - standard hardreset method for PMP link
+ * @link: link to be reset
+ * @class: resulting class of attached device
+ * @deadline: deadline jiffies for the operation
+ *
+ * Hardreset PMP port @link. Note that this function doesn't
+ * wait for BSY clearance. There simply isn't a generic way to
+ * wait the event. Instead, this function return -EAGAIN thus
+ * telling libata-EH to followup with softreset.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+ u32 tmp;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ /* do hardreset */
+ rc = sata_link_hardreset(link, timing, deadline);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "COMRESET failed (errno=%d)\n", rc);
+ goto out;
+ }
+
+ /* clear SError bits including .X which blocks the port when set */
+ rc = sata_scr_write(link, SCR_ERROR, 0xffffffff);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR, "failed to clear SError "
+ "during hardreset (errno=%d)\n", rc);
+ goto out;
+ }
+
+ /* if device is present, follow up with srst to wait for !BSY */
+ if (ata_link_online(link))
+ rc = -EAGAIN;
+ out:
+ /* if SCR isn't accessible, we need to reset the PMP */
+ if (rc && rc != -EAGAIN && sata_scr_read(link, SCR_STATUS, &tmp))
+ rc = -ERESTART;
+
+ DPRINTK("EXIT, rc=%d\n", rc);
+ return rc;
+}
+
+/**
+ * ata_std_postreset - standard postreset method for PMP link
+ * @link: the target ata_link
+ * @classes: classes of attached devices
+ *
+ * This function is invoked after a successful reset. Note that
+ * the device might have been reset more than once using
+ * different reset methods before postreset is invoked.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ */
+void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class)
+{
+ u32 serror;
+
+ DPRINTK("ENTER\n");
+
+ /* clear SError */
+ if (sata_scr_read(link, SCR_ERROR, &serror) == 0)
+ sata_scr_write(link, SCR_ERROR, serror);
+
+ /* print link status */
+ sata_print_link_status(link);
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * sata_pmp_read_gscr - read GSCR block of SATA PMP
+ * @dev: PMP device
+ * @gscr: buffer to read GSCR block into
+ *
+ * Read selected PMP GSCRs from the PMP at @dev. This will serve
+ * as configuration and identification info for the PMP.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr)
+{
+ static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) {
+ int reg = gscr_to_read[i];
+ unsigned int err_mask;
+
+ err_mask = sata_pmp_read(dev->link, reg, &gscr[reg]);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to read PMP "
+ "GSCR[%d] (Emask=0x%x)\n", reg, err_mask);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static const char *sata_pmp_spec_rev_str(const u32 *gscr)
+{
+ u32 rev = gscr[SATA_PMP_GSCR_REV];
+
+ if (rev & (1 << 2))
+ return "1.1";
+ if (rev & (1 << 1))
+ return "1.0";
+ return "<unknown>";
+}
+
+static int sata_pmp_configure(struct ata_device *dev, int print_info)
+{
+ struct ata_port *ap = dev->link->ap;
+ u32 *gscr = dev->gscr;
+ unsigned int err_mask = 0;
+ const char *reason;
+ int nr_ports, rc;
+
+ nr_ports = sata_pmp_gscr_ports(gscr);
+
+ if (nr_ports <= 0 || nr_ports > SATA_PMP_MAX_PORTS) {
+ rc = -EINVAL;
+ reason = "invalid nr_ports";
+ goto fail;
+ }
+
+ if ((ap->flags & ATA_FLAG_AN) &&
+ (gscr[SATA_PMP_GSCR_FEAT] & SATA_PMP_FEAT_NOTIFY))
+ dev->flags |= ATA_DFLAG_AN;
+
+ /* monitor SERR_PHYRDY_CHG on fan-out ports */
+ err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN,
+ SERR_PHYRDY_CHG);
+ if (err_mask) {
+ rc = -EIO;
+ reason = "failed to write GSCR_ERROR_EN";
+ goto fail;
+ }
+
+ /* turn off notification till fan-out ports are reset and configured */
+ if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
+ gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
+
+ err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN,
+ gscr[SATA_PMP_GSCR_FEAT_EN]);
+ if (err_mask) {
+ rc = -EIO;
+ reason = "failed to write GSCR_FEAT_EN";
+ goto fail;
+ }
+ }
+
+ if (print_info) {
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, "
+ "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n",
+ sata_pmp_spec_rev_str(gscr),
+ sata_pmp_gscr_vendor(gscr),
+ sata_pmp_gscr_devid(gscr),
+ sata_pmp_gscr_rev(gscr),
+ nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN],
+ gscr[SATA_PMP_GSCR_FEAT]);
+
+ if (!(dev->flags & ATA_DFLAG_AN))
+ ata_dev_printk(dev, KERN_INFO,
+ "Asynchronous notification not supported, "
+ "hotplug won't\n work on fan-out "
+ "ports. Use warm-plug instead.\n");
+ }
+
+ return 0;
+
+ fail:
+ ata_dev_printk(dev, KERN_ERR,
+ "failed to configure Port Multiplier (%s, Emask=0x%x)\n",
+ reason, err_mask);
+ return rc;
+}
+
+static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
+{
+ struct ata_link *pmp_link = ap->pmp_link;
+ int i;
+
+ if (!pmp_link) {
+ pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS,
+ GFP_NOIO);
+ if (!pmp_link)
+ return -ENOMEM;
+
+ for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+ ata_link_init(ap, &pmp_link[i], i);
+
+ ap->pmp_link = pmp_link;
+ }
+
+ for (i = 0; i < nr_ports; i++) {
+ struct ata_link *link = &pmp_link[i];
+ struct ata_eh_context *ehc = &link->eh_context;
+
+ link->flags = 0;
+ ehc->i.probe_mask |= 1;
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ ehc->i.flags |= ATA_EHI_RESUME_LINK;
+ }
+
+ return 0;
+}
+
+static void sata_pmp_quirks(struct ata_port *ap)
+{
+ u32 *gscr = ap->link.device->gscr;
+ u16 vendor = sata_pmp_gscr_vendor(gscr);
+ u16 devid = sata_pmp_gscr_devid(gscr);
+ struct ata_link *link;
+
+ if (vendor == 0x1095 && devid == 0x3726) {
+ /* sil3726 quirks */
+ ata_port_for_each_link(link, ap) {
+ /* SError.N need a kick in the ass to get working */
+ link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+ /* class code report is unreliable */
+ if (link->pmp < 5)
+ link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+ /* port 5 is for SEMB device and it doesn't like SRST */
+ if (link->pmp == 5)
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_SEMB;
+ }
+ } else if (vendor == 0x1095 && devid == 0x4723) {
+ /* sil4723 quirks */
+ ata_port_for_each_link(link, ap) {
+ /* SError.N need a kick in the ass to get working */
+ link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+ /* class code report is unreliable */
+ if (link->pmp < 2)
+ link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+ /* the config device at port 2 locks up on SRST */
+ if (link->pmp == 2)
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
+ }
+ } else if (vendor == 0x1095 && devid == 0x4726) {
+ /* sil4726 quirks */
+ ata_port_for_each_link(link, ap) {
+ /* SError.N need a kick in the ass to get working */
+ link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+ /* class code report is unreliable */
+ if (link->pmp < 5)
+ link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+ /* The config device, which can be either at
+ * port 0 or 5, locks up on SRST.
+ */
+ if (link->pmp == 0 || link->pmp == 5)
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
+
+ /* Port 6 is for SEMB device which doesn't
+ * like SRST either.
+ */
+ if (link->pmp == 6)
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_SEMB;
+ }
+ } else if (vendor == 0x1095 && (devid == 0x5723 || devid == 0x5733 ||
+ devid == 0x5734 || devid == 0x5744)) {
+ /* sil5723/5744 quirks */
+
+ /* sil5723/5744 has either two or three downstream
+ * ports depending on operation mode. The last port
+ * is empty if any actual IO device is available or
+ * occupied by a pseudo configuration device
+ * otherwise. Don't try hard to recover it.
+ */
+ ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
+ } else if (vendor == 0x11ab && devid == 0x4140) {
+ /* Marvell 88SM4140 quirks. Fan-out ports require PHY
+ * reset to work; other than that, it behaves very
+ * nicely.
+ */
+ ata_port_for_each_link(link, ap)
+ link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+ }
+}
+
+/**
+ * sata_pmp_attach - attach a SATA PMP device
+ * @dev: SATA PMP device to attach
+ *
+ * Configure and attach SATA PMP device @dev. This function is
+ * also responsible for allocating and initializing PMP links.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int sata_pmp_attach(struct ata_device *dev)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ unsigned long flags;
+ struct ata_link *tlink;
+ int rc;
+
+ /* is it hanging off the right place? */
+ if (!(ap->flags & ATA_FLAG_PMP)) {
+ ata_dev_printk(dev, KERN_ERR,
+ "host does not support Port Multiplier\n");
+ return -EINVAL;
+ }
+
+ if (!ata_is_host_link(link)) {
+ ata_dev_printk(dev, KERN_ERR,
+ "Port Multipliers cannot be nested\n");
+ return -EINVAL;
+ }
+
+ if (dev->devno) {
+ ata_dev_printk(dev, KERN_ERR,
+ "Port Multiplier must be the first device\n");
+ return -EINVAL;
+ }
+
+ WARN_ON(link->pmp != 0);
+ link->pmp = SATA_PMP_CTRL_PORT;
+
+ /* read GSCR block */
+ rc = sata_pmp_read_gscr(dev, dev->gscr);
+ if (rc)
+ goto fail;
+
+ /* config PMP */
+ rc = sata_pmp_configure(dev, 1);
+ if (rc)
+ goto fail;
+
+ rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr));
+ if (rc) {
+ ata_dev_printk(dev, KERN_INFO,
+ "failed to initialize PMP links\n");
+ goto fail;
+ }
+
+ /* attach it */
+ spin_lock_irqsave(ap->lock, flags);
+ WARN_ON(ap->nr_pmp_links);
+ ap->nr_pmp_links = sata_pmp_gscr_ports(dev->gscr);
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ sata_pmp_quirks(ap);
+
+ if (ap->ops->pmp_attach)
+ ap->ops->pmp_attach(ap);
+
+ ata_port_for_each_link(tlink, ap)
+ sata_link_init_spd(tlink);
+
+ ata_acpi_associate_sata_port(ap);
+
+ return 0;
+
+ fail:
+ link->pmp = 0;
+ return rc;
+}
+
+/**
+ * sata_pmp_detach - detach a SATA PMP device
+ * @dev: SATA PMP device to detach
+ *
+ * Detach SATA PMP device @dev. This function is also
+ * responsible for deconfiguring PMP links.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void sata_pmp_detach(struct ata_device *dev)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ struct ata_link *tlink;
+ unsigned long flags;
+
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier detaching\n");
+
+ WARN_ON(!ata_is_host_link(link) || dev->devno ||
+ link->pmp != SATA_PMP_CTRL_PORT);
+
+ if (ap->ops->pmp_detach)
+ ap->ops->pmp_detach(ap);
+
+ ata_port_for_each_link(tlink, ap)
+ ata_eh_detach_dev(tlink->device);
+
+ spin_lock_irqsave(ap->lock, flags);
+ ap->nr_pmp_links = 0;
+ link->pmp = 0;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_acpi_associate_sata_port(ap);
+}
+
+/**
+ * sata_pmp_same_pmp - does new GSCR matches the configured PMP?
+ * @dev: PMP device to compare against
+ * @new_gscr: GSCR block of the new device
+ *
+ * Compare @new_gscr against @dev and determine whether @dev is
+ * the PMP described by @new_gscr.
+ *
+ * LOCKING:
+ * None.
+ *
+ * RETURNS:
+ * 1 if @dev matches @new_gscr, 0 otherwise.
+ */
+static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr)
+{
+ const u32 *old_gscr = dev->gscr;
+ u16 old_vendor, new_vendor, old_devid, new_devid;
+ int old_nr_ports, new_nr_ports;
+
+ old_vendor = sata_pmp_gscr_vendor(old_gscr);
+ new_vendor = sata_pmp_gscr_vendor(new_gscr);
+ old_devid = sata_pmp_gscr_devid(old_gscr);
+ new_devid = sata_pmp_gscr_devid(new_gscr);
+ old_nr_ports = sata_pmp_gscr_ports(old_gscr);
+ new_nr_ports = sata_pmp_gscr_ports(new_gscr);
+
+ if (old_vendor != new_vendor) {
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+ "vendor mismatch '0x%x' != '0x%x'\n",
+ old_vendor, new_vendor);
+ return 0;
+ }
+
+ if (old_devid != new_devid) {
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+ "device ID mismatch '0x%x' != '0x%x'\n",
+ old_devid, new_devid);
+ return 0;
+ }
+
+ if (old_nr_ports != new_nr_ports) {
+ ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+ "nr_ports mismatch '0x%x' != '0x%x'\n",
+ old_nr_ports, new_nr_ports);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * sata_pmp_revalidate - revalidate SATA PMP
+ * @dev: PMP device to revalidate
+ * @new_class: new class code
+ *
+ * Re-read GSCR block and make sure @dev is still attached to the
+ * port and properly configured.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class)
+{
+ struct ata_link *link = dev->link;
+ struct ata_port *ap = link->ap;
+ u32 *gscr = (void *)ap->sector_buf;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ ata_eh_about_to_do(link, NULL, ATA_EH_REVALIDATE);
+
+ if (!ata_dev_enabled(dev)) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ /* wrong class? */
+ if (ata_class_enabled(new_class) && new_class != ATA_DEV_PMP) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ /* read GSCR */
+ rc = sata_pmp_read_gscr(dev, gscr);
+ if (rc)
+ goto fail;
+
+ /* is the pmp still there? */
+ if (!sata_pmp_same_pmp(dev, gscr)) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ memcpy(dev->gscr, gscr, sizeof(gscr[0]) * SATA_PMP_GSCR_DWORDS);
+
+ rc = sata_pmp_configure(dev, 0);
+ if (rc)
+ goto fail;
+
+ ata_eh_done(link, NULL, ATA_EH_REVALIDATE);
+
+ DPRINTK("EXIT, rc=0\n");
+ return 0;
+
+ fail:
+ ata_dev_printk(dev, KERN_ERR,
+ "PMP revalidation failed (errno=%d)\n", rc);
+ DPRINTK("EXIT, rc=%d\n", rc);
+ return rc;
+}
+
+/**
+ * sata_pmp_revalidate_quick - revalidate SATA PMP quickly
+ * @dev: PMP device to revalidate
+ *
+ * Make sure the attached PMP is accessible.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int sata_pmp_revalidate_quick(struct ata_device *dev)
+{
+ unsigned int err_mask;
+ u32 prod_id;
+
+ err_mask = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID "
+ "(Emask=0x%x)\n", err_mask);
+ return -EIO;
+ }
+
+ if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) {
+ ata_dev_printk(dev, KERN_ERR, "PMP product ID mismatch\n");
+ /* something weird is going on, request full PMP recovery */
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * sata_pmp_eh_recover_pmp - recover PMP
+ * @ap: ATA port PMP is attached to
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method
+ * @hardreset: hardreset method
+ * @postreset: postreset method (can be NULL)
+ *
+ * Recover PMP attached to @ap. Recovery procedure is somewhat
+ * similar to that of ata_eh_recover() except that reset should
+ * always be performed in hard->soft sequence and recovery
+ * failure results in PMP detachment.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+{
+ struct ata_link *link = &ap->link;
+ struct ata_eh_context *ehc = &link->eh_context;
+ struct ata_device *dev = link->device;
+ int tries = ATA_EH_PMP_TRIES;
+ int detach = 0, rc = 0;
+ int reval_failed = 0;
+
+ DPRINTK("ENTER\n");
+
+ if (dev->flags & ATA_DFLAG_DETACH) {
+ detach = 1;
+ goto fail;
+ }
+
+ retry:
+ ehc->classes[0] = ATA_DEV_UNKNOWN;
+
+ if (ehc->i.action & ATA_EH_RESET_MASK) {
+ struct ata_link *tlink;
+
+ ata_eh_freeze_port(ap);
+
+ /* reset */
+ ehc->i.action = ATA_EH_HARDRESET;
+ rc = ata_eh_reset(link, 0, prereset, softreset, hardreset,
+ postreset);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "failed to reset PMP, giving up\n");
+ goto fail;
+ }
+
+ ata_eh_thaw_port(ap);
+
+ /* PMP is reset, SErrors cannot be trusted, scan all */
+ ata_port_for_each_link(tlink, ap)
+ ata_ehi_schedule_probe(&tlink->eh_context.i);
+ }
+
+ /* If revalidation is requested, revalidate and reconfigure;
+ * otherwise, do quick revalidation.
+ */
+ if (ehc->i.action & ATA_EH_REVALIDATE)
+ rc = sata_pmp_revalidate(dev, ehc->classes[0]);
+ else
+ rc = sata_pmp_revalidate_quick(dev);
+
+ if (rc) {
+ tries--;
+
+ if (rc == -ENODEV) {
+ ehc->i.probe_mask |= 1;
+ detach = 1;
+ /* give it just two more chances */
+ tries = min(tries, 2);
+ }
+
+ if (tries) {
+ int sleep = ehc->i.flags & ATA_EHI_DID_RESET;
+
+ /* consecutive revalidation failures? speed down */
+ if (reval_failed)
+ sata_down_spd_limit(link);
+ else
+ reval_failed = 1;
+
+ ata_dev_printk(dev, KERN_WARNING,
+ "retrying hardreset%s\n",
+ sleep ? " in 5 secs" : "");
+ if (sleep)
+ ssleep(5);
+ ehc->i.action |= ATA_EH_HARDRESET;
+ goto retry;
+ } else {
+ ata_dev_printk(dev, KERN_ERR, "failed to recover PMP "
+ "after %d tries, giving up\n",
+ ATA_EH_PMP_TRIES);
+ goto fail;
+ }
+ }
+
+ /* okay, PMP resurrected */
+ ehc->i.flags = 0;
+
+ DPRINTK("EXIT, rc=0\n");
+ return 0;
+
+ fail:
+ sata_pmp_detach(dev);
+ if (detach)
+ ata_eh_detach_dev(dev);
+ else
+ ata_dev_disable(dev);
+
+ DPRINTK("EXIT, rc=%d\n", rc);
+ return rc;
+}
+
+static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap)
+{
+ struct ata_link *link;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ ata_port_for_each_link(link, ap) {
+ if (!(link->flags & ATA_LFLAG_DISABLED))
+ continue;
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* Some PMPs require hardreset sequence to get
+ * SError.N working.
+ */
+ if ((link->flags & ATA_LFLAG_HRST_TO_RESUME) &&
+ (link->eh_context.i.flags & ATA_EHI_RESUME_LINK))
+ sata_link_hardreset(link, sata_deb_timing_normal,
+ jiffies + ATA_TMOUT_INTERNAL_QUICK);
+
+ /* unconditionally clear SError.N */
+ rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR, "failed to clear "
+ "SError.N (errno=%d)\n", rc);
+ return rc;
+ }
+
+ spin_lock_irqsave(ap->lock, flags);
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return 0;
+}
+
+static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries)
+{
+ struct ata_port *ap = link->ap;
+ unsigned long flags;
+
+ if (link_tries[link->pmp] && --link_tries[link->pmp])
+ return 1;
+
+ /* disable this link */
+ if (!(link->flags & ATA_LFLAG_DISABLED)) {
+ ata_link_printk(link, KERN_WARNING,
+ "failed to recover link after %d tries, disabling\n",
+ ATA_EH_PMP_LINK_TRIES);
+
+ spin_lock_irqsave(ap->lock, flags);
+ link->flags |= ATA_LFLAG_DISABLED;
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+
+ ata_dev_disable(link->device);
+ link->eh_context.i.action = 0;
+
+ return 0;
+}
+
+/**
+ * sata_pmp_eh_recover - recover PMP-enabled port
+ * @ap: ATA port to recover
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method
+ * @hardreset: hardreset method
+ * @postreset: postreset method (can be NULL)
+ * @pmp_prereset: PMP prereset method (can be NULL)
+ * @pmp_softreset: PMP softreset method (can be NULL)
+ * @pmp_hardreset: PMP hardreset method (can be NULL)
+ * @pmp_postreset: PMP postreset method (can be NULL)
+ *
+ * Drive EH recovery operation for PMP enabled port @ap. This
+ * function recovers host and PMP ports with proper retrials and
+ * fallbacks. Actual recovery operations are performed using
+ * ata_eh_recover() and sata_pmp_eh_recover_pmp().
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+static int sata_pmp_eh_recover(struct ata_port *ap,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+ ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+ ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset)
+{
+ int pmp_tries, link_tries[SATA_PMP_MAX_PORTS];
+ struct ata_link *pmp_link = &ap->link;
+ struct ata_device *pmp_dev = pmp_link->device;
+ struct ata_eh_context *pmp_ehc = &pmp_link->eh_context;
+ struct ata_link *link;
+ struct ata_device *dev;
+ unsigned int err_mask;
+ u32 gscr_error, sntf;
+ int cnt, rc;
+
+ pmp_tries = ATA_EH_PMP_TRIES;
+ ata_port_for_each_link(link, ap)
+ link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
+
+ retry:
+ /* PMP attached? */
+ if (!ap->nr_pmp_links) {
+ rc = ata_eh_recover(ap, prereset, softreset, hardreset,
+ postreset, NULL);
+ if (rc) {
+ ata_link_for_each_dev(dev, &ap->link)
+ ata_dev_disable(dev);
+ return rc;
+ }
+
+ if (pmp_dev->class != ATA_DEV_PMP)
+ return 0;
+
+ /* new PMP online */
+ ata_port_for_each_link(link, ap)
+ link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
+
+ /* fall through */
+ }
+
+ /* recover pmp */
+ rc = sata_pmp_eh_recover_pmp(ap, prereset, softreset, hardreset,
+ postreset);
+ if (rc)
+ goto pmp_fail;
+
+ /* handle disabled links */
+ rc = sata_pmp_eh_handle_disabled_links(ap);
+ if (rc)
+ goto pmp_fail;
+
+ /* recover links */
+ rc = ata_eh_recover(ap, pmp_prereset, pmp_softreset, pmp_hardreset,
+ pmp_postreset, &link);
+ if (rc)
+ goto link_fail;
+
+ /* Connection status might have changed while resetting other
+ * links, check SATA_PMP_GSCR_ERROR before returning.
+ */
+
+ /* clear SNotification */
+ rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+ if (rc == 0)
+ sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+ /* enable notification */
+ if (pmp_dev->flags & ATA_DFLAG_AN) {
+ pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
+
+ err_mask = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN,
+ pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]);
+ if (err_mask) {
+ ata_dev_printk(pmp_dev, KERN_ERR, "failed to write "
+ "PMP_FEAT_EN (Emask=0x%x)\n", err_mask);
+ rc = -EIO;
+ goto pmp_fail;
+ }
+ }
+
+ /* check GSCR_ERROR */
+ err_mask = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error);
+ if (err_mask) {
+ ata_dev_printk(pmp_dev, KERN_ERR, "failed to read "
+ "PMP_GSCR_ERROR (Emask=0x%x)\n", err_mask);
+ rc = -EIO;
+ goto pmp_fail;
+ }
+
+ cnt = 0;
+ ata_port_for_each_link(link, ap) {
+ if (!(gscr_error & (1 << link->pmp)))
+ continue;
+
+ if (sata_pmp_handle_link_fail(link, link_tries)) {
+ ata_ehi_hotplugged(&link->eh_context.i);
+ cnt++;
+ } else {
+ ata_link_printk(link, KERN_WARNING,
+ "PHY status changed but maxed out on retries, "
+ "giving up\n");
+ ata_link_printk(link, KERN_WARNING,
+ "Manully issue scan to resume this link\n");
+ }
+ }
+
+ if (cnt) {
+ ata_port_printk(ap, KERN_INFO, "PMP SError.N set for some "
+ "ports, repeating recovery\n");
+ goto retry;
+ }
+
+ return 0;
+
+ link_fail:
+ if (sata_pmp_handle_link_fail(link, link_tries)) {
+ pmp_ehc->i.action |= ATA_EH_HARDRESET;
+ goto retry;
+ }
+
+ /* fall through */
+ pmp_fail:
+ /* Control always ends up here after detaching PMP. Shut up
+ * and return if we're unloading.
+ */
+ if (ap->pflags & ATA_PFLAG_UNLOADING)
+ return rc;
+
+ if (!ap->nr_pmp_links)
+ goto retry;
+
+ if (--pmp_tries) {
+ ata_port_printk(ap, KERN_WARNING,
+ "failed to recover PMP, retrying in 5 secs\n");
+ pmp_ehc->i.action |= ATA_EH_HARDRESET;
+ ssleep(5);
+ goto retry;
+ }
+
+ ata_port_printk(ap, KERN_ERR,
+ "failed to recover PMP after %d tries, giving up\n",
+ ATA_EH_PMP_TRIES);
+ sata_pmp_detach(pmp_dev);
+ ata_dev_disable(pmp_dev);
+
+ return rc;
+}
+
+/**
+ * sata_pmp_do_eh - do standard error handling for PMP-enabled host
+ * @ap: host port to handle error for
+ * @prereset: prereset method (can be NULL)
+ * @softreset: softreset method
+ * @hardreset: hardreset method
+ * @postreset: postreset method (can be NULL)
+ * @pmp_prereset: PMP prereset method (can be NULL)
+ * @pmp_softreset: PMP softreset method (can be NULL)
+ * @pmp_hardreset: PMP hardreset method (can be NULL)
+ * @pmp_postreset: PMP postreset method (can be NULL)
+ *
+ * Perform standard error handling sequence for PMP-enabled host
+ * @ap.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+void sata_pmp_do_eh(struct ata_port *ap,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+ ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+ ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset)
+{
+ ata_eh_autopsy(ap);
+ ata_eh_report(ap);
+ sata_pmp_eh_recover(ap, prereset, softreset, hardreset, postreset,
+ pmp_prereset, pmp_softreset, pmp_hardreset,
+ pmp_postreset);
+ ata_eh_finish(ap);
+}
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index e83647651b3..94144ed50a6 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -45,7 +45,7 @@
#include <scsi/scsi_transport.h>
#include <linux/libata.h>
#include <linux/hdreg.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include "libata.h"
@@ -53,9 +53,9 @@
typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc);
-static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
+static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
const struct scsi_device *scsidev);
-static struct ata_device * ata_scsi_find_dev(struct ata_port *ap,
+static struct ata_device *ata_scsi_find_dev(struct ata_port *ap,
const struct scsi_device *scsidev);
static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, unsigned int lun);
@@ -71,11 +71,10 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
#define ALL_SUB_MPAGES 0xff
-static const u8 def_rw_recovery_mpage[] = {
+static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = {
RW_RECOVERY_MPAGE,
RW_RECOVERY_MPAGE_LEN - 2,
- (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */
- (1 << 6), /* ARRE (auto read reallocation) */
+ (1 << 7), /* AWRE */
0, /* read retry count */
0, 0, 0, 0,
0, /* write retry count */
@@ -111,6 +110,74 @@ static struct scsi_transport_template ata_scsi_transport_template = {
};
+static const struct {
+ enum link_pm value;
+ const char *name;
+} link_pm_policy[] = {
+ { NOT_AVAILABLE, "max_performance" },
+ { MIN_POWER, "min_power" },
+ { MAX_PERFORMANCE, "max_performance" },
+ { MEDIUM_POWER, "medium_power" },
+};
+
+static const char *ata_scsi_lpm_get(enum link_pm policy)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(link_pm_policy); i++)
+ if (link_pm_policy[i].value == policy)
+ return link_pm_policy[i].name;
+
+ return NULL;
+}
+
+static ssize_t ata_scsi_lpm_put(struct class_device *class_dev,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(class_dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ enum link_pm policy = 0;
+ int i;
+
+ /*
+ * we are skipping array location 0 on purpose - this
+ * is because a value of NOT_AVAILABLE is displayed
+ * to the user as max_performance, but when the user
+ * writes "max_performance", they actually want the
+ * value to match MAX_PERFORMANCE.
+ */
+ for (i = 1; i < ARRAY_SIZE(link_pm_policy); i++) {
+ const int len = strlen(link_pm_policy[i].name);
+ if (strncmp(link_pm_policy[i].name, buf, len) == 0 &&
+ buf[len] == '\n') {
+ policy = link_pm_policy[i].value;
+ break;
+ }
+ }
+ if (!policy)
+ return -EINVAL;
+
+ ata_lpm_schedule(ap, policy);
+ return count;
+}
+
+static ssize_t
+ata_scsi_lpm_show(struct class_device *class_dev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(class_dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ const char *policy =
+ ata_scsi_lpm_get(ap->pm_policy);
+
+ if (!policy)
+ return -EINVAL;
+
+ return snprintf(buf, 23, "%s\n", policy);
+}
+CLASS_DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
+ ata_scsi_lpm_show, ata_scsi_lpm_put);
+EXPORT_SYMBOL_GPL(class_device_attr_link_power_management_policy);
+
static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
@@ -229,7 +296,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
scsi_cmd[1] = (4 << 1); /* PIO Data-in */
scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev,
- block count in sector count field */
+ block count in sector count field */
data_dir = DMA_FROM_DEVICE;
} else {
scsi_cmd[1] = (3 << 1); /* Non-data */
@@ -253,7 +320,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
/* Good values for timeout and retries? Values below
from scsi_ioctl_send_command() for default case... */
cmd_result = scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, argsize,
- sensebuf, (10*HZ), 5, 0);
+ sensebuf, (10*HZ), 5, 0);
if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */
u8 *desc = sensebuf + 8;
@@ -264,18 +331,18 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
if (cmd_result & SAM_STAT_CHECK_CONDITION) {
struct scsi_sense_hdr sshdr;
scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE,
- &sshdr);
- if (sshdr.sense_key==0 &&
- sshdr.asc==0 && sshdr.ascq==0)
+ &sshdr);
+ if (sshdr.sense_key == 0 &&
+ sshdr.asc == 0 && sshdr.ascq == 0)
cmd_result &= ~SAM_STAT_CHECK_CONDITION;
}
/* Send userspace a few ATA registers (same as drivers/ide) */
- if (sensebuf[0] == 0x72 && /* format is "descriptor" */
- desc[0] == 0x09 ) { /* code is "ATA Descriptor" */
- args[0] = desc[13]; /* status */
- args[1] = desc[3]; /* error */
- args[2] = desc[5]; /* sector count (0:7) */
+ if (sensebuf[0] == 0x72 && /* format is "descriptor" */
+ desc[0] == 0x09) { /* code is "ATA Descriptor" */
+ args[0] = desc[13]; /* status */
+ args[1] = desc[3]; /* error */
+ args[2] = desc[5]; /* sector count (0:7) */
if (copy_to_user(arg, args, sizeof(args)))
rc = -EFAULT;
}
@@ -351,8 +418,8 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
struct scsi_sense_hdr sshdr;
scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE,
&sshdr);
- if (sshdr.sense_key==0 &&
- sshdr.asc==0 && sshdr.ascq==0)
+ if (sshdr.sense_key == 0 &&
+ sshdr.asc == 0 && sshdr.ascq == 0)
cmd_result &= ~SAM_STAT_CHECK_CONDITION;
}
@@ -450,13 +517,8 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
qc->scsicmd = cmd;
qc->scsidone = done;
- if (cmd->use_sg) {
- qc->__sg = (struct scatterlist *) cmd->request_buffer;
- qc->n_elem = cmd->use_sg;
- } else if (cmd->request_bufflen) {
- qc->__sg = &qc->sgent;
- qc->n_elem = 1;
- }
+ qc->__sg = scsi_sglist(cmd);
+ qc->n_elem = scsi_sg_count(cmd);
} else {
cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
done(cmd);
@@ -755,6 +817,13 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
{
sdev->use_10_for_rw = 1;
sdev->use_10_for_ms = 1;
+
+ /* Schedule policy is determined by ->qc_defer() callback and
+ * it needs to see every deferred qc. Set dev_blocked to 1 to
+ * prevent SCSI midlayer from automatically deferring
+ * requests.
+ */
+ sdev->max_device_blocked = 1;
}
static void ata_scsi_dev_config(struct scsi_device *sdev,
@@ -772,6 +841,9 @@ static void ata_scsi_dev_config(struct scsi_device *sdev,
blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
}
+ if (dev->flags & ATA_DFLAG_AN)
+ set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events);
+
if (dev->flags & ATA_DFLAG_NCQ) {
int depth;
@@ -800,8 +872,6 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
ata_scsi_sdev_config(sdev);
- blk_queue_max_phys_segments(sdev->request_queue, LIBATA_MAX_PRD);
-
sdev->manage_start_stop = 1;
if (dev)
@@ -943,6 +1013,13 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
goto invalid_fld; /* LOEJ bit set not supported */
if (((cdb[4] >> 4) & 0xf) != 0)
goto invalid_fld; /* power conditions not supported */
+
+ if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) {
+ /* the device lacks PM support, finish without doing anything */
+ scmd->result = SAM_STAT_GOOD;
+ return 1;
+ }
+
if (cdb[4] & 0x1) {
tf->nsect = 1; /* 1 sector, lba=0 */
@@ -969,7 +1046,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc)
if ((qc->dev->flags & ATA_DFLAG_SPUNDOWN) &&
(system_state == SYSTEM_HALT ||
system_state == SYSTEM_POWER_OFF)) {
- static unsigned long warned = 0;
+ static unsigned long warned;
if (!test_and_set_bit(0, &warned)) {
ata_dev_printk(qc->dev, KERN_WARNING,
@@ -1034,6 +1111,9 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc)
else
tf->command = ATA_CMD_FLUSH;
+ /* flush is critical for IO integrity, consider it an IO command */
+ qc->flags |= ATA_QCFLAG_IO;
+
return 0;
}
@@ -1357,29 +1437,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct scsi_cmnd *cmd = qc->scsicmd;
u8 *cdb = cmd->cmnd;
- int need_sense = (qc->err_mask != 0);
-
- /* We snoop the SET_FEATURES - Write Cache ON/OFF command, and
- * schedule EH_REVALIDATE operation to update the IDENTIFY DEVICE
- * cache
- */
- if (ap->ops->error_handler && !need_sense) {
- switch (qc->tf.command) {
- case ATA_CMD_SET_FEATURES:
- if ((qc->tf.feature == SETFEATURES_WC_ON) ||
- (qc->tf.feature == SETFEATURES_WC_OFF)) {
- ap->eh_info.action |= ATA_EH_REVALIDATE;
- ata_port_schedule_eh(ap);
- }
- break;
-
- case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */
- case ATA_CMD_SET_MULTI: /* multi_count changed */
- ap->eh_info.action |= ATA_EH_REVALIDATE;
- ata_port_schedule_eh(ap);
- break;
- }
- }
+ int need_sense = (qc->err_mask != 0);
/* For ATA pass thru (SAT) commands, generate a sense block if
* user mandated it or if there's an error. Note that if we
@@ -1389,7 +1447,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
* was no error, SK, ASC and ASCQ will all be zero.
*/
if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) &&
- ((cdb[2] & 0x20) || need_sense)) {
+ ((cdb[2] & 0x20) || need_sense)) {
ata_gen_passthru_sense(qc);
} else {
if (!need_sense) {
@@ -1422,37 +1480,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
}
/**
- * ata_scmd_need_defer - Check whether we need to defer scmd
- * @dev: ATA device to which the command is addressed
- * @is_io: Is the command IO (and thus possibly NCQ)?
- *
- * NCQ and non-NCQ commands cannot run together. As upper layer
- * only knows the queue depth, we are responsible for maintaining
- * exclusion. This function checks whether a new command can be
- * issued to @dev.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- *
- * RETURNS:
- * 1 if deferring is needed, 0 otherwise.
- */
-static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
-{
- struct ata_port *ap = dev->ap;
- int is_ncq = is_io && ata_ncq_enabled(dev);
-
- if (is_ncq) {
- if (!ata_tag_valid(ap->active_tag))
- return 0;
- } else {
- if (!ata_tag_valid(ap->active_tag) && !ap->sactive)
- return 0;
- }
- return 1;
-}
-
-/**
* ata_scsi_translate - Translate then issue SCSI command to ATA device
* @dev: ATA device to which the command is addressed
* @cmd: SCSI command to execute
@@ -1483,14 +1510,12 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *),
ata_xlat_func_t xlat_func)
{
+ struct ata_port *ap = dev->link->ap;
struct ata_queued_cmd *qc;
- int is_io = xlat_func == ata_scsi_rw_xlat;
+ int rc;
VPRINTK("ENTER\n");
- if (unlikely(ata_scmd_need_defer(dev, is_io)))
- goto defer;
-
qc = ata_scsi_qc_new(dev, cmd, done);
if (!qc)
goto err_mem;
@@ -1498,17 +1523,13 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
/* data is present; dma-map it */
if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
cmd->sc_data_direction == DMA_TO_DEVICE) {
- if (unlikely(cmd->request_bufflen < 1)) {
+ if (unlikely(scsi_bufflen(cmd) < 1)) {
ata_dev_printk(dev, KERN_WARNING,
"WARNING: zero len r/w req\n");
goto err_did;
}
- if (cmd->use_sg)
- ata_sg_init(qc, cmd->request_buffer, cmd->use_sg);
- else
- ata_sg_init_one(qc, cmd->request_buffer,
- cmd->request_bufflen);
+ ata_sg_init(qc, scsi_sglist(cmd), scsi_sg_count(cmd));
qc->dma_dir = cmd->sc_data_direction;
}
@@ -1518,6 +1539,11 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
if (xlat_func(qc))
goto early_finish;
+ if (ap->ops->qc_defer) {
+ if ((rc = ap->ops->qc_defer(qc)))
+ goto defer;
+ }
+
/* select device, send command to hardware */
ata_qc_issue(qc);
@@ -1525,7 +1551,7 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,
return 0;
early_finish:
- ata_qc_free(qc);
+ ata_qc_free(qc);
qc->scsidone(cmd);
DPRINTK("EXIT - early finish (good or error)\n");
return 0;
@@ -1539,8 +1565,12 @@ err_mem:
return 0;
defer:
+ ata_qc_free(qc);
DPRINTK("EXIT - defer\n");
- return SCSI_MLQUEUE_DEVICE_BUSY;
+ if (rc == ATA_DEFER_LINK)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ else
+ return SCSI_MLQUEUE_HOST_BUSY;
}
/**
@@ -1562,15 +1592,14 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
u8 *buf;
unsigned int buflen;
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ struct scatterlist *sg = scsi_sglist(cmd);
- sg = (struct scatterlist *) cmd->request_buffer;
- buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ if (sg) {
+ buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
buflen = sg->length;
} else {
- buf = cmd->request_buffer;
- buflen = cmd->request_bufflen;
+ buf = NULL;
+ buflen = 0;
}
*buf_out = buf;
@@ -1590,12 +1619,9 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
{
- if (cmd->use_sg) {
- struct scatterlist *sg;
-
- sg = (struct scatterlist *) cmd->request_buffer;
+ struct scatterlist *sg = scsi_sglist(cmd);
+ if (sg)
kunmap_atomic(buf - sg->offset, KM_IRQ0);
- }
}
/**
@@ -1615,8 +1641,8 @@ static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
*/
void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
- unsigned int (*actor) (struct ata_scsi_args *args,
- u8 *rbuf, unsigned int buflen))
+ unsigned int (*actor) (struct ata_scsi_args *args,
+ u8 *rbuf, unsigned int buflen))
{
u8 *rbuf;
unsigned int buflen, rc;
@@ -1817,6 +1843,62 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
}
/**
+ * ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info
+ * @args: device IDENTIFY data / SCSI command of interest.
+ * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ * @buflen: Response buffer length.
+ *
+ * Yields SAT-specified ATA VPD page.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+
+unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
+ unsigned int buflen)
+{
+ u8 pbuf[60];
+ struct ata_taskfile tf;
+ unsigned int i;
+
+ if (!buflen)
+ return 0;
+
+ memset(&pbuf, 0, sizeof(pbuf));
+ memset(&tf, 0, sizeof(tf));
+
+ pbuf[1] = 0x89; /* our page code */
+ pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */
+ pbuf[3] = (0x238 & 0xff);
+
+ memcpy(&pbuf[8], "linux ", 8);
+ memcpy(&pbuf[16], "libata ", 16);
+ memcpy(&pbuf[32], DRV_VERSION, 4);
+ ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4);
+
+ /* we don't store the ATA device signature, so we fake it */
+
+ tf.command = ATA_DRDY; /* really, this is Status reg */
+ tf.lbal = 0x1;
+ tf.nsect = 0x1;
+
+ ata_tf_to_fis(&tf, 0, 1, &pbuf[36]); /* TODO: PMP? */
+ pbuf[36] = 0x34; /* force D2H Reg FIS (34h) */
+
+ pbuf[56] = ATA_CMD_ID_ATA;
+
+ i = min(buflen, 60U);
+ memcpy(rbuf, &pbuf[0], i);
+ buflen -= i;
+
+ if (!buflen)
+ return 0;
+
+ memcpy(&rbuf[60], &args->id[0], min(buflen, 512U));
+ return 0;
+}
+
+/**
* ata_scsiop_noop - Command handler that simply returns success.
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
@@ -2109,7 +2191,7 @@ saving_not_supp:
* None.
*/
unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+ unsigned int buflen)
{
u64 last_lba = args->dev->n_sectors - 1; /* LBA of the last block */
@@ -2273,8 +2355,8 @@ static void atapi_request_sense(struct ata_queued_cmd *qc)
qc->tf.feature |= ATAPI_PKT_DMA;
} else {
qc->tf.protocol = ATA_PROT_ATAPI;
- qc->tf.lbam = (8 * 1024) & 0xff;
- qc->tf.lbah = (8 * 1024) >> 8;
+ qc->tf.lbam = SCSI_SENSE_BUFFERSIZE;
+ qc->tf.lbah = 0;
}
qc->nbytes = SCSI_SENSE_BUFFERSIZE;
@@ -2383,6 +2465,7 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
struct ata_device *dev = qc->dev;
int using_pio = (dev->flags & ATA_DFLAG_PIO);
int nodata = (scmd->sc_data_direction == DMA_NONE);
+ unsigned int nbytes;
memset(qc->cdb, 0, dev->cdb_len);
memcpy(qc->cdb, scmd->cmnd, scmd->cmd_len);
@@ -2396,20 +2479,26 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
}
qc->tf.command = ATA_CMD_PACKET;
- qc->nbytes = scmd->request_bufflen;
+ qc->nbytes = scsi_bufflen(scmd);
/* check whether ATAPI DMA is safe */
if (!using_pio && ata_check_atapi_dma(qc))
using_pio = 1;
+ /* Some controller variants snoop this value for Packet transfers
+ to do state machine and FIFO management. Thus we want to set it
+ properly, and for DMA where it is effectively meaningless */
+ nbytes = min(qc->nbytes, (unsigned int)63 * 1024);
+
+ qc->tf.lbam = (nbytes & 0xFF);
+ qc->tf.lbah = (nbytes >> 8);
+
if (using_pio || nodata) {
/* no data, or PIO data xfer */
if (nodata)
qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
else
qc->tf.protocol = ATA_PROT_ATAPI;
- qc->tf.lbam = (8 * 1024) & 0xff;
- qc->tf.lbah = (8 * 1024) >> 8;
} else {
/* DMA data xfer */
qc->tf.protocol = ATA_PROT_ATAPI_DMA;
@@ -2420,24 +2509,42 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
qc->tf.feature |= ATAPI_DMADIR;
}
+
+ /* FIXME: We need to translate 0x05 READ_BLOCK_LIMITS to a MODE_SENSE
+ as ATAPI tape drives don't get this right otherwise */
return 0;
}
-static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
+static struct ata_device *ata_find_dev(struct ata_port *ap, int devno)
{
- if (likely(id < ATA_MAX_DEVICES))
- return &ap->device[id];
+ if (ap->nr_pmp_links == 0) {
+ if (likely(devno < ata_link_max_devices(&ap->link)))
+ return &ap->link.device[devno];
+ } else {
+ if (likely(devno < ap->nr_pmp_links))
+ return &ap->pmp_link[devno].device[0];
+ }
+
return NULL;
}
-static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
- const struct scsi_device *scsidev)
+static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
+ const struct scsi_device *scsidev)
{
+ int devno;
+
/* skip commands not addressed to targets we simulate */
- if (unlikely(scsidev->channel || scsidev->lun))
- return NULL;
+ if (ap->nr_pmp_links == 0) {
+ if (unlikely(scsidev->channel || scsidev->lun))
+ return NULL;
+ devno = scsidev->id;
+ } else {
+ if (unlikely(scsidev->id || scsidev->lun))
+ return NULL;
+ devno = scsidev->channel;
+ }
- return ata_find_dev(ap, scsidev->id);
+ return ata_find_dev(ap, devno);
}
/**
@@ -2458,7 +2565,7 @@ static int ata_scsi_dev_enabled(struct ata_device *dev)
if (unlikely(!ata_dev_enabled(dev)))
return 0;
- if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) {
+ if (!atapi_enabled || (dev->link->ap->flags & ATA_FLAG_NO_ATAPI)) {
if (unlikely(dev->class == ATA_DEV_ATAPI)) {
ata_dev_printk(dev, KERN_WARNING,
"WARNING: ATAPI is %s, device ignored.\n",
@@ -2508,27 +2615,27 @@ static u8
ata_scsi_map_proto(u8 byte1)
{
switch((byte1 & 0x1e) >> 1) {
- case 3: /* Non-data */
- return ATA_PROT_NODATA;
-
- case 6: /* DMA */
- case 10: /* UDMA Data-in */
- case 11: /* UDMA Data-Out */
- return ATA_PROT_DMA;
-
- case 4: /* PIO Data-in */
- case 5: /* PIO Data-out */
- return ATA_PROT_PIO;
-
- case 0: /* Hard Reset */
- case 1: /* SRST */
- case 8: /* Device Diagnostic */
- case 9: /* Device Reset */
- case 7: /* DMA Queued */
- case 12: /* FPDMA */
- case 15: /* Return Response Info */
- default: /* Reserved */
- break;
+ case 3: /* Non-data */
+ return ATA_PROT_NODATA;
+
+ case 6: /* DMA */
+ case 10: /* UDMA Data-in */
+ case 11: /* UDMA Data-Out */
+ return ATA_PROT_DMA;
+
+ case 4: /* PIO Data-in */
+ case 5: /* PIO Data-out */
+ return ATA_PROT_PIO;
+
+ case 0: /* Hard Reset */
+ case 1: /* SRST */
+ case 8: /* Device Diagnostic */
+ case 9: /* Device Reset */
+ case 7: /* DMA Queued */
+ case 12: /* FPDMA */
+ case 15: /* Return Response Info */
+ default: /* Reserved */
+ break;
}
return ATA_PROT_UNKNOWN;
@@ -2631,7 +2738,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
case ATA_CMD_WRITE_LONG_ONCE:
if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
goto invalid_fld;
- qc->sect_size = scmd->request_bufflen;
+ qc->sect_size = scsi_bufflen(scmd);
}
/*
@@ -2661,10 +2768,10 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
* TODO: find out if we need to do more here to
* cover scatter/gather case.
*/
- qc->nbytes = scmd->request_bufflen;
+ qc->nbytes = scsi_bufflen(scmd);
- /* request result TF */
- qc->flags |= ATA_QCFLAG_RESULT_TF;
+ /* request result TF and be quiet about device error */
+ qc->flags |= ATA_QCFLAG_RESULT_TF | ATA_QCFLAG_QUIET;
return 0;
@@ -2746,28 +2853,48 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
void (*done)(struct scsi_cmnd *),
struct ata_device *dev)
{
+ u8 scsi_op = scmd->cmnd[0];
+ ata_xlat_func_t xlat_func;
int rc = 0;
- if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) {
- DPRINTK("bad CDB len=%u, max=%u\n",
- scmd->cmd_len, dev->cdb_len);
- scmd->result = DID_ERROR << 16;
- done(scmd);
- return 0;
- }
-
if (dev->class == ATA_DEV_ATA) {
- ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
- scmd->cmnd[0]);
+ if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len))
+ goto bad_cdb_len;
- if (xlat_func)
- rc = ata_scsi_translate(dev, scmd, done, xlat_func);
- else
- ata_scsi_simulate(dev, scmd, done);
- } else
- rc = ata_scsi_translate(dev, scmd, done, atapi_xlat);
+ xlat_func = ata_get_xlat_func(dev, scsi_op);
+ } else {
+ if (unlikely(!scmd->cmd_len))
+ goto bad_cdb_len;
+
+ xlat_func = NULL;
+ if (likely((scsi_op != ATA_16) || !atapi_passthru16)) {
+ /* relay SCSI command to ATAPI device */
+ if (unlikely(scmd->cmd_len > dev->cdb_len))
+ goto bad_cdb_len;
+
+ xlat_func = atapi_xlat;
+ } else {
+ /* ATA_16 passthru, treat as an ATA command */
+ if (unlikely(scmd->cmd_len > 16))
+ goto bad_cdb_len;
+
+ xlat_func = ata_get_xlat_func(dev, scsi_op);
+ }
+ }
+
+ if (xlat_func)
+ rc = ata_scsi_translate(dev, scmd, done, xlat_func);
+ else
+ ata_scsi_simulate(dev, scmd, done);
return rc;
+
+ bad_cdb_len:
+ DPRINTK("bad CDB len=%u, scsi_op=0x%02x, max=%u\n",
+ scmd->cmd_len, scsi_op, dev->cdb_len);
+ scmd->result = DID_ERROR << 16;
+ done(scmd);
+ return 0;
}
/**
@@ -2835,6 +2962,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
{
struct ata_scsi_args args;
const u8 *scsicmd = cmd->cmnd;
+ u8 tmp8;
args.dev = dev;
args.id = dev->id;
@@ -2842,66 +2970,94 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
args.done = done;
switch(scsicmd[0]) {
- /* no-op's, complete with success */
- case SYNCHRONIZE_CACHE:
- case REZERO_UNIT:
- case SEEK_6:
- case SEEK_10:
- case TEST_UNIT_READY:
- case FORMAT_UNIT: /* FIXME: correct? */
- case SEND_DIAGNOSTIC: /* FIXME: correct? */
- ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
- break;
+ /* TODO: worth improving? */
+ case FORMAT_UNIT:
+ ata_scsi_invalid_field(cmd, done);
+ break;
- case INQUIRY:
- if (scsicmd[1] & 2) /* is CmdDt set? */
- ata_scsi_invalid_field(cmd, done);
- else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */
- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
- else if (scsicmd[2] == 0x00)
- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
- else if (scsicmd[2] == 0x80)
- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
- else if (scsicmd[2] == 0x83)
- ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
- else
- ata_scsi_invalid_field(cmd, done);
+ case INQUIRY:
+ if (scsicmd[1] & 2) /* is CmdDt set? */
+ ata_scsi_invalid_field(cmd, done);
+ else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
+ else switch (scsicmd[2]) {
+ case 0x00:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
break;
-
- case MODE_SENSE:
- case MODE_SENSE_10:
- ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
+ case 0x80:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
break;
-
- case MODE_SELECT: /* unconditionally return */
- case MODE_SELECT_10: /* bad-field-in-cdb */
+ case 0x83:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
+ break;
+ case 0x89:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89);
+ break;
+ default:
ata_scsi_invalid_field(cmd, done);
break;
+ }
+ break;
+
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
+ break;
+
+ case MODE_SELECT: /* unconditionally return */
+ case MODE_SELECT_10: /* bad-field-in-cdb */
+ ata_scsi_invalid_field(cmd, done);
+ break;
+
+ case READ_CAPACITY:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
+ break;
- case READ_CAPACITY:
+ case SERVICE_ACTION_IN:
+ if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
- break;
+ else
+ ata_scsi_invalid_field(cmd, done);
+ break;
- case SERVICE_ACTION_IN:
- if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
- ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
- else
- ata_scsi_invalid_field(cmd, done);
- break;
+ case REPORT_LUNS:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
+ break;
- case REPORT_LUNS:
- ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
- break;
+ case REQUEST_SENSE:
+ ata_scsi_set_sense(cmd, 0, 0, 0);
+ cmd->result = (DRIVER_SENSE << 24);
+ done(cmd);
+ break;
- /* mandatory commands we haven't implemented yet */
- case REQUEST_SENSE:
+ /* if we reach this, then writeback caching is disabled,
+ * turning this into a no-op.
+ */
+ case SYNCHRONIZE_CACHE:
+ /* fall through */
+
+ /* no-op's, complete with success */
+ case REZERO_UNIT:
+ case SEEK_6:
+ case SEEK_10:
+ case TEST_UNIT_READY:
+ ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+ break;
- /* all other commands */
- default:
- ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
- /* "Invalid command operation code" */
- done(cmd);
- break;
+ case SEND_DIAGNOSTIC:
+ tmp8 = scsicmd[1] & ~(1 << 3);
+ if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4]))
+ ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+ else
+ ata_scsi_invalid_field(cmd, done);
+ break;
+
+ /* all other commands */
+ default:
+ ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
+ /* "Invalid command operation code" */
+ done(cmd);
+ break;
}
}
@@ -2928,6 +3084,13 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
shost->max_channel = 1;
shost->max_cmd_len = 16;
+ /* Schedule policy is determined by ->qc_defer()
+ * callback and it needs to see every deferred qc.
+ * Set host_blocked to 1 to prevent SCSI midlayer from
+ * automatically deferring requests.
+ */
+ shost->max_host_blocked = 1;
+
rc = scsi_add_host(ap->scsi_host, ap->host->dev);
if (rc)
goto err_add;
@@ -2951,25 +3114,32 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
{
int tries = 5;
struct ata_device *last_failed_dev = NULL;
+ struct ata_link *link;
struct ata_device *dev;
- unsigned int i;
if (ap->flags & ATA_FLAG_DISABLED)
return;
repeat:
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct scsi_device *sdev;
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link) {
+ struct scsi_device *sdev;
+ int channel = 0, id = 0;
- dev = &ap->device[i];
+ if (!ata_dev_enabled(dev) || dev->sdev)
+ continue;
- if (!ata_dev_enabled(dev) || dev->sdev)
- continue;
+ if (ata_is_host_link(link))
+ id = dev->devno;
+ else
+ channel = link->pmp;
- sdev = __scsi_add_device(ap->scsi_host, 0, i, 0, NULL);
- if (!IS_ERR(sdev)) {
- dev->sdev = sdev;
- scsi_device_put(sdev);
+ sdev = __scsi_add_device(ap->scsi_host, channel, id, 0,
+ NULL);
+ if (!IS_ERR(sdev)) {
+ dev->sdev = sdev;
+ scsi_device_put(sdev);
+ }
}
}
@@ -2977,12 +3147,14 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
* failure occurred, scan would have failed silently. Check
* whether all devices are attached.
*/
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- dev = &ap->device[i];
- if (ata_dev_enabled(dev) && !dev->sdev)
- break;
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link) {
+ if (ata_dev_enabled(dev) && !dev->sdev)
+ goto exit_loop;
+ }
}
- if (i == ATA_MAX_DEVICES)
+ exit_loop:
+ if (!link)
return;
/* we're missing some SCSI devices */
@@ -3049,7 +3221,7 @@ int ata_scsi_offline_dev(struct ata_device *dev)
*/
static void ata_scsi_remove_dev(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
+ struct ata_port *ap = dev->link->ap;
struct scsi_device *sdev;
unsigned long flags;
@@ -3096,6 +3268,42 @@ static void ata_scsi_remove_dev(struct ata_device *dev)
}
}
+static void ata_scsi_handle_link_detach(struct ata_link *link)
+{
+ struct ata_port *ap = link->ap;
+ struct ata_device *dev;
+
+ ata_link_for_each_dev(dev, link) {
+ unsigned long flags;
+
+ if (!(dev->flags & ATA_DFLAG_DETACHED))
+ continue;
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags &= ~ATA_DFLAG_DETACHED;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_scsi_remove_dev(dev);
+ }
+}
+
+/**
+ * ata_scsi_media_change_notify - send media change event
+ * @dev: Pointer to the disk device with media change event
+ *
+ * Tell the block layer to send a media change notification
+ * event.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_scsi_media_change_notify(struct ata_device *dev)
+{
+ if (dev->sdev)
+ sdev_evt_send_simple(dev->sdev, SDEV_EVT_MEDIA_CHANGE,
+ GFP_ATOMIC);
+}
+
/**
* ata_scsi_hotplug - SCSI part of hotplug
* @work: Pointer to ATA port to perform SCSI hotplug on
@@ -3121,20 +3329,14 @@ void ata_scsi_hotplug(struct work_struct *work)
DPRINTK("ENTER\n");
- /* unplug detached devices */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- unsigned long flags;
-
- if (!(dev->flags & ATA_DFLAG_DETACHED))
- continue;
-
- spin_lock_irqsave(ap->lock, flags);
- dev->flags &= ~ATA_DFLAG_DETACHED;
- spin_unlock_irqrestore(ap->lock, flags);
-
- ata_scsi_remove_dev(dev);
- }
+ /* Unplug detached devices. We cannot use link iterator here
+ * because PMP links have to be scanned even if PMP is
+ * currently not attached. Iterate manually.
+ */
+ ata_scsi_handle_link_detach(&ap->link);
+ if (ap->pmp_link)
+ for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+ ata_scsi_handle_link_detach(&ap->pmp_link[i]);
/* scan for new ones */
ata_scsi_scan_host(ap, 0);
@@ -3163,27 +3365,42 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
{
struct ata_port *ap = ata_shost_to_port(shost);
unsigned long flags;
- int rc = 0;
+ int devno, rc = 0;
if (!ap->ops->error_handler)
return -EOPNOTSUPP;
- if ((channel != SCAN_WILD_CARD && channel != 0) ||
- (lun != SCAN_WILD_CARD && lun != 0))
+ if (lun != SCAN_WILD_CARD && lun)
return -EINVAL;
+ if (ap->nr_pmp_links == 0) {
+ if (channel != SCAN_WILD_CARD && channel)
+ return -EINVAL;
+ devno = id;
+ } else {
+ if (id != SCAN_WILD_CARD && id)
+ return -EINVAL;
+ devno = channel;
+ }
+
spin_lock_irqsave(ap->lock, flags);
- if (id == SCAN_WILD_CARD) {
- ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
- ap->eh_info.action |= ATA_EH_SOFTRESET;
+ if (devno == SCAN_WILD_CARD) {
+ struct ata_link *link;
+
+ ata_port_for_each_link(link, ap) {
+ struct ata_eh_info *ehi = &link->eh_info;
+ ehi->probe_mask |= (1 << ata_link_max_devices(link)) - 1;
+ ehi->action |= ATA_EH_SOFTRESET;
+ }
} else {
- struct ata_device *dev = ata_find_dev(ap, id);
+ struct ata_device *dev = ata_find_dev(ap, devno);
if (dev) {
- ap->eh_info.probe_mask |= 1 << dev->devno;
- ap->eh_info.action |= ATA_EH_SOFTRESET;
- ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
+ struct ata_eh_info *ehi = &dev->link->eh_info;
+ ehi->probe_mask |= 1 << dev->devno;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ehi->flags |= ATA_EHI_RESUME_LINK;
} else
rc = -EINVAL;
}
@@ -3214,24 +3431,26 @@ void ata_scsi_dev_rescan(struct work_struct *work)
{
struct ata_port *ap =
container_of(work, struct ata_port, scsi_rescan_task);
+ struct ata_link *link;
+ struct ata_device *dev;
unsigned long flags;
- unsigned int i;
spin_lock_irqsave(ap->lock, flags);
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- struct scsi_device *sdev = dev->sdev;
+ ata_port_for_each_link(link, ap) {
+ ata_link_for_each_dev(dev, link) {
+ struct scsi_device *sdev = dev->sdev;
- if (!ata_dev_enabled(dev) || !sdev)
- continue;
- if (scsi_device_get(sdev))
- continue;
+ if (!ata_dev_enabled(dev) || !sdev)
+ continue;
+ if (scsi_device_get(sdev))
+ continue;
- spin_unlock_irqrestore(ap->lock, flags);
- scsi_rescan_device(&(sdev->sdev_gendev));
- scsi_device_put(sdev);
- spin_lock_irqsave(ap->lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
+ scsi_rescan_device(&(sdev->sdev_gendev));
+ scsi_device_put(sdev);
+ spin_lock_irqsave(ap->lock, flags);
+ }
}
spin_unlock_irqrestore(ap->lock, flags);
@@ -3359,7 +3578,7 @@ EXPORT_SYMBOL_GPL(ata_sas_port_destroy);
int ata_sas_slave_configure(struct scsi_device *sdev, struct ata_port *ap)
{
ata_scsi_sdev_config(sdev);
- ata_scsi_dev_config(sdev, ap->device);
+ ata_scsi_dev_config(sdev, ap->link.device);
return 0;
}
EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
@@ -3382,8 +3601,8 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
ata_scsi_dump_cdb(ap, cmd);
- if (likely(ata_scsi_dev_enabled(ap->device)))
- rc = __ata_scsi_queuecmd(cmd, done, ap->device);
+ if (likely(ata_scsi_dev_enabled(ap->link.device)))
+ rc = __ata_scsi_queuecmd(cmd, done, ap->link.device);
else {
cmd->result = (DID_BAD_TARGET << 16);
done(cmd);
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 8023167bbbe..48acc09dab9 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -64,46 +64,6 @@ u8 ata_irq_on(struct ata_port *ap)
return tmp;
}
-u8 ata_dummy_irq_on (struct ata_port *ap) { return 0; }
-
-/**
- * ata_irq_ack - Acknowledge a device interrupt.
- * @ap: Port on which interrupts are enabled.
- *
- * Wait up to 10 ms for legacy IDE device to become idle (BUSY
- * or BUSY+DRQ clear). Obtain dma status and port status from
- * device. Clear the interrupt. Return port status.
- *
- * LOCKING:
- */
-
-u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
-{
- unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
- u8 host_stat = 0, post_stat = 0, status;
-
- status = ata_busy_wait(ap, bits, 1000);
- if (status & bits)
- if (ata_msg_err(ap))
- printk(KERN_ERR "abnormal status 0x%X\n", status);
-
- if (ap->ioaddr.bmdma_addr) {
- /* get controller status; clear intr, err bits */
- host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
- ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-
- post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
- }
- if (ata_msg_intr(ap))
- printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
- __FUNCTION__,
- host_stat, post_stat, status);
- return status;
-}
-
-u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq) { return 0; }
-
/**
* ata_tf_load - send taskfile registers to host controller
* @ap: Port to which output is sent
@@ -196,7 +156,7 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
- tf->command = ata_check_status(ap);
+ tf->command = ata_chk_status(ap);
tf->feature = ioread8(ioaddr->error_addr);
tf->nsect = ioread8(ioaddr->nsect_addr);
tf->lbal = ioread8(ioaddr->lbal_addr);
@@ -288,7 +248,7 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc)
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-void ata_bmdma_start (struct ata_queued_cmd *qc)
+void ata_bmdma_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
u8 dmactl;
@@ -445,7 +405,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
unsigned long flags;
int thaw = 0;
- qc = __ata_qc_from_tag(ap, ap->active_tag);
+ qc = __ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
qc = NULL;
@@ -500,7 +460,7 @@ void ata_bmdma_error_handler(struct ata_port *ap)
ata_reset_fn_t hardreset;
hardreset = NULL;
- if (sata_scr_valid(ap))
+ if (sata_scr_valid(&ap->link))
hardreset = sata_std_hardreset;
ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
@@ -607,6 +567,9 @@ int ata_pci_init_bmdma(struct ata_host *host)
if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) &&
(ioread8(bmdma + 2) & 0x80))
host->flags |= ATA_HOST_SIMPLEX;
+
+ ata_port_desc(ap, "bmdma 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, 4) + 8 * i);
}
return 0;
@@ -674,6 +637,10 @@ int ata_pci_init_sff_host(struct ata_host *host)
((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS);
ata_std_ports(&ap->ioaddr);
+ ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, base),
+ (unsigned long long)pci_resource_start(pdev, base + 1));
+
mask |= 1 << i;
}
@@ -844,24 +811,30 @@ int ata_pci_init_one(struct pci_dev *pdev,
IRQF_SHARED, DRV_NAME, host);
if (rc)
goto err_out;
- host->irq = pdev->irq;
+
+ ata_port_desc(host->ports[0], "irq %d", pdev->irq);
+ ata_port_desc(host->ports[1], "irq %d", pdev->irq);
} else {
if (!ata_port_is_dummy(host->ports[0])) {
- host->irq = ATA_PRIMARY_IRQ(pdev);
- rc = devm_request_irq(dev, host->irq,
+ rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
pi->port_ops->irq_handler,
IRQF_SHARED, DRV_NAME, host);
if (rc)
goto err_out;
+
+ ata_port_desc(host->ports[0], "irq %d",
+ ATA_PRIMARY_IRQ(pdev));
}
if (!ata_port_is_dummy(host->ports[1])) {
- host->irq2 = ATA_SECONDARY_IRQ(pdev);
- rc = devm_request_irq(dev, host->irq2,
+ rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev),
pi->port_ops->irq_handler,
IRQF_SHARED, DRV_NAME, host);
if (rc)
goto err_out;
+
+ ata_port_desc(host->ports[1], "irq %d",
+ ATA_SECONDARY_IRQ(pdev));
}
}
@@ -883,7 +856,7 @@ err_out:
* @pdev: PCI device
*
* Some PCI ATA devices report simplex mode but in fact can be told to
- * enter non simplex mode. This implements the neccessary logic to
+ * enter non simplex mode. This implements the necessary logic to
* perform the task on such devices. Calling it on other devices will
* have -undefined- behaviour.
*/
@@ -909,7 +882,7 @@ unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer
/* Filter out DMA modes if the device has been configured by
the BIOS as PIO only */
- if (adev->ap->ioaddr.bmdma_addr == 0)
+ if (adev->link->ap->ioaddr.bmdma_addr == NULL)
xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
return xfer_mask;
}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 564cd234c80..0e6cf3a484d 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -29,6 +29,7 @@
#define __LIBATA_H__
#define DRV_NAME "libata"
+#define DRV_VERSION "3.00" /* must be exactly four chars */
struct ata_scsi_args {
struct ata_device *dev;
@@ -56,6 +57,7 @@ extern unsigned int ata_print_id;
extern struct workqueue_struct *ata_aux_wq;
extern int atapi_enabled;
extern int atapi_dmadir;
+extern int atapi_passthru16;
extern int libata_fua;
extern int libata_noacpi;
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
@@ -67,21 +69,23 @@ extern void ata_dev_disable(struct ata_device *dev);
extern void ata_port_flush_task(struct ata_port *ap);
extern unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
- int dma_dir, void *buf, unsigned int buflen);
+ int dma_dir, void *buf, unsigned int buflen,
+ unsigned long timeout);
extern unsigned ata_exec_internal_sg(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, struct scatterlist *sg,
- unsigned int n_elem);
+ unsigned int n_elem, unsigned long timeout);
extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
unsigned int flags, u16 *id);
extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags);
-extern int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags);
+extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+ unsigned int readid_flags);
extern int ata_dev_configure(struct ata_device *dev);
-extern int sata_down_spd_limit(struct ata_port *ap);
-extern int sata_set_spd_needed(struct ata_port *ap);
+extern int sata_down_spd_limit(struct ata_link *link);
+extern int sata_set_spd_needed(struct ata_link *link);
extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
-extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
+extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
extern void ata_sg_clean(struct ata_queued_cmd *qc);
extern void ata_qc_free(struct ata_queued_cmd *qc);
extern void ata_qc_issue(struct ata_queued_cmd *qc);
@@ -92,17 +96,23 @@ extern void ata_dev_select(struct ata_port *ap, unsigned int device,
extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
extern int ata_flush_cache(struct ata_device *dev);
extern void ata_dev_init(struct ata_device *dev);
+extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
+extern int sata_link_init_spd(struct ata_link *link);
extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
extern struct ata_port *ata_port_alloc(struct ata_host *host);
+extern void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy);
+extern void ata_lpm_schedule(struct ata_port *ap, enum link_pm);
/* libata-acpi.c */
#ifdef CONFIG_ATA_ACPI
+extern void ata_acpi_associate_sata_port(struct ata_port *ap);
extern void ata_acpi_associate(struct ata_host *host);
extern int ata_acpi_on_suspend(struct ata_port *ap);
extern void ata_acpi_on_resume(struct ata_port *ap);
extern int ata_acpi_on_devcfg(struct ata_device *adev);
#else
+static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { }
static inline void ata_acpi_associate(struct ata_host *host) { }
static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
static inline void ata_acpi_on_resume(struct ata_port *ap) { }
@@ -114,6 +124,7 @@ extern int ata_scsi_add_hosts(struct ata_host *host,
struct scsi_host_template *sht);
extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
extern int ata_scsi_offline_dev(struct ata_device *dev);
+extern void ata_scsi_media_change_notify(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work);
extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
unsigned int buflen);
@@ -147,12 +158,32 @@ extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
extern void ata_scsi_dev_rescan(struct work_struct *work);
extern int ata_bus_probe(struct ata_port *ap);
+/* libata-pmp.c */
+extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val);
+extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val);
+extern int sata_pmp_attach(struct ata_device *dev);
+
/* libata-eh.c */
extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
extern void ata_scsi_error(struct Scsi_Host *host);
extern void ata_port_wait_eh(struct ata_port *ap);
extern void ata_eh_fastdrain_timerfn(unsigned long arg);
extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
+extern void ata_eh_detach_dev(struct ata_device *dev);
+extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+ unsigned int action);
+extern void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+ unsigned int action);
+extern void ata_eh_autopsy(struct ata_port *ap);
+extern void ata_eh_report(struct ata_port *ap);
+extern int ata_eh_reset(struct ata_link *link, int classify,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset);
+extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset,
+ struct ata_link **r_failed_disk);
+extern void ata_eh_finish(struct ata_port *ap);
/* libata-sff.c */
extern u8 ata_irq_on(struct ata_port *ap);
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
new file mode 100644
index 00000000000..e4542ab9c7f
--- /dev/null
+++ b/drivers/ata/pata_acpi.c
@@ -0,0 +1,397 @@
+/*
+ * ACPI PATA driver
+ *
+ * (c) 2007 Red Hat <alan@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acnames.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acexcep.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_acpi"
+#define DRV_VERSION "0.2.3"
+
+struct pata_acpi {
+ struct ata_acpi_gtm gtm;
+ void *last;
+ unsigned long mask[2];
+};
+
+/**
+ * pacpi_pre_reset - check for 40/80 pin
+ * @ap: Port
+ * @deadline: deadline jiffies for the operation
+ *
+ * Perform the PATA port setup we need.
+ */
+
+static int pacpi_pre_reset(struct ata_link *link, unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct pata_acpi *acpi = ap->private_data;
+ if (ap->acpi_handle == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0)
+ return -ENODEV;
+
+ return ata_std_prereset(link, deadline);
+}
+
+/**
+ * pacpi_cable_detect - cable type detection
+ * @ap: port to detect
+ *
+ * Perform device specific cable detection
+ */
+
+static int pacpi_cable_detect(struct ata_port *ap)
+{
+ struct pata_acpi *acpi = ap->private_data;
+
+ if ((acpi->mask[0] | acpi->mask[1]) & (0xF8 << ATA_SHIFT_UDMA))
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * pacpi_error_handler - Setup and error handler
+ * @ap: Port to handle
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void pacpi_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset,
+ NULL, ata_std_postreset);
+}
+
+/* Welcome to ACPI, bring a bucket */
+static const unsigned int pio_cycle[7] = {
+ 600, 383, 240, 180, 120, 100, 80
+};
+static const unsigned int mwdma_cycle[5] = {
+ 480, 150, 120, 100, 80
+};
+static const unsigned int udma_cycle[7] = {
+ 120, 80, 60, 45, 30, 20, 15
+};
+
+/**
+ * pacpi_discover_modes - filter non ACPI modes
+ * @adev: ATA device
+ * @mask: proposed modes
+ *
+ * Try the modes available and see which ones the ACPI method will
+ * set up sensibly. From this we get a mask of ACPI modes we can use
+ */
+
+static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev)
+{
+ int unit = adev->devno;
+ struct pata_acpi *acpi = ap->private_data;
+ int i;
+ u32 t;
+ unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO);
+
+ struct ata_acpi_gtm probe;
+
+ probe = acpi->gtm;
+
+ /* We always use the 0 slot for crap hardware */
+ if (!(probe.flags & 0x10))
+ unit = 0;
+
+ ata_acpi_gtm(ap, &probe);
+
+ /* Start by scanning for PIO modes */
+ for (i = 0; i < 7; i++) {
+ t = probe.drive[unit].pio;
+ if (t <= pio_cycle[i]) {
+ mask |= (2 << (ATA_SHIFT_PIO + i)) - 1;
+ break;
+ }
+ }
+
+ /* See if we have MWDMA or UDMA data. We don't bother with MWDMA
+ if UDMA is availabe as this means the BIOS set UDMA and our
+ error changedown if it works is UDMA to PIO anyway */
+ if (probe.flags & (1 << (2 * unit))) {
+ /* MWDMA */
+ for (i = 0; i < 5; i++) {
+ t = probe.drive[unit].dma;
+ if (t <= mwdma_cycle[i]) {
+ mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1;
+ break;
+ }
+ }
+ } else {
+ /* UDMA */
+ for (i = 0; i < 7; i++) {
+ t = probe.drive[unit].dma;
+ if (t <= udma_cycle[i]) {
+ mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1;
+ break;
+ }
+ }
+ }
+ if (mask & (0xF8 << ATA_SHIFT_UDMA))
+ ap->cbl = ATA_CBL_PATA80;
+ return mask;
+}
+
+/**
+ * pacpi_mode_filter - mode filter for ACPI
+ * @adev: device
+ * @mask: mask of valid modes
+ *
+ * Filter the valid mode list according to our own specific rules, in
+ * this case the list of discovered valid modes obtained by ACPI probing
+ */
+
+static unsigned long pacpi_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+ struct pata_acpi *acpi = adev->link->ap->private_data;
+ return ata_pci_default_filter(adev, mask & acpi->mask[adev->devno]);
+}
+
+/**
+ * pacpi_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ */
+
+static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ int unit = adev->devno;
+ struct pata_acpi *acpi = ap->private_data;
+
+ if (!(acpi->gtm.flags & 0x10))
+ unit = 0;
+
+ /* Now stuff the nS values into the structure */
+ acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0];
+ ata_acpi_stm(ap, &acpi->gtm);
+ /* See what mode we actually got */
+ ata_acpi_gtm(ap, &acpi->gtm);
+}
+
+/**
+ * pacpi_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ */
+
+static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ int unit = adev->devno;
+ struct pata_acpi *acpi = ap->private_data;
+
+ if (!(acpi->gtm.flags & 0x10))
+ unit = 0;
+
+ /* Now stuff the nS values into the structure */
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0];
+ acpi->gtm.flags |= (1 << (2 * unit));
+ } else {
+ acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0];
+ acpi->gtm.flags &= ~(1 << (2 * unit));
+ }
+ ata_acpi_stm(ap, &acpi->gtm);
+ /* See what mode we actually got */
+ ata_acpi_gtm(ap, &acpi->gtm);
+}
+
+/**
+ * pacpi_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary.
+ */
+
+static unsigned int pacpi_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct pata_acpi *acpi = ap->private_data;
+
+ if (acpi->gtm.flags & 0x10)
+ return ata_qc_issue_prot(qc);
+
+ if (adev != acpi->last) {
+ pacpi_set_piomode(ap, adev);
+ if (adev->dma_mode)
+ pacpi_set_dmamode(ap, adev);
+ acpi->last = adev;
+ }
+ return ata_qc_issue_prot(qc);
+}
+
+/**
+ * pacpi_port_start - port setup
+ * @ap: ATA port being set up
+ *
+ * Use the port_start hook to maintain private control structures
+ */
+
+static int pacpi_port_start(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct pata_acpi *acpi;
+
+ int ret;
+
+ if (ap->acpi_handle == NULL)
+ return -ENODEV;
+
+ acpi = ap->private_data = devm_kzalloc(&pdev->dev, sizeof(struct pata_acpi), GFP_KERNEL);
+ if (ap->private_data == NULL)
+ return -ENOMEM;
+ acpi->mask[0] = pacpi_discover_modes(ap, &ap->link.device[0]);
+ acpi->mask[1] = pacpi_discover_modes(ap, &ap->link.device[1]);
+ ret = ata_sff_port_start(ap);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static struct scsi_host_template pacpi_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ /* Use standard CHS mapping rules */
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations pacpi_ops = {
+ .set_piomode = pacpi_set_piomode,
+ .set_dmamode = pacpi_set_dmamode,
+ .mode_filter = pacpi_mode_filter,
+
+ /* Task file is PCI ATA format, use helpers */
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = pacpi_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = pacpi_cable_detect,
+
+ /* BMDMA handling is PCI ATA format, use helpers */
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = pacpi_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+
+ /* Timeout handling */
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ /* Generic PATA PCI ATA helpers */
+ .port_start = pacpi_port_start,
+};
+
+
+/**
+ * pacpi_init_one - Register ACPI ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in pacpi_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static const struct ata_port_info info = {
+ .sht = &pacpi_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+
+ .port_ops = &pacpi_ops,
+ };
+ const struct ata_port_info *ppi[] = { &info, NULL };
+ return ata_pci_init_one(pdev, ppi);
+}
+
+static const struct pci_device_id pacpi_pci_tbl[] = {
+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1},
+ { } /* terminate list */
+};
+
+static struct pci_driver pacpi_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pacpi_pci_tbl,
+ .probe = pacpi_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
+};
+
+static int __init pacpi_init(void)
+{
+ return pci_register_driver(&pacpi_pci_driver);
+}
+
+static void __exit pacpi_exit(void)
+{
+ pci_unregister_driver(&pacpi_pci_driver);
+}
+
+module_init(pacpi_init);
+module_exit(pacpi_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for ATA in ACPI mode");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pacpi_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 71bdc3b3189..364534e7aff 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -40,7 +40,7 @@
* Cable special cases
*/
-static struct dmi_system_id cable_dmi_table[] = {
+static const struct dmi_system_id cable_dmi_table[] = {
{
.ident = "HP Pavilion N5430",
.matches = {
@@ -305,7 +305,6 @@ static struct scsi_host_template ali_sht = {
*/
static struct ata_port_operations ali_early_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = ali_set_piomode,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -327,9 +326,8 @@ static struct ata_port_operations ali_early_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/*
@@ -337,8 +335,6 @@ static struct ata_port_operations ali_early_port_ops = {
* detect
*/
static struct ata_port_operations ali_20_port_ops = {
- .port_disable = ata_port_disable,
-
.set_piomode = ali_set_piomode,
.set_dmamode = ali_set_dmamode,
.mode_filter = ali_20_filter,
@@ -369,16 +365,14 @@ static struct ata_port_operations ali_20_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/*
* Port operations for DMA capable ALi with cable detect
*/
static struct ata_port_operations ali_c2_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = ali_set_piomode,
.set_dmamode = ali_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -408,16 +402,14 @@ static struct ata_port_operations ali_c2_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/*
* Port operations for DMA capable ALi with cable detect and LBA48
*/
static struct ata_port_operations ali_c5_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = ali_set_piomode,
.set_dmamode = ali_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -446,9 +438,8 @@ static struct ata_port_operations ali_c5_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 04048fcf630..c5779ad4abc 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -119,27 +119,28 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse
}
/**
- * amd_probe_init - perform reset handling
- * @ap: ATA port
+ * amd_pre_reset - perform reset handling
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Reset sequence checking enable bits to see which ports are
* active.
*/
-static int amd_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int amd_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits amd_enable_bits[] = {
{ 0x40, 1, 0x02, 0x02 },
{ 0x40, 1, 0x01, 0x01 }
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static void amd_error_handler(struct ata_port *ap)
@@ -221,25 +222,26 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
/**
* nv_probe_init - cable detection
- * @ap: ATA port
+ * @lin: ATA link
*
* Perform cable detection. The BIOS stores this in PCI config
* space for us.
*/
-static int nv_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int nv_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits nv_enable_bits[] = {
{ 0x50, 1, 0x02, 0x02 },
{ 0x50, 1, 0x01, 0x01 }
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static void nv_error_handler(struct ata_port *ap)
@@ -268,6 +270,9 @@ static int nv_cable_detect(struct ata_port *ap)
pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
cbl = ATA_CBL_PATA80;
+ /* And a triple check across suspend/resume with ACPI around */
+ if (ata_acpi_cbl_80wire(ap))
+ cbl = ATA_CBL_PATA80;
return cbl;
}
@@ -327,7 +332,6 @@ static struct scsi_host_template amd_sht = {
};
static struct ata_port_operations amd33_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = amd33_set_piomode,
.set_dmamode = amd33_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -356,13 +360,11 @@ static struct ata_port_operations amd33_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations amd66_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = amd66_set_piomode,
.set_dmamode = amd66_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -391,13 +393,11 @@ static struct ata_port_operations amd66_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations amd100_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = amd100_set_piomode,
.set_dmamode = amd100_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -426,13 +426,11 @@ static struct ata_port_operations amd100_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations amd133_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = amd133_set_piomode,
.set_dmamode = amd133_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -461,13 +459,11 @@ static struct ata_port_operations amd133_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations nv100_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = nv100_set_piomode,
.set_dmamode = nv100_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -496,13 +492,11 @@ static struct ata_port_operations nv100_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations nv133_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = nv133_set_piomode,
.set_dmamode = nv133_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -531,9 +525,8 @@ static struct ata_port_operations nv133_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index b5352ebecef..d4218310327 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -40,8 +40,9 @@
static int clock = 0;
-static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int artop6210_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
const struct pci_bits artop_enable_bits[] = {
{ 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
@@ -51,7 +52,7 @@ static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -71,27 +72,28 @@ static void artop6210_error_handler(struct ata_port *ap)
/**
* artop6260_pre_reset - check for 40/80 pin
- * @ap: Port
+ * @link: link
* @deadline: deadline jiffies for the operation
*
* The ARTOP hardware reports the cable detect bits in register 0x49.
* Nothing complicated needed here.
*/
-static int artop6260_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int artop6260_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits artop_enable_bits[] = {
{ 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
{ 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
/* Odd numbered device ids are the units with enable bits (the -R cards) */
if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -330,7 +332,6 @@ static struct scsi_host_template artop_sht = {
};
static const struct ata_port_operations artop6210_ops = {
- .port_disable = ata_port_disable,
.set_piomode = artop6210_set_piomode,
.set_dmamode = artop6210_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -359,13 +360,11 @@ static const struct ata_port_operations artop6210_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations artop6260_ops = {
- .port_disable = ata_port_disable,
.set_piomode = artop6260_set_piomode,
.set_dmamode = artop6260_set_dmamode,
@@ -392,9 +391,8 @@ static const struct ata_port_operations artop6260_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c
new file mode 100644
index 00000000000..bb250a48e27
--- /dev/null
+++ b/drivers/ata/pata_at32.c
@@ -0,0 +1,441 @@
+/*
+ * AVR32 SMC/CFC PATA Driver
+ *
+ * Copyright (C) 2007 Atmel Norway
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/smc.h>
+
+#define DRV_NAME "pata_at32"
+#define DRV_VERSION "0.0.2"
+
+/*
+ * CompactFlash controller memory layout relative to the base address:
+ *
+ * Attribute memory: 0000 0000 -> 003f ffff
+ * Common memory: 0040 0000 -> 007f ffff
+ * I/O memory: 0080 0000 -> 00bf ffff
+ * True IDE Mode: 00c0 0000 -> 00df ffff
+ * Alt IDE Mode: 00e0 0000 -> 00ff ffff
+ *
+ * Only True IDE and Alt True IDE mode are needed for this driver.
+ *
+ * True IDE mode => CS0 = 0, CS1 = 1 (cmd, error, stat, etc)
+ * Alt True IDE mode => CS0 = 1, CS1 = 0 (ctl, alt_stat)
+ */
+#define CF_IDE_OFFSET 0x00c00000
+#define CF_ALT_IDE_OFFSET 0x00e00000
+#define CF_RES_SIZE 2048
+
+/*
+ * Define DEBUG_BUS if you are doing debugging of your own EBI -> PATA
+ * adaptor with a logic analyzer or similar.
+ */
+#undef DEBUG_BUS
+
+/*
+ * ATA PIO modes
+ *
+ * Name | Mb/s | Min cycle time | Mask
+ * --------+-------+----------------+--------
+ * Mode 0 | 3.3 | 600 ns | 0x01
+ * Mode 1 | 5.2 | 383 ns | 0x03
+ * Mode 2 | 8.3 | 240 ns | 0x07
+ * Mode 3 | 11.1 | 180 ns | 0x0f
+ * Mode 4 | 16.7 | 120 ns | 0x1f
+ */
+#define PIO_MASK (0x1f)
+
+/*
+ * Struct containing private information about device.
+ */
+struct at32_ide_info {
+ unsigned int irq;
+ struct resource res_ide;
+ struct resource res_alt;
+ void __iomem *ide_addr;
+ void __iomem *alt_addr;
+ unsigned int cs;
+ struct smc_config smc;
+};
+
+/*
+ * Setup SMC for the given ATA timing.
+ */
+static int pata_at32_setup_timing(struct device *dev,
+ struct at32_ide_info *info,
+ const struct ata_timing *timing)
+{
+ /* These two values are found through testing */
+ const int min_recover = 25;
+ const int ncs_hold = 15;
+
+ struct smc_config *smc = &info->smc;
+
+ int active;
+ int recover;
+
+ /* Total cycle time */
+ smc->read_cycle = timing->cyc8b;
+
+ /* DIOR <= CFIOR timings */
+ smc->nrd_setup = timing->setup;
+ smc->nrd_pulse = timing->act8b;
+
+ /* Compute recover, extend total cycle if needed */
+ active = smc->nrd_setup + smc->nrd_pulse;
+ recover = smc->read_cycle - active;
+
+ if (recover < min_recover) {
+ smc->read_cycle = active + min_recover;
+ recover = min_recover;
+ }
+
+ /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */
+ smc->ncs_read_setup = 0;
+ smc->ncs_read_pulse = active + ncs_hold;
+
+ /* Write timings same as read timings */
+ smc->write_cycle = smc->read_cycle;
+ smc->nwe_setup = smc->nrd_setup;
+ smc->nwe_pulse = smc->nrd_pulse;
+ smc->ncs_write_setup = smc->ncs_read_setup;
+ smc->ncs_write_pulse = smc->ncs_read_pulse;
+
+ /* Do some debugging output */
+ dev_dbg(dev, "SMC: C=%d S=%d P=%d R=%d NCSS=%d NCSP=%d NCSR=%d\n",
+ smc->read_cycle, smc->nrd_setup, smc->nrd_pulse,
+ recover, smc->ncs_read_setup, smc->ncs_read_pulse,
+ smc->read_cycle - smc->ncs_read_pulse);
+
+ /* Finally, configure the SMC */
+ return smc_set_configuration(info->cs, smc);
+}
+
+/*
+ * Procedures for libATA.
+ */
+static void pata_at32_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_timing timing;
+ struct at32_ide_info *info = ap->host->private_data;
+
+ int ret;
+
+ /* Compute ATA timing */
+ ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0);
+ if (ret) {
+ dev_warn(ap->dev, "Failed to compute ATA timing %d\n", ret);
+ return;
+ }
+
+ /* Setup SMC to ATA timing */
+ ret = pata_at32_setup_timing(ap->dev, info, &timing);
+ if (ret) {
+ dev_warn(ap->dev, "Failed to setup ATA timing %d\n", ret);
+ return;
+ }
+}
+
+static void pata_at32_irq_clear(struct ata_port *ap)
+{
+ /* No DMA controller yet */
+}
+
+static struct scsi_host_template at32_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations at32_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = pata_at32_set_piomode,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .exec_command = ata_exec_command,
+ .check_status = ata_check_status,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_data_xfer,
+
+ .irq_clear = pata_at32_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+
+ .port_start = ata_sff_port_start,
+};
+
+static int __init pata_at32_init_one(struct device *dev,
+ struct at32_ide_info *info)
+{
+ struct ata_host *host;
+ struct ata_port *ap;
+
+ host = ata_host_alloc(dev, 1);
+ if (!host)
+ return -ENOMEM;
+
+ ap = host->ports[0];
+
+ /* Setup ATA bindings */
+ ap->ops = &at32_port_ops;
+ ap->pio_mask = PIO_MASK;
+ ap->flags = ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS
+ | ATA_FLAG_PIO_POLLING;
+
+ /*
+ * Since all 8-bit taskfile transfers has to go on the lower
+ * byte of the data bus and there is a bug in the SMC that
+ * makes it impossible to alter the bus width during runtime,
+ * we need to hardwire the address signals as follows:
+ *
+ * A_IDE(2:0) <= A_EBI(3:1)
+ *
+ * This makes all addresses on the EBI even, thus all data
+ * will be on the lower byte of the data bus. All addresses
+ * used by libATA need to be altered according to this.
+ */
+ ap->ioaddr.altstatus_addr = info->alt_addr + (0x06 << 1);
+ ap->ioaddr.ctl_addr = info->alt_addr + (0x06 << 1);
+
+ ap->ioaddr.data_addr = info->ide_addr + (ATA_REG_DATA << 1);
+ ap->ioaddr.error_addr = info->ide_addr + (ATA_REG_ERR << 1);
+ ap->ioaddr.feature_addr = info->ide_addr + (ATA_REG_FEATURE << 1);
+ ap->ioaddr.nsect_addr = info->ide_addr + (ATA_REG_NSECT << 1);
+ ap->ioaddr.lbal_addr = info->ide_addr + (ATA_REG_LBAL << 1);
+ ap->ioaddr.lbam_addr = info->ide_addr + (ATA_REG_LBAM << 1);
+ ap->ioaddr.lbah_addr = info->ide_addr + (ATA_REG_LBAH << 1);
+ ap->ioaddr.device_addr = info->ide_addr + (ATA_REG_DEVICE << 1);
+ ap->ioaddr.status_addr = info->ide_addr + (ATA_REG_STATUS << 1);
+ ap->ioaddr.command_addr = info->ide_addr + (ATA_REG_CMD << 1);
+
+ /* Set info as private data of ATA host */
+ host->private_data = info;
+
+ /* Register ATA device and return */
+ return ata_host_activate(host, info->irq, ata_interrupt,
+ IRQF_SHARED | IRQF_TRIGGER_RISING,
+ &at32_sht);
+}
+
+/*
+ * This function may come in handy for people analyzing their own
+ * EBI -> PATA adaptors.
+ */
+#ifdef DEBUG_BUS
+
+static void __init pata_at32_debug_bus(struct device *dev,
+ struct at32_ide_info *info)
+{
+ const int d1 = 0xff;
+ const int d2 = 0x00;
+
+ int i;
+
+ /* Write 8-bit values (registers) */
+ iowrite8(d1, info->alt_addr + (0x06 << 1));
+ iowrite8(d2, info->alt_addr + (0x06 << 1));
+
+ for (i = 0; i < 8; i++) {
+ iowrite8(d1, info->ide_addr + (i << 1));
+ iowrite8(d2, info->ide_addr + (i << 1));
+ }
+
+ /* Write 16 bit values (data) */
+ iowrite16(d1, info->ide_addr);
+ iowrite16(d1 << 8, info->ide_addr);
+
+ iowrite16(d1, info->ide_addr);
+ iowrite16(d1 << 8, info->ide_addr);
+}
+
+#endif
+
+static int __init pata_at32_probe(struct platform_device *pdev)
+{
+ const struct ata_timing initial_timing =
+ {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0};
+
+ struct device *dev = &pdev->dev;
+ struct at32_ide_info *info;
+ struct ide_platform_data *board = pdev->dev.platform_data;
+ struct resource *res;
+
+ int irq;
+ int ret;
+
+ if (!board)
+ return -ENXIO;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ /* Retrive IRQ */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ /* Setup struct containing private infomation */
+ info = kzalloc(sizeof(struct at32_ide_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ memset(info, 0, sizeof(struct at32_ide_info));
+
+ info->irq = irq;
+ info->cs = board->cs;
+
+ /* Request memory resources */
+ info->res_ide.start = res->start + CF_IDE_OFFSET;
+ info->res_ide.end = info->res_ide.start + CF_RES_SIZE - 1;
+ info->res_ide.name = "ide";
+ info->res_ide.flags = IORESOURCE_MEM;
+
+ ret = request_resource(res, &info->res_ide);
+ if (ret)
+ goto err_req_res_ide;
+
+ info->res_alt.start = res->start + CF_ALT_IDE_OFFSET;
+ info->res_alt.end = info->res_alt.start + CF_RES_SIZE - 1;
+ info->res_alt.name = "alt";
+ info->res_alt.flags = IORESOURCE_MEM;
+
+ ret = request_resource(res, &info->res_alt);
+ if (ret)
+ goto err_req_res_alt;
+
+ /* Setup non-timing elements of SMC */
+ info->smc.bus_width = 2; /* 16 bit data bus */
+ info->smc.nrd_controlled = 1; /* Sample data on rising edge of NRD */
+ info->smc.nwe_controlled = 0; /* Drive data on falling edge of NCS */
+ info->smc.nwait_mode = 3; /* NWAIT is in READY mode */
+ info->smc.byte_write = 0; /* Byte select access type */
+ info->smc.tdf_mode = 0; /* TDF optimization disabled */
+ info->smc.tdf_cycles = 0; /* No TDF wait cycles */
+
+ /* Setup ATA timing */
+ ret = pata_at32_setup_timing(dev, info, &initial_timing);
+ if (ret)
+ goto err_setup_timing;
+
+ /* Setup ATA addresses */
+ ret = -ENOMEM;
+ info->ide_addr = devm_ioremap(dev, info->res_ide.start, 16);
+ info->alt_addr = devm_ioremap(dev, info->res_alt.start, 16);
+ if (!info->ide_addr || !info->alt_addr)
+ goto err_ioremap;
+
+#ifdef DEBUG_BUS
+ pata_at32_debug_bus(dev, info);
+#endif
+
+ /* Register ATA device */
+ ret = pata_at32_init_one(dev, info);
+ if (ret)
+ goto err_ata_device;
+
+ return 0;
+
+ err_ata_device:
+ err_ioremap:
+ err_setup_timing:
+ release_resource(&info->res_alt);
+ err_req_res_alt:
+ release_resource(&info->res_ide);
+ err_req_res_ide:
+ kfree(info);
+
+ return ret;
+}
+
+static int __exit pata_at32_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct at32_ide_info *info;
+
+ if (!host)
+ return 0;
+
+ info = host->private_data;
+ ata_host_detach(host);
+
+ if (!info)
+ return 0;
+
+ release_resource(&info->res_ide);
+ release_resource(&info->res_alt);
+
+ kfree(info);
+
+ return 0;
+}
+
+static struct platform_driver pata_at32_driver = {
+ .remove = __exit_p(pata_at32_remove),
+ .driver = {
+ .name = "at32_ide",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pata_at32_init(void)
+{
+ return platform_driver_probe(&pata_at32_driver, pata_at32_probe);
+}
+
+static void __exit pata_at32_exit(void)
+{
+ platform_driver_unregister(&pata_at32_driver);
+}
+
+module_init(pata_at32_init);
+module_exit(pata_at32_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AVR32 SMC/CFC PATA Driver");
+MODULE_AUTHOR("Kristoffer Nyborg Gregertsen <kngregertsen@norway.atmel.com>");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 86f85a2cab7..9623f529553 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -33,8 +33,9 @@ enum {
ATIIXP_IDE_UDMA_MODE = 0x56
};
-static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int atiixp_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
static const struct pci_bits atiixp_enable_bits[] = {
{ 0x48, 1, 0x01, 0x00 },
{ 0x48, 1, 0x08, 0x00 }
@@ -44,7 +45,7 @@ static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static void atiixp_error_handler(struct ata_port *ap)
@@ -172,6 +173,9 @@ static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
*
* When DMA begins we need to ensure that the UDMA control
* register for the channel is correctly set.
+ *
+ * Note: The host lock held by the libata layer protects
+ * us from two channels both trying to set DMA bits at once
*/
static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
@@ -198,6 +202,9 @@ static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
*
* DMA has completed. Clear the UDMA flag as the next operations will
* be PIO ones not UDMA data transfer.
+ *
+ * Note: The host lock held by the libata layer protects
+ * us from two channels both trying to set DMA bits at once
*/
static void atiixp_bmdma_stop(struct ata_queued_cmd *qc)
@@ -232,7 +239,6 @@ static struct scsi_host_template atiixp_sht = {
};
static struct ata_port_operations atiixp_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = atiixp_set_piomode,
.set_dmamode = atiixp_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -261,9 +267,8 @@ static struct ata_port_operations atiixp_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
new file mode 100644
index 00000000000..b5e38426b81
--- /dev/null
+++ b/drivers/ata/pata_bf54x.c
@@ -0,0 +1,1624 @@
+/*
+ * File: drivers/ata/pata_bf54x.c
+ * Author: Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * Created:
+ * Description: PATA Driver for blackfin 54x
+ *
+ * Modified:
+ * Copyright 2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <asm/dma.h>
+#include <asm/gpio.h>
+#include <asm/portmux.h>
+
+#define DRV_NAME "pata-bf54x"
+#define DRV_VERSION "0.9"
+
+#define ATA_REG_CTRL 0x0E
+#define ATA_REG_ALTSTATUS ATA_REG_CTRL
+
+/* These are the offset of the controller's registers */
+#define ATAPI_OFFSET_CONTROL 0x00
+#define ATAPI_OFFSET_STATUS 0x04
+#define ATAPI_OFFSET_DEV_ADDR 0x08
+#define ATAPI_OFFSET_DEV_TXBUF 0x0c
+#define ATAPI_OFFSET_DEV_RXBUF 0x10
+#define ATAPI_OFFSET_INT_MASK 0x14
+#define ATAPI_OFFSET_INT_STATUS 0x18
+#define ATAPI_OFFSET_XFER_LEN 0x1c
+#define ATAPI_OFFSET_LINE_STATUS 0x20
+#define ATAPI_OFFSET_SM_STATE 0x24
+#define ATAPI_OFFSET_TERMINATE 0x28
+#define ATAPI_OFFSET_PIO_TFRCNT 0x2c
+#define ATAPI_OFFSET_DMA_TFRCNT 0x30
+#define ATAPI_OFFSET_UMAIN_TFRCNT 0x34
+#define ATAPI_OFFSET_UDMAOUT_TFRCNT 0x38
+#define ATAPI_OFFSET_REG_TIM_0 0x40
+#define ATAPI_OFFSET_PIO_TIM_0 0x44
+#define ATAPI_OFFSET_PIO_TIM_1 0x48
+#define ATAPI_OFFSET_MULTI_TIM_0 0x50
+#define ATAPI_OFFSET_MULTI_TIM_1 0x54
+#define ATAPI_OFFSET_MULTI_TIM_2 0x58
+#define ATAPI_OFFSET_ULTRA_TIM_0 0x60
+#define ATAPI_OFFSET_ULTRA_TIM_1 0x64
+#define ATAPI_OFFSET_ULTRA_TIM_2 0x68
+#define ATAPI_OFFSET_ULTRA_TIM_3 0x6c
+
+
+#define ATAPI_GET_CONTROL(base)\
+ bfin_read16(base + ATAPI_OFFSET_CONTROL)
+#define ATAPI_SET_CONTROL(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_CONTROL, val)
+#define ATAPI_GET_STATUS(base)\
+ bfin_read16(base + ATAPI_OFFSET_STATUS)
+#define ATAPI_GET_DEV_ADDR(base)\
+ bfin_read16(base + ATAPI_OFFSET_DEV_ADDR)
+#define ATAPI_SET_DEV_ADDR(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_DEV_ADDR, val)
+#define ATAPI_GET_DEV_TXBUF(base)\
+ bfin_read16(base + ATAPI_OFFSET_DEV_TXBUF)
+#define ATAPI_SET_DEV_TXBUF(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_DEV_TXBUF, val)
+#define ATAPI_GET_DEV_RXBUF(base)\
+ bfin_read16(base + ATAPI_OFFSET_DEV_RXBUF)
+#define ATAPI_SET_DEV_RXBUF(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_DEV_RXBUF, val)
+#define ATAPI_GET_INT_MASK(base)\
+ bfin_read16(base + ATAPI_OFFSET_INT_MASK)
+#define ATAPI_SET_INT_MASK(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_INT_MASK, val)
+#define ATAPI_GET_INT_STATUS(base)\
+ bfin_read16(base + ATAPI_OFFSET_INT_STATUS)
+#define ATAPI_SET_INT_STATUS(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_INT_STATUS, val)
+#define ATAPI_GET_XFER_LEN(base)\
+ bfin_read16(base + ATAPI_OFFSET_XFER_LEN)
+#define ATAPI_SET_XFER_LEN(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_XFER_LEN, val)
+#define ATAPI_GET_LINE_STATUS(base)\
+ bfin_read16(base + ATAPI_OFFSET_LINE_STATUS)
+#define ATAPI_GET_SM_STATE(base)\
+ bfin_read16(base + ATAPI_OFFSET_SM_STATE)
+#define ATAPI_GET_TERMINATE(base)\
+ bfin_read16(base + ATAPI_OFFSET_TERMINATE)
+#define ATAPI_SET_TERMINATE(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_TERMINATE, val)
+#define ATAPI_GET_PIO_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_PIO_TFRCNT)
+#define ATAPI_GET_DMA_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_DMA_TFRCNT)
+#define ATAPI_GET_UMAIN_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_UMAIN_TFRCNT)
+#define ATAPI_GET_UDMAOUT_TFRCNT(base)\
+ bfin_read16(base + ATAPI_OFFSET_UDMAOUT_TFRCNT)
+#define ATAPI_GET_REG_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_REG_TIM_0)
+#define ATAPI_SET_REG_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_REG_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_PIO_TIM_0)
+#define ATAPI_SET_PIO_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_PIO_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_1(base)\
+ bfin_read16(base + ATAPI_OFFSET_PIO_TIM_1)
+#define ATAPI_SET_PIO_TIM_1(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_PIO_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_0)
+#define ATAPI_SET_MULTI_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_0, val)
+#define ATAPI_GET_MULTI_TIM_1(base)\
+ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_1)
+#define ATAPI_SET_MULTI_TIM_1(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_2(base)\
+ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_2)
+#define ATAPI_SET_MULTI_TIM_2(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_0(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_0)
+#define ATAPI_SET_ULTRA_TIM_0(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_0, val)
+#define ATAPI_GET_ULTRA_TIM_1(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_1)
+#define ATAPI_SET_ULTRA_TIM_1(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_1, val)
+#define ATAPI_GET_ULTRA_TIM_2(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_2)
+#define ATAPI_SET_ULTRA_TIM_2(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_3(base)\
+ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_3)
+#define ATAPI_SET_ULTRA_TIM_3(base, val)\
+ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_3, val)
+
+/**
+ * PIO Mode - Frequency compatibility
+ */
+/* mode: 0 1 2 3 4 */
+static const u32 pio_fsclk[] =
+{ 33333333, 33333333, 33333333, 33333333, 33333333 };
+
+/**
+ * MDMA Mode - Frequency compatibility
+ */
+/* mode: 0 1 2 */
+static const u32 mdma_fsclk[] = { 33333333, 33333333, 33333333 };
+
+/**
+ * UDMA Mode - Frequency compatibility
+ *
+ * UDMA5 - 100 MB/s - SCLK = 133 MHz
+ * UDMA4 - 66 MB/s - SCLK >= 80 MHz
+ * UDMA3 - 44.4 MB/s - SCLK >= 50 MHz
+ * UDMA2 - 33 MB/s - SCLK >= 40 MHz
+ */
+/* mode: 0 1 2 3 4 5 */
+static const u32 udma_fsclk[] =
+{ 33333333, 33333333, 40000000, 50000000, 80000000, 133333333 };
+
+/**
+ * Register transfer timing table
+ */
+/* mode: 0 1 2 3 4 */
+/* Cycle Time */
+static const u32 reg_t0min[] = { 600, 383, 330, 180, 120 };
+/* DIOR/DIOW to end cycle */
+static const u32 reg_t2min[] = { 290, 290, 290, 70, 25 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 reg_teocmin[] = { 290, 290, 290, 80, 70 };
+
+/**
+ * PIO timing table
+ */
+/* mode: 0 1 2 3 4 */
+/* Cycle Time */
+static const u32 pio_t0min[] = { 600, 383, 240, 180, 120 };
+/* Address valid to DIOR/DIORW */
+static const u32 pio_t1min[] = { 70, 50, 30, 30, 25 };
+/* DIOR/DIOW to end cycle */
+static const u32 pio_t2min[] = { 165, 125, 100, 80, 70 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 pio_teocmin[] = { 165, 125, 100, 70, 25 };
+/* DIOW data hold */
+static const u32 pio_t4min[] = { 30, 20, 15, 10, 10 };
+
+/* ******************************************************************
+ * Multiword DMA timing table
+ * ******************************************************************
+ */
+/* mode: 0 1 2 */
+/* Cycle Time */
+static const u32 mdma_t0min[] = { 480, 150, 120 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 mdma_tdmin[] = { 215, 80, 70 };
+/* DMACK to read data released */
+static const u32 mdma_thmin[] = { 20, 15, 10 };
+/* DIOR/DIOW to DMACK hold */
+static const u32 mdma_tjmin[] = { 20, 5, 5 };
+/* DIOR negated pulse width */
+static const u32 mdma_tkrmin[] = { 50, 50, 25 };
+/* DIOR negated pulse width */
+static const u32 mdma_tkwmin[] = { 215, 50, 25 };
+/* CS[1:0] valid to DIOR/DIOW */
+static const u32 mdma_tmmin[] = { 50, 30, 25 };
+/* DMACK to read data released */
+static const u32 mdma_tzmax[] = { 20, 25, 25 };
+
+/**
+ * Ultra DMA timing table
+ */
+/* mode: 0 1 2 3 4 5 */
+static const u32 udma_tcycmin[] = { 112, 73, 54, 39, 25, 17 };
+static const u32 udma_tdvsmin[] = { 70, 48, 31, 20, 7, 5 };
+static const u32 udma_tenvmax[] = { 70, 70, 70, 55, 55, 50 };
+static const u32 udma_trpmin[] = { 160, 125, 100, 100, 100, 85 };
+static const u32 udma_tmin[] = { 5, 5, 5, 5, 3, 3 };
+
+
+static const u32 udma_tmlimin = 20;
+static const u32 udma_tzahmin = 20;
+static const u32 udma_tenvmin = 20;
+static const u32 udma_tackmin = 20;
+static const u32 udma_tssmin = 50;
+
+/**
+ *
+ * Function: num_clocks_min
+ *
+ * Description:
+ * calculate number of SCLK cycles to meet minimum timing
+ */
+static unsigned short num_clocks_min(unsigned long tmin,
+ unsigned long fsclk)
+{
+ unsigned long tmp ;
+ unsigned short result;
+
+ tmp = tmin * (fsclk/1000/1000) / 1000;
+ result = (unsigned short)tmp;
+ if ((tmp*1000*1000) < (tmin*(fsclk/1000))) {
+ result++;
+ }
+
+ return result;
+}
+
+/**
+ * bfin_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ int mode = adev->pio_mode - XFER_PIO_0;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int fsclk = get_sclk();
+ unsigned short teoc_reg, t2_reg, teoc_pio;
+ unsigned short t4_reg, t2_pio, t1_reg;
+ unsigned short n0, n6, t6min = 5;
+
+ /* the most restrictive timing value is t6 and tc, the DIOW - data hold
+ * If one SCLK pulse is longer than this minimum value then register
+ * transfers cannot be supported at this frequency.
+ */
+ n6 = num_clocks_min(t6min, fsclk);
+ if (mode >= 0 && mode <= 4 && n6 >= 1) {
+ pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);
+ /* calculate the timing values for register transfers. */
+ while (mode > 0 && pio_fsclk[mode] > fsclk)
+ mode--;
+
+ /* DIOR/DIOW to end cycle time */
+ t2_reg = num_clocks_min(reg_t2min[mode], fsclk);
+ /* DIOR/DIOW asserted pulse width */
+ teoc_reg = num_clocks_min(reg_teocmin[mode], fsclk);
+ /* Cycle Time */
+ n0 = num_clocks_min(reg_t0min[mode], fsclk);
+
+ /* increase t2 until we meed the minimum cycle length */
+ if (t2_reg + teoc_reg < n0)
+ t2_reg = n0 - teoc_reg;
+
+ /* calculate the timing values for pio transfers. */
+
+ /* DIOR/DIOW to end cycle time */
+ t2_pio = num_clocks_min(pio_t2min[mode], fsclk);
+ /* DIOR/DIOW asserted pulse width */
+ teoc_pio = num_clocks_min(pio_teocmin[mode], fsclk);
+ /* Cycle Time */
+ n0 = num_clocks_min(pio_t0min[mode], fsclk);
+
+ /* increase t2 until we meed the minimum cycle length */
+ if (t2_pio + teoc_pio < n0)
+ t2_pio = n0 - teoc_pio;
+
+ /* Address valid to DIOR/DIORW */
+ t1_reg = num_clocks_min(pio_t1min[mode], fsclk);
+
+ /* DIOW data hold */
+ t4_reg = num_clocks_min(pio_t4min[mode], fsclk);
+
+ ATAPI_SET_REG_TIM_0(base, (teoc_reg<<8 | t2_reg));
+ ATAPI_SET_PIO_TIM_0(base, (t4_reg<<12 | t2_pio<<4 | t1_reg));
+ ATAPI_SET_PIO_TIM_1(base, teoc_pio);
+ if (mode > 2) {
+ ATAPI_SET_CONTROL(base,
+ ATAPI_GET_CONTROL(base) | IORDY_EN);
+ } else {
+ ATAPI_SET_CONTROL(base,
+ ATAPI_GET_CONTROL(base) & ~IORDY_EN);
+ }
+
+ /* Disable host ATAPI PIO interrupts */
+ ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
+ & ~(PIO_DONE_MASK | HOST_TERM_XFER_MASK));
+ SSYNC();
+ }
+}
+
+/**
+ * bfin_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ * @udma: udma mode, 0 - 6
+ *
+ * Set UDMA mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ int mode;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned long fsclk = get_sclk();
+ unsigned short tenv, tack, tcyc_tdvs, tdvs, tmli, tss, trp, tzah;
+ unsigned short tm, td, tkr, tkw, teoc, th;
+ unsigned short n0, nf, tfmin = 5;
+ unsigned short nmin, tcyc;
+
+ mode = adev->dma_mode - XFER_UDMA_0;
+ if (mode >= 0 && mode <= 5) {
+ pr_debug("set udmamode: mode=%d\n", mode);
+ /* the most restrictive timing value is t6 and tc,
+ * the DIOW - data hold. If one SCLK pulse is longer
+ * than this minimum value then register
+ * transfers cannot be supported at this frequency.
+ */
+ while (mode > 0 && udma_fsclk[mode] > fsclk)
+ mode--;
+
+ nmin = num_clocks_min(udma_tmin[mode], fsclk);
+ if (nmin >= 1) {
+ /* calculate the timing values for Ultra DMA. */
+ tdvs = num_clocks_min(udma_tdvsmin[mode], fsclk);
+ tcyc = num_clocks_min(udma_tcycmin[mode], fsclk);
+ tcyc_tdvs = 2;
+
+ /* increase tcyc - tdvs (tcyc_tdvs) until we meed
+ * the minimum cycle length
+ */
+ if (tdvs + tcyc_tdvs < tcyc)
+ tcyc_tdvs = tcyc - tdvs;
+
+ /* Mow assign the values required for the timing
+ * registers
+ */
+ if (tcyc_tdvs < 2)
+ tcyc_tdvs = 2;
+
+ if (tdvs < 2)
+ tdvs = 2;
+
+ tack = num_clocks_min(udma_tackmin, fsclk);
+ tss = num_clocks_min(udma_tssmin, fsclk);
+ tmli = num_clocks_min(udma_tmlimin, fsclk);
+ tzah = num_clocks_min(udma_tzahmin, fsclk);
+ trp = num_clocks_min(udma_trpmin[mode], fsclk);
+ tenv = num_clocks_min(udma_tenvmin, fsclk);
+ if (tenv <= udma_tenvmax[mode]) {
+ ATAPI_SET_ULTRA_TIM_0(base, (tenv<<8 | tack));
+ ATAPI_SET_ULTRA_TIM_1(base,
+ (tcyc_tdvs<<8 | tdvs));
+ ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss));
+ ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah));
+
+ /* Enable host ATAPI Untra DMA interrupts */
+ ATAPI_SET_INT_MASK(base,
+ ATAPI_GET_INT_MASK(base)
+ | UDMAIN_DONE_MASK
+ | UDMAOUT_DONE_MASK
+ | UDMAIN_TERM_MASK
+ | UDMAOUT_TERM_MASK);
+ }
+ }
+ }
+
+ mode = adev->dma_mode - XFER_MW_DMA_0;
+ if (mode >= 0 && mode <= 2) {
+ pr_debug("set mdmamode: mode=%d\n", mode);
+ /* the most restrictive timing value is tf, the DMACK to
+ * read data released. If one SCLK pulse is longer than
+ * this maximum value then the MDMA mode
+ * cannot be supported at this frequency.
+ */
+ while (mode > 0 && mdma_fsclk[mode] > fsclk)
+ mode--;
+
+ nf = num_clocks_min(tfmin, fsclk);
+ if (nf >= 1) {
+ /* calculate the timing values for Multi-word DMA. */
+
+ /* DIOR/DIOW asserted pulse width */
+ td = num_clocks_min(mdma_tdmin[mode], fsclk);
+
+ /* DIOR negated pulse width */
+ tkw = num_clocks_min(mdma_tkwmin[mode], fsclk);
+
+ /* Cycle Time */
+ n0 = num_clocks_min(mdma_t0min[mode], fsclk);
+
+ /* increase tk until we meed the minimum cycle length */
+ if (tkw + td < n0)
+ tkw = n0 - td;
+
+ /* DIOR negated pulse width - read */
+ tkr = num_clocks_min(mdma_tkrmin[mode], fsclk);
+ /* CS{1:0] valid to DIOR/DIOW */
+ tm = num_clocks_min(mdma_tmmin[mode], fsclk);
+ /* DIOR/DIOW to DMACK hold */
+ teoc = num_clocks_min(mdma_tjmin[mode], fsclk);
+ /* DIOW Data hold */
+ th = num_clocks_min(mdma_thmin[mode], fsclk);
+
+ ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td));
+ ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw));
+ ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th));
+
+ /* Enable host ATAPI Multi DMA interrupts */
+ ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
+ | MULTI_DONE_MASK | MULTI_TERM_MASK);
+ SSYNC();
+ }
+ }
+ return;
+}
+
+/**
+ *
+ * Function: wait_complete
+ *
+ * Description: Waits the interrupt from device
+ *
+ */
+static inline void wait_complete(void __iomem *base, unsigned short mask)
+{
+ unsigned short status;
+ unsigned int i = 0;
+
+#define PATA_BF54X_WAIT_TIMEOUT 10000
+
+ for (i = 0; i < PATA_BF54X_WAIT_TIMEOUT; i++) {
+ status = ATAPI_GET_INT_STATUS(base) & mask;
+ if (status)
+ break;
+ }
+
+ ATAPI_SET_INT_STATUS(base, mask);
+}
+
+/**
+ *
+ * Function: write_atapi_register
+ *
+ * Description: Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_register(void __iomem *base,
+ unsigned long ata_reg, unsigned short value)
+{
+ /* Program the ATA_DEV_TXBUF register with write data (to be
+ * written into the device).
+ */
+ ATAPI_SET_DEV_TXBUF(base, value);
+
+ /* Program the ATA_DEV_ADDR register with address of the
+ * device register (0x01 to 0x0F).
+ */
+ ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+ /* Program the ATA_CTRL register with dir set to write (1)
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (We need to wait on and clear rhe ATA_DEV_INT interrupt status)
+ */
+ wait_complete(base, PIO_DONE_INT);
+}
+
+/**
+ *
+ * Function: read_atapi_register
+ *
+ *Description: Reads from ATA Device Resgister
+ *
+ */
+
+static unsigned short read_atapi_register(void __iomem *base,
+ unsigned long ata_reg)
+{
+ /* Program the ATA_DEV_ADDR register with address of the
+ * device register (0x01 to 0x0F).
+ */
+ ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+ /* Program the ATA_CTRL register with dir set to read (0) and
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (PIO_DONE interrupt is set and it doesn't seem to matter
+ * that we don't clear it)
+ */
+ wait_complete(base, PIO_DONE_INT);
+
+ /* Read the ATA_DEV_RXBUF register with write data (to be
+ * written into the device).
+ */
+ return ATAPI_GET_DEV_RXBUF(base);
+}
+
+/**
+ *
+ * Function: write_atapi_register_data
+ *
+ * Description: Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_data(void __iomem *base,
+ int len, unsigned short *buf)
+{
+ int i;
+
+ /* Set transfer length to 1 */
+ ATAPI_SET_XFER_LEN(base, 1);
+
+ /* Program the ATA_DEV_ADDR register with address of the
+ * ATA_REG_DATA
+ */
+ ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+ /* Program the ATA_CTRL register with dir set to write (1)
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ for (i = 0; i < len; i++) {
+ /* Program the ATA_DEV_TXBUF register with write data (to be
+ * written into the device).
+ */
+ ATAPI_SET_DEV_TXBUF(base, buf[i]);
+
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (We need to wait on and clear rhe ATA_DEV_INT
+ * interrupt status)
+ */
+ wait_complete(base, PIO_DONE_INT);
+ }
+}
+
+/**
+ *
+ * Function: read_atapi_register_data
+ *
+ * Description: Reads from ATA Device Resgister
+ *
+ */
+
+static void read_atapi_data(void __iomem *base,
+ int len, unsigned short *buf)
+{
+ int i;
+
+ /* Set transfer length to 1 */
+ ATAPI_SET_XFER_LEN(base, 1);
+
+ /* Program the ATA_DEV_ADDR register with address of the
+ * ATA_REG_DATA
+ */
+ ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+ /* Program the ATA_CTRL register with dir set to read (0) and
+ */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+ /* ensure PIO DMA is not set */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+ for (i = 0; i < len; i++) {
+ /* and start the transfer */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+ /* Wait for the interrupt to indicate the end of the transfer.
+ * (PIO_DONE interrupt is set and it doesn't seem to matter
+ * that we don't clear it)
+ */
+ wait_complete(base, PIO_DONE_INT);
+
+ /* Read the ATA_DEV_RXBUF register with write data (to be
+ * written into the device).
+ */
+ buf[i] = ATAPI_GET_DEV_RXBUF(base);
+ }
+}
+
+/**
+ * bfin_tf_load - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @tf: ATA taskfile register set
+ *
+ * Note: Original code is ata_tf_load().
+ */
+
+static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ write_atapi_register(base, ATA_REG_CTRL, tf->ctl);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr) {
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ write_atapi_register(base, ATA_REG_FEATURE,
+ tf->hob_feature);
+ write_atapi_register(base, ATA_REG_NSECT,
+ tf->hob_nsect);
+ write_atapi_register(base, ATA_REG_LBAL, tf->hob_lbal);
+ write_atapi_register(base, ATA_REG_LBAM, tf->hob_lbam);
+ write_atapi_register(base, ATA_REG_LBAH, tf->hob_lbah);
+ pr_debug("hob: feat 0x%X nsect 0x%X, lba 0x%X "
+ "0x%X 0x%X\n",
+ tf->hob_feature,
+ tf->hob_nsect,
+ tf->hob_lbal,
+ tf->hob_lbam,
+ tf->hob_lbah);
+ }
+
+ write_atapi_register(base, ATA_REG_FEATURE, tf->feature);
+ write_atapi_register(base, ATA_REG_NSECT, tf->nsect);
+ write_atapi_register(base, ATA_REG_LBAL, tf->lbal);
+ write_atapi_register(base, ATA_REG_LBAM, tf->lbam);
+ write_atapi_register(base, ATA_REG_LBAH, tf->lbah);
+ pr_debug("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+ tf->feature,
+ tf->nsect,
+ tf->lbal,
+ tf->lbam,
+ tf->lbah);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ write_atapi_register(base, ATA_REG_DEVICE, tf->device);
+ pr_debug("device 0x%X\n", tf->device);
+ }
+
+ ata_wait_idle(ap);
+}
+
+/**
+ * bfin_check_status - Read device status reg & clear interrupt
+ * @ap: port where the device is
+ *
+ * Note: Original code is ata_check_status().
+ */
+
+static u8 bfin_check_status(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ return read_atapi_register(base, ATA_REG_STATUS);
+}
+
+/**
+ * bfin_tf_read - input device's ATA taskfile shadow registers
+ * @ap: Port from which input is read
+ * @tf: ATA taskfile register set for storing input
+ *
+ * Note: Original code is ata_tf_read().
+ */
+
+static void bfin_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ tf->command = bfin_check_status(ap);
+ tf->feature = read_atapi_register(base, ATA_REG_ERR);
+ tf->nsect = read_atapi_register(base, ATA_REG_NSECT);
+ tf->lbal = read_atapi_register(base, ATA_REG_LBAL);
+ tf->lbam = read_atapi_register(base, ATA_REG_LBAM);
+ tf->lbah = read_atapi_register(base, ATA_REG_LBAH);
+ tf->device = read_atapi_register(base, ATA_REG_DEVICE);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ write_atapi_register(base, ATA_REG_CTRL, tf->ctl | ATA_HOB);
+ tf->hob_feature = read_atapi_register(base, ATA_REG_ERR);
+ tf->hob_nsect = read_atapi_register(base, ATA_REG_NSECT);
+ tf->hob_lbal = read_atapi_register(base, ATA_REG_LBAL);
+ tf->hob_lbam = read_atapi_register(base, ATA_REG_LBAM);
+ tf->hob_lbah = read_atapi_register(base, ATA_REG_LBAH);
+ }
+}
+
+/**
+ * bfin_exec_command - issue ATA command to host controller
+ * @ap: port to which command is being issued
+ * @tf: ATA taskfile register set
+ *
+ * Note: Original code is ata_exec_command().
+ */
+
+static void bfin_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ pr_debug("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+
+ write_atapi_register(base, ATA_REG_CMD, tf->command);
+ ata_pause(ap);
+}
+
+/**
+ * bfin_check_altstatus - Read device alternate status reg
+ * @ap: port where the device is
+ */
+
+static u8 bfin_check_altstatus(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ return read_atapi_register(base, ATA_REG_ALTSTATUS);
+}
+
+/**
+ * bfin_std_dev_select - Select device 0/1 on ATA bus
+ * @ap: ATA channel to manipulate
+ * @device: ATA device (numbered from zero) to select
+ *
+ * Note: Original code is ata_std_dev_select().
+ */
+
+static void bfin_std_dev_select(struct ata_port *ap, unsigned int device)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 tmp;
+
+ if (device == 0)
+ tmp = ATA_DEVICE_OBS;
+ else
+ tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+ write_atapi_register(base, ATA_REG_DEVICE, tmp);
+ ata_pause(ap);
+}
+
+/**
+ * bfin_bmdma_setup - Set up IDE DMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * Note: Original code is ata_bmdma_setup().
+ */
+
+static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ unsigned short config = WDSIZE_16;
+ struct scatterlist *sg;
+
+ pr_debug("in atapi dma setup\n");
+ /* Program the ATA_CTRL register with dir */
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ /* fill the ATAPI DMA controller */
+ set_dma_config(CH_ATAPI_TX, config);
+ set_dma_x_modify(CH_ATAPI_TX, 2);
+ ata_for_each_sg(sg, qc) {
+ set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg));
+ set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1);
+ }
+ } else {
+ config |= WNR;
+ /* fill the ATAPI DMA controller */
+ set_dma_config(CH_ATAPI_RX, config);
+ set_dma_x_modify(CH_ATAPI_RX, 2);
+ ata_for_each_sg(sg, qc) {
+ set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg));
+ set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1);
+ }
+ }
+}
+
+/**
+ * bfin_bmdma_start - Start an IDE DMA transaction
+ * @qc: Info associated with this ATA transaction.
+ *
+ * Note: Original code is ata_bmdma_start().
+ */
+
+static void bfin_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ struct scatterlist *sg;
+
+ pr_debug("in atapi dma start\n");
+ if (!(ap->udma_mask || ap->mwdma_mask))
+ return;
+
+ /* start ATAPI DMA controller*/
+ if (qc->tf.flags & ATA_TFLAG_WRITE) {
+ /*
+ * On blackfin arch, uncacheable memory is not
+ * allocated with flag GFP_DMA. DMA buffer from
+ * common kenel code should be flushed if WB
+ * data cache is enabled. Otherwise, this loop
+ * is an empty loop and optimized out.
+ */
+ ata_for_each_sg(sg, qc) {
+ flush_dcache_range(sg_dma_address(sg),
+ sg_dma_address(sg) + sg_dma_len(sg));
+ }
+ enable_dma(CH_ATAPI_TX);
+ pr_debug("enable udma write\n");
+
+ /* Send ATA DMA write command */
+ bfin_exec_command(ap, &qc->tf);
+
+ /* set ATA DMA write direction */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
+ | XFER_DIR));
+ } else {
+ enable_dma(CH_ATAPI_RX);
+ pr_debug("enable udma read\n");
+
+ /* Send ATA DMA read command */
+ bfin_exec_command(ap, &qc->tf);
+
+ /* set ATA DMA read direction */
+ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
+ & ~XFER_DIR));
+ }
+
+ /* Reset all transfer count */
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);
+
+ /* Set transfer length to buffer len */
+ ata_for_each_sg(sg, qc) {
+ ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
+ }
+
+ /* Enable ATA DMA operation*/
+ if (ap->udma_mask)
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)
+ | ULTRA_START);
+ else
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)
+ | MULTI_START);
+}
+
+/**
+ * bfin_bmdma_stop - Stop IDE DMA transfer
+ * @qc: Command we are ending DMA for
+ */
+
+static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scatterlist *sg;
+
+ pr_debug("in atapi dma stop\n");
+ if (!(ap->udma_mask || ap->mwdma_mask))
+ return;
+
+ /* stop ATAPI DMA controller*/
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ disable_dma(CH_ATAPI_TX);
+ else {
+ disable_dma(CH_ATAPI_RX);
+ if (ap->hsm_task_state & HSM_ST_LAST) {
+ /*
+ * On blackfin arch, uncacheable memory is not
+ * allocated with flag GFP_DMA. DMA buffer from
+ * common kenel code should be invalidated if
+ * data cache is enabled. Otherwise, this loop
+ * is an empty loop and optimized out.
+ */
+ ata_for_each_sg(sg, qc) {
+ invalidate_dcache_range(
+ sg_dma_address(sg),
+ sg_dma_address(sg)
+ + sg_dma_len(sg));
+ }
+ }
+ }
+}
+
+/**
+ * bfin_devchk - PATA device presence detection
+ * @ap: ATA channel to examine
+ * @device: Device to examine (starting at zero)
+ *
+ * Note: Original code is ata_devchk().
+ */
+
+static unsigned int bfin_devchk(struct ata_port *ap,
+ unsigned int device)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 nsect, lbal;
+
+ bfin_std_dev_select(ap, device);
+
+ write_atapi_register(base, ATA_REG_NSECT, 0x55);
+ write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+ write_atapi_register(base, ATA_REG_NSECT, 0xaa);
+ write_atapi_register(base, ATA_REG_LBAL, 0x55);
+
+ write_atapi_register(base, ATA_REG_NSECT, 0x55);
+ write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+ nsect = read_atapi_register(base, ATA_REG_NSECT);
+ lbal = read_atapi_register(base, ATA_REG_LBAL);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return 1; /* we found a device */
+
+ return 0; /* nothing found */
+}
+
+/**
+ * bfin_bus_post_reset - PATA device post reset
+ *
+ * Note: Original code is ata_bus_post_reset().
+ */
+
+static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned int dev0 = devmask & (1 << 0);
+ unsigned int dev1 = devmask & (1 << 1);
+ unsigned long timeout;
+
+ /* if device 0 was found in ata_devchk, wait for its
+ * BSY bit to clear
+ */
+ if (dev0)
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ /* if device 1 was found in ata_devchk, wait for
+ * register access, then wait for BSY to clear
+ */
+ timeout = jiffies + ATA_TMOUT_BOOT;
+ while (dev1) {
+ u8 nsect, lbal;
+
+ bfin_std_dev_select(ap, 1);
+ nsect = read_atapi_register(base, ATA_REG_NSECT);
+ lbal = read_atapi_register(base, ATA_REG_LBAL);
+ if ((nsect == 1) && (lbal == 1))
+ break;
+ if (time_after(jiffies, timeout)) {
+ dev1 = 0;
+ break;
+ }
+ msleep(50); /* give drive a breather */
+ }
+ if (dev1)
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ /* is all this really necessary? */
+ bfin_std_dev_select(ap, 0);
+ if (dev1)
+ bfin_std_dev_select(ap, 1);
+ if (dev0)
+ bfin_std_dev_select(ap, 0);
+}
+
+/**
+ * bfin_bus_softreset - PATA device software reset
+ *
+ * Note: Original code is ata_bus_softreset().
+ */
+
+static unsigned int bfin_bus_softreset(struct ata_port *ap,
+ unsigned int devmask)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ /* software reset. causes dev0 to be selected */
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+ udelay(20);
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl | ATA_SRST);
+ udelay(20);
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+
+ /* spec mandates ">= 2ms" before checking status.
+ * We wait 150ms, because that was the magic delay used for
+ * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+ * between when the ATA command register is written, and then
+ * status is checked. Because waiting for "a while" before
+ * checking status is fine, post SRST, we perform this magic
+ * delay here as well.
+ *
+ * Old drivers/ide uses the 2mS rule and then waits for ready
+ */
+ msleep(150);
+
+ /* Before we perform post reset processing we want to see if
+ * the bus shows 0xFF because the odd clown forgets the D7
+ * pulldown resistor.
+ */
+ if (bfin_check_status(ap) == 0xFF)
+ return 0;
+
+ bfin_bus_post_reset(ap, devmask);
+
+ return 0;
+}
+
+/**
+ * bfin_std_softreset - reset host port via ATA SRST
+ * @ap: port to reset
+ * @classes: resulting classes of attached devices
+ *
+ * Note: Original code is ata_std_softreset().
+ */
+
+static int bfin_std_softreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+ unsigned int devmask = 0, err_mask;
+ u8 err;
+
+ if (ata_link_offline(link)) {
+ classes[0] = ATA_DEV_NONE;
+ goto out;
+ }
+
+ /* determine if device 0/1 are present */
+ if (bfin_devchk(ap, 0))
+ devmask |= (1 << 0);
+ if (slave_possible && bfin_devchk(ap, 1))
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ bfin_std_dev_select(ap, 0);
+
+ /* issue bus reset */
+ err_mask = bfin_bus_softreset(ap, devmask);
+ if (err_mask) {
+ ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
+ err_mask);
+ return -EIO;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_dev_try_classify(&ap->link.device[0],
+ devmask & (1 << 0), &err);
+ if (slave_possible && err != 0x81)
+ classes[1] = ata_dev_try_classify(&ap->link.device[1],
+ devmask & (1 << 1), &err);
+
+ out:
+ return 0;
+}
+
+/**
+ * bfin_bmdma_status - Read IDE DMA status
+ * @ap: Port associated with this ATA transaction.
+ */
+
+static unsigned char bfin_bmdma_status(struct ata_port *ap)
+{
+ unsigned char host_stat = 0;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ unsigned short int_status = ATAPI_GET_INT_STATUS(base);
+
+ if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) {
+ host_stat = ATA_DMA_ACTIVE;
+ }
+ if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) {
+ host_stat = ATA_DMA_INTR;
+ }
+ if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) {
+ host_stat = ATA_DMA_ERR;
+ }
+
+ return host_stat;
+}
+
+/**
+ * bfin_data_xfer - Transfer data by PIO
+ * @adev: device for this I/O
+ * @buf: data buffer
+ * @buflen: buffer length
+ * @write_data: read/write
+ *
+ * Note: Original code is ata_data_xfer().
+ */
+
+static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf,
+ unsigned int buflen, int write_data)
+{
+ struct ata_port *ap = adev->link->ap;
+ unsigned int words = buflen >> 1;
+ unsigned short *buf16 = (u16 *) buf;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ /* Transfer multiple of 2 bytes */
+ if (write_data) {
+ write_atapi_data(base, words, buf16);
+ } else {
+ read_atapi_data(base, words, buf16);
+ }
+
+ /* Transfer trailing 1 byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ unsigned short align_buf[1] = { 0 };
+ unsigned char *trailing_buf = buf + buflen - 1;
+
+ if (write_data) {
+ memcpy(align_buf, trailing_buf, 1);
+ write_atapi_data(base, 1, align_buf);
+ } else {
+ read_atapi_data(base, 1, align_buf);
+ memcpy(trailing_buf, align_buf, 1);
+ }
+ }
+}
+
+/**
+ * bfin_irq_clear - Clear ATAPI interrupt.
+ * @ap: Port associated with this ATA transaction.
+ *
+ * Note: Original code is ata_bmdma_irq_clear().
+ */
+
+static void bfin_irq_clear(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ pr_debug("in atapi irq clear\n");
+
+ ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT
+ | MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT
+ | MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT);
+}
+
+/**
+ * bfin_irq_on - Enable interrupts on a port.
+ * @ap: Port on which interrupts are enabled.
+ *
+ * Note: Original code is ata_irq_on().
+ */
+
+static unsigned char bfin_irq_on(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+ u8 tmp;
+
+ pr_debug("in atapi irq on\n");
+ ap->ctl &= ~ATA_NIEN;
+ ap->last_ctl = ap->ctl;
+
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+ tmp = ata_wait_idle(ap);
+
+ bfin_irq_clear(ap);
+
+ return tmp;
+}
+
+/**
+ * bfin_bmdma_freeze - Freeze DMA controller port
+ * @ap: port to freeze
+ *
+ * Note: Original code is ata_bmdma_freeze().
+ */
+
+static void bfin_bmdma_freeze(struct ata_port *ap)
+{
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ pr_debug("in atapi dma freeze\n");
+ ap->ctl |= ATA_NIEN;
+ ap->last_ctl = ap->ctl;
+
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+
+ /* Under certain circumstances, some controllers raise IRQ on
+ * ATA_NIEN manipulation. Also, many controllers fail to mask
+ * previously pending IRQ on ATA_NIEN assertion. Clear it.
+ */
+ ata_chk_status(ap);
+
+ bfin_irq_clear(ap);
+}
+
+/**
+ * bfin_bmdma_thaw - Thaw DMA controller port
+ * @ap: port to thaw
+ *
+ * Note: Original code is ata_bmdma_thaw().
+ */
+
+void bfin_bmdma_thaw(struct ata_port *ap)
+{
+ bfin_check_status(ap);
+ bfin_irq_clear(ap);
+ bfin_irq_on(ap);
+}
+
+/**
+ * bfin_std_postreset - standard postreset callback
+ * @ap: the target ata_port
+ * @classes: classes of attached devices
+ *
+ * Note: Original code is ata_std_postreset().
+ */
+
+static void bfin_std_postreset(struct ata_link *link, unsigned int *classes)
+{
+ struct ata_port *ap = link->ap;
+ void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+ /* re-enable interrupts */
+ bfin_irq_on(ap);
+
+ /* is double-select really necessary? */
+ if (classes[0] != ATA_DEV_NONE)
+ bfin_std_dev_select(ap, 1);
+ if (classes[1] != ATA_DEV_NONE)
+ bfin_std_dev_select(ap, 0);
+
+ /* bail out if no device is present */
+ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+ return;
+ }
+
+ /* set up device control */
+ write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+}
+
+/**
+ * bfin_error_handler - Stock error handler for DMA controller
+ * @ap: port to handle error for
+ */
+
+static void bfin_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, ata_std_prereset, bfin_std_softreset, NULL,
+ bfin_std_postreset);
+}
+
+static void bfin_port_stop(struct ata_port *ap)
+{
+ pr_debug("in atapi port stop\n");
+ if (ap->udma_mask != 0 || ap->mwdma_mask != 0) {
+ free_dma(CH_ATAPI_RX);
+ free_dma(CH_ATAPI_TX);
+ }
+}
+
+static int bfin_port_start(struct ata_port *ap)
+{
+ pr_debug("in atapi port start\n");
+ if (!(ap->udma_mask || ap->mwdma_mask))
+ return 0;
+
+ if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) {
+ if (request_dma(CH_ATAPI_TX,
+ "BFIN ATAPI TX DMA") >= 0)
+ return 0;
+
+ free_dma(CH_ATAPI_RX);
+ }
+
+ ap->udma_mask = 0;
+ ap->mwdma_mask = 0;
+ dev_err(ap->dev, "Unable to request ATAPI DMA!"
+ " Continue in PIO mode.\n");
+
+ return 0;
+}
+
+static struct scsi_host_template bfin_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = SG_NONE,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
+ .resume = ata_scsi_device_resume,
+ .suspend = ata_scsi_device_suspend,
+#endif
+};
+
+static const struct ata_port_operations bfin_pata_ops = {
+ .set_piomode = bfin_set_piomode,
+ .set_dmamode = bfin_set_dmamode,
+
+ .tf_load = bfin_tf_load,
+ .tf_read = bfin_tf_read,
+ .exec_command = bfin_exec_command,
+ .check_status = bfin_check_status,
+ .check_altstatus = bfin_check_altstatus,
+ .dev_select = bfin_std_dev_select,
+
+ .bmdma_setup = bfin_bmdma_setup,
+ .bmdma_start = bfin_bmdma_start,
+ .bmdma_stop = bfin_bmdma_stop,
+ .bmdma_status = bfin_bmdma_status,
+ .data_xfer = bfin_data_xfer,
+
+ .qc_prep = ata_noop_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .freeze = bfin_bmdma_freeze,
+ .thaw = bfin_bmdma_thaw,
+ .error_handler = bfin_error_handler,
+ .post_internal_cmd = bfin_bmdma_stop,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = bfin_irq_clear,
+ .irq_on = bfin_irq_on,
+
+ .port_start = bfin_port_start,
+ .port_stop = bfin_port_stop,
+};
+
+static struct ata_port_info bfin_port_info[] = {
+ {
+ .sht = &bfin_sht,
+ .flags = ATA_FLAG_SLAVE_POSS
+ | ATA_FLAG_MMIO
+ | ATA_FLAG_NO_LEGACY,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0,
+ .udma_mask = 0,
+ .port_ops = &bfin_pata_ops,
+ },
+};
+
+/**
+ * bfin_reset_controller - initialize BF54x ATAPI controller.
+ */
+
+static int bfin_reset_controller(struct ata_host *host)
+{
+ void __iomem *base = (void __iomem *)host->ports[0]->ioaddr.ctl_addr;
+ int count;
+ unsigned short status;
+
+ /* Disable all ATAPI interrupts */
+ ATAPI_SET_INT_MASK(base, 0);
+ SSYNC();
+
+ /* Assert the RESET signal 25us*/
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | DEV_RST);
+ udelay(30);
+
+ /* Negate the RESET signal for 2ms*/
+ ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~DEV_RST);
+ msleep(2);
+
+ /* Wait on Busy flag to clear */
+ count = 10000000;
+ do {
+ status = read_atapi_register(base, ATA_REG_STATUS);
+ } while (count-- && (status & ATA_BUSY));
+
+ /* Enable only ATAPI Device interrupt */
+ ATAPI_SET_INT_MASK(base, 1);
+ SSYNC();
+
+ return (!count);
+}
+
+/**
+ * atapi_io_port - define atapi peripheral port pins.
+ */
+static unsigned short atapi_io_port[] = {
+ P_ATAPI_RESET,
+ P_ATAPI_DIOR,
+ P_ATAPI_DIOW,
+ P_ATAPI_CS0,
+ P_ATAPI_CS1,
+ P_ATAPI_DMACK,
+ P_ATAPI_DMARQ,
+ P_ATAPI_INTRQ,
+ P_ATAPI_IORDY,
+ 0
+};
+
+/**
+ * bfin_atapi_probe - attach a bfin atapi interface
+ * @pdev: platform device
+ *
+ * Register a bfin atapi interface.
+ *
+ *
+ * Platform devices are expected to contain 2 resources per port:
+ *
+ * - I/O Base (IORESOURCE_IO)
+ * - IRQ (IORESOURCE_IRQ)
+ *
+ */
+static int __devinit bfin_atapi_probe(struct platform_device *pdev)
+{
+ int board_idx = 0;
+ struct resource *res;
+ struct ata_host *host;
+ const struct ata_port_info *ppi[] =
+ { &bfin_port_info[board_idx], NULL };
+
+ /*
+ * Simple resource validation ..
+ */
+ if (unlikely(pdev->num_resources != 2)) {
+ dev_err(&pdev->dev, "invalid number of resources\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Get the register base first
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL)
+ return -EINVAL;
+
+ /*
+ * Now that that's out of the way, wire up the port..
+ */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1);
+ if (!host)
+ return -ENOMEM;
+
+ host->ports[0]->ioaddr.ctl_addr = (void *)res->start;
+
+ if (peripheral_request_list(atapi_io_port, "atapi-io-port")) {
+ dev_err(&pdev->dev, "Requesting Peripherals faild\n");
+ return -EFAULT;
+ }
+
+ if (bfin_reset_controller(host)) {
+ peripheral_free_list(atapi_io_port);
+ dev_err(&pdev->dev, "Fail to reset ATAPI device\n");
+ return -EFAULT;
+ }
+
+ if (ata_host_activate(host, platform_get_irq(pdev, 0),
+ ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
+ peripheral_free_list(atapi_io_port);
+ dev_err(&pdev->dev, "Fail to attach ATAPI device\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/**
+ * bfin_atapi_remove - unplug a bfin atapi interface
+ * @pdev: platform device
+ *
+ * A bfin atapi device has been unplugged. Perform the needed
+ * cleanup. Also called on module unload for any active devices.
+ */
+static int __devexit bfin_atapi_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ata_host *host = dev_get_drvdata(dev);
+
+ ata_host_detach(host);
+
+ peripheral_free_list(atapi_io_port);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ return 0;
+}
+
+int bfin_atapi_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
+static struct platform_driver bfin_atapi_driver = {
+ .probe = bfin_atapi_probe,
+ .remove = __devexit_p(bfin_atapi_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .suspend = bfin_atapi_suspend,
+ .resume = bfin_atapi_resume,
+#endif
+ },
+};
+
+#define ATAPI_MODE_SIZE 10
+static char bfin_atapi_mode[ATAPI_MODE_SIZE];
+
+static int __init bfin_atapi_init(void)
+{
+ pr_info("register bfin atapi driver\n");
+
+ switch(bfin_atapi_mode[0]) {
+ case 'p':
+ case 'P':
+ break;
+ case 'm':
+ case 'M':
+ bfin_port_info[0].mwdma_mask = ATA_MWDMA2;
+ break;
+ default:
+ bfin_port_info[0].udma_mask = ATA_UDMA5;
+ };
+
+ return platform_driver_register(&bfin_atapi_driver);
+}
+
+static void __exit bfin_atapi_exit(void)
+{
+ platform_driver_unregister(&bfin_atapi_driver);
+}
+
+module_init(bfin_atapi_init);
+module_exit(bfin_atapi_exit);
+/*
+ * ATAPI mode:
+ * pio/PIO
+ * udma/UDMA (default)
+ * mwdma/MWDMA
+ */
+module_param_string(bfin_atapi_mode, bfin_atapi_mode, ATAPI_MODE_SIZE, 0);
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c
index 0feb5ae8c48..43d198f9096 100644
--- a/drivers/ata/pata_cmd640.c
+++ b/drivers/ata/pata_cmd640.c
@@ -153,7 +153,7 @@ static int cmd640_port_start(struct ata_port *ap)
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct cmd640_reg *timing;
- int ret = ata_port_start(ap);
+ int ret = ata_sff_port_start(ap);
if (ret < 0)
return ret;
@@ -184,7 +184,6 @@ static struct scsi_host_template cmd640_sht = {
};
static struct ata_port_operations cmd640_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cmd640_set_piomode,
.mode_filter = ata_pci_default_filter,
.tf_load = ata_tf_load,
@@ -213,7 +212,6 @@ static struct ata_port_operations cmd640_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = cmd640_port_start,
};
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index e34b632487d..7acbbd9ee46 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -31,7 +31,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_cmd64x"
-#define DRV_VERSION "0.2.4"
+#define DRV_VERSION "0.2.5"
/*
* CMD64x specific registers definition.
@@ -88,14 +88,15 @@ static int cmd648_cable_detect(struct ata_port *ap)
}
/**
- * cmd64x_set_piomode - set initial PIO mode data
+ * cmd64x_set_piomode - set PIO and MWDMA timing
* @ap: ATA interface
* @adev: ATA device
+ * @mode: mode
*
- * Called to do the PIO mode setup.
+ * Called to do the PIO and MWDMA mode setup.
*/
-static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 mode)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct ata_timing t;
@@ -117,8 +118,9 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
int arttim = arttim_port[ap->port_no][adev->devno];
int drwtim = drwtim_port[ap->port_no][adev->devno];
-
- if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) {
+ /* ata_timing_compute is smart and will produce timings for MWDMA
+ that don't violate the drives PIO capabilities. */
+ if (ata_timing_compute(adev, mode, &t, T, 0) < 0) {
printk(KERN_ERR DRV_NAME ": mode computation failed.\n");
return;
}
@@ -168,6 +170,20 @@ static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
}
/**
+ * cmd64x_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Used when configuring the devices ot set the PIO timings. All the
+ * actual work is done by the PIO/MWDMA setting helper
+ */
+
+static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ cmd64x_set_timing(ap, adev, adev->pio_mode);
+}
+
+/**
* cmd64x_set_dmamode - set initial DMA mode data
* @ap: ATA interface
* @adev: ATA device
@@ -180,9 +196,6 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
static const u8 udma_data[] = {
0x30, 0x20, 0x10, 0x20, 0x10, 0x00
};
- static const u8 mwdma_data[] = {
- 0x30, 0x20, 0x10
- };
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 regU, regD;
@@ -202,14 +215,16 @@ static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
regU &= ~(0x05 << adev->devno);
if (adev->dma_mode >= XFER_UDMA_0) {
- /* Merge thge timing value */
+ /* Merge the timing value */
regU |= udma_data[adev->dma_mode - XFER_UDMA_0] << shift;
/* Merge the control bits */
regU |= 1 << adev->devno; /* UDMA on */
if (adev->dma_mode > 2) /* 15nS timing */
regU |= 4 << adev->devno;
- } else
- regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift;
+ } else {
+ regU &= ~ (1 << adev->devno); /* UDMA off */
+ cmd64x_set_timing(ap, adev, adev->dma_mode);
+ }
regD |= 0x20 << adev->devno;
@@ -269,7 +284,6 @@ static struct scsi_host_template cmd64x_sht = {
};
static struct ata_port_operations cmd64x_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cmd64x_set_piomode,
.set_dmamode = cmd64x_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -298,13 +312,11 @@ static struct ata_port_operations cmd64x_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static struct ata_port_operations cmd646r1_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cmd64x_set_piomode,
.set_dmamode = cmd64x_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -333,13 +345,11 @@ static struct ata_port_operations cmd646r1_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static struct ata_port_operations cmd648_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cmd64x_set_piomode,
.set_dmamode = cmd64x_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -368,7 +378,6 @@ static struct ata_port_operations cmd648_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index e2459088cdc..33f7f0843f4 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -158,7 +158,6 @@ static struct scsi_host_template cs5520_sht = {
};
static struct ata_port_operations cs5520_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cs5520_set_piomode,
.set_dmamode = cs5520_set_dmamode,
@@ -184,13 +183,14 @@ static struct ata_port_operations cs5520_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
+ static const unsigned int cmd_port[] = { 0x1F0, 0x170 };
+ static const unsigned int ctl_port[] = { 0x3F6, 0x376 };
struct ata_port_info pi = {
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f,
@@ -244,10 +244,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
}
/* Map IO ports and initialize host accordingly */
- iomap[0] = devm_ioport_map(&pdev->dev, 0x1F0, 8);
- iomap[1] = devm_ioport_map(&pdev->dev, 0x3F6, 1);
- iomap[2] = devm_ioport_map(&pdev->dev, 0x170, 8);
- iomap[3] = devm_ioport_map(&pdev->dev, 0x376, 1);
+ iomap[0] = devm_ioport_map(&pdev->dev, cmd_port[0], 8);
+ iomap[1] = devm_ioport_map(&pdev->dev, ctl_port[0], 1);
+ iomap[2] = devm_ioport_map(&pdev->dev, cmd_port[1], 8);
+ iomap[3] = devm_ioport_map(&pdev->dev, ctl_port[1], 1);
iomap[4] = pcim_iomap(pdev, 2, 0);
if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
@@ -260,6 +260,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
ioaddr->bmdma_addr = iomap[4];
ata_std_ports(ioaddr);
+ ata_port_desc(host->ports[0],
+ "cmd 0x%x ctl 0x%x", cmd_port[0], ctl_port[0]);
+ ata_port_pbar_desc(host->ports[0], 4, 0, "bmdma");
+
ioaddr = &host->ports[1]->ioaddr;
ioaddr->cmd_addr = iomap[2];
ioaddr->ctl_addr = iomap[3];
@@ -267,6 +271,10 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
ioaddr->bmdma_addr = iomap[4] + 8;
ata_std_ports(ioaddr);
+ ata_port_desc(host->ports[1],
+ "cmd 0x%x ctl 0x%x", cmd_port[1], ctl_port[1]);
+ ata_port_pbar_desc(host->ports[1], 4, 8, "bmdma");
+
/* activate the host */
pci_set_master(pdev);
rc = ata_host_start(host);
@@ -285,33 +293,12 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
if (rc)
return rc;
- if (i == 0)
- host->irq = irq[0];
- else
- host->irq2 = irq[1];
+ ata_port_desc(ap, "irq %d", irq[i]);
}
return ata_host_register(host, &cs5520_sht);
}
-/**
- * cs5520_remove_one - device unload
- * @pdev: PCI device being removed
- *
- * Handle an unplug/unload event for a PCI device. Unload the
- * PCI driver but do not use the default handler as we manage
- * resources ourself and *MUST NOT* disable the device as it has
- * other functions.
- */
-
-static void __devexit cs5520_remove_one(struct pci_dev *pdev)
-{
- struct device *dev = pci_dev_to_dev(pdev);
- struct ata_host *host = dev_get_drvdata(dev);
-
- ata_host_detach(host);
-}
-
#ifdef CONFIG_PM
/**
* cs5520_reinit_one - device resume
@@ -368,7 +355,7 @@ static struct pci_driver cs5520_pci_driver = {
.name = DRV_NAME,
.id_table = pata_cs5520,
.probe = cs5520_init_one,
- .remove = cs5520_remove_one,
+ .remove = ata_pci_remove_one,
#ifdef CONFIG_PM
.suspend = cs5520_pci_device_suspend,
.resume = cs5520_reinit_one,
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index c6066aa43ec..e1818fdd915 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -138,7 +138,7 @@ static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev)
*
* Called when the libata layer is about to issue a command. We wrap
* this interface so that we can load the correct ATA timings if
- * neccessary. Specifically we have a problem that there is only
+ * necessary. Specifically we have a problem that there is only
* one MWDMA/UDMA bit.
*/
@@ -179,7 +179,6 @@ static struct scsi_host_template cs5530_sht = {
};
static struct ata_port_operations cs5530_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cs5530_set_piomode,
.set_dmamode = cs5530_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -209,12 +208,11 @@ static struct ata_port_operations cs5530_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
-static struct dmi_system_id palmax_dmi_table[] = {
+static const struct dmi_system_id palmax_dmi_table[] = {
{
.ident = "Palmax PD1100",
.matches = {
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 360b6f32e17..01324530d05 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -25,7 +25,7 @@
* Documentation:
* Available from AMD web site.
* TODO
- * Review errata to see if serializing is neccessary
+ * Review errata to see if serializing is necessary
*/
#include <linux/kernel.h>
@@ -176,7 +176,6 @@ static struct scsi_host_template cs5535_sht = {
};
static struct ata_port_operations cs5535_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cs5535_set_piomode,
.set_dmamode = cs5535_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -206,9 +205,8 @@ static struct ata_port_operations cs5535_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c
new file mode 100644
index 00000000000..d753e568588
--- /dev/null
+++ b/drivers/ata/pata_cs5536.c
@@ -0,0 +1,344 @@
+/*
+ * pata_cs5536.c - CS5536 PATA for new ATA layer
+ * (C) 2007 Martin K. Petersen <mkp@mkp.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Documentation:
+ * Available from AMD web site.
+ *
+ * The IDE timing registers for the CS5536 live in the Geode Machine
+ * Specific Register file and not PCI config space. Most BIOSes
+ * virtualize the PCI registers so the chip looks like a standard IDE
+ * controller. Unfortunately not all implementations get this right.
+ * In particular some have problems with unaligned accesses to the
+ * virtualized PCI registers. This driver always does full dword
+ * writes to work around the issue. Also, in case of a bad BIOS this
+ * driver can be loaded with the "msr=1" parameter which forces using
+ * the Machine Specific Registers to configure the device.
+ */
+
+#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/libata.h>
+#include <scsi/scsi_host.h>
+#include <asm/msr.h>
+
+#define DRV_NAME "pata_cs5536"
+#define DRV_VERSION "0.0.6"
+
+enum {
+ CFG = 0,
+ DTC = 1,
+ CAST = 2,
+ ETC = 3,
+
+ MSR_IDE_BASE = 0x51300000,
+ MSR_IDE_CFG = (MSR_IDE_BASE + 0x10),
+ MSR_IDE_DTC = (MSR_IDE_BASE + 0x12),
+ MSR_IDE_CAST = (MSR_IDE_BASE + 0x13),
+ MSR_IDE_ETC = (MSR_IDE_BASE + 0x14),
+
+ PCI_IDE_CFG = 0x40,
+ PCI_IDE_DTC = 0x48,
+ PCI_IDE_CAST = 0x4c,
+ PCI_IDE_ETC = 0x50,
+
+ IDE_CFG_CHANEN = 0x2,
+ IDE_CFG_CABLE = 0x10000,
+
+ IDE_D0_SHIFT = 24,
+ IDE_D1_SHIFT = 16,
+ IDE_DRV_MASK = 0xff,
+
+ IDE_CAST_D0_SHIFT = 6,
+ IDE_CAST_D1_SHIFT = 4,
+ IDE_CAST_DRV_MASK = 0x3,
+ IDE_CAST_CMD_MASK = 0xff,
+ IDE_CAST_CMD_SHIFT = 24,
+
+ 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,
+};
+
+static const u8 pci_reg[4] = {
+ PCI_IDE_CFG, PCI_IDE_DTC, PCI_IDE_CAST, PCI_IDE_ETC,
+};
+
+static inline int cs5536_read(struct pci_dev *pdev, int reg, int *val)
+{
+ if (unlikely(use_msr)) {
+ u32 dummy;
+
+ rdmsr(msr_reg[reg], *val, dummy);
+ return 0;
+ }
+
+ return pci_read_config_dword(pdev, pci_reg[reg], val);
+}
+
+static inline int cs5536_write(struct pci_dev *pdev, int reg, int val)
+{
+ if (unlikely(use_msr)) {
+ wrmsr(msr_reg[reg], val, 0);
+ return 0;
+ }
+
+ return pci_write_config_dword(pdev, pci_reg[reg], val);
+}
+
+/**
+ * cs5536_cable_detect - detect cable type
+ * @ap: Port to detect on
+ * @deadline: deadline jiffies for the operation
+ *
+ * Perform cable detection for ATA66 capable cable. Return a libata
+ * cable type.
+ */
+
+static int cs5536_cable_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 cfg;
+
+ cs5536_read(pdev, CFG, &cfg);
+
+ if (cfg & (IDE_CFG_CABLE << ap->port_no))
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * cs5536_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ */
+
+static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u8 drv_timings[5] = {
+ 0x98, 0x55, 0x32, 0x21, 0x20,
+ };
+
+ static const u8 addr_timings[5] = {
+ 0x2, 0x1, 0x0, 0x0, 0x0,
+ };
+
+ static const u8 cmd_timings[5] = {
+ 0x99, 0x92, 0x90, 0x22, 0x20,
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_device *pair = ata_dev_pair(adev);
+ int mode = adev->pio_mode - XFER_PIO_0;
+ int cmdmode = mode;
+ int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT;
+ int cshift = ap->port_no ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT;
+ u32 dtc, cast, etc;
+
+ if (pair)
+ cmdmode = min(mode, pair->pio_mode - XFER_PIO_0);
+
+ cs5536_read(pdev, DTC, &dtc);
+ cs5536_read(pdev, CAST, &cast);
+ cs5536_read(pdev, ETC, &etc);
+
+ dtc &= ~(IDE_DRV_MASK << dshift);
+ dtc |= drv_timings[mode] << dshift;
+
+ cast &= ~(IDE_CAST_DRV_MASK << cshift);
+ cast |= addr_timings[mode] << cshift;
+
+ cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT);
+ cast |= cmd_timings[cmdmode] << IDE_CAST_CMD_SHIFT;
+
+ etc &= ~(IDE_DRV_MASK << dshift);
+ etc |= IDE_ETC_NODMA << dshift;
+
+ cs5536_write(pdev, DTC, dtc);
+ cs5536_write(pdev, CAST, cast);
+ cs5536_write(pdev, ETC, etc);
+}
+
+/**
+ * cs5536_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ */
+
+static void cs5536_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u8 udma_timings[6] = {
+ 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6,
+ };
+
+ static const u8 mwdma_timings[3] = {
+ 0x67, 0x21, 0x20,
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 dtc, etc;
+ int mode = adev->dma_mode;
+ int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT;
+
+ if (mode >= XFER_UDMA_0) {
+ cs5536_read(pdev, ETC, &etc);
+
+ etc &= ~(IDE_DRV_MASK << dshift);
+ etc |= udma_timings[mode - XFER_UDMA_0] << dshift;
+
+ cs5536_write(pdev, ETC, etc);
+ } else { /* MWDMA */
+ cs5536_read(pdev, DTC, &dtc);
+
+ dtc &= ~(IDE_DRV_MASK << dshift);
+ dtc |= mwdma_timings[mode - XFER_MW_DMA_0] << dshift;
+
+ cs5536_write(pdev, DTC, dtc);
+ }
+}
+
+static struct scsi_host_template cs5536_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations cs5536_port_ops = {
+ .set_piomode = cs5536_set_piomode,
+ .set_dmamode = cs5536_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = cs5536_cable_detect,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ .port_start = ata_port_start,
+};
+
+/**
+ * cs5536_init_one
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ */
+
+static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static const struct ata_port_info info = {
+ .sht = &cs5536_sht,
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &cs5536_port_ops,
+ };
+
+ const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info };
+ u32 cfg;
+
+ if (use_msr)
+ printk(KERN_ERR DRV_NAME ": Using MSR regs instead of PCI\n");
+
+ cs5536_read(dev, CFG, &cfg);
+
+ if ((cfg & IDE_CFG_CHANEN) == 0) {
+ printk(KERN_ERR DRV_NAME ": disabled by BIOS\n");
+ return -ENODEV;
+ }
+
+ return ata_pci_init_one(dev, ppi);
+}
+
+static const struct pci_device_id cs5536[] = {
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), },
+ { },
+};
+
+static struct pci_driver cs5536_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = cs5536,
+ .probe = cs5536_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
+};
+
+static int __init cs5536_init(void)
+{
+ return pci_register_driver(&cs5536_pci_driver);
+}
+
+static void __exit cs5536_exit(void)
+{
+ pci_unregister_driver(&cs5536_pci_driver);
+}
+
+MODULE_AUTHOR("Martin K. Petersen");
+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_cypress.c b/drivers/ata/pata_cypress.c
index 6cbc8778bf4..fc5f9c4e5d8 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -128,7 +128,6 @@ static struct scsi_host_template cy82c693_sht = {
};
static struct ata_port_operations cy82c693_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = cy82c693_set_piomode,
.set_dmamode = cy82c693_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -158,9 +157,8 @@ static struct ata_port_operations cy82c693_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index c8ba59c5611..043dcd35106 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -26,25 +26,26 @@
/**
* efar_pre_reset - Enable bits
- * @ap: Port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Perform cable detection for the EFAR ATA interface. This is
* different to the PIIX arrangement
*/
-static int efar_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int efar_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits efar_enable_bits[] = {
{ 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
{ 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -250,7 +251,6 @@ static struct scsi_host_template efar_sht = {
};
static const struct ata_port_operations efar_ops = {
- .port_disable = ata_port_disable,
.set_piomode = efar_set_piomode,
.set_dmamode = efar_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -278,9 +278,8 @@ static const struct ata_port_operations efar_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 6f7d34ad19e..0713872cf65 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -312,7 +312,6 @@ static struct scsi_host_template hpt36x_sht = {
*/
static struct ata_port_operations hpt366_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt366_set_piomode,
.set_dmamode = hpt366_set_dmamode,
.mode_filter = hpt366_filter,
@@ -342,9 +341,8 @@ static struct ata_port_operations hpt366_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index c5ddd937dbf..3816b8605e0 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -295,7 +295,7 @@ static unsigned long hpt370_filter(struct ata_device *adev, unsigned long mask)
static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask)
{
- if (adev->class != ATA_DEV_ATA) {
+ if (adev->class == ATA_DEV_ATA) {
if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
mask &= ~ (0x1F << ATA_SHIFT_UDMA);
}
@@ -304,15 +304,16 @@ static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask)
/**
* hpt37x_pre_reset - reset the hpt37x bus
- * @ap: ATA port to reset
+ * @link: ATA link to reset
* @deadline: deadline jiffies for the operation
*
* Perform the initial reset handling for the 370/372 and 374 func 0
*/
-static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline)
{
u8 scr2, ata66;
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits hpt37x_enable_bits[] = {
{ 0x50, 1, 0x04, 0x04 },
@@ -337,7 +338,7 @@ static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline)
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(100);
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -352,33 +353,31 @@ static void hpt37x_error_handler(struct ata_port *ap)
ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
}
-static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt374_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits hpt37x_enable_bits[] = {
{ 0x50, 1, 0x04, 0x04 },
{ 0x54, 1, 0x04, 0x04 }
};
- u16 mcr3, mcr6;
+ u16 mcr3;
u8 ata66;
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned int mcrbase = 0x50 + 4 * ap->port_no;
if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
return -ENOENT;
/* Do the extra channel work */
- pci_read_config_word(pdev, 0x52, &mcr3);
- pci_read_config_word(pdev, 0x56, &mcr6);
+ pci_read_config_word(pdev, mcrbase + 2, &mcr3);
/* Set bit 15 of 0x52 to enable TCBLID as input
- Set bit 15 of 0x56 to enable FCBLID as input
*/
- pci_write_config_word(pdev, 0x52, mcr3 | 0x8000);
- pci_write_config_word(pdev, 0x56, mcr6 | 0x8000);
+ pci_write_config_word(pdev, mcrbase + 2, mcr3 | 0x8000);
pci_read_config_byte(pdev, 0x5A, &ata66);
/* Reset TCBLID/FCBLID to output */
pci_write_config_word(pdev, 0x52, mcr3);
- pci_write_config_word(pdev, 0x56, mcr6);
- if (ata66 & (1 << ap->port_no))
+ if (ata66 & (2 >> ap->port_no))
ap->cbl = ATA_CBL_PATA40;
else
ap->cbl = ATA_CBL_PATA80;
@@ -387,7 +386,7 @@ static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(100);
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -642,7 +641,6 @@ static struct scsi_host_template hpt37x_sht = {
*/
static struct ata_port_operations hpt370_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt370_set_piomode,
.set_dmamode = hpt370_set_dmamode,
.mode_filter = hpt370_filter,
@@ -671,9 +669,8 @@ static struct ata_port_operations hpt370_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/*
@@ -681,7 +678,6 @@ static struct ata_port_operations hpt370_port_ops = {
*/
static struct ata_port_operations hpt370a_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt370_set_piomode,
.set_dmamode = hpt370_set_dmamode,
.mode_filter = hpt370a_filter,
@@ -710,9 +706,8 @@ static struct ata_port_operations hpt370a_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/*
@@ -721,7 +716,6 @@ static struct ata_port_operations hpt370a_port_ops = {
*/
static struct ata_port_operations hpt372_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt372_set_piomode,
.set_dmamode = hpt372_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -750,9 +744,8 @@ static struct ata_port_operations hpt372_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/*
@@ -761,7 +754,6 @@ static struct ata_port_operations hpt372_port_ops = {
*/
static struct ata_port_operations hpt374_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt372_set_piomode,
.set_dmamode = hpt372_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -790,9 +782,8 @@ static struct ata_port_operations hpt374_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -850,6 +841,25 @@ static int hpt37x_calibrate_dpll(struct pci_dev *dev)
/* Never went stable */
return 0;
}
+
+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 = pci_get_slot(pdev->bus, pdev->devfn - 1);
+ /* Someone hot plugged the controller on us ? */
+ if (pdev_0 == NULL)
+ return 0;
+ io_base = pci_resource_start(pdev_0, 4);
+ freq = inl(io_base + 0x90);
+ pci_dev_put(pdev_0);
+ }
+ else
+ freq = inl(io_base + 0x90);
+ return freq;
+}
+
/**
* hpt37x_init_one - Initialise an HPT37X/302
* @dev: PCI device
@@ -908,7 +918,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f,
.mwdma_mask = 0x07,
- .udma_mask = 0x0f,
+ .udma_mask = ATA_UDMA5,
.port_ops = &hpt370_port_ops
};
/* HPT370A - UDMA100 */
@@ -917,7 +927,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f,
.mwdma_mask = 0x07,
- .udma_mask = 0x0f,
+ .udma_mask = ATA_UDMA5,
.port_ops = &hpt370a_port_ops
};
/* HPT371, 372 and friends - UDMA133 */
@@ -1053,9 +1063,16 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
outb(0x0e, iobase + 0x9c);
/* Some devices do not let this value be accessed via PCI space
- according to the old driver */
+ 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);
+ if (freq == 0)
+ return -ENODEV;
+ } else
+ freq = inl(iobase + 0x90);
- freq = inl(iobase + 0x90);
if ((freq >> 12) != 0xABCDE) {
int i;
u8 sr;
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index f8f234bfc8c..9f1c084f846 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -141,21 +141,22 @@ static int hpt3x2n_cable_detect(struct ata_port *ap)
/**
* hpt3x2n_pre_reset - reset the hpt3x2n bus
- * @ap: ATA port to reset
+ * @link: ATA link to reset
* @deadline: deadline jiffies for the operation
*
* Perform the initial reset handling for the 3x2n series controllers.
* Reset the hardware and state machine,
*/
-static int hpt3xn_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt3xn_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
/* Reset the state machine */
pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(100);
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -360,7 +361,6 @@ static struct scsi_host_template hpt3x2n_sht = {
*/
static struct ata_port_operations hpt3x2n_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt3x2n_set_piomode,
.set_dmamode = hpt3x2n_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -390,9 +390,8 @@ static struct ata_port_operations hpt3x2n_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index be0f05efac6..cb8bdb6887d 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -120,7 +120,6 @@ static struct scsi_host_template hpt3x3_sht = {
};
static struct ata_port_operations hpt3x3_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = hpt3x3_set_piomode,
#if defined(CONFIG_PATA_HPT3X3_DMA)
.set_dmamode = hpt3x3_set_dmamode,
@@ -153,9 +152,8 @@ static struct ata_port_operations hpt3x3_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -239,7 +237,8 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
base = host->iomap[4]; /* Bus mastering base */
for (i = 0; i < host->n_ports; i++) {
- struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+ struct ata_port *ap = host->ports[i];
+ struct ata_ioports *ioaddr = &ap->ioaddr;
ioaddr->cmd_addr = base + offset_cmd[i];
ioaddr->altstatus_addr =
@@ -247,6 +246,9 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
ioaddr->scr_addr = NULL;
ata_std_ports(ioaddr);
ioaddr->bmdma_addr = base + 8 * i;
+
+ ata_port_pbar_desc(ap, 4, -1, "ioport");
+ ata_port_pbar_desc(ap, 4, offset_cmd[i], "cmd");
}
pci_set_master(pdev);
return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c
index 64a711776c4..842fe08a3c1 100644
--- a/drivers/ata/pata_icside.c
+++ b/drivers/ata/pata_icside.c
@@ -70,6 +70,8 @@ struct pata_icside_info {
unsigned int mwdma_mask;
unsigned int nr_ports;
const struct portinfo *port[2];
+ unsigned long raw_base;
+ unsigned long raw_ioc_base;
};
#define ICS_TYPE_A3IN 0
@@ -330,12 +332,13 @@ static void ata_dummy_noret(struct ata_port *port)
{
}
-static void pata_icside_postreset(struct ata_port *ap, unsigned int *classes)
+static void pata_icside_postreset(struct ata_link *link, unsigned int *classes)
{
+ struct ata_port *ap = link->ap;
struct pata_icside_state *state = ap->host->private_data;
if (classes[0] != ATA_DEV_NONE || classes[1] != ATA_DEV_NONE)
- return ata_std_postreset(ap, classes);
+ return ata_std_postreset(link, classes);
state->port[ap->port_no].disabled = 1;
@@ -357,26 +360,7 @@ static void pata_icside_error_handler(struct ata_port *ap)
pata_icside_postreset);
}
-static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq)
-{
- unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
- u8 status;
-
- status = ata_busy_wait(ap, bits, 1000);
- if (status & bits)
- if (ata_msg_err(ap))
- printk(KERN_ERR "abnormal status 0x%X\n", status);
-
- if (ata_msg_intr(ap))
- printk(KERN_INFO "%s: irq ack: drv_stat 0x%X\n",
- __FUNCTION__, status);
-
- return status;
-}
-
static struct ata_port_operations pata_icside_port_ops = {
- .port_disable = ata_port_disable,
-
.set_dmamode = pata_icside_set_dmamode,
.tf_load = ata_tf_load,
@@ -403,7 +387,6 @@ static struct ata_port_operations pata_icside_port_ops = {
.irq_clear = ata_dummy_noret,
.irq_on = ata_irq_on,
- .irq_ack = pata_icside_irq_ack,
.port_start = pata_icside_port_start,
@@ -412,25 +395,34 @@ static struct ata_port_operations pata_icside_port_ops = {
};
static void __devinit
-pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base,
- const struct portinfo *info)
+pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,
+ struct pata_icside_info *info,
+ const struct portinfo *port)
{
- void __iomem *cmd = base + info->dataoffset;
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ void __iomem *cmd = base + port->dataoffset;
ioaddr->cmd_addr = cmd;
- ioaddr->data_addr = cmd + (ATA_REG_DATA << info->stepping);
- ioaddr->error_addr = cmd + (ATA_REG_ERR << info->stepping);
- ioaddr->feature_addr = cmd + (ATA_REG_FEATURE << info->stepping);
- ioaddr->nsect_addr = cmd + (ATA_REG_NSECT << info->stepping);
- ioaddr->lbal_addr = cmd + (ATA_REG_LBAL << info->stepping);
- ioaddr->lbam_addr = cmd + (ATA_REG_LBAM << info->stepping);
- ioaddr->lbah_addr = cmd + (ATA_REG_LBAH << info->stepping);
- ioaddr->device_addr = cmd + (ATA_REG_DEVICE << info->stepping);
- ioaddr->status_addr = cmd + (ATA_REG_STATUS << info->stepping);
- ioaddr->command_addr = cmd + (ATA_REG_CMD << info->stepping);
-
- ioaddr->ctl_addr = base + info->ctrloffset;
+ ioaddr->data_addr = cmd + (ATA_REG_DATA << port->stepping);
+ ioaddr->error_addr = cmd + (ATA_REG_ERR << port->stepping);
+ ioaddr->feature_addr = cmd + (ATA_REG_FEATURE << port->stepping);
+ ioaddr->nsect_addr = cmd + (ATA_REG_NSECT << port->stepping);
+ ioaddr->lbal_addr = cmd + (ATA_REG_LBAL << port->stepping);
+ ioaddr->lbam_addr = cmd + (ATA_REG_LBAM << port->stepping);
+ ioaddr->lbah_addr = cmd + (ATA_REG_LBAH << port->stepping);
+ ioaddr->device_addr = cmd + (ATA_REG_DEVICE << port->stepping);
+ ioaddr->status_addr = cmd + (ATA_REG_STATUS << port->stepping);
+ ioaddr->command_addr = cmd + (ATA_REG_CMD << port->stepping);
+
+ ioaddr->ctl_addr = base + port->ctrloffset;
ioaddr->altstatus_addr = ioaddr->ctl_addr;
+
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",
+ info->raw_base + port->dataoffset,
+ info->raw_base + port->ctrloffset);
+
+ if (info->raw_ioc_base)
+ ata_port_desc(ap, "iocbase 0x%lx", info->raw_ioc_base);
}
static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
@@ -451,6 +443,8 @@ static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
info->nr_ports = 1;
info->port[0] = &pata_icside_portinfo_v5;
+ info->raw_base = ecard_resource_start(info->ec, ECARD_RES_MEMC);
+
return 0;
}
@@ -491,6 +485,9 @@ static int __devinit pata_icside_register_v6(struct pata_icside_info *info)
info->port[0] = &pata_icside_portinfo_v6_1;
info->port[1] = &pata_icside_portinfo_v6_2;
+ info->raw_base = ecard_resource_start(ec, ECARD_RES_EASI);
+ info->raw_ioc_base = ecard_resource_start(ec, ECARD_RES_IOCFAST);
+
return icside_dma_init(info);
}
@@ -527,7 +524,7 @@ static int __devinit pata_icside_add_ports(struct pata_icside_info *info)
ap->flags |= ATA_FLAG_SLAVE_POSS;
ap->ops = &pata_icside_port_ops;
- pata_icside_setup_ioaddr(&ap->ioaddr, info->base, info->port[i]);
+ pata_icside_setup_ioaddr(ap, info->base, info, info->port[i]);
}
return ata_host_activate(host, ec->irq, ata_interrupt, 0,
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
index 9e553c54203..88ab0e1d353 100644
--- a/drivers/ata/pata_isapnp.c
+++ b/drivers/ata/pata_isapnp.c
@@ -38,7 +38,6 @@ static struct scsi_host_template isapnp_sht = {
};
static struct ata_port_operations isapnp_port_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -58,9 +57,8 @@ static struct ata_port_operations isapnp_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -112,6 +110,10 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
ata_std_ports(&ap->ioaddr);
+ ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+ (unsigned long long)pnp_port_start(idev, 0),
+ (unsigned long long)pnp_port_start(idev, 1));
+
/* activate */
return ata_host_activate(host, pnp_irq(idev, 0), ata_interrupt, 0,
&isapnp_sht);
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
index b8af55e8915..1eda821e5e3 100644
--- a/drivers/ata/pata_it8213.c
+++ b/drivers/ata/pata_it8213.c
@@ -23,23 +23,24 @@
/**
* it8213_pre_reset - check for 40/80 pin
- * @ap: Port
+ * @link: link
* @deadline: deadline jiffies for the operation
*
* Filter out ports by the enable bits before doing the normal reset
* and probe.
*/
-static int it8213_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int it8213_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits it8213_enable_bits[] = {
{ 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -260,7 +261,6 @@ static struct scsi_host_template it8213_sht = {
};
static const struct ata_port_operations it8213_ops = {
- .port_disable = ata_port_disable,
.set_piomode = it8213_set_piomode,
.set_dmamode = it8213_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -288,9 +288,8 @@ static const struct ata_port_operations it8213_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 5d8b91e70ec..ca9aae09dae 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -105,7 +105,7 @@ struct it821x_dev
/*
* We allow users to force the card into non raid mode without
- * flashing the alternative BIOS. This is also neccessary right now
+ * flashing the alternative BIOS. This is also necessary right now
* for embedded platforms that cannot run a PC BIOS but are using this
* device.
*/
@@ -383,7 +383,7 @@ static void it821x_passthru_bmdma_stop(struct ata_queued_cmd *qc)
* @ap: ATA port
* @device: Device number (not pointer)
*
- * Device selection hook. If neccessary perform clock switching
+ * Device selection hook. If necessary perform clock switching
*/
static void it821x_passthru_dev_select(struct ata_port *ap,
@@ -391,7 +391,7 @@ static void it821x_passthru_dev_select(struct ata_port *ap,
{
struct it821x_dev *itdev = ap->private_data;
if (itdev && device != itdev->last_device) {
- struct ata_device *adev = &ap->device[device];
+ struct ata_device *adev = &ap->link.device[device];
it821x_program(ap, adev, itdev->pio[adev->devno]);
itdev->last_device = device;
}
@@ -450,7 +450,7 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc)
/**
* it821x_smart_set_mode - mode setting
- * @ap: interface to set up
+ * @link: interface to set up
* @unused: device that failed (error only)
*
* Use a non standard set_mode function. We don't want to be tuned.
@@ -459,12 +459,11 @@ static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc)
* and respect them.
*/
-static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unused)
{
- int i;
+ struct ata_device *dev;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
@@ -564,7 +563,7 @@ static int it821x_port_start(struct ata_port *ap)
struct it821x_dev *itdev;
u8 conf;
- int ret = ata_port_start(ap);
+ int ret = ata_sff_port_start(ap);
if (ret < 0)
return ret;
@@ -621,7 +620,6 @@ static struct scsi_host_template it821x_sht = {
static struct ata_port_operations it821x_smart_port_ops = {
.set_mode = it821x_smart_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.mode_filter = ata_pci_default_filter,
@@ -651,13 +649,11 @@ static struct ata_port_operations it821x_smart_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = it821x_port_start,
};
static struct ata_port_operations it821x_passthru_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = it821x_passthru_set_piomode,
.set_dmamode = it821x_passthru_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -688,7 +684,6 @@ static struct ata_port_operations it821x_passthru_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_handler = ata_interrupt,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = it821x_port_start,
};
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index 5dea3584c6c..fcd532afbf2 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -26,12 +26,11 @@
#define DRV_NAME "pata_ixp4xx_cf"
#define DRV_VERSION "0.2"
-static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error)
+static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
{
- int i;
+ struct ata_device *dev;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
dev->pio_mode = XFER_PIO_0;
@@ -49,7 +48,7 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int i;
unsigned int words = buflen >> 1;
u16 *buf16 = (u16 *) buf;
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
void __iomem *mmio = ap->ioaddr.data_addr;
struct ixp4xx_pata_data *data = ap->host->dev->platform_data;
@@ -108,7 +107,6 @@ static struct ata_port_operations ixp4xx_port_ops = {
.set_mode = ixp4xx_set_mode,
.mode_filter = ata_pci_default_filter,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
@@ -128,14 +126,17 @@ static struct ata_port_operations ixp4xx_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_dummy_irq_ack,
.port_start = ata_port_start,
};
static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
- struct ixp4xx_pata_data *data)
+ struct ixp4xx_pata_data *data,
+ unsigned long raw_cs0, unsigned long raw_cs1)
{
+ unsigned long raw_cmd = raw_cs0;
+ unsigned long raw_ctl = raw_cs1 + 0x06;
+
ioaddr->cmd_addr = data->cs0;
ioaddr->altstatus_addr = data->cs1 + 0x06;
ioaddr->ctl_addr = data->cs1 + 0x06;
@@ -161,7 +162,12 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
*(unsigned long *)&ioaddr->device_addr ^= 0x03;
*(unsigned long *)&ioaddr->status_addr ^= 0x03;
*(unsigned long *)&ioaddr->command_addr ^= 0x03;
+
+ raw_cmd ^= 0x03;
+ raw_ctl ^= 0x03;
#endif
+
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", raw_cmd, raw_ctl);
}
static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
@@ -206,7 +212,7 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
ap->pio_mask = 0x1f; /* PIO4 */
ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI;
- ixp4xx_setup_port(&ap->ioaddr, data);
+ ixp4xx_setup_port(ap, data, cs0->start, cs1->start);
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 4d67f238eee..225a7223a72 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -29,7 +29,7 @@ typedef enum {
/**
* jmicron_pre_reset - check for 40/80 pin
- * @ap: Port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Perform the PATA port setup we need.
@@ -39,9 +39,9 @@ typedef enum {
* and setup here. We assume that has been done by init_one and the
* BIOS.
*/
-
-static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int jmicron_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 control;
u32 control5;
@@ -103,7 +103,7 @@ static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline)
ap->cbl = ATA_CBL_SATA;
break;
}
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -141,8 +141,6 @@ static struct scsi_host_template jmicron_sht = {
};
static const struct ata_port_operations jmicron_ops = {
- .port_disable = ata_port_disable,
-
/* Task file is PCI ATA format, use helpers */
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -168,7 +166,6 @@ static const struct ata_port_operations jmicron_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
.port_start = ata_port_start,
@@ -207,17 +204,8 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
}
static const struct pci_device_id jmicron_pci_tbl[] = {
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 361 },
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 363 },
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 365 },
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 366 },
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 368 },
-
+ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
{ } /* terminate list */
};
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index edffc25d2d3..7bed8d80638 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -96,7 +96,7 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */
/**
* legacy_set_mode - mode setting
- * @ap: IDE interface
+ * @link: IDE link
* @unused: Device that failed when error is returned
*
* Use a non standard set_mode function. We don't want to be tuned.
@@ -107,12 +107,11 @@ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */
* expand on this as per hdparm in the base kernel.
*/
-static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int legacy_set_mode(struct ata_link *link, struct ata_device **unused)
{
- int i;
+ struct ata_device *dev;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
dev->pio_mode = XFER_PIO_0;
@@ -151,7 +150,6 @@ static struct scsi_host_template legacy_sht = {
*/
static struct ata_port_operations simple_port_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -172,7 +170,6 @@ static struct ata_port_operations simple_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -180,7 +177,6 @@ static struct ata_port_operations simple_port_ops = {
static struct ata_port_operations legacy_port_ops = {
.set_mode = legacy_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -201,7 +197,6 @@ static struct ata_port_operations legacy_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -256,7 +251,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
int slop = buflen & 3;
unsigned long flags;
@@ -296,7 +291,6 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig
static struct ata_port_operations pdc20230_port_ops = {
.set_piomode = pdc20230_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -317,7 +311,6 @@ static struct ata_port_operations pdc20230_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -352,7 +345,6 @@ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
static struct ata_port_operations ht6560a_port_ops = {
.set_piomode = ht6560a_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -373,7 +365,6 @@ static struct ata_port_operations ht6560a_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -419,7 +410,6 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
static struct ata_port_operations ht6560b_port_ops = {
.set_piomode = ht6560b_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -440,7 +430,6 @@ static struct ata_port_operations ht6560b_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -541,7 +530,6 @@ static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev
static struct ata_port_operations opti82c611a_port_ops = {
.set_piomode = opti82c611a_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -562,7 +550,6 @@ static struct ata_port_operations opti82c611a_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -675,7 +662,6 @@ static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc)
static struct ata_port_operations opti82c46x_port_ops = {
.set_piomode = opti82c46x_set_piomode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -696,7 +682,6 @@ static struct ata_port_operations opti82c46x_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
@@ -814,6 +799,8 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
ata_std_ports(&ap->ioaddr);
ap->private_data = ld;
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, ctrl);
+
ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht);
if (ret)
goto fail;
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index b45506f1ef7..9afc8a32b22 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -24,14 +24,15 @@
/**
* marvell_pre_reset - check for 40/80 pin
- * @ap: Port
+ * @link: link
* @deadline: deadline jiffies for the operation
*
* Perform the PATA port setup we need.
*/
-static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 devices;
void __iomem *barp;
@@ -54,7 +55,7 @@ static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline)
(!(devices & 0x10))) /* PATA enable ? */
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
static int marvell_cable_detect(struct ata_port *ap)
@@ -110,8 +111,6 @@ static struct scsi_host_template marvell_sht = {
};
static const struct ata_port_operations marvell_ops = {
- .port_disable = ata_port_disable,
-
/* Task file is PCI ATA format, use helpers */
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -138,10 +137,9 @@ static const struct ata_port_operations marvell_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 099f4cdc4cd..50c56e2814c 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -283,7 +283,6 @@ static struct scsi_host_template mpc52xx_ata_sht = {
};
static struct ata_port_operations mpc52xx_ata_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = mpc52xx_ata_set_piomode,
.dev_select = mpc52xx_ata_dev_select,
.tf_load = ata_tf_load,
@@ -299,17 +298,16 @@ static struct ata_port_operations mpc52xx_ata_port_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static int __devinit
-mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
+mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
+ unsigned long raw_ata_regs)
{
struct ata_host *host;
struct ata_port *ap;
struct ata_ioports *aio;
- int rc;
host = ata_host_alloc(dev, 1);
if (!host)
@@ -338,6 +336,8 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
aio->status_addr = &priv->ata_regs->tf_command;
aio->command_addr = &priv->ata_regs->tf_command;
+ ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs);
+
/* activate host */
return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0,
&mpc52xx_ata_sht);
@@ -434,7 +434,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match)
}
/* Register ourselves to libata */
- rv = mpc52xx_ata_init_one(&op->dev, priv);
+ rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start);
if (rv) {
printk(KERN_ERR DRV_NAME ": "
"Error while registering to ATA layer\n");
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 4ea42838297..c0d9e0cf208 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -46,15 +46,16 @@ enum {
SECONDARY = (1 << 14)
};
-static int mpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int mpiix_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 };
if (!pci_test_config_bits(pdev, &mpiix_enable_bits))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -128,7 +129,7 @@ static void mpiix_set_piomode(struct ata_port *ap, struct ata_device *adev)
*
* Called when the libata layer is about to issue a command. We wrap
* this interface so that we can load the correct ATA timings if
- * neccessary. Our logic also clears TIME0/TIME1 for the other device so
+ * necessary. Our logic also clears TIME0/TIME1 for the other device so
* that, even if we get this wrong, cycles to the other device will
* be made PIO0.
*/
@@ -168,7 +169,6 @@ static struct scsi_host_template mpiix_sht = {
};
static struct ata_port_operations mpiix_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = mpiix_set_piomode,
.tf_load = ata_tf_load,
@@ -189,9 +189,8 @@ static struct ata_port_operations mpiix_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -202,7 +201,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
struct ata_port *ap;
void __iomem *cmd_addr, *ctl_addr;
u16 idetim;
- int irq;
+ int cmd, ctl, irq;
if (!printed_version++)
dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
@@ -210,6 +209,7 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
host = ata_host_alloc(&dev->dev, 1);
if (!host)
return -ENOMEM;
+ ap = host->ports[0];
/* MPIIX has many functions which can be turned on or off according
to other devices present. Make sure IDE is enabled before we try
@@ -221,25 +221,28 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
/* See if it's primary or secondary channel... */
if (!(idetim & SECONDARY)) {
+ cmd = 0x1F0;
+ ctl = 0x3F6;
irq = 14;
- cmd_addr = devm_ioport_map(&dev->dev, 0x1F0, 8);
- ctl_addr = devm_ioport_map(&dev->dev, 0x3F6, 1);
} else {
+ cmd = 0x170;
+ ctl = 0x376;
irq = 15;
- cmd_addr = devm_ioport_map(&dev->dev, 0x170, 8);
- ctl_addr = devm_ioport_map(&dev->dev, 0x376, 1);
}
+ cmd_addr = devm_ioport_map(&dev->dev, cmd, 8);
+ ctl_addr = devm_ioport_map(&dev->dev, ctl, 1);
if (!cmd_addr || !ctl_addr)
return -ENOMEM;
+ ata_port_desc(ap, "cmd 0x%x ctl 0x%x", cmd, ctl);
+
/* We do our own plumbing to avoid leaking special cases for whacko
ancient hardware into the core code. There are two issues to
worry about. #1 The chip is a bridge so if in legacy mode and
without BARs set fools the setup. #2 If you pci_disable_device
the MPIIX your box goes castors up */
- ap = host->ports[0];
ap->ops = &mpiix_port_ops;
ap->pio_mask = 0x1F;
ap->flags |= ATA_FLAG_SLAVE_POSS;
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index 40eb574828b..25c922abd55 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -40,8 +40,6 @@ static struct scsi_host_template netcell_sht = {
};
static const struct ata_port_operations netcell_ops = {
- .port_disable = ata_port_disable,
-
/* Task file is PCI ATA format, use helpers */
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -68,10 +66,9 @@ static const struct ata_port_operations netcell_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
/* Generic PATA PCI ATA helpers */
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 2f5d714ebfc..9fe66fd7501 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -32,14 +32,15 @@
/**
* ns87410_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Check enabled ports
*/
-static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int ns87410_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits ns87410_enable_bits[] = {
{ 0x43, 1, 0x08, 0x08 },
@@ -49,7 +50,7 @@ static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -123,7 +124,7 @@ static void ns87410_set_piomode(struct ata_port *ap, struct ata_device *adev)
*
* Called when the libata layer is about to issue a command. We wrap
* this interface so that we can load the correct ATA timings if
- * neccessary.
+ * necessary.
*/
static unsigned int ns87410_qc_issue_prot(struct ata_queued_cmd *qc)
@@ -161,7 +162,6 @@ static struct scsi_host_template ns87410_sht = {
};
static struct ata_port_operations ns87410_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = ns87410_set_piomode,
.tf_load = ata_tf_load,
@@ -184,9 +184,8 @@ static struct ata_port_operations ns87410_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c
new file mode 100644
index 00000000000..d0e2e50823b
--- /dev/null
+++ b/drivers/ata/pata_ns87415.c
@@ -0,0 +1,469 @@
+/*
+ * pata_ns87415.c - NS87415 (non PARISC) PATA
+ *
+ * (C) 2005 Red Hat <alan@redhat.com>
+ *
+ * This is a fairly generic MWDMA controller. It has some limitations
+ * as it requires timing reloads on PIO/DMA transitions but it is otherwise
+ * fairly well designed.
+ *
+ * This driver assumes the firmware has left the chip in a valid ST506
+ * compliant state, either legacy IRQ 14/15 or native INTA shared. You
+ * may need to add platform code if your system fails to do this.
+ *
+ * The same cell appears in the 87560 controller used by some PARISC
+ * systems. This has its own special mountain of errata.
+ *
+ * TODO:
+ * Test PARISC SuperIO
+ * Get someone to test on SPARC
+ * Implement lazy pio/dma switching for better performance
+ * 8bit shared timing.
+ * See if we need to kill the FIFO for ATAPI
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_ns87415"
+#define DRV_VERSION "0.0.1"
+
+/**
+ * ns87415_set_mode - Initialize host controller mode timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device whose timings we are configuring
+ * @mode: Mode to set
+ *
+ * Program the mode registers for this controller, channel and
+ * device. Because the chip is quite an old design we have to do this
+ * for PIO/DMA switches.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void ns87415_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ int unit = 2 * ap->port_no + adev->devno;
+ int timing = 0x44 + 2 * unit;
+ unsigned long T = 1000000000 / 33333; /* PCI clocks */
+ struct ata_timing t;
+ u16 clocking;
+ u8 iordy;
+ u8 status;
+
+ /* Timing register format is 17 - low nybble read timing with
+ the high nybble being 16 - x for recovery time in PCI clocks */
+
+ ata_timing_compute(adev, adev->pio_mode, &t, T, 0);
+
+ clocking = 17 - FIT(t.active, 2, 17);
+ clocking |= (16 - FIT(t.recover, 1, 16)) << 4;
+ /* Use the same timing for read and write bytes */
+ clocking |= (clocking << 8);
+ pci_write_config_word(dev, timing, clocking);
+
+ /* Set the IORDY enable versus DMA enable on or off properly */
+ pci_read_config_byte(dev, 0x42, &iordy);
+ iordy &= ~(1 << (4 + unit));
+ if (mode >= XFER_MW_DMA_0 || !ata_pio_need_iordy(adev))
+ iordy |= (1 << (4 + unit));
+
+ /* Paranoia: We shouldn't ever get here with busy write buffers
+ but if so wait */
+
+ pci_read_config_byte(dev, 0x43, &status);
+ while (status & 0x03) {
+ udelay(1);
+ pci_read_config_byte(dev, 0x43, &status);
+ }
+ /* Flip the IORDY/DMA bits now we are sure the write buffers are
+ clear */
+ pci_write_config_byte(dev, 0x42, iordy);
+
+ /* TODO: Set byte 54 command timing to the best 8bit
+ mode shared by all four devices */
+}
+
+/**
+ * ns87415_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void ns87415_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ ns87415_set_mode(ap, adev, adev->pio_mode);
+}
+
+/**
+ * ns87415_bmdma_setup - Set up DMA
+ * @qc: Command block
+ *
+ * Set up for bus masterng DMA. We have to do this ourselves
+ * rather than use the helper due to a chip erratum
+ */
+
+static void ns87415_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+ u8 dmactl;
+
+ /* load PRD table addr. */
+ mb(); /* make sure PRD table writes are visible to controller */
+ iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+
+ /* specify data direction, triple-check start bit is clear */
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+ /* Due to an erratum we need to write these bits to the wrong
+ place - which does save us an I/O bizarrely */
+ dmactl |= ATA_DMA_INTR | ATA_DMA_ERR;
+ if (!rw)
+ dmactl |= ATA_DMA_WR;
+ iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ /* issue r/w command */
+ ap->ops->exec_command(ap, &qc->tf);
+}
+
+/**
+ * ns87415_bmdma_start - Begin DMA transfer
+ * @qc: Command block
+ *
+ * Switch the timings for the chip and set up for a DMA transfer
+ * before the DMA burst begins.
+ *
+ * FIXME: We should do lazy switching on bmdma_start versus
+ * ata_pio_data_xfer for better performance.
+ */
+
+static void ns87415_bmdma_start(struct ata_queued_cmd *qc)
+{
+ ns87415_set_mode(qc->ap, qc->dev, qc->dev->dma_mode);
+ ata_bmdma_start(qc);
+}
+
+/**
+ * ns87415_bmdma_stop - End DMA transfer
+ * @qc: Command block
+ *
+ * End DMA mode and switch the controller back into PIO mode
+ */
+
+static void ns87415_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ ata_bmdma_stop(qc);
+ ns87415_set_mode(qc->ap, qc->dev, qc->dev->pio_mode);
+}
+
+/**
+ * ns87415_bmdma_irq_clear - Clear interrupt
+ * @ap: Channel to clear
+ *
+ * Erratum: Due to a chip bug regisers 02 and 0A bit 1 and 2 (the
+ * error bits) are reset by writing to register 00 or 08.
+ */
+
+static void ns87415_bmdma_irq_clear(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ if (!mmio)
+ return;
+ iowrite8((ioread8(mmio + ATA_DMA_CMD) | ATA_DMA_INTR | ATA_DMA_ERR),
+ mmio + ATA_DMA_CMD);
+}
+
+/**
+ * ns87415_check_atapi_dma - ATAPI DMA filter
+ * @qc: Command block
+ *
+ * Disable ATAPI DMA (for now). We may be able to do DMA if we
+ * kill the prefetching. This isn't clear.
+ */
+
+static int ns87415_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ return -EOPNOTSUPP;
+}
+
+#if defined(CONFIG_SUPERIO)
+
+/* SUPERIO 87560 is a PoS chip that NatSem denies exists.
+ * Unfortunately, it's built-in on all Astro-based PA-RISC workstations
+ * which use the integrated NS87514 cell for CD-ROM support.
+ * i.e we have to support for CD-ROM installs.
+ * See drivers/parisc/superio.c for more gory details.
+ *
+ * Workarounds taken from drivers/ide/pci/ns87415.c
+ */
+
+#include <asm/superio.h>
+
+#define SUPERIO_IDE_MAX_RETRIES 25
+
+/**
+ * ns87560_read_buggy - workaround buggy Super I/O chip
+ * @port: Port to read
+ *
+ * Work around chipset problems in the 87560 SuperIO chip
+ */
+
+static u8 ns87560_read_buggy(void __iomem *port)
+{
+ u8 tmp;
+ int retries = SUPERIO_IDE_MAX_RETRIES;
+ do {
+ tmp = ioread8(port);
+ if (tmp != 0)
+ return tmp;
+ udelay(50);
+ } while(retries-- > 0);
+ return tmp;
+}
+
+/**
+ * ns87560_check_status
+ * @ap: channel to check
+ *
+ * Return the status of the channel working around the
+ * 87560 flaws.
+ */
+
+static u8 ns87560_check_status(struct ata_port *ap)
+{
+ return ns87560_read_buggy(ap->ioaddr.status_addr);
+}
+
+/**
+ * ns87560_tf_read - input device's ATA taskfile shadow registers
+ * @ap: Port from which input is read
+ * @tf: ATA taskfile register set for storing input
+ *
+ * Reads ATA taskfile registers for currently-selected device
+ * into @tf. Work around the 87560 bugs.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+void ns87560_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->command = ns87560_check_status(ap);
+ tf->feature = ioread8(ioaddr->error_addr);
+ tf->nsect = ioread8(ioaddr->nsect_addr);
+ tf->lbal = ioread8(ioaddr->lbal_addr);
+ tf->lbam = ioread8(ioaddr->lbam_addr);
+ tf->lbah = ioread8(ioaddr->lbah_addr);
+ tf->device = ns87560_read_buggy(ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+ tf->hob_feature = ioread8(ioaddr->error_addr);
+ tf->hob_nsect = ioread8(ioaddr->nsect_addr);
+ tf->hob_lbal = ioread8(ioaddr->lbal_addr);
+ tf->hob_lbam = ioread8(ioaddr->lbam_addr);
+ tf->hob_lbah = ioread8(ioaddr->lbah_addr);
+ iowrite8(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ }
+}
+
+/**
+ * ns87560_bmdma_status
+ * @ap: channel to check
+ *
+ * Return the DMA status of the channel working around the
+ * 87560 flaws.
+ */
+
+static u8 ns87560_bmdma_status(struct ata_port *ap)
+{
+ return ns87560_read_buggy(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+}
+
+static const struct ata_port_operations ns87560_pata_ops = {
+ .set_piomode = ns87415_set_piomode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ns87560_tf_read,
+ .check_status = ns87560_check_status,
+ .check_atapi_dma = ns87415_check_atapi_dma,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
+
+ .bmdma_setup = ns87415_bmdma_setup,
+ .bmdma_start = ns87415_bmdma_start,
+ .bmdma_stop = ns87415_bmdma_stop,
+ .bmdma_status = ns87560_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ns87415_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ .port_start = ata_sff_port_start,
+};
+
+#endif /* 87560 SuperIO Support */
+
+
+static const struct ata_port_operations ns87415_pata_ops = {
+ .set_piomode = ns87415_set_piomode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .check_atapi_dma = ns87415_check_atapi_dma,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
+
+ .bmdma_setup = ns87415_bmdma_setup,
+ .bmdma_start = ns87415_bmdma_start,
+ .bmdma_stop = ns87415_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ns87415_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+
+ .port_start = ata_sff_port_start,
+};
+
+static struct scsi_host_template ns87415_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+
+/**
+ * ns87415_init_one - Register 87415 ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in ns87415_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * and then hand over control to libata, for it to do the rest.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static const struct ata_port_info info = {
+ .sht = &ns87415_sht,
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .port_ops = &ns87415_pata_ops,
+ };
+ const struct ata_port_info *ppi[] = { &info, NULL };
+#if defined(CONFIG_SUPERIO)
+ static const struct ata_port_info info87560 = {
+ .sht = &ns87415_sht,
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .port_ops = &ns87560_pata_ops,
+ };
+
+ if (PCI_SLOT(pdev->devfn) == 0x0E)
+ ppi[0] = &info87560;
+#endif
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+ /* Select 512 byte sectors */
+ pci_write_config_byte(pdev, 0x55, 0xEE);
+ /* Select PIO0 8bit clocking */
+ pci_write_config_byte(pdev, 0x54, 0xB7);
+ return ata_pci_init_one(pdev, ppi);
+}
+
+static const struct pci_device_id ns87415_pci_tbl[] = {
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), },
+
+ { } /* terminate list */
+};
+
+static struct pci_driver ns87415_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = ns87415_pci_tbl,
+ .probe = ns87415_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
+};
+
+static int __init ns87415_init(void)
+{
+ return pci_register_driver(&ns87415_pci_driver);
+}
+
+static void __exit ns87415_exit(void)
+{
+ pci_unregister_driver(&ns87415_pci_driver);
+}
+
+module_init(ns87415_init);
+module_exit(ns87415_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("ATA low-level driver for NS87415 controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index 091a70a0ef1..44da09ace52 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -29,14 +29,15 @@
/**
* oldpiix_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int oldpiix_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits oldpiix_enable_bits[] = {
{ 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
@@ -46,7 +47,7 @@ static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -199,7 +200,7 @@ static void oldpiix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
*
* Called when the libata layer is about to issue a command. We wrap
* this interface so that we can load the correct ATA timings if
- * neccessary. Our logic also clears TIME0/TIME1 for the other device so
+ * necessary. Our logic also clears TIME0/TIME1 for the other device so
* that, even if we get this wrong, cycles to the other device will
* be made PIO0.
*/
@@ -237,7 +238,6 @@ static struct scsi_host_template oldpiix_sht = {
};
static const struct ata_port_operations oldpiix_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = oldpiix_set_piomode,
.set_dmamode = oldpiix_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -265,9 +265,8 @@ static const struct ata_port_operations oldpiix_pata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index 458bf67f766..8f79447b615 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -46,14 +46,15 @@ enum {
/**
* opti_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int opti_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int opti_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits opti_enable_bits[] = {
{ 0x45, 1, 0x80, 0x00 },
@@ -63,7 +64,7 @@ static int opti_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -182,7 +183,6 @@ static struct scsi_host_template opti_sht = {
};
static struct ata_port_operations opti_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = opti_set_piomode,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -209,9 +209,8 @@ static struct ata_port_operations opti_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index f89bdfde16d..f9b485a487a 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -47,14 +47,15 @@ static int pci_clock; /* 0 = 33 1 = 25 */
/**
* optidma_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int optidma_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits optidma_enable_bits = {
0x40, 1, 0x08, 0x00
@@ -63,7 +64,7 @@ static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline)
if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -323,25 +324,26 @@ static u8 optidma_make_bits43(struct ata_device *adev)
/**
* optidma_set_mode - mode setup
- * @ap: port to set up
+ * @link: link to set up
*
* Use the standard setup to tune the chipset and then finalise the
* configuration by writing the nibble of extra bits of data into
* the chip.
*/
-static int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed)
+static int optidma_set_mode(struct ata_link *link, struct ata_device **r_failed)
{
+ struct ata_port *ap = link->ap;
u8 r;
int nybble = 4 * ap->port_no;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- int rc = ata_do_set_mode(ap, r_failed);
+ int rc = ata_do_set_mode(link, r_failed);
if (rc == 0) {
pci_read_config_byte(pdev, 0x43, &r);
r &= (0x0F << nybble);
- r |= (optidma_make_bits43(&ap->device[0]) +
- (optidma_make_bits43(&ap->device[0]) << 2)) << nybble;
+ r |= (optidma_make_bits43(&link->device[0]) +
+ (optidma_make_bits43(&link->device[0]) << 2)) << nybble;
pci_write_config_byte(pdev, 0x43, r);
}
return rc;
@@ -366,7 +368,6 @@ static struct scsi_host_template optidma_sht = {
};
static struct ata_port_operations optidma_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = optidma_set_pio_mode,
.set_dmamode = optidma_set_dma_mode,
@@ -396,13 +397,11 @@ static struct ata_port_operations optidma_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations optiplus_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = optiplus_set_pio_mode,
.set_dmamode = optiplus_set_dma_mode,
@@ -432,9 +431,8 @@ static struct ata_port_operations optiplus_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -451,7 +449,7 @@ static int optiplus_with_udma(struct pci_dev *pdev)
/* Find function 1 */
dev1 = pci_get_device(0x1045, 0xC701, NULL);
- if(dev1 == NULL)
+ if (dev1 == NULL)
return 0;
/* Rev must be >= 0x10 */
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 0f2b027624d..fd36099428a 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -56,7 +56,7 @@ struct ata_pcmcia_info {
/**
* pcmcia_set_mode - PCMCIA specific mode setup
- * @ap: Port
+ * @link: link
* @r_failed_dev: Return pointer for failed device
*
* Perform the tuning and setup of the devices and timings, which
@@ -65,17 +65,16 @@ struct ata_pcmcia_info {
* decode, which alas is embarrassingly common in the PC world
*/
-static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
{
- struct ata_device *master = &ap->device[0];
- struct ata_device *slave = &ap->device[1];
+ struct ata_device *master = &link->device[0];
+ struct ata_device *slave = &link->device[1];
if (!ata_dev_enabled(master) || !ata_dev_enabled(slave))
- return ata_do_set_mode(ap, r_failed_dev);
+ return ata_do_set_mode(link, r_failed_dev);
if (memcmp(master->id + ATA_ID_FW_REV, slave->id + ATA_ID_FW_REV,
- ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0)
- {
+ ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0) {
/* Suspicious match, but could be two cards from
the same vendor - check serial */
if (memcmp(master->id + ATA_ID_SERNO, slave->id + ATA_ID_SERNO,
@@ -84,7 +83,7 @@ static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev
ata_dev_disable(slave);
}
}
- return ata_do_set_mode(ap, r_failed_dev);
+ return ata_do_set_mode(link, r_failed_dev);
}
static struct scsi_host_template pcmcia_sht = {
@@ -107,7 +106,6 @@ static struct scsi_host_template pcmcia_sht = {
static struct ata_port_operations pcmcia_port_ops = {
.set_mode = pcmcia_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -127,7 +125,6 @@ static struct ata_port_operations pcmcia_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_sff_port_start,
};
@@ -250,7 +247,8 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
goto next_entry;
io_base = pdev->io.BasePort1;
ctl_base = pdev->io.BasePort1 + 0x0e;
- } else goto next_entry;
+ } else
+ goto next_entry;
/* If we've got this far, we're done */
break;
}
@@ -287,8 +285,8 @@ next_entry:
printk(KERN_WARNING DRV_NAME ": second channel not yet supported.\n");
/*
- * Having done the PCMCIA plumbing the ATA side is relatively
- * sane.
+ * Having done the PCMCIA plumbing the ATA side is relatively
+ * sane.
*/
ret = -ENOMEM;
host = ata_host_alloc(&pdev->dev, 1);
@@ -304,6 +302,8 @@ next_entry:
ap->ioaddr.ctl_addr = ctl_addr;
ata_std_ports(&ap->ioaddr);
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base);
+
/* activate */
ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt,
IRQF_SHARED, &pcmcia_sht);
@@ -353,6 +353,7 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev)
static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_FUNC_ID(4),
+ PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000), /* Corsair */
PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */
PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000), /* I-O Data CFA */
PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */
@@ -362,7 +363,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */
PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */
- PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */
+ PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */
PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100), /* Viking CFA */
PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar, Viking CFA */
@@ -378,6 +379,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591),
PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
+ PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index bb64a986e8f..2622577521a 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -69,7 +69,7 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc);
static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask);
static int pdc2027x_cable_detect(struct ata_port *ap);
-static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed);
+static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed);
/*
* ATA Timing Tables based on 133MHz controller clock.
@@ -147,7 +147,6 @@ static struct scsi_host_template pdc2027x_sht = {
};
static struct ata_port_operations pdc2027x_pata100_ops = {
- .port_disable = ata_port_disable,
.mode_filter = ata_pci_default_filter,
.tf_load = ata_tf_load,
@@ -173,13 +172,11 @@ static struct ata_port_operations pdc2027x_pata100_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations pdc2027x_pata133_ops = {
- .port_disable = ata_port_disable,
.set_piomode = pdc2027x_set_piomode,
.set_dmamode = pdc2027x_set_dmamode,
.set_mode = pdc2027x_set_mode,
@@ -208,9 +205,8 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_info pdc2027x_port_info[] = {
@@ -277,7 +273,7 @@ static int pdc2027x_cable_detect(struct ata_port *ap)
u32 cgcr;
/* check cable detect results */
- cgcr = readl(port_mmio(ap, PDC_GLOBAL_CTL));
+ cgcr = ioread32(port_mmio(ap, PDC_GLOBAL_CTL));
if (cgcr & (1 << 26))
goto cbl40;
@@ -295,12 +291,12 @@ cbl40:
*/
static inline int pdc2027x_port_enabled(struct ata_port *ap)
{
- return readb(port_mmio(ap, PDC_ATA_CTL)) & 0x02;
+ return ioread8(port_mmio(ap, PDC_ATA_CTL)) & 0x02;
}
/**
* pdc2027x_prereset - prereset for PATA host controller
- * @ap: Target port
+ * @link: Target link
* @deadline: deadline jiffies for the operation
*
* Probeinit including cable detection.
@@ -309,12 +305,12 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap)
* None (inherited from caller).
*/
-static int pdc2027x_prereset(struct ata_port *ap, unsigned long deadline)
+static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline)
{
/* Check whether port enabled */
- if (!pdc2027x_port_enabled(ap))
+ if (!pdc2027x_port_enabled(link->ap))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
/**
@@ -352,7 +348,7 @@ static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long
ata_id_c_string(pair->id, model_num, ATA_ID_PROD,
ATA_ID_PROD_LEN + 1);
/* If the master is a maxtor in UDMA6 then the slave should not use UDMA 6 */
- if(strstr(model_num, "Maxtor") == 0 && pair->dma_mode == XFER_UDMA_6)
+ if (strstr(model_num, "Maxtor") == 0 && pair->dma_mode == XFER_UDMA_6)
mask &= ~ (1 << (6 + ATA_SHIFT_UDMA));
return ata_pci_default_filter(adev, mask);
@@ -387,16 +383,16 @@ static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev)
/* Set the PIO timing registers using value table for 133MHz */
PDPRINTK("Set pio regs... \n");
- ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+ ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0));
ctcr0 &= 0xffff0000;
ctcr0 |= pdc2027x_pio_timing_tbl[pio].value0 |
(pdc2027x_pio_timing_tbl[pio].value1 << 8);
- writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+ iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
- ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+ ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
ctcr1 &= 0x00ffffff;
ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24);
- writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+ iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
PDPRINTK("Set pio regs done\n");
@@ -430,18 +426,18 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
* If tHOLD is '1', the hardware will add half clock for data hold time.
* This code segment seems to be no effect. tHOLD will be overwritten below.
*/
- ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
- writel(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
+ ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
+ iowrite32(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
}
PDPRINTK("Set udma regs... \n");
- ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+ ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
ctcr1 &= 0xff000000;
ctcr1 |= pdc2027x_udma_timing_tbl[udma_mode].value0 |
(pdc2027x_udma_timing_tbl[udma_mode].value1 << 8) |
(pdc2027x_udma_timing_tbl[udma_mode].value2 << 16);
- writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+ iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
PDPRINTK("Set udma regs done\n");
@@ -453,13 +449,13 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
unsigned int mdma_mode = dma_mode & 0x07;
PDPRINTK("Set mdma regs... \n");
- ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+ ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0));
ctcr0 &= 0x0000ffff;
ctcr0 |= (pdc2027x_mdma_timing_tbl[mdma_mode].value0 << 16) |
(pdc2027x_mdma_timing_tbl[mdma_mode].value1 << 24);
- writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+ iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
PDPRINTK("Set mdma regs done\n");
PDPRINTK("Set to mdma mode[%u] \n", mdma_mode);
@@ -470,24 +466,24 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
/**
* pdc2027x_set_mode - Set the timing registers back to correct values.
- * @ap: Port to configure
+ * @link: link to configure
* @r_failed: Returned device for failure
*
* The pdc2027x hardware will look at "SET FEATURES" and change the timing registers
* automatically. The values set by the hardware might be incorrect, under 133Mhz PLL.
* This function overwrites the possibly incorrect values set by the hardware to be correct.
*/
-static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed)
+static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed)
{
- int i;
-
- i = ata_do_set_mode(ap, r_failed);
- if (i < 0)
- return i;
+ struct ata_port *ap = link->ap;
+ struct ata_device *dev;
+ int rc;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ rc = ata_do_set_mode(link, r_failed);
+ if (rc < 0)
+ return rc;
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
pdc2027x_set_piomode(ap, dev);
@@ -496,9 +492,9 @@ static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed)
* Enable prefetch if the device support PIO only.
*/
if (dev->xfer_shift == ATA_SHIFT_PIO) {
- u32 ctcr1 = readl(dev_mmio(ap, dev, PDC_CTCR1));
+ u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1));
ctcr1 |= (1 << 25);
- writel(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
+ iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
PDPRINTK("Turn on prefetch\n");
} else {
@@ -563,14 +559,12 @@ static long pdc_read_counter(struct ata_host *host)
u32 bccrl, bccrh, bccrlv, bccrhv;
retry:
- bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
- bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
- rmb();
+ bccrl = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
+ bccrh = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
/* Read the counter values again for verification */
- bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
- bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
- rmb();
+ bccrlv = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
+ bccrhv = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
counter = (bccrh << 15) | bccrl;
@@ -619,7 +613,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b
/* Show the current clock value of PLL control register
* (maybe already configured by the firmware)
*/
- pll_ctl = readw(mmio_base + PDC_PLL_CTL);
+ pll_ctl = ioread16(mmio_base + PDC_PLL_CTL);
PDPRINTK("pll_ctl[%X]\n", pll_ctl);
#endif
@@ -659,8 +653,8 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b
PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl);
- writew(pll_ctl, mmio_base + PDC_PLL_CTL);
- readw(mmio_base + PDC_PLL_CTL); /* flush */
+ iowrite16(pll_ctl, mmio_base + PDC_PLL_CTL);
+ ioread16(mmio_base + PDC_PLL_CTL); /* flush */
/* Wait the PLL circuit to be stable */
mdelay(30);
@@ -670,7 +664,7 @@ static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int b
* Show the current clock value of PLL control register
* (maybe configured by the firmware)
*/
- pll_ctl = readw(mmio_base + PDC_PLL_CTL);
+ pll_ctl = ioread16(mmio_base + PDC_PLL_CTL);
PDPRINTK("pll_ctl[%X]\n", pll_ctl);
#endif
@@ -693,10 +687,10 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
long pll_clock, usec_elapsed;
/* Start the test mode */
- scr = readl(mmio_base + PDC_SYS_CTL);
+ scr = ioread32(mmio_base + PDC_SYS_CTL);
PDPRINTK("scr[%X]\n", scr);
- writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
- readl(mmio_base + PDC_SYS_CTL); /* flush */
+ iowrite32(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
+ ioread32(mmio_base + PDC_SYS_CTL); /* flush */
/* Read current counter value */
start_count = pdc_read_counter(host);
@@ -710,10 +704,10 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
do_gettimeofday(&end_time);
/* Stop the test mode */
- scr = readl(mmio_base + PDC_SYS_CTL);
+ scr = ioread32(mmio_base + PDC_SYS_CTL);
PDPRINTK("scr[%X]\n", scr);
- writel(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);
- readl(mmio_base + PDC_SYS_CTL); /* flush */
+ iowrite32(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);
+ ioread32(mmio_base + PDC_SYS_CTL); /* flush */
/* calculate the input clock in Hz */
usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
@@ -745,9 +739,6 @@ static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx)
*/
pll_clock = pdc_detect_pll_input_clock(host);
- if (pll_clock < 0) /* counter overflow? Try again. */
- pll_clock = pdc_detect_pll_input_clock(host);
-
dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
/* Adjust PLL control register */
@@ -791,12 +782,14 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
+ static const unsigned long cmd_offset[] = { 0x17c0, 0x15c0 };
+ static const unsigned long bmdma_offset[] = { 0x1000, 0x1008 };
unsigned int board_idx = (unsigned int) ent->driver_data;
const struct ata_port_info *ppi[] =
{ &pdc2027x_port_info[board_idx], NULL };
struct ata_host *host;
void __iomem *mmio_base;
- int rc;
+ int i, rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -826,10 +819,15 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
mmio_base = host->iomap[PDC_MMIO_BAR];
- pdc_ata_setup_port(&host->ports[0]->ioaddr, mmio_base + 0x17c0);
- host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x1000;
- pdc_ata_setup_port(&host->ports[1]->ioaddr, mmio_base + 0x15c0);
- host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x1008;
+ for (i = 0; i < 2; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ pdc_ata_setup_port(&ap->ioaddr, mmio_base + cmd_offset[i]);
+ ap->ioaddr.bmdma_addr = mmio_base + bmdma_offset[i];
+
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, cmd_offset[i], "cmd");
+ }
//pci_enable_intx(pdev);
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 92447bed5e7..bc7c2d5d8d5 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -9,7 +9,7 @@
* First cut with LBA48/ATAPI
*
* TODO:
- * Channel interlock/reset on both required
+ * Channel interlock/reset on both required ?
*/
#include <linux/kernel.h>
@@ -22,7 +22,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_pdc202xx_old"
-#define DRV_VERSION "0.4.2"
+#define DRV_VERSION "0.4.3"
static int pdc2026x_cable_detect(struct ata_port *ap)
{
@@ -106,9 +106,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{ 0x20, 0x01 }
};
static u8 mdma_timing[3][2] = {
- { 0x60, 0x03 },
- { 0x60, 0x04 },
{ 0xe0, 0x0f },
+ { 0x60, 0x04 },
+ { 0x60, 0x03 },
};
u8 r_bp, r_cp;
@@ -139,6 +139,9 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev)
*
* In UDMA3 or higher we have to clock switch for the duration of the
* DMA transfer sequence.
+ *
+ * Note: The host lock held by the libata layer protects
+ * us from two channels both trying to set DMA bits at once
*/
static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
@@ -187,6 +190,9 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
*
* After a DMA completes we need to put the clock back to 33MHz for
* PIO timings.
+ *
+ * Note: The host lock held by the libata layer protects
+ * us from two channels both trying to set DMA bits at once
*/
static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
@@ -206,7 +212,6 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
iowrite32(0, atapi_reg);
iowrite8(ioread8(clock) & ~sel66, clock);
}
- /* Check we keep host level locking here */
/* Flip back to 33Mhz for PIO */
if (adev->dma_mode >= XFER_UDMA_2)
iowrite8(ioread8(clock) & ~sel66, clock);
@@ -247,7 +252,6 @@ static struct scsi_host_template pdc202xx_sht = {
};
static struct ata_port_operations pdc2024x_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = pdc202xx_set_piomode,
.set_dmamode = pdc202xx_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -275,13 +279,11 @@ static struct ata_port_operations pdc2024x_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations pdc2026x_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = pdc202xx_set_piomode,
.set_dmamode = pdc202xx_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -310,9 +312,8 @@ static struct ata_port_operations pdc2026x_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -350,9 +351,9 @@ static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id
struct pci_dev *bridge = dev->bus->self;
/* Don't grab anything behind a Promise I2O RAID */
if (bridge && bridge->vendor == PCI_VENDOR_ID_INTEL) {
- if( bridge->device == PCI_DEVICE_ID_INTEL_I960)
+ if (bridge->device == PCI_DEVICE_ID_INTEL_I960)
return -ENODEV;
- if( bridge->device == PCI_DEVICE_ID_INTEL_I960RM)
+ if (bridge->device == PCI_DEVICE_ID_INTEL_I960RM)
return -ENODEV;
}
}
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 5086d03f2d7..ac03a90a616 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -1,7 +1,7 @@
/*
* Generic platform device PATA driver
*
- * Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2006 - 2007 Paul Mundt
*
* Based on pata_pcmcia:
*
@@ -22,7 +22,7 @@
#include <linux/pata_platform.h>
#define DRV_NAME "pata_platform"
-#define DRV_VERSION "1.1"
+#define DRV_VERSION "1.2"
static int pio_mask = 1;
@@ -30,13 +30,11 @@ static int pio_mask = 1;
* Provide our own set_mode() as we don't want to change anything that has
* already been configured..
*/
-static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int pata_platform_set_mode(struct ata_link *link, struct ata_device **unused)
{
- int i;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ struct ata_device *dev;
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
/* We don't really care */
dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
@@ -71,7 +69,6 @@ static struct scsi_host_template pata_platform_sht = {
static struct ata_port_operations pata_platform_port_ops = {
.set_mode = pata_platform_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -91,7 +88,6 @@ static struct ata_port_operations pata_platform_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_dummy_ret0,
};
@@ -124,15 +120,20 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
* Register a platform bus IDE interface. Such interfaces are PIO and we
* assume do not support IRQ sharing.
*
- * Platform devices are expected to contain 3 resources per port:
+ * Platform devices are expected to contain at least 2 resources per port:
*
* - I/O Base (IORESOURCE_IO or IORESOURCE_MEM)
* - CTL Base (IORESOURCE_IO or IORESOURCE_MEM)
+ *
+ * and optionally:
+ *
* - IRQ (IORESOURCE_IRQ)
*
* If the base resources are both mem types, the ioremap() is handled
* here. For IORESOURCE_IO, it's assumed that there's no remapping
* necessary.
+ *
+ * If no IRQ resource is present, PIO polling mode is used instead.
*/
static int __devinit pata_platform_probe(struct platform_device *pdev)
{
@@ -141,11 +142,12 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
struct ata_port *ap;
struct pata_platform_info *pp_info;
unsigned int mmio;
+ int irq;
/*
* Simple resource validation ..
*/
- if (unlikely(pdev->num_resources != 3)) {
+ if ((pdev->num_resources != 3) && (pdev->num_resources != 2)) {
dev_err(&pdev->dev, "invalid number of resources\n");
return -EINVAL;
}
@@ -177,6 +179,13 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
(ctl_res->flags == IORESOURCE_MEM));
/*
+ * And the IRQ
+ */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ irq = 0; /* no irq */
+
+ /*
* Now that that's out of the way, wire up the port..
*/
host = ata_host_alloc(&pdev->dev, 1);
@@ -189,6 +198,14 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
ap->flags |= ATA_FLAG_SLAVE_POSS;
/*
+ * Use polling mode if there's no IRQ
+ */
+ if (!irq) {
+ ap->flags |= ATA_FLAG_PIO_POLLING;
+ ata_port_desc(ap, "no IRQ, using PIO polling");
+ }
+
+ /*
* Handle the MMIO case
*/
if (mmio) {
@@ -209,13 +226,17 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
- pp_info = (struct pata_platform_info *)(pdev->dev.platform_data);
+ pp_info = pdev->dev.platform_data;
pata_platform_setup_port(&ap->ioaddr, pp_info);
+ ata_port_desc(ap, "%s cmd 0x%llx ctl 0x%llx", mmio ? "mmio" : "ioport",
+ (unsigned long long)io_res->start,
+ (unsigned long long)ctl_res->start);
+
/* activate */
- return ata_host_activate(host, platform_get_irq(pdev, 0),
- ata_interrupt, pp_info ? pp_info->irq_flags
- : 0, &pata_platform_sht);
+ return ata_host_activate(host, irq, irq ? ata_interrupt : NULL,
+ pp_info ? pp_info->irq_flags : 0,
+ &pata_platform_sht);
}
/**
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index 1998c19e874..7d4c696c4cb 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -126,7 +126,7 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
int slop = buflen & 3;
if (ata_id_has_dword_io(adev->id)) {
@@ -170,7 +170,6 @@ static struct scsi_host_template qdi_sht = {
};
static struct ata_port_operations qdi6500_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = qdi6500_set_piomode,
.tf_load = ata_tf_load,
@@ -192,13 +191,11 @@ static struct ata_port_operations qdi6500_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations qdi6580_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = qdi6580_set_piomode,
.tf_load = ata_tf_load,
@@ -220,9 +217,8 @@ static struct ata_port_operations qdi6580_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -238,6 +234,7 @@ static struct ata_port_operations qdi6580_port_ops = {
static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast)
{
+ unsigned long ctl = io + 0x206;
struct platform_device *pdev;
struct ata_host *host;
struct ata_port *ap;
@@ -254,7 +251,7 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
ret = -ENOMEM;
io_addr = devm_ioport_map(&pdev->dev, io, 8);
- ctl_addr = devm_ioport_map(&pdev->dev, io + 0x206, 1);
+ ctl_addr = devm_ioport_map(&pdev->dev, ctl, 1);
if (!io_addr || !ctl_addr)
goto fail;
@@ -279,6 +276,8 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
ap->ioaddr.ctl_addr = ctl_addr;
ata_std_ports(&ap->ioaddr);
+ ata_port_desc(ap, "cmd %lx ctl %lx", io, ctl);
+
/*
* Hook in a private data structure per channel
*/
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index 7d1aabed422..8109b08fc02 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -161,7 +161,7 @@ static void radisys_set_dmamode (struct ata_port *ap, struct ata_device *adev)
*
* Called when the libata layer is about to issue a command. We wrap
* this interface so that we can load the correct ATA timings if
- * neccessary. Our logic also clears TIME0/TIME1 for the other device so
+ * necessary. Our logic also clears TIME0/TIME1 for the other device so
* that, even if we get this wrong, cycles to the other device will
* be made PIO0.
*/
@@ -203,7 +203,6 @@ static struct scsi_host_template radisys_sht = {
};
static const struct ata_port_operations radisys_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = radisys_set_piomode,
.set_dmamode = radisys_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -231,9 +230,8 @@ static const struct ata_port_operations radisys_pata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index 7632fcb070c..ba8a31c55ed 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -26,7 +26,7 @@
/**
* rz1000_set_mode - mode setting function
- * @ap: ATA interface
+ * @link: ATA link
* @unused: returned device on set_mode failure
*
* Use a non standard set_mode function. We don't want to be tuned. We
@@ -34,12 +34,11 @@
* whacked out.
*/
-static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int rz1000_set_mode(struct ata_link *link, struct ata_device **unused)
{
- int i;
+ struct ata_device *dev;
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (ata_dev_enabled(dev)) {
/* We don't really care */
dev->pio_mode = XFER_PIO_0;
@@ -74,7 +73,6 @@ static struct scsi_host_template rz1000_sht = {
static struct ata_port_operations rz1000_port_ops = {
.set_mode = rz1000_set_mode,
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -100,9 +98,8 @@ static struct ata_port_operations rz1000_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int rz1000_fifo_disable(struct pci_dev *pdev)
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index 5edf67b1f3b..725a8586cd6 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -156,7 +156,7 @@ static void sc1200_set_dmamode(struct ata_port *ap, struct ata_device *adev)
*
* Called when the libata layer is about to issue a command. We wrap
* this interface so that we can load the correct ATA timings if
- * neccessary. Specifically we have a problem that there is only
+ * necessary. Specifically we have a problem that there is only
* one MWDMA/UDMA bit.
*/
@@ -197,7 +197,6 @@ static struct scsi_host_template sc1200_sht = {
};
static struct ata_port_operations sc1200_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sc1200_set_piomode,
.set_dmamode = sc1200_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -227,9 +226,8 @@ static struct ata_port_operations sc1200_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index 2d048ef25a5..ea2ef9fc15b 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -570,17 +570,8 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
udelay(20);
out_be32(ioaddr->ctl_addr, ap->ctl);
- /* spec mandates ">= 2ms" before checking status.
- * We wait 150ms, because that was the magic delay used for
- * ATAPI devices in Hale Landis's ATADRVR, for the period of time
- * between when the ATA command register is written, and then
- * status is checked. Because waiting for "a while" before
- * checking status is fine, post SRST, we perform this magic
- * delay here as well.
- *
- * Old drivers/ide uses the 2mS rule and then waits for ready
- */
- msleep(150);
+ /* wait a while before checking status */
+ ata_wait_after_reset(ap, deadline);
/* Before we perform post reset processing we want to see if
* the bus shows 0xFF because the odd clown forgets the D7
@@ -603,16 +594,17 @@ static unsigned int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
* Note: Original code is ata_std_softreset().
*/
-static int scc_std_softreset (struct ata_port *ap, unsigned int *classes,
- unsigned long deadline)
+static int scc_std_softreset(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
unsigned int devmask = 0, err_mask;
u8 err;
DPRINTK("ENTER\n");
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
classes[0] = ATA_DEV_NONE;
goto out;
}
@@ -636,9 +628,11 @@ static int scc_std_softreset (struct ata_port *ap, unsigned int *classes,
}
/* determine by signature whether we have ATA or ATAPI devices */
- classes[0] = ata_dev_try_classify(ap, 0, &err);
+ classes[0] = ata_dev_try_classify(&ap->link.device[0],
+ devmask & (1 << 0), &err);
if (slave_possible && err != 0x81)
- classes[1] = ata_dev_try_classify(ap, 1, &err);
+ classes[1] = ata_dev_try_classify(&ap->link.device[1],
+ devmask & (1 << 1), &err);
out:
DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
@@ -701,7 +695,7 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc)
printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME);
out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT);
/* TBD: SW reset */
- scc_std_softreset(ap, &classes, deadline);
+ scc_std_softreset(&ap->link, &classes, deadline);
continue;
}
@@ -740,7 +734,7 @@ static u8 scc_bmdma_status (struct ata_port *ap)
void __iomem *mmio = ap->ioaddr.bmdma_addr;
u8 host_stat = in_be32(mmio + SCC_DMA_STATUS);
u32 int_status = in_be32(mmio + SCC_DMA_INTST);
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
static int retry = 0;
/* return if IOS_SS is cleared */
@@ -785,7 +779,7 @@ static u8 scc_bmdma_status (struct ata_port *ap)
static void scc_data_xfer (struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
unsigned int words = buflen >> 1;
unsigned int i;
u16 *buf16 = (u16 *) buf;
@@ -839,38 +833,6 @@ static u8 scc_irq_on (struct ata_port *ap)
}
/**
- * scc_irq_ack - Acknowledge a device interrupt.
- * @ap: Port on which interrupts are enabled.
- *
- * Note: Original code is ata_irq_ack().
- */
-
-static u8 scc_irq_ack (struct ata_port *ap, unsigned int chk_drq)
-{
- unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
- u8 host_stat, post_stat, status;
-
- status = ata_busy_wait(ap, bits, 1000);
- if (status & bits)
- if (ata_msg_err(ap))
- printk(KERN_ERR "abnormal status 0x%X\n", status);
-
- /* get controller status; clear intr, err bits */
- host_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS);
- out_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS,
- host_stat | ATA_DMA_INTR | ATA_DMA_ERR);
-
- post_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS);
-
- if (ata_msg_intr(ap))
- printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
- __FUNCTION__,
- host_stat, post_stat, status);
-
- return status;
-}
-
-/**
* scc_bmdma_freeze - Freeze BMDMA controller port
* @ap: port to freeze
*
@@ -901,10 +863,10 @@ static void scc_bmdma_freeze (struct ata_port *ap)
* @deadline: deadline jiffies for the operation
*/
-static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline)
+static int scc_pata_prereset(struct ata_link *link, unsigned long deadline)
{
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap, deadline);
+ link->ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(link, deadline);
}
/**
@@ -915,8 +877,10 @@ static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline)
* Note: Original code is ata_std_postreset().
*/
-static void scc_std_postreset (struct ata_port *ap, unsigned int *classes)
+static void scc_std_postreset(struct ata_link *link, unsigned int *classes)
{
+ struct ata_port *ap = link->ap;
+
DPRINTK("ENTER\n");
/* is double-select really necessary? */
@@ -1020,7 +984,6 @@ static struct scsi_host_template scc_sht = {
};
static const struct ata_port_operations scc_pata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = scc_set_piomode,
.set_dmamode = scc_set_dmamode,
.mode_filter = scc_mode_filter,
@@ -1047,7 +1010,6 @@ static const struct ata_port_operations scc_pata_ops = {
.irq_clear = scc_bmdma_irq_clear,
.irq_on = scc_irq_on,
- .irq_ack = scc_irq_ack,
.port_start = scc_port_start,
.port_stop = scc_port_stop,
@@ -1193,6 +1155,9 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
host->iomap = pcim_iomap_table(pdev);
+ ata_port_pbar_desc(host->ports[0], SCC_CTRL_BAR, -1, "ctrl");
+ ata_port_pbar_desc(host->ports[0], SCC_BMID_BAR, -1, "bmid");
+
rc = scc_host_init(host);
if (rc)
return rc;
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index 0faf99c8f13..8bed8887372 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -274,28 +274,27 @@ static void serverworks_set_dmamode(struct ata_port *ap, struct ata_device *adev
{
static const u8 dma_mode[] = { 0x77, 0x21, 0x20 };
int offset = 1 + 2 * ap->port_no - adev->devno;
- int devbits = (2 * ap->port_no + adev->devno);
+ int devbits = 2 * ap->port_no + adev->devno;
u8 ultra;
u8 ultra_cfg;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
pci_read_config_byte(pdev, 0x54, &ultra_cfg);
+ pci_read_config_byte(pdev, 0x56 + ap->port_no, &ultra);
+ ultra &= ~(0x0F << (adev->devno * 4));
if (adev->dma_mode >= XFER_UDMA_0) {
pci_write_config_byte(pdev, 0x44 + offset, 0x20);
- pci_read_config_byte(pdev, 0x56 + ap->port_no, &ultra);
- ultra &= ~(0x0F << (ap->port_no * 4));
ultra |= (adev->dma_mode - XFER_UDMA_0)
- << (ap->port_no * 4);
- pci_write_config_byte(pdev, 0x56 + ap->port_no, ultra);
-
+ << (adev->devno * 4);
ultra_cfg |= (1 << devbits);
} else {
pci_write_config_byte(pdev, 0x44 + offset,
dma_mode[adev->dma_mode - XFER_MW_DMA_0]);
ultra_cfg &= ~(1 << devbits);
}
+ pci_write_config_byte(pdev, 0x56 + ap->port_no, ultra);
pci_write_config_byte(pdev, 0x54, ultra_cfg);
}
@@ -318,7 +317,6 @@ static struct scsi_host_template serverworks_sht = {
};
static struct ata_port_operations serverworks_osb4_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = serverworks_set_piomode,
.set_dmamode = serverworks_set_dmamode,
.mode_filter = serverworks_osb4_filter,
@@ -348,13 +346,11 @@ static struct ata_port_operations serverworks_osb4_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations serverworks_csb_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = serverworks_set_piomode,
.set_dmamode = serverworks_set_dmamode,
.mode_filter = serverworks_csb_filter,
@@ -384,9 +380,8 @@ static struct ata_port_operations serverworks_csb_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int serverworks_fixup_osb4(struct pci_dev *pdev)
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index 40395804a66..5c1e9cb59ec 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -16,7 +16,7 @@
*
* If you have strange problems with nVidia chipset systems please
* see the SI support documentation and update your system BIOS
- * if neccessary
+ * if necessary
*
* TODO
* If we know all our devices are LBA28 (or LBA28 sized) we could use
@@ -95,15 +95,16 @@ static int sil680_cable_detect(struct ata_port *ap) {
/**
* sil680_bus_reset - reset the SIL680 bus
- * @ap: ATA port to reset
+ * @link: ATA link to reset
* @deadline: deadline jiffies for the operation
*
* Perform the SIL680 housekeeping when doing an ATA bus reset
*/
-static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes,
+static int sil680_bus_reset(struct ata_link *link, unsigned int *classes,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned long addr = sil680_selreg(ap, 0);
u8 reset;
@@ -112,7 +113,7 @@ static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes,
pci_write_config_byte(pdev, addr, reset | 0x03);
udelay(25);
pci_write_config_byte(pdev, addr, reset);
- return ata_std_softreset(ap, classes, deadline);
+ return ata_std_softreset(link, classes, deadline);
}
static void sil680_error_handler(struct ata_port *ap)
@@ -237,7 +238,6 @@ static struct scsi_host_template sil680_sht = {
};
static struct ata_port_operations sil680_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sil680_set_piomode,
.set_dmamode = sil680_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -266,9 +266,8 @@ static struct ata_port_operations sil680_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -280,7 +279,7 @@ static struct ata_port_operations sil680_port_ops = {
* Returns the final clock settings.
*/
-static u8 sil680_init_chip(struct pci_dev *pdev)
+static u8 sil680_init_chip(struct pci_dev *pdev, int *try_mmio)
{
u32 class_rev = 0;
u8 tmpbyte = 0;
@@ -298,6 +297,8 @@ static u8 sil680_init_chip(struct pci_dev *pdev)
dev_dbg(&pdev->dev, "sil680: BA5_EN = %d clock = %02X\n",
tmpbyte & 1, tmpbyte & 0x30);
+ *try_mmio = (tmpbyte & 1) || pci_resource_start(pdev, 5);
+
switch(tmpbyte & 0x30) {
case 0x00:
/* 133 clock attempt to force it on */
@@ -362,25 +363,76 @@ static int __devinit sil680_init_one(struct pci_dev *pdev,
};
const struct ata_port_info *ppi[] = { &info, NULL };
static int printed_version;
+ struct ata_host *host;
+ void __iomem *mmio_base;
+ int rc, try_mmio;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- switch(sil680_init_chip(pdev))
- {
+ switch (sil680_init_chip(pdev, &try_mmio)) {
case 0:
ppi[0] = &info_slow;
break;
case 0x30:
return -ENODEV;
}
+
+ if (!try_mmio)
+ goto use_ioports;
+
+ /* Try to acquire MMIO resources and fallback to PIO if
+ * that fails
+ */
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+ rc = pcim_iomap_regions(pdev, 1 << SIL680_MMIO_BAR, DRV_NAME);
+ if (rc)
+ goto use_ioports;
+
+ /* Allocate host and set it up */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+ if (!host)
+ return -ENOMEM;
+ host->iomap = pcim_iomap_table(pdev);
+
+ /* Setup DMA masks */
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+ pci_set_master(pdev);
+
+ /* Get MMIO base and initialize port addresses */
+ mmio_base = host->iomap[SIL680_MMIO_BAR];
+ host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x00;
+ host->ports[0]->ioaddr.cmd_addr = mmio_base + 0x80;
+ host->ports[0]->ioaddr.ctl_addr = mmio_base + 0x8a;
+ host->ports[0]->ioaddr.altstatus_addr = mmio_base + 0x8a;
+ ata_std_ports(&host->ports[0]->ioaddr);
+ host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x08;
+ host->ports[1]->ioaddr.cmd_addr = mmio_base + 0xc0;
+ host->ports[1]->ioaddr.ctl_addr = mmio_base + 0xca;
+ host->ports[1]->ioaddr.altstatus_addr = mmio_base + 0xca;
+ ata_std_ports(&host->ports[1]->ioaddr);
+
+ /* Register & activate */
+ return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+ &sil680_sht);
+
+use_ioports:
return ata_pci_init_one(pdev, ppi);
}
#ifdef CONFIG_PM
static int sil680_reinit_one(struct pci_dev *pdev)
{
- sil680_init_chip(pdev);
+ int try_mmio;
+
+ sil680_init_chip(pdev, &try_mmio);
return ata_pci_device_resume(pdev);
}
#endif
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index cce2834b2b6..3b5be77e861 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -84,7 +84,7 @@ static int sis_short_ata40(struct pci_dev *dev)
static int sis_old_port_base(struct ata_device *adev)
{
- return 0x40 + (4 * adev->ap->port_no) + (2 * adev->devno);
+ return 0x40 + (4 * adev->link->ap->port_no) + (2 * adev->devno);
}
/**
@@ -133,19 +133,20 @@ static int sis_66_cable_detect(struct ata_port *ap)
/**
* sis_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int sis_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int sis_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits sis_enable_bits[] = {
{ 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
{ 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
@@ -154,7 +155,7 @@ static int sis_pre_reset(struct ata_port *ap, unsigned long deadline)
/* Clear the FIFO settings. We can't enable the FIFO until
we know we are poking at a disk */
pci_write_config_byte(pdev, 0x4B, 0);
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
@@ -530,7 +531,6 @@ static struct scsi_host_template sis_sht = {
};
static const struct ata_port_operations sis_133_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_133_set_piomode,
.set_dmamode = sis_133_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -558,13 +558,11 @@ static const struct ata_port_operations sis_133_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_133_for_sata_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_133_set_piomode,
.set_dmamode = sis_133_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -592,13 +590,11 @@ static const struct ata_port_operations sis_133_for_sata_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_133_early_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_100_set_piomode,
.set_dmamode = sis_133_early_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -626,13 +622,11 @@ static const struct ata_port_operations sis_133_early_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_100_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_100_set_piomode,
.set_dmamode = sis_100_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -660,13 +654,11 @@ static const struct ata_port_operations sis_100_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_66_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_old_set_piomode,
.set_dmamode = sis_66_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -694,13 +686,11 @@ static const struct ata_port_operations sis_66_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_operations sis_old_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sis_old_set_piomode,
.set_dmamode = sis_old_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -728,9 +718,8 @@ static const struct ata_port_operations sis_old_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static const struct ata_port_info sis_info = {
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index c0f43bb2595..1388cef52c0 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -43,23 +43,24 @@ enum {
/**
* sl82c105_pre_reset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int sl82c105_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int sl82c105_pre_reset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits sl82c105_enable_bits[] = {
{ 0x40, 1, 0x01, 0x01 },
{ 0x40, 1, 0x10, 0x10 }
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
@@ -224,7 +225,6 @@ static struct scsi_host_template sl82c105_sht = {
};
static struct ata_port_operations sl82c105_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = sl82c105_set_piomode,
.mode_filter = ata_pci_default_filter,
@@ -253,9 +253,8 @@ static struct ata_port_operations sl82c105_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index af21f443db6..403eafcffe1 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -47,25 +47,26 @@
/**
* triflex_prereset - probe begin
- * @ap: ATA port
+ * @link: ATA link
* @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int triflex_prereset(struct ata_port *ap, unsigned long deadline)
+static int triflex_prereset(struct ata_link *link, unsigned long deadline)
{
static const struct pci_bits triflex_enable_bits[] = {
{ 0x80, 1, 0x01, 0x01 },
{ 0x80, 1, 0x02, 0x02 }
};
+ struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
return -ENOENT;
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
@@ -197,7 +198,6 @@ static struct scsi_host_template triflex_sht = {
};
static struct ata_port_operations triflex_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = triflex_set_piomode,
.mode_filter = ata_pci_default_filter,
@@ -226,9 +226,8 @@ static struct ata_port_operations triflex_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 636c4f1a0b2..a4175fbdd17 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -129,7 +129,7 @@ static const struct via_isa_bridge {
* Cable special cases
*/
-static struct dmi_system_id cable_dmi_table[] = {
+static const struct dmi_system_id cable_dmi_table[] = {
{
.ident = "Acer Ferrari 3400",
.matches = {
@@ -176,7 +176,7 @@ static int via_cable_detect(struct ata_port *ap) {
if ((config->flags & VIA_UDMA) < VIA_UDMA_66)
return ATA_CBL_PATA40;
/* UDMA 66 chips have only drive side logic */
- else if((config->flags & VIA_UDMA) < VIA_UDMA_100)
+ else if ((config->flags & VIA_UDMA) < VIA_UDMA_100)
return ATA_CBL_PATA_UNK;
/* UDMA 100 or later */
pci_read_config_dword(pdev, 0x50, &ata66);
@@ -184,11 +184,15 @@ static int via_cable_detect(struct ata_port *ap) {
two drives */
if (ata66 & (0x10100000 >> (16 * ap->port_no)))
return ATA_CBL_PATA80;
+ /* Check with ACPI so we can spot BIOS reported SATA bridges */
+ if (ata_acpi_cbl_80wire(ap))
+ return ATA_CBL_PATA80;
return ATA_CBL_PATA40;
}
-static int via_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int via_pre_reset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
const struct via_isa_bridge *config = ap->host->private_data;
if (!(config->flags & VIA_NO_ENABLES)) {
@@ -201,7 +205,7 @@ static int via_pre_reset(struct ata_port *ap, unsigned long deadline)
return -ENOENT;
}
- return ata_std_prereset(ap, deadline);
+ return ata_std_prereset(link, deadline);
}
@@ -344,7 +348,6 @@ static struct scsi_host_template via_sht = {
};
static struct ata_port_operations via_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = via_set_piomode,
.set_dmamode = via_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -374,13 +377,11 @@ static struct ata_port_operations via_port_ops = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
static struct ata_port_operations via_port_ops_noirq = {
- .port_disable = ata_port_disable,
.set_piomode = via_set_piomode,
.set_dmamode = via_set_dmamode,
.mode_filter = ata_pci_default_filter,
@@ -410,9 +411,8 @@ static struct ata_port_operations via_port_ops_noirq = {
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -420,7 +420,7 @@ static struct ata_port_operations via_port_ops_noirq = {
* @pdev: PCI device
* @flags: configuration flags
*
- * Set the FIFO properties for this device if neccessary. Used both on
+ * Set the FIFO properties for this device if necessary. Used both on
* set up and on and the resume path
*/
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 83abfeca405..311cdb3a556 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -94,7 +94,7 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
{
- struct ata_port *ap = adev->ap;
+ struct ata_port *ap = adev->link->ap;
int slop = buflen & 3;
if (ata_id_has_dword_io(adev->id)) {
@@ -138,7 +138,6 @@ static struct scsi_host_template winbond_sht = {
};
static struct ata_port_operations winbond_port_ops = {
- .port_disable = ata_port_disable,
.set_piomode = winbond_set_piomode,
.tf_load = ata_tf_load,
@@ -160,9 +159,8 @@ static struct ata_port_operations winbond_port_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
- .port_start = ata_port_start,
+ .port_start = ata_sff_port_start,
};
/**
@@ -199,6 +197,7 @@ static __init int winbond_init_one(unsigned long port)
for (i = 0; i < 2 ; i ++) {
unsigned long cmd_port = 0x1F0 - (0x80 * i);
+ unsigned long ctl_port = cmd_port + 0x206;
struct ata_host *host;
struct ata_port *ap;
void __iomem *cmd_addr, *ctl_addr;
@@ -214,14 +213,16 @@ static __init int winbond_init_one(unsigned long port)
host = ata_host_alloc(&pdev->dev, 1);
if (!host)
goto err_unregister;
+ ap = host->ports[0];
rc = -ENOMEM;
cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
- ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
+ ctl_addr = devm_ioport_map(&pdev->dev, ctl_port, 1);
if (!cmd_addr || !ctl_addr)
goto err_unregister;
- ap = host->ports[0];
+ ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", cmd_port, ctl_port);
+
ap->ops = &winbond_port_ops;
ap->pio_mask = 0x1F;
ap->flags |= ATA_FLAG_SLAVE_POSS;
@@ -278,7 +279,7 @@ static __init int winbond_init(void)
if (request_region(port, 2, "pata_winbond")) {
ret = winbond_init_one(port);
- if(ret <= 0)
+ if (ret <= 0)
release_region(port, 2);
else ct+= ret;
}
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 5c79271401a..bd4c2a3c88d 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -47,10 +47,10 @@
#define DRV_VERSION "1.0"
/* macro to calculate base address for ATA regs */
-#define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40))
+#define ADMA_ATA_REGS(base, port_no) ((base) + ((port_no) * 0x40))
/* macro to calculate base address for ADMA regs */
-#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20))
+#define ADMA_REGS(base, port_no) ((base) + 0x80 + ((port_no) * 0x20))
/* macro to obtain addresses from ata_port */
#define ADMA_PORT_REGS(ap) \
@@ -92,6 +92,8 @@ enum {
/* CPB bits */
cDONE = (1 << 0),
+ cATERR = (1 << 3),
+
cVLD = (1 << 0),
cDAT = (1 << 2),
cIEN = (1 << 3),
@@ -126,19 +128,20 @@ struct adma_port_priv {
adma_state_t state;
};
-static int adma_ata_init_one (struct pci_dev *pdev,
+static int adma_ata_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent);
static int adma_port_start(struct ata_port *ap);
static void adma_host_stop(struct ata_host *host);
static void adma_port_stop(struct ata_port *ap);
-static void adma_phy_reset(struct ata_port *ap);
static void adma_qc_prep(struct ata_queued_cmd *qc);
static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
static void adma_bmdma_stop(struct ata_queued_cmd *qc);
static u8 adma_bmdma_status(struct ata_port *ap);
static void adma_irq_clear(struct ata_port *ap);
-static void adma_eng_timeout(struct ata_port *ap);
+static void adma_freeze(struct ata_port *ap);
+static void adma_thaw(struct ata_port *ap);
+static void adma_error_handler(struct ata_port *ap);
static struct scsi_host_template adma_ata_sht = {
.module = THIS_MODULE,
@@ -159,21 +162,20 @@ static struct scsi_host_template adma_ata_sht = {
};
static const struct ata_port_operations adma_ata_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
.check_status = ata_check_status,
.dev_select = ata_std_dev_select,
- .phy_reset = adma_phy_reset,
.check_atapi_dma = adma_check_atapi_dma,
.data_xfer = ata_data_xfer,
.qc_prep = adma_qc_prep,
.qc_issue = adma_qc_issue,
- .eng_timeout = adma_eng_timeout,
+ .freeze = adma_freeze,
+ .thaw = adma_thaw,
+ .error_handler = adma_error_handler,
.irq_clear = adma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = adma_port_start,
.port_stop = adma_port_stop,
.host_stop = adma_host_stop,
@@ -184,7 +186,7 @@ static const struct ata_port_operations adma_ata_ops = {
static struct ata_port_info adma_port_info[] = {
/* board_1841_idx */
{
- .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
+ .flags = ATA_FLAG_SLAVE_POSS |
ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
ATA_FLAG_PIO_POLLING,
.pio_mask = 0x10, /* pio4 */
@@ -273,24 +275,42 @@ static inline void adma_enter_reg_mode(struct ata_port *ap)
readb(chan + ADMA_STATUS); /* flush */
}
-static void adma_phy_reset(struct ata_port *ap)
+static void adma_freeze(struct ata_port *ap)
{
- struct adma_port_priv *pp = ap->private_data;
+ void __iomem *chan = ADMA_PORT_REGS(ap);
+
+ /* mask/clear ATA interrupts */
+ writeb(ATA_NIEN, ap->ioaddr.ctl_addr);
+ ata_check_status(ap);
- pp->state = adma_state_idle;
+ /* reset ADMA to idle state */
+ writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
+ udelay(2);
+ writew(aPIOMD4 | aNIEN, chan + ADMA_CONTROL);
+ udelay(2);
+}
+
+static void adma_thaw(struct ata_port *ap)
+{
adma_reinit_engine(ap);
- ata_port_probe(ap);
- ata_bus_reset(ap);
}
-static void adma_eng_timeout(struct ata_port *ap)
+static int adma_prereset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct adma_port_priv *pp = ap->private_data;
if (pp->state != adma_state_idle) /* healthy paranoia */
pp->state = adma_state_mmio;
adma_reinit_engine(ap);
- ata_eng_timeout(ap);
+
+ return ata_std_prereset(link, deadline);
+}
+
+static void adma_error_handler(struct ata_port *ap)
+{
+ ata_do_eh(ap, adma_prereset, ata_std_softreset, NULL,
+ ata_std_postreset);
}
static int adma_fill_sg(struct ata_queued_cmd *qc)
@@ -298,7 +318,7 @@ static int adma_fill_sg(struct ata_queued_cmd *qc)
struct scatterlist *sg;
struct ata_port *ap = qc->ap;
struct adma_port_priv *pp = ap->private_data;
- u8 *buf = pp->pkt;
+ u8 *buf = pp->pkt, *last_buf = NULL;
int i = (2 + buf[3]) * 8;
u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0);
@@ -314,20 +334,23 @@ static int adma_fill_sg(struct ata_queued_cmd *qc)
*(__le32 *)(buf + i) = cpu_to_le32(len);
i += 4;
- if (ata_sg_is_last(sg, qc))
- pFLAGS |= pEND;
+ last_buf = &buf[i];
buf[i++] = pFLAGS;
buf[i++] = qc->dev->dma_mode & 0xf;
buf[i++] = 0; /* pPKLW */
buf[i++] = 0; /* reserved */
- *(__le32 *)(buf + i)
- = (pFLAGS & pEND) ? 0 : cpu_to_le32(pp->pkt_dma + i + 4);
+ *(__le32 *)(buf + i) =
+ (pFLAGS & pEND) ? 0 : cpu_to_le32(pp->pkt_dma + i + 4);
i += 4;
VPRINTK("PRD[%u] = (0x%lX, 0x%X)\n", i/4,
(unsigned long)addr, len);
}
+
+ if (likely(last_buf))
+ *last_buf |= pEND;
+
return i;
}
@@ -464,14 +487,33 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host)
pp = ap->private_data;
if (!pp || pp->state != adma_state_pkt)
continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
- if ((status & (aPERR | aPSD | aUIRQ)))
+ if (status & aPERR)
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ else if ((status & (aPSD | aUIRQ)))
qc->err_mask |= AC_ERR_OTHER;
+
+ if (pp->pkt[0] & cATERR)
+ qc->err_mask |= AC_ERR_DEV;
else if (pp->pkt[0] != cDONE)
qc->err_mask |= AC_ERR_OTHER;
- ata_qc_complete(qc);
+ if (!qc->err_mask)
+ ata_qc_complete(qc);
+ else {
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi,
+ "ADMA-status 0x%02X", status);
+ ata_ehi_push_desc(ehi,
+ "pkt[0] 0x%02X", pp->pkt[0]);
+
+ if (qc->err_mask == AC_ERR_DEV)
+ ata_port_abort(ap);
+ else
+ ata_port_freeze(ap);
+ }
}
}
return handled;
@@ -489,7 +531,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host)
struct adma_port_priv *pp = ap->private_data;
if (!pp || pp->state != adma_state_mmio)
continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
/* check main status, clearing INTRQ */
@@ -502,7 +544,20 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host)
/* complete taskfile transaction */
pp->state = adma_state_idle;
qc->err_mask |= ac_err_mask(status);
- ata_qc_complete(qc);
+ if (!qc->err_mask)
+ ata_qc_complete(qc);
+ else {
+ struct ata_eh_info *ehi =
+ &ap->link.eh_info;
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi,
+ "status 0x%02X", status);
+
+ if (qc->err_mask == AC_ERR_DEV)
+ ata_port_abort(ap);
+ else
+ ata_port_freeze(ap);
+ }
handled = 1;
}
}
@@ -562,7 +617,7 @@ static int adma_port_start(struct ata_port *ap)
return -ENOMEM;
/* paranoia? */
if ((pp->pkt_dma & 7) != 0) {
- printk("bad alignment for pp->pkt_dma: %08x\n",
+ printk(KERN_ERR "bad alignment for pp->pkt_dma: %08x\n",
(u32)pp->pkt_dma);
return -ENOMEM;
}
@@ -652,9 +707,16 @@ static int adma_ata_init_one(struct pci_dev *pdev,
if (rc)
return rc;
- for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
- adma_ata_setup_port(&host->ports[port_no]->ioaddr,
- ADMA_ATA_REGS(mmio_base, port_no));
+ for (port_no = 0; port_no < ADMA_PORTS; ++port_no) {
+ struct ata_port *ap = host->ports[port_no];
+ void __iomem *port_base = ADMA_ATA_REGS(mmio_base, port_no);
+ unsigned int offset = port_base - mmio_base;
+
+ adma_ata_setup_port(&ap->ioaddr, port_base);
+
+ ata_port_pbar_desc(ap, ADMA_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, ADMA_MMIO_BAR, offset, "port");
+ }
/* initialize adapter */
adma_host_init(host, board_idx);
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
new file mode 100644
index 00000000000..d015b4adcfe
--- /dev/null
+++ b/drivers/ata/sata_fsl.c
@@ -0,0 +1,1395 @@
+/*
+ * drivers/ata/sata_fsl.c
+ *
+ * Freescale 3.0Gbps SATA device driver
+ *
+ * Author: Ashish Kalra <ashish.kalra@freescale.com>
+ * Li Yang <leoli@freescale.com>
+ *
+ * Copyright (c) 2006-2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+#include <linux/of_platform.h>
+
+/* Controller information */
+enum {
+ SATA_FSL_QUEUE_DEPTH = 16,
+ SATA_FSL_MAX_PRD = 63,
+ SATA_FSL_MAX_PRD_USABLE = SATA_FSL_MAX_PRD - 1,
+ SATA_FSL_MAX_PRD_DIRECT = 16, /* Direct PRDT entries */
+
+ SATA_FSL_HOST_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_NCQ),
+ SATA_FSL_HOST_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY,
+
+ SATA_FSL_MAX_CMDS = SATA_FSL_QUEUE_DEPTH,
+ SATA_FSL_CMD_HDR_SIZE = 16, /* 4 DWORDS */
+ SATA_FSL_CMD_SLOT_SIZE = (SATA_FSL_MAX_CMDS * SATA_FSL_CMD_HDR_SIZE),
+
+ /*
+ * SATA-FSL host controller supports a max. of (15+1) direct PRDEs, and
+ * chained indirect PRDEs upto a max count of 63.
+ * We are allocating an array of 63 PRDEs contigiously, but PRDE#15 will
+ * be setup as an indirect descriptor, pointing to it's next
+ * (contigious) PRDE. Though chained indirect PRDE arrays are
+ * supported,it will be more efficient to use a direct PRDT and
+ * a single chain/link to indirect PRDE array/PRDT.
+ */
+
+ SATA_FSL_CMD_DESC_CFIS_SZ = 32,
+ SATA_FSL_CMD_DESC_SFIS_SZ = 32,
+ SATA_FSL_CMD_DESC_ACMD_SZ = 16,
+ SATA_FSL_CMD_DESC_RSRVD = 16,
+
+ SATA_FSL_CMD_DESC_SIZE = (SATA_FSL_CMD_DESC_CFIS_SZ +
+ SATA_FSL_CMD_DESC_SFIS_SZ +
+ SATA_FSL_CMD_DESC_ACMD_SZ +
+ SATA_FSL_CMD_DESC_RSRVD +
+ SATA_FSL_MAX_PRD * 16),
+
+ SATA_FSL_CMD_DESC_OFFSET_TO_PRDT =
+ (SATA_FSL_CMD_DESC_CFIS_SZ +
+ SATA_FSL_CMD_DESC_SFIS_SZ +
+ SATA_FSL_CMD_DESC_ACMD_SZ +
+ SATA_FSL_CMD_DESC_RSRVD),
+
+ SATA_FSL_CMD_DESC_AR_SZ = (SATA_FSL_CMD_DESC_SIZE * SATA_FSL_MAX_CMDS),
+ SATA_FSL_PORT_PRIV_DMA_SZ = (SATA_FSL_CMD_SLOT_SIZE +
+ SATA_FSL_CMD_DESC_AR_SZ),
+
+ /*
+ * MPC8315 has two SATA controllers, SATA1 & SATA2
+ * (one port per controller)
+ * MPC837x has 2/4 controllers, one port per controller
+ */
+
+ SATA_FSL_MAX_PORTS = 1,
+
+ SATA_FSL_IRQ_FLAG = IRQF_SHARED,
+};
+
+/*
+* Host Controller command register set - per port
+*/
+enum {
+ CQ = 0,
+ CA = 8,
+ CC = 0x10,
+ CE = 0x18,
+ DE = 0x20,
+ CHBA = 0x24,
+ HSTATUS = 0x28,
+ HCONTROL = 0x2C,
+ CQPMP = 0x30,
+ SIGNATURE = 0x34,
+ ICC = 0x38,
+
+ /*
+ * Host Status Register (HStatus) bitdefs
+ */
+ ONLINE = (1 << 31),
+ GOING_OFFLINE = (1 << 30),
+ BIST_ERR = (1 << 29),
+
+ FATAL_ERR_HC_MASTER_ERR = (1 << 18),
+ FATAL_ERR_PARITY_ERR_TX = (1 << 17),
+ FATAL_ERR_PARITY_ERR_RX = (1 << 16),
+ FATAL_ERR_DATA_UNDERRUN = (1 << 13),
+ FATAL_ERR_DATA_OVERRUN = (1 << 12),
+ FATAL_ERR_CRC_ERR_TX = (1 << 11),
+ FATAL_ERR_CRC_ERR_RX = (1 << 10),
+ FATAL_ERR_FIFO_OVRFL_TX = (1 << 9),
+ FATAL_ERR_FIFO_OVRFL_RX = (1 << 8),
+
+ FATAL_ERROR_DECODE = FATAL_ERR_HC_MASTER_ERR |
+ FATAL_ERR_PARITY_ERR_TX |
+ FATAL_ERR_PARITY_ERR_RX |
+ FATAL_ERR_DATA_UNDERRUN |
+ FATAL_ERR_DATA_OVERRUN |
+ FATAL_ERR_CRC_ERR_TX |
+ FATAL_ERR_CRC_ERR_RX |
+ FATAL_ERR_FIFO_OVRFL_TX | FATAL_ERR_FIFO_OVRFL_RX,
+
+ INT_ON_FATAL_ERR = (1 << 5),
+ INT_ON_PHYRDY_CHG = (1 << 4),
+
+ INT_ON_SIGNATURE_UPDATE = (1 << 3),
+ INT_ON_SNOTIFY_UPDATE = (1 << 2),
+ INT_ON_SINGL_DEVICE_ERR = (1 << 1),
+ INT_ON_CMD_COMPLETE = 1,
+
+ INT_ON_ERROR = INT_ON_FATAL_ERR |
+ INT_ON_PHYRDY_CHG | INT_ON_SINGL_DEVICE_ERR,
+
+ /*
+ * Host Control Register (HControl) bitdefs
+ */
+ HCONTROL_ONLINE_PHY_RST = (1 << 31),
+ HCONTROL_FORCE_OFFLINE = (1 << 30),
+ HCONTROL_PARITY_PROT_MOD = (1 << 14),
+ HCONTROL_DPATH_PARITY = (1 << 12),
+ HCONTROL_SNOOP_ENABLE = (1 << 10),
+ HCONTROL_PMP_ATTACHED = (1 << 9),
+ HCONTROL_COPYOUT_STATFIS = (1 << 8),
+ IE_ON_FATAL_ERR = (1 << 5),
+ IE_ON_PHYRDY_CHG = (1 << 4),
+ IE_ON_SIGNATURE_UPDATE = (1 << 3),
+ IE_ON_SNOTIFY_UPDATE = (1 << 2),
+ IE_ON_SINGL_DEVICE_ERR = (1 << 1),
+ IE_ON_CMD_COMPLETE = 1,
+
+ DEFAULT_PORT_IRQ_ENABLE_MASK = IE_ON_FATAL_ERR | IE_ON_PHYRDY_CHG |
+ IE_ON_SIGNATURE_UPDATE |
+ IE_ON_SINGL_DEVICE_ERR | IE_ON_CMD_COMPLETE,
+
+ EXT_INDIRECT_SEG_PRD_FLAG = (1 << 31),
+ DATA_SNOOP_ENABLE = (1 << 22),
+};
+
+/*
+ * SATA Superset Registers
+ */
+enum {
+ SSTATUS = 0,
+ SERROR = 4,
+ SCONTROL = 8,
+ SNOTIFY = 0xC,
+};
+
+/*
+ * Control Status Register Set
+ */
+enum {
+ TRANSCFG = 0,
+ TRANSSTATUS = 4,
+ LINKCFG = 8,
+ LINKCFG1 = 0xC,
+ LINKCFG2 = 0x10,
+ LINKSTATUS = 0x14,
+ LINKSTATUS1 = 0x18,
+ PHYCTRLCFG = 0x1C,
+ COMMANDSTAT = 0x20,
+};
+
+/* PHY (link-layer) configuration control */
+enum {
+ PHY_BIST_ENABLE = 0x01,
+};
+
+/*
+ * Command Header Table entry, i.e, command slot
+ * 4 Dwords per command slot, command header size == 64 Dwords.
+ */
+struct cmdhdr_tbl_entry {
+ u32 cda;
+ u32 prde_fis_len;
+ u32 ttl;
+ u32 desc_info;
+};
+
+/*
+ * Description information bitdefs
+ */
+enum {
+ VENDOR_SPECIFIC_BIST = (1 << 10),
+ CMD_DESC_SNOOP_ENABLE = (1 << 9),
+ FPDMA_QUEUED_CMD = (1 << 8),
+ SRST_CMD = (1 << 7),
+ BIST = (1 << 6),
+ ATAPI_CMD = (1 << 5),
+};
+
+/*
+ * Command Descriptor
+ */
+struct command_desc {
+ u8 cfis[8 * 4];
+ u8 sfis[8 * 4];
+ u8 acmd[4 * 4];
+ u8 fill[4 * 4];
+ u32 prdt[SATA_FSL_MAX_PRD_DIRECT * 4];
+ u32 prdt_indirect[(SATA_FSL_MAX_PRD - SATA_FSL_MAX_PRD_DIRECT) * 4];
+};
+
+/*
+ * Physical region table descriptor(PRD)
+ */
+
+struct prde {
+ u32 dba;
+ u8 fill[2 * 4];
+ u32 ddc_and_ext;
+};
+
+/*
+ * ata_port private data
+ * This is our per-port instance data.
+ */
+struct sata_fsl_port_priv {
+ struct cmdhdr_tbl_entry *cmdslot;
+ dma_addr_t cmdslot_paddr;
+ struct command_desc *cmdentry;
+ dma_addr_t cmdentry_paddr;
+
+ /*
+ * SATA FSL controller has a Status FIS which should contain the
+ * received D2H FIS & taskfile registers. This SFIS is present in
+ * the command descriptor, and to have a ready reference to it,
+ * we are caching it here, quite similar to what is done in H/W on
+ * AHCI compliant devices by copying taskfile fields to a 32-bit
+ * register.
+ */
+
+ struct ata_taskfile tf;
+};
+
+/*
+ * ata_port->host_set private data
+ */
+struct sata_fsl_host_priv {
+ void __iomem *hcr_base;
+ void __iomem *ssr_base;
+ void __iomem *csr_base;
+ int irq;
+};
+
+static inline unsigned int sata_fsl_tag(unsigned int tag,
+ void __iomem *hcr_base)
+{
+ /* We let libATA core do actual (queue) tag allocation */
+
+ /* all non NCQ/queued commands should have tag#0 */
+ if (ata_tag_internal(tag)) {
+ DPRINTK("mapping internal cmds to tag#0\n");
+ return 0;
+ }
+
+ if (unlikely(tag >= SATA_FSL_QUEUE_DEPTH)) {
+ DPRINTK("tag %d invalid : out of range\n", tag);
+ return 0;
+ }
+
+ if (unlikely((ioread32(hcr_base + CQ)) & (1 << tag))) {
+ DPRINTK("tag %d invalid : in use!!\n", tag);
+ return 0;
+ }
+
+ return tag;
+}
+
+static void sata_fsl_setup_cmd_hdr_entry(struct sata_fsl_port_priv *pp,
+ unsigned int tag, u32 desc_info,
+ u32 data_xfer_len, u8 num_prde,
+ u8 fis_len)
+{
+ dma_addr_t cmd_descriptor_address;
+
+ cmd_descriptor_address = pp->cmdentry_paddr +
+ tag * SATA_FSL_CMD_DESC_SIZE;
+
+ /* NOTE: both data_xfer_len & fis_len are Dword counts */
+
+ pp->cmdslot[tag].cda = cpu_to_le32(cmd_descriptor_address);
+ pp->cmdslot[tag].prde_fis_len =
+ cpu_to_le32((num_prde << 16) | (fis_len << 2));
+ pp->cmdslot[tag].ttl = cpu_to_le32(data_xfer_len & ~0x03);
+ pp->cmdslot[tag].desc_info = cpu_to_le32(desc_info | (tag & 0x1F));
+
+ VPRINTK("cda=0x%x, prde_fis_len=0x%x, ttl=0x%x, di=0x%x\n",
+ pp->cmdslot[tag].cda,
+ pp->cmdslot[tag].prde_fis_len,
+ pp->cmdslot[tag].ttl, pp->cmdslot[tag].desc_info);
+
+}
+
+static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc,
+ u32 *ttl, dma_addr_t cmd_desc_paddr)
+{
+ struct scatterlist *sg;
+ unsigned int num_prde = 0;
+ u32 ttl_dwords = 0;
+
+ /*
+ * NOTE : direct & indirect prdt's are contigiously allocated
+ */
+ struct prde *prd = (struct prde *)&((struct command_desc *)
+ cmd_desc)->prdt;
+
+ struct prde *prd_ptr_to_indirect_ext = NULL;
+ unsigned indirect_ext_segment_sz = 0;
+ dma_addr_t indirect_ext_segment_paddr;
+
+ VPRINTK("SATA FSL : cd = 0x%x, prd = 0x%x\n", cmd_desc, prd);
+
+ indirect_ext_segment_paddr = cmd_desc_paddr +
+ SATA_FSL_CMD_DESC_OFFSET_TO_PRDT + SATA_FSL_MAX_PRD_DIRECT * 16;
+
+ ata_for_each_sg(sg, qc) {
+ dma_addr_t sg_addr = sg_dma_address(sg);
+ u32 sg_len = sg_dma_len(sg);
+
+ VPRINTK("SATA FSL : fill_sg, sg_addr = 0x%x, sg_len = %d\n",
+ sg_addr, sg_len);
+
+ /* warn if each s/g element is not dword aligned */
+ if (sg_addr & 0x03)
+ ata_port_printk(qc->ap, KERN_ERR,
+ "s/g addr unaligned : 0x%x\n", sg_addr);
+ if (sg_len & 0x03)
+ ata_port_printk(qc->ap, KERN_ERR,
+ "s/g len unaligned : 0x%x\n", sg_len);
+
+ if ((num_prde == (SATA_FSL_MAX_PRD_DIRECT - 1)) &&
+ (qc->n_iter + 1 != qc->n_elem)) {
+ VPRINTK("setting indirect prde\n");
+ prd_ptr_to_indirect_ext = prd;
+ prd->dba = cpu_to_le32(indirect_ext_segment_paddr);
+ indirect_ext_segment_sz = 0;
+ ++prd;
+ ++num_prde;
+ }
+
+ ttl_dwords += sg_len;
+ prd->dba = cpu_to_le32(sg_addr);
+ prd->ddc_and_ext =
+ cpu_to_le32(DATA_SNOOP_ENABLE | (sg_len & ~0x03));
+
+ VPRINTK("sg_fill, ttl=%d, dba=0x%x, ddc=0x%x\n",
+ ttl_dwords, prd->dba, prd->ddc_and_ext);
+
+ ++num_prde;
+ ++prd;
+ if (prd_ptr_to_indirect_ext)
+ indirect_ext_segment_sz += sg_len;
+ }
+
+ if (prd_ptr_to_indirect_ext) {
+ /* set indirect extension flag along with indirect ext. size */
+ prd_ptr_to_indirect_ext->ddc_and_ext =
+ cpu_to_le32((EXT_INDIRECT_SEG_PRD_FLAG |
+ DATA_SNOOP_ENABLE |
+ (indirect_ext_segment_sz & ~0x03)));
+ }
+
+ *ttl = ttl_dwords;
+ return num_prde;
+}
+
+static void sata_fsl_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct sata_fsl_port_priv *pp = ap->private_data;
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ unsigned int tag = sata_fsl_tag(qc->tag, hcr_base);
+ struct command_desc *cd;
+ u32 desc_info = CMD_DESC_SNOOP_ENABLE;
+ u32 num_prde = 0;
+ u32 ttl_dwords = 0;
+ dma_addr_t cd_paddr;
+
+ cd = (struct command_desc *)pp->cmdentry + tag;
+ cd_paddr = pp->cmdentry_paddr + tag * SATA_FSL_CMD_DESC_SIZE;
+
+ ata_tf_to_fis(&qc->tf, 0, 1, (u8 *) &cd->cfis);
+
+ VPRINTK("Dumping cfis : 0x%x, 0x%x, 0x%x\n",
+ cd->cfis[0], cd->cfis[1], cd->cfis[2]);
+
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
+ VPRINTK("FPDMA xfer,Sctor cnt[0:7],[8:15] = %d,%d\n",
+ cd->cfis[3], cd->cfis[11]);
+ }
+
+ /* setup "ACMD - atapi command" in cmd. desc. if this is ATAPI cmd */
+ if (is_atapi_taskfile(&qc->tf)) {
+ desc_info |= ATAPI_CMD;
+ memset((void *)&cd->acmd, 0, 32);
+ memcpy((void *)&cd->acmd, qc->cdb, qc->dev->cdb_len);
+ }
+
+ if (qc->flags & ATA_QCFLAG_DMAMAP)
+ num_prde = sata_fsl_fill_sg(qc, (void *)cd,
+ &ttl_dwords, cd_paddr);
+
+ if (qc->tf.protocol == ATA_PROT_NCQ)
+ desc_info |= FPDMA_QUEUED_CMD;
+
+ sata_fsl_setup_cmd_hdr_entry(pp, tag, desc_info, ttl_dwords,
+ num_prde, 5);
+
+ VPRINTK("SATA FSL : xx_qc_prep, di = 0x%x, ttl = %d, num_prde = %d\n",
+ desc_info, ttl_dwords, num_prde);
+}
+
+static unsigned int sata_fsl_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ unsigned int tag = sata_fsl_tag(qc->tag, hcr_base);
+
+ VPRINTK("xx_qc_issue called,CQ=0x%x,CA=0x%x,CE=0x%x,CC=0x%x\n",
+ ioread32(CQ + hcr_base),
+ ioread32(CA + hcr_base),
+ ioread32(CE + hcr_base), ioread32(CC + hcr_base));
+
+ /* Simply queue command to the controller/device */
+ iowrite32(1 << tag, CQ + hcr_base);
+
+ VPRINTK("xx_qc_issue called, tag=%d, CQ=0x%x, CA=0x%x\n",
+ tag, ioread32(CQ + hcr_base), ioread32(CA + hcr_base));
+
+ VPRINTK("CE=0x%x, DE=0x%x, CC=0x%x, CmdStat = 0x%x\n",
+ ioread32(CE + hcr_base),
+ ioread32(DE + hcr_base),
+ ioread32(CC + hcr_base), ioread32(COMMANDSTAT + csr_base));
+
+ return 0;
+}
+
+static int sata_fsl_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
+ u32 val)
+{
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *ssr_base = host_priv->ssr_base;
+ unsigned int sc_reg;
+
+ switch (sc_reg_in) {
+ case SCR_STATUS:
+ case SCR_ERROR:
+ case SCR_CONTROL:
+ case SCR_ACTIVE:
+ sc_reg = sc_reg_in;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ VPRINTK("xx_scr_write, reg_in = %d\n", sc_reg);
+
+ iowrite32(val, ssr_base + (sc_reg * 4));
+ return 0;
+}
+
+static int sata_fsl_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
+ u32 *val)
+{
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *ssr_base = host_priv->ssr_base;
+ unsigned int sc_reg;
+
+ switch (sc_reg_in) {
+ case SCR_STATUS:
+ case SCR_ERROR:
+ case SCR_CONTROL:
+ case SCR_ACTIVE:
+ sc_reg = sc_reg_in;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ VPRINTK("xx_scr_read, reg_in = %d\n", sc_reg);
+
+ *val = ioread32(ssr_base + (sc_reg * 4));
+ return 0;
+}
+
+static void sata_fsl_freeze(struct ata_port *ap)
+{
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 temp;
+
+ VPRINTK("xx_freeze, CQ=0x%x, CA=0x%x, CE=0x%x, DE=0x%x\n",
+ ioread32(CQ + hcr_base),
+ ioread32(CA + hcr_base),
+ ioread32(CE + hcr_base), ioread32(DE + hcr_base));
+ VPRINTK("CmdStat = 0x%x\n", ioread32(csr_base + COMMANDSTAT));
+
+ /* disable interrupts on the controller/port */
+ temp = ioread32(hcr_base + HCONTROL);
+ iowrite32((temp & ~0x3F), hcr_base + HCONTROL);
+
+ VPRINTK("in xx_freeze : HControl = 0x%x, HStatus = 0x%x\n",
+ ioread32(hcr_base + HCONTROL), ioread32(hcr_base + HSTATUS));
+}
+
+static void sata_fsl_thaw(struct ata_port *ap)
+{
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 temp;
+
+ /* ack. any pending IRQs for this controller/port */
+ temp = ioread32(hcr_base + HSTATUS);
+
+ VPRINTK("xx_thaw, pending IRQs = 0x%x\n", (temp & 0x3F));
+
+ if (temp & 0x3F)
+ iowrite32((temp & 0x3F), hcr_base + HSTATUS);
+
+ /* enable interrupts on the controller/port */
+ temp = ioread32(hcr_base + HCONTROL);
+ iowrite32((temp | DEFAULT_PORT_IRQ_ENABLE_MASK), hcr_base + HCONTROL);
+
+ VPRINTK("xx_thaw : HControl = 0x%x, HStatus = 0x%x\n",
+ ioread32(hcr_base + HCONTROL), ioread32(hcr_base + HSTATUS));
+}
+
+/*
+ * NOTE : 1st D2H FIS from device does not update sfis in command descriptor.
+ */
+static inline void sata_fsl_cache_taskfile_from_d2h_fis(struct ata_queued_cmd
+ *qc,
+ struct ata_port *ap)
+{
+ struct sata_fsl_port_priv *pp = ap->private_data;
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ unsigned int tag = sata_fsl_tag(qc->tag, hcr_base);
+ struct command_desc *cd;
+
+ cd = pp->cmdentry + tag;
+
+ ata_tf_from_fis(cd->sfis, &pp->tf);
+}
+
+static u8 sata_fsl_check_status(struct ata_port *ap)
+{
+ struct sata_fsl_port_priv *pp = ap->private_data;
+
+ return pp->tf.command;
+}
+
+static void sata_fsl_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct sata_fsl_port_priv *pp = ap->private_data;
+
+ *tf = pp->tf;
+}
+
+static int sata_fsl_port_start(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct sata_fsl_port_priv *pp;
+ int retval;
+ void *mem;
+ dma_addr_t mem_dma;
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 temp;
+
+ pp = kzalloc(sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+
+ /*
+ * allocate per command dma alignment pad buffer, which is used
+ * internally by libATA to ensure that all transfers ending on
+ * unaligned boundaries are padded, to align on Dword boundaries
+ */
+ retval = ata_pad_alloc(ap, dev);
+ if (retval) {
+ kfree(pp);
+ return retval;
+ }
+
+ mem = dma_alloc_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ, &mem_dma,
+ GFP_KERNEL);
+ if (!mem) {
+ ata_pad_free(ap, dev);
+ kfree(pp);
+ return -ENOMEM;
+ }
+ memset(mem, 0, SATA_FSL_PORT_PRIV_DMA_SZ);
+
+ pp->cmdslot = mem;
+ pp->cmdslot_paddr = mem_dma;
+
+ mem += SATA_FSL_CMD_SLOT_SIZE;
+ mem_dma += SATA_FSL_CMD_SLOT_SIZE;
+
+ pp->cmdentry = mem;
+ pp->cmdentry_paddr = mem_dma;
+
+ ap->private_data = pp;
+
+ VPRINTK("CHBA = 0x%x, cmdentry_phys = 0x%x\n",
+ pp->cmdslot_paddr, pp->cmdentry_paddr);
+
+ /* Now, update the CHBA register in host controller cmd register set */
+ iowrite32(pp->cmdslot_paddr & 0xffffffff, hcr_base + CHBA);
+
+ /*
+ * Now, we can bring the controller on-line & also initiate
+ * the COMINIT sequence, we simply return here and the boot-probing
+ * & device discovery process is re-initiated by libATA using a
+ * Softreset EH (dummy) session. Hence, boot probing and device
+ * discovey will be part of sata_fsl_softreset() callback.
+ */
+
+ temp = ioread32(hcr_base + HCONTROL);
+ iowrite32((temp | HCONTROL_ONLINE_PHY_RST), hcr_base + HCONTROL);
+
+ VPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
+ VPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
+ VPRINTK("CHBA = 0x%x\n", ioread32(hcr_base + CHBA));
+
+#ifdef CONFIG_MPC8315_DS
+ /*
+ * Workaround for 8315DS board 3gbps link-up issue,
+ * currently limit SATA port to GEN1 speed
+ */
+ sata_fsl_scr_read(ap, SCR_CONTROL, &temp);
+ temp &= ~(0xF << 4);
+ temp |= (0x1 << 4);
+ sata_fsl_scr_write(ap, SCR_CONTROL, temp);
+
+ sata_fsl_scr_read(ap, SCR_CONTROL, &temp);
+ dev_printk(KERN_WARNING, dev, "scr_control, speed limited to %x\n",
+ temp);
+#endif
+
+ return 0;
+}
+
+static void sata_fsl_port_stop(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct sata_fsl_port_priv *pp = ap->private_data;
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 temp;
+
+ /*
+ * Force host controller to go off-line, aborting current operations
+ */
+ temp = ioread32(hcr_base + HCONTROL);
+ temp &= ~HCONTROL_ONLINE_PHY_RST;
+ temp |= HCONTROL_FORCE_OFFLINE;
+ iowrite32(temp, hcr_base + HCONTROL);
+
+ /* Poll for controller to go offline - should happen immediately */
+ ata_wait_register(hcr_base + HSTATUS, ONLINE, ONLINE, 1, 1);
+
+ ap->private_data = NULL;
+ dma_free_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ,
+ pp->cmdslot, pp->cmdslot_paddr);
+
+ ata_pad_free(ap, dev);
+ kfree(pp);
+}
+
+static unsigned int sata_fsl_dev_classify(struct ata_port *ap)
+{
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ struct ata_taskfile tf;
+ u32 temp;
+
+ temp = ioread32(hcr_base + SIGNATURE);
+
+ VPRINTK("raw sig = 0x%x\n", temp);
+ VPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
+ VPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
+
+ tf.lbah = (temp >> 24) & 0xff;
+ tf.lbam = (temp >> 16) & 0xff;
+ tf.lbal = (temp >> 8) & 0xff;
+ tf.nsect = temp & 0xff;
+
+ return ata_dev_classify(&tf);
+}
+
+static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct sata_fsl_port_priv *pp = ap->private_data;
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 temp;
+ struct ata_taskfile tf;
+ u8 *cfis;
+ u32 Serror;
+ int i = 0;
+ unsigned long start_jiffies;
+
+ DPRINTK("in xx_softreset\n");
+
+try_offline_again:
+ /*
+ * Force host controller to go off-line, aborting current operations
+ */
+ temp = ioread32(hcr_base + HCONTROL);
+ temp &= ~HCONTROL_ONLINE_PHY_RST;
+ iowrite32(temp, hcr_base + HCONTROL);
+
+ /* Poll for controller to go offline */
+ temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, ONLINE, 1, 500);
+
+ if (temp & ONLINE) {
+ ata_port_printk(ap, KERN_ERR,
+ "Softreset failed, not off-lined %d\n", i);
+
+ /*
+ * Try to offline controller atleast twice
+ */
+ i++;
+ if (i == 2)
+ goto err;
+ else
+ goto try_offline_again;
+ }
+
+ DPRINTK("softreset, controller off-lined\n");
+ VPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
+ VPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
+
+ /*
+ * PHY reset should remain asserted for atleast 1ms
+ */
+ msleep(1);
+
+ /*
+ * Now, bring the host controller online again, this can take time
+ * as PHY reset and communication establishment, 1st D2H FIS and
+ * device signature update is done, on safe side assume 500ms
+ * NOTE : Host online status may be indicated immediately!!
+ */
+
+ temp = ioread32(hcr_base + HCONTROL);
+ temp |= (HCONTROL_ONLINE_PHY_RST | HCONTROL_SNOOP_ENABLE);
+ iowrite32(temp, hcr_base + HCONTROL);
+
+ temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, 0, 1, 500);
+
+ if (!(temp & ONLINE)) {
+ ata_port_printk(ap, KERN_ERR,
+ "Softreset failed, not on-lined\n");
+ goto err;
+ }
+
+ DPRINTK("softreset, controller off-lined & on-lined\n");
+ VPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
+ VPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
+
+ /*
+ * First, wait for the PHYRDY change to occur before waiting for
+ * the signature, and also verify if SStatus indicates device
+ * presence
+ */
+
+ temp = ata_wait_register(hcr_base + HSTATUS, 0xFF, 0, 1, 500);
+ if ((!(temp & 0x10)) || ata_link_offline(link)) {
+ ata_port_printk(ap, KERN_WARNING,
+ "No Device OR PHYRDY change,Hstatus = 0x%x\n",
+ ioread32(hcr_base + HSTATUS));
+ goto err;
+ }
+
+ /*
+ * Wait for the first D2H from device,i.e,signature update notification
+ */
+ start_jiffies = jiffies;
+ temp = ata_wait_register(hcr_base + HSTATUS, 0xFF, 0x10,
+ 500, jiffies_to_msecs(deadline - start_jiffies));
+
+ if ((temp & 0xFF) != 0x18) {
+ ata_port_printk(ap, KERN_WARNING, "No Signature Update\n");
+ goto err;
+ } else {
+ ata_port_printk(ap, KERN_INFO,
+ "Signature Update detected @ %d msecs\n",
+ jiffies_to_msecs(jiffies - start_jiffies));
+ }
+
+ /*
+ * Send a device reset (SRST) explicitly on command slot #0
+ * Check : will the command queue (reg) be cleared during offlining ??
+ * Also we will be online only if Phy commn. has been established
+ * and device presence has been detected, therefore if we have
+ * reached here, we can send a command to the target device
+ */
+
+ DPRINTK("Sending SRST/device reset\n");
+
+ ata_tf_init(link->device, &tf);
+ cfis = (u8 *) &pp->cmdentry->cfis;
+
+ /* device reset/SRST is a control register update FIS, uses tag0 */
+ sata_fsl_setup_cmd_hdr_entry(pp, 0,
+ SRST_CMD | CMD_DESC_SNOOP_ENABLE, 0, 0, 5);
+
+ tf.ctl |= ATA_SRST; /* setup SRST bit in taskfile control reg */
+ ata_tf_to_fis(&tf, 0, 0, cfis);
+
+ DPRINTK("Dumping cfis : 0x%x, 0x%x, 0x%x, 0x%x\n",
+ cfis[0], cfis[1], cfis[2], cfis[3]);
+
+ /*
+ * Queue SRST command to the controller/device, ensure that no
+ * other commands are active on the controller/device
+ */
+
+ DPRINTK("@Softreset, CQ = 0x%x, CA = 0x%x, CC = 0x%x\n",
+ ioread32(CQ + hcr_base),
+ ioread32(CA + hcr_base), ioread32(CC + hcr_base));
+
+ iowrite32(0xFFFF, CC + hcr_base);
+ iowrite32(1, CQ + hcr_base);
+
+ temp = ata_wait_register(CQ + hcr_base, 0x1, 0x1, 1, 5000);
+ if (temp & 0x1) {
+ ata_port_printk(ap, KERN_WARNING, "ATA_SRST issue failed\n");
+
+ DPRINTK("Softreset@5000,CQ=0x%x,CA=0x%x,CC=0x%x\n",
+ ioread32(CQ + hcr_base),
+ ioread32(CA + hcr_base), ioread32(CC + hcr_base));
+
+ sata_fsl_scr_read(ap, SCR_ERROR, &Serror);
+
+ DPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
+ DPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
+ DPRINTK("Serror = 0x%x\n", Serror);
+ goto err;
+ }
+
+ msleep(1);
+
+ /*
+ * SATA device enters reset state after receving a Control register
+ * FIS with SRST bit asserted and it awaits another H2D Control reg.
+ * FIS with SRST bit cleared, then the device does internal diags &
+ * initialization, followed by indicating it's initialization status
+ * using ATA signature D2H register FIS to the host controller.
+ */
+
+ sata_fsl_setup_cmd_hdr_entry(pp, 0, CMD_DESC_SNOOP_ENABLE, 0, 0, 5);
+
+ tf.ctl &= ~ATA_SRST; /* 2nd H2D Ctl. register FIS */
+ ata_tf_to_fis(&tf, 0, 0, cfis);
+
+ iowrite32(1, CQ + hcr_base);
+ msleep(150); /* ?? */
+
+ /*
+ * The above command would have signalled an interrupt on command
+ * complete, which needs special handling, by clearing the Nth
+ * command bit of the CCreg
+ */
+ iowrite32(0x01, CC + hcr_base); /* We know it will be cmd#0 always */
+
+ DPRINTK("SATA FSL : Now checking device signature\n");
+
+ *class = ATA_DEV_NONE;
+
+ /* Verify if SStatus indicates device presence */
+ if (ata_link_online(link)) {
+ /*
+ * if we are here, device presence has been detected,
+ * 1st D2H FIS would have been received, but sfis in
+ * command desc. is not updated, but signature register
+ * would have been updated
+ */
+
+ *class = sata_fsl_dev_classify(ap);
+
+ DPRINTK("class = %d\n", *class);
+ VPRINTK("ccreg = 0x%x\n", ioread32(hcr_base + CC));
+ VPRINTK("cereg = 0x%x\n", ioread32(hcr_base + CE));
+ }
+
+ return 0;
+
+err:
+ return -EIO;
+}
+
+static void sata_fsl_error_handler(struct ata_port *ap)
+{
+
+ DPRINTK("in xx_error_handler\n");
+
+ /* perform recovery */
+ ata_do_eh(ap, ata_std_prereset, sata_fsl_softreset, sata_std_hardreset,
+ ata_std_postreset);
+}
+
+static void sata_fsl_post_internal_cmd(struct ata_queued_cmd *qc)
+{
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ qc->err_mask |= AC_ERR_OTHER;
+
+ if (qc->err_mask) {
+ /* make DMA engine forget about the failed command */
+
+ }
+}
+
+static void sata_fsl_irq_clear(struct ata_port *ap)
+{
+ /* unused */
+}
+
+static void sata_fsl_error_intr(struct ata_port *ap)
+{
+ struct ata_link *link = &ap->link;
+ struct ata_eh_info *ehi = &link->eh_info;
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 hstatus, dereg, cereg = 0, SError = 0;
+ unsigned int err_mask = 0, action = 0;
+ struct ata_queued_cmd *qc;
+ int freeze = 0;
+
+ hstatus = ioread32(hcr_base + HSTATUS);
+ cereg = ioread32(hcr_base + CE);
+
+ ata_ehi_clear_desc(ehi);
+
+ /*
+ * Handle & Clear SError
+ */
+
+ sata_fsl_scr_read(ap, SCR_ERROR, &SError);
+ if (unlikely(SError & 0xFFFF0000)) {
+ sata_fsl_scr_write(ap, SCR_ERROR, SError);
+ err_mask |= AC_ERR_ATA_BUS;
+ }
+
+ DPRINTK("error_intr,hStat=0x%x,CE=0x%x,DE =0x%x,SErr=0x%x\n",
+ hstatus, cereg, ioread32(hcr_base + DE), SError);
+
+ /* handle single device errors */
+ if (cereg) {
+ /*
+ * clear the command error, also clears queue to the device
+ * in error, and we can (re)issue commands to this device.
+ * When a device is in error all commands queued into the
+ * host controller and at the device are considered aborted
+ * and the queue for that device is stopped. Now, after
+ * clearing the device error, we can issue commands to the
+ * device to interrogate it to find the source of the error.
+ */
+ dereg = ioread32(hcr_base + DE);
+ iowrite32(dereg, hcr_base + DE);
+ iowrite32(cereg, hcr_base + CE);
+
+ DPRINTK("single device error, CE=0x%x, DE=0x%x\n",
+ ioread32(hcr_base + CE), ioread32(hcr_base + DE));
+ /*
+ * We should consider this as non fatal error, and TF must
+ * be updated as done below.
+ */
+
+ err_mask |= AC_ERR_DEV;
+ }
+
+ /* handle fatal errors */
+ if (hstatus & FATAL_ERROR_DECODE) {
+ err_mask |= AC_ERR_ATA_BUS;
+ action |= ATA_EH_SOFTRESET;
+ /* how will fatal error interrupts be completed ?? */
+ freeze = 1;
+ }
+
+ /* Handle PHYRDY change notification */
+ if (hstatus & INT_ON_PHYRDY_CHG) {
+ DPRINTK("SATA FSL: PHYRDY change indication\n");
+
+ /* Setup a soft-reset EH action */
+ ata_ehi_hotplugged(ehi);
+ freeze = 1;
+ }
+
+ /* record error info */
+ qc = ata_qc_from_tag(ap, link->active_tag);
+
+ if (qc) {
+ sata_fsl_cache_taskfile_from_d2h_fis(qc, qc->ap);
+ qc->err_mask |= err_mask;
+ } else
+ ehi->err_mask |= err_mask;
+
+ ehi->action |= action;
+ ehi->serror |= SError;
+
+ /* freeze or abort */
+ if (freeze)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
+}
+
+static void sata_fsl_qc_complete(struct ata_queued_cmd *qc)
+{
+ if (qc->flags & ATA_QCFLAG_RESULT_TF) {
+ DPRINTK("xx_qc_complete called\n");
+ sata_fsl_cache_taskfile_from_d2h_fis(qc, qc->ap);
+ }
+}
+
+static void sata_fsl_host_intr(struct ata_port *ap)
+{
+ struct ata_link *link = &ap->link;
+ struct sata_fsl_host_priv *host_priv = ap->host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 hstatus, qc_active = 0;
+ struct ata_queued_cmd *qc;
+ u32 SError;
+
+ hstatus = ioread32(hcr_base + HSTATUS);
+
+ sata_fsl_scr_read(ap, SCR_ERROR, &SError);
+
+ if (unlikely(SError & 0xFFFF0000)) {
+ DPRINTK("serror @host_intr : 0x%x\n", SError);
+ sata_fsl_error_intr(ap);
+
+ }
+
+ if (unlikely(hstatus & INT_ON_ERROR)) {
+ DPRINTK("error interrupt!!\n");
+ sata_fsl_error_intr(ap);
+ return;
+ }
+
+ if (link->sactive) { /* only true for NCQ commands */
+ int i;
+ /* Read command completed register */
+ qc_active = ioread32(hcr_base + CC);
+ /* clear CC bit, this will also complete the interrupt */
+ iowrite32(qc_active, hcr_base + CC);
+
+ DPRINTK("Status of all queues :\n");
+ DPRINTK("qc_active/CC = 0x%x, CA = 0x%x, CE=0x%x\n",
+ qc_active, ioread32(hcr_base + CA),
+ ioread32(hcr_base + CE));
+
+ for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) {
+ if (qc_active & (1 << i)) {
+ qc = ata_qc_from_tag(ap, i);
+ if (qc) {
+ sata_fsl_qc_complete(qc);
+ ata_qc_complete(qc);
+ }
+ DPRINTK
+ ("completing ncq cmd,tag=%d,CC=0x%x,CA=0x%x\n",
+ i, ioread32(hcr_base + CC),
+ ioread32(hcr_base + CA));
+ }
+ }
+ return;
+
+ } else if (ap->qc_active) {
+ iowrite32(1, hcr_base + CC);
+ qc = ata_qc_from_tag(ap, link->active_tag);
+
+ DPRINTK("completing non-ncq cmd, tag=%d,CC=0x%x\n",
+ link->active_tag, ioread32(hcr_base + CC));
+
+ if (qc) {
+ sata_fsl_qc_complete(qc);
+ ata_qc_complete(qc);
+ }
+ } else {
+ /* Spurious Interrupt!! */
+ DPRINTK("spurious interrupt!!, CC = 0x%x\n",
+ ioread32(hcr_base + CC));
+ return;
+ }
+}
+
+static irqreturn_t sata_fsl_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ struct sata_fsl_host_priv *host_priv = host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 interrupt_enables;
+ unsigned handled = 0;
+ struct ata_port *ap;
+
+ /* ack. any pending IRQs for this controller/port */
+ interrupt_enables = ioread32(hcr_base + HSTATUS);
+ interrupt_enables &= 0x3F;
+
+ DPRINTK("interrupt status 0x%x\n", interrupt_enables);
+
+ if (!interrupt_enables)
+ return IRQ_NONE;
+
+ spin_lock(&host->lock);
+
+ /* Assuming one port per host controller */
+
+ ap = host->ports[0];
+ if (ap) {
+ sata_fsl_host_intr(ap);
+ } else {
+ dev_printk(KERN_WARNING, host->dev,
+ "interrupt on disabled port 0\n");
+ }
+
+ iowrite32(interrupt_enables, hcr_base + HSTATUS);
+ handled = 1;
+
+ spin_unlock(&host->lock);
+
+ return IRQ_RETVAL(handled);
+}
+
+/*
+ * Multiple ports are represented by multiple SATA controllers with
+ * one port per controller
+ */
+static int sata_fsl_init_controller(struct ata_host *host)
+{
+ struct sata_fsl_host_priv *host_priv = host->private_data;
+ void __iomem *hcr_base = host_priv->hcr_base;
+ u32 temp;
+
+ /*
+ * NOTE : We cannot bring the controller online before setting
+ * the CHBA, hence main controller initialization is done as
+ * part of the port_start() callback
+ */
+
+ /* ack. any pending IRQs for this controller/port */
+ temp = ioread32(hcr_base + HSTATUS);
+ if (temp & 0x3F)
+ iowrite32((temp & 0x3F), hcr_base + HSTATUS);
+
+ /* Keep interrupts disabled on the controller */
+ temp = ioread32(hcr_base + HCONTROL);
+ iowrite32((temp & ~0x3F), hcr_base + HCONTROL);
+
+ /* Disable interrupt coalescing control(icc), for the moment */
+ DPRINTK("icc = 0x%x\n", ioread32(hcr_base + ICC));
+ iowrite32(0x01000000, hcr_base + ICC);
+
+ /* clear error registers, SError is cleared by libATA */
+ iowrite32(0x00000FFFF, hcr_base + CE);
+ iowrite32(0x00000FFFF, hcr_base + DE);
+
+ /* initially assuming no Port multiplier, set CQPMP to 0 */
+ iowrite32(0x0, hcr_base + CQPMP);
+
+ /*
+ * host controller will be brought on-line, during xx_port_start()
+ * callback, that should also initiate the OOB, COMINIT sequence
+ */
+
+ DPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
+ DPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
+
+ return 0;
+}
+
+/*
+ * scsi mid-layer and libata interface structures
+ */
+static struct scsi_host_template sata_fsl_sht = {
+ .module = THIS_MODULE,
+ .name = "sata_fsl",
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .can_queue = SATA_FSL_QUEUE_DEPTH,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = SATA_FSL_MAX_PRD_USABLE,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = "sata_fsl",
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations sata_fsl_ops = {
+ .check_status = sata_fsl_check_status,
+ .check_altstatus = sata_fsl_check_status,
+ .dev_select = ata_noop_dev_select,
+
+ .tf_read = sata_fsl_tf_read,
+
+ .qc_prep = sata_fsl_qc_prep,
+ .qc_issue = sata_fsl_qc_issue,
+ .irq_clear = sata_fsl_irq_clear,
+
+ .scr_read = sata_fsl_scr_read,
+ .scr_write = sata_fsl_scr_write,
+
+ .freeze = sata_fsl_freeze,
+ .thaw = sata_fsl_thaw,
+ .error_handler = sata_fsl_error_handler,
+ .post_internal_cmd = sata_fsl_post_internal_cmd,
+
+ .port_start = sata_fsl_port_start,
+ .port_stop = sata_fsl_port_stop,
+};
+
+static const struct ata_port_info sata_fsl_port_info[] = {
+ {
+ .flags = SATA_FSL_HOST_FLAGS,
+ .link_flags = SATA_FSL_HOST_LFLAGS,
+ .pio_mask = 0x1f, /* pio 0-4 */
+ .udma_mask = 0x7f, /* udma 0-6 */
+ .port_ops = &sata_fsl_ops,
+ },
+};
+
+static int sata_fsl_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ int retval = 0;
+ void __iomem *hcr_base = NULL;
+ void __iomem *ssr_base = NULL;
+ void __iomem *csr_base = NULL;
+ struct sata_fsl_host_priv *host_priv = NULL;
+ struct resource *r;
+ int irq;
+ struct ata_host *host;
+
+ struct ata_port_info pi = sata_fsl_port_info[0];
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+
+ dev_printk(KERN_INFO, &ofdev->dev,
+ "Sata FSL Platform/CSB Driver init\n");
+
+ r = kmalloc(sizeof(struct resource), GFP_KERNEL);
+
+ hcr_base = of_iomap(ofdev->node, 0);
+ if (!hcr_base)
+ goto error_exit_with_cleanup;
+
+ ssr_base = hcr_base + 0x100;
+ csr_base = hcr_base + 0x140;
+
+ DPRINTK("@reset i/o = 0x%x\n", ioread32(csr_base + TRANSCFG));
+ DPRINTK("sizeof(cmd_desc) = %d\n", sizeof(struct command_desc));
+ DPRINTK("sizeof(#define cmd_desc) = %d\n", SATA_FSL_CMD_DESC_SIZE);
+
+ host_priv = kzalloc(sizeof(struct sata_fsl_host_priv), GFP_KERNEL);
+ if (!host_priv)
+ goto error_exit_with_cleanup;
+
+ host_priv->hcr_base = hcr_base;
+ host_priv->ssr_base = ssr_base;
+ host_priv->csr_base = csr_base;
+
+ irq = irq_of_parse_and_map(ofdev->node, 0);
+ if (irq < 0) {
+ dev_printk(KERN_ERR, &ofdev->dev, "invalid irq from platform\n");
+ goto error_exit_with_cleanup;
+ }
+ host_priv->irq = irq;
+
+ /* allocate host structure */
+ host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_FSL_MAX_PORTS);
+
+ /* host->iomap is not used currently */
+ host->private_data = host_priv;
+
+ /* setup port(s) */
+
+ host->ports[0]->ioaddr.cmd_addr = host_priv->hcr_base;
+ host->ports[0]->ioaddr.scr_addr = host_priv->ssr_base;
+
+ /* initialize host controller */
+ sata_fsl_init_controller(host);
+
+ /*
+ * Now, register with libATA core, this will also initiate the
+ * device discovery process, invoking our port_start() handler &
+ * error_handler() to execute a dummy Softreset EH session
+ */
+ ata_host_activate(host, irq, sata_fsl_interrupt, SATA_FSL_IRQ_FLAG,
+ &sata_fsl_sht);
+
+ dev_set_drvdata(&ofdev->dev, host);
+
+ return 0;
+
+error_exit_with_cleanup:
+
+ if (hcr_base)
+ iounmap(hcr_base);
+ if (host_priv)
+ kfree(host_priv);
+
+ return retval;
+}
+
+static int sata_fsl_remove(struct of_device *ofdev)
+{
+ struct ata_host *host = dev_get_drvdata(&ofdev->dev);
+ struct sata_fsl_host_priv *host_priv = host->private_data;
+
+ ata_host_detach(host);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+
+ irq_dispose_mapping(host_priv->irq);
+ iounmap(host_priv->hcr_base);
+ kfree(host_priv);
+
+ return 0;
+}
+
+static struct of_device_id fsl_sata_match[] = {
+ {
+ .compatible = "fsl,mpc8315-sata",
+ },
+ {
+ .compatible = "fsl,mpc8379-sata",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, fsl_sata_match);
+
+static struct of_platform_driver fsl_sata_driver = {
+ .name = "fsl-sata",
+ .match_table = fsl_sata_match,
+ .probe = sata_fsl_probe,
+ .remove = sata_fsl_remove,
+};
+
+static int __init sata_fsl_init(void)
+{
+ of_register_platform_driver(&fsl_sata_driver);
+ return 0;
+}
+
+static void __exit sata_fsl_exit(void)
+{
+ of_unregister_platform_driver(&fsl_sata_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ashish Kalra, Freescale Semiconductor");
+MODULE_DESCRIPTION("Freescale 3.0Gbps SATA controller low level driver");
+MODULE_VERSION("1.10");
+
+module_init(sata_fsl_init);
+module_exit(sata_fsl_exit);
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index fdbed8ecdfc..323c087e8cc 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -143,7 +143,7 @@ static const int scr_map[] = {
[SCR_CONTROL] = 2,
};
-static void __iomem * inic_port_base(struct ata_port *ap)
+static void __iomem *inic_port_base(struct ata_port *ap)
{
return ap->host->iomap[MMIO_BAR] + ap->port_no * PORT_SIZE;
}
@@ -285,7 +285,7 @@ static void inic_irq_clear(struct ata_port *ap)
static void inic_host_intr(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
u8 irq_stat;
/* fetch and clear irq */
@@ -293,7 +293,8 @@ static void inic_host_intr(struct ata_port *ap)
writeb(irq_stat, port_base + PORT_IRQ_STAT);
if (likely(!(irq_stat & PIRQ_ERR))) {
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ struct ata_queued_cmd *qc =
+ ata_qc_from_tag(ap, ap->link.active_tag);
if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
ata_chk_status(ap); /* clear ATA interrupt */
@@ -416,12 +417,13 @@ static void inic_thaw(struct ata_port *ap)
* SRST and SControl hardreset don't give valid signature on this
* controller. Only controller specific hardreset mechanism works.
*/
-static int inic_hardreset(struct ata_port *ap, unsigned int *class,
+static int inic_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
void __iomem *port_base = inic_port_base(ap);
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
- const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
u16 val;
int rc;
@@ -434,24 +436,24 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class,
msleep(1);
writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
- rc = sata_phy_resume(ap, timing, deadline);
+ rc = sata_link_resume(link, timing, deadline);
if (rc) {
- ata_port_printk(ap, KERN_WARNING, "failed to resume "
+ ata_link_printk(link, KERN_WARNING, "failed to resume "
"link after reset (errno=%d)\n", rc);
return rc;
}
*class = ATA_DEV_NONE;
- if (ata_port_online(ap)) {
+ if (ata_link_online(link)) {
struct ata_taskfile tf;
/* wait a while before checking status */
- msleep(150);
+ ata_wait_after_reset(ap, deadline);
rc = ata_wait_ready(ap, deadline);
/* link occupied, -ENODEV too is an error */
if (rc) {
- ata_port_printk(ap, KERN_WARNING, "device not ready "
+ ata_link_printk(link, KERN_WARNING, "device not ready "
"after hardreset (errno=%d)\n", rc);
return rc;
}
@@ -550,7 +552,6 @@ static int inic_port_start(struct ata_port *ap)
}
static struct ata_port_operations inic_port_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -567,7 +568,6 @@ static struct ata_port_operations inic_port_ops = {
.irq_clear = inic_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.qc_prep = ata_qc_prep,
.qc_issue = inic_qc_issue,
@@ -693,16 +693,24 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
host->iomap = iomap = pcim_iomap_table(pdev);
for (i = 0; i < NR_PORTS; i++) {
- struct ata_ioports *port = &host->ports[i]->ioaddr;
- void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE;
+ struct ata_port *ap = host->ports[i];
+ struct ata_ioports *port = &ap->ioaddr;
+ unsigned int offset = i * PORT_SIZE;
port->cmd_addr = iomap[2 * i];
port->altstatus_addr =
port->ctl_addr = (void __iomem *)
((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
- port->scr_addr = port_base + PORT_SCR;
+ port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR;
ata_std_ports(port);
+
+ ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, MMIO_BAR, offset, "port");
+ ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, 2 * i),
+ (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) |
+ ATA_PCI_CTL_OFS);
}
hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index cb7dec97fee..a43f64d2775 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -69,10 +69,11 @@
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
#include <linux/libata.h>
#define DRV_NAME "sata_mv"
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.01"
enum {
/* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -481,8 +482,6 @@ static struct scsi_host_template mv6_sht = {
};
static const struct ata_port_operations mv5_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -497,7 +496,6 @@ static const struct ata_port_operations mv5_ops = {
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.error_handler = mv_error_handler,
.post_internal_cmd = mv_post_int_cmd,
@@ -512,8 +510,6 @@ static const struct ata_port_operations mv5_ops = {
};
static const struct ata_port_operations mv6_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -528,7 +524,6 @@ static const struct ata_port_operations mv6_ops = {
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.error_handler = mv_error_handler,
.post_internal_cmd = mv_post_int_cmd,
@@ -543,8 +538,6 @@ static const struct ata_port_operations mv6_ops = {
};
static const struct ata_port_operations mv_iie_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -559,7 +552,6 @@ static const struct ata_port_operations mv_iie_ops = {
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.error_handler = mv_error_handler,
.post_internal_cmd = mv_post_int_cmd,
@@ -853,7 +845,7 @@ static int __mv_stop_dma(struct ata_port *ap)
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
} else {
WARN_ON(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
- }
+ }
/* now properly wait for the eDMA to stop */
for (i = 1000; i > 0; i--) {
@@ -891,7 +883,7 @@ static void mv_dump_mem(void __iomem *start, unsigned bytes)
for (b = 0; b < bytes; ) {
DPRINTK("%p: ", start + b);
for (w = 0; b < bytes && w < 4; w++) {
- printk("%08x ",readl(start + b));
+ printk("%08x ", readl(start + b));
b += sizeof(u32);
}
printk("\n");
@@ -907,8 +899,8 @@ static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
for (b = 0; b < bytes; ) {
DPRINTK("%02x: ", b);
for (w = 0; b < bytes && w < 4; w++) {
- (void) pci_read_config_dword(pdev,b,&dw);
- printk("%08x ",dw);
+ (void) pci_read_config_dword(pdev, b, &dw);
+ printk("%08x ", dw);
b += sizeof(u32);
}
printk("\n");
@@ -952,9 +944,9 @@ static void mv_dump_all_regs(void __iomem *mmio_base, int port,
}
for (p = start_port; p < start_port + num_ports; p++) {
port_base = mv_port_base(mmio_base, p);
- DPRINTK("EDMA regs (port %i):\n",p);
+ DPRINTK("EDMA regs (port %i):\n", p);
mv_dump_mem(port_base, 0x54);
- DPRINTK("SATA regs (port %i):\n",p);
+ DPRINTK("SATA regs (port %i):\n", p);
mv_dump_mem(port_base+0x300, 0x60);
}
#endif
@@ -1130,12 +1122,11 @@ static void mv_port_stop(struct ata_port *ap)
* LOCKING:
* Inherited from caller.
*/
-static unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
+static void mv_fill_sg(struct ata_queued_cmd *qc)
{
struct mv_port_priv *pp = qc->ap->private_data;
- unsigned int n_sg = 0;
struct scatterlist *sg;
- struct mv_sg *mv_sg;
+ struct mv_sg *mv_sg, *last_sg = NULL;
mv_sg = pp->sg_tbl;
ata_for_each_sg(sg, qc) {
@@ -1151,24 +1142,21 @@ static unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
- mv_sg->flags_size = cpu_to_le32(len);
+ mv_sg->flags_size = cpu_to_le32(len & 0xffff);
sg_len -= len;
addr += len;
- if (!sg_len && ata_sg_is_last(sg, qc))
- mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
-
+ last_sg = mv_sg;
mv_sg++;
- n_sg++;
}
-
}
- return n_sg;
+ if (likely(last_sg))
+ last_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
}
-static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
+static void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
{
u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
(last ? CRQB_CMD_LAST : 0);
@@ -1196,7 +1184,7 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
u16 flags = 0;
unsigned in_index;
- if (qc->tf.protocol != ATA_PROT_DMA)
+ if (qc->tf.protocol != ATA_PROT_DMA)
return;
/* Fill in command request block
@@ -1288,7 +1276,7 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
unsigned in_index;
u32 flags = 0;
- if (qc->tf.protocol != ATA_PROT_DMA)
+ if (qc->tf.protocol != ATA_PROT_DMA)
return;
/* Fill in Gen IIE command request block
@@ -1406,7 +1394,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
struct mv_host_priv *hpriv = ap->host->private_data;
unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
unsigned int action = 0, err_mask = 0;
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
@@ -1414,8 +1402,8 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
/* just a guess: do we need to do this? should we
* expand this, and do it in all cases?
*/
- sata_scr_read(ap, SCR_ERROR, &serr);
- sata_scr_write_flush(ap, SCR_ERROR, serr);
+ sata_scr_read(&ap->link, SCR_ERROR, &serr);
+ sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
}
edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
@@ -1459,8 +1447,8 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
}
if (edma_err_cause & EDMA_ERR_SERR) {
- sata_scr_read(ap, SCR_ERROR, &serr);
- sata_scr_write_flush(ap, SCR_ERROR, serr);
+ sata_scr_read(&ap->link, SCR_ERROR, &serr);
+ sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
err_mask = AC_ERR_ATA_BUS;
action |= ATA_EH_HARDRESET;
}
@@ -1499,7 +1487,7 @@ static void mv_intr_pio(struct ata_port *ap)
return;
/* get active ATA command */
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (unlikely(!qc)) /* no active tag */
return;
if (qc->tf.flags & ATA_TFLAG_POLLING) /* polling; we don't own qc */
@@ -1534,7 +1522,7 @@ static void mv_intr_edma(struct ata_port *ap)
/* 50xx: get active ATA command */
if (IS_GEN_I(hpriv))
- tag = ap->active_tag;
+ tag = ap->link.active_tag;
/* Gen II/IIE: get active ATA command via tag, to enable
* support for queueing. this works transparently for
@@ -1618,7 +1606,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
- hc,relevant,hc_irq_cause);
+ hc, relevant, hc_irq_cause);
for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
struct ata_port *ap = host->ports[port];
@@ -1637,7 +1625,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
if (unlikely(have_err_bits)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
continue;
@@ -1678,15 +1666,15 @@ static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
for (i = 0; i < host->n_ports; i++) {
ap = host->ports[i];
- if (!ata_port_offline(ap)) {
- ehi = &ap->eh_info;
+ if (!ata_link_offline(&ap->link)) {
+ ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
if (!printed++)
ata_ehi_push_desc(ehi,
"PCI err cause 0x%08x", err_cause);
err_mask = AC_ERR_HOST_BUS;
ehi->action = ATA_EH_HARDRESET;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc)
qc->err_mask |= err_mask;
else
@@ -1995,9 +1983,8 @@ static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
for (i = 0; i < 1000; i++) {
udelay(1);
t = readl(reg);
- if (PCI_MASTER_EMPTY & t) {
+ if (PCI_MASTER_EMPTY & t)
break;
- }
}
if (!(PCI_MASTER_EMPTY & t)) {
printk(KERN_ERR DRV_NAME ": PCI master won't flush\n");
@@ -2189,14 +2176,14 @@ static void mv_phy_reset(struct ata_port *ap, unsigned int *class,
/* Issue COMRESET via SControl */
comreset_retry:
- sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+ sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x301);
msleep(1);
- sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+ sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x300);
msleep(20);
do {
- sata_scr_read(ap, SCR_STATUS, &sstatus);
+ sata_scr_read(&ap->link, SCR_STATUS, &sstatus);
if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
break;
@@ -2221,7 +2208,7 @@ comreset_retry:
}
#endif
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(&ap->link)) {
*class = ATA_DEV_NONE;
return;
}
@@ -2248,7 +2235,7 @@ comreset_retry:
*/
/* finally, read device signature from TF registers */
- *class = ata_dev_try_classify(ap, 0, NULL);
+ *class = ata_dev_try_classify(ap->link.device, 1, NULL);
writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
@@ -2257,10 +2244,11 @@ comreset_retry:
VPRINTK("EXIT\n");
}
-static int mv_prereset(struct ata_port *ap, unsigned long deadline)
+static int mv_prereset(struct ata_link *link, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct mv_port_priv *pp = ap->private_data;
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_eh_context *ehc = &link->eh_context;
int rc;
rc = mv_stop_dma(ap);
@@ -2276,7 +2264,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline)
if (ehc->i.action & ATA_EH_HARDRESET)
return 0;
- if (ata_port_online(ap))
+ if (ata_link_online(link))
rc = ata_wait_ready(ap, deadline);
else
rc = -ENODEV;
@@ -2284,9 +2272,10 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline)
return rc;
}
-static int mv_hardreset(struct ata_port *ap, unsigned int *class,
+static int mv_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
struct mv_host_priv *hpriv = ap->host->private_data;
void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
@@ -2299,16 +2288,17 @@ static int mv_hardreset(struct ata_port *ap, unsigned int *class,
return 0;
}
-static void mv_postreset(struct ata_port *ap, unsigned int *classes)
+static void mv_postreset(struct ata_link *link, unsigned int *classes)
{
+ struct ata_port *ap = link->ap;
u32 serr;
/* print link status */
- sata_print_link_status(ap);
+ sata_print_link_status(link);
/* clear SError */
- sata_scr_read(ap, SCR_ERROR, &serr);
- sata_scr_write_flush(ap, SCR_ERROR, serr);
+ sata_scr_read(link, SCR_ERROR, &serr);
+ sata_scr_write_flush(link, SCR_ERROR, serr);
/* bail out if no device is present */
if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
@@ -2439,7 +2429,7 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
struct mv_host_priv *hpriv = host->private_data;
u32 hp_flags = hpriv->hp_flags;
- switch(board_idx) {
+ switch (board_idx) {
case chip_5080:
hpriv->ops = &mv5xxx_ops;
hp_flags |= MV_HP_GEN_I;
@@ -2520,7 +2510,8 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
break;
default:
- printk(KERN_ERR DRV_NAME ": BUG: invalid board index %u\n", board_idx);
+ dev_printk(KERN_ERR, &pdev->dev,
+ "BUG: invalid board index %u\n", board_idx);
return 1;
}
@@ -2581,8 +2572,14 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
}
for (port = 0; port < host->n_ports; port++) {
+ struct ata_port *ap = host->ports[port];
void __iomem *port_mmio = mv_port_base(mmio, port);
- mv_port_init(&host->ports[port]->ioaddr, port_mmio);
+ unsigned int offset = port_mmio - mmio;
+
+ mv_port_init(&ap->ioaddr, port_mmio);
+
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
}
for (hc = 0; hc < n_hc; hc++) {
@@ -2671,7 +2668,7 @@ static void mv_print_info(struct ata_host *host)
*/
static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version = 0;
+ static int printed_version;
unsigned int board_idx = (unsigned int)ent->driver_data;
const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
struct ata_host *host;
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 40dc7313985..44f9e5d9e36 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -163,12 +163,41 @@ enum {
NV_ADMA_STAT_STOPPED = (1 << 10),
NV_ADMA_STAT_DONE = (1 << 12),
NV_ADMA_STAT_ERR = NV_ADMA_STAT_CPBERR |
- NV_ADMA_STAT_TIMEOUT,
+ NV_ADMA_STAT_TIMEOUT,
/* port flags */
NV_ADMA_PORT_REGISTER_MODE = (1 << 0),
NV_ADMA_ATAPI_SETUP_COMPLETE = (1 << 1),
+ /* MCP55 reg offset */
+ NV_CTL_MCP55 = 0x400,
+ NV_INT_STATUS_MCP55 = 0x440,
+ NV_INT_ENABLE_MCP55 = 0x444,
+ NV_NCQ_REG_MCP55 = 0x448,
+
+ /* MCP55 */
+ NV_INT_ALL_MCP55 = 0xffff,
+ NV_INT_PORT_SHIFT_MCP55 = 16, /* each port occupies 16 bits */
+ NV_INT_MASK_MCP55 = NV_INT_ALL_MCP55 & 0xfffd,
+
+ /* SWNCQ ENABLE BITS*/
+ NV_CTL_PRI_SWNCQ = 0x02,
+ NV_CTL_SEC_SWNCQ = 0x04,
+
+ /* SW NCQ status bits*/
+ NV_SWNCQ_IRQ_DEV = (1 << 0),
+ NV_SWNCQ_IRQ_PM = (1 << 1),
+ NV_SWNCQ_IRQ_ADDED = (1 << 2),
+ NV_SWNCQ_IRQ_REMOVED = (1 << 3),
+
+ NV_SWNCQ_IRQ_BACKOUT = (1 << 4),
+ NV_SWNCQ_IRQ_SDBFIS = (1 << 5),
+ NV_SWNCQ_IRQ_DHREGFIS = (1 << 6),
+ NV_SWNCQ_IRQ_DMASETUP = (1 << 7),
+
+ NV_SWNCQ_IRQ_HOTPLUG = NV_SWNCQ_IRQ_ADDED |
+ NV_SWNCQ_IRQ_REMOVED,
+
};
/* ADMA Physical Region Descriptor - one SG segment */
@@ -199,7 +228,7 @@ struct nv_adma_cpb {
u8 reserved1; /* 1 */
u8 ctl_flags; /* 2 */
/* len is length of taskfile in 64 bit words */
- u8 len; /* 3 */
+ u8 len; /* 3 */
u8 tag; /* 4 */
u8 next_cpb_idx; /* 5 */
__le16 reserved2; /* 6-7 */
@@ -215,9 +244,9 @@ struct nv_adma_port_priv {
dma_addr_t cpb_dma;
struct nv_adma_prd *aprd;
dma_addr_t aprd_dma;
- void __iomem * ctl_block;
- void __iomem * gen_block;
- void __iomem * notifier_clear_block;
+ void __iomem *ctl_block;
+ void __iomem *gen_block;
+ void __iomem *notifier_clear_block;
u8 flags;
int last_issue_ncq;
};
@@ -226,9 +255,45 @@ struct nv_host_priv {
unsigned long type;
};
-#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT)))))
+struct defer_queue {
+ u32 defer_bits;
+ unsigned int head;
+ unsigned int tail;
+ unsigned int tag[ATA_MAX_QUEUE];
+};
+
+enum ncq_saw_flag_list {
+ ncq_saw_d2h = (1U << 0),
+ ncq_saw_dmas = (1U << 1),
+ ncq_saw_sdb = (1U << 2),
+ ncq_saw_backout = (1U << 3),
+};
+
+struct nv_swncq_port_priv {
+ struct ata_prd *prd; /* our SG list */
+ dma_addr_t prd_dma; /* and its DMA mapping */
+ void __iomem *sactive_block;
+ void __iomem *irq_block;
+ void __iomem *tag_block;
+ u32 qc_active;
+
+ unsigned int last_issue_tag;
+
+ /* fifo circular queue to store deferral command */
+ struct defer_queue defer_queue;
-static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+ /* for NCQ interrupt analysis */
+ u32 dhfis_bits;
+ u32 dmafis_bits;
+ u32 sdbfis_bits;
+
+ unsigned int ncq_flags;
+};
+
+
+#define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & (1 << (19 + (12 * (PORT)))))
+
+static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
#ifdef CONFIG_PM
static int nv_pci_device_resume(struct pci_dev *pdev);
#endif
@@ -236,8 +301,8 @@ static void nv_ck804_host_stop(struct ata_host *host);
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
-static int nv_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static void nv_nf2_freeze(struct ata_port *ap);
static void nv_nf2_thaw(struct ata_port *ap);
@@ -263,13 +328,29 @@ static void nv_adma_host_stop(struct ata_host *host);
static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc);
static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+static void nv_mcp55_thaw(struct ata_port *ap);
+static void nv_mcp55_freeze(struct ata_port *ap);
+static void nv_swncq_error_handler(struct ata_port *ap);
+static int nv_swncq_slave_config(struct scsi_device *sdev);
+static int nv_swncq_port_start(struct ata_port *ap);
+static void nv_swncq_qc_prep(struct ata_queued_cmd *qc);
+static void nv_swncq_fill_sg(struct ata_queued_cmd *qc);
+static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc);
+static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis);
+static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance);
+#ifdef CONFIG_PM
+static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg);
+static int nv_swncq_port_resume(struct ata_port *ap);
+#endif
+
enum nv_host_type
{
GENERIC,
NFORCE2,
NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */
CK804,
- ADMA
+ ADMA,
+ SWNCQ,
};
static const struct pci_device_id nv_pci_tbl[] = {
@@ -280,10 +361,10 @@ static const struct pci_device_id nv_pci_tbl[] = {
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 },
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 },
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), GENERIC },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), GENERIC },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), GENERIC },
- { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), SWNCQ },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), SWNCQ },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), SWNCQ },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), SWNCQ },
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC },
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC },
{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC },
@@ -339,8 +420,26 @@ static struct scsi_host_template nv_adma_sht = {
.bios_param = ata_std_bios_param,
};
+static struct scsi_host_template nv_swncq_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .can_queue = ATA_MAX_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = nv_swncq_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
static const struct ata_port_operations nv_generic_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
@@ -359,14 +458,12 @@ static const struct ata_port_operations nv_generic_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
};
static const struct ata_port_operations nv_nf2_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
@@ -385,14 +482,12 @@ static const struct ata_port_operations nv_nf2_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
};
static const struct ata_port_operations nv_ck804_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.exec_command = ata_exec_command,
@@ -411,7 +506,6 @@ static const struct ata_port_operations nv_ck804_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = ata_port_start,
@@ -419,7 +513,6 @@ static const struct ata_port_operations nv_ck804_ops = {
};
static const struct ata_port_operations nv_adma_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = nv_adma_tf_read,
.check_atapi_dma = nv_adma_check_atapi_dma,
@@ -430,6 +523,7 @@ static const struct ata_port_operations nv_adma_ops = {
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
+ .qc_defer = ata_std_qc_defer,
.qc_prep = nv_adma_qc_prep,
.qc_issue = nv_adma_qc_issue,
.freeze = nv_adma_freeze,
@@ -439,7 +533,6 @@ static const struct ata_port_operations nv_adma_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = nv_adma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = nv_scr_read,
.scr_write = nv_scr_write,
.port_start = nv_adma_port_start,
@@ -451,12 +544,41 @@ static const struct ata_port_operations nv_adma_ops = {
.host_stop = nv_adma_host_stop,
};
+static const struct ata_port_operations nv_swncq_ops = {
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .exec_command = ata_exec_command,
+ .check_status = ata_check_status,
+ .dev_select = ata_std_dev_select,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_defer = ata_std_qc_defer,
+ .qc_prep = nv_swncq_qc_prep,
+ .qc_issue = nv_swncq_qc_issue,
+ .freeze = nv_mcp55_freeze,
+ .thaw = nv_mcp55_thaw,
+ .error_handler = nv_swncq_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .data_xfer = ata_data_xfer,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .scr_read = nv_scr_read,
+ .scr_write = nv_scr_write,
+#ifdef CONFIG_PM
+ .port_suspend = nv_swncq_port_suspend,
+ .port_resume = nv_swncq_port_resume,
+#endif
+ .port_start = nv_swncq_port_start,
+};
+
static const struct ata_port_info nv_port_info[] = {
/* generic */
{
.sht = &nv_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_HRST_TO_RESUME,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -466,8 +588,8 @@ static const struct ata_port_info nv_port_info[] = {
/* nforce2/3 */
{
.sht = &nv_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_HRST_TO_RESUME,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -477,8 +599,8 @@ static const struct ata_port_info nv_port_info[] = {
/* ck804 */
{
.sht = &nv_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_HRST_TO_RESUME,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -489,14 +611,26 @@ static const struct ata_port_info nv_port_info[] = {
{
.sht = &nv_adma_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_HRST_TO_RESUME |
ATA_FLAG_MMIO | ATA_FLAG_NCQ,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
.port_ops = &nv_adma_ops,
.irq_handler = nv_adma_interrupt,
},
+ /* SWNCQ */
+ {
+ .sht = &nv_swncq_sht,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_NCQ,
+ .link_flags = ATA_LFLAG_HRST_TO_RESUME,
+ .pio_mask = NV_PIO_MASK,
+ .mwdma_mask = NV_MWDMA_MASK,
+ .udma_mask = NV_UDMA_MASK,
+ .port_ops = &nv_swncq_ops,
+ .irq_handler = nv_swncq_interrupt,
+ },
};
MODULE_AUTHOR("NVIDIA");
@@ -506,6 +640,7 @@ MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
MODULE_VERSION(DRV_VERSION);
static int adma_enabled = 1;
+static int swncq_enabled;
static void nv_adma_register_mode(struct ata_port *ap)
{
@@ -518,12 +653,12 @@ static void nv_adma_register_mode(struct ata_port *ap)
return;
status = readw(mmio + NV_ADMA_STAT);
- while(!(status & NV_ADMA_STAT_IDLE) && count < 20) {
+ while (!(status & NV_ADMA_STAT_IDLE) && count < 20) {
ndelay(50);
status = readw(mmio + NV_ADMA_STAT);
count++;
}
- if(count == 20)
+ if (count == 20)
ata_port_printk(ap, KERN_WARNING,
"timeout waiting for ADMA IDLE, stat=0x%hx\n",
status);
@@ -533,12 +668,12 @@ static void nv_adma_register_mode(struct ata_port *ap)
count = 0;
status = readw(mmio + NV_ADMA_STAT);
- while(!(status & NV_ADMA_STAT_LEGACY) && count < 20) {
+ while (!(status & NV_ADMA_STAT_LEGACY) && count < 20) {
ndelay(50);
status = readw(mmio + NV_ADMA_STAT);
count++;
}
- if(count == 20)
+ if (count == 20)
ata_port_printk(ap, KERN_WARNING,
"timeout waiting for ADMA LEGACY, stat=0x%hx\n",
status);
@@ -562,13 +697,13 @@ static void nv_adma_mode(struct ata_port *ap)
writew(tmp | NV_ADMA_CTL_GO, mmio + NV_ADMA_CTL);
status = readw(mmio + NV_ADMA_STAT);
- while(((status & NV_ADMA_STAT_LEGACY) ||
+ while (((status & NV_ADMA_STAT_LEGACY) ||
!(status & NV_ADMA_STAT_IDLE)) && count < 20) {
ndelay(50);
status = readw(mmio + NV_ADMA_STAT);
count++;
}
- if(count == 20)
+ if (count == 20)
ata_port_printk(ap, KERN_WARNING,
"timeout waiting for ADMA LEGACY clear and IDLE, stat=0x%hx\n",
status);
@@ -594,7 +729,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
/* Not a proper libata device, ignore */
return rc;
- if (ap->device[sdev->id].class == ATA_DEV_ATAPI) {
+ if (ap->link.device[sdev->id].class == ATA_DEV_ATAPI) {
/*
* NVIDIA reports that ADMA mode does not support ATAPI commands.
* Therefore ATAPI commands are sent through the legacy interface.
@@ -612,8 +747,7 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
on the port. */
adma_enable = 0;
nv_adma_register_mode(ap);
- }
- else {
+ } else {
bounce_limit = *ap->dev->dma_mask;
segment_boundary = NV_ADMA_DMA_BOUNDARY;
sg_tablesize = NV_ADMA_SGTBL_TOTAL_LEN;
@@ -622,23 +756,22 @@ static int nv_adma_slave_config(struct scsi_device *sdev)
pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &current_reg);
- if(ap->port_no == 1)
+ if (ap->port_no == 1)
config_mask = NV_MCP_SATA_CFG_20_PORT1_EN |
NV_MCP_SATA_CFG_20_PORT1_PWB_EN;
else
config_mask = NV_MCP_SATA_CFG_20_PORT0_EN |
NV_MCP_SATA_CFG_20_PORT0_PWB_EN;
- if(adma_enable) {
+ if (adma_enable) {
new_reg = current_reg | config_mask;
pp->flags &= ~NV_ADMA_ATAPI_SETUP_COMPLETE;
- }
- else {
+ } else {
new_reg = current_reg & ~config_mask;
pp->flags |= NV_ADMA_ATAPI_SETUP_COMPLETE;
}
- if(current_reg != new_reg)
+ if (current_reg != new_reg)
pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, new_reg);
blk_queue_bounce_limit(sdev->request_queue, bounce_limit);
@@ -672,7 +805,7 @@ static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb)
{
unsigned int idx = 0;
- if(tf->flags & ATA_TFLAG_ISADDR) {
+ if (tf->flags & ATA_TFLAG_ISADDR) {
if (tf->flags & ATA_TFLAG_LBA48) {
cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->hob_feature | WNB);
cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->hob_nsect);
@@ -689,12 +822,12 @@ static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb)
cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->lbah);
}
- if(tf->flags & ATA_TFLAG_DEVICE)
+ if (tf->flags & ATA_TFLAG_DEVICE)
cpb[idx++] = cpu_to_le16((ATA_REG_DEVICE << 8) | tf->device);
cpb[idx++] = cpu_to_le16((ATA_REG_CMD << 8) | tf->command | CMDEND);
- while(idx < 12)
+ while (idx < 12)
cpb[idx++] = cpu_to_le16(IGN);
return idx;
@@ -711,11 +844,11 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
flags & (NV_CPB_RESP_ATA_ERR |
NV_CPB_RESP_CMD_ERR |
NV_CPB_RESP_CPB_ERR)))) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
int freeze = 0;
ata_ehi_clear_desc(ehi);
- __ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x: ", flags );
+ __ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x: ", flags);
if (flags & NV_CPB_RESP_ATA_ERR) {
ata_ehi_push_desc(ehi, "ATA error");
ehi->err_mask |= AC_ERR_DEV;
@@ -744,15 +877,16 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
VPRINTK("CPB flags done, flags=0x%x\n", flags);
if (likely(qc)) {
- DPRINTK("Completing qc from tag %d\n",cpb_num);
+ DPRINTK("Completing qc from tag %d\n", cpb_num);
ata_qc_complete(qc);
} else {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
/* Notifier bits set without a command may indicate the drive
is misbehaving. Raise host state machine violation on this
condition. */
- ata_port_printk(ap, KERN_ERR, "notifier for tag %d with no command?\n",
- cpb_num);
+ ata_port_printk(ap, KERN_ERR,
+ "notifier for tag %d with no cmd?\n",
+ cpb_num);
ehi->err_mask |= AC_ERR_HSM;
ehi->action |= ATA_EH_SOFTRESET;
ata_port_freeze(ap);
@@ -764,7 +898,7 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
{
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
/* freeze if hotplugged */
if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) {
@@ -817,7 +951,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
>> (NV_INT_PORT_SHIFT * i);
- if(ata_tag_valid(ap->active_tag))
+ if (ata_tag_valid(ap->link.active_tag))
/** NV_INT_DEV indication seems unreliable at times
at least in ADMA mode. Force it on always when a
command is active, to prevent losing interrupts. */
@@ -831,7 +965,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
- if( !NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier &&
+ if (!NV_ADMA_CHECK_INTR(gen_ctl, ap->port_no) && !notifier &&
!notifier_error)
/* Nothing to do */
continue;
@@ -852,10 +986,10 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
NV_ADMA_STAT_HOTUNPLUG |
NV_ADMA_STAT_TIMEOUT |
NV_ADMA_STAT_SERROR))) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
- __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status );
+ __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status);
if (status & NV_ADMA_STAT_TIMEOUT) {
ehi->err_mask |= AC_ERR_SYSTEM;
ata_ehi_push_desc(ehi, "timeout");
@@ -879,23 +1013,23 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
u32 check_commands;
int pos, error = 0;
- if(ata_tag_valid(ap->active_tag))
- check_commands = 1 << ap->active_tag;
+ if (ata_tag_valid(ap->link.active_tag))
+ check_commands = 1 << ap->link.active_tag;
else
- check_commands = ap->sactive;
+ check_commands = ap->link.sactive;
/** Check CPBs for completed commands */
while ((pos = ffs(check_commands)) && !error) {
pos--;
error = nv_adma_check_cpb(ap, pos,
- notifier_error & (1 << pos) );
- check_commands &= ~(1 << pos );
+ notifier_error & (1 << pos));
+ check_commands &= ~(1 << pos);
}
}
}
}
- if(notifier_clears[0] || notifier_clears[1]) {
+ if (notifier_clears[0] || notifier_clears[1]) {
/* Note: Both notifier clear registers must be written
if either is set, even if one is zero, according to NVIDIA. */
struct nv_adma_port_priv *pp = host->ports[0]->private_data;
@@ -921,14 +1055,14 @@ static void nv_adma_freeze(struct ata_port *ap)
return;
/* clear any outstanding CK804 notifications */
- writeb( NV_INT_ALL << (ap->port_no * NV_INT_PORT_SHIFT),
+ writeb(NV_INT_ALL << (ap->port_no * NV_INT_PORT_SHIFT),
ap->host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804);
/* Disable interrupt */
tmp = readw(mmio + NV_ADMA_CTL);
- writew( tmp & ~(NV_ADMA_CTL_AIEN | NV_ADMA_CTL_HOTPLUG_IEN),
+ writew(tmp & ~(NV_ADMA_CTL_AIEN | NV_ADMA_CTL_HOTPLUG_IEN),
mmio + NV_ADMA_CTL);
- readw( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw(mmio + NV_ADMA_CTL); /* flush posted write */
}
static void nv_adma_thaw(struct ata_port *ap)
@@ -944,9 +1078,9 @@ static void nv_adma_thaw(struct ata_port *ap)
/* Enable interrupt */
tmp = readw(mmio + NV_ADMA_CTL);
- writew( tmp | (NV_ADMA_CTL_AIEN | NV_ADMA_CTL_HOTPLUG_IEN),
+ writew(tmp | (NV_ADMA_CTL_AIEN | NV_ADMA_CTL_HOTPLUG_IEN),
mmio + NV_ADMA_CTL);
- readw( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw(mmio + NV_ADMA_CTL); /* flush posted write */
}
static void nv_adma_irq_clear(struct ata_port *ap)
@@ -961,7 +1095,7 @@ static void nv_adma_irq_clear(struct ata_port *ap)
}
/* clear any outstanding CK804 notifications */
- writeb( NV_INT_ALL << (ap->port_no * NV_INT_PORT_SHIFT),
+ writeb(NV_INT_ALL << (ap->port_no * NV_INT_PORT_SHIFT),
ap->host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804);
/* clear ADMA status */
@@ -986,7 +1120,7 @@ static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct nv_adma_port_priv *pp = qc->ap->private_data;
- if(pp->flags & NV_ADMA_PORT_REGISTER_MODE)
+ if (pp->flags & NV_ADMA_PORT_REGISTER_MODE)
ata_bmdma_post_internal_cmd(qc);
}
@@ -1032,7 +1166,7 @@ static int nv_adma_port_start(struct ata_port *ap)
pp->cpb_dma = mem_dma;
writel(mem_dma & 0xFFFFFFFF, mmio + NV_ADMA_CPB_BASE_LOW);
- writel((mem_dma >> 16 ) >> 16, mmio + NV_ADMA_CPB_BASE_HIGH);
+ writel((mem_dma >> 16) >> 16, mmio + NV_ADMA_CPB_BASE_HIGH);
mem += NV_ADMA_MAX_CPBS * NV_ADMA_CPB_SZ;
mem_dma += NV_ADMA_MAX_CPBS * NV_ADMA_CPB_SZ;
@@ -1056,15 +1190,15 @@ static int nv_adma_port_start(struct ata_port *ap)
/* clear GO for register mode, enable interrupt */
tmp = readw(mmio + NV_ADMA_CTL);
- writew( (tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN |
- NV_ADMA_CTL_HOTPLUG_IEN, mmio + NV_ADMA_CTL);
+ writew((tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN |
+ NV_ADMA_CTL_HOTPLUG_IEN, mmio + NV_ADMA_CTL);
tmp = readw(mmio + NV_ADMA_CTL);
writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
- readw( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw(mmio + NV_ADMA_CTL); /* flush posted write */
udelay(1);
writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
- readw( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw(mmio + NV_ADMA_CTL); /* flush posted write */
return 0;
}
@@ -1104,7 +1238,7 @@ static int nv_adma_port_resume(struct ata_port *ap)
/* set CPB block location */
writel(pp->cpb_dma & 0xFFFFFFFF, mmio + NV_ADMA_CPB_BASE_LOW);
- writel((pp->cpb_dma >> 16 ) >> 16, mmio + NV_ADMA_CPB_BASE_HIGH);
+ writel((pp->cpb_dma >> 16) >> 16, mmio + NV_ADMA_CPB_BASE_HIGH);
/* clear any outstanding interrupt conditions */
writew(0xffff, mmio + NV_ADMA_STAT);
@@ -1117,15 +1251,15 @@ static int nv_adma_port_resume(struct ata_port *ap)
/* clear GO for register mode, enable interrupt */
tmp = readw(mmio + NV_ADMA_CTL);
- writew( (tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN |
- NV_ADMA_CTL_HOTPLUG_IEN, mmio + NV_ADMA_CTL);
+ writew((tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN |
+ NV_ADMA_CTL_HOTPLUG_IEN, mmio + NV_ADMA_CTL);
tmp = readw(mmio + NV_ADMA_CTL);
writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
- readw( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw(mmio + NV_ADMA_CTL); /* flush posted write */
udelay(1);
writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
- readw( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw(mmio + NV_ADMA_CTL); /* flush posted write */
return 0;
}
@@ -1209,7 +1343,8 @@ static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb)
idx = 0;
ata_for_each_sg(sg, qc) {
- aprd = (idx < 5) ? &cpb->aprd[idx] : &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (idx-5)];
+ aprd = (idx < 5) ? &cpb->aprd[idx] :
+ &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (idx-5)];
nv_adma_fill_aprd(qc, sg, idx, aprd);
idx++;
}
@@ -1226,12 +1361,12 @@ static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc)
/* ADMA engine can only be used for non-ATAPI DMA commands,
or interrupt-driven no-data commands, where a result taskfile
is not required. */
- if((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
+ if ((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
(qc->tf.flags & ATA_TFLAG_POLLING) ||
(qc->flags & ATA_QCFLAG_RESULT_TF))
return 1;
- if((qc->flags & ATA_QCFLAG_DMAMAP) ||
+ if ((qc->flags & ATA_QCFLAG_DMAMAP) ||
(qc->tf.protocol == ATA_PROT_NODATA))
return 0;
@@ -1268,14 +1403,14 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc)
nv_adma_tf_to_cpb(&qc->tf, cpb->tf);
- if(qc->flags & ATA_QCFLAG_DMAMAP) {
+ if (qc->flags & ATA_QCFLAG_DMAMAP) {
nv_adma_fill_sg(qc, cpb);
ctl_flags |= NV_CPB_CTL_APRD_VALID;
} else
memset(&cpb->aprd[0], 0, sizeof(struct nv_adma_prd) * 5);
- /* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID until we are
- finished filling in all of the contents */
+ /* Be paranoid and don't let the device see NV_CPB_CTL_CPB_VALID
+ until we are finished filling in all of the contents */
wmb();
cpb->ctl_flags = ctl_flags;
wmb();
@@ -1302,16 +1437,16 @@ static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc)
and (number of cpbs to append -1) in top 8 bits */
wmb();
- if(curr_ncq != pp->last_issue_ncq) {
- /* Seems to need some delay before switching between NCQ and non-NCQ
- commands, else we get command timeouts and such. */
+ if (curr_ncq != pp->last_issue_ncq) {
+ /* Seems to need some delay before switching between NCQ and
+ non-NCQ commands, else we get command timeouts and such. */
udelay(20);
pp->last_issue_ncq = curr_ncq;
}
writew(qc->tag, mmio + NV_ADMA_APPEND);
- DPRINTK("Issued tag %u\n",qc->tag);
+ DPRINTK("Issued tag %u\n", qc->tag);
return 0;
}
@@ -1333,7 +1468,7 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance)
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += ata_host_intr(ap, qc);
else
@@ -1459,16 +1594,44 @@ static void nv_ck804_thaw(struct ata_port *ap)
writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
}
-static int nv_hardreset(struct ata_port *ap, unsigned int *class,
+static void nv_mcp55_freeze(struct ata_port *ap)
+{
+ void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR];
+ int shift = ap->port_no * NV_INT_PORT_SHIFT_MCP55;
+ u32 mask;
+
+ writel(NV_INT_ALL_MCP55 << shift, mmio_base + NV_INT_STATUS_MCP55);
+
+ mask = readl(mmio_base + NV_INT_ENABLE_MCP55);
+ mask &= ~(NV_INT_ALL_MCP55 << shift);
+ writel(mask, mmio_base + NV_INT_ENABLE_MCP55);
+ ata_bmdma_freeze(ap);
+}
+
+static void nv_mcp55_thaw(struct ata_port *ap)
+{
+ void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR];
+ int shift = ap->port_no * NV_INT_PORT_SHIFT_MCP55;
+ u32 mask;
+
+ writel(NV_INT_ALL_MCP55 << shift, mmio_base + NV_INT_STATUS_MCP55);
+
+ mask = readl(mmio_base + NV_INT_ENABLE_MCP55);
+ mask |= (NV_INT_MASK_MCP55 << shift);
+ writel(mask, mmio_base + NV_INT_ENABLE_MCP55);
+ ata_bmdma_thaw(ap);
+}
+
+static int nv_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
unsigned int dummy;
/* SATA hardreset fails to retrieve proper device signature on
* some controllers. Don't classify on hardreset. For more
- * info, see http://bugme.osdl.org/show_bug.cgi?id=3352
+ * info, see http://bugzilla.kernel.org/show_bug.cgi?id=3352
*/
- return sata_std_hardreset(ap, &dummy, deadline);
+ return sata_std_hardreset(link, &dummy, deadline);
}
static void nv_error_handler(struct ata_port *ap)
@@ -1480,12 +1643,12 @@ static void nv_error_handler(struct ata_port *ap)
static void nv_adma_error_handler(struct ata_port *ap)
{
struct nv_adma_port_priv *pp = ap->private_data;
- if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
+ if (!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) {
void __iomem *mmio = pp->ctl_block;
int i;
u16 tmp;
- if(ata_tag_valid(ap->active_tag) || ap->sactive) {
+ if (ata_tag_valid(ap->link.active_tag) || ap->link.sactive) {
u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
u32 gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
@@ -1493,16 +1656,17 @@ static void nv_adma_error_handler(struct ata_port *ap)
u8 cpb_count = readb(mmio + NV_ADMA_CPB_COUNT);
u8 next_cpb_idx = readb(mmio + NV_ADMA_NEXT_CPB_IDX);
- ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X "
+ ata_port_printk(ap, KERN_ERR,
+ "EH in ADMA mode, notifier 0x%X "
"notifier_error 0x%X gen_ctl 0x%X status 0x%X "
"next cpb count 0x%X next cpb idx 0x%x\n",
notifier, notifier_error, gen_ctl, status,
cpb_count, next_cpb_idx);
- for( i=0;i<NV_ADMA_MAX_CPBS;i++) {
+ for (i = 0; i < NV_ADMA_MAX_CPBS; i++) {
struct nv_adma_cpb *cpb = &pp->cpb[i];
- if( (ata_tag_valid(ap->active_tag) && i == ap->active_tag) ||
- ap->sactive & (1 << i) )
+ if ((ata_tag_valid(ap->link.active_tag) && i == ap->link.active_tag) ||
+ ap->link.sactive & (1 << i))
ata_port_printk(ap, KERN_ERR,
"CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n",
i, cpb->ctl_flags, cpb->resp_flags);
@@ -1512,8 +1676,9 @@ static void nv_adma_error_handler(struct ata_port *ap)
/* Push us back into port register mode for error handling. */
nv_adma_register_mode(ap);
- /* Mark all of the CPBs as invalid to prevent them from being executed */
- for( i=0;i<NV_ADMA_MAX_CPBS;i++)
+ /* Mark all of the CPBs as invalid to prevent them from
+ being executed */
+ for (i = 0; i < NV_ADMA_MAX_CPBS; i++)
pp->cpb[i].ctl_flags &= ~NV_CPB_CTL_CPB_VALID;
/* clear CPB fetch count */
@@ -1522,19 +1687,676 @@ static void nv_adma_error_handler(struct ata_port *ap)
/* Reset channel */
tmp = readw(mmio + NV_ADMA_CTL);
writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
- readw( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw(mmio + NV_ADMA_CTL); /* flush posted write */
udelay(1);
writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL);
- readw( mmio + NV_ADMA_CTL ); /* flush posted write */
+ readw(mmio + NV_ADMA_CTL); /* flush posted write */
+ }
+
+ ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
+ nv_hardreset, ata_std_postreset);
+}
+
+static void nv_swncq_qc_to_dq(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ struct defer_queue *dq = &pp->defer_queue;
+
+ /* queue is full */
+ WARN_ON(dq->tail - dq->head == ATA_MAX_QUEUE);
+ dq->defer_bits |= (1 << qc->tag);
+ dq->tag[dq->tail++ & (ATA_MAX_QUEUE - 1)] = qc->tag;
+}
+
+static struct ata_queued_cmd *nv_swncq_qc_from_dq(struct ata_port *ap)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ struct defer_queue *dq = &pp->defer_queue;
+ unsigned int tag;
+
+ if (dq->head == dq->tail) /* null queue */
+ return NULL;
+
+ tag = dq->tag[dq->head & (ATA_MAX_QUEUE - 1)];
+ dq->tag[dq->head++ & (ATA_MAX_QUEUE - 1)] = ATA_TAG_POISON;
+ WARN_ON(!(dq->defer_bits & (1 << tag)));
+ dq->defer_bits &= ~(1 << tag);
+
+ return ata_qc_from_tag(ap, tag);
+}
+
+static void nv_swncq_fis_reinit(struct ata_port *ap)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+
+ pp->dhfis_bits = 0;
+ pp->dmafis_bits = 0;
+ pp->sdbfis_bits = 0;
+ pp->ncq_flags = 0;
+}
+
+static void nv_swncq_pp_reinit(struct ata_port *ap)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ struct defer_queue *dq = &pp->defer_queue;
+
+ dq->head = 0;
+ dq->tail = 0;
+ dq->defer_bits = 0;
+ pp->qc_active = 0;
+ pp->last_issue_tag = ATA_TAG_POISON;
+ nv_swncq_fis_reinit(ap);
+}
+
+static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+
+ writew(fis, pp->irq_block);
+}
+
+static void __ata_bmdma_stop(struct ata_port *ap)
+{
+ struct ata_queued_cmd qc;
+
+ qc.ap = ap;
+ ata_bmdma_stop(&qc);
+}
+
+static void nv_swncq_ncq_stop(struct ata_port *ap)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ unsigned int i;
+ u32 sactive;
+ u32 done_mask;
+
+ ata_port_printk(ap, KERN_ERR,
+ "EH in SWNCQ mode,QC:qc_active 0x%X sactive 0x%X\n",
+ ap->qc_active, ap->link.sactive);
+ ata_port_printk(ap, KERN_ERR,
+ "SWNCQ:qc_active 0x%X defer_bits 0x%X last_issue_tag 0x%x\n "
+ "dhfis 0x%X dmafis 0x%X sdbfis 0x%X\n",
+ pp->qc_active, pp->defer_queue.defer_bits, pp->last_issue_tag,
+ pp->dhfis_bits, pp->dmafis_bits, pp->sdbfis_bits);
+
+ ata_port_printk(ap, KERN_ERR, "ATA_REG 0x%X ERR_REG 0x%X\n",
+ ap->ops->check_status(ap),
+ ioread8(ap->ioaddr.error_addr));
+
+ sactive = readl(pp->sactive_block);
+ done_mask = pp->qc_active ^ sactive;
+
+ ata_port_printk(ap, KERN_ERR, "tag : dhfis dmafis sdbfis sacitve\n");
+ for (i = 0; i < ATA_MAX_QUEUE; i++) {
+ u8 err = 0;
+ if (pp->qc_active & (1 << i))
+ err = 0;
+ else if (done_mask & (1 << i))
+ err = 1;
+ else
+ continue;
+
+ ata_port_printk(ap, KERN_ERR,
+ "tag 0x%x: %01x %01x %01x %01x %s\n", i,
+ (pp->dhfis_bits >> i) & 0x1,
+ (pp->dmafis_bits >> i) & 0x1,
+ (pp->sdbfis_bits >> i) & 0x1,
+ (sactive >> i) & 0x1,
+ (err ? "error! tag doesn't exit" : " "));
+ }
+
+ nv_swncq_pp_reinit(ap);
+ ap->ops->irq_clear(ap);
+ __ata_bmdma_stop(ap);
+ nv_swncq_irq_clear(ap, 0xffff);
+}
+
+static void nv_swncq_error_handler(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->link.eh_context;
+
+ if (ap->link.sactive) {
+ nv_swncq_ncq_stop(ap);
+ ehc->i.action |= ATA_EH_HARDRESET;
}
ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset,
nv_hardreset, ata_std_postreset);
}
-static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+#ifdef CONFIG_PM
+static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg)
+{
+ void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+ u32 tmp;
+
+ /* clear irq */
+ writel(~0, mmio + NV_INT_STATUS_MCP55);
+
+ /* disable irq */
+ writel(0, mmio + NV_INT_ENABLE_MCP55);
+
+ /* disable swncq */
+ tmp = readl(mmio + NV_CTL_MCP55);
+ tmp &= ~(NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ);
+ writel(tmp, mmio + NV_CTL_MCP55);
+
+ return 0;
+}
+
+static int nv_swncq_port_resume(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+ u32 tmp;
+
+ /* clear irq */
+ writel(~0, mmio + NV_INT_STATUS_MCP55);
+
+ /* enable irq */
+ writel(0x00fd00fd, mmio + NV_INT_ENABLE_MCP55);
+
+ /* enable swncq */
+ tmp = readl(mmio + NV_CTL_MCP55);
+ writel(tmp | NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ, mmio + NV_CTL_MCP55);
+
+ return 0;
+}
+#endif
+
+static void nv_swncq_host_init(struct ata_host *host)
+{
+ u32 tmp;
+ void __iomem *mmio = host->iomap[NV_MMIO_BAR];
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ u8 regval;
+
+ /* disable ECO 398 */
+ pci_read_config_byte(pdev, 0x7f, &regval);
+ regval &= ~(1 << 7);
+ pci_write_config_byte(pdev, 0x7f, regval);
+
+ /* enable swncq */
+ tmp = readl(mmio + NV_CTL_MCP55);
+ VPRINTK("HOST_CTL:0x%X\n", tmp);
+ writel(tmp | NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ, mmio + NV_CTL_MCP55);
+
+ /* enable irq intr */
+ tmp = readl(mmio + NV_INT_ENABLE_MCP55);
+ VPRINTK("HOST_ENABLE:0x%X\n", tmp);
+ writel(tmp | 0x00fd00fd, mmio + NV_INT_ENABLE_MCP55);
+
+ /* clear port irq */
+ writel(~0x0, mmio + NV_INT_STATUS_MCP55);
+}
+
+static int nv_swncq_slave_config(struct scsi_device *sdev)
+{
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_device *dev;
+ int rc;
+ u8 rev;
+ u8 check_maxtor = 0;
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
+
+ rc = ata_scsi_slave_config(sdev);
+ if (sdev->id >= ATA_MAX_DEVICES || sdev->channel || sdev->lun)
+ /* Not a proper libata device, ignore */
+ return rc;
+
+ dev = &ap->link.device[sdev->id];
+ if (!(ap->flags & ATA_FLAG_NCQ) || dev->class == ATA_DEV_ATAPI)
+ return rc;
+
+ /* if MCP51 and Maxtor, then disable ncq */
+ if (pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA ||
+ pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2)
+ check_maxtor = 1;
+
+ /* if MCP55 and rev <= a2 and Maxtor, then disable ncq */
+ if (pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA ||
+ pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2) {
+ pci_read_config_byte(pdev, 0x8, &rev);
+ if (rev <= 0xa2)
+ check_maxtor = 1;
+ }
+
+ if (!check_maxtor)
+ return rc;
+
+ ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
+
+ if (strncmp(model_num, "Maxtor", 6) == 0) {
+ ata_scsi_change_queue_depth(sdev, 1);
+ ata_dev_printk(dev, KERN_NOTICE,
+ "Disabling SWNCQ mode (depth %x)\n", sdev->queue_depth);
+ }
+
+ return rc;
+}
+
+static int nv_swncq_port_start(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+ struct nv_swncq_port_priv *pp;
+ int rc;
+
+ rc = ata_port_start(ap);
+ if (rc)
+ return rc;
+
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+
+ pp->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE,
+ &pp->prd_dma, GFP_KERNEL);
+ if (!pp->prd)
+ return -ENOMEM;
+ memset(pp->prd, 0, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE);
+
+ ap->private_data = pp;
+ pp->sactive_block = ap->ioaddr.scr_addr + 4 * SCR_ACTIVE;
+ pp->irq_block = mmio + NV_INT_STATUS_MCP55 + ap->port_no * 2;
+ pp->tag_block = mmio + NV_NCQ_REG_MCP55 + ap->port_no * 2;
+
+ return 0;
+}
+
+static void nv_swncq_qc_prep(struct ata_queued_cmd *qc)
+{
+ if (qc->tf.protocol != ATA_PROT_NCQ) {
+ ata_qc_prep(qc);
+ return;
+ }
+
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
+
+ nv_swncq_fill_sg(qc);
+}
+
+static void nv_swncq_fill_sg(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scatterlist *sg;
+ unsigned int idx;
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ struct ata_prd *prd;
+
+ WARN_ON(qc->__sg == NULL);
+ WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+
+ prd = pp->prd + ATA_MAX_PRD * qc->tag;
+
+ idx = 0;
+ ata_for_each_sg(sg, qc) {
+ u32 addr, offset;
+ u32 sg_len, len;
+
+ addr = (u32)sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ while (sg_len) {
+ offset = addr & 0xffff;
+ len = sg_len;
+ if ((offset + sg_len) > 0x10000)
+ len = 0x10000 - offset;
+
+ prd[idx].addr = cpu_to_le32(addr);
+ prd[idx].flags_len = cpu_to_le32(len & 0xffff);
+
+ idx++;
+ sg_len -= len;
+ addr += len;
+ }
+ }
+
+ if (idx)
+ prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+}
+
+static unsigned int nv_swncq_issue_atacmd(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+
+ if (qc == NULL)
+ return 0;
+
+ DPRINTK("Enter\n");
+
+ writel((1 << qc->tag), pp->sactive_block);
+ pp->last_issue_tag = qc->tag;
+ pp->dhfis_bits &= ~(1 << qc->tag);
+ pp->dmafis_bits &= ~(1 << qc->tag);
+ pp->qc_active |= (0x1 << qc->tag);
+
+ ap->ops->tf_load(ap, &qc->tf); /* load tf registers */
+ ap->ops->exec_command(ap, &qc->tf);
+
+ DPRINTK("Issued tag %u\n", qc->tag);
+
+ return 0;
+}
+
+static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct nv_swncq_port_priv *pp = ap->private_data;
+
+ if (qc->tf.protocol != ATA_PROT_NCQ)
+ return ata_qc_issue_prot(qc);
+
+ DPRINTK("Enter\n");
+
+ if (!pp->qc_active)
+ nv_swncq_issue_atacmd(ap, qc);
+ else
+ nv_swncq_qc_to_dq(ap, qc); /* add qc to defer queue */
+
+ return 0;
+}
+
+static void nv_swncq_hotplug(struct ata_port *ap, u32 fis)
+{
+ u32 serror;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+
+ ata_ehi_clear_desc(ehi);
+
+ /* AHCI needs SError cleared; otherwise, it might lock up */
+ sata_scr_read(&ap->link, SCR_ERROR, &serror);
+ sata_scr_write(&ap->link, SCR_ERROR, serror);
+
+ /* analyze @irq_stat */
+ if (fis & NV_SWNCQ_IRQ_ADDED)
+ ata_ehi_push_desc(ehi, "hot plug");
+ else if (fis & NV_SWNCQ_IRQ_REMOVED)
+ ata_ehi_push_desc(ehi, "hot unplug");
+
+ ata_ehi_hotplugged(ehi);
+
+ /* okay, let's hand over to EH */
+ ehi->serror |= serror;
+
+ ata_port_freeze(ap);
+}
+
+static int nv_swncq_sdbfis(struct ata_port *ap)
+{
+ struct ata_queued_cmd *qc;
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ u32 sactive;
+ int nr_done = 0;
+ u32 done_mask;
+ int i;
+ u8 host_stat;
+ u8 lack_dhfis = 0;
+
+ host_stat = ap->ops->bmdma_status(ap);
+ if (unlikely(host_stat & ATA_DMA_ERR)) {
+ /* error when transfering data to/from memory */
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
+ ehi->err_mask |= AC_ERR_HOST_BUS;
+ ehi->action |= ATA_EH_SOFTRESET;
+ return -EINVAL;
+ }
+
+ ap->ops->irq_clear(ap);
+ __ata_bmdma_stop(ap);
+
+ sactive = readl(pp->sactive_block);
+ done_mask = pp->qc_active ^ sactive;
+
+ if (unlikely(done_mask & sactive)) {
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "illegal SWNCQ:qc_active transition"
+ "(%08x->%08x)", pp->qc_active, sactive);
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_HARDRESET;
+ return -EINVAL;
+ }
+ for (i = 0; i < ATA_MAX_QUEUE; i++) {
+ if (!(done_mask & (1 << i)))
+ continue;
+
+ qc = ata_qc_from_tag(ap, i);
+ if (qc) {
+ ata_qc_complete(qc);
+ pp->qc_active &= ~(1 << i);
+ pp->dhfis_bits &= ~(1 << i);
+ pp->dmafis_bits &= ~(1 << i);
+ pp->sdbfis_bits |= (1 << i);
+ nr_done++;
+ }
+ }
+
+ if (!ap->qc_active) {
+ DPRINTK("over\n");
+ nv_swncq_pp_reinit(ap);
+ return nr_done;
+ }
+
+ if (pp->qc_active & pp->dhfis_bits)
+ return nr_done;
+
+ if ((pp->ncq_flags & ncq_saw_backout) ||
+ (pp->qc_active ^ pp->dhfis_bits))
+ /* if the controller cann't get a device to host register FIS,
+ * The driver needs to reissue the new command.
+ */
+ lack_dhfis = 1;
+
+ DPRINTK("id 0x%x QC: qc_active 0x%x,"
+ "SWNCQ:qc_active 0x%X defer_bits %X "
+ "dhfis 0x%X dmafis 0x%X last_issue_tag %x\n",
+ ap->print_id, ap->qc_active, pp->qc_active,
+ pp->defer_queue.defer_bits, pp->dhfis_bits,
+ pp->dmafis_bits, pp->last_issue_tag);
+
+ nv_swncq_fis_reinit(ap);
+
+ if (lack_dhfis) {
+ qc = ata_qc_from_tag(ap, pp->last_issue_tag);
+ nv_swncq_issue_atacmd(ap, qc);
+ return nr_done;
+ }
+
+ if (pp->defer_queue.defer_bits) {
+ /* send deferral queue command */
+ qc = nv_swncq_qc_from_dq(ap);
+ WARN_ON(qc == NULL);
+ nv_swncq_issue_atacmd(ap, qc);
+ }
+
+ return nr_done;
+}
+
+static inline u32 nv_swncq_tag(struct ata_port *ap)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ u32 tag;
+
+ tag = readb(pp->tag_block) >> 2;
+ return (tag & 0x1f);
+}
+
+static int nv_swncq_dmafis(struct ata_port *ap)
{
- static int printed_version = 0;
+ struct ata_queued_cmd *qc;
+ unsigned int rw;
+ u8 dmactl;
+ u32 tag;
+ struct nv_swncq_port_priv *pp = ap->private_data;
+
+ __ata_bmdma_stop(ap);
+ tag = nv_swncq_tag(ap);
+
+ DPRINTK("dma setup tag 0x%x\n", tag);
+ qc = ata_qc_from_tag(ap, tag);
+
+ if (unlikely(!qc))
+ return 0;
+
+ rw = qc->tf.flags & ATA_TFLAG_WRITE;
+
+ /* load PRD table addr. */
+ iowrite32(pp->prd_dma + ATA_PRD_TBL_SZ * qc->tag,
+ ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+
+ /* specify data direction, triple-check start bit is clear */
+ dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+ dmactl &= ~ATA_DMA_WR;
+ if (!rw)
+ dmactl |= ATA_DMA_WR;
+
+ iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+ return 1;
+}
+
+static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
+{
+ struct nv_swncq_port_priv *pp = ap->private_data;
+ struct ata_queued_cmd *qc;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ u32 serror;
+ u8 ata_stat;
+ int rc = 0;
+
+ ata_stat = ap->ops->check_status(ap);
+ nv_swncq_irq_clear(ap, fis);
+ if (!fis)
+ return;
+
+ if (ap->pflags & ATA_PFLAG_FROZEN)
+ return;
+
+ if (fis & NV_SWNCQ_IRQ_HOTPLUG) {
+ nv_swncq_hotplug(ap, fis);
+ return;
+ }
+
+ if (!pp->qc_active)
+ return;
+
+ if (ap->ops->scr_read(ap, SCR_ERROR, &serror))
+ return;
+ ap->ops->scr_write(ap, SCR_ERROR, serror);
+
+ if (ata_stat & ATA_ERR) {
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "Ata error. fis:0x%X", fis);
+ ehi->err_mask |= AC_ERR_DEV;
+ ehi->serror |= serror;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ata_port_freeze(ap);
+ return;
+ }
+
+ if (fis & NV_SWNCQ_IRQ_BACKOUT) {
+ /* If the IRQ is backout, driver must issue
+ * the new command again some time later.
+ */
+ pp->ncq_flags |= ncq_saw_backout;
+ }
+
+ if (fis & NV_SWNCQ_IRQ_SDBFIS) {
+ pp->ncq_flags |= ncq_saw_sdb;
+ DPRINTK("id 0x%x SWNCQ: qc_active 0x%X "
+ "dhfis 0x%X dmafis 0x%X sactive 0x%X\n",
+ ap->print_id, pp->qc_active, pp->dhfis_bits,
+ pp->dmafis_bits, readl(pp->sactive_block));
+ rc = nv_swncq_sdbfis(ap);
+ if (rc < 0)
+ goto irq_error;
+ }
+
+ if (fis & NV_SWNCQ_IRQ_DHREGFIS) {
+ /* The interrupt indicates the new command
+ * was transmitted correctly to the drive.
+ */
+ pp->dhfis_bits |= (0x1 << pp->last_issue_tag);
+ pp->ncq_flags |= ncq_saw_d2h;
+ if (pp->ncq_flags & (ncq_saw_sdb | ncq_saw_backout)) {
+ ata_ehi_push_desc(ehi, "illegal fis transaction");
+ ehi->err_mask |= AC_ERR_HSM;
+ ehi->action |= ATA_EH_HARDRESET;
+ goto irq_error;
+ }
+
+ if (!(fis & NV_SWNCQ_IRQ_DMASETUP) &&
+ !(pp->ncq_flags & ncq_saw_dmas)) {
+ ata_stat = ap->ops->check_status(ap);
+ if (ata_stat & ATA_BUSY)
+ goto irq_exit;
+
+ if (pp->defer_queue.defer_bits) {
+ DPRINTK("send next command\n");
+ qc = nv_swncq_qc_from_dq(ap);
+ nv_swncq_issue_atacmd(ap, qc);
+ }
+ }
+ }
+
+ if (fis & NV_SWNCQ_IRQ_DMASETUP) {
+ /* program the dma controller with appropriate PRD buffers
+ * and start the DMA transfer for requested command.
+ */
+ pp->dmafis_bits |= (0x1 << nv_swncq_tag(ap));
+ pp->ncq_flags |= ncq_saw_dmas;
+ rc = nv_swncq_dmafis(ap);
+ }
+
+irq_exit:
+ return;
+irq_error:
+ ata_ehi_push_desc(ehi, "fis:0x%x", fis);
+ ata_port_freeze(ap);
+ return;
+}
+
+static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ unsigned int i;
+ unsigned int handled = 0;
+ unsigned long flags;
+ u32 irq_stat;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ irq_stat = readl(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_MCP55);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
+ if (ap->link.sactive) {
+ nv_swncq_host_interrupt(ap, (u16)irq_stat);
+ handled = 1;
+ } else {
+ if (irq_stat) /* reserve Hotplug */
+ nv_swncq_irq_clear(ap, 0xfff0);
+
+ handled += nv_host_intr(ap, (u8)irq_stat);
+ }
+ }
+ irq_stat >>= NV_INT_PORT_SHIFT_MCP55;
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
const struct ata_port_info *ppi[] = { NULL, NULL };
struct ata_host *host;
struct nv_host_priv *hpriv;
@@ -1546,7 +2368,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
// Make sure this is a SATA controller by counting the number of bars
// (NVIDIA SATA controllers will always have six bars). Otherwise,
// it's an IDE controller and we ignore it.
- for (bar=0; bar<6; bar++)
+ for (bar = 0; bar < 6; bar++)
if (pci_resource_start(pdev, bar) == 0)
return -ENODEV;
@@ -1558,11 +2380,19 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
/* determine type and allocate host */
- if (type >= CK804 && adma_enabled) {
+ if (type == CK804 && adma_enabled) {
dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n");
type = ADMA;
}
+ if (type == SWNCQ) {
+ if (swncq_enabled)
+ dev_printk(KERN_NOTICE, &pdev->dev,
+ "Using SWNCQ mode\n");
+ else
+ type = GENERIC;
+ }
+
ppi[0] = &nv_port_info[type];
rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
if (rc)
@@ -1604,7 +2434,8 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
rc = nv_adma_host_init(host);
if (rc)
return rc;
- }
+ } else if (type == SWNCQ)
+ nv_swncq_host_init(host);
pci_set_master(pdev);
return ata_host_activate(host, pdev->irq, ppi[0]->irq_handler,
@@ -1619,37 +2450,37 @@ static int nv_pci_device_resume(struct pci_dev *pdev)
int rc;
rc = ata_pci_device_do_resume(pdev);
- if(rc)
+ if (rc)
return rc;
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
- if(hpriv->type >= CK804) {
+ if (hpriv->type >= CK804) {
u8 regval;
pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
}
- if(hpriv->type == ADMA) {
+ if (hpriv->type == ADMA) {
u32 tmp32;
struct nv_adma_port_priv *pp;
/* enable/disable ADMA on the ports appropriately */
pci_read_config_dword(pdev, NV_MCP_SATA_CFG_20, &tmp32);
pp = host->ports[0]->private_data;
- if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
+ if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT0_EN |
- NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
+ NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
else
tmp32 |= (NV_MCP_SATA_CFG_20_PORT0_EN |
- NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
+ NV_MCP_SATA_CFG_20_PORT0_PWB_EN);
pp = host->ports[1]->private_data;
- if(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
+ if (pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE)
tmp32 &= ~(NV_MCP_SATA_CFG_20_PORT1_EN |
- NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
+ NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
else
tmp32 |= (NV_MCP_SATA_CFG_20_PORT1_EN |
- NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
+ NV_MCP_SATA_CFG_20_PORT1_PWB_EN);
pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32);
}
@@ -1703,3 +2534,6 @@ module_init(nv_init);
module_exit(nv_exit);
module_param_named(adma, adma_enabled, bool, 0444);
MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)");
+module_param_named(swncq, swncq_enabled, bool, 0444);
+MODULE_PARM_DESC(swncq, "Enable use of SWNCQ (Default: false)");
+
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 25698cf0dce..7914def54fa 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -2,6 +2,7 @@
* sata_promise.c - Promise SATA
*
* Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Mikael Pettersson <mikpe@it.uu.se>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -45,11 +46,12 @@
#include "sata_promise.h"
#define DRV_NAME "sata_promise"
-#define DRV_VERSION "2.10"
+#define DRV_VERSION "2.11"
enum {
PDC_MAX_PORTS = 4,
PDC_MMIO_BAR = 3,
+ PDC_MAX_PRD = LIBATA_MAX_PRD - 1, /* -1 for ASIC PRD bug workaround */
/* register offsets */
PDC_FEATURE = 0x04, /* Feature/Error reg (per port) */
@@ -83,10 +85,12 @@ enum {
PDC_PCI_SYS_ERR = (1 << 22), /* PCI system error */
PDC1_PCI_PARITY_ERR = (1 << 23), /* PCI parity error (from SATA150 driver) */
PDC1_ERR_MASK = PDC1_PCI_PARITY_ERR,
- PDC2_ERR_MASK = PDC2_HTO_ERR | PDC2_ATA_HBA_ERR | PDC2_ATA_DMA_CNT_ERR,
- PDC_ERR_MASK = (PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR | PDC_OVERRUN_ERR
- | PDC_UNDERRUN_ERR | PDC_DRIVE_ERR | PDC_PCI_SYS_ERR
- | PDC1_ERR_MASK | PDC2_ERR_MASK),
+ PDC2_ERR_MASK = PDC2_HTO_ERR | PDC2_ATA_HBA_ERR |
+ PDC2_ATA_DMA_CNT_ERR,
+ PDC_ERR_MASK = PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR |
+ PDC_OVERRUN_ERR | PDC_UNDERRUN_ERR |
+ PDC_DRIVE_ERR | PDC_PCI_SYS_ERR |
+ PDC1_ERR_MASK | PDC2_ERR_MASK,
board_2037x = 0, /* FastTrak S150 TX2plus */
board_2037x_pata = 1, /* FastTrak S150 TX2plus PATA port */
@@ -155,7 +159,7 @@ static struct scsi_host_template pdc_ata_sht = {
.queuecommand = ata_scsi_queuecmd,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = LIBATA_MAX_PRD,
+ .sg_tablesize = PDC_MAX_PRD,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
@@ -167,7 +171,6 @@ static struct scsi_host_template pdc_ata_sht = {
};
static const struct ata_port_operations pdc_sata_ops = {
- .port_disable = ata_port_disable,
.tf_load = pdc_tf_load_mmio,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -185,7 +188,6 @@ static const struct ata_port_operations pdc_sata_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = pdc_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = pdc_sata_scr_read,
.scr_write = pdc_sata_scr_write,
@@ -194,7 +196,6 @@ static const struct ata_port_operations pdc_sata_ops = {
/* First-generation chips need a more restrictive ->check_atapi_dma op */
static const struct ata_port_operations pdc_old_sata_ops = {
- .port_disable = ata_port_disable,
.tf_load = pdc_tf_load_mmio,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -212,7 +213,6 @@ static const struct ata_port_operations pdc_old_sata_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = pdc_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = pdc_sata_scr_read,
.scr_write = pdc_sata_scr_write,
@@ -220,7 +220,6 @@ static const struct ata_port_operations pdc_old_sata_ops = {
};
static const struct ata_port_operations pdc_pata_ops = {
- .port_disable = ata_port_disable,
.tf_load = pdc_tf_load_mmio,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -238,13 +237,12 @@ static const struct ata_port_operations pdc_pata_ops = {
.data_xfer = ata_data_xfer,
.irq_clear = pdc_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = pdc_common_port_start,
};
static const struct ata_port_info pdc_port_info[] = {
- /* board_2037x */
+ [board_2037x] =
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
PDC_FLAG_SATA_PATA,
@@ -254,7 +252,7 @@ static const struct ata_port_info pdc_port_info[] = {
.port_ops = &pdc_old_sata_ops,
},
- /* board_2037x_pata */
+ [board_2037x_pata] =
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f, /* pio0-4 */
@@ -263,7 +261,7 @@ static const struct ata_port_info pdc_port_info[] = {
.port_ops = &pdc_pata_ops,
},
- /* board_20319 */
+ [board_20319] =
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
PDC_FLAG_4_PORTS,
@@ -273,7 +271,7 @@ static const struct ata_port_info pdc_port_info[] = {
.port_ops = &pdc_old_sata_ops,
},
- /* board_20619 */
+ [board_20619] =
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
PDC_FLAG_4_PORTS,
@@ -283,7 +281,7 @@ static const struct ata_port_info pdc_port_info[] = {
.port_ops = &pdc_pata_ops,
},
- /* board_2057x */
+ [board_2057x] =
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA,
@@ -293,7 +291,7 @@ static const struct ata_port_info pdc_port_info[] = {
.port_ops = &pdc_sata_ops,
},
- /* board_2057x_pata */
+ [board_2057x_pata] =
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
PDC_FLAG_GEN_II,
@@ -303,7 +301,7 @@ static const struct ata_port_info pdc_port_info[] = {
.port_ops = &pdc_pata_ops,
},
- /* board_40518 */
+ [board_40518] =
{
.flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS,
@@ -475,7 +473,7 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
buf32[2] = 0; /* no next-packet */
/* select drive */
- if (sata_scr_valid(ap)) {
+ if (sata_scr_valid(&ap->link)) {
dev_sel = PDC_DEVICE_SATA;
} else {
dev_sel = ATA_DEVICE_OBS;
@@ -527,6 +525,84 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
memcpy(buf+31, cdb, cdb_len);
}
+/**
+ * pdc_fill_sg - Fill PCI IDE PRD table
+ * @qc: Metadata associated with taskfile to be transferred
+ *
+ * Fill PCI IDE PRD (scatter-gather) table with segments
+ * associated with the current disk command.
+ * Make sure hardware does not choke on it.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ */
+static void pdc_fill_sg(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct scatterlist *sg;
+ unsigned int idx;
+ const u32 SG_COUNT_ASIC_BUG = 41*4;
+
+ if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+ return;
+
+ WARN_ON(qc->__sg == NULL);
+ WARN_ON(qc->n_elem == 0 && qc->pad_len == 0);
+
+ idx = 0;
+ ata_for_each_sg(sg, qc) {
+ u32 addr, offset;
+ u32 sg_len, len;
+
+ /* determine if physical DMA addr spans 64K boundary.
+ * Note h/w doesn't support 64-bit, so we unconditionally
+ * truncate dma_addr_t to u32.
+ */
+ addr = (u32) sg_dma_address(sg);
+ sg_len = sg_dma_len(sg);
+
+ while (sg_len) {
+ offset = addr & 0xffff;
+ len = sg_len;
+ if ((offset + sg_len) > 0x10000)
+ len = 0x10000 - offset;
+
+ ap->prd[idx].addr = cpu_to_le32(addr);
+ ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+
+ idx++;
+ sg_len -= len;
+ addr += len;
+ }
+ }
+
+ if (idx) {
+ u32 len = le32_to_cpu(ap->prd[idx - 1].flags_len);
+
+ if (len > SG_COUNT_ASIC_BUG) {
+ u32 addr;
+
+ VPRINTK("Splitting last PRD.\n");
+
+ addr = le32_to_cpu(ap->prd[idx - 1].addr);
+ ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG);
+
+ addr = addr + len - SG_COUNT_ASIC_BUG;
+ len = SG_COUNT_ASIC_BUG;
+ ap->prd[idx].addr = cpu_to_le32(addr);
+ ap->prd[idx].flags_len = cpu_to_le32(len);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+
+ idx++;
+ }
+
+ ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+ }
+}
+
static void pdc_qc_prep(struct ata_queued_cmd *qc)
{
struct pdc_port_priv *pp = qc->ap->private_data;
@@ -536,7 +612,7 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
- ata_qc_prep(qc);
+ pdc_fill_sg(qc);
/* fall through */
case ATA_PROT_NODATA:
@@ -552,11 +628,11 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
break;
case ATA_PROT_ATAPI:
- ata_qc_prep(qc);
+ pdc_fill_sg(qc);
break;
case ATA_PROT_ATAPI_DMA:
- ata_qc_prep(qc);
+ pdc_fill_sg(qc);
/*FALLTHROUGH*/
case ATA_PROT_ATAPI_NODATA:
pdc_atapi_pkt(qc);
@@ -626,7 +702,7 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
u32 port_status, u32 err_mask)
{
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
unsigned int ac_err_mask = 0;
ata_ehi_clear_desc(ehi);
@@ -643,7 +719,7 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
| PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
ac_err_mask |= AC_ERR_HOST_BUS;
- if (sata_scr_valid(ap)) {
+ if (sata_scr_valid(&ap->link)) {
u32 serror;
pdc_sata_scr_read(ap, SCR_ERROR, &serror);
@@ -701,19 +777,20 @@ static void pdc_irq_clear(struct ata_port *ap)
readl(mmio + PDC_INT_SEQMASK);
}
-static inline int pdc_is_sataii_tx4(unsigned long flags)
+static int pdc_is_sataii_tx4(unsigned long flags)
{
const unsigned long mask = PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS;
return (flags & mask) == mask;
}
-static inline unsigned int pdc_port_no_to_ata_no(unsigned int port_no, int is_sataii_tx4)
+static unsigned int pdc_port_no_to_ata_no(unsigned int port_no,
+ int is_sataii_tx4)
{
static const unsigned char sataii_tx4_port_remap[4] = { 3, 1, 0, 2};
return is_sataii_tx4 ? sataii_tx4_port_remap[port_no] : port_no;
}
-static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
+static irqreturn_t pdc_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
struct ata_port *ap;
@@ -773,7 +850,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
tmp = hotplug_status & (0x11 << ata_no);
if (tmp && ap &&
!(ap->flags & ATA_FLAG_DISABLED)) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
ata_ehi_clear_desc(ehi);
ata_ehi_hotplugged(ehi);
ata_ehi_push_desc(ehi, "hotplug_status %#x", tmp);
@@ -788,7 +865,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += pdc_host_intr(ap, qc);
}
@@ -845,15 +922,16 @@ static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
{
- WARN_ON (tf->protocol == ATA_PROT_DMA ||
- tf->protocol == ATA_PROT_ATAPI_DMA);
+ WARN_ON(tf->protocol == ATA_PROT_DMA ||
+ tf->protocol == ATA_PROT_ATAPI_DMA);
ata_tf_load(ap, tf);
}
-static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
+static void pdc_exec_command_mmio(struct ata_port *ap,
+ const struct ata_taskfile *tf)
{
- WARN_ON (tf->protocol == ATA_PROT_DMA ||
- tf->protocol == ATA_PROT_ATAPI_DMA);
+ WARN_ON(tf->protocol == ATA_PROT_DMA ||
+ tf->protocol == ATA_PROT_ATAPI_DMA);
ata_exec_command(ap, tf);
}
@@ -876,8 +954,11 @@ static int pdc_check_atapi_dma(struct ata_queued_cmd *qc)
}
/* -45150 (FFFF4FA2) to -1 (FFFFFFFF) shall use PIO mode */
if (scsicmd[0] == WRITE_10) {
- unsigned int lba;
- lba = (scsicmd[2] << 24) | (scsicmd[3] << 16) | (scsicmd[4] << 8) | scsicmd[5];
+ unsigned int lba =
+ (scsicmd[2] << 24) |
+ (scsicmd[3] << 16) |
+ (scsicmd[4] << 8) |
+ scsicmd[5];
if (lba >= 0xFFFF4FA2)
pio = 1;
}
@@ -962,7 +1043,8 @@ static void pdc_host_init(struct ata_host *host)
writel(tmp, mmio + PDC_SLEW_CTL);
}
-static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+static int pdc_ata_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
static int printed_version;
const struct ata_port_info *pi = &pdc_port_info[ent->driver_data];
@@ -1009,10 +1091,15 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags);
for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);
- pdc_ata_setup_port(host->ports[i],
- base + 0x200 + ata_no * 0x80,
- base + 0x400 + ata_no * 0x100);
+ unsigned int port_offset = 0x200 + ata_no * 0x80;
+ unsigned int scr_offset = 0x400 + ata_no * 0x100;
+
+ pdc_ata_setup_port(ap, base + port_offset, base + scr_offset);
+
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port");
}
/* initialize adapter */
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 5e1dfdda698..2f1de6ec044 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -103,7 +103,7 @@ enum {
QS_DMA_BOUNDARY = ~0UL
};
-typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t;
+typedef enum { qs_state_mmio, qs_state_pkt } qs_state_t;
struct qs_port_priv {
u8 *pkt;
@@ -113,17 +113,18 @@ struct qs_port_priv {
static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
-static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int qs_port_start(struct ata_port *ap);
static void qs_host_stop(struct ata_host *host);
-static void qs_phy_reset(struct ata_port *ap);
static void qs_qc_prep(struct ata_queued_cmd *qc);
static unsigned int qs_qc_issue(struct ata_queued_cmd *qc);
static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
static void qs_bmdma_stop(struct ata_queued_cmd *qc);
static u8 qs_bmdma_status(struct ata_port *ap);
static void qs_irq_clear(struct ata_port *ap);
-static void qs_eng_timeout(struct ata_port *ap);
+static void qs_freeze(struct ata_port *ap);
+static void qs_thaw(struct ata_port *ap);
+static void qs_error_handler(struct ata_port *ap);
static struct scsi_host_template qs_ata_sht = {
.module = THIS_MODULE,
@@ -135,7 +136,6 @@ static struct scsi_host_template qs_ata_sht = {
.sg_tablesize = QS_MAX_PRD,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
- //FIXME .use_clustering = ATA_SHT_USE_CLUSTERING,
.use_clustering = ENABLE_CLUSTERING,
.proc_name = DRV_NAME,
.dma_boundary = QS_DMA_BOUNDARY,
@@ -145,21 +145,20 @@ static struct scsi_host_template qs_ata_sht = {
};
static const struct ata_port_operations qs_ata_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
.check_atapi_dma = qs_check_atapi_dma,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .phy_reset = qs_phy_reset,
.qc_prep = qs_qc_prep,
.qc_issue = qs_qc_issue,
.data_xfer = ata_data_xfer,
- .eng_timeout = qs_eng_timeout,
+ .freeze = qs_freeze,
+ .thaw = qs_thaw,
+ .error_handler = qs_error_handler,
.irq_clear = qs_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = qs_scr_read,
.scr_write = qs_scr_write,
.port_start = qs_port_start,
@@ -172,8 +171,6 @@ static const struct ata_port_info qs_port_info[] = {
/* board_2068_idx */
{
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SATA_RESET |
- //FIXME ATA_FLAG_SRST |
ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
.pio_mask = 0x10, /* pio4 */
.udma_mask = ATA_UDMA6,
@@ -222,7 +219,9 @@ static void qs_irq_clear(struct ata_port *ap)
static inline void qs_enter_reg_mode(struct ata_port *ap)
{
u8 __iomem *chan = qs_mmio_base(ap->host) + (ap->port_no * 0x4000);
+ struct qs_port_priv *pp = ap->private_data;
+ pp->state = qs_state_mmio;
writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
readb(chan + QS_CCT_CTR0); /* flush */
}
@@ -236,23 +235,28 @@ static inline void qs_reset_channel_logic(struct ata_port *ap)
qs_enter_reg_mode(ap);
}
-static void qs_phy_reset(struct ata_port *ap)
+static void qs_freeze(struct ata_port *ap)
{
- struct qs_port_priv *pp = ap->private_data;
+ u8 __iomem *mmio_base = qs_mmio_base(ap->host);
- pp->state = qs_state_idle;
- qs_reset_channel_logic(ap);
- sata_phy_reset(ap);
+ writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
+ qs_enter_reg_mode(ap);
}
-static void qs_eng_timeout(struct ata_port *ap)
+static void qs_thaw(struct ata_port *ap)
{
- struct qs_port_priv *pp = ap->private_data;
+ u8 __iomem *mmio_base = qs_mmio_base(ap->host);
+
+ qs_enter_reg_mode(ap);
+ writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */
+}
+
+static int qs_prereset(struct ata_link *link, unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
- if (pp->state != qs_state_idle) /* healthy paranoia */
- pp->state = qs_state_mmio;
qs_reset_channel_logic(ap);
- ata_eng_timeout(ap);
+ return ata_std_prereset(link, deadline);
}
static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
@@ -263,6 +267,13 @@ static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
return 0;
}
+static void qs_error_handler(struct ata_port *ap)
+{
+ qs_enter_reg_mode(ap);
+ ata_do_eh(ap, qs_prereset, ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
@@ -361,7 +372,6 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
-
pp->state = qs_state_pkt;
qs_packet_start(qc);
return 0;
@@ -378,6 +388,26 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
return ata_qc_issue_prot(qc);
}
+static void qs_do_or_die(struct ata_queued_cmd *qc, u8 status)
+{
+ qc->err_mask |= ac_err_mask(status);
+
+ if (!qc->err_mask) {
+ ata_qc_complete(qc);
+ } else {
+ struct ata_port *ap = qc->ap;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "status 0x%02X", status);
+
+ if (qc->err_mask == AC_ERR_DEV)
+ ata_port_abort(ap);
+ else
+ ata_port_freeze(ap);
+ }
+}
+
static inline unsigned int qs_intr_pkt(struct ata_host *host)
{
unsigned int handled = 0;
@@ -404,15 +434,13 @@ static inline unsigned int qs_intr_pkt(struct ata_host *host)
struct qs_port_priv *pp = ap->private_data;
if (!pp || pp->state != qs_state_pkt)
continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
switch (sHST) {
case 0: /* successful CPB */
case 3: /* device error */
- pp->state = qs_state_idle;
qs_enter_reg_mode(qc->ap);
- qc->err_mask |= ac_err_mask(sDST);
- ata_qc_complete(qc);
+ qs_do_or_die(qc, sDST);
break;
default:
break;
@@ -434,25 +462,27 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host)
if (ap &&
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
- struct qs_port_priv *pp = ap->private_data;
- if (!pp || pp->state != qs_state_mmio)
- continue;
- qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
-
- /* check main status, clearing INTRQ */
- u8 status = ata_check_status(ap);
- if ((status & ATA_BUSY))
- continue;
- DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
- ap->print_id, qc->tf.protocol, status);
-
- /* complete taskfile transaction */
- pp->state = qs_state_idle;
- qc->err_mask |= ac_err_mask(status);
- ata_qc_complete(qc);
+ struct qs_port_priv *pp;
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (!qc || !(qc->flags & ATA_QCFLAG_ACTIVE)) {
+ /*
+ * The qstor hardware generates spurious
+ * interrupts from time to time when switching
+ * in and out of packet mode.
+ * There's no obvious way to know if we're
+ * here now due to that, so just ack the irq
+ * and pretend we knew it was ours.. (ugh).
+ * This does not affect packet mode.
+ */
+ ata_check_status(ap);
handled = 1;
+ continue;
}
+ pp = ap->private_data;
+ if (!pp || pp->state != qs_state_mmio)
+ continue;
+ if (!(qc->tf.flags & ATA_TFLAG_POLLING))
+ handled |= ata_host_intr(ap, qc);
}
}
return handled;
@@ -462,12 +492,13 @@ static irqreturn_t qs_intr(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
unsigned int handled = 0;
+ unsigned long flags;
VPRINTK("ENTER\n");
- spin_lock(&host->lock);
+ spin_lock_irqsave(&host->lock, flags);
handled = qs_intr_pkt(host) | qs_intr_mmio(host);
- spin_unlock(&host->lock);
+ spin_unlock_irqrestore(&host->lock, flags);
VPRINTK("EXIT\n");
@@ -504,7 +535,6 @@ static int qs_port_start(struct ata_port *ap)
rc = ata_port_start(ap);
if (rc)
return rc;
- qs_enter_reg_mode(ap);
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
@@ -515,6 +545,7 @@ static int qs_port_start(struct ata_port *ap)
memset(pp->pkt, 0, QS_PKT_BYTES);
ap->private_data = pp;
+ qs_enter_reg_mode(ap);
addr = (u64)pp->pkt_dma;
writel((u32) addr, chan + QS_CCF_CPBA);
writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4);
@@ -637,9 +668,14 @@ static int qs_ata_init_one(struct pci_dev *pdev,
return rc;
for (port_no = 0; port_no < host->n_ports; ++port_no) {
- void __iomem *chan =
- host->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
- qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan);
+ struct ata_port *ap = host->ports[port_no];
+ unsigned int offset = port_no * 0x4000;
+ void __iomem *chan = host->iomap[QS_MMIO_BAR] + offset;
+
+ qs_ata_setup_port(&ap->ioaddr, chan);
+
+ ata_port_pbar_desc(ap, QS_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, QS_MMIO_BAR, offset, "port");
}
/* initialize adapter */
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 8c72e714b45..4e6e381279c 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -59,7 +59,8 @@ enum {
SIL_FLAG_MOD15WRITE = (1 << 30),
SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME,
+ ATA_FLAG_MMIO,
+ SIL_DFL_LINK_FLAGS = ATA_LFLAG_HRST_TO_RESUME,
/*
* Controller IDs
@@ -110,14 +111,14 @@ enum {
SIL_QUIRK_UDMA5MAX = (1 << 1),
};
-static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
#ifdef CONFIG_PM
static int sil_pci_device_resume(struct pci_dev *pdev);
#endif
static void sil_dev_config(struct ata_device *dev);
static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
-static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
+static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);
static void sil_freeze(struct ata_port *ap);
static void sil_thaw(struct ata_port *ap);
@@ -137,7 +138,7 @@ static const struct pci_device_id sil_pci_tbl[] = {
/* TODO firmware versions should be added - eric */
static const struct sil_drivelist {
- const char * product;
+ const char *product;
unsigned int quirk;
} sil_blacklist [] = {
{ "ST320012AS", SIL_QUIRK_MOD15WRITE },
@@ -185,7 +186,6 @@ static struct scsi_host_template sil_sht = {
};
static const struct ata_port_operations sil_ops = {
- .port_disable = ata_port_disable,
.dev_config = sil_dev_config,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -206,7 +206,6 @@ static const struct ata_port_operations sil_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = sil_scr_read,
.scr_write = sil_scr_write,
.port_start = ata_port_start,
@@ -216,6 +215,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3112 */
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
+ .link_flags = SIL_DFL_LINK_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5,
@@ -225,6 +225,7 @@ static const struct ata_port_info sil_port_info[] = {
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
SIL_FLAG_NO_SATA_IRQ,
+ .link_flags = SIL_DFL_LINK_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5,
@@ -233,6 +234,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3512 */
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+ .link_flags = SIL_DFL_LINK_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5,
@@ -241,6 +243,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3114 */
{
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+ .link_flags = SIL_DFL_LINK_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5,
@@ -276,7 +279,7 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, sil_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-static int slow_down = 0;
+static int slow_down;
module_param(slow_down, int, 0444);
MODULE_PARM_DESC(slow_down, "Sledgehammer used to work around random problems, by limiting commands to 15 sectors (0=off, 1=on)");
@@ -290,35 +293,33 @@ static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
/**
* sil_set_mode - wrap set_mode functions
- * @ap: port to set up
+ * @link: link to set up
* @r_failed: returned device when we fail
*
* Wrap the libata method for device setup as after the setup we need
* to inspect the results and do some configuration work
*/
-static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed)
+static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed)
{
- struct ata_host *host = ap->host;
- struct ata_device *dev;
- void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
+ struct ata_port *ap = link->ap;
+ void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode;
- u32 tmp, dev_mode[2];
- unsigned int i;
+ struct ata_device *dev;
+ u32 tmp, dev_mode[2] = { };
int rc;
- rc = ata_do_set_mode(ap, r_failed);
+ rc = ata_do_set_mode(link, r_failed);
if (rc)
return rc;
- for (i = 0; i < 2; i++) {
- dev = &ap->device[i];
+ ata_link_for_each_dev(dev, link) {
if (!ata_dev_enabled(dev))
- dev_mode[i] = 0; /* PIO0/1/2 */
+ dev_mode[dev->devno] = 0; /* PIO0/1/2 */
else if (dev->flags & ATA_DFLAG_PIO)
- dev_mode[i] = 1; /* PIO3/4 */
+ dev_mode[dev->devno] = 1; /* PIO3/4 */
else
- dev_mode[i] = 3; /* UDMA */
+ dev_mode[dev->devno] = 3; /* UDMA */
/* value 2 indicates MDMA */
}
@@ -331,7 +332,8 @@ static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed)
return 0;
}
-static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
+static inline void __iomem *sil_scr_addr(struct ata_port *ap,
+ unsigned int sc_reg)
{
void __iomem *offset = ap->ioaddr.scr_addr;
@@ -374,8 +376,8 @@ static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
{
- struct ata_eh_info *ehi = &ap->eh_info;
- struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
u8 status;
if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
@@ -394,8 +396,8 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* repeat probing needlessly.
*/
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
- ata_ehi_hotplugged(&ap->eh_info);
- ap->eh_info.serror |= serror;
+ ata_ehi_hotplugged(&ap->link.eh_info);
+ ap->link.eh_info.serror |= serror;
}
goto freeze;
@@ -562,8 +564,8 @@ static void sil_thaw(struct ata_port *ap)
*/
static void sil_dev_config(struct ata_device *dev)
{
- struct ata_port *ap = dev->ap;
- int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO;
+ struct ata_port *ap = dev->link->ap;
+ int print_info = ap->link.eh_context.i.flags & ATA_EHI_PRINTINFO;
unsigned int n, quirks = 0;
unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -642,7 +644,7 @@ static void sil_init_controller(struct ata_host *host)
}
}
-static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
int board_id = ent->driver_data;
@@ -686,7 +688,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
mmio_base = host->iomap[SIL_MMIO_BAR];
for (i = 0; i < host->n_ports; i++) {
- struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+ struct ata_port *ap = host->ports[i];
+ struct ata_ioports *ioaddr = &ap->ioaddr;
ioaddr->cmd_addr = mmio_base + sil_port[i].tf;
ioaddr->altstatus_addr =
@@ -694,6 +697,9 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma;
ioaddr->scr_addr = mmio_base + sil_port[i].scr;
ata_std_ports(ioaddr);
+
+ ata_port_pbar_desc(ap, SIL_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, SIL_MMIO_BAR, sil_port[i].tf, "tf");
}
/* initialize and activate */
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 233e8869339..187dcb02c68 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -30,7 +30,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_sil24"
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.1"
/*
* Port request block (PRB) 32 bytes
@@ -168,7 +168,7 @@ enum {
DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
- PORT_IRQ_UNK_FIS,
+ PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY,
/* bits[27:16] are unmasked (raw) */
PORT_IRQ_RAW_SHIFT = 16,
@@ -237,8 +237,9 @@ enum {
/* host flags */
SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY |
- ATA_FLAG_ACPI_SATA,
+ ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA |
+ ATA_FLAG_AN | ATA_FLAG_PMP,
+ SIL24_COMMON_LFLAGS = ATA_LFLAG_SKIP_D2H_BSY,
SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
IRQ_STAT_4PORTS = 0xf,
@@ -264,11 +265,11 @@ static struct sil24_cerr_info {
unsigned int err_mask, action;
const char *desc;
} sil24_cerr_db[] = {
- [0] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
+ [0] = { AC_ERR_DEV, 0,
"device error" },
- [PORT_CERR_DEV] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
+ [PORT_CERR_DEV] = { AC_ERR_DEV, 0,
"device error via D2H FIS" },
- [PORT_CERR_SDB] = { AC_ERR_DEV, ATA_EH_REVALIDATE,
+ [PORT_CERR_SDB] = { AC_ERR_DEV, 0,
"device error via SDB FIS" },
[PORT_CERR_DATA] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET,
"error in data FIS" },
@@ -322,6 +323,7 @@ struct sil24_port_priv {
union sil24_cmd_block *cmd_block; /* 32 cmd blocks */
dma_addr_t cmd_block_dma; /* DMA base addr for them */
struct ata_taskfile tf; /* Cached taskfile registers */
+ int do_port_rst;
};
static void sil24_dev_config(struct ata_device *dev);
@@ -329,9 +331,12 @@ static u8 sil24_check_status(struct ata_port *ap);
static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+static int sil24_qc_defer(struct ata_queued_cmd *qc);
static void sil24_qc_prep(struct ata_queued_cmd *qc);
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
static void sil24_irq_clear(struct ata_port *ap);
+static void sil24_pmp_attach(struct ata_port *ap);
+static void sil24_pmp_detach(struct ata_port *ap);
static void sil24_freeze(struct ata_port *ap);
static void sil24_thaw(struct ata_port *ap);
static void sil24_error_handler(struct ata_port *ap);
@@ -340,6 +345,7 @@ static int sil24_port_start(struct ata_port *ap);
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
#ifdef CONFIG_PM
static int sil24_pci_device_resume(struct pci_dev *pdev);
+static int sil24_port_resume(struct ata_port *ap);
#endif
static const struct pci_device_id sil24_pci_tbl[] = {
@@ -384,8 +390,6 @@ static struct scsi_host_template sil24_sht = {
};
static const struct ata_port_operations sil24_ops = {
- .port_disable = ata_port_disable,
-
.dev_config = sil24_dev_config,
.check_status = sil24_check_status,
@@ -394,22 +398,28 @@ static const struct ata_port_operations sil24_ops = {
.tf_read = sil24_tf_read,
+ .qc_defer = sil24_qc_defer,
.qc_prep = sil24_qc_prep,
.qc_issue = sil24_qc_issue,
.irq_clear = sil24_irq_clear,
- .irq_on = ata_dummy_irq_on,
- .irq_ack = ata_dummy_irq_ack,
.scr_read = sil24_scr_read,
.scr_write = sil24_scr_write,
+ .pmp_attach = sil24_pmp_attach,
+ .pmp_detach = sil24_pmp_detach,
+
.freeze = sil24_freeze,
.thaw = sil24_thaw,
.error_handler = sil24_error_handler,
.post_internal_cmd = sil24_post_internal_cmd,
.port_start = sil24_port_start,
+
+#ifdef CONFIG_PM
+ .port_resume = sil24_port_resume,
+#endif
};
/*
@@ -424,6 +434,7 @@ static const struct ata_port_info sil24_port_info[] = {
{
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
SIL24_FLAG_PCIX_IRQ_WOC,
+ .link_flags = SIL24_COMMON_LFLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5, /* udma0-5 */
@@ -432,6 +443,7 @@ static const struct ata_port_info sil24_port_info[] = {
/* sil_3132 */
{
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
+ .link_flags = SIL24_COMMON_LFLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5, /* udma0-5 */
@@ -440,6 +452,7 @@ static const struct ata_port_info sil24_port_info[] = {
/* sil_3131/sil_3531 */
{
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
+ .link_flags = SIL24_COMMON_LFLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = ATA_UDMA5, /* udma0-5 */
@@ -456,7 +469,7 @@ static int sil24_tag(int tag)
static void sil24_dev_config(struct ata_device *dev)
{
- void __iomem *port = dev->ap->ioaddr.cmd_addr;
+ void __iomem *port = dev->link->ap->ioaddr.cmd_addr;
if (dev->cdb_len == 16)
writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
@@ -520,19 +533,78 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
*tf = pp->tf;
}
+static void sil24_config_port(struct ata_port *ap)
+{
+ void __iomem *port = ap->ioaddr.cmd_addr;
+
+ /* configure IRQ WoC */
+ if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+ else
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+ /* zero error counters. */
+ writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+ writel(0x8000, port + PORT_CRC_ERR_THRESH);
+ writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+ writel(0x0000, port + PORT_DECODE_ERR_CNT);
+ writel(0x0000, port + PORT_CRC_ERR_CNT);
+ writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+ /* always use 64bit activation */
+ writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+ /* clear port multiplier enable and resume bits */
+ writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
+}
+
+static void sil24_config_pmp(struct ata_port *ap, int attached)
+{
+ void __iomem *port = ap->ioaddr.cmd_addr;
+
+ if (attached)
+ writel(PORT_CS_PMP_EN, port + PORT_CTRL_STAT);
+ else
+ writel(PORT_CS_PMP_EN, port + PORT_CTRL_CLR);
+}
+
+static void sil24_clear_pmp(struct ata_port *ap)
+{
+ void __iomem *port = ap->ioaddr.cmd_addr;
+ int i;
+
+ writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
+
+ for (i = 0; i < SATA_PMP_MAX_PORTS; i++) {
+ void __iomem *pmp_base = port + PORT_PMP + i * PORT_PMP_SIZE;
+
+ writel(0, pmp_base + PORT_PMP_STATUS);
+ writel(0, pmp_base + PORT_PMP_QACTIVE);
+ }
+}
+
static int sil24_init_port(struct ata_port *ap)
{
void __iomem *port = ap->ioaddr.cmd_addr;
+ struct sil24_port_priv *pp = ap->private_data;
u32 tmp;
+ /* clear PMP error status */
+ if (ap->nr_pmp_links)
+ sil24_clear_pmp(ap);
+
writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
ata_wait_register(port + PORT_CTRL_STAT,
PORT_CS_INIT, PORT_CS_INIT, 10, 100);
tmp = ata_wait_register(port + PORT_CTRL_STAT,
PORT_CS_RDY, 0, 10, 100);
- if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
+ if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) {
+ pp->do_port_rst = 1;
+ ap->link.eh_context.i.action |= ATA_EH_HARDRESET;
return -EIO;
+ }
+
return 0;
}
@@ -583,9 +655,10 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
return rc;
}
-static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
+static int sil24_do_softreset(struct ata_link *link, unsigned int *class,
int pmp, unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
unsigned long timeout_msec = 0;
struct ata_taskfile tf;
const char *reason;
@@ -593,7 +666,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
DPRINTK("ENTER\n");
- if (ata_port_offline(ap)) {
+ if (ata_link_offline(link)) {
DPRINTK("PHY reports no device\n");
*class = ATA_DEV_NONE;
goto out;
@@ -601,7 +674,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
/* put the port into known state */
if (sil24_init_port(ap)) {
- reason ="port not ready";
+ reason = "port not ready";
goto err;
}
@@ -609,7 +682,7 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
if (time_after(deadline, jiffies))
timeout_msec = jiffies_to_msecs(deadline - jiffies);
- ata_tf_init(ap->device, &tf); /* doesn't really matter */
+ ata_tf_init(link->device, &tf); /* doesn't really matter */
rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,
timeout_msec);
if (rc == -EBUSY) {
@@ -631,46 +704,72 @@ static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
return 0;
err:
- ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+ ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
return -EIO;
}
-static int sil24_softreset(struct ata_port *ap, unsigned int *class,
+static int sil24_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
- return sil24_do_softreset(ap, class, 0, deadline);
+ return sil24_do_softreset(link, class, SATA_PMP_CTRL_PORT, deadline);
}
-static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
+static int sil24_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
+ struct ata_port *ap = link->ap;
void __iomem *port = ap->ioaddr.cmd_addr;
+ struct sil24_port_priv *pp = ap->private_data;
+ int did_port_rst = 0;
const char *reason;
int tout_msec, rc;
u32 tmp;
+ retry:
+ /* Sometimes, DEV_RST is not enough to recover the controller.
+ * This happens often after PM DMA CS errata.
+ */
+ if (pp->do_port_rst) {
+ ata_port_printk(ap, KERN_WARNING, "controller in dubious "
+ "state, performing PORT_RST\n");
+
+ writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT);
+ msleep(10);
+ writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+ ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
+ 10, 5000);
+
+ /* restore port configuration */
+ sil24_config_port(ap);
+ sil24_config_pmp(ap, ap->nr_pmp_links);
+
+ pp->do_port_rst = 0;
+ did_port_rst = 1;
+ }
+
/* sil24 does the right thing(tm) without any protection */
- sata_set_spd(ap);
+ sata_set_spd(link);
tout_msec = 100;
- if (ata_port_online(ap))
+ if (ata_link_online(link))
tout_msec = 5000;
writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
tmp = ata_wait_register(port + PORT_CTRL_STAT,
- PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10, tout_msec);
+ PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10,
+ tout_msec);
/* SStatus oscillates between zero and valid status after
* DEV_RST, debounce it.
*/
- rc = sata_phy_debounce(ap, sata_deb_timing_long, deadline);
+ rc = sata_link_debounce(link, sata_deb_timing_long, deadline);
if (rc) {
reason = "PHY debouncing failed";
goto err;
}
if (tmp & PORT_CS_DEV_RST) {
- if (ata_port_offline(ap))
+ if (ata_link_offline(link))
return 0;
reason = "link not ready";
goto err;
@@ -685,7 +784,12 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
return -EAGAIN;
err:
- ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
+ if (!did_port_rst) {
+ pp->do_port_rst = 1;
+ goto retry;
+ }
+
+ ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason);
return -EIO;
}
@@ -693,16 +797,51 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc,
struct sil24_sge *sge)
{
struct scatterlist *sg;
+ struct sil24_sge *last_sge = NULL;
ata_for_each_sg(sg, qc) {
sge->addr = cpu_to_le64(sg_dma_address(sg));
sge->cnt = cpu_to_le32(sg_dma_len(sg));
- if (ata_sg_is_last(sg, qc))
- sge->flags = cpu_to_le32(SGE_TRM);
- else
- sge->flags = 0;
+ sge->flags = 0;
+
+ last_sge = sge;
sge++;
}
+
+ if (likely(last_sge))
+ last_sge->flags = cpu_to_le32(SGE_TRM);
+}
+
+static int sil24_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_link *link = qc->dev->link;
+ struct ata_port *ap = link->ap;
+ u8 prot = qc->tf.protocol;
+ int is_atapi = (prot == ATA_PROT_ATAPI ||
+ prot == ATA_PROT_ATAPI_NODATA ||
+ prot == ATA_PROT_ATAPI_DMA);
+
+ /* ATAPI commands completing with CHECK_SENSE cause various
+ * weird problems if other commands are active. PMP DMA CS
+ * errata doesn't cover all and HSM violation occurs even with
+ * only one other device active. Always run an ATAPI command
+ * by itself.
+ */
+ if (unlikely(ap->excl_link)) {
+ if (link == ap->excl_link) {
+ if (ap->nr_active_links)
+ return ATA_DEFER_PORT;
+ qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+ } else
+ return ATA_DEFER_PORT;
+ } else if (unlikely(is_atapi)) {
+ ap->excl_link = link;
+ if (ap->nr_active_links)
+ return ATA_DEFER_PORT;
+ qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+ }
+
+ return ata_std_qc_defer(qc);
}
static void sil24_qc_prep(struct ata_queued_cmd *qc)
@@ -748,7 +887,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
}
prb->ctrl = cpu_to_le16(ctrl);
- ata_tf_to_fis(&qc->tf, 0, 1, prb->fis);
+ ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, prb->fis);
if (qc->flags & ATA_QCFLAG_DMAMAP)
sil24_fill_sg(qc, sge);
@@ -777,6 +916,39 @@ static void sil24_irq_clear(struct ata_port *ap)
/* unused */
}
+static void sil24_pmp_attach(struct ata_port *ap)
+{
+ sil24_config_pmp(ap, 1);
+ sil24_init_port(ap);
+}
+
+static void sil24_pmp_detach(struct ata_port *ap)
+{
+ sil24_init_port(ap);
+ sil24_config_pmp(ap, 0);
+}
+
+static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ return sil24_do_softreset(link, class, link->pmp, deadline);
+}
+
+static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ int rc;
+
+ rc = sil24_init_port(link->ap);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "hardreset failed (port not ready)\n");
+ return rc;
+ }
+
+ return sata_pmp_std_hardreset(link, class, deadline);
+}
+
static void sil24_freeze(struct ata_port *ap)
{
void __iomem *port = ap->ioaddr.cmd_addr;
@@ -804,8 +976,10 @@ static void sil24_error_intr(struct ata_port *ap)
{
void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
- struct ata_eh_info *ehi = &ap->eh_info;
- int freeze = 0;
+ struct ata_queued_cmd *qc = NULL;
+ struct ata_link *link;
+ struct ata_eh_info *ehi;
+ int abort = 0, freeze = 0;
u32 irq_stat;
/* on error, we need to clear IRQ explicitly */
@@ -813,10 +987,17 @@ static void sil24_error_intr(struct ata_port *ap)
writel(irq_stat, port + PORT_IRQ_STAT);
/* first, analyze and record host port events */
+ link = &ap->link;
+ ehi = &link->eh_info;
ata_ehi_clear_desc(ehi);
ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+ if (irq_stat & PORT_IRQ_SDB_NOTIFY) {
+ ata_ehi_push_desc(ehi, "SDB notify");
+ sata_async_notification(ap);
+ }
+
if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
ata_ehi_hotplugged(ehi);
ata_ehi_push_desc(ehi, "%s",
@@ -836,8 +1017,44 @@ static void sil24_error_intr(struct ata_port *ap)
if (irq_stat & PORT_IRQ_ERROR) {
struct sil24_cerr_info *ci = NULL;
unsigned int err_mask = 0, action = 0;
- struct ata_queued_cmd *qc;
- u32 cerr;
+ u32 context, cerr;
+ int pmp;
+
+ abort = 1;
+
+ /* DMA Context Switch Failure in Port Multiplier Mode
+ * errata. If we have active commands to 3 or more
+ * devices, any error condition on active devices can
+ * corrupt DMA context switching.
+ */
+ if (ap->nr_active_links >= 3) {
+ ehi->err_mask |= AC_ERR_OTHER;
+ ehi->action |= ATA_EH_HARDRESET;
+ ata_ehi_push_desc(ehi, "PMP DMA CS errata");
+ pp->do_port_rst = 1;
+ freeze = 1;
+ }
+
+ /* find out the offending link and qc */
+ if (ap->nr_pmp_links) {
+ context = readl(port + PORT_CONTEXT);
+ pmp = (context >> 5) & 0xf;
+
+ if (pmp < ap->nr_pmp_links) {
+ link = &ap->pmp_link[pmp];
+ ehi = &link->eh_info;
+ qc = ata_qc_from_tag(ap, link->active_tag);
+
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "irq_stat 0x%08x",
+ irq_stat);
+ } else {
+ err_mask |= AC_ERR_HSM;
+ action |= ATA_EH_HARDRESET;
+ freeze = 1;
+ }
+ } else
+ qc = ata_qc_from_tag(ap, link->active_tag);
/* analyze CMD_ERR */
cerr = readl(port + PORT_CMD_ERR);
@@ -856,7 +1073,6 @@ static void sil24_error_intr(struct ata_port *ap)
}
/* record error info */
- qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc) {
sil24_read_tf(ap, qc->tag, &pp->tf);
qc->err_mask |= err_mask;
@@ -864,13 +1080,21 @@ static void sil24_error_intr(struct ata_port *ap)
ehi->err_mask |= err_mask;
ehi->action |= action;
+
+ /* if PMP, resume */
+ if (ap->nr_pmp_links)
+ writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_STAT);
}
/* freeze or abort */
if (freeze)
ata_port_freeze(ap);
- else
- ata_port_abort(ap);
+ else if (abort) {
+ if (qc)
+ ata_link_abort(qc->dev->link);
+ else
+ ata_port_abort(ap);
+ }
}
static void sil24_finish_qc(struct ata_queued_cmd *qc)
@@ -910,7 +1134,7 @@ static inline void sil24_host_intr(struct ata_port *ap)
if (rc > 0)
return;
if (rc < 0) {
- struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
ehi->err_mask |= AC_ERR_HSM;
ehi->action |= ATA_EH_SOFTRESET;
ata_port_freeze(ap);
@@ -921,7 +1145,7 @@ static inline void sil24_host_intr(struct ata_port *ap)
if (!(ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) && ata_ratelimit())
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
"(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
- slot_stat, ap->active_tag, ap->sactive);
+ slot_stat, ap->link.active_tag, ap->link.sactive);
}
static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
@@ -963,16 +1187,18 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
static void sil24_error_handler(struct ata_port *ap)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct sil24_port_priv *pp = ap->private_data;
- if (sil24_init_port(ap)) {
+ if (sil24_init_port(ap))
ata_eh_freeze_port(ap);
- ehc->i.action |= ATA_EH_HARDRESET;
- }
/* perform recovery */
- ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
- ata_std_postreset);
+ sata_pmp_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
+ ata_std_postreset, sata_pmp_std_prereset,
+ sil24_pmp_softreset, sil24_pmp_hardreset,
+ sata_pmp_std_postreset);
+
+ pp->do_port_rst = 0;
}
static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
@@ -980,8 +1206,8 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
/* make DMA engine forget about the failed command */
- if (qc->flags & ATA_QCFLAG_FAILED)
- sil24_init_port(ap);
+ if ((qc->flags & ATA_QCFLAG_FAILED) && sil24_init_port(ap))
+ ata_eh_freeze_port(ap);
}
static int sil24_port_start(struct ata_port *ap)
@@ -1019,7 +1245,6 @@ static int sil24_port_start(struct ata_port *ap)
static void sil24_init_controller(struct ata_host *host)
{
void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
- void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
u32 tmp;
int i;
@@ -1031,7 +1256,8 @@ static void sil24_init_controller(struct ata_host *host)
/* init ports */
for (i = 0; i < host->n_ports; i++) {
- void __iomem *port = port_base + i * PORT_REGS_SIZE;
+ struct ata_port *ap = host->ports[i];
+ void __iomem *port = ap->ioaddr.cmd_addr;
/* Initial PHY setting */
writel(0x20c, port + PORT_PHY_CFG);
@@ -1045,29 +1271,11 @@ static void sil24_init_controller(struct ata_host *host)
PORT_CS_PORT_RST, 10, 100);
if (tmp & PORT_CS_PORT_RST)
dev_printk(KERN_ERR, host->dev,
- "failed to clear port RST\n");
+ "failed to clear port RST\n");
}
- /* Configure IRQ WoC */
- if (host->ports[0]->flags & SIL24_FLAG_PCIX_IRQ_WOC)
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
- else
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
-
- /* Zero error counters. */
- writel(0x8000, port + PORT_DECODE_ERR_THRESH);
- writel(0x8000, port + PORT_CRC_ERR_THRESH);
- writel(0x8000, port + PORT_HSHK_ERR_THRESH);
- writel(0x0000, port + PORT_DECODE_ERR_CNT);
- writel(0x0000, port + PORT_CRC_ERR_CNT);
- writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
- /* Always use 64bit activation */
- writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
- /* Clear port multiplier enable and resume bits */
- writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME,
- port + PORT_CTRL_CLR);
+ /* configure port */
+ sil24_config_port(ap);
}
/* Turn on interrupts */
@@ -1076,7 +1284,7 @@ static void sil24_init_controller(struct ata_host *host)
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- static int printed_version = 0;
+ static int printed_version;
struct ata_port_info pi = sil24_port_info[ent->driver_data];
const struct ata_port_info *ppi[] = { &pi, NULL };
void __iomem * const *iomap;
@@ -1118,12 +1326,15 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
host->iomap = iomap;
for (i = 0; i < host->n_ports; i++) {
- void __iomem *port = iomap[SIL24_PORT_BAR] + i * PORT_REGS_SIZE;
+ struct ata_port *ap = host->ports[i];
+ size_t offset = ap->port_no * PORT_REGS_SIZE;
+ void __iomem *port = iomap[SIL24_PORT_BAR] + offset;
host->ports[i]->ioaddr.cmd_addr = port;
host->ports[i]->ioaddr.scr_addr = port + PORT_SCONTROL;
- ata_std_ports(&host->ports[i]->ioaddr);
+ ata_port_pbar_desc(ap, SIL24_HOST_BAR, -1, "host");
+ ata_port_pbar_desc(ap, SIL24_PORT_BAR, offset, "port");
}
/* configure and activate the device */
@@ -1179,6 +1390,12 @@ static int sil24_pci_device_resume(struct pci_dev *pdev)
return 0;
}
+
+static int sil24_port_resume(struct ata_port *ap)
+{
+ sil24_config_pmp(ap, ap->nr_pmp_links);
+ return 0;
+}
#endif
static int __init sil24_init(void)
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 41c1d6e8f1f..a01260a5643 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -63,17 +63,17 @@ enum {
GENCTL_IOMAPPED_SCR = (1 << 26), /* if set, SCRs are in IO space */
};
-static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static int sis_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id sis_pci_tbl[] = {
- { PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */
- { PCI_VDEVICE(SI, 0x0181), sis_180 }, /* SiS 964/180 */
- { PCI_VDEVICE(SI, 0x0182), sis_180 }, /* SiS 965/965L */
- { PCI_VDEVICE(SI, 0x0183), sis_180 }, /* SiS 965/965L */
- { PCI_VDEVICE(SI, 0x1182), sis_180 }, /* SiS 966/680 */
- { PCI_VDEVICE(SI, 0x1183), sis_180 }, /* SiS 966/966L/968/680 */
+ { PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */
+ { PCI_VDEVICE(SI, 0x0181), sis_180 }, /* SiS 964/180 */
+ { PCI_VDEVICE(SI, 0x0182), sis_180 }, /* SiS 965/965L */
+ { PCI_VDEVICE(SI, 0x0183), sis_180 }, /* SiS 965/965L */
+ { PCI_VDEVICE(SI, 0x1182), sis_180 }, /* SiS 966/680 */
+ { PCI_VDEVICE(SI, 0x1183), sis_180 }, /* SiS 966/966L/968/680 */
{ } /* terminate list */
};
@@ -92,7 +92,7 @@ static struct scsi_host_template sis_sht = {
.queuecommand = ata_scsi_queuecmd,
.can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = ATA_MAX_PRD,
+ .sg_tablesize = LIBATA_MAX_PRD,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
.use_clustering = ATA_SHT_USE_CLUSTERING,
@@ -104,7 +104,6 @@ static struct scsi_host_template sis_sht = {
};
static const struct ata_port_operations sis_ops = {
- .port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -123,7 +122,6 @@ static const struct ata_port_operations sis_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = sis_scr_read,
.scr_write = sis_scr_write,
.port_start = ata_port_start,
@@ -151,28 +149,28 @@ static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
if (ap->port_no) {
switch (pdev->device) {
- case 0x0180:
- case 0x0181:
- pci_read_config_byte(pdev, SIS_PMR, &pmr);
- if ((pmr & SIS_PMR_COMBINED) == 0)
- addr += SIS180_SATA1_OFS;
- break;
-
- case 0x0182:
- case 0x0183:
- case 0x1182:
- addr += SIS182_SATA1_OFS;
- break;
+ case 0x0180:
+ case 0x0181:
+ pci_read_config_byte(pdev, SIS_PMR, &pmr);
+ if ((pmr & SIS_PMR_COMBINED) == 0)
+ addr += SIS180_SATA1_OFS;
+ break;
+
+ case 0x0182:
+ case 0x0183:
+ case 0x1182:
+ addr += SIS182_SATA1_OFS;
+ break;
}
}
return addr;
}
-static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
+static u32 sis_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
- u32 val, val2 = 0;
+ u32 val2 = 0;
u8 pmr;
if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
@@ -180,16 +178,19 @@ static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
pci_read_config_byte(pdev, SIS_PMR, &pmr);
- pci_read_config_dword(pdev, cfg_addr, &val);
+ pci_read_config_dword(pdev, cfg_addr, val);
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
pci_read_config_dword(pdev, cfg_addr+0x10, &val2);
- return (val|val2) & 0xfffffffb; /* avoid problems with powerdowned ports */
+ *val |= val2;
+ *val &= 0xfffffffb; /* avoid problems with powerdowned ports */
+
+ return 0;
}
-static void sis_scr_cfg_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static void sis_scr_cfg_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
@@ -216,7 +217,7 @@ static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
return -EINVAL;
if (ap->flags & SIS_FLAG_CFGSCR)
- return sis_scr_cfg_read(ap, sc_reg);
+ return sis_scr_cfg_read(ap, sc_reg, val);
pci_read_config_byte(pdev, SIS_PMR, &pmr);
@@ -252,7 +253,7 @@ static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
return 0;
}
-static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
struct ata_port_info pi = sis_port_info;
@@ -308,29 +309,33 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
} else {
dev_printk(KERN_INFO, &pdev->dev,
"Detected SiS 180/181 chipset in combined mode\n");
- port2_start=0;
+ port2_start = 0;
pi.flags |= ATA_FLAG_SLAVE_POSS;
}
break;
case 0x0182:
case 0x0183:
- pci_read_config_dword ( pdev, 0x6C, &val);
+ pci_read_config_dword(pdev, 0x6C, &val);
if (val & (1L << 31)) {
- dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965 chipset\n");
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Detected SiS 182/965 chipset\n");
pi.flags |= ATA_FLAG_SLAVE_POSS;
} else {
- dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 182/965L chipset\n");
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Detected SiS 182/965L chipset\n");
}
break;
case 0x1182:
- dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 1182/966/680 SATA controller\n");
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Detected SiS 1182/966/680 SATA controller\n");
pi.flags |= ATA_FLAG_SLAVE_POSS;
break;
case 0x1183:
- dev_printk(KERN_INFO, &pdev->dev, "Detected SiS 1183/966/966L/968/680 controller in PATA mode\n");
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Detected SiS 1183/966/966L/968/680 controller in PATA mode\n");
ppi[0] = &sis_info133_for_sata;
ppi[1] = &sis_info133_for_sata;
break;
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index d9678e7bc3a..69f651e0bc9 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -182,7 +182,7 @@ static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
tf->hob_lbal = lbal >> 8;
tf->hob_lbam = lbam >> 8;
tf->hob_lbah = lbah >> 8;
- }
+ }
}
/**
@@ -193,7 +193,7 @@ static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
* spin_lock_irqsave(host lock)
*/
-static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
+static void k2_bmdma_setup_mmio(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
@@ -224,7 +224,7 @@ static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
* spin_lock_irqsave(host lock)
*/
-static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
+static void k2_bmdma_start_mmio(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
void __iomem *mmio = ap->ioaddr.bmdma_addr;
@@ -255,7 +255,7 @@ static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
static u8 k2_stat_check_status(struct ata_port *ap)
{
- return readl(ap->ioaddr.status_addr);
+ return readl(ap->ioaddr.status_addr);
}
#ifdef CONFIG_PPC_OF
@@ -329,7 +329,6 @@ static struct scsi_host_template k2_sata_sht = {
static const struct ata_port_operations k2_sata_ops = {
- .port_disable = ata_port_disable,
.tf_load = k2_sata_tf_load,
.tf_read = k2_sata_tf_read,
.check_status = k2_stat_check_status,
@@ -349,7 +348,6 @@ static const struct ata_port_operations k2_sata_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = k2_sata_scr_read,
.scr_write = k2_sata_scr_write,
.port_start = ata_port_start,
@@ -397,7 +395,7 @@ static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base)
}
-static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+static int k2_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
const struct ata_port_info *ppi[] =
@@ -445,9 +443,15 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
/* different controllers have different number of ports - currently 4 or 8 */
/* All ports are on the same function. Multi-function device is no
* longer available. This should not be seen in any system. */
- for (i = 0; i < host->n_ports; i++)
- k2_sata_setup_port(&host->ports[i]->ioaddr,
- mmio_base + i * K2_SATA_PORT_OFFSET);
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ unsigned int offset = i * K2_SATA_PORT_OFFSET;
+
+ k2_sata_setup_port(&ap->ioaddr, mmio_base + offset);
+
+ ata_port_pbar_desc(ap, 5, -1, "mmio");
+ ata_port_pbar_desc(ap, 5, offset, "port");
+ }
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 97aefdd87be..4d857185f33 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -62,13 +62,13 @@
submit ATA packet to hardware
hardware executes ATA WRITE command, w/ data in DIMM
hardware raises interrupt
-
+
and each READ looks like this:
submit ATA packet to hardware
hardware executes ATA READ command, w/ data in DIMM
hardware raises interrupt
-
+
submit HDMA packet to hardware
hardware copies data from DIMM to system memory
hardware raises interrupt
@@ -212,9 +212,9 @@ struct pdc_host_priv {
};
-static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static int pdc_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static void pdc_eng_timeout(struct ata_port *ap);
-static void pdc_20621_phy_reset (struct ata_port *ap);
+static void pdc_20621_phy_reset(struct ata_port *ap);
static int pdc_port_start(struct ata_port *ap);
static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
@@ -254,7 +254,6 @@ static struct scsi_host_template pdc_sata_sht = {
};
static const struct ata_port_operations pdc_20621_ops = {
- .port_disable = ata_port_disable,
.tf_load = pdc_tf_load_mmio,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -267,7 +266,6 @@ static const struct ata_port_operations pdc_20621_ops = {
.eng_timeout = pdc_eng_timeout,
.irq_clear = pdc20621_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = pdc_port_start,
};
@@ -322,16 +320,16 @@ static int pdc_port_start(struct ata_port *ap)
return 0;
}
-static void pdc_20621_phy_reset (struct ata_port *ap)
+static void pdc_20621_phy_reset(struct ata_port *ap)
{
VPRINTK("ENTER\n");
- ap->cbl = ATA_CBL_SATA;
- ata_port_probe(ap);
- ata_bus_reset(ap);
+ ap->cbl = ATA_CBL_SATA;
+ ata_port_probe(ap);
+ ata_bus_reset(ap);
}
static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
- unsigned int portno,
+ unsigned int portno,
unsigned int total_len)
{
u32 addr;
@@ -353,7 +351,7 @@ static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
}
static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
- unsigned int portno,
+ unsigned int portno,
unsigned int total_len)
{
u32 addr;
@@ -713,8 +711,8 @@ static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
return ata_qc_issue_prot(qc);
}
-static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
- struct ata_queued_cmd *qc,
+static inline unsigned int pdc20621_host_intr(struct ata_port *ap,
+ struct ata_queued_cmd *qc,
unsigned int doing_hdma,
void __iomem *mmio)
{
@@ -805,7 +803,7 @@ static void pdc20621_irq_clear(struct ata_port *ap)
readl(mmio + PDC_20621_SEQMASK);
}
-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance)
+static irqreturn_t pdc20621_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
struct ata_port *ap;
@@ -838,9 +836,9 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance)
return IRQ_NONE;
}
- spin_lock(&host->lock);
+ spin_lock(&host->lock);
- for (i = 1; i < 9; i++) {
+ for (i = 1; i < 9; i++) {
port_no = i - 1;
if (port_no > 3)
port_no -= 4;
@@ -854,14 +852,14 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance)
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled += pdc20621_host_intr(ap, qc, (i > 4),
mmio_base);
}
}
- spin_unlock(&host->lock);
+ spin_unlock(&host->lock);
VPRINTK("mask == 0x%x\n", mask);
@@ -881,7 +879,7 @@ static void pdc_eng_timeout(struct ata_port *ap)
spin_lock_irqsave(&host->lock, flags);
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
switch (qc->tf.protocol) {
case ATA_PROT_DMA:
@@ -908,16 +906,16 @@ static void pdc_eng_timeout(struct ata_port *ap)
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
{
- WARN_ON (tf->protocol == ATA_PROT_DMA ||
- tf->protocol == ATA_PROT_NODATA);
+ WARN_ON(tf->protocol == ATA_PROT_DMA ||
+ tf->protocol == ATA_PROT_NODATA);
ata_tf_load(ap, tf);
}
static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
{
- WARN_ON (tf->protocol == ATA_PROT_DMA ||
- tf->protocol == ATA_PROT_NODATA);
+ WARN_ON(tf->protocol == ATA_PROT_DMA ||
+ tf->protocol == ATA_PROT_NODATA);
ata_exec_command(ap, tf);
}
@@ -955,7 +953,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
mmio += PDC_CHIP0_OFS;
page_mask = 0x00;
- window_size = 0x2000 * 4; /* 32K byte uchar size */
+ window_size = 0x2000 * 4; /* 32K byte uchar size */
idx = (u16) (offset / window_size);
writel(0x01, mmio + PDC_GENERAL_CTLR);
@@ -981,7 +979,7 @@ static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
window_size / 4);
psource += window_size;
size -= window_size;
- idx ++;
+ idx++;
}
if (size) {
@@ -1010,7 +1008,7 @@ static void pdc20621_put_to_dimm(struct ata_host *host, void *psource,
mmio += PDC_CHIP0_OFS;
page_mask = 0x00;
- window_size = 0x2000 * 4; /* 32K byte uchar size */
+ window_size = 0x2000 * 4; /* 32K byte uchar size */
idx = (u16) (offset / window_size);
writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
@@ -1033,7 +1031,7 @@ static void pdc20621_put_to_dimm(struct ata_host *host, void *psource,
readl(mmio + PDC_GENERAL_CTLR);
psource += window_size;
size -= window_size;
- idx ++;
+ idx++;
}
if (size) {
@@ -1052,7 +1050,7 @@ static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device,
void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
u32 i2creg = 0;
u32 status;
- u32 count =0;
+ u32 count = 0;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1084,21 +1082,21 @@ static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device,
static int pdc20621_detect_dimm(struct ata_host *host)
{
- u32 data=0 ;
+ u32 data = 0;
if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
- if (data == 100)
+ if (data == 100)
return 100;
- } else
+ } else
return 0;
if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
- if(data <= 0x75)
+ if (data <= 0x75)
return 133;
- } else
+ } else
return 0;
- return 0;
+ return 0;
}
@@ -1106,8 +1104,8 @@ static int pdc20621_prog_dimm0(struct ata_host *host)
{
u32 spd0[50];
u32 data = 0;
- int size, i;
- u8 bdimmsize;
+ int size, i;
+ u8 bdimmsize;
void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
static const struct {
unsigned int reg;
@@ -1130,40 +1128,40 @@ static int pdc20621_prog_dimm0(struct ata_host *host)
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
- for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
+ for (i = 0; i < ARRAY_SIZE(pdc_i2c_read_data); i++)
pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
pdc_i2c_read_data[i].reg,
&spd0[pdc_i2c_read_data[i].ofs]);
- data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
- data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) |
+ data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
+ data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) |
((((spd0[27] + 9) / 10) - 1) << 8) ;
- data |= (((((spd0[29] > spd0[28])
+ data |= (((((spd0[29] > spd0[28])
? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10;
- data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
+ data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
- if (spd0[18] & 0x08)
+ if (spd0[18] & 0x08)
data |= ((0x03) << 14);
- else if (spd0[18] & 0x04)
+ else if (spd0[18] & 0x04)
data |= ((0x02) << 14);
- else if (spd0[18] & 0x01)
+ else if (spd0[18] & 0x01)
data |= ((0x01) << 14);
- else
+ else
data |= (0 << 14);
- /*
+ /*
Calculate the size of bDIMMSize (power of 2) and
merge the DIMM size by program start/end address.
*/
- bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
- size = (1 << bdimmsize) >> 20; /* size = xxx(MB) */
- data |= (((size / 16) - 1) << 16);
- data |= (0 << 23);
+ bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
+ size = (1 << bdimmsize) >> 20; /* size = xxx(MB) */
+ data |= (((size / 16) - 1) << 16);
+ data |= (0 << 23);
data |= 8;
- writel(data, mmio + PDC_DIMM0_CONTROL);
+ writel(data, mmio + PDC_DIMM0_CONTROL);
readl(mmio + PDC_DIMM0_CONTROL);
- return size;
+ return size;
}
@@ -1174,9 +1172,9 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_host *host)
void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
+ mmio += PDC_CHIP0_OFS;
- /*
+ /*
Set To Default : DIMM Module Global Control Register (0x022259F1)
DIMM Arbitration Disable (bit 20)
DIMM Data/Control Output Driving Selection (bit12 - bit15)
@@ -1195,40 +1193,40 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_host *host)
writel(data, mmio + PDC_SDRAM_CONTROL);
readl(mmio + PDC_SDRAM_CONTROL);
printk(KERN_ERR "Local DIMM ECC Enabled\n");
- }
+ }
- /* DIMM Initialization Select/Enable (bit 18/19) */
- data &= (~(1<<18));
- data |= (1<<19);
- writel(data, mmio + PDC_SDRAM_CONTROL);
+ /* DIMM Initialization Select/Enable (bit 18/19) */
+ data &= (~(1<<18));
+ data |= (1<<19);
+ writel(data, mmio + PDC_SDRAM_CONTROL);
- error = 1;
- for (i = 1; i <= 10; i++) { /* polling ~5 secs */
+ error = 1;
+ for (i = 1; i <= 10; i++) { /* polling ~5 secs */
data = readl(mmio + PDC_SDRAM_CONTROL);
if (!(data & (1<<19))) {
- error = 0;
- break;
+ error = 0;
+ break;
}
msleep(i*100);
- }
- return error;
+ }
+ return error;
}
static unsigned int pdc20621_dimm_init(struct ata_host *host)
{
int speed, size, length;
- u32 addr,spd0,pci_status;
- u32 tmp=0;
- u32 time_period=0;
- u32 tcount=0;
- u32 ticks=0;
- u32 clock=0;
- u32 fparam=0;
+ u32 addr, spd0, pci_status;
+ u32 tmp = 0;
+ u32 time_period = 0;
+ u32 tcount = 0;
+ u32 ticks = 0;
+ u32 clock = 0;
+ u32 fparam = 0;
void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
- mmio += PDC_CHIP0_OFS;
+ mmio += PDC_CHIP0_OFS;
/* Initialize PLL based upon PCI Bus Frequency */
@@ -1256,7 +1254,7 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
If SX4 is on PCI-X bus, after 3 seconds, the timer counter
register should be >= (0xffffffff - 3x10^8).
*/
- if(tcount >= PCI_X_TCOUNT) {
+ if (tcount >= PCI_X_TCOUNT) {
ticks = (time_period - tcount);
VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
@@ -1287,41 +1285,43 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
if (!(speed = pdc20621_detect_dimm(host))) {
printk(KERN_ERR "Detect Local DIMM Fail\n");
return 1; /* DIMM error */
- }
- VPRINTK("Local DIMM Speed = %d\n", speed);
+ }
+ VPRINTK("Local DIMM Speed = %d\n", speed);
- /* Programming DIMM0 Module Control Register (index_CID0:80h) */
+ /* Programming DIMM0 Module Control Register (index_CID0:80h) */
size = pdc20621_prog_dimm0(host);
- VPRINTK("Local DIMM Size = %dMB\n",size);
+ VPRINTK("Local DIMM Size = %dMB\n", size);
- /* Programming DIMM Module Global Control Register (index_CID0:88h) */
+ /* Programming DIMM Module Global Control Register (index_CID0:88h) */
if (pdc20621_prog_dimm_global(host)) {
printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
return 1;
- }
+ }
#ifdef ATA_VERBOSE_DEBUG
{
- u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ',
- 'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ',
- '1','.','1','0',
- '9','8','0','3','1','6','1','2',0,0};
+ u8 test_parttern1[40] =
+ {0x55,0xAA,'P','r','o','m','i','s','e',' ',
+ 'N','o','t',' ','Y','e','t',' ',
+ 'D','e','f','i','n','e','d',' ',
+ '1','.','1','0',
+ '9','8','0','3','1','6','1','2',0,0};
u8 test_parttern2[40] = {0};
- pdc20621_put_to_dimm(host, (void *) test_parttern2, 0x10040, 40);
- pdc20621_put_to_dimm(host, (void *) test_parttern2, 0x40, 40);
+ pdc20621_put_to_dimm(host, test_parttern2, 0x10040, 40);
+ pdc20621_put_to_dimm(host, test_parttern2, 0x40, 40);
- pdc20621_put_to_dimm(host, (void *) test_parttern1, 0x10040, 40);
- pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x40, 40);
+ pdc20621_put_to_dimm(host, test_parttern1, 0x10040, 40);
+ pdc20621_get_from_dimm(host, test_parttern2, 0x40, 40);
printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
test_parttern2[1], &(test_parttern2[2]));
- pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x10040,
+ pdc20621_get_from_dimm(host, test_parttern2, 0x10040,
40);
printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
test_parttern2[1], &(test_parttern2[2]));
- pdc20621_put_to_dimm(host, (void *) test_parttern1, 0x40, 40);
- pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x40, 40);
+ pdc20621_put_to_dimm(host, test_parttern1, 0x40, 40);
+ pdc20621_get_from_dimm(host, test_parttern2, 0x40, 40);
printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
test_parttern2[1], &(test_parttern2[2]));
}
@@ -1377,15 +1377,15 @@ static void pdc_20621_init(struct ata_host *host)
readl(mmio + PDC_HDMA_CTLSTAT); /* flush */
}
-static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+static int pdc_sata_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
static int printed_version;
const struct ata_port_info *ppi[] =
{ &pdc_port_info[ent->driver_data], NULL };
struct ata_host *host;
- void __iomem *base;
struct pdc_host_priv *hpriv;
- int rc;
+ int i, rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -1411,11 +1411,17 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
return rc;
host->iomap = pcim_iomap_table(pdev);
- base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
- pdc_sata_setup_port(&host->ports[0]->ioaddr, base + 0x200);
- pdc_sata_setup_port(&host->ports[1]->ioaddr, base + 0x280);
- pdc_sata_setup_port(&host->ports[2]->ioaddr, base + 0x300);
- pdc_sata_setup_port(&host->ports[3]->ioaddr, base + 0x380);
+ for (i = 0; i < 4; i++) {
+ struct ata_port *ap = host->ports[i];
+ void __iomem *base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
+ unsigned int offset = 0x200 + i * 0x80;
+
+ pdc_sata_setup_port(&ap->ioaddr, base + offset);
+
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, PDC_DIMM_BAR, -1, "dimm");
+ ata_port_pbar_desc(ap, PDC_MMIO_BAR, offset, "port");
+ }
/* configure and activate */
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index e6b8b45279a..e710e71b7b9 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -56,9 +56,9 @@ struct uli_priv {
unsigned int scr_cfg_addr[uli_max_ports];
};
-static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
-static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static int uli_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int uli_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id uli_pci_tbl[] = {
{ PCI_VDEVICE(AL, 0x5289), uli_5289 },
@@ -94,8 +94,6 @@ static struct scsi_host_template uli_sht = {
};
static const struct ata_port_operations uli_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -117,7 +115,6 @@ static const struct ata_port_operations uli_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = uli_scr_read,
.scr_write = uli_scr_write,
@@ -146,7 +143,7 @@ static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg);
}
-static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
+static u32 uli_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
@@ -156,7 +153,7 @@ static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
return val;
}
-static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+static void uli_scr_cfg_write(struct ata_port *ap, unsigned int scr, u32 val)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(ap, scr);
@@ -164,7 +161,7 @@ static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
pci_write_config_dword(pdev, cfg_addr, val);
}
-static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val)
+static int uli_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
return -EINVAL;
@@ -173,16 +170,16 @@ static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val)
return 0;
}
-static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int uli_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
- if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
+ if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
return -EINVAL;
uli_scr_cfg_write(ap, sc_reg, val);
return 0;
}
-static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
const struct ata_port_info *ppi[] = { &uli_port_info, NULL };
@@ -242,6 +239,12 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
ata_std_ports(ioaddr);
+ ata_port_desc(host->ports[2],
+ "cmd 0x%llx ctl 0x%llx bmdma 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, 0) + 8,
+ ((unsigned long long)pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4,
+ (unsigned long long)pci_resource_start(pdev, 4) + 16);
+
ioaddr = &host->ports[3]->ioaddr;
ioaddr->cmd_addr = iomap[2] + 8;
ioaddr->altstatus_addr =
@@ -250,6 +253,13 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
ioaddr->bmdma_addr = iomap[4] + 24;
hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
ata_std_ports(ioaddr);
+
+ ata_port_desc(host->ports[2],
+ "cmd 0x%llx ctl 0x%llx bmdma 0x%llx",
+ (unsigned long long)pci_resource_start(pdev, 2) + 9,
+ ((unsigned long long)pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4,
+ (unsigned long long)pci_resource_start(pdev, 4) + 24);
+
break;
case uli_5289:
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 57fd30de8f0..3ef072ff319 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -3,7 +3,7 @@
*
* Maintained by: Jeff Garzik <jgarzik@pobox.com>
* Please ALWAYS copy linux-ide@vger.kernel.org
- on emails.
+ * on emails.
*
* Copyright 2003-2004 Red Hat, Inc. All rights reserved.
* Copyright 2003-2004 Jeff Garzik
@@ -57,7 +57,6 @@ enum {
SATA_CHAN_ENAB = 0x40, /* SATA channel enable */
SATA_INT_GATE = 0x41, /* SATA interrupt gating */
SATA_NATIVE_MODE = 0x42, /* Native mode enable */
- SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */
PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */
PATA_PIO_TIMING = 0xAB, /* PATA timing register */
@@ -68,10 +67,9 @@ enum {
NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
SATA_EXT_PHY = (1 << 6), /* 0==use PATA, 1==ext phy */
- SATA_2DEV = (1 << 5), /* SATA is master/slave */
};
-static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static void svia_noop_freeze(struct ata_port *ap);
@@ -122,8 +120,6 @@ static struct scsi_host_template svia_sht = {
};
static const struct ata_port_operations vt6420_sata_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -146,14 +142,11 @@ static const struct ata_port_operations vt6420_sata_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static const struct ata_port_operations vt6421_pata_ops = {
- .port_disable = ata_port_disable,
-
.set_piomode = vt6421_set_pio_mode,
.set_dmamode = vt6421_set_dma_mode,
@@ -180,14 +173,11 @@ static const struct ata_port_operations vt6421_pata_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
static const struct ata_port_operations vt6421_sata_ops = {
- .port_disable = ata_port_disable,
-
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -211,7 +201,6 @@ static const struct ata_port_operations vt6421_sata_ops = {
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = svia_scr_read,
.scr_write = svia_scr_write,
@@ -276,7 +265,7 @@ static void svia_noop_freeze(struct ata_port *ap)
/**
* vt6420_prereset - prereset for vt6420
- * @ap: target ATA port
+ * @link: target ATA link
* @deadline: deadline jiffies for the operation
*
* SCR registers on vt6420 are pieces of shit and may hang the
@@ -294,9 +283,10 @@ static void svia_noop_freeze(struct ata_port *ap)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
+static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
{
- struct ata_eh_context *ehc = &ap->eh_context;
+ struct ata_port *ap = link->ap;
+ struct ata_eh_context *ehc = &ap->link.eh_context;
unsigned long timeout = jiffies + (HZ * 5);
u32 sstatus, scontrol;
int online;
@@ -382,12 +372,12 @@ static const unsigned int vt6421_bar_sizes[] = {
16, 16, 16, 16, 32, 128
};
-static void __iomem * svia_scr_addr(void __iomem *addr, unsigned int port)
+static void __iomem *svia_scr_addr(void __iomem *addr, unsigned int port)
{
return addr + (port * 128);
}
-static void __iomem * vt6421_scr_addr(void __iomem *addr, unsigned int port)
+static void __iomem *vt6421_scr_addr(void __iomem *addr, unsigned int port)
{
return addr + (port * 64);
}
@@ -407,6 +397,9 @@ static void vt6421_init_addrs(struct ata_port *ap)
ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no);
ata_std_ports(ioaddr);
+
+ ata_port_pbar_desc(ap, ap->port_no, -1, "port");
+ ata_port_pbar_desc(ap, 4, ap->port_no * 8, "bmdma");
}
static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
@@ -479,7 +472,7 @@ static void svia_configure(struct pci_dev *pdev)
if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
dev_printk(KERN_DEBUG, &pdev->dev,
"enabling SATA channels (0x%x)\n",
- (int) tmp8);
+ (int) tmp8);
tmp8 |= ALL_PORTS;
pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
}
@@ -489,7 +482,7 @@ static void svia_configure(struct pci_dev *pdev)
if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
dev_printk(KERN_DEBUG, &pdev->dev,
"enabling SATA channel interrupts (0x%x)\n",
- (int) tmp8);
+ (int) tmp8);
tmp8 |= ALL_PORTS;
pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
}
@@ -499,21 +492,20 @@ static void svia_configure(struct pci_dev *pdev)
if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
dev_printk(KERN_DEBUG, &pdev->dev,
"enabling SATA channel native mode (0x%x)\n",
- (int) tmp8);
+ (int) tmp8);
tmp8 |= NATIVE_MODE_ALL;
pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
}
}
-static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
unsigned int i;
int rc;
struct ata_host *host;
int board_id = (int) ent->driver_data;
- const int *bar_sizes;
- u8 tmp8;
+ const unsigned *bar_sizes;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -522,19 +514,10 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- if (board_id == vt6420) {
- pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
- if (tmp8 & SATA_2DEV) {
- dev_printk(KERN_ERR, &pdev->dev,
- "SATA master/slave not supported (0x%x)\n",
- (int) tmp8);
- return -EIO;
- }
-
+ if (board_id == vt6420)
bar_sizes = &svia_bar_sizes[0];
- } else {
+ else
bar_sizes = &vt6421_bar_sizes[0];
- }
for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
if ((pci_resource_start(pdev, i) == 0) ||
@@ -542,8 +525,8 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
dev_printk(KERN_ERR, &pdev->dev,
"invalid PCI BAR %u (sz 0x%llx, val 0x%llx)\n",
i,
- (unsigned long long)pci_resource_start(pdev, i),
- (unsigned long long)pci_resource_len(pdev, i));
+ (unsigned long long)pci_resource_start(pdev, i),
+ (unsigned long long)pci_resource_len(pdev, i));
return -ENODEV;
}
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 1920915dfa2..95ae3ed24a9 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -162,7 +162,8 @@ static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
/*
* The only thing the ctl register is used for is SRST.
* That is not enabled or disabled via tf_load.
- * However, if ATA_NIEN is changed, then we need to change the interrupt register.
+ * However, if ATA_NIEN is changed, then we need to change
+ * the interrupt register.
*/
if ((tf->ctl & ATA_NIEN) != (ap->last_ctl & ATA_NIEN)) {
ap->last_ctl = tf->ctl;
@@ -219,7 +220,7 @@ static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
tf->hob_lbal = lbal >> 8;
tf->hob_lbam = lbam >> 8;
tf->hob_lbah = lbah >> 8;
- }
+ }
}
static inline void vsc_error_intr(u8 port_status, struct ata_port *ap)
@@ -240,7 +241,7 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap)
return;
}
- qc = ata_qc_from_tag(ap, ap->active_tag);
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING)))
handled = ata_host_intr(ap, qc);
@@ -256,9 +257,10 @@ static void vsc_port_intr(u8 port_status, struct ata_port *ap)
/*
* vsc_sata_interrupt
*
- * Read the interrupt register and process for the devices that have them pending.
+ * Read the interrupt register and process for the devices that have
+ * them pending.
*/
-static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance)
+static irqreturn_t vsc_sata_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
unsigned int i;
@@ -287,7 +289,7 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance)
handled++;
} else
dev_printk(KERN_ERR, host->dev,
- ": interrupt from disabled port %d\n", i);
+ "interrupt from disabled port %d\n", i);
}
}
@@ -317,7 +319,6 @@ static struct scsi_host_template vsc_sata_sht = {
static const struct ata_port_operations vsc_sata_ops = {
- .port_disable = ata_port_disable,
.tf_load = vsc_sata_tf_load,
.tf_read = vsc_sata_tf_read,
.exec_command = ata_exec_command,
@@ -336,7 +337,6 @@ static const struct ata_port_operations vsc_sata_ops = {
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
- .irq_ack = ata_irq_ack,
.scr_read = vsc_sata_scr_read,
.scr_write = vsc_sata_scr_write,
.port_start = ata_port_start,
@@ -365,7 +365,8 @@ static void __devinit vsc_sata_setup_port(struct ata_ioports *port,
}
-static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit vsc_sata_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
static const struct ata_port_info pi = {
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
@@ -408,9 +409,15 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
mmio_base = host->iomap[VSC_MMIO_BAR];
- for (i = 0; i < host->n_ports; i++)
- vsc_sata_setup_port(&host->ports[i]->ioaddr,
- mmio_base + (i + 1) * VSC_SATA_PORT_OFFSET);
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ unsigned int offset = (i + 1) * VSC_SATA_PORT_OFFSET;
+
+ vsc_sata_setup_port(&ap->ioaddr, mmio_base + offset);
+
+ ata_port_pbar_desc(ap, VSC_MMIO_BAR, -1, "mmio");
+ ata_port_pbar_desc(ap, VSC_MMIO_BAR, offset, "port");
+ }
/*
* Use 32 bit DMA mask, because 64 bit address support is poor.
diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile
index 1b16f8166b0..e4fa9965869 100644
--- a/drivers/atm/Makefile
+++ b/drivers/atm/Makefile
@@ -41,7 +41,7 @@ ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
# guess the target endianess to choose the right PCA-200E firmware image
ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y)
byteorder.h := include$(if $(patsubst $(srctree),,$(objtree)),2)/asm/byteorder.h
- CONFIG_ATM_FORE200E_PCA_FW := $(obj)/pca200e$(if $(shell $(CC) $(CPPFLAGS) -E -dM $(byteorder.h) | grep ' __LITTLE_ENDIAN '),.bin,_ecd.bin2)
+ CONFIG_ATM_FORE200E_PCA_FW := $(obj)/pca200e$(if $(shell $(CC) $(KBUILD_CPPFLAGS) -E -dM $(byteorder.h) | grep ' __LITTLE_ENDIAN '),.bin,_ecd.bin2)
endif
endif
diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h
index 8296420ceae..ff2a303cbe0 100644
--- a/drivers/atm/ambassador.h
+++ b/drivers/atm/ambassador.h
@@ -626,7 +626,7 @@ typedef struct {
struct amb_dev {
u8 irq;
- long flags;
+ unsigned long flags;
u32 iobase;
u32 * membase;
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 737cea49f87..f8f7139c07c 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -1295,7 +1295,7 @@ static const struct atmdev_ops ops = {
static void __devinit undocumented_pci_fix (struct pci_dev *pdev)
{
- int tint;
+ u32 tint;
/* The Windows driver says: */
/* Switch off FireStream Retry Limit Threshold
@@ -1596,7 +1596,7 @@ static irqreturn_t fs_irq (int irq, void *dev_id)
/* print the bits in the ISR register. */
if (fs_debug & FS_DEBUG_IRQ) {
- /* The FS_DEBUG things are unneccesary here. But this way it is
+ /* The FS_DEBUG things are unnecessary here. But this way it is
clear for grep that these are debug prints. */
fs_dprintk (FS_DEBUG_IRQ, "IRQ status:");
for (i=0;i<27;i++)
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index f96446c358b..9b2cf253f02 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -1382,8 +1382,9 @@ static inline void rx_data_av_handler (hrz_dev * dev) {
/********** interrupt handler **********/
-static irqreturn_t interrupt_handler(int irq, void *dev_id) {
- hrz_dev * dev = (hrz_dev *) dev_id;
+static irqreturn_t interrupt_handler(int irq, void *dev_id)
+{
+ hrz_dev *dev = dev_id;
u32 int_source;
unsigned int irq_ok;
diff --git a/drivers/atm/horizon.h b/drivers/atm/horizon.h
index 4461229f56a..b48859d0d43 100644
--- a/drivers/atm/horizon.h
+++ b/drivers/atm/horizon.h
@@ -423,7 +423,7 @@ struct hrz_dev {
wait_queue_head_t tx_queue;
u8 irq;
- long flags;
+ unsigned long flags;
u8 tx_last;
u8 tx_idle;
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index f8b1700f4c1..eee54c0cde6 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -3576,7 +3576,7 @@ init_card(struct atm_dev *dev)
* XXX: <hack>
*/
sprintf(tname, "eth%d", card->index);
- tmp = dev_get_by_name(tname); /* jhs: was "tmp = dev_get(tname);" */
+ tmp = dev_get_by_name(&init_net, tname); /* jhs: was "tmp = dev_get(tname);" */
if (tmp) {
memcpy(card->atmdev->esi, tmp->dev_addr, 6);
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 5d6312e3349..d7da109c24f 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -1,5 +1,13 @@
menu "Generic Driver Options"
+config UEVENT_HELPER_PATH
+ string "path to uevent helper"
+ depends on HOTPLUG
+ default "/sbin/hotplug"
+ help
+ Path to uevent helper program forked by the kernel for
+ every uevent.
+
config STANDALONE
bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
default y
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 47eb02d9f1a..10b2fb6c9ce 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -18,8 +18,6 @@ extern int attribute_container_init(void);
extern int bus_add_device(struct device * dev);
extern void bus_attach_device(struct device * dev);
extern void bus_remove_device(struct device * dev);
-extern struct bus_type *get_bus(struct bus_type * bus);
-extern void put_bus(struct bus_type * bus);
extern int bus_add_driver(struct device_driver *);
extern void bus_remove_driver(struct device_driver *);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 61c67526a65..9a19b071c57 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -30,6 +30,17 @@
static int __must_check bus_rescan_devices_helper(struct device *dev,
void *data);
+static struct bus_type *bus_get(struct bus_type *bus)
+{
+ return bus ? container_of(kset_get(&bus->subsys),
+ struct bus_type, subsys) : NULL;
+}
+
+static void bus_put(struct bus_type *bus)
+{
+ kset_put(&bus->subsys);
+}
+
static ssize_t
drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
{
@@ -78,7 +89,7 @@ static void driver_release(struct kobject * kobj)
*/
}
-static struct kobj_type ktype_driver = {
+static struct kobj_type driver_ktype = {
.sysfs_ops = &driver_sysfs_ops,
.release = driver_release,
};
@@ -122,9 +133,9 @@ static struct sysfs_ops bus_sysfs_ops = {
int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
{
int error;
- if (get_bus(bus)) {
+ if (bus_get(bus)) {
error = sysfs_create_file(&bus->subsys.kobj, &attr->attr);
- put_bus(bus);
+ bus_put(bus);
} else
error = -EINVAL;
return error;
@@ -132,9 +143,9 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
{
- if (get_bus(bus)) {
+ if (bus_get(bus)) {
sysfs_remove_file(&bus->subsys.kobj, &attr->attr);
- put_bus(bus);
+ bus_put(bus);
}
}
@@ -172,7 +183,7 @@ static int driver_helper(struct device *dev, void *data)
static ssize_t driver_unbind(struct device_driver *drv,
const char *buf, size_t count)
{
- struct bus_type *bus = get_bus(drv->bus);
+ struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
int err = -ENODEV;
@@ -186,7 +197,7 @@ static ssize_t driver_unbind(struct device_driver *drv,
err = count;
}
put_device(dev);
- put_bus(bus);
+ bus_put(bus);
return err;
}
static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
@@ -199,7 +210,7 @@ static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
static ssize_t driver_bind(struct device_driver *drv,
const char *buf, size_t count)
{
- struct bus_type *bus = get_bus(drv->bus);
+ struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
int err = -ENODEV;
@@ -219,7 +230,7 @@ static ssize_t driver_bind(struct device_driver *drv,
err = -ENODEV;
}
put_device(dev);
- put_bus(bus);
+ bus_put(bus);
return err;
}
static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
@@ -430,7 +441,7 @@ static inline void remove_deprecated_bus_links(struct device *dev) { }
*/
int bus_add_device(struct device * dev)
{
- struct bus_type * bus = get_bus(dev->bus);
+ struct bus_type * bus = bus_get(dev->bus);
int error = 0;
if (bus) {
@@ -459,7 +470,7 @@ out_subsys:
out_id:
device_remove_attrs(bus, dev);
out_put:
- put_bus(dev->bus);
+ bus_put(dev->bus);
return error;
}
@@ -509,7 +520,7 @@ void bus_remove_device(struct device * dev)
}
pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
device_release_driver(dev);
- put_bus(dev->bus);
+ bus_put(dev->bus);
}
}
@@ -568,32 +579,29 @@ static void remove_bind_files(struct device_driver *drv)
driver_remove_file(drv, &driver_attr_unbind);
}
+static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
+static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
+ show_drivers_autoprobe, store_drivers_autoprobe);
+
static int add_probe_files(struct bus_type *bus)
{
int retval;
- bus->drivers_probe_attr.attr.name = "drivers_probe";
- bus->drivers_probe_attr.attr.mode = S_IWUSR;
- bus->drivers_probe_attr.store = store_drivers_probe;
- retval = bus_create_file(bus, &bus->drivers_probe_attr);
+ retval = bus_create_file(bus, &bus_attr_drivers_probe);
if (retval)
goto out;
- bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe";
- bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO;
- bus->drivers_autoprobe_attr.show = show_drivers_autoprobe;
- bus->drivers_autoprobe_attr.store = store_drivers_autoprobe;
- retval = bus_create_file(bus, &bus->drivers_autoprobe_attr);
+ retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
if (retval)
- bus_remove_file(bus, &bus->drivers_probe_attr);
+ bus_remove_file(bus, &bus_attr_drivers_probe);
out:
return retval;
}
static void remove_probe_files(struct bus_type *bus)
{
- bus_remove_file(bus, &bus->drivers_autoprobe_attr);
- bus_remove_file(bus, &bus->drivers_probe_attr);
+ bus_remove_file(bus, &bus_attr_drivers_autoprobe);
+ bus_remove_file(bus, &bus_attr_drivers_probe);
}
#else
static inline int add_bind_files(struct device_driver *drv) { return 0; }
@@ -602,6 +610,17 @@ static inline int add_probe_files(struct bus_type *bus) { return 0; }
static inline void remove_probe_files(struct bus_type *bus) {}
#endif
+static ssize_t driver_uevent_store(struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ enum kobject_action action;
+
+ if (kobject_action_type(buf, count, &action) == 0)
+ kobject_uevent(&drv->kobj, action);
+ return count;
+}
+static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
+
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
@@ -609,7 +628,7 @@ static inline void remove_probe_files(struct bus_type *bus) {}
*/
int bus_add_driver(struct device_driver *drv)
{
- struct bus_type * bus = get_bus(drv->bus);
+ struct bus_type * bus = bus_get(drv->bus);
int error = 0;
if (!bus)
@@ -632,6 +651,11 @@ int bus_add_driver(struct device_driver *drv)
klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
module_add_driver(drv->owner, drv);
+ error = driver_create_file(drv, &driver_attr_uevent);
+ if (error) {
+ printk(KERN_ERR "%s: uevent attr (%s) failed\n",
+ __FUNCTION__, drv->name);
+ }
error = driver_add_attrs(bus, drv);
if (error) {
/* How the hell do we get out of this pickle? Give up */
@@ -649,7 +673,7 @@ int bus_add_driver(struct device_driver *drv)
out_unregister:
kobject_unregister(&drv->kobj);
out_put_bus:
- put_bus(bus);
+ bus_put(bus);
return error;
}
@@ -669,12 +693,13 @@ void bus_remove_driver(struct device_driver * drv)
remove_bind_files(drv);
driver_remove_attrs(drv->bus, drv);
+ driver_remove_file(drv, &driver_attr_uevent);
klist_remove(&drv->knode_bus);
pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
driver_detach(drv);
module_remove_driver(drv);
kobject_unregister(&drv->kobj);
- put_bus(drv->bus);
+ bus_put(drv->bus);
}
@@ -729,18 +754,6 @@ int device_reprobe(struct device *dev)
}
EXPORT_SYMBOL_GPL(device_reprobe);
-struct bus_type *get_bus(struct bus_type *bus)
-{
- return bus ? container_of(subsys_get(&bus->subsys),
- struct bus_type, subsys) : NULL;
-}
-
-void put_bus(struct bus_type * bus)
-{
- subsys_put(&bus->subsys);
-}
-
-
/**
* find_bus - locate bus by name.
* @name: name of bus.
@@ -808,6 +821,17 @@ static void klist_devices_put(struct klist_node *n)
put_device(dev);
}
+static ssize_t bus_uevent_store(struct bus_type *bus,
+ const char *buf, size_t count)
+{
+ enum kobject_action action;
+
+ if (kobject_action_type(buf, count, &action) == 0)
+ kobject_uevent(&bus->subsys.kobj, action);
+ return count;
+}
+static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
+
/**
* bus_register - register a bus with the system.
* @bus: bus.
@@ -826,11 +850,16 @@ int bus_register(struct bus_type * bus)
if (retval)
goto out;
- subsys_set_kset(bus, bus_subsys);
+ bus->subsys.kobj.kset = &bus_subsys;
+
retval = subsystem_register(&bus->subsys);
if (retval)
goto out;
+ retval = bus_create_file(bus, &bus_attr_uevent);
+ if (retval)
+ goto bus_uevent_fail;
+
kobject_set_name(&bus->devices.kobj, "devices");
bus->devices.kobj.parent = &bus->subsys.kobj;
retval = kset_register(&bus->devices);
@@ -839,7 +868,7 @@ int bus_register(struct bus_type * bus)
kobject_set_name(&bus->drivers.kobj, "drivers");
bus->drivers.kobj.parent = &bus->subsys.kobj;
- bus->drivers.ktype = &ktype_driver;
+ bus->drivers.ktype = &driver_ktype;
retval = kset_register(&bus->drivers);
if (retval)
goto bus_drivers_fail;
@@ -866,6 +895,8 @@ bus_probe_files_fail:
bus_drivers_fail:
kset_unregister(&bus->devices);
bus_devices_fail:
+ bus_remove_file(bus, &bus_attr_uevent);
+bus_uevent_fail:
subsystem_unregister(&bus->subsys);
out:
return retval;
@@ -876,7 +907,7 @@ out:
* @bus: bus.
*
* Unregister the child subsystems and the bus itself.
- * Finally, we call put_bus() to release the refcount
+ * Finally, we call bus_put() to release the refcount
*/
void bus_unregister(struct bus_type * bus)
{
@@ -885,6 +916,7 @@ void bus_unregister(struct bus_type * bus)
remove_probe_files(bus);
kset_unregister(&bus->drivers);
kset_unregister(&bus->devices);
+ bus_remove_file(bus, &bus_attr_uevent);
subsystem_unregister(&bus->subsys);
}
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 4d2222618b7..a863bb091e1 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -65,13 +65,13 @@ static struct sysfs_ops class_sysfs_ops = {
.store = class_attr_store,
};
-static struct kobj_type ktype_class = {
+static struct kobj_type class_ktype = {
.sysfs_ops = &class_sysfs_ops,
.release = class_release,
};
/* Hotplug events for classes go to the class_obj subsys */
-static decl_subsys(class, &ktype_class, NULL);
+static decl_subsys(class, &class_ktype, NULL);
int class_create_file(struct class * cls, const struct class_attribute * attr)
@@ -93,14 +93,14 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr)
static struct class *class_get(struct class *cls)
{
if (cls)
- return container_of(subsys_get(&cls->subsys), struct class, subsys);
+ return container_of(kset_get(&cls->subsys), struct class, subsys);
return NULL;
}
static void class_put(struct class * cls)
{
if (cls)
- subsys_put(&cls->subsys);
+ kset_put(&cls->subsys);
}
@@ -149,7 +149,7 @@ int class_register(struct class * cls)
if (error)
return error;
- subsys_set_kset(cls, class_subsys);
+ cls->subsys.kobj.kset = &class_subsys;
error = subsystem_register(&cls->subsys);
if (!error) {
@@ -180,8 +180,7 @@ static void class_device_create_release(struct class_device *class_dev)
/* needed to allow these devices to have parent class devices */
static int class_device_create_uevent(struct class_device *class_dev,
- char **envp, int num_envp,
- char *buffer, int buffer_size)
+ struct kobj_uevent_env *env)
{
pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id);
return 0;
@@ -324,7 +323,7 @@ static void class_dev_release(struct kobject * kobj)
}
}
-static struct kobj_type ktype_class_device = {
+static struct kobj_type class_device_ktype = {
.sysfs_ops = &class_dev_sysfs_ops,
.release = class_dev_release,
};
@@ -333,7 +332,7 @@ static int class_uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
- if (ktype == &ktype_class_device) {
+ if (ktype == &class_device_ktype) {
struct class_device *class_dev = to_class_dev(kobj);
if (class_dev->class)
return 1;
@@ -403,64 +402,43 @@ static void remove_deprecated_class_device_links(struct class_device *cd)
{ }
#endif
-static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int class_uevent(struct kset *kset, struct kobject *kobj,
+ struct kobj_uevent_env *env)
{
struct class_device *class_dev = to_class_dev(kobj);
struct device *dev = class_dev->dev;
- int i = 0;
- int length = 0;
int retval = 0;
pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
if (MAJOR(class_dev->devt)) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MAJOR=%u", MAJOR(class_dev->devt));
+ add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt));
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MINOR=%u", MINOR(class_dev->devt));
+ add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt));
}
if (dev) {
const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
if (path) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVPATH=%s", path);
+ add_uevent_var(env, "PHYSDEVPATH=%s", path);
kfree(path);
}
if (dev->bus)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVBUS=%s", dev->bus->name);
+ add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
if (dev->driver)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVDRIVER=%s", dev->driver->name);
+ add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
}
- /* terminate, set to next free slot, shrink available space */
- envp[i] = NULL;
- envp = &envp[i];
- num_envp -= i;
- buffer = &buffer[length];
- buffer_size -= length;
-
if (class_dev->uevent) {
/* have the class device specific function add its stuff */
- retval = class_dev->uevent(class_dev, envp, num_envp,
- buffer, buffer_size);
+ retval = class_dev->uevent(class_dev, env);
if (retval)
pr_debug("class_dev->uevent() returned %d\n", retval);
} else if (class_dev->class->uevent) {
/* have the class specific function add its stuff */
- retval = class_dev->class->uevent(class_dev, envp, num_envp,
- buffer, buffer_size);
+ retval = class_dev->class->uevent(class_dev, env);
if (retval)
pr_debug("class->uevent() returned %d\n", retval);
}
@@ -474,7 +452,7 @@ static struct kset_uevent_ops class_uevent_ops = {
.uevent = class_uevent,
};
-static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);
+static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops);
static int class_device_add_attrs(struct class_device * cd)
@@ -883,7 +861,7 @@ int __init classes_init(void)
/* ick, this is ugly, the things we go through to keep from showing up
* in sysfs... */
- subsystem_init(&class_obj_subsys);
+ kset_init(&class_obj_subsys);
if (!class_obj_subsys.kobj.parent)
class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
return 0;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index ec86d6fc236..3f4d6aa1399 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -108,7 +108,7 @@ static void device_release(struct kobject * kobj)
}
}
-static struct kobj_type ktype_device = {
+static struct kobj_type device_ktype = {
.release = device_release,
.sysfs_ops = &dev_sysfs_ops,
};
@@ -118,7 +118,7 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
- if (ktype == &ktype_device) {
+ if (ktype == &device_ktype) {
struct device *dev = to_dev(kobj);
if (dev->uevent_suppress)
return 0;
@@ -141,33 +141,23 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj)
return NULL;
}
-static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int dev_uevent(struct kset *kset, struct kobject *kobj,
+ struct kobj_uevent_env *env)
{
struct device *dev = to_dev(kobj);
- int i = 0;
- int length = 0;
int retval = 0;
/* add the major/minor if present */
if (MAJOR(dev->devt)) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MAJOR=%u", MAJOR(dev->devt));
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MINOR=%u", MINOR(dev->devt));
+ add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
+ add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
}
if (dev->type && dev->type->name)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVTYPE=%s", dev->type->name);
+ add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
if (dev->driver)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DRIVER=%s", dev->driver->name);
+ add_uevent_var(env, "DRIVER=%s", dev->driver->name);
#ifdef CONFIG_SYSFS_DEPRECATED
if (dev->class) {
@@ -181,59 +171,43 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
path = kobject_get_path(&parent->kobj, GFP_KERNEL);
if (path) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVPATH=%s", path);
+ add_uevent_var(env, "PHYSDEVPATH=%s", path);
kfree(path);
}
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVBUS=%s", parent->bus->name);
+ add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name);
if (parent->driver)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVDRIVER=%s", parent->driver->name);
+ add_uevent_var(env, "PHYSDEVDRIVER=%s",
+ parent->driver->name);
}
} else if (dev->bus) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVBUS=%s", dev->bus->name);
+ add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
if (dev->driver)
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PHYSDEVDRIVER=%s", dev->driver->name);
+ add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
}
#endif
- /* terminate, set to next free slot, shrink available space */
- envp[i] = NULL;
- envp = &envp[i];
- num_envp -= i;
- buffer = &buffer[length];
- buffer_size -= length;
-
+ /* have the bus specific function add its stuff */
if (dev->bus && dev->bus->uevent) {
- /* have the bus specific function add its stuff */
- retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
+ retval = dev->bus->uevent(dev, env);
if (retval)
pr_debug ("%s: bus uevent() returned %d\n",
__FUNCTION__, retval);
}
+ /* have the class specific function add its stuff */
if (dev->class && dev->class->dev_uevent) {
- /* have the class specific function add its stuff */
- retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
+ retval = dev->class->dev_uevent(dev, env);
if (retval)
pr_debug("%s: class uevent() returned %d\n",
__FUNCTION__, retval);
}
+ /* have the device type specific fuction add its stuff */
if (dev->type && dev->type->uevent) {
- /* have the device type specific fuction add its stuff */
- retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size);
+ retval = dev->type->uevent(dev, env);
if (retval)
pr_debug("%s: dev_type uevent() returned %d\n",
__FUNCTION__, retval);
@@ -253,22 +227,18 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
{
struct kobject *top_kobj;
struct kset *kset;
- char *envp[32];
- char *data = NULL;
- char *pos;
+ struct kobj_uevent_env *env = NULL;
int i;
size_t count = 0;
int retval;
/* search the kset, the device belongs to */
top_kobj = &dev->kobj;
- if (!top_kobj->kset && top_kobj->parent) {
- do {
- top_kobj = top_kobj->parent;
- } while (!top_kobj->kset && top_kobj->parent);
- }
+ while (!top_kobj->kset && top_kobj->parent)
+ top_kobj = top_kobj->parent;
if (!top_kobj->kset)
goto out;
+
kset = top_kobj->kset;
if (!kset->uevent_ops || !kset->uevent_ops->uevent)
goto out;
@@ -278,43 +248,29 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
if (!kset->uevent_ops->filter(kset, &dev->kobj))
goto out;
- data = (char *)get_zeroed_page(GFP_KERNEL);
- if (!data)
+ env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
+ if (!env)
return -ENOMEM;
/* let the kset specific function add its keys */
- pos = data;
- memset(envp, 0, sizeof(envp));
- retval = kset->uevent_ops->uevent(kset, &dev->kobj,
- envp, ARRAY_SIZE(envp),
- pos, PAGE_SIZE);
+ retval = kset->uevent_ops->uevent(kset, &dev->kobj, env);
if (retval)
goto out;
/* copy keys to file */
- for (i = 0; envp[i]; i++) {
- pos = &buf[count];
- count += sprintf(pos, "%s\n", envp[i]);
- }
+ for (i = 0; i < env->envp_idx; i++)
+ count += sprintf(&buf[count], "%s\n", env->envp[i]);
out:
- free_page((unsigned long)data);
+ kfree(env);
return count;
}
static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- size_t len = count;
enum kobject_action action;
- if (len && buf[len-1] == '\n')
- len--;
-
- for (action = 0; action < KOBJ_MAX; action++) {
- if (strncmp(kobject_actions[action], buf, len) != 0)
- continue;
- if (kobject_actions[action][len] != '\0')
- continue;
+ if (kobject_action_type(buf, count, &action) == 0) {
kobject_uevent(&dev->kobj, action);
goto out;
}
@@ -449,7 +405,7 @@ static struct device_attribute devt_attr =
* devices_subsys - structure to be registered with kobject core.
*/
-decl_subsys(devices, &ktype_device, &device_uevent_ops);
+decl_subsys(devices, &device_ktype, &device_uevent_ops);
/**
@@ -1272,18 +1228,18 @@ int device_rename(struct device *dev, char *new_name)
sysfs_remove_link(&dev->parent->kobj, old_class_name);
}
}
-#endif
-
+#else
if (dev->class) {
sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
dev->bus_id);
if (error) {
- /* Uh... how to unravel this if restoring can fail? */
dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n",
__FUNCTION__, error);
}
}
+#endif
+
out:
put_device(dev);
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c
index 7647abfe189..b5034dc72a0 100644
--- a/drivers/base/dmapool.c
+++ b/drivers/base/dmapool.c
@@ -2,7 +2,6 @@
#include <linux/device.h>
#include <linux/mm.h>
#include <asm/io.h> /* Needed for i386 to build */
-#include <asm/scatterlist.h> /* Needed for i386 to build */
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/slab.h>
@@ -302,7 +301,7 @@ restart:
if (mem_flags & __GFP_WAIT) {
DECLARE_WAITQUEUE (wait, current);
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue (&pool->waitq, &wait);
spin_unlock_irqrestore (&pool->lock, flags);
@@ -366,7 +365,7 @@ dma_pool_free (struct dma_pool *pool, void *vaddr, dma_addr_t dma)
unsigned long flags;
int map, block;
- if ((page = pool_find_page (pool, dma)) == 0) {
+ if ((page = pool_find_page(pool, dma)) == NULL) {
if (pool->dev)
dev_err(pool->dev, "dma_pool_free %s, %p/%lx (bad dma)\n",
pool->name, vaddr, (unsigned long) dma);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index b24efd4e3e3..0295855a3ee 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -88,19 +88,14 @@ static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store);
static void fw_dev_release(struct device *dev);
-static int firmware_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct firmware_priv *fw_priv = dev_get_drvdata(dev);
- int i = 0, len = 0;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "FIRMWARE=%s", fw_priv->fw_id))
+ if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "TIMEOUT=%i", loading_timeout))
+ if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
return -ENOMEM;
- envp[i] = NULL;
return 0;
}
@@ -297,8 +292,7 @@ firmware_class_timeout(u_long data)
static inline void fw_setup_device_id(struct device *f_dev, struct device *dev)
{
- /* XXX warning we should watch out for name collisions */
- strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE);
+ snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id);
}
static int fw_register_device(struct device **dev_p, const char *fw_name,
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 74b96795d2f..7868707c7ed 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -34,8 +34,7 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj)
return MEMORY_CLASS_NAME;
}
-static int memory_uevent(struct kset *kset, struct kobject *kobj, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int memory_uevent(struct kset *kset, struct kobject *obj, struct kobj_uevent_env *env)
{
int retval = 0;
@@ -138,7 +137,7 @@ static ssize_t show_mem_state(struct sys_device *dev, char *buf)
return len;
}
-static inline int memory_notify(unsigned long val, void *v)
+int memory_notify(unsigned long val, void *v)
{
return blocking_notifier_call_chain(&memory_chain, val, v);
}
@@ -184,7 +183,6 @@ memory_block_action(struct memory_block *mem, unsigned long action)
break;
case MEM_OFFLINE:
mem->state = MEM_GOING_OFFLINE;
- memory_notify(MEM_GOING_OFFLINE, NULL);
start_paddr = page_to_pfn(first_page) << PAGE_SHIFT;
ret = remove_memory(start_paddr,
PAGES_PER_SECTION << PAGE_SHIFT);
@@ -192,7 +190,6 @@ memory_block_action(struct memory_block *mem, unsigned long action)
mem->state = old_state;
break;
}
- memory_notify(MEM_MAPPING_INVALID, NULL);
break;
default:
printk(KERN_WARNING "%s(%p, %ld) unknown action: %ld\n",
@@ -200,11 +197,6 @@ memory_block_action(struct memory_block *mem, unsigned long action)
WARN_ON(1);
ret = -EINVAL;
}
- /*
- * For now, only notify on successful memory operations
- */
- if (!ret)
- memory_notify(action, NULL);
return ret;
}
@@ -239,7 +231,7 @@ store_mem_state(struct sys_device *dev, const char *buf, size_t count)
mem = container_of(dev, struct memory_block, sysdev);
phys_section_nr = mem->phys_index;
- if (!valid_section_nr(phys_section_nr))
+ if (!present_section_nr(phys_section_nr))
goto out;
if (!strncmp(buf, "online", min((int)count, 6)))
@@ -419,7 +411,7 @@ int register_new_memory(struct mem_section *section)
int unregister_memory_section(struct mem_section *section)
{
- if (!valid_section(section))
+ if (!present_section(section))
return -EINVAL;
return remove_memory_block(0, section, 0);
@@ -444,7 +436,7 @@ int __init memory_dev_init(void)
* during boot and have been initialized
*/
for (i = 0; i < NR_MEM_SECTIONS; i++) {
- if (!valid_section_nr(i))
+ if (!present_section_nr(i))
continue;
err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE, 0);
if (!ret)
diff --git a/drivers/base/node.c b/drivers/base/node.c
index cae346ef1b2..88eeed72b5d 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -12,6 +12,7 @@
#include <linux/topology.h>
#include <linux/nodemask.h>
#include <linux/cpu.h>
+#include <linux/device.h>
static struct sysdev_class node_class = {
set_kset_name("node"),
@@ -232,8 +233,96 @@ void unregister_one_node(int nid)
unregister_node(&node_devices[nid]);
}
+/*
+ * node states attributes
+ */
+
+static ssize_t print_nodes_state(enum node_states state, char *buf)
+{
+ int n;
+
+ n = nodelist_scnprintf(buf, PAGE_SIZE, node_states[state]);
+ if (n > 0 && PAGE_SIZE > n + 1) {
+ *(buf + n++) = '\n';
+ *(buf + n++) = '\0';
+ }
+ return n;
+}
+
+static ssize_t print_nodes_possible(struct sysdev_class *class, char *buf)
+{
+ return print_nodes_state(N_POSSIBLE, buf);
+}
+
+static ssize_t print_nodes_online(struct sysdev_class *class, char *buf)
+{
+ return print_nodes_state(N_ONLINE, buf);
+}
+
+static ssize_t print_nodes_has_normal_memory(struct sysdev_class *class,
+ char *buf)
+{
+ return print_nodes_state(N_NORMAL_MEMORY, buf);
+}
+
+static ssize_t print_nodes_has_cpu(struct sysdev_class *class, char *buf)
+{
+ return print_nodes_state(N_CPU, buf);
+}
+
+static SYSDEV_CLASS_ATTR(possible, 0444, print_nodes_possible, NULL);
+static SYSDEV_CLASS_ATTR(online, 0444, print_nodes_online, NULL);
+static SYSDEV_CLASS_ATTR(has_normal_memory, 0444, print_nodes_has_normal_memory,
+ NULL);
+static SYSDEV_CLASS_ATTR(has_cpu, 0444, print_nodes_has_cpu, NULL);
+
+#ifdef CONFIG_HIGHMEM
+static ssize_t print_nodes_has_high_memory(struct sysdev_class *class,
+ char *buf)
+{
+ return print_nodes_state(N_HIGH_MEMORY, buf);
+}
+
+static SYSDEV_CLASS_ATTR(has_high_memory, 0444, print_nodes_has_high_memory,
+ NULL);
+#endif
+
+struct sysdev_class_attribute *node_state_attr[] = {
+ &attr_possible,
+ &attr_online,
+ &attr_has_normal_memory,
+#ifdef CONFIG_HIGHMEM
+ &attr_has_high_memory,
+#endif
+ &attr_has_cpu,
+};
+
+static int node_states_init(void)
+{
+ int i;
+ int err = 0;
+
+ for (i = 0; i < NR_NODE_STATES; i++) {
+ int ret;
+ ret = sysdev_class_create_file(&node_class, node_state_attr[i]);
+ if (!err)
+ err = ret;
+ }
+ return err;
+}
+
static int __init register_node_type(void)
{
- return sysdev_class_register(&node_class);
+ int ret;
+
+ ret = sysdev_class_register(&node_class);
+ if (!ret)
+ ret = node_states_init();
+
+ /*
+ * Note: we're not going to unregister the node class if we fail
+ * to register the node state class attribute files.
+ */
+ return ret;
}
postcore_initcall(register_node_type);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 869ff8c0014..fb560924148 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -160,13 +160,8 @@ static void platform_device_release(struct device *dev)
*
* Create a platform device object which can have other objects attached
* to it, and which will have attached objects freed when it is released.
- *
- * This device will be marked as not supporting hotpluggable drivers; no
- * device add/remove uevents will be generated. In the unusual case that
- * the device isn't being dynamically allocated as a legacy "probe the
- * hardware" driver, infrastructure code should reverse this marking.
*/
-struct platform_device *platform_device_alloc(const char *name, unsigned int id)
+struct platform_device *platform_device_alloc(const char *name, int id)
{
struct platform_object *pa;
@@ -177,12 +172,6 @@ struct platform_device *platform_device_alloc(const char *name, unsigned int id)
pa->pdev.id = id;
device_initialize(&pa->pdev.dev);
pa->pdev.dev.release = platform_device_release;
-
- /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in
- * legacy probe-the-hardware drivers, which don't properly split
- * out device enumeration logic from drivers.
- */
- pa->pdev.dev.uevent_suppress = 1;
}
return pa ? &pa->pdev : NULL;
@@ -256,7 +245,8 @@ int platform_device_add(struct platform_device *pdev)
pdev->dev.bus = &platform_bus_type;
if (pdev->id != -1)
- snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
+ snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
+ pdev->id);
else
strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
@@ -370,7 +360,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister);
* the Linux driver model. In particular, when such drivers are built
* as modules, they can't be "hotplugged".
*/
-struct platform_device *platform_device_register_simple(char *name, unsigned int id,
+struct platform_device *platform_device_register_simple(char *name, int id,
struct resource *res, unsigned int num)
{
struct platform_device *pdev;
@@ -530,7 +520,7 @@ static ssize_t
modalias_show(struct device *dev, struct device_attribute *a, char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
- int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name);
+ int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
@@ -540,13 +530,11 @@ static struct device_attribute platform_dev_attrs[] = {
__ATTR_NULL,
};
-static int platform_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct platform_device *pdev = to_platform_device(dev);
- envp[0] = buffer;
- snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name);
+ add_uevent_var(env, "MODALIAS=platform:%s", pdev->name);
return 0;
}
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 9caeaea753a..a803733c839 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,5 +1,5 @@
obj-y := shutdown.o
-obj-$(CONFIG_PM_SLEEP) += main.o suspend.o resume.o sysfs.o
+obj-$(CONFIG_PM_SLEEP) += main.o sysfs.o
obj-$(CONFIG_PM_TRACE) += trace.o
ifeq ($(CONFIG_DEBUG_DRIVER),y)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index eb9f38d0aa5..0ab4ab21f56 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -20,19 +20,24 @@
*/
#include <linux/device.h>
+#include <linux/kallsyms.h>
#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/resume-trace.h>
+#include "../base.h"
#include "power.h"
LIST_HEAD(dpm_active);
-LIST_HEAD(dpm_off);
-LIST_HEAD(dpm_off_irq);
+static LIST_HEAD(dpm_off);
+static LIST_HEAD(dpm_off_irq);
-DEFINE_MUTEX(dpm_mtx);
-DEFINE_MUTEX(dpm_list_mtx);
+static DEFINE_MUTEX(dpm_mtx);
+static DEFINE_MUTEX(dpm_list_mtx);
int (*platform_enable_wakeup)(struct device *dev, int is_on);
+
int device_pm_add(struct device *dev)
{
int error;
@@ -61,3 +66,334 @@ void device_pm_remove(struct device *dev)
}
+/*------------------------- Resume routines -------------------------*/
+
+/**
+ * resume_device - Restore state for one device.
+ * @dev: Device.
+ *
+ */
+
+static int resume_device(struct device * dev)
+{
+ int error = 0;
+
+ TRACE_DEVICE(dev);
+ TRACE_RESUME(0);
+
+ down(&dev->sem);
+
+ if (dev->bus && dev->bus->resume) {
+ dev_dbg(dev,"resuming\n");
+ error = dev->bus->resume(dev);
+ }
+
+ if (!error && dev->type && dev->type->resume) {
+ dev_dbg(dev,"resuming\n");
+ error = dev->type->resume(dev);
+ }
+
+ if (!error && dev->class && dev->class->resume) {
+ dev_dbg(dev,"class resume\n");
+ error = dev->class->resume(dev);
+ }
+
+ up(&dev->sem);
+
+ TRACE_RESUME(error);
+ return error;
+}
+
+
+static int resume_device_early(struct device * dev)
+{
+ int error = 0;
+
+ TRACE_DEVICE(dev);
+ TRACE_RESUME(0);
+ if (dev->bus && dev->bus->resume_early) {
+ dev_dbg(dev,"EARLY resume\n");
+ error = dev->bus->resume_early(dev);
+ }
+ TRACE_RESUME(error);
+ return error;
+}
+
+/*
+ * Resume the devices that have either not gone through
+ * the late suspend, or that did go through it but also
+ * went through the early resume
+ */
+static void dpm_resume(void)
+{
+ mutex_lock(&dpm_list_mtx);
+ while(!list_empty(&dpm_off)) {
+ struct list_head * entry = dpm_off.next;
+ struct device * dev = to_device(entry);
+
+ get_device(dev);
+ list_move_tail(entry, &dpm_active);
+
+ mutex_unlock(&dpm_list_mtx);
+ resume_device(dev);
+ mutex_lock(&dpm_list_mtx);
+ put_device(dev);
+ }
+ mutex_unlock(&dpm_list_mtx);
+}
+
+
+/**
+ * device_resume - Restore state of each device in system.
+ *
+ * Walk the dpm_off list, remove each entry, resume the device,
+ * then add it to the dpm_active list.
+ */
+
+void device_resume(void)
+{
+ might_sleep();
+ mutex_lock(&dpm_mtx);
+ dpm_resume();
+ mutex_unlock(&dpm_mtx);
+}
+
+EXPORT_SYMBOL_GPL(device_resume);
+
+
+/**
+ * dpm_power_up - Power on some devices.
+ *
+ * Walk the dpm_off_irq list and power each device up. This
+ * is used for devices that required they be powered down with
+ * interrupts disabled. As devices are powered on, they are moved
+ * to the dpm_active list.
+ *
+ * Interrupts must be disabled when calling this.
+ */
+
+static void dpm_power_up(void)
+{
+ while(!list_empty(&dpm_off_irq)) {
+ struct list_head * entry = dpm_off_irq.next;
+ struct device * dev = to_device(entry);
+
+ list_move_tail(entry, &dpm_off);
+ resume_device_early(dev);
+ }
+}
+
+
+/**
+ * device_power_up - Turn on all devices that need special attention.
+ *
+ * Power on system devices then devices that required we shut them down
+ * with interrupts disabled.
+ * Called with interrupts disabled.
+ */
+
+void device_power_up(void)
+{
+ sysdev_resume();
+ dpm_power_up();
+}
+
+EXPORT_SYMBOL_GPL(device_power_up);
+
+
+/*------------------------- Suspend routines -------------------------*/
+
+/*
+ * The entries in the dpm_active list are in a depth first order, simply
+ * because children are guaranteed to be discovered after parents, and
+ * are inserted at the back of the list on discovery.
+ *
+ * All list on the suspend path are done in reverse order, so we operate
+ * on the leaves of the device tree (or forests, depending on how you want
+ * to look at it ;) first. As nodes are removed from the back of the list,
+ * they are inserted into the front of their destintation lists.
+ *
+ * Things are the reverse on the resume path - iterations are done in
+ * forward order, and nodes are inserted at the back of their destination
+ * lists. This way, the ancestors will be accessed before their descendents.
+ */
+
+static inline char *suspend_verb(u32 event)
+{
+ switch (event) {
+ case PM_EVENT_SUSPEND: return "suspend";
+ case PM_EVENT_FREEZE: return "freeze";
+ case PM_EVENT_PRETHAW: return "prethaw";
+ default: return "(unknown suspend event)";
+ }
+}
+
+
+static void
+suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
+{
+ dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
+ ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
+ ", may wakeup" : "");
+}
+
+/**
+ * suspend_device - Save state of one device.
+ * @dev: Device.
+ * @state: Power state device is entering.
+ */
+
+static int suspend_device(struct device * dev, pm_message_t state)
+{
+ int error = 0;
+
+ down(&dev->sem);
+ if (dev->power.power_state.event) {
+ dev_dbg(dev, "PM: suspend %d-->%d\n",
+ dev->power.power_state.event, state.event);
+ }
+
+ if (dev->class && dev->class->suspend) {
+ suspend_device_dbg(dev, state, "class ");
+ error = dev->class->suspend(dev, state);
+ suspend_report_result(dev->class->suspend, error);
+ }
+
+ if (!error && dev->type && dev->type->suspend) {
+ suspend_device_dbg(dev, state, "type ");
+ error = dev->type->suspend(dev, state);
+ suspend_report_result(dev->type->suspend, error);
+ }
+
+ if (!error && dev->bus && dev->bus->suspend) {
+ suspend_device_dbg(dev, state, "");
+ error = dev->bus->suspend(dev, state);
+ suspend_report_result(dev->bus->suspend, error);
+ }
+ up(&dev->sem);
+ return error;
+}
+
+
+/*
+ * This is called with interrupts off, only a single CPU
+ * running. We can't acquire a mutex or semaphore (and we don't
+ * need the protection)
+ */
+static int suspend_device_late(struct device *dev, pm_message_t state)
+{
+ int error = 0;
+
+ if (dev->bus && dev->bus->suspend_late) {
+ suspend_device_dbg(dev, state, "LATE ");
+ error = dev->bus->suspend_late(dev, state);
+ suspend_report_result(dev->bus->suspend_late, error);
+ }
+ return error;
+}
+
+/**
+ * device_suspend - Save state and stop all devices in system.
+ * @state: Power state to put each device in.
+ *
+ * Walk the dpm_active list, call ->suspend() for each device, and move
+ * it to the dpm_off list.
+ *
+ * (For historical reasons, if it returns -EAGAIN, that used to mean
+ * that the device would be called again with interrupts disabled.
+ * These days, we use the "suspend_late()" callback for that, so we
+ * print a warning and consider it an error).
+ *
+ * If we get a different error, try and back out.
+ *
+ * If we hit a failure with any of the devices, call device_resume()
+ * above to bring the suspended devices back to life.
+ *
+ */
+
+int device_suspend(pm_message_t state)
+{
+ int error = 0;
+
+ might_sleep();
+ mutex_lock(&dpm_mtx);
+ mutex_lock(&dpm_list_mtx);
+ while (!list_empty(&dpm_active) && error == 0) {
+ struct list_head * entry = dpm_active.prev;
+ struct device * dev = to_device(entry);
+
+ get_device(dev);
+ mutex_unlock(&dpm_list_mtx);
+
+ error = suspend_device(dev, state);
+
+ mutex_lock(&dpm_list_mtx);
+
+ /* Check if the device got removed */
+ if (!list_empty(&dev->power.entry)) {
+ /* Move it to the dpm_off list */
+ if (!error)
+ list_move(&dev->power.entry, &dpm_off);
+ }
+ if (error)
+ printk(KERN_ERR "Could not suspend device %s: "
+ "error %d%s\n",
+ kobject_name(&dev->kobj), error,
+ error == -EAGAIN ? " (please convert to suspend_late)" : "");
+ put_device(dev);
+ }
+ mutex_unlock(&dpm_list_mtx);
+ if (error)
+ dpm_resume();
+
+ mutex_unlock(&dpm_mtx);
+ return error;
+}
+
+EXPORT_SYMBOL_GPL(device_suspend);
+
+/**
+ * device_power_down - Shut down special devices.
+ * @state: Power state to enter.
+ *
+ * Walk the dpm_off_irq list, calling ->power_down() for each device that
+ * couldn't power down the device with interrupts enabled. When we're
+ * done, power down system devices.
+ */
+
+int device_power_down(pm_message_t state)
+{
+ int error = 0;
+ struct device * dev;
+
+ while (!list_empty(&dpm_off)) {
+ struct list_head * entry = dpm_off.prev;
+
+ dev = to_device(entry);
+ error = suspend_device_late(dev, state);
+ if (error)
+ goto Error;
+ list_move(&dev->power.entry, &dpm_off_irq);
+ }
+
+ error = sysdev_suspend(state);
+ Done:
+ return error;
+ Error:
+ printk(KERN_ERR "Could not power down device %s: "
+ "error %d\n", kobject_name(&dev->kobj), error);
+ dpm_power_up();
+ goto Done;
+}
+
+EXPORT_SYMBOL_GPL(device_power_down);
+
+void __suspend_report_result(const char *function, void *fn, int ret)
+{
+ if (ret) {
+ printk(KERN_ERR "%s(): ", function);
+ print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
+ printk("%d\n", ret);
+ }
+}
+EXPORT_SYMBOL_GPL(__suspend_report_result);
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 8ba0830cbc0..5c4efd493fa 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -11,32 +11,11 @@ extern void device_shutdown(void);
* main.c
*/
-/*
- * Used to synchronize global power management operations.
- */
-extern struct mutex dpm_mtx;
-
-/*
- * Used to serialize changes to the dpm_* lists.
- */
-extern struct mutex dpm_list_mtx;
-
-/*
- * The PM lists.
- */
-extern struct list_head dpm_active;
-extern struct list_head dpm_off;
-extern struct list_head dpm_off_irq;
-
-
-static inline struct dev_pm_info * to_pm_info(struct list_head * entry)
-{
- return container_of(entry, struct dev_pm_info, entry);
-}
+extern struct list_head dpm_active; /* The active device list */
static inline struct device * to_device(struct list_head * entry)
{
- return container_of(to_pm_info(entry), struct device, power);
+ return container_of(entry, struct device, power.entry);
}
extern int device_pm_add(struct device *);
@@ -49,19 +28,6 @@ extern void device_pm_remove(struct device *);
extern int dpm_sysfs_add(struct device *);
extern void dpm_sysfs_remove(struct device *);
-/*
- * resume.c
- */
-
-extern void dpm_resume(void);
-extern void dpm_power_up(void);
-extern int resume_device(struct device *);
-
-/*
- * suspend.c
- */
-extern int suspend_device(struct device *, pm_message_t);
-
#else /* CONFIG_PM_SLEEP */
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
deleted file mode 100644
index 00fd84ae6e6..00000000000
--- a/drivers/base/power/resume.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * resume.c - Functions for waking devices up.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/resume-trace.h>
-#include "../base.h"
-#include "power.h"
-
-
-/**
- * resume_device - Restore state for one device.
- * @dev: Device.
- *
- */
-
-int resume_device(struct device * dev)
-{
- int error = 0;
-
- TRACE_DEVICE(dev);
- TRACE_RESUME(0);
-
- down(&dev->sem);
-
- if (dev->bus && dev->bus->resume) {
- dev_dbg(dev,"resuming\n");
- error = dev->bus->resume(dev);
- }
-
- if (!error && dev->type && dev->type->resume) {
- dev_dbg(dev,"resuming\n");
- error = dev->type->resume(dev);
- }
-
- if (!error && dev->class && dev->class->resume) {
- dev_dbg(dev,"class resume\n");
- error = dev->class->resume(dev);
- }
-
- up(&dev->sem);
-
- TRACE_RESUME(error);
- return error;
-}
-
-
-static int resume_device_early(struct device * dev)
-{
- int error = 0;
-
- TRACE_DEVICE(dev);
- TRACE_RESUME(0);
- if (dev->bus && dev->bus->resume_early) {
- dev_dbg(dev,"EARLY resume\n");
- error = dev->bus->resume_early(dev);
- }
- TRACE_RESUME(error);
- return error;
-}
-
-/*
- * Resume the devices that have either not gone through
- * the late suspend, or that did go through it but also
- * went through the early resume
- */
-void dpm_resume(void)
-{
- mutex_lock(&dpm_list_mtx);
- while(!list_empty(&dpm_off)) {
- struct list_head * entry = dpm_off.next;
- struct device * dev = to_device(entry);
-
- get_device(dev);
- list_move_tail(entry, &dpm_active);
-
- mutex_unlock(&dpm_list_mtx);
- resume_device(dev);
- mutex_lock(&dpm_list_mtx);
- put_device(dev);
- }
- mutex_unlock(&dpm_list_mtx);
-}
-
-
-/**
- * device_resume - Restore state of each device in system.
- *
- * Walk the dpm_off list, remove each entry, resume the device,
- * then add it to the dpm_active list.
- */
-
-void device_resume(void)
-{
- might_sleep();
- mutex_lock(&dpm_mtx);
- dpm_resume();
- mutex_unlock(&dpm_mtx);
-}
-
-EXPORT_SYMBOL_GPL(device_resume);
-
-
-/**
- * dpm_power_up - Power on some devices.
- *
- * Walk the dpm_off_irq list and power each device up. This
- * is used for devices that required they be powered down with
- * interrupts disabled. As devices are powered on, they are moved
- * to the dpm_active list.
- *
- * Interrupts must be disabled when calling this.
- */
-
-void dpm_power_up(void)
-{
- while(!list_empty(&dpm_off_irq)) {
- struct list_head * entry = dpm_off_irq.next;
- struct device * dev = to_device(entry);
-
- list_move_tail(entry, &dpm_off);
- resume_device_early(dev);
- }
-}
-
-
-/**
- * device_power_up - Turn on all devices that need special attention.
- *
- * Power on system devices then devices that required we shut them down
- * with interrupts disabled.
- * Called with interrupts disabled.
- */
-
-void device_power_up(void)
-{
- sysdev_resume();
- dpm_power_up();
-}
-
-EXPORT_SYMBOL_GPL(device_power_up);
-
-
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
deleted file mode 100644
index 26df9b23173..00000000000
--- a/drivers/base/power/suspend.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * suspend.c - Functions for putting devices to sleep.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/kallsyms.h>
-#include <linux/pm.h>
-#include "../base.h"
-#include "power.h"
-
-/*
- * The entries in the dpm_active list are in a depth first order, simply
- * because children are guaranteed to be discovered after parents, and
- * are inserted at the back of the list on discovery.
- *
- * All list on the suspend path are done in reverse order, so we operate
- * on the leaves of the device tree (or forests, depending on how you want
- * to look at it ;) first. As nodes are removed from the back of the list,
- * they are inserted into the front of their destintation lists.
- *
- * Things are the reverse on the resume path - iterations are done in
- * forward order, and nodes are inserted at the back of their destination
- * lists. This way, the ancestors will be accessed before their descendents.
- */
-
-static inline char *suspend_verb(u32 event)
-{
- switch (event) {
- case PM_EVENT_SUSPEND: return "suspend";
- case PM_EVENT_FREEZE: return "freeze";
- case PM_EVENT_PRETHAW: return "prethaw";
- default: return "(unknown suspend event)";
- }
-}
-
-
-static void
-suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
-{
- dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
- ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
- ", may wakeup" : "");
-}
-
-/**
- * suspend_device - Save state of one device.
- * @dev: Device.
- * @state: Power state device is entering.
- */
-
-int suspend_device(struct device * dev, pm_message_t state)
-{
- int error = 0;
-
- down(&dev->sem);
- if (dev->power.power_state.event) {
- dev_dbg(dev, "PM: suspend %d-->%d\n",
- dev->power.power_state.event, state.event);
- }
-
- if (dev->class && dev->class->suspend) {
- suspend_device_dbg(dev, state, "class ");
- error = dev->class->suspend(dev, state);
- suspend_report_result(dev->class->suspend, error);
- }
-
- if (!error && dev->type && dev->type->suspend) {
- suspend_device_dbg(dev, state, "type ");
- error = dev->type->suspend(dev, state);
- suspend_report_result(dev->type->suspend, error);
- }
-
- if (!error && dev->bus && dev->bus->suspend) {
- suspend_device_dbg(dev, state, "");
- error = dev->bus->suspend(dev, state);
- suspend_report_result(dev->bus->suspend, error);
- }
- up(&dev->sem);
- return error;
-}
-
-
-/*
- * This is called with interrupts off, only a single CPU
- * running. We can't acquire a mutex or semaphore (and we don't
- * need the protection)
- */
-static int suspend_device_late(struct device *dev, pm_message_t state)
-{
- int error = 0;
-
- if (dev->bus && dev->bus->suspend_late) {
- suspend_device_dbg(dev, state, "LATE ");
- error = dev->bus->suspend_late(dev, state);
- suspend_report_result(dev->bus->suspend_late, error);
- }
- return error;
-}
-
-/**
- * device_suspend - Save state and stop all devices in system.
- * @state: Power state to put each device in.
- *
- * Walk the dpm_active list, call ->suspend() for each device, and move
- * it to the dpm_off list.
- *
- * (For historical reasons, if it returns -EAGAIN, that used to mean
- * that the device would be called again with interrupts disabled.
- * These days, we use the "suspend_late()" callback for that, so we
- * print a warning and consider it an error).
- *
- * If we get a different error, try and back out.
- *
- * If we hit a failure with any of the devices, call device_resume()
- * above to bring the suspended devices back to life.
- *
- */
-
-int device_suspend(pm_message_t state)
-{
- int error = 0;
-
- might_sleep();
- mutex_lock(&dpm_mtx);
- mutex_lock(&dpm_list_mtx);
- while (!list_empty(&dpm_active) && error == 0) {
- struct list_head * entry = dpm_active.prev;
- struct device * dev = to_device(entry);
-
- get_device(dev);
- mutex_unlock(&dpm_list_mtx);
-
- error = suspend_device(dev, state);
-
- mutex_lock(&dpm_list_mtx);
-
- /* Check if the device got removed */
- if (!list_empty(&dev->power.entry)) {
- /* Move it to the dpm_off list */
- if (!error)
- list_move(&dev->power.entry, &dpm_off);
- }
- if (error)
- printk(KERN_ERR "Could not suspend device %s: "
- "error %d%s\n",
- kobject_name(&dev->kobj), error,
- error == -EAGAIN ? " (please convert to suspend_late)" : "");
- put_device(dev);
- }
- mutex_unlock(&dpm_list_mtx);
- if (error)
- dpm_resume();
-
- mutex_unlock(&dpm_mtx);
- return error;
-}
-
-EXPORT_SYMBOL_GPL(device_suspend);
-
-/**
- * device_power_down - Shut down special devices.
- * @state: Power state to enter.
- *
- * Walk the dpm_off_irq list, calling ->power_down() for each device that
- * couldn't power down the device with interrupts enabled. When we're
- * done, power down system devices.
- */
-
-int device_power_down(pm_message_t state)
-{
- int error = 0;
- struct device * dev;
-
- while (!list_empty(&dpm_off)) {
- struct list_head * entry = dpm_off.prev;
-
- dev = to_device(entry);
- error = suspend_device_late(dev, state);
- if (error)
- goto Error;
- list_move(&dev->power.entry, &dpm_off_irq);
- }
-
- error = sysdev_suspend(state);
- Done:
- return error;
- Error:
- printk(KERN_ERR "Could not power down device %s: "
- "error %d\n", kobject_name(&dev->kobj), error);
- dpm_power_up();
- goto Done;
-}
-
-EXPORT_SYMBOL_GPL(device_power_down);
-
-void __suspend_report_result(const char *function, void *fn, int ret)
-{
- if (ret) {
- printk(KERN_ERR "%s(): ", function);
- print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
- printk("%d\n", ret);
- }
-}
-EXPORT_SYMBOL_GPL(__suspend_report_result);
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c
index 2b0c601e422..2b4b392dcbc 100644
--- a/drivers/base/power/trace.c
+++ b/drivers/base/power/trace.c
@@ -114,7 +114,7 @@ static unsigned int read_magic_time(void)
get_rtc_time(&time);
printk("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n",
time.tm_hour, time.tm_min, time.tm_sec,
- time.tm_mon, time.tm_mday, time.tm_year);
+ time.tm_mon + 1, time.tm_mday, time.tm_year % 100);
val = time.tm_year; /* 100 years */
if (val > 100)
val -= 100;
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 18febe26caa..ac7ff6d0c6e 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -139,7 +139,7 @@ int sysdev_class_register(struct sysdev_class * cls)
kobject_name(&cls->kset.kobj));
INIT_LIST_HEAD(&cls->drivers);
cls->kset.kobj.parent = &system_subsys.kobj;
- kset_set_kset_s(cls, system_subsys);
+ cls->kset.kobj.kset = &system_subsys;
return kset_register(&cls->kset);
}
@@ -153,25 +153,22 @@ void sysdev_class_unregister(struct sysdev_class * cls)
EXPORT_SYMBOL_GPL(sysdev_class_register);
EXPORT_SYMBOL_GPL(sysdev_class_unregister);
-
-static LIST_HEAD(sysdev_drivers);
static DEFINE_MUTEX(sysdev_drivers_lock);
/**
* sysdev_driver_register - Register auxillary driver
- * @cls: Device class driver belongs to.
+ * @cls: Device class driver belongs to.
* @drv: Driver.
*
- * If @cls is valid, then @drv is inserted into @cls->drivers to be
+ * @drv is inserted into @cls->drivers to be
* called on each operation on devices of that class. The refcount
* of @cls is incremented.
- * Otherwise, @drv is inserted into sysdev_drivers, and called for
- * each device.
*/
-int sysdev_driver_register(struct sysdev_class * cls,
- struct sysdev_driver * drv)
+int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
{
+ int err = 0;
+
mutex_lock(&sysdev_drivers_lock);
if (cls && kset_get(&cls->kset)) {
list_add_tail(&drv->entry, &cls->drivers);
@@ -182,10 +179,13 @@ int sysdev_driver_register(struct sysdev_class * cls,
list_for_each_entry(dev, &cls->kset.list, kobj.entry)
drv->add(dev);
}
- } else
- list_add_tail(&drv->entry, &sysdev_drivers);
+ } else {
+ err = -EINVAL;
+ printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__);
+ WARN_ON(1);
+ }
mutex_unlock(&sysdev_drivers_lock);
- return 0;
+ return err;
}
@@ -251,12 +251,6 @@ int sysdev_register(struct sys_device * sysdev)
* code that should have called us.
*/
- /* Notify global drivers */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->add)
- drv->add(sysdev);
- }
-
/* Notify class auxillary drivers */
list_for_each_entry(drv, &cls->drivers, entry) {
if (drv->add)
@@ -272,11 +266,6 @@ void sysdev_unregister(struct sys_device * sysdev)
struct sysdev_driver * drv;
mutex_lock(&sysdev_drivers_lock);
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->remove)
- drv->remove(sysdev);
- }
-
list_for_each_entry(drv, &sysdev->cls->drivers, entry) {
if (drv->remove)
drv->remove(sysdev);
@@ -293,7 +282,7 @@ void sysdev_unregister(struct sys_device * sysdev)
*
* Loop over each class of system devices, and the devices in each
* of those classes. For each device, we call the shutdown method for
- * each driver registered for the device - the globals, the auxillaries,
+ * each driver registered for the device - the auxillaries,
* and the class driver.
*
* Note: The list is iterated in reverse order, so that we shut down
@@ -320,13 +309,7 @@ void sysdev_shutdown(void)
struct sysdev_driver * drv;
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
- /* Call global drivers first. */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->shutdown)
- drv->shutdown(sysdev);
- }
-
- /* Call auxillary drivers next. */
+ /* Call auxillary drivers first */
list_for_each_entry(drv, &cls->drivers, entry) {
if (drv->shutdown)
drv->shutdown(sysdev);
@@ -354,12 +337,6 @@ static void __sysdev_resume(struct sys_device *dev)
if (drv->resume)
drv->resume(dev);
}
-
- /* Call global drivers. */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->resume)
- drv->resume(dev);
- }
}
/**
@@ -393,16 +370,7 @@ int sysdev_suspend(pm_message_t state)
list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
pr_debug(" %s\n", kobject_name(&sysdev->kobj));
- /* Call global drivers first. */
- list_for_each_entry(drv, &sysdev_drivers, entry) {
- if (drv->suspend) {
- ret = drv->suspend(sysdev, state);
- if (ret)
- goto gbl_driver;
- }
- }
-
- /* Call auxillary drivers next. */
+ /* Call auxillary drivers first */
list_for_each_entry(drv, &cls->drivers, entry) {
if (drv->suspend) {
ret = drv->suspend(sysdev, state);
@@ -436,18 +404,7 @@ aux_driver:
if (err_drv->resume)
err_drv->resume(sysdev);
}
- drv = NULL;
-gbl_driver:
- if (drv)
- printk(KERN_ERR "sysdev driver suspend failed for %s\n",
- kobject_name(&sysdev->kobj));
- list_for_each_entry(err_drv, &sysdev_drivers, entry) {
- if (err_drv == drv)
- break;
- if (err_drv->resume)
- err_drv->resume(sysdev);
- }
/* resume other sysdevs in current class */
list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
if (err_dev == sysdev)
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 8d8cdfec652..e1d3ad4db2f 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -94,27 +94,18 @@ static struct attribute_group topology_attr_group = {
.name = "topology"
};
-static cpumask_t topology_dev_map = CPU_MASK_NONE;
-
/* Add/Remove cpu_topology interface for CPU device */
static int __cpuinit topology_add_dev(unsigned int cpu)
{
- int rc;
struct sys_device *sys_dev = get_cpu_sysdev(cpu);
- rc = sysfs_create_group(&sys_dev->kobj, &topology_attr_group);
- if (!rc)
- cpu_set(cpu, topology_dev_map);
- return rc;
+ return sysfs_create_group(&sys_dev->kobj, &topology_attr_group);
}
static void __cpuinit topology_remove_dev(unsigned int cpu)
{
struct sys_device *sys_dev = get_cpu_sysdev(cpu);
- if (!cpu_isset(cpu, topology_dev_map))
- return;
- cpu_clear(cpu, topology_dev_map);
sysfs_remove_group(&sys_dev->kobj, &topology_attr_group);
}
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 84d6aa500e2..9030c373ce6 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -44,6 +44,7 @@
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/random.h>
+#include <linux/scatterlist.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include "DAC960.h"
@@ -345,6 +346,7 @@ static bool DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller)
Command->V1.ScatterGatherList =
(DAC960_V1_ScatterGatherSegment_T *)ScatterGatherCPU;
Command->V1.ScatterGatherListDMA = ScatterGatherDMA;
+ sg_init_table(Command->cmd_sglist, DAC960_V1_ScatterGatherLimit);
} else {
Command->cmd_sglist = Command->V2.ScatterList;
Command->V2.ScatterGatherList =
@@ -353,6 +355,7 @@ static bool DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller)
Command->V2.RequestSense =
(DAC960_SCSI_RequestSense_T *)RequestSenseCPU;
Command->V2.RequestSenseDMA = RequestSenseDMA;
+ sg_init_table(Command->cmd_sglist, DAC960_V2_ScatterGatherLimit);
}
}
return true;
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 4245b7f80a4..4d0119ea9e3 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -204,23 +204,6 @@ config BLK_DEV_COW_COMMON
bool
default BLK_DEV_UBD
-config MMAPPER
- tristate "Example IO memory driver (BROKEN)"
- depends on UML && BROKEN
- ---help---
- The User-Mode Linux port can provide support for IO Memory
- emulation with this option. This allows a host file to be
- specified as an I/O region on the kernel command line. That file
- will be mapped into UML's kernel address space where a driver can
- locate it and do whatever it wants with the memory, including
- providing an interface to it for UML processes to use.
-
- For more information, see
- <http://user-mode-linux.sourceforge.net/iomem.html>.
-
- If you'd like to be able to provide a simulated IO port space for
- User-Mode Linux processes, say Y. If unsure, say N.
-
config BLK_DEV_LOOP
tristate "Loopback device support"
---help---
@@ -351,7 +334,7 @@ config BLK_DEV_RAM_COUNT
default "16"
depends on BLK_DEV_RAM
help
- The default value is 16 RAM disks. Change this if you know what
+ The default value is 16 RAM disks. Change this if you know what you
are doing. If you boot from a filesystem that needs to be extracted
in memory, you will need at least one RAM disk (e.g. root on cramfs).
@@ -361,8 +344,7 @@ config BLK_DEV_RAM_SIZE
default "4096"
help
The default value is 4096 kilobytes. Only change this if you know
- what are you doing. If you are using IBM S/390, then set this to
- 8192.
+ what you are doing.
config BLK_DEV_RAM_BLOCKSIZE
int "Default RAM disk block size (bytes)"
@@ -443,4 +425,10 @@ config XEN_BLKDEV_FRONTEND
block device driver. It communicates with a back-end driver
in another domain which drives the actual block device.
+config VIRTIO_BLK
+ tristate "Virtio block driver (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && VIRTIO
+ ---help---
+ This is the virtual block driver for lguest. Say Y or M.
+
endif # BLK_DEV
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 014e72121b5..7691505a2e1 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -25,10 +25,10 @@ obj-$(CONFIG_SUNVDC) += sunvdc.o
obj-$(CONFIG_BLK_DEV_UMEM) += umem.o
obj-$(CONFIG_BLK_DEV_NBD) += nbd.o
obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o
+obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o
obj-$(CONFIG_VIODASD) += viodasd.o
obj-$(CONFIG_BLK_DEV_SX8) += sx8.o
obj-$(CONFIG_BLK_DEV_UB) += ub.o
obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o
-obj-$(CONFIG_LGUEST_BLOCK) += lguest_blk.o
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index ba07f762c4c..07f02f855ab 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -48,15 +48,6 @@ struct aoe_hdr {
__be32 tag;
};
-#ifdef __KERNEL__
-#include <linux/skbuff.h>
-
-static inline struct aoe_hdr *aoe_hdr(const struct sk_buff *skb)
-{
- return (struct aoe_hdr *)skb_mac_header(skb);
-}
-#endif
-
struct aoe_atahdr {
unsigned char aflags;
unsigned char errfeat;
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index 007faaf008e..b1d00ef6659 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -138,7 +138,7 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio)
buf = mempool_alloc(d->bufpool, GFP_NOIO);
if (buf == NULL) {
printk(KERN_INFO "aoe: buf allocation failure\n");
- bio_endio(bio, bio->bi_size, -ENOMEM);
+ bio_endio(bio, -ENOMEM);
return 0;
}
memset(buf, 0, sizeof(*buf));
@@ -159,7 +159,7 @@ aoeblk_make_request(struct request_queue *q, struct bio *bio)
d->aoemajor, d->aoeminor);
spin_unlock_irqrestore(&d->lock, flags);
mempool_free(buf, d->bufpool);
- bio_endio(bio, bio->bi_size, -ENXIO);
+ bio_endio(bio, -ENXIO);
return 0;
}
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 01fbdd38e3b..4d59d505773 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -9,6 +9,7 @@
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/genhd.h>
+#include <net/net_namespace.h>
#include <asm/unaligned.h>
#include "aoe.h"
@@ -119,7 +120,7 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
/* initialize the headers & frame */
skb = f->skb;
- h = aoe_hdr(skb);
+ h = (struct aoe_hdr *) skb_mac_header(skb);
ah = (struct aoe_atahdr *) (h+1);
skb_put(skb, sizeof *h + sizeof *ah);
memset(h, 0, skb->len);
@@ -194,7 +195,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
sl = sl_tail = NULL;
read_lock(&dev_base_lock);
- for_each_netdev(ifp) {
+ for_each_netdev(&init_net, ifp) {
dev_hold(ifp);
if (!is_aoe_netif(ifp))
goto cont;
@@ -208,7 +209,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
skb->dev = ifp;
if (sl_tail == NULL)
sl_tail = skb;
- h = aoe_hdr(skb);
+ h = (struct aoe_hdr *) skb_mac_header(skb);
memset(h, 0, sizeof *h + sizeof *ch);
memset(h->dst, 0xff, sizeof h->dst);
@@ -303,7 +304,7 @@ rexmit(struct aoedev *d, struct frame *f)
aoechr_error(buf);
skb = f->skb;
- h = aoe_hdr(skb);
+ h = (struct aoe_hdr *) skb_mac_header(skb);
ah = (struct aoe_atahdr *) (h+1);
f->tag = n;
h->tag = cpu_to_be32(n);
@@ -532,7 +533,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
char ebuf[128];
u16 aoemajor;
- hin = aoe_hdr(skb);
+ hin = (struct aoe_hdr *) skb_mac_header(skb);
aoemajor = be16_to_cpu(get_unaligned(&hin->major));
d = aoedev_by_aoeaddr(aoemajor, hin->minor);
if (d == NULL) {
@@ -564,7 +565,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
calc_rttavg(d, tsince(f->tag));
ahin = (struct aoe_atahdr *) (hin+1);
- hout = aoe_hdr(f->skb);
+ hout = (struct aoe_hdr *) skb_mac_header(f->skb);
ahout = (struct aoe_atahdr *) (hout+1);
buf = f->buf;
@@ -652,7 +653,7 @@ aoecmd_ata_rsp(struct sk_buff *skb)
disk_stat_add(disk, sectors[rw], n_sect);
disk_stat_add(disk, io_ticks, duration);
n = (buf->flags & BUFFL_FAIL) ? -EIO : 0;
- bio_endio(buf->bio, buf->bio->bi_size, n);
+ bio_endio(buf->bio, n);
mempool_free(buf, d->bufpool);
}
}
@@ -698,7 +699,7 @@ aoecmd_ata_id(struct aoedev *d)
/* initialize the headers & frame */
skb = f->skb;
- h = aoe_hdr(skb);
+ h = (struct aoe_hdr *) skb_mac_header(skb);
ah = (struct aoe_atahdr *) (h+1);
skb_put(skb, sizeof *h + sizeof *ah);
memset(h, 0, skb->len);
@@ -729,7 +730,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
enum { MAXFRAMES = 16 };
u16 n;
- h = aoe_hdr(skb);
+ h = (struct aoe_hdr *) skb_mac_header(skb);
ch = (struct aoe_cfghdr *) (h+1);
/*
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index 05a97197c91..51f50710e5f 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -119,7 +119,7 @@ aoedev_downdev(struct aoedev *d)
bio = buf->bio;
if (--buf->nframesout == 0) {
mempool_free(buf, d->bufpool);
- bio_endio(bio, bio->bi_size, -EIO);
+ bio_endio(bio, -EIO);
}
skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0;
}
@@ -130,7 +130,7 @@ aoedev_downdev(struct aoedev *d)
list_del(d->bufq.next);
bio = buf->bio;
mempool_free(buf, d->bufpool);
- bio_endio(bio, bio->bi_size, -EIO);
+ bio_endio(bio, -EIO);
}
if (d->gd)
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index f9ddfda4d9c..4e6deb7f5c2 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -8,6 +8,7 @@
#include <linux/blkdev.h>
#include <linux/netdevice.h>
#include <linux/moduleparam.h>
+#include <net/net_namespace.h>
#include <asm/unaligned.h>
#include "aoe.h"
@@ -114,6 +115,9 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
struct aoe_hdr *h;
u32 n;
+ if (ifp->nd_net != &init_net)
+ goto exit;
+
skb = skb_share_check(skb, GFP_ATOMIC);
if (skb == NULL)
return 0;
@@ -123,7 +127,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
goto exit;
skb_push(skb, ETH_HLEN); /* (1) */
- h = aoe_hdr(skb);
+ h = (struct aoe_hdr *) skb_mac_header(skb);
n = be32_to_cpu(get_unaligned(&h->tag));
if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31))
goto exit;
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 084358a828e..7d704968765 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -1,20 +1,20 @@
/*
- * Disk Array driver for HP SA 5xxx and 6xxx Controllers
- * Copyright 2000, 2006 Hewlett-Packard Development Company, L.P.
+ * Disk Array driver for HP Smart Array controllers.
+ * (C) Copyright 2000, 2007 Hewlett-Packard Development Company, L.P.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation; 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more details.
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
*
* You 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.
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA.
*
* Questions/Comments/Bugfixes to iss_storagedev@hp.com
*
@@ -1191,10 +1191,9 @@ static inline void complete_buffers(struct bio *bio, int status)
{
while (bio) {
struct bio *xbh = bio->bi_next;
- int nr_sectors = bio_sectors(bio);
bio->bi_next = NULL;
- bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO);
+ bio_endio(bio, status ? 0 : -EIO);
bio = xbh;
}
}
@@ -1583,38 +1582,36 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
* allows us to delete disk zero but keep the controller registered.
*/
if (h->gendisk[0] != disk) {
- if (disk) {
- struct request_queue *q = disk->queue;
- if (disk->flags & GENHD_FL_UP)
- del_gendisk(disk);
- if (q) {
- blk_cleanup_queue(q);
- /* Set drv->queue to NULL so that we do not try
- * to call blk_start_queue on this queue in the
- * interrupt handler
- */
- drv->queue = NULL;
- }
- /* If clear_all is set then we are deleting the logical
- * drive, not just refreshing its info. For drives
- * other than disk 0 we will call put_disk. We do not
- * do this for disk 0 as we need it to be able to
- * configure the controller.
+ struct request_queue *q = disk->queue;
+ if (disk->flags & GENHD_FL_UP)
+ del_gendisk(disk);
+ if (q) {
+ blk_cleanup_queue(q);
+ /* Set drv->queue to NULL so that we do not try
+ * to call blk_start_queue on this queue in the
+ * interrupt handler
+ */
+ drv->queue = NULL;
+ }
+ /* If clear_all is set then we are deleting the logical
+ * drive, not just refreshing its info. For drives
+ * other than disk 0 we will call put_disk. We do not
+ * do this for disk 0 as we need it to be able to
+ * configure the controller.
+ */
+ if (clear_all){
+ /* This isn't pretty, but we need to find the
+ * disk in our array and NULL our the pointer.
+ * This is so that we will call alloc_disk if
+ * this index is used again later.
*/
- if (clear_all){
- /* This isn't pretty, but we need to find the
- * disk in our array and NULL our the pointer.
- * This is so that we will call alloc_disk if
- * this index is used again later.
- */
- for (i=0; i < CISS_MAX_LUN; i++){
- if(h->gendisk[i] == disk){
- h->gendisk[i] = NULL;
- break;
- }
+ for (i=0; i < CISS_MAX_LUN; i++){
+ if(h->gendisk[i] == disk){
+ h->gendisk[i] = NULL;
+ break;
}
- put_disk(disk);
}
+ put_disk(disk);
}
} else {
set_capacity(disk, 0);
@@ -2366,30 +2363,55 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
start_io(h);
}
+static inline unsigned int make_status_bytes(unsigned int scsi_status_byte,
+ unsigned int msg_byte, unsigned int host_byte,
+ unsigned int driver_byte)
+{
+ /* inverse of macros in scsi.h */
+ return (scsi_status_byte & 0xff) |
+ ((msg_byte & 0xff) << 8) |
+ ((host_byte & 0xff) << 16) |
+ ((driver_byte & 0xff) << 24);
+}
+
static inline int evaluate_target_status(CommandList_struct *cmd)
{
unsigned char sense_key;
- int error_count = 1;
+ unsigned char status_byte, msg_byte, host_byte, driver_byte;
+ int error_value;
+
+ /* If we get in here, it means we got "target status", that is, scsi status */
+ status_byte = cmd->err_info->ScsiStatus;
+ driver_byte = DRIVER_OK;
+ msg_byte = cmd->err_info->CommandStatus; /* correct? seems too device specific */
+
+ if (blk_pc_request(cmd->rq))
+ host_byte = DID_PASSTHROUGH;
+ else
+ host_byte = DID_OK;
+
+ error_value = make_status_bytes(status_byte, msg_byte,
+ host_byte, driver_byte);
- if (cmd->err_info->ScsiStatus != 0x02) { /* not check condition? */
+ if (cmd->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) {
if (!blk_pc_request(cmd->rq))
printk(KERN_WARNING "cciss: cmd %p "
"has SCSI Status 0x%x\n",
cmd, cmd->err_info->ScsiStatus);
- return error_count;
+ return error_value;
}
/* check the sense key */
sense_key = 0xf & cmd->err_info->SenseInfo[2];
/* no status or recovered error */
- if ((sense_key == 0x0) || (sense_key == 0x1))
- error_count = 0;
+ if (((sense_key == 0x0) || (sense_key == 0x1)) && !blk_pc_request(cmd->rq))
+ error_value = 0;
if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */
- if (error_count != 0)
+ if (error_value != 0)
printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION"
" sense key = 0x%x\n", cmd, sense_key);
- return error_count;
+ return error_value;
}
/* SG_IO or similar, copy sense data back */
@@ -2401,7 +2423,7 @@ static inline int evaluate_target_status(CommandList_struct *cmd)
} else
cmd->rq->sense_len = 0;
- return error_count;
+ return error_value;
}
/* checks the status of the job and calls complete buffers to mark all
@@ -2417,7 +2439,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
rq->errors = 0;
if (timeout)
- rq->errors = 1;
+ rq->errors = make_status_bytes(0, 0, 0, DRIVER_TIMEOUT);
if (cmd->err_info->CommandStatus == 0) /* no error has occurred */
goto after_error_processing;
@@ -2443,32 +2465,44 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
case CMD_INVALID:
printk(KERN_WARNING "cciss: cmd %p is "
"reported invalid\n", cmd);
- rq->errors = 1;
+ rq->errors = make_status_bytes(SAM_STAT_GOOD,
+ cmd->err_info->CommandStatus, DRIVER_OK,
+ blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
break;
case CMD_PROTOCOL_ERR:
printk(KERN_WARNING "cciss: cmd %p has "
"protocol error \n", cmd);
- rq->errors = 1;
+ rq->errors = make_status_bytes(SAM_STAT_GOOD,
+ cmd->err_info->CommandStatus, DRIVER_OK,
+ blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
break;
case CMD_HARDWARE_ERR:
printk(KERN_WARNING "cciss: cmd %p had "
" hardware error\n", cmd);
- rq->errors = 1;
+ rq->errors = make_status_bytes(SAM_STAT_GOOD,
+ cmd->err_info->CommandStatus, DRIVER_OK,
+ blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
break;
case CMD_CONNECTION_LOST:
printk(KERN_WARNING "cciss: cmd %p had "
"connection lost\n", cmd);
- rq->errors = 1;
+ rq->errors = make_status_bytes(SAM_STAT_GOOD,
+ cmd->err_info->CommandStatus, DRIVER_OK,
+ blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
break;
case CMD_ABORTED:
printk(KERN_WARNING "cciss: cmd %p was "
"aborted\n", cmd);
- rq->errors = 1;
+ rq->errors = make_status_bytes(SAM_STAT_GOOD,
+ cmd->err_info->CommandStatus, DRIVER_OK,
+ blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ABORT);
break;
case CMD_ABORT_FAILED:
printk(KERN_WARNING "cciss: cmd %p reports "
"abort failed\n", cmd);
- rq->errors = 1;
+ rq->errors = make_status_bytes(SAM_STAT_GOOD,
+ cmd->err_info->CommandStatus, DRIVER_OK,
+ blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
break;
case CMD_UNSOLICITED_ABORT:
printk(KERN_WARNING "cciss%d: unsolicited "
@@ -2482,17 +2516,23 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
printk(KERN_WARNING
"cciss%d: %p retried too "
"many times\n", h->ctlr, cmd);
- rq->errors = 1;
+ rq->errors = make_status_bytes(SAM_STAT_GOOD,
+ cmd->err_info->CommandStatus, DRIVER_OK,
+ blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ABORT);
break;
case CMD_TIMEOUT:
printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd);
- rq->errors = 1;
+ rq->errors = make_status_bytes(SAM_STAT_GOOD,
+ cmd->err_info->CommandStatus, DRIVER_OK,
+ blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
break;
default:
printk(KERN_WARNING "cciss: cmd %p returned "
"unknown status %x\n", cmd,
cmd->err_info->CommandStatus);
- rq->errors = 1;
+ rq->errors = make_status_bytes(SAM_STAT_GOOD,
+ cmd->err_info->CommandStatus, DRIVER_OK,
+ blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR);
}
after_error_processing:
@@ -2570,6 +2610,7 @@ static void do_cciss_request(struct request_queue *q)
(int)creq->nr_sectors);
#endif /* CCISS_DEBUG */
+ sg_init_table(tmp_sg, MAXSGENTRIES);
seg = blk_rq_map_sg(q, creq, tmp_sg);
/* get the DMA records for the setup */
@@ -2580,7 +2621,7 @@ static void do_cciss_request(struct request_queue *q)
for (i = 0; i < seg; i++) {
c->SG[i].Len = tmp_sg[i].length;
- temp64.val = (__u64) pci_map_page(h->pdev, tmp_sg[i].page,
+ temp64.val = (__u64) pci_map_page(h->pdev, sg_page(&tmp_sg[i]),
tmp_sg[i].offset,
tmp_sg[i].length, dir);
c->SG[i].Addr.lower = temp64.val32.lower;
@@ -3035,15 +3076,20 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
}
#endif
- /* Disabling DMA prefetch for the P600
- * An ASIC bug may result in a prefetch beyond
- * physical memory.
+ /* Disabling DMA prefetch and refetch for the P600.
+ * An ASIC bug may result in accesses to invalid memory addresses.
+ * We've disabled prefetch for some time now. Testing with XEN
+ * kernels revealed a bug in the refetch if dom0 resides on a P600.
*/
if(board_id == 0x3225103C) {
__u32 dma_prefetch;
+ __u32 dma_refetch;
dma_prefetch = readl(c->vaddr + I2O_DMA1_CFG);
dma_prefetch |= 0x8000;
writel(dma_prefetch, c->vaddr + I2O_DMA1_CFG);
+ pci_read_config_dword(pdev, PCI_COMMAND_PARITY, &dma_refetch);
+ dma_refetch |= 0x1;
+ pci_write_config_dword(pdev, PCI_COMMAND_PARITY, dma_refetch);
}
#ifdef CCISS_DEBUG
@@ -3101,7 +3147,7 @@ static void cciss_getgeometry(int cntl_num)
int i;
int listlength = 0;
__u32 lunid = 0;
- int block_size;
+ unsigned block_size;
sector_t total_size;
ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index 4aca7ddfddd..63ee6c076cb 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -1,20 +1,20 @@
/*
- * Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
- * Copyright 2001 Compaq Computer Corporation
+ * Disk Array driver for HP Smart Array controllers, SCSI Tape module.
+ * (C) Copyright 2001, 2007 Hewlett-Packard Development Company, L.P.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation; 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more details.
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
*
* You 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.
+ * Foundation, Inc., 59 Temple Place, Suite 300, Boston, MA
+ * 02111-1307, USA.
*
* Questions/Comments/Bugfixes to iss_storagedev@hp.com
*
diff --git a/drivers/block/cciss_scsi.h b/drivers/block/cciss_scsi.h
index 5e7e06c07d6..d9c2c586502 100644
--- a/drivers/block/cciss_scsi.h
+++ b/drivers/block/cciss_scsi.h
@@ -1,20 +1,20 @@
/*
- * Disk Array driver for Compaq SA53xx Controllers, SCSI Tape module
- * Copyright 2001 Compaq Computer Corporation
+ * Disk Array driver for HP Smart Array controllers, SCSI Tape module.
+ * (C) Copyright 2001, 2007 Hewlett-Packard Development Company, L.P.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation; 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more details.
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
*
* You 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.
+ * Foundation, Inc., 59 Temple Place, Suite 300, Boston, MA
+ * 02111-1307, USA.
*
* Questions/Comments/Bugfixes to iss_storagedev@hp.com
*
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index eb9799acf65..c8132d95879 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -37,6 +37,7 @@
#include <linux/spinlock.h>
#include <linux/blkdev.h>
#include <linux/genhd.h>
+#include <linux/scatterlist.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -918,6 +919,7 @@ queue_next:
DBGPX(
printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors);
);
+ sg_init_table(tmp_sg, SG_MAX);
seg = blk_rq_map_sg(q, creq, tmp_sg);
/* Now do all the DMA Mappings */
@@ -929,7 +931,7 @@ DBGPX(
{
c->req.sg[i].size = tmp_sg[i].length;
c->req.sg[i].addr = (__u32) pci_map_page(h->pci_dev,
- tmp_sg[i].page,
+ sg_page(&tmp_sg[i]),
tmp_sg[i].offset,
tmp_sg[i].length, dir);
}
@@ -981,13 +983,12 @@ static void start_io(ctlr_info_t *h)
static inline void complete_buffers(struct bio *bio, int ok)
{
struct bio *xbh;
- while(bio) {
- int nr_sectors = bio_sectors(bio);
+ while (bio) {
xbh = bio->bi_next;
bio->bi_next = NULL;
- bio_endio(bio, nr_sectors << 9, ok ? 0 : -EIO);
+ bio_endio(bio, ok ? 0 : -EIO);
bio = xbh;
}
diff --git a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c
index 40535036e89..241167878ed 100644
--- a/drivers/block/cryptoloop.c
+++ b/drivers/block/cryptoloop.c
@@ -26,6 +26,7 @@
#include <linux/crypto.h>
#include <linux/blkdev.h>
#include <linux/loop.h>
+#include <linux/scatterlist.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
@@ -119,14 +120,17 @@ cryptoloop_transfer(struct loop_device *lo, int cmd,
.tfm = tfm,
.flags = CRYPTO_TFM_REQ_MAY_SLEEP,
};
- struct scatterlist sg_out = { NULL, };
- struct scatterlist sg_in = { NULL, };
+ struct scatterlist sg_out;
+ struct scatterlist sg_in;
encdec_cbc_t encdecfunc;
struct page *in_page, *out_page;
unsigned in_offs, out_offs;
int err;
+ sg_init_table(&sg_out, 1);
+ sg_init_table(&sg_in, 1);
+
if (cmd == READ) {
in_page = raw_page;
in_offs = raw_off;
@@ -146,13 +150,8 @@ cryptoloop_transfer(struct loop_device *lo, int cmd,
u32 iv[4] = { 0, };
iv[0] = cpu_to_le32(IV & 0xffffffff);
- sg_in.page = in_page;
- sg_in.offset = in_offs;
- sg_in.length = sz;
-
- sg_out.page = out_page;
- sg_out.offset = out_offs;
- sg_out.length = sz;
+ sg_set_page(&sg_in, in_page, sz, in_offs);
+ sg_set_page(&sg_out, out_page, sz, out_offs);
desc.info = iv;
err = encdecfunc(&desc, &sg_out, &sg_in, sz);
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 085b7794fb3..639ed14bb08 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -5,6 +5,7 @@
* Copyright (C) 1993, 1994 Alain Knaff
* Copyright (C) 1998 Alan Cox
*/
+
/*
* 02.12.91 - Changed to static variables to indicate need for reset
* and recalibrate. This makes some things easier (output_byte reset
@@ -149,7 +150,7 @@
#define REALLY_SLOW_IO
#define DEBUGT 2
-#define DCL_DEBUG /* debug disk change line */
+#define DCL_DEBUG /* debug disk change line */
/* do print messages for unexpected interrupts */
static int print_unex = 1;
@@ -161,10 +162,8 @@ static int print_unex = 1;
#include <linux/workqueue.h>
#define FDPATCHES
#include <linux/fdreg.h>
-
#include <linux/fd.h>
#include <linux/hdreg.h>
-
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/mm.h>
@@ -274,8 +273,7 @@ static inline void fallback_on_nodma_alloc(char **addr, size_t l)
return; /* we have the memory */
if (can_use_virtual_dma != 2)
return; /* no fallback allowed */
- printk
- ("DMA memory shortage. Temporarily falling back on virtual DMA\n");
+ printk("DMA memory shortage. Temporarily falling back on virtual DMA\n");
*addr = (char *)nodma_mem_alloc(l);
#else
return;
@@ -291,8 +289,8 @@ static int initialising = 1;
#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
#define UNIT(x) ((x) & 0x03) /* drive on fdc */
#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
+ /* reverse mapping from unit and fdc to drive */
#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
- /* reverse mapping from unit and fdc to drive */
#define DP (&drive_params[current_drive])
#define DRS (&drive_state[current_drive])
#define DRWE (&write_errors[current_drive])
@@ -356,7 +354,6 @@ static int inr; /* size of reply buffer, when called from interrupt */
#define R_HEAD (reply_buffer[4])
#define R_SECTOR (reply_buffer[5])
#define R_SIZECODE (reply_buffer[6])
-
#define SEL_DLY (2*HZ/100)
/*
@@ -472,8 +469,8 @@ static struct floppy_struct floppy_type[32] = {
{ 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
{ 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
{ 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
-
{ 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
+
{ 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
{ 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
};
@@ -539,12 +536,12 @@ static char *floppy_track_buffer;
static int max_buffer_sectors;
static int *errors;
-typedef void (*done_f) (int);
+typedef void (*done_f)(int);
static struct cont_t {
- void (*interrupt) (void); /* this is called after the interrupt of the
+ void (*interrupt)(void); /* this is called after the interrupt of the
* main command */
- void (*redo) (void); /* this is called to retry the operation */
- void (*error) (void); /* this is called to tally an error */
+ void (*redo)(void); /* this is called to retry the operation */
+ void (*error)(void); /* this is called to tally an error */
done_f done; /* this is called to say if the operation has
* succeeded/failed */
} *cont;
@@ -694,7 +691,6 @@ static void reschedule_timeout(int drive, const char *message, int marg)
}
#define INFBOUND(a,b) (a)=max_t(int, a, b)
-
#define SUPBOUND(a,b) (a)=min_t(int, a, b)
/*
@@ -733,6 +729,7 @@ static void reschedule_timeout(int drive, const char *message, int marg)
static int disk_change(int drive)
{
int fdc = FDC(drive);
+
#ifdef FLOPPY_SANITY_CHECK
if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
DPRINT("WARNING disk change called early\n");
@@ -771,7 +768,6 @@ static int disk_change(int drive)
floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
}
- /*USETF(FD_DISK_NEWCHANGE); */
return 1;
} else {
UDRS->last_checked = jiffies;
@@ -787,7 +783,10 @@ static inline int is_selected(int dor, int unit)
static int set_dor(int fdc, char mask, char data)
{
- register unsigned char drive, unit, newdor, olddor;
+ unsigned char unit;
+ unsigned char drive;
+ unsigned char newdor;
+ unsigned char olddor;
if (FDCS->address == -1)
return -1;
@@ -892,7 +891,6 @@ static int _lock_fdc(int drive, int interruptible, int line)
set_current_state(TASK_RUNNING);
remove_wait_queue(&fdc_wait, &wait);
-
flush_scheduled_work();
}
command_status = FD_COMMAND_NONE;
@@ -942,7 +940,7 @@ static void motor_off_callback(unsigned long nr)
static void floppy_off(unsigned int drive)
{
unsigned long volatile delta;
- register int fdc = FDC(drive);
+ int fdc = FDC(drive);
if (!(FDCS->dor & (0x10 << UNIT(drive))))
return;
@@ -968,7 +966,9 @@ static void floppy_off(unsigned int drive)
*/
static void scandrives(void)
{
- int i, drive, saved_drive;
+ int i;
+ int drive;
+ int saved_drive;
if (DP->select_delay)
return;
@@ -1146,7 +1146,9 @@ static void show_floppy(void);
/* waits until the fdc becomes ready */
static int wait_til_ready(void)
{
- int counter, status;
+ int status;
+ int counter;
+
if (FDCS->reset)
return -1;
for (counter = 0; counter < 10000; counter++) {
@@ -1193,7 +1195,8 @@ static int output_byte(char byte)
/* gets the response from the fdc */
static int result(void)
{
- int i, status = 0;
+ int i;
+ int status = 0;
for (i = 0; i < MAX_REPLIES; i++) {
if ((status = wait_til_ready()) < 0)
@@ -1226,6 +1229,7 @@ static int result(void)
static int need_more_output(void)
{
int status;
+
if ((status = wait_til_ready()) < 0)
return -1;
if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
@@ -1309,8 +1313,11 @@ static int fdc_configure(void)
*/
static void fdc_specify(void)
{
- unsigned char spec1, spec2;
- unsigned long srt, hlt, hut;
+ unsigned char spec1;
+ unsigned char spec2;
+ unsigned long srt;
+ unsigned long hlt;
+ unsigned long hut;
unsigned long dtr = NOMINAL_DTR;
unsigned long scale_dtr = NOMINAL_DTR;
int hlt_max_code = 0x7f;
@@ -1319,7 +1326,6 @@ static void fdc_specify(void)
if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
fdc_configure();
FDCS->need_configure = 0;
- /*DPRINT("FIFO enabled\n"); */
}
switch (raw_cmd->rate & 0x03) {
@@ -1472,7 +1478,6 @@ static int interpret_errors(void)
tell_sector();
}
printk("\n");
-
}
if (ST2 & ST2_WC || ST2 & ST2_BC)
/* wrong cylinder => recal */
@@ -1498,7 +1503,10 @@ static int interpret_errors(void)
*/
static void setup_rw_floppy(void)
{
- int i, r, flags, dflags;
+ int i;
+ int r;
+ int flags;
+ int dflags;
unsigned long ready_date;
timeout_fn function;
@@ -1728,9 +1736,9 @@ static void print_result(char *message, int inr)
/* interrupt handler. Note that this can be called externally on the Sparc */
irqreturn_t floppy_interrupt(int irq, void *dev_id)
{
- void (*handler) (void) = do_floppy;
int do_print;
unsigned long f;
+ void (*handler)(void) = do_floppy;
lasthandler = handler;
interruptjiffies = jiffies;
@@ -1912,12 +1920,11 @@ static void floppy_shutdown(unsigned long data)
is_alive("floppy shutdown");
}
-/*typedef void (*timeout_fn)(unsigned long);*/
-
/* start motor, check media-changed condition and write protection */
-static int start_motor(void (*function) (void))
+static int start_motor(void (*function)(void))
{
- int mask, data;
+ int mask;
+ int data;
mask = 0xfc;
data = UNIT(current_drive);
@@ -2020,17 +2027,17 @@ static struct cont_t wakeup_cont = {
.interrupt = empty,
.redo = do_wakeup,
.error = empty,
- .done = (done_f) empty
+ .done = (done_f)empty
};
static struct cont_t intr_cont = {
.interrupt = empty,
.redo = process_fd_request,
.error = empty,
- .done = (done_f) empty
+ .done = (done_f)empty
};
-static int wait_til_done(void (*handler) (void), int interruptible)
+static int wait_til_done(void (*handler)(void), int interruptible)
{
int ret;
@@ -2049,7 +2056,6 @@ static int wait_til_done(void (*handler) (void), int interruptible)
break;
is_alive("wait_til_done");
-
schedule();
}
@@ -2141,6 +2147,7 @@ static void bad_flp_intr(void)
static void set_floppy(int drive)
{
int type = ITYPE(UDRS->fd_device);
+
if (type)
_floppy = floppy_type + type;
else
@@ -2169,11 +2176,14 @@ static void format_interrupt(void)
#define CT(x) ((x) | 0xc0)
static void setup_format_params(int track)
{
+ int n;
+ int il;
+ int count;
+ int head_shift;
+ int track_shift;
struct fparm {
unsigned char track, head, sect, size;
} *here = (struct fparm *)floppy_track_buffer;
- int il, n;
- int count, head_shift, track_shift;
raw_cmd = &default_raw_cmd;
raw_cmd->track = track;
@@ -2344,7 +2354,10 @@ static void request_done(int uptodate)
/* Interrupt handler evaluating the result of the r/w operation */
static void rw_interrupt(void)
{
- int nr_sectors, ssize, eoc, heads;
+ int eoc;
+ int ssize;
+ int heads;
+ int nr_sectors;
if (R_HEAD >= 2) {
/* some Toshiba floppy controllers occasionnally seem to
@@ -2437,22 +2450,19 @@ static void rw_interrupt(void)
/* Compute maximal contiguous buffer size. */
static int buffer_chain_size(void)
{
- struct bio *bio;
struct bio_vec *bv;
- int size, i;
+ int size;
+ struct req_iterator iter;
char *base;
base = bio_data(current_req->bio);
size = 0;
- rq_for_each_bio(bio, current_req) {
- bio_for_each_segment(bv, bio, i) {
- if (page_address(bv->bv_page) + bv->bv_offset !=
- base + size)
- break;
+ rq_for_each_segment(bv, current_req, iter) {
+ if (page_address(bv->bv_page) + bv->bv_offset != base + size)
+ break;
- size += bv->bv_len;
- }
+ size += bv->bv_len;
}
return size >> 9;
@@ -2479,9 +2489,10 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
{
int remaining; /* number of transferred 512-byte sectors */
struct bio_vec *bv;
- struct bio *bio;
- char *buffer, *dma_buffer;
- int size, i;
+ char *buffer;
+ char *dma_buffer;
+ int size;
+ struct req_iterator iter;
max_sector = transfer_size(ssize,
min(max_sector, max_sector_2),
@@ -2514,43 +2525,41 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
size = current_req->current_nr_sectors << 9;
- rq_for_each_bio(bio, current_req) {
- bio_for_each_segment(bv, bio, i) {
- if (!remaining)
- break;
+ rq_for_each_segment(bv, current_req, iter) {
+ if (!remaining)
+ break;
- size = bv->bv_len;
- SUPBOUND(size, remaining);
+ size = bv->bv_len;
+ SUPBOUND(size, remaining);
- buffer = page_address(bv->bv_page) + bv->bv_offset;
+ buffer = page_address(bv->bv_page) + bv->bv_offset;
#ifdef FLOPPY_SANITY_CHECK
- if (dma_buffer + size >
- floppy_track_buffer + (max_buffer_sectors << 10) ||
- dma_buffer < floppy_track_buffer) {
- DPRINT("buffer overrun in copy buffer %d\n",
- (int)((floppy_track_buffer -
- dma_buffer) >> 9));
- printk("fsector_t=%d buffer_min=%d\n",
- fsector_t, buffer_min);
- printk("current_count_sectors=%ld\n",
- current_count_sectors);
- if (CT(COMMAND) == FD_READ)
- printk("read\n");
- if (CT(COMMAND) == FD_WRITE)
- printk("write\n");
- break;
- }
- if (((unsigned long)buffer) % 512)
- DPRINT("%p buffer not aligned\n", buffer);
-#endif
+ if (dma_buffer + size >
+ floppy_track_buffer + (max_buffer_sectors << 10) ||
+ dma_buffer < floppy_track_buffer) {
+ DPRINT("buffer overrun in copy buffer %d\n",
+ (int)((floppy_track_buffer -
+ dma_buffer) >> 9));
+ printk("fsector_t=%d buffer_min=%d\n",
+ fsector_t, buffer_min);
+ printk("current_count_sectors=%ld\n",
+ current_count_sectors);
if (CT(COMMAND) == FD_READ)
- memcpy(buffer, dma_buffer, size);
- else
- memcpy(dma_buffer, buffer, size);
-
- remaining -= size;
- dma_buffer += size;
+ printk("read\n");
+ if (CT(COMMAND) == FD_WRITE)
+ printk("write\n");
+ break;
}
+ if (((unsigned long)buffer) % 512)
+ DPRINT("%p buffer not aligned\n", buffer);
+#endif
+ if (CT(COMMAND) == FD_READ)
+ memcpy(buffer, dma_buffer, size);
+ else
+ memcpy(dma_buffer, buffer, size);
+
+ remaining -= size;
+ dma_buffer += size;
}
#ifdef FLOPPY_SANITY_CHECK
if (remaining) {
@@ -2561,19 +2570,6 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
#endif
}
-#if 0
-static inline int check_dma_crossing(char *start,
- unsigned long length, char *message)
-{
- if (CROSS_64KB(start, length)) {
- printk("DMA xfer crosses 64KB boundary in %s %p-%p\n",
- message, start, start + length);
- return 1;
- } else
- return 0;
-}
-#endif
-
/* work around a bug in pseudo DMA
* (on some FDCs) pseudo DMA does not stop when the CPU stops
* sending data. Hence we need a different way to signal the
@@ -2583,7 +2579,8 @@ static inline int check_dma_crossing(char *start,
*/
static void virtualdmabug_workaround(void)
{
- int hard_sectors, end_sector;
+ int hard_sectors;
+ int end_sector;
if (CT(COMMAND) == FD_WRITE) {
COMMAND &= ~0x80; /* switch off multiple track mode */
@@ -2615,7 +2612,10 @@ static void virtualdmabug_workaround(void)
static int make_raw_rw_request(void)
{
int aligned_sector_t;
- int max_sector, max_size, tracksize, ssize;
+ int max_sector;
+ int max_size;
+ int tracksize;
+ int ssize;
if (max_buffer_sectors == 0) {
printk("VFS: Block I/O scheduled on unopened device\n");
@@ -2767,9 +2767,7 @@ static int make_raw_rw_request(void)
*/
if (!direct ||
(indirect * 2 > direct * 3 &&
- *errors < DP->max_errors.read_track &&
- /*!TESTF(FD_NEED_TWADDLE) && */
- ((!probing
+ *errors < DP->max_errors.read_track && ((!probing
|| (DP->read_track & (1 << DRS->probed_format)))))) {
max_size = current_req->nr_sectors;
} else {
@@ -2782,10 +2780,6 @@ static int make_raw_rw_request(void)
indirect, direct, fsector_t);
return 0;
}
-/* check_dma_crossing(raw_cmd->kernel_data,
- raw_cmd->length,
- "end of make_raw_request [1]");*/
-
virtualdmabug_workaround();
return 2;
}
@@ -2835,8 +2829,6 @@ static int make_raw_rw_request(void)
raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
raw_cmd->length <<= 9;
#ifdef FLOPPY_SANITY_CHECK
- /*check_dma_crossing(raw_cmd->kernel_data, raw_cmd->length,
- "end of make_raw_request"); */
if ((raw_cmd->length < current_count_sectors << 9) ||
(raw_cmd->kernel_data != current_req->buffer &&
CT(COMMAND) == FD_WRITE &&
@@ -3016,6 +3008,7 @@ static struct cont_t poll_cont = {
static int poll_drive(int interruptible, int flag)
{
int ret;
+
/* no auto-sense, just clear dcl */
raw_cmd = &default_raw_cmd;
raw_cmd->flags = flag;
@@ -3178,7 +3171,8 @@ static inline int raw_cmd_copyout(int cmd, char __user *param,
static void raw_cmd_free(struct floppy_raw_cmd **ptr)
{
- struct floppy_raw_cmd *next, *this;
+ struct floppy_raw_cmd *next;
+ struct floppy_raw_cmd *this;
this = *ptr;
*ptr = NULL;
@@ -3250,8 +3244,10 @@ static inline int raw_cmd_copyin(int cmd, char __user *param,
static int raw_cmd_ioctl(int cmd, void __user *param)
{
- int drive, ret, ret2;
struct floppy_raw_cmd *my_raw_cmd;
+ int drive;
+ int ret2;
+ int ret;
if (FDCS->rawcmd <= 1)
FDCS->rawcmd = 1;
@@ -3458,7 +3454,8 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
int drive = (long)inode->i_bdev->bd_disk->private_data;
- int i, type = ITYPE(UDRS->fd_device);
+ int type = ITYPE(UDRS->fd_device);
+ int i;
int ret;
int size;
union inparam {
@@ -3624,8 +3621,7 @@ static void __init config_types(void)
if (!UDP->cmos && FLOPPY1_TYPE)
UDP->cmos = FLOPPY1_TYPE;
- /* XXX */
- /* additional physical CMOS drive detection should go here */
+ /* FIXME: additional physical CMOS drive detection should go here */
for (drive = 0; drive < N_DRIVE; drive++) {
unsigned int type = UDP->cmos;
@@ -3815,14 +3811,10 @@ static int check_floppy_change(struct gendisk *disk)
* a disk in the drive, and whether that disk is writable.
*/
-static int floppy_rb0_complete(struct bio *bio, unsigned int bytes_done,
+static void floppy_rb0_complete(struct bio *bio,
int err)
{
- if (bio->bi_size)
- return 1;
-
complete((struct completion *)bio->bi_private);
- return 0;
}
static int __floppy_read_block_0(struct block_device *bdev)
@@ -3912,13 +3904,13 @@ static int floppy_revalidate(struct gendisk *disk)
}
static struct block_device_operations floppy_fops = {
- .owner = THIS_MODULE,
- .open = floppy_open,
- .release = floppy_release,
- .ioctl = fd_ioctl,
- .getgeo = fd_getgeo,
- .media_changed = check_floppy_change,
- .revalidate_disk = floppy_revalidate,
+ .owner = THIS_MODULE,
+ .open = floppy_open,
+ .release = floppy_release,
+ .ioctl = fd_ioctl,
+ .getgeo = fd_getgeo,
+ .media_changed = check_floppy_change,
+ .revalidate_disk = floppy_revalidate,
};
/*
@@ -4397,11 +4389,15 @@ static int floppy_grab_irq_and_dma(void)
if (fd_request_dma()) {
DPRINT("Unable to grab DMA%d for the floppy driver\n",
FLOPPY_DMA);
- fd_free_irq();
- spin_lock_irqsave(&floppy_usage_lock, flags);
- usage_count--;
- spin_unlock_irqrestore(&floppy_usage_lock, flags);
- return -1;
+ if (can_use_virtual_dma & 2)
+ use_virtual_dma = can_use_virtual_dma = 1;
+ if (!(can_use_virtual_dma & 1)) {
+ fd_free_irq();
+ spin_lock_irqsave(&floppy_usage_lock, flags);
+ usage_count--;
+ spin_unlock_irqrestore(&floppy_usage_lock, flags);
+ return -1;
+ }
}
for (fdc = 0; fdc < N_FDC; fdc++) {
@@ -4433,8 +4429,8 @@ static int floppy_grab_irq_and_dma(void)
if (FDCS->address != -1)
fd_outb(FDCS->dor, FD_DOR);
/*
- * The driver will try and free resources and relies on us
- * to know if they were allocated or not.
+ * The driver will try and free resources and relies on us
+ * to know if they were allocated or not.
*/
fdc = 0;
irqdma_allocated = 1;
diff --git a/drivers/block/lguest_blk.c b/drivers/block/lguest_blk.c
deleted file mode 100644
index 160cf14431a..00000000000
--- a/drivers/block/lguest_blk.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/*D:400
- * The Guest block driver
- *
- * This is a simple block driver, which appears as /dev/lgba, lgbb, lgbc etc.
- * The mechanism is simple: we place the information about the request in the
- * device page, then use SEND_DMA (containing the data for a write, or an empty
- * "ping" DMA for a read).
- :*/
-/* Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-//#define DEBUG
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/blkdev.h>
-#include <linux/interrupt.h>
-#include <linux/lguest_bus.h>
-
-static char next_block_index = 'a';
-
-/*D:420 Here is the structure which holds all the information we need about
- * each Guest block device.
- *
- * I'm sure at this stage, you're wondering "hey, where was the adventure I was
- * promised?" and thinking "Rusty sucks, I shall say nasty things about him on
- * my blog". I think Real adventures have boring bits, too, and you're in the
- * middle of one. But it gets better. Just not quite yet. */
-struct blockdev
-{
- /* The block queue infrastructure wants a spinlock: it is held while it
- * calls our block request function. We grab it in our interrupt
- * handler so the responses don't mess with new requests. */
- spinlock_t lock;
-
- /* The disk structure registered with kernel. */
- struct gendisk *disk;
-
- /* The major device number for this disk, and the interrupt. We only
- * really keep them here for completeness; we'd need them if we
- * supported device unplugging. */
- int major;
- int irq;
-
- /* The physical address of this device's memory page */
- unsigned long phys_addr;
- /* The mapped memory page for convenient acces. */
- struct lguest_block_page *lb_page;
-
- /* We only have a single request outstanding at a time: this is it. */
- struct lguest_dma dma;
- struct request *req;
-};
-
-/*D:495 We originally used end_request() throughout the driver, but it turns
- * out that end_request() is deprecated, and doesn't actually end the request
- * (which seems like a good reason to deprecate it!). It simply ends the first
- * bio. So if we had 3 bios in a "struct request" we would do all 3,
- * end_request(), do 2, end_request(), do 1 and end_request(): twice as much
- * work as we needed to do.
- *
- * This reinforced to me that I do not understand the block layer.
- *
- * Nonetheless, Jens Axboe gave me this nice helper to end all chunks of a
- * request. This improved disk speed by 130%. */
-static void end_entire_request(struct request *req, int uptodate)
-{
- if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
- BUG();
- add_disk_randomness(req->rq_disk);
- blkdev_dequeue_request(req);
- end_that_request_last(req, uptodate);
-}
-
-/* I'm told there are only two stories in the world worth telling: love and
- * hate. So there used to be a love scene here like this:
- *
- * Launcher: We could make beautiful I/O together, you and I.
- * Guest: My, that's a big disk!
- *
- * Unfortunately, it was just too raunchy for our otherwise-gentle tale. */
-
-/*D:490 This is the interrupt handler, called when a block read or write has
- * been completed for us. */
-static irqreturn_t lgb_irq(int irq, void *_bd)
-{
- /* We handed our "struct blockdev" as the argument to request_irq(), so
- * it is passed through to us here. This tells us which device we're
- * dealing with in case we have more than one. */
- struct blockdev *bd = _bd;
- unsigned long flags;
-
- /* We weren't doing anything? Strange, but could happen if we shared
- * interrupts (we don't!). */
- if (!bd->req) {
- pr_debug("No work!\n");
- return IRQ_NONE;
- }
-
- /* Not done yet? That's equally strange. */
- if (!bd->lb_page->result) {
- pr_debug("No result!\n");
- return IRQ_NONE;
- }
-
- /* We have to grab the lock before ending the request. */
- spin_lock_irqsave(&bd->lock, flags);
- /* "result" is 1 for success, 2 for failure: end_entire_request() wants
- * to know whether this succeeded or not. */
- end_entire_request(bd->req, bd->lb_page->result == 1);
- /* Clear out request, it's done. */
- bd->req = NULL;
- /* Reset incoming DMA for next time. */
- bd->dma.used_len = 0;
- /* Ready for more reads or writes */
- blk_start_queue(bd->disk->queue);
- spin_unlock_irqrestore(&bd->lock, flags);
-
- /* The interrupt was for us, we dealt with it. */
- return IRQ_HANDLED;
-}
-
-/*D:480 The block layer's "struct request" contains a number of "struct bio"s,
- * each of which contains "struct bio_vec"s, each of which contains a page, an
- * offset and a length.
- *
- * Fortunately there are iterators to help us walk through the "struct
- * request". Even more fortunately, there were plenty of places to steal the
- * code from. We pack the "struct request" into our "struct lguest_dma" and
- * return the total length. */
-static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma)
-{
- unsigned int i = 0, idx, len = 0;
- struct bio *bio;
-
- rq_for_each_bio(bio, req) {
- struct bio_vec *bvec;
- bio_for_each_segment(bvec, bio, idx) {
- /* We told the block layer not to give us too many. */
- BUG_ON(i == LGUEST_MAX_DMA_SECTIONS);
- /* If we had a zero-length segment, it would look like
- * the end of the data referred to by the "struct
- * lguest_dma", so make sure that doesn't happen. */
- BUG_ON(!bvec->bv_len);
- /* Convert page & offset to a physical address */
- dma->addr[i] = page_to_phys(bvec->bv_page)
- + bvec->bv_offset;
- dma->len[i] = bvec->bv_len;
- len += bvec->bv_len;
- i++;
- }
- }
- /* If the array isn't full, we mark the end with a 0 length */
- if (i < LGUEST_MAX_DMA_SECTIONS)
- dma->len[i] = 0;
- return len;
-}
-
-/* This creates an empty DMA, useful for prodding the Host without sending data
- * (ie. when we want to do a read) */
-static void empty_dma(struct lguest_dma *dma)
-{
- dma->len[0] = 0;
-}
-
-/*D:470 Setting up a request is fairly easy: */
-static void setup_req(struct blockdev *bd,
- int type, struct request *req, struct lguest_dma *dma)
-{
- /* The type is 1 (write) or 0 (read). */
- bd->lb_page->type = type;
- /* The sector on disk where the read or write starts. */
- bd->lb_page->sector = req->sector;
- /* The result is initialized to 0 (unfinished). */
- bd->lb_page->result = 0;
- /* The current request (so we can end it in the interrupt handler). */
- bd->req = req;
- /* The number of bytes: returned as a side-effect of req_to_dma(),
- * which packs the block layer's "struct request" into our "struct
- * lguest_dma" */
- bd->lb_page->bytes = req_to_dma(req, dma);
-}
-
-/*D:450 Write is pretty straightforward: we pack the request into a "struct
- * lguest_dma", then use SEND_DMA to send the request. */
-static void do_write(struct blockdev *bd, struct request *req)
-{
- struct lguest_dma send;
-
- pr_debug("lgb: WRITE sector %li\n", (long)req->sector);
- setup_req(bd, 1, req, &send);
-
- lguest_send_dma(bd->phys_addr, &send);
-}
-
-/* Read is similar to write, except we pack the request into our receive
- * "struct lguest_dma" and send through an empty DMA just to tell the Host that
- * there's a request pending. */
-static void do_read(struct blockdev *bd, struct request *req)
-{
- struct lguest_dma ping;
-
- pr_debug("lgb: READ sector %li\n", (long)req->sector);
- setup_req(bd, 0, req, &bd->dma);
-
- empty_dma(&ping);
- lguest_send_dma(bd->phys_addr, &ping);
-}
-
-/*D:440 This where requests come in: we get handed the request queue and are
- * expected to pull a "struct request" off it until we've finished them or
- * we're waiting for a reply: */
-static void do_lgb_request(struct request_queue *q)
-{
- struct blockdev *bd;
- struct request *req;
-
-again:
- /* This sometimes returns NULL even on the very first time around. I
- * wonder if it's something to do with letting elves handle the request
- * queue... */
- req = elv_next_request(q);
- if (!req)
- return;
-
- /* We attached the struct blockdev to the disk: get it back */
- bd = req->rq_disk->private_data;
- /* Sometimes we get repeated requests after blk_stop_queue(), but we
- * can only handle one at a time. */
- if (bd->req)
- return;
-
- /* We only do reads and writes: no tricky business! */
- if (!blk_fs_request(req)) {
- pr_debug("Got non-command 0x%08x\n", req->cmd_type);
- req->errors++;
- end_entire_request(req, 0);
- goto again;
- }
-
- if (rq_data_dir(req) == WRITE)
- do_write(bd, req);
- else
- do_read(bd, req);
-
- /* We've put out the request, so stop any more coming in until we get
- * an interrupt, which takes us to lgb_irq() to re-enable the queue. */
- blk_stop_queue(q);
-}
-
-/*D:430 This is the "struct block_device_operations" we attach to the disk at
- * the end of lguestblk_probe(). It doesn't seem to want much. */
-static struct block_device_operations lguestblk_fops = {
- .owner = THIS_MODULE,
-};
-
-/*D:425 Setting up a disk device seems to involve a lot of code. I'm not sure
- * quite why. I do know that the IDE code sent two or three of the maintainers
- * insane, perhaps this is the fringe of the same disease?
- *
- * As in the console code, the probe function gets handed the generic
- * lguest_device from lguest_bus.c: */
-static int lguestblk_probe(struct lguest_device *lgdev)
-{
- struct blockdev *bd;
- int err;
- int irqflags = IRQF_SHARED;
-
- /* First we allocate our own "struct blockdev" and initialize the easy
- * fields. */
- bd = kmalloc(sizeof(*bd), GFP_KERNEL);
- if (!bd)
- return -ENOMEM;
-
- spin_lock_init(&bd->lock);
- bd->irq = lgdev_irq(lgdev);
- bd->req = NULL;
- bd->dma.used_len = 0;
- bd->dma.len[0] = 0;
- /* The descriptor in the lguest_devices array provided by the Host
- * gives the Guest the physical page number of the device's page. */
- bd->phys_addr = (lguest_devices[lgdev->index].pfn << PAGE_SHIFT);
-
- /* We use lguest_map() to get a pointer to the device page */
- bd->lb_page = lguest_map(bd->phys_addr, 1);
- if (!bd->lb_page) {
- err = -ENOMEM;
- goto out_free_bd;
- }
-
- /* We need a major device number: 0 means "assign one dynamically". */
- bd->major = register_blkdev(0, "lguestblk");
- if (bd->major < 0) {
- err = bd->major;
- goto out_unmap;
- }
-
- /* This allocates a "struct gendisk" where we pack all the information
- * about the disk which the rest of Linux sees. The argument is the
- * number of minor devices desired: we need one minor for the main
- * disk, and one for each partition. Of course, we can't possibly know
- * how many partitions are on the disk (add_disk does that).
- */
- bd->disk = alloc_disk(16);
- if (!bd->disk) {
- err = -ENOMEM;
- goto out_unregister_blkdev;
- }
-
- /* Every disk needs a queue for requests to come in: we set up the
- * queue with a callback function (the core of our driver) and the lock
- * to use. */
- bd->disk->queue = blk_init_queue(do_lgb_request, &bd->lock);
- if (!bd->disk->queue) {
- err = -ENOMEM;
- goto out_put_disk;
- }
-
- /* We can only handle a certain number of pointers in our SEND_DMA
- * call, so we set that with blk_queue_max_hw_segments(). This is not
- * to be confused with blk_queue_max_phys_segments() of course! I
- * know, who could possibly confuse the two?
- *
- * Well, it's simple to tell them apart: this one seems to work and the
- * other one didn't. */
- blk_queue_max_hw_segments(bd->disk->queue, LGUEST_MAX_DMA_SECTIONS);
-
- /* Due to technical limitations of our Host (and simple coding) we
- * can't have a single buffer which crosses a page boundary. Tell it
- * here. This means that our maximum request size is 16
- * (LGUEST_MAX_DMA_SECTIONS) pages. */
- blk_queue_segment_boundary(bd->disk->queue, PAGE_SIZE-1);
-
- /* We name our disk: this becomes the device name when udev does its
- * magic thing and creates the device node, such as /dev/lgba.
- * next_block_index is a global which starts at 'a'. Unfortunately
- * this simple increment logic means that the 27th disk will be called
- * "/dev/lgb{". In that case, I recommend having at least 29 disks, so
- * your /dev directory will be balanced. */
- sprintf(bd->disk->disk_name, "lgb%c", next_block_index++);
-
- /* We look to the device descriptor again to see if this device's
- * interrupts are expected to be random. If they are, we tell the irq
- * subsystem. At the moment this bit is always set. */
- if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS)
- irqflags |= IRQF_SAMPLE_RANDOM;
-
- /* Now we have the name and irqflags, we can request the interrupt; we
- * give it the "struct blockdev" we have set up to pass to lgb_irq()
- * when there is an interrupt. */
- err = request_irq(bd->irq, lgb_irq, irqflags, bd->disk->disk_name, bd);
- if (err)
- goto out_cleanup_queue;
-
- /* We bind our one-entry DMA pool to the key for this block device so
- * the Host can reply to our requests. The key is equal to the
- * physical address of the device's page, which is conveniently
- * unique. */
- err = lguest_bind_dma(bd->phys_addr, &bd->dma, 1, bd->irq);
- if (err)
- goto out_free_irq;
-
- /* We finish our disk initialization and add the disk to the system. */
- bd->disk->major = bd->major;
- bd->disk->first_minor = 0;
- bd->disk->private_data = bd;
- bd->disk->fops = &lguestblk_fops;
- /* This is initialized to the disk size by the Launcher. */
- set_capacity(bd->disk, bd->lb_page->num_sectors);
- add_disk(bd->disk);
-
- printk(KERN_INFO "%s: device %i at major %d\n",
- bd->disk->disk_name, lgdev->index, bd->major);
-
- /* We don't need to keep the "struct blockdev" around, but if we ever
- * implemented device removal, we'd need this. */
- lgdev->private = bd;
- return 0;
-
-out_free_irq:
- free_irq(bd->irq, bd);
-out_cleanup_queue:
- blk_cleanup_queue(bd->disk->queue);
-out_put_disk:
- put_disk(bd->disk);
-out_unregister_blkdev:
- unregister_blkdev(bd->major, "lguestblk");
-out_unmap:
- lguest_unmap(bd->lb_page);
-out_free_bd:
- kfree(bd);
- return err;
-}
-
-/*D:410 The boilerplate code for registering the lguest block driver is just
- * like the console: */
-static struct lguest_driver lguestblk_drv = {
- .name = "lguestblk",
- .owner = THIS_MODULE,
- .device_type = LGUEST_DEVICE_T_BLOCK,
- .probe = lguestblk_probe,
-};
-
-static __init int lguestblk_init(void)
-{
- return register_lguest_driver(&lguestblk_drv);
-}
-module_init(lguestblk_init);
-
-MODULE_DESCRIPTION("Lguest block driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 9f015fce413..56e23042728 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -29,7 +29,7 @@
*
* Maximum number of loop devices when compiled-in now selectable by passing
* max_loop=<1-255> to the kernel on boot.
- * Erik I. Bolsø, <eriki@himolde.no>, Oct 31, 1999
+ * Erik I. Bolsø, <eriki@himolde.no>, Oct 31, 1999
*
* Completely rewrite request handling to be make_request_fn style and
* non blocking, pushing work to a helper thread. Lots of fixes from
@@ -204,14 +204,13 @@ lo_do_transfer(struct loop_device *lo, int cmd,
* do_lo_send_aops - helper for writing data to a loop device
*
* This is the fast version for backing filesystems which implement the address
- * space operations prepare_write and commit_write.
+ * space operations write_begin and write_end.
*/
static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec,
- int bsize, loff_t pos, struct page *page)
+ int bsize, loff_t pos, struct page *unused)
{
struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
struct address_space *mapping = file->f_mapping;
- const struct address_space_operations *aops = mapping->a_ops;
pgoff_t index;
unsigned offset, bv_offs;
int len, ret;
@@ -223,63 +222,45 @@ static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec,
len = bvec->bv_len;
while (len > 0) {
sector_t IV;
- unsigned size;
+ unsigned size, copied;
int transfer_result;
+ struct page *page;
+ void *fsdata;
IV = ((sector_t)index << (PAGE_CACHE_SHIFT - 9))+(offset >> 9);
size = PAGE_CACHE_SIZE - offset;
if (size > len)
size = len;
- page = grab_cache_page(mapping, index);
- if (unlikely(!page))
+
+ ret = pagecache_write_begin(file, mapping, pos, size, 0,
+ &page, &fsdata);
+ if (ret)
goto fail;
- ret = aops->prepare_write(file, page, offset,
- offset + size);
- if (unlikely(ret)) {
- if (ret == AOP_TRUNCATED_PAGE) {
- page_cache_release(page);
- continue;
- }
- goto unlock;
- }
+
transfer_result = lo_do_transfer(lo, WRITE, page, offset,
bvec->bv_page, bv_offs, size, IV);
- if (unlikely(transfer_result)) {
- /*
- * The transfer failed, but we still write the data to
- * keep prepare/commit calls balanced.
- */
- printk(KERN_ERR "loop: transfer error block %llu\n",
- (unsigned long long)index);
- zero_user_page(page, offset, size, KM_USER0);
- }
- flush_dcache_page(page);
- ret = aops->commit_write(file, page, offset,
- offset + size);
- if (unlikely(ret)) {
- if (ret == AOP_TRUNCATED_PAGE) {
- page_cache_release(page);
- continue;
- }
- goto unlock;
- }
+ copied = size;
if (unlikely(transfer_result))
- goto unlock;
- bv_offs += size;
- len -= size;
+ copied = 0;
+
+ ret = pagecache_write_end(file, mapping, pos, size, copied,
+ page, fsdata);
+ if (ret < 0 || ret != copied)
+ goto fail;
+
+ if (unlikely(transfer_result))
+ goto fail;
+
+ bv_offs += copied;
+ len -= copied;
offset = 0;
index++;
- pos += size;
- unlock_page(page);
- page_cache_release(page);
+ pos += copied;
}
ret = 0;
out:
mutex_unlock(&mapping->host->i_mutex);
return ret;
-unlock:
- unlock_page(page);
- page_cache_release(page);
fail:
ret = -1;
goto out;
@@ -313,7 +294,7 @@ static int __do_lo_send_write(struct file *file,
* do_lo_send_direct_write - helper for writing data to a loop device
*
* This is the fast, non-transforming version for backing filesystems which do
- * not implement the address space operations prepare_write and commit_write.
+ * not implement the address space operations write_begin and write_end.
* It uses the write file operation which should be present on all writeable
* filesystems.
*/
@@ -332,7 +313,7 @@ static int do_lo_send_direct_write(struct loop_device *lo,
* do_lo_send_write - helper for writing data to a loop device
*
* This is the slow, transforming version for filesystems which do not
- * implement the address space operations prepare_write and commit_write. It
+ * implement the address space operations write_begin and write_end. It
* uses the write file operation which should be present on all writeable
* filesystems.
*
@@ -551,7 +532,7 @@ static int loop_make_request(struct request_queue *q, struct bio *old_bio)
out:
spin_unlock_irq(&lo->lo_lock);
- bio_io_error(old_bio, old_bio->bi_size);
+ bio_io_error(old_bio);
return 0;
}
@@ -580,7 +561,7 @@ static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio)
bio_put(bio);
} else {
int ret = do_bio_filebacked(lo, bio);
- bio_endio(bio, bio->bi_size, ret);
+ bio_endio(bio, ret);
}
}
@@ -780,7 +761,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
*/
if (!file->f_op->splice_read)
goto out_putf;
- if (aops->prepare_write && aops->commit_write)
+ if (aops->prepare_write || aops->write_begin)
lo_flags |= LO_FLAGS_USE_AOPS;
if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write)
lo_flags |= LO_FLAGS_READ_ONLY;
@@ -1304,7 +1285,6 @@ static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a
struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
int err;
- lock_kernel();
switch(cmd) {
case LOOP_SET_STATUS:
mutex_lock(&lo->lo_ctl_mutex);
@@ -1330,7 +1310,6 @@ static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a
err = -ENOIOCTLCMD;
break;
}
- unlock_kernel();
return err;
}
#endif
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index be92c658f06..b4c0888aedc 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -28,6 +28,7 @@
#include <linux/err.h>
#include <linux/kernel.h>
#include <net/sock.h>
+#include <linux/net.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -113,12 +114,42 @@ static void nbd_end_request(struct request *req)
spin_unlock_irqrestore(q->queue_lock, flags);
}
+static void sock_shutdown(struct nbd_device *lo, int lock)
+{
+ /* Forcibly shutdown the socket causing all listeners
+ * to error
+ *
+ * FIXME: This code is duplicated from sys_shutdown, but
+ * there should be a more generic interface rather than
+ * calling socket ops directly here */
+ if (lock)
+ mutex_lock(&lo->tx_lock);
+ if (lo->sock) {
+ printk(KERN_WARNING "%s: shutting down socket\n",
+ lo->disk->disk_name);
+ kernel_sock_shutdown(lo->sock, SHUT_RDWR);
+ lo->sock = NULL;
+ }
+ if (lock)
+ mutex_unlock(&lo->tx_lock);
+}
+
+static void nbd_xmit_timeout(unsigned long arg)
+{
+ struct task_struct *task = (struct task_struct *)arg;
+
+ printk(KERN_WARNING "nbd: killing hung xmit (%s, pid: %d)\n",
+ task->comm, task->pid);
+ force_sig(SIGKILL, task);
+}
+
/*
* Send or receive packet.
*/
-static int sock_xmit(struct socket *sock, int send, void *buf, int size,
+static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
int msg_flags)
{
+ struct socket *sock = lo->sock;
int result;
struct msghdr msg;
struct kvec iov;
@@ -139,17 +170,29 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size,
msg.msg_controllen = 0;
msg.msg_flags = msg_flags | MSG_NOSIGNAL;
- if (send)
+ if (send) {
+ struct timer_list ti;
+
+ if (lo->xmit_timeout) {
+ init_timer(&ti);
+ ti.function = nbd_xmit_timeout;
+ ti.data = (unsigned long)current;
+ ti.expires = jiffies + lo->xmit_timeout;
+ add_timer(&ti);
+ }
result = kernel_sendmsg(sock, &msg, &iov, 1, size);
- else
+ if (lo->xmit_timeout)
+ del_timer_sync(&ti);
+ } else
result = kernel_recvmsg(sock, &msg, &iov, 1, size, 0);
if (signal_pending(current)) {
siginfo_t info;
printk(KERN_WARNING "nbd (pid %d: %s) got signal %d\n",
- current->pid, current->comm,
+ task_pid_nr(current), current->comm,
dequeue_signal_lock(current, &current->blocked, &info));
result = -EINTR;
+ sock_shutdown(lo, !send);
break;
}
@@ -167,23 +210,22 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size,
return result;
}
-static inline int sock_send_bvec(struct socket *sock, struct bio_vec *bvec,
+static inline int sock_send_bvec(struct nbd_device *lo, struct bio_vec *bvec,
int flags)
{
int result;
void *kaddr = kmap(bvec->bv_page);
- result = sock_xmit(sock, 1, kaddr + bvec->bv_offset, bvec->bv_len,
- flags);
+ result = sock_xmit(lo, 1, kaddr + bvec->bv_offset, bvec->bv_len, flags);
kunmap(bvec->bv_page);
return result;
}
+/* always call with the tx_lock held */
static int nbd_send_req(struct nbd_device *lo, struct request *req)
{
- int result, i, flags;
+ int result, flags;
struct nbd_request request;
unsigned long size = req->nr_sectors << 9;
- struct socket *sock = lo->sock;
request.magic = htonl(NBD_REQUEST_MAGIC);
request.type = htonl(nbd_cmd(req));
@@ -196,8 +238,8 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
nbdcmd_to_ascii(nbd_cmd(req)),
(unsigned long long)req->sector << 9,
req->nr_sectors << 9);
- result = sock_xmit(sock, 1, &request, sizeof(request),
- (nbd_cmd(req) == NBD_CMD_WRITE)? MSG_MORE: 0);
+ result = sock_xmit(lo, 1, &request, sizeof(request),
+ (nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0);
if (result <= 0) {
printk(KERN_ERR "%s: Send control failed (result %d)\n",
lo->disk->disk_name, result);
@@ -205,27 +247,23 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
}
if (nbd_cmd(req) == NBD_CMD_WRITE) {
- struct bio *bio;
+ struct req_iterator iter;
+ struct bio_vec *bvec;
/*
* we are really probing at internals to determine
* whether to set MSG_MORE or not...
*/
- rq_for_each_bio(bio, req) {
- struct bio_vec *bvec;
- bio_for_each_segment(bvec, bio, i) {
- flags = 0;
- if ((i < (bio->bi_vcnt - 1)) || bio->bi_next)
- flags = MSG_MORE;
- dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n",
- lo->disk->disk_name, req,
- bvec->bv_len);
- result = sock_send_bvec(sock, bvec, flags);
- if (result <= 0) {
- printk(KERN_ERR "%s: Send data failed (result %d)\n",
- lo->disk->disk_name,
- result);
- goto error_out;
- }
+ rq_for_each_segment(bvec, req, iter) {
+ flags = 0;
+ if (!rq_iter_last(req, iter))
+ flags = MSG_MORE;
+ dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n",
+ lo->disk->disk_name, req, bvec->bv_len);
+ result = sock_send_bvec(lo, bvec, flags);
+ if (result <= 0) {
+ printk(KERN_ERR "%s: Send data failed (result %d)\n",
+ lo->disk->disk_name, result);
+ goto error_out;
}
}
}
@@ -235,22 +273,18 @@ error_out:
return 1;
}
-static struct request *nbd_find_request(struct nbd_device *lo, char *handle)
+static struct request *nbd_find_request(struct nbd_device *lo,
+ struct request *xreq)
{
- struct request *req;
- struct list_head *tmp;
- struct request *xreq;
+ struct request *req, *tmp;
int err;
- memcpy(&xreq, handle, sizeof(xreq));
-
err = wait_event_interruptible(lo->active_wq, lo->active_req != xreq);
if (unlikely(err))
goto out;
spin_lock(&lo->queue_lock);
- list_for_each(tmp, &lo->queue_head) {
- req = list_entry(tmp, struct request, queuelist);
+ list_for_each_entry_safe(req, tmp, &lo->queue_head, queuelist) {
if (req != xreq)
continue;
list_del_init(&req->queuelist);
@@ -265,11 +299,11 @@ out:
return ERR_PTR(err);
}
-static inline int sock_recv_bvec(struct socket *sock, struct bio_vec *bvec)
+static inline int sock_recv_bvec(struct nbd_device *lo, struct bio_vec *bvec)
{
int result;
void *kaddr = kmap(bvec->bv_page);
- result = sock_xmit(sock, 0, kaddr + bvec->bv_offset, bvec->bv_len,
+ result = sock_xmit(lo, 0, kaddr + bvec->bv_offset, bvec->bv_len,
MSG_WAITALL);
kunmap(bvec->bv_page);
return result;
@@ -281,10 +315,9 @@ static struct request *nbd_read_stat(struct nbd_device *lo)
int result;
struct nbd_reply reply;
struct request *req;
- struct socket *sock = lo->sock;
reply.magic = 0;
- result = sock_xmit(sock, 0, &reply, sizeof(reply), MSG_WAITALL);
+ result = sock_xmit(lo, 0, &reply, sizeof(reply), MSG_WAITALL);
if (result <= 0) {
printk(KERN_ERR "%s: Receive control failed (result %d)\n",
lo->disk->disk_name, result);
@@ -299,7 +332,7 @@ static struct request *nbd_read_stat(struct nbd_device *lo)
goto harderror;
}
- req = nbd_find_request(lo, reply.handle);
+ req = nbd_find_request(lo, *(struct request **)reply.handle);
if (unlikely(IS_ERR(req))) {
result = PTR_ERR(req);
if (result != -ENOENT)
@@ -321,22 +354,19 @@ static struct request *nbd_read_stat(struct nbd_device *lo)
dprintk(DBG_RX, "%s: request %p: got reply\n",
lo->disk->disk_name, req);
if (nbd_cmd(req) == NBD_CMD_READ) {
- int i;
- struct bio *bio;
- rq_for_each_bio(bio, req) {
- struct bio_vec *bvec;
- bio_for_each_segment(bvec, bio, i) {
- result = sock_recv_bvec(sock, bvec);
- if (result <= 0) {
- printk(KERN_ERR "%s: Receive data failed (result %d)\n",
- lo->disk->disk_name,
- result);
- req->errors++;
- return req;
- }
- dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
- lo->disk->disk_name, req, bvec->bv_len);
+ struct req_iterator iter;
+ struct bio_vec *bvec;
+
+ rq_for_each_segment(bvec, req, iter) {
+ result = sock_recv_bvec(lo, bvec);
+ if (result <= 0) {
+ printk(KERN_ERR "%s: Receive data failed (result %d)\n",
+ lo->disk->disk_name, result);
+ req->errors++;
+ return req;
}
+ dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
+ lo->disk->disk_name, req, bvec->bv_len);
}
}
return req;
@@ -403,6 +433,7 @@ static void nbd_clear_que(struct nbd_device *lo)
}
}
+
/*
* We always wait for result of write, for now. It would be nice to make it optional
* in future
@@ -478,7 +509,6 @@ error_out:
nbd_end_request(req);
spin_lock(q->queue_lock);
}
- return;
}
static int nbd_ioctl(struct inode *inode, struct file *file,
@@ -511,7 +541,9 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
sreq.nr_sectors = 0;
if (!lo->sock)
return -EINVAL;
+ mutex_lock(&lo->tx_lock);
nbd_send_req(lo, &sreq);
+ mutex_unlock(&lo->tx_lock);
return 0;
case NBD_CLEAR_SOCK:
@@ -555,6 +587,9 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
set_blocksize(inode->i_bdev, lo->blksize);
set_capacity(lo->disk, lo->bytesize >> 9);
return 0;
+ case NBD_SET_TIMEOUT:
+ lo->xmit_timeout = arg * HZ;
+ return 0;
case NBD_SET_SIZE_BLOCKS:
lo->bytesize = ((u64) arg) * lo->blksize;
inode->i_bdev->bd_inode->i_size = lo->bytesize;
@@ -567,28 +602,16 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
error = nbd_do_it(lo);
if (error)
return error;
- /* on return tidy up in case we have a signal */
- /* Forcibly shutdown the socket causing all listeners
- * to error
- *
- * FIXME: This code is duplicated from sys_shutdown, but
- * there should be a more generic interface rather than
- * calling socket ops directly here */
- mutex_lock(&lo->tx_lock);
- if (lo->sock) {
- printk(KERN_WARNING "%s: shutting down socket\n",
- lo->disk->disk_name);
- lo->sock->ops->shutdown(lo->sock,
- SEND_SHUTDOWN|RCV_SHUTDOWN);
- lo->sock = NULL;
- }
- mutex_unlock(&lo->tx_lock);
+ sock_shutdown(lo, 1);
file = lo->file;
lo->file = NULL;
nbd_clear_que(lo);
printk(KERN_WARNING "%s: queue cleared\n", lo->disk->disk_name);
if (file)
fput(file);
+ lo->bytesize = 0;
+ inode->i_bdev->bd_inode->i_size = 0;
+ set_capacity(lo->disk, 0);
return lo->harderror;
case NBD_CLEAR_QUE:
/*
@@ -666,14 +689,14 @@ static int __init nbd_init(void)
mutex_init(&nbd_dev[i].tx_lock);
init_waitqueue_head(&nbd_dev[i].active_wq);
nbd_dev[i].blksize = 1024;
- nbd_dev[i].bytesize = 0x7ffffc00ULL << 10; /* 2TB */
+ nbd_dev[i].bytesize = 0;
disk->major = NBD_MAJOR;
disk->first_minor = i;
disk->fops = &nbd_fops;
disk->private_data = &nbd_dev[i];
disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
sprintf(disk->disk_name, "nbd%d", i);
- set_capacity(disk, 0x7ffffc00ULL << 1); /* 2 TB */
+ set_capacity(disk, 0);
add_disk(disk);
}
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index ceffa6034e2..e7fe6ca97dd 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -488,13 +488,11 @@ static int pf_atapi(struct pf_unit *pf, char *cmd, int dlen, char *buf, char *fu
return r;
}
-#define DBMSG(msg) ((verbose>1)?(msg):NULL)
-
static void pf_lock(struct pf_unit *pf, int func)
{
char lo_cmd[12] = { ATAPI_LOCK, pf->lun << 5, 0, 0, func, 0, 0, 0, 0, 0, 0, 0 };
- pf_atapi(pf, lo_cmd, 0, pf_scratch, func ? "unlock" : "lock");
+ pf_atapi(pf, lo_cmd, 0, pf_scratch, func ? "lock" : "unlock");
}
static void pf_eject(struct pf_unit *pf)
@@ -555,7 +553,7 @@ static void pf_mode_sense(struct pf_unit *pf)
{ ATAPI_MODE_SENSE, pf->lun << 5, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0 };
char buf[8];
- pf_atapi(pf, ms_cmd, 8, buf, DBMSG("mode sense"));
+ pf_atapi(pf, ms_cmd, 8, buf, "mode sense");
pf->media_status = PF_RW;
if (buf[3] & 0x80)
pf->media_status = PF_RO;
@@ -591,7 +589,7 @@ static void pf_get_capacity(struct pf_unit *pf)
char buf[8];
int bs;
- if (pf_atapi(pf, rc_cmd, 8, buf, DBMSG("get capacity"))) {
+ if (pf_atapi(pf, rc_cmd, 8, buf, "get capacity")) {
pf->media_status = PF_NM;
return;
}
@@ -804,13 +802,18 @@ static int pf_next_buf(void)
pf_buf += 512;
pf_block++;
if (!pf_run)
- return 0;
- if (!pf_count)
return 1;
- spin_lock_irqsave(&pf_spin_lock, saved_flags);
- pf_end_request(1);
- spin_unlock_irqrestore(&pf_spin_lock, saved_flags);
- return 1;
+ if (!pf_count) {
+ spin_lock_irqsave(&pf_spin_lock, saved_flags);
+ pf_end_request(1);
+ pf_req = elv_next_request(pf_queue);
+ spin_unlock_irqrestore(&pf_spin_lock, saved_flags);
+ if (!pf_req)
+ return 1;
+ pf_count = pf_req->current_nr_sectors;
+ pf_buf = pf_req->buffer;
+ }
+ return 0;
}
static inline void next_request(int success)
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index 9f4e67ee1eb..b91accf1265 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -664,7 +664,7 @@ static int pt_open(struct inode *inode, struct file *file)
goto out;
err = -EROFS;
- if ((!tape->flags & PT_WRITE_OK) && (file->f_mode & 2))
+ if ((!(tape->flags & PT_WRITE_OK)) && (file->f_mode & 2))
goto out;
if (!(iminor(inode) & 128))
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index fadbfd880ba..a5ee21319d3 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -358,10 +358,19 @@ static ssize_t class_pktcdvd_store_add(struct class *c, const char *buf,
size_t count)
{
unsigned int major, minor;
+
if (sscanf(buf, "%u:%u", &major, &minor) == 2) {
+ /* pkt_setup_dev() expects caller to hold reference to self */
+ if (!try_module_get(THIS_MODULE))
+ return -ENODEV;
+
pkt_setup_dev(MKDEV(major, minor), NULL);
+
+ module_put(THIS_MODULE);
+
return count;
}
+
return -EINVAL;
}
@@ -1058,15 +1067,12 @@ static void pkt_make_local_copy(struct packet_data *pkt, struct bio_vec *bvec)
}
}
-static int pkt_end_io_read(struct bio *bio, unsigned int bytes_done, int err)
+static void pkt_end_io_read(struct bio *bio, int err)
{
struct packet_data *pkt = bio->bi_private;
struct pktcdvd_device *pd = pkt->pd;
BUG_ON(!pd);
- if (bio->bi_size)
- return 1;
-
VPRINTK("pkt_end_io_read: bio=%p sec0=%llx sec=%llx err=%d\n", bio,
(unsigned long long)pkt->sector, (unsigned long long)bio->bi_sector, err);
@@ -1077,19 +1083,14 @@ static int pkt_end_io_read(struct bio *bio, unsigned int bytes_done, int err)
wake_up(&pd->wqueue);
}
pkt_bio_finished(pd);
-
- return 0;
}
-static int pkt_end_io_packet_write(struct bio *bio, unsigned int bytes_done, int err)
+static void pkt_end_io_packet_write(struct bio *bio, int err)
{
struct packet_data *pkt = bio->bi_private;
struct pktcdvd_device *pd = pkt->pd;
BUG_ON(!pd);
- if (bio->bi_size)
- return 1;
-
VPRINTK("pkt_end_io_packet_write: id=%d, err=%d\n", pkt->id, err);
pd->stats.pkt_ended++;
@@ -1098,7 +1099,6 @@ static int pkt_end_io_packet_write(struct bio *bio, unsigned int bytes_done, int
atomic_dec(&pkt->io_wait);
atomic_inc(&pkt->run_sm);
wake_up(&pd->wqueue);
- return 0;
}
/*
@@ -1142,16 +1142,21 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
* Schedule reads for missing parts of the packet.
*/
for (f = 0; f < pkt->frames; f++) {
+ struct bio_vec *vec;
+
int p, offset;
if (written[f])
continue;
bio = pkt->r_bios[f];
+ vec = bio->bi_io_vec;
bio_init(bio);
bio->bi_max_vecs = 1;
bio->bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9);
bio->bi_bdev = pd->bdev;
bio->bi_end_io = pkt_end_io_read;
bio->bi_private = pkt;
+ bio->bi_io_vec = vec;
+ bio->bi_destructor = pkt_bio_destructor;
p = (f * CD_FRAMESIZE) / PAGE_SIZE;
offset = (f * CD_FRAMESIZE) % PAGE_SIZE;
@@ -1448,6 +1453,8 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
pkt->w_bio->bi_bdev = pd->bdev;
pkt->w_bio->bi_end_io = pkt_end_io_packet_write;
pkt->w_bio->bi_private = pkt;
+ pkt->w_bio->bi_io_vec = bvec;
+ pkt->w_bio->bi_destructor = pkt_bio_destructor;
for (f = 0; f < pkt->frames; f++)
if (!bio_add_page(pkt->w_bio, bvec[f].bv_page, CD_FRAMESIZE, bvec[f].bv_offset))
BUG();
@@ -1470,7 +1477,7 @@ static void pkt_finish_packet(struct packet_data *pkt, int uptodate)
while (bio) {
next = bio->bi_next;
bio->bi_next = NULL;
- bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO);
+ bio_endio(bio, uptodate ? 0 : -EIO);
bio = next;
}
pkt->orig_bios = pkt->orig_bios_tail = NULL;
@@ -2462,19 +2469,15 @@ static int pkt_close(struct inode *inode, struct file *file)
}
-static int pkt_end_io_read_cloned(struct bio *bio, unsigned int bytes_done, int err)
+static void pkt_end_io_read_cloned(struct bio *bio, int err)
{
struct packet_stacked_data *psd = bio->bi_private;
struct pktcdvd_device *pd = psd->pd;
- if (bio->bi_size)
- return 1;
-
bio_put(bio);
- bio_endio(psd->bio, psd->bio->bi_size, err);
+ bio_endio(psd->bio, err);
mempool_free(psd, psd_pool);
pkt_bio_finished(pd);
- return 0;
}
static int pkt_make_request(struct request_queue *q, struct bio *bio)
@@ -2620,7 +2623,7 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio)
}
return 0;
end_io:
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
index aa8b890c80d..e354bfc070e 100644
--- a/drivers/block/ps3disk.c
+++ b/drivers/block/ps3disk.c
@@ -91,30 +91,29 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
struct request *req, int gather)
{
unsigned int offset = 0;
- struct bio *bio;
- sector_t sector;
+ struct req_iterator iter;
struct bio_vec *bvec;
- unsigned int i = 0, j;
+ unsigned int i = 0;
size_t size;
void *buf;
- rq_for_each_bio(bio, req) {
- sector = bio->bi_sector;
+ rq_for_each_segment(bvec, req, iter) {
+ unsigned long flags;
dev_dbg(&dev->sbd.core,
"%s:%u: bio %u: %u segs %u sectors from %lu\n",
- __func__, __LINE__, i, bio_segments(bio),
- bio_sectors(bio), sector);
- bio_for_each_segment(bvec, bio, j) {
- size = bvec->bv_len;
- buf = __bio_kmap_atomic(bio, j, KM_IRQ0);
- if (gather)
- memcpy(dev->bounce_buf+offset, buf, size);
- else
- memcpy(buf, dev->bounce_buf+offset, size);
- offset += size;
- flush_kernel_dcache_page(bio_iovec_idx(bio, j)->bv_page);
- __bio_kunmap_atomic(bio, KM_IRQ0);
- }
+ __func__, __LINE__, i, bio_segments(iter.bio),
+ bio_sectors(iter.bio),
+ (unsigned long)iter.bio->bi_sector);
+
+ size = bvec->bv_len;
+ buf = bvec_kmap_irq(bvec, &flags);
+ if (gather)
+ memcpy(dev->bounce_buf+offset, buf, size);
+ else
+ memcpy(buf, dev->bounce_buf+offset, size);
+ offset += size;
+ flush_kernel_dcache_page(bvec->bv_page);
+ bvec_kunmap_irq(bvec, &flags);
i++;
}
}
@@ -130,12 +129,13 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
#ifdef DEBUG
unsigned int n = 0;
- struct bio *bio;
+ struct bio_vec *bv;
+ struct req_iterator iter;
- rq_for_each_bio(bio, req)
+ rq_for_each_segment(bv, req, iter)
n++;
dev_dbg(&dev->sbd.core,
- "%s:%u: %s req has %u bios for %lu sectors %lu hard sectors\n",
+ "%s:%u: %s req has %u bvecs for %lu sectors %lu hard sectors\n",
__func__, __LINE__, op, n, req->nr_sectors,
req->hard_nr_sectors);
#endif
@@ -414,26 +414,6 @@ static void ps3disk_prepare_flush(struct request_queue *q, struct request *req)
req->cmd_type = REQ_TYPE_FLUSH;
}
-static int ps3disk_issue_flush(struct request_queue *q, struct gendisk *gendisk,
- sector_t *sector)
-{
- struct ps3_storage_device *dev = q->queuedata;
- struct request *req;
- int res;
-
- dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
-
- req = blk_get_request(q, WRITE, __GFP_WAIT);
- ps3disk_prepare_flush(q, req);
- res = blk_execute_rq(q, gendisk, req, 0);
- if (res)
- dev_err(&dev->sbd.core, "%s:%u: flush request failed %d\n",
- __func__, __LINE__, res);
- blk_put_request(req);
- return res;
-}
-
-
static unsigned long ps3disk_mask;
static DEFINE_MUTEX(ps3disk_mask_mutex);
@@ -506,7 +486,6 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
blk_queue_dma_alignment(queue, dev->blk_size-1);
blk_queue_hardsect_size(queue, dev->blk_size);
- blk_queue_issue_flush_fn(queue, ps3disk_issue_flush);
blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH,
ps3disk_prepare_flush);
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 65150b548f3..82f4eecc869 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -189,6 +189,18 @@ static int ramdisk_set_page_dirty(struct page *page)
return 0;
}
+/*
+ * releasepage is called by pagevec_strip/try_to_release_page if
+ * buffers_heads_over_limit is true. Without a releasepage function
+ * try_to_free_buffers is called instead. That can unset the dirty
+ * bit of our ram disk pages, which will be eventually freed, even
+ * if the page is still in use.
+ */
+static int ramdisk_releasepage(struct page *page, gfp_t dummy)
+{
+ return 0;
+}
+
static const struct address_space_operations ramdisk_aops = {
.readpage = ramdisk_readpage,
.prepare_write = ramdisk_prepare_write,
@@ -196,6 +208,7 @@ static const struct address_space_operations ramdisk_aops = {
.writepage = ramdisk_writepage,
.set_page_dirty = ramdisk_set_page_dirty,
.writepages = ramdisk_writepages,
+ .releasepage = ramdisk_releasepage,
};
static int rd_blkdev_pagecache_IO(int rw, struct bio_vec *vec, sector_t sector,
@@ -287,10 +300,10 @@ static int rd_make_request(struct request_queue *q, struct bio *bio)
if (ret)
goto fail;
- bio_endio(bio, bio->bi_size, 0);
+ bio_endio(bio, 0);
return 0;
fail:
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
@@ -365,7 +378,7 @@ static int rd_open(struct inode *inode, struct file *filp)
/*
* Deep badness. rd_blkdev_pagecache_IO() needs to allocate
* pagecache pages within a request_fn. We cannot recur back
- * into the filesytem which is mounted atop the ramdisk, because
+ * into the filesystem which is mounted atop the ramdisk, because
* that would deadlock on fs locks. And we really don't want
* to reenter rd_blkdev_pagecache_IO when we're already within
* that function.
@@ -411,6 +424,9 @@ static void __exit rd_cleanup(void)
blk_cleanup_queue(rd_queue[i]);
}
unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
+
+ bdi_destroy(&rd_file_backing_dev_info);
+ bdi_destroy(&rd_backing_dev_info);
}
/*
@@ -419,7 +435,19 @@ static void __exit rd_cleanup(void)
static int __init rd_init(void)
{
int i;
- int err = -ENOMEM;
+ int err;
+
+ err = bdi_init(&rd_backing_dev_info);
+ if (err)
+ goto out2;
+
+ err = bdi_init(&rd_file_backing_dev_info);
+ if (err) {
+ bdi_destroy(&rd_backing_dev_info);
+ goto out2;
+ }
+
+ err = -ENOMEM;
if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 ||
(rd_blocksize & (rd_blocksize-1))) {
@@ -473,6 +501,9 @@ out:
put_disk(rd_disks[i]);
blk_cleanup_queue(rd_queue[i]);
}
+ bdi_destroy(&rd_backing_dev_info);
+ bdi_destroy(&rd_file_backing_dev_info);
+out2:
return err;
}
@@ -486,17 +517,12 @@ static int __init ramdisk_size(char *str)
rd_size = simple_strtol(str,NULL,0);
return 1;
}
-static int __init ramdisk_size2(char *str) /* kludge */
-{
- return ramdisk_size(str);
-}
static int __init ramdisk_blocksize(char *str)
{
rd_blocksize = simple_strtol(str,NULL,0);
return 1;
}
-__setup("ramdisk=", ramdisk_size);
-__setup("ramdisk_size=", ramdisk_size2);
+__setup("ramdisk_size=", ramdisk_size);
__setup("ramdisk_blocksize=", ramdisk_blocksize);
#endif
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 317a790c153..fac4c6cd04f 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/list.h>
+#include <linux/scatterlist.h>
#include <asm/vio.h>
#include <asm/ldc.h>
@@ -388,6 +389,7 @@ static int __send_request(struct request *req)
op = VD_OP_BWRITE;
}
+ sg_init_table(sg, port->ring_cookies);
nsg = blk_rq_map_sg(req->q, req, sg);
len = 0;
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 402209fec59..52dc5e13171 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -27,6 +27,7 @@
#include <linux/hdreg.h>
#include <linux/dma-mapping.h>
#include <linux/completion.h>
+#include <linux/scatterlist.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -522,6 +523,7 @@ static struct carm_request *carm_get_request(struct carm_host *host)
host->n_msgs++;
assert(host->n_msgs <= CARM_MAX_REQ);
+ sg_init_table(crq->sg, CARM_MAX_REQ_SG);
return crq;
}
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index c57dd2b3a0c..08e909dc794 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -25,6 +25,7 @@
#include <linux/usb_usual.h>
#include <linux/blkdev.h>
#include <linux/timer.h>
+#include <linux/scatterlist.h>
#include <scsi/scsi.h>
#define DRV_NAME "ub"
@@ -656,6 +657,7 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
if ((cmd = ub_get_cmd(lun)) == NULL)
return -1;
memset(cmd, 0, sizeof(struct ub_scsi_cmd));
+ sg_init_table(cmd->sgv, UB_MAX_REQ_SG);
blkdev_dequeue_request(rq);
@@ -1309,9 +1311,8 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
else
pipe = sc->send_bulk_pipe;
sc->last_pipe = pipe;
- usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe,
- page_address(sg->page) + sg->offset, sg->length,
- ub_urb_complete, sc);
+ usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, sg_virt(sg),
+ sg->length, ub_urb_complete, sc);
sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
@@ -1427,9 +1428,9 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
scmd->state = UB_CMDST_INIT;
scmd->nsg = 1;
sg = &scmd->sgv[0];
- sg->page = virt_to_page(sc->top_sense);
- sg->offset = (unsigned long)sc->top_sense & (PAGE_SIZE-1);
- sg->length = UB_SENSE_SIZE;
+ sg_init_table(sg, UB_MAX_REQ_SG);
+ sg_set_page(sg, virt_to_page(sc->top_sense), UB_SENSE_SIZE,
+ (unsigned long)sc->top_sense & (PAGE_SIZE-1));
scmd->len = UB_SENSE_SIZE;
scmd->lun = cmd->lun;
scmd->done = ub_top_sense_done;
@@ -1863,9 +1864,8 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
cmd->state = UB_CMDST_INIT;
cmd->nsg = 1;
sg = &cmd->sgv[0];
- sg->page = virt_to_page(p);
- sg->offset = (unsigned long)p & (PAGE_SIZE-1);
- sg->length = 8;
+ sg_init_table(sg, UB_MAX_REQ_SG);
+ sg_set_page(sg, virt_to_page(p), 8, (unsigned long)p & (PAGE_SIZE-1));
cmd->len = 8;
cmd->lun = lun;
cmd->done = ub_probe_done;
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index 6b7c02d6360..99806f9ee4c 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -52,7 +52,7 @@
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/hdreg.h> /* HDIO_GETGEO */
-#include <linux/umem.h>
+#include "umem.h"
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -67,9 +67,10 @@
* Version Information
*/
-#define DRIVER_VERSION "v2.3"
-#define DRIVER_AUTHOR "San Mehat, Johannes Erdfelt, NeilBrown"
-#define DRIVER_DESC "Micro Memory(tm) PCI memory board block driver"
+#define DRIVER_NAME "umem"
+#define DRIVER_VERSION "v2.3"
+#define DRIVER_AUTHOR "San Mehat, Johannes Erdfelt, NeilBrown"
+#define DRIVER_DESC "Micro Memory(tm) PCI memory board block driver"
static int debug;
/* #define HW_TRACE(x) writeb(x,cards[0].csr_remap + MEMCTRLSTATUS_MAGIC) */
@@ -97,15 +98,9 @@ static int major_nr;
#include <linux/blkpg.h>
struct cardinfo {
- int card_number;
struct pci_dev *dev;
- int irq;
-
- unsigned long csr_base;
unsigned char __iomem *csr_remap;
- unsigned long csr_len;
- unsigned int win_size; /* PCI window size */
unsigned int mm_size; /* size in kbytes */
unsigned int init_size; /* initial segment, in sectors,
@@ -113,6 +108,8 @@ struct cardinfo {
* have been written
*/
struct bio *bio, *currentbio, **biotail;
+ int current_idx;
+ sector_t current_sector;
struct request_queue *queue;
@@ -121,6 +118,7 @@ struct cardinfo {
struct mm_dma_desc *desc;
int cnt, headcnt;
struct bio *bio, **biotail;
+ int idx;
} mm_pages[2];
#define DESC_PER_PAGE ((PAGE_SIZE*2)/sizeof(struct mm_dma_desc))
@@ -233,7 +231,7 @@ static void dump_regs(struct cardinfo *card)
*/
static void dump_dmastat(struct cardinfo *card, unsigned int dmastat)
{
- printk(KERN_DEBUG "MM%d*: DMAstat - ", card->card_number);
+ dev_printk(KERN_DEBUG, &card->dev->dev, "DMAstat - ");
if (dmastat & DMASCR_ANY_ERR)
printk("ANY_ERR ");
if (dmastat & DMASCR_MBE_ERR)
@@ -295,7 +293,7 @@ static void mm_start_io(struct cardinfo *card)
desc->control_bits &= ~cpu_to_le32(DMASCR_CHAIN_EN);
desc->sem_control_bits = desc->control_bits;
-
+
if (debug & DEBUG_LED_ON_TRANSFER)
set_led(card, LED_REMOVE, LED_ON);
@@ -329,7 +327,7 @@ static int add_bio(struct cardinfo *card);
static void activate(struct cardinfo *card)
{
- /* if No page is Active, and Ready is
+ /* if No page is Active, and Ready is
* not empty, then switch Ready page
* to active and start IO.
* Then add any bh's that are available to Ready
@@ -368,7 +366,7 @@ static void mm_unplug_device(struct request_queue *q)
spin_unlock_irqrestore(&card->lock, flags);
}
-/*
+/*
* If there is room on Ready page, take
* one bh off list and add it.
* return 1 if there was room, else 0.
@@ -380,12 +378,16 @@ static int add_bio(struct cardinfo *card)
dma_addr_t dma_handle;
int offset;
struct bio *bio;
+ struct bio_vec *vec;
+ int idx;
int rw;
int len;
bio = card->currentbio;
if (!bio && card->bio) {
card->currentbio = card->bio;
+ card->current_idx = card->bio->bi_idx;
+ card->current_sector = card->bio->bi_sector;
card->bio = card->bio->bi_next;
if (card->bio == NULL)
card->biotail = &card->bio;
@@ -394,15 +396,17 @@ static int add_bio(struct cardinfo *card)
}
if (!bio)
return 0;
+ idx = card->current_idx;
rw = bio_rw(bio);
if (card->mm_pages[card->Ready].cnt >= DESC_PER_PAGE)
return 0;
- len = bio_iovec(bio)->bv_len;
- dma_handle = pci_map_page(card->dev,
- bio_page(bio),
- bio_offset(bio),
+ vec = bio_iovec_idx(bio, idx);
+ len = vec->bv_len;
+ dma_handle = pci_map_page(card->dev,
+ vec->bv_page,
+ vec->bv_offset,
len,
(rw==READ) ?
PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
@@ -410,6 +414,8 @@ static int add_bio(struct cardinfo *card)
p = &card->mm_pages[card->Ready];
desc = &p->desc[p->cnt];
p->cnt++;
+ if (p->bio == NULL)
+ p->idx = idx;
if ((p->biotail) != &bio->bi_next) {
*(p->biotail) = bio;
p->biotail = &(bio->bi_next);
@@ -419,7 +425,7 @@ static int add_bio(struct cardinfo *card)
desc->data_dma_handle = dma_handle;
desc->pci_addr = cpu_to_le64((u64)desc->data_dma_handle);
- desc->local_addr= cpu_to_le64(bio->bi_sector << 9);
+ desc->local_addr = cpu_to_le64(card->current_sector << 9);
desc->transfer_size = cpu_to_le32(len);
offset = ( ((char*)&desc->sem_control_bits) - ((char*)p->desc));
desc->sem_addr = cpu_to_le64((u64)(p->page_dma+offset));
@@ -435,10 +441,10 @@ static int add_bio(struct cardinfo *card)
desc->control_bits |= cpu_to_le32(DMASCR_TRANSFER_READ);
desc->sem_control_bits = desc->control_bits;
- bio->bi_sector += (len>>9);
- bio->bi_size -= len;
- bio->bi_idx++;
- if (bio->bi_idx >= bio->bi_vcnt)
+ card->current_sector += (len >> 9);
+ idx++;
+ card->current_idx = idx;
+ if (idx >= bio->bi_vcnt)
card->currentbio = NULL;
return 1;
@@ -461,7 +467,7 @@ static void process_page(unsigned long data)
if (card->Active < 0)
goto out_unlock;
page = &card->mm_pages[card->Active];
-
+
while (page->headcnt < page->cnt) {
struct bio *bio = page->bio;
struct mm_dma_desc *desc = &page->desc[page->headcnt];
@@ -471,32 +477,34 @@ static void process_page(unsigned long data)
if (!(control & DMASCR_DMA_COMPLETE)) {
control = dma_status;
- last=1;
+ last=1;
}
page->headcnt++;
- idx = bio->bi_phys_segments;
- bio->bi_phys_segments++;
- if (bio->bi_phys_segments >= bio->bi_vcnt)
+ idx = page->idx;
+ page->idx++;
+ if (page->idx >= bio->bi_vcnt) {
page->bio = bio->bi_next;
+ page->idx = page->bio->bi_idx;
+ }
- pci_unmap_page(card->dev, desc->data_dma_handle,
+ pci_unmap_page(card->dev, desc->data_dma_handle,
bio_iovec_idx(bio,idx)->bv_len,
(control& DMASCR_TRANSFER_READ) ?
PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
if (control & DMASCR_HARD_ERROR) {
/* error */
clear_bit(BIO_UPTODATE, &bio->bi_flags);
- printk(KERN_WARNING "MM%d: I/O error on sector %d/%d\n",
- card->card_number,
- le32_to_cpu(desc->local_addr)>>9,
- le32_to_cpu(desc->transfer_size));
+ dev_printk(KERN_WARNING, &card->dev->dev,
+ "I/O error on sector %d/%d\n",
+ le32_to_cpu(desc->local_addr)>>9,
+ le32_to_cpu(desc->transfer_size));
dump_dmastat(card, control);
} else if (test_bit(BIO_RW, &bio->bi_rw) &&
le32_to_cpu(desc->local_addr)>>9 == card->init_size) {
card->init_size += le32_to_cpu(desc->transfer_size)>>9;
if (card->init_size>>1 >= card->mm_size) {
- printk(KERN_INFO "MM%d: memory now initialised\n",
- card->card_number);
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "memory now initialised\n");
set_userbit(card, MEMORY_INITIALIZED, 1);
}
}
@@ -532,7 +540,7 @@ static void process_page(unsigned long data)
return_bio = bio->bi_next;
bio->bi_next = NULL;
- bio_endio(bio, bio->bi_size, 0);
+ bio_endio(bio, 0);
}
}
@@ -547,7 +555,6 @@ static int mm_make_request(struct request_queue *q, struct bio *bio)
pr_debug("mm_make_request %llu %u\n",
(unsigned long long)bio->bi_sector, bio->bi_size);
- bio->bi_phys_segments = bio->bi_idx; /* count of completed segments*/
spin_lock_irq(&card->lock);
*card->biotail = bio;
bio->bi_next = NULL;
@@ -585,7 +592,7 @@ HW_TRACE(0x30);
else
writeb((DMASCR_DMA_COMPLETE|DMASCR_CHAIN_COMPLETE) >> 16,
card->csr_remap+ DMA_STATUS_CTRL + 2);
-
+
/* log errors and clear interrupt status */
if (dma_status & DMASCR_ANY_ERR) {
unsigned int data_log1, data_log2;
@@ -606,46 +613,51 @@ HW_TRACE(0x30);
dump_dmastat(card, dma_status);
if (stat & 0x01)
- printk(KERN_ERR "MM%d*: Memory access error detected (err count %d)\n",
- card->card_number, count);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Memory access error detected (err count %d)\n",
+ count);
if (stat & 0x02)
- printk(KERN_ERR "MM%d*: Multi-bit EDC error\n",
- card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Multi-bit EDC error\n");
- printk(KERN_ERR "MM%d*: Fault Address 0x%02x%08x, Fault Data 0x%08x%08x\n",
- card->card_number, addr_log2, addr_log1, data_log2, data_log1);
- printk(KERN_ERR "MM%d*: Fault Check 0x%02x, Fault Syndrome 0x%02x\n",
- card->card_number, check, syndrome);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Fault Address 0x%02x%08x, Fault Data 0x%08x%08x\n",
+ addr_log2, addr_log1, data_log2, data_log1);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Fault Check 0x%02x, Fault Syndrome 0x%02x\n",
+ check, syndrome);
writeb(0, card->csr_remap + ERROR_COUNT);
}
if (dma_status & DMASCR_PARITY_ERR_REP) {
- printk(KERN_ERR "MM%d*: PARITY ERROR REPORTED\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "PARITY ERROR REPORTED\n");
pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
}
if (dma_status & DMASCR_PARITY_ERR_DET) {
- printk(KERN_ERR "MM%d*: PARITY ERROR DETECTED\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "PARITY ERROR DETECTED\n");
pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
}
if (dma_status & DMASCR_SYSTEM_ERR_SIG) {
- printk(KERN_ERR "MM%d*: SYSTEM ERROR\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev, "SYSTEM ERROR\n");
pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
}
if (dma_status & DMASCR_TARGET_ABT) {
- printk(KERN_ERR "MM%d*: TARGET ABORT\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev, "TARGET ABORT\n");
pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
}
if (dma_status & DMASCR_MASTER_ABT) {
- printk(KERN_ERR "MM%d*: MASTER ABORT\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev, "MASTER ABORT\n");
pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
}
@@ -656,7 +668,7 @@ HW_TRACE(0x30);
HW_TRACE(0x36);
- return IRQ_HANDLED;
+ return IRQ_HANDLED;
}
/*
-----------------------------------------------------------------------------------
@@ -696,20 +708,20 @@ static int check_battery(struct cardinfo *card, int battery, int status)
card->battery[battery].last_change = jiffies;
if (card->battery[battery].good) {
- printk(KERN_ERR "MM%d: Battery %d now good\n",
- card->card_number, battery + 1);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Battery %d now good\n", battery + 1);
card->battery[battery].warned = 0;
} else
- printk(KERN_ERR "MM%d: Battery %d now FAILED\n",
- card->card_number, battery + 1);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Battery %d now FAILED\n", battery + 1);
return 1;
} else if (!card->battery[battery].good &&
!card->battery[battery].warned &&
time_after_eq(jiffies, card->battery[battery].last_change +
(HZ * 60 * 60 * 5))) {
- printk(KERN_ERR "MM%d: Battery %d still FAILED after 5 hours\n",
- card->card_number, battery + 1);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Battery %d still FAILED after 5 hours\n", battery + 1);
card->battery[battery].warned = 1;
return 1;
@@ -733,8 +745,8 @@ static void check_batteries(struct cardinfo *card)
status = readb(card->csr_remap + MEMCTRLSTATUS_BATTERY);
if (debug & DEBUG_BATTERY_POLLING)
- printk(KERN_DEBUG "MM%d: checking battery status, 1 = %s, 2 = %s\n",
- card->card_number,
+ dev_printk(KERN_DEBUG, &card->dev->dev,
+ "checking battery status, 1 = %s, 2 = %s\n",
(status & BATTERY_1_FAILURE) ? "FAILURE" : "OK",
(status & BATTERY_2_FAILURE) ? "FAILURE" : "OK");
@@ -749,7 +761,7 @@ static void check_all_batteries(unsigned long ptr)
{
int i;
- for (i = 0; i < num_cards; i++)
+ for (i = 0; i < num_cards; i++)
if (!(cards[i].flags & UM_FLAG_NO_BATT)) {
struct cardinfo *card = &cards[i];
spin_lock_bh(&card->lock);
@@ -853,45 +865,56 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
unsigned char mem_present;
unsigned char batt_status;
unsigned int saved_bar, data;
+ unsigned long csr_base;
+ unsigned long csr_len;
int magic_number;
+ static int printed_version;
- if (pci_enable_device(dev) < 0)
- return -ENODEV;
+ if (!printed_version++)
+ printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n");
+
+ ret = pci_enable_device(dev);
+ if (ret)
+ return ret;
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF8);
pci_set_master(dev);
card->dev = dev;
- card->card_number = num_cards;
- card->csr_base = pci_resource_start(dev, 0);
- card->csr_len = pci_resource_len(dev, 0);
+ csr_base = pci_resource_start(dev, 0);
+ csr_len = pci_resource_len(dev, 0);
+ if (!csr_base || !csr_len)
+ return -ENODEV;
- printk(KERN_INFO "Micro Memory(tm) controller #%d found at %02x:%02x (PCI Mem Module (Battery Backup))\n",
- card->card_number, dev->bus->number, dev->devfn);
+ dev_printk(KERN_INFO, &dev->dev,
+ "Micro Memory(tm) controller found (PCI Mem Module (Battery Backup))\n");
if (pci_set_dma_mask(dev, DMA_64BIT_MASK) &&
pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING "MM%d: NO suitable DMA found\n",num_cards);
+ dev_printk(KERN_WARNING, &dev->dev, "NO suitable DMA found\n");
return -ENOMEM;
}
- if (!request_mem_region(card->csr_base, card->csr_len, "Micro Memory")) {
- printk(KERN_ERR "MM%d: Unable to request memory region\n", card->card_number);
- ret = -ENOMEM;
+ ret = pci_request_regions(dev, DRIVER_NAME);
+ if (ret) {
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Unable to request memory region\n");
goto failed_req_csr;
}
- card->csr_remap = ioremap_nocache(card->csr_base, card->csr_len);
+ card->csr_remap = ioremap_nocache(csr_base, csr_len);
if (!card->csr_remap) {
- printk(KERN_ERR "MM%d: Unable to remap memory region\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Unable to remap memory region\n");
ret = -ENOMEM;
goto failed_remap_csr;
}
- printk(KERN_INFO "MM%d: CSR 0x%08lx -> 0x%p (0x%lx)\n", card->card_number,
- card->csr_base, card->csr_remap, card->csr_len);
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "CSR 0x%08lx -> 0x%p (0x%lx)\n",
+ csr_base, card->csr_remap, csr_len);
switch(card->dev->device) {
case 0x5415:
@@ -915,7 +938,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
}
if (readb(card->csr_remap + MEMCTRLSTATUS_MAGIC) != magic_number) {
- printk(KERN_ERR "MM%d: Magic number invalid\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev, "Magic number invalid\n");
ret = -ENOMEM;
goto failed_magic;
}
@@ -928,7 +951,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
&card->mm_pages[1].page_dma);
if (card->mm_pages[0].desc == NULL ||
card->mm_pages[1].desc == NULL) {
- printk(KERN_ERR "MM%d: alloc failed\n", card->card_number);
+ dev_printk(KERN_ERR, &card->dev->dev, "alloc failed\n");
goto failed_alloc;
}
reset_page(&card->mm_pages[0]);
@@ -949,7 +972,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
tasklet_init(&card->tasklet, process_page, (unsigned long)card);
card->check_batteries = 0;
-
+
mem_present = readb(card->csr_remap + MEMCTRLSTATUS_MEMORY);
switch (mem_present) {
case MEM_128_MB:
@@ -982,12 +1005,13 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
card->battery[1].good = !(batt_status & BATTERY_2_FAILURE);
card->battery[0].last_change = card->battery[1].last_change = jiffies;
- if (card->flags & UM_FLAG_NO_BATT)
- printk(KERN_INFO "MM%d: Size %d KB\n",
- card->card_number, card->mm_size);
+ if (card->flags & UM_FLAG_NO_BATT)
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "Size %d KB\n", card->mm_size);
else {
- printk(KERN_INFO "MM%d: Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n",
- card->card_number, card->mm_size,
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n",
+ card->mm_size,
(batt_status & BATTERY_1_DISABLED ? "Disabled" : "Enabled"),
card->battery[0].good ? "OK" : "FAILURE",
(batt_status & BATTERY_2_DISABLED ? "Disabled" : "Enabled"),
@@ -1005,19 +1029,16 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
data = ~data;
data += 1;
- card->win_size = data;
-
-
- if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, "pci-umem", card)) {
- printk(KERN_ERR "MM%d: Unable to allocate IRQ\n", card->card_number);
+ if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, DRIVER_NAME, card)) {
+ dev_printk(KERN_ERR, &card->dev->dev,
+ "Unable to allocate IRQ\n");
ret = -ENODEV;
goto failed_req_irq;
}
- card->irq = dev->irq;
- printk(KERN_INFO "MM%d: Window size %d bytes, IRQ %d\n", card->card_number,
- card->win_size, card->irq);
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "Window size %d bytes, IRQ %d\n", data, dev->irq);
spin_lock_init(&card->lock);
@@ -1037,10 +1058,12 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
num_cards++;
if (!get_userbit(card, MEMORY_INITIALIZED)) {
- printk(KERN_INFO "MM%d: memory NOT initialized. Consider over-writing whole device.\n", card->card_number);
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "memory NOT initialized. Consider over-writing whole device.\n");
card->init_size = 0;
} else {
- printk(KERN_INFO "MM%d: memory already initialized\n", card->card_number);
+ dev_printk(KERN_INFO, &card->dev->dev,
+ "memory already initialized\n");
card->init_size = card->mm_size;
}
@@ -1062,7 +1085,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
failed_magic:
iounmap(card->csr_remap);
failed_remap_csr:
- release_mem_region(card->csr_base, card->csr_len);
+ pci_release_regions(dev);
failed_req_csr:
return ret;
@@ -1077,9 +1100,8 @@ static void mm_pci_remove(struct pci_dev *dev)
struct cardinfo *card = pci_get_drvdata(dev);
tasklet_kill(&card->tasklet);
+ free_irq(dev->irq, card);
iounmap(card->csr_remap);
- release_mem_region(card->csr_base, card->csr_len);
- free_irq(card->irq, card);
if (card->mm_pages[0].desc)
pci_free_consistent(card->dev, PAGE_SIZE*2,
@@ -1090,6 +1112,9 @@ static void mm_pci_remove(struct pci_dev *dev)
card->mm_pages[1].desc,
card->mm_pages[1].page_dma);
blk_cleanup_queue(card->queue);
+
+ pci_release_regions(dev);
+ pci_disable_device(dev);
}
static const struct pci_device_id mm_pci_ids[] = {
@@ -1109,11 +1134,12 @@ static const struct pci_device_id mm_pci_ids[] = {
MODULE_DEVICE_TABLE(pci, mm_pci_ids);
static struct pci_driver mm_pci_driver = {
- .name = "umem",
- .id_table = mm_pci_ids,
- .probe = mm_pci_probe,
- .remove = mm_pci_remove,
+ .name = DRIVER_NAME,
+ .id_table = mm_pci_ids,
+ .probe = mm_pci_probe,
+ .remove = mm_pci_remove,
};
+
/*
-----------------------------------------------------------------------------------
-- mm_init
@@ -1125,13 +1151,11 @@ static int __init mm_init(void)
int retval, i;
int err;
- printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n");
-
retval = pci_register_driver(&mm_pci_driver);
if (retval)
return -ENOMEM;
- err = major_nr = register_blkdev(0, "umem");
+ err = major_nr = register_blkdev(0, DRIVER_NAME);
if (err < 0) {
pci_unregister_driver(&mm_pci_driver);
return -EIO;
@@ -1157,13 +1181,13 @@ static int __init mm_init(void)
}
init_battery_timer();
- printk("MM: desc_per_page = %ld\n", DESC_PER_PAGE);
+ printk(KERN_INFO "MM: desc_per_page = %ld\n", DESC_PER_PAGE);
/* printk("mm_init: Done. 10-19-01 9:00\n"); */
return 0;
out:
pci_unregister_driver(&mm_pci_driver);
- unregister_blkdev(major_nr, "umem");
+ unregister_blkdev(major_nr, DRIVER_NAME);
while (i--)
put_disk(mm_gendisk[i]);
return -ENOMEM;
@@ -1186,7 +1210,7 @@ static void __exit mm_cleanup(void)
pci_unregister_driver(&mm_pci_driver);
- unregister_blkdev(major_nr, "umem");
+ unregister_blkdev(major_nr, DRIVER_NAME);
}
module_init(mm_init);
diff --git a/drivers/block/umem.h b/drivers/block/umem.h
new file mode 100644
index 00000000000..375c68974c9
--- /dev/null
+++ b/drivers/block/umem.h
@@ -0,0 +1,133 @@
+
+/*
+ * This file contains defines for the
+ * Micro Memory MM5415
+ * family PCI Memory Module with Battery Backup.
+ *
+ * Copyright Micro Memory INC 2001. All rights reserved.
+ * Release under the terms of the GNU GENERAL PUBLIC LICENSE version 2.
+ * See the file COPYING.
+ */
+
+#ifndef _DRIVERS_BLOCK_MM_H
+#define _DRIVERS_BLOCK_MM_H
+
+
+#define IRQ_TIMEOUT (1 * HZ)
+
+/* CSR register definition */
+#define MEMCTRLSTATUS_MAGIC 0x00
+#define MM_MAGIC_VALUE (unsigned char)0x59
+
+#define MEMCTRLSTATUS_BATTERY 0x04
+#define BATTERY_1_DISABLED 0x01
+#define BATTERY_1_FAILURE 0x02
+#define BATTERY_2_DISABLED 0x04
+#define BATTERY_2_FAILURE 0x08
+
+#define MEMCTRLSTATUS_MEMORY 0x07
+#define MEM_128_MB 0xfe
+#define MEM_256_MB 0xfc
+#define MEM_512_MB 0xf8
+#define MEM_1_GB 0xf0
+#define MEM_2_GB 0xe0
+
+#define MEMCTRLCMD_LEDCTRL 0x08
+#define LED_REMOVE 2
+#define LED_FAULT 4
+#define LED_POWER 6
+#define LED_FLIP 255
+#define LED_OFF 0x00
+#define LED_ON 0x01
+#define LED_FLASH_3_5 0x02
+#define LED_FLASH_7_0 0x03
+#define LED_POWER_ON 0x00
+#define LED_POWER_OFF 0x01
+#define USER_BIT1 0x01
+#define USER_BIT2 0x02
+
+#define MEMORY_INITIALIZED USER_BIT1
+
+#define MEMCTRLCMD_ERRCTRL 0x0C
+#define EDC_NONE_DEFAULT 0x00
+#define EDC_NONE 0x01
+#define EDC_STORE_READ 0x02
+#define EDC_STORE_CORRECT 0x03
+
+#define MEMCTRLCMD_ERRCNT 0x0D
+#define MEMCTRLCMD_ERRSTATUS 0x0E
+
+#define ERROR_DATA_LOG 0x20
+#define ERROR_ADDR_LOG 0x28
+#define ERROR_COUNT 0x3D
+#define ERROR_SYNDROME 0x3E
+#define ERROR_CHECK 0x3F
+
+#define DMA_PCI_ADDR 0x40
+#define DMA_LOCAL_ADDR 0x48
+#define DMA_TRANSFER_SIZE 0x50
+#define DMA_DESCRIPTOR_ADDR 0x58
+#define DMA_SEMAPHORE_ADDR 0x60
+#define DMA_STATUS_CTRL 0x68
+#define DMASCR_GO 0x00001
+#define DMASCR_TRANSFER_READ 0x00002
+#define DMASCR_CHAIN_EN 0x00004
+#define DMASCR_SEM_EN 0x00010
+#define DMASCR_DMA_COMP_EN 0x00020
+#define DMASCR_CHAIN_COMP_EN 0x00040
+#define DMASCR_ERR_INT_EN 0x00080
+#define DMASCR_PARITY_INT_EN 0x00100
+#define DMASCR_ANY_ERR 0x00800
+#define DMASCR_MBE_ERR 0x01000
+#define DMASCR_PARITY_ERR_REP 0x02000
+#define DMASCR_PARITY_ERR_DET 0x04000
+#define DMASCR_SYSTEM_ERR_SIG 0x08000
+#define DMASCR_TARGET_ABT 0x10000
+#define DMASCR_MASTER_ABT 0x20000
+#define DMASCR_DMA_COMPLETE 0x40000
+#define DMASCR_CHAIN_COMPLETE 0x80000
+
+/*
+3.SOME PCs HAVE HOST BRIDGES WHICH APPARENTLY DO NOT CORRECTLY HANDLE
+READ-LINE (0xE) OR READ-MULTIPLE (0xC) PCI COMMAND CODES DURING DMA
+TRANSFERS. IN OTHER SYSTEMS THESE COMMAND CODES WILL CAUSE THE HOST BRIDGE
+TO ALLOW LONGER BURSTS DURING DMA READ OPERATIONS. THE UPPER FOUR BITS
+(31..28) OF THE DMA CSR HAVE BEEN MADE PROGRAMMABLE, SO THAT EITHER A 0x6,
+AN 0xE OR A 0xC CAN BE WRITTEN TO THEM TO SET THE COMMAND CODE USED DURING
+DMA READ OPERATIONS.
+*/
+#define DMASCR_READ 0x60000000
+#define DMASCR_READLINE 0xE0000000
+#define DMASCR_READMULTI 0xC0000000
+
+
+#define DMASCR_ERROR_MASK (DMASCR_MASTER_ABT | DMASCR_TARGET_ABT | DMASCR_SYSTEM_ERR_SIG | DMASCR_PARITY_ERR_DET | DMASCR_MBE_ERR | DMASCR_ANY_ERR)
+#define DMASCR_HARD_ERROR (DMASCR_MASTER_ABT | DMASCR_TARGET_ABT | DMASCR_SYSTEM_ERR_SIG | DMASCR_PARITY_ERR_DET | DMASCR_MBE_ERR)
+
+#define WINDOWMAP_WINNUM 0x7B
+
+#define DMA_READ_FROM_HOST 0
+#define DMA_WRITE_TO_HOST 1
+
+struct mm_dma_desc {
+ __le64 pci_addr;
+ __le64 local_addr;
+ __le32 transfer_size;
+ u32 zero1;
+ __le64 next_desc_addr;
+ __le64 sem_addr;
+ __le32 control_bits;
+ u32 zero2;
+
+ dma_addr_t data_dma_handle;
+
+ /* Copy of the bits */
+ __le64 sem_control_bits;
+} __attribute__((aligned(8)));
+
+/* bits for card->flags */
+#define UM_FLAG_DMA_IN_REGS 1
+#define UM_FLAG_NO_BYTE_STATUS 2
+#define UM_FLAG_NO_BATTREG 4
+#define UM_FLAG_NO_BATT 8
+#endif
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
index af3969a9c96..ab5d404faa1 100644
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -41,6 +41,7 @@
#include <linux/dma-mapping.h>
#include <linux/completion.h>
#include <linux/device.h>
+#include <linux/scatterlist.h>
#include <asm/uaccess.h>
#include <asm/vio.h>
@@ -74,53 +75,9 @@ enum {
static DEFINE_SPINLOCK(viodasd_spinlock);
#define VIOMAXREQ 16
-#define VIOMAXBLOCKDMA 12
#define DEVICE_NO(cell) ((struct viodasd_device *)(cell) - &viodasd_devices[0])
-struct open_data {
- u64 disk_size;
- u16 max_disk;
- u16 cylinders;
- u16 tracks;
- u16 sectors;
- u16 bytes_per_sector;
-};
-
-struct rw_data {
- u64 offset;
- struct {
- u32 token;
- u32 reserved;
- u64 len;
- } dma_info[VIOMAXBLOCKDMA];
-};
-
-struct vioblocklpevent {
- struct HvLpEvent event;
- u32 reserved;
- u16 version;
- u16 sub_result;
- u16 disk;
- u16 flags;
- union {
- struct open_data open_data;
- struct rw_data rw_data;
- u64 changed;
- } u;
-};
-
-#define vioblockflags_ro 0x0001
-
-enum vioblocksubtype {
- vioblockopen = 0x0001,
- vioblockclose = 0x0002,
- vioblockread = 0x0003,
- vioblockwrite = 0x0004,
- vioblockflush = 0x0005,
- vioblockcheck = 0x0007
-};
-
struct viodasd_waitevent {
struct completion com;
int rc;
@@ -314,6 +271,7 @@ static int send_request(struct request *req)
d = req->rq_disk->private_data;
/* Now build the scatter-gather list */
+ sg_init_table(sg, VIOMAXBLOCKDMA);
nsg = blk_rq_map_sg(req->q, req, sg);
nsg = dma_map_sg(d->dev, sg, nsg, direction);
@@ -429,7 +387,7 @@ static void do_viodasd_request(struct request_queue *q)
* Probe a single disk and fill in the viodasd_device structure
* for it.
*/
-static void probe_disk(struct viodasd_device *d)
+static int probe_disk(struct viodasd_device *d)
{
HvLpEvent_Rc hvrc;
struct viodasd_waitevent we;
@@ -453,14 +411,14 @@ retry:
0, 0, 0);
if (hvrc != 0) {
printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc);
- return;
+ return 0;
}
wait_for_completion(&we.com);
if (we.rc != 0) {
if (flags != 0)
- return;
+ return 0;
/* try again with read only flag set */
flags = vioblockflags_ro;
goto retry;
@@ -490,15 +448,32 @@ retry:
if (hvrc != 0) {
printk(VIOD_KERN_WARNING
"bad rc sending event to OS/400 %d\n", (int)hvrc);
- return;
+ return 0;
}
+
+ if (d->dev == NULL) {
+ /* this is when we reprobe for new disks */
+ if (vio_create_viodasd(dev_no) == NULL) {
+ printk(VIOD_KERN_WARNING
+ "cannot allocate virtual device for disk %d\n",
+ dev_no);
+ return 0;
+ }
+ /*
+ * The vio_create_viodasd will have recursed into this
+ * routine with d->dev set to the new vio device and
+ * will finish the setup of the disk below.
+ */
+ return 1;
+ }
+
/* create the request queue for the disk */
spin_lock_init(&d->q_lock);
q = blk_init_queue(do_viodasd_request, &d->q_lock);
if (q == NULL) {
printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n",
dev_no);
- return;
+ return 0;
}
g = alloc_disk(1 << PARTITION_SHIFT);
if (g == NULL) {
@@ -506,7 +481,7 @@ retry:
"cannot allocate disk structure for disk %d\n",
dev_no);
blk_cleanup_queue(q);
- return;
+ return 0;
}
d->disk = g;
@@ -538,6 +513,7 @@ retry:
/* register us in the global list */
add_disk(g);
+ return 1;
}
/* returns the total number of scatterlist elements converted */
@@ -718,8 +694,7 @@ static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
struct viodasd_device *d = &viodasd_devices[vdev->unit_address];
d->dev = &vdev->dev;
- probe_disk(d);
- if (d->disk == NULL)
+ if (!probe_disk(d))
return -ENODEV;
return 0;
}
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
new file mode 100644
index 00000000000..3cf7129d83e
--- /dev/null
+++ b/drivers/block/virtio_blk.c
@@ -0,0 +1,310 @@
+//#define DEBUG
+#include <linux/spinlock.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/virtio.h>
+#include <linux/virtio_blk.h>
+#include <linux/scatterlist.h>
+
+#define VIRTIO_MAX_SG (3+MAX_PHYS_SEGMENTS)
+
+static unsigned char virtblk_index = 'a';
+struct virtio_blk
+{
+ spinlock_t lock;
+
+ struct virtio_device *vdev;
+ struct virtqueue *vq;
+
+ /* The disk structure for the kernel. */
+ struct gendisk *disk;
+
+ /* Request tracking. */
+ struct list_head reqs;
+
+ mempool_t *pool;
+
+ /* Scatterlist: can be too big for stack. */
+ struct scatterlist sg[VIRTIO_MAX_SG];
+};
+
+struct virtblk_req
+{
+ struct list_head list;
+ struct request *req;
+ struct virtio_blk_outhdr out_hdr;
+ struct virtio_blk_inhdr in_hdr;
+};
+
+static bool blk_done(struct virtqueue *vq)
+{
+ struct virtio_blk *vblk = vq->vdev->priv;
+ struct virtblk_req *vbr;
+ unsigned int len;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vblk->lock, flags);
+ while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
+ int uptodate;
+ switch (vbr->in_hdr.status) {
+ case VIRTIO_BLK_S_OK:
+ uptodate = 1;
+ break;
+ case VIRTIO_BLK_S_UNSUPP:
+ uptodate = -ENOTTY;
+ break;
+ default:
+ uptodate = 0;
+ break;
+ }
+
+ end_dequeued_request(vbr->req, uptodate);
+ list_del(&vbr->list);
+ mempool_free(vbr, vblk->pool);
+ }
+ /* In case queue is stopped waiting for more buffers. */
+ blk_start_queue(vblk->disk->queue);
+ spin_unlock_irqrestore(&vblk->lock, flags);
+ return true;
+}
+
+static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
+ struct request *req)
+{
+ unsigned long num, out, in;
+ struct virtblk_req *vbr;
+
+ vbr = mempool_alloc(vblk->pool, GFP_ATOMIC);
+ if (!vbr)
+ /* When another request finishes we'll try again. */
+ return false;
+
+ vbr->req = req;
+ if (blk_fs_request(vbr->req)) {
+ vbr->out_hdr.type = 0;
+ vbr->out_hdr.sector = vbr->req->sector;
+ vbr->out_hdr.ioprio = vbr->req->ioprio;
+ } else if (blk_pc_request(vbr->req)) {
+ vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD;
+ vbr->out_hdr.sector = 0;
+ vbr->out_hdr.ioprio = vbr->req->ioprio;
+ } else {
+ /* We don't put anything else in the queue. */
+ BUG();
+ }
+
+ if (blk_barrier_rq(vbr->req))
+ vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER;
+
+ /* This init could be done at vblk creation time */
+ sg_init_table(vblk->sg, VIRTIO_MAX_SG);
+ sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr));
+ num = blk_rq_map_sg(q, vbr->req, vblk->sg+1);
+ sg_set_buf(&vblk->sg[num+1], &vbr->in_hdr, sizeof(vbr->in_hdr));
+
+ if (rq_data_dir(vbr->req) == WRITE) {
+ vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
+ out = 1 + num;
+ in = 1;
+ } else {
+ vbr->out_hdr.type |= VIRTIO_BLK_T_IN;
+ out = 1;
+ in = 1 + num;
+ }
+
+ if (vblk->vq->vq_ops->add_buf(vblk->vq, vblk->sg, out, in, vbr)) {
+ mempool_free(vbr, vblk->pool);
+ return false;
+ }
+
+ list_add_tail(&vbr->list, &vblk->reqs);
+ return true;
+}
+
+static void do_virtblk_request(struct request_queue *q)
+{
+ struct virtio_blk *vblk = NULL;
+ struct request *req;
+ unsigned int issued = 0;
+
+ while ((req = elv_next_request(q)) != NULL) {
+ vblk = req->rq_disk->private_data;
+ BUG_ON(req->nr_phys_segments > ARRAY_SIZE(vblk->sg));
+
+ /* If this request fails, stop queue and wait for something to
+ finish to restart it. */
+ if (!do_req(q, vblk, req)) {
+ blk_stop_queue(q);
+ break;
+ }
+ blkdev_dequeue_request(req);
+ issued++;
+ }
+
+ if (issued)
+ vblk->vq->vq_ops->kick(vblk->vq);
+}
+
+static int virtblk_ioctl(struct inode *inode, struct file *filp,
+ unsigned cmd, unsigned long data)
+{
+ return scsi_cmd_ioctl(filp, inode->i_bdev->bd_disk->queue,
+ inode->i_bdev->bd_disk, cmd,
+ (void __user *)data);
+}
+
+static struct block_device_operations virtblk_fops = {
+ .ioctl = virtblk_ioctl,
+ .owner = THIS_MODULE,
+};
+
+static int virtblk_probe(struct virtio_device *vdev)
+{
+ struct virtio_blk *vblk;
+ int err, major;
+ void *token;
+ unsigned int len;
+ u64 cap;
+ u32 v;
+
+ vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
+ if (!vblk) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ INIT_LIST_HEAD(&vblk->reqs);
+ spin_lock_init(&vblk->lock);
+ vblk->vdev = vdev;
+
+ /* We expect one virtqueue, for output. */
+ vblk->vq = vdev->config->find_vq(vdev, blk_done);
+ if (IS_ERR(vblk->vq)) {
+ err = PTR_ERR(vblk->vq);
+ goto out_free_vblk;
+ }
+
+ vblk->pool = mempool_create_kmalloc_pool(1,sizeof(struct virtblk_req));
+ if (!vblk->pool) {
+ err = -ENOMEM;
+ goto out_free_vq;
+ }
+
+ major = register_blkdev(0, "virtblk");
+ if (major < 0) {
+ err = major;
+ goto out_mempool;
+ }
+
+ /* FIXME: How many partitions? How long is a piece of string? */
+ vblk->disk = alloc_disk(1 << 4);
+ if (!vblk->disk) {
+ err = -ENOMEM;
+ goto out_unregister_blkdev;
+ }
+
+ vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
+ if (!vblk->disk->queue) {
+ err = -ENOMEM;
+ goto out_put_disk;
+ }
+
+ sprintf(vblk->disk->disk_name, "vd%c", virtblk_index++);
+ vblk->disk->major = major;
+ vblk->disk->first_minor = 0;
+ vblk->disk->private_data = vblk;
+ vblk->disk->fops = &virtblk_fops;
+
+ /* If barriers are supported, tell block layer that queue is ordered */
+ token = vdev->config->find(vdev, VIRTIO_CONFIG_BLK_F, &len);
+ if (virtio_use_bit(vdev, token, len, VIRTIO_BLK_F_BARRIER))
+ blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
+
+ err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_CAPACITY, &cap);
+ if (err) {
+ dev_err(&vdev->dev, "Bad/missing capacity in config\n");
+ goto out_put_disk;
+ }
+
+ /* If capacity is too big, truncate with warning. */
+ if ((sector_t)cap != cap) {
+ dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n",
+ (unsigned long long)cap);
+ cap = (sector_t)-1;
+ }
+ set_capacity(vblk->disk, cap);
+
+ err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SIZE_MAX, &v);
+ if (!err)
+ blk_queue_max_segment_size(vblk->disk->queue, v);
+ else if (err != -ENOENT) {
+ dev_err(&vdev->dev, "Bad SIZE_MAX in config\n");
+ goto out_put_disk;
+ }
+
+ err = virtio_config_val(vdev, VIRTIO_CONFIG_BLK_F_SEG_MAX, &v);
+ if (!err)
+ blk_queue_max_hw_segments(vblk->disk->queue, v);
+ else if (err != -ENOENT) {
+ dev_err(&vdev->dev, "Bad SEG_MAX in config\n");
+ goto out_put_disk;
+ }
+
+ add_disk(vblk->disk);
+ return 0;
+
+out_put_disk:
+ put_disk(vblk->disk);
+out_unregister_blkdev:
+ unregister_blkdev(major, "virtblk");
+out_mempool:
+ mempool_destroy(vblk->pool);
+out_free_vq:
+ vdev->config->del_vq(vblk->vq);
+out_free_vblk:
+ kfree(vblk);
+out:
+ return err;
+}
+
+static void virtblk_remove(struct virtio_device *vdev)
+{
+ struct virtio_blk *vblk = vdev->priv;
+ int major = vblk->disk->major;
+
+ BUG_ON(!list_empty(&vblk->reqs));
+ blk_cleanup_queue(vblk->disk->queue);
+ put_disk(vblk->disk);
+ unregister_blkdev(major, "virtblk");
+ mempool_destroy(vblk->pool);
+ kfree(vblk);
+}
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static struct virtio_driver virtio_blk = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = virtblk_probe,
+ .remove = __devexit_p(virtblk_remove),
+};
+
+static int __init init(void)
+{
+ return register_virtio_driver(&virtio_blk);
+}
+
+static void __exit fini(void)
+{
+ unregister_virtio_driver(&virtio_blk);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio block driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 964e51634f2..2bdebcb3ff1 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -150,9 +150,8 @@ static int blkif_queue_request(struct request *req)
struct blkfront_info *info = req->rq_disk->private_data;
unsigned long buffer_mfn;
struct blkif_request *ring_req;
- struct bio *bio;
+ struct req_iterator iter;
struct bio_vec *bvec;
- int idx;
unsigned long id;
unsigned int fsect, lsect;
int ref;
@@ -186,34 +185,31 @@ static int blkif_queue_request(struct request *req)
ring_req->operation = BLKIF_OP_WRITE_BARRIER;
ring_req->nr_segments = 0;
- rq_for_each_bio (bio, req) {
- bio_for_each_segment (bvec, bio, idx) {
- BUG_ON(ring_req->nr_segments
- == BLKIF_MAX_SEGMENTS_PER_REQUEST);
- buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page));
- fsect = bvec->bv_offset >> 9;
- lsect = fsect + (bvec->bv_len >> 9) - 1;
- /* install a grant reference. */
- ref = gnttab_claim_grant_reference(&gref_head);
- BUG_ON(ref == -ENOSPC);
-
- gnttab_grant_foreign_access_ref(
+ rq_for_each_segment(bvec, req, iter) {
+ BUG_ON(ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page));
+ fsect = bvec->bv_offset >> 9;
+ lsect = fsect + (bvec->bv_len >> 9) - 1;
+ /* install a grant reference. */
+ ref = gnttab_claim_grant_reference(&gref_head);
+ BUG_ON(ref == -ENOSPC);
+
+ gnttab_grant_foreign_access_ref(
ref,
info->xbdev->otherend_id,
buffer_mfn,
rq_data_dir(req) );
- info->shadow[id].frame[ring_req->nr_segments] =
+ info->shadow[id].frame[ring_req->nr_segments] =
mfn_to_pfn(buffer_mfn);
- ring_req->seg[ring_req->nr_segments] =
+ ring_req->seg[ring_req->nr_segments] =
(struct blkif_request_segment) {
.gref = ref,
.first_sect = fsect,
.last_sect = lsect };
- ring_req->nr_segments++;
- }
+ ring_req->nr_segments++;
}
info->ring.req_prod_pvt++;
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index 3ede0b63da1..82effce97c5 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -91,6 +91,10 @@
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/platform_device.h>
+#if defined(CONFIG_OF)
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#endif
MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
MODULE_DESCRIPTION("Xilinx SystemACE device driver");
@@ -158,6 +162,9 @@ MODULE_LICENSE("GPL");
#define ACE_FIFO_SIZE (32)
#define ACE_BUF_PER_SECTOR (ACE_SECTOR_SIZE / ACE_FIFO_SIZE)
+#define ACE_BUS_WIDTH_8 0
+#define ACE_BUS_WIDTH_16 1
+
struct ace_reg_ops;
struct ace_device {
@@ -188,7 +195,7 @@ struct ace_device {
/* Details of hardware device */
unsigned long physaddr;
- void *baseaddr;
+ void __iomem *baseaddr;
int irq;
int bus_width; /* 0 := 8 bit; 1 := 16 bit */
struct ace_reg_ops *reg_ops;
@@ -220,20 +227,20 @@ struct ace_reg_ops {
/* 8 Bit bus width */
static u16 ace_in_8(struct ace_device *ace, int reg)
{
- void *r = ace->baseaddr + reg;
+ void __iomem *r = ace->baseaddr + reg;
return in_8(r) | (in_8(r + 1) << 8);
}
static void ace_out_8(struct ace_device *ace, int reg, u16 val)
{
- void *r = ace->baseaddr + reg;
+ void __iomem *r = ace->baseaddr + reg;
out_8(r, val);
out_8(r + 1, val >> 8);
}
static void ace_datain_8(struct ace_device *ace)
{
- void *r = ace->baseaddr + 0x40;
+ void __iomem *r = ace->baseaddr + 0x40;
u8 *dst = ace->data_ptr;
int i = ACE_FIFO_SIZE;
while (i--)
@@ -243,7 +250,7 @@ static void ace_datain_8(struct ace_device *ace)
static void ace_dataout_8(struct ace_device *ace)
{
- void *r = ace->baseaddr + 0x40;
+ void __iomem *r = ace->baseaddr + 0x40;
u8 *src = ace->data_ptr;
int i = ACE_FIFO_SIZE;
while (i--)
@@ -383,8 +390,8 @@ static inline void ace_dump_mem(void *base, int len)
static void ace_dump_regs(struct ace_device *ace)
{
dev_info(ace->dev, " ctrl: %.8x seccnt/cmd: %.4x ver:%.4x\n"
- " status:%.8x mpu_lba:%.8x busmode:%4x\n"
- " error: %.8x cfg_lba:%.8x fatstat:%.4x\n",
+ KERN_INFO " status:%.8x mpu_lba:%.8x busmode:%4x\n"
+ KERN_INFO " error: %.8x cfg_lba:%.8x fatstat:%.4x\n",
ace_in32(ace, ACE_CTRL),
ace_in(ace, ACE_SECCNTCMD),
ace_in(ace, ACE_VERSION),
@@ -931,9 +938,11 @@ static int __devinit ace_setup(struct ace_device *ace)
{
u16 version;
u16 val;
-
int rc;
+ dev_dbg(ace->dev, "ace_setup(ace=0x%p)\n", ace);
+ dev_dbg(ace->dev, "physaddr=0x%lx irq=%i\n", ace->physaddr, ace->irq);
+
spin_lock_init(&ace->lock);
init_completion(&ace->id_completion);
@@ -944,15 +953,6 @@ static int __devinit ace_setup(struct ace_device *ace)
if (!ace->baseaddr)
goto err_ioremap;
- if (ace->irq != NO_IRQ) {
- rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace);
- if (rc) {
- /* Failure - fall back to polled mode */
- dev_err(ace->dev, "request_irq failed\n");
- ace->irq = NO_IRQ;
- }
- }
-
/*
* Initialize the state machine tasklet and stall timer
*/
@@ -982,7 +982,7 @@ static int __devinit ace_setup(struct ace_device *ace)
snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a');
/* set bus width */
- if (ace->bus_width == 1) {
+ if (ace->bus_width == ACE_BUS_WIDTH_16) {
/* 0x0101 should work regardless of endianess */
ace_out_le16(ace, ACE_BUSMODE, 0x0101);
@@ -1005,6 +1005,16 @@ static int __devinit ace_setup(struct ace_device *ace)
ace_out(ace, ACE_CTRL, ACE_CTRL_FORCECFGMODE |
ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ);
+ /* Now we can hook up the irq handler */
+ if (ace->irq != NO_IRQ) {
+ rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace);
+ if (rc) {
+ /* Failure - fall back to polled mode */
+ dev_err(ace->dev, "request_irq failed\n");
+ ace->irq = NO_IRQ;
+ }
+ }
+
/* Enable interrupts */
val = ace_in(ace, ACE_CTRL);
val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ;
@@ -1024,16 +1034,14 @@ static int __devinit ace_setup(struct ace_device *ace)
return 0;
- err_read:
+err_read:
put_disk(ace->gd);
- err_alloc_disk:
+err_alloc_disk:
blk_cleanup_queue(ace->queue);
- err_blk_initq:
+err_blk_initq:
iounmap(ace->baseaddr);
- if (ace->irq != NO_IRQ)
- free_irq(ace->irq, ace);
- err_ioremap:
- printk(KERN_INFO "xsysace: error initializing device at 0x%lx\n",
+err_ioremap:
+ dev_info(ace->dev, "xsysace: error initializing device at 0x%lx\n",
ace->physaddr);
return -ENOMEM;
}
@@ -1056,98 +1064,222 @@ static void __devexit ace_teardown(struct ace_device *ace)
iounmap(ace->baseaddr);
}
-/* ---------------------------------------------------------------------
- * Platform Bus Support
- */
-
-static int __devinit ace_probe(struct device *device)
+static int __devinit
+ace_alloc(struct device *dev, int id, unsigned long physaddr,
+ int irq, int bus_width)
{
- struct platform_device *dev = to_platform_device(device);
struct ace_device *ace;
- int i;
+ int rc;
+ dev_dbg(dev, "ace_alloc(%p)\n", dev);
- dev_dbg(device, "ace_probe(%p)\n", device);
+ if (!physaddr) {
+ rc = -ENODEV;
+ goto err_noreg;
+ }
- /*
- * Allocate the ace device structure
- */
+ /* Allocate and initialize the ace device structure */
ace = kzalloc(sizeof(struct ace_device), GFP_KERNEL);
- if (!ace)
+ if (!ace) {
+ rc = -ENOMEM;
goto err_alloc;
-
- ace->dev = device;
- ace->id = dev->id;
- ace->irq = NO_IRQ;
-
- for (i = 0; i < dev->num_resources; i++) {
- if (dev->resource[i].flags & IORESOURCE_MEM)
- ace->physaddr = dev->resource[i].start;
- if (dev->resource[i].flags & IORESOURCE_IRQ)
- ace->irq = dev->resource[i].start;
}
- /* FIXME: Should get bus_width from the platform_device struct */
- ace->bus_width = 1;
-
- dev_set_drvdata(&dev->dev, ace);
+ ace->dev = dev;
+ ace->id = id;
+ ace->physaddr = physaddr;
+ ace->irq = irq;
+ ace->bus_width = bus_width;
- /* Call the bus-independant setup code */
- if (ace_setup(ace) != 0)
+ /* Call the setup code */
+ rc = ace_setup(ace);
+ if (rc)
goto err_setup;
+ dev_set_drvdata(dev, ace);
return 0;
- err_setup:
- dev_set_drvdata(&dev->dev, NULL);
+err_setup:
+ dev_set_drvdata(dev, NULL);
kfree(ace);
- err_alloc:
- printk(KERN_ERR "xsysace: could not initialize device\n");
- return -ENOMEM;
+err_alloc:
+err_noreg:
+ dev_err(dev, "could not initialize device, err=%i\n", rc);
+ return rc;
}
-/*
- * Platform bus remove() method
- */
-static int __devexit ace_remove(struct device *device)
+static void __devexit ace_free(struct device *dev)
{
- struct ace_device *ace = dev_get_drvdata(device);
-
- dev_dbg(device, "ace_remove(%p)\n", device);
+ struct ace_device *ace = dev_get_drvdata(dev);
+ dev_dbg(dev, "ace_free(%p)\n", dev);
if (ace) {
ace_teardown(ace);
+ dev_set_drvdata(dev, NULL);
kfree(ace);
}
+}
+
+/* ---------------------------------------------------------------------
+ * Platform Bus Support
+ */
+
+static int __devinit ace_probe(struct platform_device *dev)
+{
+ unsigned long physaddr = 0;
+ int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */
+ int id = dev->id;
+ int irq = NO_IRQ;
+ int i;
+ dev_dbg(&dev->dev, "ace_probe(%p)\n", dev);
+
+ for (i = 0; i < dev->num_resources; i++) {
+ if (dev->resource[i].flags & IORESOURCE_MEM)
+ physaddr = dev->resource[i].start;
+ if (dev->resource[i].flags & IORESOURCE_IRQ)
+ irq = dev->resource[i].start;
+ }
+
+ /* Call the bus-independant setup code */
+ return ace_alloc(&dev->dev, id, physaddr, irq, bus_width);
+}
+
+/*
+ * Platform bus remove() method
+ */
+static int __devexit ace_remove(struct platform_device *dev)
+{
+ ace_free(&dev->dev);
return 0;
}
-static struct device_driver ace_driver = {
- .name = "xsysace",
- .bus = &platform_bus_type,
+static struct platform_driver ace_platform_driver = {
.probe = ace_probe,
.remove = __devexit_p(ace_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "xsysace",
+ },
+};
+
+/* ---------------------------------------------------------------------
+ * OF_Platform Bus Support
+ */
+
+#if defined(CONFIG_OF)
+static int __devinit
+ace_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct resource res;
+ unsigned long physaddr;
+ const u32 *id;
+ int irq, bus_width, rc;
+
+ dev_dbg(&op->dev, "ace_of_probe(%p, %p)\n", op, match);
+
+ /* device id */
+ id = of_get_property(op->node, "port-number", NULL);
+
+ /* physaddr */
+ rc = of_address_to_resource(op->node, 0, &res);
+ if (rc) {
+ dev_err(&op->dev, "invalid address\n");
+ return rc;
+ }
+ physaddr = res.start;
+
+ /* irq */
+ irq = irq_of_parse_and_map(op->node, 0);
+
+ /* bus width */
+ bus_width = ACE_BUS_WIDTH_16;
+ if (of_find_property(op->node, "8-bit", NULL))
+ bus_width = ACE_BUS_WIDTH_8;
+
+ /* Call the bus-independant setup code */
+ return ace_alloc(&op->dev, id ? *id : 0, physaddr, irq, bus_width);
+}
+
+static int __devexit ace_of_remove(struct of_device *op)
+{
+ ace_free(&op->dev);
+ return 0;
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id __devinit ace_of_match[] = {
+ { .compatible = "xilinx,xsysace", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ace_of_match);
+
+static struct of_platform_driver ace_of_driver = {
+ .owner = THIS_MODULE,
+ .name = "xsysace",
+ .match_table = ace_of_match,
+ .probe = ace_of_probe,
+ .remove = __devexit_p(ace_of_remove),
+ .driver = {
+ .name = "xsysace",
+ },
};
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __init ace_of_register(void)
+{
+ pr_debug("xsysace: registering OF binding\n");
+ return of_register_platform_driver(&ace_of_driver);
+}
+
+static inline void __exit ace_of_unregister(void)
+{
+ of_unregister_platform_driver(&ace_of_driver);
+}
+#else /* CONFIG_OF */
+/* CONFIG_OF not enabled; do nothing helpers */
+static inline int __init ace_of_register(void) { return 0; }
+static inline void __exit ace_of_unregister(void) { }
+#endif /* CONFIG_OF */
+
/* ---------------------------------------------------------------------
* Module init/exit routines
*/
static int __init ace_init(void)
{
+ int rc;
+
ace_major = register_blkdev(ace_major, "xsysace");
if (ace_major <= 0) {
- printk(KERN_WARNING "xsysace: register_blkdev() failed\n");
- return ace_major;
+ rc = -ENOMEM;
+ goto err_blk;
}
- pr_debug("Registering Xilinx SystemACE driver, major=%i\n", ace_major);
- return driver_register(&ace_driver);
+ rc = ace_of_register();
+ if (rc)
+ goto err_of;
+
+ pr_debug("xsysace: registering platform binding\n");
+ rc = platform_driver_register(&ace_platform_driver);
+ if (rc)
+ goto err_plat;
+
+ pr_info("Xilinx SystemACE device driver, major=%i\n", ace_major);
+ return 0;
+
+err_plat:
+ ace_of_unregister();
+err_of:
+ unregister_blkdev(ace_major, "xsysace");
+err_blk:
+ printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc);
+ return rc;
}
static void __exit ace_exit(void)
{
pr_debug("Unregistering Xilinx SystemACE driver\n");
- driver_unregister(&ace_driver);
+ platform_driver_unregister(&ace_platform_driver);
+ ace_of_unregister();
unregister_blkdev(ace_major, "xsysace");
}
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index b9fbe6e7f9a..075598e1c50 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -22,6 +22,30 @@ config BT_HCIUSB_SCO
Say Y here to compile support for SCO over HCI USB.
+config BT_HCIBTUSB
+ tristate "HCI USB driver (alternate version)"
+ depends on USB && EXPERIMENTAL && BT_HCIUSB=n
+ help
+ Bluetooth HCI USB driver.
+ This driver is required if you want to use Bluetooth devices with
+ USB interface.
+
+ This driver is still experimental and has no SCO support.
+
+ Say Y here to compile support for Bluetooth USB devices into the
+ kernel or say M to compile it as module (btusb).
+
+config BT_HCIBTSDIO
+ tristate "HCI SDIO driver"
+ depends on MMC
+ help
+ Bluetooth HCI SDIO driver.
+ This driver is required if you want to use Bluetooth device with
+ SDIO interface.
+
+ Say Y here to compile support for Bluetooth SDIO devices into the
+ kernel or say M to compile it as module (btsdio).
+
config BT_HCIUART
tristate "HCI UART driver"
help
@@ -55,6 +79,17 @@ config BT_HCIUART_BCSP
Say Y here to compile support for HCI BCSP protocol.
+config BT_HCIUART_LL
+ bool "HCILL protocol support"
+ depends on BT_HCIUART
+ help
+ HCILL (HCI Low Level) is a serial protocol for communication
+ between Bluetooth device and host. This protocol is required for
+ serial Bluetooth devices that are based on Texas Instruments'
+ BRF chips.
+
+ Say Y here to compile support for HCILL protocol.
+
config BT_HCIBCM203X
tristate "HCI BCM203x USB driver"
depends on USB
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 08c10e178e0..77444afbf10 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -13,7 +13,11 @@ obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o
obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o
obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o
+obj-$(CONFIG_BT_HCIBTUSB) += btusb.o
+obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
+
hci_uart-y := hci_ldisc.o
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
+hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
hci_uart-objs := $(hci_uart-y)
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 851de4d5b7d..bcf57927b7a 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -503,10 +503,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
unsigned int iobase;
unsigned char reg;
- if (!info || !info->hdev) {
- BT_ERR("Call of irq %d for unknown device", irq);
- return IRQ_NONE;
- }
+ BUG_ON(!info->hdev);
if (!test_bit(CARD_READY, &(info->hw_state)))
return IRQ_HANDLED;
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index e8ebd5d3de8..1375b5345a0 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -2,7 +2,7 @@
*
* Digianswer Bluetooth USB driver
*
- * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -21,13 +21,14 @@
*
*/
-#include <linux/module.h>
-
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/sched.h>
#include <linux/errno.h>
+#include <linux/skbuff.h>
#include <linux/usb.h>
@@ -39,7 +40,7 @@
#define BT_DBG(D...)
#endif
-#define VERSION "0.8"
+#define VERSION "0.9"
static int ignore = 0;
@@ -52,393 +53,285 @@ static struct usb_device_id bpa10x_table[] = {
MODULE_DEVICE_TABLE(usb, bpa10x_table);
-#define BPA10X_CMD_EP 0x00
-#define BPA10X_EVT_EP 0x81
-#define BPA10X_TX_EP 0x02
-#define BPA10X_RX_EP 0x82
-
-#define BPA10X_CMD_BUF_SIZE 252
-#define BPA10X_EVT_BUF_SIZE 16
-#define BPA10X_TX_BUF_SIZE 384
-#define BPA10X_RX_BUF_SIZE 384
-
struct bpa10x_data {
- struct hci_dev *hdev;
- struct usb_device *udev;
+ struct hci_dev *hdev;
+ struct usb_device *udev;
- rwlock_t lock;
+ struct usb_anchor tx_anchor;
+ struct usb_anchor rx_anchor;
- struct sk_buff_head cmd_queue;
- struct urb *cmd_urb;
- struct urb *evt_urb;
- struct sk_buff *evt_skb;
- unsigned int evt_len;
-
- struct sk_buff_head tx_queue;
- struct urb *tx_urb;
- struct urb *rx_urb;
+ struct sk_buff *rx_skb[2];
};
-#define HCI_VENDOR_HDR_SIZE 5
+#define HCI_VENDOR_HDR_SIZE 5
struct hci_vendor_hdr {
- __u8 type;
- __le16 snum;
- __le16 dlen;
+ __u8 type;
+ __le16 snum;
+ __le16 dlen;
} __attribute__ ((packed));
-static void bpa10x_recv_bulk(struct bpa10x_data *data, unsigned char *buf, int count)
+static int bpa10x_recv(struct hci_dev *hdev, int queue, void *buf, int count)
{
- struct hci_acl_hdr *ah;
- struct hci_sco_hdr *sh;
- struct hci_vendor_hdr *vh;
- struct sk_buff *skb;
- int len;
+ struct bpa10x_data *data = hdev->driver_data;
+
+ BT_DBG("%s queue %d buffer %p count %d", hdev->name,
+ queue, buf, count);
+
+ if (queue < 0 || queue > 1)
+ return -EILSEQ;
+
+ hdev->stat.byte_rx += count;
while (count) {
- switch (*buf++) {
- case HCI_ACLDATA_PKT:
- ah = (struct hci_acl_hdr *) buf;
- len = HCI_ACL_HDR_SIZE + __le16_to_cpu(ah->dlen);
- skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (skb) {
- memcpy(skb_put(skb, len), buf, len);
- skb->dev = (void *) data->hdev;
- bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
- hci_recv_frame(skb);
- }
- break;
+ struct sk_buff *skb = data->rx_skb[queue];
+ struct { __u8 type; int expect; } *scb;
+ int type, len = 0;
- case HCI_SCODATA_PKT:
- sh = (struct hci_sco_hdr *) buf;
- len = HCI_SCO_HDR_SIZE + sh->dlen;
- skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (skb) {
- memcpy(skb_put(skb, len), buf, len);
- skb->dev = (void *) data->hdev;
- bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
- hci_recv_frame(skb);
+ if (!skb) {
+ /* Start of the frame */
+
+ type = *((__u8 *) buf);
+ count--; buf++;
+
+ switch (type) {
+ case HCI_EVENT_PKT:
+ if (count >= HCI_EVENT_HDR_SIZE) {
+ struct hci_event_hdr *h = buf;
+ len = HCI_EVENT_HDR_SIZE + h->plen;
+ } else
+ return -EILSEQ;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ if (count >= HCI_ACL_HDR_SIZE) {
+ struct hci_acl_hdr *h = buf;
+ len = HCI_ACL_HDR_SIZE +
+ __le16_to_cpu(h->dlen);
+ } else
+ return -EILSEQ;
+ break;
+
+ case HCI_SCODATA_PKT:
+ if (count >= HCI_SCO_HDR_SIZE) {
+ struct hci_sco_hdr *h = buf;
+ len = HCI_SCO_HDR_SIZE + h->dlen;
+ } else
+ return -EILSEQ;
+ break;
+
+ case HCI_VENDOR_PKT:
+ if (count >= HCI_VENDOR_HDR_SIZE) {
+ struct hci_vendor_hdr *h = buf;
+ len = HCI_VENDOR_HDR_SIZE +
+ __le16_to_cpu(h->dlen);
+ } else
+ return -EILSEQ;
+ break;
}
- break;
- case HCI_VENDOR_PKT:
- vh = (struct hci_vendor_hdr *) buf;
- len = HCI_VENDOR_HDR_SIZE + __le16_to_cpu(vh->dlen);
skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (skb) {
- memcpy(skb_put(skb, len), buf, len);
- skb->dev = (void *) data->hdev;
- bt_cb(skb)->pkt_type = HCI_VENDOR_PKT;
- hci_recv_frame(skb);
+ if (!skb) {
+ BT_ERR("%s no memory for packet", hdev->name);
+ return -ENOMEM;
}
- break;
-
- default:
- len = count - 1;
- break;
- }
- buf += len;
- count -= (len + 1);
- }
-}
-
-static int bpa10x_recv_event(struct bpa10x_data *data, unsigned char *buf, int size)
-{
- BT_DBG("data %p buf %p size %d", data, buf, size);
+ skb->dev = (void *) hdev;
- if (data->evt_skb) {
- struct sk_buff *skb = data->evt_skb;
+ data->rx_skb[queue] = skb;
- memcpy(skb_put(skb, size), buf, size);
+ scb = (void *) skb->cb;
+ scb->type = type;
+ scb->expect = len;
+ } else {
+ /* Continuation */
- if (skb->len == data->evt_len) {
- data->evt_skb = NULL;
- data->evt_len = 0;
- hci_recv_frame(skb);
- }
- } else {
- struct sk_buff *skb;
- struct hci_event_hdr *hdr;
- unsigned char pkt_type;
- int pkt_len = 0;
-
- if (size < HCI_EVENT_HDR_SIZE + 1) {
- BT_ERR("%s event packet block with size %d is too short",
- data->hdev->name, size);
- return -EILSEQ;
+ scb = (void *) skb->cb;
+ len = scb->expect;
}
- pkt_type = *buf++;
- size--;
-
- if (pkt_type != HCI_EVENT_PKT) {
- BT_ERR("%s unexpected event packet start byte 0x%02x",
- data->hdev->name, pkt_type);
- return -EPROTO;
- }
+ len = min(len, count);
- hdr = (struct hci_event_hdr *) buf;
- pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
+ memcpy(skb_put(skb, len), buf, len);
- skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("%s no memory for new event packet",
- data->hdev->name);
- return -ENOMEM;
- }
+ scb->expect -= len;
- skb->dev = (void *) data->hdev;
- bt_cb(skb)->pkt_type = pkt_type;
+ if (scb->expect == 0) {
+ /* Complete frame */
- memcpy(skb_put(skb, size), buf, size);
+ data->rx_skb[queue] = NULL;
- if (pkt_len == size) {
+ bt_cb(skb)->pkt_type = scb->type;
hci_recv_frame(skb);
- } else {
- data->evt_skb = skb;
- data->evt_len = pkt_len;
}
+
+ count -= len; buf += len;
}
return 0;
}
-static void bpa10x_wakeup(struct bpa10x_data *data)
+static void bpa10x_tx_complete(struct urb *urb)
{
- struct urb *urb;
- struct sk_buff *skb;
- int err;
+ struct sk_buff *skb = urb->context;
+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
- BT_DBG("data %p", data);
+ BT_DBG("%s urb %p status %d count %d", hdev->name,
+ urb, urb->status, urb->actual_length);
- urb = data->cmd_urb;
- if (urb->status == -EINPROGRESS)
- skb = NULL;
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ goto done;
+
+ if (!urb->status)
+ hdev->stat.byte_tx += urb->transfer_buffer_length;
else
- skb = skb_dequeue(&data->cmd_queue);
+ hdev->stat.err_tx++;
- if (skb) {
- struct usb_ctrlrequest *cr;
+done:
+ kfree(urb->setup_packet);
- if (skb->len > BPA10X_CMD_BUF_SIZE) {
- BT_ERR("%s command packet with size %d is too big",
- data->hdev->name, skb->len);
- kfree_skb(skb);
- return;
- }
+ kfree_skb(skb);
+}
+
+static void bpa10x_rx_complete(struct urb *urb)
+{
+ struct hci_dev *hdev = urb->context;
+ struct bpa10x_data *data = hdev->driver_data;
+ int err;
- cr = (struct usb_ctrlrequest *) urb->setup_packet;
- cr->wLength = __cpu_to_le16(skb->len);
+ BT_DBG("%s urb %p status %d count %d", hdev->name,
+ urb, urb->status, urb->actual_length);
- skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len);
- urb->transfer_buffer_length = skb->len;
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return;
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err < 0 && err != -ENODEV) {
- BT_ERR("%s submit failed for command urb %p with error %d",
- data->hdev->name, urb, err);
- skb_queue_head(&data->cmd_queue, skb);
- } else
- kfree_skb(skb);
+ if (urb->status == 0) {
+ if (bpa10x_recv(hdev, usb_pipebulk(urb->pipe),
+ urb->transfer_buffer,
+ urb->actual_length) < 0) {
+ BT_ERR("%s corrupted event packet", hdev->name);
+ hdev->stat.err_rx++;
+ }
}
- urb = data->tx_urb;
- if (urb->status == -EINPROGRESS)
- skb = NULL;
- else
- skb = skb_dequeue(&data->tx_queue);
-
- if (skb) {
- skb_copy_from_linear_data(skb, urb->transfer_buffer, skb->len);
- urb->transfer_buffer_length = skb->len;
-
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err < 0 && err != -ENODEV) {
- BT_ERR("%s submit failed for command urb %p with error %d",
- data->hdev->name, urb, err);
- skb_queue_head(&data->tx_queue, skb);
- } else
- kfree_skb(skb);
+ usb_anchor_urb(urb, &data->rx_anchor);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err < 0) {
+ BT_ERR("%s urb %p failed to resubmit (%d)",
+ hdev->name, urb, -err);
+ usb_unanchor_urb(urb);
}
}
-static void bpa10x_complete(struct urb *urb)
+static inline int bpa10x_submit_intr_urb(struct hci_dev *hdev)
{
- struct bpa10x_data *data = urb->context;
- unsigned char *buf = urb->transfer_buffer;
- int err, count = urb->actual_length;
+ struct bpa10x_data *data = hdev->driver_data;
+ struct urb *urb;
+ unsigned char *buf;
+ unsigned int pipe;
+ int err, size = 16;
- BT_DBG("data %p urb %p buf %p count %d", data, urb, buf, count);
+ BT_DBG("%s", hdev->name);
- read_lock(&data->lock);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return -ENOMEM;
- if (!test_bit(HCI_RUNNING, &data->hdev->flags))
- goto unlock;
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
- if (urb->status < 0 || !count)
- goto resubmit;
+ pipe = usb_rcvintpipe(data->udev, 0x81);
- if (usb_pipein(urb->pipe)) {
- data->hdev->stat.byte_rx += count;
+ usb_fill_int_urb(urb, data->udev, pipe, buf, size,
+ bpa10x_rx_complete, hdev, 1);
- if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)
- bpa10x_recv_event(data, buf, count);
+ urb->transfer_flags |= URB_FREE_BUFFER;
- if (usb_pipetype(urb->pipe) == PIPE_BULK)
- bpa10x_recv_bulk(data, buf, count);
- } else {
- data->hdev->stat.byte_tx += count;
+ usb_anchor_urb(urb, &data->rx_anchor);
- bpa10x_wakeup(data);
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err < 0) {
+ BT_ERR("%s urb %p submission failed (%d)",
+ hdev->name, urb, -err);
+ usb_unanchor_urb(urb);
+ kfree(buf);
}
-resubmit:
- if (usb_pipein(urb->pipe)) {
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err < 0 && err != -ENODEV) {
- BT_ERR("%s urb %p type %d resubmit status %d",
- data->hdev->name, urb, usb_pipetype(urb->pipe), err);
- }
- }
+ usb_free_urb(urb);
-unlock:
- read_unlock(&data->lock);
+ return err;
}
-static inline struct urb *bpa10x_alloc_urb(struct usb_device *udev, unsigned int pipe,
- size_t size, gfp_t flags, void *data)
+static inline int bpa10x_submit_bulk_urb(struct hci_dev *hdev)
{
+ struct bpa10x_data *data = hdev->driver_data;
struct urb *urb;
- struct usb_ctrlrequest *cr;
unsigned char *buf;
+ unsigned int pipe;
+ int err, size = 64;
- BT_DBG("udev %p data %p", udev, data);
+ BT_DBG("%s", hdev->name);
- urb = usb_alloc_urb(0, flags);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
- return NULL;
+ return -ENOMEM;
- buf = kmalloc(size, flags);
+ buf = kmalloc(size, GFP_KERNEL);
if (!buf) {
usb_free_urb(urb);
- return NULL;
+ return -ENOMEM;
}
- switch (usb_pipetype(pipe)) {
- case PIPE_CONTROL:
- cr = kmalloc(sizeof(*cr), flags);
- if (!cr) {
- kfree(buf);
- usb_free_urb(urb);
- return NULL;
- }
+ pipe = usb_rcvbulkpipe(data->udev, 0x82);
- cr->bRequestType = USB_TYPE_VENDOR;
- cr->bRequest = 0;
- cr->wIndex = 0;
- cr->wValue = 0;
- cr->wLength = __cpu_to_le16(0);
+ usb_fill_bulk_urb(urb, data->udev, pipe,
+ buf, size, bpa10x_rx_complete, hdev);
- usb_fill_control_urb(urb, udev, pipe, (void *) cr, buf, 0, bpa10x_complete, data);
- break;
+ urb->transfer_flags |= URB_FREE_BUFFER;
- case PIPE_INTERRUPT:
- usb_fill_int_urb(urb, udev, pipe, buf, size, bpa10x_complete, data, 1);
- break;
+ usb_anchor_urb(urb, &data->rx_anchor);
- case PIPE_BULK:
- usb_fill_bulk_urb(urb, udev, pipe, buf, size, bpa10x_complete, data);
- break;
-
- default:
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err < 0) {
+ BT_ERR("%s urb %p submission failed (%d)",
+ hdev->name, urb, -err);
+ usb_unanchor_urb(urb);
kfree(buf);
- usb_free_urb(urb);
- return NULL;
}
- return urb;
-}
-
-static inline void bpa10x_free_urb(struct urb *urb)
-{
- BT_DBG("urb %p", urb);
-
- if (!urb)
- return;
-
- kfree(urb->setup_packet);
- kfree(urb->transfer_buffer);
-
usb_free_urb(urb);
+
+ return err;
}
static int bpa10x_open(struct hci_dev *hdev)
{
struct bpa10x_data *data = hdev->driver_data;
- struct usb_device *udev = data->udev;
- unsigned long flags;
int err;
- BT_DBG("hdev %p data %p", hdev, data);
+ BT_DBG("%s", hdev->name);
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
return 0;
- data->cmd_urb = bpa10x_alloc_urb(udev, usb_sndctrlpipe(udev, BPA10X_CMD_EP),
- BPA10X_CMD_BUF_SIZE, GFP_KERNEL, data);
- if (!data->cmd_urb) {
- err = -ENOMEM;
- goto done;
- }
-
- data->evt_urb = bpa10x_alloc_urb(udev, usb_rcvintpipe(udev, BPA10X_EVT_EP),
- BPA10X_EVT_BUF_SIZE, GFP_KERNEL, data);
- if (!data->evt_urb) {
- bpa10x_free_urb(data->cmd_urb);
- err = -ENOMEM;
- goto done;
- }
-
- data->rx_urb = bpa10x_alloc_urb(udev, usb_rcvbulkpipe(udev, BPA10X_RX_EP),
- BPA10X_RX_BUF_SIZE, GFP_KERNEL, data);
- if (!data->rx_urb) {
- bpa10x_free_urb(data->evt_urb);
- bpa10x_free_urb(data->cmd_urb);
- err = -ENOMEM;
- goto done;
- }
-
- data->tx_urb = bpa10x_alloc_urb(udev, usb_sndbulkpipe(udev, BPA10X_TX_EP),
- BPA10X_TX_BUF_SIZE, GFP_KERNEL, data);
- if (!data->rx_urb) {
- bpa10x_free_urb(data->rx_urb);
- bpa10x_free_urb(data->evt_urb);
- bpa10x_free_urb(data->cmd_urb);
- err = -ENOMEM;
- goto done;
- }
+ err = bpa10x_submit_intr_urb(hdev);
+ if (err < 0)
+ goto error;
- write_lock_irqsave(&data->lock, flags);
+ err = bpa10x_submit_bulk_urb(hdev);
+ if (err < 0)
+ goto error;
- err = usb_submit_urb(data->evt_urb, GFP_ATOMIC);
- if (err < 0) {
- BT_ERR("%s submit failed for event urb %p with error %d",
- data->hdev->name, data->evt_urb, err);
- } else {
- err = usb_submit_urb(data->rx_urb, GFP_ATOMIC);
- if (err < 0) {
- BT_ERR("%s submit failed for rx urb %p with error %d",
- data->hdev->name, data->evt_urb, err);
- usb_kill_urb(data->evt_urb);
- }
- }
+ return 0;
- write_unlock_irqrestore(&data->lock, flags);
+error:
+ usb_kill_anchored_urbs(&data->rx_anchor);
-done:
- if (err < 0)
- clear_bit(HCI_RUNNING, &hdev->flags);
+ clear_bit(HCI_RUNNING, &hdev->flags);
return err;
}
@@ -446,27 +339,13 @@ done:
static int bpa10x_close(struct hci_dev *hdev)
{
struct bpa10x_data *data = hdev->driver_data;
- unsigned long flags;
- BT_DBG("hdev %p data %p", hdev, data);
+ BT_DBG("%s", hdev->name);
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
- write_lock_irqsave(&data->lock, flags);
-
- skb_queue_purge(&data->cmd_queue);
- usb_kill_urb(data->cmd_urb);
- usb_kill_urb(data->evt_urb);
- usb_kill_urb(data->rx_urb);
- usb_kill_urb(data->tx_urb);
-
- write_unlock_irqrestore(&data->lock, flags);
-
- bpa10x_free_urb(data->cmd_urb);
- bpa10x_free_urb(data->evt_urb);
- bpa10x_free_urb(data->rx_urb);
- bpa10x_free_urb(data->tx_urb);
+ usb_kill_anchored_urbs(&data->rx_anchor);
return 0;
}
@@ -475,9 +354,9 @@ static int bpa10x_flush(struct hci_dev *hdev)
{
struct bpa10x_data *data = hdev->driver_data;
- BT_DBG("hdev %p data %p", hdev, data);
+ BT_DBG("%s", hdev->name);
- skb_queue_purge(&data->cmd_queue);
+ usb_kill_anchored_urbs(&data->tx_anchor);
return 0;
}
@@ -485,45 +364,78 @@ static int bpa10x_flush(struct hci_dev *hdev)
static int bpa10x_send_frame(struct sk_buff *skb)
{
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
- struct bpa10x_data *data;
-
- BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, bt_cb(skb)->pkt_type, skb->len);
+ struct bpa10x_data *data = hdev->driver_data;
+ struct usb_ctrlrequest *dr;
+ struct urb *urb;
+ unsigned int pipe;
+ int err;
- if (!hdev) {
- BT_ERR("Frame for unknown HCI device");
- return -ENODEV;
- }
+ BT_DBG("%s", hdev->name);
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
- data = hdev->driver_data;
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb)
+ return -ENOMEM;
/* Prepend skb with frame type */
- memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+ *skb_push(skb, 1) = bt_cb(skb)->pkt_type;
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
+ dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
+ if (!dr) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+
+ dr->bRequestType = USB_TYPE_VENDOR;
+ dr->bRequest = 0;
+ dr->wIndex = 0;
+ dr->wValue = 0;
+ dr->wLength = __cpu_to_le16(skb->len);
+
+ pipe = usb_sndctrlpipe(data->udev, 0x00);
+
+ usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,
+ skb->data, skb->len, bpa10x_tx_complete, skb);
+
hdev->stat.cmd_tx++;
- skb_queue_tail(&data->cmd_queue, skb);
break;
case HCI_ACLDATA_PKT:
+ pipe = usb_sndbulkpipe(data->udev, 0x02);
+
+ usb_fill_bulk_urb(urb, data->udev, pipe,
+ skb->data, skb->len, bpa10x_tx_complete, skb);
+
hdev->stat.acl_tx++;
- skb_queue_tail(&data->tx_queue, skb);
break;
case HCI_SCODATA_PKT:
+ pipe = usb_sndbulkpipe(data->udev, 0x02);
+
+ usb_fill_bulk_urb(urb, data->udev, pipe,
+ skb->data, skb->len, bpa10x_tx_complete, skb);
+
hdev->stat.sco_tx++;
- skb_queue_tail(&data->tx_queue, skb);
break;
- };
- read_lock(&data->lock);
+ default:
+ return -EILSEQ;
+ }
+
+ usb_anchor_urb(urb, &data->tx_anchor);
- bpa10x_wakeup(data);
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err < 0) {
+ BT_ERR("%s urb %p submission failed", hdev->name, urb);
+ kfree(urb->setup_packet);
+ usb_unanchor_urb(urb);
+ }
- read_unlock(&data->lock);
+ usb_free_urb(urb);
return 0;
}
@@ -532,16 +444,17 @@ static void bpa10x_destruct(struct hci_dev *hdev)
{
struct bpa10x_data *data = hdev->driver_data;
- BT_DBG("hdev %p data %p", hdev, data);
+ BT_DBG("%s", hdev->name);
+ kfree(data->rx_skb[0]);
+ kfree(data->rx_skb[1]);
kfree(data);
}
static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct hci_dev *hdev;
struct bpa10x_data *data;
+ struct hci_dev *hdev;
int err;
BT_DBG("intf %p id %p", intf, id);
@@ -549,48 +462,43 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
if (ignore)
return -ENODEV;
- if (intf->cur_altsetting->desc.bInterfaceNumber > 0)
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- BT_ERR("Can't allocate data structure");
+ if (!data)
return -ENOMEM;
- }
-
- data->udev = udev;
- rwlock_init(&data->lock);
+ data->udev = interface_to_usbdev(intf);
- skb_queue_head_init(&data->cmd_queue);
- skb_queue_head_init(&data->tx_queue);
+ init_usb_anchor(&data->tx_anchor);
+ init_usb_anchor(&data->rx_anchor);
hdev = hci_alloc_dev();
if (!hdev) {
- BT_ERR("Can't allocate HCI device");
kfree(data);
return -ENOMEM;
}
- data->hdev = hdev;
-
hdev->type = HCI_USB;
hdev->driver_data = data;
+
+ data->hdev = hdev;
+
SET_HCIDEV_DEV(hdev, &intf->dev);
- hdev->open = bpa10x_open;
- hdev->close = bpa10x_close;
- hdev->flush = bpa10x_flush;
- hdev->send = bpa10x_send_frame;
- hdev->destruct = bpa10x_destruct;
+ hdev->open = bpa10x_open;
+ hdev->close = bpa10x_close;
+ hdev->flush = bpa10x_flush;
+ hdev->send = bpa10x_send_frame;
+ hdev->destruct = bpa10x_destruct;
hdev->owner = THIS_MODULE;
err = hci_register_dev(hdev);
if (err < 0) {
- BT_ERR("Can't register HCI device");
- kfree(data);
hci_free_dev(hdev);
+ kfree(data);
return err;
}
@@ -602,19 +510,17 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
static void bpa10x_disconnect(struct usb_interface *intf)
{
struct bpa10x_data *data = usb_get_intfdata(intf);
- struct hci_dev *hdev = data->hdev;
BT_DBG("intf %p", intf);
- if (!hdev)
+ if (!data)
return;
usb_set_intfdata(intf, NULL);
- if (hci_unregister_dev(hdev) < 0)
- BT_ERR("Can't unregister HCI device %s", hdev->name);
+ hci_unregister_dev(data->hdev);
- hci_free_dev(hdev);
+ hci_free_dev(data->hdev);
}
static struct usb_driver bpa10x_driver = {
@@ -626,15 +532,9 @@ static struct usb_driver bpa10x_driver = {
static int __init bpa10x_init(void)
{
- int err;
-
BT_INFO("Digianswer Bluetooth USB driver ver %s", VERSION);
- err = usb_register(&bpa10x_driver);
- if (err < 0)
- BT_ERR("Failed to register USB driver");
-
- return err;
+ return usb_register(&bpa10x_driver);
}
static void __exit bpa10x_exit(void)
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 39516074636..a18f9b8c9e1 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -344,10 +344,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
unsigned int iobase;
int iir;
- if (!info || !info->hdev) {
- BT_ERR("Call of irq %d for unknown device", irq);
- return IRQ_NONE;
- }
+ BUG_ON(!info->hdev);
iobase = info->p_dev->io.BasePort1;
diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c
new file mode 100644
index 00000000000..b786f618790
--- /dev/null
+++ b/drivers/bluetooth/btsdio.c
@@ -0,0 +1,406 @@
+/*
+ *
+ * Generic Bluetooth SDIO driver
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ * Copyright (C) 2007 Marcel Holtmann <marcel@holtmann.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/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#ifndef CONFIG_BT_HCIBTSDIO_DEBUG
+#undef BT_DBG
+#define BT_DBG(D...)
+#endif
+
+#define VERSION "0.1"
+
+static const struct sdio_device_id btsdio_table[] = {
+ /* Generic Bluetooth Type-A SDIO device */
+ { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_A) },
+
+ /* Generic Bluetooth Type-B SDIO device */
+ { SDIO_DEVICE_CLASS(SDIO_CLASS_BT_B) },
+
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(sdio, btsdio_table);
+
+struct btsdio_data {
+ struct hci_dev *hdev;
+ struct sdio_func *func;
+
+ struct work_struct work;
+
+ struct sk_buff_head txq;
+};
+
+#define REG_RDAT 0x00 /* Receiver Data */
+#define REG_TDAT 0x00 /* Transmitter Data */
+#define REG_PC_RRT 0x10 /* Read Packet Control */
+#define REG_PC_WRT 0x11 /* Write Packet Control */
+#define REG_RTC_STAT 0x12 /* Retry Control Status */
+#define REG_RTC_SET 0x12 /* Retry Control Set */
+#define REG_INTRD 0x13 /* Interrupt Indication */
+#define REG_CL_INTRD 0x13 /* Interrupt Clear */
+#define REG_EN_INTRD 0x14 /* Interrupt Enable */
+#define REG_MD_STAT 0x20 /* Bluetooth Mode Status */
+
+static int btsdio_tx_packet(struct btsdio_data *data, struct sk_buff *skb)
+{
+ int err;
+
+ BT_DBG("%s", data->hdev->name);
+
+ /* Prepend Type-A header */
+ skb_push(skb, 4);
+ skb->data[0] = (skb->len & 0x0000ff);
+ skb->data[1] = (skb->len & 0x00ff00) >> 8;
+ skb->data[2] = (skb->len & 0xff0000) >> 16;
+ skb->data[3] = bt_cb(skb)->pkt_type;
+
+ err = sdio_writesb(data->func, REG_TDAT, skb->data, skb->len);
+ if (err < 0) {
+ sdio_writeb(data->func, 0x01, REG_PC_WRT, NULL);
+ return err;
+ }
+
+ data->hdev->stat.byte_tx += skb->len;
+
+ kfree_skb(skb);
+
+ return 0;
+}
+
+static void btsdio_work(struct work_struct *work)
+{
+ struct btsdio_data *data = container_of(work, struct btsdio_data, work);
+ struct sk_buff *skb;
+ int err;
+
+ BT_DBG("%s", data->hdev->name);
+
+ sdio_claim_host(data->func);
+
+ while ((skb = skb_dequeue(&data->txq))) {
+ err = btsdio_tx_packet(data, skb);
+ if (err < 0) {
+ data->hdev->stat.err_tx++;
+ skb_queue_head(&data->txq, skb);
+ break;
+ }
+ }
+
+ sdio_release_host(data->func);
+}
+
+static int btsdio_rx_packet(struct btsdio_data *data)
+{
+ u8 hdr[4] __attribute__ ((aligned(4)));
+ struct sk_buff *skb;
+ int err, len;
+
+ BT_DBG("%s", data->hdev->name);
+
+ err = sdio_readsb(data->func, hdr, REG_RDAT, 4);
+ if (err < 0)
+ return err;
+
+ len = hdr[0] | (hdr[1] << 8) | (hdr[2] << 16);
+ if (len < 4 || len > 65543)
+ return -EILSEQ;
+
+ skb = bt_skb_alloc(len - 4, GFP_KERNEL);
+ if (!skb) {
+ /* Out of memory. Prepare a read retry and just
+ * return with the expectation that the next time
+ * we're called we'll have more memory. */
+ return -ENOMEM;
+ }
+
+ skb_put(skb, len - 4);
+
+ err = sdio_readsb(data->func, skb->data, REG_RDAT, len - 4);
+ if (err < 0) {
+ kfree(skb);
+ return err;
+ }
+
+ data->hdev->stat.byte_rx += len;
+
+ skb->dev = (void *) data->hdev;
+ bt_cb(skb)->pkt_type = hdr[3];
+
+ err = hci_recv_frame(skb);
+ if (err < 0) {
+ kfree(skb);
+ return err;
+ }
+
+ sdio_writeb(data->func, 0x00, REG_PC_RRT, NULL);
+
+ return 0;
+}
+
+static void btsdio_interrupt(struct sdio_func *func)
+{
+ struct btsdio_data *data = sdio_get_drvdata(func);
+ int intrd;
+
+ BT_DBG("%s", data->hdev->name);
+
+ intrd = sdio_readb(func, REG_INTRD, NULL);
+ if (intrd & 0x01) {
+ sdio_writeb(func, 0x01, REG_CL_INTRD, NULL);
+
+ if (btsdio_rx_packet(data) < 0) {
+ data->hdev->stat.err_rx++;
+ sdio_writeb(data->func, 0x01, REG_PC_RRT, NULL);
+ }
+ }
+}
+
+static int btsdio_open(struct hci_dev *hdev)
+{
+ struct btsdio_data *data = hdev->driver_data;
+ int err;
+
+ BT_DBG("%s", hdev->name);
+
+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ sdio_claim_host(data->func);
+
+ err = sdio_enable_func(data->func);
+ if (err < 0) {
+ clear_bit(HCI_RUNNING, &hdev->flags);
+ goto release;
+ }
+
+ err = sdio_claim_irq(data->func, btsdio_interrupt);
+ if (err < 0) {
+ sdio_disable_func(data->func);
+ clear_bit(HCI_RUNNING, &hdev->flags);
+ goto release;
+ }
+
+ if (data->func->class == SDIO_CLASS_BT_B)
+ sdio_writeb(data->func, 0x00, REG_MD_STAT, NULL);
+
+ sdio_writeb(data->func, 0x01, REG_EN_INTRD, NULL);
+
+release:
+ sdio_release_host(data->func);
+
+ return err;
+}
+
+static int btsdio_close(struct hci_dev *hdev)
+{
+ struct btsdio_data *data = hdev->driver_data;
+
+ BT_DBG("%s", hdev->name);
+
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ sdio_claim_host(data->func);
+
+ sdio_writeb(data->func, 0x00, REG_EN_INTRD, NULL);
+
+ sdio_release_irq(data->func);
+ sdio_disable_func(data->func);
+
+ sdio_release_host(data->func);
+
+ return 0;
+}
+
+static int btsdio_flush(struct hci_dev *hdev)
+{
+ struct btsdio_data *data = hdev->driver_data;
+
+ BT_DBG("%s", hdev->name);
+
+ skb_queue_purge(&data->txq);
+
+ return 0;
+}
+
+static int btsdio_send_frame(struct sk_buff *skb)
+{
+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+ struct btsdio_data *data = hdev->driver_data;
+
+ BT_DBG("%s", hdev->name);
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ break;
+
+ default:
+ return -EILSEQ;
+ }
+
+ skb_queue_tail(&data->txq, skb);
+
+ schedule_work(&data->work);
+
+ return 0;
+}
+
+static void btsdio_destruct(struct hci_dev *hdev)
+{
+ struct btsdio_data *data = hdev->driver_data;
+
+ BT_DBG("%s", hdev->name);
+
+ kfree(data);
+}
+
+static int btsdio_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ struct btsdio_data *data;
+ struct hci_dev *hdev;
+ struct sdio_func_tuple *tuple = func->tuples;
+ int err;
+
+ BT_DBG("func %p id %p class 0x%04x", func, id, func->class);
+
+ while (tuple) {
+ BT_DBG("code 0x%x size %d", tuple->code, tuple->size);
+ tuple = tuple->next;
+ }
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->func = func;
+
+ INIT_WORK(&data->work, btsdio_work);
+
+ skb_queue_head_init(&data->txq);
+
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ kfree(data);
+ return -ENOMEM;
+ }
+
+ hdev->type = HCI_SDIO;
+ hdev->driver_data = data;
+
+ data->hdev = hdev;
+
+ SET_HCIDEV_DEV(hdev, &func->dev);
+
+ hdev->open = btsdio_open;
+ hdev->close = btsdio_close;
+ hdev->flush = btsdio_flush;
+ hdev->send = btsdio_send_frame;
+ hdev->destruct = btsdio_destruct;
+
+ hdev->owner = THIS_MODULE;
+
+ err = hci_register_dev(hdev);
+ if (err < 0) {
+ hci_free_dev(hdev);
+ kfree(data);
+ return err;
+ }
+
+ sdio_set_drvdata(func, data);
+
+ return 0;
+}
+
+static void btsdio_remove(struct sdio_func *func)
+{
+ struct btsdio_data *data = sdio_get_drvdata(func);
+ struct hci_dev *hdev;
+
+ BT_DBG("func %p", func);
+
+ if (!data)
+ return;
+
+ hdev = data->hdev;
+
+ sdio_set_drvdata(func, NULL);
+
+ hci_unregister_dev(hdev);
+
+ hci_free_dev(hdev);
+}
+
+static struct sdio_driver btsdio_driver = {
+ .name = "btsdio",
+ .probe = btsdio_probe,
+ .remove = btsdio_remove,
+ .id_table = btsdio_table,
+};
+
+static int __init btsdio_init(void)
+{
+ BT_INFO("Generic Bluetooth SDIO driver ver %s", VERSION);
+
+ return sdio_register_driver(&btsdio_driver);
+}
+
+static void __exit btsdio_exit(void)
+{
+ sdio_unregister_driver(&btsdio_driver);
+}
+
+module_init(btsdio_init);
+module_exit(btsdio_exit);
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("Generic Bluetooth SDIO driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index d7d2ea0d86a..08f48d577ab 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -294,10 +294,7 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
int boguscount = 0;
int iir, lsr;
- if (!info || !info->hdev) {
- BT_ERR("Call of irq %d for unknown device", irq);
- return IRQ_NONE;
- }
+ BUG_ON(!info->hdev);
iobase = info->p_dev->io.BasePort1;
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
new file mode 100644
index 00000000000..12e108914f1
--- /dev/null
+++ b/drivers/bluetooth/btusb.c
@@ -0,0 +1,564 @@
+/*
+ *
+ * Generic Bluetooth USB driver
+ *
+ * Copyright (C) 2005-2007 Marcel Holtmann <marcel@holtmann.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/init.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+
+#include <linux/usb.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+//#define CONFIG_BT_HCIBTUSB_DEBUG
+#ifndef CONFIG_BT_HCIBTUSB_DEBUG
+#undef BT_DBG
+#define BT_DBG(D...)
+#endif
+
+#define VERSION "0.1"
+
+static struct usb_device_id btusb_table[] = {
+ /* Generic Bluetooth USB device */
+ { USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
+
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, btusb_table);
+
+static struct usb_device_id blacklist_table[] = {
+ { } /* Terminating entry */
+};
+
+#define BTUSB_INTR_RUNNING 0
+#define BTUSB_BULK_RUNNING 1
+
+struct btusb_data {
+ struct hci_dev *hdev;
+ struct usb_device *udev;
+
+ spinlock_t lock;
+
+ unsigned long flags;
+
+ struct work_struct work;
+
+ struct usb_anchor tx_anchor;
+ struct usb_anchor intr_anchor;
+ struct usb_anchor bulk_anchor;
+
+ struct usb_endpoint_descriptor *intr_ep;
+ struct usb_endpoint_descriptor *bulk_tx_ep;
+ struct usb_endpoint_descriptor *bulk_rx_ep;
+};
+
+static void btusb_intr_complete(struct urb *urb)
+{
+ struct hci_dev *hdev = urb->context;
+ struct btusb_data *data = hdev->driver_data;
+ int err;
+
+ BT_DBG("%s urb %p status %d count %d", hdev->name,
+ urb, urb->status, urb->actual_length);
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return;
+
+ if (urb->status == 0) {
+ if (hci_recv_fragment(hdev, HCI_EVENT_PKT,
+ urb->transfer_buffer,
+ urb->actual_length) < 0) {
+ BT_ERR("%s corrupted event packet", hdev->name);
+ hdev->stat.err_rx++;
+ }
+ }
+
+ if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
+ return;
+
+ usb_anchor_urb(urb, &data->intr_anchor);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err < 0) {
+ BT_ERR("%s urb %p failed to resubmit (%d)",
+ hdev->name, urb, -err);
+ usb_unanchor_urb(urb);
+ }
+}
+
+static inline int btusb_submit_intr_urb(struct hci_dev *hdev)
+{
+ struct btusb_data *data = hdev->driver_data;
+ struct urb *urb;
+ unsigned char *buf;
+ unsigned int pipe;
+ int err, size;
+
+ BT_DBG("%s", hdev->name);
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb)
+ return -ENOMEM;
+
+ size = le16_to_cpu(data->intr_ep->wMaxPacketSize);
+
+ buf = kmalloc(size, GFP_ATOMIC);
+ if (!buf) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+
+ pipe = usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress);
+
+ usb_fill_int_urb(urb, data->udev, pipe, buf, size,
+ btusb_intr_complete, hdev,
+ data->intr_ep->bInterval);
+
+ urb->transfer_flags |= URB_FREE_BUFFER;
+
+ usb_anchor_urb(urb, &data->intr_anchor);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err < 0) {
+ BT_ERR("%s urb %p submission failed (%d)",
+ hdev->name, urb, -err);
+ usb_unanchor_urb(urb);
+ kfree(buf);
+ }
+
+ usb_free_urb(urb);
+
+ return err;
+}
+
+static void btusb_bulk_complete(struct urb *urb)
+{
+ struct hci_dev *hdev = urb->context;
+ struct btusb_data *data = hdev->driver_data;
+ int err;
+
+ BT_DBG("%s urb %p status %d count %d", hdev->name,
+ urb, urb->status, urb->actual_length);
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return;
+
+ if (urb->status == 0) {
+ if (hci_recv_fragment(hdev, HCI_ACLDATA_PKT,
+ urb->transfer_buffer,
+ urb->actual_length) < 0) {
+ BT_ERR("%s corrupted ACL packet", hdev->name);
+ hdev->stat.err_rx++;
+ }
+ }
+
+ if (!test_bit(BTUSB_BULK_RUNNING, &data->flags))
+ return;
+
+ usb_anchor_urb(urb, &data->bulk_anchor);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err < 0) {
+ BT_ERR("%s urb %p failed to resubmit (%d)",
+ hdev->name, urb, -err);
+ usb_unanchor_urb(urb);
+ }
+}
+
+static inline int btusb_submit_bulk_urb(struct hci_dev *hdev)
+{
+ struct btusb_data *data = hdev->driver_data;
+ struct urb *urb;
+ unsigned char *buf;
+ unsigned int pipe;
+ int err, size;
+
+ BT_DBG("%s", hdev->name);
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb)
+ return -ENOMEM;
+
+ size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize);
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (!buf) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+
+ pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);
+
+ usb_fill_bulk_urb(urb, data->udev, pipe,
+ buf, size, btusb_bulk_complete, hdev);
+
+ urb->transfer_flags |= URB_FREE_BUFFER;
+
+ usb_anchor_urb(urb, &data->bulk_anchor);
+
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err < 0) {
+ BT_ERR("%s urb %p submission failed (%d)",
+ hdev->name, urb, -err);
+ usb_unanchor_urb(urb);
+ kfree(buf);
+ }
+
+ usb_free_urb(urb);
+
+ return err;
+}
+
+static void btusb_tx_complete(struct urb *urb)
+{
+ struct sk_buff *skb = urb->context;
+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+
+ BT_DBG("%s urb %p status %d count %d", hdev->name,
+ urb, urb->status, urb->actual_length);
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ goto done;
+
+ if (!urb->status)
+ hdev->stat.byte_tx += urb->transfer_buffer_length;
+ else
+ hdev->stat.err_tx++;
+
+done:
+ kfree(urb->setup_packet);
+
+ kfree_skb(skb);
+}
+
+static int btusb_open(struct hci_dev *hdev)
+{
+ struct btusb_data *data = hdev->driver_data;
+ int err;
+
+ BT_DBG("%s", hdev->name);
+
+ if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
+ return 0;
+
+ err = btusb_submit_intr_urb(hdev);
+ if (err < 0) {
+ clear_bit(BTUSB_INTR_RUNNING, &hdev->flags);
+ clear_bit(HCI_RUNNING, &hdev->flags);
+ }
+
+ return err;
+}
+
+static int btusb_close(struct hci_dev *hdev)
+{
+ struct btusb_data *data = hdev->driver_data;
+
+ BT_DBG("%s", hdev->name);
+
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+ usb_kill_anchored_urbs(&data->bulk_anchor);
+
+ clear_bit(BTUSB_INTR_RUNNING, &data->flags);
+ usb_kill_anchored_urbs(&data->intr_anchor);
+
+ return 0;
+}
+
+static int btusb_flush(struct hci_dev *hdev)
+{
+ struct btusb_data *data = hdev->driver_data;
+
+ BT_DBG("%s", hdev->name);
+
+ usb_kill_anchored_urbs(&data->tx_anchor);
+
+ return 0;
+}
+
+static int btusb_send_frame(struct sk_buff *skb)
+{
+ struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+ struct btusb_data *data = hdev->driver_data;
+ struct usb_ctrlrequest *dr;
+ struct urb *urb;
+ unsigned int pipe;
+ int err;
+
+ BT_DBG("%s", hdev->name);
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb)
+ return -ENOMEM;
+
+ dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
+ if (!dr) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+
+ dr->bRequestType = USB_TYPE_CLASS;
+ dr->bRequest = 0;
+ dr->wIndex = 0;
+ dr->wValue = 0;
+ dr->wLength = __cpu_to_le16(skb->len);
+
+ pipe = usb_sndctrlpipe(data->udev, 0x00);
+
+ usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,
+ skb->data, skb->len, btusb_tx_complete, skb);
+
+ hdev->stat.cmd_tx++;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb)
+ return -ENOMEM;
+
+ pipe = usb_sndbulkpipe(data->udev,
+ data->bulk_tx_ep->bEndpointAddress);
+
+ usb_fill_bulk_urb(urb, data->udev, pipe,
+ skb->data, skb->len, btusb_tx_complete, skb);
+
+ hdev->stat.acl_tx++;
+ break;
+
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ kfree_skb(skb);
+ return 0;
+
+ default:
+ return -EILSEQ;
+ }
+
+ usb_anchor_urb(urb, &data->tx_anchor);
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err < 0) {
+ BT_ERR("%s urb %p submission failed", hdev->name, urb);
+ kfree(urb->setup_packet);
+ usb_unanchor_urb(urb);
+ }
+
+ usb_free_urb(urb);
+
+ return err;
+}
+
+static void btusb_destruct(struct hci_dev *hdev)
+{
+ struct btusb_data *data = hdev->driver_data;
+
+ BT_DBG("%s", hdev->name);
+
+ kfree(data);
+}
+
+static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
+{
+ struct btusb_data *data = hdev->driver_data;
+
+ BT_DBG("%s evt %d", hdev->name, evt);
+
+ if (evt == HCI_NOTIFY_CONN_ADD || evt == HCI_NOTIFY_CONN_DEL)
+ schedule_work(&data->work);
+}
+
+static void btusb_work(struct work_struct *work)
+{
+ struct btusb_data *data = container_of(work, struct btusb_data, work);
+ struct hci_dev *hdev = data->hdev;
+
+ if (hdev->conn_hash.acl_num == 0) {
+ clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+ usb_kill_anchored_urbs(&data->bulk_anchor);
+ return;
+ }
+
+ if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) {
+ if (btusb_submit_bulk_urb(hdev) < 0)
+ clear_bit(BTUSB_BULK_RUNNING, &data->flags);
+ else
+ btusb_submit_bulk_urb(hdev);
+ }
+}
+
+static int btusb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_endpoint_descriptor *ep_desc;
+ struct btusb_data *data;
+ struct hci_dev *hdev;
+ int i, err;
+
+ BT_DBG("intf %p id %p", intf, id);
+
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+ return -ENODEV;
+
+ if (!id->driver_info) {
+ const struct usb_device_id *match;
+ match = usb_match_id(intf, blacklist_table);
+ if (match)
+ id = match;
+ }
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
+ ep_desc = &intf->cur_altsetting->endpoint[i].desc;
+
+ if (!data->intr_ep && usb_endpoint_is_int_in(ep_desc)) {
+ data->intr_ep = ep_desc;
+ continue;
+ }
+
+ if (!data->bulk_tx_ep && usb_endpoint_is_bulk_out(ep_desc)) {
+ data->bulk_tx_ep = ep_desc;
+ continue;
+ }
+
+ if (!data->bulk_rx_ep && usb_endpoint_is_bulk_in(ep_desc)) {
+ data->bulk_rx_ep = ep_desc;
+ continue;
+ }
+ }
+
+ if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) {
+ kfree(data);
+ return -ENODEV;
+ }
+
+ data->udev = interface_to_usbdev(intf);
+
+ spin_lock_init(&data->lock);
+
+ INIT_WORK(&data->work, btusb_work);
+
+ init_usb_anchor(&data->tx_anchor);
+ init_usb_anchor(&data->intr_anchor);
+ init_usb_anchor(&data->bulk_anchor);
+
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ kfree(data);
+ return -ENOMEM;
+ }
+
+ hdev->type = HCI_USB;
+ hdev->driver_data = data;
+
+ data->hdev = hdev;
+
+ SET_HCIDEV_DEV(hdev, &intf->dev);
+
+ hdev->open = btusb_open;
+ hdev->close = btusb_close;
+ hdev->flush = btusb_flush;
+ hdev->send = btusb_send_frame;
+ hdev->destruct = btusb_destruct;
+ hdev->notify = btusb_notify;
+
+ hdev->owner = THIS_MODULE;
+
+ set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
+
+ err = hci_register_dev(hdev);
+ if (err < 0) {
+ hci_free_dev(hdev);
+ kfree(data);
+ return err;
+ }
+
+ usb_set_intfdata(intf, data);
+
+ return 0;
+}
+
+static void btusb_disconnect(struct usb_interface *intf)
+{
+ struct btusb_data *data = usb_get_intfdata(intf);
+ struct hci_dev *hdev;
+
+ BT_DBG("intf %p", intf);
+
+ if (!data)
+ return;
+
+ hdev = data->hdev;
+
+ usb_set_intfdata(intf, NULL);
+
+ hci_unregister_dev(hdev);
+
+ hci_free_dev(hdev);
+}
+
+static struct usb_driver btusb_driver = {
+ .name = "btusb",
+ .probe = btusb_probe,
+ .disconnect = btusb_disconnect,
+ .id_table = btusb_table,
+};
+
+static int __init btusb_init(void)
+{
+ BT_INFO("Generic Bluetooth USB driver ver %s", VERSION);
+
+ return usb_register(&btusb_driver);
+}
+
+static void __exit btusb_exit(void)
+{
+ usb_deregister(&btusb_driver);
+}
+
+module_init(btusb_init);
+module_exit(btusb_exit);
+
+MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
+MODULE_DESCRIPTION("Generic Bluetooth USB driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 7f9c54b9964..dae45cdf02b 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -298,10 +298,7 @@ static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
int boguscount = 0;
int iir, lsr;
- if (!info || !info->hdev) {
- BT_ERR("Call of irq %d for unknown device", irq);
- return IRQ_NONE;
- }
+ BUG_ON(!info->hdev);
iobase = info->p_dev->io.BasePort1;
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index d66064ccb31..696f7528f02 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -237,7 +237,8 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
if (hciextn && chan == 5) {
struct hci_command_hdr *hdr = (struct hci_command_hdr *) data;
- if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == OGF_VENDOR_CMD) {
+ /* Vendor specific commands */
+ if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == 0x3f) {
u8 desc = *(data + HCI_COMMAND_HDR_SIZE);
if ((desc & 0xf0) == 0xc0) {
data += HCI_COMMAND_HDR_SIZE + 1;
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 6055b9c0ac0..e68821d074b 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -549,7 +549,10 @@ static int __init hci_uart_init(void)
#ifdef CONFIG_BT_HCIUART_BCSP
bcsp_init();
#endif
-
+#ifdef CONFIG_BT_HCIUART_LL
+ ll_init();
+#endif
+
return 0;
}
@@ -563,6 +566,9 @@ static void __exit hci_uart_exit(void)
#ifdef CONFIG_BT_HCIUART_BCSP
bcsp_deinit();
#endif
+#ifdef CONFIG_BT_HCIUART_LL
+ ll_deinit();
+#endif
/* Release tty registration of line discipline */
if ((err = tty_unregister_ldisc(N_HCI)))
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
new file mode 100644
index 00000000000..8c3e62a17b4
--- /dev/null
+++ b/drivers/bluetooth/hci_ll.c
@@ -0,0 +1,531 @@
+/*
+ * Texas Instruments' Bluetooth HCILL UART protocol
+ *
+ * HCILL (HCI Low Level) is a Texas Instruments' power management
+ * protocol extension to H4.
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ *
+ * Written by Ohad Ben-Cohen <ohad@bencohen.org>
+ *
+ * Acknowledgements:
+ * This file is based on hci_h4.c, which was written
+ * by Maxim Krasnyansky and Marcel Holtmann.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/poll.h>
+
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+
+/* HCILL commands */
+#define HCILL_GO_TO_SLEEP_IND 0x30
+#define HCILL_GO_TO_SLEEP_ACK 0x31
+#define HCILL_WAKE_UP_IND 0x32
+#define HCILL_WAKE_UP_ACK 0x33
+
+/* HCILL receiver States */
+#define HCILL_W4_PACKET_TYPE 0
+#define HCILL_W4_EVENT_HDR 1
+#define HCILL_W4_ACL_HDR 2
+#define HCILL_W4_SCO_HDR 3
+#define HCILL_W4_DATA 4
+
+/* HCILL states */
+enum hcill_states_e {
+ HCILL_ASLEEP,
+ HCILL_ASLEEP_TO_AWAKE,
+ HCILL_AWAKE,
+ HCILL_AWAKE_TO_ASLEEP
+};
+
+struct hcill_cmd {
+ u8 cmd;
+} __attribute__((packed));
+
+struct ll_struct {
+ unsigned long rx_state;
+ unsigned long rx_count;
+ struct sk_buff *rx_skb;
+ struct sk_buff_head txq;
+ spinlock_t hcill_lock; /* HCILL state lock */
+ unsigned long hcill_state; /* HCILL power state */
+ struct sk_buff_head tx_wait_q; /* HCILL wait queue */
+};
+
+/*
+ * Builds and sends an HCILL command packet.
+ * These are very simple packets with only 1 cmd byte
+ */
+static int send_hcill_cmd(u8 cmd, struct hci_uart *hu)
+{
+ int err = 0;
+ struct sk_buff *skb = NULL;
+ struct ll_struct *ll = hu->priv;
+ struct hcill_cmd *hcill_packet;
+
+ BT_DBG("hu %p cmd 0x%x", hu, cmd);
+
+ /* allocate packet */
+ skb = bt_skb_alloc(1, GFP_ATOMIC);
+ if (!skb) {
+ BT_ERR("cannot allocate memory for HCILL packet");
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /* prepare packet */
+ hcill_packet = (struct hcill_cmd *) skb_put(skb, 1);
+ hcill_packet->cmd = cmd;
+ skb->dev = (void *) hu->hdev;
+
+ /* send packet */
+ skb_queue_tail(&ll->txq, skb);
+out:
+ return err;
+}
+
+/* Initialize protocol */
+static int ll_open(struct hci_uart *hu)
+{
+ struct ll_struct *ll;
+
+ BT_DBG("hu %p", hu);
+
+ ll = kzalloc(sizeof(*ll), GFP_ATOMIC);
+ if (!ll)
+ return -ENOMEM;
+
+ skb_queue_head_init(&ll->txq);
+ skb_queue_head_init(&ll->tx_wait_q);
+ spin_lock_init(&ll->hcill_lock);
+
+ ll->hcill_state = HCILL_AWAKE;
+
+ hu->priv = ll;
+
+ return 0;
+}
+
+/* Flush protocol data */
+static int ll_flush(struct hci_uart *hu)
+{
+ struct ll_struct *ll = hu->priv;
+
+ BT_DBG("hu %p", hu);
+
+ skb_queue_purge(&ll->tx_wait_q);
+ skb_queue_purge(&ll->txq);
+
+ return 0;
+}
+
+/* Close protocol */
+static int ll_close(struct hci_uart *hu)
+{
+ struct ll_struct *ll = hu->priv;
+
+ BT_DBG("hu %p", hu);
+
+ skb_queue_purge(&ll->tx_wait_q);
+ skb_queue_purge(&ll->txq);
+
+ if (ll->rx_skb)
+ kfree_skb(ll->rx_skb);
+
+ hu->priv = NULL;
+
+ kfree(ll);
+
+ return 0;
+}
+
+/*
+ * internal function, which does common work of the device wake up process:
+ * 1. places all pending packets (waiting in tx_wait_q list) in txq list.
+ * 2. changes internal state to HCILL_AWAKE.
+ * Note: assumes that hcill_lock spinlock is taken,
+ * shouldn't be called otherwise!
+ */
+static void __ll_do_awake(struct ll_struct *ll)
+{
+ struct sk_buff *skb = NULL;
+
+ while ((skb = skb_dequeue(&ll->tx_wait_q)))
+ skb_queue_tail(&ll->txq, skb);
+
+ ll->hcill_state = HCILL_AWAKE;
+}
+
+/*
+ * Called upon a wake-up-indication from the device
+ */
+static void ll_device_want_to_wakeup(struct hci_uart *hu)
+{
+ unsigned long flags;
+ struct ll_struct *ll = hu->priv;
+
+ BT_DBG("hu %p", hu);
+
+ /* lock hcill state */
+ spin_lock_irqsave(&ll->hcill_lock, flags);
+
+ switch (ll->hcill_state) {
+ case HCILL_ASLEEP:
+ /* acknowledge device wake up */
+ if (send_hcill_cmd(HCILL_WAKE_UP_ACK, hu) < 0) {
+ BT_ERR("cannot acknowledge device wake up");
+ goto out;
+ }
+ break;
+ case HCILL_ASLEEP_TO_AWAKE:
+ /*
+ * this state means that a wake-up-indication
+ * is already on its way to the device,
+ * and will serve as the required wake-up-ack
+ */
+ BT_DBG("dual wake-up-indication");
+ break;
+ default:
+ /* any other state are illegal */
+ BT_ERR("received HCILL_WAKE_UP_IND in state %ld", ll->hcill_state);
+ break;
+ }
+
+ /* send pending packets and change state to HCILL_AWAKE */
+ __ll_do_awake(ll);
+
+out:
+ spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+ /* actually send the packets */
+ hci_uart_tx_wakeup(hu);
+}
+
+/*
+ * Called upon a sleep-indication from the device
+ */
+static void ll_device_want_to_sleep(struct hci_uart *hu)
+{
+ unsigned long flags;
+ struct ll_struct *ll = hu->priv;
+
+ BT_DBG("hu %p", hu);
+
+ /* lock hcill state */
+ spin_lock_irqsave(&ll->hcill_lock, flags);
+
+ /* sanity check */
+ if (ll->hcill_state != HCILL_AWAKE)
+ BT_ERR("ERR: HCILL_GO_TO_SLEEP_IND in state %ld", ll->hcill_state);
+
+ /* acknowledge device sleep */
+ if (send_hcill_cmd(HCILL_GO_TO_SLEEP_ACK, hu) < 0) {
+ BT_ERR("cannot acknowledge device sleep");
+ goto out;
+ }
+
+ /* update state */
+ ll->hcill_state = HCILL_ASLEEP;
+
+out:
+ spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+ /* actually send the sleep ack packet */
+ hci_uart_tx_wakeup(hu);
+}
+
+/*
+ * Called upon wake-up-acknowledgement from the device
+ */
+static void ll_device_woke_up(struct hci_uart *hu)
+{
+ unsigned long flags;
+ struct ll_struct *ll = hu->priv;
+
+ BT_DBG("hu %p", hu);
+
+ /* lock hcill state */
+ spin_lock_irqsave(&ll->hcill_lock, flags);
+
+ /* sanity check */
+ if (ll->hcill_state != HCILL_ASLEEP_TO_AWAKE)
+ BT_ERR("received HCILL_WAKE_UP_ACK in state %ld", ll->hcill_state);
+
+ /* send pending packets and change state to HCILL_AWAKE */
+ __ll_do_awake(ll);
+
+ spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+ /* actually send the packets */
+ hci_uart_tx_wakeup(hu);
+}
+
+/* Enqueue frame for transmittion (padding, crc, etc) */
+/* may be called from two simultaneous tasklets */
+static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+ unsigned long flags = 0;
+ struct ll_struct *ll = hu->priv;
+
+ BT_DBG("hu %p skb %p", hu, skb);
+
+ /* Prepend skb with frame type */
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+ /* lock hcill state */
+ spin_lock_irqsave(&ll->hcill_lock, flags);
+
+ /* act according to current state */
+ switch (ll->hcill_state) {
+ case HCILL_AWAKE:
+ BT_DBG("device awake, sending normally");
+ skb_queue_tail(&ll->txq, skb);
+ break;
+ case HCILL_ASLEEP:
+ BT_DBG("device asleep, waking up and queueing packet");
+ /* save packet for later */
+ skb_queue_tail(&ll->tx_wait_q, skb);
+ /* awake device */
+ if (send_hcill_cmd(HCILL_WAKE_UP_IND, hu) < 0) {
+ BT_ERR("cannot wake up device");
+ break;
+ }
+ ll->hcill_state = HCILL_ASLEEP_TO_AWAKE;
+ break;
+ case HCILL_ASLEEP_TO_AWAKE:
+ BT_DBG("device waking up, queueing packet");
+ /* transient state; just keep packet for later */
+ skb_queue_tail(&ll->tx_wait_q, skb);
+ break;
+ default:
+ BT_ERR("illegal hcill state: %ld (losing packet)", ll->hcill_state);
+ kfree_skb(skb);
+ break;
+ }
+
+ spin_unlock_irqrestore(&ll->hcill_lock, flags);
+
+ return 0;
+}
+
+static inline int ll_check_data_len(struct ll_struct *ll, int len)
+{
+ register int room = skb_tailroom(ll->rx_skb);
+
+ BT_DBG("len %d room %d", len, room);
+
+ if (!len) {
+ hci_recv_frame(ll->rx_skb);
+ } else if (len > room) {
+ BT_ERR("Data length is too large");
+ kfree_skb(ll->rx_skb);
+ } else {
+ ll->rx_state = HCILL_W4_DATA;
+ ll->rx_count = len;
+ return len;
+ }
+
+ ll->rx_state = HCILL_W4_PACKET_TYPE;
+ ll->rx_skb = NULL;
+ ll->rx_count = 0;
+
+ return 0;
+}
+
+/* Recv data */
+static int ll_recv(struct hci_uart *hu, void *data, int count)
+{
+ struct ll_struct *ll = hu->priv;
+ register char *ptr;
+ struct hci_event_hdr *eh;
+ struct hci_acl_hdr *ah;
+ struct hci_sco_hdr *sh;
+ register int len, type, dlen;
+
+ BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ll->rx_state, ll->rx_count);
+
+ ptr = data;
+ while (count) {
+ if (ll->rx_count) {
+ len = min_t(unsigned int, ll->rx_count, count);
+ memcpy(skb_put(ll->rx_skb, len), ptr, len);
+ ll->rx_count -= len; count -= len; ptr += len;
+
+ if (ll->rx_count)
+ continue;
+
+ switch (ll->rx_state) {
+ case HCILL_W4_DATA:
+ BT_DBG("Complete data");
+ hci_recv_frame(ll->rx_skb);
+
+ ll->rx_state = HCILL_W4_PACKET_TYPE;
+ ll->rx_skb = NULL;
+ continue;
+
+ case HCILL_W4_EVENT_HDR:
+ eh = (struct hci_event_hdr *) ll->rx_skb->data;
+
+ BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
+
+ ll_check_data_len(ll, eh->plen);
+ continue;
+
+ case HCILL_W4_ACL_HDR:
+ ah = (struct hci_acl_hdr *) ll->rx_skb->data;
+ dlen = __le16_to_cpu(ah->dlen);
+
+ BT_DBG("ACL header: dlen %d", dlen);
+
+ ll_check_data_len(ll, dlen);
+ continue;
+
+ case HCILL_W4_SCO_HDR:
+ sh = (struct hci_sco_hdr *) ll->rx_skb->data;
+
+ BT_DBG("SCO header: dlen %d", sh->dlen);
+
+ ll_check_data_len(ll, sh->dlen);
+ continue;
+ }
+ }
+
+ /* HCILL_W4_PACKET_TYPE */
+ switch (*ptr) {
+ case HCI_EVENT_PKT:
+ BT_DBG("Event packet");
+ ll->rx_state = HCILL_W4_EVENT_HDR;
+ ll->rx_count = HCI_EVENT_HDR_SIZE;
+ type = HCI_EVENT_PKT;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ BT_DBG("ACL packet");
+ ll->rx_state = HCILL_W4_ACL_HDR;
+ ll->rx_count = HCI_ACL_HDR_SIZE;
+ type = HCI_ACLDATA_PKT;
+ break;
+
+ case HCI_SCODATA_PKT:
+ BT_DBG("SCO packet");
+ ll->rx_state = HCILL_W4_SCO_HDR;
+ ll->rx_count = HCI_SCO_HDR_SIZE;
+ type = HCI_SCODATA_PKT;
+ break;
+
+ /* HCILL signals */
+ case HCILL_GO_TO_SLEEP_IND:
+ BT_DBG("HCILL_GO_TO_SLEEP_IND packet");
+ ll_device_want_to_sleep(hu);
+ ptr++; count--;
+ continue;
+
+ case HCILL_GO_TO_SLEEP_ACK:
+ /* shouldn't happen */
+ BT_ERR("received HCILL_GO_TO_SLEEP_ACK (in state %ld)", ll->hcill_state);
+ ptr++; count--;
+ continue;
+
+ case HCILL_WAKE_UP_IND:
+ BT_DBG("HCILL_WAKE_UP_IND packet");
+ ll_device_want_to_wakeup(hu);
+ ptr++; count--;
+ continue;
+
+ case HCILL_WAKE_UP_ACK:
+ BT_DBG("HCILL_WAKE_UP_ACK packet");
+ ll_device_woke_up(hu);
+ ptr++; count--;
+ continue;
+
+ default:
+ BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
+ hu->hdev->stat.err_rx++;
+ ptr++; count--;
+ continue;
+ };
+
+ ptr++; count--;
+
+ /* Allocate packet */
+ ll->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!ll->rx_skb) {
+ BT_ERR("Can't allocate mem for new packet");
+ ll->rx_state = HCILL_W4_PACKET_TYPE;
+ ll->rx_count = 0;
+ return 0;
+ }
+
+ ll->rx_skb->dev = (void *) hu->hdev;
+ bt_cb(ll->rx_skb)->pkt_type = type;
+ }
+
+ return count;
+}
+
+static struct sk_buff *ll_dequeue(struct hci_uart *hu)
+{
+ struct ll_struct *ll = hu->priv;
+ return skb_dequeue(&ll->txq);
+}
+
+static struct hci_uart_proto llp = {
+ .id = HCI_UART_LL,
+ .open = ll_open,
+ .close = ll_close,
+ .recv = ll_recv,
+ .enqueue = ll_enqueue,
+ .dequeue = ll_dequeue,
+ .flush = ll_flush,
+};
+
+int ll_init(void)
+{
+ int err = hci_uart_register_proto(&llp);
+
+ if (!err)
+ BT_INFO("HCILL protocol initialized");
+ else
+ BT_ERR("HCILL protocol registration failed");
+
+ return err;
+}
+
+int ll_deinit(void)
+{
+ return hci_uart_unregister_proto(&llp);
+}
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 1097ce72393..50113db06b9 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -33,12 +33,13 @@
#define HCIUARTGETDEVICE _IOR('U', 202, int)
/* UART protocols */
-#define HCI_UART_MAX_PROTO 4
+#define HCI_UART_MAX_PROTO 5
#define HCI_UART_H4 0
#define HCI_UART_BCSP 1
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
+#define HCI_UART_LL 4
struct hci_uart;
@@ -85,3 +86,8 @@ int h4_deinit(void);
int bcsp_init(void);
int bcsp_deinit(void);
#endif
+
+#ifdef CONFIG_BT_HCIUART_LL
+int ll_init(void);
+int ll_deinit(void);
+#endif
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 79245714f0a..af056105316 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -1107,7 +1107,7 @@ int open_for_data(struct cdrom_device_info * cdi)
is the default case! */
cdinfo(CD_OPEN, "bummer. wrong media type.\n");
cdinfo(CD_WARNING, "pid %d must open device O_NONBLOCK!\n",
- (unsigned int)current->pid);
+ (unsigned int)task_pid_nr(current));
ret=-EMEDIUMTYPE;
goto clean_up_and_return;
}
@@ -3458,47 +3458,19 @@ static void cdrom_update_settings(void)
static int cdrom_sysctl_handler(ctl_table *ctl, int write, struct file * filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
- int *valp = ctl->data;
- int val = *valp;
int ret;
ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
- if (write && *valp != val) {
+ if (write) {
/* we only care for 1 or 0. */
- if (*valp)
- *valp = 1;
- else
- *valp = 0;
+ autoclose = !!cdrom_sysctl_settings.autoclose;
+ autoeject = !!cdrom_sysctl_settings.autoeject;
+ debug = !!cdrom_sysctl_settings.debug;
+ lockdoor = !!cdrom_sysctl_settings.lock;
+ check_media_type = !!cdrom_sysctl_settings.check;
- switch (ctl->ctl_name) {
- case DEV_CDROM_AUTOCLOSE: {
- if (valp == &cdrom_sysctl_settings.autoclose)
- autoclose = cdrom_sysctl_settings.autoclose;
- break;
- }
- case DEV_CDROM_AUTOEJECT: {
- if (valp == &cdrom_sysctl_settings.autoeject)
- autoeject = cdrom_sysctl_settings.autoeject;
- break;
- }
- case DEV_CDROM_DEBUG: {
- if (valp == &cdrom_sysctl_settings.debug)
- debug = cdrom_sysctl_settings.debug;
- break;
- }
- case DEV_CDROM_LOCK: {
- if (valp == &cdrom_sysctl_settings.lock)
- lockdoor = cdrom_sysctl_settings.lock;
- break;
- }
- case DEV_CDROM_CHECK_MEDIA: {
- if (valp == &cdrom_sysctl_settings.check)
- check_media_type = cdrom_sysctl_settings.check;
- break;
- }
- }
/* update the option flags according to the changes. we
don't have per device options through sysctl yet,
but we will have and then this will disappear. */
@@ -3511,7 +3483,6 @@ static int cdrom_sysctl_handler(ctl_table *ctl, int write, struct file * filp,
/* Place files in /proc/sys/dev/cdrom */
static ctl_table cdrom_table[] = {
{
- .ctl_name = DEV_CDROM_INFO,
.procname = "info",
.data = &cdrom_sysctl_settings.info,
.maxlen = CDROM_STR_SIZE,
@@ -3519,7 +3490,6 @@ static ctl_table cdrom_table[] = {
.proc_handler = &cdrom_sysctl_info,
},
{
- .ctl_name = DEV_CDROM_AUTOCLOSE,
.procname = "autoclose",
.data = &cdrom_sysctl_settings.autoclose,
.maxlen = sizeof(int),
@@ -3527,7 +3497,6 @@ static ctl_table cdrom_table[] = {
.proc_handler = &cdrom_sysctl_handler,
},
{
- .ctl_name = DEV_CDROM_AUTOEJECT,
.procname = "autoeject",
.data = &cdrom_sysctl_settings.autoeject,
.maxlen = sizeof(int),
@@ -3535,7 +3504,6 @@ static ctl_table cdrom_table[] = {
.proc_handler = &cdrom_sysctl_handler,
},
{
- .ctl_name = DEV_CDROM_DEBUG,
.procname = "debug",
.data = &cdrom_sysctl_settings.debug,
.maxlen = sizeof(int),
@@ -3543,7 +3511,6 @@ static ctl_table cdrom_table[] = {
.proc_handler = &cdrom_sysctl_handler,
},
{
- .ctl_name = DEV_CDROM_LOCK,
.procname = "lock",
.data = &cdrom_sysctl_settings.lock,
.maxlen = sizeof(int),
@@ -3551,7 +3518,6 @@ static ctl_table cdrom_table[] = {
.proc_handler = &cdrom_sysctl_handler,
},
{
- .ctl_name = DEV_CDROM_CHECK_MEDIA,
.procname = "check_media",
.data = &cdrom_sysctl_settings.check,
.maxlen = sizeof(int),
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index e51550db157..d8bb44b98a6 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -41,9 +41,9 @@
#include <linux/completion.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/scatterlist.h>
#include <asm/vio.h>
-#include <asm/scatterlist.h>
#include <asm/iseries/hv_types.h>
#include <asm/iseries/hv_lp_event.h>
#include <asm/iseries/vio.h>
@@ -56,30 +56,6 @@
#define VIOCD_KERN_WARNING KERN_WARNING "viocd: "
#define VIOCD_KERN_INFO KERN_INFO "viocd: "
-struct viocdlpevent {
- struct HvLpEvent event;
- u32 reserved;
- u16 version;
- u16 sub_result;
- u16 disk;
- u16 flags;
- u32 token;
- u64 offset; /* On open, max number of disks */
- u64 len; /* On open, size of the disk */
- u32 block_size; /* Only set on open */
- u32 media_size; /* Only set on open */
-};
-
-enum viocdsubtype {
- viocdopen = 0x0001,
- viocdclose = 0x0002,
- viocdread = 0x0003,
- viocdwrite = 0x0004,
- viocdlockdoor = 0x0005,
- viocdgetinfo = 0x0006,
- viocdcheck = 0x0007
-};
-
/*
* Should probably make this a module parameter....sigh
*/
@@ -131,22 +107,13 @@ static struct capability_entry capability_table[] __initdata = {
/* These are our internal structures for keeping track of devices */
static int viocd_numdev;
-struct cdrom_info {
- char rsrcname[10];
- char type[4];
- char model[3];
-};
-/*
- * This needs to be allocated since it is passed to the
- * Hypervisor and we may be a module.
- */
-static struct cdrom_info *viocd_unitinfo;
-static dma_addr_t unitinfo_dmaaddr;
-
struct disk_info {
struct gendisk *viocd_disk;
struct cdrom_device_info viocd_info;
struct device *dev;
+ const char *rsrcname;
+ const char *type;
+ const char *model;
};
static struct disk_info viocd_diskinfo[VIOCD_MAX_CD];
@@ -164,9 +131,9 @@ static int proc_viocd_show(struct seq_file *m, void *v)
for (i = 0; i < viocd_numdev; i++) {
seq_printf(m, "viocd device %d is iSeries resource %10.10s"
"type %4.4s, model %3.3s\n",
- i, viocd_unitinfo[i].rsrcname,
- viocd_unitinfo[i].type,
- viocd_unitinfo[i].model);
+ i, viocd_diskinfo[i].rsrcname,
+ viocd_diskinfo[i].type,
+ viocd_diskinfo[i].model);
}
return 0;
}
@@ -216,61 +183,6 @@ struct block_device_operations viocd_fops = {
.media_changed = viocd_blk_media_changed,
};
-/* Get info on CD devices from OS/400 */
-static void __init get_viocd_info(void)
-{
- HvLpEvent_Rc hvrc;
- int i;
- struct viocd_waitevent we;
-
- viocd_unitinfo = dma_alloc_coherent(iSeries_vio_dev,
- sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
- &unitinfo_dmaaddr, GFP_ATOMIC);
- if (viocd_unitinfo == NULL) {
- printk(VIOCD_KERN_WARNING "error allocating unitinfo\n");
- return;
- }
-
- memset(viocd_unitinfo, 0, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD);
-
- init_completion(&we.com);
-
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_cdio | viocdgetinfo,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0,
- sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, 0);
- if (hvrc != HvLpEvent_Rc_Good) {
- printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n",
- (int)hvrc);
- goto error_ret;
- }
-
- wait_for_completion(&we.com);
-
- if (we.rc) {
- const struct vio_error_entry *err =
- vio_lookup_rc(viocd_err_table, we.sub_result);
- printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n",
- we.rc, we.sub_result, err->msg);
- goto error_ret;
- }
-
- for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++)
- viocd_numdev++;
-
-error_ret:
- if (viocd_numdev == 0) {
- dma_free_coherent(iSeries_vio_dev,
- sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
- viocd_unitinfo, unitinfo_dmaaddr);
- viocd_unitinfo = NULL;
- }
-}
-
static int viocd_open(struct cdrom_device_info *cdi, int purpose)
{
struct disk_info *diskinfo = cdi->handle;
@@ -346,6 +258,7 @@ static int send_request(struct request *req)
cmd = viomajorsubtype_cdio | viocdwrite;
}
+ sg_init_table(&sg, 1);
if (blk_rq_map_sg(req->q, req, &sg) == 0) {
printk(VIOCD_KERN_WARNING
"error setting up scatter/gather list\n");
@@ -581,7 +494,6 @@ static void vio_handle_cd_event(struct HvLpEvent *event)
bevent->block_size / 512);
}
/* FALLTHROUGH !! */
- case viocdgetinfo:
case viocdlockdoor:
pwe = (struct viocd_waitevent *)event->xCorrelationToken;
return_complete:
@@ -665,22 +577,30 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
int deviceno;
struct disk_info *d;
struct cdrom_device_info *c;
- struct cdrom_info *ci;
struct request_queue *q;
+ struct device_node *node = vdev->dev.archdata.of_node;
deviceno = vdev->unit_address;
- if (deviceno >= viocd_numdev)
+ if (deviceno > VIOCD_MAX_CD)
return -ENODEV;
+ if (!node)
+ return -ENODEV;
+
+ if (deviceno >= viocd_numdev)
+ viocd_numdev = deviceno + 1;
d = &viocd_diskinfo[deviceno];
+ d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL);
+ d->type = of_get_property(node, "linux,vio_type", NULL);
+ d->model = of_get_property(node, "linux,vio_model", NULL);
+
c = &d->viocd_info;
- ci = &viocd_unitinfo[deviceno];
c->ops = &viocd_dops;
c->speed = 4;
c->capacity = 1;
c->handle = d;
- c->mask = ~find_capability(ci->type);
+ c->mask = ~find_capability(d->type);
sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno);
if (register_cdrom(c) != 0) {
@@ -690,7 +610,7 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
}
printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s "
"type %4.4s, model %3.3s\n",
- c->name, ci->rsrcname, ci->type, ci->model);
+ c->name, d->rsrcname, d->type, d->model);
q = blk_init_queue(do_viocd_request, &viocd_reqlock);
if (q == NULL) {
printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n",
@@ -799,8 +719,6 @@ static int __init viocd_init(void)
/* Initialize our request handler */
vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event);
- get_viocd_info();
-
spin_lock_init(&viocd_reqlock);
ret = vio_register_driver(&viocd_driver);
@@ -816,9 +734,6 @@ static int __init viocd_init(void)
return 0;
out_free_info:
- dma_free_coherent(iSeries_vio_dev,
- sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
- viocd_unitinfo, unitinfo_dmaaddr);
vio_clearHandler(viomajorsubtype_cdio);
viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
out_unregister:
@@ -830,10 +745,6 @@ static void __exit viocd_exit(void)
{
remove_proc_entry("iSeries/viocd", NULL);
vio_unregister_driver(&viocd_driver);
- if (viocd_unitinfo != NULL)
- dma_free_coherent(iSeries_vio_dev,
- sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
- viocd_unitinfo, unitinfo_dmaaddr);
viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
vio_clearHandler(viomajorsubtype_cdio);
unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index b391776e5bf..bf18d757b87 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -568,8 +568,8 @@ config TIPAR
config HVC_DRIVER
bool
help
- Users of pSeries machines that want to utilize the hvc console front-end
- module for their backend console driver should select this option.
+ Generic "hypervisor virtual console" infrastructure for various
+ hypervisors (pSeries, iSeries, Xen, lguest).
It will automatically be selected if one of the back-end console drivers
is selected.
@@ -613,6 +613,10 @@ config HVC_XEN
help
Xen virtual console device driver
+config VIRTIO_CONSOLE
+ bool
+ select HVC_DRIVER
+
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"
depends on PPC_PSERIES
@@ -632,8 +636,6 @@ config HVCS
source "drivers/char/ipmi/Kconfig"
-source "drivers/char/watchdog/Kconfig"
-
config DS1620
tristate "NetWinder thermometer support"
depends on ARCH_NETWINDER
@@ -896,10 +898,6 @@ config GPIO_TB0219
depends on TANBAC_TB022X
select GPIO_VR41XX
-source "drivers/char/agp/Kconfig"
-
-source "drivers/char/drm/Kconfig"
-
source "drivers/char/pcmcia/Kconfig"
config MWAVE
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index c78ff26647e..07304d50e0c 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -42,7 +42,6 @@ obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_SX) += sx.o generic_serial.o
-obj-$(CONFIG_LGUEST_GUEST) += hvc_lguest.o
obj-$(CONFIG_RIO) += rio/ generic_serial.o
obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
@@ -50,6 +49,7 @@ obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_HVC_XEN) += hvc_xen.o
+obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
obj-$(CONFIG_MSPEC) += mspec.o
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index 713533d8a86..ccb1fa89de2 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -1,4 +1,4 @@
-config AGP
+menuconfig AGP
tristate "/dev/agpgart (AGP Support)"
depends on ALPHA || IA64 || PARISC || PPC || X86
depends on PCI
@@ -56,9 +56,9 @@ config AGP_AMD
X on AMD Irongate, 761, and 762 chipsets.
config AGP_AMD64
- tristate "AMD Opteron/Athlon64 on-CPU GART support" if !IOMMU
+ tristate "AMD Opteron/Athlon64 on-CPU GART support" if !GART_IOMMU
depends on AGP && X86
- default y if IOMMU
+ default y if GART_IOMMU
help
This option gives you AGP support for the GLX component of
X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs.
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 8955e7ff759..b83824c4132 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -58,6 +58,9 @@ struct gatt_mask {
* devices this will probably be ignored */
};
+#define AGP_PAGE_DESTROY_UNMAP 1
+#define AGP_PAGE_DESTROY_FREE 2
+
struct aper_size_info_8 {
int size;
int num_entries;
@@ -113,7 +116,7 @@ struct agp_bridge_driver {
struct agp_memory *(*alloc_by_type) (size_t, int);
void (*free_by_type)(struct agp_memory *);
void *(*agp_alloc_page)(struct agp_bridge_data *);
- void (*agp_destroy_page)(void *);
+ void (*agp_destroy_page)(void *, int flags);
int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
};
@@ -267,7 +270,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type);
struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type);
void agp_generic_free_by_type(struct agp_memory *curr);
void *agp_generic_alloc_page(struct agp_bridge_data *bridge);
-void agp_generic_destroy_page(void *addr);
+void agp_generic_destroy_page(void *addr, int flags);
void agp_free_key(int key);
int agp_num_entries(void);
u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 mode, u32 command);
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index 4941ddb7893..aa5ddb716ff 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -156,29 +156,34 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge)
return addr;
}
-static void ali_destroy_page(void * addr)
+static void ali_destroy_page(void * addr, int flags)
{
if (addr) {
- global_cache_flush(); /* is this really needed? --hch */
- agp_generic_destroy_page(addr);
- global_flush_tlb();
+ if (flags & AGP_PAGE_DESTROY_UNMAP) {
+ global_cache_flush(); /* is this really needed? --hch */
+ agp_generic_destroy_page(addr, flags);
+ global_flush_tlb();
+ } else
+ agp_generic_destroy_page(addr, flags);
}
}
-static void m1541_destroy_page(void * addr)
+static void m1541_destroy_page(void * addr, int flags)
{
u32 temp;
if (addr == NULL)
return;
- global_cache_flush();
+ if (flags & AGP_PAGE_DESTROY_UNMAP) {
+ global_cache_flush();
- pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
- pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
- (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
- virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN));
- agp_generic_destroy_page(addr);
+ pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
+ pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
+ (((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
+ virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN));
+ }
+ agp_generic_destroy_page(addr, flags);
}
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index f60bca70d1f..1405a42585e 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -100,21 +100,16 @@ static int amd_create_gatt_pages(int nr_tables)
for (i = 0; i < nr_tables; i++) {
entry = kzalloc(sizeof(struct amd_page_map), GFP_KERNEL);
+ tables[i] = entry;
if (entry == NULL) {
- while (i > 0) {
- kfree(tables[i-1]);
- i--;
- }
- kfree(tables);
retval = -ENOMEM;
break;
}
- tables[i] = entry;
retval = amd_create_page_map(entry);
if (retval != 0)
break;
}
- amd_irongate_private.num_tables = nr_tables;
+ amd_irongate_private.num_tables = i;
amd_irongate_private.gatt_pages = tables;
if (retval != 0)
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index d95662e9632..d8200ac8f8c 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -787,7 +787,7 @@ static void __exit agp_amd64_cleanup(void)
/* On AMD64 the PCI driver needs to initialize this driver early
for the IOMMU, so it has to be called via a backdoor. */
-#ifndef CONFIG_IOMMU
+#ifndef CONFIG_GART_IOMMU
module_init(agp_amd64_init);
module_exit(agp_amd64_cleanup);
#endif
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index 1b47c89a1b9..832ded20fe7 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -189,9 +189,11 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
err_out:
if (bridge->driver->needs_scratch_page) {
- bridge->driver->agp_destroy_page(
- gart_to_virt(bridge->scratch_page_real));
+ bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
+ AGP_PAGE_DESTROY_UNMAP);
flush_agp_mappings();
+ bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
+ AGP_PAGE_DESTROY_FREE);
}
if (got_gatt)
bridge->driver->free_gatt_table(bridge);
@@ -215,9 +217,11 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge)
if (bridge->driver->agp_destroy_page &&
bridge->driver->needs_scratch_page) {
- bridge->driver->agp_destroy_page(
- gart_to_virt(bridge->scratch_page_real));
+ bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
+ AGP_PAGE_DESTROY_UNMAP);
flush_agp_mappings();
+ bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
+ AGP_PAGE_DESTROY_FREE);
}
}
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index d78cd09186a..cac0009cebc 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -221,7 +221,7 @@ static int efficeon_create_gatt_table(struct agp_bridge_data *bridge)
SetPageReserved(virt_to_page((char *)page));
for (offset = 0; offset < PAGE_SIZE; offset += clflush_chunk)
- asm volatile("clflush %0" : : "m" (*(char *)(page+offset)));
+ clflush((char *)page+offset);
efficeon_private.l1_table[index] = page;
@@ -268,15 +268,16 @@ static int efficeon_insert_memory(struct agp_memory * mem, off_t pg_start, int t
*page = insert;
/* clflush is slow, so don't clflush until we have to */
- if ( last_page &&
- ((unsigned long)page^(unsigned long)last_page) & clflush_mask )
- asm volatile("clflush %0" : : "m" (*last_page));
+ if (last_page &&
+ (((unsigned long)page^(unsigned long)last_page) &
+ clflush_mask))
+ clflush(last_page);
last_page = page;
}
if ( last_page )
- asm volatile("clflush %0" : : "m" (*last_page));
+ clflush(last_page);
agp_bridge->driver->tlb_flush(mem);
return 0;
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 3db4f4076ed..64b2f6d7059 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -195,9 +195,12 @@ void agp_free_memory(struct agp_memory *curr)
}
if (curr->page_count != 0) {
for (i = 0; i < curr->page_count; i++) {
- curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]));
+ curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_UNMAP);
}
flush_agp_mappings();
+ for (i = 0; i < curr->page_count; i++) {
+ curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_FREE);
+ }
}
agp_free_key(curr->key);
agp_free_page_array(curr);
@@ -1176,7 +1179,7 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge)
EXPORT_SYMBOL(agp_generic_alloc_page);
-void agp_generic_destroy_page(void *addr)
+void agp_generic_destroy_page(void *addr, int flags)
{
struct page *page;
@@ -1184,10 +1187,14 @@ void agp_generic_destroy_page(void *addr)
return;
page = virt_to_page(addr);
- unmap_page_from_agp(page);
- put_page(page);
- free_page((unsigned long)addr);
- atomic_dec(&agp_bridge->current_memory_agp);
+ if (flags & AGP_PAGE_DESTROY_UNMAP)
+ unmap_page_from_agp(page);
+
+ if (flags & AGP_PAGE_DESTROY_FREE) {
+ put_page(page);
+ free_page((unsigned long)addr);
+ atomic_dec(&agp_bridge->current_memory_agp);
+ }
}
EXPORT_SYMBOL(agp_generic_destroy_page);
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index 313a133a117..cbb0444467b 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -14,15 +14,12 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/agp_backend.h>
+#include <linux/log2.h>
#include <asm/acpi-ext.h>
#include "agp.h"
-#ifndef log2
-#define log2(x) ffz(~(x))
-#endif
-
#define HP_ZX1_IOC_OFFSET 0x1000 /* ACPI reports SBA, we want IOC */
/* HP ZX1 IOC registers */
@@ -257,7 +254,7 @@ hp_zx1_configure (void)
readl(hp->ioc_regs+HP_ZX1_IMASK);
writel(hp->iova_base|1, hp->ioc_regs+HP_ZX1_IBASE);
readl(hp->ioc_regs+HP_ZX1_IBASE);
- writel(hp->iova_base|log2(HP_ZX1_IOVA_SIZE), hp->ioc_regs+HP_ZX1_PCOM);
+ writel(hp->iova_base|ilog2(HP_ZX1_IOVA_SIZE), hp->ioc_regs+HP_ZX1_PCOM);
readl(hp->ioc_regs+HP_ZX1_PCOM);
}
@@ -285,7 +282,7 @@ hp_zx1_tlbflush (struct agp_memory *mem)
{
struct _hp_private *hp = &hp_private;
- writeq(hp->gart_base | log2(hp->gart_size), hp->ioc_regs+HP_ZX1_PCOM);
+ writeq(hp->gart_base | ilog2(hp->gart_size), hp->ioc_regs+HP_ZX1_PCOM);
readq(hp->ioc_regs+HP_ZX1_PCOM);
}
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 75d2aca6353..e72a83e2bad 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -13,6 +13,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/agp_backend.h>
+#include <linux/log2.h>
#include "agp.h"
@@ -59,8 +60,6 @@
*/
#define WR_FLUSH_GATT(index) RD_GATT(index)
-#define log2(x) ffz(~(x))
-
static struct {
void *gatt; /* ioremap'd GATT area */
@@ -148,7 +147,7 @@ static int i460_fetch_size (void)
* values[i].size.
*/
values[i].num_entries = (values[i].size << 8) >> (I460_IO_PAGE_SHIFT - 12);
- values[i].page_order = log2((sizeof(u32)*values[i].num_entries) >> PAGE_SHIFT);
+ values[i].page_order = ilog2((sizeof(u32)*values[i].num_entries) >> PAGE_SHIFT);
}
for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
@@ -536,10 +535,10 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge)
return page;
}
-static void i460_destroy_page (void *page)
+static void i460_destroy_page (void *page, int flags)
{
if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) {
- agp_generic_destroy_page(page);
+ agp_generic_destroy_page(page, flags);
global_flush_tlb();
}
}
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 141ca176c39..d87961993cc 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -400,9 +400,11 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
if (curr->page_count == 4)
i8xx_destroy_pages(gart_to_virt(curr->memory[0]));
else {
- agp_bridge->driver->agp_destroy_page(
- gart_to_virt(curr->memory[0]));
+ agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
+ AGP_PAGE_DESTROY_UNMAP);
global_flush_tlb();
+ agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
+ AGP_PAGE_DESTROY_FREE);
}
agp_free_page_array(curr);
}
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index f4562cc2234..2939e3570f9 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/klist.h>
#include <linux/agp_backend.h>
+#include <linux/log2.h>
#include <asm-parisc/parisc-device.h>
#include <asm-parisc/ropes.h>
@@ -27,10 +28,6 @@
#define DRVNAME "quicksilver"
#define DRVPFX DRVNAME ": "
-#ifndef log2
-#define log2(x) ffz(~(x))
-#endif
-
#define AGP8X_MODE_BIT 3
#define AGP8X_MODE (1 << AGP8X_MODE_BIT)
@@ -92,7 +89,7 @@ parisc_agp_tlbflush(struct agp_memory *mem)
{
struct _parisc_agp_info *info = &parisc_agp_info;
- writeq(info->gart_base | log2(info->gart_size), info->ioc_regs+IOC_PCOM);
+ writeq(info->gart_base | ilog2(info->gart_size), info->ioc_regs+IOC_PCOM);
readq(info->ioc_regs+IOC_PCOM); /* flush */
}
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index ec116df919d..c99e43b837f 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -18,7 +18,7 @@
#include <linux/apm_bios.h>
#include <linux/capability.h>
#include <linux/sched.h>
-#include <linux/pm.h>
+#include <linux/suspend.h>
#include <linux/apm-emulation.h>
#include <linux/freezer.h>
#include <linux/device.h>
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index 4b3916f5490..6b104e45a32 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -494,12 +494,11 @@ int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
if (p && p->readonly) return -EIO;
if (!p || --p->refcount) {
- q = kmalloc(sizeof(*p), GFP_KERNEL);
+ q = kzalloc(sizeof(*p), GFP_KERNEL);
if (!q) {
if (p) p->refcount++;
return -ENOMEM;
}
- memset(q, 0, sizeof(*q));
q->refcount=1;
*vc->vc_uni_pagedir_loc = (unsigned long)q;
} else {
@@ -670,19 +669,29 @@ void con_protect_unimap(struct vc_data *vc, int rdonly)
p->readonly = rdonly;
}
+/*
+ * Always use USER_MAP. These functions are used by the keyboard,
+ * which shouldn't be affected by G0/G1 switching, etc.
+ * If the user map still contains default values, i.e. the
+ * direct-to-font mapping, then assume user is using Latin1.
+ */
/* may be called during an interrupt */
u32 conv_8bit_to_uni(unsigned char c)
{
- /*
- * Always use USER_MAP. This function is used by the keyboard,
- * which shouldn't be affected by G0/G1 switching, etc.
- * If the user map still contains default values, i.e. the
- * direct-to-font mapping, then assume user is using Latin1.
- */
unsigned short uni = translations[USER_MAP][c];
return uni == (0xf000 | c) ? c : uni;
}
+int conv_uni_to_8bit(u32 uni)
+{
+ int c;
+ for (c = 0; c < 0x100; c++)
+ if (translations[USER_MAP][c] == uni ||
+ (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
+ return c;
+ return -1;
+}
+
int
conv_uni_to_pc(struct vc_data *conp, long ucs)
{
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 9e0adfe27c1..e4f579c3e24 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -359,7 +359,7 @@
*
* Revision 1.36.3.8 1996/06/07 16:29:00 bentson
* starting minor number at zero; added missing verify_area
- * as noted by Heiko Eissfeldt <heiko@colossus.escape.de>
+ * as noted by Heiko Eißfeldt <heiko@colossus.escape.de>
*
* Revision 1.36.3.7 1996/04/19 21:06:18 bentson
* remove unneeded boot message & fix CLOCAL hardware flow
@@ -662,7 +662,7 @@
static void cy_throttle(struct tty_struct *tty);
static void cy_send_xchar(struct tty_struct *tty, char ch);
-#define IS_CYC_Z(card) ((card).num_chips == -1)
+#define IS_CYC_Z(card) ((card).num_chips == (unsigned int)-1)
#define Z_FPGA_CHECK(card) \
((readl(&((struct RUNTIME_9060 __iomem *) \
@@ -727,8 +727,6 @@ static struct tty_driver *cy_serial_driver;
driver to probe addresses at a different address, add it to
this table. If the driver is probing some other board and
causing problems, remove the offending address from this table.
- The cy_setup function extracts additional addresses from the
- boot options line. The form is "cyclades=address,address..."
*/
static unsigned int cy_isa_addresses[] = {
@@ -897,71 +895,6 @@ static inline int serial_paranoia_check(struct cyclades_port *info,
return 0;
} /* serial_paranoia_check */
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver
- * (also known as the "bottom half"). This can be called any
- * number of times for any channel without harm.
- */
-static inline void cy_sched_event(struct cyclades_port *info, int event)
-{
- info->event |= 1 << event; /* remember what kind of event and who */
- schedule_work(&info->tqueue);
-} /* cy_sched_event */
-
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using cy_sched_event(), and they get done here.
- *
- * This is done through one level of indirection--the task queue.
- * When a hardware interrupt service routine wants service by the
- * driver's bottom half, it enqueues the appropriate tq_struct (one
- * per port) to the keventd work queue and sets a request flag
- * that the work queue be processed.
- *
- * Although this may seem unwieldy, it gives the system a way to
- * pass an argument (in this case the pointer to the cyclades_port
- * structure) to the bottom half of the driver. Previous kernels
- * had to poll every port to see if that port needed servicing.
- */
-static void
-do_softint(struct work_struct *work)
-{
- struct cyclades_port *info =
- container_of(work, struct cyclades_port, tqueue);
- struct tty_struct *tty;
-
- tty = info->tty;
- if (!tty)
- return;
-
- if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) {
- tty_hangup(info->tty);
- wake_up_interruptible(&info->open_wait);
- info->flags &= ~ASYNC_NORMAL_ACTIVE;
- }
- if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event))
- wake_up_interruptible(&info->open_wait);
-#ifdef CONFIG_CYZ_INTR
- if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event) &&
- !timer_pending(&cyz_rx_full_timer[info->line]))
- mod_timer(&cyz_rx_full_timer[info->line], jiffies + 1);
-#endif
- if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event))
- wake_up_interruptible(&info->delta_msr_wait);
- tty_wakeup(tty);
-#ifdef Z_WAKE
- if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event))
- complete(&info->shutdown_wait);
-#endif
-} /* do_softint */
-
-
/***********************************************************/
/********* Start of block of Cyclom-Y specific code ********/
@@ -1045,382 +978,332 @@ static unsigned detect_isa_irq(void __iomem * address)
}
#endif /* CONFIG_ISA */
-static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
- void __iomem * base_addr, int status, int index)
+static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
+ void __iomem *base_addr)
{
struct cyclades_port *info;
struct tty_struct *tty;
- int char_count;
- int j, len, mdm_change, mdm_status, outch;
- int save_xir, channel, save_car;
- char data;
+ int len, index = cinfo->bus_index;
+ u8 save_xir, channel, save_car, data, char_count;
- if (status & CySRReceive) { /* reception interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
+ printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
#endif
- /* determine the channel & change to that context */
- spin_lock(&cinfo->card_lock);
- save_xir = (u_char) readb(base_addr + (CyRIR << index));
- channel = (u_short) (save_xir & CyIRChannel);
- info = &cinfo->ports[channel + chip * 4];
- save_car = readb(base_addr + (CyCAR << index));
- cy_writeb(base_addr + (CyCAR << index), save_xir);
-
- /* if there is nowhere to put the data, discard it */
- if (info->tty == NULL) {
- j = (readb(base_addr + (CyRIVR << index)) &
- CyIVRMask);
- if (j == CyIVRRxEx) { /* exception */
+ /* determine the channel & change to that context */
+ save_xir = readb(base_addr + (CyRIR << index));
+ channel = save_xir & CyIRChannel;
+ info = &cinfo->ports[channel + chip * 4];
+ save_car = readb(base_addr + (CyCAR << index));
+ cy_writeb(base_addr + (CyCAR << index), save_xir);
+
+ /* if there is nowhere to put the data, discard it */
+ if (info->tty == NULL) {
+ if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
+ CyIVRRxEx) { /* exception */
+ data = readb(base_addr + (CyRDSR << index));
+ } else { /* normal character reception */
+ char_count = readb(base_addr + (CyRDCR << index));
+ while (char_count--)
data = readb(base_addr + (CyRDSR << index));
- } else { /* normal character reception */
- char_count = readb(base_addr +
- (CyRDCR << index));
- while (char_count--) {
- data = readb(base_addr +
- (CyRDSR << index));
- }
- }
- } else { /* there is an open port for this data */
- tty = info->tty;
- j = (readb(base_addr + (CyRIVR << index)) &
- CyIVRMask);
- if (j == CyIVRRxEx) { /* exception */
- data = readb(base_addr + (CyRDSR << index));
-
- /* For statistics only */
- if (data & CyBREAK)
- info->icount.brk++;
- else if (data & CyFRAME)
- info->icount.frame++;
- else if (data & CyPARITY)
- info->icount.parity++;
- else if (data & CyOVERRUN)
- info->icount.overrun++;
-
- if (data & info->ignore_status_mask) {
+ }
+ goto end;
+ }
+ /* there is an open port for this data */
+ tty = info->tty;
+ if ((readb(base_addr + (CyRIVR << index)) & CyIVRMask) ==
+ CyIVRRxEx) { /* exception */
+ data = readb(base_addr + (CyRDSR << index));
+
+ /* For statistics only */
+ if (data & CyBREAK)
+ info->icount.brk++;
+ else if (data & CyFRAME)
+ info->icount.frame++;
+ else if (data & CyPARITY)
+ info->icount.parity++;
+ else if (data & CyOVERRUN)
+ info->icount.overrun++;
+
+ if (data & info->ignore_status_mask) {
+ info->icount.rx++;
+ return;
+ }
+ if (tty_buffer_request_room(tty, 1)) {
+ if (data & info->read_status_mask) {
+ if (data & CyBREAK) {
+ tty_insert_flip_char(tty,
+ readb(base_addr + (CyRDSR <<
+ index)), TTY_BREAK);
+ info->icount.rx++;
+ if (info->flags & ASYNC_SAK)
+ do_SAK(tty);
+ } else if (data & CyFRAME) {
+ tty_insert_flip_char( tty,
+ readb(base_addr + (CyRDSR <<
+ index)), TTY_FRAME);
+ info->icount.rx++;
+ info->idle_stats.frame_errs++;
+ } else if (data & CyPARITY) {
+ /* Pieces of seven... */
+ tty_insert_flip_char(tty,
+ readb(base_addr + (CyRDSR <<
+ index)), TTY_PARITY);
+ info->icount.rx++;
+ info->idle_stats.parity_errs++;
+ } else if (data & CyOVERRUN) {
+ tty_insert_flip_char(tty, 0,
+ TTY_OVERRUN);
+ info->icount.rx++;
+ /* If the flip buffer itself is
+ overflowing, we still lose
+ the next incoming character.
+ */
+ tty_insert_flip_char(tty,
+ readb(base_addr + (CyRDSR <<
+ index)), TTY_FRAME);
info->icount.rx++;
- spin_unlock(&cinfo->card_lock);
- return;
- }
- if (tty_buffer_request_room(tty, 1)) {
- if (data & info->read_status_mask) {
- if (data & CyBREAK) {
- tty_insert_flip_char(
- tty,
- readb(
- base_addr +
- (CyRDSR <<
- index)),
- TTY_BREAK);
- info->icount.rx++;
- if (info->flags &
- ASYNC_SAK) {
- do_SAK(tty);
- }
- } else if (data & CyFRAME) {
- tty_insert_flip_char(
- tty,
- readb(
- base_addr +
- (CyRDSR <<
- index)),
- TTY_FRAME);
- info->icount.rx++;
- info->idle_stats.
- frame_errs++;
- } else if (data & CyPARITY) {
- /* Pieces of seven... */
- tty_insert_flip_char(
- tty,
- readb(
- base_addr +
- (CyRDSR <<
- index)),
- TTY_PARITY);
- info->icount.rx++;
- info->idle_stats.
- parity_errs++;
- } else if (data & CyOVERRUN) {
- tty_insert_flip_char(
- tty, 0,
- TTY_OVERRUN);
- info->icount.rx++;
- /* If the flip buffer itself is
- overflowing, we still lose
- the next incoming character.
- */
- tty_insert_flip_char(
- tty,
- readb(
- base_addr +
- (CyRDSR <<
- index)),
- TTY_FRAME);
- info->icount.rx++;
- info->idle_stats.
- overruns++;
- /* These two conditions may imply */
- /* a normal read should be done. */
- /* }else if(data & CyTIMEOUT){ */
- /* }else if(data & CySPECHAR){ */
- } else {
- tty_insert_flip_char(
- tty, 0,
- TTY_NORMAL);
- info->icount.rx++;
- }
- } else {
- tty_insert_flip_char(tty, 0,
- TTY_NORMAL);
- info->icount.rx++;
- }
- } else {
- /* there was a software buffer
- overrun and nothing could be
- done about it!!! */
- info->icount.buf_overrun++;
info->idle_stats.overruns++;
+ /* These two conditions may imply */
+ /* a normal read should be done. */
+ /* } else if(data & CyTIMEOUT) { */
+ /* } else if(data & CySPECHAR) { */
+ } else {
+ tty_insert_flip_char(tty, 0,
+ TTY_NORMAL);
+ info->icount.rx++;
}
- } else { /* normal character reception */
- /* load # chars available from the chip */
- char_count = readb(base_addr +
- (CyRDCR << index));
+ } else {
+ tty_insert_flip_char(tty, 0, TTY_NORMAL);
+ info->icount.rx++;
+ }
+ } else {
+ /* there was a software buffer overrun and nothing
+ * could be done about it!!! */
+ info->icount.buf_overrun++;
+ info->idle_stats.overruns++;
+ }
+ } else { /* normal character reception */
+ /* load # chars available from the chip */
+ char_count = readb(base_addr + (CyRDCR << index));
#ifdef CY_ENABLE_MONITORING
- ++info->mon.int_count;
- info->mon.char_count += char_count;
- if (char_count > info->mon.char_max)
- info->mon.char_max = char_count;
- info->mon.char_last = char_count;
+ ++info->mon.int_count;
+ info->mon.char_count += char_count;
+ if (char_count > info->mon.char_max)
+ info->mon.char_max = char_count;
+ info->mon.char_last = char_count;
#endif
- len = tty_buffer_request_room(tty, char_count);
- while (len--) {
- data = readb(base_addr +
- (CyRDSR << index));
- tty_insert_flip_char(tty, data,
- TTY_NORMAL);
- info->idle_stats.recv_bytes++;
- info->icount.rx++;
+ len = tty_buffer_request_room(tty, char_count);
+ while (len--) {
+ data = readb(base_addr + (CyRDSR << index));
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
+ info->idle_stats.recv_bytes++;
+ info->icount.rx++;
#ifdef CY_16Y_HACK
- udelay(10L);
+ udelay(10L);
#endif
- }
- info->idle_stats.recv_idle = jiffies;
- }
- tty_schedule_flip(tty);
}
- /* end of service */
- cy_writeb(base_addr + (CyRIR << index), (save_xir & 0x3f));
- cy_writeb(base_addr + (CyCAR << index), (save_car));
- spin_unlock(&cinfo->card_lock);
+ info->idle_stats.recv_idle = jiffies;
}
+ tty_schedule_flip(tty);
+end:
+ /* end of service */
+ cy_writeb(base_addr + (CyRIR << index), save_xir & 0x3f);
+ cy_writeb(base_addr + (CyCAR << index), save_car);
+}
+
+static void cyy_chip_tx(struct cyclades_card *cinfo, unsigned int chip,
+ void __iomem *base_addr)
+{
+ struct cyclades_port *info;
+ int char_count, index = cinfo->bus_index;
+ u8 save_xir, channel, save_car, outch;
- if (status & CySRTransmit) { /* transmission interrupt */
- /* Since we only get here when the transmit buffer
- is empty, we know we can always stuff a dozen
- characters. */
+ /* Since we only get here when the transmit buffer
+ is empty, we know we can always stuff a dozen
+ characters. */
#ifdef CY_DEBUG_INTERRUPTS
- printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
+ printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
#endif
- /* determine the channel & change to that context */
- spin_lock(&cinfo->card_lock);
- save_xir = (u_char) readb(base_addr + (CyTIR << index));
- channel = (u_short) (save_xir & CyIRChannel);
- save_car = readb(base_addr + (CyCAR << index));
- cy_writeb(base_addr + (CyCAR << index), save_xir);
+ /* determine the channel & change to that context */
+ save_xir = readb(base_addr + (CyTIR << index));
+ channel = save_xir & CyIRChannel;
+ save_car = readb(base_addr + (CyCAR << index));
+ cy_writeb(base_addr + (CyCAR << index), save_xir);
- /* validate the port# (as configured and open) */
- if (channel + chip * 4 >= cinfo->nports) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) &
- ~CyTxRdy);
- goto txend;
- }
- info = &cinfo->ports[channel + chip * 4];
- if (info->tty == NULL) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) &
- ~CyTxRdy);
- goto txdone;
- }
+ /* validate the port# (as configured and open) */
+ if (channel + chip * 4 >= cinfo->nports) {
+ cy_writeb(base_addr + (CySRER << index),
+ readb(base_addr + (CySRER << index)) & ~CyTxRdy);
+ goto end;
+ }
+ info = &cinfo->ports[channel + chip * 4];
+ if (info->tty == NULL) {
+ cy_writeb(base_addr + (CySRER << index),
+ readb(base_addr + (CySRER << index)) & ~CyTxRdy);
+ goto end;
+ }
- /* load the on-chip space for outbound data */
- char_count = info->xmit_fifo_size;
+ /* load the on-chip space for outbound data */
+ char_count = info->xmit_fifo_size;
- if (info->x_char) { /* send special char */
- outch = info->x_char;
- cy_writeb(base_addr + (CyTDR << index), outch);
- char_count--;
- info->icount.tx++;
- info->x_char = 0;
- }
+ if (info->x_char) { /* send special char */
+ outch = info->x_char;
+ cy_writeb(base_addr + (CyTDR << index), outch);
+ char_count--;
+ info->icount.tx++;
+ info->x_char = 0;
+ }
- if (info->breakon || info->breakoff) {
- if (info->breakon) {
- cy_writeb(base_addr + (CyTDR << index), 0);
- cy_writeb(base_addr + (CyTDR << index), 0x81);
- info->breakon = 0;
- char_count -= 2;
- }
- if (info->breakoff) {
- cy_writeb(base_addr + (CyTDR << index), 0);
- cy_writeb(base_addr + (CyTDR << index), 0x83);
- info->breakoff = 0;
- char_count -= 2;
- }
+ if (info->breakon || info->breakoff) {
+ if (info->breakon) {
+ cy_writeb(base_addr + (CyTDR << index), 0);
+ cy_writeb(base_addr + (CyTDR << index), 0x81);
+ info->breakon = 0;
+ char_count -= 2;
+ }
+ if (info->breakoff) {
+ cy_writeb(base_addr + (CyTDR << index), 0);
+ cy_writeb(base_addr + (CyTDR << index), 0x83);
+ info->breakoff = 0;
+ char_count -= 2;
}
+ }
- while (char_count-- > 0) {
- if (!info->xmit_cnt) {
- if (readb(base_addr + (CySRER << index)) &
- CyTxMpty) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr +
- (CySRER << index)) &
+ while (char_count-- > 0) {
+ if (!info->xmit_cnt) {
+ if (readb(base_addr + (CySRER << index)) & CyTxMpty) {
+ cy_writeb(base_addr + (CySRER << index),
+ readb(base_addr + (CySRER << index)) &
~CyTxMpty);
- } else {
- cy_writeb(base_addr + (CySRER << index),
- (readb(base_addr +
- (CySRER << index)) &
+ } else {
+ cy_writeb(base_addr + (CySRER << index),
+ (readb(base_addr + (CySRER << index)) &
~CyTxRdy) | CyTxMpty);
- }
- goto txdone;
}
- if (info->xmit_buf == NULL) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) &
+ goto done;
+ }
+ if (info->xmit_buf == NULL) {
+ cy_writeb(base_addr + (CySRER << index),
+ readb(base_addr + (CySRER << index)) &
~CyTxRdy);
- goto txdone;
- }
- if (info->tty->stopped || info->tty->hw_stopped) {
- cy_writeb(base_addr + (CySRER << index),
- readb(base_addr + (CySRER << index)) &
+ goto done;
+ }
+ if (info->tty->stopped || info->tty->hw_stopped) {
+ cy_writeb(base_addr + (CySRER << index),
+ readb(base_addr + (CySRER << index)) &
~CyTxRdy);
- goto txdone;
- }
- /* Because the Embedded Transmit Commands have
- been enabled, we must check to see if the
- escape character, NULL, is being sent. If it
- is, we must ensure that there is room for it
- to be doubled in the output stream. Therefore
- we no longer advance the pointer when the
- character is fetched, but rather wait until
- after the check for a NULL output character.
- This is necessary because there may not be
- room for the two chars needed to send a NULL.)
- */
- outch = info->xmit_buf[info->xmit_tail];
- if (outch) {
+ goto done;
+ }
+ /* Because the Embedded Transmit Commands have been enabled,
+ * we must check to see if the escape character, NULL, is being
+ * sent. If it is, we must ensure that there is room for it to
+ * be doubled in the output stream. Therefore we no longer
+ * advance the pointer when the character is fetched, but
+ * rather wait until after the check for a NULL output
+ * character. This is necessary because there may not be room
+ * for the two chars needed to send a NULL.)
+ */
+ outch = info->xmit_buf[info->xmit_tail];
+ if (outch) {
+ info->xmit_cnt--;
+ info->xmit_tail = (info->xmit_tail + 1) &
+ (SERIAL_XMIT_SIZE - 1);
+ cy_writeb(base_addr + (CyTDR << index), outch);
+ info->icount.tx++;
+ } else {
+ if (char_count > 1) {
info->xmit_cnt--;
info->xmit_tail = (info->xmit_tail + 1) &
- (SERIAL_XMIT_SIZE - 1);
+ (SERIAL_XMIT_SIZE - 1);
cy_writeb(base_addr + (CyTDR << index), outch);
+ cy_writeb(base_addr + (CyTDR << index), 0);
info->icount.tx++;
- } else {
- if (char_count > 1) {
- info->xmit_cnt--;
- info->xmit_tail = (info->xmit_tail + 1)&
- (SERIAL_XMIT_SIZE - 1);
- cy_writeb(base_addr + (CyTDR << index),
- outch);
- cy_writeb(base_addr + (CyTDR << index),
- 0);
- info->icount.tx++;
- char_count--;
- }
+ char_count--;
}
}
-
-txdone:
- if (info->xmit_cnt < WAKEUP_CHARS) {
- cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
- }
-txend:
- /* end of service */
- cy_writeb(base_addr + (CyTIR << index), (save_xir & 0x3f));
- cy_writeb(base_addr + (CyCAR << index), (save_car));
- spin_unlock(&cinfo->card_lock);
}
- if (status & CySRModem) { /* modem interrupt */
+done:
+ tty_wakeup(info->tty);
+end:
+ /* end of service */
+ cy_writeb(base_addr + (CyTIR << index), save_xir & 0x3f);
+ cy_writeb(base_addr + (CyCAR << index), save_car);
+}
- /* determine the channel & change to that context */
- spin_lock(&cinfo->card_lock);
- save_xir = (u_char) readb(base_addr + (CyMIR << index));
- channel = (u_short) (save_xir & CyIRChannel);
- info = &cinfo->ports[channel + chip * 4];
- save_car = readb(base_addr + (CyCAR << index));
- cy_writeb(base_addr + (CyCAR << index), save_xir);
+static void cyy_chip_modem(struct cyclades_card *cinfo, int chip,
+ void __iomem *base_addr)
+{
+ struct cyclades_port *info;
+ int index = cinfo->bus_index;
+ u8 save_xir, channel, save_car, mdm_change, mdm_status;
- mdm_change = readb(base_addr + (CyMISR << index));
- mdm_status = readb(base_addr + (CyMSVR1 << index));
+ /* determine the channel & change to that context */
+ save_xir = readb(base_addr + (CyMIR << index));
+ channel = save_xir & CyIRChannel;
+ info = &cinfo->ports[channel + chip * 4];
+ save_car = readb(base_addr + (CyCAR << index));
+ cy_writeb(base_addr + (CyCAR << index), save_xir);
- if (info->tty) {
- if (mdm_change & CyANY_DELTA) {
- /* For statistics only */
- if (mdm_change & CyDCD)
- info->icount.dcd++;
- if (mdm_change & CyCTS)
- info->icount.cts++;
- if (mdm_change & CyDSR)
- info->icount.dsr++;
- if (mdm_change & CyRI)
- info->icount.rng++;
-
- cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
- }
+ mdm_change = readb(base_addr + (CyMISR << index));
+ mdm_status = readb(base_addr + (CyMSVR1 << index));
- if ((mdm_change & CyDCD) &&
- (info->flags & ASYNC_CHECK_CD)) {
- if (mdm_status & CyDCD) {
- cy_sched_event(info,
- Cy_EVENT_OPEN_WAKEUP);
- } else {
- cy_sched_event(info, Cy_EVENT_HANGUP);
- }
- }
- if ((mdm_change & CyCTS) &&
- (info->flags & ASYNC_CTS_FLOW)) {
- if (info->tty->hw_stopped) {
- if (mdm_status & CyCTS) {
- /* cy_start isn't used
- because... !!! */
- info->tty->hw_stopped = 0;
- cy_writeb(base_addr +
- (CySRER << index),
- readb(base_addr +
- (CySRER <<
- index))|
- CyTxRdy);
- cy_sched_event(info,
- Cy_EVENT_WRITE_WAKEUP);
- }
- } else {
- if (!(mdm_status & CyCTS)) {
- /* cy_stop isn't used
- because ... !!! */
- info->tty->hw_stopped = 1;
- cy_writeb(base_addr +
- (CySRER << index),
- readb(base_addr +
- (CySRER <<
- index)) &
- ~CyTxRdy);
- }
- }
+ if (!info->tty)
+ goto end;
+
+ if (mdm_change & CyANY_DELTA) {
+ /* For statistics only */
+ if (mdm_change & CyDCD)
+ info->icount.dcd++;
+ if (mdm_change & CyCTS)
+ info->icount.cts++;
+ if (mdm_change & CyDSR)
+ info->icount.dsr++;
+ if (mdm_change & CyRI)
+ info->icount.rng++;
+
+ wake_up_interruptible(&info->delta_msr_wait);
+ }
+
+ if ((mdm_change & CyDCD) && (info->flags & ASYNC_CHECK_CD)) {
+ if (!(mdm_status & CyDCD)) {
+ tty_hangup(info->tty);
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+ if ((mdm_change & CyCTS) && (info->flags & ASYNC_CTS_FLOW)) {
+ if (info->tty->hw_stopped) {
+ if (mdm_status & CyCTS) {
+ /* cy_start isn't used
+ because... !!! */
+ info->tty->hw_stopped = 0;
+ cy_writeb(base_addr + (CySRER << index),
+ readb(base_addr + (CySRER << index)) |
+ CyTxRdy);
+ tty_wakeup(info->tty);
}
-/* if (mdm_change & CyDSR) {
+ } else {
+ if (!(mdm_status & CyCTS)) {
+ /* cy_stop isn't used
+ because ... !!! */
+ info->tty->hw_stopped = 1;
+ cy_writeb(base_addr + (CySRER << index),
+ readb(base_addr + (CySRER << index)) &
+ ~CyTxRdy);
}
- if (mdm_change & CyRI) {
- }*/
}
- /* end of service */
- cy_writeb(base_addr + (CyMIR << index), (save_xir & 0x3f));
- cy_writeb(base_addr + (CyCAR << index), save_car);
- spin_unlock(&cinfo->card_lock);
}
+/* if (mdm_change & CyDSR) {
+ }
+ if (mdm_change & CyRI) {
+ }*/
+end:
+ /* end of service */
+ cy_writeb(base_addr + (CyMIR << index), save_xir & 0x3f);
+ cy_writeb(base_addr + (CyCAR << index), save_car);
}
/* The real interrupt service routine is called
@@ -1432,10 +1315,8 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
int status;
struct cyclades_card *cinfo = dev_id;
void __iomem *base_addr, *card_base_addr;
- int chip;
+ unsigned int chip, too_many, had_work;
int index;
- int too_many;
- int had_work;
if (unlikely(cinfo == NULL)) {
#ifdef CY_DEBUG_INTERRUPTS
@@ -1470,11 +1351,16 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
chips to be checked in a round-robin fashion (after
draining each of a bunch (1000) of characters).
*/
- if (1000 < too_many++) {
+ if (1000 < too_many++)
break;
- }
- cyy_intr_chip(cinfo, chip, base_addr, status,
- index);
+ spin_lock(&cinfo->card_lock);
+ if (status & CySRReceive) /* rx intr */
+ cyy_chip_rx(cinfo, chip, base_addr);
+ if (status & CySRTransmit) /* tx intr */
+ cyy_chip_tx(cinfo, chip, base_addr);
+ if (status & CySRModem) /* modem intr */
+ cyy_chip_modem(cinfo, chip, base_addr);
+ spin_unlock(&cinfo->card_lock);
}
}
} while (had_work);
@@ -1529,7 +1415,7 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
struct ZFW_CTRL __iomem *zfw_ctrl;
struct BOARD_CTRL __iomem *board_ctrl;
__u32 __iomem *pci_doorbell;
- int index;
+ unsigned int index;
firm_id = cinfo->base_addr + ID_ADDRESS;
if (!ISZLOADED(*cinfo)) {
@@ -1554,13 +1440,12 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
return 0;
} /* cyz_issue_cmd */
-static void
-cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
+static void cyz_handle_rx(struct cyclades_port *info,
struct BUF_CTRL __iomem *buf_ctrl)
{
struct cyclades_card *cinfo = info->card;
struct tty_struct *tty = info->tty;
- int char_count;
+ unsigned int char_count;
int len;
#ifdef BLOCKMOVE
unsigned char *buf;
@@ -1633,9 +1518,11 @@ cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
char_count = rx_put - rx_get;
else
char_count = rx_put - rx_get + rx_bufsize;
- if (char_count >= (int)readl(&buf_ctrl->rx_threshold)) {
- cy_sched_event(info, Cy_EVENT_Z_RX_FULL);
- }
+ if (char_count >= readl(&buf_ctrl->rx_threshold) &&
+ !timer_pending(&cyz_rx_full_timer[
+ info->line]))
+ mod_timer(&cyz_rx_full_timer[info->line],
+ jiffies + 1);
#endif
info->idle_stats.recv_idle = jiffies;
tty_schedule_flip(tty);
@@ -1645,14 +1532,13 @@ cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
}
}
-static void
-cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
+static void cyz_handle_tx(struct cyclades_port *info,
struct BUF_CTRL __iomem *buf_ctrl)
{
struct cyclades_card *cinfo = info->card;
struct tty_struct *tty = info->tty;
- char data;
- int char_count;
+ u8 data;
+ unsigned int char_count;
#ifdef BLOCKMOVE
int small_count;
#endif
@@ -1716,10 +1602,8 @@ cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
info->icount.tx++;
}
#endif
+ tty_wakeup(tty);
ztxdone:
- if (info->xmit_cnt < WAKEUP_CHARS) {
- cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP);
- }
/* Update tx_put */
cy_writel(&buf_ctrl->tx_put, tx_put);
}
@@ -1781,10 +1665,11 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
if ((fw_ver > 241 ? ((u_long) param) :
readl(&ch_ctrl->rs_status)) &
C_RS_DCD) {
- cy_sched_event(info,
- Cy_EVENT_OPEN_WAKEUP);
+ wake_up_interruptible(&info->open_wait);
} else {
- cy_sched_event(info, Cy_EVENT_HANGUP);
+ tty_hangup(info->tty);
+ wake_up_interruptible(&info->open_wait);
+ info->flags &= ~ASYNC_NORMAL_ACTIVE;
}
}
break;
@@ -1802,7 +1687,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
break;
#ifdef Z_WAKE
case C_CM_IOCTLW:
- cy_sched_event(info, Cy_EVENT_SHUTDOWN_WAKEUP);
+ complete(&info->shutdown_wait);
break;
#endif
#ifdef CONFIG_CYZ_INTR
@@ -1814,7 +1699,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
"port %ld\n", info->card, channel);
#endif
- cyz_handle_rx(info, ch_ctrl, buf_ctrl);
+ cyz_handle_rx(info, buf_ctrl);
break;
case C_CM_TXBEMPTY:
case C_CM_TXLOWWM:
@@ -1824,7 +1709,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
"port %ld\n", info->card, channel);
#endif
- cyz_handle_tx(info, ch_ctrl, buf_ctrl);
+ cyz_handle_tx(info, buf_ctrl);
break;
#endif /* CONFIG_CYZ_INTR */
case C_CM_FATAL:
@@ -1834,7 +1719,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
break;
}
if (delta_count)
- cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
+ wake_up_interruptible(&info->delta_msr_wait);
if (special_count)
tty_schedule_flip(tty);
}
@@ -1893,10 +1778,9 @@ static void cyz_poll(unsigned long arg)
struct FIRM_ID __iomem *firm_id;
struct ZFW_CTRL __iomem *zfw_ctrl;
struct BOARD_CTRL __iomem *board_ctrl;
- struct CH_CTRL __iomem *ch_ctrl;
struct BUF_CTRL __iomem *buf_ctrl;
unsigned long expires = jiffies + HZ;
- int card, port;
+ unsigned int port, card;
for (card = 0; card < NR_CARDS; card++) {
cinfo = &cy_card[card];
@@ -1923,12 +1807,11 @@ static void cyz_poll(unsigned long arg)
for (port = 0; port < cinfo->nports; port++) {
info = &cinfo->ports[port];
tty = info->tty;
- ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
if (!info->throttle)
- cyz_handle_rx(info, ch_ctrl, buf_ctrl);
- cyz_handle_tx(info, ch_ctrl, buf_ctrl);
+ cyz_handle_rx(info, buf_ctrl);
+ cyz_handle_tx(info, buf_ctrl);
}
/* poll every 'cyz_polling_cycle' period */
expires = jiffies + cyz_polling_cycle;
@@ -2491,11 +2374,11 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
static int cy_open(struct tty_struct *tty, struct file *filp)
{
struct cyclades_port *info;
- unsigned int i;
- int retval, line;
+ unsigned int i, line;
+ int retval;
line = tty->index;
- if ((line < 0) || (NR_PORTS <= line)) {
+ if ((tty->index < 0) || (NR_PORTS <= line)) {
return -ENODEV;
}
for (i = 0; i < NR_CARDS; i++)
@@ -2812,7 +2695,6 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&card->card_lock, flags);
tty->closing = 0;
- info->event = 0;
info->tty = NULL;
if (info->blocked_open) {
spin_unlock_irqrestore(&card->card_lock, flags);
@@ -4444,7 +4326,6 @@ static void cy_hangup(struct tty_struct *tty)
cy_flush_buffer(tty);
shutdown(info);
- info->event = 0;
info->count = 0;
#ifdef CY_DEBUG_COUNT
printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n",
@@ -4467,9 +4348,9 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
{
struct cyclades_port *info;
u32 uninitialized_var(mailbox);
- unsigned int nports;
+ unsigned int nports, port;
unsigned short chip_number;
- int uninitialized_var(index), port;
+ int uninitialized_var(index);
spin_lock_init(&cinfo->card_lock);
@@ -4502,7 +4383,6 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
info->closing_wait = CLOSING_WAIT_DELAY;
info->close_delay = 5 * HZ / 10;
- INIT_WORK(&info->tqueue, do_softint);
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
init_completion(&info->shutdown_wait);
@@ -5236,7 +5116,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
}
}
#endif /* CONFIG_CYZ_INTR */
- cy_card[card_no].num_chips = -1;
+ cy_card[card_no].num_chips = (unsigned int)-1;
}
/* set cy_card */
@@ -5480,13 +5360,13 @@ static int __init cy_init(void)
#ifdef CONFIG_PCI
/* look for pci boards */
retval = pci_register_driver(&cy_pci_driver);
- if (retval && !nboards)
- goto err_unr;
+ if (retval && !nboards) {
+ tty_unregister_driver(cy_serial_driver);
+ goto err_frtty;
+ }
#endif
return 0;
-err_unr:
- tty_unregister_driver(cy_serial_driver);
err_frtty:
put_tty_driver(cy_serial_driver);
err:
@@ -5496,7 +5376,7 @@ err:
static void __exit cy_cleanup_module(void)
{
struct cyclades_card *card;
- int i, e1;
+ unsigned int i, e1;
#ifndef CONFIG_CYZ_INTR
del_timer_sync(&cyz_timerlist);
@@ -5524,8 +5404,7 @@ static void __exit cy_cleanup_module(void)
#endif /* CONFIG_CYZ_INTR */
)
free_irq(card->irq, card);
- for (e1 = card->first_line;
- e1 < card->first_line +
+ for (e1 = card->first_line; e1 < card->first_line +
card->nports; e1++)
tty_unregister_device(cy_serial_driver, e1);
kfree(card->ports);
diff --git a/drivers/char/defkeymap.c_shipped b/drivers/char/defkeymap.c_shipped
index 453a2f1ffa1..0aa419a6176 100644
--- a/drivers/char/defkeymap.c_shipped
+++ b/drivers/char/defkeymap.c_shipped
@@ -222,7 +222,7 @@ char *func_table[MAX_NR_FUNC] = {
NULL,
};
-struct kbdiacr accent_table[MAX_DIACR] = {
+struct kbdiacruc accent_table[MAX_DIACR] = {
{'`', 'A', '\300'}, {'`', 'a', '\340'},
{'\'', 'A', '\301'}, {'\'', 'a', '\341'},
{'^', 'A', '\302'}, {'^', 'a', '\342'},
diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig
index 0b7ffa5191c..ba3058dd39a 100644
--- a/drivers/char/drm/Kconfig
+++ b/drivers/char/drm/Kconfig
@@ -4,7 +4,7 @@
# This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
#
-config DRM
+menuconfig DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG
help
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 2d6f2d0bd02..82fb3d0d278 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -63,27 +63,9 @@
#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size)
#endif
-#define XFREE86_VERSION(major,minor,patch,snap) \
- ((major << 16) | (minor << 8) | patch)
-
-#ifndef CONFIG_XFREE86_VERSION
-#define CONFIG_XFREE86_VERSION XFREE86_VERSION(4,1,0,0)
-#endif
-
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
-#define DRM_PROC_DEVICES "/proc/devices"
-#define DRM_PROC_MISC "/proc/misc"
-#define DRM_PROC_DRM "/proc/drm"
-#define DRM_DEV_DRM "/dev/drm"
-#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
-#define DRM_DEV_UID 0
-#define DRM_DEV_GID 0
-#endif
-
-#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0)
#define DRM_MAJOR 226
#define DRM_MAX_MINOR 15
-#endif
+
#define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */
#define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */
#define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 0df87fc3dcb..dde02a15fa5 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -80,6 +80,9 @@
#define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE)))
#define __OS_HAS_MTRR (defined(CONFIG_MTRR))
+struct drm_file;
+struct drm_device;
+
#include "drm_os_linux.h"
#include "drm_hashtab.h"
@@ -231,12 +234,13 @@
* \param dev DRM device.
* \param filp file pointer of the caller.
*/
-#define LOCK_TEST_WITH_RETURN( dev, filp ) \
+#define LOCK_TEST_WITH_RETURN( dev, file_priv ) \
do { \
if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \
- dev->lock.filp != filp ) { \
- DRM_ERROR( "%s called without lock held\n", \
- __FUNCTION__ ); \
+ dev->lock.file_priv != file_priv ) { \
+ DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\
+ __FUNCTION__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\
+ dev->lock.file_priv, file_priv ); \
return -EINVAL; \
} \
} while (0)
@@ -257,12 +261,12 @@ do { \
* Ioctl function type.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private pointer.
* \param cmd command.
* \param arg argument.
*/
-typedef int drm_ioctl_t(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+typedef int drm_ioctl_t(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,
unsigned long arg);
@@ -271,10 +275,18 @@ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,
#define DRM_MASTER 0x2
#define DRM_ROOT_ONLY 0x4
-typedef struct drm_ioctl_desc {
+struct drm_ioctl_desc {
+ unsigned int cmd;
drm_ioctl_t *func;
int flags;
-} drm_ioctl_desc_t;
+};
+
+/**
+ * Creates a driver or general drm_ioctl_desc array entry for the given
+ * ioctl, for use by drm_ioctl().
+ */
+#define DRM_IOCTL_DEF(ioctl, func, flags) \
+ [DRM_IOCTL_NR(ioctl)] = {ioctl, func, flags}
struct drm_magic_entry {
struct list_head head;
@@ -304,7 +316,7 @@ struct drm_buf {
__volatile__ int waiting; /**< On kernel DMA queue */
__volatile__ int pending; /**< On hardware DMA queue */
wait_queue_head_t dma_wait; /**< Processes waiting */
- struct file *filp; /**< Pointer to holding file descr */
+ struct drm_file *file_priv; /**< Private of holding file descr */
int context; /**< Kernel queue for this buffer */
int while_locked; /**< Dispatch this buffer while locked */
enum {
@@ -377,6 +389,7 @@ struct drm_file {
int remove_auth_on_close;
unsigned long lock_count;
void *driver_priv;
+ struct file *filp;
};
/** Wait queue */
@@ -403,7 +416,7 @@ struct drm_queue {
*/
struct drm_lock_data {
struct drm_hw_lock *hw_lock; /**< Hardware lock */
- struct file *filp; /**< File descr of lock holder (0=kernel) */
+ struct drm_file *file_priv; /**< File descr of lock holder (0=kernel) */
wait_queue_head_t lock_queue; /**< Queue of blocked processes */
unsigned long lock_time; /**< Time of last lock in jiffies */
spinlock_t spinlock;
@@ -546,17 +559,15 @@ struct drm_mm {
* a family of cards. There will one drm_device for each card present
* in this family
*/
-struct drm_device;
-
struct drm_driver {
int (*load) (struct drm_device *, unsigned long flags);
int (*firstopen) (struct drm_device *);
int (*open) (struct drm_device *, struct drm_file *);
- void (*preclose) (struct drm_device *, struct file * filp);
+ void (*preclose) (struct drm_device *, struct drm_file *file_priv);
void (*postclose) (struct drm_device *, struct drm_file *);
void (*lastclose) (struct drm_device *);
int (*unload) (struct drm_device *);
- int (*dma_ioctl) (DRM_IOCTL_ARGS);
+ int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv);
void (*dma_ready) (struct drm_device *);
int (*dma_quiescent) (struct drm_device *);
int (*context_ctor) (struct drm_device *dev, int context);
@@ -587,11 +598,12 @@ struct drm_driver {
void (*irq_preinstall) (struct drm_device *dev);
void (*irq_postinstall) (struct drm_device *dev);
void (*irq_uninstall) (struct drm_device *dev);
- void (*reclaim_buffers) (struct drm_device *dev, struct file * filp);
+ void (*reclaim_buffers) (struct drm_device *dev,
+ struct drm_file * file_priv);
void (*reclaim_buffers_locked) (struct drm_device *dev,
- struct file *filp);
+ struct drm_file *file_priv);
void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
- struct file * filp);
+ struct drm_file *file_priv);
unsigned long (*get_map_ofs) (struct drm_map * map);
unsigned long (*get_reg_ofs) (struct drm_device *dev);
void (*set_version) (struct drm_device *dev,
@@ -606,7 +618,7 @@ struct drm_driver {
u32 driver_features;
int dev_priv_size;
- drm_ioctl_desc_t *ioctls;
+ struct drm_ioctl_desc *ioctls;
int num_ioctls;
struct file_operations fops;
struct pci_driver pci_driver;
@@ -850,70 +862,70 @@ extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start);
extern int drm_unbind_agp(DRM_AGP_MEM * handle);
/* Misc. IOCTL support (drm_ioctl.h) */
-extern int drm_irq_by_busid(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getunique(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_setunique(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getmap(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getclient(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getstats(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_setversion(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_noop(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_irq_by_busid(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_getunique(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_setunique(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_getmap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_getclient(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_getstats(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_setversion(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_noop(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/* Context IOCTL support (drm_context.h) */
-extern int drm_resctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_addctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_modctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_switchctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_newctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_rmctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_resctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_addctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_modctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_getctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_switchctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_newctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_rmctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_ctxbitmap_init(struct drm_device *dev);
extern void drm_ctxbitmap_cleanup(struct drm_device *dev);
extern void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle);
-extern int drm_setsareactx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_getsareactx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_setsareactx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_getsareactx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/* Drawable IOCTL support (drm_drawable.h) */
-extern int drm_adddraw(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_rmdraw(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_update_drawable_info(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_adddraw(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_rmdraw(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_update_drawable_info(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev,
drm_drawable_t id);
extern void drm_drawable_free_all(struct drm_device *dev);
/* Authentication IOCTL support (drm_auth.h) */
-extern int drm_getmagic(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_authmagic(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_getmagic(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_authmagic(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/* Locking IOCTL support (drm_lock.h) */
-extern int drm_lock(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_unlock(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_lock(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_unlock(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context);
extern int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context);
extern void drm_idlelock_take(struct drm_lock_data *lock_data);
@@ -924,8 +936,7 @@ extern void drm_idlelock_release(struct drm_lock_data *lock_data);
* DMA quiscent + idle. DMA quiescent usually requires the hardware lock.
*/
-extern int drm_i_have_hw_lock(struct file *filp);
-extern int drm_kernel_take_hw_lock(struct file *filp);
+extern int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv);
/* Buffer management support (drm_bufs.h) */
extern int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc * request);
@@ -933,24 +944,23 @@ extern int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc * request
extern int drm_addmap(struct drm_device *dev, unsigned int offset,
unsigned int size, enum drm_map_type type,
enum drm_map_flags flags, drm_local_map_t ** map_ptr);
-extern int drm_addmap_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_rmmap(struct drm_device *dev, drm_local_map_t * map);
-extern int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t * map);
-extern int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-
+extern int drm_addmap_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_rmmap(struct drm_device *dev, drm_local_map_t *map);
+extern int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map);
+extern int drm_rmmap_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_addbufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_infobufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_markbufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_freebufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_mapbufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_order(unsigned long size);
-extern int drm_addbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_infobufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_markbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_freebufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_mapbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
extern unsigned long drm_get_resource_start(struct drm_device *dev,
unsigned int resource);
extern unsigned long drm_get_resource_len(struct drm_device *dev,
@@ -960,19 +970,20 @@ extern unsigned long drm_get_resource_len(struct drm_device *dev,
extern int drm_dma_setup(struct drm_device *dev);
extern void drm_dma_takedown(struct drm_device *dev);
extern void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf);
-extern void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp);
+extern void drm_core_reclaim_buffers(struct drm_device *dev,
+ struct drm_file *filp);
/* IRQ support (drm_irq.h) */
-extern int drm_control(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_control(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern irqreturn_t drm_irq_handler(DRM_IRQ_ARGS);
extern int drm_irq_uninstall(struct drm_device *dev);
extern void drm_driver_irq_preinstall(struct drm_device *dev);
extern void drm_driver_irq_postinstall(struct drm_device *dev);
extern void drm_driver_irq_uninstall(struct drm_device *dev);
-extern int drm_wait_vblank(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_wait_vblank(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
extern void drm_vbl_send_signals(struct drm_device *dev);
extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*));
@@ -980,31 +991,30 @@ extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_de
/* AGP/GART support (drm_agpsupport.h) */
extern struct drm_agp_head *drm_agp_init(struct drm_device *dev);
extern int drm_agp_acquire(struct drm_device *dev);
-extern int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_agp_release(struct drm_device *dev);
-extern int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_agp_release_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode);
-extern int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_agp_info(struct drm_device *dev, struct drm_agp_info * info);
-extern int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info);
+extern int drm_agp_info_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request);
-extern int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request);
-extern int drm_agp_free_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_agp_free_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request);
-extern int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request);
-extern int drm_agp_bind_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge,
- size_t pages, u32 type);
+extern int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size_t pages, u32 type);
extern int drm_agp_free_memory(DRM_AGP_MEM * handle);
extern int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start);
extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle);
@@ -1033,10 +1043,11 @@ extern int drm_proc_cleanup(int minor,
/* Scatter Gather Support (drm_scatter.h) */
extern void drm_sg_cleanup(struct drm_sg_mem * entry);
-extern int drm_sg_alloc(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int drm_sg_free(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request);
+extern int drm_sg_free(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/* ATI PCIGART support (ati_pcigart.h) */
extern int drm_ati_pcigart_init(struct drm_device *dev,
diff --git a/drivers/char/drm/drm_agpsupport.c b/drivers/char/drm/drm_agpsupport.c
index 354f0e3674b..214f4fbcba7 100644
--- a/drivers/char/drm/drm_agpsupport.c
+++ b/drivers/char/drm/drm_agpsupport.c
@@ -40,7 +40,7 @@
* Get AGP information.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a (output) drm_agp_info structure.
* \return zero on success or a negative number on failure.
@@ -71,20 +71,16 @@ int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info)
EXPORT_SYMBOL(drm_agp_info);
-int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_agp_info_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_agp_info info;
+ struct drm_agp_info *info = data;
int err;
- err = drm_agp_info(dev, &info);
+ err = drm_agp_info(dev, info);
if (err)
return err;
- if (copy_to_user((struct drm_agp_info __user *) arg, &info, sizeof(info)))
- return -EFAULT;
return 0;
}
@@ -115,7 +111,7 @@ EXPORT_SYMBOL(drm_agp_acquire);
* Acquire the AGP device (ioctl).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument.
* \return zero on success or a negative number on failure.
@@ -123,12 +119,10 @@ EXPORT_SYMBOL(drm_agp_acquire);
* Verifies the AGP device hasn't been acquired before and calls
* \c agp_backend_acquire.
*/
-int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
-
- return drm_agp_acquire((struct drm_device *) priv->head->dev);
+ return drm_agp_acquire((struct drm_device *) file_priv->head->dev);
}
/**
@@ -149,12 +143,9 @@ int drm_agp_release(struct drm_device * dev)
}
EXPORT_SYMBOL(drm_agp_release);
-int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_agp_release_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
-
return drm_agp_release(dev);
}
@@ -182,24 +173,19 @@ int drm_agp_enable(struct drm_device * dev, struct drm_agp_mode mode)
EXPORT_SYMBOL(drm_agp_enable);
-int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_agp_mode mode;
-
- if (copy_from_user(&mode, (struct drm_agp_mode __user *) arg, sizeof(mode)))
- return -EFAULT;
+ struct drm_agp_mode *mode = data;
- return drm_agp_enable(dev, mode);
+ return drm_agp_enable(dev, *mode);
}
/**
* Allocate AGP memory.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv file private pointer.
* \param cmd command.
* \param arg pointer to a drm_agp_buffer structure.
* \return zero on success or a negative number on failure.
@@ -241,35 +227,13 @@ int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
}
EXPORT_SYMBOL(drm_agp_alloc);
-int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_agp_buffer request;
- struct drm_agp_buffer __user *argp = (void __user *)arg;
- int err;
-
- if (copy_from_user(&request, argp, sizeof(request)))
- return -EFAULT;
- err = drm_agp_alloc(dev, &request);
- if (err)
- return err;
-
- if (copy_to_user(argp, &request, sizeof(request))) {
- struct drm_agp_mem *entry;
- list_for_each_entry(entry, &dev->agp->memory, head) {
- if (entry->handle == request.handle)
- break;
- }
- list_del(&entry->head);
- drm_free_agp(entry->memory, entry->pages);
- drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
- return -EFAULT;
- }
+int drm_agp_alloc_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_agp_buffer *request = data;
- return 0;
+ return drm_agp_alloc(dev, request);
}
/**
@@ -297,7 +261,7 @@ static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device * dev,
* Unbind AGP memory from the GATT (ioctl).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_agp_binding structure.
* \return zero on success or a negative number on failure.
@@ -323,25 +287,20 @@ int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
}
EXPORT_SYMBOL(drm_agp_unbind);
-int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_agp_binding request;
- if (copy_from_user
- (&request, (struct drm_agp_binding __user *) arg, sizeof(request)))
- return -EFAULT;
+int drm_agp_unbind_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_agp_binding *request = data;
- return drm_agp_unbind(dev, &request);
+ return drm_agp_unbind(dev, request);
}
/**
* Bind AGP memory into the GATT (ioctl)
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_agp_binding structure.
* \return zero on success or a negative number on failure.
@@ -372,25 +331,20 @@ int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
}
EXPORT_SYMBOL(drm_agp_bind);
-int drm_agp_bind_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_agp_binding request;
- if (copy_from_user
- (&request, (struct drm_agp_binding __user *) arg, sizeof(request)))
- return -EFAULT;
+int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_agp_binding *request = data;
- return drm_agp_bind(dev, &request);
+ return drm_agp_bind(dev, request);
}
/**
* Free AGP memory (ioctl).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_agp_buffer structure.
* \return zero on success or a negative number on failure.
@@ -419,18 +373,14 @@ int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
}
EXPORT_SYMBOL(drm_agp_free);
-int drm_agp_free_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_agp_buffer request;
- if (copy_from_user
- (&request, (struct drm_agp_buffer __user *) arg, sizeof(request)))
- return -EFAULT;
- return drm_agp_free(dev, &request);
+int drm_agp_free_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_agp_buffer *request = data;
+
+ return drm_agp_free(dev, request);
}
/**
diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c
index 7f777da872c..a73462723d2 100644
--- a/drivers/char/drm/drm_auth.c
+++ b/drivers/char/drm/drm_auth.c
@@ -128,42 +128,38 @@ static int drm_remove_magic(struct drm_device * dev, drm_magic_t magic)
* Get a unique magic number (ioctl).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a resulting drm_auth structure.
* \return zero on success, or a negative number on failure.
*
* If there is a magic number in drm_file::magic then use it, otherwise
* searches an unique non-zero magic number and add it associating it with \p
- * filp.
+ * file_priv.
*/
-int drm_getmagic(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
static drm_magic_t sequence = 0;
static DEFINE_SPINLOCK(lock);
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_auth auth;
+ struct drm_auth *auth = data;
/* Find unique magic */
- if (priv->magic) {
- auth.magic = priv->magic;
+ if (file_priv->magic) {
+ auth->magic = file_priv->magic;
} else {
do {
spin_lock(&lock);
if (!sequence)
++sequence; /* reserve 0 */
- auth.magic = sequence++;
+ auth->magic = sequence++;
spin_unlock(&lock);
- } while (drm_find_file(dev, auth.magic));
- priv->magic = auth.magic;
- drm_add_magic(dev, priv, auth.magic);
+ } while (drm_find_file(dev, auth->magic));
+ file_priv->magic = auth->magic;
+ drm_add_magic(dev, file_priv, auth->magic);
}
- DRM_DEBUG("%u\n", auth.magic);
- if (copy_to_user((struct drm_auth __user *) arg, &auth, sizeof(auth)))
- return -EFAULT;
+ DRM_DEBUG("%u\n", auth->magic);
+
return 0;
}
@@ -171,27 +167,23 @@ int drm_getmagic(struct inode *inode, struct file *filp,
* Authenticate with a magic.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_auth structure.
* \return zero if authentication successed, or a negative number otherwise.
*
- * Checks if \p filp is associated with the magic number passed in \arg.
+ * Checks if \p file_priv is associated with the magic number passed in \arg.
*/
-int drm_authmagic(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_authmagic(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_auth auth;
+ struct drm_auth *auth = data;
struct drm_file *file;
- if (copy_from_user(&auth, (struct drm_auth __user *) arg, sizeof(auth)))
- return -EFAULT;
- DRM_DEBUG("%u\n", auth.magic);
- if ((file = drm_find_file(dev, auth.magic))) {
+ DRM_DEBUG("%u\n", auth->magic);
+ if ((file = drm_find_file(dev, auth->magic))) {
file->authenticated = 1;
- drm_remove_magic(dev, auth.magic);
+ drm_remove_magic(dev, auth->magic);
return 0;
}
return -EINVAL;
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index c115b39b851..d24a6c2c2c2 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -92,7 +92,7 @@ static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
* Ioctl to specify a range of memory that is available for mapping by a non-root process.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_map structure.
* \return zero on success or a negative value on error.
@@ -332,38 +332,24 @@ int drm_addmap(struct drm_device * dev, unsigned int offset,
EXPORT_SYMBOL(drm_addmap);
-int drm_addmap_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_addmap_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_map map;
+ struct drm_map *map = data;
struct drm_map_list *maplist;
- struct drm_map __user *argp = (void __user *)arg;
int err;
- if (!(filp->f_mode & 3))
- return -EACCES; /* Require read/write */
-
- if (copy_from_user(&map, argp, sizeof(map))) {
- return -EFAULT;
- }
-
- if (!(capable(CAP_SYS_ADMIN) || map.type == _DRM_AGP))
+ if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP))
return -EPERM;
- err = drm_addmap_core(dev, map.offset, map.size, map.type, map.flags,
- &maplist);
+ err = drm_addmap_core(dev, map->offset, map->size, map->type,
+ map->flags, &maplist);
if (err)
return err;
- if (copy_to_user(argp, maplist->map, sizeof(struct drm_map)))
- return -EFAULT;
-
/* avoid a warning on 64-bit, this casting isn't very nice, but the API is set so too late */
- if (put_user((void *)(unsigned long)maplist->user_token, &argp->handle))
- return -EFAULT;
+ map->handle = (void *)(unsigned long)maplist->user_token;
return 0;
}
@@ -372,7 +358,7 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp,
* isn't in use.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a struct drm_map structure.
* \return zero on success or a negative value on error.
@@ -453,24 +439,18 @@ int drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
* gets used by drivers that the server doesn't need to care about. This seems
* unlikely.
*/
-int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_rmmap_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_map request;
+ struct drm_map *request = data;
drm_local_map_t *map = NULL;
struct drm_map_list *r_list;
int ret;
- if (copy_from_user(&request, (struct drm_map __user *) arg, sizeof(request))) {
- return -EFAULT;
- }
-
mutex_lock(&dev->struct_mutex);
list_for_each_entry(r_list, &dev->maplist, head) {
if (r_list->map &&
- r_list->user_token == (unsigned long)request.handle &&
+ r_list->user_token == (unsigned long)request->handle &&
r_list->map->flags & _DRM_REMOVABLE) {
map = r_list->map;
break;
@@ -661,7 +641,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
buf->waiting = 0;
buf->pending = 0;
init_waitqueue_head(&buf->dma_wait);
- buf->filp = NULL;
+ buf->file_priv = NULL;
buf->dev_priv_size = dev->driver->dev_priv_size;
buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
@@ -872,7 +852,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
buf->waiting = 0;
buf->pending = 0;
init_waitqueue_head(&buf->dma_wait);
- buf->filp = NULL;
+ buf->file_priv = NULL;
buf->dev_priv_size = dev->driver->dev_priv_size;
buf->dev_private = drm_alloc(buf->dev_priv_size,
@@ -1050,7 +1030,7 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request
buf->waiting = 0;
buf->pending = 0;
init_waitqueue_head(&buf->dma_wait);
- buf->filp = NULL;
+ buf->file_priv = NULL;
buf->dev_priv_size = dev->driver->dev_priv_size;
buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
@@ -1211,7 +1191,7 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
buf->waiting = 0;
buf->pending = 0;
init_waitqueue_head(&buf->dma_wait);
- buf->filp = NULL;
+ buf->file_priv = NULL;
buf->dev_priv_size = dev->driver->dev_priv_size;
buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS);
@@ -1275,7 +1255,7 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
* Add buffers for DMA transfers (ioctl).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a struct drm_buf_desc request.
* \return zero on success or a negative number on failure.
@@ -1285,38 +1265,27 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request
* addbufs_sg() or addbufs_pci() for AGP, scatter-gather or consistent
* PCI memory respectively.
*/
-int drm_addbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_addbufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_buf_desc request;
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_buf_desc *request = data;
int ret;
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
return -EINVAL;
- if (copy_from_user(&request, (struct drm_buf_desc __user *) arg,
- sizeof(request)))
- return -EFAULT;
-
#if __OS_HAS_AGP
- if (request.flags & _DRM_AGP_BUFFER)
- ret = drm_addbufs_agp(dev, &request);
+ if (request->flags & _DRM_AGP_BUFFER)
+ ret = drm_addbufs_agp(dev, request);
else
#endif
- if (request.flags & _DRM_SG_BUFFER)
- ret = drm_addbufs_sg(dev, &request);
- else if (request.flags & _DRM_FB_BUFFER)
- ret = drm_addbufs_fb(dev, &request);
+ if (request->flags & _DRM_SG_BUFFER)
+ ret = drm_addbufs_sg(dev, request);
+ else if (request->flags & _DRM_FB_BUFFER)
+ ret = drm_addbufs_fb(dev, request);
else
- ret = drm_addbufs_pci(dev, &request);
+ ret = drm_addbufs_pci(dev, request);
- if (ret == 0) {
- if (copy_to_user((void __user *)arg, &request, sizeof(request))) {
- ret = -EFAULT;
- }
- }
return ret;
}
@@ -1328,7 +1297,7 @@ int drm_addbufs(struct inode *inode, struct file *filp,
* large buffers can be used for image transfer).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_buf_info structure.
* \return zero on success or a negative number on failure.
@@ -1337,14 +1306,11 @@ int drm_addbufs(struct inode *inode, struct file *filp,
* lock, preventing of allocating more buffers after this call. Information
* about each requested buffer is then copied into user space.
*/
-int drm_infobufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_infobufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
- struct drm_buf_info request;
- struct drm_buf_info __user *argp = (void __user *)arg;
+ struct drm_buf_info *request = data;
int i;
int count;
@@ -1362,9 +1328,6 @@ int drm_infobufs(struct inode *inode, struct file *filp,
++dev->buf_use; /* Can't allocate more after this call */
spin_unlock(&dev->count_lock);
- if (copy_from_user(&request, argp, sizeof(request)))
- return -EFAULT;
-
for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
if (dma->bufs[i].buf_count)
++count;
@@ -1372,11 +1335,11 @@ int drm_infobufs(struct inode *inode, struct file *filp,
DRM_DEBUG("count = %d\n", count);
- if (request.count >= count) {
+ if (request->count >= count) {
for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
if (dma->bufs[i].buf_count) {
struct drm_buf_desc __user *to =
- &request.list[count];
+ &request->list[count];
struct drm_buf_entry *from = &dma->bufs[i];
struct drm_freelist *list = &dma->bufs[i].freelist;
if (copy_to_user(&to->count,
@@ -1403,10 +1366,7 @@ int drm_infobufs(struct inode *inode, struct file *filp,
}
}
}
- request.count = count;
-
- if (copy_to_user(argp, &request, sizeof(request)))
- return -EFAULT;
+ request->count = count;
return 0;
}
@@ -1415,7 +1375,7 @@ int drm_infobufs(struct inode *inode, struct file *filp,
* Specifies a low and high water mark for buffer allocation
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg a pointer to a drm_buf_desc structure.
* \return zero on success or a negative number on failure.
@@ -1425,13 +1385,11 @@ int drm_infobufs(struct inode *inode, struct file *filp,
*
* \note This ioctl is deprecated and mostly never used.
*/
-int drm_markbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_markbufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
- struct drm_buf_desc request;
+ struct drm_buf_desc *request = data;
int order;
struct drm_buf_entry *entry;
@@ -1441,24 +1399,20 @@ int drm_markbufs(struct inode *inode, struct file *filp,
if (!dma)
return -EINVAL;
- if (copy_from_user(&request,
- (struct drm_buf_desc __user *) arg, sizeof(request)))
- return -EFAULT;
-
DRM_DEBUG("%d, %d, %d\n",
- request.size, request.low_mark, request.high_mark);
- order = drm_order(request.size);
+ request->size, request->low_mark, request->high_mark);
+ order = drm_order(request->size);
if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER)
return -EINVAL;
entry = &dma->bufs[order];
- if (request.low_mark < 0 || request.low_mark > entry->buf_count)
+ if (request->low_mark < 0 || request->low_mark > entry->buf_count)
return -EINVAL;
- if (request.high_mark < 0 || request.high_mark > entry->buf_count)
+ if (request->high_mark < 0 || request->high_mark > entry->buf_count)
return -EINVAL;
- entry->freelist.low_mark = request.low_mark;
- entry->freelist.high_mark = request.high_mark;
+ entry->freelist.low_mark = request->low_mark;
+ entry->freelist.high_mark = request->high_mark;
return 0;
}
@@ -1467,7 +1421,7 @@ int drm_markbufs(struct inode *inode, struct file *filp,
* Unreserve the buffers in list, previously reserved using drmDMA.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_buf_free structure.
* \return zero on success or a negative number on failure.
@@ -1475,13 +1429,11 @@ int drm_markbufs(struct inode *inode, struct file *filp,
* Calls free_buffer() for each used buffer.
* This function is primarily used for debugging.
*/
-int drm_freebufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_freebufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
- struct drm_buf_free request;
+ struct drm_buf_free *request = data;
int i;
int idx;
struct drm_buf *buf;
@@ -1492,13 +1444,9 @@ int drm_freebufs(struct inode *inode, struct file *filp,
if (!dma)
return -EINVAL;
- if (copy_from_user(&request,
- (struct drm_buf_free __user *) arg, sizeof(request)))
- return -EFAULT;
-
- DRM_DEBUG("%d\n", request.count);
- for (i = 0; i < request.count; i++) {
- if (copy_from_user(&idx, &request.list[i], sizeof(idx)))
+ DRM_DEBUG("%d\n", request->count);
+ for (i = 0; i < request->count; i++) {
+ if (copy_from_user(&idx, &request->list[i], sizeof(idx)))
return -EFAULT;
if (idx < 0 || idx >= dma->buf_count) {
DRM_ERROR("Index %d (of %d max)\n",
@@ -1506,9 +1454,9 @@ int drm_freebufs(struct inode *inode, struct file *filp,
return -EINVAL;
}
buf = dma->buflist[idx];
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("Process %d freeing buffer not owned\n",
- current->pid);
+ task_pid_nr(current));
return -EINVAL;
}
drm_free_buffer(dev, buf);
@@ -1521,7 +1469,7 @@ int drm_freebufs(struct inode *inode, struct file *filp,
* Maps all of the DMA buffers into client-virtual space (ioctl).
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg pointer to a drm_buf_map structure.
* \return zero on success or a negative number on failure.
@@ -1531,18 +1479,15 @@ int drm_freebufs(struct inode *inode, struct file *filp,
* offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls
* drm_mmap_dma().
*/
-int drm_mapbufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_mapbufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
- struct drm_buf_map __user *argp = (void __user *)arg;
int retcode = 0;
const int zero = 0;
unsigned long virtual;
unsigned long address;
- struct drm_buf_map request;
+ struct drm_buf_map *request = data;
int i;
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
@@ -1559,10 +1504,7 @@ int drm_mapbufs(struct inode *inode, struct file *filp,
dev->buf_use++; /* Can't allocate more after this call */
spin_unlock(&dev->count_lock);
- if (copy_from_user(&request, argp, sizeof(request)))
- return -EFAULT;
-
- if (request.count >= dma->buf_count) {
+ if (request->count >= dma->buf_count) {
if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP))
|| (drm_core_check_feature(dev, DRIVER_SG)
&& (dma->flags & _DRM_DMA_USE_SG))
@@ -1575,15 +1517,15 @@ int drm_mapbufs(struct inode *inode, struct file *filp,
retcode = -EINVAL;
goto done;
}
-
down_write(&current->mm->mmap_sem);
- virtual = do_mmap(filp, 0, map->size,
+ virtual = do_mmap(file_priv->filp, 0, map->size,
PROT_READ | PROT_WRITE,
- MAP_SHARED, token);
+ MAP_SHARED,
+ token);
up_write(&current->mm->mmap_sem);
} else {
down_write(&current->mm->mmap_sem);
- virtual = do_mmap(filp, 0, dma->byte_count,
+ virtual = do_mmap(file_priv->filp, 0, dma->byte_count,
PROT_READ | PROT_WRITE,
MAP_SHARED, 0);
up_write(&current->mm->mmap_sem);
@@ -1593,28 +1535,28 @@ int drm_mapbufs(struct inode *inode, struct file *filp,
retcode = (signed long)virtual;
goto done;
}
- request.virtual = (void __user *)virtual;
+ request->virtual = (void __user *)virtual;
for (i = 0; i < dma->buf_count; i++) {
- if (copy_to_user(&request.list[i].idx,
+ if (copy_to_user(&request->list[i].idx,
&dma->buflist[i]->idx,
- sizeof(request.list[0].idx))) {
+ sizeof(request->list[0].idx))) {
retcode = -EFAULT;
goto done;
}
- if (copy_to_user(&request.list[i].total,
+ if (copy_to_user(&request->list[i].total,
&dma->buflist[i]->total,
- sizeof(request.list[0].total))) {
+ sizeof(request->list[0].total))) {
retcode = -EFAULT;
goto done;
}
- if (copy_to_user(&request.list[i].used,
+ if (copy_to_user(&request->list[i].used,
&zero, sizeof(zero))) {
retcode = -EFAULT;
goto done;
}
address = virtual + dma->buflist[i]->offset; /* *** */
- if (copy_to_user(&request.list[i].address,
+ if (copy_to_user(&request->list[i].address,
&address, sizeof(address))) {
retcode = -EFAULT;
goto done;
@@ -1622,11 +1564,8 @@ int drm_mapbufs(struct inode *inode, struct file *filp,
}
}
done:
- request.count = dma->buf_count;
- DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
-
- if (copy_to_user(argp, &request, sizeof(request)))
- return -EFAULT;
+ request->count = dma->buf_count;
+ DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode);
return retcode;
}
diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c
index 61ad986baa8..17fe69e7bfc 100644
--- a/drivers/char/drm/drm_context.c
+++ b/drivers/char/drm/drm_context.c
@@ -131,7 +131,7 @@ void drm_ctxbitmap_cleanup(struct drm_device * dev)
* Get per-context SAREA.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx_priv_map structure.
* \return zero on success or a negative number on failure.
@@ -139,22 +139,16 @@ void drm_ctxbitmap_cleanup(struct drm_device * dev)
* Gets the map from drm_device::ctx_idr with the handle specified and
* returns its handle.
*/
-int drm_getsareactx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getsareactx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_ctx_priv_map __user *argp = (void __user *)arg;
- struct drm_ctx_priv_map request;
+ struct drm_ctx_priv_map *request = data;
struct drm_map *map;
struct drm_map_list *_entry;
- if (copy_from_user(&request, argp, sizeof(request)))
- return -EFAULT;
-
mutex_lock(&dev->struct_mutex);
- map = idr_find(&dev->ctx_idr, request.ctx_id);
+ map = idr_find(&dev->ctx_idr, request->ctx_id);
if (!map) {
mutex_unlock(&dev->struct_mutex);
return -EINVAL;
@@ -162,19 +156,17 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
mutex_unlock(&dev->struct_mutex);
- request.handle = NULL;
+ request->handle = NULL;
list_for_each_entry(_entry, &dev->maplist, head) {
if (_entry->map == map) {
- request.handle =
+ request->handle =
(void *)(unsigned long)_entry->user_token;
break;
}
}
- if (request.handle == NULL)
+ if (request->handle == NULL)
return -EINVAL;
- if (copy_to_user(argp, &request, sizeof(request)))
- return -EFAULT;
return 0;
}
@@ -182,7 +174,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
* Set per-context SAREA.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx_priv_map structure.
* \return zero on success or a negative number on failure.
@@ -190,24 +182,17 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
* Searches the mapping specified in \p arg and update the entry in
* drm_device::ctx_idr with it.
*/
-int drm_setsareactx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_setsareactx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_ctx_priv_map request;
+ struct drm_ctx_priv_map *request = data;
struct drm_map *map = NULL;
struct drm_map_list *r_list = NULL;
- if (copy_from_user(&request,
- (struct drm_ctx_priv_map __user *) arg,
- sizeof(request)))
- return -EFAULT;
-
mutex_lock(&dev->struct_mutex);
list_for_each_entry(r_list, &dev->maplist, head) {
if (r_list->map
- && r_list->user_token == (unsigned long)request.handle)
+ && r_list->user_token == (unsigned long) request->handle)
goto found;
}
bad:
@@ -219,10 +204,11 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
if (!map)
goto bad;
- if (IS_ERR(idr_replace(&dev->ctx_idr, map, request.ctx_id)))
+ if (IS_ERR(idr_replace(&dev->ctx_idr, map, request->ctx_id)))
goto bad;
mutex_unlock(&dev->struct_mutex);
+
return 0;
}
@@ -292,34 +278,28 @@ static int drm_context_switch_complete(struct drm_device * dev, int new)
* Reserve contexts.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx_res structure.
* \return zero on success or a negative number on failure.
*/
-int drm_resctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_resctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_ctx_res res;
- struct drm_ctx_res __user *argp = (void __user *)arg;
+ struct drm_ctx_res *res = data;
struct drm_ctx ctx;
int i;
- if (copy_from_user(&res, argp, sizeof(res)))
- return -EFAULT;
-
- if (res.count >= DRM_RESERVED_CONTEXTS) {
+ if (res->count >= DRM_RESERVED_CONTEXTS) {
memset(&ctx, 0, sizeof(ctx));
for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
ctx.handle = i;
- if (copy_to_user(&res.contexts[i], &ctx, sizeof(ctx)))
+ if (copy_to_user(&res->contexts[i], &ctx, sizeof(ctx)))
return -EFAULT;
}
}
- res.count = DRM_RESERVED_CONTEXTS;
+ res->count = DRM_RESERVED_CONTEXTS;
- if (copy_to_user(argp, &res, sizeof(res)))
- return -EFAULT;
return 0;
}
@@ -327,40 +307,34 @@ int drm_resctx(struct inode *inode, struct file *filp,
* Add context.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx structure.
* \return zero on success or a negative number on failure.
*
* Get a new handle for the context and copy to userspace.
*/
-int drm_addctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_addctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_ctx_list *ctx_entry;
- struct drm_ctx __user *argp = (void __user *)arg;
- struct drm_ctx ctx;
-
- if (copy_from_user(&ctx, argp, sizeof(ctx)))
- return -EFAULT;
+ struct drm_ctx *ctx = data;
- ctx.handle = drm_ctxbitmap_next(dev);
- if (ctx.handle == DRM_KERNEL_CONTEXT) {
+ ctx->handle = drm_ctxbitmap_next(dev);
+ if (ctx->handle == DRM_KERNEL_CONTEXT) {
/* Skip kernel's context and get a new one. */
- ctx.handle = drm_ctxbitmap_next(dev);
+ ctx->handle = drm_ctxbitmap_next(dev);
}
- DRM_DEBUG("%d\n", ctx.handle);
- if (ctx.handle == -1) {
+ DRM_DEBUG("%d\n", ctx->handle);
+ if (ctx->handle == -1) {
DRM_DEBUG("Not enough free contexts.\n");
/* Should this return -EBUSY instead? */
return -ENOMEM;
}
- if (ctx.handle != DRM_KERNEL_CONTEXT) {
+ if (ctx->handle != DRM_KERNEL_CONTEXT) {
if (dev->driver->context_ctor)
- if (!dev->driver->context_ctor(dev, ctx.handle)) {
+ if (!dev->driver->context_ctor(dev, ctx->handle)) {
DRM_DEBUG("Running out of ctxs or memory.\n");
return -ENOMEM;
}
@@ -373,21 +347,18 @@ int drm_addctx(struct inode *inode, struct file *filp,
}
INIT_LIST_HEAD(&ctx_entry->head);
- ctx_entry->handle = ctx.handle;
- ctx_entry->tag = priv;
+ ctx_entry->handle = ctx->handle;
+ ctx_entry->tag = file_priv;
mutex_lock(&dev->ctxlist_mutex);
list_add(&ctx_entry->head, &dev->ctxlist);
++dev->ctx_count;
mutex_unlock(&dev->ctxlist_mutex);
- if (copy_to_user(argp, &ctx, sizeof(ctx)))
- return -EFAULT;
return 0;
}
-int drm_modctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
/* This does nothing */
return 0;
@@ -397,25 +368,18 @@ int drm_modctx(struct inode *inode, struct file *filp,
* Get context.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx structure.
* \return zero on success or a negative number on failure.
*/
-int drm_getctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- struct drm_ctx __user *argp = (void __user *)arg;
- struct drm_ctx ctx;
-
- if (copy_from_user(&ctx, argp, sizeof(ctx)))
- return -EFAULT;
+ struct drm_ctx *ctx = data;
/* This is 0, because we don't handle any context flags */
- ctx.flags = 0;
+ ctx->flags = 0;
- if (copy_to_user(argp, &ctx, sizeof(ctx)))
- return -EFAULT;
return 0;
}
@@ -423,50 +387,40 @@ int drm_getctx(struct inode *inode, struct file *filp,
* Switch context.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx structure.
* \return zero on success or a negative number on failure.
*
* Calls context_switch().
*/
-int drm_switchctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_switchctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_ctx ctx;
+ struct drm_ctx *ctx = data;
- if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx)))
- return -EFAULT;
-
- DRM_DEBUG("%d\n", ctx.handle);
- return drm_context_switch(dev, dev->last_context, ctx.handle);
+ DRM_DEBUG("%d\n", ctx->handle);
+ return drm_context_switch(dev, dev->last_context, ctx->handle);
}
/**
* New context.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx structure.
* \return zero on success or a negative number on failure.
*
* Calls context_switch_complete().
*/
-int drm_newctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_newctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_ctx ctx;
+ struct drm_ctx *ctx = data;
- if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx)))
- return -EFAULT;
-
- DRM_DEBUG("%d\n", ctx.handle);
- drm_context_switch_complete(dev, ctx.handle);
+ DRM_DEBUG("%d\n", ctx->handle);
+ drm_context_switch_complete(dev, ctx->handle);
return 0;
}
@@ -475,31 +429,26 @@ int drm_newctx(struct inode *inode, struct file *filp,
* Remove context.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument pointing to a drm_ctx structure.
* \return zero on success or a negative number on failure.
*
* If not the special kernel context, calls ctxbitmap_free() to free the specified context.
*/
-int drm_rmctx(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_rmctx(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_ctx ctx;
-
- if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx)))
- return -EFAULT;
+ struct drm_ctx *ctx = data;
- DRM_DEBUG("%d\n", ctx.handle);
- if (ctx.handle == DRM_KERNEL_CONTEXT + 1) {
- priv->remove_auth_on_close = 1;
+ DRM_DEBUG("%d\n", ctx->handle);
+ if (ctx->handle == DRM_KERNEL_CONTEXT + 1) {
+ file_priv->remove_auth_on_close = 1;
}
- if (ctx.handle != DRM_KERNEL_CONTEXT) {
+ if (ctx->handle != DRM_KERNEL_CONTEXT) {
if (dev->driver->context_dtor)
- dev->driver->context_dtor(dev, ctx.handle);
- drm_ctxbitmap_free(dev, ctx.handle);
+ dev->driver->context_dtor(dev, ctx->handle);
+ drm_ctxbitmap_free(dev, ctx->handle);
}
mutex_lock(&dev->ctxlist_mutex);
@@ -507,7 +456,7 @@ int drm_rmctx(struct inode *inode, struct file *filp,
struct drm_ctx_list *pos, *n;
list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
- if (pos->handle == ctx.handle) {
+ if (pos->handle == ctx->handle) {
list_del(&pos->head);
drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST);
--dev->ctx_count;
diff --git a/drivers/char/drm/drm_dma.c b/drivers/char/drm/drm_dma.c
index 802fbdbfe1b..7a8e2fba467 100644
--- a/drivers/char/drm/drm_dma.c
+++ b/drivers/char/drm/drm_dma.c
@@ -136,7 +136,7 @@ void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf)
buf->waiting = 0;
buf->pending = 0;
- buf->filp = NULL;
+ buf->file_priv = NULL;
buf->used = 0;
if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE)
@@ -148,11 +148,12 @@ void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf)
/**
* Reclaim the buffers.
*
- * \param filp file pointer.
+ * \param file_priv DRM file private.
*
- * Frees each buffer associated with \p filp not already on the hardware.
+ * Frees each buffer associated with \p file_priv not already on the hardware.
*/
-void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp)
+void drm_core_reclaim_buffers(struct drm_device *dev,
+ struct drm_file *file_priv)
{
struct drm_device_dma *dma = dev->dma;
int i;
@@ -160,7 +161,7 @@ void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp)
if (!dma)
return;
for (i = 0; i < dma->buf_count; i++) {
- if (dma->buflist[i]->filp == filp) {
+ if (dma->buflist[i]->file_priv == file_priv) {
switch (dma->buflist[i]->list) {
case DRM_LIST_NONE:
drm_free_buffer(dev, dma->buflist[i]);
diff --git a/drivers/char/drm/drm_drawable.c b/drivers/char/drm/drm_drawable.c
index d6cdba5644e..1839c57663c 100644
--- a/drivers/char/drm/drm_drawable.c
+++ b/drivers/char/drm/drm_drawable.c
@@ -40,11 +40,10 @@
/**
* Allocate drawable ID and memory to store information about it.
*/
-int drm_adddraw(DRM_IOCTL_ARGS)
+int drm_adddraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
unsigned long irqflags;
- struct drm_draw draw;
+ struct drm_draw *draw = data;
int new_id = 0;
int ret;
@@ -63,11 +62,9 @@ again:
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- draw.handle = new_id;
+ draw->handle = new_id;
- DRM_DEBUG("%d\n", draw.handle);
-
- DRM_COPY_TO_USER_IOCTL((struct drm_draw __user *)data, draw, sizeof(draw));
+ DRM_DEBUG("%d\n", draw->handle);
return 0;
}
@@ -75,72 +72,64 @@ again:
/**
* Free drawable ID and memory to store information about it.
*/
-int drm_rmdraw(DRM_IOCTL_ARGS)
+int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- struct drm_draw draw;
+ struct drm_draw *draw = data;
unsigned long irqflags;
- DRM_COPY_FROM_USER_IOCTL(draw, (struct drm_draw __user *) data,
- sizeof(draw));
-
spin_lock_irqsave(&dev->drw_lock, irqflags);
- drm_free(drm_get_drawable_info(dev, draw.handle),
+ drm_free(drm_get_drawable_info(dev, draw->handle),
sizeof(struct drm_drawable_info), DRM_MEM_BUFS);
- idr_remove(&dev->drw_idr, draw.handle);
+ idr_remove(&dev->drw_idr, draw->handle);
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- DRM_DEBUG("%d\n", draw.handle);
+ DRM_DEBUG("%d\n", draw->handle);
return 0;
}
-int drm_update_drawable_info(DRM_IOCTL_ARGS)
+int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- struct drm_update_draw update;
+ struct drm_update_draw *update = data;
unsigned long irqflags;
struct drm_clip_rect *rects;
struct drm_drawable_info *info;
int err;
- DRM_COPY_FROM_USER_IOCTL(update, (struct drm_update_draw __user *) data,
- sizeof(update));
-
- info = idr_find(&dev->drw_idr, update.handle);
+ info = idr_find(&dev->drw_idr, update->handle);
if (!info) {
info = drm_calloc(1, sizeof(*info), DRM_MEM_BUFS);
if (!info)
return -ENOMEM;
- if (IS_ERR(idr_replace(&dev->drw_idr, info, update.handle))) {
- DRM_ERROR("No such drawable %d\n", update.handle);
+ if (IS_ERR(idr_replace(&dev->drw_idr, info, update->handle))) {
+ DRM_ERROR("No such drawable %d\n", update->handle);
drm_free(info, sizeof(*info), DRM_MEM_BUFS);
return -EINVAL;
}
}
- switch (update.type) {
+ switch (update->type) {
case DRM_DRAWABLE_CLIPRECTS:
- if (update.num != info->num_rects) {
- rects = drm_alloc(update.num * sizeof(struct drm_clip_rect),
+ if (update->num != info->num_rects) {
+ rects = drm_alloc(update->num * sizeof(struct drm_clip_rect),
DRM_MEM_BUFS);
} else
rects = info->rects;
- if (update.num && !rects) {
+ if (update->num && !rects) {
DRM_ERROR("Failed to allocate cliprect memory\n");
- err = DRM_ERR(ENOMEM);
+ err = -ENOMEM;
goto error;
}
- if (update.num && DRM_COPY_FROM_USER(rects,
+ if (update->num && DRM_COPY_FROM_USER(rects,
(struct drm_clip_rect __user *)
- (unsigned long)update.data,
- update.num *
+ (unsigned long)update->data,
+ update->num *
sizeof(*rects))) {
DRM_ERROR("Failed to copy cliprects from userspace\n");
- err = DRM_ERR(EFAULT);
+ err = -EFAULT;
goto error;
}
@@ -152,23 +141,23 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS)
}
info->rects = rects;
- info->num_rects = update.num;
+ info->num_rects = update->num;
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
DRM_DEBUG("Updated %d cliprects for drawable %d\n",
- info->num_rects, update.handle);
+ info->num_rects, update->handle);
break;
default:
- DRM_ERROR("Invalid update type %d\n", update.type);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("Invalid update type %d\n", update->type);
+ return -EINVAL;
}
return 0;
error:
if (rects != info->rects)
- drm_free(rects, update.num * sizeof(struct drm_clip_rect),
+ drm_free(rects, update->num * sizeof(struct drm_clip_rect),
DRM_MEM_BUFS);
return err;
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index 19994cd865d..44a46268b02 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -49,73 +49,74 @@
#include "drmP.h"
#include "drm_core.h"
-static int drm_version(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+static int drm_version(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/** Ioctl table */
-static drm_ioctl_desc_t drm_ioctls[] = {
- [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = {drm_version, 0},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = {drm_getunique, 0},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = {drm_getmagic, 0},
- [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = {drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = {drm_getmap, 0},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = {drm_getclient, 0},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = {drm_getstats, 0},
- [DRM_IOCTL_NR(DRM_IOCTL_SET_VERSION)] = {drm_setversion, DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = {drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = {drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = {drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-
- [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = {drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = {drm_rmmap_ioctl, DRM_AUTH},
-
- [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = {drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = {drm_getsareactx, DRM_AUTH},
-
- [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = {drm_addctx, DRM_AUTH|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = {drm_rmctx, DRM_AUTH|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = {drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = {drm_getctx, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = {drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = {drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = {drm_resctx, DRM_AUTH},
-
- [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = {drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = {drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
-
- [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = {drm_lock, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = {drm_unlock, DRM_AUTH},
-
- [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = {drm_noop, DRM_AUTH},
-
- [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = {drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = {drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = {drm_infobufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = {drm_mapbufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = {drm_freebufs, DRM_AUTH},
+static struct drm_ioctl_desc drm_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_getmap, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0),
+ DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER|DRM_ROOT_ONLY),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_rmmap_ioctl, DRM_AUTH),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_getsareactx, DRM_AUTH),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_addctx, DRM_AUTH|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_getctx, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_resctx, DRM_AUTH),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_adddraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_rmdraw, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_LOCK, drm_lock, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_unlock, DRM_AUTH),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_infobufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_mapbufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_freebufs, DRM_AUTH),
/* The DRM_IOCTL_DMA ioctl should be defined by the driver. */
- [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = {NULL, DRM_AUTH},
+ DRM_IOCTL_DEF(DRM_IOCTL_DMA, NULL, DRM_AUTH),
- [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = {drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+ DRM_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
#if __OS_HAS_AGP
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = {drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = {drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = {drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = {drm_agp_info_ioctl, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = {drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = {drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = {drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = {drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_agp_acquire_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_agp_release_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_agp_enable_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_agp_info_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_agp_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_agp_free_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_agp_bind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_agp_unbind_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
#endif
- [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = {drm_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+ DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
+ DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
- [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+ DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
@@ -224,7 +225,7 @@ int drm_lastclose(struct drm_device * dev)
if (dev->lock.hw_lock) {
dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */
- dev->lock.filp = NULL;
+ dev->lock.file_priv = NULL;
wake_up_interruptible(&dev->lock.lock_queue);
}
mutex_unlock(&dev->struct_mutex);
@@ -418,27 +419,19 @@ module_exit(drm_core_exit);
*
* Fills in the version information in \p arg.
*/
-static int drm_version(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int drm_version(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_version __user *argp = (void __user *)arg;
- struct drm_version version;
+ struct drm_version *version = data;
int len;
- if (copy_from_user(&version, argp, sizeof(version)))
- return -EFAULT;
+ version->version_major = dev->driver->major;
+ version->version_minor = dev->driver->minor;
+ version->version_patchlevel = dev->driver->patchlevel;
+ DRM_COPY(version->name, dev->driver->name);
+ DRM_COPY(version->date, dev->driver->date);
+ DRM_COPY(version->desc, dev->driver->desc);
- version.version_major = dev->driver->major;
- version.version_minor = dev->driver->minor;
- version.version_patchlevel = dev->driver->patchlevel;
- DRM_COPY(version.name, dev->driver->name);
- DRM_COPY(version.date, dev->driver->date);
- DRM_COPY(version.desc, dev->driver->desc);
-
- if (copy_to_user(argp, &version, sizeof(version)))
- return -EFAULT;
return 0;
}
@@ -446,7 +439,7 @@ static int drm_version(struct inode *inode, struct file *filp,
* Called whenever a process performs an ioctl on /dev/drm.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument.
* \return zero on success or negative number on failure.
@@ -457,21 +450,22 @@ static int drm_version(struct inode *inode, struct file *filp,
int drm_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- drm_ioctl_desc_t *ioctl;
+ struct drm_file *file_priv = filp->private_data;
+ struct drm_device *dev = file_priv->head->dev;
+ struct drm_ioctl_desc *ioctl;
drm_ioctl_t *func;
unsigned int nr = DRM_IOCTL_NR(cmd);
int retcode = -EINVAL;
+ char *kdata = NULL;
atomic_inc(&dev->ioctl_count);
atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
- ++priv->ioctl_count;
+ ++file_priv->ioctl_count;
DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n",
- current->pid, cmd, nr,
- (long)old_encode_dev(priv->head->device),
- priv->authenticated);
+ task_pid_nr(current), cmd, nr,
+ (long)old_encode_dev(file_priv->head->device),
+ file_priv->authenticated);
if ((nr >= DRM_CORE_IOCTL_COUNT) &&
((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
@@ -489,18 +483,40 @@ int drm_ioctl(struct inode *inode, struct file *filp,
if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl)
func = dev->driver->dma_ioctl;
+
if (!func) {
DRM_DEBUG("no function\n");
retcode = -EINVAL;
} else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) ||
- ((ioctl->flags & DRM_AUTH) && !priv->authenticated) ||
- ((ioctl->flags & DRM_MASTER) && !priv->master)) {
+ ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) ||
+ ((ioctl->flags & DRM_MASTER) && !file_priv->master)) {
retcode = -EACCES;
} else {
- retcode = func(inode, filp, cmd, arg);
+ if (cmd & (IOC_IN | IOC_OUT)) {
+ kdata = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
+ if (!kdata)
+ return -ENOMEM;
+ }
+
+ if (cmd & IOC_IN) {
+ if (copy_from_user(kdata, (void __user *)arg,
+ _IOC_SIZE(cmd)) != 0) {
+ retcode = -EACCES;
+ goto err_i1;
+ }
+ }
+ retcode = func(dev, kdata, file_priv);
+
+ if (cmd & IOC_OUT) {
+ if (copy_to_user((void __user *)arg, kdata,
+ _IOC_SIZE(cmd)) != 0)
+ retcode = -EACCES;
+ }
}
err_i1:
+ if (kdata)
+ kfree(kdata);
atomic_dec(&dev->ioctl_count);
if (retcode)
DRM_DEBUG("ret = %x\n", retcode);
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 7bc51bac450..3992f73299c 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -234,7 +234,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
if (!drm_cpu_valid())
return -EINVAL;
- DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor);
+ DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor);
priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES);
if (!priv)
@@ -242,8 +242,9 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
memset(priv, 0, sizeof(*priv));
filp->private_data = priv;
+ priv->filp = filp;
priv->uid = current->euid;
- priv->pid = current->pid;
+ priv->pid = task_pid_nr(current);
priv->minor = minor;
priv->head = drm_heads[minor];
priv->ioctl_count = 0;
@@ -312,7 +313,7 @@ EXPORT_SYMBOL(drm_fasync);
* Release file.
*
* \param inode device inode
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \return zero on success or a negative number on failure.
*
* If the hardware lock is held then free it, and take it again for the kernel
@@ -322,29 +323,29 @@ EXPORT_SYMBOL(drm_fasync);
*/
int drm_release(struct inode *inode, struct file *filp)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev;
+ struct drm_file *file_priv = filp->private_data;
+ struct drm_device *dev = file_priv->head->dev;
int retcode = 0;
lock_kernel();
- dev = priv->head->dev;
DRM_DEBUG("open_count = %d\n", dev->open_count);
if (dev->driver->preclose)
- dev->driver->preclose(dev, filp);
+ dev->driver->preclose(dev, file_priv);
/* ========================================================
* Begin inline drm_release
*/
DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
- current->pid, (long)old_encode_dev(priv->head->device),
+ task_pid_nr(current),
+ (long)old_encode_dev(file_priv->head->device),
dev->open_count);
if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
- if (drm_i_have_hw_lock(filp)) {
- dev->driver->reclaim_buffers_locked(dev, filp);
+ if (drm_i_have_hw_lock(dev, file_priv)) {
+ dev->driver->reclaim_buffers_locked(dev, file_priv);
} else {
unsigned long _end=jiffies + 3*DRM_HZ;
int locked = 0;
@@ -370,7 +371,7 @@ int drm_release(struct inode *inode, struct file *filp)
"\tI will go on reclaiming the buffers anyway.\n");
}
- dev->driver->reclaim_buffers_locked(dev, filp);
+ dev->driver->reclaim_buffers_locked(dev, file_priv);
drm_idlelock_release(&dev->lock);
}
}
@@ -378,12 +379,12 @@ int drm_release(struct inode *inode, struct file *filp)
if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) {
drm_idlelock_take(&dev->lock);
- dev->driver->reclaim_buffers_idlelocked(dev, filp);
+ dev->driver->reclaim_buffers_idlelocked(dev, file_priv);
drm_idlelock_release(&dev->lock);
}
- if (drm_i_have_hw_lock(filp)) {
+ if (drm_i_have_hw_lock(dev, file_priv)) {
DRM_DEBUG("File %p released, freeing lock for context %d\n",
filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
@@ -394,7 +395,7 @@ int drm_release(struct inode *inode, struct file *filp)
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
!dev->driver->reclaim_buffers_locked) {
- dev->driver->reclaim_buffers(dev, filp);
+ dev->driver->reclaim_buffers(dev, file_priv);
}
drm_fasync(-1, filp, 0);
@@ -404,7 +405,7 @@ int drm_release(struct inode *inode, struct file *filp)
struct drm_ctx_list *pos, *n;
list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
- if (pos->tag == priv &&
+ if (pos->tag == file_priv &&
pos->handle != DRM_KERNEL_CONTEXT) {
if (dev->driver->context_dtor)
dev->driver->context_dtor(dev,
@@ -421,18 +422,18 @@ int drm_release(struct inode *inode, struct file *filp)
mutex_unlock(&dev->ctxlist_mutex);
mutex_lock(&dev->struct_mutex);
- if (priv->remove_auth_on_close == 1) {
+ if (file_priv->remove_auth_on_close == 1) {
struct drm_file *temp;
list_for_each_entry(temp, &dev->filelist, lhead)
temp->authenticated = 0;
}
- list_del(&priv->lhead);
+ list_del(&file_priv->lhead);
mutex_unlock(&dev->struct_mutex);
if (dev->driver->postclose)
- dev->driver->postclose(dev, priv);
- drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
+ dev->driver->postclose(dev, file_priv);
+ drm_free(file_priv, sizeof(*file_priv), DRM_MEM_FILES);
/* ========================================================
* End inline drm_release
diff --git a/drivers/char/drm/drm_hashtab.c b/drivers/char/drm/drm_hashtab.c
index 3ad31907070..4b8e7db5a23 100644
--- a/drivers/char/drm/drm_hashtab.c
+++ b/drivers/char/drm/drm_hashtab.c
@@ -29,7 +29,7 @@
* Simple open hash tab implementation.
*
* Authors:
- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include "drmP.h"
diff --git a/drivers/char/drm/drm_hashtab.h b/drivers/char/drm/drm_hashtab.h
index 0f137677416..573e333ac45 100644
--- a/drivers/char/drm/drm_hashtab.h
+++ b/drivers/char/drm/drm_hashtab.h
@@ -29,7 +29,7 @@
* Simple open hash tab implementation.
*
* Authors:
- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#ifndef DRM_HASHTAB_H
diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c
index 462f46f2049..2286f3312c5 100644
--- a/drivers/char/drm/drm_ioc32.c
+++ b/drivers/char/drm/drm_ioc32.c
@@ -1040,7 +1040,7 @@ drm_ioctl_compat_t *drm_compat_ioctls[] = {
* Called whenever a 32-bit process running under a 64-bit kernel
* performs an ioctl on /dev/drm.
*
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument.
* \return zero on success or negative number on failure.
diff --git a/drivers/char/drm/drm_ioctl.c b/drivers/char/drm/drm_ioctl.c
index b195e102e73..3cbebf868e6 100644
--- a/drivers/char/drm/drm_ioctl.c
+++ b/drivers/char/drm/drm_ioctl.c
@@ -42,30 +42,24 @@
* Get the bus id.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_unique structure.
* \return zero on success or a negative number on failure.
*
* Copies the bus id from drm_device::unique into user space.
*/
-int drm_getunique(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getunique(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_unique __user *argp = (void __user *)arg;
- struct drm_unique u;
+ struct drm_unique *u = data;
- if (copy_from_user(&u, argp, sizeof(u)))
- return -EFAULT;
- if (u.unique_len >= dev->unique_len) {
- if (copy_to_user(u.unique, dev->unique, dev->unique_len))
+ if (u->unique_len >= dev->unique_len) {
+ if (copy_to_user(u->unique, dev->unique, dev->unique_len))
return -EFAULT;
}
- u.unique_len = dev->unique_len;
- if (copy_to_user(argp, &u, sizeof(u)))
- return -EFAULT;
+ u->unique_len = dev->unique_len;
+
return 0;
}
@@ -73,7 +67,7 @@ int drm_getunique(struct inode *inode, struct file *filp,
* Set the bus id.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_unique structure.
* \return zero on success or a negative number on failure.
@@ -83,28 +77,23 @@ int drm_getunique(struct inode *inode, struct file *filp,
* in interface version 1.1 and will return EBUSY when setversion has requested
* version 1.1 or greater.
*/
-int drm_setunique(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_setunique(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_unique u;
+ struct drm_unique *u = data;
int domain, bus, slot, func, ret;
if (dev->unique_len || dev->unique)
return -EBUSY;
- if (copy_from_user(&u, (struct drm_unique __user *) arg, sizeof(u)))
- return -EFAULT;
-
- if (!u.unique_len || u.unique_len > 1024)
+ if (!u->unique_len || u->unique_len > 1024)
return -EINVAL;
- dev->unique_len = u.unique_len;
- dev->unique = drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER);
+ dev->unique_len = u->unique_len;
+ dev->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER);
if (!dev->unique)
return -ENOMEM;
- if (copy_from_user(dev->unique, u.unique, dev->unique_len))
+ if (copy_from_user(dev->unique, u->unique, dev->unique_len))
return -EFAULT;
dev->unique[dev->unique_len] = '\0';
@@ -123,7 +112,7 @@ int drm_setunique(struct inode *inode, struct file *filp,
*/
ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
if (ret != 3)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
domain = bus >> 8;
bus &= 0xff;
@@ -172,7 +161,7 @@ static int drm_set_busid(struct drm_device * dev)
* Get a mapping information.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_map structure.
*
@@ -181,21 +170,16 @@ static int drm_set_busid(struct drm_device * dev)
* Searches for the mapping with the specified offset and copies its information
* into userspace
*/
-int drm_getmap(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getmap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_map __user *argp = (void __user *)arg;
- struct drm_map map;
+ struct drm_map *map = data;
struct drm_map_list *r_list = NULL;
struct list_head *list;
int idx;
int i;
- if (copy_from_user(&map, argp, sizeof(map)))
- return -EFAULT;
- idx = map.offset;
+ idx = map->offset;
mutex_lock(&dev->struct_mutex);
if (idx < 0) {
@@ -216,16 +200,14 @@ int drm_getmap(struct inode *inode, struct file *filp,
return -EINVAL;
}
- map.offset = r_list->map->offset;
- map.size = r_list->map->size;
- map.type = r_list->map->type;
- map.flags = r_list->map->flags;
- map.handle = (void *)(unsigned long)r_list->user_token;
- map.mtrr = r_list->map->mtrr;
+ map->offset = r_list->map->offset;
+ map->size = r_list->map->size;
+ map->type = r_list->map->type;
+ map->flags = r_list->map->flags;
+ map->handle = (void *)(unsigned long) r_list->user_token;
+ map->mtrr = r_list->map->mtrr;
mutex_unlock(&dev->struct_mutex);
- if (copy_to_user(argp, &map, sizeof(map)))
- return -EFAULT;
return 0;
}
@@ -233,7 +215,7 @@ int drm_getmap(struct inode *inode, struct file *filp,
* Get client information.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_client structure.
*
@@ -242,20 +224,15 @@ int drm_getmap(struct inode *inode, struct file *filp,
* Searches for the client with the specified index and copies its information
* into userspace
*/
-int drm_getclient(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getclient(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_client __user *argp = (struct drm_client __user *)arg;
- struct drm_client client;
+ struct drm_client *client = data;
struct drm_file *pt;
int idx;
int i;
- if (copy_from_user(&client, argp, sizeof(client)))
- return -EFAULT;
- idx = client.idx;
+ idx = client->idx;
mutex_lock(&dev->struct_mutex);
if (list_empty(&dev->filelist)) {
@@ -269,15 +246,13 @@ int drm_getclient(struct inode *inode, struct file *filp,
break;
}
- client.auth = pt->authenticated;
- client.pid = pt->pid;
- client.uid = pt->uid;
- client.magic = pt->magic;
- client.iocs = pt->ioctl_count;
+ client->auth = pt->authenticated;
+ client->pid = pt->pid;
+ client->uid = pt->uid;
+ client->magic = pt->magic;
+ client->iocs = pt->ioctl_count;
mutex_unlock(&dev->struct_mutex);
- if (copy_to_user(argp, &client, sizeof(client)))
- return -EFAULT;
return 0;
}
@@ -285,39 +260,35 @@ int drm_getclient(struct inode *inode, struct file *filp,
* Get statistics information.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_stats structure.
*
* \return zero on success or a negative number on failure.
*/
-int drm_getstats(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_getstats(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_stats stats;
+ struct drm_stats *stats = data;
int i;
- memset(&stats, 0, sizeof(stats));
+ memset(stats, 0, sizeof(*stats));
mutex_lock(&dev->struct_mutex);
for (i = 0; i < dev->counters; i++) {
if (dev->types[i] == _DRM_STAT_LOCK)
- stats.data[i].value
- = (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0);
+ stats->data[i].value =
+ (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0);
else
- stats.data[i].value = atomic_read(&dev->counts[i]);
- stats.data[i].type = dev->types[i];
+ stats->data[i].value = atomic_read(&dev->counts[i]);
+ stats->data[i].type = dev->types[i];
}
- stats.count = dev->counters;
+ stats->count = dev->counters;
mutex_unlock(&dev->struct_mutex);
- if (copy_to_user((struct drm_stats __user *) arg, &stats, sizeof(stats)))
- return -EFAULT;
return 0;
}
@@ -325,64 +296,59 @@ int drm_getstats(struct inode *inode, struct file *filp,
* Setversion ioctl.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_lock structure.
* \return zero on success or negative number on failure.
*
* Sets the requested interface version
*/
-int drm_setversion(DRM_IOCTL_ARGS)
+int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- struct drm_set_version sv;
- struct drm_set_version retv;
- int if_version;
- struct drm_set_version __user *argp = (void __user *)data;
- int ret;
-
- if (copy_from_user(&sv, argp, sizeof(sv)))
- return -EFAULT;
-
- retv.drm_di_major = DRM_IF_MAJOR;
- retv.drm_di_minor = DRM_IF_MINOR;
- retv.drm_dd_major = dev->driver->major;
- retv.drm_dd_minor = dev->driver->minor;
-
- if (copy_to_user(argp, &retv, sizeof(retv)))
- return -EFAULT;
-
- if (sv.drm_di_major != -1) {
- if (sv.drm_di_major != DRM_IF_MAJOR ||
- sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
- return -EINVAL;
- if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor);
+ struct drm_set_version *sv = data;
+ int if_version, retcode = 0;
+
+ if (sv->drm_di_major != -1) {
+ if (sv->drm_di_major != DRM_IF_MAJOR ||
+ sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) {
+ retcode = -EINVAL;
+ goto done;
+ }
+ if_version = DRM_IF_VERSION(sv->drm_di_major,
+ sv->drm_di_minor);
dev->if_version = max(if_version, dev->if_version);
- if (sv.drm_di_minor >= 1) {
+ if (sv->drm_di_minor >= 1) {
/*
* Version 1.1 includes tying of DRM to specific device
*/
- ret = drm_set_busid(dev);
- if (ret)
- return ret;
+ drm_set_busid(dev);
}
}
- if (sv.drm_dd_major != -1) {
- if (sv.drm_dd_major != dev->driver->major ||
- sv.drm_dd_minor < 0
- || sv.drm_dd_minor > dev->driver->minor)
- return -EINVAL;
+ if (sv->drm_dd_major != -1) {
+ if (sv->drm_dd_major != dev->driver->major ||
+ sv->drm_dd_minor < 0 || sv->drm_dd_minor >
+ dev->driver->minor) {
+ retcode = -EINVAL;
+ goto done;
+ }
if (dev->driver->set_version)
- dev->driver->set_version(dev, &sv);
+ dev->driver->set_version(dev, sv);
}
- return 0;
+
+done:
+ sv->drm_di_major = DRM_IF_MAJOR;
+ sv->drm_di_minor = DRM_IF_MINOR;
+ sv->drm_dd_major = dev->driver->major;
+ sv->drm_dd_minor = dev->driver->minor;
+
+ return retcode;
}
/** No-op ioctl. */
-int drm_noop(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+int drm_noop(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
DRM_DEBUG("\n");
return 0;
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index 871d2fde09b..05eae63f85b 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -41,7 +41,7 @@
* Get interrupt from bus id.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_irq_busid structure.
* \return zero on success or a negative number on failure.
@@ -50,30 +50,24 @@
* This IOCTL is deprecated, and will now return EINVAL for any busid not equal
* to that of the device that this DRM instance attached to.
*/
-int drm_irq_by_busid(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_irq_by_busid(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_irq_busid __user *argp = (void __user *)arg;
- struct drm_irq_busid p;
+ struct drm_irq_busid *p = data;
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL;
- if (copy_from_user(&p, argp, sizeof(p)))
- return -EFAULT;
-
- if ((p.busnum >> 8) != drm_get_pci_domain(dev) ||
- (p.busnum & 0xff) != dev->pdev->bus->number ||
- p.devnum != PCI_SLOT(dev->pdev->devfn) || p.funcnum != PCI_FUNC(dev->pdev->devfn))
+ if ((p->busnum >> 8) != drm_get_pci_domain(dev) ||
+ (p->busnum & 0xff) != dev->pdev->bus->number ||
+ p->devnum != PCI_SLOT(dev->pdev->devfn) || p->funcnum != PCI_FUNC(dev->pdev->devfn))
return -EINVAL;
- p.irq = dev->irq;
+ p->irq = dev->irq;
+
+ DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum,
+ p->irq);
- DRM_DEBUG("%d:%d:%d => IRQ %d\n", p.busnum, p.devnum, p.funcnum, p.irq);
- if (copy_to_user(argp, &p, sizeof(p)))
- return -EFAULT;
return 0;
}
@@ -187,31 +181,27 @@ EXPORT_SYMBOL(drm_irq_uninstall);
* IRQ control ioctl.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_control structure.
* \return zero on success or a negative number on failure.
*
* Calls irq_install() or irq_uninstall() according to \p arg.
*/
-int drm_control(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_control(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_control ctl;
+ 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 (copy_from_user(&ctl, (struct drm_control __user *) arg, sizeof(ctl)))
- return -EFAULT;
- switch (ctl.func) {
+ switch (ctl->func) {
case DRM_INST_HANDLER:
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return 0;
if (dev->if_version < DRM_IF_VERSION(1, 2) &&
- ctl.irq != dev->irq)
+ ctl->irq != dev->irq)
return -EINVAL;
return drm_irq_install(dev);
case DRM_UNINST_HANDLER:
@@ -227,7 +217,7 @@ int drm_control(struct inode *inode, struct file *filp,
* Wait for VBLANK.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param data user argument, pointing to a drm_wait_vblank structure.
* \return zero on success or a negative number on failure.
@@ -242,31 +232,25 @@ int drm_control(struct inode *inode, struct file *filp,
*
* If a signal is not requested, then calls vblank_wait().
*/
-int drm_wait_vblank(DRM_IOCTL_ARGS)
+int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- union drm_wait_vblank __user *argp = (void __user *)data;
- union drm_wait_vblank vblwait;
+ union drm_wait_vblank *vblwait = data;
struct timeval now;
int ret = 0;
unsigned int flags, seq;
- if (!dev->irq)
+ if ((!dev->irq) || (!dev->irq_enabled))
return -EINVAL;
- if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
- return -EFAULT;
-
- if (vblwait.request.type &
+ if (vblwait->request.type &
~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) {
DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n",
- vblwait.request.type,
+ vblwait->request.type,
(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK));
return -EINVAL;
}
- flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK;
+ flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK;
if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ?
DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
@@ -275,10 +259,10 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
: &dev->vbl_received);
- switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
+ switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) {
case _DRM_VBLANK_RELATIVE:
- vblwait.request.sequence += seq;
- vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+ vblwait->request.sequence += seq;
+ vblwait->request.type &= ~_DRM_VBLANK_RELATIVE;
case _DRM_VBLANK_ABSOLUTE:
break;
default:
@@ -286,8 +270,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
}
if ((flags & _DRM_VBLANK_NEXTONMISS) &&
- (seq - vblwait.request.sequence) <= (1<<23)) {
- vblwait.request.sequence = seq + 1;
+ (seq - vblwait->request.sequence) <= (1<<23)) {
+ vblwait->request.sequence = seq + 1;
}
if (flags & _DRM_VBLANK_SIGNAL) {
@@ -303,12 +287,13 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
* that case
*/
list_for_each_entry(vbl_sig, vbl_sigs, head) {
- if (vbl_sig->sequence == vblwait.request.sequence
- && vbl_sig->info.si_signo == vblwait.request.signal
+ if (vbl_sig->sequence == vblwait->request.sequence
+ && vbl_sig->info.si_signo ==
+ vblwait->request.signal
&& vbl_sig->task == current) {
spin_unlock_irqrestore(&dev->vbl_lock,
irqflags);
- vblwait.reply.sequence = seq;
+ vblwait->reply.sequence = seq;
goto done;
}
}
@@ -330,8 +315,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
memset((void *)vbl_sig, 0, sizeof(*vbl_sig));
- vbl_sig->sequence = vblwait.request.sequence;
- vbl_sig->info.si_signo = vblwait.request.signal;
+ vbl_sig->sequence = vblwait->request.sequence;
+ vbl_sig->info.si_signo = vblwait->request.signal;
vbl_sig->task = current;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
@@ -340,25 +325,22 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
- vblwait.reply.sequence = seq;
+ vblwait->reply.sequence = seq;
} else {
if (flags & _DRM_VBLANK_SECONDARY) {
if (dev->driver->vblank_wait2)
- ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence);
+ ret = dev->driver->vblank_wait2(dev, &vblwait->request.sequence);
} else if (dev->driver->vblank_wait)
ret =
dev->driver->vblank_wait(dev,
- &vblwait.request.sequence);
+ &vblwait->request.sequence);
do_gettimeofday(&now);
- vblwait.reply.tval_sec = now.tv_sec;
- vblwait.reply.tval_usec = now.tv_usec;
+ vblwait->reply.tval_sec = now.tv_sec;
+ vblwait->reply.tval_usec = now.tv_usec;
}
done:
- if (copy_to_user(argp, &vblwait, sizeof(vblwait)))
- return -EFAULT;
-
return ret;
}
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
index c0534b5a8b7..bea2a7d5b2b 100644
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -41,39 +41,33 @@ static int drm_notifier(void *priv);
* Lock ioctl.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_lock structure.
* \return zero on success or negative number on failure.
*
* Add the current task to the lock wait queue, and attempt to take to lock.
*/
-int drm_lock(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
DECLARE_WAITQUEUE(entry, current);
- struct drm_lock lock;
+ struct drm_lock *lock = data;
int ret = 0;
- ++priv->lock_count;
+ ++file_priv->lock_count;
- if (copy_from_user(&lock, (struct drm_lock __user *) arg, sizeof(lock)))
- return -EFAULT;
-
- if (lock.context == DRM_KERNEL_CONTEXT) {
+ if (lock->context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
- current->pid, lock.context);
+ task_pid_nr(current), lock->context);
return -EINVAL;
}
DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
- lock.context, current->pid,
- dev->lock.hw_lock->lock, lock.flags);
+ lock->context, task_pid_nr(current),
+ dev->lock.hw_lock->lock, lock->flags);
if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE))
- if (lock.context < 0)
+ if (lock->context < 0)
return -EINVAL;
add_wait_queue(&dev->lock.lock_queue, &entry);
@@ -87,8 +81,8 @@ int drm_lock(struct inode *inode, struct file *filp,
ret = -EINTR;
break;
}
- if (drm_lock_take(&dev->lock, lock.context)) {
- dev->lock.filp = filp;
+ if (drm_lock_take(&dev->lock, lock->context)) {
+ dev->lock.file_priv = file_priv;
dev->lock.lock_time = jiffies;
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
break; /* Got lock */
@@ -107,7 +101,8 @@ int drm_lock(struct inode *inode, struct file *filp,
__set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->lock.lock_queue, &entry);
- DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" );
+ DRM_DEBUG("%d %s\n", lock->context,
+ ret ? "interrupted" : "has lock");
if (ret) return ret;
sigemptyset(&dev->sigmask);
@@ -115,24 +110,26 @@ int drm_lock(struct inode *inode, struct file *filp,
sigaddset(&dev->sigmask, SIGTSTP);
sigaddset(&dev->sigmask, SIGTTIN);
sigaddset(&dev->sigmask, SIGTTOU);
- dev->sigdata.context = lock.context;
+ dev->sigdata.context = lock->context;
dev->sigdata.lock = dev->lock.hw_lock;
block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
- if (dev->driver->dma_ready && (lock.flags & _DRM_LOCK_READY))
+ if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY))
dev->driver->dma_ready(dev);
- if (dev->driver->dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT)) {
+ if (dev->driver->dma_quiescent && (lock->flags & _DRM_LOCK_QUIESCENT))
+ {
if (dev->driver->dma_quiescent(dev)) {
- DRM_DEBUG("%d waiting for DMA quiescent\n", lock.context);
- return DRM_ERR(EBUSY);
+ DRM_DEBUG("%d waiting for DMA quiescent\n",
+ lock->context);
+ return -EBUSY;
}
}
if (dev->driver->kernel_context_switch &&
- dev->last_context != lock.context) {
+ dev->last_context != lock->context) {
dev->driver->kernel_context_switch(dev, dev->last_context,
- lock.context);
+ lock->context);
}
return 0;
@@ -142,27 +139,21 @@ int drm_lock(struct inode *inode, struct file *filp,
* Unlock ioctl.
*
* \param inode device inode.
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param cmd command.
* \param arg user argument, pointing to a drm_lock structure.
* \return zero on success or negative number on failure.
*
* Transfer and free the lock.
*/
-int drm_unlock(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_lock lock;
+ struct drm_lock *lock = data;
unsigned long irqflags;
- if (copy_from_user(&lock, (struct drm_lock __user *) arg, sizeof(lock)))
- return -EFAULT;
-
- if (lock.context == DRM_KERNEL_CONTEXT) {
+ if (lock->context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
- current->pid, lock.context);
+ task_pid_nr(current), lock->context);
return -EINVAL;
}
@@ -184,7 +175,7 @@ int drm_unlock(struct inode *inode, struct file *filp,
if (dev->driver->kernel_context_switch_unlock)
dev->driver->kernel_context_switch_unlock(dev);
else {
- if (drm_lock_free(&dev->lock,lock.context)) {
+ if (drm_lock_free(&dev->lock,lock->context)) {
/* FIXME: Should really bail out here. */
}
}
@@ -257,7 +248,7 @@ static int drm_lock_transfer(struct drm_lock_data *lock_data,
unsigned int old, new, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock;
- lock_data->filp = NULL;
+ lock_data->file_priv = NULL;
do {
old = *lock;
new = context | _DRM_LOCK_HELD;
@@ -390,13 +381,11 @@ void drm_idlelock_release(struct drm_lock_data *lock_data)
EXPORT_SYMBOL(drm_idlelock_release);
-int drm_i_have_hw_lock(struct file *filp)
+int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)
{
- DRM_DEVICE;
-
- return (priv->lock_count && dev->lock.hw_lock &&
+ return (file_priv->lock_count && dev->lock.hw_lock &&
_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
- dev->lock.filp == filp);
+ dev->lock.file_priv == file_priv);
}
EXPORT_SYMBOL(drm_i_have_hw_lock);
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c
index 3e6bc14f744..86f4eb61a6a 100644
--- a/drivers/char/drm/drm_mm.c
+++ b/drivers/char/drm/drm_mm.c
@@ -38,7 +38,7 @@
* Aligned allocations can also see improvement.
*
* Authors:
- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include "drmP.h"
diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h
index 0b8d3433386..daa69c9d897 100644
--- a/drivers/char/drm/drm_os_linux.h
+++ b/drivers/char/drm/drm_os_linux.h
@@ -6,13 +6,8 @@
#include <linux/interrupt.h> /* For task queue support */
#include <linux/delay.h>
-/** File pointer type */
-#define DRMFILE struct file *
-/** Ioctl arguments */
-#define DRM_IOCTL_ARGS struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data
-#define DRM_ERR(d) -(d)
/** Current process ID */
-#define DRM_CURRENTPID current->pid
+#define DRM_CURRENTPID task_pid_nr(current)
#define DRM_SUSER(p) capable(CAP_SYS_ADMIN)
#define DRM_UDELAY(d) udelay(d)
/** Read a byte from a MMIO region */
@@ -33,9 +28,6 @@
#define DRM_WRITEMEMORYBARRIER() wmb()
/** Read/write memory barrier */
#define DRM_MEMORYBARRIER() mb()
-/** DRM device local declaration */
-#define DRM_DEVICE struct drm_file *priv = filp->private_data; \
- struct drm_device *dev = priv->head->dev
/** IRQ handler arguments and return type and values */
#define DRM_IRQ_ARGS int irq, void *arg
@@ -70,14 +62,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size)
#endif
-/** For data going into the kernel through the ioctl argument */
-#define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3) \
- if ( copy_from_user(&arg1, arg2, arg3) ) \
- return -EFAULT
-/** For data going from the kernel through the ioctl argument */
-#define DRM_COPY_TO_USER_IOCTL(arg1, arg2, arg3) \
- if ( copy_to_user(arg1, &arg2, arg3) ) \
- return -EFAULT
/** Other copying of data to kernel space */
#define DRM_COPY_FROM_USER(arg1, arg2, arg3) \
copy_from_user(arg1, arg2, arg3)
@@ -94,8 +78,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size)
#define DRM_GET_USER_UNCHECKED(val, uaddr) \
__get_user(val, uaddr)
-#define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv = _filp->private_data
-
#define DRM_HZ HZ
#define DRM_WAIT_ON( ret, queue, timeout, condition ) \
diff --git a/drivers/char/drm/drm_pci.c b/drivers/char/drm/drm_pci.c
index e292bb0eaca..b55d5bc6ea6 100644
--- a/drivers/char/drm/drm_pci.c
+++ b/drivers/char/drm/drm_pci.c
@@ -8,12 +8,12 @@
* \todo Implement the remaining ioctl's for the PCI pools.
* \todo The wrappers here are so thin that they would be better off inlined..
*
- * \author Jose Fonseca <jrfonseca@tungstengraphics.com>
+ * \author José Fonseca <jrfonseca@tungstengraphics.com>
* \author Leif Delgass <ldelgass@retinalburn.net>
*/
/*
- * Copyright 2003 Jos�Fonseca.
+ * Copyright 2003 José Fonseca.
* Copyright 2003 Leif Delgass.
* All Rights Reserved.
*
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index 30b200b0131..f3593974496 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -236,10 +236,8 @@
{0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
{0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
- {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
- {0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
diff --git a/drivers/char/drm/drm_sarea.h b/drivers/char/drm/drm_sarea.h
index f5466966081..e040f47f369 100644
--- a/drivers/char/drm/drm_sarea.h
+++ b/drivers/char/drm/drm_sarea.h
@@ -2,7 +2,7 @@
* \file drm_sarea.h
* \brief SAREA definitions
*
- * \author Michel Dänzer <michel@daenzer.net>
+ * \author Michel Dänzer <michel@daenzer.net>
*/
/*
diff --git a/drivers/char/drm/drm_scatter.c b/drivers/char/drm/drm_scatter.c
index 067d25daaf1..eb7fa437355 100644
--- a/drivers/char/drm/drm_scatter.c
+++ b/drivers/char/drm/drm_scatter.c
@@ -62,13 +62,8 @@ void drm_sg_cleanup(struct drm_sg_mem * entry)
# define ScatterHandle(x) (unsigned int)(x)
#endif
-int drm_sg_alloc(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_scatter_gather __user *argp = (void __user *)arg;
- struct drm_scatter_gather request;
struct drm_sg_mem *entry;
unsigned long pages, i, j;
@@ -80,17 +75,13 @@ int drm_sg_alloc(struct inode *inode, struct file *filp,
if (dev->sg)
return -EINVAL;
- if (copy_from_user(&request, argp, sizeof(request)))
- return -EFAULT;
-
entry = drm_alloc(sizeof(*entry), DRM_MEM_SGLISTS);
if (!entry)
return -ENOMEM;
memset(entry, 0, sizeof(*entry));
-
- pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
- DRM_DEBUG("sg size=%ld pages=%ld\n", request.size, pages);
+ pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
+ DRM_DEBUG("sg size=%ld pages=%ld\n", request->size, pages);
entry->pages = pages;
entry->pagelist = drm_alloc(pages * sizeof(*entry->pagelist),
@@ -142,12 +133,7 @@ int drm_sg_alloc(struct inode *inode, struct file *filp,
SetPageReserved(entry->pagelist[j]);
}
- request.handle = entry->handle;
-
- if (copy_to_user(argp, &request, sizeof(request))) {
- drm_sg_cleanup(entry);
- return -EFAULT;
- }
+ request->handle = entry->handle;
dev->sg = entry;
@@ -197,27 +183,31 @@ int drm_sg_alloc(struct inode *inode, struct file *filp,
drm_sg_cleanup(entry);
return -ENOMEM;
}
+EXPORT_SYMBOL(drm_sg_alloc);
+
-int drm_sg_free(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+int drm_sg_alloc_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- struct drm_scatter_gather request;
+ struct drm_scatter_gather *request = data;
+
+ return drm_sg_alloc(dev, request);
+
+}
+
+int drm_sg_free(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_scatter_gather *request = data;
struct drm_sg_mem *entry;
if (!drm_core_check_feature(dev, DRIVER_SG))
return -EINVAL;
- if (copy_from_user(&request,
- (struct drm_scatter_gather __user *) arg,
- sizeof(request)))
- return -EFAULT;
-
entry = dev->sg;
dev->sg = NULL;
- if (!entry || entry->handle != request.handle)
+ if (!entry || entry->handle != request->handle)
return -EINVAL;
DRM_DEBUG("sg free virtual = %p\n", entry->virtual);
diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c
index 8421a93946d..926f146390c 100644
--- a/drivers/char/drm/drm_sman.c
+++ b/drivers/char/drm/drm_sman.c
@@ -33,7 +33,7 @@
* struct or a context identifier.
*
* Authors:
- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include "drm_sman.h"
diff --git a/drivers/char/drm/drm_sman.h b/drivers/char/drm/drm_sman.h
index 39a39fefeef..08ecf83ad5d 100644
--- a/drivers/char/drm/drm_sman.h
+++ b/drivers/char/drm/drm_sman.h
@@ -33,7 +33,7 @@
* struct or a context identifier.
*
* Authors:
- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#ifndef DRM_SMAN_H
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index 68e36e51ba0..e8d50af5820 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -463,7 +463,7 @@ static void drm_vm_close(struct vm_area_struct *vma)
/**
* mmap DMA memory.
*
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param vma virtual memory area.
* \return zero on success or a negative number on failure.
*
@@ -533,7 +533,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs);
/**
* mmap DMA memory.
*
- * \param filp file pointer.
+ * \param file_priv DRM file private.
* \param vma virtual memory area.
* \return zero on success or a negative number on failure.
*
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index cb449999d0e..eb381a7c5be 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -120,10 +120,9 @@ static const struct file_operations i810_buffer_fops = {
.fasync = drm_fasync,
};
-static int i810_map_buffer(struct drm_buf * buf, struct file *filp)
+static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = file_priv->head->dev;
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
drm_i810_private_t *dev_priv = dev->dev_private;
const struct file_operations *old_fops;
@@ -133,14 +132,14 @@ static int i810_map_buffer(struct drm_buf * buf, struct file *filp)
return -EINVAL;
down_write(&current->mm->mmap_sem);
- old_fops = filp->f_op;
- filp->f_op = &i810_buffer_fops;
+ old_fops = file_priv->filp->f_op;
+ file_priv->filp->f_op = &i810_buffer_fops;
dev_priv->mmap_buffer = buf;
- buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total,
+ buf_priv->virtual = (void *)do_mmap(file_priv->filp, 0, buf->total,
PROT_READ | PROT_WRITE,
MAP_SHARED, buf->bus_address);
dev_priv->mmap_buffer = NULL;
- filp->f_op = old_fops;
+ file_priv->filp->f_op = old_fops;
if (IS_ERR(buf_priv->virtual)) {
/* Real error */
DRM_ERROR("mmap error\n");
@@ -173,7 +172,7 @@ static int i810_unmap_buffer(struct drm_buf * buf)
}
static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d,
- struct file *filp)
+ struct drm_file *file_priv)
{
struct drm_buf *buf;
drm_i810_buf_priv_t *buf_priv;
@@ -186,13 +185,13 @@ static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d,
return retcode;
}
- retcode = i810_map_buffer(buf, filp);
+ retcode = i810_map_buffer(buf, file_priv);
if (retcode) {
i810_freelist_put(dev, buf);
DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
return retcode;
}
- buf->filp = filp;
+ buf->file_priv = file_priv;
buf_priv = buf->dev_private;
d->granted = 1;
d->request_idx = buf->idx;
@@ -380,7 +379,7 @@ static int i810_dma_initialize(struct drm_device * dev,
i810_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -430,99 +429,29 @@ static int i810_dma_initialize(struct drm_device * dev,
return 0;
}
-/* i810 DRM version 1.1 used a smaller init structure with different
- * ordering of values than is currently used (drm >= 1.2). There is
- * no defined way to detect the XFree version to correct this problem,
- * however by checking using this procedure we can detect the correct
- * thing to do.
- *
- * #1 Read the Smaller init structure from user-space
- * #2 Verify the overlay_physical is a valid physical address, or NULL
- * If it isn't then we have a v1.1 client. Fix up params.
- * If it is, then we have a 1.2 client... get the rest of the data.
- */
-static int i810_dma_init_compat(drm_i810_init_t * init, unsigned long arg)
+static int i810_dma_init(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
-
- /* Get v1.1 init data */
- if (copy_from_user(init, (drm_i810_pre12_init_t __user *) arg,
- sizeof(drm_i810_pre12_init_t))) {
- return -EFAULT;
- }
-
- if ((!init->overlay_physical) || (init->overlay_physical > 4096)) {
-
- /* This is a v1.2 client, just get the v1.2 init data */
- DRM_INFO("Using POST v1.2 init.\n");
- if (copy_from_user(init, (drm_i810_init_t __user *) arg,
- sizeof(drm_i810_init_t))) {
- return -EFAULT;
- }
- } else {
-
- /* This is a v1.1 client, fix the params */
- DRM_INFO("Using PRE v1.2 init.\n");
- init->pitch_bits = init->h;
- init->pitch = init->w;
- init->h = init->overlay_physical;
- init->w = init->overlay_offset;
- init->overlay_physical = 0;
- init->overlay_offset = 0;
- }
-
- return 0;
-}
-
-static int i810_dma_init(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv;
- drm_i810_init_t init;
+ drm_i810_init_t *init = data;
int retcode = 0;
- /* Get only the init func */
- if (copy_from_user
- (&init, (void __user *)arg, sizeof(drm_i810_init_func_t)))
- return -EFAULT;
-
- switch (init.func) {
- case I810_INIT_DMA:
- /* This case is for backward compatibility. It
- * handles XFree 4.1.0 and 4.2.0, and has to
- * do some parameter checking as described below.
- * It will someday go away.
- */
- retcode = i810_dma_init_compat(&init, arg);
- if (retcode)
- return retcode;
-
- dev_priv = drm_alloc(sizeof(drm_i810_private_t),
- DRM_MEM_DRIVER);
- if (dev_priv == NULL)
- return -ENOMEM;
- retcode = i810_dma_initialize(dev, dev_priv, &init);
- break;
-
- default:
+ switch (init->func) {
case I810_INIT_DMA_1_4:
DRM_INFO("Using v1.4 init.\n");
- if (copy_from_user(&init, (drm_i810_init_t __user *) arg,
- sizeof(drm_i810_init_t))) {
- return -EFAULT;
- }
dev_priv = drm_alloc(sizeof(drm_i810_private_t),
DRM_MEM_DRIVER);
if (dev_priv == NULL)
return -ENOMEM;
- retcode = i810_dma_initialize(dev, dev_priv, &init);
+ retcode = i810_dma_initialize(dev, dev_priv, init);
break;
case I810_CLEANUP_DMA:
DRM_INFO("DMA Cleanup\n");
retcode = i810_dma_cleanup(dev);
break;
+ default:
+ return -EINVAL;
}
return retcode;
@@ -968,7 +897,8 @@ static int i810_flush_queue(struct drm_device * dev)
}
/* Must be called with the lock held */
-static void i810_reclaim_buffers(struct drm_device * dev, struct file *filp)
+static void i810_reclaim_buffers(struct drm_device * dev,
+ struct drm_file *file_priv)
{
struct drm_device_dma *dma = dev->dma;
int i;
@@ -986,7 +916,7 @@ static void i810_reclaim_buffers(struct drm_device * dev, struct file *filp)
struct drm_buf *buf = dma->buflist[i];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
- if (buf->filp == filp && buf_priv) {
+ if (buf->file_priv == file_priv && buf_priv) {
int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
I810_BUF_FREE);
@@ -998,47 +928,38 @@ static void i810_reclaim_buffers(struct drm_device * dev, struct file *filp)
}
}
-static int i810_flush_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_flush_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
i810_flush_queue(dev);
return 0;
}
-static int i810_dma_vertex(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_dma_vertex(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
dev_priv->sarea_priv;
- drm_i810_vertex_t vertex;
-
- if (copy_from_user
- (&vertex, (drm_i810_vertex_t __user *) arg, sizeof(vertex)))
- return -EFAULT;
+ drm_i810_vertex_t *vertex = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
- vertex.idx, vertex.used, vertex.discard);
+ vertex->idx, vertex->used, vertex->discard);
- if (vertex.idx < 0 || vertex.idx > dma->buf_count)
+ if (vertex->idx < 0 || vertex->idx > dma->buf_count)
return -EINVAL;
i810_dma_dispatch_vertex(dev,
- dma->buflist[vertex.idx],
- vertex.discard, vertex.used);
+ dma->buflist[vertex->idx],
+ vertex->discard, vertex->used);
- atomic_add(vertex.used, &dev->counts[_DRM_STAT_SECONDARY]);
+ atomic_add(vertex->used, &dev->counts[_DRM_STAT_SECONDARY]);
atomic_inc(&dev->counts[_DRM_STAT_DMA]);
sarea_priv->last_enqueue = dev_priv->counter - 1;
sarea_priv->last_dispatch = (int)hw_status[5];
@@ -1046,48 +967,37 @@ static int i810_dma_vertex(struct inode *inode, struct file *filp,
return 0;
}
-static int i810_clear_bufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_clear_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- drm_i810_clear_t clear;
+ drm_i810_clear_t *clear = data;
- if (copy_from_user
- (&clear, (drm_i810_clear_t __user *) arg, sizeof(clear)))
- return -EFAULT;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* GH: Someone's doing nasty things... */
if (!dev->dev_private) {
return -EINVAL;
}
- i810_dma_dispatch_clear(dev, clear.flags,
- clear.clear_color, clear.clear_depth);
+ i810_dma_dispatch_clear(dev, clear->flags,
+ clear->clear_color, clear->clear_depth);
return 0;
}
-static int i810_swap_bufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_swap_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
-
DRM_DEBUG("i810_swap_bufs\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
i810_dma_dispatch_swap(dev);
return 0;
}
-static int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int i810_getage(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
@@ -1097,46 +1007,39 @@ static int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
return 0;
}
-static int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int i810_getbuf(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
int retcode = 0;
- drm_i810_dma_t d;
+ drm_i810_dma_t *d = data;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
dev_priv->sarea_priv;
- if (copy_from_user(&d, (drm_i810_dma_t __user *) arg, sizeof(d)))
- return -EFAULT;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- d.granted = 0;
+ d->granted = 0;
- retcode = i810_dma_get_buffer(dev, &d, filp);
+ retcode = i810_dma_get_buffer(dev, d, file_priv);
DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n",
- current->pid, retcode, d.granted);
+ task_pid_nr(current), retcode, d->granted);
- if (copy_to_user((void __user *) arg, &d, sizeof(d)))
- return -EFAULT;
sarea_priv->last_dispatch = (int)hw_status[5];
return retcode;
}
-static int i810_copybuf(struct inode *inode,
- struct file *filp, unsigned int cmd, unsigned long arg)
+static int i810_copybuf(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
/* Never copy - 2.4.x doesn't need it */
return 0;
}
-static int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int i810_docopy(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
/* Never copy - 2.4.x doesn't need it */
return 0;
@@ -1202,30 +1105,25 @@ static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * buf,
ADVANCE_LP_RING();
}
-static int i810_dma_mc(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_dma_mc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
dev_priv->sarea_priv;
- drm_i810_mc_t mc;
-
- if (copy_from_user(&mc, (drm_i810_mc_t __user *) arg, sizeof(mc)))
- return -EFAULT;
+ drm_i810_mc_t *mc = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (mc.idx >= dma->buf_count || mc.idx < 0)
+ if (mc->idx >= dma->buf_count || mc->idx < 0)
return -EINVAL;
- i810_dma_dispatch_mc(dev, dma->buflist[mc.idx], mc.used,
- mc.last_render);
+ i810_dma_dispatch_mc(dev, dma->buflist[mc->idx], mc->used,
+ mc->last_render);
- atomic_add(mc.used, &dev->counts[_DRM_STAT_SECONDARY]);
+ atomic_add(mc->used, &dev->counts[_DRM_STAT_SECONDARY]);
atomic_inc(&dev->counts[_DRM_STAT_DMA]);
sarea_priv->last_enqueue = dev_priv->counter - 1;
sarea_priv->last_dispatch = (int)hw_status[5];
@@ -1233,52 +1131,41 @@ static int i810_dma_mc(struct inode *inode, struct file *filp,
return 0;
}
-static int i810_rstatus(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_rstatus(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
return (int)(((u32 *) (dev_priv->hw_status_page))[4]);
}
-static int i810_ov0_info(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_ov0_info(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
- drm_i810_overlay_t data;
+ drm_i810_overlay_t *ov = data;
+
+ ov->offset = dev_priv->overlay_offset;
+ ov->physical = dev_priv->overlay_physical;
- data.offset = dev_priv->overlay_offset;
- data.physical = dev_priv->overlay_physical;
- if (copy_to_user
- ((drm_i810_overlay_t __user *) arg, &data, sizeof(data)))
- return -EFAULT;
return 0;
}
-static int i810_fstatus(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_fstatus(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return I810_READ(0x30008);
}
-static int i810_ov0_flip(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_ov0_flip(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
//Tell the overlay to update
I810_WRITE(0x30000, dev_priv->overlay_physical | 0x80000000);
@@ -1310,16 +1197,14 @@ static int i810_do_cleanup_pageflip(struct drm_device * dev)
return 0;
}
-static int i810_flip_bufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_flip_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("%s\n", __FUNCTION__);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv->page_flipping)
i810_do_init_pageflip(dev);
@@ -1345,7 +1230,7 @@ void i810_driver_lastclose(struct drm_device * dev)
i810_dma_cleanup(dev);
}
-void i810_driver_preclose(struct drm_device * dev, DRMFILE filp)
+void i810_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_i810_private_t *dev_priv = dev->dev_private;
@@ -1355,9 +1240,10 @@ void i810_driver_preclose(struct drm_device * dev, DRMFILE filp)
}
}
-void i810_driver_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
+void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
+ struct drm_file *file_priv)
{
- i810_reclaim_buffers(dev, filp);
+ i810_reclaim_buffers(dev, file_priv);
}
int i810_driver_dma_quiescent(struct drm_device * dev)
@@ -1366,22 +1252,22 @@ int i810_driver_dma_quiescent(struct drm_device * dev)
return 0;
}
-drm_ioctl_desc_t i810_ioctls[] = {
- [DRM_IOCTL_NR(DRM_I810_INIT)] = {i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_I810_VERTEX)] = {i810_dma_vertex, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_CLEAR)] = {i810_clear_bufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_FLUSH)] = {i810_flush_ioctl, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_GETAGE)] = {i810_getage, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_GETBUF)] = {i810_getbuf, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_SWAP)] = {i810_swap_bufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_COPY)] = {i810_copybuf, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_DOCOPY)] = {i810_docopy, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_OV0INFO)] = {i810_ov0_info, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_FSTATUS)] = {i810_fstatus, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_OV0FLIP)] = {i810_ov0_flip, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_MC)] = {i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_I810_RSTATUS)] = {i810_rstatus, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I810_FLIP)] = {i810_flip_bufs, DRM_AUTH}
+struct drm_ioctl_desc i810_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH)
};
int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls);
diff --git a/drivers/char/drm/i810_drm.h b/drivers/char/drm/i810_drm.h
index 614977dbce4..7a10bb6f2c0 100644
--- a/drivers/char/drm/i810_drm.h
+++ b/drivers/char/drm/i810_drm.h
@@ -102,13 +102,8 @@ typedef enum _drm_i810_init_func {
/* This is the init structure after v1.2 */
typedef struct _drm_i810_init {
drm_i810_init_func_t func;
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
- int ring_map_idx;
- int buffer_map_idx;
-#else
unsigned int mmio_offset;
unsigned int buffers_offset;
-#endif
int sarea_priv_offset;
unsigned int ring_start;
unsigned int ring_end;
diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h
index 648833844c7..0af45872f67 100644
--- a/drivers/char/drm/i810_drv.h
+++ b/drivers/char/drm/i810_drv.h
@@ -117,15 +117,16 @@ typedef struct drm_i810_private {
/* i810_dma.c */
extern int i810_driver_dma_quiescent(struct drm_device * dev);
extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
- struct file *filp);
+ struct drm_file *file_priv);
extern int i810_driver_load(struct drm_device *, unsigned long flags);
extern void i810_driver_lastclose(struct drm_device * dev);
-extern void i810_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void i810_driver_preclose(struct drm_device * dev,
+ struct drm_file *file_priv);
extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
- struct file *filp);
+ struct drm_file *file_priv);
extern int i810_driver_device_is_agp(struct drm_device * dev);
-extern drm_ioctl_desc_t i810_ioctls[];
+extern struct drm_ioctl_desc i810_ioctls[];
extern int i810_max_ioctl;
#define I810_BASE(reg) ((unsigned long) \
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index dc20c1a7834..69a363edb0d 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -122,10 +122,9 @@ static const struct file_operations i830_buffer_fops = {
.fasync = drm_fasync,
};
-static int i830_map_buffer(struct drm_buf * buf, struct file *filp)
+static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
+ struct drm_device *dev = file_priv->head->dev;
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
drm_i830_private_t *dev_priv = dev->dev_private;
const struct file_operations *old_fops;
@@ -136,13 +135,13 @@ static int i830_map_buffer(struct drm_buf * buf, struct file *filp)
return -EINVAL;
down_write(&current->mm->mmap_sem);
- old_fops = filp->f_op;
- filp->f_op = &i830_buffer_fops;
+ old_fops = file_priv->filp->f_op;
+ file_priv->filp->f_op = &i830_buffer_fops;
dev_priv->mmap_buffer = buf;
- virtual = do_mmap(filp, 0, buf->total, PROT_READ | PROT_WRITE,
+ virtual = do_mmap(file_priv->filp, 0, buf->total, PROT_READ | PROT_WRITE,
MAP_SHARED, buf->bus_address);
dev_priv->mmap_buffer = NULL;
- filp->f_op = old_fops;
+ file_priv->filp->f_op = old_fops;
if (IS_ERR((void *)virtual)) { /* ugh */
/* Real error */
DRM_ERROR("mmap error\n");
@@ -177,7 +176,7 @@ static int i830_unmap_buffer(struct drm_buf * buf)
}
static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d,
- struct file *filp)
+ struct drm_file *file_priv)
{
struct drm_buf *buf;
drm_i830_buf_priv_t *buf_priv;
@@ -190,13 +189,13 @@ static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d,
return retcode;
}
- retcode = i830_map_buffer(buf, filp);
+ retcode = i830_map_buffer(buf, file_priv);
if (retcode) {
i830_freelist_put(dev, buf);
DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
return retcode;
}
- buf->filp = filp;
+ buf->file_priv = file_priv;
buf_priv = buf->dev_private;
d->granted = 1;
d->request_idx = buf->idx;
@@ -389,7 +388,7 @@ static int i830_dma_initialize(struct drm_device * dev,
i830_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -451,25 +450,20 @@ static int i830_dma_initialize(struct drm_device * dev,
return 0;
}
-static int i830_dma_init(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_dma_init(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv;
- drm_i830_init_t init;
+ drm_i830_init_t *init = data;
int retcode = 0;
- if (copy_from_user(&init, (void *__user)arg, sizeof(init)))
- return -EFAULT;
-
- switch (init.func) {
+ switch (init->func) {
case I830_INIT_DMA:
dev_priv = drm_alloc(sizeof(drm_i830_private_t),
DRM_MEM_DRIVER);
if (dev_priv == NULL)
return -ENOMEM;
- retcode = i830_dma_initialize(dev, dev_priv, &init);
+ retcode = i830_dma_initialize(dev, dev_priv, init);
break;
case I830_CLEANUP_DMA:
retcode = i830_dma_cleanup(dev);
@@ -1248,7 +1242,7 @@ static int i830_flush_queue(struct drm_device * dev)
}
/* Must be called with the lock held */
-static void i830_reclaim_buffers(struct drm_device * dev, struct file *filp)
+static void i830_reclaim_buffers(struct drm_device * dev, struct drm_file *file_priv)
{
struct drm_device_dma *dma = dev->dma;
int i;
@@ -1266,7 +1260,7 @@ static void i830_reclaim_buffers(struct drm_device * dev, struct file *filp)
struct drm_buf *buf = dma->buflist[i];
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
- if (buf->filp == filp && buf_priv) {
+ if (buf->file_priv == file_priv && buf_priv) {
int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
I830_BUF_FREE);
@@ -1278,45 +1272,36 @@ static void i830_reclaim_buffers(struct drm_device * dev, struct file *filp)
}
}
-static int i830_flush_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_flush_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
i830_flush_queue(dev);
return 0;
}
-static int i830_dma_vertex(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_dma_vertex(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
struct drm_device_dma *dma = dev->dma;
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
dev_priv->sarea_priv;
- drm_i830_vertex_t vertex;
-
- if (copy_from_user
- (&vertex, (drm_i830_vertex_t __user *) arg, sizeof(vertex)))
- return -EFAULT;
+ drm_i830_vertex_t *vertex = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("i830 dma vertex, idx %d used %d discard %d\n",
- vertex.idx, vertex.used, vertex.discard);
+ vertex->idx, vertex->used, vertex->discard);
- if (vertex.idx < 0 || vertex.idx > dma->buf_count)
+ if (vertex->idx < 0 || vertex->idx > dma->buf_count)
return -EINVAL;
i830_dma_dispatch_vertex(dev,
- dma->buflist[vertex.idx],
- vertex.discard, vertex.used);
+ dma->buflist[vertex->idx],
+ vertex->discard, vertex->used);
sarea_priv->last_enqueue = dev_priv->counter - 1;
sarea_priv->last_dispatch = (int)hw_status[5];
@@ -1324,39 +1309,30 @@ static int i830_dma_vertex(struct inode *inode, struct file *filp,
return 0;
}
-static int i830_clear_bufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_clear_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
- drm_i830_clear_t clear;
-
- if (copy_from_user
- (&clear, (drm_i830_clear_t __user *) arg, sizeof(clear)))
- return -EFAULT;
+ drm_i830_clear_t *clear = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* GH: Someone's doing nasty things... */
if (!dev->dev_private) {
return -EINVAL;
}
- i830_dma_dispatch_clear(dev, clear.flags,
- clear.clear_color,
- clear.clear_depth, clear.clear_depthmask);
+ i830_dma_dispatch_clear(dev, clear->flags,
+ clear->clear_color,
+ clear->clear_depth, clear->clear_depthmask);
return 0;
}
-static int i830_swap_bufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_swap_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
-
DRM_DEBUG("i830_swap_bufs\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
i830_dma_dispatch_swap(dev);
return 0;
@@ -1386,16 +1362,14 @@ static int i830_do_cleanup_pageflip(struct drm_device * dev)
return 0;
}
-static int i830_flip_bufs(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_flip_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("%s\n", __FUNCTION__);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv->page_flipping)
i830_do_init_pageflip(dev);
@@ -1404,11 +1378,9 @@ static int i830_flip_bufs(struct inode *inode, struct file *filp,
return 0;
}
-static int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int i830_getage(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
@@ -1418,58 +1390,50 @@ static int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
return 0;
}
-static int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int i830_getbuf(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
int retcode = 0;
- drm_i830_dma_t d;
+ drm_i830_dma_t *d = data;
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
dev_priv->sarea_priv;
DRM_DEBUG("getbuf\n");
- if (copy_from_user(&d, (drm_i830_dma_t __user *) arg, sizeof(d)))
- return -EFAULT;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- d.granted = 0;
+ d->granted = 0;
- retcode = i830_dma_get_buffer(dev, &d, filp);
+ retcode = i830_dma_get_buffer(dev, d, file_priv);
DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n",
- current->pid, retcode, d.granted);
+ task_pid_nr(current), retcode, d->granted);
- if (copy_to_user((void __user *) arg, &d, sizeof(d)))
- return -EFAULT;
sarea_priv->last_dispatch = (int)hw_status[5];
return retcode;
}
-static int i830_copybuf(struct inode *inode,
- struct file *filp, unsigned int cmd, unsigned long arg)
+static int i830_copybuf(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
/* Never copy - 2.4.x doesn't need it */
return 0;
}
-static int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int i830_docopy(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
return 0;
}
-static int i830_getparam(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_getparam(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
- drm_i830_getparam_t param;
+ drm_i830_getparam_t *param = data;
int value;
if (!dev_priv) {
@@ -1477,11 +1441,7 @@ static int i830_getparam(struct inode *inode, struct file *filp,
return -EINVAL;
}
- if (copy_from_user
- (&param, (drm_i830_getparam_t __user *) arg, sizeof(param)))
- return -EFAULT;
-
- switch (param.param) {
+ switch (param->param) {
case I830_PARAM_IRQ_ACTIVE:
value = dev->irq_enabled;
break;
@@ -1489,7 +1449,7 @@ static int i830_getparam(struct inode *inode, struct file *filp,
return -EINVAL;
}
- if (copy_to_user(param.value, &value, sizeof(int))) {
+ if (copy_to_user(param->value, &value, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
return -EFAULT;
}
@@ -1497,26 +1457,20 @@ static int i830_getparam(struct inode *inode, struct file *filp,
return 0;
}
-static int i830_setparam(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i830_setparam(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
- drm_i830_setparam_t param;
+ drm_i830_setparam_t *param = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return -EINVAL;
}
- if (copy_from_user
- (&param, (drm_i830_setparam_t __user *) arg, sizeof(param)))
- return -EFAULT;
-
- switch (param.param) {
+ switch (param->param) {
case I830_SETPARAM_USE_MI_BATCHBUFFER_START:
- dev_priv->use_mi_batchbuffer_start = param.value;
+ dev_priv->use_mi_batchbuffer_start = param->value;
break;
default:
return -EINVAL;
@@ -1542,7 +1496,7 @@ void i830_driver_lastclose(struct drm_device * dev)
i830_dma_cleanup(dev);
}
-void i830_driver_preclose(struct drm_device * dev, DRMFILE filp)
+void i830_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_i830_private_t *dev_priv = dev->dev_private;
@@ -1552,9 +1506,9 @@ void i830_driver_preclose(struct drm_device * dev, DRMFILE filp)
}
}
-void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
+void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct drm_file *file_priv)
{
- i830_reclaim_buffers(dev, filp);
+ i830_reclaim_buffers(dev, file_priv);
}
int i830_driver_dma_quiescent(struct drm_device * dev)
@@ -1563,21 +1517,21 @@ int i830_driver_dma_quiescent(struct drm_device * dev)
return 0;
}
-drm_ioctl_desc_t i830_ioctls[] = {
- [DRM_IOCTL_NR(DRM_I830_INIT)] = {i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_I830_VERTEX)] = {i830_dma_vertex, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_CLEAR)] = {i830_clear_bufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_FLUSH)] = {i830_flush_ioctl, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_GETAGE)] = {i830_getage, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_GETBUF)] = {i830_getbuf, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_SWAP)] = {i830_swap_bufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_COPY)] = {i830_copybuf, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_DOCOPY)] = {i830_docopy, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_FLIP)] = {i830_flip_bufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_IRQ_EMIT)] = {i830_irq_emit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_IRQ_WAIT)] = {i830_irq_wait, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_GETPARAM)] = {i830_getparam, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I830_SETPARAM)] = {i830_setparam, DRM_AUTH}
+struct drm_ioctl_desc i830_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH)
};
int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index ddda67956de..db3a9fa8396 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -122,24 +122,25 @@ typedef struct drm_i830_private {
} drm_i830_private_t;
-extern drm_ioctl_desc_t i830_ioctls[];
+extern struct drm_ioctl_desc i830_ioctls[];
extern int i830_max_ioctl;
/* i830_irq.c */
-extern int i830_irq_emit(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
-extern int i830_irq_wait(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
+extern int i830_irq_emit(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i830_irq_wait(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS);
extern void i830_driver_irq_preinstall(struct drm_device * dev);
extern void i830_driver_irq_postinstall(struct drm_device * dev);
extern void i830_driver_irq_uninstall(struct drm_device * dev);
extern int i830_driver_load(struct drm_device *, unsigned long flags);
-extern void i830_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void i830_driver_preclose(struct drm_device * dev,
+ struct drm_file *file_priv);
extern void i830_driver_lastclose(struct drm_device * dev);
extern void i830_driver_reclaim_buffers_locked(struct drm_device * dev,
- struct file *filp);
+ struct drm_file *file_priv);
extern int i830_driver_dma_quiescent(struct drm_device * dev);
extern int i830_driver_device_is_agp(struct drm_device * dev);
diff --git a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c
index a1b5c63c3c3..76403f4b620 100644
--- a/drivers/char/drm/i830_irq.c
+++ b/drivers/char/drm/i830_irq.c
@@ -114,29 +114,23 @@ static int i830_wait_irq(struct drm_device * dev, int irq_nr)
/* Needs the lock as it touches the ring.
*/
-int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+int i830_irq_emit(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
- drm_i830_irq_emit_t emit;
+ drm_i830_irq_emit_t *emit = data;
int result;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return -EINVAL;
}
- if (copy_from_user
- (&emit, (drm_i830_irq_emit_t __user *) arg, sizeof(emit)))
- return -EFAULT;
-
result = i830_emit_irq(dev);
- if (copy_to_user(emit.irq_seq, &result, sizeof(int))) {
+ if (copy_to_user(emit->irq_seq, &result, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
return -EFAULT;
}
@@ -146,24 +140,18 @@ int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd,
/* Doesn't need the hardware lock.
*/
-int i830_irq_wait(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+int i830_irq_wait(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- struct drm_file *priv = filp->private_data;
- struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
- drm_i830_irq_wait_t irqwait;
+ drm_i830_irq_wait_t *irqwait = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return -EINVAL;
}
- if (copy_from_user(&irqwait, (drm_i830_irq_wait_t __user *) arg,
- sizeof(irqwait)))
- return -EFAULT;
-
- return i830_wait_irq(dev, irqwait.irq_seq);
+ return i830_wait_irq(dev, irqwait->irq_seq);
}
/* drm_dma.h hooks
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index 8e7d713a5a1..e61a43e5b3a 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -70,7 +70,7 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
last_head = ring->head;
}
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
void i915_kernel_lost_context(struct drm_device * dev)
@@ -137,7 +137,7 @@ static int i915_initialize(struct drm_device * dev,
DRM_ERROR("can not find sarea!\n");
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
@@ -145,7 +145,7 @@ static int i915_initialize(struct drm_device * dev,
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
DRM_ERROR("can not find mmio map!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->sarea_priv = (drm_i915_sarea_t *)
@@ -169,7 +169,7 @@ static int i915_initialize(struct drm_device * dev,
i915_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -200,7 +200,7 @@ static int i915_initialize(struct drm_device * dev,
dev->dev_private = (void *)dev_priv;
i915_dma_cleanup(dev);
DRM_ERROR("Can not allocate hardware status page\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
@@ -221,24 +221,24 @@ static int i915_dma_resume(struct drm_device * dev)
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (!dev_priv->mmio_map) {
DRM_ERROR("can not find mmio map!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (dev_priv->ring.map.handle == NULL) {
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
/* Program Hardware Status Page */
if (!dev_priv->hw_status_page) {
DRM_ERROR("Can not find hardware status page\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
@@ -251,23 +251,20 @@ static int i915_dma_resume(struct drm_device * dev)
return 0;
}
-static int i915_dma_init(DRM_IOCTL_ARGS)
+static int i915_dma_init(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv;
- drm_i915_init_t init;
+ drm_i915_init_t *init = data;
int retcode = 0;
- DRM_COPY_FROM_USER_IOCTL(init, (drm_i915_init_t __user *) data,
- sizeof(init));
-
- switch (init.func) {
+ switch (init->func) {
case I915_INIT_DMA:
dev_priv = drm_alloc(sizeof(drm_i915_private_t),
DRM_MEM_DRIVER);
if (dev_priv == NULL)
- return DRM_ERR(ENOMEM);
- retcode = i915_initialize(dev, dev_priv, &init);
+ return -ENOMEM;
+ retcode = i915_initialize(dev, dev_priv, init);
break;
case I915_CLEANUP_DMA:
retcode = i915_dma_cleanup(dev);
@@ -276,7 +273,7 @@ static int i915_dma_init(DRM_IOCTL_ARGS)
retcode = i915_dma_resume(dev);
break;
default:
- retcode = DRM_ERR(EINVAL);
+ retcode = -EINVAL;
break;
}
@@ -366,7 +363,7 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
RING_LOCALS;
if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
BEGIN_LP_RING((dwords+1)&~1);
@@ -374,17 +371,17 @@ static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwor
int cmd, sz;
if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd)))
- return DRM_ERR(EINVAL);
+ return -EINVAL;
if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
OUT_RING(cmd);
while (++i, --sz) {
if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i],
sizeof(cmd))) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
OUT_RING(cmd);
}
@@ -407,13 +404,13 @@ static int i915_emit_box(struct drm_device * dev,
RING_LOCALS;
if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
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);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (IS_I965G(dev)) {
@@ -467,7 +464,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
if (cmd->sz & 0x3) {
DRM_ERROR("alignment");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
i915_kernel_lost_context(dev);
@@ -502,7 +499,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
if ((batch->start | batch->used) & 0x7) {
DRM_ERROR("alignment");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
i915_kernel_lost_context(dev);
@@ -598,76 +595,69 @@ static int i915_quiescent(struct drm_device * dev)
return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
}
-static int i915_flush_ioctl(DRM_IOCTL_ARGS)
+static int i915_flush_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return i915_quiescent(dev);
}
-static int i915_batchbuffer(DRM_IOCTL_ARGS)
+static int i915_batchbuffer(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
- drm_i915_batchbuffer_t batch;
+ drm_i915_batchbuffer_t *batch = data;
int ret;
if (!dev_priv->allow_batchbuffer) {
DRM_ERROR("Batchbuffer ioctl disabled\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(batch, (drm_i915_batchbuffer_t __user *) data,
- sizeof(batch));
-
DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
- batch.start, batch.used, batch.num_cliprects);
+ batch->start, batch->used, batch->num_cliprects);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects,
- batch.num_cliprects *
+ if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
+ batch->num_cliprects *
sizeof(struct drm_clip_rect)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- ret = i915_dispatch_batchbuffer(dev, &batch);
+ ret = i915_dispatch_batchbuffer(dev, batch);
sarea_priv->last_dispatch = (int)hw_status[5];
return ret;
}
-static int i915_cmdbuffer(DRM_IOCTL_ARGS)
+static int i915_cmdbuffer(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
- drm_i915_cmdbuffer_t cmdbuf;
+ drm_i915_cmdbuffer_t *cmdbuf = data;
int ret;
- DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_i915_cmdbuffer_t __user *) data,
- sizeof(cmdbuf));
-
DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
- cmdbuf.buf, cmdbuf.sz, cmdbuf.num_cliprects);
+ cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (cmdbuf.num_cliprects &&
- DRM_VERIFYAREA_READ(cmdbuf.cliprects,
- cmdbuf.num_cliprects *
+ if (cmdbuf->num_cliprects &&
+ DRM_VERIFYAREA_READ(cmdbuf->cliprects,
+ cmdbuf->num_cliprects *
sizeof(struct drm_clip_rect))) {
DRM_ERROR("Fault accessing cliprects\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
- ret = i915_dispatch_cmdbuffer(dev, &cmdbuf);
+ ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
if (ret) {
DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
return ret;
@@ -677,33 +667,29 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS)
return 0;
}
-static int i915_flip_bufs(DRM_IOCTL_ARGS)
+static int i915_flip_bufs(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
-
DRM_DEBUG("%s\n", __FUNCTION__);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return i915_dispatch_flip(dev);
}
-static int i915_getparam(DRM_IOCTL_ARGS)
+static int i915_getparam(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_getparam_t param;
+ drm_i915_getparam_t *param = data;
int value;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_getparam_t __user *) data,
- sizeof(param));
-
- switch (param.param) {
+ switch (param->param) {
case I915_PARAM_IRQ_ACTIVE:
value = dev->irq ? 1 : 0;
break;
@@ -714,68 +700,64 @@ static int i915_getparam(DRM_IOCTL_ARGS)
value = READ_BREADCRUMB(dev_priv);
break;
default:
- DRM_ERROR("Unknown parameter %d\n", param.param);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("Unknown parameter %d\n", param->param);
+ return -EINVAL;
}
- if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
+ if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
DRM_ERROR("DRM_COPY_TO_USER failed\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
}
-static int i915_setparam(DRM_IOCTL_ARGS)
+static int i915_setparam(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_setparam_t param;
+ drm_i915_setparam_t *param = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(param, (drm_i915_setparam_t __user *) data,
- sizeof(param));
-
- switch (param.param) {
+ switch (param->param) {
case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
if (!IS_I965G(dev))
- dev_priv->use_mi_batchbuffer_start = param.value;
+ dev_priv->use_mi_batchbuffer_start = param->value;
break;
case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
- dev_priv->tex_lru_log_granularity = param.value;
+ dev_priv->tex_lru_log_granularity = param->value;
break;
case I915_SETPARAM_ALLOW_BATCHBUFFER:
- dev_priv->allow_batchbuffer = param.value;
+ dev_priv->allow_batchbuffer = param->value;
break;
default:
- DRM_ERROR("unknown parameter %d\n", param.param);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("unknown parameter %d\n", param->param);
+ return -EINVAL;
}
return 0;
}
-static int i915_set_status_page(DRM_IOCTL_ARGS)
+static int i915_set_status_page(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_hws_addr_t hws;
+ drm_i915_hws_addr_t *hws = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(hws, (drm_i915_hws_addr_t __user *) data,
- sizeof(hws));
- printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws.addr);
- dev_priv->status_gfx_addr = hws.addr & (0x1ffff<<12);
+ printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr);
+
+ dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
- dev_priv->hws_map.offset = dev->agp->agp_info.aper_base + hws.addr;
+ dev_priv->hws_map.offset = dev->agp->agp_info.aper_base + hws->addr;
dev_priv->hws_map.size = 4*1024;
dev_priv->hws_map.type = 0;
dev_priv->hws_map.flags = 0;
@@ -788,7 +770,7 @@ static int i915_set_status_page(DRM_IOCTL_ARGS)
dev_priv->status_gfx_addr = 0;
DRM_ERROR("can not ioremap virtual address for"
" G33 hw status page\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->hw_status_page = dev_priv->hws_map.handle;
@@ -821,32 +803,32 @@ void i915_driver_lastclose(struct drm_device * dev)
i915_dma_cleanup(dev);
}
-void i915_driver_preclose(struct drm_device * dev, DRMFILE filp)
+void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
- i915_mem_release(dev, filp, dev_priv->agp_heap);
+ i915_mem_release(dev, file_priv, dev_priv->agp_heap);
}
}
-drm_ioctl_desc_t i915_ioctls[] = {
- [DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_FLIP)] = {i915_flip_bufs, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_BATCHBUFFER)] = {i915_batchbuffer, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_IRQ_EMIT)] = {i915_irq_emit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_IRQ_WAIT)] = {i915_irq_wait, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_GETPARAM)] = {i915_getparam, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_SETPARAM)] = {i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
- [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
- [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH },
- [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_HWS_ADDR)] = {i915_set_status_page, DRM_AUTH},
+struct drm_ioctl_desc i915_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_FLIP, i915_flip_bufs, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_GETPARAM, i915_getparam, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I915_ALLOC, i915_mem_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_FREE, i915_mem_free, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_DESTROY_HEAP, i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
+ DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
+ DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH ),
+ DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH),
};
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index 28b98733beb..e064292e703 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -70,7 +70,7 @@ struct mem_block {
struct mem_block *prev;
int start;
int size;
- DRMFILE filp; /* 0: free, -1: heap, other: real files */
+ struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
};
typedef struct _drm_i915_vbl_swap {
@@ -116,21 +116,24 @@ typedef struct drm_i915_private {
unsigned int swaps_pending;
} drm_i915_private_t;
-extern drm_ioctl_desc_t i915_ioctls[];
+extern struct drm_ioctl_desc i915_ioctls[];
extern int i915_max_ioctl;
/* i915_dma.c */
extern void i915_kernel_lost_context(struct drm_device * dev);
extern int i915_driver_load(struct drm_device *, unsigned long flags);
extern void i915_driver_lastclose(struct drm_device * dev);
-extern void i915_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void i915_driver_preclose(struct drm_device *dev,
+ struct drm_file *file_priv);
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);
/* i915_irq.c */
-extern int i915_irq_emit(DRM_IOCTL_ARGS);
-extern int i915_irq_wait(DRM_IOCTL_ARGS);
+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,
+ struct drm_file *file_priv);
extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence);
extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence);
@@ -138,18 +141,25 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(struct drm_device * dev);
extern void i915_driver_irq_postinstall(struct drm_device * dev);
extern void i915_driver_irq_uninstall(struct drm_device * dev);
-extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS);
-extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS);
-extern int i915_vblank_swap(DRM_IOCTL_ARGS);
+extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i915_vblank_swap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/* i915_mem.c */
-extern int i915_mem_alloc(DRM_IOCTL_ARGS);
-extern int i915_mem_free(DRM_IOCTL_ARGS);
-extern int i915_mem_init_heap(DRM_IOCTL_ARGS);
-extern int i915_mem_destroy_heap(DRM_IOCTL_ARGS);
+extern int i915_mem_alloc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i915_mem_free(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i915_mem_init_heap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int i915_mem_destroy_heap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern void i915_mem_takedown(struct mem_block **heap);
extern void i915_mem_release(struct drm_device * dev,
- DRMFILE filp, struct mem_block *heap);
+ struct drm_file *file_priv, struct mem_block *heap);
#define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg))
#define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val))
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index bb8e9e9c820..a443f4a202e 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -311,7 +311,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
READ_BREADCRUMB(dev_priv) >= irq_nr);
- if (ret == DRM_ERR(EBUSY)) {
+ if (ret == -EBUSY) {
DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n",
__FUNCTION__,
READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
@@ -330,7 +330,7 @@ static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequ
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
@@ -355,28 +355,25 @@ int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
/* Needs the lock as it touches the ring.
*/
-int i915_irq_emit(DRM_IOCTL_ARGS)
+int i915_irq_emit(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_irq_emit_t emit;
+ drm_i915_irq_emit_t *emit = data;
int result;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(emit, (drm_i915_irq_emit_t __user *) data,
- sizeof(emit));
-
result = i915_emit_irq(dev);
- if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) {
+ if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
@@ -384,21 +381,18 @@ int i915_irq_emit(DRM_IOCTL_ARGS)
/* Doesn't need the hardware lock.
*/
-int i915_irq_wait(DRM_IOCTL_ARGS)
+int i915_irq_wait(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_irq_wait_t irqwait;
+ drm_i915_irq_wait_t *irqwait = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_i915_irq_wait_t __user *) data,
- sizeof(irqwait));
-
- return i915_wait_irq(dev, irqwait.irq_seq);
+ return i915_wait_irq(dev, irqwait->irq_seq);
}
static void i915_enable_interrupt (struct drm_device *dev)
@@ -417,64 +411,60 @@ static void i915_enable_interrupt (struct drm_device *dev)
/* Set the vblank monitor pipe
*/
-int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
+int i915_vblank_pipe_set(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_vblank_pipe_t pipe;
+ drm_i915_vblank_pipe_t *pipe = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data,
- sizeof(pipe));
-
- if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
+ if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
DRM_ERROR("%s called with invalid pipe 0x%x\n",
- __FUNCTION__, pipe.pipe);
- return DRM_ERR(EINVAL);
+ __FUNCTION__, pipe->pipe);
+ return -EINVAL;
}
- dev_priv->vblank_pipe = pipe.pipe;
+ dev_priv->vblank_pipe = pipe->pipe;
i915_enable_interrupt (dev);
return 0;
}
-int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
+int i915_vblank_pipe_get(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_vblank_pipe_t pipe;
+ drm_i915_vblank_pipe_t *pipe = data;
u16 flag;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
flag = I915_READ(I915REG_INT_ENABLE_R);
- pipe.pipe = 0;
+ pipe->pipe = 0;
if (flag & VSYNC_PIPEA_FLAG)
- pipe.pipe |= DRM_I915_VBLANK_PIPE_A;
+ pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
if (flag & VSYNC_PIPEB_FLAG)
- pipe.pipe |= DRM_I915_VBLANK_PIPE_B;
- DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_pipe_t __user *) data, pipe,
- sizeof(pipe));
+ pipe->pipe |= DRM_I915_VBLANK_PIPE_B;
+
return 0;
}
/**
* Schedule buffer swap at given vertical blank.
*/
-int i915_vblank_swap(DRM_IOCTL_ARGS)
+int i915_vblank_swap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_vblank_swap_t swap;
+ drm_i915_vblank_swap_t *swap = data;
drm_i915_vbl_swap_t *vbl_swap;
unsigned int pipe, seqtype, curseq;
unsigned long irqflags;
@@ -482,38 +472,35 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __func__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (dev_priv->sarea_priv->rotation) {
DRM_DEBUG("Rotation not supported\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data,
- sizeof(swap));
-
- if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
+ if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
_DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
- DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype);
+ return -EINVAL;
}
- pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
+ pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
- seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
+ seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
if (!(dev_priv->vblank_pipe & (1 << pipe))) {
DRM_ERROR("Invalid pipe %d\n", pipe);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
spin_lock_irqsave(&dev->drw_lock, irqflags);
- if (!drm_get_drawable_info(dev, swap.drawable)) {
+ if (!drm_get_drawable_info(dev, swap->drawable)) {
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- DRM_DEBUG("Invalid drawable ID %d\n", swap.drawable);
- return DRM_ERR(EINVAL);
+ DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable);
+ return -EINVAL;
}
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
@@ -521,14 +508,14 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
if (seqtype == _DRM_VBLANK_RELATIVE)
- swap.sequence += curseq;
+ swap->sequence += curseq;
- if ((curseq - swap.sequence) <= (1<<23)) {
- if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) {
- swap.sequence = curseq + 1;
+ if ((curseq - swap->sequence) <= (1<<23)) {
+ if (swap->seqtype & _DRM_VBLANK_NEXTONMISS) {
+ swap->sequence = curseq + 1;
} else {
DRM_DEBUG("Missed target sequence\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -537,9 +524,9 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
list_for_each(list, &dev_priv->vbl_swaps.head) {
vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
- if (vbl_swap->drw_id == swap.drawable &&
+ if (vbl_swap->drw_id == swap->drawable &&
vbl_swap->pipe == pipe &&
- vbl_swap->sequence == swap.sequence) {
+ vbl_swap->sequence == swap->sequence) {
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
DRM_DEBUG("Already scheduled\n");
return 0;
@@ -550,21 +537,21 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
if (dev_priv->swaps_pending >= 100) {
DRM_DEBUG("Too many swaps queued\n");
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
- vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER);
+ vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER);
if (!vbl_swap) {
DRM_ERROR("Failed to allocate memory to queue swap\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
DRM_DEBUG("\n");
- vbl_swap->drw_id = swap.drawable;
+ vbl_swap->drw_id = swap->drawable;
vbl_swap->pipe = pipe;
- vbl_swap->sequence = swap.sequence;
+ vbl_swap->sequence = swap->sequence;
spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
@@ -573,9 +560,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
- DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap,
- sizeof(swap));
-
return 0;
}
diff --git a/drivers/char/drm/i915_mem.c b/drivers/char/drm/i915_mem.c
index 50b4bacef0e..56fb9b30a5d 100644
--- a/drivers/char/drm/i915_mem.c
+++ b/drivers/char/drm/i915_mem.c
@@ -89,7 +89,7 @@ static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use)
*/
static struct mem_block *split_block(struct mem_block *p, int start, int size,
- DRMFILE filp)
+ struct drm_file *file_priv)
{
/* Maybe cut off the start of an existing block */
if (start > p->start) {
@@ -99,7 +99,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
goto out;
newblock->start = start;
newblock->size = p->size - (start - p->start);
- newblock->filp = NULL;
+ newblock->file_priv = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
@@ -116,7 +116,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
goto out;
newblock->start = start + size;
newblock->size = p->size - size;
- newblock->filp = NULL;
+ newblock->file_priv = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
@@ -126,20 +126,20 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
out:
/* Our block is in the middle */
- p->filp = filp;
+ p->file_priv = file_priv;
return p;
}
static struct mem_block *alloc_block(struct mem_block *heap, int size,
- int align2, DRMFILE filp)
+ int align2, struct drm_file *file_priv)
{
struct mem_block *p;
int mask = (1 << align2) - 1;
for (p = heap->next; p != heap; p = p->next) {
int start = (p->start + mask) & ~mask;
- if (p->filp == NULL && start + size <= p->start + p->size)
- return split_block(p, start, size, filp);
+ if (p->file_priv == NULL && start + size <= p->start + p->size)
+ return split_block(p, start, size, file_priv);
}
return NULL;
@@ -158,12 +158,12 @@ static struct mem_block *find_block(struct mem_block *heap, int start)
static void free_block(struct mem_block *p)
{
- p->filp = NULL;
+ p->file_priv = NULL;
- /* Assumes a single contiguous range. Needs a special filp in
+ /* Assumes a single contiguous range. Needs a special file_priv in
* 'heap' to stop it being subsumed.
*/
- if (p->next->filp == NULL) {
+ if (p->next->file_priv == NULL) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
@@ -171,7 +171,7 @@ static void free_block(struct mem_block *p)
drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS);
}
- if (p->prev->filp == NULL) {
+ if (p->prev->file_priv == NULL) {
struct mem_block *q = p->prev;
q->size += p->size;
q->next = p->next;
@@ -197,18 +197,19 @@ static int init_heap(struct mem_block **heap, int start, int size)
blocks->start = start;
blocks->size = size;
- blocks->filp = NULL;
+ blocks->file_priv = NULL;
blocks->next = blocks->prev = *heap;
memset(*heap, 0, sizeof(**heap));
- (*heap)->filp = (DRMFILE) - 1;
+ (*heap)->file_priv = (struct drm_file *) - 1;
(*heap)->next = (*heap)->prev = blocks;
return 0;
}
/* Free all blocks associated with the releasing file.
*/
-void i915_mem_release(struct drm_device * dev, DRMFILE filp, struct mem_block *heap)
+void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv,
+ struct mem_block *heap)
{
struct mem_block *p;
@@ -216,17 +217,17 @@ void i915_mem_release(struct drm_device * dev, DRMFILE filp, struct mem_block *h
return;
for (p = heap->next; p != heap; p = p->next) {
- if (p->filp == filp) {
- p->filp = NULL;
+ if (p->file_priv == file_priv) {
+ p->file_priv = NULL;
mark_block(dev, p, 0);
}
}
- /* Assumes a single contiguous range. Needs a special filp in
+ /* Assumes a single contiguous range. Needs a special file_priv in
* 'heap' to stop it being subsumed.
*/
for (p = heap->next; p != heap; p = p->next) {
- while (p->filp == NULL && p->next->filp == NULL) {
+ while (p->file_priv == NULL && p->next->file_priv == NULL) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
@@ -267,129 +268,117 @@ static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region)
/* IOCTL HANDLERS */
-int i915_mem_alloc(DRM_IOCTL_ARGS)
+int i915_mem_alloc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_mem_alloc_t alloc;
+ drm_i915_mem_alloc_t *alloc = data;
struct mem_block *block, **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(alloc, (drm_i915_mem_alloc_t __user *) data,
- sizeof(alloc));
-
- heap = get_heap(dev_priv, alloc.region);
+ heap = get_heap(dev_priv, alloc->region);
if (!heap || !*heap)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
/* Make things easier on ourselves: all allocations at least
* 4k aligned.
*/
- if (alloc.alignment < 12)
- alloc.alignment = 12;
+ if (alloc->alignment < 12)
+ alloc->alignment = 12;
- block = alloc_block(*heap, alloc.size, alloc.alignment, filp);
+ block = alloc_block(*heap, alloc->size, alloc->alignment, file_priv);
if (!block)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
mark_block(dev, block, 1);
- if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) {
+ if (DRM_COPY_TO_USER(alloc->region_offset, &block->start,
+ sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
}
-int i915_mem_free(DRM_IOCTL_ARGS)
+int i915_mem_free(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_mem_free_t memfree;
+ drm_i915_mem_free_t *memfree = data;
struct mem_block *block, **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(memfree, (drm_i915_mem_free_t __user *) data,
- sizeof(memfree));
-
- heap = get_heap(dev_priv, memfree.region);
+ heap = get_heap(dev_priv, memfree->region);
if (!heap || !*heap)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- block = find_block(*heap, memfree.region_offset);
+ block = find_block(*heap, memfree->region_offset);
if (!block)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- if (block->filp != filp)
- return DRM_ERR(EPERM);
+ if (block->file_priv != file_priv)
+ return -EPERM;
mark_block(dev, block, 0);
free_block(block);
return 0;
}
-int i915_mem_init_heap(DRM_IOCTL_ARGS)
+int i915_mem_init_heap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_mem_init_heap_t initheap;
+ drm_i915_mem_init_heap_t *initheap = data;
struct mem_block **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(initheap,
- (drm_i915_mem_init_heap_t __user *) data,
- sizeof(initheap));
-
- heap = get_heap(dev_priv, initheap.region);
+ heap = get_heap(dev_priv, initheap->region);
if (!heap)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if (*heap) {
DRM_ERROR("heap already initialized?");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
- return init_heap(heap, initheap.start, initheap.size);
+ return init_heap(heap, initheap->start, initheap->size);
}
-int i915_mem_destroy_heap( DRM_IOCTL_ARGS )
+int i915_mem_destroy_heap( struct drm_device *dev, void *data,
+ struct drm_file *file_priv )
{
- DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_mem_destroy_heap_t destroyheap;
+ drm_i915_mem_destroy_heap_t *destroyheap = data;
struct mem_block **heap;
if ( !dev_priv ) {
DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL( destroyheap, (drm_i915_mem_destroy_heap_t *)data,
- sizeof(destroyheap) );
-
- heap = get_heap( dev_priv, destroyheap.region );
+ heap = get_heap( dev_priv, destroyheap->region );
if (!heap) {
DRM_ERROR("get_heap failed");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (!*heap) {
DRM_ERROR("heap not initialized?");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
i915_mem_takedown( heap );
diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c
index 9c73a6e3861..c567c34cda7 100644
--- a/drivers/char/drm/mga_dma.c
+++ b/drivers/char/drm/mga_dma.c
@@ -71,7 +71,7 @@ int mga_do_wait_for_idle(drm_mga_private_t * dev_priv)
DRM_ERROR("failed!\n");
DRM_INFO(" status=0x%08x\n", status);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int mga_do_dma_reset(drm_mga_private_t * dev_priv)
@@ -256,7 +256,7 @@ static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_pr
dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
if (dev_priv->head == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t));
SET_AGE(&dev_priv->head->age, MGA_BUFFER_USED, 0);
@@ -267,7 +267,7 @@ static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_pr
entry = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
if (entry == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
memset(entry, 0, sizeof(drm_mga_freelist_t));
@@ -399,7 +399,7 @@ int mga_driver_load(struct drm_device * dev, unsigned long flags)
dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER);
if (!dev_priv)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
dev->dev_private = (void *)dev_priv;
memset(dev_priv, 0, sizeof(drm_mga_private_t));
@@ -578,7 +578,7 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev,
DRM_ERROR("failed to ioremap agp regions! (%p, %p, %p)\n",
dev_priv->warp->handle, dev_priv->primary->handle,
dev->agp_buffer_map->handle);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->dma_access = MGA_PAGPXFER;
@@ -622,7 +622,7 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev,
if (dev->dma == NULL) {
DRM_ERROR("dev->dma is NULL\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
/* Make drm_addbufs happy by not trying to create a mapping for less
@@ -656,7 +656,7 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev,
if (err != 0) {
DRM_ERROR("Unable to allocate primary DMA region: %d\n", err);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (dev_priv->primary->size != dma_bs->primary_size) {
@@ -759,36 +759,30 @@ static int mga_do_dma_bootstrap(struct drm_device * dev,
return err;
}
-int mga_dma_bootstrap(DRM_IOCTL_ARGS)
+int mga_dma_bootstrap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_mga_dma_bootstrap_t bootstrap;
+ drm_mga_dma_bootstrap_t *bootstrap = data;
int err;
static const int modes[] = { 0, 1, 2, 2, 4, 4, 4, 4 };
const drm_mga_private_t *const dev_priv =
(drm_mga_private_t *) dev->dev_private;
- DRM_COPY_FROM_USER_IOCTL(bootstrap,
- (drm_mga_dma_bootstrap_t __user *) data,
- sizeof(bootstrap));
-
- err = mga_do_dma_bootstrap(dev, &bootstrap);
+ err = mga_do_dma_bootstrap(dev, bootstrap);
if (err) {
mga_do_cleanup_dma(dev, FULL_CLEANUP);
return err;
}
if (dev_priv->agp_textures != NULL) {
- bootstrap.texture_handle = dev_priv->agp_textures->offset;
- bootstrap.texture_size = dev_priv->agp_textures->size;
+ bootstrap->texture_handle = dev_priv->agp_textures->offset;
+ bootstrap->texture_size = dev_priv->agp_textures->size;
} else {
- bootstrap.texture_handle = 0;
- bootstrap.texture_size = 0;
+ bootstrap->texture_handle = 0;
+ bootstrap->texture_size = 0;
}
- bootstrap.agp_mode = modes[bootstrap.agp_mode & 0x07];
- DRM_COPY_TO_USER_IOCTL((drm_mga_dma_bootstrap_t __user *)data,
- bootstrap, sizeof(bootstrap));
+ bootstrap->agp_mode = modes[bootstrap->agp_mode & 0x07];
return err;
}
@@ -826,7 +820,7 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
dev_priv->sarea = drm_getsarea(dev);
if (!dev_priv->sarea) {
DRM_ERROR("failed to find sarea!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (!dev_priv->used_new_dma_init) {
@@ -837,29 +831,29 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
dev_priv->status = drm_core_findmap(dev, init->status_offset);
if (!dev_priv->status) {
DRM_ERROR("failed to find status page!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
if (!dev_priv->mmio) {
DRM_ERROR("failed to find mmio region!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->warp = drm_core_findmap(dev, init->warp_offset);
if (!dev_priv->warp) {
DRM_ERROR("failed to find warp microcode region!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->primary = drm_core_findmap(dev, init->primary_offset);
if (!dev_priv->primary) {
DRM_ERROR("failed to find primary dma region!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev->agp_buffer_token = init->buffers_offset;
dev->agp_buffer_map =
drm_core_findmap(dev, init->buffers_offset);
if (!dev->agp_buffer_map) {
DRM_ERROR("failed to find dma buffer region!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
drm_core_ioremap(dev_priv->warp, dev);
@@ -877,7 +871,7 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
((dev->agp_buffer_map == NULL) ||
(dev->agp_buffer_map->handle == NULL)))) {
DRM_ERROR("failed to ioremap agp regions!\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
ret = mga_warp_install_microcode(dev_priv);
@@ -927,7 +921,7 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
if (mga_freelist_init(dev, dev_priv) < 0) {
DRM_ERROR("could not initialize freelist\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
return 0;
@@ -1007,20 +1001,17 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup)
return 0;
}
-int mga_dma_init(DRM_IOCTL_ARGS)
+int mga_dma_init(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_mga_init_t init;
+ drm_mga_init_t *init = data;
int err;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(init, (drm_mga_init_t __user *) data,
- sizeof(init));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- switch (init.func) {
+ switch (init->func) {
case MGA_INIT_DMA:
- err = mga_do_init_dma(dev, &init);
+ err = mga_do_init_dma(dev, init);
if (err) {
(void)mga_do_cleanup_dma(dev, FULL_CLEANUP);
}
@@ -1029,36 +1020,33 @@ int mga_dma_init(DRM_IOCTL_ARGS)
return mga_do_cleanup_dma(dev, FULL_CLEANUP);
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* ================================================================
* Primary DMA stream management
*/
-int mga_dma_flush(DRM_IOCTL_ARGS)
+int mga_dma_flush(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- struct drm_lock lock;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ struct drm_lock *lock = data;
- DRM_COPY_FROM_USER_IOCTL(lock, (struct drm_lock __user *) data,
- sizeof(lock));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("%s%s%s\n",
- (lock.flags & _DRM_LOCK_FLUSH) ? "flush, " : "",
- (lock.flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "",
- (lock.flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "");
+ (lock->flags & _DRM_LOCK_FLUSH) ? "flush, " : "",
+ (lock->flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "",
+ (lock->flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "");
WRAP_WAIT_WITH_RETURN(dev_priv);
- if (lock.flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL)) {
+ if (lock->flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL)) {
mga_do_dma_flush(dev_priv);
}
- if (lock.flags & _DRM_LOCK_QUIESCENT) {
+ if (lock->flags & _DRM_LOCK_QUIESCENT) {
#if MGA_DMA_DEBUG
int ret = mga_do_wait_for_idle(dev_priv);
if (ret < 0)
@@ -1072,12 +1060,12 @@ int mga_dma_flush(DRM_IOCTL_ARGS)
}
}
-int mga_dma_reset(DRM_IOCTL_ARGS)
+int mga_dma_reset(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return mga_do_dma_reset(dev_priv);
}
@@ -1086,7 +1074,8 @@ int mga_dma_reset(DRM_IOCTL_ARGS)
* DMA buffer management
*/
-static int mga_dma_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm_dma * d)
+static int mga_dma_get_buffers(struct drm_device * dev,
+ struct drm_file *file_priv, struct drm_dma * d)
{
struct drm_buf *buf;
int i;
@@ -1094,61 +1083,56 @@ static int mga_dma_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm
for (i = d->granted_count; i < d->request_count; i++) {
buf = mga_freelist_get(dev);
if (!buf)
- return DRM_ERR(EAGAIN);
+ return -EAGAIN;
- buf->filp = filp;
+ buf->file_priv = file_priv;
if (DRM_COPY_TO_USER(&d->request_indices[i],
&buf->idx, sizeof(buf->idx)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if (DRM_COPY_TO_USER(&d->request_sizes[i],
&buf->total, sizeof(buf->total)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
d->granted_count++;
}
return 0;
}
-int mga_dma_buffers(DRM_IOCTL_ARGS)
+int mga_dma_buffers(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
struct drm_device_dma *dma = dev->dma;
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- struct drm_dma __user *argp = (void __user *)data;
- struct drm_dma d;
+ struct drm_dma *d = data;
int ret = 0;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* Please don't send us buffers.
*/
- if (d.send_count != 0) {
+ if (d->send_count != 0) {
DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
- DRM_CURRENTPID, d.send_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->send_count);
+ return -EINVAL;
}
/* We'll send you buffers.
*/
- if (d.request_count < 0 || d.request_count > dma->buf_count) {
+ if (d->request_count < 0 || d->request_count > dma->buf_count) {
DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
- DRM_CURRENTPID, d.request_count, dma->buf_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->request_count, dma->buf_count);
+ return -EINVAL;
}
WRAP_TEST_WITH_RETURN(dev_priv);
- d.granted_count = 0;
+ d->granted_count = 0;
- if (d.request_count) {
- ret = mga_dma_get_buffers(filp, dev, &d);
+ if (d->request_count) {
+ ret = mga_dma_get_buffers(dev, file_priv, d);
}
- DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d));
-
return ret;
}
diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h
index 49253affa47..cd94c04e31c 100644
--- a/drivers/char/drm/mga_drv.h
+++ b/drivers/char/drm/mga_drv.h
@@ -148,15 +148,20 @@ typedef struct drm_mga_private {
unsigned int agp_size;
} drm_mga_private_t;
-extern drm_ioctl_desc_t mga_ioctls[];
+extern struct drm_ioctl_desc mga_ioctls[];
extern int mga_max_ioctl;
/* mga_dma.c */
-extern int mga_dma_bootstrap(DRM_IOCTL_ARGS);
-extern int mga_dma_init(DRM_IOCTL_ARGS);
-extern int mga_dma_flush(DRM_IOCTL_ARGS);
-extern int mga_dma_reset(DRM_IOCTL_ARGS);
-extern int mga_dma_buffers(DRM_IOCTL_ARGS);
+extern int mga_dma_bootstrap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int mga_dma_init(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int mga_dma_flush(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int mga_dma_reset(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int mga_dma_buffers(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern int mga_driver_load(struct drm_device *dev, unsigned long flags);
extern int mga_driver_unload(struct drm_device * dev);
extern void mga_driver_lastclose(struct drm_device * dev);
@@ -245,7 +250,7 @@ do { \
dev_priv->prim.high_mark ) { \
if ( MGA_DMA_DEBUG ) \
DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \
- return DRM_ERR(EBUSY); \
+ return -EBUSY; \
} \
} \
} while (0)
@@ -256,7 +261,7 @@ do { \
if ( mga_do_wait_for_idle( dev_priv ) < 0 ) { \
if ( MGA_DMA_DEBUG ) \
DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \
- return DRM_ERR(EBUSY); \
+ return -EBUSY; \
} \
mga_do_dma_wrap_end( dev_priv ); \
} \
diff --git a/drivers/char/drm/mga_state.c b/drivers/char/drm/mga_state.c
index d448b0aef33..5ec8b61c5d4 100644
--- a/drivers/char/drm/mga_state.c
+++ b/drivers/char/drm/mga_state.c
@@ -392,7 +392,7 @@ static int mga_verify_context(drm_mga_private_t * dev_priv)
ctx->dstorg, dev_priv->front_offset,
dev_priv->back_offset);
ctx->dstorg = 0;
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
@@ -411,7 +411,7 @@ static int mga_verify_tex(drm_mga_private_t * dev_priv, int unit)
if (org == (MGA_TEXORGMAP_SYSMEM | MGA_TEXORGACC_PCI)) {
DRM_ERROR("*** bad TEXORG: 0x%x, unit %d\n", tex->texorg, unit);
tex->texorg = 0;
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
@@ -453,13 +453,13 @@ static int mga_verify_iload(drm_mga_private_t * dev_priv,
dstorg + length > (dev_priv->texture_offset +
dev_priv->texture_size)) {
DRM_ERROR("*** bad iload DSTORG: 0x%x\n", dstorg);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (length & MGA_ILOAD_MASK) {
DRM_ERROR("*** bad iload length: 0x%x\n",
length & MGA_ILOAD_MASK);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
@@ -471,7 +471,7 @@ static int mga_verify_blit(drm_mga_private_t * dev_priv,
if ((srcorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) ||
(dstorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM)) {
DRM_ERROR("*** bad blit: src=0x%x dst=0x%x\n", srcorg, dstorg);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
}
@@ -828,24 +828,20 @@ static void mga_dma_dispatch_blit(struct drm_device * dev, drm_mga_blit_t * blit
*
*/
-static int mga_dma_clear(DRM_IOCTL_ARGS)
+static int mga_dma_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_clear_t clear;
+ drm_mga_clear_t *clear = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(clear, (drm_mga_clear_t __user *) data,
- sizeof(clear));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
WRAP_TEST_WITH_RETURN(dev_priv);
- mga_dma_dispatch_clear(dev, &clear);
+ mga_dma_dispatch_clear(dev, clear);
/* Make sure we restore the 3D state next time.
*/
@@ -854,13 +850,12 @@ static int mga_dma_clear(DRM_IOCTL_ARGS)
return 0;
}
-static int mga_dma_swap(DRM_IOCTL_ARGS)
+static int mga_dma_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
@@ -876,37 +871,32 @@ static int mga_dma_swap(DRM_IOCTL_ARGS)
return 0;
}
-static int mga_dma_vertex(DRM_IOCTL_ARGS)
+static int mga_dma_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
drm_mga_buf_priv_t *buf_priv;
- drm_mga_vertex_t vertex;
-
- LOCK_TEST_WITH_RETURN(dev, filp);
+ drm_mga_vertex_t *vertex = data;
- DRM_COPY_FROM_USER_IOCTL(vertex,
- (drm_mga_vertex_t __user *) data,
- sizeof(vertex));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (vertex.idx < 0 || vertex.idx > dma->buf_count)
- return DRM_ERR(EINVAL);
- buf = dma->buflist[vertex.idx];
+ if (vertex->idx < 0 || vertex->idx > dma->buf_count)
+ return -EINVAL;
+ buf = dma->buflist[vertex->idx];
buf_priv = buf->dev_private;
- buf->used = vertex.used;
- buf_priv->discard = vertex.discard;
+ buf->used = vertex->used;
+ buf_priv->discard = vertex->discard;
if (!mga_verify_state(dev_priv)) {
- if (vertex.discard) {
+ if (vertex->discard) {
if (buf_priv->dispatched == 1)
AGE_BUFFER(buf_priv);
buf_priv->dispatched = 0;
mga_freelist_put(dev, buf);
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
WRAP_TEST_WITH_RETURN(dev_priv);
@@ -916,82 +906,73 @@ static int mga_dma_vertex(DRM_IOCTL_ARGS)
return 0;
}
-static int mga_dma_indices(DRM_IOCTL_ARGS)
+static int mga_dma_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
drm_mga_buf_priv_t *buf_priv;
- drm_mga_indices_t indices;
+ drm_mga_indices_t *indices = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(indices,
- (drm_mga_indices_t __user *) data,
- sizeof(indices));
+ if (indices->idx < 0 || indices->idx > dma->buf_count)
+ return -EINVAL;
- if (indices.idx < 0 || indices.idx > dma->buf_count)
- return DRM_ERR(EINVAL);
-
- buf = dma->buflist[indices.idx];
+ buf = dma->buflist[indices->idx];
buf_priv = buf->dev_private;
- buf_priv->discard = indices.discard;
+ buf_priv->discard = indices->discard;
if (!mga_verify_state(dev_priv)) {
- if (indices.discard) {
+ if (indices->discard) {
if (buf_priv->dispatched == 1)
AGE_BUFFER(buf_priv);
buf_priv->dispatched = 0;
mga_freelist_put(dev, buf);
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
WRAP_TEST_WITH_RETURN(dev_priv);
- mga_dma_dispatch_indices(dev, buf, indices.start, indices.end);
+ mga_dma_dispatch_indices(dev, buf, indices->start, indices->end);
return 0;
}
-static int mga_dma_iload(DRM_IOCTL_ARGS)
+static int mga_dma_iload(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
struct drm_device_dma *dma = dev->dma;
drm_mga_private_t *dev_priv = dev->dev_private;
struct drm_buf *buf;
drm_mga_buf_priv_t *buf_priv;
- drm_mga_iload_t iload;
+ drm_mga_iload_t *iload = data;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(iload, (drm_mga_iload_t __user *) data,
- sizeof(iload));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
#if 0
if (mga_do_wait_for_idle(dev_priv) < 0) {
if (MGA_DMA_DEBUG)
DRM_INFO("%s: -EBUSY\n", __FUNCTION__);
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
#endif
- if (iload.idx < 0 || iload.idx > dma->buf_count)
- return DRM_ERR(EINVAL);
+ if (iload->idx < 0 || iload->idx > dma->buf_count)
+ return -EINVAL;
- buf = dma->buflist[iload.idx];
+ buf = dma->buflist[iload->idx];
buf_priv = buf->dev_private;
- if (mga_verify_iload(dev_priv, iload.dstorg, iload.length)) {
+ if (mga_verify_iload(dev_priv, iload->dstorg, iload->length)) {
mga_freelist_put(dev, buf);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
WRAP_TEST_WITH_RETURN(dev_priv);
- mga_dma_dispatch_iload(dev, buf, iload.dstorg, iload.length);
+ mga_dma_dispatch_iload(dev, buf, iload->dstorg, iload->length);
/* Make sure we restore the 3D state next time.
*/
@@ -1000,28 +981,24 @@ static int mga_dma_iload(DRM_IOCTL_ARGS)
return 0;
}
-static int mga_dma_blit(DRM_IOCTL_ARGS)
+static int mga_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_mga_blit_t blit;
+ drm_mga_blit_t *blit = data;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(blit, (drm_mga_blit_t __user *) data,
- sizeof(blit));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
- if (mga_verify_blit(dev_priv, blit.srcorg, blit.dstorg))
- return DRM_ERR(EINVAL);
+ if (mga_verify_blit(dev_priv, blit->srcorg, blit->dstorg))
+ return -EINVAL;
WRAP_TEST_WITH_RETURN(dev_priv);
- mga_dma_dispatch_blit(dev, &blit);
+ mga_dma_dispatch_blit(dev, blit);
/* Make sure we restore the 3D state next time.
*/
@@ -1030,24 +1007,20 @@ static int mga_dma_blit(DRM_IOCTL_ARGS)
return 0;
}
-static int mga_getparam(DRM_IOCTL_ARGS)
+static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
- drm_mga_getparam_t param;
+ drm_mga_getparam_t *param = data;
int value;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(param, (drm_mga_getparam_t __user *) data,
- sizeof(param));
-
DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
- switch (param.param) {
+ switch (param->param) {
case MGA_PARAM_IRQ_NR:
value = dev->irq;
break;
@@ -1055,36 +1028,35 @@ static int mga_getparam(DRM_IOCTL_ARGS)
value = dev_priv->chipset;
break;
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
+ if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
}
-static int mga_set_fence(DRM_IOCTL_ARGS)
+static int mga_set_fence(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
- u32 temp;
+ u32 *fence = data;
DMA_LOCALS;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
- /* I would normal do this assignment in the declaration of temp,
+ /* I would normal do this assignment in the declaration of fence,
* but dev_priv may be NULL.
*/
- temp = dev_priv->next_fence_to_post;
+ *fence = dev_priv->next_fence_to_post;
dev_priv->next_fence_to_post++;
BEGIN_DMA(1);
@@ -1093,53 +1065,40 @@ static int mga_set_fence(DRM_IOCTL_ARGS)
MGA_DMAPAD, 0x00000000, MGA_SOFTRAP, 0x00000000);
ADVANCE_DMA();
- if (DRM_COPY_TO_USER((u32 __user *) data, &temp, sizeof(u32))) {
- DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
- }
-
return 0;
}
-static int mga_wait_fence(DRM_IOCTL_ARGS)
+static int mga_wait_fence(struct drm_device *dev, void *data, struct drm_file *
+file_priv)
{
- DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
- u32 fence;
+ u32 *fence = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(fence, (u32 __user *) data, sizeof(u32));
-
DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
- mga_driver_fence_wait(dev, &fence);
-
- if (DRM_COPY_TO_USER((u32 __user *) data, &fence, sizeof(u32))) {
- DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
- }
-
+ mga_driver_fence_wait(dev, fence);
return 0;
}
-drm_ioctl_desc_t mga_ioctls[] = {
- [DRM_IOCTL_NR(DRM_MGA_INIT)] = {mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = {mga_dma_flush, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_RESET)] = {mga_dma_reset, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_SWAP)] = {mga_dma_swap, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_CLEAR)] = {mga_dma_clear, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_VERTEX)] = {mga_dma_vertex, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_INDICES)] = {mga_dma_indices, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = {mga_dma_iload, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_BLIT)] = {mga_dma_blit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_GETPARAM)] = {mga_getparam, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_SET_FENCE)] = {mga_set_fence, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_WAIT_FENCE)] = {mga_wait_fence, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_MGA_DMA_BOOTSTRAP)] = {mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+struct drm_ioctl_desc mga_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_MGA_INIT, mga_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_MGA_FLUSH, mga_dma_flush, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_RESET, mga_dma_reset, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_SWAP, mga_dma_swap, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_CLEAR, mga_dma_clear, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_VERTEX, mga_dma_vertex, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_INDICES, mga_dma_indices, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_ILOAD, mga_dma_iload, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_BLIT, mga_dma_blit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_GETPARAM, mga_getparam, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_SET_FENCE, mga_set_fence, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_WAIT_FENCE, mga_wait_fence, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_MGA_DMA_BOOTSTRAP, mga_dma_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
};
int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls);
diff --git a/drivers/char/drm/mga_warp.c b/drivers/char/drm/mga_warp.c
index d67f4925fba..651b93c8ab5 100644
--- a/drivers/char/drm/mga_warp.c
+++ b/drivers/char/drm/mga_warp.c
@@ -141,7 +141,7 @@ int mga_warp_install_microcode(drm_mga_private_t * dev_priv)
if (size > dev_priv->warp->size) {
DRM_ERROR("microcode too large! (%u > %lu)\n",
size, dev_priv->warp->size);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
switch (dev_priv->chipset) {
@@ -151,7 +151,7 @@ int mga_warp_install_microcode(drm_mga_private_t * dev_priv)
case MGA_CARD_TYPE_G200:
return mga_warp_install_g200_microcode(dev_priv);
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -177,7 +177,7 @@ int mga_warp_init(drm_mga_private_t * dev_priv)
MGA_WRITE(MGA_WVRTXSZ, 7);
break;
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
MGA_WRITE(MGA_WMISC, (MGA_WUCODECACHE_ENABLE |
@@ -186,7 +186,7 @@ int mga_warp_init(drm_mga_private_t * dev_priv)
if (wmisc != WMISC_EXPECTED) {
DRM_ERROR("WARP engine config failed! 0x%x != 0x%x\n",
wmisc, WMISC_EXPECTED);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c
index b163ed09bd8..7d550aba165 100644
--- a/drivers/char/drm/r128_cce.c
+++ b/drivers/char/drm/r128_cce.c
@@ -129,7 +129,7 @@ static int r128_do_pixcache_flush(drm_r128_private_t * dev_priv)
#if R128_FIFO_DEBUG
DRM_ERROR("failed!\n");
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries)
@@ -146,7 +146,7 @@ static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries)
#if R128_FIFO_DEBUG
DRM_ERROR("failed!\n");
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int r128_do_wait_for_idle(drm_r128_private_t * dev_priv)
@@ -168,7 +168,7 @@ static int r128_do_wait_for_idle(drm_r128_private_t * dev_priv)
#if R128_FIFO_DEBUG
DRM_ERROR("failed!\n");
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
/* ================================================================
@@ -227,7 +227,7 @@ int r128_do_cce_idle(drm_r128_private_t * dev_priv)
DRM_ERROR("failed!\n");
r128_status(dev_priv);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
/* Start the Concurrent Command Engine.
@@ -355,7 +355,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
memset(dev_priv, 0, sizeof(drm_r128_private_t));
@@ -365,7 +365,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("PCI GART memory not allocated!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->usec_timeout = init->usec_timeout;
@@ -374,7 +374,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_DEBUG("TIMEOUT problem!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->cce_mode = init->cce_mode;
@@ -394,7 +394,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_DEBUG("Bad cce_mode!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
switch (init->cce_mode) {
@@ -461,7 +461,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("could not find sarea!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
@@ -469,21 +469,21 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("could not find mmio region!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset);
if (!dev_priv->cce_ring) {
DRM_ERROR("could not find cce ring region!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
if (!dev_priv->ring_rptr) {
DRM_ERROR("could not find ring read pointer!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev->agp_buffer_token = init->buffers_offset;
dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
@@ -491,7 +491,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("could not find dma buffer region!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (!dev_priv->is_pci) {
@@ -501,7 +501,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("could not find agp texture region!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -520,7 +520,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("Could not ioremap agp regions!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
} else
#endif
@@ -567,7 +567,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
DRM_ERROR("failed to init PCI GART!\n");
dev->dev_private = (void *)dev_priv;
r128_do_cleanup_cce(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr);
#if __OS_HAS_AGP
@@ -625,35 +625,30 @@ int r128_do_cleanup_cce(struct drm_device * dev)
return 0;
}
-int r128_cce_init(DRM_IOCTL_ARGS)
+int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_r128_init_t init;
+ drm_r128_init_t *init = data;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(init, (drm_r128_init_t __user *) data,
- sizeof(init));
-
- switch (init.func) {
+ switch (init->func) {
case R128_INIT_CCE:
- return r128_do_init_cce(dev, &init);
+ return r128_do_init_cce(dev, init);
case R128_CLEANUP_CCE:
return r128_do_cleanup_cce(dev);
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
-int r128_cce_start(DRM_IOCTL_ARGS)
+int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) {
DRM_DEBUG("%s while CCE running\n", __FUNCTION__);
@@ -668,30 +663,26 @@ int r128_cce_start(DRM_IOCTL_ARGS)
/* Stop the CCE. The engine must have been idled before calling this
* routine.
*/
-int r128_cce_stop(DRM_IOCTL_ARGS)
+int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_cce_stop_t stop;
+ drm_r128_cce_stop_t *stop = data;
int ret;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(stop, (drm_r128_cce_stop_t __user *) data,
- sizeof(stop));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* Flush any pending CCE commands. This ensures any outstanding
* commands are exectuted by the engine before we turn it off.
*/
- if (stop.flush) {
+ if (stop->flush) {
r128_do_cce_flush(dev_priv);
}
/* If we fail to make the engine go idle, we return an error
* code so that the DRM ioctl wrapper can try again.
*/
- if (stop.idle) {
+ if (stop->idle) {
ret = r128_do_cce_idle(dev_priv);
if (ret)
return ret;
@@ -711,17 +702,16 @@ int r128_cce_stop(DRM_IOCTL_ARGS)
/* Just reset the CCE ring. Called as part of an X Server engine reset.
*/
-int r128_cce_reset(DRM_IOCTL_ARGS)
+int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_DEBUG("%s called before init done\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
r128_do_cce_reset(dev_priv);
@@ -732,13 +722,12 @@ int r128_cce_reset(DRM_IOCTL_ARGS)
return 0;
}
-int r128_cce_idle(DRM_IOCTL_ARGS)
+int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (dev_priv->cce_running) {
r128_do_cce_flush(dev_priv);
@@ -747,19 +736,18 @@ int r128_cce_idle(DRM_IOCTL_ARGS)
return r128_do_cce_idle(dev_priv);
}
-int r128_engine_reset(DRM_IOCTL_ARGS)
+int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return r128_do_engine_reset(dev);
}
-int r128_fullscreen(DRM_IOCTL_ARGS)
+int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* ================================================================
@@ -780,7 +768,7 @@ static int r128_freelist_init(struct drm_device * dev)
dev_priv->head = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);
if (dev_priv->head == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
memset(dev_priv->head, 0, sizeof(drm_r128_freelist_t));
dev_priv->head->age = R128_BUFFER_USED;
@@ -791,7 +779,7 @@ static int r128_freelist_init(struct drm_device * dev)
entry = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER);
if (!entry)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
entry->age = R128_BUFFER_FREE;
entry->buf = buf;
@@ -828,7 +816,7 @@ static struct drm_buf *r128_freelist_get(struct drm_device * dev)
for (i = 0; i < dma->buf_count; i++) {
buf = dma->buflist[i];
buf_priv = buf->dev_private;
- if (buf->filp == 0)
+ if (buf->file_priv == 0)
return buf;
}
@@ -883,10 +871,12 @@ int r128_wait_ring(drm_r128_private_t * dev_priv, int n)
/* FIXME: This is being ignored... */
DRM_ERROR("failed!\n");
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
-static int r128_cce_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm_dma * d)
+static int r128_cce_get_buffers(struct drm_device * dev,
+ struct drm_file *file_priv,
+ struct drm_dma * d)
{
int i;
struct drm_buf *buf;
@@ -894,57 +884,51 @@ static int r128_cce_get_buffers(DRMFILE filp, struct drm_device * dev, struct dr
for (i = d->granted_count; i < d->request_count; i++) {
buf = r128_freelist_get(dev);
if (!buf)
- return DRM_ERR(EAGAIN);
+ return -EAGAIN;
- buf->filp = filp;
+ buf->file_priv = file_priv;
if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
sizeof(buf->idx)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
sizeof(buf->total)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
d->granted_count++;
}
return 0;
}
-int r128_cce_buffers(DRM_IOCTL_ARGS)
+int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
struct drm_device_dma *dma = dev->dma;
int ret = 0;
- struct drm_dma __user *argp = (void __user *)data;
- struct drm_dma d;
+ struct drm_dma *d = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* Please don't send us buffers.
*/
- if (d.send_count != 0) {
+ if (d->send_count != 0) {
DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
- DRM_CURRENTPID, d.send_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->send_count);
+ return -EINVAL;
}
/* We'll send you buffers.
*/
- if (d.request_count < 0 || d.request_count > dma->buf_count) {
+ if (d->request_count < 0 || d->request_count > dma->buf_count) {
DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
- DRM_CURRENTPID, d.request_count, dma->buf_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->request_count, dma->buf_count);
+ return -EINVAL;
}
- d.granted_count = 0;
+ d->granted_count = 0;
- if (d.request_count) {
- ret = r128_cce_get_buffers(filp, dev, &d);
+ if (d->request_count) {
+ ret = r128_cce_get_buffers(dev, file_priv, d);
}
- DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d));
-
return ret;
}
diff --git a/drivers/char/drm/r128_drm.h b/drivers/char/drm/r128_drm.h
index e94a39c6e32..8d8878b55f5 100644
--- a/drivers/char/drm/r128_drm.h
+++ b/drivers/char/drm/r128_drm.h
@@ -222,11 +222,7 @@ typedef struct drm_r128_init {
R128_INIT_CCE = 0x01,
R128_CLEANUP_CCE = 0x02
} func;
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
- int sarea_priv_offset;
-#else
unsigned long sarea_priv_offset;
-#endif
int is_pci;
int cce_mode;
int cce_secure;
@@ -240,21 +236,12 @@ typedef struct drm_r128_init {
unsigned int depth_offset, depth_pitch;
unsigned int span_offset;
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
- unsigned int fb_offset;
- unsigned int mmio_offset;
- unsigned int ring_offset;
- unsigned int ring_rptr_offset;
- unsigned int buffers_offset;
- unsigned int agp_textures_offset;
-#else
unsigned long fb_offset;
unsigned long mmio_offset;
unsigned long ring_offset;
unsigned long ring_rptr_offset;
unsigned long buffers_offset;
unsigned long agp_textures_offset;
-#endif
} drm_r128_init_t;
typedef struct drm_r128_cce_stop {
@@ -264,15 +251,10 @@ typedef struct drm_r128_cce_stop {
typedef struct drm_r128_clear {
unsigned int flags;
-#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0)
- int x, y, w, h;
-#endif
unsigned int clear_color;
unsigned int clear_depth;
-#if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0)
unsigned int color_mask;
unsigned int depth_mask;
-#endif
} drm_r128_clear_t;
typedef struct drm_r128_vertex {
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index 72249fb2fd1..5041bd8dbed 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -29,7 +29,7 @@
* Rickard E. (Rik) Faith <faith@valinux.com>
* Kevin E. Martin <martin@valinux.com>
* Gareth Hughes <gareth@valinux.com>
- * Michel D�zer <daenzerm@student.ethz.ch>
+ * Michel Dänzer <daenzerm@student.ethz.ch>
*/
#ifndef __R128_DRV_H__
@@ -129,18 +129,18 @@ typedef struct drm_r128_buf_priv {
drm_r128_freelist_t *list_entry;
} drm_r128_buf_priv_t;
-extern drm_ioctl_desc_t r128_ioctls[];
+extern struct drm_ioctl_desc r128_ioctls[];
extern int r128_max_ioctl;
/* r128_cce.c */
-extern int r128_cce_init(DRM_IOCTL_ARGS);
-extern int r128_cce_start(DRM_IOCTL_ARGS);
-extern int r128_cce_stop(DRM_IOCTL_ARGS);
-extern int r128_cce_reset(DRM_IOCTL_ARGS);
-extern int r128_cce_idle(DRM_IOCTL_ARGS);
-extern int r128_engine_reset(DRM_IOCTL_ARGS);
-extern int r128_fullscreen(DRM_IOCTL_ARGS);
-extern int r128_cce_buffers(DRM_IOCTL_ARGS);
+extern int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern void r128_freelist_reset(struct drm_device * dev);
@@ -156,7 +156,8 @@ extern void r128_driver_irq_preinstall(struct drm_device * dev);
extern void r128_driver_irq_postinstall(struct drm_device * dev);
extern void r128_driver_irq_uninstall(struct drm_device * dev);
extern void r128_driver_lastclose(struct drm_device * dev);
-extern void r128_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void r128_driver_preclose(struct drm_device * dev,
+ struct drm_file *file_priv);
extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
@@ -428,7 +429,7 @@ do { \
DRM_UDELAY(1); \
} \
DRM_ERROR( "ring space check failed!\n" ); \
- return DRM_ERR(EBUSY); \
+ return -EBUSY; \
} \
__ring_space_done: \
; \
diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c
index 7b334fb7d64..b7f483cac6d 100644
--- a/drivers/char/drm/r128_state.c
+++ b/drivers/char/drm/r128_state.c
@@ -776,8 +776,9 @@ static void r128_cce_dispatch_indices(struct drm_device * dev,
sarea_priv->nbox = 0;
}
-static int r128_cce_dispatch_blit(DRMFILE filp,
- struct drm_device * dev, drm_r128_blit_t * blit)
+static int r128_cce_dispatch_blit(struct drm_device * dev,
+ struct drm_file *file_priv,
+ drm_r128_blit_t * blit)
{
drm_r128_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
@@ -809,7 +810,7 @@ static int r128_cce_dispatch_blit(DRMFILE filp,
break;
default:
DRM_ERROR("invalid blit format %d\n", blit->format);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* Flush the pixel cache, and mark the contents as Read Invalid.
@@ -829,14 +830,14 @@ static int r128_cce_dispatch_blit(DRMFILE filp,
buf = dma->buflist[blit->idx];
buf_priv = buf->dev_private;
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
DRM_ERROR("sending pending buffer %d\n", blit->idx);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
buf_priv->discard = 1;
@@ -900,22 +901,22 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev,
count = depth->n;
if (count > 4096 || count <= 0)
- return DRM_ERR(EMSGSIZE);
+ return -EMSGSIZE;
if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) {
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) {
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
buffer_size = depth->n * sizeof(u32);
buffer = drm_alloc(buffer_size, DRM_MEM_BUFS);
if (buffer == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) {
drm_free(buffer, buffer_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
mask_size = depth->n * sizeof(u8);
@@ -923,12 +924,12 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev,
mask = drm_alloc(mask_size, DRM_MEM_BUFS);
if (mask == NULL) {
drm_free(buffer, buffer_size, DRM_MEM_BUFS);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) {
drm_free(buffer, buffer_size, DRM_MEM_BUFS);
drm_free(mask, mask_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
for (i = 0; i < count; i++, x++) {
@@ -996,28 +997,28 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev,
count = depth->n;
if (count > 4096 || count <= 0)
- return DRM_ERR(EMSGSIZE);
+ return -EMSGSIZE;
xbuf_size = count * sizeof(*x);
ybuf_size = count * sizeof(*y);
x = drm_alloc(xbuf_size, DRM_MEM_BUFS);
if (x == NULL) {
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
y = drm_alloc(ybuf_size, DRM_MEM_BUFS);
if (y == NULL) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (DRM_COPY_FROM_USER(y, depth->y, xbuf_size)) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
buffer_size = depth->n * sizeof(u32);
@@ -1025,13 +1026,13 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev,
if (buffer == NULL) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
drm_free(buffer, buffer_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (depth->mask) {
@@ -1041,14 +1042,14 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev,
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
drm_free(buffer, buffer_size, DRM_MEM_BUFS);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
drm_free(buffer, buffer_size, DRM_MEM_BUFS);
drm_free(mask, mask_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
for (i = 0; i < count; i++) {
@@ -1115,13 +1116,13 @@ static int r128_cce_dispatch_read_span(struct drm_device * dev,
count = depth->n;
if (count > 4096 || count <= 0)
- return DRM_ERR(EMSGSIZE);
+ return -EMSGSIZE;
if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) {
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) {
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
BEGIN_RING(7);
@@ -1159,7 +1160,7 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev,
count = depth->n;
if (count > 4096 || count <= 0)
- return DRM_ERR(EMSGSIZE);
+ return -EMSGSIZE;
if (count > dev_priv->depth_pitch) {
count = dev_priv->depth_pitch;
@@ -1169,22 +1170,22 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev,
ybuf_size = count * sizeof(*y);
x = drm_alloc(xbuf_size, DRM_MEM_BUFS);
if (x == NULL) {
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
y = drm_alloc(ybuf_size, DRM_MEM_BUFS);
if (y == NULL) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (DRM_COPY_FROM_USER(y, depth->y, ybuf_size)) {
drm_free(x, xbuf_size, DRM_MEM_BUFS);
drm_free(y, ybuf_size, DRM_MEM_BUFS);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
for (i = 0; i < count; i++) {
@@ -1241,25 +1242,21 @@ static void r128_cce_dispatch_stipple(struct drm_device * dev, u32 * stipple)
* IOCTL functions
*/
-static int r128_cce_clear(DRM_IOCTL_ARGS)
+static int r128_cce_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_r128_clear_t clear;
+ drm_r128_clear_t *clear = data;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(clear, (drm_r128_clear_t __user *) data,
- sizeof(clear));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS;
- r128_cce_dispatch_clear(dev, &clear);
+ r128_cce_dispatch_clear(dev, clear);
COMMIT_RING();
/* Make sure we restore the 3D state next time.
@@ -1309,13 +1306,12 @@ static int r128_do_cleanup_pageflip(struct drm_device * dev)
* They can & should be intermixed to support multiple 3d windows.
*/
-static int r128_cce_flip(DRM_IOCTL_ARGS)
+static int r128_cce_flip(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("%s\n", __FUNCTION__);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -1328,14 +1324,13 @@ static int r128_cce_flip(DRM_IOCTL_ARGS)
return 0;
}
-static int r128_cce_swap(DRM_IOCTL_ARGS)
+static int r128_cce_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
DRM_DEBUG("%s\n", __FUNCTION__);
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -1350,58 +1345,54 @@ static int r128_cce_swap(DRM_IOCTL_ARGS)
return 0;
}
-static int r128_cce_vertex(DRM_IOCTL_ARGS)
+static int r128_cce_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
drm_r128_buf_priv_t *buf_priv;
- drm_r128_vertex_t vertex;
+ drm_r128_vertex_t *vertex = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(vertex, (drm_r128_vertex_t __user *) data,
- sizeof(vertex));
-
DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
- DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard);
+ DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard);
- if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
+ if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- vertex.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ vertex->idx, dma->buf_count - 1);
+ return -EINVAL;
}
- if (vertex.prim < 0 ||
- vertex.prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
- DRM_ERROR("buffer prim %d\n", vertex.prim);
- return DRM_ERR(EINVAL);
+ if (vertex->prim < 0 ||
+ vertex->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
+ DRM_ERROR("buffer prim %d\n", vertex->prim);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf = dma->buflist[vertex.idx];
+ buf = dma->buflist[vertex->idx];
buf_priv = buf->dev_private;
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", vertex.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", vertex->idx);
+ return -EINVAL;
}
- buf->used = vertex.count;
- buf_priv->prim = vertex.prim;
- buf_priv->discard = vertex.discard;
+ buf->used = vertex->count;
+ buf_priv->prim = vertex->prim;
+ buf_priv->discard = vertex->discard;
r128_cce_dispatch_vertex(dev, buf);
@@ -1409,134 +1400,123 @@ static int r128_cce_vertex(DRM_IOCTL_ARGS)
return 0;
}
-static int r128_cce_indices(DRM_IOCTL_ARGS)
+static int r128_cce_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
drm_r128_buf_priv_t *buf_priv;
- drm_r128_indices_t elts;
+ drm_r128_indices_t *elts = data;
int count;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(elts, (drm_r128_indices_t __user *) data,
- sizeof(elts));
-
DRM_DEBUG("pid=%d buf=%d s=%d e=%d d=%d\n", DRM_CURRENTPID,
- elts.idx, elts.start, elts.end, elts.discard);
+ elts->idx, elts->start, elts->end, elts->discard);
- if (elts.idx < 0 || elts.idx >= dma->buf_count) {
+ if (elts->idx < 0 || elts->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- elts.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ elts->idx, dma->buf_count - 1);
+ return -EINVAL;
}
- if (elts.prim < 0 || elts.prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
- DRM_ERROR("buffer prim %d\n", elts.prim);
- return DRM_ERR(EINVAL);
+ if (elts->prim < 0 ||
+ elts->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
+ DRM_ERROR("buffer prim %d\n", elts->prim);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf = dma->buflist[elts.idx];
+ buf = dma->buflist[elts->idx];
buf_priv = buf->dev_private;
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", elts.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", elts->idx);
+ return -EINVAL;
}
- count = (elts.end - elts.start) / sizeof(u16);
- elts.start -= R128_INDEX_PRIM_OFFSET;
+ count = (elts->end - elts->start) / sizeof(u16);
+ elts->start -= R128_INDEX_PRIM_OFFSET;
- if (elts.start & 0x7) {
- DRM_ERROR("misaligned buffer 0x%x\n", elts.start);
- return DRM_ERR(EINVAL);
+ if (elts->start & 0x7) {
+ DRM_ERROR("misaligned buffer 0x%x\n", elts->start);
+ return -EINVAL;
}
- if (elts.start < buf->used) {
- DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used);
- return DRM_ERR(EINVAL);
+ if (elts->start < buf->used) {
+ DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used);
+ return -EINVAL;
}
- buf->used = elts.end;
- buf_priv->prim = elts.prim;
- buf_priv->discard = elts.discard;
+ buf->used = elts->end;
+ buf_priv->prim = elts->prim;
+ buf_priv->discard = elts->discard;
- r128_cce_dispatch_indices(dev, buf, elts.start, elts.end, count);
+ r128_cce_dispatch_indices(dev, buf, elts->start, elts->end, count);
COMMIT_RING();
return 0;
}
-static int r128_cce_blit(DRM_IOCTL_ARGS)
+static int r128_cce_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
struct drm_device_dma *dma = dev->dma;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_blit_t blit;
+ drm_r128_blit_t *blit = data;
int ret;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(blit, (drm_r128_blit_t __user *) data,
- sizeof(blit));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_DEBUG("pid=%d index=%d\n", DRM_CURRENTPID, blit.idx);
+ DRM_DEBUG("pid=%d index=%d\n", DRM_CURRENTPID, blit->idx);
- if (blit.idx < 0 || blit.idx >= dma->buf_count) {
+ if (blit->idx < 0 || blit->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- blit.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ blit->idx, dma->buf_count - 1);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- ret = r128_cce_dispatch_blit(filp, dev, &blit);
+ ret = r128_cce_dispatch_blit(dev, file_priv, blit);
COMMIT_RING();
return ret;
}
-static int r128_cce_depth(DRM_IOCTL_ARGS)
+static int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_depth_t depth;
+ drm_r128_depth_t *depth = data;
int ret;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(depth, (drm_r128_depth_t __user *) data,
- sizeof(depth));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
- ret = DRM_ERR(EINVAL);
- switch (depth.func) {
+ ret = -EINVAL;
+ switch (depth->func) {
case R128_WRITE_SPAN:
- ret = r128_cce_dispatch_write_span(dev, &depth);
+ ret = r128_cce_dispatch_write_span(dev, depth);
break;
case R128_WRITE_PIXELS:
- ret = r128_cce_dispatch_write_pixels(dev, &depth);
+ ret = r128_cce_dispatch_write_pixels(dev, depth);
break;
case R128_READ_SPAN:
- ret = r128_cce_dispatch_read_span(dev, &depth);
+ ret = r128_cce_dispatch_read_span(dev, depth);
break;
case R128_READ_PIXELS:
- ret = r128_cce_dispatch_read_pixels(dev, &depth);
+ ret = r128_cce_dispatch_read_pixels(dev, depth);
break;
}
@@ -1544,20 +1524,16 @@ static int r128_cce_depth(DRM_IOCTL_ARGS)
return ret;
}
-static int r128_cce_stipple(DRM_IOCTL_ARGS)
+static int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_stipple_t stipple;
+ drm_r128_stipple_t *stipple = data;
u32 mask[32];
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(stipple, (drm_r128_stipple_t __user *) data,
- sizeof(stipple));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof(u32)))
- return DRM_ERR(EFAULT);
+ if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32)))
+ return -EFAULT;
RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -1567,61 +1543,58 @@ static int r128_cce_stipple(DRM_IOCTL_ARGS)
return 0;
}
-static int r128_cce_indirect(DRM_IOCTL_ARGS)
+static int r128_cce_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
drm_r128_buf_priv_t *buf_priv;
- drm_r128_indirect_t indirect;
+ drm_r128_indirect_t *indirect = data;
#if 0
RING_LOCALS;
#endif
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(indirect, (drm_r128_indirect_t __user *) data,
- sizeof(indirect));
-
DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
- indirect.idx, indirect.start, indirect.end, indirect.discard);
+ indirect->idx, indirect->start, indirect->end,
+ indirect->discard);
- if (indirect.idx < 0 || indirect.idx >= dma->buf_count) {
+ if (indirect->idx < 0 || indirect->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- indirect.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ indirect->idx, dma->buf_count - 1);
+ return -EINVAL;
}
- buf = dma->buflist[indirect.idx];
+ buf = dma->buflist[indirect->idx];
buf_priv = buf->dev_private;
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", indirect.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", indirect->idx);
+ return -EINVAL;
}
- if (indirect.start < buf->used) {
+ if (indirect->start < buf->used) {
DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
- indirect.start, buf->used);
- return DRM_ERR(EINVAL);
+ indirect->start, buf->used);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf->used = indirect.end;
- buf_priv->discard = indirect.discard;
+ buf->used = indirect->end;
+ buf_priv->discard = indirect->discard;
#if 0
/* Wait for the 3D stream to idle before the indirect buffer
@@ -1636,46 +1609,42 @@ static int r128_cce_indirect(DRM_IOCTL_ARGS)
* X server. This is insecure and is thus only available to
* privileged clients.
*/
- r128_cce_dispatch_indirect(dev, buf, indirect.start, indirect.end);
+ r128_cce_dispatch_indirect(dev, buf, indirect->start, indirect->end);
COMMIT_RING();
return 0;
}
-static int r128_getparam(DRM_IOCTL_ARGS)
+static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_r128_getparam_t param;
+ drm_r128_getparam_t *param = data;
int value;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(param, (drm_r128_getparam_t __user *) data,
- sizeof(param));
-
DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
- switch (param.param) {
+ switch (param->param) {
case R128_PARAM_IRQ_NR:
value = dev->irq;
break;
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
+ if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
}
-void r128_driver_preclose(struct drm_device * dev, DRMFILE filp)
+void r128_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1690,24 +1659,24 @@ void r128_driver_lastclose(struct drm_device * dev)
r128_do_cleanup_cce(dev);
}
-drm_ioctl_desc_t r128_ioctls[] = {
- [DRM_IOCTL_NR(DRM_R128_INIT)] = {r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_R128_CCE_START)] = {r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_R128_CCE_STOP)] = {r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_R128_CCE_RESET)] = {r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_R128_CCE_IDLE)] = {r128_cce_idle, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_RESET)] = {r128_engine_reset, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_FULLSCREEN)] = {r128_fullscreen, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_SWAP)] = {r128_cce_swap, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_FLIP)] = {r128_cce_flip, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_CLEAR)] = {r128_cce_clear, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_VERTEX)] = {r128_cce_vertex, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_INDICES)] = {r128_cce_indices, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_BLIT)] = {r128_cce_blit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_DEPTH)] = {r128_cce_depth, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_STIPPLE)] = {r128_cce_stipple, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_R128_INDIRECT)] = {r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_R128_GETPARAM)] = {r128_getparam, DRM_AUTH},
+struct drm_ioctl_desc r128_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_R128_INIT, r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_R128_CCE_START, r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_R128_CCE_STOP, r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_R128_CCE_RESET, r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_R128_CCE_IDLE, r128_cce_idle, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_RESET, r128_engine_reset, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_FULLSCREEN, r128_fullscreen, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_SWAP, r128_cce_swap, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_FLIP, r128_cce_flip, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_CLEAR, r128_cce_clear, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_VERTEX, r128_cce_vertex, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_INDICES, r128_cce_indices, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_BLIT, r128_cce_blit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_DEPTH, r128_cce_depth, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_STIPPLE, r128_cce_stipple, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_R128_INDIRECT, r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_R128_GETPARAM, r128_getparam, DRM_AUTH),
};
int r128_max_ioctl = DRM_ARRAY_SIZE(r128_ioctls);
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c
index 4e5aca6ba59..59b2944811c 100644
--- a/drivers/char/drm/r300_cmdbuf.c
+++ b/drivers/char/drm/r300_cmdbuf.c
@@ -74,7 +74,7 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
if (DRM_COPY_FROM_USER_UNCHECKED
(&box, &cmdbuf->boxes[n + i], sizeof(box))) {
DRM_ERROR("copy cliprect faulted\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
box.x1 =
@@ -263,7 +263,7 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
DRM_ERROR
("Cannot emit more than 64 values at a time (reg=%04x sz=%d)\n",
reg, sz);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
for (i = 0; i < sz; i++) {
values[i] = ((int *)cmdbuf->buf)[i];
@@ -275,13 +275,13 @@ static __inline__ int r300_emit_carefully_checked_packet0(drm_radeon_private_t *
DRM_ERROR
("Offset failed range check (reg=%04x sz=%d)\n",
reg, sz);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
default:
DRM_ERROR("Register %04x failed check as flag=%02x\n",
reg + i * 4, r300_reg_flags[(reg >> 2) + i]);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -317,12 +317,12 @@ static __inline__ int r300_emit_packet0(drm_radeon_private_t *dev_priv,
return 0;
if (sz * 4 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
if (reg + sz * 4 >= 0x10000) {
DRM_ERROR("No such registers in hardware reg=%04x sz=%d\n", reg,
sz);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (r300_check_range(reg, sz)) {
@@ -362,7 +362,7 @@ static __inline__ int r300_emit_vpu(drm_radeon_private_t *dev_priv,
if (!sz)
return 0;
if (sz * 16 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
BEGIN_RING(5 + sz * 4);
/* Wait for VAP to come to senses.. */
@@ -391,7 +391,7 @@ static __inline__ int r300_emit_clear(drm_radeon_private_t *dev_priv,
RING_LOCALS;
if (8 * 4 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
BEGIN_RING(10);
OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 8));
@@ -421,7 +421,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
if ((count + 1) > MAX_ARRAY_PACKET) {
DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
count);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
memset(payload, 0, MAX_ARRAY_PACKET * 4);
memcpy(payload, cmdbuf->buf + 4, (count + 1) * 4);
@@ -437,7 +437,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
k++;
i++;
@@ -448,7 +448,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
DRM_ERROR
("Offset failed range check (k=%d i=%d) while processing 3D_LOAD_VBPNTR packet.\n",
k, i);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
k++;
i++;
@@ -458,7 +458,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv,
DRM_ERROR
("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
k, i, narrays, count + 1);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* all clear, output packet */
@@ -492,7 +492,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
ret = !radeon_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt first offset is %08X\n", offset);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -502,7 +502,7 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
ret = !radeon_check_offset(dev_priv, offset);
if (ret) {
DRM_ERROR("Invalid bitblt second offset is %08X\n", offset);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -530,12 +530,12 @@ static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
if ((cmd[1] & 0x8000ffff) != 0x80000810) {
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
ret = !radeon_check_offset(dev_priv, cmd[2]);
if (ret) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(count+2);
@@ -557,7 +557,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
RING_LOCALS;
if (4 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
/* Fixme !! This simply emits a packet without much checking.
We need to be smarter. */
@@ -568,7 +568,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
/* Is it packet 3 ? */
if ((header >> 30) != 0x3) {
DRM_ERROR("Not a packet3 header (0x%08x)\n", header);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
count = (header >> 16) & 0x3fff;
@@ -578,7 +578,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
DRM_ERROR
("Expected packet3 of length %d but have only %d bytes left\n",
(count + 2) * 4, cmdbuf->bufsz);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* Is it a packet type we know about ? */
@@ -600,7 +600,7 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
break;
default:
DRM_ERROR("Unknown packet3 header (0x%08x)\n", header);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(count + 2);
@@ -664,7 +664,7 @@ static __inline__ int r300_emit_packet3(drm_radeon_private_t *dev_priv,
DRM_ERROR("bad packet3 type %i at %p\n",
header.packet3.packet,
cmdbuf->buf - sizeof(header));
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
n += R300_SIMULTANEOUS_CLIPRECTS;
@@ -726,11 +726,11 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
if (cmdbuf->bufsz <
(sizeof(u64) + header.scratch.n_bufs * sizeof(buf_idx))) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (header.scratch.reg >= 5) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->scratch_ages[header.scratch.reg]++;
@@ -745,21 +745,21 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
buf_idx *= 2; /* 8 bytes per buf */
if (DRM_COPY_TO_USER(ref_age_base + buf_idx, &dev_priv->scratch_ages[header.scratch.reg], sizeof(u32))) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (DRM_COPY_FROM_USER(&h_pending, ref_age_base + buf_idx + 1, sizeof(u32))) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (h_pending == 0) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
h_pending--;
if (DRM_COPY_TO_USER(ref_age_base + buf_idx + 1, &h_pending, sizeof(u32))) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
cmdbuf->buf += sizeof(buf_idx);
@@ -780,8 +780,7 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
* Called by the ioctl handler function radeon_cp_cmdbuf.
*/
int r300_do_cp_cmdbuf(struct drm_device *dev,
- DRMFILE filp,
- struct drm_file *filp_priv,
+ struct drm_file *file_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -879,15 +878,16 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
if (idx < 0 || idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
idx, dma->buf_count - 1);
- ret = DRM_ERR(EINVAL);
+ ret = -EINVAL;
goto cleanup;
}
buf = dma->buflist[idx];
- if (buf->filp != filp || buf->pending) {
+ if (buf->file_priv != file_priv || buf->pending) {
DRM_ERROR("bad buffer %p %p %d\n",
- buf->filp, filp, buf->pending);
- ret = DRM_ERR(EINVAL);
+ buf->file_priv, file_priv,
+ buf->pending);
+ ret = -EINVAL;
goto cleanup;
}
@@ -924,7 +924,7 @@ int r300_do_cp_cmdbuf(struct drm_device *dev,
DRM_ERROR("bad cmd_type %i at %p\n",
header.header.cmd_type,
cmdbuf->buf - sizeof(header));
- ret = DRM_ERR(EINVAL);
+ ret = -EINVAL;
goto cleanup;
}
}
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index af5790f8fd5..24fca8ec137 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -889,7 +889,7 @@ static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv)
DRM_ERROR("failed!\n");
radeon_status(dev_priv);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries)
@@ -910,7 +910,7 @@ static int radeon_do_wait_for_fifo(drm_radeon_private_t * dev_priv, int entries)
DRM_ERROR("failed!\n");
radeon_status(dev_priv);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
@@ -936,7 +936,7 @@ static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
DRM_ERROR("failed!\n");
radeon_status(dev_priv);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
/* ================================================================
@@ -1394,7 +1394,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) {
DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) {
@@ -1409,7 +1409,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) {
DRM_ERROR("PCI GART memory not allocated!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->usec_timeout = init->usec_timeout;
@@ -1417,7 +1417,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT) {
DRM_DEBUG("TIMEOUT problem!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* Enable vblank on CRTC1 for older X servers
@@ -1446,7 +1446,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
(init->cp_mode != RADEON_CSQ_PRIBM_INDBM)) {
DRM_DEBUG("BAD cp_mode (%x)!\n", init->cp_mode);
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
switch (init->fb_bpp) {
@@ -1515,27 +1515,27 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
if (!dev_priv->sarea) {
DRM_ERROR("could not find sarea!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset);
if (!dev_priv->cp_ring) {
DRM_ERROR("could not find cp ring region!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset);
if (!dev_priv->ring_rptr) {
DRM_ERROR("could not find ring read pointer!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev->agp_buffer_token = init->buffers_offset;
dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
if (!dev->agp_buffer_map) {
DRM_ERROR("could not find dma buffer region!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (init->gart_textures_offset) {
@@ -1544,7 +1544,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
if (!dev_priv->gart_textures) {
DRM_ERROR("could not find GART texture region!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -1562,7 +1562,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
!dev->agp_buffer_map->handle) {
DRM_ERROR("could not find ioremap agp regions!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else
#endif
@@ -1679,7 +1679,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
dev_priv->gart_info.bus_addr =
dev_priv->pcigart_offset + dev_priv->fb_location;
dev_priv->gart_info.mapping.offset =
- dev_priv->gart_info.bus_addr;
+ dev_priv->pcigart_offset + dev_priv->fb_aper_offset;
dev_priv->gart_info.mapping.size =
dev_priv->gart_info.table_size;
@@ -1710,14 +1710,14 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
DRM_ERROR
("Cannot use PCI Express without GART in FB memory\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
DRM_ERROR("failed to init PCI GART!\n");
radeon_do_cleanup_cp(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
/* Turn on PCI GART */
@@ -1797,7 +1797,7 @@ static int radeon_do_resume_cp(struct drm_device * dev)
if (!dev_priv) {
DRM_ERROR("Called with no initialization\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
DRM_DEBUG("Starting radeon_do_resume_cp()\n");
@@ -1823,38 +1823,33 @@ static int radeon_do_resume_cp(struct drm_device * dev)
return 0;
}
-int radeon_cp_init(DRM_IOCTL_ARGS)
+int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_radeon_init_t init;
+ drm_radeon_init_t *init = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(init, (drm_radeon_init_t __user *) data,
- sizeof(init));
-
- if (init.func == RADEON_INIT_R300_CP)
+ if (init->func == RADEON_INIT_R300_CP)
r300_init_reg_flags();
- switch (init.func) {
+ switch (init->func) {
case RADEON_INIT_CP:
case RADEON_INIT_R200_CP:
case RADEON_INIT_R300_CP:
- return radeon_do_init_cp(dev, &init);
+ return radeon_do_init_cp(dev, init);
case RADEON_CLEANUP_CP:
return radeon_do_cleanup_cp(dev);
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
-int radeon_cp_start(DRM_IOCTL_ARGS)
+int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (dev_priv->cp_running) {
DRM_DEBUG("%s while CP running\n", __FUNCTION__);
@@ -1874,18 +1869,14 @@ int radeon_cp_start(DRM_IOCTL_ARGS)
/* Stop the CP. The engine must have been idled before calling this
* routine.
*/
-int radeon_cp_stop(DRM_IOCTL_ARGS)
+int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_cp_stop_t stop;
+ drm_radeon_cp_stop_t *stop = data;
int ret;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(stop, (drm_radeon_cp_stop_t __user *) data,
- sizeof(stop));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv->cp_running)
return 0;
@@ -1893,14 +1884,14 @@ int radeon_cp_stop(DRM_IOCTL_ARGS)
/* Flush any pending CP commands. This ensures any outstanding
* commands are exectuted by the engine before we turn it off.
*/
- if (stop.flush) {
+ if (stop->flush) {
radeon_do_cp_flush(dev_priv);
}
/* If we fail to make the engine go idle, we return an error
* code so that the DRM ioctl wrapper can try again.
*/
- if (stop.idle) {
+ if (stop->idle) {
ret = radeon_do_cp_idle(dev_priv);
if (ret)
return ret;
@@ -1963,17 +1954,16 @@ void radeon_do_release(struct drm_device * dev)
/* Just reset the CP ring. Called as part of an X Server engine reset.
*/
-int radeon_cp_reset(DRM_IOCTL_ARGS)
+int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_DEBUG("%s called before init done\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
radeon_do_cp_reset(dev_priv);
@@ -1984,32 +1974,29 @@ int radeon_cp_reset(DRM_IOCTL_ARGS)
return 0;
}
-int radeon_cp_idle(DRM_IOCTL_ARGS)
+int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return radeon_do_cp_idle(dev_priv);
}
/* Added by Charl P. Botha to call radeon_do_resume_cp().
*/
-int radeon_cp_resume(DRM_IOCTL_ARGS)
+int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
return radeon_do_resume_cp(dev);
}
-int radeon_engine_reset(DRM_IOCTL_ARGS)
+int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return radeon_do_engine_reset(dev);
}
@@ -2020,7 +2007,7 @@ int radeon_engine_reset(DRM_IOCTL_ARGS)
/* KW: Deprecated to say the least:
*/
-int radeon_fullscreen(DRM_IOCTL_ARGS)
+int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
return 0;
}
@@ -2066,8 +2053,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
for (i = start; i < dma->buf_count; i++) {
buf = dma->buflist[i];
buf_priv = buf->dev_private;
- if (buf->filp == 0 || (buf->pending &&
- buf_priv->age <= done_age)) {
+ if (buf->file_priv == NULL || (buf->pending &&
+ buf_priv->age <=
+ done_age)) {
dev_priv->stats.requested_bufs++;
buf->pending = 0;
return buf;
@@ -2106,8 +2094,9 @@ struct drm_buf *radeon_freelist_get(struct drm_device * dev)
for (i = start; i < dma->buf_count; i++) {
buf = dma->buflist[i];
buf_priv = buf->dev_private;
- if (buf->filp == 0 || (buf->pending &&
- buf_priv->age <= done_age)) {
+ if (buf->file_priv == 0 || (buf->pending &&
+ buf_priv->age <=
+ done_age)) {
dev_priv->stats.requested_bufs++;
buf->pending = 0;
return buf;
@@ -2167,10 +2156,11 @@ int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n)
radeon_status(dev_priv);
DRM_ERROR("failed!\n");
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
-static int radeon_cp_get_buffers(DRMFILE filp, struct drm_device * dev,
+static int radeon_cp_get_buffers(struct drm_device *dev,
+ struct drm_file *file_priv,
struct drm_dma * d)
{
int i;
@@ -2179,58 +2169,52 @@ static int radeon_cp_get_buffers(DRMFILE filp, struct drm_device * dev,
for (i = d->granted_count; i < d->request_count; i++) {
buf = radeon_freelist_get(dev);
if (!buf)
- return DRM_ERR(EBUSY); /* NOTE: broken client */
+ return -EBUSY; /* NOTE: broken client */
- buf->filp = filp;
+ buf->file_priv = file_priv;
if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
sizeof(buf->idx)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
sizeof(buf->total)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
d->granted_count++;
}
return 0;
}
-int radeon_cp_buffers(DRM_IOCTL_ARGS)
+int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
struct drm_device_dma *dma = dev->dma;
int ret = 0;
- struct drm_dma __user *argp = (void __user *)data;
- struct drm_dma d;
+ struct drm_dma *d = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* Please don't send us buffers.
*/
- if (d.send_count != 0) {
+ if (d->send_count != 0) {
DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
- DRM_CURRENTPID, d.send_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->send_count);
+ return -EINVAL;
}
/* We'll send you buffers.
*/
- if (d.request_count < 0 || d.request_count > dma->buf_count) {
+ if (d->request_count < 0 || d->request_count > dma->buf_count) {
DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
- DRM_CURRENTPID, d.request_count, dma->buf_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->request_count, dma->buf_count);
+ return -EINVAL;
}
- d.granted_count = 0;
+ d->granted_count = 0;
- if (d.request_count) {
- ret = radeon_cp_get_buffers(filp, dev, &d);
+ if (d->request_count) {
+ ret = radeon_cp_get_buffers(dev, file_priv, d);
}
- DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d));
-
return ret;
}
@@ -2241,7 +2225,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
dev_priv = drm_alloc(sizeof(drm_radeon_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
memset(dev_priv, 0, sizeof(drm_radeon_private_t));
dev->dev_private = (void *)dev_priv;
@@ -2291,7 +2275,8 @@ int radeon_driver_firstopen(struct drm_device *dev)
if (ret != 0)
return ret;
- ret = drm_addmap(dev, drm_get_resource_start(dev, 0),
+ dev_priv->fb_aper_offset = drm_get_resource_start(dev, 0);
+ ret = drm_addmap(dev, dev_priv->fb_aper_offset,
drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER,
_DRM_WRITE_COMBINING, &map);
if (ret != 0)
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 3b3d9357201..bfbb60a9298 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -188,7 +188,7 @@ struct mem_block {
struct mem_block *prev;
int start;
int size;
- DRMFILE filp; /* 0: free, -1: heap, other: real files */
+ struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
};
struct radeon_surface {
@@ -203,7 +203,7 @@ struct radeon_virt_surface {
u32 lower;
u32 upper;
u32 flags;
- DRMFILE filp;
+ struct drm_file *file_priv;
};
typedef struct drm_radeon_private {
@@ -293,6 +293,7 @@ typedef struct drm_radeon_private {
/* starting from here on, data is preserved accross an open */
uint32_t flags; /* see radeon_chip_flags */
+ unsigned long fb_aper_offset;
} drm_radeon_private_t;
typedef struct drm_radeon_buf_priv {
@@ -307,7 +308,7 @@ typedef struct drm_radeon_kcmd_buffer {
} drm_radeon_kcmd_buffer_t;
extern int radeon_no_wb;
-extern drm_ioctl_desc_t radeon_ioctls[];
+extern struct drm_ioctl_desc radeon_ioctls[];
extern int radeon_max_ioctl;
/* Check whether the given hardware address is inside the framebuffer or the
@@ -326,15 +327,15 @@ static __inline__ int radeon_check_offset(drm_radeon_private_t *dev_priv,
}
/* radeon_cp.c */
-extern int radeon_cp_init(DRM_IOCTL_ARGS);
-extern int radeon_cp_start(DRM_IOCTL_ARGS);
-extern int radeon_cp_stop(DRM_IOCTL_ARGS);
-extern int radeon_cp_reset(DRM_IOCTL_ARGS);
-extern int radeon_cp_idle(DRM_IOCTL_ARGS);
-extern int radeon_cp_resume(DRM_IOCTL_ARGS);
-extern int radeon_engine_reset(DRM_IOCTL_ARGS);
-extern int radeon_fullscreen(DRM_IOCTL_ARGS);
-extern int radeon_cp_buffers(DRM_IOCTL_ARGS);
+extern int radeon_cp_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_start(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_stop(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern void radeon_freelist_reset(struct drm_device * dev);
extern struct drm_buf *radeon_freelist_get(struct drm_device * dev);
@@ -347,15 +348,16 @@ extern int radeon_driver_preinit(struct drm_device *dev, unsigned long flags);
extern int radeon_presetup(struct drm_device *dev);
extern int radeon_driver_postcleanup(struct drm_device *dev);
-extern int radeon_mem_alloc(DRM_IOCTL_ARGS);
-extern int radeon_mem_free(DRM_IOCTL_ARGS);
-extern int radeon_mem_init_heap(DRM_IOCTL_ARGS);
+extern int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern void radeon_mem_takedown(struct mem_block **heap);
-extern void radeon_mem_release(DRMFILE filp, struct mem_block *heap);
+extern void radeon_mem_release(struct drm_file *file_priv,
+ struct mem_block *heap);
/* radeon_irq.c */
-extern int radeon_irq_emit(DRM_IOCTL_ARGS);
-extern int radeon_irq_wait(DRM_IOCTL_ARGS);
+extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern void radeon_do_release(struct drm_device * dev);
extern int radeon_driver_vblank_wait(struct drm_device * dev,
@@ -372,7 +374,7 @@ extern int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value);
extern int radeon_driver_load(struct drm_device *dev, unsigned long flags);
extern int radeon_driver_unload(struct drm_device *dev);
extern int radeon_driver_firstopen(struct drm_device *dev);
-extern void radeon_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void radeon_driver_preclose(struct drm_device * dev, struct drm_file *file_priv);
extern void radeon_driver_postclose(struct drm_device * dev, struct drm_file * filp);
extern void radeon_driver_lastclose(struct drm_device * dev);
extern int radeon_driver_open(struct drm_device * dev, struct drm_file * filp_priv);
@@ -382,8 +384,8 @@ extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
/* r300_cmdbuf.c */
extern void r300_init_reg_flags(void);
-extern int r300_do_cp_cmdbuf(struct drm_device * dev, DRMFILE filp,
- struct drm_file * filp_priv,
+extern int r300_do_cp_cmdbuf(struct drm_device * dev,
+ struct drm_file *file_priv,
drm_radeon_kcmd_buffer_t * cmdbuf);
/* Flags for stats.boxes
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c
index ad8a0ac7182..84f5bc36252 100644
--- a/drivers/char/drm/radeon_irq.c
+++ b/drivers/char/drm/radeon_irq.c
@@ -27,7 +27,7 @@
*
* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
- * Michel D�zer <michel@daenzer.net>
+ * Michel Dänzer <michel@daenzer.net>
*/
#include "drmP.h"
@@ -144,8 +144,8 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr)
return ret;
}
-int radeon_driver_vblank_do_wait(struct drm_device * dev, unsigned int *sequence,
- int crtc)
+static int radeon_driver_vblank_do_wait(struct drm_device * dev,
+ unsigned int *sequence, int crtc)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
@@ -155,7 +155,7 @@ int radeon_driver_vblank_do_wait(struct drm_device * dev, unsigned int *sequence
atomic_t *counter;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (crtc == DRM_RADEON_VBLANK_CRTC1) {
@@ -165,7 +165,7 @@ int radeon_driver_vblank_do_wait(struct drm_device * dev, unsigned int *sequence
counter = &dev->vbl_received2;
ack |= RADEON_CRTC2_VBLANK_STAT;
} else
- return DRM_ERR(EINVAL);
+ return -EINVAL;
radeon_acknowledge_irqs(dev_priv, ack);
@@ -196,28 +196,24 @@ int radeon_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
/* Needs the lock as it touches the ring.
*/
-int radeon_irq_emit(DRM_IOCTL_ARGS)
+int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_irq_emit_t emit;
+ drm_radeon_irq_emit_t *emit = data;
int result;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(emit, (drm_radeon_irq_emit_t __user *) data,
- sizeof(emit));
-
result = radeon_emit_irq(dev);
- if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) {
+ if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
@@ -225,21 +221,17 @@ int radeon_irq_emit(DRM_IOCTL_ARGS)
/* Doesn't need the hardware lock.
*/
-int radeon_irq_wait(DRM_IOCTL_ARGS)
+int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_irq_wait_t irqwait;
+ drm_radeon_irq_wait_t *irqwait = data;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_radeon_irq_wait_t __user *) data,
- sizeof(irqwait));
-
- return radeon_wait_irq(dev, irqwait.irq_seq);
+ return radeon_wait_irq(dev, irqwait->irq_seq);
}
static void radeon_enable_interrupt(struct drm_device *dev)
@@ -320,7 +312,7 @@ int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
if (value & ~(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
DRM_ERROR("called with invalid crtc 0x%x\n", (unsigned int)value);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->vblank_crtc = (unsigned int)value;
radeon_enable_interrupt(dev);
diff --git a/drivers/char/drm/radeon_mem.c b/drivers/char/drm/radeon_mem.c
index 517cad8b6e3..a29acfe2f97 100644
--- a/drivers/char/drm/radeon_mem.c
+++ b/drivers/char/drm/radeon_mem.c
@@ -39,7 +39,7 @@
*/
static struct mem_block *split_block(struct mem_block *p, int start, int size,
- DRMFILE filp)
+ struct drm_file *file_priv)
{
/* Maybe cut off the start of an existing block */
if (start > p->start) {
@@ -49,7 +49,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
goto out;
newblock->start = start;
newblock->size = p->size - (start - p->start);
- newblock->filp = NULL;
+ newblock->file_priv = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
@@ -66,7 +66,7 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
goto out;
newblock->start = start + size;
newblock->size = p->size - size;
- newblock->filp = NULL;
+ newblock->file_priv = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
@@ -76,20 +76,20 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size,
out:
/* Our block is in the middle */
- p->filp = filp;
+ p->file_priv = file_priv;
return p;
}
static struct mem_block *alloc_block(struct mem_block *heap, int size,
- int align2, DRMFILE filp)
+ int align2, struct drm_file *file_priv)
{
struct mem_block *p;
int mask = (1 << align2) - 1;
list_for_each(p, heap) {
int start = (p->start + mask) & ~mask;
- if (p->filp == 0 && start + size <= p->start + p->size)
- return split_block(p, start, size, filp);
+ if (p->file_priv == 0 && start + size <= p->start + p->size)
+ return split_block(p, start, size, file_priv);
}
return NULL;
@@ -108,12 +108,12 @@ static struct mem_block *find_block(struct mem_block *heap, int start)
static void free_block(struct mem_block *p)
{
- p->filp = NULL;
+ p->file_priv = NULL;
- /* Assumes a single contiguous range. Needs a special filp in
+ /* Assumes a single contiguous range. Needs a special file_priv in
* 'heap' to stop it being subsumed.
*/
- if (p->next->filp == 0) {
+ if (p->next->file_priv == 0) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
@@ -121,7 +121,7 @@ static void free_block(struct mem_block *p)
drm_free(q, sizeof(*q), DRM_MEM_BUFS);
}
- if (p->prev->filp == 0) {
+ if (p->prev->file_priv == 0) {
struct mem_block *q = p->prev;
q->size += p->size;
q->next = p->next;
@@ -137,28 +137,28 @@ static int init_heap(struct mem_block **heap, int start, int size)
struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS);
if (!blocks)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
*heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFS);
if (!*heap) {
drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFS);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
blocks->start = start;
blocks->size = size;
- blocks->filp = NULL;
+ blocks->file_priv = NULL;
blocks->next = blocks->prev = *heap;
memset(*heap, 0, sizeof(**heap));
- (*heap)->filp = (DRMFILE) - 1;
+ (*heap)->file_priv = (struct drm_file *) - 1;
(*heap)->next = (*heap)->prev = blocks;
return 0;
}
/* Free all blocks associated with the releasing file.
*/
-void radeon_mem_release(DRMFILE filp, struct mem_block *heap)
+void radeon_mem_release(struct drm_file *file_priv, struct mem_block *heap)
{
struct mem_block *p;
@@ -166,15 +166,15 @@ void radeon_mem_release(DRMFILE filp, struct mem_block *heap)
return;
list_for_each(p, heap) {
- if (p->filp == filp)
- p->filp = NULL;
+ if (p->file_priv == file_priv)
+ p->file_priv = NULL;
}
- /* Assumes a single contiguous range. Needs a special filp in
+ /* Assumes a single contiguous range. Needs a special file_priv in
* 'heap' to stop it being subsumed.
*/
list_for_each(p, heap) {
- while (p->filp == 0 && p->next->filp == 0) {
+ while (p->file_priv == 0 && p->next->file_priv == 0) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
@@ -217,98 +217,86 @@ static struct mem_block **get_heap(drm_radeon_private_t * dev_priv, int region)
}
}
-int radeon_mem_alloc(DRM_IOCTL_ARGS)
+int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_mem_alloc_t alloc;
+ drm_radeon_mem_alloc_t *alloc = data;
struct mem_block *block, **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(alloc, (drm_radeon_mem_alloc_t __user *) data,
- sizeof(alloc));
-
- heap = get_heap(dev_priv, alloc.region);
+ heap = get_heap(dev_priv, alloc->region);
if (!heap || !*heap)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
/* Make things easier on ourselves: all allocations at least
* 4k aligned.
*/
- if (alloc.alignment < 12)
- alloc.alignment = 12;
+ if (alloc->alignment < 12)
+ alloc->alignment = 12;
- block = alloc_block(*heap, alloc.size, alloc.alignment, filp);
+ block = alloc_block(*heap, alloc->size, alloc->alignment, file_priv);
if (!block)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
- if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) {
+ if (DRM_COPY_TO_USER(alloc->region_offset, &block->start,
+ sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
}
-int radeon_mem_free(DRM_IOCTL_ARGS)
+int radeon_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_mem_free_t memfree;
+ drm_radeon_mem_free_t *memfree = data;
struct mem_block *block, **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_mem_free_t __user *) data,
- sizeof(memfree));
-
- heap = get_heap(dev_priv, memfree.region);
+ heap = get_heap(dev_priv, memfree->region);
if (!heap || !*heap)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- block = find_block(*heap, memfree.region_offset);
+ block = find_block(*heap, memfree->region_offset);
if (!block)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- if (block->filp != filp)
- return DRM_ERR(EPERM);
+ if (block->file_priv != file_priv)
+ return -EPERM;
free_block(block);
return 0;
}
-int radeon_mem_init_heap(DRM_IOCTL_ARGS)
+int radeon_mem_init_heap(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_mem_init_heap_t initheap;
+ drm_radeon_mem_init_heap_t *initheap = data;
struct mem_block **heap;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- DRM_COPY_FROM_USER_IOCTL(initheap,
- (drm_radeon_mem_init_heap_t __user *) data,
- sizeof(initheap));
-
- heap = get_heap(dev_priv, initheap.region);
+ heap = get_heap(dev_priv, initheap->region);
if (!heap)
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if (*heap) {
DRM_ERROR("heap already initialized?");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
- return init_heap(heap, initheap.start, initheap.size);
+ return init_heap(heap, initheap->start, initheap->size);
}
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index 3ddf86f2abf..f824f2f5fdc 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -39,7 +39,7 @@
static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
dev_priv,
- struct drm_file * filp_priv,
+ struct drm_file * file_priv,
u32 *offset)
{
u64 off = *offset;
@@ -71,7 +71,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
* magic offset we get from SETPARAM or calculated from fb_location
*/
if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
- radeon_priv = filp_priv->driver_priv;
+ radeon_priv = file_priv->driver_priv;
off += radeon_priv->radeon_fb_delta;
}
@@ -85,29 +85,29 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
*offset = off;
return 0;
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
dev_priv,
- struct drm_file * filp_priv,
+ struct drm_file *file_priv,
int id, u32 *data)
{
switch (id) {
case RADEON_EMIT_PP_MISC:
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) {
DRM_ERROR("Invalid depth buffer offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case RADEON_EMIT_PP_CNTL:
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) {
DRM_ERROR("Invalid colour buffer offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
@@ -117,20 +117,20 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
case R200_EMIT_PP_TXOFFSET_3:
case R200_EMIT_PP_TXOFFSET_4:
case R200_EMIT_PP_TXOFFSET_5:
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&data[0])) {
DRM_ERROR("Invalid R200 texture offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case RADEON_EMIT_PP_TXFILTER_0:
case RADEON_EMIT_PP_TXFILTER_1:
case RADEON_EMIT_PP_TXFILTER_2:
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) {
DRM_ERROR("Invalid R100 texture offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
@@ -143,11 +143,11 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
int i;
for (i = 0; i < 5; i++) {
if (radeon_check_and_fixup_offset(dev_priv,
- filp_priv,
+ file_priv,
&data[i])) {
DRM_ERROR
("Invalid R200 cubic texture offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
break;
@@ -159,11 +159,11 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
int i;
for (i = 0; i < 5; i++) {
if (radeon_check_and_fixup_offset(dev_priv,
- filp_priv,
+ file_priv,
&data[i])) {
DRM_ERROR
("Invalid R100 cubic texture offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
}
@@ -256,7 +256,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
default:
DRM_ERROR("Unknown state packet ID %d\n", id);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
@@ -264,7 +264,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
dev_priv,
- struct drm_file *filp_priv,
+ struct drm_file *file_priv,
drm_radeon_kcmd_buffer_t *
cmdbuf,
unsigned int *cmdsz)
@@ -277,12 +277,12 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) {
DRM_ERROR("Not a type 3 packet\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (4 * *cmdsz > cmdbuf->bufsz) {
DRM_ERROR("Packet size larger than size of data provided\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
switch(cmd[0] & 0xff00) {
@@ -307,7 +307,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
/* safe but r200 only */
if (dev_priv->microcode_version != UCODE_R200) {
DRM_ERROR("Invalid 3d packet for r100-class chip\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
@@ -317,7 +317,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
if (count > 18) { /* 12 arrays max */
DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
count);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* carefully check packet contents */
@@ -326,22 +326,25 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
i = 2;
while ((k < narrays) && (i < (count + 2))) {
i++; /* skip attribute field */
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
+ &cmd[i])) {
DRM_ERROR
("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
k, i);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
k++;
i++;
if (k == narrays)
break;
/* have one more to process, they come in pairs */
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
+ if (radeon_check_and_fixup_offset(dev_priv,
+ file_priv, &cmd[i]))
+ {
DRM_ERROR
("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
k, i);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
k++;
i++;
@@ -351,33 +354,33 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
DRM_ERROR
("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
k, i, narrays, count + 1);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case RADEON_3D_RNDR_GEN_INDX_PRIM:
if (dev_priv->microcode_version != UCODE_R100) {
DRM_ERROR("Invalid 3d packet for r200-class chip\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[1])) {
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[1])) {
DRM_ERROR("Invalid rndr_gen_indx offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case RADEON_CP_INDX_BUFFER:
if (dev_priv->microcode_version != UCODE_R200) {
DRM_ERROR("Invalid 3d packet for r100-class chip\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if ((cmd[1] & 0x8000ffff) != 0x80000810) {
DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[2])) {
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[2])) {
DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
@@ -389,9 +392,9 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
| RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[2] << 10;
if (radeon_check_and_fixup_offset
- (dev_priv, filp_priv, &offset)) {
+ (dev_priv, file_priv, &offset)) {
DRM_ERROR("Invalid first packet offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10;
}
@@ -400,9 +403,9 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
(cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
offset = cmd[3] << 10;
if (radeon_check_and_fixup_offset
- (dev_priv, filp_priv, &offset)) {
+ (dev_priv, file_priv, &offset)) {
DRM_ERROR("Invalid second packet offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
}
@@ -410,7 +413,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
default:
DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
@@ -439,7 +442,7 @@ static __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,
/* Emit 1.1 state
*/
static int radeon_emit_state(drm_radeon_private_t * dev_priv,
- struct drm_file * filp_priv,
+ struct drm_file *file_priv,
drm_radeon_context_regs_t * ctx,
drm_radeon_texture_regs_t * tex,
unsigned int dirty)
@@ -448,16 +451,16 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
DRM_DEBUG("dirty=0x%08x\n", dirty);
if (dirty & RADEON_UPLOAD_CONTEXT) {
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&ctx->rb3d_depthoffset)) {
DRM_ERROR("Invalid depth buffer offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&ctx->rb3d_coloroffset)) {
DRM_ERROR("Invalid depth buffer offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(14);
@@ -543,10 +546,10 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
}
if (dirty & RADEON_UPLOAD_TEX0) {
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&tex[0].pp_txoffset)) {
DRM_ERROR("Invalid texture offset for unit 0\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(9);
@@ -563,10 +566,10 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
}
if (dirty & RADEON_UPLOAD_TEX1) {
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&tex[1].pp_txoffset)) {
DRM_ERROR("Invalid texture offset for unit 1\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(9);
@@ -583,10 +586,10 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
}
if (dirty & RADEON_UPLOAD_TEX2) {
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv,
&tex[2].pp_txoffset)) {
DRM_ERROR("Invalid texture offset for unit 2\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(9);
@@ -608,7 +611,7 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
/* Emit 1.2 state
*/
static int radeon_emit_state2(drm_radeon_private_t * dev_priv,
- struct drm_file * filp_priv,
+ struct drm_file *file_priv,
drm_radeon_state_t * state)
{
RING_LOCALS;
@@ -621,7 +624,7 @@ static int radeon_emit_state2(drm_radeon_private_t * dev_priv,
ADVANCE_RING();
}
- return radeon_emit_state(dev_priv, filp_priv, &state->context,
+ return radeon_emit_state(dev_priv, file_priv, &state->context,
state->tex, state->dirty);
}
@@ -1646,13 +1649,12 @@ static void radeon_cp_dispatch_indices(struct drm_device * dev,
#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
-static int radeon_cp_dispatch_texture(DRMFILE filp,
- struct drm_device * dev,
+static int radeon_cp_dispatch_texture(struct drm_device * dev,
+ struct drm_file *file_priv,
drm_radeon_texture_t * tex,
drm_radeon_tex_image_t * image)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_file *filp_priv;
struct drm_buf *buf;
u32 format;
u32 *buffer;
@@ -1664,11 +1666,9 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
u32 offset;
RING_LOCALS;
- DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
- if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &tex->offset)) {
+ if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex->offset)) {
DRM_ERROR("Invalid destination offset\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
@@ -1711,11 +1711,11 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
break;
default:
DRM_ERROR("invalid texture format %d\n", tex->format);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
spitch = blit_width >> 6;
if (spitch == 0 && image->height > 1)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
texpitch = tex->pitch;
if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
@@ -1760,8 +1760,8 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
if (!buf) {
DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n");
if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
- return DRM_ERR(EFAULT);
- return DRM_ERR(EAGAIN);
+ return -EFAULT;
+ return -EAGAIN;
}
/* Dispatch the indirect buffer.
@@ -1774,7 +1774,7 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
do { \
if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\
DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \
- return DRM_ERR(EFAULT); \
+ return -EFAULT; \
} \
} while(0)
@@ -1841,7 +1841,7 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
}
#undef RADEON_COPY_MT
- buf->filp = filp;
+ buf->file_priv = file_priv;
buf->used = size;
offset = dev_priv->gart_buffers_offset + buf->offset;
BEGIN_RING(9);
@@ -1861,6 +1861,7 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
OUT_RING((image->width << 16) | height);
RADEON_WAIT_UNTIL_2D_IDLE();
ADVANCE_RING();
+ COMMIT_RING();
radeon_cp_discard_buffer(dev, buf);
@@ -1878,6 +1879,8 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
RADEON_FLUSH_CACHE();
RADEON_WAIT_UNTIL_2D_IDLE();
ADVANCE_RING();
+ COMMIT_RING();
+
return 0;
}
@@ -1929,7 +1932,8 @@ static void radeon_apply_surface_regs(int surf_index,
* not always be available.
*/
static int alloc_surface(drm_radeon_surface_alloc_t *new,
- drm_radeon_private_t *dev_priv, DRMFILE filp)
+ drm_radeon_private_t *dev_priv,
+ struct drm_file *file_priv)
{
struct radeon_virt_surface *s;
int i;
@@ -1959,7 +1963,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
/* find a virtual surface */
for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
- if (dev_priv->virt_surfaces[i].filp == 0)
+ if (dev_priv->virt_surfaces[i].file_priv == 0)
break;
if (i == 2 * RADEON_MAX_SURFACES) {
return -1;
@@ -1977,7 +1981,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
s->lower = new_lower;
s->upper = new_upper;
s->flags = new->flags;
- s->filp = filp;
+ s->file_priv = file_priv;
dev_priv->surfaces[i].refcount++;
dev_priv->surfaces[i].lower = s->lower;
radeon_apply_surface_regs(s->surface_index, dev_priv);
@@ -1993,7 +1997,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
s->lower = new_lower;
s->upper = new_upper;
s->flags = new->flags;
- s->filp = filp;
+ s->file_priv = file_priv;
dev_priv->surfaces[i].refcount++;
dev_priv->surfaces[i].upper = s->upper;
radeon_apply_surface_regs(s->surface_index, dev_priv);
@@ -2009,7 +2013,7 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
s->lower = new_lower;
s->upper = new_upper;
s->flags = new->flags;
- s->filp = filp;
+ s->file_priv = file_priv;
dev_priv->surfaces[i].refcount = 1;
dev_priv->surfaces[i].lower = s->lower;
dev_priv->surfaces[i].upper = s->upper;
@@ -2023,7 +2027,8 @@ static int alloc_surface(drm_radeon_surface_alloc_t *new,
return -1;
}
-static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
+static int free_surface(struct drm_file *file_priv,
+ drm_radeon_private_t * dev_priv,
int lower)
{
struct radeon_virt_surface *s;
@@ -2031,8 +2036,9 @@ static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
/* find the virtual surface */
for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
s = &(dev_priv->virt_surfaces[i]);
- if (s->filp) {
- if ((lower == s->lower) && (filp == s->filp)) {
+ if (s->file_priv) {
+ if ((lower == s->lower) && (file_priv == s->file_priv))
+ {
if (dev_priv->surfaces[s->surface_index].
lower == s->lower)
dev_priv->surfaces[s->surface_index].
@@ -2048,7 +2054,7 @@ static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
refcount == 0)
dev_priv->surfaces[s->surface_index].
flags = 0;
- s->filp = NULL;
+ s->file_priv = NULL;
radeon_apply_surface_regs(s->surface_index,
dev_priv);
return 0;
@@ -2058,13 +2064,13 @@ static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
return 1;
}
-static void radeon_surfaces_release(DRMFILE filp,
+static void radeon_surfaces_release(struct drm_file *file_priv,
drm_radeon_private_t * dev_priv)
{
int i;
for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
- if (dev_priv->virt_surfaces[i].filp == filp)
- free_surface(filp, dev_priv,
+ if (dev_priv->virt_surfaces[i].file_priv == file_priv)
+ free_surface(file_priv, dev_priv,
dev_priv->virt_surfaces[i].lower);
}
}
@@ -2072,61 +2078,48 @@ static void radeon_surfaces_release(DRMFILE filp,
/* ================================================================
* IOCTL functions
*/
-static int radeon_surface_alloc(DRM_IOCTL_ARGS)
+static int radeon_surface_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_surface_alloc_t alloc;
+ drm_radeon_surface_alloc_t *alloc = data;
- DRM_COPY_FROM_USER_IOCTL(alloc,
- (drm_radeon_surface_alloc_t __user *) data,
- sizeof(alloc));
-
- if (alloc_surface(&alloc, dev_priv, filp) == -1)
- return DRM_ERR(EINVAL);
+ if (alloc_surface(alloc, dev_priv, file_priv) == -1)
+ return -EINVAL;
else
return 0;
}
-static int radeon_surface_free(DRM_IOCTL_ARGS)
+static int radeon_surface_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_surface_free_t memfree;
-
- DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_surface_free_t __user *) data,
- sizeof(memfree));
+ drm_radeon_surface_free_t *memfree = data;
- if (free_surface(filp, dev_priv, memfree.address))
- return DRM_ERR(EINVAL);
+ if (free_surface(file_priv, dev_priv, memfree->address))
+ return -EINVAL;
else
return 0;
}
-static int radeon_cp_clear(DRM_IOCTL_ARGS)
+static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_radeon_clear_t clear;
+ drm_radeon_clear_t *clear = data;
drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(clear, (drm_radeon_clear_t __user *) data,
- sizeof(clear));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
- if (DRM_COPY_FROM_USER(&depth_boxes, clear.depth_boxes,
+ if (DRM_COPY_FROM_USER(&depth_boxes, clear->depth_boxes,
sarea_priv->nbox * sizeof(depth_boxes[0])))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- radeon_cp_dispatch_clear(dev, &clear, depth_boxes);
+ radeon_cp_dispatch_clear(dev, clear, depth_boxes);
COMMIT_RING();
return 0;
@@ -2162,13 +2155,12 @@ static int radeon_do_init_pageflip(struct drm_device * dev)
/* Swapping and flipping are different operations, need different ioctls.
* They can & should be intermixed to support multiple 3d windows.
*/
-static int radeon_cp_flip(DRM_IOCTL_ARGS)
+static int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -2181,14 +2173,13 @@ static int radeon_cp_flip(DRM_IOCTL_ARGS)
return 0;
}
-static int radeon_cp_swap(DRM_IOCTL_ARGS)
+static int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -2202,64 +2193,57 @@ static int radeon_cp_swap(DRM_IOCTL_ARGS)
return 0;
}
-static int radeon_cp_vertex(DRM_IOCTL_ARGS)
+static int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_file *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
- drm_radeon_vertex_t vertex;
+ drm_radeon_vertex_t *vertex = data;
drm_radeon_tcl_prim_t prim;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
- DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data,
- sizeof(vertex));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
- DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard);
+ DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard);
- if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
+ if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- vertex.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ vertex->idx, dma->buf_count - 1);
+ return -EINVAL;
}
- if (vertex.prim < 0 || vertex.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
- DRM_ERROR("buffer prim %d\n", vertex.prim);
- return DRM_ERR(EINVAL);
+ if (vertex->prim < 0 || vertex->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
+ DRM_ERROR("buffer prim %d\n", vertex->prim);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf = dma->buflist[vertex.idx];
+ buf = dma->buflist[vertex->idx];
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", vertex.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", vertex->idx);
+ return -EINVAL;
}
/* Build up a prim_t record:
*/
- if (vertex.count) {
- buf->used = vertex.count; /* not used? */
+ if (vertex->count) {
+ buf->used = vertex->count; /* not used? */
if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
- if (radeon_emit_state(dev_priv, filp_priv,
+ if (radeon_emit_state(dev_priv, file_priv,
&sarea_priv->context_state,
sarea_priv->tex_state,
sarea_priv->dirty)) {
DRM_ERROR("radeon_emit_state failed\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
@@ -2269,15 +2253,15 @@ static int radeon_cp_vertex(DRM_IOCTL_ARGS)
}
prim.start = 0;
- prim.finish = vertex.count; /* unused */
- prim.prim = vertex.prim;
- prim.numverts = vertex.count;
+ prim.finish = vertex->count; /* unused */
+ prim.prim = vertex->prim;
+ prim.numverts = vertex->count;
prim.vc_format = dev_priv->sarea_priv->vc_format;
radeon_cp_dispatch_vertex(dev, buf, &prim);
}
- if (vertex.discard) {
+ if (vertex->discard) {
radeon_cp_discard_buffer(dev, buf);
}
@@ -2285,74 +2269,68 @@ static int radeon_cp_vertex(DRM_IOCTL_ARGS)
return 0;
}
-static int radeon_cp_indices(DRM_IOCTL_ARGS)
+static int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_file *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
- drm_radeon_indices_t elts;
+ drm_radeon_indices_t *elts = data;
drm_radeon_tcl_prim_t prim;
int count;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
- DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data,
- sizeof(elts));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
- DRM_CURRENTPID, elts.idx, elts.start, elts.end, elts.discard);
+ DRM_CURRENTPID, elts->idx, elts->start, elts->end,
+ elts->discard);
- if (elts.idx < 0 || elts.idx >= dma->buf_count) {
+ if (elts->idx < 0 || elts->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- elts.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ elts->idx, dma->buf_count - 1);
+ return -EINVAL;
}
- if (elts.prim < 0 || elts.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
- DRM_ERROR("buffer prim %d\n", elts.prim);
- return DRM_ERR(EINVAL);
+ if (elts->prim < 0 || elts->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
+ DRM_ERROR("buffer prim %d\n", elts->prim);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf = dma->buflist[elts.idx];
+ buf = dma->buflist[elts->idx];
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", elts.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", elts->idx);
+ return -EINVAL;
}
- count = (elts.end - elts.start) / sizeof(u16);
- elts.start -= RADEON_INDEX_PRIM_OFFSET;
+ count = (elts->end - elts->start) / sizeof(u16);
+ elts->start -= RADEON_INDEX_PRIM_OFFSET;
- if (elts.start & 0x7) {
- DRM_ERROR("misaligned buffer 0x%x\n", elts.start);
- return DRM_ERR(EINVAL);
+ if (elts->start & 0x7) {
+ DRM_ERROR("misaligned buffer 0x%x\n", elts->start);
+ return -EINVAL;
}
- if (elts.start < buf->used) {
- DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used);
- return DRM_ERR(EINVAL);
+ if (elts->start < buf->used) {
+ DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used);
+ return -EINVAL;
}
- buf->used = elts.end;
+ buf->used = elts->end;
if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
- if (radeon_emit_state(dev_priv, filp_priv,
+ if (radeon_emit_state(dev_priv, file_priv,
&sarea_priv->context_state,
sarea_priv->tex_state,
sarea_priv->dirty)) {
DRM_ERROR("radeon_emit_state failed\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
@@ -2363,15 +2341,15 @@ static int radeon_cp_indices(DRM_IOCTL_ARGS)
/* Build up a prim_t record:
*/
- prim.start = elts.start;
- prim.finish = elts.end;
- prim.prim = elts.prim;
+ prim.start = elts->start;
+ prim.finish = elts->end;
+ prim.prim = elts->prim;
prim.offset = 0; /* offset from start of dma buffers */
prim.numverts = RADEON_MAX_VB_VERTS; /* duh */
prim.vc_format = dev_priv->sarea_priv->vc_format;
radeon_cp_dispatch_indices(dev, buf, &prim);
- if (elts.discard) {
+ if (elts->discard) {
radeon_cp_discard_buffer(dev, buf);
}
@@ -2379,52 +2357,43 @@ static int radeon_cp_indices(DRM_IOCTL_ARGS)
return 0;
}
-static int radeon_cp_texture(DRM_IOCTL_ARGS)
+static int radeon_cp_texture(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_texture_t tex;
+ drm_radeon_texture_t *tex = data;
drm_radeon_tex_image_t image;
int ret;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(tex, (drm_radeon_texture_t __user *) data,
- sizeof(tex));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (tex.image == NULL) {
+ if (tex->image == NULL) {
DRM_ERROR("null texture image!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (DRM_COPY_FROM_USER(&image,
- (drm_radeon_tex_image_t __user *) tex.image,
+ (drm_radeon_tex_image_t __user *) tex->image,
sizeof(image)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- ret = radeon_cp_dispatch_texture(filp, dev, &tex, &image);
+ ret = radeon_cp_dispatch_texture(dev, file_priv, tex, &image);
- COMMIT_RING();
return ret;
}
-static int radeon_cp_stipple(DRM_IOCTL_ARGS)
+static int radeon_cp_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_stipple_t stipple;
+ drm_radeon_stipple_t *stipple = data;
u32 mask[32];
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(stipple, (drm_radeon_stipple_t __user *) data,
- sizeof(stipple));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof(u32)))
- return DRM_ERR(EFAULT);
+ if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32)))
+ return -EFAULT;
RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -2434,52 +2403,48 @@ static int radeon_cp_stipple(DRM_IOCTL_ARGS)
return 0;
}
-static int radeon_cp_indirect(DRM_IOCTL_ARGS)
+static int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
- drm_radeon_indirect_t indirect;
+ drm_radeon_indirect_t *indirect = data;
RING_LOCALS;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(indirect,
- (drm_radeon_indirect_t __user *) data,
- sizeof(indirect));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
- indirect.idx, indirect.start, indirect.end, indirect.discard);
+ indirect->idx, indirect->start, indirect->end,
+ indirect->discard);
- if (indirect.idx < 0 || indirect.idx >= dma->buf_count) {
+ if (indirect->idx < 0 || indirect->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- indirect.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ indirect->idx, dma->buf_count - 1);
+ return -EINVAL;
}
- buf = dma->buflist[indirect.idx];
+ buf = dma->buflist[indirect->idx];
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", indirect.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", indirect->idx);
+ return -EINVAL;
}
- if (indirect.start < buf->used) {
+ if (indirect->start < buf->used) {
DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
- indirect.start, buf->used);
- return DRM_ERR(EINVAL);
+ indirect->start, buf->used);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf->used = indirect.end;
+ buf->used = indirect->end;
/* Wait for the 3D stream to idle before the indirect buffer
* containing 2D acceleration commands is processed.
@@ -2494,8 +2459,8 @@ static int radeon_cp_indirect(DRM_IOCTL_ARGS)
* X server. This is insecure and is thus only available to
* privileged clients.
*/
- radeon_cp_dispatch_indirect(dev, buf, indirect.start, indirect.end);
- if (indirect.discard) {
+ radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
+ if (indirect->discard) {
radeon_cp_discard_buffer(dev, buf);
}
@@ -2503,71 +2468,64 @@ static int radeon_cp_indirect(DRM_IOCTL_ARGS)
return 0;
}
-static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
+static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_file *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf;
- drm_radeon_vertex2_t vertex;
+ drm_radeon_vertex2_t *vertex = data;
int i;
unsigned char laststate;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
- DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data,
- sizeof(vertex));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
DRM_DEBUG("pid=%d index=%d discard=%d\n",
- DRM_CURRENTPID, vertex.idx, vertex.discard);
+ DRM_CURRENTPID, vertex->idx, vertex->discard);
- if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
+ if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
DRM_ERROR("buffer index %d (of %d max)\n",
- vertex.idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ vertex->idx, dma->buf_count - 1);
+ return -EINVAL;
}
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- buf = dma->buflist[vertex.idx];
+ buf = dma->buflist[vertex->idx];
- if (buf->filp != filp) {
+ if (buf->file_priv != file_priv) {
DRM_ERROR("process %d using buffer owned by %p\n",
- DRM_CURRENTPID, buf->filp);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, buf->file_priv);
+ return -EINVAL;
}
if (buf->pending) {
- DRM_ERROR("sending pending buffer %d\n", vertex.idx);
- return DRM_ERR(EINVAL);
+ DRM_ERROR("sending pending buffer %d\n", vertex->idx);
+ return -EINVAL;
}
if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
- for (laststate = 0xff, i = 0; i < vertex.nr_prims; i++) {
+ for (laststate = 0xff, i = 0; i < vertex->nr_prims; i++) {
drm_radeon_prim_t prim;
drm_radeon_tcl_prim_t tclprim;
- if (DRM_COPY_FROM_USER(&prim, &vertex.prim[i], sizeof(prim)))
- return DRM_ERR(EFAULT);
+ if (DRM_COPY_FROM_USER(&prim, &vertex->prim[i], sizeof(prim)))
+ return -EFAULT;
if (prim.stateidx != laststate) {
drm_radeon_state_t state;
if (DRM_COPY_FROM_USER(&state,
- &vertex.state[prim.stateidx],
+ &vertex->state[prim.stateidx],
sizeof(state)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
- if (radeon_emit_state2(dev_priv, filp_priv, &state)) {
+ if (radeon_emit_state2(dev_priv, file_priv, &state)) {
DRM_ERROR("radeon_emit_state2 failed\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
laststate = prim.stateidx;
@@ -2594,7 +2552,7 @@ static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
sarea_priv->nbox = 0;
}
- if (vertex.discard) {
+ if (vertex->discard) {
radeon_cp_discard_buffer(dev, buf);
}
@@ -2603,7 +2561,7 @@ static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
}
static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
- struct drm_file * filp_priv,
+ struct drm_file *file_priv,
drm_radeon_cmd_header_t header,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
@@ -2613,19 +2571,19 @@ static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
RING_LOCALS;
if (id >= RADEON_MAX_STATE_PACKETS)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
sz = packet[id].len;
reg = packet[id].start;
if (sz * sizeof(int) > cmdbuf->bufsz) {
DRM_ERROR("Packet size provided larger than data provided\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (radeon_check_and_fixup_packets(dev_priv, filp_priv, id, data)) {
+ if (radeon_check_and_fixup_packets(dev_priv, file_priv, id, data)) {
DRM_ERROR("Packet verification failed\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
BEGIN_RING(sz + 1);
@@ -2713,7 +2671,7 @@ static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
if (!sz)
return 0;
if (sz * 4 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
BEGIN_RING(5 + sz);
OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
@@ -2729,7 +2687,7 @@ static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
}
static int radeon_emit_packet3(struct drm_device * dev,
- struct drm_file * filp_priv,
+ struct drm_file *file_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2739,7 +2697,7 @@ static int radeon_emit_packet3(struct drm_device * dev,
DRM_DEBUG("\n");
- if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
+ if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv,
cmdbuf, &cmdsz))) {
DRM_ERROR("Packet verification failed\n");
return ret;
@@ -2755,7 +2713,7 @@ static int radeon_emit_packet3(struct drm_device * dev,
}
static int radeon_emit_packet3_cliprect(struct drm_device *dev,
- struct drm_file *filp_priv,
+ struct drm_file *file_priv,
drm_radeon_kcmd_buffer_t *cmdbuf,
int orig_nbox)
{
@@ -2769,7 +2727,7 @@ static int radeon_emit_packet3_cliprect(struct drm_device *dev,
DRM_DEBUG("\n");
- if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
+ if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv,
cmdbuf, &cmdsz))) {
DRM_ERROR("Packet verification failed\n");
return ret;
@@ -2781,7 +2739,7 @@ static int radeon_emit_packet3_cliprect(struct drm_device *dev,
do {
if (i < cmdbuf->nbox) {
if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
/* FIXME The second and subsequent times round
* this loop, send a WAIT_UNTIL_3D_IDLE before
* calling emit_clip_rect(). This fixes a
@@ -2839,62 +2797,54 @@ static int radeon_emit_wait(struct drm_device * dev, int flags)
ADVANCE_RING();
break;
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
}
-static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
+static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_file *filp_priv;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *buf = NULL;
int idx;
- drm_radeon_kcmd_buffer_t cmdbuf;
+ drm_radeon_kcmd_buffer_t *cmdbuf = data;
drm_radeon_cmd_header_t header;
int orig_nbox, orig_bufsz;
char *kbuf = NULL;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
- DRM_COPY_FROM_USER_IOCTL(cmdbuf,
- (drm_radeon_cmd_buffer_t __user *) data,
- sizeof(cmdbuf));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
RING_SPACE_TEST_WITH_RETURN(dev_priv);
VB_AGE_TEST_WITH_RETURN(dev_priv);
- if (cmdbuf.bufsz > 64 * 1024 || cmdbuf.bufsz < 0) {
- return DRM_ERR(EINVAL);
+ if (cmdbuf->bufsz > 64 * 1024 || cmdbuf->bufsz < 0) {
+ return -EINVAL;
}
/* Allocate an in-kernel area and copy in the cmdbuf. Do this to avoid
* races between checking values and using those values in other code,
* and simply to avoid a lot of function calls to copy in data.
*/
- orig_bufsz = cmdbuf.bufsz;
+ orig_bufsz = cmdbuf->bufsz;
if (orig_bufsz != 0) {
- kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER);
+ kbuf = drm_alloc(cmdbuf->bufsz, DRM_MEM_DRIVER);
if (kbuf == NULL)
- return DRM_ERR(ENOMEM);
- if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf.buf,
- cmdbuf.bufsz)) {
+ return -ENOMEM;
+ if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf->buf,
+ cmdbuf->bufsz)) {
drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
- cmdbuf.buf = kbuf;
+ cmdbuf->buf = kbuf;
}
- orig_nbox = cmdbuf.nbox;
+ orig_nbox = cmdbuf->nbox;
if (dev_priv->microcode_version == UCODE_R300) {
int temp;
- temp = r300_do_cp_cmdbuf(dev, filp, filp_priv, &cmdbuf);
+ temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf);
if (orig_bufsz != 0)
drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
@@ -2903,17 +2853,17 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
}
/* microcode_version != r300 */
- while (cmdbuf.bufsz >= sizeof(header)) {
+ while (cmdbuf->bufsz >= sizeof(header)) {
- header.i = *(int *)cmdbuf.buf;
- cmdbuf.buf += sizeof(header);
- cmdbuf.bufsz -= sizeof(header);
+ header.i = *(int *)cmdbuf->buf;
+ cmdbuf->buf += sizeof(header);
+ cmdbuf->bufsz -= sizeof(header);
switch (header.header.cmd_type) {
case RADEON_CMD_PACKET:
DRM_DEBUG("RADEON_CMD_PACKET\n");
if (radeon_emit_packets
- (dev_priv, filp_priv, header, &cmdbuf)) {
+ (dev_priv, file_priv, header, cmdbuf)) {
DRM_ERROR("radeon_emit_packets failed\n");
goto err;
}
@@ -2921,7 +2871,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
case RADEON_CMD_SCALARS:
DRM_DEBUG("RADEON_CMD_SCALARS\n");
- if (radeon_emit_scalars(dev_priv, header, &cmdbuf)) {
+ if (radeon_emit_scalars(dev_priv, header, cmdbuf)) {
DRM_ERROR("radeon_emit_scalars failed\n");
goto err;
}
@@ -2929,7 +2879,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
case RADEON_CMD_VECTORS:
DRM_DEBUG("RADEON_CMD_VECTORS\n");
- if (radeon_emit_vectors(dev_priv, header, &cmdbuf)) {
+ if (radeon_emit_vectors(dev_priv, header, cmdbuf)) {
DRM_ERROR("radeon_emit_vectors failed\n");
goto err;
}
@@ -2945,9 +2895,10 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
}
buf = dma->buflist[idx];
- if (buf->filp != filp || buf->pending) {
+ if (buf->file_priv != file_priv || buf->pending) {
DRM_ERROR("bad buffer %p %p %d\n",
- buf->filp, filp, buf->pending);
+ buf->file_priv, file_priv,
+ buf->pending);
goto err;
}
@@ -2956,7 +2907,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
case RADEON_CMD_PACKET3:
DRM_DEBUG("RADEON_CMD_PACKET3\n");
- if (radeon_emit_packet3(dev, filp_priv, &cmdbuf)) {
+ if (radeon_emit_packet3(dev, file_priv, cmdbuf)) {
DRM_ERROR("radeon_emit_packet3 failed\n");
goto err;
}
@@ -2965,7 +2916,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
case RADEON_CMD_PACKET3_CLIP:
DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
if (radeon_emit_packet3_cliprect
- (dev, filp_priv, &cmdbuf, orig_nbox)) {
+ (dev, file_priv, cmdbuf, orig_nbox)) {
DRM_ERROR("radeon_emit_packet3_clip failed\n");
goto err;
}
@@ -2973,7 +2924,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
case RADEON_CMD_SCALARS2:
DRM_DEBUG("RADEON_CMD_SCALARS2\n");
- if (radeon_emit_scalars2(dev_priv, header, &cmdbuf)) {
+ if (radeon_emit_scalars2(dev_priv, header, cmdbuf)) {
DRM_ERROR("radeon_emit_scalars2 failed\n");
goto err;
}
@@ -2988,7 +2939,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
break;
case RADEON_CMD_VECLINEAR:
DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
- if (radeon_emit_veclinear(dev_priv, header, &cmdbuf)) {
+ if (radeon_emit_veclinear(dev_priv, header, cmdbuf)) {
DRM_ERROR("radeon_emit_veclinear failed\n");
goto err;
}
@@ -2997,7 +2948,7 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
default:
DRM_ERROR("bad cmd_type %d at %p\n",
header.header.cmd_type,
- cmdbuf.buf - sizeof(header));
+ cmdbuf->buf - sizeof(header));
goto err;
}
}
@@ -3012,22 +2963,18 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
err:
if (orig_bufsz != 0)
drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
-static int radeon_cp_getparam(DRM_IOCTL_ARGS)
+static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_radeon_getparam_t param;
+ drm_radeon_getparam_t *param = data;
int value;
- DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data,
- sizeof(param));
-
DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
- switch (param.param) {
+ switch (param->param) {
case RADEON_PARAM_GART_BUFFER_OFFSET:
value = dev_priv->gart_buffers_offset;
break;
@@ -3058,7 +3005,7 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS)
/*
* This ioctl() doesn't work on 64-bit platforms because hw_lock is a
* pointer which can't fit into an int-sized variable. According to
- * Michel Dänzer, the ioctl() is only used on embedded platforms, so
+ * Michel Dänzer, the ioctl() is only used on embedded platforms, so
* not supporting it shouldn't be a problem. If the same functionality
* is needed on 64-bit platforms, a new ioctl() would have to be added,
* so backwards-compatibility for the embedded platforms can be
@@ -3074,7 +3021,7 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS)
break;
case RADEON_PARAM_SCRATCH_OFFSET:
if (!dev_priv->writeback_works)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
value = RADEON_SCRATCH_REG_OFFSET;
break;
case RADEON_PARAM_CARD_TYPE:
@@ -3089,43 +3036,37 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS)
value = radeon_vblank_crtc_get(dev);
break;
default:
- DRM_DEBUG("Invalid parameter %d\n", param.param);
- return DRM_ERR(EINVAL);
+ DRM_DEBUG("Invalid parameter %d\n", param->param);
+ return -EINVAL;
}
- if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
+ if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
DRM_ERROR("copy_to_user\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
return 0;
}
-static int radeon_cp_setparam(DRM_IOCTL_ARGS)
+static int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- struct drm_file *filp_priv;
- drm_radeon_setparam_t sp;
+ drm_radeon_setparam_t *sp = data;
struct drm_radeon_driver_file_fields *radeon_priv;
- DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
-
- DRM_COPY_FROM_USER_IOCTL(sp, (drm_radeon_setparam_t __user *) data,
- sizeof(sp));
-
- switch (sp.param) {
+ switch (sp->param) {
case RADEON_SETPARAM_FB_LOCATION:
- radeon_priv = filp_priv->driver_priv;
- radeon_priv->radeon_fb_delta = dev_priv->fb_location - sp.value;
+ radeon_priv = file_priv->driver_priv;
+ radeon_priv->radeon_fb_delta = dev_priv->fb_location -
+ sp->value;
break;
case RADEON_SETPARAM_SWITCH_TILING:
- if (sp.value == 0) {
+ if (sp->value == 0) {
DRM_DEBUG("color tiling disabled\n");
dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO;
dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO;
dev_priv->sarea_priv->tiling_enabled = 0;
- } else if (sp.value == 1) {
+ } else if (sp->value == 1) {
DRM_DEBUG("color tiling enabled\n");
dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO;
dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO;
@@ -3133,23 +3074,23 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
}
break;
case RADEON_SETPARAM_PCIGART_LOCATION:
- dev_priv->pcigart_offset = sp.value;
+ dev_priv->pcigart_offset = sp->value;
dev_priv->pcigart_offset_set = 1;
break;
case RADEON_SETPARAM_NEW_MEMMAP:
- dev_priv->new_memmap = sp.value;
+ dev_priv->new_memmap = sp->value;
break;
case RADEON_SETPARAM_PCIGART_TABLE_SIZE:
- dev_priv->gart_info.table_size = sp.value;
+ dev_priv->gart_info.table_size = sp->value;
if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE)
dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
break;
case RADEON_SETPARAM_VBLANK_CRTC:
- return radeon_vblank_crtc_set(dev, sp.value);
+ return radeon_vblank_crtc_set(dev, sp->value);
break;
default:
- DRM_DEBUG("Invalid parameter %d\n", sp.param);
- return DRM_ERR(EINVAL);
+ DRM_DEBUG("Invalid parameter %d\n", sp->param);
+ return -EINVAL;
}
return 0;
@@ -3162,14 +3103,14 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
*
* DRM infrastructure takes care of reclaiming dma buffers.
*/
-void radeon_driver_preclose(struct drm_device *dev, DRMFILE filp)
+void radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
{
if (dev->dev_private) {
drm_radeon_private_t *dev_priv = dev->dev_private;
dev_priv->page_flipping = 0;
- radeon_mem_release(filp, dev_priv->gart_heap);
- radeon_mem_release(filp, dev_priv->fb_heap);
- radeon_surfaces_release(filp, dev_priv);
+ radeon_mem_release(file_priv, dev_priv->gart_heap);
+ radeon_mem_release(file_priv, dev_priv->fb_heap);
+ radeon_surfaces_release(file_priv, dev_priv);
}
}
@@ -3186,7 +3127,7 @@ void radeon_driver_lastclose(struct drm_device *dev)
radeon_do_release(dev);
}
-int radeon_driver_open(struct drm_device *dev, struct drm_file *filp_priv)
+int radeon_driver_open(struct drm_device *dev, struct drm_file *file_priv)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
struct drm_radeon_driver_file_fields *radeon_priv;
@@ -3199,7 +3140,7 @@ int radeon_driver_open(struct drm_device *dev, struct drm_file *filp_priv)
if (!radeon_priv)
return -ENOMEM;
- filp_priv->driver_priv = radeon_priv;
+ file_priv->driver_priv = radeon_priv;
if (dev_priv)
radeon_priv->radeon_fb_delta = dev_priv->fb_location;
@@ -3208,42 +3149,42 @@ int radeon_driver_open(struct drm_device *dev, struct drm_file *filp_priv)
return 0;
}
-void radeon_driver_postclose(struct drm_device *dev, struct drm_file *filp_priv)
+void radeon_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
{
struct drm_radeon_driver_file_fields *radeon_priv =
- filp_priv->driver_priv;
+ file_priv->driver_priv;
drm_free(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES);
}
-drm_ioctl_desc_t radeon_ioctls[] = {
- [DRM_IOCTL_NR(DRM_RADEON_CP_INIT)] = {radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_RADEON_CP_START)] = {radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_RADEON_CP_STOP)] = {radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_RADEON_CP_RESET)] = {radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)] = {radeon_cp_idle, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)] = {radeon_cp_resume, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_RESET)] = {radeon_engine_reset, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] = {radeon_fullscreen, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_SWAP)] = {radeon_cp_swap, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_CLEAR)] = {radeon_cp_clear, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_VERTEX)] = {radeon_cp_vertex, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_INDICES)] = {radeon_cp_indices, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_TEXTURE)] = {radeon_cp_texture, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_STIPPLE)] = {radeon_cp_stipple, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_INDIRECT)] = {radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_RADEON_VERTEX2)] = {radeon_cp_vertex2, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_CMDBUF)] = {radeon_cp_cmdbuf, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_GETPARAM)] = {radeon_cp_getparam, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_FLIP)] = {radeon_cp_flip, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_ALLOC)] = {radeon_mem_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_FREE)] = {radeon_mem_free, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)] = {radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)] = {radeon_irq_emit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)] = {radeon_irq_wait, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_SETPARAM)] = {radeon_cp_setparam, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] = {radeon_surface_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)] = {radeon_surface_free, DRM_AUTH}
+struct drm_ioctl_desc radeon_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_RADEON_CP_START, radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_RADEON_CP_STOP, radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_RADEON_CP_RESET, radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_RADEON_CP_IDLE, radeon_cp_idle, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_CP_RESUME, radeon_cp_resume, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_RESET, radeon_engine_reset, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_FULLSCREEN, radeon_fullscreen, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_SWAP, radeon_cp_swap, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_CLEAR, radeon_cp_clear, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_VERTEX, radeon_cp_vertex, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_INDICES, radeon_cp_indices, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, radeon_cp_texture, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, radeon_cp_stipple, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_INDIRECT, radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, radeon_cp_vertex2, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, radeon_cp_cmdbuf, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, radeon_cp_getparam, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_FLIP, radeon_cp_flip, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_ALLOC, radeon_mem_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_FREE, radeon_mem_free, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_INIT_HEAP, radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, radeon_irq_emit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH)
};
int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);
diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c
index 18c7235f6b7..d465b2f9c1c 100644
--- a/drivers/char/drm/savage_bci.c
+++ b/drivers/char/drm/savage_bci.c
@@ -60,7 +60,7 @@ savage_bci_wait_fifo_shadow(drm_savage_private_t * dev_priv, unsigned int n)
DRM_ERROR("failed!\n");
DRM_INFO(" status=0x%08x, threshold=0x%08x\n", status, threshold);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int
@@ -81,7 +81,7 @@ savage_bci_wait_fifo_s3d(drm_savage_private_t * dev_priv, unsigned int n)
DRM_ERROR("failed!\n");
DRM_INFO(" status=0x%08x\n", status);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int
@@ -102,7 +102,7 @@ savage_bci_wait_fifo_s4(drm_savage_private_t * dev_priv, unsigned int n)
DRM_ERROR("failed!\n");
DRM_INFO(" status=0x%08x\n", status);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
/*
@@ -136,7 +136,7 @@ savage_bci_wait_event_shadow(drm_savage_private_t * dev_priv, uint16_t e)
DRM_INFO(" status=0x%08x, e=0x%04x\n", status, e);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
static int
@@ -158,7 +158,7 @@ savage_bci_wait_event_reg(drm_savage_private_t * dev_priv, uint16_t e)
DRM_INFO(" status=0x%08x, e=0x%04x\n", status, e);
#endif
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
uint16_t savage_bci_emit_event(drm_savage_private_t * dev_priv,
@@ -301,7 +301,7 @@ static int savage_dma_init(drm_savage_private_t * dev_priv)
dev_priv->dma_pages = drm_alloc(sizeof(drm_savage_dma_page_t) *
dev_priv->nr_dma_pages, DRM_MEM_DRIVER);
if (dev_priv->dma_pages == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
for (i = 0; i < dev_priv->nr_dma_pages; ++i) {
SET_AGE(&dev_priv->dma_pages[i].age, 0, 0);
@@ -541,7 +541,7 @@ int savage_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv = drm_alloc(sizeof(drm_savage_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
memset(dev_priv, 0, sizeof(drm_savage_private_t));
dev->dev_private = (void *)dev_priv;
@@ -682,16 +682,16 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
if (init->fb_bpp != 16 && init->fb_bpp != 32) {
DRM_ERROR("invalid frame buffer bpp %d!\n", init->fb_bpp);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (init->depth_bpp != 16 && init->depth_bpp != 32) {
DRM_ERROR("invalid depth buffer bpp %d!\n", init->fb_bpp);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (init->dma_type != SAVAGE_DMA_AGP &&
init->dma_type != SAVAGE_DMA_PCI) {
DRM_ERROR("invalid dma memory type %d!\n", init->dma_type);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->cob_size = init->cob_size;
@@ -715,14 +715,14 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
if (!dev_priv->sarea) {
DRM_ERROR("could not find sarea!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (init->status_offset != 0) {
dev_priv->status = drm_core_findmap(dev, init->status_offset);
if (!dev_priv->status) {
DRM_ERROR("could not find shadow status region!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else {
dev_priv->status = NULL;
@@ -734,13 +734,13 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
if (!dev->agp_buffer_map) {
DRM_ERROR("could not find DMA buffer region!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
drm_core_ioremap(dev->agp_buffer_map, dev);
if (!dev->agp_buffer_map) {
DRM_ERROR("failed to ioremap DMA buffer region!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
}
if (init->agp_textures_offset) {
@@ -749,7 +749,7 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
if (!dev_priv->agp_textures) {
DRM_ERROR("could not find agp texture region!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else {
dev_priv->agp_textures = NULL;
@@ -760,39 +760,39 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
DRM_ERROR("command DMA not supported on "
"Savage3D/MX/IX.\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (dev->dma && dev->dma->buflist) {
DRM_ERROR("command and vertex DMA not supported "
"at the same time.\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->cmd_dma = drm_core_findmap(dev, init->cmd_dma_offset);
if (!dev_priv->cmd_dma) {
DRM_ERROR("could not find command DMA region!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (dev_priv->dma_type == SAVAGE_DMA_AGP) {
if (dev_priv->cmd_dma->type != _DRM_AGP) {
DRM_ERROR("AGP command DMA region is not a "
"_DRM_AGP map!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
drm_core_ioremap(dev_priv->cmd_dma, dev);
if (!dev_priv->cmd_dma->handle) {
DRM_ERROR("failed to ioremap command "
"DMA region!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
} else if (dev_priv->cmd_dma->type != _DRM_CONSISTENT) {
DRM_ERROR("PCI command DMA region is not a "
"_DRM_CONSISTENT map!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else {
dev_priv->cmd_dma = NULL;
@@ -809,7 +809,7 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
if (!dev_priv->fake_dma.handle) {
DRM_ERROR("could not allocate faked DMA buffer!\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->cmd_dma = &dev_priv->fake_dma;
dev_priv->dma_flush = savage_fake_dma_flush;
@@ -886,13 +886,13 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
if (savage_freelist_init(dev) < 0) {
DRM_ERROR("could not initialize freelist\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (savage_dma_init(dev_priv) < 0) {
DRM_ERROR("could not initialize command DMA\n");
savage_do_cleanup_bci(dev);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
return 0;
@@ -928,59 +928,46 @@ static int savage_do_cleanup_bci(struct drm_device * dev)
return 0;
}
-static int savage_bci_init(DRM_IOCTL_ARGS)
+static int savage_bci_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_savage_init_t init;
+ drm_savage_init_t *init = data;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(init, (drm_savage_init_t __user *) data,
- sizeof(init));
-
- switch (init.func) {
+ switch (init->func) {
case SAVAGE_INIT_BCI:
- return savage_do_init_bci(dev, &init);
+ return savage_do_init_bci(dev, init);
case SAVAGE_CLEANUP_BCI:
return savage_do_cleanup_bci(dev);
}
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
-static int savage_bci_event_emit(DRM_IOCTL_ARGS)
+static int savage_bci_event_emit(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_savage_private_t *dev_priv = dev->dev_private;
- drm_savage_event_emit_t event;
+ drm_savage_event_emit_t *event = data;
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(event, (drm_savage_event_emit_t __user *) data,
- sizeof(event));
+ event->count = savage_bci_emit_event(dev_priv, event->flags);
+ event->count |= dev_priv->event_wrap << 16;
- event.count = savage_bci_emit_event(dev_priv, event.flags);
- event.count |= dev_priv->event_wrap << 16;
- DRM_COPY_TO_USER_IOCTL((drm_savage_event_emit_t __user *) data,
- event, sizeof(event));
return 0;
}
-static int savage_bci_event_wait(DRM_IOCTL_ARGS)
+static int savage_bci_event_wait(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_savage_private_t *dev_priv = dev->dev_private;
- drm_savage_event_wait_t event;
+ drm_savage_event_wait_t *event = data;
unsigned int event_e, hw_e;
unsigned int event_w, hw_w;
DRM_DEBUG("\n");
- DRM_COPY_FROM_USER_IOCTL(event, (drm_savage_event_wait_t __user *) data,
- sizeof(event));
-
UPDATE_EVENT_COUNTER();
if (dev_priv->status_ptr)
hw_e = dev_priv->status_ptr[1] & 0xffff;
@@ -990,8 +977,8 @@ static int savage_bci_event_wait(DRM_IOCTL_ARGS)
if (hw_e > dev_priv->event_counter)
hw_w--; /* hardware hasn't passed the last wrap yet */
- event_e = event.count & 0xffff;
- event_w = event.count >> 16;
+ event_e = event->count & 0xffff;
+ event_w = event->count >> 16;
/* Don't need to wait if
* - event counter wrapped since the event was emitted or
@@ -1007,7 +994,9 @@ static int savage_bci_event_wait(DRM_IOCTL_ARGS)
* DMA buffer management
*/
-static int savage_bci_get_buffers(DRMFILE filp, struct drm_device *dev, struct drm_dma *d)
+static int savage_bci_get_buffers(struct drm_device *dev,
+ struct drm_file *file_priv,
+ struct drm_dma *d)
{
struct drm_buf *buf;
int i;
@@ -1015,61 +1004,56 @@ static int savage_bci_get_buffers(DRMFILE filp, struct drm_device *dev, struct d
for (i = d->granted_count; i < d->request_count; i++) {
buf = savage_freelist_get(dev);
if (!buf)
- return DRM_ERR(EAGAIN);
+ return -EAGAIN;
- buf->filp = filp;
+ buf->file_priv = file_priv;
if (DRM_COPY_TO_USER(&d->request_indices[i],
&buf->idx, sizeof(buf->idx)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if (DRM_COPY_TO_USER(&d->request_sizes[i],
&buf->total, sizeof(buf->total)))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
d->granted_count++;
}
return 0;
}
-int savage_bci_buffers(DRM_IOCTL_ARGS)
+int savage_bci_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
struct drm_device_dma *dma = dev->dma;
- struct drm_dma d;
+ struct drm_dma *d = data;
int ret = 0;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(d, (struct drm_dma __user *) data, sizeof(d));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
/* Please don't send us buffers.
*/
- if (d.send_count != 0) {
+ if (d->send_count != 0) {
DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
- DRM_CURRENTPID, d.send_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->send_count);
+ return -EINVAL;
}
/* We'll send you buffers.
*/
- if (d.request_count < 0 || d.request_count > dma->buf_count) {
+ if (d->request_count < 0 || d->request_count > dma->buf_count) {
DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
- DRM_CURRENTPID, d.request_count, dma->buf_count);
- return DRM_ERR(EINVAL);
+ DRM_CURRENTPID, d->request_count, dma->buf_count);
+ return -EINVAL;
}
- d.granted_count = 0;
+ d->granted_count = 0;
- if (d.request_count) {
- ret = savage_bci_get_buffers(filp, dev, &d);
+ if (d->request_count) {
+ ret = savage_bci_get_buffers(dev, file_priv, d);
}
- DRM_COPY_TO_USER_IOCTL((struct drm_dma __user *) data, d, sizeof(d));
-
return ret;
}
-void savage_reclaim_buffers(struct drm_device *dev, DRMFILE filp)
+void savage_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv)
{
struct drm_device_dma *dma = dev->dma;
drm_savage_private_t *dev_priv = dev->dev_private;
@@ -1088,7 +1072,7 @@ void savage_reclaim_buffers(struct drm_device *dev, DRMFILE filp)
struct drm_buf *buf = dma->buflist[i];
drm_savage_buf_priv_t *buf_priv = buf->dev_private;
- if (buf->filp == filp && buf_priv &&
+ if (buf->file_priv == file_priv && buf_priv &&
buf_priv->next == NULL && buf_priv->prev == NULL) {
uint16_t event;
DRM_DEBUG("reclaimed from client\n");
@@ -1098,14 +1082,14 @@ void savage_reclaim_buffers(struct drm_device *dev, DRMFILE filp)
}
}
- drm_core_reclaim_buffers(dev, filp);
+ drm_core_reclaim_buffers(dev, file_priv);
}
-drm_ioctl_desc_t savage_ioctls[] = {
- [DRM_IOCTL_NR(DRM_SAVAGE_BCI_INIT)] = {savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_SAVAGE_BCI_CMDBUF)] = {savage_bci_cmdbuf, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_EMIT)] = {savage_bci_event_emit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SAVAGE_BCI_EVENT_WAIT)] = {savage_bci_event_wait, DRM_AUTH},
+struct drm_ioctl_desc savage_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_SAVAGE_BCI_INIT, savage_bci_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_SAVAGE_BCI_CMDBUF, savage_bci_cmdbuf, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_SAVAGE_BCI_EVENT_EMIT, savage_bci_event_emit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_SAVAGE_BCI_EVENT_WAIT, savage_bci_event_wait, DRM_AUTH),
};
int savage_max_ioctl = DRM_ARRAY_SIZE(savage_ioctls);
diff --git a/drivers/char/drm/savage_drv.h b/drivers/char/drm/savage_drv.h
index 5fd54de4280..df2aac6636f 100644
--- a/drivers/char/drm/savage_drv.h
+++ b/drivers/char/drm/savage_drv.h
@@ -104,7 +104,7 @@ enum savage_family {
S3_LAST
};
-extern drm_ioctl_desc_t savage_ioctls[];
+extern struct drm_ioctl_desc savage_ioctls[];
extern int savage_max_ioctl;
#define S3_SAVAGE3D_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
@@ -197,8 +197,8 @@ typedef struct drm_savage_private {
} drm_savage_private_t;
/* ioctls */
-extern int savage_bci_cmdbuf(DRM_IOCTL_ARGS);
-extern int savage_bci_buffers(DRM_IOCTL_ARGS);
+extern int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int savage_bci_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
/* BCI functions */
extern uint16_t savage_bci_emit_event(drm_savage_private_t * dev_priv,
@@ -212,7 +212,8 @@ extern int savage_driver_load(struct drm_device *dev, unsigned long chipset);
extern int savage_driver_firstopen(struct drm_device *dev);
extern void savage_driver_lastclose(struct drm_device *dev);
extern int savage_driver_unload(struct drm_device *dev);
-extern void savage_reclaim_buffers(struct drm_device * dev, DRMFILE filp);
+extern void savage_reclaim_buffers(struct drm_device *dev,
+ struct drm_file *file_priv);
/* state functions */
extern void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv,
diff --git a/drivers/char/drm/savage_state.c b/drivers/char/drm/savage_state.c
index 77497841478..bf8e0e10fe2 100644
--- a/drivers/char/drm/savage_state.c
+++ b/drivers/char/drm/savage_state.c
@@ -83,7 +83,7 @@ static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit,
{
if ((addr & 6) != 2) { /* reserved bits */
DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (!(addr & 1)) { /* local */
addr &= ~7;
@@ -92,13 +92,13 @@ static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit,
DRM_ERROR
("bad texAddr%d %08x (local addr out of range)\n",
unit, addr);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else { /* AGP */
if (!dev_priv->agp_textures) {
DRM_ERROR("bad texAddr%d %08x (AGP not available)\n",
unit, addr);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
addr &= ~7;
if (addr < dev_priv->agp_textures->offset ||
@@ -107,7 +107,7 @@ static int savage_verify_texaddr(drm_savage_private_t * dev_priv, int unit,
DRM_ERROR
("bad texAddr%d %08x (AGP addr out of range)\n",
unit, addr);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
return 0;
@@ -133,7 +133,7 @@ static int savage_verify_state_s3d(drm_savage_private_t * dev_priv,
start + count - 1 > SAVAGE_DESTTEXRWWATERMARK_S3D) {
DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
start, start + count - 1);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart,
@@ -165,7 +165,7 @@ static int savage_verify_state_s4(drm_savage_private_t * dev_priv,
start + count - 1 > SAVAGE_TEXBLENDCOLOR_S4) {
DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
start, start + count - 1);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0,
@@ -289,7 +289,7 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
if (!dmabuf) {
DRM_ERROR("called without dma buffers!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (!n)
@@ -303,7 +303,7 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
if (n % 3 != 0) {
DRM_ERROR("wrong number of vertices %u in TRILIST\n",
n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case SAVAGE_PRIM_TRISTRIP:
@@ -312,18 +312,18 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
DRM_ERROR
("wrong number of vertices %u in TRIFAN/STRIP\n",
n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
default:
DRM_ERROR("invalid primitive type %u\n", prim);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
if (skip != 0) {
DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else {
unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
@@ -331,18 +331,18 @@ static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
(skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (reorder) {
DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
if (start + n > dmabuf->total / 32) {
DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
start, start + n - 1, dmabuf->total / 32);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* Vertex DMA doesn't work with command DMA at the same time,
@@ -440,7 +440,7 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
if (n % 3 != 0) {
DRM_ERROR("wrong number of vertices %u in TRILIST\n",
n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case SAVAGE_PRIM_TRISTRIP:
@@ -449,24 +449,24 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
DRM_ERROR
("wrong number of vertices %u in TRIFAN/STRIP\n",
n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
default:
DRM_ERROR("invalid primitive type %u\n", prim);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
if (skip > SAVAGE_SKIP_ALL_S3D) {
DRM_ERROR("invalid skip flags 0x%04x\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
vtx_size = 8; /* full vertex */
} else {
if (skip > SAVAGE_SKIP_ALL_S4) {
DRM_ERROR("invalid skip flags 0x%04x\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
vtx_size = 10; /* full vertex */
}
@@ -478,13 +478,13 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
if (vtx_size > vb_stride) {
DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
vtx_size, vb_stride);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (start + n > vb_size / (vb_stride * 4)) {
DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
start, start + n - 1, vb_size / (vb_stride * 4));
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
prim <<= 25;
@@ -547,7 +547,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
if (!dmabuf) {
DRM_ERROR("called without dma buffers!\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (!n)
@@ -560,7 +560,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
case SAVAGE_PRIM_TRILIST:
if (n % 3 != 0) {
DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case SAVAGE_PRIM_TRISTRIP:
@@ -568,18 +568,18 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
if (n < 3) {
DRM_ERROR
("wrong number of indices %u in TRIFAN/STRIP\n", n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
default:
DRM_ERROR("invalid primitive type %u\n", prim);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
if (skip != 0) {
DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
} else {
unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
@@ -587,11 +587,11 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
(skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
DRM_ERROR("invalid skip flags 0x%04x for DMA\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (reorder) {
DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -628,7 +628,7 @@ static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
if (idx[i] > dmabuf->total / 32) {
DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
i, idx[i], dmabuf->total / 32);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -698,7 +698,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
case SAVAGE_PRIM_TRILIST:
if (n % 3 != 0) {
DRM_ERROR("wrong number of indices %u in TRILIST\n", n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
case SAVAGE_PRIM_TRISTRIP:
@@ -706,24 +706,24 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
if (n < 3) {
DRM_ERROR
("wrong number of indices %u in TRIFAN/STRIP\n", n);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
break;
default:
DRM_ERROR("invalid primitive type %u\n", prim);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
if (skip > SAVAGE_SKIP_ALL_S3D) {
DRM_ERROR("invalid skip flags 0x%04x\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
vtx_size = 8; /* full vertex */
} else {
if (skip > SAVAGE_SKIP_ALL_S4) {
DRM_ERROR("invalid skip flags 0x%04x\n", skip);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
vtx_size = 10; /* full vertex */
}
@@ -735,7 +735,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
if (vtx_size > vb_stride) {
DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
vtx_size, vb_stride);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
prim <<= 25;
@@ -748,7 +748,7 @@ static int savage_dispatch_vb_idx(drm_savage_private_t * dev_priv,
if (idx[i] > vb_size / (vb_stride * 4)) {
DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
i, idx[i], vb_size / (vb_stride * 4));
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
@@ -942,7 +942,7 @@ static int savage_dispatch_draw(drm_savage_private_t * dev_priv,
DRM_ERROR("IMPLEMENTATION ERROR: "
"non-drawing-command %d\n",
cmd_header.cmd.cmd);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (ret != 0)
@@ -953,13 +953,12 @@ static int savage_dispatch_draw(drm_savage_private_t * dev_priv,
return 0;
}
-int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
+int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_savage_private_t *dev_priv = dev->dev_private;
struct drm_device_dma *dma = dev->dma;
struct drm_buf *dmabuf;
- drm_savage_cmdbuf_t cmdbuf;
+ drm_savage_cmdbuf_t *cmdbuf = data;
drm_savage_cmd_header_t *kcmd_addr = NULL;
drm_savage_cmd_header_t *first_draw_cmd;
unsigned int *kvb_addr = NULL;
@@ -969,19 +968,16 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
DRM_DEBUG("\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_savage_cmdbuf_t __user *) data,
- sizeof(cmdbuf));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
if (dma && dma->buflist) {
- if (cmdbuf.dma_idx > dma->buf_count) {
+ if (cmdbuf->dma_idx > dma->buf_count) {
DRM_ERROR
("vertex buffer index %u out of range (0-%u)\n",
- cmdbuf.dma_idx, dma->buf_count - 1);
- return DRM_ERR(EINVAL);
+ cmdbuf->dma_idx, dma->buf_count - 1);
+ return -EINVAL;
}
- dmabuf = dma->buflist[cmdbuf.dma_idx];
+ dmabuf = dma->buflist[cmdbuf->dma_idx];
} else {
dmabuf = NULL;
}
@@ -991,47 +987,47 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
* COPY_FROM_USER_UNCHECKED when done in other drivers, and is correct
* for locking on FreeBSD.
*/
- if (cmdbuf.size) {
- kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER);
+ if (cmdbuf->size) {
+ kcmd_addr = drm_alloc(cmdbuf->size * 8, DRM_MEM_DRIVER);
if (kcmd_addr == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
- if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr,
- cmdbuf.size * 8))
+ if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf->cmd_addr,
+ cmdbuf->size * 8))
{
- drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER);
- return DRM_ERR(EFAULT);
+ drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER);
+ return -EFAULT;
}
- cmdbuf.cmd_addr = kcmd_addr;
+ cmdbuf->cmd_addr = kcmd_addr;
}
- if (cmdbuf.vb_size) {
- kvb_addr = drm_alloc(cmdbuf.vb_size, DRM_MEM_DRIVER);
+ if (cmdbuf->vb_size) {
+ kvb_addr = drm_alloc(cmdbuf->vb_size, DRM_MEM_DRIVER);
if (kvb_addr == NULL) {
- ret = DRM_ERR(ENOMEM);
+ ret = -ENOMEM;
goto done;
}
- if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf.vb_addr,
- cmdbuf.vb_size)) {
- ret = DRM_ERR(EFAULT);
+ if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf->vb_addr,
+ cmdbuf->vb_size)) {
+ ret = -EFAULT;
goto done;
}
- cmdbuf.vb_addr = kvb_addr;
+ cmdbuf->vb_addr = kvb_addr;
}
- if (cmdbuf.nbox) {
- kbox_addr = drm_alloc(cmdbuf.nbox * sizeof(struct drm_clip_rect),
+ if (cmdbuf->nbox) {
+ kbox_addr = drm_alloc(cmdbuf->nbox * sizeof(struct drm_clip_rect),
DRM_MEM_DRIVER);
if (kbox_addr == NULL) {
- ret = DRM_ERR(ENOMEM);
+ ret = -ENOMEM;
goto done;
}
- if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf.box_addr,
- cmdbuf.nbox * sizeof(struct drm_clip_rect))) {
- ret = DRM_ERR(EFAULT);
+ if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf->box_addr,
+ cmdbuf->nbox * sizeof(struct drm_clip_rect))) {
+ ret = -EFAULT;
goto done;
}
- cmdbuf.box_addr = kbox_addr;
+ cmdbuf->box_addr = kbox_addr;
}
/* Make sure writes to DMA buffers are finished before sending
@@ -1044,10 +1040,10 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
i = 0;
first_draw_cmd = NULL;
- while (i < cmdbuf.size) {
+ while (i < cmdbuf->size) {
drm_savage_cmd_header_t cmd_header;
- cmd_header = *(drm_savage_cmd_header_t *)cmdbuf.cmd_addr;
- cmdbuf.cmd_addr++;
+ cmd_header = *(drm_savage_cmd_header_t *)cmdbuf->cmd_addr;
+ cmdbuf->cmd_addr++;
i++;
/* Group drawing commands with same state to minimize
@@ -1057,28 +1053,28 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
case SAVAGE_CMD_DMA_IDX:
case SAVAGE_CMD_VB_IDX:
j = (cmd_header.idx.count + 3) / 4;
- if (i + j > cmdbuf.size) {
+ if (i + j > cmdbuf->size) {
DRM_ERROR("indexed drawing command extends "
"beyond end of command buffer\n");
DMA_FLUSH();
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/* fall through */
case SAVAGE_CMD_DMA_PRIM:
case SAVAGE_CMD_VB_PRIM:
if (!first_draw_cmd)
- first_draw_cmd = cmdbuf.cmd_addr - 1;
- cmdbuf.cmd_addr += j;
+ first_draw_cmd = cmdbuf->cmd_addr - 1;
+ cmdbuf->cmd_addr += j;
i += j;
break;
default:
if (first_draw_cmd) {
ret = savage_dispatch_draw(
dev_priv, first_draw_cmd,
- cmdbuf.cmd_addr - 1,
- dmabuf, cmdbuf.vb_addr, cmdbuf.vb_size,
- cmdbuf.vb_stride,
- cmdbuf.nbox, cmdbuf.box_addr);
+ cmdbuf->cmd_addr - 1,
+ dmabuf, cmdbuf->vb_addr, cmdbuf->vb_size,
+ cmdbuf->vb_stride,
+ cmdbuf->nbox, cmdbuf->box_addr);
if (ret != 0)
return ret;
first_draw_cmd = NULL;
@@ -1090,40 +1086,42 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
switch (cmd_header.cmd.cmd) {
case SAVAGE_CMD_STATE:
j = (cmd_header.state.count + 1) / 2;
- if (i + j > cmdbuf.size) {
+ if (i + j > cmdbuf->size) {
DRM_ERROR("command SAVAGE_CMD_STATE extends "
"beyond end of command buffer\n");
DMA_FLUSH();
- ret = DRM_ERR(EINVAL);
+ ret = -EINVAL;
goto done;
}
ret = savage_dispatch_state(dev_priv, &cmd_header,
- (const uint32_t *)cmdbuf.cmd_addr);
- cmdbuf.cmd_addr += j;
+ (const uint32_t *)cmdbuf->cmd_addr);
+ cmdbuf->cmd_addr += j;
i += j;
break;
case SAVAGE_CMD_CLEAR:
- if (i + 1 > cmdbuf.size) {
+ if (i + 1 > cmdbuf->size) {
DRM_ERROR("command SAVAGE_CMD_CLEAR extends "
"beyond end of command buffer\n");
DMA_FLUSH();
- ret = DRM_ERR(EINVAL);
+ ret = -EINVAL;
goto done;
}
ret = savage_dispatch_clear(dev_priv, &cmd_header,
- cmdbuf.cmd_addr,
- cmdbuf.nbox, cmdbuf.box_addr);
- cmdbuf.cmd_addr++;
+ cmdbuf->cmd_addr,
+ cmdbuf->nbox,
+ cmdbuf->box_addr);
+ cmdbuf->cmd_addr++;
i++;
break;
case SAVAGE_CMD_SWAP:
- ret = savage_dispatch_swap(dev_priv, cmdbuf.nbox,
- cmdbuf.box_addr);
+ ret = savage_dispatch_swap(dev_priv, cmdbuf->nbox,
+ cmdbuf->box_addr);
break;
default:
- DRM_ERROR("invalid command 0x%x\n", cmd_header.cmd.cmd);
+ DRM_ERROR("invalid command 0x%x\n",
+ cmd_header.cmd.cmd);
DMA_FLUSH();
- ret = DRM_ERR(EINVAL);
+ ret = -EINVAL;
goto done;
}
@@ -1135,9 +1133,9 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
if (first_draw_cmd) {
ret = savage_dispatch_draw (
- dev_priv, first_draw_cmd, cmdbuf.cmd_addr, dmabuf,
- cmdbuf.vb_addr, cmdbuf.vb_size, cmdbuf.vb_stride,
- cmdbuf.nbox, cmdbuf.box_addr);
+ dev_priv, first_draw_cmd, cmdbuf->cmd_addr, dmabuf,
+ cmdbuf->vb_addr, cmdbuf->vb_size, cmdbuf->vb_stride,
+ cmdbuf->nbox, cmdbuf->box_addr);
if (ret != 0) {
DMA_FLUSH();
goto done;
@@ -1146,7 +1144,7 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
DMA_FLUSH();
- if (dmabuf && cmdbuf.discard) {
+ if (dmabuf && cmdbuf->discard) {
drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private;
uint16_t event;
event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D);
@@ -1156,9 +1154,9 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
done:
/* If we didn't need to allocate them, these'll be NULL */
- drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER);
- drm_free(kvb_addr, cmdbuf.vb_size, DRM_MEM_DRIVER);
- drm_free(kbox_addr, cmdbuf.nbox * sizeof(struct drm_clip_rect),
+ drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER);
+ drm_free(kvb_addr, cmdbuf->vb_size, DRM_MEM_DRIVER);
+ drm_free(kbox_addr, cmdbuf->nbox * sizeof(struct drm_clip_rect),
DRM_MEM_DRIVER);
return ret;
diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c
index 1912f585705..7dacc64e9b5 100644
--- a/drivers/char/drm/sis_drv.c
+++ b/drivers/char/drm/sis_drv.c
@@ -42,7 +42,7 @@ static int sis_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv = drm_calloc(1, sizeof(drm_sis_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
dev->dev_private = (void *)dev_priv;
dev_priv->chipset = chipset;
diff --git a/drivers/char/drm/sis_drv.h b/drivers/char/drm/sis_drv.h
index 5630df87435..ef940bad63f 100644
--- a/drivers/char/drm/sis_drv.h
+++ b/drivers/char/drm/sis_drv.h
@@ -63,10 +63,11 @@ typedef struct drm_sis_private {
} drm_sis_private_t;
extern int sis_idle(struct drm_device *dev);
-extern void sis_reclaim_buffers_locked(struct drm_device *dev, struct file *filp);
+extern void sis_reclaim_buffers_locked(struct drm_device *dev,
+ struct drm_file *file_priv);
extern void sis_lastclose(struct drm_device *dev);
-extern drm_ioctl_desc_t sis_ioctls[];
+extern struct drm_ioctl_desc sis_ioctls[];
extern int sis_max_ioctl;
#endif
diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c
index 441bbdbf151..a6b7ccdaf73 100644
--- a/drivers/char/drm/sis_mm.c
+++ b/drivers/char/drm/sis_mm.c
@@ -28,7 +28,7 @@
/*
* Authors:
- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include "drmP.h"
@@ -82,15 +82,12 @@ static unsigned long sis_sman_mm_offset(void *private, void *ref)
#endif /* CONFIG_FB_SIS */
-static int sis_fb_init(DRM_IOCTL_ARGS)
+static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_fb_t fb;
+ drm_sis_fb_t *fb = data;
int ret;
- DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb));
-
mutex_lock(&dev->struct_mutex);
#if defined(CONFIG_FB_SIS)
{
@@ -105,7 +102,7 @@ static int sis_fb_init(DRM_IOCTL_ARGS)
}
#else
ret = drm_sman_set_range(&dev_priv->sman, VIDEO_TYPE, 0,
- fb.size >> SIS_MM_ALIGN_SHIFT);
+ fb->size >> SIS_MM_ALIGN_SHIFT);
#endif
if (ret) {
@@ -115,98 +112,88 @@ static int sis_fb_init(DRM_IOCTL_ARGS)
}
dev_priv->vram_initialized = 1;
- dev_priv->vram_offset = fb.offset;
+ dev_priv->vram_offset = fb->offset;
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
+ DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size);
return 0;
}
-static int sis_drm_alloc(struct drm_device *dev, struct drm_file * priv,
- unsigned long data, int pool)
+static int sis_drm_alloc(struct drm_device *dev, struct drm_file *file_priv,
+ void *data, int pool)
{
drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *) data;
- drm_sis_mem_t mem;
+ drm_sis_mem_t *mem = data;
int retval = 0;
struct drm_memblock_item *item;
- DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem));
-
mutex_lock(&dev->struct_mutex);
if (0 == ((pool == 0) ? dev_priv->vram_initialized :
dev_priv->agp_initialized)) {
DRM_ERROR
("Attempt to allocate from uninitialized memory manager.\n");
- return DRM_ERR(EINVAL);
+ mutex_unlock(&dev->struct_mutex);
+ return -EINVAL;
}
- mem.size = (mem.size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
- item = drm_sman_alloc(&dev_priv->sman, pool, mem.size, 0,
- (unsigned long)priv);
+ mem->size = (mem->size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
+ item = drm_sman_alloc(&dev_priv->sman, pool, mem->size, 0,
+ (unsigned long)file_priv);
mutex_unlock(&dev->struct_mutex);
if (item) {
- mem.offset = ((pool == 0) ?
+ mem->offset = ((pool == 0) ?
dev_priv->vram_offset : dev_priv->agp_offset) +
(item->mm->
offset(item->mm, item->mm_info) << SIS_MM_ALIGN_SHIFT);
- mem.free = item->user_hash.key;
- mem.size = mem.size << SIS_MM_ALIGN_SHIFT;
+ mem->free = item->user_hash.key;
+ mem->size = mem->size << SIS_MM_ALIGN_SHIFT;
} else {
- mem.offset = 0;
- mem.size = 0;
- mem.free = 0;
- retval = DRM_ERR(ENOMEM);
+ mem->offset = 0;
+ mem->size = 0;
+ mem->free = 0;
+ retval = -ENOMEM;
}
- DRM_COPY_TO_USER_IOCTL(argp, mem, sizeof(mem));
-
- DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem.size,
- mem.offset);
+ DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem->size,
+ mem->offset);
return retval;
}
-static int sis_drm_free(DRM_IOCTL_ARGS)
+static int sis_drm_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_mem_t mem;
+ drm_sis_mem_t *mem = data;
int ret;
- DRM_COPY_FROM_USER_IOCTL(mem, (drm_sis_mem_t __user *) data,
- sizeof(mem));
-
mutex_lock(&dev->struct_mutex);
- ret = drm_sman_free_key(&dev_priv->sman, mem.free);
+ ret = drm_sman_free_key(&dev_priv->sman, mem->free);
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("free = 0x%lx\n", mem.free);
+ DRM_DEBUG("free = 0x%lx\n", mem->free);
return ret;
}
-static int sis_fb_alloc(DRM_IOCTL_ARGS)
+static int sis_fb_alloc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
- return sis_drm_alloc(dev, priv, data, VIDEO_TYPE);
+ return sis_drm_alloc(dev, file_priv, data, VIDEO_TYPE);
}
-static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
+static int sis_ioctl_agp_init(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_agp_t agp;
+ drm_sis_agp_t *agp = data;
int ret;
dev_priv = dev->dev_private;
- DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data,
- sizeof(agp));
mutex_lock(&dev->struct_mutex);
ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0,
- agp.size >> SIS_MM_ALIGN_SHIFT);
+ agp->size >> SIS_MM_ALIGN_SHIFT);
if (ret) {
DRM_ERROR("AGP memory manager initialisation error\n");
@@ -215,18 +202,18 @@ static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
}
dev_priv->agp_initialized = 1;
- dev_priv->agp_offset = agp.offset;
+ dev_priv->agp_offset = agp->offset;
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
+ DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size);
return 0;
}
-static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS)
+static int sis_ioctl_agp_alloc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
- return sis_drm_alloc(dev, priv, data, AGP_TYPE);
+ return sis_drm_alloc(dev, file_priv, data, AGP_TYPE);
}
static drm_local_map_t *sis_reg_init(struct drm_device *dev)
@@ -314,13 +301,13 @@ void sis_lastclose(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
}
-void sis_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
+void sis_reclaim_buffers_locked(struct drm_device * dev,
+ struct drm_file *file_priv)
{
drm_sis_private_t *dev_priv = dev->dev_private;
- struct drm_file *priv = filp->private_data;
mutex_lock(&dev->struct_mutex);
- if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
+ if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)file_priv)) {
mutex_unlock(&dev->struct_mutex);
return;
}
@@ -329,20 +316,18 @@ void sis_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
dev->driver->dma_quiescent(dev);
}
- drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
+ drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv);
mutex_unlock(&dev->struct_mutex);
return;
}
-drm_ioctl_desc_t sis_ioctls[] = {
- [DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_drm_free, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] =
- {sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_drm_free, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] =
- {sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}
+struct drm_ioctl_desc sis_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_SIS_FB_ALLOC, sis_fb_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_SIS_FB_FREE, sis_drm_free, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_SIS_AGP_INIT, sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_SIS_AGP_ALLOC, sis_ioctl_agp_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_SIS_AGP_FREE, sis_drm_free, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_SIS_FB_INIT, sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
};
int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index 7ff2b623c2d..75d6b748c2c 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -175,24 +175,24 @@ static int via_initialize(struct drm_device * dev,
{
if (!dev_priv || !dev_priv->mmio) {
DRM_ERROR("via_dma_init called before via_map_init\n");
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (dev_priv->ring.virtual_start != NULL) {
DRM_ERROR("%s called again without calling cleanup\n",
__FUNCTION__);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (!dev->agp || !dev->agp->base) {
DRM_ERROR("%s called with no agp memory available\n",
__FUNCTION__);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (dev_priv->chipset == VIA_DX9_0) {
DRM_ERROR("AGP DMA is not supported on this chip\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
dev_priv->ring.map.offset = dev->agp->base + init->offset;
@@ -207,7 +207,7 @@ static int via_initialize(struct drm_device * dev,
via_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
@@ -227,35 +227,31 @@ static int via_initialize(struct drm_device * dev,
return 0;
}
-static int via_dma_init(DRM_IOCTL_ARGS)
+static int via_dma_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- drm_via_dma_init_t init;
+ drm_via_dma_init_t *init = data;
int retcode = 0;
- DRM_COPY_FROM_USER_IOCTL(init, (drm_via_dma_init_t __user *) data,
- sizeof(init));
-
- switch (init.func) {
+ switch (init->func) {
case VIA_INIT_DMA:
if (!DRM_SUSER(DRM_CURPROC))
- retcode = DRM_ERR(EPERM);
+ retcode = -EPERM;
else
- retcode = via_initialize(dev, dev_priv, &init);
+ retcode = via_initialize(dev, dev_priv, init);
break;
case VIA_CLEANUP_DMA:
if (!DRM_SUSER(DRM_CURPROC))
- retcode = DRM_ERR(EPERM);
+ retcode = -EPERM;
else
retcode = via_dma_cleanup(dev);
break;
case VIA_DMA_INITIALIZED:
retcode = (dev_priv->ring.virtual_start != NULL) ?
- 0 : DRM_ERR(EFAULT);
+ 0 : -EFAULT;
break;
default:
- retcode = DRM_ERR(EINVAL);
+ retcode = -EINVAL;
break;
}
@@ -273,15 +269,15 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t *
if (dev_priv->ring.virtual_start == NULL) {
DRM_ERROR("%s called without initializing AGP ring buffer.\n",
__FUNCTION__);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
if (cmd->size > VIA_PCI_BUF_SIZE) {
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
/*
* Running this function on AGP memory is dead slow. Therefore
@@ -297,7 +293,7 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t *
vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size);
if (vb == NULL) {
- return DRM_ERR(EAGAIN);
+ return -EAGAIN;
}
memcpy(vb, dev_priv->pci_buf, cmd->size);
@@ -321,34 +317,30 @@ int via_driver_dma_quiescent(struct drm_device * dev)
drm_via_private_t *dev_priv = dev->dev_private;
if (!via_wait_idle(dev_priv)) {
- return DRM_ERR(EBUSY);
+ return -EBUSY;
}
return 0;
}
-static int via_flush_ioctl(DRM_IOCTL_ARGS)
+static int via_flush_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
return via_driver_dma_quiescent(dev);
}
-static int via_cmdbuffer(DRM_IOCTL_ARGS)
+static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_cmdbuffer_t cmdbuf;
+ drm_via_cmdbuffer_t *cmdbuf = data;
int ret;
- LOCK_TEST_WITH_RETURN(dev, filp);
-
- DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t __user *) data,
- sizeof(cmdbuf));
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size);
+ DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf->buf,
+ cmdbuf->size);
- ret = via_dispatch_cmdbuffer(dev, &cmdbuf);
+ ret = via_dispatch_cmdbuffer(dev, cmdbuf);
if (ret) {
return ret;
}
@@ -363,10 +355,10 @@ static int via_dispatch_pci_cmdbuffer(struct drm_device * dev,
int ret;
if (cmd->size > VIA_PCI_BUF_SIZE) {
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
- return DRM_ERR(EFAULT);
+ return -EFAULT;
if ((ret =
via_verify_command_stream((uint32_t *) dev_priv->pci_buf,
@@ -380,21 +372,17 @@ static int via_dispatch_pci_cmdbuffer(struct drm_device * dev,
return ret;
}
-static int via_pci_cmdbuffer(DRM_IOCTL_ARGS)
+static int via_pci_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_cmdbuffer_t cmdbuf;
+ drm_via_cmdbuffer_t *cmdbuf = data;
int ret;
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t __user *) data,
- sizeof(cmdbuf));
+ DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf->buf,
+ cmdbuf->size);
- DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf.buf,
- cmdbuf.size);
-
- ret = via_dispatch_pci_cmdbuffer(dev, &cmdbuf);
+ ret = via_dispatch_pci_cmdbuffer(dev, cmdbuf);
if (ret) {
return ret;
}
@@ -653,80 +641,74 @@ static void via_cmdbuf_reset(drm_via_private_t * dev_priv)
* User interface to the space and lag functions.
*/
-static int via_cmdbuf_size(DRM_IOCTL_ARGS)
+static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_cmdbuf_size_t d_siz;
+ drm_via_cmdbuf_size_t *d_siz = data;
int ret = 0;
uint32_t tmp_size, count;
drm_via_private_t *dev_priv;
DRM_DEBUG("via cmdbuf_size\n");
- LOCK_TEST_WITH_RETURN(dev, filp);
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
dev_priv = (drm_via_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start == NULL) {
DRM_ERROR("%s called without initializing AGP ring buffer.\n",
__FUNCTION__);
- return DRM_ERR(EFAULT);
+ return -EFAULT;
}
- DRM_COPY_FROM_USER_IOCTL(d_siz, (drm_via_cmdbuf_size_t __user *) data,
- sizeof(d_siz));
-
count = 1000000;
- tmp_size = d_siz.size;
- switch (d_siz.func) {
+ tmp_size = d_siz->size;
+ switch (d_siz->func) {
case VIA_CMDBUF_SPACE:
- while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz.size)
+ while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz->size)
&& count--) {
- if (!d_siz.wait) {
+ if (!d_siz->wait) {
break;
}
}
if (!count) {
DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n");
- ret = DRM_ERR(EAGAIN);
+ ret = -EAGAIN;
}
break;
case VIA_CMDBUF_LAG:
- while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz.size)
+ while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz->size)
&& count--) {
- if (!d_siz.wait) {
+ if (!d_siz->wait) {
break;
}
}
if (!count) {
DRM_ERROR("VIA_CMDBUF_LAG timed out.\n");
- ret = DRM_ERR(EAGAIN);
+ ret = -EAGAIN;
}
break;
default:
- ret = DRM_ERR(EFAULT);
+ ret = -EFAULT;
}
- d_siz.size = tmp_size;
+ d_siz->size = tmp_size;
- DRM_COPY_TO_USER_IOCTL((drm_via_cmdbuf_size_t __user *) data, d_siz,
- sizeof(d_siz));
return ret;
}
-drm_ioctl_desc_t via_ioctls[] = {
- [DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, DRM_AUTH|DRM_MASTER},
- [DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, DRM_AUTH|DRM_MASTER},
- [DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, DRM_AUTH|DRM_MASTER},
- [DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_DMA_BLIT)] = {via_dma_blit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_BLIT_SYNC)] = {via_dma_blit_sync, DRM_AUTH}
+struct drm_ioctl_desc via_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_FREEMEM, via_mem_free, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER),
+ DRM_IOCTL_DEF(DRM_VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER),
+ DRM_IOCTL_DEF(DRM_VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER),
+ DRM_IOCTL_DEF(DRM_VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_DMA_INIT, via_dma_init, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_FLUSH, via_flush_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_DMA_BLIT, via_dma_blit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH)
};
int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls);
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index 3dd1ed3d1bf..c6fd16f3cb4 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -237,7 +237,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
first_pfn + 1;
if (NULL == (vsg->pages = vmalloc(sizeof(struct page *) * vsg->num_pages)))
- return DRM_ERR(ENOMEM);
+ 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,
@@ -251,7 +251,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
if (ret < 0)
return ret;
vsg->state = dr_via_pages_locked;
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
vsg->state = dr_via_pages_locked;
DRM_DEBUG("DMA pages locked\n");
@@ -274,13 +274,13 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg)
vsg->descriptors_per_page;
if (NULL == (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL)))
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
vsg->state = dr_via_desc_pages_alloc;
for (i=0; i<vsg->num_desc_pages; ++i) {
if (NULL == (vsg->desc_pages[i] =
(drm_via_descriptor_t *) __get_free_page(GFP_KERNEL)))
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
DRM_DEBUG("Allocated %d pages for %d descriptors.\n", vsg->num_desc_pages,
vsg->num_desc);
@@ -593,7 +593,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
if (xfer->num_lines <= 0 || xfer->line_length <= 0) {
DRM_ERROR("Zero size bitblt.\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/*
@@ -606,7 +606,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
if ((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) {
DRM_ERROR("Too large system memory stride. Stride: %d, "
"Length: %d\n", xfer->mem_stride, xfer->line_length);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if ((xfer->mem_stride == xfer->line_length) &&
@@ -624,7 +624,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) {
DRM_ERROR("Too large PCI DMA bitblt.\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/*
@@ -635,7 +635,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
if (xfer->mem_stride < xfer->line_length ||
abs(xfer->fb_stride) < xfer->line_length) {
DRM_ERROR("Invalid frame-buffer / memory stride.\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
/*
@@ -648,7 +648,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) ||
((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) {
DRM_ERROR("Invalid DRM bitblt alignment.\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
#else
if ((((unsigned long)xfer->mem_addr & 15) ||
@@ -656,7 +656,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
((xfer->num_lines > 1) &&
((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) {
DRM_ERROR("Invalid DRM bitblt alignment.\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
#endif
@@ -696,7 +696,7 @@ via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine)
DRM_WAIT_ON(ret, blitq->busy_queue, DRM_HZ, blitq->num_free > 0);
if (ret) {
- return (DRM_ERR(EINTR) == ret) ? DRM_ERR(EAGAIN) : ret;
+ return (-EINTR == ret) ? -EAGAIN : ret;
}
spin_lock_irqsave(&blitq->blit_lock, irqsave);
@@ -740,7 +740,7 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
if (dev_priv == NULL) {
DRM_ERROR("Called without initialization.\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
engine = (xfer->to_fb) ? 0 : 1;
@@ -750,7 +750,7 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
}
if (NULL == (vsg = kmalloc(sizeof(*vsg), GFP_KERNEL))) {
via_dmablit_release_slot(blitq);
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
}
if (0 != (ret = via_build_sg_info(dev, vsg, xfer))) {
via_dmablit_release_slot(blitq);
@@ -781,21 +781,18 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
*/
int
-via_dma_blit_sync( DRM_IOCTL_ARGS )
+via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv )
{
- drm_via_blitsync_t sync;
+ drm_via_blitsync_t *sync = data;
int err;
- DRM_DEVICE;
- DRM_COPY_FROM_USER_IOCTL(sync, (drm_via_blitsync_t *)data, sizeof(sync));
-
- if (sync.engine >= VIA_NUM_BLIT_ENGINES)
- return DRM_ERR(EINVAL);
+ if (sync->engine >= VIA_NUM_BLIT_ENGINES)
+ return -EINVAL;
- err = via_dmablit_sync(dev, sync.sync_handle, sync.engine);
+ err = via_dmablit_sync(dev, sync->sync_handle, sync->engine);
- if (DRM_ERR(EINTR) == err)
- err = DRM_ERR(EAGAIN);
+ if (-EINTR == err)
+ err = -EAGAIN;
return err;
}
@@ -808,17 +805,12 @@ via_dma_blit_sync( DRM_IOCTL_ARGS )
*/
int
-via_dma_blit( DRM_IOCTL_ARGS )
+via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv )
{
- drm_via_dmablit_t xfer;
+ drm_via_dmablit_t *xfer = data;
int err;
- DRM_DEVICE;
-
- DRM_COPY_FROM_USER_IOCTL(xfer, (drm_via_dmablit_t __user *)data, sizeof(xfer));
-
- err = via_dmablit(dev, &xfer);
- DRM_COPY_TO_USER_IOCTL((void __user *)data, xfer, sizeof(xfer));
+ err = via_dmablit(dev, xfer);
return err;
}
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index 576711564a1..2daae81874c 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -110,18 +110,18 @@ enum via_family {
#define VIA_READ8(reg) DRM_READ8(VIA_BASE, reg)
#define VIA_WRITE8(reg,val) DRM_WRITE8(VIA_BASE, reg, val)
-extern drm_ioctl_desc_t via_ioctls[];
+extern struct drm_ioctl_desc via_ioctls[];
extern int via_max_ioctl;
-extern int via_fb_init(DRM_IOCTL_ARGS);
-extern int via_mem_alloc(DRM_IOCTL_ARGS);
-extern int via_mem_free(DRM_IOCTL_ARGS);
-extern int via_agp_init(DRM_IOCTL_ARGS);
-extern int via_map_init(DRM_IOCTL_ARGS);
-extern int via_decoder_futex(DRM_IOCTL_ARGS);
-extern int via_wait_irq(DRM_IOCTL_ARGS);
-extern int via_dma_blit_sync( DRM_IOCTL_ARGS );
-extern int via_dma_blit( DRM_IOCTL_ARGS );
+extern int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv );
+extern int via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv );
extern int via_driver_load(struct drm_device *dev, unsigned long chipset);
extern int via_driver_unload(struct drm_device *dev);
@@ -144,7 +144,7 @@ extern void via_init_futex(drm_via_private_t * dev_priv);
extern void via_cleanup_futex(drm_via_private_t * dev_priv);
extern void via_release_futex(drm_via_private_t * dev_priv, int context);
-extern void via_reclaim_buffers_locked(struct drm_device *dev, struct file *filp);
+extern void via_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv);
extern void via_lastclose(struct drm_device *dev);
extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq);
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
index 8dc99b5fbab..9c1d52bc92d 100644
--- a/drivers/char/drm/via_irq.c
+++ b/drivers/char/drm/via_irq.c
@@ -205,13 +205,13 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
if (irq >= drm_via_irq_num) {
DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
irq);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
real_irq = dev_priv->irq_map[irq];
@@ -219,7 +219,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc
if (real_irq < 0) {
DRM_ERROR("%s Video IRQ %d not available on this hardware.\n",
__FUNCTION__, irq);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
masks = dev_priv->irq_masks;
@@ -331,11 +331,9 @@ void via_driver_irq_uninstall(struct drm_device * dev)
}
}
-int via_wait_irq(DRM_IOCTL_ARGS)
+int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_irqwait_t __user *argp = (void __user *)data;
- drm_via_irqwait_t irqwait;
+ drm_via_irqwait_t *irqwait = data;
struct timeval now;
int ret = 0;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
@@ -343,42 +341,39 @@ int via_wait_irq(DRM_IOCTL_ARGS)
int force_sequence;
if (!dev->irq)
- return DRM_ERR(EINVAL);
+ return -EINVAL;
- DRM_COPY_FROM_USER_IOCTL(irqwait, argp, sizeof(irqwait));
- if (irqwait.request.irq >= dev_priv->num_irqs) {
+ if (irqwait->request.irq >= dev_priv->num_irqs) {
DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
- irqwait.request.irq);
- return DRM_ERR(EINVAL);
+ irqwait->request.irq);
+ return -EINVAL;
}
- cur_irq += irqwait.request.irq;
+ cur_irq += irqwait->request.irq;
- switch (irqwait.request.type & ~VIA_IRQ_FLAGS_MASK) {
+ switch (irqwait->request.type & ~VIA_IRQ_FLAGS_MASK) {
case VIA_IRQ_RELATIVE:
- irqwait.request.sequence += atomic_read(&cur_irq->irq_received);
- irqwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+ irqwait->request.sequence += atomic_read(&cur_irq->irq_received);
+ irqwait->request.type &= ~_DRM_VBLANK_RELATIVE;
case VIA_IRQ_ABSOLUTE:
break;
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- if (irqwait.request.type & VIA_IRQ_SIGNAL) {
+ if (irqwait->request.type & VIA_IRQ_SIGNAL) {
DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n",
__FUNCTION__);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- force_sequence = (irqwait.request.type & VIA_IRQ_FORCE_SEQUENCE);
+ force_sequence = (irqwait->request.type & VIA_IRQ_FORCE_SEQUENCE);
- ret = via_driver_irq_wait(dev, irqwait.request.irq, force_sequence,
- &irqwait.request.sequence);
+ ret = via_driver_irq_wait(dev, irqwait->request.irq, force_sequence,
+ &irqwait->request.sequence);
do_gettimeofday(&now);
- irqwait.reply.tval_sec = now.tv_sec;
- irqwait.reply.tval_usec = now.tv_usec;
-
- DRM_COPY_TO_USER_IOCTL(argp, irqwait, sizeof(irqwait));
+ irqwait->reply.tval_sec = now.tv_sec;
+ irqwait->reply.tval_usec = now.tv_usec;
return ret;
}
diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c
index 7fb9d2a2cce..10091507a0d 100644
--- a/drivers/char/drm/via_map.c
+++ b/drivers/char/drm/via_map.c
@@ -75,19 +75,15 @@ int via_do_cleanup_map(struct drm_device * dev)
return 0;
}
-int via_map_init(DRM_IOCTL_ARGS)
+int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_init_t init;
+ drm_via_init_t *init = data;
DRM_DEBUG("%s\n", __FUNCTION__);
- DRM_COPY_FROM_USER_IOCTL(init, (drm_via_init_t __user *) data,
- sizeof(init));
-
- switch (init.func) {
+ switch (init->func) {
case VIA_INIT_MAP:
- return via_do_init_map(dev, &init);
+ return via_do_init_map(dev, init);
case VIA_CLEANUP_MAP:
return via_do_cleanup_map(dev);
}
@@ -102,7 +98,7 @@ int via_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
- return DRM_ERR(ENOMEM);
+ return -ENOMEM;
dev->dev_private = (void *)dev_priv;
diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c
index 85d56acd9d8..3ffbf864983 100644
--- a/drivers/char/drm/via_mm.c
+++ b/drivers/char/drm/via_mm.c
@@ -22,7 +22,7 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
- * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include "drmP.h"
@@ -33,18 +33,15 @@
#define VIA_MM_ALIGN_SHIFT 4
#define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1)
-int via_agp_init(DRM_IOCTL_ARGS)
+int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_agp_t agp;
+ drm_via_agp_t *agp = data;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
int ret;
- DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t __user *) data,
- sizeof(agp));
mutex_lock(&dev->struct_mutex);
ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_AGP, 0,
- agp.size >> VIA_MM_ALIGN_SHIFT);
+ agp->size >> VIA_MM_ALIGN_SHIFT);
if (ret) {
DRM_ERROR("AGP memory manager initialisation error\n");
@@ -53,25 +50,22 @@ int via_agp_init(DRM_IOCTL_ARGS)
}
dev_priv->agp_initialized = 1;
- dev_priv->agp_offset = agp.offset;
+ dev_priv->agp_offset = agp->offset;
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
+ DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size);
return 0;
}
-int via_fb_init(DRM_IOCTL_ARGS)
+int via_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_fb_t fb;
+ drm_via_fb_t *fb = data;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
int ret;
- DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t __user *) data, sizeof(fb));
-
mutex_lock(&dev->struct_mutex);
ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_VIDEO, 0,
- fb.size >> VIA_MM_ALIGN_SHIFT);
+ fb->size >> VIA_MM_ALIGN_SHIFT);
if (ret) {
DRM_ERROR("VRAM memory manager initialisation error\n");
@@ -80,10 +74,10 @@ int via_fb_init(DRM_IOCTL_ARGS)
}
dev_priv->vram_initialized = 1;
- dev_priv->vram_offset = fb.offset;
+ dev_priv->vram_offset = fb->offset;
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
+ DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size);
return 0;
@@ -121,80 +115,71 @@ void via_lastclose(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
}
-int via_mem_alloc(DRM_IOCTL_ARGS)
+int via_mem_alloc(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
{
- DRM_DEVICE;
-
- drm_via_mem_t mem;
+ drm_via_mem_t *mem = data;
int retval = 0;
struct drm_memblock_item *item;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
unsigned long tmpSize;
- DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
- sizeof(mem));
-
- if (mem.type > VIA_MEM_AGP) {
+ if (mem->type > VIA_MEM_AGP) {
DRM_ERROR("Unknown memory type allocation\n");
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
mutex_lock(&dev->struct_mutex);
- if (0 == ((mem.type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
+ if (0 == ((mem->type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
dev_priv->agp_initialized)) {
DRM_ERROR
("Attempt to allocate from uninitialized memory manager.\n");
mutex_unlock(&dev->struct_mutex);
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
- tmpSize = (mem.size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
- item = drm_sman_alloc(&dev_priv->sman, mem.type, tmpSize, 0,
- (unsigned long)priv);
+ tmpSize = (mem->size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
+ item = drm_sman_alloc(&dev_priv->sman, mem->type, tmpSize, 0,
+ (unsigned long)file_priv);
mutex_unlock(&dev->struct_mutex);
if (item) {
- mem.offset = ((mem.type == VIA_MEM_VIDEO) ?
+ mem->offset = ((mem->type == VIA_MEM_VIDEO) ?
dev_priv->vram_offset : dev_priv->agp_offset) +
(item->mm->
offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT);
- mem.index = item->user_hash.key;
+ mem->index = item->user_hash.key;
} else {
- mem.offset = 0;
- mem.size = 0;
- mem.index = 0;
+ mem->offset = 0;
+ mem->size = 0;
+ mem->index = 0;
DRM_DEBUG("Video memory allocation failed\n");
- retval = DRM_ERR(ENOMEM);
+ retval = -ENOMEM;
}
- DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, sizeof(mem));
return retval;
}
-int via_mem_free(DRM_IOCTL_ARGS)
+int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_via_private_t *dev_priv = dev->dev_private;
- drm_via_mem_t mem;
+ drm_via_mem_t *mem = data;
int ret;
- DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
- sizeof(mem));
-
mutex_lock(&dev->struct_mutex);
- ret = drm_sman_free_key(&dev_priv->sman, mem.index);
+ ret = drm_sman_free_key(&dev_priv->sman, mem->index);
mutex_unlock(&dev->struct_mutex);
- DRM_DEBUG("free = 0x%lx\n", mem.index);
+ DRM_DEBUG("free = 0x%lx\n", mem->index);
return ret;
}
-void via_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
+void via_reclaim_buffers_locked(struct drm_device * dev,
+ struct drm_file *file_priv)
{
drm_via_private_t *dev_priv = dev->dev_private;
- struct drm_file *priv = filp->private_data;
mutex_lock(&dev->struct_mutex);
- if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
+ if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)file_priv)) {
mutex_unlock(&dev->struct_mutex);
return;
}
@@ -203,7 +188,7 @@ void via_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
dev->driver->dma_quiescent(dev);
}
- drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
+ drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv);
mutex_unlock(&dev->struct_mutex);
return;
}
diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c
index 832d48356e9..46a57919874 100644
--- a/drivers/char/drm/via_verifier.c
+++ b/drivers/char/drm/via_verifier.c
@@ -1026,12 +1026,12 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
case state_error:
default:
*hc_state = saved_state;
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
if (state == state_error) {
*hc_state = saved_state;
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
}
@@ -1082,11 +1082,11 @@ via_parse_command_stream(struct drm_device * dev, const uint32_t * buf,
break;
case state_error:
default:
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
}
if (state == state_error) {
- return DRM_ERR(EINVAL);
+ return -EINVAL;
}
return 0;
}
diff --git a/drivers/char/drm/via_verifier.h b/drivers/char/drm/via_verifier.h
index 28b50296a7b..d6f8214b69f 100644
--- a/drivers/char/drm/via_verifier.h
+++ b/drivers/char/drm/via_verifier.h
@@ -20,7 +20,7 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
- * Author: Thomas Hellström 2004.
+ * Author: Thomas Hellström 2004.
*/
#ifndef _VIA_VERIFIER_H_
diff --git a/drivers/char/drm/via_video.c b/drivers/char/drm/via_video.c
index 300ac61b09e..c15e75b54cb 100644
--- a/drivers/char/drm/via_video.c
+++ b/drivers/char/drm/via_video.c
@@ -65,10 +65,9 @@ void via_release_futex(drm_via_private_t * dev_priv, int context)
}
}
-int via_decoder_futex(DRM_IOCTL_ARGS)
+int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_futex_t fx;
+ drm_via_futex_t *fx = data;
volatile int *lock;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
drm_via_sarea_t *sAPriv = dev_priv->sarea_priv;
@@ -76,21 +75,18 @@ int via_decoder_futex(DRM_IOCTL_ARGS)
DRM_DEBUG("%s\n", __FUNCTION__);
- DRM_COPY_FROM_USER_IOCTL(fx, (drm_via_futex_t __user *) data,
- sizeof(fx));
-
- if (fx.lock > VIA_NR_XVMC_LOCKS)
+ if (fx->lock > VIA_NR_XVMC_LOCKS)
return -EFAULT;
- lock = (volatile int *)XVMCLOCKPTR(sAPriv, fx.lock);
+ lock = (volatile int *)XVMCLOCKPTR(sAPriv, fx->lock);
- switch (fx.func) {
+ switch (fx->func) {
case VIA_FUTEX_WAIT:
- DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx.lock],
- (fx.ms / 10) * (DRM_HZ / 100), *lock != fx.val);
+ DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx->lock],
+ (fx->ms / 10) * (DRM_HZ / 100), *lock != fx->val);
return ret;
case VIA_FUTEX_WAKE:
- DRM_WAKEUP(&(dev_priv->decoder_queue[fx.lock]));
+ DRM_WAKEUP(&(dev_priv->decoder_queue[fx->lock]));
return 0;
}
return 0;
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index 9b8278e1f4f..a69c6528326 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -136,7 +136,7 @@ static int sizeof_bootstrap = 375;
static struct dsp56k_device {
- long in_use;
+ unsigned long in_use;
long maxio, timeout;
int tx_wsize, rx_wsize;
} dsp56k;
@@ -513,7 +513,7 @@ static int __init dsp56k_init_driver(void)
err = PTR_ERR(dsp56k_class);
goto out_chrdev;
}
- class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k");
+ device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), "dsp56k");
printk(banner);
goto out;
@@ -527,7 +527,7 @@ module_init(dsp56k_init_driver);
static void __exit dsp56k_cleanup_driver(void)
{
- class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
+ device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
class_destroy(dsp56k_class);
unregister_chrdev(DSP56K_MAJOR, "dsp56k");
}
diff --git a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c
deleted file mode 100644
index 020011495d9..00000000000
--- a/drivers/char/ec3104_keyb.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * linux/drivers/char/ec3104_keyb.c
- *
- * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- *
- * based on linux/drivers/char/pc_keyb.c, which had the following comments:
- *
- * Separation of the PC low-level part by Geert Uytterhoeven, May 1997
- * See keyboard.c for the whole history.
- *
- * Major cleanup by Martin Mares, May 1997
- *
- * Combined the keyboard and PS/2 mouse handling into one file,
- * because they share the same hardware.
- * Johan Myreen <jem@iki.fi> 1998-10-08.
- *
- * Code fixes to handle mouse ACKs properly.
- * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
- */
-/* EC3104 note:
- * This code was written without any documentation about the EC3104 chip. While
- * I hope I got most of the basic functionality right, the register names I use
- * are most likely completely different from those in the chip documentation.
- *
- * If you have any further information about the EC3104, please tell me
- * (prumpf@tux.org).
- */
-
-
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/kbd_ll.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/poll.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/kbd_kern.h>
-#include <linux/bitops.h>
-
-#include <asm/keyboard.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/ec3104.h>
-
-#include <asm/io.h>
-
-/* Some configuration switches are present in the include file... */
-
-#include <linux/pc_keyb.h>
-
-#define MSR_CTS 0x10
-#define MCR_RTS 0x02
-#define LSR_DR 0x01
-#define LSR_BOTH_EMPTY 0x60
-
-static struct e5_struct {
- u8 packet[8];
- int pos;
- int length;
-
- u8 cached_mcr;
- u8 last_msr;
-} ec3104_keyb;
-
-/* Simple translation table for the SysRq keys */
-
-
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned char ec3104_kbd_sysrq_xlate[128] =
- "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
- "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
- "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
- "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
- "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */
- "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
- "\r\000/"; /* 0x60 - 0x6f */
-#endif
-
-static void kbd_write_command_w(int data);
-static void kbd_write_output_w(int data);
-#ifdef CONFIG_PSMOUSE
-static void aux_write_ack(int val);
-static void __aux_write_ack(int val);
-#endif
-
-static DEFINE_SPINLOCK(kbd_controller_lock);
-static unsigned char handle_kbd_event(void);
-
-/* used only by send_data - set by keyboard_interrupt */
-static volatile unsigned char reply_expected;
-static volatile unsigned char acknowledge;
-static volatile unsigned char resend;
-
-
-int ec3104_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
-{
- return 0;
-}
-
-int ec3104_kbd_getkeycode(unsigned int scancode)
-{
- return 0;
-}
-
-
-/* yes, it probably would be faster to use an array. I don't care. */
-
-static inline unsigned char ec3104_scan2key(unsigned char scancode)
-{
- switch (scancode) {
- case 1: /* '`' */
- return 41;
-
- case 2 ... 27:
- return scancode;
-
- case 28: /* '\\' */
- return 43;
-
- case 29 ... 39:
- return scancode + 1;
-
- case 40: /* '\r' */
- return 28;
-
- case 41 ... 50:
- return scancode + 3;
-
- case 51: /* ' ' */
- return 57;
-
- case 52: /* escape */
- return 1;
-
- case 54: /* insert/delete (labelled delete) */
- /* this should arguably be 110, but I'd like to have ctrl-alt-del
- * working with a standard keymap */
- return 111;
-
- case 55: /* left */
- return 105;
- case 56: /* home */
- return 102;
- case 57: /* end */
- return 107;
- case 58: /* up */
- return 103;
- case 59: /* down */
- return 108;
- case 60: /* pgup */
- return 104;
- case 61: /* pgdown */
- return 109;
- case 62: /* right */
- return 106;
-
- case 79 ... 88: /* f1 - f10 */
- return scancode - 20;
-
- case 89 ... 90: /* f11 - f12 */
- return scancode - 2;
-
- case 91: /* left shift */
- return 42;
-
- case 92: /* right shift */
- return 54;
-
- case 93: /* left alt */
- return 56;
- case 94: /* right alt */
- return 100;
- case 95: /* left ctrl */
- return 29;
- case 96: /* right ctrl */
- return 97;
-
- case 97: /* caps lock */
- return 58;
- case 102: /* left windows */
- return 125;
- case 103: /* right windows */
- return 126;
-
- case 106: /* Fn */
- /* this is wrong. */
- return 84;
-
- default:
- return 0;
- }
-}
-
-int ec3104_kbd_translate(unsigned char scancode, unsigned char *keycode,
- char raw_mode)
-{
- scancode &= 0x7f;
-
- *keycode = ec3104_scan2key(scancode);
-
- return 1;
-}
-
-char ec3104_kbd_unexpected_up(unsigned char keycode)
-{
- return 0200;
-}
-
-static inline void handle_keyboard_event(unsigned char scancode)
-{
-#ifdef CONFIG_VT
- handle_scancode(scancode, !(scancode & 0x80));
-#endif
- tasklet_schedule(&keyboard_tasklet);
-}
-
-void ec3104_kbd_leds(unsigned char leds)
-{
-}
-
-static u8 e5_checksum(u8 *packet, int count)
-{
- int i;
- u8 sum = 0;
-
- for (i=0; i<count; i++)
- sum ^= packet[i];
-
- if (sum & 0x80)
- sum ^= 0xc0;
-
- return sum;
-}
-
-static void e5_wait_for_cts(struct e5_struct *k)
-{
- u8 msr;
-
- do {
- msr = ctrl_inb(EC3104_SER4_MSR);
- } while (!(msr & MSR_CTS));
-}
-
-
-static void e5_send_byte(u8 byte, struct e5_struct *k)
-{
- u8 status;
-
- do {
- status = ctrl_inb(EC3104_SER4_LSR);
- } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY);
-
- printk("<%02x>", byte);
-
- ctrl_outb(byte, EC3104_SER4_DATA);
-
- do {
- status = ctrl_inb(EC3104_SER4_LSR);
- } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY);
-
-}
-
-static int e5_send_packet(u8 *packet, int count, struct e5_struct *k)
-{
- int i;
-
- disable_irq(EC3104_IRQ_SER4);
-
- if (k->cached_mcr & MCR_RTS) {
- printk("e5_send_packet: too slow\n");
- enable_irq(EC3104_IRQ_SER4);
- return -EAGAIN;
- }
-
- k->cached_mcr |= MCR_RTS;
- ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
-
- e5_wait_for_cts(k);
-
- printk("p: ");
-
- for(i=0; i<count; i++)
- e5_send_byte(packet[i], k);
-
- e5_send_byte(e5_checksum(packet, count), k);
-
- printk("\n");
-
- udelay(1500);
-
- k->cached_mcr &= ~MCR_RTS;
- ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
-
- set_current_state(TASK_UNINTERRUPTIBLE);
-
-
-
- enable_irq(EC3104_IRQ_SER4);
-
-
-
- return 0;
-}
-
-/*
- * E5 packets we know about:
- * E5->host 0x80 0x05 <checksum> - resend packet
- * host->E5 0x83 0x43 <contrast> - set LCD contrast
- * host->E5 0x85 0x41 0x02 <brightness> 0x02 - set LCD backlight
- * E5->host 0x87 <ps2 packet> 0x00 <checksum> - external PS2
- * E5->host 0x88 <scancode> <checksum> - key press
- */
-
-static void e5_receive(struct e5_struct *k)
-{
- k->packet[k->pos++] = ctrl_inb(EC3104_SER4_DATA);
-
- if (k->pos == 1) {
- switch(k->packet[0]) {
- case 0x80:
- k->length = 3;
- break;
-
- case 0x87: /* PS2 ext */
- k->length = 6;
- break;
-
- case 0x88: /* keyboard */
- k->length = 3;
- break;
-
- default:
- k->length = 1;
- printk(KERN_WARNING "unknown E5 packet %02x\n",
- k->packet[0]);
- }
- }
-
- if (k->pos == k->length) {
- int i;
-
- if (e5_checksum(k->packet, k->length) != 0)
- printk(KERN_WARNING "E5: wrong checksum\n");
-
-#if 0
- printk("E5 packet [");
- for(i=0; i<k->length; i++) {
- printk("%02x ", k->packet[i]);
- }
-
- printk("(%02x)]\n", e5_checksum(k->packet, k->length-1));
-#endif
-
- switch(k->packet[0]) {
- case 0x80:
- case 0x88:
- handle_keyboard_event(k->packet[1]);
- break;
- }
-
- k->pos = k->length = 0;
- }
-}
-
-static void ec3104_keyb_interrupt(int irq, void *data)
-{
- struct e5_struct *k = &ec3104_keyb;
- u8 msr, lsr;
-
- msr = ctrl_inb(EC3104_SER4_MSR);
-
- if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) {
- if (k->cached_mcr & MCR_RTS)
- printk("confused: RTS already high\n");
- /* CTS went high. Send RTS. */
- k->cached_mcr |= MCR_RTS;
-
- ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
- } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) {
- /* CTS went low. */
- if (!(k->cached_mcr & MCR_RTS))
- printk("confused: RTS already low\n");
-
- k->cached_mcr &= ~MCR_RTS;
-
- ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
- }
-
- k->last_msr = msr;
-
- lsr = ctrl_inb(EC3104_SER4_LSR);
-
- if (lsr & LSR_DR)
- e5_receive(k);
-}
-
-static void ec3104_keyb_clear_state(void)
-{
- struct e5_struct *k = &ec3104_keyb;
- u8 msr, lsr;
-
- /* we want CTS to be low */
- k->last_msr = 0;
-
- for (;;) {
- msleep(100);
-
- msr = ctrl_inb(EC3104_SER4_MSR);
-
- lsr = ctrl_inb(EC3104_SER4_LSR);
-
- if (lsr & LSR_DR) {
- e5_receive(k);
- continue;
- }
-
- if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) {
- if (k->cached_mcr & MCR_RTS)
- printk("confused: RTS already high\n");
- /* CTS went high. Send RTS. */
- k->cached_mcr |= MCR_RTS;
-
- ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
- } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) {
- /* CTS went low. */
- if (!(k->cached_mcr & MCR_RTS))
- printk("confused: RTS already low\n");
-
- k->cached_mcr &= ~MCR_RTS;
-
- ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
- } else
- break;
-
- k->last_msr = msr;
-
- continue;
- }
-}
-
-void __init ec3104_kbd_init_hw(void)
-{
- ec3104_keyb.last_msr = ctrl_inb(EC3104_SER4_MSR);
- ec3104_keyb.cached_mcr = ctrl_inb(EC3104_SER4_MCR);
-
- ec3104_keyb_clear_state();
-
- /* Ok, finally allocate the IRQ, and off we go.. */
- request_irq(EC3104_IRQ_SER4, ec3104_keyb_interrupt, 0, "keyboard", NULL);
-}
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index c6c56fb8ba5..ffcecde9e2a 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -1,34 +1,30 @@
/*
-
-
Copyright (C) 1996 Digi International.
-
+
For technical support please email digiLinux@dgii.com or
call Digi tech support at (612) 912-3456
** This driver is no longer supported by Digi **
- Much of this design and code came from epca.c which was
- copyright (C) 1994, 1995 Troy De Jongh, and subsquently
- modified by David Nugent, Christoph Lameter, Mike McLagan.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
---------------------------------------------------------------------------- */
-/* See README.epca for change history --DAT*/
+ Much of this design and code came from epca.c which was
+ copyright (C) 1994, 1995 Troy De Jongh, and subsquently
+ modified by David Nugent, Christoph Lameter, Mike McLagan.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/* See README.epca for change history --DAT*/
#include <linux/module.h>
#include <linux/kernel.h>
@@ -54,13 +50,10 @@
#include "epca.h"
#include "epcaconfig.h"
-/* ---------------------- Begin defines ------------------------ */
-
#define VERSION "1.3.0.1-LK2.6"
/* This major needs to be submitted to Linux to join the majors list */
-
-#define DIGIINFOMAJOR 35 /* For Digi specific ioctl */
+#define DIGIINFOMAJOR 35 /* For Digi specific ioctl */
#define MAXCARDS 7
@@ -68,60 +61,48 @@
#define PFX "epca: "
-/* ----------------- Begin global definitions ------------------- */
-
static int nbdevs, num_cards, liloconfig;
static int digi_poller_inhibited = 1 ;
static int setup_error_code;
static int invalid_lilo_config;
-/* The ISA boards do window flipping into the same spaces so its only sane
- with a single lock. It's still pretty efficient */
-
+/*
+ * The ISA boards do window flipping into the same spaces so its only sane with
+ * a single lock. It's still pretty efficient.
+ */
static DEFINE_SPINLOCK(epca_lock);
-/* -----------------------------------------------------------------------
- MAXBOARDS is typically 12, but ISA and EISA cards are restricted to
- 7 below.
---------------------------------------------------------------------------*/
+/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted to 7 below. */
static struct board_info boards[MAXBOARDS];
-
-/* ------------- Begin structures used for driver registeration ---------- */
-
static struct tty_driver *pc_driver;
static struct tty_driver *pc_info;
/* ------------------ Begin Digi specific structures -------------------- */
-/* ------------------------------------------------------------------------
- digi_channels represents an array of structures that keep track of
- each channel of the Digi product. Information such as transmit and
- receive pointers, termio data, and signal definitions (DTR, CTS, etc ...)
- are stored here. This structure is NOT used to overlay the cards
- physical channel structure.
--------------------------------------------------------------------------- */
-
+/*
+ * digi_channels represents an array of structures that keep track of each
+ * channel of the Digi product. Information such as transmit and receive
+ * pointers, termio data, and signal definitions (DTR, CTS, etc ...) are stored
+ * here. This structure is NOT used to overlay the cards physical channel
+ * structure.
+ */
static struct channel digi_channels[MAX_ALLOC];
-/* ------------------------------------------------------------------------
- card_ptr is an array used to hold the address of the
- first channel structure of each card. This array will hold
- the addresses of various channels located in digi_channels.
--------------------------------------------------------------------------- */
+/*
+ * card_ptr is an array used to hold the address of the first channel structure
+ * of each card. This array will hold the addresses of various channels located
+ * in digi_channels.
+ */
static struct channel *card_ptr[MAXCARDS];
static struct timer_list epca_timer;
-/* ---------------------- Begin function prototypes --------------------- */
-
-/* ----------------------------------------------------------------------
- Begin generic memory functions. These functions will be alias
- (point at) more specific functions dependent on the board being
- configured.
------------------------------------------------------------------------ */
-
+/*
+ * Begin generic memory functions. These functions will be alias (point at)
+ * more specific functions dependent on the board being configured.
+ */
static void memwinon(struct board_info *b, unsigned int win);
static void memwinoff(struct board_info *b, unsigned int win);
static void globalwinon(struct channel *ch);
@@ -170,8 +151,6 @@ static void dummy_memoff(struct channel *ch);
static void dummy_assertgwinon(struct channel *ch);
static void dummy_assertmemoff(struct channel *ch);
-/* ------------------- Begin declare functions ----------------------- */
-
static struct channel *verifyChannel(struct tty_struct *);
static void pc_sched_event(struct channel *, int);
static void epca_error(int, char *);
@@ -213,62 +192,55 @@ static int pc_write(struct tty_struct *, const unsigned char *, int);
static int pc_init(void);
static int init_PCI(void);
-
-/* ------------------------------------------------------------------
- Table of functions for each board to handle memory. Mantaining
- parallelism is a *very* good idea here. The idea is for the
- runtime code to blindly call these functions, not knowing/caring
- about the underlying hardware. This stuff should contain no
- conditionals; if more functionality is needed a different entry
- should be established. These calls are the interface calls and
- are the only functions that should be accessed. Anyone caught
- making direct calls deserves what they get.
--------------------------------------------------------------------- */
-
+/*
+ * Table of functions for each board to handle memory. Mantaining parallelism
+ * is a *very* good idea here. The idea is for the runtime code to blindly call
+ * these functions, not knowing/caring about the underlying hardware. This
+ * stuff should contain no conditionals; if more functionality is needed a
+ * different entry should be established. These calls are the interface calls
+ * and are the only functions that should be accessed. Anyone caught making
+ * direct calls deserves what they get.
+ */
static void memwinon(struct board_info *b, unsigned int win)
{
- (b->memwinon)(b, win);
+ b->memwinon(b, win);
}
static void memwinoff(struct board_info *b, unsigned int win)
{
- (b->memwinoff)(b, win);
+ b->memwinoff(b, win);
}
static void globalwinon(struct channel *ch)
{
- (ch->board->globalwinon)(ch);
+ ch->board->globalwinon(ch);
}
static void rxwinon(struct channel *ch)
{
- (ch->board->rxwinon)(ch);
+ ch->board->rxwinon(ch);
}
static void txwinon(struct channel *ch)
{
- (ch->board->txwinon)(ch);
+ ch->board->txwinon(ch);
}
static void memoff(struct channel *ch)
{
- (ch->board->memoff)(ch);
+ ch->board->memoff(ch);
}
static void assertgwinon(struct channel *ch)
{
- (ch->board->assertgwinon)(ch);
+ ch->board->assertgwinon(ch);
}
static void assertmemoff(struct channel *ch)
{
- (ch->board->assertmemoff)(ch);
+ ch->board->assertmemoff(ch);
}
-/* ---------------------------------------------------------
- PCXEM windowing is the same as that used in the PCXR
- and CX series cards.
------------------------------------------------------------- */
-
+/* PCXEM windowing is the same as that used in the PCXR and CX series cards. */
static void pcxem_memwinon(struct board_info *b, unsigned int win)
{
outb_p(FEPWIN|win, b->port + 1);
@@ -300,32 +272,30 @@ static void pcxem_memoff(struct channel *ch)
}
/* ----------------- Begin pcxe memory window stuff ------------------ */
-
static void pcxe_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(FEPWIN | win, b->port + 1);
+ outb_p(FEPWIN | win, b->port + 1);
}
static void pcxe_memwinoff(struct board_info *b, unsigned int win)
{
- outb_p(inb(b->port) & ~FEPMEM,
- b->port + 1);
+ outb_p(inb(b->port) & ~FEPMEM, b->port + 1);
outb_p(0, b->port + 1);
}
static void pcxe_globalwinon(struct channel *ch)
{
- outb_p( FEPWIN, (int)ch->board->port + 1);
+ outb_p(FEPWIN, (int)ch->board->port + 1);
}
static void pcxe_rxwinon(struct channel *ch)
{
- outb_p(ch->rxwin, (int)ch->board->port + 1);
+ outb_p(ch->rxwin, (int)ch->board->port + 1);
}
static void pcxe_txwinon(struct channel *ch)
{
- outb_p(ch->txwin, (int)ch->board->port + 1);
+ outb_p(ch->txwin, (int)ch->board->port + 1);
}
static void pcxe_memoff(struct channel *ch)
@@ -335,10 +305,9 @@ static void pcxe_memoff(struct channel *ch)
}
/* ------------- Begin pc64xe and pcxi memory window stuff -------------- */
-
static void pcxi_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(inb(b->port) | FEPMEM, b->port);
+ outb_p(inb(b->port) | FEPMEM, b->port);
}
static void pcxi_memwinoff(struct board_info *b, unsigned int win)
@@ -353,12 +322,12 @@ static void pcxi_globalwinon(struct channel *ch)
static void pcxi_rxwinon(struct channel *ch)
{
- outb_p(FEPMEM, ch->board->port);
+ outb_p(FEPMEM, ch->board->port);
}
static void pcxi_txwinon(struct channel *ch)
{
- outb_p(FEPMEM, ch->board->port);
+ outb_p(FEPMEM, ch->board->port);
}
static void pcxi_memoff(struct channel *ch)
@@ -376,16 +345,13 @@ static void pcxi_assertmemoff(struct channel *ch)
epcaassert(!(inb(ch->board->port) & FEPMEM), "Memory on");
}
-
-/* ----------------------------------------------------------------------
- Not all of the cards need specific memory windowing routines. Some
- cards (Such as PCI) needs no windowing routines at all. We provide
- these do nothing routines so that the same code base can be used.
- The driver will ALWAYS call a windowing routine if it thinks it needs
- to; regardless of the card. However, dependent on the card the routine
- may or may not do anything.
----------------------------------------------------------------------------*/
-
+/*
+ * Not all of the cards need specific memory windowing routines. Some cards
+ * (Such as PCI) needs no windowing routines at all. We provide these do
+ * nothing routines so that the same code base can be used. The driver will
+ * ALWAYS call a windowing routine if it thinks it needs to; regardless of the
+ * card. However, dependent on the card the routine may or may not do anything.
+ */
static void dummy_memwinon(struct board_info *b, unsigned int win)
{
}
@@ -418,15 +384,14 @@ static void dummy_assertmemoff(struct channel *ch)
{
}
-/* ----------------- Begin verifyChannel function ----------------------- */
static struct channel *verifyChannel(struct tty_struct *tty)
-{ /* Begin verifyChannel */
- /* --------------------------------------------------------------------
- This routine basically provides a sanity check. It insures that
- the channel returned is within the proper range of addresses as
- well as properly initialized. If some bogus info gets passed in
- through tty->driver_data this should catch it.
- --------------------------------------------------------------------- */
+{
+ /*
+ * This routine basically provides a sanity check. It insures that the
+ * channel returned is within the proper range of addresses as well as
+ * properly initialized. If some bogus info gets passed in
+ * through tty->driver_data this should catch it.
+ */
if (tty) {
struct channel *ch = (struct channel *)tty->driver_data;
if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) {
@@ -435,62 +400,55 @@ static struct channel *verifyChannel(struct tty_struct *tty)
}
}
return NULL;
-
-} /* End verifyChannel */
-
-/* ------------------ Begin pc_sched_event ------------------------- */
+}
static void pc_sched_event(struct channel *ch, int event)
{
- /* ----------------------------------------------------------------------
- We call this to schedule interrupt processing on some event. The
- kernel sees our request and calls the related routine in OUR driver.
- -------------------------------------------------------------------------*/
+ /*
+ * We call this to schedule interrupt processing on some event. The
+ * kernel sees our request and calls the related routine in OUR driver.
+ */
ch->event |= 1 << event;
schedule_work(&ch->tqueue);
-} /* End pc_sched_event */
-
-/* ------------------ Begin epca_error ------------------------- */
+}
static void epca_error(int line, char *msg)
{
printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg);
}
-/* ------------------ Begin pc_close ------------------------- */
-static void pc_close(struct tty_struct * tty, struct file * filp)
+static void pc_close(struct tty_struct *tty, struct file *filp)
{
struct channel *ch;
unsigned long flags;
- /* ---------------------------------------------------------
- verifyChannel returns the channel from the tty struct
- if it is valid. This serves as a sanity check.
- ------------------------------------------------------------- */
- if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */
+ /*
+ * verifyChannel returns the channel from the tty struct if it is
+ * valid. This serves as a sanity check.
+ */
+ if ((ch = verifyChannel(tty)) != NULL) {
spin_lock_irqsave(&epca_lock, flags);
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&epca_lock, flags);
return;
}
- /* Check to see if the channel is open more than once */
if (ch->count-- > 1) {
/* Begin channel is open more than once */
- /* -------------------------------------------------------------
- Return without doing anything. Someone might still be using
- the channel.
- ---------------------------------------------------------------- */
+ /*
+ * Return without doing anything. Someone might still
+ * be using the channel.
+ */
spin_unlock_irqrestore(&epca_lock, flags);
return;
- } /* End channel is open more than once */
+ }
/* Port open only once go ahead with shutdown & reset */
BUG_ON(ch->count < 0);
- /* ---------------------------------------------------------------
- Let the rest of the driver know the channel is being closed.
- This becomes important if an open is attempted before close
- is finished.
- ------------------------------------------------------------------ */
+ /*
+ * Let the rest of the driver know the channel is being closed.
+ * This becomes important if an open is attempted before close
+ * is finished.
+ */
ch->asyncflags |= ASYNC_CLOSING;
tty->closing = 1;
@@ -498,7 +456,7 @@ static void pc_close(struct tty_struct * tty, struct file * filp)
if (ch->asyncflags & ASYNC_INITIALIZED) {
/* Setup an event to indicate when the transmit buffer empties */
- setup_empty_event(tty, ch);
+ setup_empty_event(tty, ch);
tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
}
if (tty->driver->flush_buffer)
@@ -513,27 +471,24 @@ static void pc_close(struct tty_struct * tty, struct file * filp)
ch->tty = NULL;
spin_unlock_irqrestore(&epca_lock, flags);
- if (ch->blocked_open) { /* Begin if blocked_open */
- if (ch->close_delay)
+ if (ch->blocked_open) {
+ if (ch->close_delay)
msleep_interruptible(jiffies_to_msecs(ch->close_delay));
wake_up_interruptible(&ch->open_wait);
- } /* End if blocked_open */
- ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
+ }
+ ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
ASYNC_CLOSING);
wake_up_interruptible(&ch->close_wait);
- } /* End if ch != NULL */
-} /* End pc_close */
-
-/* ------------------ Begin shutdown ------------------------- */
+ }
+}
static void shutdown(struct channel *ch)
-{ /* Begin shutdown */
-
+{
unsigned long flags;
struct tty_struct *tty;
struct board_chan __iomem *bc;
- if (!(ch->asyncflags & ASYNC_INITIALIZED))
+ if (!(ch->asyncflags & ASYNC_INITIALIZED))
return;
spin_lock_irqsave(&epca_lock, flags);
@@ -541,50 +496,40 @@ static void shutdown(struct channel *ch)
globalwinon(ch);
bc = ch->brdchan;
- /* ------------------------------------------------------------------
- In order for an event to be generated on the receipt of data the
- idata flag must be set. Since we are shutting down, this is not
- necessary clear this flag.
- --------------------------------------------------------------------- */
-
+ /*
+ * In order for an event to be generated on the receipt of data the
+ * idata flag must be set. Since we are shutting down, this is not
+ * necessary clear this flag.
+ */
if (bc)
writeb(0, &bc->idata);
tty = ch->tty;
- /* ----------------------------------------------------------------
- If we're a modem control device and HUPCL is on, drop RTS & DTR.
- ------------------------------------------------------------------ */
-
+ /* If we're a modem control device and HUPCL is on, drop RTS & DTR. */
if (tty->termios->c_cflag & HUPCL) {
ch->omodem &= ~(ch->m_rts | ch->m_dtr);
fepcmd(ch, SETMODEM, 0, ch->m_dtr | ch->m_rts, 10, 1);
}
memoff(ch);
- /* ------------------------------------------------------------------
- The channel has officialy been closed. The next time it is opened
- it will have to reinitialized. Set a flag to indicate this.
- ---------------------------------------------------------------------- */
-
+ /*
+ * The channel has officialy been closed. The next time it is opened it
+ * will have to reinitialized. Set a flag to indicate this.
+ */
/* Prevent future Digi programmed interrupts from coming active */
-
ch->asyncflags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&epca_lock, flags);
-
-} /* End shutdown */
-
-/* ------------------ Begin pc_hangup ------------------------- */
+}
static void pc_hangup(struct tty_struct *tty)
-{ /* Begin pc_hangup */
+{
struct channel *ch;
-
- /* ---------------------------------------------------------
- verifyChannel returns the channel from the tty struct
- if it is valid. This serves as a sanity check.
- ------------------------------------------------------------- */
- if ((ch = verifyChannel(tty)) != NULL) { /* Begin if ch != NULL */
+ /*
+ * verifyChannel returns the channel from the tty struct if it is
+ * valid. This serves as a sanity check.
+ */
+ if ((ch = verifyChannel(tty)) != NULL) {
unsigned long flags;
if (tty->driver->flush_buffer)
@@ -599,15 +544,12 @@ static void pc_hangup(struct tty_struct *tty)
ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED);
spin_unlock_irqrestore(&epca_lock, flags);
wake_up_interruptible(&ch->open_wait);
- } /* End if ch != NULL */
-
-} /* End pc_hangup */
-
-/* ------------------ Begin pc_write ------------------------- */
+ }
+}
-static int pc_write(struct tty_struct * tty,
+static int pc_write(struct tty_struct *tty,
const unsigned char *buf, int bytesAvailable)
-{ /* Begin pc_write */
+{
unsigned int head, tail;
int dataLen;
int size;
@@ -617,25 +559,23 @@ static int pc_write(struct tty_struct * tty,
int remain;
struct board_chan __iomem *bc;
- /* ----------------------------------------------------------------
- pc_write is primarily called directly by the kernel routine
- tty_write (Though it can also be called by put_char) found in
- tty_io.c. pc_write is passed a line discipline buffer where
- the data to be written out is stored. The line discipline
- implementation itself is done at the kernel level and is not
- brought into the driver.
- ------------------------------------------------------------------- */
-
- /* ---------------------------------------------------------
- verifyChannel returns the channel from the tty struct
- if it is valid. This serves as a sanity check.
- ------------------------------------------------------------- */
+ /*
+ * pc_write is primarily called directly by the kernel routine
+ * tty_write (Though it can also be called by put_char) found in
+ * tty_io.c. pc_write is passed a line discipline buffer where the data
+ * to be written out is stored. The line discipline implementation
+ * itself is done at the kernel level and is not brought into the
+ * driver.
+ */
+ /*
+ * verifyChannel returns the channel from the tty struct if it is
+ * valid. This serves as a sanity check.
+ */
if ((ch = verifyChannel(tty)) == NULL)
return 0;
/* Make a pointer to the channel data structure found on the board. */
-
bc = ch->brdchan;
size = ch->txbufsize;
amountCopied = 0;
@@ -650,37 +590,36 @@ static int pc_write(struct tty_struct * tty,
tail = readw(&bc->tout);
tail &= (size - 1);
- /* If head >= tail, head has not wrapped around. */
- if (head >= tail) { /* Begin head has not wrapped */
- /* ---------------------------------------------------------------
- remain (much like dataLen above) represents the total amount of
- space available on the card for data. Here dataLen represents
- the space existing between the head pointer and the end of
- buffer. This is important because a memcpy cannot be told to
- automatically wrap around when it hits the buffer end.
- ------------------------------------------------------------------ */
+ if (head >= tail) {
+ /* head has not wrapped */
+ /*
+ * remain (much like dataLen above) represents the total amount
+ * of space available on the card for data. Here dataLen
+ * represents the space existing between the head pointer and
+ * the end of buffer. This is important because a memcpy cannot
+ * be told to automatically wrap around when it hits the buffer
+ * end.
+ */
dataLen = size - head;
remain = size - (head - tail) - 1;
- } else { /* Begin head has wrapped around */
-
+ } else {
+ /* head has wrapped around */
remain = tail - head - 1;
dataLen = remain;
-
- } /* End head has wrapped around */
- /* -------------------------------------------------------------------
- Check the space on the card. If we have more data than
- space; reduce the amount of data to fit the space.
- ---------------------------------------------------------------------- */
+ }
+ /*
+ * Check the space on the card. If we have more data than space; reduce
+ * the amount of data to fit the space.
+ */
bytesAvailable = min(remain, bytesAvailable);
txwinon(ch);
- while (bytesAvailable > 0)
- { /* Begin while there is data to copy onto card */
-
- /* -----------------------------------------------------------------
- If head is not wrapped, the below will make sure the first
- data copy fills to the end of card buffer.
- ------------------------------------------------------------------- */
+ while (bytesAvailable > 0) {
+ /* there is data to copy onto card */
+ /*
+ * If head is not wrapped, the below will make sure the first
+ * data copy fills to the end of card buffer.
+ */
dataLen = min(bytesAvailable, dataLen);
memcpy_toio(ch->txptr + head, buf, dataLen);
buf += dataLen;
@@ -692,7 +631,7 @@ static int pc_write(struct tty_struct * tty,
head = 0;
dataLen = tail;
}
- } /* End while there is data to copy onto card */
+ }
ch->statusflags |= TXBUSY;
globalwinon(ch);
writew(head, &bc->tin);
@@ -703,22 +642,16 @@ static int pc_write(struct tty_struct * tty,
}
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
- return(amountCopied);
-
-} /* End pc_write */
-
-/* ------------------ Begin pc_put_char ------------------------- */
+ return amountCopied;
+}
static void pc_put_char(struct tty_struct *tty, unsigned char c)
-{ /* Begin pc_put_char */
+{
pc_write(tty, &c, 1);
-} /* End pc_put_char */
-
-/* ------------------ Begin pc_write_room ------------------------- */
+}
static int pc_write_room(struct tty_struct *tty)
-{ /* Begin pc_write_room */
-
+{
int remain;
struct channel *ch;
unsigned long flags;
@@ -727,11 +660,10 @@ static int pc_write_room(struct tty_struct *tty)
remain = 0;
- /* ---------------------------------------------------------
- verifyChannel returns the channel from the tty struct
- if it is valid. This serves as a sanity check.
- ------------------------------------------------------------- */
-
+ /*
+ * verifyChannel returns the channel from the tty struct if it is
+ * valid. This serves as a sanity check.
+ */
if ((ch = verifyChannel(tty)) != NULL) {
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
@@ -757,14 +689,10 @@ static int pc_write_room(struct tty_struct *tty)
}
/* Return how much room is left on card */
return remain;
-
-} /* End pc_write_room */
-
-/* ------------------ Begin pc_chars_in_buffer ---------------------- */
+}
static int pc_chars_in_buffer(struct tty_struct *tty)
-{ /* Begin pc_chars_in_buffer */
-
+{
int chars;
unsigned int ctail, head, tail;
int remain;
@@ -772,13 +700,12 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
struct channel *ch;
struct board_chan __iomem *bc;
- /* ---------------------------------------------------------
- verifyChannel returns the channel from the tty struct
- if it is valid. This serves as a sanity check.
- ------------------------------------------------------------- */
-
+ /*
+ * verifyChannel returns the channel from the tty struct if it is
+ * valid. This serves as a sanity check.
+ */
if ((ch = verifyChannel(tty)) == NULL)
- return(0);
+ return 0;
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
@@ -793,45 +720,40 @@ static int pc_chars_in_buffer(struct tty_struct *tty)
else { /* Begin if some space on the card has been used */
head = readw(&bc->tin) & (ch->txbufsize - 1);
tail &= (ch->txbufsize - 1);
- /* --------------------------------------------------------------
- The logic here is basically opposite of the above pc_write_room
- here we are finding the amount of bytes in the buffer filled.
- Not the amount of bytes empty.
- ------------------------------------------------------------------- */
+ /*
+ * The logic here is basically opposite of the above
+ * pc_write_room here we are finding the amount of bytes in the
+ * buffer filled. Not the amount of bytes empty.
+ */
if ((remain = tail - head - 1) < 0 )
remain += ch->txbufsize;
chars = (int)(ch->txbufsize - remain);
- /* -------------------------------------------------------------
- Make it possible to wakeup anything waiting for output
- in tty_ioctl.c, etc.
-
- If not already set. Setup an event to indicate when the
- transmit buffer empties
- ----------------------------------------------------------------- */
+ /*
+ * Make it possible to wakeup anything waiting for output in
+ * tty_ioctl.c, etc.
+ *
+ * If not already set. Setup an event to indicate when the
+ * transmit buffer empties.
+ */
if (!(ch->statusflags & EMPTYWAIT))
setup_empty_event(tty,ch);
-
} /* End if some space on the card has been used */
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
/* Return number of characters residing on card. */
- return(chars);
-
-} /* End pc_chars_in_buffer */
-
-/* ------------------ Begin pc_flush_buffer ---------------------- */
+ return chars;
+}
static void pc_flush_buffer(struct tty_struct *tty)
-{ /* Begin pc_flush_buffer */
-
+{
unsigned int tail;
unsigned long flags;
struct channel *ch;
struct board_chan __iomem *bc;
- /* ---------------------------------------------------------
- verifyChannel returns the channel from the tty struct
- if it is valid. This serves as a sanity check.
- ------------------------------------------------------------- */
+ /*
+ * verifyChannel returns the channel from the tty struct if it is
+ * valid. This serves as a sanity check.
+ */
if ((ch = verifyChannel(tty)) == NULL)
return;
@@ -844,51 +766,47 @@ static void pc_flush_buffer(struct tty_struct *tty)
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
tty_wakeup(tty);
-} /* End pc_flush_buffer */
-
-/* ------------------ Begin pc_flush_chars ---------------------- */
+}
static void pc_flush_chars(struct tty_struct *tty)
-{ /* Begin pc_flush_chars */
- struct channel * ch;
- /* ---------------------------------------------------------
- verifyChannel returns the channel from the tty struct
- if it is valid. This serves as a sanity check.
- ------------------------------------------------------------- */
+{
+ struct channel *ch;
+ /*
+ * verifyChannel returns the channel from the tty struct if it is
+ * valid. This serves as a sanity check.
+ */
if ((ch = verifyChannel(tty)) != NULL) {
unsigned long flags;
spin_lock_irqsave(&epca_lock, flags);
- /* ----------------------------------------------------------------
- If not already set and the transmitter is busy setup an event
- to indicate when the transmit empties.
- ------------------------------------------------------------------- */
+ /*
+ * If not already set and the transmitter is busy setup an
+ * event to indicate when the transmit empties.
+ */
if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))
setup_empty_event(tty,ch);
spin_unlock_irqrestore(&epca_lock, flags);
}
-} /* End pc_flush_chars */
-
-/* ------------------ Begin block_til_ready ---------------------- */
+}
-static int block_til_ready(struct tty_struct *tty,
+static int block_til_ready(struct tty_struct *tty,
struct file *filp, struct channel *ch)
-{ /* Begin block_til_ready */
+{
DECLARE_WAITQUEUE(wait,current);
- int retval, do_clocal = 0;
+ int retval, do_clocal = 0;
unsigned long flags;
if (tty_hung_up_p(filp)) {
if (ch->asyncflags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
- retval = -ERESTARTSYS;
- return(retval);
+ retval = -ERESTARTSYS;
+ return retval;
}
- /* -----------------------------------------------------------------
- If the device is in the middle of being closed, then block
- until it's done, and then try again.
- -------------------------------------------------------------------- */
+ /*
+ * If the device is in the middle of being closed, then block until
+ * it's done, and then try again.
+ */
if (ch->asyncflags & ASYNC_CLOSING) {
interruptible_sleep_on(&ch->close_wait);
@@ -899,17 +817,17 @@ static int block_til_ready(struct tty_struct *tty,
}
if (filp->f_flags & O_NONBLOCK) {
- /* -----------------------------------------------------------------
- If non-blocking mode is set, then make the check up front
- and then exit.
- -------------------------------------------------------------------- */
+ /*
+ * If non-blocking mode is set, then make the check up front
+ * and then exit.
+ */
ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
if (tty->termios->c_cflag & CLOCAL)
do_clocal = 1;
/* Block waiting for the carrier detect and the line to become free */
-
+
retval = 0;
add_wait_queue(&ch->open_wait, &wait);
@@ -918,19 +836,18 @@ static int block_til_ready(struct tty_struct *tty,
if (!tty_hung_up_p(filp))
ch->count--;
ch->blocked_open++;
- while(1)
- { /* Begin forever while */
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
- !(ch->asyncflags & ASYNC_INITIALIZED))
+ !(ch->asyncflags & ASYNC_INITIALIZED))
{
if (ch->asyncflags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
- retval = -ERESTARTSYS;
+ retval = -ERESTARTSYS;
break;
}
- if (!(ch->asyncflags & ASYNC_CLOSING) &&
+ if (!(ch->asyncflags & ASYNC_CLOSING) &&
(do_clocal || (ch->imodem & ch->dcd)))
break;
if (signal_pending(current)) {
@@ -938,16 +855,15 @@ static int block_til_ready(struct tty_struct *tty,
break;
}
spin_unlock_irqrestore(&epca_lock, flags);
- /* ---------------------------------------------------------------
- Allow someone else to be scheduled. We will occasionally go
- through this loop until one of the above conditions change.
- The below schedule call will allow other processes to enter and
- prevent this loop from hogging the cpu.
- ------------------------------------------------------------------ */
+ /*
+ * Allow someone else to be scheduled. We will occasionally go
+ * through this loop until one of the above conditions change.
+ * The below schedule call will allow other processes to enter
+ * and prevent this loop from hogging the cpu.
+ */
schedule();
spin_lock_irqsave(&epca_lock, flags);
-
- } /* End forever while */
+ }
__set_current_state(TASK_RUNNING);
remove_wait_queue(&ch->open_wait, &wait);
@@ -962,13 +878,10 @@ static int block_til_ready(struct tty_struct *tty,
ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
return 0;
-} /* End block_til_ready */
-
-/* ------------------ Begin pc_open ---------------------- */
+}
static int pc_open(struct tty_struct *tty, struct file * filp)
-{ /* Begin pc_open */
-
+{
struct channel *ch;
unsigned long flags;
int line, retval, boardnum;
@@ -984,12 +897,11 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
/* Check status of board configured in system. */
- /* -----------------------------------------------------------------
- I check to see if the epca_setup routine detected an user error.
- It might be better to put this in pc_init, but for the moment it
- goes here.
- ---------------------------------------------------------------------- */
-
+ /*
+ * I check to see if the epca_setup routine detected an user error. It
+ * might be better to put this in pc_init, but for the moment it goes
+ * here.
+ */
if (invalid_lilo_config) {
if (setup_error_code & INVALID_BOARD_TYPE)
printk(KERN_ERR "epca: pc_open: Invalid board type specified in kernel options.\n");
@@ -1010,49 +922,48 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
tty->driver_data = NULL; /* Mark this device as 'down' */
return(-ENODEV);
}
-
+
if ((bc = ch->brdchan) == 0) {
tty->driver_data = NULL;
return -ENODEV;
}
spin_lock_irqsave(&epca_lock, flags);
- /* ------------------------------------------------------------------
- Every time a channel is opened, increment a counter. This is
- necessary because we do not wish to flush and shutdown the channel
- until the last app holding the channel open, closes it.
- --------------------------------------------------------------------- */
+ /*
+ * Every time a channel is opened, increment a counter. This is
+ * necessary because we do not wish to flush and shutdown the channel
+ * until the last app holding the channel open, closes it.
+ */
ch->count++;
- /* ----------------------------------------------------------------
- Set a kernel structures pointer to our local channel
- structure. This way we can get to it when passed only
- a tty struct.
- ------------------------------------------------------------------ */
+ /*
+ * Set a kernel structures pointer to our local channel structure. This
+ * way we can get to it when passed only a tty struct.
+ */
tty->driver_data = ch;
- /* ----------------------------------------------------------------
- If this is the first time the channel has been opened, initialize
- the tty->termios struct otherwise let pc_close handle it.
- -------------------------------------------------------------------- */
+ /*
+ * If this is the first time the channel has been opened, initialize
+ * the tty->termios struct otherwise let pc_close handle it.
+ */
globalwinon(ch);
ch->statusflags = 0;
/* Save boards current modem status */
ch->imodem = readb(&bc->mstat);
- /* ----------------------------------------------------------------
- Set receive head and tail ptrs to each other. This indicates
- no data available to read.
- ----------------------------------------------------------------- */
+ /*
+ * Set receive head and tail ptrs to each other. This indicates no data
+ * available to read.
+ */
head = readw(&bc->rin);
writew(head, &bc->rout);
/* Set the channels associated tty structure */
ch->tty = tty;
- /* -----------------------------------------------------------------
- The below routine generally sets up parity, baud, flow control
- issues, etc.... It effect both control flags and input flags.
- -------------------------------------------------------------------- */
+ /*
+ * The below routine generally sets up parity, baud, flow control
+ * issues, etc.... It effect both control flags and input flags.
+ */
epcaparam(tty,ch);
ch->asyncflags |= ASYNC_INITIALIZED;
memoff(ch);
@@ -1061,10 +972,10 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
retval = block_til_ready(tty, filp, ch);
if (retval)
return retval;
- /* -------------------------------------------------------------
- Set this again in case a hangup set it to zero while this
- open() was waiting for the line...
- --------------------------------------------------------------- */
+ /*
+ * Set this again in case a hangup set it to zero while this open() was
+ * waiting for the line...
+ */
spin_lock_irqsave(&epca_lock, flags);
ch->tty = tty;
globalwinon(ch);
@@ -1073,13 +984,12 @@ static int pc_open(struct tty_struct *tty, struct file * filp)
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
return 0;
-} /* End pc_open */
+}
static int __init epca_module_init(void)
-{ /* Begin init_module */
+{
return pc_init();
}
-
module_init(epca_module_init);
static struct pci_driver epca_driver;
@@ -1092,8 +1002,7 @@ static void __exit epca_module_exit(void)
del_timer_sync(&epca_timer);
- if ((tty_unregister_driver(pc_driver)) ||
- (tty_unregister_driver(pc_info)))
+ if (tty_unregister_driver(pc_driver) || tty_unregister_driver(pc_info))
{
printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
return;
@@ -1101,23 +1010,20 @@ static void __exit epca_module_exit(void)
put_tty_driver(pc_driver);
put_tty_driver(pc_info);
- for (crd = 0; crd < num_cards; crd++) { /* Begin for each card */
+ for (crd = 0; crd < num_cards; crd++) {
bd = &boards[crd];
- if (!bd)
- { /* Begin sanity check */
+ if (!bd) { /* sanity check */
printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");
return;
- } /* End sanity check */
+ }
ch = card_ptr[crd];
- for (count = 0; count < bd->numports; count++, ch++)
- { /* Begin for each port */
+ for (count = 0; count < bd->numports; count++, ch++) {
if (ch && ch->tty)
tty_hangup(ch->tty);
- } /* End for each port */
- } /* End for each card */
- pci_unregister_driver (&epca_driver);
+ }
+ }
+ pci_unregister_driver(&epca_driver);
}
-
module_exit(epca_module_exit);
static const struct tty_operations pc_ops = {
@@ -1148,10 +1054,8 @@ static struct tty_operations info_ops = {
.ioctl = info_ioctl,
};
-/* ------------------ Begin pc_init ---------------------- */
-
static int __init pc_init(void)
-{ /* Begin pc_init */
+{
int crd;
struct board_info *bd;
unsigned char board_id = 0;
@@ -1169,63 +1073,57 @@ static int __init pc_init(void)
if (!pc_info)
goto out2;
- /* -----------------------------------------------------------------------
- If epca_setup has not been ran by LILO set num_cards to defaults; copy
- board structure defined by digiConfig into drivers board structure.
- Note : If LILO has ran epca_setup then epca_setup will handle defining
- num_cards as well as copying the data into the board structure.
- -------------------------------------------------------------------------- */
- if (!liloconfig) { /* Begin driver has been configured via. epcaconfig */
-
+ /*
+ * If epca_setup has not been ran by LILO set num_cards to defaults;
+ * copy board structure defined by digiConfig into drivers board
+ * structure. Note : If LILO has ran epca_setup then epca_setup will
+ * handle defining num_cards as well as copying the data into the board
+ * structure.
+ */
+ if (!liloconfig) {
+ /* driver has been configured via. epcaconfig */
nbdevs = NBDEVS;
num_cards = NUMCARDS;
- memcpy((void *)&boards, (void *)&static_boards,
- (sizeof(struct board_info) * NUMCARDS));
- } /* End driver has been configured via. epcaconfig */
-
- /* -----------------------------------------------------------------
- Note : If lilo was used to configure the driver and the
- ignore epcaconfig option was choosen (digiepca=2) then
- nbdevs and num_cards will equal 0 at this point. This is
- okay; PCI cards will still be picked up if detected.
- --------------------------------------------------------------------- */
-
- /* -----------------------------------------------------------
- Set up interrupt, we will worry about memory allocation in
- post_fep_init.
- --------------------------------------------------------------- */
+ memcpy(&boards, &static_boards,
+ sizeof(struct board_info) * NUMCARDS);
+ }
+ /*
+ * Note : If lilo was used to configure the driver and the ignore
+ * epcaconfig option was choosen (digiepca=2) then nbdevs and num_cards
+ * will equal 0 at this point. This is okay; PCI cards will still be
+ * picked up if detected.
+ */
+ /*
+ * Set up interrupt, we will worry about memory allocation in
+ * post_fep_init.
+ */
printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);
- /* ------------------------------------------------------------------
- NOTE : This code assumes that the number of ports found in
- the boards array is correct. This could be wrong if
- the card in question is PCI (And therefore has no ports
- entry in the boards structure.) The rest of the
- information will be valid for PCI because the beginning
- of pc_init scans for PCI and determines i/o and base
- memory addresses. I am not sure if it is possible to
- read the number of ports supported by the card prior to
- it being booted (Since that is the state it is in when
- pc_init is run). Because it is not possible to query the
- number of supported ports until after the card has booted;
- we are required to calculate the card_ptrs as the card is
- is initialized (Inside post_fep_init). The negative thing
- about this approach is that digiDload's call to GET_INFO
- will have a bad port value. (Since this is called prior
- to post_fep_init.)
-
- --------------------------------------------------------------------- */
-
+ /*
+ * NOTE : This code assumes that the number of ports found in the
+ * boards array is correct. This could be wrong if the card in question
+ * is PCI (And therefore has no ports entry in the boards structure.)
+ * The rest of the information will be valid for PCI because the
+ * beginning of pc_init scans for PCI and determines i/o and base
+ * memory addresses. I am not sure if it is possible to read the number
+ * of ports supported by the card prior to it being booted (Since that
+ * is the state it is in when pc_init is run). Because it is not
+ * possible to query the number of supported ports until after the card
+ * has booted; we are required to calculate the card_ptrs as the card
+ * is initialized (Inside post_fep_init). The negative thing about this
+ * approach is that digiDload's call to GET_INFO will have a bad port
+ * value. (Since this is called prior to post_fep_init.)
+ */
pci_boards_found = 0;
- if(num_cards < MAXBOARDS)
+ if (num_cards < MAXBOARDS)
pci_boards_found += init_PCI();
num_cards += pci_boards_found;
pc_driver->owner = THIS_MODULE;
- pc_driver->name = "ttyD";
- pc_driver->major = DIGI_MAJOR;
+ pc_driver->name = "ttyD";
+ pc_driver->major = DIGI_MAJOR;
pc_driver->minor_start = 0;
pc_driver->type = TTY_DRIVER_TYPE_SERIAL;
pc_driver->subtype = SERIAL_TYPE_NORMAL;
@@ -1256,120 +1154,108 @@ static int __init pc_init(void)
tty_set_operations(pc_info, &info_ops);
- for (crd = 0; crd < num_cards; crd++)
- { /* Begin for each card */
-
- /* ------------------------------------------------------------------
- This is where the appropriate memory handlers for the hardware is
- set. Everything at runtime blindly jumps through these vectors.
- ---------------------------------------------------------------------- */
+ for (crd = 0; crd < num_cards; crd++) {
+ /*
+ * This is where the appropriate memory handlers for the
+ * hardware is set. Everything at runtime blindly jumps through
+ * these vectors.
+ */
/* defined in epcaconfig.h */
bd = &boards[crd];
- switch (bd->type)
- { /* Begin switch on bd->type {board type} */
- case PCXEM:
- case EISAXEM:
- bd->memwinon = pcxem_memwinon ;
- bd->memwinoff = pcxem_memwinoff ;
- bd->globalwinon = pcxem_globalwinon ;
- bd->txwinon = pcxem_txwinon ;
- bd->rxwinon = pcxem_rxwinon ;
- bd->memoff = pcxem_memoff ;
- bd->assertgwinon = dummy_assertgwinon;
- bd->assertmemoff = dummy_assertmemoff;
- break;
-
- case PCIXEM:
- case PCIXRJ:
- case PCIXR:
- bd->memwinon = dummy_memwinon;
- bd->memwinoff = dummy_memwinoff;
- bd->globalwinon = dummy_globalwinon;
- bd->txwinon = dummy_txwinon;
- bd->rxwinon = dummy_rxwinon;
- bd->memoff = dummy_memoff;
- bd->assertgwinon = dummy_assertgwinon;
- bd->assertmemoff = dummy_assertmemoff;
- break;
-
- case PCXE:
- case PCXEVE:
-
- bd->memwinon = pcxe_memwinon;
- bd->memwinoff = pcxe_memwinoff;
- bd->globalwinon = pcxe_globalwinon;
- bd->txwinon = pcxe_txwinon;
- bd->rxwinon = pcxe_rxwinon;
- bd->memoff = pcxe_memoff;
- bd->assertgwinon = dummy_assertgwinon;
- bd->assertmemoff = dummy_assertmemoff;
- break;
-
- case PCXI:
- case PC64XE:
-
- bd->memwinon = pcxi_memwinon;
- bd->memwinoff = pcxi_memwinoff;
- bd->globalwinon = pcxi_globalwinon;
- bd->txwinon = pcxi_txwinon;
- bd->rxwinon = pcxi_rxwinon;
- bd->memoff = pcxi_memoff;
- bd->assertgwinon = pcxi_assertgwinon;
- bd->assertmemoff = pcxi_assertmemoff;
- break;
-
- default:
- break;
-
- } /* End switch on bd->type */
-
- /* ---------------------------------------------------------------
- Some cards need a memory segment to be defined for use in
- transmit and receive windowing operations. These boards
- are listed in the below switch. In the case of the XI the
- amount of memory on the board is variable so the memory_seg
- is also variable. This code determines what they segment
- should be.
- ----------------------------------------------------------------- */
-
- switch (bd->type)
- { /* Begin switch on bd->type {board type} */
-
- case PCXE:
- case PCXEVE:
- case PC64XE:
- bd->memory_seg = 0xf000;
+ switch (bd->type) {
+ case PCXEM:
+ case EISAXEM:
+ bd->memwinon = pcxem_memwinon;
+ bd->memwinoff = pcxem_memwinoff;
+ bd->globalwinon = pcxem_globalwinon;
+ bd->txwinon = pcxem_txwinon;
+ bd->rxwinon = pcxem_rxwinon;
+ bd->memoff = pcxem_memoff;
+ bd->assertgwinon = dummy_assertgwinon;
+ bd->assertmemoff = dummy_assertmemoff;
break;
- case PCXI:
- board_id = inb((int)bd->port);
- if ((board_id & 0x1) == 0x1)
- { /* Begin it's an XI card */
-
- /* Is it a 64K board */
- if ((board_id & 0x30) == 0)
- bd->memory_seg = 0xf000;
-
- /* Is it a 128K board */
- if ((board_id & 0x30) == 0x10)
- bd->memory_seg = 0xe000;
+ case PCIXEM:
+ case PCIXRJ:
+ case PCIXR:
+ bd->memwinon = dummy_memwinon;
+ bd->memwinoff = dummy_memwinoff;
+ bd->globalwinon = dummy_globalwinon;
+ bd->txwinon = dummy_txwinon;
+ bd->rxwinon = dummy_rxwinon;
+ bd->memoff = dummy_memoff;
+ bd->assertgwinon = dummy_assertgwinon;
+ bd->assertmemoff = dummy_assertmemoff;
+ break;
- /* Is is a 256K board */
- if ((board_id & 0x30) == 0x20)
- bd->memory_seg = 0xc000;
+ case PCXE:
+ case PCXEVE:
+ bd->memwinon = pcxe_memwinon;
+ bd->memwinoff = pcxe_memwinoff;
+ bd->globalwinon = pcxe_globalwinon;
+ bd->txwinon = pcxe_txwinon;
+ bd->rxwinon = pcxe_rxwinon;
+ bd->memoff = pcxe_memoff;
+ bd->assertgwinon = dummy_assertgwinon;
+ bd->assertmemoff = dummy_assertmemoff;
+ break;
- /* Is it a 512K board */
- if ((board_id & 0x30) == 0x30)
- bd->memory_seg = 0x8000;
+ case PCXI:
+ case PC64XE:
+ bd->memwinon = pcxi_memwinon;
+ bd->memwinoff = pcxi_memwinoff;
+ bd->globalwinon = pcxi_globalwinon;
+ bd->txwinon = pcxi_txwinon;
+ bd->rxwinon = pcxi_rxwinon;
+ bd->memoff = pcxi_memoff;
+ bd->assertgwinon = pcxi_assertgwinon;
+ bd->assertmemoff = pcxi_assertmemoff;
+ break;
- } else printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
+ default:
break;
+ }
- } /* End switch on bd->type */
+ /*
+ * Some cards need a memory segment to be defined for use in
+ * transmit and receive windowing operations. These boards are
+ * listed in the below switch. In the case of the XI the amount
+ * of memory on the board is variable so the memory_seg is also
+ * variable. This code determines what they segment should be.
+ */
+ switch (bd->type) {
+ case PCXE:
+ case PCXEVE:
+ case PC64XE:
+ bd->memory_seg = 0xf000;
+ break;
- } /* End for each card */
+ case PCXI:
+ board_id = inb((int)bd->port);
+ if ((board_id & 0x1) == 0x1) {
+ /* it's an XI card */
+ /* Is it a 64K board */
+ if ((board_id & 0x30) == 0)
+ bd->memory_seg = 0xf000;
+
+ /* Is it a 128K board */
+ if ((board_id & 0x30) == 0x10)
+ bd->memory_seg = 0xe000;
+
+ /* Is is a 256K board */
+ if ((board_id & 0x30) == 0x20)
+ bd->memory_seg = 0xc000;
+
+ /* Is it a 512K board */
+ if ((board_id & 0x30) == 0x30)
+ bd->memory_seg = 0x8000;
+ } else
+ printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
+ break;
+ }
+ }
err = tty_register_driver(pc_driver);
if (err) {
@@ -1383,10 +1269,7 @@ static int __init pc_init(void)
goto out4;
}
- /* -------------------------------------------------------------------
- Start up the poller to check for events on all enabled boards
- ---------------------------------------------------------------------- */
-
+ /* Start up the poller to check for events on all enabled boards */
init_timer(&epca_timer);
epca_timer.function = epcapoll;
mod_timer(&epca_timer, jiffies + HZ/25);
@@ -1400,51 +1283,47 @@ out2:
put_tty_driver(pc_driver);
out1:
return err;
-
-} /* End pc_init */
-
-/* ------------------ Begin post_fep_init ---------------------- */
+}
static void post_fep_init(unsigned int crd)
-{ /* Begin post_fep_init */
-
+{
int i;
void __iomem *memaddr;
struct global_data __iomem *gd;
struct board_info *bd;
struct board_chan __iomem *bc;
- struct channel *ch;
- int shrinkmem = 0, lowwater ;
-
- /* -------------------------------------------------------------
- This call is made by the user via. the ioctl call DIGI_INIT.
- It is responsible for setting up all the card specific stuff.
- ---------------------------------------------------------------- */
- bd = &boards[crd];
+ struct channel *ch;
+ int shrinkmem = 0, lowwater;
- /* -----------------------------------------------------------------
- If this is a PCI board, get the port info. Remember PCI cards
- do not have entries into the epcaconfig.h file, so we can't get
- the number of ports from it. Unfortunetly, this means that anyone
- doing a DIGI_GETINFO before the board has booted will get an invalid
- number of ports returned (It should return 0). Calls to DIGI_GETINFO
- after DIGI_INIT has been called will return the proper values.
- ------------------------------------------------------------------- */
+ /*
+ * This call is made by the user via. the ioctl call DIGI_INIT. It is
+ * responsible for setting up all the card specific stuff.
+ */
+ bd = &boards[crd];
+ /*
+ * If this is a PCI board, get the port info. Remember PCI cards do not
+ * have entries into the epcaconfig.h file, so we can't get the number
+ * of ports from it. Unfortunetly, this means that anyone doing a
+ * DIGI_GETINFO before the board has booted will get an invalid number
+ * of ports returned (It should return 0). Calls to DIGI_GETINFO after
+ * DIGI_INIT has been called will return the proper values.
+ */
if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */
- /* --------------------------------------------------------------------
- Below we use XEMPORTS as a memory offset regardless of which PCI
- card it is. This is because all of the supported PCI cards have
- the same memory offset for the channel data. This will have to be
- changed if we ever develop a PCI/XE card. NOTE : The FEP manual
- states that the port offset is 0xC22 as opposed to 0xC02. This is
- only true for PC/XE, and PC/XI cards; not for the XEM, or CX series.
- On the PCI cards the number of ports is determined by reading a
- ID PROM located in the box attached to the card. The card can then
- determine the index the id to determine the number of ports available.
- (FYI - The id should be located at 0x1ac (And may use up to 4 bytes
- if the box in question is a XEM or CX)).
- ------------------------------------------------------------------------ */
+ /*
+ * Below we use XEMPORTS as a memory offset regardless of which
+ * PCI card it is. This is because all of the supported PCI
+ * cards have the same memory offset for the channel data. This
+ * will have to be changed if we ever develop a PCI/XE card.
+ * NOTE : The FEP manual states that the port offset is 0xC22
+ * as opposed to 0xC02. This is only true for PC/XE, and PC/XI
+ * cards; not for the XEM, or CX series. On the PCI cards the
+ * number of ports is determined by reading a ID PROM located
+ * in the box attached to the card. The card can then determine
+ * the index the id to determine the number of ports available.
+ * (FYI - The id should be located at 0x1ac (And may use up to
+ * 4 bytes if the box in question is a XEM or CX)).
+ */
/* PCI cards are already remapped at this point ISA are not */
bd->numports = readw(bd->re_map_membase + XEMPORTS);
epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");
@@ -1465,95 +1344,87 @@ static void post_fep_init(unsigned int crd)
memaddr = bd->re_map_membase;
- /* -----------------------------------------------------------------
- The below assignment will set bc to point at the BEGINING of
- the cards channel structures. For 1 card there will be between
- 8 and 64 of these structures.
- -------------------------------------------------------------------- */
-
+ /*
+ * The below assignment will set bc to point at the BEGINING of the
+ * cards channel structures. For 1 card there will be between 8 and 64
+ * of these structures.
+ */
bc = memaddr + CHANSTRUCT;
- /* -------------------------------------------------------------------
- The below assignment will set gd to point at the BEGINING of
- global memory address 0xc00. The first data in that global
- memory actually starts at address 0xc1a. The command in
- pointer begins at 0xd10.
- ---------------------------------------------------------------------- */
-
+ /*
+ * The below assignment will set gd to point at the BEGINING of global
+ * memory address 0xc00. The first data in that global memory actually
+ * starts at address 0xc1a. The command in pointer begins at 0xd10.
+ */
gd = memaddr + GLOBAL;
- /* --------------------------------------------------------------------
- XEPORTS (address 0xc22) points at the number of channels the
- card supports. (For 64XE, XI, XEM, and XR use 0xc02)
- ----------------------------------------------------------------------- */
-
+ /*
+ * XEPORTS (address 0xc22) points at the number of channels the card
+ * supports. (For 64XE, XI, XEM, and XR use 0xc02)
+ */
if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3))
shrinkmem = 1;
if (bd->type < PCIXEM)
if (!request_region((int)bd->port, 4, board_desc[bd->type]))
- return;
+ return;
memwinon(bd, 0);
- /* --------------------------------------------------------------------
- Remember ch is the main drivers channels structure, while bc is
- the cards channel structure.
- ------------------------------------------------------------------------ */
-
- /* For every port on the card do ..... */
-
- for (i = 0; i < bd->numports; i++, ch++, bc++) { /* Begin for each port */
+ /*
+ * Remember ch is the main drivers channels structure, while bc is the
+ * cards channel structure.
+ */
+ for (i = 0; i < bd->numports; i++, ch++, bc++) {
unsigned long flags;
u16 tseg, rseg;
- ch->brdchan = bc;
- ch->mailbox = gd;
+ ch->brdchan = bc;
+ ch->mailbox = gd;
INIT_WORK(&ch->tqueue, do_softint);
- ch->board = &boards[crd];
+ ch->board = &boards[crd];
spin_lock_irqsave(&epca_lock, flags);
switch (bd->type) {
- /* ----------------------------------------------------------------
- Since some of the boards use different bitmaps for their
- control signals we cannot hard code these values and retain
- portability. We virtualize this data here.
- ------------------------------------------------------------------- */
- case EISAXEM:
- case PCXEM:
- case PCIXEM:
- case PCIXRJ:
- case PCIXR:
- ch->m_rts = 0x02 ;
- ch->m_dcd = 0x80 ;
- ch->m_dsr = 0x20 ;
- ch->m_cts = 0x10 ;
- ch->m_ri = 0x40 ;
- ch->m_dtr = 0x01 ;
- break;
-
- case PCXE:
- case PCXEVE:
- case PCXI:
- case PC64XE:
- ch->m_rts = 0x02 ;
- ch->m_dcd = 0x08 ;
- ch->m_dsr = 0x10 ;
- ch->m_cts = 0x20 ;
- ch->m_ri = 0x40 ;
- ch->m_dtr = 0x80 ;
- break;
-
- } /* End switch bd->type */
+ /*
+ * Since some of the boards use different bitmaps for
+ * their control signals we cannot hard code these
+ * values and retain portability. We virtualize this
+ * data here.
+ */
+ case EISAXEM:
+ case PCXEM:
+ case PCIXEM:
+ case PCIXRJ:
+ case PCIXR:
+ ch->m_rts = 0x02;
+ ch->m_dcd = 0x80;
+ ch->m_dsr = 0x20;
+ ch->m_cts = 0x10;
+ ch->m_ri = 0x40;
+ ch->m_dtr = 0x01;
+ break;
+
+ case PCXE:
+ case PCXEVE:
+ case PCXI:
+ case PC64XE:
+ ch->m_rts = 0x02;
+ ch->m_dcd = 0x08;
+ ch->m_dsr = 0x10;
+ ch->m_cts = 0x20;
+ ch->m_ri = 0x40;
+ ch->m_dtr = 0x80;
+ break;
+ }
if (boards[crd].altpin) {
ch->dsr = ch->m_dcd;
ch->dcd = ch->m_dsr;
ch->digiext.digi_flags |= DIGI_ALTPIN;
- }
- else {
+ } else {
ch->dcd = ch->m_dcd;
ch->dsr = ch->m_dsr;
}
-
+
ch->boardnum = crd;
ch->channelnum = i;
ch->magic = EPCA_MAGIC;
@@ -1568,71 +1439,67 @@ static void post_fep_init(unsigned int crd)
rseg = readw(&bc->rseg);
switch (bd->type) {
+ case PCIXEM:
+ case PCIXRJ:
+ case PCIXR:
+ /* Cover all the 2MEG cards */
+ ch->txptr = memaddr + ((tseg << 4) & 0x1fffff);
+ ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff);
+ ch->txwin = FEPWIN | (tseg >> 11);
+ ch->rxwin = FEPWIN | (rseg >> 11);
+ break;
- case PCIXEM:
- case PCIXRJ:
- case PCIXR:
- /* Cover all the 2MEG cards */
- ch->txptr = memaddr + ((tseg << 4) & 0x1fffff);
- ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff);
- ch->txwin = FEPWIN | (tseg >> 11);
- ch->rxwin = FEPWIN | (rseg >> 11);
- break;
-
- case PCXEM:
- case EISAXEM:
- /* Cover all the 32K windowed cards */
- /* Mask equal to window size - 1 */
- ch->txptr = memaddr + ((tseg << 4) & 0x7fff);
- ch->rxptr = memaddr + ((rseg << 4) & 0x7fff);
- ch->txwin = FEPWIN | (tseg >> 11);
- ch->rxwin = FEPWIN | (rseg >> 11);
- break;
-
- case PCXEVE:
- case PCXE:
- ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4) & 0x1fff);
- ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9);
- ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4) & 0x1fff);
- ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >>9 );
- break;
-
- case PCXI:
- case PC64XE:
- ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4);
- ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4);
- ch->txwin = ch->rxwin = 0;
- break;
-
- } /* End switch bd->type */
+ case PCXEM:
+ case EISAXEM:
+ /* Cover all the 32K windowed cards */
+ /* Mask equal to window size - 1 */
+ ch->txptr = memaddr + ((tseg << 4) & 0x7fff);
+ ch->rxptr = memaddr + ((rseg << 4) & 0x7fff);
+ ch->txwin = FEPWIN | (tseg >> 11);
+ ch->rxwin = FEPWIN | (rseg >> 11);
+ break;
+
+ case PCXEVE:
+ case PCXE:
+ ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4) & 0x1fff);
+ ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9);
+ ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4) & 0x1fff);
+ ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >>9 );
+ break;
+
+ case PCXI:
+ case PC64XE:
+ ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4);
+ ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4);
+ ch->txwin = ch->rxwin = 0;
+ break;
+ }
ch->txbufhead = 0;
ch->txbufsize = readw(&bc->tmax) + 1;
-
+
ch->rxbufhead = 0;
ch->rxbufsize = readw(&bc->rmax) + 1;
-
+
lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2);
/* Set transmitter low water mark */
fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);
/* Set receiver low water mark */
-
fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0);
/* Set receiver high water mark */
-
fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);
writew(100, &bc->edelay);
writeb(1, &bc->idata);
-
+
ch->startc = readb(&bc->startc);
ch->stopc = readb(&bc->stopc);
ch->startca = readb(&bc->startca);
ch->stopca = readb(&bc->stopca);
-
+
ch->fepcflag = 0;
ch->fepiflag = 0;
ch->fepoflag = 0;
@@ -1640,7 +1507,7 @@ static void post_fep_init(unsigned int crd)
ch->fepstopc = 0;
ch->fepstartca = 0;
ch->fepstopca = 0;
-
+
ch->close_delay = 50;
ch->count = 0;
ch->blocked_open = 0;
@@ -1648,80 +1515,66 @@ static void post_fep_init(unsigned int crd)
init_waitqueue_head(&ch->close_wait);
spin_unlock_irqrestore(&epca_lock, flags);
- } /* End for each port */
+ }
- printk(KERN_INFO
- "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
+ printk(KERN_INFO
+ "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n",
VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);
memwinoff(bd, 0);
-
-} /* End post_fep_init */
-
-/* --------------------- Begin epcapoll ------------------------ */
+}
static void epcapoll(unsigned long ignored)
-{ /* Begin epcapoll */
-
+{
unsigned long flags;
int crd;
volatile unsigned int head, tail;
struct channel *ch;
struct board_info *bd;
- /* -------------------------------------------------------------------
- This routine is called upon every timer interrupt. Even though
- the Digi series cards are capable of generating interrupts this
- method of non-looping polling is more efficient. This routine
- checks for card generated events (Such as receive data, are transmit
- buffer empty) and acts on those events.
- ----------------------------------------------------------------------- */
-
- for (crd = 0; crd < num_cards; crd++)
- { /* Begin for each card */
-
+ /*
+ * This routine is called upon every timer interrupt. Even though the
+ * Digi series cards are capable of generating interrupts this method
+ * of non-looping polling is more efficient. This routine checks for
+ * card generated events (Such as receive data, are transmit buffer
+ * empty) and acts on those events.
+ */
+ for (crd = 0; crd < num_cards; crd++) {
bd = &boards[crd];
ch = card_ptr[crd];
if ((bd->status == DISABLED) || digi_poller_inhibited)
- continue; /* Begin loop next interation */
-
- /* -----------------------------------------------------------
- assertmemoff is not needed here; indeed it is an empty subroutine.
- It is being kept because future boards may need this as well as
- some legacy boards.
- ---------------------------------------------------------------- */
+ continue;
+ /*
+ * assertmemoff is not needed here; indeed it is an empty
+ * subroutine. It is being kept because future boards may need
+ * this as well as some legacy boards.
+ */
spin_lock_irqsave(&epca_lock, flags);
assertmemoff(ch);
globalwinon(ch);
- /* ---------------------------------------------------------------
- In this case head and tail actually refer to the event queue not
- the transmit or receive queue.
- ------------------------------------------------------------------- */
-
+ /*
+ * In this case head and tail actually refer to the event queue
+ * not the transmit or receive queue.
+ */
head = readw(&ch->mailbox->ein);
tail = readw(&ch->mailbox->eout);
-
- /* If head isn't equal to tail we have an event */
+ /* If head isn't equal to tail we have an event */
if (head != tail)
doevent(crd);
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
-
} /* End for each card */
mod_timer(&epca_timer, jiffies + (HZ / 25));
-} /* End epcapoll */
-
-/* --------------------- Begin doevent ------------------------ */
+}
static void doevent(int crd)
-{ /* Begin doevent */
-
+{
void __iomem *eventbuf;
struct channel *ch, *chan0;
static struct tty_struct *tty;
@@ -1731,28 +1584,28 @@ static void doevent(int crd)
int event, channel;
int mstat, lstat;
- /* -------------------------------------------------------------------
- This subroutine is called by epcapoll when an event is detected
- in the event queue. This routine responds to those events.
- --------------------------------------------------------------------- */
+ /*
+ * This subroutine is called by epcapoll when an event is detected
+ * in the event queue. This routine responds to those events.
+ */
bd = &boards[crd];
chan0 = card_ptr[crd];
epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
assertgwinon(chan0);
- while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein)))
- { /* Begin while something in event queue */
+ while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein))) { /* Begin while something in event queue */
assertgwinon(chan0);
eventbuf = bd->re_map_membase + tail + ISTART;
/* Get the channel the event occurred on */
channel = readb(eventbuf);
/* Get the actual event code that occurred */
event = readb(eventbuf + 1);
- /* ----------------------------------------------------------------
- The two assignments below get the current modem status (mstat)
- and the previous modem status (lstat). These are useful becuase
- an event could signal a change in modem signals itself.
- ------------------------------------------------------------------- */
+ /*
+ * The two assignments below get the current modem status
+ * (mstat) and the previous modem status (lstat). These are
+ * useful becuase an event could signal a change in modem
+ * signals itself.
+ */
mstat = readb(eventbuf + 2);
lstat = readb(eventbuf + 3);
@@ -1772,37 +1625,36 @@ static void doevent(int crd)
assertgwinon(ch);
} /* End DATA_IND */
/* else *//* Fix for DCD transition missed bug */
- if (event & MODEMCHG_IND) { /* Begin MODEMCHG_IND */
+ if (event & MODEMCHG_IND) {
/* A modem signal change has been indicated */
ch->imodem = mstat;
- if (ch->asyncflags & ASYNC_CHECK_CD) {
+ if (ch->asyncflags & ASYNC_CHECK_CD) {
if (mstat & ch->dcd) /* We are now receiving dcd */
wake_up_interruptible(&ch->open_wait);
else
pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */
}
- } /* End MODEMCHG_IND */
+ }
tty = ch->tty;
- if (tty) { /* Begin if valid tty */
- if (event & BREAK_IND) { /* Begin if BREAK_IND */
+ if (tty) {
+ if (event & BREAK_IND) {
/* A break has been indicated */
tty_insert_flip_char(tty, 0, TTY_BREAK);
- tty_schedule_flip(tty);
- } else if (event & LOWTX_IND) { /* Begin LOWTX_IND */
- if (ch->statusflags & LOWWAIT)
- { /* Begin if LOWWAIT */
+ tty_schedule_flip(tty);
+ } else if (event & LOWTX_IND) {
+ if (ch->statusflags & LOWWAIT) {
ch->statusflags &= ~LOWWAIT;
tty_wakeup(tty);
- } /* End if LOWWAIT */
- } else if (event & EMPTYTX_IND) { /* Begin EMPTYTX_IND */
+ }
+ } else if (event & EMPTYTX_IND) {
/* This event is generated by setup_empty_event */
ch->statusflags &= ~TXBUSY;
- if (ch->statusflags & EMPTYWAIT) { /* Begin if EMPTYWAIT */
+ if (ch->statusflags & EMPTYWAIT) {
ch->statusflags &= ~EMPTYWAIT;
tty_wakeup(tty);
- } /* End if EMPTYWAIT */
- } /* End EMPTYTX_IND */
- } /* End if valid tty */
+ }
+ }
+ }
next:
globalwinon(ch);
BUG_ON(!bc);
@@ -1810,13 +1662,11 @@ static void doevent(int crd)
writew((tail + 4) & (IMAX - ISTART - 4), &chan0->mailbox->eout);
globalwinon(chan0);
} /* End while something in event queue */
-} /* End doevent */
-
-/* --------------------- Begin fepcmd ------------------------ */
+}
static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
int byte2, int ncmds, int bytecmd)
-{ /* Begin fepcmd */
+{
unchar __iomem *memaddr;
unsigned int head, cmdTail, cmdStart, cmdMax;
long count;
@@ -1831,11 +1681,11 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
head = readw(&ch->mailbox->cin);
/* cmdStart is a base address */
cmdStart = readw(&ch->mailbox->cstart);
- /* ------------------------------------------------------------------
- We do the addition below because we do not want a max pointer
- relative to cmdStart. We want a max pointer that points at the
- physical end of the command queue.
- -------------------------------------------------------------------- */
+ /*
+ * We do the addition below because we do not want a max pointer
+ * relative to cmdStart. We want a max pointer that points at the
+ * physical end of the command queue.
+ */
cmdMax = (cmdStart + 4 + readw(&ch->mailbox->cmax));
memaddr = ch->board->re_map_membase;
@@ -1860,7 +1710,7 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
writew(head, &ch->mailbox->cin);
count = FEPTIMEOUT;
- for (;;) { /* Begin forever loop */
+ for (;;) {
count--;
if (count == 0) {
printk(KERN_ERR "<Error> - Fep not responding in fepcmd()\n");
@@ -1869,26 +1719,23 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
head = readw(&ch->mailbox->cin);
cmdTail = readw(&ch->mailbox->cout);
n = (head - cmdTail) & (cmdMax - cmdStart - 4);
- /* ----------------------------------------------------------
- Basically this will break when the FEP acknowledges the
- command by incrementing cmdTail (Making it equal to head).
- ------------------------------------------------------------- */
+ /*
+ * Basically this will break when the FEP acknowledges the
+ * command by incrementing cmdTail (Making it equal to head).
+ */
if (n <= ncmds * (sizeof(short) * 4))
- break; /* Well nearly forever :-) */
- } /* End forever loop */
-} /* End fepcmd */
-
-/* ---------------------------------------------------------------------
- Digi products use fields in their channels structures that are very
- similar to the c_cflag and c_iflag fields typically found in UNIX
- termios structures. The below three routines allow mappings
- between these hardware "flags" and their respective Linux flags.
-------------------------------------------------------------------------- */
-
-/* --------------------- Begin termios2digi_h -------------------- */
+ break;
+ }
+}
+/*
+ * Digi products use fields in their channels structures that are very similar
+ * to the c_cflag and c_iflag fields typically found in UNIX termios
+ * structures. The below three routines allow mappings between these hardware
+ * "flags" and their respective Linux flags.
+ */
static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
-{ /* Begin termios2digi_h */
+{
unsigned res = 0;
if (cflag & CRTSCTS) {
@@ -1918,86 +1765,73 @@ static unsigned termios2digi_h(struct channel *ch, unsigned cflag)
ch->digiext.digi_flags |= CTSPACE;
return res;
+}
-} /* End termios2digi_h */
-
-/* --------------------- Begin termios2digi_i -------------------- */
static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
-{ /* Begin termios2digi_i */
-
- unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
+{
+ unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
INPCK | ISTRIP|IXON|IXANY|IXOFF);
if (ch->digiext.digi_flags & DIGI_AIXON)
res |= IAIXON;
return res;
-
-} /* End termios2digi_i */
-
-/* --------------------- Begin termios2digi_c -------------------- */
+}
static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
-{ /* Begin termios2digi_c */
-
+{
unsigned res = 0;
- if (cflag & CBAUDEX) { /* Begin detected CBAUDEX */
+ if (cflag & CBAUDEX) {
ch->digiext.digi_flags |= DIGI_FAST;
- /* -------------------------------------------------------------
- HUPCL bit is used by FEP to indicate fast baud
- table is to be used.
- ----------------------------------------------------------------- */
+ /*
+ * HUPCL bit is used by FEP to indicate fast baud table is to
+ * be used.
+ */
res |= FEP_HUPCL;
- } /* End detected CBAUDEX */
- else ch->digiext.digi_flags &= ~DIGI_FAST;
- /* -------------------------------------------------------------------
- CBAUD has bit position 0x1000 set these days to indicate Linux
- baud rate remap. Digi hardware can't handle the bit assignment.
- (We use a different bit assignment for high speed.). Clear this
- bit out.
- ---------------------------------------------------------------------- */
+ } else
+ ch->digiext.digi_flags &= ~DIGI_FAST;
+ /*
+ * CBAUD has bit position 0x1000 set these days to indicate Linux
+ * baud rate remap. Digi hardware can't handle the bit assignment.
+ * (We use a different bit assignment for high speed.). Clear this
+ * bit out.
+ */
res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE);
- /* -------------------------------------------------------------
- This gets a little confusing. The Digi cards have their own
- representation of c_cflags controling baud rate. For the most
- part this is identical to the Linux implementation. However;
- Digi supports one rate (76800) that Linux doesn't. This means
- that the c_cflag entry that would normally mean 76800 for Digi
- actually means 115200 under Linux. Without the below mapping,
- a stty 115200 would only drive the board at 76800. Since
- the rate 230400 is also found after 76800, the same problem afflicts
- us when we choose a rate of 230400. Without the below modificiation
- stty 230400 would actually give us 115200.
-
- There are two additional differences. The Linux value for CLOCAL
- (0x800; 0004000) has no meaning to the Digi hardware. Also in
- later releases of Linux; the CBAUD define has CBAUDEX (0x1000;
- 0010000) ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX
- should be checked for a screened out prior to termios2digi_c
- returning. Since CLOCAL isn't used by the board this can be
- ignored as long as the returned value is used only by Digi hardware.
- ----------------------------------------------------------------- */
+ /*
+ * This gets a little confusing. The Digi cards have their own
+ * representation of c_cflags controling baud rate. For the most part
+ * this is identical to the Linux implementation. However; Digi
+ * supports one rate (76800) that Linux doesn't. This means that the
+ * c_cflag entry that would normally mean 76800 for Digi actually means
+ * 115200 under Linux. Without the below mapping, a stty 115200 would
+ * only drive the board at 76800. Since the rate 230400 is also found
+ * after 76800, the same problem afflicts us when we choose a rate of
+ * 230400. Without the below modificiation stty 230400 would actually
+ * give us 115200.
+ *
+ * There are two additional differences. The Linux value for CLOCAL
+ * (0x800; 0004000) has no meaning to the Digi hardware. Also in later
+ * releases of Linux; the CBAUD define has CBAUDEX (0x1000; 0010000)
+ * ored into it (CBAUD = 0x100f as opposed to 0xf). CBAUDEX should be
+ * checked for a screened out prior to termios2digi_c returning. Since
+ * CLOCAL isn't used by the board this can be ignored as long as the
+ * returned value is used only by Digi hardware.
+ */
if (cflag & CBAUDEX) {
- /* -------------------------------------------------------------
- The below code is trying to guarantee that only baud rates
- 115200 and 230400 are remapped. We use exclusive or because
- the various baud rates share common bit positions and therefore
- can't be tested for easily.
- ----------------------------------------------------------------- */
-
-
- if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
+ /*
+ * The below code is trying to guarantee that only baud rates
+ * 115200 and 230400 are remapped. We use exclusive or because
+ * the various baud rates share common bit positions and
+ * therefore can't be tested for easily.
+ */
+ if ((!((cflag & 0x7) ^ (B115200 & ~CBAUDEX))) ||
(!((cflag & 0x7) ^ (B230400 & ~CBAUDEX))))
res += 1;
}
return res;
-
-} /* End termios2digi_c */
-
-/* --------------------- Begin epcaparam ----------------------- */
+}
/* Caller must hold the locks */
static void epcaparam(struct tty_struct *tty, struct channel *ch)
-{ /* Begin epcaparam */
-
+{
unsigned int cmdHead;
struct ktermios *ts;
struct board_chan __iomem *bc;
@@ -2013,28 +1847,29 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
writew(cmdHead, &bc->rout);
cmdHead = readw(&bc->tin);
/* Changing baud in mid-stream transmission can be wonderful */
- /* ---------------------------------------------------------------
- Flush current transmit buffer by setting cmdTail pointer (tout)
- to cmdHead pointer (tin). Hopefully the transmit buffer is empty.
- ----------------------------------------------------------------- */
+ /*
+ * Flush current transmit buffer by setting cmdTail pointer
+ * (tout) to cmdHead pointer (tin). Hopefully the transmit
+ * buffer is empty.
+ */
fepcmd(ch, STOUT, (unsigned) cmdHead, 0, 0, 0);
mval = 0;
- } else { /* Begin CBAUD not detected */
- /* -------------------------------------------------------------------
- c_cflags have changed but that change had nothing to do with BAUD.
- Propagate the change to the card.
- ---------------------------------------------------------------------- */
+ } else { /* Begin CBAUD not detected */
+ /*
+ * c_cflags have changed but that change had nothing to do with
+ * BAUD. Propagate the change to the card.
+ */
cflag = termios2digi_c(ch, ts->c_cflag);
if (cflag != ch->fepcflag) {
ch->fepcflag = cflag;
/* Set baud rate, char size, stop bits, parity */
fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);
}
- /* ----------------------------------------------------------------
- If the user has not forced CLOCAL and if the device is not a
- CALLOUT device (Which is always CLOCAL) we set flags such that
- the driver will wait on carrier detect.
- ------------------------------------------------------------------- */
+ /*
+ * If the user has not forced CLOCAL and if the device is not a
+ * CALLOUT device (Which is always CLOCAL) we set flags such
+ * that the driver will wait on carrier detect.
+ */
if (ts->c_cflag & CLOCAL)
ch->asyncflags &= ~ASYNC_CHECK_CD;
else
@@ -2045,19 +1880,19 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
/* Check input mode flags */
if (iflag != ch->fepiflag) {
ch->fepiflag = iflag;
- /* ---------------------------------------------------------------
- Command sets channels iflag structure on the board. Such things
- as input soft flow control, handling of parity errors, and
- break handling are all set here.
- ------------------------------------------------------------------- */
+ /*
+ * Command sets channels iflag structure on the board. Such
+ * things as input soft flow control, handling of parity
+ * errors, and break handling are all set here.
+ */
/* break handling, parity handling, input stripping, flow control chars */
fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
}
- /* ---------------------------------------------------------------
- Set the board mint value for this channel. This will cause hardware
- events to be generated each time the DCD signal (Described in mint)
- changes.
- ------------------------------------------------------------------- */
+ /*
+ * Set the board mint value for this channel. This will cause hardware
+ * events to be generated each time the DCD signal (Described in mint)
+ * changes.
+ */
writeb(ch->dcd, &bc->mint);
if ((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))
if (ch->digiext.digi_flags & DIGI_FORCEDCD)
@@ -2066,23 +1901,23 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
hflow = termios2digi_h(ch, ts->c_cflag);
if (hflow != ch->hflow) {
ch->hflow = hflow;
- /* --------------------------------------------------------------
- Hard flow control has been selected but the board is not
- using it. Activate hard flow control now.
- ----------------------------------------------------------------- */
+ /*
+ * Hard flow control has been selected but the board is not
+ * using it. Activate hard flow control now.
+ */
fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);
}
mval ^= ch->modemfake & (mval ^ ch->modem);
if (ch->omodem ^ mval) {
ch->omodem = mval;
- /* --------------------------------------------------------------
- The below command sets the DTR and RTS mstat structure. If
- hard flow control is NOT active these changes will drive the
- output of the actual DTR and RTS lines. If hard flow control
- is active, the changes will be saved in the mstat structure and
- only asserted when hard flow control is turned off.
- ----------------------------------------------------------------- */
+ /*
+ * The below command sets the DTR and RTS mstat structure. If
+ * hard flow control is NOT active these changes will drive the
+ * output of the actual DTR and RTS lines. If hard flow control
+ * is active, the changes will be saved in the mstat structure
+ * and only asserted when hard flow control is turned off.
+ */
/* First reset DTR & RTS; then set them */
fepcmd(ch, SETMODEM, 0, ((ch->m_dtr)|(ch->m_rts)), 0, 1);
@@ -2091,28 +1926,26 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
if (ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {
ch->fepstartc = ch->startc;
ch->fepstopc = ch->stopc;
- /* ------------------------------------------------------------
- The XON / XOFF characters have changed; propagate these
- changes to the card.
- --------------------------------------------------------------- */
+ /*
+ * The XON / XOFF characters have changed; propagate these
+ * changes to the card.
+ */
fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
}
if (ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {
ch->fepstartca = ch->startca;
ch->fepstopca = ch->stopca;
- /* ---------------------------------------------------------------
- Similar to the above, this time the auxilarly XON / XOFF
- characters have changed; propagate these changes to the card.
- ------------------------------------------------------------------ */
+ /*
+ * Similar to the above, this time the auxilarly XON / XOFF
+ * characters have changed; propagate these changes to the card.
+ */
fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
}
-} /* End epcaparam */
+}
-/* --------------------- Begin receive_data ----------------------- */
/* Caller holds lock */
static void receive_data(struct channel *ch)
-{ /* Begin receive_data */
-
+{
unchar *rptr;
struct ktermios *ts = NULL;
struct tty_struct *tty;
@@ -2121,11 +1954,10 @@ static void receive_data(struct channel *ch)
unsigned int tail, head;
unsigned int wrapmask;
- /* ---------------------------------------------------------------
- This routine is called by doint when a receive data event
- has taken place.
- ------------------------------------------------------------------- */
-
+ /*
+ * This routine is called by doint when a receive data event has taken
+ * place.
+ */
globalwinon(ch);
if (ch->statusflags & RXSTOPPED)
return;
@@ -2136,10 +1968,10 @@ static void receive_data(struct channel *ch)
BUG_ON(!bc);
wrapmask = ch->rxbufsize - 1;
- /* ---------------------------------------------------------------------
- Get the head and tail pointers to the receiver queue. Wrap the
- head pointer if it has reached the end of the buffer.
- ------------------------------------------------------------------------ */
+ /*
+ * Get the head and tail pointers to the receiver queue. Wrap the head
+ * pointer if it has reached the end of the buffer.
+ */
head = readw(&bc->rin);
head &= wrapmask;
tail = readw(&bc->rout) & wrapmask;
@@ -2148,10 +1980,7 @@ static void receive_data(struct channel *ch)
if (bytesAvailable == 0)
return;
- /* ------------------------------------------------------------------
- If CREAD bit is off or device not open, set TX tail to head
- --------------------------------------------------------------------- */
-
+ /* If CREAD bit is off or device not open, set TX tail to head */
if (!tty || !ts || !(ts->c_cflag & CREAD)) {
writew(head, &bc->rout);
return;
@@ -2168,22 +1997,20 @@ static void receive_data(struct channel *ch)
rxwinon(ch);
while (bytesAvailable > 0) { /* Begin while there is data on the card */
wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;
- /* ---------------------------------------------------------------
- Even if head has wrapped around only report the amount of
- data to be equal to the size - tail. Remember memcpy can't
- automaticly wrap around the receive buffer.
- ----------------------------------------------------------------- */
+ /*
+ * Even if head has wrapped around only report the amount of
+ * data to be equal to the size - tail. Remember memcpy can't
+ * automaticly wrap around the receive buffer.
+ */
dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable;
- /* --------------------------------------------------------------
- Make sure we don't overflow the buffer
- ----------------------------------------------------------------- */
+ /* Make sure we don't overflow the buffer */
dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead);
if (dataToRead == 0)
break;
- /* ---------------------------------------------------------------
- Move data read from our card into the line disciplines buffer
- for translation if necessary.
- ------------------------------------------------------------------ */
+ /*
+ * Move data read from our card into the line disciplines
+ * buffer for translation if necessary.
+ */
memcpy_fromio(rptr, ch->rxptr + tail, dataToRead);
tail = (tail + dataToRead) & wrapmask;
bytesAvailable -= dataToRead;
@@ -2191,28 +2018,26 @@ static void receive_data(struct channel *ch)
globalwinon(ch);
writew(tail, &bc->rout);
/* Must be called with global data */
- tty_schedule_flip(ch->tty);
- return;
-} /* End receive_data */
+ tty_schedule_flip(ch->tty);
+}
-static int info_ioctl(struct tty_struct *tty, struct file * file,
+static int info_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- switch (cmd)
- { /* Begin switch cmd */
- case DIGI_GETINFO:
- { /* Begin case DIGI_GETINFO */
- struct digi_info di ;
+ switch (cmd) {
+ case DIGI_GETINFO:
+ {
+ struct digi_info di;
int brd;
- if(get_user(brd, (unsigned int __user *)arg))
+ if (get_user(brd, (unsigned int __user *)arg))
return -EFAULT;
if (brd < 0 || brd >= num_cards || num_cards == 0)
return -ENODEV;
memset(&di, 0, sizeof(di));
- di.board = brd ;
+ di.board = brd;
di.status = boards[brd].status;
di.type = boards[brd].type ;
di.numports = boards[brd].numports ;
@@ -2220,45 +2045,44 @@ static int info_ioctl(struct tty_struct *tty, struct file * file,
di.port = (unsigned char *)boards[brd].port ;
di.membase = (unsigned char *)boards[brd].membase ;
- if (copy_to_user((void __user *)arg, &di, sizeof (di)))
+ if (copy_to_user((void __user *)arg, &di, sizeof(di)))
return -EFAULT;
break;
- } /* End case DIGI_GETINFO */
-
- case DIGI_POLLER:
- { /* Begin case DIGI_POLLER */
+ }
- int brd = arg & 0xff000000 >> 16 ;
- unsigned char state = arg & 0xff ;
+ case DIGI_POLLER:
+ {
+ int brd = arg & 0xff000000 >> 16;
+ unsigned char state = arg & 0xff;
if (brd < 0 || brd >= num_cards) {
printk(KERN_ERR "epca: DIGI POLLER : brd not valid!\n");
- return (-ENODEV);
+ return -ENODEV;
}
- digi_poller_inhibited = state ;
- break ;
- } /* End case DIGI_POLLER */
-
- case DIGI_INIT:
- { /* Begin case DIGI_INIT */
- /* ------------------------------------------------------------
- This call is made by the apps to complete the initilization
- of the board(s). This routine is responsible for setting
- the card to its initial state and setting the drivers control
- fields to the sutianle settings for the card in question.
- ---------------------------------------------------------------- */
- int crd ;
- for (crd = 0; crd < num_cards; crd++)
- post_fep_init (crd);
- break ;
- } /* End case DIGI_INIT */
- default:
- return -ENOTTY;
- } /* End switch cmd */
- return (0) ;
+ digi_poller_inhibited = state;
+ break;
+ }
+
+ case DIGI_INIT:
+ {
+ /*
+ * This call is made by the apps to complete the
+ * initilization of the board(s). This routine is
+ * responsible for setting the card to its initial
+ * state and setting the drivers control fields to the
+ * sutianle settings for the card in question.
+ */
+ int crd;
+ for (crd = 0; crd < num_cards; crd++)
+ post_fep_init(crd);
+ break;
+ }
+ default:
+ return -ENOTTY;
+ }
+ return 0;
}
-/* --------------------- Begin pc_ioctl ----------------------- */
static int pc_tiocmget(struct tty_struct *tty, struct file *file)
{
@@ -2304,9 +2128,9 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
spin_lock_irqsave(&epca_lock, flags);
/*
- * I think this modemfake stuff is broken. It doesn't
- * correctly reflect the behaviour desired by the TIOCM*
- * ioctls. Therefore this is probably broken.
+ * I think this modemfake stuff is broken. It doesn't correctly reflect
+ * the behaviour desired by the TIOCM* ioctls. Therefore this is
+ * probably broken.
*/
if (set & TIOCM_RTS) {
ch->modemfake |= ch->m_rts;
@@ -2325,10 +2149,10 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
ch->modem &= ~ch->m_dtr;
}
globalwinon(ch);
- /* --------------------------------------------------------------
- The below routine generally sets up parity, baud, flow control
- issues, etc.... It effect both control flags and input flags.
- ------------------------------------------------------------------ */
+ /*
+ * The below routine generally sets up parity, baud, flow control
+ * issues, etc.... It effect both control flags and input flags.
+ */
epcaparam(tty,ch);
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
@@ -2337,8 +2161,7 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file,
static int pc_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
-{ /* Begin pc_ioctl */
-
+{
digiflow_t dflow;
int retval;
unsigned long flags;
@@ -2347,49 +2170,47 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
struct board_chan __iomem *bc;
struct channel *ch = (struct channel *) tty->driver_data;
void __user *argp = (void __user *)arg;
-
+
if (ch)
bc = ch->brdchan;
- else
+ else
return -EINVAL;
- /* -------------------------------------------------------------------
- For POSIX compliance we need to add more ioctls. See tty_ioctl.c
- in /usr/src/linux/drivers/char for a good example. In particular
- think about adding TCSETAF, TCSETAW, TCSETA, TCSETSF, TCSETSW, TCSETS.
- ---------------------------------------------------------------------- */
-
- switch (cmd)
- { /* Begin switch cmd */
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- /* Setup an event to indicate when the transmit buffer empties */
- spin_lock_irqsave(&epca_lock, flags);
- setup_empty_event(tty,ch);
- spin_unlock_irqrestore(&epca_lock, flags);
- tty_wait_until_sent(tty, 0);
- if (!arg)
- digi_send_break(ch, HZ/4); /* 1/4 second */
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
+ /*
+ * For POSIX compliance we need to add more ioctls. See tty_ioctl.c in
+ * /usr/src/linux/drivers/char for a good example. In particular think
+ * about adding TCSETAF, TCSETAW, TCSETA, TCSETSF, TCSETSW, TCSETS.
+ */
+ switch (cmd) {
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ /* Setup an event to indicate when the transmit buffer empties */
+ spin_lock_irqsave(&epca_lock, flags);
+ setup_empty_event(tty,ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
+ tty_wait_until_sent(tty, 0);
+ if (!arg)
+ digi_send_break(ch, HZ / 4); /* 1/4 second */
+ return 0;
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
- /* Setup an event to indicate when the transmit buffer empties */
- spin_lock_irqsave(&epca_lock, flags);
- setup_empty_event(tty,ch);
- spin_unlock_irqrestore(&epca_lock, flags);
- tty_wait_until_sent(tty, 0);
- digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
- return 0;
- case TIOCGSOFTCAR:
- if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)arg))
- return -EFAULT;
- return 0;
- case TIOCSSOFTCAR:
+ /* Setup an event to indicate when the transmit buffer empties */
+ spin_lock_irqsave(&epca_lock, flags);
+ setup_empty_event(tty,ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
+ tty_wait_until_sent(tty, 0);
+ digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);
+ return 0;
+ case TIOCGSOFTCAR:
+ if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)arg))
+ return -EFAULT;
+ return 0;
+ case TIOCSSOFTCAR:
{
unsigned int value;
@@ -2400,144 +2221,141 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file,
(value ? CLOCAL : 0));
return 0;
}
- case TIOCMODG:
- mflag = pc_tiocmget(tty, file);
- if (put_user(mflag, (unsigned long __user *)argp))
- return -EFAULT;
- break;
- case TIOCMODS:
- if (get_user(mstat, (unsigned __user *)argp))
- return -EFAULT;
- return pc_tiocmset(tty, file, mstat, ~mstat);
- case TIOCSDTR:
- spin_lock_irqsave(&epca_lock, flags);
- ch->omodem |= ch->m_dtr;
- globalwinon(ch);
- fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
- memoff(ch);
- spin_unlock_irqrestore(&epca_lock, flags);
- break;
+ case TIOCMODG:
+ mflag = pc_tiocmget(tty, file);
+ if (put_user(mflag, (unsigned long __user *)argp))
+ return -EFAULT;
+ break;
+ case TIOCMODS:
+ if (get_user(mstat, (unsigned __user *)argp))
+ return -EFAULT;
+ return pc_tiocmset(tty, file, mstat, ~mstat);
+ case TIOCSDTR:
+ spin_lock_irqsave(&epca_lock, flags);
+ ch->omodem |= ch->m_dtr;
+ globalwinon(ch);
+ fepcmd(ch, SETMODEM, ch->m_dtr, 0, 10, 1);
+ memoff(ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
+ break;
- case TIOCCDTR:
+ case TIOCCDTR:
+ spin_lock_irqsave(&epca_lock, flags);
+ ch->omodem &= ~ch->m_dtr;
+ globalwinon(ch);
+ fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
+ memoff(ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
+ break;
+ case DIGI_GETA:
+ if (copy_to_user(argp, &ch->digiext, sizeof(digi_t)))
+ return -EFAULT;
+ break;
+ case DIGI_SETAW:
+ case DIGI_SETAF:
+ if (cmd == DIGI_SETAW) {
+ /* Setup an event to indicate when the transmit buffer empties */
spin_lock_irqsave(&epca_lock, flags);
- ch->omodem &= ~ch->m_dtr;
- globalwinon(ch);
- fepcmd(ch, SETMODEM, 0, ch->m_dtr, 10, 1);
- memoff(ch);
+ setup_empty_event(tty,ch);
spin_unlock_irqrestore(&epca_lock, flags);
- break;
- case DIGI_GETA:
- if (copy_to_user(argp, &ch->digiext, sizeof(digi_t)))
- return -EFAULT;
- break;
- case DIGI_SETAW:
- case DIGI_SETAF:
- if (cmd == DIGI_SETAW) {
- /* Setup an event to indicate when the transmit buffer empties */
- spin_lock_irqsave(&epca_lock, flags);
- setup_empty_event(tty,ch);
- spin_unlock_irqrestore(&epca_lock, flags);
- tty_wait_until_sent(tty, 0);
- } else {
- /* ldisc lock already held in ioctl */
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
- }
- /* Fall Thru */
- case DIGI_SETA:
- if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
- return -EFAULT;
-
- if (ch->digiext.digi_flags & DIGI_ALTPIN) {
- ch->dcd = ch->m_dsr;
- ch->dsr = ch->m_dcd;
- } else {
- ch->dcd = ch->m_dcd;
- ch->dsr = ch->m_dsr;
+ tty_wait_until_sent(tty, 0);
+ } else {
+ /* ldisc lock already held in ioctl */
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ }
+ /* Fall Thru */
+ case DIGI_SETA:
+ if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
+ return -EFAULT;
+
+ if (ch->digiext.digi_flags & DIGI_ALTPIN) {
+ ch->dcd = ch->m_dsr;
+ ch->dsr = ch->m_dcd;
+ } else {
+ ch->dcd = ch->m_dcd;
+ ch->dsr = ch->m_dsr;
}
-
- spin_lock_irqsave(&epca_lock, flags);
- globalwinon(ch);
- /* -----------------------------------------------------------------
- The below routine generally sets up parity, baud, flow control
- issues, etc.... It effect both control flags and input flags.
- ------------------------------------------------------------------- */
+ spin_lock_irqsave(&epca_lock, flags);
+ globalwinon(ch);
- epcaparam(tty,ch);
- memoff(ch);
- spin_unlock_irqrestore(&epca_lock, flags);
- break;
+ /*
+ * The below routine generally sets up parity, baud, flow
+ * control issues, etc.... It effect both control flags and
+ * input flags.
+ */
+ epcaparam(tty,ch);
+ memoff(ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
+ break;
+
+ case DIGI_GETFLOW:
+ case DIGI_GETAFLOW:
+ spin_lock_irqsave(&epca_lock, flags);
+ globalwinon(ch);
+ if (cmd == DIGI_GETFLOW) {
+ dflow.startc = readb(&bc->startc);
+ dflow.stopc = readb(&bc->stopc);
+ } else {
+ dflow.startc = readb(&bc->startca);
+ dflow.stopc = readb(&bc->stopca);
+ }
+ memoff(ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
+
+ if (copy_to_user(argp, &dflow, sizeof(dflow)))
+ return -EFAULT;
+ break;
+
+ case DIGI_SETAFLOW:
+ case DIGI_SETFLOW:
+ if (cmd == DIGI_SETFLOW) {
+ startc = ch->startc;
+ stopc = ch->stopc;
+ } else {
+ startc = ch->startca;
+ stopc = ch->stopca;
+ }
+
+ if (copy_from_user(&dflow, argp, sizeof(dflow)))
+ return -EFAULT;
- case DIGI_GETFLOW:
- case DIGI_GETAFLOW:
+ if (dflow.startc != startc || dflow.stopc != stopc) { /* Begin if setflow toggled */
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- if (cmd == DIGI_GETFLOW) {
- dflow.startc = readb(&bc->startc);
- dflow.stopc = readb(&bc->stopc);
- } else {
- dflow.startc = readb(&bc->startca);
- dflow.stopc = readb(&bc->stopca);
- }
- memoff(ch);
- spin_unlock_irqrestore(&epca_lock, flags);
- if (copy_to_user(argp, &dflow, sizeof(dflow)))
- return -EFAULT;
- break;
-
- case DIGI_SETAFLOW:
- case DIGI_SETFLOW:
if (cmd == DIGI_SETFLOW) {
- startc = ch->startc;
- stopc = ch->stopc;
+ ch->fepstartc = ch->startc = dflow.startc;
+ ch->fepstopc = ch->stopc = dflow.stopc;
+ fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
} else {
- startc = ch->startca;
- stopc = ch->stopca;
+ ch->fepstartca = ch->startca = dflow.startc;
+ ch->fepstopca = ch->stopca = dflow.stopc;
+ fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
}
- if (copy_from_user(&dflow, argp, sizeof(dflow)))
- return -EFAULT;
+ if (ch->statusflags & TXSTOPPED)
+ pc_start(tty);
- if (dflow.startc != startc || dflow.stopc != stopc) { /* Begin if setflow toggled */
- spin_lock_irqsave(&epca_lock, flags);
- globalwinon(ch);
-
- if (cmd == DIGI_SETFLOW) {
- ch->fepstartc = ch->startc = dflow.startc;
- ch->fepstopc = ch->stopc = dflow.stopc;
- fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);
- } else {
- ch->fepstartca = ch->startca = dflow.startc;
- ch->fepstopca = ch->stopca = dflow.stopc;
- fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
- }
-
- if (ch->statusflags & TXSTOPPED)
- pc_start(tty);
-
- memoff(ch);
- spin_unlock_irqrestore(&epca_lock, flags);
- } /* End if setflow toggled */
- break;
- default:
- return -ENOIOCTLCMD;
- } /* End switch cmd */
+ memoff(ch);
+ spin_unlock_irqrestore(&epca_lock, flags);
+ } /* End if setflow toggled */
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
return 0;
-} /* End pc_ioctl */
-
-/* --------------------- Begin pc_set_termios ----------------------- */
+}
static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{ /* Begin pc_set_termios */
-
+{
struct channel *ch;
unsigned long flags;
- /* ---------------------------------------------------------
- verifyChannel returns the channel from the tty struct
- if it is valid. This serves as a sanity check.
- ------------------------------------------------------------- */
+ /*
+ * verifyChannel returns the channel from the tty struct if it is
+ * valid. This serves as a sanity check.
+ */
if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
@@ -2554,47 +2372,40 @@ static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
wake_up_interruptible(&ch->open_wait);
} /* End if channel valid */
-
-} /* End pc_set_termios */
-
-/* --------------------- Begin do_softint ----------------------- */
+}
static void do_softint(struct work_struct *work)
-{ /* Begin do_softint */
+{
struct channel *ch = container_of(work, struct channel, tqueue);
/* Called in response to a modem change event */
- if (ch && ch->magic == EPCA_MAGIC) { /* Begin EPCA_MAGIC */
+ if (ch && ch->magic == EPCA_MAGIC) {
struct tty_struct *tty = ch->tty;
if (tty && tty->driver_data) {
- if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { /* Begin if clear_bit */
+ if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
tty_hangup(tty); /* FIXME: module removal race here - AKPM */
wake_up_interruptible(&ch->open_wait);
ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
- } /* End if clear_bit */
+ }
}
- } /* End EPCA_MAGIC */
-} /* End do_softint */
-
-/* ------------------------------------------------------------
- pc_stop and pc_start provide software flow control to the
- routine and the pc_ioctl routine.
----------------------------------------------------------------- */
-
-/* --------------------- Begin pc_stop ----------------------- */
+ }
+}
+/*
+ * pc_stop and pc_start provide software flow control to the routine and the
+ * pc_ioctl routine.
+ */
static void pc_stop(struct tty_struct *tty)
-{ /* Begin pc_stop */
-
+{
struct channel *ch;
unsigned long flags;
- /* ---------------------------------------------------------
- verifyChannel returns the channel from the tty struct
- if it is valid. This serves as a sanity check.
- ------------------------------------------------------------- */
- if ((ch = verifyChannel(tty)) != NULL) { /* Begin if valid channel */
+ /*
+ * verifyChannel returns the channel from the tty struct if it is
+ * valid. This serves as a sanity check.
+ */
+ if ((ch = verifyChannel(tty)) != NULL) {
spin_lock_irqsave(&epca_lock, flags);
- if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */
+ if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */
globalwinon(ch);
/* STOP transmitting now !! */
fepcmd(ch, PAUSETX, 0, 0, 0, 0);
@@ -2602,19 +2413,17 @@ static void pc_stop(struct tty_struct *tty)
memoff(ch);
} /* End if transmit stop requested */
spin_unlock_irqrestore(&epca_lock, flags);
- } /* End if valid channel */
-} /* End pc_stop */
-
-/* --------------------- Begin pc_start ----------------------- */
+ }
+}
static void pc_start(struct tty_struct *tty)
-{ /* Begin pc_start */
+{
struct channel *ch;
- /* ---------------------------------------------------------
- verifyChannel returns the channel from the tty struct
- if it is valid. This serves as a sanity check.
- ------------------------------------------------------------- */
- if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
+ /*
+ * verifyChannel returns the channel from the tty struct if it is
+ * valid. This serves as a sanity check.
+ */
+ if ((ch = verifyChannel(tty)) != NULL) {
unsigned long flags;
spin_lock_irqsave(&epca_lock, flags);
/* Just in case output was resumed because of a change in Digi-flow */
@@ -2630,28 +2439,25 @@ static void pc_start(struct tty_struct *tty)
memoff(ch);
} /* End transmit resume requested */
spin_unlock_irqrestore(&epca_lock, flags);
- } /* End if channel valid */
-} /* End pc_start */
-
-/* ------------------------------------------------------------------
- The below routines pc_throttle and pc_unthrottle are used
- to slow (And resume) the receipt of data into the kernels
- receive buffers. The exact occurrence of this depends on the
- size of the kernels receive buffer and what the 'watermarks'
- are set to for that buffer. See the n_ttys.c file for more
- details.
-______________________________________________________________________ */
-/* --------------------- Begin throttle ----------------------- */
-
-static void pc_throttle(struct tty_struct * tty)
-{ /* Begin pc_throttle */
+ }
+}
+
+/*
+ * The below routines pc_throttle and pc_unthrottle are used to slow (And
+ * resume) the receipt of data into the kernels receive buffers. The exact
+ * occurrence of this depends on the size of the kernels receive buffer and
+ * what the 'watermarks' are set to for that buffer. See the n_ttys.c file for
+ * more details.
+ */
+static void pc_throttle(struct tty_struct *tty)
+{
struct channel *ch;
unsigned long flags;
- /* ---------------------------------------------------------
- verifyChannel returns the channel from the tty struct
- if it is valid. This serves as a sanity check.
- ------------------------------------------------------------- */
- if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
+ /*
+ * verifyChannel returns the channel from the tty struct if it is
+ * valid. This serves as a sanity check.
+ */
+ if ((ch = verifyChannel(tty)) != NULL) {
spin_lock_irqsave(&epca_lock, flags);
if ((ch->statusflags & RXSTOPPED) == 0) {
globalwinon(ch);
@@ -2660,20 +2466,18 @@ static void pc_throttle(struct tty_struct * tty)
memoff(ch);
}
spin_unlock_irqrestore(&epca_lock, flags);
- } /* End if channel valid */
-} /* End pc_throttle */
-
-/* --------------------- Begin unthrottle ----------------------- */
+ }
+}
static void pc_unthrottle(struct tty_struct *tty)
-{ /* Begin pc_unthrottle */
+{
struct channel *ch;
unsigned long flags;
- /* ---------------------------------------------------------
- verifyChannel returns the channel from the tty struct
- if it is valid. This serves as a sanity check.
- ------------------------------------------------------------- */
- if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */
+ /*
+ * verifyChannel returns the channel from the tty struct if it is
+ * valid. This serves as a sanity check.
+ */
+ if ((ch = verifyChannel(tty)) != NULL) {
/* Just in case output was resumed because of a change in Digi-flow */
spin_lock_irqsave(&epca_lock, flags);
if (ch->statusflags & RXSTOPPED) {
@@ -2683,151 +2487,143 @@ static void pc_unthrottle(struct tty_struct *tty)
memoff(ch);
}
spin_unlock_irqrestore(&epca_lock, flags);
- } /* End if channel valid */
-} /* End pc_unthrottle */
-
-/* --------------------- Begin digi_send_break ----------------------- */
+ }
+}
void digi_send_break(struct channel *ch, int msec)
-{ /* Begin digi_send_break */
+{
unsigned long flags;
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
- /* --------------------------------------------------------------------
- Maybe I should send an infinite break here, schedule() for
- msec amount of time, and then stop the break. This way,
- the user can't screw up the FEP by causing digi_send_break()
- to be called (i.e. via an ioctl()) more than once in msec amount
- of time. Try this for now...
- ------------------------------------------------------------------------ */
+ /*
+ * Maybe I should send an infinite break here, schedule() for msec
+ * amount of time, and then stop the break. This way, the user can't
+ * screw up the FEP by causing digi_send_break() to be called (i.e. via
+ * an ioctl()) more than once in msec amount of time.
+ * Try this for now...
+ */
fepcmd(ch, SENDBREAK, msec, 0, 10, 0);
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
-} /* End digi_send_break */
-
-/* --------------------- Begin setup_empty_event ----------------------- */
+}
/* Caller MUST hold the lock */
-
static void setup_empty_event(struct tty_struct *tty, struct channel *ch)
-{ /* Begin setup_empty_event */
-
+{
struct board_chan __iomem *bc = ch->brdchan;
globalwinon(ch);
ch->statusflags |= EMPTYWAIT;
- /* ------------------------------------------------------------------
- When set the iempty flag request a event to be generated when the
- transmit buffer is empty (If there is no BREAK in progress).
- --------------------------------------------------------------------- */
+ /*
+ * When set the iempty flag request a event to be generated when the
+ * transmit buffer is empty (If there is no BREAK in progress).
+ */
writeb(1, &bc->iempty);
memoff(ch);
-} /* End setup_empty_event */
+}
-/* ---------------------- Begin epca_setup -------------------------- */
void epca_setup(char *str, int *ints)
-{ /* Begin epca_setup */
+{
struct board_info board;
int index, loop, last;
char *temp, *t2;
unsigned len;
- /* ----------------------------------------------------------------------
- If this routine looks a little strange it is because it is only called
- if a LILO append command is given to boot the kernel with parameters.
- In this way, we can provide the user a method of changing his board
- configuration without rebuilding the kernel.
- ----------------------------------------------------------------------- */
- if (!liloconfig)
- liloconfig = 1;
+ /*
+ * If this routine looks a little strange it is because it is only
+ * called if a LILO append command is given to boot the kernel with
+ * parameters. In this way, we can provide the user a method of
+ * changing his board configuration without rebuilding the kernel.
+ */
+ if (!liloconfig)
+ liloconfig = 1;
memset(&board, 0, sizeof(board));
/* Assume the data is int first, later we can change it */
/* I think that array position 0 of ints holds the number of args */
for (last = 0, index = 1; index <= ints[0]; index++)
- switch(index)
- { /* Begin parse switch */
- case 1:
- board.status = ints[index];
- /* ---------------------------------------------------------
- We check for 2 (As opposed to 1; because 2 is a flag
- instructing the driver to ignore epcaconfig.) For this
- reason we check for 2.
- ------------------------------------------------------------ */
- if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */
- nbdevs = 0;
- num_cards = 0;
- return;
- } /* End ignore epcaconfig as well as lilo cmd line */
-
- if (board.status > 2) {
- printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n", board.status);
- invalid_lilo_config = 1;
- setup_error_code |= INVALID_BOARD_STATUS;
- return;
- }
- last = index;
- break;
- case 2:
- board.type = ints[index];
- if (board.type >= PCIXEM) {
- printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
- invalid_lilo_config = 1;
- setup_error_code |= INVALID_BOARD_TYPE;
- return;
- }
- last = index;
- break;
- case 3:
- board.altpin = ints[index];
- if (board.altpin > 1) {
- printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
- invalid_lilo_config = 1;
- setup_error_code |= INVALID_ALTPIN;
- return;
- }
- last = index;
- break;
-
- case 4:
- board.numports = ints[index];
- if (board.numports < 2 || board.numports > 256) {
- printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
- invalid_lilo_config = 1;
- setup_error_code |= INVALID_NUM_PORTS;
- return;
- }
- nbdevs += board.numports;
- last = index;
- break;
-
- case 5:
- board.port = ints[index];
- if (ints[index] <= 0) {
- printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
- invalid_lilo_config = 1;
- setup_error_code |= INVALID_PORT_BASE;
- return;
- }
- last = index;
- break;
-
- case 6:
- board.membase = ints[index];
- if (ints[index] <= 0) {
- printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
- invalid_lilo_config = 1;
- setup_error_code |= INVALID_MEM_BASE;
- return;
- }
- last = index;
- break;
+ switch (index) { /* Begin parse switch */
+ case 1:
+ board.status = ints[index];
+ /*
+ * We check for 2 (As opposed to 1; because 2 is a flag
+ * instructing the driver to ignore epcaconfig.) For
+ * this reason we check for 2.
+ */
+ if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */
+ nbdevs = 0;
+ num_cards = 0;
+ return;
+ } /* End ignore epcaconfig as well as lilo cmd line */
+
+ if (board.status > 2) {
+ printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n", board.status);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_BOARD_STATUS;
+ return;
+ }
+ last = index;
+ break;
+ case 2:
+ board.type = ints[index];
+ if (board.type >= PCIXEM) {
+ printk(KERN_ERR "epca_setup: Invalid board type 0x%x\n", board.type);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_BOARD_TYPE;
+ return;
+ }
+ last = index;
+ break;
+ case 3:
+ board.altpin = ints[index];
+ if (board.altpin > 1) {
+ printk(KERN_ERR "epca_setup: Invalid board altpin 0x%x\n", board.altpin);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_ALTPIN;
+ return;
+ }
+ last = index;
+ break;
+
+ case 4:
+ board.numports = ints[index];
+ if (board.numports < 2 || board.numports > 256) {
+ printk(KERN_ERR "epca_setup: Invalid board numports 0x%x\n", board.numports);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_NUM_PORTS;
+ return;
+ }
+ nbdevs += board.numports;
+ last = index;
+ break;
- default:
- printk(KERN_ERR "<Error> - epca_setup: Too many integer parms\n");
+ case 5:
+ board.port = ints[index];
+ if (ints[index] <= 0) {
+ printk(KERN_ERR "epca_setup: Invalid io port 0x%x\n", (unsigned int)board.port);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_PORT_BASE;
return;
+ }
+ last = index;
+ break;
+
+ case 6:
+ board.membase = ints[index];
+ if (ints[index] <= 0) {
+ printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_MEM_BASE;
+ return;
+ }
+ last = index;
+ break;
+
+ default:
+ printk(KERN_ERR "<Error> - epca_setup: Too many integer parms\n");
+ return;
} /* End parse switch */
@@ -2844,120 +2640,121 @@ void epca_setup(char *str, int *ints)
/* Set index to the number of args + 1 */
index = last + 1;
- switch(index)
- {
- case 1:
- len = strlen(str);
- if (strncmp("Disable", str, len) == 0)
- board.status = 0;
- else if (strncmp("Enable", str, len) == 0)
- board.status = 1;
- else {
- printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
- invalid_lilo_config = 1;
- setup_error_code |= INVALID_BOARD_STATUS;
- return;
- }
- last = index;
- break;
-
- case 2:
- for(loop = 0; loop < EPCA_NUM_TYPES; loop++)
- if (strcmp(board_desc[loop], str) == 0)
- break;
- /* ---------------------------------------------------------------
- If the index incremented above refers to a legitamate board
- type set it here.
- ------------------------------------------------------------------*/
- if (index < EPCA_NUM_TYPES)
- board.type = loop;
- else {
- printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
- invalid_lilo_config = 1;
- setup_error_code |= INVALID_BOARD_TYPE;
- return;
- }
- last = index;
- break;
-
- case 3:
- len = strlen(str);
- if (strncmp("Disable", str, len) == 0)
- board.altpin = 0;
- else if (strncmp("Enable", str, len) == 0)
- board.altpin = 1;
- else {
- printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
- invalid_lilo_config = 1;
- setup_error_code |= INVALID_ALTPIN;
- return;
- }
- last = index;
- break;
-
- case 4:
- t2 = str;
- while (isdigit(*t2))
- t2++;
-
- if (*t2) {
- printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
- invalid_lilo_config = 1;
- setup_error_code |= INVALID_NUM_PORTS;
- return;
- }
+ switch (index) {
+ case 1:
+ len = strlen(str);
+ if (strncmp("Disable", str, len) == 0)
+ board.status = 0;
+ else if (strncmp("Enable", str, len) == 0)
+ board.status = 1;
+ else {
+ printk(KERN_ERR "epca_setup: Invalid status %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_BOARD_STATUS;
+ return;
+ }
+ last = index;
+ break;
- /* ------------------------------------------------------------
- There is not a man page for simple_strtoul but the code can be
- found in vsprintf.c. The first argument is the string to
- translate (To an unsigned long obviously), the second argument
- can be the address of any character variable or a NULL. If a
- variable is given, the end pointer of the string will be stored
- in that variable; if a NULL is given the end pointer will
- not be returned. The last argument is the base to use. If
- a 0 is indicated, the routine will attempt to determine the
- proper base by looking at the values prefix (A '0' for octal,
- a 'x' for hex, etc ... If a value is given it will use that
- value as the base.
- ---------------------------------------------------------------- */
- board.numports = simple_strtoul(str, NULL, 0);
- nbdevs += board.numports;
- last = index;
- break;
-
- case 5:
- t2 = str;
- while (isxdigit(*t2))
- t2++;
-
- if (*t2) {
- printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
- invalid_lilo_config = 1;
- setup_error_code |= INVALID_PORT_BASE;
- return;
- }
+ case 2:
+ for (loop = 0; loop < EPCA_NUM_TYPES; loop++)
+ if (strcmp(board_desc[loop], str) == 0)
+ break;
+ /*
+ * If the index incremented above refers to a
+ * legitamate board type set it here.
+ */
+ if (index < EPCA_NUM_TYPES)
+ board.type = loop;
+ else {
+ printk(KERN_ERR "epca_setup: Invalid board type: %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_BOARD_TYPE;
+ return;
+ }
+ last = index;
+ break;
- board.port = simple_strtoul(str, NULL, 16);
- last = index;
- break;
+ case 3:
+ len = strlen(str);
+ if (strncmp("Disable", str, len) == 0)
+ board.altpin = 0;
+ else if (strncmp("Enable", str, len) == 0)
+ board.altpin = 1;
+ else {
+ printk(KERN_ERR "epca_setup: Invalid altpin %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_ALTPIN;
+ return;
+ }
+ last = index;
+ break;
- case 6:
- t2 = str;
- while (isxdigit(*t2))
- t2++;
+ case 4:
+ t2 = str;
+ while (isdigit(*t2))
+ t2++;
- if (*t2) {
- printk(KERN_ERR "epca_setup: Invalid memory base %s\n",str);
- invalid_lilo_config = 1;
- setup_error_code |= INVALID_MEM_BASE;
- return;
- }
- board.membase = simple_strtoul(str, NULL, 16);
- last = index;
- break;
- default:
- printk(KERN_ERR "epca: Too many string parms\n");
+ if (*t2) {
+ printk(KERN_ERR "epca_setup: Invalid port count %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_NUM_PORTS;
+ return;
+ }
+
+ /*
+ * There is not a man page for simple_strtoul but the
+ * code can be found in vsprintf.c. The first argument
+ * is the string to translate (To an unsigned long
+ * obviously), the second argument can be the address
+ * of any character variable or a NULL. If a variable
+ * is given, the end pointer of the string will be
+ * stored in that variable; if a NULL is given the end
+ * pointer will not be returned. The last argument is
+ * the base to use. If a 0 is indicated, the routine
+ * will attempt to determine the proper base by looking
+ * at the values prefix (A '0' for octal, a 'x' for
+ * hex, etc ... If a value is given it will use that
+ * value as the base.
+ */
+ board.numports = simple_strtoul(str, NULL, 0);
+ nbdevs += board.numports;
+ last = index;
+ break;
+
+ case 5:
+ t2 = str;
+ while (isxdigit(*t2))
+ t2++;
+
+ if (*t2) {
+ printk(KERN_ERR "epca_setup: Invalid i/o address %s\n", str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_PORT_BASE;
+ return;
+ }
+
+ board.port = simple_strtoul(str, NULL, 16);
+ last = index;
+ break;
+
+ case 6:
+ t2 = str;
+ while (isxdigit(*t2))
+ t2++;
+
+ if (*t2) {
+ printk(KERN_ERR "epca_setup: Invalid memory base %s\n",str);
+ invalid_lilo_config = 1;
+ setup_error_code |= INVALID_MEM_BASE;
return;
+ }
+ board.membase = simple_strtoul(str, NULL, 16);
+ last = index;
+ break;
+ default:
+ printk(KERN_ERR "epca: Too many string parms\n");
+ return;
}
str = temp;
} /* End while there is a string arg */
@@ -2966,19 +2763,16 @@ void epca_setup(char *str, int *ints)
printk(KERN_ERR "epca: Insufficient parms specified\n");
return;
}
-
+
/* I should REALLY validate the stuff here */
/* Copies our local copy of board into boards */
memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board));
/* Does this get called once per lilo arg are what ? */
- printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
- num_cards, board_desc[board.type],
+ printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n",
+ num_cards, board_desc[board.type],
board.numports, (int)board.port, (unsigned int) board.membase);
num_cards++;
-} /* End epca_setup */
-
-
-/* ------------------------ Begin init_PCI --------------------------- */
+}
enum epic_board_types {
brd_xr = 0,
@@ -2987,7 +2781,6 @@ enum epic_board_types {
brd_xrj,
};
-
/* indexed directly by epic_board_types enum */
static struct {
unsigned char board_type;
@@ -2999,7 +2792,7 @@ static struct {
{ PCIXRJ, 2, },
};
-static int __devinit epca_init_one (struct pci_dev *pdev,
+static int __devinit epca_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static int board_num = -1;
@@ -3013,7 +2806,7 @@ static int __devinit epca_init_one (struct pci_dev *pdev,
board_idx = board_num + num_cards;
if (board_idx >= MAXBOARDS)
goto err_out;
-
+
addr = pci_resource_start (pdev, epca_info_tbl[info_idx].bar_idx);
if (!addr) {
printk (KERN_ERR PFX "PCI region #%d not available (size 0)\n",
@@ -3053,15 +2846,15 @@ static int __devinit epca_init_one (struct pci_dev *pdev,
goto err_out_free_memregion;
}
- /* --------------------------------------------------------------
- I don't know what the below does, but the hardware guys say
- its required on everything except PLX (In this case XRJ).
- ---------------------------------------------------------------- */
+ /*
+ * I don't know what the below does, but the hardware guys say its
+ * required on everything except PLX (In this case XRJ).
+ */
if (info_idx != brd_xrj) {
- pci_write_config_byte(pdev, 0x40, 0);
+ pci_write_config_byte(pdev, 0x40, 0);
pci_write_config_byte(pdev, 0x46, 0);
}
-
+
return 0;
err_out_free_memregion:
@@ -3086,7 +2879,7 @@ static struct pci_device_id epca_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
int __init init_PCI (void)
-{ /* Begin init_PCI */
+{
memset (&epca_driver, 0, sizeof (epca_driver));
epca_driver.name = "epca";
epca_driver.id_table = epca_pci_tbl;
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 2e7ae42a550..28607763ae6 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -19,7 +19,7 @@
*
* rs_set_termios fixed to look also for changes of the input
* flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK.
- * Bernd Anh�pl 05/17/96.
+ * Bernd Anhäupl 05/17/96.
*
* --- End of notices from serial.c ---
*
@@ -58,10 +58,10 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/bitops.h>
#include <asm/dma.h>
#include <linux/slab.h>
diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c
index 6f019f19be7..e74bb949c28 100644
--- a/drivers/char/hvc_beat.c
+++ b/drivers/char/hvc_beat.c
@@ -97,7 +97,7 @@ static int hvc_beat_config(char *p)
return 0;
}
-static int hvc_beat_console_init(void)
+static int __init hvc_beat_console_init(void)
{
if (hvc_beat_useit && machine_is_compatible("Beat")) {
hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
@@ -106,7 +106,7 @@ static int hvc_beat_console_init(void)
}
/* temp */
-static int hvc_beat_init(void)
+static int __init hvc_beat_init(void)
{
struct hvc_struct *hp;
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 83c1151ec7a..8252f866853 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -69,6 +69,8 @@ static struct task_struct *hvc_task;
/* Picks up late kicks after list walk but before schedule() */
static int hvc_kicked;
+static int hvc_init(void);
+
#ifdef CONFIG_MAGIC_SYSRQ
static int sysrq_pressed;
#endif
@@ -754,6 +756,13 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
struct hvc_struct *hp;
int i;
+ /* We wait until a driver actually comes along */
+ if (!hvc_driver) {
+ int err = hvc_init();
+ if (err)
+ return ERR_PTR(err);
+ }
+
hp = kmalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size,
GFP_KERNEL);
if (!hp)
@@ -829,16 +838,18 @@ int __devexit hvc_remove(struct hvc_struct *hp)
return 0;
}
-/* Driver initialization. Follow console initialization. This is where the TTY
- * interfaces start to become available. */
-static int __init hvc_init(void)
+/* Driver initialization: called as soon as someone uses hvc_alloc(). */
+static int hvc_init(void)
{
struct tty_driver *drv;
+ int err;
/* We need more than hvc_count adapters due to hotplug additions. */
drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS);
- if (!drv)
- return -ENOMEM;
+ if (!drv) {
+ err = -ENOMEM;
+ goto out;
+ }
drv->owner = THIS_MODULE;
drv->driver_name = "hvc";
@@ -854,30 +865,43 @@ static int __init hvc_init(void)
* added later. */
hvc_task = kthread_run(khvcd, NULL, "khvcd");
if (IS_ERR(hvc_task)) {
- panic("Couldn't create kthread for console.\n");
- put_tty_driver(drv);
- return -EIO;
+ printk(KERN_ERR "Couldn't create kthread for console.\n");
+ err = PTR_ERR(hvc_task);
+ goto put_tty;
}
- if (tty_register_driver(drv))
- panic("Couldn't register hvc console driver\n");
+ err = tty_register_driver(drv);
+ if (err) {
+ printk(KERN_ERR "Couldn't register hvc console driver\n");
+ goto stop_thread;
+ }
+ /* FIXME: This mb() seems completely random. Remove it. */
mb();
hvc_driver = drv;
return 0;
+
+put_tty:
+ put_tty_driver(hvc_driver);
+stop_thread:
+ kthread_stop(hvc_task);
+ hvc_task = NULL;
+out:
+ return err;
}
-module_init(hvc_init);
/* This isn't particularly necessary due to this being a console driver
* but it is nice to be thorough.
*/
static void __exit hvc_exit(void)
{
- kthread_stop(hvc_task);
+ if (hvc_driver) {
+ kthread_stop(hvc_task);
- tty_unregister_driver(hvc_driver);
- /* return tty_struct instances allocated in hvc_init(). */
- put_tty_driver(hvc_driver);
- unregister_console(&hvc_con_driver);
+ tty_unregister_driver(hvc_driver);
+ /* return tty_struct instances allocated in hvc_init(). */
+ put_tty_driver(hvc_driver);
+ unregister_console(&hvc_con_driver);
+ }
}
module_exit(hvc_exit);
diff --git a/drivers/char/hvc_lguest.c b/drivers/char/hvc_lguest.c
deleted file mode 100644
index 3d6bd0baa56..00000000000
--- a/drivers/char/hvc_lguest.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*D:300
- * The Guest console driver
- *
- * This is a trivial console driver: we use lguest's DMA mechanism to send
- * bytes out, and register a DMA buffer to receive bytes in. It is assumed to
- * be present and available from the very beginning of boot.
- *
- * Writing console drivers is one of the few remaining Dark Arts in Linux.
- * Fortunately for us, the path of virtual consoles has been well-trodden by
- * the PowerPC folks, who wrote "hvc_console.c" to generically support any
- * virtual console. We use that infrastructure which only requires us to write
- * the basic put_chars and get_chars functions and call the right register
- * functions.
- :*/
-
-/*M:002 The console can be flooded: while the Guest is processing input the
- * Host can send more. Buffering in the Host could alleviate this, but it is a
- * difficult problem in general. :*/
-/* Copyright (C) 2006 Rusty Russell, IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/lguest_bus.h>
-#include <asm/paravirt.h>
-#include "hvc_console.h"
-
-/*D:340 This is our single console input buffer, with associated "struct
- * lguest_dma" referring to it. Note the 0-terminated length array, and the
- * use of physical address for the buffer itself. */
-static char inbuf[256];
-static struct lguest_dma cons_input = { .used_len = 0,
- .addr[0] = __pa(inbuf),
- .len[0] = sizeof(inbuf),
- .len[1] = 0 };
-
-/*D:310 The put_chars() callback is pretty straightforward.
- *
- * First we put the pointer and length in a "struct lguest_dma": we only have
- * one pointer, so we set the second length to 0. Then we use SEND_DMA to send
- * the data to (Host) buffers attached to the console key. Usually a device's
- * key is a physical address within the device's memory, but because the
- * console device doesn't have any associated physical memory, we use the
- * LGUEST_CONSOLE_DMA_KEY constant (aka 0). */
-static int put_chars(u32 vtermno, const char *buf, int count)
-{
- struct lguest_dma dma;
-
- /* FIXME: DMA buffers in a "struct lguest_dma" are not allowed
- * to go over page boundaries. This never seems to happen,
- * but if it did we'd need to fix this code. */
- dma.len[0] = count;
- dma.len[1] = 0;
- dma.addr[0] = __pa(buf);
-
- lguest_send_dma(LGUEST_CONSOLE_DMA_KEY, &dma);
- /* We're expected to return the amount of data we wrote: all of it. */
- return count;
-}
-
-/*D:350 get_chars() is the callback from the hvc_console infrastructure when
- * an interrupt is received.
- *
- * Firstly we see if our buffer has been filled: if not, we return. The rest
- * of the code deals with the fact that the hvc_console() infrastructure only
- * asks us for 16 bytes at a time. We keep a "cons_offset" variable for
- * partially-read buffers. */
-static int get_chars(u32 vtermno, char *buf, int count)
-{
- static int cons_offset;
-
- /* Nothing left to see here... */
- if (!cons_input.used_len)
- return 0;
-
- /* You want more than we have to give? Well, try wanting less! */
- if (cons_input.used_len - cons_offset < count)
- count = cons_input.used_len - cons_offset;
-
- /* Copy across to their buffer and increment offset. */
- memcpy(buf, inbuf + cons_offset, count);
- cons_offset += count;
-
- /* Finished? Zero offset, and reset cons_input so Host will use it
- * again. */
- if (cons_offset == cons_input.used_len) {
- cons_offset = 0;
- cons_input.used_len = 0;
- }
- return count;
-}
-/*:*/
-
-static struct hv_ops lguest_cons = {
- .get_chars = get_chars,
- .put_chars = put_chars,
-};
-
-/*D:320 Console drivers are initialized very early so boot messages can go
- * out. At this stage, the console is output-only. Our driver checks we're a
- * Guest, and if so hands hvc_instantiate() the console number (0), priority
- * (0), and the struct hv_ops containing the put_chars() function. */
-static int __init cons_init(void)
-{
- if (strcmp(paravirt_ops.name, "lguest") != 0)
- return 0;
-
- return hvc_instantiate(0, 0, &lguest_cons);
-}
-console_initcall(cons_init);
-
-/*D:370 To set up and manage our virtual console, we call hvc_alloc() and
- * stash the result in the private pointer of the "struct lguest_device".
- * Since we never remove the console device we never need this pointer again,
- * but using ->private is considered good form, and you never know who's going
- * to copy your driver.
- *
- * Once the console is set up, we bind our input buffer ready for input. */
-static int lguestcons_probe(struct lguest_device *lgdev)
-{
- int err;
-
- /* The first argument of hvc_alloc() is the virtual console number, so
- * we use zero. The second argument is the interrupt number.
- *
- * The third argument is a "struct hv_ops" containing the put_chars()
- * and get_chars() pointers. The final argument is the output buffer
- * size: we use 256 and expect the Host to have room for us to send
- * that much. */
- lgdev->private = hvc_alloc(0, lgdev_irq(lgdev), &lguest_cons, 256);
- if (IS_ERR(lgdev->private))
- return PTR_ERR(lgdev->private);
-
- /* We bind a single DMA buffer at key LGUEST_CONSOLE_DMA_KEY.
- * "cons_input" is that statically-initialized global DMA buffer we saw
- * above, and we also give the interrupt we want. */
- err = lguest_bind_dma(LGUEST_CONSOLE_DMA_KEY, &cons_input, 1,
- lgdev_irq(lgdev));
- if (err)
- printk("lguest console: failed to bind buffer.\n");
- return err;
-}
-/* Note the use of lgdev_irq() for the interrupt number. We tell hvc_alloc()
- * to expect input when this interrupt is triggered, and then tell
- * lguest_bind_dma() that is the interrupt to send us when input comes in. */
-
-/*D:360 From now on the console driver follows standard Guest driver form:
- * register_lguest_driver() registers the device type and probe function, and
- * the probe function sets up the device.
- *
- * The standard "struct lguest_driver": */
-static struct lguest_driver lguestcons_drv = {
- .name = "lguestcons",
- .owner = THIS_MODULE,
- .device_type = LGUEST_DEVICE_T_CONSOLE,
- .probe = lguestcons_probe,
-};
-
-/* The standard init function */
-static int __init hvc_lguest_init(void)
-{
- return register_lguest_driver(&lguestcons_drv);
-}
-module_init(hvc_lguest_init);
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index e13dd1892bf..3f35a1c562b 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -10,7 +10,7 @@
* Mostly based on original driver:
*
* Copyright (C) 2005 Nokia Corporation
- * Author: Juha Yrj��<juha.yrjola@nokia.com>
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 0289705967d..30e56451642 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -98,9 +98,9 @@ struct smm_regs {
unsigned int edi __attribute__ ((packed));
};
-static inline char *i8k_get_dmi_data(int field)
+static inline const char *i8k_get_dmi_data(int field)
{
- char *dmi_data = dmi_get_system_info(field);
+ const char *dmi_data = dmi_get_system_info(field);
return dmi_data && *dmi_data ? dmi_data : "?";
}
@@ -371,14 +371,14 @@ static int i8k_proc_show(struct seq_file *seq, void *offset)
int fn_key, cpu_temp, ac_power;
int left_fan, right_fan, left_speed, right_speed;
- cpu_temp = i8k_get_temp(0); /* 11100 µs */
- left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */
- right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */
- left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */
- right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */
- fn_key = i8k_get_fn_status(); /* 750 µs */
+ cpu_temp = i8k_get_temp(0); /* 11100 µs */
+ left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */
+ right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */
+ left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */
+ right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */
+ fn_key = i8k_get_fn_status(); /* 750 µs */
if (power_status)
- ac_power = i8k_get_power_status(); /* 14700 µs */
+ ac_power = i8k_get_power_status(); /* 14700 µs */
else
ac_power = -1;
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 8d74b8745e6..e04e66cf2c6 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -411,8 +411,8 @@ cleanup_module(void)
iiResetDelay( i2BoardPtrTable[i] );
/* free io addresses and Tibet */
release_region( ip2config.addr[i], 8 );
- class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
- class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
+ device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
+ device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
}
/* Disable and remove interrupt handler. */
if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) {
@@ -619,11 +619,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
ip2config.irq[i] = pci_dev_i->irq;
} else { // ann error
ip2config.addr[i] = 0;
- if (status == PCIBIOS_DEVICE_NOT_FOUND) {
- printk( KERN_ERR "IP2: PCI board %d not found\n", i );
- } else {
- printk( KERN_ERR "IP2: PCI error 0x%x \n", status );
- }
+ printk(KERN_ERR "IP2: PCI board %d not found\n", i);
}
}
#else
@@ -646,10 +642,9 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
if ( ip2config.addr[i] ) {
- pB = kmalloc( sizeof(i2eBordStr), GFP_KERNEL);
- if ( pB != NULL ) {
+ pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL);
+ if (pB) {
i2BoardPtrTable[i] = pB;
- memset( pB, 0, sizeof(i2eBordStr) );
iiSetAddress( pB, ip2config.addr[i], ii2DelayTimer );
iiReset( pB );
} else {
@@ -718,12 +713,12 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
}
if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
- class_device_create(ip2_class, NULL,
+ device_create(ip2_class, NULL,
MKDEV(IP2_IPL_MAJOR, 4 * i),
- NULL, "ipl%d", i);
- class_device_create(ip2_class, NULL,
+ "ipl%d", i);
+ device_create(ip2_class, NULL,
MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
- NULL, "stat%d", i);
+ "stat%d", i);
for ( box = 0; box < ABS_MAX_BOXES; ++box )
{
@@ -757,7 +752,7 @@ retry:
continue;
rc = request_irq( ip2config.irq[i], ip2_interrupt,
IP2_SA_FLAGS | (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
- pcName, (void *)&pcName);
+ pcName, i2BoardPtrTable[i]);
if (rc) {
printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc);
ip2config.irq[i] = CIR_POLL;
@@ -1171,12 +1166,37 @@ ip2_interrupt_bh(struct work_struct *work)
/* */
/* */
/******************************************************************************/
-static irqreturn_t
-ip2_interrupt(int irq, void *dev_id)
+static void
+ip2_irq_work(i2eBordStrPtr pB)
+{
+#ifdef USE_IQI
+ if (NO_MAIL_HERE != ( pB->i2eStartMail = iiGetMail(pB))) {
+// Disable his interrupt (will be enabled when serviced)
+// This is mostly to protect from reentrancy.
+ iiDisableMailIrq(pB);
+
+// Park the board on the immediate queue for processing.
+ schedule_work(&pB->tqueue_interrupt);
+
+// Make sure the immediate queue is flagged to fire.
+ }
+#else
+
+// We are using immediate servicing here. This sucks and can
+// cause all sorts of havoc with ppp and others. The failsafe
+// check on iiSendPendingMail could also throw a hairball.
+
+ i2ServiceBoard( pB );
+
+#endif /* USE_IQI */
+}
+
+static void
+ip2_polled_interrupt(void)
{
int i;
i2eBordStrPtr pB;
- int handled = 0;
+ const int irq = 0;
ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq );
@@ -1188,32 +1208,28 @@ ip2_interrupt(int irq, void *dev_id)
// IRQ = 0 for polled boards, we won't poll "IRQ" boards
if ( pB && (pB->i2eUsingIrq == irq) ) {
- handled = 1;
-#ifdef USE_IQI
+ ip2_irq_work(pB);
+ }
+ }
- if (NO_MAIL_HERE != ( pB->i2eStartMail = iiGetMail(pB))) {
-// Disable his interrupt (will be enabled when serviced)
-// This is mostly to protect from reentrancy.
- iiDisableMailIrq(pB);
+ ++irq_counter;
-// Park the board on the immediate queue for processing.
- schedule_work(&pB->tqueue_interrupt);
+ ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
+}
-// Make sure the immediate queue is flagged to fire.
- }
-#else
-// We are using immediate servicing here. This sucks and can
-// cause all sorts of havoc with ppp and others. The failsafe
-// check on iiSendPendingMail could also throw a hairball.
- i2ServiceBoard( pB );
-#endif /* USE_IQI */
- }
- }
+static irqreturn_t
+ip2_interrupt(int irq, void *dev_id)
+{
+ i2eBordStrPtr pB = dev_id;
+
+ ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, pB->i2eUsingIrq );
+
+ ip2_irq_work(pB);
++irq_counter;
ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 );
- return IRQ_RETVAL(handled);
+ return IRQ_HANDLED;
}
/******************************************************************************/
@@ -1236,7 +1252,7 @@ ip2_poll(unsigned long arg)
// Just polled boards, IRQ = 0 will hit all non-interrupt boards.
// It will NOT poll boards handled by hard interrupts.
// The issue of queued BH interrups is handled in ip2_interrupt().
- ip2_interrupt(0, NULL);
+ ip2_polled_interrupt();
PollTimer.expires = POLL_TIMEOUT;
add_timer( &PollTimer );
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index c2aa44ee6eb..0246a2b8ce4 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -865,7 +865,7 @@ static void ipmi_new_smi(int if_num, struct device *device)
entry->dev = dev;
mutex_lock(&reg_list_mutex);
- class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num);
+ device_create(ipmi_class, device, dev, "ipmi%d", if_num);
list_add(&entry->link, &reg_list);
mutex_unlock(&reg_list_mutex);
}
@@ -883,7 +883,7 @@ static void ipmi_smi_gone(int if_num)
break;
}
}
- class_device_destroy(ipmi_class, dev);
+ device_destroy(ipmi_class, dev);
mutex_unlock(&reg_list_mutex);
}
@@ -938,7 +938,7 @@ static __exit void cleanup_ipmi(void)
mutex_lock(&reg_list_mutex);
list_for_each_entry_safe(entry, entry2, &reg_list, link) {
list_del(&entry->link);
- class_device_destroy(ipmi_class, entry->dev);
+ device_destroy(ipmi_class, entry->dev);
kfree(entry);
}
mutex_unlock(&reg_list_mutex);
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 6a01dd9e43f..5dc1265ce1d 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -221,10 +221,8 @@ struct ipmi_smi
void *send_info;
#ifdef CONFIG_PROC_FS
- /* A list of proc entries for this interface. This does not
- need a lock, only one thread creates it and only one thread
- destroys it. */
- spinlock_t proc_entry_lock;
+ /* A list of proc entries for this interface. */
+ struct mutex proc_entry_lock;
struct ipmi_proc_entry *proc_entries;
#endif
@@ -1891,11 +1889,11 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
file->write_proc = write_proc;
file->owner = owner;
- spin_lock(&smi->proc_entry_lock);
+ mutex_lock(&smi->proc_entry_lock);
/* Stick it on the list. */
entry->next = smi->proc_entries;
smi->proc_entries = entry;
- spin_unlock(&smi->proc_entry_lock);
+ mutex_unlock(&smi->proc_entry_lock);
}
#endif /* CONFIG_PROC_FS */
@@ -1939,7 +1937,7 @@ static void remove_proc_entries(ipmi_smi_t smi)
#ifdef CONFIG_PROC_FS
struct ipmi_proc_entry *entry;
- spin_lock(&smi->proc_entry_lock);
+ mutex_lock(&smi->proc_entry_lock);
while (smi->proc_entries) {
entry = smi->proc_entries;
smi->proc_entries = entry->next;
@@ -1948,7 +1946,7 @@ static void remove_proc_entries(ipmi_smi_t smi)
kfree(entry->name);
kfree(entry);
}
- spin_unlock(&smi->proc_entry_lock);
+ mutex_unlock(&smi->proc_entry_lock);
remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
#endif /* CONFIG_PROC_FS */
}
@@ -2614,6 +2612,14 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg)
return;
}
+void ipmi_poll_interface(ipmi_user_t user)
+{
+ ipmi_smi_t intf = user->intf;
+
+ if (intf->handlers->poll)
+ intf->handlers->poll(intf->send_info);
+}
+
int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
void *send_info,
struct ipmi_device_id *device_id,
@@ -2671,7 +2677,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
}
intf->curr_seq = 0;
#ifdef CONFIG_PROC_FS
- spin_lock_init(&intf->proc_entry_lock);
+ mutex_init(&intf->proc_entry_lock);
#endif
spin_lock_init(&intf->waiting_msgs_lock);
INIT_LIST_HEAD(&intf->waiting_msgs);
@@ -4136,7 +4142,7 @@ static __exit void cleanup_ipmi(void)
del_timer_sync(&ipmi_timer);
#ifdef CONFIG_PROC_FS
- remove_proc_entry(proc_ipmi_root->name, &proc_root);
+ remove_proc_entry(proc_ipmi_root->name, NULL);
#endif /* CONFIG_PROC_FS */
driver_unregister(&ipmidriver);
@@ -4166,6 +4172,7 @@ EXPORT_SYMBOL(ipmi_destroy_user);
EXPORT_SYMBOL(ipmi_get_version);
EXPORT_SYMBOL(ipmi_request_settime);
EXPORT_SYMBOL(ipmi_request_supply_msgs);
+EXPORT_SYMBOL(ipmi_poll_interface);
EXPORT_SYMBOL(ipmi_register_smi);
EXPORT_SYMBOL(ipmi_unregister_smi);
EXPORT_SYMBOL(ipmi_register_for_cmd);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index dd441ff4af5..4f560d0bb80 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -675,7 +675,8 @@ static void handle_transaction_done(struct smi_info *smi_info)
}
/* Called on timeouts and events. Timeouts should pass the elapsed
- time, interrupts should pass in zero. */
+ time, interrupts should pass in zero. Must be called with
+ si_lock held and interrupts disabled. */
static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
int time)
{
@@ -892,13 +893,16 @@ static int ipmi_thread(void *data)
static void poll(void *send_info)
{
struct smi_info *smi_info = send_info;
+ unsigned long flags;
/*
* Make sure there is some delay in the poll loop so we can
* drive time forward and timeout things.
*/
udelay(10);
+ spin_lock_irqsave(&smi_info->si_lock, flags);
smi_event_handler(smi_info, 10);
+ spin_unlock_irqrestore(&smi_info->si_lock, flags);
}
static void request_events(void *send_info)
@@ -1006,6 +1010,10 @@ static int smi_start_processing(void *send_info,
new_smi->intf = intf;
+ /* Try to claim any interrupts. */
+ if (new_smi->irq_setup)
+ new_smi->irq_setup(new_smi);
+
/* Set up the timer that drives the interface. */
setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi);
new_smi->last_timeout_jiffies = jiffies;
@@ -1072,19 +1080,19 @@ static char *si_type[SI_MAX_PARMS];
#define MAX_SI_TYPE_STR 30
static char si_type_str[MAX_SI_TYPE_STR];
static unsigned long addrs[SI_MAX_PARMS];
-static int num_addrs;
+static unsigned int num_addrs;
static unsigned int ports[SI_MAX_PARMS];
-static int num_ports;
+static unsigned int num_ports;
static int irqs[SI_MAX_PARMS];
-static int num_irqs;
+static unsigned int num_irqs;
static int regspacings[SI_MAX_PARMS];
-static int num_regspacings;
+static unsigned int num_regspacings;
static int regsizes[SI_MAX_PARMS];
-static int num_regsizes;
+static unsigned int num_regsizes;
static int regshifts[SI_MAX_PARMS];
-static int num_regshifts;
+static unsigned int num_regshifts;
static int slave_addrs[SI_MAX_PARMS];
-static int num_slave_addrs;
+static unsigned int num_slave_addrs;
#define IPMI_IO_ADDR_SPACE 0
#define IPMI_MEM_ADDR_SPACE 1
@@ -1106,12 +1114,12 @@ MODULE_PARM_DESC(type, "Defines the type of each interface, each"
" interface separated by commas. The types are 'kcs',"
" 'smic', and 'bt'. For example si_type=kcs,bt will set"
" the first interface to kcs and the second to bt");
-module_param_array(addrs, long, &num_addrs, 0);
+module_param_array(addrs, ulong, &num_addrs, 0);
MODULE_PARM_DESC(addrs, "Sets the memory address of each interface, the"
" addresses separated by commas. Only use if an interface"
" is in memory. Otherwise, set it to zero or leave"
" it blank.");
-module_param_array(ports, int, &num_ports, 0);
+module_param_array(ports, uint, &num_ports, 0);
MODULE_PARM_DESC(ports, "Sets the port address of each interface, the"
" addresses separated by commas. Only use if an interface"
" is a port. Otherwise, set it to zero or leave"
@@ -1965,10 +1973,10 @@ struct dmi_ipmi_data
u8 slave_addr;
};
-static int __devinit decode_dmi(struct dmi_header *dm,
+static int __devinit decode_dmi(const struct dmi_header *dm,
struct dmi_ipmi_data *dmi)
{
- u8 *data = (u8 *)dm;
+ const u8 *data = (const u8 *)dm;
unsigned long base_addr;
u8 reg_spacing;
u8 len = dm->length;
@@ -2091,13 +2099,14 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data)
static void __devinit dmi_find_bmc(void)
{
- struct dmi_device *dev = NULL;
+ const struct dmi_device *dev = NULL;
struct dmi_ipmi_data data;
int rv;
while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
memset(&data, 0, sizeof(data));
- rv = decode_dmi((struct dmi_header *) dev->device_data, &data);
+ rv = decode_dmi((const struct dmi_header *) dev->device_data,
+ &data);
if (!rv)
try_init_dmi(&data);
}
@@ -2252,19 +2261,19 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
return ret;
}
- regsize = get_property(np, "reg-size", &proplen);
+ regsize = of_get_property(np, "reg-size", &proplen);
if (regsize && proplen != 4) {
dev_warn(&dev->dev, PFX "invalid regsize from OF\n");
return -EINVAL;
}
- regspacing = get_property(np, "reg-spacing", &proplen);
+ regspacing = of_get_property(np, "reg-spacing", &proplen);
if (regspacing && proplen != 4) {
dev_warn(&dev->dev, PFX "invalid regspacing from OF\n");
return -EINVAL;
}
- regshift = get_property(np, "reg-shift", &proplen);
+ regshift = of_get_property(np, "reg-shift", &proplen);
if (regshift && proplen != 4) {
dev_warn(&dev->dev, PFX "invalid regshift from OF\n");
return -EINVAL;
@@ -2371,20 +2380,9 @@ static int try_get_dev_id(struct smi_info *smi_info)
/* Otherwise, we got some data. */
resp_len = smi_info->handlers->get_result(smi_info->si_sm,
resp, IPMI_MAX_MSG_LENGTH);
- if (resp_len < 14) {
- /* That's odd, it should be longer. */
- rv = -EINVAL;
- goto out;
- }
- if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0)) {
- /* That's odd, it shouldn't be able to fail. */
- rv = -EINVAL;
- goto out;
- }
-
- /* Record info from the get device id, in case we need it. */
- ipmi_demangle_device_id(resp+3, resp_len-3, &smi_info->device_id);
+ /* Check and record info from the get device id, in case we need it. */
+ rv = ipmi_demangle_device_id(resp, resp_len, &smi_info->device_id);
out:
kfree(resp);
@@ -2764,10 +2762,6 @@ static int try_smi_init(struct smi_info *new_smi)
setup_oem_data_handler(new_smi);
setup_xaction_handlers(new_smi);
- /* Try to claim any interrupts. */
- if (new_smi->irq_setup)
- new_smi->irq_setup(new_smi);
-
INIT_LIST_HEAD(&(new_smi->xmit_msgs));
INIT_LIST_HEAD(&(new_smi->hp_xmit_msgs));
new_smi->curr_msg = NULL;
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 41f78e2c158..e686fc92516 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -50,10 +50,19 @@
#include <linux/poll.h>
#include <linux/string.h>
#include <linux/ctype.h>
+#include <linux/delay.h>
#include <asm/atomic.h>
-#ifdef CONFIG_X86_LOCAL_APIC
-#include <asm/apic.h>
+#ifdef CONFIG_X86
+/* This is ugly, but I've determined that x86 is the only architecture
+ that can reasonably support the IPMI NMI watchdog timeout at this
+ time. If another architecture adds this capability somehow, it
+ will have to be a somewhat different mechanism and I have no idea
+ how it will work. So in the unlikely event that another
+ architecture supports this, we can figure out a good generic
+ mechanism for it at that time. */
+#include <asm/kdebug.h>
+#define HAVE_DIE_NMI
#endif
#define PFX "IPMI Watchdog: "
@@ -166,8 +175,6 @@ static char expect_close;
static int ifnum_to_use = -1;
-static DECLARE_RWSEM(register_sem);
-
/* Parameters to ipmi_set_timeout */
#define IPMI_SET_TIMEOUT_NO_HB 0
#define IPMI_SET_TIMEOUT_HB_IF_NECESSARY 1
@@ -193,11 +200,9 @@ static int set_param_int(const char *val, struct kernel_param *kp)
if (endp == val)
return -EINVAL;
- down_read(&register_sem);
*((int *)kp->arg) = l;
if (watchdog_user)
rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
- up_read(&register_sem);
return rv;
}
@@ -226,17 +231,15 @@ static int set_param_str(const char *val, struct kernel_param *kp)
s = strstrip(valcp);
- down_read(&register_sem);
rv = fn(s, NULL);
if (rv)
- goto out_unlock;
+ goto out;
check_parms();
if (watchdog_user)
rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
- out_unlock:
- up_read(&register_sem);
+ out:
return rv;
}
@@ -319,9 +322,12 @@ static unsigned char ipmi_version_minor;
/* If a pretimeout occurs, this is used to allow only one panic to happen. */
static atomic_t preop_panic_excl = ATOMIC_INIT(-1);
-static int ipmi_heartbeat(void);
-static void panic_halt_ipmi_heartbeat(void);
+#ifdef HAVE_DIE_NMI
+static int testing_nmi;
+static int nmi_handler_registered;
+#endif
+static int ipmi_heartbeat(void);
/* We use a mutex to make sure that only one thing can send a set
timeout at one time, because we only have one copy of the data.
@@ -360,6 +366,9 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
int hbnow = 0;
+ /* These can be cleared as we are setting the timeout. */
+ pretimeout_since_last_heartbeat = 0;
+
data[0] = 0;
WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
@@ -434,31 +443,75 @@ static int ipmi_set_timeout(int do_heartbeat)
wait_for_completion(&set_timeout_wait);
+ mutex_unlock(&set_timeout_lock);
+
if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB)
|| ((send_heartbeat_now)
&& (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY)))
- {
rv = ipmi_heartbeat();
- }
- mutex_unlock(&set_timeout_lock);
out:
return rv;
}
-static void dummy_smi_free(struct ipmi_smi_msg *msg)
+static atomic_t panic_done_count = ATOMIC_INIT(0);
+
+static void panic_smi_free(struct ipmi_smi_msg *msg)
{
+ atomic_dec(&panic_done_count);
}
-static void dummy_recv_free(struct ipmi_recv_msg *msg)
+static void panic_recv_free(struct ipmi_recv_msg *msg)
{
+ atomic_dec(&panic_done_count);
+}
+
+static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg =
+{
+ .done = panic_smi_free
+};
+static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg =
+{
+ .done = panic_recv_free
+};
+
+static void panic_halt_ipmi_heartbeat(void)
+{
+ struct kernel_ipmi_msg msg;
+ struct ipmi_system_interface_addr addr;
+ int rv;
+
+ /* Don't reset the timer if we have the timer turned off, that
+ re-enables the watchdog. */
+ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
+ return;
+
+ addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ addr.channel = IPMI_BMC_CHANNEL;
+ addr.lun = 0;
+
+ msg.netfn = 0x06;
+ msg.cmd = IPMI_WDOG_RESET_TIMER;
+ msg.data = NULL;
+ msg.data_len = 0;
+ rv = ipmi_request_supply_msgs(watchdog_user,
+ (struct ipmi_addr *) &addr,
+ 0,
+ &msg,
+ NULL,
+ &panic_halt_heartbeat_smi_msg,
+ &panic_halt_heartbeat_recv_msg,
+ 1);
+ if (!rv)
+ atomic_add(2, &panic_done_count);
}
+
static struct ipmi_smi_msg panic_halt_smi_msg =
{
- .done = dummy_smi_free
+ .done = panic_smi_free
};
static struct ipmi_recv_msg panic_halt_recv_msg =
{
- .done = dummy_recv_free
+ .done = panic_recv_free
};
/* Special call, doesn't claim any locks. This is only to be called
@@ -470,13 +523,21 @@ static void panic_halt_ipmi_set_timeout(void)
int send_heartbeat_now;
int rv;
+ /* Wait for the messages to be free. */
+ while (atomic_read(&panic_done_count) != 0)
+ ipmi_poll_interface(watchdog_user);
rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
&panic_halt_recv_msg,
&send_heartbeat_now);
if (!rv) {
+ atomic_add(2, &panic_done_count);
if (send_heartbeat_now)
panic_halt_ipmi_heartbeat();
- }
+ } else
+ printk(KERN_WARNING PFX
+ "Unable to extend the watchdog timeout.");
+ while (atomic_read(&panic_done_count) != 0)
+ ipmi_poll_interface(watchdog_user);
}
/* We use a semaphore to make sure that only one thing can send a
@@ -505,24 +566,14 @@ static struct ipmi_recv_msg heartbeat_recv_msg =
.done = heartbeat_free_recv
};
-static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg =
-{
- .done = dummy_smi_free
-};
-static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg =
-{
- .done = dummy_recv_free
-};
-
static int ipmi_heartbeat(void)
{
struct kernel_ipmi_msg msg;
int rv;
struct ipmi_system_interface_addr addr;
- if (ipmi_ignore_heartbeat) {
+ if (ipmi_ignore_heartbeat)
return 0;
- }
if (ipmi_start_timer_on_heartbeat) {
ipmi_start_timer_on_heartbeat = 0;
@@ -533,7 +584,6 @@ static int ipmi_heartbeat(void)
We don't want to set the action, though, we want to
leave that alone (thus it can't be combined with the
above operation. */
- pretimeout_since_last_heartbeat = 0;
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
}
@@ -586,35 +636,6 @@ static int ipmi_heartbeat(void)
return rv;
}
-static void panic_halt_ipmi_heartbeat(void)
-{
- struct kernel_ipmi_msg msg;
- struct ipmi_system_interface_addr addr;
-
-
- /* Don't reset the timer if we have the timer turned off, that
- re-enables the watchdog. */
- if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
- return;
-
- addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
- addr.channel = IPMI_BMC_CHANNEL;
- addr.lun = 0;
-
- msg.netfn = 0x06;
- msg.cmd = IPMI_WDOG_RESET_TIMER;
- msg.data = NULL;
- msg.data_len = 0;
- ipmi_request_supply_msgs(watchdog_user,
- (struct ipmi_addr *) &addr,
- 0,
- &msg,
- NULL,
- &panic_halt_heartbeat_smi_msg,
- &panic_halt_heartbeat_recv_msg,
- 1);
-}
-
static struct watchdog_info ident =
{
.options = 0, /* WDIOF_SETTIMEOUT, */
@@ -895,7 +916,6 @@ static void ipmi_register_watchdog(int ipmi_intf)
{
int rv = -EBUSY;
- down_write(&register_sem);
if (watchdog_user)
goto out;
@@ -921,15 +941,56 @@ static void ipmi_register_watchdog(int ipmi_intf)
printk(KERN_CRIT PFX "Unable to register misc device\n");
}
- out:
- up_write(&register_sem);
+#ifdef HAVE_DIE_NMI
+ if (nmi_handler_registered) {
+ int old_pretimeout = pretimeout;
+ int old_timeout = timeout;
+ int old_preop_val = preop_val;
+
+ /* Set the pretimeout to go off in a second and give
+ ourselves plenty of time to stop the timer. */
+ ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+ preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */
+ pretimeout = 99;
+ timeout = 100;
+
+ testing_nmi = 1;
+
+ rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
+ if (rv) {
+ printk(KERN_WARNING PFX "Error starting timer to"
+ " test NMI: 0x%x. The NMI pretimeout will"
+ " likely not work\n", rv);
+ rv = 0;
+ goto out_restore;
+ }
+
+ msleep(1500);
+ if (testing_nmi != 2) {
+ printk(KERN_WARNING PFX "IPMI NMI didn't seem to"
+ " occur. The NMI pretimeout will"
+ " likely not work\n");
+ }
+ out_restore:
+ testing_nmi = 0;
+ preop_val = old_preop_val;
+ pretimeout = old_pretimeout;
+ timeout = old_timeout;
+ }
+#endif
+
+ out:
if ((start_now) && (rv == 0)) {
/* Run from startup, so start the timer now. */
start_now = 0; /* Disable this function after first startup. */
ipmi_watchdog_state = action_val;
ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
printk(KERN_INFO PFX "Starting now!\n");
+ } else {
+ /* Stop the timer now. */
+ ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+ ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
}
}
@@ -937,8 +998,6 @@ static void ipmi_unregister_watchdog(int ipmi_intf)
{
int rv;
- down_write(&register_sem);
-
if (!watchdog_user)
goto out;
@@ -963,20 +1022,44 @@ static void ipmi_unregister_watchdog(int ipmi_intf)
watchdog_user = NULL;
out:
- up_write(&register_sem);
+ return;
}
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI
static int
-ipmi_nmi(void *dev_id, int cpu, int handled)
+ipmi_nmi(struct notifier_block *self, unsigned long val, void *data)
{
+ struct die_args *args = data;
+
+ if (val != DIE_NMI)
+ return NOTIFY_OK;
+
+ /* Hack, if it's a memory or I/O error, ignore it. */
+ if (args->err & 0xc0)
+ return NOTIFY_OK;
+
+ /*
+ * If we get here, it's an NMI that's not a memory or I/O
+ * error. We can't truly tell if it's from IPMI or not
+ * without sending a message, and sending a message is almost
+ * impossible because of locking.
+ */
+
+ if (testing_nmi) {
+ testing_nmi = 2;
+ return NOTIFY_STOP;
+ }
+
/* If we are not expecting a timeout, ignore it. */
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
- return NOTIFY_DONE;
+ return NOTIFY_OK;
+
+ if (preaction_val != WDOG_PRETIMEOUT_NMI)
+ return NOTIFY_OK;
/* If no one else handled the NMI, we assume it was the IPMI
watchdog. */
- if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) {
+ if (preop_val == WDOG_PREOP_PANIC) {
/* On some machines, the heartbeat will give
an error and not work unless we re-enable
the timer. So do so. */
@@ -985,18 +1068,12 @@ ipmi_nmi(void *dev_id, int cpu, int handled)
panic(PFX "pre-timeout");
}
- return NOTIFY_DONE;
+ return NOTIFY_STOP;
}
-static struct nmi_handler ipmi_nmi_handler =
-{
- .link = LIST_HEAD_INIT(ipmi_nmi_handler.link),
- .dev_name = "ipmi_watchdog",
- .dev_id = NULL,
- .handler = ipmi_nmi,
- .priority = 0, /* Call us last. */
+static struct notifier_block ipmi_nmi_handler = {
+ .notifier_call = ipmi_nmi
};
-int nmi_handler_registered;
#endif
static int wdog_reboot_handler(struct notifier_block *this,
@@ -1009,7 +1086,7 @@ static int wdog_reboot_handler(struct notifier_block *this,
/* Make sure we only do this once. */
reboot_event_handled = 1;
- if (code == SYS_DOWN || code == SYS_HALT) {
+ if (code == SYS_POWER_OFF || code == SYS_HALT) {
/* Disable the WDT if we are shutting down. */
ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
panic_halt_ipmi_set_timeout();
@@ -1113,7 +1190,7 @@ static int preaction_op(const char *inval, char *outval)
preaction_val = WDOG_PRETIMEOUT_NONE;
else if (strcmp(inval, "pre_smi") == 0)
preaction_val = WDOG_PRETIMEOUT_SMI;
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI
else if (strcmp(inval, "pre_nmi") == 0)
preaction_val = WDOG_PRETIMEOUT_NMI;
#endif
@@ -1147,7 +1224,7 @@ static int preop_op(const char *inval, char *outval)
static void check_parms(void)
{
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI
int do_nmi = 0;
int rv;
@@ -1160,20 +1237,9 @@ static void check_parms(void)
preop_op("preop_none", NULL);
do_nmi = 0;
}
-#ifdef CONFIG_X86_LOCAL_APIC
- if (nmi_watchdog == NMI_IO_APIC) {
- printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC"
- " mode (value is %d), that is incompatible"
- " with using NMI in the IPMI watchdog."
- " Disabling IPMI nmi pretimeout.\n",
- nmi_watchdog);
- preaction_val = WDOG_PRETIMEOUT_NONE;
- do_nmi = 0;
- }
-#endif
}
if (do_nmi && !nmi_handler_registered) {
- rv = request_nmi(&ipmi_nmi_handler);
+ rv = register_die_notifier(&ipmi_nmi_handler);
if (rv) {
printk(KERN_WARNING PFX
"Can't register nmi handler\n");
@@ -1181,7 +1247,7 @@ static void check_parms(void)
} else
nmi_handler_registered = 1;
} else if (!do_nmi && nmi_handler_registered) {
- release_nmi(&ipmi_nmi_handler);
+ unregister_die_notifier(&ipmi_nmi_handler);
nmi_handler_registered = 0;
}
#endif
@@ -1217,9 +1283,9 @@ static int __init ipmi_wdog_init(void)
rv = ipmi_smi_watcher_register(&smi_watcher);
if (rv) {
-#ifdef HAVE_NMI_HANDLER
- if (preaction_val == WDOG_PRETIMEOUT_NMI)
- release_nmi(&ipmi_nmi_handler);
+#ifdef HAVE_DIE_NMI
+ if (nmi_handler_registered)
+ unregister_die_notifier(&ipmi_nmi_handler);
#endif
atomic_notifier_chain_unregister(&panic_notifier_list,
&wdog_panic_notifier);
@@ -1238,9 +1304,9 @@ static void __exit ipmi_wdog_exit(void)
ipmi_smi_watcher_unregister(&smi_watcher);
ipmi_unregister_watchdog(watchdog_ifnum);
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI
if (nmi_handler_registered)
- release_nmi(&ipmi_nmi_handler);
+ unregister_die_notifier(&ipmi_nmi_handler);
#endif
atomic_notifier_chain_unregister(&panic_notifier_list,
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 77a7a4a0662..85d596a3c18 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -1529,7 +1529,7 @@ static int __devinit reset_card(struct pci_dev *pdev,
portcount = inw(base + 0x2);
if (!inw(base + 0xe) & 0x1 || (portcount != 0 && portcount != 4 &&
portcount != 8 && portcount != 16)) {
- dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.",
+ dev_err(&pdev->dev, "ISILoad:PCI Card%d reset failure.\n",
card + 1);
retval = -EIO;
goto end;
@@ -1622,7 +1622,9 @@ static int __devinit load_firmware(struct pci_dev *pdev,
if ((status = inw(base + 0x4)) != 0) {
dev_warn(&pdev->dev, "Card%d rejected load header:\n"
- "Address:0x%x\nCount:0x%x\nStatus:0x%x\n",
+ KERN_WARNING "Address:0x%x\n"
+ KERN_WARNING "Count:0x%x\n"
+ KERN_WARNING "Status:0x%x\n",
index + 1, frame->addr, frame->count, status);
goto errrelfw;
}
@@ -1666,7 +1668,9 @@ static int __devinit load_firmware(struct pci_dev *pdev,
if ((status = inw(base + 0x4)) != 0) {
dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
- "Address:0x%x\nCount:0x%x\nStatus: 0x%x\n",
+ KERN_WARNING "Address:0x%x\n"
+ KERN_WARNING "Count:0x%x\n"
+ KERN_WARNING "Status: 0x%x\n",
index + 1, frame->addr, frame->count, status);
goto errrelfw;
}
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 3c66f402f9d..1f27be1ec3d 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -4624,9 +4624,8 @@ static int __init istallion_module_init(void)
istallion_class = class_create(THIS_MODULE, "staliomem");
for (i = 0; i < 4; i++)
- class_device_create(istallion_class, NULL,
- MKDEV(STL_SIOMEMMAJOR, i),
- NULL, "staliomem%d", i);
+ device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+ "staliomem%d", i);
return 0;
err_deinit:
@@ -4659,8 +4658,7 @@ static void __exit istallion_module_exit(void)
unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
for (j = 0; j < 4; j++)
- class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR,
- j));
+ device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j));
class_destroy(istallion_class);
pci_unregister_driver(&stli_pcidriver);
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index d95f316afb5..fc54d234507 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -38,9 +38,11 @@
#include <linux/kbd_kern.h>
#include <linux/kbd_diacr.h>
#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
#include <linux/sysrq.h>
#include <linux/input.h>
#include <linux/reboot.h>
+#include <linux/notifier.h>
extern void ctrl_alt_del(void);
@@ -80,7 +82,8 @@ void compute_shiftstate(void);
typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
char up_flag);
static k_handler_fn K_HANDLERS;
-static k_handler_fn *k_handler[16] = { K_HANDLERS };
+k_handler_fn *k_handler[16] = { K_HANDLERS };
+EXPORT_SYMBOL_GPL(k_handler);
#define FN_HANDLERS\
fn_null, fn_enter, fn_show_ptregs, fn_show_mem,\
@@ -126,7 +129,7 @@ int shift_state = 0;
*/
static struct input_handler kbd_handler;
-static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */
+static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
static int dead_key_next;
static int npadch = -1; /* -1 or number assembled on pad */
@@ -159,6 +162,23 @@ static int sysrq_alt_use;
static int sysrq_alt;
/*
+ * Notifier list for console keyboard events
+ */
+static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list);
+
+int register_keyboard_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&keyboard_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_keyboard_notifier);
+
+int unregister_keyboard_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
+
+/*
* Translation of scancodes to keycodes. We set them on only the first
* keyboard in the list that accepts the scancode and keycode.
* Explanation for not choosing the first attached keyboard anymore:
@@ -403,9 +423,12 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
return d;
if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, conv_8bit_to_uni(d));
- else if (d < 0x100)
- put_queue(vc, d);
+ to_utf8(vc, d);
+ else {
+ int c = conv_uni_to_8bit(d);
+ if (c != -1)
+ put_queue(vc, c);
+ }
return ch;
}
@@ -417,9 +440,12 @@ static void fn_enter(struct vc_data *vc)
{
if (diacr) {
if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, conv_8bit_to_uni(diacr));
- else if (diacr < 0x100)
- put_queue(vc, diacr);
+ to_utf8(vc, diacr);
+ else {
+ int c = conv_uni_to_8bit(diacr);
+ if (c != -1)
+ put_queue(vc, c);
+ }
diacr = 0;
}
put_queue(vc, 13);
@@ -627,9 +653,12 @@ static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
return;
}
if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, conv_8bit_to_uni(value));
- else if (value < 0x100)
- put_queue(vc, value);
+ to_utf8(vc, value);
+ else {
+ int c = conv_uni_to_8bit(value);
+ if (c != -1)
+ put_queue(vc, c);
+ }
}
/*
@@ -646,7 +675,12 @@ static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
{
- k_unicode(vc, value, up_flag);
+ unsigned int uni;
+ if (kbd->kbdmode == VC_UNICODE)
+ uni = value;
+ else
+ uni = conv_8bit_to_uni(value);
+ k_unicode(vc, uni, up_flag);
}
static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
@@ -1115,6 +1149,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
unsigned char type, raw_mode;
struct tty_struct *tty;
int shift_final;
+ struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
tty = vc->vc_tty;
@@ -1202,10 +1237,11 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
return;
}
- shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
+ param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
key_map = key_maps[shift_final];
- if (!key_map) {
+ if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYCODE, &param) == NOTIFY_STOP || !key_map) {
+ atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNBOUND_KEYCODE, &param);
compute_shiftstate();
kbd->slockstate = 0;
return;
@@ -1222,6 +1258,9 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
type = KTYP(keysym);
if (type < 0xf0) {
+ param.value = keysym;
+ if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_UNICODE, &param) == NOTIFY_STOP)
+ return;
if (down && !raw_mode)
to_utf8(vc, keysym);
return;
@@ -1229,9 +1268,6 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
type -= 0xf0;
- if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
- return;
-
if (type == KT_LETTER) {
type = KT_LATIN;
if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
@@ -1240,9 +1276,18 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
keysym = key_map[keycode];
}
}
+ param.value = keysym;
+
+ if (atomic_notifier_call_chain(&keyboard_notifier_list, KBD_KEYSYM, &param) == NOTIFY_STOP)
+ return;
+
+ if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
+ return;
(*k_handler[type])(vc, keysym & 0xff, !down);
+ atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, &param);
+
if (type != KT_SLOCK)
kbd->slockstate = 0;
}
@@ -1332,12 +1377,12 @@ static void kbd_start(struct input_handle *handle)
static const struct input_device_id kbd_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
- .evbit = { BIT(EV_KEY) },
+ .evbit = { BIT_MASK(EV_KEY) },
},
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
- .evbit = { BIT(EV_SND) },
+ .evbit = { BIT_MASK(EV_SND) },
},
{ }, /* Terminating entry */
@@ -1366,7 +1411,7 @@ int __init kbd_init(void)
kbd_table[i].lockstate = KBD_DEFLOCK;
kbd_table[i].slockstate = 0;
kbd_table[i].modeflags = KBD_DEFMODE;
- kbd_table[i].kbdmode = VC_XLATE;
+ kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
}
error = input_register_handler(&kbd_handler);
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 62051f8b091..81674d7c56c 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -144,7 +144,7 @@ static unsigned int lp_count = 0;
static struct class *lp_class;
#ifdef CONFIG_LP_CONSOLE
-static struct parport *console_registered; // initially NULL
+static struct parport *console_registered;
#endif /* CONFIG_LP_CONSOLE */
#undef LP_DEBUG
@@ -749,8 +749,8 @@ static struct console lpcons = {
/* --- initialisation code ------------------------------------- */
static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
-static char *parport[LP_NO] = { NULL, };
-static int reset = 0;
+static char *parport[LP_NO];
+static int reset;
module_param_array(parport, charp, NULL, 0);
module_param(reset, bool, 0);
@@ -758,10 +758,10 @@ module_param(reset, bool, 0);
#ifndef MODULE
static int __init lp_setup (char *str)
{
- static int parport_ptr; // initially zero
+ static int parport_ptr;
int x;
- if (get_option (&str, &x)) {
+ if (get_option(&str, &x)) {
if (x == 0) {
/* disable driver on "lp=" or "lp=0" */
parport_nr[0] = LP_PARPORT_OFF;
@@ -799,8 +799,7 @@ static int lp_register(int nr, struct parport *port)
if (reset)
lp_reset(nr);
- class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev,
- "lp%d", nr);
+ device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), "lp%d", nr);
printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name,
(port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
@@ -808,7 +807,7 @@ static int lp_register(int nr, struct parport *port)
#ifdef CONFIG_LP_CONSOLE
if (!nr) {
if (port->modes & PARPORT_MODE_SAFEININT) {
- register_console (&lpcons);
+ register_console(&lpcons);
console_registered = port;
printk (KERN_INFO "lp%d: console ready\n", CONSOLE_LP);
} else
@@ -824,8 +823,7 @@ static void lp_attach (struct parport *port)
{
unsigned int i;
- switch (parport_nr[0])
- {
+ switch (parport_nr[0]) {
case LP_PARPORT_UNSPEC:
case LP_PARPORT_AUTO:
if (parport_nr[0] == LP_PARPORT_AUTO &&
@@ -856,7 +854,7 @@ static void lp_detach (struct parport *port)
/* Write this some day. */
#ifdef CONFIG_LP_CONSOLE
if (console_registered == port) {
- unregister_console (&lpcons);
+ unregister_console(&lpcons);
console_registered = NULL;
}
#endif /* CONFIG_LP_CONSOLE */
@@ -971,7 +969,7 @@ static void lp_cleanup_module (void)
if (lp_table[offset].dev == NULL)
continue;
parport_unregister_device(lp_table[offset].dev);
- class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
+ device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
}
class_destroy(lp_class);
}
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index 7ee5d944492..3c5802ae171 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -22,7 +22,6 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/mm.h>
-#include <linux/fs.h>
#include <linux/uio.h>
#include <asm/io.h>
#include <asm/uaccess.h>
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index bbee97ff355..20070b7c573 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -41,7 +41,7 @@
*/
static inline int uncached_access(struct file *file, unsigned long addr)
{
-#if defined(__i386__)
+#if defined(__i386__) && !defined(__arch_um__)
/*
* On the PPro and successors, the MTRRs are used to set
* memory types for physical addresses outside main memory,
@@ -57,7 +57,7 @@ static inline int uncached_access(struct file *file, unsigned long addr)
test_bit(X86_FEATURE_CYRIX_ARR, boot_cpu_data.x86_capability) ||
test_bit(X86_FEATURE_CENTAUR_MCR, boot_cpu_data.x86_capability) )
&& addr >= __pa(high_memory);
-#elif defined(__x86_64__)
+#elif defined(__x86_64__) && !defined(__arch_um__)
/*
* This is broken because it can generate memory type aliases,
* which can cause cache corruptions
@@ -625,65 +625,10 @@ static ssize_t splice_write_null(struct pipe_inode_info *pipe,struct file *out,
return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null);
}
-#ifdef CONFIG_MMU
-/*
- * For fun, we are using the MMU for this.
- */
-static inline size_t read_zero_pagealigned(char __user * buf, size_t size)
-{
- struct mm_struct *mm;
- struct vm_area_struct * vma;
- unsigned long addr=(unsigned long)buf;
-
- mm = current->mm;
- /* Oops, this was forgotten before. -ben */
- down_read(&mm->mmap_sem);
-
- /* For private mappings, just map in zero pages. */
- for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
- unsigned long count;
-
- if (vma->vm_start > addr || (vma->vm_flags & VM_WRITE) == 0)
- goto out_up;
- if (vma->vm_flags & (VM_SHARED | VM_HUGETLB))
- break;
- count = vma->vm_end - addr;
- if (count > size)
- count = size;
-
- zap_page_range(vma, addr, count, NULL);
- if (zeromap_page_range(vma, addr, count, PAGE_COPY))
- break;
-
- size -= count;
- buf += count;
- addr += count;
- if (size == 0)
- goto out_up;
- }
-
- up_read(&mm->mmap_sem);
-
- /* The shared case is hard. Let's do the conventional zeroing. */
- do {
- unsigned long unwritten = clear_user(buf, PAGE_SIZE);
- if (unwritten)
- return size + unwritten - PAGE_SIZE;
- cond_resched();
- buf += PAGE_SIZE;
- size -= PAGE_SIZE;
- } while (size);
-
- return size;
-out_up:
- up_read(&mm->mmap_sem);
- return size;
-}
-
static ssize_t read_zero(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- unsigned long left, unwritten, written = 0;
+ size_t written;
if (!count)
return 0;
@@ -691,69 +636,33 @@ static ssize_t read_zero(struct file * file, char __user * buf,
if (!access_ok(VERIFY_WRITE, buf, count))
return -EFAULT;
- left = count;
-
- /* do we want to be clever? Arbitrary cut-off */
- if (count >= PAGE_SIZE*4) {
- unsigned long partial;
+ written = 0;
+ while (count) {
+ unsigned long unwritten;
+ size_t chunk = count;
- /* How much left of the page? */
- partial = (PAGE_SIZE-1) & -(unsigned long) buf;
- unwritten = clear_user(buf, partial);
- written = partial - unwritten;
- if (unwritten)
- goto out;
- left -= partial;
- buf += partial;
- unwritten = read_zero_pagealigned(buf, left & PAGE_MASK);
- written += (left & PAGE_MASK) - unwritten;
+ if (chunk > PAGE_SIZE)
+ chunk = PAGE_SIZE; /* Just for latency reasons */
+ unwritten = clear_user(buf, chunk);
+ written += chunk - unwritten;
if (unwritten)
- goto out;
- buf += left & PAGE_MASK;
- left &= ~PAGE_MASK;
- }
- unwritten = clear_user(buf, left);
- written += left - unwritten;
-out:
- return written ? written : -EFAULT;
-}
-
-static int mmap_zero(struct file * file, struct vm_area_struct * vma)
-{
- int err;
-
- if (vma->vm_flags & VM_SHARED)
- return shmem_zero_setup(vma);
- err = zeromap_page_range(vma, vma->vm_start,
- vma->vm_end - vma->vm_start, vma->vm_page_prot);
- BUG_ON(err == -EEXIST);
- return err;
-}
-#else /* CONFIG_MMU */
-static ssize_t read_zero(struct file * file, char * buf,
- size_t count, loff_t *ppos)
-{
- size_t todo = count;
-
- while (todo) {
- size_t chunk = todo;
-
- if (chunk > 4096)
- chunk = 4096; /* Just for latency reasons */
- if (clear_user(buf, chunk))
- return -EFAULT;
+ break;
buf += chunk;
- todo -= chunk;
+ count -= chunk;
cond_resched();
}
- return count;
+ return written ? written : -EFAULT;
}
static int mmap_zero(struct file * file, struct vm_area_struct * vma)
{
+#ifndef CONFIG_MMU
return -ENOSYS;
+#endif
+ if (vma->vm_flags & VM_SHARED)
+ return shmem_zero_setup(vma);
+ return 0;
}
-#endif /* CONFIG_MMU */
static ssize_t write_full(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
@@ -984,6 +893,11 @@ static struct class *mem_class;
static int __init chr_dev_init(void)
{
int i;
+ int err;
+
+ err = bdi_init(&zero_bdi);
+ if (err)
+ return err;
if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index ed76f0a127f..2fc255a2148 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -41,6 +41,7 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/bitops.h>
+#include <linux/completion.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -142,7 +143,7 @@ struct moxa_port {
struct tty_struct *tty;
int cflag;
wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
+ struct completion close_wait;
struct timer_list emptyTimer;
@@ -166,7 +167,6 @@ struct moxa_port {
#define WAKEUP_CHARS 256
-static int verbose = 0;
static int ttymajor = MOXAMAJOR;
/* Variables for insmod */
#ifdef MODULE
@@ -184,7 +184,6 @@ module_param_array(baseaddr, int, NULL, 0);
module_param_array(numports, int, NULL, 0);
#endif
module_param(ttymajor, int, 0);
-module_param(verbose, bool, 0644);
/*
* static functions:
@@ -208,13 +207,13 @@ static int moxa_tiocmget(struct tty_struct *tty, struct file *file);
static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
static void moxa_poll(unsigned long);
-static void set_tty_param(struct tty_struct *);
-static int block_till_ready(struct tty_struct *, struct file *,
+static void moxa_set_tty_param(struct tty_struct *);
+static int moxa_block_till_ready(struct tty_struct *, struct file *,
struct moxa_port *);
-static void setup_empty_event(struct tty_struct *);
-static void check_xmit_empty(unsigned long);
-static void shut_down(struct moxa_port *);
-static void receive_data(struct moxa_port *);
+static void moxa_setup_empty_event(struct tty_struct *);
+static void moxa_check_xmit_empty(unsigned long);
+static void moxa_shut_down(struct moxa_port *);
+static void moxa_receive_data(struct moxa_port *);
/*
* moxa board interface functions:
*/
@@ -283,8 +282,10 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev,
int retval;
retval = pci_enable_device(pdev);
- if (retval)
+ if (retval) {
+ dev_err(&pdev->dev, "can't enable pci device\n");
goto err;
+ }
for (i = 0; i < MAX_BOARDS; i++)
if (moxa_boards[i].basemem == NULL)
@@ -292,16 +293,17 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev,
retval = -ENODEV;
if (i >= MAX_BOARDS) {
- if (verbose)
- printk("More than %d MOXA Intellio family boards "
+ dev_warn(&pdev->dev, "more than %u MOXA Intellio family boards "
"found. Board is ignored.\n", MAX_BOARDS);
goto err;
}
board = &moxa_boards[i];
board->basemem = pci_iomap(pdev, 2, 0x4000);
- if (board->basemem == NULL)
+ if (board->basemem == NULL) {
+ dev_err(&pdev->dev, "can't remap io space 2\n");
goto err;
+ }
board->boardType = board_type;
switch (board_type) {
@@ -347,7 +349,8 @@ static int __init moxa_init(void)
int i, numBoards, retval = 0;
struct moxa_port *ch;
- printk(KERN_INFO "MOXA Intellio family driver version %s\n", MOXA_VERSION);
+ printk(KERN_INFO "MOXA Intellio family driver version %s\n",
+ MOXA_VERSION);
moxaDriver = alloc_tty_driver(MAX_PORTS + 1);
if (!moxaDriver)
return -ENOMEM;
@@ -372,13 +375,13 @@ static int __init moxa_init(void)
ch->closing_wait = 30 * HZ;
ch->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
init_waitqueue_head(&ch->open_wait);
- init_waitqueue_head(&ch->close_wait);
+ init_completion(&ch->close_wait);
- setup_timer(&ch->emptyTimer, check_xmit_empty,
+ setup_timer(&ch->emptyTimer, moxa_check_xmit_empty,
(unsigned long)ch);
}
- printk("Tty devices major number = %d\n", ttymajor);
+ pr_debug("Moxa tty devices major number = %d\n", ttymajor);
if (tty_register_driver(moxaDriver)) {
printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n");
@@ -400,11 +403,10 @@ static int __init moxa_init(void)
moxa_boards[numBoards].numPorts = moxa_isa_boards[i].numPorts;
moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA;
moxa_boards[numBoards].baseAddr = moxa_isa_boards[i].baseAddr;
- if (verbose)
- printk("Board %2d: %s board(baseAddr=%lx)\n",
- numBoards + 1,
- moxa_brdname[moxa_boards[numBoards].boardType - 1],
- moxa_boards[numBoards].baseAddr);
+ pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
+ numBoards + 1,
+ moxa_brdname[moxa_boards[numBoards].boardType-1],
+ moxa_boards[numBoards].baseAddr);
numBoards++;
}
}
@@ -413,14 +415,13 @@ static int __init moxa_init(void)
for (i = 0; i < MAX_BOARDS; i++) {
if ((type[i] == MOXA_BOARD_C218_ISA) ||
(type[i] == MOXA_BOARD_C320_ISA)) {
- if (verbose)
- printk("Board %2d: %s board(baseAddr=%lx)\n",
- numBoards + 1,
- moxa_brdname[type[i] - 1],
- (unsigned long) baseaddr[i]);
+ pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
+ numBoards + 1, moxa_brdname[type[i] - 1],
+ (unsigned long)baseaddr[i]);
if (numBoards >= MAX_BOARDS) {
- if (verbose)
- printk("More than %d MOXA Intellio family boards found. Board is ignored.", MAX_BOARDS);
+ printk(KERN_WARNING "More than %d MOXA "
+ "Intellio family boards found. Board "
+ "is ignored.\n", MAX_BOARDS);
continue;
}
moxa_boards[numBoards].boardType = type[i];
@@ -456,16 +457,14 @@ static void __exit moxa_exit(void)
{
int i;
- if (verbose)
- printk("Unloading module moxa ...\n");
-
del_timer_sync(&moxaTimer);
for (i = 0; i < MAX_PORTS; i++)
del_timer_sync(&moxa_ports[i].emptyTimer);
if (tty_unregister_driver(moxaDriver))
- printk("Couldn't unregister MOXA Intellio family serial driver\n");
+ printk(KERN_ERR "Couldn't unregister MOXA Intellio family "
+ "serial driver\n");
put_tty_driver(moxaDriver);
#ifdef CONFIG_PCI
@@ -475,9 +474,6 @@ static void __exit moxa_exit(void)
for (i = 0; i < MAX_BOARDS; i++)
if (moxa_boards[i].basemem)
iounmap(moxa_boards[i].basemem);
-
- if (verbose)
- printk("Done\n");
}
module_init(moxa_init);
@@ -504,12 +500,12 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
ch->tty = tty;
if (!(ch->asyncflags & ASYNC_INITIALIZED)) {
ch->statusflags = 0;
- set_tty_param(tty);
+ moxa_set_tty_param(tty);
MoxaPortLineCtrl(ch->port, 1, 1);
MoxaPortEnable(ch->port);
ch->asyncflags |= ASYNC_INITIALIZED;
}
- retval = block_till_ready(tty, filp, ch);
+ retval = moxa_block_till_ready(tty, filp, ch);
moxa_unthrottle(tty);
@@ -532,9 +528,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
return;
}
if (!MoxaPortIsValid(port)) {
-#ifdef SERIAL_DEBUG_CLOSE
- printk("Invalid portno in moxa_close\n");
-#endif
+ pr_debug("Invalid portno in moxa_close\n");
tty->driver_data = NULL;
return;
}
@@ -547,13 +541,13 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
ch = (struct moxa_port *) tty->driver_data;
if ((tty->count == 1) && (ch->count != 1)) {
- printk("moxa_close: bad serial port count; tty->count is 1, "
- "ch->count is %d\n", ch->count);
+ printk(KERN_WARNING "moxa_close: bad serial port count; "
+ "tty->count is 1, ch->count is %d\n", ch->count);
ch->count = 1;
}
if (--ch->count < 0) {
- printk("moxa_close: bad serial port count, device=%s\n",
- tty->name);
+ printk(KERN_WARNING "moxa_close: bad serial port count, "
+ "device=%s\n", tty->name);
ch->count = 0;
}
if (ch->count) {
@@ -563,11 +557,11 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
ch->cflag = tty->termios->c_cflag;
if (ch->asyncflags & ASYNC_INITIALIZED) {
- setup_empty_event(tty);
+ moxa_setup_empty_event(tty);
tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */
del_timer_sync(&moxa_ports[ch->port].emptyTimer);
}
- shut_down(ch);
+ moxa_shut_down(ch);
MoxaPortFlushData(port, 2);
if (tty->driver->flush_buffer)
@@ -584,7 +578,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp)
wake_up_interruptible(&ch->open_wait);
}
ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
- wake_up_interruptible(&ch->close_wait);
+ complete_all(&ch->close_wait);
}
static int moxa_write(struct tty_struct *tty,
@@ -653,7 +647,7 @@ static int moxa_chars_in_buffer(struct tty_struct *tty)
* in tty_ioctl.c, etc.
*/
if (!(ch->statusflags & EMPTYWAIT))
- setup_empty_event(tty);
+ moxa_setup_empty_event(tty);
}
return (chars);
}
@@ -751,7 +745,7 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
retval = tty_check_change(tty);
if (retval)
return (retval);
- setup_empty_event(tty);
+ moxa_setup_empty_event(tty);
tty_wait_until_sent(tty, 0);
if (!arg)
MoxaPortSendBreak(ch->port, 0);
@@ -760,7 +754,7 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file,
retval = tty_check_change(tty);
if (retval)
return (retval);
- setup_empty_event(tty);
+ moxa_setup_empty_event(tty);
tty_wait_until_sent(tty, 0);
MoxaPortSendBreak(ch->port, arg);
return (0);
@@ -809,7 +803,7 @@ static void moxa_set_termios(struct tty_struct *tty,
if (ch == NULL)
return;
- set_tty_param(tty);
+ moxa_set_tty_param(tty);
if (!(old_termios->c_cflag & CLOCAL) &&
(tty->termios->c_cflag & CLOCAL))
wake_up_interruptible(&ch->open_wait);
@@ -845,7 +839,7 @@ static void moxa_hangup(struct tty_struct *tty)
struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
moxa_flush_buffer(tty);
- shut_down(ch);
+ moxa_shut_down(ch);
ch->event = 0;
ch->count = 0;
ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
@@ -875,7 +869,7 @@ static void moxa_poll(unsigned long ignored)
continue;
if (!(ch->statusflags & THROTTLE) &&
(MoxaPortRxQueue(ch->port) > 0))
- receive_data(ch);
+ moxa_receive_data(ch);
if ((tp = ch->tty) == 0)
continue;
if (ch->statusflags & LOWWAIT) {
@@ -909,7 +903,7 @@ static void moxa_poll(unsigned long ignored)
/******************************************************************************/
-static void set_tty_param(struct tty_struct *tty)
+static void moxa_set_tty_param(struct tty_struct *tty)
{
register struct ktermios *ts;
struct moxa_port *ch;
@@ -934,7 +928,7 @@ static void set_tty_param(struct tty_struct *tty)
MoxaPortSetTermio(ch->port, ts, tty_get_baud_rate(tty));
}
-static int block_till_ready(struct tty_struct *tty, struct file *filp,
+static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
struct moxa_port *ch)
{
DECLARE_WAITQUEUE(wait,current);
@@ -948,7 +942,7 @@ static int block_till_ready(struct tty_struct *tty, struct file *filp,
*/
if (tty_hung_up_p(filp) || (ch->asyncflags & ASYNC_CLOSING)) {
if (ch->asyncflags & ASYNC_CLOSING)
- interruptible_sleep_on(&ch->close_wait);
+ wait_for_completion_interruptible(&ch->close_wait);
#ifdef SERIAL_DO_RESTART
if (ch->asyncflags & ASYNC_HUP_NOTIFY)
return (-EAGAIN);
@@ -971,10 +965,8 @@ static int block_till_ready(struct tty_struct *tty, struct file *filp,
*/
retval = 0;
add_wait_queue(&ch->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttys%d, count = %d\n",
- ch->line, ch->count);
-#endif
+ pr_debug("block_til_ready before block: ttys%d, count = %d\n",
+ ch->port, ch->count);
spin_lock_irqsave(&moxa_lock, flags);
if (!tty_hung_up_p(filp))
ch->count--;
@@ -1013,10 +1005,8 @@ static int block_till_ready(struct tty_struct *tty, struct file *filp,
ch->count++;
ch->blocked_open--;
spin_unlock_irqrestore(&moxa_lock, flags);
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttys%d, count = %d\n",
- ch->line, ch->count);
-#endif
+ pr_debug("block_til_ready after blocking: ttys%d, count = %d\n",
+ ch->port, ch->count);
if (retval)
return (retval);
/* FIXME: review to see if we need to use set_bit on these */
@@ -1024,7 +1014,7 @@ static int block_till_ready(struct tty_struct *tty, struct file *filp,
return 0;
}
-static void setup_empty_event(struct tty_struct *tty)
+static void moxa_setup_empty_event(struct tty_struct *tty)
{
struct moxa_port *ch = tty->driver_data;
unsigned long flags;
@@ -1035,24 +1025,24 @@ static void setup_empty_event(struct tty_struct *tty)
spin_unlock_irqrestore(&moxa_lock, flags);
}
-static void check_xmit_empty(unsigned long data)
+static void moxa_check_xmit_empty(unsigned long data)
{
struct moxa_port *ch;
ch = (struct moxa_port *) data;
- del_timer_sync(&moxa_ports[ch->port].emptyTimer);
if (ch->tty && (ch->statusflags & EMPTYWAIT)) {
if (MoxaPortTxQueue(ch->port) == 0) {
ch->statusflags &= ~EMPTYWAIT;
tty_wakeup(ch->tty);
return;
}
- mod_timer(&moxa_ports[ch->port].emptyTimer, jiffies + HZ);
+ mod_timer(&moxa_ports[ch->port].emptyTimer,
+ round_jiffies(jiffies + HZ));
} else
ch->statusflags &= ~EMPTYWAIT;
}
-static void shut_down(struct moxa_port *ch)
+static void moxa_shut_down(struct moxa_port *ch)
{
struct tty_struct *tp;
@@ -1072,7 +1062,7 @@ static void shut_down(struct moxa_port *ch)
ch->asyncflags &= ~ASYNC_INITIALIZED;
}
-static void receive_data(struct moxa_port *ch)
+static void moxa_receive_data(struct moxa_port *ch)
{
struct tty_struct *tp;
struct ktermios *ts;
@@ -1406,8 +1396,8 @@ static struct mon_str moxaLog;
static int moxaFuncTout = HZ / 2;
static void moxafunc(void __iomem *, int, ushort);
-static void wait_finish(void __iomem *);
-static void low_water_check(void __iomem *);
+static void moxa_wait_finish(void __iomem *);
+static void moxa_low_water_check(void __iomem *);
static int moxaloadbios(int, unsigned char __user *, int);
static int moxafindcard(int);
static int moxaload320b(int, unsigned char __user *, int);
@@ -1473,7 +1463,7 @@ void MoxaPortFlushData(int port, int mode)
moxafunc(ofsAddr, FC_FlushQueue, mode);
if (mode != 1) {
moxa_ports[port].lowChkFlag = 0;
- low_water_check(ofsAddr);
+ moxa_low_water_check(ofsAddr);
}
}
@@ -1654,7 +1644,7 @@ int MoxaDriverPoll(void)
if (moxa_ports[p].lowChkFlag) {
moxa_ports[p].lowChkFlag = 0;
ofsAddr = moxa_ports[p].tableAddr;
- low_water_check(ofsAddr);
+ moxa_low_water_check(ofsAddr);
}
}
}
@@ -2081,7 +2071,7 @@ int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud)
writeb(termio->c_cc[VSTART], ofsAddr + FuncArg);
writeb(termio->c_cc[VSTOP], ofsAddr + FuncArg1);
writeb(FC_SetXonXoff, ofsAddr + FuncCode);
- wait_finish(ofsAddr);
+ moxa_wait_finish(ofsAddr);
}
return (0);
@@ -2480,10 +2470,10 @@ static void moxafunc(void __iomem *ofsAddr, int cmd, ushort arg)
writew(arg, ofsAddr + FuncArg);
writew(cmd, ofsAddr + FuncCode);
- wait_finish(ofsAddr);
+ moxa_wait_finish(ofsAddr);
}
-static void wait_finish(void __iomem *ofsAddr)
+static void moxa_wait_finish(void __iomem *ofsAddr)
{
unsigned long i, j;
@@ -2496,7 +2486,7 @@ static void wait_finish(void __iomem *ofsAddr)
}
}
-static void low_water_check(void __iomem *ofsAddr)
+static void moxa_low_water_check(void __iomem *ofsAddr)
{
int len;
ushort rptr, wptr, mask;
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index 04ac155d3a0..82f2e27dca7 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -362,7 +362,7 @@ mspec_init(void)
is_sn2 = 1;
if (is_shub2()) {
ret = -ENOMEM;
- for_each_online_node(nid) {
+ for_each_node_state(nid, N_ONLINE) {
int actual_nid;
int nasid;
unsigned long phys;
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 2aee3fef041..fd0abef7ee0 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -56,11 +56,11 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/pci.h>
+#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/bitops.h>
#include <asm/uaccess.h>
#include "mxser.h"
@@ -383,7 +383,6 @@ static int mxser_init(void);
/* static void mxser_poll(unsigned long); */
static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
-static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *);
static void mxser_do_softint(struct work_struct *);
static int mxser_open(struct tty_struct *, struct file *);
static void mxser_close(struct tty_struct *, struct file *);
@@ -422,7 +421,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout);
static void mxser_startrx(struct tty_struct *tty);
static void mxser_stoprx(struct tty_struct *tty);
-
+#ifdef CONFIG_PCI
static int CheckIsMoxaMust(int io)
{
u8 oldmcr, hwid;
@@ -445,6 +444,7 @@ static int CheckIsMoxaMust(int io)
}
return MOXA_OTHER_UART;
}
+#endif
/* above is modified by Victor Yu. 08-15-2002 */
@@ -1938,14 +1938,6 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
inb(info->base + UART_MSR);
continue;
}
- /* above add by Victor Yu. 09-13-2002 */
- /*
- if (info->tty->flip.count < TTY_FLIPBUF_SIZE / 4) {
- info->IER |= MOXA_MUST_RECV_ISR;
- outb(info->IER, info->base + UART_IER);
- }
- */
-
/* mask by Victor Yu. 09-13-2002
if ( !info->tty ||
@@ -2599,19 +2591,8 @@ static int mxser_change_speed(struct mxser_struct *info, struct ktermios *old_te
info->IER |= UART_IER_MSI;
if ((info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) {
info->MCR |= UART_MCR_AFE;
- /* status = mxser_get_msr(info->base, 0, info->port); */
-/*
- save_flags(flags);
- cli();
- status = inb(baseaddr + UART_MSR);
- restore_flags(flags);
-*/
- /* mxser_check_modem_status(info, status); */
} else {
- /* status = mxser_get_msr(info->base, 0, info->port); */
- /* MX_LOCK(&info->slock); */
status = inb(info->base + UART_MSR);
- /* MX_UNLOCK(&info->slock); */
if (info->tty->hw_stopped) {
if (status & UART_MSR_CTS) {
info->tty->hw_stopped = 0;
diff --git a/drivers/char/mxser.h b/drivers/char/mxser.h
index 9fe28497eae..1f4aa45ec00 100644
--- a/drivers/char/mxser.h
+++ b/drivers/char/mxser.h
@@ -30,8 +30,7 @@
#define TTY_THRESHOLD_THROTTLE 128
-#define LO_WATER (TTY_FLIPBUF_SIZE)
-#define HI_WATER (TTY_FLIPBUF_SIZE*2*3/4)
+#define HI_WATER 768
// added by James. 03-11-2004.
#define MOXA_SDS_GETICOUNTER (MOXA + 68)
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c
index 6a563932ba1..081c84c7b54 100644
--- a/drivers/char/mxser_new.c
+++ b/drivers/char/mxser_new.c
@@ -2,7 +2,7 @@
* mxser.c -- MOXA Smartio/Industio family multiport serial driver.
*
* Copyright (C) 1999-2006 Moxa Technologies (support@moxa.com.tw).
- * Copyright (C) 2006 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (C) 2006-2007 Jiri Slaby <jirislaby@gmail.com>
*
* This code is loosely based on the 1.8 moxa driver which is based on
* Linux serial driver, written by Linus Torvalds, Theodore T'so and
@@ -39,16 +39,16 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/pci.h>
+#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/bitops.h>
#include <asm/uaccess.h>
#include "mxser_new.h"
-#define MXSER_VERSION "2.0.1" /* 1.9.15 */
+#define MXSER_VERSION "2.0.2" /* 1.10 */
#define MXSERMAJOR 174
#define MXSERCUMAJOR 175
@@ -72,6 +72,12 @@
#define UART_MCR_AFE 0x20
#define UART_LSR_SPECIAL 0x1E
+#define PCI_DEVICE_ID_CB108 0x1080
+#define PCI_DEVICE_ID_CB114 0x1142
+#define PCI_DEVICE_ID_CB134I 0x1341
+#define PCI_DEVICE_ID_CP138U 0x1380
+#define PCI_DEVICE_ID_POS104UL 0x1044
+
#define C168_ASIC_ID 1
#define C104_ASIC_ID 2
@@ -107,71 +113,63 @@ struct mxser_cardinfo {
};
static const struct mxser_cardinfo mxser_cards[] = {
- { 8, "C168 series", }, /* C168-ISA */
- { 4, "C104 series", }, /* C104-ISA */
- { 4, "CI-104J series", }, /* CI104J */
- { 8, "C168H/PCI series", }, /* C168-PCI */
- { 4, "C104H/PCI series", }, /* C104-PCI */
- { 4, "C102 series", MXSER_HAS2 }, /* C102-ISA */
- { 4, "CI-132 series", MXSER_HAS2 }, /* CI132 */
- { 4, "CI-134 series", }, /* CI134 */
- { 2, "CP-132 series", }, /* CP132 */
- { 4, "CP-114 series", }, /* CP114 */
- { 4, "CT-114 series", }, /* CT114 */
- { 2, "CP-102 series", MXSER_HIGHBAUD }, /* CP102 */
- { 4, "CP-104U series", }, /* CP104U */
- { 8, "CP-168U series", }, /* CP168U */
- { 2, "CP-132U series", }, /* CP132U */
- { 4, "CP-134U series", }, /* CP134U */
- { 4, "CP-104JU series", }, /* CP104JU */
+/* 0*/ { 8, "C168 series", },
+ { 4, "C104 series", },
+ { 4, "CI-104J series", },
+ { 8, "C168H/PCI series", },
+ { 4, "C104H/PCI series", },
+/* 5*/ { 4, "C102 series", MXSER_HAS2 }, /* C102-ISA */
+ { 4, "CI-132 series", MXSER_HAS2 },
+ { 4, "CI-134 series", },
+ { 2, "CP-132 series", },
+ { 4, "CP-114 series", },
+/*10*/ { 4, "CT-114 series", },
+ { 2, "CP-102 series", MXSER_HIGHBAUD },
+ { 4, "CP-104U series", },
+ { 8, "CP-168U series", },
+ { 2, "CP-132U series", },
+/*15*/ { 4, "CP-134U series", },
+ { 4, "CP-104JU series", },
{ 8, "Moxa UC7000 Serial", }, /* RC7000 */
- { 8, "CP-118U series", }, /* CP118U */
- { 2, "CP-102UL series", }, /* CP102UL */
- { 2, "CP-102U series", }, /* CP102U */
- { 8, "CP-118EL series", }, /* CP118EL */
- { 8, "CP-168EL series", }, /* CP168EL */
- { 4, "CP-104EL series", } /* CP104EL */
+ { 8, "CP-118U series", },
+ { 2, "CP-102UL series", },
+/*20*/ { 2, "CP-102U series", },
+ { 8, "CP-118EL series", },
+ { 8, "CP-168EL series", },
+ { 4, "CP-104EL series", },
+ { 8, "CB-108 series", },
+/*25*/ { 4, "CB-114 series", },
+ { 4, "CB-134I series", },
+ { 8, "CP-138U series", },
+ { 4, "POS-104UL series", }
};
/* driver_data correspond to the lines in the structure above
see also ISA probe function before you change something */
static struct pci_device_id mxser_pcibrds[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C168),
- .driver_data = 3 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C104),
- .driver_data = 4 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132),
- .driver_data = 8 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114),
- .driver_data = 9 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CT114),
- .driver_data = 10 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102),
- .driver_data = 11 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104U),
- .driver_data = 12 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168U),
- .driver_data = 13 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132U),
- .driver_data = 14 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134U),
- .driver_data = 15 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104JU),
- .driver_data = 16 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_RC7000),
- .driver_data = 17 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118U),
- .driver_data = 18 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102UL),
- .driver_data = 19 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102U),
- .driver_data = 20 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118EL),
- .driver_data = 21 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168EL),
- .driver_data = 22 },
- { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104EL),
- .driver_data = 23 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 3 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104), .driver_data = 4 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 8 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114), .driver_data = 9 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114), .driver_data = 10 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102), .driver_data = 11 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 12 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 13 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 14 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 15 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 16 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 17 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 18 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 19 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 20 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 21 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 22 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 23 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108), .driver_data = 24 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114), .driver_data = 25 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I), .driver_data = 26 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U), .driver_data = 27 },
+ { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 28 },
{ }
};
MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index e8332f305d7..82bcfb9c839 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -229,7 +229,7 @@ static void n_hdlc_release(struct n_hdlc *n_hdlc)
wake_up_interruptible (&tty->read_wait);
wake_up_interruptible (&tty->write_wait);
- if (tty != NULL && tty->disc_data == n_hdlc)
+ if (tty->disc_data == n_hdlc)
tty->disc_data = NULL; /* Break the tty->n_hdlc link */
/* Release transmit and receive buffers */
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 03805691193..596c7173997 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -437,7 +437,7 @@ static inline void finish_erasing(struct tty_struct *tty)
* @c: character input
* @tty: terminal device
*
- * Perform erase and neccessary output when an erase character is
+ * Perform erase and necessary output when an erase character is
* present in the stream from the driver layer. Handles the complexities
* of UTF-8 multibyte symbols.
*/
@@ -657,7 +657,7 @@ static inline void n_tty_receive_overrun(struct tty_struct *tty)
* @c: character
*
* Process a parity error and queue the right data to indicate
- * the error case if neccessary. Locking as per n_tty_receive_buf.
+ * the error case if necessary. Locking as per n_tty_receive_buf.
*/
static inline void n_tty_receive_parity_error(struct tty_struct *tty,
unsigned char c)
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 4177f6db83e..02518da6a38 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -47,7 +47,7 @@
/* #define ATR_CSUM */
#ifdef PCMCIA_DEBUG
-#define reader_to_dev(x) (&handle_to_dev(x->p_dev->handle))
+#define reader_to_dev(x) (&handle_to_dev(x->p_dev))
static int pc_debug = PCMCIA_DEBUG;
module_param(pc_debug, int, 0600);
#define DEBUGP(n, rdr, x, args...) do { \
@@ -1863,8 +1863,7 @@ static int cm4000_probe(struct pcmcia_device *link)
return ret;
}
- class_device_create(cmm_class, NULL, MKDEV(major, i), NULL,
- "cmm%d", i);
+ device_create(cmm_class, NULL, MKDEV(major, i), "cmm%d", i);
return 0;
}
@@ -1888,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link)
dev_table[devno] = NULL;
kfree(dev);
- class_device_destroy(cmm_class, MKDEV(major, devno));
+ device_destroy(cmm_class, MKDEV(major, devno));
return;
}
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index b24a3e7bbb9..5f291bf739a 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -41,7 +41,7 @@
#ifdef PCMCIA_DEBUG
-#define reader_to_dev(x) (&handle_to_dev(x->p_dev->handle))
+#define reader_to_dev(x) (&handle_to_dev(x->p_dev))
static int pc_debug = PCMCIA_DEBUG;
module_param(pc_debug, int, 0600);
#define DEBUGP(n, rdr, x, args...) do { \
@@ -642,8 +642,7 @@ static int reader_probe(struct pcmcia_device *link)
return ret;
}
- class_device_create(cmx_class, NULL, MKDEV(major, i), NULL,
- "cmx%d", i);
+ device_create(cmx_class, NULL, MKDEV(major, i), "cmx%d", i);
return 0;
}
@@ -666,7 +665,7 @@ static void reader_detach(struct pcmcia_device *link)
dev_table[devno] = NULL;
kfree(dev);
- class_device_destroy(cmx_class, MKDEV(major, devno));
+ device_destroy(cmx_class, MKDEV(major, devno));
return;
}
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 2b889317461..8caff0ca80f 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -123,7 +123,7 @@ typedef struct
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
struct _input_signal_events {
- int ri_up;
+ int ri_up;
int ri_down;
int dsr_up;
int dsr_down;
@@ -137,7 +137,7 @@ struct _input_signal_events {
/*
* Device instance data structure
*/
-
+
typedef struct _mgslpc_info {
void *if_ptr; /* General purpose pointer (used by SPPP) */
int magic;
@@ -146,15 +146,15 @@ typedef struct _mgslpc_info {
int line;
unsigned short close_delay;
unsigned short closing_wait; /* time to wait before closing */
-
+
struct mgsl_icount icount;
-
+
struct tty_struct *tty;
int timeout;
int x_char; /* xon/xoff character */
int blocked_open; /* # of blocked opens */
unsigned char read_status_mask;
- unsigned char ignore_status_mask;
+ unsigned char ignore_status_mask;
unsigned char *tx_buf;
int tx_put;
@@ -170,10 +170,10 @@ typedef struct _mgslpc_info {
int rx_buf_size; /* size in bytes of single rx buffer */
int rx_buf_count; /* total number of rx buffers */
int rx_frame_count; /* number of full rx buffers */
-
+
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
-
+
wait_queue_head_t status_event_wait_q;
wait_queue_head_t event_wait_q;
struct timer_list tx_timer; /* HDLC transmit timeout timer */
@@ -192,7 +192,7 @@ typedef struct _mgslpc_info {
int bh_running;
int bh_requested;
-
+
int dcd_chkcount; /* check counts to prevent */
int cts_chkcount; /* too many IRQs if a signal */
int dsr_chkcount; /* is floating */
@@ -212,7 +212,7 @@ typedef struct _mgslpc_info {
unsigned int io_base; /* base I/O address of adapter */
unsigned int irq_level;
-
+
MGSL_PARAMS params; /* communications parameters */
unsigned char serial_signals; /* current serial signal states */
@@ -249,7 +249,7 @@ typedef struct _mgslpc_info {
*/
#define TXBUFSIZE 4096
-
+
#define CHA 0x00 /* channel A offset */
#define CHB 0x40 /* channel B offset */
@@ -298,9 +298,9 @@ typedef struct _mgslpc_info {
#define PIM 0x3d
#define PCR 0x3e
#define CCR4 0x3f
-
+
// IMR/ISR
-
+
#define IRQ_BREAK_ON BIT15 // rx break detected
#define IRQ_DATAOVERRUN BIT14 // receive data overflow
#define IRQ_ALLSENT BIT13 // all sent
@@ -315,13 +315,13 @@ typedef struct _mgslpc_info {
#define IRQ_DCD BIT2 // carrier detect status change
#define IRQ_OVERRUN BIT1 // receive frame overflow
#define IRQ_RXFIFO BIT0 // receive pool full
-
+
// STAR
-
+
#define XFW BIT6 // transmit FIFO write enable
#define CEC BIT2 // command executing
#define CTS BIT1 // CTS state
-
+
#define PVR_DTR BIT0
#define PVR_DSR BIT1
#define PVR_RI BIT2
@@ -329,25 +329,25 @@ typedef struct _mgslpc_info {
#define PVR_RS232 0x20 /* 0010b */
#define PVR_V35 0xe0 /* 1110b */
#define PVR_RS422 0x40 /* 0100b */
-
-/* Register access functions */
-
+
+/* Register access functions */
+
#define write_reg(info, reg, val) outb((val),(info)->io_base + (reg))
#define read_reg(info, reg) inb((info)->io_base + (reg))
-#define read_reg16(info, reg) inw((info)->io_base + (reg))
+#define read_reg16(info, reg) inw((info)->io_base + (reg))
#define write_reg16(info, reg, val) outw((val), (info)->io_base + (reg))
-
+
#define set_reg_bits(info, reg, mask) \
write_reg(info, (reg), \
- (unsigned char) (read_reg(info, (reg)) | (mask)))
+ (unsigned char) (read_reg(info, (reg)) | (mask)))
#define clear_reg_bits(info, reg, mask) \
write_reg(info, (reg), \
- (unsigned char) (read_reg(info, (reg)) & ~(mask)))
+ (unsigned char) (read_reg(info, (reg)) & ~(mask)))
/*
* interrupt enable/disable routines
- */
-static void irq_disable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask)
+ */
+static void irq_disable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask)
{
if (channel == CHA) {
info->imra_value |= mask;
@@ -357,7 +357,7 @@ static void irq_disable(MGSLPC_INFO *info, unsigned char channel, unsigned short
write_reg16(info, CHB + IMR, info->imrb_value);
}
}
-static void irq_enable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask)
+static void irq_enable(MGSLPC_INFO *info, unsigned char channel, unsigned short mask)
{
if (channel == CHA) {
info->imra_value &= ~mask;
@@ -558,7 +558,7 @@ static int mgslpc_probe(struct pcmcia_device *link)
spin_lock_init(&info->lock);
spin_lock_init(&info->netlock);
memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
- info->idle_mode = HDLC_TXIDLE_FLAGS;
+ info->idle_mode = HDLC_TXIDLE_FLAGS;
info->imra_value = 0xffff;
info->imrb_value = 0xffff;
info->pim_value = 0xff;
@@ -600,7 +600,7 @@ static int mgslpc_config(struct pcmcia_device *link)
u_char buf[64];
cistpl_cftable_entry_t dflt = { 0 };
cistpl_cftable_entry_t *cfg;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("mgslpc_config(0x%p)\n", link);
@@ -624,7 +624,7 @@ static int mgslpc_config(struct pcmcia_device *link)
link->conf.ConfigIndex = cfg->index;
link->conf.Attributes |= CONF_ENABLE_IRQ;
-
+
/* IO window settings */
link->io.NumPorts1 = 0;
if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
@@ -644,7 +644,7 @@ static int mgslpc_config(struct pcmcia_device *link)
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 8;
link->conf.Present = PRESENT_OPTION;
-
+
link->irq.Attributes |= IRQ_HANDLE_PRESENT;
link->irq.Handler = mgslpc_isr;
link->irq.Instance = info;
@@ -753,10 +753,10 @@ static inline int mgslpc_paranoia_check(MGSLPC_INFO *info,
#define CMD_TXEOM BIT1 // transmit end message
#define CMD_TXRESET BIT0 // transmit reset
-static BOOLEAN wait_command_complete(MGSLPC_INFO *info, unsigned char channel)
+static BOOLEAN wait_command_complete(MGSLPC_INFO *info, unsigned char channel)
{
int i = 0;
- /* wait for command completion */
+ /* wait for command completion */
while (read_reg(info, (unsigned char)(channel+STAR)) & BIT2) {
udelay(1);
if (i++ == 1000)
@@ -765,7 +765,7 @@ static BOOLEAN wait_command_complete(MGSLPC_INFO *info, unsigned char channel)
return TRUE;
}
-static void issue_command(MGSLPC_INFO *info, unsigned char channel, unsigned char cmd)
+static void issue_command(MGSLPC_INFO *info, unsigned char channel, unsigned char cmd)
{
wait_command_complete(info, channel);
write_reg(info, (unsigned char) (channel + CMDR), cmd);
@@ -775,12 +775,12 @@ static void tx_pause(struct tty_struct *tty)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
-
+
if (mgslpc_paranoia_check(info, tty->name, "tx_pause"))
return;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("tx_pause(%s)\n",info->device_name);
-
+ printk("tx_pause(%s)\n",info->device_name);
+
spin_lock_irqsave(&info->lock,flags);
if (info->tx_enabled)
tx_stop(info);
@@ -791,12 +791,12 @@ static void tx_release(struct tty_struct *tty)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
-
+
if (mgslpc_paranoia_check(info, tty->name, "tx_release"))
return;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("tx_release(%s)\n",info->device_name);
-
+ printk("tx_release(%s)\n",info->device_name);
+
spin_lock_irqsave(&info->lock,flags);
if (!info->tx_enabled)
tx_start(info);
@@ -810,7 +810,7 @@ static int bh_action(MGSLPC_INFO *info)
{
unsigned long flags;
int rc = 0;
-
+
spin_lock_irqsave(&info->lock,flags);
if (info->pending_bh & BH_RECEIVE) {
@@ -829,9 +829,9 @@ static int bh_action(MGSLPC_INFO *info)
info->bh_running = 0;
info->bh_requested = 0;
}
-
+
spin_unlock_irqrestore(&info->lock,flags);
-
+
return rc;
}
@@ -842,22 +842,22 @@ static void bh_handler(struct work_struct *work)
if (!info)
return;
-
+
if (debug_level >= DEBUG_LEVEL_BH)
printk( "%s(%d):bh_handler(%s) entry\n",
__FILE__,__LINE__,info->device_name);
-
+
info->bh_running = 1;
while((action = bh_action(info)) != 0) {
-
+
/* Process work item */
if ( debug_level >= DEBUG_LEVEL_BH )
printk( "%s(%d):bh_handler() work item action=%d\n",
__FILE__,__LINE__,action);
switch (action) {
-
+
case BH_RECEIVE:
while(rx_get_frame(info));
break;
@@ -897,7 +897,7 @@ static void bh_status(MGSLPC_INFO *info)
info->cts_chkcount = 0;
}
-/* eom: non-zero = end of frame */
+/* eom: non-zero = end of frame */
static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
{
unsigned char data[2];
@@ -906,7 +906,7 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):rx_ready_hdlc(eom=%d)\n",__FILE__,__LINE__,eom);
-
+
if (!info->rx_enabled)
return;
@@ -920,12 +920,12 @@ static void rx_ready_hdlc(MGSLPC_INFO *info, int eom)
}
if (eom) {
- /* end of frame, get FIFO count from RBCL register */
+ /* end of frame, get FIFO count from RBCL register */
if (!(fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f)))
fifo_count = 32;
} else
fifo_count = 32;
-
+
do {
if (fifo_count == 1) {
read_count = 1;
@@ -969,7 +969,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd)
struct mgsl_icount *icount = &info->icount;
if (tcd) {
- /* early termination, get FIFO count from RBCL register */
+ /* early termination, get FIFO count from RBCL register */
fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f);
/* Zero fifo count could mean 0 or 32 bytes available.
@@ -981,7 +981,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd)
fifo_count = 32;
tty_buffer_request_room(tty, fifo_count);
- /* Flush received async data to receive data buffer. */
+ /* Flush received async data to receive data buffer. */
while (fifo_count) {
data = read_reg(info, CHA + RXFIFO);
status = read_reg(info, CHA + RXFIFO);
@@ -995,7 +995,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd)
// BIT6:framing error
if (status & (BIT7 + BIT6)) {
- if (status & BIT7)
+ if (status & BIT7)
icount->parity++;
else
icount->frame++;
@@ -1003,7 +1003,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd)
/* discard char if tty control flags say so */
if (status & info->ignore_status_mask)
continue;
-
+
status &= info->read_status_mask;
if (status & BIT7)
@@ -1022,7 +1022,7 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd)
__FILE__,__LINE__,icount->rx,icount->brk,
icount->parity,icount->frame,icount->overrun);
}
-
+
if (work)
tty_flip_buffer_push(tty);
}
@@ -1032,7 +1032,7 @@ static void tx_done(MGSLPC_INFO *info)
{
if (!info->tx_active)
return;
-
+
info->tx_active = 0;
info->tx_aborting = 0;
@@ -1040,8 +1040,8 @@ static void tx_done(MGSLPC_INFO *info)
return;
info->tx_count = info->tx_put = info->tx_get = 0;
- del_timer(&info->tx_timer);
-
+ del_timer(&info->tx_timer);
+
if (info->drop_rts_on_tx_done) {
get_signals(info);
if (info->serial_signals & SerialSignal_RTS) {
@@ -1054,7 +1054,7 @@ static void tx_done(MGSLPC_INFO *info)
#if SYNCLINK_GENERIC_HDLC
if (info->netcount)
hdlcdev_tx_done(info);
- else
+ else
#endif
{
if (info->tty->stopped || info->tty->hw_stopped) {
@@ -1090,7 +1090,7 @@ static void tx_ready(MGSLPC_INFO *info)
while (info->tx_count && fifo_count) {
c = min(2, min_t(int, fifo_count, min(info->tx_count, TXBUFSIZE - info->tx_get)));
-
+
if (c == 1) {
write_reg(info, CHA + TXFIFO, *(info->tx_buf + info->tx_get));
} else {
@@ -1220,9 +1220,9 @@ static void ri_change(MGSLPC_INFO *info)
}
/* Interrupt service routine entry point.
- *
+ *
* Arguments:
- *
+ *
* irq interrupt number that caused interrupt
* dev_id device ID supplied during interrupt registration
*/
@@ -1233,18 +1233,18 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id)
unsigned char gis, pis;
int count=0;
- if (debug_level >= DEBUG_LEVEL_ISR)
+ if (debug_level >= DEBUG_LEVEL_ISR)
printk("mgslpc_isr(%d) entry.\n", irq);
if (!info)
return IRQ_NONE;
-
+
if (!(info->p_dev->_locked))
return IRQ_HANDLED;
spin_lock(&info->lock);
while ((gis = read_reg(info, CHA + GIS))) {
- if (debug_level >= DEBUG_LEVEL_ISR)
+ if (debug_level >= DEBUG_LEVEL_ISR)
printk("mgslpc_isr %s gis=%04X\n", info->device_name,gis);
if ((gis & 0x70) || count > 1000) {
@@ -1268,7 +1268,7 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id)
irq_disable(info, CHA, IRQ_TIMER);
}
- /* receive IRQs */
+ /* receive IRQs */
if (isr & IRQ_EXITHUNT) {
info->icount.exithunt++;
wake_up_interruptible(&info->event_wait_q);
@@ -1283,12 +1283,12 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id)
}
if (isr & (IRQ_RXEOM + IRQ_RXFIFO)) {
if (info->params.mode == MGSL_MODE_HDLC)
- rx_ready_hdlc(info, isr & IRQ_RXEOM);
+ rx_ready_hdlc(info, isr & IRQ_RXEOM);
else
rx_ready_async(info, isr & IRQ_RXEOM);
}
- /* transmit IRQs */
+ /* transmit IRQs */
if (isr & IRQ_UNDERRUN) {
if (info->tx_aborting)
info->icount.txabort++;
@@ -1311,13 +1311,13 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id)
ri_change(info);
}
}
-
- /* Request bottom half processing if there's something
+
+ /* Request bottom half processing if there's something
* for it to do and the bh is not already running
*/
if (info->pending_bh && !info->bh_running && !info->bh_requested) {
- if ( debug_level >= DEBUG_LEVEL_ISR )
+ if ( debug_level >= DEBUG_LEVEL_ISR )
printk("%s(%d):%s queueing bh task.\n",
__FILE__,__LINE__,info->device_name);
schedule_work(&info->task);
@@ -1325,8 +1325,8 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id)
}
spin_unlock(&info->lock);
-
- if (debug_level >= DEBUG_LEVEL_ISR)
+
+ if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):mgslpc_isr(%d)exit.\n",
__FILE__,__LINE__,irq);
@@ -1338,13 +1338,13 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id)
static int startup(MGSLPC_INFO * info)
{
int retval = 0;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):startup(%s)\n",__FILE__,__LINE__,info->device_name);
-
+
if (info->flags & ASYNC_INITIALIZED)
return 0;
-
+
if (!info->tx_buf) {
/* allocate a page of memory for a transmit buffer */
info->tx_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
@@ -1356,18 +1356,18 @@ static int startup(MGSLPC_INFO * info)
}
info->pending_bh = 0;
-
+
memset(&info->icount, 0, sizeof(info->icount));
setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info);
/* Allocate and claim adapter resources */
retval = claim_resources(info);
-
+
/* perform existance check and diagnostics */
if ( !retval )
retval = adapter_test(info);
-
+
if ( retval ) {
if (capable(CAP_SYS_ADMIN) && info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -1377,12 +1377,12 @@ static int startup(MGSLPC_INFO * info)
/* program hardware for current parameters */
mgslpc_change_params(info);
-
+
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
info->flags |= ASYNC_INITIALIZED;
-
+
return 0;
}
@@ -1391,7 +1391,7 @@ static int startup(MGSLPC_INFO * info)
static void shutdown(MGSLPC_INFO * info)
{
unsigned long flags;
-
+
if (!(info->flags & ASYNC_INITIALIZED))
return;
@@ -1418,16 +1418,16 @@ static void shutdown(MGSLPC_INFO * info)
/* TODO:disable interrupts instead of reset to preserve signal states */
reset_device(info);
-
+
if (!info->tty || info->tty->termios->c_cflag & HUPCL) {
info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
set_signals(info);
}
-
+
spin_unlock_irqrestore(&info->lock,flags);
- release_resources(info);
-
+ release_resources(info);
+
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -1439,18 +1439,18 @@ static void mgslpc_program_hw(MGSLPC_INFO *info)
unsigned long flags;
spin_lock_irqsave(&info->lock,flags);
-
+
rx_stop(info);
tx_stop(info);
info->tx_count = info->tx_put = info->tx_get = 0;
-
+
if (info->params.mode == MGSL_MODE_HDLC || info->netcount)
hdlc_mode(info);
else
async_mode(info);
-
+
set_signals(info);
-
+
info->dcd_chkcount = 0;
info->cts_chkcount = 0;
info->ri_chkcount = 0;
@@ -1459,10 +1459,10 @@ static void mgslpc_program_hw(MGSLPC_INFO *info)
irq_enable(info, CHB, IRQ_DCD | IRQ_CTS);
port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI);
get_signals(info);
-
+
if (info->netcount || info->tty->termios->c_cflag & CREAD)
rx_start(info);
-
+
spin_unlock_irqrestore(&info->lock,flags);
}
@@ -1475,11 +1475,11 @@ static void mgslpc_change_params(MGSLPC_INFO *info)
if (!info->tty || !info->tty->termios)
return;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_change_params(%s)\n",
__FILE__,__LINE__, info->device_name );
-
+
cflag = info->tty->termios->c_cflag;
/* if B0 rate (hangup) specified then negate DTR and RTS */
@@ -1488,9 +1488,9 @@ static void mgslpc_change_params(MGSLPC_INFO *info)
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
else
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
-
+
/* byte size and parity */
-
+
switch (cflag & CSIZE) {
case CS5: info->params.data_bits = 5; break;
case CS6: info->params.data_bits = 6; break;
@@ -1498,7 +1498,7 @@ static void mgslpc_change_params(MGSLPC_INFO *info)
case CS8: info->params.data_bits = 8; break;
default: info->params.data_bits = 7; break;
}
-
+
if (cflag & CSTOPB)
info->params.stop_bits = 2;
else
@@ -1519,7 +1519,7 @@ static void mgslpc_change_params(MGSLPC_INFO *info)
/* calculate number of jiffies to transmit a full
* FIFO (32 bytes) at specified data rate
*/
- bits_per_char = info->params.data_bits +
+ bits_per_char = info->params.data_bits +
info->params.stop_bits + 1;
/* if port data rate is set to 460800 or less then
@@ -1529,9 +1529,9 @@ static void mgslpc_change_params(MGSLPC_INFO *info)
if (info->params.data_rate <= 460800) {
info->params.data_rate = tty_get_baud_rate(info->tty);
}
-
+
if ( info->params.data_rate ) {
- info->timeout = (32*HZ*bits_per_char) /
+ info->timeout = (32*HZ*bits_per_char) /
info->params.data_rate;
}
info->timeout += HZ/50; /* Add .02 seconds of slop */
@@ -1540,14 +1540,14 @@ static void mgslpc_change_params(MGSLPC_INFO *info)
info->flags |= ASYNC_CTS_FLOW;
else
info->flags &= ~ASYNC_CTS_FLOW;
-
+
if (cflag & CLOCAL)
info->flags &= ~ASYNC_CHECK_CD;
else
info->flags |= ASYNC_CHECK_CD;
/* process tty input control flags */
-
+
info->read_status_mask = 0;
if (I_INPCK(info->tty))
info->read_status_mask |= BIT7 | BIT6;
@@ -1576,7 +1576,7 @@ static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
return;
spin_lock_irqsave(&info->lock,flags);
-
+
if (info->params.mode == MGSL_MODE_ASYNC || !info->tx_active) {
if (info->tx_count < TXBUFSIZE - 1) {
info->tx_buf[info->tx_put++] = ch;
@@ -1584,7 +1584,7 @@ static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
info->tx_count++;
}
}
-
+
spin_unlock_irqrestore(&info->lock,flags);
}
@@ -1595,11 +1595,11 @@ static void mgslpc_flush_chars(struct tty_struct *tty)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk( "%s(%d):mgslpc_flush_chars() entry on %s tx_count=%d\n",
__FILE__,__LINE__,info->device_name,info->tx_count);
-
+
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_chars"))
return;
@@ -1618,13 +1618,13 @@ static void mgslpc_flush_chars(struct tty_struct *tty)
}
/* Send a block of data
- *
+ *
* Arguments:
- *
+ *
* tty pointer to tty information structure
* buf pointer to buffer containing send data
* count size of send data in bytes
- *
+ *
* Returns: number of characters written
*/
static int mgslpc_write(struct tty_struct * tty,
@@ -1633,11 +1633,11 @@ static int mgslpc_write(struct tty_struct * tty,
int c, ret = 0;
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk( "%s(%d):mgslpc_write(%s) count=%d\n",
__FILE__,__LINE__,info->device_name,count);
-
+
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") ||
!info->tx_buf)
goto cleanup;
@@ -1659,7 +1659,7 @@ static int mgslpc_write(struct tty_struct * tty,
TXBUFSIZE - info->tx_put));
if (c <= 0)
break;
-
+
memcpy(info->tx_buf + info->tx_put, buf, c);
spin_lock_irqsave(&info->lock,flags);
@@ -1678,7 +1678,7 @@ start:
tx_start(info);
spin_unlock_irqrestore(&info->lock,flags);
}
-cleanup:
+cleanup:
if (debug_level >= DEBUG_LEVEL_INFO)
printk( "%s(%d):mgslpc_write(%s) returning=%d\n",
__FILE__,__LINE__,info->device_name,ret);
@@ -1691,7 +1691,7 @@ static int mgslpc_write_room(struct tty_struct *tty)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
int ret;
-
+
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write_room"))
return 0;
@@ -1706,7 +1706,7 @@ static int mgslpc_write_room(struct tty_struct *tty)
if (ret < 0)
ret = 0;
}
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_write_room(%s)=%d\n",
__FILE__,__LINE__, info->device_name, ret);
@@ -1719,14 +1719,14 @@ static int mgslpc_chars_in_buffer(struct tty_struct *tty)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
int rc;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_chars_in_buffer(%s)\n",
__FILE__,__LINE__, info->device_name );
-
+
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_chars_in_buffer"))
return 0;
-
+
if (info->params.mode == MGSL_MODE_HDLC)
rc = info->tx_active ? info->max_frame_size : 0;
else
@@ -1735,7 +1735,7 @@ static int mgslpc_chars_in_buffer(struct tty_struct *tty)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_chars_in_buffer(%s)=%d\n",
__FILE__,__LINE__, info->device_name, rc);
-
+
return rc;
}
@@ -1745,17 +1745,17 @@ static void mgslpc_flush_buffer(struct tty_struct *tty)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_flush_buffer(%s) entry\n",
__FILE__,__LINE__, info->device_name );
-
+
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_buffer"))
return;
-
- spin_lock_irqsave(&info->lock,flags);
+
+ spin_lock_irqsave(&info->lock,flags);
info->tx_count = info->tx_put = info->tx_get = 0;
- del_timer(&info->tx_timer);
+ del_timer(&info->tx_timer);
spin_unlock_irqrestore(&info->lock,flags);
wake_up_interruptible(&tty->write_wait);
@@ -1772,7 +1772,7 @@ static void mgslpc_send_xchar(struct tty_struct *tty, char ch)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_send_xchar(%s,%d)\n",
__FILE__,__LINE__, info->device_name, ch );
-
+
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_send_xchar"))
return;
@@ -1791,17 +1791,17 @@ static void mgslpc_throttle(struct tty_struct * tty)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_throttle(%s) entry\n",
__FILE__,__LINE__, info->device_name );
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_throttle"))
return;
-
+
if (I_IXOFF(tty))
mgslpc_send_xchar(tty, STOP_CHAR(tty));
-
+
if (tty->termios->c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals &= ~SerialSignal_RTS;
@@ -1816,21 +1816,21 @@ static void mgslpc_unthrottle(struct tty_struct * tty)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_unthrottle(%s) entry\n",
__FILE__,__LINE__, info->device_name );
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_unthrottle"))
return;
-
+
if (I_IXOFF(tty)) {
if (info->x_char)
info->x_char = 0;
else
mgslpc_send_xchar(tty, START_CHAR(tty));
}
-
+
if (tty->termios->c_cflag & CRTSCTS) {
spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS;
@@ -1870,9 +1870,9 @@ static int get_params(MGSLPC_INFO * info, MGSL_PARAMS __user *user_params)
}
/* set the serial parameters
- *
+ *
* Arguments:
- *
+ *
* info pointer to device instance data
* new_params user buffer containing new serial params
*
@@ -1883,7 +1883,7 @@ static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params)
unsigned long flags;
MGSL_PARAMS tmp_params;
int err;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):set_params %s\n", __FILE__,__LINE__,
info->device_name );
@@ -1894,13 +1894,13 @@ static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params)
__FILE__,__LINE__,info->device_name);
return -EFAULT;
}
-
+
spin_lock_irqsave(&info->lock,flags);
memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS));
spin_unlock_irqrestore(&info->lock,flags);
-
+
mgslpc_change_params(info);
-
+
return 0;
}
@@ -1963,10 +1963,10 @@ static int set_interface(MGSLPC_INFO * info, int if_mode)
static int set_txenable(MGSLPC_INFO * info, int enable)
{
unsigned long flags;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("set_txenable(%s,%d)\n", info->device_name, enable);
-
+
spin_lock_irqsave(&info->lock,flags);
if (enable) {
if (!info->tx_enabled)
@@ -1982,10 +1982,10 @@ static int set_txenable(MGSLPC_INFO * info, int enable)
static int tx_abort(MGSLPC_INFO * info)
{
unsigned long flags;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("tx_abort(%s)\n", info->device_name);
-
+
spin_lock_irqsave(&info->lock,flags);
if (info->tx_active && info->tx_count &&
info->params.mode == MGSL_MODE_HDLC) {
@@ -2002,10 +2002,10 @@ static int tx_abort(MGSLPC_INFO * info)
static int set_rxenable(MGSLPC_INFO * info, int enable)
{
unsigned long flags;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("set_rxenable(%s,%d)\n", info->device_name, enable);
-
+
spin_lock_irqsave(&info->lock,flags);
if (enable) {
if (!info->rx_enabled)
@@ -2019,7 +2019,7 @@ static int set_rxenable(MGSLPC_INFO * info, int enable)
}
/* wait for specified event to occur
- *
+ *
* Arguments: info pointer to device instance data
* mask pointer to bitmask of events to wait for
* Return Value: 0 if successful and bit mask updated with
@@ -2040,7 +2040,7 @@ static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr)
COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int));
if (rc)
return -EFAULT;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("wait_events(%s,%d)\n", info->device_name, mask);
@@ -2062,24 +2062,24 @@ static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr)
/* save current irq counts */
cprev = info->icount;
oldsigs = info->input_signal_events;
-
+
if ((info->params.mode == MGSL_MODE_HDLC) &&
(mask & MgslEvent_ExitHuntMode))
irq_enable(info, CHA, IRQ_EXITHUNT);
-
+
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&info->event_wait_q, &wait);
-
+
spin_unlock_irqrestore(&info->lock,flags);
-
-
+
+
for(;;) {
schedule();
if (signal_pending(current)) {
rc = -ERESTARTSYS;
break;
}
-
+
/* get current irq counts */
spin_lock_irqsave(&info->lock,flags);
cnow = info->icount;
@@ -2115,11 +2115,11 @@ static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr)
(cnow.rxidle != cprev.rxidle ? MgslEvent_IdleReceived:0) );
if (events)
break;
-
+
cprev = cnow;
oldsigs = newsigs;
}
-
+
remove_wait_queue(&info->event_wait_q, &wait);
set_current_state(TASK_RUNNING);
@@ -2247,42 +2247,42 @@ static void mgslpc_break(struct tty_struct *tty, int break_state)
{
MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_break(%s,%d)\n",
__FILE__,__LINE__, info->device_name, break_state);
-
+
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_break"))
return;
spin_lock_irqsave(&info->lock,flags);
if (break_state == -1)
set_reg_bits(info, CHA+DAFO, BIT6);
- else
+ else
clear_reg_bits(info, CHA+DAFO, BIT6);
spin_unlock_irqrestore(&info->lock,flags);
}
/* Service an IOCTL request
- *
+ *
* Arguments:
- *
+ *
* tty pointer to tty instance data
* file pointer to associated file object for device
* cmd IOCTL command code
* arg command argument/context
- *
+ *
* Return Value: 0 if success, otherwise error code
*/
static int mgslpc_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
info->device_name, cmd );
-
+
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_ioctl"))
return -ENODEV;
@@ -2302,7 +2302,7 @@ static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg)
struct serial_icounter_struct __user *p_cuser; /* user space */
void __user *argp = (void __user *)arg;
unsigned long flags;
-
+
switch (cmd) {
case MGSL_IOCGPARAMS:
return get_params(info, argp);
@@ -2363,9 +2363,9 @@ static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg)
}
/* Set new termios settings
- *
+ *
* Arguments:
- *
+ *
* tty pointer to tty structure
* termios pointer to buffer to hold returned old termios
*/
@@ -2373,14 +2373,14 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_set_termios %s\n", __FILE__,__LINE__,
tty->driver->name );
-
+
/* just return if nothing has changed */
if ((tty->termios->c_cflag == old_termios->c_cflag)
- && (RELEVANT_IFLAG(tty->termios->c_iflag)
+ && (RELEVANT_IFLAG(tty->termios->c_iflag)
== RELEVANT_IFLAG(old_termios->c_iflag)))
return;
@@ -2394,12 +2394,12 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
-
+
/* Handle transition away from B0 status */
if (!(old_termios->c_cflag & CBAUD) &&
tty->termios->c_cflag & CBAUD) {
info->serial_signals |= SerialSignal_DTR;
- if (!(tty->termios->c_cflag & CRTSCTS) ||
+ if (!(tty->termios->c_cflag & CRTSCTS) ||
!test_bit(TTY_THROTTLED, &tty->flags)) {
info->serial_signals |= SerialSignal_RTS;
}
@@ -2407,7 +2407,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
-
+
/* Handle turning off CRTSCTS */
if (old_termios->c_cflag & CRTSCTS &&
!(tty->termios->c_cflag & CRTSCTS)) {
@@ -2422,17 +2422,17 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp)
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_close"))
return;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_close(%s) entry, count=%d\n",
__FILE__,__LINE__, info->device_name, info->count);
-
+
if (!info->count)
return;
if (tty_hung_up_p(filp))
goto cleanup;
-
+
if ((tty->count == 1) && (info->count != 1)) {
/*
* tty->count is 1 and the tty structure will be freed.
@@ -2443,30 +2443,30 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp)
"info->count is %d\n", info->count);
info->count = 1;
}
-
+
info->count--;
-
+
/* if at least one open remaining, leave hardware active */
if (info->count)
goto cleanup;
-
+
info->flags |= ASYNC_CLOSING;
-
- /* set tty->closing to notify line discipline to
+
+ /* set tty->closing to notify line discipline to
* only process XON/XOFF characters. Only the N_TTY
* discipline appears to use this (ppp does not).
*/
tty->closing = 1;
-
+
/* wait for transmit data to clear all layers */
-
+
if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) {
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_close(%s) calling tty_wait_until_sent\n",
__FILE__,__LINE__, info->device_name );
tty_wait_until_sent(tty, info->closing_wait);
}
-
+
if (info->flags & ASYNC_INITIALIZED)
mgslpc_wait_until_sent(tty, info->timeout);
@@ -2474,24 +2474,24 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp)
tty->driver->flush_buffer(tty);
ldisc_flush_buffer(tty);
-
+
shutdown(info);
-
+
tty->closing = 0;
info->tty = NULL;
-
+
if (info->blocked_open) {
if (info->close_delay) {
msleep_interruptible(jiffies_to_msecs(info->close_delay));
}
wake_up_interruptible(&info->open_wait);
}
-
+
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-
+
wake_up_interruptible(&info->close_wait);
-
-cleanup:
+
+cleanup:
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_close(%s) exit, count=%d\n", __FILE__,__LINE__,
tty->driver->name, info->count);
@@ -2510,31 +2510,31 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_wait_until_sent(%s) entry\n",
__FILE__,__LINE__, info->device_name );
-
+
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_wait_until_sent"))
return;
if (!(info->flags & ASYNC_INITIALIZED))
goto exit;
-
+
orig_jiffies = jiffies;
-
+
/* Set check interval to 1/5 of estimated time to
* send a character, and make it at least 1. The check
* interval should also be less than the timeout.
* Note: use tight timings here to satisfy the NIST-PCTS.
- */
-
+ */
+
if ( info->params.data_rate ) {
char_time = info->timeout/(32 * 5);
if (!char_time)
char_time++;
} else
char_time = 1;
-
+
if (timeout)
char_time = min_t(unsigned long, char_time, timeout);
-
+
if (info->params.mode == MGSL_MODE_HDLC) {
while (info->tx_active) {
msleep_interruptible(jiffies_to_msecs(char_time));
@@ -2553,7 +2553,7 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout)
break;
}
}
-
+
exit:
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_wait_until_sent(%s) exit\n",
@@ -2566,18 +2566,18 @@ exit:
static void mgslpc_hangup(struct tty_struct *tty)
{
MGSLPC_INFO * info = (MGSLPC_INFO *)tty->driver_data;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_hangup(%s)\n",
__FILE__,__LINE__, info->device_name );
-
+
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_hangup"))
return;
mgslpc_flush_buffer(tty);
shutdown(info);
-
- info->count = 0;
+
+ info->count = 0;
info->flags &= ~ASYNC_NORMAL_ACTIVE;
info->tty = NULL;
@@ -2594,7 +2594,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
int retval;
int do_clocal = 0, extra_count = 0;
unsigned long flags;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready on %s\n",
__FILE__,__LINE__, tty->driver->name );
@@ -2615,10 +2615,10 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
* mgslpc_close() knows when to free things. We restore it upon
* exit, either normal or abnormal.
*/
-
+
retval = 0;
add_wait_queue(&info->open_wait, &wait);
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready before block on %s count=%d\n",
__FILE__,__LINE__, tty->driver->name, info->count );
@@ -2630,7 +2630,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
}
spin_unlock_irqrestore(&info->lock, flags);
info->blocked_open++;
-
+
while (1) {
if ((tty->termios->c_cflag & CBAUD)) {
spin_lock_irqsave(&info->lock,flags);
@@ -2638,50 +2638,50 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
-
+
set_current_state(TASK_INTERRUPTIBLE);
-
+
if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)){
retval = (info->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS;
break;
}
-
+
spin_lock_irqsave(&info->lock,flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
-
+
if (!(info->flags & ASYNC_CLOSING) &&
(do_clocal || (info->serial_signals & SerialSignal_DCD)) ) {
break;
}
-
+
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready blocking on %s count=%d\n",
__FILE__,__LINE__, tty->driver->name, info->count );
-
+
schedule();
}
-
+
set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
-
+
if (extra_count)
info->count++;
info->blocked_open--;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):block_til_ready after blocking on %s count=%d\n",
__FILE__,__LINE__, tty->driver->name, info->count );
-
+
if (!retval)
info->flags |= ASYNC_NORMAL_ACTIVE;
-
+
return retval;
}
@@ -2691,7 +2691,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
int retval, line;
unsigned long flags;
- /* verify range of specified line number */
+ /* verify range of specified line number */
line = tty->index;
if ((line < 0) || (line >= mgslpc_device_count)) {
printk("%s(%d):mgslpc_open with invalid line #%d.\n",
@@ -2705,10 +2705,10 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
info = info->next_device;
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_open"))
return -ENODEV;
-
+
tty->driver_data = info;
info->tty = tty;
-
+
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_open(%s), old ref count = %d\n",
__FILE__,__LINE__,tty->driver->name, info->count);
@@ -2721,7 +2721,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
-EAGAIN : -ERESTARTSYS);
goto cleanup;
}
-
+
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
spin_lock_irqsave(&info->netlock, flags);
@@ -2752,15 +2752,15 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
printk("%s(%d):mgslpc_open(%s) success\n",
__FILE__,__LINE__, info->device_name);
retval = 0;
-
-cleanup:
+
+cleanup:
if (retval) {
if (tty->count == 1)
info->tty = NULL; /* tty layer will release tty struct */
if(info->count)
info->count--;
}
-
+
return retval;
}
@@ -2781,7 +2781,7 @@ static inline int line_info(char *buf, MGSLPC_INFO *info)
spin_lock_irqsave(&info->lock,flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
-
+
stat_buf[0] = 0;
stat_buf[1] = 0;
if (info->serial_signals & SerialSignal_RTS)
@@ -2805,7 +2805,7 @@ static inline int line_info(char *buf, MGSLPC_INFO *info)
if (info->icount.txabort)
ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);
if (info->icount.rxshort)
- ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
+ ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);
if (info->icount.rxlong)
ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);
if (info->icount.rxover)
@@ -2820,18 +2820,18 @@ static inline int line_info(char *buf, MGSLPC_INFO *info)
if (info->icount.parity)
ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
if (info->icount.brk)
- ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
+ ret += sprintf(buf+ret, " brk:%d", info->icount.brk);
if (info->icount.overrun)
ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
}
-
+
/* Append serial signal status to end */
ret += sprintf(buf+ret, " %s\n", stat_buf+1);
-
+
ret += sprintf(buf+ret, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n",
info->tx_active,info->bh_requested,info->bh_running,
info->pending_bh);
-
+
return ret;
}
@@ -2843,9 +2843,9 @@ static int mgslpc_read_proc(char *page, char **start, off_t off, int count,
int len = 0, l;
off_t begin = 0;
MGSLPC_INFO *info;
-
+
len += sprintf(page, "synclink driver:%s\n", driver_version);
-
+
info = mgslpc_device_list;
while( info ) {
l = line_info(page + len, info);
@@ -2902,7 +2902,7 @@ static int claim_resources(MGSLPC_INFO *info)
printk( "Cant allocate rx buffer %s\n", info->device_name);
release_resources(info);
return -ENODEV;
- }
+ }
return 0;
}
@@ -2915,7 +2915,7 @@ static void release_resources(MGSLPC_INFO *info)
/* Add the specified device instance data structure to the
* global linked list of devices and increment the device count.
- *
+ *
* Arguments: info pointer to device instance data
*/
static void mgslpc_add_device(MGSLPC_INFO *info)
@@ -2923,7 +2923,7 @@ static void mgslpc_add_device(MGSLPC_INFO *info)
info->next_device = NULL;
info->line = mgslpc_device_count;
sprintf(info->device_name,"ttySLP%d",info->line);
-
+
if (info->line < MAX_DEVICE_COUNT) {
if (maxframe[info->line])
info->max_frame_size = maxframe[info->line];
@@ -2931,21 +2931,21 @@ static void mgslpc_add_device(MGSLPC_INFO *info)
}
mgslpc_device_count++;
-
+
if (!mgslpc_device_list)
mgslpc_device_list = info;
- else {
+ else {
MGSLPC_INFO *current_dev = mgslpc_device_list;
while( current_dev->next_device )
current_dev = current_dev->next_device;
current_dev->next_device = info;
}
-
+
if (info->max_frame_size < 4096)
info->max_frame_size = 4096;
else if (info->max_frame_size > 65535)
info->max_frame_size = 65535;
-
+
printk( "SyncLink PC Card %s:IO=%04X IRQ=%d\n",
info->device_name, info->io_base, info->irq_level);
@@ -3060,7 +3060,7 @@ static int __init synclink_cs_init(void)
}
/* Initialize the tty_driver structure */
-
+
serial_driver->owner = THIS_MODULE;
serial_driver->driver_name = "synclink_cs";
serial_driver->name = "ttySLP";
@@ -3081,11 +3081,11 @@ static int __init synclink_cs_init(void)
serial_driver = NULL;
goto error;
}
-
+
printk("%s %s, tty major#%d\n",
driver_name, driver_version,
serial_driver->major);
-
+
return 0;
error:
@@ -3093,7 +3093,7 @@ error:
return rc;
}
-static void __exit synclink_cs_exit(void)
+static void __exit synclink_cs_exit(void)
{
synclink_cs_cleanup();
}
@@ -3106,8 +3106,8 @@ static void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned i
unsigned int M, N;
unsigned char val;
- /* note:standard BRG mode is broken in V3.2 chip
- * so enhanced mode is always used
+ /* note:standard BRG mode is broken in V3.2 chip
+ * so enhanced mode is always used
*/
if (rate) {
@@ -3126,7 +3126,7 @@ static void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned i
* divisor = (N+1)*2^M
*
* Note: M *must* not be zero (causes asymetric duty cycle)
- */
+ */
write_reg(info, (unsigned char) (channel + BGR),
(unsigned char) ((M << 6) + N));
val = read_reg(info, (unsigned char) (channel + CCR2)) & 0x3f;
@@ -3140,7 +3140,7 @@ static void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned i
static void enable_auxclk(MGSLPC_INFO *info)
{
unsigned char val;
-
+
/* MODE
*
* 07..06 MDS[1..0] 10 = transparent HDLC mode
@@ -3152,14 +3152,14 @@ static void enable_auxclk(MGSLPC_INFO *info)
* 00 TLP Test Loop, 0 = no loop
*
* 1000 0010
- */
+ */
val = 0x82;
-
- /* channel B RTS is used to enable AUXCLK driver on SP505 */
+
+ /* channel B RTS is used to enable AUXCLK driver on SP505 */
if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed)
val |= BIT2;
write_reg(info, CHB + MODE, val);
-
+
/* CCR0
*
* 07 PU Power Up, 1=active, 0=power down
@@ -3169,9 +3169,9 @@ static void enable_auxclk(MGSLPC_INFO *info)
* 01..00 SM[1..0] Serial Mode, 00=HDLC
*
* 11000000
- */
+ */
write_reg(info, CHB + CCR0, 0xc0);
-
+
/* CCR1
*
* 07 SFLG Shared Flag, 0 = disable shared flags
@@ -3182,9 +3182,9 @@ static void enable_auxclk(MGSLPC_INFO *info)
* 02..00 CM[2..0] Clock Mode
*
* 0001 0111
- */
+ */
write_reg(info, CHB + CCR1, 0x17);
-
+
/* CCR2 (Channel B)
*
* 07..06 BGR[9..8] Baud rate bits 9..8
@@ -3196,12 +3196,12 @@ static void enable_auxclk(MGSLPC_INFO *info)
* 00 DIV, data inversion 0=disabled, 1=enabled
*
* 0011 1000
- */
+ */
if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed)
write_reg(info, CHB + CCR2, 0x38);
else
write_reg(info, CHB + CCR2, 0x30);
-
+
/* CCR4
*
* 07 MCK4 Master Clock Divide by 4, 1=enabled
@@ -3212,37 +3212,37 @@ static void enable_auxclk(MGSLPC_INFO *info)
* 01..00 RFT[1..0] RxFIFO Threshold 00=32 bytes
*
* 0101 0000
- */
+ */
write_reg(info, CHB + CCR4, 0x50);
-
+
/* if auxclk not enabled, set internal BRG so
* CTS transitions can be detected (requires TxC)
- */
+ */
if (info->params.mode == MGSL_MODE_HDLC && info->params.clock_speed)
mgslpc_set_rate(info, CHB, info->params.clock_speed);
else
mgslpc_set_rate(info, CHB, 921600);
}
-static void loopback_enable(MGSLPC_INFO *info)
+static void loopback_enable(MGSLPC_INFO *info)
{
unsigned char val;
-
- /* CCR1:02..00 CM[2..0] Clock Mode = 111 (clock mode 7) */
+
+ /* CCR1:02..00 CM[2..0] Clock Mode = 111 (clock mode 7) */
val = read_reg(info, CHA + CCR1) | (BIT2 + BIT1 + BIT0);
write_reg(info, CHA + CCR1, val);
-
- /* CCR2:04 SSEL Clock source select, 1=submode b */
+
+ /* CCR2:04 SSEL Clock source select, 1=submode b */
val = read_reg(info, CHA + CCR2) | (BIT4 + BIT5);
write_reg(info, CHA + CCR2, val);
-
- /* set LinkSpeed if available, otherwise default to 2Mbps */
+
+ /* set LinkSpeed if available, otherwise default to 2Mbps */
if (info->params.clock_speed)
mgslpc_set_rate(info, CHA, info->params.clock_speed);
else
mgslpc_set_rate(info, CHA, 1843200);
-
- /* MODE:00 TLP Test Loop, 1=loopback enabled */
+
+ /* MODE:00 TLP Test Loop, 1=loopback enabled */
val = read_reg(info, CHA + MODE) | BIT0;
write_reg(info, CHA + MODE, val);
}
@@ -3252,36 +3252,36 @@ static void hdlc_mode(MGSLPC_INFO *info)
unsigned char val;
unsigned char clkmode, clksubmode;
- /* disable all interrupts */
+ /* disable all interrupts */
irq_disable(info, CHA, 0xffff);
irq_disable(info, CHB, 0xffff);
port_irq_disable(info, 0xff);
-
- /* assume clock mode 0a, rcv=RxC xmt=TxC */
+
+ /* assume clock mode 0a, rcv=RxC xmt=TxC */
clkmode = clksubmode = 0;
if (info->params.flags & HDLC_FLAG_RXC_DPLL
&& info->params.flags & HDLC_FLAG_TXC_DPLL) {
- /* clock mode 7a, rcv = DPLL, xmt = DPLL */
+ /* clock mode 7a, rcv = DPLL, xmt = DPLL */
clkmode = 7;
} else if (info->params.flags & HDLC_FLAG_RXC_BRG
&& info->params.flags & HDLC_FLAG_TXC_BRG) {
- /* clock mode 7b, rcv = BRG, xmt = BRG */
+ /* clock mode 7b, rcv = BRG, xmt = BRG */
clkmode = 7;
clksubmode = 1;
} else if (info->params.flags & HDLC_FLAG_RXC_DPLL) {
if (info->params.flags & HDLC_FLAG_TXC_BRG) {
- /* clock mode 6b, rcv = DPLL, xmt = BRG/16 */
+ /* clock mode 6b, rcv = DPLL, xmt = BRG/16 */
clkmode = 6;
clksubmode = 1;
} else {
- /* clock mode 6a, rcv = DPLL, xmt = TxC */
+ /* clock mode 6a, rcv = DPLL, xmt = TxC */
clkmode = 6;
}
} else if (info->params.flags & HDLC_FLAG_TXC_BRG) {
- /* clock mode 0b, rcv = RxC, xmt = BRG */
+ /* clock mode 0b, rcv = RxC, xmt = BRG */
clksubmode = 1;
}
-
+
/* MODE
*
* 07..06 MDS[1..0] 10 = transparent HDLC mode
@@ -3293,16 +3293,16 @@ static void hdlc_mode(MGSLPC_INFO *info)
* 00 TLP Test Loop, 0 = no loop
*
* 1000 0010
- */
+ */
val = 0x82;
if (info->params.loopback)
val |= BIT0;
-
- /* preserve RTS state */
+
+ /* preserve RTS state */
if (info->serial_signals & SerialSignal_RTS)
val |= BIT2;
write_reg(info, CHA + MODE, val);
-
+
/* CCR0
*
* 07 PU Power Up, 1=active, 0=power down
@@ -3312,7 +3312,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
* 01..00 SM[1..0] Serial Mode, 00=HDLC
*
* 11000000
- */
+ */
val = 0xc0;
switch (info->params.encoding)
{
@@ -3330,7 +3330,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
break; // Manchester
}
write_reg(info, CHA + CCR0, val);
-
+
/* CCR1
*
* 07 SFLG Shared Flag, 0 = disable shared flags
@@ -3341,10 +3341,10 @@ static void hdlc_mode(MGSLPC_INFO *info)
* 02..00 CM[2..0] Clock Mode
*
* 0001 0000
- */
+ */
val = 0x10 + clkmode;
write_reg(info, CHA + CCR1, val);
-
+
/* CCR2
*
* 07..06 BGR[9..8] Baud rate bits 9..8
@@ -3356,7 +3356,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
* 00 DIV, data inversion 0=disabled, 1=enabled
*
* 0000 0000
- */
+ */
val = 0x00;
if (clkmode == 2 || clkmode == 3 || clkmode == 6
|| clkmode == 7 || (clkmode == 0 && clksubmode == 1))
@@ -3368,7 +3368,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
if (info->params.encoding == HDLC_ENCODING_NRZB)
val |= BIT0;
write_reg(info, CHA + CCR2, val);
-
+
/* CCR3
*
* 07..06 PRE[1..0] Preamble count 00=1, 01=2, 10=4, 11=8
@@ -3380,7 +3380,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
* 00 PSD DPLL Phase Shift Disable
*
* 0000 0000
- */
+ */
val = 0x00;
if (info->params.crc_type == HDLC_CRC_NONE)
val |= BIT2 + BIT1;
@@ -3399,8 +3399,8 @@ static void hdlc_mode(MGSLPC_INFO *info)
break;
}
write_reg(info, CHA + CCR3, val);
-
- /* PRE - Preamble pattern */
+
+ /* PRE - Preamble pattern */
val = 0;
switch (info->params.preamble)
{
@@ -3410,7 +3410,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
case HDLC_PREAMBLE_PATTERN_ONES: val = 0xff; break;
}
write_reg(info, CHA + PRE, val);
-
+
/* CCR4
*
* 07 MCK4 Master Clock Divide by 4, 1=enabled
@@ -3421,21 +3421,21 @@ static void hdlc_mode(MGSLPC_INFO *info)
* 01..00 RFT[1..0] RxFIFO Threshold 00=32 bytes
*
* 0101 0000
- */
+ */
val = 0x50;
write_reg(info, CHA + CCR4, val);
if (info->params.flags & HDLC_FLAG_RXC_DPLL)
mgslpc_set_rate(info, CHA, info->params.clock_speed * 16);
else
mgslpc_set_rate(info, CHA, info->params.clock_speed);
-
+
/* RLCR Receive length check register
*
* 7 1=enable receive length check
* 6..0 Max frame length = (RL + 1) * 32
- */
+ */
write_reg(info, CHA + RLCR, 0);
-
+
/* XBCH Transmit Byte Count High
*
* 07 DMA mode, 0 = interrupt driven
@@ -3445,7 +3445,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
* 03..00 XBC[10..8] Transmit byte count bits 10..8
*
* 0000 0000
- */
+ */
val = 0x00;
if (info->params.flags & HDLC_FLAG_AUTO_DCD)
val |= BIT5;
@@ -3456,7 +3456,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
if (info->params.flags & HDLC_FLAG_AUTO_CTS)
{
irq_enable(info, CHB, IRQ_CTS);
- /* PVR[3] 1=AUTO CTS active */
+ /* PVR[3] 1=AUTO CTS active */
set_reg_bits(info, CHA + PVR, BIT3);
} else
clear_reg_bits(info, CHA + PVR, BIT3);
@@ -3467,7 +3467,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
issue_command(info, CHA, CMD_TXRESET + CMD_RXRESET);
wait_command_complete(info, CHA);
read_reg16(info, CHA + ISR); /* clear pending IRQs */
-
+
/* Master clock mode enabled above to allow reset commands
* to complete even if no data clocks are present.
*
@@ -3477,7 +3477,7 @@ static void hdlc_mode(MGSLPC_INFO *info)
*
* Leave master clock mode enabled for IRQ test because the
* timer IRQ used by the test can only happen in master clock mode.
- */
+ */
if (!info->testing_irq)
clear_reg_bits(info, CHA + CCR0, BIT6);
@@ -3492,8 +3492,8 @@ static void rx_stop(MGSLPC_INFO *info)
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):rx_stop(%s)\n",
__FILE__,__LINE__, info->device_name );
-
- /* MODE:03 RAC Receiver Active, 0=inactive */
+
+ /* MODE:03 RAC Receiver Active, 0=inactive */
clear_reg_bits(info, CHA + MODE, BIT3);
info->rx_enabled = 0;
@@ -3510,7 +3510,7 @@ static void rx_start(MGSLPC_INFO *info)
info->rx_enabled = 0;
info->rx_overflow = 0;
- /* MODE:03 RAC Receiver Active, 1=active */
+ /* MODE:03 RAC Receiver Active, 1=active */
set_reg_bits(info, CHA + MODE, BIT3);
info->rx_enabled = 1;
@@ -3521,7 +3521,7 @@ static void tx_start(MGSLPC_INFO *info)
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):tx_start(%s)\n",
__FILE__,__LINE__, info->device_name );
-
+
if (info->tx_count) {
/* If auto RTS enabled and RTS is inactive, then assert */
/* RTS and set a flag indicating that the driver should */
@@ -3559,8 +3559,8 @@ static void tx_stop(MGSLPC_INFO *info)
if (debug_level >= DEBUG_LEVEL_ISR)
printk("%s(%d):tx_stop(%s)\n",
__FILE__,__LINE__, info->device_name );
-
- del_timer(&info->tx_timer);
+
+ del_timer(&info->tx_timer);
info->tx_enabled = 0;
info->tx_active = 0;
@@ -3570,17 +3570,17 @@ static void tx_stop(MGSLPC_INFO *info)
*/
static void reset_device(MGSLPC_INFO *info)
{
- /* power up both channels (set BIT7) */
+ /* power up both channels (set BIT7) */
write_reg(info, CHA + CCR0, 0x80);
write_reg(info, CHB + CCR0, 0x80);
write_reg(info, CHA + MODE, 0);
write_reg(info, CHB + MODE, 0);
-
- /* disable all interrupts */
+
+ /* disable all interrupts */
irq_disable(info, CHA, 0xffff);
irq_disable(info, CHB, 0xffff);
port_irq_disable(info, 0xff);
-
+
/* PCR Port Configuration Register
*
* 07..04 DEC[3..0] Serial I/F select outputs
@@ -3590,9 +3590,9 @@ static void reset_device(MGSLPC_INFO *info)
* 00 DTR output 0=active
*
* 0000 0110
- */
+ */
write_reg(info, PCR, 0x06);
-
+
/* PVR Port Value Register
*
* 07..04 DEC[3..0] Serial I/F select (0000=disabled)
@@ -3604,7 +3604,7 @@ static void reset_device(MGSLPC_INFO *info)
* 0000 0001
*/
// write_reg(info, PVR, PVR_DTR);
-
+
/* IPC Interrupt Port Configuration
*
* 07 VIS 1=Masked interrupts visible
@@ -3614,7 +3614,7 @@ static void reset_device(MGSLPC_INFO *info)
* 01..00 IC[1..0] Interrupt Config, 01=push-pull output, active low
*
* 0000 0101
- */
+ */
write_reg(info, IPC, 0x05);
}
@@ -3622,11 +3622,11 @@ static void async_mode(MGSLPC_INFO *info)
{
unsigned char val;
- /* disable all interrupts */
+ /* disable all interrupts */
irq_disable(info, CHA, 0xffff);
irq_disable(info, CHB, 0xffff);
port_irq_disable(info, 0xff);
-
+
/* MODE
*
* 07 Reserved, 0
@@ -3639,16 +3639,16 @@ static void async_mode(MGSLPC_INFO *info)
* 00 TLP Test Loop, 0 = no loop
*
* 0000 0110
- */
+ */
val = 0x06;
if (info->params.loopback)
val |= BIT0;
-
- /* preserve RTS state */
+
+ /* preserve RTS state */
if (!(info->serial_signals & SerialSignal_RTS))
val |= BIT6;
write_reg(info, CHA + MODE, val);
-
+
/* CCR0
*
* 07 PU Power Up, 1=active, 0=power down
@@ -3658,9 +3658,9 @@ static void async_mode(MGSLPC_INFO *info)
* 01..00 SM[1..0] Serial Mode, 11=Async
*
* 1000 0011
- */
+ */
write_reg(info, CHA + CCR0, 0x83);
-
+
/* CCR1
*
* 07..05 Reserved, 0
@@ -3669,9 +3669,9 @@ static void async_mode(MGSLPC_INFO *info)
* 02..00 CM[2..0] Clock Mode, 111=BRG
*
* 0001 1111
- */
+ */
write_reg(info, CHA + CCR1, 0x1f);
-
+
/* CCR2 (channel A)
*
* 07..06 BGR[9..8] Baud rate bits 9..8
@@ -3683,18 +3683,18 @@ static void async_mode(MGSLPC_INFO *info)
* 00 DIV, data inversion 0=disabled, 1=enabled
*
* 0001 0000
- */
+ */
write_reg(info, CHA + CCR2, 0x10);
-
+
/* CCR3
*
* 07..01 Reserved, 0
* 00 PSD DPLL Phase Shift Disable
*
* 0000 0000
- */
+ */
write_reg(info, CHA + CCR3, 0);
-
+
/* CCR4
*
* 07 MCK4 Master Clock Divide by 4, 1=enabled
@@ -3704,10 +3704,10 @@ static void async_mode(MGSLPC_INFO *info)
* 03..00 Reserved, must be 0
*
* 0101 0000
- */
+ */
write_reg(info, CHA + CCR4, 0x50);
mgslpc_set_rate(info, CHA, info->params.data_rate * 16);
-
+
/* DAFO Data Format
*
* 07 Reserved, 0
@@ -3717,7 +3717,7 @@ static void async_mode(MGSLPC_INFO *info)
* 02 PAREN Parity Enable
* 01..00 CHL[1..0] Character Length (00=8, 01=7)
*
- */
+ */
val = 0x00;
if (info->params.data_bits != 8)
val |= BIT0; /* 7 bits */
@@ -3732,7 +3732,7 @@ static void async_mode(MGSLPC_INFO *info)
val |= BIT4;
}
write_reg(info, CHA + DAFO, val);
-
+
/* RFC Rx FIFO Control
*
* 07 Reserved, 0
@@ -3744,15 +3744,15 @@ static void async_mode(MGSLPC_INFO *info)
* 00 TCDE Terminate Char Detect Enable, 0=disabled
*
* 0101 1100
- */
+ */
write_reg(info, CHA + RFC, 0x5c);
-
+
/* RLCR Receive length check register
*
* Max frame length = (RL + 1) * 32
- */
+ */
write_reg(info, CHA + RLCR, 0);
-
+
/* XBCH Transmit Byte Count High
*
* 07 DMA mode, 0 = interrupt driven
@@ -3762,20 +3762,20 @@ static void async_mode(MGSLPC_INFO *info)
* 03..00 XBC[10..8] Transmit byte count bits 10..8
*
* 0000 0000
- */
+ */
val = 0x00;
if (info->params.flags & HDLC_FLAG_AUTO_DCD)
val |= BIT5;
write_reg(info, CHA + XBCH, val);
if (info->params.flags & HDLC_FLAG_AUTO_CTS)
irq_enable(info, CHA, IRQ_CTS);
-
- /* MODE:03 RAC Receiver Active, 1=active */
+
+ /* MODE:03 RAC Receiver Active, 1=active */
set_reg_bits(info, CHA + MODE, BIT3);
enable_auxclk(info);
if (info->params.flags & HDLC_FLAG_AUTO_CTS) {
irq_enable(info, CHB, IRQ_CTS);
- /* PVR[3] 1=AUTO CTS active */
+ /* PVR[3] 1=AUTO CTS active */
set_reg_bits(info, CHA + PVR, BIT3);
} else
clear_reg_bits(info, CHA + PVR, BIT3);
@@ -3791,7 +3791,7 @@ static void async_mode(MGSLPC_INFO *info)
*/
static void tx_set_idle(MGSLPC_INFO *info)
{
- /* Note: ESCC2 only supports flags and one idle modes */
+ /* Note: ESCC2 only supports flags and one idle modes */
if (info->idle_mode == HDLC_TXIDLE_FLAGS)
set_reg_bits(info, CHA + CCR1, BIT3);
else
@@ -3803,8 +3803,8 @@ static void tx_set_idle(MGSLPC_INFO *info)
static void get_signals(MGSLPC_INFO *info)
{
unsigned char status = 0;
-
- /* preserve DTR and RTS */
+
+ /* preserve DTR and RTS */
info->serial_signals &= SerialSignal_DTR + SerialSignal_RTS;
if (read_reg(info, CHB + VSTR) & BIT7)
@@ -3873,7 +3873,7 @@ static int rx_get_frame(MGSLPC_INFO *info)
unsigned long flags;
struct tty_struct *tty = info->tty;
int return_frame = 0;
-
+
if (info->rx_frame_count == 0)
return 0;
@@ -3913,10 +3913,10 @@ static int rx_get_frame(MGSLPC_INFO *info)
if (debug_level >= DEBUG_LEVEL_BH)
printk("%s(%d):rx_get_frame(%s) status=%04X size=%d\n",
__FILE__,__LINE__,info->device_name,status,framesize);
-
+
if (debug_level >= DEBUG_LEVEL_DATA)
- trace_block(info, buf->data, framesize, 0);
-
+ trace_block(info, buf->data, framesize, 0);
+
if (framesize) {
if ((info->params.crc_type & HDLC_CRC_RETURN_EX &&
framesize+1 > info->max_frame_size) ||
@@ -3953,7 +3953,7 @@ static int rx_get_frame(MGSLPC_INFO *info)
static BOOLEAN register_test(MGSLPC_INFO *info)
{
- static unsigned char patterns[] =
+ static unsigned char patterns[] =
{ 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f };
static unsigned int count = ARRAY_SIZE(patterns);
unsigned int i;
@@ -4002,13 +4002,13 @@ static BOOLEAN irq_test(MGSLPC_INFO *info)
while(end_time-- && !info->irq_occurred) {
msleep_interruptible(10);
}
-
+
info->testing_irq = FALSE;
spin_lock_irqsave(&info->lock,flags);
reset_device(info);
spin_unlock_irqrestore(&info->lock,flags);
-
+
return info->irq_occurred ? TRUE : FALSE;
}
@@ -4042,13 +4042,13 @@ static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit)
printk("%s tx data:\n",info->device_name);
else
printk("%s rx data:\n",info->device_name);
-
+
while(count) {
if (count > 16)
linecount = 16;
else
linecount = count;
-
+
for(i=0;i<linecount;i++)
printk("%02X ",(unsigned char)data[i]);
for(;i<17;i++)
@@ -4060,7 +4060,7 @@ static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit)
printk(".");
}
printk("\n");
-
+
data += linecount;
count -= linecount;
}
@@ -4073,7 +4073,7 @@ static void tx_timeout(unsigned long context)
{
MGSLPC_INFO *info = (MGSLPC_INFO*)context;
unsigned long flags;
-
+
if ( debug_level >= DEBUG_LEVEL_INFO )
printk( "%s(%d):tx_timeout(%s)\n",
__FILE__,__LINE__,info->device_name);
@@ -4086,7 +4086,7 @@ static void tx_timeout(unsigned long context)
info->tx_count = info->tx_put = info->tx_get = 0;
spin_unlock_irqrestore(&info->lock,flags);
-
+
#if SYNCLINK_GENERIC_HDLC
if (info->netcount)
hdlcdev_tx_done(info);
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 84ac64fc48a..3aab837d948 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -66,7 +66,6 @@
#include <linux/poll.h>
#include <linux/major.h>
#include <linux/ppdev.h>
-#include <linux/device.h>
#include <asm/uaccess.h>
#define PP_VERSION "ppdev: user-space parallel port driver"
@@ -268,9 +267,9 @@ static ssize_t pp_write (struct file * file, const char __user * buf,
return bytes_written;
}
-static void pp_irq (int irq, void * private)
+static void pp_irq (void *private)
{
- struct pp_struct * pp = (struct pp_struct *) private;
+ struct pp_struct *pp = private;
if (pp->irqresponse) {
parport_write_control (pp->pdev->port, pp->irqctl);
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index de14aea34e1..706ff34728f 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -248,14 +248,19 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
return -ENOIOCTLCMD;
}
+static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
+module_param(legacy_count, int, 0);
+
static void __init legacy_pty_init(void)
{
+ if (legacy_count <= 0)
+ return;
- pty_driver = alloc_tty_driver(NR_PTYS);
+ pty_driver = alloc_tty_driver(legacy_count);
if (!pty_driver)
panic("Couldn't allocate pty driver");
- pty_slave_driver = alloc_tty_driver(NR_PTYS);
+ pty_slave_driver = alloc_tty_driver(legacy_count);
if (!pty_slave_driver)
panic("Couldn't allocate pty slave driver");
@@ -313,7 +318,7 @@ int pty_limit = NR_UNIX98_PTY_DEFAULT;
static int pty_limit_min = 0;
static int pty_limit_max = NR_UNIX98_PTY_MAX;
-ctl_table pty_table[] = {
+static struct ctl_table pty_table[] = {
{
.ctl_name = PTY_MAX,
.procname = "max",
@@ -335,6 +340,27 @@ ctl_table pty_table[] = {
}
};
+static struct ctl_table pty_kern_table[] = {
+ {
+ .ctl_name = KERN_PTY,
+ .procname = "pty",
+ .mode = 0555,
+ .child = pty_table,
+ },
+ {}
+};
+
+static struct ctl_table pty_root_table[] = {
+ {
+ .ctl_name = CTL_KERN,
+ .procname = "kernel",
+ .mode = 0555,
+ .child = pty_kern_table,
+ },
+ {}
+};
+
+
static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -399,6 +425,7 @@ static void __init unix98_pty_init(void)
panic("Couldn't register Unix98 pts driver");
pty_table[1].data = &ptm_driver->refcount;
+ register_sysctl_table(pty_root_table);
}
#else
static inline void unix98_pty_init(void) { }
diff --git a/drivers/char/random.c b/drivers/char/random.c
index af274e5a25e..5fee0566182 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -649,7 +649,7 @@ EXPORT_SYMBOL_GPL(add_input_randomness);
void add_interrupt_randomness(int irq)
{
- if (irq >= NR_IRQS || irq_timer_state[irq] == 0)
+ if (irq >= NR_IRQS || irq_timer_state[irq] == NULL)
return;
DEBUG_ENT("irq event %d\n", irq);
@@ -1494,7 +1494,7 @@ __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK;
seq += keyptr->count;
- seq += ktime_get_real().tv64;
+ seq += ktime_to_ns(ktime_get_real());
return seq;
}
@@ -1556,7 +1556,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
* overlaps less than one time per MSL (2 minutes).
* Choosing a clock of 64 ns period is OK. (period of 274 s)
*/
- seq += ktime_get_real().tv64 >> 6;
+ seq += ktime_to_ns(ktime_get_real()) >> 6;
#if 0
printk("init_seq(%lx, %lx, %d, %d) = %d\n",
saddr, daddr, sport, dport, seq);
@@ -1616,7 +1616,7 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
seq = half_md4_transform(hash, keyptr->secret);
seq |= ((u64)keyptr->count) << (32 - HASH_BITS);
- seq += ktime_get_real().tv64;
+ seq += ktime_to_ns(ktime_get_real());
seq &= (1ull << 48) - 1;
#if 0
printk("dccp init_seq(%lx, %lx, %d, %d) = %d\n",
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 1f0d7c60c94..bbfa0e241cb 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -255,10 +255,7 @@ static const struct file_operations raw_ctl_fops = {
.owner = THIS_MODULE,
};
-static struct cdev raw_cdev = {
- .kobj = {.name = "raw", },
- .owner = THIS_MODULE,
-};
+static struct cdev raw_cdev;
static int __init raw_init(void)
{
diff --git a/drivers/char/rio/host.h b/drivers/char/rio/host.h
index 23d0681fe49..78f24540c22 100644
--- a/drivers/char/rio/host.h
+++ b/drivers/char/rio/host.h
@@ -99,7 +99,7 @@ struct Host {
struct UnixRup UnixRups[MAX_RUP + LINKS_PER_UNIT];
int timeout_id; /* For calling 100 ms delays */
int timeout_sem; /* For calling 100 ms delays */
- long locks; /* long req'd for set_bit --RR */
+ unsigned long locks; /* long req'd for set_bit --RR */
char ____end_marker____;
};
#define Control CardP->DpControl
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index b37e626f4fa..102ece4c4e0 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -79,7 +79,6 @@
#define RS_EVENT_WRITE_WAKEUP 0
-static struct riscom_board * IRQ_to_board[16];
static struct tty_driver *riscom_driver;
static struct riscom_board rc_board[RC_NBOARD] = {
@@ -537,16 +536,14 @@ static inline void rc_check_modem(struct riscom_board const * bp)
}
/* The main interrupt processing routine */
-static irqreturn_t rc_interrupt(int irq, void * dev_id)
+static irqreturn_t rc_interrupt(int dummy, void * dev_id)
{
unsigned char status;
unsigned char ack;
- struct riscom_board *bp;
+ struct riscom_board *bp = dev_id;
unsigned long loop = 0;
int handled = 0;
- bp = IRQ_to_board[irq];
-
if (!(bp->flags & RC_BOARD_ACTIVE))
return IRQ_NONE;
@@ -603,7 +600,7 @@ static irqreturn_t rc_interrupt(int irq, void * dev_id)
*/
/* Called with disabled interrupts */
-static inline int rc_setup_board(struct riscom_board * bp)
+static int rc_setup_board(struct riscom_board * bp)
{
int error;
@@ -611,7 +608,7 @@ static inline int rc_setup_board(struct riscom_board * bp)
return 0;
error = request_irq(bp->irq, rc_interrupt, IRQF_DISABLED,
- "RISCom/8", NULL);
+ "RISCom/8", bp);
if (error)
return error;
@@ -619,14 +616,13 @@ static inline int rc_setup_board(struct riscom_board * bp)
bp->DTR = ~0;
rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
- IRQ_to_board[bp->irq] = bp;
bp->flags |= RC_BOARD_ACTIVE;
return 0;
}
/* Called with disabled interrupts */
-static inline void rc_shutdown_board(struct riscom_board *bp)
+static void rc_shutdown_board(struct riscom_board *bp)
{
if (!(bp->flags & RC_BOARD_ACTIVE))
return;
@@ -634,7 +630,6 @@ static inline void rc_shutdown_board(struct riscom_board *bp)
bp->flags &= ~RC_BOARD_ACTIVE;
free_irq(bp->irq, NULL);
- IRQ_to_board[bp->irq] = NULL;
bp->DTR = ~0;
rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
@@ -1594,7 +1589,6 @@ static inline int rc_init_drivers(void)
if (!riscom_driver)
return -ENOMEM;
- memset(IRQ_to_board, 0, sizeof(IRQ_to_board));
riscom_driver->owner = THIS_MODULE;
riscom_driver->name = "ttyL";
riscom_driver->major = RISCOM8_NORMAL_MAJOR;
diff --git a/drivers/char/riscom8.h b/drivers/char/riscom8.h
index 6317aade201..9cc1313d5e6 100644
--- a/drivers/char/riscom8.h
+++ b/drivers/char/riscom8.h
@@ -71,7 +71,7 @@ struct riscom_port {
struct tty_struct * tty;
int count;
int blocked_open;
- long event; /* long req'd for set_bit --RR */
+ unsigned long event; /* long req'd for set_bit --RR */
int timeout;
int close_delay;
unsigned char * xmit_buf;
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 56cbba7b6ec..d83419c3857 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -84,6 +84,7 @@
#include <linux/mutex.h>
#include <linux/ioport.h>
#include <linux/delay.h>
+#include <linux/completion.h>
#include <linux/wait.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
@@ -548,8 +549,8 @@ static void rp_handle_port(struct r_port *info)
static void rp_do_poll(unsigned long dummy)
{
CONTROLLER_t *ctlp;
- int ctrl, aiop, ch, line, i;
- unsigned int xmitmask;
+ int ctrl, aiop, ch, line;
+ unsigned int xmitmask, i;
unsigned int CtlMask;
unsigned char AiopMask;
Word_t bit;
@@ -562,7 +563,7 @@ static void rp_do_poll(unsigned long dummy)
/* Get a ptr to the board's control struct */
ctlp = sCtlNumToCtlPtr(ctrl);
- /* Get the interupt status from the board */
+ /* Get the interrupt status from the board */
#ifdef CONFIG_PCI
if (ctlp->BusType == isPCI)
CtlMask = sPCIGetControllerIntStatus(ctlp);
@@ -650,7 +651,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
info->closing_wait = 3000;
info->close_delay = 50;
init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
+ init_completion(&info->close_wait);
info->flags &= ~ROCKET_MODE_MASK;
switch (pc104[board][line]) {
case 422:
@@ -699,8 +700,8 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
spin_lock_init(&info->slock);
mutex_init(&info->write_mtx);
rp_table[line] = info;
- if (pci_dev)
- tty_register_device(rocket_driver, line, &pci_dev->dev);
+ tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev :
+ NULL);
}
/*
@@ -878,7 +879,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
if (tty_hung_up_p(filp))
return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
if (info->flags & ROCKET_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
+ if (wait_for_completion_interruptible(&info->close_wait))
+ return -ERESTARTSYS;
return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
}
@@ -983,8 +985,10 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
return -ENOMEM;
if (info->flags & ROCKET_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
+ retval = wait_for_completion_interruptible(&info->close_wait);
free_page(page);
+ if (retval)
+ return retval;
return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
}
@@ -1176,7 +1180,7 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
}
info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | ROCKET_NORMAL_ACTIVE);
tty->closing = 0;
- wake_up_interruptible(&info->close_wait);
+ complete_all(&info->close_wait);
atomic_dec(&rp_num_ports_open);
#ifdef ROCKET_DEBUG_OPEN
@@ -1869,8 +1873,6 @@ static __init int register_PCI(int i, struct pci_dev *dev)
int fast_clock = 0;
int altChanRingIndicator = 0;
int ports_per_aiop = 8;
- int ret;
- unsigned int class_rev;
WordIO_t ConfigIO = 0;
ByteIO_t UPCIRingInd = 0;
@@ -1878,12 +1880,6 @@ static __init int register_PCI(int i, struct pci_dev *dev)
return 0;
rcktpt_io_addr[i] = pci_resource_start(dev, 0);
- ret = pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-
- if (ret) {
- printk(KERN_INFO " Error during register_PCI(), unable to read config dword \n");
- return 0;
- }
rcktpt_type[i] = ROCKET_TYPE_NORMAL;
rocketModel[i].loadrm2 = 0;
@@ -2037,8 +2033,9 @@ static __init int register_PCI(int i, struct pci_dev *dev)
ports_per_aiop = 6;
str = "6-port";
- /* If class_rev is 1, the rocketmodem flash must be loaded. If it is 2 it is a "socketed" version. */
- if ((class_rev & 0xFF) == 1) {
+ /* If revision is 1, the rocketmodem flash must be loaded.
+ * If it is 2 it is a "socketed" version. */
+ if (dev->revision == 1) {
rcktpt_type[i] = ROCKET_TYPE_MODEMII;
rocketModel[i].loadrm2 = 1;
} else {
@@ -2053,7 +2050,7 @@ static __init int register_PCI(int i, struct pci_dev *dev)
max_num_aiops = 1;
ports_per_aiop = 4;
str = "4-port";
- if ((class_rev & 0xFF) == 1) {
+ if (dev->revision == 1) {
rcktpt_type[i] = ROCKET_TYPE_MODEMII;
rocketModel[i].loadrm2 = 1;
} else {
@@ -2362,26 +2359,14 @@ static const struct tty_operations rocket_ops = {
*/
static int __init rp_init(void)
{
- int retval, pci_boards_found, isa_boards_found, i;
+ int ret = -ENOMEM, pci_boards_found, isa_boards_found, i;
printk(KERN_INFO "RocketPort device driver module, version %s, %s\n",
ROCKET_VERSION, ROCKET_DATE);
rocket_driver = alloc_tty_driver(MAX_RP_PORTS);
if (!rocket_driver)
- return -ENOMEM;
-
- /*
- * Initialize the array of pointers to our own internal state
- * structures.
- */
- memset(rp_table, 0, sizeof (rp_table));
- memset(xmit_flags, 0, sizeof (xmit_flags));
-
- for (i = 0; i < MAX_RP_PORTS; i++)
- lineNumbers[i] = 0;
- nextLineNumber = 0;
- memset(rocketModel, 0, sizeof (rocketModel));
+ goto err;
/*
* If board 1 is non-zero, there is at least one ISA configured. If controller is
@@ -2396,8 +2381,11 @@ static int __init rp_init(void)
/* If an ISA card is configured, reserve the 4 byte IO space for the Mudbac controller */
if (controller && (!request_region(controller, 4, "Comtrol RocketPort"))) {
- printk(KERN_INFO "Unable to reserve IO region for first configured ISA RocketPort controller 0x%lx. Driver exiting \n", controller);
- return -EBUSY;
+ printk(KERN_ERR "Unable to reserve IO region for first "
+ "configured ISA RocketPort controller 0x%lx. "
+ "Driver exiting\n", controller);
+ ret = -EBUSY;
+ goto err_tty;
}
/* Store ISA variable retrieved from command line or .conf file. */
@@ -2434,15 +2422,14 @@ static int __init rp_init(void)
rocket_driver->init_termios.c_ispeed = 9600;
rocket_driver->init_termios.c_ospeed = 9600;
#ifdef ROCKET_SOFT_FLOW
- rocket_driver->flags |= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ rocket_driver->flags |= TTY_DRIVER_REAL_RAW;
#endif
tty_set_operations(rocket_driver, &rocket_ops);
- retval = tty_register_driver(rocket_driver);
- if (retval < 0) {
- printk(KERN_INFO "Couldn't install tty RocketPort driver (error %d)\n", -retval);
- put_tty_driver(rocket_driver);
- return -1;
+ ret = tty_register_driver(rocket_driver);
+ if (ret < 0) {
+ printk(KERN_ERR "Couldn't install tty RocketPort driver\n");
+ goto err_tty;
}
#ifdef ROCKET_DEBUG_OPEN
@@ -2469,14 +2456,18 @@ static int __init rp_init(void)
max_board = pci_boards_found + isa_boards_found;
if (max_board == 0) {
- printk(KERN_INFO "No rocketport ports found; unloading driver.\n");
- del_timer_sync(&rocket_timer);
- tty_unregister_driver(rocket_driver);
- put_tty_driver(rocket_driver);
- return -ENXIO;
+ printk(KERN_ERR "No rocketport ports found; unloading driver\n");
+ ret = -ENXIO;
+ goto err_ttyu;
}
return 0;
+err_ttyu:
+ tty_unregister_driver(rocket_driver);
+err_tty:
+ put_tty_driver(rocket_driver);
+err:
+ return ret;
}
@@ -2491,10 +2482,14 @@ static void rp_cleanup_module(void)
if (retval)
printk(KERN_INFO "Error %d while trying to unregister "
"rocketport driver\n", -retval);
- put_tty_driver(rocket_driver);
for (i = 0; i < MAX_RP_PORTS; i++)
- kfree(rp_table[i]);
+ if (rp_table[i]) {
+ tty_unregister_device(rocket_driver, i);
+ kfree(rp_table[i]);
+ }
+
+ put_tty_driver(rocket_driver);
for (i = 0; i < NUM_BOARDS; i++) {
if (rcktpt_io_addr[i] <= 0 || is_PCI[i])
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
index b4c53dfa795..55b8f2d71a9 100644
--- a/drivers/char/rocket_int.h
+++ b/drivers/char/rocket_int.h
@@ -1163,13 +1163,8 @@ struct r_port {
int read_status_mask;
int cps;
-#ifdef DECLARE_WAITQUEUE
wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
-#else
- struct wait_queue *open_wait;
- struct wait_queue *close_wait;
-#endif
+ struct completion close_wait;
spinlock_t slock;
struct mutex write_mtx;
};
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index ec6b65ec69e..0c66b802736 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -918,6 +918,31 @@ static const struct file_operations rtc_proc_fops = {
};
#endif
+static resource_size_t rtc_size;
+
+static struct resource * __init rtc_request_region(resource_size_t size)
+{
+ struct resource *r;
+
+ if (RTC_IOMAPPED)
+ r = request_region(RTC_PORT(0), size, "rtc");
+ else
+ r = request_mem_region(RTC_PORT(0), size, "rtc");
+
+ if (r)
+ rtc_size = size;
+
+ return r;
+}
+
+static void rtc_release_region(void)
+{
+ if (RTC_IOMAPPED)
+ release_region(RTC_PORT(0), rtc_size);
+ else
+ release_mem_region(RTC_PORT(0), rtc_size);
+}
+
static int __init rtc_init(void)
{
#ifdef CONFIG_PROC_FS
@@ -968,10 +993,17 @@ found:
}
no_irq:
#else
- if (RTC_IOMAPPED)
- r = request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
- else
- r = request_mem_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
+ r = rtc_request_region(RTC_IO_EXTENT);
+
+ /*
+ * If we've already requested a smaller range (for example, because
+ * PNPBIOS or ACPI told us how the device is configured), the request
+ * above might fail because it's too big.
+ *
+ * If so, request just the range we actually use.
+ */
+ if (!r)
+ r = rtc_request_region(RTC_IO_EXTENT_USED);
if (!r) {
#ifdef RTC_IRQ
rtc_has_irq = 0;
@@ -992,10 +1024,7 @@ no_irq:
/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
rtc_has_irq = 0;
printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
- if (RTC_IOMAPPED)
- release_region(RTC_PORT(0), RTC_IO_EXTENT);
- else
- release_mem_region(RTC_PORT(0), RTC_IO_EXTENT);
+ rtc_release_region();
return -EIO;
}
hpet_rtc_timer_init();
@@ -1009,7 +1038,7 @@ no_irq:
free_irq(RTC_IRQ, NULL);
rtc_has_irq = 0;
#endif
- release_region(RTC_PORT(0), RTC_IO_EXTENT);
+ rtc_release_region();
return -ENODEV;
}
@@ -1091,10 +1120,7 @@ static void __exit rtc_exit (void)
if (rtc_has_irq)
free_irq (rtc_irq, &rtc_port);
#else
- if (RTC_IOMAPPED)
- release_region(RTC_PORT(0), RTC_IO_EXTENT);
- else
- release_mem_region(RTC_PORT(0), RTC_IO_EXTENT);
+ rtc_release_region();
#ifdef RTC_IRQ
if (rtc_has_irq)
free_irq (RTC_IRQ, NULL);
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index 52753e723ea..b9c1dba6bd0 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -441,8 +441,7 @@ scdrv_init(void)
continue;
}
- class_device_create(snsc_class, NULL, dev, NULL,
- "%s", devname);
+ device_create(snsc_class, NULL, dev, "%s", devname);
ia64_sn_irtr_intr_enable(scd->scd_nasid,
0 /*ignored */ ,
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 859858561ab..877e53dcb99 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -7,7 +7,7 @@
*
* Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
*
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
*
* Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
*
@@ -1178,9 +1178,9 @@ static int __devinit sonypi_create_input_devices(void)
jog_dev->id.bustype = BUS_ISA;
jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
- jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
- jog_dev->relbit[0] = BIT(REL_WHEEL);
+ jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE);
+ jog_dev->relbit[0] = BIT_MASK(REL_WHEEL);
sonypi_device.input_key_dev = key_dev = input_allocate_device();
if (!key_dev) {
@@ -1193,7 +1193,7 @@ static int __devinit sonypi_create_input_devices(void)
key_dev->id.vendor = PCI_VENDOR_ID_SONY;
/* Initialize the Input Drivers: special keys */
- key_dev->evbit[0] = BIT(EV_KEY);
+ key_dev->evbit[0] = BIT_MASK(EV_KEY);
for (i = 0; sonypi_inputkeys[i].sonypiev; i++)
if (sonypi_inputkeys[i].inputev)
set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit);
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 4a80b2f864e..45758d5b56e 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -4778,9 +4778,8 @@ static int __init stallion_module_init(void)
if (IS_ERR(stallion_class))
printk("STALLION: failed to create class\n");
for (i = 0; i < 4; i++)
- class_device_create(stallion_class, NULL,
- MKDEV(STL_SIOMEMMAJOR, i), NULL,
- "staliomem%d", i);
+ device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+ "staliomem%d", i);
return 0;
err_unrtty:
@@ -4816,7 +4815,7 @@ static void __exit stallion_module_exit(void)
}
for (i = 0; i < 4; i++)
- class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
+ device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
class_destroy(stallion_class);
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index 85a23283dff..a6e1c9ba121 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -1467,7 +1467,7 @@ static int sx_open(struct tty_struct *tty, struct file *filp)
line = tty->index;
sx_dprintk(SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, "
- "np=%d)\n", current->pid, line, tty,
+ "np=%d)\n", task_pid_nr(current), line, tty,
current->signal->tty, sx_nports);
if ((line < 0) || (line >= SX_NPORTS) || (line >= sx_nports))
diff --git a/drivers/char/sx.h b/drivers/char/sx.h
index 432aad0a2dd..70d9783c732 100644
--- a/drivers/char/sx.h
+++ b/drivers/char/sx.h
@@ -27,7 +27,7 @@ struct sx_port {
int c_dcd;
struct sx_board *board;
int line;
- long locks;
+ unsigned long locks;
};
struct sx_board {
@@ -45,7 +45,7 @@ struct sx_board {
int poll;
int ta_type;
struct timer_list timer;
- long locks;
+ unsigned long locks;
};
struct vpd_prom {
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index fdc256b380b..905d1f51a7b 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -81,13 +81,9 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
-
#include <linux/netdevice.h>
-
#include <linux/vmalloc.h>
#include <linux/init.h>
-
-#include <linux/delay.h>
#include <linux/ioctl.h>
#include <asm/system.h>
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 2f97d2f8f91..64e835f6243 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -206,10 +206,10 @@ static void flush_cond_wait(struct cond_wait **head);
*/
struct slgt_desc
{
- unsigned short count;
- unsigned short status;
- unsigned int pbuf; /* physical address of data buffer */
- unsigned int next; /* physical address of next descriptor */
+ __le16 count;
+ __le16 status;
+ __le32 pbuf; /* physical address of data buffer */
+ __le32 next; /* physical address of next descriptor */
/* driver book keeping */
char *buf; /* virtual address of data buffer */
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 39cc318011e..de60e1ea4fb 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -36,6 +36,7 @@
#include <linux/kexec.h>
#include <linux/irq.h>
#include <linux/hrtimer.h>
+#include <linux/oom.h>
#include <asm/ptrace.h>
#include <asm/irq_regs.h>
@@ -107,12 +108,12 @@ static void sysrq_handle_unraw(int key, struct tty_struct *tty)
struct kbd_struct *kbd = &kbd_table[fg_console];
if (kbd)
- kbd->kbdmode = VC_XLATE;
+ kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
}
static struct sysrq_key_op sysrq_unraw_op = {
.handler = sysrq_handle_unraw,
.help_msg = "unRaw",
- .action_msg = "Keyboard mode set to XLATE",
+ .action_msg = "Keyboard mode set to system default",
.enable_mask = SYSRQ_ENABLE_KEYBOARD,
};
#else
@@ -250,7 +251,7 @@ static void send_sig_all(int sig)
struct task_struct *p;
for_each_process(p) {
- if (p->mm && !is_init(p))
+ if (p->mm && !is_global_init(p))
/* Not swapper, init nor kernel thread */
force_sig(sig, p);
}
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index 35b40b99653..cef55c40654 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -441,8 +441,8 @@ tipar_register(int nr, struct parport *port)
goto out;
}
- class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR,
- TIPAR_MINOR + nr), port->dev, "par%d", nr);
+ device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR,
+ TIPAR_MINOR + nr), "par%d", nr);
/* Display informations */
pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq ==
@@ -534,7 +534,7 @@ tipar_cleanup_module(void)
if (table[i].dev == NULL)
continue;
parport_unregister_device(table[i].dev);
- class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
+ device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
}
class_destroy(tipar_class);
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 23fa18a6654..fd771a4d6d1 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -381,7 +381,7 @@ static struct tpm_vendor_specific tpm_tis = {
static irqreturn_t tis_int_probe(int irq, void *dev_id)
{
- struct tpm_chip *chip = (struct tpm_chip *) dev_id;
+ struct tpm_chip *chip = dev_id;
u32 interrupt;
interrupt = ioread32(chip->vendor.iobase +
@@ -401,7 +401,7 @@ static irqreturn_t tis_int_probe(int irq, void *dev_id)
static irqreturn_t tis_int_handler(int irq, void *dev_id)
{
- struct tpm_chip *chip = (struct tpm_chip *) dev_id;
+ struct tpm_chip *chip = dev_id;
u32 interrupt;
int i;
@@ -435,17 +435,12 @@ module_param(interrupts, bool, 0444);
MODULE_PARM_DESC(interrupts, "Enable interrupts");
static int tpm_tis_init(struct device *dev, resource_size_t start,
- resource_size_t len)
+ resource_size_t len, unsigned int irq)
{
u32 vendor, intfcaps, intmask;
int rc, i;
struct tpm_chip *chip;
- if (!start)
- start = TIS_MEM_BASE;
- if (!len)
- len = TIS_MEM_LEN;
-
if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
return -ENODEV;
@@ -512,7 +507,9 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
iowrite32(intmask,
chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.locality));
- if (interrupts) {
+ if (interrupts)
+ chip->vendor.irq = irq;
+ if (interrupts && !chip->vendor.irq) {
chip->vendor.irq =
ioread8(chip->vendor.iobase +
TPM_INT_VECTOR(chip->vendor.locality));
@@ -597,10 +594,17 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
const struct pnp_device_id *pnp_id)
{
resource_size_t start, len;
+ unsigned int irq = 0;
+
start = pnp_mem_start(pnp_dev, 0);
len = pnp_mem_len(pnp_dev, 0);
- return tpm_tis_init(&pnp_dev->dev, start, len);
+ if (pnp_irq_valid(pnp_dev, 0))
+ irq = pnp_irq(pnp_dev, 0);
+ else
+ interrupts = 0;
+
+ return tpm_tis_init(&pnp_dev->dev, start, len, irq);
}
static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg)
@@ -660,7 +664,7 @@ static int __init init_tis(void)
return rc;
if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0)))
return PTR_ERR(pdev);
- if((rc=tpm_tis_init(&pdev->dev, 0, 0)) != 0) {
+ if((rc=tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0)) != 0) {
platform_device_unregister(pdev);
driver_unregister(&tis_drv);
}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 9c867cf6de6..f36fecd3fd2 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -103,6 +103,7 @@
#include <linux/selection.h>
#include <linux/kmod.h>
+#include <linux/nsproxy.h>
#undef TTY_DEBUG_HANGUP
@@ -942,7 +943,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_deref);
* @tty: terminal to activate ldisc on
*
* Set the TTY_LDISC flag when the line discipline can be called
- * again. Do neccessary wakeups for existing sleepers.
+ * again. Do necessary wakeups for existing sleepers.
*
* Note: nobody should set this bit except via this function. Clearing
* directly is allowed.
@@ -1503,7 +1504,7 @@ EXPORT_SYMBOL(tty_hangup);
*
* The user has asked via system call for the terminal to be hung up.
* We do this synchronously so that when the syscall returns the process
- * is complete. That guarantee is neccessary for security reasons.
+ * is complete. That guarantee is necessary for security reasons.
*/
void tty_vhangup(struct tty_struct * tty)
@@ -1690,7 +1691,7 @@ EXPORT_SYMBOL(stop_tty);
* @tty: tty to start
*
* Start a tty that has been stopped if at all possible. Perform
- * any neccessary wakeups and propagate the TIOCPKT status. If this
+ * any necessary wakeups and propagate the TIOCPKT status. If this
* is the tty was previous stopped and is being started then the
* driver start method is invoked and the line discipline woken.
*
@@ -2876,7 +2877,7 @@ static int tty_fasync(int fd, struct file * filp, int on)
* @tty: tty to fake input into
* @p: pointer to character
*
- * Fake input to a tty device. Does the neccessary locking and
+ * Fake input to a tty device. Does the necessary locking and
* input management.
*
* FIXME: does not honour flow control ??
@@ -3107,7 +3108,7 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
*/
if (tty == real_tty && current->signal->tty != real_tty)
return -ENOTTY;
- return put_user(pid_nr(real_tty->pgrp), p);
+ return put_user(pid_vnr(real_tty->pgrp), p);
}
/**
@@ -3141,7 +3142,7 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
if (pgrp_nr < 0)
return -EINVAL;
rcu_read_lock();
- pgrp = find_pid(pgrp_nr);
+ pgrp = find_vpid(pgrp_nr);
retval = -ESRCH;
if (!pgrp)
goto out_unlock;
@@ -3178,7 +3179,7 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
return -ENOTTY;
if (!real_tty->session)
return -ENOTTY;
- return put_user(pid_nr(real_tty->session), p);
+ return put_user(pid_vnr(real_tty->session), p);
}
/**
@@ -3528,8 +3529,8 @@ void __do_SAK(struct tty_struct *tty)
/* Kill the entire session */
do_each_pid_task(session, PIDTYPE_SID, p) {
printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): process_session(p)==tty->session\n",
- p->pid, p->comm);
+ " (%s): task_session_nr(p)==tty->session\n",
+ task_pid_nr(p), p->comm);
send_sig(SIGKILL, p, 1);
} while_each_pid_task(session, PIDTYPE_SID, p);
/* Now kill any processes that happen to have the
@@ -3538,8 +3539,8 @@ void __do_SAK(struct tty_struct *tty)
do_each_thread(g, p) {
if (p->signal->tty == tty) {
printk(KERN_NOTICE "SAK: killed process %d"
- " (%s): process_session(p)==tty->session\n",
- p->pid, p->comm);
+ " (%s): task_session_nr(p)==tty->session\n",
+ task_pid_nr(p), p->comm);
send_sig(SIGKILL, p, 1);
continue;
}
@@ -3559,7 +3560,7 @@ void __do_SAK(struct tty_struct *tty)
filp->private_data == tty) {
printk(KERN_NOTICE "SAK: killed process %d"
" (%s): fd#%d opened to the tty\n",
- p->pid, p->comm, i);
+ task_pid_nr(p), p->comm, i);
force_sig(SIGKILL, p);
break;
}
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 3ee73cf64bd..1bdd2bf4f37 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -206,8 +206,6 @@ speed_t tty_termios_input_baud_rate(struct ktermios *termios)
EXPORT_SYMBOL(tty_termios_input_baud_rate);
-#ifdef BOTHER
-
/**
* tty_termios_encode_baud_rate
* @termios: ktermios structure holding user requested state
@@ -225,18 +223,26 @@ EXPORT_SYMBOL(tty_termios_input_baud_rate);
*
* Locking: Caller should hold termios lock. This is already held
* when calling this function from the driver termios handler.
+ *
+ * The ifdefs deal with platforms whose owners have yet to update them
+ * and will all go away once this is done.
*/
-void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed_t obaud)
+void tty_termios_encode_baud_rate(struct ktermios *termios,
+ speed_t ibaud, speed_t obaud)
{
int i = 0;
int ifound = -1, ofound = -1;
int iclose = ibaud/50, oclose = obaud/50;
int ibinput = 0;
+ if (obaud == 0) /* CD dropped */
+ ibaud = 0; /* Clear ibaud to be sure */
+
termios->c_ispeed = ibaud;
termios->c_ospeed = obaud;
+#ifdef BOTHER
/* If the user asked for a precise weird speed give a precise weird
answer. If they asked for a Bfoo speed they many have problems
digesting non-exact replies so fuzz a bit */
@@ -247,32 +253,64 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed
iclose = 0;
if ((termios->c_cflag >> IBSHIFT) & CBAUD)
ibinput = 1; /* An input speed was specified */
-
+#endif
termios->c_cflag &= ~CBAUD;
+ /*
+ * Our goal is to find a close match to the standard baud rate
+ * returned. Walk the baud rate table and if we get a very close
+ * match then report back the speed as a POSIX Bxxxx value by
+ * preference
+ */
+
do {
- if (obaud - oclose >= baud_table[i] && obaud + oclose <= baud_table[i]) {
+ if (obaud - oclose <= baud_table[i] &&
+ obaud + oclose >= baud_table[i]) {
termios->c_cflag |= baud_bits[i];
ofound = i;
}
- if (ibaud - iclose >= baud_table[i] && ibaud + iclose <= baud_table[i]) {
- /* For the case input == output don't set IBAUD bits if the user didn't do so */
- if (ofound != i || ibinput)
+ if (ibaud - iclose <= baud_table[i] &&
+ ibaud + iclose >= baud_table[i]) {
+ /* For the case input == output don't set IBAUD bits
+ if the user didn't do so */
+ if (ofound == i && !ibinput)
+ ifound = i;
+#ifdef IBSHIFT
+ else {
+ ifound = i;
termios->c_cflag |= (baud_bits[i] << IBSHIFT);
- ifound = i;
+ }
+#endif
}
} while (++i < n_baud_table);
+
+ /*
+ * If we found no match then use BOTHER if provided or warn
+ * the user their platform maintainer needs to wake up if not.
+ */
+#ifdef BOTHER
if (ofound == -1)
termios->c_cflag |= BOTHER;
/* Set exact input bits only if the input and output differ or the
user already did */
if (ifound == -1 && (ibaud != obaud || ibinput))
termios->c_cflag |= (BOTHER << IBSHIFT);
+#else
+ if (ifound == -1 || ofound == -1) {
+ static int warned;
+ if (!warned++)
+ printk(KERN_WARNING "tty: Unable to return correct "
+ "speed data as your architecture needs updating.\n");
+ }
+#endif
}
-
EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
-#endif
+void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
+{
+ tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
+}
+EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
/**
* tty_get_baud_rate - get tty bit rates
@@ -304,6 +342,29 @@ speed_t tty_get_baud_rate(struct tty_struct *tty)
EXPORT_SYMBOL(tty_get_baud_rate);
/**
+ * tty_termios_copy_hw - copy hardware settings
+ * @new: New termios
+ * @old: Old termios
+ *
+ * Propogate the hardware specific terminal setting bits from
+ * the old termios structure to the new one. This is used in cases
+ * where the hardware does not support reconfiguration or as a helper
+ * in some cases where only minimal reconfiguration is supported
+ */
+
+void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
+{
+ /* The bits a dumb device handles in software. Smart devices need
+ to always provide a set_termios method */
+ new->c_cflag &= HUPCL | CREAD | CLOCAL;
+ new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
+ new->c_ispeed = old->c_ispeed;
+ new->c_ospeed = old->c_ospeed;
+}
+
+EXPORT_SYMBOL(tty_termios_copy_hw);
+
+/**
* change_termios - update termios values
* @tty: tty to update
* @new_termios: desired new value
@@ -340,13 +401,12 @@ static void change_termios(struct tty_struct * tty, struct ktermios * new_termio
tty->erasing = 0;
}
-
+ /* This bit should be in the ldisc code */
if (canon_change && !L_ICANON(tty) && tty->read_cnt)
/* Get characters left over from canonical mode. */
wake_up_interruptible(&tty->read_wait);
/* See if packet mode change of state. */
-
if (tty->link && tty->link->packet) {
int old_flow = ((old_termios.c_iflag & IXON) &&
(old_termios.c_cc[VSTOP] == '\023') &&
@@ -366,6 +426,8 @@ static void change_termios(struct tty_struct * tty, struct ktermios * new_termio
if (tty->driver->set_termios)
(*tty->driver->set_termios)(tty, &old_termios);
+ else
+ tty_termios_copy_hw(tty->termios, &old_termios);
ld = tty_ldisc_ref(tty);
if (ld != NULL) {
@@ -382,7 +444,7 @@ static void change_termios(struct tty_struct * tty, struct ktermios * new_termio
* @arg: user data
* @opt: option information
*
- * Helper function to prepare termios data and run neccessary other
+ * Helper function to prepare termios data and run necessary other
* functions before using change_termios to do the actual changes.
*
* Locking:
@@ -440,6 +502,11 @@ static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
}
change_termios(tty, &tmp_termios);
+
+ /* FIXME: Arguably if tmp_termios == tty->termios AND the
+ actual requested termios was not tmp_termios then we may
+ want to return an error as no user requested change has
+ succeeded */
return 0;
}
@@ -663,13 +730,23 @@ static int send_prio_char(struct tty_struct *tty, char ch)
return 0;
}
-int n_tty_ioctl(struct tty_struct * tty, struct file * file,
- unsigned int cmd, unsigned long arg)
+/**
+ * tty_mode_ioctl - mode related ioctls
+ * @tty: tty for the ioctl
+ * @file: file pointer for the tty
+ * @cmd: command
+ * @arg: ioctl argument
+ *
+ * Perform non line discipline specific mode control ioctls. This
+ * is designed to be called by line disciplines to ensure they provide
+ * consistent mode setting.
+ */
+
+int tty_mode_ioctl(struct tty_struct * tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
struct tty_struct * real_tty;
void __user *p = (void __user *)arg;
- int retval;
- struct tty_ldisc *ld;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
@@ -732,6 +809,93 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
case TCSETA:
return set_termios(real_tty, p, TERMIOS_TERMIO);
+#ifndef TCGETS2
+ case TIOCGLCKTRMIOS:
+ if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
+ return -EFAULT;
+ return 0;
+
+ case TIOCSLCKTRMIOS:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg))
+ return -EFAULT;
+ return 0;
+#else
+ case TIOCGLCKTRMIOS:
+ if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
+ return -EFAULT;
+ return 0;
+
+ case TIOCSLCKTRMIOS:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg))
+ return -EFAULT;
+ return 0;
+#endif
+ case TIOCGSOFTCAR:
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg);
+ case TIOCSSOFTCAR:
+ if (get_user(arg, (unsigned int __user *) arg))
+ return -EFAULT;
+ mutex_lock(&tty->termios_mutex);
+ tty->termios->c_cflag =
+ ((tty->termios->c_cflag & ~CLOCAL) |
+ (arg ? CLOCAL : 0));
+ mutex_unlock(&tty->termios_mutex);
+ return 0;
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+EXPORT_SYMBOL_GPL(tty_mode_ioctl);
+
+int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
+{
+ struct tty_ldisc *ld;
+ int retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+
+ ld = tty_ldisc_ref(tty);
+ switch (arg) {
+ case TCIFLUSH:
+ if (ld && ld->flush_buffer)
+ ld->flush_buffer(tty);
+ break;
+ case TCIOFLUSH:
+ if (ld && ld->flush_buffer)
+ ld->flush_buffer(tty);
+ /* fall through */
+ case TCOFLUSH:
+ if (tty->driver->flush_buffer)
+ tty->driver->flush_buffer(tty);
+ break;
+ default:
+ tty_ldisc_deref(ld);
+ return -EINVAL;
+ }
+ tty_ldisc_deref(ld);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(tty_perform_flush);
+
+int n_tty_ioctl(struct tty_struct * tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct tty_struct * real_tty;
+ int retval;
+
+ if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+ tty->driver->subtype == PTY_TYPE_MASTER)
+ real_tty = tty->link;
+ else
+ real_tty = tty;
+
+ switch (cmd) {
case TCXONC:
retval = tty_check_change(tty);
if (retval)
@@ -762,30 +926,7 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
}
return 0;
case TCFLSH:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
-
- ld = tty_ldisc_ref(tty);
- switch (arg) {
- case TCIFLUSH:
- if (ld && ld->flush_buffer)
- ld->flush_buffer(tty);
- break;
- case TCIOFLUSH:
- if (ld && ld->flush_buffer)
- ld->flush_buffer(tty);
- /* fall through */
- case TCOFLUSH:
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- break;
- default:
- tty_ldisc_deref(ld);
- return -EINVAL;
- }
- tty_ldisc_deref(ld);
- return 0;
+ return tty_perform_flush(tty, arg);
case TIOCOUTQ:
return put_user(tty->driver->chars_in_buffer ?
tty->driver->chars_in_buffer(tty) : 0,
@@ -795,32 +936,6 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
if (L_ICANON(tty))
retval = inq_canon(tty);
return put_user(retval, (unsigned int __user *) arg);
-#ifndef TCGETS2
- case TIOCGLCKTRMIOS:
- if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
- return -EFAULT;
- return 0;
-
- case TIOCSLCKTRMIOS:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg))
- return -EFAULT;
- return 0;
-#else
- case TIOCGLCKTRMIOS:
- if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
- return -EFAULT;
- return 0;
-
- case TIOCSLCKTRMIOS:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg))
- return -EFAULT;
- return 0;
-#endif
-
case TIOCPKT:
{
int pktmode;
@@ -839,19 +954,9 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
tty->packet = 0;
return 0;
}
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg);
- case TIOCSSOFTCAR:
- if (get_user(arg, (unsigned int __user *) arg))
- return -EFAULT;
- mutex_lock(&tty->termios_mutex);
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- mutex_unlock(&tty->termios_mutex);
- return 0;
default:
- return -ENOIOCTLCMD;
+ /* Try the mode commands */
+ return tty_mode_ioctl(tty, file, cmd, arg);
}
}
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index e12275df6ea..db7a731e236 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -92,47 +92,6 @@ struct viot_devinfo_struct {
#define VIOTAPOP_SETPART 14
#define VIOTAPOP_UNLOAD 15
-struct viotapelpevent {
- struct HvLpEvent event;
- u32 reserved;
- u16 version;
- u16 sub_type_result;
- u16 tape;
- u16 flags;
- u32 token;
- u64 len;
- union {
- struct {
- u32 tape_op;
- u32 count;
- } op;
- struct {
- u32 type;
- u32 resid;
- u32 dsreg;
- u32 gstat;
- u32 erreg;
- u32 file_no;
- u32 block_no;
- } get_status;
- struct {
- u32 block_no;
- } get_pos;
- } u;
-};
-
-enum viotapesubtype {
- viotapeopen = 0x0001,
- viotapeclose = 0x0002,
- viotaperead = 0x0003,
- viotapewrite = 0x0004,
- viotapegetinfo = 0x0005,
- viotapeop = 0x0006,
- viotapegetpos = 0x0007,
- viotapesetpos = 0x0008,
- viotapegetstatus = 0x0009
-};
-
enum viotaperc {
viotape_InvalidRange = 0x0601,
viotape_InvalidToken = 0x0602,
@@ -223,14 +182,11 @@ static const struct vio_error_entry viotape_err_table[] = {
#define VIOT_WRITING 2
/* Our info on the tapes */
-struct tape_descr {
- char rsrcname[10];
- char type[4];
- char model[3];
-};
-
-static struct tape_descr *viotape_unitinfo;
-static dma_addr_t viotape_unitinfo_token;
+static struct {
+ const char *rsrcname;
+ const char *type;
+ const char *model;
+} viotape_unitinfo[VIOTAPE_MAX_TAPE];
static struct mtget viomtget[VIOTAPE_MAX_TAPE];
@@ -381,53 +337,6 @@ int tape_rc_to_errno(int tape_rc, char *operation, int tapeno)
return -err->errno;
}
-/* Get info on all tapes from OS/400 */
-static int get_viotape_info(void)
-{
- HvLpEvent_Rc hvrc;
- int i;
- size_t len = sizeof(*viotape_unitinfo) * VIOTAPE_MAX_TAPE;
- struct op_struct *op = get_op_struct();
-
- if (op == NULL)
- return -ENOMEM;
-
- viotape_unitinfo = dma_alloc_coherent(iSeries_vio_dev, len,
- &viotape_unitinfo_token, GFP_ATOMIC);
- if (viotape_unitinfo == NULL) {
- free_op_struct(op);
- return -ENOMEM;
- }
-
- memset(viotape_unitinfo, 0, len);
-
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_tape | viotapegetinfo,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64) (unsigned long) op, VIOVERSION << 16,
- viotape_unitinfo_token, len, 0, 0);
- if (hvrc != HvLpEvent_Rc_Good) {
- printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
- (int)hvrc);
- free_op_struct(op);
- return -EIO;
- }
-
- wait_for_completion(&op->com);
-
- free_op_struct(op);
-
- for (i = 0;
- ((i < VIOTAPE_MAX_TAPE) && (viotape_unitinfo[i].rsrcname[0]));
- i++)
- viotape_numdev++;
- return 0;
-}
-
-
/* Write */
static ssize_t viotap_write(struct file *file, const char *buf,
size_t count, loff_t * ppos)
@@ -899,7 +808,6 @@ static void vioHandleTapeEvent(struct HvLpEvent *event)
tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
op = (struct op_struct *)event->xCorrelationToken;
switch (tapeminor) {
- case viotapegetinfo:
case viotapeopen:
case viotapeclose:
op->rc = tevent->sub_type_result;
@@ -942,19 +850,31 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
{
int i = vdev->unit_address;
int j;
+ struct device_node *node = vdev->dev.archdata.of_node;
- if (i >= viotape_numdev)
+ if (i > VIOTAPE_MAX_TAPE)
+ return -ENODEV;
+ if (!node)
return -ENODEV;
+ if (i >= viotape_numdev)
+ viotape_numdev = i + 1;
+
tape_device[i] = &vdev->dev;
+ viotape_unitinfo[i].rsrcname = of_get_property(node,
+ "linux,vio_rsrcname", NULL);
+ viotape_unitinfo[i].type = of_get_property(node, "linux,vio_type",
+ NULL);
+ viotape_unitinfo[i].model = of_get_property(node, "linux,vio_model",
+ NULL);
state[i].cur_part = 0;
for (j = 0; j < MAX_PARTITIONS; ++j)
state[i].part_stat_rwi[j] = VIOT_IDLE;
- class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL,
+ device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i),
"iseries!vt%d", i);
- class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
- NULL, "iseries!nvt%d", i);
+ device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
+ "iseries!nvt%d", i);
printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries "
"resource %10.10s type %4.4s, model %3.3s\n",
i, viotape_unitinfo[i].rsrcname,
@@ -966,8 +886,8 @@ static int viotape_remove(struct vio_dev *vdev)
{
int i = vdev->unit_address;
- class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
- class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
+ device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
+ device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
return 0;
}
@@ -1044,11 +964,6 @@ int __init viotap_init(void)
goto unreg_chrdev;
}
- if ((ret = get_viotape_info()) < 0) {
- printk(VIOTAPE_KERN_WARN "Unable to obtain virtual device information");
- goto unreg_class;
- }
-
ret = vio_register_driver(&viotape_driver);
if (ret)
goto unreg_class;
@@ -1102,10 +1017,6 @@ static void __exit viotap_exit(void)
vio_unregister_driver(&viotape_driver);
class_destroy(tape_class);
unregister_chrdev(VIOTAPE_MAJOR, "viotape");
- if (viotape_unitinfo)
- dma_free_coherent(iSeries_vio_dev,
- sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE,
- viotape_unitinfo, viotape_unitinfo_token);
viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);
vio_clearHandler(viomajorsubtype_tape);
clear_op_struct_pool();
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
new file mode 100644
index 00000000000..e34da5c9719
--- /dev/null
+++ b/drivers/char/virtio_console.c
@@ -0,0 +1,225 @@
+/*D:300
+ * The Guest console driver
+ *
+ * Writing console drivers is one of the few remaining Dark Arts in Linux.
+ * Fortunately for us, the path of virtual consoles has been well-trodden by
+ * the PowerPC folks, who wrote "hvc_console.c" to generically support any
+ * virtual console. We use that infrastructure which only requires us to write
+ * the basic put_chars and get_chars functions and call the right register
+ * functions.
+ :*/
+
+/*M:002 The console can be flooded: while the Guest is processing input the
+ * Host can send more. Buffering in the Host could alleviate this, but it is a
+ * difficult problem in general. :*/
+/* Copyright (C) 2006, 2007 Rusty Russell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/virtio.h>
+#include <linux/virtio_console.h>
+#include "hvc_console.h"
+
+/*D:340 These represent our input and output console queues, and the virtio
+ * operations for them. */
+static struct virtqueue *in_vq, *out_vq;
+static struct virtio_device *vdev;
+
+/* This is our input buffer, and how much data is left in it. */
+static unsigned int in_len;
+static char *in, *inbuf;
+
+/* The operations for our console. */
+static struct hv_ops virtio_cons;
+
+/*D:310 The put_chars() callback is pretty straightforward.
+ *
+ * We turn the characters into a scatter-gather list, add it to the output
+ * queue and then kick the Host. Then we sit here waiting for it to finish:
+ * inefficient in theory, but in practice implementations will do it
+ * immediately (lguest's Launcher does). */
+static int put_chars(u32 vtermno, const char *buf, int count)
+{
+ struct scatterlist sg[1];
+ unsigned int len;
+
+ /* This is a convenient routine to initialize a single-elem sg list */
+ sg_init_one(sg, buf, count);
+
+ /* add_buf wants a token to identify this buffer: we hand it any
+ * non-NULL pointer, since there's only ever one buffer. */
+ if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, (void *)1) == 0) {
+ /* Tell Host to go! */
+ out_vq->vq_ops->kick(out_vq);
+ /* Chill out until it's done with the buffer. */
+ while (!out_vq->vq_ops->get_buf(out_vq, &len))
+ cpu_relax();
+ }
+
+ /* We're expected to return the amount of data we wrote: all of it. */
+ return count;
+}
+
+/* Create a scatter-gather list representing our input buffer and put it in the
+ * queue. */
+static void add_inbuf(void)
+{
+ struct scatterlist sg[1];
+ sg_init_one(sg, inbuf, PAGE_SIZE);
+
+ /* We should always be able to add one buffer to an empty queue. */
+ if (in_vq->vq_ops->add_buf(in_vq, sg, 0, 1, inbuf) != 0)
+ BUG();
+ in_vq->vq_ops->kick(in_vq);
+}
+
+/*D:350 get_chars() is the callback from the hvc_console infrastructure when
+ * an interrupt is received.
+ *
+ * Most of the code deals with the fact that the hvc_console() infrastructure
+ * only asks us for 16 bytes at a time. We keep in_offset and in_used fields
+ * for partially-filled buffers. */
+static int get_chars(u32 vtermno, char *buf, int count)
+{
+ /* If we don't have an input queue yet, we can't get input. */
+ BUG_ON(!in_vq);
+
+ /* No buffer? Try to get one. */
+ if (!in_len) {
+ in = in_vq->vq_ops->get_buf(in_vq, &in_len);
+ if (!in)
+ return 0;
+ }
+
+ /* You want more than we have to give? Well, try wanting less! */
+ if (in_len < count)
+ count = in_len;
+
+ /* Copy across to their buffer and increment offset. */
+ memcpy(buf, in, count);
+ in += count;
+ in_len -= count;
+
+ /* Finished? Re-register buffer so Host will use it again. */
+ if (in_len == 0)
+ add_inbuf();
+
+ return count;
+}
+/*:*/
+
+/*D:320 Console drivers are initialized very early so boot messages can go out,
+ * so we do things slightly differently from the generic virtio initialization
+ * of the net and block drivers.
+ *
+ * At this stage, the console is output-only. It's too early to set up a
+ * virtqueue, so we let the drivers do some boutique early-output thing. */
+int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
+{
+ virtio_cons.put_chars = put_chars;
+ return hvc_instantiate(0, 0, &virtio_cons);
+}
+
+/*D:370 Once we're further in boot, we get probed like any other virtio device.
+ * At this stage we set up the output virtqueue.
+ *
+ * To set up and manage our virtual console, we call hvc_alloc(). Since we
+ * never remove the console device we never need this pointer again.
+ *
+ * Finally we put our input buffer in the input queue, ready to receive. */
+static int __devinit virtcons_probe(struct virtio_device *dev)
+{
+ int err;
+ struct hvc_struct *hvc;
+
+ vdev = dev;
+
+ /* This is the scratch page we use to receive console input */
+ inbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!inbuf) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ /* Find the input queue. */
+ /* FIXME: This is why we want to wean off hvc: we do nothing
+ * when input comes in. */
+ in_vq = vdev->config->find_vq(vdev, NULL);
+ if (IS_ERR(in_vq)) {
+ err = PTR_ERR(in_vq);
+ goto free;
+ }
+
+ out_vq = vdev->config->find_vq(vdev, NULL);
+ if (IS_ERR(out_vq)) {
+ err = PTR_ERR(out_vq);
+ goto free_in_vq;
+ }
+
+ /* Start using the new console output. */
+ virtio_cons.get_chars = get_chars;
+ virtio_cons.put_chars = put_chars;
+
+ /* The first argument of hvc_alloc() is the virtual console number, so
+ * we use zero. The second argument is the interrupt number; we
+ * currently leave this as zero: it would be better not to use the
+ * hvc mechanism and fix this (FIXME!).
+ *
+ * The third argument is a "struct hv_ops" containing the put_chars()
+ * and get_chars() pointers. The final argument is the output buffer
+ * size: we can do any size, so we put PAGE_SIZE here. */
+ hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE);
+ if (IS_ERR(hvc)) {
+ err = PTR_ERR(hvc);
+ goto free_out_vq;
+ }
+
+ /* Register the input buffer the first time. */
+ add_inbuf();
+ return 0;
+
+free_out_vq:
+ vdev->config->del_vq(out_vq);
+free_in_vq:
+ vdev->config->del_vq(in_vq);
+free:
+ kfree(inbuf);
+fail:
+ return err;
+}
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static struct virtio_driver virtio_console = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = virtcons_probe,
+};
+
+static int __init init(void)
+{
+ return register_virtio_driver(&virtio_console);
+}
+module_init(init);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio console driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index edb7002a321..7a5badfb7d8 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -99,6 +99,7 @@
#include <linux/pm.h>
#include <linux/font.h>
#include <linux/bitops.h>
+#include <linux/notifier.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -158,7 +159,7 @@ static void blank_screen_t(unsigned long dummy);
static void set_palette(struct vc_data *vc);
static int printable; /* Is console ready for printing? */
-static int default_utf8;
+int default_utf8 = true;
module_param(default_utf8, int, S_IRUGO | S_IWUSR);
/*
@@ -223,6 +224,35 @@ enum {
};
/*
+ * Notifier list for console events.
+ */
+static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);
+
+int register_vt_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&vt_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_vt_notifier);
+
+int unregister_vt_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&vt_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_vt_notifier);
+
+static void notify_write(struct vc_data *vc, unsigned int unicode)
+{
+ struct vt_notifier_param param = { .vc = vc, unicode = unicode };
+ atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, &param);
+}
+
+static void notify_update(struct vc_data *vc)
+{
+ struct vt_notifier_param param = { .vc = vc };
+ atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param);
+}
+
+/*
* Low-Level Functions
*/
@@ -718,6 +748,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
return -ENXIO;
if (!vc_cons[currcons].d) {
struct vc_data *vc;
+ struct vt_notifier_param param;
/* prevent users from taking too much memory */
if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
@@ -729,7 +760,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
/* although the numbers above are not valid since long ago, the
point is still up-to-date and the comment still has its value
even if only as a historical artifact. --mj, July 1998 */
- vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
+ param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
if (!vc)
return -ENOMEM;
vc_cons[currcons].d = vc;
@@ -746,17 +777,20 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
}
vc->vc_kmalloced = 1;
vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
+ atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
}
return 0;
}
-static inline int resize_screen(struct vc_data *vc, int width, int height)
+static inline int resize_screen(struct vc_data *vc, int width, int height,
+ int user)
{
/* Resizes the resolution of the display adapater */
int err = 0;
if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
- err = vc->vc_sw->con_resize(vc, width, height);
+ err = vc->vc_sw->con_resize(vc, width, height, user);
+
return err;
}
@@ -772,7 +806,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
unsigned int old_cols, old_rows, old_row_size, old_screen_size;
unsigned int new_cols, new_rows, new_row_size, new_screen_size;
- unsigned int end;
+ unsigned int end, user;
unsigned short *newscreen;
WARN_CONSOLE_UNLOCKED();
@@ -780,6 +814,9 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
if (!vc)
return -ENXIO;
+ user = vc->vc_resize_user;
+ vc->vc_resize_user = 0;
+
if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
return -EINVAL;
@@ -800,7 +837,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
old_row_size = vc->vc_size_row;
old_screen_size = vc->vc_screenbuf_size;
- err = resize_screen(vc, new_cols, new_rows);
+ err = resize_screen(vc, new_cols, new_rows, user);
if (err) {
kfree(newscreen);
return err;
@@ -902,6 +939,8 @@ void vc_deallocate(unsigned int currcons)
if (vc_cons_allocated(currcons)) {
struct vc_data *vc = vc_cons[currcons].d;
+ struct vt_notifier_param param = { .vc = vc };
+ atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
vc->vc_sw->con_deinit(vc);
put_pid(vc->vt_pid);
module_put(vc->vc_sw->owner);
@@ -1014,6 +1053,7 @@ static void lf(struct vc_data *vc)
vc->vc_pos += vc->vc_size_row;
}
vc->vc_need_wrap = 0;
+ notify_write(vc, '\n');
}
static void ri(struct vc_data *vc)
@@ -1034,6 +1074,7 @@ static inline void cr(struct vc_data *vc)
{
vc->vc_pos -= vc->vc_x << 1;
vc->vc_need_wrap = vc->vc_x = 0;
+ notify_write(vc, '\r');
}
static inline void bs(struct vc_data *vc)
@@ -1042,6 +1083,7 @@ static inline void bs(struct vc_data *vc)
vc->vc_pos -= 2;
vc->vc_x--;
vc->vc_need_wrap = 0;
+ notify_write(vc, '\b');
}
}
@@ -1588,6 +1630,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
break;
}
vc->vc_pos += (vc->vc_x << 1);
+ notify_write(vc, '\t');
return;
case 10: case 11: case 12:
lf(vc);
@@ -2247,6 +2290,7 @@ rescan_last_byte:
tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
if (tc < 0) tc = ' ';
}
+ notify_write(vc, c);
if (inverse) {
FLUSH
@@ -2269,6 +2313,7 @@ rescan_last_byte:
release_console_sem();
out:
+ notify_update(vc);
return n;
#undef FLUSH
}
@@ -2312,6 +2357,7 @@ static void console_callback(struct work_struct *ignored)
do_blank_screen(0);
blank_timer_expired = 0;
}
+ notify_update(vc_cons[fg_console].d);
release_console_sem();
}
@@ -2413,6 +2459,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
continue;
}
scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
+ notify_write(vc, c);
cnt++;
if (myx == vc->vc_cols - 1) {
vc->vc_need_wrap = 1;
@@ -2431,6 +2478,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count)
}
}
set_cursor(vc);
+ notify_update(vc);
quit:
clear_bit(0, &printing);
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index 7a61a2a9aaf..e6f89e8b925 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -23,6 +23,7 @@
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/console.h>
+#include <linux/consolemap.h>
#include <linux/signal.h>
#include <linux/timex.h>
@@ -582,10 +583,27 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KDGKBDIACR:
{
struct kbdiacrs __user *a = up;
+ struct kbdiacr diacr;
+ int i;
if (put_user(accent_table_size, &a->kb_cnt))
return -EFAULT;
- if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr)))
+ for (i = 0; i < accent_table_size; i++) {
+ diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
+ diacr.base = conv_uni_to_8bit(accent_table[i].base);
+ diacr.result = conv_uni_to_8bit(accent_table[i].result);
+ if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr)))
+ return -EFAULT;
+ }
+ return 0;
+ }
+ case KDGKBDIACRUC:
+ {
+ struct kbdiacrsuc __user *a = up;
+
+ if (put_user(accent_table_size, &a->kb_cnt))
+ return -EFAULT;
+ if (copy_to_user(a->kbdiacruc, accent_table, accent_table_size*sizeof(struct kbdiacruc)))
return -EFAULT;
return 0;
}
@@ -593,6 +611,30 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KDSKBDIACR:
{
struct kbdiacrs __user *a = up;
+ struct kbdiacr diacr;
+ unsigned int ct;
+ int i;
+
+ if (!perm)
+ return -EPERM;
+ if (get_user(ct,&a->kb_cnt))
+ return -EFAULT;
+ if (ct >= MAX_DIACR)
+ return -EINVAL;
+ accent_table_size = ct;
+ for (i = 0; i < ct; i++) {
+ if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr)))
+ return -EFAULT;
+ accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
+ accent_table[i].base = conv_8bit_to_uni(diacr.base);
+ accent_table[i].result = conv_8bit_to_uni(diacr.result);
+ }
+ return 0;
+ }
+
+ case KDSKBDIACRUC:
+ {
+ struct kbdiacrsuc __user *a = up;
unsigned int ct;
if (!perm)
@@ -602,7 +644,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (ct >= MAX_DIACR)
return -EINVAL;
accent_table_size = ct;
- if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr)))
+ if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
return -EFAULT;
return 0;
}
@@ -847,14 +889,24 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case VT_RESIZE:
{
struct vt_sizes __user *vtsizes = up;
+ struct vc_data *vc;
+
ushort ll,cc;
if (!perm)
return -EPERM;
if (get_user(ll, &vtsizes->v_rows) ||
get_user(cc, &vtsizes->v_cols))
return -EFAULT;
- for (i = 0; i < MAX_NR_CONSOLES; i++)
- vc_lock_resize(vc_cons[i].d, cc, ll);
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ vc = vc_cons[i].d;
+
+ if (vc) {
+ vc->vc_resize_user = 1;
+ vc_lock_resize(vc_cons[i].d, cc, ll);
+ }
+ }
+
return 0;
}
@@ -900,6 +952,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
vc_cons[i].d->vc_scan_lines = vlin;
if (clin)
vc_cons[i].d->vc_font.height = clin;
+ vc_cons[i].d->vc_resize_user = 1;
vc_resize(vc_cons[i].d, cc, ll);
release_console_sem();
}
@@ -1072,7 +1125,7 @@ int vt_waitactive(int vt)
void reset_vc(struct vc_data *vc)
{
vc->vc_mode = KD_TEXT;
- kbd_table[vc->vc_num].kbdmode = VC_XLATE;
+ kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
vc->vt_mode.mode = VT_AUTO;
vc->vt_mode.waitv = 0;
vc->vt_mode.relsig = 0;
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index a7b9e9bb3e8..6883fcb79ad 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -218,7 +218,7 @@ static void cn_rx_skb(struct sk_buff *__skb)
skb->len < nlh->nlmsg_len ||
nlh->nlmsg_len > CONNECTOR_MAX_MSG_SIZE) {
kfree_skb(skb);
- goto out;
+ return;
}
len = NLMSG_ALIGN(nlh->nlmsg_len);
@@ -229,21 +229,6 @@ static void cn_rx_skb(struct sk_buff *__skb)
if (err < 0)
kfree_skb(skb);
}
-
-out:
- kfree_skb(__skb);
-}
-
-/*
- * Netlink socket input callback - dequeues the skbs and calls the
- * main netlink receiving function.
- */
-static void cn_input(struct sock *sk, int len)
-{
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
- cn_rx_skb(skb);
}
/*
@@ -442,11 +427,11 @@ static int __devinit cn_init(void)
struct cn_dev *dev = &cdev;
int err;
- dev->input = cn_input;
+ dev->input = cn_rx_skb;
dev->id.idx = cn_idx;
dev->id.val = cn_val;
- dev->nls = netlink_kernel_create(NETLINK_CONNECTOR,
+ dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR,
CN_NETLINK_USERS + 0xf,
dev->input, NULL, THIS_MODULE);
if (!dev->nls)
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 993fa7b8925..721f86f4f00 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -56,10 +56,6 @@ config CPU_FREQ_STAT_DETAILS
If in doubt, say N.
-# Note that it is not currently possible to set the other governors (such as ondemand)
-# as the default, since if they fail to initialise, cpufreq will be
-# left in an undefined state.
-
choice
prompt "Default CPUFreq governor"
default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
@@ -85,6 +81,29 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE
program shall be able to set the CPU dynamically without having
to enable the userspace governor manually.
+config CPU_FREQ_DEFAULT_GOV_ONDEMAND
+ bool "ondemand"
+ select CPU_FREQ_GOV_ONDEMAND
+ select CPU_FREQ_GOV_PERFORMANCE
+ help
+ Use the CPUFreq governor 'ondemand' as default. This allows
+ you to get a full dynamic frequency capable system by simply
+ loading your cpufreq low-level hardware driver.
+ Be aware that not all cpufreq drivers support the ondemand
+ governor. If unsure have a look at the help section of the
+ driver. Fallback governor will be the performance governor.
+
+config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
+ bool "conservative"
+ select CPU_FREQ_GOV_CONSERVATIVE
+ select CPU_FREQ_GOV_PERFORMANCE
+ help
+ Use the CPUFreq governor 'conservative' as default. This allows
+ you to get a full dynamic frequency capable system by simply
+ loading your cpufreq low-level hardware driver.
+ Be aware that not all cpufreq drivers support the conservative
+ governor. If unsure have a look at the help section of the
+ driver. Fallback governor will be the performance governor.
endchoice
config CPU_FREQ_GOV_PERFORMANCE
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 2f6a73c01b7..5e626b12b97 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -763,6 +763,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update);
+ /* Set governor before ->init, so that driver could check it */
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
/* call driver. From then on the cpufreq must be able
* to accept all calls to ->verify and ->setpolicy for this CPU
*/
@@ -828,7 +830,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
/* prepare interface data */
policy->kobj.parent = &sys_dev->kobj;
policy->kobj.ktype = &ktype_cpufreq;
- strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN);
+ kobject_set_name(&policy->kobj, "cpufreq");
ret = kobject_register(&policy->kobj);
if (ret) {
@@ -1109,12 +1111,7 @@ unsigned int cpufreq_quick_get(unsigned int cpu)
unsigned int ret_freq = 0;
if (policy) {
- if (unlikely(lock_policy_rwsem_read(cpu)))
- return ret_freq;
-
ret_freq = policy->cur;
-
- unlock_policy_rwsem_read(cpu);
cpufreq_cpu_put(policy);
}
@@ -1483,6 +1480,31 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
{
int ret;
+ /* Only must be defined when default governor is known to have latency
+ restrictions, like e.g. conservative or ondemand.
+ That this is the case is already ensured in Kconfig
+ */
+#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
+ struct cpufreq_governor *gov = &cpufreq_gov_performance;
+#else
+ struct cpufreq_governor *gov = NULL;
+#endif
+
+ if (policy->governor->max_transition_latency &&
+ policy->cpuinfo.transition_latency >
+ policy->governor->max_transition_latency) {
+ if (!gov)
+ return -EINVAL;
+ else {
+ printk(KERN_WARNING "%s governor failed, too long"
+ " transition latency of HW, fallback"
+ " to %s governor\n",
+ policy->governor->name,
+ gov->name);
+ policy->governor = gov;
+ }
+ }
+
if (!try_module_get(policy->governor->owner))
return -EINVAL;
@@ -1703,7 +1725,7 @@ int cpufreq_update_policy(unsigned int cpu)
}
EXPORT_SYMBOL(cpufreq_update_policy);
-static int cpufreq_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 26f440ccc3f..1bba99747f5 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -37,17 +37,17 @@
#define DEF_FREQUENCY_UP_THRESHOLD (80)
#define DEF_FREQUENCY_DOWN_THRESHOLD (20)
-/*
- * The polling frequency of this governor depends on the capability of
+/*
+ * The polling frequency of this governor depends on the capability of
* the processor. Default polling frequency is 1000 times the transition
- * latency of the processor. The governor will work on any processor with
- * transition latency <= 10mS, using appropriate sampling
+ * latency of the processor. The governor will work on any processor with
+ * transition latency <= 10mS, using appropriate sampling
* rate.
* For CPUs with transition latency > 10mS (mostly drivers
* with CPUFREQ_ETERNAL), this governor will not work.
* All times here are in uS.
*/
-static unsigned int def_sampling_rate;
+static unsigned int def_sampling_rate;
#define MIN_SAMPLING_RATE_RATIO (2)
/* for correct statistics, we need at least 10 ticks between each measure */
#define MIN_STAT_SAMPLING_RATE \
@@ -58,17 +58,17 @@ static unsigned int def_sampling_rate;
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
#define DEF_SAMPLING_DOWN_FACTOR (1)
#define MAX_SAMPLING_DOWN_FACTOR (10)
-#define TRANSITION_LATENCY_LIMIT (10 * 1000)
+#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
static void do_dbs_timer(struct work_struct *work);
struct cpu_dbs_info_s {
- struct cpufreq_policy *cur_policy;
- unsigned int prev_cpu_idle_up;
- unsigned int prev_cpu_idle_down;
- unsigned int enable;
- unsigned int down_skip;
- unsigned int requested_freq;
+ struct cpufreq_policy *cur_policy;
+ unsigned int prev_cpu_idle_up;
+ unsigned int prev_cpu_idle_down;
+ unsigned int enable;
+ unsigned int down_skip;
+ unsigned int requested_freq;
};
static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
@@ -82,24 +82,24 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */
* cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock
* is recursive for the same process. -Venki
*/
-static DEFINE_MUTEX (dbs_mutex);
+static DEFINE_MUTEX (dbs_mutex);
static DECLARE_DELAYED_WORK(dbs_work, do_dbs_timer);
struct dbs_tuners {
- unsigned int sampling_rate;
- unsigned int sampling_down_factor;
- unsigned int up_threshold;
- unsigned int down_threshold;
- unsigned int ignore_nice;
- unsigned int freq_step;
+ unsigned int sampling_rate;
+ unsigned int sampling_down_factor;
+ unsigned int up_threshold;
+ unsigned int down_threshold;
+ unsigned int ignore_nice;
+ unsigned int freq_step;
};
static struct dbs_tuners dbs_tuners_ins = {
- .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
- .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
- .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
- .ignore_nice = 0,
- .freq_step = 5,
+ .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
+ .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD,
+ .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
+ .ignore_nice = 0,
+ .freq_step = 5,
};
static inline unsigned int get_cpu_idle_time(unsigned int cpu)
@@ -109,13 +109,34 @@ static inline unsigned int get_cpu_idle_time(unsigned int cpu)
if (dbs_tuners_ins.ignore_nice)
add_nice = kstat_cpu(cpu).cpustat.nice;
- ret = kstat_cpu(cpu).cpustat.idle +
+ ret = kstat_cpu(cpu).cpustat.idle +
kstat_cpu(cpu).cpustat.iowait +
add_nice;
return ret;
}
+/* keep track of frequency transitions */
+static int
+dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
+ void *data)
+{
+ struct cpufreq_freqs *freq = data;
+ struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cpu_dbs_info,
+ freq->cpu);
+
+ if (!this_dbs_info->enable)
+ return 0;
+
+ this_dbs_info->requested_freq = freq->new;
+
+ return 0;
+}
+
+static struct notifier_block dbs_cpufreq_notifier_block = {
+ .notifier_call = dbs_cpufreq_notifier
+};
+
/************************** sysfs interface ************************/
static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
{
@@ -127,8 +148,8 @@ static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf)
return sprintf (buf, "%u\n", MIN_SAMPLING_RATE);
}
-#define define_one_ro(_name) \
-static struct freq_attr _name = \
+#define define_one_ro(_name) \
+static struct freq_attr _name = \
__ATTR(_name, 0444, show_##_name, NULL)
define_one_ro(sampling_rate_max);
@@ -148,7 +169,7 @@ show_one(down_threshold, down_threshold);
show_one(ignore_nice_load, ignore_nice);
show_one(freq_step, freq_step);
-static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
+static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
const char *buf, size_t count)
{
unsigned int input;
@@ -164,7 +185,7 @@ static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
return count;
}
-static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
+static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
const char *buf, size_t count)
{
unsigned int input;
@@ -183,7 +204,7 @@ static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
return count;
}
-static ssize_t store_up_threshold(struct cpufreq_policy *unused,
+static ssize_t store_up_threshold(struct cpufreq_policy *unused,
const char *buf, size_t count)
{
unsigned int input;
@@ -202,7 +223,7 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
return count;
}
-static ssize_t store_down_threshold(struct cpufreq_policy *unused,
+static ssize_t store_down_threshold(struct cpufreq_policy *unused,
const char *buf, size_t count)
{
unsigned int input;
@@ -228,16 +249,16 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
int ret;
unsigned int j;
-
- ret = sscanf (buf, "%u", &input);
- if ( ret != 1 )
+
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
return -EINVAL;
- if ( input > 1 )
+ if (input > 1)
input = 1;
-
+
mutex_lock(&dbs_mutex);
- if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */
+ if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */
mutex_unlock(&dbs_mutex);
return count;
}
@@ -261,14 +282,14 @@ static ssize_t store_freq_step(struct cpufreq_policy *policy,
unsigned int input;
int ret;
- ret = sscanf (buf, "%u", &input);
+ ret = sscanf(buf, "%u", &input);
- if ( ret != 1 )
+ if (ret != 1)
return -EINVAL;
- if ( input > 100 )
+ if (input > 100)
input = 100;
-
+
/* no need to test here if freq_step is zero as the user might actually
* want this, they would be crazy though :) */
mutex_lock(&dbs_mutex);
@@ -322,18 +343,18 @@ static void dbs_check_cpu(int cpu)
policy = this_dbs_info->cur_policy;
- /*
- * The default safe range is 20% to 80%
+ /*
+ * The default safe range is 20% to 80%
* Every sampling_rate, we check
- * - If current idle time is less than 20%, then we try to
- * increase frequency
+ * - If current idle time is less than 20%, then we try to
+ * increase frequency
* Every sampling_rate*sampling_down_factor, we check
- * - If current idle time is more than 80%, then we try to
- * decrease frequency
+ * - If current idle time is more than 80%, then we try to
+ * decrease frequency
*
- * Any frequency increase takes it to the maximum frequency.
- * Frequency reduction happens at minimum steps of
- * 5% (default) of max_frequency
+ * Any frequency increase takes it to the maximum frequency.
+ * Frequency reduction happens at minimum steps of
+ * 5% (default) of max_frequency
*/
/* Check for frequency increase */
@@ -361,13 +382,13 @@ static void dbs_check_cpu(int cpu)
/* if we are already at full speed then break out early */
if (this_dbs_info->requested_freq == policy->max)
return;
-
+
freq_step = (dbs_tuners_ins.freq_step * policy->max) / 100;
/* max freq cannot be less than 100. But who knows.... */
if (unlikely(freq_step == 0))
freq_step = 5;
-
+
this_dbs_info->requested_freq += freq_step;
if (this_dbs_info->requested_freq > policy->max)
this_dbs_info->requested_freq = policy->max;
@@ -427,15 +448,15 @@ static void dbs_check_cpu(int cpu)
}
static void do_dbs_timer(struct work_struct *work)
-{
+{
int i;
mutex_lock(&dbs_mutex);
for_each_online_cpu(i)
dbs_check_cpu(i);
- schedule_delayed_work(&dbs_work,
+ schedule_delayed_work(&dbs_work,
usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
mutex_unlock(&dbs_mutex);
-}
+}
static inline void dbs_timer_init(void)
{
@@ -462,16 +483,12 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
switch (event) {
case CPUFREQ_GOV_START:
- if ((!cpu_online(cpu)) ||
- (!policy->cur))
+ if ((!cpu_online(cpu)) || (!policy->cur))
return -EINVAL;
- if (policy->cpuinfo.transition_latency >
- (TRANSITION_LATENCY_LIMIT * 1000))
- return -EINVAL;
if (this_dbs_info->enable) /* Already enabled */
break;
-
+
mutex_lock(&dbs_mutex);
rc = sysfs_create_group(&policy->kobj, &dbs_attr_group);
@@ -484,7 +501,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
struct cpu_dbs_info_s *j_dbs_info;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
j_dbs_info->cur_policy = policy;
-
+
j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(cpu);
j_dbs_info->prev_cpu_idle_down
= j_dbs_info->prev_cpu_idle_up;
@@ -514,8 +531,11 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
dbs_tuners_ins.sampling_rate = def_sampling_rate;
dbs_timer_init();
+ cpufreq_register_notifier(
+ &dbs_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
}
-
+
mutex_unlock(&dbs_mutex);
break;
@@ -528,9 +548,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
* Stop the timerschedule work, when this governor
* is used for first time
*/
- if (dbs_enable == 0)
+ if (dbs_enable == 0) {
dbs_timer_exit();
-
+ cpufreq_unregister_notifier(
+ &dbs_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ }
+
mutex_unlock(&dbs_mutex);
break;
@@ -540,26 +564,28 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
if (policy->max < this_dbs_info->cur_policy->cur)
__cpufreq_driver_target(
this_dbs_info->cur_policy,
- policy->max, CPUFREQ_RELATION_H);
+ policy->max, CPUFREQ_RELATION_H);
else if (policy->min > this_dbs_info->cur_policy->cur)
__cpufreq_driver_target(
this_dbs_info->cur_policy,
- policy->min, CPUFREQ_RELATION_L);
+ policy->min, CPUFREQ_RELATION_L);
mutex_unlock(&dbs_mutex);
break;
}
return 0;
}
-static struct cpufreq_governor cpufreq_gov_dbs = {
- .name = "conservative",
- .governor = cpufreq_governor_dbs,
- .owner = THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_conservative = {
+ .name = "conservative",
+ .governor = cpufreq_governor_dbs,
+ .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+ .owner = THIS_MODULE,
};
+EXPORT_SYMBOL(cpufreq_gov_conservative);
static int __init cpufreq_gov_dbs_init(void)
{
- return cpufreq_register_governor(&cpufreq_gov_dbs);
+ return cpufreq_register_governor(&cpufreq_gov_conservative);
}
static void __exit cpufreq_gov_dbs_exit(void)
@@ -567,7 +593,7 @@ static void __exit cpufreq_gov_dbs_exit(void)
/* Make sure that the scheduled work is indeed not running */
flush_scheduled_work();
- cpufreq_unregister_governor(&cpufreq_gov_dbs);
+ cpufreq_unregister_governor(&cpufreq_gov_conservative);
}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index e794527e492..369f4459515 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -47,7 +47,7 @@ static unsigned int def_sampling_rate;
(def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
#define MAX_SAMPLING_RATE (500 * def_sampling_rate)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
-#define TRANSITION_LATENCY_LIMIT (10 * 1000)
+#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
static void do_dbs_timer(struct work_struct *work);
@@ -508,12 +508,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
if ((!cpu_online(cpu)) || (!policy->cur))
return -EINVAL;
- if (policy->cpuinfo.transition_latency >
- (TRANSITION_LATENCY_LIMIT * 1000)) {
- printk(KERN_WARNING "ondemand governor failed to load "
- "due to too long transition latency\n");
- return -EINVAL;
- }
if (this_dbs_info->enable) /* Already enabled */
break;
@@ -585,11 +579,13 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
}
-static struct cpufreq_governor cpufreq_gov_dbs = {
- .name = "ondemand",
- .governor = cpufreq_governor_dbs,
- .owner = THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_ondemand = {
+ .name = "ondemand",
+ .governor = cpufreq_governor_dbs,
+ .max_transition_latency = TRANSITION_LATENCY_LIMIT,
+ .owner = THIS_MODULE,
};
+EXPORT_SYMBOL(cpufreq_gov_ondemand);
static int __init cpufreq_gov_dbs_init(void)
{
@@ -598,12 +594,12 @@ static int __init cpufreq_gov_dbs_init(void)
printk(KERN_ERR "Creation of kondemand failed\n");
return -EFAULT;
}
- return cpufreq_register_governor(&cpufreq_gov_dbs);
+ return cpufreq_register_governor(&cpufreq_gov_ondemand);
}
static void __exit cpufreq_gov_dbs_exit(void)
{
- cpufreq_unregister_governor(&cpufreq_gov_dbs);
+ cpufreq_unregister_governor(&cpufreq_gov_ondemand);
destroy_workqueue(kondemand_wq);
}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 917b9bab9cc..8a45d0f93e2 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -164,8 +164,7 @@ freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
return -1;
}
-static void
-cpufreq_stats_free_table (unsigned int cpu)
+static void __cpuexit cpufreq_stats_free_table(unsigned int cpu)
{
struct cpufreq_stats *stat = cpufreq_stats_table[cpu];
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
@@ -305,8 +304,9 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val,
return 0;
}
-static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
+static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
+ unsigned long action,
+ void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
@@ -323,7 +323,7 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block cpufreq_stat_cpu_notifier =
+static struct notifier_block cpufreq_stat_cpu_notifier __cpuinitdata =
{
.notifier_call = cpufreq_stat_cpu_callback,
};
@@ -356,8 +356,7 @@ __init cpufreq_stats_init(void)
register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) {
- cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
- CPU_ONLINE, (void *)(long)cpu);
+ cpufreq_update_policy(cpu);
}
return 0;
}
@@ -372,13 +371,12 @@ __exit cpufreq_stats_exit(void)
CPUFREQ_TRANSITION_NOTIFIER);
unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) {
- cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
- CPU_DEAD, (void *)(long)cpu);
+ cpufreq_stats_free_table(cpu);
}
}
MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");
-MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats"
+MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats "
"through sysfs filesystem");
MODULE_LICENSE ("GPL");
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index c0fc4aeb859..5fd6688a444 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -14,7 +14,6 @@ config CRYPTO_DEV_PADLOCK
tristate "Support for VIA PadLock ACE"
depends on X86_32
select CRYPTO_ALGAPI
- default m
help
Some VIA processors come with an integrated crypto engine
(so called VIA PadLock ACE, Advanced Cryptography Engine)
@@ -28,7 +27,6 @@ config CRYPTO_DEV_PADLOCK_AES
tristate "PadLock driver for AES algorithm"
depends on CRYPTO_DEV_PADLOCK
select CRYPTO_BLKCIPHER
- default m
help
Use VIA PadLock for AES algorithm.
@@ -42,7 +40,6 @@ config CRYPTO_DEV_PADLOCK_SHA
depends on CRYPTO_DEV_PADLOCK
select CRYPTO_SHA1
select CRYPTO_SHA256
- default m
help
Use VIA PadLock for SHA1/SHA256 algorithms.
@@ -58,7 +55,6 @@ config CRYPTO_DEV_GEODE
depends on X86_32 && PCI
select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
- default m
help
Say 'Y' here to use the AMD Geode LX processor on-board AES
engine for the CryptoAPI AES algorithm.
@@ -70,7 +66,6 @@ config ZCRYPT
tristate "Support for PCI-attached cryptographic adapters"
depends on S390
select ZCRYPT_MONOLITHIC if ZCRYPT="y"
- default "m"
help
Select this option if you want to use a PCI-attached cryptographic
adapter like:
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c
index 6a86958b577..711e246e1ef 100644
--- a/drivers/crypto/geode-aes.c
+++ b/drivers/crypto/geode-aes.c
@@ -110,8 +110,7 @@ geode_aes_crypt(struct geode_aes_op *op)
* we don't need to worry
*/
- if (op->src == op->dst)
- flags |= (AES_CTRL_DCA | AES_CTRL_SCA);
+ flags |= (AES_CTRL_DCA | AES_CTRL_SCA);
if (op->dir == AES_DIR_ENCRYPT)
flags |= AES_CTRL_ENCRYPT;
@@ -473,6 +472,7 @@ geode_aes_exit(void)
MODULE_AUTHOR("Advanced Micro Devices, Inc.");
MODULE_DESCRIPTION("Geode LX Hardware AES driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("aes");
module_init(geode_aes_init);
module_exit(geode_aes_exit);
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index d4501dc7e65..abbcff0762b 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -5,7 +5,7 @@
*
* Copyright (c) 2004 Michal Ludvig <michal@logix.cz>
*
- * Key expansion routine taken from crypto/aes.c
+ * Key expansion routine taken from crypto/aes_generic.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -660,4 +660,4 @@ MODULE_DESCRIPTION("VIA PadLock AES algorithm support");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michal Ludvig");
-MODULE_ALIAS("aes-padlock");
+MODULE_ALIAS("aes");
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index a781fd23b60..c666b4e0933 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -13,6 +13,7 @@
*/
#include <crypto/algapi.h>
+#include <crypto/sha.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -24,12 +25,7 @@
#include "padlock.h"
#define SHA1_DEFAULT_FALLBACK "sha1-generic"
-#define SHA1_DIGEST_SIZE 20
-#define SHA1_HMAC_BLOCK_SIZE 64
-
#define SHA256_DEFAULT_FALLBACK "sha256-generic"
-#define SHA256_DIGEST_SIZE 32
-#define SHA256_HMAC_BLOCK_SIZE 64
struct padlock_sha_ctx {
char *data;
@@ -59,7 +55,7 @@ static void padlock_sha_bypass(struct crypto_tfm *tfm)
if (ctx(tfm)->data && ctx(tfm)->used) {
struct scatterlist sg;
- sg_set_buf(&sg, ctx(tfm)->data, ctx(tfm)->used);
+ sg_init_one(&sg, ctx(tfm)->data, ctx(tfm)->used);
crypto_hash_update(&ctx(tfm)->fallback, &sg, sg.length);
}
@@ -83,7 +79,7 @@ static void padlock_sha_update(struct crypto_tfm *tfm,
if (unlikely(ctx(tfm)->bypass)) {
struct scatterlist sg;
- sg_set_buf(&sg, (uint8_t *)data, length);
+ sg_init_one(&sg, (uint8_t *)data, length);
crypto_hash_update(&ctx(tfm)->fallback, &sg, length);
return;
}
@@ -107,11 +103,11 @@ static void padlock_do_sha1(const char *in, char *out, int count)
char buf[128+16];
char *result = NEAREST_ALIGNED(buf);
- ((uint32_t *)result)[0] = 0x67452301;
- ((uint32_t *)result)[1] = 0xEFCDAB89;
- ((uint32_t *)result)[2] = 0x98BADCFE;
- ((uint32_t *)result)[3] = 0x10325476;
- ((uint32_t *)result)[4] = 0xC3D2E1F0;
+ ((uint32_t *)result)[0] = SHA1_H0;
+ ((uint32_t *)result)[1] = SHA1_H1;
+ ((uint32_t *)result)[2] = SHA1_H2;
+ ((uint32_t *)result)[3] = SHA1_H3;
+ ((uint32_t *)result)[4] = SHA1_H4;
asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */
: "+S"(in), "+D"(result)
@@ -128,14 +124,14 @@ static void padlock_do_sha256(const char *in, char *out, int count)
char buf[128+16];
char *result = NEAREST_ALIGNED(buf);
- ((uint32_t *)result)[0] = 0x6A09E667;
- ((uint32_t *)result)[1] = 0xBB67AE85;
- ((uint32_t *)result)[2] = 0x3C6EF372;
- ((uint32_t *)result)[3] = 0xA54FF53A;
- ((uint32_t *)result)[4] = 0x510E527F;
- ((uint32_t *)result)[5] = 0x9B05688C;
- ((uint32_t *)result)[6] = 0x1F83D9AB;
- ((uint32_t *)result)[7] = 0x5BE0CD19;
+ ((uint32_t *)result)[0] = SHA256_H0;
+ ((uint32_t *)result)[1] = SHA256_H1;
+ ((uint32_t *)result)[2] = SHA256_H2;
+ ((uint32_t *)result)[3] = SHA256_H3;
+ ((uint32_t *)result)[4] = SHA256_H4;
+ ((uint32_t *)result)[5] = SHA256_H5;
+ ((uint32_t *)result)[6] = SHA256_H6;
+ ((uint32_t *)result)[7] = SHA256_H7;
asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */
: "+S"(in), "+D"(result)
@@ -215,7 +211,7 @@ static struct crypto_alg sha1_alg = {
.cra_priority = PADLOCK_CRA_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_DIGEST |
CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA1_HMAC_BLOCK_SIZE,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct padlock_sha_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(sha1_alg.cra_list),
@@ -237,7 +233,7 @@ static struct crypto_alg sha256_alg = {
.cra_priority = PADLOCK_CRA_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_DIGEST |
CRYPTO_ALG_NEED_FALLBACK,
- .cra_blocksize = SHA256_HMAC_BLOCK_SIZE,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct padlock_sha_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(sha256_alg.cra_list),
@@ -253,19 +249,6 @@ static struct crypto_alg sha256_alg = {
}
};
-static void __init padlock_sha_check_fallbacks(void)
-{
- if (!crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK))
- printk(KERN_WARNING PFX
- "Couldn't load fallback module for sha1.\n");
-
- if (!crypto_has_hash("sha256", 0, CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK))
- printk(KERN_WARNING PFX
- "Couldn't load fallback module for sha256.\n");
-}
-
static int __init padlock_init(void)
{
int rc = -ENODEV;
@@ -280,8 +263,6 @@ static int __init padlock_init(void)
return -ENODEV;
}
- padlock_sha_check_fallbacks();
-
rc = crypto_register_alg(&sha1_alg);
if (rc)
goto out;
@@ -314,5 +295,7 @@ MODULE_DESCRIPTION("VIA PadLock SHA1/SHA256 algorithms support.");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michal Ludvig");
+MODULE_ALIAS("sha1");
+MODULE_ALIAS("sha256");
MODULE_ALIAS("sha1-padlock");
MODULE_ALIAS("sha256-padlock");
diff --git a/drivers/dca/Kconfig b/drivers/dca/Kconfig
new file mode 100644
index 00000000000..94f0364a0ef
--- /dev/null
+++ b/drivers/dca/Kconfig
@@ -0,0 +1,7 @@
+#
+# DCA server configuration
+#
+
+config DCA
+ tristate
+
diff --git a/drivers/dca/Makefile b/drivers/dca/Makefile
new file mode 100644
index 00000000000..b2db56bb9dd
--- /dev/null
+++ b/drivers/dca/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_DCA) += dca.o
+dca-objs := dca-core.o dca-sysfs.o
diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c
new file mode 100644
index 00000000000..bf5b92f86df
--- /dev/null
+++ b/drivers/dca/dca-core.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright(c) 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+
+/*
+ * This driver supports an interface for DCA clients and providers to meet.
+ */
+
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#include <linux/device.h>
+#include <linux/dca.h>
+
+MODULE_LICENSE("GPL");
+
+/* For now we're assuming a single, global, DCA provider for the system. */
+
+static DEFINE_SPINLOCK(dca_lock);
+
+static struct dca_provider *global_dca = NULL;
+
+/**
+ * dca_add_requester - add a dca client to the list
+ * @dev - the device that wants dca service
+ */
+int dca_add_requester(struct device *dev)
+{
+ int err, slot;
+
+ if (!global_dca)
+ return -ENODEV;
+
+ spin_lock(&dca_lock);
+ slot = global_dca->ops->add_requester(global_dca, dev);
+ spin_unlock(&dca_lock);
+ if (slot < 0)
+ return slot;
+
+ err = dca_sysfs_add_req(global_dca, dev, slot);
+ if (err) {
+ spin_lock(&dca_lock);
+ global_dca->ops->remove_requester(global_dca, dev);
+ spin_unlock(&dca_lock);
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dca_add_requester);
+
+/**
+ * dca_remove_requester - remove a dca client from the list
+ * @dev - the device that wants dca service
+ */
+int dca_remove_requester(struct device *dev)
+{
+ int slot;
+ if (!global_dca)
+ return -ENODEV;
+
+ spin_lock(&dca_lock);
+ slot = global_dca->ops->remove_requester(global_dca, dev);
+ spin_unlock(&dca_lock);
+ if (slot < 0)
+ return slot;
+
+ dca_sysfs_remove_req(global_dca, slot);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dca_remove_requester);
+
+/**
+ * dca_get_tag - return the dca tag for the given cpu
+ * @cpu - the cpuid as returned by get_cpu()
+ */
+u8 dca_get_tag(int cpu)
+{
+ if (!global_dca)
+ return -ENODEV;
+ return global_dca->ops->get_tag(global_dca, cpu);
+}
+EXPORT_SYMBOL_GPL(dca_get_tag);
+
+/**
+ * alloc_dca_provider - get data struct for describing a dca provider
+ * @ops - pointer to struct of dca operation function pointers
+ * @priv_size - size of extra mem to be added for provider's needs
+ */
+struct dca_provider *alloc_dca_provider(struct dca_ops *ops, int priv_size)
+{
+ struct dca_provider *dca;
+ int alloc_size;
+
+ alloc_size = (sizeof(*dca) + priv_size);
+ dca = kzalloc(alloc_size, GFP_KERNEL);
+ if (!dca)
+ return NULL;
+ dca->ops = ops;
+
+ return dca;
+}
+EXPORT_SYMBOL_GPL(alloc_dca_provider);
+
+/**
+ * free_dca_provider - release the dca provider data struct
+ * @ops - pointer to struct of dca operation function pointers
+ * @priv_size - size of extra mem to be added for provider's needs
+ */
+void free_dca_provider(struct dca_provider *dca)
+{
+ kfree(dca);
+}
+EXPORT_SYMBOL_GPL(free_dca_provider);
+
+static BLOCKING_NOTIFIER_HEAD(dca_provider_chain);
+
+/**
+ * register_dca_provider - register a dca provider
+ * @dca - struct created by alloc_dca_provider()
+ * @dev - device providing dca services
+ */
+int register_dca_provider(struct dca_provider *dca, struct device *dev)
+{
+ int err;
+
+ if (global_dca)
+ return -EEXIST;
+ err = dca_sysfs_add_provider(dca, dev);
+ if (err)
+ return err;
+ global_dca = dca;
+ blocking_notifier_call_chain(&dca_provider_chain,
+ DCA_PROVIDER_ADD, NULL);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(register_dca_provider);
+
+/**
+ * unregister_dca_provider - remove a dca provider
+ * @dca - struct created by alloc_dca_provider()
+ */
+void unregister_dca_provider(struct dca_provider *dca)
+{
+ if (!global_dca)
+ return;
+ blocking_notifier_call_chain(&dca_provider_chain,
+ DCA_PROVIDER_REMOVE, NULL);
+ global_dca = NULL;
+ dca_sysfs_remove_provider(dca);
+}
+EXPORT_SYMBOL_GPL(unregister_dca_provider);
+
+/**
+ * dca_register_notify - register a client's notifier callback
+ */
+void dca_register_notify(struct notifier_block *nb)
+{
+ blocking_notifier_chain_register(&dca_provider_chain, nb);
+}
+EXPORT_SYMBOL_GPL(dca_register_notify);
+
+/**
+ * dca_unregister_notify - remove a client's notifier callback
+ */
+void dca_unregister_notify(struct notifier_block *nb)
+{
+ blocking_notifier_chain_unregister(&dca_provider_chain, nb);
+}
+EXPORT_SYMBOL_GPL(dca_unregister_notify);
+
+static int __init dca_init(void)
+{
+ return dca_sysfs_init();
+}
+
+static void __exit dca_exit(void)
+{
+ dca_sysfs_exit();
+}
+
+module_init(dca_init);
+module_exit(dca_exit);
+
diff --git a/drivers/dca/dca-sysfs.c b/drivers/dca/dca-sysfs.c
new file mode 100644
index 00000000000..24a263b6844
--- /dev/null
+++ b/drivers/dca/dca-sysfs.c
@@ -0,0 +1,88 @@
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/idr.h>
+#include <linux/kdev_t.h>
+#include <linux/err.h>
+#include <linux/dca.h>
+
+static struct class *dca_class;
+static struct idr dca_idr;
+static spinlock_t dca_idr_lock;
+
+int dca_sysfs_add_req(struct dca_provider *dca, struct device *dev, int slot)
+{
+ struct class_device *cd;
+
+ cd = class_device_create(dca_class, dca->cd, MKDEV(0, slot + 1),
+ dev, "requester%d", slot);
+ if (IS_ERR(cd))
+ return PTR_ERR(cd);
+ return 0;
+}
+
+void dca_sysfs_remove_req(struct dca_provider *dca, int slot)
+{
+ class_device_destroy(dca_class, MKDEV(0, slot + 1));
+}
+
+int dca_sysfs_add_provider(struct dca_provider *dca, struct device *dev)
+{
+ struct class_device *cd;
+ int err = 0;
+
+idr_try_again:
+ if (!idr_pre_get(&dca_idr, GFP_KERNEL))
+ return -ENOMEM;
+ spin_lock(&dca_idr_lock);
+ err = idr_get_new(&dca_idr, dca, &dca->id);
+ spin_unlock(&dca_idr_lock);
+ switch (err) {
+ case 0:
+ break;
+ case -EAGAIN:
+ goto idr_try_again;
+ default:
+ return err;
+ }
+
+ cd = class_device_create(dca_class, NULL, MKDEV(0, 0),
+ dev, "dca%d", dca->id);
+ if (IS_ERR(cd)) {
+ spin_lock(&dca_idr_lock);
+ idr_remove(&dca_idr, dca->id);
+ spin_unlock(&dca_idr_lock);
+ return PTR_ERR(cd);
+ }
+ dca->cd = cd;
+ return 0;
+}
+
+void dca_sysfs_remove_provider(struct dca_provider *dca)
+{
+ class_device_unregister(dca->cd);
+ dca->cd = NULL;
+ spin_lock(&dca_idr_lock);
+ idr_remove(&dca_idr, dca->id);
+ spin_unlock(&dca_idr_lock);
+}
+
+int __init dca_sysfs_init(void)
+{
+ idr_init(&dca_idr);
+ spin_lock_init(&dca_idr_lock);
+
+ dca_class = class_create(THIS_MODULE, "dca");
+ if (IS_ERR(dca_class)) {
+ idr_destroy(&dca_idr);
+ return PTR_ERR(dca_class);
+ }
+ return 0;
+}
+
+void __exit dca_sysfs_exit(void)
+{
+ class_destroy(dca_class);
+ idr_destroy(&dca_idr);
+}
+
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 8f670dae53b..6a7d25fc247 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -2,42 +2,51 @@
# DMA engine configuration
#
-menu "DMA Engine support"
- depends on HAS_DMA
+menuconfig DMADEVICES
+ bool "DMA Offload Engine support"
+ depends on (PCI && X86) || ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX
+ help
+ Intel(R) offload engines enable offloading memory copies in the
+ network stack and RAID operations in the MD driver.
+
+if DMADEVICES
+
+comment "DMA Devices"
+
+config INTEL_IOATDMA
+ tristate "Intel I/OAT DMA support"
+ depends on PCI && X86
+ select DMA_ENGINE
+ select DCA
+ help
+ Enable support for the Intel(R) I/OAT DMA engine present
+ in recent Intel Xeon chipsets.
+
+ Say Y here if you have such a chipset.
+
+ If unsure, say N.
+
+config INTEL_IOP_ADMA
+ tristate "Intel IOP ADMA support"
+ depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX
+ select ASYNC_CORE
+ select DMA_ENGINE
+ help
+ Enable support for the Intel(R) IOP Series RAID engines.
config DMA_ENGINE
- bool "Support for DMA engines"
- ---help---
- DMA engines offload bulk memory operations from the CPU to dedicated
- hardware, allowing the operations to happen asynchronously.
+ bool
comment "DMA Clients"
+ depends on DMA_ENGINE
config NET_DMA
bool "Network: TCP receive copy offload"
depends on DMA_ENGINE && NET
- default y
- ---help---
+ help
This enables the use of DMA engines in the network stack to
offload receive copy-to-user operations, freeing CPU cycles.
Since this is the main user of the DMA engine, it should be enabled;
say Y here.
-comment "DMA Devices"
-
-config INTEL_IOATDMA
- tristate "Intel I/OAT DMA support"
- depends on DMA_ENGINE && PCI
- default m
- ---help---
- Enable support for the Intel(R) I/OAT DMA engine.
-
-config INTEL_IOP_ADMA
- tristate "Intel IOP ADMA support"
- depends on DMA_ENGINE && (ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX)
- select ASYNC_CORE
- default m
- ---help---
- Enable support for the Intel(R) IOP Series RAID engines.
-
-endmenu
+endif
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index b3839b687ae..b152cd84e12 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
obj-$(CONFIG_NET_DMA) += iovlock.o
obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o
+ioatdma-objs := ioat.o ioat_dma.o ioat_dca.o
obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 82489923af0..d59b2f41730 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -182,10 +182,9 @@ static void dma_client_chan_alloc(struct dma_client *client)
/* we are done once this client rejects
* an available resource
*/
- if (ack == DMA_ACK) {
+ if (ack == DMA_ACK)
dma_chan_get(chan);
- kref_get(&device->refcount);
- } else if (ack == DMA_NAK)
+ else if (ack == DMA_NAK)
return;
}
}
@@ -272,11 +271,8 @@ static void dma_clients_notify_removed(struct dma_chan *chan)
/* client was holding resources for this channel so
* free it
*/
- if (ack == DMA_ACK) {
+ if (ack == DMA_ACK)
dma_chan_put(chan);
- kref_put(&chan->device->refcount,
- dma_async_device_cleanup);
- }
}
mutex_unlock(&dma_list_mutex);
@@ -316,11 +312,8 @@ void dma_async_client_unregister(struct dma_client *client)
ack = client->event_callback(client, chan,
DMA_RESOURCE_REMOVED);
- if (ack == DMA_ACK) {
+ if (ack == DMA_ACK)
dma_chan_put(chan);
- kref_put(&chan->device->refcount,
- dma_async_device_cleanup);
- }
}
list_del(&client->global_node);
@@ -397,6 +390,8 @@ int dma_async_device_register(struct dma_device *device)
goto err_out;
}
+ /* One for the channel, one of the class device */
+ kref_get(&device->refcount);
kref_get(&device->refcount);
kref_init(&chan->refcount);
chan->slow_ref = 0;
diff --git a/drivers/dma/ioat.c b/drivers/dma/ioat.c
new file mode 100644
index 00000000000..16e0fd8facf
--- /dev/null
+++ b/drivers/dma/ioat.c
@@ -0,0 +1,211 @@
+/*
+ * Intel I/OAT DMA Linux driver
+ * Copyright(c) 2007 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You 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".
+ *
+ */
+
+/*
+ * This driver supports an Intel I/OAT DMA engine, which does asynchronous
+ * copy operations.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/dca.h>
+#include "ioatdma.h"
+#include "ioatdma_registers.h"
+#include "ioatdma_hw.h"
+
+MODULE_VERSION(IOAT_DMA_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Intel Corporation");
+
+static struct pci_device_id ioat_pci_tbl[] = {
+ /* I/OAT v1 platforms */
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_CNB) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SCNB) },
+ { PCI_DEVICE(PCI_VENDOR_ID_UNISYS, PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR) },
+
+ /* I/OAT v2 platforms */
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB) },
+ { 0, }
+};
+
+struct ioat_device {
+ struct pci_dev *pdev;
+ void __iomem *iobase;
+ struct ioatdma_device *dma;
+ struct dca_provider *dca;
+};
+
+static int __devinit ioat_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id);
+static void __devexit ioat_remove(struct pci_dev *pdev);
+
+static int ioat_dca_enabled = 1;
+module_param(ioat_dca_enabled, int, 0644);
+MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)");
+
+static int ioat_setup_functionality(struct pci_dev *pdev, void __iomem *iobase)
+{
+ struct ioat_device *device = pci_get_drvdata(pdev);
+ u8 version;
+ int err = 0;
+
+ version = readb(iobase + IOAT_VER_OFFSET);
+ switch (version) {
+ case IOAT_VER_1_2:
+ device->dma = ioat_dma_probe(pdev, iobase);
+ if (device->dma && ioat_dca_enabled)
+ device->dca = ioat_dca_init(pdev, iobase);
+ break;
+ case IOAT_VER_2_0:
+ device->dma = ioat_dma_probe(pdev, iobase);
+ if (device->dma && ioat_dca_enabled)
+ device->dca = ioat2_dca_init(pdev, iobase);
+ break;
+ default:
+ err = -ENODEV;
+ break;
+ }
+ if (!device->dma)
+ err = -ENODEV;
+ return err;
+}
+
+static void ioat_shutdown_functionality(struct pci_dev *pdev)
+{
+ struct ioat_device *device = pci_get_drvdata(pdev);
+
+ dev_err(&pdev->dev, "Removing dma and dca services\n");
+ if (device->dca) {
+ unregister_dca_provider(device->dca);
+ free_dca_provider(device->dca);
+ device->dca = NULL;
+ }
+
+ if (device->dma) {
+ ioat_dma_remove(device->dma);
+ device->dma = NULL;
+ }
+}
+
+static struct pci_driver ioat_pci_driver = {
+ .name = "ioatdma",
+ .id_table = ioat_pci_tbl,
+ .probe = ioat_probe,
+ .shutdown = ioat_shutdown_functionality,
+ .remove = __devexit_p(ioat_remove),
+};
+
+static int __devinit ioat_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ void __iomem *iobase;
+ struct ioat_device *device;
+ unsigned long mmio_start, mmio_len;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ goto err_enable_device;
+
+ err = pci_request_regions(pdev, ioat_pci_driver.name);
+ if (err)
+ goto err_request_regions;
+
+ err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ if (err)
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err)
+ goto err_set_dma_mask;
+
+ err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (err)
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err)
+ goto err_set_dma_mask;
+
+ mmio_start = pci_resource_start(pdev, 0);
+ mmio_len = pci_resource_len(pdev, 0);
+ iobase = ioremap(mmio_start, mmio_len);
+ if (!iobase) {
+ err = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ device = kzalloc(sizeof(*device), GFP_KERNEL);
+ if (!device) {
+ err = -ENOMEM;
+ goto err_kzalloc;
+ }
+ device->pdev = pdev;
+ pci_set_drvdata(pdev, device);
+ device->iobase = iobase;
+
+ pci_set_master(pdev);
+
+ err = ioat_setup_functionality(pdev, iobase);
+ if (err)
+ goto err_version;
+
+ return 0;
+
+err_version:
+ kfree(device);
+err_kzalloc:
+ iounmap(iobase);
+err_ioremap:
+err_set_dma_mask:
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+err_request_regions:
+err_enable_device:
+ return err;
+}
+
+/*
+ * It is unsafe to remove this module: if removed while a requested
+ * dma is outstanding, esp. from tcp, it is possible to hang while
+ * waiting for something that will never finish. However, if you're
+ * feeling lucky, this usually works just fine.
+ */
+static void __devexit ioat_remove(struct pci_dev *pdev)
+{
+ struct ioat_device *device = pci_get_drvdata(pdev);
+
+ ioat_shutdown_functionality(pdev);
+
+ kfree(device);
+}
+
+static int __init ioat_init_module(void)
+{
+ return pci_register_driver(&ioat_pci_driver);
+}
+module_init(ioat_init_module);
+
+static void __exit ioat_exit_module(void)
+{
+ pci_unregister_driver(&ioat_pci_driver);
+}
+module_exit(ioat_exit_module);
diff --git a/drivers/dma/ioat_dca.c b/drivers/dma/ioat_dca.c
new file mode 100644
index 00000000000..0fa8a98051a
--- /dev/null
+++ b/drivers/dma/ioat_dca.c
@@ -0,0 +1,427 @@
+/*
+ * Intel I/OAT DMA Linux driver
+ * Copyright(c) 2007 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You 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".
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/dca.h>
+
+/* either a kernel change is needed, or we need something like this in kernel */
+#ifndef CONFIG_SMP
+#include <asm/smp.h>
+#undef cpu_physical_id
+#define cpu_physical_id(cpu) (cpuid_ebx(1) >> 24)
+#endif
+
+#include "ioatdma.h"
+#include "ioatdma_registers.h"
+
+/*
+ * Bit 16 of a tag map entry is the "valid" bit, if it is set then bits 0:15
+ * contain the bit number of the APIC ID to map into the DCA tag. If the valid
+ * bit is not set, then the value must be 0 or 1 and defines the bit in the tag.
+ */
+#define DCA_TAG_MAP_VALID 0x80
+
+/*
+ * "Legacy" DCA systems do not implement the DCA register set in the
+ * I/OAT device. Software needs direct support for their tag mappings.
+ */
+
+#define APICID_BIT(x) (DCA_TAG_MAP_VALID | (x))
+#define IOAT_TAG_MAP_LEN 8
+
+static u8 ioat_tag_map_BNB[IOAT_TAG_MAP_LEN] = {
+ 1, APICID_BIT(1), APICID_BIT(2), APICID_BIT(2), };
+static u8 ioat_tag_map_SCNB[IOAT_TAG_MAP_LEN] = {
+ 1, APICID_BIT(1), APICID_BIT(2), APICID_BIT(2), };
+static u8 ioat_tag_map_CNB[IOAT_TAG_MAP_LEN] = {
+ 1, APICID_BIT(1), APICID_BIT(3), APICID_BIT(4), APICID_BIT(2), };
+static u8 ioat_tag_map_UNISYS[IOAT_TAG_MAP_LEN] = { 0 };
+
+/* pack PCI B/D/F into a u16 */
+static inline u16 dcaid_from_pcidev(struct pci_dev *pci)
+{
+ return (pci->bus->number << 8) | pci->devfn;
+}
+
+static int dca_enabled_in_bios(struct pci_dev *pdev)
+{
+ /* CPUID level 9 returns DCA configuration */
+ /* Bit 0 indicates DCA enabled by the BIOS */
+ unsigned long cpuid_level_9;
+ int res;
+
+ cpuid_level_9 = cpuid_eax(9);
+ res = test_bit(0, &cpuid_level_9);
+ if (!res)
+ dev_err(&pdev->dev, "DCA is disabled in BIOS\n");
+
+ return res;
+}
+
+static int system_has_dca_enabled(struct pci_dev *pdev)
+{
+ if (boot_cpu_has(X86_FEATURE_DCA))
+ return dca_enabled_in_bios(pdev);
+
+ dev_err(&pdev->dev, "boot cpu doesn't have X86_FEATURE_DCA\n");
+ return 0;
+}
+
+struct ioat_dca_slot {
+ struct pci_dev *pdev; /* requester device */
+ u16 rid; /* requester id, as used by IOAT */
+};
+
+#define IOAT_DCA_MAX_REQ 6
+
+struct ioat_dca_priv {
+ void __iomem *iobase;
+ void *dca_base;
+ int max_requesters;
+ int requester_count;
+ u8 tag_map[IOAT_TAG_MAP_LEN];
+ struct ioat_dca_slot req_slots[0];
+};
+
+/* 5000 series chipset DCA Port Requester ID Table Entry Format
+ * [15:8] PCI-Express Bus Number
+ * [7:3] PCI-Express Device Number
+ * [2:0] PCI-Express Function Number
+ *
+ * 5000 series chipset DCA control register format
+ * [7:1] Reserved (0)
+ * [0] Ignore Function Number
+ */
+
+static int ioat_dca_add_requester(struct dca_provider *dca, struct device *dev)
+{
+ struct ioat_dca_priv *ioatdca = dca_priv(dca);
+ struct pci_dev *pdev;
+ int i;
+ u16 id;
+
+ /* This implementation only supports PCI-Express */
+ if (dev->bus != &pci_bus_type)
+ return -ENODEV;
+ pdev = to_pci_dev(dev);
+ id = dcaid_from_pcidev(pdev);
+
+ if (ioatdca->requester_count == ioatdca->max_requesters)
+ return -ENODEV;
+
+ for (i = 0; i < ioatdca->max_requesters; i++) {
+ if (ioatdca->req_slots[i].pdev == NULL) {
+ /* found an empty slot */
+ ioatdca->requester_count++;
+ ioatdca->req_slots[i].pdev = pdev;
+ ioatdca->req_slots[i].rid = id;
+ writew(id, ioatdca->dca_base + (i * 4));
+ /* make sure the ignore function bit is off */
+ writeb(0, ioatdca->dca_base + (i * 4) + 2);
+ return i;
+ }
+ }
+ /* Error, ioatdma->requester_count is out of whack */
+ return -EFAULT;
+}
+
+static int ioat_dca_remove_requester(struct dca_provider *dca,
+ struct device *dev)
+{
+ struct ioat_dca_priv *ioatdca = dca_priv(dca);
+ struct pci_dev *pdev;
+ int i;
+
+ /* This implementation only supports PCI-Express */
+ if (dev->bus != &pci_bus_type)
+ return -ENODEV;
+ pdev = to_pci_dev(dev);
+
+ for (i = 0; i < ioatdca->max_requesters; i++) {
+ if (ioatdca->req_slots[i].pdev == pdev) {
+ writew(0, ioatdca->dca_base + (i * 4));
+ ioatdca->req_slots[i].pdev = NULL;
+ ioatdca->req_slots[i].rid = 0;
+ ioatdca->requester_count--;
+ return i;
+ }
+ }
+ return -ENODEV;
+}
+
+static u8 ioat_dca_get_tag(struct dca_provider *dca, int cpu)
+{
+ struct ioat_dca_priv *ioatdca = dca_priv(dca);
+ int i, apic_id, bit, value;
+ u8 entry, tag;
+
+ tag = 0;
+ apic_id = cpu_physical_id(cpu);
+
+ for (i = 0; i < IOAT_TAG_MAP_LEN; i++) {
+ entry = ioatdca->tag_map[i];
+ if (entry & DCA_TAG_MAP_VALID) {
+ bit = entry & ~DCA_TAG_MAP_VALID;
+ value = (apic_id & (1 << bit)) ? 1 : 0;
+ } else {
+ value = entry ? 1 : 0;
+ }
+ tag |= (value << i);
+ }
+ return tag;
+}
+
+static struct dca_ops ioat_dca_ops = {
+ .add_requester = ioat_dca_add_requester,
+ .remove_requester = ioat_dca_remove_requester,
+ .get_tag = ioat_dca_get_tag,
+};
+
+
+struct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase)
+{
+ struct dca_provider *dca;
+ struct ioat_dca_priv *ioatdca;
+ u8 *tag_map = NULL;
+ int i;
+ int err;
+
+ if (!system_has_dca_enabled(pdev))
+ return NULL;
+
+ /* I/OAT v1 systems must have a known tag_map to support DCA */
+ switch (pdev->vendor) {
+ case PCI_VENDOR_ID_INTEL:
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_INTEL_IOAT:
+ tag_map = ioat_tag_map_BNB;
+ break;
+ case PCI_DEVICE_ID_INTEL_IOAT_CNB:
+ tag_map = ioat_tag_map_CNB;
+ break;
+ case PCI_DEVICE_ID_INTEL_IOAT_SCNB:
+ tag_map = ioat_tag_map_SCNB;
+ break;
+ }
+ break;
+ case PCI_VENDOR_ID_UNISYS:
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR:
+ tag_map = ioat_tag_map_UNISYS;
+ break;
+ }
+ break;
+ }
+ if (tag_map == NULL)
+ return NULL;
+
+ dca = alloc_dca_provider(&ioat_dca_ops,
+ sizeof(*ioatdca) +
+ (sizeof(struct ioat_dca_slot) * IOAT_DCA_MAX_REQ));
+ if (!dca)
+ return NULL;
+
+ ioatdca = dca_priv(dca);
+ ioatdca->max_requesters = IOAT_DCA_MAX_REQ;
+
+ ioatdca->dca_base = iobase + 0x54;
+
+ /* copy over the APIC ID to DCA tag mapping */
+ for (i = 0; i < IOAT_TAG_MAP_LEN; i++)
+ ioatdca->tag_map[i] = tag_map[i];
+
+ err = register_dca_provider(dca, &pdev->dev);
+ if (err) {
+ free_dca_provider(dca);
+ return NULL;
+ }
+
+ return dca;
+}
+
+
+static int ioat2_dca_add_requester(struct dca_provider *dca, struct device *dev)
+{
+ struct ioat_dca_priv *ioatdca = dca_priv(dca);
+ struct pci_dev *pdev;
+ int i;
+ u16 id;
+ u16 global_req_table;
+
+ /* This implementation only supports PCI-Express */
+ if (dev->bus != &pci_bus_type)
+ return -ENODEV;
+ pdev = to_pci_dev(dev);
+ id = dcaid_from_pcidev(pdev);
+
+ if (ioatdca->requester_count == ioatdca->max_requesters)
+ return -ENODEV;
+
+ for (i = 0; i < ioatdca->max_requesters; i++) {
+ if (ioatdca->req_slots[i].pdev == NULL) {
+ /* found an empty slot */
+ ioatdca->requester_count++;
+ ioatdca->req_slots[i].pdev = pdev;
+ ioatdca->req_slots[i].rid = id;
+ global_req_table =
+ readw(ioatdca->dca_base + IOAT_DCA_GREQID_OFFSET);
+ writel(id | IOAT_DCA_GREQID_VALID,
+ ioatdca->iobase + global_req_table + (i * 4));
+ return i;
+ }
+ }
+ /* Error, ioatdma->requester_count is out of whack */
+ return -EFAULT;
+}
+
+static int ioat2_dca_remove_requester(struct dca_provider *dca,
+ struct device *dev)
+{
+ struct ioat_dca_priv *ioatdca = dca_priv(dca);
+ struct pci_dev *pdev;
+ int i;
+ u16 global_req_table;
+
+ /* This implementation only supports PCI-Express */
+ if (dev->bus != &pci_bus_type)
+ return -ENODEV;
+ pdev = to_pci_dev(dev);
+
+ for (i = 0; i < ioatdca->max_requesters; i++) {
+ if (ioatdca->req_slots[i].pdev == pdev) {
+ global_req_table =
+ readw(ioatdca->dca_base + IOAT_DCA_GREQID_OFFSET);
+ writel(0, ioatdca->iobase + global_req_table + (i * 4));
+ ioatdca->req_slots[i].pdev = NULL;
+ ioatdca->req_slots[i].rid = 0;
+ ioatdca->requester_count--;
+ return i;
+ }
+ }
+ return -ENODEV;
+}
+
+static u8 ioat2_dca_get_tag(struct dca_provider *dca, int cpu)
+{
+ u8 tag;
+
+ tag = ioat_dca_get_tag(dca, cpu);
+ tag = (~tag) & 0x1F;
+ return tag;
+}
+
+static struct dca_ops ioat2_dca_ops = {
+ .add_requester = ioat2_dca_add_requester,
+ .remove_requester = ioat2_dca_remove_requester,
+ .get_tag = ioat2_dca_get_tag,
+};
+
+static int ioat2_dca_count_dca_slots(void *iobase, u16 dca_offset)
+{
+ int slots = 0;
+ u32 req;
+ u16 global_req_table;
+
+ global_req_table = readw(iobase + dca_offset + IOAT_DCA_GREQID_OFFSET);
+ if (global_req_table == 0)
+ return 0;
+ do {
+ req = readl(iobase + global_req_table + (slots * sizeof(u32)));
+ slots++;
+ } while ((req & IOAT_DCA_GREQID_LASTID) == 0);
+
+ return slots;
+}
+
+struct dca_provider *ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase)
+{
+ struct dca_provider *dca;
+ struct ioat_dca_priv *ioatdca;
+ int slots;
+ int i;
+ int err;
+ u32 tag_map;
+ u16 dca_offset;
+ u16 csi_fsb_control;
+ u16 pcie_control;
+ u8 bit;
+
+ if (!system_has_dca_enabled(pdev))
+ return NULL;
+
+ dca_offset = readw(iobase + IOAT_DCAOFFSET_OFFSET);
+ if (dca_offset == 0)
+ return NULL;
+
+ slots = ioat2_dca_count_dca_slots(iobase, dca_offset);
+ if (slots == 0)
+ return NULL;
+
+ dca = alloc_dca_provider(&ioat2_dca_ops,
+ sizeof(*ioatdca)
+ + (sizeof(struct ioat_dca_slot) * slots));
+ if (!dca)
+ return NULL;
+
+ ioatdca = dca_priv(dca);
+ ioatdca->iobase = iobase;
+ ioatdca->dca_base = iobase + dca_offset;
+ ioatdca->max_requesters = slots;
+
+ /* some bios might not know to turn these on */
+ csi_fsb_control = readw(ioatdca->dca_base + IOAT_FSB_CAP_ENABLE_OFFSET);
+ if ((csi_fsb_control & IOAT_FSB_CAP_ENABLE_PREFETCH) == 0) {
+ csi_fsb_control |= IOAT_FSB_CAP_ENABLE_PREFETCH;
+ writew(csi_fsb_control,
+ ioatdca->dca_base + IOAT_FSB_CAP_ENABLE_OFFSET);
+ }
+ pcie_control = readw(ioatdca->dca_base + IOAT_PCI_CAP_ENABLE_OFFSET);
+ if ((pcie_control & IOAT_PCI_CAP_ENABLE_MEMWR) == 0) {
+ pcie_control |= IOAT_PCI_CAP_ENABLE_MEMWR;
+ writew(pcie_control,
+ ioatdca->dca_base + IOAT_PCI_CAP_ENABLE_OFFSET);
+ }
+
+
+ /* TODO version, compatibility and configuration checks */
+
+ /* copy out the APIC to DCA tag map */
+ tag_map = readl(ioatdca->dca_base + IOAT_APICID_TAG_MAP_OFFSET);
+ for (i = 0; i < 5; i++) {
+ bit = (tag_map >> (4 * i)) & 0x0f;
+ if (bit < 8)
+ ioatdca->tag_map[i] = bit | DCA_TAG_MAP_VALID;
+ else
+ ioatdca->tag_map[i] = 0;
+ }
+
+ err = register_dca_provider(dca, &pdev->dev);
+ if (err) {
+ free_dca_provider(dca);
+ return NULL;
+ }
+
+ return dca;
+}
diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c
new file mode 100644
index 00000000000..c1c2dcc6fc2
--- /dev/null
+++ b/drivers/dma/ioat_dma.c
@@ -0,0 +1,1383 @@
+/*
+ * Intel I/OAT DMA Linux driver
+ * Copyright(c) 2004 - 2007 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You 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".
+ *
+ */
+
+/*
+ * This driver supports an Intel I/OAT DMA engine, which does asynchronous
+ * copy operations.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include "ioatdma.h"
+#include "ioatdma_registers.h"
+#include "ioatdma_hw.h"
+
+#define to_ioat_chan(chan) container_of(chan, struct ioat_dma_chan, common)
+#define to_ioatdma_device(dev) container_of(dev, struct ioatdma_device, common)
+#define to_ioat_desc(lh) container_of(lh, struct ioat_desc_sw, node)
+#define tx_to_ioat_desc(tx) container_of(tx, struct ioat_desc_sw, async_tx)
+
+static int ioat_pending_level = 4;
+module_param(ioat_pending_level, int, 0644);
+MODULE_PARM_DESC(ioat_pending_level,
+ "high-water mark for pushing ioat descriptors (default: 4)");
+
+/* internal functions */
+static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan);
+static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan);
+
+static struct ioat_desc_sw *
+ioat1_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan);
+static struct ioat_desc_sw *
+ioat2_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan);
+
+static inline struct ioat_dma_chan *ioat_lookup_chan_by_index(
+ struct ioatdma_device *device,
+ int index)
+{
+ return device->idx[index];
+}
+
+/**
+ * ioat_dma_do_interrupt - handler used for single vector interrupt mode
+ * @irq: interrupt id
+ * @data: interrupt data
+ */
+static irqreturn_t ioat_dma_do_interrupt(int irq, void *data)
+{
+ struct ioatdma_device *instance = data;
+ struct ioat_dma_chan *ioat_chan;
+ unsigned long attnstatus;
+ int bit;
+ u8 intrctrl;
+
+ intrctrl = readb(instance->reg_base + IOAT_INTRCTRL_OFFSET);
+
+ if (!(intrctrl & IOAT_INTRCTRL_MASTER_INT_EN))
+ return IRQ_NONE;
+
+ if (!(intrctrl & IOAT_INTRCTRL_INT_STATUS)) {
+ writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
+ return IRQ_NONE;
+ }
+
+ attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET);
+ for_each_bit(bit, &attnstatus, BITS_PER_LONG) {
+ ioat_chan = ioat_lookup_chan_by_index(instance, bit);
+ tasklet_schedule(&ioat_chan->cleanup_task);
+ }
+
+ writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
+ return IRQ_HANDLED;
+}
+
+/**
+ * ioat_dma_do_interrupt_msix - handler used for vector-per-channel interrupt mode
+ * @irq: interrupt id
+ * @data: interrupt data
+ */
+static irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data)
+{
+ struct ioat_dma_chan *ioat_chan = data;
+
+ tasklet_schedule(&ioat_chan->cleanup_task);
+
+ return IRQ_HANDLED;
+}
+
+static void ioat_dma_cleanup_tasklet(unsigned long data);
+
+/**
+ * ioat_dma_enumerate_channels - find and initialize the device's channels
+ * @device: the device to be enumerated
+ */
+static int ioat_dma_enumerate_channels(struct ioatdma_device *device)
+{
+ u8 xfercap_scale;
+ u32 xfercap;
+ int i;
+ struct ioat_dma_chan *ioat_chan;
+
+ device->common.chancnt = readb(device->reg_base + IOAT_CHANCNT_OFFSET);
+ xfercap_scale = readb(device->reg_base + IOAT_XFERCAP_OFFSET);
+ xfercap = (xfercap_scale == 0 ? -1 : (1UL << xfercap_scale));
+
+ for (i = 0; i < device->common.chancnt; i++) {
+ ioat_chan = kzalloc(sizeof(*ioat_chan), GFP_KERNEL);
+ if (!ioat_chan) {
+ device->common.chancnt = i;
+ break;
+ }
+
+ ioat_chan->device = device;
+ ioat_chan->reg_base = device->reg_base + (0x80 * (i + 1));
+ ioat_chan->xfercap = xfercap;
+ ioat_chan->desccount = 0;
+ if (ioat_chan->device->version != IOAT_VER_1_2) {
+ writel(IOAT_DCACTRL_CMPL_WRITE_ENABLE
+ | IOAT_DMA_DCA_ANY_CPU,
+ ioat_chan->reg_base + IOAT_DCACTRL_OFFSET);
+ }
+ spin_lock_init(&ioat_chan->cleanup_lock);
+ spin_lock_init(&ioat_chan->desc_lock);
+ INIT_LIST_HEAD(&ioat_chan->free_desc);
+ INIT_LIST_HEAD(&ioat_chan->used_desc);
+ /* This should be made common somewhere in dmaengine.c */
+ ioat_chan->common.device = &device->common;
+ list_add_tail(&ioat_chan->common.device_node,
+ &device->common.channels);
+ device->idx[i] = ioat_chan;
+ tasklet_init(&ioat_chan->cleanup_task,
+ ioat_dma_cleanup_tasklet,
+ (unsigned long) ioat_chan);
+ tasklet_disable(&ioat_chan->cleanup_task);
+ }
+ return device->common.chancnt;
+}
+
+static void ioat_set_src(dma_addr_t addr,
+ struct dma_async_tx_descriptor *tx,
+ int index)
+{
+ tx_to_ioat_desc(tx)->src = addr;
+}
+
+static void ioat_set_dest(dma_addr_t addr,
+ struct dma_async_tx_descriptor *tx,
+ int index)
+{
+ tx_to_ioat_desc(tx)->dst = addr;
+}
+
+static inline void __ioat1_dma_memcpy_issue_pending(
+ struct ioat_dma_chan *ioat_chan);
+static inline void __ioat2_dma_memcpy_issue_pending(
+ struct ioat_dma_chan *ioat_chan);
+
+static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan);
+ struct ioat_desc_sw *first = tx_to_ioat_desc(tx);
+ struct ioat_desc_sw *prev, *new;
+ struct ioat_dma_descriptor *hw;
+ dma_cookie_t cookie;
+ LIST_HEAD(new_chain);
+ u32 copy;
+ size_t len;
+ dma_addr_t src, dst;
+ int orig_ack;
+ unsigned int desc_count = 0;
+
+ /* src and dest and len are stored in the initial descriptor */
+ len = first->len;
+ src = first->src;
+ dst = first->dst;
+ orig_ack = first->async_tx.ack;
+ new = first;
+
+ spin_lock_bh(&ioat_chan->desc_lock);
+ prev = to_ioat_desc(ioat_chan->used_desc.prev);
+ prefetch(prev->hw);
+ do {
+ copy = min((u32) len, ioat_chan->xfercap);
+
+ new->async_tx.ack = 1;
+
+ hw = new->hw;
+ hw->size = copy;
+ hw->ctl = 0;
+ hw->src_addr = src;
+ hw->dst_addr = dst;
+ hw->next = 0;
+
+ /* chain together the physical address list for the HW */
+ wmb();
+ prev->hw->next = (u64) new->async_tx.phys;
+
+ len -= copy;
+ dst += copy;
+ src += copy;
+
+ list_add_tail(&new->node, &new_chain);
+ desc_count++;
+ prev = new;
+ } while (len && (new = ioat1_dma_get_next_descriptor(ioat_chan)));
+
+ hw->ctl = IOAT_DMA_DESCRIPTOR_CTL_CP_STS;
+ if (new->async_tx.callback) {
+ hw->ctl |= IOAT_DMA_DESCRIPTOR_CTL_INT_GN;
+ if (first != new) {
+ /* move callback into to last desc */
+ new->async_tx.callback = first->async_tx.callback;
+ new->async_tx.callback_param
+ = first->async_tx.callback_param;
+ first->async_tx.callback = NULL;
+ first->async_tx.callback_param = NULL;
+ }
+ }
+
+ new->tx_cnt = desc_count;
+ new->async_tx.ack = orig_ack; /* client is in control of this ack */
+
+ /* store the original values for use in later cleanup */
+ if (new != first) {
+ new->src = first->src;
+ new->dst = first->dst;
+ new->len = first->len;
+ }
+
+ /* cookie incr and addition to used_list must be atomic */
+ cookie = ioat_chan->common.cookie;
+ cookie++;
+ if (cookie < 0)
+ cookie = 1;
+ ioat_chan->common.cookie = new->async_tx.cookie = cookie;
+
+ /* write address into NextDescriptor field of last desc in chain */
+ to_ioat_desc(ioat_chan->used_desc.prev)->hw->next =
+ first->async_tx.phys;
+ __list_splice(&new_chain, ioat_chan->used_desc.prev);
+
+ ioat_chan->dmacount += desc_count;
+ ioat_chan->pending += desc_count;
+ if (ioat_chan->pending >= ioat_pending_level)
+ __ioat1_dma_memcpy_issue_pending(ioat_chan);
+ spin_unlock_bh(&ioat_chan->desc_lock);
+
+ return cookie;
+}
+
+static dma_cookie_t ioat2_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan);
+ struct ioat_desc_sw *first = tx_to_ioat_desc(tx);
+ struct ioat_desc_sw *new;
+ struct ioat_dma_descriptor *hw;
+ dma_cookie_t cookie;
+ u32 copy;
+ size_t len;
+ dma_addr_t src, dst;
+ int orig_ack;
+ unsigned int desc_count = 0;
+
+ /* src and dest and len are stored in the initial descriptor */
+ len = first->len;
+ src = first->src;
+ dst = first->dst;
+ orig_ack = first->async_tx.ack;
+ new = first;
+
+ /* ioat_chan->desc_lock is still in force in version 2 path */
+
+ do {
+ copy = min((u32) len, ioat_chan->xfercap);
+
+ new->async_tx.ack = 1;
+
+ hw = new->hw;
+ hw->size = copy;
+ hw->ctl = 0;
+ hw->src_addr = src;
+ hw->dst_addr = dst;
+
+ len -= copy;
+ dst += copy;
+ src += copy;
+ desc_count++;
+ } while (len && (new = ioat2_dma_get_next_descriptor(ioat_chan)));
+
+ hw->ctl = IOAT_DMA_DESCRIPTOR_CTL_CP_STS;
+ if (new->async_tx.callback) {
+ hw->ctl |= IOAT_DMA_DESCRIPTOR_CTL_INT_GN;
+ if (first != new) {
+ /* move callback into to last desc */
+ new->async_tx.callback = first->async_tx.callback;
+ new->async_tx.callback_param
+ = first->async_tx.callback_param;
+ first->async_tx.callback = NULL;
+ first->async_tx.callback_param = NULL;
+ }
+ }
+
+ new->tx_cnt = desc_count;
+ new->async_tx.ack = orig_ack; /* client is in control of this ack */
+
+ /* store the original values for use in later cleanup */
+ if (new != first) {
+ new->src = first->src;
+ new->dst = first->dst;
+ new->len = first->len;
+ }
+
+ /* cookie incr and addition to used_list must be atomic */
+ cookie = ioat_chan->common.cookie;
+ cookie++;
+ if (cookie < 0)
+ cookie = 1;
+ ioat_chan->common.cookie = new->async_tx.cookie = cookie;
+
+ ioat_chan->dmacount += desc_count;
+ ioat_chan->pending += desc_count;
+ if (ioat_chan->pending >= ioat_pending_level)
+ __ioat2_dma_memcpy_issue_pending(ioat_chan);
+ spin_unlock_bh(&ioat_chan->desc_lock);
+
+ return cookie;
+}
+
+/**
+ * ioat_dma_alloc_descriptor - allocate and return a sw and hw descriptor pair
+ * @ioat_chan: the channel supplying the memory pool for the descriptors
+ * @flags: allocation flags
+ */
+static struct ioat_desc_sw *ioat_dma_alloc_descriptor(
+ struct ioat_dma_chan *ioat_chan,
+ gfp_t flags)
+{
+ struct ioat_dma_descriptor *desc;
+ struct ioat_desc_sw *desc_sw;
+ struct ioatdma_device *ioatdma_device;
+ dma_addr_t phys;
+
+ ioatdma_device = to_ioatdma_device(ioat_chan->common.device);
+ desc = pci_pool_alloc(ioatdma_device->dma_pool, flags, &phys);
+ if (unlikely(!desc))
+ return NULL;
+
+ desc_sw = kzalloc(sizeof(*desc_sw), flags);
+ if (unlikely(!desc_sw)) {
+ pci_pool_free(ioatdma_device->dma_pool, desc, phys);
+ return NULL;
+ }
+
+ memset(desc, 0, sizeof(*desc));
+ dma_async_tx_descriptor_init(&desc_sw->async_tx, &ioat_chan->common);
+ desc_sw->async_tx.tx_set_src = ioat_set_src;
+ desc_sw->async_tx.tx_set_dest = ioat_set_dest;
+ switch (ioat_chan->device->version) {
+ case IOAT_VER_1_2:
+ desc_sw->async_tx.tx_submit = ioat1_tx_submit;
+ break;
+ case IOAT_VER_2_0:
+ desc_sw->async_tx.tx_submit = ioat2_tx_submit;
+ break;
+ }
+ INIT_LIST_HEAD(&desc_sw->async_tx.tx_list);
+
+ desc_sw->hw = desc;
+ desc_sw->async_tx.phys = phys;
+
+ return desc_sw;
+}
+
+static int ioat_initial_desc_count = 256;
+module_param(ioat_initial_desc_count, int, 0644);
+MODULE_PARM_DESC(ioat_initial_desc_count,
+ "initial descriptors per channel (default: 256)");
+
+/**
+ * ioat2_dma_massage_chan_desc - link the descriptors into a circle
+ * @ioat_chan: the channel to be massaged
+ */
+static void ioat2_dma_massage_chan_desc(struct ioat_dma_chan *ioat_chan)
+{
+ struct ioat_desc_sw *desc, *_desc;
+
+ /* setup used_desc */
+ ioat_chan->used_desc.next = ioat_chan->free_desc.next;
+ ioat_chan->used_desc.prev = NULL;
+
+ /* pull free_desc out of the circle so that every node is a hw
+ * descriptor, but leave it pointing to the list
+ */
+ ioat_chan->free_desc.prev->next = ioat_chan->free_desc.next;
+ ioat_chan->free_desc.next->prev = ioat_chan->free_desc.prev;
+
+ /* circle link the hw descriptors */
+ desc = to_ioat_desc(ioat_chan->free_desc.next);
+ desc->hw->next = to_ioat_desc(desc->node.next)->async_tx.phys;
+ list_for_each_entry_safe(desc, _desc, ioat_chan->free_desc.next, node) {
+ desc->hw->next = to_ioat_desc(desc->node.next)->async_tx.phys;
+ }
+}
+
+/**
+ * ioat_dma_alloc_chan_resources - returns the number of allocated descriptors
+ * @chan: the channel to be filled out
+ */
+static int ioat_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+ struct ioat_desc_sw *desc = NULL;
+ u16 chanctrl;
+ u32 chanerr;
+ int i;
+ LIST_HEAD(tmp_list);
+
+ /* have we already been set up? */
+ if (!list_empty(&ioat_chan->free_desc))
+ return ioat_chan->desccount;
+
+ /* Setup register to interrupt and write completion status on error */
+ chanctrl = IOAT_CHANCTRL_ERR_INT_EN |
+ IOAT_CHANCTRL_ANY_ERR_ABORT_EN |
+ IOAT_CHANCTRL_ERR_COMPLETION_EN;
+ writew(chanctrl, ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
+
+ chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
+ if (chanerr) {
+ dev_err(&ioat_chan->device->pdev->dev,
+ "CHANERR = %x, clearing\n", chanerr);
+ writel(chanerr, ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
+ }
+
+ /* Allocate descriptors */
+ for (i = 0; i < ioat_initial_desc_count; i++) {
+ desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_KERNEL);
+ if (!desc) {
+ dev_err(&ioat_chan->device->pdev->dev,
+ "Only %d initial descriptors\n", i);
+ break;
+ }
+ list_add_tail(&desc->node, &tmp_list);
+ }
+ spin_lock_bh(&ioat_chan->desc_lock);
+ ioat_chan->desccount = i;
+ list_splice(&tmp_list, &ioat_chan->free_desc);
+ if (ioat_chan->device->version != IOAT_VER_1_2)
+ ioat2_dma_massage_chan_desc(ioat_chan);
+ spin_unlock_bh(&ioat_chan->desc_lock);
+
+ /* allocate a completion writeback area */
+ /* doing 2 32bit writes to mmio since 1 64b write doesn't work */
+ ioat_chan->completion_virt =
+ pci_pool_alloc(ioat_chan->device->completion_pool,
+ GFP_KERNEL,
+ &ioat_chan->completion_addr);
+ memset(ioat_chan->completion_virt, 0,
+ sizeof(*ioat_chan->completion_virt));
+ writel(((u64) ioat_chan->completion_addr) & 0x00000000FFFFFFFF,
+ ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_LOW);
+ writel(((u64) ioat_chan->completion_addr) >> 32,
+ ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
+
+ tasklet_enable(&ioat_chan->cleanup_task);
+ ioat_dma_start_null_desc(ioat_chan); /* give chain to dma device */
+ return ioat_chan->desccount;
+}
+
+/**
+ * ioat_dma_free_chan_resources - release all the descriptors
+ * @chan: the channel to be cleaned
+ */
+static void ioat_dma_free_chan_resources(struct dma_chan *chan)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+ struct ioatdma_device *ioatdma_device = to_ioatdma_device(chan->device);
+ struct ioat_desc_sw *desc, *_desc;
+ int in_use_descs = 0;
+
+ tasklet_disable(&ioat_chan->cleanup_task);
+ ioat_dma_memcpy_cleanup(ioat_chan);
+
+ /* Delay 100ms after reset to allow internal DMA logic to quiesce
+ * before removing DMA descriptor resources.
+ */
+ writeb(IOAT_CHANCMD_RESET,
+ ioat_chan->reg_base
+ + IOAT_CHANCMD_OFFSET(ioat_chan->device->version));
+ mdelay(100);
+
+ spin_lock_bh(&ioat_chan->desc_lock);
+ switch (ioat_chan->device->version) {
+ case IOAT_VER_1_2:
+ list_for_each_entry_safe(desc, _desc,
+ &ioat_chan->used_desc, node) {
+ in_use_descs++;
+ list_del(&desc->node);
+ pci_pool_free(ioatdma_device->dma_pool, desc->hw,
+ desc->async_tx.phys);
+ kfree(desc);
+ }
+ list_for_each_entry_safe(desc, _desc,
+ &ioat_chan->free_desc, node) {
+ list_del(&desc->node);
+ pci_pool_free(ioatdma_device->dma_pool, desc->hw,
+ desc->async_tx.phys);
+ kfree(desc);
+ }
+ break;
+ case IOAT_VER_2_0:
+ list_for_each_entry_safe(desc, _desc,
+ ioat_chan->free_desc.next, node) {
+ list_del(&desc->node);
+ pci_pool_free(ioatdma_device->dma_pool, desc->hw,
+ desc->async_tx.phys);
+ kfree(desc);
+ }
+ desc = to_ioat_desc(ioat_chan->free_desc.next);
+ pci_pool_free(ioatdma_device->dma_pool, desc->hw,
+ desc->async_tx.phys);
+ kfree(desc);
+ INIT_LIST_HEAD(&ioat_chan->free_desc);
+ INIT_LIST_HEAD(&ioat_chan->used_desc);
+ break;
+ }
+ spin_unlock_bh(&ioat_chan->desc_lock);
+
+ pci_pool_free(ioatdma_device->completion_pool,
+ ioat_chan->completion_virt,
+ ioat_chan->completion_addr);
+
+ /* one is ok since we left it on there on purpose */
+ if (in_use_descs > 1)
+ dev_err(&ioat_chan->device->pdev->dev,
+ "Freeing %d in use descriptors!\n",
+ in_use_descs - 1);
+
+ ioat_chan->last_completion = ioat_chan->completion_addr = 0;
+ ioat_chan->pending = 0;
+ ioat_chan->dmacount = 0;
+}
+
+/**
+ * ioat_dma_get_next_descriptor - return the next available descriptor
+ * @ioat_chan: IOAT DMA channel handle
+ *
+ * Gets the next descriptor from the chain, and must be called with the
+ * channel's desc_lock held. Allocates more descriptors if the channel
+ * has run out.
+ */
+static struct ioat_desc_sw *
+ioat1_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan)
+{
+ struct ioat_desc_sw *new = NULL;
+
+ if (!list_empty(&ioat_chan->free_desc)) {
+ new = to_ioat_desc(ioat_chan->free_desc.next);
+ list_del(&new->node);
+ } else {
+ /* try to get another desc */
+ new = ioat_dma_alloc_descriptor(ioat_chan, GFP_ATOMIC);
+ /* will this ever happen? */
+ /* TODO add upper limit on these */
+ BUG_ON(!new);
+ }
+
+ prefetch(new->hw);
+ return new;
+}
+
+static struct ioat_desc_sw *
+ioat2_dma_get_next_descriptor(struct ioat_dma_chan *ioat_chan)
+{
+ struct ioat_desc_sw *new = NULL;
+
+ /*
+ * used.prev points to where to start processing
+ * used.next points to next free descriptor
+ * if used.prev == NULL, there are none waiting to be processed
+ * if used.next == used.prev.prev, there is only one free descriptor,
+ * and we need to use it to as a noop descriptor before
+ * linking in a new set of descriptors, since the device
+ * has probably already read the pointer to it
+ */
+ if (ioat_chan->used_desc.prev &&
+ ioat_chan->used_desc.next == ioat_chan->used_desc.prev->prev) {
+
+ struct ioat_desc_sw *desc = NULL;
+ struct ioat_desc_sw *noop_desc = NULL;
+ int i;
+
+ /* set up the noop descriptor */
+ noop_desc = to_ioat_desc(ioat_chan->used_desc.next);
+ noop_desc->hw->size = 0;
+ noop_desc->hw->ctl = IOAT_DMA_DESCRIPTOR_NUL;
+ noop_desc->hw->src_addr = 0;
+ noop_desc->hw->dst_addr = 0;
+
+ ioat_chan->used_desc.next = ioat_chan->used_desc.next->next;
+ ioat_chan->pending++;
+ ioat_chan->dmacount++;
+
+ /* get a few more descriptors */
+ for (i = 16; i; i--) {
+ desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_ATOMIC);
+ BUG_ON(!desc);
+ list_add_tail(&desc->node, ioat_chan->used_desc.next);
+
+ desc->hw->next
+ = to_ioat_desc(desc->node.next)->async_tx.phys;
+ to_ioat_desc(desc->node.prev)->hw->next
+ = desc->async_tx.phys;
+ ioat_chan->desccount++;
+ }
+
+ ioat_chan->used_desc.next = noop_desc->node.next;
+ }
+ new = to_ioat_desc(ioat_chan->used_desc.next);
+ prefetch(new);
+ ioat_chan->used_desc.next = new->node.next;
+
+ if (ioat_chan->used_desc.prev == NULL)
+ ioat_chan->used_desc.prev = &new->node;
+
+ prefetch(new->hw);
+ return new;
+}
+
+static struct ioat_desc_sw *ioat_dma_get_next_descriptor(
+ struct ioat_dma_chan *ioat_chan)
+{
+ if (!ioat_chan)
+ return NULL;
+
+ switch (ioat_chan->device->version) {
+ case IOAT_VER_1_2:
+ return ioat1_dma_get_next_descriptor(ioat_chan);
+ break;
+ case IOAT_VER_2_0:
+ return ioat2_dma_get_next_descriptor(ioat_chan);
+ break;
+ }
+ return NULL;
+}
+
+static struct dma_async_tx_descriptor *ioat1_dma_prep_memcpy(
+ struct dma_chan *chan,
+ size_t len,
+ int int_en)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+ struct ioat_desc_sw *new;
+
+ spin_lock_bh(&ioat_chan->desc_lock);
+ new = ioat_dma_get_next_descriptor(ioat_chan);
+ new->len = len;
+ spin_unlock_bh(&ioat_chan->desc_lock);
+
+ return new ? &new->async_tx : NULL;
+}
+
+static struct dma_async_tx_descriptor *ioat2_dma_prep_memcpy(
+ struct dma_chan *chan,
+ size_t len,
+ int int_en)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+ struct ioat_desc_sw *new;
+
+ spin_lock_bh(&ioat_chan->desc_lock);
+ new = ioat2_dma_get_next_descriptor(ioat_chan);
+ new->len = len;
+
+ /* leave ioat_chan->desc_lock set in version 2 path */
+ return new ? &new->async_tx : NULL;
+}
+
+
+/**
+ * ioat_dma_memcpy_issue_pending - push potentially unrecognized appended
+ * descriptors to hw
+ * @chan: DMA channel handle
+ */
+static inline void __ioat1_dma_memcpy_issue_pending(
+ struct ioat_dma_chan *ioat_chan)
+{
+ ioat_chan->pending = 0;
+ writeb(IOAT_CHANCMD_APPEND, ioat_chan->reg_base + IOAT1_CHANCMD_OFFSET);
+}
+
+static void ioat1_dma_memcpy_issue_pending(struct dma_chan *chan)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+
+ if (ioat_chan->pending != 0) {
+ spin_lock_bh(&ioat_chan->desc_lock);
+ __ioat1_dma_memcpy_issue_pending(ioat_chan);
+ spin_unlock_bh(&ioat_chan->desc_lock);
+ }
+}
+
+static inline void __ioat2_dma_memcpy_issue_pending(
+ struct ioat_dma_chan *ioat_chan)
+{
+ ioat_chan->pending = 0;
+ writew(ioat_chan->dmacount,
+ ioat_chan->reg_base + IOAT_CHAN_DMACOUNT_OFFSET);
+}
+
+static void ioat2_dma_memcpy_issue_pending(struct dma_chan *chan)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+
+ if (ioat_chan->pending != 0) {
+ spin_lock_bh(&ioat_chan->desc_lock);
+ __ioat2_dma_memcpy_issue_pending(ioat_chan);
+ spin_unlock_bh(&ioat_chan->desc_lock);
+ }
+}
+
+static void ioat_dma_cleanup_tasklet(unsigned long data)
+{
+ struct ioat_dma_chan *chan = (void *)data;
+ ioat_dma_memcpy_cleanup(chan);
+ writew(IOAT_CHANCTRL_INT_DISABLE,
+ chan->reg_base + IOAT_CHANCTRL_OFFSET);
+}
+
+/**
+ * ioat_dma_memcpy_cleanup - cleanup up finished descriptors
+ * @chan: ioat channel to be cleaned up
+ */
+static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan)
+{
+ unsigned long phys_complete;
+ struct ioat_desc_sw *desc, *_desc;
+ dma_cookie_t cookie = 0;
+ unsigned long desc_phys;
+ struct ioat_desc_sw *latest_desc;
+
+ prefetch(ioat_chan->completion_virt);
+
+ if (!spin_trylock_bh(&ioat_chan->cleanup_lock))
+ return;
+
+ /* The completion writeback can happen at any time,
+ so reads by the driver need to be atomic operations
+ The descriptor physical addresses are limited to 32-bits
+ when the CPU can only do a 32-bit mov */
+
+#if (BITS_PER_LONG == 64)
+ phys_complete =
+ ioat_chan->completion_virt->full
+ & IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR;
+#else
+ phys_complete =
+ ioat_chan->completion_virt->low & IOAT_LOW_COMPLETION_MASK;
+#endif
+
+ if ((ioat_chan->completion_virt->full
+ & IOAT_CHANSTS_DMA_TRANSFER_STATUS) ==
+ IOAT_CHANSTS_DMA_TRANSFER_STATUS_HALTED) {
+ dev_err(&ioat_chan->device->pdev->dev,
+ "Channel halted, chanerr = %x\n",
+ readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET));
+
+ /* TODO do something to salvage the situation */
+ }
+
+ if (phys_complete == ioat_chan->last_completion) {
+ spin_unlock_bh(&ioat_chan->cleanup_lock);
+ return;
+ }
+
+ cookie = 0;
+ spin_lock_bh(&ioat_chan->desc_lock);
+ switch (ioat_chan->device->version) {
+ case IOAT_VER_1_2:
+ list_for_each_entry_safe(desc, _desc,
+ &ioat_chan->used_desc, node) {
+
+ /*
+ * Incoming DMA requests may use multiple descriptors,
+ * due to exceeding xfercap, perhaps. If so, only the
+ * last one will have a cookie, and require unmapping.
+ */
+ if (desc->async_tx.cookie) {
+ cookie = desc->async_tx.cookie;
+
+ /*
+ * yes we are unmapping both _page and _single
+ * alloc'd regions with unmap_page. Is this
+ * *really* that bad?
+ */
+ pci_unmap_page(ioat_chan->device->pdev,
+ pci_unmap_addr(desc, dst),
+ pci_unmap_len(desc, len),
+ PCI_DMA_FROMDEVICE);
+ pci_unmap_page(ioat_chan->device->pdev,
+ pci_unmap_addr(desc, src),
+ pci_unmap_len(desc, len),
+ PCI_DMA_TODEVICE);
+
+ if (desc->async_tx.callback) {
+ desc->async_tx.callback(desc->async_tx.callback_param);
+ desc->async_tx.callback = NULL;
+ }
+ }
+
+ if (desc->async_tx.phys != phys_complete) {
+ /*
+ * a completed entry, but not the last, so clean
+ * up if the client is done with the descriptor
+ */
+ if (desc->async_tx.ack) {
+ list_del(&desc->node);
+ list_add_tail(&desc->node,
+ &ioat_chan->free_desc);
+ } else
+ desc->async_tx.cookie = 0;
+ } else {
+ /*
+ * last used desc. Do not remove, so we can
+ * append from it, but don't look at it next
+ * time, either
+ */
+ desc->async_tx.cookie = 0;
+
+ /* TODO check status bits? */
+ break;
+ }
+ }
+ break;
+ case IOAT_VER_2_0:
+ /* has some other thread has already cleaned up? */
+ if (ioat_chan->used_desc.prev == NULL)
+ break;
+
+ /* work backwards to find latest finished desc */
+ desc = to_ioat_desc(ioat_chan->used_desc.next);
+ latest_desc = NULL;
+ do {
+ desc = to_ioat_desc(desc->node.prev);
+ desc_phys = (unsigned long)desc->async_tx.phys
+ & IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR;
+ if (desc_phys == phys_complete) {
+ latest_desc = desc;
+ break;
+ }
+ } while (&desc->node != ioat_chan->used_desc.prev);
+
+ if (latest_desc != NULL) {
+
+ /* work forwards to clear finished descriptors */
+ for (desc = to_ioat_desc(ioat_chan->used_desc.prev);
+ &desc->node != latest_desc->node.next &&
+ &desc->node != ioat_chan->used_desc.next;
+ desc = to_ioat_desc(desc->node.next)) {
+ if (desc->async_tx.cookie) {
+ cookie = desc->async_tx.cookie;
+ desc->async_tx.cookie = 0;
+
+ pci_unmap_page(ioat_chan->device->pdev,
+ pci_unmap_addr(desc, dst),
+ pci_unmap_len(desc, len),
+ PCI_DMA_FROMDEVICE);
+ pci_unmap_page(ioat_chan->device->pdev,
+ pci_unmap_addr(desc, src),
+ pci_unmap_len(desc, len),
+ PCI_DMA_TODEVICE);
+
+ if (desc->async_tx.callback) {
+ desc->async_tx.callback(desc->async_tx.callback_param);
+ desc->async_tx.callback = NULL;
+ }
+ }
+ }
+
+ /* move used.prev up beyond those that are finished */
+ if (&desc->node == ioat_chan->used_desc.next)
+ ioat_chan->used_desc.prev = NULL;
+ else
+ ioat_chan->used_desc.prev = &desc->node;
+ }
+ break;
+ }
+
+ spin_unlock_bh(&ioat_chan->desc_lock);
+
+ ioat_chan->last_completion = phys_complete;
+ if (cookie != 0)
+ ioat_chan->completed_cookie = cookie;
+
+ spin_unlock_bh(&ioat_chan->cleanup_lock);
+}
+
+static void ioat_dma_dependency_added(struct dma_chan *chan)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+ spin_lock_bh(&ioat_chan->desc_lock);
+ if (ioat_chan->pending == 0) {
+ spin_unlock_bh(&ioat_chan->desc_lock);
+ ioat_dma_memcpy_cleanup(ioat_chan);
+ } else
+ spin_unlock_bh(&ioat_chan->desc_lock);
+}
+
+/**
+ * ioat_dma_is_complete - poll the status of a IOAT DMA transaction
+ * @chan: IOAT DMA channel handle
+ * @cookie: DMA transaction identifier
+ * @done: if not %NULL, updated with last completed transaction
+ * @used: if not %NULL, updated with last used transaction
+ */
+static enum dma_status ioat_dma_is_complete(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ dma_cookie_t *done,
+ dma_cookie_t *used)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+ dma_cookie_t last_used;
+ dma_cookie_t last_complete;
+ enum dma_status ret;
+
+ last_used = chan->cookie;
+ last_complete = ioat_chan->completed_cookie;
+
+ if (done)
+ *done = last_complete;
+ if (used)
+ *used = last_used;
+
+ ret = dma_async_is_complete(cookie, last_complete, last_used);
+ if (ret == DMA_SUCCESS)
+ return ret;
+
+ ioat_dma_memcpy_cleanup(ioat_chan);
+
+ last_used = chan->cookie;
+ last_complete = ioat_chan->completed_cookie;
+
+ if (done)
+ *done = last_complete;
+ if (used)
+ *used = last_used;
+
+ return dma_async_is_complete(cookie, last_complete, last_used);
+}
+
+static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan)
+{
+ struct ioat_desc_sw *desc;
+
+ spin_lock_bh(&ioat_chan->desc_lock);
+
+ desc = ioat_dma_get_next_descriptor(ioat_chan);
+ desc->hw->ctl = IOAT_DMA_DESCRIPTOR_NUL
+ | IOAT_DMA_DESCRIPTOR_CTL_INT_GN
+ | IOAT_DMA_DESCRIPTOR_CTL_CP_STS;
+ desc->hw->size = 0;
+ desc->hw->src_addr = 0;
+ desc->hw->dst_addr = 0;
+ desc->async_tx.ack = 1;
+ switch (ioat_chan->device->version) {
+ case IOAT_VER_1_2:
+ desc->hw->next = 0;
+ list_add_tail(&desc->node, &ioat_chan->used_desc);
+
+ writel(((u64) desc->async_tx.phys) & 0x00000000FFFFFFFF,
+ ioat_chan->reg_base + IOAT1_CHAINADDR_OFFSET_LOW);
+ writel(((u64) desc->async_tx.phys) >> 32,
+ ioat_chan->reg_base + IOAT1_CHAINADDR_OFFSET_HIGH);
+
+ writeb(IOAT_CHANCMD_START, ioat_chan->reg_base
+ + IOAT_CHANCMD_OFFSET(ioat_chan->device->version));
+ break;
+ case IOAT_VER_2_0:
+ writel(((u64) desc->async_tx.phys) & 0x00000000FFFFFFFF,
+ ioat_chan->reg_base + IOAT2_CHAINADDR_OFFSET_LOW);
+ writel(((u64) desc->async_tx.phys) >> 32,
+ ioat_chan->reg_base + IOAT2_CHAINADDR_OFFSET_HIGH);
+
+ ioat_chan->dmacount++;
+ __ioat2_dma_memcpy_issue_pending(ioat_chan);
+ break;
+ }
+ spin_unlock_bh(&ioat_chan->desc_lock);
+}
+
+/*
+ * Perform a IOAT transaction to verify the HW works.
+ */
+#define IOAT_TEST_SIZE 2000
+
+static void ioat_dma_test_callback(void *dma_async_param)
+{
+ printk(KERN_ERR "ioatdma: ioat_dma_test_callback(%p)\n",
+ dma_async_param);
+}
+
+/**
+ * ioat_dma_self_test - Perform a IOAT transaction to verify the HW works.
+ * @device: device to be tested
+ */
+static int ioat_dma_self_test(struct ioatdma_device *device)
+{
+ int i;
+ u8 *src;
+ u8 *dest;
+ struct dma_chan *dma_chan;
+ struct dma_async_tx_descriptor *tx = NULL;
+ dma_addr_t addr;
+ dma_cookie_t cookie;
+ int err = 0;
+
+ src = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL);
+ if (!src)
+ return -ENOMEM;
+ dest = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL);
+ if (!dest) {
+ kfree(src);
+ return -ENOMEM;
+ }
+
+ /* Fill in src buffer */
+ for (i = 0; i < IOAT_TEST_SIZE; i++)
+ src[i] = (u8)i;
+
+ /* Start copy, using first DMA channel */
+ dma_chan = container_of(device->common.channels.next,
+ struct dma_chan,
+ device_node);
+ if (device->common.device_alloc_chan_resources(dma_chan) < 1) {
+ dev_err(&device->pdev->dev,
+ "selftest cannot allocate chan resource\n");
+ err = -ENODEV;
+ goto out;
+ }
+
+ tx = device->common.device_prep_dma_memcpy(dma_chan, IOAT_TEST_SIZE, 0);
+ if (!tx) {
+ dev_err(&device->pdev->dev,
+ "Self-test prep failed, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ async_tx_ack(tx);
+ addr = dma_map_single(dma_chan->device->dev, src, IOAT_TEST_SIZE,
+ DMA_TO_DEVICE);
+ tx->tx_set_src(addr, tx, 0);
+ addr = dma_map_single(dma_chan->device->dev, dest, IOAT_TEST_SIZE,
+ DMA_FROM_DEVICE);
+ tx->tx_set_dest(addr, tx, 0);
+ tx->callback = ioat_dma_test_callback;
+ tx->callback_param = (void *)0x8086;
+ cookie = tx->tx_submit(tx);
+ if (cookie < 0) {
+ dev_err(&device->pdev->dev,
+ "Self-test setup failed, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+ device->common.device_issue_pending(dma_chan);
+ msleep(1);
+
+ if (device->common.device_is_tx_complete(dma_chan, cookie, NULL, NULL)
+ != DMA_SUCCESS) {
+ dev_err(&device->pdev->dev,
+ "Self-test copy timed out, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+ if (memcmp(src, dest, IOAT_TEST_SIZE)) {
+ dev_err(&device->pdev->dev,
+ "Self-test copy failed compare, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+free_resources:
+ device->common.device_free_chan_resources(dma_chan);
+out:
+ kfree(src);
+ kfree(dest);
+ return err;
+}
+
+static char ioat_interrupt_style[32] = "msix";
+module_param_string(ioat_interrupt_style, ioat_interrupt_style,
+ sizeof(ioat_interrupt_style), 0644);
+MODULE_PARM_DESC(ioat_interrupt_style,
+ "set ioat interrupt style: msix (default), "
+ "msix-single-vector, msi, intx)");
+
+/**
+ * ioat_dma_setup_interrupts - setup interrupt handler
+ * @device: ioat device
+ */
+static int ioat_dma_setup_interrupts(struct ioatdma_device *device)
+{
+ struct ioat_dma_chan *ioat_chan;
+ int err, i, j, msixcnt;
+ u8 intrctrl = 0;
+
+ if (!strcmp(ioat_interrupt_style, "msix"))
+ goto msix;
+ if (!strcmp(ioat_interrupt_style, "msix-single-vector"))
+ goto msix_single_vector;
+ if (!strcmp(ioat_interrupt_style, "msi"))
+ goto msi;
+ if (!strcmp(ioat_interrupt_style, "intx"))
+ goto intx;
+ dev_err(&device->pdev->dev, "invalid ioat_interrupt_style %s\n",
+ ioat_interrupt_style);
+ goto err_no_irq;
+
+msix:
+ /* The number of MSI-X vectors should equal the number of channels */
+ msixcnt = device->common.chancnt;
+ for (i = 0; i < msixcnt; i++)
+ device->msix_entries[i].entry = i;
+
+ err = pci_enable_msix(device->pdev, device->msix_entries, msixcnt);
+ if (err < 0)
+ goto msi;
+ if (err > 0)
+ goto msix_single_vector;
+
+ for (i = 0; i < msixcnt; i++) {
+ ioat_chan = ioat_lookup_chan_by_index(device, i);
+ err = request_irq(device->msix_entries[i].vector,
+ ioat_dma_do_interrupt_msix,
+ 0, "ioat-msix", ioat_chan);
+ if (err) {
+ for (j = 0; j < i; j++) {
+ ioat_chan =
+ ioat_lookup_chan_by_index(device, j);
+ free_irq(device->msix_entries[j].vector,
+ ioat_chan);
+ }
+ goto msix_single_vector;
+ }
+ }
+ intrctrl |= IOAT_INTRCTRL_MSIX_VECTOR_CONTROL;
+ device->irq_mode = msix_multi_vector;
+ goto done;
+
+msix_single_vector:
+ device->msix_entries[0].entry = 0;
+ err = pci_enable_msix(device->pdev, device->msix_entries, 1);
+ if (err)
+ goto msi;
+
+ err = request_irq(device->msix_entries[0].vector, ioat_dma_do_interrupt,
+ 0, "ioat-msix", device);
+ if (err) {
+ pci_disable_msix(device->pdev);
+ goto msi;
+ }
+ device->irq_mode = msix_single_vector;
+ goto done;
+
+msi:
+ err = pci_enable_msi(device->pdev);
+ if (err)
+ goto intx;
+
+ err = request_irq(device->pdev->irq, ioat_dma_do_interrupt,
+ 0, "ioat-msi", device);
+ if (err) {
+ pci_disable_msi(device->pdev);
+ goto intx;
+ }
+ /*
+ * CB 1.2 devices need a bit set in configuration space to enable MSI
+ */
+ if (device->version == IOAT_VER_1_2) {
+ u32 dmactrl;
+ pci_read_config_dword(device->pdev,
+ IOAT_PCI_DMACTRL_OFFSET, &dmactrl);
+ dmactrl |= IOAT_PCI_DMACTRL_MSI_EN;
+ pci_write_config_dword(device->pdev,
+ IOAT_PCI_DMACTRL_OFFSET, dmactrl);
+ }
+ device->irq_mode = msi;
+ goto done;
+
+intx:
+ err = request_irq(device->pdev->irq, ioat_dma_do_interrupt,
+ IRQF_SHARED, "ioat-intx", device);
+ if (err)
+ goto err_no_irq;
+ device->irq_mode = intx;
+
+done:
+ intrctrl |= IOAT_INTRCTRL_MASTER_INT_EN;
+ writeb(intrctrl, device->reg_base + IOAT_INTRCTRL_OFFSET);
+ return 0;
+
+err_no_irq:
+ /* Disable all interrupt generation */
+ writeb(0, device->reg_base + IOAT_INTRCTRL_OFFSET);
+ dev_err(&device->pdev->dev, "no usable interrupts\n");
+ device->irq_mode = none;
+ return -1;
+}
+
+/**
+ * ioat_dma_remove_interrupts - remove whatever interrupts were set
+ * @device: ioat device
+ */
+static void ioat_dma_remove_interrupts(struct ioatdma_device *device)
+{
+ struct ioat_dma_chan *ioat_chan;
+ int i;
+
+ /* Disable all interrupt generation */
+ writeb(0, device->reg_base + IOAT_INTRCTRL_OFFSET);
+
+ switch (device->irq_mode) {
+ case msix_multi_vector:
+ for (i = 0; i < device->common.chancnt; i++) {
+ ioat_chan = ioat_lookup_chan_by_index(device, i);
+ free_irq(device->msix_entries[i].vector, ioat_chan);
+ }
+ pci_disable_msix(device->pdev);
+ break;
+ case msix_single_vector:
+ free_irq(device->msix_entries[0].vector, device);
+ pci_disable_msix(device->pdev);
+ break;
+ case msi:
+ free_irq(device->pdev->irq, device);
+ pci_disable_msi(device->pdev);
+ break;
+ case intx:
+ free_irq(device->pdev->irq, device);
+ break;
+ case none:
+ dev_warn(&device->pdev->dev,
+ "call to %s without interrupts setup\n", __func__);
+ }
+ device->irq_mode = none;
+}
+
+struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev,
+ void __iomem *iobase)
+{
+ int err;
+ struct ioatdma_device *device;
+
+ device = kzalloc(sizeof(*device), GFP_KERNEL);
+ if (!device) {
+ err = -ENOMEM;
+ goto err_kzalloc;
+ }
+ device->pdev = pdev;
+ device->reg_base = iobase;
+ device->version = readb(device->reg_base + IOAT_VER_OFFSET);
+
+ /* DMA coherent memory pool for DMA descriptor allocations */
+ device->dma_pool = pci_pool_create("dma_desc_pool", pdev,
+ sizeof(struct ioat_dma_descriptor),
+ 64, 0);
+ if (!device->dma_pool) {
+ err = -ENOMEM;
+ goto err_dma_pool;
+ }
+
+ device->completion_pool = pci_pool_create("completion_pool", pdev,
+ sizeof(u64), SMP_CACHE_BYTES,
+ SMP_CACHE_BYTES);
+ if (!device->completion_pool) {
+ err = -ENOMEM;
+ goto err_completion_pool;
+ }
+
+ INIT_LIST_HEAD(&device->common.channels);
+ ioat_dma_enumerate_channels(device);
+
+ device->common.device_alloc_chan_resources =
+ ioat_dma_alloc_chan_resources;
+ device->common.device_free_chan_resources =
+ ioat_dma_free_chan_resources;
+ device->common.dev = &pdev->dev;
+
+ dma_cap_set(DMA_MEMCPY, device->common.cap_mask);
+ device->common.device_is_tx_complete = ioat_dma_is_complete;
+ device->common.device_dependency_added = ioat_dma_dependency_added;
+ switch (device->version) {
+ case IOAT_VER_1_2:
+ device->common.device_prep_dma_memcpy = ioat1_dma_prep_memcpy;
+ device->common.device_issue_pending =
+ ioat1_dma_memcpy_issue_pending;
+ break;
+ case IOAT_VER_2_0:
+ device->common.device_prep_dma_memcpy = ioat2_dma_prep_memcpy;
+ device->common.device_issue_pending =
+ ioat2_dma_memcpy_issue_pending;
+ break;
+ }
+
+ dev_err(&device->pdev->dev,
+ "Intel(R) I/OAT DMA Engine found,"
+ " %d channels, device version 0x%02x, driver version %s\n",
+ device->common.chancnt, device->version, IOAT_DMA_VERSION);
+
+ err = ioat_dma_setup_interrupts(device);
+ if (err)
+ goto err_setup_interrupts;
+
+ err = ioat_dma_self_test(device);
+ if (err)
+ goto err_self_test;
+
+ dma_async_device_register(&device->common);
+
+ return device;
+
+err_self_test:
+ ioat_dma_remove_interrupts(device);
+err_setup_interrupts:
+ pci_pool_destroy(device->completion_pool);
+err_completion_pool:
+ pci_pool_destroy(device->dma_pool);
+err_dma_pool:
+ kfree(device);
+err_kzalloc:
+ dev_err(&device->pdev->dev,
+ "Intel(R) I/OAT DMA Engine initialization failed\n");
+ return NULL;
+}
+
+void ioat_dma_remove(struct ioatdma_device *device)
+{
+ struct dma_chan *chan, *_chan;
+ struct ioat_dma_chan *ioat_chan;
+
+ ioat_dma_remove_interrupts(device);
+
+ dma_async_device_unregister(&device->common);
+
+ pci_pool_destroy(device->dma_pool);
+ pci_pool_destroy(device->completion_pool);
+
+ iounmap(device->reg_base);
+ pci_release_regions(device->pdev);
+ pci_disable_device(device->pdev);
+
+ list_for_each_entry_safe(chan, _chan,
+ &device->common.channels, device_node) {
+ ioat_chan = to_ioat_chan(chan);
+ list_del(&chan->device_node);
+ kfree(ioat_chan);
+ }
+ kfree(device);
+}
+
diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c
deleted file mode 100644
index 41b18c5a314..00000000000
--- a/drivers/dma/ioatdma.c
+++ /dev/null
@@ -1,817 +0,0 @@
-/*
- * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-/*
- * This driver supports an Intel I/OAT DMA engine, which does asynchronous
- * copy operations.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/dmaengine.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include "ioatdma.h"
-#include "ioatdma_registers.h"
-#include "ioatdma_hw.h"
-
-#define to_ioat_chan(chan) container_of(chan, struct ioat_dma_chan, common)
-#define to_ioat_device(dev) container_of(dev, struct ioat_device, common)
-#define to_ioat_desc(lh) container_of(lh, struct ioat_desc_sw, node)
-#define tx_to_ioat_desc(tx) container_of(tx, struct ioat_desc_sw, async_tx)
-
-/* internal functions */
-static int __devinit ioat_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
-static void ioat_shutdown(struct pci_dev *pdev);
-static void __devexit ioat_remove(struct pci_dev *pdev);
-
-static int enumerate_dma_channels(struct ioat_device *device)
-{
- u8 xfercap_scale;
- u32 xfercap;
- int i;
- struct ioat_dma_chan *ioat_chan;
-
- device->common.chancnt = readb(device->reg_base + IOAT_CHANCNT_OFFSET);
- xfercap_scale = readb(device->reg_base + IOAT_XFERCAP_OFFSET);
- xfercap = (xfercap_scale == 0 ? -1 : (1UL << xfercap_scale));
-
- for (i = 0; i < device->common.chancnt; i++) {
- ioat_chan = kzalloc(sizeof(*ioat_chan), GFP_KERNEL);
- if (!ioat_chan) {
- device->common.chancnt = i;
- break;
- }
-
- ioat_chan->device = device;
- ioat_chan->reg_base = device->reg_base + (0x80 * (i + 1));
- ioat_chan->xfercap = xfercap;
- spin_lock_init(&ioat_chan->cleanup_lock);
- spin_lock_init(&ioat_chan->desc_lock);
- INIT_LIST_HEAD(&ioat_chan->free_desc);
- INIT_LIST_HEAD(&ioat_chan->used_desc);
- /* This should be made common somewhere in dmaengine.c */
- ioat_chan->common.device = &device->common;
- list_add_tail(&ioat_chan->common.device_node,
- &device->common.channels);
- }
- return device->common.chancnt;
-}
-
-static void
-ioat_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx, int index)
-{
- struct ioat_desc_sw *iter, *desc = tx_to_ioat_desc(tx);
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan);
-
- pci_unmap_addr_set(desc, src, addr);
-
- list_for_each_entry(iter, &desc->async_tx.tx_list, node) {
- iter->hw->src_addr = addr;
- addr += ioat_chan->xfercap;
- }
-
-}
-
-static void
-ioat_set_dest(dma_addr_t addr, struct dma_async_tx_descriptor *tx, int index)
-{
- struct ioat_desc_sw *iter, *desc = tx_to_ioat_desc(tx);
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan);
-
- pci_unmap_addr_set(desc, dst, addr);
-
- list_for_each_entry(iter, &desc->async_tx.tx_list, node) {
- iter->hw->dst_addr = addr;
- addr += ioat_chan->xfercap;
- }
-}
-
-static dma_cookie_t
-ioat_tx_submit(struct dma_async_tx_descriptor *tx)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan);
- struct ioat_desc_sw *desc = tx_to_ioat_desc(tx);
- int append = 0;
- dma_cookie_t cookie;
- struct ioat_desc_sw *group_start;
-
- group_start = list_entry(desc->async_tx.tx_list.next,
- struct ioat_desc_sw, node);
- spin_lock_bh(&ioat_chan->desc_lock);
- /* cookie incr and addition to used_list must be atomic */
- cookie = ioat_chan->common.cookie;
- cookie++;
- if (cookie < 0)
- cookie = 1;
- ioat_chan->common.cookie = desc->async_tx.cookie = cookie;
-
- /* write address into NextDescriptor field of last desc in chain */
- to_ioat_desc(ioat_chan->used_desc.prev)->hw->next =
- group_start->async_tx.phys;
- list_splice_init(&desc->async_tx.tx_list, ioat_chan->used_desc.prev);
-
- ioat_chan->pending += desc->tx_cnt;
- if (ioat_chan->pending >= 4) {
- append = 1;
- ioat_chan->pending = 0;
- }
- spin_unlock_bh(&ioat_chan->desc_lock);
-
- if (append)
- writeb(IOAT_CHANCMD_APPEND,
- ioat_chan->reg_base + IOAT_CHANCMD_OFFSET);
-
- return cookie;
-}
-
-static struct ioat_desc_sw *ioat_dma_alloc_descriptor(
- struct ioat_dma_chan *ioat_chan,
- gfp_t flags)
-{
- struct ioat_dma_descriptor *desc;
- struct ioat_desc_sw *desc_sw;
- struct ioat_device *ioat_device;
- dma_addr_t phys;
-
- ioat_device = to_ioat_device(ioat_chan->common.device);
- desc = pci_pool_alloc(ioat_device->dma_pool, flags, &phys);
- if (unlikely(!desc))
- return NULL;
-
- desc_sw = kzalloc(sizeof(*desc_sw), flags);
- if (unlikely(!desc_sw)) {
- pci_pool_free(ioat_device->dma_pool, desc, phys);
- return NULL;
- }
-
- memset(desc, 0, sizeof(*desc));
- dma_async_tx_descriptor_init(&desc_sw->async_tx, &ioat_chan->common);
- desc_sw->async_tx.tx_set_src = ioat_set_src;
- desc_sw->async_tx.tx_set_dest = ioat_set_dest;
- desc_sw->async_tx.tx_submit = ioat_tx_submit;
- INIT_LIST_HEAD(&desc_sw->async_tx.tx_list);
- desc_sw->hw = desc;
- desc_sw->async_tx.phys = phys;
-
- return desc_sw;
-}
-
-#define INITIAL_IOAT_DESC_COUNT 128
-
-static void ioat_start_null_desc(struct ioat_dma_chan *ioat_chan);
-
-/* returns the actual number of allocated descriptors */
-static int ioat_dma_alloc_chan_resources(struct dma_chan *chan)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
- struct ioat_desc_sw *desc = NULL;
- u16 chanctrl;
- u32 chanerr;
- int i;
- LIST_HEAD(tmp_list);
-
- /* have we already been set up? */
- if (!list_empty(&ioat_chan->free_desc))
- return INITIAL_IOAT_DESC_COUNT;
-
- /* Setup register to interrupt and write completion status on error */
- chanctrl = IOAT_CHANCTRL_ERR_INT_EN |
- IOAT_CHANCTRL_ANY_ERR_ABORT_EN |
- IOAT_CHANCTRL_ERR_COMPLETION_EN;
- writew(chanctrl, ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
-
- chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
- if (chanerr) {
- printk("IOAT: CHANERR = %x, clearing\n", chanerr);
- writel(chanerr, ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
- }
-
- /* Allocate descriptors */
- for (i = 0; i < INITIAL_IOAT_DESC_COUNT; i++) {
- desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_KERNEL);
- if (!desc) {
- printk(KERN_ERR "IOAT: Only %d initial descriptors\n", i);
- break;
- }
- list_add_tail(&desc->node, &tmp_list);
- }
- spin_lock_bh(&ioat_chan->desc_lock);
- list_splice(&tmp_list, &ioat_chan->free_desc);
- spin_unlock_bh(&ioat_chan->desc_lock);
-
- /* allocate a completion writeback area */
- /* doing 2 32bit writes to mmio since 1 64b write doesn't work */
- ioat_chan->completion_virt =
- pci_pool_alloc(ioat_chan->device->completion_pool,
- GFP_KERNEL,
- &ioat_chan->completion_addr);
- memset(ioat_chan->completion_virt, 0,
- sizeof(*ioat_chan->completion_virt));
- writel(((u64) ioat_chan->completion_addr) & 0x00000000FFFFFFFF,
- ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_LOW);
- writel(((u64) ioat_chan->completion_addr) >> 32,
- ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
-
- ioat_start_null_desc(ioat_chan);
- return i;
-}
-
-static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan);
-
-static void ioat_dma_free_chan_resources(struct dma_chan *chan)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
- struct ioat_device *ioat_device = to_ioat_device(chan->device);
- struct ioat_desc_sw *desc, *_desc;
- u16 chanctrl;
- int in_use_descs = 0;
-
- ioat_dma_memcpy_cleanup(ioat_chan);
-
- writeb(IOAT_CHANCMD_RESET, ioat_chan->reg_base + IOAT_CHANCMD_OFFSET);
-
- spin_lock_bh(&ioat_chan->desc_lock);
- list_for_each_entry_safe(desc, _desc, &ioat_chan->used_desc, node) {
- in_use_descs++;
- list_del(&desc->node);
- pci_pool_free(ioat_device->dma_pool, desc->hw,
- desc->async_tx.phys);
- kfree(desc);
- }
- list_for_each_entry_safe(desc, _desc, &ioat_chan->free_desc, node) {
- list_del(&desc->node);
- pci_pool_free(ioat_device->dma_pool, desc->hw,
- desc->async_tx.phys);
- kfree(desc);
- }
- spin_unlock_bh(&ioat_chan->desc_lock);
-
- pci_pool_free(ioat_device->completion_pool,
- ioat_chan->completion_virt,
- ioat_chan->completion_addr);
-
- /* one is ok since we left it on there on purpose */
- if (in_use_descs > 1)
- printk(KERN_ERR "IOAT: Freeing %d in use descriptors!\n",
- in_use_descs - 1);
-
- ioat_chan->last_completion = ioat_chan->completion_addr = 0;
-}
-
-static struct dma_async_tx_descriptor *
-ioat_dma_prep_memcpy(struct dma_chan *chan, size_t len, int int_en)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
- struct ioat_desc_sw *first, *prev, *new;
- LIST_HEAD(new_chain);
- u32 copy;
- size_t orig_len;
- int desc_count = 0;
-
- if (!len)
- return NULL;
-
- orig_len = len;
-
- first = NULL;
- prev = NULL;
-
- spin_lock_bh(&ioat_chan->desc_lock);
- while (len) {
- if (!list_empty(&ioat_chan->free_desc)) {
- new = to_ioat_desc(ioat_chan->free_desc.next);
- list_del(&new->node);
- } else {
- /* try to get another desc */
- new = ioat_dma_alloc_descriptor(ioat_chan, GFP_ATOMIC);
- /* will this ever happen? */
- /* TODO add upper limit on these */
- BUG_ON(!new);
- }
-
- copy = min((u32) len, ioat_chan->xfercap);
-
- new->hw->size = copy;
- new->hw->ctl = 0;
- new->async_tx.cookie = 0;
- new->async_tx.ack = 1;
-
- /* chain together the physical address list for the HW */
- if (!first)
- first = new;
- else
- prev->hw->next = (u64) new->async_tx.phys;
-
- prev = new;
- len -= copy;
- list_add_tail(&new->node, &new_chain);
- desc_count++;
- }
-
- list_splice(&new_chain, &new->async_tx.tx_list);
-
- new->hw->ctl = IOAT_DMA_DESCRIPTOR_CTL_CP_STS;
- new->hw->next = 0;
- new->tx_cnt = desc_count;
- new->async_tx.ack = 0; /* client is in control of this ack */
- new->async_tx.cookie = -EBUSY;
-
- pci_unmap_len_set(new, len, orig_len);
- spin_unlock_bh(&ioat_chan->desc_lock);
-
- return new ? &new->async_tx : NULL;
-}
-
-
-/**
- * ioat_dma_memcpy_issue_pending - push potentially unrecognized appended descriptors to hw
- * @chan: DMA channel handle
- */
-
-static void ioat_dma_memcpy_issue_pending(struct dma_chan *chan)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
-
- if (ioat_chan->pending != 0) {
- ioat_chan->pending = 0;
- writeb(IOAT_CHANCMD_APPEND,
- ioat_chan->reg_base + IOAT_CHANCMD_OFFSET);
- }
-}
-
-static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan)
-{
- unsigned long phys_complete;
- struct ioat_desc_sw *desc, *_desc;
- dma_cookie_t cookie = 0;
-
- prefetch(chan->completion_virt);
-
- if (!spin_trylock(&chan->cleanup_lock))
- return;
-
- /* The completion writeback can happen at any time,
- so reads by the driver need to be atomic operations
- The descriptor physical addresses are limited to 32-bits
- when the CPU can only do a 32-bit mov */
-
-#if (BITS_PER_LONG == 64)
- phys_complete =
- chan->completion_virt->full & IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR;
-#else
- phys_complete = chan->completion_virt->low & IOAT_LOW_COMPLETION_MASK;
-#endif
-
- if ((chan->completion_virt->full & IOAT_CHANSTS_DMA_TRANSFER_STATUS) ==
- IOAT_CHANSTS_DMA_TRANSFER_STATUS_HALTED) {
- printk("IOAT: Channel halted, chanerr = %x\n",
- readl(chan->reg_base + IOAT_CHANERR_OFFSET));
-
- /* TODO do something to salvage the situation */
- }
-
- if (phys_complete == chan->last_completion) {
- spin_unlock(&chan->cleanup_lock);
- return;
- }
-
- spin_lock_bh(&chan->desc_lock);
- list_for_each_entry_safe(desc, _desc, &chan->used_desc, node) {
-
- /*
- * Incoming DMA requests may use multiple descriptors, due to
- * exceeding xfercap, perhaps. If so, only the last one will
- * have a cookie, and require unmapping.
- */
- if (desc->async_tx.cookie) {
- cookie = desc->async_tx.cookie;
-
- /* yes we are unmapping both _page and _single alloc'd
- regions with unmap_page. Is this *really* that bad?
- */
- pci_unmap_page(chan->device->pdev,
- pci_unmap_addr(desc, dst),
- pci_unmap_len(desc, len),
- PCI_DMA_FROMDEVICE);
- pci_unmap_page(chan->device->pdev,
- pci_unmap_addr(desc, src),
- pci_unmap_len(desc, len),
- PCI_DMA_TODEVICE);
- }
-
- if (desc->async_tx.phys != phys_complete) {
- /* a completed entry, but not the last, so cleanup
- * if the client is done with the descriptor
- */
- if (desc->async_tx.ack) {
- list_del(&desc->node);
- list_add_tail(&desc->node, &chan->free_desc);
- } else
- desc->async_tx.cookie = 0;
- } else {
- /* last used desc. Do not remove, so we can append from
- it, but don't look at it next time, either */
- desc->async_tx.cookie = 0;
-
- /* TODO check status bits? */
- break;
- }
- }
-
- spin_unlock_bh(&chan->desc_lock);
-
- chan->last_completion = phys_complete;
- if (cookie != 0)
- chan->completed_cookie = cookie;
-
- spin_unlock(&chan->cleanup_lock);
-}
-
-static void ioat_dma_dependency_added(struct dma_chan *chan)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
- spin_lock_bh(&ioat_chan->desc_lock);
- if (ioat_chan->pending == 0) {
- spin_unlock_bh(&ioat_chan->desc_lock);
- ioat_dma_memcpy_cleanup(ioat_chan);
- } else
- spin_unlock_bh(&ioat_chan->desc_lock);
-}
-
-/**
- * ioat_dma_is_complete - poll the status of a IOAT DMA transaction
- * @chan: IOAT DMA channel handle
- * @cookie: DMA transaction identifier
- * @done: if not %NULL, updated with last completed transaction
- * @used: if not %NULL, updated with last used transaction
- */
-
-static enum dma_status ioat_dma_is_complete(struct dma_chan *chan,
- dma_cookie_t cookie,
- dma_cookie_t *done,
- dma_cookie_t *used)
-{
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
- enum dma_status ret;
-
- last_used = chan->cookie;
- last_complete = ioat_chan->completed_cookie;
-
- if (done)
- *done= last_complete;
- if (used)
- *used = last_used;
-
- ret = dma_async_is_complete(cookie, last_complete, last_used);
- if (ret == DMA_SUCCESS)
- return ret;
-
- ioat_dma_memcpy_cleanup(ioat_chan);
-
- last_used = chan->cookie;
- last_complete = ioat_chan->completed_cookie;
-
- if (done)
- *done= last_complete;
- if (used)
- *used = last_used;
-
- return dma_async_is_complete(cookie, last_complete, last_used);
-}
-
-/* PCI API */
-
-static struct pci_device_id ioat_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT) },
- { PCI_DEVICE(PCI_VENDOR_ID_UNISYS,
- PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR) },
- { 0, }
-};
-
-static struct pci_driver ioat_pci_driver = {
- .name = "ioatdma",
- .id_table = ioat_pci_tbl,
- .probe = ioat_probe,
- .shutdown = ioat_shutdown,
- .remove = __devexit_p(ioat_remove),
-};
-
-static irqreturn_t ioat_do_interrupt(int irq, void *data)
-{
- struct ioat_device *instance = data;
- unsigned long attnstatus;
- u8 intrctrl;
-
- intrctrl = readb(instance->reg_base + IOAT_INTRCTRL_OFFSET);
-
- if (!(intrctrl & IOAT_INTRCTRL_MASTER_INT_EN))
- return IRQ_NONE;
-
- if (!(intrctrl & IOAT_INTRCTRL_INT_STATUS)) {
- writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
- return IRQ_NONE;
- }
-
- attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET);
-
- printk(KERN_ERR "ioatdma error: interrupt! status %lx\n", attnstatus);
-
- writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
- return IRQ_HANDLED;
-}
-
-static void ioat_start_null_desc(struct ioat_dma_chan *ioat_chan)
-{
- struct ioat_desc_sw *desc;
-
- spin_lock_bh(&ioat_chan->desc_lock);
-
- if (!list_empty(&ioat_chan->free_desc)) {
- desc = to_ioat_desc(ioat_chan->free_desc.next);
- list_del(&desc->node);
- } else {
- /* try to get another desc */
- spin_unlock_bh(&ioat_chan->desc_lock);
- desc = ioat_dma_alloc_descriptor(ioat_chan, GFP_KERNEL);
- spin_lock_bh(&ioat_chan->desc_lock);
- /* will this ever happen? */
- BUG_ON(!desc);
- }
-
- desc->hw->ctl = IOAT_DMA_DESCRIPTOR_NUL;
- desc->hw->next = 0;
- desc->async_tx.ack = 1;
-
- list_add_tail(&desc->node, &ioat_chan->used_desc);
- spin_unlock_bh(&ioat_chan->desc_lock);
-
- writel(((u64) desc->async_tx.phys) & 0x00000000FFFFFFFF,
- ioat_chan->reg_base + IOAT_CHAINADDR_OFFSET_LOW);
- writel(((u64) desc->async_tx.phys) >> 32,
- ioat_chan->reg_base + IOAT_CHAINADDR_OFFSET_HIGH);
-
- writeb(IOAT_CHANCMD_START, ioat_chan->reg_base + IOAT_CHANCMD_OFFSET);
-}
-
-/*
- * Perform a IOAT transaction to verify the HW works.
- */
-#define IOAT_TEST_SIZE 2000
-
-static int ioat_self_test(struct ioat_device *device)
-{
- int i;
- u8 *src;
- u8 *dest;
- struct dma_chan *dma_chan;
- struct dma_async_tx_descriptor *tx;
- dma_addr_t addr;
- dma_cookie_t cookie;
- int err = 0;
-
- src = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL);
- if (!src)
- return -ENOMEM;
- dest = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL);
- if (!dest) {
- kfree(src);
- return -ENOMEM;
- }
-
- /* Fill in src buffer */
- for (i = 0; i < IOAT_TEST_SIZE; i++)
- src[i] = (u8)i;
-
- /* Start copy, using first DMA channel */
- dma_chan = container_of(device->common.channels.next,
- struct dma_chan,
- device_node);
- if (ioat_dma_alloc_chan_resources(dma_chan) < 1) {
- err = -ENODEV;
- goto out;
- }
-
- tx = ioat_dma_prep_memcpy(dma_chan, IOAT_TEST_SIZE, 0);
- async_tx_ack(tx);
- addr = dma_map_single(dma_chan->device->dev, src, IOAT_TEST_SIZE,
- DMA_TO_DEVICE);
- ioat_set_src(addr, tx, 0);
- addr = dma_map_single(dma_chan->device->dev, dest, IOAT_TEST_SIZE,
- DMA_FROM_DEVICE);
- ioat_set_dest(addr, tx, 0);
- cookie = ioat_tx_submit(tx);
- ioat_dma_memcpy_issue_pending(dma_chan);
- msleep(1);
-
- if (ioat_dma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) {
- printk(KERN_ERR "ioatdma: Self-test copy timed out, disabling\n");
- err = -ENODEV;
- goto free_resources;
- }
- if (memcmp(src, dest, IOAT_TEST_SIZE)) {
- printk(KERN_ERR "ioatdma: Self-test copy failed compare, disabling\n");
- err = -ENODEV;
- goto free_resources;
- }
-
-free_resources:
- ioat_dma_free_chan_resources(dma_chan);
-out:
- kfree(src);
- kfree(dest);
- return err;
-}
-
-static int __devinit ioat_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int err;
- unsigned long mmio_start, mmio_len;
- void __iomem *reg_base;
- struct ioat_device *device;
-
- err = pci_enable_device(pdev);
- if (err)
- goto err_enable_device;
-
- err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
- if (err)
- err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (err)
- goto err_set_dma_mask;
-
- err = pci_request_regions(pdev, ioat_pci_driver.name);
- if (err)
- goto err_request_regions;
-
- mmio_start = pci_resource_start(pdev, 0);
- mmio_len = pci_resource_len(pdev, 0);
-
- reg_base = ioremap(mmio_start, mmio_len);
- if (!reg_base) {
- err = -ENOMEM;
- goto err_ioremap;
- }
-
- device = kzalloc(sizeof(*device), GFP_KERNEL);
- if (!device) {
- err = -ENOMEM;
- goto err_kzalloc;
- }
-
- /* DMA coherent memory pool for DMA descriptor allocations */
- device->dma_pool = pci_pool_create("dma_desc_pool", pdev,
- sizeof(struct ioat_dma_descriptor), 64, 0);
- if (!device->dma_pool) {
- err = -ENOMEM;
- goto err_dma_pool;
- }
-
- device->completion_pool = pci_pool_create("completion_pool", pdev, sizeof(u64), SMP_CACHE_BYTES, SMP_CACHE_BYTES);
- if (!device->completion_pool) {
- err = -ENOMEM;
- goto err_completion_pool;
- }
-
- device->pdev = pdev;
- pci_set_drvdata(pdev, device);
-#ifdef CONFIG_PCI_MSI
- if (pci_enable_msi(pdev) == 0) {
- device->msi = 1;
- } else {
- device->msi = 0;
- }
-#endif
- err = request_irq(pdev->irq, &ioat_do_interrupt, IRQF_SHARED, "ioat",
- device);
- if (err)
- goto err_irq;
-
- device->reg_base = reg_base;
-
- writeb(IOAT_INTRCTRL_MASTER_INT_EN, device->reg_base + IOAT_INTRCTRL_OFFSET);
- pci_set_master(pdev);
-
- INIT_LIST_HEAD(&device->common.channels);
- enumerate_dma_channels(device);
-
- dma_cap_set(DMA_MEMCPY, device->common.cap_mask);
- device->common.device_alloc_chan_resources = ioat_dma_alloc_chan_resources;
- device->common.device_free_chan_resources = ioat_dma_free_chan_resources;
- device->common.device_prep_dma_memcpy = ioat_dma_prep_memcpy;
- device->common.device_is_tx_complete = ioat_dma_is_complete;
- device->common.device_issue_pending = ioat_dma_memcpy_issue_pending;
- device->common.device_dependency_added = ioat_dma_dependency_added;
- device->common.dev = &pdev->dev;
- printk(KERN_INFO "Intel(R) I/OAT DMA Engine found, %d channels\n",
- device->common.chancnt);
-
- err = ioat_self_test(device);
- if (err)
- goto err_self_test;
-
- dma_async_device_register(&device->common);
-
- return 0;
-
-err_self_test:
-err_irq:
- pci_pool_destroy(device->completion_pool);
-err_completion_pool:
- pci_pool_destroy(device->dma_pool);
-err_dma_pool:
- kfree(device);
-err_kzalloc:
- iounmap(reg_base);
-err_ioremap:
- pci_release_regions(pdev);
-err_request_regions:
-err_set_dma_mask:
- pci_disable_device(pdev);
-err_enable_device:
-
- printk(KERN_ERR "Intel(R) I/OAT DMA Engine initialization failed\n");
-
- return err;
-}
-
-static void ioat_shutdown(struct pci_dev *pdev)
-{
- struct ioat_device *device;
- device = pci_get_drvdata(pdev);
-
- dma_async_device_unregister(&device->common);
-}
-
-static void __devexit ioat_remove(struct pci_dev *pdev)
-{
- struct ioat_device *device;
- struct dma_chan *chan, *_chan;
- struct ioat_dma_chan *ioat_chan;
-
- device = pci_get_drvdata(pdev);
- dma_async_device_unregister(&device->common);
-
- free_irq(device->pdev->irq, device);
-#ifdef CONFIG_PCI_MSI
- if (device->msi)
- pci_disable_msi(device->pdev);
-#endif
- pci_pool_destroy(device->dma_pool);
- pci_pool_destroy(device->completion_pool);
- iounmap(device->reg_base);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- list_for_each_entry_safe(chan, _chan, &device->common.channels, device_node) {
- ioat_chan = to_ioat_chan(chan);
- list_del(&chan->device_node);
- kfree(ioat_chan);
- }
- kfree(device);
-}
-
-/* MODULE API */
-MODULE_VERSION("1.9");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Intel Corporation");
-
-static int __init ioat_init_module(void)
-{
- /* it's currently unsafe to unload this module */
- /* if forced, worst case is that rmmod hangs */
- __unsafe(THIS_MODULE);
-
- return pci_register_driver(&ioat_pci_driver);
-}
-
-module_init(ioat_init_module);
-
-static void __exit ioat_exit_module(void)
-{
- pci_unregister_driver(&ioat_pci_driver);
-}
-
-module_exit(ioat_exit_module);
diff --git a/drivers/dma/ioatdma.h b/drivers/dma/ioatdma.h
index bf4dad70e0f..b668234ef65 100644
--- a/drivers/dma/ioatdma.h
+++ b/drivers/dma/ioatdma.h
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
+ * Copyright(c) 2004 - 2007 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -28,46 +28,47 @@
#include <linux/cache.h>
#include <linux/pci_ids.h>
+#define IOAT_DMA_VERSION "2.04"
+
+enum ioat_interrupt {
+ none = 0,
+ msix_multi_vector = 1,
+ msix_single_vector = 2,
+ msi = 3,
+ intx = 4,
+};
+
#define IOAT_LOW_COMPLETION_MASK 0xffffffc0
+#define IOAT_DMA_DCA_ANY_CPU ~0
+
/**
- * struct ioat_device - internal representation of a IOAT device
+ * struct ioatdma_device - internal representation of a IOAT device
* @pdev: PCI-Express device
* @reg_base: MMIO register space base address
* @dma_pool: for allocating DMA descriptors
* @common: embedded struct dma_device
- * @msi: Message Signaled Interrupt number
+ * @version: version of ioatdma device
+ * @irq_mode: which style irq to use
+ * @msix_entries: irq handlers
+ * @idx: per channel data
*/
-struct ioat_device {
+struct ioatdma_device {
struct pci_dev *pdev;
void __iomem *reg_base;
struct pci_pool *dma_pool;
struct pci_pool *completion_pool;
-
struct dma_device common;
- u8 msi;
+ u8 version;
+ enum ioat_interrupt irq_mode;
+ struct msix_entry msix_entries[4];
+ struct ioat_dma_chan *idx[4];
};
/**
* struct ioat_dma_chan - internal representation of a DMA channel
- * @device:
- * @reg_base:
- * @sw_in_use:
- * @completion:
- * @completion_low:
- * @completion_high:
- * @completed_cookie: last cookie seen completed on cleanup
- * @cookie: value of last cookie given to client
- * @last_completion:
- * @xfercap:
- * @desc_lock:
- * @free_desc:
- * @used_desc:
- * @resource:
- * @device_node:
*/
-
struct ioat_dma_chan {
void __iomem *reg_base;
@@ -83,8 +84,10 @@ struct ioat_dma_chan {
struct list_head used_desc;
int pending;
+ int dmacount;
+ int desccount;
- struct ioat_device *device;
+ struct ioatdma_device *device;
struct dma_chan common;
dma_addr_t completion_addr;
@@ -95,6 +98,7 @@ struct ioat_dma_chan {
u32 high;
};
} *completion_virt;
+ struct tasklet_struct cleanup_task;
};
/* wrapper around hardware descriptor format + additional software fields */
@@ -111,10 +115,23 @@ struct ioat_desc_sw {
struct ioat_dma_descriptor *hw;
struct list_head node;
int tx_cnt;
- DECLARE_PCI_UNMAP_LEN(len)
- DECLARE_PCI_UNMAP_ADDR(src)
- DECLARE_PCI_UNMAP_ADDR(dst)
+ size_t len;
+ dma_addr_t src;
+ dma_addr_t dst;
struct dma_async_tx_descriptor async_tx;
};
+#if defined(CONFIG_INTEL_IOATDMA) || defined(CONFIG_INTEL_IOATDMA_MODULE)
+struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev,
+ void __iomem *iobase);
+void ioat_dma_remove(struct ioatdma_device *device);
+struct dca_provider *ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase);
+struct dca_provider *ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase);
+#else
+#define ioat_dma_probe(pdev, iobase) NULL
+#define ioat_dma_remove(device) do { } while (0)
+#define ioat_dca_init(pdev, iobase) NULL
+#define ioat2_dca_init(pdev, iobase) NULL
+#endif
+
#endif /* IOATDMA_H */
diff --git a/drivers/dma/ioatdma_hw.h b/drivers/dma/ioatdma_hw.h
index 4d7a12880be..dd470fa91d8 100644
--- a/drivers/dma/ioatdma_hw.h
+++ b/drivers/dma/ioatdma_hw.h
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
+ * Copyright(c) 2004 - 2007 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -22,12 +22,19 @@
#define _IOAT_HW_H_
/* PCI Configuration Space Values */
-#define IOAT_PCI_VID 0x8086
-#define IOAT_PCI_DID 0x1A38
-#define IOAT_PCI_RID 0x00
-#define IOAT_PCI_SVID 0x8086
-#define IOAT_PCI_SID 0x8086
-#define IOAT_VER 0x12 /* Version 1.2 */
+#define IOAT_PCI_VID 0x8086
+
+/* CB device ID's */
+#define IOAT_PCI_DID_5000 0x1A38
+#define IOAT_PCI_DID_CNB 0x360B
+#define IOAT_PCI_DID_SCNB 0x65FF
+#define IOAT_PCI_DID_SNB 0x402F
+
+#define IOAT_PCI_RID 0x00
+#define IOAT_PCI_SVID 0x8086
+#define IOAT_PCI_SID 0x8086
+#define IOAT_VER_1_2 0x12 /* Version 1.2 */
+#define IOAT_VER_2_0 0x20 /* Version 2.0 */
struct ioat_dma_descriptor {
uint32_t size;
@@ -47,6 +54,16 @@ struct ioat_dma_descriptor {
#define IOAT_DMA_DESCRIPTOR_CTL_CP_STS 0x00000008
#define IOAT_DMA_DESCRIPTOR_CTL_FRAME 0x00000010
#define IOAT_DMA_DESCRIPTOR_NUL 0x00000020
-#define IOAT_DMA_DESCRIPTOR_OPCODE 0xFF000000
+#define IOAT_DMA_DESCRIPTOR_CTL_SP_BRK 0x00000040
+#define IOAT_DMA_DESCRIPTOR_CTL_DP_BRK 0x00000080
+#define IOAT_DMA_DESCRIPTOR_CTL_BNDL 0x00000100
+#define IOAT_DMA_DESCRIPTOR_CTL_DCA 0x00000200
+#define IOAT_DMA_DESCRIPTOR_CTL_BUFHINT 0x00000400
+
+#define IOAT_DMA_DESCRIPTOR_CTL_OPCODE_CONTEXT 0xFF000000
+#define IOAT_DMA_DESCRIPTOR_CTL_OPCODE_DMA 0x00000000
+
+#define IOAT_DMA_DESCRIPTOR_CTL_CONTEXT_DCA 0x00000001
+#define IOAT_DMA_DESCRIPTOR_CTL_OPCODE_MASK 0xFF000000
#endif
diff --git a/drivers/dma/ioatdma_registers.h b/drivers/dma/ioatdma_registers.h
index a30c7349075..9832d7ebd93 100644
--- a/drivers/dma/ioatdma_registers.h
+++ b/drivers/dma/ioatdma_registers.h
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
+ * Copyright(c) 2004 - 2007 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@@ -21,6 +21,9 @@
#ifndef _IOAT_REGISTERS_H_
#define _IOAT_REGISTERS_H_
+#define IOAT_PCI_DMACTRL_OFFSET 0x48
+#define IOAT_PCI_DMACTRL_DMA_EN 0x00000001
+#define IOAT_PCI_DMACTRL_MSI_EN 0x00000002
/* MMIO Device Registers */
#define IOAT_CHANCNT_OFFSET 0x00 /* 8-bit */
@@ -39,25 +42,25 @@
#define IOAT_INTRCTRL_MASTER_INT_EN 0x01 /* Master Interrupt Enable */
#define IOAT_INTRCTRL_INT_STATUS 0x02 /* ATTNSTATUS -or- Channel Int */
#define IOAT_INTRCTRL_INT 0x04 /* INT_STATUS -and- MASTER_INT_EN */
+#define IOAT_INTRCTRL_MSIX_VECTOR_CONTROL 0x08 /* Enable all MSI-X vectors */
#define IOAT_ATTNSTATUS_OFFSET 0x04 /* Each bit is a channel */
#define IOAT_VER_OFFSET 0x08 /* 8-bit */
#define IOAT_VER_MAJOR_MASK 0xF0
#define IOAT_VER_MINOR_MASK 0x0F
-#define GET_IOAT_VER_MAJOR(x) ((x) & IOAT_VER_MAJOR_MASK)
+#define GET_IOAT_VER_MAJOR(x) (((x) & IOAT_VER_MAJOR_MASK) >> 4)
#define GET_IOAT_VER_MINOR(x) ((x) & IOAT_VER_MINOR_MASK)
#define IOAT_PERPORTOFFSET_OFFSET 0x0A /* 16-bit */
#define IOAT_INTRDELAY_OFFSET 0x0C /* 16-bit */
#define IOAT_INTRDELAY_INT_DELAY_MASK 0x3FFF /* Interrupt Delay Time */
-#define IOAT_INTRDELAY_COALESE_SUPPORT 0x8000 /* Interrupt Coalesing Supported */
+#define IOAT_INTRDELAY_COALESE_SUPPORT 0x8000 /* Interrupt Coalescing Supported */
#define IOAT_DEVICE_STATUS_OFFSET 0x0E /* 16-bit */
#define IOAT_DEVICE_STATUS_DEGRADED_MODE 0x0001
-
#define IOAT_CHANNEL_MMIO_SIZE 0x80 /* Each Channel MMIO space is this size */
/* DMA Channel Registers */
@@ -70,25 +73,101 @@
#define IOAT_CHANCTRL_ERR_COMPLETION_EN 0x0004
#define IOAT_CHANCTRL_INT_DISABLE 0x0001
-#define IOAT_DMA_COMP_OFFSET 0x02 /* 16-bit DMA channel compatability */
-#define IOAT_DMA_COMP_V1 0x0001 /* Compatability with DMA version 1 */
-
-#define IOAT_CHANSTS_OFFSET 0x04 /* 64-bit Channel Status Register */
-#define IOAT_CHANSTS_OFFSET_LOW 0x04
-#define IOAT_CHANSTS_OFFSET_HIGH 0x08
-#define IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR 0xFFFFFFFFFFFFFFC0UL
+#define IOAT_DMA_COMP_OFFSET 0x02 /* 16-bit DMA channel compatibility */
+#define IOAT_DMA_COMP_V1 0x0001 /* Compatibility with DMA version 1 */
+#define IOAT_DMA_COMP_V2 0x0002 /* Compatibility with DMA version 2 */
+
+
+#define IOAT1_CHANSTS_OFFSET 0x04 /* 64-bit Channel Status Register */
+#define IOAT2_CHANSTS_OFFSET 0x08 /* 64-bit Channel Status Register */
+#define IOAT_CHANSTS_OFFSET(ver) ((ver) < IOAT_VER_2_0 \
+ ? IOAT1_CHANSTS_OFFSET : IOAT2_CHANSTS_OFFSET)
+#define IOAT1_CHANSTS_OFFSET_LOW 0x04
+#define IOAT2_CHANSTS_OFFSET_LOW 0x08
+#define IOAT_CHANSTS_OFFSET_LOW(ver) ((ver) < IOAT_VER_2_0 \
+ ? IOAT1_CHANSTS_OFFSET_LOW : IOAT2_CHANSTS_OFFSET_LOW)
+#define IOAT1_CHANSTS_OFFSET_HIGH 0x08
+#define IOAT2_CHANSTS_OFFSET_HIGH 0x0C
+#define IOAT_CHANSTS_OFFSET_HIGH(ver) ((ver) < IOAT_VER_2_0 \
+ ? IOAT1_CHANSTS_OFFSET_HIGH : IOAT2_CHANSTS_OFFSET_HIGH)
+#define IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR ~0x3F
#define IOAT_CHANSTS_SOFT_ERR 0x0000000000000010
+#define IOAT_CHANSTS_UNAFFILIATED_ERR 0x0000000000000008
#define IOAT_CHANSTS_DMA_TRANSFER_STATUS 0x0000000000000007
#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_ACTIVE 0x0
#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_DONE 0x1
#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_SUSPENDED 0x2
#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_HALTED 0x3
-#define IOAT_CHAINADDR_OFFSET 0x0C /* 64-bit Descriptor Chain Address Register */
-#define IOAT_CHAINADDR_OFFSET_LOW 0x0C
-#define IOAT_CHAINADDR_OFFSET_HIGH 0x10
-#define IOAT_CHANCMD_OFFSET 0x14 /* 8-bit DMA Channel Command Register */
+
+#define IOAT_CHAN_DMACOUNT_OFFSET 0x06 /* 16-bit DMA Count register */
+
+#define IOAT_DCACTRL_OFFSET 0x30 /* 32 bit Direct Cache Access Control Register */
+#define IOAT_DCACTRL_CMPL_WRITE_ENABLE 0x10000
+#define IOAT_DCACTRL_TARGET_CPU_MASK 0xFFFF /* APIC ID */
+
+/* CB DCA Memory Space Registers */
+#define IOAT_DCAOFFSET_OFFSET 0x14
+/* CB_BAR + IOAT_DCAOFFSET value */
+#define IOAT_DCA_VER_OFFSET 0x00
+#define IOAT_DCA_VER_MAJOR_MASK 0xF0
+#define IOAT_DCA_VER_MINOR_MASK 0x0F
+
+#define IOAT_DCA_COMP_OFFSET 0x02
+#define IOAT_DCA_COMP_V1 0x1
+
+#define IOAT_FSB_CAPABILITY_OFFSET 0x04
+#define IOAT_FSB_CAPABILITY_PREFETCH 0x1
+
+#define IOAT_PCI_CAPABILITY_OFFSET 0x06
+#define IOAT_PCI_CAPABILITY_MEMWR 0x1
+
+#define IOAT_FSB_CAP_ENABLE_OFFSET 0x08
+#define IOAT_FSB_CAP_ENABLE_PREFETCH 0x1
+
+#define IOAT_PCI_CAP_ENABLE_OFFSET 0x0A
+#define IOAT_PCI_CAP_ENABLE_MEMWR 0x1
+
+#define IOAT_APICID_TAG_MAP_OFFSET 0x0C
+#define IOAT_APICID_TAG_MAP_TAG0 0x0000000F
+#define IOAT_APICID_TAG_MAP_TAG0_SHIFT 0
+#define IOAT_APICID_TAG_MAP_TAG1 0x000000F0
+#define IOAT_APICID_TAG_MAP_TAG1_SHIFT 4
+#define IOAT_APICID_TAG_MAP_TAG2 0x00000F00
+#define IOAT_APICID_TAG_MAP_TAG2_SHIFT 8
+#define IOAT_APICID_TAG_MAP_TAG3 0x0000F000
+#define IOAT_APICID_TAG_MAP_TAG3_SHIFT 12
+#define IOAT_APICID_TAG_MAP_TAG4 0x000F0000
+#define IOAT_APICID_TAG_MAP_TAG4_SHIFT 16
+#define IOAT_APICID_TAG_CB2_VALID 0x8080808080
+
+#define IOAT_DCA_GREQID_OFFSET 0x10
+#define IOAT_DCA_GREQID_SIZE 0x04
+#define IOAT_DCA_GREQID_MASK 0xFFFF
+#define IOAT_DCA_GREQID_IGNOREFUN 0x10000000
+#define IOAT_DCA_GREQID_VALID 0x20000000
+#define IOAT_DCA_GREQID_LASTID 0x80000000
+
+
+
+#define IOAT1_CHAINADDR_OFFSET 0x0C /* 64-bit Descriptor Chain Address Register */
+#define IOAT2_CHAINADDR_OFFSET 0x10 /* 64-bit Descriptor Chain Address Register */
+#define IOAT_CHAINADDR_OFFSET(ver) ((ver) < IOAT_VER_2_0 \
+ ? IOAT1_CHAINADDR_OFFSET : IOAT2_CHAINADDR_OFFSET)
+#define IOAT1_CHAINADDR_OFFSET_LOW 0x0C
+#define IOAT2_CHAINADDR_OFFSET_LOW 0x10
+#define IOAT_CHAINADDR_OFFSET_LOW(ver) ((ver) < IOAT_VER_2_0 \
+ ? IOAT1_CHAINADDR_OFFSET_LOW : IOAT2_CHAINADDR_OFFSET_LOW)
+#define IOAT1_CHAINADDR_OFFSET_HIGH 0x10
+#define IOAT2_CHAINADDR_OFFSET_HIGH 0x14
+#define IOAT_CHAINADDR_OFFSET_HIGH(ver) ((ver) < IOAT_VER_2_0 \
+ ? IOAT1_CHAINADDR_OFFSET_HIGH : IOAT2_CHAINADDR_OFFSET_HIGH)
+
+#define IOAT1_CHANCMD_OFFSET 0x14 /* 8-bit DMA Channel Command Register */
+#define IOAT2_CHANCMD_OFFSET 0x04 /* 8-bit DMA Channel Command Register */
+#define IOAT_CHANCMD_OFFSET(ver) ((ver) < IOAT_VER_2_0 \
+ ? IOAT1_CHANCMD_OFFSET : IOAT2_CHANCMD_OFFSET)
#define IOAT_CHANCMD_RESET 0x20
#define IOAT_CHANCMD_RESUME 0x10
#define IOAT_CHANCMD_ABORT 0x08
@@ -120,6 +199,7 @@
#define IOAT_CHANERR_COMPLETION_ADDR_ERR 0x1000
#define IOAT_CHANERR_INT_CONFIGURATION_ERR 0x2000
#define IOAT_CHANERR_SOFT_ERR 0x4000
+#define IOAT_CHANERR_UNAFFILIATED_ERR 0x8000
#define IOAT_CHANERR_MASK_OFFSET 0x2C /* 32-bit Channel Error Register */
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
index 5a1d426744d..e5c62b75f36 100644
--- a/drivers/dma/iop-adma.c
+++ b/drivers/dma/iop-adma.c
@@ -1446,21 +1446,20 @@ static struct platform_driver iop_adma_driver = {
static int __init iop_adma_init (void)
{
- /* it's currently unsafe to unload this module */
- /* if forced, worst case is that rmmod hangs */
- __unsafe(THIS_MODULE);
-
return platform_driver_register(&iop_adma_driver);
}
+/* it's currently unsafe to unload this module */
+#if 0
static void __exit iop_adma_exit (void)
{
platform_driver_unregister(&iop_adma_driver);
return;
}
+module_exit(iop_adma_exit);
+#endif
module_init(iop_adma_init);
-module_exit(iop_adma_exit);
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("IOP ADMA Engine Driver");
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index e80af67664c..2d23e304f5e 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -94,8 +94,6 @@ extern int edac_debug_level;
#endif /* !CONFIG_EDAC_DEBUG */
-#define BIT(x) (1 << (x))
-
#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \
PCI_DEVICE_ID_ ## vend ## _ ## dev
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 4a0576bd06f..3706b2bc098 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -743,7 +743,7 @@ static struct kobj_type ktype_mc_set_attribs = {
* /sys/devices/system/edac/mc
*/
static struct kset mc_kset = {
- .kobj = {.name = "mc", .ktype = &ktype_mc_set_attribs },
+ .kobj = {.ktype = &ktype_mc_set_attribs },
.ktype = &ktype_mci,
};
@@ -1010,6 +1010,7 @@ int edac_sysfs_setup_mc_kset(void)
}
/* Init the MC's kobject */
+ kobject_set_name(&mc_kset.kobj, "mc");
mc_kset.kobj.parent = &edac_class->kset.kobj;
/* register the mc_kset */
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 96f7e63e399..a1f24c42d5f 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -1462,7 +1462,7 @@ MODULE_DEVICE_TABLE(pci, i5000_pci_tbl);
*
*/
static struct pci_driver i5000_driver = {
- .name = __stringify(KBUILD_BASENAME),
+ .name = KBUILD_BASENAME,
.probe = i5000_init_one,
.remove = __devexit_p(i5000_remove_one),
.id_table = i5000_pci_tbl,
diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c
index e66cdd42a39..9007d067722 100644
--- a/drivers/edac/pasemi_edac.c
+++ b/drivers/edac/pasemi_edac.c
@@ -270,6 +270,7 @@ static void __devexit pasemi_edac_remove(struct pci_dev *pdev)
static const struct pci_device_id pasemi_edac_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa00a) },
+ { }
};
MODULE_DEVICE_TABLE(pci, pasemi_edac_pci_tbl);
diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
index d944647c82c..65dcf043265 100644
--- a/drivers/eisa/eisa-bus.c
+++ b/drivers/eisa/eisa-bus.c
@@ -35,9 +35,9 @@ static struct eisa_device_info __initdata eisa_table[] = {
#define EISA_MAX_FORCED_DEV 16
static int enable_dev[EISA_MAX_FORCED_DEV];
-static int enable_dev_count;
+static unsigned int enable_dev_count;
static int disable_dev[EISA_MAX_FORCED_DEV];
-static int disable_dev_count;
+static unsigned int disable_dev_count;
static int is_forced_dev (int *forced_tab,
int forced_count,
@@ -128,16 +128,11 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv)
return 0;
}
-static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int eisa_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct eisa_device *edev = to_eisa_device(dev);
- int i = 0;
- int length = 0;
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
- envp[i] = NULL;
+ add_uevent_var(env, "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
return 0;
}
diff --git a/drivers/fc4/Kconfig b/drivers/fc4/Kconfig
deleted file mode 100644
index 345dbe6f10d..00000000000
--- a/drivers/fc4/Kconfig
+++ /dev/null
@@ -1,81 +0,0 @@
-#
-# FC4 device configuration
-#
-
-menu "Fibre Channel support"
-
-config FC4
- tristate "Fibre Channel and FC4 SCSI support"
- ---help---
- Fibre Channel is a high speed serial protocol mainly used to
- connect large storage devices to the computer; it is compatible with
- and intended to replace SCSI.
-
- This is an experimental support for storage arrays connected to your
- computer using optical fibre cables and the "X3.269-199X Fibre
- Channel Protocol for SCSI" specification. If you want to use this,
- you need to say Y here and to "SCSI support" as well as to the
- drivers for the storage array itself and for the interface adapter
- such as SOC or SOC+. This subsystem could even serve for IP
- networking, with some code extensions.
-
- If unsure, say N.
-
-comment "FC4 drivers"
- depends on FC4
-
-config FC4_SOC
- tristate "Sun SOC/Sbus"
- depends on FC4!=n && SPARC
- help
- Serial Optical Channel is an interface card with one or two Fibre
- Optic ports, each of which can be connected to a disk array. Note
- that if you have older firmware in the card, you'll need the
- microcode from the Solaris driver to make it work.
-
- To compile this support as a module, choose M here: the module will
- be called soc.
-
-config FC4_SOCAL
- tristate "Sun SOC+ (aka SOCAL)"
- depends on FC4!=n && SPARC
- ---help---
- Serial Optical Channel Plus is an interface card with up to two
- Fibre Optic ports. This card supports FC Arbitrated Loop (usually
- A5000 or internal FC disks in E[3-6]000 machines through the
- Interface Board). You'll probably need the microcode from the
- Solaris driver to make it work.
-
- To compile this support as a module, choose M here: the module will
- be called socal.
-
-comment "FC4 targets"
- depends on FC4
-
-config SCSI_PLUTO
- tristate "SparcSTORAGE Array 100 and 200 series"
- depends on FC4!=n && SCSI
- help
- If you never bought a disk array made by Sun, go with N.
-
- To compile this support as a module, choose M here: the module will
- be called pluto.
-
-config SCSI_FCAL
- tristate "Sun Enterprise Network Array (A5000 and EX500)" if SPARC
- depends on FC4!=n && SCSI
- help
- This driver drives FC-AL disks connected through a Fibre Channel
- card using the drivers/fc4 layer (currently only SOCAL). The most
- common is either A5000 array or internal disks in E[3-6]000
- machines.
-
- To compile this support as a module, choose M here: the module will
- be called fcal.
-
-config SCSI_FCAL
- prompt "Generic FC-AL disk driver"
- depends on FC4!=n && SCSI && !SPARC
-
-endmenu
-
diff --git a/drivers/fc4/Makefile b/drivers/fc4/Makefile
deleted file mode 100644
index 0db3fbb553e..00000000000
--- a/drivers/fc4/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for the Linux Fibre Channel device drivers.
-#
-
-fc4-objs := fc.o fc_syms.o
-
-obj-$(CONFIG_FC4) += fc4.o
-obj-$(CONFIG_FC4_SOC) += soc.o
-obj-$(CONFIG_FC4_SOCAL) += socal.o
diff --git a/drivers/fc4/fc-al.h b/drivers/fc4/fc-al.h
deleted file mode 100644
index 62d3ca436d7..00000000000
--- a/drivers/fc4/fc-al.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* fc-al.h: Definitions for Fibre Channel Arbitrated Loop topology.
- *
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- *
- * Sources:
- * Fibre Channel Arbitrated Loop (FC-AL), ANSI, Rev. 4.5, 1995
- */
-
-#ifndef __FC_AL_H
-#define __FC_AL_H
-
-/* Loop initialization payloads */
-#define FC_AL_LISM 0x11010000 /* Select Master, 12B payload */
-#define FC_AL_LIFA 0x11020000 /* Fabric Assign AL_PA bitmap, 20B payload */
-#define FC_AL_LIPA 0x11030000 /* Previously Acquired AL_PA bitmap, 20B payload */
-#define FC_AL_LIHA 0x11040000 /* Hard Assigned AL_PA bitmap, 20B payload */
-#define FC_AL_LISA 0x11050000 /* Soft Assigned AL_PA bitmap, 20B payload */
-#define FC_AL_LIRP 0x11060000 /* Report AL_PA position map, 132B payload */
-#define FC_AL_LILP 0x11070000 /* Loop AL_PA position map, 132B payload */
-
-typedef struct {
- u32 magic;
- u8 len;
- u8 alpa[127];
-} fc_al_posmap;
-
-#endif /* !(__FC_H) */
diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c
deleted file mode 100644
index 22b62b3cd14..00000000000
--- a/drivers/fc4/fc.c
+++ /dev/null
@@ -1,1157 +0,0 @@
-/* fc.c: Generic Fibre Channel and FC4 SCSI driver.
- *
- * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
- * Copyright (C) 1997,1998 Jirka Hanika (geo@ff.cuni.cz)
- *
- * There are two kinds of Fibre Channel adapters used in Linux. Either
- * the adapter is "smart" and does all FC bookkeeping by itself and
- * just presents a standard SCSI interface to the operating system
- * (that's e.g. the case with Qlogic FC cards), or leaves most of the FC
- * bookkeeping to the OS (e.g. soc, socal). Drivers for the former adapters
- * will look like normal SCSI drivers (with the exception of max_id will be
- * usually 127), the latter on the other side allows SCSI, IP over FC and other
- * protocols. This driver tree is for the latter adapters.
- *
- * This file should support both Point-to-Point and Arbitrated Loop topologies.
- *
- * Sources:
- * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994
- * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995
- * Fibre Channel Arbitrated Loop (FC-AL), Rev. 4.5, 1995
- * Fibre Channel Private Loop SCSI Direct Attach (FC-PLDA), Rev. 2.1, 1997
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/semaphore.h>
-#include "fcp_impl.h"
-#include <scsi/scsi_host.h>
-
-/* #define FCDEBUG */
-
-#define fc_printk printk ("%s: ", fc->name); printk
-
-#ifdef FCDEBUG
-#define FCD(x) fc_printk x;
-#define FCND(x) printk ("FC: "); printk x;
-#else
-#define FCD(x)
-#define FCND(x)
-#endif
-
-#ifdef __sparc__
-#define dma_alloc_consistent(d,s,p) sbus_alloc_consistent(d,s,p)
-#define dma_free_consistent(d,s,v,h) sbus_free_consistent(d,s,v,h)
-#define dma_map_single(d,v,s,dir) sbus_map_single(d,v,s,dir)
-#define dma_unmap_single(d,h,s,dir) sbus_unmap_single(d,h,s,dir)
-#define dma_map_sg(d,s,n,dir) sbus_map_sg(d,s,n,dir)
-#define dma_unmap_sg(d,s,n,dir) sbus_unmap_sg(d,s,n,dir)
-#else
-#define dma_alloc_consistent(d,s,p) pci_alloc_consistent(d,s,p)
-#define dma_free_consistent(d,s,v,h) pci_free_consistent(d,s,v,h)
-#define dma_map_single(d,v,s,dir) pci_map_single(d,v,s,dir)
-#define dma_unmap_single(d,h,s,dir) pci_unmap_single(d,h,s,dir)
-#define dma_map_sg(d,s,n,dir) pci_map_sg(d,s,n,dir)
-#define dma_unmap_sg(d,s,n,dir) pci_unmap_sg(d,s,n,dir)
-#endif
-
-#define FCP_CMND(SCpnt) ((fcp_cmnd *)&(SCpnt->SCp))
-#define FC_SCMND(SCpnt) ((fc_channel *)(SCpnt->device->host->hostdata[0]))
-#define SC_FCMND(fcmnd) ((struct scsi_cmnd *)((long)fcmnd - (long)&(((struct scsi_cmnd *)0)->SCp)))
-
-static int fcp_scsi_queue_it(fc_channel *, struct scsi_cmnd *, fcp_cmnd *, int);
-void fcp_queue_empty(fc_channel *);
-
-static void fcp_scsi_insert_queue (fc_channel *fc, fcp_cmnd *fcmd)
-{
- if (!fc->scsi_que) {
- fc->scsi_que = fcmd;
- fcmd->next = fcmd;
- fcmd->prev = fcmd;
- } else {
- fc->scsi_que->prev->next = fcmd;
- fcmd->prev = fc->scsi_que->prev;
- fc->scsi_que->prev = fcmd;
- fcmd->next = fc->scsi_que;
- }
-}
-
-static void fcp_scsi_remove_queue (fc_channel *fc, fcp_cmnd *fcmd)
-{
- if (fcmd == fcmd->next) {
- fc->scsi_que = NULL;
- return;
- }
- if (fcmd == fc->scsi_que)
- fc->scsi_que = fcmd->next;
- fcmd->prev->next = fcmd->next;
- fcmd->next->prev = fcmd->prev;
-}
-
-fc_channel *fc_channels = NULL;
-
-#define LSMAGIC 620829043
-typedef struct {
- /* Must be first */
- struct semaphore sem;
- int magic;
- int count;
- logi *logi;
- fcp_cmnd *fcmds;
- atomic_t todo;
- struct timer_list timer;
- unsigned char grace[0];
-} ls;
-
-#define LSOMAGIC 654907799
-typedef struct {
- /* Must be first */
- struct semaphore sem;
- int magic;
- int count;
- fcp_cmnd *fcmds;
- atomic_t todo;
- struct timer_list timer;
-} lso;
-
-#define LSEMAGIC 84482456
-typedef struct {
- /* Must be first */
- struct semaphore sem;
- int magic;
- int status;
- struct timer_list timer;
-} lse;
-
-static void fcp_login_timeout(unsigned long data)
-{
- ls *l = (ls *)data;
- FCND(("Login timeout\n"))
- up(&l->sem);
-}
-
-static void fcp_login_done(fc_channel *fc, int i, int status)
-{
- fcp_cmnd *fcmd;
- logi *plogi;
- fc_hdr *fch;
- ls *l = (ls *)fc->ls;
-
- FCD(("Login done %d %d\n", i, status))
- if (i < l->count) {
- if (fc->state == FC_STATE_FPORT_OK) {
- FCD(("Additional FPORT_OK received with status %d\n", status))
- return;
- }
- switch (status) {
- case FC_STATUS_OK: /* Oh, we found a fabric */
- case FC_STATUS_P_RJT: /* Oh, we haven't found any */
- fc->state = FC_STATE_FPORT_OK;
- fcmd = l->fcmds + i;
- plogi = l->logi + 3 * i;
- dma_unmap_single (fc->dev, fcmd->cmd, 3 * sizeof(logi),
- DMA_BIDIRECTIONAL);
- plogi->code = LS_PLOGI;
- memcpy (&plogi->nport_wwn, &fc->wwn_nport, sizeof(fc_wwn));
- memcpy (&plogi->node_wwn, &fc->wwn_node, sizeof(fc_wwn));
- memcpy (&plogi->common, fc->common_svc, sizeof(common_svc_parm));
- memcpy (&plogi->class1, fc->class_svcs, 3*sizeof(svc_parm));
- fch = &fcmd->fch;
- fcmd->token += l->count;
- FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, fc->did);
- FILL_FCHDR_SID(fch, fc->sid);
-#ifdef FCDEBUG
- {
- int i;
- unsigned *x = (unsigned *)plogi;
- printk ("logi: ");
- for (i = 0; i < 21; i++)
- printk ("%08x ", x[i]);
- printk ("\n");
- }
-#endif
- fcmd->cmd = dma_map_single (fc->dev, plogi, 3 * sizeof(logi),
- DMA_BIDIRECTIONAL);
- fcmd->rsp = fcmd->cmd + 2 * sizeof(logi);
- if (fc->hw_enque (fc, fcmd))
- printk ("FC: Cannot enque PLOGI packet on %s\n", fc->name);
- break;
- case FC_STATUS_ERR_OFFLINE:
- fc->state = FC_STATE_MAYBEOFFLINE;
- FCD (("FC is offline %d\n", l->grace[i]))
- break;
- default:
- printk ("FLOGI failed for %s with status %d\n", fc->name, status);
- /* Do some sort of error recovery here */
- break;
- }
- } else {
- i -= l->count;
- if (fc->state != FC_STATE_FPORT_OK) {
- FCD(("Unexpected N-PORT rsp received"))
- return;
- }
- switch (status) {
- case FC_STATUS_OK:
- plogi = l->logi + 3 * i;
- dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi),
- DMA_BIDIRECTIONAL);
- if (!fc->wwn_dest.lo && !fc->wwn_dest.hi) {
- memcpy (&fc->wwn_dest, &plogi[1].node_wwn, sizeof(fc_wwn));
- FCD(("Dest WWN %08x%08x\n", *(u32 *)&fc->wwn_dest, fc->wwn_dest.lo))
- } else if (fc->wwn_dest.lo != plogi[1].node_wwn.lo ||
- fc->wwn_dest.hi != plogi[1].node_wwn.hi) {
- printk ("%s: mismatch in wwns. Got %08x%08x, expected %08x%08x\n",
- fc->name,
- *(u32 *)&plogi[1].node_wwn, plogi[1].node_wwn.lo,
- *(u32 *)&fc->wwn_dest, fc->wwn_dest.lo);
- }
- fc->state = FC_STATE_ONLINE;
- printk ("%s: ONLINE\n", fc->name);
- if (atomic_dec_and_test (&l->todo))
- up(&l->sem);
- break;
- case FC_STATUS_ERR_OFFLINE:
- fc->state = FC_STATE_OFFLINE;
- dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi),
- DMA_BIDIRECTIONAL);
- printk ("%s: FC is offline\n", fc->name);
- if (atomic_dec_and_test (&l->todo))
- up(&l->sem);
- break;
- default:
- printk ("PLOGI failed for %s with status %d\n", fc->name, status);
- /* Do some sort of error recovery here */
- break;
- }
- }
-}
-
-static void fcp_report_map_done(fc_channel *fc, int i, int status)
-{
- fcp_cmnd *fcmd;
- fc_hdr *fch;
- unsigned char j;
- ls *l = (ls *)fc->ls;
- fc_al_posmap *p;
-
- FCD(("Report map done %d %d\n", i, status))
- switch (status) {
- case FC_STATUS_OK: /* Ok, let's have a fun on a loop */
- dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi),
- DMA_BIDIRECTIONAL);
- p = (fc_al_posmap *)(l->logi + 3 * i);
-#ifdef FCDEBUG
- {
- u32 *u = (u32 *)p;
- FCD(("%08x\n", u[0]))
- u ++;
- FCD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n", u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7]))
- }
-#endif
- if ((p->magic & 0xffff0000) != FC_AL_LILP || !p->len) {
- printk ("FC: Bad magic from REPORT_AL_MAP on %s - %08x\n", fc->name, p->magic);
- fc->state = FC_STATE_OFFLINE;
- } else {
- fc->posmap = kzalloc(sizeof(fcp_posmap)+p->len, GFP_KERNEL);
- if (!fc->posmap) {
- printk("FC: Not enough memory, offlining channel\n");
- fc->state = FC_STATE_OFFLINE;
- } else {
- int k;
- /* FIXME: This is where SOCAL transfers our AL-PA.
- Keep it here till we found out what other cards do... */
- fc->sid = (p->magic & 0xff);
- for (i = 0; i < p->len; i++)
- if (p->alpa[i] == fc->sid)
- break;
- k = p->len;
- if (i == p->len)
- i = 0;
- else {
- p->len--;
- i++;
- }
- fc->posmap->len = p->len;
- for (j = 0; j < p->len; j++) {
- if (i == k) i = 0;
- fc->posmap->list[j] = p->alpa[i++];
- }
- fc->state = FC_STATE_ONLINE;
- }
- }
- printk ("%s: ONLINE\n", fc->name);
- if (atomic_dec_and_test (&l->todo))
- up(&l->sem);
- break;
- case FC_STATUS_POINTTOPOINT: /* We're Point-to-Point, no AL... */
- FCD(("SID %d DID %d\n", fc->sid, fc->did))
- fcmd = l->fcmds + i;
- dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi),
- DMA_BIDIRECTIONAL);
- fch = &fcmd->fch;
- memset(l->logi + 3 * i, 0, 3 * sizeof(logi));
- FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT);
- FILL_FCHDR_SID(fch, 0);
- FILL_FCHDR_TYPE_FCTL(fch, TYPE_EXTENDED_LS, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE);
- FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0);
- FILL_FCHDR_OXRX(fch, 0xffff, 0xffff);
- fch->param = 0;
- l->logi [3 * i].code = LS_FLOGI;
- fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi),
- DMA_BIDIRECTIONAL);
- fcmd->rsp = fcmd->cmd + sizeof(logi);
- fcmd->cmdlen = sizeof(logi);
- fcmd->rsplen = sizeof(logi);
- fcmd->data = (dma_addr_t)NULL;
- fcmd->class = FC_CLASS_SIMPLE;
- fcmd->proto = TYPE_EXTENDED_LS;
- if (fc->hw_enque (fc, fcmd))
- printk ("FC: Cannot enque FLOGI packet on %s\n", fc->name);
- break;
- case FC_STATUS_ERR_OFFLINE:
- fc->state = FC_STATE_MAYBEOFFLINE;
- FCD (("FC is offline %d\n", l->grace[i]))
- break;
- default:
- printk ("FLOGI failed for %s with status %d\n", fc->name, status);
- /* Do some sort of error recovery here */
- break;
- }
-}
-
-void fcp_register(fc_channel *fc, u8 type, int unregister)
-{
- int size, i;
- int slots = (fc->can_queue * 3) >> 1;
-
- FCND(("Going to %sregister\n", unregister ? "un" : ""))
-
- if (type == TYPE_SCSI_FCP) {
- if (!unregister) {
- fc->scsi_cmd_pool = (fcp_cmd *)
- dma_alloc_consistent (fc->dev,
- slots * (sizeof (fcp_cmd) + fc->rsp_size),
- &fc->dma_scsi_cmd);
- fc->scsi_rsp_pool = (char *)(fc->scsi_cmd_pool + slots);
- fc->dma_scsi_rsp = fc->dma_scsi_cmd + slots * sizeof (fcp_cmd);
- fc->scsi_bitmap_end = (slots + 63) & ~63;
- size = fc->scsi_bitmap_end / 8;
- fc->scsi_bitmap = kzalloc (size, GFP_KERNEL);
- set_bit (0, fc->scsi_bitmap);
- for (i = fc->can_queue; i < fc->scsi_bitmap_end; i++)
- set_bit (i, fc->scsi_bitmap);
- fc->scsi_free = fc->can_queue;
- fc->cmd_slots = kzalloc(slots * sizeof(fcp_cmnd*), GFP_KERNEL);
- fc->abort_count = 0;
- } else {
- fc->scsi_name[0] = 0;
- kfree (fc->scsi_bitmap);
- kfree (fc->cmd_slots);
- FCND(("Unregistering\n"));
-#if 0
- if (fc->rst_pkt) {
- if (fc->rst_pkt->eh_state == SCSI_STATE_UNUSED)
- kfree(fc->rst_pkt);
- else {
- /* Can't happen. Some memory would be lost. */
- printk("FC: Reset in progress. Now?!");
- }
- }
-#endif
- FCND(("Unregistered\n"));
- }
- } else
- printk ("FC: %segistering unknown type %02x\n", unregister ? "Unr" : "R", type);
-}
-
-static void fcp_scsi_done(struct scsi_cmnd *SCpnt);
-
-static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hdr *fch)
-{
- fcp_cmnd *fcmd;
- fcp_rsp *rsp;
- int host_status;
- struct scsi_cmnd *SCpnt;
- int sense_len;
- int rsp_status;
-
- fcmd = fc->cmd_slots[token];
- if (!fcmd) return;
- rsp = (fcp_rsp *) (fc->scsi_rsp_pool + fc->rsp_size * token);
- SCpnt = SC_FCMND(fcmd);
-
- if (SCpnt->done != fcp_scsi_done)
- return;
-
- rsp_status = rsp->fcp_status;
- FCD(("rsp_status %08x status %08x\n", rsp_status, status))
- switch (status) {
- case FC_STATUS_OK:
- host_status=DID_OK;
-
- if (rsp_status & FCP_STATUS_RESID) {
-#ifdef FCDEBUG
- FCD(("Resid %d\n", rsp->fcp_resid))
- {
- fcp_cmd *cmd = fc->scsi_cmd_pool + token;
- int i;
-
- printk ("Command ");
- for (i = 0; i < sizeof(fcp_cmd); i+=4)
- printk ("%08x ", *(u32 *)(((char *)cmd)+i));
- printk ("\nResponse ");
- for (i = 0; i < fc->rsp_size; i+=4)
- printk ("%08x ", *(u32 *)(((char *)rsp)+i));
- printk ("\n");
- }
-#endif
- }
-
- if (rsp_status & FCP_STATUS_SENSE_LEN) {
- sense_len = rsp->fcp_sense_len;
- if (sense_len > sizeof(SCpnt->sense_buffer)) sense_len = sizeof(SCpnt->sense_buffer);
- memcpy(SCpnt->sense_buffer, ((char *)(rsp+1)), sense_len);
- }
-
- if (fcmd->data) {
- if (SCpnt->use_sg)
- dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->request_buffer,
- SCpnt->use_sg,
- SCpnt->sc_data_direction);
- else
- dma_unmap_single(fc->dev, fcmd->data, SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- }
- break;
- default:
- host_status=DID_ERROR; /* FIXME */
- FCD(("Wrong FC status %d for token %d\n", status, token))
- break;
- }
-
- if (status_byte(rsp_status) == QUEUE_FULL) {
- printk ("%s: (%d,%d) Received rsp_status 0x%x\n", fc->name, SCpnt->device->channel, SCpnt->device->id, rsp_status);
- }
-
- SCpnt->result = (host_status << 16) | (rsp_status & 0xff);
-#ifdef FCDEBUG
- if (host_status || SCpnt->result || rsp_status) printk("FC: host_status %d, packet status %d\n",
- host_status, SCpnt->result);
-#endif
- SCpnt->done = fcmd->done;
- fcmd->done=NULL;
- clear_bit(token, fc->scsi_bitmap);
- fc->scsi_free++;
- FCD(("Calling scsi_done with %08x\n", SCpnt->result))
- SCpnt->scsi_done(SCpnt);
-}
-
-void fcp_receive_solicited(fc_channel *fc, int proto, int token, int status, fc_hdr *fch)
-{
- int magic;
- FCD(("receive_solicited %d %d %d\n", proto, token, status))
- switch (proto) {
- case TYPE_SCSI_FCP:
- fcp_scsi_receive(fc, token, status, fch); break;
- case TYPE_EXTENDED_LS:
- case PROTO_REPORT_AL_MAP:
- magic = 0;
- if (fc->ls)
- magic = ((ls *)(fc->ls))->magic;
- if (magic == LSMAGIC) {
- ls *l = (ls *)fc->ls;
- int i = (token >= l->count) ? token - l->count : token;
-
- /* Let's be sure */
- if ((unsigned)i < l->count && l->fcmds[i].fc == fc) {
- if (proto == TYPE_EXTENDED_LS)
- fcp_login_done(fc, token, status);
- else
- fcp_report_map_done(fc, token, status);
- break;
- }
- }
- FCD(("fc %p fc->ls %p fc->cmd_slots %p\n", fc, fc->ls, fc->cmd_slots))
- if (proto == TYPE_EXTENDED_LS && !fc->ls && fc->cmd_slots) {
- fcp_cmnd *fcmd;
-
- fcmd = fc->cmd_slots[token];
- if (fcmd && fcmd->ls && ((ls *)(fcmd->ls))->magic == LSEMAGIC) {
- lse *l = (lse *)fcmd->ls;
-
- l->status = status;
- up (&l->sem);
- }
- }
- break;
- case PROTO_OFFLINE:
- if (fc->ls && ((lso *)(fc->ls))->magic == LSOMAGIC) {
- lso *l = (lso *)fc->ls;
-
- if ((unsigned)token < l->count && l->fcmds[token].fc == fc) {
- /* Wow, OFFLINE response arrived :) */
- FCD(("OFFLINE Response arrived\n"))
- fc->state = FC_STATE_OFFLINE;
- if (atomic_dec_and_test (&l->todo))
- up(&l->sem);
- }
- }
- break;
-
- default:
- break;
- }
-}
-
-void fcp_state_change(fc_channel *fc, int state)
-{
- FCD(("state_change %d %d\n", state, fc->state))
- if (state == FC_STATE_ONLINE && fc->state == FC_STATE_MAYBEOFFLINE)
- fc->state = FC_STATE_UNINITED;
- else if (state == FC_STATE_ONLINE)
- printk (KERN_WARNING "%s: state change to ONLINE\n", fc->name);
- else
- printk (KERN_ERR "%s: state change to OFFLINE\n", fc->name);
-}
-
-int fcp_initialize(fc_channel *fcchain, int count)
-{
- fc_channel *fc;
- fcp_cmnd *fcmd;
- int i, retry, ret;
- ls *l;
-
- FCND(("fcp_inititialize %08lx\n", (long)fcp_init))
- FCND(("fc_channels %08lx\n", (long)fc_channels))
- FCND((" SID %d DID %d\n", fcchain->sid, fcchain->did))
- l = kzalloc(sizeof (ls) + count, GFP_KERNEL);
- if (!l) {
- printk ("FC: Cannot allocate memory for initialization\n");
- return -ENOMEM;
- }
- l->magic = LSMAGIC;
- l->count = count;
- FCND(("FCP Init for %d channels\n", count))
- init_MUTEX_LOCKED(&l->sem);
- init_timer(&l->timer);
- l->timer.function = fcp_login_timeout;
- l->timer.data = (unsigned long)l;
- atomic_set (&l->todo, count);
- l->logi = kzalloc (count * 3 * sizeof(logi), GFP_KERNEL);
- l->fcmds = kzalloc (count * sizeof(fcp_cmnd), GFP_KERNEL);
- if (!l->logi || !l->fcmds) {
- kfree (l->logi);
- kfree (l->fcmds);
- kfree (l);
- printk ("FC: Cannot allocate DMA memory for initialization\n");
- return -ENOMEM;
- }
- for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) {
- fc->state = FC_STATE_UNINITED;
- fc->rst_pkt = NULL; /* kmalloc when first used */
- }
- /* First try if we are in a AL topology */
- FCND(("Initializing REPORT_MAP packets\n"))
- for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) {
- fcmd = l->fcmds + i;
- fc->login = fcmd;
- fc->ls = (void *)l;
- /* Assumes sizeof(fc_al_posmap) < 3 * sizeof(logi), which is true */
- fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi),
- DMA_BIDIRECTIONAL);
- fcmd->proto = PROTO_REPORT_AL_MAP;
- fcmd->token = i;
- fcmd->fc = fc;
- }
- for (retry = 0; retry < 8; retry++) {
- int nqueued = 0;
- FCND(("Sending REPORT_MAP/FLOGI/PLOGI packets\n"))
- for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) {
- if (fc->state == FC_STATE_ONLINE || fc->state == FC_STATE_OFFLINE)
- continue;
- disable_irq(fc->irq);
- if (fc->state == FC_STATE_MAYBEOFFLINE) {
- if (!l->grace[i]) {
- l->grace[i]++;
- FCD(("Grace\n"))
- } else {
- fc->state = FC_STATE_OFFLINE;
- enable_irq(fc->irq);
- dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), DMA_BIDIRECTIONAL);
- if (atomic_dec_and_test (&l->todo))
- goto all_done;
- }
- }
- ret = fc->hw_enque (fc, fc->login);
- enable_irq(fc->irq);
- if (!ret) {
- nqueued++;
- continue;
- }
- if (ret == -ENOSYS && fc->login->proto == PROTO_REPORT_AL_MAP) {
- /* Oh yes, this card handles Point-to-Point only, so let's try that. */
- fc_hdr *fch;
-
- FCD(("SID %d DID %d\n", fc->sid, fc->did))
- fcmd = l->fcmds + i;
- dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi), DMA_BIDIRECTIONAL);
- fch = &fcmd->fch;
- FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT);
- FILL_FCHDR_SID(fch, 0);
- FILL_FCHDR_TYPE_FCTL(fch, TYPE_EXTENDED_LS, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE);
- FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0);
- FILL_FCHDR_OXRX(fch, 0xffff, 0xffff);
- fch->param = 0;
- l->logi [3 * i].code = LS_FLOGI;
- fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi), DMA_BIDIRECTIONAL);
- fcmd->rsp = fcmd->cmd + sizeof(logi);
- fcmd->cmdlen = sizeof(logi);
- fcmd->rsplen = sizeof(logi);
- fcmd->data = (dma_addr_t)NULL;
- fcmd->class = FC_CLASS_SIMPLE;
- fcmd->proto = TYPE_EXTENDED_LS;
- } else
- printk ("FC: Cannot enque FLOGI/REPORT_MAP packet on %s\n", fc->name);
- }
-
- if (nqueued) {
- l->timer.expires = jiffies + 5 * HZ;
- add_timer(&l->timer);
-
- down(&l->sem);
- if (!atomic_read(&l->todo)) {
- FCND(("All channels answered in time\n"))
- break; /* All fc channels have answered us */
- }
- }
- }
-all_done:
- for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) {
- fc->ls = NULL;
- switch (fc->state) {
- case FC_STATE_ONLINE: break;
- case FC_STATE_OFFLINE: break;
- default: dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), DMA_BIDIRECTIONAL);
- break;
- }
- }
- del_timer(&l->timer);
- kfree (l->logi);
- kfree (l->fcmds);
- kfree (l);
- return 0;
-}
-
-int fcp_forceoffline(fc_channel *fcchain, int count)
-{
- fc_channel *fc;
- fcp_cmnd *fcmd;
- int i, ret;
- lso l;
-
- memset (&l, 0, sizeof(lso));
- l.count = count;
- l.magic = LSOMAGIC;
- FCND(("FCP Force Offline for %d channels\n", count))
- init_MUTEX_LOCKED(&l.sem);
- init_timer(&l.timer);
- l.timer.function = fcp_login_timeout;
- l.timer.data = (unsigned long)&l;
- atomic_set (&l.todo, count);
- l.fcmds = kzalloc (count * sizeof(fcp_cmnd), GFP_KERNEL);
- if (!l.fcmds) {
- printk ("FC: Cannot allocate memory for forcing offline\n");
- return -ENOMEM;
- }
- FCND(("Initializing OFFLINE packets\n"))
- for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++) {
- fc->state = FC_STATE_UNINITED;
- fcmd = l.fcmds + i;
- fc->login = fcmd;
- fc->ls = (void *)&l;
- fcmd->did = fc->did;
- fcmd->class = FC_CLASS_OFFLINE;
- fcmd->proto = PROTO_OFFLINE;
- fcmd->token = i;
- fcmd->fc = fc;
- disable_irq(fc->irq);
- ret = fc->hw_enque (fc, fc->login);
- enable_irq(fc->irq);
- if (ret) printk ("FC: Cannot enque OFFLINE packet on %s\n", fc->name);
- }
-
- l.timer.expires = jiffies + 5 * HZ;
- add_timer(&l.timer);
- down(&l.sem);
- del_timer(&l.timer);
-
- for (fc = fcchain, i = 0; fc && i < count; fc = fc->next, i++)
- fc->ls = NULL;
- kfree (l.fcmds);
- return 0;
-}
-
-int fcp_init(fc_channel *fcchain)
-{
- fc_channel *fc;
- int count=0;
- int ret;
-
- for (fc = fcchain; fc; fc = fc->next) {
- fc->fcp_register = fcp_register;
- count++;
- }
-
- ret = fcp_initialize (fcchain, count);
- if (ret)
- return ret;
-
- if (!fc_channels)
- fc_channels = fcchain;
- else {
- for (fc = fc_channels; fc->next; fc = fc->next);
- fc->next = fcchain;
- }
- return ret;
-}
-
-void fcp_release(fc_channel *fcchain, int count) /* count must > 0 */
-{
- fc_channel *fc;
- fc_channel *fcx;
-
- for (fc = fcchain; --count && fc->next; fc = fc->next);
- if (count) {
- printk("FC: nothing to release\n");
- return;
- }
-
- if (fc_channels == fcchain)
- fc_channels = fc->next;
- else {
- for (fcx = fc_channels; fcx->next != fcchain; fcx = fcx->next);
- fcx->next = fc->next;
- }
- fc->next = NULL;
-
- /*
- * We've just grabbed fcchain out of the fc_channel list
- * and zero-terminated it, while destroying the count.
- *
- * Freeing the fc's is the low level driver's responsibility.
- */
-}
-
-
-static void fcp_scsi_done(struct scsi_cmnd *SCpnt)
-{
- if (FCP_CMND(SCpnt)->done)
- FCP_CMND(SCpnt)->done(SCpnt);
-}
-
-static int fcp_scsi_queue_it(fc_channel *fc, struct scsi_cmnd *SCpnt,
- fcp_cmnd *fcmd, int prepare)
-{
- long i;
- fcp_cmd *cmd;
- u32 fcp_cntl;
- if (prepare) {
- i = find_first_zero_bit (fc->scsi_bitmap, fc->scsi_bitmap_end);
- set_bit (i, fc->scsi_bitmap);
- fcmd->token = i;
- cmd = fc->scsi_cmd_pool + i;
-
- if (fc->encode_addr (SCpnt, cmd->fcp_addr, fc, fcmd)) {
- /* Invalid channel/id/lun and couldn't map it into fcp_addr */
- clear_bit (i, fc->scsi_bitmap);
- SCpnt->result = (DID_BAD_TARGET << 16);
- SCpnt->scsi_done(SCpnt);
- return 0;
- }
- fc->scsi_free--;
- fc->cmd_slots[fcmd->token] = fcmd;
-
- if (SCpnt->device->tagged_supported) {
- if (jiffies - fc->ages[SCpnt->device->channel * fc->targets + SCpnt->device->id] > (5 * 60 * HZ)) {
- fc->ages[SCpnt->device->channel * fc->targets + SCpnt->device->id] = jiffies;
- fcp_cntl = FCP_CNTL_QTYPE_ORDERED;
- } else
- fcp_cntl = FCP_CNTL_QTYPE_SIMPLE;
- } else
- fcp_cntl = FCP_CNTL_QTYPE_UNTAGGED;
- if (!SCpnt->request_bufflen && !SCpnt->use_sg) {
- cmd->fcp_cntl = fcp_cntl;
- fcmd->data = (dma_addr_t)NULL;
- } else {
- switch (SCpnt->cmnd[0]) {
- case WRITE_6:
- case WRITE_10:
- case WRITE_12:
- cmd->fcp_cntl = (FCP_CNTL_WRITE | fcp_cntl); break;
- default:
- cmd->fcp_cntl = (FCP_CNTL_READ | fcp_cntl); break;
- }
- if (!SCpnt->use_sg) {
- cmd->fcp_data_len = SCpnt->request_bufflen;
- fcmd->data = dma_map_single (fc->dev, (char *)SCpnt->request_buffer,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- } else {
- struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer;
- int nents;
-
- FCD(("XXX: Use_sg %d %d\n", SCpnt->use_sg, sg->length))
- nents = dma_map_sg (fc->dev, sg, SCpnt->use_sg,
- SCpnt->sc_data_direction);
- if (nents > 1) printk ("%s: SG for nents %d (use_sg %d) not handled yet\n", fc->name, nents, SCpnt->use_sg);
- fcmd->data = sg_dma_address(sg);
- cmd->fcp_data_len = sg_dma_len(sg);
- }
- }
- memcpy (cmd->fcp_cdb, SCpnt->cmnd, SCpnt->cmd_len);
- memset (cmd->fcp_cdb+SCpnt->cmd_len, 0, sizeof(cmd->fcp_cdb)-SCpnt->cmd_len);
- FCD(("XXX: %04x.%04x.%04x.%04x - %08x%08x%08x\n", cmd->fcp_addr[0], cmd->fcp_addr[1], cmd->fcp_addr[2], cmd->fcp_addr[3], *(u32 *)SCpnt->cmnd, *(u32 *)(SCpnt->cmnd+4), *(u32 *)(SCpnt->cmnd+8)))
- }
- FCD(("Trying to enque %p\n", fcmd))
- if (!fc->scsi_que) {
- if (!fc->hw_enque (fc, fcmd)) {
- FCD(("hw_enque succeeded for %p\n", fcmd))
- return 0;
- }
- }
- FCD(("Putting into que1 %p\n", fcmd))
- fcp_scsi_insert_queue (fc, fcmd);
- return 0;
-}
-
-int fcp_scsi_queuecommand(struct scsi_cmnd *SCpnt,
- void (* done)(struct scsi_cmnd *))
-{
- fcp_cmnd *fcmd = FCP_CMND(SCpnt);
- fc_channel *fc = FC_SCMND(SCpnt);
-
- FCD(("Entering SCSI queuecommand %p\n", fcmd))
- if (SCpnt->done != fcp_scsi_done) {
- fcmd->done = SCpnt->done;
- SCpnt->done = fcp_scsi_done;
- SCpnt->scsi_done = done;
- fcmd->proto = TYPE_SCSI_FCP;
- if (!fc->scsi_free) {
- FCD(("FC: !scsi_free, putting cmd on ML queue\n"))
-#if (FCP_SCSI_USE_NEW_EH_CODE == 0)
- printk("fcp_scsi_queue_command: queue full, losing cmd, bad\n");
-#endif
- return 1;
- }
- return fcp_scsi_queue_it(fc, SCpnt, fcmd, 1);
- }
- return fcp_scsi_queue_it(fc, SCpnt, fcmd, 0);
-}
-
-void fcp_queue_empty(fc_channel *fc)
-{
- fcp_cmnd *fcmd;
-
- FCD(("Queue empty\n"))
- while ((fcmd = fc->scsi_que)) {
- /* The hw told us we can try again queue some packet */
- if (fc->hw_enque (fc, fcmd))
- break;
- fcp_scsi_remove_queue (fc, fcmd);
- }
-}
-
-int fcp_scsi_abort(struct scsi_cmnd *SCpnt)
-{
- /* Internal bookkeeping only. Lose 1 cmd_slots slot. */
- fcp_cmnd *fcmd = FCP_CMND(SCpnt);
- fc_channel *fc = FC_SCMND(SCpnt);
-
- /*
- * We react to abort requests by simply forgetting
- * about the command and pretending everything's sweet.
- * This may or may not be silly. We can't, however,
- * immediately reuse the command's cmd_slots slot,
- * as its result may arrive later and we cannot
- * check whether it is the aborted one, can't we?
- *
- * Therefore, after the first few aborts are done,
- * we tell the scsi error handler to do something clever.
- * It will eventually call host reset, refreshing
- * cmd_slots for us.
- *
- * There is a theoretical chance that we sometimes allow
- * more than can_queue packets to the jungle this way,
- * but the worst outcome possible is a series of
- * more aborts and eventually the dev_reset catharsis.
- */
-
- if (++fc->abort_count < (fc->can_queue >> 1)) {
- SCpnt->result = DID_ABORT;
- fcmd->done(SCpnt);
- printk("FC: soft abort\n");
- return SUCCESS;
- } else {
- printk("FC: hard abort refused\n");
- return FAILED;
- }
-}
-
-#if 0
-void fcp_scsi_reset_done(struct scsi_cmnd *SCpnt)
-{
- fc_channel *fc = FC_SCMND(SCpnt);
-
- fc->rst_pkt->eh_state = SCSI_STATE_FINISHED;
- up(fc->rst_pkt->device->host->eh_action);
-}
-#endif
-
-#define FCP_RESET_TIMEOUT (2*HZ)
-
-int fcp_scsi_dev_reset(struct scsi_cmnd *SCpnt)
-{
-#if 0 /* broken junk, but if davem wants to compile this driver, let him.. */
- unsigned long flags;
- fcp_cmd *cmd;
- fcp_cmnd *fcmd;
- fc_channel *fc = FC_SCMND(SCpnt);
- DECLARE_MUTEX_LOCKED(sem);
-
- if (!fc->rst_pkt) {
- fc->rst_pkt = kmalloc(sizeof(SCpnt), GFP_KERNEL);
- if (!fc->rst_pkt) return FAILED;
-
- fcmd = FCP_CMND(fc->rst_pkt);
-
-
- fcmd->token = 0;
- cmd = fc->scsi_cmd_pool + 0;
- FCD(("Preparing rst packet\n"))
- fc->encode_addr (SCpnt, cmd->fcp_addr, fc, fcmd);
- fc->rst_pkt->device = SCpnt->device;
- fc->rst_pkt->cmd_len = 0;
-
- fc->cmd_slots[0] = fcmd;
-
- cmd->fcp_cntl = FCP_CNTL_QTYPE_ORDERED | FCP_CNTL_RESET;
- fcmd->data = (dma_addr_t)NULL;
- fcmd->proto = TYPE_SCSI_FCP;
-
- memcpy (cmd->fcp_cdb, SCpnt->cmnd, SCpnt->cmd_len);
- memset (cmd->fcp_cdb+SCpnt->cmd_len, 0, sizeof(cmd->fcp_cdb)-SCpnt->cmd_len);
- FCD(("XXX: %04x.%04x.%04x.%04x - %08x%08x%08x\n", cmd->fcp_addr[0], cmd->fcp_addr[1], cmd->fcp_addr[2], cmd->fcp_addr[3], *(u32 *)SCpnt->cmnd, *(u32 *)(SCpnt->cmnd+4), *(u32 *)(SCpnt->cmnd+8)))
- } else {
- fcmd = FCP_CMND(fc->rst_pkt);
- if (fc->rst_pkt->eh_state == SCSI_STATE_QUEUED)
- return FAILED; /* or SUCCESS. Only these */
- }
- fc->rst_pkt->done = NULL;
-
-
- fc->rst_pkt->eh_state = SCSI_STATE_QUEUED;
- init_timer(&fc->rst_pkt->eh_timeout);
- fc->rst_pkt->eh_timeout.data = (unsigned long) fc->rst_pkt;
- fc->rst_pkt->eh_timeout.expires = jiffies + FCP_RESET_TIMEOUT;
- fc->rst_pkt->eh_timeout.function = (void (*)(unsigned long))fcp_scsi_reset_done;
-
- add_timer(&fc->rst_pkt->eh_timeout);
-
- /*
- * Set up the semaphore so we wait for the command to complete.
- */
-
- fc->rst_pkt->device->host->eh_action = &sem;
-
- fc->rst_pkt->done = fcp_scsi_reset_done;
-
- spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
- fcp_scsi_queue_it(fc, fc->rst_pkt, fcmd, 0);
- spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
-
- down(&sem);
-
- fc->rst_pkt->device->host->eh_action = NULL;
- del_timer(&fc->rst_pkt->eh_timeout);
-
- /*
- * See if timeout. If so, tell the host to forget about it.
- * In other words, we don't want a callback any more.
- */
- if (fc->rst_pkt->eh_state == SCSI_STATE_TIMEOUT ) {
- fc->rst_pkt->eh_state = SCSI_STATE_UNUSED;
- return FAILED;
- }
- fc->rst_pkt->eh_state = SCSI_STATE_UNUSED;
-#endif
- return SUCCESS;
-}
-
-static int __fcp_scsi_host_reset(struct scsi_cmnd *SCpnt)
-{
- fc_channel *fc = FC_SCMND(SCpnt);
- fcp_cmnd *fcmd = FCP_CMND(SCpnt);
- int i;
-
- printk ("FC: host reset\n");
-
- for (i=0; i < fc->can_queue; i++) {
- if (fc->cmd_slots[i] && SCpnt->result != DID_ABORT) {
- SCpnt->result = DID_RESET;
- fcmd->done(SCpnt);
- fc->cmd_slots[i] = NULL;
- }
- }
- fc->reset(fc);
- fc->abort_count = 0;
- if (fcp_initialize(fc, 1)) return SUCCESS;
- else return FAILED;
-}
-
-int fcp_scsi_host_reset(struct scsi_cmnd *SCpnt)
-{
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
- rc = __fcp_scsi_host_reset(SCpnt);
- spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
-
- return rc;
-}
-
-static int fcp_els_queue_it(fc_channel *fc, fcp_cmnd *fcmd)
-{
- long i;
-
- i = find_first_zero_bit (fc->scsi_bitmap, fc->scsi_bitmap_end);
- set_bit (i, fc->scsi_bitmap);
- fcmd->token = i;
- fc->scsi_free--;
- fc->cmd_slots[fcmd->token] = fcmd;
- return fcp_scsi_queue_it(fc, NULL, fcmd, 0);
-}
-
-static int fc_do_els(fc_channel *fc, unsigned int alpa, void *data, int len)
-{
- fcp_cmnd _fcmd, *fcmd;
- fc_hdr *fch;
- lse l;
- int i;
-
- fcmd = &_fcmd;
- memset(fcmd, 0, sizeof(fcp_cmnd));
- FCD(("PLOGI SID %d DID %d\n", fc->sid, alpa))
- fch = &fcmd->fch;
- FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, alpa);
- FILL_FCHDR_SID(fch, fc->sid);
- FILL_FCHDR_TYPE_FCTL(fch, TYPE_EXTENDED_LS, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE);
- FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0);
- FILL_FCHDR_OXRX(fch, 0xffff, 0xffff);
- fch->param = 0;
- fcmd->cmd = dma_map_single (fc->dev, data, 2 * len, DMA_BIDIRECTIONAL);
- fcmd->rsp = fcmd->cmd + len;
- fcmd->cmdlen = len;
- fcmd->rsplen = len;
- fcmd->data = (dma_addr_t)NULL;
- fcmd->fc = fc;
- fcmd->class = FC_CLASS_SIMPLE;
- fcmd->proto = TYPE_EXTENDED_LS;
-
- memset (&l, 0, sizeof(lse));
- l.magic = LSEMAGIC;
- init_MUTEX_LOCKED(&l.sem);
- l.timer.function = fcp_login_timeout;
- l.timer.data = (unsigned long)&l;
- l.status = FC_STATUS_TIMED_OUT;
- fcmd->ls = (void *)&l;
-
- disable_irq(fc->irq);
- fcp_els_queue_it(fc, fcmd);
- enable_irq(fc->irq);
-
- for (i = 0;;) {
- l.timer.expires = jiffies + 5 * HZ;
- add_timer(&l.timer);
- down(&l.sem);
- del_timer(&l.timer);
- if (l.status != FC_STATUS_TIMED_OUT) break;
- if (++i == 3) break;
- disable_irq(fc->irq);
- fcp_scsi_queue_it(fc, NULL, fcmd, 0);
- enable_irq(fc->irq);
- }
-
- clear_bit(fcmd->token, fc->scsi_bitmap);
- fc->scsi_free++;
- dma_unmap_single (fc->dev, fcmd->cmd, 2 * len, DMA_BIDIRECTIONAL);
- return l.status;
-}
-
-int fc_do_plogi(fc_channel *fc, unsigned char alpa, fc_wwn *node, fc_wwn *nport)
-{
- logi *l;
- int status;
-
- l = kzalloc(2 * sizeof(logi), GFP_KERNEL);
- if (!l) return -ENOMEM;
- l->code = LS_PLOGI;
- memcpy (&l->nport_wwn, &fc->wwn_nport, sizeof(fc_wwn));
- memcpy (&l->node_wwn, &fc->wwn_node, sizeof(fc_wwn));
- memcpy (&l->common, fc->common_svc, sizeof(common_svc_parm));
- memcpy (&l->class1, fc->class_svcs, 3*sizeof(svc_parm));
- status = fc_do_els(fc, alpa, l, sizeof(logi));
- if (status == FC_STATUS_OK) {
- if (l[1].code == LS_ACC) {
-#ifdef FCDEBUG
- u32 *u = (u32 *)&l[1].nport_wwn;
- FCD(("AL-PA %02x: Port WWN %08x%08x Node WWN %08x%08x\n", alpa,
- u[0], u[1], u[2], u[3]))
-#endif
- memcpy(nport, &l[1].nport_wwn, sizeof(fc_wwn));
- memcpy(node, &l[1].node_wwn, sizeof(fc_wwn));
- } else
- status = FC_STATUS_BAD_RSP;
- }
- kfree(l);
- return status;
-}
-
-typedef struct {
- unsigned int code;
- unsigned params[4];
-} prli;
-
-int fc_do_prli(fc_channel *fc, unsigned char alpa)
-{
- prli *p;
- int status;
-
- p = kzalloc(2 * sizeof(prli), GFP_KERNEL);
- if (!p) return -ENOMEM;
- p->code = LS_PRLI;
- p->params[0] = 0x08002000;
- p->params[3] = 0x00000022;
- status = fc_do_els(fc, alpa, p, sizeof(prli));
- if (status == FC_STATUS_OK && p[1].code != LS_PRLI_ACC && p[1].code != LS_ACC)
- status = FC_STATUS_BAD_RSP;
- kfree(p);
- return status;
-}
-
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/fc4/fc.h b/drivers/fc4/fc.h
deleted file mode 100644
index 13f89d4c8cb..00000000000
--- a/drivers/fc4/fc.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/* fc.h: Definitions for Fibre Channel Physical and Signaling Interface.
- *
- * Copyright (C) 1996-1997,1999 Jakub Jelinek (jj@ultra.linux.cz)
- *
- * Sources:
- * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994
- * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995
- */
-
-#ifndef __FC_H
-#define __FC_H
-
-/* World Wide Name */
-#define NAAID_IEEE 1
-#define NAAID_IEEE_EXT 2
-#define NAAID_LOCAL 3
-#define NAAID_IP 4
-#define NAAID_IEEE_REG 5
-#define NAAID_IEEE_REG_EXT 6
-#define NAAID_CCITT 12
-#define NAAID_CCITT_GRP 14
-
-/* This is NAAID_IEEE_EXT scheme */
-typedef struct {
- u32 naaid:4;
- u32 nportid:12;
- u32 hi:16;
- u32 lo;
-} fc_wwn;
-
-/* Frame header for FC-PH frames */
-
-/* r_ctl field */
-#define R_CTL_DEVICE_DATA 0x00 /* FC4 Device_Data frame */
-#define R_CTL_EXTENDED_SVC 0x20 /* Extended Link_Data frame */
-#define R_CTL_FC4_SVC 0x30 /* FC4 Link_Data frame */
-#define R_CTL_VIDEO 0x40 /* Video_Data frame */
-#define R_CTL_BASIC_SVC 0x80 /* Basic Link_Data frame */
-#define R_CTL_LINK_CTL 0xc0 /* Link_Control frame */
-/* FC4 Device_Data frames */
-#define R_CTL_UNCATEGORIZED 0x00
-#define R_CTL_SOLICITED_DATA 0x01
-#define R_CTL_UNSOL_CONTROL 0x02
-#define R_CTL_SOLICITED_CONTROL 0x03
-#define R_CTL_UNSOL_DATA 0x04
-#define R_CTL_XFER_RDY 0x05
-#define R_CTL_COMMAND 0x06
-#define R_CTL_STATUS 0x07
-/* Basic Link_Data frames */
-#define R_CTL_LS_NOP 0x80
-#define R_CTL_LS_ABTS 0x81
-#define R_CTL_LS_RMC 0x82
-#define R_CTL_LS_BA_ACC 0x84
-#define R_CTL_LS_BA_RJT 0x85
-/* Extended Link_Data frames */
-#define R_CTL_ELS_REQ 0x22
-#define R_CTL_ELS_RSP 0x23
-/* Link_Control frames */
-#define R_CTL_ACK_1 0xc0
-#define R_CTL_ACK_N 0xc1
-#define R_CTL_P_RJT 0xc2
-#define R_CTL_F_RJT 0xc3
-#define R_CTL_P_BSY 0xc4
-#define R_CTL_F_BSY_DF 0xc5
-#define R_CTL_F_BSY_LC 0xc6
-#define R_CTL_LCR 0xc7
-
-/* type field */
-#define TYPE_BASIC_LS 0x00
-#define TYPE_EXTENDED_LS 0x01
-#define TYPE_IS8802 0x04
-#define TYPE_IS8802_SNAP 0x05
-#define TYPE_SCSI_FCP 0x08
-#define TYPE_SCSI_GPP 0x09
-#define TYPE_HIPP_FP 0x0a
-#define TYPE_IPI3_MASTER 0x11
-#define TYPE_IPI3_SLAVE 0x12
-#define TYPE_IPI3_PEER 0x13
-
-/* f_ctl field */
-#define F_CTL_FILL_BYTES 0x000003
-#define F_CTL_XCHG_REASSEMBLE 0x000004
-#define F_CTL_RO_PRESENT 0x000008
-#define F_CTL_ABORT_SEQ 0x000030
-#define F_CTL_CONTINUE_SEQ 0x0000c0
-#define F_CTL_INVALIDATE_XID 0x004000
-#define F_CTL_XID_REASSIGNED 0x008000
-#define F_CTL_SEQ_INITIATIVE 0x010000
-#define F_CTL_CHAINED_SEQ 0x020000
-#define F_CTL_END_CONNECT 0x040000
-#define F_CTL_END_SEQ 0x080000
-#define F_CTL_LAST_SEQ 0x100000
-#define F_CTL_FIRST_SEQ 0x200000
-#define F_CTL_SEQ_CONTEXT 0x400000
-#define F_CTL_XCHG_CONTEXT 0x800000
-
-typedef struct {
- u32 r_ctl:8, did:24;
- u32 xxx1:8, sid:24;
- u32 type:8, f_ctl:24;
- u32 seq_id:8, df_ctl:8, seq_cnt:16;
- u16 ox_id, rx_id;
- u32 param;
-} fc_hdr;
-/* The following are ugly macros to make setup of this structure faster */
-#define FILL_FCHDR_RCTL_DID(fch, r_ctl, did) *(u32 *)(fch) = ((r_ctl) << 24) | (did);
-#define FILL_FCHDR_SID(fch, sid) *((u32 *)(fch)+1) = (sid);
-#define FILL_FCHDR_TYPE_FCTL(fch, type, f_ctl) *((u32 *)(fch)+2) = ((type) << 24) | (f_ctl);
-#define FILL_FCHDR_SEQ_DF_SEQ(fch, seq_id, df_ctl, seq_cnt) *((u32 *)(fch)+3) = ((seq_id) << 24) | ((df_ctl) << 16) | (seq_cnt);
-#define FILL_FCHDR_OXRX(fch, ox_id, rx_id) *((u32 *)(fch)+4) = ((ox_id) << 16) | (rx_id);
-
-/* Well known addresses */
-#define FS_GENERAL_MULTICAST 0xfffff7
-#define FS_WELL_KNOWN_MULTICAST 0xfffff8
-#define FS_HUNT_GROUP 0xfffff9
-#define FS_MANAGEMENT_SERVER 0xfffffa
-#define FS_TIME_SERVER 0xfffffb
-#define FS_NAME_SERVER 0xfffffc
-#define FS_FABRIC_CONTROLLER 0xfffffd
-#define FS_FABRIC_F_PORT 0xfffffe
-#define FS_BROADCAST 0xffffff
-
-/* Reject frames */
-/* The param field should be cast to this structure */
-typedef struct {
- u8 action;
- u8 reason;
- u8 xxx;
- u8 vendor_unique;
-} rjt_param;
-
-/* Reject action codes */
-#define RJT_RETRY 0x01
-#define RJT_NONRETRY 0x02
-
-/* Reject reason codes */
-#define RJT_INVALID_DID 0x01
-#define RJT_INVALID_SID 0x02
-#define RJT_NPORT_NOT_AVAIL_TEMP 0x03
-#define RJT_NPORT_NOT_AVAIL_PERM 0x04
-#define RJT_CLASS_NOT_SUPPORTED 0x05
-#define RJT_DELIMITER_ERROR 0x06
-#define RJT_TYPE_NOT_SUPPORTED 0x07
-#define RJT_INVALID_LINK_CONTROL 0x08
-#define RJT_INVALID_R_CTL 0x09
-#define RJT_INVALID_F_CTL 0x0a
-#define RJT_INVALID_OX_ID 0x0b
-#define RJT_INVALID_RX_ID 0x0c
-#define RJT_INVALID_SEQ_ID 0x0d
-#define RJT_INVALID_DF_CTL 0x0e
-#define RJT_INVALID_SEQ_CNT 0x0f
-#define RJT_INVALID_PARAMETER 0x10
-#define RJT_EXCHANGE_ERROR 0x11
-#define RJT_PROTOCOL_ERROR 0x12
-#define RJT_INCORRECT_LENGTH 0x13
-#define RJT_UNEXPECTED_ACK 0x14
-#define RJT_UNEXPECTED_LINK_RESP 0x15
-#define RJT_LOGIN_REQUIRED 0x16
-#define RJT_EXCESSIVE_SEQUENCES 0x17
-#define RJT_CANT_ESTABLISH_EXCHANGE 0x18
-#define RJT_SECURITY_NOT_SUPPORTED 0x19
-#define RJT_FABRIC_NA 0x1a
-#define RJT_VENDOR_UNIQUE 0xff
-
-
-#define SP_F_PORT_LOGIN 0x10
-
-/* Extended SVC commands */
-#define LS_RJT 0x01000000
-#define LS_ACC 0x02000000
-#define LS_PRLI_ACC 0x02100014
-#define LS_PLOGI 0x03000000
-#define LS_FLOGI 0x04000000
-#define LS_LOGO 0x05000000
-#define LS_ABTX 0x06000000
-#define LS_RCS 0x07000000
-#define LS_RES 0x08000000
-#define LS_RSS 0x09000000
-#define LS_RSI 0x0a000000
-#define LS_ESTS 0x0b000000
-#define LS_ESTC 0x0c000000
-#define LS_ADVC 0x0d000000
-#define LS_RTV 0x0e000000
-#define LS_RLS 0x0f000000
-#define LS_ECHO 0x10000000
-#define LS_TEST 0x11000000
-#define LS_RRQ 0x12000000
-#define LS_IDENT 0x20000000
-#define LS_PRLI 0x20100014
-#define LS_DISPLAY 0x21000000
-#define LS_PRLO 0x21100014
-#define LS_PDISC 0x50000000
-#define LS_ADISC 0x52000000
-
-typedef struct {
- u8 fcph_hi, fcph_lo;
- u16 buf2buf_credit;
- u8 common_features;
- u8 xxx1;
- u16 buf2buf_size;
- u8 xxx2;
- u8 total_concurrent;
- u16 off_by_info;
- u32 e_d_tov;
-} common_svc_parm;
-
-typedef struct {
- u16 serv_opts;
- u16 initiator_ctl;
- u16 rcpt_ctl;
- u16 recv_size;
- u8 xxx1;
- u8 concurrent_seqs;
- u16 end2end_credit;
- u16 open_seqs_per_xchg;
- u16 xxx2;
-} svc_parm;
-
-/* Login */
-typedef struct {
- u32 code;
- common_svc_parm common;
- fc_wwn nport_wwn;
- fc_wwn node_wwn;
- svc_parm class1;
- svc_parm class2;
- svc_parm class3;
-} logi;
-
-#endif /* !(__FC_H) */
diff --git a/drivers/fc4/fc_syms.c b/drivers/fc4/fc_syms.c
deleted file mode 100644
index bd3918ddf7a..00000000000
--- a/drivers/fc4/fc_syms.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * We should not even be trying to compile this if we are not doing
- * a module.
- */
-#include <linux/module.h>
-
-#ifdef CONFIG_MODULES
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-
-#include "fcp_impl.h"
-
-EXPORT_SYMBOL(fcp_init);
-EXPORT_SYMBOL(fcp_release);
-EXPORT_SYMBOL(fcp_queue_empty);
-EXPORT_SYMBOL(fcp_receive_solicited);
-EXPORT_SYMBOL(fc_channels);
-EXPORT_SYMBOL(fcp_state_change);
-EXPORT_SYMBOL(fc_do_plogi);
-EXPORT_SYMBOL(fc_do_prli);
-
-/* SCSI stuff */
-EXPORT_SYMBOL(fcp_scsi_queuecommand);
-EXPORT_SYMBOL(fcp_scsi_abort);
-EXPORT_SYMBOL(fcp_scsi_dev_reset);
-EXPORT_SYMBOL(fcp_scsi_host_reset);
-
-#endif /* CONFIG_MODULES */
diff --git a/drivers/fc4/fcp.h b/drivers/fc4/fcp.h
deleted file mode 100644
index 6aa34a7a4c1..00000000000
--- a/drivers/fc4/fcp.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/* fcp.h: Definitions for Fibre Channel Protocol.
- *
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- *
- */
-
-#ifndef __FCP_H
-#define __FCP_H
-
-/* FCP addressing is hierarchical with up to 4 layers, MS first.
- Exact meaning of the addresses is up to the vendor */
-
-/* fcp_cntl field */
-#define FCP_CNTL_WRITE 0x00000001 /* Initiator write */
-#define FCP_CNTL_READ 0x00000002 /* Initiator read */
-#define FCP_CNTL_ABORT_TSK 0x00000200 /* Abort task set */
-#define FCP_CNTL_CLR_TASK 0x00000400 /* Clear task set */
-#define FCP_CNTL_RESET 0x00002000 /* Reset */
-#define FCP_CNTL_CLR_ACA 0x00004000 /* Clear ACA */
-#define FCP_CNTL_KILL_TASK 0x00008000 /* Terminate task */
-#define FCP_CNTL_QTYPE_MASK 0x00070000 /* Tagged queueing type */
-#define FCP_CNTL_QTYPE_SIMPLE 0x00000000
-#define FCP_CNTL_QTYPE_HEAD_OF_Q 0x00010000
-#define FCP_CNTL_QTYPE_ORDERED 0x00020000
-#define FCP_CNTL_QTYPE_ACA_Q_TAG 0x00040000
-#define FCP_CNTL_QTYPE_UNTAGGED 0x00050000
-
-typedef struct {
- u16 fcp_addr[4];
- u32 fcp_cntl;
- u8 fcp_cdb[16];
- u32 fcp_data_len;
-} fcp_cmd;
-
-/* fcp_status field */
-#define FCP_STATUS_MASK 0x000000ff /* scsi status of command */
-#define FCP_STATUS_RSP_LEN 0x00000100 /* response_len != 0 */
-#define FCP_STATUS_SENSE_LEN 0x00000200 /* sense_len != 0 */
-#define FCP_STATUS_RESID 0x00000400 /* resid != 0 */
-
-typedef struct {
- u32 xxx[2];
- u32 fcp_status;
- u32 fcp_resid;
- u32 fcp_sense_len;
- u32 fcp_response_len;
- /* u8 fcp_sense[fcp_sense_len]; */
- /* u8 fcp_response[fcp_response_len]; */
-} fcp_rsp;
-
-/* fcp errors */
-
-/* rsp_info_type field */
-#define FCP_RSP_SCSI_BUS_ERR 0x01
-#define FCP_RSP_SCSI_PORT_ERR 0x02
-#define FCP_RSP_CARD_ERR 0x03
-
-/* isp_status field */
-#define FCP_RSP_CMD_COMPLETE 0x0000
-#define FCP_RSP_CMD_INCOMPLETE 0x0001
-#define FCP_RSP_CMD_DMA_ERR 0x0002
-#define FCP_RSP_CMD_TRAN_ERR 0x0003
-#define FCP_RSP_CMD_RESET 0x0004
-#define FCP_RSP_CMD_ABORTED 0x0005
-#define FCP_RSP_CMD_TIMEOUT 0x0006
-#define FCP_RSP_CMD_OVERRUN 0x0007
-
-/* isp_state_flags field */
-#define FCP_RSP_ST_GOT_BUS 0x0100
-#define FCP_RSP_ST_GOT_TARGET 0x0200
-#define FCP_RSP_ST_SENT_CMD 0x0400
-#define FCP_RSP_ST_XFRD_DATA 0x0800
-#define FCP_RSP_ST_GOT_STATUS 0x1000
-#define FCP_RSP_ST_GOT_SENSE 0x2000
-
-/* isp_stat_flags field */
-#define FCP_RSP_STAT_DISC 0x0001
-#define FCP_RSP_STAT_SYNC 0x0002
-#define FCP_RSP_STAT_PERR 0x0004
-#define FCP_RSP_STAT_BUS_RESET 0x0008
-#define FCP_RSP_STAT_DEV_RESET 0x0010
-#define FCP_RSP_STAT_ABORTED 0x0020
-#define FCP_RSP_STAT_TIMEOUT 0x0040
-#define FCP_RSP_STAT_NEGOTIATE 0x0080
-
-typedef struct {
- u8 rsp_info_type;
- u8 xxx;
- u16 isp_status;
- u16 isp_state_flags;
- u16 isp_stat_flags;
-} fcp_scsi_err;
-
-#endif /* !(__FCP_H) */
diff --git a/drivers/fc4/fcp_impl.h b/drivers/fc4/fcp_impl.h
deleted file mode 100644
index 1ac61330592..00000000000
--- a/drivers/fc4/fcp_impl.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/* fcp_impl.h: Generic SCSI on top of FC4 - our interface defines.
- *
- * Copyright (C) 1997-1999 Jakub Jelinek (jj@ultra.linux.cz)
- * Copyright (C) 1998 Jirka Hanika (geo@ff.cuni.cz)
- */
-
-#ifndef _FCP_SCSI_H
-#define _FCP_SCSI_H
-
-#include <linux/types.h>
-#include "../scsi/scsi.h"
-
-#include "fc.h"
-#include "fcp.h"
-#include "fc-al.h"
-
-#include <asm/io.h>
-#ifdef __sparc__
-#include <asm/sbus.h>
-#endif
-
-/* 0 or 1 */
-#define FCP_SCSI_USE_NEW_EH_CODE 0
-
-#define FC_CLASS_OUTBOUND 0x01
-#define FC_CLASS_INBOUND 0x02
-#define FC_CLASS_SIMPLE 0x03
-#define FC_CLASS_IO_WRITE 0x04
-#define FC_CLASS_IO_READ 0x05
-#define FC_CLASS_UNSOLICITED 0x06
-#define FC_CLASS_OFFLINE 0x08
-
-#define PROTO_OFFLINE 0x02
-#define PROTO_REPORT_AL_MAP 0x03
-#define PROTO_FORCE_LIP 0x06
-
-struct _fc_channel;
-
-typedef struct fcp_cmnd {
- struct fcp_cmnd *next;
- struct fcp_cmnd *prev;
- void (*done)(struct scsi_cmnd *);
- unsigned short proto;
- unsigned short token;
- unsigned int did;
- /* FCP SCSI stuff */
- dma_addr_t data;
- /* From now on this cannot be touched for proto == TYPE_SCSI_FCP */
- fc_hdr fch;
- dma_addr_t cmd;
- dma_addr_t rsp;
- int cmdlen;
- int rsplen;
- int class;
- int datalen;
- /* This is just used as a verification during login */
- struct _fc_channel *fc;
- void *ls;
-} fcp_cmnd;
-
-typedef struct {
- unsigned int len;
- unsigned char list[0];
-} fcp_posmap;
-
-typedef struct _fc_channel {
- struct _fc_channel *next;
- int irq;
- int state;
- int sid;
- int did;
- char name[16];
- void (*fcp_register)(struct _fc_channel *, u8, int);
- void (*reset)(struct _fc_channel *);
- int (*hw_enque)(struct _fc_channel *, fcp_cmnd *);
- fc_wwn wwn_node;
- fc_wwn wwn_nport;
- fc_wwn wwn_dest;
- common_svc_parm *common_svc;
- svc_parm *class_svcs;
-#ifdef __sparc__
- struct sbus_dev *dev;
-#else
- struct pci_dev *dev;
-#endif
- struct module *module;
- /* FCP SCSI stuff */
- short can_queue;
- short abort_count;
- int rsp_size;
- fcp_cmd *scsi_cmd_pool;
- char *scsi_rsp_pool;
- dma_addr_t dma_scsi_cmd, dma_scsi_rsp;
- long *scsi_bitmap;
- long scsi_bitmap_end;
- int scsi_free;
- int (*encode_addr)(struct scsi_cmnd *, u16 *, struct _fc_channel *, fcp_cmnd *);
- fcp_cmnd *scsi_que;
- char scsi_name[4];
- fcp_cmnd **cmd_slots;
- int channels;
- int targets;
- long *ages;
- struct scsi_cmnd *rst_pkt;
- fcp_posmap *posmap;
- /* LOGIN stuff */
- fcp_cmnd *login;
- void *ls;
-} fc_channel;
-
-extern fc_channel *fc_channels;
-
-#define FC_STATE_UNINITED 0
-#define FC_STATE_ONLINE 1
-#define FC_STATE_OFFLINE 2
-#define FC_STATE_RESETING 3
-#define FC_STATE_FPORT_OK 4
-#define FC_STATE_MAYBEOFFLINE 5
-
-#define FC_STATUS_OK 0
-#define FC_STATUS_P_RJT 2
-#define FC_STATUS_F_RJT 3
-#define FC_STATUS_P_BSY 4
-#define FC_STATUS_F_BSY 5
-#define FC_STATUS_ERR_OFFLINE 0x11
-#define FC_STATUS_TIMEOUT 0x12
-#define FC_STATUS_ERR_OVERRUN 0x13
-#define FC_STATUS_POINTTOPOINT 0x15
-#define FC_STATUS_AL 0x16
-#define FC_STATUS_UNKNOWN_CQ_TYPE 0x20
-#define FC_STATUS_BAD_SEG_CNT 0x21
-#define FC_STATUS_MAX_XCHG_EXCEEDED 0x22
-#define FC_STATUS_BAD_XID 0x23
-#define FC_STATUS_XCHG_BUSY 0x24
-#define FC_STATUS_BAD_POOL_ID 0x25
-#define FC_STATUS_INSUFFICIENT_CQES 0x26
-#define FC_STATUS_ALLOC_FAIL 0x27
-#define FC_STATUS_BAD_SID 0x28
-#define FC_STATUS_NO_SEQ_INIT 0x29
-#define FC_STATUS_TIMED_OUT -1
-#define FC_STATUS_BAD_RSP -2
-
-void fcp_queue_empty(fc_channel *);
-int fcp_init(fc_channel *);
-void fcp_release(fc_channel *fc_chain, int count);
-void fcp_receive_solicited(fc_channel *, int, int, int, fc_hdr *);
-void fcp_state_change(fc_channel *, int);
-int fc_do_plogi(fc_channel *, unsigned char, fc_wwn *, fc_wwn *);
-int fc_do_prli(fc_channel *, unsigned char);
-
-#define for_each_fc_channel(fc) \
- for (fc = fc_channels; fc; fc = fc->next)
-
-#define for_each_online_fc_channel(fc) \
- for_each_fc_channel(fc) \
- if (fc->state == FC_STATE_ONLINE)
-
-int fcp_scsi_queuecommand(struct scsi_cmnd *,
- void (* done) (struct scsi_cmnd *));
-int fcp_scsi_abort(struct scsi_cmnd *);
-int fcp_scsi_dev_reset(struct scsi_cmnd *);
-int fcp_scsi_host_reset(struct scsi_cmnd *);
-
-#endif /* !(_FCP_SCSI_H) */
diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c
deleted file mode 100644
index d517734462e..00000000000
--- a/drivers/fc4/soc.c
+++ /dev/null
@@ -1,764 +0,0 @@
-/* soc.c: Sparc SUNW,soc (Serial Optical Channel) Fibre Channel Sbus adapter support.
- *
- * Copyright (C) 1996,1997,1999 Jakub Jelinek (jj@ultra.linux.cz)
- * Copyright (C) 1997,1998 Jirka Hanika (geo@ff.cuni.cz)
- *
- * Sources:
- * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994
- * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995
- *
- * Supported hardware:
- * Tested on SOC sbus card bought with SS1000 in Linux running on SS5 and Ultra1.
- * For SOC sbus cards, you have to make sure your FCode is 1.52 or later.
- * If you have older FCode, you should try to upgrade or get SOC microcode from Sun
- * (the microcode is present in Solaris soc driver as well). In that case you need
- * to #define HAVE_SOC_UCODE and format the microcode into soc_asm.c. For the exact
- * format mail me and I will tell you. I cannot offer you the actual microcode though,
- * unless Sun confirms they don't mind.
- */
-
-static char *version =
- "soc.c:v1.3 9/Feb/99 Jakub Jelinek (jj@ultra.linux.cz), Jirka Hanika (geo@ff.cuni.cz)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/errno.h>
-#include <asm/byteorder.h>
-
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-
-/* #define SOCDEBUG */
-/* #define HAVE_SOC_UCODE */
-
-#include "fcp_impl.h"
-#include "soc.h"
-#ifdef HAVE_SOC_UCODE
-#include "soc_asm.h"
-#endif
-
-#define soc_printk printk ("soc%d: ", s->soc_no); printk
-
-#ifdef SOCDEBUG
-#define SOD(x) soc_printk x;
-#else
-#define SOD(x)
-#endif
-
-#define for_each_soc(s) for (s = socs; s; s = s->next)
-struct soc *socs = NULL;
-
-static inline void soc_disable(struct soc *s)
-{
- sbus_writel(0, s->regs + IMASK);
- sbus_writel(SOC_CMD_SOFT_RESET, s->regs + CMD);
-}
-
-static inline void soc_enable(struct soc *s)
-{
- SOD(("enable %08x\n", s->cfg))
- sbus_writel(0, s->regs + SAE);
- sbus_writel(s->cfg, s->regs + CFG);
- sbus_writel(SOC_CMD_RSP_QALL, s->regs + CMD);
- SOC_SETIMASK(s, SOC_IMASK_RSP_QALL | SOC_IMASK_SAE);
- SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMAK)));
-}
-
-static void soc_reset(fc_channel *fc)
-{
- soc_port *port = (soc_port *)fc;
- struct soc *s = port->s;
-
- /* FIXME */
- soc_disable(s);
- s->req[0].seqno = 1;
- s->req[1].seqno = 1;
- s->rsp[0].seqno = 1;
- s->rsp[1].seqno = 1;
- s->req[0].in = 0;
- s->req[1].in = 0;
- s->rsp[0].in = 0;
- s->rsp[1].in = 0;
- s->req[0].out = 0;
- s->req[1].out = 0;
- s->rsp[0].out = 0;
- s->rsp[1].out = 0;
-
- /* FIXME */
- soc_enable(s);
-}
-
-static inline void soc_solicited (struct soc *s)
-{
- fc_hdr fchdr;
- soc_rsp __iomem *hwrsp;
- soc_cq_rsp *sw_cq;
- int token;
- int status;
- fc_channel *fc;
-
- sw_cq = &s->rsp[SOC_SOLICITED_RSP_Q];
-
- if (sw_cq->pool == NULL)
- sw_cq->pool = (soc_req __iomem *)
- (s->xram + xram_get_32low ((xram_p)&sw_cq->hw_cq->address));
- sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in);
- SOD (("soc_solicited, %d pkts arrived\n", (sw_cq->in-sw_cq->out) & sw_cq->last))
- for (;;) {
- hwrsp = (soc_rsp __iomem *)sw_cq->pool + sw_cq->out;
- token = xram_get_32low ((xram_p)&hwrsp->shdr.token);
- status = xram_get_32low ((xram_p)&hwrsp->status);
- fc = (fc_channel *)(&s->port[(token >> 11) & 1]);
-
- if (status == SOC_OK) {
- fcp_receive_solicited(fc, token >> 12,
- token & ((1 << 11) - 1),
- FC_STATUS_OK, NULL);
- } else {
- xram_copy_from(&fchdr, (xram_p)&hwrsp->fchdr, sizeof(fchdr));
- /* We have intentionally defined FC_STATUS_* constants
- * to match SOC_* constants, otherwise we'd have to
- * translate status.
- */
- fcp_receive_solicited(fc, token >> 12,
- token & ((1 << 11) - 1),
- status, &fchdr);
- }
-
- if (++sw_cq->out > sw_cq->last) {
- sw_cq->seqno++;
- sw_cq->out = 0;
- }
-
- if (sw_cq->out == sw_cq->in) {
- sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in);
- if (sw_cq->out == sw_cq->in) {
- /* Tell the hardware about it */
- sbus_writel((sw_cq->out << 24) |
- (SOC_CMD_RSP_QALL &
- ~(SOC_CMD_RSP_Q0 << SOC_SOLICITED_RSP_Q)),
- s->regs + CMD);
-
- /* Read it, so that we're sure it has been updated */
- sbus_readl(s->regs + CMD);
- sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in);
- if (sw_cq->out == sw_cq->in)
- break;
- }
- }
- }
-}
-
-static inline void soc_request (struct soc *s, u32 cmd)
-{
- SOC_SETIMASK(s, s->imask & ~(cmd & SOC_CMD_REQ_QALL));
- SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMASK)));
-
- SOD(("Queues available %08x OUT %X %X\n", cmd,
- xram_get_8((xram_p)&s->req[0].hw_cq->out),
- xram_get_8((xram_p)&s->req[0].hw_cq->out)))
- if (s->port[s->curr_port].fc.state != FC_STATE_OFFLINE) {
- fcp_queue_empty ((fc_channel *)&(s->port[s->curr_port]));
- if (((s->req[1].in + 1) & s->req[1].last) != (s->req[1].out))
- fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port]));
- } else {
- fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port]));
- }
- if (s->port[1 - s->curr_port].fc.state != FC_STATE_OFFLINE)
- s->curr_port ^= 1;
-}
-
-static inline void soc_unsolicited (struct soc *s)
-{
- soc_rsp __iomem *hwrsp, *hwrspc;
- soc_cq_rsp *sw_cq;
- int count;
- int status;
- int flags;
- fc_channel *fc;
-
- sw_cq = &s->rsp[SOC_UNSOLICITED_RSP_Q];
- if (sw_cq->pool == NULL)
- sw_cq->pool = (soc_req __iomem *)
- (s->xram + (xram_get_32low ((xram_p)&sw_cq->hw_cq->address)));
-
- sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in);
- SOD (("soc_unsolicited, %d packets arrived\n", (sw_cq->in - sw_cq->out) & sw_cq->last))
- while (sw_cq->in != sw_cq->out) {
- /* ...real work per entry here... */
- hwrsp = (soc_rsp __iomem *)sw_cq->pool + sw_cq->out;
-
- hwrspc = NULL;
- flags = xram_get_16 ((xram_p)&hwrsp->shdr.flags);
- count = xram_get_8 ((xram_p)&hwrsp->count);
- fc = (fc_channel *)&s->port[flags & SOC_PORT_B];
- SOD(("FC %08lx fcp_state_change %08lx\n",
- (long)fc, (long)fc->fcp_state_change))
-
- if (count != 1) {
- /* Ugh, continuation entries */
- u8 in;
-
- if (count != 2) {
- printk("%s: Too many continuations entries %d\n",
- fc->name, count);
- goto update_out;
- }
-
- in = sw_cq->in;
- if (in < sw_cq->out) in += sw_cq->last + 1;
- if (in < sw_cq->out + 2) {
- /* Ask the hardware if they haven't arrived yet. */
- sbus_writel((sw_cq->out << 24) |
- (SOC_CMD_RSP_QALL &
- ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)),
- s->regs + CMD);
-
- /* Read it, so that we're sure it has been updated */
- sbus_readl(s->regs + CMD);
- sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in);
- in = sw_cq->in;
- if (in < sw_cq->out)
- in += sw_cq->last + 1;
- if (in < sw_cq->out + 2) /* Nothing came, let us wait */
- return;
- }
- if (sw_cq->out == sw_cq->last)
- hwrspc = (soc_rsp __iomem *)sw_cq->pool;
- else
- hwrspc = hwrsp + 1;
- }
-
- switch (flags & ~SOC_PORT_B) {
- case SOC_STATUS:
- status = xram_get_32low ((xram_p)&hwrsp->status);
- switch (status) {
- case SOC_ONLINE:
- SOD(("State change to ONLINE\n"));
- fcp_state_change(fc, FC_STATE_ONLINE);
- break;
- case SOC_OFFLINE:
- SOD(("State change to OFFLINE\n"));
- fcp_state_change(fc, FC_STATE_OFFLINE);
- break;
- default:
- printk ("%s: Unknown STATUS no %d\n",
- fc->name, status);
- break;
- }
- break;
- case (SOC_UNSOLICITED|SOC_FC_HDR):
- {
- int r_ctl = xram_get_8 ((xram_p)&hwrsp->fchdr);
- unsigned len;
- char buf[64];
-
- if ((r_ctl & 0xf0) == R_CTL_EXTENDED_SVC) {
- len = xram_get_32 ((xram_p)&hwrsp->shdr.bytecnt);
- if (len < 4 || !hwrspc) {
- printk ("%s: Invalid R_CTL %02x "
- "continuation entries\n",
- fc->name, r_ctl);
- } else {
- if (len > 60)
- len = 60;
- xram_copy_from (buf, (xram_p)hwrspc,
- (len + 3) & ~3);
- if (*(u32 *)buf == LS_DISPLAY) {
- int i;
-
- for (i = 4; i < len; i++)
- if (buf[i] == '\n')
- buf[i] = ' ';
- buf[len] = 0;
- printk ("%s message: %s\n",
- fc->name, buf + 4);
- } else {
- printk ("%s: Unknown LS_CMD "
- "%02x\n", fc->name,
- buf[0]);
- }
- }
- } else {
- printk ("%s: Unsolicited R_CTL %02x "
- "not handled\n", fc->name, r_ctl);
- }
- }
- break;
- default:
- printk ("%s: Unexpected flags %08x\n", fc->name, flags);
- break;
- };
-update_out:
- if (++sw_cq->out > sw_cq->last) {
- sw_cq->seqno++;
- sw_cq->out = 0;
- }
-
- if (hwrspc) {
- if (++sw_cq->out > sw_cq->last) {
- sw_cq->seqno++;
- sw_cq->out = 0;
- }
- }
-
- if (sw_cq->out == sw_cq->in) {
- sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in);
- if (sw_cq->out == sw_cq->in) {
- /* Tell the hardware about it */
- sbus_writel((sw_cq->out << 24) |
- (SOC_CMD_RSP_QALL &
- ~(SOC_CMD_RSP_Q0 << SOC_UNSOLICITED_RSP_Q)),
- s->regs + CMD);
-
- /* Read it, so that we're sure it has been updated */
- sbus_readl(s->regs + CMD);
- sw_cq->in = xram_get_8 ((xram_p)&sw_cq->hw_cq->in);
- }
- }
- }
-}
-
-static irqreturn_t soc_intr(int irq, void *dev_id)
-{
- u32 cmd;
- unsigned long flags;
- register struct soc *s = (struct soc *)dev_id;
-
- spin_lock_irqsave(&s->lock, flags);
- cmd = sbus_readl(s->regs + CMD);
- for (; (cmd = SOC_INTR (s, cmd)); cmd = sbus_readl(s->regs + CMD)) {
- if (cmd & SOC_CMD_RSP_Q1) soc_unsolicited (s);
- if (cmd & SOC_CMD_RSP_Q0) soc_solicited (s);
- if (cmd & SOC_CMD_REQ_QALL) soc_request (s, cmd);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-
- return IRQ_HANDLED;
-}
-
-#define TOKEN(proto, port, token) (((proto)<<12)|(token)|(port))
-
-static int soc_hw_enque (fc_channel *fc, fcp_cmnd *fcmd)
-{
- soc_port *port = (soc_port *)fc;
- struct soc *s = port->s;
- int qno;
- soc_cq_req *sw_cq;
- int cq_next_in;
- soc_req *request;
- fc_hdr *fch;
- int i;
-
- if (fcmd->proto == TYPE_SCSI_FCP)
- qno = 1;
- else
- qno = 0;
- SOD(("Putting a FCP packet type %d into hw queue %d\n", fcmd->proto, qno))
- if (s->imask & (SOC_IMASK_REQ_Q0 << qno)) {
- SOD(("EIO %08x\n", s->imask))
- return -EIO;
- }
- sw_cq = s->req + qno;
- cq_next_in = (sw_cq->in + 1) & sw_cq->last;
-
- if (cq_next_in == sw_cq->out &&
- cq_next_in == (sw_cq->out = xram_get_8((xram_p)&sw_cq->hw_cq->out))) {
- SOD(("%d IN %d OUT %d LAST %d\n", qno, sw_cq->in, sw_cq->out, sw_cq->last))
- SOC_SETIMASK(s, s->imask | (SOC_IMASK_REQ_Q0 << qno));
- SOD(("imask %08lx %08lx\n", s->imask, sbus_readl(s->regs + IMASK)));
- /* If queue is full, just say NO */
- return -EBUSY;
- }
-
- request = sw_cq->pool + sw_cq->in;
- fch = &request->fchdr;
-
- switch (fcmd->proto) {
- case TYPE_SCSI_FCP:
- request->shdr.token = TOKEN(TYPE_SCSI_FCP, port->mask, fcmd->token);
- request->data[0].base = fc->dma_scsi_cmd + fcmd->token * sizeof(fcp_cmd);
- request->data[0].count = sizeof(fcp_cmd);
- request->data[1].base = fc->dma_scsi_rsp + fcmd->token * fc->rsp_size;
- request->data[1].count = fc->rsp_size;
- if (fcmd->data) {
- request->shdr.segcnt = 3;
- i = fc->scsi_cmd_pool[fcmd->token].fcp_data_len;
- request->shdr.bytecnt = i;
- request->data[2].base = fcmd->data;
- request->data[2].count = i;
- request->type =
- (fc->scsi_cmd_pool[fcmd->token].fcp_cntl & FCP_CNTL_WRITE) ?
- SOC_CQTYPE_IO_WRITE : SOC_CQTYPE_IO_READ;
- } else {
- request->shdr.segcnt = 2;
- request->shdr.bytecnt = 0;
- request->data[2].base = 0;
- request->data[2].count = 0;
- request->type = SOC_CQTYPE_SIMPLE;
- }
- FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fc->did);
- FILL_FCHDR_SID(fch, fc->sid);
- FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP,
- F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE);
- FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0);
- FILL_FCHDR_OXRX(fch, 0xffff, 0xffff);
- fch->param = 0;
- request->shdr.flags = port->flags;
- request->shdr.class = 2;
- break;
-
- case PROTO_OFFLINE:
- memset (request, 0, sizeof(*request));
- request->shdr.token = TOKEN(PROTO_OFFLINE, port->mask, fcmd->token);
- request->type = SOC_CQTYPE_OFFLINE;
- FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fc->did);
- FILL_FCHDR_SID(fch, fc->sid);
- FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP,
- F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE);
- FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0);
- FILL_FCHDR_OXRX(fch, 0xffff, 0xffff);
- request->shdr.flags = port->flags;
- break;
-
- case PROTO_REPORT_AL_MAP:
- /* SOC only supports Point-to-Point topology, no FC-AL, sorry... */
- return -ENOSYS;
-
- default:
- request->shdr.token = TOKEN(fcmd->proto, port->mask, fcmd->token);
- request->shdr.class = 2;
- request->shdr.flags = port->flags;
- memcpy (fch, &fcmd->fch, sizeof(fc_hdr));
- request->data[0].count = fcmd->cmdlen;
- request->data[1].count = fcmd->rsplen;
- request->type = fcmd->class;
- switch (fcmd->class) {
- case FC_CLASS_OUTBOUND:
- request->data[0].base = fcmd->cmd;
- request->data[0].count = fcmd->cmdlen;
- request->type = SOC_CQTYPE_OUTBOUND;
- request->shdr.bytecnt = fcmd->cmdlen;
- request->shdr.segcnt = 1;
- break;
- case FC_CLASS_INBOUND:
- request->data[0].base = fcmd->rsp;
- request->data[0].count = fcmd->rsplen;
- request->type = SOC_CQTYPE_INBOUND;
- request->shdr.bytecnt = 0;
- request->shdr.segcnt = 1;
- break;
- case FC_CLASS_SIMPLE:
- request->data[0].base = fcmd->cmd;
- request->data[1].base = fcmd->rsp;
- request->data[0].count = fcmd->cmdlen;
- request->data[1].count = fcmd->rsplen;
- request->type = SOC_CQTYPE_SIMPLE;
- request->shdr.bytecnt = fcmd->cmdlen;
- request->shdr.segcnt = 2;
- break;
- case FC_CLASS_IO_READ:
- case FC_CLASS_IO_WRITE:
- request->data[0].base = fcmd->cmd;
- request->data[1].base = fcmd->rsp;
- request->data[0].count = fcmd->cmdlen;
- request->data[1].count = fcmd->rsplen;
- request->type =
- (fcmd->class == FC_CLASS_IO_READ) ?
- SOC_CQTYPE_IO_READ : SOC_CQTYPE_IO_WRITE;
- if (fcmd->data) {
- request->data[2].base = fcmd->data;
- request->data[2].count = fcmd->datalen;
- request->shdr.bytecnt = fcmd->datalen;
- request->shdr.segcnt = 3;
- } else {
- request->shdr.bytecnt = 0;
- request->shdr.segcnt = 2;
- }
- break;
- };
- break;
- };
-
- request->count = 1;
- request->flags = 0;
- request->seqno = sw_cq->seqno;
-
- /* And now tell the SOC about it */
-
- if (++sw_cq->in > sw_cq->last) {
- sw_cq->in = 0;
- sw_cq->seqno++;
- }
-
- SOD(("Putting %08x into cmd\n",
- SOC_CMD_RSP_QALL | (sw_cq->in << 24) | (SOC_CMD_REQ_Q0 << qno)))
-
- sbus_writel(SOC_CMD_RSP_QALL | (sw_cq->in << 24) | (SOC_CMD_REQ_Q0 << qno),
- s->regs + CMD);
-
- /* Read so that command is completed. */
- sbus_readl(s->regs + CMD);
-
- return 0;
-}
-
-static inline void soc_download_fw(struct soc *s)
-{
-#ifdef HAVE_SOC_UCODE
- xram_copy_to (s->xram, soc_ucode, sizeof(soc_ucode));
- xram_bzero (s->xram + sizeof(soc_ucode), 32768 - sizeof(soc_ucode));
-#endif
-}
-
-/* Check for what the best SBUS burst we can use happens
- * to be on this machine.
- */
-static inline void soc_init_bursts(struct soc *s, struct sbus_dev *sdev)
-{
- int bsizes, bsizes_more;
-
- bsizes = (prom_getintdefault(sdev->prom_node,"burst-sizes",0xff) & 0xff);
- bsizes_more = (prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff) & 0xff);
- bsizes &= bsizes_more;
- if ((bsizes & 0x7f) == 0x7f)
- s->cfg = SOC_CFG_BURST_64;
- else if ((bsizes & 0x3f) == 0x3f)
- s->cfg = SOC_CFG_BURST_32;
- else if ((bsizes & 0x1f) == 0x1f)
- s->cfg = SOC_CFG_BURST_16;
- else
- s->cfg = SOC_CFG_BURST_4;
-}
-
-static inline void soc_init(struct sbus_dev *sdev, int no)
-{
- unsigned char tmp[60];
- int propl;
- struct soc *s;
- static int version_printed = 0;
- soc_hw_cq cq[8];
- int size, i;
- int irq;
-
- s = kzalloc (sizeof (struct soc), GFP_KERNEL);
- if (s == NULL)
- return;
- spin_lock_init(&s->lock);
- s->soc_no = no;
-
- SOD(("socs %08lx soc_intr %08lx soc_hw_enque %08x\n",
- (long)socs, (long)soc_intr, (long)soc_hw_enque))
- if (version_printed++ == 0)
- printk (version);
-
- s->port[0].fc.module = THIS_MODULE;
- s->port[1].fc.module = THIS_MODULE;
-
- s->next = socs;
- socs = s;
- s->port[0].fc.dev = sdev;
- s->port[1].fc.dev = sdev;
- s->port[0].s = s;
- s->port[1].s = s;
-
- s->port[0].fc.next = &s->port[1].fc;
-
- /* World Wide Name of SOC */
- propl = prom_getproperty (sdev->prom_node, "soc-wwn", tmp, sizeof(tmp));
- if (propl != sizeof (fc_wwn)) {
- s->wwn.naaid = NAAID_IEEE;
- s->wwn.lo = 0x12345678;
- } else
- memcpy (&s->wwn, tmp, sizeof (fc_wwn));
-
- propl = prom_getproperty (sdev->prom_node, "port-wwns", tmp, sizeof(tmp));
- if (propl != 2 * sizeof (fc_wwn)) {
- s->port[0].fc.wwn_nport.naaid = NAAID_IEEE_EXT;
- s->port[0].fc.wwn_nport.hi = s->wwn.hi;
- s->port[0].fc.wwn_nport.lo = s->wwn.lo;
- s->port[1].fc.wwn_nport.naaid = NAAID_IEEE_EXT;
- s->port[1].fc.wwn_nport.nportid = 1;
- s->port[1].fc.wwn_nport.hi = s->wwn.hi;
- s->port[1].fc.wwn_nport.lo = s->wwn.lo;
- } else {
- memcpy (&s->port[0].fc.wwn_nport, tmp, sizeof (fc_wwn));
- memcpy (&s->port[1].fc.wwn_nport, tmp + sizeof (fc_wwn), sizeof (fc_wwn));
- }
- memcpy (&s->port[0].fc.wwn_node, &s->wwn, sizeof (fc_wwn));
- memcpy (&s->port[1].fc.wwn_node, &s->wwn, sizeof (fc_wwn));
- SOD(("Got wwns %08x%08x ports %08x%08x and %08x%08x\n",
- *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo,
- *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo,
- *(u32 *)&s->port[1].fc.wwn_nport, s->port[1].fc.wwn_nport.lo))
-
- s->port[0].fc.sid = 1;
- s->port[1].fc.sid = 17;
- s->port[0].fc.did = 2;
- s->port[1].fc.did = 18;
-
- s->port[0].fc.reset = soc_reset;
- s->port[1].fc.reset = soc_reset;
-
- if (sdev->num_registers == 1) {
- /* Probably SunFire onboard SOC */
- s->xram = sbus_ioremap(&sdev->resource[0], 0,
- 0x10000UL, "soc xram");
- s->regs = sbus_ioremap(&sdev->resource[0], 0x10000UL,
- 0x10UL, "soc regs");
- } else {
- /* Probably SOC sbus card */
- s->xram = sbus_ioremap(&sdev->resource[1], 0,
- sdev->reg_addrs[1].reg_size, "soc xram");
- s->regs = sbus_ioremap(&sdev->resource[2], 0,
- sdev->reg_addrs[2].reg_size, "soc regs");
- }
-
- soc_init_bursts(s, sdev);
-
- SOD(("Disabling SOC\n"))
-
- soc_disable (s);
-
- irq = sdev->irqs[0];
-
- if (request_irq (irq, soc_intr, IRQF_SHARED, "SOC", (void *)s)) {
- soc_printk ("Cannot order irq %d to go\n", irq);
- socs = s->next;
- return;
- }
-
- SOD(("SOC uses IRQ %d\n", irq))
-
- s->port[0].fc.irq = irq;
- s->port[1].fc.irq = irq;
-
- sprintf (s->port[0].fc.name, "soc%d port A", no);
- sprintf (s->port[1].fc.name, "soc%d port B", no);
- s->port[0].flags = SOC_FC_HDR | SOC_PORT_A;
- s->port[1].flags = SOC_FC_HDR | SOC_PORT_B;
- s->port[1].mask = (1 << 11);
-
- s->port[0].fc.hw_enque = soc_hw_enque;
- s->port[1].fc.hw_enque = soc_hw_enque;
-
- soc_download_fw (s);
-
- SOD(("Downloaded firmware\n"))
-
- /* Now setup xram circular queues */
- memset (cq, 0, sizeof(cq));
-
- size = (SOC_CQ_REQ0_SIZE + SOC_CQ_REQ1_SIZE) * sizeof(soc_req);
- s->req_cpu = sbus_alloc_consistent(sdev, size, &s->req_dvma);
- s->req[0].pool = s->req_cpu;
- cq[0].address = s->req_dvma;
- s->req[1].pool = s->req[0].pool + SOC_CQ_REQ0_SIZE;
-
- s->req[0].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_REQ_OFFSET);
- s->req[1].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_REQ_OFFSET + sizeof(soc_hw_cq));
- s->rsp[0].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_RSP_OFFSET);
- s->rsp[1].hw_cq = (soc_hw_cq __iomem *)(s->xram + SOC_CQ_RSP_OFFSET + sizeof(soc_hw_cq));
-
- cq[1].address = cq[0].address + (SOC_CQ_REQ0_SIZE * sizeof(soc_req));
- cq[4].address = 1;
- cq[5].address = 1;
- cq[0].last = SOC_CQ_REQ0_SIZE - 1;
- cq[1].last = SOC_CQ_REQ1_SIZE - 1;
- cq[4].last = SOC_CQ_RSP0_SIZE - 1;
- cq[5].last = SOC_CQ_RSP1_SIZE - 1;
- for (i = 0; i < 8; i++)
- cq[i].seqno = 1;
-
- s->req[0].last = SOC_CQ_REQ0_SIZE - 1;
- s->req[1].last = SOC_CQ_REQ1_SIZE - 1;
- s->rsp[0].last = SOC_CQ_RSP0_SIZE - 1;
- s->rsp[1].last = SOC_CQ_RSP1_SIZE - 1;
-
- s->req[0].seqno = 1;
- s->req[1].seqno = 1;
- s->rsp[0].seqno = 1;
- s->rsp[1].seqno = 1;
-
- xram_copy_to (s->xram + SOC_CQ_REQ_OFFSET, cq, sizeof(cq));
-
- /* Make our sw copy of SOC service parameters */
- xram_copy_from (s->serv_params, s->xram + 0x140, sizeof (s->serv_params));
-
- s->port[0].fc.common_svc = (common_svc_parm *)s->serv_params;
- s->port[0].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20);
- s->port[1].fc.common_svc = (common_svc_parm *)&s->serv_params;
- s->port[1].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20);
-
- soc_enable (s);
-
- SOD(("Enabled SOC\n"))
-}
-
-static int __init soc_probe(void)
-{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev = NULL;
- struct soc *s;
- int cards = 0;
-
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if(!strcmp(sdev->prom_name, "SUNW,soc")) {
- soc_init(sdev, cards);
- cards++;
- }
- }
- }
- if (!cards) return -EIO;
-
- for_each_soc(s)
- if (s->next)
- s->port[1].fc.next = &s->next->port[0].fc;
- fcp_init (&socs->port[0].fc);
- return 0;
-}
-
-static void __exit soc_cleanup(void)
-{
- struct soc *s;
- int irq;
- struct sbus_dev *sdev;
-
- for_each_soc(s) {
- irq = s->port[0].fc.irq;
- free_irq (irq, s);
-
- fcp_release(&(s->port[0].fc), 2);
-
- sdev = s->port[0].fc.dev;
- if (sdev->num_registers == 1) {
- sbus_iounmap(s->xram, 0x10000UL);
- sbus_iounmap(s->regs, 0x10UL);
- } else {
- sbus_iounmap(s->xram, sdev->reg_addrs[1].reg_size);
- sbus_iounmap(s->regs, sdev->reg_addrs[2].reg_size);
- }
- sbus_free_consistent(sdev,
- (SOC_CQ_REQ0_SIZE+SOC_CQ_REQ1_SIZE)*sizeof(soc_req),
- s->req_cpu, s->req_dvma);
- }
-}
-
-module_init(soc_probe);
-module_exit(soc_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/fc4/soc.h b/drivers/fc4/soc.h
deleted file mode 100644
index d38cf5b28ee..00000000000
--- a/drivers/fc4/soc.h
+++ /dev/null
@@ -1,301 +0,0 @@
-/* soc.h: Definitions for Sparc SUNW,soc Fibre Channel Sbus driver.
- *
- * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#ifndef __SOC_H
-#define __SOC_H
-
-#include "fc.h"
-#include "fcp.h"
-#include "fcp_impl.h"
-
-/* Hardware register offsets and constants first {{{ */
-#define CFG 0x00UL /* Config Register */
-#define SAE 0x04UL /* Slave Access Error Register */
-#define CMD 0x08UL /* Command and Status Register */
-#define IMASK 0x0cUL /* Interrupt Mask Register */
-
-/* Config Register */
-#define SOC_CFG_EXT_RAM_BANK_MASK 0x07000000
-#define SOC_CFG_EEPROM_BANK_MASK 0x00030000
-#define SOC_CFG_BURST64_MASK 0x00000700
-#define SOC_CFG_SBUS_PARITY_TEST 0x00000020
-#define SOC_CFG_SBUS_PARITY_CHECK 0x00000010
-#define SOC_CFG_SBUS_ENHANCED 0x00000008
-#define SOC_CFG_BURST_MASK 0x00000007
-/* Bursts */
-#define SOC_CFG_BURST_4 0x00000000
-#define SOC_CFG_BURST_16 0x00000004
-#define SOC_CFG_BURST_32 0x00000005
-#define SOC_CFG_BURST_64 0x00000006
-
-/* Slave Access Error Register */
-#define SOC_SAE_ALIGNMENT 0x00000004
-#define SOC_SAE_UNSUPPORTED 0x00000002
-#define SOC_SAE_PARITY 0x00000001
-
-/* Command & Status Register */
-#define SOC_CMD_RSP_QALL 0x000f0000
-#define SOC_CMD_RSP_Q0 0x00010000
-#define SOC_CMD_RSP_Q1 0x00020000
-#define SOC_CMD_RSP_Q2 0x00040000
-#define SOC_CMD_RSP_Q3 0x00080000
-#define SOC_CMD_REQ_QALL 0x00000f00
-#define SOC_CMD_REQ_Q0 0x00000100
-#define SOC_CMD_REQ_Q1 0x00000200
-#define SOC_CMD_REQ_Q2 0x00000400
-#define SOC_CMD_REQ_Q3 0x00000800
-#define SOC_CMD_SAE 0x00000080
-#define SOC_CMD_INTR_PENDING 0x00000008
-#define SOC_CMD_NON_QUEUED 0x00000004
-#define SOC_CMD_IDLE 0x00000002
-#define SOC_CMD_SOFT_RESET 0x00000001
-
-/* Interrupt Mask Register */
-#define SOC_IMASK_RSP_QALL 0x000f0000
-#define SOC_IMASK_RSP_Q0 0x00010000
-#define SOC_IMASK_RSP_Q1 0x00020000
-#define SOC_IMASK_RSP_Q2 0x00040000
-#define SOC_IMASK_RSP_Q3 0x00080000
-#define SOC_IMASK_REQ_QALL 0x00000f00
-#define SOC_IMASK_REQ_Q0 0x00000100
-#define SOC_IMASK_REQ_Q1 0x00000200
-#define SOC_IMASK_REQ_Q2 0x00000400
-#define SOC_IMASK_REQ_Q3 0x00000800
-#define SOC_IMASK_SAE 0x00000080
-#define SOC_IMASK_NON_QUEUED 0x00000004
-
-#define SOC_INTR(s, cmd) \
- (((cmd & SOC_CMD_RSP_QALL) | ((~cmd) & SOC_CMD_REQ_QALL)) \
- & s->imask)
-
-#define SOC_SETIMASK(s, i) \
-do { (s)->imask = (i); \
- sbus_writel((i), (s)->regs + IMASK); \
-} while(0)
-
-/* XRAM
- *
- * This is a 64KB register area. It accepts only halfword access.
- * That's why here are the following inline functions...
- */
-
-typedef void __iomem *xram_p;
-
-/* Get 32bit number from XRAM */
-static inline u32 xram_get_32(xram_p x)
-{
- return ((sbus_readw(x + 0x00UL) << 16) |
- (sbus_readw(x + 0x02UL)));
-}
-
-/* Like the above, but when we don't care about the high 16 bits */
-static inline u32 xram_get_32low(xram_p x)
-{
- return (u32) sbus_readw(x + 0x02UL);
-}
-
-static inline u16 xram_get_16(xram_p x)
-{
- return sbus_readw(x);
-}
-
-static inline u8 xram_get_8(xram_p x)
-{
- if ((unsigned long)x & 0x1UL) {
- x = x - 1;
- return (u8) sbus_readw(x);
- } else {
- return (u8) (sbus_readw(x) >> 8);
- }
-}
-
-static inline void xram_copy_from(void *p, xram_p x, int len)
-{
- for (len >>= 2; len > 0; len--, x += sizeof(u32)) {
- u32 val, *p32 = p;
-
- val = ((sbus_readw(x + 0x00UL) << 16) |
- (sbus_readw(x + 0x02UL)));
- *p32++ = val;
- p = p32;
- }
-}
-
-static inline void xram_copy_to(xram_p x, void *p, int len)
-{
- for (len >>= 2; len > 0; len--, x += sizeof(u32)) {
- u32 tmp, *p32 = p;
-
- tmp = *p32++;
- p = p32;
- sbus_writew(tmp >> 16, x + 0x00UL);
- sbus_writew(tmp, x + 0x02UL);
- }
-}
-
-static inline void xram_bzero(xram_p x, int len)
-{
- for (len >>= 1; len > 0; len--, x += sizeof(u16))
- sbus_writew(0, x);
-}
-
-/* Circular Queue */
-
-#define SOC_CQ_REQ_OFFSET (0x100 * sizeof(u16))
-#define SOC_CQ_RSP_OFFSET (0x110 * sizeof(u16))
-
-typedef struct {
- u32 address;
- u8 in;
- u8 out;
- u8 last;
- u8 seqno;
-} soc_hw_cq;
-
-#define SOC_PORT_A 0x0000 /* From/To Port A */
-#define SOC_PORT_B 0x0001 /* From/To Port A */
-#define SOC_FC_HDR 0x0002 /* Contains FC Header */
-#define SOC_NORSP 0x0004 /* Don't generate response nor interrupt */
-#define SOC_NOINT 0x0008 /* Generate response but not interrupt */
-#define SOC_XFERRDY 0x0010 /* Generate XFERRDY */
-#define SOC_IGNOREPARAM 0x0020 /* Ignore PARAM field in the FC header */
-#define SOC_COMPLETE 0x0040 /* Command completed */
-#define SOC_UNSOLICITED 0x0080 /* For request this is the packet to establish unsolicited pools, */
- /* for rsp this is unsolicited packet */
-#define SOC_STATUS 0x0100 /* State change (on/off line) */
-
-typedef struct {
- u32 token;
- u16 flags;
- u8 class;
- u8 segcnt;
- u32 bytecnt;
-} soc_hdr;
-
-typedef struct {
- u32 base;
- u32 count;
-} soc_data;
-
-#define SOC_CQTYPE_OUTBOUND 0x01
-#define SOC_CQTYPE_INBOUND 0x02
-#define SOC_CQTYPE_SIMPLE 0x03
-#define SOC_CQTYPE_IO_WRITE 0x04
-#define SOC_CQTYPE_IO_READ 0x05
-#define SOC_CQTYPE_UNSOLICITED 0x06
-#define SOC_CQTYPE_DIAG 0x07
-#define SOC_CQTYPE_OFFLINE 0x08
-#define SOC_CQTYPE_RESPONSE 0x10
-#define SOC_CQTYPE_INLINE 0x20
-
-#define SOC_CQFLAGS_CONT 0x01
-#define SOC_CQFLAGS_FULL 0x02
-#define SOC_CQFLAGS_BADHDR 0x04
-#define SOC_CQFLAGS_BADPKT 0x08
-
-typedef struct {
- soc_hdr shdr;
- soc_data data[3];
- fc_hdr fchdr;
- u8 count;
- u8 type;
- u8 flags;
- u8 seqno;
-} soc_req;
-
-#define SOC_OK 0
-#define SOC_P_RJT 2
-#define SOC_F_RJT 3
-#define SOC_P_BSY 4
-#define SOC_F_BSY 5
-#define SOC_ONLINE 0x10
-#define SOC_OFFLINE 0x11
-#define SOC_TIMEOUT 0x12
-#define SOC_OVERRUN 0x13
-#define SOC_UNKOWN_CQ_TYPE 0x20
-#define SOC_BAD_SEG_CNT 0x21
-#define SOC_MAX_XCHG_EXCEEDED 0x22
-#define SOC_BAD_XID 0x23
-#define SOC_XCHG_BUSY 0x24
-#define SOC_BAD_POOL_ID 0x25
-#define SOC_INSUFFICIENT_CQES 0x26
-#define SOC_ALLOC_FAIL 0x27
-#define SOC_BAD_SID 0x28
-#define SOC_NO_SEG_INIT 0x29
-
-typedef struct {
- soc_hdr shdr;
- u32 status;
- soc_data data;
- u8 xxx1[12];
- fc_hdr fchdr;
- u8 count;
- u8 type;
- u8 flags;
- u8 seqno;
-} soc_rsp;
-
-/* }}} */
-
-/* Now our software structures and constants we use to drive the beast {{{ */
-
-#define SOC_CQ_REQ0_SIZE 4
-#define SOC_CQ_REQ1_SIZE 64
-#define SOC_CQ_RSP0_SIZE 8
-#define SOC_CQ_RSP1_SIZE 4
-
-#define SOC_SOLICITED_RSP_Q 0
-#define SOC_UNSOLICITED_RSP_Q 1
-
-struct soc;
-
-typedef struct {
- /* This must come first */
- fc_channel fc;
- struct soc *s;
- u16 flags;
- u16 mask;
-} soc_port;
-
-typedef struct {
- soc_hw_cq __iomem *hw_cq; /* Related XRAM cq */
- soc_req __iomem *pool;
- u8 in;
- u8 out;
- u8 last;
- u8 seqno;
-} soc_cq_rsp;
-
-typedef struct {
- soc_hw_cq __iomem *hw_cq; /* Related XRAM cq */
- soc_req *pool;
- u8 in;
- u8 out;
- u8 last;
- u8 seqno;
-} soc_cq_req;
-
-struct soc {
- spinlock_t lock;
- soc_port port[2]; /* Every SOC has one or two FC ports */
- soc_cq_req req[2]; /* Request CQs */
- soc_cq_rsp rsp[2]; /* Response CQs */
- int soc_no;
- void __iomem *regs;
- xram_p xram;
- fc_wwn wwn;
- u32 imask; /* Our copy of regs->imask */
- u32 cfg; /* Our copy of regs->cfg */
- char serv_params[80];
- struct soc *next;
- int curr_port; /* Which port will have priority to fcp_queue_empty */
-
- soc_req *req_cpu;
- u32 req_dvma;
-};
-
-/* }}} */
-
-#endif /* !(__SOC_H) */
diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c
deleted file mode 100644
index c903ebfab52..00000000000
--- a/drivers/fc4/socal.c
+++ /dev/null
@@ -1,904 +0,0 @@
-/* socal.c: Sparc SUNW,socal (SOC+) Fibre Channel Sbus adapter support.
- *
- * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
- *
- * Sources:
- * Fibre Channel Physical & Signaling Interface (FC-PH), dpANS, 1994
- * dpANS Fibre Channel Protocol for SCSI (X3.269-199X), Rev. 012, 1995
- * SOC+ Programming Guide 0.1
- * Fibre Channel Arbitrated Loop (FC-AL), dpANS rev. 4.5, 1995
- *
- * Supported hardware:
- * On-board SOC+ adapters of Ultra Enterprise servers and sun4d.
- */
-
-static char *version =
- "socal.c: SOC+ driver v1.1 9/Feb/99 Jakub Jelinek (jj@ultra.linux.cz)\n";
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/errno.h>
-#include <asm/byteorder.h>
-
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-
-/* #define SOCALDEBUG */
-/* #define HAVE_SOCAL_UCODE */
-/* #define USE_64BIT_MODE */
-
-#include "fcp_impl.h"
-#include "socal.h"
-#ifdef HAVE_SOCAL_UCODE
-#include "socal_asm.h"
-#endif
-
-#define socal_printk printk ("socal%d: ", s->socal_no); printk
-
-#ifdef SOCALDEBUG
-#define SOD(x) socal_printk x;
-#else
-#define SOD(x)
-#endif
-
-#define for_each_socal(s) for (s = socals; s; s = s->next)
-struct socal *socals = NULL;
-
-static void socal_copy_from_xram(void *d, void __iomem *xram, long size)
-{
- u32 *dp = (u32 *) d;
- while (size) {
- *dp++ = sbus_readl(xram);
- xram += sizeof(u32);
- size -= sizeof(u32);
- }
-}
-
-static void socal_copy_to_xram(void __iomem *xram, void *s, long size)
-{
- u32 *sp = (u32 *) s;
- while (size) {
- u32 val = *sp++;
- sbus_writel(val, xram);
- xram += sizeof(u32);
- size -= sizeof(u32);
- }
-}
-
-#ifdef HAVE_SOCAL_UCODE
-static void socal_bzero(unsigned long xram, int size)
-{
- while (size) {
- sbus_writel(0, xram);
- xram += sizeof(u32);
- size -= sizeof(u32);
- }
-}
-#endif
-
-static inline void socal_disable(struct socal *s)
-{
- sbus_writel(0, s->regs + IMASK);
- sbus_writel(SOCAL_CMD_SOFT_RESET, s->regs + CMD);
-}
-
-static inline void socal_enable(struct socal *s)
-{
- SOD(("enable %08x\n", s->cfg))
- sbus_writel(0, s->regs + SAE);
- sbus_writel(s->cfg, s->regs + CFG);
- sbus_writel(SOCAL_CMD_RSP_QALL, s->regs + CMD);
- SOCAL_SETIMASK(s, SOCAL_IMASK_RSP_QALL | SOCAL_IMASK_SAE);
- SOD(("imask %08x %08x\n", s->imask, sbus_readl(s->regs + IMASK)));
-}
-
-static void socal_reset(fc_channel *fc)
-{
- socal_port *port = (socal_port *)fc;
- struct socal *s = port->s;
-
- /* FIXME */
- socal_disable(s);
- s->req[0].seqno = 1;
- s->req[1].seqno = 1;
- s->rsp[0].seqno = 1;
- s->rsp[1].seqno = 1;
- s->req[0].in = 0;
- s->req[1].in = 0;
- s->rsp[0].in = 0;
- s->rsp[1].in = 0;
- s->req[0].out = 0;
- s->req[1].out = 0;
- s->rsp[0].out = 0;
- s->rsp[1].out = 0;
-
- /* FIXME */
- socal_enable(s);
-}
-
-static inline void socal_solicited(struct socal *s, unsigned long qno)
-{
- socal_rsp *hwrsp;
- socal_cq *sw_cq;
- int token;
- int status;
- fc_channel *fc;
-
- sw_cq = &s->rsp[qno];
-
- /* Finally an improvement against old SOC :) */
- sw_cq->in = sbus_readb(s->regs + RESP + qno);
- SOD (("socal_solicited, %d packets arrived\n",
- (sw_cq->in - sw_cq->out) & sw_cq->last))
- for (;;) {
- hwrsp = (socal_rsp *)sw_cq->pool + sw_cq->out;
- SOD(("hwrsp %p out %d\n", hwrsp, sw_cq->out))
-
-#if defined(SOCALDEBUG) && 0
- {
- u32 *u = (u32 *)hwrsp;
- SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n",
- u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7]))
- u += 8;
- SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n",
- u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7]))
- u = (u32 *)s->xram;
- while (u < ((u32 *)s->regs)) {
- if (sbus_readl(&u[0]) == 0x00003000 ||
- sbus_readl(&u[0]) == 0x00003801) {
- SOD(("Found at %04lx\n",
- (unsigned long)u - (unsigned long)s->xram))
- SOD((" %08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n",
- sbus_readl(&u[0]), sbus_readl(&u[1]),
- sbus_readl(&u[2]), sbus_readl(&u[3]),
- sbus_readl(&u[4]), sbus_readl(&u[5]),
- sbus_readl(&u[6]), sbus_readl(&u[7])))
- u += 8;
- SOD((" %08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n",
- sbus_readl(&u[0]), sbus_readl(&u[1]),
- sbus_readl(&u[2]), sbus_readl(&u[3]),
- sbus_readl(&u[4]), sbus_readl(&u[5]),
- sbus_readl(&u[6]), sbus_readl(&u[7])))
- u -= 8;
- }
- u++;
- }
- }
-#endif
-
- token = hwrsp->shdr.token;
- status = hwrsp->status;
- fc = (fc_channel *)(&s->port[(token >> 11) & 1]);
-
- SOD(("Solicited token %08x status %08x\n", token, status))
- if (status == SOCAL_OK) {
- fcp_receive_solicited(fc, token >> 12,
- token & ((1 << 11) - 1),
- FC_STATUS_OK, NULL);
- } else {
- /* We have intentionally defined FC_STATUS_* constants
- * to match SOCAL_* constants, otherwise we'd have to
- * translate status.
- */
- fcp_receive_solicited(fc, token >> 12,
- token & ((1 << 11) - 1), status, &hwrsp->fchdr);
- }
-
- if (++sw_cq->out > sw_cq->last) {
- sw_cq->seqno++;
- sw_cq->out = 0;
- }
-
- if (sw_cq->out == sw_cq->in) {
- sw_cq->in = sbus_readb(s->regs + RESP + qno);
- if (sw_cq->out == sw_cq->in) {
- /* Tell the hardware about it */
- sbus_writel((sw_cq->out << 24) |
- (SOCAL_CMD_RSP_QALL &
- ~(SOCAL_CMD_RSP_Q0 << qno)),
- s->regs + CMD);
-
- /* Read it, so that we're sure it has been updated */
- sbus_readl(s->regs + CMD);
- sw_cq->in = sbus_readb(s->regs + RESP + qno);
- if (sw_cq->out == sw_cq->in)
- break;
- }
- }
- }
-}
-
-static inline void socal_request (struct socal *s, u32 cmd)
-{
- SOCAL_SETIMASK(s, s->imask & ~(cmd & SOCAL_CMD_REQ_QALL));
- SOD(("imask %08x %08x\n", s->imask, sbus_readl(s->regs + IMASK)));
-
- SOD(("Queues available %08x OUT %X\n", cmd, s->regs->reqpr[0]))
- if (s->port[s->curr_port].fc.state != FC_STATE_OFFLINE) {
- fcp_queue_empty ((fc_channel *)&(s->port[s->curr_port]));
- if (((s->req[1].in + 1) & s->req[1].last) != (s->req[1].out))
- fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port]));
- } else {
- fcp_queue_empty ((fc_channel *)&(s->port[1 - s->curr_port]));
- }
- if (s->port[1 - s->curr_port].fc.state != FC_STATE_OFFLINE)
- s->curr_port ^= 1;
-}
-
-static inline void socal_unsolicited (struct socal *s, unsigned long qno)
-{
- socal_rsp *hwrsp, *hwrspc;
- socal_cq *sw_cq;
- int count;
- int status;
- int flags;
- fc_channel *fc;
-
- sw_cq = &s->rsp[qno];
-
- sw_cq->in = sbus_readb(s->regs + RESP + qno);
- SOD (("socal_unsolicited, %d packets arrived, in %d\n",
- (sw_cq->in - sw_cq->out) & sw_cq->last, sw_cq->in))
- while (sw_cq->in != sw_cq->out) {
- /* ...real work per entry here... */
- hwrsp = (socal_rsp *)sw_cq->pool + sw_cq->out;
- SOD(("hwrsp %p out %d\n", hwrsp, sw_cq->out))
-
-#if defined(SOCALDEBUG) && 0
- {
- u32 *u = (u32 *)hwrsp;
- SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n",
- u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7]))
- u += 8;
- SOD(("%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x\n",
- u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7]))
- }
-#endif
-
- hwrspc = NULL;
- flags = hwrsp->shdr.flags;
- count = hwrsp->count;
- fc = (fc_channel *)&s->port[flags & SOCAL_PORT_B];
- SOD(("FC %08lx\n", (long)fc))
-
- if (count != 1) {
- /* Ugh, continuation entries */
- u8 in;
-
- if (count != 2) {
- printk("%s: Too many continuations entries %d\n",
- fc->name, count);
- goto update_out;
- }
-
- in = sw_cq->in;
- if (in < sw_cq->out)
- in += sw_cq->last + 1;
- if (in < sw_cq->out + 2) {
- /* Ask the hardware if they haven't arrived yet. */
- sbus_writel((sw_cq->out << 24) |
- (SOCAL_CMD_RSP_QALL &
- ~(SOCAL_CMD_RSP_Q0 << qno)),
- s->regs + CMD);
-
- /* Read it, so that we're sure it has been updated */
- sbus_readl(s->regs + CMD);
- sw_cq->in = sbus_readb(s->regs + RESP + qno);
- in = sw_cq->in;
- if (in < sw_cq->out)
- in += sw_cq->last + 1;
- if (in < sw_cq->out + 2) /* Nothing came, let us wait */
- return;
- }
- if (sw_cq->out == sw_cq->last)
- hwrspc = (socal_rsp *)sw_cq->pool;
- else
- hwrspc = hwrsp + 1;
- }
-
- switch (flags & ~SOCAL_PORT_B) {
- case SOCAL_STATUS:
- status = hwrsp->status;
- switch (status) {
- case SOCAL_ONLINE:
- SOD(("State change to ONLINE\n"));
- fcp_state_change(fc, FC_STATE_ONLINE);
- break;
- case SOCAL_ONLINE_LOOP:
- SOD(("State change to ONLINE_LOOP\n"));
- fcp_state_change(fc, FC_STATE_ONLINE);
- break;
- case SOCAL_OFFLINE:
- SOD(("State change to OFFLINE\n"));
- fcp_state_change(fc, FC_STATE_OFFLINE);
- break;
- default:
- printk ("%s: Unknown STATUS no %d\n",
- fc->name, status);
- break;
- };
-
- break;
- case (SOCAL_UNSOLICITED|SOCAL_FC_HDR):
- {
- int r_ctl = *((u8 *)&hwrsp->fchdr);
- unsigned len;
-
- if ((r_ctl & 0xf0) == R_CTL_EXTENDED_SVC) {
- len = hwrsp->shdr.bytecnt;
- if (len < 4 || !hwrspc) {
- printk ("%s: Invalid R_CTL %02x "
- "continuation entries\n",
- fc->name, r_ctl);
- } else {
- if (len > 60)
- len = 60;
- if (*(u32 *)hwrspc == LS_DISPLAY) {
- int i;
-
- for (i = 4; i < len; i++)
- if (((u8 *)hwrspc)[i] == '\n')
- ((u8 *)hwrspc)[i] = ' ';
- ((u8 *)hwrspc)[len] = 0;
- printk ("%s message: %s\n",
- fc->name, ((u8 *)hwrspc) + 4);
- } else {
- printk ("%s: Unknown LS_CMD "
- "%08x\n", fc->name,
- *(u32 *)hwrspc);
- }
- }
- } else {
- printk ("%s: Unsolicited R_CTL %02x "
- "not handled\n", fc->name, r_ctl);
- }
- }
- break;
- default:
- printk ("%s: Unexpected flags %08x\n", fc->name, flags);
- break;
- };
-update_out:
- if (++sw_cq->out > sw_cq->last) {
- sw_cq->seqno++;
- sw_cq->out = 0;
- }
-
- if (hwrspc) {
- if (++sw_cq->out > sw_cq->last) {
- sw_cq->seqno++;
- sw_cq->out = 0;
- }
- }
-
- if (sw_cq->out == sw_cq->in) {
- sw_cq->in = sbus_readb(s->regs + RESP + qno);
- if (sw_cq->out == sw_cq->in) {
- /* Tell the hardware about it */
- sbus_writel((sw_cq->out << 24) |
- (SOCAL_CMD_RSP_QALL &
- ~(SOCAL_CMD_RSP_Q0 << qno)),
- s->regs + CMD);
-
- /* Read it, so that we're sure it has been updated */
- sbus_readl(s->regs + CMD);
- sw_cq->in = sbus_readb(s->regs + RESP + qno);
- }
- }
- }
-}
-
-static irqreturn_t socal_intr(int irq, void *dev_id)
-{
- u32 cmd;
- unsigned long flags;
- register struct socal *s = (struct socal *)dev_id;
-
- spin_lock_irqsave(&s->lock, flags);
- cmd = sbus_readl(s->regs + CMD);
- for (; (cmd = SOCAL_INTR (s, cmd)); cmd = sbus_readl(s->regs + CMD)) {
-#ifdef SOCALDEBUG
- static int cnt = 0;
- if (cnt++ < 50)
- printk("soc_intr %08x\n", cmd);
-#endif
- if (cmd & SOCAL_CMD_RSP_Q2)
- socal_unsolicited (s, SOCAL_UNSOLICITED_RSP_Q);
- if (cmd & SOCAL_CMD_RSP_Q1)
- socal_unsolicited (s, SOCAL_SOLICITED_BAD_RSP_Q);
- if (cmd & SOCAL_CMD_RSP_Q0)
- socal_solicited (s, SOCAL_SOLICITED_RSP_Q);
- if (cmd & SOCAL_CMD_REQ_QALL)
- socal_request (s, cmd);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-
- return IRQ_HANDLED;
-}
-
-#define TOKEN(proto, port, token) (((proto)<<12)|(token)|(port))
-
-static int socal_hw_enque (fc_channel *fc, fcp_cmnd *fcmd)
-{
- socal_port *port = (socal_port *)fc;
- struct socal *s = port->s;
- unsigned long qno;
- socal_cq *sw_cq;
- int cq_next_in;
- socal_req *request;
- fc_hdr *fch;
- int i;
-
- if (fcmd->proto == TYPE_SCSI_FCP)
- qno = 1;
- else
- qno = 0;
- SOD(("Putting a FCP packet type %d into hw queue %d\n", fcmd->proto, qno))
- if (s->imask & (SOCAL_IMASK_REQ_Q0 << qno)) {
- SOD(("EIO %08x\n", s->imask))
- return -EIO;
- }
- sw_cq = s->req + qno;
- cq_next_in = (sw_cq->in + 1) & sw_cq->last;
-
- if (cq_next_in == sw_cq->out &&
- cq_next_in == (sw_cq->out = sbus_readb(s->regs + REQP + qno))) {
- SOD(("%d IN %d OUT %d LAST %d\n",
- qno, sw_cq->in,
- sw_cq->out, sw_cq->last))
- SOCAL_SETIMASK(s, s->imask | (SOCAL_IMASK_REQ_Q0 << qno));
- SOD(("imask %08x %08x\n", s->imask, sbus_readl(s->regs + IMASK)));
-
- /* If queue is full, just say NO. */
- return -EBUSY;
- }
-
- request = sw_cq->pool + sw_cq->in;
- fch = &request->fchdr;
-
- switch (fcmd->proto) {
- case TYPE_SCSI_FCP:
- request->shdr.token = TOKEN(TYPE_SCSI_FCP, port->mask, fcmd->token);
- request->data[0].base = fc->dma_scsi_cmd + fcmd->token * sizeof(fcp_cmd);
- request->data[0].count = sizeof(fcp_cmd);
- request->data[1].base = fc->dma_scsi_rsp + fcmd->token * fc->rsp_size;
- request->data[1].count = fc->rsp_size;
- if (fcmd->data) {
- request->shdr.segcnt = 3;
- i = fc->scsi_cmd_pool[fcmd->token].fcp_data_len;
- request->shdr.bytecnt = i;
- request->data[2].base = fcmd->data;
- request->data[2].count = i;
- request->type = (fc->scsi_cmd_pool[fcmd->token].fcp_cntl & FCP_CNTL_WRITE) ?
- SOCAL_CQTYPE_IO_WRITE : SOCAL_CQTYPE_IO_READ;
- } else {
- request->shdr.segcnt = 2;
- request->shdr.bytecnt = 0;
- request->data[2].base = 0;
- request->data[2].count = 0;
- request->type = SOCAL_CQTYPE_SIMPLE;
- }
- FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fcmd->did);
- FILL_FCHDR_SID(fch, fc->sid);
- FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE);
- FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0);
- FILL_FCHDR_OXRX(fch, 0xffff, 0xffff);
- fch->param = 0;
- request->shdr.flags = port->flags;
- request->shdr.class = fc->posmap ? 3 : 2;
- break;
-
- case PROTO_OFFLINE:
- memset (request, 0, sizeof(*request));
- request->shdr.token = TOKEN(PROTO_OFFLINE, port->mask, fcmd->token);
- request->type = SOCAL_CQTYPE_OFFLINE;
- FILL_FCHDR_RCTL_DID(fch, R_CTL_COMMAND, fcmd->did);
- FILL_FCHDR_SID(fch, fc->sid);
- FILL_FCHDR_TYPE_FCTL(fch, TYPE_SCSI_FCP, F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE);
- FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0);
- FILL_FCHDR_OXRX(fch, 0xffff, 0xffff);
- request->shdr.flags = port->flags;
- break;
-
- case PROTO_REPORT_AL_MAP:
- memset (request, 0, sizeof(*request));
- request->shdr.token = TOKEN(PROTO_REPORT_AL_MAP, port->mask, fcmd->token);
- request->type = SOCAL_CQTYPE_REPORT_MAP;
- request->shdr.flags = port->flags;
- request->shdr.segcnt = 1;
- request->shdr.bytecnt = sizeof(fc_al_posmap);
- request->data[0].base = fcmd->cmd;
- request->data[0].count = sizeof(fc_al_posmap);
- break;
-
- default:
- request->shdr.token = TOKEN(fcmd->proto, port->mask, fcmd->token);
- request->shdr.class = fc->posmap ? 3 : 2;
- request->shdr.flags = port->flags;
- memcpy (fch, &fcmd->fch, sizeof(fc_hdr));
- request->data[0].count = fcmd->cmdlen;
- request->data[1].count = fcmd->rsplen;
- request->type = fcmd->class;
- switch (fcmd->class) {
- case FC_CLASS_OUTBOUND:
- request->data[0].base = fcmd->cmd;
- request->data[0].count = fcmd->cmdlen;
- request->type = SOCAL_CQTYPE_OUTBOUND;
- request->shdr.bytecnt = fcmd->cmdlen;
- request->shdr.segcnt = 1;
- break;
- case FC_CLASS_INBOUND:
- request->data[0].base = fcmd->rsp;
- request->data[0].count = fcmd->rsplen;
- request->type = SOCAL_CQTYPE_INBOUND;
- request->shdr.bytecnt = 0;
- request->shdr.segcnt = 1;
- break;
- case FC_CLASS_SIMPLE:
- request->data[0].base = fcmd->cmd;
- request->data[1].base = fcmd->rsp;
- request->data[0].count = fcmd->cmdlen;
- request->data[1].count = fcmd->rsplen;
- request->type = SOCAL_CQTYPE_SIMPLE;
- request->shdr.bytecnt = fcmd->cmdlen;
- request->shdr.segcnt = 2;
- break;
- case FC_CLASS_IO_READ:
- case FC_CLASS_IO_WRITE:
- request->data[0].base = fcmd->cmd;
- request->data[1].base = fcmd->rsp;
- request->data[0].count = fcmd->cmdlen;
- request->data[1].count = fcmd->rsplen;
- request->type = (fcmd->class == FC_CLASS_IO_READ) ? SOCAL_CQTYPE_IO_READ : SOCAL_CQTYPE_IO_WRITE;
- if (fcmd->data) {
- request->data[2].base = fcmd->data;
- request->data[2].count = fcmd->datalen;
- request->shdr.bytecnt = fcmd->datalen;
- request->shdr.segcnt = 3;
- } else {
- request->shdr.bytecnt = 0;
- request->shdr.segcnt = 2;
- }
- break;
- }
- break;
- }
-
- request->count = 1;
- request->flags = 0;
- request->seqno = sw_cq->seqno;
-
- SOD(("queueing token %08x\n", request->shdr.token))
-
- /* And now tell the SOCAL about it */
-
- if (++sw_cq->in > sw_cq->last) {
- sw_cq->in = 0;
- sw_cq->seqno++;
- }
-
- SOD(("Putting %08x into cmd\n", SOCAL_CMD_RSP_QALL | (sw_cq->in << 24) | (SOCAL_CMD_REQ_Q0 << qno)))
-
- sbus_writel(SOCAL_CMD_RSP_QALL | (sw_cq->in << 24) | (SOCAL_CMD_REQ_Q0 << qno),
- s->regs + CMD);
-
- /* Read so that command is completed */
- sbus_readl(s->regs + CMD);
-
- return 0;
-}
-
-static inline void socal_download_fw(struct socal *s)
-{
-#ifdef HAVE_SOCAL_UCODE
- SOD(("Loading %ld bytes from %p to %p\n", sizeof(socal_ucode), socal_ucode, s->xram))
- socal_copy_to_xram(s->xram, socal_ucode, sizeof(socal_ucode));
- SOD(("Clearing the rest of memory\n"))
- socal_bzero (s->xram + sizeof(socal_ucode), 65536 - sizeof(socal_ucode));
- SOD(("Done\n"))
-#endif
-}
-
-/* Check for what the best SBUS burst we can use happens
- * to be on this machine.
- */
-static inline void socal_init_bursts(struct socal *s, struct sbus_dev *sdev)
-{
- int bsizes, bsizes_more;
- u32 cfg;
-
- bsizes = (prom_getintdefault(sdev->prom_node,"burst-sizes",0xff) & 0xff);
- bsizes_more = (prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff) & 0xff);
- bsizes &= bsizes_more;
-#ifdef USE_64BIT_MODE
-#ifdef __sparc_v9__
- mmu_set_sbus64(sdev, bsizes >> 16);
-#endif
-#endif
- if ((bsizes & 0x7f) == 0x7f)
- cfg = SOCAL_CFG_BURST_64;
- else if ((bsizes & 0x3f) == 0x3f)
- cfg = SOCAL_CFG_BURST_32;
- else if ((bsizes & 0x1f) == 0x1f)
- cfg = SOCAL_CFG_BURST_16;
- else
- cfg = SOCAL_CFG_BURST_4;
-#ifdef USE_64BIT_MODE
-#ifdef __sparc_v9__
- /* What is BURST_128? -jj */
- if ((bsizes & 0x780000) == 0x780000)
- cfg |= (SOCAL_CFG_BURST_64 << 8) | SOCAL_CFG_SBUS_ENHANCED;
- else if ((bsizes & 0x380000) == 0x380000)
- cfg |= (SOCAL_CFG_BURST_32 << 8) | SOCAL_CFG_SBUS_ENHANCED;
- else if ((bsizes & 0x180000) == 0x180000)
- cfg |= (SOCAL_CFG_BURST_16 << 8) | SOCAL_CFG_SBUS_ENHANCED;
- else
- cfg |= (SOCAL_CFG_BURST_8 << 8) | SOCAL_CFG_SBUS_ENHANCED;
-#endif
-#endif
- s->cfg = cfg;
-}
-
-static inline void socal_init(struct sbus_dev *sdev, int no)
-{
- unsigned char tmp[60];
- int propl;
- struct socal *s;
- static unsigned version_printed = 0;
- socal_hw_cq cq[8];
- int size, i;
- int irq, node;
-
- s = kzalloc (sizeof (struct socal), GFP_KERNEL);
- if (!s) return;
- spin_lock_init(&s->lock);
- s->socal_no = no;
-
- SOD(("socals %08lx socal_intr %08lx socal_hw_enque %08lx\n",
- (long)socals, (long)socal_intr, (long)socal_hw_enque))
- if (version_printed++ == 0)
- printk (version);
-
- s->port[0].fc.module = THIS_MODULE;
- s->port[1].fc.module = THIS_MODULE;
-
- s->next = socals;
- socals = s;
- s->port[0].fc.dev = sdev;
- s->port[1].fc.dev = sdev;
- s->port[0].s = s;
- s->port[1].s = s;
-
- s->port[0].fc.next = &s->port[1].fc;
-
- /* World Wide Name of SOCAL */
- propl = prom_getproperty (sdev->prom_node, "wwn", tmp, sizeof(tmp));
- if (propl != sizeof (fc_wwn)) {
- s->wwn.naaid = NAAID_IEEE_REG;
- s->wwn.nportid = 0x123;
- s->wwn.hi = 0x1234;
- s->wwn.lo = 0x12345678;
- } else
- memcpy (&s->wwn, tmp, sizeof (fc_wwn));
-
- memcpy (&s->port[0].fc.wwn_nport, &s->wwn, sizeof (fc_wwn));
- s->port[0].fc.wwn_nport.lo++;
- memcpy (&s->port[1].fc.wwn_nport, &s->wwn, sizeof (fc_wwn));
- s->port[1].fc.wwn_nport.lo+=2;
-
- node = prom_getchild (sdev->prom_node);
- while (node && (node = prom_searchsiblings (node, "sf"))) {
- int port;
-
- port = prom_getintdefault(node, "port#", -1);
- switch (port) {
- case 0:
- case 1:
- if (prom_getproplen(node, "port-wwn") == sizeof (fc_wwn))
- prom_getproperty (node, "port-wwn",
- (char *)&s->port[port].fc.wwn_nport,
- sizeof (fc_wwn));
- break;
- default:
- break;
- };
-
- node = prom_getsibling(node);
- }
-
- memcpy (&s->port[0].fc.wwn_node, &s->wwn, sizeof (fc_wwn));
- memcpy (&s->port[1].fc.wwn_node, &s->wwn, sizeof (fc_wwn));
- SOD(("Got wwns %08x%08x ports %08x%08x and %08x%08x\n",
- *(u32 *)&s->port[0].fc.wwn_node, s->port[0].fc.wwn_node.lo,
- *(u32 *)&s->port[0].fc.wwn_nport, s->port[0].fc.wwn_nport.lo,
- *(u32 *)&s->port[1].fc.wwn_nport, s->port[1].fc.wwn_nport.lo))
-
- s->port[0].fc.sid = 1;
- s->port[1].fc.sid = 17;
- s->port[0].fc.did = 2;
- s->port[1].fc.did = 18;
-
- s->port[0].fc.reset = socal_reset;
- s->port[1].fc.reset = socal_reset;
-
- if (sdev->num_registers == 1) {
- s->eeprom = sbus_ioremap(&sdev->resource[0], 0,
- sdev->reg_addrs[0].reg_size, "socal xram");
- if (sdev->reg_addrs[0].reg_size > 0x20000)
- s->xram = s->eeprom + 0x10000UL;
- else
- s->xram = s->eeprom;
- s->regs = (s->xram + 0x10000UL);
- } else {
- /* E.g. starfire presents 3 registers for SOCAL */
- s->xram = sbus_ioremap(&sdev->resource[1], 0,
- sdev->reg_addrs[1].reg_size, "socal xram");
- s->regs = sbus_ioremap(&sdev->resource[2], 0,
- sdev->reg_addrs[2].reg_size, "socal regs");
- }
-
- socal_init_bursts(s, sdev);
-
- SOD(("Disabling SOCAL\n"))
-
- socal_disable (s);
-
- irq = sdev->irqs[0];
-
- if (request_irq (irq, socal_intr, IRQF_SHARED, "SOCAL", (void *)s)) {
- socal_printk ("Cannot order irq %d to go\n", irq);
- socals = s->next;
- return;
- }
-
- SOD(("SOCAL uses IRQ %d\n", irq))
-
- s->port[0].fc.irq = irq;
- s->port[1].fc.irq = irq;
-
- sprintf (s->port[0].fc.name, "socal%d port A", no);
- sprintf (s->port[1].fc.name, "socal%d port B", no);
- s->port[0].flags = SOCAL_FC_HDR | SOCAL_PORT_A;
- s->port[1].flags = SOCAL_FC_HDR | SOCAL_PORT_B;
- s->port[1].mask = (1 << 11);
-
- s->port[0].fc.hw_enque = socal_hw_enque;
- s->port[1].fc.hw_enque = socal_hw_enque;
-
- socal_download_fw (s);
-
- SOD(("Downloaded firmware\n"))
-
- /* Now setup xram circular queues */
- memset (cq, 0, sizeof(cq));
-
- size = (SOCAL_CQ_REQ0_SIZE + SOCAL_CQ_REQ1_SIZE +
- SOCAL_CQ_RSP0_SIZE + SOCAL_CQ_RSP1_SIZE +
- SOCAL_CQ_RSP2_SIZE) * sizeof(socal_req);
- s->req_cpu = sbus_alloc_consistent(sdev, size, &s->req_dvma);
- s->req[0].pool = s->req_cpu;
- cq[0].address = s->req_dvma;
- s->req[1].pool = s->req[0].pool + SOCAL_CQ_REQ0_SIZE;
- s->rsp[0].pool = s->req[1].pool + SOCAL_CQ_REQ1_SIZE;
- s->rsp[1].pool = s->rsp[0].pool + SOCAL_CQ_RSP0_SIZE;
- s->rsp[2].pool = s->rsp[1].pool + SOCAL_CQ_RSP1_SIZE;
-
- s->req[0].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_REQ_OFFSET);
- s->req[1].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_REQ_OFFSET + sizeof(socal_hw_cq));
- s->rsp[0].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_RSP_OFFSET);
- s->rsp[1].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_RSP_OFFSET + sizeof(socal_hw_cq));
- s->rsp[2].hw_cq = (socal_hw_cq __iomem *)(s->xram + SOCAL_CQ_RSP_OFFSET + 2 * sizeof(socal_hw_cq));
-
- cq[1].address = cq[0].address + (SOCAL_CQ_REQ0_SIZE * sizeof(socal_req));
- cq[4].address = cq[1].address + (SOCAL_CQ_REQ1_SIZE * sizeof(socal_req));
- cq[5].address = cq[4].address + (SOCAL_CQ_RSP0_SIZE * sizeof(socal_req));
- cq[6].address = cq[5].address + (SOCAL_CQ_RSP1_SIZE * sizeof(socal_req));
-
- cq[0].last = SOCAL_CQ_REQ0_SIZE - 1;
- cq[1].last = SOCAL_CQ_REQ1_SIZE - 1;
- cq[4].last = SOCAL_CQ_RSP0_SIZE - 1;
- cq[5].last = SOCAL_CQ_RSP1_SIZE - 1;
- cq[6].last = SOCAL_CQ_RSP2_SIZE - 1;
- for (i = 0; i < 8; i++)
- cq[i].seqno = 1;
-
- s->req[0].last = SOCAL_CQ_REQ0_SIZE - 1;
- s->req[1].last = SOCAL_CQ_REQ1_SIZE - 1;
- s->rsp[0].last = SOCAL_CQ_RSP0_SIZE - 1;
- s->rsp[1].last = SOCAL_CQ_RSP1_SIZE - 1;
- s->rsp[2].last = SOCAL_CQ_RSP2_SIZE - 1;
-
- s->req[0].seqno = 1;
- s->req[1].seqno = 1;
- s->rsp[0].seqno = 1;
- s->rsp[1].seqno = 1;
- s->rsp[2].seqno = 1;
-
- socal_copy_to_xram(s->xram + SOCAL_CQ_REQ_OFFSET, cq, sizeof(cq));
-
- SOD(("Setting up params\n"))
-
- /* Make our sw copy of SOCAL service parameters */
- socal_copy_from_xram(s->serv_params, s->xram + 0x280, sizeof (s->serv_params));
-
- s->port[0].fc.common_svc = (common_svc_parm *)s->serv_params;
- s->port[0].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20);
- s->port[1].fc.common_svc = (common_svc_parm *)&s->serv_params;
- s->port[1].fc.class_svcs = (svc_parm *)(s->serv_params + 0x20);
-
- socal_enable (s);
-
- SOD(("Enabled SOCAL\n"))
-}
-
-static int __init socal_probe(void)
-{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev = NULL;
- struct socal *s;
- int cards = 0;
-
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if(!strcmp(sdev->prom_name, "SUNW,socal")) {
- socal_init(sdev, cards);
- cards++;
- }
- }
- }
- if (!cards)
- return -EIO;
-
- for_each_socal(s)
- if (s->next)
- s->port[1].fc.next = &s->next->port[0].fc;
-
- fcp_init (&socals->port[0].fc);
- return 0;
-}
-
-static void __exit socal_cleanup(void)
-{
- struct socal *s;
- int irq;
- struct sbus_dev *sdev;
-
- for_each_socal(s) {
- irq = s->port[0].fc.irq;
- free_irq (irq, s);
-
- fcp_release(&(s->port[0].fc), 2);
-
- sdev = s->port[0].fc.dev;
- if (sdev->num_registers == 1) {
- sbus_iounmap(s->eeprom, sdev->reg_addrs[0].reg_size);
- } else {
- sbus_iounmap(s->xram, sdev->reg_addrs[1].reg_size);
- sbus_iounmap(s->regs, sdev->reg_addrs[2].reg_size);
- }
- sbus_free_consistent(sdev,
- (SOCAL_CQ_REQ0_SIZE + SOCAL_CQ_REQ1_SIZE +
- SOCAL_CQ_RSP0_SIZE + SOCAL_CQ_RSP1_SIZE +
- SOCAL_CQ_RSP2_SIZE) * sizeof(socal_req),
- s->req_cpu, s->req_dvma);
- }
-}
-
-module_init(socal_probe);
-module_exit(socal_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/fc4/socal.h b/drivers/fc4/socal.h
deleted file mode 100644
index 774edf68e4d..00000000000
--- a/drivers/fc4/socal.h
+++ /dev/null
@@ -1,314 +0,0 @@
-/* socal.h: Definitions for Sparc SUNW,socal (SOC+) Fibre Channel Sbus driver.
- *
- * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
- */
-
-#ifndef __SOCAL_H
-#define __SOCAL_H
-
-#include "fc.h"
-#include "fcp.h"
-#include "fcp_impl.h"
-
-/* Hardware register offsets and constants first {{{ */
-#define CFG 0x00UL
-#define SAE 0x04UL
-#define CMD 0x08UL
-#define IMASK 0x0cUL
-#define REQP 0x10UL
-#define RESP 0x14UL
-
-/* Config Register */
-#define SOCAL_CFG_EXT_RAM_BANK_MASK 0x07000000
-#define SOCAL_CFG_EEPROM_BANK_MASK 0x00030000
-#define SOCAL_CFG_BURST64_MASK 0x00000700
-#define SOCAL_CFG_SBUS_PARITY_TEST 0x00000020
-#define SOCAL_CFG_SBUS_PARITY_CHECK 0x00000010
-#define SOCAL_CFG_SBUS_ENHANCED 0x00000008
-#define SOCAL_CFG_BURST_MASK 0x00000007
-/* Bursts */
-#define SOCAL_CFG_BURST_4 0x00000000
-#define SOCAL_CFG_BURST_8 0x00000003
-#define SOCAL_CFG_BURST_16 0x00000004
-#define SOCAL_CFG_BURST_32 0x00000005
-#define SOCAL_CFG_BURST_64 0x00000006
-#define SOCAL_CFG_BURST_128 0x00000007
-
-/* Slave Access Error Register */
-#define SOCAL_SAE_ALIGNMENT 0x00000004
-#define SOCAL_SAE_UNSUPPORTED 0x00000002
-#define SOCAL_SAE_PARITY 0x00000001
-
-/* Command & Status Register */
-#define SOCAL_CMD_RSP_QALL 0x000f0000
-#define SOCAL_CMD_RSP_Q0 0x00010000
-#define SOCAL_CMD_RSP_Q1 0x00020000
-#define SOCAL_CMD_RSP_Q2 0x00040000
-#define SOCAL_CMD_RSP_Q3 0x00080000
-#define SOCAL_CMD_REQ_QALL 0x00000f00
-#define SOCAL_CMD_REQ_Q0 0x00000100
-#define SOCAL_CMD_REQ_Q1 0x00000200
-#define SOCAL_CMD_REQ_Q2 0x00000400
-#define SOCAL_CMD_REQ_Q3 0x00000800
-#define SOCAL_CMD_SAE 0x00000080
-#define SOCAL_CMD_INTR_PENDING 0x00000008
-#define SOCAL_CMD_NON_QUEUED 0x00000004
-#define SOCAL_CMD_IDLE 0x00000002
-#define SOCAL_CMD_SOFT_RESET 0x00000001
-
-/* Interrupt Mask Register */
-#define SOCAL_IMASK_RSP_QALL 0x000f0000
-#define SOCAL_IMASK_RSP_Q0 0x00010000
-#define SOCAL_IMASK_RSP_Q1 0x00020000
-#define SOCAL_IMASK_RSP_Q2 0x00040000
-#define SOCAL_IMASK_RSP_Q3 0x00080000
-#define SOCAL_IMASK_REQ_QALL 0x00000f00
-#define SOCAL_IMASK_REQ_Q0 0x00000100
-#define SOCAL_IMASK_REQ_Q1 0x00000200
-#define SOCAL_IMASK_REQ_Q2 0x00000400
-#define SOCAL_IMASK_REQ_Q3 0x00000800
-#define SOCAL_IMASK_SAE 0x00000080
-#define SOCAL_IMASK_NON_QUEUED 0x00000004
-
-#define SOCAL_INTR(s, cmd) \
- (((cmd & SOCAL_CMD_RSP_QALL) | ((~cmd) & SOCAL_CMD_REQ_QALL)) \
- & s->imask)
-
-#define SOCAL_SETIMASK(s, i) \
-do { (s)->imask = (i); \
- sbus_writel((i), (s)->regs + IMASK); \
-} while (0)
-
-#define SOCAL_MAX_EXCHANGES 1024
-
-/* XRAM
- *
- * This is a 64KB register area.
- * From the documentation, it seems like it is finally able to cope
- * at least with 1,2,4 byte accesses for read and 2,4 byte accesses for write.
- */
-
-/* Circular Queue */
-
-#define SOCAL_CQ_REQ_OFFSET 0x200
-#define SOCAL_CQ_RSP_OFFSET 0x220
-
-typedef struct {
- u32 address;
- u8 in;
- u8 out;
- u8 last;
- u8 seqno;
-} socal_hw_cq;
-
-#define SOCAL_PORT_A 0x0000 /* From/To Port A */
-#define SOCAL_PORT_B 0x0001 /* From/To Port A */
-#define SOCAL_FC_HDR 0x0002 /* Contains FC Header */
-#define SOCAL_NORSP 0x0004 /* Don't generate response nor interrupt */
-#define SOCAL_NOINT 0x0008 /* Generate response but not interrupt */
-#define SOCAL_XFERRDY 0x0010 /* Generate XFERRDY */
-#define SOCAL_IGNOREPARAM 0x0020 /* Ignore PARAM field in the FC header */
-#define SOCAL_COMPLETE 0x0040 /* Command completed */
-#define SOCAL_UNSOLICITED 0x0080 /* For request this is the packet to establish unsolicited pools, */
- /* for rsp this is unsolicited packet */
-#define SOCAL_STATUS 0x0100 /* State change (on/off line) */
-#define SOCAL_RSP_HDR 0x0200 /* Return frame header in any case */
-
-typedef struct {
- u32 token;
- u16 flags;
- u8 class;
- u8 segcnt;
- u32 bytecnt;
-} socal_hdr;
-
-typedef struct {
- u32 base;
- u32 count;
-} socal_data;
-
-#define SOCAL_CQTYPE_NOP 0x00
-#define SOCAL_CQTYPE_OUTBOUND 0x01
-#define SOCAL_CQTYPE_INBOUND 0x02
-#define SOCAL_CQTYPE_SIMPLE 0x03
-#define SOCAL_CQTYPE_IO_WRITE 0x04
-#define SOCAL_CQTYPE_IO_READ 0x05
-#define SOCAL_CQTYPE_UNSOLICITED 0x06
-#define SOCAL_CQTYPE_BYPASS_DEV 0x06
-#define SOCAL_CQTYPE_DIAG 0x07
-#define SOCAL_CQTYPE_OFFLINE 0x08
-#define SOCAL_CQTYPE_ADD_POOL 0x09
-#define SOCAL_CQTYPE_DELETE_POOL 0x0a
-#define SOCAL_CQTYPE_ADD_BUFFER 0x0b
-#define SOCAL_CQTYPE_ADD_POOL_BUFFER 0x0c
-#define SOCAL_CQTYPE_REQUEST_ABORT 0x0d
-#define SOCAL_CQTYPE_REQUEST_LIP 0x0e
-#define SOCAL_CQTYPE_REPORT_MAP 0x0f
-#define SOCAL_CQTYPE_RESPONSE 0x10
-#define SOCAL_CQTYPE_INLINE 0x20
-
-#define SOCAL_CQFLAGS_CONT 0x01
-#define SOCAL_CQFLAGS_FULL 0x02
-#define SOCAL_CQFLAGS_BADHDR 0x04
-#define SOCAL_CQFLAGS_BADPKT 0x08
-
-typedef struct {
- socal_hdr shdr;
- socal_data data[3];
- fc_hdr fchdr;
- u8 count;
- u8 type;
- u8 flags;
- u8 seqno;
-} socal_req;
-
-#define SOCAL_OK 0
-#define SOCAL_P_RJT 2
-#define SOCAL_F_RJT 3
-#define SOCAL_P_BSY 4
-#define SOCAL_F_BSY 5
-#define SOCAL_ONLINE 0x10
-#define SOCAL_OFFLINE 0x11
-#define SOCAL_TIMEOUT 0x12
-#define SOCAL_OVERRUN 0x13
-#define SOCAL_ONLINE_LOOP 0x14
-#define SOCAL_OLD_PORT 0x15
-#define SOCAL_AL_PORT 0x16
-#define SOCAL_UNKOWN_CQ_TYPE 0x20
-#define SOCAL_BAD_SEG_CNT 0x21
-#define SOCAL_MAX_XCHG_EXCEEDED 0x22
-#define SOCAL_BAD_XID 0x23
-#define SOCAL_XCHG_BUSY 0x24
-#define SOCAL_BAD_POOL_ID 0x25
-#define SOCAL_INSUFFICIENT_CQES 0x26
-#define SOCAL_ALLOC_FAIL 0x27
-#define SOCAL_BAD_SID 0x28
-#define SOCAL_NO_SEG_INIT 0x29
-#define SOCAL_BAD_DID 0x2a
-#define SOCAL_ABORTED 0x30
-#define SOCAL_ABORT_FAILED 0x31
-
-typedef struct {
- socal_hdr shdr;
- u32 status;
- socal_data data;
- u8 xxx1[10];
- u16 ncmds;
- fc_hdr fchdr;
- u8 count;
- u8 type;
- u8 flags;
- u8 seqno;
-} socal_rsp;
-
-typedef struct {
- socal_hdr shdr;
- u8 xxx1[48];
- u8 count;
- u8 type;
- u8 flags;
- u8 seqno;
-} socal_cmdonly;
-
-#define SOCAL_DIAG_NOP 0x00
-#define SOCAL_DIAG_INT_LOOP 0x01
-#define SOCAL_DIAG_EXT_LOOP 0x02
-#define SOCAL_DIAG_REM_LOOP 0x03
-#define SOCAL_DIAG_XRAM_TEST 0x04
-#define SOCAL_DIAG_SOC_TEST 0x05
-#define SOCAL_DIAG_HCB_TEST 0x06
-#define SOCAL_DIAG_SOCLB_TEST 0x07
-#define SOCAL_DIAG_SRDSLB_TEST 0x08
-#define SOCAL_DIAG_EXTOE_TEST 0x09
-
-typedef struct {
- socal_hdr shdr;
- u32 cmd;
- u8 xxx1[44];
- u8 count;
- u8 type;
- u8 flags;
- u8 seqno;
-} socal_diag_req;
-
-#define SOCAL_POOL_MASK_RCTL 0x800000
-#define SOCAL_POOL_MASK_DID 0x700000
-#define SOCAL_POOL_MASK_SID 0x070000
-#define SOCAL_POOL_MASK_TYPE 0x008000
-#define SOCAL_POOL_MASK_F_CTL 0x007000
-#define SOCAL_POOL_MASK_SEQ_ID 0x000800
-#define SOCAL_POOL_MASK_D_CTL 0x000400
-#define SOCAL_POOL_MASK_SEQ_CNT 0x000300
-#define SOCAL_POOL_MASK_OX_ID 0x0000f0
-#define SOCAL_POOL_MASK_PARAM 0x00000f
-
-typedef struct {
- socal_hdr shdr;
- u32 pool_id;
- u32 header_mask;
- u32 buf_size;
- u32 entries;
- u8 xxx1[8];
- fc_hdr fchdr;
- u8 count;
- u8 type;
- u8 flags;
- u8 seqno;
-} socal_pool_req;
-
-/* }}} */
-
-/* Now our software structures and constants we use to drive the beast {{{ */
-
-#define SOCAL_CQ_REQ0_SIZE 4
-#define SOCAL_CQ_REQ1_SIZE 256
-#define SOCAL_CQ_RSP0_SIZE 8
-#define SOCAL_CQ_RSP1_SIZE 4
-#define SOCAL_CQ_RSP2_SIZE 4
-
-#define SOCAL_SOLICITED_RSP_Q 0
-#define SOCAL_SOLICITED_BAD_RSP_Q 1
-#define SOCAL_UNSOLICITED_RSP_Q 2
-
-struct socal;
-
-typedef struct {
- /* This must come first */
- fc_channel fc;
- struct socal *s;
- u16 flags;
- u16 mask;
-} socal_port;
-
-typedef struct {
- socal_hw_cq __iomem *hw_cq; /* Related XRAM cq */
- socal_req *pool;
- u8 in;
- u8 out;
- u8 last;
- u8 seqno;
-} socal_cq;
-
-struct socal {
- spinlock_t lock;
- socal_port port[2]; /* Every SOCAL has one or two FC ports */
- socal_cq req[4]; /* Request CQs */
- socal_cq rsp[4]; /* Response CQs */
- int socal_no;
- void __iomem *regs;
- void __iomem *xram;
- void __iomem *eeprom;
- fc_wwn wwn;
- u32 imask; /* Our copy of regs->imask */
- u32 cfg; /* Our copy of regs->cfg */
- char serv_params[80];
- struct socal *next;
- int curr_port; /* Which port will have priority to fcp_queue_empty */
-
- socal_req * req_cpu;
- u32 req_dvma;
-};
-
-/* }}} */
-
-#endif /* !(__SOCAL_H) */
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
index 75388641a7d..60f1a8924a9 100644
--- a/drivers/firewire/fw-cdev.c
+++ b/drivers/firewire/fw-cdev.c
@@ -25,11 +25,14 @@
#include <linux/device.h>
#include <linux/vmalloc.h>
#include <linux/poll.h>
+#include <linux/preempt.h>
+#include <linux/time.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/idr.h>
#include <linux/compat.h>
#include <linux/firewire-cdev.h>
+#include <asm/system.h>
#include <asm/uaccess.h>
#include "fw-transaction.h"
#include "fw-topology.h"
@@ -140,11 +143,10 @@ static void queue_event(struct client *client, struct event *event,
event->v[1].size = size1;
spin_lock_irqsave(&client->lock, flags);
-
list_add_tail(&event->link, &client->event_list);
- wake_up_interruptible(&client->wait);
-
spin_unlock_irqrestore(&client->lock, flags);
+
+ wake_up_interruptible(&client->wait);
}
static int
@@ -621,20 +623,19 @@ iso_callback(struct fw_iso_context *context, u32 cycle,
size_t header_length, void *header, void *data)
{
struct client *client = data;
- struct iso_interrupt *interrupt;
+ struct iso_interrupt *irq;
- interrupt = kzalloc(sizeof(*interrupt) + header_length, GFP_ATOMIC);
- if (interrupt == NULL)
+ irq = kzalloc(sizeof(*irq) + header_length, GFP_ATOMIC);
+ if (irq == NULL)
return;
- interrupt->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT;
- interrupt->interrupt.closure = client->iso_closure;
- interrupt->interrupt.cycle = cycle;
- interrupt->interrupt.header_length = header_length;
- memcpy(interrupt->interrupt.header, header, header_length);
- queue_event(client, &interrupt->event,
- &interrupt->interrupt,
- sizeof(interrupt->interrupt) + header_length, NULL, 0);
+ irq->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT;
+ irq->interrupt.closure = client->iso_closure;
+ irq->interrupt.cycle = cycle;
+ irq->interrupt.header_length = header_length;
+ memcpy(irq->interrupt.header, header, header_length);
+ queue_event(client, &irq->event, &irq->interrupt,
+ sizeof(irq->interrupt) + header_length, NULL, 0);
}
static int ioctl_create_iso_context(struct client *client, void *buffer)
@@ -722,10 +723,11 @@ static int ioctl_queue_iso(struct client *client, void *buffer)
buffer_end = 0;
}
- if (!access_ok(VERIFY_READ, request->packets, request->size))
+ p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets);
+
+ if (!access_ok(VERIFY_READ, p, request->size))
return -EFAULT;
- p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets);
end = (void __user *)p + request->size;
count = 0;
while (p < end) {
@@ -811,6 +813,28 @@ static int ioctl_stop_iso(struct client *client, void *buffer)
return fw_iso_context_stop(client->iso_context);
}
+static int ioctl_get_cycle_timer(struct client *client, void *buffer)
+{
+ struct fw_cdev_get_cycle_timer *request = buffer;
+ struct fw_card *card = client->device->card;
+ unsigned long long bus_time;
+ struct timeval tv;
+ unsigned long flags;
+
+ preempt_disable();
+ local_irq_save(flags);
+
+ bus_time = card->driver->get_bus_time(card);
+ do_gettimeofday(&tv);
+
+ local_irq_restore(flags);
+ preempt_enable();
+
+ request->local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;
+ request->cycle_timer = bus_time & 0xffffffff;
+ return 0;
+}
+
static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
ioctl_get_info,
ioctl_send_request,
@@ -824,6 +848,7 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
ioctl_queue_iso,
ioctl_start_iso,
ioctl_stop_iso,
+ ioctl_get_cycle_timer,
};
static int
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index 2b658634163..56681b3b297 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -130,23 +130,16 @@ static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
}
static int
-fw_unit_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct fw_unit *unit = fw_unit(dev);
char modalias[64];
- int length = 0;
- int i = 0;
get_modalias(unit, modalias, sizeof(modalias));
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=%s", modalias))
+ if (add_uevent_var(env, "MODALIAS=%s", modalias))
return -ENOMEM;
- envp[i] = NULL;
-
return 0;
}
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h
index d13e6a69707..894d4a92a18 100644
--- a/drivers/firewire/fw-device.h
+++ b/drivers/firewire/fw-device.h
@@ -102,11 +102,6 @@ fw_unit(struct device *dev)
#define CSR_INSTANCE 0x18
#define CSR_DIRECTORY_ID 0x20
-#define SBP2_COMMAND_SET_SPECIFIER 0x38
-#define SBP2_COMMAND_SET 0x39
-#define SBP2_COMMAND_SET_REVISION 0x3b
-#define SBP2_FIRMWARE_REVISION 0x3c
-
struct fw_csr_iterator {
u32 *p;
u32 *end;
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
index e14c1ca7813..c9b9081831d 100644
--- a/drivers/firewire/fw-ohci.c
+++ b/drivers/firewire/fw-ohci.c
@@ -18,21 +18,23 @@
* 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/interrupt.h>
-#include <linux/pci.h>
+#include <linux/compiler.h>
#include <linux/delay.h>
-#include <linux/poll.h>
#include <linux/dma-mapping.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
-#include <asm/uaccess.h>
-#include <asm/semaphore.h>
+#include <asm/page.h>
+#include <asm/system.h>
-#include "fw-transaction.h"
#include "fw-ohci.h"
+#include "fw-transaction.h"
#define DESCRIPTOR_OUTPUT_MORE 0
#define DESCRIPTOR_OUTPUT_LAST (1 << 12)
@@ -604,7 +606,7 @@ static int
at_context_queue_packet(struct context *ctx, struct fw_packet *packet)
{
struct fw_ohci *ohci = ctx->ohci;
- dma_addr_t d_bus, payload_bus;
+ dma_addr_t d_bus, uninitialized_var(payload_bus);
struct driver_data *driver_data;
struct descriptor *d, *last;
__le32 *header;
@@ -678,6 +680,9 @@ at_context_queue_packet(struct context *ctx, struct fw_packet *packet)
/* FIXME: Document how the locking works. */
if (ohci->generation != packet->generation) {
+ if (packet->payload_length > 0)
+ dma_unmap_single(ohci->card.device, payload_bus,
+ packet->payload_length, DMA_TO_DEVICE);
packet->ack = RCODE_GENERATION;
return -1;
}
@@ -912,10 +917,15 @@ static void bus_reset_tasklet(unsigned long data)
reg = reg_read(ohci, OHCI1394_NodeID);
if (!(reg & OHCI1394_NodeID_idValid)) {
- fw_error("node ID not valid, new bus reset in progress\n");
+ fw_notify("node ID not valid, new bus reset in progress\n");
+ return;
+ }
+ if ((reg & OHCI1394_NodeID_nodeNumber) == 63) {
+ fw_notify("malconfigured bus\n");
return;
}
- ohci->node_id = reg & 0xffff;
+ ohci->node_id = reg & (OHCI1394_NodeID_busNumber |
+ OHCI1394_NodeID_nodeNumber);
/*
* The count in the SelfIDCount register is the number of
@@ -926,12 +936,14 @@ static void bus_reset_tasklet(unsigned long data)
self_id_count = (reg_read(ohci, OHCI1394_SelfIDCount) >> 3) & 0x3ff;
generation = (le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff;
+ rmb();
for (i = 1, j = 0; j < self_id_count; i += 2, j++) {
if (ohci->self_id_cpu[i] != ~ohci->self_id_cpu[i + 1])
fw_error("inconsistent self IDs\n");
ohci->self_id_buffer[j] = le32_to_cpu(ohci->self_id_cpu[i]);
}
+ rmb();
/*
* Check the consistency of the self IDs we just read. The
@@ -972,8 +984,10 @@ static void bus_reset_tasklet(unsigned long data)
*/
if (ohci->next_config_rom != NULL) {
- free_rom = ohci->config_rom;
- free_rom_bus = ohci->config_rom_bus;
+ if (ohci->next_config_rom != ohci->config_rom) {
+ free_rom = ohci->config_rom;
+ free_rom_bus = ohci->config_rom_bus;
+ }
ohci->config_rom = ohci->next_config_rom;
ohci->config_rom_bus = ohci->next_config_rom_bus;
ohci->next_config_rom = NULL;
@@ -1046,6 +1060,9 @@ static irqreturn_t irq_handler(int irq, void *data)
iso_event &= ~(1 << i);
}
+ if (unlikely(event & OHCI1394_postedWriteErr))
+ fw_error("PCI posted write error\n");
+
if (event & OHCI1394_cycle64Seconds) {
cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
if ((cycle_time & 0x80000000) == 0)
@@ -1119,8 +1136,8 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
OHCI1394_RQPkt | OHCI1394_RSPkt |
OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
OHCI1394_isochRx | OHCI1394_isochTx |
- OHCI1394_masterIntEnable |
- OHCI1394_cycle64Seconds);
+ OHCI1394_postedWriteErr | OHCI1394_cycle64Seconds |
+ OHCI1394_masterIntEnable);
/* Activate link_on bit and contender bit in our self ID packets.*/
if (ohci_update_phy_reg(card, 4, 0,
@@ -1146,19 +1163,30 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
* the right values in the bus reset tasklet.
*/
- ohci->next_config_rom =
- dma_alloc_coherent(ohci->card.device, CONFIG_ROM_SIZE,
- &ohci->next_config_rom_bus, GFP_KERNEL);
- if (ohci->next_config_rom == NULL)
- return -ENOMEM;
+ if (config_rom) {
+ ohci->next_config_rom =
+ dma_alloc_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+ &ohci->next_config_rom_bus,
+ GFP_KERNEL);
+ if (ohci->next_config_rom == NULL)
+ return -ENOMEM;
- memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE);
- fw_memcpy_to_be32(ohci->next_config_rom, config_rom, length * 4);
+ memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE);
+ fw_memcpy_to_be32(ohci->next_config_rom, config_rom, length * 4);
+ } else {
+ /*
+ * In the suspend case, config_rom is NULL, which
+ * means that we just reuse the old config rom.
+ */
+ ohci->next_config_rom = ohci->config_rom;
+ ohci->next_config_rom_bus = ohci->config_rom_bus;
+ }
- ohci->next_header = config_rom[0];
+ ohci->next_header = be32_to_cpu(ohci->next_config_rom[0]);
ohci->next_config_rom[0] = 0;
reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
- reg_write(ohci, OHCI1394_BusOptions, config_rom[2]);
+ reg_write(ohci, OHCI1394_BusOptions,
+ be32_to_cpu(ohci->next_config_rom[2]));
reg_write(ohci, OHCI1394_ConfigROMmap, ohci->next_config_rom_bus);
reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
@@ -1444,7 +1472,7 @@ ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
/* FIXME: We need a fallback for pre 1.1 OHCI. */
if (callback == handle_ir_dualbuffer_packet &&
ohci->version < OHCI_VERSION_1_1)
- return ERR_PTR(-EINVAL);
+ return ERR_PTR(-ENOSYS);
spin_lock_irqsave(&ohci->lock, flags);
index = ffs(*mask) - 1;
@@ -1763,7 +1791,7 @@ ohci_queue_iso(struct fw_iso_context *base,
buffer, payload);
else
/* FIXME: Implement fallback for OHCI 1.0 controllers. */
- return -EINVAL;
+ return -ENOSYS;
}
static const struct fw_card_driver ohci_driver = {
@@ -1883,7 +1911,12 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
ohci->version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
dev->dev.bus_id, ohci->version >> 16, ohci->version & 0xff);
-
+ if (ohci->version < OHCI_VERSION_1_1) {
+ fw_notify(" Isochronous I/O is not yet implemented for "
+ "OHCI 1.0 chips.\n");
+ fw_notify(" Cameras, audio devices etc. won't work on "
+ "this controller with this driver version.\n");
+ }
return 0;
fail_self_id:
@@ -1964,7 +1997,7 @@ static int pci_resume(struct pci_dev *pdev)
return err;
}
- return ohci_enable(&ohci->card, ohci->config_rom, CONFIG_ROM_SIZE);
+ return ohci_enable(&ohci->card, NULL, 0);
}
#endif
diff --git a/drivers/firewire/fw-ohci.h b/drivers/firewire/fw-ohci.h
index fa15706397d..dec4f04e6b2 100644
--- a/drivers/firewire/fw-ohci.h
+++ b/drivers/firewire/fw-ohci.h
@@ -59,6 +59,8 @@
#define OHCI1394_LinkControl_cycleSource (1 << 22)
#define OHCI1394_NodeID 0x0E8
#define OHCI1394_NodeID_idValid 0x80000000
+#define OHCI1394_NodeID_nodeNumber 0x0000003f
+#define OHCI1394_NodeID_busNumber 0x0000ffc0
#define OHCI1394_PhyControl 0x0EC
#define OHCI1394_PhyControl_Read(addr) (((addr) << 8) | 0x00008000)
#define OHCI1394_PhyControl_ReadDone 0x80000000
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 238730f75db..624ff3e082f 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -37,11 +37,12 @@
#include <linux/dma-mapping.h>
#include <linux/blkdev.h>
#include <linux/string.h>
+#include <linux/stringify.h>
#include <linux/timer.h>
+#include <linux/workqueue.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_dbg.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
@@ -61,36 +62,94 @@ module_param_named(exclusive_login, sbp2_param_exclusive_login, bool, 0644);
MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
"(default = Y, use N for concurrent initiators)");
+/*
+ * Flags for firmware oddities
+ *
+ * - 128kB max transfer
+ * Limit transfer size. Necessary for some old bridges.
+ *
+ * - 36 byte inquiry
+ * When scsi_mod probes the device, let the inquiry command look like that
+ * from MS Windows.
+ *
+ * - skip mode page 8
+ * Suppress sending of mode_sense for mode page 8 if the device pretends to
+ * support the SCSI Primary Block commands instead of Reduced Block Commands.
+ *
+ * - fix capacity
+ * Tell sd_mod to correct the last sector number reported by read_capacity.
+ * Avoids access beyond actual disk limits on devices with an off-by-one bug.
+ * Don't use this with devices which don't have this bug.
+ *
+ * - override internal blacklist
+ * Instead of adding to the built-in blacklist, use only the workarounds
+ * specified in the module load parameter.
+ * Useful if a blacklist entry interfered with a non-broken device.
+ */
+#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
+#define SBP2_WORKAROUND_INQUIRY_36 0x2
+#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
+#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
+#define SBP2_WORKAROUND_OVERRIDE 0x100
+
+static int sbp2_param_workarounds;
+module_param_named(workarounds, sbp2_param_workarounds, int, 0644);
+MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
+ ", 128kB max transfer = " __stringify(SBP2_WORKAROUND_128K_MAX_TRANS)
+ ", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36)
+ ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
+ ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
+ ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
+ ", or a combination)");
+
/* I don't know why the SCSI stack doesn't define something like this... */
typedef void (*scsi_done_fn_t)(struct scsi_cmnd *);
static const char sbp2_driver_name[] = "sbp2";
-struct sbp2_device {
- struct kref kref;
- struct fw_unit *unit;
+/*
+ * We create one struct sbp2_logical_unit per SBP-2 Logical Unit Number Entry
+ * and one struct scsi_device per sbp2_logical_unit.
+ */
+struct sbp2_logical_unit {
+ struct sbp2_target *tgt;
+ struct list_head link;
+ struct scsi_device *sdev;
struct fw_address_handler address_handler;
struct list_head orb_list;
- u64 management_agent_address;
+
u64 command_block_agent_address;
- u32 workarounds;
+ u16 lun;
int login_id;
/*
- * We cache these addresses and only update them once we've
- * logged in or reconnected to the sbp2 device. That way, any
- * IO to the device will automatically fail and get retried if
- * it happens in a window where the device is not ready to
- * handle it (e.g. after a bus reset but before we reconnect).
+ * The generation is updated once we've logged in or reconnected
+ * to the logical unit. Thus, I/O to the device will automatically
+ * fail and get retried if it happens in a window where the device
+ * is not ready, e.g. after a bus reset but before we reconnect.
*/
- int node_id;
- int address_high;
int generation;
-
int retries;
struct delayed_work work;
};
+/*
+ * We create one struct sbp2_target per IEEE 1212 Unit Directory
+ * and one struct Scsi_Host per sbp2_target.
+ */
+struct sbp2_target {
+ struct kref kref;
+ struct fw_unit *unit;
+
+ u64 management_agent_address;
+ int directory_id;
+ int node_id;
+ int address_high;
+
+ unsigned workarounds;
+ struct list_head lu_list;
+};
+
#define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000
#define SBP2_MAX_SECTORS 255 /* Max sectors supported */
#define SBP2_ORB_TIMEOUT 2000 /* Timeout in ms */
@@ -101,17 +160,9 @@ struct sbp2_device {
#define SBP2_DIRECTION_FROM_MEDIA 0x1
/* Unit directory keys */
-#define SBP2_COMMAND_SET_SPECIFIER 0x38
-#define SBP2_COMMAND_SET 0x39
-#define SBP2_COMMAND_SET_REVISION 0x3b
-#define SBP2_FIRMWARE_REVISION 0x3c
-
-/* Flags for detected oddities and brokeness */
-#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
-#define SBP2_WORKAROUND_INQUIRY_36 0x2
-#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
-#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
-#define SBP2_WORKAROUND_OVERRIDE 0x100
+#define SBP2_CSR_FIRMWARE_REVISION 0x3c
+#define SBP2_CSR_LOGICAL_UNIT_NUMBER 0x14
+#define SBP2_CSR_LOGICAL_UNIT_DIRECTORY 0xd4
/* Management orb opcodes */
#define SBP2_LOGIN_REQUEST 0x0
@@ -219,7 +270,7 @@ struct sbp2_command_orb {
} request;
struct scsi_cmnd *cmd;
scsi_done_fn_t done;
- struct fw_unit *unit;
+ struct sbp2_logical_unit *lu;
struct sbp2_pointer page_table[SG_ALL] __attribute__((aligned(8)));
dma_addr_t page_table_bus;
@@ -295,7 +346,7 @@ sbp2_status_write(struct fw_card *card, struct fw_request *request,
unsigned long long offset,
void *payload, size_t length, void *callback_data)
{
- struct sbp2_device *sd = callback_data;
+ struct sbp2_logical_unit *lu = callback_data;
struct sbp2_orb *orb;
struct sbp2_status status;
size_t header_size;
@@ -319,7 +370,7 @@ sbp2_status_write(struct fw_card *card, struct fw_request *request,
/* Lookup the orb corresponding to this status write. */
spin_lock_irqsave(&card->lock, flags);
- list_for_each_entry(orb, &sd->orb_list, link) {
+ list_for_each_entry(orb, &lu->orb_list, link) {
if (STATUS_GET_ORB_HIGH(status) == 0 &&
STATUS_GET_ORB_LOW(status) == orb->request_bus) {
orb->rcode = RCODE_COMPLETE;
@@ -329,7 +380,7 @@ sbp2_status_write(struct fw_card *card, struct fw_request *request,
}
spin_unlock_irqrestore(&card->lock, flags);
- if (&orb->link != &sd->orb_list)
+ if (&orb->link != &lu->orb_list)
orb->callback(orb, &status);
else
fw_error("status write for unknown orb\n");
@@ -361,20 +412,20 @@ complete_transaction(struct fw_card *card, int rcode,
orb->rcode = rcode;
if (orb->rcode != RCODE_COMPLETE) {
list_del(&orb->link);
+ spin_unlock_irqrestore(&card->lock, flags);
orb->callback(orb, NULL);
+ } else {
+ spin_unlock_irqrestore(&card->lock, flags);
}
- spin_unlock_irqrestore(&card->lock, flags);
-
kref_put(&orb->kref, free_orb);
}
static void
-sbp2_send_orb(struct sbp2_orb *orb, struct fw_unit *unit,
+sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
int node_id, int generation, u64 offset)
{
- struct fw_device *device = fw_device(unit->device.parent);
- struct sbp2_device *sd = unit->device.driver_data;
+ struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
unsigned long flags;
orb->pointer.high = 0;
@@ -382,7 +433,7 @@ sbp2_send_orb(struct sbp2_orb *orb, struct fw_unit *unit,
fw_memcpy_to_be32(&orb->pointer, &orb->pointer, sizeof(orb->pointer));
spin_lock_irqsave(&device->card->lock, flags);
- list_add_tail(&orb->link, &sd->orb_list);
+ list_add_tail(&orb->link, &lu->orb_list);
spin_unlock_irqrestore(&device->card->lock, flags);
/* Take a ref for the orb list and for the transaction callback. */
@@ -395,10 +446,9 @@ sbp2_send_orb(struct sbp2_orb *orb, struct fw_unit *unit,
complete_transaction, orb);
}
-static int sbp2_cancel_orbs(struct fw_unit *unit)
+static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu)
{
- struct fw_device *device = fw_device(unit->device.parent);
- struct sbp2_device *sd = unit->device.driver_data;
+ struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
struct sbp2_orb *orb, *next;
struct list_head list;
unsigned long flags;
@@ -406,7 +456,7 @@ static int sbp2_cancel_orbs(struct fw_unit *unit)
INIT_LIST_HEAD(&list);
spin_lock_irqsave(&device->card->lock, flags);
- list_splice_init(&sd->orb_list, &list);
+ list_splice_init(&lu->orb_list, &list);
spin_unlock_irqrestore(&device->card->lock, flags);
list_for_each_entry_safe(orb, next, &list, link) {
@@ -433,11 +483,11 @@ complete_management_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
}
static int
-sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation,
- int function, int lun, void *response)
+sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
+ int generation, int function, int lun_or_login_id,
+ void *response)
{
- struct fw_device *device = fw_device(unit->device.parent);
- struct sbp2_device *sd = unit->device.driver_data;
+ struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
struct sbp2_management_orb *orb;
int retval = -ENOMEM;
@@ -458,12 +508,12 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation,
orb->request.misc =
MANAGEMENT_ORB_NOTIFY |
MANAGEMENT_ORB_FUNCTION(function) |
- MANAGEMENT_ORB_LUN(lun);
+ MANAGEMENT_ORB_LUN(lun_or_login_id);
orb->request.length =
MANAGEMENT_ORB_RESPONSE_LENGTH(sizeof(orb->response));
- orb->request.status_fifo.high = sd->address_handler.offset >> 32;
- orb->request.status_fifo.low = sd->address_handler.offset;
+ orb->request.status_fifo.high = lu->address_handler.offset >> 32;
+ orb->request.status_fifo.low = lu->address_handler.offset;
if (function == SBP2_LOGIN_REQUEST) {
orb->request.misc |=
@@ -482,14 +532,14 @@ sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation,
if (dma_mapping_error(orb->base.request_bus))
goto fail_mapping_request;
- sbp2_send_orb(&orb->base, unit,
- node_id, generation, sd->management_agent_address);
+ sbp2_send_orb(&orb->base, lu, node_id, generation,
+ lu->tgt->management_agent_address);
wait_for_completion_timeout(&orb->done,
msecs_to_jiffies(SBP2_ORB_TIMEOUT));
retval = -EIO;
- if (sbp2_cancel_orbs(unit) == 0) {
+ if (sbp2_cancel_orbs(lu) == 0) {
fw_error("orb reply timed out, rcode=0x%02x\n",
orb->base.rcode);
goto out;
@@ -534,10 +584,9 @@ complete_agent_reset_write(struct fw_card *card, int rcode,
kfree(t);
}
-static int sbp2_agent_reset(struct fw_unit *unit)
+static int sbp2_agent_reset(struct sbp2_logical_unit *lu)
{
- struct fw_device *device = fw_device(unit->device.parent);
- struct sbp2_device *sd = unit->device.driver_data;
+ struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
struct fw_transaction *t;
static u32 zero;
@@ -546,181 +595,273 @@ static int sbp2_agent_reset(struct fw_unit *unit)
return -ENOMEM;
fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST,
- sd->node_id, sd->generation, device->max_speed,
- sd->command_block_agent_address + SBP2_AGENT_RESET,
+ lu->tgt->node_id, lu->generation, device->max_speed,
+ lu->command_block_agent_address + SBP2_AGENT_RESET,
&zero, sizeof(zero), complete_agent_reset_write, t);
return 0;
}
-static void sbp2_reconnect(struct work_struct *work);
-static struct scsi_host_template scsi_driver_template;
-
-static void release_sbp2_device(struct kref *kref)
+static void sbp2_release_target(struct kref *kref)
{
- struct sbp2_device *sd = container_of(kref, struct sbp2_device, kref);
- struct Scsi_Host *host =
- container_of((void *)sd, struct Scsi_Host, hostdata[0]);
-
- scsi_remove_host(host);
- sbp2_send_management_orb(sd->unit, sd->node_id, sd->generation,
- SBP2_LOGOUT_REQUEST, sd->login_id, NULL);
- fw_core_remove_address_handler(&sd->address_handler);
- fw_notify("removed sbp2 unit %s\n", sd->unit->device.bus_id);
- put_device(&sd->unit->device);
- scsi_host_put(host);
+ struct sbp2_target *tgt = container_of(kref, struct sbp2_target, kref);
+ struct sbp2_logical_unit *lu, *next;
+ struct Scsi_Host *shost =
+ container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
+
+ list_for_each_entry_safe(lu, next, &tgt->lu_list, link) {
+ if (lu->sdev)
+ scsi_remove_device(lu->sdev);
+
+ sbp2_send_management_orb(lu, tgt->node_id, lu->generation,
+ SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
+ fw_core_remove_address_handler(&lu->address_handler);
+ list_del(&lu->link);
+ kfree(lu);
+ }
+ scsi_remove_host(shost);
+ fw_notify("released %s\n", tgt->unit->device.bus_id);
+
+ put_device(&tgt->unit->device);
+ scsi_host_put(shost);
}
+static struct workqueue_struct *sbp2_wq;
+
+static void sbp2_reconnect(struct work_struct *work);
+
static void sbp2_login(struct work_struct *work)
{
- struct sbp2_device *sd =
- container_of(work, struct sbp2_device, work.work);
- struct Scsi_Host *host =
- container_of((void *)sd, struct Scsi_Host, hostdata[0]);
- struct fw_unit *unit = sd->unit;
+ struct sbp2_logical_unit *lu =
+ container_of(work, struct sbp2_logical_unit, work.work);
+ struct Scsi_Host *shost =
+ container_of((void *)lu->tgt, struct Scsi_Host, hostdata[0]);
+ struct scsi_device *sdev;
+ struct scsi_lun eight_bytes_lun;
+ struct fw_unit *unit = lu->tgt->unit;
struct fw_device *device = fw_device(unit->device.parent);
struct sbp2_login_response response;
- int generation, node_id, local_node_id, lun, retval;
-
- /* FIXME: Make this work for multi-lun devices. */
- lun = 0;
+ int generation, node_id, local_node_id;
generation = device->card->generation;
node_id = device->node->node_id;
local_node_id = device->card->local_node->node_id;
- if (sbp2_send_management_orb(unit, node_id, generation,
- SBP2_LOGIN_REQUEST, lun, &response) < 0) {
- if (sd->retries++ < 5) {
- schedule_delayed_work(&sd->work, DIV_ROUND_UP(HZ, 5));
+ if (sbp2_send_management_orb(lu, node_id, generation,
+ SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) {
+ if (lu->retries++ < 5) {
+ if (queue_delayed_work(sbp2_wq, &lu->work,
+ DIV_ROUND_UP(HZ, 5)))
+ kref_get(&lu->tgt->kref);
} else {
- fw_error("failed to login to %s\n",
- unit->device.bus_id);
- kref_put(&sd->kref, release_sbp2_device);
+ fw_error("failed to login to %s LUN %04x\n",
+ unit->device.bus_id, lu->lun);
}
+ kref_put(&lu->tgt->kref, sbp2_release_target);
return;
}
- sd->generation = generation;
- sd->node_id = node_id;
- sd->address_high = local_node_id << 16;
+ lu->generation = generation;
+ lu->tgt->node_id = node_id;
+ lu->tgt->address_high = local_node_id << 16;
/* Get command block agent offset and login id. */
- sd->command_block_agent_address =
+ lu->command_block_agent_address =
((u64) (response.command_block_agent.high & 0xffff) << 32) |
response.command_block_agent.low;
- sd->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response);
+ lu->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response);
- fw_notify("logged in to sbp2 unit %s (%d retries)\n",
- unit->device.bus_id, sd->retries);
- fw_notify(" - management_agent_address: 0x%012llx\n",
- (unsigned long long) sd->management_agent_address);
- fw_notify(" - command_block_agent_address: 0x%012llx\n",
- (unsigned long long) sd->command_block_agent_address);
- fw_notify(" - status write address: 0x%012llx\n",
- (unsigned long long) sd->address_handler.offset);
+ fw_notify("logged in to %s LUN %04x (%d retries)\n",
+ unit->device.bus_id, lu->lun, lu->retries);
#if 0
/* FIXME: The linux1394 sbp2 does this last step. */
sbp2_set_busy_timeout(scsi_id);
#endif
- PREPARE_DELAYED_WORK(&sd->work, sbp2_reconnect);
- sbp2_agent_reset(unit);
+ PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
+ sbp2_agent_reset(lu);
+
+ memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun));
+ eight_bytes_lun.scsi_lun[0] = (lu->lun >> 8) & 0xff;
+ eight_bytes_lun.scsi_lun[1] = lu->lun & 0xff;
- /* FIXME: Loop over luns here. */
- lun = 0;
- retval = scsi_add_device(host, 0, 0, lun);
- if (retval < 0) {
- sbp2_send_management_orb(unit, sd->node_id, sd->generation,
- SBP2_LOGOUT_REQUEST, sd->login_id,
- NULL);
+ sdev = __scsi_add_device(shost, 0, 0,
+ scsilun_to_int(&eight_bytes_lun), lu);
+ if (IS_ERR(sdev)) {
+ sbp2_send_management_orb(lu, node_id, generation,
+ SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
/*
* Set this back to sbp2_login so we fall back and
* retry login on bus reset.
*/
- PREPARE_DELAYED_WORK(&sd->work, sbp2_login);
+ PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
+ } else {
+ lu->sdev = sdev;
+ scsi_device_put(sdev);
}
- kref_put(&sd->kref, release_sbp2_device);
+ kref_put(&lu->tgt->kref, sbp2_release_target);
}
-static int sbp2_probe(struct device *dev)
+static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
{
- struct fw_unit *unit = fw_unit(dev);
- struct fw_device *device = fw_device(unit->device.parent);
- struct sbp2_device *sd;
- struct fw_csr_iterator ci;
- struct Scsi_Host *host;
- int i, key, value, err;
- u32 model, firmware_revision;
+ struct sbp2_logical_unit *lu;
- err = -ENOMEM;
- host = scsi_host_alloc(&scsi_driver_template, sizeof(*sd));
- if (host == NULL)
- goto fail;
+ lu = kmalloc(sizeof(*lu), GFP_KERNEL);
+ if (!lu)
+ return -ENOMEM;
- sd = (struct sbp2_device *) host->hostdata;
- unit->device.driver_data = sd;
- sd->unit = unit;
- INIT_LIST_HEAD(&sd->orb_list);
- kref_init(&sd->kref);
+ lu->address_handler.length = 0x100;
+ lu->address_handler.address_callback = sbp2_status_write;
+ lu->address_handler.callback_data = lu;
- sd->address_handler.length = 0x100;
- sd->address_handler.address_callback = sbp2_status_write;
- sd->address_handler.callback_data = sd;
+ if (fw_core_add_address_handler(&lu->address_handler,
+ &fw_high_memory_region) < 0) {
+ kfree(lu);
+ return -ENOMEM;
+ }
- err = fw_core_add_address_handler(&sd->address_handler,
- &fw_high_memory_region);
- if (err < 0)
- goto fail_host;
+ lu->tgt = tgt;
+ lu->sdev = NULL;
+ lu->lun = lun_entry & 0xffff;
+ lu->retries = 0;
+ INIT_LIST_HEAD(&lu->orb_list);
+ INIT_DELAYED_WORK(&lu->work, sbp2_login);
- err = fw_device_enable_phys_dma(device);
- if (err < 0)
- goto fail_address_handler;
+ list_add_tail(&lu->link, &tgt->lu_list);
+ return 0;
+}
- err = scsi_add_host(host, &unit->device);
- if (err < 0)
- goto fail_address_handler;
+static int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt, u32 *directory)
+{
+ struct fw_csr_iterator ci;
+ int key, value;
- /*
- * Scan unit directory to get management agent address,
- * firmware revison and model. Initialize firmware_revision
- * and model to values that wont match anything in our table.
- */
- firmware_revision = 0xff000000;
- model = 0xff000000;
- fw_csr_iterator_init(&ci, unit->directory);
+ fw_csr_iterator_init(&ci, directory);
+ while (fw_csr_iterator_next(&ci, &key, &value))
+ if (key == SBP2_CSR_LOGICAL_UNIT_NUMBER &&
+ sbp2_add_logical_unit(tgt, value) < 0)
+ return -ENOMEM;
+ return 0;
+}
+
+static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
+ u32 *model, u32 *firmware_revision)
+{
+ struct fw_csr_iterator ci;
+ int key, value;
+
+ fw_csr_iterator_init(&ci, directory);
while (fw_csr_iterator_next(&ci, &key, &value)) {
switch (key) {
+
case CSR_DEPENDENT_INFO | CSR_OFFSET:
- sd->management_agent_address =
- 0xfffff0000000ULL + 4 * value;
+ tgt->management_agent_address =
+ CSR_REGISTER_BASE + 4 * value;
break;
- case SBP2_FIRMWARE_REVISION:
- firmware_revision = value;
+
+ case CSR_DIRECTORY_ID:
+ tgt->directory_id = value;
break;
+
case CSR_MODEL:
- model = value;
+ *model = value;
+ break;
+
+ case SBP2_CSR_FIRMWARE_REVISION:
+ *firmware_revision = value;
+ break;
+
+ case SBP2_CSR_LOGICAL_UNIT_NUMBER:
+ if (sbp2_add_logical_unit(tgt, value) < 0)
+ return -ENOMEM;
+ break;
+
+ case SBP2_CSR_LOGICAL_UNIT_DIRECTORY:
+ if (sbp2_scan_logical_unit_dir(tgt, ci.p + value) < 0)
+ return -ENOMEM;
break;
}
}
+ return 0;
+}
+
+static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
+ u32 firmware_revision)
+{
+ int i;
+ unsigned w = sbp2_param_workarounds;
+
+ if (w)
+ fw_notify("Please notify linux1394-devel@lists.sourceforge.net "
+ "if you need the workarounds parameter for %s\n",
+ tgt->unit->device.bus_id);
+
+ if (w & SBP2_WORKAROUND_OVERRIDE)
+ goto out;
for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
+
if (sbp2_workarounds_table[i].firmware_revision !=
(firmware_revision & 0xffffff00))
continue;
+
if (sbp2_workarounds_table[i].model != model &&
sbp2_workarounds_table[i].model != ~0)
continue;
- sd->workarounds |= sbp2_workarounds_table[i].workarounds;
+
+ w |= sbp2_workarounds_table[i].workarounds;
break;
}
-
- if (sd->workarounds)
- fw_notify("Workarounds for node %s: 0x%x "
+ out:
+ if (w)
+ fw_notify("Workarounds for %s: 0x%x "
"(firmware_revision 0x%06x, model_id 0x%06x)\n",
- unit->device.bus_id,
- sd->workarounds, firmware_revision, model);
+ tgt->unit->device.bus_id,
+ w, firmware_revision, model);
+ tgt->workarounds = w;
+}
+
+static struct scsi_host_template scsi_driver_template;
+
+static int sbp2_probe(struct device *dev)
+{
+ struct fw_unit *unit = fw_unit(dev);
+ struct fw_device *device = fw_device(unit->device.parent);
+ struct sbp2_target *tgt;
+ struct sbp2_logical_unit *lu;
+ struct Scsi_Host *shost;
+ u32 model, firmware_revision;
+
+ shost = scsi_host_alloc(&scsi_driver_template, sizeof(*tgt));
+ if (shost == NULL)
+ return -ENOMEM;
+
+ tgt = (struct sbp2_target *)shost->hostdata;
+ unit->device.driver_data = tgt;
+ tgt->unit = unit;
+ kref_init(&tgt->kref);
+ INIT_LIST_HEAD(&tgt->lu_list);
+
+ if (fw_device_enable_phys_dma(device) < 0)
+ goto fail_shost_put;
+
+ if (scsi_add_host(shost, &unit->device) < 0)
+ goto fail_shost_put;
+
+ /* Initialize to values that won't match anything in our table. */
+ firmware_revision = 0xff000000;
+ model = 0xff000000;
+
+ /* implicit directory ID */
+ tgt->directory_id = ((unit->directory - device->config_rom) * 4
+ + CSR_CONFIG_ROM) & 0xffffff;
+
+ if (sbp2_scan_unit_dir(tgt, unit->directory, &model,
+ &firmware_revision) < 0)
+ goto fail_tgt_put;
+
+ sbp2_init_workarounds(tgt, model, firmware_revision);
get_device(&unit->device);
@@ -729,35 +870,34 @@ static int sbp2_probe(struct device *dev)
* reschedule retries. Always get the ref before scheduling
* work.
*/
- INIT_DELAYED_WORK(&sd->work, sbp2_login);
- if (schedule_delayed_work(&sd->work, 0))
- kref_get(&sd->kref);
-
+ list_for_each_entry(lu, &tgt->lu_list, link)
+ if (queue_delayed_work(sbp2_wq, &lu->work, 0))
+ kref_get(&tgt->kref);
return 0;
- fail_address_handler:
- fw_core_remove_address_handler(&sd->address_handler);
- fail_host:
- scsi_host_put(host);
- fail:
- return err;
+ fail_tgt_put:
+ kref_put(&tgt->kref, sbp2_release_target);
+ return -ENOMEM;
+
+ fail_shost_put:
+ scsi_host_put(shost);
+ return -ENOMEM;
}
static int sbp2_remove(struct device *dev)
{
struct fw_unit *unit = fw_unit(dev);
- struct sbp2_device *sd = unit->device.driver_data;
-
- kref_put(&sd->kref, release_sbp2_device);
+ struct sbp2_target *tgt = unit->device.driver_data;
+ kref_put(&tgt->kref, sbp2_release_target);
return 0;
}
static void sbp2_reconnect(struct work_struct *work)
{
- struct sbp2_device *sd =
- container_of(work, struct sbp2_device, work.work);
- struct fw_unit *unit = sd->unit;
+ struct sbp2_logical_unit *lu =
+ container_of(work, struct sbp2_logical_unit, work.work);
+ struct fw_unit *unit = lu->tgt->unit;
struct fw_device *device = fw_device(unit->device.parent);
int generation, node_id, local_node_id;
@@ -765,40 +905,51 @@ static void sbp2_reconnect(struct work_struct *work)
node_id = device->node->node_id;
local_node_id = device->card->local_node->node_id;
- if (sbp2_send_management_orb(unit, node_id, generation,
+ if (sbp2_send_management_orb(lu, node_id, generation,
SBP2_RECONNECT_REQUEST,
- sd->login_id, NULL) < 0) {
- if (sd->retries++ >= 5) {
+ lu->login_id, NULL) < 0) {
+ if (lu->retries++ >= 5) {
fw_error("failed to reconnect to %s\n",
unit->device.bus_id);
/* Fall back and try to log in again. */
- sd->retries = 0;
- PREPARE_DELAYED_WORK(&sd->work, sbp2_login);
+ lu->retries = 0;
+ PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
}
- schedule_delayed_work(&sd->work, DIV_ROUND_UP(HZ, 5));
+ if (queue_delayed_work(sbp2_wq, &lu->work, DIV_ROUND_UP(HZ, 5)))
+ kref_get(&lu->tgt->kref);
+ kref_put(&lu->tgt->kref, sbp2_release_target);
return;
}
- sd->generation = generation;
- sd->node_id = node_id;
- sd->address_high = local_node_id << 16;
+ lu->generation = generation;
+ lu->tgt->node_id = node_id;
+ lu->tgt->address_high = local_node_id << 16;
- fw_notify("reconnected to unit %s (%d retries)\n",
- unit->device.bus_id, sd->retries);
- sbp2_agent_reset(unit);
- sbp2_cancel_orbs(unit);
- kref_put(&sd->kref, release_sbp2_device);
+ fw_notify("reconnected to %s LUN %04x (%d retries)\n",
+ unit->device.bus_id, lu->lun, lu->retries);
+
+ sbp2_agent_reset(lu);
+ sbp2_cancel_orbs(lu);
+
+ kref_put(&lu->tgt->kref, sbp2_release_target);
}
static void sbp2_update(struct fw_unit *unit)
{
- struct fw_device *device = fw_device(unit->device.parent);
- struct sbp2_device *sd = unit->device.driver_data;
+ struct sbp2_target *tgt = unit->device.driver_data;
+ struct sbp2_logical_unit *lu;
- sd->retries = 0;
- fw_device_enable_phys_dma(device);
- if (schedule_delayed_work(&sd->work, 0))
- kref_get(&sd->kref);
+ fw_device_enable_phys_dma(fw_device(unit->device.parent));
+
+ /*
+ * Fw-core serializes sbp2_update() against sbp2_remove().
+ * Iteration over tgt->lu_list is therefore safe here.
+ */
+ list_for_each_entry(lu, &tgt->lu_list, link) {
+ lu->retries = 0;
+ if (queue_delayed_work(sbp2_wq, &lu->work, 0))
+ kref_get(&tgt->kref);
+ }
}
#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e
@@ -868,13 +1019,12 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
{
struct sbp2_command_orb *orb =
container_of(base_orb, struct sbp2_command_orb, base);
- struct fw_unit *unit = orb->unit;
- struct fw_device *device = fw_device(unit->device.parent);
+ struct fw_device *device = fw_device(orb->lu->tgt->unit->device.parent);
int result;
if (status != NULL) {
if (STATUS_GET_DEAD(*status))
- sbp2_agent_reset(unit);
+ sbp2_agent_reset(orb->lu);
switch (STATUS_GET_RESPONSE(*status)) {
case SBP2_STATUS_REQUEST_COMPLETE:
@@ -918,12 +1068,10 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
orb->done(orb->cmd);
}
-static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
+static int
+sbp2_map_scatterlist(struct sbp2_command_orb *orb, struct fw_device *device,
+ struct sbp2_logical_unit *lu)
{
- struct sbp2_device *sd =
- (struct sbp2_device *)orb->cmd->device->host->hostdata;
- struct fw_unit *unit = sd->unit;
- struct fw_device *device = fw_device(unit->device.parent);
struct scatterlist *sg;
int sg_len, l, i, j, count;
dma_addr_t sg_addr;
@@ -942,10 +1090,9 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
* tables.
*/
if (count == 1 && sg_dma_len(sg) < SBP2_MAX_SG_ELEMENT_LENGTH) {
- orb->request.data_descriptor.high = sd->address_high;
+ orb->request.data_descriptor.high = lu->tgt->address_high;
orb->request.data_descriptor.low = sg_dma_address(sg);
- orb->request.misc |=
- COMMAND_ORB_DATA_SIZE(sg_dma_len(sg));
+ orb->request.misc |= COMMAND_ORB_DATA_SIZE(sg_dma_len(sg));
return 0;
}
@@ -989,7 +1136,7 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
* initiator (i.e. us), but data_descriptor can refer to data
* on other nodes so we need to put our ID in descriptor.high.
*/
- orb->request.data_descriptor.high = sd->address_high;
+ orb->request.data_descriptor.high = lu->tgt->address_high;
orb->request.data_descriptor.low = orb->page_table_bus;
orb->request.misc |=
COMMAND_ORB_PAGE_TABLE_PRESENT |
@@ -1008,12 +1155,11 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
{
- struct sbp2_device *sd =
- (struct sbp2_device *)cmd->device->host->hostdata;
- struct fw_unit *unit = sd->unit;
- struct fw_device *device = fw_device(unit->device.parent);
+ struct sbp2_logical_unit *lu = cmd->device->hostdata;
+ struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
struct sbp2_command_orb *orb;
unsigned max_payload;
+ int retval = SCSI_MLQUEUE_HOST_BUSY;
/*
* Bidirectional commands are not yet implemented, and unknown
@@ -1029,14 +1175,14 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
orb = kzalloc(sizeof(*orb), GFP_ATOMIC);
if (orb == NULL) {
fw_notify("failed to alloc orb\n");
- goto fail_alloc;
+ return SCSI_MLQUEUE_HOST_BUSY;
}
/* Initialize rcode to something not RCODE_COMPLETE. */
orb->base.rcode = -1;
kref_init(&orb->base.kref);
- orb->unit = unit;
+ orb->lu = lu;
orb->done = done;
orb->cmd = cmd;
@@ -1062,8 +1208,8 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
orb->request.misc |=
COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA);
- if (scsi_sg_count(cmd) && sbp2_command_orb_map_scatterlist(orb) < 0)
- goto fail_mapping;
+ if (scsi_sg_count(cmd) && sbp2_map_scatterlist(orb, device, lu) < 0)
+ goto out;
fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request));
@@ -1076,49 +1222,47 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
dma_map_single(device->card->device, &orb->request,
sizeof(orb->request), DMA_TO_DEVICE);
if (dma_mapping_error(orb->base.request_bus))
- goto fail_mapping;
-
- sbp2_send_orb(&orb->base, unit, sd->node_id, sd->generation,
- sd->command_block_agent_address + SBP2_ORB_POINTER);
-
- kref_put(&orb->base.kref, free_orb);
- return 0;
+ goto out;
- fail_mapping:
+ sbp2_send_orb(&orb->base, lu, lu->tgt->node_id, lu->generation,
+ lu->command_block_agent_address + SBP2_ORB_POINTER);
+ retval = 0;
+ out:
kref_put(&orb->base.kref, free_orb);
- fail_alloc:
- return SCSI_MLQUEUE_HOST_BUSY;
+ return retval;
}
static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
{
- struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata;
+ struct sbp2_logical_unit *lu = sdev->hostdata;
sdev->allow_restart = 1;
- if (sd->workarounds & SBP2_WORKAROUND_INQUIRY_36)
+ if (lu->tgt->workarounds & SBP2_WORKAROUND_INQUIRY_36)
sdev->inquiry_len = 36;
+
return 0;
}
static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
{
- struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata;
- struct fw_unit *unit = sd->unit;
+ struct sbp2_logical_unit *lu = sdev->hostdata;
sdev->use_10_for_rw = 1;
if (sdev->type == TYPE_ROM)
sdev->use_10_for_ms = 1;
+
if (sdev->type == TYPE_DISK &&
- sd->workarounds & SBP2_WORKAROUND_MODE_SENSE_8)
+ lu->tgt->workarounds & SBP2_WORKAROUND_MODE_SENSE_8)
sdev->skip_ms_page_8 = 1;
- if (sd->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) {
- fw_notify("setting fix_capacity for %s\n", unit->device.bus_id);
+
+ if (lu->tgt->workarounds & SBP2_WORKAROUND_FIX_CAPACITY)
sdev->fix_capacity = 1;
- }
- if (sd->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
+
+ if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
blk_queue_max_sectors(sdev->request_queue, 128 * 1024 / 512);
+
return 0;
}
@@ -1128,13 +1272,11 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
*/
static int sbp2_scsi_abort(struct scsi_cmnd *cmd)
{
- struct sbp2_device *sd =
- (struct sbp2_device *)cmd->device->host->hostdata;
- struct fw_unit *unit = sd->unit;
+ struct sbp2_logical_unit *lu = cmd->device->hostdata;
fw_notify("sbp2_scsi_abort\n");
- sbp2_agent_reset(unit);
- sbp2_cancel_orbs(unit);
+ sbp2_agent_reset(lu);
+ sbp2_cancel_orbs(lu);
return SUCCESS;
}
@@ -1151,37 +1293,18 @@ sbp2_sysfs_ieee1394_id_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct scsi_device *sdev = to_scsi_device(dev);
- struct sbp2_device *sd;
- struct fw_unit *unit;
+ struct sbp2_logical_unit *lu;
struct fw_device *device;
- u32 directory_id;
- struct fw_csr_iterator ci;
- int key, value, lun;
if (!sdev)
return 0;
- sd = (struct sbp2_device *)sdev->host->hostdata;
- unit = sd->unit;
- device = fw_device(unit->device.parent);
-
- /* implicit directory ID */
- directory_id = ((unit->directory - device->config_rom) * 4
- + CSR_CONFIG_ROM) & 0xffffff;
-
- /* explicit directory ID, overrides implicit ID if present */
- fw_csr_iterator_init(&ci, unit->directory);
- while (fw_csr_iterator_next(&ci, &key, &value))
- if (key == CSR_DIRECTORY_ID) {
- directory_id = value;
- break;
- }
- /* FIXME: Make this work for multi-lun devices. */
- lun = 0;
+ lu = sdev->hostdata;
+ device = fw_device(lu->tgt->unit->device.parent);
return sprintf(buf, "%08x%08x:%06x:%04x\n",
device->config_rom[3], device->config_rom[4],
- directory_id, lun);
+ lu->tgt->directory_id, lu->lun);
}
static DEVICE_ATTR(ieee1394_id, S_IRUGO, sbp2_sysfs_ieee1394_id_show, NULL);
@@ -1219,12 +1342,17 @@ MODULE_ALIAS("sbp2");
static int __init sbp2_init(void)
{
+ sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME);
+ if (!sbp2_wq)
+ return -ENOMEM;
+
return driver_register(&sbp2_driver.driver);
}
static void __exit sbp2_cleanup(void)
{
driver_unregister(&sbp2_driver.driver);
+ destroy_workqueue(sbp2_wq);
}
module_init(sbp2_init);
diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c
index 39e5cd12aa5..0fc9b000e99 100644
--- a/drivers/firewire/fw-topology.c
+++ b/drivers/firewire/fw-topology.c
@@ -152,6 +152,10 @@ static void update_hop_count(struct fw_node *node)
node->max_hops = max(max_child_hops, depths[0] + depths[1] + 2);
}
+static inline struct fw_node *fw_node(struct list_head *l)
+{
+ return list_entry(l, struct fw_node, link);
+}
/**
* build_tree - Build the tree representation of the topology
@@ -162,7 +166,7 @@ static void update_hop_count(struct fw_node *node)
* This function builds the tree representation of the topology given
* by the self IDs from the latest bus reset. During the construction
* of the tree, the function checks that the self IDs are valid and
- * internally consistent. On succcess this funtions returns the
+ * internally consistent. On succcess this function returns the
* fw_node corresponding to the local card otherwise NULL.
*/
static struct fw_node *build_tree(struct fw_card *card,
@@ -211,6 +215,10 @@ static struct fw_node *build_tree(struct fw_card *card,
*/
for (i = 0, h = &stack; i < child_port_count; i++)
h = h->prev;
+ /*
+ * When the stack is empty, this yields an invalid value,
+ * but that pointer will never be dereferenced.
+ */
child = fw_node(h);
node = fw_node_create(q, port_count, card->color);
diff --git a/drivers/firewire/fw-topology.h b/drivers/firewire/fw-topology.h
index 1b56b4ac7fb..cedc1ec906e 100644
--- a/drivers/firewire/fw-topology.h
+++ b/drivers/firewire/fw-topology.h
@@ -51,12 +51,6 @@ struct fw_node {
};
static inline struct fw_node *
-fw_node(struct list_head *l)
-{
- return list_entry(l, struct fw_node, link);
-}
-
-static inline struct fw_node *
fw_node_get(struct fw_node *node)
{
atomic_inc(&node->ref_count);
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
index 3e1cb12e43c..c00d4a9b39e 100644
--- a/drivers/firewire/fw-transaction.c
+++ b/drivers/firewire/fw-transaction.c
@@ -228,7 +228,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
*
* @param card the card from which to send the request
* @param tcode the tcode for this transaction. Do not use
- * TCODE_LOCK_REQUEST directly, insted use TCODE_LOCK_MASK_SWAP
+ * TCODE_LOCK_REQUEST directly, instead use TCODE_LOCK_MASK_SWAP
* etc. to specify tcode and ext_tcode.
* @param node_id the destination node ID (bus ID and PHY ID concatenated)
* @param generation the generation for which node_id is valid
@@ -410,7 +410,12 @@ EXPORT_SYMBOL(fw_unit_space_region);
* controller. When a request is received that falls within the
* specified address range, the specified callback is invoked. The
* parameters passed to the callback give the details of the
- * particular request
+ * particular request.
+ *
+ * Return value: 0 on success, non-zero otherwise.
+ * The start offset of the handler's address region is determined by
+ * fw_core_add_address_handler() and is returned in handler->offset.
+ * The offset is quadlet-aligned.
*/
int
fw_core_add_address_handler(struct fw_address_handler *handler,
@@ -422,14 +427,15 @@ fw_core_add_address_handler(struct fw_address_handler *handler,
spin_lock_irqsave(&address_handler_lock, flags);
- handler->offset = region->start;
+ handler->offset = roundup(region->start, 4);
while (handler->offset + handler->length <= region->end) {
other =
lookup_overlapping_address_handler(&address_handler_list,
handler->offset,
handler->length);
if (other != NULL) {
- handler->offset += other->length;
+ handler->offset =
+ roundup(other->offset + other->length, 4);
} else {
list_add_tail(&handler->link, &address_handler_list);
ret = 0;
diff --git a/drivers/firmware/dcdbas.h b/drivers/firmware/dcdbas.h
index dcdba0f1b32..87bc3417de2 100644
--- a/drivers/firmware/dcdbas.h
+++ b/drivers/firmware/dcdbas.h
@@ -17,7 +17,6 @@
#define _DCDBAS_H_
#include <linux/device.h>
-#include <linux/input.h>
#include <linux/sysfs.h>
#include <linux/types.h>
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
index 59c3b5aa89f..b6e1eb77d14 100644
--- a/drivers/firmware/dmi-id.c
+++ b/drivers/firmware/dmi-id.c
@@ -13,21 +13,31 @@
#include <linux/device.h>
#include <linux/autoconf.h>
-#define DEFINE_DMI_ATTR(_name, _mode, _show) \
-static struct device_attribute sys_dmi_##_name##_attr = \
- __ATTR(_name, _mode, _show, NULL);
-
-#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \
-static ssize_t sys_dmi_##_name##_show(struct device *dev, \
- struct device_attribute *attr, \
- char *page) \
-{ \
- ssize_t len; \
- len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \
- page[len-1] = '\n'; \
- return len; \
-} \
-DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show);
+struct dmi_device_attribute{
+ struct device_attribute dev_attr;
+ int field;
+};
+#define to_dmi_dev_attr(_dev_attr) \
+ container_of(_dev_attr, struct dmi_device_attribute, dev_attr)
+
+static ssize_t sys_dmi_field_show(struct device *dev,
+ struct device_attribute *attr,
+ char *page)
+{
+ int field = to_dmi_dev_attr(attr)->field;
+ ssize_t len;
+ len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(field));
+ page[len-1] = '\n';
+ return len;
+}
+
+#define DMI_ATTR(_name, _mode, _show, _field) \
+ { .dev_attr = __ATTR(_name, _mode, _show, NULL), \
+ .field = _field }
+
+#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \
+static struct dmi_device_attribute sys_dmi_##_name##_attr = \
+ DMI_ATTR(_name, _mode, sys_dmi_field_show, _field);
DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor, 0444, DMI_BIOS_VENDOR);
DEFINE_DMI_ATTR_WITH_SHOW(bios_version, 0444, DMI_BIOS_VERSION);
@@ -121,7 +131,8 @@ static ssize_t sys_dmi_modalias_show(struct device *dev,
return r+1;
}
-DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show);
+static struct device_attribute sys_dmi_modalias_attr =
+ __ATTR(modalias, 0444, sys_dmi_modalias_show, NULL);
static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2];
@@ -134,14 +145,17 @@ static struct attribute_group* sys_dmi_attribute_groups[] = {
NULL
};
-static int dmi_dev_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
{
- strcpy(buffer, "MODALIAS=");
- get_modalias(buffer+9, buffer_size-9);
- envp[0] = buffer;
- envp[1] = NULL;
-
+ ssize_t len;
+
+ if (add_uevent_var(env, "MODALIAS="))
+ return -ENOMEM;
+ len = get_modalias(&env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen);
+ if (len >= (sizeof(env->buf) - env->buflen))
+ return -ENOMEM;
+ env->buflen += len;
return 0;
}
@@ -157,7 +171,7 @@ static struct device *dmi_dev;
#define ADD_DMI_ATTR(_name, _field) \
if (dmi_get_system_info(_field)) \
- sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr;
+ sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr;
extern int dmi_available;
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index f7318b3b51f..0cdadea7a40 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -8,9 +8,9 @@
#include <linux/slab.h>
#include <asm/dmi.h>
-static char * __init dmi_string(struct dmi_header *dm, u8 s)
+static char * __init dmi_string(const struct dmi_header *dm, u8 s)
{
- u8 *bp = ((u8 *) dm) + dm->length;
+ const u8 *bp = ((u8 *) dm) + dm->length;
char *str = "";
if (s) {
@@ -37,7 +37,7 @@ static char * __init dmi_string(struct dmi_header *dm, u8 s)
* pointing to completely the wrong place for example
*/
static int __init dmi_table(u32 base, int len, int num,
- void (*decode)(struct dmi_header *))
+ void (*decode)(const struct dmi_header *))
{
u8 *buf, *data;
int i = 0;
@@ -53,7 +53,8 @@ static int __init dmi_table(u32 base, int len, int num,
* OR we run off the end of the table (also happens)
*/
while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
- struct dmi_header *dm = (struct dmi_header *)data;
+ const struct dmi_header *dm = (const struct dmi_header *)data;
+
/*
* We want to know the total length (formated area and strings)
* before decoding to make sure we won't run off the table in
@@ -71,7 +72,7 @@ static int __init dmi_table(u32 base, int len, int num,
return 0;
}
-static int __init dmi_checksum(u8 *buf)
+static int __init dmi_checksum(const u8 *buf)
{
u8 sum = 0;
int a;
@@ -89,9 +90,10 @@ int dmi_available;
/*
* Save a DMI string
*/
-static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
+static void __init dmi_save_ident(const struct dmi_header *dm, int slot, int string)
{
- char *p, *d = (char*) dm;
+ const char *d = (const char*) dm;
+ char *p;
if (dmi_ident[slot])
return;
@@ -103,9 +105,9 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
dmi_ident[slot] = p;
}
-static void __init dmi_save_uuid(struct dmi_header *dm, int slot, int index)
+static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int index)
{
- u8 *d = (u8*) dm + index;
+ const u8 *d = (u8*) dm + index;
char *s;
int is_ff = 1, is_00 = 1, i;
@@ -132,9 +134,9 @@ static void __init dmi_save_uuid(struct dmi_header *dm, int slot, int index)
dmi_ident[slot] = s;
}
-static void __init dmi_save_type(struct dmi_header *dm, int slot, int index)
+static void __init dmi_save_type(const struct dmi_header *dm, int slot, int index)
{
- u8 *d = (u8*) dm + index;
+ const u8 *d = (u8*) dm + index;
char *s;
if (dmi_ident[slot])
@@ -148,13 +150,13 @@ static void __init dmi_save_type(struct dmi_header *dm, int slot, int index)
dmi_ident[slot] = s;
}
-static void __init dmi_save_devices(struct dmi_header *dm)
+static void __init dmi_save_devices(const struct dmi_header *dm)
{
int i, count = (dm->length - sizeof(struct dmi_header)) / 2;
struct dmi_device *dev;
for (i = 0; i < count; i++) {
- char *d = (char *)(dm + 1) + (i * 2);
+ const char *d = (char *)(dm + 1) + (i * 2);
/* Skip disabled device */
if ((*d & 0x80) == 0)
@@ -173,7 +175,7 @@ static void __init dmi_save_devices(struct dmi_header *dm)
}
}
-static void __init dmi_save_oem_strings_devices(struct dmi_header *dm)
+static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
{
int i, count = *(u8 *)(dm + 1);
struct dmi_device *dev;
@@ -194,7 +196,7 @@ static void __init dmi_save_oem_strings_devices(struct dmi_header *dm)
}
}
-static void __init dmi_save_ipmi_device(struct dmi_header *dm)
+static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
{
struct dmi_device *dev;
void * data;
@@ -225,7 +227,7 @@ static void __init dmi_save_ipmi_device(struct dmi_header *dm)
* and machine entries. For 2.5 we should pull the smbus controller info
* out of here.
*/
-static void __init dmi_decode(struct dmi_header *dm)
+static void __init dmi_decode(const struct dmi_header *dm)
{
switch(dm->type) {
case 0: /* BIOS Information */
@@ -265,9 +267,10 @@ static void __init dmi_decode(struct dmi_header *dm)
}
}
-static int __init dmi_present(char __iomem *p)
+static int __init dmi_present(const char __iomem *p)
{
u8 buf[15];
+
memcpy_fromio(buf, p, 15);
if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
u16 num = (buf[13] << 8) | buf[12];
@@ -348,10 +351,10 @@ void __init dmi_scan_machine(void)
* returns non zero or we hit the end. Callback function is called for
* each successful match. Returns the number of matches.
*/
-int dmi_check_system(struct dmi_system_id *list)
+int dmi_check_system(const struct dmi_system_id *list)
{
int i, count = 0;
- struct dmi_system_id *d = list;
+ const struct dmi_system_id *d = list;
while (d->ident) {
for (i = 0; i < ARRAY_SIZE(d->matches); i++) {
@@ -380,7 +383,7 @@ EXPORT_SYMBOL(dmi_check_system);
* Returns one DMI data value, can be used to perform
* complex DMI data checks.
*/
-char *dmi_get_system_info(int field)
+const char *dmi_get_system_info(int field)
{
return dmi_ident[field];
}
@@ -391,7 +394,7 @@ EXPORT_SYMBOL(dmi_get_system_info);
* dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information.
* @str: Case sensitive Name
*/
-int dmi_name_in_vendors(char *str)
+int dmi_name_in_vendors(const char *str)
{
static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR,
DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR,
@@ -418,13 +421,15 @@ EXPORT_SYMBOL(dmi_name_in_vendors);
* A new search is initiated by passing %NULL as the @from argument.
* If @from is not %NULL, searches continue from next device.
*/
-struct dmi_device * dmi_find_device(int type, const char *name,
- struct dmi_device *from)
+const struct dmi_device * dmi_find_device(int type, const char *name,
+ const struct dmi_device *from)
{
- struct list_head *d, *head = from ? &from->list : &dmi_devices;
+ const struct list_head *head = from ? &from->list : &dmi_devices;
+ struct list_head *d;
for(d = head->next; d != &dmi_devices; d = d->next) {
- struct dmi_device *dev = list_entry(d, struct dmi_device, list);
+ const struct dmi_device *dev =
+ list_entry(d, struct dmi_device, list);
if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) &&
((name == NULL) || (strcmp(dev->name, name) == 0)))
@@ -444,7 +449,7 @@ EXPORT_SYMBOL(dmi_find_device);
int dmi_get_year(int field)
{
int year;
- char *s = dmi_get_system_info(field);
+ const char *s = dmi_get_system_info(field);
if (!s)
return -1;
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index 0fb730ee1da..6942e065e60 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -625,13 +625,13 @@ static void edd_release(struct kobject * kobj)
kfree(dev);
}
-static struct kobj_type ktype_edd = {
+static struct kobj_type edd_ktype = {
.release = edd_release,
.sysfs_ops = &edd_attr_ops,
.default_attrs = def_attrs,
};
-static decl_subsys(edd,&ktype_edd,NULL);
+static decl_subsys(edd, &edd_ktype, NULL);
/**
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index bfd2d67df68..858a7b95933 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -402,7 +402,7 @@ static struct attribute *def_attrs[] = {
NULL,
};
-static struct kobj_type ktype_efivar = {
+static struct kobj_type efivar_ktype = {
.release = efivar_release,
.sysfs_ops = &efivar_attr_ops,
.default_attrs = def_attrs,
@@ -583,7 +583,7 @@ static struct subsys_attribute *efi_subsys_attrs[] = {
NULL, /* maybe more in the future? */
};
-static decl_subsys(vars, &ktype_efivar, NULL);
+static decl_subsys(vars, &efivar_ktype, NULL);
static decl_subsys(efi, NULL, NULL);
/*
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 19667fcc722..cacf89e65af 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -46,6 +46,25 @@ config HID_DEBUG
If unsure, say N
+config HIDRAW
+ bool "/dev/hidraw raw HID device support"
+ depends on HID
+ ---help---
+ Say Y here if you want to support HID devices (from the USB
+ specification standpoint) that aren't strictly user interface
+ devices, like monitor controls and Uninterruptable Power Supplies.
+
+ This module supports these devices separately using a separate
+ event interface on /dev/hidraw.
+
+ There is also a /dev/hiddev configuration option in the USB HID
+ configuration menu. In comparison to hiddev, this device does not process
+ the hid events at all (no parsing, no lookups). This lets applications
+ to work on raw hid events when they want to, and avoid using transport-specific
+ userspace libhid/libusb libraries.
+
+ If unsure, say Y.
+
source "drivers/hid/usbhid/Kconfig"
endif # HID_SUPPORT
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 68d1376a53f..1ac5103f7c9 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -4,7 +4,9 @@
hid-objs := hid-core.o hid-input.o
obj-$(CONFIG_HID) += hid.o
+
hid-$(CONFIG_HID_DEBUG) += hid-debug.o
+hid-$(CONFIG_HIDRAW) += hidraw.o
obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 317cf8a7b63..2884b036495 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -30,6 +30,7 @@
#include <linux/hid.h>
#include <linux/hiddev.h>
#include <linux/hid-debug.h>
+#include <linux/hidraw.h>
/*
* Version Information
@@ -979,6 +980,8 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
hid->hiddev_report_event(hid, report);
+ if (hid->claimed & HID_CLAIMED_HIDRAW)
+ hidraw_report_event(hid, data, size);
for (n = 0; n < report->maxfield; n++)
hid_input_field(hid, report->field[n], data, interrupt);
@@ -990,5 +993,18 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
}
EXPORT_SYMBOL_GPL(hid_input_report);
+static int __init hid_init(void)
+{
+ return hidraw_init();
+}
+
+static void __exit hid_exit(void)
+{
+ hidraw_exit();
+}
+
+module_init(hid_init);
+module_exit(hid_exit);
+
MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index a13757b7898..5c24fe46d8e 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -34,7 +34,7 @@
struct hid_usage_entry {
unsigned page;
unsigned usage;
- char *description;
+ const char *description;
};
static const struct hid_usage_entry hid_usage_table[] = {
@@ -365,8 +365,8 @@ void hid_resolv_usage(unsigned usage) {
}
EXPORT_SYMBOL_GPL(hid_resolv_usage);
-__inline__ static void tab(int n) {
- while (n--) printk(" ");
+static void tab(int n) {
+ printk(KERN_DEBUG "%*s", n, "");
}
void hid_dump_field(struct hid_field *field, int n) {
@@ -401,8 +401,8 @@ void hid_dump_field(struct hid_field *field, int n) {
tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
}
if (field->unit) {
- char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
- char *units[5][8] = {
+ static const char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
+ static const char *units[5][8] = {
{ "None", "None", "None", "None", "None", "None", "None", "None" },
{ "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" },
{ "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" },
@@ -457,7 +457,7 @@ void hid_dump_field(struct hid_field *field, int n) {
printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
- printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : "");
+ printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPreferredState " : "");
printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
@@ -470,7 +470,7 @@ void hid_dump_device(struct hid_device *device) {
struct hid_report *report;
struct list_head *list;
unsigned i,k;
- static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
+ static const char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
if (!hid_debug)
return;
@@ -501,13 +501,13 @@ void hid_dump_input(struct hid_usage *usage, __s32 value) {
if (!hid_debug)
return;
- printk("hid-debug: input ");
+ printk(KERN_DEBUG "hid-debug: input ");
hid_resolv_usage(usage->hid);
printk(" = %d\n", value);
}
EXPORT_SYMBOL_GPL(hid_dump_input);
-static char *events[EV_MAX + 1] = {
+static const char *events[EV_MAX + 1] = {
[EV_SYN] = "Sync", [EV_KEY] = "Key",
[EV_REL] = "Relative", [EV_ABS] = "Absolute",
[EV_MSC] = "Misc", [EV_LED] = "LED",
@@ -516,10 +516,10 @@ static char *events[EV_MAX + 1] = {
[EV_FF_STATUS] = "ForceFeedbackStatus",
};
-static char *syncs[2] = {
+static const char *syncs[2] = {
[SYN_REPORT] = "Report", [SYN_CONFIG] = "Config",
};
-static char *keys[KEY_MAX + 1] = {
+static const char *keys[KEY_MAX + 1] = {
[KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc",
[KEY_1] = "1", [KEY_2] = "2",
[KEY_3] = "3", [KEY_4] = "4",
@@ -697,7 +697,8 @@ static char *keys[KEY_MAX + 1] = {
[KEY_DEL_LINE] = "DeleteLine",
[KEY_SEND] = "Send", [KEY_REPLY] = "Reply",
[KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save",
- [KEY_DOCUMENTS] = "Documents",
+ [KEY_DOCUMENTS] = "Documents", [KEY_SPELLCHECK] = "SpellCheck",
+ [KEY_LOGOFF] = "Logoff",
[KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC",
[KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2",
[KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D",
@@ -715,7 +716,7 @@ static char *keys[KEY_MAX + 1] = {
[KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
};
-static char *relatives[REL_MAX + 1] = {
+static const char *relatives[REL_MAX + 1] = {
[REL_X] = "X", [REL_Y] = "Y",
[REL_Z] = "Z", [REL_RX] = "Rx",
[REL_RY] = "Ry", [REL_RZ] = "Rz",
@@ -723,7 +724,7 @@ static char *relatives[REL_MAX + 1] = {
[REL_WHEEL] = "Wheel", [REL_MISC] = "Misc",
};
-static char *absolutes[ABS_MAX + 1] = {
+static const char *absolutes[ABS_MAX + 1] = {
[ABS_X] = "X", [ABS_Y] = "Y",
[ABS_Z] = "Z", [ABS_RX] = "Rx",
[ABS_RY] = "Ry", [ABS_RZ] = "Rz",
@@ -739,12 +740,12 @@ static char *absolutes[ABS_MAX + 1] = {
[ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc",
};
-static char *misc[MSC_MAX + 1] = {
+static const char *misc[MSC_MAX + 1] = {
[MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled",
[MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData"
};
-static char *leds[LED_MAX + 1] = {
+static const char *leds[LED_MAX + 1] = {
[LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock",
[LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose",
[LED_KANA] = "Kana", [LED_SLEEP] = "Sleep",
@@ -752,16 +753,16 @@ static char *leds[LED_MAX + 1] = {
[LED_MISC] = "Misc",
};
-static char *repeats[REP_MAX + 1] = {
+static const char *repeats[REP_MAX + 1] = {
[REP_DELAY] = "Delay", [REP_PERIOD] = "Period"
};
-static char *sounds[SND_MAX + 1] = {
+static const char *sounds[SND_MAX + 1] = {
[SND_CLICK] = "Click", [SND_BELL] = "Bell",
[SND_TONE] = "Tone"
};
-static char **names[EV_MAX + 1] = {
+static const char **names[EV_MAX + 1] = {
[EV_SYN] = syncs, [EV_KEY] = keys,
[EV_REL] = relatives, [EV_ABS] = absolutes,
[EV_MSC] = misc, [EV_LED] = leds,
@@ -777,4 +778,3 @@ void hid_resolv_event(__u8 type, __u16 code) {
names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
}
EXPORT_SYMBOL_GPL(hid_resolv_event);
-
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 8edbd30cf79..0b27da7d749 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -53,7 +53,7 @@ static const unsigned char hid_keyboard[256] = {
115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
- unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+ unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
@@ -86,6 +86,10 @@ static const struct {
#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0)
#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0)
+/* hardware needing special handling due to colliding MSVENDOR page usages */
+#define IS_CHICONY_TACTICAL_PAD(x) (x->vendor == 0x04f2 && device->product == 0x0418)
+#define IS_MS_KB(x) (x->vendor == 0x045e && (x->product == 0x00db || x->product == 0x00f9))
+
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
struct hidinput_key_translation {
@@ -293,9 +297,9 @@ static struct hid_usage *hidinput_find_key(struct hid_device *hid,
static int hidinput_getkeycode(struct input_dev *dev, int scancode,
int *keycode)
{
- struct hid_device *hid = dev->private;
+ struct hid_device *hid = input_get_drvdata(dev);
struct hid_usage *usage;
-
+
usage = hidinput_find_key(hid, scancode, 0);
if (usage) {
*keycode = usage->code;
@@ -307,18 +311,18 @@ static int hidinput_getkeycode(struct input_dev *dev, int scancode,
static int hidinput_setkeycode(struct input_dev *dev, int scancode,
int keycode)
{
- struct hid_device *hid = dev->private;
+ struct hid_device *hid = input_get_drvdata(dev);
struct hid_usage *usage;
int old_keycode;
-
+
if (keycode < 0 || keycode > KEY_MAX)
return -EINVAL;
-
+
usage = hidinput_find_key(hid, scancode, 0);
if (usage) {
old_keycode = usage->code;
usage->code = keycode;
-
+
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", keycode, scancode);
@@ -326,10 +330,10 @@ static int hidinput_setkeycode(struct input_dev *dev, int scancode,
* by another key */
if (hidinput_find_key (hid, 0, old_keycode))
set_bit(old_keycode, dev->keybit);
-
+
return 0;
}
-
+
return -EINVAL;
}
@@ -351,6 +355,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
if (field->flags & HID_MAIN_ITEM_CONSTANT)
goto ignore;
+ /* only LED usages are supported in output fields */
+ if (field->report_type == HID_OUTPUT_REPORT &&
+ (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
+ dbg_hid_line(" [non-LED output field] ");
+ goto ignore;
+ }
+
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_UNDEFINED:
@@ -595,6 +606,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0f6: map_key_clear(KEY_NEXT); break;
case 0x0fa: map_key_clear(KEY_BACK); break;
+ case 0x182: map_key_clear(KEY_BOOKMARKS); break;
case 0x183: map_key_clear(KEY_CONFIG); break;
case 0x184: map_key_clear(KEY_WORDPROCESSOR); break;
case 0x185: map_key_clear(KEY_EDITOR); break;
@@ -611,9 +623,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x192: map_key_clear(KEY_CALC); break;
case 0x194: map_key_clear(KEY_FILE); break;
case 0x196: map_key_clear(KEY_WWW); break;
+ case 0x19c: map_key_clear(KEY_LOGOFF); break;
case 0x19e: map_key_clear(KEY_COFFEE); break;
case 0x1a6: map_key_clear(KEY_HELP); break;
case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
+ case 0x1ab: map_key_clear(KEY_SPELLCHECK); break;
+ case 0x1b6: map_key_clear(KEY_MEDIA); break;
+ case 0x1b7: map_key_clear(KEY_SOUND); break;
case 0x1bc: map_key_clear(KEY_MESSENGER); break;
case 0x1bd: map_key_clear(KEY_INFO); break;
case 0x201: map_key_clear(KEY_NEW); break;
@@ -720,8 +736,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_UP_MSVENDOR:
- /* special case - Chicony Chicony KU-0418 tactical pad */
- if (device->vendor == 0x04f2 && device->product == 0x0418) {
+ /* Unfortunately, there are multiple devices which
+ * emit usages from MSVENDOR page that require different
+ * handling. If this list grows too much in the future,
+ * more general handling will have to be introduced here
+ * (i.e. another blacklist).
+ */
+
+ /* Chicony Chicony KU-0418 tactical pad */
+ if (IS_CHICONY_TACTICAL_PAD(device)) {
set_bit(EV_REP, input->evbit);
switch(usage->hid & HID_USAGE) {
case 0xff01: map_key_clear(BTN_1); break;
@@ -737,6 +760,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0xff0b: map_key_clear(BTN_B); break;
default: goto ignore;
}
+
+ /* Microsoft Natural Ergonomic Keyboard 4000 */
+ } else if (IS_MS_KB(device)) {
+ switch(usage->hid & HID_USAGE) {
+ case 0xfd06:
+ map_key_clear(KEY_CHAT);
+ break;
+ case 0xfd07:
+ map_key_clear(KEY_PHONE);
+ break;
+ case 0xff05:
+ set_bit(EV_REP, input->evbit);
+ map_key_clear(KEY_F13);
+ set_bit(KEY_F14, input->keybit);
+ set_bit(KEY_F15, input->keybit);
+ set_bit(KEY_F16, input->keybit);
+ set_bit(KEY_F17, input->keybit);
+ set_bit(KEY_F18, input->keybit);
+ default: goto ignore;
+ }
} else {
goto ignore;
}
@@ -888,6 +931,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
set_bit(KEY_VOLUMEDOWN, input->keybit);
}
+ if (usage->type == EV_KEY) {
+ set_bit(EV_MSC, input->evbit);
+ set_bit(MSC_SCAN, input->mscbit);
+ }
+
hid_resolv_event(usage->type, usage->code);
dbg_hid_line("\n");
@@ -902,7 +950,7 @@ ignore:
void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
{
struct input_dev *input;
- int *quirks = &hid->quirks;
+ unsigned *quirks = &hid->quirks;
if (!field->hidinput)
return;
@@ -991,6 +1039,29 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
}
+ /* Handling MS keyboards special buttons */
+ if (IS_MS_KB(hid) && usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
+ int key = 0;
+ static int last_key = 0;
+ switch (value) {
+ case 0x01: key = KEY_F14; break;
+ case 0x02: key = KEY_F15; break;
+ case 0x04: key = KEY_F16; break;
+ case 0x08: key = KEY_F17; break;
+ case 0x10: key = KEY_F18; break;
+ default: break;
+ }
+ if (key) {
+ input_event(input, usage->type, key, 1);
+ last_key = key;
+ } else {
+ input_event(input, usage->type, last_key, 0);
+ }
+ }
+ /* report the usage code as scancode if the key status has changed */
+ if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value)
+ input_event(input, EV_MSC, MSC_SCAN, usage->hid);
+
input_event(input, usage->type, usage->code, value);
if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
@@ -1051,6 +1122,9 @@ int hidinput_connect(struct hid_device *hid)
int i, j, k;
int max_report_type = HID_OUTPUT_REPORT;
+ if (hid->quirks & HID_QUIRK_IGNORE_HIDINPUT)
+ return -1;
+
INIT_LIST_HEAD(&hid->inputs);
for (i = 0; i < hid->maxcollection; i++)
@@ -1078,7 +1152,7 @@ int hidinput_connect(struct hid_device *hid)
kfree(hidinput);
input_free_device(input_dev);
err_hid("Out of memory during hid input probe");
- return -1;
+ goto out_unwind;
}
input_set_drvdata(input_dev, hid);
@@ -1112,15 +1186,25 @@ int hidinput_connect(struct hid_device *hid)
* UGCI) cram a lot of unrelated inputs into the
* same interface. */
hidinput->report = report;
- input_register_device(hidinput->input);
+ if (input_register_device(hidinput->input))
+ goto out_cleanup;
hidinput = NULL;
}
}
- if (hidinput)
- input_register_device(hidinput->input);
+ if (hidinput && input_register_device(hidinput->input))
+ goto out_cleanup;
return 0;
+
+out_cleanup:
+ input_free_device(hidinput->input);
+ kfree(hidinput);
+out_unwind:
+ /* unwind the ones we already registered */
+ hidinput_disconnect(hid);
+
+ return -1;
}
EXPORT_SYMBOL_GPL(hidinput_connect);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
new file mode 100644
index 00000000000..1ca6f4635ee
--- /dev/null
+++ b/drivers/hid/hidraw.c
@@ -0,0 +1,407 @@
+/*
+ * HID raw devices, giving access to raw HID events.
+ *
+ * In comparison to hiddev, this device does not process the
+ * hid events at all (no parsing, no lookups). This lets applications
+ * to work on raw hid events as they want to, and avoids a need to
+ * use a transport-specific userspace libhid/libusb libraries.
+ *
+ * Copyright (c) 2007 Jiri Kosina
+ */
+
+/*
+ * 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.
+ *
+ * You 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/fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/poll.h>
+#include <linux/device.h>
+#include <linux/major.h>
+#include <linux/hid.h>
+#include <linux/mutex.h>
+
+#include <linux/hidraw.h>
+
+static int hidraw_major;
+static struct cdev hidraw_cdev;
+static struct class *hidraw_class;
+static struct hidraw *hidraw_table[HIDRAW_MAX_DEVICES];
+static DEFINE_SPINLOCK(minors_lock);
+
+static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+{
+ struct hidraw_list *list = file->private_data;
+ int ret = 0, len;
+ char *report;
+ DECLARE_WAITQUEUE(wait, current);
+
+ while (ret == 0) {
+
+ mutex_lock(&list->read_mutex);
+
+ if (list->head == list->tail) {
+ add_wait_queue(&list->hidraw->wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ while (list->head == list->tail) {
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ if (!list->hidraw->exist) {
+ ret = -EIO;
+ break;
+ }
+
+ /* allow O_NONBLOCK to work well from other threads */
+ mutex_unlock(&list->read_mutex);
+ schedule();
+ mutex_lock(&list->read_mutex);
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&list->hidraw->wait, &wait);
+ }
+
+ if (ret)
+ goto out;
+
+ report = list->buffer[list->tail].value;
+ len = list->buffer[list->tail].len > count ?
+ count : list->buffer[list->tail].len;
+
+ if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ ret += len;
+
+ kfree(list->buffer[list->tail].value);
+ list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
+ }
+out:
+ mutex_unlock(&list->read_mutex);
+ return ret;
+}
+
+/* the first byte is expected to be a report number */
+static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+{
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
+ struct hid_device *dev = hidraw_table[minor]->hid;
+ __u8 *buf;
+ int ret = 0;
+
+ if (!dev->hid_output_raw_report)
+ return -ENODEV;
+
+ if (count > HID_MIN_BUFFER_SIZE) {
+ printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
+ task_pid_nr(current));
+ return -EINVAL;
+ }
+
+ if (count < 2) {
+ printk(KERN_WARNING "hidraw: pid %d passed too short report\n",
+ task_pid_nr(current));
+ return -EINVAL;
+ }
+
+ buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, buffer, count)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = dev->hid_output_raw_report(dev, buf, count);
+out:
+ kfree(buf);
+ return ret;
+}
+
+static unsigned int hidraw_poll(struct file *file, poll_table *wait)
+{
+ struct hidraw_list *list = file->private_data;
+
+ poll_wait(file, &list->hidraw->wait, wait);
+ if (list->head != list->tail)
+ return POLLIN | POLLRDNORM;
+ if (!list->hidraw->exist)
+ return POLLERR | POLLHUP;
+ return 0;
+}
+
+static int hidraw_open(struct inode *inode, struct file *file)
+{
+ unsigned int minor = iminor(inode);
+ struct hidraw *dev;
+ struct hidraw_list *list;
+ int err = 0;
+
+ if (!(list = kzalloc(sizeof(struct hidraw_list), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ spin_lock(&minors_lock);
+ if (!hidraw_table[minor]) {
+ printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n",
+ minor);
+ kfree(list);
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
+ list->hidraw = hidraw_table[minor];
+ mutex_init(&list->read_mutex);
+ list_add_tail(&list->node, &hidraw_table[minor]->list);
+ file->private_data = list;
+
+ dev = hidraw_table[minor];
+ if (!dev->open++)
+ dev->hid->hid_open(dev->hid);
+
+out_unlock:
+ spin_unlock(&minors_lock);
+out:
+ return err;
+
+}
+
+static int hidraw_release(struct inode * inode, struct file * file)
+{
+ unsigned int minor = iminor(inode);
+ struct hidraw *dev;
+ struct hidraw_list *list = file->private_data;
+
+ if (!hidraw_table[minor]) {
+ printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n",
+ minor);
+ return -ENODEV;
+ }
+
+ list_del(&list->node);
+ dev = hidraw_table[minor];
+ if (!dev->open--) {
+ if (list->hidraw->exist)
+ dev->hid->hid_close(dev->hid);
+ else
+ kfree(list->hidraw);
+ }
+
+ return 0;
+}
+
+static int hidraw_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ unsigned int minor = iminor(inode);
+ struct hidraw *dev = hidraw_table[minor];
+ void __user *user_arg = (void __user*) arg;
+
+ switch (cmd) {
+ case HIDIOCGRDESCSIZE:
+ if (put_user(dev->hid->rsize, (int __user *)arg))
+ return -EFAULT;
+ return 0;
+
+ case HIDIOCGRDESC:
+ {
+ __u32 len;
+
+ if (get_user(len, (int __user *)arg))
+ return -EFAULT;
+
+ if (len > HID_MAX_DESCRIPTOR_SIZE - 1)
+ return -EINVAL;
+
+ if (copy_to_user(user_arg + offsetof(
+ struct hidraw_report_descriptor,
+ value[0]),
+ dev->hid->rdesc,
+ min(dev->hid->rsize, len)))
+ return -EFAULT;
+ return 0;
+ }
+ case HIDIOCGRAWINFO:
+ {
+ struct hidraw_devinfo dinfo;
+
+ dinfo.bustype = dev->hid->bus;
+ dinfo.vendor = dev->hid->vendor;
+ dinfo.product = dev->hid->product;
+ if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
+ return -EFAULT;
+
+ return 0;
+ }
+ default:
+ printk(KERN_EMERG "hidraw: unsupported ioctl() %x\n",
+ cmd);
+ }
+ return -EINVAL;
+}
+
+static const struct file_operations hidraw_ops = {
+ .owner = THIS_MODULE,
+ .read = hidraw_read,
+ .write = hidraw_write,
+ .poll = hidraw_poll,
+ .open = hidraw_open,
+ .release = hidraw_release,
+ .ioctl = hidraw_ioctl,
+};
+
+void hidraw_report_event(struct hid_device *hid, u8 *data, int len)
+{
+ struct hidraw *dev = hid->hidraw;
+ struct hidraw_list *list;
+
+ list_for_each_entry(list, &dev->list, node) {
+ list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC);
+ list->buffer[list->head].len = len;
+ list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
+ kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ }
+
+ wake_up_interruptible(&dev->wait);
+}
+EXPORT_SYMBOL_GPL(hidraw_report_event);
+
+int hidraw_connect(struct hid_device *hid)
+{
+ int minor, result;
+ struct hidraw *dev;
+
+ /* TODO currently we accept any HID device. This should later
+ * probably be fixed to accept only those devices which provide
+ * non-input applications
+ */
+
+ dev = kzalloc(sizeof(struct hidraw), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ result = -EINVAL;
+
+ spin_lock(&minors_lock);
+
+ for (minor = 0; minor < HIDRAW_MAX_DEVICES; minor++) {
+ if (hidraw_table[minor])
+ continue;
+ hidraw_table[minor] = dev;
+ result = 0;
+ break;
+ }
+
+ spin_unlock(&minors_lock);
+
+ if (result) {
+ kfree(dev);
+ goto out;
+ }
+
+ dev->dev = device_create(hidraw_class, NULL, MKDEV(hidraw_major, minor),
+ "%s%d", "hidraw", minor);
+
+ if (IS_ERR(dev->dev)) {
+ spin_lock(&minors_lock);
+ hidraw_table[minor] = NULL;
+ spin_unlock(&minors_lock);
+ result = PTR_ERR(dev->dev);
+ kfree(dev);
+ goto out;
+ }
+
+ init_waitqueue_head(&dev->wait);
+ INIT_LIST_HEAD(&dev->list);
+
+ dev->hid = hid;
+ dev->minor = minor;
+
+ dev->exist = 1;
+ hid->hidraw = dev;
+
+out:
+ return result;
+
+}
+EXPORT_SYMBOL_GPL(hidraw_connect);
+
+void hidraw_disconnect(struct hid_device *hid)
+{
+ struct hidraw *hidraw = hid->hidraw;
+
+ hidraw->exist = 0;
+
+ spin_lock(&minors_lock);
+ hidraw_table[hidraw->minor] = NULL;
+ spin_unlock(&minors_lock);
+
+ device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
+
+ if (hidraw->open) {
+ hid->hid_close(hid);
+ wake_up_interruptible(&hidraw->wait);
+ } else {
+ kfree(hidraw);
+ }
+}
+EXPORT_SYMBOL_GPL(hidraw_disconnect);
+
+int __init hidraw_init(void)
+{
+ int result;
+ dev_t dev_id;
+
+ result = alloc_chrdev_region(&dev_id, HIDRAW_FIRST_MINOR,
+ HIDRAW_MAX_DEVICES, "hidraw");
+
+ hidraw_major = MAJOR(dev_id);
+
+ if (result < 0) {
+ printk(KERN_WARNING "hidraw: can't get major number\n");
+ result = 0;
+ goto out;
+ }
+
+ hidraw_class = class_create(THIS_MODULE, "hidraw");
+ if (IS_ERR(hidraw_class)) {
+ result = PTR_ERR(hidraw_class);
+ unregister_chrdev(hidraw_major, "hidraw");
+ goto out;
+ }
+
+ cdev_init(&hidraw_cdev, &hidraw_ops);
+ cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
+out:
+ return result;
+}
+
+void __exit hidraw_exit(void)
+{
+ dev_t dev_id = MKDEV(hidraw_major, 0);
+
+ cdev_del(&hidraw_cdev);
+ class_destroy(hidraw_class);
+ unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
+
+}
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index 1b4b572f899..c557d7040a6 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -71,19 +71,20 @@ config LOGITECH_FF
force feedback.
config PANTHERLORD_FF
- bool "PantherLord USB/PS2 2in1 Adapter support"
+ bool "PantherLord/GreenAsia based device support"
depends on HID_FF
select INPUT_FF_MEMLESS if USB_HID
help
- Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
- to enable force feedback support for it.
+ Say Y here if you have a PantherLord/GreenAsia based game controller
+ or adapter and want to enable force feedback support for it.
config THRUSTMASTER_FF
- bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
+ bool "ThrustMaster devices support (EXPERIMENTAL)"
depends on HID_FF && EXPERIMENTAL
select INPUT_FF_MEMLESS if USB_HID
help
- Say Y here if you have a THRUSTMASTER FireStore Dual Power 2,
+ Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
+ a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel,
and want to enable force feedback support for it.
Note: if you say N here, this device will still be supported, but without
force feedback.
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 0a1f2b52a12..b38e559b7a4 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -32,6 +32,7 @@
#include <linux/hid.h>
#include <linux/hiddev.h>
#include <linux/hid-debug.h>
+#include <linux/hidraw.h>
#include "usbhid.h"
/*
@@ -512,7 +513,16 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
int usbhid_open(struct hid_device *hid)
{
- ++hid->open;
+ struct usbhid_device *usbhid = hid->driver_data;
+ int res;
+
+ if (!hid->open++) {
+ res = usb_autopm_get_interface(usbhid->intf);
+ if (res < 0) {
+ hid->open--;
+ return -EIO;
+ }
+ }
if (hid_start_in(hid))
hid_io_error(hid);
return 0;
@@ -522,8 +532,10 @@ void usbhid_close(struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
- if (!--hid->open)
+ if (!--hid->open) {
usb_kill_urb(usbhid->urbin);
+ usb_autopm_put_interface(usbhid->intf);
+ }
}
/*
@@ -628,6 +640,28 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
return 0;
}
+static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+ struct usb_device *dev = hid_to_usb_dev(hid);
+ struct usb_interface *intf = usbhid->intf;
+ struct usb_host_interface *interface = intf->cur_altsetting;
+ int ret;
+
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ HID_REQ_SET_REPORT,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ cpu_to_le16(((HID_OUTPUT_REPORT + 1) << 8) | *buf),
+ interface->desc.bInterfaceNumber, buf + 1, count - 1,
+ USB_CTRL_SET_TIMEOUT);
+
+ /* count also the report id */
+ if (ret > 0)
+ ret++;
+
+ return ret;
+}
+
static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
@@ -871,6 +905,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
hid->hiddev_hid_event = hiddev_hid_event;
hid->hiddev_report_event = hiddev_report_event;
#endif
+ hid->hid_output_raw_report = usbhid_output_raw_report;
return hid;
fail:
@@ -909,6 +944,8 @@ static void hid_disconnect(struct usb_interface *intf)
hidinput_disconnect(hid);
if (hid->claimed & HID_CLAIMED_HIDDEV)
hiddev_disconnect(hid);
+ if (hid->claimed & HID_CLAIMED_HIDRAW)
+ hidraw_disconnect(hid);
usb_free_urb(usbhid->urbin);
usb_free_urb(usbhid->urbctrl);
@@ -941,11 +978,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
hid->claimed |= HID_CLAIMED_INPUT;
if (!hiddev_connect(hid))
hid->claimed |= HID_CLAIMED_HIDDEV;
+ if (!hidraw_connect(hid))
+ hid->claimed |= HID_CLAIMED_HIDRAW;
usb_set_intfdata(intf, hid);
if (!hid->claimed) {
- printk ("HID device not claimed by input or hiddev\n");
+ printk ("HID device claimed by neither input, hiddev nor hidraw\n");
hid_disconnect(intf);
return -ENODEV;
}
@@ -961,10 +1000,16 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (hid->claimed & HID_CLAIMED_INPUT)
printk("input");
- if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))
+ if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) ||
+ hid->claimed & HID_CLAIMED_HIDRAW))
printk(",");
if (hid->claimed & HID_CLAIMED_HIDDEV)
printk("hiddev%d", hid->minor);
+ if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) &&
+ (hid->claimed & HID_CLAIMED_HIDRAW))
+ printk(",");
+ if (hid->claimed & HID_CLAIMED_HIDRAW)
+ printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor);
c = "Device";
for (i = 0; i < hid->maxcollection; i++) {
@@ -1048,6 +1093,7 @@ static struct usb_driver hid_driver = {
.pre_reset = hid_pre_reset,
.post_reset = hid_post_reset,
.id_table = hid_usb_ids,
+ .supports_autosuspend = 1,
};
static int __init hid_init(void)
diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c
index 23431fbbc3d..4c210e16b1b 100644
--- a/drivers/hid/usbhid/hid-ff.c
+++ b/drivers/hid/usbhid/hid-ff.c
@@ -1,6 +1,4 @@
/*
- * $Id: hid-ff.c,v 1.2 2002/04/18 22:02:47 jdeneux Exp $
- *
* Force feedback support for hid devices.
* Not all hid devices use the same protocol. For example, some use PID,
* other use their own proprietary procotol.
@@ -62,11 +60,14 @@ static struct hid_ff_initializer inits[] = {
{ 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
#endif
#ifdef CONFIG_PANTHERLORD_FF
- { 0x810, 0x0001, hid_plff_init },
+ { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */
+ { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */
#endif
#ifdef CONFIG_THRUSTMASTER_FF
{ 0x44f, 0xb300, hid_tmff_init },
{ 0x44f, 0xb304, hid_tmff_init },
+ { 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */
+ { 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */
#endif
#ifdef CONFIG_ZEROPLUS_FF
{ 0xc12, 0x0005, hid_zpff_init },
diff --git a/drivers/hid/usbhid/hid-plff.c b/drivers/hid/usbhid/hid-plff.c
index d6a8f2b49bd..9eb83cf9d22 100644
--- a/drivers/hid/usbhid/hid-plff.c
+++ b/drivers/hid/usbhid/hid-plff.c
@@ -1,5 +1,15 @@
/*
- * Force feedback support for PantherLord USB/PS2 2in1 Adapter devices
+ * Force feedback support for PantherLord/GreenAsia based devices
+ *
+ * The devices are distributed under various names and the same USB device ID
+ * can be used in both adapters and actual game controllers.
+ *
+ * 0810:0001 "Twin USB Joystick"
+ * - tested with PantherLord USB/PS2 2in1 Adapter
+ * - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT)
+ *
+ * 0e8f:0003 "GreenAsia Inc. USB Joystick "
+ * - tested with Köng Gaming gamepad
*
* Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
*/
@@ -67,11 +77,11 @@ int hid_plff_init(struct hid_device *hid)
struct input_dev *dev;
int error;
- /* The device contains 2 output reports (one for each
- HID_QUIRK_MULTI_INPUT device), both containing 1 field, which
- contains 4 ff00.0002 usages and 4 16bit absolute values.
+ /* The device contains one output report per physical device, all
+ containing 1 field, which contains 4 ff00.0002 usages and 4 16bit
+ absolute values.
- The 2 input reports also contain a field which contains
+ The input reports also contain a field which contains
8 ff00.0001 usages and 8 boolean values. Their meaning is
currently unknown. */
@@ -122,8 +132,8 @@ int hid_plff_init(struct hid_device *hid)
usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
}
- printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 "
- "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n");
+ printk(KERN_INFO "hid-plff: Force feedback for PantherLord/GreenAsia "
+ "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 6b21a214f41..a2552856476 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -61,6 +61,7 @@
#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
+#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
#define USB_VENDOR_ID_ASUS 0x0b05
#define USB_DEVICE_ID_ASUS_LCM 0x1726
@@ -86,6 +87,9 @@
#define USB_VENDOR_ID_CIDC 0x1677
+#define USB_VENDOR_ID_CMEDIA 0x0d8c
+#define USB_DEVICE_ID_CM109 0x000e
+
#define USB_VENDOR_ID_CODEMERCS 0x07c0
#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500
#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff
@@ -104,12 +108,17 @@
#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
+#define USB_VENDOR_ID_ELO 0x04E7
+#define USB_DEVICE_ID_ELO_TS2700 0x0020
+
#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
#define USB_VENDOR_ID_GAMERON 0x0810
#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001
+#define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc
+
#define USB_VENDOR_ID_GLAB 0x06c2
#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039
@@ -120,6 +129,11 @@
#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053
#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058
+#define USB_VENDOR_ID_GOTOP 0x08f2
+#define USB_DEVICE_ID_SUPER_Q2 0x007f
+#define USB_DEVICE_ID_GOGOPEN 0x00ce
+#define USB_DEVICE_ID_PENPOWER 0x00f4
+
#define USB_VENDOR_ID_GRIFFIN 0x077d
#define USB_DEVICE_ID_POWERMATE 0x0410
#define USB_DEVICE_ID_SOUNDKNOB 0x04AA
@@ -373,6 +387,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
{ USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
@@ -387,11 +402,16 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE},
{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GENERAL_TOUCH, 0x0001, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GENERAL_TOUCH, 0x0002, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GENERAL_TOUCH, 0x0003, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GENERAL_TOUCH, 0x0004, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
@@ -400,6 +420,9 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE },
@@ -507,6 +530,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
@@ -614,6 +638,8 @@ static const struct hid_rdesc_blacklist {
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS },
+
{ USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
@@ -927,6 +953,18 @@ static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
printk(KERN_INFO "Fixing up Cypress report descriptor\n");
}
+/*
+ * MacBook JIS keyboard has wrong logical maximum
+ */
+static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize)
+{
+ if (rsize >= 60 && rdesc[53] == 0x65
+ && rdesc[59] == 0x65) {
+ printk(KERN_INFO "Fixing up MacBook JIS keyboard report descriptor\n");
+ rdesc[53] = rdesc[59] = 0xe7;
+ }
+}
+
static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
{
@@ -941,6 +979,9 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned
if (quirks & HID_QUIRK_RDESC_PETALYNX)
usbhid_fixup_petalynx_descriptor(rdesc, rsize);
+
+ if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS)
+ usbhid_fixup_macbook_descriptor(rdesc, rsize);
}
/**
diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c
index 555bb48b429..69882a726e9 100644
--- a/drivers/hid/usbhid/hid-tmff.c
+++ b/drivers/hid/usbhid/hid-tmff.c
@@ -36,16 +36,39 @@
#include "usbhid.h"
/* Usages for thrustmaster devices I know about */
-#define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb)
+#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb)
+struct dev_type {
+ u16 idVendor;
+ u16 idProduct;
+ const signed short *ff;
+};
+
+static const signed short ff_rumble[] = {
+ FF_RUMBLE,
+ -1
+};
+
+static const signed short ff_joystick[] = {
+ FF_CONSTANT,
+ -1
+};
+
+static const struct dev_type devices[] = {
+ { 0x44f, 0xb300, ff_rumble },
+ { 0x44f, 0xb304, ff_rumble },
+ { 0x44f, 0xb651, ff_rumble }, /* FGT Rumble Force Wheel */
+ { 0x44f, 0xb654, ff_joystick }, /* FGT Force Feedback Wheel */
+};
struct tmff_device {
struct hid_report *report;
- struct hid_field *rumble;
+ struct hid_field *ff_field;
};
/* Changes values from 0 to 0xffff into values from minimum to maximum */
-static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
+static inline int hid_tmff_scale_u16(unsigned int in,
+ int minimum, int maximum)
{
int ret;
@@ -57,22 +80,57 @@ static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
return ret;
}
+/* Changes values from -0x80 to 0x7f into values from minimum to maximum */
+static inline int hid_tmff_scale_s8(int in,
+ int minimum, int maximum)
+{
+ int ret;
+
+ ret = (((in + 0x80) * (maximum - minimum)) / 0xff) + minimum;
+ if (ret < minimum)
+ return minimum;
+ if (ret > maximum)
+ return maximum;
+ return ret;
+}
+
static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
{
struct hid_device *hid = input_get_drvdata(dev);
struct tmff_device *tmff = data;
+ struct hid_field *ff_field = tmff->ff_field;
+ int x, y;
int left, right; /* Rumbling */
- left = hid_tmff_scale(effect->u.rumble.weak_magnitude,
- tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
- right = hid_tmff_scale(effect->u.rumble.strong_magnitude,
- tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
-
- tmff->rumble->value[0] = left;
- tmff->rumble->value[1] = right;
- dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
- usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
-
+ switch (effect->type) {
+ case FF_CONSTANT:
+ x = hid_tmff_scale_s8(effect->u.ramp.start_level,
+ ff_field->logical_minimum,
+ ff_field->logical_maximum);
+ y = hid_tmff_scale_s8(effect->u.ramp.end_level,
+ ff_field->logical_minimum,
+ ff_field->logical_maximum);
+
+ dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
+ ff_field->value[0] = x;
+ ff_field->value[1] = y;
+ usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+ break;
+
+ case FF_RUMBLE:
+ left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude,
+ ff_field->logical_minimum,
+ ff_field->logical_maximum);
+ right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude,
+ ff_field->logical_minimum,
+ ff_field->logical_maximum);
+
+ dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
+ ff_field->value[0] = left;
+ ff_field->value[1] = right;
+ usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
+ break;
+ }
return 0;
}
@@ -82,14 +140,16 @@ int hid_tmff_init(struct hid_device *hid)
struct list_head *pos;
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
struct input_dev *input_dev = hidinput->input;
+ const signed short *ff_bits = ff_joystick;
int error;
+ int i;
tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
if (!tmff)
return -ENOMEM;
/* Find the report to use */
- __list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
+ list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
struct hid_report *report = (struct hid_report *)pos;
int fieldnum;
@@ -100,48 +160,65 @@ int hid_tmff_init(struct hid_device *hid)
continue;
switch (field->usage[0].hid) {
- case THRUSTMASTER_USAGE_RUMBLE_LR:
- if (field->report_count < 2) {
- warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with report_count < 2");
- continue;
- }
+ case THRUSTMASTER_USAGE_FF:
+ if (field->report_count < 2) {
+ warn("ignoring FF field with report_count < 2");
+ continue;
+ }
- if (field->logical_maximum == field->logical_minimum) {
- warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR with logical_maximum == logical_minimum");
- continue;
- }
+ if (field->logical_maximum == field->logical_minimum) {
+ warn("ignoring FF field with logical_maximum == logical_minimum");
+ continue;
+ }
- if (tmff->report && tmff->report != report) {
- warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report");
- continue;
- }
+ if (tmff->report && tmff->report != report) {
+ warn("ignoring FF field in other report");
+ continue;
+ }
- if (tmff->rumble && tmff->rumble != field) {
- warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR");
- continue;
+ if (tmff->ff_field && tmff->ff_field != field) {
+ warn("ignoring duplicate FF field");
+ continue;
+ }
+
+ tmff->report = report;
+ tmff->ff_field = field;
+
+ for (i = 0; i < ARRAY_SIZE(devices); i++) {
+ if (input_dev->id.vendor == devices[i].idVendor &&
+ input_dev->id.product == devices[i].idProduct) {
+ ff_bits = devices[i].ff;
+ break;
}
+ }
- tmff->report = report;
- tmff->rumble = field;
+ for (i = 0; ff_bits[i] >= 0; i++)
+ set_bit(ff_bits[i], input_dev->ffbit);
- set_bit(FF_RUMBLE, input_dev->ffbit);
- break;
+ break;
- default:
- warn("ignoring unknown output usage %08x", field->usage[0].hid);
- continue;
+ default:
+ warn("ignoring unknown output usage %08x", field->usage[0].hid);
+ continue;
}
}
}
- error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
- if (error) {
- kfree(tmff);
- return error;
+ if (!tmff->report) {
+ err("cant find FF field in output reports\n");
+ error = -ENODEV;
+ goto fail;
}
- info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>");
+ error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
+ if (error)
+ goto fail;
+ info("Force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>");
return 0;
+
+ fail:
+ kfree(tmff);
+ return error;
}
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index e793127f971..5fc4019956b 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -34,6 +34,7 @@
#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/hiddev.h>
+#include <linux/compat.h>
#include "usbhid.h"
#ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -738,6 +739,14 @@ inval:
return -EINVAL;
}
+#ifdef CONFIG_COMPAT
+static long hiddev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ return hiddev_ioctl(inode, file, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
static const struct file_operations hiddev_fops = {
.owner = THIS_MODULE,
.read = hiddev_read,
@@ -747,6 +756,9 @@ static const struct file_operations hiddev_fops = {
.release = hiddev_release,
.ioctl = hiddev_ioctl,
.fasync = hiddev_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = hiddev_compat_ioctl,
+#endif
};
static struct usb_class_driver hiddev_class = {
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index b76b02f7b52..775a1ef28a2 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -274,8 +274,11 @@ static int usb_kbd_probe(struct usb_interface *iface,
input_set_drvdata(input_dev, kbd);
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
- input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
+ BIT_MASK(EV_REP);
+ input_dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
+ BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_COMPOSE) |
+ BIT_MASK(LED_KANA);
for (i = 0; i < 255; i++)
set_bit(usb_kbd_keycode[i], input_dev->keybit);
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index 5345c73bcf6..f8ad6910d3d 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -173,11 +173,13 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
usb_to_input_id(dev, &input_dev->id);
input_dev->dev.parent = &intf->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
- input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
- input_dev->relbit[0] |= BIT(REL_WHEEL);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
+ input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+ input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |
+ BIT_MASK(BTN_EXTRA);
+ input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);
input_set_drvdata(input_dev, mouse);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 192953b29b2..a0445bea9f7 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -30,7 +30,7 @@ config HWMON_VID
config SENSORS_ABITUGURU
tristate "Abit uGuru (rev 1 & 2)"
- depends on EXPERIMENTAL
+ depends on X86 && EXPERIMENTAL
help
If you say yes here you get support for the sensor part of the first
and second revision of the Abit uGuru chip. The voltage and frequency
@@ -45,7 +45,7 @@ config SENSORS_ABITUGURU
config SENSORS_ABITUGURU3
tristate "Abit uGuru (rev 3)"
- depends on HWMON && EXPERIMENTAL
+ depends on X86 && EXPERIMENTAL
help
If you say yes here you get support for the sensor part of the
third revision of the Abit uGuru chip. Only reading the sensors
@@ -133,6 +133,16 @@ config SENSORS_ADM9240
This driver can also be built as a module. If so, the module
will be called adm9240.
+config SENSORS_ADT7470
+ tristate "Analog Devices ADT7470"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Analog Devices
+ ADT7470 temperature monitoring chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called adt7470.
+
config SENSORS_K8TEMP
tristate "AMD Athlon64/FX or Opteron temperature sensor"
depends on X86 && PCI && EXPERIMENTAL
@@ -148,6 +158,7 @@ config SENSORS_K8TEMP
config SENSORS_AMS
tristate "Apple Motion Sensor driver"
depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
+ select INPUT_POLLDEV
help
Support for the motion sensor included in PowerBooks. Includes
implementations for PMU and I2C.
@@ -172,7 +183,7 @@ config SENSORS_AMS_I2C
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
- depends on I2C && EXPERIMENTAL
+ depends on X86 && I2C && EXPERIMENTAL
select HWMON_VID
help
If you say yes here you get support for the ASB100 Bach sensor
@@ -205,20 +216,50 @@ config SENSORS_DS1621
This driver can also be built as a module. If so, the module
will be called ds1621.
+config SENSORS_I5K_AMB
+ tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
+ depends on PCI && EXPERIMENTAL
+ help
+ If you say yes here you get support for FB-DIMM AMB temperature
+ monitoring chips on systems with the Intel 5000 series chipset.
+
+ This driver can also be built as a module. If so, the module
+ will be called i5k_amb.
+
config SENSORS_F71805F
- tristate "Fintek F71805F/FG and F71872F/FG"
+ tristate "Fintek F71805F/FG, F71806F/FG and F71872F/FG"
depends on EXPERIMENTAL
help
If you say yes here you get support for hardware monitoring
- features of the Fintek F71805F/FG and F71872F/FG Super-I/O
- chips.
+ features of the Fintek F71805F/FG, F71806F/FG and F71872F/FG
+ Super-I/O chips.
This driver can also be built as a module. If so, the module
will be called f71805f.
+config SENSORS_F71882FG
+ tristate "Fintek F71882FG and F71883FG"
+ depends on EXPERIMENTAL
+ help
+ If you say yes here you get support for hardware monitoring
+ features of the Fintek F71882FG and F71883FG Super-I/O chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called f71882fg.
+
+config SENSORS_F75375S
+ tristate "Fintek F75375S/SP and F75373";
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for hardware monitoring
+ features of the Fintek F75375S/SP and F75373
+
+ This driver can also be built as a module. If so, the module
+ will be called f75375s.
+
config SENSORS_FSCHER
tristate "FSC Hermes"
- depends on I2C
+ depends on X86 && I2C
help
If you say yes here you get support for Fujitsu Siemens
Computers Hermes sensor chips.
@@ -228,7 +269,7 @@ config SENSORS_FSCHER
config SENSORS_FSCPOS
tristate "FSC Poseidon"
- depends on I2C
+ depends on X86 && I2C
help
If you say yes here you get support for Fujitsu Siemens
Computers Poseidon sensor chips.
@@ -236,6 +277,20 @@ config SENSORS_FSCPOS
This driver can also be built as a module. If so, the module
will be called fscpos.
+config SENSORS_FSCHMD
+ tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles"
+ depends on X86 && I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for various Fujitsu Siemens
+ Computers sensor chips.
+
+ This is a new merged driver for FSC sensor chips which is intended
+ as a replacment for the fscpos, fscscy and fscher drivers and adds
+ support for several other FCS sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called fschmd.
+
config SENSORS_GL518SM
tristate "Genesys Logic GL518SM"
depends on I2C
@@ -265,6 +320,19 @@ config SENSORS_CORETEMP
sensor inside your CPU. Supported all are all known variants
of Intel Core family.
+config SENSORS_IBMPEX
+ tristate "IBM PowerExecutive temperature/power sensors"
+ select IPMI_SI
+ depends on IPMI_HANDLER
+ help
+ If you say yes here you get support for the temperature and
+ power sensors in various IBM System X servers that support
+ PowerExecutive. So far this includes the x3550, x3650, x3655,
+ x3755, and certain HS20 blades.
+
+ This driver can also be built as a module. If so, the module
+ will be called ibmpex.
+
config SENSORS_IT87
tristate "ITE IT87xx and compatibles"
select HWMON_VID
@@ -401,7 +469,7 @@ config SENSORS_LM92
config SENSORS_LM93
tristate "National Semiconductor LM93 and compatibles"
- depends on HWMON && I2C
+ depends on I2C
select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM93
@@ -466,13 +534,13 @@ config SENSORS_SIS5595
will be called sis5595.
config SENSORS_DME1737
- tristate "SMSC DME1737 and compatibles"
+ tristate "SMSC DME1737, SCH311x and compatibles"
depends on I2C && EXPERIMENTAL
select HWMON_VID
help
If you say yes here you get support for the hardware monitoring
and fan control features of the SMSC DME1737 (and compatibles
- like the Asus A8000) Super-I/O chip.
+ like the Asus A8000) and SCH311x Super-I/O chips.
This driver can also be built as a module. If so, the module
will be called dme1737.
@@ -644,6 +712,7 @@ config SENSORS_W83627EHF
config SENSORS_HDAPS
tristate "IBM Hard Drive Active Protection System (hdaps)"
depends on INPUT && X86
+ select INPUT_POLLDEV
default n
help
This driver provides support for the IBM Hard Drive Active Protection
@@ -665,6 +734,7 @@ config SENSORS_APPLESMC
depends on INPUT && X86
select NEW_LEDS
select LEDS_CLASS
+ select INPUT_POLLDEV
default n
help
This driver provides support for the Apple System Management
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index d04f90031eb..55595f6e1aa 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
+obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_AMS) += ams/
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
@@ -29,11 +30,16 @@ obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
+obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
+obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
+obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o
obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
+obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
+obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
obj-$(CONFIG_SENSORS_LM63) += lm63.o
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index d575ee958de..4dbdb81ea3b 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -176,7 +176,7 @@ MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n"
The structure is dynamically allocated, at the same time when a new
abituguru device is allocated. */
struct abituguru_data {
- struct class_device *class_dev; /* hwmon registered device */
+ struct device *hwmon_dev; /* hwmon registered device */
struct mutex update_lock; /* protect access to data and uGuru */
unsigned long last_updated; /* In jiffies */
unsigned short addr; /* uguru base address */
@@ -1287,11 +1287,11 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
&abituguru_sysfs_attr[i].dev_attr))
goto abituguru_probe_error;
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (!IS_ERR(data->class_dev))
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (!IS_ERR(data->hwmon_dev))
return 0; /* success */
- res = PTR_ERR(data->class_dev);
+ res = PTR_ERR(data->hwmon_dev);
abituguru_probe_error:
for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
@@ -1308,7 +1308,7 @@ static int __devexit abituguru_remove(struct platform_device *pdev)
int i;
struct abituguru_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
@@ -1449,7 +1449,7 @@ static int __init abituguru_init(void)
struct resource res = { .flags = IORESOURCE_IO };
#ifdef CONFIG_DMI
- char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+ const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
/* safety check, refuse to load on non Abit motherboards */
if (!force && (!board_vendor ||
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index cdd8b6dea16..d9f04ce9032 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -124,7 +124,7 @@ struct abituguru3_motherboard_info {
The structure is dynamically allocated, at the same time when a new
abituguru3 device is allocated. */
struct abituguru3_data {
- struct class_device *class_dev; /* hwmon registered device */
+ struct device *hwmon_dev; /* hwmon registered device */
struct mutex update_lock; /* protect access to data and uGuru */
unsigned short addr; /* uguru base address */
char valid; /* !=0 if following fields are valid */
@@ -503,7 +503,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
{ "AUX3 FAN", 36, 2, 60, 1, 0 },
{ NULL, 0, 0, 0, 0, 0 } }
},
- { 0x001A, "unknown", {
+ { 0x001A, "Abit IP35 Pro", {
{ "CPU Core", 0, 0, 10, 1, 0 },
{ "DDR2", 1, 0, 20, 1, 0 },
{ "DDR2 VTT", 2, 0, 10, 1, 0 },
@@ -530,6 +530,60 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
{ "AUX3 Fan", 36, 2, 60, 1, 0 },
{ NULL, 0, 0, 0, 0, 0 } }
},
+ { 0x001B, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR3", 1, 0, 20, 1, 0 },
+ { "DDR3 VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT", 3, 0, 10, 1, 0 },
+ { "MCH 1.25V", 4, 0, 10, 1, 0 },
+ { "ICHIO 1.5V", 5, 0, 10, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (8-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System", 25, 1, 1, 1, 0 },
+ { "PWM Phase1", 26, 1, 1, 1, 0 },
+ { "PWM Phase2", 27, 1, 1, 1, 0 },
+ { "PWM Phase3", 28, 1, 1, 1, 0 },
+ { "PWM Phase4", 29, 1, 1, 1, 0 },
+ { "PWM Phase5", 30, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 33, 2, 60, 1, 0 },
+ { "AUX2 Fan", 35, 2, 60, 1, 0 },
+ { "AUX3 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x001C, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR2", 1, 0, 20, 1, 0 },
+ { "DDR2 VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT", 3, 0, 10, 1, 0 },
+ { "MCH 1.25V", 4, 0, 10, 1, 0 },
+ { "ICHIO 1.5V", 5, 0, 10, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (8-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System", 25, 1, 1, 1, 0 },
+ { "PWM Phase1", 26, 1, 1, 1, 0 },
+ { "PWM Phase2", 27, 1, 1, 1, 0 },
+ { "PWM Phase3", 28, 1, 1, 1, 0 },
+ { "PWM Phase4", 29, 1, 1, 1, 0 },
+ { "PWM Phase5", 30, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 33, 2, 60, 1, 0 },
+ { "AUX2 Fan", 35, 2, 60, 1, 0 },
+ { "AUX3 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
{ 0x0000, NULL, { { NULL, 0, 0, 0, 0, 0 } } }
};
@@ -933,9 +987,9 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
&abituguru3_sysfs_attr[i].dev_attr))
goto abituguru3_probe_error;
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- res = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ res = PTR_ERR(data->hwmon_dev);
goto abituguru3_probe_error;
}
@@ -957,7 +1011,7 @@ static int __devexit abituguru3_remove(struct platform_device *pdev)
struct abituguru3_data *data = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c
index cc8b624a1e5..fcd7fe78f3f 100644
--- a/drivers/hwmon/ad7418.c
+++ b/drivers/hwmon/ad7418.c
@@ -47,7 +47,7 @@ static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN,
struct ad7418_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct attribute_group attrs;
enum chips type;
struct mutex lock;
@@ -172,7 +172,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct ad7418_data *data = i2c_get_clientdata(client);
- int temp = simple_strtol(buf, NULL, 10);
+ long temp = simple_strtol(buf, NULL, 10);
mutex_lock(&data->lock);
data->temp[attr->index] = LM75_TEMP_TO_REG(temp);
@@ -326,9 +326,9 @@ static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -347,7 +347,7 @@ exit:
static int ad7418_detach_client(struct i2c_client *client)
{
struct ad7418_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &data->attrs);
i2c_detach_client(client);
kfree(data);
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index c466329b2ef..ebdc6d7db23 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -1,6 +1,6 @@
/*
adm1021.c - Part of lm_sensors, Linux kernel modules for hardware
- monitoring
+ monitoring
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
Philip Edelbrock <phil@netroedge.com>
@@ -25,6 +25,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
@@ -32,93 +33,77 @@
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
0x29, 0x2a, 0x2b,
- 0x4c, 0x4d, 0x4e,
+ 0x4c, 0x4d, 0x4e,
I2C_CLIENT_END };
/* Insmod parameters */
-I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066);
+I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm,
+ mc1066);
/* adm1021 constants specified below */
/* The adm1021 registers */
/* Read-only */
-#define ADM1021_REG_TEMP 0x00
-#define ADM1021_REG_REMOTE_TEMP 0x01
+/* For nr in 0-1 */
+#define ADM1021_REG_TEMP(nr) (nr)
#define ADM1021_REG_STATUS 0x02
-#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/
-#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */
-#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */
+/* 0x41 = AD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi */
+#define ADM1021_REG_MAN_ID 0xFE
+/* ADM1021 = 0x0X, ADM1023 = 0x3X */
+#define ADM1021_REG_DEV_ID 0xFF
/* These use different addresses for reading/writing */
#define ADM1021_REG_CONFIG_R 0x03
#define ADM1021_REG_CONFIG_W 0x09
#define ADM1021_REG_CONV_RATE_R 0x04
#define ADM1021_REG_CONV_RATE_W 0x0A
/* These are for the ADM1023's additional precision on the remote temp sensor */
-#define ADM1021_REG_REM_TEMP_PREC 0x010
-#define ADM1021_REG_REM_OFFSET 0x011
-#define ADM1021_REG_REM_OFFSET_PREC 0x012
-#define ADM1021_REG_REM_TOS_PREC 0x013
-#define ADM1021_REG_REM_THYST_PREC 0x014
+#define ADM1023_REG_REM_TEMP_PREC 0x10
+#define ADM1023_REG_REM_OFFSET 0x11
+#define ADM1023_REG_REM_OFFSET_PREC 0x12
+#define ADM1023_REG_REM_TOS_PREC 0x13
+#define ADM1023_REG_REM_THYST_PREC 0x14
/* limits */
-#define ADM1021_REG_TOS_R 0x05
-#define ADM1021_REG_TOS_W 0x0B
-#define ADM1021_REG_REMOTE_TOS_R 0x07
-#define ADM1021_REG_REMOTE_TOS_W 0x0D
-#define ADM1021_REG_THYST_R 0x06
-#define ADM1021_REG_THYST_W 0x0C
-#define ADM1021_REG_REMOTE_THYST_R 0x08
-#define ADM1021_REG_REMOTE_THYST_W 0x0E
+/* For nr in 0-1 */
+#define ADM1021_REG_TOS_R(nr) (0x05 + 2 * (nr))
+#define ADM1021_REG_TOS_W(nr) (0x0B + 2 * (nr))
+#define ADM1021_REG_THYST_R(nr) (0x06 + 2 * (nr))
+#define ADM1021_REG_THYST_W(nr) (0x0C + 2 * (nr))
/* write-only */
#define ADM1021_REG_ONESHOT 0x0F
-
-/* Conversions. Rounding and limit checking is only done on the TO_REG
- variants. Note that you should be a bit careful with which arguments
- these macros are called: arguments may be evaluated more than once.
- Fixing this is just not worth it. */
-/* Conversions note: 1021 uses normal integer signed-byte format*/
-#define TEMP_FROM_REG(val) (val > 127 ? (val-256)*1000 : val*1000)
-#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? (val/1000)+256 : val/1000),0,255))
-
/* Initial values */
-/* Note: Even though I left the low and high limits named os and hyst,
-they don't quite work like a thermostat the way the LM75 does. I.e.,
-a lower temp than THYST actually triggers an alarm instead of
+/* Note: Even though I left the low and high limits named os and hyst,
+they don't quite work like a thermostat the way the LM75 does. I.e.,
+a lower temp than THYST actually triggers an alarm instead of
clearing it. Weird, ey? --Phil */
/* Each client has this additional data */
struct adm1021_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
enum chips type;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
- u8 temp_max; /* Register values */
- u8 temp_hyst;
- u8 temp_input;
- u8 remote_temp_max;
- u8 remote_temp_hyst;
- u8 remote_temp_input;
- u8 alarms;
- /* Special values for ADM1023 only */
- u8 remote_temp_prec;
- u8 remote_temp_os_prec;
- u8 remote_temp_hyst_prec;
- u8 remote_temp_offset;
- u8 remote_temp_offset_prec;
+ s8 temp_max[2]; /* Register values */
+ s8 temp_min[2];
+ s8 temp[2];
+ u8 alarms;
+ /* Special values for ADM1023 only */
+ u8 remote_temp_prec;
+ u8 remote_temp_os_prec;
+ u8 remote_temp_hyst_prec;
+ u8 remote_temp_offset;
+ u8 remote_temp_offset_prec;
};
static int adm1021_attach_adapter(struct i2c_adapter *adapter);
static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind);
static void adm1021_init_client(struct i2c_client *client);
static int adm1021_detach_client(struct i2c_client *client);
-static int adm1021_read_value(struct i2c_client *client, u8 reg);
-static int adm1021_write_value(struct i2c_client *client, u8 reg,
- u16 value);
static struct adm1021_data *adm1021_update_device(struct device *dev);
/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
@@ -135,53 +120,104 @@ static struct i2c_driver adm1021_driver = {
.detach_client = adm1021_detach_client,
};
-#define show(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct adm1021_data *data = adm1021_update_device(dev); \
- return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct adm1021_data *data = adm1021_update_device(dev);
+
+ return sprintf(buf, "%d\n", 1000 * data->temp[index]);
}
-show(temp_max);
-show(temp_hyst);
-show(temp_input);
-show(remote_temp_max);
-show(remote_temp_hyst);
-show(remote_temp_input);
-
-#define show2(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct adm1021_data *data = adm1021_update_device(dev); \
- return sprintf(buf, "%d\n", data->value); \
+
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct adm1021_data *data = adm1021_update_device(dev);
+
+ return sprintf(buf, "%d\n", 1000 * data->temp_max[index]);
}
-show2(alarms);
-
-#define set(value, reg) \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct adm1021_data *data = i2c_get_clientdata(client); \
- int temp = simple_strtoul(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- data->value = TEMP_TO_REG(temp); \
- adm1021_write_value(client, reg, data->value); \
- mutex_unlock(&data->update_lock); \
- return count; \
+
+static ssize_t show_temp_min(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct adm1021_data *data = adm1021_update_device(dev);
+
+ return sprintf(buf, "%d\n", 1000 * data->temp_min[index]);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct adm1021_data *data = adm1021_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
+}
+
+static ssize_t show_alarms(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct adm1021_data *data = adm1021_update_device(dev);
+ return sprintf(buf, "%u\n", data->alarms);
}
-set(temp_max, ADM1021_REG_TOS_W);
-set(temp_hyst, ADM1021_REG_THYST_W);
-set(remote_temp_max, ADM1021_REG_REMOTE_TOS_W);
-set(remote_temp_hyst, ADM1021_REG_REMOTE_THYST_W);
-
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst);
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL);
-static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remote_temp_max);
-static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst);
-static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL);
-static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t set_temp_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm1021_data *data = i2c_get_clientdata(client);
+ long temp = simple_strtol(buf, NULL, 10) / 1000;
+
+ mutex_lock(&data->update_lock);
+ data->temp_max[index] = SENSORS_LIMIT(temp, -128, 127);
+ if (!read_only)
+ i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index),
+ data->temp_max[index]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t set_temp_min(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adm1021_data *data = i2c_get_clientdata(client);
+ long temp = simple_strtol(buf, NULL, 10) / 1000;
+
+ mutex_lock(&data->update_lock);
+ data->temp_min[index] = SENSORS_LIMIT(temp, -128, 127);
+ if (!read_only)
+ i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index),
+ data->temp_min[index]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static int adm1021_attach_adapter(struct i2c_adapter *adapter)
{
@@ -191,12 +227,17 @@ static int adm1021_attach_adapter(struct i2c_adapter *adapter)
}
static struct attribute *adm1021_attributes[] = {
- &dev_attr_temp1_max.attr,
- &dev_attr_temp1_min.attr,
- &dev_attr_temp1_input.attr,
- &dev_attr_temp2_max.attr,
- &dev_attr_temp2_min.attr,
- &dev_attr_temp2_input.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&dev_attr_alarms.attr,
NULL
};
@@ -208,35 +249,44 @@ static const struct attribute_group adm1021_group = {
static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i;
- struct i2c_client *new_client;
+ struct i2c_client *client;
struct adm1021_data *data;
int err = 0;
const char *type_name = "";
+ int conv_rate, status, config;
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ pr_debug("adm1021: detect failed, "
+ "smbus byte data not supported!\n");
goto error0;
+ }
/* OK. For now, we presume we have a valid client. We now create the
client structure, even though we cannot fill it completely yet.
- But it allows us to access adm1021_{read,write}_value. */
+ But it allows us to access adm1021 register values. */
if (!(data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL))) {
+ pr_debug("adm1021: detect failed, kzalloc failed!\n");
err = -ENOMEM;
goto error0;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &adm1021_driver;
- new_client->flags = 0;
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &adm1021_driver;
+ status = i2c_smbus_read_byte_data(client, ADM1021_REG_STATUS);
+ conv_rate = i2c_smbus_read_byte_data(client,
+ ADM1021_REG_CONV_RATE_R);
+ config = i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R);
/* Now, we do the remaining detection. */
if (kind < 0) {
- if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00
- || (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00
- || (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) {
+ if ((status & 0x03) != 0x00 || (config & 0x3F) != 0x00
+ || (conv_rate & 0xF8) != 0x00) {
+ pr_debug("adm1021: detect failed, "
+ "chip not detected!\n");
err = -ENODEV;
goto error1;
}
@@ -244,9 +294,10 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
/* Determine the chip type. */
if (kind <= 0) {
- i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID);
+ i = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID);
if (i == 0x41)
- if ((adm1021_read_value(new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030)
+ if ((i2c_smbus_read_byte_data(client,
+ ADM1021_REG_DEV_ID) & 0xF0) == 0x30)
kind = adm1023;
else
kind = adm1021;
@@ -255,15 +306,16 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
else if (i == 0x23)
kind = gl523sm;
else if ((i == 0x4d) &&
- (adm1021_read_value(new_client, ADM1021_REG_DEV_ID) == 0x01))
+ (i2c_smbus_read_byte_data(client,
+ ADM1021_REG_DEV_ID) == 0x01))
kind = max1617a;
else if (i == 0x54)
kind = mc1066;
/* LM84 Mfr ID in a different place, and it has more unused bits */
- else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00
- && (kind == 0 /* skip extra detection */
- || ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00
- && (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00)))
+ else if (conv_rate == 0x00
+ && (kind == 0 /* skip extra detection */
+ || ((config & 0x7F) == 0x00
+ && (status & 0xAB) == 0x00)))
kind = lm84;
else
kind = max1617;
@@ -286,37 +338,38 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
} else if (kind == mc1066) {
type_name = "mc1066";
}
+ pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n",
+ type_name, i2c_adapter_id(adapter), address);
- /* Fill in the remaining client fields and put it into the global list */
- strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
+ /* Fill in the remaining client fields */
+ strlcpy(client->name, type_name, I2C_NAME_SIZE);
data->type = kind;
- data->valid = 0;
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
+ if ((err = i2c_attach_client(client)))
goto error1;
/* Initialize the ADM1021 chip */
- if (kind != lm84)
- adm1021_init_client(new_client);
+ if (kind != lm84 && !read_only)
+ adm1021_init_client(client);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1021_group)))
+ if ((err = sysfs_create_group(&client->dev.kobj, &adm1021_group)))
goto error2;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto error3;
}
return 0;
error3:
- sysfs_remove_group(&new_client->dev.kobj, &adm1021_group);
+ sysfs_remove_group(&client->dev.kobj, &adm1021_group);
error2:
- i2c_detach_client(new_client);
+ i2c_detach_client(client);
error1:
kfree(data);
error0:
@@ -326,10 +379,10 @@ error0:
static void adm1021_init_client(struct i2c_client *client)
{
/* Enable ADC and disable suspend mode */
- adm1021_write_value(client, ADM1021_REG_CONFIG_W,
- adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF);
+ i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W,
+ i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R) & 0xBF);
/* Set Conversion rate to 1/sec (this can be tinkered with) */
- adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04);
+ i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04);
}
static int adm1021_detach_client(struct i2c_client *client)
@@ -337,7 +390,7 @@ static int adm1021_detach_client(struct i2c_client *client)
struct adm1021_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1021_group);
if ((err = i2c_detach_client(client)))
@@ -347,19 +400,6 @@ static int adm1021_detach_client(struct i2c_client *client)
return 0;
}
-/* All registers are byte-sized */
-static int adm1021_read_value(struct i2c_client *client, u8 reg)
-{
- return i2c_smbus_read_byte_data(client, reg);
-}
-
-static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value)
-{
- if (!read_only)
- return i2c_smbus_write_byte_data(client, reg, value);
- return 0;
-}
-
static struct adm1021_data *adm1021_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -369,21 +409,36 @@ static struct adm1021_data *adm1021_update_device(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
+ int i;
+
dev_dbg(&client->dev, "Starting adm1021 update\n");
- data->temp_input = adm1021_read_value(client, ADM1021_REG_TEMP);
- data->temp_max = adm1021_read_value(client, ADM1021_REG_TOS_R);
- data->temp_hyst = adm1021_read_value(client, ADM1021_REG_THYST_R);
- data->remote_temp_input = adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP);
- data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R);
- data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R);
- data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c;
+ for (i = 0; i < 2; i++) {
+ data->temp[i] = i2c_smbus_read_byte_data(client,
+ ADM1021_REG_TEMP(i));
+ data->temp_max[i] = i2c_smbus_read_byte_data(client,
+ ADM1021_REG_TOS_R(i));
+ data->temp_min[i] = i2c_smbus_read_byte_data(client,
+ ADM1021_REG_THYST_R(i));
+ }
+ data->alarms = i2c_smbus_read_byte_data(client,
+ ADM1021_REG_STATUS) & 0x7c;
if (data->type == adm1023) {
- data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC);
- data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC);
- data->remote_temp_hyst_prec = adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC);
- data->remote_temp_offset = adm1021_read_value(client, ADM1021_REG_REM_OFFSET);
- data->remote_temp_offset_prec = adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC);
+ data->remote_temp_prec =
+ i2c_smbus_read_byte_data(client,
+ ADM1023_REG_REM_TEMP_PREC);
+ data->remote_temp_os_prec =
+ i2c_smbus_read_byte_data(client,
+ ADM1023_REG_REM_TOS_PREC);
+ data->remote_temp_hyst_prec =
+ i2c_smbus_read_byte_data(client,
+ ADM1023_REG_REM_THYST_PREC);
+ data->remote_temp_offset =
+ i2c_smbus_read_byte_data(client,
+ ADM1023_REG_REM_OFFSET);
+ data->remote_temp_offset_prec =
+ i2c_smbus_read_byte_data(client,
+ ADM1023_REG_REM_OFFSET_PREC);
}
data->last_updated = jiffies;
data->valid = 1;
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
index 8c562885b54..041ecb0bdf4 100644
--- a/drivers/hwmon/adm1025.c
+++ b/drivers/hwmon/adm1025.c
@@ -133,7 +133,7 @@ static struct i2c_driver adm1025_driver = {
struct adm1025_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -292,7 +292,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct adm1025_data *data = adm1025_update_device(dev);
+ struct adm1025_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", data->vrm);
}
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
@@ -472,9 +472,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_remove;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -538,7 +538,7 @@ static int adm1025_detach_client(struct i2c_client *client)
struct adm1025_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1025_group);
sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt);
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index ba80cd3258c..3e63c148677 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -260,7 +260,7 @@ struct pwm_data {
struct adm1026_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
enum chips type;
struct mutex update_lock;
@@ -1221,7 +1221,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct adm1026_data *data = adm1026_update_device(dev);
+ struct adm1026_data *data = dev_get_drvdata(dev);
return sprintf(buf,"%d\n", data->vrm);
}
static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf,
@@ -1651,7 +1651,7 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
break;
default :
dev_err(&adapter->dev, ": Internal error, invalid "
- "kind (%d)!", kind);
+ "kind (%d)!\n", kind);
err = -EFAULT;
goto exitfree;
}
@@ -1676,9 +1676,9 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1026_group)))
goto exitdetach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exitremove;
}
@@ -1698,7 +1698,7 @@ exit:
static int adm1026_detach_client(struct i2c_client *client)
{
struct adm1026_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1026_group);
i2c_detach_client(client);
kfree(data);
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
index 73ce31b3151..0bc897dffa2 100644
--- a/drivers/hwmon/adm1029.c
+++ b/drivers/hwmon/adm1029.c
@@ -141,7 +141,7 @@ static struct i2c_driver adm1029_driver = {
struct adm1029_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -391,9 +391,9 @@ static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -431,7 +431,7 @@ static int adm1029_detach_client(struct i2c_client *client)
struct adm1029_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1029_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index 122683fc91d..37cfc101da5 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -70,7 +70,7 @@ typedef u8 auto_chan_table_t[8][2];
/* Each client has this additional data */
struct adm1031_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
int chip_type;
char valid; /* !=0 if following fields are valid */
@@ -853,9 +853,9 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_remove;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -877,7 +877,7 @@ static int adm1031_detach_client(struct i2c_client *client)
struct adm1031_data *data = i2c_get_clientdata(client);
int ret;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm1031_group);
sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
if ((ret = i2c_detach_client(client)) != 0) {
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index aad594adf0c..c17d0b6b328 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -150,7 +150,7 @@ static struct i2c_driver adm9240_driver = {
struct adm9240_data {
enum chips type;
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid;
unsigned long last_updated_measure;
@@ -590,9 +590,9 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -620,7 +620,7 @@ static int adm9240_detach_client(struct i2c_client *client)
struct adm9240_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adm9240_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
new file mode 100644
index 00000000000..9810aaa0489
--- /dev/null
+++ b/drivers/hwmon/adt7470.c
@@ -0,0 +1,1050 @@
+/*
+ * A hwmon driver for the Analog Devices ADT7470
+ * Copyright (C) 2007 IBM
+ *
+ * Author: Darrick J. Wong <djwong@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(adt7470);
+
+/* ADT7470 registers */
+#define ADT7470_REG_BASE_ADDR 0x20
+#define ADT7470_REG_TEMP_BASE_ADDR 0x20
+#define ADT7470_REG_TEMP_MAX_ADDR 0x29
+#define ADT7470_REG_FAN_BASE_ADDR 0x2A
+#define ADT7470_REG_FAN_MAX_ADDR 0x31
+#define ADT7470_REG_PWM_BASE_ADDR 0x32
+#define ADT7470_REG_PWM_MAX_ADDR 0x35
+#define ADT7470_REG_PWM_MAX_BASE_ADDR 0x38
+#define ADT7470_REG_PWM_MAX_MAX_ADDR 0x3B
+#define ADT7470_REG_CFG 0x40
+#define ADT7470_FSPD_MASK 0x04
+#define ADT7470_REG_ALARM1 0x41
+#define ADT7470_REG_ALARM2 0x42
+#define ADT7470_REG_TEMP_LIMITS_BASE_ADDR 0x44
+#define ADT7470_REG_TEMP_LIMITS_MAX_ADDR 0x57
+#define ADT7470_REG_FAN_MIN_BASE_ADDR 0x58
+#define ADT7470_REG_FAN_MIN_MAX_ADDR 0x5F
+#define ADT7470_REG_FAN_MAX_BASE_ADDR 0x60
+#define ADT7470_REG_FAN_MAX_MAX_ADDR 0x67
+#define ADT7470_REG_PWM_CFG_BASE_ADDR 0x68
+#define ADT7470_REG_PWM12_CFG 0x68
+#define ADT7470_PWM2_AUTO_MASK 0x40
+#define ADT7470_PWM1_AUTO_MASK 0x80
+#define ADT7470_REG_PWM34_CFG 0x69
+#define ADT7470_PWM3_AUTO_MASK 0x40
+#define ADT7470_PWM4_AUTO_MASK 0x80
+#define ADT7470_REG_PWM_MIN_BASE_ADDR 0x6A
+#define ADT7470_REG_PWM_MIN_MAX_ADDR 0x6D
+#define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR 0x6E
+#define ADT7470_REG_PWM_TEMP_MIN_MAX_ADDR 0x71
+#define ADT7470_REG_ACOUSTICS12 0x75
+#define ADT7470_REG_ACOUSTICS34 0x76
+#define ADT7470_REG_DEVICE 0x3D
+#define ADT7470_REG_VENDOR 0x3E
+#define ADT7470_REG_REVISION 0x3F
+#define ADT7470_REG_ALARM1_MASK 0x72
+#define ADT7470_REG_ALARM2_MASK 0x73
+#define ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR 0x7C
+#define ADT7470_REG_PWM_AUTO_TEMP_MAX_ADDR 0x7D
+#define ADT7470_REG_MAX_ADDR 0x81
+
+#define ADT7470_TEMP_COUNT 10
+#define ADT7470_TEMP_REG(x) (ADT7470_REG_TEMP_BASE_ADDR + (x))
+#define ADT7470_TEMP_MIN_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + ((x) * 2))
+#define ADT7470_TEMP_MAX_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + \
+ ((x) * 2) + 1)
+
+#define ADT7470_FAN_COUNT 4
+#define ADT7470_REG_FAN(x) (ADT7470_REG_FAN_BASE_ADDR + ((x) * 2))
+#define ADT7470_REG_FAN_MIN(x) (ADT7470_REG_FAN_MIN_BASE_ADDR + ((x) * 2))
+#define ADT7470_REG_FAN_MAX(x) (ADT7470_REG_FAN_MAX_BASE_ADDR + ((x) * 2))
+
+#define ADT7470_PWM_COUNT 4
+#define ADT7470_REG_PWM(x) (ADT7470_REG_PWM_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_MAX(x) (ADT7470_REG_PWM_MAX_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_MIN(x) (ADT7470_REG_PWM_MIN_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_TMIN(x) (ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR + (x))
+#define ADT7470_REG_PWM_CFG(x) (ADT7470_REG_PWM_CFG_BASE_ADDR + ((x) / 2))
+#define ADT7470_REG_PWM_AUTO_TEMP(x) (ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR + \
+ ((x) / 2))
+
+#define ADT7470_VENDOR 0x41
+#define ADT7470_DEVICE 0x70
+/* datasheet only mentions a revision 2 */
+#define ADT7470_REVISION 0x02
+
+/* "all temps" according to hwmon sysfs interface spec */
+#define ADT7470_PWM_ALL_TEMPS 0x3FF
+
+/* How often do we reread sensors values? (In jiffies) */
+#define SENSOR_REFRESH_INTERVAL (5 * HZ)
+
+/* How often do we reread sensor limit values? (In jiffies) */
+#define LIMIT_REFRESH_INTERVAL (60 * HZ)
+
+/* sleep 1s while gathering temperature data */
+#define TEMP_COLLECTION_TIME 1000
+
+#define power_of_2(x) (((x) & ((x) - 1)) == 0)
+
+/* datasheet says to divide this number by the fan reading to get fan rpm */
+#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x))
+#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM
+#define FAN_PERIOD_INVALID 65535
+#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
+
+struct adt7470_data {
+ struct i2c_client client;
+ struct device *hwmon_dev;
+ struct attribute_group attrs;
+ struct mutex lock;
+ char sensors_valid;
+ char limits_valid;
+ unsigned long sensors_last_updated; /* In jiffies */
+ unsigned long limits_last_updated; /* In jiffies */
+
+ s8 temp[ADT7470_TEMP_COUNT];
+ s8 temp_min[ADT7470_TEMP_COUNT];
+ s8 temp_max[ADT7470_TEMP_COUNT];
+ u16 fan[ADT7470_FAN_COUNT];
+ u16 fan_min[ADT7470_FAN_COUNT];
+ u16 fan_max[ADT7470_FAN_COUNT];
+ u16 alarms, alarms_mask;
+ u8 force_pwm_max;
+ u8 pwm[ADT7470_PWM_COUNT];
+ u8 pwm_max[ADT7470_PWM_COUNT];
+ u8 pwm_automatic[ADT7470_PWM_COUNT];
+ u8 pwm_min[ADT7470_PWM_COUNT];
+ s8 pwm_tmin[ADT7470_PWM_COUNT];
+ u8 pwm_auto_temp[ADT7470_PWM_COUNT];
+};
+
+static int adt7470_attach_adapter(struct i2c_adapter *adapter);
+static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind);
+static int adt7470_detach_client(struct i2c_client *client);
+
+static struct i2c_driver adt7470_driver = {
+ .driver = {
+ .name = "adt7470",
+ },
+ .attach_adapter = adt7470_attach_adapter,
+ .detach_client = adt7470_detach_client,
+};
+
+/*
+ * 16-bit registers on the ADT7470 are low-byte first. The data sheet says
+ * that the low byte must be read before the high byte.
+ */
+static inline int adt7470_read_word_data(struct i2c_client *client, u8 reg)
+{
+ u16 foo;
+ foo = i2c_smbus_read_byte_data(client, reg);
+ foo |= ((u16)i2c_smbus_read_byte_data(client, reg + 1) << 8);
+ return foo;
+}
+
+static inline int adt7470_write_word_data(struct i2c_client *client, u8 reg,
+ u16 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value & 0xFF)
+ && i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
+}
+
+static void adt7470_init_client(struct i2c_client *client)
+{
+ int reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+
+ if (reg < 0) {
+ dev_err(&client->dev, "cannot read configuration register\n");
+ } else {
+ /* start monitoring (and do a self-test) */
+ i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg | 3);
+ }
+}
+
+static struct adt7470_data *adt7470_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ unsigned long local_jiffies = jiffies;
+ u8 cfg;
+ int i;
+
+ mutex_lock(&data->lock);
+ if (time_before(local_jiffies, data->sensors_last_updated +
+ SENSOR_REFRESH_INTERVAL)
+ && data->sensors_valid)
+ goto no_sensor_update;
+
+ /* start reading temperature sensors */
+ cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+ cfg |= 0x80;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg);
+
+ /*
+ * Delay is 200ms * number of tmp05 sensors. Too bad
+ * there's no way to figure out how many are connected.
+ * For now, assume 1s will work.
+ */
+ msleep(TEMP_COLLECTION_TIME);
+
+ /* done reading temperature sensors */
+ cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+ cfg &= ~0x80;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg);
+
+ for (i = 0; i < ADT7470_TEMP_COUNT; i++)
+ data->temp[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_TEMP_REG(i));
+
+ for (i = 0; i < ADT7470_FAN_COUNT; i++)
+ data->fan[i] = adt7470_read_word_data(client,
+ ADT7470_REG_FAN(i));
+
+ for (i = 0; i < ADT7470_PWM_COUNT; i++) {
+ int reg;
+ int reg_mask;
+
+ data->pwm[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_REG_PWM(i));
+
+ if (i % 2)
+ reg_mask = ADT7470_PWM2_AUTO_MASK;
+ else
+ reg_mask = ADT7470_PWM1_AUTO_MASK;
+
+ reg = ADT7470_REG_PWM_CFG(i);
+ if (i2c_smbus_read_byte_data(client, reg) & reg_mask)
+ data->pwm_automatic[i] = 1;
+ else
+ data->pwm_automatic[i] = 0;
+
+ reg = ADT7470_REG_PWM_AUTO_TEMP(i);
+ cfg = i2c_smbus_read_byte_data(client, reg);
+ if (!(i % 2))
+ data->pwm_auto_temp[i] = cfg >> 4;
+ else
+ data->pwm_auto_temp[i] = cfg & 0xF;
+ }
+
+ if (i2c_smbus_read_byte_data(client, ADT7470_REG_CFG) &
+ ADT7470_FSPD_MASK)
+ data->force_pwm_max = 1;
+ else
+ data->force_pwm_max = 0;
+
+ data->alarms = adt7470_read_word_data(client, ADT7470_REG_ALARM1);
+ data->alarms_mask = adt7470_read_word_data(client,
+ ADT7470_REG_ALARM1_MASK);
+
+ data->sensors_last_updated = local_jiffies;
+ data->sensors_valid = 1;
+
+no_sensor_update:
+ if (time_before(local_jiffies, data->limits_last_updated +
+ LIMIT_REFRESH_INTERVAL)
+ && data->limits_valid)
+ goto out;
+
+ for (i = 0; i < ADT7470_TEMP_COUNT; i++) {
+ data->temp_min[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_TEMP_MIN_REG(i));
+ data->temp_max[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_TEMP_MAX_REG(i));
+ }
+
+ for (i = 0; i < ADT7470_FAN_COUNT; i++) {
+ data->fan_min[i] = adt7470_read_word_data(client,
+ ADT7470_REG_FAN_MIN(i));
+ data->fan_max[i] = adt7470_read_word_data(client,
+ ADT7470_REG_FAN_MAX(i));
+ }
+
+ for (i = 0; i < ADT7470_PWM_COUNT; i++) {
+ data->pwm_max[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_REG_PWM_MAX(i));
+ data->pwm_min[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_REG_PWM_MIN(i));
+ data->pwm_tmin[i] = i2c_smbus_read_byte_data(client,
+ ADT7470_REG_PWM_TMIN(i));
+ }
+
+ data->limits_last_updated = local_jiffies;
+ data->limits_valid = 1;
+
+out:
+ mutex_unlock(&data->lock);
+ return data;
+}
+
+static ssize_t show_temp_min(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", 1000 * data->temp_min[attr->index]);
+}
+
+static ssize_t set_temp_min(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10) / 1000;
+
+ mutex_lock(&data->lock);
+ data->temp_min[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7470_TEMP_MIN_REG(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", 1000 * data->temp_max[attr->index]);
+}
+
+static ssize_t set_temp_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10) / 1000;
+
+ mutex_lock(&data->lock);
+ data->temp_max[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7470_TEMP_MAX_REG(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]);
+}
+
+static ssize_t show_alarms(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+
+ if (attr->index)
+ return sprintf(buf, "%x\n", data->alarms);
+ else
+ return sprintf(buf, "%x\n", data->alarms_mask);
+}
+
+static ssize_t show_fan_max(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+
+ if (FAN_DATA_VALID(data->fan_max[attr->index]))
+ return sprintf(buf, "%d\n",
+ FAN_PERIOD_TO_RPM(data->fan_max[attr->index]));
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t set_fan_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ if (!temp)
+ return -EINVAL;
+ temp = FAN_RPM_TO_PERIOD(temp);
+
+ mutex_lock(&data->lock);
+ data->fan_max[attr->index] = temp;
+ adt7470_write_word_data(client, ADT7470_REG_FAN_MAX(attr->index), temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_fan_min(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+
+ if (FAN_DATA_VALID(data->fan_min[attr->index]))
+ return sprintf(buf, "%d\n",
+ FAN_PERIOD_TO_RPM(data->fan_min[attr->index]));
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t set_fan_min(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ if (!temp)
+ return -EINVAL;
+ temp = FAN_RPM_TO_PERIOD(temp);
+
+ mutex_lock(&data->lock);
+ data->fan_min[attr->index] = temp;
+ adt7470_write_word_data(client, ADT7470_REG_FAN_MIN(attr->index), temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+
+ if (FAN_DATA_VALID(data->fan[attr->index]))
+ return sprintf(buf, "%d\n",
+ FAN_PERIOD_TO_RPM(data->fan[attr->index]));
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_force_pwm_max(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", data->force_pwm_max);
+}
+
+static ssize_t set_force_pwm_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+ u8 reg;
+
+ mutex_lock(&data->lock);
+ data->force_pwm_max = temp;
+ reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
+ if (temp)
+ reg |= ADT7470_FSPD_MASK;
+ else
+ reg &= ~ADT7470_FSPD_MASK;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm[attr->index]);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->lock);
+ data->pwm[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_PWM(attr->index), temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_max(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm_max[attr->index]);
+}
+
+static ssize_t set_pwm_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->lock);
+ data->pwm_max[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MAX(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_min(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm_min[attr->index]);
+}
+
+static ssize_t set_pwm_min(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->lock);
+ data->pwm_min[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MIN(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_tmax(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ /* the datasheet says that tmax = tmin + 20C */
+ return sprintf(buf, "%d\n", 1000 * (20 + data->pwm_tmin[attr->index]));
+}
+
+static ssize_t show_pwm_tmin(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", 1000 * data->pwm_tmin[attr->index]);
+}
+
+static ssize_t set_pwm_tmin(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10) / 1000;
+
+ mutex_lock(&data->lock);
+ data->pwm_tmin[attr->index] = temp;
+ i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_TMIN(attr->index),
+ temp);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_auto(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ return sprintf(buf, "%d\n", 1 + data->pwm_automatic[attr->index]);
+}
+
+static ssize_t set_pwm_auto(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+ int pwm_auto_reg = ADT7470_REG_PWM_CFG(attr->index);
+ int pwm_auto_reg_mask;
+ u8 reg;
+
+ if (attr->index % 2)
+ pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK;
+ else
+ pwm_auto_reg_mask = ADT7470_PWM1_AUTO_MASK;
+
+ if (temp != 2 && temp != 1)
+ return -EINVAL;
+ temp--;
+
+ mutex_lock(&data->lock);
+ data->pwm_automatic[attr->index] = temp;
+ reg = i2c_smbus_read_byte_data(client, pwm_auto_reg);
+ if (temp)
+ reg |= pwm_auto_reg_mask;
+ else
+ reg &= ~pwm_auto_reg_mask;
+ i2c_smbus_write_byte_data(client, pwm_auto_reg, reg);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_auto_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct adt7470_data *data = adt7470_update_device(dev);
+ u8 ctrl = data->pwm_auto_temp[attr->index];
+
+ if (ctrl)
+ return sprintf(buf, "%d\n", 1 << (ctrl - 1));
+ else
+ return sprintf(buf, "%d\n", ADT7470_PWM_ALL_TEMPS);
+}
+
+static int cvt_auto_temp(int input)
+{
+ if (input == ADT7470_PWM_ALL_TEMPS)
+ return 0;
+ if (input < 1 || !power_of_2(input))
+ return -EINVAL;
+ return ilog2(input) + 1;
+}
+
+static ssize_t set_pwm_auto_temp(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+ int temp = cvt_auto_temp(simple_strtol(buf, NULL, 10));
+ int pwm_auto_reg = ADT7470_REG_PWM_AUTO_TEMP(attr->index);
+ u8 reg;
+
+ if (temp < 0)
+ return temp;
+
+ mutex_lock(&data->lock);
+ data->pwm_automatic[attr->index] = temp;
+ reg = i2c_smbus_read_byte_data(client, pwm_auto_reg);
+
+ if (!(attr->index % 2)) {
+ reg &= 0xF;
+ reg |= (temp << 4) & 0xF0;
+ } else {
+ reg &= 0xF0;
+ reg |= temp & 0xF;
+ }
+
+ i2c_smbus_write_byte_data(client, pwm_auto_reg, reg);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL, 0);
+static SENSOR_DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarms, NULL, 1);
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 3);
+static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 4);
+static SENSOR_DEVICE_ATTR(temp6_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 5);
+static SENSOR_DEVICE_ATTR(temp7_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 6);
+static SENSOR_DEVICE_ATTR(temp8_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 7);
+static SENSOR_DEVICE_ATTR(temp9_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 8);
+static SENSOR_DEVICE_ATTR(temp10_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 9);
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 2);
+static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 3);
+static SENSOR_DEVICE_ATTR(temp5_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 4);
+static SENSOR_DEVICE_ATTR(temp6_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 5);
+static SENSOR_DEVICE_ATTR(temp7_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 6);
+static SENSOR_DEVICE_ATTR(temp8_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 7);
+static SENSOR_DEVICE_ATTR(temp9_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 8);
+static SENSOR_DEVICE_ATTR(temp10_min, S_IWUSR | S_IRUGO, show_temp_min,
+ set_temp_min, 9);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_temp, NULL, 9);
+
+static SENSOR_DEVICE_ATTR(fan1_max, S_IWUSR | S_IRUGO, show_fan_max,
+ set_fan_max, 0);
+static SENSOR_DEVICE_ATTR(fan2_max, S_IWUSR | S_IRUGO, show_fan_max,
+ set_fan_max, 1);
+static SENSOR_DEVICE_ATTR(fan3_max, S_IWUSR | S_IRUGO, show_fan_max,
+ set_fan_max, 2);
+static SENSOR_DEVICE_ATTR(fan4_max, S_IWUSR | S_IRUGO, show_fan_max,
+ set_fan_max, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
+ set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
+ set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
+ set_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
+ set_fan_min, 3);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
+
+static SENSOR_DEVICE_ATTR(force_pwm_max, S_IWUSR | S_IRUGO,
+ show_force_pwm_max, set_force_pwm_max, 0);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_min, set_pwm_min, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_min, set_pwm_min, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_min, set_pwm_min, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_min, set_pwm_min, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_max, set_pwm_max, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_max, set_pwm_max, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_max, set_pwm_max, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO,
+ show_pwm_max, set_pwm_max, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_pwm_tmin, set_pwm_tmin, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_pwm_tmin, set_pwm_tmin, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_pwm_tmin, set_pwm_tmin, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO,
+ show_pwm_tmin, set_pwm_tmin, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+ NULL, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+ NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+ NULL, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_point2_temp, S_IRUGO, show_pwm_tmax,
+ NULL, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+ set_pwm_auto, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+ set_pwm_auto, 1);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+ set_pwm_auto, 2);
+static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_auto,
+ set_pwm_auto, 3);
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IWUSR | S_IRUGO,
+ show_pwm_auto_temp, set_pwm_auto_temp, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IWUSR | S_IRUGO,
+ show_pwm_auto_temp, set_pwm_auto_temp, 1);
+static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO,
+ show_pwm_auto_temp, set_pwm_auto_temp, 2);
+static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO,
+ show_pwm_auto_temp, set_pwm_auto_temp, 3);
+
+static struct attribute *adt7470_attr[] =
+{
+ &sensor_dev_attr_alarms.dev_attr.attr,
+ &sensor_dev_attr_alarm_mask.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp5_max.dev_attr.attr,
+ &sensor_dev_attr_temp6_max.dev_attr.attr,
+ &sensor_dev_attr_temp7_max.dev_attr.attr,
+ &sensor_dev_attr_temp8_max.dev_attr.attr,
+ &sensor_dev_attr_temp9_max.dev_attr.attr,
+ &sensor_dev_attr_temp10_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp4_min.dev_attr.attr,
+ &sensor_dev_attr_temp5_min.dev_attr.attr,
+ &sensor_dev_attr_temp6_min.dev_attr.attr,
+ &sensor_dev_attr_temp7_min.dev_attr.attr,
+ &sensor_dev_attr_temp8_min.dev_attr.attr,
+ &sensor_dev_attr_temp9_min.dev_attr.attr,
+ &sensor_dev_attr_temp10_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_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_fan1_max.dev_attr.attr,
+ &sensor_dev_attr_fan2_max.dev_attr.attr,
+ &sensor_dev_attr_fan3_max.dev_attr.attr,
+ &sensor_dev_attr_fan4_max.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_force_pwm_max.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm4.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm4_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
+ NULL
+};
+
+static int adt7470_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, adt7470_detect);
+}
+
+static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct adt7470_data *data;
+ int err = 0;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ goto exit;
+
+ if (!(data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &data->client;
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &adt7470_driver;
+
+ i2c_set_clientdata(client, data);
+
+ mutex_init(&data->lock);
+
+ if (kind <= 0) {
+ int vendor, device, revision;
+
+ vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR);
+ if (vendor != ADT7470_VENDOR) {
+ err = -ENODEV;
+ goto exit_free;
+ }
+
+ device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE);
+ if (device != ADT7470_DEVICE) {
+ err = -ENODEV;
+ goto exit_free;
+ }
+
+ revision = i2c_smbus_read_byte_data(client,
+ ADT7470_REG_REVISION);
+ if (revision != ADT7470_REVISION) {
+ err = -ENODEV;
+ goto exit_free;
+ }
+ } else
+ dev_dbg(&adapter->dev, "detection forced\n");
+
+ strlcpy(client->name, "adt7470", I2C_NAME_SIZE);
+
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ dev_info(&client->dev, "%s chip found\n", client->name);
+
+ /* Initialize the ADT7470 chip */
+ adt7470_init_client(client);
+
+ /* Register sysfs hooks */
+ data->attrs.attrs = adt7470_attr;
+ if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
+ goto exit_detach;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
+exit_detach:
+ i2c_detach_client(client);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int adt7470_detach_client(struct i2c_client *client)
+{
+ struct adt7470_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
+ i2c_detach_client(client);
+ kfree(data);
+ return 0;
+}
+
+static int __init adt7470_init(void)
+{
+ return i2c_add_driver(&adt7470_driver);
+}
+
+static void __exit adt7470_exit(void)
+{
+ i2c_del_driver(&adt7470_driver);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_DESCRIPTION("ADT7470 driver");
+MODULE_LICENSE("GPL");
+
+module_init(adt7470_init);
+module_exit(adt7470_exit);
diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c
index ca7095d96ad..7b81e0c2c2d 100644
--- a/drivers/hwmon/ams/ams-input.c
+++ b/drivers/hwmon/ams/ams-input.c
@@ -27,47 +27,32 @@ static unsigned int invert;
module_param(invert, bool, 0644);
MODULE_PARM_DESC(invert, "Invert input data on X and Y axis");
-static int ams_input_kthread(void *data)
+static void ams_idev_poll(struct input_polled_dev *dev)
{
+ struct input_dev *idev = dev->input;
s8 x, y, z;
- while (!kthread_should_stop()) {
- mutex_lock(&ams_info.lock);
-
- ams_sensors(&x, &y, &z);
-
- x -= ams_info.xcalib;
- y -= ams_info.ycalib;
- z -= ams_info.zcalib;
-
- input_report_abs(ams_info.idev, ABS_X, invert ? -x : x);
- input_report_abs(ams_info.idev, ABS_Y, invert ? -y : y);
- input_report_abs(ams_info.idev, ABS_Z, z);
+ mutex_lock(&ams_info.lock);
- input_sync(ams_info.idev);
+ ams_sensors(&x, &y, &z);
- mutex_unlock(&ams_info.lock);
+ x -= ams_info.xcalib;
+ y -= ams_info.ycalib;
+ z -= ams_info.zcalib;
- msleep(25);
- }
+ input_report_abs(idev, ABS_X, invert ? -x : x);
+ input_report_abs(idev, ABS_Y, invert ? -y : y);
+ input_report_abs(idev, ABS_Z, z);
- return 0;
-}
+ input_sync(idev);
-static int ams_input_open(struct input_dev *dev)
-{
- ams_info.kthread = kthread_run(ams_input_kthread, NULL, "kams");
- return IS_ERR(ams_info.kthread) ? PTR_ERR(ams_info.kthread) : 0;
-}
-
-static void ams_input_close(struct input_dev *dev)
-{
- kthread_stop(ams_info.kthread);
+ mutex_unlock(&ams_info.lock);
}
/* Call with ams_info.lock held! */
static void ams_input_enable(void)
{
+ struct input_dev *input;
s8 x, y, z;
if (ams_info.idev)
@@ -78,27 +63,29 @@ static void ams_input_enable(void)
ams_info.ycalib = y;
ams_info.zcalib = z;
- ams_info.idev = input_allocate_device();
+ ams_info.idev = input_allocate_polled_device();
if (!ams_info.idev)
return;
- ams_info.idev->name = "Apple Motion Sensor";
- ams_info.idev->id.bustype = ams_info.bustype;
- ams_info.idev->id.vendor = 0;
- ams_info.idev->open = ams_input_open;
- ams_info.idev->close = ams_input_close;
- ams_info.idev->dev.parent = &ams_info.of_dev->dev;
+ ams_info.idev->poll = ams_idev_poll;
+ ams_info.idev->poll_interval = 25;
+
+ input = ams_info.idev->input;
+ input->name = "Apple Motion Sensor";
+ input->id.bustype = ams_info.bustype;
+ input->id.vendor = 0;
+ input->dev.parent = &ams_info.of_dev->dev;
- input_set_abs_params(ams_info.idev, ABS_X, -50, 50, 3, 0);
- input_set_abs_params(ams_info.idev, ABS_Y, -50, 50, 3, 0);
- input_set_abs_params(ams_info.idev, ABS_Z, -50, 50, 3, 0);
+ input_set_abs_params(input, ABS_X, -50, 50, 3, 0);
+ input_set_abs_params(input, ABS_Y, -50, 50, 3, 0);
+ input_set_abs_params(input, ABS_Z, -50, 50, 3, 0);
- set_bit(EV_ABS, ams_info.idev->evbit);
- set_bit(EV_KEY, ams_info.idev->evbit);
- set_bit(BTN_TOUCH, ams_info.idev->keybit);
+ set_bit(EV_ABS, input->evbit);
+ set_bit(EV_KEY, input->evbit);
+ set_bit(BTN_TOUCH, input->keybit);
- if (input_register_device(ams_info.idev)) {
- input_free_device(ams_info.idev);
+ if (input_register_polled_device(ams_info.idev)) {
+ input_free_polled_device(ams_info.idev);
ams_info.idev = NULL;
return;
}
@@ -108,7 +95,8 @@ static void ams_input_enable(void)
static void ams_input_disable(void)
{
if (ams_info.idev) {
- input_unregister_device(ams_info.idev);
+ input_unregister_polled_device(ams_info.idev);
+ input_free_polled_device(ams_info.idev);
ams_info.idev = NULL;
}
}
diff --git a/drivers/hwmon/ams/ams.h b/drivers/hwmon/ams/ams.h
index 240730e6bcd..a6221e5dd98 100644
--- a/drivers/hwmon/ams/ams.h
+++ b/drivers/hwmon/ams/ams.h
@@ -1,5 +1,5 @@
#include <linux/i2c.h>
-#include <linux/input.h>
+#include <linux/input-polldev.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
@@ -52,8 +52,7 @@ struct ams {
#endif
/* Joystick emulation */
- struct task_struct *kthread;
- struct input_dev *idev;
+ struct input_polled_dev *idev;
__u16 bustype;
/* calibrated null values */
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 941729a131f..86c66c345f8 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -28,7 +28,7 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
-#include <linux/input.h>
+#include <linux/input-polldev.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>
@@ -59,9 +59,9 @@
#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6 bytes) */
#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6 bytes) */
-#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */
+#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */
-#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */
+#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */
#define MOTION_SENSOR_X_KEY "MO_X" /* r-o sp78 (2 bytes) */
#define MOTION_SENSOR_Y_KEY "MO_Y" /* r-o sp78 (2 bytes) */
@@ -80,7 +80,7 @@
/*
* Temperature sensors keys (sp78 - 2 bytes).
*/
-static const char* temperature_sensors_sets[][13] = {
+static const char* temperature_sensors_sets[][36] = {
/* Set 0: Macbook Pro */
{ "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
"Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
@@ -88,7 +88,13 @@ static const char* temperature_sensors_sets[][13] = {
{ "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S",
"Th1H", "Ts0P", NULL },
/* Set 2: Macmini set */
- { "TC0D", "TC0P", NULL }
+ { "TC0D", "TC0P", NULL },
+/* Set 3: 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 },
};
/* List of keys used to read/write fan speeds */
@@ -103,7 +109,7 @@ static const char* fan_speed_keys[] = {
#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
-#define APPLESMC_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */
+#define APPLESMC_POLL_INTERVAL 50 /* msecs */
#define APPLESMC_INPUT_FUZZ 4 /* input event threshold */
#define APPLESMC_INPUT_FLAT 4
@@ -125,9 +131,8 @@ static const int debug;
static struct platform_device *pdev;
static s16 rest_x;
static s16 rest_y;
-static struct timer_list applesmc_timer;
-static struct input_dev *applesmc_idev;
-static struct class_device *hwmon_class_dev;
+static struct device *hwmon_dev;
+static struct input_polled_dev *applesmc_idev;
/* Indicates whether this computer has an accelerometer. */
static unsigned int applesmc_accelerometer;
@@ -138,7 +143,7 @@ static unsigned int applesmc_light;
/* Indicates which temperature sensors set to use. */
static unsigned int applesmc_temperature_set;
-static struct mutex applesmc_lock;
+static DEFINE_MUTEX(applesmc_lock);
/*
* Last index written to key_at_index sysfs file, and value to use for all other
@@ -455,27 +460,12 @@ static void applesmc_calibrate(void)
rest_x = -rest_x;
}
-static int applesmc_idev_open(struct input_dev *dev)
-{
- add_timer(&applesmc_timer);
-
- return 0;
-}
-
-static void applesmc_idev_close(struct input_dev *dev)
-{
- del_timer_sync(&applesmc_timer);
-}
-
-static void applesmc_idev_poll(unsigned long unused)
+static void applesmc_idev_poll(struct input_polled_dev *dev)
{
+ struct input_dev *idev = dev->input;
s16 x, y;
- /* Cannot sleep. Try nonblockingly. If we fail, try again later. */
- if (!mutex_trylock(&applesmc_lock)) {
- mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
- return;
- }
+ mutex_lock(&applesmc_lock);
if (applesmc_read_motion_sensor(SENSOR_X, &x))
goto out;
@@ -483,13 +473,11 @@ static void applesmc_idev_poll(unsigned long unused)
goto out;
x = -x;
- input_report_abs(applesmc_idev, ABS_X, x - rest_x);
- input_report_abs(applesmc_idev, ABS_Y, y - rest_y);
- input_sync(applesmc_idev);
+ input_report_abs(idev, ABS_X, x - rest_x);
+ input_report_abs(idev, ABS_Y, y - rest_y);
+ input_sync(idev);
out:
- mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
-
mutex_unlock(&applesmc_lock);
}
@@ -821,8 +809,7 @@ static ssize_t applesmc_key_at_index_read_show(struct device *dev,
if (!ret) {
return info[0];
- }
- else {
+ } else {
return ret;
}
}
@@ -1009,14 +996,18 @@ static struct attribute *fan##offset##_attributes[] = { \
/*
* Create the needed functions for each fan using the macro defined above
- * (2 fans are supported)
+ * (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 = fan2_attributes },
+ { .attrs = fan3_attributes },
+ { .attrs = fan4_attributes },
};
/*
@@ -1046,6 +1037,52 @@ 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 struct attribute *temperature_attributes[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
@@ -1060,6 +1097,29 @@ static struct attribute *temperature_attributes[] = {
&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,
NULL
};
@@ -1071,7 +1131,7 @@ static const struct attribute_group temperature_attributes_group =
/*
* applesmc_dmi_match - found a match. return one, short-circuiting the hunt.
*/
-static int applesmc_dmi_match(struct dmi_system_id *id)
+static int applesmc_dmi_match(const struct dmi_system_id *id)
{
int i = 0;
struct dmi_match_data* dmi_data = id->driver_data;
@@ -1093,6 +1153,7 @@ static int applesmc_dmi_match(struct dmi_system_id *id)
/* Create accelerometer ressources */
static int applesmc_create_accelerometer(void)
{
+ struct input_dev *idev;
int ret;
ret = sysfs_create_group(&pdev->dev.kobj,
@@ -1100,40 +1161,37 @@ static int applesmc_create_accelerometer(void)
if (ret)
goto out;
- applesmc_idev = input_allocate_device();
+ applesmc_idev = input_allocate_polled_device();
if (!applesmc_idev) {
ret = -ENOMEM;
goto out_sysfs;
}
+ applesmc_idev->poll = applesmc_idev_poll;
+ applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
+
/* initial calibrate for the input device */
applesmc_calibrate();
- /* initialize the input class */
- applesmc_idev->name = "applesmc";
- applesmc_idev->id.bustype = BUS_HOST;
- applesmc_idev->dev.parent = &pdev->dev;
- applesmc_idev->evbit[0] = BIT(EV_ABS);
- applesmc_idev->open = applesmc_idev_open;
- applesmc_idev->close = applesmc_idev_close;
- input_set_abs_params(applesmc_idev, ABS_X,
+ /* initialize the input device */
+ idev = applesmc_idev->input;
+ idev->name = "applesmc";
+ idev->id.bustype = BUS_HOST;
+ idev->dev.parent = &pdev->dev;
+ idev->evbit[0] = BIT_MASK(EV_ABS);
+ input_set_abs_params(idev, ABS_X,
-256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
- input_set_abs_params(applesmc_idev, ABS_Y,
+ input_set_abs_params(idev, ABS_Y,
-256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
- ret = input_register_device(applesmc_idev);
+ ret = input_register_polled_device(applesmc_idev);
if (ret)
goto out_idev;
- /* start up our timer for the input device */
- init_timer(&applesmc_timer);
- applesmc_timer.function = applesmc_idev_poll;
- applesmc_timer.expires = jiffies + APPLESMC_POLL_PERIOD;
-
return 0;
out_idev:
- input_free_device(applesmc_idev);
+ input_free_polled_device(applesmc_idev);
out_sysfs:
sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
@@ -1146,8 +1204,8 @@ out:
/* Release all ressources used by the accelerometer */
static void applesmc_release_accelerometer(void)
{
- del_timer_sync(&applesmc_timer);
- input_unregister_device(applesmc_idev);
+ input_unregister_polled_device(applesmc_idev);
+ input_free_polled_device(applesmc_idev);
sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
}
@@ -1158,6 +1216,8 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = {
{ .accelerometer = 1, .light = 0, .temperature_set = 1 },
/* MacMini: temperature set 2 */
{ .accelerometer = 0, .light = 0, .temperature_set = 2 },
+/* MacPro: temperature set 3 */
+ { .accelerometer = 0, .light = 0, .temperature_set = 3 },
};
/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
@@ -1175,6 +1235,10 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = {
DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
(void*)&applesmc_dmi_data[2]},
+ { applesmc_dmi_match, "Apple MacPro2", {
+ DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
+ DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") },
+ (void*)&applesmc_dmi_data[3]},
{ .ident = NULL }
};
@@ -1184,8 +1248,6 @@ static int __init applesmc_init(void)
int count;
int i;
- mutex_init(&applesmc_lock);
-
if (!dmi_check_system(applesmc_whitelist)) {
printk(KERN_WARNING "applesmc: supported laptop not found!\n");
ret = -ENODEV;
@@ -1227,9 +1289,19 @@ static int __init applesmc_init(void)
switch (count) {
default:
- printk(KERN_WARNING "applesmc: More than 2 fans found,"
- " but at most 2 fans are supported"
+ printk(KERN_WARNING "applesmc: More than 4 fans found,"
+ " but at most 4 fans are supported"
" by the driver.\n");
+ case 4:
+ ret = sysfs_create_group(&pdev->dev.kobj,
+ &fan_attribute_groups[3]);
+ if (ret)
+ goto out_key_enumeration;
+ case 3:
+ ret = sysfs_create_group(&pdev->dev.kobj,
+ &fan_attribute_groups[2]);
+ if (ret)
+ goto out_key_enumeration;
case 2:
ret = sysfs_create_group(&pdev->dev.kobj,
&fan_attribute_groups[1]);
@@ -1287,9 +1359,9 @@ static int __init applesmc_init(void)
goto out_light_wq;
}
- hwmon_class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(hwmon_class_dev)) {
- ret = PTR_ERR(hwmon_class_dev);
+ hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(hwmon_dev)) {
+ ret = PTR_ERR(hwmon_dev);
goto out_light_ledclass;
}
@@ -1331,7 +1403,7 @@ out:
static void __exit applesmc_exit(void)
{
- hwmon_device_unregister(hwmon_class_dev);
+ hwmon_device_unregister(hwmon_dev);
if (applesmc_light) {
led_classdev_unregister(&applesmc_backlight);
destroy_workqueue(applesmc_led_wq);
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 57b1c7b7ac3..9460dba4cf7 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -143,7 +143,7 @@ static int FAN_FROM_REG(u8 val, int div)
/* TEMP: 0.001C/bit (-128C to +127C)
REG: 1C/bit, two's complement */
-static u8 TEMP_TO_REG(int temp)
+static u8 TEMP_TO_REG(long temp)
{
int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX);
ntemp += (ntemp<0 ? -500 : 500);
@@ -182,7 +182,7 @@ static u8 DIV_TO_REG(long val)
dynamically allocated, at the same time the client itself is allocated. */
struct asb100_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
enum chips type;
@@ -448,7 +448,7 @@ static ssize_t set_##reg(struct device *dev, const char *buf, \
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct asb100_data *data = i2c_get_clientdata(client); \
- unsigned long val = simple_strtoul(buf, NULL, 10); \
+ long val = simple_strtol(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
switch (nr) { \
@@ -514,7 +514,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
/* VRM */
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct asb100_data *data = asb100_update_device(dev);
+ struct asb100_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->vrm);
}
@@ -844,9 +844,9 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &asb100_group)))
goto ERROR3;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR4;
}
@@ -874,7 +874,7 @@ static int asb100_detach_client(struct i2c_client *client)
/* main client */
if (data) {
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &asb100_group);
}
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
index 0ccdd0750c4..cce3350e539 100644
--- a/drivers/hwmon/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -61,7 +61,7 @@ static struct i2c_driver atxp1_driver = {
struct atxp1_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
unsigned long last_updated;
u8 valid;
@@ -335,9 +335,9 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -361,7 +361,7 @@ static int atxp1_detach_client(struct i2c_client * client)
struct atxp1_data * data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &atxp1_group);
err = i2c_detach_client(client);
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 7c1795225b0..5c82ec7f8bb 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -47,7 +47,7 @@ typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW;
static struct coretemp_data *coretemp_update_device(struct device *dev);
struct coretemp_data {
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
const char *name;
u32 id;
@@ -58,8 +58,6 @@ struct coretemp_data {
u8 alarm;
};
-static struct coretemp_data *coretemp_update_device(struct device *dev);
-
/*
* Sysfs stuff
*/
@@ -152,7 +150,7 @@ static struct coretemp_data *coretemp_update_device(struct device *dev)
static int __devinit coretemp_probe(struct platform_device *pdev)
{
struct coretemp_data *data;
- struct cpuinfo_x86 *c = &(cpu_data)[pdev->id];
+ struct cpuinfo_x86 *c = &cpu_data(pdev->id);
int err;
u32 eax, edx;
@@ -228,9 +226,9 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
goto exit_free;
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
dev_err(&pdev->dev, "Class registration failed (%d)\n",
err);
goto exit_class;
@@ -250,7 +248,7 @@ static int __devexit coretemp_remove(struct platform_device *pdev)
{
struct coretemp_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
platform_set_drvdata(pdev, NULL);
kfree(data);
@@ -350,7 +348,7 @@ static int coretemp_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata coretemp_cpu_notifier = {
+static struct notifier_block coretemp_cpu_notifier = {
.notifier_call = coretemp_cpu_callback,
};
#endif /* !CONFIG_HOTPLUG_CPU */
@@ -361,7 +359,7 @@ static int __init coretemp_init(void)
struct pdev_entry *p, *n;
/* quick check if we run Intel */
- if (cpu_data[0].x86_vendor != X86_VENDOR_INTEL)
+ if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL)
goto exit;
err = platform_driver_register(&coretemp_driver);
@@ -369,11 +367,12 @@ static int __init coretemp_init(void)
goto exit;
for_each_online_cpu(i) {
- struct cpuinfo_x86 *c = &(cpu_data)[i];
+ struct cpuinfo_x86 *c = &cpu_data(i);
- /* check if family 6, models e, f */
+ /* check if family 6, models e, f, 16 */
if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
- !((c->x86_model == 0xe) || (c->x86_model == 0xf))) {
+ !((c->x86_model == 0xe) || (c->x86_model == 0xf) ||
+ (c->x86_model == 0x16))) {
/* supported CPU not found, but report the unknown
family 6 CPU */
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index e9cbc727664..a878c98e252 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -1,12 +1,12 @@
/*
- * dme1737.c - driver for the SMSC DME1737 and Asus A8000 Super-I/O chips
- * integrated hardware monitoring features.
+ * dme1737.c - Driver for the SMSC DME1737, Asus A8000, and SMSC SCH311x
+ * Super-I/O chips integrated hardware monitoring features.
* Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com>
*
- * This driver is based on the LM85 driver. The hardware monitoring
- * capabilities of the DME1737 are very similar to the LM85 with some
- * additional features. Even though the DME1737 is a Super-I/O chip, the
- * hardware monitoring registers are only accessible via SMBus.
+ * This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access
+ * the chip registers if a DME1737 (or A8000) is found and the ISA bus if a
+ * SCH311x chip is found. Both types of chips have very similar hardware
+ * monitoring capabilities but differ in the way they can be accessed.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
@@ -35,6 +36,9 @@
#include <linux/mutex.h>
#include <asm/io.h>
+/* ISA device, if found */
+static struct platform_device *pdev;
+
/* Module load parameters */
static int force_start;
module_param(force_start, bool, 0);
@@ -133,6 +137,7 @@ static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6};
static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
/* Miscellaneous registers */
+#define DME1737_REG_DEVICE 0x3d
#define DME1737_REG_COMPANY 0x3e
#define DME1737_REG_VERSTEP 0x3f
#define DME1737_REG_CONFIG 0x40
@@ -148,14 +153,20 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
#define DME1737_COMPANY_SMSC 0x5c
#define DME1737_VERSTEP 0x88
#define DME1737_VERSTEP_MASK 0xf8
+#define SCH311X_DEVICE 0x8c
+
+/* Length of ISA address segment */
+#define DME1737_EXTENT 2
/* ---------------------------------------------------------------------
* Data structures and manipulation thereof
* --------------------------------------------------------------------- */
+/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
+ the driver field to differentiate between I2C and ISA chips. */
struct dme1737_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
int valid; /* !=0 if following fields are valid */
@@ -465,27 +476,48 @@ static inline int PWM_OFF_TO_REG(int val, int ix, int reg)
/* ---------------------------------------------------------------------
* Device I/O access
+ *
+ * ISA access is performed through an index/data register pair and needs to
+ * be protected by a mutex during runtime (not required for initialization).
+ * We use data->update_lock for this and need to ensure that we acquire it
+ * before calling dme1737_read or dme1737_write.
* --------------------------------------------------------------------- */
static u8 dme1737_read(struct i2c_client *client, u8 reg)
{
- s32 val = i2c_smbus_read_byte_data(client, reg);
+ s32 val;
+
+ if (client->driver) { /* I2C device */
+ val = i2c_smbus_read_byte_data(client, reg);
- if (val < 0) {
- dev_warn(&client->dev, "Read from register 0x%02x failed! "
- "Please report to the driver maintainer.\n", reg);
+ if (val < 0) {
+ dev_warn(&client->dev, "Read from register "
+ "0x%02x failed! Please report to the driver "
+ "maintainer.\n", reg);
+ }
+ } else { /* ISA device */
+ outb(reg, client->addr);
+ val = inb(client->addr + 1);
}
return val;
}
-static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value)
+static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val)
{
- s32 res = i2c_smbus_write_byte_data(client, reg, value);
+ s32 res = 0;
+
+ if (client->driver) { /* I2C device */
+ res = i2c_smbus_write_byte_data(client, reg, val);
- if (res < 0) {
- dev_warn(&client->dev, "Write to register 0x%02x failed! "
- "Please report to the driver maintainer.\n", reg);
+ if (res < 0) {
+ dev_warn(&client->dev, "Write to register "
+ "0x%02x failed! Please report to the driver "
+ "maintainer.\n", reg);
+ }
+ } else { /* ISA device */
+ outb(reg, client->addr);
+ outb(val, client->addr + 1);
}
return res;
@@ -493,8 +525,8 @@ static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value)
static struct dme1737_data *dme1737_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
int ix;
u8 lsb[5];
@@ -630,6 +662,24 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
DME1737_REG_ALARM3) << 16;
}
+ /* The ISA chips require explicit clearing of alarm bits.
+ * Don't worry, an alarm will come back if the condition
+ * that causes it still exists */
+ if (!client->driver) {
+ if (data->alarms & 0xff0000) {
+ dme1737_write(client, DME1737_REG_ALARM3,
+ 0xff);
+ }
+ if (data->alarms & 0xff00) {
+ dme1737_write(client, DME1737_REG_ALARM2,
+ 0xff);
+ }
+ if (data->alarms & 0xff) {
+ dme1737_write(client, DME1737_REG_ALARM1,
+ 0xff);
+ }
+ }
+
data->last_update = jiffies;
data->valid = 1;
}
@@ -674,7 +724,7 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
break;
default:
res = 0;
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
return sprintf(buf, "%d\n", res);
@@ -683,8 +733,8 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
static ssize_t set_in(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -704,7 +754,7 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
data->in_max[ix]);
break;
default:
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
mutex_unlock(&data->update_lock);
@@ -754,7 +804,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
break;
default:
res = 0;
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
return sprintf(buf, "%d\n", res);
@@ -763,8 +813,8 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -789,7 +839,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
data->temp_offset[ix]);
break;
default:
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
mutex_unlock(&data->update_lock);
@@ -843,7 +893,7 @@ static ssize_t show_zone(struct device *dev, struct device_attribute *attr,
break;
default:
res = 0;
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
return sprintf(buf, "%d\n", res);
@@ -852,8 +902,8 @@ static ssize_t show_zone(struct device *dev, struct device_attribute *attr,
static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -898,7 +948,7 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
data->zone_abs[ix]);
break;
default:
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
mutex_unlock(&data->update_lock);
@@ -950,7 +1000,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
break;
default:
res = 0;
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
return sprintf(buf, "%d\n", res);
@@ -959,8 +1009,8 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -995,7 +1045,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
/* Only valid for fan[1-4] */
if (!(val == 1 || val == 2 || val == 4)) {
count = -EINVAL;
- dev_warn(&client->dev, "Fan type value %ld not "
+ dev_warn(dev, "Fan type value %ld not "
"supported. Choose one of 1, 2, or 4.\n",
val);
goto exit;
@@ -1006,7 +1056,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
data->fan_opt[ix]);
break;
default:
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
exit:
mutex_unlock(&data->update_lock);
@@ -1086,20 +1136,20 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
break;
default:
res = 0;
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
return sprintf(buf, "%d\n", res);
}
static struct attribute *dme1737_attr_pwm[];
-static void dme1737_chmod_file(struct i2c_client*, struct attribute*, mode_t);
+static void dme1737_chmod_file(struct device*, struct attribute*, mode_t);
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -1122,7 +1172,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
/* Only valid for pwm[1-3] */
if (val < 0 || val > 2) {
count = -EINVAL;
- dev_warn(&client->dev, "PWM enable %ld not "
+ dev_warn(dev, "PWM enable %ld not "
"supported. Choose one of 0, 1, or 2.\n",
val);
goto exit;
@@ -1156,7 +1206,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
switch (val) {
case 0:
/* Change permissions of pwm[ix] to read-only */
- dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+ dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
S_IRUGO);
/* Turn fan fully on */
data->pwm_config[ix] = PWM_EN_TO_REG(0,
@@ -1171,12 +1221,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
data->pwm_config[ix]);
/* Change permissions of pwm[ix] to read-writeable */
- dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+ dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
S_IRUGO | S_IWUSR);
break;
case 2:
/* Change permissions of pwm[ix] to read-only */
- dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+ dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
S_IRUGO);
/* Turn on auto mode using the saved zone channel
* assignment */
@@ -1223,7 +1273,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
if (!(val == 1 || val == 2 || val == 4 ||
val == 6 || val == 7)) {
count = -EINVAL;
- dev_warn(&client->dev, "PWM auto channels zone %ld "
+ dev_warn(dev, "PWM auto channels zone %ld "
"not supported. Choose one of 1, 2, 4, 6, "
"or 7.\n", val);
goto exit;
@@ -1257,12 +1307,10 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
dme1737_read(client,
DME1737_REG_PWM_RR(0)));
-
} else {
data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
dme1737_read(client,
DME1737_REG_PWM_RR(0)));
-
}
dme1737_write(client, DME1737_REG_PWM_RR(0),
data->pwm_rr[0]);
@@ -1274,7 +1322,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
data->pwm_min[ix]);
break;
default:
- dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ dev_dbg(dev, "Unknown function %d.\n", fn);
}
exit:
mutex_unlock(&data->update_lock);
@@ -1298,8 +1346,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
data->vrm = val;
@@ -1314,6 +1361,14 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
}
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->client.name);
+}
+
/* ---------------------------------------------------------------------
* Sysfs device attribute defines and structs
* --------------------------------------------------------------------- */
@@ -1322,13 +1377,13 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
#define SENSOR_DEVICE_ATTR_IN(ix) \
static SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \
- show_in, NULL, SYS_IN_INPUT, ix); \
+ show_in, NULL, SYS_IN_INPUT, ix); \
static SENSOR_DEVICE_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
- show_in, set_in, SYS_IN_MIN, ix); \
+ show_in, set_in, SYS_IN_MIN, ix); \
static SENSOR_DEVICE_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
- show_in, set_in, SYS_IN_MAX, ix); \
+ show_in, set_in, SYS_IN_MAX, ix); \
static SENSOR_DEVICE_ATTR_2(in##ix##_alarm, S_IRUGO, \
- show_in, NULL, SYS_IN_ALARM, ix)
+ show_in, NULL, SYS_IN_ALARM, ix)
SENSOR_DEVICE_ATTR_IN(0);
SENSOR_DEVICE_ATTR_IN(1);
@@ -1342,17 +1397,17 @@ SENSOR_DEVICE_ATTR_IN(6);
#define SENSOR_DEVICE_ATTR_TEMP(ix) \
static SENSOR_DEVICE_ATTR_2(temp##ix##_input, S_IRUGO, \
- show_temp, NULL, SYS_TEMP_INPUT, ix-1); \
+ show_temp, NULL, SYS_TEMP_INPUT, ix-1); \
static SENSOR_DEVICE_ATTR_2(temp##ix##_min, S_IRUGO | S_IWUSR, \
- show_temp, set_temp, SYS_TEMP_MIN, ix-1); \
+ show_temp, set_temp, SYS_TEMP_MIN, ix-1); \
static SENSOR_DEVICE_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
- show_temp, set_temp, SYS_TEMP_MAX, ix-1); \
+ show_temp, set_temp, SYS_TEMP_MAX, ix-1); \
static SENSOR_DEVICE_ATTR_2(temp##ix##_offset, S_IRUGO, \
- show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \
+ show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \
static SENSOR_DEVICE_ATTR_2(temp##ix##_alarm, S_IRUGO, \
- show_temp, NULL, SYS_TEMP_ALARM, ix-1); \
+ show_temp, NULL, SYS_TEMP_ALARM, ix-1); \
static SENSOR_DEVICE_ATTR_2(temp##ix##_fault, S_IRUGO, \
- show_temp, NULL, SYS_TEMP_FAULT, ix-1)
+ show_temp, NULL, SYS_TEMP_FAULT, ix-1)
SENSOR_DEVICE_ATTR_TEMP(1);
SENSOR_DEVICE_ATTR_TEMP(2);
@@ -1362,15 +1417,15 @@ SENSOR_DEVICE_ATTR_TEMP(3);
#define SENSOR_DEVICE_ATTR_ZONE(ix) \
static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_channels_temp, S_IRUGO, \
- show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \
+ show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \
static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp_hyst, S_IRUGO, \
- show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \
static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp, S_IRUGO, \
- show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \
static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point2_temp, S_IRUGO, \
- show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \
static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point3_temp, S_IRUGO, \
- show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1)
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1)
SENSOR_DEVICE_ATTR_ZONE(1);
SENSOR_DEVICE_ATTR_ZONE(2);
@@ -1380,13 +1435,13 @@ SENSOR_DEVICE_ATTR_ZONE(3);
#define SENSOR_DEVICE_ATTR_FAN_1TO4(ix) \
static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
- show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+ show_fan, NULL, SYS_FAN_INPUT, ix-1); \
static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
- show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+ show_fan, set_fan, SYS_FAN_MIN, ix-1); \
static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
- show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+ show_fan, NULL, SYS_FAN_ALARM, ix-1); \
static SENSOR_DEVICE_ATTR_2(fan##ix##_type, S_IRUGO | S_IWUSR, \
- show_fan, set_fan, SYS_FAN_TYPE, ix-1)
+ show_fan, set_fan, SYS_FAN_TYPE, ix-1)
SENSOR_DEVICE_ATTR_FAN_1TO4(1);
SENSOR_DEVICE_ATTR_FAN_1TO4(2);
@@ -1397,13 +1452,13 @@ SENSOR_DEVICE_ATTR_FAN_1TO4(4);
#define SENSOR_DEVICE_ATTR_FAN_5TO6(ix) \
static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
- show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+ show_fan, NULL, SYS_FAN_INPUT, ix-1); \
static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
- show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+ show_fan, set_fan, SYS_FAN_MIN, ix-1); \
static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
- show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+ show_fan, NULL, SYS_FAN_ALARM, ix-1); \
static SENSOR_DEVICE_ATTR_2(fan##ix##_max, S_IRUGO | S_IWUSR, \
- show_fan, set_fan, SYS_FAN_MAX, ix-1)
+ show_fan, set_fan, SYS_FAN_MAX, ix-1)
SENSOR_DEVICE_ATTR_FAN_5TO6(5);
SENSOR_DEVICE_ATTR_FAN_5TO6(6);
@@ -1412,21 +1467,21 @@ SENSOR_DEVICE_ATTR_FAN_5TO6(6);
#define SENSOR_DEVICE_ATTR_PWM_1TO3(ix) \
static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM, ix-1); \
+ show_pwm, set_pwm, SYS_PWM, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_ramp_rate, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_channels_zone, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_pwm_min, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point1_pwm, S_IRUGO, \
- show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point2_pwm, S_IRUGO, \
- show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1)
+ show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1)
SENSOR_DEVICE_ATTR_PWM_1TO3(1);
SENSOR_DEVICE_ATTR_PWM_1TO3(2);
@@ -1436,11 +1491,11 @@ SENSOR_DEVICE_ATTR_PWM_1TO3(3);
#define SENSOR_DEVICE_ATTR_PWM_5TO6(ix) \
static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO | S_IWUSR, \
- show_pwm, set_pwm, SYS_PWM, ix-1); \
+ show_pwm, set_pwm, SYS_PWM, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \
- show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+ show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
- show_pwm, NULL, SYS_PWM_ENABLE, ix-1)
+ show_pwm, NULL, SYS_PWM_ENABLE, ix-1)
SENSOR_DEVICE_ATTR_PWM_5TO6(5);
SENSOR_DEVICE_ATTR_PWM_5TO6(6);
@@ -1449,6 +1504,7 @@ SENSOR_DEVICE_ATTR_PWM_5TO6(6);
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); /* for ISA devices */
#define SENSOR_DEV_ATTR_IN(ix) \
&sensor_dev_attr_in##ix##_input.dev_attr.attr, \
@@ -1519,53 +1575,53 @@ SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix), \
* permissions are created read-only and write permissions are added or removed
* on the fly when required */
static struct attribute *dme1737_attr[] ={
- /* Voltages */
- SENSOR_DEV_ATTR_IN(0),
- SENSOR_DEV_ATTR_IN(1),
- SENSOR_DEV_ATTR_IN(2),
- SENSOR_DEV_ATTR_IN(3),
- SENSOR_DEV_ATTR_IN(4),
- SENSOR_DEV_ATTR_IN(5),
- SENSOR_DEV_ATTR_IN(6),
- /* Temperatures */
- SENSOR_DEV_ATTR_TEMP(1),
- SENSOR_DEV_ATTR_TEMP(2),
- SENSOR_DEV_ATTR_TEMP(3),
- /* Zones */
- SENSOR_DEV_ATTR_ZONE(1),
- SENSOR_DEV_ATTR_ZONE(2),
- SENSOR_DEV_ATTR_ZONE(3),
- /* Misc */
- &dev_attr_vrm.attr,
- &dev_attr_cpu0_vid.attr,
+ /* Voltages */
+ SENSOR_DEV_ATTR_IN(0),
+ SENSOR_DEV_ATTR_IN(1),
+ SENSOR_DEV_ATTR_IN(2),
+ SENSOR_DEV_ATTR_IN(3),
+ SENSOR_DEV_ATTR_IN(4),
+ SENSOR_DEV_ATTR_IN(5),
+ SENSOR_DEV_ATTR_IN(6),
+ /* Temperatures */
+ SENSOR_DEV_ATTR_TEMP(1),
+ SENSOR_DEV_ATTR_TEMP(2),
+ SENSOR_DEV_ATTR_TEMP(3),
+ /* Zones */
+ SENSOR_DEV_ATTR_ZONE(1),
+ SENSOR_DEV_ATTR_ZONE(2),
+ SENSOR_DEV_ATTR_ZONE(3),
+ /* Misc */
+ &dev_attr_vrm.attr,
+ &dev_attr_cpu0_vid.attr,
NULL
};
static const struct attribute_group dme1737_group = {
- .attrs = dme1737_attr,
+ .attrs = dme1737_attr,
};
/* The following structs hold the PWM attributes, some of which are optional.
* Their creation depends on the chip configuration which is determined during
* module load. */
static struct attribute *dme1737_attr_pwm1[] = {
- SENSOR_DEV_ATTR_PWM_1TO3(1),
+ SENSOR_DEV_ATTR_PWM_1TO3(1),
NULL
};
static struct attribute *dme1737_attr_pwm2[] = {
- SENSOR_DEV_ATTR_PWM_1TO3(2),
+ SENSOR_DEV_ATTR_PWM_1TO3(2),
NULL
};
static struct attribute *dme1737_attr_pwm3[] = {
- SENSOR_DEV_ATTR_PWM_1TO3(3),
+ SENSOR_DEV_ATTR_PWM_1TO3(3),
NULL
};
static struct attribute *dme1737_attr_pwm5[] = {
- SENSOR_DEV_ATTR_PWM_5TO6(5),
+ SENSOR_DEV_ATTR_PWM_5TO6(5),
NULL
};
static struct attribute *dme1737_attr_pwm6[] = {
- SENSOR_DEV_ATTR_PWM_5TO6(6),
+ SENSOR_DEV_ATTR_PWM_5TO6(6),
NULL
};
@@ -1582,27 +1638,27 @@ static const struct attribute_group dme1737_pwm_group[] = {
* Their creation depends on the chip configuration which is determined during
* module load. */
static struct attribute *dme1737_attr_fan1[] = {
- SENSOR_DEV_ATTR_FAN_1TO4(1),
+ SENSOR_DEV_ATTR_FAN_1TO4(1),
NULL
};
static struct attribute *dme1737_attr_fan2[] = {
- SENSOR_DEV_ATTR_FAN_1TO4(2),
+ SENSOR_DEV_ATTR_FAN_1TO4(2),
NULL
};
static struct attribute *dme1737_attr_fan3[] = {
- SENSOR_DEV_ATTR_FAN_1TO4(3),
+ SENSOR_DEV_ATTR_FAN_1TO4(3),
NULL
};
static struct attribute *dme1737_attr_fan4[] = {
- SENSOR_DEV_ATTR_FAN_1TO4(4),
+ SENSOR_DEV_ATTR_FAN_1TO4(4),
NULL
};
static struct attribute *dme1737_attr_fan5[] = {
- SENSOR_DEV_ATTR_FAN_5TO6(5),
+ SENSOR_DEV_ATTR_FAN_5TO6(5),
NULL
};
static struct attribute *dme1737_attr_fan6[] = {
- SENSOR_DEV_ATTR_FAN_5TO6(6),
+ SENSOR_DEV_ATTR_FAN_5TO6(6),
NULL
};
@@ -1637,23 +1693,23 @@ static const struct attribute_group dme1737_lock_group = {
* writeable if the chip is *not* locked and the respective PWM is available.
* Otherwise they stay read-only. */
static struct attribute *dme1737_attr_pwm1_lock[] = {
- SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1),
+ SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1),
NULL
};
static struct attribute *dme1737_attr_pwm2_lock[] = {
- SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2),
+ SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2),
NULL
};
static struct attribute *dme1737_attr_pwm3_lock[] = {
- SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3),
+ SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3),
NULL
};
static struct attribute *dme1737_attr_pwm5_lock[] = {
- SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5),
+ SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5),
NULL
};
static struct attribute *dme1737_attr_pwm6_lock[] = {
- SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6),
+ SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6),
NULL
};
@@ -1678,6 +1734,16 @@ static struct attribute *dme1737_attr_pwm[] = {
* Super-IO functions
* --------------------------------------------------------------------- */
+static inline void dme1737_sio_enter(int sio_cip)
+{
+ outb(0x55, sio_cip);
+}
+
+static inline void dme1737_sio_exit(int sio_cip)
+{
+ outb(0xaa, sio_cip);
+}
+
static inline int dme1737_sio_inb(int sio_cip, int reg)
{
outb(reg, sio_cip);
@@ -1690,136 +1756,196 @@ static inline void dme1737_sio_outb(int sio_cip, int reg, int val)
outb(val, sio_cip + 1);
}
-static int dme1737_sio_get_features(int sio_cip, struct i2c_client *client)
+/* ---------------------------------------------------------------------
+ * Device initialization
+ * --------------------------------------------------------------------- */
+
+static int dme1737_i2c_get_features(int, struct dme1737_data*);
+
+static void dme1737_chmod_file(struct device *dev,
+ struct attribute *attr, mode_t mode)
{
- struct dme1737_data *data = i2c_get_clientdata(client);
- int err = 0, reg;
- u16 addr;
+ if (sysfs_chmod_file(&dev->kobj, attr, mode)) {
+ dev_warn(dev, "Failed to change permissions of %s.\n",
+ attr->name);
+ }
+}
- /* Enter configuration mode */
- outb(0x55, sio_cip);
+static void dme1737_chmod_group(struct device *dev,
+ const struct attribute_group *group,
+ mode_t mode)
+{
+ struct attribute **attr;
- /* Check device ID
- * The DME1737 can return either 0x78 or 0x77 as its device ID. */
- reg = dme1737_sio_inb(sio_cip, 0x20);
- if (!(reg == 0x77 || reg == 0x78)) {
- err = -ENODEV;
- goto exit;
+ for (attr = group->attrs; *attr; attr++) {
+ dme1737_chmod_file(dev, *attr, mode);
}
+}
- /* Select logical device A (runtime registers) */
- dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+static void dme1737_remove_files(struct device *dev)
+{
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ int ix;
- /* Get the base address of the runtime registers */
- if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
- dme1737_sio_inb(sio_cip, 0x61))) {
- err = -ENODEV;
- goto exit;
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+ if (data->has_fan & (1 << ix)) {
+ sysfs_remove_group(&dev->kobj,
+ &dme1737_fan_group[ix]);
+ }
}
- /* Read the runtime registers to determine which optional features
- * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
- * to '10' if the respective feature is enabled. */
- if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
- data->has_fan |= (1 << 5);
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ sysfs_remove_group(&dev->kobj,
+ &dme1737_pwm_group[ix]);
+ }
}
- if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
- data->has_pwm |= (1 << 5);
+
+ sysfs_remove_group(&dev->kobj, &dme1737_group);
+
+ if (!data->client.driver) {
+ sysfs_remove_file(&dev->kobj, &dev_attr_name.attr);
}
- if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
- data->has_fan |= (1 << 4);
+}
+
+static int dme1737_create_files(struct device *dev)
+{
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ int err, ix;
+
+ /* Create a name attribute for ISA devices */
+ if (!data->client.driver &&
+ (err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) {
+ goto exit;
}
- if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
- data->has_pwm |= (1 << 4);
+
+ /* Create standard sysfs attributes */
+ if ((err = sysfs_create_group(&dev->kobj, &dme1737_group))) {
+ goto exit_remove;
}
-exit:
- /* Exit configuration mode */
- outb(0xaa, sio_cip);
+ /* Create fan sysfs attributes */
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+ if (data->has_fan & (1 << ix)) {
+ if ((err = sysfs_create_group(&dev->kobj,
+ &dme1737_fan_group[ix]))) {
+ goto exit_remove;
+ }
+ }
+ }
- return err;
-}
+ /* Create PWM sysfs attributes */
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ if ((err = sysfs_create_group(&dev->kobj,
+ &dme1737_pwm_group[ix]))) {
+ goto exit_remove;
+ }
+ }
+ }
-/* ---------------------------------------------------------------------
- * Device detection, registration and initialization
- * --------------------------------------------------------------------- */
+ /* Inform if the device is locked. Otherwise change the permissions of
+ * selected attributes from read-only to read-writeable. */
+ if (data->config & 0x02) {
+ dev_info(dev, "Device is locked. Some attributes "
+ "will be read-only.\n");
+ } else {
+ /* Change permissions of standard attributes */
+ dme1737_chmod_group(dev, &dme1737_lock_group,
+ S_IRUGO | S_IWUSR);
-static struct i2c_driver dme1737_driver;
+ /* Change permissions of PWM attributes */
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ dme1737_chmod_group(dev,
+ &dme1737_pwm_lock_group[ix],
+ S_IRUGO | S_IWUSR);
+ }
+ }
-static void dme1737_chmod_file(struct i2c_client *client,
- struct attribute *attr, mode_t mode)
-{
- if (sysfs_chmod_file(&client->dev.kobj, attr, mode)) {
- dev_warn(&client->dev, "Failed to change permissions of %s.\n",
- attr->name);
+ /* Change permissions of pwm[1-3] if in manual mode */
+ for (ix = 0; ix < 3; ix++) {
+ if ((data->has_pwm & (1 << ix)) &&
+ (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
+ dme1737_chmod_file(dev,
+ dme1737_attr_pwm[ix],
+ S_IRUGO | S_IWUSR);
+ }
+ }
}
-}
-static void dme1737_chmod_group(struct i2c_client *client,
- const struct attribute_group *group,
- mode_t mode)
-{
- struct attribute **attr;
+ return 0;
- for (attr = group->attrs; *attr; attr++) {
- dme1737_chmod_file(client, *attr, mode);
- }
+exit_remove:
+ dme1737_remove_files(dev);
+exit:
+ return err;
}
-static int dme1737_init_client(struct i2c_client *client)
+static int dme1737_init_device(struct device *dev)
{
- struct dme1737_data *data = i2c_get_clientdata(client);
+ struct dme1737_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
int ix;
u8 reg;
- data->config = dme1737_read(client, DME1737_REG_CONFIG);
- /* Inform if part is not monitoring/started */
- if (!(data->config & 0x01)) {
- if (!force_start) {
- dev_err(&client->dev, "Device is not monitoring. "
- "Use the force_start load parameter to "
- "override.\n");
- return -EFAULT;
- }
-
- /* Force monitoring */
- data->config |= 0x01;
- dme1737_write(client, DME1737_REG_CONFIG, data->config);
- }
+ data->config = dme1737_read(client, DME1737_REG_CONFIG);
+ /* Inform if part is not monitoring/started */
+ if (!(data->config & 0x01)) {
+ if (!force_start) {
+ dev_err(dev, "Device is not monitoring. "
+ "Use the force_start load parameter to "
+ "override.\n");
+ return -EFAULT;
+ }
+
+ /* Force monitoring */
+ data->config |= 0x01;
+ dme1737_write(client, DME1737_REG_CONFIG, data->config);
+ }
/* Inform if part is not ready */
if (!(data->config & 0x04)) {
- dev_err(&client->dev, "Device is not ready.\n");
+ dev_err(dev, "Device is not ready.\n");
return -EFAULT;
}
- data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
- /* Check if optional fan3 input is enabled */
- if (data->config2 & 0x04) {
- data->has_fan |= (1 << 2);
- }
+ /* Determine which optional fan and pwm features are enabled/present */
+ if (client->driver) { /* I2C chip */
+ data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
+ /* Check if optional fan3 input is enabled */
+ if (data->config2 & 0x04) {
+ data->has_fan |= (1 << 2);
+ }
- /* Fan4 and pwm3 are only available if the client's I2C address
- * is the default 0x2e. Otherwise the I/Os associated with these
- * functions are used for addr enable/select. */
- if (client->addr == 0x2e) {
- data->has_fan |= (1 << 3);
- data->has_pwm |= (1 << 2);
- }
+ /* Fan4 and pwm3 are only available if the client's I2C address
+ * is the default 0x2e. Otherwise the I/Os associated with
+ * these functions are used for addr enable/select. */
+ if (data->client.addr == 0x2e) {
+ data->has_fan |= (1 << 3);
+ data->has_pwm |= (1 << 2);
+ }
- /* Determine if the optional fan[5-6] and/or pwm[5-6] are enabled.
- * For this, we need to query the runtime registers through the
- * Super-IO LPC interface. Try both config ports 0x2e and 0x4e. */
- if (dme1737_sio_get_features(0x2e, client) &&
- dme1737_sio_get_features(0x4e, client)) {
- dev_warn(&client->dev, "Failed to query Super-IO for optional "
- "features.\n");
+ /* Determine which of the optional fan[5-6] and pwm[5-6]
+ * features are enabled. For this, we need to query the runtime
+ * registers through the Super-IO LPC interface. Try both
+ * config ports 0x2e and 0x4e. */
+ if (dme1737_i2c_get_features(0x2e, data) &&
+ dme1737_i2c_get_features(0x4e, data)) {
+ dev_warn(dev, "Failed to query Super-IO for optional "
+ "features.\n");
+ }
+ } else { /* ISA chip */
+ /* Fan3 and pwm3 are always available. Fan[4-5] and pwm[5-6]
+ * don't exist in the ISA chip. */
+ data->has_fan |= (1 << 2);
+ data->has_pwm |= (1 << 2);
}
/* Fan1, fan2, pwm1, and pwm2 are always present */
data->has_fan |= 0x03;
data->has_pwm |= 0x03;
- dev_info(&client->dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
+ dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
"fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
(data->has_pwm & (1 << 2)) ? "yes" : "no",
(data->has_pwm & (1 << 4)) ? "yes" : "no",
@@ -1831,13 +1957,19 @@ static int dme1737_init_client(struct i2c_client *client)
reg = dme1737_read(client, DME1737_REG_TACH_PWM);
/* Inform if fan-to-pwm mapping differs from the default */
- if (reg != 0xa4) {
- dev_warn(&client->dev, "Non-standard fan to pwm mapping: "
+ if (client->driver && reg != 0xa4) { /* I2C chip */
+ dev_warn(dev, "Non-standard fan to pwm mapping: "
"fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
"fan4->pwm%d. Please report to the driver "
"maintainer.\n",
(reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
+ } else if (!client->driver && reg != 0x24) { /* ISA chip */
+ dev_warn(dev, "Non-standard fan to pwm mapping: "
+ "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. "
+ "Please report to the driver maintainer.\n",
+ (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
+ ((reg >> 4) & 0x03) + 1);
}
/* Switch pwm[1-3] to manual mode if they are currently disabled and
@@ -1849,7 +1981,7 @@ static int dme1737_init_client(struct i2c_client *client)
DME1737_REG_PWM_CONFIG(ix));
if ((data->has_pwm & (1 << ix)) &&
(PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
- dev_info(&client->dev, "Switching pwm%d to "
+ dev_info(dev, "Switching pwm%d to "
"manual mode.\n", ix + 1);
data->pwm_config[ix] = PWM_EN_TO_REG(1,
data->pwm_config[ix]);
@@ -1872,13 +2004,67 @@ static int dme1737_init_client(struct i2c_client *client)
return 0;
}
-static int dme1737_detect(struct i2c_adapter *adapter, int address,
- int kind)
+/* ---------------------------------------------------------------------
+ * I2C device detection and registration
+ * --------------------------------------------------------------------- */
+
+static struct i2c_driver dme1737_i2c_driver;
+
+static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
+{
+ int err = 0, reg;
+ u16 addr;
+
+ dme1737_sio_enter(sio_cip);
+
+ /* Check device ID
+ * The DME1737 can return either 0x78 or 0x77 as its device ID. */
+ reg = dme1737_sio_inb(sio_cip, 0x20);
+ if (!(reg == 0x77 || reg == 0x78)) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ /* Select logical device A (runtime registers) */
+ dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+
+ /* Get the base address of the runtime registers */
+ if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
+ dme1737_sio_inb(sio_cip, 0x61))) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ /* Read the runtime registers to determine which optional features
+ * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
+ * to '10' if the respective feature is enabled. */
+ if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
+ data->has_fan |= (1 << 5);
+ }
+ if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
+ data->has_pwm |= (1 << 5);
+ }
+ if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
+ data->has_fan |= (1 << 4);
+ }
+ if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
+ data->has_pwm |= (1 << 4);
+ }
+
+exit:
+ dme1737_sio_exit(sio_cip);
+
+ return err;
+}
+
+static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
+ int kind)
{
u8 company, verstep = 0;
struct i2c_client *client;
struct dme1737_data *data;
- int ix, err = 0;
+ struct device *dev;
+ int err = 0;
const char *name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
@@ -1894,7 +2080,8 @@ static int dme1737_detect(struct i2c_adapter *adapter, int address,
i2c_set_clientdata(client, data);
client->addr = address;
client->adapter = adapter;
- client->driver = &dme1737_driver;
+ client->driver = &dme1737_i2c_driver;
+ dev = &client->dev;
/* A negative kind means that the driver was loaded with no force
* parameter (default), so we must identify the chip. */
@@ -1922,92 +2109,33 @@ static int dme1737_detect(struct i2c_adapter *adapter, int address,
goto exit_kfree;
}
+ dev_info(dev, "Found a DME1737 chip at 0x%02x (rev 0x%02x).\n",
+ client->addr, verstep);
+
/* Initialize the DME1737 chip */
- if ((err = dme1737_init_client(client))) {
+ if ((err = dme1737_init_device(dev))) {
+ dev_err(dev, "Failed to initialize device.\n");
goto exit_detach;
}
- /* Create standard sysfs attributes */
- if ((err = sysfs_create_group(&client->dev.kobj, &dme1737_group))) {
- goto exit_detach;
- }
-
- /* Create fan sysfs attributes */
- for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
- if (data->has_fan & (1 << ix)) {
- if ((err = sysfs_create_group(&client->dev.kobj,
- &dme1737_fan_group[ix]))) {
- goto exit_remove;
- }
- }
- }
-
- /* Create PWM sysfs attributes */
- for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
- if (data->has_pwm & (1 << ix)) {
- if ((err = sysfs_create_group(&client->dev.kobj,
- &dme1737_pwm_group[ix]))) {
- goto exit_remove;
- }
- }
- }
-
- /* Inform if the device is locked. Otherwise change the permissions of
- * selected attributes from read-only to read-writeable. */
- if (data->config & 0x02) {
- dev_info(&client->dev, "Device is locked. Some attributes "
- "will be read-only.\n");
- } else {
- /* Change permissions of standard attributes */
- dme1737_chmod_group(client, &dme1737_lock_group,
- S_IRUGO | S_IWUSR);
-
- /* Change permissions of PWM attributes */
- for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) {
- if (data->has_pwm & (1 << ix)) {
- dme1737_chmod_group(client,
- &dme1737_pwm_lock_group[ix],
- S_IRUGO | S_IWUSR);
- }
- }
-
- /* Change permissions of pwm[1-3] if in manual mode */
- for (ix = 0; ix < 3; ix++) {
- if ((data->has_pwm & (1 << ix)) &&
- (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
- dme1737_chmod_file(client,
- dme1737_attr_pwm[ix],
- S_IRUGO | S_IWUSR);
- }
- }
+ /* Create sysfs files */
+ if ((err = dme1737_create_files(dev))) {
+ dev_err(dev, "Failed to create sysfs files.\n");
+ goto exit_detach;
}
/* Register device */
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ dev_err(dev, "Failed to register device.\n");
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
- dev_info(&adapter->dev, "Found a DME1737 chip at 0x%02x "
- "(rev 0x%02x)\n", client->addr, verstep);
-
return 0;
exit_remove:
- for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
- if (data->has_fan & (1 << ix)) {
- sysfs_remove_group(&client->dev.kobj,
- &dme1737_fan_group[ix]);
- }
- }
- for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
- if (data->has_pwm & (1 << ix)) {
- sysfs_remove_group(&client->dev.kobj,
- &dme1737_pwm_group[ix]);
- }
- }
- sysfs_remove_group(&client->dev.kobj, &dme1737_group);
+ dme1737_remove_files(dev);
exit_detach:
i2c_detach_client(client);
exit_kfree:
@@ -2016,60 +2144,260 @@ exit:
return err;
}
-static int dme1737_attach_adapter(struct i2c_adapter *adapter)
+static int dme1737_i2c_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON)) {
return 0;
}
- return i2c_probe(adapter, &addr_data, dme1737_detect);
+ return i2c_probe(adapter, &addr_data, dme1737_i2c_detect);
}
-static int dme1737_detach_client(struct i2c_client *client)
+static int dme1737_i2c_detach_client(struct i2c_client *client)
{
struct dme1737_data *data = i2c_get_clientdata(client);
- int ix, err;
+ int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
+ dme1737_remove_files(&client->dev);
- for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
- if (data->has_fan & (1 << ix)) {
- sysfs_remove_group(&client->dev.kobj,
- &dme1737_fan_group[ix]);
- }
+ if ((err = i2c_detach_client(client))) {
+ return err;
}
- for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
- if (data->has_pwm & (1 << ix)) {
- sysfs_remove_group(&client->dev.kobj,
- &dme1737_pwm_group[ix]);
- }
+
+ kfree(data);
+ return 0;
+}
+
+static struct i2c_driver dme1737_i2c_driver = {
+ .driver = {
+ .name = "dme1737",
+ },
+ .attach_adapter = dme1737_i2c_attach_adapter,
+ .detach_client = dme1737_i2c_detach_client,
+};
+
+/* ---------------------------------------------------------------------
+ * ISA device detection and registration
+ * --------------------------------------------------------------------- */
+
+static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr)
+{
+ int err = 0, reg;
+ unsigned short base_addr;
+
+ dme1737_sio_enter(sio_cip);
+
+ /* Check device ID
+ * We currently know about SCH3112 (0x7c), SCH3114 (0x7d), and
+ * SCH3116 (0x7f). */
+ reg = dme1737_sio_inb(sio_cip, 0x20);
+ if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) {
+ err = -ENODEV;
+ goto exit;
}
- sysfs_remove_group(&client->dev.kobj, &dme1737_group);
- if ((err = i2c_detach_client(client))) {
- return err;
+ /* Select logical device A (runtime registers) */
+ 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");
+ err = -ENODEV;
+ goto exit;
+ }
+
+ /* Access to the hwmon registers is through an index/data register
+ * pair located at offset 0x70/0x71. */
+ *addr = base_addr + 0x70;
+
+exit:
+ dme1737_sio_exit(sio_cip);
+ return err;
+}
+
+static int __init dme1737_isa_device_add(unsigned short addr)
+{
+ struct resource res = {
+ .start = addr,
+ .end = addr + DME1737_EXTENT - 1,
+ .name = "dme1737",
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ if (!(pdev = platform_device_alloc("dme1737", addr))) {
+ printk(KERN_ERR "dme1737: 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);
+ goto exit_device_put;
+ }
+
+ if ((err = platform_device_add(pdev))) {
+ printk(KERN_ERR "dme1737: Failed to add device (err = %d).\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+ pdev = NULL;
+exit:
+ return err;
+}
+
+static int __devinit dme1737_isa_probe(struct platform_device *pdev)
+{
+ u8 company, device;
+ struct resource *res;
+ struct i2c_client *client;
+ struct dme1737_data *data;
+ struct device *dev = &pdev->dev;
+ int err;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, DME1737_EXTENT, "dme1737")) {
+ 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;
+ }
+
+ if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit_release_region;
+ }
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = res->start;
+ platform_set_drvdata(pdev, data);
+
+ company = dme1737_read(client, DME1737_REG_COMPANY);
+ device = dme1737_read(client, DME1737_REG_DEVICE);
+
+ if (!((company == DME1737_COMPANY_SMSC) &&
+ (device == SCH311X_DEVICE))) {
+ err = -ENODEV;
+ goto exit_kfree;
+ }
+
+ /* Fill in the remaining client fields and initialize the mutex */
+ strlcpy(client->name, "sch311x", I2C_NAME_SIZE);
+ mutex_init(&data->update_lock);
+
+ dev_info(dev, "Found a SCH311x chip at 0x%04x\n", client->addr);
+
+ /* Initialize the chip */
+ if ((err = dme1737_init_device(dev))) {
+ dev_err(dev, "Failed to initialize device.\n");
+ goto exit_kfree;
}
+ /* Create sysfs files */
+ if ((err = dme1737_create_files(dev))) {
+ dev_err(dev, "Failed to create sysfs files.\n");
+ goto exit_kfree;
+ }
+
+ /* Register device */
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ dev_err(dev, "Failed to register device.\n");
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove_files;
+ }
+
+ return 0;
+
+exit_remove_files:
+ dme1737_remove_files(dev);
+exit_kfree:
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+exit_release_region:
+ release_region(res->start, DME1737_EXTENT);
+exit:
+ return err;
+}
+
+static int __devexit dme1737_isa_remove(struct platform_device *pdev)
+{
+ struct dme1737_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ dme1737_remove_files(&pdev->dev);
+ release_region(data->client.addr, DME1737_EXTENT);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
+
return 0;
}
-static struct i2c_driver dme1737_driver = {
+static struct platform_driver dme1737_isa_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "dme1737",
},
- .attach_adapter = dme1737_attach_adapter,
- .detach_client = dme1737_detach_client,
+ .probe = dme1737_isa_probe,
+ .remove = __devexit_p(dme1737_isa_remove),
};
+/* ---------------------------------------------------------------------
+ * Module initialization and cleanup
+ * --------------------------------------------------------------------- */
+
static int __init dme1737_init(void)
{
- return i2c_add_driver(&dme1737_driver);
+ int err;
+ unsigned short addr;
+
+ if ((err = i2c_add_driver(&dme1737_i2c_driver))) {
+ goto exit;
+ }
+
+ if (dme1737_isa_detect(0x2e, &addr) &&
+ dme1737_isa_detect(0x4e, &addr)) {
+ /* Return 0 if we didn't find an ISA device */
+ return 0;
+ }
+
+ if ((err = platform_driver_register(&dme1737_isa_driver))) {
+ goto exit_del_i2c_driver;
+ }
+
+ /* Sets global pdev as a side effect */
+ if ((err = dme1737_isa_device_add(addr))) {
+ goto exit_del_isa_driver;
+ }
+
+ return 0;
+
+exit_del_isa_driver:
+ platform_driver_unregister(&dme1737_isa_driver);
+exit_del_i2c_driver:
+ i2c_del_driver(&dme1737_i2c_driver);
+exit:
+ return err;
}
static void __exit dme1737_exit(void)
{
- i2c_del_driver(&dme1737_driver);
+ if (pdev) {
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&dme1737_isa_driver);
+ }
+
+ i2c_del_driver(&dme1737_i2c_driver);
}
MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index 1212d6b7f31..b7bd000b130 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -73,7 +73,7 @@ static const u8 DS1621_REG_TEMP[3] = {
/* Each client has this additional data */
struct ds1621_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -151,7 +151,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct ds1621_data *data = ds1621_update_client(dev);
- u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));
+ u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10));
mutex_lock(&data->update_lock);
data->temp[attr->index] = val;
@@ -266,9 +266,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -289,7 +289,7 @@ static int ds1621_detach_client(struct i2c_client *client)
struct ds1621_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ds1621_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 6f60715f34f..5d9d5cc816a 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -10,6 +10,9 @@
* The F71872F/FG is almost the same, with two more voltages monitored,
* and 6 VID inputs.
*
+ * The F71806F/FG is essentially the same as the F71872F/FG. It even has
+ * the same chip ID, so the driver can't differentiate between.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -159,7 +162,7 @@ struct f71805f_auto_point {
struct f71805f_data {
unsigned short addr;
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -1378,9 +1381,9 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
}
}
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
goto exit_remove_files;
}
@@ -1407,7 +1410,7 @@ static int __devexit f71805f_remove(struct platform_device *pdev)
struct resource *res;
int i;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
for (i = 0; i < 4; i++)
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
@@ -1485,7 +1488,7 @@ static int __init f71805f_find(int sioaddr, unsigned short *address,
static const char *names[] = {
"F71805F/FG",
- "F71872F/FG",
+ "F71872F/FG or F71806F/FG",
};
superio_enter(sioaddr);
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
new file mode 100644
index 00000000000..6db74434a02
--- /dev/null
+++ b/drivers/hwmon/f71882fg.c
@@ -0,0 +1,950 @@
+/***************************************************************************
+ * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
+ * Copyright (C) 2007 by Hans de Goede <j.w.r.degoede@hhs.nl> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <asm/io.h>
+
+#define DRVNAME "f71882fg"
+
+#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device*/
+#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
+#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */
+
+#define SIO_REG_LDSEL 0x07 /* Logical device select */
+#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_ENABLE 0x30 /* Logical device enable */
+#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
+
+#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
+#define SIO_F71882_ID 0x0541 /* Chipset ID */
+
+#define REGION_LENGTH 8
+#define ADDR_REG_OFFSET 5
+#define DATA_REG_OFFSET 6
+
+#define F71882FG_REG_PECI 0x0A
+
+#define F71882FG_REG_IN_STATUS 0x12
+#define F71882FG_REG_IN_BEEP 0x13
+#define F71882FG_REG_IN(nr) (0x20 + (nr))
+#define F71882FG_REG_IN1_HIGH 0x32
+
+#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
+#define F71882FG_REG_FAN_STATUS 0x92
+#define F71882FG_REG_FAN_BEEP 0x93
+
+#define F71882FG_REG_TEMP(nr) (0x72 + 2 * (nr))
+#define F71882FG_REG_TEMP_OVT(nr) (0x82 + 2 * (nr))
+#define F71882FG_REG_TEMP_HIGH(nr) (0x83 + 2 * (nr))
+#define F71882FG_REG_TEMP_STATUS 0x62
+#define F71882FG_REG_TEMP_BEEP 0x63
+#define F71882FG_REG_TEMP_HYST1 0x6C
+#define F71882FG_REG_TEMP_HYST23 0x6D
+#define F71882FG_REG_TEMP_TYPE 0x6B
+#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
+
+#define F71882FG_REG_START 0x01
+
+#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
+
+static struct platform_device *f71882fg_pdev = NULL;
+
+/* Super-I/O Function prototypes */
+static inline int superio_inb(int base, int reg);
+static inline int superio_inw(int base, int reg);
+static inline void superio_enter(int base);
+static inline void superio_select(int base, int ld);
+static inline void superio_exit(int base);
+
+static inline u16 fan_from_reg ( u16 reg );
+
+struct f71882fg_data {
+ unsigned short addr;
+ struct device *hwmon_dev;
+
+ struct mutex update_lock;
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+ unsigned long last_limits; /* In jiffies */
+
+ /* Register Values */
+ u8 in[9];
+ u8 in1_max;
+ u8 in_status;
+ u8 in_beep;
+ u16 fan[4];
+ u8 fan_status;
+ u8 fan_beep;
+ u8 temp[3];
+ u8 temp_ovt[3];
+ u8 temp_high[3];
+ u8 temp_hyst[3];
+ u8 temp_type[3];
+ u8 temp_status;
+ u8 temp_beep;
+ u8 temp_diode_open;
+};
+
+static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg);
+static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg);
+static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val);
+
+/* Sysfs in*/
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+ char *buf);
+static ssize_t show_in_max(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_in_max(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_in_beep(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_in_beep(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_in_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+/* Sysfs Fan */
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+ char *buf);
+static ssize_t show_fan_beep(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_fan_beep(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+/* Sysfs Temp */
+static ssize_t show_temp(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t show_temp_max(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_temp_crit(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t show_temp_type(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t show_temp_beep(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t store_temp_beep(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count);
+static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+static ssize_t show_temp_fault(struct device *dev, struct device_attribute
+ *devattr, char *buf);
+/* Sysfs misc */
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+ char *buf);
+
+static int __devinit f71882fg_probe(struct platform_device * pdev);
+static int __devexit f71882fg_remove(struct platform_device *pdev);
+static int __init f71882fg_init(void);
+static int __init f71882fg_find(int sioaddr, unsigned short *address);
+static int __init f71882fg_device_add(unsigned short address);
+static void __exit f71882fg_exit(void);
+
+static struct platform_driver f71882fg_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = f71882fg_probe,
+ .remove = __devexit_p(f71882fg_remove),
+};
+
+static struct device_attribute f71882fg_dev_attr[] =
+{
+ __ATTR( name, S_IRUGO, show_name, NULL ),
+};
+
+static struct sensor_device_attribute f71882fg_in_temp_attr[] =
+{
+ SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
+ SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
+ SENSOR_ATTR(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max, 1),
+ SENSOR_ATTR(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep, 1),
+ SENSOR_ATTR(in1_alarm, S_IRUGO, show_in_alarm, NULL, 1),
+ SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
+ SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
+ SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
+ SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
+ SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
+ SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
+ SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
+ SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
+ SENSOR_ATTR(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 0),
+ SENSOR_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 0),
+ SENSOR_ATTR(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 0),
+ SENSOR_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 0),
+ SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
+ SENSOR_ATTR(temp1_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0),
+ SENSOR_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0),
+ SENSOR_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0),
+ SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
+ SENSOR_ATTR(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 1),
+ SENSOR_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 1),
+ SENSOR_ATTR(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 1),
+ SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1),
+ SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
+ SENSOR_ATTR(temp2_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 1),
+ SENSOR_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 1),
+ SENSOR_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1),
+ SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
+ SENSOR_ATTR(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 2),
+ SENSOR_ATTR(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 2),
+ SENSOR_ATTR(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 2),
+ SENSOR_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 2),
+ SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
+ SENSOR_ATTR(temp3_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 2),
+ SENSOR_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 2),
+ SENSOR_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2)
+};
+
+static struct sensor_device_attribute f71882fg_fan_attr[] =
+{
+ SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
+ SENSOR_ATTR(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 0),
+ SENSOR_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0),
+ SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
+ SENSOR_ATTR(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 1),
+ SENSOR_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 1),
+ SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
+ SENSOR_ATTR(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 2),
+ SENSOR_ATTR(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 2),
+ SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
+ SENSOR_ATTR(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 3),
+ SENSOR_ATTR(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 3)
+};
+
+
+/* Super I/O functions */
+static inline int superio_inb(int base, int reg)
+{
+ outb(reg, base);
+ return inb(base + 1);
+}
+
+static int superio_inw(int base, int reg)
+{
+ int val;
+ outb(reg++, base);
+ val = inb(base + 1) << 8;
+ outb(reg, base);
+ val |= inb(base + 1);
+ return val;
+}
+
+static inline void superio_enter(int base)
+{
+ /* according to the datasheet the key must be send twice! */
+ outb( SIO_UNLOCK_KEY, base);
+ outb( SIO_UNLOCK_KEY, base);
+}
+
+static inline void superio_select( int base, int ld)
+{
+ outb(SIO_REG_LDSEL, base);
+ outb(ld, base + 1);
+}
+
+static inline void superio_exit(int base)
+{
+ outb(SIO_LOCK_KEY, base);
+}
+
+static inline u16 fan_from_reg(u16 reg)
+{
+ return reg ? (1500000 / reg) : 0;
+}
+
+static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
+{
+ u8 val;
+
+ outb(reg, data->addr + ADDR_REG_OFFSET);
+ val = inb(data->addr + DATA_REG_OFFSET);
+
+ return val;
+}
+
+static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
+{
+ u16 val;
+
+ outb(reg++, data->addr + ADDR_REG_OFFSET);
+ val = inb(data->addr + DATA_REG_OFFSET) << 8;
+ outb(reg, data->addr + ADDR_REG_OFFSET);
+ val |= inb(data->addr + DATA_REG_OFFSET);
+
+ return val;
+}
+
+static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
+{
+ outb(reg, data->addr + ADDR_REG_OFFSET);
+ outb(val, data->addr + DATA_REG_OFFSET);
+}
+
+static struct f71882fg_data *f71882fg_update_device(struct device * dev)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr, reg, reg2;
+
+ mutex_lock(&data->update_lock);
+
+ /* Update once every 60 seconds */
+ if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
+ !data->valid) {
+ data->in1_max = f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
+ data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
+
+ /* Get High & boundary temps*/
+ for (nr = 0; nr < 3; nr++) {
+ data->temp_ovt[nr] = f71882fg_read8(data,
+ F71882FG_REG_TEMP_OVT(nr));
+ data->temp_high[nr] = f71882fg_read8(data,
+ F71882FG_REG_TEMP_HIGH(nr));
+ }
+
+ /* Have to hardcode hyst*/
+ data->temp_hyst[0] = f71882fg_read8(data,
+ F71882FG_REG_TEMP_HYST1) >> 4;
+ /* Hyst temps 2 & 3 stored in same register */
+ reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST23);
+ data->temp_hyst[1] = reg & 0x0F;
+ data->temp_hyst[2] = reg >> 4;
+
+ /* Have to hardcode type, because temp1 is special */
+ reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
+ reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
+ if ((reg2 & 0x03) == 0x01)
+ data->temp_type[0] = 6 /* PECI */;
+ else if ((reg2 & 0x03) == 0x02)
+ data->temp_type[0] = 5 /* AMDSI */;
+ else
+ data->temp_type[0] = (reg & 0x02) ? 2 : 4;
+
+ data->temp_type[1] = (reg & 0x04) ? 2 : 4;
+ data->temp_type[2] = (reg & 0x08) ? 2 : 4;
+
+ data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
+
+ data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
+
+ data->last_limits = jiffies;
+ }
+
+ /* Update every second */
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ data->temp_status = f71882fg_read8(data,
+ F71882FG_REG_TEMP_STATUS);
+ data->temp_diode_open = f71882fg_read8(data,
+ F71882FG_REG_TEMP_DIODE_OPEN);
+ for (nr = 0; nr < 3; nr++)
+ data->temp[nr] = f71882fg_read8(data,
+ F71882FG_REG_TEMP(nr));
+
+ data->fan_status = f71882fg_read8(data,
+ F71882FG_REG_FAN_STATUS);
+ for (nr = 0; nr < 4; nr++)
+ data->fan[nr] = f71882fg_read16(data,
+ F71882FG_REG_FAN(nr));
+
+ data->in_status = f71882fg_read8(data,
+ F71882FG_REG_IN_STATUS);
+ for (nr = 0; nr < 9; nr++)
+ data->in[nr] = f71882fg_read8(data,
+ F71882FG_REG_IN(nr));
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+/* Sysfs Interface */
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int speed = fan_from_reg(data->fan[nr]);
+
+ if (speed == FAN_MIN_DETECT)
+ speed = 0;
+
+ return sprintf(buf, "%d\n", speed);
+}
+
+static ssize_t show_fan_beep(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->fan_beep & (1 << nr))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t store_fan_beep(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ if (val)
+ data->fan_beep |= 1 << nr;
+ else
+ data->fan_beep &= ~(1 << nr);
+
+ f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->fan_status & (1 << nr))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n", data->in[nr] * 8);
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+
+ return sprintf(buf, "%d\n", data->in1_max * 8);
+}
+
+static ssize_t store_in_max(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int val = simple_strtoul(buf, NULL, 10) / 8;
+
+ if (val > 255)
+ val = 255;
+
+ mutex_lock(&data->update_lock);
+ f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
+ data->in1_max = val;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_in_beep(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->in_beep & (1 << nr))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t store_in_beep(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ if (val)
+ data->in_beep |= 1 << nr;
+ else
+ data->in_beep &= ~(1 << nr);
+
+ f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_in_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->in_status & (1 << nr))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n", data->temp[nr] * 1000);
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int val = simple_strtoul(buf, NULL, 10) / 1000;
+
+ if (val > 255)
+ val = 255;
+
+ mutex_lock(&data->update_lock);
+ f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
+ data->temp_high[nr] = val;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n",
+ (data->temp_high[nr] - data->temp_hyst[nr]) * 1000);
+}
+
+static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int val = simple_strtoul(buf, NULL, 10) / 1000;
+ ssize_t ret = count;
+
+ mutex_lock(&data->update_lock);
+
+ /* convert abs to relative and check */
+ val = data->temp_high[nr] - val;
+ if (val < 0 || val > 15) {
+ ret = -EINVAL;
+ goto store_temp_max_hyst_exit;
+ }
+
+ data->temp_hyst[nr] = val;
+
+ /* convert value to register contents */
+ switch (nr) {
+ case 0:
+ val = val << 4;
+ break;
+ case 1:
+ val = val | (data->temp_hyst[2] << 4);
+ break;
+ case 2:
+ val = data->temp_hyst[1] | (val << 4);
+ break;
+ }
+
+ f71882fg_write8(data, nr ? F71882FG_REG_TEMP_HYST23 :
+ F71882FG_REG_TEMP_HYST1, val);
+
+store_temp_max_hyst_exit:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static ssize_t show_temp_crit(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
+}
+
+static ssize_t store_temp_crit(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int val = simple_strtoul(buf, NULL, 10) / 1000;
+
+ if (val > 255)
+ val = 255;
+
+ mutex_lock(&data->update_lock);
+ f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
+ data->temp_ovt[nr] = val;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n",
+ (data->temp_ovt[nr] - data->temp_hyst[nr]) * 1000);
+}
+
+static ssize_t show_temp_type(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%d\n", data->temp_type[nr]);
+}
+
+static ssize_t show_temp_beep(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->temp_beep & (1 << (nr + 1)))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t store_temp_beep(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+ int val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ if (val)
+ data->temp_beep |= 1 << (nr + 1);
+ else
+ data->temp_beep &= ~(1 << (nr + 1));
+
+ f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->temp_status & (1 << (nr + 1)))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_temp_fault(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr(devattr)->index;
+
+ if (data->temp_diode_open & (1 << (nr + 1)))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ return sprintf(buf, DRVNAME "\n");
+}
+
+
+static int __devinit f71882fg_probe(struct platform_device * pdev)
+{
+ struct f71882fg_data *data;
+ int err, i;
+ u8 start_reg;
+
+ if (!(data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL)))
+ return -ENOMEM;
+
+ data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+ mutex_init(&data->update_lock);
+ platform_set_drvdata(pdev, data);
+
+ /* Register sysfs interface files */
+ for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++) {
+ err = device_create_file(&pdev->dev, &f71882fg_dev_attr[i]);
+ if (err)
+ goto exit_unregister_sysfs;
+ }
+
+ start_reg = f71882fg_read8(data, F71882FG_REG_START);
+ if (start_reg & 0x01) {
+ for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++) {
+ err = device_create_file(&pdev->dev,
+ &f71882fg_in_temp_attr[i].dev_attr);
+ if (err)
+ goto exit_unregister_sysfs;
+ }
+ }
+
+ if (start_reg & 0x02) {
+ for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++) {
+ err = device_create_file(&pdev->dev,
+ &f71882fg_fan_attr[i].dev_attr);
+ if (err)
+ goto exit_unregister_sysfs;
+ }
+ }
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_unregister_sysfs;
+ }
+
+ return 0;
+
+exit_unregister_sysfs:
+ for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++)
+ device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]);
+
+ for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
+ device_remove_file(&pdev->dev,
+ &f71882fg_in_temp_attr[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
+ device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
+
+ kfree(data);
+
+ return err;
+}
+
+static int __devexit f71882fg_remove(struct platform_device *pdev)
+{
+ int i;
+ struct f71882fg_data *data = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ hwmon_device_unregister(data->hwmon_dev);
+
+ for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++)
+ device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]);
+
+ for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
+ device_remove_file(&pdev->dev,
+ &f71882fg_in_temp_attr[i].dev_attr);
+
+ for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
+ device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
+
+ kfree(data);
+
+ return 0;
+}
+
+static int __init f71882fg_find(int sioaddr, unsigned short *address)
+{
+ int err = -ENODEV;
+ u16 devid;
+ u8 start_reg;
+ struct f71882fg_data data;
+
+ superio_enter(sioaddr);
+
+ devid = superio_inw(sioaddr, SIO_REG_MANID);
+ if (devid != SIO_FINTEK_ID) {
+ printk(KERN_INFO DRVNAME ": Not a Fintek device\n");
+ goto exit;
+ }
+
+ devid = superio_inw(sioaddr, SIO_REG_DEVID);
+ if (devid != SIO_F71882_ID) {
+ printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
+ goto exit;
+ }
+
+ superio_select(sioaddr, SIO_F71882FG_LD_HWM);
+ if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
+ printk(KERN_WARNING DRVNAME ": Device not activated\n");
+ goto exit;
+ }
+
+ *address = superio_inw(sioaddr, SIO_REG_ADDR);
+ if (*address == 0)
+ {
+ printk(KERN_WARNING DRVNAME ": Base address not set\n");
+ goto exit;
+ }
+ *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
+
+ data.addr = *address;
+ start_reg = f71882fg_read8(&data, F71882FG_REG_START);
+ if (!(start_reg & 0x03)) {
+ printk(KERN_WARNING DRVNAME
+ ": Hardware monitoring not activated\n");
+ goto exit;
+ }
+
+ err = 0;
+ printk(KERN_INFO DRVNAME ": Found F71882FG chip at %#x, revision %d\n",
+ (unsigned int)*address,
+ (int)superio_inb(sioaddr, SIO_REG_DEVREV));
+exit:
+ superio_exit(sioaddr);
+ return err;
+}
+
+static int __init f71882fg_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + REGION_LENGTH - 1,
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ f71882fg_pdev = platform_device_alloc(DRVNAME, address);
+ if (!f71882fg_pdev)
+ return -ENOMEM;
+
+ res.name = f71882fg_pdev->name;
+ err = platform_device_add_resources(f71882fg_pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(f71882fg_pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed\n");
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(f71882fg_pdev);
+
+ return err;
+}
+
+static int __init f71882fg_init(void)
+{
+ int err = -ENODEV;
+ unsigned short address;
+
+ if (f71882fg_find(0x2e, &address) && f71882fg_find(0x4e, &address))
+ goto exit;
+
+ if ((err = platform_driver_register(&f71882fg_driver)))
+ goto exit;
+
+ if ((err = f71882fg_device_add(address)))
+ goto exit_driver;
+
+ return 0;
+
+exit_driver:
+ platform_driver_unregister(&f71882fg_driver);
+exit:
+ return err;
+}
+
+static void __exit f71882fg_exit(void)
+{
+ platform_device_unregister(f71882fg_pdev);
+ platform_driver_unregister(&f71882fg_driver);
+}
+
+MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
+MODULE_AUTHOR("Hans Edgington (hans@edgington.nl)");
+MODULE_LICENSE("GPL");
+
+module_init(f71882fg_init);
+module_exit(f71882fg_exit);
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
new file mode 100644
index 00000000000..6892f76fc18
--- /dev/null
+++ b/drivers/hwmon/f75375s.c
@@ -0,0 +1,789 @@
+/*
+ * f75375s.c - driver for the Fintek F75375/SP and F75373
+ * hardware monitoring features
+ * Copyright (C) 2006-2007 Riku Voipio <riku.voipio@movial.fi>
+ *
+ * Datasheets available at:
+ *
+ * f75375:
+ * http://www.fintek.com.tw/files/productfiles/2005111152950.pdf
+ *
+ * f75373:
+ * http://www.fintek.com.tw/files/productfiles/2005111153128.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/f75375s.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_2(f75373, f75375);
+
+/* Fintek F75375 registers */
+#define F75375_REG_CONFIG0 0x0
+#define F75375_REG_CONFIG1 0x1
+#define F75375_REG_CONFIG2 0x2
+#define F75375_REG_CONFIG3 0x3
+#define F75375_REG_ADDR 0x4
+#define F75375_REG_INTR 0x31
+#define F75375_CHIP_ID 0x5A
+#define F75375_REG_VERSION 0x5C
+#define F75375_REG_VENDOR 0x5D
+#define F75375_REG_FAN_TIMER 0x60
+
+#define F75375_REG_VOLT(nr) (0x10 + (nr))
+#define F75375_REG_VOLT_HIGH(nr) (0x20 + (nr) * 2)
+#define F75375_REG_VOLT_LOW(nr) (0x21 + (nr) * 2)
+
+#define F75375_REG_TEMP(nr) (0x14 + (nr))
+#define F75375_REG_TEMP_HIGH(nr) (0x28 + (nr) * 2)
+#define F75375_REG_TEMP_HYST(nr) (0x29 + (nr) * 2)
+
+#define F75375_REG_FAN(nr) (0x16 + (nr) * 2)
+#define F75375_REG_FAN_MIN(nr) (0x2C + (nr) * 2)
+#define F75375_REG_FAN_FULL(nr) (0x70 + (nr) * 0x10)
+#define F75375_REG_FAN_PWM_DUTY(nr) (0x76 + (nr) * 0x10)
+#define F75375_REG_FAN_PWM_CLOCK(nr) (0x7D + (nr) * 0x10)
+
+#define F75375_REG_FAN_EXP(nr) (0x74 + (nr) * 0x10)
+#define F75375_REG_FAN_B_TEMP(nr, step) ((0xA0 + (nr) * 0x10) + (step))
+#define F75375_REG_FAN_B_SPEED(nr, step) \
+ ((0xA5 + (nr) * 0x10) + (step) * 2)
+
+#define F75375_REG_PWM1_RAISE_DUTY 0x69
+#define F75375_REG_PWM2_RAISE_DUTY 0x6A
+#define F75375_REG_PWM1_DROP_DUTY 0x6B
+#define F75375_REG_PWM2_DROP_DUTY 0x6C
+
+#define FAN_CTRL_LINEAR(nr) (4 + nr)
+#define FAN_CTRL_MODE(nr) (5 + ((nr) * 2))
+
+/*
+ * Data structures and manipulation thereof
+ */
+
+struct f75375_data {
+ unsigned short addr;
+ struct i2c_client *client;
+ struct device *hwmon_dev;
+
+ const char *name;
+ int kind;
+ struct mutex update_lock; /* protect register access */
+ char valid;
+ unsigned long last_updated; /* In jiffies */
+ unsigned long last_limits; /* In jiffies */
+
+ /* Register values */
+ u8 in[4];
+ u8 in_max[4];
+ u8 in_min[4];
+ u16 fan[2];
+ u16 fan_min[2];
+ u16 fan_full[2];
+ u16 fan_exp[2];
+ u8 fan_timer;
+ u8 pwm[2];
+ u8 pwm_mode[2];
+ u8 pwm_enable[2];
+ s8 temp[2];
+ s8 temp_high[2];
+ s8 temp_max_hyst[2];
+};
+
+static int f75375_attach_adapter(struct i2c_adapter *adapter);
+static int f75375_detect(struct i2c_adapter *adapter, int address, int kind);
+static int f75375_detach_client(struct i2c_client *client);
+static int f75375_probe(struct i2c_client *client);
+static int f75375_remove(struct i2c_client *client);
+
+static struct i2c_driver f75375_legacy_driver = {
+ .driver = {
+ .name = "f75375_legacy",
+ },
+ .attach_adapter = f75375_attach_adapter,
+ .detach_client = f75375_detach_client,
+};
+
+static struct i2c_driver f75375_driver = {
+ .driver = {
+ .name = "f75375",
+ },
+ .probe = f75375_probe,
+ .remove = f75375_remove,
+};
+
+static inline int f75375_read8(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* in most cases, should be called while holding update_lock */
+static inline u16 f75375_read16(struct i2c_client *client, u8 reg)
+{
+ return ((i2c_smbus_read_byte_data(client, reg) << 8)
+ | i2c_smbus_read_byte_data(client, reg + 1));
+}
+
+static inline void f75375_write8(struct i2c_client *client, u8 reg,
+ u8 value)
+{
+ i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline void f75375_write16(struct i2c_client *client, u8 reg,
+ u16 value)
+{
+ int err = i2c_smbus_write_byte_data(client, reg, (value << 8));
+ if (err)
+ return;
+ i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF));
+}
+
+static struct f75375_data *f75375_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int nr;
+
+ mutex_lock(&data->update_lock);
+
+ /* Limit registers cache is refreshed after 60 seconds */
+ if (time_after(jiffies, data->last_limits + 60 * HZ)
+ || !data->valid) {
+ for (nr = 0; nr < 2; nr++) {
+ data->temp_high[nr] =
+ f75375_read8(client, F75375_REG_TEMP_HIGH(nr));
+ data->temp_max_hyst[nr] =
+ f75375_read8(client, F75375_REG_TEMP_HYST(nr));
+ data->fan_full[nr] =
+ f75375_read16(client, F75375_REG_FAN_FULL(nr));
+ data->fan_min[nr] =
+ f75375_read16(client, F75375_REG_FAN_MIN(nr));
+ data->fan_exp[nr] =
+ f75375_read16(client, F75375_REG_FAN_EXP(nr));
+ data->pwm[nr] = f75375_read8(client,
+ F75375_REG_FAN_PWM_DUTY(nr));
+
+ }
+ for (nr = 0; nr < 4; nr++) {
+ data->in_max[nr] =
+ f75375_read8(client, F75375_REG_VOLT_HIGH(nr));
+ data->in_min[nr] =
+ f75375_read8(client, F75375_REG_VOLT_LOW(nr));
+ }
+ data->fan_timer = f75375_read8(client, F75375_REG_FAN_TIMER);
+ data->last_limits = jiffies;
+ }
+
+ /* Measurement registers cache is refreshed after 2 second */
+ if (time_after(jiffies, data->last_updated + 2 * HZ)
+ || !data->valid) {
+ for (nr = 0; nr < 2; nr++) {
+ data->temp[nr] =
+ f75375_read8(client, F75375_REG_TEMP(nr));
+ data->fan[nr] =
+ f75375_read16(client, F75375_REG_FAN(nr));
+ }
+ for (nr = 0; nr < 4; nr++)
+ data->in[nr] =
+ f75375_read8(client, F75375_REG_VOLT(nr));
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+ return data;
+}
+
+static inline u16 rpm_from_reg(u16 reg)
+{
+ if (reg == 0 || reg == 0xffff)
+ return 0;
+ return (1500000 / reg);
+}
+
+static inline u16 rpm_to_reg(int rpm)
+{
+ if (rpm < 367 || rpm > 0xffff)
+ return 0xffff;
+ return (1500000 / rpm);
+}
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->fan_min[nr] = rpm_to_reg(val);
+ f75375_write16(client, F75375_REG_FAN_MIN(nr), data->fan_min[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_fan_exp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->fan_exp[nr] = rpm_to_reg(val);
+ f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_exp[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
+ f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), data->pwm[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
+ *attr, char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm_enable[nr]);
+}
+
+static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val)
+{
+ struct f75375_data *data = i2c_get_clientdata(client);
+ u8 fanmode;
+
+ if (val < 0 || val > 4)
+ return -EINVAL;
+
+ fanmode = f75375_read8(client, F75375_REG_FAN_TIMER);
+ fanmode = ~(3 << FAN_CTRL_MODE(nr));
+
+ switch (val) {
+ case 0: /* Full speed */
+ fanmode |= (3 << FAN_CTRL_MODE(nr));
+ data->pwm[nr] = 255;
+ f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr),
+ data->pwm[nr]);
+ break;
+ case 1: /* PWM */
+ fanmode |= (3 << FAN_CTRL_MODE(nr));
+ break;
+ case 2: /* AUTOMATIC*/
+ fanmode |= (2 << FAN_CTRL_MODE(nr));
+ break;
+ case 3: /* fan speed */
+ break;
+ }
+ f75375_write8(client, F75375_REG_FAN_TIMER, fanmode);
+ data->pwm_enable[nr] = val;
+ return 0;
+}
+
+static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+ int err = 0;
+
+ mutex_lock(&data->update_lock);
+ err = set_pwm_enable_direct(client, nr, val);
+ mutex_unlock(&data->update_lock);
+ return err ? err : count;
+}
+
+static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+ u8 conf = 0;
+
+ if (!(val == 0 || val == 1))
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ conf = f75375_read8(client, F75375_REG_CONFIG1);
+ conf = ~(1 << FAN_CTRL_LINEAR(nr));
+
+ if (val == 0)
+ conf |= (1 << FAN_CTRL_LINEAR(nr)) ;
+
+ f75375_write8(client, F75375_REG_CONFIG1, conf);
+ data->pwm_mode[nr] = val;
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute
+ *attr, char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm[nr]);
+}
+
+static ssize_t show_pwm_mode(struct device *dev, struct device_attribute
+ *attr, char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", data->pwm_mode[nr]);
+}
+
+#define VOLT_FROM_REG(val) ((val) * 8)
+#define VOLT_TO_REG(val) ((val) / 8)
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in[nr]));
+}
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_max[nr]));
+}
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_min[nr]));
+}
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+ val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
+ mutex_lock(&data->update_lock);
+ data->in_max[nr] = val;
+ f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtoul(buf, NULL, 10);
+ val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff);
+ mutex_lock(&data->update_lock);
+ data->in_min[nr] = val;
+ f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+#define TEMP_FROM_REG(val) ((val) * 1000)
+#define TEMP_TO_REG(val) ((val) / 1000)
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr]));
+}
+
+static ssize_t show_temp_max_hyst(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct f75375_data *data = f75375_update_device(dev);
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[nr]));
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtol(buf, NULL, 10);
+ val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
+ mutex_lock(&data->update_lock);
+ data->temp_high[nr] = val;
+ f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t set_temp_max_hyst(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct f75375_data *data = i2c_get_clientdata(client);
+ int val = simple_strtol(buf, NULL, 10);
+ val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127);
+ mutex_lock(&data->update_lock);
+ data->temp_max_hyst[nr] = val;
+ f75375_write8(client, F75375_REG_TEMP_HYST(nr),
+ data->temp_max_hyst[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+#define show_fan(thing) \
+static ssize_t show_##thing(struct device *dev, struct device_attribute *attr, \
+ char *buf)\
+{\
+ int nr = to_sensor_dev_attr(attr)->index;\
+ struct f75375_data *data = f75375_update_device(dev); \
+ return sprintf(buf, "%d\n", rpm_from_reg(data->thing[nr])); \
+}
+
+show_fan(fan);
+show_fan(fan_min);
+show_fan(fan_full);
+show_fan(fan_exp);
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO|S_IWUSR,
+ show_in_max, set_in_max, 0);
+static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO|S_IWUSR,
+ show_in_min, set_in_min, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO|S_IWUSR,
+ show_in_max, set_in_max, 1);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO|S_IWUSR,
+ show_in_min, set_in_min, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO|S_IWUSR,
+ show_in_max, set_in_max, 2);
+static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO|S_IWUSR,
+ show_in_min, set_in_min, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO|S_IWUSR,
+ show_in_max, set_in_max, 3);
+static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO|S_IWUSR,
+ show_in_min, set_in_min, 3);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR,
+ show_temp_max_hyst, set_temp_max_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO|S_IWUSR,
+ show_temp_max, set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR,
+ show_temp_max_hyst, set_temp_max_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO|S_IWUSR,
+ show_temp_max, set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_full, S_IRUGO, show_fan_full, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO|S_IWUSR,
+ show_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan1_exp, S_IRUGO|S_IWUSR,
+ show_fan_exp, set_fan_exp, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_full, S_IRUGO, show_fan_full, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO|S_IWUSR,
+ show_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan2_exp, S_IRUGO|S_IWUSR,
+ show_fan_exp, set_fan_exp, 1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR,
+ show_pwm, set_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR,
+ show_pwm_enable, set_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO,
+ show_pwm_mode, set_pwm_mode, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR,
+ show_pwm, set_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR,
+ show_pwm_enable, set_pwm_enable, 1);
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO,
+ show_pwm_mode, set_pwm_mode, 1);
+
+static struct attribute *f75375_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_full.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_exp.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_full.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_exp.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_mode.dev_attr.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group f75375_group = {
+ .attrs = f75375_attributes,
+};
+
+static int f75375_detach_client(struct i2c_client *client)
+{
+ int err;
+
+ f75375_remove(client);
+ err = i2c_detach_client(client);
+ if (err) {
+ dev_err(&client->dev,
+ "Client deregistration failed, "
+ "client not detached.\n");
+ return err;
+ }
+ kfree(client);
+ return 0;
+}
+
+static void f75375_init(struct i2c_client *client, struct f75375_data *data,
+ struct f75375s_platform_data *f75375s_pdata)
+{
+ int nr;
+ set_pwm_enable_direct(client, 0, f75375s_pdata->pwm_enable[0]);
+ set_pwm_enable_direct(client, 1, f75375s_pdata->pwm_enable[1]);
+ for (nr = 0; nr < 2; nr++) {
+ data->pwm[nr] = SENSORS_LIMIT(f75375s_pdata->pwm[nr], 0, 255);
+ f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr),
+ data->pwm[nr]);
+ }
+
+}
+
+static int f75375_probe(struct i2c_client *client)
+{
+ struct f75375_data *data = i2c_get_clientdata(client);
+ struct f75375s_platform_data *f75375s_pdata = client->dev.platform_data;
+ int err;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+ if (!(data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL)))
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ data->client = client;
+ mutex_init(&data->update_lock);
+
+ if (strcmp(client->name, "f75375") == 0)
+ data->kind = f75375;
+ else if (strcmp(client->name, "f75373") == 0)
+ data->kind = f75373;
+ else {
+ dev_err(&client->dev, "Unsupported device: %s\n", client->name);
+ return -ENODEV;
+ }
+
+ if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group)))
+ goto exit_free;
+
+ if (data->kind == f75375) {
+ err = sysfs_chmod_file(&client->dev.kobj,
+ &sensor_dev_attr_pwm1_mode.dev_attr.attr,
+ S_IRUGO | S_IWUSR);
+ if (err)
+ goto exit_remove;
+ err = sysfs_chmod_file(&client->dev.kobj,
+ &sensor_dev_attr_pwm2_mode.dev_attr.attr,
+ S_IRUGO | S_IWUSR);
+ if (err)
+ goto exit_remove;
+ }
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ if (f75375s_pdata != NULL)
+ f75375_init(client, data, f75375s_pdata);
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &f75375_group);
+exit_free:
+ kfree(data);
+ i2c_set_clientdata(client, NULL);
+ return err;
+}
+
+static int f75375_remove(struct i2c_client *client)
+{
+ struct f75375_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &f75375_group);
+ kfree(data);
+ i2c_set_clientdata(client, NULL);
+ return 0;
+}
+
+static int f75375_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, f75375_detect);
+}
+
+/* This function is called by i2c_probe */
+static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ u8 version = 0;
+ int err = 0;
+ const char *name = "";
+
+ if (!(client = kzalloc(sizeof(*client), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &f75375_legacy_driver;
+
+ if (kind < 0) {
+ u16 vendid = f75375_read16(client, F75375_REG_VENDOR);
+ u16 chipid = f75375_read16(client, F75375_CHIP_ID);
+ version = f75375_read8(client, F75375_REG_VERSION);
+ if (chipid == 0x0306 && vendid == 0x1934) {
+ kind = f75375;
+ } else if (chipid == 0x0204 && vendid == 0x1934) {
+ kind = f75373;
+ } else {
+ dev_err(&adapter->dev,
+ "failed,%02X,%02X,%02X\n",
+ chipid, version, vendid);
+ goto exit_free;
+ }
+ }
+
+ if (kind == f75375) {
+ name = "f75375";
+ } else if (kind == f75373) {
+ name = "f75373";
+ }
+ dev_info(&adapter->dev, "found %s version: %02X\n", name, version);
+ strlcpy(client->name, name, I2C_NAME_SIZE);
+
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ if ((err = f75375_probe(client)) < 0)
+ goto exit_detach;
+
+ return 0;
+
+exit_detach:
+ i2c_detach_client(client);
+exit_free:
+ kfree(client);
+exit:
+ return err;
+}
+
+static int __init sensors_f75375_init(void)
+{
+ int status;
+ status = i2c_add_driver(&f75375_driver);
+ if (status)
+ return status;
+
+ status = i2c_add_driver(&f75375_legacy_driver);
+ if (status)
+ i2c_del_driver(&f75375_driver);
+
+ return status;
+}
+
+static void __exit sensors_f75375_exit(void)
+{
+ i2c_del_driver(&f75375_legacy_driver);
+ i2c_del_driver(&f75375_driver);
+}
+
+MODULE_AUTHOR("Riku Voipio <riku.voipio@movial.fi>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("F75373/F75375 hardware monitoring driver");
+
+module_init(sensors_f75375_init);
+module_exit(sensors_f75375_exit);
diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c
index b34b546c68b..e67c36953b2 100644
--- a/drivers/hwmon/fscher.c
+++ b/drivers/hwmon/fscher.c
@@ -134,7 +134,7 @@ static struct i2c_driver fscher_driver = {
struct fscher_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -344,9 +344,9 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &fscher_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -367,7 +367,7 @@ static int fscher_detach_client(struct i2c_client *client)
struct fscher_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &fscher_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
new file mode 100644
index 00000000000..63a4df0580d
--- /dev/null
+++ b/drivers/hwmon/fschmd.c
@@ -0,0 +1,778 @@
+/* fschmd.c
+ *
+ * Copyright (C) 2007 Hans de Goede <j.w.r.degoede@hhs.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes,
+ * Scylla, Heracles and Heimdall chips
+ *
+ * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6
+ * (candidate) fschmd drivers:
+ * Copyright (C) 2006 Thilo Cestonaro
+ * <thilo.cestonaro.external@fujitsu-siemens.com>
+ * Copyright (C) 2004, 2005 Stefan Ott <stefan@desire.ch>
+ * Copyright (C) 2003, 2004 Reinhard Nissl <rnissl@gmx.de>
+ * Copyright (c) 2001 Martin Knoblauch <mkn@teraport.de, knobi@knobisoft.de>
+ * Copyright (C) 2000 Hermann Jung <hej@odn.de>
+ */
+
+#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>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
+
+/*
+ * The FSCHMD registers and other defines
+ */
+
+/* chip identification */
+#define FSCHMD_REG_IDENT_0 0x00
+#define FSCHMD_REG_IDENT_1 0x01
+#define FSCHMD_REG_IDENT_2 0x02
+#define FSCHMD_REG_REVISION 0x03
+
+/* global control and status */
+#define FSCHMD_REG_EVENT_STATE 0x04
+#define FSCHMD_REG_CONTROL 0x05
+
+#define FSCHMD_CONTROL_ALERT_LED_MASK 0x01
+
+/* watchdog (support to be implemented) */
+#define FSCHMD_REG_WDOG_PRESET 0x28
+#define FSCHMD_REG_WDOG_STATE 0x23
+#define FSCHMD_REG_WDOG_CONTROL 0x21
+
+/* voltages, weird order is to keep the same order as the old drivers */
+static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 };
+
+/* minimum pwm at which the fan is driven (pwm can by increased depending on
+ the temp. Notice that for the scy some fans share there minimum speed.
+ Also notice that with the scy the sensor order is different then with the
+ other chips, this order was in the 2.4 driver and kept for consistency. */
+static const u8 FSCHMD_REG_FAN_MIN[5][6] = {
+ { 0x55, 0x65 }, /* pos */
+ { 0x55, 0x65, 0xb5 }, /* her */
+ { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */
+ { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */
+ { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */
+};
+
+/* actual fan speed */
+static const u8 FSCHMD_REG_FAN_ACT[5][6] = {
+ { 0x0e, 0x6b, 0xab }, /* pos */
+ { 0x0e, 0x6b, 0xbb }, /* her */
+ { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */
+ { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */
+ { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */
+};
+
+/* fan status registers */
+static const u8 FSCHMD_REG_FAN_STATE[5][6] = {
+ { 0x0d, 0x62, 0xa2 }, /* pos */
+ { 0x0d, 0x62, 0xb2 }, /* her */
+ { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */
+ { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */
+ { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */
+};
+
+/* fan ripple / divider registers */
+static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = {
+ { 0x0f, 0x6f, 0xaf }, /* pos */
+ { 0x0f, 0x6f, 0xbf }, /* her */
+ { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */
+ { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */
+ { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */
+};
+
+static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 };
+
+/* Fan status register bitmasks */
+#define FSCHMD_FAN_ALARM_MASK 0x04 /* called fault by FSC! */
+#define FSCHMD_FAN_NOT_PRESENT_MASK 0x08 /* not documented */
+
+
+/* actual temperature registers */
+static const u8 FSCHMD_REG_TEMP_ACT[5][5] = {
+ { 0x64, 0x32, 0x35 }, /* pos */
+ { 0x64, 0x32, 0x35 }, /* her */
+ { 0x64, 0xD0, 0x32, 0x35 }, /* scy */
+ { 0x64, 0x32, 0x35 }, /* hrc */
+ { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */
+};
+
+/* temperature state registers */
+static const u8 FSCHMD_REG_TEMP_STATE[5][5] = {
+ { 0x71, 0x81, 0x91 }, /* pos */
+ { 0x71, 0x81, 0x91 }, /* her */
+ { 0x71, 0xd1, 0x81, 0x91 }, /* scy */
+ { 0x71, 0x81, 0x91 }, /* hrc */
+ { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */
+};
+
+/* temperature high limit registers, FSC does not document these. Proven to be
+ there with field testing on the fscher and fschrc, already supported / used
+ in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
+ at these addresses, but doesn't want to confirm they are the same as with
+ the fscher?? */
+static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = {
+ { 0, 0, 0 }, /* pos */
+ { 0x76, 0x86, 0x96 }, /* her */
+ { 0x76, 0xd6, 0x86, 0x96 }, /* scy */
+ { 0x76, 0x86, 0x96 }, /* hrc */
+ { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */
+};
+
+/* These were found through experimenting with an fscher, currently they are
+ not used, but we keep them around for future reference.
+static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 };
+static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */
+
+static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 };
+
+/* temp status register bitmasks */
+#define FSCHMD_TEMP_WORKING_MASK 0x01
+#define FSCHMD_TEMP_ALERT_MASK 0x02
+/* there only really is an alarm if the sensor is working and alert == 1 */
+#define FSCHMD_TEMP_ALARM_MASK \
+ (FSCHMD_TEMP_WORKING_MASK | FSCHMD_TEMP_ALERT_MASK)
+
+/* our driver name */
+#define FSCHMD_NAME "fschmd"
+
+/*
+ * Functions declarations
+ */
+
+static int fschmd_attach_adapter(struct i2c_adapter *adapter);
+static int fschmd_detach_client(struct i2c_client *client);
+static struct fschmd_data *fschmd_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static struct i2c_driver fschmd_driver = {
+ .driver = {
+ .name = FSCHMD_NAME,
+ },
+ .attach_adapter = fschmd_attach_adapter,
+ .detach_client = fschmd_detach_client,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct fschmd_data {
+ struct i2c_client client;
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ int kind;
+ char valid; /* zero until following fields are valid */
+ unsigned long last_updated; /* in jiffies */
+
+ /* register values */
+ u8 global_control; /* global control register */
+ u8 volt[3]; /* 12, 5, battery voltage */
+ u8 temp_act[5]; /* temperature */
+ u8 temp_status[5]; /* status of sensor */
+ u8 temp_max[5]; /* high temp limit, notice: undocumented! */
+ u8 fan_act[6]; /* fans revolutions per second */
+ u8 fan_status[6]; /* fan status */
+ u8 fan_min[6]; /* fan min value for rps */
+ u8 fan_ripple[6]; /* divider for rps */
+};
+
+/*
+ * Sysfs attr show / store functions
+ */
+
+static ssize_t show_in_value(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ const int max_reading[3] = { 14200, 6600, 3300 };
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ return sprintf(buf, "%d\n", (data->volt[index] *
+ max_reading[index] + 128) / 255);
+}
+
+
+#define TEMP_FROM_REG(val) (((val) - 128) * 1000)
+
+static ssize_t show_temp_value(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[index]));
+}
+
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index]));
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = dev_get_drvdata(dev);
+ long v = simple_strtol(buf, NULL, 10) / 1000;
+
+ v = SENSORS_LIMIT(v, -128, 127) + 128;
+
+ mutex_lock(&data->update_lock);
+ i2c_smbus_write_byte_data(&data->client,
+ FSCHMD_REG_TEMP_LIMIT[data->kind][index], v);
+ data->temp_max[index] = v;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_temp_fault(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ /* bit 0 set means sensor working ok, so no fault! */
+ if (data->temp_status[index] & FSCHMD_TEMP_WORKING_MASK)
+ return sprintf(buf, "0\n");
+ else
+ return sprintf(buf, "1\n");
+}
+
+static ssize_t show_temp_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ if ((data->temp_status[index] & FSCHMD_TEMP_ALARM_MASK) ==
+ FSCHMD_TEMP_ALARM_MASK)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+
+#define RPM_FROM_REG(val) ((val) * 60)
+
+static ssize_t show_fan_value(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[index]));
+}
+
+static ssize_t show_fan_div(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ /* bits 2..7 reserved => mask with 3 */
+ return sprintf(buf, "%d\n", 1 << (data->fan_ripple[index] & 3));
+}
+
+static ssize_t store_fan_div(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ u8 reg;
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = dev_get_drvdata(dev);
+ /* supported values: 2, 4, 8 */
+ unsigned long v = simple_strtoul(buf, NULL, 10);
+
+ switch (v) {
+ case 2: v = 1; break;
+ case 4: v = 2; break;
+ case 8: v = 3; break;
+ default:
+ dev_err(dev, "fan_div value %lu not supported. "
+ "Choose one of 2, 4 or 8!\n", v);
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->update_lock);
+
+ reg = i2c_smbus_read_byte_data(&data->client,
+ FSCHMD_REG_FAN_RIPPLE[data->kind][index]);
+
+ /* bits 2..7 reserved => mask with 0x03 */
+ reg &= ~0x03;
+ reg |= v;
+
+ i2c_smbus_write_byte_data(&data->client,
+ FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg);
+
+ data->fan_ripple[index] = reg;
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_fan_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ if (data->fan_status[index] & FSCHMD_FAN_ALARM_MASK)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_fan_fault(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT_MASK)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+
+static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ int val = fschmd_update_device(dev)->fan_min[index];
+
+ /* 0 = allow turning off, 1-255 = 50-100% */
+ if (val)
+ val = val / 2 + 128;
+
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ struct fschmd_data *data = dev_get_drvdata(dev);
+ unsigned long v = simple_strtoul(buf, NULL, 10);
+
+ /* register: 0 = allow turning off, 1-255 = 50-100% */
+ if (v) {
+ v = SENSORS_LIMIT(v, 128, 255);
+ v = (v - 128) * 2 + 1;
+ }
+
+ mutex_lock(&data->update_lock);
+
+ i2c_smbus_write_byte_data(&data->client,
+ FSCHMD_REG_FAN_MIN[data->kind][index], v);
+ data->fan_min[index] = v;
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+
+/* The FSC hwmon family has the ability to force an attached alert led to flash
+ from software, we export this as an alert_led sysfs attr */
+static ssize_t show_alert_led(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct fschmd_data *data = fschmd_update_device(dev);
+
+ if (data->global_control & FSCHMD_CONTROL_ALERT_LED_MASK)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t store_alert_led(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count)
+{
+ u8 reg;
+ struct fschmd_data *data = dev_get_drvdata(dev);
+ unsigned long v = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+
+ reg = i2c_smbus_read_byte_data(&data->client, FSCHMD_REG_CONTROL);
+
+ if (v)
+ reg |= FSCHMD_CONTROL_ALERT_LED_MASK;
+ else
+ reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK;
+
+ i2c_smbus_write_byte_data(&data->client, FSCHMD_REG_CONTROL, reg);
+
+ data->global_control = reg;
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static struct sensor_device_attribute fschmd_attr[] = {
+ SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
+ SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
+ SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
+ SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0),
+};
+
+static struct sensor_device_attribute fschmd_temp_attr[] = {
+ SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
+ SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0),
+ SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0),
+ SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0),
+ SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
+ SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1),
+ SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1),
+ SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1),
+ SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2),
+ SENSOR_ATTR(temp3_max, 0644, show_temp_max, store_temp_max, 2),
+ SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2),
+ SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2),
+ SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3),
+ SENSOR_ATTR(temp4_max, 0644, show_temp_max, store_temp_max, 3),
+ SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3),
+ SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3),
+ SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4),
+ SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4),
+ SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
+ SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
+};
+
+static struct sensor_device_attribute fschmd_fan_attr[] = {
+ SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0),
+ SENSOR_ATTR(fan1_div, 0644, show_fan_div, store_fan_div, 0),
+ SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0),
+ SENSOR_ATTR(fan1_fault, 0444, show_fan_fault, NULL, 0),
+ SENSOR_ATTR(pwm1_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+ store_pwm_auto_point1_pwm, 0),
+ SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1),
+ SENSOR_ATTR(fan2_div, 0644, show_fan_div, store_fan_div, 1),
+ SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1),
+ SENSOR_ATTR(fan2_fault, 0444, show_fan_fault, NULL, 1),
+ SENSOR_ATTR(pwm2_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+ store_pwm_auto_point1_pwm, 1),
+ SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2),
+ SENSOR_ATTR(fan3_div, 0644, show_fan_div, store_fan_div, 2),
+ SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2),
+ SENSOR_ATTR(fan3_fault, 0444, show_fan_fault, NULL, 2),
+ SENSOR_ATTR(pwm3_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+ store_pwm_auto_point1_pwm, 2),
+ SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3),
+ SENSOR_ATTR(fan4_div, 0644, show_fan_div, store_fan_div, 3),
+ SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3),
+ SENSOR_ATTR(fan4_fault, 0444, show_fan_fault, NULL, 3),
+ SENSOR_ATTR(pwm4_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+ store_pwm_auto_point1_pwm, 3),
+ SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4),
+ SENSOR_ATTR(fan5_div, 0644, show_fan_div, store_fan_div, 4),
+ SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4),
+ SENSOR_ATTR(fan5_fault, 0444, show_fan_fault, NULL, 4),
+ SENSOR_ATTR(pwm5_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+ store_pwm_auto_point1_pwm, 4),
+ SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5),
+ SENSOR_ATTR(fan6_div, 0644, show_fan_div, store_fan_div, 5),
+ SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5),
+ SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
+ SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
+ store_pwm_auto_point1_pwm, 5),
+};
+
+
+/*
+ * Real code
+ */
+
+static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct fschmd_data *data;
+ u8 revision;
+ const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
+ "Heracles", "Heimdall" };
+ const char * const client_names[5] = { "fscpos", "fscher", "fscscy",
+ "fschrc", "fschmd" };
+ int i, err = 0;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ * client structure, even though we cannot fill it completely yet.
+ * But it allows us to access i2c_smbus_read_byte_data. */
+ if (!(data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL)))
+ return -ENOMEM;
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &fschmd_driver;
+ mutex_init(&data->update_lock);
+
+ /* Detect & Identify the chip */
+ if (kind <= 0) {
+ char id[4];
+
+ id[0] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_IDENT_0);
+ id[1] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_IDENT_1);
+ id[2] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_IDENT_2);
+ id[3] = '\0';
+
+ if (!strcmp(id, "PEG"))
+ kind = fscpos;
+ else if (!strcmp(id, "HER"))
+ kind = fscher;
+ else if (!strcmp(id, "SCY"))
+ kind = fscscy;
+ else if (!strcmp(id, "HRC"))
+ kind = fschrc;
+ else if (!strcmp(id, "HMD"))
+ kind = fschmd;
+ else
+ goto exit_free;
+ }
+
+ if (kind == fscpos) {
+ /* The Poseidon has hardwired temp limits, fill these
+ in for the alarm resetting code */
+ data->temp_max[0] = 70 + 128;
+ data->temp_max[1] = 50 + 128;
+ data->temp_max[2] = 50 + 128;
+ }
+
+ /* i2c kind goes from 1-5, we want from 0-4 to address arrays */
+ data->kind = kind - 1;
+ strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE);
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) {
+ err = device_create_file(&client->dev,
+ &fschmd_attr[i].dev_attr);
+ if (err)
+ goto exit_detach;
+ }
+
+ for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) {
+ /* Poseidon doesn't have TEMP_LIMIT registers */
+ if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show ==
+ show_temp_max)
+ continue;
+
+ err = device_create_file(&client->dev,
+ &fschmd_temp_attr[i].dev_attr);
+ if (err)
+ goto exit_detach;
+ }
+
+ for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) {
+ /* Poseidon doesn't have a FAN_MIN register for its 3rd fan */
+ if (kind == fscpos &&
+ !strcmp(fschmd_fan_attr[i].dev_attr.attr.name,
+ "pwm3_auto_point1_pwm"))
+ continue;
+
+ err = device_create_file(&client->dev,
+ &fschmd_fan_attr[i].dev_attr);
+ if (err)
+ goto exit_detach;
+ }
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ data->hwmon_dev = NULL;
+ goto exit_detach;
+ }
+
+ revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
+ printk(KERN_INFO FSCHMD_NAME ": Detected FSC %s chip, revision: %d\n",
+ names[data->kind], (int) revision);
+
+ return 0;
+
+exit_detach:
+ fschmd_detach_client(client); /* will also free data for us */
+ return err;
+
+exit_free:
+ kfree(data);
+ return err;
+}
+
+static int fschmd_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, fschmd_detect);
+}
+
+static int fschmd_detach_client(struct i2c_client *client)
+{
+ struct fschmd_data *data = i2c_get_clientdata(client);
+ int i, err;
+
+ /* Check if registered in case we're called from fschmd_detect
+ to cleanup after an error */
+ if (data->hwmon_dev)
+ hwmon_device_unregister(data->hwmon_dev);
+
+ for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++)
+ device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);
+ for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
+ device_remove_file(&client->dev,
+ &fschmd_temp_attr[i].dev_attr);
+ for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++)
+ device_remove_file(&client->dev,
+ &fschmd_fan_attr[i].dev_attr);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(data);
+ return 0;
+}
+
+static struct fschmd_data *fschmd_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct fschmd_data *data = i2c_get_clientdata(client);
+ int i;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
+
+ for (i = 0; i < FSCHMD_NO_TEMP_SENSORS[data->kind]; i++) {
+ data->temp_act[i] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_TEMP_ACT[data->kind][i]);
+ data->temp_status[i] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_TEMP_STATE[data->kind][i]);
+
+ /* The fscpos doesn't have TEMP_LIMIT registers */
+ if (FSCHMD_REG_TEMP_LIMIT[data->kind][i])
+ data->temp_max[i] = i2c_smbus_read_byte_data(
+ client,
+ FSCHMD_REG_TEMP_LIMIT[data->kind][i]);
+
+ /* reset alarm if the alarm condition is gone,
+ the chip doesn't do this itself */
+ if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) ==
+ FSCHMD_TEMP_ALARM_MASK &&
+ data->temp_act[i] < data->temp_max[i])
+ i2c_smbus_write_byte_data(client,
+ FSCHMD_REG_TEMP_STATE[data->kind][i],
+ FSCHMD_TEMP_ALERT_MASK);
+ }
+
+ for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
+ data->fan_act[i] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_FAN_ACT[data->kind][i]);
+ data->fan_status[i] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_FAN_STATE[data->kind][i]);
+ data->fan_ripple[i] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_FAN_RIPPLE[data->kind][i]);
+
+ /* The fscpos third fan doesn't have a fan_min */
+ if (FSCHMD_REG_FAN_MIN[data->kind][i])
+ data->fan_min[i] = i2c_smbus_read_byte_data(
+ client,
+ FSCHMD_REG_FAN_MIN[data->kind][i]);
+
+ /* reset fan status if speed is back to > 0 */
+ if ((data->fan_status[i] & FSCHMD_FAN_ALARM_MASK) &&
+ data->fan_act[i])
+ i2c_smbus_write_byte_data(client,
+ FSCHMD_REG_FAN_STATE[data->kind][i],
+ FSCHMD_FAN_ALARM_MASK);
+ }
+
+ for (i = 0; i < 3; i++)
+ data->volt[i] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_VOLT[i]);
+
+ data->global_control = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_CONTROL);
+
+ /* To be implemented in the future
+ data->watchdog[0] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_WDOG_PRESET);
+ data->watchdog[1] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_WDOG_STATE);
+ data->watchdog[2] = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_WDOG_CONTROL); */
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+static int __init fschmd_init(void)
+{
+ return i2c_add_driver(&fschmd_driver);
+}
+
+static void __exit fschmd_exit(void)
+{
+ i2c_del_driver(&fschmd_driver);
+}
+
+MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and "
+ "Heimdall driver");
+MODULE_LICENSE("GPL");
+
+module_init(fschmd_init);
+module_exit(fschmd_exit);
diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c
index ea506a77f9c..92c9703d0ac 100644
--- a/drivers/hwmon/fscpos.c
+++ b/drivers/hwmon/fscpos.c
@@ -115,7 +115,7 @@ static struct i2c_driver fscpos_driver = {
*/
struct fscpos_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* 0 until following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -539,9 +539,9 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -562,7 +562,7 @@ static int fscpos_detach_client(struct i2c_client *client)
struct fscpos_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &fscpos_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index c103640455a..bb58d9866a3 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -119,7 +119,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
/* Each client has this additional data */
struct gl518_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
enum chips type;
struct mutex update_lock;
@@ -460,9 +460,9 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &gl518_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -502,7 +502,7 @@ static int gl518_detach_client(struct i2c_client *client)
struct gl518_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &gl518_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index ebe7b9aaa91..2d39d8fc238 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -2,7 +2,7 @@
gl520sm.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>,
- Kyösti Mälkki <kmalkki@cc.hut.fi>
+ Kyösti Mälkki <kmalkki@cc.hut.fi>
Copyright (c) 2005 Maarten Deprez <maartendeprez@users.sourceforge.net>
This program is free software; you can redistribute it and/or modify
@@ -122,7 +122,7 @@ static struct i2c_driver gl520_driver = {
/* Client data */
struct gl520_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until the following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -622,9 +622,9 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
}
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -685,7 +685,7 @@ static int gl520_detach_client(struct i2c_client *client)
struct gl520_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &gl520_group);
sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
@@ -805,7 +805,7 @@ static void __exit sensors_gl520sm_exit(void)
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
- "Kyösti Mälkki <kmalkki@cc.hut.fi>, "
+ "Kyösti Mälkki <kmalkki@cc.hut.fi>, "
"Maarten Deprez <maartendeprez@users.sourceforge.net>");
MODULE_DESCRIPTION("GL520SM driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index e0cf5e6fe5b..bab5fd2e4df 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -28,7 +28,7 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
-#include <linux/input.h>
+#include <linux/input-polldev.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/module.h>
@@ -61,13 +61,12 @@
#define INIT_TIMEOUT_MSECS 4000 /* wait up to 4s for device init ... */
#define INIT_WAIT_MSECS 200 /* ... in 200ms increments */
-#define HDAPS_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */
+#define HDAPS_POLL_INTERVAL 50 /* poll for input every 1/20s (50 ms)*/
#define HDAPS_INPUT_FUZZ 4 /* input event threshold */
#define HDAPS_INPUT_FLAT 4
-static struct timer_list hdaps_timer;
static struct platform_device *pdev;
-static struct input_dev *hdaps_idev;
+static struct input_polled_dev *hdaps_idev;
static unsigned int hdaps_invert;
static u8 km_activity;
static int rest_x;
@@ -323,24 +322,19 @@ static void hdaps_calibrate(void)
__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &rest_x, &rest_y);
}
-static void hdaps_mousedev_poll(unsigned long unused)
+static void hdaps_mousedev_poll(struct input_polled_dev *dev)
{
+ struct input_dev *input_dev = dev->input;
int x, y;
- /* Cannot sleep. Try nonblockingly. If we fail, try again later. */
- if (mutex_trylock(&hdaps_mtx)) {
- mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD);
- return;
- }
+ mutex_lock(&hdaps_mtx);
if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y))
goto out;
- input_report_abs(hdaps_idev, ABS_X, x - rest_x);
- input_report_abs(hdaps_idev, ABS_Y, y - rest_y);
- input_sync(hdaps_idev);
-
- mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD);
+ input_report_abs(input_dev, ABS_X, x - rest_x);
+ input_report_abs(input_dev, ABS_Y, y - rest_y);
+ input_sync(input_dev);
out:
mutex_unlock(&hdaps_mtx);
@@ -480,14 +474,14 @@ static struct attribute_group hdaps_attribute_group = {
/* Module stuff */
/* hdaps_dmi_match - found a match. return one, short-circuiting the hunt. */
-static int __init hdaps_dmi_match(struct dmi_system_id *id)
+static int __init hdaps_dmi_match(const struct dmi_system_id *id)
{
printk(KERN_INFO "hdaps: %s detected.\n", id->ident);
return 1;
}
/* hdaps_dmi_match_invert - found an inverted match. */
-static int __init hdaps_dmi_match_invert(struct dmi_system_id *id)
+static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
{
hdaps_invert = 1;
printk(KERN_INFO "hdaps: inverting axis readings.\n");
@@ -536,6 +530,7 @@ static struct dmi_system_id __initdata hdaps_whitelist[] = {
static int __init hdaps_init(void)
{
+ struct input_dev *idev;
int ret;
if (!dmi_check_system(hdaps_whitelist)) {
@@ -563,39 +558,37 @@ static int __init hdaps_init(void)
if (ret)
goto out_device;
- hdaps_idev = input_allocate_device();
+ hdaps_idev = input_allocate_polled_device();
if (!hdaps_idev) {
ret = -ENOMEM;
goto out_group;
}
+ hdaps_idev->poll = hdaps_mousedev_poll;
+ hdaps_idev->poll_interval = HDAPS_POLL_INTERVAL;
+
/* initial calibrate for the input device */
hdaps_calibrate();
/* initialize the input class */
- hdaps_idev->name = "hdaps";
- hdaps_idev->dev.parent = &pdev->dev;
- hdaps_idev->evbit[0] = BIT(EV_ABS);
- input_set_abs_params(hdaps_idev, ABS_X,
+ idev = hdaps_idev->input;
+ idev->name = "hdaps";
+ idev->dev.parent = &pdev->dev;
+ idev->evbit[0] = BIT_MASK(EV_ABS);
+ input_set_abs_params(idev, ABS_X,
-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
- input_set_abs_params(hdaps_idev, ABS_Y,
+ input_set_abs_params(idev, ABS_Y,
-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
- ret = input_register_device(hdaps_idev);
+ ret = input_register_polled_device(hdaps_idev);
if (ret)
goto out_idev;
- /* start up our timer for the input device */
- init_timer(&hdaps_timer);
- hdaps_timer.function = hdaps_mousedev_poll;
- hdaps_timer.expires = jiffies + HDAPS_POLL_PERIOD;
- add_timer(&hdaps_timer);
-
printk(KERN_INFO "hdaps: driver successfully loaded.\n");
return 0;
out_idev:
- input_free_device(hdaps_idev);
+ input_free_polled_device(hdaps_idev);
out_group:
sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
out_device:
@@ -611,8 +604,8 @@ out:
static void __exit hdaps_exit(void)
{
- del_timer_sync(&hdaps_timer);
- input_unregister_device(hdaps_idev);
+ input_unregister_polled_device(hdaps_idev);
+ input_free_polled_device(hdaps_idev);
sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
platform_device_unregister(pdev);
platform_driver_unregister(&hdaps_driver);
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
index f17e771e42f..3330667280b 100644
--- a/drivers/hwmon/hwmon-vid.c
+++ b/drivers/hwmon/hwmon-vid.c
@@ -200,7 +200,7 @@ static u8 find_vrm(u8 eff_family, u8 eff_model, u8 eff_stepping, u8 vendor)
u8 vid_which_vrm(void)
{
- struct cpuinfo_x86 *c = cpu_data;
+ struct cpuinfo_x86 *c = &cpu_data(0);
u32 eax;
u8 eff_family, eff_model, eff_stepping, vrm_ret;
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index affcc00764d..3db28450a3b 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -28,17 +28,17 @@ static DEFINE_IDR(hwmon_idr);
static DEFINE_SPINLOCK(idr_lock);
/**
- * hwmon_device_register - register w/ hwmon sysfs class
+ * hwmon_device_register - register w/ hwmon
* @dev: the device to register
*
- * hwmon_device_unregister() must be called when the class device is no
+ * hwmon_device_unregister() must be called when the device is no
* longer needed.
*
- * Returns the pointer to the new struct class device.
+ * Returns the pointer to the new device.
*/
-struct class_device *hwmon_device_register(struct device *dev)
+struct device *hwmon_device_register(struct device *dev)
{
- struct class_device *cdev;
+ struct device *hwdev;
int id, err;
again:
@@ -55,34 +55,33 @@ again:
return ERR_PTR(err);
id = id & MAX_ID_MASK;
- cdev = class_device_create(hwmon_class, NULL, MKDEV(0,0), dev,
- HWMON_ID_FORMAT, id);
+ hwdev = device_create(hwmon_class, dev, MKDEV(0,0), HWMON_ID_FORMAT, id);
- if (IS_ERR(cdev)) {
+ if (IS_ERR(hwdev)) {
spin_lock(&idr_lock);
idr_remove(&hwmon_idr, id);
spin_unlock(&idr_lock);
}
- return cdev;
+ return hwdev;
}
/**
* hwmon_device_unregister - removes the previously registered class device
*
- * @cdev: the class device to destroy
+ * @dev: the class device to destroy
*/
-void hwmon_device_unregister(struct class_device *cdev)
+void hwmon_device_unregister(struct device *dev)
{
int id;
- if (likely(sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1)) {
- class_device_unregister(cdev);
+ if (likely(sscanf(dev->bus_id, HWMON_ID_FORMAT, &id) == 1)) {
+ device_unregister(dev);
spin_lock(&idr_lock);
idr_remove(&hwmon_idr, id);
spin_unlock(&idr_lock);
} else
- dev_dbg(cdev->dev,
+ dev_dbg(dev->parent,
"hwmon_device_unregister() failed: bad class ID!\n");
}
diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c
new file mode 100644
index 00000000000..6ac5c6f5358
--- /dev/null
+++ b/drivers/hwmon/i5k_amb.c
@@ -0,0 +1,552 @@
+/*
+ * A hwmon driver for the Intel 5000 series chipset FB-DIMM AMB
+ * temperature sensors
+ * Copyright (C) 2007 IBM
+ *
+ * Author: Darrick J. Wong <djwong@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+#define DRVNAME "i5k_amb"
+
+#define I5K_REG_AMB_BASE_ADDR 0x48
+#define I5K_REG_AMB_LEN_ADDR 0x50
+#define I5K_REG_CHAN0_PRESENCE_ADDR 0x64
+#define I5K_REG_CHAN1_PRESENCE_ADDR 0x66
+
+#define AMB_REG_TEMP_MIN_ADDR 0x80
+#define AMB_REG_TEMP_MID_ADDR 0x81
+#define AMB_REG_TEMP_MAX_ADDR 0x82
+#define AMB_REG_TEMP_STATUS_ADDR 0x84
+#define AMB_REG_TEMP_ADDR 0x85
+
+#define AMB_CONFIG_SIZE 2048
+#define AMB_FUNC_3_OFFSET 768
+
+static unsigned long amb_reg_temp_status(unsigned int amb)
+{
+ return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_STATUS_ADDR +
+ AMB_CONFIG_SIZE * amb;
+}
+
+static unsigned long amb_reg_temp_min(unsigned int amb)
+{
+ return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_MIN_ADDR +
+ AMB_CONFIG_SIZE * amb;
+}
+
+static unsigned long amb_reg_temp_mid(unsigned int amb)
+{
+ return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_MID_ADDR +
+ AMB_CONFIG_SIZE * amb;
+}
+
+static unsigned long amb_reg_temp_max(unsigned int amb)
+{
+ return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_MAX_ADDR +
+ AMB_CONFIG_SIZE * amb;
+}
+
+static unsigned long amb_reg_temp(unsigned int amb)
+{
+ return AMB_FUNC_3_OFFSET + AMB_REG_TEMP_ADDR +
+ AMB_CONFIG_SIZE * amb;
+}
+
+#define MAX_MEM_CHANNELS 4
+#define MAX_AMBS_PER_CHANNEL 16
+#define MAX_AMBS (MAX_MEM_CHANNELS * \
+ MAX_AMBS_PER_CHANNEL)
+/*
+ * Ugly hack: For some reason the highest bit is set if there
+ * are _any_ DIMMs in the channel. Attempting to read from
+ * this "high-order" AMB results in a memory bus error, so
+ * for now we'll just ignore that top bit, even though that
+ * might prevent us from seeing the 16th DIMM in the channel.
+ */
+#define REAL_MAX_AMBS_PER_CHANNEL 15
+#define KNOBS_PER_AMB 5
+
+static unsigned long amb_num_from_reg(unsigned int byte_num, unsigned int bit)
+{
+ return byte_num * MAX_AMBS_PER_CHANNEL + bit;
+}
+
+#define AMB_SYSFS_NAME_LEN 16
+struct i5k_device_attribute {
+ struct sensor_device_attribute s_attr;
+ char name[AMB_SYSFS_NAME_LEN];
+};
+
+struct i5k_amb_data {
+ struct device *hwmon_dev;
+
+ unsigned long amb_base;
+ unsigned long amb_len;
+ u16 amb_present[MAX_MEM_CHANNELS];
+ void __iomem *amb_mmio;
+ struct i5k_device_attribute *attrs;
+ unsigned int num_attrs;
+};
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", DRVNAME);
+}
+
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct platform_device *amb_pdev;
+
+static u8 amb_read_byte(struct i5k_amb_data *data, unsigned long offset)
+{
+ return ioread8(data->amb_mmio + offset);
+}
+
+static void amb_write_byte(struct i5k_amb_data *data, unsigned long offset,
+ u8 val)
+{
+ iowrite8(val, data->amb_mmio + offset);
+}
+
+static ssize_t show_amb_alarm(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i5k_amb_data *data = dev_get_drvdata(dev);
+
+ if (!(amb_read_byte(data, amb_reg_temp_status(attr->index)) & 0x20) &&
+ (amb_read_byte(data, amb_reg_temp_status(attr->index)) & 0x8))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t store_amb_min(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i5k_amb_data *data = dev_get_drvdata(dev);
+ unsigned long temp = simple_strtoul(buf, NULL, 10) / 500;
+
+ if (temp > 255)
+ temp = 255;
+
+ amb_write_byte(data, amb_reg_temp_min(attr->index), temp);
+ return count;
+}
+
+static ssize_t store_amb_mid(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i5k_amb_data *data = dev_get_drvdata(dev);
+ unsigned long temp = simple_strtoul(buf, NULL, 10) / 500;
+
+ if (temp > 255)
+ temp = 255;
+
+ amb_write_byte(data, amb_reg_temp_mid(attr->index), temp);
+ return count;
+}
+
+static ssize_t store_amb_max(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i5k_amb_data *data = dev_get_drvdata(dev);
+ unsigned long temp = simple_strtoul(buf, NULL, 10) / 500;
+
+ if (temp > 255)
+ temp = 255;
+
+ amb_write_byte(data, amb_reg_temp_max(attr->index), temp);
+ return count;
+}
+
+static ssize_t show_amb_min(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i5k_amb_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n",
+ 500 * amb_read_byte(data, amb_reg_temp_min(attr->index)));
+}
+
+static ssize_t show_amb_mid(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i5k_amb_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n",
+ 500 * amb_read_byte(data, amb_reg_temp_mid(attr->index)));
+}
+
+static ssize_t show_amb_max(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i5k_amb_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n",
+ 500 * amb_read_byte(data, amb_reg_temp_max(attr->index)));
+}
+
+static ssize_t show_amb_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i5k_amb_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n",
+ 500 * amb_read_byte(data, amb_reg_temp(attr->index)));
+}
+
+static int __devinit i5k_amb_hwmon_init(struct platform_device *pdev)
+{
+ int i, j, k, d = 0;
+ u16 c;
+ int res = 0;
+ int num_ambs = 0;
+ struct i5k_amb_data *data = platform_get_drvdata(pdev);
+
+ /* Count the number of AMBs found */
+ /* ignore the high-order bit, see "Ugly hack" comment above */
+ for (i = 0; i < MAX_MEM_CHANNELS; i++)
+ num_ambs += hweight16(data->amb_present[i] & 0x7fff);
+
+ /* Set up sysfs stuff */
+ data->attrs = kzalloc(sizeof(*data->attrs) * num_ambs * KNOBS_PER_AMB,
+ GFP_KERNEL);
+ if (!data->attrs)
+ return -ENOMEM;
+ data->num_attrs = 0;
+
+ for (i = 0; i < MAX_MEM_CHANNELS; i++) {
+ c = data->amb_present[i];
+ for (j = 0; j < REAL_MAX_AMBS_PER_CHANNEL; j++, c >>= 1) {
+ struct i5k_device_attribute *iattr;
+
+ k = amb_num_from_reg(i, j);
+ if (!(c & 0x1))
+ continue;
+ d++;
+
+ /* Temperature sysfs knob */
+ iattr = data->attrs + data->num_attrs;
+ snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+ "temp%d_input", d);
+ iattr->s_attr.dev_attr.attr.name = iattr->name;
+ iattr->s_attr.dev_attr.attr.mode = S_IRUGO;
+ iattr->s_attr.dev_attr.show = show_amb_temp;
+ iattr->s_attr.index = k;
+ res = device_create_file(&pdev->dev,
+ &iattr->s_attr.dev_attr);
+ if (res)
+ goto exit_remove;
+ data->num_attrs++;
+
+ /* Temperature min sysfs knob */
+ iattr = data->attrs + data->num_attrs;
+ snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+ "temp%d_min", d);
+ iattr->s_attr.dev_attr.attr.name = iattr->name;
+ iattr->s_attr.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
+ iattr->s_attr.dev_attr.show = show_amb_min;
+ iattr->s_attr.dev_attr.store = store_amb_min;
+ iattr->s_attr.index = k;
+ res = device_create_file(&pdev->dev,
+ &iattr->s_attr.dev_attr);
+ if (res)
+ goto exit_remove;
+ data->num_attrs++;
+
+ /* Temperature mid sysfs knob */
+ iattr = data->attrs + data->num_attrs;
+ snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+ "temp%d_mid", d);
+ iattr->s_attr.dev_attr.attr.name = iattr->name;
+ iattr->s_attr.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
+ iattr->s_attr.dev_attr.show = show_amb_mid;
+ iattr->s_attr.dev_attr.store = store_amb_mid;
+ iattr->s_attr.index = k;
+ res = device_create_file(&pdev->dev,
+ &iattr->s_attr.dev_attr);
+ if (res)
+ goto exit_remove;
+ data->num_attrs++;
+
+ /* Temperature max sysfs knob */
+ iattr = data->attrs + data->num_attrs;
+ snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+ "temp%d_max", d);
+ iattr->s_attr.dev_attr.attr.name = iattr->name;
+ iattr->s_attr.dev_attr.attr.mode = S_IWUSR | S_IRUGO;
+ iattr->s_attr.dev_attr.show = show_amb_max;
+ iattr->s_attr.dev_attr.store = store_amb_max;
+ iattr->s_attr.index = k;
+ res = device_create_file(&pdev->dev,
+ &iattr->s_attr.dev_attr);
+ if (res)
+ goto exit_remove;
+ data->num_attrs++;
+
+ /* Temperature alarm sysfs knob */
+ iattr = data->attrs + data->num_attrs;
+ snprintf(iattr->name, AMB_SYSFS_NAME_LEN,
+ "temp%d_alarm", d);
+ iattr->s_attr.dev_attr.attr.name = iattr->name;
+ iattr->s_attr.dev_attr.attr.mode = S_IRUGO;
+ iattr->s_attr.dev_attr.show = show_amb_alarm;
+ iattr->s_attr.index = k;
+ res = device_create_file(&pdev->dev,
+ &iattr->s_attr.dev_attr);
+ if (res)
+ goto exit_remove;
+ data->num_attrs++;
+ }
+ }
+
+ res = device_create_file(&pdev->dev, &dev_attr_name);
+ if (res)
+ goto exit_remove;
+
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ res = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ return res;
+
+exit_remove:
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ for (i = 0; i < data->num_attrs; i++)
+ device_remove_file(&pdev->dev, &data->attrs[i].s_attr.dev_attr);
+ kfree(data->attrs);
+
+ return res;
+}
+
+static int __devinit i5k_amb_add(void)
+{
+ int res = -ENODEV;
+
+ /* only ever going to be one of these */
+ amb_pdev = platform_device_alloc(DRVNAME, 0);
+ if (!amb_pdev)
+ return -ENOMEM;
+
+ res = platform_device_add(amb_pdev);
+ if (res)
+ goto err;
+ return 0;
+
+err:
+ platform_device_put(amb_pdev);
+ return res;
+}
+
+static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data)
+{
+ struct pci_dev *pcidev;
+ u32 val32;
+ int res = -ENODEV;
+
+ /* Find AMB register memory space */
+ pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_5000_ERR,
+ NULL);
+ if (!pcidev)
+ return -ENODEV;
+
+ if (pci_read_config_dword(pcidev, I5K_REG_AMB_BASE_ADDR, &val32))
+ goto out;
+ data->amb_base = val32;
+
+ if (pci_read_config_dword(pcidev, I5K_REG_AMB_LEN_ADDR, &val32))
+ goto out;
+ data->amb_len = val32;
+
+ /* Is it big enough? */
+ if (data->amb_len < AMB_CONFIG_SIZE * MAX_AMBS) {
+ dev_err(&pcidev->dev, "AMB region too small!\n");
+ goto out;
+ }
+
+ res = 0;
+out:
+ pci_dev_put(pcidev);
+ return res;
+}
+
+static int __devinit i5k_channel_probe(u16 *amb_present, unsigned long dev_id)
+{
+ struct pci_dev *pcidev;
+ u16 val16;
+ int res = -ENODEV;
+
+ /* Copy the DIMM presence map for these two channels */
+ pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, NULL);
+ if (!pcidev)
+ return -ENODEV;
+
+ if (pci_read_config_word(pcidev, I5K_REG_CHAN0_PRESENCE_ADDR, &val16))
+ goto out;
+ amb_present[0] = val16;
+
+ if (pci_read_config_word(pcidev, I5K_REG_CHAN1_PRESENCE_ADDR, &val16))
+ goto out;
+ amb_present[1] = val16;
+
+ res = 0;
+
+out:
+ pci_dev_put(pcidev);
+ return res;
+}
+
+static int __devinit i5k_amb_probe(struct platform_device *pdev)
+{
+ struct i5k_amb_data *data;
+ struct resource *reso;
+ int res = -ENODEV;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /* Figure out where the AMB registers live */
+ res = i5k_find_amb_registers(data);
+ if (res)
+ goto err;
+
+ /* Copy the DIMM presence map for the first two channels */
+ res = i5k_channel_probe(&data->amb_present[0],
+ PCI_DEVICE_ID_INTEL_5000_FBD0);
+ if (res)
+ goto err;
+
+ /* Copy the DIMM presence map for the optional second two channels */
+ i5k_channel_probe(&data->amb_present[2],
+ PCI_DEVICE_ID_INTEL_5000_FBD1);
+
+ /* Set up resource regions */
+ reso = request_mem_region(data->amb_base, data->amb_len, DRVNAME);
+ if (!reso) {
+ res = -EBUSY;
+ goto err;
+ }
+
+ data->amb_mmio = ioremap_nocache(data->amb_base, data->amb_len);
+ if (!data->amb_mmio) {
+ res = -EBUSY;
+ goto err_map_failed;
+ }
+
+ platform_set_drvdata(pdev, data);
+
+ res = i5k_amb_hwmon_init(pdev);
+ if (res)
+ goto err_init_failed;
+
+ return res;
+
+err_init_failed:
+ iounmap(data->amb_mmio);
+ platform_set_drvdata(pdev, NULL);
+err_map_failed:
+ release_mem_region(data->amb_base, data->amb_len);
+err:
+ kfree(data);
+ return res;
+}
+
+static int __devexit i5k_amb_remove(struct platform_device *pdev)
+{
+ int i;
+ struct i5k_amb_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ for (i = 0; i < data->num_attrs; i++)
+ device_remove_file(&pdev->dev, &data->attrs[i].s_attr.dev_attr);
+ kfree(data->attrs);
+ iounmap(data->amb_mmio);
+ release_mem_region(data->amb_base, data->amb_len);
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+ return 0;
+}
+
+static struct platform_driver i5k_amb_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = i5k_amb_probe,
+ .remove = __devexit_p(i5k_amb_remove),
+};
+
+static int __init i5k_amb_init(void)
+{
+ int res;
+
+ res = platform_driver_register(&i5k_amb_driver);
+ if (res)
+ return res;
+
+ res = i5k_amb_add();
+ if (res)
+ platform_driver_unregister(&i5k_amb_driver);
+
+ return res;
+}
+
+static void __exit i5k_amb_exit(void)
+{
+ platform_device_unregister(amb_pdev);
+ platform_driver_unregister(&i5k_amb_driver);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_DESCRIPTION("Intel 5000 chipset FB-DIMM AMB temperature sensor");
+MODULE_LICENSE("GPL");
+
+module_init(i5k_amb_init);
+module_exit(i5k_amb_exit);
diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c
new file mode 100644
index 00000000000..9c9cdb0685e
--- /dev/null
+++ b/drivers/hwmon/ibmpex.c
@@ -0,0 +1,605 @@
+/*
+ * A hwmon driver for the IBM PowerExecutive temperature/power sensors
+ * Copyright (C) 2007 IBM
+ *
+ * Author: Darrick J. Wong <djwong@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/ipmi.h>
+#include <linux/module.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+
+#define REFRESH_INTERVAL (2 * HZ)
+#define DRVNAME "ibmpex"
+
+#define PEX_GET_VERSION 1
+#define PEX_GET_SENSOR_COUNT 2
+#define PEX_GET_SENSOR_NAME 3
+#define PEX_RESET_HIGH_LOW 4
+#define PEX_GET_SENSOR_DATA 6
+
+#define PEX_NET_FUNCTION 0x3A
+#define PEX_COMMAND 0x3C
+
+static inline u16 extract_value(const char *data, int offset)
+{
+ return be16_to_cpup((u16 *)&data[offset]);
+}
+
+#define TEMP_SENSOR 1
+#define POWER_SENSOR 2
+
+#define PEX_SENSOR_TYPE_LEN 3
+static u8 const power_sensor_sig[] = {0x70, 0x77, 0x72};
+static u8 const temp_sensor_sig[] = {0x74, 0x65, 0x6D};
+
+#define PEX_MULT_LEN 2
+static u8 const watt_sensor_sig[] = {0x41, 0x43};
+
+#define PEX_NUM_SENSOR_FUNCS 3
+static char const * const power_sensor_name_templates[] = {
+ "%s%d_average",
+ "%s%d_average_lowest",
+ "%s%d_average_highest"
+};
+static char const * const temp_sensor_name_templates[] = {
+ "%s%d_input",
+ "%s%d_input_lowest",
+ "%s%d_input_highest"
+};
+
+static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data);
+static void ibmpex_register_bmc(int iface, struct device *dev);
+static void ibmpex_bmc_gone(int iface);
+
+struct ibmpex_sensor_data {
+ int in_use;
+ s16 values[PEX_NUM_SENSOR_FUNCS];
+ int multiplier;
+
+ struct sensor_device_attribute_2 attr[PEX_NUM_SENSOR_FUNCS];
+};
+
+struct ibmpex_bmc_data {
+ struct list_head list;
+ struct device *hwmon_dev;
+ struct device *bmc_device;
+ struct mutex lock;
+ char valid;
+ unsigned long last_updated; /* In jiffies */
+
+ struct ipmi_addr address;
+ struct completion read_complete;
+ ipmi_user_t user;
+ int interface;
+
+ struct kernel_ipmi_msg tx_message;
+ unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH];
+ long tx_msgid;
+
+ unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH];
+ unsigned long rx_msg_len;
+ unsigned char rx_result;
+ int rx_recv_type;
+
+ unsigned char sensor_major;
+ unsigned char sensor_minor;
+
+ unsigned char num_sensors;
+ struct ibmpex_sensor_data *sensors;
+};
+
+struct ibmpex_driver_data {
+ struct list_head bmc_data;
+ struct ipmi_smi_watcher bmc_events;
+ struct ipmi_user_hndl ipmi_hndlrs;
+};
+
+static struct ibmpex_driver_data driver_data = {
+ .bmc_data = LIST_HEAD_INIT(driver_data.bmc_data),
+ .bmc_events = {
+ .owner = THIS_MODULE,
+ .new_smi = ibmpex_register_bmc,
+ .smi_gone = ibmpex_bmc_gone,
+ },
+ .ipmi_hndlrs = {
+ .ipmi_recv_hndl = ibmpex_msg_handler,
+ },
+};
+
+static int ibmpex_send_message(struct ibmpex_bmc_data *data)
+{
+ int err;
+
+ err = ipmi_validate_addr(&data->address, sizeof(data->address));
+ if (err)
+ goto out;
+
+ data->tx_msgid++;
+ err = ipmi_request_settime(data->user, &data->address, data->tx_msgid,
+ &data->tx_message, data, 0, 0, 0);
+ if (err)
+ goto out1;
+
+ return 0;
+out1:
+ dev_err(data->bmc_device, "request_settime=%x\n", err);
+ return err;
+out:
+ dev_err(data->bmc_device, "validate_addr=%x\n", err);
+ return err;
+}
+
+static int ibmpex_ver_check(struct ibmpex_bmc_data *data)
+{
+ data->tx_msg_data[0] = PEX_GET_VERSION;
+ data->tx_message.data_len = 1;
+ ibmpex_send_message(data);
+
+ wait_for_completion(&data->read_complete);
+
+ if (data->rx_result || data->rx_msg_len != 6)
+ return -ENOENT;
+
+ data->sensor_major = data->rx_msg_data[0];
+ data->sensor_minor = data->rx_msg_data[1];
+
+ dev_info(data->bmc_device, "Found BMC with sensor interface "
+ "v%d.%d %d-%02d-%02d on interface %d\n",
+ data->sensor_major,
+ data->sensor_minor,
+ extract_value(data->rx_msg_data, 2),
+ data->rx_msg_data[4],
+ data->rx_msg_data[5],
+ data->interface);
+
+ return 0;
+}
+
+static int ibmpex_query_sensor_count(struct ibmpex_bmc_data *data)
+{
+ data->tx_msg_data[0] = PEX_GET_SENSOR_COUNT;
+ data->tx_message.data_len = 1;
+ ibmpex_send_message(data);
+
+ wait_for_completion(&data->read_complete);
+
+ if (data->rx_result || data->rx_msg_len != 1)
+ return -ENOENT;
+
+ return data->rx_msg_data[0];
+}
+
+static int ibmpex_query_sensor_name(struct ibmpex_bmc_data *data, int sensor)
+{
+ data->tx_msg_data[0] = PEX_GET_SENSOR_NAME;
+ data->tx_msg_data[1] = sensor;
+ data->tx_message.data_len = 2;
+ ibmpex_send_message(data);
+
+ wait_for_completion(&data->read_complete);
+
+ if (data->rx_result || data->rx_msg_len < 1)
+ return -ENOENT;
+
+ return 0;
+}
+
+static int ibmpex_query_sensor_data(struct ibmpex_bmc_data *data, int sensor)
+{
+ data->tx_msg_data[0] = PEX_GET_SENSOR_DATA;
+ data->tx_msg_data[1] = sensor;
+ data->tx_message.data_len = 2;
+ ibmpex_send_message(data);
+
+ wait_for_completion(&data->read_complete);
+
+ if (data->rx_result || data->rx_msg_len < 26) {
+ dev_err(data->bmc_device, "Error reading sensor %d.\n",
+ sensor);
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static int ibmpex_reset_high_low_data(struct ibmpex_bmc_data *data)
+{
+ data->tx_msg_data[0] = PEX_RESET_HIGH_LOW;
+ data->tx_message.data_len = 1;
+ ibmpex_send_message(data);
+
+ wait_for_completion(&data->read_complete);
+
+ return 0;
+}
+
+static void ibmpex_update_device(struct ibmpex_bmc_data *data)
+{
+ int i, err;
+
+ mutex_lock(&data->lock);
+ if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) &&
+ data->valid)
+ goto out;
+
+ for (i = 0; i < data->num_sensors; i++) {
+ if (!data->sensors[i].in_use)
+ continue;
+ err = ibmpex_query_sensor_data(data, i);
+ if (err)
+ continue;
+ data->sensors[i].values[0] =
+ extract_value(data->rx_msg_data, 16);
+ data->sensors[i].values[1] =
+ extract_value(data->rx_msg_data, 18);
+ data->sensors[i].values[2] =
+ extract_value(data->rx_msg_data, 20);
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+
+out:
+ mutex_unlock(&data->lock);
+}
+
+static struct ibmpex_bmc_data *get_bmc_data(int iface)
+{
+ struct ibmpex_bmc_data *p, *next;
+
+ list_for_each_entry_safe(p, next, &driver_data.bmc_data, list)
+ if (p->interface == iface)
+ return p;
+
+ return NULL;
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", DRVNAME);
+}
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+static ssize_t ibmpex_show_sensor(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct ibmpex_bmc_data *data = dev_get_drvdata(dev);
+ int mult = data->sensors[attr->index].multiplier;
+ ibmpex_update_device(data);
+
+ return sprintf(buf, "%d\n",
+ data->sensors[attr->index].values[attr->nr] * mult);
+}
+
+static ssize_t ibmpex_reset_high_low(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf,
+ size_t count)
+{
+ struct ibmpex_bmc_data *data = dev_get_drvdata(dev);
+
+ ibmpex_reset_high_low_data(data);
+
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(reset_high_low, S_IWUSR, NULL,
+ ibmpex_reset_high_low, 0);
+
+static int is_power_sensor(const char *sensor_id, int len)
+{
+ if (len < PEX_SENSOR_TYPE_LEN)
+ return 0;
+
+ if (!memcmp(sensor_id, power_sensor_sig, PEX_SENSOR_TYPE_LEN))
+ return 1;
+ return 0;
+}
+
+static int is_temp_sensor(const char *sensor_id, int len)
+{
+ if (len < PEX_SENSOR_TYPE_LEN)
+ return 0;
+
+ if (!memcmp(sensor_id, temp_sensor_sig, PEX_SENSOR_TYPE_LEN))
+ return 1;
+ return 0;
+}
+
+static int power_sensor_multiplier(const char *sensor_id, int len)
+{
+ int i;
+
+ for (i = PEX_SENSOR_TYPE_LEN; i < len - 1; i++)
+ if (!memcmp(&sensor_id[i], watt_sensor_sig, PEX_MULT_LEN))
+ return 1000000;
+
+ return 100000;
+}
+
+static int create_sensor(struct ibmpex_bmc_data *data, int type,
+ int counter, int sensor, int func)
+{
+ int err;
+ char *n;
+
+ n = kmalloc(32, GFP_KERNEL);
+ if (!n)
+ return -ENOMEM;
+
+ if (type == TEMP_SENSOR)
+ sprintf(n, temp_sensor_name_templates[func], "temp", counter);
+ else if (type == POWER_SENSOR)
+ sprintf(n, power_sensor_name_templates[func], "power", counter);
+
+ data->sensors[sensor].attr[func].dev_attr.attr.name = n;
+ data->sensors[sensor].attr[func].dev_attr.attr.mode = S_IRUGO;
+ data->sensors[sensor].attr[func].dev_attr.show = ibmpex_show_sensor;
+ data->sensors[sensor].attr[func].index = sensor;
+ data->sensors[sensor].attr[func].nr = func;
+
+ err = device_create_file(data->bmc_device,
+ &data->sensors[sensor].attr[func].dev_attr);
+ if (err) {
+ data->sensors[sensor].attr[func].dev_attr.attr.name = NULL;
+ kfree(n);
+ return err;
+ }
+
+ return 0;
+}
+
+static int ibmpex_find_sensors(struct ibmpex_bmc_data *data)
+{
+ int i, j, err;
+ int sensor_type;
+ int sensor_counter;
+ int num_power = 0;
+ int num_temp = 0;
+
+ err = ibmpex_query_sensor_count(data);
+ if (err <= 0)
+ return -ENOENT;
+ data->num_sensors = err;
+
+ data->sensors = kzalloc(data->num_sensors * sizeof(*data->sensors),
+ GFP_KERNEL);
+ if (!data->sensors)
+ return -ENOMEM;
+
+ for (i = 0; i < data->num_sensors; i++) {
+ err = ibmpex_query_sensor_name(data, i);
+ if (err)
+ continue;
+
+ if (is_power_sensor(data->rx_msg_data, data->rx_msg_len)) {
+ sensor_type = POWER_SENSOR;
+ num_power++;
+ sensor_counter = num_power;
+ data->sensors[i].multiplier =
+ power_sensor_multiplier(data->rx_msg_data,
+ data->rx_msg_len);
+ } else if (is_temp_sensor(data->rx_msg_data,
+ data->rx_msg_len)) {
+ sensor_type = TEMP_SENSOR;
+ num_temp++;
+ sensor_counter = num_temp;
+ data->sensors[i].multiplier = 1;
+ } else
+ continue;
+
+ data->sensors[i].in_use = 1;
+
+ /* Create attributes */
+ for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
+ err = create_sensor(data, sensor_type, sensor_counter,
+ i, j);
+ if (err)
+ goto exit_remove;
+ }
+ }
+
+ err = device_create_file(data->bmc_device,
+ &sensor_dev_attr_reset_high_low.dev_attr);
+ if (err)
+ goto exit_remove;
+
+ err = device_create_file(data->bmc_device,
+ &sensor_dev_attr_name.dev_attr);
+ if (err)
+ goto exit_remove;
+
+ return 0;
+
+exit_remove:
+ device_remove_file(data->bmc_device,
+ &sensor_dev_attr_reset_high_low.dev_attr);
+ device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr);
+ for (i = 0; i < data->num_sensors; i++)
+ for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
+ if (!data->sensors[i].attr[j].dev_attr.attr.name)
+ continue;
+ device_remove_file(data->bmc_device,
+ &data->sensors[i].attr[j].dev_attr);
+ kfree(data->sensors[i].attr[j].dev_attr.attr.name);
+ }
+
+ kfree(data->sensors);
+ return err;
+}
+
+static void ibmpex_register_bmc(int iface, struct device *dev)
+{
+ struct ibmpex_bmc_data *data;
+ int err;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(dev, "Insufficient memory for BMC interface.\n");
+ return;
+ }
+
+ data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ data->address.channel = IPMI_BMC_CHANNEL;
+ data->address.data[0] = 0;
+ data->interface = iface;
+ data->bmc_device = dev;
+
+ /* Create IPMI messaging interface user */
+ err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs,
+ data, &data->user);
+ if (err < 0) {
+ dev_err(dev, "Unable to register user with IPMI "
+ "interface %d\n", data->interface);
+ goto out;
+ }
+
+ mutex_init(&data->lock);
+
+ /* Initialize message */
+ data->tx_msgid = 0;
+ init_completion(&data->read_complete);
+ data->tx_message.netfn = PEX_NET_FUNCTION;
+ data->tx_message.cmd = PEX_COMMAND;
+ data->tx_message.data = data->tx_msg_data;
+
+ /* Does this BMC support PowerExecutive? */
+ err = ibmpex_ver_check(data);
+ if (err)
+ goto out_user;
+
+ /* Register the BMC as a HWMON class device */
+ data->hwmon_dev = hwmon_device_register(data->bmc_device);
+
+ if (IS_ERR(data->hwmon_dev)) {
+ dev_err(data->bmc_device, "Unable to register hwmon "
+ "device for IPMI interface %d\n",
+ data->interface);
+ goto out_user;
+ }
+
+ /* finally add the new bmc data to the bmc data list */
+ dev_set_drvdata(dev, data);
+ list_add_tail(&data->list, &driver_data.bmc_data);
+
+ /* Now go find all the sensors */
+ err = ibmpex_find_sensors(data);
+ if (err) {
+ dev_err(data->bmc_device, "Error %d finding sensors\n", err);
+ goto out_register;
+ }
+
+ return;
+
+out_register:
+ hwmon_device_unregister(data->hwmon_dev);
+out_user:
+ ipmi_destroy_user(data->user);
+out:
+ kfree(data);
+}
+
+static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data)
+{
+ int i, j;
+
+ device_remove_file(data->bmc_device,
+ &sensor_dev_attr_reset_high_low.dev_attr);
+ device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr);
+ for (i = 0; i < data->num_sensors; i++)
+ for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) {
+ if (!data->sensors[i].attr[j].dev_attr.attr.name)
+ continue;
+ device_remove_file(data->bmc_device,
+ &data->sensors[i].attr[j].dev_attr);
+ kfree(data->sensors[i].attr[j].dev_attr.attr.name);
+ }
+
+ list_del(&data->list);
+ dev_set_drvdata(data->bmc_device, NULL);
+ hwmon_device_unregister(data->hwmon_dev);
+ ipmi_destroy_user(data->user);
+ kfree(data->sensors);
+ kfree(data);
+}
+
+static void ibmpex_bmc_gone(int iface)
+{
+ struct ibmpex_bmc_data *data = get_bmc_data(iface);
+
+ if (!data)
+ return;
+
+ ibmpex_bmc_delete(data);
+}
+
+static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
+{
+ struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
+
+ if (msg->msgid != data->tx_msgid) {
+ dev_err(data->bmc_device, "Mismatch between received msgid "
+ "(%02x) and transmitted msgid (%02x)!\n",
+ (int)msg->msgid,
+ (int)data->tx_msgid);
+ ipmi_free_recv_msg(msg);
+ return;
+ }
+
+ data->rx_recv_type = msg->recv_type;
+ if (msg->msg.data_len > 0)
+ data->rx_result = msg->msg.data[0];
+ else
+ data->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE;
+
+ if (msg->msg.data_len > 1) {
+ data->rx_msg_len = msg->msg.data_len - 1;
+ memcpy(data->rx_msg_data, msg->msg.data + 1, data->rx_msg_len);
+ } else
+ data->rx_msg_len = 0;
+
+ ipmi_free_recv_msg(msg);
+ complete(&data->read_complete);
+}
+
+static int __init ibmpex_init(void)
+{
+ return ipmi_smi_watcher_register(&driver_data.bmc_events);
+}
+
+static void __exit ibmpex_exit(void)
+{
+ struct ibmpex_bmc_data *p, *next;
+
+ ipmi_smi_watcher_unregister(&driver_data.bmc_events);
+ list_for_each_entry_safe(p, next, &driver_data.bmc_data, list)
+ ibmpex_bmc_delete(p);
+}
+
+MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>");
+MODULE_DESCRIPTION("IBM PowerExecutive power/temperature sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(ibmpex_init);
+module_exit(ibmpex_exit);
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index d75dba9b810..6a182e14cf5 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -141,10 +141,10 @@ static int fix_pwm_polarity;
/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */
-#define IT87_REG_FAN(nr) (0x0d + (nr))
-#define IT87_REG_FAN_MIN(nr) (0x10 + (nr))
-#define IT87_REG_FANX(nr) (0x18 + (nr))
-#define IT87_REG_FANX_MIN(nr) (0x1b + (nr))
+static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
+static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86 };
+static const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83 };
+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))
@@ -222,7 +222,7 @@ struct it87_sio_data {
/* For each registered chip, we need to keep some data in memory.
The structure is dynamically allocated. */
struct it87_data {
- struct class_device *class_dev;
+ struct device *hwmon_dev;
enum chips type;
unsigned short addr;
@@ -235,8 +235,8 @@ struct it87_data {
u8 in_max[8]; /* Register value */
u8 in_min[8]; /* Register value */
u8 has_fan; /* Bitfield, fans enabled */
- u16 fan[3]; /* Register values, possibly combined */
- u16 fan_min[3]; /* Register values, possibly combined */
+ u16 fan[5]; /* Register values, possibly combined */
+ u16 fan_min[5]; /* Register values, possibly combined */
u8 temp[3]; /* Register value */
u8 temp_high[3]; /* Register value */
u8 temp_low[3]; /* Register value */
@@ -555,7 +555,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
}
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
- it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+ it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -596,7 +596,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
/* Restore fan min limit */
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
- it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+ it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -729,9 +729,9 @@ static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN16_TO_REG(val);
- it87_write_value(data, IT87_REG_FAN_MIN(nr),
+ it87_write_value(data, IT87_REG_FAN_MIN[nr],
data->fan_min[nr] & 0xff);
- it87_write_value(data, IT87_REG_FANX_MIN(nr),
+ it87_write_value(data, IT87_REG_FANX_MIN[nr],
data->fan_min[nr] >> 8);
mutex_unlock(&data->update_lock);
return count;
@@ -751,6 +751,8 @@ static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \
show_fan16_offset(1);
show_fan16_offset(2);
show_fan16_offset(3);
+show_fan16_offset(4);
+show_fan16_offset(5);
/* Alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
@@ -763,7 +765,7 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
static ssize_t
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct it87_data *data = it87_update_device(dev);
+ struct it87_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", data->vrm);
}
static ssize_t
@@ -851,6 +853,10 @@ static struct attribute *it87_attributes_opt[] = {
&sensor_dev_attr_fan2_min16.dev_attr.attr,
&sensor_dev_attr_fan3_input16.dev_attr.attr,
&sensor_dev_attr_fan3_min16.dev_attr.attr,
+ &sensor_dev_attr_fan4_input16.dev_attr.attr,
+ &sensor_dev_attr_fan4_min16.dev_attr.attr,
+ &sensor_dev_attr_fan5_input16.dev_attr.attr,
+ &sensor_dev_attr_fan5_min16.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
@@ -1024,6 +1030,20 @@ static int __devinit it87_probe(struct platform_device *pdev)
&sensor_dev_attr_fan3_min16.dev_attr)))
goto ERROR4;
}
+ if (data->has_fan & (1 << 3)) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_fan4_input16.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan4_min16.dev_attr)))
+ goto ERROR4;
+ }
+ if (data->has_fan & (1 << 4)) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_fan5_input16.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan5_min16.dev_attr)))
+ goto ERROR4;
+ }
} else {
/* 8-bit tachometers with clock divider */
if (data->has_fan & (1 << 0)) {
@@ -1089,9 +1109,9 @@ static int __devinit it87_probe(struct platform_device *pdev)
goto ERROR4;
}
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR4;
}
@@ -1113,7 +1133,7 @@ static int __devexit it87_remove(struct platform_device *pdev)
{
struct it87_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &it87_group);
sysfs_remove_group(&pdev->dev.kobj, &it87_group_opt);
@@ -1260,6 +1280,10 @@ static void __devinit it87_init_device(struct platform_device *pdev)
it87_write_value(data, IT87_REG_FAN_16BIT,
tmp | 0x07);
}
+ if (tmp & (1 << 4))
+ data->has_fan |= (1 << 3); /* fan4 enabled */
+ if (tmp & (1 << 5))
+ data->has_fan |= (1 << 4); /* fan5 enabled */
}
/* Set current fan mode registers and the default settings for the
@@ -1314,21 +1338,21 @@ static struct it87_data *it87_update_device(struct device *dev)
data->in[8] =
it87_read_value(data, IT87_REG_VIN(8));
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 5; i++) {
/* Skip disabled fans */
if (!(data->has_fan & (1 << i)))
continue;
data->fan_min[i] =
- it87_read_value(data, IT87_REG_FAN_MIN(i));
+ it87_read_value(data, IT87_REG_FAN_MIN[i]);
data->fan[i] = it87_read_value(data,
- IT87_REG_FAN(i));
+ IT87_REG_FAN[i]);
/* Add high byte if in 16-bit mode */
if (data->type == it8716 || data->type == it8718) {
data->fan[i] |= it87_read_value(data,
- IT87_REG_FANX(i)) << 8;
+ IT87_REG_FANX[i]) << 8;
data->fan_min[i] |= it87_read_value(data,
- IT87_REG_FANX_MIN(i)) << 8;
+ IT87_REG_FANX_MIN[i]) << 8;
}
}
for (i = 0; i < 3; i++) {
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
index 5d8d0ca08fa..bd2bde0ef95 100644
--- a/drivers/hwmon/k8temp.c
+++ b/drivers/hwmon/k8temp.c
@@ -38,7 +38,7 @@
#define SEL_CORE 0x04
struct k8temp_data {
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
const char *name;
char valid; /* zero until following fields are valid */
@@ -225,10 +225,10 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
if (err)
goto exit_remove;
- data->class_dev = hwmon_device_register(&pdev->dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -255,7 +255,7 @@ static void __devexit k8temp_remove(struct pci_dev *pdev)
{
struct k8temp_data *data = dev_get_drvdata(&pdev->dev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
device_remove_file(&pdev->dev,
&sensor_dev_attr_temp1_input.dev_attr);
device_remove_file(&pdev->dev,
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 2162d69a8c0..650b07d5b90 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -154,7 +154,7 @@ static struct i2c_driver lm63_driver = {
struct lm63_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -502,9 +502,9 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_remove_files;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -533,7 +533,7 @@ static void lm63_init_client(struct i2c_client *client)
/* Start converting if needed */
if (data->config & 0x40) { /* standby */
- dev_dbg(&client->dev, "Switching to operational mode");
+ dev_dbg(&client->dev, "Switching to operational mode\n");
data->config &= 0xA7;
i2c_smbus_write_byte_data(client, LM63_REG_CONFIG1,
data->config);
@@ -561,7 +561,7 @@ static int lm63_detach_client(struct i2c_client *client)
struct lm63_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm63_group);
sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
index 275d392eca6..d435f003292 100644
--- a/drivers/hwmon/lm70.c
+++ b/drivers/hwmon/lm70.c
@@ -31,14 +31,15 @@
#include <linux/err.h>
#include <linux/sysfs.h>
#include <linux/hwmon.h>
+#include <linux/mutex.h>
#include <linux/spi/spi.h>
-#include <asm/semaphore.h>
+
#define DRVNAME "lm70"
struct lm70 {
- struct class_device *cdev;
- struct semaphore sem;
+ struct device *hwmon_dev;
+ struct mutex lock;
};
/* sysfs hook function */
@@ -51,7 +52,7 @@ static ssize_t lm70_sense_temp(struct device *dev,
s16 raw=0;
struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
- if (down_interruptible(&p_lm70->sem))
+ if (mutex_lock_interruptible(&p_lm70->lock))
return -ERESTARTSYS;
/*
@@ -81,14 +82,22 @@ static ssize_t lm70_sense_temp(struct device *dev,
* So it's equivalent to multiplying by 0.25 * 1000 = 250.
*/
val = ((int)raw/32) * 250;
- status = sprintf(buf, "%+d\n", val); /* millidegrees Celsius */
+ status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */
out:
- up(&p_lm70->sem);
+ mutex_unlock(&p_lm70->lock);
return status;
}
static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL);
+static ssize_t lm70_show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ return sprintf(buf, "lm70\n");
+}
+
+static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL);
+
/*----------------------------------------------------------------------*/
static int __devinit lm70_probe(struct spi_device *spi)
@@ -104,18 +113,19 @@ static int __devinit lm70_probe(struct spi_device *spi)
if (!p_lm70)
return -ENOMEM;
- init_MUTEX(&p_lm70->sem);
+ mutex_init(&p_lm70->lock);
/* sysfs hook */
- p_lm70->cdev = hwmon_device_register(&spi->dev);
- if (IS_ERR(p_lm70->cdev)) {
+ p_lm70->hwmon_dev = hwmon_device_register(&spi->dev);
+ if (IS_ERR(p_lm70->hwmon_dev)) {
dev_dbg(&spi->dev, "hwmon_device_register failed.\n");
- status = PTR_ERR(p_lm70->cdev);
+ status = PTR_ERR(p_lm70->hwmon_dev);
goto out_dev_reg_failed;
}
dev_set_drvdata(&spi->dev, p_lm70);
- if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))) {
+ if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))
+ || (status = device_create_file(&spi->dev, &dev_attr_name))) {
dev_dbg(&spi->dev, "device_create_file failure.\n");
goto out_dev_create_file_failed;
}
@@ -123,7 +133,8 @@ static int __devinit lm70_probe(struct spi_device *spi)
return 0;
out_dev_create_file_failed:
- hwmon_device_unregister(p_lm70->cdev);
+ device_remove_file(&spi->dev, &dev_attr_temp1_input);
+ hwmon_device_unregister(p_lm70->hwmon_dev);
out_dev_reg_failed:
dev_set_drvdata(&spi->dev, NULL);
kfree(p_lm70);
@@ -135,7 +146,8 @@ static int __devexit lm70_remove(struct spi_device *spi)
struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
device_remove_file(&spi->dev, &dev_attr_temp1_input);
- hwmon_device_unregister(p_lm70->cdev);
+ device_remove_file(&spi->dev, &dev_attr_name);
+ hwmon_device_unregister(p_lm70->hwmon_dev);
dev_set_drvdata(&spi->dev, NULL);
kfree(p_lm70);
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index a40166ffad1..37a8cc032ff 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -50,7 +50,7 @@ static const u8 LM75_REG_TEMP[3] = {
/* Each client has this additional data */
struct lm75_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -95,7 +95,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
struct i2c_client *client = to_i2c_client(dev);
struct lm75_data *data = i2c_get_clientdata(client);
int nr = attr->index;
- unsigned long temp = simple_strtoul(buf, NULL, 10);
+ long temp = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp[nr] = LM75_TEMP_TO_REG(temp);
@@ -219,9 +219,9 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -240,7 +240,7 @@ exit:
static int lm75_detach_client(struct i2c_client *client)
{
struct lm75_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm75_group);
i2c_detach_client(client);
kfree(data);
diff --git a/drivers/hwmon/lm75.h b/drivers/hwmon/lm75.h
index af7dc650ee1..7c93454bb4e 100644
--- a/drivers/hwmon/lm75.h
+++ b/drivers/hwmon/lm75.h
@@ -33,7 +33,7 @@
/* TEMP: 0.001C/bit (-55C to +125C)
REG: (0.5C/bit, two's complement) << 7 */
-static inline u16 LM75_TEMP_TO_REG(int temp)
+static inline u16 LM75_TEMP_TO_REG(long temp)
{
int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
ntemp += (ntemp<0 ? -250 : 250);
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index dd969f1e841..cee5c2e8cfa 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -51,7 +51,7 @@ I2C_CLIENT_INSMOD_1(lm77);
/* Each client has this additional data */
struct lm77_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid;
unsigned long last_updated; /* In jiffies */
@@ -138,7 +138,7 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co
{ \
struct i2c_client *client = to_i2c_client(dev); \
struct lm77_data *data = i2c_get_clientdata(client); \
- long val = simple_strtoul(buf, NULL, 10); \
+ long val = simple_strtol(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->value = val; \
@@ -337,9 +337,9 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -358,7 +358,7 @@ exit:
static int lm77_detach_client(struct i2c_client *client)
{
struct lm77_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm77_group);
i2c_detach_client(client);
kfree(data);
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 6eea3476b90..3f7055ee679 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -131,7 +131,7 @@ static inline int TEMP_FROM_REG(s8 val)
the driver field to differentiate between I2C and ISA chips. */
struct lm78_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
enum chips type;
@@ -438,6 +438,25 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct lm78_data *data = lm78_update_device(dev);
+ int nr = to_sensor_dev_attr(da)->index;
+ return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+
/* This function is called when:
* lm78_driver is inserted (when this module is loaded), for each
available adapter
@@ -453,36 +472,47 @@ static struct attribute *lm78_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_min.dev_attr.attr,
&sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in2_min.dev_attr.attr,
&sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in3_min.dev_attr.attr,
&sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in4_min.dev_attr.attr,
&sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
&sensor_dev_attr_in5_input.dev_attr.attr,
&sensor_dev_attr_in5_min.dev_attr.attr,
&sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
&sensor_dev_attr_in6_input.dev_attr.attr,
&sensor_dev_attr_in6_min.dev_attr.attr,
&sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
&dev_attr_temp1_input.attr,
&dev_attr_temp1_max.attr,
&dev_attr_temp1_max_hyst.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan3_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_cpu0_vid.attr,
@@ -585,9 +615,9 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group)))
goto ERROR3;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR4;
}
@@ -608,7 +638,7 @@ static int lm78_detach_client(struct i2c_client *client)
struct lm78_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm78_group);
if ((err = i2c_detach_client(client)))
@@ -659,9 +689,9 @@ static int __devinit lm78_isa_probe(struct platform_device *pdev)
|| (err = device_create_file(&pdev->dev, &dev_attr_name)))
goto exit_remove_files;
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -681,7 +711,7 @@ static int __devexit lm78_isa_remove(struct platform_device *pdev)
{
struct lm78_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &lm78_group);
device_remove_file(&pdev->dev, &dev_attr_name);
release_region(data->client.addr, LM78_EXTENT);
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index 064516d824a..063cdba00a8 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -108,7 +108,7 @@ static inline long TEMP_FROM_REG(u16 temp)
struct lm80_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -497,9 +497,9 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm80_group)))
goto error_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto error_remove;
}
@@ -520,7 +520,7 @@ static int lm80_detach_client(struct i2c_client *client)
struct lm80_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm80_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index 654c0f73464..0336b4572a6 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -144,7 +144,7 @@ static struct i2c_driver lm83_driver = {
struct lm83_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -400,9 +400,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_remove_files;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -424,7 +424,7 @@ static int lm83_detach_client(struct i2c_client *client)
struct lm83_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm83_group);
sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 20a8c648280..a02480be65f 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -30,6 +30,7 @@
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
@@ -122,23 +123,6 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102);
#define EMC6D102_REG_EXTEND_ADC3 0x87
#define EMC6D102_REG_EXTEND_ADC4 0x88
-#define LM85_ALARM_IN0 0x0001
-#define LM85_ALARM_IN1 0x0002
-#define LM85_ALARM_IN2 0x0004
-#define LM85_ALARM_IN3 0x0008
-#define LM85_ALARM_TEMP1 0x0010
-#define LM85_ALARM_TEMP2 0x0020
-#define LM85_ALARM_TEMP3 0x0040
-#define LM85_ALARM_ALARM2 0x0080
-#define LM85_ALARM_IN4 0x0100
-#define LM85_ALARM_RESERVED 0x0200
-#define LM85_ALARM_FAN1 0x0400
-#define LM85_ALARM_FAN2 0x0800
-#define LM85_ALARM_FAN3 0x1000
-#define LM85_ALARM_FAN4 0x2000
-#define LM85_ALARM_TEMP1_FAULT 0x4000
-#define LM85_ALARM_TEMP3_FAULT 0x8000
-
/* Conversions. Rounding and limit checking is only done on the TO_REG
variants. Note that you should be a bit careful with which arguments
@@ -155,22 +139,26 @@ static int lm85_scaling[] = { /* .001 Volts */
#define INS_TO_REG(n,val) \
SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255)
-#define INSEXT_FROM_REG(n,val,ext,scale) \
- SCALE((val)*(scale) + (ext),192*(scale),lm85_scaling[n])
+#define INSEXT_FROM_REG(n,val,ext) \
+ SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n])
-#define INS_FROM_REG(n,val) INSEXT_FROM_REG(n,val,0,1)
+#define INS_FROM_REG(n,val) SCALE((val), 192, lm85_scaling[n])
/* FAN speed is measured using 90kHz clock */
-#define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534))
+static inline u16 FAN_TO_REG(unsigned long val)
+{
+ if (!val)
+ return 0xffff;
+ return SENSORS_LIMIT(5400000 / val, 1, 0xfffe);
+}
#define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val))
/* Temperature is reported in .001 degC increments */
#define TEMP_TO_REG(val) \
SENSORS_LIMIT(SCALE(val,1000,1),-127,127)
-#define TEMPEXT_FROM_REG(val,ext,scale) \
- SCALE((val)*scale + (ext),scale,1000)
-#define TEMP_FROM_REG(val) \
- TEMPEXT_FROM_REG(val,0,1)
+#define TEMPEXT_FROM_REG(val,ext) \
+ SCALE(((val) << 4) + (ext), 16, 1000)
+#define TEMP_FROM_REG(val) ((val) * 1000)
#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255))
#define PWM_FROM_REG(val) (val)
@@ -328,7 +316,7 @@ struct lm85_autofan {
The structure is dynamically allocated. */
struct lm85_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
enum chips type;
struct mutex update_lock;
@@ -350,7 +338,6 @@ struct lm85_data {
u8 tach_mode; /* Register encoding, combined */
u8 temp_ext[3]; /* Decoded values */
u8 in_ext[8]; /* Decoded values */
- u8 adc_scale; /* ADC Extended bits scaling factor */
u8 fan_ppr; /* Register value */
u8 smooth[3]; /* Register encoding */
u8 vid; /* Register value */
@@ -387,22 +374,29 @@ static struct i2c_driver lm85_driver = {
/* 4 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr]) );
}
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr]) );
}
-static ssize_t set_fan_min(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
- long val = simple_strtol(buf, NULL, 10);
+ unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN_TO_REG(val);
@@ -412,23 +406,10 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
}
#define show_fan_offset(offset) \
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_min(dev, buf, offset - 1); \
-} \
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_min(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \
- NULL); \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
- show_fan_##offset##_min, set_fan_##offset##_min);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, set_fan_min, offset - 1)
show_fan_offset(1);
show_fan_offset(2);
@@ -457,7 +438,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct lm85_data *data = lm85_update_device(dev);
+ struct lm85_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%ld\n", (long) data->vrm);
}
@@ -482,16 +463,46 @@ static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(attr)->index;
+ struct lm85_data *data = lm85_update_device(dev);
+ return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 18);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 13);
+
/* pwm */
-static ssize_t show_pwm(struct device *dev, char *buf, int nr)
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm[nr]) );
}
-static ssize_t set_pwm(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -502,8 +513,11 @@ static ssize_t set_pwm(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
+
+static ssize_t show_pwm_enable(struct device *dev, struct device_attribute
+ *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
int pwm_zone;
@@ -512,23 +526,10 @@ static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr)
}
#define show_pwm_reg(offset) \
-static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_pwm(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_pwm_enable##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_pwm_enable(dev, buf, offset - 1); \
-} \
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
- show_pwm_##offset, set_pwm_##offset); \
-static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \
- show_pwm_enable##offset, NULL);
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
+ show_pwm, set_pwm, offset - 1); \
+static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \
+ show_pwm_enable, NULL, offset - 1)
show_pwm_reg(1);
show_pwm_reg(2);
@@ -536,22 +537,28 @@ show_pwm_reg(3);
/* Voltages */
-static ssize_t show_in(struct device *dev, char *buf, int nr)
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf( buf, "%d\n", INSEXT_FROM_REG(nr,
data->in[nr],
- data->in_ext[nr],
- data->adc_scale) );
+ data->in_ext[nr]));
}
-static ssize_t show_in_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]) );
}
-static ssize_t set_in_min(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -562,14 +569,19 @@ static ssize_t set_in_min(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_in_max(struct device *dev, char *buf, int nr)
+
+static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]) );
}
-static ssize_t set_in_max(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -580,59 +592,47 @@ static ssize_t set_in_max(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
+
#define show_in_reg(offset) \
-static ssize_t show_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in(dev, buf, offset); \
-} \
-static ssize_t show_in_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_min(dev, buf, offset); \
-} \
-static ssize_t show_in_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_max(dev, buf, offset); \
-} \
-static ssize_t set_in_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_min(dev, buf, count, offset); \
-} \
-static ssize_t set_in_##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_max(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, \
- NULL); \
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
- show_in_##offset##_min, set_in_##offset##_min); \
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
- show_in_##offset##_max, set_in_##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in_max, set_in_max, offset)
show_in_reg(0);
show_in_reg(1);
show_in_reg(2);
show_in_reg(3);
show_in_reg(4);
+show_in_reg(5);
+show_in_reg(6);
+show_in_reg(7);
/* Temps */
-static ssize_t show_temp(struct device *dev, char *buf, int nr)
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMPEXT_FROM_REG(data->temp[nr],
- data->temp_ext[nr],
- data->adc_scale) );
+ data->temp_ext[nr]));
}
-static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]) );
}
-static ssize_t set_temp_min(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -643,14 +643,19 @@ static ssize_t set_temp_min(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]) );
}
-static ssize_t set_temp_max(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -661,35 +666,14 @@ static ssize_t set_temp_max(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
+
#define show_temp_reg(offset) \
-static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp(dev, buf, offset - 1); \
-} \
-static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_min(dev, buf, offset - 1); \
-} \
-static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_max(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_max(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \
- NULL); \
-static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_min, set_temp_##offset##_min); \
-static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_max, set_temp_##offset##_max);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_temp, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
+ show_temp_min, set_temp_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
+ show_temp_max, set_temp_max, offset - 1);
show_temp_reg(1);
show_temp_reg(2);
@@ -698,14 +682,18 @@ show_temp_reg(3);
/* Automatic PWM control */
-static ssize_t show_pwm_auto_channels(struct device *dev, char *buf, int nr)
+static ssize_t show_pwm_auto_channels(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", ZONE_FROM_REG(data->autofan[nr].config));
}
-static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_pwm_auto_channels(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -718,14 +706,19 @@ static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_pwm_auto_pwm_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_pwm_auto_pwm_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", PWM_FROM_REG(data->autofan[nr].min_pwm));
}
-static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_pwm_auto_pwm_min(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -737,14 +730,19 @@ static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, char *buf, int nr)
+
+static ssize_t show_pwm_auto_pwm_minctl(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", data->autofan[nr].min_off);
}
-static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_pwm_auto_pwm_minctl(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -760,14 +758,19 @@ static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_pwm_auto_pwm_freq(struct device *dev, char *buf, int nr)
+
+static ssize_t show_pwm_auto_pwm_freq(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", FREQ_FROM_REG(data->autofan[nr].freq));
}
-static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_pwm_auto_pwm_freq(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -781,74 +784,40 @@ static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
+
#define pwm_auto(offset) \
-static ssize_t show_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_pwm_auto_channels(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm_auto_channels(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_pwm_auto_pwm_min(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm_auto_pwm_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_pwm_auto_pwm_minctl(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm_auto_pwm_minctl(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_pwm##offset##_auto_pwm_freq (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_pwm_auto_pwm_freq(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm##offset##_auto_pwm_freq(struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm_auto_pwm_freq(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(pwm##offset##_auto_channels, S_IRUGO | S_IWUSR, \
- show_pwm##offset##_auto_channels, \
- set_pwm##offset##_auto_channels); \
-static DEVICE_ATTR(pwm##offset##_auto_pwm_min, S_IRUGO | S_IWUSR, \
- show_pwm##offset##_auto_pwm_min, \
- set_pwm##offset##_auto_pwm_min); \
-static DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, S_IRUGO | S_IWUSR, \
- show_pwm##offset##_auto_pwm_minctl, \
- set_pwm##offset##_auto_pwm_minctl); \
-static DEVICE_ATTR(pwm##offset##_auto_pwm_freq, S_IRUGO | S_IWUSR, \
- show_pwm##offset##_auto_pwm_freq, \
- set_pwm##offset##_auto_pwm_freq);
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels, \
+ S_IRUGO | S_IWUSR, show_pwm_auto_channels, \
+ set_pwm_auto_channels, offset - 1); \
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_min, \
+ S_IRUGO | S_IWUSR, show_pwm_auto_pwm_min, \
+ set_pwm_auto_pwm_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, \
+ S_IRUGO | S_IWUSR, show_pwm_auto_pwm_minctl, \
+ set_pwm_auto_pwm_minctl, offset - 1); \
+static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_freq, \
+ S_IRUGO | S_IWUSR, show_pwm_auto_pwm_freq, \
+ set_pwm_auto_pwm_freq, offset - 1);
+
pwm_auto(1);
pwm_auto(2);
pwm_auto(3);
/* Temperature settings for automatic PWM control */
-static ssize_t show_temp_auto_temp_off(struct device *dev, char *buf, int nr)
+static ssize_t show_temp_auto_temp_off(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) -
HYST_FROM_REG(data->zone[nr].hyst));
}
-static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_temp_auto_temp_off(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
int min;
@@ -871,14 +840,19 @@ static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_temp_auto_temp_min(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_auto_temp_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) );
}
-static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_temp_auto_temp_min(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -913,15 +887,20 @@ static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_temp_auto_temp_max(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_auto_temp_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) +
RANGE_FROM_REG(data->zone[nr].range));
}
-static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_temp_auto_temp_max(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
int min;
@@ -938,14 +917,19 @@ static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_temp_auto_temp_crit(struct device *dev, char *buf, int nr)
+
+static ssize_t show_temp_auto_temp_crit(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = lm85_update_device(dev);
return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].critical));
}
-static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf,
- size_t count, int nr)
+
+static ssize_t set_temp_auto_temp_crit(struct device *dev,
+ struct device_attribute *attr,const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(attr)->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm85_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
@@ -957,59 +941,21 @@ static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf,
mutex_unlock(&data->update_lock);
return count;
}
+
#define temp_auto(offset) \
-static ssize_t show_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_temp_auto_temp_off(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_auto_temp_off(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_temp_auto_temp_min(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_auto_temp_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_temp_auto_temp_max(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_auto_temp_max(dev, buf, count, offset - 1); \
-} \
-static ssize_t show_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \
- char *buf) \
-{ \
- return show_temp_auto_temp_crit(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_auto_temp_crit(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(temp##offset##_auto_temp_off, S_IRUGO | S_IWUSR, \
- show_temp##offset##_auto_temp_off, \
- set_temp##offset##_auto_temp_off); \
-static DEVICE_ATTR(temp##offset##_auto_temp_min, S_IRUGO | S_IWUSR, \
- show_temp##offset##_auto_temp_min, \
- set_temp##offset##_auto_temp_min); \
-static DEVICE_ATTR(temp##offset##_auto_temp_max, S_IRUGO | S_IWUSR, \
- show_temp##offset##_auto_temp_max, \
- set_temp##offset##_auto_temp_max); \
-static DEVICE_ATTR(temp##offset##_auto_temp_crit, S_IRUGO | S_IWUSR, \
- show_temp##offset##_auto_temp_crit, \
- set_temp##offset##_auto_temp_crit);
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_off, \
+ S_IRUGO | S_IWUSR, show_temp_auto_temp_off, \
+ set_temp_auto_temp_off, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_min, \
+ S_IRUGO | S_IWUSR, show_temp_auto_temp_min, \
+ set_temp_auto_temp_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_max, \
+ S_IRUGO | S_IWUSR, show_temp_auto_temp_max, \
+ set_temp_auto_temp_max, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_crit, \
+ S_IRUGO | S_IWUSR, show_temp_auto_temp_crit, \
+ set_temp_auto_temp_crit, offset - 1);
+
temp_auto(1);
temp_auto(2);
temp_auto(3);
@@ -1022,69 +968,87 @@ static int lm85_attach_adapter(struct i2c_adapter *adapter)
}
static struct attribute *lm85_attributes[] = {
- &dev_attr_fan1_input.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan3_input.attr,
- &dev_attr_fan4_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan3_min.attr,
- &dev_attr_fan4_min.attr,
- &dev_attr_pwm1.attr,
- &dev_attr_pwm2.attr,
- &dev_attr_pwm3.attr,
- &dev_attr_pwm1_enable.attr,
- &dev_attr_pwm2_enable.attr,
- &dev_attr_pwm3_enable.attr,
- &dev_attr_in0_input.attr,
- &dev_attr_in1_input.attr,
- &dev_attr_in2_input.attr,
- &dev_attr_in3_input.attr,
- &dev_attr_in0_min.attr,
- &dev_attr_in1_min.attr,
- &dev_attr_in2_min.attr,
- &dev_attr_in3_min.attr,
- &dev_attr_in0_max.attr,
- &dev_attr_in1_max.attr,
- &dev_attr_in2_max.attr,
- &dev_attr_in3_max.attr,
- &dev_attr_temp1_input.attr,
- &dev_attr_temp2_input.attr,
- &dev_attr_temp3_input.attr,
- &dev_attr_temp1_min.attr,
- &dev_attr_temp2_min.attr,
- &dev_attr_temp3_min.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp2_max.attr,
- &dev_attr_temp3_max.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan4_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
+
+ &sensor_dev_attr_pwm1_auto_channels.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_channels.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_channels.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_pwm_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_pwm_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_pwm_freq.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_temp_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_temp_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_temp_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_temp_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_temp_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_temp_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_temp_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_temp_crit.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_temp_crit.dev_attr.attr,
+
&dev_attr_vrm.attr,
&dev_attr_cpu0_vid.attr,
&dev_attr_alarms.attr,
- &dev_attr_pwm1_auto_channels.attr,
- &dev_attr_pwm2_auto_channels.attr,
- &dev_attr_pwm3_auto_channels.attr,
- &dev_attr_pwm1_auto_pwm_min.attr,
- &dev_attr_pwm2_auto_pwm_min.attr,
- &dev_attr_pwm3_auto_pwm_min.attr,
- &dev_attr_pwm1_auto_pwm_minctl.attr,
- &dev_attr_pwm2_auto_pwm_minctl.attr,
- &dev_attr_pwm3_auto_pwm_minctl.attr,
- &dev_attr_pwm1_auto_pwm_freq.attr,
- &dev_attr_pwm2_auto_pwm_freq.attr,
- &dev_attr_pwm3_auto_pwm_freq.attr,
- &dev_attr_temp1_auto_temp_off.attr,
- &dev_attr_temp2_auto_temp_off.attr,
- &dev_attr_temp3_auto_temp_off.attr,
- &dev_attr_temp1_auto_temp_min.attr,
- &dev_attr_temp2_auto_temp_min.attr,
- &dev_attr_temp3_auto_temp_min.attr,
- &dev_attr_temp1_auto_temp_max.attr,
- &dev_attr_temp2_auto_temp_max.attr,
- &dev_attr_temp3_auto_temp_max.attr,
- &dev_attr_temp1_auto_temp_crit.attr,
- &dev_attr_temp2_auto_temp_crit.attr,
- &dev_attr_temp3_auto_temp_crit.attr,
-
NULL
};
@@ -1092,16 +1056,36 @@ static const struct attribute_group lm85_group = {
.attrs = lm85_attributes,
};
-static struct attribute *lm85_attributes_opt[] = {
- &dev_attr_in4_input.attr,
- &dev_attr_in4_min.attr,
- &dev_attr_in4_max.attr,
+static struct attribute *lm85_attributes_in4[] = {
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group lm85_group_in4 = {
+ .attrs = lm85_attributes_in4,
+};
+static struct attribute *lm85_attributes_in567[] = {
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
NULL
};
-static const struct attribute_group lm85_group_opt = {
- .attrs = lm85_attributes_opt,
+static const struct attribute_group lm85_group_in567 = {
+ .attrs = lm85_attributes_in567,
};
static int lm85_detect(struct i2c_adapter *adapter, int address,
@@ -1249,17 +1233,19 @@ static int lm85_detect(struct i2c_adapter *adapter, int address,
as a sixth digital VID input rather than an analog input. */
data->vid = lm85_read_value(new_client, LM85_REG_VID);
if (!(kind == adt7463 && (data->vid & 0x80)))
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_in4_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in4_min))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in4_max)))
+ if ((err = sysfs_create_group(&new_client->dev.kobj,
+ &lm85_group_in4)))
goto ERROR3;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ /* The EMC6D100 has 3 additional voltage inputs */
+ if (kind == emc6d100)
+ if ((err = sysfs_create_group(&new_client->dev.kobj,
+ &lm85_group_in567)))
+ goto ERROR3;
+
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR3;
}
@@ -1268,7 +1254,9 @@ static int lm85_detect(struct i2c_adapter *adapter, int address,
/* Error out and cleanup code */
ERROR3:
sysfs_remove_group(&new_client->dev.kobj, &lm85_group);
- sysfs_remove_group(&new_client->dev.kobj, &lm85_group_opt);
+ sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in4);
+ if (kind == emc6d100)
+ sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in567);
ERROR2:
i2c_detach_client(new_client);
ERROR1:
@@ -1280,9 +1268,11 @@ static int lm85_detect(struct i2c_adapter *adapter, int address,
static int lm85_detach_client(struct i2c_client *client)
{
struct lm85_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm85_group);
- sysfs_remove_group(&client->dev.kobj, &lm85_group_opt);
+ sysfs_remove_group(&client->dev.kobj, &lm85_group_in4);
+ if (data->type == emc6d100)
+ sysfs_remove_group(&client->dev.kobj, &lm85_group_in567);
i2c_detach_client(client);
kfree(data);
return 0;
@@ -1405,6 +1395,8 @@ static struct lm85_data *lm85_update_device(struct device *dev)
/* Have to read extended bits first to "freeze" the
* more significant bits that are read later.
+ * There are 2 additional resolution bits per channel and we
+ * have room for 4, so we shift them to the left.
*/
if ( (data->type == adm1027) || (data->type == adt7463) ) {
int ext1 = lm85_read_value(client,
@@ -1414,18 +1406,12 @@ static struct lm85_data *lm85_update_device(struct device *dev)
int val = (ext1 << 8) + ext2;
for(i = 0; i <= 4; i++)
- data->in_ext[i] = (val>>(i * 2))&0x03;
+ data->in_ext[i] = ((val>>(i * 2))&0x03) << 2;
for(i = 0; i <= 2; i++)
- data->temp_ext[i] = (val>>((i + 5) * 2))&0x03;
+ data->temp_ext[i] = (val>>((i + 4) * 2))&0x0c;
}
- /* adc_scale is 2^(number of LSBs). There are 4 extra bits in
- the emc6d102 and 2 in the adt7463 and adm1027. In all
- other chips ext is always 0 and the value of scale is
- irrelevant. So it is left in 4*/
- data->adc_scale = (data->type == emc6d102 ) ? 16 : 4;
-
data->vid = lm85_read_value(client, LM85_REG_VID);
for (i = 0; i <= 3; ++i) {
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index 988ae1c4aad..28cdff0c556 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -58,6 +58,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
@@ -129,7 +130,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
(((val) < 0 ? (val)-500 : (val)+500) / 1000))
#define FAN_FROM_REG(reg,div) ((reg) == 255 || (reg) == 0 ? 0 : \
- 1350000 + (reg)*(div) / 2) / ((reg)*(div))
+ (1350000 + (reg)*(div) / 2) / ((reg)*(div)))
#define FAN_TO_REG(val,div) ((val)*(div) * 255 <= 1350000 ? 255 : \
(1350000 + (val)*(div) / 2) / ((val)*(div)))
@@ -145,7 +146,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
#define CHAN_NO_FAN(nr) (1 << (nr))
#define CHAN_TEMP3 (1 << 2)
#define CHAN_VCC_5V (1 << 3)
-#define CHAN_NO_VID (1 << 8)
+#define CHAN_NO_VID (1 << 7)
/*
* Functions declaration
@@ -176,7 +177,7 @@ static struct i2c_driver lm87_driver = {
struct lm87_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -500,7 +501,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct lm87_data *data = lm87_update_device(dev);
+ struct lm87_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->vrm);
}
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
@@ -531,6 +532,29 @@ static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const
}
static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lm87_data *data = lm87_update_device(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 14);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15);
+
/*
* Real code
*/
@@ -546,24 +570,31 @@ static struct attribute *lm87_attributes[] = {
&dev_attr_in1_input.attr,
&dev_attr_in1_min.attr,
&dev_attr_in1_max.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
&dev_attr_in2_input.attr,
&dev_attr_in2_min.attr,
&dev_attr_in2_max.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
&dev_attr_in3_input.attr,
&dev_attr_in3_min.attr,
&dev_attr_in3_max.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
&dev_attr_in4_input.attr,
&dev_attr_in4_min.attr,
&dev_attr_in4_max.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
&dev_attr_temp1_input.attr,
&dev_attr_temp1_max.attr,
&dev_attr_temp1_min.attr,
&dev_attr_temp1_crit.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
&dev_attr_temp2_input.attr,
&dev_attr_temp2_max.attr,
&dev_attr_temp2_min.attr,
&dev_attr_temp2_crit.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_aout_output.attr,
@@ -579,30 +610,38 @@ static struct attribute *lm87_attributes_opt[] = {
&dev_attr_in6_input.attr,
&dev_attr_in6_min.attr,
&dev_attr_in6_max.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
&dev_attr_fan1_input.attr,
&dev_attr_fan1_min.attr,
&dev_attr_fan1_div.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
&dev_attr_in7_input.attr,
&dev_attr_in7_min.attr,
&dev_attr_in7_max.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
&dev_attr_fan2_input.attr,
&dev_attr_fan2_min.attr,
&dev_attr_fan2_div.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&dev_attr_temp3_input.attr,
&dev_attr_temp3_max.attr,
&dev_attr_temp3_min.attr,
&dev_attr_temp3_crit.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
&dev_attr_in0_input.attr,
&dev_attr_in0_min.attr,
&dev_attr_in0_max.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
&dev_attr_in5_input.attr,
&dev_attr_in5_min.attr,
&dev_attr_in5_max.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
&dev_attr_cpu0_vid.attr,
&dev_attr_vrm.attr,
@@ -690,7 +729,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|| (err = device_create_file(&new_client->dev,
&dev_attr_in6_min))
|| (err = device_create_file(&new_client->dev,
- &dev_attr_in6_max)))
+ &dev_attr_in6_max))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_in6_alarm.dev_attr)))
goto exit_remove;
} else {
if ((err = device_create_file(&new_client->dev,
@@ -698,7 +739,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|| (err = device_create_file(&new_client->dev,
&dev_attr_fan1_min))
|| (err = device_create_file(&new_client->dev,
- &dev_attr_fan1_div)))
+ &dev_attr_fan1_div))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_alarm.dev_attr)))
goto exit_remove;
}
@@ -708,7 +751,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|| (err = device_create_file(&new_client->dev,
&dev_attr_in7_min))
|| (err = device_create_file(&new_client->dev,
- &dev_attr_in7_max)))
+ &dev_attr_in7_max))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_in7_alarm.dev_attr)))
goto exit_remove;
} else {
if ((err = device_create_file(&new_client->dev,
@@ -716,7 +761,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|| (err = device_create_file(&new_client->dev,
&dev_attr_fan2_min))
|| (err = device_create_file(&new_client->dev,
- &dev_attr_fan2_div)))
+ &dev_attr_fan2_div))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan2_alarm.dev_attr)))
goto exit_remove;
}
@@ -728,7 +775,11 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|| (err = device_create_file(&new_client->dev,
&dev_attr_temp3_min))
|| (err = device_create_file(&new_client->dev,
- &dev_attr_temp3_crit)))
+ &dev_attr_temp3_crit))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp3_alarm.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp3_fault.dev_attr)))
goto exit_remove;
} else {
if ((err = device_create_file(&new_client->dev,
@@ -738,11 +789,15 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|| (err = device_create_file(&new_client->dev,
&dev_attr_in0_max))
|| (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_in0_alarm.dev_attr))
+ || (err = device_create_file(&new_client->dev,
&dev_attr_in5_input))
|| (err = device_create_file(&new_client->dev,
&dev_attr_in5_min))
|| (err = device_create_file(&new_client->dev,
- &dev_attr_in5_max)))
+ &dev_attr_in5_max))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_in5_alarm.dev_attr)))
goto exit_remove;
}
@@ -755,9 +810,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_remove;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -816,7 +871,7 @@ static int lm87_detach_client(struct i2c_client *client)
struct lm87_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm87_group);
sysfs_remove_group(&client->dev.kobj, &lm87_group_opt);
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index af541d67245..960df9fa75a 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -41,7 +41,8 @@
* http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
* Note that there is no easy way to differentiate between the three
* variants. The extra address and features of the MAX6659 are not
- * supported by this driver.
+ * supported by this driver. These chips lack the remote temperature
+ * offset feature.
*
* This driver also supports the MAX6680 and MAX6681, two other sensor
* chips made by Maxim. These are quite similar to the other Maxim
@@ -214,7 +215,7 @@ static struct i2c_driver lm90_driver = {
struct lm90_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -226,9 +227,10 @@ struct lm90_data {
2: local high limit
3: local critical limit
4: remote critical limit */
- s16 temp11[3]; /* 0: remote input
+ s16 temp11[4]; /* 0: remote input
1: remote low limit
- 2: remote high limit */
+ 2: remote high limit
+ 3: remote offset (except max6657) */
u8 temp_hyst;
u8 alarms; /* bitvector */
};
@@ -282,11 +284,13 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
- static const u8 reg[4] = {
+ static const u8 reg[6] = {
LM90_REG_W_REMOTE_LOWH,
LM90_REG_W_REMOTE_LOWL,
LM90_REG_W_REMOTE_HIGHH,
LM90_REG_W_REMOTE_HIGHL,
+ LM90_REG_W_REMOTE_OFFSH,
+ LM90_REG_W_REMOTE_OFFSL,
};
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
@@ -367,6 +371,8 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8,
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
set_temphyst, 3);
static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11,
+ set_temp11, 3);
/* Individual alarm files */
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
@@ -652,10 +658,15 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
&dev_attr_pec)))
goto exit_remove_files;
}
+ if (data->kind != max6657) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp2_offset.dev_attr)))
+ goto exit_remove_files;
+ }
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -707,9 +718,12 @@ static int lm90_detach_client(struct i2c_client *client)
struct lm90_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm90_group);
device_remove_file(&client->dev, &dev_attr_pec);
+ if (data->kind != max6657)
+ device_remove_file(&client->dev,
+ &sensor_dev_attr_temp2_offset.dev_attr);
if ((err = i2c_detach_client(client)))
return err;
@@ -763,6 +777,13 @@ static struct lm90_data *lm90_update_device(struct device *dev)
if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &newh) == 0
&& lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, &l) == 0)
data->temp11[2] = (newh << 8) | l;
+ if (data->kind != max6657) {
+ if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH,
+ &newh) == 0
+ && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL,
+ &l) == 0)
+ data->temp11[3] = (newh << 8) | l;
+ }
lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms);
data->last_updated = jiffies;
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index 30b536333f1..61d1bd1d5b6 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -96,7 +96,7 @@ static struct i2c_driver lm92_driver;
/* Client data (each client gets its own) */
struct lm92_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -379,9 +379,9 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -409,7 +409,7 @@ static int lm92_detach_client(struct i2c_client *client)
struct lm92_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm92_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index d84f8bf6f28..ea61946a4bf 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -201,7 +201,7 @@ struct block1_t {
*/
struct lm93_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
unsigned long last_updated; /* In jiffies */
@@ -413,7 +413,7 @@ static int LM93_TEMP_FROM_REG(u8 reg)
/* TEMP: 1/1000 degrees C (-128C to +127C)
REG: 1C/bit, two's complement */
-static u8 LM93_TEMP_TO_REG(int temp)
+static u8 LM93_TEMP_TO_REG(long temp)
{
int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
ntemp += (ntemp<0 ? -500 : 500);
@@ -1268,7 +1268,7 @@ static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr,
int nr = (to_sensor_dev_attr(attr))->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm93_data *data = i2c_get_clientdata(client);
- u32 val = simple_strtoul(buf, NULL, 10);
+ long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_lim[nr].min = LM93_TEMP_TO_REG(val);
@@ -1298,7 +1298,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr,
int nr = (to_sensor_dev_attr(attr))->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm93_data *data = i2c_get_clientdata(client);
- u32 val = simple_strtoul(buf, NULL, 10);
+ long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_lim[nr].max = LM93_TEMP_TO_REG(val);
@@ -1329,7 +1329,7 @@ static ssize_t store_temp_auto_base(struct device *dev,
int nr = (to_sensor_dev_attr(attr))->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm93_data *data = i2c_get_clientdata(client);
- u32 val = simple_strtoul(buf, NULL, 10);
+ long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->block10.base[nr] = LM93_TEMP_TO_REG(val);
@@ -1360,7 +1360,7 @@ static ssize_t store_temp_auto_boost(struct device *dev,
int nr = (to_sensor_dev_attr(attr))->index;
struct i2c_client *client = to_i2c_client(dev);
struct lm93_data *data = i2c_get_clientdata(client);
- u32 val = simple_strtoul(buf, NULL, 10);
+ long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->boost[nr] = LM93_TEMP_TO_REG(val);
@@ -2078,8 +2078,8 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
return sprintf(buf,"%d\n",LM93_VID_FROM_REG(data->vid[nr]));
}
-static SENSOR_DEVICE_ATTR(vid1, S_IRUGO, show_vid, NULL, 0);
-static SENSOR_DEVICE_ATTR(vid2, S_IRUGO, show_vid, NULL, 1);
+static SENSOR_DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL, 0);
+static SENSOR_DEVICE_ATTR(cpu1_vid, S_IRUGO, show_vid, NULL, 1);
static ssize_t show_prochot(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -2431,8 +2431,8 @@ static struct attribute *lm93_attrs[] = {
&sensor_dev_attr_pwm2_auto_spinup_time.dev_attr.attr,
&dev_attr_pwm_auto_prochot_ramp.attr,
&dev_attr_pwm_auto_vrdhot_ramp.attr,
- &sensor_dev_attr_vid1.dev_attr.attr,
- &sensor_dev_attr_vid2.dev_attr.attr,
+ &sensor_dev_attr_cpu0_vid.dev_attr.attr,
+ &sensor_dev_attr_cpu1_vid.dev_attr.attr,
&sensor_dev_attr_prochot1.dev_attr.attr,
&sensor_dev_attr_prochot2.dev_attr.attr,
&sensor_dev_attr_prochot1_avg.dev_attr.attr,
@@ -2590,11 +2590,11 @@ static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
goto err_detach;
/* Register hwmon driver class */
- data->class_dev = hwmon_device_register(&client->dev);
- if ( !IS_ERR(data->class_dev))
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if ( !IS_ERR(data->hwmon_dev))
return 0;
- err = PTR_ERR(data->class_dev);
+ err = PTR_ERR(data->hwmon_dev);
dev_err(&client->dev, "error registering hwmon device.\n");
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
err_detach:
@@ -2619,7 +2619,7 @@ static int lm93_detach_client(struct i2c_client *client)
struct lm93_data *data = i2c_get_clientdata(client);
int err = 0;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
err = i2c_detach_client(client);
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
index 2f58f651f03..38a44c3d6ce 100644
--- a/drivers/hwmon/max1619.c
+++ b/drivers/hwmon/max1619.c
@@ -105,7 +105,7 @@ static struct i2c_driver max1619_driver = {
struct max1619_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -293,9 +293,9 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -331,7 +331,7 @@ static int max1619_detach_client(struct i2c_client *client)
struct max1619_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &max1619_group);
if ((err = i2c_detach_client(client)))
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index 8415664f33c..755570c1f4e 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -128,7 +128,7 @@ static struct i2c_driver max6650_driver = {
struct max6650_data
{
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -523,11 +523,11 @@ static int max6650_detect(struct i2c_adapter *adapter, int address, int kind)
if (err)
goto err_detach;
- data->class_dev = hwmon_device_register(&client->dev);
- if (!IS_ERR(data->class_dev))
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (!IS_ERR(data->hwmon_dev))
return 0;
- err = PTR_ERR(data->class_dev);
+ err = PTR_ERR(data->hwmon_dev);
dev_err(&client->dev, "error registering hwmon device.\n");
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
err_detach:
@@ -543,7 +543,7 @@ static int max6650_detach_client(struct i2c_client *client)
int err;
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
err = i2c_detach_client(client);
if (!err)
kfree(data);
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index f57c75d59a5..9d660133d51 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -180,7 +180,7 @@ static inline u8 PWM_TO_REG(int val, int inv)
struct pc87360_data {
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -500,7 +500,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct pc87360_data *data = pc87360_update_device(dev);
+ struct pc87360_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", data->vrm);
}
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
@@ -1054,9 +1054,9 @@ static int __devinit pc87360_probe(struct platform_device *pdev)
if ((err = device_create_file(dev, &dev_attr_name)))
goto ERROR3;
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR3;
}
return 0;
@@ -1083,7 +1083,7 @@ static int __devexit pc87360_remove(struct platform_device *pdev)
struct pc87360_data *data = platform_get_drvdata(pdev);
int i;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
device_remove_file(&pdev->dev, &dev_attr_name);
sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group);
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index 2915bc4ad0d..d40509ad6ae 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -42,7 +42,7 @@ static struct platform_device *pdev;
device is using banked registers) and the register cache (needed to keep
the data in the registers and the cache in sync at any time). */
struct pc87427_data {
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
int address[2];
const char *name;
@@ -454,9 +454,9 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
goto exit_remove_files;
}
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
goto exit_remove_files;
}
@@ -484,7 +484,7 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
struct resource *res;
int i;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
device_remove_file(&pdev->dev, &dev_attr_name);
for (i = 0; i < 8; i++) {
if (!(data->fan_enabled & (1 << i)))
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 92956eb3f3c..a276806f3d5 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -3,7 +3,7 @@
for hardware monitoring
Copyright (C) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
- Kyösti Mälkki <kmalkki@cc.hut.fi>, and
+ Kyösti Mälkki <kmalkki@cc.hut.fi>, and
Mark D. Studebaker <mdsxyz123@yahoo.com>
Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
the help of Jean Delvare <khali@linux-fr.org>
@@ -163,7 +163,7 @@ static inline u8 DIV_TO_REG(int val)
struct sis5595_data {
unsigned short addr;
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
struct mutex update_lock;
@@ -435,6 +435,22 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sis5595_data *data = sis5595_update_device(dev);
+ int nr = to_sensor_dev_attr(da)->index;
+ return sprintf(buf, "%u\n", (data->alarms >> nr) & 1);
+}
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 15);
+
static ssize_t show_name(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -447,22 +463,28 @@ static struct attribute *sis5595_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_min.dev_attr.attr,
&sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in2_min.dev_attr.attr,
&sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in3_min.dev_attr.attr,
&sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_name.attr,
@@ -473,19 +495,28 @@ static const struct attribute_group sis5595_group = {
.attrs = sis5595_attributes,
};
-static struct attribute *sis5595_attributes_opt[] = {
+static struct attribute *sis5595_attributes_in4[] = {
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in4_min.dev_attr.attr,
&sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group sis5595_group_in4 = {
+ .attrs = sis5595_attributes_in4,
+};
+static struct attribute *sis5595_attributes_temp1[] = {
&dev_attr_temp1_input.attr,
&dev_attr_temp1_max.attr,
&dev_attr_temp1_max_hyst.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
NULL
};
-static const struct attribute_group sis5595_group_opt = {
- .attrs = sis5595_attributes_opt,
+static const struct attribute_group sis5595_group_temp1 = {
+ .attrs = sis5595_attributes_temp1,
};
/* This is called when the module is loaded */
@@ -517,7 +548,7 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
/* Check revision and pin registers to determine whether 4 or 5 voltages */
- pci_read_config_byte(s_bridge, PCI_REVISION_ID, &data->revision);
+ data->revision = s_bridge->revision;
/* 4 voltages, 1 temp */
data->maxins = 3;
if (data->revision >= REV2MIN) {
@@ -540,26 +571,18 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
if ((err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group)))
goto exit_free;
if (data->maxins == 4) {
- if ((err = device_create_file(&pdev->dev,
- &sensor_dev_attr_in4_input.dev_attr))
- || (err = device_create_file(&pdev->dev,
- &sensor_dev_attr_in4_min.dev_attr))
- || (err = device_create_file(&pdev->dev,
- &sensor_dev_attr_in4_max.dev_attr)))
+ if ((err = sysfs_create_group(&pdev->dev.kobj,
+ &sis5595_group_in4)))
goto exit_remove_files;
} else {
- if ((err = device_create_file(&pdev->dev,
- &dev_attr_temp1_input))
- || (err = device_create_file(&pdev->dev,
- &dev_attr_temp1_max))
- || (err = device_create_file(&pdev->dev,
- &dev_attr_temp1_max_hyst)))
+ if ((err = sysfs_create_group(&pdev->dev.kobj,
+ &sis5595_group_temp1)))
goto exit_remove_files;
}
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -567,7 +590,8 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
exit_remove_files:
sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
- sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
+ sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
+ sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
exit_free:
kfree(data);
exit_release:
@@ -580,9 +604,10 @@ static int __devexit sis5595_remove(struct platform_device *pdev)
{
struct sis5595_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
- sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
+ sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
+ sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
release_region(data->addr, SIS5595_EXTENT);
platform_set_drvdata(pdev, NULL);
@@ -739,11 +764,10 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
int *i;
for (i = blacklist; *i != 0; i++) {
- struct pci_dev *dev;
- dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
- if (dev) {
- dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
- pci_dev_put(dev);
+ struct pci_dev *d;
+ if ((d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL))) {
+ dev_err(&d->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
+ pci_dev_put(d);
return -ENODEV;
}
}
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index 45266b30ce1..0b57d2ea2cf 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -94,7 +94,7 @@ static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80};
struct smsc47b397_data {
unsigned short addr;
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
struct mutex update_lock;
@@ -222,7 +222,7 @@ static int __devexit smsc47b397_remove(struct platform_device *pdev)
struct smsc47b397_data *data = platform_get_drvdata(pdev);
struct resource *res;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &smsc47b397_group);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
release_region(res->start, SMSC_EXTENT);
@@ -272,9 +272,9 @@ static int __devinit smsc47b397_probe(struct platform_device *pdev)
if ((err = sysfs_create_group(&dev->kobj, &smsc47b397_group)))
goto error_free;
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto error_remove;
}
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index d3181967f16..a10a380868e 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -116,7 +116,7 @@ struct smsc47m1_data {
unsigned short addr;
const char *name;
enum chips type;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
unsigned long last_updated; /* In jiffies */
@@ -553,7 +553,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
|| (err = device_create_file(dev,
&sensor_dev_attr_fan3_div.dev_attr)))
goto error_remove_files;
- } else
+ } else if (data->type == smsc47m2)
dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
if (pwm1) {
@@ -580,7 +580,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
|| (err = device_create_file(dev,
&sensor_dev_attr_pwm3_enable.dev_attr)))
goto error_remove_files;
- } else
+ } else if (data->type == smsc47m2)
dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n");
if ((err = device_create_file(dev, &dev_attr_alarms)))
@@ -588,9 +588,9 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
if ((err = device_create_file(dev, &dev_attr_name)))
goto error_remove_files;
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto error_remove_files;
}
@@ -611,7 +611,7 @@ static int __devexit smsc47m1_remove(struct platform_device *pdev)
struct smsc47m1_data *data = platform_get_drvdata(pdev);
struct resource *res;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index d3a3ba04cb0..b8755265258 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -97,7 +97,7 @@ static inline int TEMP_FROM_REG(s8 val)
struct smsc47m192_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -334,7 +334,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct smsc47m192_data *data = smsc47m192_update_device(dev);
+ struct smsc47m192_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->vrm);
}
@@ -553,9 +553,9 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
goto exit_remove_files;
}
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -577,7 +577,7 @@ static int smsc47m192_detach_client(struct i2c_client *client)
struct smsc47m192_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c
index 9395b52d9b9..04dd7699b3a 100644
--- a/drivers/hwmon/thmc50.c
+++ b/drivers/hwmon/thmc50.c
@@ -46,6 +46,11 @@ I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs "
#define THMC50_REG_COMPANY_ID 0x3E
#define THMC50_REG_DIE_CODE 0x3F
#define THMC50_REG_ANALOG_OUT 0x19
+/*
+ * The mirror status register cannot be used as
+ * reading it does not clear alarms.
+ */
+#define THMC50_REG_INTR 0x41
const static u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
const static u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
@@ -56,7 +61,7 @@ const static u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
/* Each client has this additional data */
struct thmc50_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
enum chips type;
@@ -69,6 +74,7 @@ struct thmc50_data {
s8 temp_max[3];
s8 temp_min[3];
u8 analog_out;
+ u8 alarms;
};
static int thmc50_attach_adapter(struct i2c_adapter *adapter);
@@ -180,6 +186,15 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
return count;
}
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int index = to_sensor_dev_attr(attr)->index;
+ struct thmc50_data *data = thmc50_update_device(dev);
+
+ return sprintf(buf, "%u\n", (data->alarms >> index) & 1);
+}
+
#define temp_reg(offset) \
static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \
NULL, offset - 1); \
@@ -192,6 +207,12 @@ temp_reg(1);
temp_reg(2);
temp_reg(3);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
+
static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_analog_out,
set_analog_out, 0);
static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0);
@@ -200,9 +221,12 @@ static struct attribute *thmc50_attributes[] = {
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm1_mode.dev_attr.attr,
NULL
@@ -213,15 +237,17 @@ static const struct attribute_group thmc50_group = {
};
/* for ADM1022 3rd temperature mode */
-static struct attribute *adm1022_attributes[] = {
+static struct attribute *temp3_attributes[] = {
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
NULL
};
-static const struct attribute_group adm1022_group = {
- .attrs = adm1022_attributes,
+static const struct attribute_group temp3_group = {
+ .attrs = temp3_attributes,
};
static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -233,7 +259,7 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
struct thmc50_data *data;
struct device *dev;
int err = 0;
- const char *type_name = "";
+ const char *type_name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
pr_debug("thmc50: detect failed, "
@@ -283,13 +309,9 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
goto exit_free;
}
- pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
- type_name, (revision >> 4) - 0xc, revision & 0xf);
data->type = kind;
- if (kind == thmc50)
- type_name = "thmc50";
- else if (kind == adm1022) {
+ if (kind == adm1022) {
int id = i2c_adapter_id(client->adapter);
int i;
@@ -302,7 +324,11 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
data->has_temp3 = 1;
break;
}
+ } else {
+ type_name = "thmc50";
}
+ pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
+ type_name, (revision >> 4) - 0xc, revision & 0xf);
/* Fill in the remaining client fields & put it into the global list */
strlcpy(client->name, type_name, I2C_NAME_SIZE);
@@ -319,23 +345,23 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_detach;
/* Register ADM1022 sysfs hooks */
- if (data->type == adm1022)
+ if (data->has_temp3)
if ((err = sysfs_create_group(&client->dev.kobj,
- &adm1022_group)))
+ &temp3_group)))
goto exit_remove_sysfs_thmc50;
/* Register a new directory entry with module sensors */
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_sysfs;
}
return 0;
exit_remove_sysfs:
- if (data->type == adm1022)
- sysfs_remove_group(&client->dev.kobj, &adm1022_group);
+ if (data->has_temp3)
+ sysfs_remove_group(&client->dev.kobj, &temp3_group);
exit_remove_sysfs_thmc50:
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
exit_detach:
@@ -358,10 +384,10 @@ static int thmc50_detach_client(struct i2c_client *client)
struct thmc50_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
- if (data->type == adm1022)
- sysfs_remove_group(&client->dev.kobj, &adm1022_group);
+ if (data->has_temp3)
+ sysfs_remove_group(&client->dev.kobj, &temp3_group);
if ((err = i2c_detach_client(client)))
return err;
@@ -414,6 +440,8 @@ static struct thmc50_data *thmc50_update_device(struct device *dev)
}
data->analog_out =
i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
+ data->alarms =
+ i2c_smbus_read_byte_data(client, THMC50_REG_INTR);
data->last_updated = jiffies;
data->valid = 1;
}
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 696c8a2e537..2635bba1e3f 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -3,7 +3,7 @@
for hardware monitoring
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
- Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ Kyösti Mälkki <kmalkki@cc.hut.fi>,
Mark Studebaker <mdsxyz123@yahoo.com>,
and Bob Dougherty <bobd@stanford.edu>
(Some conversion-factor data were contributed by Jonathan Teh Soon Yew
@@ -294,7 +294,7 @@ static inline long TEMP_FROM_REG10(u16 val)
struct via686a_data {
unsigned short addr;
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -627,9 +627,9 @@ static int __devinit via686a_probe(struct platform_device *pdev)
if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group)))
goto exit_free;
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -648,7 +648,7 @@ static int __devexit via686a_remove(struct platform_device *pdev)
{
struct via686a_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
release_region(data->addr, VIA686A_EXTENT);
@@ -866,7 +866,7 @@ static void __exit sm_via686a_exit(void)
}
}
-MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
+MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>, "
"Mark Studebaker <mdsxyz123@yahoo.com> "
"and Bob Dougherty <bobd@stanford.edu>");
MODULE_DESCRIPTION("VIA 686A Sensor device");
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index 9f3e332c5b7..7dfcc8dd316 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -108,7 +108,7 @@ static const u8 bitalarmfan[] = {6, 7};
struct vt1211_data {
unsigned short addr;
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -795,7 +795,7 @@ static ssize_t set_pwm_auto_point_pwm(struct device *dev,
if ((val < 0) || (val > 255)) {
dev_err(dev, "pwm value %ld is out of range. "
- "Choose a value between 0 and 255." , val);
+ "Choose a value between 0 and 255.\n" , val);
return -EINVAL;
}
@@ -1191,9 +1191,9 @@ static int __devinit vt1211_probe(struct platform_device *pdev)
}
/* Register device */
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
dev_err(dev, "Class registration failed (%d)\n", err);
goto EXIT_DEV_REMOVE_SILENT;
}
@@ -1217,7 +1217,7 @@ static int __devexit vt1211_remove(struct platform_device *pdev)
struct vt1211_data *data = platform_get_drvdata(pdev);
struct resource *res;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
vt1211_remove_sysfs(pdev);
platform_set_drvdata(pdev, NULL);
kfree(data);
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index 3e63eaf1904..2196a84603f 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -148,7 +148,7 @@ struct vt8231_data {
const char *name;
struct mutex update_lock;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -676,7 +676,7 @@ static struct pci_driver vt8231_pci_driver = {
.probe = vt8231_pci_probe,
};
-int vt8231_probe(struct platform_device *pdev)
+static int vt8231_probe(struct platform_device *pdev)
{
struct resource *res;
struct vt8231_data *data;
@@ -726,9 +726,9 @@ int vt8231_probe(struct platform_device *pdev)
}
}
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
return 0;
@@ -756,7 +756,7 @@ static int __devexit vt8231_remove(struct platform_device *pdev)
struct vt8231_data *data = platform_get_drvdata(pdev);
int i;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index d9a9ec7dd84..b15c6a998b7 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -223,7 +223,7 @@ temp1_from_reg(s8 reg)
}
static inline s8
-temp1_to_reg(int temp, int min, int max)
+temp1_to_reg(long temp, int min, int max)
{
if (temp <= min)
return min / 1000;
@@ -256,7 +256,7 @@ struct w83627ehf_data {
int addr; /* IO base of hw monitor block */
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
struct mutex update_lock;
@@ -805,7 +805,7 @@ store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
struct w83627ehf_data *data = dev_get_drvdata(dev); \
- u32 val = simple_strtoul(buf, NULL, 10); \
+ long val = simple_strtol(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
@@ -840,7 +840,7 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
struct w83627ehf_data *data = dev_get_drvdata(dev); \
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
- u32 val = simple_strtoul(buf, NULL, 10); \
+ long val = simple_strtol(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->reg[nr] = LM75_TEMP_TO_REG(val); \
@@ -1384,9 +1384,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev)
goto exit_remove;
}
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -1406,7 +1406,7 @@ static int __devexit w83627ehf_remove(struct platform_device *pdev)
{
struct w83627ehf_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
w83627ehf_device_remove_files(&pdev->dev);
release_region(data->addr, IOREGION_LENGTH);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 7a4a15f4bf8..879d0a6544c 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -45,6 +45,7 @@
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
@@ -169,20 +170,16 @@ superio_exit(void)
#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
(0x550 + (nr) - 7))
-#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))
-#define W83781D_REG_FAN(nr) (0x27 + (nr))
-
-#define W83781D_REG_TEMP2_CONFIG 0x152
-#define W83781D_REG_TEMP3_CONFIG 0x252
-#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \
- ((nr == 2) ? (0x0150) : \
- (0x27)))
-#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \
- ((nr == 2) ? (0x153) : \
- (0x3A)))
-#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \
- ((nr == 2) ? (0x155) : \
- (0x39)))
+/* nr:0-2 for fans:1-3 */
+#define W83627HF_REG_FAN_MIN(nr) (0x3b + (nr))
+#define W83627HF_REG_FAN(nr) (0x28 + (nr))
+
+#define W83627HF_REG_TEMP2_CONFIG 0x152
+#define W83627HF_REG_TEMP3_CONFIG 0x252
+/* these are zero-based, unlike config constants above */
+static const u16 w83627hf_reg_temp[] = { 0x27, 0x150, 0x250 };
+static const u16 w83627hf_reg_temp_hyst[] = { 0x3A, 0x153, 0x253 };
+static const u16 w83627hf_reg_temp_over[] = { 0x39, 0x155, 0x255 };
#define W83781D_REG_BANK 0x4E
@@ -218,7 +215,7 @@ static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
W83627THF_REG_PWM3 };
#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
- regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])
+ regpwm_627hf[nr] : regpwm[nr])
#define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */
@@ -263,7 +260,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
/* TEMP: 0.001C/bit (-128C to +127C)
REG: 1C/bit, two's complement */
-static u8 TEMP_TO_REG(int temp)
+static u8 TEMP_TO_REG(long temp)
{
int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);
ntemp += (ntemp<0 ? -500 : 500);
@@ -346,7 +343,7 @@ static inline u8 DIV_TO_REG(long val)
struct w83627hf_data {
unsigned short addr;
const char *name;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
enum chips type;
@@ -359,12 +356,9 @@ struct w83627hf_data {
u8 in_min[9]; /* Register value */
u8 fan[3]; /* Register value */
u8 fan_min[3]; /* Register value */
- u8 temp;
- u8 temp_max; /* Register value */
- u8 temp_max_hyst; /* Register value */
- u16 temp_add[2]; /* Register value */
- u16 temp_max_add[2]; /* Register value */
- u16 temp_max_hyst_add[2]; /* Register value */
+ u16 temp[3]; /* Register value */
+ u16 temp_max[3]; /* Register value */
+ u16 temp_max_hyst[3]; /* Register value */
u8 fan_div[3]; /* Register encoding, shifted right */
u8 vid; /* Register encoding, combined */
u32 alarms; /* Register encoding, combined */
@@ -372,11 +366,8 @@ struct w83627hf_data {
u8 beep_enable; /* Boolean */
u8 pwm[3]; /* Register value */
u8 pwm_freq[3]; /* Register value */
- u16 sens[3]; /* 782D/783S only.
- 1 = pentium diode; 2 = 3904 diode;
- 3000-5000 = thermistor beta.
- Default = 3435.
- Other Betas unimplemented */
+ u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode;
+ 4 = thermistor */
u8 vrm;
u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */
};
@@ -391,6 +382,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev);
static int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
+static void w83627hf_update_fan_div(struct w83627hf_data *data);
static struct w83627hf_data *w83627hf_update_device(struct device *dev);
static void w83627hf_init_device(struct platform_device *pdev);
@@ -403,72 +395,71 @@ static struct platform_driver w83627hf_driver = {
.remove = __devexit_p(w83627hf_remove),
};
-/* following are the sysfs callback functions */
-#define show_in_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
-{ \
- struct w83627hf_data *data = w83627hf_update_device(dev); \
- return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \
+static ssize_t
+show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr]));
}
-show_in_reg(in)
-show_in_reg(in_min)
-show_in_reg(in_max)
-
-#define store_in_reg(REG, reg) \
-static ssize_t \
-store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
-{ \
- struct w83627hf_data *data = dev_get_drvdata(dev); \
- u32 val; \
- \
- val = simple_strtoul(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- data->in_##reg[nr] = IN_TO_REG(val); \
- w83627hf_write_value(data, W83781D_REG_IN_##REG(nr), \
- data->in_##reg[nr]); \
- \
- mutex_unlock(&data->update_lock); \
- return count; \
+static ssize_t
+show_in_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr]));
+}
+static ssize_t
+show_in_max(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr]));
}
-store_in_reg(MIN, min)
-store_in_reg(MAX, max)
+static ssize_t
+store_in_min(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = dev_get_drvdata(dev);
+ long val = simple_strtol(buf, NULL, 10);
-#define sysfs_in_offset(offset) \
-static ssize_t \
-show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in(dev, buf, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
+ mutex_lock(&data->update_lock);
+ data->in_min[nr] = IN_TO_REG(val);
+ w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+static ssize_t
+store_in_max(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = dev_get_drvdata(dev);
+ long val = simple_strtol(buf, NULL, 10);
-#define sysfs_in_reg_offset(reg, offset) \
-static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_##reg (dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return store_in_##reg (dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \
- show_regs_in_##reg##offset, store_regs_in_##reg##offset);
-
-#define sysfs_in_offsets(offset) \
-sysfs_in_offset(offset) \
-sysfs_in_reg_offset(min, offset) \
-sysfs_in_reg_offset(max, offset)
-
-sysfs_in_offsets(1);
-sysfs_in_offsets(2);
-sysfs_in_offsets(3);
-sysfs_in_offsets(4);
-sysfs_in_offsets(5);
-sysfs_in_offsets(6);
-sysfs_in_offsets(7);
-sysfs_in_offsets(8);
+ mutex_lock(&data->update_lock);
+ data->in_max[nr] = IN_TO_REG(val);
+ w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+#define sysfs_vin_decl(offset) \
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in_input, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO|S_IWUSR, \
+ show_in_min, store_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO|S_IWUSR, \
+ show_in_max, store_in_max, offset);
+
+sysfs_vin_decl(1);
+sysfs_vin_decl(2);
+sysfs_vin_decl(3);
+sysfs_vin_decl(4);
+sysfs_vin_decl(5);
+sysfs_vin_decl(6);
+sysfs_vin_decl(7);
+sysfs_vin_decl(8);
/* use a different set of functions for in0 */
static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
@@ -566,134 +557,126 @@ static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
show_regs_in_max0, store_regs_in_max0);
-#define show_fan_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
-{ \
- struct w83627hf_data *data = w83627hf_update_device(dev); \
- return sprintf(buf,"%ld\n", \
- FAN_FROM_REG(data->reg[nr-1], \
- (long)DIV_FROM_REG(data->fan_div[nr-1]))); \
+static ssize_t
+show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr],
+ (long)DIV_FROM_REG(data->fan_div[nr])));
+}
+static ssize_t
+show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr],
+ (long)DIV_FROM_REG(data->fan_div[nr])));
}
-show_fan_reg(fan);
-show_fan_reg(fan_min);
-
static ssize_t
-store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
+store_fan_min(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = dev_get_drvdata(dev);
- u32 val;
-
- val = simple_strtoul(buf, NULL, 10);
+ u32 val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
- data->fan_min[nr - 1] =
- FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
- w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr),
- data->fan_min[nr - 1]);
+ data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+ w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr),
+ data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
+#define sysfs_fan_decl(offset) \
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan_input, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, store_fan_min, offset - 1);
-#define sysfs_fan_offset(offset) \
-static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, offset); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
+sysfs_fan_decl(1);
+sysfs_fan_decl(2);
+sysfs_fan_decl(3);
-#define sysfs_fan_min_offset(offset) \
-static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_min(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_fan_min(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
- show_regs_fan_min##offset, store_regs_fan_min##offset);
-
-sysfs_fan_offset(1);
-sysfs_fan_min_offset(1);
-sysfs_fan_offset(2);
-sysfs_fan_min_offset(2);
-sysfs_fan_offset(3);
-sysfs_fan_min_offset(3);
-
-#define show_temp_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
-{ \
- struct w83627hf_data *data = w83627hf_update_device(dev); \
- if (nr >= 2) { /* TEMP2 and TEMP3 */ \
- return sprintf(buf,"%ld\n", \
- (long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
- } else { /* TEMP1 */ \
- return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
- } \
+static ssize_t
+show_temp(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+
+ u16 tmp = data->temp[nr];
+ return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
+ : (long) TEMP_FROM_REG(tmp));
}
-show_temp_reg(temp);
-show_temp_reg(temp_max);
-show_temp_reg(temp_max_hyst);
-#define store_temp_reg(REG, reg) \
-static ssize_t \
-store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
-{ \
- struct w83627hf_data *data = dev_get_drvdata(dev); \
- u32 val; \
- \
- val = simple_strtoul(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- \
- if (nr >= 2) { /* TEMP2 and TEMP3 */ \
- data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
- w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \
- data->temp_##reg##_add[nr-2]); \
- } else { /* TEMP1 */ \
- data->temp_##reg = TEMP_TO_REG(val); \
- w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \
- data->temp_##reg); \
- } \
- \
- mutex_unlock(&data->update_lock); \
- return count; \
+static ssize_t
+show_temp_max(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+
+ u16 tmp = data->temp_max[nr];
+ return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
+ : (long) TEMP_FROM_REG(tmp));
}
-store_temp_reg(OVER, max);
-store_temp_reg(HYST, max_hyst);
-#define sysfs_temp_offset(offset) \
-static ssize_t \
-show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp(dev, buf, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
+static ssize_t
+show_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = w83627hf_update_device(dev);
-#define sysfs_temp_reg_offset(reg, offset) \
-static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_##reg (dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return store_temp_##reg (dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
- show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
+ u16 tmp = data->temp_max_hyst[nr];
+ return sprintf(buf, "%ld\n", (nr) ? (long) LM75_TEMP_FROM_REG(tmp)
+ : (long) TEMP_FROM_REG(tmp));
+}
-#define sysfs_temp_offsets(offset) \
-sysfs_temp_offset(offset) \
-sysfs_temp_reg_offset(max, offset) \
-sysfs_temp_reg_offset(max_hyst, offset)
+static ssize_t
+store_temp_max(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = dev_get_drvdata(dev);
+ long val = simple_strtol(buf, NULL, 10);
+ u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
-sysfs_temp_offsets(1);
-sysfs_temp_offsets(2);
-sysfs_temp_offsets(3);
+ mutex_lock(&data->update_lock);
+ data->temp_max[nr] = tmp;
+ w83627hf_write_value(data, w83627hf_reg_temp_over[nr], tmp);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+store_temp_max_hyst(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int nr = to_sensor_dev_attr(devattr)->index;
+ struct w83627hf_data *data = dev_get_drvdata(dev);
+ long val = simple_strtol(buf, NULL, 10);
+ u16 tmp = (nr) ? LM75_TEMP_TO_REG(val) : TEMP_TO_REG(val);
+
+ mutex_lock(&data->update_lock);
+ data->temp_max_hyst[nr] = tmp;
+ w83627hf_write_value(data, w83627hf_reg_temp_hyst[nr], tmp);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+#define sysfs_temp_decl(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_temp, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO|S_IWUSR, \
+ show_temp_max, store_temp_max, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO|S_IWUSR, \
+ show_temp_max_hyst, store_temp_max_hyst, offset - 1);
+
+sysfs_temp_decl(1);
+sysfs_temp_decl(2);
+sysfs_temp_decl(3);
static ssize_t
show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
@@ -706,7 +689,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
static ssize_t
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct w83627hf_data *data = w83627hf_update_device(dev);
+ struct w83627hf_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%ld\n", (long) data->vrm);
}
static ssize_t
@@ -791,20 +774,22 @@ sysfs_beep(ENABLE, enable);
sysfs_beep(MASK, mask);
static ssize_t
-show_fan_div_reg(struct device *dev, char *buf, int nr)
+show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = w83627hf_update_device(dev);
return sprintf(buf, "%ld\n",
- (long) DIV_FROM_REG(data->fan_div[nr - 1]));
+ (long) DIV_FROM_REG(data->fan_div[nr]));
}
-
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor. This follows the principle of
least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
static ssize_t
-store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_fan_div(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = dev_get_drvdata(dev);
unsigned long min;
u8 reg;
@@ -830,98 +815,78 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
/* Restore fan_min */
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
- w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
+ w83627hf_write_value(data, W83627HF_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-#define sysfs_fan_div(offset) \
-static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_div_reg(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return store_fan_div_reg(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
- show_regs_fan_div_##offset, store_regs_fan_div_##offset);
-
-sysfs_fan_div(1);
-sysfs_fan_div(2);
-sysfs_fan_div(3);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO|S_IWUSR,
+ show_fan_div, store_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO|S_IWUSR,
+ show_fan_div, store_fan_div, 1);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO|S_IWUSR,
+ show_fan_div, store_fan_div, 2);
static ssize_t
-show_pwm_reg(struct device *dev, char *buf, int nr)
+show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = w83627hf_update_device(dev);
- return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]);
+ return sprintf(buf, "%ld\n", (long) data->pwm[nr]);
}
static ssize_t
-store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_pwm(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = dev_get_drvdata(dev);
- u32 val;
-
- val = simple_strtoul(buf, NULL, 10);
+ u32 val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
if (data->type == w83627thf) {
/* bits 0-3 are reserved in 627THF */
- data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0;
+ data->pwm[nr] = PWM_TO_REG(val) & 0xf0;
w83627hf_write_value(data,
W836X7HF_REG_PWM(data->type, nr),
- data->pwm[nr - 1] |
+ data->pwm[nr] |
(w83627hf_read_value(data,
W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
} else {
- data->pwm[nr - 1] = PWM_TO_REG(val);
+ data->pwm[nr] = PWM_TO_REG(val);
w83627hf_write_value(data,
W836X7HF_REG_PWM(data->type, nr),
- data->pwm[nr - 1]);
+ data->pwm[nr]);
}
mutex_unlock(&data->update_lock);
return count;
}
-#define sysfs_pwm(offset) \
-static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_pwm_reg(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_pwm_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
- show_regs_pwm_##offset, store_regs_pwm_##offset);
-
-sysfs_pwm(1);
-sysfs_pwm(2);
-sysfs_pwm(3);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
static ssize_t
-show_pwm_freq_reg(struct device *dev, char *buf, int nr)
+show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = w83627hf_update_device(dev);
if (data->type == w83627hf)
return sprintf(buf, "%ld\n",
- pwm_freq_from_reg_627hf(data->pwm_freq[nr - 1]));
+ pwm_freq_from_reg_627hf(data->pwm_freq[nr]));
else
return sprintf(buf, "%ld\n",
- pwm_freq_from_reg(data->pwm_freq[nr - 1]));
+ pwm_freq_from_reg(data->pwm_freq[nr]));
}
static ssize_t
-store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_pwm_freq(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = dev_get_drvdata(dev);
static const u8 mask[]={0xF8, 0x8F};
u32 val;
@@ -931,50 +896,42 @@ store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr)
mutex_lock(&data->update_lock);
if (data->type == w83627hf) {
- data->pwm_freq[nr - 1] = pwm_freq_to_reg_627hf(val);
+ data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val);
w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
- (data->pwm_freq[nr - 1] << ((nr - 1)*4)) |
+ (data->pwm_freq[nr] << (nr*4)) |
(w83627hf_read_value(data,
- W83627HF_REG_PWM_FREQ) & mask[nr - 1]));
+ W83627HF_REG_PWM_FREQ) & mask[nr]));
} else {
- data->pwm_freq[nr - 1] = pwm_freq_to_reg(val);
- w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr - 1],
- data->pwm_freq[nr - 1]);
+ data->pwm_freq[nr] = pwm_freq_to_reg(val);
+ w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr],
+ data->pwm_freq[nr]);
}
mutex_unlock(&data->update_lock);
return count;
}
-#define sysfs_pwm_freq(offset) \
-static ssize_t show_regs_pwm_freq_##offset(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- return show_pwm_freq_reg(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_pwm_freq_##offset(struct device *dev, \
- struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_pwm_freq_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR, \
- show_regs_pwm_freq_##offset, store_regs_pwm_freq_##offset);
-
-sysfs_pwm_freq(1);
-sysfs_pwm_freq(2);
-sysfs_pwm_freq(3);
+static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO|S_IWUSR,
+ show_pwm_freq, store_pwm_freq, 0);
+static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO|S_IWUSR,
+ show_pwm_freq, store_pwm_freq, 1);
+static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO|S_IWUSR,
+ show_pwm_freq, store_pwm_freq, 2);
static ssize_t
-show_sensor_reg(struct device *dev, char *buf, int nr)
+show_temp_type(struct device *dev, struct device_attribute *devattr,
+ char *buf)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = w83627hf_update_device(dev);
- return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]);
+ return sprintf(buf, "%ld\n", (long) data->sens[nr]);
}
static ssize_t
-store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_temp_type(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
{
+ int nr = to_sensor_dev_attr(devattr)->index;
struct w83627hf_data *data = dev_get_drvdata(dev);
u32 val, tmp;
@@ -986,31 +943,35 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
case 1: /* PII/Celeron diode */
tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
w83627hf_write_value(data, W83781D_REG_SCFG1,
- tmp | BIT_SCFG1[nr - 1]);
+ tmp | BIT_SCFG1[nr]);
tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
w83627hf_write_value(data, W83781D_REG_SCFG2,
- tmp | BIT_SCFG2[nr - 1]);
- data->sens[nr - 1] = val;
+ tmp | BIT_SCFG2[nr]);
+ data->sens[nr] = val;
break;
case 2: /* 3904 */
tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
w83627hf_write_value(data, W83781D_REG_SCFG1,
- tmp | BIT_SCFG1[nr - 1]);
+ tmp | BIT_SCFG1[nr]);
tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
w83627hf_write_value(data, W83781D_REG_SCFG2,
- tmp & ~BIT_SCFG2[nr - 1]);
- data->sens[nr - 1] = val;
+ tmp & ~BIT_SCFG2[nr]);
+ data->sens[nr] = val;
break;
- case W83781D_DEFAULT_BETA: /* thermistor */
+ case W83781D_DEFAULT_BETA:
+ dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
+ "instead\n", W83781D_DEFAULT_BETA);
+ /* fall through */
+ case 4: /* thermistor */
tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
w83627hf_write_value(data, W83781D_REG_SCFG1,
- tmp & ~BIT_SCFG1[nr - 1]);
- data->sens[nr - 1] = val;
+ tmp & ~BIT_SCFG1[nr]);
+ data->sens[nr] = val;
break;
default:
dev_err(dev,
- "Invalid sensor type %ld; must be 1, 2, or %d\n",
- (long) val, W83781D_DEFAULT_BETA);
+ "Invalid sensor type %ld; must be 1, 2, or 4\n",
+ (long) val);
break;
}
@@ -1018,25 +979,16 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
return count;
}
-#define sysfs_sensor(offset) \
-static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_sensor_reg(dev, buf, offset); \
-} \
-static ssize_t \
-store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_sensor_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
- show_regs_sensor_##offset, store_regs_sensor_##offset);
+#define sysfs_temp_type(offset) \
+static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
+ show_temp_type, store_temp_type, offset - 1);
-sysfs_sensor(1);
-sysfs_sensor(2);
-sysfs_sensor(3);
+sysfs_temp_type(1);
+sysfs_temp_type(2);
+sysfs_temp_type(3);
-static ssize_t show_name(struct device *dev, struct device_attribute
- *devattr, char *buf)
+static ssize_t
+show_name(struct device *dev, struct device_attribute *devattr, char *buf)
{
struct w83627hf_data *data = dev_get_drvdata(dev);
@@ -1118,49 +1070,44 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr,
return err;
}
+#define VIN_UNIT_ATTRS(_X_) \
+ &sensor_dev_attr_in##_X_##_input.dev_attr.attr, \
+ &sensor_dev_attr_in##_X_##_min.dev_attr.attr, \
+ &sensor_dev_attr_in##_X_##_max.dev_attr.attr
+
+#define FAN_UNIT_ATTRS(_X_) \
+ &sensor_dev_attr_fan##_X_##_input.dev_attr.attr, \
+ &sensor_dev_attr_fan##_X_##_min.dev_attr.attr, \
+ &sensor_dev_attr_fan##_X_##_div.dev_attr.attr
+
+#define TEMP_UNIT_ATTRS(_X_) \
+ &sensor_dev_attr_temp##_X_##_input.dev_attr.attr, \
+ &sensor_dev_attr_temp##_X_##_max.dev_attr.attr, \
+ &sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr, \
+ &sensor_dev_attr_temp##_X_##_type.dev_attr.attr
+
static struct attribute *w83627hf_attributes[] = {
&dev_attr_in0_input.attr,
&dev_attr_in0_min.attr,
&dev_attr_in0_max.attr,
- &dev_attr_in2_input.attr,
- &dev_attr_in2_min.attr,
- &dev_attr_in2_max.attr,
- &dev_attr_in3_input.attr,
- &dev_attr_in3_min.attr,
- &dev_attr_in3_max.attr,
- &dev_attr_in4_input.attr,
- &dev_attr_in4_min.attr,
- &dev_attr_in4_max.attr,
- &dev_attr_in7_input.attr,
- &dev_attr_in7_min.attr,
- &dev_attr_in7_max.attr,
- &dev_attr_in8_input.attr,
- &dev_attr_in8_min.attr,
- &dev_attr_in8_max.attr,
-
- &dev_attr_fan1_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan1_div.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan2_div.attr,
-
- &dev_attr_temp1_input.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp1_max_hyst.attr,
- &dev_attr_temp1_type.attr,
- &dev_attr_temp2_input.attr,
- &dev_attr_temp2_max.attr,
- &dev_attr_temp2_max_hyst.attr,
- &dev_attr_temp2_type.attr,
+ VIN_UNIT_ATTRS(2),
+ VIN_UNIT_ATTRS(3),
+ VIN_UNIT_ATTRS(4),
+ VIN_UNIT_ATTRS(7),
+ VIN_UNIT_ATTRS(8),
+
+ FAN_UNIT_ATTRS(1),
+ FAN_UNIT_ATTRS(2),
+
+ TEMP_UNIT_ATTRS(1),
+ TEMP_UNIT_ATTRS(2),
&dev_attr_alarms.attr,
&dev_attr_beep_enable.attr,
&dev_attr_beep_mask.attr,
- &dev_attr_pwm1.attr,
- &dev_attr_pwm2.attr,
-
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
&dev_attr_name.attr,
NULL
};
@@ -1170,30 +1117,17 @@ static const struct attribute_group w83627hf_group = {
};
static struct attribute *w83627hf_attributes_opt[] = {
- &dev_attr_in1_input.attr,
- &dev_attr_in1_min.attr,
- &dev_attr_in1_max.attr,
- &dev_attr_in5_input.attr,
- &dev_attr_in5_min.attr,
- &dev_attr_in5_max.attr,
- &dev_attr_in6_input.attr,
- &dev_attr_in6_min.attr,
- &dev_attr_in6_max.attr,
-
- &dev_attr_fan3_input.attr,
- &dev_attr_fan3_min.attr,
- &dev_attr_fan3_div.attr,
-
- &dev_attr_temp3_input.attr,
- &dev_attr_temp3_max.attr,
- &dev_attr_temp3_max_hyst.attr,
- &dev_attr_temp3_type.attr,
-
- &dev_attr_pwm3.attr,
-
- &dev_attr_pwm1_freq.attr,
- &dev_attr_pwm2_freq.attr,
- &dev_attr_pwm3_freq.attr,
+ VIN_UNIT_ATTRS(1),
+ VIN_UNIT_ATTRS(5),
+ VIN_UNIT_ATTRS(6),
+
+ FAN_UNIT_ATTRS(3),
+ TEMP_UNIT_ATTRS(3),
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+
+ &sensor_dev_attr_pwm1_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm2_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm3_freq.dev_attr.attr,
NULL
};
@@ -1207,7 +1141,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
struct w83627hf_sio_data *sio_data = dev->platform_data;
struct w83627hf_data *data;
struct resource *res;
- int err;
+ int err, i;
static const char *names[] = {
"w83627hf",
@@ -1241,9 +1175,10 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
w83627hf_init_device(pdev);
/* A few vars need to be filled upon startup */
- data->fan_min[0] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(1));
- data->fan_min[1] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(2));
- data->fan_min[2] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(3));
+ for (i = 0; i <= 2; i++)
+ data->fan_min[i] = w83627hf_read_value(
+ data, W83627HF_REG_FAN_MIN(i));
+ w83627hf_update_fan_div(data);
/* Register common device attributes */
if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group)))
@@ -1251,27 +1186,45 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
/* Register chip-specific device attributes */
if (data->type == w83627hf || data->type == w83697hf)
- if ((err = device_create_file(dev, &dev_attr_in5_input))
- || (err = device_create_file(dev, &dev_attr_in5_min))
- || (err = device_create_file(dev, &dev_attr_in5_max))
- || (err = device_create_file(dev, &dev_attr_in6_input))
- || (err = device_create_file(dev, &dev_attr_in6_min))
- || (err = device_create_file(dev, &dev_attr_in6_max))
- || (err = device_create_file(dev, &dev_attr_pwm1_freq))
- || (err = device_create_file(dev, &dev_attr_pwm2_freq)))
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_in5_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in5_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in5_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in6_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in6_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in6_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm1_freq.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm2_freq.dev_attr)))
goto ERROR4;
if (data->type != w83697hf)
- if ((err = device_create_file(dev, &dev_attr_in1_input))
- || (err = device_create_file(dev, &dev_attr_in1_min))
- || (err = device_create_file(dev, &dev_attr_in1_max))
- || (err = device_create_file(dev, &dev_attr_fan3_input))
- || (err = device_create_file(dev, &dev_attr_fan3_min))
- || (err = device_create_file(dev, &dev_attr_fan3_div))
- || (err = device_create_file(dev, &dev_attr_temp3_input))
- || (err = device_create_file(dev, &dev_attr_temp3_max))
- || (err = device_create_file(dev, &dev_attr_temp3_max_hyst))
- || (err = device_create_file(dev, &dev_attr_temp3_type)))
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_in1_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in1_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in1_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan3_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan3_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan3_div.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_type.dev_attr)))
goto ERROR4;
if (data->type != w83697hf && data->vid != 0xff) {
@@ -1285,18 +1238,22 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
if (data->type == w83627thf || data->type == w83637hf
|| data->type == w83687thf)
- if ((err = device_create_file(dev, &dev_attr_pwm3)))
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_pwm3.dev_attr)))
goto ERROR4;
if (data->type == w83637hf || data->type == w83687thf)
- if ((err = device_create_file(dev, &dev_attr_pwm1_freq))
- || (err = device_create_file(dev, &dev_attr_pwm2_freq))
- || (err = device_create_file(dev, &dev_attr_pwm3_freq)))
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_pwm1_freq.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm2_freq.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm3_freq.dev_attr)))
goto ERROR4;
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR4;
}
@@ -1319,7 +1276,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
struct w83627hf_data *data = platform_get_drvdata(pdev);
struct resource *res;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
@@ -1333,6 +1290,24 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
}
+/* Registers 0x50-0x5f are banked */
+static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg)
+{
+ if ((reg & 0x00f0) == 0x50) {
+ outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
+ outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET);
+ }
+}
+
+/* Not strictly necessary, but play it safe for now */
+static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg)
+{
+ if (reg & 0xff00) {
+ outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);
+ outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
+ }
+}
+
static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
{
int res, word_sized;
@@ -1343,12 +1318,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
&& (((reg & 0x00ff) == 0x50)
|| ((reg & 0x00ff) == 0x53)
|| ((reg & 0x00ff) == 0x55));
- if (reg & 0xff00) {
- outb_p(W83781D_REG_BANK,
- data->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(reg >> 8,
- data->addr + W83781D_DATA_REG_OFFSET);
- }
+ w83627hf_set_bank(data, reg);
outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);
if (word_sized) {
@@ -1358,11 +1328,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
(res << 8) + inb_p(data->addr +
W83781D_DATA_REG_OFFSET);
}
- if (reg & 0xff00) {
- outb_p(W83781D_REG_BANK,
- data->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
- }
+ w83627hf_reset_bank(data, reg);
mutex_unlock(&data->lock);
return res;
}
@@ -1433,12 +1399,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
|| ((reg & 0xff00) == 0x200))
&& (((reg & 0x00ff) == 0x53)
|| ((reg & 0x00ff) == 0x55));
- if (reg & 0xff00) {
- outb_p(W83781D_REG_BANK,
- data->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(reg >> 8,
- data->addr + W83781D_DATA_REG_OFFSET);
- }
+ w83627hf_set_bank(data, reg);
outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
if (word_sized) {
outb_p(value >> 8,
@@ -1448,11 +1409,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
}
outb_p(value & 0xff,
data->addr + W83781D_DATA_REG_OFFSET);
- if (reg & 0xff00) {
- outb_p(W83781D_REG_BANK,
- data->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
- }
+ w83627hf_reset_bank(data, reg);
mutex_unlock(&data->lock);
return 0;
}
@@ -1513,7 +1470,7 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
for (i = 1; i <= 3; i++) {
if (!(tmp & BIT_SCFG1[i - 1])) {
- data->sens[i - 1] = W83781D_DEFAULT_BETA;
+ data->sens[i - 1] = 4;
} else {
if (w83627hf_read_value
(data,
@@ -1528,23 +1485,23 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
if(init) {
/* Enable temp2 */
- tmp = w83627hf_read_value(data, W83781D_REG_TEMP2_CONFIG);
+ tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG);
if (tmp & 0x01) {
dev_warn(&pdev->dev, "Enabling temp2, readings "
"might not make sense\n");
- w83627hf_write_value(data, W83781D_REG_TEMP2_CONFIG,
+ w83627hf_write_value(data, W83627HF_REG_TEMP2_CONFIG,
tmp & 0xfe);
}
/* Enable temp3 */
if (type != w83697hf) {
tmp = w83627hf_read_value(data,
- W83781D_REG_TEMP3_CONFIG);
+ W83627HF_REG_TEMP3_CONFIG);
if (tmp & 0x01) {
dev_warn(&pdev->dev, "Enabling temp3, "
"readings might not make sense\n");
w83627hf_write_value(data,
- W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
+ W83627HF_REG_TEMP3_CONFIG, tmp & 0xfe);
}
}
}
@@ -1556,10 +1513,28 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
| 0x01);
}
+static void w83627hf_update_fan_div(struct w83627hf_data *data)
+{
+ int reg;
+
+ reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
+ data->fan_div[0] = (reg >> 4) & 0x03;
+ data->fan_div[1] = (reg >> 6) & 0x03;
+ if (data->type != w83697hf) {
+ data->fan_div[2] = (w83627hf_read_value(data,
+ W83781D_REG_PIN) >> 6) & 0x03;
+ }
+ reg = w83627hf_read_value(data, W83781D_REG_VBAT);
+ data->fan_div[0] |= (reg >> 3) & 0x04;
+ data->fan_div[1] |= (reg >> 4) & 0x04;
+ if (data->type != w83697hf)
+ data->fan_div[2] |= (reg >> 5) & 0x04;
+}
+
static struct w83627hf_data *w83627hf_update_device(struct device *dev)
{
struct w83627hf_data *data = dev_get_drvdata(dev);
- int i;
+ int i, num_temps = (data->type == w83697hf) ? 2 : 3;
mutex_lock(&data->update_lock);
@@ -1580,22 +1555,22 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
w83627hf_read_value(data,
W83781D_REG_IN_MAX(i));
}
- for (i = 1; i <= 3; i++) {
- data->fan[i - 1] =
- w83627hf_read_value(data, W83781D_REG_FAN(i));
- data->fan_min[i - 1] =
+ for (i = 0; i <= 2; i++) {
+ data->fan[i] =
+ w83627hf_read_value(data, W83627HF_REG_FAN(i));
+ data->fan_min[i] =
w83627hf_read_value(data,
- W83781D_REG_FAN_MIN(i));
+ W83627HF_REG_FAN_MIN(i));
}
- for (i = 1; i <= 3; i++) {
+ for (i = 0; i <= 2; i++) {
u8 tmp = w83627hf_read_value(data,
W836X7HF_REG_PWM(data->type, i));
/* bits 0-3 are reserved in 627THF */
if (data->type == w83627thf)
tmp &= 0xf0;
- data->pwm[i - 1] = tmp;
- if(i == 2 &&
- (data->type == w83627hf || data->type == w83697hf))
+ data->pwm[i] = tmp;
+ if (i == 1 &&
+ (data->type == w83627hf || data->type == w83697hf))
break;
}
if (data->type == w83627hf) {
@@ -1612,39 +1587,17 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
break;
}
}
-
- data->temp = w83627hf_read_value(data, W83781D_REG_TEMP(1));
- data->temp_max =
- w83627hf_read_value(data, W83781D_REG_TEMP_OVER(1));
- data->temp_max_hyst =
- w83627hf_read_value(data, W83781D_REG_TEMP_HYST(1));
- data->temp_add[0] =
- w83627hf_read_value(data, W83781D_REG_TEMP(2));
- data->temp_max_add[0] =
- w83627hf_read_value(data, W83781D_REG_TEMP_OVER(2));
- data->temp_max_hyst_add[0] =
- w83627hf_read_value(data, W83781D_REG_TEMP_HYST(2));
- if (data->type != w83697hf) {
- data->temp_add[1] =
- w83627hf_read_value(data, W83781D_REG_TEMP(3));
- data->temp_max_add[1] =
- w83627hf_read_value(data, W83781D_REG_TEMP_OVER(3));
- data->temp_max_hyst_add[1] =
- w83627hf_read_value(data, W83781D_REG_TEMP_HYST(3));
+ for (i = 0; i < num_temps; i++) {
+ data->temp[i] = w83627hf_read_value(
+ data, w83627hf_reg_temp[i]);
+ data->temp_max[i] = w83627hf_read_value(
+ data, w83627hf_reg_temp_over[i]);
+ data->temp_max_hyst[i] = w83627hf_read_value(
+ data, w83627hf_reg_temp_hyst[i]);
}
- i = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
- data->fan_div[0] = (i >> 4) & 0x03;
- data->fan_div[1] = (i >> 6) & 0x03;
- if (data->type != w83697hf) {
- data->fan_div[2] = (w83627hf_read_value(data,
- W83781D_REG_PIN) >> 6) & 0x03;
- }
- i = w83627hf_read_value(data, W83781D_REG_VBAT);
- data->fan_div[0] |= (i >> 3) & 0x04;
- data->fan_div[1] |= (i >> 4) & 0x04;
- if (data->type != w83697hf)
- data->fan_div[2] |= (i >> 5) & 0x04;
+ w83627hf_update_fan_div(data);
+
data->alarms =
w83627hf_read_value(data, W83781D_REG_ALARM1) |
(w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index dcc941a5aaf..e0fa7520400 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -220,7 +220,7 @@ DIV_TO_REG(long val, enum chips type)
the driver field to differentiate between I2C and ISA chips. */
struct w83781d_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex lock;
enum chips type;
@@ -251,9 +251,7 @@ struct w83781d_data {
u8 pwm2_enable; /* Boolean */
u16 sens[3]; /* 782D/783S only.
1 = pentium diode; 2 = 3904 diode;
- 3000-5000 = thermistor beta.
- Default = 3435.
- Other Betas unimplemented */
+ 4 = thermistor */
u8 vrm;
};
@@ -410,7 +408,7 @@ static ssize_t store_temp_##reg (struct device *dev, \
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
struct w83781d_data *data = dev_get_drvdata(dev); \
int nr = attr->index; \
- s32 val; \
+ long val; \
\
val = simple_strtol(buf, NULL, 10); \
\
@@ -456,7 +454,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
static ssize_t
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct w83781d_data *data = w83781d_update_device(dev);
+ struct w83781d_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%ld\n", (long) data->vrm);
}
@@ -483,6 +481,39 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct w83781d_data *data = w83781d_update_device(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+/* The W83781D has a single alarm bit for temp2 and temp3 */
+static ssize_t show_temp3_alarm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct w83781d_data *data = w83781d_update_device(dev);
+ int bitnr = (data->type == w83781d) ? 5 : 13;
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0);
+
static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
{
struct w83781d_data *data = w83781d_update_device(dev);
@@ -546,6 +577,100 @@ static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
show_beep_enable, store_beep_enable);
+static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct w83781d_data *data = w83781d_update_device(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct w83781d_data *data = dev_get_drvdata(dev);
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ unsigned long bit;
+ u8 reg;
+
+ bit = simple_strtoul(buf, NULL, 10);
+ if (bit & ~1)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ if (bit)
+ data->beep_mask |= (1 << bitnr);
+ else
+ data->beep_mask &= ~(1 << bitnr);
+
+ if (bitnr < 8) {
+ reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
+ if (bit)
+ reg |= (1 << bitnr);
+ else
+ reg &= ~(1 << bitnr);
+ w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg);
+ } else if (bitnr < 16) {
+ reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
+ if (bit)
+ reg |= (1 << (bitnr - 8));
+ else
+ reg &= ~(1 << (bitnr - 8));
+ w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg);
+ } else {
+ reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3);
+ if (bit)
+ reg |= (1 << (bitnr - 16));
+ else
+ reg &= ~(1 << (bitnr - 16));
+ w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* The W83781D has a single beep bit for temp2 and temp3 */
+static ssize_t show_temp3_beep(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct w83781d_data *data = w83781d_update_device(dev);
+ int bitnr = (data->type == w83781d) ? 5 : 13;
+ return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 0);
+static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 1);
+static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 2);
+static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 3);
+static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 8);
+static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 9);
+static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 10);
+static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 16);
+static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 17);
+static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 6);
+static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 7);
+static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 11);
+static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 4);
+static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR,
+ show_beep, store_beep, 5);
+static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO,
+ show_temp3_beep, store_beep, 13);
+
static ssize_t
show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
{
@@ -721,15 +846,19 @@ store_sensor(struct device *dev, struct device_attribute *da,
tmp & ~BIT_SCFG2[nr]);
data->sens[nr] = val;
break;
- case W83781D_DEFAULT_BETA: /* thermistor */
+ case W83781D_DEFAULT_BETA:
+ dev_warn(dev, "Sensor type %d is deprecated, please use 4 "
+ "instead\n", W83781D_DEFAULT_BETA);
+ /* fall through */
+ case 4: /* thermistor */
tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
w83781d_write_value(data, W83781D_REG_SCFG1,
tmp & ~BIT_SCFG1[nr]);
data->sens[nr] = val;
break;
default:
- dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n",
- (long) val, W83781D_DEFAULT_BETA);
+ dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n",
+ (long) val);
break;
}
@@ -875,17 +1004,23 @@ ERROR_SC_0:
#define IN_UNIT_ATTRS(X) \
&sensor_dev_attr_in##X##_input.dev_attr.attr, \
&sensor_dev_attr_in##X##_min.dev_attr.attr, \
- &sensor_dev_attr_in##X##_max.dev_attr.attr
+ &sensor_dev_attr_in##X##_max.dev_attr.attr, \
+ &sensor_dev_attr_in##X##_alarm.dev_attr.attr, \
+ &sensor_dev_attr_in##X##_beep.dev_attr.attr
#define FAN_UNIT_ATTRS(X) \
&sensor_dev_attr_fan##X##_input.dev_attr.attr, \
&sensor_dev_attr_fan##X##_min.dev_attr.attr, \
- &sensor_dev_attr_fan##X##_div.dev_attr.attr
+ &sensor_dev_attr_fan##X##_div.dev_attr.attr, \
+ &sensor_dev_attr_fan##X##_alarm.dev_attr.attr, \
+ &sensor_dev_attr_fan##X##_beep.dev_attr.attr
#define TEMP_UNIT_ATTRS(X) \
&sensor_dev_attr_temp##X##_input.dev_attr.attr, \
&sensor_dev_attr_temp##X##_max.dev_attr.attr, \
- &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr
+ &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr, \
+ &sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \
+ &sensor_dev_attr_temp##X##_beep.dev_attr.attr
static struct attribute* w83781d_attributes[] = {
IN_UNIT_ATTRS(0),
@@ -944,7 +1079,11 @@ w83781d_create_files(struct device *dev, int kind, int is_isa)
|| (err = device_create_file(dev,
&sensor_dev_attr_in1_min.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_in1_max.dev_attr)))
+ &sensor_dev_attr_in1_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in1_alarm.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in1_beep.dev_attr)))
return err;
}
if (kind != as99127f && kind != w83781d && kind != w83783s) {
@@ -955,11 +1094,19 @@ w83781d_create_files(struct device *dev, int kind, int is_isa)
|| (err = device_create_file(dev,
&sensor_dev_attr_in7_max.dev_attr))
|| (err = device_create_file(dev,
+ &sensor_dev_attr_in7_alarm.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in7_beep.dev_attr))
+ || (err = device_create_file(dev,
&sensor_dev_attr_in8_input.dev_attr))
|| (err = device_create_file(dev,
&sensor_dev_attr_in8_min.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_in8_max.dev_attr)))
+ &sensor_dev_attr_in8_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in8_alarm.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in8_beep.dev_attr)))
return err;
}
if (kind != w83783s) {
@@ -968,8 +1115,20 @@ w83781d_create_files(struct device *dev, int kind, int is_isa)
|| (err = device_create_file(dev,
&sensor_dev_attr_temp3_max.dev_attr))
|| (err = device_create_file(dev,
- &sensor_dev_attr_temp3_max_hyst.dev_attr)))
+ &sensor_dev_attr_temp3_max_hyst.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_alarm.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_beep.dev_attr)))
return err;
+
+ if (kind != w83781d) {
+ err = sysfs_chmod_file(&dev->kobj,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ S_IRUGO | S_IWUSR);
+ if (err)
+ return err;
+ }
}
if (kind != w83781d && kind != as99127f) {
@@ -1156,9 +1315,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
if (err)
goto ERROR4;
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto ERROR4;
}
@@ -1192,7 +1351,7 @@ w83781d_detach_client(struct i2c_client *client)
/* main client */
if (data) {
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &w83781d_group);
sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt);
}
@@ -1259,9 +1418,9 @@ w83781d_isa_probe(struct platform_device *pdev)
if (err)
goto exit_remove_files;
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -1283,7 +1442,7 @@ w83781d_isa_remove(struct platform_device *pdev)
{
struct w83781d_data *data = platform_get_drvdata(pdev);
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
device_remove_file(&pdev->dev, &dev_attr_name);
@@ -1485,7 +1644,7 @@ w83781d_init_device(struct device *dev)
tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
for (i = 1; i <= 3; i++) {
if (!(tmp & BIT_SCFG1[i - 1])) {
- data->sens[i - 1] = W83781D_DEFAULT_BETA;
+ data->sens[i - 1] = 4;
} else {
if (w83781d_read_value
(data,
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index 9e5f885368b..a9c01a6f005 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -2,7 +2,7 @@
w83791d.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
- Copyright (C) 2006 Charles Spirakis <bezaur@gmail.com>
+ Copyright (C) 2006-2007 Charles Spirakis <bezaur@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
@@ -247,7 +247,7 @@ static u8 div_to_reg(int nr, long val)
struct w83791d_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -384,6 +384,85 @@ static struct sensor_device_attribute sda_in_max[] = {
SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
};
+
+static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr =
+ to_sensor_dev_attr(attr);
+ struct w83791d_data *data = w83791d_update_device(dev);
+ int bitnr = sensor_attr->index;
+
+ return sprintf(buf, "%d\n", (data->beep_mask >> bitnr) & 1);
+}
+
+static ssize_t store_beep(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr =
+ to_sensor_dev_attr(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83791d_data *data = i2c_get_clientdata(client);
+ int bitnr = sensor_attr->index;
+ int bytenr = bitnr / 8;
+ long val = simple_strtol(buf, NULL, 10) ? 1 : 0;
+
+ mutex_lock(&data->update_lock);
+
+ data->beep_mask &= ~(0xff << (bytenr * 8));
+ data->beep_mask |= w83791d_read(client, W83791D_REG_BEEP_CTRL[bytenr])
+ << (bytenr * 8);
+
+ data->beep_mask &= ~(1 << bitnr);
+ data->beep_mask |= val << bitnr;
+
+ w83791d_write(client, W83791D_REG_BEEP_CTRL[bytenr],
+ (data->beep_mask >> (bytenr * 8)) & 0xff);
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr =
+ to_sensor_dev_attr(attr);
+ struct w83791d_data *data = w83791d_update_device(dev);
+ int bitnr = sensor_attr->index;
+
+ return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
+/* Note: The bitmask for the beep enable/disable is different than
+ the bitmask for the alarm. */
+static struct sensor_device_attribute sda_in_beep[] = {
+ SENSOR_ATTR(in0_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 0),
+ SENSOR_ATTR(in1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 13),
+ SENSOR_ATTR(in2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 2),
+ SENSOR_ATTR(in3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 3),
+ SENSOR_ATTR(in4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 8),
+ SENSOR_ATTR(in5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 9),
+ SENSOR_ATTR(in6_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 10),
+ SENSOR_ATTR(in7_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 16),
+ SENSOR_ATTR(in8_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 17),
+ SENSOR_ATTR(in9_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 14),
+};
+
+static struct sensor_device_attribute sda_in_alarm[] = {
+ SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
+ SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
+ SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
+ SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
+ SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
+ SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9),
+ SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10),
+ SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19),
+ SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20),
+ SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 14),
+};
+
#define show_fan_reg(reg) \
static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
char *buf) \
@@ -536,6 +615,22 @@ static struct sensor_device_attribute sda_fan_div[] = {
show_fan_div, store_fan_div, 4),
};
+static struct sensor_device_attribute sda_fan_beep[] = {
+ SENSOR_ATTR(fan1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 6),
+ SENSOR_ATTR(fan2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 7),
+ SENSOR_ATTR(fan3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 11),
+ SENSOR_ATTR(fan4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 21),
+ SENSOR_ATTR(fan5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 22),
+};
+
+static struct sensor_device_attribute sda_fan_alarm[] = {
+ SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
+ SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
+ SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
+ SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21),
+ SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22),
+};
+
/* read/write the temperature1, includes measured value and limits */
static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr,
char *buf)
@@ -618,6 +713,19 @@ static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
show_temp23, store_temp23, 1, 2),
};
+/* Note: The bitmask for the beep enable/disable is different than
+ the bitmask for the alarm. */
+static struct sensor_device_attribute sda_temp_beep[] = {
+ SENSOR_ATTR(temp1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 4),
+ SENSOR_ATTR(temp2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 5),
+ SENSOR_ATTR(temp3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 1),
+};
+
+static struct sensor_device_attribute sda_temp_alarm[] = {
+ SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
+ SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
+ SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+};
/* get reatime status of all sensors items: voltage, temp, fan */
static ssize_t show_alarms_reg(struct device *dev,
@@ -724,7 +832,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
static ssize_t show_vrm_reg(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct w83791d_data *data = w83791d_update_device(dev);
+ struct w83791d_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->vrm);
}
@@ -749,17 +857,23 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
#define IN_UNIT_ATTRS(X) \
&sda_in_input[X].dev_attr.attr, \
&sda_in_min[X].dev_attr.attr, \
- &sda_in_max[X].dev_attr.attr
+ &sda_in_max[X].dev_attr.attr, \
+ &sda_in_beep[X].dev_attr.attr, \
+ &sda_in_alarm[X].dev_attr.attr
#define FAN_UNIT_ATTRS(X) \
&sda_fan_input[X].dev_attr.attr, \
&sda_fan_min[X].dev_attr.attr, \
- &sda_fan_div[X].dev_attr.attr
+ &sda_fan_div[X].dev_attr.attr, \
+ &sda_fan_beep[X].dev_attr.attr, \
+ &sda_fan_alarm[X].dev_attr.attr
#define TEMP_UNIT_ATTRS(X) \
&sda_temp_input[X].dev_attr.attr, \
&sda_temp_max[X].dev_attr.attr, \
- &sda_temp_max_hyst[X].dev_attr.attr
+ &sda_temp_max_hyst[X].dev_attr.attr, \
+ &sda_temp_beep[X].dev_attr.attr, \
+ &sda_temp_alarm[X].dev_attr.attr
static struct attribute *w83791d_attributes[] = {
IN_UNIT_ATTRS(0),
@@ -982,7 +1096,7 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
if (kind == w83791d) {
client_name = "w83791d";
} else {
- dev_err(dev, "w83791d: Internal error: unknown kind (%d)?!?",
+ dev_err(dev, "w83791d: Internal error: unknown kind (%d)?!?\n",
kind);
goto error1;
}
@@ -1017,9 +1131,9 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
goto error3;
/* Everything is ready, now register the working device */
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto error4;
}
@@ -1051,7 +1165,7 @@ static int w83791d_detach_client(struct i2c_client *client)
/* main client */
if (data) {
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &w83791d_group);
}
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index b0fa296740d..007449d3e16 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -267,7 +267,7 @@ DIV_TO_REG(long val)
struct w83792d_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
enum chips type;
struct mutex update_lock;
@@ -540,6 +540,15 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%d\n", data->alarms);
}
+static ssize_t show_alarm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct w83792d_data *data = w83792d_update_device(dev);
+ return sprintf(buf, "%d\n", (data->alarms >> nr) & 1);
+}
+
static ssize_t
show_pwm(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -1015,6 +1024,25 @@ static SENSOR_DEVICE_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR,
show_temp23, store_temp23, 1, 4);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_alarm, NULL, 15);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20);
+static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21);
+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);
@@ -1123,26 +1151,30 @@ static SENSOR_DEVICE_ATTR(fan6_div, S_IWUSR | S_IRUGO,
static SENSOR_DEVICE_ATTR(fan7_div, S_IWUSR | S_IRUGO,
show_fan_div, store_fan_div, 7);
-static struct attribute *w83792d_attributes_fan[4][4] = {
+static struct attribute *w83792d_attributes_fan[4][5] = {
{
&sensor_dev_attr_fan4_input.dev_attr.attr,
&sensor_dev_attr_fan4_min.dev_attr.attr,
&sensor_dev_attr_fan4_div.dev_attr.attr,
+ &sensor_dev_attr_fan4_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_fan5_input.dev_attr.attr,
&sensor_dev_attr_fan5_min.dev_attr.attr,
&sensor_dev_attr_fan5_div.dev_attr.attr,
+ &sensor_dev_attr_fan5_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_fan6_input.dev_attr.attr,
&sensor_dev_attr_fan6_min.dev_attr.attr,
&sensor_dev_attr_fan6_div.dev_attr.attr,
+ &sensor_dev_attr_fan6_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_fan7_input.dev_attr.attr,
&sensor_dev_attr_fan7_min.dev_attr.attr,
&sensor_dev_attr_fan7_div.dev_attr.attr,
+ &sensor_dev_attr_fan7_alarm.dev_attr.attr,
NULL
}
};
@@ -1182,6 +1214,15 @@ static struct attribute *w83792d_attributes[] = {
&sensor_dev_attr_in8_input.dev_attr.attr,
&sensor_dev_attr_in8_max.dev_attr.attr,
&sensor_dev_attr_in8_min.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
+ &sensor_dev_attr_in8_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
@@ -1191,6 +1232,9 @@ static struct attribute *w83792d_attributes[] = {
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm1_mode.dev_attr.attr,
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
@@ -1233,12 +1277,15 @@ static struct attribute *w83792d_attributes[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan3_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
NULL
};
@@ -1338,8 +1385,8 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
if (kind == w83792d) {
client_name = "w83792d";
} else {
- dev_err(dev, "w83792d: Internal error: unknown"
- " kind (%d)?!?", kind);
+ dev_err(dev, "w83792d: Internal error: unknown kind (%d)?!?\n",
+ kind);
goto ERROR1;
}
@@ -1396,9 +1443,9 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
&w83792d_group_fan[3])))
goto exit_remove_files;
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
@@ -1433,7 +1480,7 @@ w83792d_detach_client(struct i2c_client *client)
/* main client */
if (data) {
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &w83792d_group);
for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
sysfs_remove_group(&client->dev.kobj,
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 253ffaf1568..48599e1cc55 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -179,7 +179,7 @@ static inline s8 TEMP_TO_REG(long val, s8 min, s8 max)
struct w83793_data {
struct i2c_client client;
struct i2c_client *lm75[2];
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -1075,7 +1075,7 @@ static int w83793_detach_client(struct i2c_client *client)
/* main client */
if (data) {
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
device_remove_file(dev,
@@ -1434,9 +1434,9 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
}
}
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index a3fcace412f..b5db354e2f1 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -107,7 +107,7 @@ static struct i2c_driver w83l785ts_driver = {
struct w83l785ts_data {
struct i2c_client client;
- struct class_device *class_dev;
+ struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -247,9 +247,9 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_remove;
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
@@ -272,7 +272,7 @@ static int w83l785ts_detach_client(struct i2c_client *client)
struct w83l785ts_data *data = i2c_get_clientdata(client);
int err;
- hwmon_device_unregister(data->class_dev);
+ hwmon_device_unregister(data->hwmon_dev);
device_remove_file(&client->dev,
&sensor_dev_attr_temp1_input.dev_attr);
device_remove_file(&client->dev,
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 7f0a0a62cf6..a37cb6b8593 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -18,7 +18,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
-/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
+/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
<kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
#include <linux/kernel.h>
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index 36fdf971f08..2a16211f12e 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -350,7 +350,7 @@ static int pca_init(struct i2c_algo_pca_data *adap)
pca_outw(adap, I2C_PCA_ADR, own << 1);
pca_set_con(adap, I2C_PCA_CON_ENSIO | clock);
- udelay(500); /* 500 µs for oscilator to stabilise */
+ udelay(500); /* 500 µs for oscilator to stabilise */
return 0;
}
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index ecb2c2d7d54..ab2e6f3498b 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -19,7 +19,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
<mbailey@littlefeet-inc.com> */
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 9f3a4cd0b07..c466c6cfc2e 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -75,11 +75,19 @@ config I2C_AMD8111
config I2C_AT91
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
- depends on ARCH_AT91 && EXPERIMENTAL
+ depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
help
This supports the use of the I2C interface on Atmel AT91
processors.
+ This driver is BROKEN because the controller which it uses
+ will easily trigger RX overrun and TX underrun errors. Using
+ low I2C clock rates may partially work around those issues
+ on some systems. Another serious problem is that there is no
+ documented way to issue repeated START conditions, as needed
+ to support combined I2C messages. Use the i2c-gpio driver
+ unless your system can cope with those limitations.
+
config I2C_AU1550
tristate "Au1550/Au1200 SMBus interface"
depends on SOC_AU1550 || SOC_AU1200
@@ -106,6 +114,19 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
help
The unit of the TWI clock is kHz.
+config I2C_DAVINCI
+ tristate "DaVinci I2C driver"
+ depends on ARCH_DAVINCI
+ help
+ Support for TI DaVinci I2C controller driver.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-davinci.
+
+ Please note that this driver might be needed to bring up other
+ devices such as DaVinci NIC.
+ For details please see http://www.ti.com/davinci
+
config I2C_ELEKTOR
tristate "Elektor ISA card"
depends on ISA && BROKEN_ON_SMP
@@ -257,7 +278,7 @@ config I2C_IXP2000
depends on ARCH_IXP2000
select I2C_ALGOBIT
help
- Say Y here if you have an Intel IXP2000(2400, 2800, 2850) based
+ Say Y here if you have an Intel IXP2000 (2400, 2800, 2850) based
system and are using GPIO lines for an I2C bus.
This support is also available as a module. If so, the module
@@ -272,8 +293,8 @@ config I2C_POWERMAC
default y
help
This exposes the various PowerMac i2c interfaces to the linux i2c
- layer and to userland. It is used by various drivers on the powemac
- platform, thus should generally be enabled.
+ layer and to userland. It is used by various drivers on the PowerMac
+ platform, and should generally be enabled.
This support is also available as a module. If so, the module
will be called i2c-powermac.
@@ -417,12 +438,12 @@ config I2C_SIMTEC
tristate "Simtec Generic I2C interface"
select I2C_ALGOBIT
help
- If you say yes to this option, support will be inclyded for
+ If you say yes to this option, support will be included for
the Simtec Generic I2C interface. This driver is for the
simple I2C bus used on newer Simtec products for general
I2C, such as DDC on the Simtec BBD2016A.
- This driver can also be build as a module. If so, the module
+ This driver can also be built as a module. If so, the module
will be called i2c-simtec.
config SCx200_I2C
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 5b752e4e191..81d43c27cf9 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
obj-$(CONFIG_I2C_AT91) += i2c-at91.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index c9fca7b4926..5d1a27ef250 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -326,7 +326,7 @@ static u32 amd8111_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
- I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC;
+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC;
}
static const struct i2c_algorithm smbus_algorithm = {
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index d7e7c359fc3..2f684166c43 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -48,17 +48,14 @@ wait_xfer_done(struct i2c_au1550_data *adap)
sp = (volatile psc_smb_t *)(adap->psc_base);
- /* Wait for Tx FIFO Underflow.
+ /* Wait for Tx Buffer Empty
*/
for (i = 0; i < adap->xfer_timeout; i++) {
- stat = sp->psc_smbevnt;
+ stat = sp->psc_smbstat;
au_sync();
- if ((stat & PSC_SMBEVNT_TU) != 0) {
- /* Clear it. */
- sp->psc_smbevnt = PSC_SMBEVNT_TU;
- au_sync();
+ if ((stat & PSC_SMBSTAT_TE) != 0)
return 0;
- }
+
udelay(1);
}
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 6311039dfe6..67224a424ab 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -44,7 +44,6 @@
#define TWI_I2C_MODE_COMBINED 0x04
struct bfin_twi_iface {
- struct mutex twi_lock;
int irq;
spinlock_t lock;
char read_write;
@@ -228,12 +227,8 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
return -ENXIO;
- mutex_lock(&iface->twi_lock);
-
while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
- mutex_unlock(&iface->twi_lock);
yield();
- mutex_lock(&iface->twi_lock);
}
ret = 0;
@@ -310,9 +305,6 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
break;
}
- /* Release mutex */
- mutex_unlock(&iface->twi_lock);
-
return ret;
}
@@ -330,12 +322,8 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
return -ENXIO;
- mutex_lock(&iface->twi_lock);
-
while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
- mutex_unlock(&iface->twi_lock);
yield();
- mutex_lock(&iface->twi_lock);
}
iface->writeNum = 0;
@@ -502,9 +490,6 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
rc = (iface->result >= 0) ? 0 : -1;
- /* Release mutex */
- mutex_unlock(&iface->twi_lock);
-
return rc;
}
@@ -555,7 +540,6 @@ static int i2c_bfin_twi_probe(struct platform_device *dev)
struct i2c_adapter *p_adap;
int rc;
- mutex_init(&(iface->twi_lock));
spin_lock_init(&(iface->lock));
init_completion(&(iface->complete));
iface->irq = IRQ_TWI;
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
new file mode 100644
index 00000000000..bd7aaff3524
--- /dev/null
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -0,0 +1,586 @@
+/*
+ * TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ *
+ * Updated by Vinod & Sudhakar Feb 2005
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/i2c.h>
+
+/* ----- global defines ----------------------------------------------- */
+
+#define DAVINCI_I2C_TIMEOUT (1*HZ)
+#define I2C_DAVINCI_INTR_ALL (DAVINCI_I2C_IMR_AAS | \
+ DAVINCI_I2C_IMR_SCD | \
+ DAVINCI_I2C_IMR_ARDY | \
+ DAVINCI_I2C_IMR_NACK | \
+ DAVINCI_I2C_IMR_AL)
+
+#define DAVINCI_I2C_OAR_REG 0x00
+#define DAVINCI_I2C_IMR_REG 0x04
+#define DAVINCI_I2C_STR_REG 0x08
+#define DAVINCI_I2C_CLKL_REG 0x0c
+#define DAVINCI_I2C_CLKH_REG 0x10
+#define DAVINCI_I2C_CNT_REG 0x14
+#define DAVINCI_I2C_DRR_REG 0x18
+#define DAVINCI_I2C_SAR_REG 0x1c
+#define DAVINCI_I2C_DXR_REG 0x20
+#define DAVINCI_I2C_MDR_REG 0x24
+#define DAVINCI_I2C_IVR_REG 0x28
+#define DAVINCI_I2C_EMDR_REG 0x2c
+#define DAVINCI_I2C_PSC_REG 0x30
+
+#define DAVINCI_I2C_IVR_AAS 0x07
+#define DAVINCI_I2C_IVR_SCD 0x06
+#define DAVINCI_I2C_IVR_XRDY 0x05
+#define DAVINCI_I2C_IVR_RDR 0x04
+#define DAVINCI_I2C_IVR_ARDY 0x03
+#define DAVINCI_I2C_IVR_NACK 0x02
+#define DAVINCI_I2C_IVR_AL 0x01
+
+#define DAVINCI_I2C_STR_BB (1 << 12)
+#define DAVINCI_I2C_STR_RSFULL (1 << 11)
+#define DAVINCI_I2C_STR_SCD (1 << 5)
+#define DAVINCI_I2C_STR_ARDY (1 << 2)
+#define DAVINCI_I2C_STR_NACK (1 << 1)
+#define DAVINCI_I2C_STR_AL (1 << 0)
+
+#define DAVINCI_I2C_MDR_NACK (1 << 15)
+#define DAVINCI_I2C_MDR_STT (1 << 13)
+#define DAVINCI_I2C_MDR_STP (1 << 11)
+#define DAVINCI_I2C_MDR_MST (1 << 10)
+#define DAVINCI_I2C_MDR_TRX (1 << 9)
+#define DAVINCI_I2C_MDR_XA (1 << 8)
+#define DAVINCI_I2C_MDR_IRS (1 << 5)
+
+#define DAVINCI_I2C_IMR_AAS (1 << 6)
+#define DAVINCI_I2C_IMR_SCD (1 << 5)
+#define DAVINCI_I2C_IMR_XRDY (1 << 4)
+#define DAVINCI_I2C_IMR_RRDY (1 << 3)
+#define DAVINCI_I2C_IMR_ARDY (1 << 2)
+#define DAVINCI_I2C_IMR_NACK (1 << 1)
+#define DAVINCI_I2C_IMR_AL (1 << 0)
+
+#define MOD_REG_BIT(val, mask, set) do { \
+ if (set) { \
+ val |= mask; \
+ } else { \
+ val &= ~mask; \
+ } \
+} while (0)
+
+struct davinci_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct completion cmd_complete;
+ struct clk *clk;
+ int cmd_err;
+ u8 *buf;
+ size_t buf_len;
+ int irq;
+ struct i2c_adapter adapter;
+};
+
+/* default platform data to use if not supplied in the platform_device */
+static struct davinci_i2c_platform_data davinci_i2c_platform_data_default = {
+ .bus_freq = 100,
+ .bus_delay = 0,
+};
+
+static inline void davinci_i2c_write_reg(struct davinci_i2c_dev *i2c_dev,
+ int reg, u16 val)
+{
+ __raw_writew(val, i2c_dev->base + reg);
+}
+
+static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg)
+{
+ return __raw_readw(i2c_dev->base + reg);
+}
+
+/*
+ * This functions configures I2C and brings I2C out of reset.
+ * This function is called during I2C init function. This function
+ * also gets called if I2C encounters any errors.
+ */
+static int i2c_davinci_init(struct davinci_i2c_dev *dev)
+{
+ struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+ u16 psc;
+ u32 clk;
+ u32 clkh;
+ u32 clkl;
+ u32 input_clock = clk_get_rate(dev->clk);
+ u16 w;
+
+ if (!pdata)
+ pdata = &davinci_i2c_platform_data_default;
+
+ /* put I2C into reset */
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 0);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+
+ /* NOTE: I2C Clock divider programming info
+ * As per I2C specs the following formulas provide prescaler
+ * and low/high divider values
+ * input clk --> PSC Div -----------> ICCL/H Div --> output clock
+ * module clk
+ *
+ * output clk = module clk / (PSC + 1) [ (ICCL + d) + (ICCH + d) ]
+ *
+ * Thus,
+ * (ICCL + ICCH) = clk = (input clk / ((psc +1) * output clk)) - 2d;
+ *
+ * where if PSC == 0, d = 7,
+ * if PSC == 1, d = 6
+ * if PSC > 1 , d = 5
+ */
+
+ psc = 26; /* To get 1MHz clock */
+
+ clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000)) - 10;
+ clkh = (50 * clk) / 100;
+ clkl = clk - clkh;
+
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_PSC_REG, psc);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);
+
+ dev_dbg(dev->dev, "CLK = %d\n", clk);
+ dev_dbg(dev->dev, "PSC = %d\n",
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG));
+ dev_dbg(dev->dev, "CLKL = %d\n",
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG));
+ dev_dbg(dev->dev, "CLKH = %d\n",
+ davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG));
+
+ /* Take the I2C module out of reset: */
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_MDR_IRS, 1);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+
+ /* Enable interrupts */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, I2C_DAVINCI_INTR_ALL);
+
+ return 0;
+}
+
+/*
+ * Waiting for bus not busy
+ */
+static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
+ char allow_sleep)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + DAVINCI_I2C_TIMEOUT;
+ while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG)
+ & DAVINCI_I2C_STR_BB) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev,
+ "timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+ if (allow_sleep)
+ schedule_timeout(1);
+ }
+
+ return 0;
+}
+
+/*
+ * Low level master read/write transaction. This function is called
+ * from i2c_davinci_xfer.
+ */
+static int
+i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+ struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+ u32 flag;
+ u32 stat;
+ u16 w;
+ int r;
+
+ if (msg->len == 0)
+ return -EINVAL;
+
+ if (!pdata)
+ pdata = &davinci_i2c_platform_data_default;
+ /* Introduce a delay, required for some boards (e.g Davinci EVM) */
+ if (pdata->bus_delay)
+ udelay(pdata->bus_delay);
+
+ /* set the slave address */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_SAR_REG, msg->addr);
+
+ dev->buf = msg->buf;
+ dev->buf_len = msg->len;
+
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len);
+
+ init_completion(&dev->cmd_complete);
+ dev->cmd_err = 0;
+
+ /* Clear any pending interrupts by reading the IVR */
+ stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG);
+
+ /* Take I2C out of reset, configure it as master and set the
+ * start bit */
+ flag = DAVINCI_I2C_MDR_IRS | DAVINCI_I2C_MDR_MST | DAVINCI_I2C_MDR_STT;
+
+ /* if the slave address is ten bit address, enable XA bit */
+ if (msg->flags & I2C_M_TEN)
+ flag |= DAVINCI_I2C_MDR_XA;
+ if (!(msg->flags & I2C_M_RD))
+ flag |= DAVINCI_I2C_MDR_TRX;
+ if (stop)
+ flag |= DAVINCI_I2C_MDR_STP;
+
+ /* Enable receive or transmit interrupts */
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG);
+ if (msg->flags & I2C_M_RD)
+ MOD_REG_BIT(w, DAVINCI_I2C_IMR_RRDY, 1);
+ else
+ MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 1);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w);
+
+ /* write the data into mode register */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+
+ r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ DAVINCI_I2C_TIMEOUT);
+ dev->buf_len = 0;
+ if (r < 0)
+ return r;
+
+ if (r == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ i2c_davinci_init(dev);
+ return -ETIMEDOUT;
+ }
+
+ /* no error */
+ if (likely(!dev->cmd_err))
+ return msg->len;
+
+ /* We have an error */
+ if (dev->cmd_err & DAVINCI_I2C_STR_AL) {
+ i2c_davinci_init(dev);
+ return -EIO;
+ }
+
+ if (dev->cmd_err & DAVINCI_I2C_STR_NACK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return msg->len;
+ if (stop) {
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_MDR_STP, 1);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+ }
+ return -EREMOTEIO;
+ }
+ return -EIO;
+}
+
+/*
+ * Prepare controller for a transaction and call i2c_davinci_xfer_msg
+ */
+static int
+i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+ int i;
+ int ret;
+
+ dev_dbg(dev->dev, "%s: msgs: %d\n", __FUNCTION__, num);
+
+ ret = i2c_davinci_wait_bus_not_busy(dev, 1);
+ if (ret < 0) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return ret;
+ }
+
+ for (i = 0; i < num; i++) {
+ ret = i2c_davinci_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+ if (ret < 0)
+ return ret;
+ }
+
+ dev_dbg(dev->dev, "%s:%d ret: %d\n", __FUNCTION__, __LINE__, ret);
+
+ return num;
+}
+
+static u32 i2c_davinci_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C interrupt
+ * occurs.
+ */
+static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
+{
+ struct davinci_i2c_dev *dev = dev_id;
+ u32 stat;
+ int count = 0;
+ u16 w;
+
+ while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) {
+ dev_dbg(dev->dev, "%s: stat=0x%x\n", __FUNCTION__, stat);
+ if (count++ == 100) {
+ dev_warn(dev->dev, "Too much work in one IRQ\n");
+ break;
+ }
+
+ switch (stat) {
+ case DAVINCI_I2C_IVR_AL:
+ dev->cmd_err |= DAVINCI_I2C_STR_AL;
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_NACK:
+ dev->cmd_err |= DAVINCI_I2C_STR_NACK;
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_ARDY:
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_STR_ARDY, 1);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_STR_REG, w);
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_RDR:
+ if (dev->buf_len) {
+ *dev->buf++ =
+ davinci_i2c_read_reg(dev,
+ DAVINCI_I2C_DRR_REG);
+ dev->buf_len--;
+ if (dev->buf_len)
+ continue;
+
+ w = davinci_i2c_read_reg(dev,
+ DAVINCI_I2C_STR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_IMR_RRDY, 0);
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_STR_REG,
+ w);
+ } else
+ dev_err(dev->dev, "RDR IRQ while no"
+ "data requested\n");
+ break;
+
+ case DAVINCI_I2C_IVR_XRDY:
+ if (dev->buf_len) {
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG,
+ *dev->buf++);
+ dev->buf_len--;
+ if (dev->buf_len)
+ continue;
+
+ w = davinci_i2c_read_reg(dev,
+ DAVINCI_I2C_IMR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_IMR_XRDY, 0);
+ davinci_i2c_write_reg(dev,
+ DAVINCI_I2C_IMR_REG,
+ w);
+ } else
+ dev_err(dev->dev, "TDR IRQ while no data to"
+ "send\n");
+ break;
+
+ case DAVINCI_I2C_IVR_SCD:
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG);
+ MOD_REG_BIT(w, DAVINCI_I2C_STR_SCD, 1);
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_STR_REG, w);
+ complete(&dev->cmd_complete);
+ break;
+
+ case DAVINCI_I2C_IVR_AAS:
+ dev_warn(dev->dev, "Address as slave interrupt\n");
+ }/* switch */
+ }/* while */
+
+ return count ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static struct i2c_algorithm i2c_davinci_algo = {
+ .master_xfer = i2c_davinci_xfer,
+ .functionality = i2c_davinci_func,
+};
+
+static int davinci_i2c_probe(struct platform_device *pdev)
+{
+ struct davinci_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *mem, *irq, *ioarea;
+ int r;
+
+ /* NOTE: driver uses the static register mapping */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return -ENODEV;
+ }
+
+ ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+ pdev->name);
+ if (!ioarea) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ dev = kzalloc(sizeof(struct davinci_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ r = -ENOMEM;
+ goto err_release_region;
+ }
+
+ dev->dev = get_device(&pdev->dev);
+ dev->irq = irq->start;
+ platform_set_drvdata(pdev, dev);
+
+ dev->clk = clk_get(&pdev->dev, "I2CCLK");
+ if (IS_ERR(dev->clk)) {
+ r = -ENODEV;
+ goto err_free_mem;
+ }
+ clk_enable(dev->clk);
+
+ dev->base = (void __iomem *)IO_ADDRESS(mem->start);
+ i2c_davinci_init(dev);
+
+ r = request_irq(dev->irq, i2c_davinci_isr, 0, pdev->name, dev);
+ if (r) {
+ dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+ goto err_unuse_clocks;
+ }
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name));
+ adap->algo = &i2c_davinci_algo;
+ adap->dev.parent = &pdev->dev;
+
+ /* FIXME */
+ adap->timeout = 1;
+ adap->retries = 1;
+
+ adap->nr = pdev->id;
+ r = i2c_add_numbered_adapter(adap);
+ if (r) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ return 0;
+
+err_free_irq:
+ free_irq(dev->irq, dev);
+err_unuse_clocks:
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+err_free_mem:
+ platform_set_drvdata(pdev, NULL);
+ put_device(&pdev->dev);
+ kfree(dev);
+err_release_region:
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+ return r;
+}
+
+static int davinci_i2c_remove(struct platform_device *pdev)
+{
+ struct davinci_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ platform_set_drvdata(pdev, NULL);
+ i2c_del_adapter(&dev->adapter);
+ put_device(&pdev->dev);
+
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
+ free_irq(IRQ_I2C, dev);
+ kfree(dev);
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+ return 0;
+}
+
+static struct platform_driver davinci_i2c_driver = {
+ .probe = davinci_i2c_probe,
+ .remove = davinci_i2c_remove,
+ .driver = {
+ .name = "i2c_davinci",
+ .owner = THIS_MODULE,
+ },
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init davinci_i2c_init_driver(void)
+{
+ return platform_driver_register(&davinci_i2c_driver);
+}
+subsys_initcall(davinci_i2c_init_driver);
+
+static void __exit davinci_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&davinci_i2c_driver);
+}
+module_exit(davinci_i2c_exit_driver);
+
+MODULE_AUTHOR("Texas Instruments India");
+MODULE_DESCRIPTION("TI DaVinci I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
index 804f0a551c0..b7a9977b025 100644
--- a/drivers/i2c/busses/i2c-elektor.c
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -19,7 +19,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
/* Partialy rewriten by Oleg I. Vdovikin for mmapped support of
diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
index 9832f773651..f9972f9651e 100644
--- a/drivers/i2c/busses/i2c-hydra.c
+++ b/drivers/i2c/busses/i2c-hydra.c
@@ -7,7 +7,7 @@
Copyright (c) 1999-2004 Geert Uytterhoeven <geert@linux-m68k.org>
Based on i2c Support for Via Technologies 82C586B South Bridge
- Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
+ Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 289816db52a..ac27e5f84eb 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -34,6 +34,7 @@
ESB2 269B
ICH8 283E
ICH9 2930
+ Tolapai 5032
This driver supports several versions of Intel's I/O Controller Hubs (ICH).
For SMBus support, they are similar to the PIIX4 and are part
of Intel's '810' and other chipsets.
@@ -515,7 +516,7 @@ static u32 i801_func(struct i2c_adapter *adapter)
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
- | (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);
+ | (isich4 ? I2C_FUNC_SMBUS_PEC : 0);
}
static const struct i2c_algorithm smbus_algorithm = {
@@ -543,6 +544,7 @@ static struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) },
{ 0, }
};
@@ -563,6 +565,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
case PCI_DEVICE_ID_INTEL_ESB2_17:
case PCI_DEVICE_ID_INTEL_ICH8_5:
case PCI_DEVICE_ID_INTEL_ICH9_6:
+ case PCI_DEVICE_ID_INTEL_TOLAPAI_1:
isich4 = 1;
break;
default:
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 8b14d14e60c..9b43ff7270d 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -18,7 +18,7 @@
* Copyright 1995-97 Simon G. Vogl
* 1998-99 Hans Berglund
*
- * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>
+ * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>
* and even Frodo Looijaard <frodol@dds.nl>
*
* This program is free software; you can redistribute it and/or modify it
@@ -738,7 +738,14 @@ static int __devinit iic_probe(struct ocp_device *ocp){
adap->timeout = 1;
adap->retries = 1;
- if ((ret = i2c_add_adapter(adap)) != 0){
+ /*
+ * If "dev->idx" is negative we consider it as zero.
+ * The reason to do so is to avoid sysfs names that only make
+ * sense when there are multiple adapters.
+ */
+ adap->nr = dev->idx >= 0 ? dev->idx : 0;
+
+ if ((ret = i2c_add_numbered_adapter(adap)) < 0) {
printk(KERN_CRIT "ibm-iic%d: failed to register i2c adapter\n",
dev->idx);
goto fail;
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index ace644e21b1..c70146e4c2c 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -389,13 +389,6 @@ iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
return im;
}
-static int
-iop3xx_i2c_algo_control(struct i2c_adapter *adapter, unsigned int cmd,
- unsigned long arg)
-{
- return 0;
-}
-
static u32
iop3xx_i2c_func(struct i2c_adapter *adap)
{
@@ -404,7 +397,6 @@ iop3xx_i2c_func(struct i2c_adapter *adap)
static const struct i2c_algorithm iop3xx_i2c_algo = {
.master_xfer = iop3xx_i2c_master_xfer,
- .algo_control = iop3xx_i2c_algo_control,
.functionality = iop3xx_i2c_func,
};
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index c48140f782d..1bf590c7416 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -62,6 +62,7 @@ struct nforce2_smbus {
int base;
int size;
int blockops;
+ int can_abort;
};
@@ -83,7 +84,14 @@ struct nforce2_smbus {
#define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */
#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data
bytes */
-
+#define NVIDIA_SMB_STATUS_ABRT (smbus->base + 0x3c) /* register used to
+ check the status of
+ the abort command */
+#define NVIDIA_SMB_CTRL (smbus->base + 0x3e) /* control register */
+
+#define NVIDIA_SMB_STATUS_ABRT_STS 0x01 /* Bit to notify that
+ abort succeeded */
+#define NVIDIA_SMB_CTRL_ABORT 0x20
#define NVIDIA_SMB_STS_DONE 0x80
#define NVIDIA_SMB_STS_ALRM 0x40
#define NVIDIA_SMB_STS_RES 0x20
@@ -98,15 +106,61 @@ struct nforce2_smbus {
#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a
#define NVIDIA_SMB_PRTCL_PEC 0x80
+/* Misc definitions */
+#define MAX_TIMEOUT 100
+
static struct pci_driver nforce2_driver;
+static void nforce2_abort(struct i2c_adapter *adap)
+{
+ struct nforce2_smbus *smbus = adap->algo_data;
+ int timeout = 0;
+ unsigned char temp;
+
+ dev_dbg(&adap->dev, "Aborting current transaction\n");
+
+ outb_p(NVIDIA_SMB_CTRL_ABORT, NVIDIA_SMB_CTRL);
+ do {
+ msleep(1);
+ temp = inb_p(NVIDIA_SMB_STATUS_ABRT);
+ } while (!(temp & NVIDIA_SMB_STATUS_ABRT_STS) &&
+ (timeout++ < MAX_TIMEOUT));
+ if (!(temp & NVIDIA_SMB_STATUS_ABRT_STS))
+ dev_err(&adap->dev, "Can't reset the smbus\n");
+ outb_p(NVIDIA_SMB_STATUS_ABRT_STS, NVIDIA_SMB_STATUS_ABRT);
+}
+
+static int nforce2_check_status(struct i2c_adapter *adap)
+{
+ struct nforce2_smbus *smbus = adap->algo_data;
+ int timeout = 0;
+ unsigned char temp;
+
+ do {
+ msleep(1);
+ temp = inb_p(NVIDIA_SMB_STS);
+ } while ((!temp) && (timeout++ < MAX_TIMEOUT));
+
+ if (timeout >= MAX_TIMEOUT) {
+ dev_dbg(&adap->dev, "SMBus Timeout!\n");
+ if (smbus->can_abort)
+ nforce2_abort(adap);
+ return -1;
+ }
+ if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
+ dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp);
+ return -1;
+ }
+ return 0;
+}
+
/* Return -1 on error */
static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data * data)
{
struct nforce2_smbus *smbus = adap->algo_data;
- unsigned char protocol, pec, temp;
+ unsigned char protocol, pec;
u8 len;
int i;
@@ -170,21 +224,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
outb_p(protocol, NVIDIA_SMB_PRTCL);
- temp = inb_p(NVIDIA_SMB_STS);
-
- if (~temp & NVIDIA_SMB_STS_DONE) {
- udelay(500);
- temp = inb_p(NVIDIA_SMB_STS);
- }
- if (~temp & NVIDIA_SMB_STS_DONE) {
- msleep(10);
- temp = inb_p(NVIDIA_SMB_STS);
- }
-
- if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
- dev_dbg(&adap->dev, "SMBus Timeout! (0x%02x)\n", temp);
+ if (nforce2_check_status(adap))
return -1;
- }
if (read_write == I2C_SMBUS_WRITE)
return 0;
@@ -202,7 +243,12 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
case I2C_SMBUS_BLOCK_DATA:
len = inb_p(NVIDIA_SMB_BCNT);
- len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
+ if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
+ dev_err(&adap->dev, "Transaction failed "
+ "(received block size: 0x%02x)\n",
+ len);
+ return -1;
+ }
for (i = 0; i < len; i++)
data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
data->block[0] = len;
@@ -218,6 +264,7 @@ static u32 nforce2_func(struct i2c_adapter *adapter)
/* other functionality might be possible, but is not tested */
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_PEC |
(((struct nforce2_smbus*)adapter->algo_data)->blockops ?
I2C_FUNC_SMBUS_BLOCK_DATA : 0);
}
@@ -308,6 +355,8 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
smbuses[0].blockops = 1;
smbuses[1].blockops = 1;
+ smbuses[0].can_abort = 1;
+ smbuses[1].can_abort = 1;
}
/* SMBus adapter 1 */
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index e471e3bfdc1..89a30028ddb 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -8,7 +8,7 @@
* Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
* Copyright (C) 2005 Nokia Corporation
*
- * Cleaned up by Juha Yrjölä <juha.yrjola@nokia.com>
+ * Cleaned up by Juha Yrjölä <juha.yrjola@nokia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index 49a95e2887b..c6faf9bdad1 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -7,7 +7,7 @@
Copyright (C) 1995-2000 Simon G. Vogl
With some changes from:
Frodo Looijaard <frodol@dds.nl>
- Kyösti Mälkki <kmalkki@cc.hut.fi>
+ Kyösti Mälkki <kmalkki@cc.hut.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
index 039a07fde90..59ba2086d2f 100644
--- a/drivers/i2c/busses/i2c-parport.c
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -7,7 +7,7 @@
Copyright (C) 1995-2000 Simon G. Vogl
With some changes from:
Frodo Looijaard <frodol@dds.nl>
- Kyösti Mälkki <kmalkki@cc.hut.fi>
+ Kyösti Mälkki <kmalkki@cc.hut.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
index 58e32714afb..ca18e0be490 100644
--- a/drivers/i2c/busses/i2c-pasemi.c
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -51,6 +51,7 @@ struct pasemi_smbus {
#define MRXFIFO_DATA_M 0x000000ff
#define SMSTA_XEN 0x08000000
+#define SMSTA_MTN 0x00200000
#define CTL_MRR 0x00000400
#define CTL_MTR 0x00000200
@@ -98,6 +99,10 @@ static unsigned int pasemi_smb_waitready(struct pasemi_smbus *smbus)
status = reg_read(smbus, REG_SMSTA);
}
+ /* Got NACK? */
+ if (status & SMSTA_MTN)
+ return -ENXIO;
+
if (timeout < 0) {
dev_warn(&smbus->dev->dev, "Timeout, status 0x%08x\n", status);
reg_write(smbus, REG_SMSTA, status);
@@ -364,7 +369,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev,
smbus->adapter.algo = &smbus_algorithm;
smbus->adapter.algo_data = smbus;
- /* set up the driverfs linkage to our parent device */
+ /* set up the sysfs linkage to our parent device */
smbus->adapter.dev.parent = &dev->dev;
reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
index 17cecf1ea79..be99c02ecac 100644
--- a/drivers/i2c/busses/i2c-pmcmsp.c
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -591,18 +591,18 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
if (msg->flags & I2C_M_TEN)
pmcmsptwi_set_twi_config(&oldcfg, data);
- dev_dbg(&adap->dev, "I2C %s of %d bytes ",
- (msg->flags & I2C_M_RD) ? "read" : "write", msg->len);
+ dev_dbg(&adap->dev, "I2C %s of %d bytes %s\n",
+ (msg->flags & I2C_M_RD) ? "read" : "write", msg->len,
+ (ret == MSP_TWI_XFER_OK) ? "succeeded" : "failed");
+
if (ret != MSP_TWI_XFER_OK) {
/*
* TODO: We could potentially loop and retry in the case
* of MSP_TWI_XFER_TIMEOUT.
*/
- dev_dbg(&adap->dev, "failed\n");
return -1;
}
- dev_dbg(&adap->dev, "succeeded\n");
return 0;
}
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index 17376feb1ac..f8d0dff0de7 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -575,7 +575,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
else {
freq_mhz = PNX_DEFAULT_FREQ;
dev_info(&pdev->dev, "Setting bus frequency to default value: "
- "%d MHz", freq_mhz);
+ "%d MHz\n", freq_mhz);
}
i2c_pnx->adapter->algo = &pnx_algorithm;
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index bb5466b27b5..6426a61f8d4 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -31,6 +31,8 @@
#include <linux/interrupt.h>
#include <linux/i2c-pxa.h>
#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
#include <asm/hardware.h>
#include <asm/irq.h>
@@ -48,6 +50,7 @@ struct pxa_i2c {
unsigned int slave_addr;
struct i2c_adapter adap;
+ struct clk *clk;
#ifdef CONFIG_I2C_PXA_SLAVE
struct i2c_slave_client *slave;
#endif
@@ -82,7 +85,7 @@ struct bits {
const char *set;
const char *unset;
};
-#define BIT(m, s, u) { .mask = m, .set = s, .unset = u }
+#define PXA_BIT(m, s, u) { .mask = m, .set = s, .unset = u }
static inline void
decode_bits(const char *prefix, const struct bits *bits, int num, u32 val)
@@ -97,17 +100,17 @@ decode_bits(const char *prefix, const struct bits *bits, int num, u32 val)
}
static const struct bits isr_bits[] = {
- BIT(ISR_RWM, "RX", "TX"),
- BIT(ISR_ACKNAK, "NAK", "ACK"),
- BIT(ISR_UB, "Bsy", "Rdy"),
- BIT(ISR_IBB, "BusBsy", "BusRdy"),
- BIT(ISR_SSD, "SlaveStop", NULL),
- BIT(ISR_ALD, "ALD", NULL),
- BIT(ISR_ITE, "TxEmpty", NULL),
- BIT(ISR_IRF, "RxFull", NULL),
- BIT(ISR_GCAD, "GenCall", NULL),
- BIT(ISR_SAD, "SlaveAddr", NULL),
- BIT(ISR_BED, "BusErr", NULL),
+ PXA_BIT(ISR_RWM, "RX", "TX"),
+ PXA_BIT(ISR_ACKNAK, "NAK", "ACK"),
+ PXA_BIT(ISR_UB, "Bsy", "Rdy"),
+ PXA_BIT(ISR_IBB, "BusBsy", "BusRdy"),
+ PXA_BIT(ISR_SSD, "SlaveStop", NULL),
+ PXA_BIT(ISR_ALD, "ALD", NULL),
+ PXA_BIT(ISR_ITE, "TxEmpty", NULL),
+ PXA_BIT(ISR_IRF, "RxFull", NULL),
+ PXA_BIT(ISR_GCAD, "GenCall", NULL),
+ PXA_BIT(ISR_SAD, "SlaveAddr", NULL),
+ PXA_BIT(ISR_BED, "BusErr", NULL),
};
static void decode_ISR(unsigned int val)
@@ -117,21 +120,21 @@ static void decode_ISR(unsigned int val)
}
static const struct bits icr_bits[] = {
- BIT(ICR_START, "START", NULL),
- BIT(ICR_STOP, "STOP", NULL),
- BIT(ICR_ACKNAK, "ACKNAK", NULL),
- BIT(ICR_TB, "TB", NULL),
- BIT(ICR_MA, "MA", NULL),
- BIT(ICR_SCLE, "SCLE", "scle"),
- BIT(ICR_IUE, "IUE", "iue"),
- BIT(ICR_GCD, "GCD", NULL),
- BIT(ICR_ITEIE, "ITEIE", NULL),
- BIT(ICR_IRFIE, "IRFIE", NULL),
- BIT(ICR_BEIE, "BEIE", NULL),
- BIT(ICR_SSDIE, "SSDIE", NULL),
- BIT(ICR_ALDIE, "ALDIE", NULL),
- BIT(ICR_SADIE, "SADIE", NULL),
- BIT(ICR_UR, "UR", "ur"),
+ PXA_BIT(ICR_START, "START", NULL),
+ PXA_BIT(ICR_STOP, "STOP", NULL),
+ PXA_BIT(ICR_ACKNAK, "ACKNAK", NULL),
+ PXA_BIT(ICR_TB, "TB", NULL),
+ PXA_BIT(ICR_MA, "MA", NULL),
+ PXA_BIT(ICR_SCLE, "SCLE", "scle"),
+ PXA_BIT(ICR_IUE, "IUE", "iue"),
+ PXA_BIT(ICR_GCD, "GCD", NULL),
+ PXA_BIT(ICR_ITEIE, "ITEIE", NULL),
+ PXA_BIT(ICR_IRFIE, "IRFIE", NULL),
+ PXA_BIT(ICR_BEIE, "BEIE", NULL),
+ PXA_BIT(ICR_SSDIE, "SSDIE", NULL),
+ PXA_BIT(ICR_ALDIE, "ALDIE", NULL),
+ PXA_BIT(ICR_SADIE, "SADIE", NULL),
+ PXA_BIT(ICR_UR, "UR", "ur"),
};
static void decode_ICR(unsigned int val)
@@ -869,6 +872,12 @@ static int i2c_pxa_probe(struct platform_device *dev)
sprintf(i2c->adap.name, "pxa_i2c-i2c.%u", dev->id);
+ i2c->clk = clk_get(&dev->dev, "I2CCLK");
+ if (IS_ERR(i2c->clk)) {
+ ret = PTR_ERR(i2c->clk);
+ goto eclk;
+ }
+
i2c->reg_base = ioremap(res->start, res_len(res));
if (!i2c->reg_base) {
ret = -EIO;
@@ -889,22 +898,19 @@ static int i2c_pxa_probe(struct platform_device *dev)
}
#endif
+ clk_enable(i2c->clk);
+#ifdef CONFIG_PXA27x
switch (dev->id) {
case 0:
-#ifdef CONFIG_PXA27x
pxa_gpio_mode(GPIO117_I2CSCL_MD);
pxa_gpio_mode(GPIO118_I2CSDA_MD);
-#endif
- pxa_set_cken(CKEN_I2C, 1);
break;
-#ifdef CONFIG_PXA27x
case 1:
local_irq_disable();
PCFR |= PCFR_PI2CEN;
local_irq_enable();
- pxa_set_cken(CKEN_PWRI2C, 1);
-#endif
}
+#endif
ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED,
i2c->adap.name, i2c);
@@ -948,19 +954,18 @@ static int i2c_pxa_probe(struct platform_device *dev)
eadapt:
free_irq(irq, i2c);
ereqirq:
- switch (dev->id) {
- case 0:
- pxa_set_cken(CKEN_I2C, 0);
- break;
+ clk_disable(i2c->clk);
+
#ifdef CONFIG_PXA27x
- case 1:
- pxa_set_cken(CKEN_PWRI2C, 0);
+ if (dev->id == 1) {
local_irq_disable();
PCFR &= ~PCFR_PI2CEN;
local_irq_enable();
-#endif
}
+#endif
eremap:
+ clk_put(i2c->clk);
+eclk:
kfree(i2c);
emalloc:
release_mem_region(res->start, res_len(res));
@@ -975,18 +980,18 @@ static int i2c_pxa_remove(struct platform_device *dev)
i2c_del_adapter(&i2c->adap);
free_irq(i2c->irq, i2c);
- switch (dev->id) {
- case 0:
- pxa_set_cken(CKEN_I2C, 0);
- break;
+
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
#ifdef CONFIG_PXA27x
- case 1:
- pxa_set_cken(CKEN_PWRI2C, 0);
+ if (dev->id == 1) {
local_irq_disable();
PCFR &= ~PCFR_PI2CEN;
local_irq_enable();
-#endif
}
+#endif
+
release_mem_region(i2c->iobase, i2c->iosize);
kfree(i2c);
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
index a54adc50d16..84df29da1dd 100644
--- a/drivers/i2c/busses/i2c-stub.c
+++ b/drivers/i2c/busses/i2c-stub.c
@@ -24,24 +24,41 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/i2c.h>
-static unsigned short chip_addr;
-module_param(chip_addr, ushort, S_IRUGO);
-MODULE_PARM_DESC(chip_addr, "Chip address (between 0x03 and 0x77)\n");
+#define MAX_CHIPS 10
-static u8 stub_pointer;
-static u8 stub_bytes[256];
-static u16 stub_words[256];
+static unsigned short chip_addr[MAX_CHIPS];
+module_param_array(chip_addr, ushort, NULL, S_IRUGO);
+MODULE_PARM_DESC(chip_addr,
+ "Chip addresses (up to 10, between 0x03 and 0x77)\n");
+
+struct stub_chip {
+ u8 pointer;
+ u8 bytes[256];
+ u16 words[256];
+};
+
+static struct stub_chip *stub_chips;
/* Return -1 on error. */
static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
char read_write, u8 command, int size, union i2c_smbus_data * data)
{
s32 ret;
-
- if (addr != chip_addr)
+ int i;
+ struct stub_chip *chip = NULL;
+
+ /* Search for the right chip */
+ for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
+ if (addr == chip_addr[i]) {
+ chip = stub_chips + i;
+ break;
+ }
+ }
+ if (!chip)
return -ENODEV;
switch (size) {
@@ -53,12 +70,12 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
case I2C_SMBUS_BYTE:
if (read_write == I2C_SMBUS_WRITE) {
- stub_pointer = command;
+ chip->pointer = command;
dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
"wrote 0x%02x.\n",
addr, command);
} else {
- data->byte = stub_bytes[stub_pointer++];
+ data->byte = chip->bytes[chip->pointer++];
dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
"read 0x%02x.\n",
addr, data->byte);
@@ -69,29 +86,29 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
case I2C_SMBUS_BYTE_DATA:
if (read_write == I2C_SMBUS_WRITE) {
- stub_bytes[command] = data->byte;
+ chip->bytes[command] = data->byte;
dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
"wrote 0x%02x at 0x%02x.\n",
addr, data->byte, command);
} else {
- data->byte = stub_bytes[command];
+ data->byte = chip->bytes[command];
dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
"read 0x%02x at 0x%02x.\n",
addr, data->byte, command);
}
- stub_pointer = command + 1;
+ chip->pointer = command + 1;
ret = 0;
break;
case I2C_SMBUS_WORD_DATA:
if (read_write == I2C_SMBUS_WRITE) {
- stub_words[command] = data->word;
+ chip->words[command] = data->word;
dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
"wrote 0x%04x at 0x%02x.\n",
addr, data->word, command);
} else {
- data->word = stub_words[command];
+ data->word = chip->words[command];
dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
"read 0x%04x at 0x%02x.\n",
addr, data->word, command);
@@ -129,23 +146,41 @@ static struct i2c_adapter stub_adapter = {
static int __init i2c_stub_init(void)
{
- if (!chip_addr) {
+ int i, ret;
+
+ if (!chip_addr[0]) {
printk(KERN_ERR "i2c-stub: Please specify a chip address\n");
return -ENODEV;
}
- if (chip_addr < 0x03 || chip_addr > 0x77) {
- printk(KERN_ERR "i2c-stub: Invalid chip address 0x%02x\n",
- chip_addr);
- return -EINVAL;
+
+ for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
+ if (chip_addr[i] < 0x03 || chip_addr[i] > 0x77) {
+ printk(KERN_ERR "i2c-stub: Invalid chip address "
+ "0x%02x\n", chip_addr[i]);
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n",
+ chip_addr[i]);
}
- printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", chip_addr);
- return i2c_add_adapter(&stub_adapter);
+ /* Allocate memory for all chips at once */
+ stub_chips = kzalloc(i * sizeof(struct stub_chip), GFP_KERNEL);
+ if (!stub_chips) {
+ printk(KERN_ERR "i2c-stub: Out of memory\n");
+ return -ENOMEM;
+ }
+
+ ret = i2c_add_adapter(&stub_adapter);
+ if (ret)
+ kfree(stub_chips);
+ return ret;
}
static void __exit i2c_stub_exit(void)
{
i2c_del_adapter(&stub_adapter);
+ kfree(stub_chips);
}
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
index 81520868797..61716f6b14d 100644
--- a/drivers/i2c/busses/i2c-via.c
+++ b/drivers/i2c/busses/i2c-via.c
@@ -4,7 +4,7 @@
i2c Support for Via Technologies 82C586B South Bridge
- Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
+ Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -176,7 +176,7 @@ static void __exit i2c_vt586b_exit(void)
}
-MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>");
+MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>");
MODULE_DESCRIPTION("i2c for Via vt82c586b southbridge");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index edc275002f8..c9ce77f13c0 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -2,7 +2,7 @@
i2c-viapro.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
- Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
Mark D. Studebaker <mdsxyz123@yahoo.com>
Copyright (C) 2005 - 2007 Jean Delvare <khali@linux-fr.org>
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
index d3da1fb05b9..1a7eeebac50 100644
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -128,13 +128,20 @@ static ssize_t eeprom_read(struct kobject *kobj, struct bin_attribute *bin_attr,
for (slice = off >> 5; slice <= (off + count - 1) >> 5; slice++)
eeprom_update_client(client, slice);
- /* Hide Vaio security settings to regular users (16 first bytes) */
- if (data->nature == VAIO && off < 16 && !capable(CAP_SYS_ADMIN)) {
- size_t in_row1 = 16 - off;
- in_row1 = min(in_row1, count);
- memset(buf, 0, in_row1);
- if (count - in_row1 > 0)
- memcpy(buf + in_row1, &data->data[16], count - in_row1);
+ /* Hide Vaio private settings to regular users:
+ - BIOS passwords: bytes 0x00 to 0x0f
+ - UUID: bytes 0x10 to 0x1f
+ - Serial number: 0xc0 to 0xdf */
+ if (data->nature == VAIO && !capable(CAP_SYS_ADMIN)) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if ((off + i <= 0x1f) ||
+ (off + i >= 0xc0 && off + i <= 0xdf))
+ buf[i] = 0;
+ else
+ buf[i] = data->data[off + i];
+ }
} else {
memcpy(buf, &data->data[off], count);
}
@@ -197,14 +204,18 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_kfree;
/* Detect the Vaio nature of EEPROMs.
- We use the "PCG-" prefix as the signature. */
+ We use the "PCG-" or "VGN-" prefix as the signature. */
if (address == 0x57) {
- if (i2c_smbus_read_byte_data(new_client, 0x80) == 'P'
- && i2c_smbus_read_byte(new_client) == 'C'
- && i2c_smbus_read_byte(new_client) == 'G'
- && i2c_smbus_read_byte(new_client) == '-') {
+ char name[4];
+
+ name[0] = i2c_smbus_read_byte_data(new_client, 0x80);
+ name[1] = i2c_smbus_read_byte(new_client);
+ name[2] = i2c_smbus_read_byte(new_client);
+ name[3] = i2c_smbus_read_byte(new_client);
+
+ if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) {
dev_info(&new_client->dev, "Vaio EEPROM detected, "
- "enabling password protection\n");
+ "enabling privacy protection\n");
data->nature = VAIO;
}
}
diff --git a/drivers/i2c/chips/menelaus.c b/drivers/i2c/chips/menelaus.c
index d9c92c5e007..2dea0123a95 100644
--- a/drivers/i2c/chips/menelaus.c
+++ b/drivers/i2c/chips/menelaus.c
@@ -49,8 +49,6 @@
#define DRIVER_NAME "menelaus"
-#define pr_err(fmt, arg...) printk(KERN_ERR DRIVER_NAME ": ", ## arg);
-
#define MENELAUS_I2C_ADDRESS 0x72
#define MENELAUS_REV 0x01
@@ -155,7 +153,7 @@ static int menelaus_write_reg(int reg, u8 value)
int val = i2c_smbus_write_byte_data(the_menelaus->client, reg, value);
if (val < 0) {
- pr_err("write error");
+ pr_err(DRIVER_NAME ": write error");
return val;
}
@@ -167,7 +165,7 @@ static int menelaus_read_reg(int reg)
int val = i2c_smbus_read_byte_data(the_menelaus->client, reg);
if (val < 0)
- pr_err("read error");
+ pr_err(DRIVER_NAME ": read error");
return val;
}
@@ -1177,7 +1175,7 @@ static int menelaus_probe(struct i2c_client *client)
/* If a true probe check the device */
rev = menelaus_read_reg(MENELAUS_REV);
if (rev < 0) {
- pr_err("device not found");
+ pr_err(DRIVER_NAME ": device not found");
err = -ENODEV;
goto fail1;
}
@@ -1197,7 +1195,7 @@ static int menelaus_probe(struct i2c_client *client)
err = request_irq(client->irq, menelaus_irq, IRQF_DISABLED,
DRIVER_NAME, menelaus);
if (err) {
- dev_dbg(&client->dev, "can't get IRQ %d, err %d",
+ dev_dbg(&client->dev, "can't get IRQ %d, err %d\n",
client->irq, err);
goto fail1;
}
@@ -1258,7 +1256,7 @@ static int __init menelaus_init(void)
res = i2c_add_driver(&menelaus_i2c_driver);
if (res < 0) {
- pr_err("driver registration failed\n");
+ pr_err(DRIVER_NAME ": driver registration failed\n");
return res;
}
diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c
index 32b25427eab..21c6dd69193 100644
--- a/drivers/i2c/chips/pcf8574.c
+++ b/drivers/i2c/chips/pcf8574.c
@@ -48,14 +48,11 @@ static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
/* Insmod parameters */
I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
-/* Initial values */
-#define PCF8574_INIT 255 /* All outputs on (input mode) */
-
/* Each client has this additional data */
struct pcf8574_data {
struct i2c_client client;
- u8 write; /* Remember last written value */
+ int write; /* Remember last written value */
};
static int pcf8574_attach_adapter(struct i2c_adapter *adapter);
@@ -85,7 +82,11 @@ static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
static ssize_t show_write(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pcf8574_data *data = i2c_get_clientdata(to_i2c_client(dev));
- return sprintf(buf, "%u\n", data->write);
+
+ if (data->write < 0)
+ return data->write;
+
+ return sprintf(buf, "%d\n", data->write);
}
static ssize_t set_write(struct device *dev, struct device_attribute *attr, const char *buf,
@@ -206,8 +207,7 @@ static int pcf8574_detach_client(struct i2c_client *client)
static void pcf8574_init_client(struct i2c_client *client)
{
struct pcf8574_data *data = i2c_get_clientdata(client);
- data->write = PCF8574_INIT;
- i2c_smbus_write_byte(client, data->write);
+ data->write = -EAGAIN;
}
static int __init pcf8574_init(void)
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index 503ffec2ce0..e320994b981 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -24,20 +24,13 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
-#include <linux/suspend.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/mutex.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-
-#include <asm/arch/gpio.h>
-#include <asm/arch/mux.h>
#include <asm/arch/tps65010.h>
/*-------------------------------------------------------------------------*/
@@ -48,10 +41,6 @@
MODULE_DESCRIPTION("TPS6501x Power Management Driver");
MODULE_LICENSE("GPL");
-static unsigned short normal_i2c[] = { 0x48, /* 0x49, */ I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
static struct i2c_driver tps65010_driver;
/*-------------------------------------------------------------------------*/
@@ -79,9 +68,8 @@ enum tps_model {
};
struct tps65010 {
- struct i2c_client client;
+ struct i2c_client *client;
struct mutex lock;
- int irq;
struct delayed_work work;
struct dentry *file;
unsigned charging:1;
@@ -229,22 +217,22 @@ static int dbg_show(struct seq_file *s, void *_)
/* registers for monitoring battery charging and status; note
* that reading chgstat and regstat may ack IRQs...
*/
- value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG);
dbg_chgconf(tps->por, buf, sizeof buf, value);
seq_printf(s, "chgconfig %s", buf);
- value = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_CHGSTATUS);
dbg_chgstat(buf, sizeof buf, value);
seq_printf(s, "chgstat %s", buf);
- value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK1);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_MASK1);
dbg_chgstat(buf, sizeof buf, value);
seq_printf(s, "mask1 %s", buf);
/* ignore ackint1 */
- value = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_REGSTATUS);
dbg_regstat(buf, sizeof buf, value);
seq_printf(s, "regstat %s", buf);
- value = i2c_smbus_read_byte_data(&tps->client, TPS_MASK2);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_MASK2);
dbg_regstat(buf, sizeof buf, value);
seq_printf(s, "mask2 %s\n", buf);
/* ignore ackint2 */
@@ -253,21 +241,21 @@ static int dbg_show(struct seq_file *s, void *_)
/* VMAIN voltage, enable lowpower, etc */
- value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC1);
seq_printf(s, "vdcdc1 %02x\n", value);
/* VCORE voltage, vibrator on/off */
- value = i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC2);
seq_printf(s, "vdcdc2 %02x\n", value);
/* both LD0s, and their lowpower behavior */
- value = i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_VREGS1);
seq_printf(s, "vregs1 %02x\n\n", value);
/* LEDs and GPIOs */
- value = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_ON);
- v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED1_PER);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_LED1_ON);
+ v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED1_PER);
seq_printf(s, "led1 %s, on=%02x, per=%02x, %d/%d msec\n",
(value & 0x80)
? ((v2 & 0x80) ? "on" : "off")
@@ -275,8 +263,8 @@ static int dbg_show(struct seq_file *s, void *_)
value, v2,
(value & 0x7f) * 10, (v2 & 0x7f) * 100);
- value = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_ON);
- v2 = i2c_smbus_read_byte_data(&tps->client, TPS_LED2_PER);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_LED2_ON);
+ v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED2_PER);
seq_printf(s, "led2 %s, on=%02x, per=%02x, %d/%d msec\n",
(value & 0x80)
? ((v2 & 0x80) ? "on" : "off")
@@ -284,8 +272,8 @@ static int dbg_show(struct seq_file *s, void *_)
value, v2,
(value & 0x7f) * 10, (v2 & 0x7f) * 100);
- value = i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO);
- v2 = i2c_smbus_read_byte_data(&tps->client, TPS_MASK3);
+ value = i2c_smbus_read_byte_data(tps->client, TPS_DEFGPIO);
+ v2 = i2c_smbus_read_byte_data(tps->client, TPS_MASK3);
seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2);
for (i = 0; i < 4; i++) {
@@ -335,7 +323,7 @@ static void tps65010_interrupt(struct tps65010 *tps)
/* regstatus irqs */
if (tps->nmask2) {
- tmp = i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS);
+ tmp = i2c_smbus_read_byte_data(tps->client, TPS_REGSTATUS);
mask = tmp ^ tps->regstatus;
tps->regstatus = tmp;
mask &= tps->nmask2;
@@ -362,7 +350,7 @@ static void tps65010_interrupt(struct tps65010 *tps)
/* chgstatus irqs */
if (tps->nmask1) {
- tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS);
+ tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGSTATUS);
mask = tmp ^ tps->chgstatus;
tps->chgstatus = tmp;
mask &= tps->nmask1;
@@ -426,7 +414,7 @@ static void tps65010_work(struct work_struct *work)
int status;
u8 chgconfig, tmp;
- chgconfig = i2c_smbus_read_byte_data(&tps->client,
+ chgconfig = i2c_smbus_read_byte_data(tps->client,
TPS_CHGCONFIG);
chgconfig &= ~(TPS_VBUS_500MA | TPS_VBUS_CHARGING);
if (tps->vbus == 500)
@@ -434,17 +422,17 @@ static void tps65010_work(struct work_struct *work)
else if (tps->vbus >= 100)
chgconfig |= TPS_VBUS_CHARGING;
- status = i2c_smbus_write_byte_data(&tps->client,
+ status = i2c_smbus_write_byte_data(tps->client,
TPS_CHGCONFIG, chgconfig);
/* vbus update fails unless VBUS is connected! */
- tmp = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG);
+ tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG);
tps->chgconf = tmp;
show_chgconfig(tps->por, "update vbus", tmp);
}
if (test_and_clear_bit(FLAG_IRQ_ENABLE, &tps->flags))
- enable_irq(tps->irq);
+ enable_irq(tps->client->irq);
mutex_unlock(&tps->lock);
}
@@ -463,114 +451,75 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
static struct tps65010 *the_tps;
-static int __exit tps65010_detach_client(struct i2c_client *client)
+static int __exit tps65010_remove(struct i2c_client *client)
{
- struct tps65010 *tps;
+ struct tps65010 *tps = i2c_get_clientdata(client);
- tps = container_of(client, struct tps65010, client);
- free_irq(tps->irq, tps);
-#ifdef CONFIG_ARM
- if (machine_is_omap_h2())
- omap_free_gpio(58);
- if (machine_is_omap_osk())
- omap_free_gpio(OMAP_MPUIO(1));
-#endif
+ if (client->irq > 0)
+ free_irq(client->irq, tps);
cancel_delayed_work(&tps->work);
flush_scheduled_work();
debugfs_remove(tps->file);
- if (i2c_detach_client(client) == 0)
- kfree(tps);
+ kfree(tps);
the_tps = NULL;
return 0;
}
-static int tps65010_noscan(struct i2c_adapter *bus)
-{
- /* pure paranoia, in case someone adds another i2c bus
- * after our init section's gone...
- */
- return -ENODEV;
-}
-
-/* no error returns, they'd just make bus scanning stop */
-static int __init
-tps65010_probe(struct i2c_adapter *bus, int address, int kind)
+static int tps65010_probe(struct i2c_client *client)
{
struct tps65010 *tps;
int status;
- unsigned long irqflags;
if (the_tps) {
- dev_dbg(&bus->dev, "only one %s for now\n", DRIVER_NAME);
- return 0;
+ dev_dbg(&client->dev, "only one tps6501x chip allowed\n");
+ return -ENODEV;
}
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EINVAL;
+
tps = kzalloc(sizeof *tps, GFP_KERNEL);
if (!tps)
- return 0;
+ return -ENOMEM;
mutex_init(&tps->lock);
INIT_DELAYED_WORK(&tps->work, tps65010_work);
- tps->irq = -1;
- tps->client.addr = address;
- tps->client.adapter = bus;
- tps->client.driver = &tps65010_driver;
- strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE);
-
- status = i2c_attach_client(&tps->client);
- if (status < 0) {
- dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
- DRIVER_NAME, address, status);
- goto fail1;
- }
+ tps->client = client;
- /* the IRQ is active low, but many gpio lines can't support that
- * so this driver can use falling-edge triggers instead.
- */
- irqflags = IRQF_SAMPLE_RANDOM;
-#ifdef CONFIG_ARM
- if (machine_is_omap_h2()) {
- tps->model = TPS65010;
- omap_cfg_reg(W4_GPIO58);
- tps->irq = OMAP_GPIO_IRQ(58);
- omap_request_gpio(58);
- omap_set_gpio_direction(58, 1);
- irqflags |= IRQF_TRIGGER_FALLING;
- }
- if (machine_is_omap_osk()) {
+ if (strcmp(client->name, "tps65010") == 0)
tps->model = TPS65010;
- // omap_cfg_reg(U19_1610_MPUIO1);
- tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1));
- omap_request_gpio(OMAP_MPUIO(1));
- omap_set_gpio_direction(OMAP_MPUIO(1), 1);
- irqflags |= IRQF_TRIGGER_FALLING;
- }
- if (machine_is_omap_h3()) {
+ else if (strcmp(client->name, "tps65011") == 0)
+ tps->model = TPS65011;
+ else if (strcmp(client->name, "tps65012") == 0)
+ tps->model = TPS65012;
+ else if (strcmp(client->name, "tps65013") == 0)
tps->model = TPS65013;
-
- // FIXME set up this board's IRQ ...
+ else {
+ dev_warn(&client->dev, "unknown chip '%s'\n", client->name);
+ status = -ENODEV;
+ goto fail1;
}
-#endif
- if (tps->irq > 0) {
- status = request_irq(tps->irq, tps65010_irq,
- irqflags, DRIVER_NAME, tps);
+ /* the IRQ is active low, but many gpio lines can't support that
+ * so this driver uses falling-edge triggers instead.
+ */
+ if (client->irq > 0) {
+ status = request_irq(client->irq, tps65010_irq,
+ IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_FALLING,
+ DRIVER_NAME, tps);
if (status < 0) {
- dev_dbg(&tps->client.dev, "can't get IRQ %d, err %d\n",
- tps->irq, status);
- i2c_detach_client(&tps->client);
+ dev_dbg(&client->dev, "can't get IRQ %d, err %d\n",
+ client->irq, status);
goto fail1;
}
-#ifdef CONFIG_ARM
/* annoying race here, ideally we'd have an option
* to claim the irq now and enable it later.
+ * FIXME genirq IRQF_NOAUTOEN now solves that ...
*/
- disable_irq(tps->irq);
+ disable_irq(client->irq);
set_bit(FLAG_IRQ_ENABLE, &tps->flags);
-#endif
} else
- printk(KERN_WARNING "%s: IRQ not configured!\n",
- DRIVER_NAME);
+ dev_warn(&client->dev, "IRQ not configured!\n");
switch (tps->model) {
@@ -583,23 +532,22 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
break;
/* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */
}
- tps->chgconf = i2c_smbus_read_byte_data(&tps->client, TPS_CHGCONFIG);
+ tps->chgconf = i2c_smbus_read_byte_data(client, TPS_CHGCONFIG);
show_chgconfig(tps->por, "conf/init", tps->chgconf);
show_chgstatus("chg/init",
- i2c_smbus_read_byte_data(&tps->client, TPS_CHGSTATUS));
+ i2c_smbus_read_byte_data(client, TPS_CHGSTATUS));
show_regstatus("reg/init",
- i2c_smbus_read_byte_data(&tps->client, TPS_REGSTATUS));
+ i2c_smbus_read_byte_data(client, TPS_REGSTATUS));
pr_debug("%s: vdcdc1 0x%02x, vdcdc2 %02x, vregs1 %02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC1),
- i2c_smbus_read_byte_data(&tps->client, TPS_VDCDC2),
- i2c_smbus_read_byte_data(&tps->client, TPS_VREGS1));
+ i2c_smbus_read_byte_data(client, TPS_VDCDC1),
+ i2c_smbus_read_byte_data(client, TPS_VDCDC2),
+ i2c_smbus_read_byte_data(client, TPS_VREGS1));
pr_debug("%s: defgpio 0x%02x, mask3 0x%02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&tps->client, TPS_DEFGPIO),
- i2c_smbus_read_byte_data(&tps->client, TPS_MASK3));
+ i2c_smbus_read_byte_data(client, TPS_DEFGPIO),
+ i2c_smbus_read_byte_data(client, TPS_MASK3));
- tps65010_driver.attach_adapter = tps65010_noscan;
the_tps = tps;
#if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG)
@@ -615,15 +563,15 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
* registers, and maybe disable VBUS draw.
*/
tps->nmask1 = ~0;
- (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK1, ~tps->nmask1);
+ (void) i2c_smbus_write_byte_data(client, TPS_MASK1, ~tps->nmask1);
tps->nmask2 = TPS_REG_ONOFF;
if (tps->model == TPS65013)
tps->nmask2 |= TPS_REG_NO_CHG;
- (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK2, ~tps->nmask2);
+ (void) i2c_smbus_write_byte_data(client, TPS_MASK2, ~tps->nmask2);
- (void) i2c_smbus_write_byte_data(&tps->client, TPS_MASK3, 0x0f
- | i2c_smbus_read_byte_data(&tps->client, TPS_MASK3));
+ (void) i2c_smbus_write_byte_data(client, TPS_MASK3, 0x0f
+ | i2c_smbus_read_byte_data(client, TPS_MASK3));
tps65010_work(&tps->work.work);
@@ -632,22 +580,15 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
return 0;
fail1:
kfree(tps);
- return 0;
-}
-
-static int __init tps65010_scan_bus(struct i2c_adapter *bus)
-{
- if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA))
- return -EINVAL;
- return i2c_probe(bus, &addr_data, tps65010_probe);
+ return status;
}
static struct i2c_driver tps65010_driver = {
.driver = {
.name = "tps65010",
},
- .attach_adapter = tps65010_scan_bus,
- .detach_client = __exit_p(tps65010_detach_client),
+ .probe = tps65010_probe,
+ .remove = __exit_p(tps65010_remove),
};
/*-------------------------------------------------------------------------*/
@@ -702,7 +643,7 @@ int tps65010_set_gpio_out_value(unsigned gpio, unsigned value)
mutex_lock(&the_tps->lock);
- defgpio = i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO);
+ defgpio = i2c_smbus_read_byte_data(the_tps->client, TPS_DEFGPIO);
/* Configure GPIO for output */
defgpio |= 1 << (gpio + 3);
@@ -718,12 +659,12 @@ int tps65010_set_gpio_out_value(unsigned gpio, unsigned value)
break;
}
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_DEFGPIO, defgpio);
pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME,
gpio, value ? "high" : "low",
- i2c_smbus_read_byte_data(&the_tps->client, TPS_DEFGPIO));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_DEFGPIO));
mutex_unlock(&the_tps->lock);
return status;
@@ -753,11 +694,11 @@ int tps65010_set_led(unsigned led, unsigned mode)
mutex_lock(&the_tps->lock);
pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led,
- i2c_smbus_read_byte_data(&the_tps->client,
+ i2c_smbus_read_byte_data(the_tps->client,
TPS_LED1_ON + offs));
pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led,
- i2c_smbus_read_byte_data(&the_tps->client,
+ i2c_smbus_read_byte_data(the_tps->client,
TPS_LED1_PER + offs));
switch (mode) {
@@ -780,7 +721,7 @@ int tps65010_set_led(unsigned led, unsigned mode)
return -EINVAL;
}
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_LED1_ON + offs, led_on);
if (status != 0) {
@@ -791,9 +732,9 @@ int tps65010_set_led(unsigned led, unsigned mode)
}
pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_LED1_ON + offs));
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_LED1_PER + offs, led_per);
if (status != 0) {
@@ -804,7 +745,7 @@ int tps65010_set_led(unsigned led, unsigned mode)
}
pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led,
- i2c_smbus_read_byte_data(&the_tps->client,
+ i2c_smbus_read_byte_data(the_tps->client,
TPS_LED1_PER + offs));
mutex_unlock(&the_tps->lock);
@@ -827,11 +768,11 @@ int tps65010_set_vib(unsigned value)
mutex_lock(&the_tps->lock);
- vdcdc2 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC2);
+ vdcdc2 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC2);
vdcdc2 &= ~(1 << 1);
if (value)
vdcdc2 |= (1 << 1);
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_VDCDC2, vdcdc2);
pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off");
@@ -857,9 +798,9 @@ int tps65010_set_low_pwr(unsigned mode)
pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME,
mode ? "enable" : "disable",
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1));
- vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1);
+ vdcdc1 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1);
switch (mode) {
case OFF:
@@ -871,7 +812,7 @@ int tps65010_set_low_pwr(unsigned mode)
break;
}
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_VDCDC1, vdcdc1);
if (status != 0)
@@ -879,7 +820,7 @@ int tps65010_set_low_pwr(unsigned mode)
DRIVER_NAME);
else
pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1));
mutex_unlock(&the_tps->lock);
@@ -902,9 +843,9 @@ int tps65010_config_vregs1(unsigned value)
mutex_lock(&the_tps->lock);
pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_VREGS1));
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_VREGS1, value);
if (status != 0)
@@ -912,7 +853,7 @@ int tps65010_config_vregs1(unsigned value)
DRIVER_NAME);
else
pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_VREGS1));
mutex_unlock(&the_tps->lock);
@@ -941,11 +882,11 @@ int tps65013_set_low_pwr(unsigned mode)
pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n",
DRIVER_NAME,
mode ? "enable" : "disable",
- i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG),
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG),
+ i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1));
- chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG);
- vdcdc1 = i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1);
+ chgconfig = i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG);
+ vdcdc1 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1);
switch (mode) {
case OFF:
@@ -959,7 +900,7 @@ int tps65013_set_low_pwr(unsigned mode)
break;
}
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_CHGCONFIG, chgconfig);
if (status != 0) {
printk(KERN_ERR "%s: Failed to write chconfig register\n",
@@ -968,11 +909,11 @@ int tps65013_set_low_pwr(unsigned mode)
return status;
}
- chgconfig = i2c_smbus_read_byte_data(&the_tps->client, TPS_CHGCONFIG);
+ chgconfig = i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG);
the_tps->chgconf = chgconfig;
show_chgconfig(0, "chgconf", chgconfig);
- status = i2c_smbus_write_byte_data(&the_tps->client,
+ status = i2c_smbus_write_byte_data(the_tps->client,
TPS_VDCDC1, vdcdc1);
if (status != 0)
@@ -980,7 +921,7 @@ int tps65013_set_low_pwr(unsigned mode)
DRIVER_NAME);
else
pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
+ i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1));
mutex_unlock(&the_tps->lock);
@@ -1011,52 +952,6 @@ static int __init tps_init(void)
msleep(10);
}
-#ifdef CONFIG_ARM
- if (machine_is_omap_osk()) {
-
- // FIXME: More should be placed in the initialization code
- // of the submodules (DSP, ethernet, power management,
- // board-osk.c). Careful: I2C is initialized "late".
-
- /* Let LED1 (D9) blink */
- tps65010_set_led(LED1, BLINK);
-
- /* Disable LED 2 (D2) */
- tps65010_set_led(LED2, OFF);
-
- /* Set GPIO 1 HIGH to disable VBUS power supply;
- * OHCI driver powers it up/down as needed.
- */
- tps65010_set_gpio_out_value(GPIO1, HIGH);
-
- /* Set GPIO 2 low to turn on LED D3 */
- tps65010_set_gpio_out_value(GPIO2, HIGH);
-
- /* Set GPIO 3 low to take ethernet out of reset */
- tps65010_set_gpio_out_value(GPIO3, LOW);
-
- /* gpio4 for VDD_DSP */
-
- /* Enable LOW_PWR */
- tps65010_set_low_pwr(ON);
-
- /* Switch VLDO2 to 3.0V for AIC23 */
- tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V | TPS_LDO1_ENABLE);
-
- } else if (machine_is_omap_h2()) {
- /* gpio3 for SD, gpio4 for VDD_DSP */
-
- /* Enable LOW_PWR */
- tps65010_set_low_pwr(ON);
- } else if (machine_is_omap_h3()) {
- /* gpio4 for SD, gpio3 for VDD_DSP */
-#ifdef CONFIG_PM
- /* Enable LOW_PWR */
- tps65013_set_low_pwr(ON);
-#endif
- }
-#endif
-
return status;
}
/* NOTE: this MUST be initialized before the other parts of the system
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index d663e6960d9..b5e13e405e7 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -17,7 +17,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and
Jean Delvare <khali@linux-fr.org> */
@@ -67,20 +67,16 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv)
#ifdef CONFIG_HOTPLUG
/* uevent helps with hotplug: modprobe -q $(MODALIAS) */
-static int i2c_device_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct i2c_client *client = to_i2c_client(dev);
- int i = 0, length = 0;
/* by definition, legacy drivers can't hotplug */
if (dev->driver || !client->driver_name)
return 0;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MODALIAS=%s", client->driver_name))
+ if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))
return -ENOMEM;
- envp[i] = NULL;
dev_dbg(dev, "uevent\n");
return 0;
}
@@ -190,7 +186,7 @@ static struct device_attribute i2c_dev_attrs[] = {
{ },
};
-struct bus_type i2c_bus_type = {
+static struct bus_type i2c_bus_type = {
.name = "i2c",
.dev_attrs = i2c_dev_attrs,
.match = i2c_device_match,
@@ -201,7 +197,6 @@ struct bus_type i2c_bus_type = {
.suspend = i2c_device_suspend,
.resume = i2c_device_resume,
};
-EXPORT_SYMBOL_GPL(i2c_bus_type);
/**
* i2c_new_device - instantiate an i2c device for use with a new style driver
@@ -230,7 +225,9 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
client->adapter = adap;
client->dev.platform_data = info->platform_data;
- client->flags = info->flags;
+ device_init_wakeup(&client->dev, info->flags & I2C_CLIENT_WAKE);
+
+ client->flags = info->flags & ~I2C_CLIENT_WAKE;
client->addr = info->addr;
client->irq = info->irq;
@@ -283,7 +280,7 @@ EXPORT_SYMBOL_GPL(i2c_unregister_device);
/* I2C bus adapters -- one roots each I2C or SMBUS segment */
-void i2c_adapter_dev_release(struct device *dev)
+static void i2c_adapter_dev_release(struct device *dev)
{
struct i2c_adapter *adap = to_i2c_adapter(dev);
complete(&adap->dev_released);
@@ -301,7 +298,7 @@ static struct device_attribute i2c_adapter_attrs[] = {
{ },
};
-struct class i2c_adapter_class = {
+static struct class i2c_adapter_class = {
.owner = THIS_MODULE,
.name = "i2c-adapter",
.dev_attrs = i2c_adapter_attrs,
@@ -676,7 +673,7 @@ static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
return 0;
}
-int i2c_check_addr(struct i2c_adapter *adapter, int addr)
+static int i2c_check_addr(struct i2c_adapter *adapter, int addr)
{
int rval;
@@ -686,7 +683,6 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr)
return rval;
}
-EXPORT_SYMBOL(i2c_check_addr);
int i2c_attach_client(struct i2c_client *client)
{
@@ -934,28 +930,6 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
}
EXPORT_SYMBOL(i2c_master_recv);
-int i2c_control(struct i2c_client *client,
- unsigned int cmd, unsigned long arg)
-{
- int ret = 0;
- struct i2c_adapter *adap = client->adapter;
-
- dev_dbg(&client->adapter->dev, "i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg);
- switch (cmd) {
- case I2C_RETRIES:
- adap->retries = arg;
- break;
- case I2C_TIMEOUT:
- adap->timeout = arg;
- break;
- default:
- if (adap->algo->algo_control!=NULL)
- ret = adap->algo->algo_control(adap,cmd,arg);
- }
- return ret;
-}
-EXPORT_SYMBOL(i2c_control);
-
/* ----------------------------------------------------
* the i2c address scanning function
* Will not work for 10-bit addresses!
@@ -1310,7 +1284,22 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
}
EXPORT_SYMBOL(i2c_smbus_write_word_data);
-/* Returns the number of read bytes */
+/**
+ * i2c_smbus_read_block_data - SMBus block read request
+ * @client: Handle to slave device
+ * @command: Command byte issued to let the slave know what data should
+ * be returned
+ * @values: Byte array into which data will be read; big enough to hold
+ * the data returned by the slave. SMBus allows at most 32 bytes.
+ *
+ * Returns the number of bytes read in the slave's response, else a
+ * negative number to indicate some kind of error.
+ *
+ * Note that using this function requires that the client's adapter support
+ * the I2C_FUNC_SMBUS_READ_BLOCK_DATA functionality. Not all adapter drivers
+ * 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,
u8 *values)
{
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 64eee9551b2..c21ae20ae36 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -38,6 +38,15 @@
static struct i2c_driver i2cdev_driver;
+/*
+ * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a
+ * slave (i2c_client) with which messages will be exchanged. It's coupled
+ * with a character special file which is accessed by user mode drivers.
+ *
+ * The list of i2c_dev structures is parallel to the i2c_adapter lists
+ * maintained by the driver model, and is updated using notifications
+ * delivered to the i2cdev_driver.
+ */
struct i2c_dev {
struct list_head list;
struct i2c_adapter *adap;
@@ -103,6 +112,25 @@ static ssize_t show_adapter_name(struct device *dev,
}
static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
+/* ------------------------------------------------------------------------- */
+
+/*
+ * After opening an instance of this character special file, a file
+ * descriptor starts out associated only with an i2c_adapter (and bus).
+ *
+ * Using the I2C_RDWR ioctl(), you can then *immediately* issue i2c_msg
+ * traffic to any devices on the bus used by that adapter. That's because
+ * the i2c_msg vectors embed all the addressing information they need, and
+ * are submitted directly to an i2c_adapter. However, SMBus-only adapters
+ * don't support that interface.
+ *
+ * To use read()/write() system calls on that file descriptor, or to use
+ * SMBus interfaces (and work with SMBus-only hosts!), you must first issue
+ * an I2C_SLAVE (or I2C_SLAVE_FORCE) ioctl. That configures an anonymous
+ * (never registered) i2c_client so it holds the addressing information
+ * needed by those system calls and by this SMBus interface.
+ */
+
static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count,
loff_t *offset)
{
@@ -154,6 +182,29 @@ static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t c
return ret;
}
+/* This address checking function differs from the one in i2c-core
+ in that it considers an address with a registered device, but no
+ bounded driver, as NOT busy. */
+static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
+{
+ struct list_head *item;
+ struct i2c_client *client;
+ int res = 0;
+
+ mutex_lock(&adapter->clist_lock);
+ list_for_each(item, &adapter->clients) {
+ client = list_entry(item, struct i2c_client, list);
+ if (client->addr == addr) {
+ if (client->driver)
+ res = -EBUSY;
+ break;
+ }
+ }
+ mutex_unlock(&adapter->clist_lock);
+
+ return res;
+}
+
static int i2cdev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
@@ -172,11 +223,22 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
switch ( cmd ) {
case I2C_SLAVE:
case I2C_SLAVE_FORCE:
+ /* NOTE: devices set up to work with "new style" drivers
+ * can't use I2C_SLAVE, even when the device node is not
+ * bound to a driver. Only I2C_SLAVE_FORCE will work.
+ *
+ * Setting the PEC flag here won't affect kernel drivers,
+ * which will be using the i2c_client node registered with
+ * the driver model core. Likewise, when that client has
+ * the PEC flag already set, the i2c-dev driver won't see
+ * (or use) this setting.
+ */
if ((arg > 0x3ff) ||
(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
return -EINVAL;
- if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
+ if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
return -EBUSY;
+ /* REVISIT: address could become busy later */
client->addr = arg;
return 0;
case I2C_TENBIT:
@@ -226,8 +288,10 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
res = 0;
for( i=0; i<rdwr_arg.nmsgs; i++ ) {
- /* Limit the size of the message to a sane amount */
- if (rdwr_pa[i].len > 8192) {
+ /* Limit the size of the message to a sane amount;
+ * and don't let length change either. */
+ if ((rdwr_pa[i].len > 8192) ||
+ (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
res = -EINVAL;
break;
}
@@ -352,9 +416,19 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
}
return res;
-
+ case I2C_RETRIES:
+ client->adapter->retries = arg;
+ break;
+ case I2C_TIMEOUT:
+ client->adapter->timeout = arg;
+ break;
default:
- return i2c_control(client,cmd,arg);
+ /* NOTE: returning a fault code here could cause trouble
+ * in buggy userspace code. Some old kernel bugs returned
+ * zero in this case, and userspace code might accidentally
+ * have depended on that bug.
+ */
+ return -ENOTTY;
}
return 0;
}
@@ -374,6 +448,13 @@ static int i2cdev_open(struct inode *inode, struct file *file)
if (!adap)
return -ENODEV;
+ /* This creates an anonymous i2c_client, which may later be
+ * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
+ *
+ * This client is ** NEVER REGISTERED ** with the driver model
+ * or I2C core code!! It just holds private copies of addressing
+ * information and maybe a PEC flag.
+ */
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
@@ -382,7 +463,6 @@ static int i2cdev_open(struct inode *inode, struct file *file)
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
client->driver = &i2cdev_driver;
- /* registered with adapter, passed as client to user */
client->adapter = adap;
file->private_data = client;
@@ -410,6 +490,14 @@ static const struct file_operations i2cdev_fops = {
.release = i2cdev_release,
};
+/* ------------------------------------------------------------------------- */
+
+/*
+ * The legacy "i2cdev_driver" is used primarily to get notifications when
+ * I2C adapters are added or removed, so that each one gets an i2c_dev
+ * and is thus made available to userspace driver code.
+ */
+
static struct class *i2c_dev_class;
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
@@ -474,6 +562,12 @@ static struct i2c_driver i2cdev_driver = {
.detach_client = i2cdev_detach_client,
};
+/* ------------------------------------------------------------------------- */
+
+/*
+ * module load/unload record keeping
+ */
+
static int __init i2c_dev_init(void)
{
int res;
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 4200251ff63..e445fe6e4ba 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -152,9 +152,22 @@ config BLK_DEV_IDEDISK
If unsure, say Y.
config IDEDISK_MULTI_MODE
- bool "Use multi-mode by default"
- help
- If you get this error, try to say Y here:
+ bool "Use multiple sector mode for Programmed Input/Output by default"
+ help
+ This setting is irrelevant for most IDE disks, with direct memory
+ access, to which multiple sector mode does not apply. Multiple sector
+ mode is a feature of most modern IDE hard drives, permitting the
+ transfer of multiple sectors per Programmed Input/Output interrupt,
+ rather than the usual one sector per interrupt. When this feature is
+ enabled, it can reduce operating system overhead for disk Programmed
+ Input/Output. On some systems, it also can increase the data
+ throughput of Programmed Input/Output. Some drives, however, seemed
+ to run slower with multiple sector mode enabled. Some drives claimed
+ to support multiple sector mode, but lost data at some settings.
+ Under rare circumstances, such failures could result in massive
+ filesystem corruption.
+
+ If you get the following error, try to say Y here:
hda: set_multmode: status=0x51 { DriveReady SeekComplete Error }
hda: set_multmode: error=0x04 { DriveStatusError }
@@ -190,10 +203,6 @@ config BLK_DEV_IDECD
CD-ROM drive, you can say N to all other CD-ROM options, but be sure
to say Y or M to "ISO 9660 CD-ROM file system support".
- Note that older versions of LILO (LInux LOader) cannot properly deal
- with IDE/ATAPI CD-ROMs, so install LILO 16 or higher, available from
- <http://lilo.go.dyndns.org/>.
-
To compile this driver as a module, choose M here: the
module will be called ide-cd.
@@ -308,6 +317,14 @@ config IDE_GENERIC
help
If unsure, say N.
+config BLK_DEV_PLATFORM
+ tristate "Platform driver for IDE interfaces"
+ help
+ This is the platform IDE driver, used mostly for Memory Mapped
+ IDE devices, like Compact Flashes running in True IDE mode.
+
+ If unsure, say N.
+
config BLK_DEV_CMD640
bool "CMD640 chipset bugfix/support"
depends on X86
@@ -351,17 +368,16 @@ config BLK_DEV_IDEPNP
would like the kernel to automatically detect and activate
it, say Y here.
+if PCI
+
+comment "PCI IDE chipsets support"
+
config BLK_DEV_IDEPCI
- bool "PCI IDE chipset support" if PCI
- default BLK_DEV_IDEDMA_PMAC if PPC_PMAC && BLK_DEV_IDEDMA_PMAC
- help
- Say Y here for PCI systems which use IDE drive(s).
- This option helps the IDE driver to automatically detect and
- configure all PCI-based IDE interfaces in your system.
+ bool
config IDEPCI_SHARE_IRQ
bool "Sharing PCI IDE interrupts support"
- depends on PCI && BLK_DEV_IDEPCI
+ depends on BLK_DEV_IDEPCI
help
Some ATA/IDE chipsets have hardware support which allows for
sharing a single IRQ with other cards. To enable support for
@@ -371,11 +387,12 @@ config IDEPCI_SHARE_IRQ
If unsure, say N.
config IDEPCI_PCIBUS_ORDER
- def_bool PCI && BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+ def_bool BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+# TODO: split it on per host driver config options (or module parameters)
config BLK_DEV_OFFBOARD
bool "Boot off-board chipsets first support"
- depends on PCI && BLK_DEV_IDEPCI
+ depends on BLK_DEV_IDEPCI && (BLK_DEV_AEC62XX || BLK_DEV_GENERIC || BLK_DEV_HPT34X || BLK_DEV_HPT366 || BLK_DEV_PDC202XX_NEW || BLK_DEV_PDC202XX_OLD || BLK_DEV_TC86C001)
help
Normally, IDE controllers built into the motherboard (on-board
controllers) are assigned to ide0 and ide1 while those on add-in PCI
@@ -398,21 +415,23 @@ config BLK_DEV_OFFBOARD
config BLK_DEV_GENERIC
tristate "Generic PCI IDE Chipset Support"
- depends on BLK_DEV_IDEPCI
+ select BLK_DEV_IDEPCI
help
This option provides generic support for various PCI IDE Chipsets
which otherwise might not be supported.
config BLK_DEV_OPTI621
tristate "OPTi 82C621 chipset enhanced support (EXPERIMENTAL)"
- depends on PCI && BLK_DEV_IDEPCI && EXPERIMENTAL
+ depends on EXPERIMENTAL
+ select BLK_DEV_IDEPCI
help
This is a driver for the OPTi 82C621 EIDE controller.
Please read the comments at the top of <file:drivers/ide/pci/opti621.c>.
config BLK_DEV_RZ1000
tristate "RZ1000 chipset bugfix/support"
- depends on PCI && BLK_DEV_IDEPCI && X86
+ depends on X86
+ select BLK_DEV_IDEPCI
help
The PC-Technologies RZ1000 IDE chip is used on many common 486 and
Pentium motherboards, usually along with the "Neptune" chipset.
@@ -423,43 +442,12 @@ config BLK_DEV_RZ1000
things will operate 100% reliably.
config BLK_DEV_IDEDMA_PCI
- bool "Generic PCI bus-master DMA support"
- depends on PCI && BLK_DEV_IDEPCI
- ---help---
- If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and
- is capable of bus-master DMA operation (most Pentium PCI systems),
- you will want to say Y here to reduce CPU overhead. You can then use
- the "hdparm" utility to enable DMA for drives for which it was not
- enabled automatically. By default, DMA is not enabled automatically
- for these drives, but you can change that by saying Y to the
- following question "Use DMA by default when available". You can get
- the latest version of the hdparm utility from
- <ftp://ibiblio.org/pub/Linux/system/hardware/>.
-
- Read the comments at the beginning of <file:drivers/ide/ide-dma.c>
- and the file <file:Documentation/ide.txt> for more information.
-
- It is safe to say Y to this question.
-
-if BLK_DEV_IDEDMA_PCI
-
-config BLK_DEV_IDEDMA_FORCED
- bool "Force enable legacy 2.0.X HOSTS to use DMA"
- help
- This is an old piece of lost code from Linux 2.0 Kernels.
-
- Generally say N here.
-
-config IDEDMA_ONLYDISK
- bool "Enable DMA only for disks "
- help
- This is used if you know your ATAPI Devices are going to fail DMA
- Transfers.
-
- Generally say N here.
+ bool
+ select BLK_DEV_IDEPCI
config BLK_DEV_AEC62XX
tristate "AEC62XX chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds explicit support for Acard AEC62xx (Artop ATP8xx)
IDE controllers. This allows the kernel to change PIO, DMA and UDMA
@@ -467,6 +455,7 @@ config BLK_DEV_AEC62XX
config BLK_DEV_ALI15X3
tristate "ALI M15x3 chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
onboard chipsets. It also tests for Simplex mode and enables
@@ -495,6 +484,7 @@ config WDC_ALI15X3
config BLK_DEV_AMD74XX
tristate "AMD and nVidia IDE support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds explicit support for AMD-7xx and AMD-8111 chips
and also for the nVidia nForce chip. This allows the kernel to
@@ -504,6 +494,7 @@ config BLK_DEV_AMD74XX
config BLK_DEV_ATIIXP
tristate "ATI IXP chipset IDE support"
depends on X86
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds explicit support for ATI IXP chipset.
This allows the kernel to change PIO, DMA and UDMA speeds
@@ -513,18 +504,21 @@ config BLK_DEV_ATIIXP
config BLK_DEV_CMD64X
tristate "CMD64{3|6|8|9} chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
Say Y here if you have an IDE controller which uses any of these
chipsets: CMD643, CMD646, or CMD648.
config BLK_DEV_TRIFLEX
tristate "Compaq Triflex IDE support"
+ select BLK_DEV_IDEDMA_PCI
help
Say Y here if you have a Compaq Triflex IDE controller, such
as those commonly found on Compaq Pentium-Pro systems
config BLK_DEV_CY82C693
tristate "CY82C693 chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds detection and support for the CY82C693 chipset
used on Digital's PC-Alpha 164SX boards.
@@ -535,6 +529,7 @@ config BLK_DEV_CY82C693
config BLK_DEV_CS5520
tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)"
depends on EXPERIMENTAL
+ select BLK_DEV_IDEDMA_PCI
help
Include support for PIO tuning and virtual DMA on the Cyrix MediaGX
5510/5520 chipset. This will automatically be detected and
@@ -544,6 +539,7 @@ config BLK_DEV_CS5520
config BLK_DEV_CS5530
tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
Include support for UDMA on the Cyrix MediaGX 5530 chipset. This
will automatically be detected and configured if found.
@@ -553,6 +549,7 @@ config BLK_DEV_CS5530
config BLK_DEV_CS5535
tristate "AMD CS5535 chipset support"
depends on X86 && !X86_64
+ select BLK_DEV_IDEDMA_PCI
help
Include support for UDMA on the NSC/AMD CS5535 companion chipset.
This will automatically be detected and configured if found.
@@ -561,6 +558,7 @@ config BLK_DEV_CS5535
config BLK_DEV_HPT34X
tristate "HPT34X chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds up to 4 more EIDE devices sharing a single
interrupt. The HPT343 chipset in its current form is a non-bootable
@@ -581,7 +579,8 @@ config HPT34X_AUTODMA
config BLK_DEV_HPT366
tristate "HPT36X/37X chipset support"
- ---help---
+ select BLK_DEV_IDEDMA_PCI
+ help
HPT366 is an Ultra DMA chipset for ATA-66.
HPT368 is an Ultra DMA chipset for ATA-66 RAID Based.
HPT370 is an Ultra DMA chipset for ATA-100.
@@ -605,18 +604,21 @@ config BLK_DEV_HPT366
config BLK_DEV_JMICRON
tristate "JMicron JMB36x support"
+ select BLK_DEV_IDEDMA_PCI
help
Basic support for the JMicron ATA controllers. For full support
use the libata drivers.
config BLK_DEV_SC1200
tristate "National SCx200 chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds support for the built in IDE on the National
SCx200 series of embedded x86 "Geode" systems
config BLK_DEV_PIIX
tristate "Intel PIIXn chipsets support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds explicit support for Intel PIIX and ICH chips
and also for the Efar Victory66 (slc90e66) chip. This allows
@@ -625,17 +627,20 @@ config BLK_DEV_PIIX
config BLK_DEV_IT8213
tristate "IT8213 IDE support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds support for the ITE 8213 IDE controller.
config BLK_DEV_IT821X
tristate "IT821X IDE support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds support for the ITE 8211 IDE controller and the
IT 8212 IDE RAID controller in both RAID and pass-through mode.
config BLK_DEV_NS87415
tristate "NS87415 chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds detection and support for the NS87415 chip
(used mainly on SPARC64 and PA-RISC machines).
@@ -644,6 +649,7 @@ config BLK_DEV_NS87415
config BLK_DEV_PDC202XX_OLD
tristate "PROMISE PDC202{46|62|65|67} support"
+ select BLK_DEV_IDEDMA_PCI
help
Promise Ultra33 or PDC20246
Promise Ultra66 or PDC20262
@@ -685,9 +691,11 @@ config PDC202XX_BURST
config BLK_DEV_PDC202XX_NEW
tristate "PROMISE PDC202{68|69|70|71|75|76|77} support"
+ select BLK_DEV_IDEDMA_PCI
config BLK_DEV_SVWKS
tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5
chipsets.
@@ -696,6 +704,7 @@ config BLK_DEV_SGIIOC4
tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
select IDEPCI_SHARE_IRQ
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
chipset, which has one channel and can support two devices.
@@ -703,6 +712,7 @@ config BLK_DEV_SGIIOC4
config BLK_DEV_SIIMAGE
tristate "Silicon Image chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds PIO/(U)DMA support for the SI CMD680 and SII
3112 (Serial ATA) chips.
@@ -710,7 +720,8 @@ config BLK_DEV_SIIMAGE
config BLK_DEV_SIS5513
tristate "SiS5513 chipset support"
depends on X86
- ---help---
+ select BLK_DEV_IDEDMA_PCI
+ help
This driver ensures (U)DMA support for SIS5513 chipset family based
mainboards.
@@ -729,6 +740,7 @@ config BLK_DEV_SIS5513
config BLK_DEV_SL82C105
tristate "Winbond SL82c105 support"
depends on (PPC || ARM)
+ select BLK_DEV_IDEDMA_PCI
help
If you have a Winbond SL82c105 IDE controller, say Y here to enable
special configuration for this chip. This is common on various CHRP
@@ -736,6 +748,7 @@ config BLK_DEV_SL82C105
config BLK_DEV_SLC90E66
tristate "SLC90E66 chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver ensures (U)DMA support for Victory66 SouthBridges for
SMsC with Intel NorthBridges. This is an Ultra66 based chipset.
@@ -751,6 +764,7 @@ config BLK_DEV_SLC90E66
config BLK_DEV_TRM290
tristate "Tekram TRM290 chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds support for bus master DMA transfers
using the Tekram TRM290 PCI IDE chip. Volunteers are
@@ -759,6 +773,7 @@ config BLK_DEV_TRM290
config BLK_DEV_VIA82CXXX
tristate "VIA82CXXX chipset support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds explicit support for VIA BusMastering IDE chips.
This allows the kernel to change PIO, DMA and UDMA speeds and to
@@ -766,12 +781,14 @@ config BLK_DEV_VIA82CXXX
config BLK_DEV_TC86C001
tristate "Toshiba TC86C001 support"
+ select BLK_DEV_IDEDMA_PCI
help
This driver adds support for Toshiba TC86C001 GOKU-S chip.
config BLK_DEV_CELLEB
tristate "Toshiba's Cell Reference Set IDE support"
depends on PPC_CELLEB
+ select BLK_DEV_IDEDMA_PCI
help
This driver provides support for the built-in IDE controller on
Toshiba Cell Reference Board.
@@ -985,24 +1002,9 @@ config IDE_EXT_DIRECT
endchoice
# no isa -> no vlb
-config IDE_CHIPSETS
- bool "Other IDE chipset support"
- depends on ISA
- ---help---
- Say Y here if you want to include enhanced support for various IDE
- interface chipsets used on motherboards and add-on cards. You can
- then pick your particular IDE chip from among the following options.
- This enhanced support may be necessary for Linux to be able to
- access the 3rd/4th drives in some systems. It may also enable
- setting of higher speed I/O rates to improve system performance with
- these chipsets. Most of these also require special kernel boot
- parameters to actually turn on the support at runtime; you can find
- a list of these in the file <file:Documentation/ide.txt>.
-
- People with SCSI-only systems can say N here.
-
-if IDE_CHIPSETS
+if ISA
+comment "Other IDE chipsets support"
comment "Note: most of these also require special kernel boot parameters"
config BLK_DEV_4DRIVES
@@ -1064,21 +1066,8 @@ endif
config BLK_DEV_IDEDMA
def_bool BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-config IDEDMA_IVB
- bool "IGNORE word93 Validation BITS"
- depends on BLK_DEV_IDEDMA_PCI || BLK_DEV_IDEDMA_PMAC || BLK_DEV_IDEDMA_ICS
- ---help---
- There are unclear terms in ATA-4 and ATA-5 standards how certain
- hardware (an 80c ribbon) should be detected. Different interpretations
- of the standards have been released in hardware. This causes problems:
- for example, a host with Ultra Mode 4 (or higher) will not run
- in that mode with an 80c ribbon.
-
- If you are experiencing compatibility or performance problems, you
- MAY try to answer Y here. However, it does not necessarily solve
- any of your problems, it could even cause more of them.
-
- It is normally safe to answer Y; however, the default is N.
+config IDE_ARCH_OBSOLETE_INIT
+ def_bool ALPHA || (ARM && !ARCH_L7200) || BLACKFIN || X86 || IA64 || M32R || MIPS || PARISC || PPC || (SUPERH64 && BLK_DEV_IDEPCI) || SPARC
endif
diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c
index f7449d04114..48db6167bb9 100644
--- a/drivers/ide/arm/bast-ide.c
+++ b/drivers/ide/arm/bast-ide.c
@@ -45,7 +45,7 @@ bastide_register(unsigned int base, unsigned int aux, int irq,
hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20);
hw.irq = irq;
- ide_register_hw(&hw, 0, hwif);
+ ide_register_hw(&hw, NULL, 0, hwif);
return 0;
}
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index 8a9b98fcb66..93f71fcfc04 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -248,15 +248,9 @@ static void icside_build_sglist(ide_drive_t *drive, struct request *rq)
* MW1 80 50 50 150 C
* MW2 70 25 25 120 C
*/
-static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode)
+static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode)
{
- int on = 0, cycle_time = 0, use_dma_info = 0;
-
- /*
- * Limit the transfer speed to MW_DMA_2.
- */
- if (xfer_mode > XFER_MW_DMA_2)
- xfer_mode = XFER_MW_DMA_2;
+ int cycle_time, use_dma_info = 0;
switch (xfer_mode) {
case XFER_MW_DMA_2:
@@ -278,6 +272,8 @@ static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode)
case XFER_SW_DMA_0:
cycle_time = 480;
break;
+ default:
+ return;
}
/*
@@ -289,17 +285,8 @@ static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode)
drive->drive_data = cycle_time;
- if (cycle_time && ide_config_drive_speed(drive, xfer_mode) == 0)
- on = 1;
- else
- drive->drive_data = 480;
-
printk("%s: %s selected (peak %dMB/s)\n", drive->name,
ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
-
- drive->current_speed = xfer_mode;
-
- return on;
}
static void icside_dma_host_off(ide_drive_t *drive)
@@ -322,45 +309,6 @@ static int icside_dma_on(ide_drive_t *drive)
return 0;
}
-static int icside_dma_check(ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
- int xfer_mode = XFER_PIO_2;
- int on;
-
- if (!(id->capability & 1) || !hwif->autodma)
- goto out;
-
- /*
- * Consult the list of known "bad" drives
- */
- if (__ide_dma_bad_drive(drive))
- goto out;
-
- /*
- * Enable DMA on any drive that has multiword DMA
- */
- if (id->field_valid & 2) {
- xfer_mode = ide_max_dma_mode(drive);
- goto out;
- }
-
- /*
- * Consult the list of known "good" drives
- */
- if (__ide_dma_good_drive(drive)) {
- if (id->eide_dma_time > 150)
- goto out;
- xfer_mode = XFER_MW_DMA_1;
- }
-
-out:
- on = icside_set_speed(drive, xfer_mode);
-
- return on ? 0 : -1;
-}
-
static int icside_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
@@ -368,27 +316,29 @@ static int icside_dma_end(ide_drive_t *drive)
drive->waiting_for_dma = 0;
- disable_dma(hwif->hw.dma);
+ disable_dma(ECARD_DEV(state->dev)->dma);
/* Teardown mappings after DMA has completed. */
dma_unmap_sg(state->dev, hwif->sg_table, hwif->sg_nents,
hwif->sg_dma_direction);
- return get_dma_residue(hwif->hw.dma) != 0;
+ return get_dma_residue(ECARD_DEV(state->dev)->dma) != 0;
}
static void icside_dma_start(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
+ struct icside_state *state = hwif->hwif_data;
/* We can not enable DMA on both channels simultaneously. */
- BUG_ON(dma_channel_active(hwif->hw.dma));
- enable_dma(hwif->hw.dma);
+ BUG_ON(dma_channel_active(ECARD_DEV(state->dev)->dma));
+ enable_dma(ECARD_DEV(state->dev)->dma);
}
static int icside_dma_setup(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
+ struct icside_state *state = hwif->hwif_data;
struct request *rq = hwif->hwgroup->rq;
unsigned int dma_mode;
@@ -400,7 +350,7 @@ static int icside_dma_setup(ide_drive_t *drive)
/*
* We can not enable DMA on both channels.
*/
- BUG_ON(dma_channel_active(hwif->hw.dma));
+ BUG_ON(dma_channel_active(ECARD_DEV(state->dev)->dma));
icside_build_sglist(drive, rq);
@@ -417,14 +367,14 @@ static int icside_dma_setup(ide_drive_t *drive)
/*
* Select the correct timing for this drive.
*/
- set_dma_speed(hwif->hw.dma, drive->drive_data);
+ set_dma_speed(ECARD_DEV(state->dev)->dma, drive->drive_data);
/*
* Tell the DMA engine about the SG table and
* data direction.
*/
- set_dma_sg(hwif->hw.dma, hwif->sg_table, hwif->sg_nents);
- set_dma_mode(hwif->hw.dma, dma_mode);
+ set_dma_sg(ECARD_DEV(state->dev)->dma, hwif->sg_table, hwif->sg_nents);
+ set_dma_mode(ECARD_DEV(state->dev)->dma, dma_mode);
drive->waiting_for_dma = 1;
@@ -467,18 +417,13 @@ static void icside_dma_lost_irq(ide_drive_t *drive)
static void icside_dma_init(ide_hwif_t *hwif)
{
- printk(" %s: SG-DMA", hwif->name);
-
- hwif->atapi_dma = 1;
hwif->mwdma_mask = 7; /* MW0..2 */
hwif->swdma_mask = 7; /* SW0..2 */
hwif->dmatable_cpu = NULL;
hwif->dmatable_dma = 0;
- hwif->speedproc = icside_set_speed;
- hwif->autodma = 1;
+ hwif->set_dma_mode = icside_set_dma_mode;
- hwif->ide_dma_check = icside_dma_check;
hwif->dma_host_off = icside_dma_host_off;
hwif->dma_off_quietly = icside_dma_off_quietly;
hwif->dma_host_on = icside_dma_host_on;
@@ -490,50 +435,21 @@ static void icside_dma_init(ide_hwif_t *hwif)
hwif->ide_dma_test_irq = icside_dma_test_irq;
hwif->dma_timeout = icside_dma_timeout;
hwif->dma_lost_irq = icside_dma_lost_irq;
-
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
-
- printk(" capable%s\n", hwif->autodma ? ", auto-enable" : "");
}
#else
#define icside_dma_init(hwif) (0)
#endif
-static ide_hwif_t *icside_find_hwif(unsigned long dataport)
-{
- ide_hwif_t *hwif;
- int index;
-
- for (index = 0; index < MAX_HWIFS; ++index) {
- hwif = &ide_hwifs[index];
- if (hwif->io_ports[IDE_DATA_OFFSET] == dataport)
- goto found;
- }
-
- for (index = 0; index < MAX_HWIFS; ++index) {
- hwif = &ide_hwifs[index];
- if (!hwif->io_ports[IDE_DATA_OFFSET])
- goto found;
- }
-
- hwif = NULL;
-found:
- return hwif;
-}
-
static ide_hwif_t *
icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *ec)
{
unsigned long port = (unsigned long)base + info->dataoffset;
ide_hwif_t *hwif;
- hwif = icside_find_hwif(port);
+ hwif = ide_find_port(port);
if (hwif) {
int i;
- memset(&hwif->hw, 0, sizeof(hw_regs_t));
-
/*
* Ensure we're using MMIO
*/
@@ -541,13 +457,10 @@ icside_setup(void __iomem *base, struct cardinfo *info, struct expansion_card *e
hwif->mmio = 1;
for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
- hwif->hw.io_ports[i] = port;
hwif->io_ports[i] = port;
port += 1 << info->stepping;
}
- hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (unsigned long)base + info->ctrloffset;
hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)base + info->ctrloffset;
- hwif->hw.irq = ec->irq;
hwif->irq = ec->irq;
hwif->noprobe = 0;
hwif->chipset = ide_acorn;
@@ -562,6 +475,7 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec)
{
ide_hwif_t *hwif;
void __iomem *base;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
if (!base)
@@ -585,9 +499,9 @@ icside_register_v5(struct icside_state *state, struct expansion_card *ec)
state->hwif[0] = hwif;
- probe_hwif_init(hwif);
+ idx[0] = hwif->index;
- ide_proc_register_port(hwif);
+ ide_device_add(idx);
return 0;
}
@@ -599,6 +513,7 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
void __iomem *ioc_base, *easi_base;
unsigned int sel = 0;
int ret;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
ioc_base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0);
if (!ioc_base) {
@@ -654,7 +569,6 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
hwif->serialized = 1;
hwif->config_data = (unsigned long)ioc_base;
hwif->select_data = sel;
- hwif->hw.dma = ec->dma;
mate->maskproc = icside_maskproc;
mate->channel = 1;
@@ -663,18 +577,16 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec)
mate->serialized = 1;
mate->config_data = (unsigned long)ioc_base;
mate->select_data = sel | 1;
- mate->hw.dma = ec->dma;
if (ec->dma != NO_DMA && !request_dma(ec->dma, hwif->name)) {
icside_dma_init(hwif);
icside_dma_init(mate);
}
- probe_hwif_init(hwif);
- probe_hwif_init(mate);
+ idx[0] = hwif->index;
+ idx[1] = mate->index;
- ide_proc_register_port(hwif);
- ide_proc_register_port(mate);
+ ide_device_add(idx);
return 0;
diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c
index bce2bec8141..8957cbadf5c 100644
--- a/drivers/ide/arm/ide_arm.c
+++ b/drivers/ide/arm/ide_arm.c
@@ -31,5 +31,5 @@ void __init ide_arm_init(void)
memset(&hw, 0, sizeof(hw));
ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206);
hw.irq = IDE_ARM_IRQ;
- ide_register_hw(&hw, 1, NULL);
+ ide_register_hw(&hw, NULL, 1, NULL);
}
diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
index 83811af1161..0775a3afef4 100644
--- a/drivers/ide/arm/rapide.c
+++ b/drivers/ide/arm/rapide.c
@@ -13,42 +13,25 @@
#include <asm/ecard.h>
-/*
- * Something like this really should be in generic code, but isn't.
- */
static ide_hwif_t *
rapide_locate_hwif(void __iomem *base, void __iomem *ctrl, unsigned int sz, int irq)
{
unsigned long port = (unsigned long)base;
- ide_hwif_t *hwif;
- int index, i;
-
- for (index = 0; index < MAX_HWIFS; ++index) {
- hwif = ide_hwifs + index;
- if (hwif->io_ports[IDE_DATA_OFFSET] == port)
- goto found;
- }
-
- for (index = 0; index < MAX_HWIFS; ++index) {
- hwif = ide_hwifs + index;
- if (hwif->io_ports[IDE_DATA_OFFSET] == 0)
- goto found;
- }
+ ide_hwif_t *hwif = ide_find_port(port);
+ int i;
- return NULL;
+ if (hwif == NULL)
+ goto out;
- found:
for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
- hwif->hw.io_ports[i] = port;
hwif->io_ports[i] = port;
port += sz;
}
- hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
- hwif->hw.irq = hwif->irq = irq;
+ hwif->irq = irq;
hwif->mmio = 1;
default_hwif_mmiops(hwif);
-
+out:
return hwif;
}
@@ -58,6 +41,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
ide_hwif_t *hwif;
void __iomem *base;
int ret;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
ret = ecard_request_resources(ec);
if (ret)
@@ -74,8 +58,11 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id)
hwif->hwif_data = base;
hwif->gendev.parent = &ec->dev;
hwif->noprobe = 0;
- probe_hwif_init(hwif);
- ide_proc_register_port(hwif);
+
+ idx[0] = hwif->index;
+
+ ide_device_add(idx);
+
ecard_set_drvdata(ec, hwif);
goto out;
}
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 04636f7eaae..7f5bc2ee6c7 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -664,7 +664,6 @@ cris_ide_inb(unsigned long reg)
return (unsigned char)cris_ide_inw(reg);
}
-static int cris_dma_check (ide_drive_t *drive);
static int cris_dma_end (ide_drive_t *drive);
static int cris_dma_setup (ide_drive_t *drive);
static void cris_dma_exec_cmd (ide_drive_t *drive, u8 command);
@@ -680,12 +679,10 @@ static void cris_dma_off(ide_drive_t *drive)
{
}
-static void tune_cris_ide(ide_drive_t *drive, u8 pio)
+static void cris_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
int setup, strobe, hold;
- pio = ide_get_best_pio_mode(drive, pio, 4);
-
switch(pio)
{
case 0:
@@ -718,19 +715,12 @@ static void tune_cris_ide(ide_drive_t *drive, u8 pio)
}
cris_ide_set_speed(TYPE_PIO, setup, strobe, hold);
-
- (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
-static int speed_cris_ide(ide_drive_t *drive, u8 speed)
+static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
int cyc = 0, dvs = 0, strobe = 0, hold = 0;
- if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
- tune_cris_ide(drive, speed - XFER_PIO_0);
- return ide_config_drive_speed(drive, speed);
- }
-
switch(speed)
{
case XFER_UDMA_0:
@@ -758,16 +748,13 @@ static int speed_cris_ide(ide_drive_t *drive, u8 speed)
hold = ATA_DMA2_HOLD;
break;
default:
- BUG();
- break;
+ return;
}
if (speed >= XFER_UDMA_0)
cris_ide_set_speed(TYPE_UDMA, cyc, dvs, 0);
else
cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
-
- return ide_config_drive_speed(drive, speed);
}
void __init
@@ -794,16 +781,15 @@ init_e100_ide (void)
ide_offsets,
0, 0, cris_ide_ack_intr,
ide_default_irq(0));
- ide_register_hw(&hw, 1, &hwif);
+ ide_register_hw(&hw, NULL, 1, &hwif);
hwif->mmio = 1;
hwif->chipset = ide_etrax100;
- hwif->tuneproc = &tune_cris_ide;
- hwif->speedproc = &speed_cris_ide;
+ hwif->set_pio_mode = &cris_set_pio_mode;
+ hwif->set_dma_mode = &cris_set_dma_mode;
hwif->ata_input_data = &cris_ide_input_data;
hwif->ata_output_data = &cris_ide_output_data;
hwif->atapi_input_bytes = &cris_atapi_input_bytes;
hwif->atapi_output_bytes = &cris_atapi_output_bytes;
- hwif->ide_dma_check = &cris_dma_check;
hwif->ide_dma_end = &cris_dma_end;
hwif->dma_setup = &cris_dma_setup;
hwif->dma_exec_cmd = &cris_dma_exec_cmd;
@@ -818,12 +804,12 @@ init_e100_ide (void)
hwif->dma_host_on = &cris_dma_on;
hwif->dma_off_quietly = &cris_dma_off;
hwif->cbl = ATA_CBL_PATA40;
+ hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
hwif->pio_mask = ATA_PIO4,
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
hwif->ultra_mask = cris_ultra_mask;
hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
- hwif->autodma = 1;
- hwif->drives[0].autodma = 1;
- hwif->drives[1].autodma = 1;
}
/* Reset pulse */
@@ -948,10 +934,11 @@ static int cris_ide_build_dmatable (ide_drive_t *drive)
* than two possibly non-adjacent physical 4kB pages.
*/
/* group sequential buffers into one large buffer */
- addr = page_to_phys(sg->page) + sg->offset;
+ addr = sg_phys(sg);
size = sg_dma_len(sg);
- while (sg++, --i) {
- if ((addr + size) != page_to_phys(sg->page) + sg->offset)
+ while (--i) {
+ sg = sg_next(sg);
+ if ((addr + size) != sg_phys(sg))
break;
size += sg_dma_len(sg);
}
@@ -1028,14 +1015,6 @@ static ide_startstop_t cris_dma_intr (ide_drive_t *drive)
* the caller should revert to PIO for the current request.
*/
-static int cris_dma_check(ide_drive_t *drive)
-{
- if (ide_tune_dma(drive))
- return 0;
-
- return -1;
-}
-
static int cris_dma_end(ide_drive_t *drive)
{
drive->waiting_for_dma = 0;
diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
index 6d26ad7360d..4a49b5c59ac 100644
--- a/drivers/ide/h8300/ide-h8300.c
+++ b/drivers/ide/h8300/ide-h8300.c
@@ -68,7 +68,6 @@ static inline void hw_setup(hw_regs_t *hw)
hw->io_ports[i] = CONFIG_H8300_IDE_BASE + H8300_IDE_GAP*i;
hw->io_ports[IDE_CONTROL_OFFSET] = CONFIG_H8300_IDE_ALT;
hw->irq = EXT_IRQ0 + CONFIG_H8300_IDE_IRQ;
- hw->dma = NO_DMA;
hw->chipset = ide_generic;
}
@@ -101,7 +100,7 @@ void __init h8300_ide_init(void)
hw_setup(&hw);
/* register if */
- idx = ide_register_hw(&hw, 1, &hwif);
+ idx = ide_register_hw(&hw, NULL, 1, &hwif);
if (idx == -1) {
printk(KERN_ERR "ide-h8300: IDE I/F register failed\n");
return;
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index 17aea65d7dd..89df48fdc69 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -350,7 +350,7 @@ static int taskfile_load_raw(ide_drive_t *drive,
memset(&args, 0, sizeof(ide_task_t));
args.command_type = IDE_DRIVE_TASK_NO_DATA;
- args.data_phase = TASKFILE_IN;
+ args.data_phase = TASKFILE_NO_DATA;
args.handler = &task_no_data_intr;
/* convert gtf to IDE Taskfile */
@@ -612,6 +612,45 @@ void ide_acpi_push_timing(ide_hwif_t *hwif)
EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
/**
+ * ide_acpi_set_state - set the channel power state
+ * @hwif: target IDE interface
+ * @on: state, on/off
+ *
+ * This function executes the _PS0/_PS3 ACPI method to set the power state.
+ * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
+ */
+void ide_acpi_set_state(ide_hwif_t *hwif, int on)
+{
+ int unit;
+
+ if (ide_noacpi)
+ return;
+
+ DEBPRINT("ENTER:\n");
+
+ if (!hwif->acpidata) {
+ DEBPRINT("no ACPI data for %s\n", hwif->name);
+ return;
+ }
+ /* channel first and then drives for power on and verse versa for power off */
+ if (on)
+ acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
+ for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ ide_drive_t *drive = &hwif->drives[unit];
+
+ if (!drive->acpidata->obj_handle)
+ drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
+
+ if (drive->acpidata->obj_handle && drive->present) {
+ acpi_bus_set_power(drive->acpidata->obj_handle,
+ on? ACPI_STATE_D0: ACPI_STATE_D3);
+ }
+ }
+ if (!on)
+ acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
+}
+
+/**
* ide_acpi_init - initialize the ACPI link for an IDE interface
* @hwif: target IDE interface (channel)
*
@@ -679,6 +718,8 @@ void ide_acpi_init(ide_hwif_t *hwif)
return;
}
+ /* ACPI _PS0 before _STM */
+ ide_acpi_set_state(hwif, 1);
/*
* ACPI requires us to call _STM on startup
*/
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index ca843522f91..57a5f63d6ae 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -120,7 +120,7 @@
* Reformat to match kernel tabbing style.
* Add CDROM_GET_UPC ioctl.
* 3.10 Apr 10, 1996 -- Fix compilation error with STANDARD_ATAPI.
- * 3.11 Apr 29, 1996 -- Patch from Heiko Eissfeldt <heiko@colossus.escape.de>
+ * 3.11 Apr 29, 1996 -- Patch from Heiko Eißfeldt <heiko@colossus.escape.de>
* to remove redundant verify_area calls.
* 3.12 May 7, 1996 -- Rudimentary changer support. Based on patches
* from Gerhard Zuber <zuber@berlin.snafu.de>.
@@ -256,7 +256,7 @@
* - Minimize the TOC reading - only do it when we
* know a media change has occurred.
* - Moved all the CDROMREADx ioctls to the Uniform layer.
- * - Heiko Eissfeldt <heiko@colossus.escape.de> supplied
+ * - Heiko Eißfeldt <heiko@colossus.escape.de> supplied
* some fixes for CDI.
* - CD-ROM leaving door locked fix from Andries
* Brouwer <Andries.Brouwer@cwi.nl>
@@ -2341,7 +2341,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
If we get an error for the regular case, we assume
a CDI without additional audio tracks. In this case
the readable TOC is empty (CDI tracks are not included)
- and only holds the Leadout entry. Heiko Eißfeldt */
+ and only holds the Leadout entry. Heiko Eißfeldt */
ntracks = 0;
stat = cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0,
(char *)&toc->hdr,
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 4754769eda9..00123d99527 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -169,7 +169,7 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
nsectors.all = (u16) rq->nr_sectors;
- if (hwif->no_lba48_dma && lba48 && dma) {
+ if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) {
if (block + rq->nr_sectors > 1ULL << 28)
dma = 0;
else
@@ -593,28 +593,12 @@ static int smart_enable(ide_drive_t *drive)
return ide_raw_taskfile(drive, &args, NULL);
}
-static int get_smart_values(ide_drive_t *drive, u8 *buf)
+static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd)
{
ide_task_t args;
memset(&args, 0, sizeof(ide_task_t));
- args.tfRegister[IDE_FEATURE_OFFSET] = SMART_READ_VALUES;
- args.tfRegister[IDE_NSECTOR_OFFSET] = 0x01;
- args.tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
- args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
- args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART;
- args.command_type = IDE_DRIVE_TASK_IN;
- args.data_phase = TASKFILE_IN;
- args.handler = &task_in_intr;
- (void) smart_enable(drive);
- return ide_raw_taskfile(drive, &args, buf);
-}
-
-static int get_smart_thresholds(ide_drive_t *drive, u8 *buf)
-{
- ide_task_t args;
- memset(&args, 0, sizeof(ide_task_t));
- args.tfRegister[IDE_FEATURE_OFFSET] = SMART_READ_THRESHOLDS;
+ args.tfRegister[IDE_FEATURE_OFFSET] = sub_cmd;
args.tfRegister[IDE_NSECTOR_OFFSET] = 0x01;
args.tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
@@ -656,7 +640,7 @@ static int proc_idedisk_read_smart_thresholds
ide_drive_t *drive = (ide_drive_t *)data;
int len = 0, i = 0;
- if (!get_smart_thresholds(drive, page)) {
+ if (get_smart_data(drive, page, SMART_READ_THRESHOLDS) == 0) {
unsigned short *val = (unsigned short *) page;
char *out = ((char *)val) + (SECTOR_WORDS * 4);
page = out;
@@ -675,7 +659,7 @@ static int proc_idedisk_read_smart_values
ide_drive_t *drive = (ide_drive_t *)data;
int len = 0, i = 0;
- if (!get_smart_values(drive, page)) {
+ if (get_smart_data(drive, page, SMART_READ_VALUES) == 0) {
unsigned short *val = (unsigned short *) page;
char *out = ((char *)val) + (SECTOR_WORDS * 4);
page = out;
@@ -716,32 +700,6 @@ static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
rq->buffer = rq->cmd;
}
-static int idedisk_issue_flush(struct request_queue *q, struct gendisk *disk,
- sector_t *error_sector)
-{
- ide_drive_t *drive = q->queuedata;
- struct request *rq;
- int ret;
-
- if (!drive->wcache)
- return 0;
-
- rq = blk_get_request(q, WRITE, __GFP_WAIT);
-
- idedisk_prepare_flush(q, rq);
-
- ret = blk_execute_rq(q, disk, rq, 0);
-
- /*
- * if we failed and caller wants error offset, get it
- */
- if (ret && error_sector)
- *error_sector = ide_get_error_location(drive, rq->cmd);
-
- blk_put_request(rq);
- return ret;
-}
-
/*
* This is tightly woven into the driver->do_special can not touch.
* DON'T do it again until a total personality rewrite is committed.
@@ -781,7 +739,6 @@ static void update_ordered(ide_drive_t *drive)
struct hd_driveid *id = drive->id;
unsigned ordered = QUEUE_ORDERED_NONE;
prepare_flush_fn *prep_fn = NULL;
- issue_flush_fn *issue_fn = NULL;
if (drive->wcache) {
unsigned long long capacity;
@@ -805,13 +762,11 @@ static void update_ordered(ide_drive_t *drive)
if (barrier) {
ordered = QUEUE_ORDERED_DRAIN_FLUSH;
prep_fn = idedisk_prepare_flush;
- issue_fn = idedisk_issue_flush;
}
} else
ordered = QUEUE_ORDERED_DRAIN;
blk_queue_ordered(drive->queue, ordered, prep_fn);
- blk_queue_issue_flush_fn(drive->queue, issue_fn);
}
static int write_cache(ide_drive_t *drive, int arg)
@@ -885,7 +840,7 @@ static int set_lba_addressing(ide_drive_t *drive, int arg)
drive->addressing = 0;
- if (HWIF(drive)->no_lba48)
+ if (drive->hwif->host_flags & IDE_HFLAG_NO_LBA48)
return 0;
if (!idedisk_supports_lba48(drive->id))
@@ -918,6 +873,7 @@ static inline void idedisk_add_settings(ide_drive_t *drive) { ; }
static void idedisk_setup (ide_drive_t *drive)
{
+ ide_hwif_t *hwif = drive->hwif;
struct hd_driveid *id = drive->id;
unsigned long long capacity;
@@ -938,7 +894,6 @@ static void idedisk_setup (ide_drive_t *drive)
(void)set_lba_addressing(drive, 1);
if (drive->addressing == 1) {
- ide_hwif_t *hwif = HWIF(drive);
int max_s = 2048;
if (max_s > hwif->rqsize)
@@ -961,7 +916,7 @@ static void idedisk_setup (ide_drive_t *drive)
drive->capacity64 = 1ULL << 28;
}
- if (drive->hwif->no_lba48_dma && drive->addressing) {
+ if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && drive->addressing) {
if (drive->capacity64 > 1ULL << 28) {
printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode will"
" be used for accessing sectors > %u\n",
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index ff644a5e12c..e3add70b9cd 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -169,6 +169,11 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive)
EXPORT_SYMBOL_GPL(ide_dma_intr);
+static int ide_dma_good_drive(ide_drive_t *drive)
+{
+ return ide_in_drive_list(drive->id, drive_whitelist);
+}
+
#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
/**
* ide_build_sglist - map IDE scatter gather for DMA I/O
@@ -275,7 +280,7 @@ int ide_build_dmatable (ide_drive_t *drive, struct request *rq)
}
}
- sg++;
+ sg = sg_next(sg);
i--;
}
@@ -333,35 +338,32 @@ static int config_drive_for_dma (ide_drive_t *drive)
ide_hwif_t *hwif = drive->hwif;
struct hd_driveid *id = drive->id;
- /* consult the list of known "bad" drives */
- if (__ide_dma_bad_drive(drive))
- return -1;
+ if (drive->media != ide_disk) {
+ if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
+ return 0;
+ }
- if (drive->media != ide_disk && hwif->atapi_dma == 0)
- return -1;
+ /*
+ * Enable DMA on any drive that has
+ * UltraDMA (mode 0/1/2/3/4/5/6) enabled
+ */
+ if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f))
+ return 1;
- if ((id->capability & 1) && drive->autodma) {
- /*
- * Enable DMA on any drive that has
- * UltraDMA (mode 0/1/2/3/4/5/6) enabled
- */
- if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f))
- return 0;
- /*
- * Enable DMA on any drive that has mode2 DMA
- * (multi or single) enabled
- */
- if (id->field_valid & 2) /* regular DMA */
- if ((id->dma_mword & 0x404) == 0x404 ||
- (id->dma_1word & 0x404) == 0x404)
- return 0;
+ /*
+ * Enable DMA on any drive that has mode2 DMA
+ * (multi or single) enabled
+ */
+ if (id->field_valid & 2) /* regular DMA */
+ if ((id->dma_mword & 0x404) == 0x404 ||
+ (id->dma_1word & 0x404) == 0x404)
+ return 1;
- /* Consult the list of known "good" drives */
- if (__ide_dma_good_drive(drive))
- return 0;
- }
+ /* Consult the list of known "good" drives */
+ if (ide_dma_good_drive(drive))
+ return 1;
- return -1;
+ return 0;
}
/**
@@ -622,6 +624,8 @@ static int __ide_dma_test_irq(ide_drive_t *drive)
drive->name, __FUNCTION__);
return 0;
}
+#else
+static inline int config_drive_for_dma(ide_drive_t *drive) { return 0; }
#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
int __ide_dma_bad_drive (ide_drive_t *drive)
@@ -639,21 +643,13 @@ int __ide_dma_bad_drive (ide_drive_t *drive)
EXPORT_SYMBOL(__ide_dma_bad_drive);
-int __ide_dma_good_drive (ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
- return ide_in_drive_list(id, drive_whitelist);
-}
-
-EXPORT_SYMBOL(__ide_dma_good_drive);
-
static const u8 xfer_mode_bases[] = {
XFER_UDMA_0,
XFER_MW_DMA_0,
XFER_SW_DMA_0,
};
-static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base)
+static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
{
struct hd_driveid *id = drive->id;
ide_hwif_t *hwif = drive->hwif;
@@ -664,17 +660,28 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base)
if ((id->field_valid & 4) == 0)
break;
- mask = id->dma_ultra & hwif->ultra_mask;
-
if (hwif->udma_filter)
- mask &= hwif->udma_filter(drive);
+ mask = hwif->udma_filter(drive);
+ else
+ mask = hwif->ultra_mask;
+ mask &= id->dma_ultra;
- if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
- mask &= 0x07;
+ /*
+ * avoid false cable warning from eighty_ninty_three()
+ */
+ if (req_mode > XFER_UDMA_2) {
+ if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
+ mask &= 0x07;
+ }
break;
case XFER_MW_DMA_0:
- if (id->field_valid & 2)
- mask = id->dma_mword & hwif->mwdma_mask;
+ if ((id->field_valid & 2) == 0)
+ break;
+ if (hwif->mdma_filter)
+ mask = hwif->mdma_filter(drive);
+ else
+ mask = hwif->mwdma_mask;
+ mask &= id->dma_mword;
break;
case XFER_SW_DMA_0:
if (id->field_valid & 2) {
@@ -703,26 +710,33 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base)
}
/**
- * ide_max_dma_mode - compute DMA speed
+ * ide_find_dma_mode - compute DMA speed
* @drive: IDE device
+ * @req_mode: requested mode
*
- * Checks the drive capabilities and returns the speed to use
- * for the DMA transfer. Returns 0 if the drive is incapable
- * of DMA transfers.
+ * Checks the drive/host capabilities and finds the speed to use for
+ * the DMA transfer. The speed is then limited by the requested mode.
+ *
+ * Returns 0 if the drive/host combination is incapable of DMA transfers
+ * or if the requested mode is not a DMA mode.
*/
-u8 ide_max_dma_mode(ide_drive_t *drive)
+u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
{
ide_hwif_t *hwif = drive->hwif;
unsigned int mask;
int x, i;
u8 mode = 0;
- if (drive->media != ide_disk && hwif->atapi_dma == 0)
- return 0;
+ if (drive->media != ide_disk) {
+ if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
+ return 0;
+ }
for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) {
- mask = ide_get_mode_mask(drive, xfer_mode_bases[i]);
+ if (req_mode < xfer_mode_bases[i])
+ continue;
+ mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode);
x = fls(mask) - 1;
if (x >= 0) {
mode = xfer_mode_bases[i] + x;
@@ -730,36 +744,66 @@ u8 ide_max_dma_mode(ide_drive_t *drive)
}
}
- printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode);
+ if (hwif->chipset == ide_acorn && mode == 0) {
+ /*
+ * is this correct?
+ */
+ if (ide_dma_good_drive(drive) && drive->id->eide_dma_time < 150)
+ mode = XFER_MW_DMA_1;
+ }
- return mode;
+ printk(KERN_DEBUG "%s: %s mode selected\n", drive->name,
+ mode ? ide_xfer_verbose(mode) : "no DMA");
+
+ return min(mode, req_mode);
}
-EXPORT_SYMBOL_GPL(ide_max_dma_mode);
+EXPORT_SYMBOL_GPL(ide_find_dma_mode);
-int ide_tune_dma(ide_drive_t *drive)
+static int ide_tune_dma(ide_drive_t *drive)
{
u8 speed;
- if ((drive->id->capability & 1) == 0 || drive->autodma == 0)
+ if (noautodma || drive->nodma || (drive->id->capability & 1) == 0)
return 0;
/* consult the list of known "bad" drives */
if (__ide_dma_bad_drive(drive))
return 0;
+ if (drive->hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
+ return config_drive_for_dma(drive);
+
speed = ide_max_dma_mode(drive);
if (!speed)
return 0;
- if (drive->hwif->speedproc(drive, speed))
+ if (drive->hwif->host_flags & IDE_HFLAG_NO_SET_MODE)
+ return 0;
+
+ if (ide_set_dma_mode(drive, speed))
return 0;
return 1;
}
-EXPORT_SYMBOL_GPL(ide_tune_dma);
+static int ide_dma_check(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ int vdma = (hwif->host_flags & IDE_HFLAG_VDMA)? 1 : 0;
+
+ if (!vdma && ide_tune_dma(drive))
+ return 0;
+
+ /* TODO: always do PIO fallback */
+ if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
+ return -1;
+
+ ide_set_max_pio(drive);
+
+ return vdma ? 0 : -1;
+}
void ide_dma_verbose(ide_drive_t *drive)
{
@@ -818,7 +862,7 @@ int ide_set_dma(ide_drive_t *drive)
ide_hwif_t *hwif = drive->hwif;
int rc;
- rc = hwif->ide_dma_check(drive);
+ rc = ide_dma_check(drive);
switch(rc) {
case -1: /* DMA needs to be disabled */
@@ -858,10 +902,7 @@ void ide_dma_timeout (ide_drive_t *drive)
EXPORT_SYMBOL(ide_dma_timeout);
-/*
- * Needed for allowing full modular support of ide-driver
- */
-static int ide_release_dma_engine(ide_hwif_t *hwif)
+static void ide_release_dma_engine(ide_hwif_t *hwif)
{
if (hwif->dmatable_cpu) {
pci_free_consistent(hwif->pci_dev,
@@ -870,7 +911,6 @@ static int ide_release_dma_engine(ide_hwif_t *hwif)
hwif->dmatable_dma);
hwif->dmatable_cpu = NULL;
}
- return 1;
}
static int ide_release_iomio_dma(ide_hwif_t *hwif)
@@ -913,12 +953,6 @@ static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base, unsigned in
{
printk(KERN_INFO " %s: MMIO-DMA ", hwif->name);
- hwif->dma_base = base;
-
- if(hwif->mate)
- hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
- else
- hwif->dma_master = base;
return 0;
}
@@ -932,8 +966,6 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port
return 1;
}
- hwif->dma_base = base;
-
if (hwif->cds->extra) {
hwif->extra_base = base + (hwif->channel ? 8 : 16);
@@ -948,10 +980,6 @@ static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int port
}
}
- if(hwif->mate)
- hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base:base;
- else
- hwif->dma_master = base;
return 0;
}
@@ -963,12 +991,9 @@ static int ide_dma_iobase(ide_hwif_t *hwif, unsigned long base, unsigned int por
return ide_iomio_dma(hwif, base, ports);
}
-/*
- * This can be called for a dynamically installed interface. Don't __init it
- */
-void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports)
{
- if (ide_dma_iobase(hwif, dma_base, num_ports))
+ if (ide_dma_iobase(hwif, base, num_ports))
return;
if (ide_allocate_dma_engine(hwif)) {
@@ -976,6 +1001,13 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p
return;
}
+ hwif->dma_base = base;
+
+ if (hwif->mate)
+ hwif->dma_master = hwif->channel ? hwif->mate->dma_base : base;
+ else
+ hwif->dma_master = base;
+
if (!(hwif->dma_command))
hwif->dma_command = hwif->dma_base;
if (!(hwif->dma_vendor1))
@@ -995,8 +1027,6 @@ void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_p
hwif->ide_dma_on = &__ide_dma_on;
if (!hwif->dma_host_on)
hwif->dma_host_on = &ide_dma_host_on;
- if (!hwif->ide_dma_check)
- hwif->ide_dma_check = &config_drive_for_dma;
if (!hwif->dma_setup)
hwif->dma_setup = &ide_dma_setup;
if (!hwif->dma_exec_cmd)
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index ae8e1a64b8a..04a357808f2 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -606,26 +606,24 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns
{
struct request *rq = pc->rq;
struct bio_vec *bvec;
- struct bio *bio;
+ struct req_iterator iter;
unsigned long flags;
char *data;
- int count, i, done = 0;
+ int count, done = 0;
- rq_for_each_bio(bio, rq) {
- bio_for_each_segment(bvec, bio, i) {
- if (!bcount)
- break;
+ rq_for_each_segment(bvec, rq, iter) {
+ if (!bcount)
+ break;
- count = min(bvec->bv_len, bcount);
+ count = min(bvec->bv_len, bcount);
- data = bvec_kmap_irq(bvec, &flags);
- drive->hwif->atapi_input_bytes(drive, data, count);
- bvec_kunmap_irq(data, &flags);
+ data = bvec_kmap_irq(bvec, &flags);
+ drive->hwif->atapi_input_bytes(drive, data, count);
+ bvec_kunmap_irq(data, &flags);
- bcount -= count;
- pc->b_count += count;
- done += count;
- }
+ bcount -= count;
+ pc->b_count += count;
+ done += count;
}
idefloppy_do_end_request(drive, 1, done >> 9);
@@ -639,27 +637,25 @@ static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, uns
static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
{
struct request *rq = pc->rq;
- struct bio *bio;
+ struct req_iterator iter;
struct bio_vec *bvec;
unsigned long flags;
- int count, i, done = 0;
+ int count, done = 0;
char *data;
- rq_for_each_bio(bio, rq) {
- bio_for_each_segment(bvec, bio, i) {
- if (!bcount)
- break;
+ rq_for_each_segment(bvec, rq, iter) {
+ if (!bcount)
+ break;
- count = min(bvec->bv_len, bcount);
+ count = min(bvec->bv_len, bcount);
- data = bvec_kmap_irq(bvec, &flags);
- drive->hwif->atapi_output_bytes(drive, data, count);
- bvec_kunmap_irq(data, &flags);
+ data = bvec_kmap_irq(bvec, &flags);
+ drive->hwif->atapi_output_bytes(drive, data, count);
+ bvec_kunmap_irq(data, &flags);
- bcount -= count;
- pc->b_count += count;
- done += count;
- }
+ bcount -= count;
+ pc->b_count += count;
+ done += count;
}
idefloppy_do_end_request(drive, 1, done >> 9);
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index aa9f5f0b1e6..db22d1ff4e5 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -47,15 +47,15 @@
#include <linux/device.h>
#include <linux/kmod.h>
#include <linux/scatterlist.h>
+#include <linux/bitops.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>
-#include <asm/bitops.h>
static int __ide_end_request(ide_drive_t *drive, struct request *rq,
- int uptodate, unsigned int nr_bytes)
+ int uptodate, unsigned int nr_bytes, int dequeue)
{
int ret = 1;
@@ -80,9 +80,11 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
if (!end_that_request_chunk(rq, uptodate, nr_bytes)) {
add_disk_randomness(rq->rq_disk);
- if (!list_empty(&rq->queuelist))
- blkdev_dequeue_request(rq);
- HWGROUP(drive)->rq = NULL;
+ if (dequeue) {
+ if (!list_empty(&rq->queuelist))
+ blkdev_dequeue_request(rq);
+ HWGROUP(drive)->rq = NULL;
+ }
end_that_request_last(rq, uptodate);
ret = 0;
}
@@ -122,7 +124,7 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
nr_bytes = rq->hard_cur_sectors << 9;
}
- ret = __ide_end_request(drive, rq, uptodate, nr_bytes);
+ ret = __ide_end_request(drive, rq, uptodate, nr_bytes, 1);
spin_unlock_irqrestore(&ide_lock, flags);
return ret;
@@ -201,8 +203,7 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
return do_rw_taskfile(drive, args);
case idedisk_pm_restore_pio: /* Resume step 1 (restore PIO) */
- if (drive->hwif->tuneproc != NULL)
- drive->hwif->tuneproc(drive, 255);
+ ide_set_max_pio(drive);
/*
* skip idedisk_pm_idle for ATAPI devices
*/
@@ -220,11 +221,11 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
case ide_pm_restore_dma: /* Resume step 3 (restore DMA) */
/*
- * Right now, all we do is call hwif->ide_dma_check(drive),
+ * Right now, all we do is call ide_set_dma(drive),
* we could be smarter and check for current xfer_speed
* in struct drive etc...
*/
- if (drive->hwif->ide_dma_check == NULL)
+ if (drive->hwif->ide_dma_on == NULL)
break;
drive->hwif->dma_off_quietly(drive);
/*
@@ -256,39 +257,13 @@ int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
int uptodate, int nr_sectors)
{
unsigned long flags;
- int ret = 1;
+ int ret;
spin_lock_irqsave(&ide_lock, flags);
-
BUG_ON(!blk_rq_started(rq));
-
- /*
- * if failfast is set on a request, override number of sectors and
- * complete the whole request right now
- */
- if (blk_noretry_request(rq) && end_io_error(uptodate))
- nr_sectors = rq->hard_nr_sectors;
-
- if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors)
- rq->errors = -EIO;
-
- /*
- * decide whether to reenable DMA -- 3 is a random magic for now,
- * if we DMA timeout more than 3 times, just stay in PIO
- */
- if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
- drive->state = 0;
- HWGROUP(drive)->hwif->ide_dma_on(drive);
- }
-
- if (!end_that_request_first(rq, uptodate, nr_sectors)) {
- add_disk_randomness(rq->rq_disk);
- if (blk_rq_tagged(rq))
- blk_queue_end_tag(drive->queue, rq);
- end_that_request_last(rq, uptodate);
- ret = 0;
- }
+ ret = __ide_end_request(drive, rq, uptodate, nr_sectors << 9, 0);
spin_unlock_irqrestore(&ide_lock, flags);
+
return ret;
}
EXPORT_SYMBOL_GPL(ide_end_dequeued_request);
@@ -323,41 +298,6 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq)
spin_unlock_irqrestore(&ide_lock, flags);
}
-/*
- * FIXME: probably move this somewhere else, name is bad too :)
- */
-u64 ide_get_error_location(ide_drive_t *drive, char *args)
-{
- u32 high, low;
- u8 hcyl, lcyl, sect;
- u64 sector;
-
- high = 0;
- hcyl = args[5];
- lcyl = args[4];
- sect = args[3];
-
- if (ide_id_has_flush_cache_ext(drive->id)) {
- low = (hcyl << 16) | (lcyl << 8) | sect;
- HWIF(drive)->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
- high = ide_read_24(drive);
- } else {
- u8 cur = HWIF(drive)->INB(IDE_SELECT_REG);
- if (cur & 0x40) {
- high = cur & 0xf;
- low = (hcyl << 16) | (lcyl << 8) | sect;
- } else {
- low = hcyl * drive->head * drive->sect;
- low += lcyl * drive->sect;
- low += sect - 1;
- }
- }
-
- sector = ((u64) high << 24) | low;
- return sector;
-}
-EXPORT_SYMBOL(ide_get_error_location);
-
/**
* ide_end_drive_cmd - end an explicit drive command
* @drive: command
@@ -400,6 +340,8 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
if (args) {
args[0] = stat;
args[1] = err;
+ /* be sure we're looking at the low order bits */
+ hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG);
args[2] = hwif->INB(IDE_NSECTOR_REG);
args[3] = hwif->INB(IDE_SECTOR_REG);
args[4] = hwif->INB(IDE_LCYL_REG);
@@ -520,7 +462,8 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8
}
}
- if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ && hwif->err_stops_fifo == 0)
+ if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ &&
+ (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0)
try_to_flush_leftover_data(drive);
if (rq->errors >= ERROR_MAX || blk_noretry_request(rq)) {
@@ -713,7 +656,8 @@ static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
int retries = 10;
local_irq_enable_in_hardirq();
- if ((stat & DRQ_STAT) && args && args[3]) {
+ if (rq->cmd_type == REQ_TYPE_ATA_CMD &&
+ (stat & DRQ_STAT) && args && args[3]) {
u8 io_32bit = drive->io_32bit;
drive->io_32bit = 0;
hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS);
@@ -788,6 +732,30 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
return ide_started;
}
+/*
+ * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
+ */
+static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
+{
+ switch (req_pio) {
+ case 202:
+ case 201:
+ case 200:
+ case 102:
+ case 101:
+ case 100:
+ return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
+ case 9:
+ case 8:
+ return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
+ case 7:
+ case 6:
+ return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
+ default:
+ return 0;
+ }
+}
+
/**
* do_special - issue some special commands
* @drive: drive the command is for
@@ -805,9 +773,38 @@ static ide_startstop_t do_special (ide_drive_t *drive)
printk("%s: do_special: 0x%02x\n", drive->name, s->all);
#endif
if (s->b.set_tune) {
+ ide_hwif_t *hwif = drive->hwif;
+ u8 req_pio = drive->tune_req;
+
s->b.set_tune = 0;
- if (HWIF(drive)->tuneproc != NULL)
- HWIF(drive)->tuneproc(drive, drive->tune_req);
+
+ if (set_pio_mode_abuse(drive->hwif, req_pio)) {
+
+ if (hwif->set_pio_mode == NULL)
+ return ide_stopped;
+
+ /*
+ * take ide_lock for drive->[no_]unmask/[no_]io_32bit
+ */
+ if (req_pio == 8 || req_pio == 9) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&ide_lock, flags);
+ hwif->set_pio_mode(drive, req_pio);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ } else
+ hwif->set_pio_mode(drive, req_pio);
+ } else {
+ int keep_dma = drive->using_dma;
+
+ ide_set_pio(drive, req_pio);
+
+ if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
+ if (keep_dma)
+ hwif->ide_dma_on(drive);
+ }
+ }
+
return ide_stopped;
} else {
if (drive->media == ide_disk)
@@ -842,7 +839,8 @@ void ide_init_sg_cmd(ide_drive_t *drive, struct request *rq)
ide_hwif_t *hwif = drive->hwif;
hwif->nsect = hwif->nleft = rq->nr_sectors;
- hwif->cursg = hwif->cursg_ofs = 0;
+ hwif->cursg_ofs = 0;
+ hwif->cursg = NULL;
}
EXPORT_SYMBOL_GPL(ide_init_sg_cmd);
@@ -887,7 +885,6 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
return do_rw_taskfile(drive, args);
} else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {
u8 *args = rq->buffer;
- u8 sel;
if (!args)
goto done;
@@ -905,10 +902,7 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
hwif->OUTB(args[3], IDE_SECTOR_REG);
hwif->OUTB(args[4], IDE_LCYL_REG);
hwif->OUTB(args[5], IDE_HCYL_REG);
- sel = (args[6] & ~0x10);
- if (drive->select.b.unit)
- sel |= 0x10;
- hwif->OUTB(sel, IDE_SELECT_REG);
+ hwif->OUTB((args[6] & 0xEF)|drive->select.all, IDE_SELECT_REG);
ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
return ide_started;
} else if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 646a54e233d..e17a9ee120e 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -403,8 +403,12 @@ void ide_fix_driveid (struct hd_driveid *id)
#endif
}
-/* FIXME: exported for use by the USB storage (isd200.c) code only */
-EXPORT_SYMBOL(ide_fix_driveid);
+/*
+ * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
+ * removing leading/trailing blanks and compressing internal blanks.
+ * It is primarily used to tidy up the model name/number fields as
+ * returned by the WIN_[P]IDENTIFY commands.
+ */
void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
{
@@ -473,57 +477,22 @@ int drive_is_ready (ide_drive_t *drive)
EXPORT_SYMBOL(drive_is_ready);
/*
- * Global for All, and taken from ide-pmac.c. Can be called
- * with spinlock held & IRQs disabled, so don't schedule !
- */
-int wait_for_ready (ide_drive_t *drive, int timeout)
-{
- ide_hwif_t *hwif = HWIF(drive);
- u8 stat = 0;
-
- while(--timeout) {
- stat = hwif->INB(IDE_STATUS_REG);
- if (!(stat & BUSY_STAT)) {
- if (drive->ready_stat == 0)
- break;
- else if ((stat & drive->ready_stat)||(stat & ERR_STAT))
- break;
- }
- mdelay(1);
- }
- if ((stat & ERR_STAT) || timeout <= 0) {
- if (stat & ERR_STAT) {
- printk(KERN_ERR "%s: wait_for_ready, "
- "error status: %x\n", drive->name, stat);
- }
- return 1;
- }
- return 0;
-}
-
-/*
* This routine busy-waits for the drive status to be not "busy".
* It then checks the status for all of the "good" bits and none
* of the "bad" bits, and if all is okay it returns 0. All other
- * cases return 1 after invoking ide_error() -- caller should just return.
+ * cases return error -- caller may then invoke ide_error().
*
* This routine should get fixed to not hog the cpu during extra long waits..
* That could be done by busy-waiting for the first jiffy or two, and then
* setting a timer to wake up at half second intervals thereafter,
* until timeout is achieved, before timing out.
*/
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout, u8 *rstat)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 stat;
- int i;
+ ide_hwif_t *hwif = drive->hwif;
unsigned long flags;
-
- /* bail early if we've exceeded max_failures */
- if (drive->max_failures && (drive->failures > drive->max_failures)) {
- *startstop = ide_stopped;
- return 1;
- }
+ int i;
+ u8 stat;
udelay(1); /* spec allows drive 400ns to assert "BUSY" */
if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
@@ -541,8 +510,8 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 b
break;
local_irq_restore(flags);
- *startstop = ide_error(drive, "status timeout", stat);
- return 1;
+ *rstat = stat;
+ return -EBUSY;
}
}
local_irq_restore(flags);
@@ -556,11 +525,39 @@ int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 b
*/
for (i = 0; i < 10; i++) {
udelay(1);
- if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad))
+ if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad)) {
+ *rstat = stat;
return 0;
+ }
}
- *startstop = ide_error(drive, "status error", stat);
- return 1;
+ *rstat = stat;
+ return -EFAULT;
+}
+
+/*
+ * In case of error returns error value after doing "*startstop = ide_error()".
+ * The caller should return the updated value of "startstop" in this case,
+ * "startstop" is unchanged when the function returns 0.
+ */
+int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout)
+{
+ int err;
+ u8 stat;
+
+ /* bail early if we've exceeded max_failures */
+ if (drive->max_failures && (drive->failures > drive->max_failures)) {
+ *startstop = ide_stopped;
+ return 1;
+ }
+
+ err = __ide_wait_stat(drive, good, bad, timeout, &stat);
+
+ if (err) {
+ char *s = (err == -EBUSY) ? "status timeout" : "status error";
+ *startstop = ide_error(drive, s, stat);
+ }
+
+ return err;
}
EXPORT_SYMBOL(ide_wait_stat);
@@ -589,9 +586,12 @@ EXPORT_SYMBOL_GPL(ide_in_drive_list);
/*
* Early UDMA66 devices don't set bit14 to 1, only bit13 is valid.
* We list them here and depend on the device side cable detection for them.
+ *
+ * Some optical devices with the buggy firmwares have the same problem.
*/
static const struct drive_list_entry ivb_list[] = {
{ "QUANTUM FIREBALLlct10 05" , "A03.0900" },
+ { "TSSTcorp CDDVDW SH-S202J" , "SB00" },
{ NULL , NULL }
};
@@ -620,15 +620,10 @@ u8 eighty_ninty_three (ide_drive_t *drive)
/*
* FIXME:
- * - change master/slave IDENTIFY order
* - force bit13 (80c cable present) check also for !ivb devices
* (unless the slave device is pre-ATA3)
*/
-#ifndef CONFIG_IDEDMA_IVB
if ((id->hw_config & 0x4000) || (ivb && (id->hw_config & 0x2000)))
-#else
- if (id->hw_config & 0x6000)
-#endif
return 1;
no_80w:
@@ -705,35 +700,16 @@ static u8 ide_auto_reduce_xfer (ide_drive_t *drive)
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
-/*
- * Update the
- */
-int ide_driveid_update (ide_drive_t *drive)
+int ide_driveid_update(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ ide_hwif_t *hwif = drive->hwif;
struct hd_driveid *id;
-#if 0
- id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
- if (!id)
- return 0;
-
- taskfile_lib_get_identify(drive, (char *)&id);
+ unsigned long timeout, flags;
- ide_fix_driveid(id);
- if (id) {
- drive->id->dma_ultra = id->dma_ultra;
- drive->id->dma_mword = id->dma_mword;
- drive->id->dma_1word = id->dma_1word;
- /* anything more ? */
- kfree(id);
- }
- return 1;
-#else
/*
* Re-read drive->id for possible DMA mode
* change (copied from ide-probe.c)
*/
- unsigned long timeout, flags;
SELECT_MASK(drive, 1);
if (IDE_CONTROL_REG)
@@ -775,31 +751,19 @@ int ide_driveid_update (ide_drive_t *drive)
}
return 1;
-#endif
}
-/*
- * Similar to ide_wait_stat(), except it never calls ide_error internally.
- * This is a kludge to handle the new ide_config_drive_speed() function,
- * and should not otherwise be used anywhere. Eventually, the tuneproc's
- * should be updated to return ide_startstop_t, in which case we can get
- * rid of this abomination again. :) -ml
- *
- * It is gone..........
- *
- * const char *msg == consider adding for verbose errors.
- */
-int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
+int ide_config_drive_speed(ide_drive_t *drive, u8 speed)
{
- ide_hwif_t *hwif = HWIF(drive);
- int i, error = 1;
+ ide_hwif_t *hwif = drive->hwif;
+ int error;
u8 stat;
// while (HWGROUP(drive)->busy)
// msleep(50);
#ifdef CONFIG_BLK_DEV_IDEDMA
- if (hwif->ide_dma_check) /* check if host supports DMA */
+ if (hwif->ide_dma_on) /* check if host supports DMA */
hwif->dma_host_off(drive);
#endif
@@ -832,35 +796,10 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
- udelay(1);
- /*
- * Wait for drive to become non-BUSY
- */
- if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
- unsigned long flags, timeout;
- local_irq_set(flags);
- timeout = jiffies + WAIT_CMD;
- while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {
- if (time_after(jiffies, timeout))
- break;
- }
- local_irq_restore(flags);
- }
- /*
- * Allow status to settle, then read it again.
- * A few rare drives vastly violate the 400ns spec here,
- * so we'll wait up to 10usec for a "good" status
- * rather than expensively fail things immediately.
- * This fix courtesy of Matthew Faupel & Niccolo Rigacci.
- */
- for (i = 0; i < 10; i++) {
- udelay(1);
- if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), drive->ready_stat, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
- error = 0;
- break;
- }
- }
+ error = __ide_wait_stat(drive, drive->ready_stat,
+ BUSY_STAT|DRQ_STAT|ERR_STAT,
+ WAIT_CMD, &stat);
SELECT_MASK(drive, 0);
@@ -878,7 +817,7 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
#ifdef CONFIG_BLK_DEV_IDEDMA
if (speed >= XFER_SW_DMA_0)
hwif->dma_host_on(drive);
- else if (hwif->ide_dma_check) /* check if host supports DMA */
+ else if (hwif->ide_dma_on) /* check if host supports DMA */
hwif->dma_off_quietly(drive);
#endif
@@ -905,9 +844,6 @@ int ide_config_drive_speed (ide_drive_t *drive, u8 speed)
return error;
}
-EXPORT_SYMBOL(ide_config_drive_speed);
-
-
/*
* This should get invoked any time we exit the driver to
* wait for an interrupt response from a drive. handler() points
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 92a6c7bcf52..1609b8604f5 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -76,56 +76,26 @@ EXPORT_SYMBOL(ide_xfer_verbose);
* Given the available transfer modes this function returns
* the best available speed at or below the speed requested.
*
- * FIXME: filter also PIO/SWDMA/MWDMA modes
+ * TODO: check device PIO capabilities
*/
-u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
+static u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
{
-#ifdef CONFIG_BLK_DEV_IDEDMA
ide_hwif_t *hwif = drive->hwif;
- u8 mask = hwif->ultra_mask, mode = XFER_MW_DMA_2;
+ u8 mode = ide_find_dma_mode(drive, speed);
- if (hwif->udma_filter)
- mask = hwif->udma_filter(drive);
-
- /*
- * TODO: speed > XFER_UDMA_2 extra check is needed to avoid false
- * cable warning from eighty_ninty_three(), moving ide_rate_filter()
- * calls from ->speedproc to core code will make this hack go away
- */
- if (speed > XFER_UDMA_2) {
- if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
- mask &= 0x07;
+ if (mode == 0) {
+ if (hwif->pio_mask)
+ mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0;
+ else
+ mode = XFER_PIO_4;
}
- if (mask)
- mode = fls(mask) - 1 + XFER_UDMA_0;
-
// printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
return min(speed, mode);
-#else /* !CONFIG_BLK_DEV_IDEDMA */
- return min(speed, (u8)XFER_PIO_4);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-EXPORT_SYMBOL(ide_rate_filter);
-
-int ide_use_fast_pio(ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
-
- if ((id->capability & 1) && drive->autodma)
- return 1;
-
- if ((id->capability & 8) || (id->field_valid & 2))
- return 1;
-
- return 0;
}
-EXPORT_SYMBOL_GPL(ide_use_fast_pio);
-
/*
* Standard (generic) timings for PIO modes, from ATA2 specification.
* These timings are for access to the IDE data port register *only*.
@@ -340,6 +310,35 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
+/* req_pio == "255" for auto-tune */
+void ide_set_pio(ide_drive_t *drive, u8 req_pio)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 host_pio, pio;
+
+ if (hwif->set_pio_mode == NULL)
+ return;
+
+ BUG_ON(hwif->pio_mask == 0x00);
+
+ host_pio = fls(hwif->pio_mask) - 1;
+
+ pio = ide_get_best_pio_mode(drive, req_pio, host_pio);
+
+ /*
+ * TODO:
+ * - report device max PIO mode
+ * - check req_pio != 255 against device max PIO mode
+ */
+ printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n",
+ drive->name, host_pio, req_pio,
+ req_pio == 255 ? "(auto-tune)" : "", pio);
+
+ (void)ide_set_pio_mode(drive, XFER_PIO_0 + pio);
+}
+
+EXPORT_SYMBOL_GPL(ide_set_pio);
+
/**
* ide_toggle_bounce - handle bounce buffering
* @drive: drive to update
@@ -364,26 +363,83 @@ void ide_toggle_bounce(ide_drive_t *drive, int on)
blk_queue_bounce_limit(drive->queue, addr);
}
+int ide_set_pio_mode(ide_drive_t *drive, const u8 mode)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ if (hwif->set_pio_mode == NULL)
+ return -1;
+
+ /*
+ * TODO: temporary hack for some legacy host drivers that didn't
+ * set transfer mode on the device in ->set_pio_mode method...
+ */
+ if (hwif->set_dma_mode == NULL) {
+ hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+ return 0;
+ }
+
+ if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
+ if (ide_config_drive_speed(drive, mode))
+ return -1;
+ hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+ return 0;
+ } else {
+ hwif->set_pio_mode(drive, mode - XFER_PIO_0);
+ return ide_config_drive_speed(drive, mode);
+ }
+}
+
+int ide_set_dma_mode(ide_drive_t *drive, const u8 mode)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ if (hwif->set_dma_mode == NULL)
+ return -1;
+
+ if (hwif->host_flags & IDE_HFLAG_POST_SET_MODE) {
+ if (ide_config_drive_speed(drive, mode))
+ return -1;
+ hwif->set_dma_mode(drive, mode);
+ return 0;
+ } else {
+ hwif->set_dma_mode(drive, mode);
+ return ide_config_drive_speed(drive, mode);
+ }
+}
+
+EXPORT_SYMBOL_GPL(ide_set_dma_mode);
+
/**
* ide_set_xfer_rate - set transfer rate
* @drive: drive to set
- * @speed: speed to attempt to set
+ * @rate: speed to attempt to set
*
* General helper for setting the speed of an IDE device. This
* function knows about user enforced limits from the configuration
- * which speedproc() does not. High level drivers should never
- * invoke speedproc() directly.
+ * which ->set_pio_mode/->set_dma_mode does not.
*/
-
+
int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
{
-#ifndef CONFIG_BLK_DEV_IDEDMA
- rate = min(rate, (u8) XFER_PIO_4);
-#endif
- if(HWIF(drive)->speedproc)
- return HWIF(drive)->speedproc(drive, rate);
- else
+ ide_hwif_t *hwif = drive->hwif;
+
+ if (hwif->set_dma_mode == NULL)
return -1;
+
+ rate = ide_rate_filter(drive, rate);
+
+ if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5)
+ return ide_set_pio_mode(drive, rate);
+
+ /*
+ * TODO: transfer modes 0x00-0x07 passed from the user-space are
+ * currently handled here which needs fixing (please note that such
+ * case could happen iff the transfer mode has already been set on
+ * the device by ide-proc.c::set_xfer_rate()).
+ */
+
+ return ide_set_dma_mode(drive, rate);
}
static void ide_dump_opcode(ide_drive_t *drive)
@@ -458,6 +514,7 @@ static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
if (drive->addressing == 1) {
__u64 sectors = 0;
u32 low = 0, high = 0;
+ hwif->OUTB(drive->ctl&~0x80, IDE_CONTROL_REG);
low = ide_read_24(drive);
hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
high = ide_read_24(drive);
diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
index 2b8009c50e9..e245521af7b 100644
--- a/drivers/ide/ide-pnp.c
+++ b/drivers/ide/ide-pnp.c
@@ -40,9 +40,8 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id
ide_std_init_ports(&hw, pnp_port_start(dev, 0),
pnp_port_start(dev, 1));
hw.irq = pnp_irq(dev, 0);
- hw.dma = NO_DMA;
- index = ide_register_hw(&hw, 1, &hwif);
+ index = ide_register_hw(&hw, NULL, 1, &hwif);
if (index != -1) {
printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 3a2a9a338fd..56fb0b84342 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -47,6 +47,7 @@
#include <linux/spinlock.h>
#include <linux/kmod.h>
#include <linux/pci.h>
+#include <linux/scatterlist.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
@@ -171,11 +172,12 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
ide_fixstring(id->fw_rev, sizeof(id->fw_rev), bswap);
ide_fixstring(id->serial_no, sizeof(id->serial_no), bswap);
+ /* we depend on this a lot! */
+ id->model[sizeof(id->model)-1] = '\0';
+
if (strstr(id->model, "E X A B Y T E N E S T"))
goto err_misc;
- /* we depend on this a lot! */
- id->model[sizeof(id->model)-1] = '\0';
printk("%s: %s, ", drive->name, id->model);
drive->present = 1;
drive->dead = 0;
@@ -717,11 +719,11 @@ EXPORT_SYMBOL_GPL(ide_undecoded_slave);
* This routine only knows how to look for drive units 0 and 1
* on an interface, so any setting of MAX_DRIVES > 2 won't work here.
*/
-static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
+static void probe_hwif(ide_hwif_t *hwif)
{
- unsigned int unit;
unsigned long flags;
unsigned int irqd;
+ int unit;
if (hwif->noprobe)
return;
@@ -777,10 +779,9 @@ static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
printk(KERN_DEBUG "%s: Wait for ready failed before probe !\n", hwif->name);
/*
- * Second drive should only exist if first drive was found,
- * but a lot of cdrom drives are configured as single slaves.
+ * Need to probe slave device first to make it release PDIAG-.
*/
- for (unit = 0; unit < MAX_DRIVES; ++unit) {
+ for (unit = MAX_DRIVES - 1; unit >= 0; unit--) {
ide_drive_t *drive = &hwif->drives[unit];
drive->dn = (hwif->channel ? 2 : 0) + unit;
(void) probe_for_drive(drive);
@@ -820,17 +821,15 @@ static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
return;
}
- if (fixup)
- fixup(hwif);
+ if (hwif->fixup)
+ hwif->fixup(hwif);
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
if (drive->present) {
- if (hwif->tuneproc != NULL &&
- drive->autotune == IDE_TUNE_AUTO)
- /* auto-tune PIO mode */
- hwif->tuneproc(drive, 255);
+ if (drive->autotune == IDE_TUNE_AUTO)
+ ide_set_max_pio(drive);
if (drive->autotune != IDE_TUNE_DEFAULT &&
drive->autotune != IDE_TUNE_AUTO)
@@ -838,16 +837,7 @@ static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
drive->nice1 = 1;
- /*
- * MAJOR HACK BARF :-/
- *
- * FIXME: chipsets own this cruft!
- */
- /*
- * Move here to prevent module loading clashing.
- */
- // drive->autodma = hwif->autodma;
- if (hwif->ide_dma_check) {
+ if (hwif->ide_dma_on) {
/*
* Force DMAing for the beginning of the check.
* Some chipsets appear to do interesting
@@ -855,10 +845,7 @@ static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
* PARANOIA!!!
*/
hwif->dma_off_quietly(drive);
-#ifdef CONFIG_IDEDMA_ONLYDISK
- if (drive->media == ide_disk)
-#endif
- ide_set_dma(drive);
+ ide_set_dma(drive);
}
}
}
@@ -874,10 +861,11 @@ static void probe_hwif(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
}
static int hwif_init(ide_hwif_t *hwif);
+static void hwif_register_devices(ide_hwif_t *hwif);
-int probe_hwif_init_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif))
+static int probe_hwif_init(ide_hwif_t *hwif)
{
- probe_hwif(hwif, fixup);
+ probe_hwif(hwif);
if (!hwif_init(hwif)) {
printk(KERN_INFO "%s: failed to initialize IDE interface\n",
@@ -885,34 +873,12 @@ int probe_hwif_init_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif)
return -1;
}
- if (hwif->present) {
- u16 unit = 0;
- int ret;
+ if (hwif->present)
+ hwif_register_devices(hwif);
- for (unit = 0; unit < MAX_DRIVES; ++unit) {
- ide_drive_t *drive = &hwif->drives[unit];
- /* For now don't attach absent drives, we may
- want them on default or a new "empty" class
- for hotplug reprobing ? */
- if (drive->present) {
- ret = device_register(&drive->gendev);
- if (ret < 0)
- printk(KERN_WARNING "IDE: %s: "
- "device_register error: %d\n",
- __FUNCTION__, ret);
- }
- }
- }
return 0;
}
-int probe_hwif_init(ide_hwif_t *hwif)
-{
- return probe_hwif_init_with_fixup(hwif, NULL);
-}
-
-EXPORT_SYMBOL(probe_hwif_init);
-
#if MAX_HWIFS > 1
/*
* save_match() is used to simplify logic in init_irq() below.
@@ -966,7 +932,8 @@ static int ide_init_queue(ide_drive_t *drive)
blk_queue_segment_boundary(q, 0xffff);
if (!hwif->rqsize) {
- if (hwif->no_lba48 || hwif->no_lba48_dma)
+ if ((hwif->host_flags & IDE_HFLAG_NO_LBA48) ||
+ (hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA))
hwif->rqsize = 256;
else
hwif->rqsize = 65536;
@@ -1358,6 +1325,8 @@ static int hwif_init(ide_hwif_t *hwif)
printk(KERN_ERR "%s: unable to allocate SG table.\n", hwif->name);
goto out;
}
+
+ sg_init_table(hwif->sg_table, hwif->sg_max_nents);
if (init_irq(hwif) == 0)
goto done;
@@ -1393,6 +1362,24 @@ out:
return 0;
}
+static void hwif_register_devices(ide_hwif_t *hwif)
+{
+ unsigned int i;
+
+ for (i = 0; i < MAX_DRIVES; i++) {
+ ide_drive_t *drive = &hwif->drives[i];
+
+ if (drive->present) {
+ int ret = device_register(&drive->gendev);
+
+ if (ret < 0)
+ printk(KERN_WARNING "IDE: %s: "
+ "device_register error: %d\n",
+ __FUNCTION__, ret);
+ }
+ }
+}
+
int ideprobe_init (void)
{
unsigned int index;
@@ -1404,27 +1391,18 @@ int ideprobe_init (void)
for (index = 0; index < MAX_HWIFS; ++index)
if (probe[index])
- probe_hwif(&ide_hwifs[index], NULL);
+ probe_hwif(&ide_hwifs[index]);
for (index = 0; index < MAX_HWIFS; ++index)
if (probe[index])
hwif_init(&ide_hwifs[index]);
for (index = 0; index < MAX_HWIFS; ++index) {
if (probe[index]) {
ide_hwif_t *hwif = &ide_hwifs[index];
- int unit;
if (!hwif->present)
continue;
if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced)
hwif->chipset = ide_generic;
- for (unit = 0; unit < MAX_DRIVES; ++unit)
- if (hwif->drives[unit].present) {
- int ret = device_register(
- &hwif->drives[unit].gendev);
- if (ret < 0)
- printk(KERN_WARNING "IDE: %s: "
- "device_register error: %d\n",
- __FUNCTION__, ret);
- }
+ hwif_register_devices(hwif);
}
}
for (index = 0; index < MAX_HWIFS; ++index)
@@ -1434,3 +1412,22 @@ int ideprobe_init (void)
}
EXPORT_SYMBOL_GPL(ideprobe_init);
+
+int ide_device_add(u8 idx[4])
+{
+ int i, rc = 0;
+
+ for (i = 0; i < 4; i++) {
+ if (idx[i] != 0xff)
+ rc |= probe_hwif_init(&ide_hwifs[idx[i]]);
+ }
+
+ for (i = 0; i < 4; i++) {
+ if (idx[i] != 0xff)
+ ide_proc_register_port(&ide_hwifs[idx[i]]);
+ }
+
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(ide_device_add);
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index fc1d8ae6a80..a4007d30da5 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -804,8 +804,6 @@ void ide_proc_register_port(ide_hwif_t *hwif)
create_proc_ide_drives(hwif);
}
-EXPORT_SYMBOL_GPL(ide_proc_register_port);
-
#ifdef CONFIG_BLK_DEV_IDEPCI
void ide_pci_create_host_proc(const char *name, get_info_t *get_info)
{
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 1fa57947bca..7b9181b5469 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -565,7 +565,7 @@ typedef struct os_dat_s {
* The following parameter is used to select the point in the internal
* tape fifo in which we will start to refill the buffer. Decreasing
* the following parameter will improve the system's latency and
- * interactive response, while using a high value might improve sytem
+ * interactive response, while using a high value might improve system
* throughput.
*/
#define IDETAPE_FIFO_THRESHOLD 2
@@ -621,7 +621,6 @@ typedef struct os_dat_s {
*/
#define USE_IOTRACE 0
#if USE_IOTRACE
-#include <linux/io_trace.h>
#define IO_IDETAPE_FIFO 500
#endif
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index aa06dafb74a..2b60f1b0437 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -8,23 +8,6 @@
* Copyright (C) 2003-2004 Bartlomiej Zolnierkiewicz
*
* The big the bad and the ugly.
- *
- * Problems to be fixed because of BH interface or the lack therefore.
- *
- * Fill me in stupid !!!
- *
- * HOST:
- * General refers to the Controller and Driver "pair".
- * DATA HANDLER:
- * Under the context of Linux it generally refers to an interrupt handler.
- * However, it correctly describes the 'HOST'
- * DATA BLOCK:
- * The amount of data needed to be transfered as predefined in the
- * setup of the device.
- * STORAGE ATOMIC:
- * The 'DATA BLOCK' associated to the 'DATA HANDLER', and can be as
- * small as a single sector or as large as the entire command block
- * request.
*/
#include <linux/module.h>
@@ -45,6 +28,7 @@
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/bitops.h>
+#include <linux/scatterlist.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
@@ -263,6 +247,7 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
{
ide_hwif_t *hwif = drive->hwif;
struct scatterlist *sg = hwif->sg_table;
+ struct scatterlist *cursg = hwif->cursg;
struct page *page;
#ifdef CONFIG_HIGHMEM
unsigned long flags;
@@ -270,8 +255,14 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
unsigned int offset;
u8 *buf;
- page = sg[hwif->cursg].page;
- offset = sg[hwif->cursg].offset + hwif->cursg_ofs * SECTOR_SIZE;
+ cursg = hwif->cursg;
+ if (!cursg) {
+ cursg = sg;
+ hwif->cursg = sg;
+ }
+
+ page = sg_page(cursg);
+ offset = cursg->offset + hwif->cursg_ofs * SECTOR_SIZE;
/* get the current page and offset */
page = nth_page(page, (offset >> PAGE_SHIFT));
@@ -285,8 +276,8 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write)
hwif->nleft--;
hwif->cursg_ofs++;
- if ((hwif->cursg_ofs * SECTOR_SIZE) == sg[hwif->cursg].length) {
- hwif->cursg++;
+ if ((hwif->cursg_ofs * SECTOR_SIZE) == cursg->length) {
+ hwif->cursg = sg_next(hwif->cursg);
hwif->cursg_ofs = 0;
}
@@ -367,6 +358,8 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
{
+ HWIF(drive)->cursg = NULL;
+
if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
ide_task_t *task = rq->special;
@@ -478,6 +471,7 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long
struct request rq;
memset(&rq, 0, sizeof(rq));
+ rq.ref_count = 1;
rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
rq.buffer = buf;
@@ -518,6 +512,7 @@ int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf)
EXPORT_SYMBOL(ide_raw_taskfile);
+#ifdef CONFIG_IDE_TASK_IOCTL
int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
{
ide_task_request_t *req_task;
@@ -667,6 +662,7 @@ abort:
return err;
}
+#endif
int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
{
@@ -685,9 +681,6 @@ int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors,
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
-/*
- * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
- */
int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
{
int err = 0;
@@ -751,9 +744,6 @@ static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf)
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
-/*
- * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
- */
int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
{
void __user *p = (void __user *)arg;
@@ -850,9 +840,14 @@ ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
case TASKFILE_OUT_DMA:
case TASKFILE_IN_DMAQ:
case TASKFILE_IN_DMA:
- hwif->dma_setup(drive);
- hwif->dma_exec_cmd(drive, taskfile->command);
- hwif->dma_start(drive);
+ if (!drive->using_dma)
+ break;
+
+ if (!hwif->dma_setup(drive)) {
+ hwif->dma_exec_cmd(drive, taskfile->command);
+ hwif->dma_start(drive);
+ return ide_started;
+ }
break;
default:
@@ -866,7 +861,8 @@ ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
return task->prehandler(drive, task->rq);
}
ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
+ return ide_started;
}
- return ide_started;
+ return ide_stopped;
}
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 5e88a060df0..674a65c1a13 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -100,8 +100,6 @@ static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */
int noautodma = 0;
-EXPORT_SYMBOL(noautodma);
-
#ifdef CONFIG_BLK_DEV_IDEACPI
int ide_noacpi = 0;
int ide_noacpitfs = 1;
@@ -136,8 +134,6 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
hwif->bus_state = BUSSTATE_ON;
- hwif->atapi_dma = 0; /* disable all atapi dma */
-
init_completion(&hwif->gendev_rel_comp);
default_hwif_iops(hwif);
@@ -172,7 +168,6 @@ static void init_hwif_default(ide_hwif_t *hwif, unsigned int index)
ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &hwif->irq);
- memcpy(&hwif->hw, &hw, sizeof(hw));
memcpy(hwif->io_ports, hw.io_ports, sizeof(hw.io_ports));
hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
@@ -218,7 +213,7 @@ static void __init init_ide_data (void)
init_hwif_data(hwif, index);
init_hwif_default(hwif, index);
#if !defined(CONFIG_PPC32) || !defined(CONFIG_PCI)
- hwif->irq = hwif->hw.irq =
+ hwif->irq =
ide_init_default_irq(hwif->io_ports[IDE_DATA_OFFSET]);
#endif
}
@@ -269,6 +264,30 @@ static int ide_system_bus_speed(void)
return system_bus_speed;
}
+ide_hwif_t * ide_find_port(unsigned long base)
+{
+ ide_hwif_t *hwif;
+ int i;
+
+ for (i = 0; i < MAX_HWIFS; i++) {
+ hwif = &ide_hwifs[i];
+ if (hwif->io_ports[IDE_DATA_OFFSET] == base)
+ goto found;
+ }
+
+ for (i = 0; i < MAX_HWIFS; i++) {
+ hwif = &ide_hwifs[i];
+ if (hwif->io_ports[IDE_DATA_OFFSET] == 0)
+ goto found;
+ }
+
+ hwif = NULL;
+found:
+ return hwif;
+}
+
+EXPORT_SYMBOL_GPL(ide_find_port);
+
static struct resource* hwif_request_region(ide_hwif_t *hwif,
unsigned long addr, int num)
{
@@ -381,7 +400,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
hwif->pio_mask = tmp_hwif->pio_mask;
- hwif->atapi_dma = tmp_hwif->atapi_dma;
hwif->ultra_mask = tmp_hwif->ultra_mask;
hwif->mwdma_mask = tmp_hwif->mwdma_mask;
hwif->swdma_mask = tmp_hwif->swdma_mask;
@@ -396,8 +414,11 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
hwif->cds = tmp_hwif->cds;
#endif
- hwif->tuneproc = tmp_hwif->tuneproc;
- hwif->speedproc = tmp_hwif->speedproc;
+ hwif->fixup = tmp_hwif->fixup;
+
+ hwif->set_pio_mode = tmp_hwif->set_pio_mode;
+ hwif->set_dma_mode = tmp_hwif->set_dma_mode;
+ hwif->mdma_filter = tmp_hwif->mdma_filter;
hwif->udma_filter = tmp_hwif->udma_filter;
hwif->selectproc = tmp_hwif->selectproc;
hwif->reset_poll = tmp_hwif->reset_poll;
@@ -417,7 +438,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
hwif->dma_exec_cmd = tmp_hwif->dma_exec_cmd;
hwif->dma_start = tmp_hwif->dma_start;
hwif->ide_dma_end = tmp_hwif->ide_dma_end;
- hwif->ide_dma_check = tmp_hwif->ide_dma_check;
hwif->ide_dma_on = tmp_hwif->ide_dma_on;
hwif->dma_off_quietly = tmp_hwif->dma_off_quietly;
hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq;
@@ -442,7 +462,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
hwif->mmio = tmp_hwif->mmio;
hwif->rqsize = tmp_hwif->rqsize;
- hwif->no_lba48 = tmp_hwif->no_lba48;
#ifndef CONFIG_BLK_DEV_IDECS
hwif->irq = tmp_hwif->irq;
@@ -460,7 +479,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
hwif->select_data = tmp_hwif->select_data;
hwif->extra_base = tmp_hwif->extra_base;
hwif->extra_ports = tmp_hwif->extra_ports;
- hwif->autodma = tmp_hwif->autodma;
hwif->hwif_data = tmp_hwif->hwif_data;
}
@@ -659,7 +677,6 @@ void ide_setup_ports ( hw_regs_t *hw,
}
}
hw->irq = irq;
- hw->dma = NO_DMA;
hw->ack_intr = ack_intr;
/*
* hw->iops = iops;
@@ -667,11 +684,11 @@ void ide_setup_ports ( hw_regs_t *hw,
}
/**
- * ide_register_hw_with_fixup - register IDE interface
+ * ide_register_hw - register IDE interface
* @hw: hardware registers
+ * @fixup: fixup function
* @initializing: set while initializing built-in drivers
* @hwifp: pointer to returned hwif
- * @fixup: fixup function
*
* Register an IDE interface, specifying exactly the registers etc.
* Set init=1 iff calling before probes have taken place.
@@ -679,9 +696,8 @@ void ide_setup_ports ( hw_regs_t *hw,
* Returns -1 on error.
*/
-int ide_register_hw_with_fixup(hw_regs_t *hw, int initializing,
- ide_hwif_t **hwifp,
- void(*fixup)(ide_hwif_t *hwif))
+int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *),
+ int initializing, ide_hwif_t **hwifp)
{
int index, retry = 1;
ide_hwif_t *hwif;
@@ -689,7 +705,7 @@ int ide_register_hw_with_fixup(hw_regs_t *hw, int initializing,
do {
for (index = 0; index < MAX_HWIFS; ++index) {
hwif = &ide_hwifs[index];
- if (hwif->hw.io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET])
+ if (hwif->io_ports[IDE_DATA_OFFSET] == hw->io_ports[IDE_DATA_OFFSET])
goto found;
}
for (index = 0; index < MAX_HWIFS; ++index) {
@@ -697,7 +713,7 @@ int ide_register_hw_with_fixup(hw_regs_t *hw, int initializing,
if (hwif->hold)
continue;
if ((!hwif->present && !hwif->mate && !initializing) ||
- (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing))
+ (!hwif->io_ports[IDE_DATA_OFFSET] && initializing))
goto found;
}
for (index = 0; index < MAX_HWIFS; index++)
@@ -713,16 +729,18 @@ found:
}
if (hwif->present)
return -1;
- memcpy(&hwif->hw, hw, sizeof(*hw));
- memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
+ memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
hwif->irq = hw->irq;
hwif->noprobe = 0;
+ hwif->fixup = fixup;
hwif->chipset = hw->chipset;
hwif->gendev.parent = hw->dev;
+ hwif->ack_intr = hw->ack_intr;
+
+ if (initializing == 0) {
+ u8 idx[4] = { index, 0xff, 0xff, 0xff };
- if (!initializing) {
- probe_hwif_init_with_fixup(hwif, fixup);
- ide_proc_register_port(hwif);
+ ide_device_add(idx);
}
if (hwifp)
@@ -731,13 +749,6 @@ found:
return (initializing || hwif->present) ? index : -1;
}
-EXPORT_SYMBOL(ide_register_hw_with_fixup);
-
-int ide_register_hw(hw_regs_t *hw, int initializing, ide_hwif_t **hwifp)
-{
- return ide_register_hw_with_fixup(hw, initializing, hwifp, NULL);
-}
-
EXPORT_SYMBOL(ide_register_hw);
/*
@@ -822,7 +833,7 @@ int set_using_dma(ide_drive_t *drive, int arg)
if (!drive->id || !(drive->id->capability & 1))
goto out;
- if (hwif->ide_dma_check == NULL)
+ if (hwif->ide_dma_on == NULL)
goto out;
err = -EBUSY;
@@ -866,8 +877,9 @@ int set_pio_mode(ide_drive_t *drive, int arg)
if (arg < 0 || arg > 255)
return -EINVAL;
- if (!HWIF(drive)->tuneproc)
+ if (drive->hwif->set_pio_mode == NULL)
return -ENOSYS;
+
if (drive->special.b.set_tune)
return -EBUSY;
ide_init_drive_cmd(&rq);
@@ -914,6 +926,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
struct request rq;
struct request_pm_state rqpm;
ide_task_t args;
+ int ret;
/* Call ACPI _GTM only once */
if (!(drive->dn % 2))
@@ -930,7 +943,14 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
mesg.event = PM_EVENT_FREEZE;
rqpm.pm_state = mesg.event;
- return ide_do_drive_cmd(drive, &rq, ide_wait);
+ ret = ide_do_drive_cmd(drive, &rq, ide_wait);
+ /* only call ACPI _PS3 after both drivers are suspended */
+ if (!ret && (((drive->dn % 2) && hwif->drives[0].present
+ && hwif->drives[1].present)
+ || !hwif->drives[0].present
+ || !hwif->drives[1].present))
+ ide_acpi_set_state(hwif, 0);
+ return ret;
}
static int generic_ide_resume(struct device *dev)
@@ -943,8 +963,10 @@ static int generic_ide_resume(struct device *dev)
int err;
/* Call ACPI _STM only once */
- if (!(drive->dn % 2))
+ if (!(drive->dn % 2)) {
+ ide_acpi_set_state(hwif, 1);
ide_acpi_push_timing(hwif);
+ }
ide_acpi_exec_tfs(drive);
@@ -1042,7 +1064,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
ide_init_hwif_ports(&hw, (unsigned long) args[0],
(unsigned long) args[1], NULL);
hw.irq = args[2];
- if (ide_register_hw(&hw, 0, NULL) == -1)
+ if (ide_register_hw(&hw, NULL, 0, NULL) == -1)
return -EIO;
return 0;
}
@@ -1264,7 +1286,7 @@ static int __init ide_setup(char *s)
if (!strcmp(s, "ide=nodma")) {
printk(" : Prevented DMA\n");
noautodma = 1;
- return 1;
+ goto obsolete_option;
}
#ifdef CONFIG_IDEPCI_PCIBUS_ORDER
@@ -1298,7 +1320,7 @@ static int __init ide_setup(char *s)
*/
if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) {
const char *hd_words[] = {
- "none", "noprobe", "nowerr", "cdrom", "minus5",
+ "none", "noprobe", "nowerr", "cdrom", "nodma",
"autotune", "noautotune", "minus8", "swapdata", "bswap",
"noflush", "remap", "remap63", "scsi", NULL };
unit = s[2] - 'a';
@@ -1326,6 +1348,9 @@ static int __init ide_setup(char *s)
drive->ready_stat = 0;
hwif->noprobe = 0;
goto done;
+ case -5: /* nodma */
+ drive->nodma = 1;
+ goto done;
case -6: /* "autotune" */
drive->autotune = IDE_TUNE_AUTO;
goto obsolete_option;
@@ -1387,9 +1412,12 @@ static int __init ide_setup(char *s)
*/
static const char *ide_words[] = {
"noprobe", "serialize", "minus3", "minus4",
- "reset", "dma", "ata66", "minus8", "minus9",
+ "reset", "minus6", "ata66", "minus8", "minus9",
"minus10", "four", "qd65xx", "ht6560b", "cmd640_vlb",
"dtc2278", "umc8672", "ali14xx", NULL };
+
+ hw_regs_t hwregs;
+
hw = s[3] - '0';
hwif = &ide_hwifs[hw];
i = match_parm(&s[4], ide_words, vals, 3);
@@ -1466,6 +1494,7 @@ static int __init ide_setup(char *s)
case -10: /* minus10 */
case -9: /* minus9 */
case -8: /* minus8 */
+ case -6:
case -4:
case -3:
goto bad_option;
@@ -1480,9 +1509,6 @@ static int __init ide_setup(char *s)
#else
goto bad_hwif;
#endif
- case -6: /* dma */
- hwif->autodma = 1;
- goto obsolete_option;
case -5: /* "reset" */
hwif->reset = 1;
goto obsolete_option;
@@ -1501,9 +1527,9 @@ static int __init ide_setup(char *s)
case 2: /* base,ctl */
vals[2] = 0; /* default irq = probe for it */
case 3: /* base,ctl,irq */
- hwif->hw.irq = vals[2];
- ide_init_hwif_ports(&hwif->hw, (unsigned long) vals[0], (unsigned long) vals[1], &hwif->irq);
- memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+ memset(&hwregs, 0, sizeof(hwregs));
+ ide_init_hwif_ports(&hwregs, vals[0], vals[1], &hwif->irq);
+ memcpy(hwif->io_ports, hwregs.io_ports, sizeof(hwif->io_ports));
hwif->irq = vals[2];
hwif->noprobe = 0;
hwif->chipset = ide_forced;
@@ -1651,20 +1677,13 @@ static struct device_attribute ide_dev_attrs[] = {
__ATTR_NULL
};
-static int ide_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int ide_uevent(struct device *dev, struct kobj_uevent_env *env)
{
ide_drive_t *drive = to_ide_device(dev);
- int i = 0;
- int length = 0;
-
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MEDIA=%s", media_string(drive));
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "DRIVENAME=%s", drive->name);
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MODALIAS=ide:m-%s", media_string(drive));
- envp[i] = NULL;
+
+ add_uevent_var(env, "MEDIA=%s", media_string(drive));
+ add_uevent_var(env, "DRIVENAME=%s", drive->name);
+ add_uevent_var(env, "MODALIAS=ide:m-%s", media_string(drive));
return 0;
}
diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile
index c7971061767..409822349f1 100644
--- a/drivers/ide/legacy/Makefile
+++ b/drivers/ide/legacy/Makefile
@@ -7,6 +7,8 @@ obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o
obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o
+obj-$(CONFIG_BLK_DEV_PLATFORM) += ide_platform.o
+
# Last of all
obj-$(CONFIG_BLK_DEV_HD) += hd.o
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
index 9b9c4761cb7..10311ecc674 100644
--- a/drivers/ide/legacy/ali14xx.c
+++ b/drivers/ide/legacy/ali14xx.c
@@ -68,8 +68,6 @@ static RegInitializer initData[] __initdata = {
{0x35, 0x03}, {0x00, 0x00}
};
-#define ALI_MAX_PIO 4
-
/* timing parameter registers for each drive */
static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = {
{0x03, 0x26, 0x04, 0x27}, /* drive 0 */
@@ -104,12 +102,14 @@ static void outReg (u8 data, u8 reg)
outb_p(data, dataPort);
}
+static DEFINE_SPINLOCK(ali14xx_lock);
+
/*
* Set PIO mode for the specified drive.
* This function computes timing parameters
* and sets controller registers accordingly.
*/
-static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio)
+static void ali14xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
int driveNum;
int time1, time2;
@@ -117,8 +117,6 @@ static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio)
unsigned long flags;
int bus_speed = system_bus_clock();
- pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO);
-
/* calculate timing, according to PIO mode */
time1 = ide_pio_cycle_time(drive, pio);
time2 = ide_pio_timings[pio].active_time;
@@ -133,14 +131,14 @@ static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio)
/* stuff timing parameters into controller registers */
driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&ali14xx_lock, flags);
outb_p(regOn, basePort);
outReg(param1, regTab[driveNum].reg1);
outReg(param2, regTab[driveNum].reg2);
outReg(param3, regTab[driveNum].reg3);
outReg(param4, regTab[driveNum].reg4);
outb_p(regOff, basePort);
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&ali14xx_lock, flags);
}
/*
@@ -197,6 +195,7 @@ static int __init initRegisters (void) {
static int __init ali14xx_probe(void)
{
ide_hwif_t *hwif, *mate;
+ static u8 idx[4] = { 0, 1, 0xff, 0xff };
printk(KERN_DEBUG "ali14xx: base=0x%03x, regOn=0x%02x.\n",
basePort, regOn);
@@ -212,20 +211,16 @@ static int __init ali14xx_probe(void)
hwif->chipset = ide_ali14xx;
hwif->pio_mask = ATA_PIO4;
- hwif->tuneproc = &ali14xx_tune_drive;
+ hwif->set_pio_mode = &ali14xx_set_pio_mode;
hwif->mate = mate;
mate->chipset = ide_ali14xx;
mate->pio_mask = ATA_PIO4;
- mate->tuneproc = &ali14xx_tune_drive;
+ mate->set_pio_mode = &ali14xx_set_pio_mode;
mate->mate = hwif;
mate->channel = 1;
- probe_hwif_init(hwif);
- probe_hwif_init(mate);
-
- ide_proc_register_port(hwif);
- ide_proc_register_port(mate);
+ ide_device_add(idx);
return 0;
}
diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c
index 101aee1711c..4a0be251a05 100644
--- a/drivers/ide/legacy/buddha.c
+++ b/drivers/ide/legacy/buddha.c
@@ -212,8 +212,8 @@ fail_base2:
// xsurf_iops,
IRQ_AMIGA_PORTS);
}
-
- index = ide_register_hw(&hw, 1, &hwif);
+
+ index = ide_register_hw(&hw, NULL, 1, &hwif);
if (index != -1) {
hwif->mmio = 1;
printk("ide%d: ", index);
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
index 6c01d951d07..24a845d45bd 100644
--- a/drivers/ide/legacy/dtc2278.c
+++ b/drivers/ide/legacy/dtc2278.c
@@ -67,22 +67,24 @@ static void sub22 (char b, char c)
}
}
-static void tune_dtc2278 (ide_drive_t *drive, u8 pio)
+static DEFINE_SPINLOCK(dtc2278_lock);
+
+static void dtc2278_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
unsigned long flags;
- pio = ide_get_best_pio_mode(drive, pio, 4);
-
if (pio >= 3) {
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&dtc2278_lock, flags);
/*
* This enables PIO mode4 (3?) on the first interface
*/
sub22(1,0xc3);
sub22(0,0xa0);
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&dtc2278_lock, flags);
} else {
/* we don't know how to set it back again.. */
+ /* Actually we do - there is a data sheet available for the
+ Winbond but does anyone actually care */
}
/*
@@ -96,6 +98,7 @@ static int __init dtc2278_probe(void)
{
unsigned long flags;
ide_hwif_t *hwif, *mate;
+ static u8 idx[4] = { 0, 1, 0xff, 0xff };
hwif = &ide_hwifs[0];
mate = &ide_hwifs[1];
@@ -124,23 +127,20 @@ static int __init dtc2278_probe(void)
hwif->serialized = 1;
hwif->chipset = ide_dtc2278;
hwif->pio_mask = ATA_PIO4;
- hwif->tuneproc = &tune_dtc2278;
+ hwif->set_pio_mode = &dtc2278_set_pio_mode;
hwif->drives[0].no_unmask = 1;
hwif->drives[1].no_unmask = 1;
hwif->mate = mate;
mate->serialized = 1;
mate->chipset = ide_dtc2278;
+ mate->pio_mask = ATA_PIO4;
mate->drives[0].no_unmask = 1;
mate->drives[1].no_unmask = 1;
mate->mate = hwif;
mate->channel = 1;
- probe_hwif_init(hwif);
- probe_hwif_init(mate);
-
- ide_proc_register_port(hwif);
- ide_proc_register_port(mate);
+ ide_device_add(idx);
return 0;
}
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index f0829b83e97..7d7936f1b90 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -72,7 +72,7 @@ void __init falconide_init(void)
0, 0, NULL,
// falconide_iops,
IRQ_MFP_IDE);
- index = ide_register_hw(&hw, 1, NULL);
+ index = ide_register_hw(&hw, NULL, 1, NULL);
if (index != -1)
printk("ide%d: Falcon IDE interface\n", index);
diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
index 0830a021bbb..53331ee1e95 100644
--- a/drivers/ide/legacy/gayle.c
+++ b/drivers/ide/legacy/gayle.c
@@ -165,7 +165,7 @@ found:
// &gayle_iops,
IRQ_AMIGA_PORTS);
- index = ide_register_hw(&hw, 1, &hwif);
+ index = ide_register_hw(&hw, NULL, 1, &hwif);
if (index != -1) {
hwif->mmio = 1;
switch (i) {
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index bfaa2025173..a4245d13f11 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -199,7 +199,7 @@ static int __init try_to_init_ht6560b(void)
return 1;
}
-static u8 ht_pio2timings(ide_drive_t *drive, u8 pio)
+static u8 ht_pio2timings(ide_drive_t *drive, const u8 pio)
{
int active_time, recovery_time;
int active_cycles, recovery_cycles;
@@ -208,7 +208,6 @@ static u8 ht_pio2timings(ide_drive_t *drive, u8 pio)
if (pio) {
unsigned int cycle_time;
- pio = ide_get_best_pio_mode(drive, pio, 5);
cycle_time = ide_pio_cycle_time(drive, pio);
/*
@@ -248,6 +247,8 @@ static u8 ht_pio2timings(ide_drive_t *drive, u8 pio)
}
}
+static DEFINE_SPINLOCK(ht6560b_lock);
+
/*
* Enable/Disable so called prefetch mode
*/
@@ -255,9 +256,9 @@ static void ht_set_prefetch(ide_drive_t *drive, u8 state)
{
unsigned long flags;
int t = HT_PREFETCH_MODE << 8;
-
- spin_lock_irqsave(&ide_lock, flags);
-
+
+ spin_lock_irqsave(&ht6560b_lock, flags);
+
/*
* Prefetch mode and unmask irq seems to conflict
*/
@@ -269,15 +270,15 @@ static void ht_set_prefetch(ide_drive_t *drive, u8 state)
drive->drive_data &= ~t; /* disable prefetch mode */
drive->no_unmask = 0;
}
-
- spin_unlock_irqrestore(&ide_lock, flags);
-
+
+ spin_unlock_irqrestore(&ht6560b_lock, flags);
+
#ifdef DEBUG
printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
#endif
}
-static void tune_ht6560b (ide_drive_t *drive, u8 pio)
+static void ht6560b_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
unsigned long flags;
u8 timing;
@@ -288,16 +289,14 @@ static void tune_ht6560b (ide_drive_t *drive, u8 pio)
ht_set_prefetch(drive, pio & 1);
return;
}
-
+
timing = ht_pio2timings(drive, pio);
-
- spin_lock_irqsave(&ide_lock, flags);
-
+
+ spin_lock_irqsave(&ht6560b_lock, flags);
drive->drive_data &= 0xff00;
drive->drive_data |= timing;
-
- spin_unlock_irqrestore(&ide_lock, flags);
-
+ spin_unlock_irqrestore(&ht6560b_lock, flags);
+
#ifdef DEBUG
printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
#endif
@@ -312,6 +311,7 @@ MODULE_PARM_DESC(probe, "probe for HT6560B chipset");
int __init ht6560b_init(void)
{
ide_hwif_t *hwif, *mate;
+ static u8 idx[4] = { 0, 1, 0xff, 0xff };
int t;
if (probe_ht6560b == 0)
@@ -333,15 +333,17 @@ int __init ht6560b_init(void)
hwif->chipset = ide_ht6560b;
hwif->selectproc = &ht6560b_selectproc;
+ hwif->host_flags = IDE_HFLAG_ABUSE_PREFETCH;
hwif->pio_mask = ATA_PIO5;
- hwif->tuneproc = &tune_ht6560b;
+ hwif->set_pio_mode = &ht6560b_set_pio_mode;
hwif->serialized = 1; /* is this needed? */
hwif->mate = mate;
mate->chipset = ide_ht6560b;
mate->selectproc = &ht6560b_selectproc;
+ mate->host_flags = IDE_HFLAG_ABUSE_PREFETCH;
mate->pio_mask = ATA_PIO5;
- mate->tuneproc = &tune_ht6560b;
+ mate->set_pio_mode = &ht6560b_set_pio_mode;
mate->serialized = 1; /* is this needed? */
mate->mate = hwif;
mate->channel = 1;
@@ -358,11 +360,7 @@ int __init ht6560b_init(void)
mate->drives[0].drive_data = t;
mate->drives[1].drive_data = t;
- probe_hwif_init(hwif);
- probe_hwif_init(mate);
-
- ide_proc_register_port(hwif);
- ide_proc_register_port(mate);
+ ide_device_add(idx);
return 0;
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 4cdb519f983..03715c05866 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -28,7 +28,7 @@
and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this
file under either the MPL or the GPL.
-
+
======================================================================*/
#include <linux/module.h>
@@ -153,7 +153,7 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq
hw.irq = irq;
hw.chipset = ide_pci;
hw.dev = &handle->dev;
- return ide_register_hw_with_fixup(&hw, 0, NULL, ide_undecoded_slave);
+ return ide_register_hw(&hw, &ide_undecoded_slave, 0, NULL);
}
/*======================================================================
@@ -327,13 +327,13 @@ failed:
After a card is removed, ide_release() will unregister the net
device, and release the PCMCIA configuration. If the device is
still open, this will be postponed until it is closed.
-
+
======================================================================*/
void ide_release(struct pcmcia_device *link)
{
ide_info_t *info = link->priv;
-
+
DEBUG(0, "ide_release(0x%p)\n", link);
if (info->ndev) {
@@ -353,11 +353,12 @@ void ide_release(struct pcmcia_device *link)
stuff to run after an event is received. A CARD_REMOVAL event
also sets some flags to discourage the ide drivers from
talking to the ports.
-
+
======================================================================*/
static struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_FUNC_ID(4),
+ PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000), /* Corsair */
PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */
PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000), /* I-O Data CFA */
PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */
@@ -366,7 +367,7 @@ static struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */
PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */
- PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */
+ PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */
PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100), /* Viking CFA */
PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar, Viking CFA */
@@ -384,6 +385,7 @@ static struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
+ PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c
new file mode 100644
index 00000000000..7bb79f53dac
--- /dev/null
+++ b/drivers/ide/legacy/ide_platform.c
@@ -0,0 +1,169 @@
+/*
+ * Platform IDE driver
+ *
+ * Copyright (C) 2007 MontaVista Software
+ *
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/pata_platform.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+static struct {
+ void __iomem *plat_ide_mapbase;
+ void __iomem *plat_ide_alt_mapbase;
+ ide_hwif_t *hwif;
+ int index;
+} hwif_prop;
+
+static ide_hwif_t *__devinit plat_ide_locate_hwif(void __iomem *base,
+ void __iomem *ctrl, struct pata_platform_info *pdata, int irq,
+ int mmio)
+{
+ unsigned long port = (unsigned long)base;
+ ide_hwif_t *hwif = ide_find_port(port);
+ int i;
+
+ if (hwif == NULL)
+ goto out;
+
+ hwif->io_ports[IDE_DATA_OFFSET] = port;
+
+ port += (1 << pdata->ioport_shift);
+ for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET;
+ i++, port += (1 << pdata->ioport_shift))
+ hwif->io_ports[i] = port;
+
+ hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+
+ hwif->irq = irq;
+
+ hwif->chipset = ide_generic;
+
+ if (mmio) {
+ hwif->mmio = 1;
+ default_hwif_mmiops(hwif);
+ }
+
+ hwif_prop.hwif = hwif;
+ hwif_prop.index = hwif->index;
+out:
+ return hwif;
+}
+
+static int __devinit plat_ide_probe(struct platform_device *pdev)
+{
+ struct resource *res_base, *res_alt, *res_irq;
+ ide_hwif_t *hwif;
+ struct pata_platform_info *pdata;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ int ret = 0;
+ int mmio = 0;
+
+ pdata = pdev->dev.platform_data;
+
+ /* get a pointer to the register memory */
+ res_base = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ res_alt = platform_get_resource(pdev, IORESOURCE_IO, 1);
+
+ if (!res_base || !res_alt) {
+ res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res_alt = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res_base || !res_alt) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ mmio = 1;
+ }
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (mmio) {
+ hwif_prop.plat_ide_mapbase = devm_ioremap(&pdev->dev,
+ res_base->start, res_base->end - res_base->start + 1);
+ hwif_prop.plat_ide_alt_mapbase = devm_ioremap(&pdev->dev,
+ res_alt->start, res_alt->end - res_alt->start + 1);
+ } else {
+ hwif_prop.plat_ide_mapbase = devm_ioport_map(&pdev->dev,
+ res_base->start, res_base->end - res_base->start + 1);
+ hwif_prop.plat_ide_alt_mapbase = devm_ioport_map(&pdev->dev,
+ res_alt->start, res_alt->end - res_alt->start + 1);
+ }
+
+ hwif = plat_ide_locate_hwif(hwif_prop.plat_ide_mapbase,
+ hwif_prop.plat_ide_alt_mapbase, pdata, res_irq->start, mmio);
+
+ if (!hwif) {
+ ret = -ENODEV;
+ goto out;
+ }
+ hwif->gendev.parent = &pdev->dev;
+ hwif->noprobe = 0;
+
+ idx[0] = hwif->index;
+
+ ide_device_add(idx);
+
+ platform_set_drvdata(pdev, hwif);
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static int __devexit plat_ide_remove(struct platform_device *pdev)
+{
+ ide_hwif_t *hwif = pdev->dev.driver_data;
+
+ if (hwif != hwif_prop.hwif) {
+ dev_printk(KERN_DEBUG, &pdev->dev, "%s: hwif value error",
+ pdev->name);
+ } else {
+ ide_unregister(hwif_prop.index);
+ hwif_prop.index = 0;
+ hwif_prop.hwif = NULL;
+ }
+
+ return 0;
+}
+
+static struct platform_driver platform_ide_driver = {
+ .driver = {
+ .name = "pata_platform",
+ },
+ .probe = plat_ide_probe,
+ .remove = __devexit_p(plat_ide_remove),
+};
+
+static int __init platform_ide_init(void)
+{
+ return platform_driver_register(&platform_ide_driver);
+}
+
+static void __exit platform_ide_exit(void)
+{
+ platform_driver_unregister(&platform_ide_driver);
+}
+
+MODULE_DESCRIPTION("Platform IDE driver");
+MODULE_LICENSE("GPL");
+
+module_init(platform_ide_init);
+module_exit(platform_ide_exit);
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index b557c45a5a9..e87cd2f1643 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -93,21 +93,21 @@ void macide_init(void)
0, 0, macide_ack_intr,
// quadra_ide_iops,
IRQ_NUBUS_F);
- index = ide_register_hw(&hw, 1, &hwif);
+ index = ide_register_hw(&hw, NULL, 1, &hwif);
break;
case MAC_IDE_PB:
ide_setup_ports(&hw, IDE_BASE, macide_offsets,
0, 0, macide_ack_intr,
// macide_pb_iops,
IRQ_NUBUS_C);
- index = ide_register_hw(&hw, 1, &hwif);
+ index = ide_register_hw(&hw, NULL, 1, &hwif);
break;
case MAC_IDE_BABOON:
ide_setup_ports(&hw, BABOON_BASE, macide_offsets,
0, 0, NULL,
// macide_baboon_iops,
IRQ_BABOON_1);
- index = ide_register_hw(&hw, 1, &hwif);
+ index = ide_register_hw(&hw, NULL, 1, &hwif);
if (index == -1) break;
if (macintosh_config->ident == MAC_MODEL_PB190) {
diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c
index e628a983ce3..a73db1bd482 100644
--- a/drivers/ide/legacy/q40ide.c
+++ b/drivers/ide/legacy/q40ide.c
@@ -89,9 +89,8 @@ void q40_ide_setup_ports ( hw_regs_t *hw,
else
hw->io_ports[i] = Q40_ISA_IO_B(base + offsets[i]);
}
-
+
hw->irq = irq;
- hw->dma = NO_DMA;
hw->ack_intr = ack_intr;
/*
* hw->iops = iops;
@@ -102,7 +101,7 @@ void q40_ide_setup_ports ( hw_regs_t *hw,
/*
* the static array is needed to have the name reported in /proc/ioports,
- * hwif->name unfortunately isn´t available yet
+ * hwif->name unfortunately isn't available yet
*/
static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
"ide0", "ide1"
@@ -142,7 +141,7 @@ void q40ide_init(void)
0, NULL,
// m68kide_iops,
q40ide_default_irq(pcide_bases[i]));
- index = ide_register_hw(&hw, 1, &hwif);
+ index = ide_register_hw(&hw, NULL, 1, &hwif);
// **FIXME**
if (index != -1)
hwif->mmio = 1;
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
index 8b87a424094..912e73853fa 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/legacy/qd65xx.c
@@ -89,26 +89,6 @@
static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */
-static void qd_write_reg (u8 content, unsigned long reg)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ide_lock, flags);
- outb(content,reg);
- spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-static u8 __init qd_read_reg (unsigned long reg)
-{
- unsigned long flags;
- u8 read;
-
- spin_lock_irqsave(&ide_lock, flags);
- read = inb(reg);
- spin_unlock_irqrestore(&ide_lock, flags);
- return read;
-}
-
/*
* qd_select:
*
@@ -121,7 +101,7 @@ static void qd_select (ide_drive_t *drive)
(QD_TIMREG(drive) & 0x02);
if (timings[index] != QD_TIMING(drive))
- qd_write_reg(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
+ outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive));
}
/*
@@ -224,15 +204,14 @@ static void qd_set_timing (ide_drive_t *drive, u8 timing)
printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
}
-/*
- * qd6500_tune_drive
- */
-
-static void qd6500_tune_drive (ide_drive_t *drive, u8 pio)
+static void qd6500_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
int active_time = 175;
int recovery_time = 415; /* worst case values from the dos driver */
+ /*
+ * FIXME: use "pio" value
+ */
if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)
&& drive->id->tPIO && (drive->id->field_valid & 0x02)
&& drive->id->eide_pio >= 240) {
@@ -246,11 +225,7 @@ static void qd6500_tune_drive (ide_drive_t *drive, u8 pio)
qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time));
}
-/*
- * qd6580_tune_drive
- */
-
-static void qd6580_tune_drive (ide_drive_t *drive, u8 pio)
+static void qd6580_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
int base = HWIF(drive)->select_data;
unsigned int cycle_time;
@@ -258,7 +233,6 @@ static void qd6580_tune_drive (ide_drive_t *drive, u8 pio)
int recovery_time = 415; /* worst case values from the dos driver */
if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
- pio = ide_get_best_pio_mode(drive, pio, 4);
cycle_time = ide_pio_cycle_time(drive, pio);
switch (pio) {
@@ -290,7 +264,7 @@ static void qd6580_tune_drive (ide_drive_t *drive, u8 pio)
}
if (!HWIF(drive)->channel && drive->media != ide_disk) {
- qd_write_reg(0x5f, QD_CONTROL_PORT);
+ outb(0x5f, QD_CONTROL_PORT);
printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO "
"and post-write buffer on %s.\n",
drive->name, HWIF(drive)->name);
@@ -307,16 +281,15 @@ static void qd6580_tune_drive (ide_drive_t *drive, u8 pio)
static int __init qd_testreg(int port)
{
- u8 savereg;
- u8 readreg;
unsigned long flags;
+ u8 savereg, readreg;
- spin_lock_irqsave(&ide_lock, flags);
+ local_irq_save(flags);
savereg = inb_p(port);
outb_p(QD_TESTVAL, port); /* safe value */
readreg = inb_p(port);
outb(savereg, port);
- spin_unlock_irqrestore(&ide_lock, flags);
+ local_irq_restore(flags);
if (savereg == QD_TESTVAL) {
printk(KERN_ERR "Outch ! the probe for qd65xx isn't reliable !\n");
@@ -335,8 +308,7 @@ static int __init qd_testreg(int port)
*/
static void __init qd_setup(ide_hwif_t *hwif, int base, int config,
- unsigned int data0, unsigned int data1,
- void (*tuneproc) (ide_drive_t *, u8 pio))
+ unsigned int data0, unsigned int data1)
{
hwif->chipset = ide_qd65xx;
hwif->channel = hwif->index;
@@ -347,8 +319,6 @@ static void __init qd_setup(ide_hwif_t *hwif, int base, int config,
hwif->drives[0].io_32bit =
hwif->drives[1].io_32bit = 1;
hwif->pio_mask = ATA_PIO4;
- hwif->tuneproc = tuneproc;
- probe_hwif_init(hwif);
}
/*
@@ -361,7 +331,7 @@ static void __exit qd_unsetup(ide_hwif_t *hwif)
{
u8 config = hwif->config_data;
int base = hwif->select_data;
- void *tuneproc = (void *) hwif->tuneproc;
+ void *set_pio_mode = (void *)hwif->set_pio_mode;
if (hwif->chipset != ide_qd65xx)
return;
@@ -369,17 +339,17 @@ static void __exit qd_unsetup(ide_hwif_t *hwif)
printk(KERN_NOTICE "%s: back to defaults\n", hwif->name);
hwif->selectproc = NULL;
- hwif->tuneproc = NULL;
+ hwif->set_pio_mode = NULL;
- if (tuneproc == (void *) qd6500_tune_drive) {
+ if (set_pio_mode == (void *)qd6500_set_pio_mode) {
// will do it for both
- qd_write_reg(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
- } else if (tuneproc == (void *) qd6580_tune_drive) {
+ outb(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+ } else if (set_pio_mode == (void *)qd6580_set_pio_mode) {
if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
- qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
- qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
+ outb(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+ outb(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
} else {
- qd_write_reg(hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
+ outb(hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
}
} else {
printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n");
@@ -398,10 +368,11 @@ static void __exit qd_unsetup(ide_hwif_t *hwif)
static int __init qd_probe(int base)
{
ide_hwif_t *hwif;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
u8 config;
u8 unit;
- config = qd_read_reg(QD_CONFIG_PORT);
+ config = inb(QD_CONFIG_PORT);
if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) )
return 1;
@@ -424,10 +395,13 @@ static int __init qd_probe(int base)
return 1;
}
- qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA,
- &qd6500_tune_drive);
+ qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA);
+
+ hwif->set_pio_mode = &qd6500_set_pio_mode;
- ide_proc_register_port(hwif);
+ idx[0] = unit;
+
+ ide_device_add(idx);
return 1;
}
@@ -442,7 +416,7 @@ static int __init qd_probe(int base)
/* qd6580 found */
- control = qd_read_reg(QD_CONTROL_PORT);
+ control = inb(QD_CONTROL_PORT);
printk(KERN_NOTICE "qd6580 at %#x\n", base);
printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n",
@@ -455,11 +429,15 @@ static int __init qd_probe(int base)
printk(KERN_INFO "%s: qd6580: single IDE board\n",
hwif->name);
qd_setup(hwif, base, config | (control << 8),
- QD6580_DEF_DATA, QD6580_DEF_DATA2,
- &qd6580_tune_drive);
- qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+ QD6580_DEF_DATA, QD6580_DEF_DATA2);
+
+ hwif->set_pio_mode = &qd6580_set_pio_mode;
+
+ idx[0] = unit;
- ide_proc_register_port(hwif);
+ ide_device_add(idx);
+
+ outb(QD_DEF_CONTR, QD_CONTROL_PORT);
return 1;
} else {
@@ -472,15 +450,21 @@ static int __init qd_probe(int base)
hwif->name, mate->name);
qd_setup(hwif, base, config | (control << 8),
- QD6580_DEF_DATA, QD6580_DEF_DATA,
- &qd6580_tune_drive);
+ QD6580_DEF_DATA, QD6580_DEF_DATA);
+
+ hwif->set_pio_mode = &qd6580_set_pio_mode;
+
qd_setup(mate, base, config | (control << 8),
- QD6580_DEF_DATA2, QD6580_DEF_DATA2,
- &qd6580_tune_drive);
- qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
+ QD6580_DEF_DATA2, QD6580_DEF_DATA2);
+
+ mate->set_pio_mode = &qd6580_set_pio_mode;
+
+ idx[0] = 0;
+ idx[1] = 1;
+
+ ide_device_add(idx);
- ide_proc_register_port(hwif);
- ide_proc_register_port(mate);
+ outb(QD_DEF_CONTR, QD_CONTROL_PORT);
return 0; /* no other qd65xx possible */
}
diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
index d2862e638bc..79577b91687 100644
--- a/drivers/ide/legacy/umc8672.c
+++ b/drivers/ide/legacy/umc8672.c
@@ -105,12 +105,11 @@ static void umc_set_speeds (u8 speeds[])
speeds[0], speeds[1], speeds[2], speeds[3]);
}
-static void tune_umc (ide_drive_t *drive, u8 pio)
+static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
unsigned long flags;
ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
- pio = ide_get_best_pio_mode(drive, pio, 4);
printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
drive->name, pio, pio_to_umc[pio]);
spin_lock_irqsave(&ide_lock, flags);
@@ -125,8 +124,9 @@ static void tune_umc (ide_drive_t *drive, u8 pio)
static int __init umc8672_probe(void)
{
- unsigned long flags;
ide_hwif_t *hwif, *mate;
+ unsigned long flags;
+ static u8 idx[4] = { 0, 1, 0xff, 0xff };
if (!request_region(0x108, 2, "umc8672")) {
printk(KERN_ERR "umc8672: ports 0x108-0x109 already in use.\n");
@@ -150,20 +150,16 @@ static int __init umc8672_probe(void)
hwif->chipset = ide_umc8672;
hwif->pio_mask = ATA_PIO4;
- hwif->tuneproc = &tune_umc;
+ hwif->set_pio_mode = &umc_set_pio_mode;
hwif->mate = mate;
mate->chipset = ide_umc8672;
mate->pio_mask = ATA_PIO4;
- mate->tuneproc = &tune_umc;
+ mate->set_pio_mode = &umc_set_pio_mode;
mate->mate = hwif;
mate->channel = 1;
- probe_hwif_init(hwif);
- probe_hwif_init(mate);
-
- ide_proc_register_port(hwif);
- ide_proc_register_port(mate);
+ ide_device_add(idx);
return 0;
}
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index 2ba6a054b86..a4ce3ba15d6 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -99,20 +99,9 @@ void auide_outsw(unsigned long port, void *addr, u32 count)
#endif
-static void auide_tune_drive(ide_drive_t *drive, byte pio)
+static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- int mem_sttime;
- int mem_stcfg;
- u8 speed;
-
- /* get the best pio mode for the drive */
- pio = ide_get_best_pio_mode(drive, pio, 4);
-
- printk(KERN_INFO "%s: setting Au1XXX IDE to PIO mode%d\n",
- drive->name, pio);
-
- mem_sttime = 0;
- mem_stcfg = au_readl(MEM_STCFG2);
+ int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
/* set pio mode! */
switch(pio) {
@@ -170,23 +159,11 @@ static void auide_tune_drive(ide_drive_t *drive, byte pio)
au_writel(mem_sttime,MEM_STTIME2);
au_writel(mem_stcfg,MEM_STCFG2);
-
- speed = pio + XFER_PIO_0;
- ide_config_drive_speed(drive, speed);
}
-static int auide_tune_chipset (ide_drive_t *drive, u8 speed)
+static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
- int mem_sttime;
- int mem_stcfg;
-
- mem_sttime = 0;
- mem_stcfg = au_readl(MEM_STCFG2);
-
- if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
- auide_tune_drive(drive, speed - XFER_PIO_0);
- return 0;
- }
+ int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
switch(speed) {
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
@@ -222,16 +199,11 @@ static int auide_tune_chipset (ide_drive_t *drive, u8 speed)
break;
#endif
default:
- return 1;
+ return;
}
- if (ide_config_drive_speed(drive, speed))
- return 1;
-
au_writel(mem_sttime,MEM_STTIME2);
au_writel(mem_stcfg,MEM_STCFG2);
-
- return 0;
}
/*
@@ -304,8 +276,7 @@ static int auide_build_dmatable(ide_drive_t *drive)
if (iswrite) {
if(!put_source_flags(ahwif->tx_chan,
- (void*)(page_address(sg->page)
- + sg->offset),
+ (void*) sg_virt(sg),
tc, flags)) {
printk(KERN_ERR "%s failed %d\n",
__FUNCTION__, __LINE__);
@@ -313,8 +284,7 @@ static int auide_build_dmatable(ide_drive_t *drive)
} else
{
if(!put_dest_flags(ahwif->rx_chan,
- (void*)(page_address(sg->page)
- + sg->offset),
+ (void*) sg_virt(sg),
tc, flags)) {
printk(KERN_ERR "%s failed %d\n",
__FUNCTION__, __LINE__);
@@ -324,7 +294,7 @@ static int auide_build_dmatable(ide_drive_t *drive)
cur_addr += tc;
cur_len -= tc;
}
- sg++;
+ sg = sg_next(sg);
i--;
}
@@ -379,11 +349,18 @@ static int auide_dma_setup(ide_drive_t *drive)
return 0;
}
-static int auide_dma_check(ide_drive_t *drive)
+static u8 auide_mdma_filter(ide_drive_t *drive)
{
- u8 speed = ide_max_dma_mode(drive);
+ /*
+ * FIXME: ->white_list and ->black_list are based on completely bogus
+ * ->ide_dma_check implementation which didn't set neither the host
+ * controller timings nor the device for the desired transfer mode.
+ *
+ * They should be either removed or 0x00 MWDMA mask should be
+ * returned for devices on the ->black_list.
+ */
- if( dbdma_init_done == 0 ){
+ if (dbdma_init_done == 0) {
auide_hwif.white_list = ide_in_drive_list(drive->id,
dma_white_list);
auide_hwif.black_list = ide_in_drive_list(drive->id,
@@ -394,22 +371,11 @@ static int auide_dma_check(ide_drive_t *drive)
}
/* Is the drive in our DMA black list? */
-
- if ( auide_hwif.black_list ) {
- drive->using_dma = 0;
-
- /* Borrowed the warning message from ide-dma.c */
-
+ if (auide_hwif.black_list)
printk(KERN_WARNING "%s: Disabling DMA for %s (blacklisted)\n",
- drive->name, drive->id->model);
- }
- else
- drive->using_dma = 1;
-
- if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
- return 0;
+ drive->name, drive->id->model);
- return -1;
+ return drive->hwif->mwdma_mask;
}
static int auide_dma_test_irq(ide_drive_t *drive)
@@ -633,8 +599,9 @@ static int au_ide_probe(struct device *dev)
_auide_hwif *ahwif = &auide_hwif;
ide_hwif_t *hwif;
struct resource *res;
- hw_regs_t *hw;
int ret = 0;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ hw_regs_t hw;
#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA)
char *mode = "MWDMA2";
@@ -676,12 +643,12 @@ static int au_ide_probe(struct device *dev)
/* FIXME: This might possibly break PCMCIA IDE devices */
hwif = &ide_hwifs[pdev->id];
- hw = &hwif->hw;
- hwif->irq = hw->irq = ahwif->irq;
+ hwif->irq = ahwif->irq;
hwif->chipset = ide_au1xxx;
- auide_setup_ports(hw, ahwif);
- memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports));
+ memset(&hw, 0, sizeof(hw));
+ auide_setup_ports(&hw, ahwif);
+ memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
hwif->ultra_mask = 0x0; /* Disable Ultra DMA */
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
@@ -693,6 +660,7 @@ static int au_ide_probe(struct device *dev)
#endif
hwif->pio_mask = ATA_PIO4;
+ hwif->host_flags = IDE_HFLAG_POST_SET_MODE;
hwif->noprobe = 0;
hwif->drives[0].unmask = 1;
@@ -712,14 +680,15 @@ static int au_ide_probe(struct device *dev)
hwif->OUTSW = auide_outsw;
#endif
- hwif->tuneproc = &auide_tune_drive;
- hwif->speedproc = &auide_tune_chipset;
+ hwif->set_pio_mode = &au1xxx_set_pio_mode;
+ hwif->set_dma_mode = &auide_set_dma_mode;
#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
hwif->dma_off_quietly = &auide_dma_off_quietly;
hwif->dma_timeout = &auide_dma_timeout;
- hwif->ide_dma_check = &auide_dma_check;
+ hwif->mdma_filter = &auide_mdma_filter;
+
hwif->dma_exec_cmd = &auide_dma_exec_cmd;
hwif->dma_start = &auide_dma_start;
hwif->ide_dma_end = &auide_dma_end;
@@ -729,23 +698,17 @@ static int au_ide_probe(struct device *dev)
hwif->dma_host_on = &auide_dma_host_on;
hwif->dma_lost_irq = &auide_dma_lost_irq;
hwif->ide_dma_on = &auide_dma_on;
-
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
- hwif->atapi_dma = 1;
-
#else /* !CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */
- hwif->autodma = 0;
hwif->channel = 0;
hwif->hold = 1;
hwif->select_data = 0; /* no chipset-specific code */
hwif->config_data = 0; /* no chipset-specific code */
- hwif->drives[0].autodma = 0;
hwif->drives[0].autotune = 1; /* 1=autotune, 2=noautotune, 0=default */
+ hwif->drives[1].autotune = 1;
#endif
- hwif->drives[0].no_io_32bit = 1;
+ hwif->drives[0].no_io_32bit = 1;
+ hwif->drives[1].no_io_32bit = 1;
auide_hwif.hwif = hwif;
hwif->hwif_data = &auide_hwif;
@@ -755,9 +718,9 @@ static int au_ide_probe(struct device *dev)
dbdma_init_done = 1;
#endif
- probe_hwif_init(hwif);
+ idx[0] = hwif->index;
- ide_proc_register_port(hwif);
+ ide_device_add(idx);
dev_set_drvdata(dev, hwif);
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
index c2e29571b00..521edd41b57 100644
--- a/drivers/ide/mips/swarm.c
+++ b/drivers/ide/mips/swarm.c
@@ -71,6 +71,7 @@ static int __devinit swarm_ide_probe(struct device *dev)
u8 __iomem *base;
phys_t offset, size;
int i;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
if (!SIBYTE_HAVE_IDE)
return -ENODEV;
@@ -119,18 +120,15 @@ static int __devinit swarm_ide_probe(struct device *dev)
hwif->noprobe = 0;
for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
- hwif->hw.io_ports[i] =
+ hwif->io_ports[i] =
(unsigned long)(base + ((0x1f0 + i) << 5));
- hwif->hw.io_ports[IDE_CONTROL_OFFSET] =
+ hwif->io_ports[IDE_CONTROL_OFFSET] =
(unsigned long)(base + (0x3f6 << 5));
- hwif->hw.irq = K_INT_GB_IDE;
+ hwif->irq = K_INT_GB_IDE;
- memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
- hwif->irq = hwif->hw.irq;
+ idx[0] = hwif->index;
- probe_hwif_init(hwif);
-
- ide_proc_register_port(hwif);
+ ide_device_add(idx);
dev_set_drvdata(dev, hwif);
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index 74432830abf..19ec421f7b9 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/aec62xx.c Version 0.24 May 24, 2007
+ * linux/drivers/ide/pci/aec62xx.c Version 0.27 Sep 16, 2007
*
* Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
@@ -87,12 +87,11 @@ static u8 pci_bus_clock_list_ultra (u8 speed, struct chipset_bus_clock_list_entr
return chipset_table->ultra_settings;
}
-static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static void aec6210_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u16 d_conf = 0;
- u8 speed = ide_rate_filter(drive, xferspeed);
u8 ultra = 0, ultra_conf = 0;
u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
unsigned long flags;
@@ -112,14 +111,12 @@ static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed)
tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
pci_write_config_byte(dev, 0x54, tmp2);
local_irq_restore(flags);
- return(ide_config_drive_speed(drive, speed));
}
-static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static void aec6260_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- u8 speed = ide_rate_filter(drive, xferspeed);
u8 unit = (drive->select.b.unit & 0x01);
u8 tmp1 = 0, tmp2 = 0;
u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
@@ -137,37 +134,11 @@ static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
pci_write_config_byte(dev, (0x44|hwif->channel), tmp2);
local_irq_restore(flags);
- return(ide_config_drive_speed(drive, speed));
}
-static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
+static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- (void) HWIF(drive)->speedproc(drive, pio + XFER_PIO_0);
-}
-
-static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
-{
- if (ide_tune_dma(drive))
- return 0;
-
- if (ide_use_fast_pio(drive))
- aec62xx_tune_drive(drive, 255);
-
- return -1;
-}
-
-static void aec62xx_dma_lost_irq (ide_drive_t *drive)
-{
- switch (HWIF(drive)->pci_dev->device) {
- case PCI_DEVICE_ID_ARTOP_ATP860:
- case PCI_DEVICE_ID_ARTOP_ATP860R:
- case PCI_DEVICE_ID_ARTOP_ATP865:
- case PCI_DEVICE_ID_ARTOP_ATP865R:
- printk(" AEC62XX time out ");
- default:
- break;
- }
+ drive->hwif->set_dma_mode(drive, pio + XFER_PIO_0);
}
static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const char *name)
@@ -200,114 +171,76 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
- u8 reg54 = 0, mask = hwif->channel ? 0xf0 : 0x0f;
- unsigned long flags;
- hwif->tuneproc = &aec62xx_tune_drive;
+ hwif->set_pio_mode = &aec_set_pio_mode;
- if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
- if(hwif->mate)
- hwif->mate->serialized = hwif->serialized = 1;
- hwif->speedproc = &aec6210_tune_chipset;
- } else
- hwif->speedproc = &aec6260_tune_chipset;
+ if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
+ hwif->set_dma_mode = &aec6210_set_mode;
+ else
+ hwif->set_dma_mode = &aec6260_set_mode;
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+ if (hwif->dma_base == 0)
return;
- }
- hwif->ultra_mask = hwif->cds->udma_mask;
- hwif->mwdma_mask = 0x07;
-
- hwif->ide_dma_check = &aec62xx_config_drive_xfer_rate;
- hwif->dma_lost_irq = &aec62xx_dma_lost_irq;
+ if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF)
+ return;
- if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
- spin_lock_irqsave(&ide_lock, flags);
- pci_read_config_byte (dev, 0x54, &reg54);
- pci_write_config_byte(dev, 0x54, (reg54 & ~mask));
- spin_unlock_irqrestore(&ide_lock, flags);
- } else if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
+ if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
u8 ata66 = 0, mask = hwif->channel ? 0x02 : 0x01;
pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
hwif->cbl = (ata66 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
}
-
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
-}
-
-static int __devinit init_setup_aec62xx(struct pci_dev *dev, ide_pci_device_t *d)
-{
- return ide_setup_pci_device(dev, d);
-}
-
-static int __devinit init_setup_aec6x80(struct pci_dev *dev, ide_pci_device_t *d)
-{
- unsigned long dma_base = pci_resource_start(dev, 4);
-
- if (inb(dma_base + 2) & 0x10) {
- d->name = (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R) ?
- "AEC6880R" : "AEC6880";
- d->udma_mask = 0x7f; /* udma0-6 */
- }
-
- return ide_setup_pci_device(dev, d);
}
-static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
+static const struct ide_port_info aec62xx_chipsets[] __devinitdata = {
{ /* 0 */
.name = "AEC6210",
- .init_setup = init_setup_aec62xx,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .autodma = AUTODMA,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
- .bootable = OFF_BOARD,
+ .host_flags = IDE_HFLAG_SERIALIZE |
+ IDE_HFLAG_NO_ATAPI_DMA |
+ IDE_HFLAG_OFF_BOARD,
.pio_mask = ATA_PIO4,
- .udma_mask = 0x07, /* udma0-2 */
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
},{ /* 1 */
.name = "AEC6260",
- .init_setup = init_setup_aec62xx,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .autodma = NOAUTODMA,
- .bootable = OFF_BOARD,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA |
+ IDE_HFLAG_OFF_BOARD,
.pio_mask = ATA_PIO4,
- .udma_mask = 0x1f, /* udma0-4 */
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
},{ /* 2 */
.name = "AEC6260R",
- .init_setup = init_setup_aec62xx,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .autodma = AUTODMA,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
- .bootable = NEVER_BOARD,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA,
.pio_mask = ATA_PIO4,
- .udma_mask = 0x1f, /* udma0-4 */
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
},{ /* 3 */
.name = "AEC6280",
- .init_setup = init_setup_aec6x80,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
.pio_mask = ATA_PIO4,
- .udma_mask = 0x3f, /* udma0-5 */
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
},{ /* 4 */
.name = "AEC6280R",
- .init_setup = init_setup_aec6x80,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .autodma = AUTODMA,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
- .bootable = OFF_BOARD,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
.pio_mask = ATA_PIO4,
- .udma_mask = 0x3f, /* udma0-5 */
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
}
};
@@ -320,22 +253,34 @@ static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
* finds a device matching our IDE device tables.
*
* NOTE: since we're going to modify the 'name' field for AEC-6[26]80[R]
- * chips, pass a local copy of 'struct pci_device_id' down the call chain.
+ * chips, pass a local copy of 'struct ide_port_info' down the call chain.
*/
-
+
static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_pci_device_t d = aec62xx_chipsets[id->driver_data];
+ struct ide_port_info d;
+ u8 idx = id->driver_data;
+
+ d = aec62xx_chipsets[idx];
+
+ if (idx == 3 || idx == 4) {
+ unsigned long dma_base = pci_resource_start(dev, 4);
+
+ if (inb(dma_base + 2) & 0x10) {
+ d.name = (idx == 4) ? "AEC6880R" : "AEC6880";
+ d.udma_mask = ATA_UDMA6;
+ }
+ }
- return d.init_setup(dev, &d);
+ return ide_setup_pci_device(dev, &d);
}
-static struct pci_device_id aec62xx_pci_tbl[] = {
- { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
- { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
- { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
- { PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+static const struct pci_device_id aec62xx_pci_tbl[] = {
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF), 0 },
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860), 1 },
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R), 2 },
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865), 3 },
+ { PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R), 4 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl);
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index 11ecb618007..a607dd31a64 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/alim15x3.c Version 0.25 Jun 9 2007
+ * linux/drivers/ide/pci/alim15x3.c Version 0.29 Sep 16 2007
*
* Copyright (C) 1998-2000 Michel Aubry, Maintainer
* Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
@@ -283,17 +283,14 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
#endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
/**
- * ali15x3_tune_pio - set up chipset for PIO mode
- * @drive: drive to tune
- * @pio: desired mode
+ * ali_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
- * Select the best PIO mode for the drive in question.
- * Then program the controller for this mode.
- *
- * Returns the PIO mode programmed.
+ * Program the controller for the given PIO mode.
*/
-
-static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio)
+
+static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -306,7 +303,6 @@ static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio)
u8 cd_dma_fifo = 0;
int unit = drive->select.b.unit & 1;
- pio = ide_get_best_pio_mode(drive, pio, 5);
s_time = ide_pio_timings[pio].setup_time;
a_time = ide_pio_timings[pio].active_time;
if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
@@ -359,23 +355,6 @@ static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio)
* { 25, 70, 25 }, PIO Mode 4 with IORDY ns
* { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard)
*/
-
- return pio;
-}
-
-/**
- * ali15x3_tune_drive - set up drive for PIO mode
- * @drive: drive to tune
- * @pio: desired mode
- *
- * Program the controller with the best PIO timing for the given drive.
- * Then set up the drive itself.
- */
-
-static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio)
-{
- pio = ali15x3_tune_pio(drive, pio);
- (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
/**
@@ -407,24 +386,25 @@ static u8 ali_udma_filter(ide_drive_t *drive)
}
/**
- * ali15x3_tune_chipset - set up chipset/drive for new speed
- * @drive: drive to configure for
- * @xferspeed: desired speed
+ * ali_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
* Configure the hardware for the desired IDE transfer mode.
- * We also do the needed drive configuration through helpers
*/
-
-static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+
+static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- u8 speed = ide_rate_filter(drive, xferspeed);
u8 speed1 = speed;
u8 unit = (drive->select.b.unit & 0x01);
u8 tmpbyte = 0x00;
int m5229_udma = (hwif->channel) ? 0x57 : 0x56;
+ if (speed < XFER_PIO_0)
+ return;
+
if (speed == XFER_UDMA_6)
speed1 = 0x47;
@@ -437,8 +417,9 @@ static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
tmpbyte &= ultra_enable;
pci_write_config_byte(dev, m5229_udma, tmpbyte);
- if (speed < XFER_SW_DMA_0)
- (void) ali15x3_tune_pio(drive, speed - XFER_PIO_0);
+ /*
+ * FIXME: Oh, my... DMA timings are never set.
+ */
} else {
pci_read_config_byte(dev, m5229_udma, &tmpbyte);
tmpbyte &= (0x0f << ((1-unit) << 2));
@@ -453,27 +434,6 @@ static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
pci_write_config_byte(dev, 0x4b, tmpbyte);
}
}
- return (ide_config_drive_speed(drive, speed));
-}
-
-/**
- * ali15x3_config_drive_for_dma - configure for DMA
- * @drive: drive to configure
- *
- * Configure a drive for DMA operation. If DMA is not possible we
- * drop the drive into PIO mode instead.
- */
-
-static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
-{
- drive->init_speed = 0;
-
- if (ide_tune_dma(drive))
- return 0;
-
- ali15x3_tune_drive(drive, 255);
-
- return -1;
}
/**
@@ -532,6 +492,13 @@ static unsigned int __devinit init_chipset_ali15x3 (struct pci_dev *dev, const c
* clear bit 7
*/
pci_write_config_byte(dev, 0x4b, tmpbyte & 0x7F);
+ /*
+ * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
+ */
+ if (m5229_revision >= 0x20 && isa_dev) {
+ pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
+ chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
+ }
goto out;
}
@@ -577,7 +544,30 @@ static unsigned int __devinit init_chipset_ali15x3 (struct pci_dev *dev, const c
pci_write_config_byte(isa_dev, 0x79, tmpbyte | 0x02);
}
}
+
out:
+ /*
+ * CD_ROM DMA on (m5229, 0x53, bit0)
+ * Enable this bit even if we want to use PIO.
+ * PIO FIFO off (m5229, 0x53, bit1)
+ * The hardware will use 0x54h and 0x55h to control PIO FIFO.
+ * (Not on later devices it seems)
+ *
+ * 0x53 changes meaning on later revs - we must no touch
+ * bit 1 on them. Need to check if 0x20 is the right break.
+ */
+ if (m5229_revision >= 0x20) {
+ pci_read_config_byte(dev, 0x53, &tmpbyte);
+
+ if (m5229_revision <= 0x20)
+ tmpbyte = (tmpbyte & (~0x02)) | 0x01;
+ else if (m5229_revision == 0xc7 || m5229_revision == 0xc8)
+ tmpbyte |= 0x03;
+ else
+ tmpbyte |= 0x01;
+
+ pci_write_config_byte(dev, 0x53, tmpbyte);
+ }
pci_dev_put(north);
pci_dev_put(isa_dev);
local_irq_restore(flags);
@@ -588,7 +578,7 @@ out:
* Cable special cases
*/
-static struct dmi_system_id cable_dmi_table[] = {
+static const struct dmi_system_id cable_dmi_table[] = {
{
.ident = "HP Pavilion N5430",
.matches = {
@@ -656,36 +646,8 @@ static u8 __devinit ata66_ali15x3(ide_hwif_t *hwif)
if ((tmpbyte & (1 << hwif->channel)) == 0)
cbl = ATA_CBL_PATA80;
}
- } else {
- /*
- * check m1533, 0x5e, bit 1~4 == 1001 => & 00011110 = 00010010
- */
- pci_read_config_byte(isa_dev, 0x5e, &tmpbyte);
- chip_is_1543c_e = ((tmpbyte & 0x1e) == 0x12) ? 1: 0;
}
- /*
- * CD_ROM DMA on (m5229, 0x53, bit0)
- * Enable this bit even if we want to use PIO
- * PIO FIFO off (m5229, 0x53, bit1)
- * The hardware will use 0x54h and 0x55h to control PIO FIFO
- * (Not on later devices it seems)
- *
- * 0x53 changes meaning on later revs - we must no touch
- * bit 1 on them. Need to check if 0x20 is the right break
- */
-
- pci_read_config_byte(dev, 0x53, &tmpbyte);
-
- if(m5229_revision <= 0x20)
- tmpbyte = (tmpbyte & (~0x02)) | 0x01;
- else if (m5229_revision == 0xc7 || m5229_revision == 0xc8)
- tmpbyte |= 0x03;
- else
- tmpbyte |= 0x01;
-
- pci_write_config_byte(dev, 0x53, tmpbyte);
-
local_irq_restore(flags);
return cbl;
@@ -700,51 +662,17 @@ static u8 __devinit ata66_ali15x3(ide_hwif_t *hwif)
static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
{
- hwif->autodma = 0;
- hwif->tuneproc = &ali15x3_tune_drive;
- hwif->speedproc = &ali15x3_tune_chipset;
+ hwif->set_pio_mode = &ali_set_pio_mode;
+ hwif->set_dma_mode = &ali_set_dma_mode;
hwif->udma_filter = &ali_udma_filter;
- /* don't use LBA48 DMA on ALi devices before rev 0xC5 */
- hwif->no_lba48_dma = (m5229_revision <= 0xC4) ? 1 : 0;
-
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ if (hwif->dma_base == 0)
return;
- }
- if (m5229_revision > 0x20)
- hwif->atapi_dma = 1;
-
- if (m5229_revision <= 0x20)
- hwif->ultra_mask = 0x00; /* no udma */
- else if (m5229_revision < 0xC2)
- hwif->ultra_mask = 0x07; /* udma0-2 */
- else if (m5229_revision == 0xC2 || m5229_revision == 0xC3)
- hwif->ultra_mask = 0x1f; /* udma0-4 */
- else if (m5229_revision == 0xC4)
- hwif->ultra_mask = 0x3f; /* udma0-5 */
- else
- hwif->ultra_mask = 0x7f; /* udma0-6 */
-
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
-
- if (m5229_revision >= 0x20) {
- /*
- * M1543C or newer for DMAing
- */
- hwif->ide_dma_check = &ali15x3_config_drive_for_dma;
- hwif->dma_setup = &ali15x3_dma_setup;
- if (!noautodma)
- hwif->autodma = 1;
-
- if (hwif->cbl != ATA_CBL_PATA40_SHORT)
- hwif->cbl = ata66_ali15x3(hwif);
- }
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
+ hwif->dma_setup = &ali15x3_dma_setup;
+
+ if (hwif->cbl != ATA_CBL_PATA40_SHORT)
+ hwif->cbl = ata66_ali15x3(hwif);
}
/**
@@ -818,14 +746,15 @@ static void __devinit init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
ide_setup_dma(hwif, dmabase, 8);
}
-static ide_pci_device_t ali15x3_chipset __devinitdata = {
+static const struct ide_port_info ali15x3_chipset __devinitdata = {
.name = "ALI15X3",
.init_chipset = init_chipset_ali15x3,
.init_hwif = init_hwif_ali15x3,
.init_dma = init_dma_ali15x3,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO5,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
};
/**
@@ -843,21 +772,40 @@ static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_dev
{ },
};
- ide_pci_device_t *d = &ali15x3_chipset;
+ struct ide_port_info d = ali15x3_chipset;
+ u8 rev = dev->revision;
if (pci_dev_present(ati_rs100))
printk(KERN_WARNING "alim15x3: ATI Radeon IGP Northbridge is not yet fully tested.\n");
+ /* don't use LBA48 DMA on ALi devices before rev 0xC5 */
+ if (rev <= 0xC4)
+ d.host_flags |= IDE_HFLAG_NO_LBA48_DMA;
+
+ if (rev >= 0x20) {
+ if (rev == 0x20)
+ d.host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
+
+ if (rev < 0xC2)
+ d.udma_mask = ATA_UDMA2;
+ else if (rev == 0xC2 || rev == 0xC3)
+ d.udma_mask = ATA_UDMA4;
+ else if (rev == 0xC4)
+ d.udma_mask = ATA_UDMA5;
+ else
+ d.udma_mask = ATA_UDMA6;
+ }
+
#if defined(CONFIG_SPARC64)
- d->init_hwif = init_hwif_common_ali15x3;
+ d.init_hwif = init_hwif_common_ali15x3;
#endif /* CONFIG_SPARC64 */
- return ide_setup_pci_device(dev, d);
+ return ide_setup_pci_device(dev, &d);
}
-static struct pci_device_id alim15x3_pci_tbl[] = {
- { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5228, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+static const struct pci_device_id alim15x3_pci_tbl[] = {
+ { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), 0 },
+ { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl);
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 06c15a6a3e7..8d4125ec252 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -1,5 +1,5 @@
/*
- * Version 2.21
+ * Version 2.24
*
* AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
* IDE driver for Linux.
@@ -28,9 +28,6 @@
#include "ide-timing.h"
-#define DISPLAY_AMD_TIMINGS
-
-#define AMD_IDE_ENABLE (0x00 + amd_config->base)
#define AMD_IDE_CONFIG (0x01 + amd_config->base)
#define AMD_CABLE_DETECT (0x02 + amd_config->base)
#define AMD_DRIVE_TIMING (0x08 + amd_config->base)
@@ -80,7 +77,7 @@ static struct amd_ide_chip {
};
static struct amd_ide_chip *amd_config;
-static ide_pci_device_t *amd_chipset;
+static const struct ide_port_info *amd_chipset;
static unsigned int amd_80w;
static unsigned int amd_clock;
@@ -88,118 +85,6 @@ static char *amd_dma[] = { "16", "25", "33", "44", "66", "100", "133" };
static unsigned char amd_cyc2udma[] = { 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7 };
/*
- * AMD /proc entry.
- */
-
-#ifdef CONFIG_IDE_PROC_FS
-
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static u8 amd74xx_proc;
-
-static unsigned char amd_udma2cyc[] = { 4, 6, 8, 10, 3, 2, 1, 15 };
-static unsigned long amd_base;
-static struct pci_dev *bmide_dev;
-extern int (*amd74xx_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-
-#define amd_print(format, arg...) p += sprintf(p, format "\n" , ## arg)
-#define amd_print_drive(name, format, arg...)\
- p += sprintf(p, name); for (i = 0; i < 4; i++) p += sprintf(p, format, ## arg); p += sprintf(p, "\n");
-
-static int amd74xx_get_info(char *buffer, char **addr, off_t offset, int count)
-{
- int speed[4], cycle[4], setup[4], active[4], recover[4], den[4],
- uen[4], udma[4], active8b[4], recover8b[4];
- struct pci_dev *dev = bmide_dev;
- unsigned int v, u, i;
- unsigned short c, w;
- unsigned char t;
- int len;
- char *p = buffer;
-
- amd_print("----------AMD BusMastering IDE Configuration----------------");
-
- amd_print("Driver Version: 2.13");
- amd_print("South Bridge: %s", pci_name(bmide_dev));
-
- amd_print("Revision: IDE %#x", dev->revision);
- amd_print("Highest DMA rate: UDMA%s", amd_dma[fls(amd_config->udma_mask) - 1]);
-
- amd_print("BM-DMA base: %#lx", amd_base);
- amd_print("PCI clock: %d.%dMHz", amd_clock / 1000, amd_clock / 100 % 10);
-
- amd_print("-----------------------Primary IDE-------Secondary IDE------");
-
- pci_read_config_byte(dev, AMD_IDE_CONFIG, &t);
- amd_print("Prefetch Buffer: %10s%20s", (t & 0x80) ? "yes" : "no", (t & 0x20) ? "yes" : "no");
- amd_print("Post Write Buffer: %10s%20s", (t & 0x40) ? "yes" : "no", (t & 0x10) ? "yes" : "no");
-
- pci_read_config_byte(dev, AMD_IDE_ENABLE, &t);
- amd_print("Enabled: %10s%20s", (t & 0x02) ? "yes" : "no", (t & 0x01) ? "yes" : "no");
-
- c = inb(amd_base + 0x02) | (inb(amd_base + 0x0a) << 8);
- amd_print("Simplex only: %10s%20s", (c & 0x80) ? "yes" : "no", (c & 0x8000) ? "yes" : "no");
-
- amd_print("Cable Type: %10s%20s", (amd_80w & 1) ? "80w" : "40w", (amd_80w & 2) ? "80w" : "40w");
-
- if (!amd_clock)
- return p - buffer;
-
- amd_print("-------------------drive0----drive1----drive2----drive3-----");
-
- pci_read_config_byte(dev, AMD_ADDRESS_SETUP, &t);
- pci_read_config_dword(dev, AMD_DRIVE_TIMING, &v);
- pci_read_config_word(dev, AMD_8BIT_TIMING, &w);
- pci_read_config_dword(dev, AMD_UDMA_TIMING, &u);
-
- for (i = 0; i < 4; i++) {
- setup[i] = ((t >> ((3 - i) << 1)) & 0x3) + 1;
- recover8b[i] = ((w >> ((1 - (i >> 1)) << 3)) & 0xf) + 1;
- active8b[i] = ((w >> (((1 - (i >> 1)) << 3) + 4)) & 0xf) + 1;
- active[i] = ((v >> (((3 - i) << 3) + 4)) & 0xf) + 1;
- recover[i] = ((v >> ((3 - i) << 3)) & 0xf) + 1;
-
- udma[i] = amd_udma2cyc[((u >> ((3 - i) << 3)) & 0x7)];
- uen[i] = ((u >> ((3 - i) << 3)) & 0x40) ? 1 : 0;
- den[i] = (c & ((i & 1) ? 0x40 : 0x20) << ((i & 2) << 2));
-
- if (den[i] && uen[i] && udma[i] == 1) {
- speed[i] = amd_clock * 3;
- cycle[i] = 666666 / amd_clock;
- continue;
- }
-
- if (den[i] && uen[i] && udma[i] == 15) {
- speed[i] = amd_clock * 4;
- cycle[i] = 500000 / amd_clock;
- continue;
- }
-
- speed[i] = 4 * amd_clock / ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2);
- cycle[i] = 1000000 * ((den[i] && uen[i]) ? udma[i] : (active[i] + recover[i]) * 2) / amd_clock / 2;
- }
-
- amd_print_drive("Transfer Mode: ", "%10s", den[i] ? (uen[i] ? "UDMA" : "DMA") : "PIO");
-
- amd_print_drive("Address Setup: ", "%8dns", 1000000 * setup[i] / amd_clock);
- amd_print_drive("Cmd Active: ", "%8dns", 1000000 * active8b[i] / amd_clock);
- amd_print_drive("Cmd Recovery: ", "%8dns", 1000000 * recover8b[i] / amd_clock);
- amd_print_drive("Data Active: ", "%8dns", 1000000 * active[i] / amd_clock);
- amd_print_drive("Data Recovery: ", "%8dns", 1000000 * recover[i] / amd_clock);
- amd_print_drive("Cycle Time: ", "%8dns", cycle[i]);
- amd_print_drive("Transfer Rate: ", "%4d.%dMB/s", speed[i] / 1000, speed[i] / 100 % 10);
-
- /* hoping p - buffer is less than 4K... */
- len = (p - buffer) - offset;
- *addr = buffer + offset;
-
- return len > count ? count : len;
-}
-
-#endif
-
-/*
* amd_set_speed() writes timing values to the chipset registers
*/
@@ -229,20 +114,16 @@ static void amd_set_speed(struct pci_dev *dev, unsigned char dn, struct ide_timi
}
/*
- * amd_set_drive() computes timing values configures the drive and
- * the chipset to a desired transfer mode. It also can be called
- * by upper layers.
+ * amd_set_drive() computes timing values and configures the chipset
+ * to a desired transfer mode. It also can be called by upper layers.
*/
-static int amd_set_drive(ide_drive_t *drive, u8 speed)
+static void amd_set_drive(ide_drive_t *drive, const u8 speed)
{
ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
struct ide_timing t, p;
int T, UT;
- if (speed != XFER_PIO_SLOW)
- ide_config_drive_speed(drive, speed);
-
T = 1000000000 / amd_clock;
UT = (amd_config->udma_mask == ATA_UDMA2) ? T : (T / 2);
@@ -257,42 +138,15 @@ static int amd_set_drive(ide_drive_t *drive, u8 speed)
if (speed == XFER_UDMA_6 && amd_clock <= 33333) t.udma = 15;
amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
-
- if (!drive->init_speed)
- drive->init_speed = speed;
- drive->current_speed = speed;
-
- return 0;
}
/*
- * amd74xx_tune_drive() is a callback from upper layers for
- * PIO-only tuning.
+ * amd_set_pio_mode() is a callback from upper layers for PIO-only tuning.
*/
-static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio)
+static void amd_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- if (pio == 255)
- pio = ide_get_best_pio_mode(drive, 255, 5);
-
- amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5));
-}
-
-static int amd74xx_ide_dma_check(ide_drive_t *drive)
-{
- u8 speed = ide_max_dma_mode(drive);
-
- if (speed == 0) {
- amd74xx_tune_drive(drive, 255);
- return -1;
- }
-
- amd_set_drive(drive, speed);
-
- if (drive->autodma)
- return 0;
-
- return -1;
+ amd_set_drive(drive, XFER_PIO_0 + pio);
}
/*
@@ -379,55 +233,27 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const ch
* Print the boot message.
*/
- pci_read_config_byte(dev, PCI_REVISION_ID, &t);
printk(KERN_INFO "%s: %s (rev %02x) UDMA%s controller\n",
amd_chipset->name, pci_name(dev), dev->revision,
amd_dma[fls(amd_config->udma_mask) - 1]);
-/*
- * Register /proc/ide/amd74xx entry
- */
-
-#if defined(DISPLAY_AMD_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
- if (!amd74xx_proc) {
- amd_base = pci_resource_start(dev, 4);
- bmide_dev = dev;
- ide_pci_create_host_proc("amd74xx", amd74xx_get_info);
- amd74xx_proc = 1;
- }
-#endif /* DISPLAY_AMD_TIMINGS && CONFIG_IDE_PROC_FS */
-
return dev->irq;
}
static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
{
- int i;
-
if (hwif->irq == 0) /* 0 is bogus but will do for now */
hwif->irq = pci_get_legacy_ide_irq(hwif->pci_dev, hwif->channel);
- hwif->autodma = 0;
-
- hwif->tuneproc = &amd74xx_tune_drive;
- hwif->speedproc = &amd_set_drive;
-
- for (i = 0; i < 2; i++) {
- hwif->drives[i].io_32bit = 1;
- hwif->drives[i].unmask = 1;
- hwif->drives[i].autotune = 1;
- hwif->drives[i].dn = hwif->channel * 2 + i;
- }
+ hwif->set_pio_mode = &amd_set_pio_mode;
+ hwif->set_dma_mode = &amd_set_drive;
if (!hwif->dma_base)
return;
- hwif->atapi_dma = 1;
-
hwif->ultra_mask = amd_config->udma_mask;
- hwif->mwdma_mask = 0x07;
- if ((amd_config->flags & AMD_BAD_SWDMA) == 0)
- hwif->swdma_mask = 0x07;
+ if (amd_config->flags & AMD_BAD_SWDMA)
+ hwif->swdma_mask = 0x00;
if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
if ((amd_80w >> hwif->channel) & 1)
@@ -435,25 +261,26 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
else
hwif->cbl = ATA_CBL_PATA40;
}
-
- hwif->ide_dma_check = &amd74xx_ide_dma_check;
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
}
+#define IDE_HFLAGS_AMD \
+ (IDE_HFLAG_PIO_NO_BLACKLIST | \
+ IDE_HFLAG_PIO_NO_DOWNGRADE | \
+ IDE_HFLAG_POST_SET_MODE | \
+ IDE_HFLAG_IO_32BIT | \
+ IDE_HFLAG_UNMASK_IRQS | \
+ IDE_HFLAG_BOOTABLE)
+
#define DECLARE_AMD_DEV(name_str) \
{ \
.name = name_str, \
.init_chipset = init_chipset_amd74xx, \
.init_hwif = init_hwif_amd74xx, \
- .autodma = AUTODMA, \
.enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
- .bootable = ON_BOARD, \
- .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST \
- | IDE_HFLAG_PIO_NO_DOWNGRADE, \
+ .host_flags = IDE_HFLAGS_AMD, \
.pio_mask = ATA_PIO5, \
+ .swdma_mask = ATA_SWDMA2, \
+ .mwdma_mask = ATA_MWDMA2, \
}
#define DECLARE_NV_DEV(name_str) \
@@ -461,15 +288,14 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
.name = name_str, \
.init_chipset = init_chipset_amd74xx, \
.init_hwif = init_hwif_amd74xx, \
- .autodma = AUTODMA, \
.enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
- .bootable = ON_BOARD, \
- .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST \
- | IDE_HFLAG_PIO_NO_DOWNGRADE, \
+ .host_flags = IDE_HFLAGS_AMD, \
.pio_mask = ATA_PIO5, \
+ .swdma_mask = ATA_SWDMA2, \
+ .mwdma_mask = ATA_MWDMA2, \
}
-static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
+static const struct ide_port_info amd74xx_chipsets[] __devinitdata = {
/* 0 */ DECLARE_AMD_DEV("AMD7401"),
/* 1 */ DECLARE_AMD_DEV("AMD7409"),
/* 2 */ DECLARE_AMD_DEV("AMD7411"),
@@ -508,34 +334,34 @@ static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_
return ide_setup_pci_device(dev, amd_chipset);
}
-static struct pci_device_id amd74xx_pci_tbl[] = {
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
+static const struct pci_device_id amd74xx_pci_tbl[] = {
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7409), 1 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7411), 2 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_OPUS_7441), 3 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_8111_IDE), 4 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE), 6 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE), 7 },
#ifdef CONFIG_BLK_DEV_IDE_SATA
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA), 8 },
#endif
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE), 9 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE), 10 },
#ifdef CONFIG_BLK_DEV_IDE_SATA
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA), 11 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2), 12 },
#endif
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 21 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 22 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE), 13 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE), 14 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE), 15 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE), 16 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE), 17 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE), 18 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE), 19 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE), 20 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE), 21 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 22 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index 1725aa402d9..ef8e0164ef7 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/atiixp.c Version 0.02 Jun 16 2007
+ * linux/drivers/ide/pci/atiixp.c Version 0.03 Aug 3 2007
*
* Copyright (C) 2003 ATI Inc. <hyu@ati.com>
* Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
@@ -47,43 +47,6 @@ static int save_mdma_mode[4];
static DEFINE_SPINLOCK(atiixp_lock);
-/**
- * atiixp_dma_2_pio - return the PIO mode matching DMA
- * @xfer_rate: transfer speed
- *
- * Returns the nearest equivalent PIO timing for the PIO or DMA
- * mode requested by the controller.
- */
-
-static u8 atiixp_dma_2_pio(u8 xfer_rate) {
- switch(xfer_rate) {
- case XFER_UDMA_6:
- case XFER_UDMA_5:
- case XFER_UDMA_4:
- case XFER_UDMA_3:
- case XFER_UDMA_2:
- case XFER_UDMA_1:
- case XFER_UDMA_0:
- case XFER_MW_DMA_2:
- case XFER_PIO_4:
- return 4;
- case XFER_MW_DMA_1:
- case XFER_PIO_3:
- return 3;
- case XFER_SW_DMA_2:
- case XFER_PIO_2:
- return 2;
- case XFER_MW_DMA_0:
- case XFER_SW_DMA_1:
- case XFER_SW_DMA_0:
- case XFER_PIO_1:
- case XFER_PIO_0:
- case XFER_PIO_SLOW:
- default:
- return 0;
- }
-}
-
static void atiixp_dma_host_on(ide_drive_t *drive)
{
struct pci_dev *dev = drive->hwif->pci_dev;
@@ -122,14 +85,14 @@ static void atiixp_dma_host_off(ide_drive_t *drive)
}
/**
- * atiixp_tune_pio - tune a drive attached to a ATIIXP
- * @drive: drive to tune
- * @pio: desired PIO mode
+ * atiixp_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
* Set the interface PIO mode.
*/
-static void atiixp_tune_pio(ide_drive_t *drive, u8 pio)
+static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
struct pci_dev *dev = drive->hwif->pci_dev;
unsigned long flags;
@@ -153,38 +116,25 @@ static void atiixp_tune_pio(ide_drive_t *drive, u8 pio)
spin_unlock_irqrestore(&atiixp_lock, flags);
}
-static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
-{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- atiixp_tune_pio(drive, pio);
- (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
/**
- * atiixp_tune_chipset - tune a ATIIXP interface
- * @drive: IDE drive to tune
- * @xferspeed: speed to configure
+ * atiixp_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
- * Set a ATIIXP interface channel to the desired speeds. This involves
- * requires the right timing data into the ATIIXP configuration space
- * then setting the drive parameters appropriately
+ * Set a ATIIXP host controller to the desired DMA mode. This involves
+ * programming the right timing data into the PCI configuration space.
*/
-static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
+static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
struct pci_dev *dev = drive->hwif->pci_dev;
unsigned long flags;
int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
u32 tmp32;
u16 tmp16;
- u8 speed, pio;
- speed = ide_rate_filter(drive, xferspeed);
-
- if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
- atiixp_tune_pio(drive, speed - XFER_PIO_0);
- return ide_config_drive_speed(drive, speed);
- }
+ if (speed < XFER_MW_DMA_0)
+ return;
spin_lock_irqsave(&atiixp_lock, flags);
@@ -206,36 +156,6 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
}
spin_unlock_irqrestore(&atiixp_lock, flags);
-
- if (speed >= XFER_SW_DMA_0)
- pio = atiixp_dma_2_pio(speed);
- else
- pio = speed - XFER_PIO_0;
-
- atiixp_tune_pio(drive, pio);
-
- return ide_config_drive_speed(drive, speed);
-}
-
-/**
- * atiixp_dma_check - set up an IDE device
- * @drive: IDE drive to configure
- *
- * Set up the ATIIXP interface for the best available speed on this
- * interface, preferring DMA to PIO.
- */
-
-static int atiixp_dma_check(ide_drive_t *drive)
-{
- drive->init_speed = 0;
-
- if (ide_tune_dma(drive))
- return 0;
-
- if (ide_use_fast_pio(drive))
- atiixp_tuneproc(drive, 255);
-
- return -1;
}
/**
@@ -252,23 +172,12 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
u8 ch = hwif->channel;
struct pci_dev *pdev = hwif->pci_dev;
- if (!hwif->irq)
- hwif->irq = ch ? 15 : 14;
-
- hwif->autodma = 0;
- hwif->tuneproc = &atiixp_tuneproc;
- hwif->speedproc = &atiixp_speedproc;
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ hwif->set_pio_mode = &atiixp_set_pio_mode;
+ hwif->set_dma_mode = &atiixp_set_dma_mode;
if (!hwif->dma_base)
return;
- hwif->atapi_dma = 1;
- hwif->ultra_mask = 0x3f;
- hwif->mwdma_mask = 0x06;
- hwif->swdma_mask = 0x04;
-
pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ch, &udma_mode);
if ((udma_mode & 0x07) >= 0x04 || (udma_mode & 0x70) >= 0x40)
@@ -278,31 +187,26 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
hwif->dma_host_on = &atiixp_dma_host_on;
hwif->dma_host_off = &atiixp_dma_host_off;
- hwif->ide_dma_check = &atiixp_dma_check;
- if (!noautodma)
- hwif->autodma = 1;
-
- hwif->drives[1].autodma = hwif->autodma;
- hwif->drives[0].autodma = hwif->autodma;
}
-
-static ide_pci_device_t atiixp_pci_info[] __devinitdata = {
+static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
{ /* 0 */
.name = "ATIIXP",
.init_hwif = init_hwif_atiixp,
- .autodma = AUTODMA,
.enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
},{ /* 1 */
.name = "SB600_PATA",
.init_hwif = init_hwif_atiixp,
- .autodma = AUTODMA,
.enablebits = {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
- .bootable = ON_BOARD,
- .host_flags = IDE_HFLAG_SINGLE,
+ .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_LEGACY_IRQS |
+ IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
},
};
@@ -320,12 +224,12 @@ static int __devinit atiixp_init_one(struct pci_dev *dev, const struct pci_devic
return ide_setup_pci_device(dev, &atiixp_pci_info[id->driver_data]);
}
-static struct pci_device_id atiixp_pci_tbl[] = {
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+static const struct pci_device_id atiixp_pci_tbl[] = {
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), 0 },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), 0 },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), 0 },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), 1 },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP700_IDE), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
index 9689494efa2..4aa48104e0c 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/pci/cmd640.c
@@ -185,6 +185,8 @@ static u8 recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
+static DEFINE_SPINLOCK(cmd640_lock);
+
/*
* These are initialized to point at the devices we control
*/
@@ -258,12 +260,12 @@ static u8 get_cmd640_reg_vlb (u16 reg)
static u8 get_cmd640_reg(u16 reg)
{
- u8 b;
unsigned long flags;
+ u8 b;
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&cmd640_lock, flags);
b = __get_cmd640_reg(reg);
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
return b;
}
@@ -271,9 +273,9 @@ static void put_cmd640_reg(u16 reg, u8 val)
{
unsigned long flags;
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&cmd640_lock, flags);
__put_cmd640_reg(reg,val);
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
}
static int __init match_pci_cmd640_device (void)
@@ -351,7 +353,7 @@ static int __init secondary_port_responding (void)
{
unsigned long flags;
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&cmd640_lock, flags);
outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET); /* select drive0 */
udelay(100);
@@ -359,11 +361,11 @@ static int __init secondary_port_responding (void)
outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
udelay(100);
if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
return 0; /* nothing responded */
}
}
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
return 1; /* success */
}
@@ -440,11 +442,11 @@ static void __init setup_device_ptrs (void)
static void set_prefetch_mode (unsigned int index, int mode)
{
ide_drive_t *drive = cmd_drives[index];
+ unsigned long flags;
int reg = prefetch_regs[index];
u8 b;
- unsigned long flags;
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&cmd640_lock, flags);
b = __get_cmd640_reg(reg);
if (mode) { /* want prefetch on? */
#if CMD640_PREFETCH_MASKS
@@ -460,7 +462,7 @@ static void set_prefetch_mode (unsigned int index, int mode)
b |= prefetch_masks[index]; /* disable prefetch */
}
__put_cmd640_reg(reg, b);
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
}
/*
@@ -561,7 +563,7 @@ static void program_drive_counts (unsigned int index)
/*
* Now that everything is ready, program the new timings
*/
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&cmd640_lock, flags);
/*
* Program the address_setup clocks into ARTTIM reg,
* and then the active/recovery counts into the DRWTIM reg
@@ -570,7 +572,7 @@ static void program_drive_counts (unsigned int index)
setup_count |= __get_cmd640_reg(arttim_regs[index]) & 0x3f;
__put_cmd640_reg(arttim_regs[index], setup_count);
__put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
}
/*
@@ -628,45 +630,40 @@ static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle
program_drive_counts (index);
}
-/*
- * Drive PIO mode selection:
- */
-static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted)
+static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
unsigned int index = 0, cycle_time;
u8 b;
while (drive != cmd_drives[index]) {
if (++index > 3) {
- printk("%s: bad news in cmd640_tune_drive\n", drive->name);
+ printk(KERN_ERR "%s: bad news in %s\n",
+ drive->name, __FUNCTION__);
return;
}
}
- switch (mode_wanted) {
+ switch (pio) {
case 6: /* set fast-devsel off */
case 7: /* set fast-devsel on */
- mode_wanted &= 1;
b = get_cmd640_reg(CNTRL) & ~0x27;
- if (mode_wanted)
+ if (pio & 1)
b |= 0x27;
put_cmd640_reg(CNTRL, b);
- printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
+ printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, (pio & 1) ? "en" : "dis");
return;
case 8: /* set prefetch off */
case 9: /* set prefetch on */
- mode_wanted &= 1;
- set_prefetch_mode(index, mode_wanted);
- printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
+ set_prefetch_mode(index, pio & 1);
+ printk("%s: %sabled cmd640 prefetch\n", drive->name, (pio & 1) ? "en" : "dis");
return;
}
- mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 5);
- cycle_time = ide_pio_cycle_time(drive, mode_wanted);
- cmd640_set_mode(index, mode_wanted, cycle_time);
+ cycle_time = ide_pio_cycle_time(drive, pio);
+ cmd640_set_mode(index, pio, cycle_time);
printk("%s: selected cmd640 PIO mode%d (%dns)",
- drive->name, mode_wanted, cycle_time);
+ drive->name, pio, cycle_time);
display_clocks(index);
}
@@ -675,20 +672,20 @@ static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted)
static int pci_conf1(void)
{
- u32 tmp;
unsigned long flags;
+ u32 tmp;
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&cmd640_lock, flags);
outb(0x01, 0xCFB);
tmp = inl(0xCF8);
outl(0x80000000, 0xCF8);
if (inl(0xCF8) == 0x80000000) {
outl(tmp, 0xCF8);
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
return 1;
}
outl(tmp, 0xCF8);
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
return 0;
}
@@ -696,15 +693,15 @@ static int pci_conf2(void)
{
unsigned long flags;
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&cmd640_lock, flags);
outb(0x00, 0xCFB);
outb(0x00, 0xCF8);
outb(0x00, 0xCFA);
if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
return 1;
}
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&cmd640_lock, flags);
return 0;
}
@@ -766,8 +763,10 @@ int __init ide_probe_for_cmd640x (void)
cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
cmd_hwif0->chipset = ide_cmd640;
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ cmd_hwif0->host_flags = IDE_HFLAG_ABUSE_PREFETCH |
+ IDE_HFLAG_ABUSE_FAST_DEVSEL;
cmd_hwif0->pio_mask = ATA_PIO5;
- cmd_hwif0->tuneproc = &cmd640_tune_drive;
+ cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
/*
@@ -822,8 +821,10 @@ int __init ide_probe_for_cmd640x (void)
cmd_hwif1->mate = cmd_hwif0;
cmd_hwif1->channel = 1;
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ cmd_hwif1->host_flags = IDE_HFLAG_ABUSE_PREFETCH |
+ IDE_HFLAG_ABUSE_FAST_DEVSEL;
cmd_hwif1->pio_mask = ATA_PIO5;
- cmd_hwif1->tuneproc = &cmd640_tune_drive;
+ cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
}
printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 0e3b5de26e6..51fca441c29 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/cmd64x.c Version 1.50 May 10, 2007
+ * linux/drivers/ide/pci/cmd64x.c Version 1.51 Nov 8, 2007
*
* cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
* Due to massive hardware bugs, UltraDMA is only supported
@@ -214,28 +214,25 @@ static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_
}
/*
- * This routine selects drive's best PIO mode and writes into the chipset
- * registers setup/active/recovery timings.
+ * This routine writes into the chipset registers
+ * PIO setup/active/recovery timings.
*/
-static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted)
+static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
unsigned int cycle_time;
- u8 pio_mode, setup_count, arttim = 0;
+ u8 setup_count, arttim = 0;
+
static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
- pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5);
- cycle_time = ide_pio_cycle_time(drive, pio_mode);
-
- cmdprintk("%s: PIO mode wanted %d, selected %d (%d ns)\n",
- drive->name, mode_wanted, pio_mode, cycle_time);
+ cycle_time = ide_pio_cycle_time(drive, pio);
program_cycle_times(drive, cycle_time,
- ide_pio_timings[pio_mode].active_time);
+ ide_pio_timings[pio].active_time);
- setup_count = quantize_timing(ide_pio_timings[pio_mode].setup_time,
+ setup_count = quantize_timing(ide_pio_timings[pio].setup_time,
1000 / system_bus_clock());
/*
@@ -266,16 +263,14 @@ static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted)
arttim |= setup_values[setup_count];
(void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
cmdprintk("Write 0x%02x to reg 0x%x\n", arttim, arttim_regs[drive->dn]);
-
- return pio_mode;
}
/*
* Attempts to set drive's PIO mode.
- * Special cases are 8: prefetch off, 9: prefetch on (both never worked),
- * and 255: auto-select best mode (used at boot time).
+ * Special cases are 8: prefetch off, 9: prefetch on (both never worked)
*/
-static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio)
+
+static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
/*
* Filter out the prefetch control values
@@ -284,19 +279,16 @@ static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio)
if (pio == 8 || pio == 9)
return;
- pio = cmd64x_tune_pio(drive, pio);
- (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+ cmd64x_tune_pio(drive, pio);
}
-static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed)
+static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u8 unit = drive->dn & 0x01;
u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0;
- speed = ide_rate_filter(drive, speed);
-
if (speed >= XFER_SW_DMA_0) {
(void) pci_read_config_byte(dev, pciU, &regU);
regU &= ~(unit ? 0xCA : 0x35);
@@ -330,33 +322,12 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed)
case XFER_MW_DMA_0:
program_cycle_times(drive, 480, 215);
break;
- case XFER_PIO_5:
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- (void) cmd64x_tune_pio(drive, speed - XFER_PIO_0);
- break;
default:
- return 1;
+ return;
}
if (speed >= XFER_SW_DMA_0)
(void) pci_write_config_byte(dev, pciU, regU);
-
- return ide_config_drive_speed(drive, speed);
-}
-
-static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
-{
- if (ide_tune_dma(drive))
- return 0;
-
- if (ide_use_fast_pio(drive))
- cmd64x_tune_drive(drive, 255);
-
- return -1;
}
static int cmd648_ide_dma_end (ide_drive_t *drive)
@@ -368,7 +339,8 @@ static int cmd648_ide_dma_end (ide_drive_t *drive)
u8 mrdmode = inb(hwif->dma_master + 0x01);
/* clear the interrupt bit */
- outb(mrdmode | irq_mask, hwif->dma_master + 0x01);
+ outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask,
+ hwif->dma_master + 0x01);
return err;
}
@@ -468,11 +440,8 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
u8 mrdmode = 0;
if (dev->device == PCI_DEVICE_ID_CMD_646) {
- u8 rev = 0;
- pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
-
- switch (rev) {
+ switch (dev->revision) {
case 0x07:
case 0x05:
printk("%s: UltraDMA capable\n", name);
@@ -534,22 +503,13 @@ static u8 __devinit ata66_cmd64x(ide_hwif_t *hwif)
static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
- u8 rev = 0;
-
- pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
-
- hwif->tuneproc = &cmd64x_tune_drive;
- hwif->speedproc = &cmd64x_tune_chipset;
- hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+ hwif->set_pio_mode = &cmd64x_set_pio_mode;
+ hwif->set_dma_mode = &cmd64x_set_dma_mode;
if (!hwif->dma_base)
return;
- hwif->atapi_dma = 1;
- hwif->mwdma_mask = 0x07;
- hwif->ultra_mask = hwif->cds->udma_mask;
-
/*
* UltraDMA only supported on PCI646U and PCI646U2, which
* correspond to revisions 0x03, 0x05 and 0x07 respectively.
@@ -562,11 +522,9 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
*
* So we only do UltraDMA on revision 0x05 and 0x07 chipsets.
*/
- if (dev->device == PCI_DEVICE_ID_CMD_646 && rev < 5)
+ if (dev->device == PCI_DEVICE_ID_CMD_646 && dev->revision < 5)
hwif->ultra_mask = 0x00;
- hwif->ide_dma_check = &cmd64x_config_drive_for_dma;
-
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
hwif->cbl = ata66_cmd64x(hwif);
@@ -578,11 +536,10 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
hwif->ide_dma_test_irq = &cmd648_ide_dma_test_irq;
break;
case PCI_DEVICE_ID_CMD_646:
- hwif->chipset = ide_cmd646;
- if (rev == 0x01) {
+ if (dev->revision == 0x01) {
hwif->ide_dma_end = &cmd646_1_ide_dma_end;
break;
- } else if (rev >= 0x03)
+ } else if (dev->revision >= 0x03)
goto alt_irq_bits;
/* fall thru */
default:
@@ -590,89 +547,71 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
break;
}
-
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
-}
-
-static int __devinit init_setup_cmd64x(struct pci_dev *dev, ide_pci_device_t *d)
-{
- return ide_setup_pci_device(dev, d);
-}
-
-static int __devinit init_setup_cmd646(struct pci_dev *dev, ide_pci_device_t *d)
-{
- /*
- * The original PCI0646 didn't have the primary channel enable bit,
- * it appeared starting with PCI0646U (i.e. revision ID 3).
- */
- if (dev->revision < 3)
- d->enablebits[0].reg = 0;
-
- return ide_setup_pci_device(dev, d);
}
-static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
+static const struct ide_port_info cmd64x_chipsets[] __devinitdata = {
{ /* 0 */
.name = "CMD643",
- .init_setup = init_setup_cmd64x,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
- .autodma = AUTODMA,
.enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO5,
+ .mwdma_mask = ATA_MWDMA2,
.udma_mask = 0x00, /* no udma */
},{ /* 1 */
.name = "CMD646",
- .init_setup = init_setup_cmd646,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
- .autodma = AUTODMA,
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO5,
- .udma_mask = 0x07, /* udma0-2 */
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
},{ /* 2 */
.name = "CMD648",
- .init_setup = init_setup_cmd64x,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
- .autodma = AUTODMA,
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
- .bootable = ON_BOARD,
+ .chipset = ide_cmd646,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO5,
- .udma_mask = 0x1f, /* udma0-4 */
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
},{ /* 3 */
.name = "CMD649",
- .init_setup = init_setup_cmd64x,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
- .autodma = AUTODMA,
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_ABUSE_PREFETCH | IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO5,
- .udma_mask = 0x3f, /* udma0-5 */
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
}
};
-/*
- * We may have to modify enablebits for PCI0646, so we'd better pass
- * a local copy of the ide_pci_device_t structure down the call chain...
- */
static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_pci_device_t d = cmd64x_chipsets[id->driver_data];
+ struct ide_port_info d;
+ u8 idx = id->driver_data;
+
+ d = cmd64x_chipsets[idx];
+
+ /*
+ * The original PCI0646 didn't have the primary channel enable bit,
+ * it appeared starting with PCI0646U (i.e. revision ID 3).
+ */
+ if (idx == 1 && dev->revision < 3)
+ d.enablebits[0].reg = 0;
- return d.init_setup(dev, &d);
+ return ide_setup_pci_device(dev, &d);
}
-static struct pci_device_id cmd64x_pci_tbl[] = {
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+static const struct pci_device_id cmd64x_pci_tbl[] = {
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 2 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 3 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl);
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index b89e8165687..0466462fd21 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -66,32 +66,13 @@ static struct pio_clocks cs5520_pio_clocks[]={
{1, 2, 1}
};
-static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *pdev = hwif->pci_dev;
- u8 speed = min((u8)XFER_PIO_4, xferspeed);
- int pio = speed;
- u8 reg;
int controller = drive->dn > 1 ? 1 : 0;
- int error;
-
- switch(speed)
- {
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- pio -= XFER_PIO_0;
- break;
- default:
- pio = 0;
- printk(KERN_ERR "cs55x0: bad ide timing.\n");
- }
-
- printk("PIO clocking = %d\n", pio);
-
+ u8 reg;
+
/* FIXME: if DMA = 1 do we need to set the DMA bit here ? */
/* 8bit CAT/CRT - 8bit command timing for channel */
@@ -115,40 +96,13 @@ static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed)
reg = inb(hwif->dma_base + 0x02 + 8*controller);
reg |= 1<<((drive->dn&1)+5);
outb(reg, hwif->dma_base + 0x02 + 8*controller);
-
- error = ide_config_drive_speed(drive, speed);
- /* ATAPI is harder so leave it for now */
- if(!error && drive->media == ide_disk)
- error = hwif->ide_dma_on(drive);
-
- return error;
-}
-
-static void cs5520_tune_drive(ide_drive_t *drive, u8 pio)
-{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- cs5520_tune_chipset(drive, (XFER_PIO_0 + pio));
}
-static int cs5520_config_drive_xfer_rate(ide_drive_t *drive)
+static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
- /* Tune the drive for PIO modes up to PIO 4 */
- cs5520_tune_drive(drive, 255);
+ printk(KERN_ERR "cs55x0: bad ide timing.\n");
- /* Then tell the core to use DMA operations */
- return 0;
-}
-
-/*
- * We provide a callback for our nonstandard DMA location
- */
-
-static void __devinit cs5520_init_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif)
-{
- unsigned long bmide = pci_resource_start(dev, 2); /* Not the usual 4 */
- if(hwif->mate && hwif->mate->dma_base) /* Second channel at primary + 8 */
- bmide += 8;
- ide_setup_dma(hwif, bmide, 8);
+ cs5520_set_pio_mode(drive, 0);
}
/*
@@ -159,48 +113,35 @@ static void __devinit cs5520_init_setup_dma(struct pci_dev *dev, ide_pci_device_
static int cs5520_dma_on(ide_drive_t *drive)
{
+ /* ATAPI is harder so leave it for now */
drive->vdma = 1;
return 0;
}
static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
{
- hwif->tuneproc = &cs5520_tune_drive;
- hwif->speedproc = &cs5520_tune_chipset;
- hwif->ide_dma_check = &cs5520_config_drive_xfer_rate;
- hwif->ide_dma_on = &cs5520_dma_on;
+ hwif->set_pio_mode = &cs5520_set_pio_mode;
+ hwif->set_dma_mode = &cs5520_set_dma_mode;
- if(!noautodma)
- hwif->autodma = 1;
-
- if(!hwif->dma_base)
- {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ if (hwif->dma_base == 0)
return;
- }
-
- hwif->atapi_dma = 0;
- hwif->ultra_mask = 0;
- hwif->swdma_mask = 0;
- hwif->mwdma_mask = 0;
-
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
+
+ hwif->ide_dma_on = &cs5520_dma_on;
}
#define DECLARE_CS_DEV(name_str) \
{ \
.name = name_str, \
- .init_setup_dma = cs5520_init_setup_dma, \
.init_hwif = init_hwif_cs5520, \
- .autodma = AUTODMA, \
- .bootable = ON_BOARD, \
- .host_flags = IDE_HFLAG_ISA_PORTS, \
+ .host_flags = IDE_HFLAG_ISA_PORTS | \
+ IDE_HFLAG_CS5520 | \
+ IDE_HFLAG_VDMA | \
+ IDE_HFLAG_NO_ATAPI_DMA | \
+ IDE_HFLAG_BOOTABLE, \
.pio_mask = ATA_PIO4, \
}
-static ide_pci_device_t cyrix_chipsets[] __devinitdata = {
+static const struct ide_port_info cyrix_chipsets[] __devinitdata = {
/* 0 */ DECLARE_CS_DEV("Cyrix 5510"),
/* 1 */ DECLARE_CS_DEV("Cyrix 5520")
};
@@ -213,9 +154,8 @@ static ide_pci_device_t cyrix_chipsets[] __devinitdata = {
static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_hwif_t *hwif = NULL, *mate = NULL;
- ata_index_t index;
- ide_pci_device_t *d = &cyrix_chipsets[id->driver_data];
+ const struct ide_port_info *d = &cyrix_chipsets[id->driver_data];
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
ide_setup_pci_noise(dev, d);
@@ -231,36 +171,21 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
return -ENODEV;
}
- index.all = 0xf0f0;
-
/*
* Now the chipset is configured we can let the core
* do all the device setup for us
*/
- ide_pci_setup_ports(dev, d, 14, &index);
-
- if ((index.b.low & 0xf0) != 0xf0)
- hwif = &ide_hwifs[index.b.low];
- if ((index.b.high & 0xf0) != 0xf0)
- mate = &ide_hwifs[index.b.high];
-
- if (hwif)
- probe_hwif_init(hwif);
- if (mate)
- probe_hwif_init(mate);
+ ide_pci_setup_ports(dev, d, 14, &idx[0]);
- if (hwif)
- ide_proc_register_port(hwif);
- if (mate)
- ide_proc_register_port(mate);
+ ide_device_add(idx);
return 0;
}
-static struct pci_device_id cs5520_pci_tbl[] = {
- { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+static const struct pci_device_id cs5520_pci_tbl[] = {
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), 0 },
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), 1 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl);
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index e5949b1d3fb..547690395ee 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/cs5530.c Version 0.74 Jul 28 2007
+ * linux/drivers/ide/pci/cs5530.c Version 0.77 Sep 24 2007
*
* Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2000 Mark Lord <mlord@pobox.com>
@@ -30,22 +30,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-/**
- * cs5530_xfer_set_mode - set a new transfer mode at the drive
- * @drive: drive to tune
- * @mode: new mode
- *
- * Logging wrapper to the IDE driver speed configuration. This can
- * probably go away now.
- */
-
-static int cs5530_set_xfer_mode (ide_drive_t *drive, u8 mode)
-{
- printk(KERN_DEBUG "%s: cs5530_set_xfer_mode(%s)\n",
- drive->name, ide_xfer_verbose(mode));
- return (ide_config_drive_speed(drive, mode));
-}
-
/*
* Here are the standard PIO mode 0-4 timings for each "format".
* Format-0 uses fast data reg timings, with slower command reg timings.
@@ -62,30 +46,23 @@ static unsigned int cs5530_pio_timings[2][5] = {
#define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
#define CS5530_BASEREG(hwif) (((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
-static void cs5530_tunepio(ide_drive_t *drive, u8 pio)
-{
- unsigned long basereg = CS5530_BASEREG(drive->hwif);
- unsigned int format = (inl(basereg + 4) >> 31) & 1;
-
- outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3));
-}
-
/**
- * cs5530_tuneproc - select/set PIO modes
+ * cs5530_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
- * cs5530_tuneproc() handles selection/setting of PIO modes
- * for both the chipset and drive.
+ * Handles setting of PIO mode for the chipset.
*
- * The ide_init_cs5530() routine guarantees that all drives
+ * The init_hwif_cs5530() routine guarantees that all drives
* will have valid default PIO timings set up before we get here.
*/
-static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autotune" */
+static void cs5530_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4);
+ unsigned long basereg = CS5530_BASEREG(drive->hwif);
+ unsigned int format = (inl(basereg + 4) >> 31) & 1;
- if (cs5530_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
- cs5530_tunepio(drive, pio);
+ outl(cs5530_pio_timings[format][pio], basereg + ((drive->dn & 1)<<3));
}
/**
@@ -127,38 +104,11 @@ out:
return mask;
}
-/**
- * cs5530_config_dma - set DMA/UDMA mode
- * @drive: drive to tune
- *
- * cs5530_config_dma() handles setting of DMA/UDMA mode
- * for both the chipset and drive.
- */
-
-static int cs5530_config_dma(ide_drive_t *drive)
-{
- if (ide_tune_dma(drive))
- return 0;
-
- return 1;
-}
-
-static int cs5530_tune_chipset(ide_drive_t *drive, u8 mode)
+static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
{
unsigned long basereg;
unsigned int reg, timings = 0;
- mode = ide_rate_filter(drive, mode);
-
- /*
- * Tell the drive to switch to the new mode; abort on failure.
- */
- if (cs5530_set_xfer_mode(drive, mode))
- return 1; /* failure */
-
- /*
- * Now tune the chipset to match the drive:
- */
switch (mode) {
case XFER_UDMA_0: timings = 0x00921250; break;
case XFER_UDMA_1: timings = 0x00911140; break;
@@ -166,16 +116,8 @@ static int cs5530_tune_chipset(ide_drive_t *drive, u8 mode)
case XFER_MW_DMA_0: timings = 0x00077771; break;
case XFER_MW_DMA_1: timings = 0x00012121; break;
case XFER_MW_DMA_2: timings = 0x00002020; break;
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- cs5530_tunepio(drive, mode - XFER_PIO_0);
- return 0;
default:
- BUG();
- break;
+ return;
}
basereg = CS5530_BASEREG(drive->hwif);
reg = inl(basereg + 4); /* get drive0 config register */
@@ -190,8 +132,6 @@ static int cs5530_tune_chipset(ide_drive_t *drive, u8 mode)
outl(reg, basereg + 4); /* write drive0 config register */
outl(timings, basereg + 12); /* write drive1 config register */
}
-
- return 0; /* success */
}
/**
@@ -205,7 +145,6 @@ static int cs5530_tune_chipset(ide_drive_t *drive, u8 mode)
static unsigned int __devinit init_chipset_cs5530 (struct pci_dev *dev, const char *name)
{
struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
- unsigned long flags;
if (pci_resource_start(dev, 4) == 0)
return -EFAULT;
@@ -230,9 +169,6 @@ static unsigned int __devinit init_chipset_cs5530 (struct pci_dev *dev, const ch
goto out;
}
- spin_lock_irqsave(&ide_lock, flags);
- /* all CPUs (there should only be one CPU with this chipset) */
-
/*
* Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
* --> OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530
@@ -283,8 +219,6 @@ static unsigned int __devinit init_chipset_cs5530 (struct pci_dev *dev, const ch
pci_write_config_byte(master_0, 0x42, 0x00);
pci_write_config_byte(master_0, 0x43, 0xc1);
- spin_unlock_irqrestore(&ide_lock, flags);
-
out:
pci_dev_put(master_0);
pci_dev_put(cs5530_0);
@@ -303,53 +237,33 @@ static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif)
{
unsigned long basereg;
u32 d0_timings;
- hwif->autodma = 0;
- if (hwif->mate)
- hwif->serialized = hwif->mate->serialized = 1;
-
- hwif->tuneproc = &cs5530_tuneproc;
- hwif->speedproc = &cs5530_tune_chipset;
+ hwif->set_pio_mode = &cs5530_set_pio_mode;
+ hwif->set_dma_mode = &cs5530_set_dma_mode;
basereg = CS5530_BASEREG(hwif);
d0_timings = inl(basereg + 0);
- if (CS5530_BAD_PIO(d0_timings)) {
- /* PIO timings not initialized? */
+ if (CS5530_BAD_PIO(d0_timings))
outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 0);
- if (!hwif->drives[0].autotune)
- hwif->drives[0].autotune = 1;
- /* needs autotuning later */
- }
- if (CS5530_BAD_PIO(inl(basereg + 8))) {
- /* PIO timings not initialized? */
+ if (CS5530_BAD_PIO(inl(basereg + 8)))
outl(cs5530_pio_timings[(d0_timings >> 31) & 1][0], basereg + 8);
- if (!hwif->drives[1].autotune)
- hwif->drives[1].autotune = 1;
- /* needs autotuning later */
- }
if (hwif->dma_base == 0)
return;
- hwif->atapi_dma = 1;
- hwif->ultra_mask = 0x07;
- hwif->mwdma_mask = 0x07;
-
hwif->udma_filter = cs5530_udma_filter;
- hwif->ide_dma_check = &cs5530_config_dma;
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
}
-static ide_pci_device_t cs5530_chipset __devinitdata = {
+static const struct ide_port_info cs5530_chipset __devinitdata = {
.name = "CS5530",
.init_chipset = init_chipset_cs5530,
.init_hwif = init_hwif_cs5530,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_SERIALIZE |
+ IDE_HFLAG_POST_SET_MODE |
+ IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
};
static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -357,8 +271,8 @@ static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_devic
return ide_setup_pci_device(dev, &cs5530_chipset);
}
-static struct pci_device_id cs5530_pci_tbl[] = {
- { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static const struct pci_device_id cs5530_pci_tbl[] = {
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl);
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
index 082ca7da2cb..9094916e378 100644
--- a/drivers/ide/pci/cs5535.c
+++ b/drivers/ide/pci/cs5535.c
@@ -75,7 +75,7 @@ static unsigned int cs5535_udma_timings[5] =
*
* cs5535_set_speed() configures the chipset to a new speed.
*/
-static void cs5535_set_speed(ide_drive_t *drive, u8 speed)
+static void cs5535_set_speed(ide_drive_t *drive, const u8 speed)
{
u32 reg = 0, dummy;
@@ -84,7 +84,7 @@ static void cs5535_set_speed(ide_drive_t *drive, u8 speed)
/* Set the PIO timings */
if ((speed & XFER_MODE) == XFER_PIO) {
- ide_drive_t *pair = &drive->hwif->drives[drive->dn ^ 1];
+ ide_drive_t *pair = ide_get_paired_drive(drive);
u8 cmd, pioa;
cmd = pioa = speed - XFER_PIO_0;
@@ -131,48 +131,30 @@ static void cs5535_set_speed(ide_drive_t *drive, u8 speed)
}
}
-/****
- * cs5535_set_drive - Configure the drive to the new speed
- * @drive: Drive to set up
- * @speed: desired speed
+/**
+ * cs5535_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
- * cs5535_set_drive() configures the drive and the chipset to a
- * new speed. It also can be called by upper layers.
+ * Programs the chipset for DMA mode.
*/
-static int cs5535_set_drive(ide_drive_t *drive, u8 speed)
+
+static void cs5535_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
- speed = ide_rate_filter(drive, speed);
- ide_config_drive_speed(drive, speed);
cs5535_set_speed(drive, speed);
-
- return 0;
}
-/****
- * cs5535_tuneproc - PIO setup
- * @drive: drive to set up
- * @pio: mode to use (255 for 'best possible')
+/**
+ * cs5535_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
* A callback from the upper layers for PIO-only tuning.
*/
-static void cs5535_tuneproc(ide_drive_t *drive, u8 pio)
-{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- ide_config_drive_speed(drive, XFER_PIO_0 + pio);
- cs5535_set_speed(drive, XFER_PIO_0 + pio);
-}
-static int cs5535_dma_check(ide_drive_t *drive)
+static void cs5535_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- drive->init_speed = 0;
-
- if (ide_tune_dma(drive))
- return 0;
-
- if (ide_use_fast_pio(drive))
- cs5535_tuneproc(drive, 255);
-
- return -1;
+ cs5535_set_speed(drive, XFER_PIO_0 + pio);
}
static u8 __devinit cs5535_cable_detect(struct pci_dev *dev)
@@ -195,37 +177,23 @@ static u8 __devinit cs5535_cable_detect(struct pci_dev *dev)
*/
static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
{
- int i;
-
- hwif->autodma = 0;
-
- hwif->tuneproc = &cs5535_tuneproc;
- hwif->speedproc = &cs5535_set_drive;
- hwif->ide_dma_check = &cs5535_dma_check;
+ hwif->set_pio_mode = &cs5535_set_pio_mode;
+ hwif->set_dma_mode = &cs5535_set_dma_mode;
- hwif->atapi_dma = 1;
- hwif->ultra_mask = 0x1F;
- hwif->mwdma_mask = 0x07;
+ if (hwif->dma_base == 0)
+ return;
hwif->cbl = cs5535_cable_detect(hwif->pci_dev);
-
- if (!noautodma)
- hwif->autodma = 1;
-
- /* just setting autotune and not worrying about bios timings */
- for (i = 0; i < 2; i++) {
- hwif->drives[i].autotune = 1;
- hwif->drives[i].autodma = hwif->autodma;
- }
}
-static ide_pci_device_t cs5535_chipset __devinitdata = {
+static const struct ide_port_info cs5535_chipset __devinitdata = {
.name = "CS5535",
.init_hwif = init_hwif_cs5535,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
- .host_flags = IDE_HFLAG_SINGLE,
+ .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE |
+ IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
};
static int __devinit cs5535_init_one(struct pci_dev *dev,
@@ -234,10 +202,8 @@ static int __devinit cs5535_init_one(struct pci_dev *dev,
return ide_setup_pci_device(dev, &cs5535_chipset);
}
-static struct pci_device_id cs5535_pci_tbl[] =
-{
- { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_IDE, PCI_ANY_ID,
- PCI_ANY_ID, 0, 0, 0},
+static const struct pci_device_id cs5535_pci_tbl[] = {
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_CS5535_IDE), 0 },
{ 0, },
};
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index daa36fcbc8e..1cd4e9cb052 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/cy82c693.c Version 0.40 Sep. 10, 2002
+ * linux/drivers/ide/pci/cy82c693.c Version 0.42 Oct 23, 2007
*
* Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer
* Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator
@@ -97,9 +97,6 @@
#define CY82_INDEX_CHANNEL1 0x31
#define CY82_INDEX_TIMEOUT 0x32
-/* the max PIO mode - from datasheet */
-#define CY82C693_MAX_PIO 4
-
/* the min and max PCI bus speed in MHz - from datasheet */
#define CY82C963_MIN_BUS_SPEED 25
#define CY82C963_MAX_BUS_SPEED 33
@@ -148,9 +145,6 @@ static void compute_clocks (u8 pio, pio_clocks_t *p_pclk)
* so you can play with the idebus=xx parameter
*/
- if (pio > CY82C693_MAX_PIO)
- pio = CY82C693_MAX_PIO;
-
/* let's calc the address setup time clocks */
p_pclk->address_time = (u8)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
@@ -269,10 +263,7 @@ static int cy82c693_ide_dma_on (ide_drive_t *drive)
return __ide_dma_on(drive);
}
-/*
- * tune ide drive - set PIO mode
- */
-static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
+static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -329,13 +320,6 @@ static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
#endif /* CY82C693_DEBUG_LOGS */
- /* first let's calc the pio modes */
- pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO);
-
-#if CY82C693_DEBUG_INFO
- printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
-#endif /* CY82C693_DEBUG_INFO */
-
/* let's calc the values for this PIO mode */
compute_clocks(pio, &pclk);
@@ -444,32 +428,18 @@ static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev, const c
*/
static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif)
{
- hwif->autodma = 0;
-
- hwif->chipset = ide_cy82c693;
- hwif->tuneproc = &cy82c693_tune_drive;
+ hwif->set_pio_mode = &cy82c693_set_pio_mode;
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ if (hwif->dma_base == 0)
return;
- }
-
- hwif->atapi_dma = 1;
- hwif->mwdma_mask = 0x04;
- hwif->swdma_mask = 0x04;
hwif->ide_dma_on = &cy82c693_ide_dma_on;
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
}
-static __devinitdata ide_hwif_t *primary;
-
static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
{
+ static ide_hwif_t *primary;
+
if (PCI_FUNC(hwif->pci_dev->devfn) == 1)
primary = hwif;
else {
@@ -478,15 +448,17 @@ static void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
}
}
-static ide_pci_device_t cy82c693_chipset __devinitdata = {
+static const struct ide_port_info cy82c693_chipset __devinitdata = {
.name = "CY82C693",
.init_chipset = init_chipset_cy82c693,
.init_iops = init_iops_cy82c693,
.init_hwif = init_hwif_cy82c693,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
- .host_flags = IDE_HFLAG_SINGLE,
+ .chipset = ide_cy82c693,
+ .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+ IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .swdma_mask = ATA_SWDMA2_ONLY,
+ .mwdma_mask = ATA_MWDMA2_ONLY,
};
static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -505,8 +477,8 @@ static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_dev
return ret;
}
-static struct pci_device_id cy82c693_pci_tbl[] = {
- { PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static const struct pci_device_id cy82c693_pci_tbl[] = {
+ { PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl);
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
index 46f4a888c03..83829081640 100644
--- a/drivers/ide/pci/delkin_cb.c
+++ b/drivers/ide/pci/delkin_cb.c
@@ -80,7 +80,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
hw.irq = dev->irq;
hw.chipset = ide_pci; /* this enables IRQ sharing */
- rc = ide_register_hw_with_fixup(&hw, 0, &hwif, ide_undecoded_slave);
+ rc = ide_register_hw(&hw, &ide_undecoded_slave, 0, &hwif);
if (rc < 0) {
printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
pci_disable_device(dev);
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index 48caa468b76..06885697ed7 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -49,125 +49,66 @@ static int __init ide_generic_all_on(char *unused)
printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n");
return 1;
}
-__setup("all-generic-ide", ide_generic_all_on);
+const __setup("all-generic-ide", ide_generic_all_on);
#endif
module_param_named(all_generic_ide, ide_generic_all, bool, 0444);
MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers.");
-static void __devinit init_hwif_generic (ide_hwif_t *hwif)
-{
- switch(hwif->pci_dev->device) {
- case PCI_DEVICE_ID_UMC_UM8673F:
- case PCI_DEVICE_ID_UMC_UM8886A:
- case PCI_DEVICE_ID_UMC_UM8886BF:
- hwif->irq = hwif->channel ? 15 : 14;
- break;
- default:
- break;
+#define IDE_HFLAGS_UMC (IDE_HFLAG_NO_DMA | IDE_HFLAG_FORCE_LEGACY_IRQS)
+
+#define DECLARE_GENERIC_PCI_DEV(name_str, extra_flags) \
+ { \
+ .name = name_str, \
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA | \
+ extra_flags | \
+ IDE_HFLAG_BOOTABLE, \
+ .swdma_mask = ATA_SWDMA2, \
+ .mwdma_mask = ATA_MWDMA2, \
+ .udma_mask = ATA_UDMA6, \
}
- if (!(hwif->dma_base))
- return;
-
- hwif->atapi_dma = 1;
- hwif->ultra_mask = 0x7f;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
-
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
-}
-
-#if 0
- /* Logic to add back later on */
-
- if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
- ide_pci_device_t *unknown = unknown_chipset;
- init_setup_unknown(dev, unknown);
- return 1;
- }
- return 0;
-#endif
+static const struct ide_port_info generic_chipsets[] __devinitdata = {
+ /* 0 */ DECLARE_GENERIC_PCI_DEV("Unknown", 0),
-static ide_pci_device_t generic_chipsets[] __devinitdata = {
- { /* 0 */
- .name = "Unknown",
- .init_hwif = init_hwif_generic,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
- },{ /* 1 */
+ { /* 1 */
.name = "NS87410",
- .init_hwif = init_hwif_generic,
- .autodma = AUTODMA,
.enablebits = {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
- .bootable = ON_BOARD,
- },{ /* 2 */
- .name = "SAMURAI",
- .init_hwif = init_hwif_generic,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
- },{ /* 3 */
- .name = "HT6565",
- .init_hwif = init_hwif_generic,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
- },{ /* 4 */
- .name = "UM8673F",
- .init_hwif = init_hwif_generic,
- .autodma = NODMA,
- .bootable = ON_BOARD,
- },{ /* 5 */
- .name = "UM8886A",
- .init_hwif = init_hwif_generic,
- .autodma = NODMA,
- .bootable = ON_BOARD,
- },{ /* 6 */
- .name = "UM8886BF",
- .init_hwif = init_hwif_generic,
- .autodma = NODMA,
- .bootable = ON_BOARD,
- },{ /* 7 */
- .name = "HINT_IDE",
- .init_hwif = init_hwif_generic,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
- },{ /* 8 */
- .name = "VIA_IDE",
- .init_hwif = init_hwif_generic,
- .autodma = NOAUTODMA,
- .bootable = ON_BOARD,
- },{ /* 9 */
- .name = "OPTI621V",
- .init_hwif = init_hwif_generic,
- .autodma = NOAUTODMA,
- .bootable = ON_BOARD,
- },{ /* 10 */
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+ IDE_HFLAG_BOOTABLE,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ },
+
+ /* 2 */ DECLARE_GENERIC_PCI_DEV("SAMURAI", 0),
+ /* 3 */ DECLARE_GENERIC_PCI_DEV("HT6565", 0),
+ /* 4 */ DECLARE_GENERIC_PCI_DEV("UM8673F", IDE_HFLAGS_UMC),
+ /* 5 */ DECLARE_GENERIC_PCI_DEV("UM8886A", IDE_HFLAGS_UMC),
+ /* 6 */ DECLARE_GENERIC_PCI_DEV("UM8886BF", IDE_HFLAGS_UMC),
+ /* 7 */ DECLARE_GENERIC_PCI_DEV("HINT_IDE", 0),
+ /* 8 */ DECLARE_GENERIC_PCI_DEV("VIA_IDE", IDE_HFLAG_NO_AUTODMA),
+ /* 9 */ DECLARE_GENERIC_PCI_DEV("OPTI621V", IDE_HFLAG_NO_AUTODMA),
+
+ { /* 10 */
.name = "VIA8237SATA",
- .init_hwif = init_hwif_generic,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- },{ /* 11 */
- .name = "Piccolo0102",
- .init_hwif = init_hwif_generic,
- .autodma = NOAUTODMA,
- .bootable = ON_BOARD,
- },{ /* 12 */
- .name = "Piccolo0103",
- .init_hwif = init_hwif_generic,
- .autodma = NOAUTODMA,
- .bootable = ON_BOARD,
- },{ /* 13 */
- .name = "Piccolo0105",
- .init_hwif = init_hwif_generic,
- .autodma = NOAUTODMA,
- .bootable = ON_BOARD,
- },{ /* 14 */
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+ IDE_HFLAG_OFF_BOARD,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ },
+
+ /* 11 */ DECLARE_GENERIC_PCI_DEV("Piccolo0102", IDE_HFLAG_NO_AUTODMA),
+ /* 12 */ DECLARE_GENERIC_PCI_DEV("Piccolo0103", IDE_HFLAG_NO_AUTODMA),
+ /* 13 */ DECLARE_GENERIC_PCI_DEV("Piccolo0105", IDE_HFLAG_NO_AUTODMA),
+
+ { /* 14 */
.name = "Revolution",
- .init_hwif = init_hwif_generic,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+ IDE_HFLAG_OFF_BOARD,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
}
};
@@ -182,7 +123,7 @@ static ide_pci_device_t generic_chipsets[] __devinitdata = {
static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_pci_device_t *d = &generic_chipsets[id->driver_data];
+ const struct ide_port_info *d = &generic_chipsets[id->driver_data];
int ret = -ENODEV;
/* Don't use the generic entry unless instructed to do so */
@@ -226,25 +167,28 @@ out:
return ret;
}
-static struct pci_device_id generic_pci_tbl[] = {
- { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
- { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
- { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
- { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
- { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
- { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
- { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+static const struct pci_device_id generic_pci_tbl[] = {
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87410), 1 },
+ { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE), 2 },
+ { PCI_VDEVICE(HOLTEK, PCI_DEVICE_ID_HOLTEK_6565), 3 },
+ { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8673F), 4 },
+ { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8886A), 5 },
+ { PCI_VDEVICE(UMC, PCI_DEVICE_ID_UMC_UM8886BF), 6 },
+ { PCI_VDEVICE(HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE), 7 },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C561), 8 },
+ { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C558), 9 },
#ifdef CONFIG_BLK_DEV_IDE_SATA
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_8237_SATA), 10 },
#endif
- { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
- { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
- { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
- { PCI_VENDOR_ID_NETCELL,PCI_DEVICE_ID_REVOLUTION, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14},
- /* Must come last. If you add entries adjust this table appropriately and the init_one code */
- { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0},
+ { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO), 11 },
+ { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), 12 },
+ { PCI_VDEVICE(TOSHIBA, PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), 13 },
+ { PCI_VDEVICE(NETCELL, PCI_DEVICE_ID_REVOLUTION), 14 },
+ /*
+ * Must come last. If you add entries adjust
+ * this table and generic_chipsets[] appropriately.
+ */
+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, generic_pci_tbl);
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index cb8fe5643d3..ae6307fae4f 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -43,10 +43,9 @@
#define HPT343_DEBUG_DRIVE_INFO 0
-static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static void hpt34x_set_mode(ide_drive_t *drive, const u8 speed)
{
struct pci_dev *dev = HWIF(drive)->pci_dev;
- u8 speed = ide_rate_filter(drive, xferspeed);
u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
u8 hi_speed, lo_speed;
@@ -74,27 +73,11 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
drive->dn, reg1, tmp1, reg2, tmp2,
hi_speed, lo_speed);
#endif /* HPT343_DEBUG_DRIVE_INFO */
-
- return(ide_config_drive_speed(drive, speed));
}
-static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio)
+static void hpt34x_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 5);
- (void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
-}
-
-static int hpt34x_config_drive_xfer_rate (ide_drive_t *drive)
-{
- drive->init_speed = 0;
-
- if (ide_tune_dma(drive))
- return -1;
-
- if (ide_use_fast_pio(drive))
- hpt34x_tune_drive(drive, 255);
-
- return -1;
+ hpt34x_set_mode(drive, XFER_PIO_0 + pio);
}
/*
@@ -142,59 +125,51 @@ static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const cha
static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif)
{
- u16 pcicmd = 0;
-
- hwif->autodma = 0;
-
- hwif->tuneproc = &hpt34x_tune_drive;
- hwif->speedproc = &hpt34x_tune_chipset;
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
-
- pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
-
- if (!hwif->dma_base)
- return;
+ hwif->set_pio_mode = &hpt34x_set_pio_mode;
+ hwif->set_dma_mode = &hpt34x_set_mode;
+}
+static const struct ide_port_info hpt34x_chipsets[] __devinitdata = {
+ { /* 0 */
+ .name = "HPT343",
+ .init_chipset = init_chipset_hpt34x,
+ .init_hwif = init_hwif_hpt34x,
+ .extra = 16,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA |
+ IDE_HFLAG_NO_AUTODMA,
+ .pio_mask = ATA_PIO5,
+ },
+ { /* 1 */
+ .name = "HPT345",
+ .init_chipset = init_chipset_hpt34x,
+ .init_hwif = init_hwif_hpt34x,
+ .extra = 16,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA |
+ IDE_HFLAG_NO_AUTODMA |
+ IDE_HFLAG_OFF_BOARD,
+ .pio_mask = ATA_PIO5,
#ifdef CONFIG_HPT34X_AUTODMA
- hwif->ultra_mask = 0x07;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
#endif
-
- hwif->ide_dma_check = &hpt34x_config_drive_xfer_rate;
- if (!noautodma)
- hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
-}
-
-static ide_pci_device_t hpt34x_chipset __devinitdata = {
- .name = "HPT34X",
- .init_chipset = init_chipset_hpt34x,
- .init_hwif = init_hwif_hpt34x,
- .autodma = NOAUTODMA,
- .bootable = NEVER_BOARD,
- .extra = 16,
- .pio_mask = ATA_PIO5,
+ }
};
static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_pci_device_t *d = &hpt34x_chipset;
- static char *chipset_names[] = {"HPT343", "HPT345"};
+ const struct ide_port_info *d;
u16 pcicmd = 0;
pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
- d->name = chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0];
- d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
+ d = &hpt34x_chipsets[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0];
return ide_setup_pci_device(dev, d);
}
-static struct pci_device_id hpt34x_pci_tbl[] = {
- { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static const struct pci_device_id hpt34x_pci_tbl[] = {
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT343), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, hpt34x_pci_tbl);
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index 39f1c89f7c8..5682895d36d 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -1,9 +1,10 @@
/*
- * linux/drivers/ide/pci/hpt366.c Version 1.12 Aug 19, 2007
+ * linux/drivers/ide/pci/hpt366.c Version 1.21 Oct 23, 2007
*
* 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) 2007 Bartlomiej Zolnierkiewicz
* Portions Copyright (C) 2005-2007 MontaVista Software, Inc.
*
* Thanks to HighPoint Technologies for their assistance, and hardware.
@@ -114,7 +115,7 @@
* unify HPT36x/37x timing setup code and the speedproc handlers by joining
* the register setting lists into the table indexed by the clock selected
* - set the correct hwif->ultra_mask for each individual chip
- * - add UltraDMA mode filtering for the HPT37[24] based SATA cards
+ * - add Ultra and MW DMA mode filtering for the HPT37[24] based SATA cards
* Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
*/
@@ -393,8 +394,9 @@ enum ata_clock {
*/
struct hpt_info {
+ char *chip_name; /* Chip name */
u8 chip_type; /* Chip type */
- u8 max_ultra; /* Max. UltraDMA mode allowed */
+ u8 udma_mask; /* Allowed UltraDMA modes mask. */
u8 dpll_clk; /* DPLL clock in MHz */
u8 pci_clk; /* PCI clock in MHz */
u32 **settings; /* Chipset settings table */
@@ -431,79 +433,90 @@ static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
sixty_six_base_hpt37x
};
-static struct hpt_info hpt36x __devinitdata = {
+static const struct hpt_info hpt36x __devinitdata = {
+ .chip_name = "HPT36x",
.chip_type = HPT36x,
- .max_ultra = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? 4 : 3) : 2,
+ .udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2,
.dpll_clk = 0, /* no DPLL */
.settings = hpt36x_settings
};
-static struct hpt_info hpt370 __devinitdata = {
+static const struct hpt_info hpt370 __devinitdata = {
+ .chip_name = "HPT370",
.chip_type = HPT370,
- .max_ultra = HPT370_ALLOW_ATA100_5 ? 5 : 4,
+ .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
.dpll_clk = 48,
.settings = hpt37x_settings
};
-static struct hpt_info hpt370a __devinitdata = {
+static const struct hpt_info hpt370a __devinitdata = {
+ .chip_name = "HPT370A",
.chip_type = HPT370A,
- .max_ultra = HPT370_ALLOW_ATA100_5 ? 5 : 4,
+ .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4,
.dpll_clk = 48,
.settings = hpt37x_settings
};
-static struct hpt_info hpt374 __devinitdata = {
+static const struct hpt_info hpt374 __devinitdata = {
+ .chip_name = "HPT374",
.chip_type = HPT374,
- .max_ultra = 5,
+ .udma_mask = ATA_UDMA5,
.dpll_clk = 48,
.settings = hpt37x_settings
};
-static struct hpt_info hpt372 __devinitdata = {
+static const struct hpt_info hpt372 __devinitdata = {
+ .chip_name = "HPT372",
.chip_type = HPT372,
- .max_ultra = HPT372_ALLOW_ATA133_6 ? 6 : 5,
+ .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
.dpll_clk = 55,
.settings = hpt37x_settings
};
-static struct hpt_info hpt372a __devinitdata = {
+static const struct hpt_info hpt372a __devinitdata = {
+ .chip_name = "HPT372A",
.chip_type = HPT372A,
- .max_ultra = HPT372_ALLOW_ATA133_6 ? 6 : 5,
+ .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
.dpll_clk = 66,
.settings = hpt37x_settings
};
-static struct hpt_info hpt302 __devinitdata = {
+static const struct hpt_info hpt302 __devinitdata = {
+ .chip_name = "HPT302",
.chip_type = HPT302,
- .max_ultra = HPT372_ALLOW_ATA133_6 ? 6 : 5,
+ .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
.dpll_clk = 66,
.settings = hpt37x_settings
};
-static struct hpt_info hpt371 __devinitdata = {
+static const struct hpt_info hpt371 __devinitdata = {
+ .chip_name = "HPT371",
.chip_type = HPT371,
- .max_ultra = HPT371_ALLOW_ATA133_6 ? 6 : 5,
+ .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
.dpll_clk = 66,
.settings = hpt37x_settings
};
-static struct hpt_info hpt372n __devinitdata = {
+static const struct hpt_info hpt372n __devinitdata = {
+ .chip_name = "HPT372N",
.chip_type = HPT372N,
- .max_ultra = HPT372_ALLOW_ATA133_6 ? 6 : 5,
+ .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
.dpll_clk = 77,
.settings = hpt37x_settings
};
-static struct hpt_info hpt302n __devinitdata = {
+static const struct hpt_info hpt302n __devinitdata = {
+ .chip_name = "HPT302N",
.chip_type = HPT302N,
- .max_ultra = HPT302_ALLOW_ATA133_6 ? 6 : 5,
+ .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
.dpll_clk = 77,
.settings = hpt37x_settings
};
-static struct hpt_info hpt371n __devinitdata = {
+static const struct hpt_info hpt371n __devinitdata = {
+ .chip_name = "HPT371N",
.chip_type = HPT371N,
- .max_ultra = HPT371_ALLOW_ATA133_6 ? 6 : 5,
+ .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
.dpll_clk = 77,
.settings = hpt37x_settings
};
@@ -562,6 +575,24 @@ static u8 hpt3xx_udma_filter(ide_drive_t *drive)
return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask;
}
+static u8 hpt3xx_mdma_filter(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ struct hpt_info *info = pci_get_drvdata(hwif->pci_dev);
+
+ switch (info->chip_type) {
+ case HPT372 :
+ case HPT372A:
+ case HPT372N:
+ case HPT374 :
+ if (ide_dev_is_sata(drive->id))
+ return 0x00;
+ /* Fall thru */
+ default:
+ return 0x07;
+ }
+}
+
static u32 get_speed_setting(u8 speed, struct hpt_info *info)
{
int i;
@@ -582,20 +613,15 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info)
return (*info->settings)[i];
}
-static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static void hpt36x_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
struct hpt_info *info = pci_get_drvdata(dev);
- u8 speed = ide_rate_filter(drive, xferspeed);
u8 itr_addr = drive->dn ? 0x44 : 0x40;
u32 old_itr = 0;
u32 itr_mask, new_itr;
- /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */
- if (drive->media != ide_disk)
- speed = min_t(u8, speed, XFER_PIO_4);
-
itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
(speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff);
@@ -610,24 +636,17 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
new_itr &= ~0xc0000000;
pci_write_config_dword(dev, itr_addr, new_itr);
-
- return ide_config_drive_speed(drive, speed);
}
-static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static void hpt37x_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
struct hpt_info *info = pci_get_drvdata(dev);
- u8 speed = ide_rate_filter(drive, xferspeed);
u8 itr_addr = 0x40 + (drive->dn * 4);
u32 old_itr = 0;
u32 itr_mask, new_itr;
- /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */
- if (drive->media != ide_disk)
- speed = min_t(u8, speed, XFER_PIO_4);
-
itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
(speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff);
@@ -639,25 +658,22 @@ static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
if (speed < XFER_MW_DMA_0)
new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
pci_write_config_dword(dev, itr_addr, new_itr);
-
- return ide_config_drive_speed(drive, speed);
}
-static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
+static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct hpt_info *info = pci_get_drvdata(hwif->pci_dev);
if (info->chip_type >= HPT370)
- return hpt37x_tune_chipset(drive, speed);
+ hpt37x_set_mode(drive, speed);
else /* hpt368: hpt_minimum_revision(dev, 2) */
- return hpt36x_tune_chipset(drive, speed);
+ hpt36x_set_mode(drive, speed);
}
-static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
+static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
+ hpt3xx_set_mode(drive, XFER_PIO_0 + pio);
}
static int hpt3xx_quirkproc(ide_drive_t *drive)
@@ -673,12 +689,11 @@ static int hpt3xx_quirkproc(ide_drive_t *drive)
static void hpt3xx_intrproc(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
-
if (drive->quirk_list)
return;
+
/* drives in the quirk_list may not like intr setups/cleanups */
- hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
+ outb(drive->ctl | 2, IDE_CONTROL_REG);
}
static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
@@ -706,21 +721,8 @@ static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
enable_irq (hwif->irq);
}
} else
- hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
- IDE_CONTROL_REG);
-}
-
-static int hpt366_config_drive_xfer_rate(ide_drive_t *drive)
-{
- drive->init_speed = 0;
-
- if (ide_tune_dma(drive))
- return 0;
-
- if (ide_use_fast_pio(drive))
- hpt3xx_tune_drive(drive, 255);
-
- return -1;
+ outb(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
+ IDE_CONTROL_REG);
}
/*
@@ -760,9 +762,9 @@ static void hpt370_irq_timeout(ide_drive_t *drive)
printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
/* get DMA command mode */
- dma_cmd = hwif->INB(hwif->dma_command);
+ dma_cmd = inb(hwif->dma_command);
/* stop DMA */
- hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
+ outb(dma_cmd & ~0x1, hwif->dma_command);
hpt370_clear_engine(drive);
}
@@ -777,12 +779,12 @@ static void hpt370_ide_dma_start(ide_drive_t *drive)
static int hpt370_ide_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
- u8 dma_stat = hwif->INB(hwif->dma_status);
+ u8 dma_stat = inb(hwif->dma_status);
if (dma_stat & 0x01) {
/* wait a little */
udelay(20);
- dma_stat = hwif->INB(hwif->dma_status);
+ dma_stat = inb(hwif->dma_status);
if (dma_stat & 0x01)
hpt370_irq_timeout(drive);
}
@@ -843,34 +845,32 @@ static int hpt374_ide_dma_end(ide_drive_t *drive)
static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
{
- u8 scr2 = hwif->INB(hwif->dma_master + 0x7b);
+ u8 scr2 = inb(hwif->dma_master + 0x7b);
if ((scr2 & 0x7f) == mode)
return;
/* Tristate the bus */
- hwif->OUTB(0x80, hwif->dma_master + 0x73);
- hwif->OUTB(0x80, hwif->dma_master + 0x77);
+ outb(0x80, hwif->dma_master + 0x73);
+ outb(0x80, hwif->dma_master + 0x77);
/* Switch clock and reset channels */
- hwif->OUTB(mode, hwif->dma_master + 0x7b);
- hwif->OUTB(0xc0, hwif->dma_master + 0x79);
+ outb(mode, hwif->dma_master + 0x7b);
+ outb(0xc0, hwif->dma_master + 0x79);
/*
* Reset the state machines.
* NOTE: avoid accidentally enabling the disabled channels.
*/
- hwif->OUTB(hwif->INB(hwif->dma_master + 0x70) | 0x32,
- hwif->dma_master + 0x70);
- hwif->OUTB(hwif->INB(hwif->dma_master + 0x74) | 0x32,
- hwif->dma_master + 0x74);
+ outb(inb(hwif->dma_master + 0x70) | 0x32, hwif->dma_master + 0x70);
+ outb(inb(hwif->dma_master + 0x74) | 0x32, hwif->dma_master + 0x74);
/* Complete reset */
- hwif->OUTB(0x00, hwif->dma_master + 0x79);
+ outb(0x00, hwif->dma_master + 0x79);
/* Reconnect channels to bus */
- hwif->OUTB(0x00, hwif->dma_master + 0x73);
- hwif->OUTB(0x00, hwif->dma_master + 0x77);
+ outb(0x00, hwif->dma_master + 0x73);
+ outb(0x00, hwif->dma_master + 0x77);
}
/**
@@ -1149,7 +1149,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
* Select 66 MHz DPLL clock only if UltraATA/133 mode is
* supported/enabled, use 50 MHz DPLL clock otherwise...
*/
- if (info->max_ultra == 6) {
+ if (info->udma_mask == ATA_UDMA6) {
dpll_clk = 66;
clock = ATA_CLOCK_66MHZ;
} else if (dpll_clk) { /* HPT36x chips don't have DPLL */
@@ -1249,14 +1249,15 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
/* Cache the channel's MISC. control registers' offset */
hwif->select_data = hwif->channel ? 0x54 : 0x50;
- hwif->tuneproc = &hpt3xx_tune_drive;
- hwif->speedproc = &hpt3xx_tune_chipset;
+ hwif->set_pio_mode = &hpt3xx_set_pio_mode;
+ hwif->set_dma_mode = &hpt3xx_set_mode;
hwif->quirkproc = &hpt3xx_quirkproc;
hwif->intrproc = &hpt3xx_intrproc;
hwif->maskproc = &hpt3xx_maskproc;
hwif->busproc = &hpt3xx_busproc;
hwif->udma_filter = &hpt3xx_udma_filter;
+ hwif->mdma_filter = &hpt3xx_mdma_filter;
/*
* HPT3xxN chips have some complications:
@@ -1300,13 +1301,8 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
if (new_mcr != old_mcr)
pci_write_config_byte(dev, hwif->select_data + 1, new_mcr);
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+ if (hwif->dma_base == 0)
return;
- }
-
- hwif->ultra_mask = hwif->cds->udma_mask;
- hwif->mwdma_mask = 0x07;
/*
* The HPT37x uses the CBLID pins as outputs for MA15/MA16
@@ -1345,8 +1341,6 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
hwif->cbl = (scr1 & ata66) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
- hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
-
if (chip_type >= HPT374) {
hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
hwif->ide_dma_end = &hpt374_ide_dma_end;
@@ -1356,10 +1350,6 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
hwif->dma_timeout = &hpt370_dma_timeout;
} else
hwif->dma_lost_irq = &hpt366_dma_lost_irq;
-
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
}
static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
@@ -1369,7 +1359,7 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
u8 dma_new = 0, dma_old = 0;
unsigned long flags;
- dma_old = hwif->INB(dmabase + 2);
+ dma_old = inb(dmabase + 2);
local_irq_save(flags);
@@ -1380,60 +1370,26 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
if (masterdma & 0x30) dma_new |= 0x20;
if ( slavedma & 0x30) dma_new |= 0x40;
if (dma_new != dma_old)
- hwif->OUTB(dma_new, dmabase + 2);
+ outb(dma_new, dmabase + 2);
local_irq_restore(flags);
ide_setup_dma(hwif, dmabase, 8);
}
-static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
+static void __devinit hpt374_init(struct pci_dev *dev, struct pci_dev *dev2)
{
- struct pci_dev *dev2;
-
- if (PCI_FUNC(dev->devfn) & 1)
- return -ENODEV;
-
- pci_set_drvdata(dev, &hpt374);
-
- if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
- int ret;
-
- pci_set_drvdata(dev2, &hpt374);
-
- if (dev2->irq != dev->irq) {
- /* FIXME: we need a core pci_set_interrupt() */
- dev2->irq = dev->irq;
- printk(KERN_WARNING "%s: PCI config space interrupt "
- "fixed.\n", d->name);
- }
- ret = ide_setup_pci_devices(dev, dev2, d);
- if (ret < 0)
- pci_dev_put(dev2);
- return ret;
+ if (dev2->irq != dev->irq) {
+ /* FIXME: we need a core pci_set_interrupt() */
+ dev2->irq = dev->irq;
+ printk(KERN_INFO "HPT374: PCI config space interrupt fixed\n");
}
- return ide_setup_pci_device(dev, d);
-}
-
-static int __devinit init_setup_hpt372n(struct pci_dev *dev, ide_pci_device_t *d)
-{
- pci_set_drvdata(dev, &hpt372n);
-
- return ide_setup_pci_device(dev, d);
}
-static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
+static void __devinit hpt371_init(struct pci_dev *dev)
{
- struct hpt_info *info;
u8 mcr1 = 0;
- if (dev->revision > 1) {
- d->name = "HPT371N";
-
- info = &hpt371n;
- } else
- info = &hpt371;
-
/*
* HPT371 chips physically have only one channel, the secondary one,
* but the primary channel registers do exist! Go figure...
@@ -1443,194 +1399,102 @@ static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
pci_read_config_byte(dev, 0x50, &mcr1);
if (mcr1 & 0x04)
pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
-
- pci_set_drvdata(dev, info);
-
- return ide_setup_pci_device(dev, d);
}
-static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2)
{
- struct hpt_info *info;
-
- if (dev->revision > 1) {
- d->name = "HPT372N";
+ u8 mcr1 = 0, pin1 = 0, pin2 = 0;
- info = &hpt372n;
- } else
- info = &hpt372a;
- pci_set_drvdata(dev, info);
-
- return ide_setup_pci_device(dev, d);
-}
-
-static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d)
-{
- struct hpt_info *info;
+ /*
+ * Now we'll have to force both channels enabled if
+ * at least one of them has been enabled by BIOS...
+ */
+ pci_read_config_byte(dev, 0x50, &mcr1);
+ if (mcr1 & 0x30)
+ pci_write_config_byte(dev, 0x50, mcr1 | 0x30);
- if (dev->revision > 1) {
- d->name = "HPT302N";
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
+ pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
- info = &hpt302n;
- } else
- info = &hpt302;
- pci_set_drvdata(dev, info);
+ if (pin1 != pin2 && dev->irq == dev2->irq) {
+ printk(KERN_INFO "HPT36x: onboard version of chipset, "
+ "pin1=%d pin2=%d\n", pin1, pin2);
+ return 1;
+ }
- return ide_setup_pci_device(dev, d);
+ return 0;
}
-static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
-{
- struct pci_dev *dev2;
- u8 rev = dev->revision;
- static char *chipset_names[] = { "HPT366", "HPT366", "HPT368",
- "HPT370", "HPT370A", "HPT372",
- "HPT372N" };
- static struct hpt_info *info[] = { &hpt36x, &hpt36x, &hpt36x,
- &hpt370, &hpt370a, &hpt372,
- &hpt372n };
-
- if (PCI_FUNC(dev->devfn) & 1)
- return -ENODEV;
-
- switch (rev) {
- case 0:
- case 1:
- case 2:
+static const struct ide_port_info hpt366_chipsets[] __devinitdata = {
+ { /* 0 */
+ .name = "HPT36x",
+ .init_chipset = init_chipset_hpt366,
+ .init_hwif = init_hwif_hpt366,
+ .init_dma = init_dma_hpt366,
/*
* HPT36x chips have one channel per function and have
* both channel enable bits located differently and visible
* to both functions -- really stupid design decision... :-(
* Bit 4 is for the primary channel, bit 5 for the secondary.
*/
- d->host_flags |= IDE_HFLAG_SINGLE;
- d->enablebits[0].mask = d->enablebits[0].val = 0x10;
-
- d->udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ?
- ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2;
- break;
- case 3:
- case 4:
- d->udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4;
- break;
- default:
- rev = 6;
- /* fall thru */
- case 5:
- case 6:
- d->udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5;
- break;
- }
-
- d->name = chipset_names[rev];
-
- pci_set_drvdata(dev, info[rev]);
-
- if (rev > 2)
- goto init_single;
-
- if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
- u8 mcr1 = 0, pin1 = 0, pin2 = 0;
- int ret;
-
- pci_set_drvdata(dev2, info[rev]);
-
- /*
- * Now we'll have to force both channels enabled if
- * at least one of them has been enabled by BIOS...
- */
- pci_read_config_byte(dev, 0x50, &mcr1);
- if (mcr1 & 0x30)
- pci_write_config_byte(dev, 0x50, mcr1 | 0x30);
-
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
- pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
- if (pin1 != pin2 && dev->irq == dev2->irq) {
- d->bootable = ON_BOARD;
- printk("%s: onboard version of chipset, pin1=%d pin2=%d\n",
- d->name, pin1, pin2);
- }
- ret = ide_setup_pci_devices(dev, dev2, d);
- if (ret < 0)
- pci_dev_put(dev2);
- return ret;
- }
-init_single:
- return ide_setup_pci_device(dev, d);
-}
-
-static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
- { /* 0 */
- .name = "HPT366",
- .init_setup = init_setup_hpt366,
- .init_chipset = init_chipset_hpt366,
- .init_hwif = init_hwif_hpt366,
- .init_dma = init_dma_hpt366,
- .autodma = AUTODMA,
- .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .bootable = OFF_BOARD,
+ .enablebits = {{0x50,0x10,0x10}, {0x54,0x04,0x04}},
.extra = 240,
+ .host_flags = IDE_HFLAG_SINGLE |
+ IDE_HFLAG_NO_ATAPI_DMA |
+ IDE_HFLAG_OFF_BOARD,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
},{ /* 1 */
.name = "HPT372A",
- .init_setup = init_setup_hpt372a,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- .bootable = OFF_BOARD,
.extra = 240,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
},{ /* 2 */
.name = "HPT302",
- .init_setup = init_setup_hpt302,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- .bootable = OFF_BOARD,
.extra = 240,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
},{ /* 3 */
.name = "HPT371",
- .init_setup = init_setup_hpt371,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- .bootable = OFF_BOARD,
.extra = 240,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
},{ /* 4 */
.name = "HPT374",
- .init_setup = init_setup_hpt374,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.udma_mask = ATA_UDMA5,
- .bootable = OFF_BOARD,
.extra = 240,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
},{ /* 5 */
.name = "HPT372N",
- .init_setup = init_setup_hpt372n,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
- .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
- .bootable = OFF_BOARD,
.extra = 240,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
}
};
@@ -1641,25 +1505,86 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
*
* Called when the PCI registration layer (or the IDE initialization)
* finds a device matching our IDE device tables.
- *
- * NOTE: since we'll have to modify some fields of the ide_pci_device_t
- * structure depending on the chip's revision, we'd better pass a local
- * copy down the call chain...
*/
static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_pci_device_t d = hpt366_chipsets[id->driver_data];
+ const struct hpt_info *info = NULL;
+ struct pci_dev *dev2 = NULL;
+ struct ide_port_info d;
+ u8 idx = id->driver_data;
+ u8 rev = dev->revision;
+
+ if ((idx == 0 || idx == 4) && (PCI_FUNC(dev->devfn) & 1))
+ return -ENODEV;
+
+ switch (idx) {
+ case 0:
+ if (rev < 3)
+ info = &hpt36x;
+ else {
+ static const struct hpt_info *hpt37x_info[] =
+ { &hpt370, &hpt370a, &hpt372, &hpt372n };
+
+ info = hpt37x_info[min_t(u8, rev, 6) - 3];
+ idx++;
+ }
+ break;
+ case 1:
+ info = (rev > 1) ? &hpt372n : &hpt372a;
+ break;
+ case 2:
+ info = (rev > 1) ? &hpt302n : &hpt302;
+ break;
+ case 3:
+ hpt371_init(dev);
+ info = (rev > 1) ? &hpt371n : &hpt371;
+ break;
+ case 4:
+ info = &hpt374;
+ break;
+ case 5:
+ info = &hpt372n;
+ break;
+ }
+
+ d = hpt366_chipsets[idx];
+
+ d.name = info->chip_name;
+ d.udma_mask = info->udma_mask;
+
+ pci_set_drvdata(dev, (void *)info);
+
+ if (info == &hpt36x || info == &hpt374)
+ dev2 = pci_get_slot(dev->bus, dev->devfn + 1);
+
+ if (dev2) {
+ int ret;
+
+ pci_set_drvdata(dev2, (void *)info);
+
+ if (info == &hpt374)
+ hpt374_init(dev, dev2);
+ else {
+ if (hpt36x_init(dev, dev2))
+ d.host_flags |= IDE_HFLAG_BOOTABLE;
+ }
+
+ ret = ide_setup_pci_devices(dev, dev2, &d);
+ if (ret < 0)
+ pci_dev_put(dev2);
+ return ret;
+ }
- return d.init_setup(dev, &d);
+ return ide_setup_pci_device(dev, &d);
}
-static struct pci_device_id hpt366_pci_tbl[] = {
- { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
- { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
- { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
- { PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+static const struct pci_device_id hpt366_pci_tbl[] = {
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), 0 },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), 1 },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), 2 },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), 3 },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT374), 4 },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), 5 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl);
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
index 70b3245dbf6..90b52ed37bf 100644
--- a/drivers/ide/pci/it8213.c
+++ b/drivers/ide/pci/it8213.c
@@ -18,45 +18,14 @@
#include <asm/io.h>
/**
- * it8213_dma_2_pio - return the PIO mode matching DMA
- * @xfer_rate: transfer speed
- *
- * Returns the nearest equivalent PIO timing for the DMA
- * mode requested by the controller.
- */
-
-static u8 it8213_dma_2_pio (u8 xfer_rate) {
- switch(xfer_rate) {
- case XFER_UDMA_6:
- case XFER_UDMA_5:
- case XFER_UDMA_4:
- case XFER_UDMA_3:
- case XFER_UDMA_2:
- case XFER_UDMA_1:
- case XFER_UDMA_0:
- case XFER_MW_DMA_2:
- return 4;
- case XFER_MW_DMA_1:
- return 3;
- case XFER_SW_DMA_2:
- return 2;
- case XFER_MW_DMA_0:
- case XFER_SW_DMA_1:
- case XFER_SW_DMA_0:
- default:
- return 0;
- }
-}
-
-/*
- * it8213_tune_pio - tune a drive
- * @drive: drive to tune
- * @pio: desired PIO mode
+ * it8213_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
* Set the interface PIO mode.
*/
-static void it8213_tune_pio(ide_drive_t *drive, const u8 pio)
+static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -105,30 +74,19 @@ static void it8213_tune_pio(ide_drive_t *drive, const u8 pio)
spin_unlock_irqrestore(&tune_lock, flags);
}
-static void it8213_tuneproc(ide_drive_t *drive, u8 pio)
-{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- it8213_tune_pio(drive, pio);
- ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
/**
- * it8213_tune_chipset - set controller timings
- * @drive: Drive to set up
- * @xferspeed: speed we want to achieve
+ * it8213_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
- * Tune the ITE chipset for the desired mode. If we can't achieve
- * the desired mode then tune for a lower one, but ultimately
- * make the thing work.
+ * Tune the ITE chipset for the DMA mode.
*/
-static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
-
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u8 maslave = 0x40;
- u8 speed = ide_rate_filter(drive, xferspeed);
int a_speed = 3 << (drive->dn * 4);
int u_flag = 1 << drive->dn;
int v_flag = 0x01 << drive->dn;
@@ -156,14 +114,8 @@ static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_MW_DMA_1:
case XFER_SW_DMA_2:
break;
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- break;
default:
- return -1;
+ return;
}
if (speed >= XFER_UDMA_0) {
@@ -183,6 +135,9 @@ static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
} else
pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
} else {
+ const u8 mwdma_to_pio[] = { 0, 3, 4 };
+ u8 pio;
+
if (reg48 & u_flag)
pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
if (reg4a & a_speed)
@@ -191,81 +146,37 @@ static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
if (reg55 & w_flag)
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
- }
-
- if (speed > XFER_PIO_4)
- it8213_tune_pio(drive, it8213_dma_2_pio(speed));
- else
- it8213_tune_pio(drive, speed - XFER_PIO_0);
-
- return ide_config_drive_speed(drive, speed);
-}
-/**
- * it8213_configure_drive_for_dma - set up for DMA transfers
- * @drive: drive we are going to set up
- *
- * Set up the drive for DMA, tune the controller and drive as
- * required. If the drive isn't suitable for DMA or we hit
- * other problems then we will drop down to PIO and set up
- * PIO appropriately
- */
-
-static int it8213_config_drive_for_dma (ide_drive_t *drive)
-{
- if (ide_tune_dma(drive))
- return 0;
+ if (speed >= XFER_MW_DMA_0)
+ pio = mwdma_to_pio[speed - XFER_MW_DMA_0];
+ else
+ pio = 2; /* only SWDMA2 is allowed */
- it8213_tuneproc(drive, 255);
-
- return -1;
+ it8213_set_pio_mode(drive, pio);
+ }
}
/**
* init_hwif_it8213 - set up hwif structs
* @hwif: interface to set up
*
- * We do the basic set up of the interface structure. The IT8212
- * requires several custom handlers so we override the default
- * ide DMA handlers appropriately
+ * We do the basic set up of the interface structure.
*/
static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
{
u8 reg42h = 0;
- hwif->speedproc = &it8213_tune_chipset;
- hwif->tuneproc = &it8213_tuneproc;
-
- hwif->autodma = 0;
-
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ hwif->set_dma_mode = &it8213_set_dma_mode;
+ hwif->set_pio_mode = &it8213_set_pio_mode;
if (!hwif->dma_base)
return;
- hwif->atapi_dma = 1;
- hwif->ultra_mask = 0x7f;
- hwif->mwdma_mask = 0x06;
- hwif->swdma_mask = 0x04;
-
pci_read_config_byte(hwif->pci_dev, 0x42, &reg42h);
- hwif->ide_dma_check = &it8213_config_drive_for_dma;
-
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
hwif->cbl = (reg42h & 0x02) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-
- /*
- * The BIOS often doesn't set up DMA on this controller
- * so we always do it.
- */
- if (!noautodma)
- hwif->autodma = 1;
-
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
}
@@ -273,14 +184,16 @@ static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
{ \
.name = name_str, \
.init_hwif = init_hwif_it8213, \
- .autodma = AUTODMA, \
.enablebits = {{0x41,0x80,0x80}}, \
- .bootable = ON_BOARD, \
- .host_flags = IDE_HFLAG_SINGLE, \
+ .host_flags = IDE_HFLAG_SINGLE | \
+ IDE_HFLAG_BOOTABLE, \
.pio_mask = ATA_PIO4, \
+ .swdma_mask = ATA_SWDMA2_ONLY, \
+ .mwdma_mask = ATA_MWDMA12_ONLY, \
+ .udma_mask = ATA_UDMA6, \
}
-static ide_pci_device_t it8213_chipsets[] __devinitdata = {
+static const struct ide_port_info it8213_chipsets[] __devinitdata = {
/* 0 */ DECLARE_ITE_DEV("IT8213"),
};
@@ -301,9 +214,8 @@ static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_devic
return 0;
}
-
-static struct pci_device_id it8213_pci_tbl[] = {
- { PCI_VENDOR_ID_ITE, 0x8213, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+static const struct pci_device_id it8213_pci_tbl[] = {
+ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8213), 0 },
{ 0, },
};
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 9286c99e2ff..99b7d763b6c 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -95,7 +95,7 @@ struct it821x_dev
/*
* We allow users to force the card into non raid mode without
- * flashing the alternative BIOS. This is also neccessary right now
+ * flashing the alternative BIOS. This is also necessary right now
* for embedded platforms that cannot run a PC BIOS but are using this
* device.
*/
@@ -229,24 +229,24 @@ static void it821x_clock_strategy(ide_drive_t *drive)
}
/**
- * it821x_tunepio - tune a drive
- * @drive: drive to tune
- * @pio: the desired PIO mode
+ * it821x_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
- * Try to tune the drive/host to the desired PIO mode taking into
- * the consideration the maximum PIO mode supported by the other
- * device on the cable.
+ * Tune the host to the desired PIO mode taking into the consideration
+ * the maximum PIO mode supported by the other device on the cable.
*/
-static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
+static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = drive->hwif;
struct it821x_dev *itdev = ide_get_hwifdata(hwif);
int unit = drive->select.b.unit;
ide_drive_t *pair = &hwif->drives[1 - unit];
+ u8 set_pio = pio;
/* Spec says 89 ref driver uses 88 */
- static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
+ static u16 pio_timings[]= { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
/*
@@ -261,23 +261,12 @@ static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
set_pio = pair_pio;
}
- if (itdev->smart)
- return 0;
-
/* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
itdev->want[unit][1] = pio_want[set_pio];
itdev->want[unit][0] = 1; /* PIO is lowest priority */
- itdev->pio[unit] = pio[set_pio];
+ itdev->pio[unit] = pio_timings[set_pio];
it821x_clock_strategy(drive);
it821x_program(drive, itdev->pio[unit]);
-
- return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio);
-}
-
-static void it821x_tuneproc(ide_drive_t *drive, u8 pio)
-{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- (void)it821x_tunepio(drive, pio);
}
/**
@@ -405,81 +394,25 @@ static int it821x_dma_end(ide_drive_t *drive)
return ret;
}
-
-/**
- * it821x_tune_chipset - set controller timings
- * @drive: Drive to set up
- * @xferspeed: speed we want to achieve
- *
- * Tune the ITE chipset for the desired mode. If we can't achieve
- * the desired mode then tune for a lower one, but ultimately
- * make the thing work.
- */
-
-static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
-{
-
- ide_hwif_t *hwif = drive->hwif;
- struct it821x_dev *itdev = ide_get_hwifdata(hwif);
- u8 speed = ide_rate_filter(drive, xferspeed);
-
- switch (speed) {
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- return it821x_tunepio(drive, speed - XFER_PIO_0);
- }
-
- if (itdev->smart == 0) {
- switch (speed) {
- /* MWDMA tuning is really hard because our MWDMA and PIO
- timings are kept in the same place. We can switch in the
- host dma on/off callbacks */
- case XFER_MW_DMA_2:
- case XFER_MW_DMA_1:
- case XFER_MW_DMA_0:
- it821x_tune_mwdma(drive, (speed - XFER_MW_DMA_0));
- break;
- case XFER_UDMA_6:
- case XFER_UDMA_5:
- case XFER_UDMA_4:
- case XFER_UDMA_3:
- case XFER_UDMA_2:
- case XFER_UDMA_1:
- case XFER_UDMA_0:
- it821x_tune_udma(drive, (speed - XFER_UDMA_0));
- break;
- default:
- return 1;
- }
-
- return ide_config_drive_speed(drive, speed);
- }
-
- /* don't touch anything in the smart mode */
- return 0;
-}
-
/**
- * it821x_configure_drive_for_dma - set up for DMA transfers
- * @drive: drive we are going to set up
+ * it821x_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
- * Set up the drive for DMA, tune the controller and drive as
- * required. If the drive isn't suitable for DMA or we hit
- * other problems then we will drop down to PIO and set up
- * PIO appropriately
+ * Tune the ITE chipset for the desired DMA mode.
*/
-static int it821x_config_drive_for_dma (ide_drive_t *drive)
+static void it821x_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
- if (ide_tune_dma(drive))
- return 0;
-
- it821x_tuneproc(drive, 255);
-
- return -1;
+ /*
+ * MWDMA tuning is really hard because our MWDMA and PIO
+ * timings are kept in the same place. We can switch in the
+ * host dma on/off callbacks.
+ */
+ if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_6)
+ it821x_tune_udma(drive, speed - XFER_UDMA_0);
+ else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+ it821x_tune_mwdma(drive, speed - XFER_MW_DMA_0);
}
/**
@@ -604,18 +537,17 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
struct it821x_dev *idev = kzalloc(sizeof(struct it821x_dev), GFP_KERNEL);
u8 conf;
- if(idev == NULL) {
+ if (idev == NULL) {
printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n");
- goto fallback;
+ return;
}
- ide_set_hwifdata(hwif, idev);
- hwif->atapi_dma = 1;
+ ide_set_hwifdata(hwif, idev);
pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
- if(conf & 1) {
+ if (conf & 1) {
idev->smart = 1;
- hwif->atapi_dma = 0;
+ hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
/* Long I/O's although allowed in LBA48 space cause the
onboard firmware to enter the twighlight zone */
hwif->rqsize = 256;
@@ -632,52 +564,35 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
/*
* Not in the docs but according to the reference driver
- * this is neccessary.
+ * this is necessary.
*/
pci_read_config_byte(hwif->pci_dev, 0x08, &conf);
- if(conf == 0x10) {
+ if (conf == 0x10) {
idev->timing10 = 1;
- hwif->atapi_dma = 0;
- if(!idev->smart)
+ hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
+ if (idev->smart == 0)
printk(KERN_WARNING "it821x: Revision 0x10, workarounds activated.\n");
}
- hwif->speedproc = &it821x_tune_chipset;
- hwif->tuneproc = &it821x_tuneproc;
+ if (idev->smart == 0) {
+ hwif->set_pio_mode = &it821x_set_pio_mode;
+ hwif->set_dma_mode = &it821x_set_dma_mode;
- /* MWDMA/PIO clock switching for pass through mode */
- if(!idev->smart) {
+ /* MWDMA/PIO clock switching for pass through mode */
hwif->dma_start = &it821x_dma_start;
hwif->ide_dma_end = &it821x_dma_end;
- }
-
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ } else
+ hwif->host_flags |= IDE_HFLAG_NO_SET_MODE;
- if (!hwif->dma_base)
- goto fallback;
-
- hwif->ultra_mask = 0x7f;
- hwif->mwdma_mask = 0x07;
+ if (hwif->dma_base == 0)
+ return;
- hwif->ide_dma_check = &it821x_config_drive_for_dma;
+ hwif->ultra_mask = ATA_UDMA6;
+ hwif->mwdma_mask = ATA_MWDMA2;
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
hwif->cbl = ata66_it821x(hwif);
-
- /*
- * The BIOS often doesn't set up DMA on this controller
- * so we always do it.
- */
-
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
- return;
-fallback:
- hwif->autodma = 0;
- return;
}
static void __devinit it8212_disable_raid(struct pci_dev *dev)
@@ -718,13 +633,12 @@ static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const cha
.name = name_str, \
.init_chipset = init_chipset_it821x, \
.init_hwif = init_hwif_it821x, \
- .autodma = AUTODMA, \
- .bootable = ON_BOARD, \
.fixup = it821x_fixups, \
+ .host_flags = IDE_HFLAG_BOOTABLE, \
.pio_mask = ATA_PIO4, \
}
-static ide_pci_device_t it821x_chipsets[] __devinitdata = {
+static const struct ide_port_info it821x_chipsets[] __devinitdata = {
/* 0 */ DECLARE_ITE_DEV("IT8212"),
};
@@ -739,13 +653,12 @@ static ide_pci_device_t it821x_chipsets[] __devinitdata = {
static int __devinit it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_setup_pci_device(dev, &it821x_chipsets[id->driver_data]);
- return 0;
+ return ide_setup_pci_device(dev, &it821x_chipsets[id->driver_data]);
}
-static struct pci_device_id it821x_pci_tbl[] = {
- { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static const struct pci_device_id it821x_pci_tbl[] = {
+ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), 0 },
+ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), 0 },
{ 0, },
};
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
index 65a0ff352b9..0083eaf89c7 100644
--- a/drivers/ide/pci/jmicron.c
+++ b/drivers/ide/pci/jmicron.c
@@ -83,45 +83,20 @@ static u8 __devinit ata66_jmicron(ide_hwif_t *hwif)
return ATA_CBL_PATA80;
}
-static void jmicron_tuneproc(ide_drive_t *drive, u8 pio)
+static void jmicron_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 5);
- ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
/**
- * jmicron_tune_chipset - set controller timings
- * @drive: Drive to set up
- * @xferspeed: speed we want to achieve
+ * jmicron_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @mode: DMA mode
*
- * As the JMicron snoops for timings all we actually need to do is
- * make sure we don't set an invalid mode. We do need to honour
- * the cable detect here.
+ * As the JMicron snoops for timings we don't need to do anything here.
*/
-static int jmicron_tune_chipset (ide_drive_t *drive, byte xferspeed)
+static void jmicron_set_dma_mode(ide_drive_t *drive, const u8 mode)
{
- u8 speed = ide_rate_filter(drive, xferspeed);
-
- return ide_config_drive_speed(drive, speed);
-}
-
-/**
- * jmicron_configure_drive_for_dma - set up for DMA transfers
- * @drive: drive we are going to set up
- *
- * As the JMicron snoops for timings all we actually need to do is
- * make sure we don't set an invalid mode.
- */
-
-static int jmicron_config_drive_for_dma (ide_drive_t *drive)
-{
- if (ide_tune_dma(drive))
- return 0;
-
- jmicron_tuneproc(drive, 255);
-
- return -1;
}
/**
@@ -133,49 +108,24 @@ static int jmicron_config_drive_for_dma (ide_drive_t *drive)
static void __devinit init_hwif_jmicron(ide_hwif_t *hwif)
{
- hwif->speedproc = &jmicron_tune_chipset;
- hwif->tuneproc = &jmicron_tuneproc;
+ hwif->set_pio_mode = &jmicron_set_pio_mode;
+ hwif->set_dma_mode = &jmicron_set_dma_mode;
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
-
- if (!hwif->dma_base)
- goto fallback;
-
- hwif->atapi_dma = 1;
- hwif->ultra_mask = 0x7f;
- hwif->mwdma_mask = 0x07;
-
- hwif->ide_dma_check = &jmicron_config_drive_for_dma;
+ if (hwif->dma_base == 0)
+ return;
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
hwif->cbl = ata66_jmicron(hwif);
-
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
- return;
-fallback:
- hwif->autodma = 0;
- return;
}
-#define DECLARE_JMB_DEV(name_str) \
- { \
- .name = name_str, \
- .init_hwif = init_hwif_jmicron, \
- .autodma = AUTODMA, \
- .bootable = ON_BOARD, \
- .enablebits = { {0x40, 1, 1}, {0x40, 0x10, 0x10} }, \
- .pio_mask = ATA_PIO5, \
- }
-
-static ide_pci_device_t jmicron_chipsets[] __devinitdata = {
- /* 0 */ DECLARE_JMB_DEV("JMB361"),
- /* 1 */ DECLARE_JMB_DEV("JMB363"),
- /* 2 */ DECLARE_JMB_DEV("JMB365"),
- /* 3 */ DECLARE_JMB_DEV("JMB366"),
- /* 4 */ DECLARE_JMB_DEV("JMB368"),
+static const struct ide_port_info jmicron_chipset __devinitdata = {
+ .name = "JMB",
+ .init_hwif = init_hwif_jmicron,
+ .host_flags = IDE_HFLAG_BOOTABLE,
+ .enablebits = { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } },
+ .pio_mask = ATA_PIO5,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
};
/**
@@ -189,35 +139,28 @@ static ide_pci_device_t jmicron_chipsets[] __devinitdata = {
static int __devinit jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_setup_pci_device(dev, &jmicron_chipsets[id->driver_data]);
- return 0;
+ return ide_setup_pci_device(dev, &jmicron_chipset);
}
-/* If libata is configured, jmicron PCI quirk will configure it such
- * that the SATA ports are in AHCI function while the PATA ports are
- * in a separate IDE function. In such cases, match device class and
- * attach only to IDE. If libata isn't configured, keep the old
- * behavior for backward compatibility.
+/* All JMB PATA controllers have and will continue to have the same
+ * interface. Matching vendor and device class is enough for all
+ * current and future controllers if the controller is programmed
+ * properly.
+ *
+ * If libata is configured, jmicron PCI quirk programs the controller
+ * into the correct mode. If libata isn't configured, match known
+ * device IDs too to maintain backward compatibility.
*/
-#if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
-#define JMB_CLASS PCI_CLASS_STORAGE_IDE << 8
-#define JMB_CLASS_MASK 0xffff00
-#else
-#define JMB_CLASS 0
-#define JMB_CLASS_MASK 0
-#endif
-
static struct pci_device_id jmicron_pci_tbl[] = {
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361,
- PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 0},
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363,
- PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 1},
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365,
- PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 2},
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366,
- PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 3},
- { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368,
- PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 4},
+#if !defined(CONFIG_ATA) && !defined(CONFIG_ATA_MODULE)
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366) },
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368) },
+#endif
+ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
{ 0, },
};
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
index 465c935fdf2..d4df4642dbb 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/pci/ns87415.c
@@ -197,7 +197,6 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
u8 stat;
#endif
- hwif->autodma = 0;
hwif->selectproc = &ns87415_selectproc;
/*
@@ -259,21 +258,17 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
outb(0x60, hwif->dma_status);
hwif->dma_setup = &ns87415_ide_dma_setup;
hwif->ide_dma_end = &ns87415_ide_dma_end;
-
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
}
-static ide_pci_device_t ns87415_chipset __devinitdata = {
+static const struct ide_port_info ns87415_chipset __devinitdata = {
.name = "NS87415",
#ifdef CONFIG_SUPERIO
.init_iops = init_iops_ns87415,
#endif
.init_hwif = init_hwif_ns87415,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+ IDE_HFLAG_NO_ATAPI_DMA |
+ IDE_HFLAG_BOOTABLE,
};
static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -281,8 +276,8 @@ static int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_devi
return ide_setup_pci_device(dev, &ns87415_chipset);
}
-static struct pci_device_id ns87415_pci_tbl[] = {
- { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static const struct pci_device_id ns87415_pci_tbl[] = {
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl);
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
index 3a2bb272351..8953d9c3926 100644
--- a/drivers/ide/pci/opti621.c
+++ b/drivers/ide/pci/opti621.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/opti621.c Version 0.7 Sept 10, 2002
+ * linux/drivers/ide/pci/opti621.c Version 0.9 Sep 24, 2007
*
* Copyright (C) 1996-1998 Linus Torvalds & authors (see below)
*/
@@ -47,7 +47,7 @@
* The main problem with OPTi is that some timings for master
* and slave must be the same. For example, if you have master
* PIO 3 and slave PIO 0, driver have to set some timings of
- * master for PIO 0. Second problem is that opti621_tune_drive
+ * master for PIO 0. Second problem is that opti621_set_pio_mode
* got only one drive to set, but have to set both drives.
* This is solved in compute_pios. If you don't set
* the second drive, compute_pios use ide_get_best_pio_mode
@@ -57,9 +57,6 @@
* There is a 25/33MHz switch in configuration
* register, but driver is written for use at any frequency which get
* (use idebus=xx to select PCI bus speed).
- * Use hda=autotune and hdb=autotune for automatical tune of the PIO modes.
- * If you get strange results, do not use this and set PIO manually
- * by hdparm.
*
* Version 0.1, Nov 8, 1996
* by Jaromir Koutek, for 2.1.8.
@@ -103,7 +100,7 @@
#include <asm/io.h>
-#define OPTI621_MAX_PIO 3
+//#define OPTI621_MAX_PIO 3
/* In fact, I do not have any PIO 4 drive
* (address: 25 ns, data: 70 ns, recovery: 35 ns),
* but OPTi 82C621 is programmable and it can do (minimal values):
@@ -136,8 +133,10 @@ static int reg_base;
#define PIO_NOT_EXIST 254
#define PIO_DONT_KNOW 255
-/* there are stored pio numbers from other calls of opti621_tune_drive */
-static void compute_pios(ide_drive_t *drive, u8 pio)
+static DEFINE_SPINLOCK(opti621_lock);
+
+/* there are stored pio numbers from other calls of opti621_set_pio_mode */
+static void compute_pios(ide_drive_t *drive, const u8 pio)
/* Store values into drive->drive_data
* second_contr - 0 for primary controller, 1 for secondary
* slave_drive - 0 -> pio is for master, 1 -> pio is for slave
@@ -147,12 +146,13 @@ static void compute_pios(ide_drive_t *drive, u8 pio)
int d;
ide_hwif_t *hwif = HWIF(drive);
- drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO);
+ drive->drive_data = pio;
+
for (d = 0; d < 2; ++d) {
drive = &hwif->drives[d];
if (drive->present) {
if (drive->drive_data == PIO_DONT_KNOW)
- drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO);
+ drive->drive_data = ide_get_best_pio_mode(drive, 255, 3);
#ifdef OPTI621_DEBUG
printk("%s: Selected PIO mode %d\n",
drive->name, drive->drive_data);
@@ -240,8 +240,7 @@ static void compute_clocks(int pio, pio_clocks_t *clks)
}
-/* Main tune procedure, called from tuneproc. */
-static void opti621_tune_drive (ide_drive_t *drive, u8 pio)
+static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
/* primary and secondary drives share some registers,
* so we have to program both drives
@@ -281,7 +280,7 @@ static void opti621_tune_drive (ide_drive_t *drive, u8 pio)
second.recovery_time, drdy);
#endif
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&opti621_lock, flags);
reg_base = hwif->io_ports[IDE_DATA_OFFSET];
@@ -320,7 +319,7 @@ static void opti621_tune_drive (ide_drive_t *drive, u8 pio)
/* and read prefetch for both drives */
write_reg(misc, MISC_REG);
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&opti621_lock, flags);
}
/*
@@ -328,39 +327,31 @@ static void opti621_tune_drive (ide_drive_t *drive, u8 pio)
*/
static void __devinit init_hwif_opti621 (ide_hwif_t *hwif)
{
- hwif->autodma = 0;
hwif->drives[0].drive_data = PIO_DONT_KNOW;
hwif->drives[1].drive_data = PIO_DONT_KNOW;
- hwif->tuneproc = &opti621_tune_drive;
-
- if (!(hwif->dma_base))
- return;
-
- hwif->atapi_dma = 1;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
+ hwif->set_pio_mode = &opti621_set_pio_mode;
}
-static ide_pci_device_t opti621_chipsets[] __devinitdata = {
+static const struct ide_port_info opti621_chipsets[] __devinitdata = {
{ /* 0 */
.name = "OPTI621",
.init_hwif = init_hwif_opti621,
- .autodma = AUTODMA,
.enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+ IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO3,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
},{ /* 1 */
.name = "OPTI621X",
.init_hwif = init_hwif_opti621,
- .autodma = AUTODMA,
.enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+ IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO3,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
}
};
@@ -369,9 +360,9 @@ static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_devi
return ide_setup_pci_device(dev, &opti621_chipsets[id->driver_data]);
}
-static struct pci_device_id opti621_pci_tbl[] = {
- { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+static const struct pci_device_id opti621_pci_tbl[] = {
+ { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 },
+ { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 1 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, opti621_pci_tbl);
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index 7b0e479c355..4234efeba60 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -146,21 +146,16 @@ static struct udma_timing {
{ 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */
};
-static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
+static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
u8 adj = (drive->dn & 1) ? 0x08 : 0x00;
- int err;
-
- speed = ide_rate_filter(drive, speed);
/*
- * Issue SETFEATURES_XFER to the drive first. PDC202xx hardware will
+ * IDE core issues SETFEATURES_XFER to the drive first (thanks to
+ * IDE_HFLAG_POST_SET_MODE in ->host_flags). PDC202xx hardware will
* automatically set the timing registers based on 100 MHz PLL output.
- */
- err = ide_config_drive_speed(drive, speed);
-
- /*
+ *
* As we set up the PLL to output 133 MHz for UltraDMA/133 capable
* chips, we must override the default register settings...
*/
@@ -213,14 +208,11 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
set_indexed_reg(hwif, 0x10 + adj, tmp & 0x7f);
}
-
- return err;
}
-static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
+static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- (void)pdcnew_tune_chipset(drive, XFER_PIO_0 + pio);
+ pdcnew_set_mode(drive, XFER_PIO_0 + pio);
}
static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
@@ -231,19 +223,6 @@ static u8 pdcnew_cable_detect(ide_hwif_t *hwif)
return ATA_CBL_PATA80;
}
-static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive)
-{
- drive->init_speed = 0;
-
- if (ide_tune_dma(drive))
- return 0;
-
- if (ide_use_fast_pio(drive))
- pdcnew_tune_drive(drive, 255);
-
- return -1;
-}
-
static int pdcnew_quirkproc(ide_drive_t *drive)
{
const char **list, *model = drive->id->model;
@@ -353,16 +332,12 @@ static long __devinit detect_pll_input_clock(unsigned long dma_base)
static void __devinit apple_kiwi_init(struct pci_dev *pdev)
{
struct device_node *np = pci_device_to_OF_node(pdev);
- unsigned int class_rev = 0;
u8 conf;
if (np == NULL || !of_device_is_compatible(np, "kiwi-root"))
return;
- pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
-
- if (class_rev >= 0x03) {
+ if (pdev->revision >= 0x03) {
/* Setup chip magic config stuff (from darwin) */
pci_read_config_byte (pdev, 0x40, &conf);
pci_write_config_byte(pdev, 0x40, (conf | 0x01));
@@ -490,148 +465,62 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
{
- hwif->autodma = 0;
+ hwif->set_pio_mode = &pdcnew_set_pio_mode;
+ hwif->set_dma_mode = &pdcnew_set_mode;
- hwif->tuneproc = &pdcnew_tune_drive;
hwif->quirkproc = &pdcnew_quirkproc;
- hwif->speedproc = &pdcnew_tune_chipset;
hwif->resetproc = &pdcnew_reset;
- hwif->err_stops_fifo = 1;
-
- hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
-
if (hwif->dma_base == 0)
return;
- hwif->atapi_dma = 1;
-
- hwif->ultra_mask = hwif->cds->udma_mask;
- hwif->mwdma_mask = 0x07;
-
- hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
-
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
hwif->cbl = pdcnew_cable_detect(hwif);
-
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
}
-static int __devinit init_setup_pdcnew(struct pci_dev *dev, ide_pci_device_t *d)
+static struct pci_dev * __devinit pdc20270_get_dev2(struct pci_dev *dev)
{
- return ide_setup_pci_device(dev, d);
-}
-
-static int __devinit init_setup_pdc20270(struct pci_dev *dev,
- ide_pci_device_t *d)
-{
- struct pci_dev *findev = NULL;
- int ret;
-
- if ((dev->bus->self &&
- dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
- (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
- if (PCI_SLOT(dev->devfn) & 2)
- return -ENODEV;
-
- while ((findev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
- if ((findev->vendor == dev->vendor) &&
- (findev->device == dev->device) &&
- (PCI_SLOT(findev->devfn) & 2)) {
- if (findev->irq != dev->irq) {
- findev->irq = dev->irq;
- }
- ret = ide_setup_pci_devices(dev, findev, d);
- if (ret < 0)
- pci_dev_put(findev);
- return ret;
- }
+ struct pci_dev *dev2;
+
+ dev2 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn) + 2,
+ PCI_FUNC(dev->devfn)));
+ if (dev2 &&
+ dev2->vendor == dev->vendor &&
+ dev2->device == dev->device) {
+
+ if (dev2->irq != dev->irq) {
+ dev2->irq = dev->irq;
+ printk(KERN_INFO "PDC20270: PCI config space "
+ "interrupt fixed\n");
}
- }
- return ide_setup_pci_device(dev, d);
-}
-static int __devinit init_setup_pdc20276(struct pci_dev *dev,
- ide_pci_device_t *d)
-{
- if ((dev->bus->self) &&
- (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
- ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
- (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
- printk(KERN_INFO "ide: Skipping Promise PDC20276 "
- "attached to I2O RAID controller.\n");
- return -ENODEV;
+ return dev2;
}
- return ide_setup_pci_device(dev, d);
+
+ return NULL;
}
-static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
- { /* 0 */
- .name = "PDC20268",
- .init_setup = init_setup_pdcnew,
- .init_chipset = init_chipset_pdcnew,
- .init_hwif = init_hwif_pdc202new,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- .pio_mask = ATA_PIO4,
- .udma_mask = 0x3f, /* udma0-5 */
- },{ /* 1 */
- .name = "PDC20269",
- .init_setup = init_setup_pdcnew,
- .init_chipset = init_chipset_pdcnew,
- .init_hwif = init_hwif_pdc202new,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- .pio_mask = ATA_PIO4,
- .udma_mask = 0x7f, /* udma0-6*/
- },{ /* 2 */
- .name = "PDC20270",
- .init_setup = init_setup_pdc20270,
- .init_chipset = init_chipset_pdcnew,
- .init_hwif = init_hwif_pdc202new,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- .pio_mask = ATA_PIO4,
- .udma_mask = 0x3f, /* udma0-5 */
- },{ /* 3 */
- .name = "PDC20271",
- .init_setup = init_setup_pdcnew,
- .init_chipset = init_chipset_pdcnew,
- .init_hwif = init_hwif_pdc202new,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- .pio_mask = ATA_PIO4,
- .udma_mask = 0x7f, /* udma0-6*/
- },{ /* 4 */
- .name = "PDC20275",
- .init_setup = init_setup_pdcnew,
- .init_chipset = init_chipset_pdcnew,
- .init_hwif = init_hwif_pdc202new,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- .pio_mask = ATA_PIO4,
- .udma_mask = 0x7f, /* udma0-6*/
- },{ /* 5 */
- .name = "PDC20276",
- .init_setup = init_setup_pdc20276,
- .init_chipset = init_chipset_pdcnew,
- .init_hwif = init_hwif_pdc202new,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- .pio_mask = ATA_PIO4,
- .udma_mask = 0x7f, /* udma0-6*/
- },{ /* 6 */
- .name = "PDC20277",
- .init_setup = init_setup_pdcnew,
- .init_chipset = init_chipset_pdcnew,
- .init_hwif = init_hwif_pdc202new,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- .pio_mask = ATA_PIO4,
- .udma_mask = 0x7f, /* udma0-6*/
+#define DECLARE_PDCNEW_DEV(name_str, udma) \
+ { \
+ .name = name_str, \
+ .init_chipset = init_chipset_pdcnew, \
+ .init_hwif = init_hwif_pdc202new, \
+ .host_flags = IDE_HFLAG_POST_SET_MODE | \
+ IDE_HFLAG_ERROR_STOPS_FIFO | \
+ IDE_HFLAG_OFF_BOARD, \
+ .pio_mask = ATA_PIO4, \
+ .mwdma_mask = ATA_MWDMA2, \
+ .udma_mask = udma, \
}
+
+static const struct ide_port_info pdcnew_chipsets[] __devinitdata = {
+ /* 0 */ DECLARE_PDCNEW_DEV("PDC20268", ATA_UDMA5),
+ /* 1 */ DECLARE_PDCNEW_DEV("PDC20269", ATA_UDMA6),
+ /* 2 */ DECLARE_PDCNEW_DEV("PDC20270", ATA_UDMA5),
+ /* 3 */ DECLARE_PDCNEW_DEV("PDC20271", ATA_UDMA6),
+ /* 4 */ DECLARE_PDCNEW_DEV("PDC20275", ATA_UDMA6),
+ /* 5 */ DECLARE_PDCNEW_DEV("PDC20276", ATA_UDMA6),
+ /* 6 */ DECLARE_PDCNEW_DEV("PDC20277", ATA_UDMA6),
};
/**
@@ -645,19 +534,50 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
static int __devinit pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_pci_device_t *d = &pdcnew_chipsets[id->driver_data];
+ const struct ide_port_info *d;
+ struct pci_dev *bridge = dev->bus->self;
+ u8 idx = id->driver_data;
+
+ d = &pdcnew_chipsets[idx];
+
+ if (idx == 2 && bridge &&
+ bridge->vendor == PCI_VENDOR_ID_DEC &&
+ bridge->device == PCI_DEVICE_ID_DEC_21150) {
+ struct pci_dev *dev2;
- return d->init_setup(dev, d);
+ if (PCI_SLOT(dev->devfn) & 2)
+ return -ENODEV;
+
+ dev2 = pdc20270_get_dev2(dev);
+
+ if (dev2) {
+ int ret = ide_setup_pci_devices(dev, dev2, d);
+ if (ret < 0)
+ pci_dev_put(dev2);
+ return ret;
+ }
+ }
+
+ if (idx == 5 && bridge &&
+ bridge->vendor == PCI_VENDOR_ID_INTEL &&
+ (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
+ bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
+ printk(KERN_INFO "PDC20276: attached to I2O RAID controller, "
+ "skipping\n");
+ return -ENODEV;
+ }
+
+ return ide_setup_pci_device(dev, d);
}
-static struct pci_device_id pdc202new_pci_tbl[] = {
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+static const struct pci_device_id pdc202new_pci_tbl[] = {
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), 0 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), 1 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), 2 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), 3 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), 4 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), 5 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), 6 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl);
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index e19a891171c..e09742e2ba5 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/pdc202xx_old.c Version 0.51 Jul 27, 2007
+ * linux/drivers/ide/pci/pdc202xx_old.c Version 0.52 Aug 27, 2007
*
* Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2006-2007 MontaVista Software, Inc.
@@ -63,12 +63,11 @@ static const char *pdc_quirk_drives[] = {
static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
-static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u8 drive_pci = 0x60 + (drive->dn << 2);
- u8 speed = ide_rate_filter(drive, xferspeed);
u8 AP = 0, BP = 0, CP = 0;
u8 TA = 0, TB = 0, TC = 0;
@@ -98,9 +97,6 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_MW_DMA_2: TB = 0x60; TC = 0x03; break;
case XFER_MW_DMA_1: TB = 0x60; TC = 0x04; break;
case XFER_MW_DMA_0: TB = 0xE0; TC = 0x0F; break;
- case XFER_SW_DMA_2: TB = 0x60; TC = 0x05; break;
- case XFER_SW_DMA_1: TB = 0x80; TC = 0x06; break;
- case XFER_SW_DMA_0: TB = 0xC0; TC = 0x0B; break;
case XFER_PIO_4: TA = 0x01; TB = 0x04; break;
case XFER_PIO_3: TA = 0x02; TB = 0x06; break;
case XFER_PIO_2: TA = 0x03; TB = 0x08; break;
@@ -139,14 +135,11 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
pci_read_config_dword(dev, drive_pci, &drive_conf);
printk("0x%08x\n", drive_conf);
#endif
-
- return ide_config_drive_speed(drive, speed);
}
-static void pdc202xx_tune_drive(ide_drive_t *drive, u8 pio)
+static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- pdc202xx_tune_chipset(drive, XFER_PIO_0 + pio);
+ pdc202xx_set_mode(drive, XFER_PIO_0 + pio);
}
static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif)
@@ -183,19 +176,6 @@ static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif)
outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg);
}
-static int pdc202xx_config_drive_xfer_rate (ide_drive_t *drive)
-{
- drive->init_speed = 0;
-
- if (ide_tune_dma(drive))
- return 0;
-
- if (ide_use_fast_pio(drive))
- pdc202xx_tune_drive(drive, 255);
-
- return -1;
-}
-
static int pdc202xx_quirkproc (ide_drive_t *drive)
{
const char **list, *model = drive->id->model;
@@ -307,10 +287,11 @@ static void pdc202xx_reset (ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
ide_hwif_t *mate = hwif->mate;
-
+
pdc202xx_reset_host(hwif);
pdc202xx_reset_host(mate);
- pdc202xx_tune_drive(drive, 255);
+
+ ide_set_max_pio(drive);
}
static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
@@ -321,35 +302,17 @@ static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
{
- struct pci_dev *dev = hwif->pci_dev;
+ hwif->set_pio_mode = &pdc202xx_set_pio_mode;
+ hwif->set_dma_mode = &pdc202xx_set_mode;
- /* PDC20265 has problems with large LBA48 requests */
- if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) ||
- (dev->device == PCI_DEVICE_ID_PROMISE_20265))
- hwif->rqsize = 256;
-
- hwif->autodma = 0;
- hwif->tuneproc = &pdc202xx_tune_drive;
hwif->quirkproc = &pdc202xx_quirkproc;
if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246)
hwif->resetproc = &pdc202xx_reset;
- hwif->speedproc = &pdc202xx_tune_chipset;
-
- hwif->err_stops_fifo = 1;
-
- hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
-
if (hwif->dma_base == 0)
return;
- hwif->ultra_mask = hwif->cds->udma_mask;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
- hwif->atapi_dma = 1;
-
- hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
hwif->dma_lost_irq = &pdc202xx_dma_lost_irq;
hwif->dma_timeout = &pdc202xx_dma_timeout;
@@ -361,10 +324,6 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
hwif->ide_dma_end = &pdc202xx_old_ide_dma_end;
}
hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq;
-
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
}
static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
@@ -399,8 +358,8 @@ static void __devinit init_dma_pdc202xx(ide_hwif_t *hwif, unsigned long dmabase)
ide_setup_dma(hwif, dmabase, 8);
}
-static int __devinit init_setup_pdc202ata4(struct pci_dev *dev,
- ide_pci_device_t *d)
+static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev,
+ const char *name)
{
if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
u8 irq = 0, irq2 = 0;
@@ -410,90 +369,45 @@ static int __devinit init_setup_pdc202ata4(struct pci_dev *dev,
if (irq != irq2) {
pci_write_config_byte(dev,
(PCI_INTERRUPT_LINE)|0x80, irq); /* 0xbc */
- printk(KERN_INFO "%s: pci-config space interrupt "
- "mirror fixed.\n", d->name);
+ printk(KERN_INFO "%s: PCI config space interrupt "
+ "mirror fixed\n", name);
}
}
- return ide_setup_pci_device(dev, d);
}
-static int __devinit init_setup_pdc20265(struct pci_dev *dev,
- ide_pci_device_t *d)
-{
- if ((dev->bus->self) &&
- (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
- ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
- (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
- printk(KERN_INFO "ide: Skipping Promise PDC20265 "
- "attached to I2O RAID controller.\n");
- return -ENODEV;
+#define DECLARE_PDC2026X_DEV(name_str, udma, extra_flags) \
+ { \
+ .name = name_str, \
+ .init_chipset = init_chipset_pdc202xx, \
+ .init_hwif = init_hwif_pdc202xx, \
+ .init_dma = init_dma_pdc202xx, \
+ .extra = 48, \
+ .host_flags = IDE_HFLAG_ERROR_STOPS_FIFO | \
+ extra_flags | \
+ IDE_HFLAG_OFF_BOARD, \
+ .pio_mask = ATA_PIO4, \
+ .mwdma_mask = ATA_MWDMA2, \
+ .udma_mask = udma, \
}
- return ide_setup_pci_device(dev, d);
-}
-
-static int __devinit init_setup_pdc202xx(struct pci_dev *dev,
- ide_pci_device_t *d)
-{
- return ide_setup_pci_device(dev, d);
-}
-static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
+static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = {
{ /* 0 */
.name = "PDC20246",
- .init_setup = init_setup_pdc202ata4,
.init_chipset = init_chipset_pdc202xx,
.init_hwif = init_hwif_pdc202xx,
.init_dma = init_dma_pdc202xx,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
.extra = 16,
+ .host_flags = IDE_HFLAG_ERROR_STOPS_FIFO |
+ IDE_HFLAG_OFF_BOARD,
.pio_mask = ATA_PIO4,
- .udma_mask = 0x07, /* udma0-2 */
- },{ /* 1 */
- .name = "PDC20262",
- .init_setup = init_setup_pdc202ata4,
- .init_chipset = init_chipset_pdc202xx,
- .init_hwif = init_hwif_pdc202xx,
- .init_dma = init_dma_pdc202xx,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- .extra = 48,
- .pio_mask = ATA_PIO4,
- .udma_mask = 0x1f, /* udma0-4 */
- },{ /* 2 */
- .name = "PDC20263",
- .init_setup = init_setup_pdc202ata4,
- .init_chipset = init_chipset_pdc202xx,
- .init_hwif = init_hwif_pdc202xx,
- .init_dma = init_dma_pdc202xx,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- .extra = 48,
- .pio_mask = ATA_PIO4,
- .udma_mask = 0x1f, /* udma0-4 */
- },{ /* 3 */
- .name = "PDC20265",
- .init_setup = init_setup_pdc20265,
- .init_chipset = init_chipset_pdc202xx,
- .init_hwif = init_hwif_pdc202xx,
- .init_dma = init_dma_pdc202xx,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- .extra = 48,
- .pio_mask = ATA_PIO4,
- .udma_mask = 0x3f, /* udma0-5 */
- },{ /* 4 */
- .name = "PDC20267",
- .init_setup = init_setup_pdc202xx,
- .init_chipset = init_chipset_pdc202xx,
- .init_hwif = init_hwif_pdc202xx,
- .init_dma = init_dma_pdc202xx,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- .extra = 48,
- .pio_mask = ATA_PIO4,
- .udma_mask = 0x3f, /* udma0-5 */
- }
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
+ },
+
+ /* 1 */ DECLARE_PDC2026X_DEV("PDC20262", ATA_UDMA4, 0),
+ /* 2 */ DECLARE_PDC2026X_DEV("PDC20263", ATA_UDMA4, 0),
+ /* 3 */ DECLARE_PDC2026X_DEV("PDC20265", ATA_UDMA5, IDE_HFLAG_RQSIZE_256),
+ /* 4 */ DECLARE_PDC2026X_DEV("PDC20267", ATA_UDMA5, IDE_HFLAG_RQSIZE_256),
};
/**
@@ -507,17 +421,36 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_pci_device_t *d = &pdc202xx_chipsets[id->driver_data];
+ const struct ide_port_info *d;
+ u8 idx = id->driver_data;
+
+ d = &pdc202xx_chipsets[idx];
+
+ if (idx < 3)
+ pdc202ata4_fixup_irq(dev, d->name);
- return d->init_setup(dev, d);
+ if (idx == 3) {
+ struct pci_dev *bridge = dev->bus->self;
+
+ if (bridge &&
+ bridge->vendor == PCI_VENDOR_ID_INTEL &&
+ (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
+ bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
+ printk(KERN_INFO "ide: Skipping Promise PDC20265 "
+ "attached to I2O RAID controller\n");
+ return -ENODEV;
+ }
+ }
+
+ return ide_setup_pci_device(dev, d);
}
-static struct pci_device_id pdc202xx_pci_tbl[] = {
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+static const struct pci_device_id pdc202xx_pci_tbl[] = {
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 2 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 3 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 4 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index 5cfa9378bbb..63625a0be71 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/piix.c Version 0.51 Jul 6, 2007
+ * linux/drivers/ide/pci/piix.c Version 0.54 Sep 5, 2007
*
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
* Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
@@ -17,11 +17,11 @@
* 41
* 43
*
- * | PIO 0 | c0 | 80 | 0 | piix_tune_drive(drive, 0);
- * | PIO 2 | SW2 | d0 | 90 | 4 | piix_tune_drive(drive, 2);
- * | PIO 3 | MW1 | e1 | a1 | 9 | piix_tune_drive(drive, 3);
- * | PIO 4 | MW2 | e3 | a3 | b | piix_tune_drive(drive, 4);
- *
+ * | PIO 0 | c0 | 80 | 0 |
+ * | PIO 2 | SW2 | d0 | 90 | 4 |
+ * | PIO 3 | MW1 | e1 | a1 | 9 |
+ * | PIO 4 | MW2 | e3 | a3 | b |
+ *
* sitre = word40 & 0x4000; primary
* sitre = word42 & 0x4000; secondary
*
@@ -106,44 +106,14 @@
static int no_piix_dma;
/**
- * piix_dma_2_pio - return the PIO mode matching DMA
- * @xfer_rate: transfer speed
- *
- * Returns the nearest equivalent PIO timing for the DMA
- * mode requested by the controller.
- */
-
-static u8 piix_dma_2_pio (u8 xfer_rate) {
- switch(xfer_rate) {
- case XFER_UDMA_6:
- case XFER_UDMA_5:
- case XFER_UDMA_4:
- case XFER_UDMA_3:
- case XFER_UDMA_2:
- case XFER_UDMA_1:
- case XFER_UDMA_0:
- case XFER_MW_DMA_2:
- return 4;
- case XFER_MW_DMA_1:
- return 3;
- case XFER_SW_DMA_2:
- return 2;
- case XFER_MW_DMA_0:
- case XFER_SW_DMA_1:
- case XFER_SW_DMA_0:
- default:
- return 0;
- }
-}
-
-/**
- * piix_tune_pio - tune PIIX for PIO mode
- * @drive: drive to tune
- * @pio: desired PIO mode
+ * piix_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
* Set the interface PIO mode based upon the settings done by AMI BIOS.
*/
-static void piix_tune_pio (ide_drive_t *drive, u8 pio)
+
+static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -204,36 +174,19 @@ static void piix_tune_pio (ide_drive_t *drive, u8 pio)
}
/**
- * piix_tune_drive - tune a drive attached to PIIX
- * @drive: drive to tune
- * @pio: desired PIO mode
+ * piix_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
- * Set the drive's PIO mode (might be useful if drive is not registered
- * in CMOS for any reason).
+ * Set a PIIX host controller to the desired DMA mode. This involves
+ * programming the right timing data into the PCI configuration space.
*/
-static void piix_tune_drive (ide_drive_t *drive, u8 pio)
-{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- piix_tune_pio(drive, pio);
- (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-/**
- * piix_tune_chipset - tune a PIIX interface
- * @drive: IDE drive to tune
- * @xferspeed: speed to configure
- *
- * Set a PIIX interface channel to the desired speeds. This involves
- * requires the right timing data into the PIIX configuration space
- * then setting the drive parameters appropriately
- */
-
-static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u8 maslave = hwif->channel ? 0x42 : 0x40;
- u8 speed = ide_rate_filter(drive, xferspeed);
int a_speed = 3 << (drive->dn * 4);
int u_flag = 1 << drive->dn;
int v_flag = 0x01 << drive->dn;
@@ -260,12 +213,7 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_SW_DMA_2: break;
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0: break;
- default: return -1;
+ default: return;
}
if (speed >= XFER_UDMA_0) {
@@ -284,6 +232,9 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
} else
pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
} else {
+ const u8 mwdma_to_pio[] = { 0, 3, 4 };
+ u8 pio;
+
if (reg48 & u_flag)
pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
if (reg4a & a_speed)
@@ -292,85 +243,31 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
if (reg55 & w_flag)
pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
- }
-
- if (speed > XFER_PIO_4)
- piix_tune_pio(drive, piix_dma_2_pio(speed));
- else
- piix_tune_pio(drive, speed - XFER_PIO_0);
-
- return ide_config_drive_speed(drive, speed);
-}
-
-/**
- * piix_config_drive_xfer_rate - set up an IDE device
- * @drive: IDE drive to configure
- *
- * Set up the PIIX interface for the best available speed on this
- * interface, preferring DMA to PIO.
- */
-
-static int piix_config_drive_xfer_rate (ide_drive_t *drive)
-{
- drive->init_speed = 0;
- if (ide_tune_dma(drive))
- return 0;
+ if (speed >= XFER_MW_DMA_0)
+ pio = mwdma_to_pio[speed - XFER_MW_DMA_0];
+ else
+ pio = 2; /* only SWDMA2 is allowed */
- if (ide_use_fast_pio(drive))
- piix_tune_drive(drive, 255);
-
- return -1;
-}
-
-/**
- * piix_is_ichx - check if ICHx
- * @dev: PCI device to check
- *
- * returns 1 if ICHx, 0 otherwise.
- */
-static int piix_is_ichx(struct pci_dev *dev)
-{
- switch (dev->device) {
- case PCI_DEVICE_ID_INTEL_82801EB_1:
- case PCI_DEVICE_ID_INTEL_82801AA_1:
- case PCI_DEVICE_ID_INTEL_82801AB_1:
- case PCI_DEVICE_ID_INTEL_82801BA_8:
- case PCI_DEVICE_ID_INTEL_82801BA_9:
- case PCI_DEVICE_ID_INTEL_82801CA_10:
- case PCI_DEVICE_ID_INTEL_82801CA_11:
- case PCI_DEVICE_ID_INTEL_82801DB_1:
- case PCI_DEVICE_ID_INTEL_82801DB_10:
- case PCI_DEVICE_ID_INTEL_82801DB_11:
- case PCI_DEVICE_ID_INTEL_82801EB_11:
- case PCI_DEVICE_ID_INTEL_82801E_11:
- case PCI_DEVICE_ID_INTEL_ESB_2:
- case PCI_DEVICE_ID_INTEL_ICH6_19:
- case PCI_DEVICE_ID_INTEL_ICH7_21:
- case PCI_DEVICE_ID_INTEL_ESB2_18:
- case PCI_DEVICE_ID_INTEL_ICH8_6:
- return 1;
+ piix_set_pio_mode(drive, pio);
}
-
- return 0;
}
/**
- * init_chipset_piix - set up the PIIX chipset
+ * init_chipset_ich - set up the ICH chipset
* @dev: PCI device to set up
* @name: Name of the device
*
- * Initialize the PCI device as required. For the PIIX this turns
- * out to be nice and simple
+ * Initialize the PCI device as required. For the ICH this turns
+ * out to be nice and simple.
*/
-static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_ich(struct pci_dev *dev, const char *name)
{
- if (piix_is_ichx(dev)) {
- unsigned int extra = 0;
- pci_read_config_dword(dev, 0x54, &extra);
- pci_write_config_dword(dev, 0x54, extra|0x400);
- }
+ u32 extra = 0;
+
+ pci_read_config_dword(dev, 0x54, &extra);
+ pci_write_config_dword(dev, 0x54, extra | 0x400);
return 0;
}
@@ -388,9 +285,9 @@ static void piix_dma_clear_irq(ide_drive_t *drive)
u8 dma_stat;
/* clear the INTR & ERROR bits */
- dma_stat = hwif->INB(hwif->dma_status);
+ dma_stat = inb(hwif->dma_status);
/* Should we force the bit as well ? */
- hwif->OUTB(dma_stat, hwif->dma_status);
+ outb(dma_stat, hwif->dma_status);
}
struct ich_laptop {
@@ -405,6 +302,7 @@ struct ich_laptop {
static const struct ich_laptop ich_laptop[] = {
/* devid, subvendor, subdev */
+ { 0x27DF, 0x1025, 0x0102 }, /* ICH7 on Acer 5602aWLMi */
{ 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */
{ 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
{ 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
@@ -444,35 +342,12 @@ static u8 __devinit piix_cable_detect(ide_hwif_t *hwif)
static void __devinit init_hwif_piix(ide_hwif_t *hwif)
{
-#ifndef CONFIG_IA64
- if (!hwif->irq)
- hwif->irq = hwif->channel ? 15 : 14;
-#endif /* CONFIG_IA64 */
-
- if (hwif->pci_dev->device == PCI_DEVICE_ID_INTEL_82371MX) {
- /* This is a painful system best to let it self tune for now */
- return;
- }
-
- hwif->autodma = 0;
- hwif->tuneproc = &piix_tune_drive;
- hwif->speedproc = &piix_tune_chipset;
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ hwif->set_pio_mode = &piix_set_pio_mode;
+ hwif->set_dma_mode = &piix_set_dma_mode;
if (!hwif->dma_base)
return;
- /* ICHx need to clear the bmdma status for all interrupts */
- if (piix_is_ichx(hwif->pci_dev))
- hwif->ide_dma_clear_irq = &piix_dma_clear_irq;
-
- hwif->atapi_dma = 1;
-
- hwif->ultra_mask = hwif->cds->udma_mask;
- hwif->mwdma_mask = 0x06;
- hwif->swdma_mask = 0x04;
-
if (hwif->ultra_mask & 0x78) {
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
hwif->cbl = piix_cable_detect(hwif);
@@ -480,30 +355,51 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
if (no_piix_dma)
hwif->ultra_mask = hwif->mwdma_mask = hwif->swdma_mask = 0;
+}
- hwif->ide_dma_check = &piix_config_drive_xfer_rate;
- if (!noautodma)
- hwif->autodma = 1;
+static void __devinit init_hwif_ich(ide_hwif_t *hwif)
+{
+ init_hwif_piix(hwif);
- hwif->drives[1].autodma = hwif->autodma;
- hwif->drives[0].autodma = hwif->autodma;
+ /* ICHx need to clear the BMDMA status for all interrupts */
+ if (hwif->dma_base)
+ hwif->ide_dma_clear_irq = &piix_dma_clear_irq;
}
+#ifndef CONFIG_IA64
+ #define IDE_HFLAGS_PIIX (IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE)
+#else
+ #define IDE_HFLAGS_PIIX IDE_HFLAG_BOOTABLE
+#endif
+
#define DECLARE_PIIX_DEV(name_str, udma) \
{ \
.name = name_str, \
- .init_chipset = init_chipset_piix, \
.init_hwif = init_hwif_piix, \
- .autodma = AUTODMA, \
.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
- .bootable = ON_BOARD, \
+ .host_flags = IDE_HFLAGS_PIIX, \
.pio_mask = ATA_PIO4, \
+ .swdma_mask = ATA_SWDMA2_ONLY, \
+ .mwdma_mask = ATA_MWDMA12_ONLY, \
.udma_mask = udma, \
}
-static ide_pci_device_t piix_pci_info[] __devinitdata = {
- /* 0 */ DECLARE_PIIX_DEV("PIIXa", 0x00), /* no udma */
- /* 1 */ DECLARE_PIIX_DEV("PIIXb", 0x00), /* no udma */
+#define DECLARE_ICH_DEV(name_str, udma) \
+ { \
+ .name = name_str, \
+ .init_chipset = init_chipset_ich, \
+ .init_hwif = init_hwif_ich, \
+ .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
+ .host_flags = IDE_HFLAGS_PIIX, \
+ .pio_mask = ATA_PIO4, \
+ .swdma_mask = ATA_SWDMA2_ONLY, \
+ .mwdma_mask = ATA_MWDMA12_ONLY, \
+ .udma_mask = udma, \
+ }
+
+static const struct ide_port_info piix_pci_info[] __devinitdata = {
+ /* 0 */ DECLARE_PIIX_DEV("PIIXa", 0x00), /* no udma */
+ /* 1 */ DECLARE_PIIX_DEV("PIIXb", 0x00), /* no udma */
/* 2 */
{ /*
@@ -512,36 +408,35 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
* of the bit 14 of the IDETIM register at offset 0x6c
*/
.name = "MPIIX",
- .init_hwif = init_hwif_piix,
- .autodma = NODMA,
.enablebits = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
- .bootable = ON_BOARD,
- .host_flags = IDE_HFLAG_ISA_PORTS,
+ .host_flags = IDE_HFLAG_ISA_PORTS | IDE_HFLAG_NO_DMA |
+ IDE_HFLAGS_PIIX,
.pio_mask = ATA_PIO4,
+ /* This is a painful system best to let it self tune for now */
},
- /* 3 */ DECLARE_PIIX_DEV("PIIX3", 0x00), /* no udma */
- /* 4 */ DECLARE_PIIX_DEV("PIIX4", 0x07), /* udma0-2 */
- /* 5 */ DECLARE_PIIX_DEV("ICH0", 0x07), /* udma0-2 */
- /* 6 */ DECLARE_PIIX_DEV("PIIX4", 0x07), /* udma0-2 */
- /* 7 */ DECLARE_PIIX_DEV("ICH", 0x1f), /* udma0-4 */
- /* 8 */ DECLARE_PIIX_DEV("PIIX4", 0x1f), /* udma0-4 */
- /* 9 */ DECLARE_PIIX_DEV("PIIX4", 0x07), /* udma0-2 */
- /* 10 */ DECLARE_PIIX_DEV("ICH2", 0x3f), /* udma0-5 */
- /* 11 */ DECLARE_PIIX_DEV("ICH2M", 0x3f), /* udma0-5 */
- /* 12 */ DECLARE_PIIX_DEV("ICH3M", 0x3f), /* udma0-5 */
- /* 13 */ DECLARE_PIIX_DEV("ICH3", 0x3f), /* udma0-5 */
- /* 14 */ DECLARE_PIIX_DEV("ICH4", 0x3f), /* udma0-5 */
- /* 15 */ DECLARE_PIIX_DEV("ICH5", 0x3f), /* udma0-5 */
- /* 16 */ DECLARE_PIIX_DEV("C-ICH", 0x3f), /* udma0-5 */
- /* 17 */ DECLARE_PIIX_DEV("ICH4", 0x3f), /* udma0-5 */
- /* 18 */ DECLARE_PIIX_DEV("ICH5-SATA", 0x3f), /* udma0-5 */
- /* 19 */ DECLARE_PIIX_DEV("ICH5", 0x3f), /* udma0-5 */
- /* 20 */ DECLARE_PIIX_DEV("ICH6", 0x3f), /* udma0-5 */
- /* 21 */ DECLARE_PIIX_DEV("ICH7", 0x3f), /* udma0-5 */
- /* 22 */ DECLARE_PIIX_DEV("ICH4", 0x3f), /* udma0-5 */
- /* 23 */ DECLARE_PIIX_DEV("ESB2", 0x3f), /* udma0-5 */
- /* 24 */ DECLARE_PIIX_DEV("ICH8M", 0x3f), /* udma0-5 */
+ /* 3 */ DECLARE_PIIX_DEV("PIIX3", 0x00), /* no udma */
+ /* 4 */ DECLARE_PIIX_DEV("PIIX4", ATA_UDMA2),
+ /* 5 */ DECLARE_ICH_DEV("ICH0", ATA_UDMA2),
+ /* 6 */ DECLARE_PIIX_DEV("PIIX4", ATA_UDMA2),
+ /* 7 */ DECLARE_ICH_DEV("ICH", ATA_UDMA4),
+ /* 8 */ DECLARE_PIIX_DEV("PIIX4", ATA_UDMA4),
+ /* 9 */ DECLARE_PIIX_DEV("PIIX4", ATA_UDMA2),
+ /* 10 */ DECLARE_ICH_DEV("ICH2", ATA_UDMA5),
+ /* 11 */ DECLARE_ICH_DEV("ICH2M", ATA_UDMA5),
+ /* 12 */ DECLARE_ICH_DEV("ICH3M", ATA_UDMA5),
+ /* 13 */ DECLARE_ICH_DEV("ICH3", ATA_UDMA5),
+ /* 14 */ DECLARE_ICH_DEV("ICH4", ATA_UDMA5),
+ /* 15 */ DECLARE_ICH_DEV("ICH5", ATA_UDMA5),
+ /* 16 */ DECLARE_ICH_DEV("C-ICH", ATA_UDMA5),
+ /* 17 */ DECLARE_ICH_DEV("ICH4", ATA_UDMA5),
+ /* 18 */ DECLARE_ICH_DEV("ICH5-SATA", ATA_UDMA5),
+ /* 19 */ DECLARE_ICH_DEV("ICH5", ATA_UDMA5),
+ /* 20 */ DECLARE_ICH_DEV("ICH6", ATA_UDMA5),
+ /* 21 */ DECLARE_ICH_DEV("ICH7", ATA_UDMA5),
+ /* 22 */ DECLARE_ICH_DEV("ICH4", ATA_UDMA5),
+ /* 23 */ DECLARE_ICH_DEV("ESB2", ATA_UDMA5),
+ /* 24 */ DECLARE_ICH_DEV("ICH8M", ATA_UDMA5),
};
/**
@@ -555,9 +450,7 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
static int __devinit piix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_pci_device_t *d = &piix_pci_info[id->driver_data];
-
- return ide_setup_pci_device(dev, d);
+ return ide_setup_pci_device(dev, &piix_pci_info[id->driver_data]);
}
/**
@@ -589,34 +482,34 @@ static void __devinit piix_check_450nx(void)
printk(KERN_WARNING "piix: A BIOS update may resolve this.\n");
}
-static struct pci_device_id piix_pci_tbl[] = {
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17},
+static const struct pci_device_id piix_pci_tbl[] = {
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_0), 0 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371FB_1), 1 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), 2 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371SB_1), 3 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371AB), 4 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801AB_1), 5 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82443MX_1), 6 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801AA_1), 7 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82372FB_1), 8 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82451NX), 9 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801BA_9), 10 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801BA_8), 11 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801CA_10), 12 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801CA_11), 13 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_11), 14 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_11), 15 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801E_11), 16 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_10), 17 },
#ifdef CONFIG_BLK_DEV_IDE_SATA
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18},
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801EB_1), 18 },
#endif
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_19, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 21},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 22},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 23},
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 24},
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB_2), 19 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH6_19), 20 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH7_21), 21 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1), 22 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18), 23 },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6), 24 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
index 10e1ae7a4a0..6b10ae260fa 100644
--- a/drivers/ide/pci/rz1000.c
+++ b/drivers/ide/pci/rz1000.c
@@ -35,13 +35,13 @@ static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif)
u16 reg;
struct pci_dev *dev = hwif->pci_dev;
- hwif->chipset = ide_rz1000;
if (!pci_read_config_word (dev, 0x40, &reg) &&
!pci_write_config_word(dev, 0x40, reg & 0xdfff)) {
printk(KERN_INFO "%s: disabled chipset read-ahead "
"(buggy RZ1000/RZ1001)\n", hwif->name);
} else {
- hwif->serialized = 1;
+ if (hwif->mate)
+ hwif->mate->serialized = hwif->serialized = 1;
hwif->drives[0].no_unmask = 1;
hwif->drives[1].no_unmask = 1;
printk(KERN_INFO "%s: serialized, disabled unmasking "
@@ -49,11 +49,11 @@ static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif)
}
}
-static ide_pci_device_t rz1000_chipset __devinitdata = {
+static const struct ide_port_info rz1000_chipset __devinitdata = {
.name = "RZ100x",
.init_hwif = init_hwif_rz1000,
- .autodma = NODMA,
- .bootable = ON_BOARD,
+ .chipset = ide_rz1000,
+ .host_flags = IDE_HFLAG_NO_DMA | IDE_HFLAG_BOOTABLE,
};
static int __devinit rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -61,9 +61,9 @@ static int __devinit rz1000_init_one(struct pci_dev *dev, const struct pci_devic
return ide_setup_pci_device(dev, &rz1000_chipset);
}
-static struct pci_device_id rz1000_pci_tbl[] = {
- { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static const struct pci_device_id rz1000_pci_tbl[] = {
+ { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), 0 },
+ { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl);
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index 9bdc9694d50..707d5ff66b0 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/sc1200.c Version 0.95 Jun 16 2007
+ * linux/drivers/ide/pci/sc1200.c Version 0.97 Aug 3 2007
*
* Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com>
* Copyright (C) 2007 Bartlomiej Zolnierkiewicz
@@ -68,17 +68,6 @@ static unsigned short sc1200_get_pci_clock (void)
return pci_clock;
}
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * Set a new transfer mode at the drive
- */
-static int sc1200_set_xfer_mode (ide_drive_t *drive, byte mode)
-{
- printk("%s: sc1200_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
- return ide_config_drive_speed(drive, mode);
-}
-
/*
* Here are the standard PIO mode 0-4 timings for each "format".
* Format-0 uses fast data reg timings, with slower command reg timings.
@@ -138,7 +127,7 @@ out:
return mask;
}
-static int sc1200_tune_chipset(ide_drive_t *drive, u8 mode)
+static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode)
{
ide_hwif_t *hwif = HWIF(drive);
int unit = drive->select.b.unit;
@@ -146,31 +135,9 @@ static int sc1200_tune_chipset(ide_drive_t *drive, u8 mode)
unsigned short pci_clock;
unsigned int basereg = hwif->channel ? 0x50 : 0x40;
- mode = ide_rate_filter(drive, mode);
-
- /*
- * Tell the drive to switch to the new mode; abort on failure.
- */
- if (sc1200_set_xfer_mode(drive, mode)) {
- printk("SC1200: set xfer mode failure\n");
- return 1; /* failure */
- }
-
- switch (mode) {
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- sc1200_tunepio(drive, mode - XFER_PIO_0);
- return 0;
- }
-
pci_clock = sc1200_get_pci_clock();
/*
- * Now tune the chipset to match the drive:
- *
* Note that each DMA mode has several timings associated with it.
* The correct timing depends on the fast PCI clock freq.
*/
@@ -219,8 +186,7 @@ static int sc1200_tune_chipset(ide_drive_t *drive, u8 mode)
}
break;
default:
- BUG();
- break;
+ return;
}
if (unit == 0) { /* are we configuring drive0? */
@@ -230,23 +196,8 @@ static int sc1200_tune_chipset(ide_drive_t *drive, u8 mode)
} else {
pci_write_config_dword(hwif->pci_dev, basereg+12, timings);
}
-
- return 0; /* success */
-}
-
-/*
- * sc1200_config_dma() handles selection/setting of DMA/UDMA modes
- * for both the chipset and drive.
- */
-static int sc1200_config_dma (ide_drive_t *drive)
-{
- if (ide_tune_dma(drive))
- return 0;
-
- return 1;
}
-
/* Replacement for the standard ide_dma_end action in
* dma_proc.
*
@@ -274,19 +225,20 @@ static int sc1200_ide_dma_end (ide_drive_t *drive)
}
/*
- * sc1200_tuneproc() handles selection/setting of PIO modes
+ * sc1200_set_pio_mode() handles setting of PIO modes
* for both the chipset and drive.
*
* All existing BIOSs for this chipset guarantee that all drives
* will have valid default PIO timings set up before we get here.
*/
-static void sc1200_tuneproc (ide_drive_t *drive, byte pio) /* mode=255 means "autotune" */
+
+static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
int mode = -1;
/*
- * bad abuse of ->tuneproc interface
+ * bad abuse of ->set_pio_mode interface
*/
switch (pio) {
case 200: mode = XFER_UDMA_0; break;
@@ -299,16 +251,12 @@ static void sc1200_tuneproc (ide_drive_t *drive, byte pio) /* mode=255 means "au
if (mode != -1) {
printk("SC1200: %s: changing (U)DMA mode\n", drive->name);
hwif->dma_off_quietly(drive);
- if (sc1200_tune_chipset(drive, mode) == 0)
+ if (ide_set_dma_mode(drive, mode) == 0)
hwif->dma_host_on(drive);
return;
}
- pio = ide_get_best_pio_mode(drive, pio, 4);
- printk("SC1200: %s: setting PIO mode%d\n", drive->name, pio);
-
- if (sc1200_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
- sc1200_tunepio(drive, pio);
+ sc1200_tunepio(drive, pio);
}
#ifdef CONFIG_PM
@@ -375,17 +323,18 @@ static int sc1200_suspend (struct pci_dev *dev, pm_message_t state)
pci_disable_device(dev);
pci_set_power_state(dev, pci_choose_state(dev, state));
- dev->current_state = state.event;
return 0;
}
static int sc1200_resume (struct pci_dev *dev)
{
ide_hwif_t *hwif = NULL;
+ int i;
+
+ i = pci_enable_device(dev);
+ if (i)
+ return i;
- pci_set_power_state(dev, PCI_D0); // bring chip back from sleep state
- dev->current_state = PM_EVENT_ON;
- pci_enable_device(dev);
//
// loop over all interfaces that are part of this pci device:
//
@@ -413,32 +362,26 @@ static int sc1200_resume (struct pci_dev *dev)
*/
static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif)
{
- if (hwif->mate)
- hwif->serialized = hwif->mate->serialized = 1;
- hwif->autodma = 0;
- if (hwif->dma_base) {
- hwif->udma_filter = sc1200_udma_filter;
- hwif->ide_dma_check = &sc1200_config_dma;
- hwif->ide_dma_end = &sc1200_ide_dma_end;
- if (!noautodma)
- hwif->autodma = 1;
- hwif->tuneproc = &sc1200_tuneproc;
- hwif->speedproc = &sc1200_tune_chipset;
- }
- hwif->atapi_dma = 1;
- hwif->ultra_mask = 0x07;
- hwif->mwdma_mask = 0x07;
+ hwif->set_pio_mode = &sc1200_set_pio_mode;
+ hwif->set_dma_mode = &sc1200_set_dma_mode;
+
+ if (hwif->dma_base == 0)
+ return;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
+ hwif->udma_filter = sc1200_udma_filter;
+ hwif->ide_dma_end = &sc1200_ide_dma_end;
}
-static ide_pci_device_t sc1200_chipset __devinitdata = {
+static const struct ide_port_info sc1200_chipset __devinitdata = {
.name = "SC1200",
.init_hwif = init_hwif_sc1200,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_SERIALIZE |
+ IDE_HFLAG_POST_SET_MODE |
+ IDE_HFLAG_ABUSE_DMA_MODES |
+ IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA2,
};
static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -446,8 +389,8 @@ static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_devic
return ide_setup_pci_device(dev, &sc1200_chipset);
}
-static struct pci_device_id sc1200_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE), 0},
+static const struct pci_device_id sc1200_pci_tbl[] = {
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), 0},
{ 0, },
};
MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl);
diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
index eeb0a6d434a..ebb7132b9b8 100644
--- a/drivers/ide/pci/scc_pata.c
+++ b/drivers/ide/pci/scc_pata.c
@@ -190,15 +190,15 @@ scc_ide_outsl(unsigned long port, void *addr, u32 count)
}
/**
- * scc_tune_pio - tune a drive PIO mode
- * @drive: drive to tune
- * @mode_wanted: the target operating mode
+ * scc_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
* Load the timing settings for this device mode into the
* controller.
*/
-static void scc_tune_pio(ide_drive_t *drive, const u8 pio)
+static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct scc_ports *ports = ide_get_hwifdata(hwif);
@@ -221,26 +221,18 @@ static void scc_tune_pio(ide_drive_t *drive, const u8 pio)
out_be32((void __iomem *)pioct_port, reg);
}
-static void scc_tuneproc(ide_drive_t *drive, u8 pio)
-{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- scc_tune_pio(drive, pio);
- ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
/**
- * scc_tune_chipset - tune a drive DMA mode
- * @drive: Drive to set up
- * @xferspeed: speed we want to achieve
+ * scc_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
* Load the timing settings for this device mode into the
* controller.
*/
-static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed)
+static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
- u8 speed = ide_rate_filter(drive, xferspeed);
struct scc_ports *ports = ide_get_hwifdata(hwif);
unsigned long ctl_base = ports->ctl;
unsigned long cckctrl_port = ctl_base + 0xff0;
@@ -272,15 +264,8 @@ static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed)
case XFER_UDMA_0:
idx = speed - XFER_UDMA_0;
break;
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- scc_tune_pio(drive, speed - XFER_PIO_0);
- return ide_config_drive_speed(drive, speed);
default:
- return 1;
+ return;
}
jcactsel = JCACTSELtbl[offset][idx];
@@ -296,30 +281,6 @@ static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed)
}
reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx];
out_be32((void __iomem *)udenvt_port, reg);
-
- return ide_config_drive_speed(drive, speed);
-}
-
-/**
- * scc_configure_drive_for_dma - set up for DMA transfers
- * @drive: drive we are going to set up
- *
- * Set up the drive for DMA, tune the controller and drive as
- * required.
- * If the drive isn't suitable for DMA or we hit other problems
- * then we will drop down to PIO and set up PIO appropriately.
- * (return -1)
- */
-
-static int scc_config_drive_for_dma(ide_drive_t *drive)
-{
- if (ide_tune_dma(drive))
- return 0;
-
- if (ide_use_fast_pio(drive))
- scc_tuneproc(drive, 255);
-
- return -1;
}
/**
@@ -511,7 +472,7 @@ static u8 scc_udma_filter(ide_drive_t *drive)
if ((drive->media != ide_disk) && (mask & 0xE0)) {
printk(KERN_INFO "%s: limit %s to UDMA4\n",
SCC_PATA_NAME, drive->name);
- mask = 0x1F;
+ mask = ATA_UDMA4;
}
return mask;
@@ -577,12 +538,13 @@ static int setup_mmio_scc (struct pci_dev *dev, const char *name)
/**
* init_setup_scc - set up an SCC PATA Controller
* @dev: PCI device
- * @d: IDE PCI device
+ * @d: IDE port info
*
* Perform the initial set up for this device.
*/
-static int __devinit init_setup_scc(struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit init_setup_scc(struct pci_dev *dev,
+ const struct ide_port_info *d)
{
unsigned long ctl_base;
unsigned long dma_base;
@@ -717,47 +679,31 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
hwif->dma_setup = scc_dma_setup;
hwif->ide_dma_end = scc_ide_dma_end;
- hwif->speedproc = scc_tune_chipset;
- hwif->tuneproc = scc_tuneproc;
- hwif->ide_dma_check = scc_config_drive_for_dma;
+ hwif->set_pio_mode = scc_set_pio_mode;
+ hwif->set_dma_mode = scc_set_dma_mode;
hwif->ide_dma_test_irq = scc_dma_test_irq;
hwif->udma_filter = scc_udma_filter;
- hwif->drives[0].autotune = IDE_TUNE_AUTO;
- hwif->drives[1].autotune = IDE_TUNE_AUTO;
-
- if (in_be32((void __iomem *)(hwif->config_data + 0xff0)) & CCKCTRL_ATACLKOEN) {
- hwif->ultra_mask = 0x7f; /* 133MHz */
- } else {
- hwif->ultra_mask = 0x3f; /* 100MHz */
- }
- hwif->mwdma_mask = 0x00;
- hwif->swdma_mask = 0x00;
- hwif->atapi_dma = 1;
+ if (in_be32((void __iomem *)(hwif->config_data + 0xff0)) & CCKCTRL_ATACLKOEN)
+ hwif->ultra_mask = ATA_UDMA6; /* 133MHz */
+ else
+ hwif->ultra_mask = ATA_UDMA5; /* 100MHz */
/* we support 80c cable only. */
hwif->cbl = ATA_CBL_PATA80;
-
- hwif->autodma = 0;
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
}
#define DECLARE_SCC_DEV(name_str) \
{ \
.name = name_str, \
- .init_setup = init_setup_scc, \
.init_iops = init_iops_scc, \
.init_hwif = init_hwif_scc, \
- .autodma = AUTODMA, \
- .bootable = ON_BOARD, \
- .host_flags = IDE_HFLAG_SINGLE, \
+ .host_flags = IDE_HFLAG_SINGLE | \
+ IDE_HFLAG_BOOTABLE, \
.pio_mask = ATA_PIO4, \
}
-static ide_pci_device_t scc_chipsets[] __devinitdata = {
+static const struct ide_port_info scc_chipsets[] __devinitdata = {
/* 0 */ DECLARE_SCC_DEV("sccIDE"),
};
@@ -772,8 +718,7 @@ static ide_pci_device_t scc_chipsets[] __devinitdata = {
static int __devinit scc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_pci_device_t *d = &scc_chipsets[id->driver_data];
- return d->init_setup(dev, d);
+ return init_setup_scc(dev, &scc_chipsets[id->driver_data]);
}
/**
@@ -810,8 +755,8 @@ static void __devexit scc_remove(struct pci_dev *dev)
memset(ports, 0, sizeof(*ports));
}
-static struct pci_device_id scc_pci_tbl[] = {
- { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static const struct pci_device_id scc_pci_tbl[] = {
+ { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, scc_pci_tbl);
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index 9fead2e7d4c..a7280311357 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -97,6 +97,7 @@ static u8 svwks_udma_filter(ide_drive_t *drive)
mode = 2;
switch(mode) {
+ case 3: mask = 0x3f; break;
case 2: mask = 0x1f; break;
case 1: mask = 0x07; break;
default: mask = 0x00; break;
@@ -124,7 +125,7 @@ static u8 svwks_csb_check (struct pci_dev *dev)
return 0;
}
-static void svwks_tune_pio(ide_drive_t *drive, const u8 pio)
+static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
@@ -145,7 +146,7 @@ static void svwks_tune_pio(ide_drive_t *drive, const u8 pio)
}
}
-static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
static const u8 dma_modes[] = { 0x77, 0x21, 0x20 };
@@ -153,23 +154,10 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- u8 speed = ide_rate_filter(drive, xferspeed);
u8 unit = (drive->select.b.unit & 0x01);
u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0;
- if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
- svwks_tune_pio(drive, speed - XFER_PIO_0);
- return ide_config_drive_speed(drive, speed);
- }
-
- /* If we are about to put a disk into UDMA mode we screwed up.
- Our code assumes we never _ever_ do this on an OSB4 */
-
- if(dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4 &&
- drive->media == ide_disk && speed >= XFER_UDMA_0)
- BUG();
-
pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
pci_read_config_byte(dev, 0x54, &ultra_enable);
@@ -199,28 +187,6 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
pci_write_config_byte(dev, 0x54, ultra_enable);
-
- return (ide_config_drive_speed(drive, speed));
-}
-
-static void svwks_tune_drive (ide_drive_t *drive, u8 pio)
-{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- svwks_tune_pio(drive, pio);
- (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
-static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
-{
- drive->init_speed = 0;
-
- if (ide_tune_dma(drive))
- return 0;
-
- if (ide_use_fast_pio(drive))
- svwks_tune_drive(drive, 255);
-
- return -1;
}
static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const char *name)
@@ -387,105 +353,62 @@ static u8 __devinit ata66_svwks(ide_hwif_t *hwif)
static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
{
- if (!hwif->irq)
- hwif->irq = hwif->channel ? 15 : 14;
-
- hwif->tuneproc = &svwks_tune_drive;
- hwif->speedproc = &svwks_tune_chipset;
+ hwif->set_pio_mode = &svwks_set_pio_mode;
+ hwif->set_dma_mode = &svwks_set_dma_mode;
hwif->udma_filter = &svwks_udma_filter;
- hwif->atapi_dma = 1;
-
- if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE)
- hwif->ultra_mask = 0x3f;
-
- hwif->mwdma_mask = 0x07;
-
- hwif->autodma = 0;
-
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
-
if (!hwif->dma_base)
return;
- hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
hwif->cbl = ata66_svwks(hwif);
}
- if (!noautodma)
- hwif->autodma = 1;
-
- hwif->drives[0].autodma = hwif->drives[1].autodma = 1;
}
-static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
-{
- return ide_setup_pci_device(dev, d);
-}
-
-static int __devinit init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
-{
- if (!(PCI_FUNC(dev->devfn) & 1)) {
- d->bootable = NEVER_BOARD;
- if (dev->resource[0].start == 0x01f1)
- d->bootable = ON_BOARD;
- }
-
- if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ||
- dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) &&
- (!(PCI_FUNC(dev->devfn) & 1)))
- d->host_flags |= IDE_HFLAG_SINGLE;
- else
- d->host_flags &= ~IDE_HFLAG_SINGLE;
-
- return ide_setup_pci_device(dev, d);
-}
-
-static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
+static const struct ide_port_info serverworks_chipsets[] __devinitdata = {
{ /* 0 */
.name = "SvrWks OSB4",
- .init_setup = init_setup_svwks,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = 0x00, /* UDMA is problematic on OSB4 */
},{ /* 1 */
.name = "SvrWks CSB5",
- .init_setup = init_setup_svwks,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
},{ /* 2 */
.name = "SvrWks CSB6",
- .init_setup = init_setup_csb6,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
},{ /* 3 */
.name = "SvrWks CSB6",
- .init_setup = init_setup_csb6,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
- .host_flags = IDE_HFLAG_SINGLE,
+ .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE |
+ IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
},{ /* 4 */
.name = "SvrWks HT1000",
- .init_setup = init_setup_svwks,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .autodma = AUTODMA,
- .bootable = ON_BOARD,
- .host_flags = IDE_HFLAG_SINGLE,
+ .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE |
+ IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA5,
}
};
@@ -500,17 +423,29 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- ide_pci_device_t *d = &serverworks_chipsets[id->driver_data];
+ struct ide_port_info d;
+ u8 idx = id->driver_data;
+
+ d = serverworks_chipsets[idx];
+
+ if (idx == 2 || idx == 3) {
+ if ((PCI_FUNC(dev->devfn) & 1) == 0) {
+ if (pci_resource_start(dev, 0) != 0x01f1)
+ d.host_flags &= ~IDE_HFLAG_BOOTABLE;
+ d.host_flags |= IDE_HFLAG_SINGLE;
+ } else
+ d.host_flags &= ~IDE_HFLAG_SINGLE;
+ }
- return d->init_setup(dev, d);
+ return ide_setup_pci_device(dev, &d);
}
-static struct pci_device_id svwks_pci_tbl[] = {
- { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
- { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
- { PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+static const struct pci_device_id svwks_pci_tbl[] = {
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0 },
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 1 },
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2 },
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 3 },
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 4 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, svwks_pci_tbl);
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index 57145767c3d..de820aa58cd 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -29,11 +29,14 @@
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/blkdev.h>
+#include <linux/scatterlist.h>
#include <linux/ioc4.h>
#include <asm/io.h>
#include <linux/ide.h>
+#define DRV_NAME "SGIIOC4"
+
/* IOC4 Specific Definitions */
#define IOC4_CMD_OFFSET 0x100
#define IOC4_CTRL_OFFSET 0x120
@@ -289,15 +292,8 @@ static void sgiioc4_dma_off_quietly(ide_drive_t *drive)
drive->hwif->dma_host_off(drive);
}
-static int sgiioc4_ide_dma_check(ide_drive_t *drive)
+static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
- /* FIXME: check for available DMA modes */
- if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) {
- printk(KERN_WARNING "%s: couldn't set MWDMA2 mode, "
- "using PIO instead\n", drive->name);
- return -1;
- } else
- return 0;
}
/* returns 1 if dma irq issued, 0 otherwise */
@@ -353,7 +349,7 @@ sgiioc4_INB(unsigned long port)
}
/* Creates a dma map for the scatter-gather list entries */
-static void __devinit
+static int __devinit
ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
{
void __iomem *virt_dma_base;
@@ -369,7 +365,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
"ALREADY in use\n",
__FUNCTION__, hwif->name, (void *) dma_base,
(void *) dma_base + num_ports - 1);
- goto dma_alloc_failure;
+ return -1;
}
virt_dma_base = ioremap(dma_base, num_ports);
@@ -395,7 +391,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
if (pad) {
ide_set_hwifdata(hwif, pad);
- return;
+ return 0;
}
pci_free_consistent(hwif->pci_dev,
@@ -413,10 +409,7 @@ dma_pci_alloc_failure:
dma_remap_failure:
release_mem_region(dma_base, num_ports);
-dma_alloc_failure:
- /* Disable DMA because we couldnot allocate any DMA maps */
- hwif->autodma = 0;
- hwif->atapi_dma = 0;
+ return -1;
}
/* Initializes the IOC4 DMA Engine */
@@ -531,7 +524,7 @@ sgiioc4_build_dma_table(ide_drive_t * drive, struct request *rq, int ddir)
}
}
- sg++;
+ sg = sg_next(sg);
i--;
}
@@ -581,14 +574,9 @@ static void __devinit
ide_init_sgiioc4(ide_hwif_t * hwif)
{
hwif->mmio = 1;
- hwif->autodma = 1;
- hwif->atapi_dma = 1;
- hwif->ultra_mask = 0x0; /* Disable Ultra DMA */
- hwif->mwdma_mask = 0x2; /* Multimode-2 DMA */
- hwif->swdma_mask = 0x2;
hwif->pio_mask = 0x00;
- hwif->tuneproc = NULL; /* Sets timing for PIO mode */
- hwif->speedproc = NULL; /* Sets timing for DMA &/or PIO modes */
+ hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */
+ hwif->set_dma_mode = &sgiioc4_set_dma_mode;
hwif->selectproc = NULL;/* Use the default routine to select drive */
hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */
hwif->pre_reset = NULL; /* No HBA specific pre_set needed */
@@ -599,10 +587,16 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
hwif->quirkproc = NULL;
hwif->busproc = NULL;
+ hwif->INB = &sgiioc4_INB;
+
+ if (hwif->dma_base == 0)
+ return;
+
+ hwif->mwdma_mask = ATA_MWDMA2_ONLY;
+
hwif->dma_setup = &sgiioc4_ide_dma_setup;
hwif->dma_start = &sgiioc4_ide_dma_start;
hwif->ide_dma_end = &sgiioc4_ide_dma_end;
- hwif->ide_dma_check = &sgiioc4_ide_dma_check;
hwif->ide_dma_on = &sgiioc4_ide_dma_on;
hwif->dma_off_quietly = &sgiioc4_dma_off_quietly;
hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq;
@@ -610,18 +604,17 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
hwif->dma_host_off = &sgiioc4_dma_host_off;
hwif->dma_lost_irq = &sgiioc4_dma_lost_irq;
hwif->dma_timeout = &ide_dma_timeout;
-
- hwif->INB = &sgiioc4_INB;
}
static int __devinit
-sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
+sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
{
unsigned long cmd_base, dma_base, irqport;
unsigned long bar0, cmd_phys_base, ctl;
void __iomem *virt_base;
ide_hwif_t *hwif;
int h;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
/*
* Find an empty HWIF; if none available, return -ENOMEM.
@@ -632,7 +625,8 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
break;
}
if (h == MAX_HWIFS) {
- printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", d->name);
+ printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n",
+ DRV_NAME);
return -ENOMEM;
}
@@ -641,7 +635,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
virt_base = ioremap(bar0, pci_resource_len(dev, 0));
if (virt_base == NULL) {
printk(KERN_ERR "%s: Unable to remap BAR 0 address: 0x%lx\n",
- d->name, bar0);
+ DRV_NAME, bar0);
return -ENOMEM;
}
cmd_base = (unsigned long) virt_base + IOC4_CMD_OFFSET;
@@ -661,10 +655,12 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
}
if (hwif->io_ports[IDE_DATA_OFFSET] != cmd_base) {
+ hw_regs_t hw;
+
/* Initialize the IO registers */
- sgiioc4_init_hwif_ports(&hwif->hw, cmd_base, ctl, irqport);
- memcpy(hwif->io_ports, hwif->hw.io_ports,
- sizeof (hwif->io_ports));
+ memset(&hw, 0, sizeof(hw));
+ sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport);
+ memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
}
@@ -672,7 +668,6 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
hwif->chipset = ide_pci;
hwif->pci_dev = dev;
hwif->channel = 0; /* Single Channel chip */
- hwif->cds = (struct ide_pci_device_s *) d;
hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */
/* The IOC4 uses MMIO rather than Port IO. */
@@ -681,56 +676,41 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
/* Initializing chipset IRQ Registers */
writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4));
+ if (dma_base == 0 || ide_dma_sgiioc4(hwif, dma_base))
+ printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n",
+ hwif->name, DRV_NAME);
+
ide_init_sgiioc4(hwif);
- if (dma_base)
- ide_dma_sgiioc4(hwif, dma_base);
- else
- printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n",
- hwif->name, d->name);
+ idx[0] = hwif->index;
- if (probe_hwif_init(hwif))
+ if (ide_device_add(idx))
return -EIO;
- /* Create /proc/ide entries */
- ide_proc_register_port(hwif);
-
return 0;
}
static unsigned int __devinit
-pci_init_sgiioc4(struct pci_dev *dev, ide_pci_device_t * d)
+pci_init_sgiioc4(struct pci_dev *dev)
{
- unsigned int class_rev;
int ret;
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n",
- d->name, pci_name(dev), class_rev);
- if (class_rev < IOC4_SUPPORTED_FIRMWARE_REV) {
+ DRV_NAME, pci_name(dev), dev->revision);
+
+ if (dev->revision < IOC4_SUPPORTED_FIRMWARE_REV) {
printk(KERN_ERR "Skipping %s IDE controller in slot %s: "
- "firmware is obsolete - please upgrade to revision"
- "46 or higher\n", d->name, pci_name(dev));
+ "firmware is obsolete - please upgrade to "
+ "revision46 or higher\n",
+ DRV_NAME, pci_name(dev));
ret = -EAGAIN;
goto out;
}
- ret = sgiioc4_ide_setup_pci_device(dev, d);
+ ret = sgiioc4_ide_setup_pci_device(dev);
out:
return ret;
}
-static ide_pci_device_t sgiioc4_chipset __devinitdata = {
- /* Channel 0 */
- .name = "SGIIOC4",
- .init_hwif = ide_init_sgiioc4,
- .init_dma = ide_dma_sgiioc4,
- .autodma = AUTODMA,
- /* SGI IOC4 doesn't have enablebits. */
- .bootable = ON_BOARD,
- .host_flags = IDE_HFLAG_SINGLE,
-};
-
int
ioc4_ide_attach_one(struct ioc4_driver_data *idd)
{
@@ -740,7 +720,7 @@ ioc4_ide_attach_one(struct ioc4_driver_data *idd)
if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
return 0;
- return pci_init_sgiioc4(idd->idd_pdev, &sgiioc4_chipset);
+ return pci_init_sgiioc4(idd->idd_pdev);
}
static struct ioc4_submodule ioc4_ide_submodule = {
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 50f6d172ef7..6d99441c605 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/siimage.c Version 1.15 Jun 29 2007
+ * linux/drivers/ide/pci/siimage.c Version 1.18 Oct 18 2007
*
* Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2003 Red Hat <alan@redhat.com>
@@ -26,7 +26,7 @@
*
* If you have strange problems with nVidia chipset systems please
* see the SI support documentation and update your system BIOS
- * if neccessary
+ * if necessary
*
* The Dell DRAC4 has some interesting features including effectively hot
* unplugging/replugging the virtual CD interface when the DRAC is reset.
@@ -57,8 +57,8 @@
static int pdev_is_sata(struct pci_dev *pdev)
{
- switch(pdev->device)
- {
+#ifdef CONFIG_BLK_DEV_IDE_SATA
+ switch(pdev->device) {
case PCI_DEVICE_ID_SII_3112:
case PCI_DEVICE_ID_SII_1210SA:
return 1;
@@ -66,9 +66,10 @@ static int pdev_is_sata(struct pci_dev *pdev)
return 0;
}
BUG();
+#endif
return 0;
}
-
+
/**
* is_sata - check if hwif is SATA
* @hwif: interface to check
@@ -136,7 +137,7 @@ static inline unsigned long siimage_seldev(ide_drive_t *drive, int r)
* SI3112 SATA controller life is a bit simpler.
*/
-static u8 sil_udma_filter(ide_drive_t *drive)
+static u8 sil_pata_udma_filter(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
unsigned long base = (unsigned long) hwif->hwif_data;
@@ -147,45 +148,50 @@ static u8 sil_udma_filter(ide_drive_t *drive)
else
pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
- if (is_sata(hwif)) {
- mask = strstr(drive->id->model, "Maxtor") ? 0x3f : 0x7f;
- goto out;
- }
-
if ((scsc & 0x30) == 0x10) /* 133 */
- mask = 0x7f;
+ mask = ATA_UDMA6;
else if ((scsc & 0x30) == 0x20) /* 2xPCI */
- mask = 0x7f;
+ mask = ATA_UDMA6;
else if ((scsc & 0x30) == 0x00) /* 100 */
- mask = 0x3f;
+ mask = ATA_UDMA5;
else /* Disabled ? */
BUG();
-out:
+
return mask;
}
+static u8 sil_sata_udma_filter(ide_drive_t *drive)
+{
+ return strstr(drive->id->model, "Maxtor") ? ATA_UDMA5 : ATA_UDMA6;
+}
+
/**
- * sil_tune_pio - tune a drive
- * @drive: drive to tune
- * @pio: the desired PIO mode
+ * sil_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
* Load the timing settings for this device mode into the
* controller. If we are in PIO mode 3 or 4 turn on IORDY
* monitoring (bit 9). The TF timing is bits 31:16
*/
-static void sil_tune_pio(ide_drive_t *drive, u8 pio)
+static void sil_set_pio_mode(ide_drive_t *drive, u8 pio)
{
const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
ide_hwif_t *hwif = HWIF(drive);
- ide_drive_t *pair = &hwif->drives[drive->dn ^ 1];
+ ide_drive_t *pair = ide_get_paired_drive(drive);
u32 speedt = 0;
u16 speedp = 0;
unsigned long addr = siimage_seldev(drive, 0x04);
unsigned long tfaddr = siimage_selreg(hwif, 0x02);
+ unsigned long base = (unsigned long)hwif->hwif_data;
u8 tf_pio = pio;
+ u8 addr_mask = hwif->channel ? (hwif->mmio ? 0xF4 : 0x84)
+ : (hwif->mmio ? 0xB4 : 0x80);
+ u8 mode = 0;
+ u8 unit = drive->select.b.unit;
/* trim *taskfile* PIO to the slowest of the master/slave */
if (pair->present) {
@@ -207,6 +213,11 @@ static void sil_tune_pio(ide_drive_t *drive, u8 pio)
hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2);
else
hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2);
+
+ mode = hwif->INB(base + addr_mask);
+ mode &= ~(unit ? 0x30 : 0x03);
+ mode |= (unit ? 0x10 : 0x01);
+ hwif->OUTB(mode, base + addr_mask);
} else {
pci_write_config_word(hwif->pci_dev, addr, speedp);
pci_write_config_word(hwif->pci_dev, tfaddr, speedt);
@@ -216,27 +227,23 @@ static void sil_tune_pio(ide_drive_t *drive, u8 pio)
if (pio > 2)
speedp |= 0x200;
pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp);
- }
-}
-static void sil_tuneproc(ide_drive_t *drive, u8 pio)
-{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- sil_tune_pio(drive, pio);
- (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+ pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);
+ mode &= ~(unit ? 0x30 : 0x03);
+ mode |= (unit ? 0x10 : 0x01);
+ pci_write_config_byte(hwif->pci_dev, addr_mask, mode);
+ }
}
/**
- * siimage_tune_chipset - set controller timings
- * @drive: Drive to set up
- * @xferspeed: speed we want to achieve
+ * sil_set_dma_mode - set host controller for DMA mode
+ * @drive: drive
+ * @speed: DMA mode
*
- * Tune the SII chipset for the desired mode. If we can't achieve
- * the desired mode then tune for a lower one, but ultimately
- * make the thing work.
+ * Tune the SiI chipset for the desired DMA mode.
*/
-
-static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
+
+static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
u8 ultra6[] = { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
u8 ultra5[] = { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
@@ -245,7 +252,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
ide_hwif_t *hwif = HWIF(drive);
u16 ultra = 0, multi = 0;
u8 mode = 0, unit = drive->select.b.unit;
- u8 speed = ide_rate_filter(drive, xferspeed);
unsigned long base = (unsigned long)hwif->hwif_data;
u8 scsc = 0, addr_mask = ((hwif->channel) ?
((hwif->mmio) ? 0xF4 : 0x84) :
@@ -273,14 +279,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
scsc = is_sata(hwif) ? 1 : scsc;
switch(speed) {
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- sil_tune_pio(drive, speed - XFER_PIO_0);
- mode |= ((unit) ? 0x10 : 0x01);
- break;
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_MW_DMA_0:
@@ -300,7 +298,7 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
mode |= ((unit) ? 0x30 : 0x03);
break;
default:
- return 1;
+ return;
}
if (hwif->mmio) {
@@ -312,28 +310,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
pci_write_config_word(hwif->pci_dev, ma, multi);
pci_write_config_word(hwif->pci_dev, ua, ultra);
}
- return (ide_config_drive_speed(drive, speed));
-}
-
-/**
- * siimage_configure_drive_for_dma - set up for DMA transfers
- * @drive: drive we are going to set up
- *
- * Set up the drive for DMA, tune the controller and drive as
- * required. If the drive isn't suitable for DMA or we hit
- * other problems then we will drop down to PIO and set up
- * PIO appropriately
- */
-
-static int siimage_config_drive_for_dma (ide_drive_t *drive)
-{
- if (ide_tune_dma(drive))
- return 0;
-
- if (ide_use_fast_pio(drive))
- sil_tuneproc(drive, 255);
-
- return -1;
}
/* returns 1 if dma irq issued, 0 otherwise */
@@ -365,10 +341,11 @@ static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
- unsigned long base = (unsigned long)hwif->hwif_data;
unsigned long addr = siimage_selreg(hwif, 0x1);
if (SATA_ERROR_REG) {
+ unsigned long base = (unsigned long)hwif->hwif_data;
+
u32 ext_stat = readl((void __iomem *)(base + 0x10));
u8 watchdog = 0;
if (ext_stat & ((hwif->channel) ? 0x40 : 0x10)) {
@@ -401,7 +378,7 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
}
/**
- * siimage_busproc - bus isolation ioctl
+ * sil_sata_busproc - bus isolation IOCTL
* @drive: drive to isolate/restore
* @state: bus state to set
*
@@ -409,8 +386,8 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
* SATA controller the work required is quite limited, we
* just have to clean up the statistics
*/
-
-static int siimage_busproc (ide_drive_t * drive, int state)
+
+static int sil_sata_busproc(ide_drive_t * drive, int state)
{
ide_hwif_t *hwif = HWIF(drive);
u32 stat_config = 0;
@@ -442,14 +419,14 @@ static int siimage_busproc (ide_drive_t * drive, int state)
}
/**
- * siimage_reset_poll - wait for sata reset
+ * sil_sata_reset_poll - wait for SATA reset
* @drive: drive we are resetting
*
* Poll the SATA phy and see whether it has come back from the dead
* yet.
*/
-
-static int siimage_reset_poll (ide_drive_t *drive)
+
+static int sil_sata_reset_poll(ide_drive_t *drive)
{
if (SATA_STATUS_REG) {
ide_hwif_t *hwif = HWIF(drive);
@@ -461,27 +438,22 @@ static int siimage_reset_poll (ide_drive_t *drive)
HWGROUP(drive)->polling = 0;
return ide_started;
}
- return 0;
- } else {
- return 0;
}
+
+ return 0;
}
/**
- * siimage_pre_reset - reset hook
+ * sil_sata_pre_reset - reset hook
* @drive: IDE device being reset
*
* For the SATA devices we need to handle recalibration/geometry
* differently
*/
-
-static void siimage_pre_reset (ide_drive_t *drive)
-{
- if (drive->media != ide_disk)
- return;
- if (is_sata(HWIF(drive)))
- {
+static void sil_sata_pre_reset(ide_drive_t *drive)
+{
+ if (drive->media == ide_disk) {
drive->special.b.set_geometry = 0;
drive->special.b.recalibrate = 0;
}
@@ -527,7 +499,6 @@ static void siimage_reset (ide_drive_t *drive)
drive->failures++;
}
}
-
}
/**
@@ -665,13 +636,9 @@ static unsigned int setup_mmio_siimage (struct pci_dev *dev, const char *name)
static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const char *name)
{
- u32 class_rev = 0;
- u8 tmpbyte = 0;
- u8 BA5_EN = 0;
+ u8 rev = dev->revision, tmpbyte = 0, BA5_EN = 0;
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255);
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, rev ? 1 : 255);
pci_read_config_byte(dev, 0x8A, &BA5_EN);
if ((BA5_EN & 0x01) || (pci_resource_start(dev, 5))) {
@@ -787,16 +754,11 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
hwif->sata_misc[SATA_IEN_OFFSET] = base + 0x148;
}
- hw.irq = hwif->pci_dev->irq;
+ memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
- memcpy(&hwif->hw, &hw, sizeof(hw));
- memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
+ hwif->irq = dev->irq;
- hwif->irq = hw.irq;
-
- base = (unsigned long) addr;
-
- hwif->dma_base = base + (ch ? 0x08 : 0x00);
+ hwif->dma_base = (unsigned long)addr + (ch ? 0x08 : 0x00);
hwif->mmio = 1;
}
@@ -850,19 +812,14 @@ static void __devinit siimage_fixup(ide_hwif_t *hwif)
static void __devinit init_iops_siimage(ide_hwif_t *hwif)
{
- struct pci_dev *dev = hwif->pci_dev;
- u32 class_rev = 0;
-
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
-
hwif->hwif_data = NULL;
/* Pessimal until we finish probing */
hwif->rqsize = 15;
- if (pci_get_drvdata(dev) == NULL)
+ if (pci_get_drvdata(hwif->pci_dev) == NULL)
return;
+
init_mmio_iops_siimage(hwif);
}
@@ -898,38 +855,32 @@ static u8 __devinit ata66_siimage(ide_hwif_t *hwif)
static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
{
- hwif->autodma = 0;
-
+ u8 sata = is_sata(hwif);
+
hwif->resetproc = &siimage_reset;
- hwif->speedproc = &siimage_tune_chipset;
- hwif->tuneproc = &sil_tuneproc;
- hwif->reset_poll = &siimage_reset_poll;
- hwif->pre_reset = &siimage_pre_reset;
- hwif->udma_filter = &sil_udma_filter;
+ hwif->set_pio_mode = &sil_set_pio_mode;
+ hwif->set_dma_mode = &sil_set_dma_mode;
- if(is_sata(hwif)) {
+ if (sata) {
static int first = 1;
- hwif->busproc = &siimage_busproc;
+ hwif->busproc = &sil_sata_busproc;
+ hwif->reset_poll = &sil_sata_reset_poll;
+ hwif->pre_reset = &sil_sata_pre_reset;
+ hwif->udma_filter = &sil_sata_udma_filter;
if (first) {
printk(KERN_INFO "siimage: For full SATA support you should use the libata sata_sil module.\n");
first = 0;
}
- }
-
- hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+ } else
+ hwif->udma_filter = &sil_pata_udma_filter;
if (hwif->dma_base == 0)
return;
- hwif->ultra_mask = 0x7f;
- hwif->mwdma_mask = 0x07;
-
- if (!is_sata(hwif))
- hwif->atapi_dma = 1;
-
- hwif->ide_dma_check = &siimage_config_drive_for_dma;
+ if (sata)
+ hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
hwif->cbl = ata66_siimage(hwif);
@@ -939,15 +890,6 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
} else {
hwif->ide_dma_test_irq = & siimage_io_ide_dma_test_irq;
}
-
- /*
- * The BIOS often doesn't set up DMA on this controller
- * so we always do it.
- */
-
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
}
#define DECLARE_SII_DEV(name_str) \
@@ -957,12 +899,13 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
.init_iops = init_iops_siimage, \
.init_hwif = init_hwif_siimage, \
.fixup = siimage_fixup, \
- .autodma = AUTODMA, \
- .bootable = ON_BOARD, \
+ .host_flags = IDE_HFLAG_BOOTABLE, \
.pio_mask = ATA_PIO4, \
+ .mwdma_mask = ATA_MWDMA2, \
+ .udma_mask = ATA_UDMA6, \
}
-static ide_pci_device_t siimage_chipsets[] __devinitdata = {
+static const struct ide_port_info siimage_chipsets[] __devinitdata = {
/* 0 */ DECLARE_SII_DEV("SiI680"),
/* 1 */ DECLARE_SII_DEV("SiI3112 Serial ATA"),
/* 2 */ DECLARE_SII_DEV("Adaptec AAR-1210SA")
@@ -982,11 +925,11 @@ static int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_devi
return ide_setup_pci_device(dev, &siimage_chipsets[id->driver_data]);
}
-static struct pci_device_id siimage_pci_tbl[] = {
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static const struct pci_device_id siimage_pci_tbl[] = {
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), 0 },
#ifdef CONFIG_BLK_DEV_IDE_SATA
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_3112), 1 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_1210SA), 2 },
#endif
{ 0, },
};
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 26f24802d3e..f6e2ab3dd16 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/sis5513.c Version 0.25 Jun 10, 2007
+ * linux/drivers/ide/pci/sis5513.c Version 0.31 Aug 9, 2007
*
* Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
@@ -65,8 +65,6 @@
#include "ide-timing.h"
-#define DISPLAY_SIS_TIMINGS
-
/* registers layout and init values are chipset family dependant */
#define ATA_16 0x01
@@ -193,378 +191,125 @@ static char* chipset_capability[] = {
"ATA 133 (1st gen)", "ATA 133 (2nd gen)"
};
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-
-static u8 sis_proc = 0;
+/*
+ * Configuration functions
+ */
-static struct pci_dev *bmide_dev;
+static u8 sis_ata133_get_base(ide_drive_t *drive)
+{
+ struct pci_dev *dev = drive->hwif->pci_dev;
+ u32 reg54 = 0;
-static char* cable_type[] = {
- "80 pins",
- "40 pins"
-};
+ pci_read_config_dword(dev, 0x54, &reg54);
-static char* recovery_time[] ={
- "12 PCICLK", "1 PCICLK",
- "2 PCICLK", "3 PCICLK",
- "4 PCICLK", "5 PCICLCK",
- "6 PCICLK", "7 PCICLCK",
- "8 PCICLK", "9 PCICLCK",
- "10 PCICLK", "11 PCICLK",
- "13 PCICLK", "14 PCICLK",
- "15 PCICLK", "15 PCICLK"
-};
+ return ((reg54 & 0x40000000) ? 0x70 : 0x40) + drive->dn * 4;
+}
-static char* active_time[] = {
- "8 PCICLK", "1 PCICLCK",
- "2 PCICLK", "3 PCICLK",
- "4 PCICLK", "5 PCICLK",
- "6 PCICLK", "12 PCICLK"
-};
+static void sis_ata16_program_timings(ide_drive_t *drive, const u8 mode)
+{
+ struct pci_dev *dev = drive->hwif->pci_dev;
+ u16 t1 = 0;
+ u8 drive_pci = 0x40 + drive->dn * 2;
-static char* cycle_time[] = {
- "Reserved", "2 CLK",
- "3 CLK", "4 CLK",
- "5 CLK", "6 CLK",
- "7 CLK", "8 CLK",
- "9 CLK", "10 CLK",
- "11 CLK", "12 CLK",
- "13 CLK", "14 CLK",
- "15 CLK", "16 CLK"
-};
+ const u16 pio_timings[] = { 0x000, 0x607, 0x404, 0x303, 0x301 };
+ const u16 mwdma_timings[] = { 0x008, 0x302, 0x301 };
-/* Generic add master or slave info function */
-static char* get_drives_info (char *buffer, u8 pos)
-{
- u8 reg00, reg01, reg10, reg11; /* timing registers */
- u32 regdw0, regdw1;
- char* p = buffer;
-
-/* Postwrite/Prefetch */
- if (chipset_family < ATA_133) {
- pci_read_config_byte(bmide_dev, 0x4b, &reg00);
- p += sprintf(p, "Drive %d: Postwrite %s \t \t Postwrite %s\n",
- pos, (reg00 & (0x10 << pos)) ? "Enabled" : "Disabled",
- (reg00 & (0x40 << pos)) ? "Enabled" : "Disabled");
- p += sprintf(p, " Prefetch %s \t \t Prefetch %s\n",
- (reg00 & (0x01 << pos)) ? "Enabled" : "Disabled",
- (reg00 & (0x04 << pos)) ? "Enabled" : "Disabled");
- pci_read_config_byte(bmide_dev, 0x40+2*pos, &reg00);
- pci_read_config_byte(bmide_dev, 0x41+2*pos, &reg01);
- pci_read_config_byte(bmide_dev, 0x44+2*pos, &reg10);
- pci_read_config_byte(bmide_dev, 0x45+2*pos, &reg11);
- } else {
- u32 reg54h;
- u8 drive_pci = 0x40;
- pci_read_config_dword(bmide_dev, 0x54, &reg54h);
- if (reg54h & 0x40000000) {
- // Configuration space remapped to 0x70
- drive_pci = 0x70;
- }
- pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+4*pos, &regdw0);
- pci_read_config_dword(bmide_dev, (unsigned long)drive_pci+4*pos+8, &regdw1);
+ pci_read_config_word(dev, drive_pci, &t1);
- p += sprintf(p, "Drive %d:\n", pos);
- }
+ /* clear active/recovery timings */
+ t1 &= ~0x070f;
+ if (mode >= XFER_MW_DMA_0) {
+ if (chipset_family > ATA_16)
+ t1 &= ~0x8000; /* disable UDMA */
+ t1 |= mwdma_timings[mode - XFER_MW_DMA_0];
+ } else
+ t1 |= pio_timings[mode - XFER_PIO_0];
+ pci_write_config_word(dev, drive_pci, t1);
+}
-/* UDMA */
- if (chipset_family >= ATA_133) {
- p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n",
- (regdw0 & 0x04) ? "Enabled" : "Disabled",
- (regdw1 & 0x04) ? "Enabled" : "Disabled");
- p += sprintf(p, " UDMA Cycle Time %s \t UDMA Cycle Time %s\n",
- cycle_time[(regdw0 & 0xF0) >> 4],
- cycle_time[(regdw1 & 0xF0) >> 4]);
- } else if (chipset_family >= ATA_33) {
- p += sprintf(p, " UDMA %s \t \t \t UDMA %s\n",
- (reg01 & 0x80) ? "Enabled" : "Disabled",
- (reg11 & 0x80) ? "Enabled" : "Disabled");
-
- p += sprintf(p, " UDMA Cycle Time ");
- switch(chipset_family) {
- case ATA_33: p += sprintf(p, cycle_time[(reg01 & 0x60) >> 5]); break;
- case ATA_66:
- case ATA_100a: p += sprintf(p, cycle_time[(reg01 & 0x70) >> 4]); break;
- case ATA_100:
- case ATA_133a: p += sprintf(p, cycle_time[reg01 & 0x0F]); break;
- default: p += sprintf(p, "?"); break;
- }
- p += sprintf(p, " \t UDMA Cycle Time ");
- switch(chipset_family) {
- case ATA_33: p += sprintf(p, cycle_time[(reg11 & 0x60) >> 5]); break;
- case ATA_66:
- case ATA_100a: p += sprintf(p, cycle_time[(reg11 & 0x70) >> 4]); break;
- case ATA_100:
- case ATA_133a: p += sprintf(p, cycle_time[reg11 & 0x0F]); break;
- default: p += sprintf(p, "?"); break;
- }
- p += sprintf(p, "\n");
- }
+static void sis_ata100_program_timings(ide_drive_t *drive, const u8 mode)
+{
+ struct pci_dev *dev = drive->hwif->pci_dev;
+ u8 t1, drive_pci = 0x40 + drive->dn * 2;
+ /* timing bits: 7:4 active 3:0 recovery */
+ const u8 pio_timings[] = { 0x00, 0x67, 0x44, 0x33, 0x31 };
+ const u8 mwdma_timings[] = { 0x08, 0x32, 0x31 };
- if (chipset_family < ATA_133) { /* else case TODO */
+ if (mode >= XFER_MW_DMA_0) {
+ u8 t2 = 0;
-/* Data Active */
- p += sprintf(p, " Data Active Time ");
- switch(chipset_family) {
- case ATA_16: /* confirmed */
- case ATA_33:
- case ATA_66:
- case ATA_100a: p += sprintf(p, active_time[reg01 & 0x07]); break;
- case ATA_100:
- case ATA_133a: p += sprintf(p, active_time[(reg00 & 0x70) >> 4]); break;
- default: p += sprintf(p, "?"); break;
- }
- p += sprintf(p, " \t Data Active Time ");
- switch(chipset_family) {
- case ATA_16:
- case ATA_33:
- case ATA_66:
- case ATA_100a: p += sprintf(p, active_time[reg11 & 0x07]); break;
- case ATA_100:
- case ATA_133a: p += sprintf(p, active_time[(reg10 & 0x70) >> 4]); break;
- default: p += sprintf(p, "?"); break;
- }
- p += sprintf(p, "\n");
+ pci_read_config_byte(dev, drive_pci, &t2);
+ t2 &= ~0x80; /* disable UDMA */
+ pci_write_config_byte(dev, drive_pci, t2);
-/* Data Recovery */
- /* warning: may need (reg&0x07) for pre ATA66 chips */
- p += sprintf(p, " Data Recovery Time %s \t Data Recovery Time %s\n",
- recovery_time[reg00 & 0x0f], recovery_time[reg10 & 0x0f]);
- }
+ t1 = mwdma_timings[mode - XFER_MW_DMA_0];
+ } else
+ t1 = pio_timings[mode - XFER_PIO_0];
- return p;
+ pci_write_config_byte(dev, drive_pci + 1, t1);
}
-static char* get_masters_info(char* buffer)
+static void sis_ata133_program_timings(ide_drive_t *drive, const u8 mode)
{
- return get_drives_info(buffer, 0);
+ struct pci_dev *dev = drive->hwif->pci_dev;
+ u32 t1 = 0;
+ u8 drive_pci = sis_ata133_get_base(drive), clk, idx;
+
+ pci_read_config_dword(dev, drive_pci, &t1);
+
+ t1 &= 0xc0c00fff;
+ clk = (t1 & 0x08) ? ATA_133 : ATA_100;
+ if (mode >= XFER_MW_DMA_0) {
+ t1 &= ~0x04; /* disable UDMA */
+ idx = mode - XFER_MW_DMA_0 + 5;
+ } else
+ idx = mode - XFER_PIO_0;
+ t1 |= ini_time_value[clk][idx] << 12;
+ t1 |= act_time_value[clk][idx] << 16;
+ t1 |= rco_time_value[clk][idx] << 24;
+
+ pci_write_config_dword(dev, drive_pci, t1);
}
-static char* get_slaves_info(char* buffer)
+static void sis_program_timings(ide_drive_t *drive, const u8 mode)
{
- return get_drives_info(buffer, 1);
+ if (chipset_family < ATA_100) /* ATA_16/33/66/100a */
+ sis_ata16_program_timings(drive, mode);
+ else if (chipset_family < ATA_133) /* ATA_100/133a */
+ sis_ata100_program_timings(drive, mode);
+ else /* ATA_133 */
+ sis_ata133_program_timings(drive, mode);
}
-/* Main get_info, called on /proc/ide/sis reads */
-static int sis_get_info (char *buffer, char **addr, off_t offset, int count)
-{
- char *p = buffer;
- int len;
- u8 reg;
- u16 reg2, reg3;
-
- p += sprintf(p, "\nSiS 5513 ");
- switch(chipset_family) {
- case ATA_16: p += sprintf(p, "DMA 16"); break;
- case ATA_33: p += sprintf(p, "Ultra 33"); break;
- case ATA_66: p += sprintf(p, "Ultra 66"); break;
- case ATA_100a:
- case ATA_100: p += sprintf(p, "Ultra 100"); break;
- case ATA_133a:
- case ATA_133: p += sprintf(p, "Ultra 133"); break;
- default: p+= sprintf(p, "Unknown???"); break;
- }
- p += sprintf(p, " chipset\n");
- p += sprintf(p, "--------------- Primary Channel "
- "---------------- Secondary Channel "
- "-------------\n");
-
-/* Status */
- pci_read_config_byte(bmide_dev, 0x4a, &reg);
- if (chipset_family == ATA_133) {
- pci_read_config_word(bmide_dev, 0x50, &reg2);
- pci_read_config_word(bmide_dev, 0x52, &reg3);
- }
- p += sprintf(p, "Channel Status: ");
- if (chipset_family < ATA_66) {
- p += sprintf(p, "%s \t \t \t \t %s\n",
- (reg & 0x04) ? "On" : "Off",
- (reg & 0x02) ? "On" : "Off");
- } else if (chipset_family < ATA_133) {
- p += sprintf(p, "%s \t \t \t \t %s \n",
- (reg & 0x02) ? "On" : "Off",
- (reg & 0x04) ? "On" : "Off");
- } else { /* ATA_133 */
- p += sprintf(p, "%s \t \t \t \t %s \n",
- (reg2 & 0x02) ? "On" : "Off",
- (reg3 & 0x02) ? "On" : "Off");
- }
-
-/* Operation Mode */
- pci_read_config_byte(bmide_dev, 0x09, &reg);
- p += sprintf(p, "Operation Mode: %s \t \t \t %s \n",
- (reg & 0x01) ? "Native" : "Compatible",
- (reg & 0x04) ? "Native" : "Compatible");
-
-/* 80-pin cable ? */
- if (chipset_family >= ATA_133) {
- p += sprintf(p, "Cable Type: %s \t \t \t %s\n",
- (reg2 & 0x01) ? cable_type[1] : cable_type[0],
- (reg3 & 0x01) ? cable_type[1] : cable_type[0]);
- } else if (chipset_family > ATA_33) {
- pci_read_config_byte(bmide_dev, 0x48, &reg);
- p += sprintf(p, "Cable Type: %s \t \t \t %s\n",
- (reg & 0x10) ? cable_type[1] : cable_type[0],
- (reg & 0x20) ? cable_type[1] : cable_type[0]);
- }
-
-/* Prefetch Count */
- if (chipset_family < ATA_133) {
- pci_read_config_word(bmide_dev, 0x4c, &reg2);
- pci_read_config_word(bmide_dev, 0x4e, &reg3);
- p += sprintf(p, "Prefetch Count: %d \t \t \t \t %d\n",
- reg2, reg3);
- }
-
- p = get_masters_info(p);
- p = get_slaves_info(p);
-
- len = (p - buffer) - offset;
- *addr = buffer + offset;
-
- return len > count ? count : len;
-}
-#endif /* defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
-
-/*
- * Configuration functions
- */
-/* Enables per-drive prefetch and postwrite */
static void config_drive_art_rwp (ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
-
u8 reg4bh = 0;
- u8 rw_prefetch = (0x11 << drive->dn);
+ u8 rw_prefetch = 0;
- if (drive->media != ide_disk)
- return;
pci_read_config_byte(dev, 0x4b, &reg4bh);
- if ((reg4bh & rw_prefetch) != rw_prefetch)
+ if (drive->media == ide_disk)
+ rw_prefetch = 0x11 << drive->dn;
+
+ if ((reg4bh & (0x11 << drive->dn)) != rw_prefetch)
pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
}
-/* Set per-drive active and recovery time */
-static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
+static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
-
- u8 drive_pci, test1, test2;
-
config_drive_art_rwp(drive);
-
- /* In pre ATA_133 case, drives sit at 0x40 + 4*drive->dn */
- drive_pci = 0x40;
- /* In SiS962 case drives sit at (0x40 or 0x70) + 8*drive->dn) */
- if (chipset_family >= ATA_133) {
- u32 reg54h;
- pci_read_config_dword(dev, 0x54, &reg54h);
- if (reg54h & 0x40000000) drive_pci = 0x70;
- drive_pci += ((drive->dn)*0x4);
- } else {
- drive_pci += ((drive->dn)*0x2);
- }
-
- /* register layout changed with newer ATA100 chips */
- if (chipset_family < ATA_100) {
- pci_read_config_byte(dev, drive_pci, &test1);
- pci_read_config_byte(dev, drive_pci+1, &test2);
-
- /* Clear active and recovery timings */
- test1 &= ~0x0F;
- test2 &= ~0x07;
-
- switch(pio) {
- case 4: test1 |= 0x01; test2 |= 0x03; break;
- case 3: test1 |= 0x03; test2 |= 0x03; break;
- case 2: test1 |= 0x04; test2 |= 0x04; break;
- case 1: test1 |= 0x07; test2 |= 0x06; break;
- case 0: /* PIO0: register setting == X000 */
- default: break;
- }
- pci_write_config_byte(dev, drive_pci, test1);
- pci_write_config_byte(dev, drive_pci+1, test2);
- } else if (chipset_family < ATA_133) {
- switch(pio) { /* active recovery
- v v */
- case 4: test1 = 0x30|0x01; break;
- case 3: test1 = 0x30|0x03; break;
- case 2: test1 = 0x40|0x04; break;
- case 1: test1 = 0x60|0x07; break;
- case 0: test1 = 0x00; break;
- default: break;
- }
- pci_write_config_byte(dev, drive_pci, test1);
- } else { /* ATA_133 */
- u32 test3;
- pci_read_config_dword(dev, drive_pci, &test3);
- test3 &= 0xc0c00fff;
- if (test3 & 0x08) {
- test3 |= ini_time_value[ATA_133][pio] << 12;
- test3 |= act_time_value[ATA_133][pio] << 16;
- test3 |= rco_time_value[ATA_133][pio] << 24;
- } else {
- test3 |= ini_time_value[ATA_100][pio] << 12;
- test3 |= act_time_value[ATA_100][pio] << 16;
- test3 |= rco_time_value[ATA_100][pio] << 24;
- }
- pci_write_config_dword(dev, drive_pci, test3);
- }
-}
-
-static int sis5513_tune_drive(ide_drive_t *drive, u8 pio)
-{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- config_art_rwp_pio(drive, pio);
- return ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
-static void sis5513_tuneproc(ide_drive_t *drive, u8 pio)
-{
- (void)sis5513_tune_drive(drive, pio);
+ sis_program_timings(drive, XFER_PIO_0 + pio);
}
-static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- u8 drive_pci, reg, speed;
- u32 regdw;
-
- speed = ide_rate_filter(drive, xferspeed);
-
- /* See config_art_rwp_pio for drive pci config registers */
- drive_pci = 0x40;
- if (chipset_family >= ATA_133) {
- u32 reg54h;
- pci_read_config_dword(dev, 0x54, &reg54h);
- if (reg54h & 0x40000000) drive_pci = 0x70;
- drive_pci += ((drive->dn)*0x4);
- pci_read_config_dword(dev, (unsigned long)drive_pci, &regdw);
- /* Disable UDMA bit for non UDMA modes on UDMA chips */
- if (speed < XFER_UDMA_0) {
- regdw &= 0xfffffffb;
- pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
- }
-
- } else {
- drive_pci += ((drive->dn)*0x2);
- pci_read_config_byte(dev, drive_pci+1, &reg);
- /* Disable UDMA bit for non UDMA modes on UDMA chips */
- if ((speed < XFER_UDMA_0) && (chipset_family > ATA_16)) {
- reg &= 0x7F;
- pci_write_config_byte(dev, drive_pci+1, reg);
- }
- }
-
/* Config chip for mode */
switch(speed) {
case XFER_UDMA_6:
@@ -575,6 +320,10 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_UDMA_1:
case XFER_UDMA_0:
if (chipset_family >= ATA_133) {
+ u32 regdw = 0;
+ u8 drive_pci = sis_ata133_get_base(drive);
+
+ pci_read_config_dword(dev, drive_pci, &regdw);
regdw |= 0x04;
regdw &= 0xfffff00f;
/* check if ATA133 enable */
@@ -582,14 +331,14 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4;
regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8;
} else {
- /* if ATA133 disable, we should not set speed above UDMA5 */
- if (speed > XFER_UDMA_5)
- speed = XFER_UDMA_5;
regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4;
regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8;
}
pci_write_config_dword(dev, (unsigned long)drive_pci, regdw);
} else {
+ u8 drive_pci = 0x40 + drive->dn * 2, reg = 0;
+
+ pci_read_config_byte(dev, drive_pci+1, &reg);
/* Force the UDMA bit on if we want to use UDMA */
reg |= 0x80;
/* clean reg cycle time bits */
@@ -604,40 +353,23 @@ static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_MW_DMA_0:
- case XFER_SW_DMA_2:
- case XFER_SW_DMA_1:
- case XFER_SW_DMA_0:
+ sis_program_timings(drive, speed);
break;
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- return sis5513_tune_drive(drive, speed - XFER_PIO_0);
default:
- BUG();
break;
}
-
- return ide_config_drive_speed(drive, speed);
}
-static int sis5513_config_xfer_rate(ide_drive_t *drive)
+static u8 sis5513_ata133_udma_filter(ide_drive_t *drive)
{
- /*
- * TODO: always set PIO mode and remove this
- */
- sis5513_tuneproc(drive, 255);
+ struct pci_dev *dev = drive->hwif->pci_dev;
+ u32 regdw = 0;
+ u8 drive_pci = sis_ata133_get_base(drive);
- drive->init_speed = 0;
+ pci_read_config_dword(dev, drive_pci, &regdw);
- if (ide_tune_dma(drive))
- return 0;
-
- if (ide_use_fast_pio(drive))
- sis5513_tuneproc(drive, 255);
-
- return -1;
+ /* if ATA133 disable, we should not set speed above UDMA5 */
+ return (regdw & 0x08) ? ATA_UDMA6 : ATA_UDMA5;
}
/* Chip detection and general config */
@@ -779,14 +511,6 @@ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const c
}
break;
}
-
-#if defined(DISPLAY_SIS_TIMINGS) && defined(CONFIG_IDE_PROC_FS)
- if (!sis_proc) {
- sis_proc = 1;
- bmide_dev = dev;
- ide_pci_create_host_proc("sis", sis_get_info);
- }
-#endif
}
return 0;
@@ -839,50 +563,30 @@ static void __devinit init_hwif_sis5513 (ide_hwif_t *hwif)
{
u8 udma_rates[] = { 0x00, 0x00, 0x07, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f };
- hwif->autodma = 0;
-
- if (!hwif->irq)
- hwif->irq = hwif->channel ? 15 : 14;
+ hwif->set_pio_mode = &sis_set_pio_mode;
+ hwif->set_dma_mode = &sis_set_dma_mode;
- hwif->tuneproc = &sis5513_tuneproc;
- hwif->speedproc = &sis5513_tune_chipset;
+ if (chipset_family >= ATA_133)
+ hwif->udma_filter = sis5513_ata133_udma_filter;
- if (!(hwif->dma_base)) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ if (hwif->dma_base == 0)
return;
- }
-
- hwif->atapi_dma = 1;
hwif->ultra_mask = udma_rates[chipset_family];
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
-
- if (!chipset_family)
- return;
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
hwif->cbl = ata66_sis5513(hwif);
-
- if (chipset_family > ATA_16) {
- hwif->ide_dma_check = &sis5513_config_xfer_rate;
- if (!noautodma)
- hwif->autodma = 1;
- }
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
- return;
}
-static ide_pci_device_t sis5513_chipset __devinitdata = {
+static const struct ide_port_info sis5513_chipset __devinitdata = {
.name = "SIS5513",
.init_chipset = init_chipset_sis5513,
.init_hwif = init_hwif_sis5513,
- .autodma = NOAUTODMA,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_NO_AUTODMA |
+ IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
};
static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -890,10 +594,10 @@ static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_devi
return ide_setup_pci_device(dev, &sis5513_chipset);
}
-static struct pci_device_id sis5513_pci_tbl[] = {
- { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5518, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_1180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static const struct pci_device_id sis5513_pci_tbl[] = {
+ { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_5513), 0 },
+ { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_5518), 0 },
+ { PCI_VDEVICE(SI, PCI_DEVICE_ID_SI_1180), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl);
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index 0947cab0059..147d783f752 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -75,16 +75,12 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
/*
* Configure the chipset for PIO mode.
*/
-static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio)
+static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
struct pci_dev *dev = HWIF(drive)->pci_dev;
int reg = 0x44 + drive->dn * 4;
u16 drv_ctrl;
- DBG(("sl82c105_tune_pio(drive:%s, pio:%u)\n", drive->name, pio));
-
- pio = ide_get_best_pio_mode(drive, pio, 5);
-
drv_ctrl = get_pio_timings(drive, pio);
/*
@@ -106,14 +102,12 @@ static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio)
printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
ide_xfer_verbose(pio + XFER_PIO_0),
ide_pio_cycle_time(drive, pio), drv_ctrl);
-
- return pio;
}
/*
- * Configure the drive and chipset for a new transfer speed.
+ * Configure the chipset for DMA mode.
*/
-static int sl82c105_tune_chipset(ide_drive_t *drive, u8 speed)
+static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200};
u16 drv_ctrl;
@@ -121,8 +115,6 @@ static int sl82c105_tune_chipset(ide_drive_t *drive, u8 speed)
DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n",
drive->name, ide_xfer_verbose(speed)));
- speed = ide_rate_filter(drive, speed);
-
switch (speed) {
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
@@ -147,32 +139,9 @@ static int sl82c105_tune_chipset(ide_drive_t *drive, u8 speed)
pci_write_config_word(dev, reg, drv_ctrl);
}
break;
- case XFER_PIO_5:
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- (void) sl82c105_tune_pio(drive, speed - XFER_PIO_0);
- break;
default:
- return -1;
+ return;
}
-
- return ide_config_drive_speed(drive, speed);
-}
-
-/*
- * Check to see if the drive and chipset are capable of DMA mode.
- */
-static int sl82c105_ide_dma_check(ide_drive_t *drive)
-{
- DBG(("sl82c105_ide_dma_check(drive:%s)\n", drive->name));
-
- if (ide_tune_dma(drive))
- return 0;
-
- return -1;
}
/*
@@ -322,18 +291,6 @@ static void sl82c105_resetproc(ide_drive_t *drive)
pci_read_config_dword(dev, 0x40, &val);
pci_set_drvdata(dev, (void *)val);
}
-
-/*
- * We only deal with PIO mode here - DMA mode 'using_dma' is not
- * initialised at the point that this function is called.
- */
-static void sl82c105_tune_drive(ide_drive_t *drive, u8 pio)
-{
- DBG(("sl82c105_tune_drive(drive:%s, pio:%u)\n", drive->name, pio));
-
- pio = sl82c105_tune_pio(drive, pio);
- (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
/*
* Return the revision of the Winbond bridge
@@ -399,24 +356,11 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
- hwif->tuneproc = &sl82c105_tune_drive;
- hwif->speedproc = &sl82c105_tune_chipset;
+ hwif->set_pio_mode = &sl82c105_set_pio_mode;
+ hwif->set_dma_mode = &sl82c105_set_dma_mode;
hwif->selectproc = &sl82c105_selectproc;
hwif->resetproc = &sl82c105_resetproc;
- /*
- * We support 32-bit I/O on this interface, and
- * it doesn't have problems with interrupts.
- */
- hwif->drives[0].io_32bit = hwif->drives[1].io_32bit = 1;
- hwif->drives[0].unmask = hwif->drives[1].unmask = 1;
-
- /*
- * We always autotune PIO, this is done before DMA is checked,
- * so there's no risk of accidentally disabling DMA
- */
- hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
-
if (!hwif->dma_base)
return;
@@ -431,31 +375,27 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
return;
}
- hwif->atapi_dma = 1;
- hwif->mwdma_mask = 0x07;
+ hwif->mwdma_mask = ATA_MWDMA2;
- hwif->ide_dma_check = &sl82c105_ide_dma_check;
hwif->ide_dma_on = &sl82c105_ide_dma_on;
hwif->dma_off_quietly = &sl82c105_dma_off_quietly;
hwif->dma_lost_irq = &sl82c105_dma_lost_irq;
hwif->dma_start = &sl82c105_dma_start;
hwif->dma_timeout = &sl82c105_dma_timeout;
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
-
if (hwif->mate)
hwif->serialized = hwif->mate->serialized = 1;
}
-static ide_pci_device_t sl82c105_chipset __devinitdata = {
+static const struct ide_port_info sl82c105_chipset __devinitdata = {
.name = "W82C105",
.init_chipset = init_chipset_sl82c105,
.init_hwif = init_hwif_sl82c105,
- .autodma = NOAUTODMA,
.enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_IO_32BIT |
+ IDE_HFLAG_UNMASK_IRQS |
+ IDE_HFLAG_NO_AUTODMA |
+ IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO5,
};
@@ -464,8 +404,8 @@ static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_dev
return ide_setup_pci_device(dev, &sl82c105_chipset);
}
-static struct pci_device_id sl82c105_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105), 0},
+static const struct pci_device_id sl82c105_pci_tbl[] = {
+ { PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl);
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index 628b0664f57..eb4445b229e 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/slc90e66.c Version 0.15 Jul 6, 2007
+ * linux/drivers/ide/pci/slc90e66.c Version 0.19 Sep 24, 2007
*
* Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
@@ -21,28 +21,9 @@
#include <asm/io.h>
-static u8 slc90e66_dma_2_pio (u8 xfer_rate) {
- switch(xfer_rate) {
- case XFER_UDMA_4:
- case XFER_UDMA_3:
- case XFER_UDMA_2:
- case XFER_UDMA_1:
- case XFER_UDMA_0:
- case XFER_MW_DMA_2:
- return 4;
- case XFER_MW_DMA_1:
- return 3;
- case XFER_SW_DMA_2:
- return 2;
- case XFER_MW_DMA_0:
- case XFER_SW_DMA_1:
- case XFER_SW_DMA_0:
- default:
- return 0;
- }
-}
+static DEFINE_SPINLOCK(slc90e66_lock);
-static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio)
+static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -61,7 +42,7 @@ static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio)
{ 2, 1 },
{ 2, 3 }, };
- spin_lock_irqsave(&ide_lock, flags);
+ spin_lock_irqsave(&slc90e66_lock, flags);
pci_read_config_word(dev, master_port, &master_data);
if (pio > 1)
@@ -92,22 +73,14 @@ static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio)
pci_write_config_word(dev, master_port, master_data);
if (is_slave)
pci_write_config_byte(dev, slave_port, slave_data);
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&slc90e66_lock, flags);
}
-static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
-{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- slc90e66_tune_pio(drive, pio);
- (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
-}
-
-static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u8 maslave = hwif->channel ? 0x42 : 0x40;
- u8 speed = ide_rate_filter(drive, xferspeed);
int sitre = 0, a_speed = 7 << (drive->dn * 4);
int u_speed = 0, u_flag = 1 << drive->dn;
u16 reg4042, reg44, reg48, reg4a;
@@ -127,12 +100,7 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_SW_DMA_2: break;
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0: break;
- default: return -1;
+ default: return;
}
if (speed >= XFER_UDMA_0) {
@@ -145,31 +113,21 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
pci_write_config_word(dev, 0x4a, reg4a|u_speed);
}
} else {
+ const u8 mwdma_to_pio[] = { 0, 3, 4 };
+ u8 pio;
+
if (reg48 & u_flag)
pci_write_config_word(dev, 0x48, reg48 & ~u_flag);
if (reg4a & a_speed)
pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- }
-
- if (speed > XFER_PIO_4)
- slc90e66_tune_pio(drive, slc90e66_dma_2_pio(speed));
- else
- slc90e66_tune_pio(drive, speed - XFER_PIO_0);
-
- return ide_config_drive_speed(drive, speed);
-}
-
-static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
-{
- drive->init_speed = 0;
- if (ide_tune_dma(drive))
- return 0;
+ if (speed >= XFER_MW_DMA_0)
+ pio = mwdma_to_pio[speed - XFER_MW_DMA_0];
+ else
+ pio = 2; /* only SWDMA2 is allowed */
- if (ide_use_fast_pio(drive))
- slc90e66_tune_drive(drive, 255);
-
- return -1;
+ slc90e66_set_pio_mode(drive, pio);
+ }
}
static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
@@ -177,46 +135,28 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
u8 reg47 = 0;
u8 mask = hwif->channel ? 0x01 : 0x02; /* bit0:Primary */
- hwif->autodma = 0;
-
- if (!hwif->irq)
- hwif->irq = hwif->channel ? 15 : 14;
-
- hwif->speedproc = &slc90e66_tune_chipset;
- hwif->tuneproc = &slc90e66_tune_drive;
+ hwif->set_pio_mode = &slc90e66_set_pio_mode;
+ hwif->set_dma_mode = &slc90e66_set_dma_mode;
pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ if (hwif->dma_base == 0)
return;
- }
-
- hwif->atapi_dma = 1;
- hwif->ultra_mask = 0x1f;
- hwif->mwdma_mask = 0x06;
- hwif->swdma_mask = 0x04;
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
/* bit[0(1)]: 0:80, 1:40 */
hwif->cbl = (reg47 & mask) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
-
- hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
-
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
}
-static ide_pci_device_t slc90e66_chipset __devinitdata = {
+static const struct ide_port_info slc90e66_chipset __devinitdata = {
.name = "SLC90E66",
.init_hwif = init_hwif_slc90e66,
- .autodma = AUTODMA,
.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .swdma_mask = ATA_SWDMA2_ONLY,
+ .mwdma_mask = ATA_MWDMA12_ONLY,
+ .udma_mask = ATA_UDMA4,
};
static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -224,8 +164,8 @@ static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_dev
return ide_setup_pci_device(dev, &slc90e66_chipset);
}
-static struct pci_device_id slc90e66_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1), 0},
+static const struct pci_device_id slc90e66_pci_tbl[] = {
+ { PCI_VDEVICE(EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl);
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
index ec79bacc30c..a66ebd14664 100644
--- a/drivers/ide/pci/tc86c001.c
+++ b/drivers/ide/pci/tc86c001.c
@@ -1,5 +1,5 @@
/*
- * drivers/ide/pci/tc86c001.c Version 1.00 Dec 12, 2006
+ * drivers/ide/pci/tc86c001.c Version 1.01 Sep 5, 2007
*
* Copyright (C) 2002 Toshiba Corporation
* Copyright (C) 2005-2006 MontaVista Software, Inc. <source@mvista.com>
@@ -13,13 +13,11 @@
#include <linux/pci.h>
#include <linux/ide.h>
-static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
+static void tc86c001_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
unsigned long scr_port = hwif->config_data + (drive->dn ? 0x02 : 0x00);
- u16 mode, scr = hwif->INW(scr_port);
-
- speed = ide_rate_filter(drive, speed);
+ u16 mode, scr = inw(scr_port);
switch (speed) {
case XFER_UDMA_4: mode = 0x00c0; break;
@@ -41,14 +39,11 @@ static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
scr |= mode;
outw(scr, scr_port);
-
- return ide_config_drive_speed(drive, speed);
}
-static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio)
+static void tc86c001_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4);
- (void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
+ tc86c001_set_mode(drive, XFER_PIO_0 + pio);
}
/*
@@ -70,7 +65,7 @@ static int tc86c001_timer_expiry(ide_drive_t *drive)
ide_hwif_t *hwif = HWIF(drive);
ide_expiry_t *expiry = ide_get_hwifdata(hwif);
ide_hwgroup_t *hwgroup = HWGROUP(drive);
- u8 dma_stat = hwif->INB(hwif->dma_status);
+ u8 dma_stat = inb(hwif->dma_status);
/* Restore a higher level driver's expiry handler first. */
hwgroup->expiry = expiry;
@@ -78,7 +73,7 @@ static int tc86c001_timer_expiry(ide_drive_t *drive)
if ((dma_stat & 5) == 1) { /* DMA active and no interrupt */
unsigned long sc_base = hwif->config_data;
unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
- u8 dma_cmd = hwif->INB(hwif->dma_command);
+ u8 dma_cmd = inb(hwif->dma_command);
printk(KERN_WARNING "%s: DMA interrupt possibly stuck, "
"attempting recovery...\n", drive->name);
@@ -140,7 +135,7 @@ static int tc86c001_busproc(ide_drive_t *drive, int state)
u16 scr1;
/* System Control 1 Register bit 11 (ATA Hard Reset) read */
- scr1 = hwif->INW(sc_base + 0x00);
+ scr1 = inw(sc_base + 0x00);
switch (state) {
case BUSSTATE_ON:
@@ -167,21 +162,10 @@ static int tc86c001_busproc(ide_drive_t *drive, int state)
return 0;
}
-static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive)
-{
- if (ide_tune_dma(drive))
- return 0;
-
- if (ide_use_fast_pio(drive))
- tc86c001_tune_drive(drive, 255);
-
- return -1;
-}
-
static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
{
unsigned long sc_base = pci_resource_start(hwif->pci_dev, 5);
- u16 scr1 = hwif->INW(sc_base + 0x00);;
+ u16 scr1 = inw(sc_base + 0x00);
/* System Control 1 Register bit 15 (Soft Reset) set */
outw(scr1 | 0x8000, sc_base + 0x00);
@@ -195,11 +179,10 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
/* Store the system control register base for convenience... */
hwif->config_data = sc_base;
- hwif->tuneproc = &tc86c001_tune_drive;
- hwif->speedproc = &tc86c001_tune_chipset;
- hwif->busproc = &tc86c001_busproc;
+ hwif->set_pio_mode = &tc86c001_set_pio_mode;
+ hwif->set_dma_mode = &tc86c001_set_mode;
- hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+ hwif->busproc = &tc86c001_busproc;
if (!hwif->dma_base)
return;
@@ -213,11 +196,6 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
/* Sector Count Register limit */
hwif->rqsize = 0xffff;
- hwif->atapi_dma = 1;
- hwif->ultra_mask = 0x1f;
- hwif->mwdma_mask = 0x07;
-
- hwif->ide_dma_check = &tc86c001_config_drive_xfer_rate;
hwif->dma_start = &tc86c001_dma_start;
if (hwif->cbl != ATA_CBL_PATA40_SHORT) {
@@ -225,13 +203,9 @@ static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
* System Control 1 Register bit 13 (PDIAGN):
* 0=80-pin cable, 1=40-pin cable
*/
- scr1 = hwif->INW(sc_base + 0x00);
+ scr1 = inw(sc_base + 0x00);
hwif->cbl = (scr1 & 0x2000) ? ATA_CBL_PATA40 : ATA_CBL_PATA80;
}
-
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
}
static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev,
@@ -244,14 +218,14 @@ static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev,
return err;
}
-static ide_pci_device_t tc86c001_chipset __devinitdata = {
+static const struct ide_port_info tc86c001_chipset __devinitdata = {
.name = "TC86C001",
.init_chipset = init_chipset_tc86c001,
.init_hwif = init_hwif_tc86c001,
- .autodma = AUTODMA,
- .bootable = OFF_BOARD,
- .host_flags = IDE_HFLAG_SINGLE,
+ .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD,
.pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA4,
};
static int __devinit tc86c001_init_one(struct pci_dev *dev,
@@ -260,9 +234,8 @@ static int __devinit tc86c001_init_one(struct pci_dev *dev,
return ide_setup_pci_device(dev, &tc86c001_chipset);
}
-static struct pci_device_id tc86c001_pci_tbl[] = {
- { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static const struct pci_device_id tc86c001_pci_tbl[] = {
+ { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE), 0 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl);
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index 098692a6d61..a227c41d23a 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -40,7 +40,7 @@
#include <linux/ide.h>
#include <linux/init.h>
-static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static void triflex_set_mode(ide_drive_t *drive, const u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -48,7 +48,6 @@ static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
u16 timing = 0;
u32 triflex_timings = 0;
u8 unit = (drive->select.b.unit & 0x01);
- u8 speed = ide_rate_filter(drive, xferspeed);
pci_read_config_dword(dev, channel_offset, &triflex_timings);
@@ -83,59 +82,34 @@ static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
timing = 0x0808;
break;
default:
- return -1;
+ return;
}
triflex_timings &= ~(0xFFFF << (16 * unit));
triflex_timings |= (timing << (16 * unit));
pci_write_config_dword(dev, channel_offset, triflex_timings);
-
- return (ide_config_drive_speed(drive, speed));
}
-static void triflex_tune_drive(ide_drive_t *drive, u8 pio)
+static void triflex_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- int use_pio = ide_get_best_pio_mode(drive, pio, 4);
- (void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio));
-}
-
-static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
-{
- if (ide_tune_dma(drive))
- return 0;
-
- triflex_tune_drive(drive, 255);
-
- return -1;
+ triflex_set_mode(drive, XFER_PIO_0 + pio);
}
static void __devinit init_hwif_triflex(ide_hwif_t *hwif)
{
- hwif->tuneproc = &triflex_tune_drive;
- hwif->speedproc = &triflex_tune_chipset;
-
- if (hwif->dma_base == 0)
- return;
-
- hwif->atapi_dma = 1;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
- hwif->ide_dma_check = &triflex_config_drive_xfer_rate;
-
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
+ hwif->set_pio_mode = &triflex_set_pio_mode;
+ hwif->set_dma_mode = &triflex_set_mode;
}
-static ide_pci_device_t triflex_device __devinitdata = {
+static const struct ide_port_info triflex_device __devinitdata = {
.name = "TRIFLEX",
.init_hwif = init_hwif_triflex,
- .autodma = AUTODMA,
.enablebits = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
- .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_BOOTABLE,
.pio_mask = ATA_PIO4,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
};
static int __devinit triflex_init_one(struct pci_dev *dev,
@@ -144,9 +118,8 @@ static int __devinit triflex_init_one(struct pci_dev *dev,
return ide_setup_pci_device(dev, &triflex_device);
}
-static struct pci_device_id triflex_pci_tbl[] = {
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+static const struct pci_device_id triflex_pci_tbl[] = {
+ { PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, triflex_pci_tbl);
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
index dc4f4e298e0..5011ba22e36 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/pci/trm290.c
@@ -250,8 +250,6 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
u8 reg = 0;
struct pci_dev *dev = hwif->pci_dev;
- hwif->no_lba48 = 1;
- hwif->chipset = ide_trm290;
cfgbase = pci_resource_start(dev, 4);
if ((dev->class & 5) && cfgbase) {
hwif->config_data = cfgbase;
@@ -292,9 +290,6 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq;
hwif->selectproc = &trm290_selectproc;
- hwif->autodma = 0; /* play it safe for now */
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
#if 1
{
/*
@@ -324,11 +319,17 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
#endif
}
-static ide_pci_device_t trm290_chipset __devinitdata = {
+static const struct ide_port_info trm290_chipset __devinitdata = {
.name = "TRM290",
.init_hwif = init_hwif_trm290,
- .autodma = NOAUTODMA,
- .bootable = ON_BOARD,
+ .chipset = ide_trm290,
+ .host_flags = IDE_HFLAG_NO_ATAPI_DMA |
+#if 0 /* play it safe for now */
+ IDE_HFLAG_TRUST_BIOS_FOR_DMA |
+#endif
+ IDE_HFLAG_NO_AUTODMA |
+ IDE_HFLAG_BOOTABLE |
+ IDE_HFLAG_NO_LBA48,
};
static int __devinit trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -336,8 +337,8 @@ static int __devinit trm290_init_one(struct pci_dev *dev, const struct pci_devic
return ide_setup_pci_device(dev, &trm290_chipset);
}
-static struct pci_device_id trm290_pci_tbl[] = {
- { PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static const struct pci_device_id trm290_pci_tbl[] = {
+ { PCI_VDEVICE(TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, trm290_pci_tbl);
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index a7be7795e6a..a0d3c16b68e 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -1,6 +1,6 @@
/*
*
- * Version 3.47
+ * Version 3.50
*
* VIA IDE driver for Linux. Supported southbridges:
*
@@ -153,21 +153,17 @@ static void via_set_speed(ide_hwif_t *hwif, u8 dn, struct ide_timing *timing)
* @drive: Drive to set up
* @speed: desired speed
*
- * via_set_drive() computes timing values configures the drive and
- * the chipset to a desired transfer mode. It also can be called
- * by upper layers.
+ * via_set_drive() computes timing values configures the chipset to
+ * a desired transfer mode. It also can be called by upper layers.
*/
-static int via_set_drive(ide_drive_t *drive, u8 speed)
+static void via_set_drive(ide_drive_t *drive, const u8 speed)
{
ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
struct via82cxxx_dev *vdev = pci_get_drvdata(drive->hwif->pci_dev);
struct ide_timing t, p;
unsigned int T, UT;
- if (speed != XFER_PIO_SLOW)
- ide_config_drive_speed(drive, speed);
-
T = 1000000000 / via_clock;
switch (vdev->via_config->udma_mask) {
@@ -186,53 +182,19 @@ static int via_set_drive(ide_drive_t *drive, u8 speed)
}
via_set_speed(HWIF(drive), drive->dn, &t);
-
- if (!drive->init_speed)
- drive->init_speed = speed;
- drive->current_speed = speed;
-
- return 0;
}
/**
- * via82cxxx_tune_drive - PIO setup
- * @drive: drive to set up
- * @pio: mode to use (255 for 'best possible')
+ * via_set_pio_mode - set host controller for PIO mode
+ * @drive: drive
+ * @pio: PIO mode number
*
* A callback from the upper layers for PIO-only tuning.
*/
-static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
+static void via_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- if (pio == 255)
- pio = ide_get_best_pio_mode(drive, 255, 5);
-
- via_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5));
-}
-
-/**
- * via82cxxx_ide_dma_check - set up for DMA if possible
- * @drive: IDE drive to set up
- *
- * Set up the drive for the highest supported speed considering the
- * driver, controller and cable
- */
-
-static int via82cxxx_ide_dma_check (ide_drive_t *drive)
-{
- u8 speed = ide_max_dma_mode(drive);
-
- if (speed == 0) {
- via82cxxx_tune_drive(drive, 255);
- return -1;
- }
-
- via_set_drive(drive, speed);
-
- if (drive->autodma)
- return 0;
-
- return -1;
+ via_set_drive(drive, XFER_PIO_0 + pio);
}
static struct via_isa_bridge *via_config_find(struct pci_dev **isa)
@@ -419,7 +381,7 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const
* Cable special cases
*/
-static struct dmi_system_id cable_dmi_table[] = {
+static const struct dmi_system_id cable_dmi_table[] = {
{
.ident = "Acer Ferrari 3400",
.matches = {
@@ -460,75 +422,40 @@ static u8 __devinit via82cxxx_cable_detect(ide_hwif_t *hwif)
static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif)
{
- struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev);
- int i;
-
- hwif->autodma = 0;
-
- hwif->tuneproc = &via82cxxx_tune_drive;
- hwif->speedproc = &via_set_drive;
-
-
-#ifdef CONFIG_PPC_CHRP
- if(machine_is(chrp) && _chrp_type == _CHRP_Pegasos) {
- hwif->irq = hwif->channel ? 15 : 14;
- }
-#endif
-
- for (i = 0; i < 2; i++) {
- hwif->drives[i].io_32bit = 1;
- hwif->drives[i].unmask = (vdev->via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
- hwif->drives[i].autotune = 1;
- hwif->drives[i].dn = hwif->channel * 2 + i;
- }
+ hwif->set_pio_mode = &via_set_pio_mode;
+ hwif->set_dma_mode = &via_set_drive;
if (!hwif->dma_base)
return;
- hwif->atapi_dma = 1;
-
- hwif->ultra_mask = vdev->via_config->udma_mask;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
-
if (hwif->cbl != ATA_CBL_PATA40_SHORT)
hwif->cbl = via82cxxx_cable_detect(hwif);
-
- hwif->ide_dma_check = &via82cxxx_ide_dma_check;
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
}
-static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
- { /* 0 */
- .name = "VP_IDE",
- .init_chipset = init_chipset_via82cxxx,
- .init_hwif = init_hwif_via82cxxx,
- .autodma = NOAUTODMA,
- .enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
- .bootable = ON_BOARD,
- .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST
- | IDE_HFLAG_PIO_NO_DOWNGRADE,
- .pio_mask = ATA_PIO5,
- },{ /* 1 */
- .name = "VP_IDE",
- .init_chipset = init_chipset_via82cxxx,
- .init_hwif = init_hwif_via82cxxx,
- .autodma = AUTODMA,
- .enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
- .bootable = ON_BOARD,
- .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST
- | IDE_HFLAG_PIO_NO_DOWNGRADE,
- .pio_mask = ATA_PIO5,
- }
+static const struct ide_port_info via82cxxx_chipset __devinitdata = {
+ .name = "VP_IDE",
+ .init_chipset = init_chipset_via82cxxx,
+ .init_hwif = init_hwif_via82cxxx,
+ .enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } },
+ .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST |
+ IDE_HFLAG_PIO_NO_DOWNGRADE |
+ IDE_HFLAG_POST_SET_MODE |
+ IDE_HFLAG_IO_32BIT |
+ IDE_HFLAG_BOOTABLE,
+ .pio_mask = ATA_PIO5,
+ .swdma_mask = ATA_SWDMA2,
+ .mwdma_mask = ATA_MWDMA2,
};
static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
struct pci_dev *isa = NULL;
struct via_isa_bridge *via_config;
+ u8 idx = id->driver_data;
+ struct ide_port_info d;
+
+ d = via82cxxx_chipset;
+
/*
* Find the ISA bridge and check we know what it is.
*/
@@ -538,14 +465,30 @@ static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_i
printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, disabling DMA.\n");
return -ENODEV;
}
- return ide_setup_pci_device(dev, &via82cxxx_chipsets[id->driver_data]);
+
+ if (idx == 0)
+ d.host_flags |= IDE_HFLAG_NO_AUTODMA;
+ else
+ d.enablebits[1].reg = d.enablebits[0].reg = 0;
+
+ if ((via_config->flags & VIA_NO_UNMASK) == 0)
+ d.host_flags |= IDE_HFLAG_UNMASK_IRQS;
+
+#ifdef CONFIG_PPC_CHRP
+ if (machine_is(chrp) && _chrp_type == _CHRP_Pegasos)
+ d.host_flags |= IDE_HFLAG_FORCE_LEGACY_IRQS;
+#endif
+
+ d.udma_mask = via_config->udma_mask;
+
+ return ide_setup_pci_device(dev, &d);
}
-static struct pci_device_id via_pci_tbl[] = {
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_6410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_SATA_EIDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+static const struct pci_device_id via_pci_tbl[] = {
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), 0 },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), 0 },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), 1 },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), 1 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, via_pci_tbl);
diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
index dab79afa9b2..5f0da35ab5a 100644
--- a/drivers/ide/ppc/mpc8xx.c
+++ b/drivers/ide/ppc/mpc8xx.c
@@ -45,7 +45,7 @@ static void print_funcid (int func);
static int check_ide_device (unsigned long base);
static void ide_interrupt_ack (void *dev);
-static void m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio);
+static void m8xx_ide_set_pio_mode(ide_drive_t *drive, const u8 pio);
typedef struct ide_ioport_desc {
unsigned long base_off; /* Offset to PCMCIA memory */
@@ -314,11 +314,10 @@ m8xx_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port,
#endif /* CONFIG_IDE_8xx_PCCARD */
}
- /* register routine to tune PIO mode */
ide_hwifs[data_port].pio_mask = ATA_PIO4;
- ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+ ide_hwifs[data_port].set_pio_mode = m8xx_ide_set_pio_mode;
+ ide_hwifs[data_port].ack_intr = (ide_ack_intr_t *)ide_interrupt_ack;
- hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
/* Enable Harddisk Interrupt,
* and make it edge sensitive
*/
@@ -401,11 +400,10 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
*irq = ioport_dsc[data_port].irq;
}
- /* register routine to tune PIO mode */
ide_hwifs[data_port].pio_mask = ATA_PIO4;
- ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+ ide_hwifs[data_port].set_pio_mode = m8xx_ide_set_pio_mode;
+ ide_hwifs[data_port].ack_intr = (ide_ack_intr_t *)ide_interrupt_ack;
- hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
/* Enable Harddisk Interrupt,
* and make it edge sensitive
*/
@@ -427,24 +425,13 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
#define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length */
#endif
-
/* Calculate PIO timings */
-static void
-m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
+static void m8xx_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
volatile pcmconf8xx_t *pcmp;
ulong timing, mask, reg;
-#endif
-
- pio = ide_get_best_pio_mode(drive, pio, 4);
-#if 1
- printk("%s[%d] %s: best PIO mode: %d\n",
- __FILE__,__LINE__,__FUNCTION__, pio);
-#endif
-
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 2fb047b898a..5afdfef7264 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -6,6 +6,7 @@
* for doing DMA.
*
* Copyright (C) 1998-2003 Paul Mackerras & Ben. Herrenschmidt
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -311,7 +312,8 @@ static struct kauai_timing kauai_pio_timings[] =
{ 240 , 0x0800038b },
{ 239 , 0x0800030c },
{ 180 , 0x05000249 },
- { 120 , 0x04000148 }
+ { 120 , 0x04000148 },
+ { 0 , 0 },
};
static struct kauai_timing kauai_mdma_timings[] =
@@ -351,7 +353,8 @@ static struct kauai_timing shasta_pio_timings[] =
{ 240 , 0x040003cd },
{ 239 , 0x040003cd },
{ 180 , 0x0400028b },
- { 120 , 0x0400010a }
+ { 120 , 0x0400010a },
+ { 0 , 0 },
};
static struct kauai_timing shasta_mdma_timings[] =
@@ -389,6 +392,7 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
for (i=0; table[i].cycle_time; i++)
if (cycle_time > table[i+1].cycle_time)
return table[i].timing_reg;
+ BUG();
return 0;
}
@@ -411,8 +415,6 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time)
static void pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif);
static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq);
-static int pmac_ide_tune_chipset(ide_drive_t *drive, u8 speed);
-static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio);
static void pmac_ide_selectproc(ide_drive_t *drive);
static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
@@ -528,97 +530,12 @@ pmac_outbsync(ide_drive_t *drive, u8 value, unsigned long port)
}
/*
- * Send the SET_FEATURE IDE command to the drive and update drive->id with
- * the new state. We currently don't use the generic routine as it used to
- * cause various trouble, especially with older mediabays.
- * This code is sometimes triggering a spurrious interrupt though, I need
- * to sort that out sooner or later and see if I can finally get the
- * common version to work properly in all cases
- */
-static int
-pmac_ide_do_setfeature(ide_drive_t *drive, u8 command)
-{
- ide_hwif_t *hwif = HWIF(drive);
- int result = 1;
-
- disable_irq_nosync(hwif->irq);
- udelay(1);
- SELECT_DRIVE(drive);
- SELECT_MASK(drive, 0);
- udelay(1);
- /* Get rid of pending error state */
- (void) hwif->INB(IDE_STATUS_REG);
- /* Timeout bumped for some powerbooks */
- if (wait_for_ready(drive, 2000)) {
- /* Timeout bumped for some powerbooks */
- printk(KERN_ERR "%s: pmac_ide_do_setfeature disk not ready "
- "before SET_FEATURE!\n", drive->name);
- goto out;
- }
- udelay(10);
- hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
- hwif->OUTB(command, IDE_NSECTOR_REG);
- hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
- hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
- udelay(1);
- /* Timeout bumped for some powerbooks */
- result = wait_for_ready(drive, 2000);
- hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
- if (result)
- printk(KERN_ERR "%s: pmac_ide_do_setfeature disk not ready "
- "after SET_FEATURE !\n", drive->name);
-out:
- SELECT_MASK(drive, 0);
- if (result == 0) {
- drive->id->dma_ultra &= ~0xFF00;
- drive->id->dma_mword &= ~0x0F00;
- drive->id->dma_1word &= ~0x0F00;
- switch(command) {
- case XFER_UDMA_7:
- drive->id->dma_ultra |= 0x8080; break;
- case XFER_UDMA_6:
- drive->id->dma_ultra |= 0x4040; break;
- case XFER_UDMA_5:
- drive->id->dma_ultra |= 0x2020; break;
- case XFER_UDMA_4:
- drive->id->dma_ultra |= 0x1010; break;
- case XFER_UDMA_3:
- drive->id->dma_ultra |= 0x0808; break;
- case XFER_UDMA_2:
- drive->id->dma_ultra |= 0x0404; break;
- case XFER_UDMA_1:
- drive->id->dma_ultra |= 0x0202; break;
- case XFER_UDMA_0:
- drive->id->dma_ultra |= 0x0101; break;
- case XFER_MW_DMA_2:
- drive->id->dma_mword |= 0x0404; break;
- case XFER_MW_DMA_1:
- drive->id->dma_mword |= 0x0202; break;
- case XFER_MW_DMA_0:
- drive->id->dma_mword |= 0x0101; break;
- case XFER_SW_DMA_2:
- drive->id->dma_1word |= 0x0404; break;
- case XFER_SW_DMA_1:
- drive->id->dma_1word |= 0x0202; break;
- case XFER_SW_DMA_0:
- drive->id->dma_1word |= 0x0101; break;
- default: break;
- }
- if (!drive->init_speed)
- drive->init_speed = command;
- drive->current_speed = command;
- }
- enable_irq(hwif->irq);
- return result;
-}
-
-/*
* Old tuning functions (called on hdparm -p), sets up drive PIO timings
*/
static void
-pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
+pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
{
- u32 *timings;
+ u32 *timings, t;
unsigned accessTicks, recTicks;
unsigned accessTime, recTime;
pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
@@ -629,26 +546,22 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
/* which drive is it ? */
timings = &pmif->timings[drive->select.b.unit & 0x01];
+ t = *timings;
- pio = ide_get_best_pio_mode(drive, pio, 4);
cycle_time = ide_pio_cycle_time(drive, pio);
switch (pmif->kind) {
case controller_sh_ata6: {
/* 133Mhz cell */
u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time);
- if (tr == 0)
- return;
- *timings = ((*timings) & ~TR_133_PIOREG_PIO_MASK) | tr;
+ t = (t & ~TR_133_PIOREG_PIO_MASK) | tr;
break;
}
case controller_un_ata6:
case controller_k2_ata6: {
/* 100Mhz cell */
u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time);
- if (tr == 0)
- return;
- *timings = ((*timings) & ~TR_100_PIOREG_PIO_MASK) | tr;
+ t = (t & ~TR_100_PIOREG_PIO_MASK) | tr;
break;
}
case controller_kl_ata4:
@@ -662,9 +575,9 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
accessTicks = min(accessTicks, 0x1fU);
recTicks = SYSCLK_TICKS_66(recTime);
recTicks = min(recTicks, 0x1fU);
- *timings = ((*timings) & ~TR_66_PIO_MASK) |
- (accessTicks << TR_66_PIO_ACCESS_SHIFT) |
- (recTicks << TR_66_PIO_RECOVERY_SHIFT);
+ t = (t & ~TR_66_PIO_MASK) |
+ (accessTicks << TR_66_PIO_ACCESS_SHIFT) |
+ (recTicks << TR_66_PIO_RECOVERY_SHIFT);
break;
default: {
/* 33Mhz cell */
@@ -684,11 +597,11 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
recTicks--; /* guess, but it's only for PIO0, so... */
ebit = 1;
}
- *timings = ((*timings) & ~TR_33_PIO_MASK) |
+ t = (t & ~TR_33_PIO_MASK) |
(accessTicks << TR_33_PIO_ACCESS_SHIFT) |
(recTicks << TR_33_PIO_RECOVERY_SHIFT);
if (ebit)
- *timings |= TR_33_PIO_E;
+ t |= TR_33_PIO_E;
break;
}
}
@@ -698,8 +611,8 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
drive->name, pio, *timings);
#endif
- if (drive->select.all == HWIF(drive)->INB(IDE_SELECT_REG))
- pmac_ide_do_update_timings(drive);
+ *timings = t;
+ pmac_ide_do_update_timings(drive);
}
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
@@ -744,8 +657,6 @@ set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed)
if (speed > XFER_UDMA_5 || t == NULL)
return 1;
tr = kauai_lookup_timing(kauai_udma_timings, (int)t->udma);
- if (tr == 0)
- return 1;
*ultra_timings = ((*ultra_timings) & ~TR_100_UDMAREG_UDMA_MASK) | tr;
*ultra_timings = (*ultra_timings) | TR_100_UDMAREG_UDMA_EN;
@@ -764,8 +675,6 @@ set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed)
if (speed > XFER_UDMA_6 || t == NULL)
return 1;
tr = kauai_lookup_timing(shasta_udma133_timings, (int)t->udma);
- if (tr == 0)
- return 1;
*ultra_timings = ((*ultra_timings) & ~TR_133_UDMAREG_UDMA_MASK) | tr;
*ultra_timings = (*ultra_timings) | TR_133_UDMAREG_UDMA_EN;
@@ -775,12 +684,13 @@ set_timings_udma_shasta(u32 *pio_timings, u32 *ultra_timings, u8 speed)
/*
* Calculate MDMA timings for all cells
*/
-static int
+static void
set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
- u8 speed, int drive_cycle_time)
+ u8 speed)
{
int cycleTime, accessTime = 0, recTime = 0;
unsigned accessTicks, recTicks;
+ struct hd_driveid *id = drive->id;
struct mdma_timings_t* tm = NULL;
int i;
@@ -790,11 +700,14 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
case 1: cycleTime = 150; break;
case 2: cycleTime = 120; break;
default:
- return 1;
+ BUG();
+ break;
}
- /* Adjust for drive */
- if (drive_cycle_time && drive_cycle_time > cycleTime)
- cycleTime = drive_cycle_time;
+
+ /* Check if drive provides explicit DMA cycle time */
+ if ((id->field_valid & 2) && id->eide_dma_time)
+ cycleTime = max_t(int, id->eide_dma_time, cycleTime);
+
/* OHare limits according to some old Apple sources */
if ((intf_type == controller_ohare) && (cycleTime < 150))
cycleTime = 150;
@@ -822,8 +735,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
break;
i++;
}
- if (i < 0)
- return 1;
cycleTime = tm[i].cycleTime;
accessTime = tm[i].accessTime;
recTime = tm[i].recoveryTime;
@@ -837,8 +748,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
case controller_sh_ata6: {
/* 133Mhz cell */
u32 tr = kauai_lookup_timing(shasta_mdma_timings, cycleTime);
- if (tr == 0)
- return 1;
*timings = ((*timings) & ~TR_133_PIOREG_MDMA_MASK) | tr;
*timings2 = (*timings2) & ~TR_133_UDMAREG_UDMA_EN;
}
@@ -846,8 +755,6 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
case controller_k2_ata6: {
/* 100Mhz cell */
u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime);
- if (tr == 0)
- return 1;
*timings = ((*timings) & ~TR_100_PIOREG_MDMA_MASK) | tr;
*timings2 = (*timings2) & ~TR_100_UDMAREG_UDMA_EN;
}
@@ -909,88 +816,63 @@ set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
printk(KERN_ERR "%s: Set MDMA timing for mode %d, reg: 0x%08x\n",
drive->name, speed & 0xf, *timings);
#endif
- return 0;
}
#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
-/*
- * Speedproc. This function is called by the core to set any of the standard
- * timing (PIO, MDMA or UDMA) to both the drive and the controller.
- * You may notice we don't use this function on normal "dma check" operation,
- * our dedicated function is more precise as it uses the drive provided
- * cycle time value. We should probably fix this one to deal with that too...
- */
-static int
-pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
+static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed)
{
int unit = (drive->select.b.unit & 0x01);
int ret = 0;
pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
- u32 *timings, *timings2;
+ u32 *timings, *timings2, tl[2];
- if (pmif == NULL)
- return 1;
-
timings = &pmif->timings[unit];
timings2 = &pmif->timings[unit+2];
-
+
+ /* Copy timings to local image */
+ tl[0] = *timings;
+ tl[1] = *timings2;
+
switch(speed) {
#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
case XFER_UDMA_6:
- if (pmif->kind != controller_sh_ata6)
- return 1;
case XFER_UDMA_5:
- if (pmif->kind != controller_un_ata6 &&
- pmif->kind != controller_k2_ata6 &&
- pmif->kind != controller_sh_ata6)
- return 1;
case XFER_UDMA_4:
case XFER_UDMA_3:
- if (drive->hwif->cbl != ATA_CBL_PATA80)
- return 1;
case XFER_UDMA_2:
case XFER_UDMA_1:
case XFER_UDMA_0:
if (pmif->kind == controller_kl_ata4)
- ret = set_timings_udma_ata4(timings, speed);
+ ret = set_timings_udma_ata4(&tl[0], speed);
else if (pmif->kind == controller_un_ata6
|| pmif->kind == controller_k2_ata6)
- ret = set_timings_udma_ata6(timings, timings2, speed);
+ ret = set_timings_udma_ata6(&tl[0], &tl[1], speed);
else if (pmif->kind == controller_sh_ata6)
- ret = set_timings_udma_shasta(timings, timings2, speed);
+ ret = set_timings_udma_shasta(&tl[0], &tl[1], speed);
else
- ret = 1;
+ ret = 1;
break;
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_MW_DMA_0:
- ret = set_timings_mdma(drive, pmif->kind, timings, timings2, speed, 0);
+ set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed);
break;
case XFER_SW_DMA_2:
case XFER_SW_DMA_1:
case XFER_SW_DMA_0:
- return 1;
+ return;
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- pmac_ide_tuneproc(drive, speed & 0x07);
- break;
default:
ret = 1;
}
if (ret)
- return ret;
+ return;
- ret = pmac_ide_do_setfeature(drive, speed);
- if (ret)
- return ret;
-
- pmac_ide_do_update_timings(drive);
+ /* Apply timings to controller */
+ *timings = tl[0];
+ *timings2 = tl[1];
- return 0;
+ pmac_ide_do_update_timings(drive);
}
/*
@@ -1157,6 +1039,8 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
{
struct device_node *np = pmif->node;
const int *bidp;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
+ hw_regs_t hw;
pmif->cable_80 = 0;
pmif->broken_dma = pmif->broken_dma_warn = 0;
@@ -1242,23 +1126,29 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
/* Tell common code _not_ to mess with resources */
hwif->mmio = 1;
hwif->hwif_data = pmif;
- pmac_ide_init_hwif_ports(&hwif->hw, pmif->regbase, 0, &hwif->irq);
- memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+ memset(&hw, 0, sizeof(hw));
+ pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, &hwif->irq);
+ memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
hwif->chipset = ide_pmac;
hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || pmif->mediabay;
hwif->hold = pmif->mediabay;
hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
hwif->drives[0].unmask = 1;
hwif->drives[1].unmask = 1;
+ hwif->drives[0].autotune = IDE_TUNE_AUTO;
+ hwif->drives[1].autotune = IDE_TUNE_AUTO;
+ hwif->host_flags = IDE_HFLAG_SET_PIO_MODE_KEEP_DMA |
+ IDE_HFLAG_PIO_NO_DOWNGRADE |
+ IDE_HFLAG_POST_SET_MODE;
hwif->pio_mask = ATA_PIO4;
- hwif->tuneproc = pmac_ide_tuneproc;
+ hwif->set_pio_mode = pmac_ide_set_pio_mode;
if (pmif->kind == controller_un_ata6
|| pmif->kind == controller_k2_ata6
|| pmif->kind == controller_sh_ata6)
hwif->selectproc = pmac_ide_kauai_selectproc;
else
hwif->selectproc = pmac_ide_selectproc;
- hwif->speedproc = pmac_ide_tune_chipset;
+ hwif->set_dma_mode = pmac_ide_set_dma_mode;
printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n",
hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
@@ -1277,10 +1167,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
pmac_ide_setup_dma(pmif, hwif);
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
- /* We probe the hwif now */
- probe_hwif_init(hwif);
+ idx[0] = hwif->index;
- ide_proc_register_port(hwif);
+ ide_device_add(idx);
return 0;
}
@@ -1535,17 +1424,12 @@ static struct macio_driver pmac_ide_macio_driver =
.resume = pmac_ide_macio_resume,
};
-static struct pci_device_id pmac_ide_pci_match[] = {
- { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_SH_ATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static const struct pci_device_id pmac_ide_pci_match[] = {
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA), 0 },
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100), 0 },
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100), 0 },
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_SH_ATA), 0 },
+ { PCI_VDEVICE(APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA), 0 },
{},
};
@@ -1653,7 +1537,7 @@ pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq)
cur_len -= tc;
++table;
}
- sg++;
+ sg = sg_next(sg);
i--;
}
@@ -1693,141 +1577,6 @@ pmac_ide_destroy_dmatable (ide_drive_t *drive)
}
/*
- * Pick up best MDMA timing for the drive and apply it
- */
-static int
-pmac_ide_mdma_enable(ide_drive_t *drive, u16 mode)
-{
- ide_hwif_t *hwif = HWIF(drive);
- pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
- int drive_cycle_time;
- struct hd_driveid *id = drive->id;
- u32 *timings, *timings2;
- u32 timing_local[2];
- int ret;
-
- /* which drive is it ? */
- timings = &pmif->timings[drive->select.b.unit & 0x01];
- timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2];
-
- /* Check if drive provide explicit cycle time */
- if ((id->field_valid & 2) && (id->eide_dma_time))
- drive_cycle_time = id->eide_dma_time;
- else
- drive_cycle_time = 0;
-
- /* Copy timings to local image */
- timing_local[0] = *timings;
- timing_local[1] = *timings2;
-
- /* Calculate controller timings */
- ret = set_timings_mdma( drive, pmif->kind,
- &timing_local[0],
- &timing_local[1],
- mode,
- drive_cycle_time);
- if (ret)
- return 0;
-
- /* Set feature on drive */
- printk(KERN_INFO "%s: Enabling MultiWord DMA %d\n", drive->name, mode & 0xf);
- ret = pmac_ide_do_setfeature(drive, mode);
- if (ret) {
- printk(KERN_WARNING "%s: Failed !\n", drive->name);
- return 0;
- }
-
- /* Apply timings to controller */
- *timings = timing_local[0];
- *timings2 = timing_local[1];
-
- return 1;
-}
-
-/*
- * Pick up best UDMA timing for the drive and apply it
- */
-static int
-pmac_ide_udma_enable(ide_drive_t *drive, u16 mode)
-{
- ide_hwif_t *hwif = HWIF(drive);
- pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
- u32 *timings, *timings2;
- u32 timing_local[2];
- int ret;
-
- /* which drive is it ? */
- timings = &pmif->timings[drive->select.b.unit & 0x01];
- timings2 = &pmif->timings[(drive->select.b.unit & 0x01) + 2];
-
- /* Copy timings to local image */
- timing_local[0] = *timings;
- timing_local[1] = *timings2;
-
- /* Calculate timings for interface */
- if (pmif->kind == controller_un_ata6
- || pmif->kind == controller_k2_ata6)
- ret = set_timings_udma_ata6( &timing_local[0],
- &timing_local[1],
- mode);
- else if (pmif->kind == controller_sh_ata6)
- ret = set_timings_udma_shasta( &timing_local[0],
- &timing_local[1],
- mode);
- else
- ret = set_timings_udma_ata4(&timing_local[0], mode);
- if (ret)
- return 0;
-
- /* Set feature on drive */
- printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, mode & 0x0f);
- ret = pmac_ide_do_setfeature(drive, mode);
- if (ret) {
- printk(KERN_WARNING "%s: Failed !\n", drive->name);
- return 0;
- }
-
- /* Apply timings to controller */
- *timings = timing_local[0];
- *timings2 = timing_local[1];
-
- return 1;
-}
-
-/*
- * Check what is the best DMA timing setting for the drive and
- * call appropriate functions to apply it.
- */
-static int
-pmac_ide_dma_check(ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
- int enable = 1;
- drive->using_dma = 0;
-
- if (drive->media == ide_floppy)
- enable = 0;
- if (((id->capability & 1) == 0) && !__ide_dma_good_drive(drive))
- enable = 0;
- if (__ide_dma_bad_drive(drive))
- enable = 0;
-
- if (enable) {
- u8 mode = ide_max_dma_mode(drive);
-
- if (mode >= XFER_UDMA_0)
- drive->using_dma = pmac_ide_udma_enable(drive, mode);
- else if (mode >= XFER_MW_DMA_0)
- drive->using_dma = pmac_ide_mdma_enable(drive, mode);
- hwif->OUTB(0, IDE_CONTROL_REG);
- /* Apply settings to controller */
- pmac_ide_do_update_timings(drive);
- }
- return 0;
-}
-
-/*
* Prepare a DMA transfer. We build the DMA table, adjust the timings for
* a read on KeyLargo ATA/66 and mark us as waiting for DMA completion
*/
@@ -2024,7 +1773,6 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->dma_off_quietly = &ide_dma_off_quietly;
hwif->ide_dma_on = &__ide_dma_on;
- hwif->ide_dma_check = &pmac_ide_dma_check;
hwif->dma_setup = &pmac_ide_dma_setup;
hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd;
hwif->dma_start = &pmac_ide_dma_start;
@@ -2035,7 +1783,6 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->dma_timeout = &ide_dma_timeout;
hwif->dma_lost_irq = &pmac_ide_dma_lost_irq;
- hwif->atapi_dma = 1;
switch(pmif->kind) {
case controller_sh_ata6:
hwif->ultra_mask = pmif->cable_80 ? 0x7f : 0x07;
@@ -2058,7 +1805,7 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->mwdma_mask = 0x07;
hwif->swdma_mask = 0x00;
break;
- }
+ }
}
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index 1129f8c3084..25fd0905322 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -7,11 +7,6 @@
* May be copied or modified under the terms of the GNU General Public License
*/
-/*
- * This module provides support for automatic detection and
- * configuration of all PCI IDE interfaces present in a system.
- */
-
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -145,74 +140,36 @@ static int ide_setup_pci_baseregs (struct pci_dev *dev, const char *name)
}
#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
-
-#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
-/*
- * Long lost data from 2.0.34 that is now in 2.0.39
- *
- * This was used in ./drivers/block/triton.c to do DMA Base address setup
- * when PnP failed. Oh the things we forget. I believe this was part
- * of SFF-8038i that has been withdrawn from public access... :-((
- */
-#define DEFAULT_BMIBA 0xe800 /* in case BIOS did not init it */
-#define DEFAULT_BMCRBA 0xcc00 /* VIA's default value */
-#define DEFAULT_BMALIBA 0xd400 /* ALI's default value */
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
-
/**
* ide_get_or_set_dma_base - setup BMIBA
- * @hwif: Interface
+ * @d: IDE port info
+ * @hwif: IDE interface
*
- * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
- * If need be we set up the DMA base. Where a device has a partner that
- * is already in DMA mode we check and enforce IDE simplex rules.
+ * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space.
+ * Where a device has a partner that is already in DMA mode we check
+ * and enforce IDE simplex rules.
*/
-static unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif)
+static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_hwif_t *hwif)
{
unsigned long dma_base = 0;
struct pci_dev *dev = hwif->pci_dev;
-#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
- int second_chance = 0;
-
-second_chance_to_dma:
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
-
if (hwif->mmio)
return hwif->dma_base;
if (hwif->mate && hwif->mate->dma_base) {
dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
} else {
- dma_base = pci_resource_start(dev, 4);
- if (!dma_base) {
- printk(KERN_ERR "%s: dma_base is invalid\n",
- hwif->cds->name);
- }
- }
+ u8 baridx = (d->host_flags & IDE_HFLAG_CS5520) ? 2 : 4;
-#ifdef CONFIG_BLK_DEV_IDEDMA_FORCED
- /* FIXME - should use pci_assign_resource surely */
- if ((!dma_base) && (!second_chance)) {
- unsigned long set_bmiba = 0;
- second_chance++;
- switch(dev->vendor) {
- case PCI_VENDOR_ID_AL:
- set_bmiba = DEFAULT_BMALIBA; break;
- case PCI_VENDOR_ID_VIA:
- set_bmiba = DEFAULT_BMCRBA; break;
- case PCI_VENDOR_ID_INTEL:
- set_bmiba = DEFAULT_BMIBA; break;
- default:
- return dma_base;
- }
- pci_write_config_dword(dev, 0x20, set_bmiba|1);
- goto second_chance_to_dma;
+ dma_base = pci_resource_start(dev, baridx);
+
+ if (dma_base == 0)
+ printk(KERN_ERR "%s: DMA base is invalid\n", d->name);
}
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
- if (dma_base) {
+ if ((d->host_flags & IDE_HFLAG_CS5520) == 0 && dma_base) {
u8 simplex_stat = 0;
dma_base += hwif->channel ? 8 : 0;
@@ -223,13 +180,13 @@ second_chance_to_dma:
case PCI_DEVICE_ID_CMD_643:
case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
case PCI_DEVICE_ID_REVOLUTION:
- simplex_stat = hwif->INB(dma_base + 2);
- hwif->OUTB((simplex_stat&0x60),(dma_base + 2));
- simplex_stat = hwif->INB(dma_base + 2);
+ simplex_stat = inb(dma_base + 2);
+ outb(simplex_stat & 0x60, dma_base + 2);
+ simplex_stat = inb(dma_base + 2);
if (simplex_stat & 0x80) {
printk(KERN_INFO "%s: simplex device: "
- "DMA forced\n",
- hwif->cds->name);
+ "DMA forced\n",
+ d->name);
}
break;
default:
@@ -252,8 +209,8 @@ second_chance_to_dma:
*/
if (hwif->mate && hwif->mate->dma_base) {
printk(KERN_INFO "%s: simplex device: "
- "DMA disabled\n",
- hwif->cds->name);
+ "DMA disabled\n",
+ d->name);
dma_base = 0;
}
}
@@ -263,10 +220,11 @@ second_chance_to_dma:
}
#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
-void ide_setup_pci_noise (struct pci_dev *dev, ide_pci_device_t *d)
+void ide_setup_pci_noise(struct pci_dev *dev, const struct ide_port_info *d)
{
- printk(KERN_INFO "%s: IDE controller at PCI slot %s\n",
- d->name, pci_name(dev));
+ printk(KERN_INFO "%s: IDE controller (0x%04x:0x%04x rev 0x%02x) at "
+ " PCI slot %s\n", d->name, dev->vendor, dev->device,
+ dev->revision, pci_name(dev));
}
EXPORT_SYMBOL_GPL(ide_setup_pci_noise);
@@ -275,15 +233,15 @@ EXPORT_SYMBOL_GPL(ide_setup_pci_noise);
/**
* ide_pci_enable - do PCI enables
* @dev: PCI device
- * @d: IDE pci device data
+ * @d: IDE port info
*
* Enable the IDE PCI device. We attempt to enable the device in full
* but if that fails then we only need BAR4 so we will enable that.
*
* Returns zero on success or an error code
*/
-
-static int ide_pci_enable(struct pci_dev *dev, ide_pci_device_t *d)
+
+static int ide_pci_enable(struct pci_dev *dev, const struct ide_port_info *d)
{
int ret;
@@ -298,9 +256,9 @@ static int ide_pci_enable(struct pci_dev *dev, ide_pci_device_t *d)
}
/*
- * assume all devices can do 32-bit dma for now. we can add a
- * dma mask field to the ide_pci_device_t if we need it (or let
- * lower level driver set the dma mask)
+ * assume all devices can do 32-bit DMA for now, we can add
+ * a DMA mask field to the struct ide_port_info if we need it
+ * (or let lower level driver set the DMA mask)
*/
ret = pci_set_dma_mask(dev, DMA_32BIT_MASK);
if (ret < 0) {
@@ -322,13 +280,13 @@ out:
/**
* ide_pci_configure - configure an unconfigured device
* @dev: PCI device
- * @d: IDE pci device data
+ * @d: IDE port info
*
* Enable and configure the PCI device we have been passed.
* Returns zero on success or an error code.
*/
-
-static int ide_pci_configure(struct pci_dev *dev, ide_pci_device_t *d)
+
+static int ide_pci_configure(struct pci_dev *dev, const struct ide_port_info *d)
{
u16 pcicmd = 0;
/*
@@ -356,15 +314,15 @@ static int ide_pci_configure(struct pci_dev *dev, ide_pci_device_t *d)
/**
* ide_pci_check_iomem - check a register is I/O
- * @dev: pci device
- * @d: ide_pci_device
- * @bar: bar number
+ * @dev: PCI device
+ * @d: IDE port info
+ * @bar: BAR number
*
* Checks if a BAR is configured and points to MMIO space. If so
* print an error and return an error code. Otherwise return 0
*/
-
-static int ide_pci_check_iomem(struct pci_dev *dev, ide_pci_device_t *d, int bar)
+
+static int ide_pci_check_iomem(struct pci_dev *dev, const struct ide_port_info *d, int bar)
{
ulong flags = pci_resource_flags(dev, bar);
@@ -386,7 +344,7 @@ static int ide_pci_check_iomem(struct pci_dev *dev, ide_pci_device_t *d, int bar
/**
* ide_hwif_configure - configure an IDE interface
* @dev: PCI device holding interface
- * @d: IDE pci data
+ * @d: IDE port info
* @mate: Paired interface if any
*
* Perform the initial set up for the hardware interface structure. This
@@ -395,11 +353,12 @@ static int ide_pci_check_iomem(struct pci_dev *dev, ide_pci_device_t *d, int bar
*
* Returns the new hardware interface structure, or NULL on a failure
*/
-
-static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *mate, int port, int irq)
+
+static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port_info *d, ide_hwif_t *mate, int port, int irq)
{
unsigned long ctl = 0, base = 0;
ide_hwif_t *hwif;
+ u8 bootable = (d->host_flags & IDE_HFLAG_BOOTABLE) ? 1 : 0;
if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
/* Possibly we should fail if these checks report true */
@@ -420,23 +379,24 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, ide_pci_device_t *d,
ctl = port ? 0x374 : 0x3f4;
base = port ? 0x170 : 0x1f0;
}
- if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL)
+ if ((hwif = ide_match_hwif(base, bootable, d->name)) == NULL)
return NULL; /* no room in ide_hwifs[] */
if (hwif->io_ports[IDE_DATA_OFFSET] != base ||
hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) {
- memset(&hwif->hw, 0, sizeof(hwif->hw));
-#ifndef IDE_ARCH_OBSOLETE_INIT
- ide_std_init_ports(&hwif->hw, base, (ctl | 2));
- hwif->hw.io_ports[IDE_IRQ_OFFSET] = 0;
+ hw_regs_t hw;
+
+ memset(&hw, 0, sizeof(hw));
+#ifndef CONFIG_IDE_ARCH_OBSOLETE_INIT
+ ide_std_init_ports(&hw, base, ctl | 2);
#else
- ide_init_hwif_ports(&hwif->hw, base, (ctl | 2), NULL);
+ ide_init_hwif_ports(&hw, base, ctl | 2, NULL);
#endif
- memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
+ memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports));
hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
}
- hwif->chipset = ide_pci;
+ hwif->chipset = d->chipset ? d->chipset : ide_pci;
hwif->pci_dev = dev;
- hwif->cds = (struct ide_pci_device_s *) d;
+ hwif->cds = d;
hwif->channel = port;
if (!hwif->irq)
@@ -451,35 +411,30 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, ide_pci_device_t *d,
/**
* ide_hwif_setup_dma - configure DMA interface
* @dev: PCI device
- * @d: IDE pci data
- * @hwif: Hardware interface we are configuring
+ * @d: IDE port info
+ * @hwif: IDE interface
*
* Set up the DMA base for the interface. Enable the master bits as
* necessary and attempt to bring the device DMA into a ready to use
* state
*/
-
-#ifndef CONFIG_BLK_DEV_IDEDMA_PCI
-static void ide_hwif_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif)
-{
-}
-#else
-static void ide_hwif_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif)
+
+static void ide_hwif_setup_dma(struct pci_dev *dev, const struct ide_port_info *d, ide_hwif_t *hwif)
{
+#ifdef CONFIG_BLK_DEV_IDEDMA_PCI
u16 pcicmd;
+
pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
- if ((d->autodma == AUTODMA) ||
+ if ((d->host_flags & IDE_HFLAG_NO_AUTODMA) == 0 ||
((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
(dev->class & 0x80))) {
- unsigned long dma_base = ide_get_or_set_dma_base(hwif);
+ unsigned long dma_base = ide_get_or_set_dma_base(d, hwif);
if (dma_base && !(pcicmd & PCI_COMMAND_MASTER)) {
/*
* Set up BM-DMA capability
* (PnP BIOS should have done this)
*/
- /* default DMA off if we had to configure it here */
- hwif->autodma = 0;
pci_set_master(dev);
if (pci_read_config_word(dev, PCI_COMMAND, &pcicmd) || !(pcicmd & PCI_COMMAND_MASTER)) {
printk(KERN_ERR "%s: %s error updating PCICMD\n",
@@ -498,13 +453,13 @@ static void ide_hwif_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwi
"(BIOS)\n", hwif->name, d->name);
}
}
-}
#endif /* CONFIG_BLK_DEV_IDEDMA_PCI*/
+}
/**
* ide_setup_pci_controller - set up IDE PCI
* @dev: PCI device
- * @d: IDE PCI data
+ * @d: IDE port info
* @noisy: verbose flag
* @config: returned as 1 if we configured the hardware
*
@@ -512,11 +467,10 @@ static void ide_hwif_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwi
* up the PCI side of the device, checks that the device is enabled
* and enables it if need be
*/
-
-static int ide_setup_pci_controller(struct pci_dev *dev, ide_pci_device_t *d, int noisy, int *config)
+
+static int ide_setup_pci_controller(struct pci_dev *dev, const struct ide_port_info *d, int noisy, int *config)
{
int ret;
- u32 class_rev;
u16 pcicmd;
if (noisy)
@@ -539,10 +493,6 @@ static int ide_setup_pci_controller(struct pci_dev *dev, ide_pci_device_t *d, in
printk(KERN_INFO "%s: device enabled (Linux)\n", d->name);
}
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
- class_rev &= 0xff;
- if (noisy)
- printk(KERN_INFO "%s: chipset revision %d\n", d->name, class_rev);
out:
return ret;
}
@@ -550,9 +500,9 @@ out:
/**
* ide_pci_setup_ports - configure ports/devices on PCI IDE
* @dev: PCI device
- * @d: IDE pci device info
+ * @d: IDE port info
* @pciirq: IRQ line
- * @index: ata index to update
+ * @idx: ATA index table to update
*
* Scan the interfaces attached to this device and do any
* necessary per port setup. Attach the devices and ask the
@@ -562,26 +512,25 @@ out:
* but is also used directly as a helper function by some controllers
* where the chipset setup is not the default PCI IDE one.
*/
-
-void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int pciirq, ata_index_t *index)
+
+void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int pciirq, u8 *idx)
{
int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
- int at_least_one_hwif_enabled = 0;
ide_hwif_t *hwif, *mate = NULL;
u8 tmp;
- index->all = 0xf0f0;
-
/*
* Set up the IDE ports
*/
-
+
for (port = 0; port < channels; ++port) {
- ide_pci_enablebit_t *e = &(d->enablebits[port]);
-
+ const ide_pci_enablebit_t *e = &(d->enablebits[port]);
+
if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
- (tmp & e->mask) != e->val))
+ (tmp & e->mask) != e->val)) {
+ printk(KERN_INFO "%s: IDE port disabled\n", d->name);
continue; /* port not enabled */
+ }
if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
continue;
@@ -589,27 +538,49 @@ void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int pciirq, a
/* setup proper ancestral information */
hwif->gendev.parent = &dev->dev;
- if (hwif->channel) {
- index->b.high = hwif->index;
- } else {
- index->b.low = hwif->index;
- }
+ *(idx + port) = hwif->index;
if (d->init_iops)
d->init_iops(hwif);
- if (d->autodma == NODMA)
- goto bypass_legacy_dma;
-
- if(d->init_setup_dma)
- d->init_setup_dma(dev, d, hwif);
- else
+ if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0)
ide_hwif_setup_dma(dev, d, hwif);
-bypass_legacy_dma:
+
+ if ((!hwif->irq && (d->host_flags & IDE_HFLAG_LEGACY_IRQS)) ||
+ (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
+ hwif->irq = port ? 15 : 14;
+
+ hwif->fixup = d->fixup;
+
hwif->host_flags = d->host_flags;
hwif->pio_mask = d->pio_mask;
+ if ((d->host_flags & IDE_HFLAG_SERIALIZE) && hwif->mate)
+ hwif->mate->serialized = hwif->serialized = 1;
+
+ if (d->host_flags & IDE_HFLAG_IO_32BIT) {
+ hwif->drives[0].io_32bit = 1;
+ hwif->drives[1].io_32bit = 1;
+ }
+
+ if (d->host_flags & IDE_HFLAG_UNMASK_IRQS) {
+ hwif->drives[0].unmask = 1;
+ hwif->drives[1].unmask = 1;
+ }
+
+ if (hwif->dma_base) {
+ hwif->swdma_mask = d->swdma_mask;
+ hwif->mwdma_mask = d->mwdma_mask;
+ hwif->ultra_mask = d->udma_mask;
+ }
+
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ if (d->host_flags & IDE_HFLAG_RQSIZE_256)
+ hwif->rqsize = 256;
+
if (d->init_hwif)
/* Call chipset-specific routine
* for each enabled hwif
@@ -617,10 +588,7 @@ bypass_legacy_dma:
d->init_hwif(hwif);
mate = hwif;
- at_least_one_hwif_enabled = 1;
}
- if (!at_least_one_hwif_enabled)
- printk(KERN_INFO "%s: neither IDE port enabled (BIOS)\n", d->name);
}
EXPORT_SYMBOL_GPL(ide_pci_setup_ports);
@@ -632,13 +600,13 @@ EXPORT_SYMBOL_GPL(ide_pci_setup_ports);
*
* One thing that is not standardized is the location of the
* primary/secondary interface "enable/disable" bits. For chipsets that
- * we "know" about, this information is in the ide_pci_device_t struct;
+ * we "know" about, this information is in the struct ide_port_info;
* for all other chipsets, we just assume both interfaces are enabled.
*/
-static int do_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d,
- ata_index_t *index, u8 noisy)
+static int do_ide_setup_pci_device(struct pci_dev *dev,
+ const struct ide_port_info *d,
+ u8 *idx, u8 noisy)
{
- static ata_index_t ata_index = { .b = { .low = 0xff, .high = 0xff } };
int tried_config = 0;
int pciirq, ret;
@@ -688,51 +656,35 @@ static int do_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d,
/* FIXME: silent failure can happen */
- *index = ata_index;
- ide_pci_setup_ports(dev, d, pciirq, index);
+ ide_pci_setup_ports(dev, d, pciirq, idx);
out:
return ret;
}
-int ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t *d)
+int ide_setup_pci_device(struct pci_dev *dev, const struct ide_port_info *d)
{
- ide_hwif_t *hwif = NULL, *mate = NULL;
- ata_index_t index_list;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
int ret;
- ret = do_ide_setup_pci_device(dev, d, &index_list, 1);
- if (ret < 0)
- goto out;
-
- if ((index_list.b.low & 0xf0) != 0xf0)
- hwif = &ide_hwifs[index_list.b.low];
- if ((index_list.b.high & 0xf0) != 0xf0)
- mate = &ide_hwifs[index_list.b.high];
+ ret = do_ide_setup_pci_device(dev, d, &idx[0], 1);
- if (hwif)
- probe_hwif_init_with_fixup(hwif, d->fixup);
- if (mate)
- probe_hwif_init_with_fixup(mate, d->fixup);
+ if (ret >= 0)
+ ide_device_add(idx);
- if (hwif)
- ide_proc_register_port(hwif);
- if (mate)
- ide_proc_register_port(mate);
-out:
return ret;
}
EXPORT_SYMBOL_GPL(ide_setup_pci_device);
int ide_setup_pci_devices(struct pci_dev *dev1, struct pci_dev *dev2,
- ide_pci_device_t *d)
+ const struct ide_port_info *d)
{
struct pci_dev *pdev[] = { dev1, dev2 };
- ata_index_t index_list[2];
int ret, i;
+ u8 idx[4] = { 0xff, 0xff, 0xff, 0xff };
for (i = 0; i < 2; i++) {
- ret = do_ide_setup_pci_device(pdev[i], d, index_list + i, !i);
+ ret = do_ide_setup_pci_device(pdev[i], d, &idx[i*2], !i);
/*
* FIXME: Mom, mom, they stole me the helper function to undo
* do_ide_setup_pci_device() on the first device!
@@ -741,25 +693,7 @@ int ide_setup_pci_devices(struct pci_dev *dev1, struct pci_dev *dev2,
goto out;
}
- for (i = 0; i < 2; i++) {
- u8 idx[2] = { index_list[i].b.low, index_list[i].b.high };
- int j;
-
- for (j = 0; j < 2; j++) {
- if ((idx[j] & 0xf0) != 0xf0)
- probe_hwif_init(ide_hwifs + idx[j]);
- }
- }
-
- for (i = 0; i < 2; i++) {
- u8 idx[2] = { index_list[i].b.low, index_list[i].b.high };
- int j;
-
- for (j = 0; j < 2; j++) {
- if ((idx[j] & 0xf0) != 0xf0)
- ide_proc_register_port(ide_hwifs + idx[j]);
- }
- }
+ ide_device_add(idx);
out:
return ret;
}
@@ -784,9 +718,6 @@ static LIST_HEAD(ide_pci_drivers);
* hands the controllers off to the core PCI code to do the rest of
* the work.
*
- * The driver_data of the driver table must point to an ide_pci_device_t
- * describing the interface.
- *
* Returns are the same as for pci_register_driver
*/
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
index d08166bda1c..e8122def164 100644
--- a/drivers/ieee1394/csr1212.c
+++ b/drivers/ieee1394/csr1212.c
@@ -218,12 +218,10 @@ static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
if (!kv)
return NULL;
+ atomic_set(&kv->refcnt, 1);
kv->key.type = type;
kv->key.id = key;
-
kv->associate = NULL;
- kv->refcnt = 1;
-
kv->next = NULL;
kv->prev = NULL;
kv->offset = 0;
@@ -326,12 +324,13 @@ void csr1212_associate_keyval(struct csr1212_keyval *kv,
if (kv->associate)
csr1212_release_keyval(kv->associate);
- associate->refcnt++;
+ csr1212_keep_keyval(associate);
kv->associate = associate;
}
-int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
- struct csr1212_keyval *kv)
+static int __csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
+ struct csr1212_keyval *kv,
+ bool keep_keyval)
{
struct csr1212_dentry *dentry;
@@ -341,10 +340,10 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
if (!dentry)
return -ENOMEM;
+ if (keep_keyval)
+ csr1212_keep_keyval(kv);
dentry->kv = kv;
- kv->refcnt++;
-
dentry->next = NULL;
dentry->prev = dir->value.directory.dentries_tail;
@@ -358,6 +357,12 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
return CSR1212_SUCCESS;
}
+int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
+ struct csr1212_keyval *kv)
+{
+ return __csr1212_attach_keyval_to_directory(dir, kv, true);
+}
+
#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
(&((kv)->value.leaf.data[1]))
@@ -483,15 +488,18 @@ void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
/* This function is used to free the memory taken by a keyval. If the given
* keyval is a directory type, then any keyvals contained in that directory
- * will be destroyed as well if their respective refcnts are 0. By means of
+ * will be destroyed as well if noone holds a reference on them. By means of
* list manipulation, this routine will descend a directory structure in a
* non-recursive manner. */
-static void csr1212_destroy_keyval(struct csr1212_keyval *kv)
+void csr1212_release_keyval(struct csr1212_keyval *kv)
{
struct csr1212_keyval *k, *a;
struct csr1212_dentry dentry;
struct csr1212_dentry *head, *tail;
+ if (!atomic_dec_and_test(&kv->refcnt))
+ return;
+
dentry.kv = kv;
dentry.next = NULL;
dentry.prev = NULL;
@@ -503,9 +511,8 @@ static void csr1212_destroy_keyval(struct csr1212_keyval *kv)
k = head->kv;
while (k) {
- k->refcnt--;
-
- if (k->refcnt > 0)
+ /* must not dec_and_test kv->refcnt again */
+ if (k != kv && !atomic_dec_and_test(&k->refcnt))
break;
a = k->associate;
@@ -536,14 +543,6 @@ static void csr1212_destroy_keyval(struct csr1212_keyval *kv)
}
}
-void csr1212_release_keyval(struct csr1212_keyval *kv)
-{
- if (kv->refcnt > 1)
- kv->refcnt--;
- else
- csr1212_destroy_keyval(kv);
-}
-
void csr1212_destroy_csr(struct csr1212_csr *csr)
{
struct csr1212_csr_rom_cache *c, *oc;
@@ -1126,6 +1125,7 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
int ret = CSR1212_SUCCESS;
struct csr1212_keyval *k = NULL;
u32 offset;
+ bool keep_keyval = true;
switch (CSR1212_KV_KEY_TYPE(ki)) {
case CSR1212_KV_TYPE_IMMEDIATE:
@@ -1135,8 +1135,8 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
ret = -ENOMEM;
goto out;
}
-
- k->refcnt = 0; /* Don't keep local reference when parsing. */
+ /* Don't keep local reference when parsing. */
+ keep_keyval = false;
break;
case CSR1212_KV_TYPE_CSR_OFFSET:
@@ -1146,7 +1146,8 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
ret = -ENOMEM;
goto out;
}
- k->refcnt = 0; /* Don't keep local reference when parsing. */
+ /* Don't keep local reference when parsing. */
+ keep_keyval = false;
break;
default:
@@ -1174,8 +1175,10 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
ret = -ENOMEM;
goto out;
}
- k->refcnt = 0; /* Don't keep local reference when parsing. */
- k->valid = 0; /* Contents not read yet so it's not valid. */
+ /* Don't keep local reference when parsing. */
+ keep_keyval = false;
+ /* Contents not read yet so it's not valid. */
+ k->valid = 0;
k->offset = offset;
k->prev = dir;
@@ -1183,7 +1186,7 @@ csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
dir->next->prev = k;
dir->next = k;
}
- ret = csr1212_attach_keyval_to_directory(dir, k);
+ ret = __csr1212_attach_keyval_to_directory(dir, k, keep_keyval);
out:
if (ret != CSR1212_SUCCESS && k != NULL)
free_keyval(k);
diff --git a/drivers/ieee1394/csr1212.h b/drivers/ieee1394/csr1212.h
index df909ce6630..043039fc63e 100644
--- a/drivers/ieee1394/csr1212.h
+++ b/drivers/ieee1394/csr1212.h
@@ -32,6 +32,7 @@
#include <linux/types.h>
#include <linux/slab.h>
+#include <asm/atomic.h>
#define CSR1212_MALLOC(size) kmalloc((size), GFP_KERNEL)
#define CSR1212_FREE(ptr) kfree(ptr)
@@ -149,7 +150,7 @@ struct csr1212_keyval {
struct csr1212_directory directory;
} value;
struct csr1212_keyval *associate;
- int refcnt;
+ atomic_t refcnt;
/* used in generating and/or parsing CSR image */
struct csr1212_keyval *next, *prev; /* flat list of CSR elements */
@@ -350,7 +351,8 @@ csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv);
* need for code to retain a keyval that has been parsed. */
static inline void csr1212_keep_keyval(struct csr1212_keyval *kv)
{
- kv->refcnt++;
+ atomic_inc(&kv->refcnt);
+ smp_mb__after_atomic_inc();
}
diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c
index 45d60558192..7c4eb39b702 100644
--- a/drivers/ieee1394/dma.c
+++ b/drivers/ieee1394/dma.c
@@ -12,7 +12,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include "dma.h"
@@ -103,16 +103,15 @@ int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
goto err;
}
- /* just to be safe - this will become unnecessary once sglist->address goes away */
- memset(dma->sglist, 0, dma->n_pages * sizeof(*dma->sglist));
+ sg_init_table(dma->sglist, dma->n_pages);
/* fill scatter/gather list with pages */
for (i = 0; i < dma->n_pages; i++) {
unsigned long va =
(unsigned long)dma->kvirt + (i << PAGE_SHIFT);
- dma->sglist[i].page = vmalloc_to_page((void *)va);
- dma->sglist[i].length = PAGE_SIZE;
+ sg_set_page(&dma->sglist[i], vmalloc_to_page((void *)va),
+ PAGE_SIZE, 0);
}
/* map sglist to the IOMMU */
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 3a9d7e2d4de..b166b3575fa 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -159,14 +159,16 @@ MODULE_PARM_DESC(max_partial_datagrams,
static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len);
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len);
static int ether1394_rebuild_header(struct sk_buff *skb);
-static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr);
-static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh);
+static int ether1394_header_parse(const struct sk_buff *skb,
+ unsigned char *haddr);
+static int ether1394_header_cache(const struct neighbour *neigh,
+ struct hh_cache *hh);
static void ether1394_header_cache_update(struct hh_cache *hh,
- struct net_device *dev,
- unsigned char *haddr);
+ const struct net_device *dev,
+ const unsigned char *haddr);
static int ether1394_tx(struct sk_buff *skb, struct net_device *dev);
static void ether1394_iso(struct hpsb_iso *iso);
@@ -506,6 +508,14 @@ static void ether1394_reset_priv(struct net_device *dev, int set_mtu)
spin_unlock_irqrestore(&priv->lock, flags);
}
+static const struct header_ops ether1394_header_ops = {
+ .create = ether1394_header,
+ .rebuild = ether1394_rebuild_header,
+ .cache = ether1394_header_cache,
+ .cache_update = ether1394_header_cache_update,
+ .parse = ether1394_header_parse,
+};
+
static void ether1394_init_dev(struct net_device *dev)
{
dev->open = ether1394_open;
@@ -515,11 +525,7 @@ static void ether1394_init_dev(struct net_device *dev)
dev->tx_timeout = ether1394_tx_timeout;
dev->change_mtu = ether1394_change_mtu;
- dev->hard_header = ether1394_header;
- dev->rebuild_header = ether1394_rebuild_header;
- dev->hard_header_cache = ether1394_header_cache;
- dev->header_cache_update= ether1394_header_cache_update;
- dev->hard_header_parse = ether1394_header_parse;
+ dev->header_ops = &ether1394_header_ops;
SET_ETHTOOL_OPS(dev, &ethtool_ops);
@@ -598,7 +604,6 @@ static void ether1394_add_host(struct hpsb_host *host)
goto out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &host->device);
priv = netdev_priv(dev);
@@ -711,8 +716,8 @@ static void ether1394_host_reset(struct hpsb_host *host)
* saddr=NULL means use device source address
* daddr=NULL means leave destination address (eg unresolved arp). */
static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
struct eth1394hdr *eth =
(struct eth1394hdr *)skb_push(skb, ETH1394_HLEN);
@@ -752,15 +757,15 @@ static int ether1394_rebuild_header(struct sk_buff *skb)
return 0;
}
-static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr)
+static int ether1394_header_parse(const struct sk_buff *skb,
+ unsigned char *haddr)
{
- struct net_device *dev = skb->dev;
-
- memcpy(haddr, dev->dev_addr, ETH1394_ALEN);
+ memcpy(haddr, skb->dev->dev_addr, ETH1394_ALEN);
return ETH1394_ALEN;
}
-static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+static int ether1394_header_cache(const struct neighbour *neigh,
+ struct hh_cache *hh)
{
unsigned short type = hh->hh_type;
struct net_device *dev = neigh->dev;
@@ -779,8 +784,8 @@ static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh)
/* Called by Address Resolution module to notify changes in address. */
static void ether1394_header_cache_update(struct hh_cache *hh,
- struct net_device *dev,
- unsigned char * haddr)
+ const struct net_device *dev,
+ const unsigned char * haddr)
{
memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len);
}
@@ -900,8 +905,8 @@ static u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
}
/* Now add the ethernet header. */
- if (dev->hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL,
- skb->len) >= 0)
+ if (dev_hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL,
+ skb->len) >= 0)
ret = ether1394_type_trans(skb, dev);
return ret;
@@ -1148,8 +1153,6 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
pdg->sz++;
lh = find_partial_datagram(pdgl, dgl);
} else {
- struct partial_datagram *pd;
-
pd = list_entry(lh, struct partial_datagram, list);
if (fragment_overlap(&pd->frag_info, fg_off, fg_len)) {
@@ -1217,23 +1220,19 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
priv->stats.rx_errors++;
priv->stats.rx_dropped++;
dev_kfree_skb_any(skb);
- goto bad_proto;
- }
-
- if (netif_rx(skb) == NET_RX_DROP) {
+ } else if (netif_rx(skb) == NET_RX_DROP) {
priv->stats.rx_errors++;
priv->stats.rx_dropped++;
- goto bad_proto;
+ } else {
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += skb->len;
}
- /* Statistics */
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += skb->len;
+ spin_unlock_irqrestore(&priv->lock, flags);
bad_proto:
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
- spin_unlock_irqrestore(&priv->lock, flags);
dev->last_rx = jiffies;
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index 98fd985a32f..36c747b277d 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -488,7 +488,7 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
highlevel_host_reset(host);
}
-static spinlock_t pending_packets_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(pending_packets_lock);
/**
* hpsb_packet_sent - notify core of sending a packet
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
index c39c70a8aa9..67798932095 100644
--- a/drivers/ieee1394/ieee1394_transactions.c
+++ b/drivers/ieee1394/ieee1394_transactions.c
@@ -235,7 +235,6 @@ int hpsb_packet_success(struct hpsb_packet *packet)
packet->node_id);
return -EAGAIN;
}
- BUG();
case ACK_BUSY_X:
case ACK_BUSY_A:
@@ -282,7 +281,6 @@ int hpsb_packet_success(struct hpsb_packet *packet)
packet->ack_code, packet->node_id, packet->tcode);
return -EAGAIN;
}
- BUG();
}
struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 2ffd53461db..90dc75be341 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -153,8 +153,7 @@ struct host_info {
};
static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size);
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env);
static void nodemgr_resume_ne(struct node_entry *ne);
static void nodemgr_remove_ne(struct node_entry *ne);
static struct node_entry *find_entry_by_guid(u64 guid);
@@ -1015,13 +1014,13 @@ static struct unit_directory *nodemgr_process_unit_directory
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
switch (last_key_id) {
case CSR1212_KV_ID_VENDOR:
- ud->vendor_name_kv = kv;
csr1212_keep_keyval(kv);
+ ud->vendor_name_kv = kv;
break;
case CSR1212_KV_ID_MODEL:
- ud->model_name_kv = kv;
csr1212_keep_keyval(kv);
+ ud->model_name_kv = kv;
break;
}
@@ -1113,7 +1112,7 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
{
unsigned int ud_id = 0;
struct csr1212_dentry *dentry;
- struct csr1212_keyval *kv;
+ struct csr1212_keyval *kv, *vendor_name_kv = NULL;
u8 last_key_id = 0;
ne->needs_probe = 0;
@@ -1140,8 +1139,8 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
- ne->vendor_name_kv = kv;
csr1212_keep_keyval(kv);
+ vendor_name_kv = kv;
}
}
break;
@@ -1150,22 +1149,22 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
}
if (ne->vendor_name_kv) {
- int error = device_create_file(&ne->device,
- &dev_attr_ne_vendor_name_kv);
-
- if (error && error != -EEXIST)
+ kv = ne->vendor_name_kv;
+ ne->vendor_name_kv = vendor_name_kv;
+ csr1212_release_keyval(kv);
+ } else if (vendor_name_kv) {
+ ne->vendor_name_kv = vendor_name_kv;
+ if (device_create_file(&ne->device,
+ &dev_attr_ne_vendor_name_kv) != 0)
HPSB_ERR("Failed to add sysfs attribute");
}
}
#ifdef CONFIG_HOTPLUG
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct unit_directory *ud;
- int i = 0;
- int length = 0;
int retval = 0;
/* ieee1394:venNmoNspNverN */
char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
@@ -1180,9 +1179,7 @@ static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
#define PUT_ENVP(fmt,val) \
do { \
- retval = add_uevent_var(envp, num_envp, &i, \
- buffer, buffer_size, &length, \
- fmt, val); \
+ retval = add_uevent_var(env, fmt, val); \
if (retval) \
return retval; \
} while (0)
@@ -1201,15 +1198,12 @@ do { \
#undef PUT_ENVP
- envp[i] = NULL;
-
return 0;
}
#else
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
@@ -1721,7 +1715,8 @@ static int nodemgr_host_thread(void *__hi)
* to make sure things settle down. */
g = get_hpsb_generation(host);
for (i = 0; i < 4 ; i++) {
- if (msleep_interruptible(63) || kthread_should_stop())
+ msleep_interruptible(63);
+ if (kthread_should_stop())
goto exit;
/* Now get the generation in which the node ID's we collect
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index d1a5bcdb5e0..8af01ab30cc 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -121,16 +121,6 @@ static int bit_getsda(void *data)
return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000010;
}
-static int bit_reg(struct i2c_client *client)
-{
- return 0;
-}
-
-static int bit_unreg(struct i2c_client *client)
-{
- return 0;
-}
-
static struct i2c_algo_bit_data bit_data = {
.setsda = bit_setsda,
.setscl = bit_setscl,
@@ -140,14 +130,6 @@ static struct i2c_algo_bit_data bit_data = {
.timeout = 100,
};
-static struct i2c_adapter bit_ops = {
- .id = 0xAA, //FIXME: probably we should get an id in i2c-id.h
- .client_register = bit_reg,
- .client_unregister = bit_unreg,
- .name = "PCILynx I2C",
-};
-
-
/*
* PCL handling functions.
@@ -765,7 +747,6 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
} else {
struct ti_pcl pcl;
u32 ack;
- struct hpsb_packet *packet;
PRINT(KERN_INFO, lynx->id, "cancelling async packet, that was already in PCL");
@@ -1436,9 +1417,11 @@ static int __devinit add_card(struct pci_dev *dev,
struct i2c_algo_bit_data i2c_adapter_data;
error = -ENOMEM;
- i2c_ad = kmemdup(&bit_ops, sizeof(*i2c_ad), GFP_KERNEL);
+ i2c_ad = kzalloc(sizeof(*i2c_ad), GFP_KERNEL);
if (!i2c_ad) FAIL("failed to allocate I2C adapter memory");
+ i2c_ad->id = I2C_HW_B_PCILYNX;
+ strlcpy(i2c_ad->name, "PCILynx I2C", sizeof(i2c_ad->name));
i2c_adapter_data = bit_data;
i2c_ad->algo_data = &i2c_adapter_data;
i2c_adapter_data.data = lynx;
@@ -1465,13 +1448,11 @@ static int __devinit add_card(struct pci_dev *dev,
{ 0x50, I2C_M_RD, 20, (unsigned char*) lynx->bus_info_block }
};
- /* we use i2c_transfer, because i2c_smbus_read_block_data does not work properly and we
- do it more efficiently in one transaction rather then using several reads */
+ /* we use i2c_transfer because we have no i2c_client
+ at hand */
if (i2c_transfer(i2c_ad, msg, 2) < 0) {
PRINT(KERN_ERR, lynx->id, "unable to read bus info block from i2c");
} else {
- int i;
-
PRINT(KERN_INFO, lynx->id, "got bus info block from serial eeprom");
/* FIXME: probably we shoud rewrite the max_rec, max_ROM(1394a),
* generation(1394a) and link_spd(1394a) field and recalculate
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index a81ba8fca0d..b83d254bc86 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -71,11 +71,11 @@
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
+#include <linux/scatterlist.h>
#include <asm/byteorder.h>
#include <asm/errno.h>
#include <asm/param.h>
-#include <asm/scatterlist.h>
#include <asm/system.h>
#include <asm/types.h>
@@ -242,6 +242,8 @@ static int sbp2_max_speed_and_size(struct sbp2_lu *);
static const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xA, 0xB, 0xC };
+static DEFINE_RWLOCK(sbp2_hi_logical_units_lock);
+
static struct hpsb_highlevel sbp2_highlevel = {
.name = SBP2_DEVICE_NAME,
.host_reset = sbp2_host_reset,
@@ -732,6 +734,7 @@ static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
struct sbp2_fwhost_info *hi;
struct Scsi_Host *shost = NULL;
struct sbp2_lu *lu = NULL;
+ unsigned long flags;
lu = kzalloc(sizeof(*lu), GFP_KERNEL);
if (!lu) {
@@ -784,7 +787,9 @@ static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
lu->hi = hi;
+ write_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
list_add_tail(&lu->lu_list, &hi->logical_units);
+ write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
/* Register the status FIFO address range. We could use the same FIFO
* for targets at different nodes. However we need different FIFOs per
@@ -828,16 +833,20 @@ static void sbp2_host_reset(struct hpsb_host *host)
{
struct sbp2_fwhost_info *hi;
struct sbp2_lu *lu;
+ unsigned long flags;
hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
if (!hi)
return;
+
+ read_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
list_for_each_entry(lu, &hi->logical_units, lu_list)
if (likely(atomic_read(&lu->state) !=
SBP2LU_STATE_IN_SHUTDOWN)) {
atomic_set(&lu->state, SBP2LU_STATE_IN_RESET);
scsi_block_requests(lu->shost);
}
+ read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
}
static int sbp2_start_device(struct sbp2_lu *lu)
@@ -919,6 +928,7 @@ alloc_fail:
static void sbp2_remove_device(struct sbp2_lu *lu)
{
struct sbp2_fwhost_info *hi;
+ unsigned long flags;
if (!lu)
return;
@@ -933,7 +943,9 @@ static void sbp2_remove_device(struct sbp2_lu *lu)
flush_scheduled_work();
sbp2util_remove_command_orb_pool(lu, hi->host);
+ write_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
list_del(&lu->lu_list);
+ write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
if (lu->login_response)
dma_free_coherent(hi->host->device.parent,
@@ -1454,7 +1466,7 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
cmd->dma_size = sgpnt[0].length;
cmd->dma_type = CMD_DMA_PAGE;
cmd->cmd_dma = dma_map_page(hi->host->device.parent,
- sgpnt[0].page, sgpnt[0].offset,
+ sg_page(&sgpnt[0]), sgpnt[0].offset,
cmd->dma_size, cmd->dma_dir);
orb->data_descriptor_lo = cmd->cmd_dma;
@@ -1707,6 +1719,7 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
}
/* Find the unit which wrote the status. */
+ read_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
list_for_each_entry(lu_tmp, &hi->logical_units, lu_list) {
if (lu_tmp->ne->nodeid == nodeid &&
lu_tmp->status_fifo_addr == addr) {
@@ -1714,6 +1727,8 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
break;
}
}
+ read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
+
if (unlikely(!lu)) {
SBP2_ERR("lu is NULL - device is gone?");
return RCODE_ADDRESS_ERROR;
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index c5c33d35f87..5381c80de10 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -161,8 +161,7 @@ static void addr_send_arp(struct sockaddr_in *dst_in)
if (ip_route_output_key(&rt, &fl))
return;
- arp_send(ARPOP_REQUEST, ETH_P_ARP, rt->rt_gateway, rt->idev->dev,
- rt->rt_src, NULL, rt->idev->dev->dev_addr, NULL);
+ neigh_event_send(rt->u.dst.neighbour, NULL);
ip_rt_put(rt);
}
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 4df269f5d9a..2e39236d189 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -2219,6 +2219,9 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id,
{
struct cm_id_private *cm_id_priv;
struct ib_mad_send_buf *msg;
+ enum ib_cm_state cm_state;
+ enum ib_cm_lap_state lap_state;
+ enum cm_msg_response msg_response;
void *data;
unsigned long flags;
int ret;
@@ -2235,48 +2238,40 @@ int ib_send_cm_mra(struct ib_cm_id *cm_id,
spin_lock_irqsave(&cm_id_priv->lock, flags);
switch(cm_id_priv->id.state) {
case IB_CM_REQ_RCVD:
- ret = cm_alloc_msg(cm_id_priv, &msg);
- if (ret)
- goto error1;
-
- cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
- CM_MSG_RESPONSE_REQ, service_timeout,
- private_data, private_data_len);
- ret = ib_post_send_mad(msg, NULL);
- if (ret)
- goto error2;
- cm_id->state = IB_CM_MRA_REQ_SENT;
+ cm_state = IB_CM_MRA_REQ_SENT;
+ lap_state = cm_id->lap_state;
+ msg_response = CM_MSG_RESPONSE_REQ;
break;
case IB_CM_REP_RCVD:
- ret = cm_alloc_msg(cm_id_priv, &msg);
- if (ret)
- goto error1;
-
- cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
- CM_MSG_RESPONSE_REP, service_timeout,
- private_data, private_data_len);
- ret = ib_post_send_mad(msg, NULL);
- if (ret)
- goto error2;
- cm_id->state = IB_CM_MRA_REP_SENT;
+ cm_state = IB_CM_MRA_REP_SENT;
+ lap_state = cm_id->lap_state;
+ msg_response = CM_MSG_RESPONSE_REP;
break;
case IB_CM_ESTABLISHED:
+ cm_state = cm_id->state;
+ lap_state = IB_CM_MRA_LAP_SENT;
+ msg_response = CM_MSG_RESPONSE_OTHER;
+ break;
+ default:
+ ret = -EINVAL;
+ goto error1;
+ }
+
+ if (!(service_timeout & IB_CM_MRA_FLAG_DELAY)) {
ret = cm_alloc_msg(cm_id_priv, &msg);
if (ret)
goto error1;
cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
- CM_MSG_RESPONSE_OTHER, service_timeout,
+ msg_response, service_timeout,
private_data, private_data_len);
ret = ib_post_send_mad(msg, NULL);
if (ret)
goto error2;
- cm_id->lap_state = IB_CM_MRA_LAP_SENT;
- break;
- default:
- ret = -EINVAL;
- goto error1;
}
+
+ cm_id->state = cm_state;
+ cm_id->lap_state = lap_state;
cm_id_priv->service_timeout = service_timeout;
cm_set_private_data(cm_id_priv, data, private_data_len);
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 9ffb9987450..0751697ef98 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -52,6 +52,7 @@ MODULE_LICENSE("Dual BSD/GPL");
#define CMA_CM_RESPONSE_TIMEOUT 20
#define CMA_MAX_CM_RETRIES 15
+#define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24)
static void cma_add_one(struct ib_device *device);
static void cma_remove_one(struct ib_device *device);
@@ -113,13 +114,16 @@ struct rdma_id_private {
struct rdma_bind_list *bind_list;
struct hlist_node node;
- struct list_head list;
- struct list_head listen_list;
+ struct list_head list; /* listen_any_list or cma_device.list */
+ struct list_head listen_list; /* per device listens */
struct cma_device *cma_dev;
struct list_head mc_list;
+ int internal_id;
enum cma_state state;
spinlock_t lock;
+ struct mutex qp_mutex;
+
struct completion comp;
atomic_t refcount;
wait_queue_head_t wait_remove;
@@ -138,6 +142,7 @@ struct rdma_id_private {
u32 qkey;
u32 qp_num;
u8 srq;
+ u8 tos;
};
struct cma_multicast {
@@ -387,6 +392,7 @@ struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
id_priv->id.event_handler = event_handler;
id_priv->id.ps = ps;
spin_lock_init(&id_priv->lock);
+ mutex_init(&id_priv->qp_mutex);
init_completion(&id_priv->comp);
atomic_set(&id_priv->refcount, 1);
init_waitqueue_head(&id_priv->wait_remove);
@@ -472,61 +478,86 @@ EXPORT_SYMBOL(rdma_create_qp);
void rdma_destroy_qp(struct rdma_cm_id *id)
{
- ib_destroy_qp(id->qp);
+ struct rdma_id_private *id_priv;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ mutex_lock(&id_priv->qp_mutex);
+ ib_destroy_qp(id_priv->id.qp);
+ id_priv->id.qp = NULL;
+ mutex_unlock(&id_priv->qp_mutex);
}
EXPORT_SYMBOL(rdma_destroy_qp);
-static int cma_modify_qp_rtr(struct rdma_cm_id *id)
+static int cma_modify_qp_rtr(struct rdma_id_private *id_priv)
{
struct ib_qp_attr qp_attr;
int qp_attr_mask, ret;
- if (!id->qp)
- return 0;
+ mutex_lock(&id_priv->qp_mutex);
+ if (!id_priv->id.qp) {
+ ret = 0;
+ goto out;
+ }
/* Need to update QP attributes from default values. */
qp_attr.qp_state = IB_QPS_INIT;
- ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
+ ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
if (ret)
- return ret;
+ goto out;
- ret = ib_modify_qp(id->qp, &qp_attr, qp_attr_mask);
+ ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
if (ret)
- return ret;
+ goto out;
qp_attr.qp_state = IB_QPS_RTR;
- ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
+ ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
if (ret)
- return ret;
+ goto out;
- return ib_modify_qp(id->qp, &qp_attr, qp_attr_mask);
+ ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
+out:
+ mutex_unlock(&id_priv->qp_mutex);
+ return ret;
}
-static int cma_modify_qp_rts(struct rdma_cm_id *id)
+static int cma_modify_qp_rts(struct rdma_id_private *id_priv)
{
struct ib_qp_attr qp_attr;
int qp_attr_mask, ret;
- if (!id->qp)
- return 0;
+ mutex_lock(&id_priv->qp_mutex);
+ if (!id_priv->id.qp) {
+ ret = 0;
+ goto out;
+ }
qp_attr.qp_state = IB_QPS_RTS;
- ret = rdma_init_qp_attr(id, &qp_attr, &qp_attr_mask);
+ ret = rdma_init_qp_attr(&id_priv->id, &qp_attr, &qp_attr_mask);
if (ret)
- return ret;
+ goto out;
- return ib_modify_qp(id->qp, &qp_attr, qp_attr_mask);
+ ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask);
+out:
+ mutex_unlock(&id_priv->qp_mutex);
+ return ret;
}
-static int cma_modify_qp_err(struct rdma_cm_id *id)
+static int cma_modify_qp_err(struct rdma_id_private *id_priv)
{
struct ib_qp_attr qp_attr;
+ int ret;
- if (!id->qp)
- return 0;
+ mutex_lock(&id_priv->qp_mutex);
+ if (!id_priv->id.qp) {
+ ret = 0;
+ goto out;
+ }
qp_attr.qp_state = IB_QPS_ERR;
- return ib_modify_qp(id->qp, &qp_attr, IB_QP_STATE);
+ ret = ib_modify_qp(id_priv->id.qp, &qp_attr, IB_QP_STATE);
+out:
+ mutex_unlock(&id_priv->qp_mutex);
+ return ret;
}
static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
@@ -715,50 +746,27 @@ static void cma_cancel_route(struct rdma_id_private *id_priv)
}
}
-static inline int cma_internal_listen(struct rdma_id_private *id_priv)
-{
- return (id_priv->state == CMA_LISTEN) && id_priv->cma_dev &&
- cma_any_addr(&id_priv->id.route.addr.src_addr);
-}
-
-static void cma_destroy_listen(struct rdma_id_private *id_priv)
-{
- cma_exch(id_priv, CMA_DESTROYING);
-
- if (id_priv->cma_dev) {
- switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
- case RDMA_TRANSPORT_IB:
- if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
- ib_destroy_cm_id(id_priv->cm_id.ib);
- break;
- case RDMA_TRANSPORT_IWARP:
- if (id_priv->cm_id.iw && !IS_ERR(id_priv->cm_id.iw))
- iw_destroy_cm_id(id_priv->cm_id.iw);
- break;
- default:
- break;
- }
- cma_detach_from_dev(id_priv);
- }
- list_del(&id_priv->listen_list);
-
- cma_deref_id(id_priv);
- wait_for_completion(&id_priv->comp);
-
- kfree(id_priv);
-}
-
static void cma_cancel_listens(struct rdma_id_private *id_priv)
{
struct rdma_id_private *dev_id_priv;
+ /*
+ * Remove from listen_any_list to prevent added devices from spawning
+ * additional listen requests.
+ */
mutex_lock(&lock);
list_del(&id_priv->list);
while (!list_empty(&id_priv->listen_list)) {
dev_id_priv = list_entry(id_priv->listen_list.next,
struct rdma_id_private, listen_list);
- cma_destroy_listen(dev_id_priv);
+ /* sync with device removal to avoid duplicate destruction */
+ list_del_init(&dev_id_priv->list);
+ list_del(&dev_id_priv->listen_list);
+ mutex_unlock(&lock);
+
+ rdma_destroy_id(&dev_id_priv->id);
+ mutex_lock(&lock);
}
mutex_unlock(&lock);
}
@@ -846,6 +854,9 @@ void rdma_destroy_id(struct rdma_cm_id *id)
cma_deref_id(id_priv);
wait_for_completion(&id_priv->comp);
+ if (id_priv->internal_id)
+ cma_deref_id(id_priv->id.context);
+
kfree(id_priv->id.route.path_rec);
kfree(id_priv);
}
@@ -855,11 +866,11 @@ static int cma_rep_recv(struct rdma_id_private *id_priv)
{
int ret;
- ret = cma_modify_qp_rtr(&id_priv->id);
+ ret = cma_modify_qp_rtr(id_priv);
if (ret)
goto reject;
- ret = cma_modify_qp_rts(&id_priv->id);
+ ret = cma_modify_qp_rts(id_priv);
if (ret)
goto reject;
@@ -869,7 +880,7 @@ static int cma_rep_recv(struct rdma_id_private *id_priv)
return 0;
reject:
- cma_modify_qp_err(&id_priv->id);
+ cma_modify_qp_err(id_priv);
ib_send_cm_rej(id_priv->cm_id.ib, IB_CM_REJ_CONSUMER_DEFINED,
NULL, 0, NULL, 0);
return ret;
@@ -945,7 +956,7 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
/* ignore event */
goto out;
case IB_CM_REJ_RECEIVED:
- cma_modify_qp_err(&id_priv->id);
+ cma_modify_qp_err(id_priv);
event.status = ib_event->param.rej_rcvd.reason;
event.event = RDMA_CM_EVENT_REJECTED;
event.param.conn.private_data = ib_event->private_data;
@@ -1089,6 +1100,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
event.param.ud.private_data_len =
IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset;
} else {
+ ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
conn_id = cma_new_conn_id(&listen_id->id, ib_event);
cma_set_req_event_data(&event, &ib_event->param.req_rcvd,
ib_event->private_data, offset);
@@ -1401,14 +1413,13 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
cma_attach_to_dev(dev_id_priv, cma_dev);
list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list);
+ atomic_inc(&id_priv->refcount);
+ dev_id_priv->internal_id = 1;
ret = rdma_listen(id, id_priv->backlog);
if (ret)
- goto err;
-
- return;
-err:
- cma_destroy_listen(dev_id_priv);
+ printk(KERN_WARNING "RDMA CMA: cma_listen_on_dev, error %d, "
+ "listening on device %s", ret, cma_dev->device->name);
}
static void cma_listen_on_all(struct rdma_id_private *id_priv)
@@ -1474,6 +1485,15 @@ err:
}
EXPORT_SYMBOL(rdma_listen);
+void rdma_set_service_type(struct rdma_cm_id *id, int tos)
+{
+ struct rdma_id_private *id_priv;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ id_priv->tos = (u8) tos;
+}
+EXPORT_SYMBOL(rdma_set_service_type);
+
static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
void *context)
{
@@ -1498,23 +1518,37 @@ static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
struct cma_work *work)
{
- struct rdma_dev_addr *addr = &id_priv->id.route.addr.dev_addr;
+ struct rdma_addr *addr = &id_priv->id.route.addr;
struct ib_sa_path_rec path_rec;
+ ib_sa_comp_mask comp_mask;
+ struct sockaddr_in6 *sin6;
memset(&path_rec, 0, sizeof path_rec);
- ib_addr_get_sgid(addr, &path_rec.sgid);
- ib_addr_get_dgid(addr, &path_rec.dgid);
- path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr));
+ ib_addr_get_sgid(&addr->dev_addr, &path_rec.sgid);
+ ib_addr_get_dgid(&addr->dev_addr, &path_rec.dgid);
+ path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr));
path_rec.numb_path = 1;
path_rec.reversible = 1;
+ path_rec.service_id = cma_get_service_id(id_priv->id.ps, &addr->dst_addr);
+
+ comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
+ IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
+ IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID;
+
+ if (addr->src_addr.sa_family == AF_INET) {
+ path_rec.qos_class = cpu_to_be16((u16) id_priv->tos);
+ comp_mask |= IB_SA_PATH_REC_QOS_CLASS;
+ } else {
+ sin6 = (struct sockaddr_in6 *) &addr->src_addr;
+ path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20);
+ comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
+ }
id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
- id_priv->id.port_num, &path_rec,
- IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
- IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
- IB_SA_PATH_REC_REVERSIBLE,
- timeout_ms, GFP_KERNEL,
- cma_query_handler, work, &id_priv->query);
+ id_priv->id.port_num, &path_rec,
+ comp_mask, timeout_ms,
+ GFP_KERNEL, cma_query_handler,
+ work, &id_priv->query);
return (id_priv->query_id < 0) ? id_priv->query_id : 0;
}
@@ -1866,13 +1900,14 @@ err1:
static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
{
struct rdma_bind_list *bind_list;
- int port, ret;
+ int port, ret, low, high;
bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
if (!bind_list)
return -ENOMEM;
retry:
+ /* FIXME: add proper port randomization per like inet_csk_get_port */
do {
ret = idr_get_new_above(ps, bind_list, next_port, &port);
} while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));
@@ -1880,18 +1915,19 @@ retry:
if (ret)
goto err1;
- if (port > sysctl_local_port_range[1]) {
- if (next_port != sysctl_local_port_range[0]) {
+ inet_get_local_port_range(&low, &high);
+ if (port > high) {
+ if (next_port != low) {
idr_remove(ps, port);
- next_port = sysctl_local_port_range[0];
+ next_port = low;
goto retry;
}
ret = -EADDRNOTAVAIL;
goto err2;
}
- if (port == sysctl_local_port_range[1])
- next_port = sysctl_local_port_range[0];
+ if (port == high)
+ next_port = low;
else
next_port = port + 1;
@@ -2236,7 +2272,7 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
cm_id->remote_addr = *sin;
- ret = cma_modify_qp_rtr(&id_priv->id);
+ ret = cma_modify_qp_rtr(id_priv);
if (ret)
goto out;
@@ -2303,7 +2339,7 @@ static int cma_accept_ib(struct rdma_id_private *id_priv,
int qp_attr_mask, ret;
if (id_priv->id.qp) {
- ret = cma_modify_qp_rtr(&id_priv->id);
+ ret = cma_modify_qp_rtr(id_priv);
if (ret)
goto out;
@@ -2342,7 +2378,7 @@ static int cma_accept_iw(struct rdma_id_private *id_priv,
struct iw_cm_conn_param iw_param;
int ret;
- ret = cma_modify_qp_rtr(&id_priv->id);
+ ret = cma_modify_qp_rtr(id_priv);
if (ret)
return ret;
@@ -2414,7 +2450,7 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
return 0;
reject:
- cma_modify_qp_err(id);
+ cma_modify_qp_err(id_priv);
rdma_reject(id, NULL, 0);
return ret;
}
@@ -2484,7 +2520,7 @@ int rdma_disconnect(struct rdma_cm_id *id)
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
- ret = cma_modify_qp_err(id);
+ ret = cma_modify_qp_err(id_priv);
if (ret)
goto out;
/* Initiate or respond to a disconnect. */
@@ -2515,9 +2551,11 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
cma_disable_remove(id_priv, CMA_ADDR_RESOLVED))
return 0;
+ mutex_lock(&id_priv->qp_mutex);
if (!status && id_priv->id.qp)
status = ib_attach_mcast(id_priv->id.qp, &multicast->rec.mgid,
multicast->rec.mlid);
+ mutex_unlock(&id_priv->qp_mutex);
memset(&event, 0, sizeof event);
event.status = status;
@@ -2729,16 +2767,12 @@ static void cma_process_remove(struct cma_device *cma_dev)
id_priv = list_entry(cma_dev->id_list.next,
struct rdma_id_private, list);
- if (cma_internal_listen(id_priv)) {
- cma_destroy_listen(id_priv);
- continue;
- }
-
+ list_del(&id_priv->listen_list);
list_del_init(&id_priv->list);
atomic_inc(&id_priv->refcount);
mutex_unlock(&lock);
- ret = cma_remove_id_dev(id_priv);
+ ret = id_priv->internal_id ? 1 : cma_remove_id_dev(id_priv);
cma_deref_id(id_priv);
if (ret)
rdma_destroy_id(&id_priv->id);
@@ -2769,12 +2803,13 @@ static void cma_remove_one(struct ib_device *device)
static int cma_init(void)
{
- int ret;
+ int ret, low, high, remaining;
get_random_bytes(&next_port, sizeof next_port);
- next_port = ((unsigned int) next_port %
- (sysctl_local_port_range[1] - sysctl_local_port_range[0])) +
- sysctl_local_port_range[0];
+ inet_get_local_port_range(&low, &high);
+ remaining = (high - low) + 1;
+ next_port = ((unsigned int) next_port % remaining) + low;
+
cma_wq = create_singlethread_workqueue("rdma_cm");
if (!cma_wq)
return -ENOMEM;
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 2506c43ba04..5ac5ffee05c 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -120,12 +120,12 @@ static struct ib_device *__ib_device_get_by_name(const char *name)
static int alloc_name(char *name)
{
- long *inuse;
+ unsigned long *inuse;
char buf[IB_DEVICE_NAME_MAX];
struct ib_device *device;
int i;
- inuse = (long *) get_zeroed_page(GFP_KERNEL);
+ inuse = (unsigned long *) get_zeroed_page(GFP_KERNEL);
if (!inuse)
return -ENOMEM;
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index a06bcc65a87..e8d5f6b6499 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -152,7 +152,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
#ifdef DEBUG
if (fmr->ref_count !=0) {
- printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d",
+ printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d\n",
fmr, fmr->ref_count);
}
#endif
@@ -170,7 +170,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
ret = ib_unmap_fmr(&fmr_list);
if (ret)
- printk(KERN_WARNING PFX "ib_unmap_fmr returned %d", ret);
+ printk(KERN_WARNING PFX "ib_unmap_fmr returned %d\n", ret);
spin_lock_irq(&pool->pool_lock);
list_splice(&unmap_list, &pool->free_list);
@@ -235,13 +235,13 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
attr = kmalloc(sizeof *attr, GFP_KERNEL);
if (!attr) {
- printk(KERN_WARNING PFX "couldn't allocate device attr struct");
+ printk(KERN_WARNING PFX "couldn't allocate device attr struct\n");
return ERR_PTR(-ENOMEM);
}
ret = ib_query_device(device, attr);
if (ret) {
- printk(KERN_WARNING PFX "couldn't query device: %d", ret);
+ printk(KERN_WARNING PFX "couldn't query device: %d\n", ret);
kfree(attr);
return ERR_PTR(ret);
}
@@ -255,7 +255,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
pool = kmalloc(sizeof *pool, GFP_KERNEL);
if (!pool) {
- printk(KERN_WARNING PFX "couldn't allocate pool struct");
+ printk(KERN_WARNING PFX "couldn't allocate pool struct\n");
return ERR_PTR(-ENOMEM);
}
@@ -272,7 +272,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket,
GFP_KERNEL);
if (!pool->cache_bucket) {
- printk(KERN_WARNING PFX "Failed to allocate cache in pool");
+ printk(KERN_WARNING PFX "Failed to allocate cache in pool\n");
ret = -ENOMEM;
goto out_free_pool;
}
@@ -291,12 +291,12 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
atomic_set(&pool->flush_ser, 0);
init_waitqueue_head(&pool->force_wait);
- pool->thread = kthread_create(ib_fmr_cleanup_thread,
- pool,
- "ib_fmr(%s)",
- device->name);
+ pool->thread = kthread_run(ib_fmr_cleanup_thread,
+ pool,
+ "ib_fmr(%s)",
+ device->name);
if (IS_ERR(pool->thread)) {
- printk(KERN_WARNING PFX "couldn't start cleanup thread");
+ printk(KERN_WARNING PFX "couldn't start cleanup thread\n");
ret = PTR_ERR(pool->thread);
goto out_free_pool;
}
@@ -314,7 +314,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
GFP_KERNEL);
if (!fmr) {
printk(KERN_WARNING PFX "failed to allocate fmr "
- "struct for FMR %d", i);
+ "struct for FMR %d\n", i);
goto out_fail;
}
@@ -326,7 +326,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr);
if (IS_ERR(fmr->fmr)) {
printk(KERN_WARNING PFX "fmr_create failed "
- "for FMR %d", i);
+ "for FMR %d\n", i);
kfree(fmr);
goto out_fail;
}
@@ -381,7 +381,7 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool)
}
if (i < pool->pool_size)
- printk(KERN_WARNING PFX "pool still has %d regions registered",
+ printk(KERN_WARNING PFX "pool still has %d regions registered\n",
pool->pool_size - i);
kfree(pool->cache_bucket);
@@ -518,7 +518,7 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr)
#ifdef DEBUG
if (fmr->ref_count < 0)
- printk(KERN_WARNING PFX "FMR %p has ref count %d < 0",
+ printk(KERN_WARNING PFX "FMR %p has ref count %d < 0\n",
fmr, fmr->ref_count);
#endif
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
index 15b4c4d3606..1bc1fe60528 100644
--- a/drivers/infiniband/core/multicast.c
+++ b/drivers/infiniband/core/multicast.c
@@ -196,7 +196,7 @@ static void queue_join(struct mcast_member *member)
unsigned long flags;
spin_lock_irqsave(&group->lock, flags);
- list_add(&member->list, &group->pending_list);
+ list_add_tail(&member->list, &group->pending_list);
if (group->state == MCAST_IDLE) {
group->state = MCAST_BUSY;
atomic_inc(&group->refcount);
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index d271bd715c1..cf474ec2707 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -123,14 +123,10 @@ static u32 tid;
.field_name = "sa_path_rec:" #field
static const struct ib_field path_rec_table[] = {
- { RESERVED,
+ { PATH_REC_FIELD(service_id),
.offset_words = 0,
.offset_bits = 0,
- .size_bits = 32 },
- { RESERVED,
- .offset_words = 1,
- .offset_bits = 0,
- .size_bits = 32 },
+ .size_bits = 64 },
{ PATH_REC_FIELD(dgid),
.offset_words = 2,
.offset_bits = 0,
@@ -179,7 +175,7 @@ static const struct ib_field path_rec_table[] = {
.offset_words = 12,
.offset_bits = 16,
.size_bits = 16 },
- { RESERVED,
+ { PATH_REC_FIELD(qos_class),
.offset_words = 13,
.offset_bits = 0,
.size_bits = 12 },
@@ -531,7 +527,7 @@ static int alloc_mad(struct ib_sa_query *query, gfp_t gfp_mask)
query->sm_ah->pkey_index,
0, IB_MGMT_SA_HDR, IB_MGMT_SA_DATA,
gfp_mask);
- if (!query->mad_buf) {
+ if (IS_ERR(query->mad_buf)) {
kref_put(&query->sm_ah->ref, free_sm_ah);
return -ENOMEM;
}
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 70b77ae6742..3d405068132 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -434,21 +434,18 @@ static void ib_device_release(struct class_device *cdev)
kfree(dev);
}
-static int ib_device_uevent(struct class_device *cdev, char **envp,
- int num_envp, char *buf, int size)
+static int ib_device_uevent(struct class_device *cdev,
+ struct kobj_uevent_env *env)
{
struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
- int i = 0, len = 0;
- if (add_uevent_var(envp, num_envp, &i, buf, size, &len,
- "NAME=%s", dev->name))
+ if (add_uevent_var(env, "NAME=%s", dev->name))
return -ENOMEM;
/*
* It would be nice to pass the node GUID with the event...
*/
- envp[i] = NULL;
return 0;
}
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 53b4c94a7eb..90d675ad9ec 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -792,6 +792,78 @@ out:
return ret;
}
+static int ucma_set_option_id(struct ucma_context *ctx, int optname,
+ void *optval, size_t optlen)
+{
+ int ret = 0;
+
+ switch (optname) {
+ case RDMA_OPTION_ID_TOS:
+ if (optlen != sizeof(u8)) {
+ ret = -EINVAL;
+ break;
+ }
+ rdma_set_service_type(ctx->cm_id, *((u8 *) optval));
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ return ret;
+}
+
+static int ucma_set_option_level(struct ucma_context *ctx, int level,
+ int optname, void *optval, size_t optlen)
+{
+ int ret;
+
+ switch (level) {
+ case RDMA_OPTION_ID:
+ ret = ucma_set_option_id(ctx, optname, optval, optlen);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ return ret;
+}
+
+static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf,
+ int in_len, int out_len)
+{
+ struct rdma_ucm_set_option cmd;
+ struct ucma_context *ctx;
+ void *optval;
+ int ret;
+
+ if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+ return -EFAULT;
+
+ ctx = ucma_get_ctx(file, cmd.id);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
+
+ optval = kmalloc(cmd.optlen, GFP_KERNEL);
+ if (!optval) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ if (copy_from_user(optval, (void __user *) (unsigned long) cmd.optval,
+ cmd.optlen)) {
+ ret = -EFAULT;
+ goto out2;
+ }
+
+ ret = ucma_set_option_level(ctx, cmd.level, cmd.optname, optval,
+ cmd.optlen);
+out2:
+ kfree(optval);
+out1:
+ ucma_put_ctx(ctx);
+ return ret;
+}
+
static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
int in_len, int out_len)
{
@@ -936,7 +1008,7 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file,
[RDMA_USER_CM_CMD_INIT_QP_ATTR] = ucma_init_qp_attr,
[RDMA_USER_CM_CMD_GET_EVENT] = ucma_get_event,
[RDMA_USER_CM_CMD_GET_OPTION] = NULL,
- [RDMA_USER_CM_CMD_SET_OPTION] = NULL,
+ [RDMA_USER_CM_CMD_SET_OPTION] = ucma_set_option,
[RDMA_USER_CM_CMD_NOTIFY] = ucma_notify,
[RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast,
[RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast,
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index 664d2faa9e7..4e3128ff73c 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -37,6 +37,7 @@
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <linux/sched.h>
+#include <linux/hugetlb.h>
#include "uverbs.h"
@@ -54,9 +55,11 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d
ib_dma_unmap_sg(dev, chunk->page_list,
chunk->nents, DMA_BIDIRECTIONAL);
for (i = 0; i < chunk->nents; ++i) {
+ struct page *page = sg_page(&chunk->page_list[i]);
+
if (umem->writable && dirty)
- set_page_dirty_lock(chunk->page_list[i].page);
- put_page(chunk->page_list[i].page);
+ set_page_dirty_lock(page);
+ put_page(page);
}
kfree(chunk);
@@ -75,6 +78,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
{
struct ib_umem *umem;
struct page **page_list;
+ struct vm_area_struct **vma_list;
struct ib_umem_chunk *chunk;
unsigned long locked;
unsigned long lock_limit;
@@ -104,6 +108,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
*/
umem->writable = !!(access & ~IB_ACCESS_REMOTE_READ);
+ /* We assume the memory is from hugetlb until proved otherwise */
+ umem->hugetlb = 1;
+
INIT_LIST_HEAD(&umem->chunk_list);
page_list = (struct page **) __get_free_page(GFP_KERNEL);
@@ -112,6 +119,14 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
return ERR_PTR(-ENOMEM);
}
+ /*
+ * if we can't alloc the vma_list, it's not so bad;
+ * just assume the memory is not hugetlb memory
+ */
+ vma_list = (struct vm_area_struct **) __get_free_page(GFP_KERNEL);
+ if (!vma_list)
+ umem->hugetlb = 0;
+
npages = PAGE_ALIGN(size + umem->offset) >> PAGE_SHIFT;
down_write(&current->mm->mmap_sem);
@@ -131,7 +146,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
ret = get_user_pages(current, current->mm, cur_base,
min_t(int, npages,
PAGE_SIZE / sizeof (struct page *)),
- 1, !umem->writable, page_list, NULL);
+ 1, !umem->writable, page_list, vma_list);
if (ret < 0)
goto out;
@@ -151,10 +166,12 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
}
chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK);
+ sg_init_table(chunk->page_list, chunk->nents);
for (i = 0; i < chunk->nents; ++i) {
- chunk->page_list[i].page = page_list[i + off];
- chunk->page_list[i].offset = 0;
- chunk->page_list[i].length = PAGE_SIZE;
+ if (vma_list &&
+ !is_vm_hugetlb_page(vma_list[i + off]))
+ umem->hugetlb = 0;
+ sg_set_page(&chunk->page_list[i], page_list[i + off], PAGE_SIZE, 0);
}
chunk->nmap = ib_dma_map_sg(context->device,
@@ -163,7 +180,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
DMA_BIDIRECTIONAL);
if (chunk->nmap <= 0) {
for (i = 0; i < chunk->nents; ++i)
- put_page(chunk->page_list[i].page);
+ put_page(sg_page(&chunk->page_list[i]));
kfree(chunk);
ret = -ENOMEM;
@@ -186,6 +203,8 @@ out:
current->mm->locked_vm = locked;
up_write(&current->mm->mmap_sem);
+ if (vma_list)
+ free_page((unsigned long) vma_list);
free_page((unsigned long) page_list);
return ret < 0 ? ERR_PTR(ret) : umem;
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index d97ded25c4f..b53eac4611d 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -44,6 +44,7 @@
#include <linux/poll.h>
#include <linux/rwsem.h>
#include <linux/kref.h>
+#include <linux/compat.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
@@ -118,6 +119,8 @@ struct ib_umad_file {
wait_queue_head_t recv_wait;
struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS];
int agents_dead;
+ u8 use_pkey_index;
+ u8 already_used;
};
struct ib_umad_packet {
@@ -147,6 +150,12 @@ static void ib_umad_release_dev(struct kref *ref)
kfree(dev);
}
+static int hdr_size(struct ib_umad_file *file)
+{
+ return file->use_pkey_index ? sizeof (struct ib_user_mad_hdr) :
+ sizeof (struct ib_user_mad_hdr_old);
+}
+
/* caller must hold port->mutex at least for reading */
static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id)
{
@@ -221,13 +230,13 @@ static void recv_handler(struct ib_mad_agent *agent,
packet->length = mad_recv_wc->mad_len;
packet->recv_wc = mad_recv_wc;
- packet->mad.hdr.status = 0;
- packet->mad.hdr.length = sizeof (struct ib_user_mad) +
- mad_recv_wc->mad_len;
- packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp);
- packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid);
- packet->mad.hdr.sl = mad_recv_wc->wc->sl;
- packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits;
+ packet->mad.hdr.status = 0;
+ packet->mad.hdr.length = hdr_size(file) + mad_recv_wc->mad_len;
+ packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp);
+ packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid);
+ packet->mad.hdr.sl = mad_recv_wc->wc->sl;
+ packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits;
+ packet->mad.hdr.pkey_index = mad_recv_wc->wc->pkey_index;
packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH);
if (packet->mad.hdr.grh_present) {
struct ib_ah_attr ah_attr;
@@ -253,8 +262,8 @@ err1:
ib_free_recv_mad(mad_recv_wc);
}
-static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
- size_t count)
+static ssize_t copy_recv_mad(struct ib_umad_file *file, char __user *buf,
+ struct ib_umad_packet *packet, size_t count)
{
struct ib_mad_recv_buf *recv_buf;
int left, seg_payload, offset, max_seg_payload;
@@ -262,15 +271,15 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
/* We need enough room to copy the first (or only) MAD segment. */
recv_buf = &packet->recv_wc->recv_buf;
if ((packet->length <= sizeof (*recv_buf->mad) &&
- count < sizeof (packet->mad) + packet->length) ||
+ count < hdr_size(file) + packet->length) ||
(packet->length > sizeof (*recv_buf->mad) &&
- count < sizeof (packet->mad) + sizeof (*recv_buf->mad)))
+ count < hdr_size(file) + sizeof (*recv_buf->mad)))
return -EINVAL;
- if (copy_to_user(buf, &packet->mad, sizeof (packet->mad)))
+ if (copy_to_user(buf, &packet->mad, hdr_size(file)))
return -EFAULT;
- buf += sizeof (packet->mad);
+ buf += hdr_size(file);
seg_payload = min_t(int, packet->length, sizeof (*recv_buf->mad));
if (copy_to_user(buf, recv_buf->mad, seg_payload))
return -EFAULT;
@@ -280,7 +289,7 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
* Multipacket RMPP MAD message. Copy remainder of message.
* Note that last segment may have a shorter payload.
*/
- if (count < sizeof (packet->mad) + packet->length) {
+ if (count < hdr_size(file) + packet->length) {
/*
* The buffer is too small, return the first RMPP segment,
* which includes the RMPP message length.
@@ -300,18 +309,23 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
return -EFAULT;
}
}
- return sizeof (packet->mad) + packet->length;
+ return hdr_size(file) + packet->length;
}
-static ssize_t copy_send_mad(char __user *buf, struct ib_umad_packet *packet,
- size_t count)
+static ssize_t copy_send_mad(struct ib_umad_file *file, char __user *buf,
+ struct ib_umad_packet *packet, size_t count)
{
- ssize_t size = sizeof (packet->mad) + packet->length;
+ ssize_t size = hdr_size(file) + packet->length;
if (count < size)
return -EINVAL;
- if (copy_to_user(buf, &packet->mad, size))
+ if (copy_to_user(buf, &packet->mad, hdr_size(file)))
+ return -EFAULT;
+
+ buf += hdr_size(file);
+
+ if (copy_to_user(buf, packet->mad.data, packet->length))
return -EFAULT;
return size;
@@ -324,7 +338,7 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
struct ib_umad_packet *packet;
ssize_t ret;
- if (count < sizeof (struct ib_user_mad))
+ if (count < hdr_size(file))
return -EINVAL;
spin_lock_irq(&file->recv_lock);
@@ -348,9 +362,9 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
spin_unlock_irq(&file->recv_lock);
if (packet->recv_wc)
- ret = copy_recv_mad(buf, packet, count);
+ ret = copy_recv_mad(file, buf, packet, count);
else
- ret = copy_send_mad(buf, packet, count);
+ ret = copy_send_mad(file, buf, packet, count);
if (ret < 0) {
/* Requeue packet */
@@ -442,15 +456,14 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
__be64 *tid;
int ret, data_len, hdr_len, copy_offset, rmpp_active;
- if (count < sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)
+ if (count < hdr_size(file) + IB_MGMT_RMPP_HDR)
return -EINVAL;
packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
if (!packet)
return -ENOMEM;
- if (copy_from_user(&packet->mad, buf,
- sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)) {
+ if (copy_from_user(&packet->mad, buf, hdr_size(file))) {
ret = -EFAULT;
goto err;
}
@@ -461,6 +474,13 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
goto err;
}
+ buf += hdr_size(file);
+
+ if (copy_from_user(packet->mad.data, buf, IB_MGMT_RMPP_HDR)) {
+ ret = -EFAULT;
+ goto err;
+ }
+
down_read(&file->port->mutex);
agent = __get_agent(file, packet->mad.hdr.id);
@@ -500,11 +520,11 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
IB_MGMT_RMPP_FLAG_ACTIVE;
}
- data_len = count - sizeof (struct ib_user_mad) - hdr_len;
+ data_len = count - hdr_size(file) - hdr_len;
packet->msg = ib_create_send_mad(agent,
be32_to_cpu(packet->mad.hdr.qpn),
- 0, rmpp_active, hdr_len,
- data_len, GFP_KERNEL);
+ packet->mad.hdr.pkey_index, rmpp_active,
+ hdr_len, data_len, GFP_KERNEL);
if (IS_ERR(packet->msg)) {
ret = PTR_ERR(packet->msg);
goto err_ah;
@@ -517,7 +537,6 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
/* Copy MAD header. Any RMPP header is already in place. */
memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR);
- buf += sizeof (struct ib_user_mad);
if (!rmpp_active) {
if (copy_from_user(packet->msg->mad + copy_offset,
@@ -589,7 +608,8 @@ static unsigned int ib_umad_poll(struct file *filp, struct poll_table_struct *wa
return mask;
}
-static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg)
+static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
+ int compat_method_mask)
{
struct ib_user_mad_reg_req ureq;
struct ib_mad_reg_req req;
@@ -604,7 +624,7 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg)
goto out;
}
- if (copy_from_user(&ureq, (void __user *) arg, sizeof ureq)) {
+ if (copy_from_user(&ureq, arg, sizeof ureq)) {
ret = -EFAULT;
goto out;
}
@@ -625,8 +645,18 @@ found:
if (ureq.mgmt_class) {
req.mgmt_class = ureq.mgmt_class;
req.mgmt_class_version = ureq.mgmt_class_version;
- memcpy(req.method_mask, ureq.method_mask, sizeof req.method_mask);
- memcpy(req.oui, ureq.oui, sizeof req.oui);
+ memcpy(req.oui, ureq.oui, sizeof req.oui);
+
+ if (compat_method_mask) {
+ u32 *umm = (u32 *) ureq.method_mask;
+ int i;
+
+ for (i = 0; i < BITS_TO_LONGS(IB_MGMT_MAX_METHODS); ++i)
+ req.method_mask[i] =
+ umm[i * 2] | ((u64) umm[i * 2 + 1] << 32);
+ } else
+ memcpy(req.method_mask, ureq.method_mask,
+ sizeof req.method_mask);
}
agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num,
@@ -646,6 +676,16 @@ found:
goto out;
}
+ if (!file->already_used) {
+ file->already_used = 1;
+ if (!file->use_pkey_index) {
+ printk(KERN_WARNING "user_mad: process %s did not enable "
+ "P_Key index support.\n", current->comm);
+ printk(KERN_WARNING "user_mad: Documentation/infiniband/user_mad.txt "
+ "has info on the new ABI.\n");
+ }
+ }
+
file->agent[agent_id] = agent;
ret = 0;
@@ -654,13 +694,13 @@ out:
return ret;
}
-static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg)
+static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
{
struct ib_mad_agent *agent = NULL;
u32 id;
int ret = 0;
- if (get_user(id, (u32 __user *) arg))
+ if (get_user(id, arg))
return -EFAULT;
down_write(&file->port->mutex);
@@ -682,18 +722,51 @@ out:
return ret;
}
+static long ib_umad_enable_pkey(struct ib_umad_file *file)
+{
+ int ret = 0;
+
+ down_write(&file->port->mutex);
+ if (file->already_used)
+ ret = -EINVAL;
+ else
+ file->use_pkey_index = 1;
+ up_write(&file->port->mutex);
+
+ return ret;
+}
+
static long ib_umad_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
switch (cmd) {
case IB_USER_MAD_REGISTER_AGENT:
- return ib_umad_reg_agent(filp->private_data, arg);
+ return ib_umad_reg_agent(filp->private_data, (void __user *) arg, 0);
+ case IB_USER_MAD_UNREGISTER_AGENT:
+ return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg);
+ case IB_USER_MAD_ENABLE_PKEY:
+ return ib_umad_enable_pkey(filp->private_data);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ switch (cmd) {
+ case IB_USER_MAD_REGISTER_AGENT:
+ return ib_umad_reg_agent(filp->private_data, compat_ptr(arg), 1);
case IB_USER_MAD_UNREGISTER_AGENT:
- return ib_umad_unreg_agent(filp->private_data, arg);
+ return ib_umad_unreg_agent(filp->private_data, compat_ptr(arg));
+ case IB_USER_MAD_ENABLE_PKEY:
+ return ib_umad_enable_pkey(filp->private_data);
default:
return -ENOIOCTLCMD;
}
}
+#endif
static int ib_umad_open(struct inode *inode, struct file *filp)
{
@@ -782,7 +855,9 @@ static const struct file_operations umad_fops = {
.write = ib_umad_write,
.poll = ib_umad_poll,
.unlocked_ioctl = ib_umad_ioctl,
- .compat_ioctl = ib_umad_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ib_umad_compat_ioctl,
+#endif
.open = ib_umad_open,
.release = ib_umad_close
};
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index c33546f9e96..c75eb6c9bd4 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -148,7 +148,6 @@ void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj);
struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
int is_async, int *fd);
-void ib_uverbs_release_event_file(struct kref *ref);
struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd);
void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 01d70084aeb..495c803fb11 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -147,8 +147,12 @@ static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id,
spin_lock(&ib_uverbs_idr_lock);
uobj = idr_find(idr, id);
- if (uobj)
- kref_get(&uobj->ref);
+ if (uobj) {
+ if (uobj->context == context)
+ kref_get(&uobj->ref);
+ else
+ uobj = NULL;
+ }
spin_unlock(&ib_uverbs_idr_lock);
return uobj;
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 14d7ccd8919..7c2ac390558 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -125,6 +125,14 @@ static void ib_uverbs_release_dev(struct kref *ref)
complete(&dev->comp);
}
+static void ib_uverbs_release_event_file(struct kref *ref)
+{
+ struct ib_uverbs_event_file *file =
+ container_of(ref, struct ib_uverbs_event_file, ref);
+
+ kfree(file);
+}
+
void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
struct ib_uverbs_event_file *ev_file,
struct ib_ucq_object *uobj)
@@ -331,14 +339,6 @@ static unsigned int ib_uverbs_event_poll(struct file *filp,
return pollflags;
}
-void ib_uverbs_release_event_file(struct kref *ref)
-{
- struct ib_uverbs_event_file *file =
- container_of(ref, struct ib_uverbs_event_file, ref);
-
- kfree(file);
-}
-
static int ib_uverbs_event_fasync(int fd, struct file *filp, int on)
{
struct ib_uverbs_event_file *file = filp->private_data;
diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c
index 0aecea67f3e..f283a9f0c23 100644
--- a/drivers/infiniband/hw/amso1100/c2.c
+++ b/drivers/infiniband/hw/amso1100/c2.c
@@ -886,7 +886,6 @@ static struct net_device *c2_devinit(struct c2_dev *c2dev,
return NULL;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev);
netdev->open = c2_up;
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
index 997cf153076..7a6cece6ea9 100644
--- a/drivers/infiniband/hw/amso1100/c2_provider.c
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -715,7 +715,6 @@ static int c2_pseudo_change_mtu(struct net_device *netdev, int new_mtu)
static void setup(struct net_device *netdev)
{
- SET_MODULE_OWNER(netdev);
netdev->open = c2_pseudo_up;
netdev->stop = c2_pseudo_down;
netdev->hard_start_xmit = c2_pseudo_xmit_frame;
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index beb2a381467..eec6a30840c 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -37,6 +37,7 @@
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
+#include <net/net_namespace.h>
#include "cxio_resource.h"
#include "cxio_hal.h"
@@ -894,7 +895,7 @@ int cxio_rdev_open(struct cxio_rdev *rdev_p)
if (cxio_hal_find_rdev_by_name(rdev_p->dev_name)) {
return -EBUSY;
}
- netdev_p = dev_get_by_name(rdev_p->dev_name);
+ netdev_p = dev_get_by_name(&init_net, rdev_p->dev_name);
if (!netdev_p) {
return -EINVAL;
}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 1cdfcd43b0b..20ba372dd18 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -63,37 +63,37 @@ static char *states[] = {
};
static int ep_timeout_secs = 10;
-module_param(ep_timeout_secs, int, 0444);
+module_param(ep_timeout_secs, int, 0644);
MODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout "
"in seconds (default=10)");
static int mpa_rev = 1;
-module_param(mpa_rev, int, 0444);
+module_param(mpa_rev, int, 0644);
MODULE_PARM_DESC(mpa_rev, "MPA Revision, 0 supports amso1100, "
"1 is spec compliant. (default=1)");
static int markers_enabled = 0;
-module_param(markers_enabled, int, 0444);
+module_param(markers_enabled, int, 0644);
MODULE_PARM_DESC(markers_enabled, "Enable MPA MARKERS (default(0)=disabled)");
static int crc_enabled = 1;
-module_param(crc_enabled, int, 0444);
+module_param(crc_enabled, int, 0644);
MODULE_PARM_DESC(crc_enabled, "Enable MPA CRC (default(1)=enabled)");
static int rcv_win = 256 * 1024;
-module_param(rcv_win, int, 0444);
+module_param(rcv_win, int, 0644);
MODULE_PARM_DESC(rcv_win, "TCP receive window in bytes (default=256)");
static int snd_win = 32 * 1024;
-module_param(snd_win, int, 0444);
+module_param(snd_win, int, 0644);
MODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=32KB)");
static unsigned int nocong = 0;
-module_param(nocong, uint, 0444);
+module_param(nocong, uint, 0644);
MODULE_PARM_DESC(nocong, "Turn off congestion control (default=0)");
static unsigned int cong_flavor = 1;
-module_param(cong_flavor, uint, 0444);
+module_param(cong_flavor, uint, 0644);
MODULE_PARM_DESC(cong_flavor, "TCP Congestion control flavor (default=1)");
static void process_work(struct work_struct *work);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index f0c77758937..b5436ca92e6 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -1000,6 +1000,7 @@ static int iwch_query_device(struct ib_device *ibdev,
props->max_sge = dev->attr.max_sge_per_wr;
props->max_sge_rd = 1;
props->max_qp_rd_atom = dev->attr.max_rdma_reads_per_qp;
+ props->max_qp_init_rd_atom = dev->attr.max_rdma_reads_per_qp;
props->max_cq = dev->attr.max_cqs;
props->max_cqe = dev->attr.max_cqes_per_cq;
props->max_mr = dev->attr.max_mem_regs;
diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c
index 97d108634c5..453eb995c1d 100644
--- a/drivers/infiniband/hw/ehca/ehca_av.c
+++ b/drivers/infiniband/hw/ehca/ehca_av.c
@@ -50,6 +50,38 @@
static struct kmem_cache *av_cache;
+int ehca_calc_ipd(struct ehca_shca *shca, int port,
+ enum ib_rate path_rate, u32 *ipd)
+{
+ int path = ib_rate_to_mult(path_rate);
+ int link, ret;
+ struct ib_port_attr pa;
+
+ if (path_rate == IB_RATE_PORT_CURRENT) {
+ *ipd = 0;
+ return 0;
+ }
+
+ if (unlikely(path < 0)) {
+ ehca_err(&shca->ib_device, "Invalid static rate! path_rate=%x",
+ path_rate);
+ return -EINVAL;
+ }
+
+ ret = ehca_query_port(&shca->ib_device, port, &pa);
+ if (unlikely(ret < 0)) {
+ ehca_err(&shca->ib_device, "Failed to query port ret=%i", ret);
+ return ret;
+ }
+
+ link = ib_width_enum_to_int(pa.active_width) * pa.active_speed;
+
+ /* IPD = round((link / path) - 1) */
+ *ipd = ((link + (path >> 1)) / path) - 1;
+
+ return 0;
+}
+
struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
{
int ret;
@@ -69,15 +101,13 @@ struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
av->av.slid_path_bits = ah_attr->src_path_bits;
if (ehca_static_rate < 0) {
- int ah_mult = ib_rate_to_mult(ah_attr->static_rate);
- int ehca_mult =
- ib_rate_to_mult(shca->sport[ah_attr->port_num].rate );
-
- if (ah_mult >= ehca_mult)
- av->av.ipd = 0;
- else
- av->av.ipd = (ah_mult > 0) ?
- ((ehca_mult - 1) / ah_mult) : 0;
+ u32 ipd;
+ if (ehca_calc_ipd(shca, ah_attr->port_num,
+ ah_attr->static_rate, &ipd)) {
+ ret = -EINVAL;
+ goto create_ah_exit1;
+ }
+ av->av.ipd = ipd;
} else
av->av.ipd = ehca_static_rate;
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index b5e96030531..87f12d4312a 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -53,6 +53,7 @@ struct ehca_pd;
struct ehca_av;
#include <linux/wait.h>
+#include <linux/mutex.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_user_verbs.h>
@@ -94,19 +95,18 @@ struct ehca_sma_attr {
struct ehca_sport {
struct ib_cq *ibcq_aqp1;
struct ib_qp *ibqp_aqp1;
- enum ib_rate rate;
enum ib_port_state port_state;
struct ehca_sma_attr saved_attr;
};
-#define HCA_CAP_MR_PGSIZE_4K 1
-#define HCA_CAP_MR_PGSIZE_64K 2
-#define HCA_CAP_MR_PGSIZE_1M 4
-#define HCA_CAP_MR_PGSIZE_16M 8
+#define HCA_CAP_MR_PGSIZE_4K 0x80000000
+#define HCA_CAP_MR_PGSIZE_64K 0x40000000
+#define HCA_CAP_MR_PGSIZE_1M 0x20000000
+#define HCA_CAP_MR_PGSIZE_16M 0x10000000
struct ehca_shca {
struct ib_device ib_device;
- struct ibmebus_dev *ibmebus_dev;
+ struct of_device *ofdev;
u8 num_ports;
int hw_level;
struct list_head shca_list;
@@ -322,7 +322,6 @@ extern int ehca_static_rate;
extern int ehca_port_act_time;
extern int ehca_use_hp_mr;
extern int ehca_scaling_code;
-extern int ehca_mr_largepage;
struct ipzu_queue_resp {
u32 qe_size; /* queue entry size */
@@ -337,6 +336,8 @@ struct ehca_create_cq_resp {
u32 cq_number;
u32 token;
struct ipzu_queue_resp ipz_queue;
+ u32 fw_handle_ofs;
+ u32 dummy;
};
struct ehca_create_qp_resp {
@@ -347,7 +348,8 @@ struct ehca_create_qp_resp {
u32 qkey;
/* qp_num assigned by ehca: sqp0/1 may have got different numbers */
u32 real_qp_num;
- u32 dummy; /* padding for 8 byte alignment */
+ u32 fw_handle_ofs;
+ u32 dummy;
struct ipzu_queue_resp ipz_squeue;
struct ipzu_queue_resp ipz_rqueue;
};
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 81aff36101b..79c25f51c21 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -166,7 +166,6 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
write_lock_irqsave(&ehca_cq_idr_lock, flags);
ret = idr_get_new(&ehca_cq_idr, my_cq, &my_cq->token);
write_unlock_irqrestore(&ehca_cq_idr_lock, flags);
-
} while (ret == -EAGAIN);
if (ret) {
@@ -176,6 +175,12 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
goto create_cq_exit1;
}
+ if (my_cq->token > 0x1FFFFFF) {
+ cq = ERR_PTR(-ENOMEM);
+ ehca_err(device, "Invalid number of cq. device=%p", device);
+ goto create_cq_exit2;
+ }
+
/*
* CQs maximum depth is 4GB-64, but we need additional 20 as buffer
* for receiving errors CQEs.
@@ -185,7 +190,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
if (h_ret != H_SUCCESS) {
ehca_err(device, "hipz_h_alloc_resource_cq() failed "
- "h_ret=%lx device=%p", h_ret, device);
+ "h_ret=%li device=%p", h_ret, device);
cq = ERR_PTR(ehca2ib_return_code(h_ret));
goto create_cq_exit2;
}
@@ -193,7 +198,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
ipz_rc = ipz_queue_ctor(NULL, &my_cq->ipz_queue, param.act_pages,
EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0, 0);
if (!ipz_rc) {
- ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%x device=%p",
+ ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%i device=%p",
ipz_rc, device);
cq = ERR_PTR(-EINVAL);
goto create_cq_exit3;
@@ -221,7 +226,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
if (h_ret < H_SUCCESS) {
ehca_err(device, "hipz_h_register_rpage_cq() failed "
- "ehca_cq=%p cq_num=%x h_ret=%lx counter=%i "
+ "ehca_cq=%p cq_num=%x h_ret=%li counter=%i "
"act_pages=%i", my_cq, my_cq->cq_number,
h_ret, counter, param.act_pages);
cq = ERR_PTR(-EINVAL);
@@ -233,7 +238,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
if ((h_ret != H_SUCCESS) || vpage) {
ehca_err(device, "Registration of pages not "
"complete ehca_cq=%p cq_num=%x "
- "h_ret=%lx", my_cq, my_cq->cq_number,
+ "h_ret=%li", my_cq, my_cq->cq_number,
h_ret);
cq = ERR_PTR(-EAGAIN);
goto create_cq_exit4;
@@ -241,7 +246,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
} else {
if (h_ret != H_PAGE_REGISTERED) {
ehca_err(device, "Registration of page failed "
- "ehca_cq=%p cq_num=%x h_ret=%lx"
+ "ehca_cq=%p cq_num=%x h_ret=%li"
"counter=%i act_pages=%i",
my_cq, my_cq->cq_number,
h_ret, counter, param.act_pages);
@@ -276,6 +281,8 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
resp.ipz_queue.queue_length = ipz_queue->queue_length;
resp.ipz_queue.pagesize = ipz_queue->pagesize;
resp.ipz_queue.toggle_state = ipz_queue->toggle_state;
+ resp.fw_handle_ofs = (u32)
+ (my_cq->galpas.user.fw_handle & (PAGE_SIZE - 1));
if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
ehca_err(device, "Copy to udata failed.");
goto create_cq_exit4;
@@ -291,7 +298,7 @@ create_cq_exit3:
h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
if (h_ret != H_SUCCESS)
ehca_err(device, "hipz_h_destroy_cq() failed ehca_cq=%p "
- "cq_num=%x h_ret=%lx", my_cq, my_cq->cq_number, h_ret);
+ "cq_num=%x h_ret=%li", my_cq, my_cq->cq_number, h_ret);
create_cq_exit2:
write_lock_irqsave(&ehca_cq_idr_lock, flags);
@@ -355,7 +362,7 @@ int ehca_destroy_cq(struct ib_cq *cq)
cq_num);
}
if (h_ret != H_SUCCESS) {
- ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%lx "
+ ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%li "
"ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num);
return ehca2ib_return_code(h_ret);
}
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c
index 1d41faa7a33..b4ac617a70e 100644
--- a/drivers/infiniband/hw/ehca/ehca_eq.c
+++ b/drivers/infiniband/hw/ehca/ehca_eq.c
@@ -123,7 +123,7 @@ int ehca_create_eq(struct ehca_shca *shca,
/* register interrupt handlers and initialize work queues */
if (type == EHCA_EQ) {
- ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_eq,
+ ret = ibmebus_request_irq(eq->ist, ehca_interrupt_eq,
IRQF_DISABLED, "ehca_eq",
(void *)shca);
if (ret < 0)
@@ -131,7 +131,7 @@ int ehca_create_eq(struct ehca_shca *shca,
tasklet_init(&eq->interrupt_task, ehca_tasklet_eq, (long)shca);
} else if (type == EHCA_NEQ) {
- ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_neq,
+ ret = ibmebus_request_irq(eq->ist, ehca_interrupt_neq,
IRQF_DISABLED, "ehca_neq",
(void *)shca);
if (ret < 0)
@@ -171,7 +171,7 @@ int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq)
u64 h_ret;
spin_lock_irqsave(&eq->spinlock, flags);
- ibmebus_free_irq(NULL, eq->ist, (void *)shca);
+ ibmebus_free_irq(eq->ist, (void *)shca);
h_ret = hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
index cf22472d941..5bd7b591987 100644
--- a/drivers/infiniband/hw/ehca/ehca_hca.c
+++ b/drivers/infiniband/hw/ehca/ehca_hca.c
@@ -77,22 +77,23 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
}
memset(props, 0, sizeof(struct ib_device_attr));
+ props->page_size_cap = shca->hca_cap_mr_pgsize;
props->fw_ver = rblock->hw_ver;
props->max_mr_size = rblock->max_mr_size;
props->vendor_id = rblock->vendor_id >> 8;
props->vendor_part_id = rblock->vendor_part_id >> 16;
props->hw_ver = rblock->hw_ver;
- props->max_qp = min_t(int, rblock->max_qp, INT_MAX);
- props->max_qp_wr = min_t(int, rblock->max_wqes_wq, INT_MAX);
- props->max_sge = min_t(int, rblock->max_sge, INT_MAX);
- props->max_sge_rd = min_t(int, rblock->max_sge_rd, INT_MAX);
- props->max_cq = min_t(int, rblock->max_cq, INT_MAX);
- props->max_cqe = min_t(int, rblock->max_cqe, INT_MAX);
- props->max_mr = min_t(int, rblock->max_mr, INT_MAX);
- props->max_mw = min_t(int, rblock->max_mw, INT_MAX);
- props->max_pd = min_t(int, rblock->max_pd, INT_MAX);
- props->max_ah = min_t(int, rblock->max_ah, INT_MAX);
- props->max_fmr = min_t(int, rblock->max_mr, INT_MAX);
+ props->max_qp = min_t(unsigned, rblock->max_qp, INT_MAX);
+ props->max_qp_wr = min_t(unsigned, rblock->max_wqes_wq, INT_MAX);
+ props->max_sge = min_t(unsigned, rblock->max_sge, INT_MAX);
+ props->max_sge_rd = min_t(unsigned, rblock->max_sge_rd, INT_MAX);
+ props->max_cq = min_t(unsigned, rblock->max_cq, INT_MAX);
+ props->max_cqe = min_t(unsigned, rblock->max_cqe, INT_MAX);
+ props->max_mr = min_t(unsigned, rblock->max_mr, INT_MAX);
+ props->max_mw = min_t(unsigned, rblock->max_mw, INT_MAX);
+ props->max_pd = min_t(unsigned, rblock->max_pd, INT_MAX);
+ props->max_ah = min_t(unsigned, rblock->max_ah, INT_MAX);
+ props->max_fmr = min_t(unsigned, rblock->max_mr, INT_MAX);
if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) {
props->max_srq = props->max_qp;
@@ -104,15 +105,15 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
props->local_ca_ack_delay
= rblock->local_ca_ack_delay;
props->max_raw_ipv6_qp
- = min_t(int, rblock->max_raw_ipv6_qp, INT_MAX);
+ = min_t(unsigned, rblock->max_raw_ipv6_qp, INT_MAX);
props->max_raw_ethy_qp
- = min_t(int, rblock->max_raw_ethy_qp, INT_MAX);
+ = min_t(unsigned, rblock->max_raw_ethy_qp, INT_MAX);
props->max_mcast_grp
- = min_t(int, rblock->max_mcast_grp, INT_MAX);
+ = min_t(unsigned, rblock->max_mcast_grp, INT_MAX);
props->max_mcast_qp_attach
- = min_t(int, rblock->max_mcast_qp_attach, INT_MAX);
+ = min_t(unsigned, rblock->max_mcast_qp_attach, INT_MAX);
props->max_total_mcast_qp_attach
- = min_t(int, rblock->max_total_mcast_qp_attach, INT_MAX);
+ = min_t(unsigned, rblock->max_total_mcast_qp_attach, INT_MAX);
/* translate device capabilities */
props->device_cap_flags = IB_DEVICE_SYS_IMAGE_GUID |
@@ -150,7 +151,6 @@ int ehca_query_port(struct ib_device *ibdev,
}
memset(props, 0, sizeof(struct ib_port_attr));
- props->state = rblock->state;
switch (rblock->max_mtu) {
case 0x1:
@@ -187,11 +187,20 @@ int ehca_query_port(struct ib_device *ibdev,
props->subnet_timeout = rblock->subnet_timeout;
props->init_type_reply = rblock->init_type_reply;
- props->active_width = IB_WIDTH_12X;
- props->active_speed = 0x1;
-
- /* at the moment (logical) link state is always LINK_UP */
- props->phys_state = 0x5;
+ if (rblock->state && rblock->phys_width) {
+ props->phys_state = rblock->phys_pstate;
+ props->state = rblock->phys_state;
+ props->active_width = rblock->phys_width;
+ props->active_speed = rblock->phys_speed;
+ } else {
+ /* old firmware releases don't report physical
+ * port info, so use default values
+ */
+ props->phys_state = 5;
+ props->state = rblock->state;
+ props->active_width = IB_WIDTH_12X;
+ props->active_speed = 0x1;
+ }
query_port1:
ehca_free_fw_ctrlblock(rblock);
@@ -352,7 +361,7 @@ int ehca_modify_port(struct ib_device *ibdev,
hret = hipz_h_modify_port(shca->ipz_hca_handle, port,
cap, props->init_type, port_modify_mask);
if (hret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "Modify port failed hret=%lx",
+ ehca_err(&shca->ib_device, "Modify port failed h_ret=%li",
hret);
ret = -EINVAL;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index a925ea52443..3f617b27b95 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -69,9 +69,6 @@
static void queue_comp_task(struct ehca_cq *__cq);
static struct ehca_comp_pool *pool;
-#ifdef CONFIG_HOTPLUG_CPU
-static struct notifier_block comp_pool_callback_nb;
-#endif
static inline void comp_event_callback(struct ehca_cq *cq)
{
@@ -294,8 +291,8 @@ static void parse_identifier(struct ehca_shca *shca, u64 eqe)
case 0x11: /* unaffiliated access error */
ehca_err(&shca->ib_device, "Unaffiliated access error.");
break;
- case 0x12: /* path migrating error */
- ehca_err(&shca->ib_device, "Path migration error.");
+ case 0x12: /* path migrating */
+ ehca_err(&shca->ib_device, "Path migrating.");
break;
case 0x13: /* interface trace stopped */
ehca_err(&shca->ib_device, "Interface trace stopped.");
@@ -760,9 +757,7 @@ static void destroy_comp_task(struct ehca_comp_pool *pool,
kthread_stop(task);
}
-#ifdef CONFIG_HOTPLUG_CPU
-static void take_over_work(struct ehca_comp_pool *pool,
- int cpu)
+static void __cpuinit take_over_work(struct ehca_comp_pool *pool, int cpu)
{
struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
LIST_HEAD(list);
@@ -785,9 +780,9 @@ static void take_over_work(struct ehca_comp_pool *pool,
}
-static int comp_pool_callback(struct notifier_block *nfb,
- unsigned long action,
- void *hcpu)
+static int __cpuinit comp_pool_callback(struct notifier_block *nfb,
+ unsigned long action,
+ void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
struct ehca_cpu_comp_task *cct;
@@ -833,7 +828,11 @@ static int comp_pool_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-#endif
+
+static struct notifier_block comp_pool_callback_nb __cpuinitdata = {
+ .notifier_call = comp_pool_callback,
+ .priority = 0,
+};
int ehca_create_comp_pool(void)
{
@@ -864,11 +863,7 @@ int ehca_create_comp_pool(void)
}
}
-#ifdef CONFIG_HOTPLUG_CPU
- comp_pool_callback_nb.notifier_call = comp_pool_callback;
- comp_pool_callback_nb.priority = 0;
- register_cpu_notifier(&comp_pool_callback_nb);
-#endif
+ register_hotcpu_notifier(&comp_pool_callback_nb);
printk(KERN_INFO "eHCA scaling code enabled\n");
@@ -882,9 +877,7 @@ void ehca_destroy_comp_pool(void)
if (!ehca_scaling_code)
return;
-#ifdef CONFIG_HOTPLUG_CPU
- unregister_cpu_notifier(&comp_pool_callback_nb);
-#endif
+ unregister_hotcpu_notifier(&comp_pool_callback_nb);
for (i = 0; i < NR_CPUS; i++) {
if (cpu_online(i))
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index dce503bb7d6..5485799cdc8 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -189,6 +189,9 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
void ehca_poll_eqs(unsigned long data);
+int ehca_calc_ipd(struct ehca_shca *shca, int port,
+ enum ib_rate path_rate, u32 *ipd);
+
#ifdef CONFIG_PPC_64K_PAGES
void *ehca_alloc_fw_ctrlblock(gfp_t flags);
void ehca_free_fw_ctrlblock(void *ptr);
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 99036b65bb8..90d4334179b 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -49,10 +49,12 @@
#include "ehca_tools.h"
#include "hcp_if.h"
+#define HCAD_VERSION "0024"
+
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
-MODULE_VERSION("SVNEHCA_0023");
+MODULE_VERSION(HCAD_VERSION);
int ehca_open_aqp1 = 0;
int ehca_debug_level = 0;
@@ -63,18 +65,18 @@ int ehca_port_act_time = 30;
int ehca_poll_all_eqs = 1;
int ehca_static_rate = -1;
int ehca_scaling_code = 0;
-int ehca_mr_largepage = 0;
-
-module_param_named(open_aqp1, ehca_open_aqp1, int, 0);
-module_param_named(debug_level, ehca_debug_level, int, 0);
-module_param_named(hw_level, ehca_hw_level, int, 0);
-module_param_named(nr_ports, ehca_nr_ports, int, 0);
-module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0);
-module_param_named(port_act_time, ehca_port_act_time, int, 0);
-module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0);
-module_param_named(static_rate, ehca_static_rate, int, 0);
-module_param_named(scaling_code, ehca_scaling_code, int, 0);
-module_param_named(mr_largepage, ehca_mr_largepage, int, 0);
+int ehca_mr_largepage = 1;
+
+module_param_named(open_aqp1, ehca_open_aqp1, int, S_IRUGO);
+module_param_named(debug_level, ehca_debug_level, int, S_IRUGO);
+module_param_named(hw_level, ehca_hw_level, int, S_IRUGO);
+module_param_named(nr_ports, ehca_nr_ports, int, S_IRUGO);
+module_param_named(use_hp_mr, ehca_use_hp_mr, int, S_IRUGO);
+module_param_named(port_act_time, ehca_port_act_time, int, S_IRUGO);
+module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, S_IRUGO);
+module_param_named(static_rate, ehca_static_rate, int, S_IRUGO);
+module_param_named(scaling_code, ehca_scaling_code, int, S_IRUGO);
+module_param_named(mr_largepage, ehca_mr_largepage, int, S_IRUGO);
MODULE_PARM_DESC(open_aqp1,
"AQP1 on startup (0: no (default), 1: yes)");
@@ -258,13 +260,20 @@ static struct cap_descr {
{ HCA_CAP_MINI_QP, "HCA_CAP_MINI_QP" },
};
-int ehca_sense_attributes(struct ehca_shca *shca)
+static int ehca_sense_attributes(struct ehca_shca *shca)
{
int i, ret = 0;
u64 h_ret;
struct hipz_query_hca *rblock;
struct hipz_query_port *port;
+ static const u32 pgsize_map[] = {
+ HCA_CAP_MR_PGSIZE_4K, 0x1000,
+ HCA_CAP_MR_PGSIZE_64K, 0x10000,
+ HCA_CAP_MR_PGSIZE_1M, 0x100000,
+ HCA_CAP_MR_PGSIZE_16M, 0x1000000,
+ };
+
rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!rblock) {
ehca_gen_err("Cannot allocate rblock memory.");
@@ -273,7 +282,7 @@ int ehca_sense_attributes(struct ehca_shca *shca)
h_ret = hipz_h_query_hca(shca->ipz_hca_handle, rblock);
if (h_ret != H_SUCCESS) {
- ehca_gen_err("Cannot query device properties. h_ret=%lx",
+ ehca_gen_err("Cannot query device properties. h_ret=%li",
h_ret);
ret = -EPERM;
goto sense_attributes1;
@@ -318,21 +327,25 @@ int ehca_sense_attributes(struct ehca_shca *shca)
shca->hw_level = ehca_hw_level;
ehca_gen_dbg(" ... hardware level=%x", shca->hw_level);
- shca->sport[0].rate = IB_RATE_30_GBPS;
- shca->sport[1].rate = IB_RATE_30_GBPS;
-
shca->hca_cap = rblock->hca_cap_indicators;
ehca_gen_dbg(" ... HCA capabilities:");
for (i = 0; i < ARRAY_SIZE(hca_cap_descr); i++)
if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap))
ehca_gen_dbg(" %s", hca_cap_descr[i].descr);
- shca->hca_cap_mr_pgsize = rblock->memory_page_size_supported;
+ /* translate supported MR page sizes; always support 4K */
+ shca->hca_cap_mr_pgsize = EHCA_PAGESIZE;
+ if (ehca_mr_largepage) { /* support extra sizes only if enabled */
+ for (i = 0; i < ARRAY_SIZE(pgsize_map); i += 2)
+ if (rblock->memory_page_size_supported & pgsize_map[i])
+ shca->hca_cap_mr_pgsize |= pgsize_map[i + 1];
+ }
+ /* query max MTU from first port -- it's the same for all ports */
port = (struct hipz_query_port *)rblock;
h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port);
if (h_ret != H_SUCCESS) {
- ehca_gen_err("Cannot query port properties. h_ret=%lx",
+ ehca_gen_err("Cannot query port properties. h_ret=%li",
h_ret);
ret = -EPERM;
goto sense_attributes1;
@@ -380,7 +393,7 @@ int ehca_init_device(struct ehca_shca *shca)
strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
shca->ib_device.owner = THIS_MODULE;
- shca->ib_device.uverbs_abi_ver = 7;
+ shca->ib_device.uverbs_abi_ver = 8;
shca->ib_device.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
@@ -402,7 +415,7 @@ int ehca_init_device(struct ehca_shca *shca)
shca->ib_device.node_type = RDMA_NODE_IB_CA;
shca->ib_device.phys_port_cnt = shca->num_ports;
shca->ib_device.num_comp_vectors = 1;
- shca->ib_device.dma_device = &shca->ibmebus_dev->ofdev.dev;
+ shca->ib_device.dma_device = &shca->ofdev->dev;
shca->ib_device.query_device = ehca_query_device;
shca->ib_device.query_port = ehca_query_port;
shca->ib_device.query_gid = ehca_query_gid;
@@ -526,13 +539,13 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport)
ret = ib_destroy_qp(sport->ibqp_aqp1);
if (ret) {
- ehca_gen_err("Cannot destroy AQP1 QP. ret=%x", ret);
+ ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret);
return ret;
}
ret = ib_destroy_cq(sport->ibcq_aqp1);
if (ret)
- ehca_gen_err("Cannot destroy AQP1 CQ. ret=%x", ret);
+ ehca_gen_err("Cannot destroy AQP1 CQ. ret=%i", ret);
return ret;
}
@@ -577,12 +590,12 @@ static ssize_t ehca_show_##name(struct device *dev, \
\
rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL); \
if (!rblock) { \
- dev_err(dev, "Can't allocate rblock memory."); \
+ dev_err(dev, "Can't allocate rblock memory.\n"); \
return 0; \
} \
\
if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) { \
- dev_err(dev, "Can't query device properties"); \
+ dev_err(dev, "Can't query device properties\n"); \
ehca_free_fw_ctrlblock(rblock); \
return 0; \
} \
@@ -656,7 +669,7 @@ static struct attribute_group ehca_dev_attr_grp = {
.attrs = ehca_dev_attrs
};
-static int __devinit ehca_probe(struct ibmebus_dev *dev,
+static int __devinit ehca_probe(struct of_device *dev,
const struct of_device_id *id)
{
struct ehca_shca *shca;
@@ -664,16 +677,16 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
struct ib_pd *ibpd;
int ret;
- handle = of_get_property(dev->ofdev.node, "ibm,hca-handle", NULL);
+ handle = of_get_property(dev->node, "ibm,hca-handle", NULL);
if (!handle) {
ehca_gen_err("Cannot get eHCA handle for adapter: %s.",
- dev->ofdev.node->full_name);
+ dev->node->full_name);
return -ENODEV;
}
if (!(*handle)) {
ehca_gen_err("Wrong eHCA handle for adapter: %s.",
- dev->ofdev.node->full_name);
+ dev->node->full_name);
return -ENODEV;
}
@@ -684,9 +697,9 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
}
mutex_init(&shca->modify_mutex);
- shca->ibmebus_dev = dev;
+ shca->ofdev = dev;
shca->ipz_hca_handle.handle = *handle;
- dev->ofdev.dev.driver_data = shca;
+ dev->dev.driver_data = shca;
ret = ehca_sense_attributes(shca);
if (ret < 0) {
@@ -728,7 +741,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
ret = ehca_reg_internal_maxmr(shca, shca->pd, &shca->maxmr);
if (ret) {
- ehca_err(&shca->ib_device, "Cannot create internal MR ret=%x",
+ ehca_err(&shca->ib_device, "Cannot create internal MR ret=%i",
ret);
goto probe5;
}
@@ -736,7 +749,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
ret = ib_register_device(&shca->ib_device);
if (ret) {
ehca_err(&shca->ib_device,
- "ib_register_device() failed ret=%x", ret);
+ "ib_register_device() failed ret=%i", ret);
goto probe6;
}
@@ -762,7 +775,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
}
}
- ret = sysfs_create_group(&dev->ofdev.dev.kobj, &ehca_dev_attr_grp);
+ ret = sysfs_create_group(&dev->dev.kobj, &ehca_dev_attr_grp);
if (ret) /* only complain; we can live without attributes */
ehca_err(&shca->ib_device,
"Cannot create device attributes ret=%d", ret);
@@ -777,7 +790,7 @@ probe8:
ret = ehca_destroy_aqp1(&shca->sport[0]);
if (ret)
ehca_err(&shca->ib_device,
- "Cannot destroy AQP1 for port 1. ret=%x", ret);
+ "Cannot destroy AQP1 for port 1. ret=%i", ret);
probe7:
ib_unregister_device(&shca->ib_device);
@@ -812,12 +825,12 @@ probe1:
return -EINVAL;
}
-static int __devexit ehca_remove(struct ibmebus_dev *dev)
+static int __devexit ehca_remove(struct of_device *dev)
{
- struct ehca_shca *shca = dev->ofdev.dev.driver_data;
+ struct ehca_shca *shca = dev->dev.driver_data;
int ret;
- sysfs_remove_group(&dev->ofdev.dev.kobj, &ehca_dev_attr_grp);
+ sysfs_remove_group(&dev->dev.kobj, &ehca_dev_attr_grp);
if (ehca_open_aqp1 == 1) {
int i;
@@ -826,7 +839,7 @@ static int __devexit ehca_remove(struct ibmebus_dev *dev)
if (ret)
ehca_err(&shca->ib_device,
"Cannot destroy AQP1 for port %x "
- "ret=%x", ret, i);
+ "ret=%i", ret, i);
}
}
@@ -835,20 +848,20 @@ static int __devexit ehca_remove(struct ibmebus_dev *dev)
ret = ehca_dereg_internal_maxmr(shca);
if (ret)
ehca_err(&shca->ib_device,
- "Cannot destroy internal MR. ret=%x", ret);
+ "Cannot destroy internal MR. ret=%i", ret);
ret = ehca_dealloc_pd(&shca->pd->ib_pd);
if (ret)
ehca_err(&shca->ib_device,
- "Cannot destroy internal PD. ret=%x", ret);
+ "Cannot destroy internal PD. ret=%i", ret);
ret = ehca_destroy_eq(shca, &shca->eq);
if (ret)
- ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%x", ret);
+ ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%i", ret);
ret = ehca_destroy_eq(shca, &shca->neq);
if (ret)
- ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%x", ret);
+ ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%i", ret);
ib_dealloc_device(&shca->ib_device);
@@ -868,11 +881,11 @@ static struct of_device_id ehca_device_table[] =
{},
};
-static struct ibmebus_driver ehca_driver = {
- .name = "ehca",
- .id_table = ehca_device_table,
- .probe = ehca_probe,
- .remove = ehca_remove,
+static struct of_platform_driver ehca_driver = {
+ .name = "ehca",
+ .match_table = ehca_device_table,
+ .probe = ehca_probe,
+ .remove = ehca_remove,
};
void ehca_poll_eqs(unsigned long data)
@@ -909,7 +922,7 @@ int __init ehca_module_init(void)
int ret;
printk(KERN_INFO "eHCA Infiniband Device Driver "
- "(Rel.: SVNEHCA_0023)\n");
+ "(Version " HCAD_VERSION ")\n");
ret = ehca_create_comp_pool();
if (ret) {
diff --git a/drivers/infiniband/hw/ehca/ehca_mcast.c b/drivers/infiniband/hw/ehca/ehca_mcast.c
index 32a870660bf..e3ef0264ccc 100644
--- a/drivers/infiniband/hw/ehca/ehca_mcast.c
+++ b/drivers/infiniband/hw/ehca/ehca_mcast.c
@@ -88,7 +88,7 @@ int ehca_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
if (h_ret != H_SUCCESS)
ehca_err(ibqp->device,
"ehca_qp=%p qp_num=%x hipz_h_attach_mcqp() failed "
- "h_ret=%lx", my_qp, ibqp->qp_num, h_ret);
+ "h_ret=%li", my_qp, ibqp->qp_num, h_ret);
return ehca2ib_return_code(h_ret);
}
@@ -125,7 +125,7 @@ int ehca_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
if (h_ret != H_SUCCESS)
ehca_err(ibqp->device,
"ehca_qp=%p qp_num=%x hipz_h_detach_mcqp() failed "
- "h_ret=%lx", my_qp, ibqp->qp_num, h_ret);
+ "h_ret=%li", my_qp, ibqp->qp_num, h_ret);
return ehca2ib_return_code(h_ret);
}
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
index d97eda3e1da..e239bbf54da 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.c
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -51,6 +51,7 @@
#define NUM_CHUNKS(length, chunk_size) \
(((length) + (chunk_size - 1)) / (chunk_size))
+
/* max number of rpages (per hcall register_rpages) */
#define MAX_RPAGES 512
@@ -64,26 +65,21 @@ enum ehca_mr_pgsize {
EHCA_MR_PGSIZE16M = 0x1000000L
};
+#define EHCA_MR_PGSHIFT4K 12
+#define EHCA_MR_PGSHIFT64K 16
+#define EHCA_MR_PGSHIFT1M 20
+#define EHCA_MR_PGSHIFT16M 24
+
static u32 ehca_encode_hwpage_size(u32 pgsize)
{
- u32 idx = 0;
- pgsize >>= 12;
- /*
- * map mr page size into hw code:
- * 0, 1, 2, 3 for 4K, 64K, 1M, 64M
- */
- while (!(pgsize & 1)) {
- idx++;
- pgsize >>= 4;
- }
- return idx;
+ int log = ilog2(pgsize);
+ WARN_ON(log < 12 || log > 24 || log & 3);
+ return (log - 12) / 4;
}
static u64 ehca_get_max_hwpage_size(struct ehca_shca *shca)
{
- if (shca->hca_cap_mr_pgsize & HCA_CAP_MR_PGSIZE_16M)
- return EHCA_MR_PGSIZE16M;
- return EHCA_MR_PGSIZE4K;
+ return 1UL << ilog2(shca->hca_cap_mr_pgsize);
}
static struct ehca_mr *ehca_mr_new(void)
@@ -159,7 +155,7 @@ struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
get_dma_mr_exit0:
if (IS_ERR(ib_mr))
- ehca_err(&shca->ib_device, "rc=%lx pd=%p mr_access_flags=%x ",
+ ehca_err(&shca->ib_device, "h_ret=%li pd=%p mr_access_flags=%x",
PTR_ERR(ib_mr), pd, mr_access_flags);
return ib_mr;
} /* end ehca_get_dma_mr() */
@@ -253,7 +249,7 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
pginfo.u.phy.num_phys_buf = num_phys_buf;
pginfo.u.phy.phys_buf_array = phys_buf_array;
pginfo.next_hwpage =
- ((u64)iova_start & ~(hw_pgsize - 1)) / hw_pgsize;
+ ((u64)iova_start & ~PAGE_MASK) / hw_pgsize;
ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags,
e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
@@ -271,7 +267,7 @@ reg_phys_mr_exit1:
ehca_mr_delete(e_mr);
reg_phys_mr_exit0:
if (IS_ERR(ib_mr))
- ehca_err(pd->device, "rc=%lx pd=%p phys_buf_array=%p "
+ ehca_err(pd->device, "h_ret=%li pd=%p phys_buf_array=%p "
"num_phys_buf=%x mr_access_flags=%x iova_start=%p",
PTR_ERR(ib_mr), pd, phys_buf_array,
num_phys_buf, mr_access_flags, iova_start);
@@ -290,7 +286,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
container_of(pd->device, struct ehca_shca, ib_device);
struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
struct ehca_mr_pginfo pginfo;
- int ret;
+ int ret, page_shift;
u32 num_kpages;
u32 num_hwpages;
u64 hwpage_size;
@@ -345,20 +341,20 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
/* determine number of MR pages */
num_kpages = NUM_CHUNKS((virt % PAGE_SIZE) + length, PAGE_SIZE);
/* select proper hw_pgsize */
- if (ehca_mr_largepage &&
- (shca->hca_cap_mr_pgsize & HCA_CAP_MR_PGSIZE_16M)) {
- if (length <= EHCA_MR_PGSIZE4K
- && PAGE_SIZE == EHCA_MR_PGSIZE4K)
- hwpage_size = EHCA_MR_PGSIZE4K;
- else if (length <= EHCA_MR_PGSIZE64K)
- hwpage_size = EHCA_MR_PGSIZE64K;
- else if (length <= EHCA_MR_PGSIZE1M)
- hwpage_size = EHCA_MR_PGSIZE1M;
- else
- hwpage_size = EHCA_MR_PGSIZE16M;
- } else
- hwpage_size = EHCA_MR_PGSIZE4K;
- ehca_dbg(pd->device, "hwpage_size=%lx", hwpage_size);
+ page_shift = PAGE_SHIFT;
+ if (e_mr->umem->hugetlb) {
+ /* determine page_shift, clamp between 4K and 16M */
+ page_shift = (fls64(length - 1) + 3) & ~3;
+ page_shift = min(max(page_shift, EHCA_MR_PGSHIFT4K),
+ EHCA_MR_PGSHIFT16M);
+ }
+ hwpage_size = 1UL << page_shift;
+
+ /* now that we have the desired page size, shift until it's
+ * supported, too. 4K is always supported, so this terminates.
+ */
+ while (!(hwpage_size & shca->hca_cap_mr_pgsize))
+ hwpage_size >>= 4;
reg_user_mr_fallback:
num_hwpages = NUM_CHUNKS((virt % hwpage_size) + length, hwpage_size);
@@ -403,8 +399,7 @@ reg_user_mr_exit1:
ehca_mr_delete(e_mr);
reg_user_mr_exit0:
if (IS_ERR(ib_mr))
- ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x"
- " udata=%p",
+ ehca_err(pd->device, "rc=%li pd=%p mr_access_flags=%x udata=%p",
PTR_ERR(ib_mr), pd, mr_access_flags, udata);
return ib_mr;
} /* end ehca_reg_user_mr() */
@@ -543,7 +538,7 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
pginfo.u.phy.num_phys_buf = num_phys_buf;
pginfo.u.phy.phys_buf_array = phys_buf_array;
pginfo.next_hwpage =
- ((u64)iova_start & ~(hw_pgsize - 1)) / hw_pgsize;
+ ((u64)iova_start & ~PAGE_MASK) / hw_pgsize;
}
if (mr_rereg_mask & IB_MR_REREG_ACCESS)
new_acl = mr_access_flags;
@@ -565,7 +560,7 @@ rereg_phys_mr_exit1:
spin_unlock_irqrestore(&e_mr->mrlock, sl_flags);
rereg_phys_mr_exit0:
if (ret)
- ehca_err(mr->device, "ret=%x mr=%p mr_rereg_mask=%x pd=%p "
+ ehca_err(mr->device, "ret=%i mr=%p mr_rereg_mask=%x pd=%p "
"phys_buf_array=%p num_phys_buf=%x mr_access_flags=%x "
"iova_start=%p",
ret, mr, mr_rereg_mask, pd, phys_buf_array,
@@ -607,7 +602,7 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
h_ret = hipz_h_query_mr(shca->ipz_hca_handle, e_mr, &hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(mr->device, "hipz_mr_query failed, h_ret=%lx mr=%p "
+ ehca_err(mr->device, "hipz_mr_query failed, h_ret=%li mr=%p "
"hca_hndl=%lx mr_hndl=%lx lkey=%x",
h_ret, mr, shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle, mr->lkey);
@@ -625,7 +620,7 @@ query_mr_exit1:
spin_unlock_irqrestore(&e_mr->mrlock, sl_flags);
query_mr_exit0:
if (ret)
- ehca_err(mr->device, "ret=%x mr=%p mr_attr=%p",
+ ehca_err(mr->device, "ret=%i mr=%p mr_attr=%p",
ret, mr, mr_attr);
return ret;
} /* end ehca_query_mr() */
@@ -667,7 +662,7 @@ int ehca_dereg_mr(struct ib_mr *mr)
/* TODO: BUSY: MR still has bound window(s) */
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
if (h_ret != H_SUCCESS) {
- ehca_err(mr->device, "hipz_free_mr failed, h_ret=%lx shca=%p "
+ ehca_err(mr->device, "hipz_free_mr failed, h_ret=%li shca=%p "
"e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x",
h_ret, shca, e_mr, shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle, mr->lkey);
@@ -683,7 +678,7 @@ int ehca_dereg_mr(struct ib_mr *mr)
dereg_mr_exit0:
if (ret)
- ehca_err(mr->device, "ret=%x mr=%p", ret, mr);
+ ehca_err(mr->device, "ret=%i mr=%p", ret, mr);
return ret;
} /* end ehca_dereg_mr() */
@@ -708,7 +703,7 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd)
h_ret = hipz_h_alloc_resource_mw(shca->ipz_hca_handle, e_mw,
e_pd->fw_pd, &hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lx "
+ ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%li "
"shca=%p hca_hndl=%lx mw=%p",
h_ret, shca, shca->ipz_hca_handle.handle, e_mw);
ib_mw = ERR_PTR(ehca2ib_return_code(h_ret));
@@ -723,7 +718,7 @@ alloc_mw_exit1:
ehca_mw_delete(e_mw);
alloc_mw_exit0:
if (IS_ERR(ib_mw))
- ehca_err(pd->device, "rc=%lx pd=%p", PTR_ERR(ib_mw), pd);
+ ehca_err(pd->device, "h_ret=%li pd=%p", PTR_ERR(ib_mw), pd);
return ib_mw;
} /* end ehca_alloc_mw() */
@@ -750,7 +745,7 @@ int ehca_dealloc_mw(struct ib_mw *mw)
h_ret = hipz_h_free_resource_mw(shca->ipz_hca_handle, e_mw);
if (h_ret != H_SUCCESS) {
- ehca_err(mw->device, "hipz_free_mw failed, h_ret=%lx shca=%p "
+ ehca_err(mw->device, "hipz_free_mw failed, h_ret=%li shca=%p "
"mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx",
h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle,
e_mw->ipz_mw_handle.handle);
@@ -805,8 +800,9 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
ib_fmr = ERR_PTR(-EINVAL);
goto alloc_fmr_exit0;
}
- hw_pgsize = ehca_get_max_hwpage_size(shca);
- if ((1 << fmr_attr->page_shift) != hw_pgsize) {
+
+ hw_pgsize = 1 << fmr_attr->page_shift;
+ if (!(hw_pgsize & shca->hca_cap_mr_pgsize)) {
ehca_err(pd->device, "unsupported fmr_attr->page_shift=%x",
fmr_attr->page_shift);
ib_fmr = ERR_PTR(-EINVAL);
@@ -822,6 +818,7 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
/* register MR on HCA */
memset(&pginfo, 0, sizeof(pginfo));
+ pginfo.hwpage_size = hw_pgsize;
/*
* pginfo.num_hwpages==0, ie register_rpages() will not be called
* but deferred to map_phys_fmr()
@@ -846,10 +843,6 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
alloc_fmr_exit1:
ehca_mr_delete(e_fmr);
alloc_fmr_exit0:
- if (IS_ERR(ib_fmr))
- ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x "
- "fmr_attr=%p", PTR_ERR(ib_fmr), pd,
- mr_access_flags, fmr_attr);
return ib_fmr;
} /* end ehca_alloc_fmr() */
@@ -916,7 +909,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
map_phys_fmr_exit0:
if (ret)
- ehca_err(fmr->device, "ret=%x fmr=%p page_list=%p list_len=%x "
+ ehca_err(fmr->device, "ret=%i fmr=%p page_list=%p list_len=%x "
"iova=%lx", ret, fmr, page_list, list_len, iova);
return ret;
} /* end ehca_map_phys_fmr() */
@@ -979,7 +972,7 @@ int ehca_unmap_fmr(struct list_head *fmr_list)
unmap_fmr_exit0:
if (ret)
- ehca_gen_err("ret=%x fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x",
+ ehca_gen_err("ret=%i fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x",
ret, fmr_list, num_fmr, unmap_fmr_cnt);
return ret;
} /* end ehca_unmap_fmr() */
@@ -1003,7 +996,7 @@ int ehca_dealloc_fmr(struct ib_fmr *fmr)
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
if (h_ret != H_SUCCESS) {
- ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%lx e_fmr=%p "
+ ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%li e_fmr=%p "
"hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x",
h_ret, e_fmr, shca->ipz_hca_handle.handle,
e_fmr->ipz_mr_handle.handle, fmr->lkey);
@@ -1016,7 +1009,7 @@ int ehca_dealloc_fmr(struct ib_fmr *fmr)
free_fmr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x fmr=%p", ret, fmr);
+ ehca_err(&shca->ib_device, "ret=%i fmr=%p", ret, fmr);
return ret;
} /* end ehca_dealloc_fmr() */
@@ -1046,7 +1039,7 @@ int ehca_reg_mr(struct ehca_shca *shca,
(u64)iova_start, size, hipz_acl,
e_pd->fw_pd, &hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lx "
+ ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%li "
"hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle);
ret = ehca2ib_return_code(h_ret);
goto ehca_reg_mr_exit0;
@@ -1072,9 +1065,9 @@ int ehca_reg_mr(struct ehca_shca *shca,
ehca_reg_mr_exit1:
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "h_ret=%lx shca=%p e_mr=%p "
+ ehca_err(&shca->ib_device, "h_ret=%li shca=%p e_mr=%p "
"iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x "
- "pginfo=%p num_kpages=%lx num_hwpages=%lx ret=%x",
+ "pginfo=%p num_kpages=%lx num_hwpages=%lx ret=%i",
h_ret, shca, e_mr, iova_start, size, acl, e_pd,
hipzout.lkey, pginfo, pginfo->num_kpages,
pginfo->num_hwpages, ret);
@@ -1083,7 +1076,7 @@ ehca_reg_mr_exit1:
}
ehca_reg_mr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
+ ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p "
"iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
"num_kpages=%lx num_hwpages=%lx",
ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo,
@@ -1127,7 +1120,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
ret = ehca_set_pagebuf(pginfo, rnum, kpage);
if (ret) {
ehca_err(&shca->ib_device, "ehca_set_pagebuf "
- "bad rc, ret=%x rnum=%x kpage=%p",
+ "bad rc, ret=%i rnum=%x kpage=%p",
ret, rnum, kpage);
goto ehca_reg_mr_rpages_exit1;
}
@@ -1155,7 +1148,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
*/
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "last "
- "hipz_reg_rpage_mr failed, h_ret=%lx "
+ "hipz_reg_rpage_mr failed, h_ret=%li "
"e_mr=%p i=%x hca_hndl=%lx mr_hndl=%lx"
" lkey=%x", h_ret, e_mr, i,
shca->ipz_hca_handle.handle,
@@ -1167,7 +1160,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
ret = 0;
} else if (h_ret != H_PAGE_REGISTERED) {
ehca_err(&shca->ib_device, "hipz_reg_rpage_mr failed, "
- "h_ret=%lx e_mr=%p i=%x lkey=%x hca_hndl=%lx "
+ "h_ret=%li e_mr=%p i=%x lkey=%x hca_hndl=%lx "
"mr_hndl=%lx", h_ret, e_mr, i,
e_mr->ib.ib_mr.lkey,
shca->ipz_hca_handle.handle,
@@ -1183,7 +1176,7 @@ ehca_reg_mr_rpages_exit1:
ehca_free_fw_ctrlblock(kpage);
ehca_reg_mr_rpages_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p "
+ ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p pginfo=%p "
"num_kpages=%lx num_hwpages=%lx", ret, shca, e_mr,
pginfo, pginfo->num_kpages, pginfo->num_hwpages);
return ret;
@@ -1244,7 +1237,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
* (MW bound or MR is shared)
*/
ehca_warn(&shca->ib_device, "hipz_h_reregister_pmr failed "
- "(Rereg1), h_ret=%lx e_mr=%p", h_ret, e_mr);
+ "(Rereg1), h_ret=%li e_mr=%p", h_ret, e_mr);
*pginfo = pginfo_save;
ret = -EAGAIN;
} else if ((u64 *)hipzout.vaddr != iova_start) {
@@ -1273,7 +1266,7 @@ ehca_rereg_mr_rereg1_exit1:
ehca_free_fw_ctrlblock(kpage);
ehca_rereg_mr_rereg1_exit0:
if ( ret && (ret != -EAGAIN) )
- ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x "
+ ehca_err(&shca->ib_device, "ret=%i lkey=%x rkey=%x "
"pginfo=%p num_kpages=%lx num_hwpages=%lx",
ret, *lkey, *rkey, pginfo, pginfo->num_kpages,
pginfo->num_hwpages);
@@ -1334,7 +1327,7 @@ int ehca_rereg_mr(struct ehca_shca *shca,
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "hipz_free_mr failed, "
- "h_ret=%lx e_mr=%p hca_hndl=%lx mr_hndl=%lx "
+ "h_ret=%li e_mr=%p hca_hndl=%lx mr_hndl=%lx "
"mr->lkey=%x",
h_ret, e_mr, shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle,
@@ -1366,7 +1359,7 @@ int ehca_rereg_mr(struct ehca_shca *shca,
ehca_rereg_mr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
+ ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p "
"iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
"num_kpages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
"rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size,
@@ -1410,7 +1403,7 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca,
* FMRs are not shared and no MW bound to FMRs
*/
ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
- "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx "
+ "(Rereg1), h_ret=%li e_fmr=%p hca_hndl=%lx "
"mr_hndl=%lx lkey=%x lkey_out=%x",
h_ret, e_fmr, shca->ipz_hca_handle.handle,
e_fmr->ipz_mr_handle.handle,
@@ -1422,7 +1415,7 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca,
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "hipz_free_mr failed, "
- "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
+ "h_ret=%li e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
"lkey=%x",
h_ret, e_fmr, shca->ipz_hca_handle.handle,
e_fmr->ipz_mr_handle.handle,
@@ -1457,7 +1450,7 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca,
ehca_unmap_one_fmr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x tmp_lkey=%x tmp_rkey=%x "
+ ehca_err(&shca->ib_device, "ret=%i tmp_lkey=%x tmp_rkey=%x "
"fmr_max_pages=%x",
ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages);
return ret;
@@ -1486,7 +1479,7 @@ int ehca_reg_smr(struct ehca_shca *shca,
(u64)iova_start, hipz_acl, e_pd->fw_pd,
&hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx "
+ ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%li "
"shca=%p e_origmr=%p e_newmr=%p iova_start=%p acl=%x "
"e_pd=%p hca_hndl=%lx mr_hndl=%lx lkey=%x",
h_ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd,
@@ -1510,7 +1503,7 @@ int ehca_reg_smr(struct ehca_shca *shca,
ehca_reg_smr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x shca=%p e_origmr=%p "
+ ehca_err(&shca->ib_device, "ret=%i shca=%p e_origmr=%p "
"e_newmr=%p iova_start=%p acl=%x e_pd=%p",
ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd);
return ret;
@@ -1585,7 +1578,7 @@ ehca_reg_internal_maxmr_exit1:
ehca_mr_delete(e_mr);
ehca_reg_internal_maxmr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x shca=%p e_pd=%p e_maxmr=%p",
+ ehca_err(&shca->ib_device, "ret=%i shca=%p e_pd=%p e_maxmr=%p",
ret, shca, e_pd, e_maxmr);
return ret;
} /* end ehca_reg_internal_maxmr() */
@@ -1612,7 +1605,7 @@ int ehca_reg_maxmr(struct ehca_shca *shca,
(u64)iova_start, hipz_acl, e_pd->fw_pd,
&hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx "
+ ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%li "
"e_origmr=%p hca_hndl=%lx mr_hndl=%lx lkey=%x",
h_ret, e_origmr, shca->ipz_hca_handle.handle,
e_origmr->ipz_mr_handle.handle,
@@ -1653,7 +1646,7 @@ int ehca_dereg_internal_maxmr(struct ehca_shca *shca)
ret = ehca_dereg_mr(&e_maxmr->ib.ib_mr);
if (ret) {
ehca_err(&shca->ib_device, "dereg internal max-MR failed, "
- "ret=%x e_maxmr=%p shca=%p lkey=%x",
+ "ret=%i e_maxmr=%p shca=%p lkey=%x",
ret, e_maxmr, shca, e_maxmr->ib.ib_mr.lkey);
shca->maxmr = e_maxmr;
goto ehca_dereg_internal_maxmr_exit0;
@@ -1663,7 +1656,7 @@ int ehca_dereg_internal_maxmr(struct ehca_shca *shca)
ehca_dereg_internal_maxmr_exit0:
if (ret)
- ehca_err(&shca->ib_device, "ret=%x shca=%p shca->maxmr=%p",
+ ehca_err(&shca->ib_device, "ret=%i shca=%p shca->maxmr=%p",
ret, shca, shca->maxmr);
return ret;
} /* end ehca_dereg_internal_maxmr() */
@@ -1776,7 +1769,7 @@ static int ehca_set_pagebuf_user1(struct ehca_mr_pginfo *pginfo,
list_for_each_entry_continue(
chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
- pgaddr = page_to_pfn(chunk->page_list[i].page)
+ pgaddr = page_to_pfn(sg_page(&chunk->page_list[i]))
<< PAGE_SHIFT ;
*kpage = phys_to_abs(pgaddr +
(pginfo->next_hwpage *
@@ -1832,7 +1825,7 @@ static int ehca_check_kpages_per_ate(struct scatterlist *page_list,
{
int t;
for (t = start_idx; t <= end_idx; t++) {
- u64 pgaddr = page_to_pfn(page_list[t].page) << PAGE_SHIFT;
+ u64 pgaddr = page_to_pfn(sg_page(&page_list[t])) << PAGE_SHIFT;
ehca_gen_dbg("chunk_page=%lx value=%016lx", pgaddr,
*(u64 *)abs_to_virt(phys_to_abs(pgaddr)));
if (pgaddr - PAGE_SIZE != *prev_pgaddr) {
@@ -1867,7 +1860,7 @@ static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo,
chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
if (nr_kpages == kpages_per_hwpage) {
- pgaddr = ( page_to_pfn(chunk->page_list[i].page)
+ pgaddr = ( page_to_pfn(sg_page(&chunk->page_list[i]))
<< PAGE_SHIFT );
*kpage = phys_to_abs(pgaddr);
if ( !(*kpage) ) {
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 84d435a5ee1..2e3e6547cb7 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -273,6 +273,7 @@ static inline void queue2resp(struct ipzu_queue_resp *resp,
resp->queue_length = queue->queue_length;
resp->pagesize = queue->pagesize;
resp->toggle_state = queue->toggle_state;
+ resp->offset = queue->offset;
}
/*
@@ -309,7 +310,7 @@ static inline int init_qp_queue(struct ehca_shca *shca,
}
if (!ipz_rc) {
- ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%x",
+ ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%i",
ipz_rc);
return -EBUSY;
}
@@ -333,7 +334,7 @@ static inline int init_qp_queue(struct ehca_shca *shca,
if (cnt == (nr_q_pages - 1)) { /* last page! */
if (h_ret != expected_hret) {
ehca_err(ib_dev, "hipz_qp_register_rpage() "
- "h_ret= %lx ", h_ret);
+ "h_ret=%li", h_ret);
ret = ehca2ib_return_code(h_ret);
goto init_qp_queue1;
}
@@ -347,7 +348,7 @@ static inline int init_qp_queue(struct ehca_shca *shca,
} else {
if (h_ret != H_PAGE_REGISTERED) {
ehca_err(ib_dev, "hipz_qp_register_rpage() "
- "h_ret= %lx ", h_ret);
+ "h_ret=%li", h_ret);
ret = ehca2ib_return_code(h_ret);
goto init_qp_queue1;
}
@@ -450,7 +451,6 @@ static struct ehca_qp *internal_create_qp(
has_srq = 1;
parms.ext_type = EQPT_SRQBASE;
parms.srq_qpn = my_srq->real_qp_num;
- parms.srq_token = my_srq->token;
}
if (is_llqp && has_srq) {
@@ -512,7 +512,7 @@ static struct ehca_qp *internal_create_qp(
} else if (init_attr->cap.max_send_wr > 255) {
ehca_err(pd->device,
"Invalid Number of "
- "ax_send_wr=%x for UD QP_TYPE=%x",
+ "max_send_wr=%x for UD QP_TYPE=%x",
init_attr->cap.max_send_wr, qp_type);
return ERR_PTR(-EINVAL);
}
@@ -523,6 +523,18 @@ static struct ehca_qp *internal_create_qp(
return ERR_PTR(-EINVAL);
break;
}
+ } else {
+ int max_sge = (qp_type == IB_QPT_UD || qp_type == IB_QPT_SMI
+ || qp_type == IB_QPT_GSI) ? 250 : 252;
+
+ if (init_attr->cap.max_send_sge > max_sge
+ || init_attr->cap.max_recv_sge > max_sge) {
+ ehca_err(pd->device, "Invalid number of SGEs requested "
+ "send_sge=%x recv_sge=%x max_sge=%x",
+ init_attr->cap.max_send_sge,
+ init_attr->cap.max_recv_sge, max_sge);
+ return ERR_PTR(-EINVAL);
+ }
}
if (pd->uobject && udata)
@@ -556,7 +568,6 @@ static struct ehca_qp *internal_create_qp(
write_lock_irqsave(&ehca_qp_idr_lock, flags);
ret = idr_get_new(&ehca_qp_idr, my_qp, &my_qp->token);
write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
-
} while (ret == -EAGAIN);
if (ret) {
@@ -565,11 +576,20 @@ static struct ehca_qp *internal_create_qp(
goto create_qp_exit0;
}
+ if (my_qp->token > 0x1FFFFFF) {
+ ret = -EINVAL;
+ ehca_err(pd->device, "Invalid number of qp");
+ goto create_qp_exit1;
+ }
+
+ if (has_srq)
+ parms.srq_token = my_qp->token;
+
parms.servicetype = ibqptype2servicetype(qp_type);
if (parms.servicetype < 0) {
ret = -EINVAL;
ehca_err(pd->device, "Invalid qp_type=%x", qp_type);
- goto create_qp_exit0;
+ goto create_qp_exit1;
}
if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
@@ -598,8 +618,7 @@ static struct ehca_qp *internal_create_qp(
parms.squeue.max_sge = max_send_sge;
parms.rqueue.max_sge = max_recv_sge;
- if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)
- && !(context && udata)) { /* no small QP support in userspace ATM */
+ if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)) {
if (HAS_SQ(my_qp))
ehca_determine_small_queue(
&parms.squeue, max_send_sge, is_llqp);
@@ -612,7 +631,7 @@ static struct ehca_qp *internal_create_qp(
h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms);
if (h_ret != H_SUCCESS) {
- ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%lx",
+ ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%li",
h_ret);
ret = ehca2ib_return_code(h_ret);
goto create_qp_exit1;
@@ -666,7 +685,7 @@ static struct ehca_qp *internal_create_qp(
&parms.squeue, swqe_size);
if (ret) {
ehca_err(pd->device, "Couldn't initialize squeue "
- "and pages ret=%x", ret);
+ "and pages ret=%i", ret);
goto create_qp_exit2;
}
}
@@ -677,7 +696,7 @@ static struct ehca_qp *internal_create_qp(
H_SUCCESS, &parms.rqueue, rwqe_size);
if (ret) {
ehca_err(pd->device, "Couldn't initialize rqueue "
- "and pages ret=%x", ret);
+ "and pages ret=%i", ret);
goto create_qp_exit3;
}
}
@@ -714,8 +733,6 @@ static struct ehca_qp *internal_create_qp(
if (qp_type == IB_QPT_GSI) {
h_ret = ehca_define_sqp(shca, my_qp, init_attr);
if (h_ret != H_SUCCESS) {
- ehca_err(pd->device, "ehca_define_sqp() failed rc=%lx",
- h_ret);
ret = ehca2ib_return_code(h_ret);
goto create_qp_exit4;
}
@@ -725,7 +742,7 @@ static struct ehca_qp *internal_create_qp(
ret = ehca_cq_assign_qp(my_qp->send_cq, my_qp);
if (ret) {
ehca_err(pd->device,
- "Couldn't assign qp to send_cq ret=%x", ret);
+ "Couldn't assign qp to send_cq ret=%i", ret);
goto create_qp_exit4;
}
}
@@ -741,12 +758,13 @@ static struct ehca_qp *internal_create_qp(
resp.ext_type = my_qp->ext_type;
resp.qkey = my_qp->qkey;
resp.real_qp_num = my_qp->real_qp_num;
- resp.ipz_rqueue.offset = my_qp->ipz_rqueue.offset;
- resp.ipz_squeue.offset = my_qp->ipz_squeue.offset;
+
if (HAS_SQ(my_qp))
queue2resp(&resp.ipz_squeue, &my_qp->ipz_squeue);
if (HAS_RQ(my_qp))
queue2resp(&resp.ipz_rqueue, &my_qp->ipz_rqueue);
+ resp.fw_handle_ofs = (u32)
+ (my_qp->galpas.user.fw_handle & (PAGE_SIZE - 1));
if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
ehca_err(pd->device, "Copy to udata failed");
@@ -841,7 +859,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
mqpcb, my_qp->galpas.kernel);
if (hret != H_SUCCESS) {
ehca_err(pd->device, "Could not modify SRQ to INIT"
- "ehca_qp=%p qp_num=%x hret=%lx",
+ "ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, my_qp->real_qp_num, hret);
goto create_srq2;
}
@@ -855,7 +873,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
mqpcb, my_qp->galpas.kernel);
if (hret != H_SUCCESS) {
ehca_err(pd->device, "Could not enable SRQ"
- "ehca_qp=%p qp_num=%x hret=%lx",
+ "ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, my_qp->real_qp_num, hret);
goto create_srq2;
}
@@ -869,11 +887,13 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
mqpcb, my_qp->galpas.kernel);
if (hret != H_SUCCESS) {
ehca_err(pd->device, "Could not modify SRQ to RTR"
- "ehca_qp=%p qp_num=%x hret=%lx",
+ "ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, my_qp->real_qp_num, hret);
goto create_srq2;
}
+ ehca_free_fw_ctrlblock(mqpcb);
+
return &my_qp->ib_srq;
create_srq2:
@@ -907,7 +927,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
&bad_send_wqe_p, NULL, 2);
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "hipz_h_disable_and_get_wqe() failed"
- " ehca_qp=%p qp_num=%x h_ret=%lx",
+ " ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, qp_num, h_ret);
return ehca2ib_return_code(h_ret);
}
@@ -985,7 +1005,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
mqpcb, my_qp->galpas.kernel);
if (h_ret != H_SUCCESS) {
ehca_err(ibqp->device, "hipz_h_query_qp() failed "
- "ehca_qp=%p qp_num=%x h_ret=%lx",
+ "ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, ibqp->qp_num, h_ret);
ret = ehca2ib_return_code(h_ret);
goto modify_qp_exit1;
@@ -1021,7 +1041,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
ibqp, &smiqp_attr, smiqp_attr_mask, 1);
if (smirc) {
ehca_err(ibqp->device, "SMI RESET -> INIT failed. "
- "ehca_modify_qp() rc=%x", smirc);
+ "ehca_modify_qp() rc=%i", smirc);
ret = H_PARAMETER;
goto modify_qp_exit1;
}
@@ -1123,7 +1143,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
ret = prepare_sqe_rts(my_qp, shca, &bad_wqe_cnt);
if (ret) {
ehca_err(ibqp->device, "prepare_sqe_rts() failed "
- "ehca_qp=%p qp_num=%x ret=%x",
+ "ehca_qp=%p qp_num=%x ret=%i",
my_qp, ibqp->qp_num, ret);
goto modify_qp_exit2;
}
@@ -1149,6 +1169,13 @@ static int internal_modify_qp(struct ib_qp *ibqp,
}
if (attr_mask & IB_QP_PKEY_INDEX) {
+ if (attr->pkey_index >= 16) {
+ ret = -EINVAL;
+ ehca_err(ibqp->device, "Invalid pkey_index=%x. "
+ "ehca_qp=%p qp_num=%x max_pkey_index=f",
+ attr->pkey_index, my_qp, ibqp->qp_num);
+ goto modify_qp_exit2;
+ }
mqpcb->prim_p_key_idx = attr->pkey_index;
update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1);
}
@@ -1169,10 +1196,6 @@ static int internal_modify_qp(struct ib_qp *ibqp,
update_mask |= EHCA_BMASK_SET(MQPCB_MASK_QKEY, 1);
}
if (attr_mask & IB_QP_AV) {
- int ah_mult = ib_rate_to_mult(attr->ah_attr.static_rate);
- int ehca_mult = ib_rate_to_mult(shca->sport[my_qp->
- init_attr.port_num].rate);
-
mqpcb->dlid = attr->ah_attr.dlid;
update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID, 1);
mqpcb->source_path_bits = attr->ah_attr.src_path_bits;
@@ -1180,11 +1203,12 @@ static int internal_modify_qp(struct ib_qp *ibqp,
mqpcb->service_level = attr->ah_attr.sl;
update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL, 1);
- if (ah_mult < ehca_mult)
- mqpcb->max_static_rate = (ah_mult > 0) ?
- ((ehca_mult - 1) / ah_mult) : 0;
- else
- mqpcb->max_static_rate = 0;
+ if (ehca_calc_ipd(shca, my_qp->init_attr.port_num,
+ attr->ah_attr.static_rate,
+ &mqpcb->max_static_rate)) {
+ ret = -EINVAL;
+ goto modify_qp_exit2;
+ }
update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE, 1);
/*
@@ -1253,54 +1277,80 @@ static int internal_modify_qp(struct ib_qp *ibqp,
(MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP, 1);
}
if (attr_mask & IB_QP_ALT_PATH) {
- int ah_mult = ib_rate_to_mult(attr->alt_ah_attr.static_rate);
- int ehca_mult = ib_rate_to_mult(
- shca->sport[my_qp->init_attr.port_num].rate);
+ if (attr->alt_port_num < 1
+ || attr->alt_port_num > shca->num_ports) {
+ ret = -EINVAL;
+ ehca_err(ibqp->device, "Invalid alt_port=%x. "
+ "ehca_qp=%p qp_num=%x num_ports=%x",
+ attr->alt_port_num, my_qp, ibqp->qp_num,
+ shca->num_ports);
+ goto modify_qp_exit2;
+ }
+ mqpcb->alt_phys_port = attr->alt_port_num;
+
+ if (attr->alt_pkey_index >= 16) {
+ ret = -EINVAL;
+ ehca_err(ibqp->device, "Invalid alt_pkey_index=%x. "
+ "ehca_qp=%p qp_num=%x max_pkey_index=f",
+ attr->pkey_index, my_qp, ibqp->qp_num);
+ goto modify_qp_exit2;
+ }
+ mqpcb->alt_p_key_idx = attr->alt_pkey_index;
+ mqpcb->timeout_al = attr->alt_timeout;
mqpcb->dlid_al = attr->alt_ah_attr.dlid;
- update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1);
mqpcb->source_path_bits_al = attr->alt_ah_attr.src_path_bits;
- update_mask |=
- EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1);
mqpcb->service_level_al = attr->alt_ah_attr.sl;
- update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1);
- if (ah_mult < ehca_mult)
- mqpcb->max_static_rate = (ah_mult > 0) ?
- ((ehca_mult - 1) / ah_mult) : 0;
- else
- mqpcb->max_static_rate_al = 0;
+ if (ehca_calc_ipd(shca, my_qp->init_attr.port_num,
+ attr->alt_ah_attr.static_rate,
+ &mqpcb->max_static_rate_al)) {
+ ret = -EINVAL;
+ goto modify_qp_exit2;
+ }
+
+ /* OpenIB doesn't support alternate retry counts - copy them */
+ mqpcb->retry_count_al = mqpcb->retry_count;
+ mqpcb->rnr_retry_count_al = mqpcb->rnr_retry_count;
- update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1);
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_ALT_PHYS_PORT, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_ALT_P_KEY_IDX, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_TIMEOUT_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_RETRY_COUNT_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_RNR_RETRY_COUNT_AL, 1);
+
+ /*
+ * Always supply the GRH flag, even if it's zero, to give the
+ * hypervisor a clear "yes" or "no" instead of a "perhaps"
+ */
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1);
/*
* only if GRH is TRUE we might consider SOURCE_GID_IDX
* and DEST_GID otherwise phype will return H_ATTR_PARM!!!
*/
if (attr->alt_ah_attr.ah_flags == IB_AH_GRH) {
- mqpcb->send_grh_flag_al = 1 << 31;
- update_mask |=
- EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1);
- mqpcb->source_gid_idx_al =
- attr->alt_ah_attr.grh.sgid_index;
- update_mask |=
- EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1);
+ mqpcb->send_grh_flag_al = 1;
for (cnt = 0; cnt < 16; cnt++)
mqpcb->dest_gid_al.byte[cnt] =
attr->alt_ah_attr.grh.dgid.raw[cnt];
-
- update_mask |=
- EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1);
+ mqpcb->source_gid_idx_al =
+ attr->alt_ah_attr.grh.sgid_index;
mqpcb->flow_label_al = attr->alt_ah_attr.grh.flow_label;
- update_mask |=
- EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1);
mqpcb->hop_limit_al = attr->alt_ah_attr.grh.hop_limit;
- update_mask |=
- EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1);
mqpcb->traffic_class_al =
attr->alt_ah_attr.grh.traffic_class;
+
update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1) |
EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS_AL, 1);
}
}
@@ -1322,7 +1372,14 @@ static int internal_modify_qp(struct ib_qp *ibqp,
}
if (attr_mask & IB_QP_PATH_MIG_STATE) {
- mqpcb->path_migration_state = attr->path_mig_state;
+ if (attr->path_mig_state != IB_MIG_REARM
+ && attr->path_mig_state != IB_MIG_MIGRATED) {
+ ret = -EINVAL;
+ ehca_err(ibqp->device, "Invalid mig_state=%x",
+ attr->path_mig_state);
+ goto modify_qp_exit2;
+ }
+ mqpcb->path_migration_state = attr->path_mig_state + 1;
update_mask |=
EHCA_BMASK_SET(MQPCB_MASK_PATH_MIGRATION_STATE, 1);
}
@@ -1348,7 +1405,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
- ehca_err(ibqp->device, "hipz_h_modify_qp() failed rc=%lx "
+ ehca_err(ibqp->device, "hipz_h_modify_qp() failed h_ret=%li "
"ehca_qp=%p qp_num=%x", h_ret, my_qp, ibqp->qp_num);
goto modify_qp_exit2;
}
@@ -1381,7 +1438,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
ret = ehca2ib_return_code(h_ret);
ehca_err(ibqp->device, "ENABLE in context of "
"RESET_2_INIT failed! Maybe you didn't get "
- "a LID h_ret=%lx ehca_qp=%p qp_num=%x",
+ "a LID h_ret=%li ehca_qp=%p qp_num=%x",
h_ret, my_qp, ibqp->qp_num);
goto modify_qp_exit2;
}
@@ -1469,7 +1526,7 @@ int ehca_query_qp(struct ib_qp *qp,
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
ehca_err(qp->device, "hipz_h_query_qp() failed "
- "ehca_qp=%p qp_num=%x h_ret=%lx",
+ "ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, qp->qp_num, h_ret);
goto query_qp_exit1;
}
@@ -1490,7 +1547,7 @@ int ehca_query_qp(struct ib_qp *qp,
qp_attr->qkey = qpcb->qkey;
qp_attr->path_mtu = qpcb->path_mtu;
- qp_attr->path_mig_state = qpcb->path_migration_state;
+ qp_attr->path_mig_state = qpcb->path_migration_state - 1;
qp_attr->rq_psn = qpcb->receive_psn;
qp_attr->sq_psn = qpcb->send_psn;
qp_attr->min_rnr_timer = qpcb->min_rnr_nak_timer_field;
@@ -1644,7 +1701,7 @@ int ehca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
- ehca_err(ibsrq->device, "hipz_h_modify_qp() failed rc=%lx "
+ ehca_err(ibsrq->device, "hipz_h_modify_qp() failed h_ret=%li "
"ehca_qp=%p qp_num=%x",
h_ret, my_qp, my_qp->real_qp_num);
}
@@ -1687,12 +1744,13 @@ int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr)
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
ehca_err(srq->device, "hipz_h_query_qp() failed "
- "ehca_qp=%p qp_num=%x h_ret=%lx",
+ "ehca_qp=%p qp_num=%x h_ret=%li",
my_qp, my_qp->real_qp_num, h_ret);
goto query_srq_exit1;
}
srq_attr->max_wr = qpcb->max_nr_outst_recv_wr - 1;
+ srq_attr->max_sge = qpcb->actual_nr_sges_in_rq_wqe;
srq_attr->srq_limit = EHCA_BMASK_GET(
MQPCB_CURR_SRQ_LIMIT, qpcb->curr_srq_limit);
@@ -1737,7 +1795,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
ret = ehca_cq_unassign_qp(my_qp->send_cq, qp_num);
if (ret) {
ehca_err(dev, "Couldn't unassign qp from "
- "send_cq ret=%x qp_num=%x cq_num=%x", ret,
+ "send_cq ret=%i qp_num=%x cq_num=%x", ret,
qp_num, my_qp->send_cq->cq_number);
return ret;
}
@@ -1749,7 +1807,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
if (h_ret != H_SUCCESS) {
- ehca_err(dev, "hipz_h_destroy_qp() failed rc=%lx "
+ ehca_err(dev, "hipz_h_destroy_qp() failed h_ret=%li "
"ehca_qp=%p qp_num=%x", h_ret, my_qp, qp_num);
return ehca2ib_return_code(h_ret);
}
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index 94eed70fedf..ea91360835d 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -526,7 +526,7 @@ poll_cq_one_read_cqe:
if (!cqe) {
ret = -EAGAIN;
ehca_dbg(cq->device, "Completion queue is empty ehca_cq=%p "
- "cq_num=%x ret=%x", my_cq, my_cq->cq_number, ret);
+ "cq_num=%x ret=%i", my_cq, my_cq->cq_number, ret);
goto poll_cq_one_exit0;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c
index 9f16e9c7939..f0792e5fbd0 100644
--- a/drivers/infiniband/hw/ehca/ehca_sqp.c
+++ b/drivers/infiniband/hw/ehca/ehca_sqp.c
@@ -82,7 +82,7 @@ u64 ehca_define_sqp(struct ehca_shca *shca,
if (ret != H_SUCCESS) {
ehca_err(&shca->ib_device,
- "Can't define AQP1 for port %x. rc=%lx",
+ "Can't define AQP1 for port %x. h_ret=%li",
port, ret);
return ret;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h
index 57c77a715f4..4a8346a2bc9 100644
--- a/drivers/infiniband/hw/ehca/ehca_tools.h
+++ b/drivers/infiniband/hw/ehca/ehca_tools.h
@@ -73,40 +73,37 @@ extern int ehca_debug_level;
if (unlikely(ehca_debug_level)) \
dev_printk(KERN_DEBUG, (ib_dev)->dma_device, \
"PU%04x EHCA_DBG:%s " format "\n", \
- get_paca()->paca_index, __FUNCTION__, \
+ raw_smp_processor_id(), __FUNCTION__, \
## arg); \
} while (0)
#define ehca_info(ib_dev, format, arg...) \
dev_info((ib_dev)->dma_device, "PU%04x EHCA_INFO:%s " format "\n", \
- get_paca()->paca_index, __FUNCTION__, ## arg)
+ raw_smp_processor_id(), __FUNCTION__, ## arg)
#define ehca_warn(ib_dev, format, arg...) \
dev_warn((ib_dev)->dma_device, "PU%04x EHCA_WARN:%s " format "\n", \
- get_paca()->paca_index, __FUNCTION__, ## arg)
+ raw_smp_processor_id(), __FUNCTION__, ## arg)
#define ehca_err(ib_dev, format, arg...) \
dev_err((ib_dev)->dma_device, "PU%04x EHCA_ERR:%s " format "\n", \
- get_paca()->paca_index, __FUNCTION__, ## arg)
+ raw_smp_processor_id(), __FUNCTION__, ## arg)
/* use this one only if no ib_dev available */
#define ehca_gen_dbg(format, arg...) \
do { \
if (unlikely(ehca_debug_level)) \
printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n", \
- get_paca()->paca_index, __FUNCTION__, ## arg); \
+ raw_smp_processor_id(), __FUNCTION__, ## arg); \
} while (0)
#define ehca_gen_warn(format, arg...) \
- do { \
- if (unlikely(ehca_debug_level)) \
- printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \
- get_paca()->paca_index, __FUNCTION__, ## arg); \
- } while (0)
+ printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \
+ raw_smp_processor_id(), __FUNCTION__, ## arg)
#define ehca_gen_err(format, arg...) \
printk(KERN_ERR "PU%04x EHCA_ERR:%s " format "\n", \
- get_paca()->paca_index, __FUNCTION__, ## arg)
+ raw_smp_processor_id(), __FUNCTION__, ## arg)
/**
* ehca_dmp - printk a memory block, whose length is n*8 bytes.
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
index 4bc687fdf53..5234d6c15c4 100644
--- a/drivers/infiniband/hw/ehca/ehca_uverbs.c
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -109,7 +109,7 @@ static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,
u64 vsize, physical;
vsize = vma->vm_end - vma->vm_start;
- if (vsize != EHCA_PAGESIZE) {
+ if (vsize < EHCA_PAGESIZE) {
ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start);
return -EINVAL;
}
@@ -118,10 +118,10 @@ static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical);
/* VM_IO | VM_RESERVED are set by remap_pfn_range() */
- ret = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT,
- vsize, vma->vm_page_prot);
+ ret = remap_4k_pfn(vma, vma->vm_start, physical >> EHCA_PAGESHIFT,
+ vma->vm_page_prot);
if (unlikely(ret)) {
- ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
+ ehca_gen_err("remap_pfn_range() failed ret=%i", ret);
return -ENOMEM;
}
@@ -146,7 +146,7 @@ static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,
page = virt_to_page(virt_addr);
ret = vm_insert_page(vma, start, page);
if (unlikely(ret)) {
- ehca_gen_err("vm_insert_page() failed rc=%x", ret);
+ ehca_gen_err("vm_insert_page() failed rc=%i", ret);
return ret;
}
start += PAGE_SIZE;
@@ -164,23 +164,23 @@ static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq,
int ret;
switch (rsrc_type) {
- case 1: /* galpa fw handle */
+ case 0: /* galpa fw handle */
ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number);
ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa);
if (unlikely(ret)) {
ehca_err(cq->ib_cq.device,
- "ehca_mmap_fw() failed rc=%x cq_num=%x",
+ "ehca_mmap_fw() failed rc=%i cq_num=%x",
ret, cq->cq_number);
return ret;
}
break;
- case 2: /* cq queue_addr */
+ case 1: /* cq queue_addr */
ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number);
ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue);
if (unlikely(ret)) {
ehca_err(cq->ib_cq.device,
- "ehca_mmap_queue() failed rc=%x cq_num=%x",
+ "ehca_mmap_queue() failed rc=%i cq_num=%x",
ret, cq->cq_number);
return ret;
}
@@ -201,38 +201,38 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
int ret;
switch (rsrc_type) {
- case 1: /* galpa fw handle */
+ case 0: /* galpa fw handle */
ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num);
ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa);
if (unlikely(ret)) {
ehca_err(qp->ib_qp.device,
- "remap_pfn_range() failed ret=%x qp_num=%x",
+ "remap_pfn_range() failed ret=%i qp_num=%x",
ret, qp->ib_qp.qp_num);
return -ENOMEM;
}
break;
- case 2: /* qp rqueue_addr */
+ case 1: /* qp rqueue_addr */
ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue",
qp->ib_qp.qp_num);
ret = ehca_mmap_queue(vma, &qp->ipz_rqueue,
&qp->mm_count_rqueue);
if (unlikely(ret)) {
ehca_err(qp->ib_qp.device,
- "ehca_mmap_queue(rq) failed rc=%x qp_num=%x",
+ "ehca_mmap_queue(rq) failed rc=%i qp_num=%x",
ret, qp->ib_qp.qp_num);
return ret;
}
break;
- case 3: /* qp squeue_addr */
+ case 2: /* qp squeue_addr */
ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue",
qp->ib_qp.qp_num);
ret = ehca_mmap_queue(vma, &qp->ipz_squeue,
&qp->mm_count_squeue);
if (unlikely(ret)) {
ehca_err(qp->ib_qp.device,
- "ehca_mmap_queue(sq) failed rc=%x qp_num=%x",
+ "ehca_mmap_queue(sq) failed rc=%i qp_num=%x",
ret, qp->ib_qp.qp_num);
return ret;
}
@@ -249,10 +249,10 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
{
- u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
- u32 idr_handle = fileoffset >> 32;
- u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
- u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
+ u64 fileoffset = vma->vm_pgoff;
+ u32 idr_handle = fileoffset & 0x1FFFFFF;
+ u32 q_type = (fileoffset >> 27) & 0x1; /* CQ, QP,... */
+ u32 rsrc_type = (fileoffset >> 25) & 0x3; /* sq,rq,cmnd_window */
u32 cur_pid = current->tgid;
u32 ret;
struct ehca_cq *cq;
@@ -261,7 +261,7 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
struct ib_uobject *uobject;
switch (q_type) {
- case 1: /* CQ */
+ case 0: /* CQ */
read_lock(&ehca_cq_idr_lock);
cq = idr_find(&ehca_cq_idr, idr_handle);
read_unlock(&ehca_cq_idr_lock);
@@ -283,13 +283,13 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
ret = ehca_mmap_cq(vma, cq, rsrc_type);
if (unlikely(ret)) {
ehca_err(cq->ib_cq.device,
- "ehca_mmap_cq() failed rc=%x cq_num=%x",
+ "ehca_mmap_cq() failed rc=%i cq_num=%x",
ret, cq->cq_number);
return ret;
}
break;
- case 2: /* QP */
+ case 1: /* QP */
read_lock(&ehca_qp_idr_lock);
qp = idr_find(&ehca_qp_idr, idr_handle);
read_unlock(&ehca_qp_idr_lock);
@@ -313,7 +313,7 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
ret = ehca_mmap_qp(vma, qp, rsrc_type);
if (unlikely(ret)) {
ehca_err(qp->ib_qp.device,
- "ehca_mmap_qp() failed rc=%x qp_num=%x",
+ "ehca_mmap_qp() failed rc=%i qp_num=%x",
ret, qp->ib_qp.qp_num);
return ret;
}
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c
index 24f454162f2..c16a21374bb 100644
--- a/drivers/infiniband/hw/ehca/hcp_if.c
+++ b/drivers/infiniband/hw/ehca/hcp_if.c
@@ -84,6 +84,10 @@
#define H_MP_SHUTDOWN EHCA_BMASK_IBM(48, 48)
#define H_MP_RESET_QKEY_CTR EHCA_BMASK_IBM(49, 49)
+#define HCALL4_REGS_FORMAT "r4=%lx r5=%lx r6=%lx r7=%lx"
+#define HCALL7_REGS_FORMAT HCALL4_REGS_FORMAT " r8=%lx r9=%lx r10=%lx"
+#define HCALL9_REGS_FORMAT HCALL7_REGS_FORMAT " r11=%lx r12=%lx"
+
static DEFINE_SPINLOCK(hcall_lock);
static u32 get_longbusy_msecs(int longbusy_rc)
@@ -116,16 +120,28 @@ static long ehca_plpar_hcall_norets(unsigned long opcode,
unsigned long arg7)
{
long ret;
- int i, sleep_msecs;
+ int i, sleep_msecs, do_lock;
+ unsigned long flags;
- ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
- "arg5=%lx arg6=%lx arg7=%lx",
+ ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT,
opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ /* lock H_FREE_RESOURCE(MR) against itself and H_ALLOC_RESOURCE(MR) */
+ if ((opcode == H_FREE_RESOURCE) && (arg7 == 5)) {
+ arg7 = 0; /* better not upset firmware */
+ do_lock = 1;
+ }
+
for (i = 0; i < 5; i++) {
+ if (do_lock)
+ spin_lock_irqsave(&hcall_lock, flags);
+
ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4,
arg5, arg6, arg7);
+ if (do_lock)
+ spin_unlock_irqrestore(&hcall_lock, flags);
+
if (H_IS_LONG_BUSY(ret)) {
sleep_msecs = get_longbusy_msecs(ret);
msleep_interruptible(sleep_msecs);
@@ -133,16 +149,13 @@ static long ehca_plpar_hcall_norets(unsigned long opcode,
}
if (ret < H_SUCCESS)
- ehca_gen_err("opcode=%lx ret=%lx"
- " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
- " arg5=%lx arg6=%lx arg7=%lx ",
- opcode, ret,
- arg1, arg2, arg3, arg4, arg5,
- arg6, arg7);
-
- ehca_gen_dbg("opcode=%lx ret=%lx", opcode, ret);
- return ret;
+ ehca_gen_err("opcode=%lx ret=%li " HCALL7_REGS_FORMAT,
+ opcode, ret, arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7);
+ else
+ ehca_gen_dbg("opcode=%lx ret=%li", opcode, ret);
+ return ret;
}
return H_BUSY;
@@ -161,25 +174,24 @@ static long ehca_plpar_hcall9(unsigned long opcode,
unsigned long arg9)
{
long ret;
- int i, sleep_msecs, lock_is_set = 0;
+ int i, sleep_msecs, do_lock;
unsigned long flags = 0;
- ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
- "arg5=%lx arg6=%lx arg7=%lx arg8=%lx arg9=%lx",
- opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
- arg8, arg9);
+ ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode,
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+
+ /* lock H_ALLOC_RESOURCE(MR) against itself and H_FREE_RESOURCE(MR) */
+ do_lock = ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5));
for (i = 0; i < 5; i++) {
- if ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5)) {
+ if (do_lock)
spin_lock_irqsave(&hcall_lock, flags);
- lock_is_set = 1;
- }
ret = plpar_hcall9(opcode, outs,
arg1, arg2, arg3, arg4, arg5,
arg6, arg7, arg8, arg9);
- if (lock_is_set)
+ if (do_lock)
spin_unlock_irqrestore(&hcall_lock, flags);
if (H_IS_LONG_BUSY(ret)) {
@@ -188,26 +200,19 @@ static long ehca_plpar_hcall9(unsigned long opcode,
continue;
}
- if (ret < H_SUCCESS)
- ehca_gen_err("opcode=%lx ret=%lx"
- " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
- " arg5=%lx arg6=%lx arg7=%lx arg8=%lx"
- " arg9=%lx"
- " out1=%lx out2=%lx out3=%lx out4=%lx"
- " out5=%lx out6=%lx out7=%lx out8=%lx"
- " out9=%lx",
- opcode, ret,
- arg1, arg2, arg3, arg4, arg5,
- arg6, arg7, arg8, arg9,
- outs[0], outs[1], outs[2], outs[3],
+ if (ret < H_SUCCESS) {
+ ehca_gen_err("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT,
+ opcode, arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, arg9);
+ ehca_gen_err("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT,
+ ret, outs[0], outs[1], outs[2], outs[3],
+ outs[4], outs[5], outs[6], outs[7],
+ outs[8]);
+ } else
+ ehca_gen_dbg("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT,
+ ret, outs[0], outs[1], outs[2], outs[3],
outs[4], outs[5], outs[6], outs[7],
outs[8]);
-
- ehca_gen_dbg("opcode=%lx ret=%lx out1=%lx out2=%lx out3=%lx "
- "out4=%lx out5=%lx out6=%lx out7=%lx out8=%lx "
- "out9=%lx",
- opcode, ret, outs[0], outs[1], outs[2], outs[3],
- outs[4], outs[5], outs[6], outs[7], outs[8]);
return ret;
}
@@ -247,7 +252,7 @@ u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle,
*eq_ist = (u32)outs[5];
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Not enough resource - ret=%lx ", ret);
+ ehca_gen_err("Not enough resource - ret=%li ", ret);
return ret;
}
@@ -285,7 +290,7 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]);
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Not enough resources. ret=%lx", ret);
+ ehca_gen_err("Not enough resources. ret=%li", ret);
return ret;
}
@@ -360,7 +365,7 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
hcp_galpas_ctor(&parms->galpas, outs[6], outs[6]);
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Not enough resources. ret=%lx", ret);
+ ehca_gen_err("Not enough resources. ret=%li", ret);
return ret;
}
@@ -555,7 +560,7 @@ u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle,
0, 0, 0, 0, 0);
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Insufficient resources ret=%lx", ret);
+ ehca_gen_err("Insufficient resources ret=%li", ret);
return ret;
}
@@ -591,7 +596,7 @@ u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
qp->ipz_qp_handle.handle, /* r6 */
0, 0, 0, 0, 0, 0);
if (ret == H_HARDWARE)
- ehca_gen_err("HCA not operational. ret=%lx", ret);
+ ehca_gen_err("HCA not operational. ret=%li", ret);
ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
adapter_handle.handle, /* r4 */
@@ -599,7 +604,7 @@ u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
0, 0, 0, 0, 0);
if (ret == H_RESOURCE)
- ehca_gen_err("Resource still in use. ret=%lx", ret);
+ ehca_gen_err("Resource still in use. ret=%li", ret);
return ret;
}
@@ -634,7 +639,7 @@ u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle,
*bma_qp_nr = (u32)outs[1];
if (ret == H_ALIAS_EXIST)
- ehca_gen_err("AQP1 already exists. ret=%lx", ret);
+ ehca_gen_err("AQP1 already exists. ret=%li", ret);
return ret;
}
@@ -656,7 +661,7 @@ u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle,
0, 0);
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Not enough resources. ret=%lx", ret);
+ ehca_gen_err("Not enough resources. ret=%li", ret);
return ret;
}
@@ -695,7 +700,7 @@ u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle,
0, 0, 0, 0);
if (ret == H_RESOURCE)
- ehca_gen_err("H_FREE_RESOURCE failed ret=%lx ", ret);
+ ehca_gen_err("H_FREE_RESOURCE failed ret=%li ", ret);
return ret;
}
@@ -717,7 +722,7 @@ u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle,
0, 0, 0, 0, 0);
if (ret == H_RESOURCE)
- ehca_gen_err("Resource in use. ret=%lx ", ret);
+ ehca_gen_err("Resource in use. ret=%li ", ret);
return ret;
}
@@ -816,7 +821,7 @@ u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle,
return ehca_plpar_hcall_norets(H_FREE_RESOURCE,
adapter_handle.handle, /* r4 */
mr->ipz_mr_handle.handle, /* r5 */
- 0, 0, 0, 0, 0);
+ 0, 0, 0, 0, 5);
}
u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle,
diff --git a/drivers/infiniband/hw/ehca/hipz_hw.h b/drivers/infiniband/hw/ehca/hipz_hw.h
index d9739e55451..485b8400359 100644
--- a/drivers/infiniband/hw/ehca/hipz_hw.h
+++ b/drivers/infiniband/hw/ehca/hipz_hw.h
@@ -402,7 +402,11 @@ struct hipz_query_port {
u64 max_msg_sz;
u32 max_mtu;
u32 vl_cap;
- u8 reserved2[1900];
+ u32 phys_pstate;
+ u32 phys_state;
+ u32 phys_speed;
+ u32 phys_width;
+ u8 reserved2[1884];
u64 guid_entries[255];
} __attribute__ ((packed));
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
index 29bd476fbd5..661f8db6270 100644
--- a/drivers/infiniband/hw/ehca/ipz_pt_fn.c
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
@@ -158,6 +158,7 @@ static int alloc_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd)
queue->queue_pages[0] = (void *)(page->page | (bit << (order + 9)));
queue->small_page = page;
+ queue->offset = bit << (order + 9);
return 1;
out:
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h
index 6ad822c3593..851df8a75e7 100644
--- a/drivers/infiniband/hw/ipath/ipath_common.h
+++ b/drivers/infiniband/hw/ipath/ipath_common.h
@@ -189,6 +189,8 @@ typedef enum _ipath_ureg {
#define IPATH_RUNTIME_RCVHDR_COPY 0x8
#define IPATH_RUNTIME_MASTER 0x10
/* 0x20 and 0x40 are no longer used, but are reserved for ABI compatibility */
+#define IPATH_RUNTIME_FORCE_PIOAVAIL 0x400
+#define IPATH_RUNTIME_PIO_REGSWAPPED 0x800
/*
* This structure is returned by ipath_userinit() immediately after
@@ -350,7 +352,7 @@ struct ipath_base_info {
* may not be implemented; the user code must deal with this if it
* cares, or it must abort after initialization reports the difference.
*/
-#define IPATH_USER_SWMINOR 5
+#define IPATH_USER_SWMINOR 6
#define IPATH_USER_SWVERSION ((IPATH_USER_SWMAJOR<<16) | IPATH_USER_SWMINOR)
diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c
index a6f04d27ec5..08d8ae148cd 100644
--- a/drivers/infiniband/hw/ipath/ipath_cq.c
+++ b/drivers/infiniband/hw/ipath/ipath_cq.c
@@ -76,22 +76,25 @@ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited)
}
return;
}
- wc->queue[head].wr_id = entry->wr_id;
- wc->queue[head].status = entry->status;
- wc->queue[head].opcode = entry->opcode;
- wc->queue[head].vendor_err = entry->vendor_err;
- wc->queue[head].byte_len = entry->byte_len;
- wc->queue[head].imm_data = (__u32 __force)entry->imm_data;
- wc->queue[head].qp_num = entry->qp->qp_num;
- wc->queue[head].src_qp = entry->src_qp;
- wc->queue[head].wc_flags = entry->wc_flags;
- wc->queue[head].pkey_index = entry->pkey_index;
- wc->queue[head].slid = entry->slid;
- wc->queue[head].sl = entry->sl;
- wc->queue[head].dlid_path_bits = entry->dlid_path_bits;
- wc->queue[head].port_num = entry->port_num;
- /* Make sure queue entry is written before the head index. */
- smp_wmb();
+ if (cq->ip) {
+ wc->uqueue[head].wr_id = entry->wr_id;
+ wc->uqueue[head].status = entry->status;
+ wc->uqueue[head].opcode = entry->opcode;
+ wc->uqueue[head].vendor_err = entry->vendor_err;
+ wc->uqueue[head].byte_len = entry->byte_len;
+ wc->uqueue[head].imm_data = (__u32 __force)entry->imm_data;
+ wc->uqueue[head].qp_num = entry->qp->qp_num;
+ wc->uqueue[head].src_qp = entry->src_qp;
+ wc->uqueue[head].wc_flags = entry->wc_flags;
+ wc->uqueue[head].pkey_index = entry->pkey_index;
+ wc->uqueue[head].slid = entry->slid;
+ wc->uqueue[head].sl = entry->sl;
+ wc->uqueue[head].dlid_path_bits = entry->dlid_path_bits;
+ wc->uqueue[head].port_num = entry->port_num;
+ /* Make sure entry is written before the head index. */
+ smp_wmb();
+ } else
+ wc->kqueue[head] = *entry;
wc->head = next;
if (cq->notify == IB_CQ_NEXT_COMP ||
@@ -130,6 +133,12 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
int npolled;
u32 tail;
+ /* The kernel can only poll a kernel completion queue */
+ if (cq->ip) {
+ npolled = -EINVAL;
+ goto bail;
+ }
+
spin_lock_irqsave(&cq->lock, flags);
wc = cq->queue;
@@ -137,31 +146,10 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
if (tail > (u32) cq->ibcq.cqe)
tail = (u32) cq->ibcq.cqe;
for (npolled = 0; npolled < num_entries; ++npolled, ++entry) {
- struct ipath_qp *qp;
-
if (tail == wc->head)
break;
- /* Make sure entry is read after head index is read. */
- smp_rmb();
- qp = ipath_lookup_qpn(&to_idev(cq->ibcq.device)->qp_table,
- wc->queue[tail].qp_num);
- entry->qp = &qp->ibqp;
- if (atomic_dec_and_test(&qp->refcount))
- wake_up(&qp->wait);
-
- entry->wr_id = wc->queue[tail].wr_id;
- entry->status = wc->queue[tail].status;
- entry->opcode = wc->queue[tail].opcode;
- entry->vendor_err = wc->queue[tail].vendor_err;
- entry->byte_len = wc->queue[tail].byte_len;
- entry->imm_data = wc->queue[tail].imm_data;
- entry->src_qp = wc->queue[tail].src_qp;
- entry->wc_flags = wc->queue[tail].wc_flags;
- entry->pkey_index = wc->queue[tail].pkey_index;
- entry->slid = wc->queue[tail].slid;
- entry->sl = wc->queue[tail].sl;
- entry->dlid_path_bits = wc->queue[tail].dlid_path_bits;
- entry->port_num = wc->queue[tail].port_num;
+ /* The kernel doesn't need a RMB since it has the lock. */
+ *entry = wc->kqueue[tail];
if (tail >= cq->ibcq.cqe)
tail = 0;
else
@@ -171,6 +159,7 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
spin_unlock_irqrestore(&cq->lock, flags);
+bail:
return npolled;
}
@@ -215,6 +204,7 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec
struct ipath_cq *cq;
struct ipath_cq_wc *wc;
struct ib_cq *ret;
+ u32 sz;
if (entries < 1 || entries > ib_ipath_max_cqes) {
ret = ERR_PTR(-EINVAL);
@@ -235,7 +225,12 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec
* We need to use vmalloc() in order to support mmap and large
* numbers of entries.
*/
- wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * entries);
+ sz = sizeof(*wc);
+ if (udata && udata->outlen >= sizeof(__u64))
+ sz += sizeof(struct ib_uverbs_wc) * (entries + 1);
+ else
+ sz += sizeof(struct ib_wc) * (entries + 1);
+ wc = vmalloc_user(sz);
if (!wc) {
ret = ERR_PTR(-ENOMEM);
goto bail_cq;
@@ -247,9 +242,8 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vec
*/
if (udata && udata->outlen >= sizeof(__u64)) {
int err;
- u32 s = sizeof *wc + sizeof(struct ib_wc) * entries;
- cq->ip = ipath_create_mmap_info(dev, s, context, wc);
+ cq->ip = ipath_create_mmap_info(dev, sz, context, wc);
if (!cq->ip) {
ret = ERR_PTR(-ENOMEM);
goto bail_wc;
@@ -380,6 +374,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
struct ipath_cq_wc *wc;
u32 head, tail, n;
int ret;
+ u32 sz;
if (cqe < 1 || cqe > ib_ipath_max_cqes) {
ret = -EINVAL;
@@ -389,7 +384,12 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
/*
* Need to use vmalloc() if we want to support large #s of entries.
*/
- wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * cqe);
+ sz = sizeof(*wc);
+ if (udata && udata->outlen >= sizeof(__u64))
+ sz += sizeof(struct ib_uverbs_wc) * (cqe + 1);
+ else
+ sz += sizeof(struct ib_wc) * (cqe + 1);
+ wc = vmalloc_user(sz);
if (!wc) {
ret = -ENOMEM;
goto bail;
@@ -404,7 +404,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
ret = ib_copy_to_udata(udata, &offset, sizeof(offset));
if (ret)
- goto bail;
+ goto bail_free;
}
spin_lock_irq(&cq->lock);
@@ -424,13 +424,14 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
else
n = head - tail;
if (unlikely((u32)cqe < n)) {
- spin_unlock_irq(&cq->lock);
- vfree(wc);
ret = -EOVERFLOW;
- goto bail;
+ goto bail_unlock;
}
for (n = 0; tail != head; n++) {
- wc->queue[n] = old_wc->queue[tail];
+ if (cq->ip)
+ wc->uqueue[n] = old_wc->uqueue[tail];
+ else
+ wc->kqueue[n] = old_wc->kqueue[tail];
if (tail == (u32) cq->ibcq.cqe)
tail = 0;
else
@@ -447,9 +448,8 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
if (cq->ip) {
struct ipath_ibdev *dev = to_idev(ibcq->device);
struct ipath_mmap_info *ip = cq->ip;
- u32 s = sizeof *wc + sizeof(struct ib_wc) * cqe;
- ipath_update_mmap_info(dev, ip, s, wc);
+ ipath_update_mmap_info(dev, ip, sz, wc);
spin_lock_irq(&dev->pending_lock);
if (list_empty(&ip->pending_mmaps))
list_add(&ip->pending_mmaps, &dev->pending_mmaps);
@@ -457,7 +457,12 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
}
ret = 0;
+ goto bail;
+bail_unlock:
+ spin_unlock_irq(&cq->lock);
+bail_free:
+ vfree(wc);
bail:
return ret;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
index cf25cdab02f..4137c7770f1 100644
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
@@ -446,19 +446,21 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
dd->ipath_unit, plen - 1, pbufn);
if (dp.pbc_wd == 0)
- /* Legacy operation, use computed pbc_wd */
dp.pbc_wd = plen;
-
- /* we have to flush after the PBC for correctness on some cpus
- * or WC buffer can be written out of order */
writeq(dp.pbc_wd, piobuf);
- ipath_flush_wc();
- /* copy all by the trigger word, then flush, so it's written
+ /*
+ * Copy all by the trigger word, then flush, so it's written
* to chip before trigger word, then write trigger word, then
- * flush again, so packet is sent. */
- __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
- ipath_flush_wc();
- __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
+ * flush again, so packet is sent.
+ */
+ if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) {
+ ipath_flush_wc();
+ __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
+ ipath_flush_wc();
+ __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
+ } else
+ __iowrite32_copy(piobuf + 2, tmpbuf, clen);
+
ipath_flush_wc();
ret = sizeof(dp);
diff --git a/drivers/infiniband/hw/ipath/ipath_dma.c b/drivers/infiniband/hw/ipath/ipath_dma.c
index f87f003e3ef..e90a0ea538a 100644
--- a/drivers/infiniband/hw/ipath/ipath_dma.c
+++ b/drivers/infiniband/hw/ipath/ipath_dma.c
@@ -30,6 +30,7 @@
* SOFTWARE.
*/
+#include <linux/scatterlist.h>
#include <rdma/ib_verbs.h>
#include "ipath_verbs.h"
@@ -96,17 +97,18 @@ static void ipath_dma_unmap_page(struct ib_device *dev,
BUG_ON(!valid_dma_direction(direction));
}
-static int ipath_map_sg(struct ib_device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction direction)
+static int ipath_map_sg(struct ib_device *dev, struct scatterlist *sgl,
+ int nents, enum dma_data_direction direction)
{
+ struct scatterlist *sg;
u64 addr;
int i;
int ret = nents;
BUG_ON(!valid_dma_direction(direction));
- for (i = 0; i < nents; i++) {
- addr = (u64) page_address(sg[i].page);
+ for_each_sg(sgl, sg, nents, i) {
+ addr = (u64) page_address(sg_page(sg));
/* TODO: handle highmem pages */
if (!addr) {
ret = 0;
@@ -125,7 +127,7 @@ static void ipath_unmap_sg(struct ib_device *dev,
static u64 ipath_sg_dma_address(struct ib_device *dev, struct scatterlist *sg)
{
- u64 addr = (u64) page_address(sg->page);
+ u64 addr = (u64) page_address(sg_page(sg));
if (addr)
addr += sg->offset;
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index 6ccba365a24..1f152ded1e3 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -34,6 +34,7 @@
#include <linux/spinlock.h>
#include <linux/idr.h>
#include <linux/pci.h>
+#include <linux/io.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/vmalloc.h>
@@ -280,6 +281,89 @@ void __attribute__((weak)) ipath_disable_wc(struct ipath_devdata *dd)
{
}
+/*
+ * Perform a PIO buffer bandwidth write test, to verify proper system
+ * configuration. Even when all the setup calls work, occasionally
+ * BIOS or other issues can prevent write combining from working, or
+ * can cause other bandwidth problems to the chip.
+ *
+ * This test simply writes the same buffer over and over again, and
+ * measures close to the peak bandwidth to the chip (not testing
+ * data bandwidth to the wire). On chips that use an address-based
+ * trigger to send packets to the wire, this is easy. On chips that
+ * use a count to trigger, we want to make sure that the packet doesn't
+ * go out on the wire, or trigger flow control checks.
+ */
+static void ipath_verify_pioperf(struct ipath_devdata *dd)
+{
+ u32 pbnum, cnt, lcnt;
+ u32 __iomem *piobuf;
+ u32 *addr;
+ u64 msecs, emsecs;
+
+ piobuf = ipath_getpiobuf(dd, &pbnum);
+ if (!piobuf) {
+ dev_info(&dd->pcidev->dev,
+ "No PIObufs for checking perf, skipping\n");
+ return;
+ }
+
+ /*
+ * Enough to give us a reasonable test, less than piobuf size, and
+ * likely multiple of store buffer length.
+ */
+ cnt = 1024;
+
+ addr = vmalloc(cnt);
+ if (!addr) {
+ dev_info(&dd->pcidev->dev,
+ "Couldn't get memory for checking PIO perf,"
+ " skipping\n");
+ goto done;
+ }
+
+ preempt_disable(); /* we want reasonably accurate elapsed time */
+ msecs = 1 + jiffies_to_msecs(jiffies);
+ for (lcnt = 0; lcnt < 10000U; lcnt++) {
+ /* wait until we cross msec boundary */
+ if (jiffies_to_msecs(jiffies) >= msecs)
+ break;
+ udelay(1);
+ }
+
+ writeq(0, piobuf); /* length 0, no dwords actually sent */
+ ipath_flush_wc();
+
+ /*
+ * this is only roughly accurate, since even with preempt we
+ * still take interrupts that could take a while. Running for
+ * >= 5 msec seems to get us "close enough" to accurate values
+ */
+ msecs = jiffies_to_msecs(jiffies);
+ for (emsecs = lcnt = 0; emsecs <= 5UL; lcnt++) {
+ __iowrite32_copy(piobuf + 64, addr, cnt >> 2);
+ emsecs = jiffies_to_msecs(jiffies) - msecs;
+ }
+
+ /* 1 GiB/sec, slightly over IB SDR line rate */
+ if (lcnt < (emsecs * 1024U))
+ ipath_dev_err(dd,
+ "Performance problem: bandwidth to PIO buffers is "
+ "only %u MiB/sec\n",
+ lcnt / (u32) emsecs);
+ else
+ ipath_dbg("PIO buffer bandwidth %u MiB/sec is OK\n",
+ lcnt / (u32) emsecs);
+
+ preempt_enable();
+
+ vfree(addr);
+
+done:
+ /* disarm piobuf, so it's available again */
+ ipath_disarm_piobufs(dd, pbnum, 1);
+}
+
static int __devinit ipath_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -298,8 +382,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
ipath_cdbg(VERBOSE, "initializing unit #%u\n", dd->ipath_unit);
- read_bars(dd, pdev, &bar0, &bar1);
-
ret = pci_enable_device(pdev);
if (ret) {
/* This can happen iff:
@@ -445,9 +527,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
goto bail_regions;
}
- dd->ipath_deviceid = ent->device; /* save for later use */
- dd->ipath_vendorid = ent->vendor;
-
dd->ipath_pcirev = pdev->revision;
#if defined(__powerpc__)
@@ -515,6 +594,8 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
ret = 0;
}
+ ipath_verify_pioperf(dd);
+
ipath_device_create_group(&pdev->dev, dd);
ipathfs_add_device(dd);
ipath_user_add(dd);
@@ -2005,6 +2086,8 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
INFINIPATH_IBCC_LINKINITCMD_SHIFT);
ipath_cancel_sends(dd, 0);
+ signal_ib_event(dd, IB_EVENT_PORT_ERR);
+
/* disable IBC */
dd->ipath_control &= ~INFINIPATH_C_LINKENABLE;
ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c
index b4503e9c1e9..e7c25dbbcdc 100644
--- a/drivers/infiniband/hw/ipath/ipath_eeprom.c
+++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c
@@ -538,7 +538,15 @@ static u8 flash_csum(struct ipath_flash *ifp, int adjust)
u8 *ip = (u8 *) ifp;
u8 csum = 0, len;
- for (len = 0; len < ifp->if_length; len++)
+ /*
+ * Limit length checksummed to max length of actual data.
+ * Checksum of erased eeprom will still be bad, but we avoid
+ * reading past the end of the buffer we were passed.
+ */
+ len = ifp->if_length;
+ if (len > sizeof(struct ipath_flash))
+ len = sizeof(struct ipath_flash);
+ while (len--)
csum += *ip++;
csum -= ifp->if_csum;
csum = ~csum;
@@ -596,7 +604,11 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
goto bail;
}
- len = offsetof(struct ipath_flash, if_future);
+ /*
+ * read full flash, not just currently used part, since it may have
+ * been written with a newer definition
+ * */
+ len = sizeof(struct ipath_flash);
buf = vmalloc(len);
if (!buf) {
ipath_dev_err(dd, "Couldn't allocate memory to read %u "
@@ -737,8 +749,10 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd)
/*
* The quick-check above determined that there is something worthy
* of logging, so get current contents and do a more detailed idea.
+ * read full flash, not just currently used part, since it may have
+ * been written with a newer definition
*/
- len = offsetof(struct ipath_flash, if_future);
+ len = sizeof(struct ipath_flash);
buf = vmalloc(len);
ret = 1;
if (!buf) {
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 33ab0d6b80f..5de3243a47c 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -538,6 +538,9 @@ static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport,
continue;
cnt++;
if (dd->ipath_pageshadow[porttid + tid]) {
+ struct page *p;
+ p = dd->ipath_pageshadow[porttid + tid];
+ dd->ipath_pageshadow[porttid + tid] = NULL;
ipath_cdbg(VERBOSE, "PID %u freeing TID %u\n",
pd->port_pid, tid);
dd->ipath_f_put_tid(dd, &tidbase[tid],
@@ -546,9 +549,7 @@ static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport,
pci_unmap_page(dd->pcidev,
dd->ipath_physshadow[porttid + tid],
PAGE_SIZE, PCI_DMA_FROMDEVICE);
- ipath_release_user_pages(
- &dd->ipath_pageshadow[porttid + tid], 1);
- dd->ipath_pageshadow[porttid + tid] = NULL;
+ ipath_release_user_pages(&p, 1);
ipath_stats.sps_pageunlocks++;
} else
ipath_dbg("Unused tid %u, ignoring\n", tid);
@@ -1341,6 +1342,19 @@ bail:
return ret;
}
+static unsigned ipath_poll_hdrqfull(struct ipath_portdata *pd)
+{
+ unsigned pollflag = 0;
+
+ if ((pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) &&
+ pd->port_hdrqfull != pd->port_hdrqfull_poll) {
+ pollflag |= POLLIN | POLLRDNORM;
+ pd->port_hdrqfull_poll = pd->port_hdrqfull;
+ }
+
+ return pollflag;
+}
+
static unsigned int ipath_poll_urgent(struct ipath_portdata *pd,
struct file *fp,
struct poll_table_struct *pt)
@@ -1350,22 +1364,20 @@ static unsigned int ipath_poll_urgent(struct ipath_portdata *pd,
dd = pd->port_dd;
- if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) {
- pollflag |= POLLERR;
- clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag);
- }
+ /* variable access in ipath_poll_hdrqfull() needs this */
+ rmb();
+ pollflag = ipath_poll_hdrqfull(pd);
- if (test_bit(IPATH_PORT_WAITING_URG, &pd->int_flag)) {
+ if (pd->port_urgent != pd->port_urgent_poll) {
pollflag |= POLLIN | POLLRDNORM;
- clear_bit(IPATH_PORT_WAITING_URG, &pd->int_flag);
+ pd->port_urgent_poll = pd->port_urgent;
}
if (!pollflag) {
+ /* this saves a spin_lock/unlock in interrupt handler... */
set_bit(IPATH_PORT_WAITING_URG, &pd->port_flag);
- if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW)
- set_bit(IPATH_PORT_WAITING_OVERFLOW,
- &pd->port_flag);
-
+ /* flush waiting flag so don't miss an event... */
+ wmb();
poll_wait(fp, &pd->port_wait, pt);
}
@@ -1376,31 +1388,27 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd,
struct file *fp,
struct poll_table_struct *pt)
{
- u32 head, tail;
+ u32 head;
+ u32 tail;
unsigned pollflag = 0;
struct ipath_devdata *dd;
dd = pd->port_dd;
+ /* variable access in ipath_poll_hdrqfull() needs this */
+ rmb();
+ pollflag = ipath_poll_hdrqfull(pd);
+
head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port);
tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr;
- if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) {
- pollflag |= POLLERR;
- clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag);
- }
-
- if (tail != head ||
- test_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag)) {
+ if (head != tail)
pollflag |= POLLIN | POLLRDNORM;
- clear_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag);
- }
-
- if (!pollflag) {
+ else {
+ /* this saves a spin_lock/unlock in interrupt handler */
set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
- if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW)
- set_bit(IPATH_PORT_WAITING_OVERFLOW,
- &pd->port_flag);
+ /* flush waiting flag so we don't miss an event */
+ wmb();
set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
&dd->ipath_rcvctrl);
@@ -1917,6 +1925,12 @@ static int ipath_do_user_init(struct file *fp,
ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
pd->port_port, head32);
pd->port_tidcursor = 0; /* start at beginning after open */
+
+ /* initialize poll variables... */
+ pd->port_urgent = 0;
+ pd->port_urgent_poll = 0;
+ pd->port_hdrqfull_poll = pd->port_hdrqfull;
+
/*
* now enable the port; the tail registers will be written to memory
* by the chip as soon as it sees the write to
@@ -2039,9 +2053,11 @@ static int ipath_close(struct inode *in, struct file *fp)
if (dd->ipath_kregbase) {
int i;
- /* atomically clear receive enable port. */
+ /* atomically clear receive enable port and intr avail. */
clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
&dd->ipath_rcvctrl);
+ clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
+ &dd->ipath_rcvctrl);
ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_rcvctrl);
/* and read back from chip to be sure that nothing
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index 2e689b974e1..262c25db05c 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -130,175 +130,6 @@ static const struct file_operations atomic_counters_ops = {
.read = atomic_counters_read,
};
-static ssize_t atomic_node_info_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- u32 nodeinfo[10];
- struct ipath_devdata *dd;
- u64 guid;
-
- dd = file->f_path.dentry->d_inode->i_private;
-
- guid = be64_to_cpu(dd->ipath_guid);
-
- nodeinfo[0] = /* BaseVersion is SMA */
- /* ClassVersion is SMA */
- (1 << 8) /* NodeType */
- | (1 << 0); /* NumPorts */
- nodeinfo[1] = (u32) (guid >> 32);
- nodeinfo[2] = (u32) (guid & 0xffffffff);
- /* PortGUID == SystemImageGUID for us */
- nodeinfo[3] = nodeinfo[1];
- /* PortGUID == SystemImageGUID for us */
- nodeinfo[4] = nodeinfo[2];
- /* PortGUID == NodeGUID for us */
- nodeinfo[5] = nodeinfo[3];
- /* PortGUID == NodeGUID for us */
- nodeinfo[6] = nodeinfo[4];
- nodeinfo[7] = (4 << 16) /* we support 4 pkeys */
- | (dd->ipath_deviceid << 0);
- /* our chip version as 16 bits major, 16 bits minor */
- nodeinfo[8] = dd->ipath_minrev | (dd->ipath_majrev << 16);
- nodeinfo[9] = (dd->ipath_unit << 24) | (dd->ipath_vendorid << 0);
-
- return simple_read_from_buffer(buf, count, ppos, nodeinfo,
- sizeof nodeinfo);
-}
-
-static const struct file_operations atomic_node_info_ops = {
- .read = atomic_node_info_read,
-};
-
-static ssize_t atomic_port_info_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- u32 portinfo[13];
- u32 tmp, tmp2;
- struct ipath_devdata *dd;
-
- dd = file->f_path.dentry->d_inode->i_private;
-
- /* so we only initialize non-zero fields. */
- memset(portinfo, 0, sizeof portinfo);
-
- /*
- * Notimpl yet M_Key (64)
- * Notimpl yet GID (64)
- */
-
- portinfo[4] = (dd->ipath_lid << 16);
-
- /*
- * Notimpl yet SMLID.
- * CapabilityMask is 0, we don't support any of these
- * DiagCode is 0; we don't store any diag info for now Notimpl yet
- * M_KeyLeasePeriod (we don't support M_Key)
- */
-
- /* LocalPortNum is whichever port number they ask for */
- portinfo[7] = (dd->ipath_unit << 24)
- /* LinkWidthEnabled */
- | (2 << 16)
- /* LinkWidthSupported (really 2, but not IB valid) */
- | (3 << 8)
- /* LinkWidthActive */
- | (2 << 0);
- tmp = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK;
- tmp2 = 5;
- if (tmp == IPATH_IBSTATE_INIT)
- tmp = 2;
- else if (tmp == IPATH_IBSTATE_ARM)
- tmp = 3;
- else if (tmp == IPATH_IBSTATE_ACTIVE)
- tmp = 4;
- else {
- tmp = 0; /* down */
- tmp2 = tmp & 0xf;
- }
-
- portinfo[8] = (1 << 28) /* LinkSpeedSupported */
- | (tmp << 24) /* PortState */
- | (tmp2 << 20) /* PortPhysicalState */
- | (2 << 16)
-
- /* LinkDownDefaultState */
- /* M_KeyProtectBits == 0 */
- /* NotImpl yet LMC == 0 (we can support all values) */
- | (1 << 4) /* LinkSpeedActive */
- | (1 << 0); /* LinkSpeedEnabled */
- switch (dd->ipath_ibmtu) {
- case 4096:
- tmp = 5;
- break;
- case 2048:
- tmp = 4;
- break;
- case 1024:
- tmp = 3;
- break;
- case 512:
- tmp = 2;
- break;
- case 256:
- tmp = 1;
- break;
- default: /* oops, something is wrong */
- ipath_dbg("Problem, ipath_ibmtu 0x%x not a valid IB MTU, "
- "treat as 2048\n", dd->ipath_ibmtu);
- tmp = 4;
- break;
- }
- portinfo[9] = (tmp << 28)
- /* NeighborMTU */
- /* Notimpl MasterSMSL */
- | (1 << 20)
-
- /* VLCap */
- /* Notimpl InitType (actually, an SMA decision) */
- /* VLHighLimit is 0 (only one VL) */
- ; /* VLArbitrationHighCap is 0 (only one VL) */
- /*
- * Note: the chips support a maximum MTU of 4096, but the driver
- * hasn't implemented this feature yet, so set the maximum
- * to 2048.
- */
- portinfo[10] = /* VLArbitrationLowCap is 0 (only one VL) */
- /* InitTypeReply is SMA decision */
- (4 << 16) /* MTUCap 2048 */
- | (7 << 13) /* VLStallCount */
- | (0x1f << 8) /* HOQLife */
- | (1 << 4)
-
- /* OperationalVLs 0 */
- /* PartitionEnforcementInbound */
- /* PartitionEnforcementOutbound not enforced */
- /* FilterRawinbound not enforced */
- ; /* FilterRawOutbound not enforced */
- /* M_KeyViolations are not counted by hardware, SMA can count */
- tmp = ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey);
- /* P_KeyViolations are counted by hardware. */
- portinfo[11] = ((tmp & 0xffff) << 0);
- portinfo[12] =
- /* Q_KeyViolations are not counted by hardware */
- (1 << 8)
-
- /* GUIDCap */
- /* SubnetTimeOut handled by SMA */
- /* RespTimeValue handled by SMA */
- ;
- /* LocalPhyErrors are programmed to max */
- portinfo[12] |= (0xf << 20)
- | (0xf << 16) /* OverRunErrors are programmed to max */
- ;
-
- return simple_read_from_buffer(buf, count, ppos, portinfo,
- sizeof portinfo);
-}
-
-static const struct file_operations atomic_port_info_ops = {
- .read = atomic_port_info_read,
-};
-
static ssize_t flash_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -427,22 +258,6 @@ static int create_device_files(struct super_block *sb,
goto bail;
}
- ret = create_file("node_info", S_IFREG|S_IRUGO, dir, &tmp,
- &atomic_node_info_ops, dd);
- if (ret) {
- printk(KERN_ERR "create_file(%s/node_info) "
- "failed: %d\n", unit, ret);
- goto bail;
- }
-
- ret = create_file("port_info", S_IFREG|S_IRUGO, dir, &tmp,
- &atomic_port_info_ops, dd);
- if (ret) {
- printk(KERN_ERR "create_file(%s/port_info) "
- "failed: %d\n", unit, ret);
- goto bail;
- }
-
ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp,
&flash_ops, dd);
if (ret) {
@@ -508,8 +323,6 @@ static int remove_device_files(struct super_block *sb,
}
remove_file(dir, "flash");
- remove_file(dir, "port_info");
- remove_file(dir, "node_info");
remove_file(dir, "atomic_counters");
d_delete(dir);
ret = simple_rmdir(root->d_inode, dir);
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index 650745d83fa..ddbebe4bdb2 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -631,56 +631,35 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
{
char *n = NULL;
u8 boardrev = dd->ipath_boardrev;
- int ret;
+ int ret = 0;
switch (boardrev) {
- case 4: /* Ponderosa is one of the bringup boards */
- n = "Ponderosa";
- break;
case 5:
/*
* original production board; two production levels, with
* different serial number ranges. See ipath_ht_early_init() for
* case where we enable IPATH_GPIO_INTR for later serial # range.
+ * Original 112* serial number is no longer supported.
*/
n = "InfiniPath_QHT7040";
break;
- case 6:
- n = "OEM_Board_3";
- break;
case 7:
/* small form factor production board */
n = "InfiniPath_QHT7140";
break;
- case 8:
- n = "LS/X-1";
- break;
- case 9: /* Comstock bringup test board */
- n = "Comstock";
- break;
- case 10:
- n = "OEM_Board_2";
- break;
- case 11:
- n = "InfiniPath_HT-470"; /* obsoleted */
- break;
- case 12:
- n = "OEM_Board_4";
- break;
default: /* don't know, just print the number */
ipath_dev_err(dd, "Don't yet know about board "
"with ID %u\n", boardrev);
snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u",
boardrev);
+ ret = 1;
break;
}
if (n)
snprintf(name, namelen, "%s", n);
- if (dd->ipath_boardrev != 6 && dd->ipath_boardrev != 7 &&
- dd->ipath_boardrev != 11) {
+ if (ret) {
ipath_dev_err(dd, "Unsupported InfiniPath board %s!\n", name);
- ret = 1;
goto bail;
}
if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 ||
@@ -1554,10 +1533,25 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
* can use GPIO interrupts. They have serial #'s starting
* with 128, rather than 112.
*/
- dd->ipath_flags |= IPATH_GPIO_INTR;
- } else
- ipath_dev_err(dd, "Unsupported InfiniPath serial "
- "number %.16s!\n", dd->ipath_serial);
+ if (dd->ipath_serial[0] == '1' &&
+ dd->ipath_serial[1] == '2' &&
+ dd->ipath_serial[2] == '8')
+ dd->ipath_flags |= IPATH_GPIO_INTR;
+ else {
+ ipath_dev_err(dd, "Unsupported InfiniPath board "
+ "(serial number %.16s)!\n",
+ dd->ipath_serial);
+ return 1;
+ }
+ }
+
+ if (dd->ipath_minrev >= 4) {
+ /* Rev4+ reports extra errors via internal GPIO pins */
+ dd->ipath_flags |= IPATH_GPIO_ERRINTRS;
+ dd->ipath_gpio_mask |= IPATH_GPIO_ERRINTR_MASK;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
+ dd->ipath_gpio_mask);
+ }
return 0;
}
@@ -1592,7 +1586,10 @@ static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase)
struct ipath_base_info *kinfo = kbase;
kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT |
- IPATH_RUNTIME_RCVHDR_COPY;
+ IPATH_RUNTIME_PIO_REGSWAPPED;
+
+ if (pd->port_dd->ipath_minrev < 4)
+ kinfo->spi_runtime_flags |= IPATH_RUNTIME_RCVHDR_COPY;
return 0;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
index 5b6ac9a1a70..0103d6f4847 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6120.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
@@ -1143,11 +1143,14 @@ static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr,
pa |= 2 << 29;
}
- /* workaround chip bug 9437 by writing each TID twice
- * and holding a spinlock around the writes, so they don't
- * intermix with other TID (eager or expected) writes
- * Unfortunately, this call can be done from interrupt level
- * for the port 0 eager TIDs, so we have to use irqsave
+ /*
+ * Workaround chip bug 9437 by writing the scratch register
+ * before and after the TID, and with an io write barrier.
+ * We use a spinlock around the writes, so they can't intermix
+ * with other TID (eager or expected) writes (the chip bug
+ * is triggered by back to back TID writes). Unfortunately, this
+ * call can be done from interrupt level for the port 0 eager TIDs,
+ * so we have to use irqsave locks.
*/
spin_lock_irqsave(&dd->ipath_tid_lock, flags);
ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xfeeddeaf);
@@ -1273,6 +1276,8 @@ static void ipath_pe_tidtemplate(struct ipath_devdata *dd)
static int ipath_pe_early_init(struct ipath_devdata *dd)
{
dd->ipath_flags |= IPATH_4BYTE_TID;
+ if (ipath_unordered_wc())
+ dd->ipath_flags |= IPATH_PIO_FLUSH_WC;
/*
* For openfabrics, we need to be able to handle an IB header of
@@ -1343,7 +1348,8 @@ static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase)
dd = pd->port_dd;
done:
- kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE;
+ kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE |
+ IPATH_RUNTIME_FORCE_PIOAVAIL | IPATH_RUNTIME_PIO_REGSWAPPED;
return 0;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index b29fe7e9b11..c61f9da2964 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -275,6 +275,16 @@ static char *ib_linkstate(u32 linkstate)
return ret;
}
+void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev)
+{
+ struct ib_event event;
+
+ event.device = &dd->verbs_dev->ibdev;
+ event.element.port_num = 1;
+ event.event = ev;
+ ib_dispatch_event(&event);
+}
+
static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
ipath_err_t errs, int noprint)
{
@@ -373,6 +383,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
dd->ipath_ibpollcnt = 0; /* some state other than 2 or 3 */
ipath_stats.sps_iblink++;
if (ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) {
+ if (dd->ipath_flags & IPATH_LINKACTIVE)
+ signal_ib_event(dd, IB_EVENT_PORT_ERR);
dd->ipath_flags |= IPATH_LINKDOWN;
dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT
| IPATH_LINKACTIVE |
@@ -405,7 +417,10 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
*dd->ipath_statusp |=
IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF;
dd->ipath_f_setextled(dd, lstate, ltstate);
+ signal_ib_event(dd, IB_EVENT_PORT_ACTIVE);
} else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) {
+ if (dd->ipath_flags & IPATH_LINKACTIVE)
+ signal_ib_event(dd, IB_EVENT_PORT_ERR);
/*
* set INIT and DOWN. Down is checked by most of the other
* code, but INIT is useful to know in a few places.
@@ -418,6 +433,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
| IPATH_STATUS_IB_READY);
dd->ipath_f_setextled(dd, lstate, ltstate);
} else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_ARM) {
+ if (dd->ipath_flags & IPATH_LINKACTIVE)
+ signal_ib_event(dd, IB_EVENT_PORT_ERR);
dd->ipath_flags |= IPATH_LINKARMED;
dd->ipath_flags &=
~(IPATH_LINKUNK | IPATH_LINKDOWN | IPATH_LINKINIT |
@@ -436,7 +453,7 @@ skip_ibchange:
}
static void handle_supp_msgs(struct ipath_devdata *dd,
- unsigned supp_msgs, char msg[512])
+ unsigned supp_msgs, char *msg, int msgsz)
{
/*
* Print the message unless it's ibc status change only, which
@@ -444,9 +461,9 @@ static void handle_supp_msgs(struct ipath_devdata *dd,
*/
if (dd->ipath_lasterror & ~INFINIPATH_E_IBSTATUSCHANGED) {
int iserr;
- iserr = ipath_decode_err(msg, sizeof msg,
- dd->ipath_lasterror &
- ~INFINIPATH_E_IBSTATUSCHANGED);
+ iserr = ipath_decode_err(msg, msgsz,
+ dd->ipath_lasterror &
+ ~INFINIPATH_E_IBSTATUSCHANGED);
if (dd->ipath_lasterror &
~(INFINIPATH_E_RRCVEGRFULL |
INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_PKTERRS))
@@ -475,8 +492,8 @@ static void handle_supp_msgs(struct ipath_devdata *dd,
}
static unsigned handle_frequent_errors(struct ipath_devdata *dd,
- ipath_err_t errs, char msg[512],
- int *noprint)
+ ipath_err_t errs, char *msg,
+ int msgsz, int *noprint)
{
unsigned long nc;
static unsigned long nextmsg_time;
@@ -495,7 +512,7 @@ static unsigned handle_frequent_errors(struct ipath_devdata *dd,
nextmsg_time = nc + HZ * 3;
}
else if (supp_msgs) {
- handle_supp_msgs(dd, supp_msgs, msg);
+ handle_supp_msgs(dd, supp_msgs, msg, msgsz);
supp_msgs = 0;
nmsgs = 0;
}
@@ -508,14 +525,14 @@ static unsigned handle_frequent_errors(struct ipath_devdata *dd,
static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
{
- char msg[512];
+ char msg[128];
u64 ignore_this_time = 0;
int i, iserr = 0;
int chkerrpkts = 0, noprint = 0;
unsigned supp_msgs;
int log_idx;
- supp_msgs = handle_frequent_errors(dd, errs, msg, &noprint);
+ supp_msgs = handle_frequent_errors(dd, errs, msg, sizeof msg, &noprint);
/* don't report errors that are masked */
errs &= ~dd->ipath_maskederrs;
@@ -688,17 +705,9 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
chkerrpkts = 1;
dd->ipath_lastrcvhdrqtails[i] = tl;
pd->port_hdrqfull++;
- if (test_bit(IPATH_PORT_WAITING_OVERFLOW,
- &pd->port_flag)) {
- clear_bit(
- IPATH_PORT_WAITING_OVERFLOW,
- &pd->port_flag);
- set_bit(
- IPATH_PORT_WAITING_OVERFLOW,
- &pd->int_flag);
- wake_up_interruptible(
- &pd->port_wait);
- }
+ /* flush hdrqfull so that poll() sees it */
+ wmb();
+ wake_up_interruptible(&pd->port_wait);
}
}
}
@@ -960,6 +969,8 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
int i;
int rcvdint = 0;
+ /* test_bit below needs this... */
+ rmb();
portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) &
dd->ipath_i_rcvavail_mask)
| ((istat >> INFINIPATH_I_RCVURG_SHIFT) &
@@ -967,22 +978,15 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
for (i = 1; i < dd->ipath_cfgports; i++) {
struct ipath_portdata *pd = dd->ipath_pd[i];
if (portr & (1 << i) && pd && pd->port_cnt) {
- if (test_bit(IPATH_PORT_WAITING_RCV,
- &pd->port_flag)) {
- clear_bit(IPATH_PORT_WAITING_RCV,
- &pd->port_flag);
- set_bit(IPATH_PORT_WAITING_RCV,
- &pd->int_flag);
+ if (test_and_clear_bit(IPATH_PORT_WAITING_RCV,
+ &pd->port_flag)) {
clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
&dd->ipath_rcvctrl);
wake_up_interruptible(&pd->port_wait);
rcvdint = 1;
- } else if (test_bit(IPATH_PORT_WAITING_URG,
- &pd->port_flag)) {
- clear_bit(IPATH_PORT_WAITING_URG,
- &pd->port_flag);
- set_bit(IPATH_PORT_WAITING_URG,
- &pd->int_flag);
+ } else if (test_and_clear_bit(IPATH_PORT_WAITING_URG,
+ &pd->port_flag)) {
+ pd->port_urgent++;
wake_up_interruptible(&pd->port_wait);
}
}
@@ -1085,8 +1089,8 @@ irqreturn_t ipath_intr(int irq, void *data)
* GPIO_2 indicates (on some HT4xx boards) that a packet
* has arrived for Port 0. Checking for this
* is controlled by flag IPATH_GPIO_INTR.
- * GPIO_3..5 on IBA6120 Rev2 chips indicate errors
- * that we need to count. Checking for this
+ * GPIO_3..5 on IBA6120 Rev2 and IBA6110 Rev4 chips indicate
+ * errors that we need to count. Checking for this
* is controlled by flag IPATH_GPIO_ERRINTRS.
*/
u32 gpiostatus;
@@ -1137,10 +1141,8 @@ irqreturn_t ipath_intr(int irq, void *data)
/*
* Some unexpected bits remain. If they could have
* caused the interrupt, complain and clear.
- * MEA: this is almost certainly non-ideal.
- * we should look into auto-disable of unexpected
- * GPIO interrupts, possibly on a "three strikes"
- * basis.
+ * To avoid repetition of this condition, also clear
+ * the mask. It is almost certainly due to error.
*/
const u32 mask = (u32) dd->ipath_gpio_mask;
@@ -1148,6 +1150,10 @@ irqreturn_t ipath_intr(int irq, void *data)
ipath_dbg("Unexpected GPIO IRQ bits %x\n",
gpiostatus & mask);
to_clear |= (gpiostatus & mask);
+ dd->ipath_gpio_mask &= ~(gpiostatus & mask);
+ ipath_write_kreg(dd,
+ dd->ipath_kregs->kr_gpio_mask,
+ dd->ipath_gpio_mask);
}
}
if (to_clear) {
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 7a7966f7e4f..8786dd7922e 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -42,6 +42,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
+#include <rdma/ib_verbs.h>
#include "ipath_common.h"
#include "ipath_debug.h"
@@ -139,6 +140,12 @@ struct ipath_portdata {
u32 port_pionowait;
/* total number of rcvhdrqfull errors */
u32 port_hdrqfull;
+ /* saved total number of rcvhdrqfull errors for poll edge trigger */
+ u32 port_hdrqfull_poll;
+ /* total number of polled urgent packets */
+ u32 port_urgent;
+ /* saved total number of polled urgent packets for poll edge trigger */
+ u32 port_urgent_poll;
/* pid of process using this port */
pid_t port_pid;
/* same size as task_struct .comm[] */
@@ -724,6 +731,8 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
#define IPATH_LINKACTIVE 0x200
/* link current state is unknown */
#define IPATH_LINKUNK 0x400
+ /* Write combining flush needed for PIO */
+#define IPATH_PIO_FLUSH_WC 0x1000
/* no IB cable, or no device on IB cable */
#define IPATH_NOCABLE 0x4000
/* Supports port zero per packet receive interrupts via
@@ -755,8 +764,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
#define IPATH_PORT_MASTER_UNINIT 4
/* waiting for an urgent packet to arrive */
#define IPATH_PORT_WAITING_URG 5
- /* waiting for a header overflow */
-#define IPATH_PORT_WAITING_OVERFLOW 6
/* free up any allocated data at closes */
void ipath_free_data(struct ipath_portdata *dd);
@@ -769,6 +776,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *);
int ipath_update_eeprom_log(struct ipath_devdata *dd);
void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr);
u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg);
+void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev);
/*
* Set LED override, only the two LSBs have "public" meaning, but
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c
index d61c0304454..3d1432d1e3f 100644
--- a/drivers/infiniband/hw/ipath/ipath_mad.c
+++ b/drivers/infiniband/hw/ipath/ipath_mad.c
@@ -245,7 +245,7 @@ static int recv_subn_get_portinfo(struct ib_smp *smp,
/* Only return the mkey if the protection field allows it. */
if (smp->method == IB_MGMT_METHOD_SET || dev->mkey == smp->mkey ||
- (dev->mkeyprot_resv_lmc >> 6) == 0)
+ dev->mkeyprot == 0)
pip->mkey = dev->mkey;
pip->gid_prefix = dev->gid_prefix;
lid = dev->dd->ipath_lid;
@@ -264,7 +264,7 @@ static int recv_subn_get_portinfo(struct ib_smp *smp,
pip->portphysstate_linkdown =
(ipath_cvt_physportstate[ibcstat & 0xf] << 4) |
(get_linkdowndefaultstate(dev->dd) ? 1 : 2);
- pip->mkeyprot_resv_lmc = dev->mkeyprot_resv_lmc;
+ pip->mkeyprot_resv_lmc = (dev->mkeyprot << 6) | dev->dd->ipath_lmc;
pip->linkspeedactive_enabled = 0x11; /* 2.5Gbps, 2.5Gbps */
switch (dev->dd->ipath_ibmtu) {
case 4096:
@@ -401,7 +401,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
struct ib_port_info *pip = (struct ib_port_info *)smp->data;
struct ib_event event;
struct ipath_ibdev *dev;
- u32 flags;
+ struct ipath_devdata *dd;
char clientrereg = 0;
u16 lid, smlid;
u8 lwe;
@@ -415,6 +415,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
goto err;
dev = to_idev(ibdev);
+ dd = dev->dd;
event.device = ibdev;
event.element.port_num = port;
@@ -423,11 +424,12 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
dev->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period);
lid = be16_to_cpu(pip->lid);
- if (lid != dev->dd->ipath_lid) {
+ if (dd->ipath_lid != lid ||
+ dd->ipath_lmc != (pip->mkeyprot_resv_lmc & 7)) {
/* Must be a valid unicast LID address. */
if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE)
goto err;
- ipath_set_lid(dev->dd, lid, pip->mkeyprot_resv_lmc & 7);
+ ipath_set_lid(dd, lid, pip->mkeyprot_resv_lmc & 7);
event.event = IB_EVENT_LID_CHANGE;
ib_dispatch_event(&event);
}
@@ -461,18 +463,18 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
case 0: /* NOP */
break;
case 1: /* SLEEP */
- if (set_linkdowndefaultstate(dev->dd, 1))
+ if (set_linkdowndefaultstate(dd, 1))
goto err;
break;
case 2: /* POLL */
- if (set_linkdowndefaultstate(dev->dd, 0))
+ if (set_linkdowndefaultstate(dd, 0))
goto err;
break;
default:
goto err;
}
- dev->mkeyprot_resv_lmc = pip->mkeyprot_resv_lmc;
+ dev->mkeyprot = pip->mkeyprot_resv_lmc >> 6;
dev->vl_high_limit = pip->vl_high_limit;
switch ((pip->neighbormtu_mastersmsl >> 4) & 0xF) {
@@ -495,7 +497,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
/* XXX We have already partially updated our state! */
goto err;
}
- ipath_set_mtu(dev->dd, mtu);
+ ipath_set_mtu(dd, mtu);
dev->sm_sl = pip->neighbormtu_mastersmsl & 0xF;
@@ -511,16 +513,16 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
* later.
*/
if (pip->pkey_violations == 0)
- dev->z_pkey_violations = ipath_get_cr_errpkey(dev->dd);
+ dev->z_pkey_violations = ipath_get_cr_errpkey(dd);
if (pip->qkey_violations == 0)
dev->qkey_violations = 0;
ore = pip->localphyerrors_overrunerrors;
- if (set_phyerrthreshold(dev->dd, (ore >> 4) & 0xF))
+ if (set_phyerrthreshold(dd, (ore >> 4) & 0xF))
goto err;
- if (set_overrunthreshold(dev->dd, (ore & 0xF)))
+ if (set_overrunthreshold(dd, (ore & 0xF)))
goto err;
dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F;
@@ -538,7 +540,6 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
* is down or is being set to down.
*/
state = pip->linkspeed_portstate & 0xF;
- flags = dev->dd->ipath_flags;
lstate = (pip->portphysstate_linkdown >> 4) & 0xF;
if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP))
goto err;
@@ -554,7 +555,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
/* FALLTHROUGH */
case IB_PORT_DOWN:
if (lstate == 0)
- if (get_linkdowndefaultstate(dev->dd))
+ if (get_linkdowndefaultstate(dd))
lstate = IPATH_IB_LINKDOWN_SLEEP;
else
lstate = IPATH_IB_LINKDOWN;
@@ -566,27 +567,13 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
lstate = IPATH_IB_LINKDOWN_DISABLE;
else
goto err;
- ipath_set_linkstate(dev->dd, lstate);
- if (flags & IPATH_LINKACTIVE) {
- event.event = IB_EVENT_PORT_ERR;
- ib_dispatch_event(&event);
- }
+ ipath_set_linkstate(dd, lstate);
break;
case IB_PORT_ARMED:
- if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE)))
- break;
- ipath_set_linkstate(dev->dd, IPATH_IB_LINKARM);
- if (flags & IPATH_LINKACTIVE) {
- event.event = IB_EVENT_PORT_ERR;
- ib_dispatch_event(&event);
- }
+ ipath_set_linkstate(dd, IPATH_IB_LINKARM);
break;
case IB_PORT_ACTIVE:
- if (!(flags & IPATH_LINKARMED))
- break;
- ipath_set_linkstate(dev->dd, IPATH_IB_LINKACTIVE);
- event.event = IB_EVENT_PORT_ACTIVE;
- ib_dispatch_event(&event);
+ ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
break;
default:
/* XXX We have already partially updated our state! */
@@ -1350,7 +1337,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags,
if (dev->mkey_lease_timeout && jiffies >= dev->mkey_lease_timeout) {
/* Clear timeout and mkey protection field. */
dev->mkey_lease_timeout = 0;
- dev->mkeyprot_resv_lmc &= 0x3F;
+ dev->mkeyprot = 0;
}
/*
@@ -1361,7 +1348,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags,
dev->mkey != smp->mkey &&
(smp->method == IB_MGMT_METHOD_SET ||
(smp->method == IB_MGMT_METHOD_GET &&
- (dev->mkeyprot_resv_lmc >> 7) != 0))) {
+ dev->mkeyprot >= 2))) {
if (dev->mkey_violations != 0xFFFF)
++dev->mkey_violations;
if (dev->mkey_lease_timeout ||
diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c
index e442470a237..db4ba92f79f 100644
--- a/drivers/infiniband/hw/ipath/ipath_mr.c
+++ b/drivers/infiniband/hw/ipath/ipath_mr.c
@@ -225,7 +225,7 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
for (i = 0; i < chunk->nents; i++) {
void *vaddr;
- vaddr = page_address(chunk->page_list[i].page);
+ vaddr = page_address(sg_page(&chunk->page_list[i]));
if (!vaddr) {
ret = ERR_PTR(-EINVAL);
goto bail;
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 1324b35ff1f..6a41fdbc8e5 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -338,6 +338,7 @@ static void ipath_reset_qp(struct ipath_qp *qp)
qp->s_busy = 0;
qp->s_flags &= IPATH_S_SIGNAL_REQ_WR;
qp->s_hdrwords = 0;
+ qp->s_wqe = NULL;
qp->s_psn = 0;
qp->r_psn = 0;
qp->r_msn = 0;
@@ -376,13 +377,15 @@ static void ipath_reset_qp(struct ipath_qp *qp)
* @err: the receive completion error to signal if a RWQE is active
*
* Flushes both send and receive work queues.
+ * Returns true if last WQE event should be generated.
* The QP s_lock should be held and interrupts disabled.
*/
-void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
+int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
{
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ib_wc wc;
+ int ret = 0;
ipath_dbg("QP%d/%d in error state\n",
qp->ibqp.qp_num, qp->remote_qpn);
@@ -453,7 +456,10 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
wq->tail = tail;
spin_unlock(&qp->r_rq.lock);
- }
+ } else if (qp->ibqp.event_handler)
+ ret = 1;
+
+ return ret;
}
/**
@@ -472,6 +478,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
struct ipath_qp *qp = to_iqp(ibqp);
enum ib_qp_state cur_state, new_state;
unsigned long flags;
+ int lastwqe = 0;
int ret;
spin_lock_irqsave(&qp->s_lock, flags);
@@ -531,7 +538,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
break;
case IB_QPS_ERR:
- ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
+ lastwqe = ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
break;
default:
@@ -590,6 +597,14 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
qp->state = new_state;
spin_unlock_irqrestore(&qp->s_lock, flags);
+ if (lastwqe) {
+ struct ib_event ev;
+
+ ev.device = qp->ibqp.device;
+ ev.element.qp = &qp->ibqp;
+ ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
+ qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+ }
ret = 0;
goto bail;
@@ -751,6 +766,9 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
switch (init_attr->qp_type) {
case IB_QPT_UC:
case IB_QPT_RC:
+ case IB_QPT_UD:
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
sz = sizeof(struct ipath_sge) *
init_attr->cap.max_send_sge +
sizeof(struct ipath_swqe);
@@ -759,10 +777,6 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
ret = ERR_PTR(-ENOMEM);
goto bail;
}
- /* FALLTHROUGH */
- case IB_QPT_UD:
- case IB_QPT_SMI:
- case IB_QPT_GSI:
sz = sizeof(*qp);
if (init_attr->srq) {
struct ipath_srq *srq = to_isrq(init_attr->srq);
@@ -805,8 +819,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
spin_lock_init(&qp->r_rq.lock);
atomic_set(&qp->refcount, 0);
init_waitqueue_head(&qp->wait);
- tasklet_init(&qp->s_task, ipath_do_ruc_send,
- (unsigned long)qp);
+ tasklet_init(&qp->s_task, ipath_do_send, (unsigned long)qp);
INIT_LIST_HEAD(&qp->piowait);
INIT_LIST_HEAD(&qp->timerwait);
qp->state = IB_QPS_RESET;
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index 46744ea2bab..120a61b03bc 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -81,9 +81,8 @@ static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe)
* Note that we are in the responder's side of the QP context.
* Note the QP s_lock must be held.
*/
-static int ipath_make_rc_ack(struct ipath_qp *qp,
- struct ipath_other_headers *ohdr,
- u32 pmtu, u32 *bth0p, u32 *bth2p)
+static int ipath_make_rc_ack(struct ipath_ibdev *dev, struct ipath_qp *qp,
+ struct ipath_other_headers *ohdr, u32 pmtu)
{
struct ipath_ack_entry *e;
u32 hwords;
@@ -192,8 +191,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
}
qp->s_hdrwords = hwords;
qp->s_cur_size = len;
- *bth0p = bth0 | (1 << 22); /* Set M bit */
- *bth2p = bth2;
+ ipath_make_ruc_header(dev, qp, ohdr, bth0, bth2);
return 1;
bail:
@@ -203,32 +201,39 @@ bail:
/**
* ipath_make_rc_req - construct a request packet (SEND, RDMA r/w, ATOMIC)
* @qp: a pointer to the QP
- * @ohdr: a pointer to the IB header being constructed
- * @pmtu: the path MTU
- * @bth0p: pointer to the BTH opcode word
- * @bth2p: pointer to the BTH PSN word
*
* Return 1 if constructed; otherwise, return 0.
- * Note the QP s_lock must be held and interrupts disabled.
*/
-int ipath_make_rc_req(struct ipath_qp *qp,
- struct ipath_other_headers *ohdr,
- u32 pmtu, u32 *bth0p, u32 *bth2p)
+int ipath_make_rc_req(struct ipath_qp *qp)
{
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
+ struct ipath_other_headers *ohdr;
struct ipath_sge_state *ss;
struct ipath_swqe *wqe;
u32 hwords;
u32 len;
u32 bth0;
u32 bth2;
+ u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
char newreq;
+ unsigned long flags;
+ int ret = 0;
+
+ ohdr = &qp->s_hdr.u.oth;
+ if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
+ ohdr = &qp->s_hdr.u.l.oth;
+
+ /*
+ * The lock is needed to synchronize between the sending tasklet,
+ * the receive interrupt handler, and timeout resends.
+ */
+ spin_lock_irqsave(&qp->s_lock, flags);
/* Sending responses has higher priority over sending requests. */
if ((qp->r_head_ack_queue != qp->s_tail_ack_queue ||
(qp->s_flags & IPATH_S_ACK_PENDING) ||
qp->s_ack_state != OP(ACKNOWLEDGE)) &&
- ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p))
+ ipath_make_rc_ack(dev, qp, ohdr, pmtu))
goto done;
if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) ||
@@ -560,13 +565,12 @@ int ipath_make_rc_req(struct ipath_qp *qp,
qp->s_hdrwords = hwords;
qp->s_cur_sge = ss;
qp->s_cur_size = len;
- *bth0p = bth0 | (qp->s_state << 24);
- *bth2p = bth2;
+ ipath_make_ruc_header(dev, qp, ohdr, bth0 | (qp->s_state << 24), bth2);
done:
- return 1;
-
+ ret = 1;
bail:
- return 0;
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ return ret;
}
/**
@@ -627,7 +631,7 @@ static void send_rc_ack(struct ipath_qp *qp)
/*
* If we can send the ACK, clear the ACK state.
*/
- if (ipath_verbs_send(dev->dd, hwords, (u32 *) &hdr, 0, NULL) == 0) {
+ if (ipath_verbs_send(qp, &hdr, hwords, NULL, 0) == 0) {
dev->n_unicast_xmit++;
goto done;
}
@@ -757,7 +761,9 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
wc->vendor_err = 0;
wc->byte_len = 0;
wc->qp = &qp->ibqp;
+ wc->imm_data = 0;
wc->src_qp = qp->remote_qpn;
+ wc->wc_flags = 0;
wc->pkey_index = 0;
wc->slid = qp->remote_ah_attr.dlid;
wc->sl = qp->remote_ah_attr.sl;
@@ -953,8 +959,9 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
/* If this is a partial ACK, reset the retransmit timer. */
if (qp->s_last != qp->s_tail) {
spin_lock(&dev->pending_lock);
- list_add_tail(&qp->timerwait,
- &dev->pending[dev->pending_index]);
+ if (list_empty(&qp->timerwait))
+ list_add_tail(&qp->timerwait,
+ &dev->pending[dev->pending_index]);
spin_unlock(&dev->pending_lock);
/*
* If we get a partial ACK for a resent operation,
@@ -1041,7 +1048,9 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
wc.vendor_err = 0;
wc.byte_len = 0;
wc.qp = &qp->ibqp;
+ wc.imm_data = 0;
wc.src_qp = qp->remote_qpn;
+ wc.wc_flags = 0;
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
wc.sl = qp->remote_ah_attr.sl;
@@ -1454,6 +1463,19 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
goto send_ack;
}
/*
+ * Try to send a simple ACK to work around a Mellanox bug
+ * which doesn't accept a RDMA read response or atomic
+ * response as an ACK for earlier SENDs or RDMA writes.
+ */
+ if (qp->r_head_ack_queue == qp->s_tail_ack_queue &&
+ !(qp->s_flags & IPATH_S_ACK_PENDING) &&
+ qp->s_ack_state == OP(ACKNOWLEDGE)) {
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ qp->r_nak_state = 0;
+ qp->r_ack_psn = qp->s_ack_queue[i].psn - 1;
+ goto send_ack;
+ }
+ /*
* Resend the RDMA read or atomic op which
* ACKs this duplicate request.
*/
@@ -1476,11 +1498,21 @@ send_ack:
static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
{
unsigned long flags;
+ int lastwqe;
spin_lock_irqsave(&qp->s_lock, flags);
qp->state = IB_QPS_ERR;
- ipath_error_qp(qp, err);
+ lastwqe = ipath_error_qp(qp, err);
spin_unlock_irqrestore(&qp->s_lock, flags);
+
+ if (lastwqe) {
+ struct ib_event ev;
+
+ ev.device = qp->ibqp.device;
+ ev.element.qp = &qp->ibqp;
+ ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
+ qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+ }
}
static inline void ipath_update_ack_queue(struct ipath_qp *qp, unsigned n)
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index c69c2523944..54c61a972de 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -31,6 +31,8 @@
* SOFTWARE.
*/
+#include <linux/spinlock.h>
+
#include "ipath_verbs.h"
#include "ipath_kernel.h"
@@ -106,27 +108,30 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp)
spin_unlock_irqrestore(&dev->pending_lock, flags);
}
-static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe)
+/**
+ * ipath_init_sge - Validate a RWQE and fill in the SGE state
+ * @qp: the QP
+ *
+ * Return 1 if OK.
+ */
+int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
+ u32 *lengthp, struct ipath_sge_state *ss)
{
- int user = to_ipd(qp->ibqp.pd)->user;
int i, j, ret;
struct ib_wc wc;
- qp->r_len = 0;
+ *lengthp = 0;
for (i = j = 0; i < wqe->num_sge; i++) {
if (wqe->sg_list[i].length == 0)
continue;
/* Check LKEY */
- if ((user && wqe->sg_list[i].lkey == 0) ||
- !ipath_lkey_ok(qp, &qp->r_sg_list[j], &wqe->sg_list[i],
- IB_ACCESS_LOCAL_WRITE))
+ if (!ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge,
+ &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE))
goto bad_lkey;
- qp->r_len += wqe->sg_list[i].length;
+ *lengthp += wqe->sg_list[i].length;
j++;
}
- qp->r_sge.sge = qp->r_sg_list[0];
- qp->r_sge.sg_list = qp->r_sg_list + 1;
- qp->r_sge.num_sge = j;
+ ss->num_sge = j;
ret = 1;
goto bail;
@@ -172,6 +177,8 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
u32 tail;
int ret;
+ qp->r_sge.sg_list = qp->r_sg_list;
+
if (qp->ibqp.srq) {
srq = to_isrq(qp->ibqp.srq);
handler = srq->ibsrq.event_handler;
@@ -199,7 +206,8 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
wqe = get_rwqe_ptr(rq, tail);
if (++tail >= rq->size)
tail = 0;
- } while (!wr_id_only && !init_sge(qp, wqe));
+ } while (!wr_id_only && !ipath_init_sge(qp, wqe, &qp->r_len,
+ &qp->r_sge));
qp->r_wr_id = wqe->wr_id;
wq->tail = tail;
@@ -239,9 +247,9 @@ bail:
/**
* ipath_ruc_loopback - handle UC and RC lookback requests
- * @sqp: the loopback QP
+ * @sqp: the sending QP
*
- * This is called from ipath_do_uc_send() or ipath_do_rc_send() to
+ * This is called from ipath_do_send() to
* forward a WQE addressed to the same HCA.
* Note that although we are single threaded due to the tasklet, we still
* have to protect against post_send(). We don't have to worry about
@@ -450,40 +458,18 @@ again:
wc.byte_len = wqe->length;
wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
- /* XXX do we know which pkey matched? Only needed for GSI. */
wc.pkey_index = 0;
wc.slid = qp->remote_ah_attr.dlid;
wc.sl = qp->remote_ah_attr.sl;
wc.dlid_path_bits = 0;
+ wc.port_num = 1;
/* Signal completion event if the solicited bit is set. */
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
wqe->wr.send_flags & IB_SEND_SOLICITED);
send_comp:
sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
-
- if (!(sqp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
- (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
- wc.wr_id = wqe->wr.wr_id;
- wc.status = IB_WC_SUCCESS;
- wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
- wc.vendor_err = 0;
- wc.byte_len = wqe->length;
- wc.qp = &sqp->ibqp;
- wc.src_qp = 0;
- wc.pkey_index = 0;
- wc.slid = 0;
- wc.sl = 0;
- wc.dlid_path_bits = 0;
- wc.port_num = 0;
- ipath_cq_enter(to_icq(sqp->ibqp.send_cq), &wc, 0);
- }
-
- /* Update s_last now that we are finished with the SWQE */
- spin_lock_irqsave(&sqp->s_lock, flags);
- if (++sqp->s_last >= sqp->s_size)
- sqp->s_last = 0;
- spin_unlock_irqrestore(&sqp->s_lock, flags);
+ ipath_send_complete(sqp, wqe, IB_WC_SUCCESS);
goto again;
done:
@@ -491,13 +477,11 @@ done:
wake_up(&qp->wait);
}
-static int want_buffer(struct ipath_devdata *dd)
+static void want_buffer(struct ipath_devdata *dd)
{
set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
-
- return 0;
}
/**
@@ -507,14 +491,11 @@ static int want_buffer(struct ipath_devdata *dd)
*
* Called when we run out of PIO buffers.
*/
-static void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
+static void ipath_no_bufs_available(struct ipath_qp *qp,
+ struct ipath_ibdev *dev)
{
unsigned long flags;
- spin_lock_irqsave(&dev->pending_lock, flags);
- if (list_empty(&qp->piowait))
- list_add_tail(&qp->piowait, &dev->piowait);
- spin_unlock_irqrestore(&dev->pending_lock, flags);
/*
* Note that as soon as want_buffer() is called and
* possibly before it returns, ipath_ib_piobufavail()
@@ -524,101 +505,14 @@ static void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev
* We leave the busy flag set so that another post send doesn't
* try to put the same QP on the piowait list again.
*/
+ spin_lock_irqsave(&dev->pending_lock, flags);
+ list_add_tail(&qp->piowait, &dev->piowait);
+ spin_unlock_irqrestore(&dev->pending_lock, flags);
want_buffer(dev->dd);
dev->n_piowait++;
}
/**
- * ipath_post_ruc_send - post RC and UC sends
- * @qp: the QP to post on
- * @wr: the work request to send
- */
-int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr)
-{
- struct ipath_swqe *wqe;
- unsigned long flags;
- u32 next;
- int i, j;
- int acc;
- int ret;
-
- /*
- * Don't allow RDMA reads or atomic operations on UC or
- * undefined operations.
- * Make sure buffer is large enough to hold the result for atomics.
- */
- if (qp->ibqp.qp_type == IB_QPT_UC) {
- if ((unsigned) wr->opcode >= IB_WR_RDMA_READ) {
- ret = -EINVAL;
- goto bail;
- }
- } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD) {
- ret = -EINVAL;
- goto bail;
- } else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP &&
- (wr->num_sge == 0 ||
- wr->sg_list[0].length < sizeof(u64) ||
- wr->sg_list[0].addr & (sizeof(u64) - 1))) {
- ret = -EINVAL;
- goto bail;
- } else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic) {
- ret = -EINVAL;
- goto bail;
- }
- /* IB spec says that num_sge == 0 is OK. */
- if (wr->num_sge > qp->s_max_sge) {
- ret = -ENOMEM;
- goto bail;
- }
- spin_lock_irqsave(&qp->s_lock, flags);
- next = qp->s_head + 1;
- if (next >= qp->s_size)
- next = 0;
- if (next == qp->s_last) {
- spin_unlock_irqrestore(&qp->s_lock, flags);
- ret = -EINVAL;
- goto bail;
- }
-
- wqe = get_swqe_ptr(qp, qp->s_head);
- wqe->wr = *wr;
- wqe->ssn = qp->s_ssn++;
- wqe->sg_list[0].mr = NULL;
- wqe->sg_list[0].vaddr = NULL;
- wqe->sg_list[0].length = 0;
- wqe->sg_list[0].sge_length = 0;
- wqe->length = 0;
- acc = wr->opcode >= IB_WR_RDMA_READ ? IB_ACCESS_LOCAL_WRITE : 0;
- for (i = 0, j = 0; i < wr->num_sge; i++) {
- if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) {
- spin_unlock_irqrestore(&qp->s_lock, flags);
- ret = -EINVAL;
- goto bail;
- }
- if (wr->sg_list[i].length == 0)
- continue;
- if (!ipath_lkey_ok(qp, &wqe->sg_list[j], &wr->sg_list[i],
- acc)) {
- spin_unlock_irqrestore(&qp->s_lock, flags);
- ret = -EINVAL;
- goto bail;
- }
- wqe->length += wr->sg_list[i].length;
- j++;
- }
- wqe->wr.num_sge = j;
- qp->s_head = next;
- spin_unlock_irqrestore(&qp->s_lock, flags);
-
- ipath_do_ruc_send((unsigned long) qp);
-
- ret = 0;
-
-bail:
- return ret;
-}
-
-/**
* ipath_make_grh - construct a GRH header
* @dev: a pointer to the ipath device
* @hdr: a pointer to the GRH header being constructed
@@ -648,39 +542,66 @@ u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr,
return sizeof(struct ib_grh) / sizeof(u32);
}
+void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp,
+ struct ipath_other_headers *ohdr,
+ u32 bth0, u32 bth2)
+{
+ u16 lrh0;
+ u32 nwords;
+ u32 extra_bytes;
+
+ /* Construct the header. */
+ extra_bytes = -qp->s_cur_size & 3;
+ nwords = (qp->s_cur_size + extra_bytes) >> 2;
+ lrh0 = IPATH_LRH_BTH;
+ if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
+ qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh,
+ &qp->remote_ah_attr.grh,
+ qp->s_hdrwords, nwords);
+ lrh0 = IPATH_LRH_GRH;
+ }
+ lrh0 |= qp->remote_ah_attr.sl << 4;
+ qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
+ qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
+ qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);
+ qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid);
+ bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index);
+ bth0 |= extra_bytes << 20;
+ ohdr->bth[0] = cpu_to_be32(bth0 | (1 << 22));
+ ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
+ ohdr->bth[2] = cpu_to_be32(bth2);
+}
+
/**
- * ipath_do_ruc_send - perform a send on an RC or UC QP
+ * ipath_do_send - perform a send on a QP
* @data: contains a pointer to the QP
*
* Process entries in the send work queue until credit or queue is
* exhausted. Only allow one CPU to send a packet per QP (tasklet).
- * Otherwise, after we drop the QP s_lock, two threads could send
- * packets out of order.
+ * Otherwise, two threads could send packets out of order.
*/
-void ipath_do_ruc_send(unsigned long data)
+void ipath_do_send(unsigned long data)
{
struct ipath_qp *qp = (struct ipath_qp *)data;
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
- unsigned long flags;
- u16 lrh0;
- u32 nwords;
- u32 extra_bytes;
- u32 bth0;
- u32 bth2;
- u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
- struct ipath_other_headers *ohdr;
+ int (*make_req)(struct ipath_qp *qp);
if (test_and_set_bit(IPATH_S_BUSY, &qp->s_busy))
goto bail;
- if (unlikely(qp->remote_ah_attr.dlid == dev->dd->ipath_lid)) {
+ if ((qp->ibqp.qp_type == IB_QPT_RC ||
+ qp->ibqp.qp_type == IB_QPT_UC) &&
+ qp->remote_ah_attr.dlid == dev->dd->ipath_lid) {
ipath_ruc_loopback(qp);
goto clear;
}
- ohdr = &qp->s_hdr.u.oth;
- if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
- ohdr = &qp->s_hdr.u.l.oth;
+ if (qp->ibqp.qp_type == IB_QPT_RC)
+ make_req = ipath_make_rc_req;
+ else if (qp->ibqp.qp_type == IB_QPT_UC)
+ make_req = ipath_make_uc_req;
+ else
+ make_req = ipath_make_ud_req;
again:
/* Check for a constructed packet to be sent. */
@@ -689,9 +610,8 @@ again:
* If no PIO bufs are available, return. An interrupt will
* call ipath_ib_piobufavail() when one is available.
*/
- if (ipath_verbs_send(dev->dd, qp->s_hdrwords,
- (u32 *) &qp->s_hdr, qp->s_cur_size,
- qp->s_cur_sge)) {
+ if (ipath_verbs_send(qp, &qp->s_hdr, qp->s_hdrwords,
+ qp->s_cur_sge, qp->s_cur_size)) {
ipath_no_bufs_available(qp, dev);
goto bail;
}
@@ -700,54 +620,46 @@ again:
qp->s_hdrwords = 0;
}
- /*
- * The lock is needed to synchronize between setting
- * qp->s_ack_state, resend timer, and post_send().
- */
- spin_lock_irqsave(&qp->s_lock, flags);
+ if (make_req(qp))
+ goto again;
+clear:
+ clear_bit(IPATH_S_BUSY, &qp->s_busy);
+bail:;
+}
- if (!((qp->ibqp.qp_type == IB_QPT_RC) ?
- ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2) :
- ipath_make_uc_req(qp, ohdr, pmtu, &bth0, &bth2))) {
- /*
- * Clear the busy bit before unlocking to avoid races with
- * adding new work queue items and then failing to process
- * them.
- */
- clear_bit(IPATH_S_BUSY, &qp->s_busy);
- spin_unlock_irqrestore(&qp->s_lock, flags);
- goto bail;
- }
+void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe,
+ enum ib_wc_status status)
+{
+ unsigned long flags;
+ u32 last;
- spin_unlock_irqrestore(&qp->s_lock, flags);
+ /* See ch. 11.2.4.1 and 10.7.3.1 */
+ if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
+ (wqe->wr.send_flags & IB_SEND_SIGNALED) ||
+ status != IB_WC_SUCCESS) {
+ struct ib_wc wc;
- /* Construct the header. */
- extra_bytes = (4 - qp->s_cur_size) & 3;
- nwords = (qp->s_cur_size + extra_bytes) >> 2;
- lrh0 = IPATH_LRH_BTH;
- if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
- qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh,
- &qp->remote_ah_attr.grh,
- qp->s_hdrwords, nwords);
- lrh0 = IPATH_LRH_GRH;
+ wc.wr_id = wqe->wr.wr_id;
+ wc.status = status;
+ wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
+ wc.vendor_err = 0;
+ wc.byte_len = wqe->length;
+ wc.imm_data = 0;
+ wc.qp = &qp->ibqp;
+ wc.src_qp = 0;
+ wc.wc_flags = 0;
+ wc.pkey_index = 0;
+ wc.slid = 0;
+ wc.sl = 0;
+ wc.dlid_path_bits = 0;
+ wc.port_num = 0;
+ ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0);
}
- lrh0 |= qp->remote_ah_attr.sl << 4;
- qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
- qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
- qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords +
- SIZE_OF_CRC);
- qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid);
- bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index);
- bth0 |= extra_bytes << 20;
- ohdr->bth[0] = cpu_to_be32(bth0);
- ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
- ohdr->bth[2] = cpu_to_be32(bth2);
-
- /* Check for more work to do. */
- goto again;
-clear:
- clear_bit(IPATH_S_BUSY, &qp->s_busy);
-bail:
- return;
+ spin_lock_irqsave(&qp->s_lock, flags);
+ last = qp->s_last;
+ if (++last >= qp->s_size)
+ last = 0;
+ qp->s_last = last;
+ spin_unlock_irqrestore(&qp->s_lock, flags);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c
index bae4f56f727..f0271415cd5 100644
--- a/drivers/infiniband/hw/ipath/ipath_stats.c
+++ b/drivers/infiniband/hw/ipath/ipath_stats.c
@@ -55,7 +55,6 @@ u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg)
u64 val64;
unsigned long t0, t1;
u64 ret;
- unsigned long flags;
t0 = jiffies;
/* If fast increment counters are only 32 bits, snapshot them,
@@ -92,18 +91,12 @@ u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg)
if (creg == dd->ipath_cregs->cr_wordsendcnt) {
if (val != dd->ipath_lastsword) {
dd->ipath_sword += val - dd->ipath_lastsword;
- spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
- dd->ipath_traffic_wds += val - dd->ipath_lastsword;
- spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
dd->ipath_lastsword = val;
}
val64 = dd->ipath_sword;
} else if (creg == dd->ipath_cregs->cr_wordrcvcnt) {
if (val != dd->ipath_lastrword) {
dd->ipath_rword += val - dd->ipath_lastrword;
- spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
- dd->ipath_traffic_wds += val - dd->ipath_lastrword;
- spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
dd->ipath_lastrword = val;
}
val64 = dd->ipath_rword;
@@ -247,6 +240,7 @@ void ipath_get_faststats(unsigned long opaque)
u32 val;
static unsigned cnt;
unsigned long flags;
+ u64 traffic_wds;
/*
* don't access the chip while running diags, or memory diags can
@@ -262,12 +256,13 @@ void ipath_get_faststats(unsigned long opaque)
* exceeding a threshold, so we need to check the word-counts
* even if they are 64-bit.
*/
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
+ traffic_wds = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt) +
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
- if (dd->ipath_traffic_wds >= IPATH_TRAFFIC_ACTIVE_THRESHOLD)
+ traffic_wds -= dd->ipath_traffic_wds;
+ dd->ipath_traffic_wds += traffic_wds;
+ if (traffic_wds >= IPATH_TRAFFIC_ACTIVE_THRESHOLD)
atomic_add(5, &dd->ipath_active_time); /* S/B #define */
- dd->ipath_traffic_wds = 0;
spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
if (dd->ipath_flags & IPATH_32BITCOUNTERS) {
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
index 16238cd3a03..e1ad7cfc21f 100644
--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
@@ -163,6 +163,42 @@ static ssize_t show_boardversion(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%s", dd->ipath_boardversion);
}
+static ssize_t show_lmc(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ipath_devdata *dd = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_lmc);
+}
+
+static ssize_t store_lmc(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct ipath_devdata *dd = dev_get_drvdata(dev);
+ u16 lmc = 0;
+ int ret;
+
+ ret = ipath_parse_ushort(buf, &lmc);
+ if (ret < 0)
+ goto invalid;
+
+ if (lmc > 7) {
+ ret = -EINVAL;
+ goto invalid;
+ }
+
+ ipath_set_lid(dd, dd->ipath_lid, lmc);
+
+ goto bail;
+invalid:
+ ipath_dev_err(dd, "attempt to set invalid LMC %u\n", lmc);
+bail:
+ return ret;
+}
+
static ssize_t show_lid(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -190,7 +226,7 @@ static ssize_t store_lid(struct device *dev,
goto invalid;
}
- ipath_set_lid(dd, lid, 0);
+ ipath_set_lid(dd, lid, dd->ipath_lmc);
goto bail;
invalid:
@@ -648,6 +684,7 @@ static struct attribute_group driver_attr_group = {
};
static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid);
+static DEVICE_ATTR(lmc, S_IWUSR | S_IRUGO, show_lmc, store_lmc);
static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid);
static DEVICE_ATTR(link_state, S_IWUSR, NULL, store_link_state);
static DEVICE_ATTR(mlid, S_IWUSR | S_IRUGO, show_mlid, store_mlid);
@@ -667,6 +704,7 @@ static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL);
static struct attribute *dev_attributes[] = {
&dev_attr_guid.attr,
+ &dev_attr_lmc.attr,
&dev_attr_lid.attr,
&dev_attr_link_state.attr,
&dev_attr_mlid.attr,
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
index 8380fbc50d2..2dd8de20d22 100644
--- a/drivers/infiniband/hw/ipath/ipath_uc.c
+++ b/drivers/infiniband/hw/ipath/ipath_uc.c
@@ -37,72 +37,40 @@
/* cut down ridiculously long IB macro names */
#define OP(x) IB_OPCODE_UC_##x
-static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe,
- struct ib_wc *wc)
-{
- if (++qp->s_last == qp->s_size)
- qp->s_last = 0;
- if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
- (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
- wc->wr_id = wqe->wr.wr_id;
- wc->status = IB_WC_SUCCESS;
- wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
- wc->vendor_err = 0;
- wc->byte_len = wqe->length;
- wc->qp = &qp->ibqp;
- wc->src_qp = qp->remote_qpn;
- wc->pkey_index = 0;
- wc->slid = qp->remote_ah_attr.dlid;
- wc->sl = qp->remote_ah_attr.sl;
- wc->dlid_path_bits = 0;
- wc->port_num = 0;
- ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 0);
- }
-}
-
/**
* ipath_make_uc_req - construct a request packet (SEND, RDMA write)
* @qp: a pointer to the QP
- * @ohdr: a pointer to the IB header being constructed
- * @pmtu: the path MTU
- * @bth0p: pointer to the BTH opcode word
- * @bth2p: pointer to the BTH PSN word
*
* Return 1 if constructed; otherwise, return 0.
- * Note the QP s_lock must be held and interrupts disabled.
*/
-int ipath_make_uc_req(struct ipath_qp *qp,
- struct ipath_other_headers *ohdr,
- u32 pmtu, u32 *bth0p, u32 *bth2p)
+int ipath_make_uc_req(struct ipath_qp *qp)
{
+ struct ipath_other_headers *ohdr;
struct ipath_swqe *wqe;
u32 hwords;
u32 bth0;
u32 len;
- struct ib_wc wc;
+ u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
+ int ret = 0;
if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK))
goto done;
+ ohdr = &qp->s_hdr.u.oth;
+ if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
+ ohdr = &qp->s_hdr.u.l.oth;
+
/* header size in 32-bit words LRH+BTH = (8+12)/4. */
hwords = 5;
bth0 = 1 << 22; /* Set M bit */
/* Get the next send request. */
- wqe = get_swqe_ptr(qp, qp->s_last);
+ wqe = get_swqe_ptr(qp, qp->s_cur);
+ qp->s_wqe = NULL;
switch (qp->s_state) {
default:
- /*
- * Signal the completion of the last send
- * (if there is one).
- */
- if (qp->s_last != qp->s_tail) {
- complete_last_send(qp, wqe, &wc);
- wqe = get_swqe_ptr(qp, qp->s_last);
- }
-
/* Check if send work queue is empty. */
- if (qp->s_tail == qp->s_head)
+ if (qp->s_cur == qp->s_head)
goto done;
/*
* Start a new request.
@@ -131,6 +99,9 @@ int ipath_make_uc_req(struct ipath_qp *qp,
}
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
bth0 |= 1 << 23;
+ qp->s_wqe = wqe;
+ if (++qp->s_cur >= qp->s_size)
+ qp->s_cur = 0;
break;
case IB_WR_RDMA_WRITE:
@@ -157,13 +128,14 @@ int ipath_make_uc_req(struct ipath_qp *qp,
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
bth0 |= 1 << 23;
}
+ qp->s_wqe = wqe;
+ if (++qp->s_cur >= qp->s_size)
+ qp->s_cur = 0;
break;
default:
goto done;
}
- if (++qp->s_tail >= qp->s_size)
- qp->s_tail = 0;
break;
case OP(SEND_FIRST):
@@ -185,6 +157,9 @@ int ipath_make_uc_req(struct ipath_qp *qp,
}
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
bth0 |= 1 << 23;
+ qp->s_wqe = wqe;
+ if (++qp->s_cur >= qp->s_size)
+ qp->s_cur = 0;
break;
case OP(RDMA_WRITE_FIRST):
@@ -207,18 +182,22 @@ int ipath_make_uc_req(struct ipath_qp *qp,
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
bth0 |= 1 << 23;
}
+ qp->s_wqe = wqe;
+ if (++qp->s_cur >= qp->s_size)
+ qp->s_cur = 0;
break;
}
qp->s_len -= len;
qp->s_hdrwords = hwords;
qp->s_cur_sge = &qp->s_sge;
qp->s_cur_size = len;
- *bth0p = bth0 | (qp->s_state << 24);
- *bth2p = qp->s_next_psn++ & IPATH_PSN_MASK;
- return 1;
+ ipath_make_ruc_header(to_idev(qp->ibqp.device),
+ qp, ohdr, bth0 | (qp->s_state << 24),
+ qp->s_next_psn++ & IPATH_PSN_MASK);
+ ret = 1;
done:
- return 0;
+ return ret;
}
/**
@@ -485,6 +464,16 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
rdma_last_imm:
+ if (header_in_data) {
+ wc.imm_data = *(__be32 *) data;
+ data += sizeof(__be32);
+ } else {
+ /* Immediate data comes after BTH */
+ wc.imm_data = ohdr->u.imm_data;
+ }
+ hdrsize += 4;
+ wc.wc_flags = IB_WC_WITH_IMM;
+
/* Get the number of bytes the message was padded by. */
pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
/* Check for invalid length. */
@@ -505,16 +494,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
dev->n_pkt_drops++;
goto done;
}
- if (header_in_data) {
- wc.imm_data = *(__be32 *) data;
- data += sizeof(__be32);
- } else {
- /* Immediate data comes after BTH */
- wc.imm_data = ohdr->u.imm_data;
- }
- hdrsize += 4;
- wc.wc_flags = IB_WC_WITH_IMM;
- wc.byte_len = 0;
+ wc.byte_len = qp->r_len;
goto last_imm;
case OP(RDMA_WRITE_LAST):
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index f9a3338a5fb..16a2a938b52 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -36,68 +36,17 @@
#include "ipath_verbs.h"
#include "ipath_kernel.h"
-static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
- u32 *lengthp, struct ipath_sge_state *ss)
-{
- int user = to_ipd(qp->ibqp.pd)->user;
- int i, j, ret;
- struct ib_wc wc;
-
- *lengthp = 0;
- for (i = j = 0; i < wqe->num_sge; i++) {
- if (wqe->sg_list[i].length == 0)
- continue;
- /* Check LKEY */
- if ((user && wqe->sg_list[i].lkey == 0) ||
- !ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge,
- &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE))
- goto bad_lkey;
- *lengthp += wqe->sg_list[i].length;
- j++;
- }
- ss->num_sge = j;
- ret = 1;
- goto bail;
-
-bad_lkey:
- wc.wr_id = wqe->wr_id;
- wc.status = IB_WC_LOC_PROT_ERR;
- wc.opcode = IB_WC_RECV;
- wc.vendor_err = 0;
- wc.byte_len = 0;
- wc.imm_data = 0;
- wc.qp = &qp->ibqp;
- wc.src_qp = 0;
- wc.wc_flags = 0;
- wc.pkey_index = 0;
- wc.slid = 0;
- wc.sl = 0;
- wc.dlid_path_bits = 0;
- wc.port_num = 0;
- /* Signal solicited completion event. */
- ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
- ret = 0;
-bail:
- return ret;
-}
-
/**
* ipath_ud_loopback - handle send on loopback QPs
- * @sqp: the QP
- * @ss: the SGE state
- * @length: the length of the data to send
- * @wr: the work request
- * @wc: the work completion entry
+ * @sqp: the sending QP
+ * @swqe: the send work request
*
- * This is called from ipath_post_ud_send() to forward a WQE addressed
+ * This is called from ipath_make_ud_req() to forward a WQE addressed
* to the same HCA.
* Note that the receive interrupt handler may be calling ipath_ud_rcv()
* while this is being called.
*/
-static void ipath_ud_loopback(struct ipath_qp *sqp,
- struct ipath_sge_state *ss,
- u32 length, struct ib_send_wr *wr,
- struct ib_wc *wc)
+static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe)
{
struct ipath_ibdev *dev = to_idev(sqp->ibqp.device);
struct ipath_qp *qp;
@@ -110,12 +59,18 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
struct ipath_rwq *wq;
struct ipath_rwqe *wqe;
void (*handler)(struct ib_event *, void *);
+ struct ib_wc wc;
u32 tail;
u32 rlen;
+ u32 length;
- qp = ipath_lookup_qpn(&dev->qp_table, wr->wr.ud.remote_qpn);
- if (!qp)
- return;
+ qp = ipath_lookup_qpn(&dev->qp_table, swqe->wr.wr.ud.remote_qpn);
+ if (!qp) {
+ dev->n_pkt_drops++;
+ goto send_comp;
+ }
+
+ rsge.sg_list = NULL;
/*
* Check that the qkey matches (except for QP0, see 9.6.1.4.1).
@@ -123,39 +78,34 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
* qkey from the QP context instead of the WR (see 10.2.5).
*/
if (unlikely(qp->ibqp.qp_num &&
- ((int) wr->wr.ud.remote_qkey < 0
- ? qp->qkey : wr->wr.ud.remote_qkey) != qp->qkey)) {
+ ((int) swqe->wr.wr.ud.remote_qkey < 0 ?
+ sqp->qkey : swqe->wr.wr.ud.remote_qkey) != qp->qkey)) {
/* XXX OK to lose a count once in a while. */
dev->qkey_violations++;
dev->n_pkt_drops++;
- goto done;
+ goto drop;
}
/*
* A GRH is expected to preceed the data even if not
* present on the wire.
*/
- wc->byte_len = length + sizeof(struct ib_grh);
+ length = swqe->length;
+ wc.byte_len = length + sizeof(struct ib_grh);
- if (wr->opcode == IB_WR_SEND_WITH_IMM) {
- wc->wc_flags = IB_WC_WITH_IMM;
- wc->imm_data = wr->imm_data;
+ if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
+ wc.wc_flags = IB_WC_WITH_IMM;
+ wc.imm_data = swqe->wr.imm_data;
} else {
- wc->wc_flags = 0;
- wc->imm_data = 0;
+ wc.wc_flags = 0;
+ wc.imm_data = 0;
}
- if (wr->num_sge > 1) {
- rsge.sg_list = kmalloc((wr->num_sge - 1) *
- sizeof(struct ipath_sge),
- GFP_ATOMIC);
- } else
- rsge.sg_list = NULL;
-
/*
- * Get the next work request entry to find where to put the data.
- * Note that it is safe to drop the lock after changing rq->tail
- * since ipath_post_receive() won't fill the empty slot.
+ * This would be a lot simpler if we could call ipath_get_rwqe()
+ * but that uses state that the receive interrupt handler uses
+ * so we would need to lock out receive interrupts while doing
+ * local loopback.
*/
if (qp->ibqp.srq) {
srq = to_isrq(qp->ibqp.srq);
@@ -167,32 +117,53 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
rq = &qp->r_rq;
}
+ if (rq->max_sge > 1) {
+ /*
+ * XXX We could use GFP_KERNEL if ipath_do_send()
+ * was always called from the tasklet instead of
+ * from ipath_post_send().
+ */
+ rsge.sg_list = kmalloc((rq->max_sge - 1) *
+ sizeof(struct ipath_sge),
+ GFP_ATOMIC);
+ if (!rsge.sg_list) {
+ dev->n_pkt_drops++;
+ goto drop;
+ }
+ }
+
+ /*
+ * Get the next work request entry to find where to put the data.
+ * Note that it is safe to drop the lock after changing rq->tail
+ * since ipath_post_receive() won't fill the empty slot.
+ */
spin_lock_irqsave(&rq->lock, flags);
wq = rq->wq;
tail = wq->tail;
- while (1) {
- if (unlikely(tail == wq->head)) {
- spin_unlock_irqrestore(&rq->lock, flags);
- dev->n_pkt_drops++;
- goto bail_sge;
- }
- /* Make sure entry is read after head index is read. */
- smp_rmb();
- wqe = get_rwqe_ptr(rq, tail);
- if (++tail >= rq->size)
- tail = 0;
- if (init_sge(qp, wqe, &rlen, &rsge))
- break;
- wq->tail = tail;
+ /* Validate tail before using it since it is user writable. */
+ if (tail >= rq->size)
+ tail = 0;
+ if (unlikely(tail == wq->head)) {
+ spin_unlock_irqrestore(&rq->lock, flags);
+ dev->n_pkt_drops++;
+ goto drop;
+ }
+ wqe = get_rwqe_ptr(rq, tail);
+ if (!ipath_init_sge(qp, wqe, &rlen, &rsge)) {
+ spin_unlock_irqrestore(&rq->lock, flags);
+ dev->n_pkt_drops++;
+ goto drop;
}
/* Silently drop packets which are too big. */
- if (wc->byte_len > rlen) {
+ if (wc.byte_len > rlen) {
spin_unlock_irqrestore(&rq->lock, flags);
dev->n_pkt_drops++;
- goto bail_sge;
+ goto drop;
}
+ if (++tail >= rq->size)
+ tail = 0;
wq->tail = tail;
- wc->wr_id = wqe->wr_id;
+ wc.wr_id = wqe->wr_id;
if (handler) {
u32 n;
@@ -221,13 +192,13 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
} else
spin_unlock_irqrestore(&rq->lock, flags);
- ah_attr = &to_iah(wr->wr.ud.ah)->attr;
+ ah_attr = &to_iah(swqe->wr.wr.ud.ah)->attr;
if (ah_attr->ah_flags & IB_AH_GRH) {
ipath_copy_sge(&rsge, &ah_attr->grh, sizeof(struct ib_grh));
- wc->wc_flags |= IB_WC_GRH;
+ wc.wc_flags |= IB_WC_GRH;
} else
ipath_skip_sge(&rsge, sizeof(struct ib_grh));
- sge = &ss->sge;
+ sge = swqe->sg_list;
while (length) {
u32 len = sge->length;
@@ -241,8 +212,8 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
sge->length -= len;
sge->sge_length -= len;
if (sge->sge_length == 0) {
- if (--ss->num_sge)
- *sge = *ss->sg_list++;
+ if (--swqe->wr.num_sge)
+ sge++;
} else if (sge->length == 0 && sge->mr != NULL) {
if (++sge->n >= IPATH_SEGSZ) {
if (++sge->m >= sge->mr->mapsz)
@@ -256,123 +227,60 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
}
length -= len;
}
- wc->status = IB_WC_SUCCESS;
- wc->opcode = IB_WC_RECV;
- wc->vendor_err = 0;
- wc->qp = &qp->ibqp;
- wc->src_qp = sqp->ibqp.qp_num;
+ wc.status = IB_WC_SUCCESS;
+ wc.opcode = IB_WC_RECV;
+ wc.vendor_err = 0;
+ wc.qp = &qp->ibqp;
+ wc.src_qp = sqp->ibqp.qp_num;
/* XXX do we know which pkey matched? Only needed for GSI. */
- wc->pkey_index = 0;
- wc->slid = dev->dd->ipath_lid |
+ wc.pkey_index = 0;
+ wc.slid = dev->dd->ipath_lid |
(ah_attr->src_path_bits &
- ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1));
- wc->sl = ah_attr->sl;
- wc->dlid_path_bits =
- ah_attr->dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+ ((1 << dev->dd->ipath_lmc) - 1));
+ wc.sl = ah_attr->sl;
+ wc.dlid_path_bits =
+ ah_attr->dlid & ((1 << dev->dd->ipath_lmc) - 1);
+ wc.port_num = 1;
/* Signal completion event if the solicited bit is set. */
- ipath_cq_enter(to_icq(qp->ibqp.recv_cq), wc,
- wr->send_flags & IB_SEND_SOLICITED);
-
-bail_sge:
+ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
+ swqe->wr.send_flags & IB_SEND_SOLICITED);
+drop:
kfree(rsge.sg_list);
-done:
if (atomic_dec_and_test(&qp->refcount))
wake_up(&qp->wait);
+send_comp:
+ ipath_send_complete(sqp, swqe, IB_WC_SUCCESS);
}
/**
- * ipath_post_ud_send - post a UD send on QP
+ * ipath_make_ud_req - construct a UD request packet
* @qp: the QP
- * @wr: the work request
*
- * Note that we actually send the data as it is posted instead of putting
- * the request into a ring buffer. If we wanted to use a ring buffer,
- * we would need to save a reference to the destination address in the SWQE.
+ * Return 1 if constructed; otherwise, return 0.
*/
-int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
+int ipath_make_ud_req(struct ipath_qp *qp)
{
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ipath_other_headers *ohdr;
struct ib_ah_attr *ah_attr;
- struct ipath_sge_state ss;
- struct ipath_sge *sg_list;
- struct ib_wc wc;
- u32 hwords;
+ struct ipath_swqe *wqe;
u32 nwords;
- u32 len;
u32 extra_bytes;
u32 bth0;
u16 lrh0;
u16 lid;
- int i;
- int ret;
+ int ret = 0;
- if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) {
- ret = 0;
+ if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)))
goto bail;
- }
- if (wr->wr.ud.ah->pd != qp->ibqp.pd) {
- ret = -EPERM;
+ if (qp->s_cur == qp->s_head)
goto bail;
- }
- /* IB spec says that num_sge == 0 is OK. */
- if (wr->num_sge > qp->s_max_sge) {
- ret = -EINVAL;
- goto bail;
- }
-
- if (wr->num_sge > 1) {
- sg_list = kmalloc((qp->s_max_sge - 1) * sizeof(*sg_list),
- GFP_ATOMIC);
- if (!sg_list) {
- ret = -ENOMEM;
- goto bail;
- }
- } else
- sg_list = NULL;
-
- /* Check the buffer to send. */
- ss.sg_list = sg_list;
- ss.sge.mr = NULL;
- ss.sge.vaddr = NULL;
- ss.sge.length = 0;
- ss.sge.sge_length = 0;
- ss.num_sge = 0;
- len = 0;
- for (i = 0; i < wr->num_sge; i++) {
- /* Check LKEY */
- if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) {
- ret = -EINVAL;
- goto bail;
- }
-
- if (wr->sg_list[i].length == 0)
- continue;
- if (!ipath_lkey_ok(qp, ss.num_sge ?
- sg_list + ss.num_sge - 1 : &ss.sge,
- &wr->sg_list[i], 0)) {
- ret = -EINVAL;
- goto bail;
- }
- len += wr->sg_list[i].length;
- ss.num_sge++;
- }
- /* Check for invalid packet size. */
- if (len > dev->dd->ipath_ibmtu) {
- ret = -EINVAL;
- goto bail;
- }
- extra_bytes = (4 - len) & 3;
- nwords = (len + extra_bytes) >> 2;
+ wqe = get_swqe_ptr(qp, qp->s_cur);
/* Construct the header. */
- ah_attr = &to_iah(wr->wr.ud.ah)->attr;
- if (ah_attr->dlid == 0) {
- ret = -EINVAL;
- goto bail;
- }
+ ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr;
if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE) {
if (ah_attr->dlid != IPATH_PERMISSIVE_LID)
dev->n_multicast_xmit++;
@@ -381,74 +289,63 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
} else {
dev->n_unicast_xmit++;
lid = ah_attr->dlid &
- ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+ ~((1 << dev->dd->ipath_lmc) - 1);
if (unlikely(lid == dev->dd->ipath_lid)) {
- /*
- * Pass in an uninitialized ib_wc to save stack
- * space.
- */
- ipath_ud_loopback(qp, &ss, len, wr, &wc);
+ ipath_ud_loopback(qp, wqe);
goto done;
}
}
+
+ extra_bytes = -wqe->length & 3;
+ nwords = (wqe->length + extra_bytes) >> 2;
+
+ /* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */
+ qp->s_hdrwords = 7;
+ if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
+ qp->s_hdrwords++;
+ qp->s_cur_size = wqe->length;
+ qp->s_cur_sge = &qp->s_sge;
+ qp->s_wqe = wqe;
+ qp->s_sge.sge = wqe->sg_list[0];
+ qp->s_sge.sg_list = wqe->sg_list + 1;
+ qp->s_sge.num_sge = wqe->wr.num_sge;
+
if (ah_attr->ah_flags & IB_AH_GRH) {
/* Header size in 32-bit words. */
- hwords = 17;
+ qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh,
+ &ah_attr->grh,
+ qp->s_hdrwords, nwords);
lrh0 = IPATH_LRH_GRH;
ohdr = &qp->s_hdr.u.l.oth;
- qp->s_hdr.u.l.grh.version_tclass_flow =
- cpu_to_be32((6 << 28) |
- (ah_attr->grh.traffic_class << 20) |
- ah_attr->grh.flow_label);
- qp->s_hdr.u.l.grh.paylen =
- cpu_to_be16(((wr->opcode ==
- IB_WR_SEND_WITH_IMM ? 6 : 5) +
- nwords + SIZE_OF_CRC) << 2);
- /* next_hdr is defined by C8-7 in ch. 8.4.1 */
- qp->s_hdr.u.l.grh.next_hdr = 0x1B;
- qp->s_hdr.u.l.grh.hop_limit = ah_attr->grh.hop_limit;
- /* The SGID is 32-bit aligned. */
- qp->s_hdr.u.l.grh.sgid.global.subnet_prefix =
- dev->gid_prefix;
- qp->s_hdr.u.l.grh.sgid.global.interface_id =
- dev->dd->ipath_guid;
- qp->s_hdr.u.l.grh.dgid = ah_attr->grh.dgid;
/*
* Don't worry about sending to locally attached multicast
* QPs. It is unspecified by the spec. what happens.
*/
} else {
/* Header size in 32-bit words. */
- hwords = 7;
lrh0 = IPATH_LRH_BTH;
ohdr = &qp->s_hdr.u.oth;
}
- if (wr->opcode == IB_WR_SEND_WITH_IMM) {
- ohdr->u.ud.imm_data = wr->imm_data;
- wc.imm_data = wr->imm_data;
- hwords += 1;
+ if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
+ ohdr->u.ud.imm_data = wqe->wr.imm_data;
bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24;
- } else if (wr->opcode == IB_WR_SEND) {
- wc.imm_data = 0;
+ } else
bth0 = IB_OPCODE_UD_SEND_ONLY << 24;
- } else {
- ret = -EINVAL;
- goto bail;
- }
lrh0 |= ah_attr->sl << 4;
if (qp->ibqp.qp_type == IB_QPT_SMI)
lrh0 |= 0xF000; /* Set VL (see ch. 13.5.3.1) */
qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */
- qp->s_hdr.lrh[2] = cpu_to_be16(hwords + nwords + SIZE_OF_CRC);
+ qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords +
+ SIZE_OF_CRC);
lid = dev->dd->ipath_lid;
if (lid) {
lid |= ah_attr->src_path_bits &
- ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+ ((1 << dev->dd->ipath_lmc) - 1);
qp->s_hdr.lrh[3] = cpu_to_be16(lid);
} else
qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE;
- if (wr->send_flags & IB_SEND_SOLICITED)
+ if (wqe->wr.send_flags & IB_SEND_SOLICITED)
bth0 |= 1 << 23;
bth0 |= extra_bytes << 20;
bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPATH_DEFAULT_P_KEY :
@@ -460,38 +357,20 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
ohdr->bth[1] = ah_attr->dlid >= IPATH_MULTICAST_LID_BASE &&
ah_attr->dlid != IPATH_PERMISSIVE_LID ?
__constant_cpu_to_be32(IPATH_MULTICAST_QPN) :
- cpu_to_be32(wr->wr.ud.remote_qpn);
- /* XXX Could lose a PSN count but not worth locking */
+ cpu_to_be32(wqe->wr.wr.ud.remote_qpn);
ohdr->bth[2] = cpu_to_be32(qp->s_next_psn++ & IPATH_PSN_MASK);
/*
* Qkeys with the high order bit set mean use the
* qkey from the QP context instead of the WR (see 10.2.5).
*/
- ohdr->u.ud.deth[0] = cpu_to_be32((int)wr->wr.ud.remote_qkey < 0 ?
- qp->qkey : wr->wr.ud.remote_qkey);
+ ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->wr.wr.ud.remote_qkey < 0 ?
+ qp->qkey : wqe->wr.wr.ud.remote_qkey);
ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num);
- if (ipath_verbs_send(dev->dd, hwords, (u32 *) &qp->s_hdr,
- len, &ss))
- dev->n_no_piobuf++;
done:
- /* Queue the completion status entry. */
- if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
- (wr->send_flags & IB_SEND_SIGNALED)) {
- wc.wr_id = wr->wr_id;
- wc.status = IB_WC_SUCCESS;
- wc.vendor_err = 0;
- wc.opcode = IB_WC_SEND;
- wc.byte_len = len;
- wc.qp = &qp->ibqp;
- wc.src_qp = 0;
- wc.wc_flags = 0;
- /* XXX initialize other fields? */
- ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0);
- }
- kfree(sg_list);
-
- ret = 0;
+ if (++qp->s_cur >= qp->s_size)
+ qp->s_cur = 0;
+ ret = 1;
bail:
return ret;
@@ -672,7 +551,8 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
* Save the LMC lower bits if the destination LID is a unicast LID.
*/
wc.dlid_path_bits = dlid >= IPATH_MULTICAST_LID_BASE ? 0 :
- dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+ dlid & ((1 << dev->dd->ipath_lmc) - 1);
+ wc.port_num = 1;
/* Signal completion event if the solicited bit is set. */
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
(ohdr->bth[0] &
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index 16aa61fd808..74f77e7c2c1 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -230,6 +230,121 @@ void ipath_skip_sge(struct ipath_sge_state *ss, u32 length)
}
}
+static void ipath_flush_wqe(struct ipath_qp *qp, struct ib_send_wr *wr)
+{
+ struct ib_wc wc;
+
+ memset(&wc, 0, sizeof(wc));
+ wc.wr_id = wr->wr_id;
+ wc.status = IB_WC_WR_FLUSH_ERR;
+ wc.opcode = ib_ipath_wc_opcode[wr->opcode];
+ wc.qp = &qp->ibqp;
+ ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1);
+}
+
+/**
+ * ipath_post_one_send - post one RC, UC, or UD send work request
+ * @qp: the QP to post on
+ * @wr: the work request to send
+ */
+static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
+{
+ struct ipath_swqe *wqe;
+ u32 next;
+ int i;
+ int j;
+ int acc;
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qp->s_lock, flags);
+
+ /* Check that state is OK to post send. */
+ if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK))) {
+ if (qp->state != IB_QPS_SQE && qp->state != IB_QPS_ERR)
+ goto bail_inval;
+ /* C10-96 says generate a flushed completion entry. */
+ ipath_flush_wqe(qp, wr);
+ ret = 0;
+ goto bail;
+ }
+
+ /* IB spec says that num_sge == 0 is OK. */
+ if (wr->num_sge > qp->s_max_sge)
+ goto bail_inval;
+
+ /*
+ * Don't allow RDMA reads or atomic operations on UC or
+ * undefined operations.
+ * Make sure buffer is large enough to hold the result for atomics.
+ */
+ if (qp->ibqp.qp_type == IB_QPT_UC) {
+ if ((unsigned) wr->opcode >= IB_WR_RDMA_READ)
+ goto bail_inval;
+ } else if (qp->ibqp.qp_type == IB_QPT_UD) {
+ /* Check UD opcode */
+ if (wr->opcode != IB_WR_SEND &&
+ wr->opcode != IB_WR_SEND_WITH_IMM)
+ goto bail_inval;
+ /* Check UD destination address PD */
+ if (qp->ibqp.pd != wr->wr.ud.ah->pd)
+ goto bail_inval;
+ } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD)
+ goto bail_inval;
+ else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP &&
+ (wr->num_sge == 0 ||
+ wr->sg_list[0].length < sizeof(u64) ||
+ wr->sg_list[0].addr & (sizeof(u64) - 1)))
+ goto bail_inval;
+ else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic)
+ goto bail_inval;
+
+ next = qp->s_head + 1;
+ if (next >= qp->s_size)
+ next = 0;
+ if (next == qp->s_last)
+ goto bail_inval;
+
+ wqe = get_swqe_ptr(qp, qp->s_head);
+ wqe->wr = *wr;
+ wqe->ssn = qp->s_ssn++;
+ wqe->length = 0;
+ if (wr->num_sge) {
+ acc = wr->opcode >= IB_WR_RDMA_READ ?
+ IB_ACCESS_LOCAL_WRITE : 0;
+ for (i = 0, j = 0; i < wr->num_sge; i++) {
+ u32 length = wr->sg_list[i].length;
+ int ok;
+
+ if (length == 0)
+ continue;
+ ok = ipath_lkey_ok(qp, &wqe->sg_list[j],
+ &wr->sg_list[i], acc);
+ if (!ok)
+ goto bail_inval;
+ wqe->length += length;
+ j++;
+ }
+ wqe->wr.num_sge = j;
+ }
+ if (qp->ibqp.qp_type == IB_QPT_UC ||
+ qp->ibqp.qp_type == IB_QPT_RC) {
+ if (wqe->length > 0x80000000U)
+ goto bail_inval;
+ } else if (wqe->length > to_idev(qp->ibqp.device)->dd->ipath_ibmtu)
+ goto bail_inval;
+ qp->s_head = next;
+
+ ret = 0;
+ goto bail;
+
+bail_inval:
+ ret = -EINVAL;
+bail:
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ return ret;
+}
+
/**
* ipath_post_send - post a send on a QP
* @ibqp: the QP to post the send on
@@ -244,35 +359,17 @@ static int ipath_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ipath_qp *qp = to_iqp(ibqp);
int err = 0;
- /* Check that state is OK to post send. */
- if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)) {
- *bad_wr = wr;
- err = -EINVAL;
- goto bail;
- }
-
for (; wr; wr = wr->next) {
- switch (qp->ibqp.qp_type) {
- case IB_QPT_UC:
- case IB_QPT_RC:
- err = ipath_post_ruc_send(qp, wr);
- break;
-
- case IB_QPT_SMI:
- case IB_QPT_GSI:
- case IB_QPT_UD:
- err = ipath_post_ud_send(qp, wr);
- break;
-
- default:
- err = -EINVAL;
- }
+ err = ipath_post_one_send(qp, wr);
if (err) {
*bad_wr = wr;
- break;
+ goto bail;
}
}
+ /* Try to do the send work in the caller's context. */
+ ipath_do_send((unsigned long) qp);
+
bail:
return err;
}
@@ -416,7 +513,7 @@ void ipath_ib_rcv(struct ipath_ibdev *dev, void *rhdr, void *data,
/* Check for a valid destination LID (see ch. 7.11.1). */
lid = be16_to_cpu(hdr->lrh[1]);
if (lid < IPATH_MULTICAST_LID_BASE) {
- lid &= ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+ lid &= ~((1 << dev->dd->ipath_lmc) - 1);
if (unlikely(lid != dev->dd->ipath_lid)) {
dev->rcv_errors++;
goto bail;
@@ -631,7 +728,7 @@ static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
#endif
static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
- u32 length)
+ u32 length, unsigned flush_wc)
{
u32 extra = 0;
u32 data = 0;
@@ -641,11 +738,11 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
u32 len = ss->sge.length;
u32 off;
- BUG_ON(len == 0);
if (len > length)
len = length;
if (len > ss->sge.sge_length)
len = ss->sge.sge_length;
+ BUG_ON(len == 0);
/* If the source address is not aligned, try to align it. */
off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1);
if (off) {
@@ -757,36 +854,25 @@ static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
}
/* Update address before sending packet. */
update_sge(ss, length);
- /* must flush early everything before trigger word */
- ipath_flush_wc();
- __raw_writel(last, piobuf);
- /* be sure trigger word is written */
- ipath_flush_wc();
+ if (flush_wc) {
+ /* must flush early everything before trigger word */
+ ipath_flush_wc();
+ __raw_writel(last, piobuf);
+ /* be sure trigger word is written */
+ ipath_flush_wc();
+ } else
+ __raw_writel(last, piobuf);
}
-/**
- * ipath_verbs_send - send a packet
- * @dd: the infinipath device
- * @hdrwords: the number of words in the header
- * @hdr: the packet header
- * @len: the length of the packet in bytes
- * @ss: the SGE to send
- */
-int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
- u32 *hdr, u32 len, struct ipath_sge_state *ss)
+static int ipath_verbs_send_pio(struct ipath_qp *qp, u32 *hdr, u32 hdrwords,
+ struct ipath_sge_state *ss, u32 len,
+ u32 plen, u32 dwords)
{
+ struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
u32 __iomem *piobuf;
- u32 plen;
+ unsigned flush_wc;
int ret;
- /* +1 is for the qword padding of pbc */
- plen = hdrwords + ((len + 3) >> 2) + 1;
- if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) {
- ret = -EINVAL;
- goto bail;
- }
-
- /* Get a PIO buffer to use. */
piobuf = ipath_getpiobuf(dd, NULL);
if (unlikely(piobuf == NULL)) {
ret = -EBUSY;
@@ -799,51 +885,90 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
* or WC buffer can be written out of order.
*/
writeq(plen, piobuf);
- ipath_flush_wc();
piobuf += 2;
+
+ flush_wc = dd->ipath_flags & IPATH_PIO_FLUSH_WC;
if (len == 0) {
/*
* If there is just the header portion, must flush before
* writing last word of header for correctness, and after
* the last header word (trigger word).
*/
- __iowrite32_copy(piobuf, hdr, hdrwords - 1);
- ipath_flush_wc();
- __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1);
- ipath_flush_wc();
- ret = 0;
- goto bail;
+ if (flush_wc) {
+ ipath_flush_wc();
+ __iowrite32_copy(piobuf, hdr, hdrwords - 1);
+ ipath_flush_wc();
+ __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1);
+ ipath_flush_wc();
+ } else
+ __iowrite32_copy(piobuf, hdr, hdrwords);
+ goto done;
}
+ if (flush_wc)
+ ipath_flush_wc();
__iowrite32_copy(piobuf, hdr, hdrwords);
piobuf += hdrwords;
/* The common case is aligned and contained in one segment. */
if (likely(ss->num_sge == 1 && len <= ss->sge.length &&
!((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) {
- u32 w;
u32 *addr = (u32 *) ss->sge.vaddr;
/* Update address before sending packet. */
update_sge(ss, len);
- /* Need to round up for the last dword in the packet. */
- w = (len + 3) >> 2;
- __iowrite32_copy(piobuf, addr, w - 1);
- /* must flush early everything before trigger word */
- ipath_flush_wc();
- __raw_writel(addr[w - 1], piobuf + w - 1);
- /* be sure trigger word is written */
- ipath_flush_wc();
- ret = 0;
- goto bail;
+ if (flush_wc) {
+ __iowrite32_copy(piobuf, addr, dwords - 1);
+ /* must flush early everything before trigger word */
+ ipath_flush_wc();
+ __raw_writel(addr[dwords - 1], piobuf + dwords - 1);
+ /* be sure trigger word is written */
+ ipath_flush_wc();
+ } else
+ __iowrite32_copy(piobuf, addr, dwords);
+ goto done;
}
- copy_io(piobuf, ss, len);
+ copy_io(piobuf, ss, len, flush_wc);
+done:
+ if (qp->s_wqe)
+ ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
ret = 0;
-
bail:
return ret;
}
+/**
+ * ipath_verbs_send - send a packet
+ * @qp: the QP to send on
+ * @hdr: the packet header
+ * @hdrwords: the number of words in the header
+ * @ss: the SGE to send
+ * @len: the length of the packet in bytes
+ */
+int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
+ u32 hdrwords, struct ipath_sge_state *ss, u32 len)
+{
+ struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
+ u32 plen;
+ int ret;
+ u32 dwords = (len + 3) >> 2;
+
+ /* +1 is for the qword padding of pbc */
+ plen = hdrwords + dwords + 1;
+
+ /* Drop non-VL15 packets if we are not in the active state */
+ if (!(dd->ipath_flags & IPATH_LINKACTIVE) &&
+ qp->ibqp.qp_type != IB_QPT_SMI) {
+ if (qp->s_wqe)
+ ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
+ ret = 0;
+ } else
+ ret = ipath_verbs_send_pio(qp, (u32 *) hdr, hdrwords,
+ ss, len, plen, dwords);
+
+ return ret;
+}
+
int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
u64 *rwords, u64 *spkts, u64 *rpkts,
u64 *xmit_wait)
@@ -852,7 +977,6 @@ int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
if (!(dd->ipath_flags & IPATH_INITTED)) {
/* no hardware, freeze, etc. */
- ipath_dbg("unit %u not usable\n", dd->ipath_unit);
ret = -EINVAL;
goto bail;
}
@@ -878,48 +1002,44 @@ bail:
int ipath_get_counters(struct ipath_devdata *dd,
struct ipath_verbs_counters *cntrs)
{
+ struct ipath_cregs const *crp = dd->ipath_cregs;
int ret;
if (!(dd->ipath_flags & IPATH_INITTED)) {
/* no hardware, freeze, etc. */
- ipath_dbg("unit %u not usable\n", dd->ipath_unit);
ret = -EINVAL;
goto bail;
}
cntrs->symbol_error_counter =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
+ ipath_snap_cntr(dd, crp->cr_ibsymbolerrcnt);
cntrs->link_error_recovery_counter =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
+ ipath_snap_cntr(dd, crp->cr_iblinkerrrecovcnt);
/*
* The link downed counter counts when the other side downs the
* connection. We add in the number of times we downed the link
* due to local link integrity errors to compensate.
*/
cntrs->link_downed_counter =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkdowncnt);
+ ipath_snap_cntr(dd, crp->cr_iblinkdowncnt);
cntrs->port_rcv_errors =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_rxdroppktcnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvovflcnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_portovflcnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_err_rlencnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_invalidrlencnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt) +
+ ipath_snap_cntr(dd, crp->cr_rxdroppktcnt) +
+ ipath_snap_cntr(dd, crp->cr_rcvovflcnt) +
+ ipath_snap_cntr(dd, crp->cr_portovflcnt) +
+ ipath_snap_cntr(dd, crp->cr_err_rlencnt) +
+ ipath_snap_cntr(dd, crp->cr_invalidrlencnt) +
+ ipath_snap_cntr(dd, crp->cr_errlinkcnt) +
+ ipath_snap_cntr(dd, crp->cr_erricrccnt) +
+ ipath_snap_cntr(dd, crp->cr_errvcrccnt) +
+ ipath_snap_cntr(dd, crp->cr_errlpcrccnt) +
+ ipath_snap_cntr(dd, crp->cr_badformatcnt) +
dd->ipath_rxfc_unsupvl_errs;
cntrs->port_rcv_remphys_errors =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt);
- cntrs->port_xmit_discards =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_unsupvlcnt);
- cntrs->port_xmit_data =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
- cntrs->port_rcv_data =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
- cntrs->port_xmit_packets =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
- cntrs->port_rcv_packets =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
+ ipath_snap_cntr(dd, crp->cr_rcvebpcnt);
+ cntrs->port_xmit_discards = ipath_snap_cntr(dd, crp->cr_unsupvlcnt);
+ cntrs->port_xmit_data = ipath_snap_cntr(dd, crp->cr_wordsendcnt);
+ cntrs->port_rcv_data = ipath_snap_cntr(dd, crp->cr_wordrcvcnt);
+ cntrs->port_xmit_packets = ipath_snap_cntr(dd, crp->cr_pktsendcnt);
+ cntrs->port_rcv_packets = ipath_snap_cntr(dd, crp->cr_pktrcvcnt);
cntrs->local_link_integrity_errors =
(dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
dd->ipath_lli_errs : dd->ipath_lli_errors;
@@ -1033,25 +1153,26 @@ static int ipath_query_port(struct ib_device *ibdev,
u8 port, struct ib_port_attr *props)
{
struct ipath_ibdev *dev = to_idev(ibdev);
+ struct ipath_devdata *dd = dev->dd;
enum ib_mtu mtu;
- u16 lid = dev->dd->ipath_lid;
+ u16 lid = dd->ipath_lid;
u64 ibcstat;
memset(props, 0, sizeof(*props));
props->lid = lid ? lid : __constant_be16_to_cpu(IB_LID_PERMISSIVE);
- props->lmc = dev->mkeyprot_resv_lmc & 7;
+ props->lmc = dd->ipath_lmc;
props->sm_lid = dev->sm_lid;
props->sm_sl = dev->sm_sl;
- ibcstat = dev->dd->ipath_lastibcstat;
+ ibcstat = dd->ipath_lastibcstat;
props->state = ((ibcstat >> 4) & 0x3) + 1;
/* See phys_state_show() */
props->phys_state = ipath_cvt_physportstate[
- dev->dd->ipath_lastibcstat & 0xf];
+ dd->ipath_lastibcstat & 0xf];
props->port_cap_flags = dev->port_cap_flags;
props->gid_tbl_len = 1;
props->max_msg_sz = 0x80000000;
- props->pkey_tbl_len = ipath_get_npkeys(dev->dd);
- props->bad_pkey_cntr = ipath_get_cr_errpkey(dev->dd) -
+ props->pkey_tbl_len = ipath_get_npkeys(dd);
+ props->bad_pkey_cntr = ipath_get_cr_errpkey(dd) -
dev->z_pkey_violations;
props->qkey_viol_cntr = dev->qkey_violations;
props->active_width = IB_WIDTH_4X;
@@ -1061,12 +1182,12 @@ static int ipath_query_port(struct ib_device *ibdev,
props->init_type_reply = 0;
/*
- * Note: the chips support a maximum MTU of 4096, but the driver
+ * Note: the chip supports a maximum MTU of 4096, but the driver
* hasn't implemented this feature yet, so set the maximum value
* to 2048.
*/
props->max_mtu = IB_MTU_2048;
- switch (dev->dd->ipath_ibmtu) {
+ switch (dd->ipath_ibmtu) {
case 4096:
mtu = IB_MTU_4096;
break;
@@ -1415,9 +1536,7 @@ static int disable_timer(struct ipath_devdata *dd)
{
/* Disable GPIO bit 2 interrupt */
if (dd->ipath_flags & IPATH_GPIO_INTR) {
- u64 val;
/* Disable GPIO bit 2 interrupt */
- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask);
dd->ipath_gpio_mask &= ~((u64) (1 << IPATH_GPIO_PORT0_BIT));
ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
dd->ipath_gpio_mask);
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index 1a24c6a4a81..6ccb54f104a 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -42,6 +42,8 @@
#include <rdma/ib_pack.h>
#include <rdma/ib_user_verbs.h>
+#include "ipath_kernel.h"
+
#define IPATH_MAX_RDMA_ATOMIC 4
#define QPN_MAX (1 << 24)
@@ -59,6 +61,7 @@
*/
#define IB_CQ_NONE (IB_CQ_NEXT_COMP + 1)
+/* AETH NAK opcode values */
#define IB_RNR_NAK 0x20
#define IB_NAK_PSN_ERROR 0x60
#define IB_NAK_INVALID_REQUEST 0x61
@@ -66,6 +69,7 @@
#define IB_NAK_REMOTE_OPERATIONAL_ERROR 0x63
#define IB_NAK_INVALID_RD_REQUEST 0x64
+/* Flags for checking QP state (see ib_ipath_state_ops[]) */
#define IPATH_POST_SEND_OK 0x01
#define IPATH_POST_RECV_OK 0x02
#define IPATH_PROCESS_RECV_OK 0x04
@@ -187,7 +191,11 @@ struct ipath_mmap_info {
struct ipath_cq_wc {
u32 head; /* index of next entry to fill */
u32 tail; /* index of next ib_poll_cq() entry */
- struct ib_uverbs_wc queue[1]; /* this is actually size ibcq.cqe + 1 */
+ union {
+ /* these are actually size ibcq.cqe + 1 */
+ struct ib_uverbs_wc uqueue[0];
+ struct ib_wc kqueue[0];
+ };
};
/*
@@ -239,7 +247,7 @@ struct ipath_mregion {
*/
struct ipath_sge {
struct ipath_mregion *mr;
- void *vaddr; /* current pointer into the segment */
+ void *vaddr; /* kernel virtual address of segment */
u32 sge_length; /* length of the SGE */
u32 length; /* remaining length of the segment */
u16 m; /* current index: mr->map[m] */
@@ -407,6 +415,7 @@ struct ipath_qp {
u32 s_ssn; /* SSN of tail entry */
u32 s_lsn; /* limit sequence number (credit) */
struct ipath_swqe *s_wq; /* send work queue */
+ struct ipath_swqe *s_wqe;
struct ipath_rq r_rq; /* receive work queue */
struct ipath_sge r_sg_list[0]; /* verified SGEs */
};
@@ -492,7 +501,7 @@ struct ipath_ibdev {
int ib_unit; /* This is the device number */
u16 sm_lid; /* in host order */
u8 sm_sl;
- u8 mkeyprot_resv_lmc;
+ u8 mkeyprot;
/* non-zero when timer is set */
unsigned long mkey_lease_timeout;
@@ -667,7 +676,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
int ipath_destroy_qp(struct ib_qp *ibqp);
-void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err);
+int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err);
int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask, struct ib_udata *udata);
@@ -683,8 +692,8 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc);
void ipath_get_credit(struct ipath_qp *qp, u32 aeth);
-int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
- u32 *hdr, u32 len, struct ipath_sge_state *ss);
+int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
+ u32 hdrwords, struct ipath_sge_state *ss, u32 len);
void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
@@ -692,8 +701,6 @@ void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length);
void ipath_skip_sge(struct ipath_sge_state *ss, u32 length);
-int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr);
-
void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
int has_grh, void *data, u32 tlen, struct ipath_qp *qp);
@@ -733,6 +740,8 @@ int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr);
int ipath_destroy_srq(struct ib_srq *ibsrq);
+void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
+
int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector,
@@ -782,18 +791,28 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
void ipath_insert_rnr_queue(struct ipath_qp *qp);
+int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
+ u32 *lengthp, struct ipath_sge_state *ss);
+
int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only);
u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr,
struct ib_global_route *grh, u32 hwords, u32 nwords);
-void ipath_do_ruc_send(unsigned long data);
+void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp,
+ struct ipath_other_headers *ohdr,
+ u32 bth0, u32 bth2);
+
+void ipath_do_send(unsigned long data);
+
+void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe,
+ enum ib_wc_status status);
+
+int ipath_make_rc_req(struct ipath_qp *qp);
-int ipath_make_rc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
- u32 pmtu, u32 *bth0p, u32 *bth2p);
+int ipath_make_uc_req(struct ipath_qp *qp);
-int ipath_make_uc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
- u32 pmtu, u32 *bth0p, u32 *bth2p);
+int ipath_make_ud_req(struct ipath_qp *qp);
int ipath_register_ib_device(struct ipath_devdata *);
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index dde8fe9af47..d8287d9db41 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -476,9 +476,48 @@ out:
return err;
}
+static ssize_t show_hca(struct class_device *cdev, char *buf)
+{
+ struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev);
+ return sprintf(buf, "MT%d\n", dev->dev->pdev->device);
+}
+
+static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
+{
+ struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev);
+ return sprintf(buf, "%d.%d.%d\n", (int) (dev->dev->caps.fw_ver >> 32),
+ (int) (dev->dev->caps.fw_ver >> 16) & 0xffff,
+ (int) dev->dev->caps.fw_ver & 0xffff);
+}
+
+static ssize_t show_rev(struct class_device *cdev, char *buf)
+{
+ struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev);
+ return sprintf(buf, "%x\n", dev->dev->rev_id);
+}
+
+static ssize_t show_board(struct class_device *cdev, char *buf)
+{
+ struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev);
+ return sprintf(buf, "%.*s\n", MLX4_BOARD_ID_LEN, dev->dev->board_id);
+}
+
+static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
+static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
+static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
+static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+
+static struct class_device_attribute *mlx4_class_attributes[] = {
+ &class_device_attr_hw_rev,
+ &class_device_attr_fw_ver,
+ &class_device_attr_hca_type,
+ &class_device_attr_board_id
+};
+
static void *mlx4_ib_add(struct mlx4_dev *dev)
{
struct mlx4_ib_dev *ibdev;
+ int i;
ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev);
if (!ibdev) {
@@ -568,6 +607,11 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev->ib_dev.detach_mcast = mlx4_ib_mcg_detach;
ibdev->ib_dev.process_mad = mlx4_ib_process_mad;
+ ibdev->ib_dev.alloc_fmr = mlx4_ib_fmr_alloc;
+ ibdev->ib_dev.map_phys_fmr = mlx4_ib_map_phys_fmr;
+ ibdev->ib_dev.unmap_fmr = mlx4_ib_unmap_fmr;
+ ibdev->ib_dev.dealloc_fmr = mlx4_ib_fmr_dealloc;
+
if (init_node_data(ibdev))
goto err_map;
@@ -580,6 +624,12 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
if (mlx4_ib_mad_init(ibdev))
goto err_reg;
+ for (i = 0; i < ARRAY_SIZE(mlx4_class_attributes); ++i) {
+ if (class_device_create_file(&ibdev->ib_dev.class_dev,
+ mlx4_class_attributes[i]))
+ goto err_reg;
+ }
+
return ibdev;
err_reg:
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index 705ff2fa237..28697653a37 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -93,6 +93,11 @@ struct mlx4_ib_mr {
struct ib_umem *umem;
};
+struct mlx4_ib_fmr {
+ struct ib_fmr ibfmr;
+ struct mlx4_fmr mfmr;
+};
+
struct mlx4_ib_wq {
u64 *wrid;
spinlock_t lock;
@@ -199,6 +204,10 @@ static inline struct mlx4_ib_mr *to_mmr(struct ib_mr *ibmr)
return container_of(ibmr, struct mlx4_ib_mr, ibmr);
}
+static inline struct mlx4_ib_fmr *to_mfmr(struct ib_fmr *ibfmr)
+{
+ return container_of(ibfmr, struct mlx4_ib_fmr, ibfmr);
+}
static inline struct mlx4_ib_qp *to_mqp(struct ib_qp *ibqp)
{
return container_of(ibqp, struct mlx4_ib_qp, ibqp);
@@ -284,6 +293,13 @@ int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
int mlx4_ib_mad_init(struct mlx4_ib_dev *dev);
void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev);
+struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int mr_access_flags,
+ struct ib_fmr_attr *fmr_attr);
+int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, int npages,
+ u64 iova);
+int mlx4_ib_unmap_fmr(struct list_head *fmr_list);
+int mlx4_ib_fmr_dealloc(struct ib_fmr *fmr);
+
static inline int mlx4_ib_ah_grh_present(struct mlx4_ib_ah *ah)
{
return !!(ah->av.g_slid & 0x80);
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c
index 85ae906f1d1..7dc91a3e712 100644
--- a/drivers/infiniband/hw/mlx4/mr.c
+++ b/drivers/infiniband/hw/mlx4/mr.c
@@ -96,11 +96,10 @@ int mlx4_ib_umem_write_mtt(struct mlx4_ib_dev *dev, struct mlx4_mtt *mtt,
pages[i++] = sg_dma_address(&chunk->page_list[j]) +
umem->page_size * k;
/*
- * Be friendly to WRITE_MTT firmware
- * command, and pass it chunks of
- * appropriate size.
+ * Be friendly to mlx4_write_mtt() and
+ * pass it chunks of appropriate size.
*/
- if (i == PAGE_SIZE / sizeof (u64) - 2) {
+ if (i == PAGE_SIZE / sizeof (u64)) {
err = mlx4_write_mtt(dev->dev, mtt, n,
i, pages);
if (err)
@@ -182,3 +181,96 @@ int mlx4_ib_dereg_mr(struct ib_mr *ibmr)
return 0;
}
+
+struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int acc,
+ struct ib_fmr_attr *fmr_attr)
+{
+ struct mlx4_ib_dev *dev = to_mdev(pd->device);
+ struct mlx4_ib_fmr *fmr;
+ int err = -ENOMEM;
+
+ fmr = kmalloc(sizeof *fmr, GFP_KERNEL);
+ if (!fmr)
+ return ERR_PTR(-ENOMEM);
+
+ err = mlx4_fmr_alloc(dev->dev, to_mpd(pd)->pdn, convert_access(acc),
+ fmr_attr->max_pages, fmr_attr->max_maps,
+ fmr_attr->page_shift, &fmr->mfmr);
+ if (err)
+ goto err_free;
+
+ err = mlx4_mr_enable(to_mdev(pd->device)->dev, &fmr->mfmr.mr);
+ if (err)
+ goto err_mr;
+
+ fmr->ibfmr.rkey = fmr->ibfmr.lkey = fmr->mfmr.mr.key;
+
+ return &fmr->ibfmr;
+
+err_mr:
+ mlx4_mr_free(to_mdev(pd->device)->dev, &fmr->mfmr.mr);
+
+err_free:
+ kfree(fmr);
+
+ return ERR_PTR(err);
+}
+
+int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+ int npages, u64 iova)
+{
+ struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr);
+ struct mlx4_ib_dev *dev = to_mdev(ifmr->ibfmr.device);
+
+ return mlx4_map_phys_fmr(dev->dev, &ifmr->mfmr, page_list, npages, iova,
+ &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey);
+}
+
+int mlx4_ib_unmap_fmr(struct list_head *fmr_list)
+{
+ struct ib_fmr *ibfmr;
+ int err;
+ struct mlx4_dev *mdev = NULL;
+
+ list_for_each_entry(ibfmr, fmr_list, list) {
+ if (mdev && to_mdev(ibfmr->device)->dev != mdev)
+ return -EINVAL;
+ mdev = to_mdev(ibfmr->device)->dev;
+ }
+
+ if (!mdev)
+ return 0;
+
+ list_for_each_entry(ibfmr, fmr_list, list) {
+ struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr);
+
+ mlx4_fmr_unmap(mdev, &ifmr->mfmr, &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey);
+ }
+
+ /*
+ * Make sure all MPT status updates are visible before issuing
+ * SYNC_TPT firmware command.
+ */
+ wmb();
+
+ err = mlx4_SYNC_TPT(mdev);
+ if (err)
+ printk(KERN_WARNING "mlx4_ib: SYNC_TPT error %d when "
+ "unmapping FMRs\n", err);
+
+ return 0;
+}
+
+int mlx4_ib_fmr_dealloc(struct ib_fmr *ibfmr)
+{
+ struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr);
+ struct mlx4_ib_dev *dev = to_mdev(ibfmr->device);
+ int err;
+
+ err = mlx4_fmr_free(dev->dev, &ifmr->mfmr);
+
+ if (!err)
+ kfree(ifmr);
+
+ return err;
+}
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 85c51bdc36f..8cba9c532e6 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -63,6 +63,10 @@ struct mlx4_ib_sqp {
u8 header_buf[MLX4_IB_UD_HEADER_SIZE];
};
+enum {
+ MLX4_IB_MIN_SQ_STRIDE = 6
+};
+
static const __be32 mlx4_ib_opcode[] = {
[IB_WR_SEND] = __constant_cpu_to_be32(MLX4_OPCODE_SEND),
[IB_WR_SEND_WITH_IMM] = __constant_cpu_to_be32(MLX4_OPCODE_SEND_IMM),
@@ -285,9 +289,17 @@ static int set_kernel_sq_size(struct mlx4_ib_dev *dev, struct ib_qp_cap *cap,
return 0;
}
-static int set_user_sq_size(struct mlx4_ib_qp *qp,
+static int set_user_sq_size(struct mlx4_ib_dev *dev,
+ struct mlx4_ib_qp *qp,
struct mlx4_ib_create_qp *ucmd)
{
+ /* Sanity check SQ size before proceeding */
+ if ((1 << ucmd->log_sq_bb_count) > dev->dev->caps.max_wqes ||
+ ucmd->log_sq_stride >
+ ilog2(roundup_pow_of_two(dev->dev->caps.max_sq_desc_sz)) ||
+ ucmd->log_sq_stride < MLX4_IB_MIN_SQ_STRIDE)
+ return -EINVAL;
+
qp->sq.wqe_cnt = 1 << ucmd->log_sq_bb_count;
qp->sq.wqe_shift = ucmd->log_sq_stride;
@@ -330,7 +342,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
qp->sq_no_prefetch = ucmd.sq_no_prefetch;
- err = set_user_sq_size(qp, &ucmd);
+ err = set_user_sq_size(dev, qp, &ucmd);
if (err)
goto err;
@@ -1249,6 +1261,13 @@ static void set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg)
dseg->byte_count = cpu_to_be32(sg->length);
}
+static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg)
+{
+ dseg->byte_count = cpu_to_be32(sg->length);
+ dseg->lkey = cpu_to_be32(sg->lkey);
+ dseg->addr = cpu_to_be64(sg->addr);
+}
+
int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr)
{
@@ -1263,7 +1282,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
int size;
int i;
- spin_lock_irqsave(&qp->rq.lock, flags);
+ spin_lock_irqsave(&qp->sq.lock, flags);
ind = qp->sq.head;
@@ -1429,7 +1448,7 @@ out:
(qp->sq.wqe_cnt - 1));
}
- spin_unlock_irqrestore(&qp->rq.lock, flags);
+ spin_unlock_irqrestore(&qp->sq.lock, flags);
return err;
}
@@ -1464,11 +1483,8 @@ int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
scat = get_recv_wqe(qp, ind);
- for (i = 0; i < wr->num_sge; ++i) {
- scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length);
- scat[i].lkey = cpu_to_be32(wr->sg_list[i].lkey);
- scat[i].addr = cpu_to_be64(wr->sg_list[i].addr);
- }
+ for (i = 0; i < wr->num_sge; ++i)
+ __set_data_seg(scat + i, wr->sg_list + i);
if (i < qp->rq.max_gs) {
scat[i].byte_count = 0;
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index 408748fb528..e7e9a3d0dac 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -251,7 +251,7 @@ int mlx4_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
if (ret)
return ret;
- srq_attr->srq_limit = be16_to_cpu(limit_watermark);
+ srq_attr->srq_limit = limit_watermark;
srq_attr->max_wr = srq->msrq.max - 1;
srq_attr->max_sge = srq->msrq.max_gs;
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index acc95892713..6966f943f44 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -290,6 +290,12 @@ static int mthca_cmd_post(struct mthca_dev *dev,
err = mthca_cmd_post_hcr(dev, in_param, out_param, in_modifier,
op_modifier, op, token, event);
+ /*
+ * Make sure that our HCR writes don't get mixed in with
+ * writes from another CPU starting a FW command.
+ */
+ mmiowb();
+
mutex_unlock(&dev->cmd.hcr_mutex);
return err;
}
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index be6e1e03bda..6bd9f139334 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -204,16 +204,11 @@ static void dump_cqe(struct mthca_dev *dev, void *cqe_ptr)
static inline void update_cons_index(struct mthca_dev *dev, struct mthca_cq *cq,
int incr)
{
- __be32 doorbell[2];
-
if (mthca_is_memfree(dev)) {
*cq->set_ci_db = cpu_to_be32(cq->cons_index);
wmb();
} else {
- doorbell[0] = cpu_to_be32(MTHCA_TAVOR_CQ_DB_INC_CI | cq->cqn);
- doorbell[1] = cpu_to_be32(incr - 1);
-
- mthca_write64(doorbell,
+ mthca_write64(MTHCA_TAVOR_CQ_DB_INC_CI | cq->cqn, incr - 1,
dev->kar + MTHCA_CQ_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
/*
@@ -731,17 +726,12 @@ repoll:
int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags)
{
- __be32 doorbell[2];
+ u32 dbhi = ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
+ MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL :
+ MTHCA_TAVOR_CQ_DB_REQ_NOT) |
+ to_mcq(cq)->cqn;
- doorbell[0] = cpu_to_be32(((flags & IB_CQ_SOLICITED_MASK) ==
- IB_CQ_SOLICITED ?
- MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL :
- MTHCA_TAVOR_CQ_DB_REQ_NOT) |
- to_mcq(cq)->cqn);
- doorbell[1] = (__force __be32) 0xffffffff;
-
- mthca_write64(doorbell,
- to_mdev(cq->device)->kar + MTHCA_CQ_DOORBELL,
+ mthca_write64(dbhi, 0xffffffff, to_mdev(cq->device)->kar + MTHCA_CQ_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&to_mdev(cq->device)->doorbell_lock));
return 0;
@@ -750,19 +740,16 @@ int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags)
int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
{
struct mthca_cq *cq = to_mcq(ibcq);
- __be32 doorbell[2];
- u32 sn;
- __be32 ci;
-
- sn = cq->arm_sn & 3;
- ci = cpu_to_be32(cq->cons_index);
+ __be32 db_rec[2];
+ u32 dbhi;
+ u32 sn = cq->arm_sn & 3;
- doorbell[0] = ci;
- doorbell[1] = cpu_to_be32((cq->cqn << 8) | (2 << 5) | (sn << 3) |
- ((flags & IB_CQ_SOLICITED_MASK) ==
- IB_CQ_SOLICITED ? 1 : 2));
+ db_rec[0] = cpu_to_be32(cq->cons_index);
+ db_rec[1] = cpu_to_be32((cq->cqn << 8) | (2 << 5) | (sn << 3) |
+ ((flags & IB_CQ_SOLICITED_MASK) ==
+ IB_CQ_SOLICITED ? 1 : 2));
- mthca_write_db_rec(doorbell, cq->arm_db);
+ mthca_write_db_rec(db_rec, cq->arm_db);
/*
* Make sure that the doorbell record in host memory is
@@ -770,14 +757,12 @@ int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
*/
wmb();
- doorbell[0] = cpu_to_be32((sn << 28) |
- ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
- MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL :
- MTHCA_ARBEL_CQ_DB_REQ_NOT) |
- cq->cqn);
- doorbell[1] = ci;
+ dbhi = (sn << 28) |
+ ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
+ MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL :
+ MTHCA_ARBEL_CQ_DB_REQ_NOT) | cq->cqn;
- mthca_write64(doorbell,
+ mthca_write64(dbhi, cq->cons_index,
to_mdev(ibcq->device)->kar + MTHCA_CQ_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->doorbell_lock));
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index 9bae3cc6060..15aa32eb78b 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -83,7 +83,7 @@ enum {
MTHCA_QP_CONTEXT_SIZE = 0x200,
MTHCA_RDB_ENTRY_SIZE = 0x20,
MTHCA_AV_SIZE = 0x20,
- MTHCA_MGM_ENTRY_SIZE = 0x40,
+ MTHCA_MGM_ENTRY_SIZE = 0x100,
/* Arbel FW gives us these, but we need them for Tavor */
MTHCA_MPT_ENTRY_SIZE = 0x40,
diff --git a/drivers/infiniband/hw/mthca/mthca_doorbell.h b/drivers/infiniband/hw/mthca/mthca_doorbell.h
index dd9a44d170c..b374dc395be 100644
--- a/drivers/infiniband/hw/mthca/mthca_doorbell.h
+++ b/drivers/infiniband/hw/mthca/mthca_doorbell.h
@@ -58,10 +58,10 @@ static inline void mthca_write64_raw(__be64 val, void __iomem *dest)
__raw_writeq((__force u64) val, dest);
}
-static inline void mthca_write64(__be32 val[2], void __iomem *dest,
+static inline void mthca_write64(u32 hi, u32 lo, void __iomem *dest,
spinlock_t *doorbell_lock)
{
- __raw_writeq(*(u64 *) val, dest);
+ __raw_writeq((__force u64) cpu_to_be64((u64) hi << 32 | lo), dest);
}
static inline void mthca_write_db_rec(__be32 val[2], __be32 *db)
@@ -87,14 +87,17 @@ static inline void mthca_write64_raw(__be64 val, void __iomem *dest)
__raw_writel(((__force u32 *) &val)[1], dest + 4);
}
-static inline void mthca_write64(__be32 val[2], void __iomem *dest,
+static inline void mthca_write64(u32 hi, u32 lo, void __iomem *dest,
spinlock_t *doorbell_lock)
{
unsigned long flags;
+ hi = (__force u32) cpu_to_be32(hi);
+ lo = (__force u32) cpu_to_be32(lo);
+
spin_lock_irqsave(doorbell_lock, flags);
- __raw_writel((__force u32) val[0], dest);
- __raw_writel((__force u32) val[1], dest + 4);
+ __raw_writel(hi, dest);
+ __raw_writel(lo, dest + 4);
spin_unlock_irqrestore(doorbell_lock, flags);
}
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index 8592b26dc4e..b29de51b7f3 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -173,11 +173,6 @@ static inline u64 async_mask(struct mthca_dev *dev)
static inline void tavor_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
{
- __be32 doorbell[2];
-
- doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_SET_CI | eq->eqn);
- doorbell[1] = cpu_to_be32(ci & (eq->nent - 1));
-
/*
* This barrier makes sure that all updates to ownership bits
* done by set_eqe_hw() hit memory before the consumer index
@@ -187,7 +182,7 @@ static inline void tavor_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u
* having set_eqe_hw() overwrite the owner field.
*/
wmb();
- mthca_write64(doorbell,
+ mthca_write64(MTHCA_EQ_DB_SET_CI | eq->eqn, ci & (eq->nent - 1),
dev->kar + MTHCA_EQ_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
}
@@ -212,12 +207,7 @@ static inline void set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
static inline void tavor_eq_req_not(struct mthca_dev *dev, int eqn)
{
- __be32 doorbell[2];
-
- doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_REQ_NOT | eqn);
- doorbell[1] = 0;
-
- mthca_write64(doorbell,
+ mthca_write64(MTHCA_EQ_DB_REQ_NOT | eqn, 0,
dev->kar + MTHCA_EQ_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
}
@@ -230,12 +220,7 @@ static inline void arbel_eq_req_not(struct mthca_dev *dev, u32 eqn_mask)
static inline void disarm_cq(struct mthca_dev *dev, int eqn, int cqn)
{
if (!mthca_is_memfree(dev)) {
- __be32 doorbell[2];
-
- doorbell[0] = cpu_to_be32(MTHCA_EQ_DB_DISARM_CQ | eqn);
- doorbell[1] = cpu_to_be32(cqn);
-
- mthca_write64(doorbell,
+ mthca_write64(MTHCA_EQ_DB_DISARM_CQ | eqn, cqn,
dev->kar + MTHCA_EQ_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
}
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 76fed7545c5..60de6f93869 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -61,7 +61,7 @@ MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0");
#ifdef CONFIG_PCI_MSI
-static int msi_x = 0;
+static int msi_x = 1;
module_param(msi_x, int, 0444);
MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
@@ -137,40 +137,23 @@ static const char mthca_version[] __devinitdata =
static int mthca_tune_pci(struct mthca_dev *mdev)
{
- int cap;
- u16 val;
-
if (!tune_pci)
return 0;
/* First try to max out Read Byte Count */
- cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX);
- if (cap) {
- if (pci_read_config_word(mdev->pdev, cap + PCI_X_CMD, &val)) {
- mthca_err(mdev, "Couldn't read PCI-X command register, "
- "aborting.\n");
- return -ENODEV;
- }
- val = (val & ~PCI_X_CMD_MAX_READ) | (3 << 2);
- if (pci_write_config_word(mdev->pdev, cap + PCI_X_CMD, val)) {
- mthca_err(mdev, "Couldn't write PCI-X command register, "
- "aborting.\n");
+ if (pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX)) {
+ if (pcix_set_mmrbc(mdev->pdev, pcix_get_max_mmrbc(mdev->pdev))) {
+ mthca_err(mdev, "Couldn't set PCI-X max read count, "
+ "aborting.\n");
return -ENODEV;
}
} else if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE))
mthca_info(mdev, "No PCI-X capability, not setting RBC.\n");
- cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP);
- if (cap) {
- if (pci_read_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, &val)) {
- mthca_err(mdev, "Couldn't read PCI Express device control "
- "register, aborting.\n");
- return -ENODEV;
- }
- val = (val & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12);
- if (pci_write_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, val)) {
- mthca_err(mdev, "Couldn't write PCI Express device control "
- "register, aborting.\n");
+ if (pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP)) {
+ if (pcie_set_readrq(mdev->pdev, 4096)) {
+ mthca_err(mdev, "Couldn't write PCI Express read request, "
+ "aborting.\n");
return -ENODEV;
}
} else if (mdev->mthca_flags & MTHCA_FLAG_PCIE)
@@ -833,14 +816,19 @@ static int mthca_setup_hca(struct mthca_dev *dev)
err = mthca_NOP(dev, &status);
if (err || status) {
- mthca_err(dev, "NOP command failed to generate interrupt (IRQ %d), aborting.\n",
- dev->mthca_flags & MTHCA_FLAG_MSI_X ?
- dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector :
- dev->pdev->irq);
- if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))
- mthca_err(dev, "Try again with MSI/MSI-X disabled.\n");
- else
+ if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) {
+ mthca_warn(dev, "NOP command failed to generate interrupt "
+ "(IRQ %d).\n",
+ dev->mthca_flags & MTHCA_FLAG_MSI_X ?
+ dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector :
+ dev->pdev->irq);
+ mthca_warn(dev, "Trying again with MSI/MSI-X disabled.\n");
+ } else {
+ mthca_err(dev, "NOP command failed to generate interrupt "
+ "(IRQ %d), aborting.\n",
+ dev->pdev->irq);
mthca_err(dev, "BIOS or ACPI interrupt routing problem?\n");
+ }
goto err_cmd_poll;
}
@@ -1115,24 +1103,6 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
goto err_free_dev;
}
- if (msi_x && !mthca_enable_msi_x(mdev))
- mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
- else if (msi) {
- static int warned;
-
- if (!warned) {
- printk(KERN_WARNING PFX "WARNING: MSI support will be "
- "removed from the ib_mthca driver in January 2008.\n");
- printk(KERN_WARNING " If you are using MSI and cannot "
- "switch to MSI-X, please tell "
- "<general@lists.openfabrics.org>.\n");
- ++warned;
- }
-
- if (!pci_enable_msi(pdev))
- mdev->mthca_flags |= MTHCA_FLAG_MSI;
- }
-
if (mthca_cmd_init(mdev)) {
mthca_err(mdev, "Failed to init command interface, aborting.\n");
goto err_free_dev;
@@ -1156,7 +1126,35 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n");
}
+ if (msi_x && !mthca_enable_msi_x(mdev))
+ mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
+ else if (msi) {
+ static int warned;
+
+ if (!warned) {
+ printk(KERN_WARNING PFX "WARNING: MSI support will be "
+ "removed from the ib_mthca driver in January 2008.\n");
+ printk(KERN_WARNING " If you are using MSI and cannot "
+ "switch to MSI-X, please tell "
+ "<general@lists.openfabrics.org>.\n");
+ ++warned;
+ }
+
+ if (!pci_enable_msi(pdev))
+ mdev->mthca_flags |= MTHCA_FLAG_MSI;
+ }
+
err = mthca_setup_hca(mdev);
+ if (err == -EBUSY && (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))) {
+ if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
+ pci_disable_msix(pdev);
+ if (mdev->mthca_flags & MTHCA_FLAG_MSI)
+ pci_disable_msi(pdev);
+ mdev->mthca_flags &= ~(MTHCA_FLAG_MSI_X | MTHCA_FLAG_MSI);
+
+ err = mthca_setup_hca(mdev);
+ }
+
if (err)
goto err_close;
@@ -1192,17 +1190,17 @@ err_cleanup:
mthca_cleanup_uar_table(mdev);
err_close:
+ if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
+ pci_disable_msix(pdev);
+ if (mdev->mthca_flags & MTHCA_FLAG_MSI)
+ pci_disable_msi(pdev);
+
mthca_close_hca(mdev);
err_cmd:
mthca_cmd_cleanup(mdev);
err_free_dev:
- if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
- pci_disable_msix(pdev);
- if (mdev->mthca_flags & MTHCA_FLAG_MSI)
- pci_disable_msi(pdev);
-
ib_dealloc_device(&mdev->ib_dev);
err_free_res:
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index e61f3e62698..1f4d27d7c16 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -71,7 +71,7 @@ static void mthca_free_icm_pages(struct mthca_dev *dev, struct mthca_icm_chunk *
PCI_DMA_BIDIRECTIONAL);
for (i = 0; i < chunk->npages; ++i)
- __free_pages(chunk->mem[i].page,
+ __free_pages(sg_page(&chunk->mem[i]),
get_order(chunk->mem[i].length));
}
@@ -81,7 +81,7 @@ static void mthca_free_icm_coherent(struct mthca_dev *dev, struct mthca_icm_chun
for (i = 0; i < chunk->npages; ++i) {
dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length,
- lowmem_page_address(chunk->mem[i].page),
+ lowmem_page_address(sg_page(&chunk->mem[i])),
sg_dma_address(&chunk->mem[i]));
}
}
@@ -107,12 +107,13 @@ void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm, int coherent)
static int mthca_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask)
{
- mem->page = alloc_pages(gfp_mask, order);
- if (!mem->page)
+ struct page *page;
+
+ page = alloc_pages(gfp_mask, order);
+ if (!page)
return -ENOMEM;
- mem->length = PAGE_SIZE << order;
- mem->offset = 0;
+ sg_set_page(mem, page, PAGE_SIZE << order, 0);
return 0;
}
@@ -157,6 +158,7 @@ struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
if (!chunk)
goto fail;
+ sg_init_table(chunk->mem, MTHCA_ICM_CHUNK_LEN);
chunk->npages = 0;
chunk->nsg = 0;
list_add_tail(&chunk->list, &icm->chunk_list);
@@ -304,7 +306,7 @@ void *mthca_table_find(struct mthca_icm_table *table, int obj, dma_addr_t *dma_h
* so if we found the page, dma_handle has already
* been assigned to. */
if (chunk->mem[i].length > offset) {
- page = chunk->mem[i].page;
+ page = sg_page(&chunk->mem[i]);
goto out;
}
offset -= chunk->mem[i].length;
@@ -445,6 +447,7 @@ static u64 mthca_uarc_virt(struct mthca_dev *dev, struct mthca_uar *uar, int pag
int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
struct mthca_user_db_table *db_tab, int index, u64 uaddr)
{
+ struct page *pages[1];
int ret = 0;
u8 status;
int i;
@@ -472,16 +475,16 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
}
ret = get_user_pages(current, current->mm, uaddr & PAGE_MASK, 1, 1, 0,
- &db_tab->page[i].mem.page, NULL);
+ pages, NULL);
if (ret < 0)
goto out;
- db_tab->page[i].mem.length = MTHCA_ICM_PAGE_SIZE;
- db_tab->page[i].mem.offset = uaddr & ~PAGE_MASK;
+ sg_set_page(&db_tab->page[i].mem, pages[0], MTHCA_ICM_PAGE_SIZE,
+ uaddr & ~PAGE_MASK);
ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
if (ret < 0) {
- put_page(db_tab->page[i].mem.page);
+ put_page(pages[0]);
goto out;
}
@@ -491,7 +494,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
ret = -EINVAL;
if (ret) {
pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
- put_page(db_tab->page[i].mem.page);
+ put_page(sg_page(&db_tab->page[i].mem));
goto out;
}
@@ -557,7 +560,7 @@ void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
if (db_tab->page[i].uvirt) {
mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1, &status);
pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
- put_page(db_tab->page[i].mem.page);
+ put_page(sg_page(&db_tab->page[i].mem));
}
}
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index df01b2026a6..0e5461c6573 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -1799,15 +1799,11 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
out:
if (likely(nreq)) {
- __be32 doorbell[2];
-
- doorbell[0] = cpu_to_be32(((qp->sq.next_ind << qp->sq.wqe_shift) +
- qp->send_wqe_offset) | f0 | op0);
- doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0);
-
wmb();
- mthca_write64(doorbell,
+ mthca_write64(((qp->sq.next_ind << qp->sq.wqe_shift) +
+ qp->send_wqe_offset) | f0 | op0,
+ (qp->qpn << 8) | size0,
dev->kar + MTHCA_SEND_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
/*
@@ -1829,7 +1825,6 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
{
struct mthca_dev *dev = to_mdev(ibqp->device);
struct mthca_qp *qp = to_mqp(ibqp);
- __be32 doorbell[2];
unsigned long flags;
int err = 0;
int nreq;
@@ -1907,13 +1902,10 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) {
nreq = 0;
- doorbell[0] = cpu_to_be32((qp->rq.next_ind << qp->rq.wqe_shift) | size0);
- doorbell[1] = cpu_to_be32(qp->qpn << 8);
-
wmb();
- mthca_write64(doorbell,
- dev->kar + MTHCA_RECEIVE_DOORBELL,
+ mthca_write64((qp->rq.next_ind << qp->rq.wqe_shift) | size0,
+ qp->qpn << 8, dev->kar + MTHCA_RECEIVE_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
qp->rq.next_ind = ind;
@@ -1923,13 +1915,10 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
out:
if (likely(nreq)) {
- doorbell[0] = cpu_to_be32((qp->rq.next_ind << qp->rq.wqe_shift) | size0);
- doorbell[1] = cpu_to_be32((qp->qpn << 8) | nreq);
-
wmb();
- mthca_write64(doorbell,
- dev->kar + MTHCA_RECEIVE_DOORBELL,
+ mthca_write64((qp->rq.next_ind << qp->rq.wqe_shift) | size0,
+ qp->qpn << 8 | nreq, dev->kar + MTHCA_RECEIVE_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
}
@@ -1951,7 +1940,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
{
struct mthca_dev *dev = to_mdev(ibqp->device);
struct mthca_qp *qp = to_mqp(ibqp);
- __be32 doorbell[2];
+ u32 dbhi;
void *wqe;
void *prev_wqe;
unsigned long flags;
@@ -1981,10 +1970,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
if (unlikely(nreq == MTHCA_ARBEL_MAX_WQES_PER_SEND_DB)) {
nreq = 0;
- doorbell[0] = cpu_to_be32((MTHCA_ARBEL_MAX_WQES_PER_SEND_DB << 24) |
- ((qp->sq.head & 0xffff) << 8) |
- f0 | op0);
- doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0);
+ dbhi = (MTHCA_ARBEL_MAX_WQES_PER_SEND_DB << 24) |
+ ((qp->sq.head & 0xffff) << 8) | f0 | op0;
qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB;
@@ -2000,7 +1987,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
* write MMIO send doorbell.
*/
wmb();
- mthca_write64(doorbell,
+
+ mthca_write64(dbhi, (qp->qpn << 8) | size0,
dev->kar + MTHCA_SEND_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
}
@@ -2154,10 +2142,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
out:
if (likely(nreq)) {
- doorbell[0] = cpu_to_be32((nreq << 24) |
- ((qp->sq.head & 0xffff) << 8) |
- f0 | op0);
- doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0);
+ dbhi = (nreq << 24) | ((qp->sq.head & 0xffff) << 8) | f0 | op0;
qp->sq.head += nreq;
@@ -2173,8 +2158,8 @@ out:
* write MMIO send doorbell.
*/
wmb();
- mthca_write64(doorbell,
- dev->kar + MTHCA_SEND_DOORBELL,
+
+ mthca_write64(dbhi, (qp->qpn << 8) | size0, dev->kar + MTHCA_SEND_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
}
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index 88d219e730a..553d681f681 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -491,7 +491,6 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
{
struct mthca_dev *dev = to_mdev(ibsrq->device);
struct mthca_srq *srq = to_msrq(ibsrq);
- __be32 doorbell[2];
unsigned long flags;
int err = 0;
int first_ind;
@@ -509,7 +508,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
for (nreq = 0; wr; wr = wr->next) {
ind = srq->first_free;
- if (ind < 0) {
+ if (unlikely(ind < 0)) {
mthca_err(dev, "SRQ %06x full\n", srq->srqn);
err = -ENOMEM;
*bad_wr = wr;
@@ -519,7 +518,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
wqe = get_wqe(srq, ind);
next_ind = *wqe_to_link(wqe);
- if (next_ind < 0) {
+ if (unlikely(next_ind < 0)) {
mthca_err(dev, "SRQ %06x full\n", srq->srqn);
err = -ENOMEM;
*bad_wr = wr;
@@ -563,16 +562,13 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
if (unlikely(nreq == MTHCA_TAVOR_MAX_WQES_PER_RECV_DB)) {
nreq = 0;
- doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift);
- doorbell[1] = cpu_to_be32(srq->srqn << 8);
-
/*
* Make sure that descriptors are written
* before doorbell is rung.
*/
wmb();
- mthca_write64(doorbell,
+ mthca_write64(first_ind << srq->wqe_shift, srq->srqn << 8,
dev->kar + MTHCA_RECEIVE_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
@@ -581,16 +577,13 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
}
if (likely(nreq)) {
- doorbell[0] = cpu_to_be32(first_ind << srq->wqe_shift);
- doorbell[1] = cpu_to_be32((srq->srqn << 8) | nreq);
-
/*
* Make sure that descriptors are written before
* doorbell is rung.
*/
wmb();
- mthca_write64(doorbell,
+ mthca_write64(first_ind << srq->wqe_shift, (srq->srqn << 8) | nreq,
dev->kar + MTHCA_RECEIVE_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
}
@@ -623,7 +616,7 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
for (nreq = 0; wr; ++nreq, wr = wr->next) {
ind = srq->first_free;
- if (ind < 0) {
+ if (unlikely(ind < 0)) {
mthca_err(dev, "SRQ %06x full\n", srq->srqn);
err = -ENOMEM;
*bad_wr = wr;
@@ -633,7 +626,7 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
wqe = get_wqe(srq, ind);
next_ind = *wqe_to_link(wqe);
- if (next_ind < 0) {
+ if (unlikely(next_ind < 0)) {
mthca_err(dev, "SRQ %06x full\n", srq->srqn);
err = -ENOMEM;
*bad_wr = wr;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 285c143115c..eb7edab0e83 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -84,8 +84,8 @@ enum {
IPOIB_MCAST_RUN = 6,
IPOIB_STOP_REAPER = 7,
IPOIB_MCAST_STARTED = 8,
- IPOIB_FLAG_NETIF_STOPPED = 9,
- IPOIB_FLAG_ADMIN_CM = 10,
+ IPOIB_FLAG_ADMIN_CM = 9,
+ IPOIB_FLAG_UMCAST = 10,
IPOIB_MAX_BACKOFF_SECONDS = 16,
@@ -97,9 +97,9 @@ enum {
#define IPOIB_OP_RECV (1ul << 31)
#ifdef CONFIG_INFINIBAND_IPOIB_CM
-#define IPOIB_CM_OP_SRQ (1ul << 30)
+#define IPOIB_OP_CM (1ul << 30)
#else
-#define IPOIB_CM_OP_SRQ (0)
+#define IPOIB_OP_CM (0)
#endif
/* structs */
@@ -113,7 +113,27 @@ struct ipoib_pseudoheader {
u8 hwaddr[INFINIBAND_ALEN];
};
-struct ipoib_mcast;
+/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */
+struct ipoib_mcast {
+ struct ib_sa_mcmember_rec mcmember;
+ struct ib_sa_multicast *mc;
+ struct ipoib_ah *ah;
+
+ struct rb_node rb_node;
+ struct list_head list;
+
+ unsigned long created;
+ unsigned long backoff;
+
+ unsigned long flags;
+ unsigned char logcount;
+
+ struct list_head neigh_list;
+
+ struct sk_buff_head pkt_queue;
+
+ struct net_device *dev;
+};
struct ipoib_rx_buf {
struct sk_buff *skb;
@@ -176,7 +196,6 @@ struct ipoib_cm_rx {
struct ipoib_cm_tx {
struct ib_cm_id *id;
- struct ib_cq *cq;
struct ib_qp *qp;
struct list_head list;
struct net_device *dev;
@@ -228,6 +247,8 @@ struct ipoib_dev_priv {
struct net_device *dev;
+ struct napi_struct napi;
+
unsigned long flags;
struct mutex mcast_mutex;
@@ -271,6 +292,7 @@ struct ipoib_dev_priv {
unsigned tx_tail;
struct ib_sge tx_sge;
struct ib_send_wr tx_wr;
+ unsigned tx_outstanding;
struct ib_wc ibwc[IPOIB_NUM_WC];
@@ -278,8 +300,6 @@ struct ipoib_dev_priv {
struct ib_event_handler event_handler;
- struct net_device_stats stats;
-
struct net_device *parent;
struct list_head child_intfs;
struct list_head list;
@@ -328,6 +348,7 @@ struct ipoib_neigh {
struct sk_buff_head queue;
struct neighbour *neighbour;
+ struct net_device *dev;
struct list_head list;
};
@@ -344,14 +365,15 @@ static inline struct ipoib_neigh **to_ipoib_neigh(struct neighbour *neigh)
INFINIBAND_ALEN, sizeof(void *));
}
-struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh);
+struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh,
+ struct net_device *dev);
void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh);
extern struct workqueue_struct *ipoib_workqueue;
/* functions */
-int ipoib_poll(struct net_device *dev, int *budget);
+int ipoib_poll(struct napi_struct *napi, int budget);
void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr);
struct ipoib_ah *ipoib_create_ah(struct net_device *dev,
@@ -364,6 +386,7 @@ static inline void ipoib_put_ah(struct ipoib_ah *ah)
int ipoib_open(struct net_device *dev);
int ipoib_add_pkey_attr(struct net_device *dev);
+int ipoib_add_umcast_attr(struct net_device *dev);
void ipoib_send(struct net_device *dev, struct sk_buff *skb,
struct ipoib_ah *address, u32 qpn);
@@ -480,6 +503,7 @@ void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx);
void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb,
unsigned int mtu);
void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc);
+void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc);
#else
struct ipoib_cm_tx;
@@ -568,6 +592,9 @@ static inline void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *w
{
}
+static inline void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
+{
+}
#endif
#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 08b4676a382..059cf92b60a 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -60,7 +60,7 @@ static struct ib_qp_attr ipoib_cm_err_attr = {
.qp_state = IB_QPS_ERR
};
-#define IPOIB_CM_RX_DRAIN_WRID 0x7fffffff
+#define IPOIB_CM_RX_DRAIN_WRID 0xffffffff
static struct ib_send_wr ipoib_cm_rx_drain_wr = {
.wr_id = IPOIB_CM_RX_DRAIN_WRID,
@@ -87,7 +87,7 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id)
struct ib_recv_wr *bad_wr;
int i, ret;
- priv->cm.rx_wr.wr_id = id | IPOIB_CM_OP_SRQ;
+ priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV;
for (i = 0; i < IPOIB_CM_RX_SG; ++i)
priv->cm.rx_sge[i].addr = priv->cm.srq_ring[id].mapping[i];
@@ -401,7 +401,7 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
- unsigned int wr_id = wc->wr_id & ~IPOIB_CM_OP_SRQ;
+ unsigned int wr_id = wc->wr_id & ~(IPOIB_OP_CM | IPOIB_OP_RECV);
struct sk_buff *skb, *newskb;
struct ipoib_cm_rx *p;
unsigned long flags;
@@ -412,7 +412,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
wr_id, wc->status);
if (unlikely(wr_id >= ipoib_recvq_size)) {
- if (wr_id == (IPOIB_CM_RX_DRAIN_WRID & ~IPOIB_CM_OP_SRQ)) {
+ if (wr_id == (IPOIB_CM_RX_DRAIN_WRID & ~(IPOIB_OP_CM | IPOIB_OP_RECV))) {
spin_lock_irqsave(&priv->lock, flags);
list_splice_init(&priv->cm.rx_drain_list, &priv->cm.rx_reap_list);
ipoib_cm_start_rx_drain(priv);
@@ -430,11 +430,11 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
ipoib_dbg(priv, "cm recv error "
"(status=%d, wrid=%d vend_err %x)\n",
wc->status, wr_id, wc->vendor_err);
- ++priv->stats.rx_dropped;
+ ++dev->stats.rx_dropped;
goto repost;
}
- if (!likely(wr_id & IPOIB_CM_RX_UPDATE_MASK)) {
+ if (unlikely(!(wr_id & IPOIB_CM_RX_UPDATE_MASK))) {
p = wc->qp->qp_context;
if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
spin_lock_irqsave(&priv->lock, flags);
@@ -457,7 +457,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
* this packet and reuse the old buffer.
*/
ipoib_dbg(priv, "failed to allocate receive buffer %d\n", wr_id);
- ++priv->stats.rx_dropped;
+ ++dev->stats.rx_dropped;
goto repost;
}
@@ -474,8 +474,8 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
skb_pull(skb, IPOIB_ENCAP_LEN);
dev->last_rx = jiffies;
- ++priv->stats.rx_packets;
- priv->stats.rx_bytes += skb->len;
+ ++dev->stats.rx_packets;
+ dev->stats.rx_bytes += skb->len;
skb->dev = dev;
/* XXX get correct PACKET_ type here */
@@ -498,7 +498,7 @@ static inline int post_send(struct ipoib_dev_priv *priv,
priv->tx_sge.addr = addr;
priv->tx_sge.length = len;
- priv->tx_wr.wr_id = wr_id;
+ priv->tx_wr.wr_id = wr_id | IPOIB_OP_CM;
return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr);
}
@@ -512,8 +512,8 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
if (unlikely(skb->len > tx->mtu)) {
ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
skb->len, tx->mtu);
- ++priv->stats.tx_dropped;
- ++priv->stats.tx_errors;
+ ++dev->stats.tx_dropped;
+ ++dev->stats.tx_errors;
ipoib_cm_skb_too_long(dev, skb, tx->mtu - IPOIB_ENCAP_LEN);
return;
}
@@ -532,7 +532,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
tx_req->skb = skb;
addr = ib_dma_map_single(priv->ca, skb->data, skb->len, DMA_TO_DEVICE);
if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
- ++priv->stats.tx_errors;
+ ++dev->stats.tx_errors;
dev_kfree_skb_any(skb);
return;
}
@@ -542,27 +542,26 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1),
addr, skb->len))) {
ipoib_warn(priv, "post_send failed\n");
- ++priv->stats.tx_errors;
+ ++dev->stats.tx_errors;
ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
} else {
dev->trans_start = jiffies;
++tx->tx_head;
- if (tx->tx_head - tx->tx_tail == ipoib_sendq_size) {
+ if (++priv->tx_outstanding == ipoib_sendq_size) {
ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n",
tx->qp->qp_num);
netif_stop_queue(dev);
- set_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags);
}
}
}
-static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx,
- struct ib_wc *wc)
+void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
- unsigned int wr_id = wc->wr_id;
+ struct ipoib_cm_tx *tx = wc->qp->qp_context;
+ unsigned int wr_id = wc->wr_id & ~IPOIB_OP_CM;
struct ipoib_tx_buf *tx_req;
unsigned long flags;
@@ -580,18 +579,17 @@ static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx
ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len, DMA_TO_DEVICE);
/* FIXME: is this right? Shouldn't we only increment on success? */
- ++priv->stats.tx_packets;
- priv->stats.tx_bytes += tx_req->skb->len;
+ ++dev->stats.tx_packets;
+ dev->stats.tx_bytes += tx_req->skb->len;
dev_kfree_skb_any(tx_req->skb);
spin_lock_irqsave(&priv->tx_lock, flags);
++tx->tx_tail;
- if (unlikely(test_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags)) &&
- tx->tx_head - tx->tx_tail <= ipoib_sendq_size >> 1) {
- clear_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags);
+ if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
+ netif_queue_stopped(dev) &&
+ test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
netif_wake_queue(dev);
- }
if (wc->status != IB_WC_SUCCESS &&
wc->status != IB_WC_WR_FLUSH_ERR) {
@@ -614,11 +612,6 @@ static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx
tx->neigh = NULL;
}
- /* queue would be re-started anyway when TX is destroyed,
- * but it makes sense to do it ASAP here. */
- if (test_and_clear_bit(IPOIB_FLAG_NETIF_STOPPED, &tx->flags))
- netif_wake_queue(dev);
-
if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
list_move(&tx->list, &priv->cm.reap_list);
queue_work(ipoib_workqueue, &priv->cm.reap_task);
@@ -632,19 +625,6 @@ static void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ipoib_cm_tx *tx
spin_unlock_irqrestore(&priv->tx_lock, flags);
}
-static void ipoib_cm_tx_completion(struct ib_cq *cq, void *tx_ptr)
-{
- struct ipoib_cm_tx *tx = tx_ptr;
- int n, i;
-
- ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
- do {
- n = ib_poll_cq(cq, IPOIB_NUM_WC, tx->ibwc);
- for (i = 0; i < n; ++i)
- ipoib_cm_handle_tx_wc(tx->dev, tx, tx->ibwc + i);
- } while (n == IPOIB_NUM_WC);
-}
-
int ipoib_cm_dev_open(struct net_device *dev)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -807,17 +787,20 @@ static int ipoib_cm_rep_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even
return 0;
}
-static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ib_cq *cq)
+static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_cm_tx *tx)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
- struct ib_qp_init_attr attr = {};
- attr.recv_cq = priv->cq;
- attr.srq = priv->cm.srq;
- attr.cap.max_send_wr = ipoib_sendq_size;
- attr.cap.max_send_sge = 1;
- attr.sq_sig_type = IB_SIGNAL_ALL_WR;
- attr.qp_type = IB_QPT_RC;
- attr.send_cq = cq;
+ struct ib_qp_init_attr attr = {
+ .send_cq = priv->cq,
+ .recv_cq = priv->cq,
+ .srq = priv->cm.srq,
+ .cap.max_send_wr = ipoib_sendq_size,
+ .cap.max_send_sge = 1,
+ .sq_sig_type = IB_SIGNAL_ALL_WR,
+ .qp_type = IB_QPT_RC,
+ .qp_context = tx
+ };
+
return ib_create_qp(priv->pd, &attr);
}
@@ -897,21 +880,7 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn,
goto err_tx;
}
- p->cq = ib_create_cq(priv->ca, ipoib_cm_tx_completion, NULL, p,
- ipoib_sendq_size + 1, 0);
- if (IS_ERR(p->cq)) {
- ret = PTR_ERR(p->cq);
- ipoib_warn(priv, "failed to allocate tx cq: %d\n", ret);
- goto err_cq;
- }
-
- ret = ib_req_notify_cq(p->cq, IB_CQ_NEXT_COMP);
- if (ret) {
- ipoib_warn(priv, "failed to request completion notification: %d\n", ret);
- goto err_req_notify;
- }
-
- p->qp = ipoib_cm_create_tx_qp(p->dev, p->cq);
+ p->qp = ipoib_cm_create_tx_qp(p->dev, p);
if (IS_ERR(p->qp)) {
ret = PTR_ERR(p->qp);
ipoib_warn(priv, "failed to allocate tx qp: %d\n", ret);
@@ -948,12 +917,8 @@ err_modify:
err_id:
p->id = NULL;
ib_destroy_qp(p->qp);
-err_req_notify:
err_qp:
p->qp = NULL;
- ib_destroy_cq(p->cq);
-err_cq:
- p->cq = NULL;
err_tx:
return ret;
}
@@ -962,6 +927,8 @@ static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p)
{
struct ipoib_dev_priv *priv = netdev_priv(p->dev);
struct ipoib_tx_buf *tx_req;
+ unsigned long flags;
+ unsigned long begin;
ipoib_dbg(priv, "Destroy active connection 0x%x head 0x%x tail 0x%x\n",
p->qp ? p->qp->qp_num : 0, p->tx_head, p->tx_tail);
@@ -969,27 +936,40 @@ static void ipoib_cm_tx_destroy(struct ipoib_cm_tx *p)
if (p->id)
ib_destroy_cm_id(p->id);
- if (p->qp)
- ib_destroy_qp(p->qp);
-
- if (p->cq)
- ib_destroy_cq(p->cq);
-
- if (test_bit(IPOIB_FLAG_NETIF_STOPPED, &p->flags))
- netif_wake_queue(p->dev);
-
if (p->tx_ring) {
+ /* Wait for all sends to complete */
+ begin = jiffies;
while ((int) p->tx_tail - (int) p->tx_head < 0) {
- tx_req = &p->tx_ring[p->tx_tail & (ipoib_sendq_size - 1)];
- ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len,
- DMA_TO_DEVICE);
- dev_kfree_skb_any(tx_req->skb);
- ++p->tx_tail;
+ if (time_after(jiffies, begin + 5 * HZ)) {
+ ipoib_warn(priv, "timing out; %d sends not completed\n",
+ p->tx_head - p->tx_tail);
+ goto timeout;
+ }
+
+ msleep(1);
}
+ }
+
+timeout:
- kfree(p->tx_ring);
+ while ((int) p->tx_tail - (int) p->tx_head < 0) {
+ tx_req = &p->tx_ring[p->tx_tail & (ipoib_sendq_size - 1)];
+ ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len,
+ DMA_TO_DEVICE);
+ dev_kfree_skb_any(tx_req->skb);
+ ++p->tx_tail;
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
+ netif_queue_stopped(p->dev) &&
+ test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
+ netif_wake_queue(p->dev);
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
}
+ if (p->qp)
+ ib_destroy_qp(p->qp);
+
+ kfree(p->tx_ring);
kfree(p);
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 10944888cff..5063dd509ad 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -208,7 +208,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
* this packet and reuse the old buffer.
*/
if (unlikely(ipoib_alloc_rx_skb(dev, wr_id))) {
- ++priv->stats.rx_dropped;
+ ++dev->stats.rx_dropped;
goto repost;
}
@@ -225,8 +225,8 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
skb_pull(skb, IPOIB_ENCAP_LEN);
dev->last_rx = jiffies;
- ++priv->stats.rx_packets;
- priv->stats.rx_bytes += skb->len;
+ ++dev->stats.rx_packets;
+ dev->stats.rx_bytes += skb->len;
skb->dev = dev;
/* XXX get correct PACKET_ type here */
@@ -260,18 +260,17 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
ib_dma_unmap_single(priv->ca, tx_req->mapping,
tx_req->skb->len, DMA_TO_DEVICE);
- ++priv->stats.tx_packets;
- priv->stats.tx_bytes += tx_req->skb->len;
+ ++dev->stats.tx_packets;
+ dev->stats.tx_bytes += tx_req->skb->len;
dev_kfree_skb_any(tx_req->skb);
spin_lock_irqsave(&priv->tx_lock, flags);
++priv->tx_tail;
- if (unlikely(test_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags)) &&
- priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1) {
- clear_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
+ if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
+ netif_queue_stopped(dev) &&
+ test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
netif_wake_queue(dev);
- }
spin_unlock_irqrestore(&priv->tx_lock, flags);
if (wc->status != IB_WC_SUCCESS &&
@@ -281,63 +280,62 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
wc->status, wr_id, wc->vendor_err);
}
-int ipoib_poll(struct net_device *dev, int *budget)
+int ipoib_poll(struct napi_struct *napi, int budget)
{
- struct ipoib_dev_priv *priv = netdev_priv(dev);
- int max = min(*budget, dev->quota);
+ struct ipoib_dev_priv *priv = container_of(napi, struct ipoib_dev_priv, napi);
+ struct net_device *dev = priv->dev;
int done;
int t;
- int empty;
int n, i;
done = 0;
- empty = 0;
- while (max) {
+poll_more:
+ while (done < budget) {
+ int max = (budget - done);
+
t = min(IPOIB_NUM_WC, max);
n = ib_poll_cq(priv->cq, t, priv->ibwc);
- for (i = 0; i < n; ++i) {
+ for (i = 0; i < n; i++) {
struct ib_wc *wc = priv->ibwc + i;
- if (wc->wr_id & IPOIB_CM_OP_SRQ) {
- ++done;
- --max;
- ipoib_cm_handle_rx_wc(dev, wc);
- } else if (wc->wr_id & IPOIB_OP_RECV) {
+ if (wc->wr_id & IPOIB_OP_RECV) {
++done;
- --max;
- ipoib_ib_handle_rx_wc(dev, wc);
- } else
- ipoib_ib_handle_tx_wc(dev, wc);
+ if (wc->wr_id & IPOIB_OP_CM)
+ ipoib_cm_handle_rx_wc(dev, wc);
+ else
+ ipoib_ib_handle_rx_wc(dev, wc);
+ } else {
+ if (wc->wr_id & IPOIB_OP_CM)
+ ipoib_cm_handle_tx_wc(dev, wc);
+ else
+ ipoib_ib_handle_tx_wc(dev, wc);
+ }
}
- if (n != t) {
- empty = 1;
+ if (n != t)
break;
- }
}
- dev->quota -= done;
- *budget -= done;
-
- if (empty) {
- netif_rx_complete(dev);
+ if (done < budget) {
+ netif_rx_complete(dev, napi);
if (unlikely(ib_req_notify_cq(priv->cq,
IB_CQ_NEXT_COMP |
IB_CQ_REPORT_MISSED_EVENTS)) &&
- netif_rx_reschedule(dev, 0))
- return 1;
-
- return 0;
+ netif_rx_reschedule(dev, napi))
+ goto poll_more;
}
- return 1;
+ return done;
}
void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
{
- netif_rx_schedule(dev_ptr);
+ struct net_device *dev = dev_ptr;
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+
+ netif_rx_schedule(dev, &priv->napi);
}
static inline int post_send(struct ipoib_dev_priv *priv,
@@ -367,8 +365,8 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
if (unlikely(skb->len > priv->mcast_mtu + IPOIB_ENCAP_LEN)) {
ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
skb->len, priv->mcast_mtu + IPOIB_ENCAP_LEN);
- ++priv->stats.tx_dropped;
- ++priv->stats.tx_errors;
+ ++dev->stats.tx_dropped;
+ ++dev->stats.tx_errors;
ipoib_cm_skb_too_long(dev, skb, priv->mcast_mtu);
return;
}
@@ -388,7 +386,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
addr = ib_dma_map_single(priv->ca, skb->data, skb->len,
DMA_TO_DEVICE);
if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
- ++priv->stats.tx_errors;
+ ++dev->stats.tx_errors;
dev_kfree_skb_any(skb);
return;
}
@@ -397,7 +395,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
address->ah, qpn, addr, skb->len))) {
ipoib_warn(priv, "post_send failed\n");
- ++priv->stats.tx_errors;
+ ++dev->stats.tx_errors;
ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
dev_kfree_skb_any(skb);
} else {
@@ -406,10 +404,9 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
address->last_send = priv->tx_head;
++priv->tx_head;
- if (priv->tx_head - priv->tx_tail == ipoib_sendq_size) {
+ if (++priv->tx_outstanding == ipoib_sendq_size) {
ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
netif_stop_queue(dev);
- set_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
}
}
}
@@ -441,7 +438,8 @@ void ipoib_reap_ah(struct work_struct *work)
__ipoib_reap_ah(dev);
if (!test_bit(IPOIB_STOP_REAPER, &priv->flags))
- queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task, HZ);
+ queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task,
+ round_jiffies_relative(HZ));
}
int ipoib_ib_dev_open(struct net_device *dev)
@@ -477,7 +475,8 @@ int ipoib_ib_dev_open(struct net_device *dev)
}
clear_bit(IPOIB_STOP_REAPER, &priv->flags);
- queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task, HZ);
+ queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task,
+ round_jiffies_relative(HZ));
set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
@@ -558,12 +557,25 @@ void ipoib_drain_cq(struct net_device *dev)
do {
n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc);
for (i = 0; i < n; ++i) {
- if (priv->ibwc[i].wr_id & IPOIB_CM_OP_SRQ)
- ipoib_cm_handle_rx_wc(dev, priv->ibwc + i);
- else if (priv->ibwc[i].wr_id & IPOIB_OP_RECV)
- ipoib_ib_handle_rx_wc(dev, priv->ibwc + i);
- else
- ipoib_ib_handle_tx_wc(dev, priv->ibwc + i);
+ /*
+ * Convert any successful completions to flush
+ * errors to avoid passing packets up the
+ * stack after bringing the device down.
+ */
+ if (priv->ibwc[i].status == IB_WC_SUCCESS)
+ priv->ibwc[i].status = IB_WC_WR_FLUSH_ERR;
+
+ if (priv->ibwc[i].wr_id & IPOIB_OP_RECV) {
+ if (priv->ibwc[i].wr_id & IPOIB_OP_CM)
+ ipoib_cm_handle_rx_wc(dev, priv->ibwc + i);
+ else
+ ipoib_ib_handle_rx_wc(dev, priv->ibwc + i);
+ } else {
+ if (priv->ibwc[i].wr_id & IPOIB_OP_CM)
+ ipoib_cm_handle_tx_wc(dev, priv->ibwc + i);
+ else
+ ipoib_ib_handle_tx_wc(dev, priv->ibwc + i);
+ }
}
} while (n == IPOIB_NUM_WC);
}
@@ -577,7 +589,6 @@ int ipoib_ib_dev_stop(struct net_device *dev, int flush)
int i;
clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
- netif_poll_disable(dev);
ipoib_cm_dev_stop(dev);
@@ -610,6 +621,7 @@ int ipoib_ib_dev_stop(struct net_device *dev, int flush)
DMA_TO_DEVICE);
dev_kfree_skb_any(tx_req->skb);
++priv->tx_tail;
+ --priv->tx_outstanding;
}
for (i = 0; i < ipoib_recvq_size; ++i) {
@@ -660,7 +672,6 @@ timeout:
msleep(1);
}
- netif_poll_enable(dev);
ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP);
return 0;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 894b1dcdf3e..a03a65ebcf0 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -98,16 +98,20 @@ int ipoib_open(struct net_device *dev)
ipoib_dbg(priv, "bringing up interface\n");
+ napi_enable(&priv->napi);
set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
if (ipoib_pkey_dev_delay_open(dev))
return 0;
- if (ipoib_ib_dev_open(dev))
+ if (ipoib_ib_dev_open(dev)) {
+ napi_disable(&priv->napi);
return -EINVAL;
+ }
if (ipoib_ib_dev_up(dev)) {
ipoib_ib_dev_stop(dev, 1);
+ napi_disable(&priv->napi);
return -EINVAL;
}
@@ -140,11 +144,10 @@ static int ipoib_stop(struct net_device *dev)
ipoib_dbg(priv, "stopping interface\n");
clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
+ napi_disable(&priv->napi);
netif_stop_queue(dev);
- clear_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
-
/*
* Now flush workqueue to make sure a scheduled task doesn't
* bring our internal state back up.
@@ -468,9 +471,10 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid)
INIT_LIST_HEAD(&path->neigh_list);
memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid));
- path->pathrec.sgid = priv->local_gid;
- path->pathrec.pkey = cpu_to_be16(priv->pkey);
- path->pathrec.numb_path = 1;
+ path->pathrec.sgid = priv->local_gid;
+ path->pathrec.pkey = cpu_to_be16(priv->pkey);
+ path->pathrec.numb_path = 1;
+ path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class;
return path;
}
@@ -491,6 +495,7 @@ static int path_rec_start(struct net_device *dev,
IB_SA_PATH_REC_DGID |
IB_SA_PATH_REC_SGID |
IB_SA_PATH_REC_NUMB_PATH |
+ IB_SA_PATH_REC_TRAFFIC_CLASS |
IB_SA_PATH_REC_PKEY,
1000, GFP_ATOMIC,
path_rec_completion,
@@ -510,9 +515,9 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
struct ipoib_path *path;
struct ipoib_neigh *neigh;
- neigh = ipoib_neigh_alloc(skb->dst->neighbour);
+ neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev);
if (!neigh) {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
return;
}
@@ -577,7 +582,7 @@ err_list:
err_path:
ipoib_neigh_free(dev, neigh);
err_drop:
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
spin_unlock(&priv->lock);
@@ -626,7 +631,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
} else
__path_add(dev, path);
} else {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
}
@@ -645,7 +650,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
skb_push(skb, sizeof *phdr);
__skb_queue_tail(&path->queue, skb);
} else {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
}
@@ -685,9 +690,10 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto out;
}
} else if (neigh->ah) {
- if (unlikely(memcmp(&neigh->dgid.raw,
+ if (unlikely((memcmp(&neigh->dgid.raw,
skb->dst->neighbour->ha + 4,
- sizeof(union ib_gid)))) {
+ sizeof(union ib_gid))) ||
+ (neigh->dev != dev))) {
spin_lock(&priv->lock);
/*
* It's safe to call ipoib_put_ah() inside
@@ -713,7 +719,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
__skb_queue_tail(&neigh->queue, skb);
spin_unlock(&priv->lock);
} else {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
}
} else {
@@ -739,7 +745,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
IPOIB_QPN(phdr->hwaddr),
IPOIB_GID_RAW_ARG(phdr->hwaddr + 4));
dev_kfree_skb_any(skb);
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
goto out;
}
@@ -753,13 +759,6 @@ out:
return NETDEV_TX_OK;
}
-static struct net_device_stats *ipoib_get_stats(struct net_device *dev)
-{
- struct ipoib_dev_priv *priv = netdev_priv(dev);
-
- return &priv->stats;
-}
-
static void ipoib_timeout(struct net_device *dev)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -775,7 +774,7 @@ static void ipoib_timeout(struct net_device *dev)
static int ipoib_hard_header(struct sk_buff *skb,
struct net_device *dev,
unsigned short type,
- void *daddr, void *saddr, unsigned len)
+ const void *daddr, const void *saddr, unsigned len)
{
struct ipoib_header *header;
@@ -817,6 +816,13 @@ static void ipoib_neigh_cleanup(struct neighbour *n)
unsigned long flags;
struct ipoib_ah *ah = NULL;
+ neigh = *to_ipoib_neigh(n);
+ if (neigh) {
+ priv = netdev_priv(neigh->dev);
+ ipoib_dbg(priv, "neigh_destructor for bonding device: %s\n",
+ n->dev->name);
+ } else
+ return;
ipoib_dbg(priv,
"neigh_cleanup for %06x " IPOIB_GID_FMT "\n",
IPOIB_QPN(n->ha),
@@ -824,13 +830,10 @@ static void ipoib_neigh_cleanup(struct neighbour *n)
spin_lock_irqsave(&priv->lock, flags);
- neigh = *to_ipoib_neigh(n);
- if (neigh) {
- if (neigh->ah)
- ah = neigh->ah;
- list_del(&neigh->list);
- ipoib_neigh_free(n->dev, neigh);
- }
+ if (neigh->ah)
+ ah = neigh->ah;
+ list_del(&neigh->list);
+ ipoib_neigh_free(n->dev, neigh);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -838,7 +841,8 @@ static void ipoib_neigh_cleanup(struct neighbour *n)
ipoib_put_ah(ah);
}
-struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
+struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour,
+ struct net_device *dev)
{
struct ipoib_neigh *neigh;
@@ -847,6 +851,7 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
return NULL;
neigh->neighbour = neighbour;
+ neigh->dev = dev;
*to_ipoib_neigh(neighbour) = neigh;
skb_queue_head_init(&neigh->queue);
ipoib_cm_set(neigh, NULL);
@@ -856,11 +861,10 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh)
{
- struct ipoib_dev_priv *priv = netdev_priv(dev);
struct sk_buff *skb;
*to_ipoib_neigh(neigh->neighbour) = NULL;
while ((skb = __skb_dequeue(&neigh->queue))) {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
}
if (ipoib_cm_get(neigh))
@@ -896,7 +900,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
goto out_rx_ring_cleanup;
}
- /* priv->tx_head & tx_tail are already 0 */
+ /* priv->tx_head, tx_tail & tx_outstanding are already 0 */
if (ipoib_ib_dev_init(dev, ca, port))
goto out_tx_ring_cleanup;
@@ -935,6 +939,10 @@ void ipoib_dev_cleanup(struct net_device *dev)
priv->tx_ring = NULL;
}
+static const struct header_ops ipoib_header_ops = {
+ .create = ipoib_hard_header,
+};
+
static void ipoib_setup(struct net_device *dev)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -943,13 +951,12 @@ static void ipoib_setup(struct net_device *dev)
dev->stop = ipoib_stop;
dev->change_mtu = ipoib_change_mtu;
dev->hard_start_xmit = ipoib_start_xmit;
- dev->get_stats = ipoib_get_stats;
dev->tx_timeout = ipoib_timeout;
- dev->hard_header = ipoib_hard_header;
+ dev->header_ops = &ipoib_header_ops;
dev->set_multicast_list = ipoib_set_mcast_list;
dev->neigh_setup = ipoib_neigh_setup_dev;
- dev->poll = ipoib_poll;
- dev->weight = 100;
+
+ netif_napi_add(dev, &priv->napi, ipoib_poll, 100);
dev->watchdog_timeo = HZ;
@@ -973,8 +980,6 @@ static void ipoib_setup(struct net_device *dev)
netif_carrier_off(dev);
- SET_MODULE_OWNER(dev);
-
priv->dev = dev;
spin_lock_init(&priv->lock);
@@ -1017,6 +1022,37 @@ static ssize_t show_pkey(struct device *dev,
}
static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
+static ssize_t show_umcast(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
+
+ return sprintf(buf, "%d\n", test_bit(IPOIB_FLAG_UMCAST, &priv->flags));
+}
+
+static ssize_t set_umcast(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
+ unsigned long umcast_val = simple_strtoul(buf, NULL, 0);
+
+ if (umcast_val > 0) {
+ set_bit(IPOIB_FLAG_UMCAST, &priv->flags);
+ ipoib_warn(priv, "ignoring multicast groups joined directly "
+ "by userspace\n");
+ } else
+ clear_bit(IPOIB_FLAG_UMCAST, &priv->flags);
+
+ return count;
+}
+static DEVICE_ATTR(umcast, S_IWUSR | S_IRUGO, show_umcast, set_umcast);
+
+int ipoib_add_umcast_attr(struct net_device *dev)
+{
+ return device_create_file(&dev->dev, &dev_attr_umcast);
+}
+
static ssize_t create_child(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -1083,7 +1119,7 @@ static struct net_device *ipoib_add_port(const char *format,
if (result) {
printk(KERN_WARNING "%s: ib_query_pkey port %d failed (ret = %d)\n",
hca->name, port, result);
- goto alloc_mem_failed;
+ goto device_init_failed;
}
/*
@@ -1099,7 +1135,7 @@ static struct net_device *ipoib_add_port(const char *format,
if (result) {
printk(KERN_WARNING "%s: ib_query_gid port %d failed (ret = %d)\n",
hca->name, port, result);
- goto alloc_mem_failed;
+ goto device_init_failed;
} else
memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid));
@@ -1134,6 +1170,8 @@ static struct net_device *ipoib_add_port(const char *format,
goto sysfs_failed;
if (ipoib_add_pkey_attr(priv->dev))
goto sysfs_failed;
+ if (ipoib_add_umcast_attr(priv->dev))
+ goto sysfs_failed;
if (device_create_file(&priv->dev->dev, &dev_attr_create_child))
goto sysfs_failed;
if (device_create_file(&priv->dev->dev, &dev_attr_delete_child))
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index aae367057a5..9bcfc7ad6aa 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -57,28 +57,6 @@ MODULE_PARM_DESC(mcast_debug_level,
static DEFINE_MUTEX(mcast_mutex);
-/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */
-struct ipoib_mcast {
- struct ib_sa_mcmember_rec mcmember;
- struct ib_sa_multicast *mc;
- struct ipoib_ah *ah;
-
- struct rb_node rb_node;
- struct list_head list;
-
- unsigned long created;
- unsigned long backoff;
-
- unsigned long flags;
- unsigned char logcount;
-
- struct list_head neigh_list;
-
- struct sk_buff_head pkt_queue;
-
- struct net_device *dev;
-};
-
struct ipoib_mcast_iter {
struct net_device *dev;
union ib_gid mgid;
@@ -125,7 +103,7 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast)
}
spin_lock_irqsave(&priv->tx_lock, flags);
- priv->stats.tx_dropped += tx_dropped;
+ dev->stats.tx_dropped += tx_dropped;
spin_unlock_irqrestore(&priv->tx_lock, flags);
kfree(mcast);
@@ -320,7 +298,7 @@ ipoib_mcast_sendonly_join_complete(int status,
/* Flush out any queued packets */
spin_lock_irq(&priv->tx_lock);
while (!skb_queue_empty(&mcast->pkt_queue)) {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
}
spin_unlock_irq(&priv->tx_lock);
@@ -675,7 +653,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
if (!test_bit(IPOIB_MCAST_STARTED, &priv->flags) ||
!priv->broadcast ||
!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
goto unlock;
}
@@ -690,7 +668,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
if (!mcast) {
ipoib_warn(priv, "unable to allocate memory for "
"multicast structure\n");
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
goto out;
}
@@ -705,7 +683,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE)
skb_queue_tail(&mcast->pkt_queue, skb);
else {
- ++priv->stats.tx_dropped;
+ ++dev->stats.tx_dropped;
dev_kfree_skb_any(skb);
}
@@ -727,7 +705,8 @@ out:
if (skb->dst &&
skb->dst->neighbour &&
!*to_ipoib_neigh(skb->dst->neighbour)) {
- struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour);
+ struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour,
+ skb->dev);
if (neigh) {
kref_get(&mcast->ah->ref);
@@ -783,6 +762,7 @@ void ipoib_mcast_restart_task(struct work_struct *work)
struct ipoib_mcast *mcast, *tmcast;
LIST_HEAD(remove_list);
unsigned long flags;
+ struct ib_sa_mcmember_rec rec;
ipoib_dbg_mcast(priv, "restarting multicast task\n");
@@ -816,6 +796,14 @@ void ipoib_mcast_restart_task(struct work_struct *work)
if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
struct ipoib_mcast *nmcast;
+ /* ignore group which is directly joined by userspace */
+ if (test_bit(IPOIB_FLAG_UMCAST, &priv->flags) &&
+ !ib_sa_get_mcmember_rec(priv->ca, priv->port, &mgid, &rec)) {
+ ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid "
+ IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid));
+ continue;
+ }
+
/* Not found or send-only group, let's add a new entry */
ipoib_dbg_mcast(priv, "adding multicast entry for mgid "
IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid));
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 563aeacf9e1..3c6e45db0ab 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -185,7 +185,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
goto out_free_cq;
init_attr.send_cq = priv->cq;
- init_attr.recv_cq = priv->cq,
+ init_attr.recv_cq = priv->cq;
priv->qp = ib_create_qp(priv->pd, &init_attr);
if (IS_ERR(priv->qp)) {
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 6762988439d..293f5b892e3 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -119,6 +119,8 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
goto sysfs_failed;
if (ipoib_add_pkey_attr(priv->dev))
goto sysfs_failed;
+ if (ipoib_add_umcast_attr(priv->dev))
+ goto sysfs_failed;
if (device_create_file(&priv->dev->dev, &dev_attr_parent))
goto sysfs_failed;
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 9ea5b9aaba7..a6f2303ed14 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -34,8 +34,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <asm/io.h>
-#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
#include <linux/kfifo.h>
#include <scsi/scsi_cmnd.h>
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index 36cdf77ae92..d6879806179 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -36,8 +36,6 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/highmem.h>
-#include <asm/io.h>
-#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
#include "iscsi_iser.h"
@@ -126,17 +124,19 @@ static int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
if (cmd_dir == ISER_DIR_OUT) {
/* copy the unaligned sg the buffer which is used for RDMA */
- struct scatterlist *sg = (struct scatterlist *)data->buf;
+ struct scatterlist *sgl = (struct scatterlist *)data->buf;
+ struct scatterlist *sg;
int i;
char *p, *from;
- for (p = mem, i = 0; i < data->size; i++) {
- from = kmap_atomic(sg[i].page, KM_USER0);
+ p = mem;
+ for_each_sg(sgl, sg, data->size, i) {
+ from = kmap_atomic(sg_page(sg), KM_USER0);
memcpy(p,
- from + sg[i].offset,
- sg[i].length);
+ from + sg->offset,
+ sg->length);
kunmap_atomic(from, KM_USER0);
- p += sg[i].length;
+ p += sg->length;
}
}
@@ -178,7 +178,7 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
if (cmd_dir == ISER_DIR_IN) {
char *mem;
- struct scatterlist *sg;
+ struct scatterlist *sgl, *sg;
unsigned char *p, *to;
unsigned int sg_size;
int i;
@@ -186,16 +186,17 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
/* copy back read RDMA to unaligned sg */
mem = mem_copy->copy_buf;
- sg = (struct scatterlist *)iser_ctask->data[ISER_DIR_IN].buf;
+ sgl = (struct scatterlist *)iser_ctask->data[ISER_DIR_IN].buf;
sg_size = iser_ctask->data[ISER_DIR_IN].size;
- for (p = mem, i = 0; i < sg_size; i++){
- to = kmap_atomic(sg[i].page, KM_SOFTIRQ0);
- memcpy(to + sg[i].offset,
+ p = mem;
+ for_each_sg(sgl, sg, sg_size, i) {
+ to = kmap_atomic(sg_page(sg), KM_SOFTIRQ0);
+ memcpy(to + sg->offset,
p,
- sg[i].length);
+ sg->length);
kunmap_atomic(to, KM_SOFTIRQ0);
- p += sg[i].length;
+ p += sg->length;
}
}
@@ -226,7 +227,8 @@ static int iser_sg_to_page_vec(struct iser_data_buf *data,
struct iser_page_vec *page_vec,
struct ib_device *ibdev)
{
- struct scatterlist *sg = (struct scatterlist *)data->buf;
+ struct scatterlist *sgl = (struct scatterlist *)data->buf;
+ struct scatterlist *sg;
u64 first_addr, last_addr, page;
int end_aligned;
unsigned int cur_page = 0;
@@ -234,24 +236,25 @@ static int iser_sg_to_page_vec(struct iser_data_buf *data,
int i;
/* compute the offset of first element */
- page_vec->offset = (u64) sg[0].offset & ~MASK_4K;
+ page_vec->offset = (u64) sgl[0].offset & ~MASK_4K;
- for (i = 0; i < data->dma_nents; i++) {
- unsigned int dma_len = ib_sg_dma_len(ibdev, &sg[i]);
+ for_each_sg(sgl, sg, data->dma_nents, i) {
+ unsigned int dma_len = ib_sg_dma_len(ibdev, sg);
total_sz += dma_len;
- first_addr = ib_sg_dma_address(ibdev, &sg[i]);
+ first_addr = ib_sg_dma_address(ibdev, sg);
last_addr = first_addr + dma_len;
end_aligned = !(last_addr & ~MASK_4K);
/* continue to collect page fragments till aligned or SG ends */
while (!end_aligned && (i + 1 < data->dma_nents)) {
+ sg = sg_next(sg);
i++;
- dma_len = ib_sg_dma_len(ibdev, &sg[i]);
+ dma_len = ib_sg_dma_len(ibdev, sg);
total_sz += dma_len;
- last_addr = ib_sg_dma_address(ibdev, &sg[i]) + dma_len;
+ last_addr = ib_sg_dma_address(ibdev, sg) + dma_len;
end_aligned = !(last_addr & ~MASK_4K);
}
@@ -286,25 +289,26 @@ static int iser_sg_to_page_vec(struct iser_data_buf *data,
static unsigned int iser_data_buf_aligned_len(struct iser_data_buf *data,
struct ib_device *ibdev)
{
- struct scatterlist *sg;
+ struct scatterlist *sgl, *sg;
u64 end_addr, next_addr;
int i, cnt;
unsigned int ret_len = 0;
- sg = (struct scatterlist *)data->buf;
+ sgl = (struct scatterlist *)data->buf;
- for (cnt = 0, i = 0; i < data->dma_nents; i++, cnt++) {
+ cnt = 0;
+ for_each_sg(sgl, sg, data->dma_nents, i) {
/* iser_dbg("Checking sg iobuf [%d]: phys=0x%08lX "
"offset: %ld sz: %ld\n", i,
- (unsigned long)page_to_phys(sg[i].page),
- (unsigned long)sg[i].offset,
- (unsigned long)sg[i].length); */
- end_addr = ib_sg_dma_address(ibdev, &sg[i]) +
- ib_sg_dma_len(ibdev, &sg[i]);
+ (unsigned long)sg_phys(sg),
+ (unsigned long)sg->offset,
+ (unsigned long)sg->length); */
+ end_addr = ib_sg_dma_address(ibdev, sg) +
+ ib_sg_dma_len(ibdev, sg);
/* iser_dbg("Checking sg iobuf end address "
"0x%08lX\n", end_addr); */
if (i + 1 < data->dma_nents) {
- next_addr = ib_sg_dma_address(ibdev, &sg[i+1]);
+ next_addr = ib_sg_dma_address(ibdev, sg_next(sg));
/* are i, i+1 fragments of the same page? */
if (end_addr == next_addr)
continue;
@@ -324,15 +328,16 @@ static unsigned int iser_data_buf_aligned_len(struct iser_data_buf *data,
static void iser_data_buf_dump(struct iser_data_buf *data,
struct ib_device *ibdev)
{
- struct scatterlist *sg = (struct scatterlist *)data->buf;
+ struct scatterlist *sgl = (struct scatterlist *)data->buf;
+ struct scatterlist *sg;
int i;
- for (i = 0; i < data->dma_nents; i++)
+ for_each_sg(sgl, sg, data->dma_nents, i)
iser_err("sg[%d] dma_addr:0x%lX page:0x%p "
"off:0x%x sz:0x%x dma_len:0x%x\n",
- i, (unsigned long)ib_sg_dma_address(ibdev, &sg[i]),
- sg[i].page, sg[i].offset,
- sg[i].length, ib_sg_dma_len(ibdev, &sg[i]));
+ i, (unsigned long)ib_sg_dma_address(ibdev, sg),
+ sg_page(sg), sg->offset,
+ sg->length, ib_sg_dma_len(ibdev, sg));
}
static void iser_dump_page_vec(struct iser_page_vec *page_vec)
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index d42ec0156ee..654a4dce023 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -32,7 +32,6 @@
*
* $Id: iser_verbs.c 7051 2006-05-10 12:29:11Z ogerlitz $
*/
-#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
diff --git a/drivers/infiniband/ulp/srp/Kconfig b/drivers/infiniband/ulp/srp/Kconfig
index 3432dce2952..c74ee963304 100644
--- a/drivers/infiniband/ulp/srp/Kconfig
+++ b/drivers/infiniband/ulp/srp/Kconfig
@@ -1,6 +1,7 @@
config INFINIBAND_SRP
tristate "InfiniBand SCSI RDMA Protocol"
depends on SCSI
+ select SCSI_SRP_ATTRS
---help---
Support for the SCSI RDMA Protocol over InfiniBand. This
allows you to access storage devices that speak SRP over
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index f6a05142814..950228fb009 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -47,6 +47,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_dbg.h>
#include <scsi/srp.h>
+#include <scsi/scsi_transport_srp.h>
#include <rdma/ib_cache.h>
@@ -86,6 +87,8 @@ static void srp_remove_one(struct ib_device *device);
static void srp_completion(struct ib_cq *cq, void *target_ptr);
static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
+static struct scsi_transport_template *ib_srp_transport_template;
+
static struct ib_client srp_client = {
.name = "srp",
.add = srp_add_one,
@@ -285,6 +288,7 @@ static int srp_lookup_path(struct srp_target_port *target)
target->srp_host->dev->dev,
target->srp_host->port,
&target->path,
+ IB_SA_PATH_REC_SERVICE_ID |
IB_SA_PATH_REC_DGID |
IB_SA_PATH_REC_SGID |
IB_SA_PATH_REC_NUMB_PATH |
@@ -419,6 +423,7 @@ static void srp_remove_work(struct work_struct *work)
list_del(&target->list);
spin_unlock(&target->srp_host->target_lock);
+ srp_remove_host(target->scsi_host);
scsi_remove_host(target->scsi_host);
ib_destroy_cm_id(target->cm_id);
srp_free_target_ib(target);
@@ -1543,12 +1548,24 @@ static struct scsi_host_template srp_template = {
static int srp_add_target(struct srp_host *host, struct srp_target_port *target)
{
+ struct srp_rport_identifiers ids;
+ struct srp_rport *rport;
+
sprintf(target->target_name, "SRP.T10:%016llX",
(unsigned long long) be64_to_cpu(target->id_ext));
if (scsi_add_host(target->scsi_host, host->dev->dev->dma_device))
return -ENODEV;
+ memcpy(ids.port_id, &target->id_ext, 8);
+ memcpy(ids.port_id + 8, &target->ioc_guid, 8);
+ ids.roles = SRP_RPORT_ROLE_TARGET;
+ rport = srp_rport_add(target->scsi_host, &ids);
+ if (IS_ERR(rport)) {
+ scsi_remove_host(target->scsi_host);
+ return PTR_ERR(rport);
+ }
+
spin_lock(&host->target_lock);
list_add_tail(&target->list, &host->target_list);
spin_unlock(&host->target_lock);
@@ -1692,6 +1709,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
goto out;
}
target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16));
+ target->path.service_id = target->service_id;
kfree(p);
break;
@@ -1773,6 +1791,7 @@ static ssize_t srp_create_target(struct class_device *class_dev,
if (!target_host)
return -ENOMEM;
+ target_host->transportt = ib_srp_transport_template;
target_host->max_lun = SRP_MAX_LUN;
target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb;
@@ -2052,10 +2071,18 @@ static void srp_remove_one(struct ib_device *device)
kfree(srp_dev);
}
+static struct srp_function_template ib_srp_transport_functions = {
+};
+
static int __init srp_init_module(void)
{
int ret;
+ ib_srp_transport_template =
+ srp_attach_transport(&ib_srp_transport_functions);
+ if (!ib_srp_transport_template)
+ return -ENOMEM;
+
srp_template.sg_tablesize = srp_sg_tablesize;
srp_max_iu_len = (sizeof (struct srp_cmd) +
sizeof (struct srp_indirect_buf) +
@@ -2064,6 +2091,7 @@ static int __init srp_init_module(void)
ret = class_register(&srp_class);
if (ret) {
printk(KERN_ERR PFX "couldn't register class infiniband_srp\n");
+ srp_release_transport(ib_srp_transport_template);
return ret;
}
@@ -2072,6 +2100,7 @@ static int __init srp_init_module(void)
ret = ib_register_client(&srp_client);
if (ret) {
printk(KERN_ERR PFX "couldn't register IB client\n");
+ srp_release_transport(ib_srp_transport_template);
ib_sa_unregister_client(&srp_sa_client);
class_unregister(&srp_class);
return ret;
@@ -2085,6 +2114,7 @@ static void __exit srp_cleanup_module(void)
ib_unregister_client(&srp_client);
ib_sa_unregister_client(&srp_sa_client);
class_unregister(&srp_class);
+ srp_release_transport(ib_srp_transport_template);
}
module_init(srp_init_module);
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 2d87357e2b2..63512d906f0 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -114,28 +114,6 @@ config INPUT_JOYDEV
To compile this driver as a module, choose M here: the
module will be called joydev.
-config INPUT_TSDEV
- tristate "Touchscreen interface"
- ---help---
- Say Y here if you have an application that only can understand the
- Compaq touchscreen protocol for absolute pointer data. This is
- useful namely for embedded configurations.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called tsdev.
-
-config INPUT_TSDEV_SCREEN_X
- int "Horizontal screen resolution"
- depends on INPUT_TSDEV
- default "240"
-
-config INPUT_TSDEV_SCREEN_Y
- int "Vertical screen resolution"
- depends on INPUT_TSDEV
- default "320"
-
config INPUT_EVDEV
tristate "Event interface"
help
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 15eb752697b..99af903bd3c 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
-obj-$(CONFIG_INPUT_TSDEV) += tsdev.o
obj-$(CONFIG_INPUT_EVBUG) += evbug.o
obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index f1c3d6cebd5..e5b4e9bfbdc 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -30,6 +30,8 @@ struct evdev {
wait_queue_head_t wait;
struct evdev_client *grab;
struct list_head client_list;
+ spinlock_t client_lock; /* protects client_list */
+ struct mutex mutex;
struct device dev;
};
@@ -37,39 +39,54 @@ struct evdev_client {
struct input_event buffer[EVDEV_BUFFER_SIZE];
int head;
int tail;
+ spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct fasync_struct *fasync;
struct evdev *evdev;
struct list_head node;
};
static struct evdev *evdev_table[EVDEV_MINORS];
+static DEFINE_MUTEX(evdev_table_mutex);
-static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+static void evdev_pass_event(struct evdev_client *client,
+ struct input_event *event)
+{
+ /*
+ * Interrupts are disabled, just acquire the lock
+ */
+ spin_lock(&client->buffer_lock);
+ client->buffer[client->head++] = *event;
+ client->head &= EVDEV_BUFFER_SIZE - 1;
+ spin_unlock(&client->buffer_lock);
+
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
+}
+
+/*
+ * Pass incoming event to all connected clients.
+ */
+static void evdev_event(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
+ struct input_event event;
- if (evdev->grab) {
- client = evdev->grab;
+ do_gettimeofday(&event.time);
+ event.type = type;
+ event.code = code;
+ event.value = value;
- do_gettimeofday(&client->buffer[client->head].time);
- client->buffer[client->head].type = type;
- client->buffer[client->head].code = code;
- client->buffer[client->head].value = value;
- client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
+ rcu_read_lock();
- kill_fasync(&client->fasync, SIGIO, POLL_IN);
- } else
- list_for_each_entry(client, &evdev->client_list, node) {
+ client = rcu_dereference(evdev->grab);
+ if (client)
+ evdev_pass_event(client, &event);
+ else
+ list_for_each_entry_rcu(client, &evdev->client_list, node)
+ evdev_pass_event(client, &event);
- do_gettimeofday(&client->buffer[client->head].time);
- client->buffer[client->head].type = type;
- client->buffer[client->head].code = code;
- client->buffer[client->head].value = value;
- client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
-
- kill_fasync(&client->fasync, SIGIO, POLL_IN);
- }
+ rcu_read_unlock();
wake_up_interruptible(&evdev->wait);
}
@@ -88,38 +105,140 @@ static int evdev_flush(struct file *file, fl_owner_t id)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
+ int retval;
+
+ retval = mutex_lock_interruptible(&evdev->mutex);
+ if (retval)
+ return retval;
if (!evdev->exist)
- return -ENODEV;
+ retval = -ENODEV;
+ else
+ retval = input_flush_device(&evdev->handle, file);
- return input_flush_device(&evdev->handle, file);
+ mutex_unlock(&evdev->mutex);
+ return retval;
}
static void evdev_free(struct device *dev)
{
struct evdev *evdev = container_of(dev, struct evdev, dev);
- evdev_table[evdev->minor] = NULL;
kfree(evdev);
}
+/*
+ * Grabs an event device (along with underlying input device).
+ * This function is called with evdev->mutex taken.
+ */
+static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
+{
+ int error;
+
+ if (evdev->grab)
+ return -EBUSY;
+
+ error = input_grab_device(&evdev->handle);
+ if (error)
+ return error;
+
+ rcu_assign_pointer(evdev->grab, client);
+ synchronize_rcu();
+
+ return 0;
+}
+
+static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
+{
+ if (evdev->grab != client)
+ return -EINVAL;
+
+ rcu_assign_pointer(evdev->grab, NULL);
+ synchronize_rcu();
+ input_release_device(&evdev->handle);
+
+ return 0;
+}
+
+static void evdev_attach_client(struct evdev *evdev,
+ struct evdev_client *client)
+{
+ spin_lock(&evdev->client_lock);
+ list_add_tail_rcu(&client->node, &evdev->client_list);
+ spin_unlock(&evdev->client_lock);
+ synchronize_rcu();
+}
+
+static void evdev_detach_client(struct evdev *evdev,
+ struct evdev_client *client)
+{
+ spin_lock(&evdev->client_lock);
+ list_del_rcu(&client->node);
+ spin_unlock(&evdev->client_lock);
+ synchronize_rcu();
+}
+
+static int evdev_open_device(struct evdev *evdev)
+{
+ int retval;
+
+ retval = mutex_lock_interruptible(&evdev->mutex);
+ if (retval)
+ return retval;
+
+ if (!evdev->exist)
+ retval = -ENODEV;
+ else if (!evdev->open++) {
+ retval = input_open_device(&evdev->handle);
+ if (retval)
+ evdev->open--;
+ }
+
+ mutex_unlock(&evdev->mutex);
+ return retval;
+}
+
+static void evdev_close_device(struct evdev *evdev)
+{
+ mutex_lock(&evdev->mutex);
+
+ if (evdev->exist && !--evdev->open)
+ input_close_device(&evdev->handle);
+
+ mutex_unlock(&evdev->mutex);
+}
+
+/*
+ * Wake up users waiting for IO so they can disconnect from
+ * dead device.
+ */
+static void evdev_hangup(struct evdev *evdev)
+{
+ struct evdev_client *client;
+
+ spin_lock(&evdev->client_lock);
+ list_for_each_entry(client, &evdev->client_list, node)
+ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+ spin_unlock(&evdev->client_lock);
+
+ wake_up_interruptible(&evdev->wait);
+}
+
static int evdev_release(struct inode *inode, struct file *file)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
- if (evdev->grab == client) {
- input_release_device(&evdev->handle);
- evdev->grab = NULL;
- }
+ mutex_lock(&evdev->mutex);
+ if (evdev->grab == client)
+ evdev_ungrab(evdev, client);
+ mutex_unlock(&evdev->mutex);
evdev_fasync(-1, file, 0);
- list_del(&client->node);
+ evdev_detach_client(evdev, client);
kfree(client);
- if (!--evdev->open && evdev->exist)
- input_close_device(&evdev->handle);
-
+ evdev_close_device(evdev);
put_device(&evdev->dev);
return 0;
@@ -127,41 +246,44 @@ static int evdev_release(struct inode *inode, struct file *file)
static int evdev_open(struct inode *inode, struct file *file)
{
- struct evdev_client *client;
struct evdev *evdev;
+ struct evdev_client *client;
int i = iminor(inode) - EVDEV_MINOR_BASE;
int error;
if (i >= EVDEV_MINORS)
return -ENODEV;
+ error = mutex_lock_interruptible(&evdev_table_mutex);
+ if (error)
+ return error;
evdev = evdev_table[i];
+ if (evdev)
+ get_device(&evdev->dev);
+ mutex_unlock(&evdev_table_mutex);
- if (!evdev || !evdev->exist)
+ if (!evdev)
return -ENODEV;
- get_device(&evdev->dev);
-
client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
if (!client) {
error = -ENOMEM;
goto err_put_evdev;
}
+ spin_lock_init(&client->buffer_lock);
client->evdev = evdev;
- list_add_tail(&client->node, &evdev->client_list);
+ evdev_attach_client(evdev, client);
- if (!evdev->open++ && evdev->exist) {
- error = input_open_device(&evdev->handle);
- if (error)
- goto err_free_client;
- }
+ error = evdev_open_device(evdev);
+ if (error)
+ goto err_free_client;
file->private_data = client;
return 0;
err_free_client:
- list_del(&client->node);
+ evdev_detach_client(evdev, client);
kfree(client);
err_put_evdev:
put_device(&evdev->dev);
@@ -197,12 +319,14 @@ static inline size_t evdev_event_size(void)
sizeof(struct input_event_compat) : sizeof(struct input_event);
}
-static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
+static int evdev_event_from_user(const char __user *buffer,
+ struct input_event *event)
{
if (COMPAT_TEST) {
struct input_event_compat compat_event;
- if (copy_from_user(&compat_event, buffer, sizeof(struct input_event_compat)))
+ if (copy_from_user(&compat_event, buffer,
+ sizeof(struct input_event_compat)))
return -EFAULT;
event->time.tv_sec = compat_event.time.tv_sec;
@@ -219,7 +343,8 @@ static int evdev_event_from_user(const char __user *buffer, struct input_event *
return 0;
}
-static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
+static int evdev_event_to_user(char __user *buffer,
+ const struct input_event *event)
{
if (COMPAT_TEST) {
struct input_event_compat compat_event;
@@ -230,7 +355,8 @@ static int evdev_event_to_user(char __user *buffer, const struct input_event *ev
compat_event.code = event->code;
compat_event.value = event->value;
- if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat)))
+ if (copy_to_user(buffer, &compat_event,
+ sizeof(struct input_event_compat)))
return -EFAULT;
} else {
@@ -248,7 +374,8 @@ static inline size_t evdev_event_size(void)
return sizeof(struct input_event);
}
-static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
+static int evdev_event_from_user(const char __user *buffer,
+ struct input_event *event)
{
if (copy_from_user(event, buffer, sizeof(struct input_event)))
return -EFAULT;
@@ -256,7 +383,8 @@ static int evdev_event_from_user(const char __user *buffer, struct input_event *
return 0;
}
-static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
+static int evdev_event_to_user(char __user *buffer,
+ const struct input_event *event)
{
if (copy_to_user(buffer, event, sizeof(struct input_event)))
return -EFAULT;
@@ -266,37 +394,71 @@ static int evdev_event_to_user(char __user *buffer, const struct input_event *ev
#endif /* CONFIG_COMPAT */
-static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+static ssize_t evdev_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_event event;
- int retval = 0;
+ int retval;
- if (!evdev->exist)
- return -ENODEV;
+ retval = mutex_lock_interruptible(&evdev->mutex);
+ if (retval)
+ return retval;
+
+ if (!evdev->exist) {
+ retval = -ENODEV;
+ goto out;
+ }
while (retval < count) {
- if (evdev_event_from_user(buffer + retval, &event))
- return -EFAULT;
- input_inject_event(&evdev->handle, event.type, event.code, event.value);
+ if (evdev_event_from_user(buffer + retval, &event)) {
+ retval = -EFAULT;
+ goto out;
+ }
+
+ input_inject_event(&evdev->handle,
+ event.type, event.code, event.value);
retval += evdev_event_size();
}
+ out:
+ mutex_unlock(&evdev->mutex);
return retval;
}
-static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+static int evdev_fetch_next_event(struct evdev_client *client,
+ struct input_event *event)
+{
+ int have_event;
+
+ spin_lock_irq(&client->buffer_lock);
+
+ have_event = client->head != client->tail;
+ if (have_event) {
+ *event = client->buffer[client->tail++];
+ client->tail &= EVDEV_BUFFER_SIZE - 1;
+ }
+
+ spin_unlock_irq(&client->buffer_lock);
+
+ return have_event;
+}
+
+static ssize_t evdev_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
+ struct input_event event;
int retval;
if (count < evdev_event_size())
return -EINVAL;
- if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
+ if (client->head == client->tail && evdev->exist &&
+ (file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(evdev->wait,
@@ -307,14 +469,12 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count,
if (!evdev->exist)
return -ENODEV;
- while (client->head != client->tail && retval + evdev_event_size() <= count) {
-
- struct input_event *event = (struct input_event *) client->buffer + client->tail;
+ while (retval + evdev_event_size() <= count &&
+ evdev_fetch_next_event(client, &event)) {
- if (evdev_event_to_user(buffer + retval, event))
+ if (evdev_event_to_user(buffer + retval, &event))
return -EFAULT;
- client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
retval += evdev_event_size();
}
@@ -335,7 +495,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
#ifdef CONFIG_COMPAT
#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
-#define NBITS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1)
+#define BITS_TO_LONGS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1)
#ifdef __BIG_ENDIAN
static int bits_to_user(unsigned long *bits, unsigned int maxbit,
@@ -344,7 +504,7 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit,
int len, i;
if (compat) {
- len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t);
+ len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t);
if (len > maxlen)
len = maxlen;
@@ -355,7 +515,7 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit,
sizeof(compat_long_t)))
return -EFAULT;
} else {
- len = NBITS(maxbit) * sizeof(long);
+ len = BITS_TO_LONGS(maxbit) * sizeof(long);
if (len > maxlen)
len = maxlen;
@@ -370,8 +530,8 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit,
unsigned int maxlen, void __user *p, int compat)
{
int len = compat ?
- NBITS_COMPAT(maxbit) * sizeof(compat_long_t) :
- NBITS(maxbit) * sizeof(long);
+ BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t) :
+ BITS_TO_LONGS(maxbit) * sizeof(long);
if (len > maxlen)
len = maxlen;
@@ -385,7 +545,7 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit,
static int bits_to_user(unsigned long *bits, unsigned int maxbit,
unsigned int maxlen, void __user *p, int compat)
{
- int len = NBITS(maxbit) * sizeof(long);
+ int len = BITS_TO_LONGS(maxbit) * sizeof(long);
if (len > maxlen)
len = maxlen;
@@ -409,8 +569,8 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
return copy_to_user(p, str, len) ? -EFAULT : len;
}
-static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
- void __user *p, int compat_mode)
+static long evdev_do_ioctl(struct file *file, unsigned int cmd,
+ void __user *p, int compat_mode)
{
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
@@ -421,215 +581,289 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
int i, t, u, v;
int error;
- if (!evdev->exist)
- return -ENODEV;
-
switch (cmd) {
- case EVIOCGVERSION:
- return put_user(EV_VERSION, ip);
+ case EVIOCGVERSION:
+ return put_user(EV_VERSION, ip);
- case EVIOCGID:
- if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
- return -EFAULT;
- return 0;
+ case EVIOCGID:
+ if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
+ return -EFAULT;
+ return 0;
- case EVIOCGREP:
- if (!test_bit(EV_REP, dev->evbit))
- return -ENOSYS;
- if (put_user(dev->rep[REP_DELAY], ip))
- return -EFAULT;
- if (put_user(dev->rep[REP_PERIOD], ip + 1))
- return -EFAULT;
- return 0;
+ case EVIOCGREP:
+ if (!test_bit(EV_REP, dev->evbit))
+ return -ENOSYS;
+ if (put_user(dev->rep[REP_DELAY], ip))
+ return -EFAULT;
+ if (put_user(dev->rep[REP_PERIOD], ip + 1))
+ return -EFAULT;
+ return 0;
- case EVIOCSREP:
- if (!test_bit(EV_REP, dev->evbit))
- return -ENOSYS;
- if (get_user(u, ip))
- return -EFAULT;
- if (get_user(v, ip + 1))
- return -EFAULT;
+ case EVIOCSREP:
+ if (!test_bit(EV_REP, dev->evbit))
+ return -ENOSYS;
+ if (get_user(u, ip))
+ return -EFAULT;
+ if (get_user(v, ip + 1))
+ return -EFAULT;
- input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
- input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
+ input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
+ input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
- return 0;
+ return 0;
- case EVIOCGKEYCODE:
- if (get_user(t, ip))
- return -EFAULT;
+ case EVIOCGKEYCODE:
+ if (get_user(t, ip))
+ return -EFAULT;
- error = dev->getkeycode(dev, t, &v);
- if (error)
- return error;
+ error = dev->getkeycode(dev, t, &v);
+ if (error)
+ return error;
- if (put_user(v, ip + 1))
- return -EFAULT;
+ if (put_user(v, ip + 1))
+ return -EFAULT;
- return 0;
+ return 0;
- case EVIOCSKEYCODE:
- if (get_user(t, ip) || get_user(v, ip + 1))
- return -EFAULT;
+ case EVIOCSKEYCODE:
+ if (get_user(t, ip) || get_user(v, ip + 1))
+ return -EFAULT;
- return dev->setkeycode(dev, t, v);
+ return dev->setkeycode(dev, t, v);
- case EVIOCSFF:
- if (copy_from_user(&effect, p, sizeof(effect)))
- return -EFAULT;
+ case EVIOCSFF:
+ if (copy_from_user(&effect, p, sizeof(effect)))
+ return -EFAULT;
- error = input_ff_upload(dev, &effect, file);
+ error = input_ff_upload(dev, &effect, file);
- if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
- return -EFAULT;
+ if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
+ return -EFAULT;
- return error;
+ return error;
- case EVIOCRMFF:
- return input_ff_erase(dev, (int)(unsigned long) p, file);
+ case EVIOCRMFF:
+ return input_ff_erase(dev, (int)(unsigned long) p, file);
- case EVIOCGEFFECTS:
- i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0;
- if (put_user(i, ip))
- return -EFAULT;
- return 0;
-
- case EVIOCGRAB:
- if (p) {
- if (evdev->grab)
- return -EBUSY;
- if (input_grab_device(&evdev->handle))
- return -EBUSY;
- evdev->grab = client;
- return 0;
- } else {
- if (evdev->grab != client)
- return -EINVAL;
- input_release_device(&evdev->handle);
- evdev->grab = NULL;
- return 0;
- }
+ case EVIOCGEFFECTS:
+ i = test_bit(EV_FF, dev->evbit) ?
+ dev->ff->max_effects : 0;
+ if (put_user(i, ip))
+ return -EFAULT;
+ return 0;
+
+ case EVIOCGRAB:
+ if (p)
+ return evdev_grab(evdev, client);
+ else
+ return evdev_ungrab(evdev, client);
- default:
+ default:
- if (_IOC_TYPE(cmd) != 'E')
- return -EINVAL;
+ if (_IOC_TYPE(cmd) != 'E')
+ return -EINVAL;
- if (_IOC_DIR(cmd) == _IOC_READ) {
+ if (_IOC_DIR(cmd) == _IOC_READ) {
- if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+ if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) {
- unsigned long *bits;
- int len;
+ unsigned long *bits;
+ int len;
- switch (_IOC_NR(cmd) & EV_MAX) {
- case 0: bits = dev->evbit; len = EV_MAX; break;
- case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
- case EV_REL: bits = dev->relbit; len = REL_MAX; break;
- case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
- case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
- case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
- case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
- case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
- case EV_SW: bits = dev->swbit; len = SW_MAX; break;
- default: return -EINVAL;
- }
- return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
- }
+ switch (_IOC_NR(cmd) & EV_MAX) {
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
- return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
- p, compat_mode);
+ case 0: bits = dev->evbit; len = EV_MAX; break;
+ case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
+ case EV_REL: bits = dev->relbit; len = REL_MAX; break;
+ case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+ case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
+ case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
+ case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+ case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
+ case EV_SW: bits = dev->swbit; len = SW_MAX; break;
+ default: return -EINVAL;
+ }
+ return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
+ }
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
- return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
- p, compat_mode);
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
+ return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
+ p, compat_mode);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
- return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
- p, compat_mode);
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
+ return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
+ p, compat_mode);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
- return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
- p, compat_mode);
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
+ return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
+ p, compat_mode);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
- return str_to_user(dev->name, _IOC_SIZE(cmd), p);
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
+ return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
+ p, compat_mode);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
- return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
+ return str_to_user(dev->name, _IOC_SIZE(cmd), p);
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
- return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
+ return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
- if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
+ return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
- t = _IOC_NR(cmd) & ABS_MAX;
+ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
- abs.value = dev->abs[t];
- abs.minimum = dev->absmin[t];
- abs.maximum = dev->absmax[t];
- abs.fuzz = dev->absfuzz[t];
- abs.flat = dev->absflat[t];
+ t = _IOC_NR(cmd) & ABS_MAX;
- if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
- return -EFAULT;
+ abs.value = dev->abs[t];
+ abs.minimum = dev->absmin[t];
+ abs.maximum = dev->absmax[t];
+ abs.fuzz = dev->absfuzz[t];
+ abs.flat = dev->absflat[t];
- return 0;
- }
+ if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
+ return -EFAULT;
+ return 0;
}
- if (_IOC_DIR(cmd) == _IOC_WRITE) {
+ }
+
+ if (_IOC_DIR(cmd) == _IOC_WRITE) {
- if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
- t = _IOC_NR(cmd) & ABS_MAX;
+ t = _IOC_NR(cmd) & ABS_MAX;
- if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
- return -EFAULT;
+ if (copy_from_user(&abs, p,
+ sizeof(struct input_absinfo)))
+ return -EFAULT;
- dev->abs[t] = abs.value;
- dev->absmin[t] = abs.minimum;
- dev->absmax[t] = abs.maximum;
- dev->absfuzz[t] = abs.fuzz;
- dev->absflat[t] = abs.flat;
+ /*
+ * Take event lock to ensure that we are not
+ * changing device parameters in the middle
+ * of event.
+ */
+ spin_lock_irq(&dev->event_lock);
- return 0;
- }
+ dev->abs[t] = abs.value;
+ dev->absmin[t] = abs.minimum;
+ dev->absmax[t] = abs.maximum;
+ dev->absfuzz[t] = abs.fuzz;
+ dev->absflat[t] = abs.flat;
+
+ spin_unlock_irq(&dev->event_lock);
+
+ return 0;
}
+ }
}
return -EINVAL;
}
+static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
+ void __user *p, int compat_mode)
+{
+ struct evdev_client *client = file->private_data;
+ struct evdev *evdev = client->evdev;
+ int retval;
+
+ retval = mutex_lock_interruptible(&evdev->mutex);
+ if (retval)
+ return retval;
+
+ if (!evdev->exist) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ retval = evdev_do_ioctl(file, cmd, p, compat_mode);
+
+ out:
+ mutex_unlock(&evdev->mutex);
+ return retval;
+}
+
static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0);
}
#ifdef CONFIG_COMPAT
-static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+static long evdev_ioctl_compat(struct file *file,
+ unsigned int cmd, unsigned long arg)
{
return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1);
}
#endif
static const struct file_operations evdev_fops = {
- .owner = THIS_MODULE,
- .read = evdev_read,
- .write = evdev_write,
- .poll = evdev_poll,
- .open = evdev_open,
- .release = evdev_release,
- .unlocked_ioctl = evdev_ioctl,
+ .owner = THIS_MODULE,
+ .read = evdev_read,
+ .write = evdev_write,
+ .poll = evdev_poll,
+ .open = evdev_open,
+ .release = evdev_release,
+ .unlocked_ioctl = evdev_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = evdev_ioctl_compat,
+ .compat_ioctl = evdev_ioctl_compat,
#endif
- .fasync = evdev_fasync,
- .flush = evdev_flush
+ .fasync = evdev_fasync,
+ .flush = evdev_flush
};
+static int evdev_install_chrdev(struct evdev *evdev)
+{
+ /*
+ * No need to do any locking here as calls to connect and
+ * disconnect are serialized by the input core
+ */
+ evdev_table[evdev->minor] = evdev;
+ return 0;
+}
+
+static void evdev_remove_chrdev(struct evdev *evdev)
+{
+ /*
+ * Lock evdev table to prevent race with evdev_open()
+ */
+ mutex_lock(&evdev_table_mutex);
+ evdev_table[evdev->minor] = NULL;
+ mutex_unlock(&evdev_table_mutex);
+}
+
+/*
+ * Mark device non-existent. This disables writes, ioctls and
+ * prevents new users from opening the device. Already posted
+ * blocking reads will stay, however new ones will fail.
+ */
+static void evdev_mark_dead(struct evdev *evdev)
+{
+ mutex_lock(&evdev->mutex);
+ evdev->exist = 0;
+ mutex_unlock(&evdev->mutex);
+}
+
+static void evdev_cleanup(struct evdev *evdev)
+{
+ struct input_handle *handle = &evdev->handle;
+
+ evdev_mark_dead(evdev);
+ evdev_hangup(evdev);
+ evdev_remove_chrdev(evdev);
+
+ /* evdev is marked dead so no one else accesses evdev->open */
+ if (evdev->open) {
+ input_flush_device(handle, NULL);
+ input_close_device(handle);
+ }
+}
+
+/*
+ * Create new evdev device. Note that input core serializes calls
+ * to connect and disconnect so we don't need to lock evdev_table here.
+ */
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
@@ -637,7 +871,10 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
int minor;
int error;
- for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
+ for (minor = 0; minor < EVDEV_MINORS; minor++)
+ if (!evdev_table[minor])
+ break;
+
if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: no more free evdev devices\n");
return -ENFILE;
@@ -648,38 +885,44 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
return -ENOMEM;
INIT_LIST_HEAD(&evdev->client_list);
+ spin_lock_init(&evdev->client_lock);
+ mutex_init(&evdev->mutex);
init_waitqueue_head(&evdev->wait);
+ snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
evdev->exist = 1;
evdev->minor = minor;
+
evdev->handle.dev = dev;
evdev->handle.name = evdev->name;
evdev->handle.handler = handler;
evdev->handle.private = evdev;
- snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
- snprintf(evdev->dev.bus_id, sizeof(evdev->dev.bus_id),
- "event%d", minor);
+ strlcpy(evdev->dev.bus_id, evdev->name, sizeof(evdev->dev.bus_id));
+ evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
evdev->dev.class = &input_class;
evdev->dev.parent = &dev->dev;
- evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
evdev->dev.release = evdev_free;
device_initialize(&evdev->dev);
- evdev_table[minor] = evdev;
-
- error = device_add(&evdev->dev);
+ error = input_register_handle(&evdev->handle);
if (error)
goto err_free_evdev;
- error = input_register_handle(&evdev->handle);
+ error = evdev_install_chrdev(evdev);
+ if (error)
+ goto err_unregister_handle;
+
+ error = device_add(&evdev->dev);
if (error)
- goto err_delete_evdev;
+ goto err_cleanup_evdev;
return 0;
- err_delete_evdev:
- device_del(&evdev->dev);
+ err_cleanup_evdev:
+ evdev_cleanup(evdev);
+ err_unregister_handle:
+ input_unregister_handle(&evdev->handle);
err_free_evdev:
put_device(&evdev->dev);
return error;
@@ -688,21 +931,10 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
static void evdev_disconnect(struct input_handle *handle)
{
struct evdev *evdev = handle->private;
- struct evdev_client *client;
- input_unregister_handle(handle);
device_del(&evdev->dev);
-
- evdev->exist = 0;
-
- if (evdev->open) {
- input_flush_device(handle, NULL);
- input_close_device(handle);
- list_for_each_entry(client, &evdev->client_list, node)
- kill_fasync(&client->fasync, SIGIO, POLL_HUP);
- wake_up_interruptible(&evdev->wait);
- }
-
+ evdev_cleanup(evdev);
+ input_unregister_handle(handle);
put_device(&evdev->dev);
}
@@ -714,13 +946,13 @@ static const struct input_device_id evdev_ids[] = {
MODULE_DEVICE_TABLE(input, evdev_ids);
static struct input_handler evdev_handler = {
- .event = evdev_event,
- .connect = evdev_connect,
- .disconnect = evdev_disconnect,
- .fops = &evdev_fops,
- .minor = EVDEV_MINOR_BASE,
- .name = "evdev",
- .id_table = evdev_ids,
+ .event = evdev_event,
+ .connect = evdev_connect,
+ .disconnect = evdev_disconnect,
+ .fops = &evdev_fops,
+ .minor = EVDEV_MINOR_BASE,
+ .name = "evdev",
+ .id_table = evdev_ids,
};
static int __init evdev_init(void)
diff --git a/drivers/input/fixp-arith.h b/drivers/input/fixp-arith.h
index ed3d2da0c48..3089d738232 100644
--- a/drivers/input/fixp-arith.h
+++ b/drivers/input/fixp-arith.h
@@ -24,7 +24,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so by
- * e-mail - mail your message to <deneux@ifrance.com>
+ * e-mail - mail your message to <johann.deneux@gmail.com>
*/
#include <linux/types.h>
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 20896d5e5f0..bfc6061f155 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -136,7 +136,8 @@ static int gameport_measure_speed(struct gameport *gameport)
}
gameport_close(gameport);
- return (cpu_data[raw_smp_processor_id()].loops_per_jiffy * (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx);
+ return (cpu_data(raw_smp_processor_id()).loops_per_jiffy *
+ (unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx);
#else
@@ -448,9 +449,8 @@ static int gameport_thread(void *nothing)
set_freezable();
do {
gameport_handle_event();
- wait_event_interruptible(gameport_wait,
+ wait_event_freezable(gameport_wait,
kthread_should_stop() || !list_empty(&gameport_event_list));
- try_to_freeze();
} while (!kthread_should_stop());
printk(KERN_DEBUG "gameport: kgameportd exiting\n");
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index b773d4c756a..92b359894e8 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -70,6 +70,7 @@ static int input_open_polled_device(struct input_dev *input)
{
struct input_polled_dev *dev = input->private;
int error;
+ unsigned long ticks;
error = input_polldev_start_workqueue();
if (error)
@@ -78,8 +79,10 @@ static int input_open_polled_device(struct input_dev *input)
if (dev->flush)
dev->flush(dev);
- queue_delayed_work(polldev_wq, &dev->work,
- msecs_to_jiffies(dev->poll_interval));
+ ticks = msecs_to_jiffies(dev->poll_interval);
+ if (ticks >= HZ)
+ ticks = round_jiffies(ticks);
+ queue_delayed_work(polldev_wq, &dev->work, ticks);
return 0;
}
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 5fe75558662..307c7b5c2b3 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -17,10 +17,10 @@
#include <linux/major.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/device.h>
#include <linux/mutex.h>
+#include <linux/rcupdate.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input core");
@@ -31,167 +31,245 @@ MODULE_LICENSE("GPL");
static LIST_HEAD(input_dev_list);
static LIST_HEAD(input_handler_list);
+/*
+ * input_mutex protects access to both input_dev_list and input_handler_list.
+ * This also causes input_[un]register_device and input_[un]register_handler
+ * be mutually exclusive which simplifies locking in drivers implementing
+ * input handlers.
+ */
+static DEFINE_MUTEX(input_mutex);
+
static struct input_handler *input_table[8];
-/**
- * input_event() - report new input event
- * @dev: device that generated the event
- * @type: type of the event
- * @code: event code
- * @value: value of the event
- *
- * This function should be used by drivers implementing various input devices
- * See also input_inject_event()
- */
-void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+static inline int is_event_supported(unsigned int code,
+ unsigned long *bm, unsigned int max)
{
- struct input_handle *handle;
-
- if (type > EV_MAX || !test_bit(type, dev->evbit))
- return;
+ return code <= max && test_bit(code, bm);
+}
- add_input_randomness(type, code, value);
+static int input_defuzz_abs_event(int value, int old_val, int fuzz)
+{
+ if (fuzz) {
+ if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2)
+ return old_val;
- switch (type) {
+ if (value > old_val - fuzz && value < old_val + fuzz)
+ return (old_val * 3 + value) / 4;
- case EV_SYN:
- switch (code) {
- case SYN_CONFIG:
- if (dev->event)
- dev->event(dev, type, code, value);
- break;
-
- case SYN_REPORT:
- if (dev->sync)
- return;
- dev->sync = 1;
- break;
- }
- break;
+ if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2)
+ return (old_val + value) / 2;
+ }
- case EV_KEY:
+ return value;
+}
- if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
- return;
+/*
+ * Pass event through all open handles. This function is called with
+ * dev->event_lock held and interrupts disabled.
+ */
+static void input_pass_event(struct input_dev *dev,
+ unsigned int type, unsigned int code, int value)
+{
+ struct input_handle *handle;
- if (value == 2)
- break;
+ rcu_read_lock();
- change_bit(code, dev->key);
+ handle = rcu_dereference(dev->grab);
+ if (handle)
+ handle->handler->event(handle, type, code, value);
+ else
+ list_for_each_entry_rcu(handle, &dev->h_list, d_node)
+ if (handle->open)
+ handle->handler->event(handle,
+ type, code, value);
+ rcu_read_unlock();
+}
- if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && dev->timer.data && value) {
- dev->repeat_key = code;
- mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
- }
+/*
+ * Generate software autorepeat event. Note that we take
+ * dev->event_lock here to avoid racing with input_event
+ * which may cause keys get "stuck".
+ */
+static void input_repeat_key(unsigned long data)
+{
+ struct input_dev *dev = (void *) data;
+ unsigned long flags;
- break;
+ spin_lock_irqsave(&dev->event_lock, flags);
- case EV_SW:
+ if (test_bit(dev->repeat_key, dev->key) &&
+ is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
- if (code > SW_MAX || !test_bit(code, dev->swbit) || !!test_bit(code, dev->sw) == value)
- return;
+ input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
- change_bit(code, dev->sw);
+ if (dev->sync) {
+ /*
+ * Only send SYN_REPORT if we are not in a middle
+ * of driver parsing a new hardware packet.
+ * Otherwise assume that the driver will send
+ * SYN_REPORT once it's done.
+ */
+ input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+ }
- break;
+ if (dev->rep[REP_PERIOD])
+ mod_timer(&dev->timer, jiffies +
+ msecs_to_jiffies(dev->rep[REP_PERIOD]));
+ }
- case EV_ABS:
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+}
- if (code > ABS_MAX || !test_bit(code, dev->absbit))
- return;
+static void input_start_autorepeat(struct input_dev *dev, int code)
+{
+ if (test_bit(EV_REP, dev->evbit) &&
+ dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
+ dev->timer.data) {
+ dev->repeat_key = code;
+ mod_timer(&dev->timer,
+ jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
+ }
+}
- if (dev->absfuzz[code]) {
- if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) &&
- (value < dev->abs[code] + (dev->absfuzz[code] >> 1)))
- return;
+#define INPUT_IGNORE_EVENT 0
+#define INPUT_PASS_TO_HANDLERS 1
+#define INPUT_PASS_TO_DEVICE 2
+#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
- if ((value > dev->abs[code] - dev->absfuzz[code]) &&
- (value < dev->abs[code] + dev->absfuzz[code]))
- value = (dev->abs[code] * 3 + value) >> 2;
+static void input_handle_event(struct input_dev *dev,
+ unsigned int type, unsigned int code, int value)
+{
+ int disposition = INPUT_IGNORE_EVENT;
- if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) &&
- (value < dev->abs[code] + (dev->absfuzz[code] << 1)))
- value = (dev->abs[code] + value) >> 1;
- }
+ switch (type) {
- if (dev->abs[code] == value)
- return;
+ case EV_SYN:
+ switch (code) {
+ case SYN_CONFIG:
+ disposition = INPUT_PASS_TO_ALL;
+ break;
- dev->abs[code] = value;
+ case SYN_REPORT:
+ if (!dev->sync) {
+ dev->sync = 1;
+ disposition = INPUT_PASS_TO_HANDLERS;
+ }
break;
+ }
+ break;
- case EV_REL:
+ case EV_KEY:
+ if (is_event_supported(code, dev->keybit, KEY_MAX) &&
+ !!test_bit(code, dev->key) != value) {
- if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0))
- return;
+ if (value != 2) {
+ __change_bit(code, dev->key);
+ if (value)
+ input_start_autorepeat(dev, code);
+ }
- break;
+ disposition = INPUT_PASS_TO_HANDLERS;
+ }
+ break;
- case EV_MSC:
+ case EV_SW:
+ if (is_event_supported(code, dev->swbit, SW_MAX) &&
+ !!test_bit(code, dev->sw) != value) {
- if (code > MSC_MAX || !test_bit(code, dev->mscbit))
- return;
+ __change_bit(code, dev->sw);
+ disposition = INPUT_PASS_TO_HANDLERS;
+ }
+ break;
+
+ case EV_ABS:
+ if (is_event_supported(code, dev->absbit, ABS_MAX)) {
- if (dev->event)
- dev->event(dev, type, code, value);
+ value = input_defuzz_abs_event(value,
+ dev->abs[code], dev->absfuzz[code]);
- break;
+ if (dev->abs[code] != value) {
+ dev->abs[code] = value;
+ disposition = INPUT_PASS_TO_HANDLERS;
+ }
+ }
+ break;
- case EV_LED:
+ case EV_REL:
+ if (is_event_supported(code, dev->relbit, REL_MAX) && value)
+ disposition = INPUT_PASS_TO_HANDLERS;
- if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
- return;
+ break;
- change_bit(code, dev->led);
+ case EV_MSC:
+ if (is_event_supported(code, dev->mscbit, MSC_MAX))
+ disposition = INPUT_PASS_TO_ALL;
- if (dev->event)
- dev->event(dev, type, code, value);
+ break;
- break;
+ case EV_LED:
+ if (is_event_supported(code, dev->ledbit, LED_MAX) &&
+ !!test_bit(code, dev->led) != value) {
- case EV_SND:
+ __change_bit(code, dev->led);
+ disposition = INPUT_PASS_TO_ALL;
+ }
+ break;
- if (code > SND_MAX || !test_bit(code, dev->sndbit))
- return;
+ case EV_SND:
+ if (is_event_supported(code, dev->sndbit, SND_MAX)) {
if (!!test_bit(code, dev->snd) != !!value)
- change_bit(code, dev->snd);
+ __change_bit(code, dev->snd);
+ disposition = INPUT_PASS_TO_ALL;
+ }
+ break;
- if (dev->event)
- dev->event(dev, type, code, value);
+ case EV_REP:
+ if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
+ dev->rep[code] = value;
+ disposition = INPUT_PASS_TO_ALL;
+ }
+ break;
- break;
+ case EV_FF:
+ if (value >= 0)
+ disposition = INPUT_PASS_TO_ALL;
+ break;
+ }
- case EV_REP:
+ if (type != EV_SYN)
+ dev->sync = 0;
- if (code > REP_MAX || value < 0 || dev->rep[code] == value)
- return;
+ if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
+ dev->event(dev, type, code, value);
- dev->rep[code] = value;
- if (dev->event)
- dev->event(dev, type, code, value);
+ if (disposition & INPUT_PASS_TO_HANDLERS)
+ input_pass_event(dev, type, code, value);
+}
- break;
+/**
+ * input_event() - report new input event
+ * @dev: device that generated the event
+ * @type: type of the event
+ * @code: event code
+ * @value: value of the event
+ *
+ * This function should be used by drivers implementing various input
+ * devices. See also input_inject_event().
+ */
- case EV_FF:
+void input_event(struct input_dev *dev,
+ unsigned int type, unsigned int code, int value)
+{
+ unsigned long flags;
- if (value < 0)
- return;
+ if (is_event_supported(type, dev->evbit, EV_MAX)) {
- if (dev->event)
- dev->event(dev, type, code, value);
- break;
+ spin_lock_irqsave(&dev->event_lock, flags);
+ add_input_randomness(type, code, value);
+ input_handle_event(dev, type, code, value);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
}
-
- if (type != EV_SYN)
- dev->sync = 0;
-
- if (dev->grab)
- dev->grab->handler->event(dev->grab, type, code, value);
- else
- list_for_each_entry(handle, &dev->h_list, d_node)
- if (handle->open)
- handle->handler->event(handle, type, code, value);
}
EXPORT_SYMBOL(input_event);
@@ -202,102 +280,228 @@ EXPORT_SYMBOL(input_event);
* @code: event code
* @value: value of the event
*
- * Similar to input_event() but will ignore event if device is "grabbed" and handle
- * injecting event is not the one that owns the device.
+ * Similar to input_event() but will ignore event if device is
+ * "grabbed" and handle injecting event is not the one that owns
+ * the device.
*/
-void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+void input_inject_event(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
{
- if (!handle->dev->grab || handle->dev->grab == handle)
- input_event(handle->dev, type, code, value);
-}
-EXPORT_SYMBOL(input_inject_event);
-
-static void input_repeat_key(unsigned long data)
-{
- struct input_dev *dev = (void *) data;
+ struct input_dev *dev = handle->dev;
+ struct input_handle *grab;
+ unsigned long flags;
- if (!test_bit(dev->repeat_key, dev->key))
- return;
+ if (is_event_supported(type, dev->evbit, EV_MAX)) {
+ spin_lock_irqsave(&dev->event_lock, flags);
- input_event(dev, EV_KEY, dev->repeat_key, 2);
- input_sync(dev);
+ rcu_read_lock();
+ grab = rcu_dereference(dev->grab);
+ if (!grab || grab == handle)
+ input_handle_event(dev, type, code, value);
+ rcu_read_unlock();
- if (dev->rep[REP_PERIOD])
- mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD]));
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
}
+EXPORT_SYMBOL(input_inject_event);
+/**
+ * input_grab_device - grabs device for exclusive use
+ * @handle: input handle that wants to own the device
+ *
+ * When a device is grabbed by an input handle all events generated by
+ * the device are delivered only to this handle. Also events injected
+ * by other input handles are ignored while device is grabbed.
+ */
int input_grab_device(struct input_handle *handle)
{
- if (handle->dev->grab)
- return -EBUSY;
+ struct input_dev *dev = handle->dev;
+ int retval;
- handle->dev->grab = handle;
- return 0;
+ retval = mutex_lock_interruptible(&dev->mutex);
+ if (retval)
+ return retval;
+
+ if (dev->grab) {
+ retval = -EBUSY;
+ goto out;
+ }
+
+ rcu_assign_pointer(dev->grab, handle);
+ synchronize_rcu();
+
+ out:
+ mutex_unlock(&dev->mutex);
+ return retval;
}
EXPORT_SYMBOL(input_grab_device);
-void input_release_device(struct input_handle *handle)
+static void __input_release_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
if (dev->grab == handle) {
- dev->grab = NULL;
+ rcu_assign_pointer(dev->grab, NULL);
+ /* Make sure input_pass_event() notices that grab is gone */
+ synchronize_rcu();
list_for_each_entry(handle, &dev->h_list, d_node)
- if (handle->handler->start)
+ if (handle->open && handle->handler->start)
handle->handler->start(handle);
}
}
+
+/**
+ * input_release_device - release previously grabbed device
+ * @handle: input handle that owns the device
+ *
+ * Releases previously grabbed device so that other input handles can
+ * start receiving input events. Upon release all handlers attached
+ * to the device have their start() method called so they have a change
+ * to synchronize device state with the rest of the system.
+ */
+void input_release_device(struct input_handle *handle)
+{
+ struct input_dev *dev = handle->dev;
+
+ mutex_lock(&dev->mutex);
+ __input_release_device(handle);
+ mutex_unlock(&dev->mutex);
+}
EXPORT_SYMBOL(input_release_device);
+/**
+ * input_open_device - open input device
+ * @handle: handle through which device is being accessed
+ *
+ * This function should be called by input handlers when they
+ * want to start receive events from given input device.
+ */
int input_open_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
- int err;
+ int retval;
- err = mutex_lock_interruptible(&dev->mutex);
- if (err)
- return err;
+ retval = mutex_lock_interruptible(&dev->mutex);
+ if (retval)
+ return retval;
+
+ if (dev->going_away) {
+ retval = -ENODEV;
+ goto out;
+ }
handle->open++;
if (!dev->users++ && dev->open)
- err = dev->open(dev);
-
- if (err)
- handle->open--;
+ retval = dev->open(dev);
+
+ if (retval) {
+ dev->users--;
+ if (!--handle->open) {
+ /*
+ * Make sure we are not delivering any more events
+ * through this handle
+ */
+ synchronize_rcu();
+ }
+ }
+ out:
mutex_unlock(&dev->mutex);
-
- return err;
+ return retval;
}
EXPORT_SYMBOL(input_open_device);
-int input_flush_device(struct input_handle* handle, struct file* file)
+int input_flush_device(struct input_handle *handle, struct file *file)
{
- if (handle->dev->flush)
- return handle->dev->flush(handle->dev, file);
+ struct input_dev *dev = handle->dev;
+ int retval;
- return 0;
+ retval = mutex_lock_interruptible(&dev->mutex);
+ if (retval)
+ return retval;
+
+ if (dev->flush)
+ retval = dev->flush(dev, file);
+
+ mutex_unlock(&dev->mutex);
+ return retval;
}
EXPORT_SYMBOL(input_flush_device);
+/**
+ * input_close_device - close input device
+ * @handle: handle through which device is being accessed
+ *
+ * This function should be called by input handlers when they
+ * want to stop receive events from given input device.
+ */
void input_close_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
- input_release_device(handle);
-
mutex_lock(&dev->mutex);
+ __input_release_device(handle);
+
if (!--dev->users && dev->close)
dev->close(dev);
- handle->open--;
+
+ if (!--handle->open) {
+ /*
+ * synchronize_rcu() makes sure that input_pass_event()
+ * completed and that no more input events are delivered
+ * through this handle
+ */
+ synchronize_rcu();
+ }
mutex_unlock(&dev->mutex);
}
EXPORT_SYMBOL(input_close_device);
+/*
+ * Prepare device for unregistering
+ */
+static void input_disconnect_device(struct input_dev *dev)
+{
+ struct input_handle *handle;
+ int code;
+
+ /*
+ * Mark device as going away. Note that we take dev->mutex here
+ * not to protect access to dev->going_away but rather to ensure
+ * that there are no threads in the middle of input_open_device()
+ */
+ mutex_lock(&dev->mutex);
+ dev->going_away = 1;
+ mutex_unlock(&dev->mutex);
+
+ spin_lock_irq(&dev->event_lock);
+
+ /*
+ * Simulate keyup events for all pressed keys so that handlers
+ * are not left with "stuck" keys. The driver may continue
+ * generate events even after we done here but they will not
+ * reach any handlers.
+ */
+ if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
+ for (code = 0; code <= KEY_MAX; code++) {
+ if (is_event_supported(code, dev->keybit, KEY_MAX) &&
+ test_bit(code, dev->key)) {
+ input_pass_event(dev, EV_KEY, code, 0);
+ }
+ }
+ input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+ }
+
+ list_for_each_entry(handle, &dev->h_list, d_node)
+ handle->open = 0;
+
+ spin_unlock_irq(&dev->event_lock);
+}
+
static int input_fetch_keycode(struct input_dev *dev, int scancode)
{
switch (dev->keycodesize) {
@@ -380,10 +584,10 @@ static int input_default_setkeycode(struct input_dev *dev,
#define MATCH_BIT(bit, max) \
- for (i = 0; i < NBITS(max); i++) \
+ for (i = 0; i < BITS_TO_LONGS(max); i++) \
if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
break; \
- if (i != NBITS(max)) \
+ if (i != BITS_TO_LONGS(max)) \
continue;
static const struct input_device_id *input_match_device(const struct input_device_id *id,
@@ -473,7 +677,8 @@ static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
{
- /* acquire lock here ... Yes, we do need locking, I knowi, I know... */
+ if (mutex_lock_interruptible(&input_mutex))
+ return NULL;
return seq_list_start(&input_dev_list, *pos);
}
@@ -485,7 +690,7 @@ static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void input_devices_seq_stop(struct seq_file *seq, void *v)
{
- /* release lock here */
+ mutex_unlock(&input_mutex);
}
static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
@@ -493,7 +698,7 @@ static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
{
int i;
- for (i = NBITS(max) - 1; i > 0; i--)
+ for (i = BITS_TO_LONGS(max) - 1; i > 0; i--)
if (bitmap[i])
break;
@@ -569,7 +774,9 @@ static const struct file_operations input_devices_fileops = {
static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
{
- /* acquire lock here ... Yes, we do need locking, I knowi, I know... */
+ if (mutex_lock_interruptible(&input_mutex))
+ return NULL;
+
seq->private = (void *)(unsigned long)*pos;
return seq_list_start(&input_handler_list, *pos);
}
@@ -582,7 +789,7 @@ static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void input_handlers_seq_stop(struct seq_file *seq, void *v)
{
- /* release lock here */
+ mutex_unlock(&input_mutex);
}
static int input_handlers_seq_show(struct seq_file *seq, void *v)
@@ -685,7 +892,7 @@ static int input_print_modalias_bits(char *buf, int size,
len += snprintf(buf, max(size, 0), "%c", name);
for (i = min_bit; i < max_bit; i++)
- if (bm[LONG(i)] & BIT(i))
+ if (bm[BIT_WORD(i)] & BIT_MASK(i))
len += snprintf(buf + len, max(size - len, 0), "%X,", i);
return len;
}
@@ -784,7 +991,7 @@ static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap,
int i;
int len = 0;
- for (i = NBITS(max) - 1; i > 0; i--)
+ for (i = BITS_TO_LONGS(max) - 1; i > 0; i--)
if (bitmap[i])
break;
@@ -859,87 +1066,66 @@ static void input_dev_release(struct device *device)
* Input uevent interface - loading event handlers based on
* device bitfields.
*/
-static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index,
- char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
const char *name, unsigned long *bitmap, int max)
{
- if (*cur_index >= num_envp - 1)
- return -ENOMEM;
-
- envp[*cur_index] = buffer + *cur_len;
+ int len;
- *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name);
- if (*cur_len >= buffer_size)
+ if (add_uevent_var(env, "%s=", name))
return -ENOMEM;
- *cur_len += input_print_bitmap(buffer + *cur_len,
- max(buffer_size - *cur_len, 0),
- bitmap, max, 0) + 1;
- if (*cur_len > buffer_size)
+ len = input_print_bitmap(&env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen,
+ bitmap, max, 0);
+ if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
- (*cur_index)++;
+ env->buflen += len;
return 0;
}
-static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_index,
- char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_modalias_var(struct kobj_uevent_env *env,
struct input_dev *dev)
{
- if (*cur_index >= num_envp - 1)
- return -ENOMEM;
-
- envp[*cur_index] = buffer + *cur_len;
+ int len;
- *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0),
- "MODALIAS=");
- if (*cur_len >= buffer_size)
+ if (add_uevent_var(env, "MODALIAS="))
return -ENOMEM;
- *cur_len += input_print_modalias(buffer + *cur_len,
- max(buffer_size - *cur_len, 0),
- dev, 0) + 1;
- if (*cur_len > buffer_size)
+ len = input_print_modalias(&env->buf[env->buflen - 1],
+ sizeof(env->buf) - env->buflen,
+ dev, 0);
+ if (len >= (sizeof(env->buf) - env->buflen))
return -ENOMEM;
- (*cur_index)++;
+ env->buflen += len;
return 0;
}
#define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \
do { \
- int err = add_uevent_var(envp, num_envp, &i, \
- buffer, buffer_size, &len, \
- fmt, val); \
+ int err = add_uevent_var(env, fmt, val); \
if (err) \
return err; \
} while (0)
#define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \
do { \
- int err = input_add_uevent_bm_var(envp, num_envp, &i, \
- buffer, buffer_size, &len, \
- name, bm, max); \
+ int err = input_add_uevent_bm_var(env, name, bm, max); \
if (err) \
return err; \
} while (0)
#define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev) \
do { \
- int err = input_add_uevent_modalias_var(envp, \
- num_envp, &i, \
- buffer, buffer_size, &len, \
- dev); \
+ int err = input_add_uevent_modalias_var(env, dev); \
if (err) \
return err; \
} while (0)
-static int input_dev_uevent(struct device *device, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
{
struct input_dev *dev = to_input_dev(device);
- int i = 0;
- int len = 0;
INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x",
dev->id.bustype, dev->id.vendor,
@@ -971,7 +1157,6 @@ static int input_dev_uevent(struct device *device, char **envp,
INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev);
- envp[i] = NULL;
return 0;
}
@@ -1005,6 +1190,7 @@ struct input_dev *input_allocate_device(void)
dev->dev.class = &input_class;
device_initialize(&dev->dev);
mutex_init(&dev->mutex);
+ spin_lock_init(&dev->event_lock);
INIT_LIST_HEAD(&dev->h_list);
INIT_LIST_HEAD(&dev->node);
@@ -1022,7 +1208,7 @@ EXPORT_SYMBOL(input_allocate_device);
* This function should only be used if input_register_device()
* was not called yet or if it failed. Once device was registered
* use input_unregister_device() and memory will be freed once last
- * refrence to the device is dropped.
+ * reference to the device is dropped.
*
* Device should be allocated by input_allocate_device().
*
@@ -1092,6 +1278,18 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int
}
EXPORT_SYMBOL(input_set_capability);
+/**
+ * input_register_device - register device with input core
+ * @dev: device to be registered
+ *
+ * This function registers device with input core. The device must be
+ * allocated with input_allocate_device() and all it's capabilities
+ * set up before registering.
+ * If function fails the device must be freed with input_free_device().
+ * Once device has been successfully registered it can be unregistered
+ * with input_unregister_device(); input_free_device() should not be
+ * called in this case.
+ */
int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0);
@@ -1099,7 +1297,7 @@ int input_register_device(struct input_dev *dev)
const char *path;
int error;
- set_bit(EV_SYN, dev->evbit);
+ __set_bit(EV_SYN, dev->evbit);
/*
* If delay and period are pre-set by the driver, then autorepeating
@@ -1120,8 +1318,6 @@ int input_register_device(struct input_dev *dev)
if (!dev->setkeycode)
dev->setkeycode = input_default_setkeycode;
- list_add_tail(&dev->node, &input_dev_list);
-
snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
@@ -1137,49 +1333,79 @@ int input_register_device(struct input_dev *dev)
dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
kfree(path);
+ error = mutex_lock_interruptible(&input_mutex);
+ if (error) {
+ device_del(&dev->dev);
+ return error;
+ }
+
+ list_add_tail(&dev->node, &input_dev_list);
+
list_for_each_entry(handler, &input_handler_list, node)
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
+ mutex_unlock(&input_mutex);
+
return 0;
}
EXPORT_SYMBOL(input_register_device);
+/**
+ * input_unregister_device - unregister previously registered device
+ * @dev: device to be unregistered
+ *
+ * This function unregisters an input device. Once device is unregistered
+ * the caller should not try to access it as it may get freed at any moment.
+ */
void input_unregister_device(struct input_dev *dev)
{
struct input_handle *handle, *next;
- int code;
- for (code = 0; code <= KEY_MAX; code++)
- if (test_bit(code, dev->key))
- input_report_key(dev, code, 0);
- input_sync(dev);
+ input_disconnect_device(dev);
- del_timer_sync(&dev->timer);
+ mutex_lock(&input_mutex);
list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
handle->handler->disconnect(handle);
WARN_ON(!list_empty(&dev->h_list));
+ del_timer_sync(&dev->timer);
list_del_init(&dev->node);
- device_unregister(&dev->dev);
-
input_wakeup_procfs_readers();
+
+ mutex_unlock(&input_mutex);
+
+ device_unregister(&dev->dev);
}
EXPORT_SYMBOL(input_unregister_device);
+/**
+ * input_register_handler - register a new input handler
+ * @handler: handler to be registered
+ *
+ * This function registers a new input handler (interface) for input
+ * devices in the system and attaches it to all input devices that
+ * are compatible with the handler.
+ */
int input_register_handler(struct input_handler *handler)
{
struct input_dev *dev;
+ int retval;
+
+ retval = mutex_lock_interruptible(&input_mutex);
+ if (retval)
+ return retval;
INIT_LIST_HEAD(&handler->h_list);
if (handler->fops != NULL) {
- if (input_table[handler->minor >> 5])
- return -EBUSY;
-
+ if (input_table[handler->minor >> 5]) {
+ retval = -EBUSY;
+ goto out;
+ }
input_table[handler->minor >> 5] = handler;
}
@@ -1189,14 +1415,26 @@ int input_register_handler(struct input_handler *handler)
input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
- return 0;
+
+ out:
+ mutex_unlock(&input_mutex);
+ return retval;
}
EXPORT_SYMBOL(input_register_handler);
+/**
+ * input_unregister_handler - unregisters an input handler
+ * @handler: handler to be unregistered
+ *
+ * This function disconnects a handler from its input devices and
+ * removes it from lists of known handlers.
+ */
void input_unregister_handler(struct input_handler *handler)
{
struct input_handle *handle, *next;
+ mutex_lock(&input_mutex);
+
list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
handler->disconnect(handle);
WARN_ON(!list_empty(&handler->h_list));
@@ -1207,14 +1445,45 @@ void input_unregister_handler(struct input_handler *handler)
input_table[handler->minor >> 5] = NULL;
input_wakeup_procfs_readers();
+
+ mutex_unlock(&input_mutex);
}
EXPORT_SYMBOL(input_unregister_handler);
+/**
+ * input_register_handle - register a new input handle
+ * @handle: handle to register
+ *
+ * This function puts a new input handle onto device's
+ * and handler's lists so that events can flow through
+ * it once it is opened using input_open_device().
+ *
+ * This function is supposed to be called from handler's
+ * connect() method.
+ */
int input_register_handle(struct input_handle *handle)
{
struct input_handler *handler = handle->handler;
+ struct input_dev *dev = handle->dev;
+ int error;
- list_add_tail(&handle->d_node, &handle->dev->h_list);
+ /*
+ * We take dev->mutex here to prevent race with
+ * input_release_device().
+ */
+ error = mutex_lock_interruptible(&dev->mutex);
+ if (error)
+ return error;
+ list_add_tail_rcu(&handle->d_node, &dev->h_list);
+ mutex_unlock(&dev->mutex);
+ synchronize_rcu();
+
+ /*
+ * Since we are supposed to be called from ->connect()
+ * which is mutually exclusive with ->disconnect()
+ * we can't be racing with input_unregister_handle()
+ * and so separate lock is not needed here.
+ */
list_add_tail(&handle->h_node, &handler->h_list);
if (handler->start)
@@ -1224,10 +1493,29 @@ int input_register_handle(struct input_handle *handle)
}
EXPORT_SYMBOL(input_register_handle);
+/**
+ * input_unregister_handle - unregister an input handle
+ * @handle: handle to unregister
+ *
+ * This function removes input handle from device's
+ * and handler's lists.
+ *
+ * This function is supposed to be called from handler's
+ * disconnect() method.
+ */
void input_unregister_handle(struct input_handle *handle)
{
+ struct input_dev *dev = handle->dev;
+
list_del_init(&handle->h_node);
- list_del_init(&handle->d_node);
+
+ /*
+ * Take dev->mutex to prevent race with input_release_device().
+ */
+ mutex_lock(&dev->mutex);
+ list_del_rcu(&handle->d_node);
+ mutex_unlock(&dev->mutex);
+ synchronize_rcu();
}
EXPORT_SYMBOL(input_unregister_handle);
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index a9a0180bfd4..22b2789ef58 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -43,6 +43,8 @@ struct joydev {
struct input_handle handle;
wait_queue_head_t wait;
struct list_head client_list;
+ spinlock_t client_lock; /* protects client_list */
+ struct mutex mutex;
struct device dev;
struct js_corr corr[ABS_MAX + 1];
@@ -61,31 +63,61 @@ struct joydev_client {
int head;
int tail;
int startup;
+ spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct fasync_struct *fasync;
struct joydev *joydev;
struct list_head node;
};
static struct joydev *joydev_table[JOYDEV_MINORS];
+static DEFINE_MUTEX(joydev_table_mutex);
static int joydev_correct(int value, struct js_corr *corr)
{
switch (corr->type) {
- case JS_CORR_NONE:
- break;
- case JS_CORR_BROKEN:
- value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
- ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
- ((corr->coef[2] * (value - corr->coef[0])) >> 14);
- break;
- default:
- return 0;
+
+ case JS_CORR_NONE:
+ break;
+
+ case JS_CORR_BROKEN:
+ value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
+ ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
+ ((corr->coef[2] * (value - corr->coef[0])) >> 14);
+ break;
+
+ default:
+ return 0;
}
return value < -32767 ? -32767 : (value > 32767 ? 32767 : value);
}
-static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+static void joydev_pass_event(struct joydev_client *client,
+ struct js_event *event)
+{
+ struct joydev *joydev = client->joydev;
+
+ /*
+ * IRQs already disabled, just acquire the lock
+ */
+ spin_lock(&client->buffer_lock);
+
+ client->buffer[client->head] = *event;
+
+ if (client->startup == joydev->nabs + joydev->nkey) {
+ client->head++;
+ client->head &= JOYDEV_BUFFER_SIZE - 1;
+ if (client->tail == client->head)
+ client->startup = 0;
+ }
+
+ spin_unlock(&client->buffer_lock);
+
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
+}
+
+static void joydev_event(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
{
struct joydev *joydev = handle->private;
struct joydev_client *client;
@@ -93,39 +125,34 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
switch (type) {
- case EV_KEY:
- if (code < BTN_MISC || value == 2)
- return;
- event.type = JS_EVENT_BUTTON;
- event.number = joydev->keymap[code - BTN_MISC];
- event.value = value;
- break;
-
- case EV_ABS:
- event.type = JS_EVENT_AXIS;
- event.number = joydev->absmap[code];
- event.value = joydev_correct(value, joydev->corr + event.number);
- if (event.value == joydev->abs[event.number])
- return;
- joydev->abs[event.number] = event.value;
- break;
+ case EV_KEY:
+ if (code < BTN_MISC || value == 2)
+ return;
+ event.type = JS_EVENT_BUTTON;
+ event.number = joydev->keymap[code - BTN_MISC];
+ event.value = value;
+ break;
- default:
+ case EV_ABS:
+ event.type = JS_EVENT_AXIS;
+ event.number = joydev->absmap[code];
+ event.value = joydev_correct(value,
+ &joydev->corr[event.number]);
+ if (event.value == joydev->abs[event.number])
return;
+ joydev->abs[event.number] = event.value;
+ break;
+
+ default:
+ return;
}
event.time = jiffies_to_msecs(jiffies);
- list_for_each_entry(client, &joydev->client_list, node) {
-
- memcpy(client->buffer + client->head, &event, sizeof(struct js_event));
-
- if (client->startup == joydev->nabs + joydev->nkey)
- if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
- client->startup = 0;
-
- kill_fasync(&client->fasync, SIGIO, POLL_IN);
- }
+ rcu_read_lock();
+ list_for_each_entry_rcu(client, &joydev->client_list, node)
+ joydev_pass_event(client, &event);
+ rcu_read_unlock();
wake_up_interruptible(&joydev->wait);
}
@@ -144,23 +171,83 @@ static void joydev_free(struct device *dev)
{
struct joydev *joydev = container_of(dev, struct joydev, dev);
- joydev_table[joydev->minor] = NULL;
kfree(joydev);
}
+static void joydev_attach_client(struct joydev *joydev,
+ struct joydev_client *client)
+{
+ spin_lock(&joydev->client_lock);
+ list_add_tail_rcu(&client->node, &joydev->client_list);
+ spin_unlock(&joydev->client_lock);
+ synchronize_rcu();
+}
+
+static void joydev_detach_client(struct joydev *joydev,
+ struct joydev_client *client)
+{
+ spin_lock(&joydev->client_lock);
+ list_del_rcu(&client->node);
+ spin_unlock(&joydev->client_lock);
+ synchronize_rcu();
+}
+
+static int joydev_open_device(struct joydev *joydev)
+{
+ int retval;
+
+ retval = mutex_lock_interruptible(&joydev->mutex);
+ if (retval)
+ return retval;
+
+ if (!joydev->exist)
+ retval = -ENODEV;
+ else if (!joydev->open++) {
+ retval = input_open_device(&joydev->handle);
+ if (retval)
+ joydev->open--;
+ }
+
+ mutex_unlock(&joydev->mutex);
+ return retval;
+}
+
+static void joydev_close_device(struct joydev *joydev)
+{
+ mutex_lock(&joydev->mutex);
+
+ if (joydev->exist && !--joydev->open)
+ input_close_device(&joydev->handle);
+
+ mutex_unlock(&joydev->mutex);
+}
+
+/*
+ * Wake up users waiting for IO so they can disconnect from
+ * dead device.
+ */
+static void joydev_hangup(struct joydev *joydev)
+{
+ struct joydev_client *client;
+
+ spin_lock(&joydev->client_lock);
+ list_for_each_entry(client, &joydev->client_list, node)
+ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+ spin_unlock(&joydev->client_lock);
+
+ wake_up_interruptible(&joydev->wait);
+}
+
static int joydev_release(struct inode *inode, struct file *file)
{
struct joydev_client *client = file->private_data;
struct joydev *joydev = client->joydev;
joydev_fasync(-1, file, 0);
-
- list_del(&client->node);
+ joydev_detach_client(joydev, client);
kfree(client);
- if (!--joydev->open && joydev->exist)
- input_close_device(&joydev->handle);
-
+ joydev_close_device(joydev);
put_device(&joydev->dev);
return 0;
@@ -176,11 +263,16 @@ static int joydev_open(struct inode *inode, struct file *file)
if (i >= JOYDEV_MINORS)
return -ENODEV;
+ error = mutex_lock_interruptible(&joydev_table_mutex);
+ if (error)
+ return error;
joydev = joydev_table[i];
- if (!joydev || !joydev->exist)
- return -ENODEV;
+ if (joydev)
+ get_device(&joydev->dev);
+ mutex_unlock(&joydev_table_mutex);
- get_device(&joydev->dev);
+ if (!joydev)
+ return -ENODEV;
client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
if (!client) {
@@ -188,37 +280,129 @@ static int joydev_open(struct inode *inode, struct file *file)
goto err_put_joydev;
}
+ spin_lock_init(&client->buffer_lock);
client->joydev = joydev;
- list_add_tail(&client->node, &joydev->client_list);
+ joydev_attach_client(joydev, client);
- if (!joydev->open++ && joydev->exist) {
- error = input_open_device(&joydev->handle);
- if (error)
- goto err_free_client;
- }
+ error = joydev_open_device(joydev);
+ if (error)
+ goto err_free_client;
file->private_data = client;
return 0;
err_free_client:
- list_del(&client->node);
+ joydev_detach_client(joydev, client);
kfree(client);
err_put_joydev:
put_device(&joydev->dev);
return error;
}
-static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+static int joydev_generate_startup_event(struct joydev_client *client,
+ struct input_dev *input,
+ struct js_event *event)
{
- return -EINVAL;
+ struct joydev *joydev = client->joydev;
+ int have_event;
+
+ spin_lock_irq(&client->buffer_lock);
+
+ have_event = client->startup < joydev->nabs + joydev->nkey;
+
+ if (have_event) {
+
+ event->time = jiffies_to_msecs(jiffies);
+ if (client->startup < joydev->nkey) {
+ event->type = JS_EVENT_BUTTON | JS_EVENT_INIT;
+ event->number = client->startup;
+ event->value = !!test_bit(joydev->keypam[event->number],
+ input->key);
+ } else {
+ event->type = JS_EVENT_AXIS | JS_EVENT_INIT;
+ event->number = client->startup - joydev->nkey;
+ event->value = joydev->abs[event->number];
+ }
+ client->startup++;
+ }
+
+ spin_unlock_irq(&client->buffer_lock);
+
+ return have_event;
+}
+
+static int joydev_fetch_next_event(struct joydev_client *client,
+ struct js_event *event)
+{
+ int have_event;
+
+ spin_lock_irq(&client->buffer_lock);
+
+ have_event = client->head != client->tail;
+ if (have_event) {
+ *event = client->buffer[client->tail++];
+ client->tail &= JOYDEV_BUFFER_SIZE - 1;
+ }
+
+ spin_unlock_irq(&client->buffer_lock);
+
+ return have_event;
+}
+
+/*
+ * Old joystick interface
+ */
+static ssize_t joydev_0x_read(struct joydev_client *client,
+ struct input_dev *input,
+ char __user *buf)
+{
+ struct joydev *joydev = client->joydev;
+ struct JS_DATA_TYPE data;
+ int i;
+
+ spin_lock_irq(&input->event_lock);
+
+ /*
+ * Get device state
+ */
+ for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
+ data.buttons |=
+ test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
+ data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
+ data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
+
+ /*
+ * Reset reader's event queue
+ */
+ spin_lock(&client->buffer_lock);
+ client->startup = 0;
+ client->tail = client->head;
+ spin_unlock(&client->buffer_lock);
+
+ spin_unlock_irq(&input->event_lock);
+
+ if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
+ return -EFAULT;
+
+ return sizeof(struct JS_DATA_TYPE);
+}
+
+static inline int joydev_data_pending(struct joydev_client *client)
+{
+ struct joydev *joydev = client->joydev;
+
+ return client->startup < joydev->nabs + joydev->nkey ||
+ client->head != client->tail;
}
-static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+static ssize_t joydev_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
{
struct joydev_client *client = file->private_data;
struct joydev *joydev = client->joydev;
struct input_dev *input = joydev->handle.dev;
- int retval = 0;
+ struct js_event event;
+ int retval;
if (!joydev->exist)
return -ENODEV;
@@ -226,68 +410,35 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo
if (count < sizeof(struct js_event))
return -EINVAL;
- if (count == sizeof(struct JS_DATA_TYPE)) {
-
- struct JS_DATA_TYPE data;
- int i;
-
- for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
- data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
- data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
- data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
-
- if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
- return -EFAULT;
-
- client->startup = 0;
- client->tail = client->head;
+ if (count == sizeof(struct JS_DATA_TYPE))
+ return joydev_0x_read(client, input, buf);
- return sizeof(struct JS_DATA_TYPE);
- }
-
- if (client->startup == joydev->nabs + joydev->nkey &&
- client->head == client->tail && (file->f_flags & O_NONBLOCK))
+ if (!joydev_data_pending(client) && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(joydev->wait,
- !joydev->exist ||
- client->startup < joydev->nabs + joydev->nkey ||
- client->head != client->tail);
+ !joydev->exist || joydev_data_pending(client));
if (retval)
return retval;
if (!joydev->exist)
return -ENODEV;
- while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
-
- struct js_event event;
-
- event.time = jiffies_to_msecs(jiffies);
-
- if (client->startup < joydev->nkey) {
- event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
- event.number = client->startup;
- event.value = !!test_bit(joydev->keypam[event.number], input->key);
- } else {
- event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
- event.number = client->startup - joydev->nkey;
- event.value = joydev->abs[event.number];
- }
+ while (retval + sizeof(struct js_event) <= count &&
+ joydev_generate_startup_event(client, input, &event)) {
if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
return -EFAULT;
- client->startup++;
retval += sizeof(struct js_event);
}
- while (client->head != client->tail && retval + sizeof(struct js_event) <= count) {
+ while (retval + sizeof(struct js_event) <= count &&
+ joydev_fetch_next_event(client, &event)) {
- if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event)))
+ if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
return -EFAULT;
- client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
retval += sizeof(struct js_event);
}
@@ -301,126 +452,144 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
struct joydev *joydev = client->joydev;
poll_wait(file, &joydev->wait, wait);
- return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ?
- (POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR));
+ return (joydev_data_pending(client) ? (POLLIN | POLLRDNORM) : 0) |
+ (joydev->exist ? 0 : (POLLHUP | POLLERR));
}
-static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
+static int joydev_ioctl_common(struct joydev *joydev,
+ unsigned int cmd, void __user *argp)
{
struct input_dev *dev = joydev->handle.dev;
int i, j;
switch (cmd) {
- case JS_SET_CAL:
- return copy_from_user(&joydev->glue.JS_CORR, argp,
+ case JS_SET_CAL:
+ return copy_from_user(&joydev->glue.JS_CORR, argp,
sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
- case JS_GET_CAL:
- return copy_to_user(argp, &joydev->glue.JS_CORR,
+ case JS_GET_CAL:
+ return copy_to_user(argp, &joydev->glue.JS_CORR,
sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
- case JS_SET_TIMEOUT:
- return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
+ case JS_SET_TIMEOUT:
+ return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
- case JS_GET_TIMEOUT:
- return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
+ case JS_GET_TIMEOUT:
+ return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
- case JSIOCGVERSION:
- return put_user(JS_VERSION, (__u32 __user *) argp);
+ case JSIOCGVERSION:
+ return put_user(JS_VERSION, (__u32 __user *) argp);
- case JSIOCGAXES:
- return put_user(joydev->nabs, (__u8 __user *) argp);
+ case JSIOCGAXES:
+ return put_user(joydev->nabs, (__u8 __user *) argp);
- case JSIOCGBUTTONS:
- return put_user(joydev->nkey, (__u8 __user *) argp);
+ case JSIOCGBUTTONS:
+ return put_user(joydev->nkey, (__u8 __user *) argp);
- case JSIOCSCORR:
- if (copy_from_user(joydev->corr, argp,
- sizeof(joydev->corr[0]) * joydev->nabs))
- return -EFAULT;
- for (i = 0; i < joydev->nabs; i++) {
- j = joydev->abspam[i];
- joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
- }
- return 0;
+ case JSIOCSCORR:
+ if (copy_from_user(joydev->corr, argp,
+ sizeof(joydev->corr[0]) * joydev->nabs))
+ return -EFAULT;
- case JSIOCGCORR:
- return copy_to_user(argp, joydev->corr,
- sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
+ for (i = 0; i < joydev->nabs; i++) {
+ j = joydev->abspam[i];
+ joydev->abs[i] = joydev_correct(dev->abs[j],
+ &joydev->corr[i]);
+ }
+ return 0;
- case JSIOCSAXMAP:
- if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
- return -EFAULT;
- for (i = 0; i < joydev->nabs; i++) {
- if (joydev->abspam[i] > ABS_MAX)
- return -EINVAL;
- joydev->absmap[joydev->abspam[i]] = i;
- }
- return 0;
-
- case JSIOCGAXMAP:
- return copy_to_user(argp, joydev->abspam,
- sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
-
- case JSIOCSBTNMAP:
- if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
+ case JSIOCGCORR:
+ return copy_to_user(argp, joydev->corr,
+ sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
+
+ case JSIOCSAXMAP:
+ if (copy_from_user(joydev->abspam, argp,
+ sizeof(__u8) * (ABS_MAX + 1)))
+ return -EFAULT;
+
+ for (i = 0; i < joydev->nabs; i++) {
+ if (joydev->abspam[i] > ABS_MAX)
+ return -EINVAL;
+ joydev->absmap[joydev->abspam[i]] = i;
+ }
+ return 0;
+
+ case JSIOCGAXMAP:
+ return copy_to_user(argp, joydev->abspam,
+ sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
+
+ case JSIOCSBTNMAP:
+ if (copy_from_user(joydev->keypam, argp,
+ sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
+ return -EFAULT;
+
+ for (i = 0; i < joydev->nkey; i++) {
+ if (joydev->keypam[i] > KEY_MAX ||
+ joydev->keypam[i] < BTN_MISC)
+ return -EINVAL;
+ joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
+ }
+
+ return 0;
+
+ case JSIOCGBTNMAP:
+ return copy_to_user(argp, joydev->keypam,
+ sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
+
+ default:
+ if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) {
+ int len;
+ if (!dev->name)
+ return 0;
+ len = strlen(dev->name) + 1;
+ if (len > _IOC_SIZE(cmd))
+ len = _IOC_SIZE(cmd);
+ if (copy_to_user(argp, dev->name, len))
return -EFAULT;
- for (i = 0; i < joydev->nkey; i++) {
- if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC)
- return -EINVAL;
- joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
- }
- return 0;
-
- case JSIOCGBTNMAP:
- return copy_to_user(argp, joydev->keypam,
- sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
-
- default:
- if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
- int len;
- if (!dev->name)
- return 0;
- len = strlen(dev->name) + 1;
- if (len > _IOC_SIZE(cmd))
- len = _IOC_SIZE(cmd);
- if (copy_to_user(argp, dev->name, len))
- return -EFAULT;
- return len;
- }
+ return len;
+ }
}
return -EINVAL;
}
#ifdef CONFIG_COMPAT
-static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long joydev_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
{
struct joydev_client *client = file->private_data;
struct joydev *joydev = client->joydev;
void __user *argp = (void __user *)arg;
s32 tmp32;
struct JS_DATA_SAVE_TYPE_32 ds32;
- int err;
+ int retval;
- if (!joydev->exist)
- return -ENODEV;
+ retval = mutex_lock_interruptible(&joydev->mutex);
+ if (retval)
+ return retval;
+
+ if (!joydev->exist) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ switch (cmd) {
- switch(cmd) {
case JS_SET_TIMELIMIT:
- err = get_user(tmp32, (s32 __user *) arg);
- if (err == 0)
+ retval = get_user(tmp32, (s32 __user *) arg);
+ if (retval == 0)
joydev->glue.JS_TIMELIMIT = tmp32;
break;
+
case JS_GET_TIMELIMIT:
tmp32 = joydev->glue.JS_TIMELIMIT;
- err = put_user(tmp32, (s32 __user *) arg);
+ retval = put_user(tmp32, (s32 __user *) arg);
break;
case JS_SET_ALL:
- err = copy_from_user(&ds32, argp,
- sizeof(ds32)) ? -EFAULT : 0;
- if (err == 0) {
+ retval = copy_from_user(&ds32, argp,
+ sizeof(ds32)) ? -EFAULT : 0;
+ if (retval == 0) {
joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT;
joydev->glue.BUSY = ds32.BUSY;
joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
@@ -438,55 +607,119 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo
ds32.JS_SAVE = joydev->glue.JS_SAVE;
ds32.JS_CORR = joydev->glue.JS_CORR;
- err = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
+ retval = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
break;
default:
- err = joydev_ioctl_common(joydev, cmd, argp);
+ retval = joydev_ioctl_common(joydev, cmd, argp);
+ break;
}
- return err;
+
+ out:
+ mutex_unlock(&joydev->mutex);
+ return retval;
}
#endif /* CONFIG_COMPAT */
-static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long joydev_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
{
struct joydev_client *client = file->private_data;
struct joydev *joydev = client->joydev;
void __user *argp = (void __user *)arg;
+ int retval;
- if (!joydev->exist)
- return -ENODEV;
+ retval = mutex_lock_interruptible(&joydev->mutex);
+ if (retval)
+ return retval;
+
+ if (!joydev->exist) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ switch (cmd) {
+
+ case JS_SET_TIMELIMIT:
+ retval = get_user(joydev->glue.JS_TIMELIMIT,
+ (long __user *) arg);
+ break;
+
+ case JS_GET_TIMELIMIT:
+ retval = put_user(joydev->glue.JS_TIMELIMIT,
+ (long __user *) arg);
+ break;
+
+ case JS_SET_ALL:
+ retval = copy_from_user(&joydev->glue, argp,
+ sizeof(joydev->glue)) ? -EFAULT: 0;
+ break;
+
+ case JS_GET_ALL:
+ retval = copy_to_user(argp, &joydev->glue,
+ sizeof(joydev->glue)) ? -EFAULT : 0;
+ break;
- switch(cmd) {
- case JS_SET_TIMELIMIT:
- return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
- case JS_GET_TIMELIMIT:
- return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
- case JS_SET_ALL:
- return copy_from_user(&joydev->glue, argp,
- sizeof(joydev->glue)) ? -EFAULT : 0;
- case JS_GET_ALL:
- return copy_to_user(argp, &joydev->glue,
- sizeof(joydev->glue)) ? -EFAULT : 0;
- default:
- return joydev_ioctl_common(joydev, cmd, argp);
+ default:
+ retval = joydev_ioctl_common(joydev, cmd, argp);
+ break;
}
+ out:
+ mutex_unlock(&joydev->mutex);
+ return retval;
}
static const struct file_operations joydev_fops = {
- .owner = THIS_MODULE,
- .read = joydev_read,
- .write = joydev_write,
- .poll = joydev_poll,
- .open = joydev_open,
- .release = joydev_release,
- .ioctl = joydev_ioctl,
+ .owner = THIS_MODULE,
+ .read = joydev_read,
+ .poll = joydev_poll,
+ .open = joydev_open,
+ .release = joydev_release,
+ .unlocked_ioctl = joydev_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = joydev_compat_ioctl,
+ .compat_ioctl = joydev_compat_ioctl,
#endif
- .fasync = joydev_fasync,
+ .fasync = joydev_fasync,
};
+static int joydev_install_chrdev(struct joydev *joydev)
+{
+ joydev_table[joydev->minor] = joydev;
+ return 0;
+}
+
+static void joydev_remove_chrdev(struct joydev *joydev)
+{
+ mutex_lock(&joydev_table_mutex);
+ joydev_table[joydev->minor] = NULL;
+ mutex_unlock(&joydev_table_mutex);
+}
+
+/*
+ * Mark device non-existant. This disables writes, ioctls and
+ * prevents new users from opening the device. Already posted
+ * blocking reads will stay, however new ones will fail.
+ */
+static void joydev_mark_dead(struct joydev *joydev)
+{
+ mutex_lock(&joydev->mutex);
+ joydev->exist = 0;
+ mutex_unlock(&joydev->mutex);
+}
+
+static void joydev_cleanup(struct joydev *joydev)
+{
+ struct input_handle *handle = &joydev->handle;
+
+ joydev_mark_dead(joydev);
+ joydev_hangup(joydev);
+ joydev_remove_chrdev(joydev);
+
+ /* joydev is marked dead so noone else accesses joydev->open */
+ if (joydev->open)
+ input_close_device(handle);
+}
+
static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
const struct input_device_id *id)
{
@@ -494,7 +727,10 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
int i, j, t, minor;
int error;
- for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
+ for (minor = 0; minor < JOYDEV_MINORS; minor++)
+ if (!joydev_table[minor])
+ break;
+
if (minor == JOYDEV_MINORS) {
printk(KERN_ERR "joydev: no more free joydev devices\n");
return -ENFILE;
@@ -505,15 +741,19 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
return -ENOMEM;
INIT_LIST_HEAD(&joydev->client_list);
+ spin_lock_init(&joydev->client_lock);
+ mutex_init(&joydev->mutex);
init_waitqueue_head(&joydev->wait);
+ snprintf(joydev->name, sizeof(joydev->name), "js%d", minor);
+ joydev->exist = 1;
joydev->minor = minor;
+
joydev->exist = 1;
joydev->handle.dev = dev;
joydev->handle.name = joydev->name;
joydev->handle.handler = handler;
joydev->handle.private = joydev;
- snprintf(joydev->name, sizeof(joydev->name), "js%d", minor);
for (i = 0; i < ABS_MAX + 1; i++)
if (test_bit(i, dev->absbit)) {
@@ -545,88 +785,89 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
}
joydev->corr[i].type = JS_CORR_BROKEN;
joydev->corr[i].prec = dev->absfuzz[j];
- joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
- joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
- if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j])))
- continue;
- joydev->corr[i].coef[2] = (1 << 29) / t;
- joydev->corr[i].coef[3] = (1 << 29) / t;
-
- joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
+ joydev->corr[i].coef[0] =
+ (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
+ joydev->corr[i].coef[1] =
+ (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
+
+ t = (dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j];
+ if (t) {
+ joydev->corr[i].coef[2] = (1 << 29) / t;
+ joydev->corr[i].coef[3] = (1 << 29) / t;
+
+ joydev->abs[i] = joydev_correct(dev->abs[j],
+ joydev->corr + i);
+ }
}
- snprintf(joydev->dev.bus_id, sizeof(joydev->dev.bus_id),
- "js%d", minor);
+ strlcpy(joydev->dev.bus_id, joydev->name, sizeof(joydev->dev.bus_id));
+ joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
joydev->dev.class = &input_class;
joydev->dev.parent = &dev->dev;
- joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
joydev->dev.release = joydev_free;
device_initialize(&joydev->dev);
- joydev_table[minor] = joydev;
-
- error = device_add(&joydev->dev);
+ error = input_register_handle(&joydev->handle);
if (error)
goto err_free_joydev;
- error = input_register_handle(&joydev->handle);
+ error = joydev_install_chrdev(joydev);
if (error)
- goto err_delete_joydev;
+ goto err_unregister_handle;
+
+ error = device_add(&joydev->dev);
+ if (error)
+ goto err_cleanup_joydev;
return 0;
- err_delete_joydev:
- device_del(&joydev->dev);
+ err_cleanup_joydev:
+ joydev_cleanup(joydev);
+ err_unregister_handle:
+ input_unregister_handle(&joydev->handle);
err_free_joydev:
put_device(&joydev->dev);
return error;
}
-
static void joydev_disconnect(struct input_handle *handle)
{
struct joydev *joydev = handle->private;
- struct joydev_client *client;
- input_unregister_handle(handle);
device_del(&joydev->dev);
-
- joydev->exist = 0;
-
- if (joydev->open) {
- input_close_device(handle);
- list_for_each_entry(client, &joydev->client_list, node)
- kill_fasync(&client->fasync, SIGIO, POLL_HUP);
- wake_up_interruptible(&joydev->wait);
- }
-
+ joydev_cleanup(joydev);
+ input_unregister_handle(handle);
put_device(&joydev->dev);
}
static const struct input_device_id joydev_blacklist[] = {
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
- .evbit = { BIT(EV_KEY) },
- .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT,
+ .evbit = { BIT_MASK(EV_KEY) },
+ .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
}, /* Avoid itouchpads, touchscreens and tablets */
{ } /* Terminating entry */
};
static const struct input_device_id joydev_ids[] = {
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
- .evbit = { BIT(EV_ABS) },
- .absbit = { BIT(ABS_X) },
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT_MASK(EV_ABS) },
+ .absbit = { BIT_MASK(ABS_X) },
},
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
- .evbit = { BIT(EV_ABS) },
- .absbit = { BIT(ABS_WHEEL) },
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT_MASK(EV_ABS) },
+ .absbit = { BIT_MASK(ABS_WHEEL) },
},
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
- .evbit = { BIT(EV_ABS) },
- .absbit = { BIT(ABS_THROTTLE) },
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT_MASK(EV_ABS) },
+ .absbit = { BIT_MASK(ABS_THROTTLE) },
},
{ } /* Terminating entry */
};
@@ -634,14 +875,14 @@ static const struct input_device_id joydev_ids[] = {
MODULE_DEVICE_TABLE(input, joydev_ids);
static struct input_handler joydev_handler = {
- .event = joydev_event,
- .connect = joydev_connect,
- .disconnect = joydev_disconnect,
- .fops = &joydev_fops,
- .minor = JOYDEV_MINOR_BASE,
- .name = "joydev",
- .id_table = joydev_ids,
- .blacklist = joydev_blacklist,
+ .event = joydev_event,
+ .connect = joydev_connect,
+ .disconnect = joydev_disconnect,
+ .fops = &joydev_fops,
+ .minor = JOYDEV_MINOR_BASE,
+ .name = "joydev",
+ .id_table = joydev_ids,
+ .blacklist = joydev_blacklist,
};
static int __init joydev_init(void)
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index ff701ab10d7..52ba16f487c 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -326,14 +326,19 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv)
a3d->length = 33;
- input_dev->evbit[0] |= BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
- input_dev->relbit[0] |= BIT(REL_X) | BIT(REL_Y);
- input_dev->absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_RUDDER)
- | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) | BIT(ABS_HAT1X) | BIT(ABS_HAT1Y);
- input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE)
- | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
- input_dev->keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP)
- | BIT(BTN_PINKIE);
+ input_dev->evbit[0] |= BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY) |
+ BIT_MASK(EV_REL);
+ input_dev->relbit[0] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+ input_dev->absbit[0] |= BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
+ BIT_MASK(ABS_THROTTLE) | BIT_MASK(ABS_RUDDER) |
+ BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) |
+ BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y);
+ input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_RIGHT) |
+ BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) |
+ BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
+ input_dev->keybit[BIT_WORD(BTN_JOYSTICK)] |=
+ BIT_MASK(BTN_TRIGGER) | BIT_MASK(BTN_THUMB) |
+ BIT_MASK(BTN_TOP) | BIT_MASK(BTN_PINKIE);
a3d_read(a3d, data);
@@ -348,9 +353,10 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv)
} else {
a3d->length = 29;
- input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_REL);
- input_dev->relbit[0] |= BIT(REL_X) | BIT(REL_Y);
- input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
+ input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ input_dev->relbit[0] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+ input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_RIGHT) |
+ BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE);
a3d_read(a3d, data);
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index 28140c4a110..d1ca8a14950 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -431,7 +431,7 @@ static int adi_init_input(struct adi *adi, struct adi_port *port, int half)
input_dev->open = adi_open;
input_dev->close = adi_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++)
set_bit(adi->abs[i], input_dev->absbit);
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index b0f5541ec3e..5cf9f3610e6 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -137,9 +137,10 @@ static int __init amijoy_init(void)
amijoy_dev[i]->open = amijoy_open;
amijoy_dev[i]->close = amijoy_close;
- amijoy_dev[i]->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- amijoy_dev[i]->absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
- amijoy_dev[i]->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ amijoy_dev[i]->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ amijoy_dev[i]->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y);
+ amijoy_dev[i]->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
for (j = 0; j < 2; j++) {
amijoy_dev[i]->absmin[ABS_X + j] = -1;
amijoy_dev[i]->absmax[ABS_X + j] = 1;
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index bdd157c1ebf..15739880afc 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -456,7 +456,7 @@ static int analog_init_device(struct analog_port *port, struct analog *analog, i
input_dev->open = analog_open;
input_dev->close = analog_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
for (i = j = 0; i < 4; i++)
if (analog->mask & (1 << i)) {
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
index d3352a849b8..55646a6d89f 100644
--- a/drivers/input/joystick/cobra.c
+++ b/drivers/input/joystick/cobra.c
@@ -218,7 +218,7 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv)
input_dev->open = cobra_open;
input_dev->close = cobra_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_set_abs_params(input_dev, ABS_X, -1, 1, 0, 0);
input_set_abs_params(input_dev, ABS_Y, -1, 1, 0, 0);
for (j = 0; cobra_btn[j]; j++)
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index b069ee18e35..a6ca9d5e252 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -4,7 +4,7 @@
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Based on the work of:
- * Andree Borrmann Mats Sjövall
+ * Andree Borrmann Mats Sjövall
*/
/*
@@ -631,7 +631,7 @@ static struct db9 __init *db9_probe(int parport, int mode)
input_dev->open = db9_open;
input_dev->close = db9_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
for (j = 0; j < db9_mode->n_buttons; j++)
set_bit(db9_mode->buttons[j], input_dev->keybit);
for (j = 0; j < db9_mode->n_axis; j++) {
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 1a452e0e5f2..df2a9d02ca6 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -653,12 +653,12 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
input_dev->close = gc_close;
if (pad_type != GC_SNESMOUSE) {
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
for (i = 0; i < 2; i++)
input_set_abs_params(input_dev, ABS_X + i, -1, 1, 0, 0);
} else
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
gc->pads[0] |= gc_status_bit[idx];
gc->pads[pad_type] |= gc_status_bit[idx];
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index d514aebf755..1f6302c0eb3 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -315,7 +315,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
input_dev->open = gf2k_open;
input_dev->close = gf2k_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
for (i = 0; i < gf2k_axes[gf2k->id]; i++)
set_bit(gf2k_abs[i], input_dev->absbit);
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
index 73eb5ab6f14..fd3853ab1aa 100644
--- a/drivers/input/joystick/grip.c
+++ b/drivers/input/joystick/grip.c
@@ -370,7 +370,7 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
input_dev->open = grip_open;
input_dev->close = grip_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) {
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 4ed3a3eadf1..c57e21d68c0 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -606,7 +606,7 @@ static int register_slot(int slot, struct grip_mp *grip)
input_dev->open = grip_open;
input_dev->close = grip_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
for (j = 0; (t = grip_abs[port->mode][j]) >= 0; j++)
input_set_abs_params(input_dev, t, -1, 1, 0, 0);
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
index d4e8073caf2..aa6bfb3fb8c 100644
--- a/drivers/input/joystick/guillemot.c
+++ b/drivers/input/joystick/guillemot.c
@@ -238,7 +238,7 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver *
input_dev->open = guillemot_open;
input_dev->close = guillemot_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++)
input_set_abs_params(input_dev, t, 0, 255, 0, 0);
diff --git a/drivers/input/joystick/iforce/Makefile b/drivers/input/joystick/iforce/Makefile
index 17ae42bf9ff..74daff49ab6 100644
--- a/drivers/input/joystick/iforce/Makefile
+++ b/drivers/input/joystick/iforce/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the I-Force driver
#
-# By Johann Deneux <deneux@ifrance.com>
+# By Johann Deneux <johann.deneux@gmail.com>
#
# Goal definition
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 682244b1c04..6f826b37d9a 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -389,7 +389,8 @@ int iforce_init_device(struct iforce *iforce)
* Set input device bitfields and ranges.
*/
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF_STATUS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) |
+ BIT_MASK(EV_FF_STATUS);
for (i = 0; iforce->type->btn[i] >= 0; i++)
set_bit(iforce->type->btn[i], input_dev->keybit);
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
index 40a853ac21c..a964a7cfd21 100644
--- a/drivers/input/joystick/iforce/iforce.h
+++ b/drivers/input/joystick/iforce/iforce.h
@@ -62,13 +62,13 @@
#define FF_CORE_IS_PLAYED 3 /* Effect is currently being played */
#define FF_CORE_SHOULD_PLAY 4 /* User wants the effect to be played */
#define FF_CORE_UPDATE 5 /* Effect is being updated */
-#define FF_MODCORE_MAX 5
+#define FF_MODCORE_CNT 6
struct iforce_core_effect {
/* Information about where modifiers are stored in the device's memory */
struct resource mod1_chunk;
struct resource mod2_chunk;
- unsigned long flags[NBITS(FF_MODCORE_MAX)];
+ unsigned long flags[BITS_TO_LONGS(FF_MODCORE_CNT)];
};
#define FF_CMD_EFFECT 0x010e
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
index 1aec1e9d7c5..bc8ea95dfd0 100644
--- a/drivers/input/joystick/interact.c
+++ b/drivers/input/joystick/interact.c
@@ -269,7 +269,7 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d
input_dev->open = interact_open;
input_dev->close = interact_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) {
set_bit(t, input_dev->absbit);
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
index b35604ee43a..54e676948eb 100644
--- a/drivers/input/joystick/magellan.c
+++ b/drivers/input/joystick/magellan.c
@@ -170,7 +170,7 @@ static int magellan_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
for (i = 0; i < 9; i++)
set_bit(magellan_buttons[i], input_dev->keybit);
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index 2adf73f63c9..7b4865fdee5 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -758,7 +758,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
input_dev->open = sw_open;
input_dev->close = sw_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
for (j = 0; (bits = sw_bit[sw->type][j]); j++) {
code = sw_abs[sw->type][j];
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index abb7c4cf54a..d4087fd4965 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -228,18 +228,23 @@ static int spaceball_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
switch (id) {
case SPACEBALL_4000FLX:
case SPACEBALL_4000FLX_L:
- input_dev->keybit[LONG(BTN_0)] |= BIT(BTN_9);
- input_dev->keybit[LONG(BTN_A)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_MODE);
+ input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_9);
+ input_dev->keybit[BIT_WORD(BTN_A)] |= BIT_MASK(BTN_A) |
+ BIT_MASK(BTN_B) | BIT_MASK(BTN_C) |
+ BIT_MASK(BTN_MODE);
default:
- input_dev->keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4)
- | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7) | BIT(BTN_8);
+ input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_2) |
+ BIT_MASK(BTN_3) | BIT_MASK(BTN_4) |
+ BIT_MASK(BTN_5) | BIT_MASK(BTN_6) |
+ BIT_MASK(BTN_7) | BIT_MASK(BTN_8);
case SPACEBALL_3003C:
- input_dev->keybit[LONG(BTN_0)] |= BIT(BTN_1) | BIT(BTN_8);
+ input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_1) |
+ BIT_MASK(BTN_8);
}
for (i = 0; i < 3; i++) {
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index c4937f1e837..f7ce4004f4b 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -185,7 +185,7 @@ static int spaceorb_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
for (i = 0; i < 6; i++)
set_bit(spaceorb_buttons[i], input_dev->keybit);
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
index 8581ee991d4..baa10b2f7ba 100644
--- a/drivers/input/joystick/stinger.c
+++ b/drivers/input/joystick/stinger.c
@@ -156,10 +156,11 @@ static int stinger_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) |
- BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) |
- BIT(BTN_START) | BIT(BTN_SELECT);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input_dev->keybit[BIT_WORD(BTN_A)] = BIT_MASK(BTN_A) | BIT_MASK(BTN_B) |
+ BIT_MASK(BTN_C) | BIT_MASK(BTN_X) | BIT_MASK(BTN_Y) |
+ BIT_MASK(BTN_Z) | BIT_MASK(BTN_TL) | BIT_MASK(BTN_TR) |
+ BIT_MASK(BTN_START) | BIT_MASK(BTN_SELECT);
input_set_abs_params(input_dev, ABS_X, -64, 64, 0, 4);
input_set_abs_params(input_dev, ABS_Y, -64, 64, 0, 4);
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index 3b36ee04f72..0feeb8acb53 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -333,7 +333,7 @@ static int tmdc_setup_port(struct tmdc *tmdc, int idx, unsigned char *data)
input_dev->open = tmdc_open;
input_dev->close = tmdc_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
for (i = 0; i < port->absc && i < TMDC_ABS; i++)
if (port->abs[i] >= 0)
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index 8381c6f1437..bbebd4e2ad7 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -229,7 +229,7 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
input_dev->open = tgfx_open;
input_dev->close = tgfx_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_set_abs_params(input_dev, ABS_X, -1, 1, 0, 0);
input_set_abs_params(input_dev, ABS_Y, -1, 1, 0, 0);
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
index c91504ec38e..1085c841fec 100644
--- a/drivers/input/joystick/twidjoy.c
+++ b/drivers/input/joystick/twidjoy.c
@@ -207,7 +207,7 @@ static int twidjoy_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_set_abs_params(input_dev, ABS_X, -50, 50, 4, 4);
input_set_abs_params(input_dev, ABS_Y, -50, 50, 4, 4);
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
index 4e85f72eefd..e928b6e3724 100644
--- a/drivers/input/joystick/warrior.c
+++ b/drivers/input/joystick/warrior.c
@@ -162,9 +162,11 @@ static int warrior_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2);
- input_dev->relbit[0] = BIT(REL_DIAL);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) |
+ BIT_MASK(EV_ABS);
+ input_dev->keybit[BIT_WORD(BTN_TRIGGER)] = BIT_MASK(BTN_TRIGGER) |
+ BIT_MASK(BTN_THUMB) | BIT_MASK(BTN_TOP) | BIT_MASK(BTN_TOP2);
+ input_dev->relbit[0] = BIT_MASK(REL_DIAL);
input_set_abs_params(input_dev, ABS_X, -64, 64, 0, 8);
input_set_abs_params(input_dev, ABS_Y, -64, 64, 0, 8);
input_set_abs_params(input_dev, ABS_THROTTLE, -112, 112, 0, 0);
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 28080395899..6e9d75bd2b1 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -120,6 +120,7 @@ static const struct xpad_device {
{ 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+ { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
{ 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
@@ -129,6 +130,7 @@ static const struct xpad_device {
{ 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
+ { 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
{ 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
@@ -223,12 +225,16 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
struct input_dev *dev = xpad->dev;
/* left stick */
- input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12]));
- input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14]));
+ input_report_abs(dev, ABS_X,
+ (__s16) le16_to_cpup((__le16 *)(data + 12)));
+ input_report_abs(dev, ABS_Y,
+ (__s16) le16_to_cpup((__le16 *)(data + 14)));
/* right stick */
- input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16]));
- input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18]));
+ input_report_abs(dev, ABS_RX,
+ (__s16) le16_to_cpup((__le16 *)(data + 16)));
+ input_report_abs(dev, ABS_RY,
+ (__s16) le16_to_cpup((__le16 *)(data + 18)));
/* triggers left/right */
input_report_abs(dev, ABS_Z, data[10]);
@@ -236,8 +242,10 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
/* digital pad */
if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
- input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
- input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
+ input_report_abs(dev, ABS_HAT0X,
+ !!(data[2] & 0x08) - !!(data[2] & 0x04));
+ input_report_abs(dev, ABS_HAT0Y,
+ !!(data[2] & 0x02) - !!(data[2] & 0x01));
} else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
@@ -274,14 +282,17 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
* http://www.free60.org/wiki/Gamepad
*/
-static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
+static void xpad360_process_packet(struct usb_xpad *xpad,
+ u16 cmd, unsigned char *data)
{
struct input_dev *dev = xpad->dev;
/* digital pad */
if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
- input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
- input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
+ input_report_abs(dev, ABS_HAT0X,
+ !!(data[2] & 0x08) - !!(data[2] & 0x04));
+ input_report_abs(dev, ABS_HAT0Y,
+ !!(data[2] & 0x02) - !!(data[2] & 0x01));
} else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) {
/* dpad as buttons (right, left, down, up) */
input_report_key(dev, BTN_LEFT, data[2] & 0x04);
@@ -308,12 +319,16 @@ static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
input_report_key(dev, BTN_MODE, data[3] & 0x04);
/* left stick */
- input_report_abs(dev, ABS_X, (__s16) (((__s16)data[7] << 8) | (__s16)data[6]));
- input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[9] << 8) | (__s16)data[8]));
+ input_report_abs(dev, ABS_X,
+ (__s16) le16_to_cpup((__le16 *)(data + 6)));
+ input_report_abs(dev, ABS_Y,
+ (__s16) le16_to_cpup((__le16 *)(data + 8)));
/* right stick */
- input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[11] << 8) | (__s16)data[10]));
- input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[13] << 8) | (__s16)data[12]));
+ input_report_abs(dev, ABS_RX,
+ (__s16) le16_to_cpup((__le16 *)(data + 10)));
+ input_report_abs(dev, ABS_RY,
+ (__s16) le16_to_cpup((__le16 *)(data + 12)));
/* triggers left/right */
input_report_abs(dev, ABS_Z, data[4]);
@@ -335,10 +350,12 @@ static void xpad_irq_in(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d",
+ __FUNCTION__, urb->status);
goto exit;
}
@@ -367,10 +384,12 @@ static void xpad_irq_out(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d",
+ __FUNCTION__, urb->status);
goto exit;
}
@@ -378,7 +397,7 @@ exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
err("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
+ __FUNCTION__, retval);
}
static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
@@ -595,7 +614,7 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
- struct usb_device *udev = interface_to_usbdev (intf);
+ struct usb_device *udev = interface_to_usbdev(intf);
struct usb_xpad *xpad;
struct input_dev *input_dev;
struct usb_endpoint_descriptor *ep_irq_in;
@@ -641,7 +660,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
input_dev->open = xpad_open;
input_dev->close = xpad_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
/* set up buttons */
for (i = 0; xpad_btn[i] >= 0; i++)
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index c97d5eb0075..2316a018fae 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -208,6 +208,27 @@ config KEYBOARD_HIL
This driver implements support for HIL-keyboards attached
to your machine, so normally you should say Y here.
+config KEYBOARD_HP6XX
+ tristate "HP Jornada 6XX Keyboard support"
+ depends on SH_HP6XX
+ select INPUT_POLLDEV
+ help
+ This adds support for the onboard keyboard found on
+ HP Jornada 620/660/680/690.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jornada680_kbd.
+
+config KEYBOARD_HP7XX
+ tristate "HP Jornada 7XX Keyboard Driver"
+ depends on SA1100_JORNADA720_SSP && SA1100_SSP
+ help
+ Say Y here to add support for the HP Jornada 7xx (710/720/728)
+ onboard keyboard.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jornada720_kbd.
+
config KEYBOARD_OMAP
tristate "TI OMAP keypad support"
depends on (ARCH_OMAP1 || ARCH_OMAP2)
@@ -253,4 +274,23 @@ config KEYBOARD_GPIO
To compile this driver as a module, choose M here: the
module will be called gpio-keys.
+config KEYBOARD_MAPLE
+ tristate "Maple bus keyboard"
+ depends on SH_DREAMCAST && MAPLE
+ help
+ Say Y here if you have a Dreamcast console running Linux and have
+ a keyboard attached to its Maple bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called maple_keyb.
+
+config KEYBOARD_BFIN
+ tristate "Blackfin BF54x keypad support"
+ depends on BF54x
+ help
+ Say Y here if you want to use the BF54x keypad.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bf54x-keys.
+
endif
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 28d211b87b1..e97455fdcc8 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -21,4 +21,7 @@ obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
-
+obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
+obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
+obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
+obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
diff --git a/drivers/input/keyboard/aaed2000_kbd.c b/drivers/input/keyboard/aaed2000_kbd.c
index 63d6ead6b87..72abc196ce6 100644
--- a/drivers/input/keyboard/aaed2000_kbd.c
+++ b/drivers/input/keyboard/aaed2000_kbd.c
@@ -125,7 +125,7 @@ static int __devinit aaedkbd_probe(struct platform_device *pdev)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &pdev->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ 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);
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
index c67e84ec2d6..81bf7562aca 100644
--- a/drivers/input/keyboard/amikbd.c
+++ b/drivers/input/keyboard/amikbd.c
@@ -209,7 +209,7 @@ static int __init amikbd_init(void)
amikbd_dev->id.product = 0x0001;
amikbd_dev->id.version = 0x0100;
- amikbd_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ amikbd_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
for (i = 0; i < 0x78; i++)
set_bit(i, amikbd_dev->keybit);
diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c
index ded1d6ac6ff..4e92100c56a 100644
--- a/drivers/input/keyboard/atakbd.c
+++ b/drivers/input/keyboard/atakbd.c
@@ -55,7 +55,140 @@ MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>");
MODULE_DESCRIPTION("Atari keyboard driver");
MODULE_LICENSE("GPL");
-static unsigned char atakbd_keycode[0x72];
+/*
+ 0x47: KP_7 71
+ 0x48: KP_8 72
+ 0x49: KP_9 73
+ 0x62: KP_/ 98
+ 0x4b: KP_4 75
+ 0x4c: KP_5 76
+ 0x4d: KP_6 77
+ 0x37: KP_* 55
+ 0x4f: KP_1 79
+ 0x50: KP_2 80
+ 0x51: KP_3 81
+ 0x4a: KP_- 74
+ 0x52: KP_0 82
+ 0x53: KP_. 83
+ 0x4e: KP_+ 78
+
+ 0x67: Up 103
+ 0x6c: Down 108
+ 0x69: Left 105
+ 0x6a: Right 106
+ */
+
+
+static unsigned char atakbd_keycode[0x72] = { /* American layout */
+ [0] = KEY_GRAVE,
+ [1] = KEY_ESC,
+ [2] = KEY_1,
+ [3] = KEY_2,
+ [4] = KEY_3,
+ [5] = KEY_4,
+ [6] = KEY_5,
+ [7] = KEY_6,
+ [8] = KEY_7,
+ [9] = KEY_8,
+ [10] = KEY_9,
+ [11] = KEY_0,
+ [12] = KEY_MINUS,
+ [13] = KEY_EQUAL,
+ [14] = KEY_BACKSPACE,
+ [15] = KEY_TAB,
+ [16] = KEY_Q,
+ [17] = KEY_W,
+ [18] = KEY_E,
+ [19] = KEY_R,
+ [20] = KEY_T,
+ [21] = KEY_Y,
+ [22] = KEY_U,
+ [23] = KEY_I,
+ [24] = KEY_O,
+ [25] = KEY_P,
+ [26] = KEY_LEFTBRACE,
+ [27] = KEY_RIGHTBRACE,
+ [28] = KEY_ENTER,
+ [29] = KEY_LEFTCTRL,
+ [30] = KEY_A,
+ [31] = KEY_S,
+ [32] = KEY_D,
+ [33] = KEY_F,
+ [34] = KEY_G,
+ [35] = KEY_H,
+ [36] = KEY_J,
+ [37] = KEY_K,
+ [38] = KEY_L,
+ [39] = KEY_SEMICOLON,
+ [40] = KEY_APOSTROPHE,
+ [41] = KEY_BACKSLASH, /* FIXME, '#' */
+ [42] = KEY_LEFTSHIFT,
+ [43] = KEY_GRAVE, /* FIXME: '~' */
+ [44] = KEY_Z,
+ [45] = KEY_X,
+ [46] = KEY_C,
+ [47] = KEY_V,
+ [48] = KEY_B,
+ [49] = KEY_N,
+ [50] = KEY_M,
+ [51] = KEY_COMMA,
+ [52] = KEY_DOT,
+ [53] = KEY_SLASH,
+ [54] = KEY_RIGHTSHIFT,
+ [55] = KEY_KPASTERISK,
+ [56] = KEY_LEFTALT,
+ [57] = KEY_SPACE,
+ [58] = KEY_CAPSLOCK,
+ [59] = KEY_F1,
+ [60] = KEY_F2,
+ [61] = KEY_F3,
+ [62] = KEY_F4,
+ [63] = KEY_F5,
+ [64] = KEY_F6,
+ [65] = KEY_F7,
+ [66] = KEY_F8,
+ [67] = KEY_F9,
+ [68] = KEY_F10,
+ [69] = KEY_ESC,
+ [70] = KEY_DELETE,
+ [71] = KEY_KP7,
+ [72] = KEY_KP8,
+ [73] = KEY_KP9,
+ [74] = KEY_KPMINUS,
+ [75] = KEY_KP4,
+ [76] = KEY_KP5,
+ [77] = KEY_KP6,
+ [78] = KEY_KPPLUS,
+ [79] = KEY_KP1,
+ [80] = KEY_KP2,
+ [81] = KEY_KP3,
+ [82] = KEY_KP0,
+ [83] = KEY_KPDOT,
+ [90] = KEY_KPLEFTPAREN,
+ [91] = KEY_KPRIGHTPAREN,
+ [92] = KEY_KPASTERISK, /* FIXME */
+ [93] = KEY_KPASTERISK,
+ [94] = KEY_KPPLUS,
+ [95] = KEY_HELP,
+ [96] = KEY_BACKSLASH, /* FIXME: '<' */
+ [97] = KEY_KPASTERISK, /* FIXME */
+ [98] = KEY_KPSLASH,
+ [99] = KEY_KPLEFTPAREN,
+ [100] = KEY_KPRIGHTPAREN,
+ [101] = KEY_KPSLASH,
+ [102] = KEY_KPASTERISK,
+ [103] = KEY_UP,
+ [104] = KEY_KPASTERISK, /* FIXME */
+ [105] = KEY_LEFT,
+ [106] = KEY_RIGHT,
+ [107] = KEY_KPASTERISK, /* FIXME */
+ [108] = KEY_DOWN,
+ [109] = KEY_KPASTERISK, /* FIXME */
+ [110] = KEY_KPASTERISK, /* FIXME */
+ [111] = KEY_KPASTERISK, /* FIXME */
+ [112] = KEY_KPASTERISK, /* FIXME */
+ [113] = KEY_KPASTERISK /* FIXME */
+};
static struct input_dev *atakbd_dev;
@@ -84,43 +217,44 @@ static void atakbd_interrupt(unsigned char scancode, char down)
static int __init atakbd_init(void)
{
- int i;
+ int i, error;
- if (!ATARIHW_PRESENT(ST_MFP))
+ if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
return -EIO;
- // TODO: request_mem_region if not done in arch code
-
- if (!(atakbd_dev = input_allocate_device()))
- return -ENOMEM;
-
// need to init core driver if not already done so
if (atari_keyb_init())
return -ENODEV;
+ atakbd_dev = input_allocate_device();
+ if (!atakbd_dev)
+ return -ENOMEM;
+
atakbd_dev->name = "Atari Keyboard";
atakbd_dev->phys = "atakbd/input0";
- atakbd_dev->id.bustype = BUS_ATARI;
+ atakbd_dev->id.bustype = BUS_HOST;
atakbd_dev->id.vendor = 0x0001;
atakbd_dev->id.product = 0x0001;
atakbd_dev->id.version = 0x0100;
- atakbd_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ atakbd_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
atakbd_dev->keycode = atakbd_keycode;
atakbd_dev->keycodesize = sizeof(unsigned char);
atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode);
for (i = 1; i < 0x72; i++) {
- atakbd_keycode[i] = i;
set_bit(atakbd_keycode[i], atakbd_dev->keybit);
}
- input_register_device(atakbd_dev);
+ /* error check */
+ error = input_register_device(atakbd_dev);
+ if (error) {
+ input_free_device(atakbd_dev);
+ return error;
+ }
atari_input_keyboard_interrupt_hook = atakbd_interrupt;
- printk(KERN_INFO "input: %s at IKBD ACIA\n", atakbd_dev->name);
-
return 0;
}
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 41fc3d03b6e..b39c5b31e62 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -900,27 +900,32 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
input_set_drvdata(input_dev, atkbd);
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
+ BIT_MASK(EV_MSC);
if (atkbd->write) {
- input_dev->evbit[0] |= BIT(EV_LED);
- input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+ input_dev->evbit[0] |= BIT_MASK(EV_LED);
+ input_dev->ledbit[0] = BIT_MASK(LED_NUML) |
+ BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SCROLLL);
}
if (atkbd->extra)
- input_dev->ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) |
- BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
+ input_dev->ledbit[0] |= BIT_MASK(LED_COMPOSE) |
+ BIT_MASK(LED_SUSPEND) | BIT_MASK(LED_SLEEP) |
+ BIT_MASK(LED_MUTE) | BIT_MASK(LED_MISC);
if (!atkbd->softrepeat) {
input_dev->rep[REP_DELAY] = 250;
input_dev->rep[REP_PERIOD] = 33;
}
- input_dev->mscbit[0] = atkbd->softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN);
+ input_dev->mscbit[0] = atkbd->softraw ? BIT_MASK(MSC_SCAN) :
+ BIT_MASK(MSC_RAW) | BIT_MASK(MSC_SCAN);
if (atkbd->scroll) {
- input_dev->evbit[0] |= BIT(EV_REL);
- input_dev->relbit[0] = BIT(REL_WHEEL) | BIT(REL_HWHEEL);
+ input_dev->evbit[0] |= BIT_MASK(EV_REL);
+ input_dev->relbit[0] = BIT_MASK(REL_WHEEL) |
+ BIT_MASK(REL_HWHEEL);
set_bit(BTN_MIDDLE, input_dev->keybit);
}
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c
new file mode 100644
index 00000000000..e5f4da92834
--- /dev/null
+++ b/drivers/input/keyboard/bf54x-keys.c
@@ -0,0 +1,381 @@
+/*
+ * File: drivers/input/keyboard/bf54x-keys.c
+ * Based on:
+ * Author: Michael Hennerich <hennerich@blackfin.uclinux.org>
+ *
+ * Created:
+ * Description: keypad driver for Analog Devices Blackfin BF54x Processors
+ *
+ *
+ * Modified:
+ * Copyright 2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+
+#include <asm/portmux.h>
+#include <asm/mach/bf54x_keys.h>
+
+#define DRV_NAME "bf54x-keys"
+#define TIME_SCALE 100 /* 100 ns */
+#define MAX_MULT (0xFF * TIME_SCALE)
+#define MAX_RC 8 /* Max Row/Col */
+
+static const u16 per_rows[] = {
+ P_KEY_ROW7,
+ P_KEY_ROW6,
+ P_KEY_ROW5,
+ P_KEY_ROW4,
+ P_KEY_ROW3,
+ P_KEY_ROW2,
+ P_KEY_ROW1,
+ P_KEY_ROW0,
+ 0
+};
+
+static const u16 per_cols[] = {
+ P_KEY_COL7,
+ P_KEY_COL6,
+ P_KEY_COL5,
+ P_KEY_COL4,
+ P_KEY_COL3,
+ P_KEY_COL2,
+ P_KEY_COL1,
+ P_KEY_COL0,
+ 0
+};
+
+struct bf54x_kpad {
+ struct input_dev *input;
+ int irq;
+ unsigned short lastkey;
+ unsigned short *keycode;
+ struct timer_list timer;
+ unsigned int keyup_test_jiffies;
+};
+
+static inline int bfin_kpad_find_key(struct bf54x_kpad *bf54x_kpad,
+ struct input_dev *input, u16 keyident)
+{
+ u16 i;
+
+ for (i = 0; i < input->keycodemax; i++)
+ if (bf54x_kpad->keycode[i + input->keycodemax] == keyident)
+ return bf54x_kpad->keycode[i];
+ return -1;
+}
+
+static inline void bfin_keycodecpy(unsigned short *keycode,
+ const unsigned int *pdata_kc,
+ unsigned short keymapsize)
+{
+ unsigned int i;
+
+ for (i = 0; i < keymapsize; i++) {
+ keycode[i] = pdata_kc[i] & 0xffff;
+ keycode[i + keymapsize] = pdata_kc[i] >> 16;
+ }
+}
+
+static inline u16 bfin_kpad_get_prescale(u32 timescale)
+{
+ u32 sclk = get_sclk();
+
+ return ((((sclk / 1000) * timescale) / 1024) - 1);
+}
+
+static inline u16 bfin_kpad_get_keypressed(struct bf54x_kpad *bf54x_kpad)
+{
+ return (bfin_read_KPAD_STAT() & KPAD_PRESSED);
+}
+
+static inline void bfin_kpad_clear_irq(void)
+{
+ bfin_write_KPAD_STAT(0xFFFF);
+ bfin_write_KPAD_ROWCOL(0xFFFF);
+}
+
+static void bfin_kpad_timer(unsigned long data)
+{
+ struct platform_device *pdev = (struct platform_device *) data;
+ struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
+
+ if (bfin_kpad_get_keypressed(bf54x_kpad)) {
+ /* Try again later */
+ mod_timer(&bf54x_kpad->timer,
+ jiffies + bf54x_kpad->keyup_test_jiffies);
+ return;
+ }
+
+ input_report_key(bf54x_kpad->input, bf54x_kpad->lastkey, 0);
+ input_sync(bf54x_kpad->input);
+
+ /* Clear IRQ Status */
+
+ bfin_kpad_clear_irq();
+ enable_irq(bf54x_kpad->irq);
+}
+
+static irqreturn_t bfin_kpad_isr(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
+ struct input_dev *input = bf54x_kpad->input;
+ int key;
+ u16 rowcol = bfin_read_KPAD_ROWCOL();
+
+ key = bfin_kpad_find_key(bf54x_kpad, input, rowcol);
+
+ input_report_key(input, key, 1);
+ input_sync(input);
+
+ if (bfin_kpad_get_keypressed(bf54x_kpad)) {
+ disable_irq(bf54x_kpad->irq);
+ bf54x_kpad->lastkey = key;
+ mod_timer(&bf54x_kpad->timer,
+ jiffies + bf54x_kpad->keyup_test_jiffies);
+ } else {
+ input_report_key(input, key, 0);
+ input_sync(input);
+
+ bfin_kpad_clear_irq();
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit bfin_kpad_probe(struct platform_device *pdev)
+{
+ struct bf54x_kpad *bf54x_kpad;
+ struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data;
+ struct input_dev *input;
+ int i, error;
+
+ if (!pdata->rows || !pdata->cols || !pdata->keymap) {
+ printk(KERN_ERR DRV_NAME
+ ": No rows, cols or keymap from pdata\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->keymapsize ||
+ pdata->keymapsize > (pdata->rows * pdata->cols)) {
+ printk(KERN_ERR DRV_NAME ": Invalid keymapsize\n");
+ return -EINVAL;
+ }
+
+ bf54x_kpad = kzalloc(sizeof(struct bf54x_kpad), GFP_KERNEL);
+ if (!bf54x_kpad)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, bf54x_kpad);
+
+ /* Allocate memory for keymap followed by private LUT */
+ bf54x_kpad->keycode = kmalloc(pdata->keymapsize *
+ sizeof(unsigned short) * 2, GFP_KERNEL);
+ if (!bf54x_kpad->keycode) {
+ error = -ENOMEM;
+ goto out;
+ }
+
+ if (!pdata->debounce_time || !pdata->debounce_time > MAX_MULT ||
+ !pdata->coldrive_time || !pdata->coldrive_time > MAX_MULT) {
+ printk(KERN_ERR DRV_NAME
+ ": Invalid Debounce/Columdrive Time from pdata\n");
+ bfin_write_KPAD_MSEL(0xFF0); /* Default MSEL */
+ } else {
+ bfin_write_KPAD_MSEL(
+ ((pdata->debounce_time / TIME_SCALE)
+ & DBON_SCALE) |
+ (((pdata->coldrive_time / TIME_SCALE) << 8)
+ & COLDRV_SCALE));
+
+ }
+
+ if (!pdata->keyup_test_interval)
+ bf54x_kpad->keyup_test_jiffies = msecs_to_jiffies(50);
+ else
+ bf54x_kpad->keyup_test_jiffies =
+ msecs_to_jiffies(pdata->keyup_test_interval);
+
+ if (peripheral_request_list((u16 *)&per_rows[MAX_RC - pdata->rows],
+ DRV_NAME)) {
+ printk(KERN_ERR DRV_NAME
+ ": Requesting Peripherals failed\n");
+ error = -EFAULT;
+ goto out0;
+ }
+
+ if (peripheral_request_list((u16 *)&per_cols[MAX_RC - pdata->cols],
+ DRV_NAME)) {
+ printk(KERN_ERR DRV_NAME
+ ": Requesting Peripherals failed\n");
+ error = -EFAULT;
+ goto out1;
+ }
+
+ bf54x_kpad->irq = platform_get_irq(pdev, 0);
+ if (bf54x_kpad->irq < 0) {
+ error = -ENODEV;
+ goto out2;
+ }
+
+ error = request_irq(bf54x_kpad->irq, bfin_kpad_isr,
+ IRQF_SAMPLE_RANDOM, DRV_NAME, pdev);
+ if (error) {
+ printk(KERN_ERR DRV_NAME
+ ": unable to claim irq %d; error %d\n",
+ bf54x_kpad->irq, error);
+ goto out2;
+ }
+
+ input = input_allocate_device();
+ if (!input) {
+ error = -ENOMEM;
+ goto out3;
+ }
+
+ bf54x_kpad->input = input;
+
+ input->name = pdev->name;
+ input->phys = "bf54x-keys/input0";
+ input->dev.parent = &pdev->dev;
+
+ input_set_drvdata(input, bf54x_kpad);
+
+ input->id.bustype = BUS_HOST;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0001;
+ input->id.version = 0x0100;
+
+ input->keycodesize = sizeof(unsigned short);
+ input->keycodemax = pdata->keymapsize;
+ input->keycode = bf54x_kpad->keycode;
+
+ bfin_keycodecpy(bf54x_kpad->keycode, pdata->keymap, pdata->keymapsize);
+
+ /* setup input device */
+ __set_bit(EV_KEY, input->evbit);
+
+ if (pdata->repeat)
+ __set_bit(EV_REP, input->evbit);
+
+ for (i = 0; i < input->keycodemax; i++)
+ __set_bit(bf54x_kpad->keycode[i] & KEY_MAX, input->keybit);
+ __clear_bit(KEY_RESERVED, input->keybit);
+
+ error = input_register_device(input);
+ if (error) {
+ printk(KERN_ERR DRV_NAME
+ ": Unable to register input device (%d)\n", error);
+ goto out4;
+ }
+
+ /* Init Keypad Key Up/Release test timer */
+
+ setup_timer(&bf54x_kpad->timer, bfin_kpad_timer, (unsigned long) pdev);
+
+ bfin_write_KPAD_PRESCALE(bfin_kpad_get_prescale(TIME_SCALE));
+
+ bfin_write_KPAD_CTL((((pdata->cols - 1) << 13) & KPAD_COLEN) |
+ (((pdata->rows - 1) << 10) & KPAD_ROWEN) |
+ (2 & KPAD_IRQMODE));
+
+ bfin_write_KPAD_CTL(bfin_read_KPAD_CTL() | KPAD_EN);
+
+ printk(KERN_ERR DRV_NAME
+ ": Blackfin BF54x Keypad registered IRQ %d\n", bf54x_kpad->irq);
+
+ return 0;
+
+out4:
+ input_free_device(input);
+out3:
+ free_irq(bf54x_kpad->irq, pdev);
+out2:
+ peripheral_free_list((u16 *)&per_cols[MAX_RC - pdata->cols]);
+out1:
+ peripheral_free_list((u16 *)&per_rows[MAX_RC - pdata->rows]);
+out0:
+ kfree(bf54x_kpad->keycode);
+out:
+ kfree(bf54x_kpad);
+ platform_set_drvdata(pdev, NULL);
+
+ return error;
+}
+
+static int __devexit bfin_kpad_remove(struct platform_device *pdev)
+{
+ struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data;
+ struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
+
+ del_timer_sync(&bf54x_kpad->timer);
+ free_irq(bf54x_kpad->irq, pdev);
+
+ input_unregister_device(bf54x_kpad->input);
+
+ peripheral_free_list((u16 *)&per_rows[MAX_RC - pdata->rows]);
+ peripheral_free_list((u16 *)&per_cols[MAX_RC - pdata->cols]);
+
+ kfree(bf54x_kpad->keycode);
+ kfree(bf54x_kpad);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+struct platform_driver bfin_kpad_device_driver = {
+ .probe = bfin_kpad_probe,
+ .remove = __devexit_p(bfin_kpad_remove),
+ .driver = {
+ .name = DRV_NAME,
+ }
+};
+
+static int __init bfin_kpad_init(void)
+{
+ return platform_driver_register(&bfin_kpad_device_driver);
+}
+
+static void __exit bfin_kpad_exit(void)
+{
+ platform_driver_unregister(&bfin_kpad_device_driver);
+}
+
+module_init(bfin_kpad_init);
+module_exit(bfin_kpad_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Keypad driver for BF54x Processors");
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 6578bfff644..790fed368aa 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -325,7 +325,8 @@ static int __init corgikbd_probe(struct platform_device *pdev)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &pdev->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
+ BIT_MASK(EV_PWR) | BIT_MASK(EV_SW);
input_dev->keycode = corgikbd->keycode;
input_dev->keycodesize = sizeof(unsigned char);
input_dev->keycodemax = ARRAY_SIZE(corgikbd_keycode);
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index f0b22b8b276..3eddf52a0bb 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -54,6 +54,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
struct input_dev *input;
int i, error;
+ int wakeup = 0;
input = input_allocate_device();
if (!input)
@@ -61,7 +62,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, input);
- input->evbit[0] = BIT(EV_KEY);
+ input->evbit[0] = BIT_MASK(EV_KEY);
input->name = pdev->name;
input->phys = "gpio-keys/input0";
@@ -77,31 +78,51 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
int irq = gpio_to_irq(button->gpio);
unsigned int type = button->type ?: EV_KEY;
- set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
- error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM,
- button->desc ? button->desc : "gpio_keys",
- pdev);
+ if (irq < 0) {
+ error = irq;
+ printk(KERN_ERR
+ "gpio-keys: "
+ "Unable to get irq number for GPIO %d,"
+ "error %d\n",
+ button->gpio, error);
+ goto fail;
+ }
+
+ error = request_irq(irq, gpio_keys_isr,
+ IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ button->desc ? button->desc : "gpio_keys",
+ pdev);
if (error) {
- printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n",
+ printk(KERN_ERR
+ "gpio-keys: Unable to claim irq %d; error %d\n",
irq, error);
goto fail;
}
+ if (button->wakeup)
+ wakeup = 1;
+
input_set_capability(input, type, button->code);
}
error = input_register_device(input);
if (error) {
- printk(KERN_ERR "Unable to register gpio-keys input device\n");
+ printk(KERN_ERR
+ "gpio-keys: Unable to register input device, "
+ "error: %d\n", error);
goto fail;
}
+ device_init_wakeup(&pdev->dev, wakeup);
+
return 0;
fail:
- for (i = i - 1; i >= 0; i--)
+ while (--i >= 0)
free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);
+ platform_set_drvdata(pdev, NULL);
input_free_device(input);
return error;
@@ -113,6 +134,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
struct input_dev *input = platform_get_drvdata(pdev);
int i;
+ device_init_wakeup(&pdev->dev, 0);
+
for (i = 0; i < pdata->nbuttons; i++) {
int irq = gpio_to_irq(pdata->buttons[i].gpio);
free_irq(irq, pdev);
@@ -123,9 +146,53 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
return 0;
}
+
+#ifdef CONFIG_PM
+static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+ int i;
+
+ if (device_may_wakeup(&pdev->dev)) {
+ for (i = 0; i < pdata->nbuttons; i++) {
+ struct gpio_keys_button *button = &pdata->buttons[i];
+ if (button->wakeup) {
+ int irq = gpio_to_irq(button->gpio);
+ enable_irq_wake(irq);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int gpio_keys_resume(struct platform_device *pdev)
+{
+ struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+ int i;
+
+ if (device_may_wakeup(&pdev->dev)) {
+ for (i = 0; i < pdata->nbuttons; i++) {
+ struct gpio_keys_button *button = &pdata->buttons[i];
+ if (button->wakeup) {
+ int irq = gpio_to_irq(button->gpio);
+ disable_irq_wake(irq);
+ }
+ }
+ }
+
+ return 0;
+}
+#else
+#define gpio_keys_suspend NULL
+#define gpio_keys_resume NULL
+#endif
+
struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.remove = __devexit_p(gpio_keys_remove),
+ .suspend = gpio_keys_suspend,
+ .resume = gpio_keys_resume,
.driver = {
.name = "gpio-keys",
}
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index cdd254f2e6c..adbf29f0169 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -323,8 +323,9 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
goto bail2;
}
- kbd->dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
- kbd->dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+ kbd->dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+ kbd->dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
+ BIT_MASK(LED_SCROLLL);
kbd->dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
kbd->dev->keycodesize = sizeof(hil_kbd_set1[0]);
kbd->dev->keycode = hil_kbd_set1;
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index 499b6974457..50d80ecf0b8 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -266,8 +266,9 @@ hil_keyb_init(void)
if (hphilkeyb_keycode[i] != KEY_RESERVED)
set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit);
- hil_dev.dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
- hil_dev.dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+ hil_dev.dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+ hil_dev.dev->ledbit[0] = BIT_MASK(LED_NUML) | BIT_MASK(LED_CAPSL) |
+ BIT_MASK(LED_SCROLLL);
hil_dev.dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
hil_dev.dev->keycodesize= sizeof(hphilkeyb_keycode[0]);
hil_dev.dev->keycode = hphilkeyb_keycode;
diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c
new file mode 100644
index 00000000000..bec1cf48372
--- /dev/null
+++ b/drivers/input/keyboard/jornada680_kbd.c
@@ -0,0 +1,277 @@
+/*
+ * drivers/input/keyboard/jornada680_kbd.c
+ *
+ * HP Jornada 620/660/680/690 scan keyboard platform driver
+ * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
+ *
+ * Based on hp680_keyb.c
+ * Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2005 Andriy Skulysh
+ * Split from drivers/input/keyboard/hp600_keyb.c
+ * Copyright (C) 2000 Yaegashi Takeshi (hp6xx kbd scan routine and translation table)
+ * Copyright (C) 2000 Niibe Yutaka (HP620 Keyb translation table)
+ *
+ * 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.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input-polldev.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <asm/delay.h>
+#include <asm/io.h>
+
+#define PCCR 0xa4000104
+#define PDCR 0xa4000106
+#define PECR 0xa4000108
+#define PFCR 0xa400010a
+#define PCDR 0xa4000124
+#define PDDR 0xa4000126
+#define PEDR 0xa4000128
+#define PFDR 0xa400012a
+#define PGDR 0xa400012c
+#define PHDR 0xa400012e
+#define PJDR 0xa4000130
+#define PKDR 0xa4000132
+#define PLDR 0xa4000134
+
+static const unsigned short jornada_scancodes[] = {
+/* PTD1 */ KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, 0, 0, 0, /* 1 -> 8 */
+ KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F2, KEY_F4, KEY_F5, /* 9 -> 16 */
+/* PTD5 */ KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0, /* 17 -> 24 */
+ KEY_X, KEY_C, KEY_V, KEY_DOT, KEY_COMMA, KEY_M, KEY_B, KEY_N, /* 25 -> 32 */
+/* PTD7 */ KEY_KP2, KEY_KP6, 0, 0, 0, 0, 0, 0, /* 33 -> 40 */
+ 0, 0, 0, KEY_KP4, 0, 0, KEY_LEFTALT, KEY_HANJA, /* 41 -> 48 */
+/* PTE0 */ 0, 0, 0, 0, KEY_FINANCE, 0, 0, 0, /* 49 -> 56 */
+ KEY_LEFTCTRL, 0, KEY_SPACE, KEY_KPDOT, KEY_VOLUMEUP, 249, 0, 0, /* 57 -> 64 */
+/* PTE1 */ KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0, 0, 0,/* 65 -> 72 */
+ KEY_S, KEY_D, KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H, /* 73 -> 80 */
+/* PTE3 */ KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0,0, /* 81 -> 88 */
+ 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 89 -> 96 */
+/* PTE6 */ KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0, 0, /* 97 -> 104 */
+ KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_R, /* 105 -> 112 */
+/* PTE7 */ KEY_0, KEY_MINUS, KEY_EQUAL, 0, KEY_1, 0, 0, 0, /* 113 -> 120 */
+ KEY_2, KEY_3, KEY_4, KEY_9, KEY_8, KEY_7, KEY_5, KEY_6, /* 121 -> 128 */
+/* **** */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0
+};
+
+#define JORNADA_SCAN_SIZE 18
+
+struct jornadakbd {
+ struct input_polled_dev *poll_dev;
+ unsigned short keymap[ARRAY_SIZE(jornada_scancodes)];
+ unsigned char length;
+ unsigned char old_scan[JORNADA_SCAN_SIZE];
+ unsigned char new_scan[JORNADA_SCAN_SIZE];
+};
+
+static void jornada_parse_kbd(struct jornadakbd *jornadakbd)
+{
+ struct input_dev *input_dev = jornadakbd->poll_dev->input;
+ unsigned short *keymap = jornadakbd->keymap;
+ unsigned int sync_me = 0;
+ unsigned int i, j;
+
+ for (i = 0; i < JORNADA_SCAN_SIZE; i++) {
+ unsigned char new = jornadakbd->new_scan[i];
+ unsigned char old = jornadakbd->old_scan[i];
+ unsigned int xor = new ^ old;
+
+ if (xor == 0)
+ continue;
+
+ for (j = 0; j < 8; j++) {
+ unsigned int bit = 1 << j;
+ if (xor & bit) {
+ unsigned int scancode = (i << 3) + j;
+ input_event(input_dev,
+ EV_MSC, MSC_SCAN, scancode);
+ input_report_key(input_dev,
+ keymap[scancode],
+ !(new & bit));
+ sync_me = 1;
+ }
+ }
+ }
+
+ if (sync_me)
+ input_sync(input_dev);
+}
+
+static void jornada_scan_keyb(unsigned char *s)
+{
+ int i;
+ unsigned short ec_static, dc_static; /* = UINT16_t */
+ unsigned char matrix_switch[] = {
+ 0xfd, 0xff, /* PTD1 PD(1) */
+ 0xdf, 0xff, /* PTD5 PD(5) */
+ 0x7f, 0xff, /* PTD7 PD(7) */
+ 0xff, 0xfe, /* PTE0 PE(0) */
+ 0xff, 0xfd, /* PTE1 PE(1) */
+ 0xff, 0xf7, /* PTE3 PE(3) */
+ 0xff, 0xbf, /* PTE6 PE(6) */
+ 0xff, 0x7f, /* PTE7 PE(7) */
+ }, *t = matrix_switch;
+ /* PD(x) :
+ 1. 0xcc0c & (1~(1 << (2*(x)+1)))))
+ 2. (0xf0cf & 0xfffff) */
+ /* PE(x) :
+ 1. 0xcc0c & 0xffff
+ 2. 0xf0cf & (1~(1 << (2*(x)+1))))) */
+ unsigned short matrix_PDE[] = {
+ 0xcc04, 0xf0cf, /* PD(1) */
+ 0xc40c, 0xf0cf, /* PD(5) */
+ 0x4c0c, 0xf0cf, /* PD(7) */
+ 0xcc0c, 0xf0cd, /* PE(0) */
+ 0xcc0c, 0xf0c7, /* PE(1) */
+ 0xcc0c, 0xf04f, /* PE(3) */
+ 0xcc0c, 0xd0cf, /* PE(6) */
+ 0xcc0c, 0x70cf, /* PE(7) */
+ }, *y = matrix_PDE;
+
+ /* Save these control reg bits */
+ dc_static = (ctrl_inw(PDCR) & (~0xcc0c));
+ ec_static = (ctrl_inw(PECR) & (~0xf0cf));
+
+ for (i = 0; i < 8; i++) {
+ /* disable output for all but the one we want to scan */
+ ctrl_outw((dc_static | *y++), PDCR);
+ ctrl_outw((ec_static | *y++), PECR);
+ udelay(5);
+
+ /* Get scanline row */
+ ctrl_outb(*t++, PDDR);
+ ctrl_outb(*t++, PEDR);
+ udelay(50);
+
+ /* Read data */
+ *s++ = ctrl_inb(PCDR);
+ *s++ = ctrl_inb(PFDR);
+ }
+ /* Scan no lines */
+ ctrl_outb(0xff, PDDR);
+ ctrl_outb(0xff, PEDR);
+
+ /* Enable all scanlines */
+ ctrl_outw((dc_static | (0x5555 & 0xcc0c)),PDCR);
+ ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR);
+
+ /* Ignore extra keys and events */
+ *s++ = ctrl_inb(PGDR);
+ *s++ = ctrl_inb(PHDR);
+}
+
+static void jornadakbd680_poll(struct input_polled_dev *dev)
+{
+ struct jornadakbd *jornadakbd = dev->private;
+
+ jornada_scan_keyb(jornadakbd->new_scan);
+ jornada_parse_kbd(jornadakbd);
+ memcpy(jornadakbd->old_scan, jornadakbd->new_scan, JORNADA_SCAN_SIZE);
+}
+
+static int __devinit jornada680kbd_probe(struct platform_device *pdev)
+{
+ struct jornadakbd *jornadakbd;
+ struct input_polled_dev *poll_dev;
+ struct input_dev *input_dev;
+ int i, error;
+
+ jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
+ if (!jornadakbd)
+ return -ENOMEM;
+
+ poll_dev = input_allocate_polled_device();
+ if (!poll_dev) {
+ error = -ENOMEM;
+ goto failed;
+ }
+
+ platform_set_drvdata(pdev, jornadakbd);
+
+ jornadakbd->poll_dev = poll_dev;
+
+ memcpy(jornadakbd->keymap, jornada_scancodes,
+ sizeof(jornadakbd->keymap));
+
+ poll_dev->private = jornadakbd;
+ poll_dev->poll = jornadakbd680_poll;
+ poll_dev->poll_interval = 50; /* msec */
+
+ input_dev = poll_dev->input;
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ input_dev->name = "HP Jornada 680 keyboard";
+ input_dev->phys = "jornadakbd/input0";
+ input_dev->keycode = jornadakbd->keymap;
+ input_dev->keycodesize = sizeof(unsigned short);
+ input_dev->keycodemax = ARRAY_SIZE(jornada_scancodes);
+ input_dev->dev.parent = &pdev->dev;
+ input_dev->id.bustype = BUS_HOST;
+
+ for (i = 0; i < 128; i++)
+ if (jornadakbd->keymap[i])
+ __set_bit(jornadakbd->keymap[i], input_dev->keybit);
+ __clear_bit(KEY_RESERVED, input_dev->keybit);
+
+ input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+ error = input_register_polled_device(jornadakbd->poll_dev);
+ if (error)
+ goto failed;
+
+ return 0;
+
+ failed:
+ printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n",
+ error);
+ platform_set_drvdata(pdev, NULL);
+ input_free_polled_device(poll_dev);
+ kfree(jornadakbd);
+ return error;
+
+}
+
+static int __devexit jornada680kbd_remove(struct platform_device *pdev)
+{
+ struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ input_unregister_polled_device(jornadakbd->poll_dev);
+ input_free_polled_device(jornadakbd->poll_dev);
+ kfree(jornadakbd);
+
+ return 0;
+}
+
+static struct platform_driver jornada680kbd_driver = {
+ .driver = {
+ .name = "jornada680_kbd",
+ },
+ .probe = jornada680kbd_probe,
+ .remove = __devexit_p(jornada680kbd_remove),
+};
+
+static int __init jornada680kbd_init(void)
+{
+ return platform_driver_register(&jornada680kbd_driver);
+}
+
+static void __exit jornada680kbd_exit(void)
+{
+ platform_driver_unregister(&jornada680kbd_driver);
+}
+
+module_init(jornada680kbd_init);
+module_exit(jornada680kbd_exit);
+
+MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c
new file mode 100644
index 00000000000..e6696b3c941
--- /dev/null
+++ b/drivers/input/keyboard/jornada720_kbd.c
@@ -0,0 +1,185 @@
+/*
+ * drivers/input/keyboard/jornada720_kbd.c
+ *
+ * HP Jornada 720 keyboard platform driver
+ *
+ * Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@Gmail.com>
+ *
+ * Copyright (C) 2006 jornada 720 kbd driver by
+ Filip Zyzniewsk <Filip.Zyzniewski@tefnet.plX
+ * based on (C) 2004 jornada 720 kbd driver by
+ Alex Lange <chicken@handhelds.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/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/jornada720.h>
+#include <asm/hardware.h>
+
+MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver");
+MODULE_LICENSE("GPLv2");
+
+static unsigned short jornada_std_keymap[128] = { /* ROW */
+ 0, KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, /* #1 */
+ KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, /* -> */
+ 0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, /* #2 */
+ KEY_0, KEY_MINUS, KEY_EQUAL,0, 0, 0, /* -> */
+ 0, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, /* #3 */
+ KEY_P, KEY_BACKSLASH, KEY_BACKSPACE, 0, 0, 0, /* -> */
+ 0, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, /* #4 */
+ KEY_SEMICOLON, KEY_LEFTBRACE, KEY_RIGHTBRACE, 0, 0, 0, /* -> */
+ 0, KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, KEY_COMMA, /* #5 */
+ KEY_DOT, KEY_KPMINUS, KEY_APOSTROPHE, KEY_ENTER, 0, 0,0, /* -> */
+ 0, KEY_TAB, 0, KEY_LEFTSHIFT, 0, KEY_APOSTROPHE, 0, 0, 0, 0, /* #6 */
+ KEY_UP, 0, KEY_RIGHTSHIFT, 0, 0, 0,0, 0, 0, 0, 0, KEY_LEFTALT, KEY_GRAVE, /* -> */
+ 0, 0, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0,0, KEY_KPASTERISK, /* -> */
+ KEY_LEFTCTRL, 0, KEY_SPACE, 0, 0, 0, KEY_SLASH, KEY_DELETE, 0, 0, /* -> */
+ 0, 0, 0, KEY_POWER, /* -> */
+};
+
+struct jornadakbd {
+ unsigned short keymap[ARRAY_SIZE(jornada_std_keymap)];
+ struct input_dev *input;
+};
+
+static irqreturn_t jornada720_kbd_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
+ struct input_dev *input = jornadakbd->input;
+ u8 count, kbd_data, scan_code;
+
+ /* startup ssp with spinlock */
+ jornada_ssp_start();
+
+ if (jornada_ssp_inout(GETSCANKEYCODE) != TXDUMMY) {
+ printk(KERN_DEBUG
+ "jornada720_kbd: "
+ "GetKeycode command failed with ETIMEDOUT, "
+ "flushed bus\n");
+ } else {
+ /* How many keycodes are waiting for us? */
+ count = jornada_ssp_byte(TXDUMMY);
+
+ /* Lets drag them out one at a time */
+ while (count--) {
+ /* Exchange TxDummy for location (keymap[kbddata]) */
+ kbd_data = jornada_ssp_byte(TXDUMMY);
+ scan_code = kbd_data & 0x7f;
+
+ input_event(input, EV_MSC, MSC_SCAN, scan_code);
+ input_report_key(input, jornadakbd->keymap[scan_code],
+ !(kbd_data & 0x80));
+ input_sync(input);
+ }
+ }
+
+ /* release spinlock and turn off ssp */
+ jornada_ssp_end();
+
+ return IRQ_HANDLED;
+};
+
+static int __devinit jornada720_kbd_probe(struct platform_device *pdev)
+{
+ struct jornadakbd *jornadakbd;
+ struct input_dev *input_dev;
+ int i, err;
+
+ jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!jornadakbd || !input_dev) {
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ platform_set_drvdata(pdev, jornadakbd);
+
+ memcpy(jornadakbd->keymap, jornada_std_keymap,
+ sizeof(jornada_std_keymap));
+ jornadakbd->input = input_dev;
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ input_dev->name = "HP Jornada 720 keyboard";
+ input_dev->phys = "jornadakbd/input0";
+ input_dev->keycode = jornadakbd->keymap;
+ input_dev->keycodesize = sizeof(unsigned short);
+ input_dev->keycodemax = ARRAY_SIZE(jornada_std_keymap);
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->dev.parent = &pdev->dev;
+
+ for (i = 0; i < ARRAY_SIZE(jornadakbd->keymap); i++)
+ __set_bit(jornadakbd->keymap[i], input_dev->keybit);
+ __clear_bit(KEY_RESERVED, input_dev->keybit);
+
+ input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+ err = request_irq(IRQ_GPIO0,
+ jornada720_kbd_interrupt,
+ IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+ "jornadakbd", pdev);
+ if (err) {
+ printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n");
+ goto fail1;
+ }
+
+ err = input_register_device(jornadakbd->input);
+ if (err)
+ goto fail2;
+
+ return 0;
+
+ fail2: /* IRQ, DEVICE, MEMORY */
+ free_irq(IRQ_GPIO0, pdev);
+ fail1: /* DEVICE, MEMORY */
+ platform_set_drvdata(pdev, NULL);
+ input_free_device(input_dev);
+ kfree(jornadakbd);
+ return err;
+};
+
+static int __devexit jornada720_kbd_remove(struct platform_device *pdev)
+{
+ struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
+
+ free_irq(IRQ_GPIO0, pdev);
+ platform_set_drvdata(pdev, NULL);
+ input_unregister_device(jornadakbd->input);
+ kfree(jornadakbd);
+
+ return 0;
+}
+
+static struct platform_driver jornada720_kbd_driver = {
+ .driver = {
+ .name = "jornada720_kbd",
+ },
+ .probe = jornada720_kbd_probe,
+ .remove = __devexit_p(jornada720_kbd_remove),
+};
+
+static int __init jornada720_kbd_init(void)
+{
+ return platform_driver_register(&jornada720_kbd_driver);
+}
+
+static void __exit jornada720_kbd_exit(void)
+{
+ platform_driver_unregister(&jornada720_kbd_driver);
+}
+
+module_init(jornada720_kbd_init);
+module_exit(jornada720_kbd_exit);
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index 7a41b271f22..5a0ca18d675 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -233,7 +233,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &dev->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_dev->keycode = locomokbd->keycode;
input_dev->keycodesize = sizeof(unsigned char);
input_dev->keycodemax = ARRAY_SIZE(locomokbd_keycode);
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c
new file mode 100644
index 00000000000..2b404284c28
--- /dev/null
+++ b/drivers/input/keyboard/maple_keyb.c
@@ -0,0 +1,252 @@
+/*
+ * SEGA Dreamcast keyboard driver
+ * Based on drivers/usb/usbkbd.c
+ * Copyright YAEGASHI Takeshi, 2001
+ * Porting to 2.6 Copyright Adrian McMenamin, 2007
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/maple.h>
+#include <asm/mach/maple.h>
+
+/* Very simple mutex to ensure proper cleanup */
+static DEFINE_MUTEX(maple_keyb_mutex);
+
+#define NR_SCANCODES 256
+
+MODULE_AUTHOR("YAEGASHI Takeshi, Adrian McMenamin");
+MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver");
+MODULE_LICENSE("GPL");
+
+struct dc_kbd {
+ struct input_dev *dev;
+ unsigned short keycode[NR_SCANCODES];
+ unsigned char new[8];
+ unsigned char old[8];
+};
+
+static const unsigned short dc_kbd_keycode[NR_SCANCODES] = {
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, KEY_B, KEY_C, KEY_D,
+ KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L,
+ KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
+ KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2,
+ KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
+ KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE,
+ KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA,
+ KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6,
+ KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_SYSRQ,
+ KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP, KEY_DELETE,
+ KEY_END, KEY_PAGEDOWN, KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP,
+ KEY_NUMLOCK, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPENTER, KEY_KP1, KEY_KP2,
+ KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT,
+ KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, KEY_F14, KEY_F15,
+ KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20,
+ KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT,
+ KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE,
+ KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_KPCOMMA, KEY_RESERVED, KEY_RO, KEY_KATAKANAHIRAGANA , KEY_YEN,
+ KEY_HENKAN, KEY_MUHENKAN, KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, KEY_ZENKAKUHANKAKU, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
+ KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA,
+ KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG, KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE,
+ KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP,
+ KEY_SCREENLOCK, KEY_REFRESH, KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED
+};
+
+static void dc_scan_kbd(struct dc_kbd *kbd)
+{
+ struct input_dev *dev = kbd->dev;
+ void *ptr;
+ int code, keycode;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ code = i + 224;
+ keycode = kbd->keycode[code];
+ input_event(dev, EV_MSC, MSC_SCAN, code);
+ input_report_key(dev, keycode, (kbd->new[0] >> i) & 1);
+ }
+
+ for (i = 2; i < 8; i++) {
+ ptr = memchr(kbd->new + 2, kbd->old[i], 6);
+ code = kbd->old[i];
+ if (code > 3 && ptr == NULL) {
+ keycode = kbd->keycode[code];
+ if (keycode) {
+ input_event(dev, EV_MSC, MSC_SCAN, code);
+ input_report_key(dev, keycode, 0);
+ } else
+ printk(KERN_DEBUG "maple_keyb: "
+ "Unknown key (scancode %#x) released.",
+ code);
+ }
+ ptr = memchr(kbd->old + 2, kbd->new[i], 6);
+ code = kbd->new[i];
+ if (code > 3 && ptr) {
+ keycode = kbd->keycode[code];
+ if (keycode) {
+ input_event(dev, EV_MSC, MSC_SCAN, code);
+ input_report_key(dev, keycode, 1);
+ } else
+ printk(KERN_DEBUG "maple_keyb: "
+ "Unknown key (scancode %#x) pressed.",
+ code);
+ }
+ }
+ input_sync(dev);
+ memcpy(kbd->old, kbd->new, 8);
+}
+
+static void dc_kbd_callback(struct mapleq *mq)
+{
+ struct maple_device *mapledev = mq->dev;
+ struct dc_kbd *kbd = mapledev->private_data;
+ unsigned long *buf = mq->recvbuf;
+
+ /*
+ * We should always be getting the lock because the only
+ * time it may be locked if driver is in cleanup phase.
+ */
+ if (likely(mutex_trylock(&maple_keyb_mutex))) {
+
+ if (buf[1] == mapledev->function) {
+ memcpy(kbd->new, buf + 2, 8);
+ dc_scan_kbd(kbd);
+ }
+
+ mutex_unlock(&maple_keyb_mutex);
+ }
+}
+
+static int dc_kbd_connect(struct maple_device *mdev)
+{
+ int i, error;
+ struct dc_kbd *kbd;
+ struct input_dev *dev;
+
+ if (!(mdev->function & MAPLE_FUNC_KEYBOARD))
+ return -EINVAL;
+
+ kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL);
+ dev = input_allocate_device();
+ if (!kbd || !dev) {
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ mdev->private_data = kbd;
+
+ kbd->dev = dev;
+ memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode));
+
+ dev->name = mdev->product_name;
+ dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ dev->keycode = kbd->keycode;
+ dev->keycodesize = sizeof (unsigned short);
+ dev->keycodemax = ARRAY_SIZE(kbd->keycode);
+ dev->id.bustype = BUS_HOST;
+ dev->dev.parent = &mdev->dev;
+
+ for (i = 0; i < NR_SCANCODES; i++)
+ __set_bit(dc_kbd_keycode[i], dev->keybit);
+ __clear_bit(KEY_RESERVED, dev->keybit);
+
+ input_set_capability(dev, EV_MSC, MSC_SCAN);
+ input_set_drvdata(dev, kbd);
+
+ error = input_register_device(dev);
+ if (error)
+ goto fail;
+
+ /* Maple polling is locked to VBLANK - which may be just 50/s */
+ maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, MAPLE_FUNC_KEYBOARD);
+ return 0;
+
+ fail:
+ input_free_device(dev);
+ kfree(kbd);
+ mdev->private_data = NULL;
+ return error;
+}
+
+static void dc_kbd_disconnect(struct maple_device *mdev)
+{
+ struct dc_kbd *kbd;
+
+ mutex_lock(&maple_keyb_mutex);
+
+ kbd = mdev->private_data;
+ mdev->private_data = NULL;
+ input_unregister_device(kbd->dev);
+ kfree(kbd);
+
+ mutex_unlock(&maple_keyb_mutex);
+}
+
+/* allow the keyboard to be used */
+static int probe_maple_kbd(struct device *dev)
+{
+ struct maple_device *mdev = to_maple_dev(dev);
+ struct maple_driver *mdrv = to_maple_driver(dev->driver);
+ int error;
+
+ error = dc_kbd_connect(mdev);
+ if (error)
+ return error;
+
+ mdev->driver = mdrv;
+ mdev->registered = 1;
+
+ return 0;
+}
+
+static struct maple_driver dc_kbd_driver = {
+ .function = MAPLE_FUNC_KEYBOARD,
+ .connect = dc_kbd_connect,
+ .disconnect = dc_kbd_disconnect,
+ .drv = {
+ .name = "Dreamcast_keyboard",
+ .probe = probe_maple_kbd,
+ },
+};
+
+static int __init dc_kbd_init(void)
+{
+ return maple_driver_register(&dc_kbd_driver.drv);
+}
+
+static void __exit dc_kbd_exit(void)
+{
+ driver_unregister(&dc_kbd_driver.drv);
+}
+
+module_init(dc_kbd_init);
+module_exit(dc_kbd_exit);
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
index b97a41e3ee5..48d1cab0aa1 100644
--- a/drivers/input/keyboard/newtonkbd.c
+++ b/drivers/input/keyboard/newtonkbd.c
@@ -106,7 +106,7 @@ static int nkbd_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_dev->keycode = nkbd->keycode;
input_dev->keycodesize = sizeof(unsigned char);
input_dev->keycodemax = ARRAY_SIZE(nkbd_keycode);
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index 3a228634f10..babc913d549 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -4,7 +4,7 @@
* OMAP Keypad Driver
*
* Copyright (C) 2003 Nokia Corporation
- * Written by Timo Teräs <ext-timo.teras@nokia.com>
+ * Written by Timo Teräs <ext-timo.teras@nokia.com>
*
* Added support for H2 & H3 Keypad
* Copyright (C) 2004 Texas Instruments
@@ -233,7 +233,7 @@ static void omap_kp_tasklet(unsigned long data)
omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
kp_cur_group = -1;
}
- }
+ }
}
static ssize_t omap_kp_enable_show(struct device *dev,
@@ -318,7 +318,7 @@ static int __init omap_kp_probe(struct platform_device *pdev)
keymap = pdata->keymap;
if (pdata->rep)
- set_bit(EV_REP, input_dev->evbit);
+ __set_bit(EV_REP, input_dev->evbit);
if (pdata->delay)
omap_kp->delay = pdata->delay;
@@ -365,9 +365,9 @@ static int __init omap_kp_probe(struct platform_device *pdev)
goto err2;
/* setup input device */
- set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_KEY, input_dev->evbit);
for (i = 0; keymap[i] != 0; i++)
- set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
+ __set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
input_dev->name = "omap-keypad";
input_dev->phys = "omap-keypad/input0";
input_dev->dev.parent = &pdev->dev;
@@ -377,10 +377,6 @@ static int __init omap_kp_probe(struct platform_device *pdev)
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->keycode = keymap;
- input_dev->keycodesize = sizeof(unsigned int);
- input_dev->keycodemax = pdata->keymapsize;
-
ret = input_register_device(omap_kp->input);
if (ret < 0) {
printk(KERN_ERR "Unable to register omap-keypad input device\n");
@@ -403,15 +399,15 @@ static int __init omap_kp_probe(struct platform_device *pdev)
} else {
for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) {
if (request_irq(OMAP_GPIO_IRQ(row_gpios[irq_idx]),
- omap_kp_interrupt,
+ omap_kp_interrupt,
IRQF_TRIGGER_FALLING,
- "omap-keypad", omap_kp) < 0)
+ "omap-keypad", omap_kp) < 0)
goto err5;
}
}
return 0;
err5:
- for (i = irq_idx-1; i >=0; i--)
+ for (i = irq_idx - 1; i >=0; i--)
free_irq(row_gpios[i], 0);
err4:
input_unregister_device(omap_kp->input);
@@ -440,9 +436,9 @@ static int omap_kp_remove(struct platform_device *pdev)
if (cpu_is_omap24xx()) {
int i;
for (i = 0; i < omap_kp->cols; i++)
- omap_free_gpio(col_gpios[i]);
+ omap_free_gpio(col_gpios[i]);
for (i = 0; i < omap_kp->rows; i++) {
- omap_free_gpio(row_gpios[i]);
+ omap_free_gpio(row_gpios[i]);
free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0);
}
} else {
@@ -485,6 +481,6 @@ static void __exit omap_kp_exit(void)
module_init(omap_kp_init);
module_exit(omap_kp_exit);
-MODULE_AUTHOR("Timo Teräs");
+MODULE_AUTHOR("Timo Teräs");
MODULE_DESCRIPTION("OMAP Keypad Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/pxa27x_keyboard.c b/drivers/input/keyboard/pxa27x_keyboard.c
index ebe5eacf299..bdd64ee4c5c 100644
--- a/drivers/input/keyboard/pxa27x_keyboard.c
+++ b/drivers/input/keyboard/pxa27x_keyboard.c
@@ -23,6 +23,8 @@
#include <linux/input.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -40,6 +42,8 @@
col/2 == 2 ? KPASMKP2 : KPASMKP3)
#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2)))
+static struct clk *pxakbd_clk;
+
static irqreturn_t pxakbd_irq_handler(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
@@ -104,7 +108,7 @@ static int pxakbd_open(struct input_dev *dev)
KPREC = 0x7F;
/* Enable unit clock */
- pxa_set_cken(CKEN_KEYPAD, 1);
+ clk_enable(pxakbd_clk);
return 0;
}
@@ -112,7 +116,7 @@ static int pxakbd_open(struct input_dev *dev)
static void pxakbd_close(struct input_dev *dev)
{
/* Disable clock unit */
- pxa_set_cken(CKEN_KEYPAD, 0);
+ clk_disable(pxakbd_clk);
}
#ifdef CONFIG_PM
@@ -140,7 +144,8 @@ static int pxakbd_resume(struct platform_device *pdev)
KPREC = pdata->reg_kprec;
/* Enable unit clock */
- pxa_set_cken(CKEN_KEYPAD, 1);
+ clk_disable(pxakbd_clk);
+ clk_enable(pxakbd_clk);
}
mutex_unlock(&input_dev->mutex);
@@ -158,11 +163,18 @@ static int __devinit pxakbd_probe(struct platform_device *pdev)
struct input_dev *input_dev;
int i, row, col, error;
+ pxakbd_clk = clk_get(&pdev->dev, "KBDCLK");
+ if (IS_ERR(pxakbd_clk)) {
+ error = PTR_ERR(pxakbd_clk);
+ goto err_clk;
+ }
+
/* Create and register the input driver. */
input_dev = input_allocate_device();
if (!input_dev) {
printk(KERN_ERR "Cannot request keypad device\n");
- return -ENOMEM;
+ error = -ENOMEM;
+ goto err_alloc;
}
input_dev->name = DRIVER_NAME;
@@ -171,8 +183,9 @@ static int __devinit pxakbd_probe(struct platform_device *pdev)
input_dev->close = pxakbd_close;
input_dev->dev.parent = &pdev->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL);
- input_dev->relbit[LONG(REL_WHEEL)] = BIT(REL_WHEEL);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
+ BIT_MASK(EV_REL);
+ input_dev->relbit[BIT_WORD(REL_WHEEL)] = BIT_MASK(REL_WHEEL);
for (row = 0; row < pdata->nr_rows; row++) {
for (col = 0; col < pdata->nr_cols; col++) {
int code = pdata->keycodes[row][col];
@@ -185,7 +198,6 @@ static int __devinit pxakbd_probe(struct platform_device *pdev)
DRIVER_NAME, pdev);
if (error) {
printk(KERN_ERR "Cannot request keypad IRQ\n");
- pxa_set_cken(CKEN_KEYPAD, 0);
goto err_free_dev;
}
@@ -217,6 +229,9 @@ static int __devinit pxakbd_probe(struct platform_device *pdev)
free_irq(IRQ_KEYPAD, pdev);
err_free_dev:
input_free_device(input_dev);
+ err_alloc:
+ clk_put(pxakbd_clk);
+ err_clk:
return error;
}
@@ -226,6 +241,7 @@ static int __devexit pxakbd_remove(struct platform_device *pdev)
input_unregister_device(input_dev);
free_irq(IRQ_KEYPAD, pdev);
+ clk_put(pxakbd_clk);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
index 41b80385476..410d78a774d 100644
--- a/drivers/input/keyboard/spitzkbd.c
+++ b/drivers/input/keyboard/spitzkbd.c
@@ -381,7 +381,8 @@ static int __init spitzkbd_probe(struct platform_device *dev)
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
+ BIT_MASK(EV_PWR) | BIT_MASK(EV_SW);
input_dev->keycode = spitzkbd->keycode;
input_dev->keycodesize = sizeof(unsigned char);
input_dev->keycodemax = ARRAY_SIZE(spitzkbd_keycode);
diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c
index b44b0684d54..7437219370b 100644
--- a/drivers/input/keyboard/stowaway.c
+++ b/drivers/input/keyboard/stowaway.c
@@ -110,7 +110,7 @@ static int skbd_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_dev->keycode = skbd->keycode;
input_dev->keycodesize = sizeof(unsigned char);
input_dev->keycodemax = ARRAY_SIZE(skbd_keycode);
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
index 1d4e39624cf..be0f5d19d02 100644
--- a/drivers/input/keyboard/sunkbd.c
+++ b/drivers/input/keyboard/sunkbd.c
@@ -277,9 +277,11 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
input_dev->event = sunkbd_event;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP);
- input_dev->ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML);
- input_dev->sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
+ BIT_MASK(EV_SND) | BIT_MASK(EV_REP);
+ input_dev->ledbit[0] = BIT_MASK(LED_CAPSL) | BIT_MASK(LED_COMPOSE) |
+ BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_NUML);
+ input_dev->sndbit[0] = BIT_MASK(SND_CLICK) | BIT_MASK(SND_BELL);
input_dev->keycode = sunkbd->keycode;
input_dev->keycodesize = sizeof(unsigned char);
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
index f3a56eb58ed..152a2c07050 100644
--- a/drivers/input/keyboard/xtkbd.c
+++ b/drivers/input/keyboard/xtkbd.c
@@ -110,7 +110,7 @@ static int xtkbd_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_dev->keycode = xtkbd->keycode;
input_dev->keycodesize = sizeof(unsigned char);
input_dev->keycodemax = ARRAY_SIZE(xtkbd_keycode);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index d602b8fa7d4..8f5c7b90187 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -70,9 +70,9 @@ config INPUT_WISTRON_BTNS
select LEDS_CLASS
select CHECK_SIGNATURE
help
- Say Y here for support of Winstron laptop button interface, used on
+ Say Y here for support of Wistron laptop button interfaces, used on
laptops of various brands, including Acer and Fujitsu-Siemens. If
- available, mail and wifi leds will be controlable via /sys/class/leds.
+ available, mail and wifi LEDs will be controllable via /sys/class/leds.
To compile this driver as a module, choose M here: the module will
be called wistron_btns.
@@ -152,7 +152,7 @@ config INPUT_POWERMATE
config INPUT_YEALINK
tristate "Yealink usb-p1k voip phone"
- depends EXPERIMENTAL
+ depends on EXPERIMENTAL
depends on USB_ARCH_HAS_HCD
select USB
help
diff --git a/drivers/input/misc/ati_remote.c b/drivers/input/misc/ati_remote.c
index 471aab20644..3a7937481ad 100644
--- a/drivers/input/misc/ati_remote.c
+++ b/drivers/input/misc/ati_remote.c
@@ -662,10 +662,10 @@ static void ati_remote_input_init(struct ati_remote *ati_remote)
struct input_dev *idev = ati_remote->idev;
int i;
- idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
- BIT(BTN_SIDE) | BIT(BTN_EXTRA) );
- idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
+ idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
if (ati_remote_tbl[i].type == EV_KEY)
set_bit(ati_remote_tbl[i].code, idev->keybit);
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index 1031543e5c3..f2709b82485 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -346,9 +346,10 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2)
ar2->idev = idev;
input_set_drvdata(idev, ar2);
- idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL);
- idev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
- idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL);
+ idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_RIGHT);
+ idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
set_bit(ati_remote2_key_table[i].key_code, idev->keybit);
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index e43e92fd9e2..4e3ad657ed8 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -81,7 +81,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
input_dev->name = "Atlas ACPI button driver";
input_dev->phys = "ASIM0000/atlas/input0";
input_dev->id.bustype = BUS_HOST;
- input_dev->evbit[LONG(EV_KEY)] = BIT(EV_KEY);
+ input_dev->evbit[BIT_WORD(EV_KEY)] = BIT_MASK(EV_KEY);
set_bit(KEY_F1, input_dev->keybit);
set_bit(KEY_F2, input_dev->keybit);
diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c
index 064b0793601..1aef97ed5e8 100644
--- a/drivers/input/misc/cobalt_btns.c
+++ b/drivers/input/misc/cobalt_btns.c
@@ -104,7 +104,7 @@ static int __devinit cobalt_buttons_probe(struct platform_device *pdev)
input->id.bustype = BUS_HOST;
input->cdev.dev = &pdev->dev;
- input->evbit[0] = BIT(EV_KEY);
+ input->evbit[0] = BIT_MASK(EV_KEY);
for (i = 0; i < ARRAY_SIZE(buttons_map); i++) {
set_bit(buttons_map[i].keycode, input->keybit);
buttons_map[i].count = 0;
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
index e759944041a..d2ade7443b7 100644
--- a/drivers/input/misc/ixp4xx-beeper.c
+++ b/drivers/input/misc/ixp4xx-beeper.c
@@ -109,8 +109,8 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &dev->dev;
- input_dev->evbit[0] = BIT(EV_SND);
- input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
+ input_dev->evbit[0] = BIT_MASK(EV_SND);
+ input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
input_dev->event = ixp4xx_spkr_event;
err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt,
diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c
index 1bffc9fa98c..fd74347047d 100644
--- a/drivers/input/misc/keyspan_remote.c
+++ b/drivers/input/misc/keyspan_remote.c
@@ -497,7 +497,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
usb_to_input_id(udev, &input_dev->id);
input_dev->dev.parent = &interface->dev;
- input_dev->evbit[0] = BIT(EV_KEY); /* We will only report KEY events. */
+ input_dev->evbit[0] = BIT_MASK(EV_KEY); /* We will only report KEY events. */
for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++)
if (keyspan_key_table[i] != KEY_RESERVED)
set_bit(keyspan_key_table[i], input_dev->keybit);
diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c
index e9f26e766b4..0c64d9bb718 100644
--- a/drivers/input/misc/m68kspkr.c
+++ b/drivers/input/misc/m68kspkr.c
@@ -65,8 +65,8 @@ static int __devinit m68kspkr_probe(struct platform_device *dev)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &dev->dev;
- input_dev->evbit[0] = BIT(EV_SND);
- input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
+ input_dev->evbit[0] = BIT_MASK(EV_SND);
+ input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
input_dev->event = m68kspkr_event;
err = input_register_device(input_dev);
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index 906bf5e8de8..43aaa5cebd1 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -17,17 +17,18 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/platform_device.h>
-#include <asm/8253pit.h>
#include <asm/io.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("PC Speaker beeper driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcspkr");
-#ifdef CONFIG_X86
+#if defined(CONFIG_MIPS) || defined(CONFIG_X86)
/* Use the global PIT lock ! */
#include <asm/i8253.h>
#else
+#include <asm/8253pit.h>
static DEFINE_SPINLOCK(i8253_lock);
#endif
@@ -85,8 +86,8 @@ static int __devinit pcspkr_probe(struct platform_device *dev)
pcspkr_dev->id.version = 0x0100;
pcspkr_dev->dev.parent = &dev->dev;
- pcspkr_dev->evbit[0] = BIT(EV_SND);
- pcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
+ pcspkr_dev->evbit[0] = BIT_MASK(EV_SND);
+ pcspkr_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
pcspkr_dev->event = pcspkr_event;
err = input_register_device(pcspkr_dev);
diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c
index 448a470d28f..7a7b8c7b963 100644
--- a/drivers/input/misc/powermate.c
+++ b/drivers/input/misc/powermate.c
@@ -363,10 +363,11 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
input_dev->event = powermate_input_event;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC);
- input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
- input_dev->relbit[LONG(REL_DIAL)] = BIT(REL_DIAL);
- input_dev->mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) |
+ BIT_MASK(EV_MSC);
+ input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+ input_dev->relbit[BIT_WORD(REL_DIAL)] = BIT_MASK(REL_DIAL);
+ input_dev->mscbit[BIT_WORD(MSC_PULSELED)] = BIT_MASK(MSC_PULSELED);
/* get a handle to the interrupt data pipe */
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index e36ec1d92be..a3637d87088 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -115,8 +115,8 @@ static int __devinit sparcspkr_probe(struct device *dev)
input_dev->id.version = 0x0100;
input_dev->dev.parent = dev;
- input_dev->evbit[0] = BIT(EV_SND);
- input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
+ input_dev->evbit[0] = BIT_MASK(EV_SND);
+ input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
input_dev->event = state->event;
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 60121f10f8d..b438d998625 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -247,7 +247,7 @@ static int have_wifi;
static int have_bluetooth;
static int have_leds;
-static int __init dmi_matched(struct dmi_system_id *dmi)
+static int __init dmi_matched(const struct dmi_system_id *dmi)
{
const struct key_entry *key;
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
index ab15880fd56..46279ef2b64 100644
--- a/drivers/input/misc/yealink.c
+++ b/drivers/input/misc/yealink.c
@@ -945,7 +945,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* input_dev->event = input_ev; TODO */
/* register available key events */
- input_dev->evbit[0] = BIT(EV_KEY);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY);
for (i = 0; i < 256; i++) {
int k = map_p1k_to_key(i);
if (k >= 0) {
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 2c5f11a4f6b..2b5ed119c9a 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -48,11 +48,13 @@ static const struct alps_model_info alps_model_data[] = {
{ { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
{ { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */
+ { { 0x73, 0x00, 0x0a }, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
{ { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
{ { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
{ { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
{ { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
+ { { 0x73, 0x02, 0x50 }, 0xcf, 0xff, ALPS_FW_BK_1 } /* Dell Vostro 1400 */
};
/*
@@ -453,24 +455,25 @@ int alps_init(struct psmouse *psmouse)
if (alps_hw_init(psmouse, &version))
goto init_fail;
- dev1->evbit[LONG(EV_KEY)] |= BIT(EV_KEY);
- dev1->keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
- dev1->keybit[LONG(BTN_TOOL_FINGER)] |= BIT(BTN_TOOL_FINGER);
- dev1->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY);
+ dev1->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);
+ dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER);
+ dev1->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
- dev1->evbit[LONG(EV_ABS)] |= BIT(EV_ABS);
+ dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
if (priv->i->flags & ALPS_WHEEL) {
- dev1->evbit[LONG(EV_REL)] |= BIT(EV_REL);
- dev1->relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL);
+ dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
+ dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL);
}
if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
- dev1->keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
- dev1->keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
+ dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD);
+ dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK);
}
snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
@@ -481,9 +484,10 @@ int alps_init(struct psmouse *psmouse)
dev2->id.product = PSMOUSE_ALPS;
dev2->id.version = 0x0000;
- dev2->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- dev2->relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y);
- dev2->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ dev2->relbit[BIT_WORD(REL_X)] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+ dev2->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
if (input_register_device(priv->dev2))
goto init_fail;
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index 239a0e16d91..a185ac78a42 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -111,9 +111,10 @@ static int __init amimouse_init(void)
amimouse_dev->id.product = 0x0002;
amimouse_dev->id.version = 0x0100;
- amimouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- amimouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
- amimouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ amimouse_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ amimouse_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+ amimouse_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
amimouse_dev->open = amimouse_open;
amimouse_dev->close = amimouse_close;
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index a1804bfdbb8..b4423a471f0 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -129,12 +129,12 @@ MODULE_DEVICE_TABLE (usb, atp_table);
*/
#define ATP_THRESHOLD 5
-/* MacBook Pro (Geyser 3 & 4) initialization constants */
-#define ATP_GEYSER3_MODE_READ_REQUEST_ID 1
-#define ATP_GEYSER3_MODE_WRITE_REQUEST_ID 9
-#define ATP_GEYSER3_MODE_REQUEST_VALUE 0x300
-#define ATP_GEYSER3_MODE_REQUEST_INDEX 0
-#define ATP_GEYSER3_MODE_VENDOR_VALUE 0x04
+/* Geyser initialization constants */
+#define ATP_GEYSER_MODE_READ_REQUEST_ID 1
+#define ATP_GEYSER_MODE_WRITE_REQUEST_ID 9
+#define ATP_GEYSER_MODE_REQUEST_VALUE 0x300
+#define ATP_GEYSER_MODE_REQUEST_INDEX 0
+#define ATP_GEYSER_MODE_VENDOR_VALUE 0x04
/* Structure to hold all of our device specific stuff */
struct atp {
@@ -142,9 +142,11 @@ struct atp {
struct usb_device * udev; /* usb device */
struct urb * urb; /* usb request block */
signed char * data; /* transferred data */
- int open; /* non-zero if opened */
- struct input_dev *input; /* input dev */
- int valid; /* are the sensors valid ? */
+ struct input_dev * input; /* input dev */
+ unsigned char open; /* non-zero if opened */
+ unsigned char valid; /* are the sensors valid ? */
+ unsigned char size_detect_done;
+ unsigned char overflowwarn; /* overflow warning printed? */
int x_old; /* last reported x/y, */
int y_old; /* used for smoothing */
/* current value of the sensors */
@@ -153,7 +155,6 @@ struct atp {
signed char xy_old[ATP_XSENSORS + ATP_YSENSORS];
/* accumulated sensors */
int xy_acc[ATP_XSENSORS + ATP_YSENSORS];
- int overflowwarn; /* overflow warning printed? */
int datalen; /* size of an USB urb transfer */
int idlecount; /* number of empty packets */
struct work_struct work;
@@ -170,7 +171,7 @@ struct atp {
#define dprintk(format, a...) \
do { \
- if (debug) printk(format, ##a); \
+ if (debug) printk(KERN_DEBUG format, ##a); \
} while (0)
MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold, Michael Hanselmann");
@@ -188,6 +189,15 @@ static int debug = 1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Activate debugging output");
+static inline int atp_is_fountain(struct atp *dev)
+{
+ u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+ return productId == FOUNTAIN_ANSI_PRODUCT_ID ||
+ productId == FOUNTAIN_ISO_PRODUCT_ID ||
+ productId == FOUNTAIN_TP_ONLY_PRODUCT_ID;
+}
+
/* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */
static inline int atp_is_geyser_2(struct atp *dev)
{
@@ -211,52 +221,63 @@ static inline int atp_is_geyser_3(struct atp *dev)
}
/*
- * By default Geyser 3 device sends standard USB HID mouse
+ * By default newer Geyser devices send standard USB HID mouse
* packets (Report ID 2). This code changes device mode, so it
* sends raw sensor reports (Report ID 5).
*/
-static int atp_geyser3_init(struct usb_device *udev)
+static int atp_geyser_init(struct usb_device *udev)
{
char data[8];
int size;
size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- ATP_GEYSER3_MODE_READ_REQUEST_ID,
+ ATP_GEYSER_MODE_READ_REQUEST_ID,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ATP_GEYSER3_MODE_REQUEST_VALUE,
- ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+ ATP_GEYSER_MODE_REQUEST_VALUE,
+ ATP_GEYSER_MODE_REQUEST_INDEX, &data, 8, 5000);
if (size != 8) {
err("Could not do mode read request from device"
- " (Geyser 3 mode)");
+ " (Geyser Raw mode)");
return -EIO;
}
/* Apply the mode switch */
- data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
+ data[0] = ATP_GEYSER_MODE_VENDOR_VALUE;
size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
+ ATP_GEYSER_MODE_WRITE_REQUEST_ID,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ATP_GEYSER3_MODE_REQUEST_VALUE,
- ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+ ATP_GEYSER_MODE_REQUEST_VALUE,
+ ATP_GEYSER_MODE_REQUEST_INDEX, &data, 8, 5000);
if (size != 8) {
err("Could not do mode write request to device"
- " (Geyser 3 mode)");
+ " (Geyser Raw mode)");
return -EIO;
}
return 0;
}
-/* Reinitialise the device if it's a geyser 3 */
+/*
+ * Reinitialise the device. This usually stops stream of empty packets
+ * coming from it.
+ */
static void atp_reinit(struct work_struct *work)
{
struct atp *dev = container_of(work, struct atp, work);
struct usb_device *udev = dev->udev;
+ int retval;
dev->idlecount = 0;
- atp_geyser3_init(udev);
+
+ atp_geyser_init(udev);
+
+ retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
+ if (retval) {
+ err("%s - usb_submit_urb failed with result %d",
+ __FUNCTION__, retval);
+ }
}
static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
@@ -337,7 +358,7 @@ static void atp_complete(struct urb* urb)
break;
case -EOVERFLOW:
if(!dev->overflowwarn) {
- printk("appletouch: OVERFLOW with data "
+ printk(KERN_WARNING "appletouch: OVERFLOW with data "
"length %d, actual length is %d\n",
dev->datalen, dev->urb->actual_length);
dev->overflowwarn = 1;
@@ -426,15 +447,17 @@ static void atp_complete(struct urb* urb)
dev->x_old = dev->y_old = -1;
memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
- if (atp_is_geyser_3(dev)) /* No 17" Macbooks (yet) */
+ if (dev->size_detect_done ||
+ atp_is_geyser_3(dev)) /* No 17" Macbooks (yet) */
goto exit;
/* 17" Powerbooks have extra X sensors */
- for (i = (atp_is_geyser_2(dev)?15:16); i < ATP_XSENSORS; i++) {
- if (!dev->xy_cur[i]) continue;
+ for (i = (atp_is_geyser_2(dev) ? 15 : 16); i < ATP_XSENSORS; i++) {
+ if (!dev->xy_cur[i])
+ continue;
- printk("appletouch: 17\" model detected.\n");
- if(atp_is_geyser_2(dev))
+ printk(KERN_INFO "appletouch: 17\" model detected.\n");
+ if (atp_is_geyser_2(dev))
input_set_abs_params(dev->input, ABS_X, 0,
(20 - 1) *
ATP_XFACT - 1,
@@ -444,10 +467,10 @@ static void atp_complete(struct urb* urb)
(ATP_XSENSORS - 1) *
ATP_XFACT - 1,
ATP_FUZZ, 0);
-
break;
}
+ dev->size_detect_done = 1;
goto exit;
}
@@ -479,7 +502,7 @@ static void atp_complete(struct urb* urb)
dev->y_old = y;
if (debug > 1)
- printk("appletouch: X: %3d Y: %3d "
+ printk(KERN_DEBUG "appletouch: X: %3d Y: %3d "
"Xz: %3d Yz: %3d\n",
x, y, x_z, y_z);
@@ -502,23 +525,31 @@ static void atp_complete(struct urb* urb)
/* reset the accumulator on release */
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
+ }
+
+ input_report_key(dev->input, BTN_LEFT, key);
+ input_sync(dev->input);
- /* Geyser 3 will continue to send packets continually after
- the first touch unless reinitialised. Do so if it's been
- idle for a while in order to avoid waking the kernel up
- several hundred times a second */
- if (!key && atp_is_geyser_3(dev)) {
+ /*
+ * Many Geysers will continue to send packets continually after
+ * the first touch unless reinitialised. Do so if it's been
+ * idle for a while in order to avoid waking the kernel up
+ * several hundred times a second. Re-initialization does not
+ * work on Fountain touchpads.
+ */
+ if (!atp_is_fountain(dev)) {
+ if (!x && !y && !key) {
dev->idlecount++;
if (dev->idlecount == 10) {
dev->valid = 0;
schedule_work(&dev->work);
+ /* Don't resubmit urb here, wait for reinit */
+ return;
}
- }
+ } else
+ dev->idlecount = 0;
}
- input_report_key(dev->input, BTN_LEFT, key);
- input_sync(dev->input);
-
exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval) {
@@ -591,12 +622,12 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
else
dev->datalen = 81;
- if (atp_is_geyser_3(dev)) {
+ if (!atp_is_fountain(dev)) {
/* switch to raw sensor mode */
- if (atp_geyser3_init(udev))
+ if (atp_geyser_init(udev))
goto err_free_devs;
- printk("appletouch Geyser 3 inited.\n");
+ printk(KERN_INFO "appletouch: Geyser mode initialized.\n");
}
dev->urb = usb_alloc_urb(0, GFP_KERNEL);
diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c
index 43ab6566fb6..98a3561d4b0 100644
--- a/drivers/input/mouse/atarimouse.c
+++ b/drivers/input/mouse/atarimouse.c
@@ -73,14 +73,11 @@ static void atamouse_interrupt(char *buf)
{
int buttons, dx, dy;
-/* ikbd_mouse_disable(); */
-
buttons = (buf[0] & 1) | ((buf[0] & 2) << 1);
#ifdef FIXED_ATARI_JOYSTICK
buttons |= atari_mouse_buttons & 2;
atari_mouse_buttons = buttons;
#endif
-/* ikbd_mouse_rel_pos(); */
/* only relative events get here */
dx = buf[1];
@@ -126,28 +123,32 @@ static int __init atamouse_init(void)
if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
return -ENODEV;
- if (!(atamouse_dev = input_allocate_device()))
- return -ENOMEM;
-
if (!(atari_keyb_init()))
return -ENODEV;
+ atamouse_dev = input_allocate_device();
+ if (!atamouse_dev)
+ return -ENOMEM;
+
atamouse_dev->name = "Atari mouse";
atamouse_dev->phys = "atamouse/input0";
- atamouse_dev->id.bustype = BUS_ATARI;
+ atamouse_dev->id.bustype = BUS_HOST;
atamouse_dev->id.vendor = 0x0001;
atamouse_dev->id.product = 0x0002;
atamouse_dev->id.version = 0x0100;
- atamouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- atamouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
- atamouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ atamouse_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ atamouse_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+ atamouse_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
atamouse_dev->open = atamouse_open;
atamouse_dev->close = atamouse_close;
- input_register_device(atamouse_dev);
+ if (input_register_device(atamouse_dev)) {
+ input_free_device(atamouse_dev);
+ return -ENOMEM;
+ }
- printk(KERN_INFO "input: %s at keyboard ACIA\n", atamouse_dev->name);
return 0;
}
diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c
index 449bf4dcbbc..27f88fbb713 100644
--- a/drivers/input/mouse/hil_ptr.c
+++ b/drivers/input/mouse/hil_ptr.c
@@ -298,12 +298,12 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
idd = ptr->idd + 1;
txt = "unknown";
if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
- ptr->dev->evbit[0] = BIT(EV_REL);
+ ptr->dev->evbit[0] = BIT_MASK(EV_REL);
txt = "relative";
}
if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_ABS) {
- ptr->dev->evbit[0] = BIT(EV_ABS);
+ ptr->dev->evbit[0] = BIT_MASK(EV_ABS);
txt = "absolute";
}
if (!ptr->dev->evbit[0])
@@ -311,7 +311,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
if (ptr->nbtn)
- ptr->dev->evbit[0] |= BIT(EV_KEY);
+ ptr->dev->evbit[0] |= BIT_MASK(EV_KEY);
naxsets = HIL_IDD_NUM_AXSETS(*idd);
ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
index 79b624fe899..26ec09529b5 100644
--- a/drivers/input/mouse/inport.c
+++ b/drivers/input/mouse/inport.c
@@ -144,7 +144,7 @@ static int __init inport_init(void)
b = inb(INPORT_SIGNATURE_PORT);
c = inb(INPORT_SIGNATURE_PORT);
if (a == b || a != c) {
- printk(KERN_ERR "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE);
+ printk(KERN_INFO "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE);
err = -ENODEV;
goto err_release_region;
}
@@ -163,9 +163,10 @@ static int __init inport_init(void)
inport_dev->id.product = 0x0001;
inport_dev->id.version = 0x0100;
- inport_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- inport_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
- inport_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ inport_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ inport_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
+ inport_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
inport_dev->open = inport_open;
inport_dev->close = inport_close;
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 91109b49fde..9ec57d80186 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -27,7 +27,7 @@ struct lifebook_data {
static const char *desired_serio_phys;
-static int lifebook_set_serio_phys(struct dmi_system_id *d)
+static int lifebook_set_serio_phys(const struct dmi_system_id *d)
{
desired_serio_phys = d->driver_data;
return 0;
@@ -35,13 +35,13 @@ static int lifebook_set_serio_phys(struct dmi_system_id *d)
static unsigned char lifebook_use_6byte_proto;
-static int lifebook_set_6byte_proto(struct dmi_system_id *d)
+static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
{
lifebook_use_6byte_proto = 1;
return 0;
}
-static struct dmi_system_id lifebook_dmi_table[] = {
+static const struct dmi_system_id lifebook_dmi_table[] = {
{
.ident = "FLORA-ie 55mi",
.matches = {
@@ -97,6 +97,14 @@ static struct dmi_system_id lifebook_dmi_table[] = {
.callback = lifebook_set_6byte_proto,
},
{
+ .ident = "CF-72",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"),
+ },
+ .callback = lifebook_set_serio_phys,
+ .driver_data = "isa0060/serio3",
+ },
+ {
.ident = "Lifebook B142",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"),
@@ -262,9 +270,10 @@ static int lifebook_create_relative_device(struct psmouse *psmouse)
dev2->id.version = 0x0000;
dev2->dev.parent = &psmouse->ps2dev.serio->dev;
- dev2->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- dev2->relbit[LONG(REL_X)] = BIT(REL_X) | BIT(REL_Y);
- dev2->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
+ dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
+ dev2->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_RIGHT);
error = input_register_device(priv->dev2);
if (error)
@@ -282,14 +291,14 @@ static int lifebook_create_relative_device(struct psmouse *psmouse)
int lifebook_init(struct psmouse *psmouse)
{
struct input_dev *dev1 = psmouse->dev;
- int max_coord = lifebook_use_6byte_proto ? 1024 : 4096;
+ int max_coord = lifebook_use_6byte_proto ? 4096 : 1024;
if (lifebook_absolute_mode(psmouse))
return -1;
- dev1->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+ dev1->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
dev1->relbit[0] = 0;
- dev1->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ dev1->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0);
input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0);
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
index 26c3b2e2ca9..37e7c75b43b 100644
--- a/drivers/input/mouse/logibm.c
+++ b/drivers/input/mouse/logibm.c
@@ -134,7 +134,7 @@ static int __init logibm_init(void)
udelay(100);
if (inb(LOGIBM_SIGNATURE_PORT) != LOGIBM_SIGNATURE_BYTE) {
- printk(KERN_ERR "logibm.c: Didn't find Logitech busmouse at %#x\n", LOGIBM_BASE);
+ printk(KERN_INFO "logibm.c: Didn't find Logitech busmouse at %#x\n", LOGIBM_BASE);
err = -ENODEV;
goto err_release_region;
}
@@ -156,9 +156,10 @@ static int __init logibm_init(void)
logibm_dev->id.product = 0x0001;
logibm_dev->id.version = 0x0100;
- logibm_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- logibm_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
- logibm_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ logibm_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ logibm_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
+ logibm_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
logibm_dev->open = logibm_open;
logibm_dev->close = logibm_close;
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
index 05d992e514f..8991ab0b4fe 100644
--- a/drivers/input/mouse/pc110pad.c
+++ b/drivers/input/mouse/pc110pad.c
@@ -144,9 +144,9 @@ static int __init pc110pad_init(void)
pc110pad_dev->id.product = 0x0001;
pc110pad_dev->id.version = 0x0100;
- pc110pad_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- pc110pad_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
- pc110pad_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ pc110pad_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ pc110pad_dev->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y);
+ pc110pad_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
pc110pad_dev->absmax[ABS_X] = 0x1ff;
pc110pad_dev->absmax[ABS_Y] = 0x0ff;
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index b9f0fb2530e..21a9c0b69a1 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -648,9 +648,10 @@ static int psmouse_extensions(struct psmouse *psmouse,
/*
* Reset to defaults in case the device got confused by extended
- * protocol probes. Note that we do full reset becuase some mice
- * put themselves to sleep when see PSMOUSE_RESET_DIS.
+ * protocol probes. Note that we follow up with full reset because
+ * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS.
*/
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
psmouse_reset(psmouse);
if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0)
@@ -905,7 +906,7 @@ static void psmouse_activate(struct psmouse *psmouse)
/*
* psmouse_deactivate() puts the mouse into poll mode so that we don't get motion
- * reports from it unless we explicitely request it.
+ * reports from it unless we explicitly request it.
*/
static void psmouse_deactivate(struct psmouse *psmouse)
@@ -1114,9 +1115,10 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse
input_dev->dev.parent = &psmouse->ps2dev.serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
- input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
+ input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
psmouse->set_rate = psmouse_set_rate;
psmouse->set_resolution = psmouse_set_resolution;
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index 355efd0423e..18a48636ba4 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -78,9 +78,10 @@ static int __init rpcmouse_init(void)
rpcmouse_dev->id.product = 0x0001;
rpcmouse_dev->id.version = 0x0100;
- rpcmouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- rpcmouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
- rpcmouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ rpcmouse_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ rpcmouse_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
+ rpcmouse_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
rpcmouse_lastx = (short) iomd_readl(IOMD_MOUSEX);
rpcmouse_lasty = (short) iomd_readl(IOMD_MOUSEY);
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
index 77b8ee2b965..ed917bfd086 100644
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -268,9 +268,10 @@ static int sermouse_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
- input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_RIGHT);
+ input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
if (c & 0x01) set_bit(BTN_MIDDLE, input_dev->keybit);
if (c & 0x02) set_bit(BTN_SIDE, input_dev->keybit);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 666ad3a53fd..d349c4a5e3e 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -602,7 +602,7 @@ static int synaptics_reconnect(struct psmouse *psmouse)
#if defined(__i386__)
#include <linux/dmi.h>
-static struct dmi_system_id toshiba_dmi_table[] = {
+static const struct dmi_system_id toshiba_dmi_table[] = {
{
.ident = "Toshiba Satellite",
.matches = {
diff --git a/drivers/input/mouse/touchkit_ps2.c b/drivers/input/mouse/touchkit_ps2.c
index 7b977fd2357..3fadb2accac 100644
--- a/drivers/input/mouse/touchkit_ps2.c
+++ b/drivers/input/mouse/touchkit_ps2.c
@@ -85,7 +85,7 @@ int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
return -ENODEV;
if (set_properties) {
- dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
set_bit(BTN_TOUCH, dev->keybit);
input_set_abs_params(dev, ABS_X, 0, TOUCHKIT_MAX_XC, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0);
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index 4a321576f34..404eedd5ffa 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -330,7 +330,7 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
/*
* Check for Power-On-Reset packets. These are sent out
- * after plugging the mouse in, or when explicitely
+ * after plugging the mouse in, or when explicitly
* requested by sending 'T'.
*
* [0]: 1 0 1 0 R3 R2 R1 R0
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 9173916b8be..78c3ea75da2 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -61,9 +61,11 @@ struct mousedev {
int open;
int minor;
char name[16];
+ struct input_handle handle;
wait_queue_head_t wait;
struct list_head client_list;
- struct input_handle handle;
+ spinlock_t client_lock; /* protects client_list */
+ struct mutex mutex;
struct device dev;
struct list_head mixdev_node;
@@ -113,108 +115,137 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
static struct input_handler mousedev_handler;
static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
+static DEFINE_MUTEX(mousedev_table_mutex);
static struct mousedev *mousedev_mix;
static LIST_HEAD(mousedev_mix_list);
+static void mixdev_open_devices(void);
+static void mixdev_close_devices(void);
+
#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
-static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
+static void mousedev_touchpad_event(struct input_dev *dev,
+ struct mousedev *mousedev,
+ unsigned int code, int value)
{
int size, tmp;
enum { FRACTION_DENOM = 128 };
switch (code) {
- case ABS_X:
- fx(0) = value;
- if (mousedev->touch && mousedev->pkt_count >= 2) {
- size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
- if (size == 0)
- size = 256 * 2;
- tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
- tmp += mousedev->frac_dx;
- mousedev->packet.dx = tmp / FRACTION_DENOM;
- mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM;
- }
- break;
- case ABS_Y:
- fy(0) = value;
- if (mousedev->touch && mousedev->pkt_count >= 2) {
- /* use X size to keep the same scale */
- size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
- if (size == 0)
- size = 256 * 2;
- tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
- tmp += mousedev->frac_dy;
- mousedev->packet.dy = tmp / FRACTION_DENOM;
- mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM;
- }
- break;
+ case ABS_X:
+ fx(0) = value;
+ if (mousedev->touch && mousedev->pkt_count >= 2) {
+ size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+ if (size == 0)
+ size = 256 * 2;
+ tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size;
+ tmp += mousedev->frac_dx;
+ mousedev->packet.dx = tmp / FRACTION_DENOM;
+ mousedev->frac_dx =
+ tmp - mousedev->packet.dx * FRACTION_DENOM;
+ }
+ break;
+
+ case ABS_Y:
+ fy(0) = value;
+ if (mousedev->touch && mousedev->pkt_count >= 2) {
+ /* use X size to keep the same scale */
+ size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+ if (size == 0)
+ size = 256 * 2;
+ tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size;
+ tmp += mousedev->frac_dy;
+ mousedev->packet.dy = tmp / FRACTION_DENOM;
+ mousedev->frac_dy = tmp -
+ mousedev->packet.dy * FRACTION_DENOM;
+ }
+ break;
}
}
-static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
+static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
+ unsigned int code, int value)
{
int size;
switch (code) {
- case ABS_X:
- size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
- if (size == 0)
- size = xres ? : 1;
- if (value > dev->absmax[ABS_X])
- value = dev->absmax[ABS_X];
- if (value < dev->absmin[ABS_X])
- value = dev->absmin[ABS_X];
- mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size;
- mousedev->packet.abs_event = 1;
- break;
- case ABS_Y:
- size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
- if (size == 0)
- size = yres ? : 1;
- if (value > dev->absmax[ABS_Y])
- value = dev->absmax[ABS_Y];
- if (value < dev->absmin[ABS_Y])
- value = dev->absmin[ABS_Y];
- mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size;
- mousedev->packet.abs_event = 1;
- break;
+ case ABS_X:
+ size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+ if (size == 0)
+ size = xres ? : 1;
+ if (value > dev->absmax[ABS_X])
+ value = dev->absmax[ABS_X];
+ if (value < dev->absmin[ABS_X])
+ value = dev->absmin[ABS_X];
+ mousedev->packet.x =
+ ((value - dev->absmin[ABS_X]) * xres) / size;
+ mousedev->packet.abs_event = 1;
+ break;
+
+ case ABS_Y:
+ size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
+ if (size == 0)
+ size = yres ? : 1;
+ if (value > dev->absmax[ABS_Y])
+ value = dev->absmax[ABS_Y];
+ if (value < dev->absmin[ABS_Y])
+ value = dev->absmin[ABS_Y];
+ mousedev->packet.y = yres -
+ ((value - dev->absmin[ABS_Y]) * yres) / size;
+ mousedev->packet.abs_event = 1;
+ break;
}
}
-static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value)
+static void mousedev_rel_event(struct mousedev *mousedev,
+ unsigned int code, int value)
{
switch (code) {
- case REL_X: mousedev->packet.dx += value; break;
- case REL_Y: mousedev->packet.dy -= value; break;
- case REL_WHEEL: mousedev->packet.dz -= value; break;
+ case REL_X:
+ mousedev->packet.dx += value;
+ break;
+
+ case REL_Y:
+ mousedev->packet.dy -= value;
+ break;
+
+ case REL_WHEEL:
+ mousedev->packet.dz -= value;
+ break;
}
}
-static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value)
+static void mousedev_key_event(struct mousedev *mousedev,
+ unsigned int code, int value)
{
int index;
switch (code) {
- case BTN_TOUCH:
- case BTN_0:
- case BTN_LEFT: index = 0; break;
- case BTN_STYLUS:
- case BTN_1:
- case BTN_RIGHT: index = 1; break;
- case BTN_2:
- case BTN_FORWARD:
- case BTN_STYLUS2:
- case BTN_MIDDLE: index = 2; break;
- case BTN_3:
- case BTN_BACK:
- case BTN_SIDE: index = 3; break;
- case BTN_4:
- case BTN_EXTRA: index = 4; break;
- default: return;
+
+ case BTN_TOUCH:
+ case BTN_0:
+ case BTN_LEFT: index = 0; break;
+
+ case BTN_STYLUS:
+ case BTN_1:
+ case BTN_RIGHT: index = 1; break;
+
+ case BTN_2:
+ case BTN_FORWARD:
+ case BTN_STYLUS2:
+ case BTN_MIDDLE: index = 2; break;
+
+ case BTN_3:
+ case BTN_BACK:
+ case BTN_SIDE: index = 3; break;
+
+ case BTN_4:
+ case BTN_EXTRA: index = 4; break;
+
+ default: return;
}
if (value) {
@@ -226,19 +257,23 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int
}
}
-static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet)
+static void mousedev_notify_readers(struct mousedev *mousedev,
+ struct mousedev_hw_data *packet)
{
struct mousedev_client *client;
struct mousedev_motion *p;
- unsigned long flags;
+ unsigned int new_head;
int wake_readers = 0;
- list_for_each_entry(client, &mousedev->client_list, node) {
- spin_lock_irqsave(&client->packet_lock, flags);
+ rcu_read_lock();
+ list_for_each_entry_rcu(client, &mousedev->client_list, node) {
+
+ /* Just acquire the lock, interrupts already disabled */
+ spin_lock(&client->packet_lock);
p = &client->packets[client->head];
if (client->ready && p->buttons != mousedev->packet.buttons) {
- unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN;
+ new_head = (client->head + 1) % PACKET_QUEUE_LEN;
if (new_head != client->tail) {
p = &client->packets[client->head = new_head];
memset(p, 0, sizeof(struct mousedev_motion));
@@ -253,25 +288,29 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
}
client->pos_x += packet->dx;
- client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x);
+ client->pos_x = client->pos_x < 0 ?
+ 0 : (client->pos_x >= xres ? xres : client->pos_x);
client->pos_y += packet->dy;
- client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y);
+ client->pos_y = client->pos_y < 0 ?
+ 0 : (client->pos_y >= yres ? yres : client->pos_y);
p->dx += packet->dx;
p->dy += packet->dy;
p->dz += packet->dz;
p->buttons = mousedev->packet.buttons;
- if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons)
+ if (p->dx || p->dy || p->dz ||
+ p->buttons != client->last_buttons)
client->ready = 1;
- spin_unlock_irqrestore(&client->packet_lock, flags);
+ spin_unlock(&client->packet_lock);
if (client->ready) {
kill_fasync(&client->fasync, SIGIO, POLL_IN);
wake_readers = 1;
}
}
+ rcu_read_unlock();
if (wake_readers)
wake_up_interruptible(&mousedev->wait);
@@ -281,7 +320,8 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
{
if (!value) {
if (mousedev->touch &&
- time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) {
+ time_before(jiffies,
+ mousedev->touch + msecs_to_jiffies(tap_time))) {
/*
* Toggle left button to emulate tap.
* We rely on the fact that mousedev_mix always has 0
@@ -290,7 +330,8 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
set_bit(0, &mousedev->packet.buttons);
set_bit(0, &mousedev_mix->packet.buttons);
mousedev_notify_readers(mousedev, &mousedev_mix->packet);
- mousedev_notify_readers(mousedev_mix, &mousedev_mix->packet);
+ mousedev_notify_readers(mousedev_mix,
+ &mousedev_mix->packet);
clear_bit(0, &mousedev->packet.buttons);
clear_bit(0, &mousedev_mix->packet.buttons);
}
@@ -302,54 +343,61 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
mousedev->touch = jiffies;
}
-static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+static void mousedev_event(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
{
struct mousedev *mousedev = handle->private;
switch (type) {
- case EV_ABS:
- /* Ignore joysticks */
- if (test_bit(BTN_TRIGGER, handle->dev->keybit))
- return;
- if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
- mousedev_touchpad_event(handle->dev, mousedev, code, value);
- else
- mousedev_abs_event(handle->dev, mousedev, code, value);
+ case EV_ABS:
+ /* Ignore joysticks */
+ if (test_bit(BTN_TRIGGER, handle->dev->keybit))
+ return;
- break;
+ if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
+ mousedev_touchpad_event(handle->dev,
+ mousedev, code, value);
+ else
+ mousedev_abs_event(handle->dev, mousedev, code, value);
- case EV_REL:
- mousedev_rel_event(mousedev, code, value);
- break;
+ break;
- case EV_KEY:
- if (value != 2) {
- if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
- mousedev_touchpad_touch(mousedev, value);
- else
- mousedev_key_event(mousedev, code, value);
- }
- break;
+ case EV_REL:
+ mousedev_rel_event(mousedev, code, value);
+ break;
- case EV_SYN:
- if (code == SYN_REPORT) {
- if (mousedev->touch) {
- mousedev->pkt_count++;
- /* Input system eats duplicate events, but we need all of them
- * to do correct averaging so apply present one forward
- */
- fx(0) = fx(1);
- fy(0) = fy(1);
- }
-
- mousedev_notify_readers(mousedev, &mousedev->packet);
- mousedev_notify_readers(mousedev_mix, &mousedev->packet);
-
- mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
- mousedev->packet.abs_event = 0;
+ case EV_KEY:
+ if (value != 2) {
+ if (code == BTN_TOUCH &&
+ test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
+ mousedev_touchpad_touch(mousedev, value);
+ else
+ mousedev_key_event(mousedev, code, value);
+ }
+ break;
+
+ case EV_SYN:
+ if (code == SYN_REPORT) {
+ if (mousedev->touch) {
+ mousedev->pkt_count++;
+ /*
+ * Input system eats duplicate events,
+ * but we need all of them to do correct
+ * averaging so apply present one forward
+ */
+ fx(0) = fx(1);
+ fy(0) = fy(1);
}
- break;
+
+ mousedev_notify_readers(mousedev, &mousedev->packet);
+ mousedev_notify_readers(mousedev_mix, &mousedev->packet);
+
+ mousedev->packet.dx = mousedev->packet.dy =
+ mousedev->packet.dz = 0;
+ mousedev->packet.abs_event = 0;
+ }
+ break;
}
}
@@ -367,41 +415,48 @@ static void mousedev_free(struct device *dev)
{
struct mousedev *mousedev = container_of(dev, struct mousedev, dev);
- mousedev_table[mousedev->minor] = NULL;
kfree(mousedev);
}
-static int mixdev_add_device(struct mousedev *mousedev)
+static int mousedev_open_device(struct mousedev *mousedev)
{
- int error;
+ int retval;
- if (mousedev_mix->open) {
- error = input_open_device(&mousedev->handle);
- if (error)
- return error;
+ retval = mutex_lock_interruptible(&mousedev->mutex);
+ if (retval)
+ return retval;
- mousedev->open++;
- mousedev->mixdev_open = 1;
+ if (mousedev->minor == MOUSEDEV_MIX)
+ mixdev_open_devices();
+ else if (!mousedev->exist)
+ retval = -ENODEV;
+ else if (!mousedev->open++) {
+ retval = input_open_device(&mousedev->handle);
+ if (retval)
+ mousedev->open--;
}
- get_device(&mousedev->dev);
- list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
-
- return 0;
+ mutex_unlock(&mousedev->mutex);
+ return retval;
}
-static void mixdev_remove_device(struct mousedev *mousedev)
+static void mousedev_close_device(struct mousedev *mousedev)
{
- if (mousedev->mixdev_open) {
- mousedev->mixdev_open = 0;
- if (!--mousedev->open && mousedev->exist)
- input_close_device(&mousedev->handle);
- }
+ mutex_lock(&mousedev->mutex);
- list_del_init(&mousedev->mixdev_node);
- put_device(&mousedev->dev);
+ if (mousedev->minor == MOUSEDEV_MIX)
+ mixdev_close_devices();
+ else if (mousedev->exist && !--mousedev->open)
+ input_close_device(&mousedev->handle);
+
+ mutex_unlock(&mousedev->mutex);
}
+/*
+ * Open all available devices so they can all be multiplexed in one.
+ * stream. Note that this function is called with mousedev_mix->mutex
+ * held.
+ */
static void mixdev_open_devices(void)
{
struct mousedev *mousedev;
@@ -411,16 +466,19 @@ static void mixdev_open_devices(void)
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
if (!mousedev->mixdev_open) {
- if (!mousedev->open && mousedev->exist)
- if (input_open_device(&mousedev->handle))
- continue;
+ if (mousedev_open_device(mousedev))
+ continue;
- mousedev->open++;
mousedev->mixdev_open = 1;
}
}
}
+/*
+ * Close all devices that were opened as part of multiplexed
+ * device. Note that this function is called with mousedev_mix->mutex
+ * held.
+ */
static void mixdev_close_devices(void)
{
struct mousedev *mousedev;
@@ -431,33 +489,45 @@ static void mixdev_close_devices(void)
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
if (mousedev->mixdev_open) {
mousedev->mixdev_open = 0;
- if (!--mousedev->open && mousedev->exist)
- input_close_device(&mousedev->handle);
+ mousedev_close_device(mousedev);
}
}
}
+
+static void mousedev_attach_client(struct mousedev *mousedev,
+ struct mousedev_client *client)
+{
+ spin_lock(&mousedev->client_lock);
+ list_add_tail_rcu(&client->node, &mousedev->client_list);
+ spin_unlock(&mousedev->client_lock);
+ synchronize_rcu();
+}
+
+static void mousedev_detach_client(struct mousedev *mousedev,
+ struct mousedev_client *client)
+{
+ spin_lock(&mousedev->client_lock);
+ list_del_rcu(&client->node);
+ spin_unlock(&mousedev->client_lock);
+ synchronize_rcu();
+}
+
static int mousedev_release(struct inode *inode, struct file *file)
{
struct mousedev_client *client = file->private_data;
struct mousedev *mousedev = client->mousedev;
mousedev_fasync(-1, file, 0);
-
- list_del(&client->node);
+ mousedev_detach_client(mousedev, client);
kfree(client);
- if (mousedev->minor == MOUSEDEV_MIX)
- mixdev_close_devices();
- else if (!--mousedev->open && mousedev->exist)
- input_close_device(&mousedev->handle);
-
+ mousedev_close_device(mousedev);
put_device(&mousedev->dev);
return 0;
}
-
static int mousedev_open(struct inode *inode, struct file *file)
{
struct mousedev_client *client;
@@ -475,12 +545,17 @@ static int mousedev_open(struct inode *inode, struct file *file)
if (i >= MOUSEDEV_MINORS)
return -ENODEV;
+ error = mutex_lock_interruptible(&mousedev_table_mutex);
+ if (error)
+ return error;
mousedev = mousedev_table[i];
+ if (mousedev)
+ get_device(&mousedev->dev);
+ mutex_unlock(&mousedev_table_mutex);
+
if (!mousedev)
return -ENODEV;
- get_device(&mousedev->dev);
-
client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
if (!client) {
error = -ENOMEM;
@@ -491,21 +566,17 @@ static int mousedev_open(struct inode *inode, struct file *file)
client->pos_x = xres / 2;
client->pos_y = yres / 2;
client->mousedev = mousedev;
- list_add_tail(&client->node, &mousedev->client_list);
+ mousedev_attach_client(mousedev, client);
- if (mousedev->minor == MOUSEDEV_MIX)
- mixdev_open_devices();
- else if (!mousedev->open++ && mousedev->exist) {
- error = input_open_device(&mousedev->handle);
- if (error)
- goto err_free_client;
- }
+ error = mousedev_open_device(mousedev);
+ if (error)
+ goto err_free_client;
file->private_data = client;
return 0;
err_free_client:
- list_del(&client->node);
+ mousedev_detach_client(mousedev, client);
kfree(client);
err_put_mousedev:
put_device(&mousedev->dev);
@@ -517,41 +588,41 @@ static inline int mousedev_limit_delta(int delta, int limit)
return delta > limit ? limit : (delta < -limit ? -limit : delta);
}
-static void mousedev_packet(struct mousedev_client *client, signed char *ps2_data)
+static void mousedev_packet(struct mousedev_client *client,
+ signed char *ps2_data)
{
- struct mousedev_motion *p;
- unsigned long flags;
-
- spin_lock_irqsave(&client->packet_lock, flags);
- p = &client->packets[client->tail];
+ struct mousedev_motion *p = &client->packets[client->tail];
- ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
+ ps2_data[0] = 0x08 |
+ ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
ps2_data[1] = mousedev_limit_delta(p->dx, 127);
ps2_data[2] = mousedev_limit_delta(p->dy, 127);
p->dx -= ps2_data[1];
p->dy -= ps2_data[2];
switch (client->mode) {
- case MOUSEDEV_EMUL_EXPS:
- ps2_data[3] = mousedev_limit_delta(p->dz, 7);
- p->dz -= ps2_data[3];
- ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
- client->bufsiz = 4;
- break;
-
- case MOUSEDEV_EMUL_IMPS:
- ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
- ps2_data[3] = mousedev_limit_delta(p->dz, 127);
- p->dz -= ps2_data[3];
- client->bufsiz = 4;
- break;
-
- case MOUSEDEV_EMUL_PS2:
- default:
- ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
- p->dz = 0;
- client->bufsiz = 3;
- break;
+ case MOUSEDEV_EMUL_EXPS:
+ ps2_data[3] = mousedev_limit_delta(p->dz, 7);
+ p->dz -= ps2_data[3];
+ ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
+ client->bufsiz = 4;
+ break;
+
+ case MOUSEDEV_EMUL_IMPS:
+ ps2_data[0] |=
+ ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
+ ps2_data[3] = mousedev_limit_delta(p->dz, 127);
+ p->dz -= ps2_data[3];
+ client->bufsiz = 4;
+ break;
+
+ case MOUSEDEV_EMUL_PS2:
+ default:
+ ps2_data[0] |=
+ ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
+ p->dz = 0;
+ client->bufsiz = 3;
+ break;
}
if (!p->dx && !p->dy && !p->dz) {
@@ -561,12 +632,56 @@ static void mousedev_packet(struct mousedev_client *client, signed char *ps2_dat
} else
client->tail = (client->tail + 1) % PACKET_QUEUE_LEN;
}
-
- spin_unlock_irqrestore(&client->packet_lock, flags);
}
+static void mousedev_generate_response(struct mousedev_client *client,
+ int command)
+{
+ client->ps2[0] = 0xfa; /* ACK */
+
+ switch (command) {
-static ssize_t mousedev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+ case 0xeb: /* Poll */
+ mousedev_packet(client, &client->ps2[1]);
+ client->bufsiz++; /* account for leading ACK */
+ break;
+
+ case 0xf2: /* Get ID */
+ switch (client->mode) {
+ case MOUSEDEV_EMUL_PS2:
+ client->ps2[1] = 0;
+ break;
+ case MOUSEDEV_EMUL_IMPS:
+ client->ps2[1] = 3;
+ break;
+ case MOUSEDEV_EMUL_EXPS:
+ client->ps2[1] = 4;
+ break;
+ }
+ client->bufsiz = 2;
+ break;
+
+ case 0xe9: /* Get info */
+ client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
+ client->bufsiz = 4;
+ break;
+
+ case 0xff: /* Reset */
+ client->impsseq = client->imexseq = 0;
+ client->mode = MOUSEDEV_EMUL_PS2;
+ client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
+ client->bufsiz = 3;
+ break;
+
+ default:
+ client->bufsiz = 1;
+ break;
+ }
+ client->buffer = client->bufsiz;
+}
+
+static ssize_t mousedev_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
{
struct mousedev_client *client = file->private_data;
unsigned char c;
@@ -577,6 +692,8 @@ static ssize_t mousedev_write(struct file *file, const char __user *buffer, size
if (get_user(c, buffer + i))
return -EFAULT;
+ spin_lock_irq(&client->packet_lock);
+
if (c == mousedev_imex_seq[client->imexseq]) {
if (++client->imexseq == MOUSEDEV_SEQ_LEN) {
client->imexseq = 0;
@@ -593,68 +710,39 @@ static ssize_t mousedev_write(struct file *file, const char __user *buffer, size
} else
client->impsseq = 0;
- client->ps2[0] = 0xfa;
-
- switch (c) {
-
- case 0xeb: /* Poll */
- mousedev_packet(client, &client->ps2[1]);
- client->bufsiz++; /* account for leading ACK */
- break;
-
- case 0xf2: /* Get ID */
- switch (client->mode) {
- case MOUSEDEV_EMUL_PS2: client->ps2[1] = 0; break;
- case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break;
- case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break;
- }
- client->bufsiz = 2;
- break;
-
- case 0xe9: /* Get info */
- client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
- client->bufsiz = 4;
- break;
-
- case 0xff: /* Reset */
- client->impsseq = client->imexseq = 0;
- client->mode = MOUSEDEV_EMUL_PS2;
- client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
- client->bufsiz = 3;
- break;
-
- default:
- client->bufsiz = 1;
- break;
- }
+ mousedev_generate_response(client, c);
- client->buffer = client->bufsiz;
+ spin_unlock_irq(&client->packet_lock);
}
kill_fasync(&client->fasync, SIGIO, POLL_IN);
-
wake_up_interruptible(&client->mousedev->wait);
return count;
}
-static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+static ssize_t mousedev_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
{
struct mousedev_client *client = file->private_data;
+ struct mousedev *mousedev = client->mousedev;
+ signed char data[sizeof(client->ps2)];
int retval = 0;
- if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK))
+ if (!client->ready && !client->buffer && mousedev->exist &&
+ (file->f_flags & O_NONBLOCK))
return -EAGAIN;
- retval = wait_event_interruptible(client->mousedev->wait,
- !client->mousedev->exist || client->ready || client->buffer);
-
+ retval = wait_event_interruptible(mousedev->wait,
+ !mousedev->exist || client->ready || client->buffer);
if (retval)
return retval;
- if (!client->mousedev->exist)
+ if (!mousedev->exist)
return -ENODEV;
+ spin_lock_irq(&client->packet_lock);
+
if (!client->buffer && client->ready) {
mousedev_packet(client, client->ps2);
client->buffer = client->bufsiz;
@@ -663,9 +751,12 @@ static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t coun
if (count > client->buffer)
count = client->buffer;
+ memcpy(data, client->ps2 + client->bufsiz - client->buffer, count);
client->buffer -= count;
- if (copy_to_user(buffer, client->ps2 + client->bufsiz - client->buffer - count, count))
+ spin_unlock_irq(&client->packet_lock);
+
+ if (copy_to_user(buffer, data, count))
return -EFAULT;
return count;
@@ -692,6 +783,60 @@ static const struct file_operations mousedev_fops = {
.fasync = mousedev_fasync,
};
+static int mousedev_install_chrdev(struct mousedev *mousedev)
+{
+ mousedev_table[mousedev->minor] = mousedev;
+ return 0;
+}
+
+static void mousedev_remove_chrdev(struct mousedev *mousedev)
+{
+ mutex_lock(&mousedev_table_mutex);
+ mousedev_table[mousedev->minor] = NULL;
+ mutex_unlock(&mousedev_table_mutex);
+}
+
+/*
+ * Mark device non-existent. This disables writes, ioctls and
+ * prevents new users from opening the device. Already posted
+ * blocking reads will stay, however new ones will fail.
+ */
+static void mousedev_mark_dead(struct mousedev *mousedev)
+{
+ mutex_lock(&mousedev->mutex);
+ mousedev->exist = 0;
+ mutex_unlock(&mousedev->mutex);
+}
+
+/*
+ * Wake up users waiting for IO so they can disconnect from
+ * dead device.
+ */
+static void mousedev_hangup(struct mousedev *mousedev)
+{
+ struct mousedev_client *client;
+
+ spin_lock(&mousedev->client_lock);
+ list_for_each_entry(client, &mousedev->client_list, node)
+ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+ spin_unlock(&mousedev->client_lock);
+
+ wake_up_interruptible(&mousedev->wait);
+}
+
+static void mousedev_cleanup(struct mousedev *mousedev)
+{
+ struct input_handle *handle = &mousedev->handle;
+
+ mousedev_mark_dead(mousedev);
+ mousedev_hangup(mousedev);
+ mousedev_remove_chrdev(mousedev);
+
+ /* mousedev is marked dead so no one else accesses mousedev->open */
+ if (mousedev->open)
+ input_close_device(handle);
+}
+
static struct mousedev *mousedev_create(struct input_dev *dev,
struct input_handler *handler,
int minor)
@@ -707,6 +852,10 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
INIT_LIST_HEAD(&mousedev->client_list);
INIT_LIST_HEAD(&mousedev->mixdev_node);
+ spin_lock_init(&mousedev->client_lock);
+ mutex_init(&mousedev->mutex);
+ lockdep_set_subclass(&mousedev->mutex,
+ minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0);
init_waitqueue_head(&mousedev->wait);
if (minor == MOUSEDEV_MIX)
@@ -731,14 +880,27 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
mousedev->dev.release = mousedev_free;
device_initialize(&mousedev->dev);
- mousedev_table[minor] = mousedev;
+ if (minor != MOUSEDEV_MIX) {
+ error = input_register_handle(&mousedev->handle);
+ if (error)
+ goto err_free_mousedev;
+ }
+
+ error = mousedev_install_chrdev(mousedev);
+ if (error)
+ goto err_unregister_handle;
error = device_add(&mousedev->dev);
if (error)
- goto err_free_mousedev;
+ goto err_cleanup_mousedev;
return mousedev;
+ err_cleanup_mousedev:
+ mousedev_cleanup(mousedev);
+ err_unregister_handle:
+ if (minor != MOUSEDEV_MIX)
+ input_unregister_handle(&mousedev->handle);
err_free_mousedev:
put_device(&mousedev->dev);
err_out:
@@ -747,29 +909,64 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
static void mousedev_destroy(struct mousedev *mousedev)
{
- struct mousedev_client *client;
-
device_del(&mousedev->dev);
- mousedev->exist = 0;
+ mousedev_cleanup(mousedev);
+ if (mousedev->minor != MOUSEDEV_MIX)
+ input_unregister_handle(&mousedev->handle);
+ put_device(&mousedev->dev);
+}
- if (mousedev->open) {
- input_close_device(&mousedev->handle);
- list_for_each_entry(client, &mousedev->client_list, node)
- kill_fasync(&client->fasync, SIGIO, POLL_HUP);
- wake_up_interruptible(&mousedev->wait);
+static int mixdev_add_device(struct mousedev *mousedev)
+{
+ int retval;
+
+ retval = mutex_lock_interruptible(&mousedev_mix->mutex);
+ if (retval)
+ return retval;
+
+ if (mousedev_mix->open) {
+ retval = mousedev_open_device(mousedev);
+ if (retval)
+ goto out;
+
+ mousedev->mixdev_open = 1;
}
+ get_device(&mousedev->dev);
+ list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
+
+ out:
+ mutex_unlock(&mousedev_mix->mutex);
+ return retval;
+}
+
+static void mixdev_remove_device(struct mousedev *mousedev)
+{
+ mutex_lock(&mousedev_mix->mutex);
+
+ if (mousedev->mixdev_open) {
+ mousedev->mixdev_open = 0;
+ mousedev_close_device(mousedev);
+ }
+
+ list_del_init(&mousedev->mixdev_node);
+ mutex_unlock(&mousedev_mix->mutex);
+
put_device(&mousedev->dev);
}
-static int mousedev_connect(struct input_handler *handler, struct input_dev *dev,
+static int mousedev_connect(struct input_handler *handler,
+ struct input_dev *dev,
const struct input_device_id *id)
{
struct mousedev *mousedev;
int minor;
int error;
- for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
+ for (minor = 0; minor < MOUSEDEV_MINORS; minor++)
+ if (!mousedev_table[minor])
+ break;
+
if (minor == MOUSEDEV_MINORS) {
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
return -ENFILE;
@@ -779,21 +976,13 @@ static int mousedev_connect(struct input_handler *handler, struct input_dev *dev
if (IS_ERR(mousedev))
return PTR_ERR(mousedev);
- error = input_register_handle(&mousedev->handle);
- if (error)
- goto err_delete_mousedev;
-
error = mixdev_add_device(mousedev);
- if (error)
- goto err_unregister_handle;
+ if (error) {
+ mousedev_destroy(mousedev);
+ return error;
+ }
return 0;
-
- err_unregister_handle:
- input_unregister_handle(&mousedev->handle);
- err_delete_mousedev:
- device_unregister(&mousedev->dev);
- return error;
}
static void mousedev_disconnect(struct input_handle *handle)
@@ -801,33 +990,44 @@ static void mousedev_disconnect(struct input_handle *handle)
struct mousedev *mousedev = handle->private;
mixdev_remove_device(mousedev);
- input_unregister_handle(handle);
mousedev_destroy(mousedev);
}
static const struct input_device_id mousedev_ids[] = {
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
- .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
- .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
- .relbit = { BIT(REL_X) | BIT(REL_Y) },
- }, /* A mouse like device, at least one button, two relative axes */
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT |
+ INPUT_DEVICE_ID_MATCH_RELBIT,
+ .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
+ .keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },
+ .relbit = { BIT_MASK(REL_X) | BIT_MASK(REL_Y) },
+ }, /* A mouse like device, at least one button,
+ two relative axes */
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
- .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
- .relbit = { BIT(REL_WHEEL) },
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_RELBIT,
+ .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) },
+ .relbit = { BIT_MASK(REL_WHEEL) },
}, /* A separate scrollwheel */
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
- .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
- .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
- .absbit = { BIT(ABS_X) | BIT(ABS_Y) },
- }, /* A tablet like device, at least touch detection, two absolute axes */
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
+ .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
+ .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
+ }, /* A tablet like device, at least touch detection,
+ two absolute axes */
{
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
- .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
- .keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) },
- .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) },
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+ INPUT_DEVICE_ID_MATCH_KEYBIT |
+ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
+ .keybit = { [BIT_WORD(BTN_TOOL_FINGER)] =
+ BIT_MASK(BTN_TOOL_FINGER) },
+ .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
+ BIT_MASK(ABS_PRESSURE) |
+ BIT_MASK(ABS_TOOL_WIDTH) },
}, /* A touchpad */
{ }, /* Terminating entry */
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index 6af199805ff..02b3ad8c082 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -944,11 +944,7 @@ static int __init hp_sdc_init_hppa(struct parisc_device *d)
#endif /* __hppa__ */
-#if !defined(__mc68000__) /* Link error on m68k! */
-static void __exit hp_sdc_exit(void)
-#else
static void hp_sdc_exit(void)
-#endif
{
write_lock_irq(&hp_sdc.lock);
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index c2eea2767e1..1a0cea3c529 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/rcupdate.h>
#include <linux/platform_device.h>
+#include <linux/i8042.h>
#include <asm/io.h>
@@ -208,7 +209,7 @@ static int __i8042_command(unsigned char *param, int command)
return 0;
}
-static int i8042_command(unsigned char *param, int command)
+int i8042_command(unsigned char *param, int command)
{
unsigned long flags;
int retval;
@@ -219,6 +220,7 @@ static int i8042_command(unsigned char *param, int command)
return retval;
}
+EXPORT_SYMBOL(i8042_command);
/*
* i8042_kbd_write() sends a byte out through the keyboard interface.
@@ -385,6 +387,8 @@ static int i8042_enable_kbd_port(void)
i8042_ctr |= I8042_CTR_KBDINT;
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");
return -EIO;
}
@@ -402,6 +406,8 @@ static int i8042_enable_aux_port(void)
i8042_ctr |= I8042_CTR_AUXINT;
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");
return -EIO;
}
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
index b3eb7a72d96..dd22d91f8b3 100644
--- a/drivers/input/serio/i8042.h
+++ b/drivers/input/serio/i8042.h
@@ -61,28 +61,6 @@
#define I8042_CTR_XLATE 0x40
/*
- * Commands.
- */
-
-#define I8042_CMD_CTL_RCTR 0x0120
-#define I8042_CMD_CTL_WCTR 0x1060
-#define I8042_CMD_CTL_TEST 0x01aa
-
-#define I8042_CMD_KBD_DISABLE 0x00ad
-#define I8042_CMD_KBD_ENABLE 0x00ae
-#define I8042_CMD_KBD_TEST 0x01ab
-#define I8042_CMD_KBD_LOOP 0x11d2
-
-#define I8042_CMD_AUX_DISABLE 0x00a7
-#define I8042_CMD_AUX_ENABLE 0x00a8
-#define I8042_CMD_AUX_TEST 0x01a9
-#define I8042_CMD_AUX_SEND 0x10d4
-#define I8042_CMD_AUX_LOOP 0x11d3
-
-#define I8042_CMD_MUX_PFX 0x0090
-#define I8042_CMD_MUX_SEND 0x1090
-
-/*
* Return codes.
*/
diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
index 688610e86a3..b089977e0ef 100644
--- a/drivers/input/serio/parkbd.c
+++ b/drivers/input/serio/parkbd.c
@@ -102,7 +102,7 @@ static int parkbd_write(struct serio *port, unsigned char c)
return 0;
}
-static void parkbd_interrupt(int irq, void *dev_id)
+static void parkbd_interrupt(void *dev_id)
{
if (parkbd_writing) {
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 372ca493119..7f5293828fb 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -387,9 +387,8 @@ static int serio_thread(void *nothing)
set_freezable();
do {
serio_handle_event();
- wait_event_interruptible(serio_wait,
+ wait_event_freezable(serio_wait,
kthread_should_stop() || !list_empty(&serio_event_list));
- try_to_freeze();
} while (!kthread_should_stop());
printk(KERN_DEBUG "serio: kseriod exiting\n");
@@ -876,18 +875,14 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv)
#define SERIO_ADD_UEVENT_VAR(fmt, val...) \
do { \
- int err = add_uevent_var(envp, num_envp, &i, \
- buffer, buffer_size, &len, \
- fmt, val); \
+ int err = add_uevent_var(env, fmt, val); \
if (err) \
return err; \
} while (0)
-static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct serio *serio;
- int i = 0;
- int len = 0;
if (!dev)
return -ENODEV;
@@ -900,7 +895,6 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf
SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra);
SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X",
serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
- envp[i] = NULL;
return 0;
}
@@ -908,7 +902,7 @@ static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buf
#else
-static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c
index dd2310458c4..b973d0ef6d1 100644
--- a/drivers/input/tablet/acecad.c
+++ b/drivers/input/tablet/acecad.c
@@ -192,10 +192,14 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
input_dev->open = usb_acecad_open;
input_dev->close = usb_acecad_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
- input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- input_dev->keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input_dev->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
+ BIT_MASK(ABS_PRESSURE);
+ input_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
+ input_dev->keybit[BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_TOOL_PEN) |
+ BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS) |
+ BIT_MASK(BTN_STYLUS2);
switch (id->driver_info) {
case 0:
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index b2ca10f2fe0..d2c6da26472 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -573,10 +573,12 @@ static void gtco_setup_caps(struct input_dev *inputdev)
struct gtco *device = input_get_drvdata(inputdev);
/* Which events */
- inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+ inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) |
+ BIT_MASK(EV_MSC);
/* Misc event menu block */
- inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
+ inputdev->mscbit[0] = BIT_MASK(MSC_SCAN) | BIT_MASK(MSC_SERIAL) |
+ BIT_MASK(MSC_RAW);
/* Absolute values based on HID report info */
input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
index 91e6d00d4a4..1182fc13316 100644
--- a/drivers/input/tablet/kbtab.c
+++ b/drivers/input/tablet/kbtab.c
@@ -153,10 +153,13 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
input_dev->open = kbtab_open;
input_dev->close = kbtab_close;
- input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH);
- input_dev->mscbit[0] |= BIT(MSC_SERIAL);
+ input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) |
+ BIT_MASK(EV_MSC);
+ input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
+ input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) |
+ BIT_MASK(BTN_TOUCH);
+ input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0);
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 064e123c9b7..d64b1ea136b 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -140,48 +140,58 @@ static void wacom_close(struct input_dev *dev)
void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_1) | BIT(BTN_5);
+ input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_1) |
+ BIT_MASK(BTN_5);
input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
}
void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
- input_dev->evbit[0] |= BIT(EV_MSC);
- input_dev->mscbit[0] |= BIT(MSC_SERIAL);
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_4);
+ input_dev->evbit[0] |= BIT_MASK(EV_MSC);
+ input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
+ input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_FINGER);
+ input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_0) |
+ BIT_MASK(BTN_4);
}
void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
- input_dev->evbit[0] |= BIT(EV_REL);
- input_dev->relbit[0] |= BIT(REL_WHEEL);
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
+ input_dev->evbit[0] |= BIT_MASK(EV_REL);
+ input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);
+ input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
+ input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) |
+ BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_STYLUS2);
input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
}
void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3);
+ input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_FINGER);
+ input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_0) |
+ BIT_MASK(BTN_1) | BIT_MASK(BTN_2) | BIT_MASK(BTN_3);
input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
}
void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
+ input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_4) |
+ BIT_MASK(BTN_5) | BIT_MASK(BTN_6) | BIT_MASK(BTN_7);
input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
}
void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
- input_dev->evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
- input_dev->mscbit[0] |= BIT(MSC_SERIAL);
- input_dev->relbit[0] |= BIT(REL_WHEEL);
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH)
- | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2);
+ input_dev->evbit[0] |= BIT_MASK(EV_MSC) | BIT_MASK(EV_REL);
+ input_dev->mscbit[0] |= BIT_MASK(MSC_SERIAL);
+ input_dev->relbit[0] |= BIT_MASK(REL_WHEEL);
+ input_dev->keybit[BIT_WORD(BTN_LEFT)] |= BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE) |
+ BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
+ input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER) |
+ BIT_MASK(BTN_TOOL_MOUSE) | BIT_MASK(BTN_TOOL_BRUSH) |
+ BIT_MASK(BTN_TOOL_PENCIL) | BIT_MASK(BTN_TOOL_AIRBRUSH) |
+ BIT_MASK(BTN_TOOL_LENS) | BIT_MASK(BTN_STYLUS2);
input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
@@ -192,12 +202,13 @@ void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
+ input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_STYLUS2) |
+ BIT_MASK(BTN_TOOL_RUBBER);
}
void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
{
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER);
+ input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_RUBBER);
}
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -243,12 +254,13 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
input_dev->open = wacom_open;
input_dev->close = wacom_close;
- input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
+ input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_PEN) |
+ BIT_MASK(BTN_TOUCH) | BIT_MASK(BTN_STYLUS);
input_set_abs_params(input_dev, ABS_X, 0, wacom_wac->features->x_max, 4, 0);
input_set_abs_params(input_dev, ABS_Y, 0, wacom_wac->features->y_max, 4, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom_wac->features->pressure_max, 0, 0);
- input_dev->absbit[LONG(ABS_MISC)] |= BIT(ABS_MISC);
+ input_dev->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
wacom_init_input_dev(input_dev, wacom_wac);
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index f929fcdbae2..fa8442b6241 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -126,6 +126,16 @@ config TOUCHSCREEN_HP600
To compile this driver as a module, choose M here: the
module will be called hp680_ts_input.
+config TOUCHSCREEN_HP7XX
+ tristate "HP Jornada 710/720/728 touchscreen"
+ depends on SA1100_JORNADA720_SSP
+ help
+ Say Y here if you have a HP Jornada 710/720/728 and want
+ to support the built-in touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jornada720_ts.
+
config TOUCHSCREEN_PENMOUNT
tristate "Penmount serial touchscreen"
select SERIO
@@ -191,6 +201,8 @@ config TOUCHSCREEN_USB_COMPOSITE
- Gunze AHL61
- DMC TSC-10/25
- IRTOUCHSYSTEMS/UNITOP
+ - IdealTEK URTC1000
+ - GoTop Super_Q2/GogoPen/PenPower tablets
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
@@ -238,4 +250,19 @@ config TOUCHSCREEN_USB_IRTOUCH
bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
+config TOUCHSCREEN_USB_IDEALTEK
+ default y
+ bool "IdealTEK URTC1000 device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_GENERAL_TOUCH
+ default y
+ bool "GeneralTouch Touchscreen device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_GOTOP
+ default y
+ bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 5de8933c499..35d4097df35 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 96581d08774..f59aecf5ec1 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -83,7 +83,7 @@ struct ads7846 {
#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
struct attribute_group *attr_group;
- struct class_device *hwmon;
+ struct device *hwmon;
#endif
u16 model;
@@ -369,7 +369,7 @@ static struct attribute_group ads7845_attr_group = {
static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
{
- struct class_device *hwmon;
+ struct device *hwmon;
int err;
/* hwmon sensors need a reference voltage */
@@ -917,8 +917,8 @@ static int __devinit ads7846_probe(struct spi_device *spi)
input_dev->phys = ts->phys;
input_dev->dev.parent = &spi->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ 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,
pdata->x_min ? : 0,
pdata->x_max ? : MAX_12BIT,
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index e6a31d11878..b1b2e07bf08 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -302,8 +302,8 @@ static int __init corgits_probe(struct platform_device *pdev)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &pdev->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ 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, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0);
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 557d781719f..d20689cdbd5 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -320,8 +320,8 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
serio_set_drvdata(serio, elo);
err = serio_open(serio, drv);
diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c
index daf7a4afc93..80b21800355 100644
--- a/drivers/input/touchscreen/fujitsu_ts.c
+++ b/drivers/input/touchscreen/fujitsu_ts.c
@@ -122,8 +122,8 @@ static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = SERIO_FUJITSU;
input_dev->id.product = 0;
input_dev->id.version = 0x0100;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ 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, 4096, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 4096, 0, 0);
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index 39d602600d7..a48a15868c4 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -137,8 +137,8 @@ static int gunze_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.product = 0x0051;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ 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, 24, 1000, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 24, 1000, 0, 0);
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index 09ed7803cb8..2ae6c6016a8 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -373,8 +373,9 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
input_dev->event = h3600ts_event;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_LED) | BIT(EV_PWR);
- input_dev->ledbit[0] = BIT(LED_SLEEP);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) |
+ BIT_MASK(EV_LED) | BIT_MASK(EV_PWR);
+ input_dev->ledbit[0] = BIT_MASK(LED_SLEEP);
input_set_abs_params(input_dev, ABS_X, 60, 985, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 35, 1024, 0, 0);
diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
index 1a15475aedf..c38d4e0f95c 100644
--- a/drivers/input/touchscreen/hp680_ts_input.c
+++ b/drivers/input/touchscreen/hp680_ts_input.c
@@ -81,8 +81,8 @@ static int __init hp680_ts_init(void)
if (!hp680_ts_dev)
return -ENOMEM;
- hp680_ts_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
- hp680_ts_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ hp680_ts_dev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
+ hp680_ts_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(hp680_ts_dev, ABS_X,
HP680_TS_ABS_X_MIN, HP680_TS_ABS_X_MAX, 0, 0);
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c
new file mode 100644
index 00000000000..42a1c9a1940
--- /dev/null
+++ b/drivers/input/touchscreen/jornada720_ts.c
@@ -0,0 +1,182 @@
+/*
+ * drivers/input/touchscreen/jornada720_ts.c
+ *
+ * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
+ *
+ * Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
+ * based on HP Jornada 56x touchscreen driver by Alex Lange <chicken@handhelds.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.
+ *
+ * HP Jornada 710/720/729 Touchscreen Driver
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/jornada720.h>
+
+MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>");
+MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver");
+MODULE_LICENSE("GPLv2");
+
+struct jornada_ts {
+ struct input_dev *dev;
+ int x_data[4]; /* X sample values */
+ int y_data[4]; /* Y sample values */
+};
+
+static void jornada720_ts_collect_data(struct jornada_ts *jornada_ts)
+{
+
+ /* 3 low word X samples */
+ jornada_ts->x_data[0] = jornada_ssp_byte(TXDUMMY);
+ jornada_ts->x_data[1] = jornada_ssp_byte(TXDUMMY);
+ jornada_ts->x_data[2] = jornada_ssp_byte(TXDUMMY);
+
+ /* 3 low word Y samples */
+ jornada_ts->y_data[0] = jornada_ssp_byte(TXDUMMY);
+ jornada_ts->y_data[1] = jornada_ssp_byte(TXDUMMY);
+ jornada_ts->y_data[2] = jornada_ssp_byte(TXDUMMY);
+
+ /* combined x samples bits */
+ jornada_ts->x_data[3] = jornada_ssp_byte(TXDUMMY);
+
+ /* combined y samples bits */
+ jornada_ts->y_data[3] = jornada_ssp_byte(TXDUMMY);
+}
+
+static int jornada720_ts_average(int coords[4])
+{
+ int coord, high_bits = coords[3];
+
+ coord = coords[0] | ((high_bits & 0x03) << 8);
+ coord += coords[1] | ((high_bits & 0x0c) << 6);
+ coord += coords[2] | ((high_bits & 0x30) << 4);
+
+ return coord / 3;
+}
+
+static irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
+ struct input_dev *input = jornada_ts->dev;
+ int x, y;
+
+ /* If GPIO_GPIO9 is set to high then report pen up */
+ if (GPLR & GPIO_GPIO(9)) {
+ input_report_key(input, BTN_TOUCH, 0);
+ input_sync(input);
+ } else {
+ jornada_ssp_start();
+
+ /* proper reply to request is always TXDUMMY */
+ if (jornada_ssp_inout(GETTOUCHSAMPLES) == TXDUMMY) {
+ jornada720_ts_collect_data(jornada_ts);
+
+ x = jornada720_ts_average(jornada_ts->x_data);
+ y = jornada720_ts_average(jornada_ts->y_data);
+
+ input_report_key(input, BTN_TOUCH, 1);
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ input_sync(input);
+ }
+
+ jornada_ssp_end();
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit jornada720_ts_probe(struct platform_device *pdev)
+{
+ struct jornada_ts *jornada_ts;
+ struct input_dev *input_dev;
+ int error;
+
+ jornada_ts = kzalloc(sizeof(struct jornada_ts), GFP_KERNEL);
+ input_dev = input_allocate_device();
+
+ if (!jornada_ts || !input_dev) {
+ error = -ENOMEM;
+ goto fail1;
+ }
+
+ platform_set_drvdata(pdev, jornada_ts);
+
+ jornada_ts->dev = input_dev;
+
+ input_dev->name = "HP Jornada 7xx Touchscreen";
+ input_dev->phys = "jornadats/input0";
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->dev.parent = &pdev->dev;
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0);
+
+ error = request_irq(IRQ_GPIO9,
+ jornada720_ts_interrupt,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING,
+ "HP7XX Touchscreen driver", pdev);
+ if (error) {
+ printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n");
+ goto fail1;
+ }
+
+ error = input_register_device(jornada_ts->dev);
+ if (error)
+ goto fail2;
+
+ return 0;
+
+ fail2:
+ free_irq(IRQ_GPIO9, pdev);
+ fail1:
+ platform_set_drvdata(pdev, NULL);
+ input_free_device(input_dev);
+ kfree(jornada_ts);
+ return error;
+}
+
+static int __devexit jornada720_ts_remove(struct platform_device *pdev)
+{
+ struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
+
+ free_irq(IRQ_GPIO9, pdev);
+ platform_set_drvdata(pdev, NULL);
+ input_unregister_device(jornada_ts->dev);
+ kfree(jornada_ts);
+
+ return 0;
+}
+
+static struct platform_driver jornada720_ts_driver = {
+ .probe = jornada720_ts_probe,
+ .remove = __devexit_p(jornada720_ts_remove),
+ .driver = {
+ .name = "jornada_ts",
+ },
+};
+
+static int __init jornada720_ts_init(void)
+{
+ return platform_driver_register(&jornada720_ts_driver);
+}
+
+static void __exit jornada720_ts_exit(void)
+{
+ platform_driver_unregister(&jornada720_ts_driver);
+}
+
+module_init(jornada720_ts_init);
+module_exit(jornada720_ts_exit);
diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
index 44140feeffc..80a65886870 100644
--- a/drivers/input/touchscreen/mk712.c
+++ b/drivers/input/touchscreen/mk712.c
@@ -186,8 +186,8 @@ static int __init mk712_init(void)
mk712_dev->open = mk712_open;
mk712_dev->close = mk712_close;
- mk712_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- mk712_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ mk712_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ mk712_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(mk712_dev, ABS_X, 0, 0xfff, 88, 0);
input_set_abs_params(mk712_dev, ABS_Y, 0, 0xfff, 88, 0);
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
index 4ec3b1f940c..9077228418b 100644
--- a/drivers/input/touchscreen/mtouch.c
+++ b/drivers/input/touchscreen/mtouch.c
@@ -151,8 +151,8 @@ static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.product = 0;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ 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(mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0);
input_set_abs_params(mtouch->dev, ABS_Y, MTOUCH_MIN_YC, MTOUCH_MAX_YC, 0, 0);
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c
index f2c0d3c7149..c7f9cebebbb 100644
--- a/drivers/input/touchscreen/penmount.c
+++ b/drivers/input/touchscreen/penmount.c
@@ -113,8 +113,8 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ 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(pm->dev, ABS_X, 0, 0x3ff, 0, 0);
input_set_abs_params(pm->dev, ABS_Y, 0, 0x3ff, 0, 0);
diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c
index 3def7bb1df4..3a5c142c2a7 100644
--- a/drivers/input/touchscreen/touchright.c
+++ b/drivers/input/touchscreen/touchright.c
@@ -125,8 +125,8 @@ static int tr_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.product = 0;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ 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(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0);
input_set_abs_params(tr->dev, ABS_Y, TR_MIN_YC, TR_MAX_YC, 0, 0);
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c
index ac4bdcf1866..763a656a59f 100644
--- a/drivers/input/touchscreen/touchwin.c
+++ b/drivers/input/touchscreen/touchwin.c
@@ -132,8 +132,8 @@ static int tw_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.product = 0;
input_dev->id.version = 0x0100;
input_dev->dev.parent = &serio->dev;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ 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(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0);
input_set_abs_params(tw->dev, ABS_Y, TW_MIN_YC, TW_MAX_YC, 0, 0);
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index 36f94401915..7549939b953 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -130,8 +130,7 @@ static unsigned int ucb1400_adc_read(struct ucb1400 *ucb, u16 adc_channel)
if (val & UCB_ADC_DAT_VALID)
break;
/* yield to other processes */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_timeout_uninterruptible(1);
}
return UCB_ADC_DAT_VALUE(val);
@@ -334,10 +333,9 @@ static int ucb1400_ts_thread(void *_ucb)
timeout = msecs_to_jiffies(10);
}
- wait_event_interruptible_timeout(ucb->ts_wait,
+ wait_event_freezable_timeout(ucb->ts_wait,
ucb->irq_pending || ucb->ts_restart || kthread_should_stop(),
timeout);
- try_to_freeze();
}
/* Send the "pen off" if we are stopping with the pen still active */
@@ -519,7 +517,7 @@ static int ucb1400_ts_probe(struct device *dev)
idev->id.product = id;
idev->open = ucb1400_ts_open;
idev->close = ucb1400_ts_close;
- idev->evbit[0] = BIT(EV_ABS);
+ idev->evbit[0] = BIT_MASK(EV_ABS);
ucb1400_adc_enable(ucb);
x_res = ucb1400_ts_read_xres(ucb);
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 741f6c6f1e5..19055e7381f 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -10,8 +10,10 @@
* - Gunze AHL61
* - DMC TSC-10/25
* - IRTOUCHSYSTEMS/UNITOP
+ * - IdealTEK URTC1000
+ * - GoTop Super_Q2/GogoPen/PenPower tablets
*
- * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch>
+ * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
*
* This program is free software; you can redistribute it and/or
@@ -92,7 +94,7 @@ struct usbtouch_usb {
};
-#if defined(CONFIG_TOUCHSCREEN_USB_EGALAX) || defined(CONFIG_TOUCHSCREEN_USB_ETURBO)
+#if defined(CONFIG_TOUCHSCREEN_USB_EGALAX) || defined(CONFIG_TOUCHSCREEN_USB_ETURBO) || defined(CONFIG_TOUCHSCREEN_USB_IDEALTEK)
#define MULTI_PACKET
#endif
@@ -112,6 +114,9 @@ enum {
DEVTYPE_GUNZE,
DEVTYPE_DMC_TSC10,
DEVTYPE_IRTOUCH,
+ DEVTYPE_IDEALTEK,
+ DEVTYPE_GENERAL_TOUCH,
+ DEVTYPE_GOTOP,
};
static struct usb_device_id usbtouch_devices[] = {
@@ -157,6 +162,20 @@ static struct usb_device_id usbtouch_devices[] = {
{USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
#endif
+#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
+ {USB_DEVICE(0x1391, 0x1000), .driver_info = DEVTYPE_IDEALTEK},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
+ {USB_DEVICE(0x0dfc, 0x0001), .driver_info = DEVTYPE_GENERAL_TOUCH},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
+ {USB_DEVICE(0x08f2, 0x007f), .driver_info = DEVTYPE_GOTOP},
+ {USB_DEVICE(0x08f2, 0x00ce), .driver_info = DEVTYPE_GOTOP},
+ {USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP},
+#endif
+
{}
};
@@ -396,7 +415,8 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
if (ret < 0)
return ret;
- if (buf[0] != 0x06 || buf[1] != 0x00)
+ if ((buf[0] != 0x06 || buf[1] != 0x00) &&
+ (buf[0] != 0x15 || buf[1] != 0x01))
return -ENODEV;
/* start sending data */
@@ -438,6 +458,71 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
/*****************************************************************************
+ * IdealTEK URTC1000 Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
+static int idealtek_get_pkt_len(unsigned char *buf, int len)
+{
+ if (buf[0] & 0x80)
+ return 5;
+ if (buf[0] == 0x01)
+ return len;
+ return 0;
+}
+
+static int idealtek_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+ switch (pkt[0] & 0x98) {
+ case 0x88:
+ /* touch data in IdealTEK mode */
+ dev->x = (pkt[1] << 5) | (pkt[2] >> 2);
+ dev->y = (pkt[3] << 5) | (pkt[4] >> 2);
+ dev->touch = (pkt[0] & 0x40) ? 1 : 0;
+ return 1;
+
+ case 0x98:
+ /* touch data in MT emulation mode */
+ dev->x = (pkt[2] << 5) | (pkt[1] >> 2);
+ dev->y = (pkt[4] << 5) | (pkt[3] >> 2);
+ dev->touch = (pkt[0] & 0x40) ? 1 : 0;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+#endif
+
+/*****************************************************************************
+ * General Touch Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
+static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+ dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1] ;
+ dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3] ;
+ dev->press = pkt[5] & 0xff;
+ dev->touch = pkt[0] & 0x01;
+
+ return 1;
+}
+#endif
+
+/*****************************************************************************
+ * GoTop Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
+static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+ dev->x = ((pkt[1] & 0x38) << 4) | pkt[2];
+ dev->y = ((pkt[1] & 0x07) << 7) | pkt[3];
+ dev->touch = pkt[0] & 0x01;
+ return 1;
+}
+#endif
+
+
+/*****************************************************************************
* the different device descriptors
*/
static struct usbtouch_device_info usbtouch_dev_info[] = {
@@ -537,6 +622,42 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.read_data = irtouch_read_data,
},
#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
+ [DEVTYPE_IDEALTEK] = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 8,
+ .flags = USBTOUCH_FLG_BUFFER,
+ .process_pkt = usbtouch_process_multi,
+ .get_pkt_len = idealtek_get_pkt_len,
+ .read_data = idealtek_read_data,
+ },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
+ [DEVTYPE_GENERAL_TOUCH] = {
+ .min_xc = 0x0,
+ .max_xc = 0x0500,
+ .min_yc = 0x0,
+ .max_yc = 0x0500,
+ .rept_size = 7,
+ .read_data = general_touch_read_data,
+ },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
+ [DEVTYPE_GOTOP] = {
+ .min_xc = 0x0,
+ .max_xc = 0x03ff,
+ .min_yc = 0x0,
+ .max_yc = 0x03ff,
+ .rept_size = 4,
+ .read_data = gotop_read_data,
+ },
+#endif
};
@@ -779,8 +900,8 @@ static int usbtouch_probe(struct usb_interface *intf,
input_dev->open = usbtouch_open;
input_dev->close = usbtouch_close;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ 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, type->min_xc, type->max_xc, 0, 0);
input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0);
if (type->max_press)
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
deleted file mode 100644
index d2f882e98e5..00000000000
--- a/drivers/input/tsdev.c
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $
- *
- * Copyright (c) 2001 "Crazy" james Simmons
- *
- * Compaq touchscreen protocol driver. The protocol emulated by this driver
- * is obsolete; for new programs use the tslib library which can read directly
- * from evdev and perform dejittering, variance filtering and calibration -
- * all in user space, not at kernel level. The meaning of this driver is
- * to allow usage of newer input drivers with old applications that use the
- * old /dev/h3600_ts and /dev/h3600_tsraw devices.
- *
- * 09-Apr-2004: Andrew Zabolotny <zap@homelink.ru>
- * Fixed to actually work, not just output random numbers.
- * Added support for both h3600_ts and h3600_tsraw protocol
- * emulation.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <jsimmons@infradead.org>.
- */
-
-#define TSDEV_MINOR_BASE 128
-#define TSDEV_MINORS 32
-/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */
-#define TSDEV_MINOR_MASK 15
-#define TSDEV_BUFFER_SIZE 64
-
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/major.h>
-#include <linux/random.h>
-#include <linux/time.h>
-#include <linux/device.h>
-
-#ifndef CONFIG_INPUT_TSDEV_SCREEN_X
-#define CONFIG_INPUT_TSDEV_SCREEN_X 240
-#endif
-#ifndef CONFIG_INPUT_TSDEV_SCREEN_Y
-#define CONFIG_INPUT_TSDEV_SCREEN_Y 320
-#endif
-
-/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw
- * devices. The first one must output X/Y data in 'cooked' format, e.g.
- * filtered, dejittered and calibrated. Second device just outputs raw
- * data received from the hardware.
- *
- * This driver doesn't support filtering and dejittering; it supports only
- * calibration. Filtering and dejittering must be done in the low-level
- * driver, if needed, because it may gain additional benefits from knowing
- * the low-level details, the nature of noise and so on.
- *
- * The driver precomputes a calibration matrix given the initial xres and
- * yres values (quite innacurate for most touchscreens) that will result
- * in a more or less expected range of output values. The driver supports
- * the TS_SET_CAL ioctl, which will replace the calibration matrix with a
- * new one, supposedly generated from the values taken from the raw device.
- */
-
-MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
-MODULE_DESCRIPTION("Input driver to touchscreen converter");
-MODULE_LICENSE("GPL");
-
-static int xres = CONFIG_INPUT_TSDEV_SCREEN_X;
-module_param(xres, uint, 0);
-MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)");
-
-static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y;
-module_param(yres, uint, 0);
-MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)");
-
-/* From Compaq's Touch Screen Specification version 0.2 (draft) */
-struct ts_event {
- short pressure;
- short x;
- short y;
- short millisecs;
-};
-
-struct ts_calibration {
- int xscale;
- int xtrans;
- int yscale;
- int ytrans;
- int xyswap;
-};
-
-struct tsdev {
- int exist;
- int open;
- int minor;
- char name[8];
- struct input_handle handle;
- wait_queue_head_t wait;
- struct list_head client_list;
- struct device dev;
-
- int x, y, pressure;
- struct ts_calibration cal;
-};
-
-struct tsdev_client {
- struct fasync_struct *fasync;
- struct list_head node;
- struct tsdev *tsdev;
- int head, tail;
- struct ts_event event[TSDEV_BUFFER_SIZE];
- int raw;
-};
-
-/* The following ioctl codes are defined ONLY for backward compatibility.
- * Don't use tsdev for new developement; use the tslib library instead.
- * Touchscreen calibration is a fully userspace task.
- */
-/* Use 'f' as magic number */
-#define IOC_H3600_TS_MAGIC 'f'
-#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration)
-#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
-
-static struct tsdev *tsdev_table[TSDEV_MINORS/2];
-
-static int tsdev_fasync(int fd, struct file *file, int on)
-{
- struct tsdev_client *client = file->private_data;
- int retval;
-
- retval = fasync_helper(fd, file, on, &client->fasync);
- return retval < 0 ? retval : 0;
-}
-
-static int tsdev_open(struct inode *inode, struct file *file)
-{
- int i = iminor(inode) - TSDEV_MINOR_BASE;
- struct tsdev_client *client;
- struct tsdev *tsdev;
- int error;
-
- printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
- "for removal.\nSee Documentation/feature-removal-schedule.txt "
- "for details.\n");
-
- if (i >= TSDEV_MINORS)
- return -ENODEV;
-
- tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
- if (!tsdev || !tsdev->exist)
- return -ENODEV;
-
- get_device(&tsdev->dev);
-
- client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);
- if (!client) {
- error = -ENOMEM;
- goto err_put_tsdev;
- }
-
- client->tsdev = tsdev;
- client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0;
- list_add_tail(&client->node, &tsdev->client_list);
-
- if (!tsdev->open++ && tsdev->exist) {
- error = input_open_device(&tsdev->handle);
- if (error)
- goto err_free_client;
- }
-
- file->private_data = client;
- return 0;
-
- err_free_client:
- list_del(&client->node);
- kfree(client);
- err_put_tsdev:
- put_device(&tsdev->dev);
- return error;
-}
-
-static void tsdev_free(struct device *dev)
-{
- struct tsdev *tsdev = container_of(dev, struct tsdev, dev);
-
- tsdev_table[tsdev->minor] = NULL;
- kfree(tsdev);
-}
-
-static int tsdev_release(struct inode *inode, struct file *file)
-{
- struct tsdev_client *client = file->private_data;
- struct tsdev *tsdev = client->tsdev;
-
- tsdev_fasync(-1, file, 0);
-
- list_del(&client->node);
- kfree(client);
-
- if (!--tsdev->open && tsdev->exist)
- input_close_device(&tsdev->handle);
-
- put_device(&tsdev->dev);
-
- return 0;
-}
-
-static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
- loff_t *ppos)
-{
- struct tsdev_client *client = file->private_data;
- struct tsdev *tsdev = client->tsdev;
- int retval = 0;
-
- if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK))
- return -EAGAIN;
-
- retval = wait_event_interruptible(tsdev->wait,
- client->head != client->tail || !tsdev->exist);
- if (retval)
- return retval;
-
- if (!tsdev->exist)
- return -ENODEV;
-
- while (client->head != client->tail &&
- retval + sizeof (struct ts_event) <= count) {
- if (copy_to_user (buffer + retval, client->event + client->tail,
- sizeof (struct ts_event)))
- return -EFAULT;
- client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
- retval += sizeof (struct ts_event);
- }
-
- return retval;
-}
-
-/* No kernel lock - fine */
-static unsigned int tsdev_poll(struct file *file, poll_table *wait)
-{
- struct tsdev_client *client = file->private_data;
- struct tsdev *tsdev = client->tsdev;
-
- poll_wait(file, &tsdev->wait, wait);
- return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
- (tsdev->exist ? 0 : (POLLHUP | POLLERR));
-}
-
-static int tsdev_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct tsdev_client *client = file->private_data;
- struct tsdev *tsdev = client->tsdev;
- int retval = 0;
-
- switch (cmd) {
- case TS_GET_CAL:
- if (copy_to_user((void __user *)arg, &tsdev->cal,
- sizeof (struct ts_calibration)))
- retval = -EFAULT;
- break;
-
- case TS_SET_CAL:
- if (copy_from_user(&tsdev->cal, (void __user *)arg,
- sizeof (struct ts_calibration)))
- retval = -EFAULT;
- break;
-
- default:
- retval = -EINVAL;
- break;
- }
-
- return retval;
-}
-
-static const struct file_operations tsdev_fops = {
- .owner = THIS_MODULE,
- .open = tsdev_open,
- .release = tsdev_release,
- .read = tsdev_read,
- .poll = tsdev_poll,
- .fasync = tsdev_fasync,
- .ioctl = tsdev_ioctl,
-};
-
-static void tsdev_event(struct input_handle *handle, unsigned int type,
- unsigned int code, int value)
-{
- struct tsdev *tsdev = handle->private;
- struct tsdev_client *client;
- struct timeval time;
-
- switch (type) {
- case EV_ABS:
- switch (code) {
- case ABS_X:
- tsdev->x = value;
- break;
-
- case ABS_Y:
- tsdev->y = value;
- break;
-
- case ABS_PRESSURE:
- if (value > handle->dev->absmax[ABS_PRESSURE])
- value = handle->dev->absmax[ABS_PRESSURE];
- value -= handle->dev->absmin[ABS_PRESSURE];
- if (value < 0)
- value = 0;
- tsdev->pressure = value;
- break;
- }
- break;
-
- case EV_REL:
- switch (code) {
- case REL_X:
- tsdev->x += value;
- if (tsdev->x < 0)
- tsdev->x = 0;
- else if (tsdev->x > xres)
- tsdev->x = xres;
- break;
-
- case REL_Y:
- tsdev->y += value;
- if (tsdev->y < 0)
- tsdev->y = 0;
- else if (tsdev->y > yres)
- tsdev->y = yres;
- break;
- }
- break;
-
- case EV_KEY:
- if (code == BTN_TOUCH || code == BTN_MOUSE) {
- switch (value) {
- case 0:
- tsdev->pressure = 0;
- break;
-
- case 1:
- if (!tsdev->pressure)
- tsdev->pressure = 1;
- break;
- }
- }
- break;
- }
-
- if (type != EV_SYN || code != SYN_REPORT)
- return;
-
- list_for_each_entry(client, &tsdev->client_list, node) {
- int x, y, tmp;
-
- do_gettimeofday(&time);
- client->event[client->head].millisecs = time.tv_usec / 1000;
- client->event[client->head].pressure = tsdev->pressure;
-
- x = tsdev->x;
- y = tsdev->y;
-
- /* Calibration */
- if (!client->raw) {
- x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
- y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
- if (tsdev->cal.xyswap) {
- tmp = x; x = y; y = tmp;
- }
- }
-
- client->event[client->head].x = x;
- client->event[client->head].y = y;
- client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1);
- kill_fasync(&client->fasync, SIGIO, POLL_IN);
- }
- wake_up_interruptible(&tsdev->wait);
-}
-
-static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
- const struct input_device_id *id)
-{
- struct tsdev *tsdev;
- int minor, delta;
- int error;
-
- for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
- if (minor >= TSDEV_MINORS / 2) {
- printk(KERN_ERR
- "tsdev: You have way too many touchscreens\n");
- return -ENFILE;
- }
-
- tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL);
- if (!tsdev)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&tsdev->client_list);
- init_waitqueue_head(&tsdev->wait);
-
- tsdev->exist = 1;
- tsdev->minor = minor;
- tsdev->handle.dev = dev;
- tsdev->handle.name = tsdev->name;
- tsdev->handle.handler = handler;
- tsdev->handle.private = tsdev;
- snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor);
-
- /* Precompute the rough calibration matrix */
- delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
- if (delta == 0)
- delta = 1;
- tsdev->cal.xscale = (xres << 8) / delta;
- tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8);
-
- delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1;
- if (delta == 0)
- delta = 1;
- tsdev->cal.yscale = (yres << 8) / delta;
- tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);
-
- snprintf(tsdev->dev.bus_id, sizeof(tsdev->dev.bus_id),
- "ts%d", minor);
- tsdev->dev.class = &input_class;
- tsdev->dev.parent = &dev->dev;
- tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor);
- tsdev->dev.release = tsdev_free;
- device_initialize(&tsdev->dev);
-
- tsdev_table[minor] = tsdev;
-
- error = device_add(&tsdev->dev);
- if (error)
- goto err_free_tsdev;
-
- error = input_register_handle(&tsdev->handle);
- if (error)
- goto err_delete_tsdev;
-
- return 0;
-
- err_delete_tsdev:
- device_del(&tsdev->dev);
- err_free_tsdev:
- put_device(&tsdev->dev);
- return error;
-}
-
-static void tsdev_disconnect(struct input_handle *handle)
-{
- struct tsdev *tsdev = handle->private;
- struct tsdev_client *client;
-
- input_unregister_handle(handle);
- device_del(&tsdev->dev);
-
- tsdev->exist = 0;
-
- if (tsdev->open) {
- input_close_device(handle);
- list_for_each_entry(client, &tsdev->client_list, node)
- kill_fasync(&client->fasync, SIGIO, POLL_HUP);
- wake_up_interruptible(&tsdev->wait);
- }
-
- put_device(&tsdev->dev);
-}
-
-static const struct input_device_id tsdev_ids[] = {
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
- .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
- .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
- .relbit = { BIT(REL_X) | BIT(REL_Y) },
- }, /* A mouse like device, at least one button, two relative axes */
-
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
- .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
- .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
- .absbit = { BIT(ABS_X) | BIT(ABS_Y) },
- }, /* A tablet like device, at least touch detection, two absolute axes */
-
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
- .evbit = { BIT(EV_ABS) },
- .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
- }, /* A tablet like device with several gradations of pressure */
-
- {} /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(input, tsdev_ids);
-
-static struct input_handler tsdev_handler = {
- .event = tsdev_event,
- .connect = tsdev_connect,
- .disconnect = tsdev_disconnect,
- .fops = &tsdev_fops,
- .minor = TSDEV_MINOR_BASE,
- .name = "tsdev",
- .id_table = tsdev_ids,
-};
-
-static int __init tsdev_init(void)
-{
- return input_register_handler(&tsdev_handler);
-}
-
-static void __exit tsdev_exit(void)
-{
- input_unregister_handler(&tsdev_handler);
-}
-
-module_init(tsdev_init);
-module_exit(tsdev_exit);
diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c
index 09ea50dd345..1bd8960ead3 100644
--- a/drivers/isdn/act2000/act2000_isa.c
+++ b/drivers/isdn/act2000/act2000_isa.c
@@ -61,7 +61,7 @@ act2000_isa_detect(unsigned short portbase)
}
static irqreturn_t
-act2000_isa_interrupt(int irq, void *dev_id)
+act2000_isa_interrupt(int dummy, void *dev_id)
{
act2000_card *card = dev_id;
u_char istatus;
@@ -80,7 +80,7 @@ act2000_isa_interrupt(int irq, void *dev_id)
printk(KERN_WARNING "act2000: errIRQ\n");
}
if (istatus)
- printk(KERN_DEBUG "act2000: ?IRQ %d %02x\n", irq, istatus);
+ printk(KERN_DEBUG "act2000: ?IRQ %d %02x\n", card->irq, istatus);
return IRQ_HANDLED;
}
@@ -126,11 +126,13 @@ act2000_isa_enable_irq(act2000_card * card)
/*
* Install interrupt handler, enable irq on card.
- * If irq is -1, choose next free irq, else irq is given explicitely.
+ * If irq is -1, choose next free irq, else irq is given explicitly.
*/
int
act2000_isa_config_irq(act2000_card * card, short irq)
{
+ int old_irq;
+
if (card->flags & ACT2000_FLAGS_IVALID) {
free_irq(card->irq, card);
}
@@ -139,8 +141,10 @@ act2000_isa_config_irq(act2000_card * card, short irq)
if (!irq)
return 0;
- if (!request_irq(irq, &act2000_isa_interrupt, 0, card->regname, card)) {
- card->irq = irq;
+ old_irq = card->irq;
+ card->irq = irq;
+ if (request_irq(irq, &act2000_isa_interrupt, 0, card->regname, card)) {
+ card->irq = old_irq;
card->flags |= ACT2000_FLAGS_IVALID;
printk(KERN_WARNING
"act2000: Could not request irq %d\n",irq);
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index 23b6f7bc16b..48c1775ef5b 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -506,9 +506,14 @@ static void send_message(capidrv_contr * card, _cmsg * cmsg)
{
struct sk_buff *skb;
size_t len;
+
capi_cmsg2message(cmsg, cmsg->buf);
len = CAPIMSG_LEN(cmsg->buf);
skb = alloc_skb(len, GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_ERR "capidrv::send_message: can't allocate mem\n");
+ return;
+ }
memcpy(skb_put(skb, len), cmsg->buf, len);
if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR)
kfree_skb(skb);
@@ -1838,6 +1843,7 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
int msglen;
u16 errcode;
u16 datahandle;
+ u32 data;
if (!card) {
printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n",
@@ -1855,9 +1861,26 @@ static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb)
return 0;
}
datahandle = nccip->datahandle;
+
+ /*
+ * Here we copy pointer skb->data into the 32-bit 'Data' field.
+ * The 'Data' field is not used in practice in linux kernel
+ * (neither in 32 or 64 bit), but should have some value,
+ * since a CAPI message trace will display it.
+ *
+ * The correct value in the 32 bit case is the address of the
+ * data, in 64 bit it makes no sense, we use 0 there.
+ */
+
+#ifdef CONFIG_64BIT
+ data = 0;
+#else
+ data = (unsigned long) skb->data;
+#endif
+
capi_fill_DATA_B3_REQ(&sendcmsg, global.ap.applid, card->msgid++,
nccip->ncci, /* adr */
- (u32) skb->data, /* Data */
+ data, /* Data */
skb->len, /* DataLength */
datahandle, /* DataHandle */
0 /* Flags */
@@ -2118,7 +2141,10 @@ static int capidrv_delcontr(u16 contr)
printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
return -1;
}
- #warning FIXME: maybe a race condition the card should be removed here from global list /kkeil
+
+ /* FIXME: maybe a race condition the card should be removed
+ * here from global list /kkeil
+ */
spin_unlock_irqrestore(&global_lock, flags);
del_timer(&card->listentimer);
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
index 9f73bc2727c..f5553186931 100644
--- a/drivers/isdn/capi/kcapi.c
+++ b/drivers/isdn/capi/kcapi.c
@@ -821,6 +821,8 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
return -EFAULT;
}
card = get_capi_ctr_by_nr(ldef.contr);
+ if (!card)
+ return -EINVAL;
card = capi_ctr_get(card);
if (!card)
return -ESRCH;
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 559a0d0244c..4fd4c46892e 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -17,6 +17,7 @@
#include <linux/fs.h>
#endif
#include <linux/isdnif.h>
+#include <net/net_namespace.h>
#include "isdn_divert.h"
@@ -284,12 +285,12 @@ divert_dev_init(void)
init_waitqueue_head(&rd_queue);
#ifdef CONFIG_PROC_FS
- isdn_proc_entry = proc_mkdir("net/isdn", NULL);
+ isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net);
if (!isdn_proc_entry)
return (-1);
isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry);
if (!isdn_divert_entry) {
- remove_proc_entry("net/isdn", NULL);
+ remove_proc_entry("isdn", init_net.proc_net);
return (-1);
}
isdn_divert_entry->proc_fops = &isdn_fops;
@@ -309,7 +310,7 @@ divert_dev_deinit(void)
#ifdef CONFIG_PROC_FS
remove_proc_entry("divert", isdn_proc_entry);
- remove_proc_entry("net/isdn", NULL);
+ remove_proc_entry("isdn", init_net.proc_net);
#endif /* CONFIG_PROC_FS */
return (0);
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 00e31609a23..af7648274b3 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -1936,14 +1936,7 @@ static int gigaset_write_room(struct cardstate *cs)
*/
static int gigaset_chars_in_buffer(struct cardstate *cs)
{
- unsigned long flags;
- unsigned bytes;
-
- spin_lock_irqsave(&cs->cmdlock, flags);
- bytes = cs->cmdbytes;
- spin_unlock_irqrestore(&cs->cmdlock, flags);
-
- return bytes;
+ return cs->cmdbytes;
}
/* gigaset_brkchars
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index 6df336bdd57..acd417197d0 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -534,7 +534,8 @@ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
n = RBUFSIZE - tail;
if (!n) {
dev_err(inbuf->cs->dev,
- "buffer overflow (%u bytes lost)", bytesleft);
+ "buffer overflow (%u bytes lost)\n",
+ bytesleft);
break;
}
if (n > bytesleft)
diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
index 1654fa41357..9e089f06a94 100644
--- a/drivers/isdn/gigaset/i4l.c
+++ b/drivers/isdn/gigaset/i4l.c
@@ -109,13 +109,9 @@ EXPORT_SYMBOL_GPL(gigaset_skb_sent);
static int command_from_LL(isdn_ctrl *cntrl)
{
struct cardstate *cs = gigaset_get_cs_by_id(cntrl->driver);
- //isdn_ctrl response;
- //unsigned long flags;
struct bc_state *bcs;
int retval = 0;
struct setup_parm *sp;
- unsigned param;
- unsigned long flags;
gigaset_debugdrivers();
@@ -162,12 +158,8 @@ static int command_from_LL(isdn_ctrl *cntrl)
}
*sp = cntrl->parm.setup;
- spin_lock_irqsave(&cs->lock, flags);
- param = bcs->at_state.seq_index;
- spin_unlock_irqrestore(&cs->lock, flags);
-
- if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp, param,
- NULL)) {
+ if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp,
+ bcs->at_state.seq_index, NULL)) {
//FIXME what should we do?
kfree(sp);
gigaset_free_channel(bcs);
diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c
index e767afa55ab..da6f3acf9fd 100644
--- a/drivers/isdn/gigaset/proc.c
+++ b/drivers/isdn/gigaset/proc.c
@@ -19,15 +19,9 @@
static ssize_t show_cidmode(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int ret;
- unsigned long flags;
struct cardstate *cs = dev_get_drvdata(dev);
- spin_lock_irqsave(&cs->lock, flags);
- ret = sprintf(buf, "%u\n", cs->cidmode);
- spin_unlock_irqrestore(&cs->lock, flags);
-
- return ret;
+ return sprintf(buf, "%u\n", cs->cidmode);
}
static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index a1263019df5..ca4bee173cf 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -310,7 +310,6 @@ static void gigaset_modem_fill(unsigned long data)
struct cardstate *cs = (struct cardstate *) data;
struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
struct cmdbuf_t *cb;
- unsigned long flags;
int again;
gig_dbg(DEBUG_OUTPUT, "modem_fill");
@@ -323,9 +322,7 @@ static void gigaset_modem_fill(unsigned long data)
do {
again = 0;
if (!bcs->tx_skb) { /* no skb is being sent */
- spin_lock_irqsave(&cs->cmdlock, flags);
cb = cs->cmdbuf;
- spin_unlock_irqrestore(&cs->cmdlock, flags);
if (cb) { /* commands to send? */
gig_dbg(DEBUG_OUTPUT, "modem_fill: cb");
if (send_cb(cs, cb) < 0) {
@@ -546,13 +543,9 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf,
static int gigaset_write_room(struct cardstate *cs)
{
- unsigned long flags;
unsigned bytes;
- spin_lock_irqsave(&cs->cmdlock, flags);
bytes = cs->cmdbytes;
- spin_unlock_irqrestore(&cs->cmdlock, flags);
-
return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0;
}
diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c
index 7a69a18d07e..4484a641723 100644
--- a/drivers/isdn/hardware/avm/b1.c
+++ b/drivers/isdn/hardware/avm/b1.c
@@ -321,12 +321,15 @@ void b1_reset_ctr(struct capi_ctr *ctrl)
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
+ unsigned long flags;
b1_reset(port);
b1_reset(port);
memset(cinfo->version, 0, sizeof(cinfo->version));
+ spin_lock_irqsave(&card->lock, flags);
capilib_release(&cinfo->ncci_head);
+ spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_reseted(ctrl);
}
@@ -361,9 +364,8 @@ void b1_release_appl(struct capi_ctr *ctrl, u16 appl)
unsigned int port = card->port;
unsigned long flags;
- capilib_release_appl(&cinfo->ncci_head, appl);
-
spin_lock_irqsave(&card->lock, flags);
+ capilib_release_appl(&cinfo->ncci_head, appl);
b1_put_byte(port, SEND_RELEASE);
b1_put_word(port, appl);
spin_unlock_irqrestore(&card->lock, flags);
@@ -380,27 +382,27 @@ u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
u16 dlen, retval;
+ spin_lock_irqsave(&card->lock, flags);
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
- if (retval != CAPI_NOERROR)
+ if (retval != CAPI_NOERROR) {
+ spin_unlock_irqrestore(&card->lock, flags);
return retval;
+ }
dlen = CAPIMSG_DATALEN(skb->data);
- spin_lock_irqsave(&card->lock, flags);
b1_put_byte(port, SEND_DATA_B3_REQ);
b1_put_slice(port, skb->data, len);
b1_put_slice(port, skb->data + len, dlen);
- spin_unlock_irqrestore(&card->lock, flags);
} else {
- spin_lock_irqsave(&card->lock, flags);
b1_put_byte(port, SEND_MESSAGE);
b1_put_slice(port, skb->data, len);
- spin_unlock_irqrestore(&card->lock, flags);
}
+ spin_unlock_irqrestore(&card->lock, flags);
dev_kfree_skb_any(skb);
return CAPI_NOERROR;
@@ -534,17 +536,17 @@ irqreturn_t b1_interrupt(int interrupt, void *devptr)
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = b1_get_slice(card->port, card->msgbuf);
- spin_unlock_irqrestore(&card->lock, flags);
if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
+ spin_unlock_irqrestore(&card->lock, flags);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF)
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
-
+ spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
@@ -554,21 +556,17 @@ irqreturn_t b1_interrupt(int interrupt, void *devptr)
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
WindowSize = b1_get_word(card->port);
- spin_unlock_irqrestore(&card->lock, flags);
-
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
-
+ spin_unlock_irqrestore(&card->lock, flags);
break;
case RECEIVE_FREE_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
- spin_unlock_irqrestore(&card->lock, flags);
-
if (NCCI != 0xffffffff)
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
-
+ spin_unlock_irqrestore(&card->lock, flags);
break;
case RECEIVE_START:
diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
index 428872b653e..669f6f67449 100644
--- a/drivers/isdn/hardware/avm/b1dma.c
+++ b/drivers/isdn/hardware/avm/b1dma.c
@@ -486,11 +486,13 @@ static void b1dma_handle_rx(avmcard *card)
card->name);
} else {
memcpy(skb_put(skb, MsgLen), card->msgbuf, MsgLen);
- if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF)
+ if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) {
+ spin_lock(&card->lock);
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
- CAPIMSG_NCCI(skb->data),
- CAPIMSG_MSGID(skb->data));
-
+ CAPIMSG_NCCI(skb->data),
+ CAPIMSG_MSGID(skb->data));
+ spin_unlock(&card->lock);
+ }
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
@@ -500,9 +502,9 @@ static void b1dma_handle_rx(avmcard *card)
ApplId = _get_word(&p);
NCCI = _get_word(&p);
WindowSize = _get_word(&p);
-
+ spin_lock(&card->lock);
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
-
+ spin_unlock(&card->lock);
break;
case RECEIVE_FREE_NCCI:
@@ -510,9 +512,11 @@ static void b1dma_handle_rx(avmcard *card)
ApplId = _get_word(&p);
NCCI = _get_word(&p);
- if (NCCI != 0xffffffff)
+ if (NCCI != 0xffffffff) {
+ spin_lock(&card->lock);
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
-
+ spin_unlock(&card->lock);
+ }
break;
case RECEIVE_START:
@@ -751,10 +755,10 @@ void b1dma_reset_ctr(struct capi_ctr *ctrl)
spin_lock_irqsave(&card->lock, flags);
b1dma_reset(card);
- spin_unlock_irqrestore(&card->lock, flags);
memset(cinfo->version, 0, sizeof(cinfo->version));
capilib_release(&cinfo->ncci_head);
+ spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_reseted(ctrl);
}
@@ -803,8 +807,11 @@ void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl)
avmcard *card = cinfo->card;
struct sk_buff *skb;
void *p;
+ unsigned long flags;
+ spin_lock_irqsave(&card->lock, flags);
capilib_release_appl(&cinfo->ncci_head, appl);
+ spin_unlock_irqrestore(&card->lock, flags);
skb = alloc_skb(7, GFP_ATOMIC);
if (!skb) {
@@ -832,10 +839,13 @@ u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
u16 retval = CAPI_NOERROR;
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
+ unsigned long flags;
+ spin_lock_irqsave(&card->lock, flags);
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
+ spin_unlock_irqrestore(&card->lock, flags);
}
if (retval == CAPI_NOERROR)
b1dma_queue_tx(card, skb);
diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
index d58f927e766..4bbbbe68807 100644
--- a/drivers/isdn/hardware/avm/c4.c
+++ b/drivers/isdn/hardware/avm/c4.c
@@ -678,7 +678,9 @@ static irqreturn_t c4_handle_interrupt(avmcard *card)
for (i=0; i < card->nr_controllers; i++) {
avmctrl_info *cinfo = &card->ctrlinfo[i];
memset(cinfo->version, 0, sizeof(cinfo->version));
+ spin_lock_irqsave(&card->lock, flags);
capilib_release(&cinfo->ncci_head);
+ spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_reseted(&cinfo->capi_ctrl);
}
card->nlogcontr = 0;
@@ -727,6 +729,7 @@ static void c4_send_init(avmcard *card)
{
struct sk_buff *skb;
void *p;
+ unsigned long flags;
skb = alloc_skb(15, GFP_ATOMIC);
if (!skb) {
@@ -744,12 +747,15 @@ static void c4_send_init(avmcard *card)
skb_put(skb, (u8 *)p - (u8 *)skb->data);
skb_queue_tail(&card->dma->send_queue, skb);
+ spin_lock_irqsave(&card->lock, flags);
c4_dispatch_tx(card);
+ spin_unlock_irqrestore(&card->lock, flags);
}
static int queue_sendconfigword(avmcard *card, u32 val)
{
struct sk_buff *skb;
+ unsigned long flags;
void *p;
skb = alloc_skb(3+4, GFP_ATOMIC);
@@ -766,7 +772,9 @@ static int queue_sendconfigword(avmcard *card, u32 val)
skb_put(skb, (u8 *)p - (u8 *)skb->data);
skb_queue_tail(&card->dma->send_queue, skb);
+ spin_lock_irqsave(&card->lock, flags);
c4_dispatch_tx(card);
+ spin_unlock_irqrestore(&card->lock, flags);
return 0;
}
@@ -986,7 +994,9 @@ static void c4_release_appl(struct capi_ctr *ctrl, u16 appl)
struct sk_buff *skb;
void *p;
+ spin_lock_irqsave(&card->lock, flags);
capilib_release_appl(&cinfo->ncci_head, appl);
+ spin_unlock_irqrestore(&card->lock, flags);
if (ctrl->cnr == card->cardnr) {
skb = alloc_skb(7, GFP_ATOMIC);
@@ -1019,7 +1029,8 @@ static u16 c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
u16 retval = CAPI_NOERROR;
unsigned long flags;
- if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
+ spin_lock_irqsave(&card->lock, flags);
+ if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
@@ -1027,10 +1038,9 @@ static u16 c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
}
if (retval == CAPI_NOERROR) {
skb_queue_tail(&card->dma->send_queue, skb);
- spin_lock_irqsave(&card->lock, flags);
c4_dispatch_tx(card);
- spin_unlock_irqrestore(&card->lock, flags);
}
+ spin_unlock_irqrestore(&card->lock, flags);
return retval;
}
diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c
index c925020fe9b..6130724e46e 100644
--- a/drivers/isdn/hardware/avm/t1isa.c
+++ b/drivers/isdn/hardware/avm/t1isa.c
@@ -180,8 +180,8 @@ static irqreturn_t t1isa_interrupt(int interrupt, void *devptr)
ApplId = (unsigned) b1_get_word(card->port);
MsgLen = t1_get_slice(card->port, card->msgbuf);
- spin_unlock_irqrestore(&card->lock, flags);
if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) {
+ spin_unlock_irqrestore(&card->lock, flags);
printk(KERN_ERR "%s: incoming packet dropped\n",
card->name);
} else {
@@ -190,7 +190,7 @@ static irqreturn_t t1isa_interrupt(int interrupt, void *devptr)
capilib_data_b3_conf(&cinfo->ncci_head, ApplId,
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
-
+ spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_handle_message(ctrl, ApplId, skb);
}
break;
@@ -200,21 +200,17 @@ static irqreturn_t t1isa_interrupt(int interrupt, void *devptr)
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
WindowSize = b1_get_word(card->port);
- spin_unlock_irqrestore(&card->lock, flags);
-
capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize);
-
+ spin_unlock_irqrestore(&card->lock, flags);
break;
case RECEIVE_FREE_NCCI:
ApplId = b1_get_word(card->port);
NCCI = b1_get_word(card->port);
- spin_unlock_irqrestore(&card->lock, flags);
-
if (NCCI != 0xffffffff)
capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI);
-
+ spin_unlock_irqrestore(&card->lock, flags);
break;
case RECEIVE_START:
@@ -333,13 +329,16 @@ static void t1isa_reset_ctr(struct capi_ctr *ctrl)
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
unsigned int port = card->port;
+ unsigned long flags;
t1_disable_irq(port);
b1_reset(port);
b1_reset(port);
memset(cinfo->version, 0, sizeof(cinfo->version));
+ spin_lock_irqsave(&card->lock, flags);
capilib_release(&cinfo->ncci_head);
+ spin_unlock_irqrestore(&card->lock, flags);
capi_ctr_reseted(ctrl);
}
@@ -466,29 +465,26 @@ static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data);
u16 dlen, retval;
+ spin_lock_irqsave(&card->lock, flags);
if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) {
retval = capilib_data_b3_req(&cinfo->ncci_head,
CAPIMSG_APPID(skb->data),
CAPIMSG_NCCI(skb->data),
CAPIMSG_MSGID(skb->data));
- if (retval != CAPI_NOERROR)
+ if (retval != CAPI_NOERROR) {
+ spin_unlock_irqrestore(&card->lock, flags);
return retval;
-
+ }
dlen = CAPIMSG_DATALEN(skb->data);
- spin_lock_irqsave(&card->lock, flags);
b1_put_byte(port, SEND_DATA_B3_REQ);
t1_put_slice(port, skb->data, len);
t1_put_slice(port, skb->data + len, dlen);
- spin_unlock_irqrestore(&card->lock, flags);
} else {
-
- spin_lock_irqsave(&card->lock, flags);
b1_put_byte(port, SEND_MESSAGE);
t1_put_slice(port, skb->data, len);
- spin_unlock_irqrestore(&card->lock, flags);
}
-
+ spin_unlock_irqrestore(&card->lock, flags);
dev_kfree_skb_any(skb);
return CAPI_NOERROR;
}
diff --git a/drivers/isdn/hardware/eicon/capifunc.c b/drivers/isdn/hardware/eicon/capifunc.c
index 82edc1c1db7..4d425c644d4 100644
--- a/drivers/isdn/hardware/eicon/capifunc.c
+++ b/drivers/isdn/hardware/eicon/capifunc.c
@@ -321,7 +321,7 @@ void sendf(APPL * appl, word command, dword Id, word Number, byte * format, ...)
DBG_BLK((((char *)(long)GET_DWORD(&msg.info.data_b3_ind.Data)) + i,
((dlength - i) < 256) ? (dlength - i) : 256))
if (!(myDriverDebugHandle.dbgMask & DL_PRV0))
- break; /* not more if not explicitely requested */
+ break; /* not more if not explicitly requested */
}
}
break;
@@ -965,7 +965,7 @@ static u16 diva_send_message(struct capi_ctr *ctrl,
((GET_WORD(&msg->info.data_b3_req.Data_Length) - j) <
256) ? (GET_WORD(&msg->info.data_b3_req.Data_Length) - j) : 256))
if (!(myDriverDebugHandle.dbgMask & DL_PRV0))
- break; /* not more if not explicitely requested */
+ break; /* not more if not explicitly requested */
}
}
#endif
diff --git a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c
index d755d904e62..993b14cf177 100644
--- a/drivers/isdn/hardware/eicon/diva_didd.c
+++ b/drivers/isdn/hardware/eicon/diva_didd.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
+#include <net/net_namespace.h>
#include "platform.h"
#include "di_defs.h"
@@ -86,7 +87,7 @@ proc_read(char *page, char **start, off_t off, int count, int *eof,
static int DIVA_INIT_FUNCTION create_proc(void)
{
- proc_net_eicon = proc_mkdir("net/eicon", NULL);
+ proc_net_eicon = proc_mkdir("eicon", init_net.proc_net);
if (proc_net_eicon) {
if ((proc_didd =
@@ -102,7 +103,7 @@ static int DIVA_INIT_FUNCTION create_proc(void)
static void remove_proc(void)
{
remove_proc_entry(DRIVERLNAME, proc_net_eicon);
- remove_proc_entry("net/eicon", NULL);
+ remove_proc_entry("eicon", init_net.proc_net);
}
static int DIVA_INIT_FUNCTION divadidd_init(void)
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
index a3b945ac325..7832d8ba8e4 100644
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -109,7 +109,7 @@ config HISAX_16_3
config HISAX_TELESPCI
bool "Teles PCI"
- depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
+ depends on PCI && PCI_LEGACY && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the Teles PCI.
See <file:Documentation/isdn/README.HiSax> on how to configure it.
@@ -237,7 +237,7 @@ config HISAX_MIC
config HISAX_NETJET
bool "NETjet card"
- depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
+ depends on PCI && PCI_LEGACY && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the NetJet from Traverse
Technologies.
@@ -248,7 +248,7 @@ config HISAX_NETJET
config HISAX_NETJET_U
bool "NETspider U card"
- depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
+ depends on PCI && PCI_LEGACY && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the Netspider U interface ISDN card
from Traverse Technologies.
@@ -287,7 +287,7 @@ config HISAX_HSTSAPHIR
config HISAX_BKM_A4T
bool "Telekom A4T card"
- depends on PCI
+ depends on PCI && PCI_LEGACY
help
This enables HiSax support for the Telekom A4T card.
@@ -297,7 +297,7 @@ config HISAX_BKM_A4T
config HISAX_SCT_QUADRO
bool "Scitel Quadro card"
- depends on PCI
+ depends on PCI && PCI_LEGACY
help
This enables HiSax support for the Scitel Quadro card.
@@ -316,7 +316,7 @@ config HISAX_GAZEL
config HISAX_HFC_PCI
bool "HFC PCI-Bus cards"
- depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
+ depends on PCI && PCI_LEGACY && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
@@ -325,7 +325,7 @@ config HISAX_HFC_PCI
config HISAX_W6692
bool "Winbond W6692 based cards"
- depends on PCI
+ depends on PCI && PCI_LEGACY
help
This enables HiSax support for Winbond W6692 based PCI ISDN cards.
@@ -341,7 +341,7 @@ config HISAX_HFC_SX
config HISAX_ENTERNOW_PCI
bool "Formula-n enter:now PCI card"
- depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
+ depends on HISAX_NETJET && PCI && PCI_LEGACY && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV))
help
This enables HiSax support for the Formula-n enter:now PCI
ISDN card.
@@ -411,7 +411,7 @@ config HISAX_HFC4S8S
config HISAX_FRITZ_PCIPNP
tristate "AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI && PCI_LEGACY && EXPERIMENTAL
help
This enables the driver for the AVM Fritz!Card PCI,
Fritz!Card PCI v2 and Fritz!Card PnP.
diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c
index 3b19caeba25..c0d7036404a 100644
--- a/drivers/isdn/hisax/amd7930_fn.c
+++ b/drivers/isdn/hisax/amd7930_fn.c
@@ -767,7 +767,7 @@ Amd7930_init(struct IsdnCardState *cs)
/* read */
if (*ptr++ >= 0x100) {
if (cmd < 8)
- /* setzt Register zurück */
+ /* reset register */
rByteAMD(cs, cmd);
else {
wByteAMD(cs, 0x00, cmd);
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index b04a178e502..035d158779d 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -20,7 +20,6 @@
#include <linux/isapnp.h>
#include <linux/interrupt.h>
-extern const char *CardType[];
static const char *avm_pci_rev = "$Revision: 1.29.2.4 $";
#define AVM_FRITZ_PCI 1
@@ -726,100 +725,15 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-#ifdef CONFIG_PCI
-static struct pci_dev *dev_avm __devinitdata = NULL;
-#endif
-#ifdef __ISAPNP__
-static struct pnp_card *pnp_avm_c __devinitdata = NULL;
-#endif
-
-int __devinit
-setup_avm_pcipnp(struct IsdnCard *card)
+static int __devinit avm_setup_rest(struct IsdnCardState *cs)
{
u_int val, ver;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
- strcpy(tmp, avm_pci_rev);
- printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_FRITZPCI)
- return (0);
- if (card->para[1]) {
- /* old manual method */
- cs->hw.avm.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- cs->subtyp = AVM_FRITZ_PNP;
- goto ready;
- }
-#ifdef __ISAPNP__
- if (isapnp_present()) {
- struct pnp_dev *pnp_avm_d = NULL;
- if ((pnp_avm_c = pnp_find_card(
- ISAPNP_VENDOR('A', 'V', 'M'),
- ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
- if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
- ISAPNP_VENDOR('A', 'V', 'M'),
- ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
- int err;
-
- pnp_disable_dev(pnp_avm_d);
- err = pnp_activate_dev(pnp_avm_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- cs->hw.avm.cfg_reg =
- pnp_port_start(pnp_avm_d, 0);
- cs->irq = pnp_irq(pnp_avm_d, 0);
- if (!cs->irq) {
- printk(KERN_ERR "FritzPnP:No IRQ\n");
- return(0);
- }
- if (!cs->hw.avm.cfg_reg) {
- printk(KERN_ERR "FritzPnP:No IO address\n");
- return(0);
- }
- cs->subtyp = AVM_FRITZ_PNP;
- goto ready;
- }
- }
- } else {
- printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
- }
-#endif
-#ifdef CONFIG_PCI
- if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
- PCI_DEVICE_ID_AVM_A1, dev_avm))) {
- if (pci_enable_device(dev_avm))
- return(0);
- cs->irq = dev_avm->irq;
- if (!cs->irq) {
- printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
- return(0);
- }
- cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
- if (!cs->hw.avm.cfg_reg) {
- printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
- return(0);
- }
- cs->subtyp = AVM_FRITZ_PCI;
- } else {
- printk(KERN_WARNING "FritzPCI: No PCI card found\n");
- return(0);
- }
- cs->irq_flags |= IRQF_SHARED;
-#else
- printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
- return (0);
-#endif /* CONFIG_PCI */
-ready:
cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
if (!request_region(cs->hw.avm.cfg_reg, 32,
(cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
printk(KERN_WARNING
- "HiSax: %s config port %x-%x already in use\n",
- CardType[card->typ],
+ "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n",
cs->hw.avm.cfg_reg,
cs->hw.avm.cfg_reg + 31);
return (0);
@@ -860,3 +774,137 @@ ready:
ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
return (1);
}
+
+#ifndef __ISAPNP__
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+ return(1); /* no-op: success */
+}
+
+#else
+
+static struct pnp_card *pnp_avm_c __devinitdata = NULL;
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+ struct pnp_dev *pnp_avm_d = NULL;
+
+ if (!isapnp_present())
+ return(1); /* no-op: success */
+
+ if ((pnp_avm_c = pnp_find_card(
+ ISAPNP_VENDOR('A', 'V', 'M'),
+ ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
+ if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
+ ISAPNP_VENDOR('A', 'V', 'M'),
+ ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
+ int err;
+
+ pnp_disable_dev(pnp_avm_d);
+ err = pnp_activate_dev(pnp_avm_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ cs->hw.avm.cfg_reg =
+ pnp_port_start(pnp_avm_d, 0);
+ cs->irq = pnp_irq(pnp_avm_d, 0);
+ if (!cs->irq) {
+ printk(KERN_ERR "FritzPnP:No IRQ\n");
+ return(0);
+ }
+ if (!cs->hw.avm.cfg_reg) {
+ printk(KERN_ERR "FritzPnP:No IO address\n");
+ return(0);
+ }
+ cs->subtyp = AVM_FRITZ_PNP;
+
+ return (2); /* goto 'ready' label */
+ }
+ }
+
+ return (1);
+}
+
+#endif /* __ISAPNP__ */
+
+#ifndef CONFIG_PCI_LEGACY
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+ return(1); /* no-op: success */
+}
+
+#else
+
+static struct pci_dev *dev_avm __devinitdata = NULL;
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+ if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
+ PCI_DEVICE_ID_AVM_A1, dev_avm))) {
+
+ if (pci_enable_device(dev_avm))
+ return(0);
+
+ cs->irq = dev_avm->irq;
+ if (!cs->irq) {
+ printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
+ return(0);
+ }
+
+ cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
+ if (!cs->hw.avm.cfg_reg) {
+ printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+
+ cs->subtyp = AVM_FRITZ_PCI;
+ } else {
+ printk(KERN_WARNING "FritzPCI: No PCI card found\n");
+ return(0);
+ }
+
+ cs->irq_flags |= IRQF_SHARED;
+
+ return (1);
+}
+
+#endif /* CONFIG_PCI_LEGACY */
+
+int __devinit
+setup_avm_pcipnp(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+ int rc;
+
+ strcpy(tmp, avm_pci_rev);
+ printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
+
+ if (cs->typ != ISDN_CTYPE_FRITZPCI)
+ return (0);
+
+ if (card->para[1]) {
+ /* old manual method */
+ cs->hw.avm.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ cs->subtyp = AVM_FRITZ_PNP;
+ goto ready;
+ }
+
+ rc = avm_pnp_setup(cs);
+ if (rc < 1)
+ return (0);
+ if (rc == 2)
+ goto ready;
+
+ rc = avm_pci_setup(cs);
+ if (rc < 1)
+ return (0);
+
+ready:
+ return avm_setup_rest(cs);
+}
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index 6339bb443f6..99ef3b43fcd 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -20,8 +20,6 @@
#include <linux/pci.h>
#include "bkm_ax.h"
-#ifdef CONFIG_PCI
-
#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
extern const char *CardType[];
@@ -279,12 +277,9 @@ static u_char pci_bus __devinitdata = 0;
static u_char pci_device_fn __devinitdata = 0;
static u_char pci_irq __devinitdata = 0;
-#endif /* CONFIG_PCI */
-
int __devinit
setup_sct_quadro(struct IsdnCard *card)
{
-#ifdef CONFIG_PCI
struct IsdnCardState *cs = card->cs;
char tmp[64];
u_int found = 0;
@@ -442,7 +437,4 @@ setup_sct_quadro(struct IsdnCard *card)
sct_quadro_subtypes[cs->subtyp],
readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
return (1);
-#else
- printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
-#endif /* CONFIG_PCI */
}
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 6eebeb441bf..2d670856d14 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -25,8 +25,6 @@
#include <linux/pci.h>
#include <linux/isapnp.h>
-extern const char *CardType[];
-
static const char *Diva_revision = "$Revision: 1.33.2.6 $";
#define byteout(addr,val) outb(val,addr)
@@ -906,225 +904,15 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_diva __devinitdata = NULL;
-static struct pci_dev *dev_diva_u __devinitdata = NULL;
-static struct pci_dev *dev_diva201 __devinitdata = NULL;
-static struct pci_dev *dev_diva202 __devinitdata = NULL;
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id diva_ids[] __devinitdata = {
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- (unsigned long) "Diva picola" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51),
- (unsigned long) "Diva picola" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- (unsigned long) "Diva 2.0" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71),
- (unsigned long) "Diva 2.0" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- (unsigned long) "Diva 2.01" },
- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1),
- (unsigned long) "Diva 2.01" },
- { 0, }
-};
-
-static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
-
-
-int __devinit
-setup_diva(struct IsdnCard *card)
+static int __devinit setup_diva_common(struct IsdnCardState *cs)
{
- int bytecnt = 8;
+ int bytecnt;
u_char val;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
- strcpy(tmp, Diva_revision);
- printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
- return(0);
- cs->hw.diva.status = 0;
- if (card->para[1]) {
- cs->hw.diva.ctrl_reg = 0;
- cs->hw.diva.cfg_reg = card->para[1];
- val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
- cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
- printk(KERN_INFO "Diva: IPAC version %x\n", val);
- if ((val == 1) || (val==2)) {
- cs->subtyp = DIVA_IPAC_ISA;
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
- cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = DIVA_ISA;
- cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
- cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
- cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
- cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
- }
- cs->irq = card->para[0];
- } else {
-#ifdef __ISAPNP__
- if (isapnp_present()) {
- struct pnp_dev *pnp_d;
- while(ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
- if (!card->para[0] || !card->para[1]) {
- printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return(0);
- }
- cs->hw.diva.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
- cs->subtyp = DIVA_IPAC_ISA;
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac =
- card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.hscx =
- card->para[1] + DIVA_IPAC_DATA;
- cs->hw.diva.isac_adr =
- card->para[1] + DIVA_IPAC_ADR;
- cs->hw.diva.hscx_adr =
- card->para[1] + DIVA_IPAC_ADR;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = DIVA_ISA;
- cs->hw.diva.ctrl =
- card->para[1] + DIVA_ISA_CTRL;
- cs->hw.diva.isac =
- card->para[1] + DIVA_ISA_ISAC_DATA;
- cs->hw.diva.hscx =
- card->para[1] + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr =
- card->para[1] + DIVA_ISA_ISAC_ADR;
- cs->hw.diva.hscx_adr =
- card->para[1] + DIVA_HSCX_ADR;
- }
- goto ready;
- } else {
- printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
- return(0);
- }
- }
- ipid++;
- pnp_c=NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
- }
- }
-#endif
-#ifdef CONFIG_PCI
- cs->subtyp = 0;
- if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
- if (pci_enable_device(dev_diva))
- return(0);
- cs->subtyp = DIVA_PCI;
- cs->irq = dev_diva->irq;
- cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
- } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
- if (pci_enable_device(dev_diva_u))
- return(0);
- cs->subtyp = DIVA_PCI;
- cs->irq = dev_diva_u->irq;
- cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
- } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
- if (pci_enable_device(dev_diva201))
- return(0);
- cs->subtyp = DIVA_IPAC_PCI;
- cs->irq = dev_diva201->irq;
- cs->hw.diva.pci_cfg =
- (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
- cs->hw.diva.cfg_reg =
- (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
- } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
- PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
- if (pci_enable_device(dev_diva202))
- return(0);
- cs->subtyp = DIVA_IPACX_PCI;
- cs->irq = dev_diva202->irq;
- cs->hw.diva.pci_cfg =
- (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
- cs->hw.diva.cfg_reg =
- (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
- } else {
- printk(KERN_WARNING "Diva: No PCI card found\n");
- return(0);
- }
-
- if (!cs->irq) {
- printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
- iounmap_diva(cs);
- return(0);
- }
-
- if (!cs->hw.diva.cfg_reg) {
- printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
- iounmap_diva(cs);
- return(0);
- }
- cs->irq_flags |= IRQF_SHARED;
-#else
- printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
- printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
- return (0);
-#endif /* CONFIG_PCI */
- if ((cs->subtyp == DIVA_IPAC_PCI) ||
- (cs->subtyp == DIVA_IPACX_PCI) ) {
- cs->hw.diva.ctrl = 0;
- cs->hw.diva.isac = 0;
- cs->hw.diva.hscx = 0;
- cs->hw.diva.isac_adr = 0;
- cs->hw.diva.hscx_adr = 0;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- bytecnt = 0;
- } else {
- cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
- cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
- cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
- cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
- cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
- bytecnt = 32;
- }
- }
-
-#ifdef __ISAPNP__
-ready:
-#endif
+ if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA))
+ bytecnt = 8;
+ else
+ bytecnt = 32;
printk(KERN_INFO
"Diva: %s card configured at %#lx IRQ %d\n",
@@ -1145,7 +933,7 @@ ready:
if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) {
printk(KERN_WARNING
"HiSax: %s config port %lx-%lx already in use\n",
- CardType[card->typ],
+ "diva",
cs->hw.diva.cfg_reg,
cs->hw.diva.cfg_reg + bytecnt);
iounmap_diva(cs);
@@ -1206,3 +994,290 @@ ready:
}
return (1);
}
+
+#ifdef CONFIG_ISA
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u_char val;
+
+ if (!card->para[1])
+ return (-1); /* card not found; continue search */
+
+ cs->hw.diva.ctrl_reg = 0;
+ cs->hw.diva.cfg_reg = card->para[1];
+ val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
+ cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
+ printk(KERN_INFO "Diva: IPAC version %x\n", val);
+ if ((val == 1) || (val==2)) {
+ cs->subtyp = DIVA_IPAC_ISA;
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
+ cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->subtyp = DIVA_ISA;
+ cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
+ cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
+ cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
+ cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
+ }
+ cs->irq = card->para[0];
+
+ return (1); /* card found */
+}
+
+#else /* if !CONFIG_ISA */
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+ return (-1); /* card not found; continue search */
+}
+
+#endif /* CONFIG_ISA */
+
+#ifdef __ISAPNP__
+static struct isapnp_device_id diva_ids[] __devinitdata = {
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+ (unsigned long) "Diva picola" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+ ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51),
+ (unsigned long) "Diva picola" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+ (unsigned long) "Diva 2.0" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+ ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71),
+ (unsigned long) "Diva 2.0" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+ (unsigned long) "Diva 2.01" },
+ { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+ ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1),
+ (unsigned long) "Diva 2.01" },
+ { 0, }
+};
+
+static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
+static struct pnp_card *pnp_c __devinitdata = NULL;
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ struct pnp_dev *pnp_d;
+
+ if (!isapnp_present())
+ return (-1); /* card not found; continue search */
+
+ while(ipid->card_vendor) {
+ if ((pnp_c = pnp_find_card(ipid->card_vendor,
+ ipid->card_device, pnp_c))) {
+ pnp_d = NULL;
+ if ((pnp_d = pnp_find_dev(pnp_c,
+ ipid->vendor, ipid->function, pnp_d))) {
+ int err;
+
+ printk(KERN_INFO "HiSax: %s detected\n",
+ (char *)ipid->driver_data);
+ pnp_disable_dev(pnp_d);
+ err = pnp_activate_dev(pnp_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ card->para[1] = pnp_port_start(pnp_d, 0);
+ card->para[0] = pnp_irq(pnp_d, 0);
+ if (!card->para[0] || !card->para[1]) {
+ printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
+ card->para[0], card->para[1]);
+ pnp_disable_dev(pnp_d);
+ return(0);
+ }
+ cs->hw.diva.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
+ cs->subtyp = DIVA_IPAC_ISA;
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac =
+ card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.hscx =
+ card->para[1] + DIVA_IPAC_DATA;
+ cs->hw.diva.isac_adr =
+ card->para[1] + DIVA_IPAC_ADR;
+ cs->hw.diva.hscx_adr =
+ card->para[1] + DIVA_IPAC_ADR;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->subtyp = DIVA_ISA;
+ cs->hw.diva.ctrl =
+ card->para[1] + DIVA_ISA_CTRL;
+ cs->hw.diva.isac =
+ card->para[1] + DIVA_ISA_ISAC_DATA;
+ cs->hw.diva.hscx =
+ card->para[1] + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr =
+ card->para[1] + DIVA_ISA_ISAC_ADR;
+ cs->hw.diva.hscx_adr =
+ card->para[1] + DIVA_HSCX_ADR;
+ }
+ return (1); /* card found */
+ } else {
+ printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
+ return(0);
+ }
+ }
+ ipid++;
+ pnp_c=NULL;
+ }
+
+ return (-1); /* card not found; continue search */
+}
+
+#else /* if !ISAPNP */
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+ return (-1); /* card not found; continue search */
+}
+
+#endif /* ISAPNP */
+
+#ifdef CONFIG_PCI_LEGACY
+static struct pci_dev *dev_diva __devinitdata = NULL;
+static struct pci_dev *dev_diva_u __devinitdata = NULL;
+static struct pci_dev *dev_diva201 __devinitdata = NULL;
+static struct pci_dev *dev_diva202 __devinitdata = NULL;
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+
+ cs->subtyp = 0;
+ if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
+ if (pci_enable_device(dev_diva))
+ return(0);
+ cs->subtyp = DIVA_PCI;
+ cs->irq = dev_diva->irq;
+ cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
+ } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
+ if (pci_enable_device(dev_diva_u))
+ return(0);
+ cs->subtyp = DIVA_PCI;
+ cs->irq = dev_diva_u->irq;
+ cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
+ } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
+ if (pci_enable_device(dev_diva201))
+ return(0);
+ cs->subtyp = DIVA_IPAC_PCI;
+ cs->irq = dev_diva201->irq;
+ cs->hw.diva.pci_cfg =
+ (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
+ cs->hw.diva.cfg_reg =
+ (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
+ } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
+ if (pci_enable_device(dev_diva202))
+ return(0);
+ cs->subtyp = DIVA_IPACX_PCI;
+ cs->irq = dev_diva202->irq;
+ cs->hw.diva.pci_cfg =
+ (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
+ cs->hw.diva.cfg_reg =
+ (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
+ } else {
+ return (-1); /* card not found; continue search */
+ }
+
+ if (!cs->irq) {
+ printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
+ iounmap_diva(cs);
+ return(0);
+ }
+
+ if (!cs->hw.diva.cfg_reg) {
+ printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
+ iounmap_diva(cs);
+ return(0);
+ }
+ cs->irq_flags |= IRQF_SHARED;
+
+ if ((cs->subtyp == DIVA_IPAC_PCI) ||
+ (cs->subtyp == DIVA_IPACX_PCI) ) {
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac = 0;
+ cs->hw.diva.hscx = 0;
+ cs->hw.diva.isac_adr = 0;
+ cs->hw.diva.hscx_adr = 0;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
+ cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
+ cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
+ cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
+ cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
+ }
+
+ return (1); /* card found */
+}
+
+#else /* if !CONFIG_PCI_LEGACY */
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+ return (-1); /* card not found; continue search */
+}
+
+#endif /* CONFIG_PCI_LEGACY */
+
+int __devinit
+setup_diva(struct IsdnCard *card)
+{
+ int rc, have_card = 0;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, Diva_revision);
+ printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
+ return(0);
+ cs->hw.diva.status = 0;
+
+ rc = setup_diva_isa(card);
+ if (!rc)
+ return rc;
+ if (rc > 0) {
+ have_card = 1;
+ goto ready;
+ }
+
+ rc = setup_diva_isapnp(card);
+ if (!rc)
+ return rc;
+ if (rc > 0) {
+ have_card = 1;
+ goto ready;
+ }
+
+ rc = setup_diva_pci(card);
+ if (!rc)
+ return rc;
+ if (rc > 0)
+ have_card = 1;
+
+ready:
+ if (!have_card) {
+ printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n");
+ return(0);
+ }
+
+ return setup_diva_common(card->cs);
+}
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index fab3e4ea059..d272d8ce653 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -30,8 +30,6 @@
#include <linux/serial.h>
#include <linux/serial_reg.h>
-extern const char *CardType[];
-
static const char *Elsa_revision = "$Revision: 2.32.2.4 $";
static const char *Elsa_Types[] =
{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
@@ -832,8 +830,75 @@ probe_elsa(struct IsdnCardState *cs)
return (CARD_portlist[i]);
}
-static struct pci_dev *dev_qs1000 __devinitdata = NULL;
-static struct pci_dev *dev_qs3000 __devinitdata = NULL;
+static int __devinit
+setup_elsa_isa(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u_char val;
+
+ cs->hw.elsa.base = card->para[0];
+ printk(KERN_INFO "Elsa: Microlink IO probing\n");
+ if (cs->hw.elsa.base) {
+ if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
+ cs->typ))) {
+ printk(KERN_WARNING
+ "Elsa: no Elsa Microlink at %#lx\n",
+ cs->hw.elsa.base);
+ return (0);
+ }
+ } else
+ cs->hw.elsa.base = probe_elsa(cs);
+
+ if (!cs->hw.elsa.base) {
+ printk(KERN_WARNING
+ "No Elsa Microlink found\n");
+ return (0);
+ }
+
+ cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+ cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+ cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+ cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+ val = bytein(cs->hw.elsa.cfg);
+ if (cs->subtyp == ELSA_PC) {
+ const u_char CARD_IrqTab[8] =
+ {7, 3, 5, 9, 0, 0, 0, 0};
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
+ } else if (cs->subtyp == ELSA_PCC8) {
+ const u_char CARD_IrqTab[8] =
+ {7, 3, 5, 9, 0, 0, 0, 0};
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
+ } else {
+ const u_char CARD_IrqTab[8] =
+ {15, 10, 15, 3, 11, 5, 11, 9};
+ cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
+ }
+ val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
+ if (val < 3)
+ val |= 8;
+ val += 'A' - 3;
+ if (val == 'B' || val == 'C')
+ val ^= 1;
+ if ((cs->subtyp == ELSA_PCFPRO) && (val == 'G'))
+ val = 'C';
+ printk(KERN_INFO
+ "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ val, cs->irq);
+ val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
+ if (val) {
+ printk(KERN_WARNING
+ "Elsa: Microlink S0 bus power bad\n");
+ cs->hw.elsa.status |= ELSA_BAD_PWR;
+ }
+
+ return (1);
+}
#ifdef __ISAPNP__
static struct isapnp_device_id elsa_ids[] __devinitdata = {
@@ -848,233 +913,194 @@ static struct isapnp_device_id elsa_ids[] __devinitdata = {
static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
+#endif /* __ISAPNP__ */
-int __devinit
-setup_elsa(struct IsdnCard *card)
+static int __devinit
+setup_elsa_isapnp(struct IsdnCard *card)
{
- int bytecnt;
- u_char val;
struct IsdnCardState *cs = card->cs;
- char tmp[64];
- strcpy(tmp, Elsa_revision);
- printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
- cs->hw.elsa.ctrl_reg = 0;
- cs->hw.elsa.status = 0;
- cs->hw.elsa.MFlag = 0;
- cs->subtyp = 0;
- if (cs->typ == ISDN_CTYPE_ELSA) {
- cs->hw.elsa.base = card->para[0];
- printk(KERN_INFO "Elsa: Microlink IO probing\n");
- if (cs->hw.elsa.base) {
- if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
- cs->typ))) {
- printk(KERN_WARNING
- "Elsa: no Elsa Microlink at %#lx\n",
- cs->hw.elsa.base);
- return (0);
- }
- } else
- cs->hw.elsa.base = probe_elsa(cs);
- if (cs->hw.elsa.base) {
- cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
- cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
- cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
- cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
- val = bytein(cs->hw.elsa.cfg);
- if (cs->subtyp == ELSA_PC) {
- const u_char CARD_IrqTab[8] =
- {7, 3, 5, 9, 0, 0, 0, 0};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
- } else if (cs->subtyp == ELSA_PCC8) {
- const u_char CARD_IrqTab[8] =
- {7, 3, 5, 9, 0, 0, 0, 0};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
- } else {
- const u_char CARD_IrqTab[8] =
- {15, 10, 15, 3, 11, 5, 11, 9};
- cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
- }
- val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
- if (val < 3)
- val |= 8;
- val += 'A' - 3;
- if (val == 'B' || val == 'C')
- val ^= 1;
- if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
- val = 'C';
- printk(KERN_INFO
- "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- val, cs->irq);
- val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
- if (val) {
- printk(KERN_WARNING
- "Elsa: Microlink S0 bus power bad\n");
- cs->hw.elsa.status |= ELSA_BAD_PWR;
- }
- } else {
- printk(KERN_WARNING
- "No Elsa Microlink found\n");
- return (0);
- }
- } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
#ifdef __ISAPNP__
- if (!card->para[1] && isapnp_present()) {
- struct pnp_dev *pnp_d;
- while(ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
+ if (!card->para[1] && isapnp_present()) {
+ struct pnp_dev *pnp_d;
+ while(ipid->card_vendor) {
+ if ((pnp_c = pnp_find_card(ipid->card_vendor,
+ ipid->card_device, pnp_c))) {
+ pnp_d = NULL;
+ if ((pnp_d = pnp_find_dev(pnp_c,
+ ipid->vendor, ipid->function, pnp_d))) {
+ int err;
+
+ printk(KERN_INFO "HiSax: %s detected\n",
+ (char *)ipid->driver_data);
+ pnp_disable_dev(pnp_d);
+ err = pnp_activate_dev(pnp_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ card->para[1] = pnp_port_start(pnp_d, 0);
+ card->para[0] = pnp_irq(pnp_d, 0);
+
+ if (!card->para[0] || !card->para[1]) {
+ printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
+ card->para[0], card->para[1]);
pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
-
- if (!card->para[0] || !card->para[1]) {
- printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return(0);
- }
- if (ipid->function == ISAPNP_FUNCTION(0x133))
- cs->subtyp = ELSA_QS1000;
- else
- cs->subtyp = ELSA_QS3000;
- break;
- } else {
- printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
return(0);
}
+ if (ipid->function == ISAPNP_FUNCTION(0x133))
+ cs->subtyp = ELSA_QS1000;
+ else
+ cs->subtyp = ELSA_QS3000;
+ break;
+ } else {
+ printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
+ return(0);
}
- ipid++;
- pnp_c=NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
- return(0);
}
+ ipid++;
+ pnp_c=NULL;
+ }
+ if (!ipid->card_vendor) {
+ printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
+ return(0);
}
-#endif
- if (card->para[1] && card->para[0]) {
- cs->hw.elsa.base = card->para[1];
- cs->irq = card->para[0];
- if (!cs->subtyp)
- cs->subtyp = ELSA_QS1000;
- } else {
- printk(KERN_ERR "Elsa PnP: no parameter\n");
- }
- cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
- cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
- cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->irq);
- } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) {
+ }
+#endif /* __ISAPNP__ */
+
+ if (card->para[1] && card->para[0]) {
cs->hw.elsa.base = card->para[1];
cs->irq = card->para[0];
- val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
- if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
- cs->subtyp = ELSA_PCMCIA_IPAC;
- cs->hw.elsa.ale = cs->hw.elsa.base + 0;
- cs->hw.elsa.isac = cs->hw.elsa.base + 2;
- cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- } else {
- cs->subtyp = ELSA_PCMCIA;
- cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
- cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
- cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
- }
- cs->hw.elsa.timer = 0;
- cs->hw.elsa.trig = 0;
- cs->hw.elsa.ctrl = 0;
- cs->irq_flags |= IRQF_SHARED;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->irq);
- } else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
-#ifdef CONFIG_PCI
- cs->subtyp = 0;
- if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
- PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
- if (pci_enable_device(dev_qs1000))
- return(0);
- cs->subtyp = ELSA_QS1000PCI;
- cs->irq = dev_qs1000->irq;
- cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
- cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
- } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
- PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
- if (pci_enable_device(dev_qs3000))
- return(0);
- cs->subtyp = ELSA_QS3000PCI;
- cs->irq = dev_qs3000->irq;
- cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
- cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
- } else {
- printk(KERN_WARNING "Elsa: No PCI card found\n");
+ if (!cs->subtyp)
+ cs->subtyp = ELSA_QS1000;
+ } else {
+ printk(KERN_ERR "Elsa PnP: no parameter\n");
+ }
+ cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+ cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+ cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+ printk(KERN_INFO
+ "Elsa: %s defined at %#lx IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->irq);
+
+ return (1);
+}
+
+static void __devinit
+setup_elsa_pcmcia(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u_char val;
+
+ cs->hw.elsa.base = card->para[1];
+ cs->irq = card->para[0];
+ val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
+ if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
+ cs->subtyp = ELSA_PCMCIA_IPAC;
+ cs->hw.elsa.ale = cs->hw.elsa.base + 0;
+ cs->hw.elsa.isac = cs->hw.elsa.base + 2;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ } else {
+ cs->subtyp = ELSA_PCMCIA;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
+ cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+ }
+ cs->hw.elsa.timer = 0;
+ cs->hw.elsa.trig = 0;
+ cs->hw.elsa.ctrl = 0;
+ cs->irq_flags |= IRQF_SHARED;
+ printk(KERN_INFO
+ "Elsa: %s defined at %#lx IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->irq);
+}
+
+#ifdef CONFIG_PCI_LEGACY
+static struct pci_dev *dev_qs1000 __devinitdata = NULL;
+static struct pci_dev *dev_qs3000 __devinitdata = NULL;
+
+static int __devinit
+setup_elsa_pci(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+
+ cs->subtyp = 0;
+ if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+ PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
+ if (pci_enable_device(dev_qs1000))
return(0);
- }
- if (!cs->irq) {
- printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+ cs->subtyp = ELSA_QS1000PCI;
+ cs->irq = dev_qs1000->irq;
+ cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
+ cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
+ } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+ PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
+ if (pci_enable_device(dev_qs3000))
return(0);
- }
+ cs->subtyp = ELSA_QS3000PCI;
+ cs->irq = dev_qs3000->irq;
+ cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
+ cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
+ } else {
+ printk(KERN_WARNING "Elsa: No PCI card found\n");
+ return(0);
+ }
+ if (!cs->irq) {
+ printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+ return(0);
+ }
+
+ if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
+ printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
+ printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
+ printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
+ printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
+ }
+ cs->hw.elsa.ale = cs->hw.elsa.base;
+ cs->hw.elsa.isac = cs->hw.elsa.base +1;
+ cs->hw.elsa.hscx = cs->hw.elsa.base +1;
+ test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+ cs->hw.elsa.timer = 0;
+ cs->hw.elsa.trig = 0;
+ cs->irq_flags |= IRQF_SHARED;
+ printk(KERN_INFO
+ "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
+ Elsa_Types[cs->subtyp],
+ cs->hw.elsa.base,
+ cs->hw.elsa.cfg,
+ cs->irq);
+
+ return (1);
+}
- if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
- printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
- return(0);
- }
- if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
- printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
- printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
- printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
- }
- cs->hw.elsa.ale = cs->hw.elsa.base;
- cs->hw.elsa.isac = cs->hw.elsa.base +1;
- cs->hw.elsa.hscx = cs->hw.elsa.base +1;
- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
- cs->hw.elsa.timer = 0;
- cs->hw.elsa.trig = 0;
- cs->irq_flags |= IRQF_SHARED;
- printk(KERN_INFO
- "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
- Elsa_Types[cs->subtyp],
- cs->hw.elsa.base,
- cs->hw.elsa.cfg,
- cs->irq);
#else
- printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n");
- printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n");
- return (0);
-#endif /* CONFIG_PCI */
- } else
- return (0);
+
+static int __devinit
+setup_elsa_pci(struct IsdnCard *card)
+{
+ return (1);
+}
+#endif /* CONFIG_PCI_LEGACY */
+
+static int __devinit
+setup_elsa_common(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u_char val;
+ int bytecnt;
switch (cs->subtyp) {
case ELSA_PC:
@@ -1104,8 +1130,7 @@ setup_elsa(struct IsdnCard *card)
here, it would fail. */
if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) {
printk(KERN_WARNING
- "HiSax: %s config port %#lx-%#lx already in use\n",
- CardType[card->typ],
+ "HiSax: ELSA config port %#lx-%#lx already in use\n",
cs->hw.elsa.base,
cs->hw.elsa.base + bytecnt);
return (0);
@@ -1113,8 +1138,7 @@ setup_elsa(struct IsdnCard *card)
if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) {
printk(KERN_WARNING
- "HiSax: %s pci port %x-%x already in use\n",
- CardType[card->typ],
+ "HiSax: ELSA pci port %x-%x already in use\n",
cs->hw.elsa.cfg,
cs->hw.elsa.cfg + 0x80);
release_region(cs->hw.elsa.base, bytecnt);
@@ -1186,3 +1210,41 @@ setup_elsa(struct IsdnCard *card)
}
return (1);
}
+
+int __devinit
+setup_elsa(struct IsdnCard *card)
+{
+ int rc;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+ strcpy(tmp, Elsa_revision);
+ printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
+ cs->hw.elsa.ctrl_reg = 0;
+ cs->hw.elsa.status = 0;
+ cs->hw.elsa.MFlag = 0;
+ cs->subtyp = 0;
+
+ if (cs->typ == ISDN_CTYPE_ELSA) {
+ rc = setup_elsa_isa(card);
+ if (!rc)
+ return (0);
+
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
+ rc = setup_elsa_isapnp(card);
+ if (!rc)
+ return (0);
+
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA)
+ setup_elsa_pcmcia(card);
+
+ else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
+ rc = setup_elsa_pci(card);
+ if (!rc)
+ return (0);
+
+ } else
+ return (0);
+
+ return setup_elsa_common(card);
+}
diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c
index b73027ff50e..39f421ed8de 100644
--- a/drivers/isdn/hisax/enternow_pci.c
+++ b/drivers/isdn/hisax/enternow_pci.c
@@ -75,16 +75,16 @@
static const char *enternow_pci_rev = "$Revision: 1.1.4.5 $";
-/* für PowerISDN PCI */
+/* for PowerISDN PCI */
#define TJ_AMD_IRQ 0x20
#define TJ_LED1 0x40
#define TJ_LED2 0x80
-/* Das Fenster zum AMD...
- * Ab Adresse hw.njet.base + TJ_AMD_PORT werden vom AMD jeweils 8 Bit in
- * den TigerJet i/o-Raum gemappt
- * -> 0x01 des AMD bei hw.njet.base + 0C4 */
+/* The window to [the] AMD [chip]...
+ * From address hw.njet.base + TJ_AMD_PORT onwards, the AMD
+ * maps [consecutive/multiple] 8 bits into the TigerJet I/O space
+ * -> 0x01 of the AMD at hw.njet.base + 0C4 */
#define TJ_AMD_PORT 0xC0
@@ -96,11 +96,11 @@ static const char *enternow_pci_rev = "$Revision: 1.1.4.5 $";
static unsigned char
ReadByteAmd7930(struct IsdnCardState *cs, unsigned char offset)
{
- /* direktes Register */
+ /* direct register */
if(offset < 8)
return (inb(cs->hw.njet.isac + 4*offset));
- /* indirektes Register */
+ /* indirect register */
else {
outb(offset, cs->hw.njet.isac + 4*AMD_CR);
return(inb(cs->hw.njet.isac + 4*AMD_DR));
@@ -111,11 +111,11 @@ ReadByteAmd7930(struct IsdnCardState *cs, unsigned char offset)
static void
WriteByteAmd7930(struct IsdnCardState *cs, unsigned char offset, unsigned char value)
{
- /* direktes Register */
+ /* direct register */
if(offset < 8)
outb(value, cs->hw.njet.isac + 4*offset);
- /* indirektes Register */
+ /* indirect register */
else {
outb(offset, cs->hw.njet.isac + 4*AMD_CR);
outb(value, cs->hw.njet.isac + 4*AMD_DR);
diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c
index 3efa719b6d2..f66620ad8e7 100644
--- a/drivers/isdn/hisax/gazel.c
+++ b/drivers/isdn/hisax/gazel.c
@@ -532,6 +532,7 @@ setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
return (0);
}
+#ifdef CONFIG_PCI_LEGACY
static struct pci_dev *dev_tel __devinitdata = NULL;
static int __devinit
@@ -620,6 +621,7 @@ setup_gazelpci(struct IsdnCardState *cs)
return (0);
}
+#endif /* CONFIG_PCI_LEGACY */
int __devinit
setup_gazel(struct IsdnCard *card)
@@ -639,7 +641,7 @@ setup_gazel(struct IsdnCard *card)
return (0);
} else {
-#ifdef CONFIG_PCI
+#ifdef CONFIG_PCI_LEGACY
if (setup_gazelpci(cs))
return (0);
#else
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index 8d9864453a2..5c46a7130e0 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -1019,7 +1019,8 @@ hfc_dbusy_timer(struct IsdnCardState *cs)
static unsigned int
*init_send_hfcd(int cnt)
{
- int i, *send;
+ int i;
+ unsigned *send;
if (!(send = kmalloc(cnt * sizeof(unsigned int), GFP_ATOMIC))) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 077080aca79..fba8b624ffc 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -1,6 +1,6 @@
/* $Id: hfc_pci.c,v 1.48.2.4 2004/02/11 13:21:33 keil Exp $
*
- * low level driver for CCD´s hfc-pci based cards
+ * low level driver for CCD's hfc-pci based cards
*
* Author Werner Cornelius
* based on existing driver for CCD hfc ISA cards
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 60843b3f3b6..98b0149bca6 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -1,7 +1,7 @@
/*
* hfc_usb.c
*
- * $Id: hfc_usb.c,v 2.3.2.20 2007/08/20 14:07:54 mbachem Exp $
+ * $Id: hfc_usb.c,v 2.3.2.24 2007/10/14 08:40:29 mbachem Exp $
*
* modular HiSax ISDN driver for Colognechip HFC-S USB chip
*
@@ -45,7 +45,7 @@
#include "hfc_usb.h"
static const char *hfcusb_revision =
- "$Revision: 2.3.2.20 $ $Date: 2007/08/20 14:07:54 $ ";
+ "$Revision: 2.3.2.24 $ $Date: 2007/10/14 08:40:29 $ ";
/* Hisax debug support
* debug flags defined in hfc_usb.h as HFCUSB_DBG_[*]
@@ -126,6 +126,12 @@ static struct usb_device_id hfcusb_idtab[] = {
{LED_SCHEME1, {0x80, -64, -32, -16},
"Twister ISDN TA"}),
},
+ {
+ USB_DEVICE(0x071d, 0x1005),
+ .driver_info = (unsigned long) &((hfcsusb_vdata)
+ {LED_SCHEME1, {0x02, 0, 0x01, 0x04},
+ "Eicon DIVA USB 4.0"}),
+ },
{ }
};
@@ -187,7 +193,7 @@ typedef struct hfcusb_data {
struct usb_ctrlrequest ctrl_write; /* buffer for control write request */
struct usb_ctrlrequest ctrl_read; /* same for read request */
- __u8 old_led_state, led_state, led_new_data, led_b_active;
+ __u8 old_led_state, led_state;
volatile __u8 threshold_mask; /* threshold actually reported */
volatile __u8 bch_enables; /* or mask for sctrl_r and sctrl register values */
@@ -263,7 +269,7 @@ ctrl_complete(struct urb *urb)
ctrl_start_transfer(hfc); /* start next transfer */
}
-} /* ctrl_complete */
+}
/* write led data to auxport & invert if necessary */
static void
@@ -276,18 +282,18 @@ write_led(hfcusb_data * hfc, __u8 led_state)
}
static void
-set_led_bit(hfcusb_data * hfc, signed short led_bits, int unset)
+set_led_bit(hfcusb_data * hfc, signed short led_bits, int on)
{
- if (unset) {
+ if (on) {
if (led_bits < 0)
- hfc->led_state |= abs(led_bits);
+ hfc->led_state &= ~abs(led_bits);
else
- hfc->led_state &= ~led_bits;
+ hfc->led_state |= led_bits;
} else {
if (led_bits < 0)
- hfc->led_state &= ~abs(led_bits);
+ hfc->led_state |= abs(led_bits);
else
- hfc->led_state |= led_bits;
+ hfc->led_state &= ~led_bits;
}
}
@@ -304,34 +310,34 @@ handle_led(hfcusb_data * hfc, int event)
switch (event) {
case LED_POWER_ON:
- set_led_bit(hfc, driver_info->led_bits[0], 0);
- set_led_bit(hfc, driver_info->led_bits[1], 1);
- set_led_bit(hfc, driver_info->led_bits[2], 1);
- set_led_bit(hfc, driver_info->led_bits[3], 1);
+ set_led_bit(hfc, driver_info->led_bits[0], 1);
+ set_led_bit(hfc, driver_info->led_bits[1], 0);
+ set_led_bit(hfc, driver_info->led_bits[2], 0);
+ set_led_bit(hfc, driver_info->led_bits[3], 0);
break;
case LED_POWER_OFF:
- set_led_bit(hfc, driver_info->led_bits[0], 1);
- set_led_bit(hfc, driver_info->led_bits[1], 1);
- set_led_bit(hfc, driver_info->led_bits[2], 1);
- set_led_bit(hfc, driver_info->led_bits[3], 1);
+ set_led_bit(hfc, driver_info->led_bits[0], 0);
+ set_led_bit(hfc, driver_info->led_bits[1], 0);
+ set_led_bit(hfc, driver_info->led_bits[2], 0);
+ set_led_bit(hfc, driver_info->led_bits[3], 0);
break;
case LED_S0_ON:
- set_led_bit(hfc, driver_info->led_bits[1], 0);
+ set_led_bit(hfc, driver_info->led_bits[1], 1);
break;
case LED_S0_OFF:
- set_led_bit(hfc, driver_info->led_bits[1], 1);
+ set_led_bit(hfc, driver_info->led_bits[1], 0);
break;
case LED_B1_ON:
- set_led_bit(hfc, driver_info->led_bits[2], 0);
+ set_led_bit(hfc, driver_info->led_bits[2], 1);
break;
case LED_B1_OFF:
- set_led_bit(hfc, driver_info->led_bits[2], 1);
+ set_led_bit(hfc, driver_info->led_bits[2], 0);
break;
case LED_B2_ON:
- set_led_bit(hfc, driver_info->led_bits[3], 0);
+ set_led_bit(hfc, driver_info->led_bits[3], 1);
break;
case LED_B2_OFF:
- set_led_bit(hfc, driver_info->led_bits[3], 1);
+ set_led_bit(hfc, driver_info->led_bits[3], 0);
break;
}
write_led(hfc, hfc->led_state);
@@ -1159,7 +1165,6 @@ hfc_usb_init(hfcusb_data * hfc)
hfc->l1_activated = 0;
hfc->disc_flag = 0;
hfc->led_state = 0;
- hfc->led_new_data = 0;
hfc->old_led_state = 0;
/* init the t3 timer */
@@ -1514,20 +1519,18 @@ hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* callback for unplugged USB device */
static void
-hfc_usb_disconnect(struct usb_interface
- *intf)
+hfc_usb_disconnect(struct usb_interface *intf)
{
hfcusb_data *context = usb_get_intfdata(intf);
int i;
handle_led(context, LED_POWER_OFF);
- schedule_timeout((10 * HZ) / 1000);
+ schedule_timeout(HZ / 100);
printk(KERN_INFO "HFC-S USB: device disconnect\n");
context->disc_flag = 1;
usb_set_intfdata(intf, NULL);
- if (!context)
- return;
+
if (timer_pending(&context->t3_timer))
del_timer(&context->t3_timer);
if (timer_pending(&context->t4_timer))
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 3cd8d5ba239..34733c903df 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -202,7 +202,7 @@ struct Layer1 {
void *hardware;
struct BCState *bcs;
struct PStack **stlistp;
- long Flags;
+ unsigned long Flags;
struct FsmInst l1m;
struct FsmTimer timer;
void (*l1l2) (struct PStack *, int, void *);
diff --git a/drivers/isdn/hisax/hisax_if.h b/drivers/isdn/hisax/hisax_if.h
index 4898fce2d50..aa7c94037b2 100644
--- a/drivers/isdn/hisax/hisax_if.h
+++ b/drivers/isdn/hisax/hisax_if.h
@@ -56,7 +56,7 @@ struct hisax_d_if {
struct IsdnCardState *cs;
struct hisax_b_if *b_if[2];
struct sk_buff_head erq;
- long ph_state;
+ unsigned long ph_state;
};
int hisax_register(struct hisax_d_if *hisax_if, struct hisax_b_if *b_if[],
diff --git a/drivers/isdn/hisax/isdnhdlc.c b/drivers/isdn/hisax/isdnhdlc.c
index 268dced6c34..c69a77a8006 100644
--- a/drivers/isdn/hisax/isdnhdlc.c
+++ b/drivers/isdn/hisax/isdnhdlc.c
@@ -1,7 +1,7 @@
/*
* isdnhdlc.c -- General purpose ISDN HDLC decoder.
*
- *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
+ *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
* 2001 Frode Isaksen <fisaksen@bewan.com>
* 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
*
@@ -27,7 +27,7 @@
/*-------------------------------------------------------------------*/
-MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
+MODULE_AUTHOR("Wolfgang Mües <wolfgang@iksw-muees.de>, "
"Frode Isaksen <fisaksen@bewan.com>, "
"Kai Germaschewski <kai.germaschewski@gmx.de>");
MODULE_DESCRIPTION("General purpose ISDN HDLC decoder");
diff --git a/drivers/isdn/hisax/isdnhdlc.h b/drivers/isdn/hisax/isdnhdlc.h
index 45167d2f8fb..cf0a95a2401 100644
--- a/drivers/isdn/hisax/isdnhdlc.h
+++ b/drivers/isdn/hisax/isdnhdlc.h
@@ -5,7 +5,7 @@
* Neccessary because some ISDN devices don't have HDLC
* controllers. Also included: a bit reversal table.
*
- *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
+ *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
* 2001 Frode Isaksen <fisaksen@bewan.com>
* 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
*
diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c
index 43d61d1bc5b..70840a710ac 100644
--- a/drivers/isdn/hisax/jade.c
+++ b/drivers/isdn/hisax/jade.c
@@ -304,7 +304,7 @@ initjade(struct IsdnCardState *cs)
cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00);
/* Setup host access to hdlc controller */
jade_write_indirect(cs, jade_HDLCCNTRACCESS, (jadeINDIRECT_HAH1|jadeINDIRECT_HAH2));
- /* Unmask HDLC int (don´t forget DSP int later on)*/
+ /* Unmask HDLC int (don't forget DSP int later on)*/
cs->BC_Write_Reg(cs, -1,jade_INT, (jadeINT_HDLC1|jadeINT_HDLC2));
/* once again TRANSPARENT */
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
index e5918c6fe73..bd9921128aa 100644
--- a/drivers/isdn/hisax/niccy.c
+++ b/drivers/isdn/hisax/niccy.c
@@ -223,7 +223,6 @@ static int niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return 0;
}
-static struct pci_dev *niccy_dev __devinitdata = NULL;
#ifdef __ISAPNP__
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
@@ -299,7 +298,9 @@ int __devinit setup_niccy(struct IsdnCard *card)
return 0;
}
} else {
-#ifdef CONFIG_PCI
+#ifdef CONFIG_PCI_LEGACY
+ static struct pci_dev *niccy_dev __devinitdata;
+
u_int pci_ioaddr;
cs->subtyp = 0;
if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM,
@@ -356,7 +357,7 @@ int __devinit setup_niccy(struct IsdnCard *card)
printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
return 0;
-#endif /* CONFIG_PCI */
+#endif /* CONFIG_PCI_LEGACY */
}
printk(KERN_INFO "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n",
CardType[cs->typ], (cs->subtyp == 1) ? "PnP" : "PCI",
diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
index fa2db87667c..a895dfed40e 100644
--- a/drivers/isdn/hisax/nj_s.c
+++ b/drivers/isdn/hisax/nj_s.c
@@ -151,7 +151,7 @@ NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
static int __devinit njs_pci_probe(struct pci_dev *dev_netjet,
struct IsdnCardState *cs)
{
- int cfg;
+ u32 cfg;
if (pci_enable_device(dev_netjet))
return(0);
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index ad06f3cc60f..95425f3d222 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -518,8 +518,6 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_sedl __devinitdata = NULL;
-
#ifdef __ISAPNP__
static struct isapnp_device_id sedl_ids[] __devinitdata = {
{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
@@ -533,15 +531,158 @@ static struct isapnp_device_id sedl_ids[] __devinitdata = {
static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
+
+static int __devinit
+setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+{
+ struct IsdnCardState *cs = card->cs;
+ struct pnp_dev *pnp_d;
+
+ if (!isapnp_present())
+ return -1;
+
+ while(ipid->card_vendor) {
+ if ((pnp_c = pnp_find_card(ipid->card_vendor,
+ ipid->card_device, pnp_c))) {
+ pnp_d = NULL;
+ if ((pnp_d = pnp_find_dev(pnp_c,
+ ipid->vendor, ipid->function, pnp_d))) {
+ int err;
+
+ printk(KERN_INFO "HiSax: %s detected\n",
+ (char *)ipid->driver_data);
+ pnp_disable_dev(pnp_d);
+ err = pnp_activate_dev(pnp_d);
+ if (err<0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+ __FUNCTION__, err);
+ return(0);
+ }
+ card->para[1] = pnp_port_start(pnp_d, 0);
+ card->para[0] = pnp_irq(pnp_d, 0);
+
+ if (!card->para[0] || !card->para[1]) {
+ printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
+ card->para[0], card->para[1]);
+ pnp_disable_dev(pnp_d);
+ return(0);
+ }
+ cs->hw.sedl.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ if (ipid->function == ISAPNP_FUNCTION(0x2)) {
+ cs->subtyp = SEDL_SPEED_FAX;
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ *bytecnt = 16;
+ } else {
+ cs->subtyp = SEDL_SPEED_CARD_WIN;
+ cs->hw.sedl.chip = SEDL_CHIP_TEST;
+ }
+
+ return (1);
+ } else {
+ printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
+ return(0);
+ }
+ }
+ ipid++;
+ pnp_c = NULL;
+ }
+
+ printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
+ return -1;
+}
+#else
+
+static int __devinit
+setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+{
+ return -1;
+}
+#endif /* __ISAPNP__ */
+
+#ifdef CONFIG_PCI_LEGACY
+static struct pci_dev *dev_sedl __devinitdata = NULL;
+
+static int __devinit
+setup_sedlbauer_pci(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ u16 sub_vendor_id, sub_id;
+
+ if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
+ if (pci_enable_device(dev_sedl))
+ return(0);
+ cs->irq = dev_sedl->irq;
+ if (!cs->irq) {
+ printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
+ return(0);
+ }
+ cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
+ } else {
+ printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
+ return(0);
+ }
+ cs->irq_flags |= IRQF_SHARED;
+ cs->hw.sedl.bus = SEDL_BUS_PCI;
+ sub_vendor_id = dev_sedl->subsystem_vendor;
+ sub_id = dev_sedl->subsystem_device;
+ printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
+ sub_vendor_id, sub_id);
+ printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
+ cs->hw.sedl.cfg_reg);
+ if (sub_id != PCI_SUB_ID_SEDLBAUER) {
+ printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
+ return(0);
+ }
+ if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ cs->subtyp = SEDL_SPEEDFAX_PCI;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
+ cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+ cs->subtyp = HST_SAPHIR3;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
+ cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+ cs->subtyp = SEDL_SPEED_PCI;
+ } else {
+ printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
+ sub_vendor_id);
+ return(0);
+ }
+
+ cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
+ cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
+ byteout(cs->hw.sedl.cfg_reg, 0xff);
+ byteout(cs->hw.sedl.cfg_reg, 0x00);
+ byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
+ byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
+ byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+ mdelay(2);
+ byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+ mdelay(10);
+
+ return (1);
+}
+
+#else
+
+static int __devinit
+setup_sedlbauer_pci(struct IsdnCard *card)
+{
+ return (1);
+}
+
+#endif /* CONFIG_PCI_LEGACY */
int __devinit
setup_sedlbauer(struct IsdnCard *card)
{
- int bytecnt, ver, val;
+ int bytecnt = 8, ver, val, rc;
struct IsdnCardState *cs = card->cs;
char tmp[64];
- u16 sub_vendor_id, sub_id;
strcpy(tmp, Sedlbauer_revision);
printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
@@ -569,124 +710,21 @@ setup_sedlbauer(struct IsdnCard *card)
bytecnt = 16;
}
} else {
-#ifdef __ISAPNP__
- if (isapnp_present()) {
- struct pnp_dev *pnp_d;
- while(ipid->card_vendor) {
- if ((pnp_c = pnp_find_card(ipid->card_vendor,
- ipid->card_device, pnp_c))) {
- pnp_d = NULL;
- if ((pnp_d = pnp_find_dev(pnp_c,
- ipid->vendor, ipid->function, pnp_d))) {
- int err;
-
- printk(KERN_INFO "HiSax: %s detected\n",
- (char *)ipid->driver_data);
- pnp_disable_dev(pnp_d);
- err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
- }
- card->para[1] = pnp_port_start(pnp_d, 0);
- card->para[0] = pnp_irq(pnp_d, 0);
-
- if (!card->para[0] || !card->para[1]) {
- printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
- card->para[0], card->para[1]);
- pnp_disable_dev(pnp_d);
- return(0);
- }
- cs->hw.sedl.cfg_reg = card->para[1];
- cs->irq = card->para[0];
- if (ipid->function == ISAPNP_FUNCTION(0x2)) {
- cs->subtyp = SEDL_SPEED_FAX;
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- bytecnt = 16;
- } else {
- cs->subtyp = SEDL_SPEED_CARD_WIN;
- cs->hw.sedl.chip = SEDL_CHIP_TEST;
- }
- goto ready;
- } else {
- printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
- return(0);
- }
- }
- ipid++;
- pnp_c = NULL;
- }
- if (!ipid->card_vendor) {
- printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
- }
- }
-#endif
-/* Probe for Sedlbauer speed pci */
-#ifdef CONFIG_PCI
- if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
- PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
- if (pci_enable_device(dev_sedl))
- return(0);
- cs->irq = dev_sedl->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
- return(0);
- }
- cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
- } else {
- printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
- return(0);
- }
- cs->irq_flags |= IRQF_SHARED;
- cs->hw.sedl.bus = SEDL_BUS_PCI;
- sub_vendor_id = dev_sedl->subsystem_vendor;
- sub_id = dev_sedl->subsystem_device;
- printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
- sub_vendor_id, sub_id);
- printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
- cs->hw.sedl.cfg_reg);
- if (sub_id != PCI_SUB_ID_SEDLBAUER) {
- printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
- return(0);
- }
- if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
- } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
- cs->subtyp = SEDL_SPEEDFAX_PCI;
- } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
- cs->hw.sedl.chip = SEDL_CHIP_IPAC;
- cs->subtyp = HST_SAPHIR3;
- } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
- cs->hw.sedl.chip = SEDL_CHIP_IPAC;
- cs->subtyp = SEDL_SPEED_PCI;
- } else {
- printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
- sub_vendor_id);
- return(0);
- }
+ rc = setup_sedlbauer_isapnp(card, &bytecnt);
+ if (!rc)
+ return (0);
+ if (rc > 0)
+ goto ready;
+
+ /* Probe for Sedlbauer speed pci */
+ rc = setup_sedlbauer_pci(card);
+ if (!rc)
+ return (0);
+
bytecnt = 256;
- cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
- cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
- byteout(cs->hw.sedl.cfg_reg, 0xff);
- byteout(cs->hw.sedl.cfg_reg, 0x00);
- byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
- byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
- byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
- mdelay(2);
- byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
- mdelay(10);
-#else
- printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
- return (0);
-#endif /* CONFIG_PCI */
}
-#ifdef __ISAPNP__
ready:
-#endif
/* In case of the sedlbauer pcmcia card, this region is in use,
* reserved for us by the card manager. So we do not check it
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index d09f6d033f1..4393003ae16 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -295,11 +295,12 @@ setup_telespci(struct IsdnCard *card)
#ifdef __BIG_ENDIAN
#error "not running on big endian machines now"
#endif
+
strcpy(tmp, telespci_revision);
printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_TELESPCI)
return (0);
-#ifdef CONFIG_PCI
+
if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
if (pci_enable_device(dev_tel))
return(0);
@@ -317,11 +318,6 @@ setup_telespci(struct IsdnCard *card)
printk(KERN_WARNING "TelesPCI: No PCI card found\n");
return(0);
}
-#else
- printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n");
- printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n");
- return (0);
-#endif /* CONFIG_PCI */
/* Initialize Zoran PCI controller */
writel(0x00000000, cs->hw.teles0.membase + 0x28);
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index 3aeceaf9769..39129b94f8b 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -1009,7 +1009,7 @@ setup_w6692(struct IsdnCard *card)
printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_W6692)
return (0);
-#ifdef CONFIG_PCI
+
while (id_list[id_idx].vendor_id) {
dev_w6692 = pci_find_device(id_list[id_idx].vendor_id,
id_list[id_idx].device_id,
@@ -1061,11 +1061,6 @@ setup_w6692(struct IsdnCard *card)
cs->hw.w6692.iobase + 255);
return (0);
}
-#else
- printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n");
- printk(KERN_WARNING "HiSax: W6692 unable to config\n");
- return (0);
-#endif /* CONFIG_PCI */
printk(KERN_INFO
"HiSax: %s config irq:%d I/O:%x\n",
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
index 9e01748a176..b7cc5c2f08c 100644
--- a/drivers/isdn/hysdn/hysdn_init.c
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -20,10 +20,15 @@
#include "hysdn_defs.h"
static struct pci_device_id hysdn_pci_tbl[] = {
- {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO},
- {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2},
- {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO},
- {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO},
+ { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+ PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO },
+ { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+ PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, 0, 0, BD_CHAMP2 },
+ { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+ PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, 0, 0, BD_ERGO },
+ { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+ PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, 0, 0, BD_ERGO },
+
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl);
@@ -34,128 +39,7 @@ MODULE_LICENSE("GPL");
static char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
static int cardmax; /* number of found cards */
hysdn_card *card_root = NULL; /* pointer to first card */
-
-/**********************************************/
-/* table assigning PCI-sub ids to board types */
-/* the last entry contains all 0 */
-/**********************************************/
-static struct {
- unsigned short subid; /* PCI sub id */
- unsigned char cardtyp; /* card type assigned */
-} pci_subid_map[] = {
-
- {
- PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO
- },
- {
- PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2
- },
- {
- PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO
- },
- {
- PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO
- },
- {
- 0, 0
- } /* terminating entry */
-};
-
-
-/*********************************************************************/
-/* search_cards searches for available cards in the pci config data. */
-/* If a card is found, the card structure is allocated and the cards */
-/* ressources are reserved. cardmax is incremented. */
-/*********************************************************************/
-static void
-search_cards(void)
-{
- struct pci_dev *akt_pcidev = NULL;
- hysdn_card *card, *card_last;
- int i;
-
- card_root = NULL;
- card_last = NULL;
- while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
- akt_pcidev)) != NULL) {
- if (pci_enable_device(akt_pcidev))
- continue;
-
- if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
- printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
- return;
- }
- card->myid = cardmax; /* set own id */
- card->bus = akt_pcidev->bus->number;
- card->devfn = akt_pcidev->devfn; /* slot + function */
- card->subsysid = akt_pcidev->subsystem_device;
- card->irq = akt_pcidev->irq;
- card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
- card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
- card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
- card->brdtype = BD_NONE; /* unknown */
- card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
- card->faxchans = 0; /* default no fax channels */
- card->bchans = 2; /* and 2 b-channels */
- for (i = 0; pci_subid_map[i].subid; i++)
- if (pci_subid_map[i].subid == card->subsysid) {
- card->brdtype = pci_subid_map[i].cardtyp;
- break;
- }
- if (card->brdtype != BD_NONE) {
- if (ergo_inithardware(card)) {
- printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
- kfree(card);
- continue;
- }
- } else {
- printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid);
- kfree(card); /* release mem */
- continue;
- }
- cardmax++;
- card->next = NULL; /*end of chain */
- if (card_last)
- card_last->next = card; /* pointer to next card */
- else
- card_root = card;
- card_last = card; /* new chain end */
- } /* device found */
-} /* search_cards */
-
-/************************************************************************************/
-/* free_resources frees the acquired PCI resources and returns the allocated memory */
-/************************************************************************************/
-static void
-free_resources(void)
-{
- hysdn_card *card;
-
- while (card_root) {
- card = card_root;
- if (card->releasehardware)
- card->releasehardware(card); /* free all hardware resources */
- card_root = card_root->next; /* remove card from chain */
- kfree(card); /* return mem */
-
- } /* while card_root */
-} /* free_resources */
-
-/**************************************************************************/
-/* stop_cards disables (hardware resets) all cards and disables interrupt */
-/**************************************************************************/
-static void
-stop_cards(void)
-{
- hysdn_card *card;
-
- card = card_root; /* first in chain */
- while (card) {
- if (card->stopcard)
- card->stopcard(card);
- card = card->next; /* remove card from chain */
- } /* while card */
-} /* stop_cards */
+static hysdn_card *card_last = NULL; /* pointer to first card */
/****************************************************************************/
@@ -191,31 +75,138 @@ hysdn_getrev(const char *revision)
/* and the module is added to the list in /proc/modules, otherwise an error */
/* is assumed and the module will not be kept in memory. */
/****************************************************************************/
+
+static int __devinit hysdn_pci_init_one(struct pci_dev *akt_pcidev,
+ const struct pci_device_id *ent)
+{
+ hysdn_card *card;
+ int rc;
+
+ rc = pci_enable_device(akt_pcidev);
+ if (rc)
+ return rc;
+
+ if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
+ printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ card->myid = cardmax; /* set own id */
+ card->bus = akt_pcidev->bus->number;
+ card->devfn = akt_pcidev->devfn; /* slot + function */
+ card->subsysid = akt_pcidev->subsystem_device;
+ card->irq = akt_pcidev->irq;
+ card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
+ card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
+ card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
+ card->brdtype = BD_NONE; /* unknown */
+ card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
+ card->faxchans = 0; /* default no fax channels */
+ card->bchans = 2; /* and 2 b-channels */
+ card->brdtype = ent->driver_data;
+
+ if (ergo_inithardware(card)) {
+ printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
+ rc = -EBUSY;
+ goto err_out_card;
+ }
+
+ cardmax++;
+ card->next = NULL; /*end of chain */
+ if (card_last)
+ card_last->next = card; /* pointer to next card */
+ else
+ card_root = card;
+ card_last = card; /* new chain end */
+
+ pci_set_drvdata(akt_pcidev, card);
+ return 0;
+
+err_out_card:
+ kfree(card);
+err_out:
+ pci_disable_device(akt_pcidev);
+ return rc;
+}
+
+static void __devexit hysdn_pci_remove_one(struct pci_dev *akt_pcidev)
+{
+ hysdn_card *card = pci_get_drvdata(akt_pcidev);
+
+ pci_set_drvdata(akt_pcidev, NULL);
+
+ if (card->stopcard)
+ card->stopcard(card);
+
+#ifdef CONFIG_HYSDN_CAPI
+ hycapi_capi_release(card);
+#endif
+
+ if (card->releasehardware)
+ card->releasehardware(card); /* free all hardware resources */
+
+ if (card == card_root) {
+ card_root = card_root->next;
+ if (!card_root)
+ card_last = NULL;
+ } else {
+ hysdn_card *tmp = card_root;
+ while (tmp) {
+ if (tmp->next == card)
+ tmp->next = card->next;
+ card_last = tmp;
+ tmp = tmp->next;
+ }
+ }
+
+ kfree(card);
+ pci_disable_device(akt_pcidev);
+}
+
+static struct pci_driver hysdn_pci_driver = {
+ .name = "hysdn",
+ .id_table = hysdn_pci_tbl,
+ .probe = hysdn_pci_init_one,
+ .remove = __devexit_p(hysdn_pci_remove_one),
+};
+
+static int hysdn_have_procfs;
+
static int __init
hysdn_init(void)
{
char tmp[50];
+ int rc;
strcpy(tmp, hysdn_init_revision);
printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
strcpy(tmp, hysdn_net_revision);
printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
- search_cards();
+
+ rc = pci_register_driver(&hysdn_pci_driver);
+ if (rc)
+ return rc;
+
printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
- if (hysdn_procconf_init()) {
- free_resources(); /* proc file_sys not created */
- return (-1);
- }
+ if (!hysdn_procconf_init())
+ hysdn_have_procfs = 1;
+
#ifdef CONFIG_HYSDN_CAPI
if(cardmax > 0) {
if(hycapi_init()) {
printk(KERN_ERR "HYCAPI: init failed\n");
- return(-1);
+
+ if (hysdn_have_procfs)
+ hysdn_procconf_release();
+
+ pci_unregister_driver(&hysdn_pci_driver);
+ return -ESPIPE;
}
}
#endif /* CONFIG_HYSDN_CAPI */
- return (0); /* no error */
+
+ return 0; /* no error */
} /* init_module */
@@ -230,20 +221,15 @@ hysdn_init(void)
static void __exit
hysdn_exit(void)
{
+ if (hysdn_have_procfs)
+ hysdn_procconf_release();
+
+ pci_unregister_driver(&hysdn_pci_driver);
+
#ifdef CONFIG_HYSDN_CAPI
- hysdn_card *card;
-#endif /* CONFIG_HYSDN_CAPI */
- stop_cards();
-#ifdef CONFIG_HYSDN_CAPI
- card = card_root; /* first in chain */
- while (card) {
- hycapi_capi_release(card);
- card = card->next; /* remove card from chain */
- } /* while card */
hycapi_cleanup();
#endif /* CONFIG_HYSDN_CAPI */
- hysdn_procconf_release();
- free_resources();
+
printk(KERN_NOTICE "HYSDN: module unloaded\n");
} /* cleanup_module */
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index dc477e0aab0..27d890b48f8 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -16,6 +16,7 @@
#include <linux/proc_fs.h>
#include <linux/pci.h>
#include <linux/smp_lock.h>
+#include <net/net_namespace.h>
#include "hysdn_defs.h"
@@ -392,7 +393,7 @@ hysdn_procconf_init(void)
hysdn_card *card;
unsigned char conf_name[20];
- hysdn_proc_entry = proc_mkdir(PROC_SUBDIR_NAME, proc_net);
+ hysdn_proc_entry = proc_mkdir(PROC_SUBDIR_NAME, init_net.proc_net);
if (!hysdn_proc_entry) {
printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n");
return (-1);
@@ -437,5 +438,5 @@ hysdn_procconf_release(void)
card = card->next; /* point to next card */
}
- remove_proc_entry(PROC_SUBDIR_NAME, proc_net);
+ remove_proc_entry(PROC_SUBDIR_NAME, init_net.proc_net);
}
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 4910bca5264..c6df2925ebd 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1365,7 +1365,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
} else {
s = NULL;
}
- ret = down_interruptible(&dev->sem);
+ ret = mutex_lock_interruptible(&dev->mtx);
if( ret ) return ret;
if ((s = isdn_net_new(s, NULL))) {
if (copy_to_user(argp, s, strlen(s) + 1)){
@@ -1375,7 +1375,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
}
} else
ret = -ENODEV;
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
return ret;
case IIOCNETASL:
/* Add a slave to a network-interface */
@@ -1384,7 +1384,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
return -EFAULT;
} else
return -EINVAL;
- ret = down_interruptible(&dev->sem);
+ ret = mutex_lock_interruptible(&dev->mtx);
if( ret ) return ret;
if ((s = isdn_net_newslave(bname))) {
if (copy_to_user(argp, s, strlen(s) + 1)){
@@ -1394,17 +1394,17 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
}
} else
ret = -ENODEV;
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
return ret;
case IIOCNETDIF:
/* Delete a network-interface */
if (arg) {
if (copy_from_user(name, argp, sizeof(name)))
return -EFAULT;
- ret = down_interruptible(&dev->sem);
+ ret = mutex_lock_interruptible(&dev->mtx);
if( ret ) return ret;
ret = isdn_net_rm(name);
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
return ret;
} else
return -EINVAL;
@@ -1433,10 +1433,10 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
if (arg) {
if (copy_from_user(&phone, argp, sizeof(phone)))
return -EFAULT;
- ret = down_interruptible(&dev->sem);
+ ret = mutex_lock_interruptible(&dev->mtx);
if( ret ) return ret;
ret = isdn_net_addphone(&phone);
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
return ret;
} else
return -EINVAL;
@@ -1445,10 +1445,10 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
if (arg) {
if (copy_from_user(&phone, argp, sizeof(phone)))
return -EFAULT;
- ret = down_interruptible(&dev->sem);
+ ret = mutex_lock_interruptible(&dev->mtx);
if( ret ) return ret;
ret = isdn_net_getphones(&phone, argp);
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
return ret;
} else
return -EINVAL;
@@ -1457,10 +1457,10 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
if (arg) {
if (copy_from_user(&phone, argp, sizeof(phone)))
return -EFAULT;
- ret = down_interruptible(&dev->sem);
+ ret = mutex_lock_interruptible(&dev->mtx);
if( ret ) return ret;
ret = isdn_net_delphone(&phone);
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
return ret;
} else
return -EINVAL;
@@ -2304,7 +2304,7 @@ static int __init isdn_init(void)
#ifdef MODULE
dev->owner = THIS_MODULE;
#endif
- init_MUTEX(&dev->sem);
+ mutex_init(&dev->mtx);
init_waitqueue_head(&dev->info_waitq);
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
dev->drvmap[i] = -1;
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index aa83277aba7..b39d1f5b378 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -77,7 +77,7 @@ static __inline__ int isdn_net_device_started(isdn_net_dev *n)
if (lp->master)
dev = lp->master;
else
- dev = &n->dev;
+ dev = n->dev;
return netif_running(dev);
}
@@ -90,7 +90,7 @@ static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp)
if (lp->master)
netif_wake_queue(lp->master);
else
- netif_wake_queue(&lp->netdev->dev);
+ netif_wake_queue(lp->netdev->dev);
}
/*
@@ -102,7 +102,7 @@ static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
if (lp->master)
netif_stop_queue(lp->master);
else
- netif_stop_queue(&lp->netdev->dev);
+ netif_stop_queue(lp->netdev->dev);
}
/*
@@ -287,7 +287,7 @@ isdn_net_unbind_channel(isdn_net_local * lp)
BEWARE! This chunk of code cannot be called from hardware
interrupt handler. I hope it is true. --ANK
*/
- qdisc_reset(lp->netdev->dev.qdisc);
+ qdisc_reset(lp->netdev->dev->qdisc);
}
lp->dialstate = 0;
dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
@@ -328,7 +328,7 @@ isdn_net_autohup(void)
l->cps = (l->transcount * HZ) / (jiffies - last_jiffies);
l->transcount = 0;
if (dev->net_verbose > 3)
- printk(KERN_DEBUG "%s: %d bogocps\n", l->name, l->cps);
+ printk(KERN_DEBUG "%s: %d bogocps\n", p->dev->name, l->cps);
if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
anymore = 1;
l->huptimer++;
@@ -345,27 +345,27 @@ isdn_net_autohup(void)
l->chargetime += l->chargeint;
if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ))
if (l->outgoing || l->hupflags & ISDN_INHUP)
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
} else if (l->outgoing) {
if (l->hupflags & ISDN_CHARGEHUP) {
if (l->hupflags & ISDN_WAITCHARGE) {
printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n",
- l->name, l->hupflags);
- isdn_net_hangup(&p->dev);
+ p->dev->name, l->hupflags);
+ isdn_net_hangup(p->dev);
} else if (time_after(jiffies, l->chargetime + l->chargeint)) {
printk(KERN_DEBUG
"isdn_net: %s: chtime = %lu, chint = %d\n",
- l->name, l->chargetime, l->chargeint);
- isdn_net_hangup(&p->dev);
+ p->dev->name, l->chargetime, l->chargeint);
+ isdn_net_hangup(p->dev);
}
} else
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
} else if (l->hupflags & ISDN_INHUP)
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
}
if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) {
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
break;
}
}
@@ -442,8 +442,8 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
#endif
isdn_net_lp_disconnected(lp);
isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
- printk(KERN_INFO "%s: remote hangup\n", lp->name);
- printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
+ printk(KERN_INFO "%s: remote hangup\n", p->dev->name);
+ printk(KERN_INFO "%s: Chargesum is %d\n", p->dev->name,
lp->charge);
isdn_net_unbind_channel(lp);
return 1;
@@ -487,7 +487,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
isdn_net_add_to_bundle(nd, lp);
}
}
- printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
+ printk(KERN_INFO "isdn_net: %s connected\n", p->dev->name);
/* If first Chargeinfo comes before B-Channel connect,
* we correct the timestamp here.
*/
@@ -534,7 +534,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c)
lp->hupflags |= ISDN_HAVECHARGE;
lp->chargetime = jiffies;
printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n",
- lp->name, lp->chargetime);
+ p->dev->name, lp->chargetime);
return 1;
}
}
@@ -565,7 +565,7 @@ isdn_net_dial(void)
#ifdef ISDN_DEBUG_NET_DIAL
if (lp->dialstate)
- printk(KERN_DEBUG "%s: dialstate=%d\n", lp->name, lp->dialstate);
+ printk(KERN_DEBUG "%s: dialstate=%d\n", p->dev->name, lp->dialstate);
#endif
switch (lp->dialstate) {
case 0:
@@ -578,8 +578,8 @@ isdn_net_dial(void)
lp->dial = lp->phone[1];
if (!lp->dial) {
printk(KERN_WARNING "%s: phone number deleted?\n",
- lp->name);
- isdn_net_hangup(&p->dev);
+ p->dev->name);
+ isdn_net_hangup(p->dev);
break;
}
anymore = 1;
@@ -616,8 +616,8 @@ isdn_net_dial(void)
s = "dial suppressed: isdn system stopped";
else
s = "dial suppressed: dialmode `off'";
- isdn_net_unreachable(&p->dev, NULL, s);
- isdn_net_hangup(&p->dev);
+ isdn_net_unreachable(p->dev, NULL, s);
+ isdn_net_hangup(p->dev);
break;
}
cmd.driver = lp->isdn_device;
@@ -632,20 +632,20 @@ isdn_net_dial(void)
cmd.arg = lp->isdn_channel;
if (!lp->dial) {
printk(KERN_WARNING "%s: phone number deleted?\n",
- lp->name);
- isdn_net_hangup(&p->dev);
+ p->dev->name);
+ isdn_net_hangup(p->dev);
break;
}
if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) {
lp->dialstate = 4;
- printk(KERN_INFO "%s: Open leased line ...\n", lp->name);
+ printk(KERN_INFO "%s: Open leased line ...\n", p->dev->name);
} else {
if(lp->dialtimeout > 0)
if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
- isdn_net_unreachable(&p->dev, NULL, "dial: timed out");
- isdn_net_hangup(&p->dev);
+ isdn_net_unreachable(p->dev, NULL, "dial: timed out");
+ isdn_net_hangup(p->dev);
break;
}
@@ -674,9 +674,9 @@ isdn_net_dial(void)
if (lp->dialtimeout == 0) {
lp->dialwait_timer = jiffies + lp->dialwait;
lp->dialstarted = 0;
- isdn_net_unreachable(&p->dev, NULL, "dial: tried all numbers dialmax times");
+ isdn_net_unreachable(p->dev, NULL, "dial: tried all numbers dialmax times");
}
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
break;
}
}
@@ -688,7 +688,7 @@ isdn_net_dial(void)
dev->usage[i] |= ISDN_USAGE_OUTGOING;
isdn_info_update();
}
- printk(KERN_INFO "%s: dialing %d %s... %s\n", lp->name,
+ printk(KERN_INFO "%s: dialing %d %s... %s\n", p->dev->name,
lp->dialretry, cmd.parm.setup.phone,
(cmd.parm.setup.si1 == 1) ? "DOV" : "");
lp->dtimer = 0;
@@ -758,7 +758,7 @@ isdn_net_dial(void)
cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
isdn_command(&cmd);
if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15)
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
else {
anymore = 1;
lp->dialstate++;
@@ -781,7 +781,7 @@ isdn_net_dial(void)
printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
#endif
if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
else
anymore = 1;
break;
@@ -797,7 +797,7 @@ isdn_net_dial(void)
*/
if (lp->dtimer++ > lp->cbdelay)
{
- printk(KERN_INFO "%s: hangup waiting for callback ...\n", lp->name);
+ printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->dev->name);
lp->dtimer = 0;
lp->dialstate = 4;
cmd.driver = lp->isdn_device;
@@ -810,7 +810,7 @@ isdn_net_dial(void)
break;
default:
printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n",
- lp->dialstate, lp->name);
+ lp->dialstate, p->dev->name);
}
p = (isdn_net_dev *) p->next;
}
@@ -836,11 +836,11 @@ isdn_net_hangup(struct net_device *d)
if (slp->flags & ISDN_NET_CONNECTED) {
printk(KERN_INFO
"isdn_net: hang up slave %s before %s\n",
- slp->name, lp->name);
+ lp->slave->name, d->name);
isdn_net_hangup(lp->slave);
}
}
- printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
+ printk(KERN_INFO "isdn_net: local hangup %s\n", d->name);
#ifdef CONFIG_ISDN_PPP
if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
isdn_ppp_free(lp);
@@ -858,7 +858,7 @@ isdn_net_hangup(struct net_device *d)
cmd.command = ISDN_CMD_HANGUP;
cmd.arg = lp->isdn_channel;
isdn_command(&cmd);
- printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge);
+ printk(KERN_INFO "%s: Chargesum is %d\n", d->name, lp->charge);
isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
}
isdn_net_unbind_channel(lp);
@@ -885,7 +885,7 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
/* fall back to old isdn_net_log_packet method() */
char * buf = skb->data;
- printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->name);
+ printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->netdev->dev->name);
p = buf;
proto = ETH_P_IP;
switch (lp->p_encap) {
@@ -1023,7 +1023,7 @@ void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
if (ret != len) {
/* we should never get here */
- printk(KERN_WARNING "%s: HL driver queue full\n", lp->name);
+ printk(KERN_WARNING "%s: HL driver queue full\n", lp->netdev->dev->name);
goto error;
}
@@ -1461,7 +1461,7 @@ isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
mod_timer(&lp->cisco_timer, expires);
printk(KERN_INFO "%s: Keepalive period set "
"to %d seconds.\n",
- lp->name, lp->cisco_keepalive_period);
+ dev->name, lp->cisco_keepalive_period);
}
break;
@@ -1512,7 +1512,7 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
lp->cisco_line_state = 0;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
- " changed state to down\n", lp->name);
+ " changed state to down\n", lp->netdev->dev->name);
/* should stop routing higher-level data accross */
} else if ((!lp->cisco_line_state) &&
(myseq_diff >= 0) && (myseq_diff <= 2)) {
@@ -1520,14 +1520,14 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
lp->cisco_line_state = 1;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
- " changed state to up\n", lp->name);
+ " changed state to up\n", lp->netdev->dev->name);
/* restart routing higher-level data accross */
}
if (lp->cisco_debserint)
printk (KERN_DEBUG "%s: HDLC "
"myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
- lp->name, last_cisco_myseq, lp->cisco_mineseen,
+ lp->netdev->dev->name, last_cisco_myseq, lp->cisco_mineseen,
((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040),
lp->cisco_yourseq,
((lp->cisco_line_state) ? "line up" : "line down"));
@@ -1618,7 +1618,7 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
__be32 addr = 0; /* local ipv4 address */
__be32 mask = 0; /* local netmask */
- if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
+ if ((in_dev = lp->netdev->dev->ip_ptr) != NULL) {
/* take primary(first) address of interface */
struct in_ifaddr *ifa = in_dev->ifa_list;
if (ifa != NULL) {
@@ -1682,7 +1682,7 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
"remote ip: %d.%d.%d.%d, "
"local ip: %d.%d.%d.%d "
"mask: %d.%d.%d.%d\n",
- lp->name,
+ lp->netdev->dev->name,
HIPQUAD(addr),
HIPQUAD(local),
HIPQUAD(mask));
@@ -1690,7 +1690,7 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
slarp_reply_out:
printk(KERN_INFO "%s: got invalid slarp "
"reply (%d.%d.%d.%d/%d.%d.%d.%d) "
- "- ignored\n", lp->name,
+ "- ignored\n", lp->netdev->dev->name,
HIPQUAD(addr), HIPQUAD(mask));
break;
case CISCO_SLARP_KEEPALIVE:
@@ -1701,7 +1701,8 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
lp->cisco_last_slarp_in) {
printk(KERN_DEBUG "%s: Keepalive period mismatch - "
"is %d but should be %d.\n",
- lp->name, period, lp->cisco_keepalive_period);
+ lp->netdev->dev->name, period,
+ lp->cisco_keepalive_period);
}
lp->cisco_last_slarp_in = jiffies;
p += get_u32(p, &my_seq);
@@ -1732,12 +1733,12 @@ isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) {
printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n",
- lp->name, addr);
+ lp->netdev->dev->name, addr);
goto out_free;
}
if (ctrl != CISCO_CTRL) {
printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n",
- lp->name, ctrl);
+ lp->netdev->dev->name, ctrl);
goto out_free;
}
@@ -1748,7 +1749,8 @@ isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb)
case CISCO_TYPE_CDP:
if (lp->cisco_debserint)
printk(KERN_DEBUG "%s: Received CDP packet. use "
- "\"no cdp enable\" on cisco.\n", lp->name);
+ "\"no cdp enable\" on cisco.\n",
+ lp->netdev->dev->name);
goto out_free;
default:
/* no special cisco protocol */
@@ -1843,7 +1845,7 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb)
};
#endif /* CONFIG_ISDN_X25 */
printk(KERN_WARNING "%s: unknown encapsulation, dropping\n",
- lp->name);
+ lp->netdev->dev->name);
kfree_skb(skb);
return;
}
@@ -1866,61 +1868,21 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb)
isdn_net_local *lp = p->local;
if ((lp->flags & ISDN_NET_CONNECTED) &&
(!lp->dialstate)) {
- isdn_net_receive(&p->dev, skb);
+ isdn_net_receive(p->dev, skb);
return 1;
}
}
return 0;
}
-static int
-my_eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len)
-{
- struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
-
- /*
- * Set the protocol type. For a packet of type ETH_P_802_3 we
- * put the length here instead. It is up to the 802.2 layer to
- * carry protocol information.
- */
-
- if (type != ETH_P_802_3)
- eth->h_proto = htons(type);
- else
- eth->h_proto = htons(len);
-
- /*
- * Set the source hardware address.
- */
- if (saddr)
- memcpy(eth->h_source, saddr, dev->addr_len);
- else
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-
- /*
- * Anyway, the loopback-device should never use this function...
- */
-
- if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
- memset(eth->h_dest, 0, dev->addr_len);
- return ETH_HLEN /*(dev->hard_header_len)*/;
- }
- if (daddr) {
- memcpy(eth->h_dest, daddr, dev->addr_len);
- return ETH_HLEN /*dev->hard_header_len*/;
- }
- return -ETH_HLEN /*dev->hard_header_len*/;
-}
-
/*
* build an header
* depends on encaps that is being used.
*/
-static int
-isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned plen)
+static int isdn_net_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type,
+ const void *daddr, const void *saddr, unsigned plen)
{
isdn_net_local *lp = dev->priv;
unsigned char *p;
@@ -1928,7 +1890,7 @@ isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type
switch (lp->p_encap) {
case ISDN_NET_ENCAP_ETHER:
- len = my_eth_header(skb, dev, type, daddr, saddr, plen);
+ len = eth_header(skb, dev, type, daddr, saddr, plen);
break;
#ifdef CONFIG_ISDN_PPP
case ISDN_NET_ENCAP_SYNCPPP:
@@ -2005,6 +1967,32 @@ isdn_net_rebuild_header(struct sk_buff *skb)
return ret;
}
+static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
+{
+ const struct net_device *dev = neigh->dev;
+ isdn_net_local *lp = dev->priv;
+
+ if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
+ return eth_header_cache(neigh, hh);
+ return -1;
+}
+
+static void isdn_header_cache_update(struct hh_cache *hh,
+ const struct net_device *dev,
+ const unsigned char *haddr)
+{
+ isdn_net_local *lp = dev->priv;
+ if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
+ return eth_header_cache_update(hh, dev, haddr);
+}
+
+static const struct header_ops isdn_header_ops = {
+ .create = isdn_net_header,
+ .rebuild = isdn_net_rebuild_header,
+ .cache = isdn_header_cache,
+ .cache_update = isdn_header_cache_update,
+};
+
/*
* Interface-setup. (just after registering a new interface)
*/
@@ -2012,18 +2000,12 @@ static int
isdn_net_init(struct net_device *ndev)
{
ushort max_hlhdr_len = 0;
- isdn_net_local *lp = (isdn_net_local *) ndev->priv;
- int drvidx, i;
+ int drvidx;
ether_setup(ndev);
- lp->org_hhc = ndev->hard_header_cache;
- lp->org_hcu = ndev->header_cache_update;
+ ndev->header_ops = NULL;
/* Setup the generic properties */
-
- ndev->hard_header = NULL;
- ndev->hard_header_cache = NULL;
- ndev->header_cache_update = NULL;
ndev->mtu = 1500;
ndev->flags = IFF_NOARP|IFF_POINTOPOINT;
ndev->type = ARPHRD_ETHER;
@@ -2032,9 +2014,6 @@ isdn_net_init(struct net_device *ndev)
/* for clients with MPPP maybe higher values better */
ndev->tx_queue_len = 30;
- for (i = 0; i < ETH_ALEN; i++)
- ndev->broadcast[i] = 0xff;
-
/* The ISDN-specific entries in the device structure. */
ndev->open = &isdn_net_open;
ndev->hard_start_xmit = &isdn_net_start_xmit;
@@ -2052,7 +2031,6 @@ isdn_net_init(struct net_device *ndev)
ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
ndev->stop = &isdn_net_close;
ndev->get_stats = &isdn_net_get_stats;
- ndev->rebuild_header = &isdn_net_rebuild_header;
ndev->do_ioctl = NULL;
return 0;
}
@@ -2198,7 +2176,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
wret = matchret;
#ifdef ISDN_DEBUG_NET_ICALL
printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
- lp->name, lp->msn, lp->flags, lp->dialstate);
+ p->dev->name, lp->msn, lp->flags, lp->dialstate);
#endif
if ((!matchret) && /* EAZ is matching */
(((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */
@@ -2301,7 +2279,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
* */
if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n",
- lp->name);
+ p->dev->name);
return 3;
}
/*
@@ -2310,7 +2288,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
*/
if (!isdn_net_device_started(p)) {
printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
- lp->name);
+ p->dev->name);
return 3;
}
/* Interface is up, now see if it's a slave. If so, see if
@@ -2318,8 +2296,8 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
*/
if (lp->master) {
isdn_net_local *mlp = (isdn_net_local *) lp->master->priv;
- printk(KERN_DEBUG "ICALLslv: %s\n", lp->name);
- printk(KERN_DEBUG "master=%s\n", mlp->name);
+ printk(KERN_DEBUG "ICALLslv: %s\n", p->dev->name);
+ printk(KERN_DEBUG "master=%s\n", lp->master->name);
if (mlp->flags & ISDN_NET_CONNECTED) {
printk(KERN_DEBUG "master online\n");
/* Master is online, find parent-slave (master if first slave) */
@@ -2346,11 +2324,11 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
* */
if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) {
printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n",
- lp->name);
+ p->dev->name);
return 3;
}
printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n",
- lp->name, nr, eaz);
+ p->dev->name, nr, eaz);
if (lp->phone[1]) {
/* Grab a free ISDN-Channel */
spin_lock_irqsave(&dev->lock, flags);
@@ -2364,7 +2342,8 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
lp->msn)
) < 0) {
- printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", lp->name);
+ printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n",
+ p->dev->name);
spin_unlock_irqrestore(&dev->lock, flags);
return 0;
}
@@ -2385,11 +2364,12 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
/* Initiate dialing by returning 2 or 4 */
return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4;
} else
- printk(KERN_WARNING "isdn_net: %s: No phone number\n", lp->name);
+ printk(KERN_WARNING "isdn_net: %s: No phone number\n",
+ p->dev->name);
return 0;
} else {
- printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr,
- eaz);
+ printk(KERN_DEBUG "%s: call from %s -> %s accepted\n",
+ p->dev->name, nr, eaz);
/* if this interface is dialing, it does it probably on a different
device, so free this device */
if ((lp->dialstate == 4) || (lp->dialstate == 12)) {
@@ -2448,7 +2428,7 @@ isdn_net_findif(char *name)
isdn_net_dev *p = dev->netdev;
while (p) {
- if (!strcmp(p->local->name, name))
+ if (!strcmp(p->dev->name, name))
return p;
p = (isdn_net_dev *) p->next;
}
@@ -2477,7 +2457,8 @@ isdn_net_force_dial_lp(isdn_net_local * lp)
lp->pre_device,
lp->pre_channel,
lp->msn)) < 0) {
- printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
+ printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n",
+ lp->netdev->dev->name);
spin_unlock_irqrestore(&dev->lock, flags);
return -EAGAIN;
}
@@ -2531,6 +2512,42 @@ isdn_net_force_dial(char *name)
}
/*
+ * Helper for alloc_netdev()
+ */
+static void _isdn_setup(struct net_device *dev)
+{
+ isdn_net_local *lp = dev->priv;
+
+ dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+ lp->p_encap = ISDN_NET_ENCAP_RAWIP;
+ lp->magic = ISDN_NET_MAGIC;
+ lp->last = lp;
+ lp->next = lp;
+ lp->isdn_device = -1;
+ lp->isdn_channel = -1;
+ lp->pre_device = -1;
+ lp->pre_channel = -1;
+ lp->exclusive = -1;
+ lp->ppp_slot = -1;
+ lp->pppbind = -1;
+ skb_queue_head_init(&lp->super_tx_queue);
+ lp->l2_proto = ISDN_PROTO_L2_X75I;
+ lp->l3_proto = ISDN_PROTO_L3_TRANS;
+ lp->triggercps = 6000;
+ lp->slavedelay = 10 * HZ;
+ lp->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
+ lp->onhtime = 10; /* Default hangup-time for saving costs */
+ lp->dialmax = 1;
+ /* Hangup before Callback, manual dial */
+ lp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL;
+ lp->cbdelay = 25; /* Wait 5 secs before Callback */
+ lp->dialtimeout = -1; /* Infinite Dial-Timeout */
+ lp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
+ lp->dialstarted = 0; /* Jiffies of last dial-start */
+ lp->dialwait_timer = 0; /* Jiffies of earliest next dial-start */
+}
+
+/*
* Allocate a new network-interface and initialize its data structures.
*/
char *
@@ -2543,23 +2560,20 @@ isdn_net_new(char *name, struct net_device *master)
printk(KERN_WARNING "isdn_net: interface %s already exists\n", name);
return NULL;
}
+ if (name == NULL)
+ return NULL;
if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
return NULL;
}
- if (!(netdev->local = kzalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
- printk(KERN_WARNING "isdn_net: Could not allocate device locals\n");
+ netdev->dev = alloc_netdev(sizeof(isdn_net_local), name, _isdn_setup);
+ if (!netdev->dev) {
+ printk(KERN_WARNING "isdn_net: Could not allocate network device\n");
kfree(netdev);
return NULL;
}
- if (name == NULL)
- strcpy(netdev->local->name, " ");
- else
- strcpy(netdev->local->name, name);
- strcpy(netdev->dev.name, netdev->local->name);
- netdev->dev.priv = netdev->local;
- netdev->dev.init = isdn_net_init;
- netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP;
+ netdev->local = netdev->dev->priv;
+ netdev->dev->init = isdn_net_init;
if (master) {
/* Device shall be a slave */
struct net_device *p = (((isdn_net_local *) master->priv)->slave);
@@ -2571,60 +2585,33 @@ isdn_net_new(char *name, struct net_device *master)
q = p;
p = (((isdn_net_local *) p->priv)->slave);
}
- ((isdn_net_local *) q->priv)->slave = &(netdev->dev);
+ ((isdn_net_local *) q->priv)->slave = netdev->dev;
} else {
/* Device shall be a master */
/*
* Watchdog timer (currently) for master only.
*/
- netdev->dev.tx_timeout = isdn_net_tx_timeout;
- netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
- if (register_netdev(&netdev->dev) != 0) {
+ netdev->dev->tx_timeout = isdn_net_tx_timeout;
+ netdev->dev->watchdog_timeo = ISDN_NET_TX_TIMEOUT;
+ if (register_netdev(netdev->dev) != 0) {
printk(KERN_WARNING "isdn_net: Could not register net-device\n");
- kfree(netdev->local);
+ free_netdev(netdev->dev);
kfree(netdev);
return NULL;
}
}
- netdev->local->magic = ISDN_NET_MAGIC;
-
netdev->queue = netdev->local;
spin_lock_init(&netdev->queue_lock);
- netdev->local->last = netdev->local;
netdev->local->netdev = netdev;
- netdev->local->next = netdev->local;
INIT_WORK(&netdev->local->tqueue, isdn_net_softint);
spin_lock_init(&netdev->local->xmit_lock);
- netdev->local->isdn_device = -1;
- netdev->local->isdn_channel = -1;
- netdev->local->pre_device = -1;
- netdev->local->pre_channel = -1;
- netdev->local->exclusive = -1;
- netdev->local->ppp_slot = -1;
- netdev->local->pppbind = -1;
- skb_queue_head_init(&netdev->local->super_tx_queue);
- netdev->local->l2_proto = ISDN_PROTO_L2_X75I;
- netdev->local->l3_proto = ISDN_PROTO_L3_TRANS;
- netdev->local->triggercps = 6000;
- netdev->local->slavedelay = 10 * HZ;
- netdev->local->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
- netdev->local->onhtime = 10; /* Default hangup-time for saving costs
- of those who forget configuring this */
- netdev->local->dialmax = 1;
- netdev->local->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */
- netdev->local->cbdelay = 25; /* Wait 5 secs before Callback */
- netdev->local->dialtimeout = -1; /* Infinite Dial-Timeout */
- netdev->local->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
- netdev->local->dialstarted = 0; /* Jiffies of last dial-start */
- netdev->local->dialwait_timer = 0; /* Jiffies of earliest next dial-start */
-
/* Put into to netdev-chain */
netdev->next = (void *) dev->netdev;
dev->netdev = netdev;
- return netdev->dev.name;
+ return netdev->dev->name;
}
char *
@@ -2649,7 +2636,7 @@ isdn_net_newslave(char *parm)
/* Master must not be started yet */
if (isdn_net_device_started(n))
return NULL;
- return (isdn_net_new(newname, &(n->dev)));
+ return (isdn_net_new(newname, n->dev));
}
return NULL;
}
@@ -2690,7 +2677,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
#endif
if (isdn_net_device_started(p)) {
printk(KERN_WARNING "%s: cannot change encap when if is up\n",
- lp->name);
+ p->dev->name);
return -EBUSY;
}
#ifdef CONFIG_ISDN_X25
@@ -2715,26 +2702,26 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
case ISDN_NET_ENCAP_SYNCPPP:
#ifndef CONFIG_ISDN_PPP
printk(KERN_WARNING "%s: SyncPPP support not configured\n",
- lp->name);
+ p->dev->name);
return -EINVAL;
#else
- p->dev.type = ARPHRD_PPP; /* change ARP type */
- p->dev.addr_len = 0;
- p->dev.do_ioctl = isdn_ppp_dev_ioctl;
+ p->dev->type = ARPHRD_PPP; /* change ARP type */
+ p->dev->addr_len = 0;
+ p->dev->do_ioctl = isdn_ppp_dev_ioctl;
#endif
break;
case ISDN_NET_ENCAP_X25IFACE:
#ifndef CONFIG_ISDN_X25
printk(KERN_WARNING "%s: isdn-x25 support not configured\n",
- p->local->name);
+ p->dev->name);
return -EINVAL;
#else
- p->dev.type = ARPHRD_X25; /* change ARP type */
- p->dev.addr_len = 0;
+ p->dev->type = ARPHRD_X25; /* change ARP type */
+ p->dev->addr_len = 0;
#endif
break;
case ISDN_NET_ENCAP_CISCOHDLCK:
- p->dev.do_ioctl = isdn_ciscohdlck_dev_ioctl;
+ p->dev->do_ioctl = isdn_ciscohdlck_dev_ioctl;
break;
default:
if( cfg->p_encap >= 0 &&
@@ -2742,7 +2729,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
break;
printk(KERN_WARNING
"%s: encapsulation protocol %d not supported\n",
- p->local->name, cfg->p_encap);
+ p->dev->name, cfg->p_encap);
return -EINVAL;
}
if (strlen(cfg->drvid)) {
@@ -2861,21 +2848,14 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
}
if (cfg->p_encap != lp->p_encap) {
if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
- p->dev.hard_header = NULL;
- p->dev.hard_header_cache = NULL;
- p->dev.header_cache_update = NULL;
- p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
+ p->dev->header_ops = NULL;
+ p->dev->flags = IFF_NOARP|IFF_POINTOPOINT;
} else {
- p->dev.hard_header = isdn_net_header;
- if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
- p->dev.hard_header_cache = lp->org_hhc;
- p->dev.header_cache_update = lp->org_hcu;
- p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
- } else {
- p->dev.hard_header_cache = NULL;
- p->dev.header_cache_update = NULL;
- p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
- }
+ p->dev->header_ops = &isdn_header_ops;
+ if (cfg->p_encap == ISDN_NET_ENCAP_ETHER)
+ p->dev->flags = IFF_BROADCAST | IFF_MULTICAST;
+ else
+ p->dev->flags = IFF_NOARP|IFF_POINTOPOINT;
}
}
lp->p_encap = cfg->p_encap;
@@ -2926,13 +2906,18 @@ isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
cfg->pppbind = lp->pppbind;
cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1;
cfg->dialwait = lp->dialwait / HZ;
- if (lp->slave)
- strcpy(cfg->slave, ((isdn_net_local *) lp->slave->priv)->name);
- else
+ if (lp->slave) {
+ if (strlen(lp->slave->name) > 8)
+ strcpy(cfg->slave, "too-long");
+ else
+ strcpy(cfg->slave, lp->slave->name);
+ } else
cfg->slave[0] = '\0';
- if (lp->master)
- strcpy(cfg->master, ((isdn_net_local *) lp->master->priv)->name);
- else
+ if (lp->master) {
+ if (strlen(lp->master->name) > 8)
+ strcpy(cfg->master, "too-long");
+ strcpy(cfg->master, lp->master->name);
+ } else
cfg->master[0] = '\0';
return 0;
}
@@ -3002,7 +2987,8 @@ isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone __user *peer)
isdn_net_dev *p = isdn_net_findif(phone->name);
int ch, dv, idx;
- if (!p) return -ENODEV;
+ if (!p)
+ return -ENODEV;
/*
* Theoretical race: while this executes, the remote number might
* become invalid (hang up) or change (new connection), resulting
@@ -3011,14 +2997,18 @@ isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone __user *peer)
*/
ch = p->local->isdn_channel;
dv = p->local->isdn_device;
- if(ch<0 && dv<0) return -ENOTCONN;
+ if(ch < 0 && dv < 0)
+ return -ENOTCONN;
idx = isdn_dc2minor(dv, ch);
- if (idx<0) return -ENODEV;
+ if (idx <0 )
+ return -ENODEV;
/* for pre-bound channels, we need this extra check */
- if ( strncmp(dev->num[idx],"???",3) == 0 ) return -ENOTCONN;
- strncpy(phone->phone,dev->num[idx],ISDN_MSNLEN);
- phone->outgoing=USG_OUTGOING(dev->usage[idx]);
- if ( copy_to_user(peer,phone,sizeof(*peer)) ) return -EFAULT;
+ if (strncmp(dev->num[idx], "???", 3) == 0)
+ return -ENOTCONN;
+ strncpy(phone->phone, dev->num[idx], ISDN_MSNLEN);
+ phone->outgoing = USG_OUTGOING(dev->usage[idx]);
+ if (copy_to_user(peer, phone, sizeof(*peer)))
+ return -EFAULT;
return 0;
}
/*
@@ -3095,7 +3085,7 @@ isdn_net_force_hangup(char *name)
isdn_net_hangup(q);
q = (((isdn_net_local *) q->priv)->slave);
}
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
return 0;
}
return -ENODEV;
@@ -3123,13 +3113,11 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel);
if (p->local->master) {
/* It's a slave-device, so update master's slave-pointer if necessary */
- if (((isdn_net_local *) (p->local->master->priv))->slave == &p->dev)
+ if (((isdn_net_local *) (p->local->master->priv))->slave == p->dev)
((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave;
} else {
/* Unregister only if it's a master-device */
- p->dev.hard_header_cache = p->local->org_hhc;
- p->dev.header_cache_update = p->local->org_hcu;
- unregister_netdev(&p->dev);
+ unregister_netdev(p->dev);
}
/* Unlink device from chain */
spin_lock_irqsave(&dev->lock, flags);
@@ -3139,25 +3127,25 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q)
dev->netdev = p->next;
if (p->local->slave) {
/* If this interface has a slave, remove it also */
- char *slavename = ((isdn_net_local *) (p->local->slave->priv))->name;
+ char *slavename = p->local->slave->name;
isdn_net_dev *n = dev->netdev;
q = NULL;
while (n) {
- if (!strcmp(n->local->name, slavename)) {
+ if (!strcmp(n->dev->name, slavename)) {
spin_unlock_irqrestore(&dev->lock, flags);
isdn_net_realrm(n, q);
spin_lock_irqsave(&dev->lock, flags);
break;
}
q = n;
- n = (isdn_net_dev *) n->next;
+ n = (isdn_net_dev *)n->next;
}
}
spin_unlock_irqrestore(&dev->lock, flags);
/* If no more net-devices remain, disable auto-hangup timer */
if (dev->netdev == NULL)
isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
- kfree(p->local);
+ free_netdev(p->dev);
kfree(p);
return 0;
@@ -3178,7 +3166,7 @@ isdn_net_rm(char *name)
p = dev->netdev;
q = NULL;
while (p) {
- if (!strcmp(p->local->name, name)) {
+ if (!strcmp(p->dev->name, name)) {
spin_unlock_irqrestore(&dev->lock, flags);
return (isdn_net_realrm(p, q));
}
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 387392cb3d6..9f5fe372f83 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -190,9 +190,11 @@ isdn_ppp_bind(isdn_net_local * lp)
retval = -1;
goto out;
}
- unit = isdn_ppp_if_get_unit(lp->name); /* get unit number from interface name .. ugly! */
+ /* get unit number from interface name .. ugly! */
+ unit = isdn_ppp_if_get_unit(lp->netdev->dev->name);
if (unit < 0) {
- printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", lp->name);
+ printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n",
+ lp->netdev->dev->name);
retval = -1;
goto out;
}
@@ -360,7 +362,7 @@ isdn_ppp_release(int min, struct file *file)
* isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
* removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
*/
- isdn_net_hangup(&p->dev);
+ isdn_net_hangup(p->dev);
}
for (i = 0; i < NUM_RCV_BUFFS; i++) {
kfree(is->rq[i].buf);
@@ -507,7 +509,8 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
case PPPIOCGIFNAME:
if(!lp)
return -EINVAL;
- if ((r = set_arg(argp, lp->name, strlen(lp->name))))
+ if ((r = set_arg(argp, lp->netdev->dev->name,
+ strlen(lp->netdev->dev->name))))
return r;
break;
case PPPIOCGMPFLAGS: /* get configuration flags */
@@ -531,7 +534,7 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
if (lp) {
/* OK .. we are ready to send buffers */
is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
- netif_wake_queue(&lp->netdev->dev);
+ netif_wake_queue(lp->netdev->dev);
break;
}
}
@@ -1023,7 +1026,7 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
static void
isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
{
- struct net_device *dev = &net_dev->dev;
+ struct net_device *dev = net_dev->dev;
struct ippp_struct *is, *mis;
isdn_net_local *mlp = NULL;
int slot;
diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c
index 7b55e151f1b..ac5a91ccde8 100644
--- a/drivers/isdn/pcbit/capi.c
+++ b/drivers/isdn/pcbit/capi.c
@@ -15,9 +15,9 @@
/*
* Documentation:
- * - "Common ISDN API - Perfil Português - Versão 2.1",
+ * - "Common ISDN API - Perfil Português - Versão 2.1",
* Telecom Portugal, Fev 1992.
- * - "Common ISDN API - Especificação de protocolos para
+ * - "Common ISDN API - Especificação de protocolos para
* acesso aos canais B", Inesc, Jan 1994.
*/
diff --git a/drivers/isdn/sc/card.h b/drivers/isdn/sc/card.h
index 5992f63c383..0120bcf8831 100644
--- a/drivers/isdn/sc/card.h
+++ b/drivers/isdn/sc/card.h
@@ -109,7 +109,7 @@ void memcpy_fromshmem(int card, void *dest, const void *src, size_t n);
int get_card_from_id(int driver);
int indicate_status(int card, int event, ulong Channel, char *Data);
irqreturn_t interrupt_handler(int interrupt, void *cardptr);
-int sndpkt(int devId, int channel, struct sk_buff *data);
+int sndpkt(int devId, int channel, int ack, struct sk_buff *data);
void rcvpkt(int card, RspMessage *rcvmsg);
int command(isdn_ctrl *cmd);
int reset(int card);
diff --git a/drivers/isdn/sc/debug.h b/drivers/isdn/sc/debug.h
deleted file mode 100644
index e9db96ede4b..00000000000
--- a/drivers/isdn/sc/debug.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* $Id: debug.h,v 1.2.8.1 2001/09/23 22:24:59 kai Exp $
- *
- * Copyright (C) 1996 SpellCaster Telecommunications Inc.
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For more information, please contact gpl-info@spellcast.com or write:
- *
- * SpellCaster Telecommunications Inc.
- * 5621 Finch Avenue East, Unit #3
- * Scarborough, Ontario Canada
- * M1B 2T9
- * +1 (416) 297-8565
- * +1 (416) 297-6433 Facsimile
- */
-
-#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
-#define FREE_IRQ(a,b) free_irq(a,b)
diff --git a/drivers/isdn/sc/includes.h b/drivers/isdn/sc/includes.h
index 5286e0c810a..4766e5b7737 100644
--- a/drivers/isdn/sc/includes.h
+++ b/drivers/isdn/sc/includes.h
@@ -14,4 +14,3 @@
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/isdnif.h>
-#include "debug.h"
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
index 0bf76344a0d..dd0acd06750 100644
--- a/drivers/isdn/sc/init.c
+++ b/drivers/isdn/sc/init.c
@@ -334,7 +334,8 @@ static int __init sc_init(void)
*/
sc_adapter[cinst]->interrupt = irq[b];
if (request_irq(sc_adapter[cinst]->interrupt, interrupt_handler,
- IRQF_DISABLED, interface->id, NULL))
+ IRQF_DISABLED, interface->id,
+ (void *)(unsigned long) cinst))
{
kfree(sc_adapter[cinst]->channel);
indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL); /* Fix me */
@@ -404,7 +405,7 @@ static void __exit sc_exit(void)
/*
* Release the IRQ
*/
- FREE_IRQ(sc_adapter[i]->interrupt, NULL);
+ free_irq(sc_adapter[i]->interrupt, NULL);
/*
* Reset for a clean start
diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c
index bef7963cdd0..485be8b1e1b 100644
--- a/drivers/isdn/sc/interrupt.c
+++ b/drivers/isdn/sc/interrupt.c
@@ -21,28 +21,15 @@
#include "card.h"
#include <linux/interrupt.h>
-static int get_card_from_irq(int irq)
-{
- int i;
-
- for(i = 0 ; i < cinst ; i++) {
- if(sc_adapter[i]->interrupt == irq)
- return i;
- }
- return -1;
-}
-
/*
*
*/
-irqreturn_t interrupt_handler(int interrupt, void *cardptr)
+irqreturn_t interrupt_handler(int dummy, void *card_inst)
{
RspMessage rcvmsg;
int channel;
- int card;
-
- card = get_card_from_irq(interrupt);
+ int card = (int)(unsigned long) card_inst;
if(!IS_VALID_CARD(card)) {
pr_debug("Invalid param: %d is not a valid card id\n", card);
diff --git a/drivers/isdn/sc/packet.c b/drivers/isdn/sc/packet.c
index 92016a2608e..5ff6ae86844 100644
--- a/drivers/isdn/sc/packet.c
+++ b/drivers/isdn/sc/packet.c
@@ -20,7 +20,7 @@
#include "message.h"
#include "card.h"
-int sndpkt(int devId, int channel, struct sk_buff *data)
+int sndpkt(int devId, int channel, int ack, struct sk_buff *data)
{
LLData ReqLnkWrite;
int status;
diff --git a/drivers/isdn/sc/shmem.c b/drivers/isdn/sc/shmem.c
index 034d41a61ae..712220cef13 100644
--- a/drivers/isdn/sc/shmem.c
+++ b/drivers/isdn/sc/shmem.c
@@ -28,15 +28,15 @@ void memcpy_toshmem(int card, void *dest, const void *src, size_t n)
{
unsigned long flags;
unsigned char ch;
+ unsigned long dest_rem = ((unsigned long) dest) % 0x4000;
- if(!IS_VALID_CARD(card)) {
+ if (!IS_VALID_CARD(card)) {
pr_debug("Invalid param: %d is not a valid card id\n", card);
return;
}
- if(n > SRAM_PAGESIZE) {
+ if (n > SRAM_PAGESIZE)
return;
- }
/*
* determine the page to load from the address
@@ -50,8 +50,7 @@ void memcpy_toshmem(int card, void *dest, const void *src, size_t n)
outb(((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE) >> 14) | 0x80,
sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport]);
- memcpy_toio(sc_adapter[card]->rambase +
- ((unsigned long) dest % 0x4000), src, n);
+ memcpy_toio((void __iomem *)(sc_adapter[card]->rambase + dest_rem), src, n);
spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig
index 0a419a0de60..656920636cb 100644
--- a/drivers/kvm/Kconfig
+++ b/drivers/kvm/Kconfig
@@ -17,6 +17,7 @@ if VIRTUALIZATION
config KVM
tristate "Kernel-based Virtual Machine (KVM) support"
depends on X86 && EXPERIMENTAL
+ select PREEMPT_NOTIFIERS
select ANON_INODES
---help---
Support hosting fully virtualized guest machines using hardware
@@ -46,4 +47,8 @@ config KVM_AMD
Provides support for KVM on AMD processors equipped with the AMD-V
(SVM) extensions.
+# OK, it's a little counter-intuitive to do this, but it puts it neatly under
+# the virtualization menu.
+source drivers/lguest/Kconfig
+
endif # VIRTUALIZATION
diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile
index c0a789fa9d6..e5a8f4d3e97 100644
--- a/drivers/kvm/Makefile
+++ b/drivers/kvm/Makefile
@@ -2,7 +2,7 @@
# Makefile for Kernel-based Virtual Machine module
#
-kvm-objs := kvm_main.o mmu.o x86_emulate.o
+kvm-objs := kvm_main.o mmu.o x86_emulate.o i8259.o irq.o lapic.o ioapic.o
obj-$(CONFIG_KVM) += kvm.o
kvm-intel-objs = vmx.o
obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
diff --git a/drivers/kvm/i8259.c b/drivers/kvm/i8259.c
new file mode 100644
index 00000000000..a679157bc59
--- /dev/null
+++ b/drivers/kvm/i8259.c
@@ -0,0 +1,450 @@
+/*
+ * 8259 interrupt controller emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2007 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 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:
+ * Yaozu (Eddie) Dong <Eddie.dong@intel.com>
+ * Port from Qemu.
+ */
+#include <linux/mm.h>
+#include "irq.h"
+
+/*
+ * set irq level. If an edge is detected, then the IRR is set to 1
+ */
+static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level)
+{
+ int mask;
+ mask = 1 << irq;
+ if (s->elcr & mask) /* level triggered */
+ if (level) {
+ s->irr |= mask;
+ s->last_irr |= mask;
+ } else {
+ s->irr &= ~mask;
+ s->last_irr &= ~mask;
+ }
+ else /* edge triggered */
+ if (level) {
+ if ((s->last_irr & mask) == 0)
+ s->irr |= mask;
+ s->last_irr |= mask;
+ } else
+ s->last_irr &= ~mask;
+}
+
+/*
+ * return the highest priority found in mask (highest = smallest
+ * number). Return 8 if no irq
+ */
+static inline int get_priority(struct kvm_kpic_state *s, int mask)
+{
+ int priority;
+ if (mask == 0)
+ return 8;
+ priority = 0;
+ while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
+ priority++;
+ return priority;
+}
+
+/*
+ * return the pic wanted interrupt. return -1 if none
+ */
+static int pic_get_irq(struct kvm_kpic_state *s)
+{
+ int mask, cur_priority, priority;
+
+ mask = s->irr & ~s->imr;
+ priority = get_priority(s, mask);
+ if (priority == 8)
+ return -1;
+ /*
+ * compute current priority. If special fully nested mode on the
+ * master, the IRQ coming from the slave is not taken into account
+ * for the priority computation.
+ */
+ mask = s->isr;
+ if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
+ mask &= ~(1 << 2);
+ cur_priority = get_priority(s, mask);
+ if (priority < cur_priority)
+ /*
+ * higher priority found: an irq should be generated
+ */
+ return (priority + s->priority_add) & 7;
+ else
+ return -1;
+}
+
+/*
+ * raise irq to CPU if necessary. must be called every time the active
+ * irq may change
+ */
+static void pic_update_irq(struct kvm_pic *s)
+{
+ int irq2, irq;
+
+ irq2 = pic_get_irq(&s->pics[1]);
+ if (irq2 >= 0) {
+ /*
+ * if irq request by slave pic, signal master PIC
+ */
+ pic_set_irq1(&s->pics[0], 2, 1);
+ pic_set_irq1(&s->pics[0], 2, 0);
+ }
+ irq = pic_get_irq(&s->pics[0]);
+ if (irq >= 0)
+ s->irq_request(s->irq_request_opaque, 1);
+ else
+ s->irq_request(s->irq_request_opaque, 0);
+}
+
+void kvm_pic_update_irq(struct kvm_pic *s)
+{
+ pic_update_irq(s);
+}
+
+void kvm_pic_set_irq(void *opaque, int irq, int level)
+{
+ struct kvm_pic *s = opaque;
+
+ pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
+ pic_update_irq(s);
+}
+
+/*
+ * acknowledge interrupt 'irq'
+ */
+static inline void pic_intack(struct kvm_kpic_state *s, int irq)
+{
+ if (s->auto_eoi) {
+ if (s->rotate_on_auto_eoi)
+ s->priority_add = (irq + 1) & 7;
+ } else
+ s->isr |= (1 << irq);
+ /*
+ * We don't clear a level sensitive interrupt here
+ */
+ if (!(s->elcr & (1 << irq)))
+ s->irr &= ~(1 << irq);
+}
+
+int kvm_pic_read_irq(struct kvm_pic *s)
+{
+ int irq, irq2, intno;
+
+ irq = pic_get_irq(&s->pics[0]);
+ if (irq >= 0) {
+ pic_intack(&s->pics[0], irq);
+ if (irq == 2) {
+ irq2 = pic_get_irq(&s->pics[1]);
+ if (irq2 >= 0)
+ pic_intack(&s->pics[1], irq2);
+ else
+ /*
+ * spurious IRQ on slave controller
+ */
+ irq2 = 7;
+ intno = s->pics[1].irq_base + irq2;
+ irq = irq2 + 8;
+ } else
+ intno = s->pics[0].irq_base + irq;
+ } else {
+ /*
+ * spurious IRQ on host controller
+ */
+ irq = 7;
+ intno = s->pics[0].irq_base + irq;
+ }
+ pic_update_irq(s);
+
+ return intno;
+}
+
+static void pic_reset(void *opaque)
+{
+ struct kvm_kpic_state *s = opaque;
+
+ s->last_irr = 0;
+ s->irr = 0;
+ s->imr = 0;
+ s->isr = 0;
+ s->priority_add = 0;
+ s->irq_base = 0;
+ s->read_reg_select = 0;
+ s->poll = 0;
+ s->special_mask = 0;
+ s->init_state = 0;
+ s->auto_eoi = 0;
+ s->rotate_on_auto_eoi = 0;
+ s->special_fully_nested_mode = 0;
+ s->init4 = 0;
+}
+
+static void pic_ioport_write(void *opaque, u32 addr, u32 val)
+{
+ struct kvm_kpic_state *s = opaque;
+ int priority, cmd, irq;
+
+ addr &= 1;
+ if (addr == 0) {
+ if (val & 0x10) {
+ pic_reset(s); /* init */
+ /*
+ * deassert a pending interrupt
+ */
+ s->pics_state->irq_request(s->pics_state->
+ irq_request_opaque, 0);
+ s->init_state = 1;
+ s->init4 = val & 1;
+ if (val & 0x02)
+ printk(KERN_ERR "single mode not supported");
+ if (val & 0x08)
+ printk(KERN_ERR
+ "level sensitive irq not supported");
+ } else if (val & 0x08) {
+ if (val & 0x04)
+ s->poll = 1;
+ if (val & 0x02)
+ s->read_reg_select = val & 1;
+ if (val & 0x40)
+ s->special_mask = (val >> 5) & 1;
+ } else {
+ cmd = val >> 5;
+ switch (cmd) {
+ case 0:
+ case 4:
+ s->rotate_on_auto_eoi = cmd >> 2;
+ break;
+ case 1: /* end of interrupt */
+ case 5:
+ priority = get_priority(s, s->isr);
+ if (priority != 8) {
+ irq = (priority + s->priority_add) & 7;
+ s->isr &= ~(1 << irq);
+ if (cmd == 5)
+ s->priority_add = (irq + 1) & 7;
+ pic_update_irq(s->pics_state);
+ }
+ break;
+ case 3:
+ irq = val & 7;
+ s->isr &= ~(1 << irq);
+ pic_update_irq(s->pics_state);
+ break;
+ case 6:
+ s->priority_add = (val + 1) & 7;
+ pic_update_irq(s->pics_state);
+ break;
+ case 7:
+ irq = val & 7;
+ s->isr &= ~(1 << irq);
+ s->priority_add = (irq + 1) & 7;
+ pic_update_irq(s->pics_state);
+ break;
+ default:
+ break; /* no operation */
+ }
+ }
+ } else
+ switch (s->init_state) {
+ case 0: /* normal mode */
+ s->imr = val;
+ pic_update_irq(s->pics_state);
+ break;
+ case 1:
+ s->irq_base = val & 0xf8;
+ s->init_state = 2;
+ break;
+ case 2:
+ if (s->init4)
+ s->init_state = 3;
+ else
+ s->init_state = 0;
+ break;
+ case 3:
+ s->special_fully_nested_mode = (val >> 4) & 1;
+ s->auto_eoi = (val >> 1) & 1;
+ s->init_state = 0;
+ break;
+ }
+}
+
+static u32 pic_poll_read(struct kvm_kpic_state *s, u32 addr1)
+{
+ int ret;
+
+ ret = pic_get_irq(s);
+ if (ret >= 0) {
+ if (addr1 >> 7) {
+ s->pics_state->pics[0].isr &= ~(1 << 2);
+ s->pics_state->pics[0].irr &= ~(1 << 2);
+ }
+ s->irr &= ~(1 << ret);
+ s->isr &= ~(1 << ret);
+ if (addr1 >> 7 || ret != 2)
+ pic_update_irq(s->pics_state);
+ } else {
+ ret = 0x07;
+ pic_update_irq(s->pics_state);
+ }
+
+ return ret;
+}
+
+static u32 pic_ioport_read(void *opaque, u32 addr1)
+{
+ struct kvm_kpic_state *s = opaque;
+ unsigned int addr;
+ int ret;
+
+ addr = addr1;
+ addr &= 1;
+ if (s->poll) {
+ ret = pic_poll_read(s, addr1);
+ s->poll = 0;
+ } else
+ if (addr == 0)
+ if (s->read_reg_select)
+ ret = s->isr;
+ else
+ ret = s->irr;
+ else
+ ret = s->imr;
+ return ret;
+}
+
+static void elcr_ioport_write(void *opaque, u32 addr, u32 val)
+{
+ struct kvm_kpic_state *s = opaque;
+ s->elcr = val & s->elcr_mask;
+}
+
+static u32 elcr_ioport_read(void *opaque, u32 addr1)
+{
+ struct kvm_kpic_state *s = opaque;
+ return s->elcr;
+}
+
+static int picdev_in_range(struct kvm_io_device *this, gpa_t addr)
+{
+ switch (addr) {
+ case 0x20:
+ case 0x21:
+ case 0xa0:
+ case 0xa1:
+ case 0x4d0:
+ case 0x4d1:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static void picdev_write(struct kvm_io_device *this,
+ gpa_t addr, int len, const void *val)
+{
+ struct kvm_pic *s = this->private;
+ unsigned char data = *(unsigned char *)val;
+
+ if (len != 1) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "PIC: non byte write\n");
+ return;
+ }
+ switch (addr) {
+ case 0x20:
+ case 0x21:
+ case 0xa0:
+ case 0xa1:
+ pic_ioport_write(&s->pics[addr >> 7], addr, data);
+ break;
+ case 0x4d0:
+ case 0x4d1:
+ elcr_ioport_write(&s->pics[addr & 1], addr, data);
+ break;
+ }
+}
+
+static void picdev_read(struct kvm_io_device *this,
+ gpa_t addr, int len, void *val)
+{
+ struct kvm_pic *s = this->private;
+ unsigned char data = 0;
+
+ if (len != 1) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "PIC: non byte read\n");
+ return;
+ }
+ switch (addr) {
+ case 0x20:
+ case 0x21:
+ case 0xa0:
+ case 0xa1:
+ data = pic_ioport_read(&s->pics[addr >> 7], addr);
+ break;
+ case 0x4d0:
+ case 0x4d1:
+ data = elcr_ioport_read(&s->pics[addr & 1], addr);
+ break;
+ }
+ *(unsigned char *)val = data;
+}
+
+/*
+ * callback when PIC0 irq status changed
+ */
+static void pic_irq_request(void *opaque, int level)
+{
+ struct kvm *kvm = opaque;
+ struct kvm_vcpu *vcpu = kvm->vcpus[0];
+
+ pic_irqchip(kvm)->output = level;
+ if (vcpu)
+ kvm_vcpu_kick(vcpu);
+}
+
+struct kvm_pic *kvm_create_pic(struct kvm *kvm)
+{
+ struct kvm_pic *s;
+ s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL);
+ if (!s)
+ return NULL;
+ s->pics[0].elcr_mask = 0xf8;
+ s->pics[1].elcr_mask = 0xde;
+ s->irq_request = pic_irq_request;
+ s->irq_request_opaque = kvm;
+ s->pics[0].pics_state = s;
+ s->pics[1].pics_state = s;
+
+ /*
+ * Initialize PIO device
+ */
+ s->dev.read = picdev_read;
+ s->dev.write = picdev_write;
+ s->dev.in_range = picdev_in_range;
+ s->dev.private = s;
+ kvm_io_bus_register_dev(&kvm->pio_bus, &s->dev);
+ return s;
+}
diff --git a/drivers/kvm/ioapic.c b/drivers/kvm/ioapic.c
new file mode 100644
index 00000000000..c7992e667fd
--- /dev/null
+++ b/drivers/kvm/ioapic.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2001 MandrakeSoft S.A.
+ *
+ * MandrakeSoft S.A.
+ * 43, rue d'Aboukir
+ * 75002 Paris - France
+ * http://www.linux-mandrake.com/
+ * http://www.mandrakesoft.com/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Yunhong Jiang <yunhong.jiang@intel.com>
+ * Yaozu (Eddie) Dong <eddie.dong@intel.com>
+ * Based on Xen 3.1 code.
+ */
+
+#include "kvm.h"
+#include <linux/kvm.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/smp.h>
+#include <linux/hrtimer.h>
+#include <linux/io.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/page.h>
+#include <asm/current.h>
+#include <asm/apicdef.h>
+#include <asm/io_apic.h>
+#include "irq.h"
+/* #define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */
+#define ioapic_debug(fmt, arg...)
+static void ioapic_deliver(struct kvm_ioapic *vioapic, int irq);
+
+static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
+ unsigned long addr,
+ unsigned long length)
+{
+ unsigned long result = 0;
+
+ switch (ioapic->ioregsel) {
+ case IOAPIC_REG_VERSION:
+ result = ((((IOAPIC_NUM_PINS - 1) & 0xff) << 16)
+ | (IOAPIC_VERSION_ID & 0xff));
+ break;
+
+ case IOAPIC_REG_APIC_ID:
+ case IOAPIC_REG_ARB_ID:
+ result = ((ioapic->id & 0xf) << 24);
+ break;
+
+ default:
+ {
+ u32 redir_index = (ioapic->ioregsel - 0x10) >> 1;
+ u64 redir_content;
+
+ ASSERT(redir_index < IOAPIC_NUM_PINS);
+
+ redir_content = ioapic->redirtbl[redir_index].bits;
+ result = (ioapic->ioregsel & 0x1) ?
+ (redir_content >> 32) & 0xffffffff :
+ redir_content & 0xffffffff;
+ break;
+ }
+ }
+
+ return result;
+}
+
+static void ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
+{
+ union ioapic_redir_entry *pent;
+
+ pent = &ioapic->redirtbl[idx];
+
+ if (!pent->fields.mask) {
+ ioapic_deliver(ioapic, idx);
+ if (pent->fields.trig_mode == IOAPIC_LEVEL_TRIG)
+ pent->fields.remote_irr = 1;
+ }
+ if (!pent->fields.trig_mode)
+ ioapic->irr &= ~(1 << idx);
+}
+
+static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
+{
+ unsigned index;
+
+ switch (ioapic->ioregsel) {
+ case IOAPIC_REG_VERSION:
+ /* Writes are ignored. */
+ break;
+
+ case IOAPIC_REG_APIC_ID:
+ ioapic->id = (val >> 24) & 0xf;
+ break;
+
+ case IOAPIC_REG_ARB_ID:
+ break;
+
+ default:
+ index = (ioapic->ioregsel - 0x10) >> 1;
+
+ ioapic_debug("change redir index %x val %x", index, val);
+ if (index >= IOAPIC_NUM_PINS)
+ return;
+ if (ioapic->ioregsel & 1) {
+ ioapic->redirtbl[index].bits &= 0xffffffff;
+ ioapic->redirtbl[index].bits |= (u64) val << 32;
+ } else {
+ ioapic->redirtbl[index].bits &= ~0xffffffffULL;
+ ioapic->redirtbl[index].bits |= (u32) val;
+ ioapic->redirtbl[index].fields.remote_irr = 0;
+ }
+ if (ioapic->irr & (1 << index))
+ ioapic_service(ioapic, index);
+ break;
+ }
+}
+
+static void ioapic_inj_irq(struct kvm_ioapic *ioapic,
+ struct kvm_lapic *target,
+ u8 vector, u8 trig_mode, u8 delivery_mode)
+{
+ ioapic_debug("irq %d trig %d deliv %d", vector, trig_mode,
+ delivery_mode);
+
+ ASSERT((delivery_mode == dest_Fixed) ||
+ (delivery_mode == dest_LowestPrio));
+
+ kvm_apic_set_irq(target, vector, trig_mode);
+}
+
+static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
+ u8 dest_mode)
+{
+ u32 mask = 0;
+ int i;
+ struct kvm *kvm = ioapic->kvm;
+ struct kvm_vcpu *vcpu;
+
+ ioapic_debug("dest %d dest_mode %d", dest, dest_mode);
+
+ if (dest_mode == 0) { /* Physical mode. */
+ if (dest == 0xFF) { /* Broadcast. */
+ for (i = 0; i < KVM_MAX_VCPUS; ++i)
+ if (kvm->vcpus[i] && kvm->vcpus[i]->apic)
+ mask |= 1 << i;
+ return mask;
+ }
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ vcpu = kvm->vcpus[i];
+ if (!vcpu)
+ continue;
+ if (kvm_apic_match_physical_addr(vcpu->apic, dest)) {
+ if (vcpu->apic)
+ mask = 1 << i;
+ break;
+ }
+ }
+ } else if (dest != 0) /* Logical mode, MDA non-zero. */
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ vcpu = kvm->vcpus[i];
+ if (!vcpu)
+ continue;
+ if (vcpu->apic &&
+ kvm_apic_match_logical_addr(vcpu->apic, dest))
+ mask |= 1 << vcpu->vcpu_id;
+ }
+ ioapic_debug("mask %x", mask);
+ return mask;
+}
+
+static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
+{
+ u8 dest = ioapic->redirtbl[irq].fields.dest_id;
+ u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode;
+ u8 delivery_mode = ioapic->redirtbl[irq].fields.delivery_mode;
+ u8 vector = ioapic->redirtbl[irq].fields.vector;
+ u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode;
+ u32 deliver_bitmask;
+ struct kvm_lapic *target;
+ struct kvm_vcpu *vcpu;
+ int vcpu_id;
+
+ ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
+ "vector=%x trig_mode=%x",
+ dest, dest_mode, delivery_mode, vector, trig_mode);
+
+ deliver_bitmask = ioapic_get_delivery_bitmask(ioapic, dest, dest_mode);
+ if (!deliver_bitmask) {
+ ioapic_debug("no target on destination");
+ return;
+ }
+
+ switch (delivery_mode) {
+ case dest_LowestPrio:
+ target =
+ kvm_apic_round_robin(ioapic->kvm, vector, deliver_bitmask);
+ if (target != NULL)
+ ioapic_inj_irq(ioapic, target, vector,
+ trig_mode, delivery_mode);
+ else
+ ioapic_debug("null round robin: "
+ "mask=%x vector=%x delivery_mode=%x",
+ deliver_bitmask, vector, dest_LowestPrio);
+ break;
+ case dest_Fixed:
+ for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
+ if (!(deliver_bitmask & (1 << vcpu_id)))
+ continue;
+ deliver_bitmask &= ~(1 << vcpu_id);
+ vcpu = ioapic->kvm->vcpus[vcpu_id];
+ if (vcpu) {
+ target = vcpu->apic;
+ ioapic_inj_irq(ioapic, target, vector,
+ trig_mode, delivery_mode);
+ }
+ }
+ break;
+
+ /* TODO: NMI */
+ default:
+ printk(KERN_WARNING "Unsupported delivery mode %d\n",
+ delivery_mode);
+ break;
+ }
+}
+
+void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
+{
+ u32 old_irr = ioapic->irr;
+ u32 mask = 1 << irq;
+ union ioapic_redir_entry entry;
+
+ if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
+ entry = ioapic->redirtbl[irq];
+ level ^= entry.fields.polarity;
+ if (!level)
+ ioapic->irr &= ~mask;
+ else {
+ ioapic->irr |= mask;
+ if ((!entry.fields.trig_mode && old_irr != ioapic->irr)
+ || !entry.fields.remote_irr)
+ ioapic_service(ioapic, irq);
+ }
+ }
+}
+
+static int get_eoi_gsi(struct kvm_ioapic *ioapic, int vector)
+{
+ int i;
+
+ for (i = 0; i < IOAPIC_NUM_PINS; i++)
+ if (ioapic->redirtbl[i].fields.vector == vector)
+ return i;
+ return -1;
+}
+
+void kvm_ioapic_update_eoi(struct kvm *kvm, int vector)
+{
+ struct kvm_ioapic *ioapic = kvm->vioapic;
+ union ioapic_redir_entry *ent;
+ int gsi;
+
+ gsi = get_eoi_gsi(ioapic, vector);
+ if (gsi == -1) {
+ printk(KERN_WARNING "Can't find redir item for %d EOI\n",
+ vector);
+ return;
+ }
+
+ ent = &ioapic->redirtbl[gsi];
+ ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
+
+ ent->fields.remote_irr = 0;
+ if (!ent->fields.mask && (ioapic->irr & (1 << gsi)))
+ ioapic_deliver(ioapic, gsi);
+}
+
+static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr)
+{
+ struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
+
+ return ((addr >= ioapic->base_address &&
+ (addr < ioapic->base_address + IOAPIC_MEM_LENGTH)));
+}
+
+static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
+ void *val)
+{
+ struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
+ u32 result;
+
+ ioapic_debug("addr %lx", (unsigned long)addr);
+ ASSERT(!(addr & 0xf)); /* check alignment */
+
+ addr &= 0xff;
+ switch (addr) {
+ case IOAPIC_REG_SELECT:
+ result = ioapic->ioregsel;
+ break;
+
+ case IOAPIC_REG_WINDOW:
+ result = ioapic_read_indirect(ioapic, addr, len);
+ break;
+
+ default:
+ result = 0;
+ break;
+ }
+ switch (len) {
+ case 8:
+ *(u64 *) val = result;
+ break;
+ case 1:
+ case 2:
+ case 4:
+ memcpy(val, (char *)&result, len);
+ break;
+ default:
+ printk(KERN_WARNING "ioapic: wrong length %d\n", len);
+ }
+}
+
+static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
+ const void *val)
+{
+ struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
+ u32 data;
+
+ ioapic_debug("ioapic_mmio_write addr=%lx len=%d val=%p\n",
+ addr, len, val);
+ ASSERT(!(addr & 0xf)); /* check alignment */
+ if (len == 4 || len == 8)
+ data = *(u32 *) val;
+ else {
+ printk(KERN_WARNING "ioapic: Unsupported size %d\n", len);
+ return;
+ }
+
+ addr &= 0xff;
+ switch (addr) {
+ case IOAPIC_REG_SELECT:
+ ioapic->ioregsel = data;
+ break;
+
+ case IOAPIC_REG_WINDOW:
+ ioapic_write_indirect(ioapic, data);
+ break;
+
+ default:
+ break;
+ }
+}
+
+int kvm_ioapic_init(struct kvm *kvm)
+{
+ struct kvm_ioapic *ioapic;
+ int i;
+
+ ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL);
+ if (!ioapic)
+ return -ENOMEM;
+ kvm->vioapic = ioapic;
+ for (i = 0; i < IOAPIC_NUM_PINS; i++)
+ ioapic->redirtbl[i].fields.mask = 1;
+ ioapic->base_address = IOAPIC_DEFAULT_BASE_ADDRESS;
+ ioapic->dev.read = ioapic_mmio_read;
+ ioapic->dev.write = ioapic_mmio_write;
+ ioapic->dev.in_range = ioapic_in_range;
+ ioapic->dev.private = ioapic;
+ ioapic->kvm = kvm;
+ kvm_io_bus_register_dev(&kvm->mmio_bus, &ioapic->dev);
+ return 0;
+}
diff --git a/drivers/kvm/irq.c b/drivers/kvm/irq.c
new file mode 100644
index 00000000000..7628c7ff628
--- /dev/null
+++ b/drivers/kvm/irq.c
@@ -0,0 +1,98 @@
+/*
+ * irq.c: API for in kernel interrupt controller
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ * Authors:
+ * Yaozu (Eddie) Dong <Eddie.dong@intel.com>
+ *
+ */
+
+#include <linux/module.h>
+
+#include "kvm.h"
+#include "irq.h"
+
+/*
+ * check if there is pending interrupt without
+ * intack.
+ */
+int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
+{
+ struct kvm_pic *s;
+
+ if (kvm_apic_has_interrupt(v) == -1) { /* LAPIC */
+ if (kvm_apic_accept_pic_intr(v)) {
+ s = pic_irqchip(v->kvm); /* PIC */
+ return s->output;
+ } else
+ return 0;
+ }
+ return 1;
+}
+EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt);
+
+/*
+ * Read pending interrupt vector and intack.
+ */
+int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
+{
+ struct kvm_pic *s;
+ int vector;
+
+ vector = kvm_get_apic_interrupt(v); /* APIC */
+ if (vector == -1) {
+ if (kvm_apic_accept_pic_intr(v)) {
+ s = pic_irqchip(v->kvm);
+ s->output = 0; /* PIC */
+ vector = kvm_pic_read_irq(s);
+ }
+ }
+ return vector;
+}
+EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
+
+static void vcpu_kick_intr(void *info)
+{
+#ifdef DEBUG
+ struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info;
+ printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu);
+#endif
+}
+
+void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
+{
+ int ipi_pcpu = vcpu->cpu;
+
+ if (waitqueue_active(&vcpu->wq)) {
+ wake_up_interruptible(&vcpu->wq);
+ ++vcpu->stat.halt_wakeup;
+ }
+ if (vcpu->guest_mode)
+ smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0);
+}
+
+void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
+{
+ kvm_inject_apic_timer_irqs(vcpu);
+ /* TODO: PIT, RTC etc. */
+}
+EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
+
+void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
+{
+ kvm_apic_timer_intr_post(vcpu, vec);
+ /* TODO: PIT, RTC etc. */
+}
+EXPORT_SYMBOL_GPL(kvm_timer_intr_post);
diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h
new file mode 100644
index 00000000000..11fc014e2b3
--- /dev/null
+++ b/drivers/kvm/irq.h
@@ -0,0 +1,165 @@
+/*
+ * irq.h: in kernel interrupt controller related definitions
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ * Authors:
+ * Yaozu (Eddie) Dong <Eddie.dong@intel.com>
+ *
+ */
+
+#ifndef __IRQ_H
+#define __IRQ_H
+
+#include "kvm.h"
+
+typedef void irq_request_func(void *opaque, int level);
+
+struct kvm_kpic_state {
+ u8 last_irr; /* edge detection */
+ u8 irr; /* interrupt request register */
+ u8 imr; /* interrupt mask register */
+ u8 isr; /* interrupt service register */
+ u8 priority_add; /* highest irq priority */
+ u8 irq_base;
+ u8 read_reg_select;
+ u8 poll;
+ u8 special_mask;
+ u8 init_state;
+ u8 auto_eoi;
+ u8 rotate_on_auto_eoi;
+ u8 special_fully_nested_mode;
+ u8 init4; /* true if 4 byte init */
+ u8 elcr; /* PIIX edge/trigger selection */
+ u8 elcr_mask;
+ struct kvm_pic *pics_state;
+};
+
+struct kvm_pic {
+ struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */
+ irq_request_func *irq_request;
+ void *irq_request_opaque;
+ int output; /* intr from master PIC */
+ struct kvm_io_device dev;
+};
+
+struct kvm_pic *kvm_create_pic(struct kvm *kvm);
+void kvm_pic_set_irq(void *opaque, int irq, int level);
+int kvm_pic_read_irq(struct kvm_pic *s);
+int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
+int kvm_cpu_has_interrupt(struct kvm_vcpu *v);
+void kvm_pic_update_irq(struct kvm_pic *s);
+
+#define IOAPIC_NUM_PINS KVM_IOAPIC_NUM_PINS
+#define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */
+#define IOAPIC_EDGE_TRIG 0
+#define IOAPIC_LEVEL_TRIG 1
+
+#define IOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000
+#define IOAPIC_MEM_LENGTH 0x100
+
+/* Direct registers. */
+#define IOAPIC_REG_SELECT 0x00
+#define IOAPIC_REG_WINDOW 0x10
+#define IOAPIC_REG_EOI 0x40 /* IA64 IOSAPIC only */
+
+/* Indirect registers. */
+#define IOAPIC_REG_APIC_ID 0x00 /* x86 IOAPIC only */
+#define IOAPIC_REG_VERSION 0x01
+#define IOAPIC_REG_ARB_ID 0x02 /* x86 IOAPIC only */
+
+struct kvm_ioapic {
+ u64 base_address;
+ u32 ioregsel;
+ u32 id;
+ u32 irr;
+ u32 pad;
+ union ioapic_redir_entry {
+ u64 bits;
+ struct {
+ u8 vector;
+ u8 delivery_mode:3;
+ u8 dest_mode:1;
+ u8 delivery_status:1;
+ u8 polarity:1;
+ u8 remote_irr:1;
+ u8 trig_mode:1;
+ u8 mask:1;
+ u8 reserve:7;
+ u8 reserved[4];
+ u8 dest_id;
+ } fields;
+ } redirtbl[IOAPIC_NUM_PINS];
+ struct kvm_io_device dev;
+ struct kvm *kvm;
+};
+
+struct kvm_lapic {
+ unsigned long base_address;
+ struct kvm_io_device dev;
+ struct {
+ atomic_t pending;
+ s64 period; /* unit: ns */
+ u32 divide_count;
+ ktime_t last_update;
+ struct hrtimer dev;
+ } timer;
+ struct kvm_vcpu *vcpu;
+ struct page *regs_page;
+ void *regs;
+};
+
+#ifdef DEBUG
+#define ASSERT(x) \
+do { \
+ if (!(x)) { \
+ printk(KERN_EMERG "assertion failed %s: %d: %s\n", \
+ __FILE__, __LINE__, #x); \
+ BUG(); \
+ } \
+} while (0)
+#else
+#define ASSERT(x) do { } while (0)
+#endif
+
+void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
+int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu);
+int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu);
+int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
+int kvm_create_lapic(struct kvm_vcpu *vcpu);
+void kvm_lapic_reset(struct kvm_vcpu *vcpu);
+void kvm_free_apic(struct kvm_lapic *apic);
+u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
+void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
+void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
+struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
+ unsigned long bitmap);
+u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
+void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
+int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
+void kvm_ioapic_update_eoi(struct kvm *kvm, int vector);
+int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
+int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig);
+void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
+int kvm_ioapic_init(struct kvm *kvm);
+void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
+int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
+int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
+void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
+void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
+void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
+void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu);
+void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu);
+
+#endif
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 336be86c6f5..3b0bc4bda5f 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -13,60 +13,38 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/preempt.h>
#include <asm/signal.h>
-#include "vmx.h"
#include <linux/kvm.h>
#include <linux/kvm_para.h>
-#define CR0_PE_MASK (1ULL << 0)
-#define CR0_MP_MASK (1ULL << 1)
-#define CR0_TS_MASK (1ULL << 3)
-#define CR0_NE_MASK (1ULL << 5)
-#define CR0_WP_MASK (1ULL << 16)
-#define CR0_NW_MASK (1ULL << 29)
-#define CR0_CD_MASK (1ULL << 30)
-#define CR0_PG_MASK (1ULL << 31)
-
-#define CR3_WPT_MASK (1ULL << 3)
-#define CR3_PCD_MASK (1ULL << 4)
-
-#define CR3_RESEVED_BITS 0x07ULL
-#define CR3_L_MODE_RESEVED_BITS (~((1ULL << 40) - 1) | 0x0fe7ULL)
-#define CR3_FLAGS_MASK ((1ULL << 5) - 1)
-
-#define CR4_VME_MASK (1ULL << 0)
-#define CR4_PSE_MASK (1ULL << 4)
-#define CR4_PAE_MASK (1ULL << 5)
-#define CR4_PGE_MASK (1ULL << 7)
-#define CR4_VMXE_MASK (1ULL << 13)
+#define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1)
+#define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD))
+#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS|0xFFFFFF0000000000ULL)
#define KVM_GUEST_CR0_MASK \
- (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK \
- | CR0_NW_MASK | CR0_CD_MASK)
+ (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE \
+ | X86_CR0_NW | X86_CR0_CD)
#define KVM_VM_CR0_ALWAYS_ON \
- (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK | CR0_TS_MASK \
- | CR0_MP_MASK)
+ (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE | X86_CR0_TS \
+ | X86_CR0_MP)
#define KVM_GUEST_CR4_MASK \
- (CR4_PSE_MASK | CR4_PAE_MASK | CR4_PGE_MASK | CR4_VMXE_MASK | CR4_VME_MASK)
-#define KVM_PMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK)
-#define KVM_RMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK | CR4_VME_MASK)
+ (X86_CR4_VME | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_VMXE)
+#define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE)
+#define KVM_RMODE_VM_CR4_ALWAYS_ON (X86_CR4_VME | X86_CR4_PAE | X86_CR4_VMXE)
#define INVALID_PAGE (~(hpa_t)0)
#define UNMAPPED_GVA (~(gpa_t)0)
#define KVM_MAX_VCPUS 4
#define KVM_ALIAS_SLOTS 4
-#define KVM_MEMORY_SLOTS 4
+#define KVM_MEMORY_SLOTS 8
#define KVM_NUM_MMU_PAGES 1024
#define KVM_MIN_FREE_MMU_PAGES 5
#define KVM_REFILL_PAGES 25
#define KVM_MAX_CPUID_ENTRIES 40
-#define FX_IMAGE_SIZE 512
-#define FX_IMAGE_ALIGN 16
-#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN)
-
#define DE_VECTOR 0
#define NM_VECTOR 7
#define DF_VECTOR 8
@@ -158,15 +136,8 @@ struct kvm_mmu_page {
};
};
-struct vmcs {
- u32 revision_id;
- u32 abort;
- char data[0];
-};
-
-#define vmx_msr_entry kvm_msr_entry
-
struct kvm_vcpu;
+extern struct kmem_cache *kvm_vcpu_cache;
/*
* x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level
@@ -260,6 +231,7 @@ struct kvm_stat {
u32 signal_exits;
u32 irq_window_exits;
u32 halt_exits;
+ u32 halt_wakeup;
u32 request_irq_exits;
u32 irq_exits;
u32 light_exits;
@@ -328,21 +300,17 @@ void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
struct kvm_vcpu {
struct kvm *kvm;
- union {
- struct vmcs *vmcs;
- struct vcpu_svm *svm;
- };
+ struct preempt_notifier preempt_notifier;
+ int vcpu_id;
struct mutex mutex;
int cpu;
- int launched;
u64 host_tsc;
struct kvm_run *run;
int interrupt_window_open;
int guest_mode;
unsigned long requests;
unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
-#define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
- unsigned long irq_pending[NR_IRQ_WORDS];
+ DECLARE_BITMAP(irq_pending, KVM_NR_INTERRUPTS);
unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */
unsigned long rip; /* needs vcpu_load_rsp_rip() */
@@ -357,15 +325,15 @@ struct kvm_vcpu {
u64 pdptrs[4]; /* pae */
u64 shadow_efer;
u64 apic_base;
+ struct kvm_lapic *apic; /* kernel irqchip context */
+#define VCPU_MP_STATE_RUNNABLE 0
+#define VCPU_MP_STATE_UNINITIALIZED 1
+#define VCPU_MP_STATE_INIT_RECEIVED 2
+#define VCPU_MP_STATE_SIPI_RECEIVED 3
+#define VCPU_MP_STATE_HALTED 4
+ int mp_state;
+ int sipi_vector;
u64 ia32_misc_enable_msr;
- int nmsrs;
- int save_nmsrs;
- int msr_offset_efer;
-#ifdef CONFIG_X86_64
- int msr_offset_kernel_gs_base;
-#endif
- struct vmx_msr_entry *guest_msrs;
- struct vmx_msr_entry *host_msrs;
struct kvm_mmu mmu;
@@ -379,16 +347,10 @@ struct kvm_vcpu {
struct kvm_guest_debug guest_debug;
- char fx_buf[FX_BUF_SIZE];
- char *host_fx_image;
- char *guest_fx_image;
+ struct i387_fxsave_struct host_fx_image;
+ struct i387_fxsave_struct guest_fx_image;
int fpu_active;
int guest_fpu_loaded;
- struct vmx_host_state {
- int loaded;
- u16 fs_sel, gs_sel, ldt_sel;
- int fs_gs_ldt_reload_needed;
- } vmx_host_state;
int mmio_needed;
int mmio_read_completed;
@@ -399,6 +361,7 @@ struct kvm_vcpu {
gva_t mmio_fault_cr2;
struct kvm_pio_request pio;
void *pio_data;
+ wait_queue_head_t wq;
int sigset_active;
sigset_t sigset;
@@ -436,7 +399,7 @@ struct kvm_memory_slot {
};
struct kvm {
- spinlock_t lock; /* protects everything except vcpus */
+ struct mutex lock; /* protects everything except vcpus */
int naliases;
struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS];
int nmemslots;
@@ -447,39 +410,59 @@ struct kvm {
struct list_head active_mmu_pages;
int n_free_mmu_pages;
struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
- int nvcpus;
- struct kvm_vcpu vcpus[KVM_MAX_VCPUS];
- int memory_config_version;
- int busy;
+ struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
unsigned long rmap_overflow;
struct list_head vm_list;
struct file *filp;
struct kvm_io_bus mmio_bus;
struct kvm_io_bus pio_bus;
+ struct kvm_pic *vpic;
+ struct kvm_ioapic *vioapic;
+ int round_robin_prev_vcpu;
};
+static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
+{
+ return kvm->vpic;
+}
+
+static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm)
+{
+ return kvm->vioapic;
+}
+
+static inline int irqchip_in_kernel(struct kvm *kvm)
+{
+ return pic_irqchip(kvm) != 0;
+}
+
struct descriptor_table {
u16 limit;
unsigned long base;
} __attribute__((packed));
-struct kvm_arch_ops {
+struct kvm_x86_ops {
int (*cpu_has_kvm_support)(void); /* __init */
int (*disabled_by_bios)(void); /* __init */
void (*hardware_enable)(void *dummy); /* __init */
void (*hardware_disable)(void *dummy);
+ void (*check_processor_compatibility)(void *rtn);
int (*hardware_setup)(void); /* __init */
void (*hardware_unsetup)(void); /* __exit */
- int (*vcpu_create)(struct kvm_vcpu *vcpu);
+ /* Create, but do not attach this VCPU */
+ struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id);
void (*vcpu_free)(struct kvm_vcpu *vcpu);
+ void (*vcpu_reset)(struct kvm_vcpu *vcpu);
- void (*vcpu_load)(struct kvm_vcpu *vcpu);
+ void (*prepare_guest_switch)(struct kvm_vcpu *vcpu);
+ void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
void (*vcpu_put)(struct kvm_vcpu *vcpu);
void (*vcpu_decache)(struct kvm_vcpu *vcpu);
int (*set_guest_debug)(struct kvm_vcpu *vcpu,
struct kvm_debug_guest *dbg);
+ void (*guest_debug_pre)(struct kvm_vcpu *vcpu);
int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
@@ -505,27 +488,43 @@ struct kvm_arch_ops {
unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags);
- void (*invlpg)(struct kvm_vcpu *vcpu, gva_t addr);
void (*tlb_flush)(struct kvm_vcpu *vcpu);
void (*inject_page_fault)(struct kvm_vcpu *vcpu,
unsigned long addr, u32 err_code);
void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code);
- int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
- int (*vcpu_setup)(struct kvm_vcpu *vcpu);
+ void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run);
+ int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu);
void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
void (*patch_hypercall)(struct kvm_vcpu *vcpu,
unsigned char *hypercall_addr);
+ int (*get_irq)(struct kvm_vcpu *vcpu);
+ void (*set_irq)(struct kvm_vcpu *vcpu, int vec);
+ void (*inject_pending_irq)(struct kvm_vcpu *vcpu);
+ void (*inject_pending_vectors)(struct kvm_vcpu *vcpu,
+ struct kvm_run *run);
};
-extern struct kvm_arch_ops *kvm_arch_ops;
+extern struct kvm_x86_ops *kvm_x86_ops;
+
+/* The guest did something we don't support. */
+#define pr_unimpl(vcpu, fmt, ...) \
+ do { \
+ if (printk_ratelimit()) \
+ printk(KERN_ERR "kvm: %i: cpu%i " fmt, \
+ current->tgid, (vcpu)->vcpu_id , ## __VA_ARGS__); \
+ } while(0)
#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
#define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt)
-int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module);
-void kvm_exit_arch(void);
+int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id);
+void kvm_vcpu_uninit(struct kvm_vcpu *vcpu);
+
+int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size,
+ struct module *module);
+void kvm_exit_x86(void);
int kvm_mmu_module_init(void);
void kvm_mmu_module_exit(void);
@@ -545,8 +544,6 @@ static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva);
struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva);
-void kvm_emulator_want_group7_invlpg(void);
-
extern hpa_t bad_page_address;
struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
@@ -561,6 +558,7 @@ enum emulation_result {
int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run,
unsigned long cr2, u16 error_code);
+void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context);
void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
@@ -574,9 +572,11 @@ int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
struct x86_emulate_ctxt;
-int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
- int size, unsigned long count, int string, int down,
- gva_t address, int rep, unsigned port);
+int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+ int size, unsigned port);
+int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+ int size, unsigned long count, int down,
+ gva_t address, int rep, unsigned port);
void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
int kvm_emulate_halt(struct kvm_vcpu *vcpu);
int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
@@ -590,34 +590,33 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0);
void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0);
void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0);
+unsigned long get_cr8(struct kvm_vcpu *vcpu);
void lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
+void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l);
int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data);
void fx_init(struct kvm_vcpu *vcpu);
-void load_msrs(struct vmx_msr_entry *e, int n);
-void save_msrs(struct vmx_msr_entry *e, int n);
void kvm_resched(struct kvm_vcpu *vcpu);
void kvm_load_guest_fpu(struct kvm_vcpu *vcpu);
void kvm_put_guest_fpu(struct kvm_vcpu *vcpu);
void kvm_flush_remote_tlbs(struct kvm *kvm);
-int kvm_read_guest(struct kvm_vcpu *vcpu,
- gva_t addr,
- unsigned long size,
- void *dest);
-
-int kvm_write_guest(struct kvm_vcpu *vcpu,
- gva_t addr,
- unsigned long size,
- void *data);
+int emulator_read_std(unsigned long addr,
+ void *val,
+ unsigned int bytes,
+ struct kvm_vcpu *vcpu);
+int emulator_write_emulated(unsigned long addr,
+ const void *val,
+ unsigned int bytes,
+ struct kvm_vcpu *vcpu);
unsigned long segment_base(u16 selector);
void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
- const u8 *old, const u8 *new, int bytes);
+ const u8 *new, int bytes);
int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);
void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
int kvm_mmu_load(struct kvm_vcpu *vcpu);
@@ -625,6 +624,16 @@ void kvm_mmu_unload(struct kvm_vcpu *vcpu);
int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run);
+static inline void kvm_guest_enter(void)
+{
+ current->flags |= PF_VCPU;
+}
+
+static inline void kvm_guest_exit(void)
+{
+ current->flags &= ~PF_VCPU;
+}
+
static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
u32 error_code)
{
@@ -656,17 +665,17 @@ static inline int is_long_mode(struct kvm_vcpu *vcpu)
static inline int is_pae(struct kvm_vcpu *vcpu)
{
- return vcpu->cr4 & CR4_PAE_MASK;
+ return vcpu->cr4 & X86_CR4_PAE;
}
static inline int is_pse(struct kvm_vcpu *vcpu)
{
- return vcpu->cr4 & CR4_PSE_MASK;
+ return vcpu->cr4 & X86_CR4_PSE;
}
static inline int is_paging(struct kvm_vcpu *vcpu)
{
- return vcpu->cr0 & CR0_PG_MASK;
+ return vcpu->cr0 & X86_CR0_PG;
}
static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot)
@@ -746,12 +755,12 @@ static inline unsigned long read_msr(unsigned long msr)
}
#endif
-static inline void fx_save(void *image)
+static inline void fx_save(struct i387_fxsave_struct *image)
{
asm ("fxsave (%0)":: "r" (image));
}
-static inline void fx_restore(void *image)
+static inline void fx_restore(struct i387_fxsave_struct *image)
{
asm ("fxrstor (%0)":: "r" (image));
}
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index cd0557954e5..07ae280e8fe 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -18,6 +18,7 @@
#include "kvm.h"
#include "x86_emulate.h"
#include "segment_descriptor.h"
+#include "irq.h"
#include <linux/kvm.h>
#include <linux/module.h>
@@ -37,6 +38,7 @@
#include <linux/cpumask.h>
#include <linux/smp.h>
#include <linux/anon_inodes.h>
+#include <linux/profile.h>
#include <asm/processor.h>
#include <asm/msr.h>
@@ -52,9 +54,11 @@ static LIST_HEAD(vm_list);
static cpumask_t cpus_hardware_enabled;
-struct kvm_arch_ops *kvm_arch_ops;
+struct kvm_x86_ops *kvm_x86_ops;
+struct kmem_cache *kvm_vcpu_cache;
+EXPORT_SYMBOL_GPL(kvm_vcpu_cache);
-static void hardware_disable(void *ignored);
+static __read_mostly struct preempt_ops kvm_preempt_ops;
#define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x)
@@ -73,6 +77,7 @@ static struct kvm_stats_debugfs_item {
{ "signal_exits", STAT_OFFSET(signal_exits) },
{ "irq_window", STAT_OFFSET(irq_window_exits) },
{ "halt_exits", STAT_OFFSET(halt_exits) },
+ { "halt_wakeup", STAT_OFFSET(halt_wakeup) },
{ "request_irq", STAT_OFFSET(request_irq_exits) },
{ "irq_exits", STAT_OFFSET(irq_exits) },
{ "light_exits", STAT_OFFSET(light_exits) },
@@ -84,10 +89,17 @@ static struct dentry *debugfs_dir;
#define MAX_IO_MSRS 256
-#define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL
-#define LMSW_GUEST_MASK 0x0eULL
-#define CR4_RESEVED_BITS (~((1ULL << 11) - 1))
-#define CR8_RESEVED_BITS (~0x0fULL)
+#define CR0_RESERVED_BITS \
+ (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
+ | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \
+ | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG))
+#define CR4_RESERVED_BITS \
+ (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\
+ | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \
+ | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR \
+ | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE))
+
+#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
#define EFER_RESERVED_BITS 0xfffffffffffff2fe
#ifdef CONFIG_X86_64
@@ -139,82 +151,14 @@ static inline int valid_vcpu(int n)
return likely(n >= 0 && n < KVM_MAX_VCPUS);
}
-int kvm_read_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size,
- void *dest)
-{
- unsigned char *host_buf = dest;
- unsigned long req_size = size;
-
- while (size) {
- hpa_t paddr;
- unsigned now;
- unsigned offset;
- hva_t guest_buf;
-
- paddr = gva_to_hpa(vcpu, addr);
-
- if (is_error_hpa(paddr))
- break;
-
- guest_buf = (hva_t)kmap_atomic(
- pfn_to_page(paddr >> PAGE_SHIFT),
- KM_USER0);
- offset = addr & ~PAGE_MASK;
- guest_buf |= offset;
- now = min(size, PAGE_SIZE - offset);
- memcpy(host_buf, (void*)guest_buf, now);
- host_buf += now;
- addr += now;
- size -= now;
- kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0);
- }
- return req_size - size;
-}
-EXPORT_SYMBOL_GPL(kvm_read_guest);
-
-int kvm_write_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size,
- void *data)
-{
- unsigned char *host_buf = data;
- unsigned long req_size = size;
-
- while (size) {
- hpa_t paddr;
- unsigned now;
- unsigned offset;
- hva_t guest_buf;
- gfn_t gfn;
-
- paddr = gva_to_hpa(vcpu, addr);
-
- if (is_error_hpa(paddr))
- break;
-
- gfn = vcpu->mmu.gva_to_gpa(vcpu, addr) >> PAGE_SHIFT;
- mark_page_dirty(vcpu->kvm, gfn);
- guest_buf = (hva_t)kmap_atomic(
- pfn_to_page(paddr >> PAGE_SHIFT), KM_USER0);
- offset = addr & ~PAGE_MASK;
- guest_buf |= offset;
- now = min(size, PAGE_SIZE - offset);
- memcpy((void*)guest_buf, host_buf, now);
- host_buf += now;
- addr += now;
- size -= now;
- kunmap_atomic((void *)(guest_buf & PAGE_MASK), KM_USER0);
- }
- return req_size - size;
-}
-EXPORT_SYMBOL_GPL(kvm_write_guest);
-
void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
{
if (!vcpu->fpu_active || vcpu->guest_fpu_loaded)
return;
vcpu->guest_fpu_loaded = 1;
- fx_save(vcpu->host_fx_image);
- fx_restore(vcpu->guest_fx_image);
+ fx_save(&vcpu->host_fx_image);
+ fx_restore(&vcpu->guest_fx_image);
}
EXPORT_SYMBOL_GPL(kvm_load_guest_fpu);
@@ -224,8 +168,8 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
return;
vcpu->guest_fpu_loaded = 0;
- fx_save(vcpu->guest_fx_image);
- fx_restore(vcpu->host_fx_image);
+ fx_save(&vcpu->guest_fx_image);
+ fx_restore(&vcpu->host_fx_image);
}
EXPORT_SYMBOL_GPL(kvm_put_guest_fpu);
@@ -234,89 +178,121 @@ EXPORT_SYMBOL_GPL(kvm_put_guest_fpu);
*/
static void vcpu_load(struct kvm_vcpu *vcpu)
{
+ int cpu;
+
mutex_lock(&vcpu->mutex);
- kvm_arch_ops->vcpu_load(vcpu);
+ cpu = get_cpu();
+ preempt_notifier_register(&vcpu->preempt_notifier);
+ kvm_x86_ops->vcpu_load(vcpu, cpu);
+ put_cpu();
}
static void vcpu_put(struct kvm_vcpu *vcpu)
{
- kvm_arch_ops->vcpu_put(vcpu);
+ preempt_disable();
+ kvm_x86_ops->vcpu_put(vcpu);
+ preempt_notifier_unregister(&vcpu->preempt_notifier);
+ preempt_enable();
mutex_unlock(&vcpu->mutex);
}
static void ack_flush(void *_completed)
{
- atomic_t *completed = _completed;
-
- atomic_inc(completed);
}
void kvm_flush_remote_tlbs(struct kvm *kvm)
{
- int i, cpu, needed;
+ int i, cpu;
cpumask_t cpus;
struct kvm_vcpu *vcpu;
- atomic_t completed;
- atomic_set(&completed, 0);
cpus_clear(cpus);
- needed = 0;
- for (i = 0; i < kvm->nvcpus; ++i) {
- vcpu = &kvm->vcpus[i];
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ vcpu = kvm->vcpus[i];
+ if (!vcpu)
+ continue;
if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests))
continue;
cpu = vcpu->cpu;
if (cpu != -1 && cpu != raw_smp_processor_id())
- if (!cpu_isset(cpu, cpus)) {
- cpu_set(cpu, cpus);
- ++needed;
- }
+ cpu_set(cpu, cpus);
}
+ smp_call_function_mask(cpus, ack_flush, NULL, 1);
+}
- /*
- * We really want smp_call_function_mask() here. But that's not
- * available, so ipi all cpus in parallel and wait for them
- * to complete.
- */
- for (cpu = first_cpu(cpus); cpu != NR_CPUS; cpu = next_cpu(cpu, cpus))
- smp_call_function_single(cpu, ack_flush, &completed, 1, 0);
- while (atomic_read(&completed) != needed) {
- cpu_relax();
- barrier();
+int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
+{
+ struct page *page;
+ int r;
+
+ mutex_init(&vcpu->mutex);
+ vcpu->cpu = -1;
+ vcpu->mmu.root_hpa = INVALID_PAGE;
+ vcpu->kvm = kvm;
+ vcpu->vcpu_id = id;
+ if (!irqchip_in_kernel(kvm) || id == 0)
+ vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+ else
+ vcpu->mp_state = VCPU_MP_STATE_UNINITIALIZED;
+ init_waitqueue_head(&vcpu->wq);
+
+ page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!page) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ vcpu->run = page_address(page);
+
+ page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!page) {
+ r = -ENOMEM;
+ goto fail_free_run;
}
+ vcpu->pio_data = page_address(page);
+
+ r = kvm_mmu_create(vcpu);
+ if (r < 0)
+ goto fail_free_pio_data;
+
+ return 0;
+
+fail_free_pio_data:
+ free_page((unsigned long)vcpu->pio_data);
+fail_free_run:
+ free_page((unsigned long)vcpu->run);
+fail:
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(kvm_vcpu_init);
+
+void kvm_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+ kvm_mmu_destroy(vcpu);
+ if (vcpu->apic)
+ hrtimer_cancel(&vcpu->apic->timer.dev);
+ kvm_free_apic(vcpu->apic);
+ free_page((unsigned long)vcpu->pio_data);
+ free_page((unsigned long)vcpu->run);
}
+EXPORT_SYMBOL_GPL(kvm_vcpu_uninit);
static struct kvm *kvm_create_vm(void)
{
struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
- int i;
if (!kvm)
return ERR_PTR(-ENOMEM);
kvm_io_bus_init(&kvm->pio_bus);
- spin_lock_init(&kvm->lock);
+ mutex_init(&kvm->lock);
INIT_LIST_HEAD(&kvm->active_mmu_pages);
kvm_io_bus_init(&kvm->mmio_bus);
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- struct kvm_vcpu *vcpu = &kvm->vcpus[i];
-
- mutex_init(&vcpu->mutex);
- vcpu->cpu = -1;
- vcpu->kvm = kvm;
- vcpu->mmu.root_hpa = INVALID_PAGE;
- }
spin_lock(&kvm_lock);
list_add(&kvm->vm_list, &vm_list);
spin_unlock(&kvm_lock);
return kvm;
}
-static int kvm_dev_open(struct inode *inode, struct file *filp)
-{
- return 0;
-}
-
/*
* Free any memory in @free but not in @dont.
*/
@@ -353,7 +329,7 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
{
int i;
- for (i = 0; i < 2; ++i)
+ for (i = 0; i < ARRAY_SIZE(vcpu->pio.guest_pages); ++i)
if (vcpu->pio.guest_pages[i]) {
__free_page(vcpu->pio.guest_pages[i]);
vcpu->pio.guest_pages[i] = NULL;
@@ -362,30 +338,11 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
{
- if (!vcpu->vmcs)
- return;
-
vcpu_load(vcpu);
kvm_mmu_unload(vcpu);
vcpu_put(vcpu);
}
-static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
-{
- if (!vcpu->vmcs)
- return;
-
- vcpu_load(vcpu);
- kvm_mmu_destroy(vcpu);
- vcpu_put(vcpu);
- kvm_arch_ops->vcpu_free(vcpu);
- free_page((unsigned long)vcpu->run);
- vcpu->run = NULL;
- free_page((unsigned long)vcpu->pio_data);
- vcpu->pio_data = NULL;
- free_pio_guest_pages(vcpu);
-}
-
static void kvm_free_vcpus(struct kvm *kvm)
{
unsigned int i;
@@ -394,14 +351,15 @@ static void kvm_free_vcpus(struct kvm *kvm)
* Unpin any mmu pages first.
*/
for (i = 0; i < KVM_MAX_VCPUS; ++i)
- kvm_unload_vcpu_mmu(&kvm->vcpus[i]);
- for (i = 0; i < KVM_MAX_VCPUS; ++i)
- kvm_free_vcpu(&kvm->vcpus[i]);
-}
+ if (kvm->vcpus[i])
+ kvm_unload_vcpu_mmu(kvm->vcpus[i]);
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ if (kvm->vcpus[i]) {
+ kvm_x86_ops->vcpu_free(kvm->vcpus[i]);
+ kvm->vcpus[i] = NULL;
+ }
+ }
-static int kvm_dev_release(struct inode *inode, struct file *filp)
-{
- return 0;
}
static void kvm_destroy_vm(struct kvm *kvm)
@@ -411,6 +369,8 @@ static void kvm_destroy_vm(struct kvm *kvm)
spin_unlock(&kvm_lock);
kvm_io_bus_destroy(&kvm->pio_bus);
kvm_io_bus_destroy(&kvm->mmio_bus);
+ kfree(kvm->vpic);
+ kfree(kvm->vioapic);
kvm_free_vcpus(kvm);
kvm_free_physmem(kvm);
kfree(kvm);
@@ -426,7 +386,7 @@ static int kvm_vm_release(struct inode *inode, struct file *filp)
static void inject_gp(struct kvm_vcpu *vcpu)
{
- kvm_arch_ops->inject_gp(vcpu, 0);
+ kvm_x86_ops->inject_gp(vcpu, 0);
}
/*
@@ -437,58 +397,60 @@ static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT;
unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2;
int i;
- u64 pdpte;
u64 *pdpt;
int ret;
struct page *page;
+ u64 pdpte[ARRAY_SIZE(vcpu->pdptrs)];
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
page = gfn_to_page(vcpu->kvm, pdpt_gfn);
- /* FIXME: !page - emulate? 0xff? */
+ if (!page) {
+ ret = 0;
+ goto out;
+ }
+
pdpt = kmap_atomic(page, KM_USER0);
+ memcpy(pdpte, pdpt+offset, sizeof(pdpte));
+ kunmap_atomic(pdpt, KM_USER0);
- ret = 1;
- for (i = 0; i < 4; ++i) {
- pdpte = pdpt[offset + i];
- if ((pdpte & 1) && (pdpte & 0xfffffff0000001e6ull)) {
+ for (i = 0; i < ARRAY_SIZE(pdpte); ++i) {
+ if ((pdpte[i] & 1) && (pdpte[i] & 0xfffffff0000001e6ull)) {
ret = 0;
goto out;
}
}
+ ret = 1;
- for (i = 0; i < 4; ++i)
- vcpu->pdptrs[i] = pdpt[offset + i];
-
+ memcpy(vcpu->pdptrs, pdpte, sizeof(vcpu->pdptrs));
out:
- kunmap_atomic(pdpt, KM_USER0);
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
return ret;
}
void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
{
- if (cr0 & CR0_RESEVED_BITS) {
+ if (cr0 & CR0_RESERVED_BITS) {
printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n",
cr0, vcpu->cr0);
inject_gp(vcpu);
return;
}
- if ((cr0 & CR0_NW_MASK) && !(cr0 & CR0_CD_MASK)) {
+ if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) {
printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n");
inject_gp(vcpu);
return;
}
- if ((cr0 & CR0_PG_MASK) && !(cr0 & CR0_PE_MASK)) {
+ if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) {
printk(KERN_DEBUG "set_cr0: #GP, set PG flag "
"and a clear PE flag\n");
inject_gp(vcpu);
return;
}
- if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
+ if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
#ifdef CONFIG_X86_64
if ((vcpu->shadow_efer & EFER_LME)) {
int cs_db, cs_l;
@@ -499,7 +461,7 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
inject_gp(vcpu);
return;
}
- kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+ kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
if (cs_l) {
printk(KERN_DEBUG "set_cr0: #GP, start paging "
"in long mode while CS.L == 1\n");
@@ -518,12 +480,12 @@ void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
}
- kvm_arch_ops->set_cr0(vcpu, cr0);
+ kvm_x86_ops->set_cr0(vcpu, cr0);
vcpu->cr0 = cr0;
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
kvm_mmu_reset_context(vcpu);
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
return;
}
EXPORT_SYMBOL_GPL(set_cr0);
@@ -536,62 +498,72 @@ EXPORT_SYMBOL_GPL(lmsw);
void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
{
- if (cr4 & CR4_RESEVED_BITS) {
+ if (cr4 & CR4_RESERVED_BITS) {
printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n");
inject_gp(vcpu);
return;
}
if (is_long_mode(vcpu)) {
- if (!(cr4 & CR4_PAE_MASK)) {
+ if (!(cr4 & X86_CR4_PAE)) {
printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while "
"in long mode\n");
inject_gp(vcpu);
return;
}
- } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & CR4_PAE_MASK)
+ } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & X86_CR4_PAE)
&& !load_pdptrs(vcpu, vcpu->cr3)) {
printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n");
inject_gp(vcpu);
+ return;
}
- if (cr4 & CR4_VMXE_MASK) {
+ if (cr4 & X86_CR4_VMXE) {
printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n");
inject_gp(vcpu);
return;
}
- kvm_arch_ops->set_cr4(vcpu, cr4);
- spin_lock(&vcpu->kvm->lock);
+ kvm_x86_ops->set_cr4(vcpu, cr4);
+ vcpu->cr4 = cr4;
+ mutex_lock(&vcpu->kvm->lock);
kvm_mmu_reset_context(vcpu);
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
}
EXPORT_SYMBOL_GPL(set_cr4);
void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
{
if (is_long_mode(vcpu)) {
- if (cr3 & CR3_L_MODE_RESEVED_BITS) {
+ if (cr3 & CR3_L_MODE_RESERVED_BITS) {
printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
inject_gp(vcpu);
return;
}
} else {
- if (cr3 & CR3_RESEVED_BITS) {
- printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
- inject_gp(vcpu);
- return;
- }
- if (is_paging(vcpu) && is_pae(vcpu) &&
- !load_pdptrs(vcpu, cr3)) {
- printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
- "reserved bits\n");
- inject_gp(vcpu);
- return;
+ if (is_pae(vcpu)) {
+ if (cr3 & CR3_PAE_RESERVED_BITS) {
+ printk(KERN_DEBUG
+ "set_cr3: #GP, reserved bits\n");
+ inject_gp(vcpu);
+ return;
+ }
+ if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) {
+ printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
+ "reserved bits\n");
+ inject_gp(vcpu);
+ return;
+ }
+ } else {
+ if (cr3 & CR3_NONPAE_RESERVED_BITS) {
+ printk(KERN_DEBUG
+ "set_cr3: #GP, reserved bits\n");
+ inject_gp(vcpu);
+ return;
+ }
}
}
- vcpu->cr3 = cr3;
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
/*
* Does the new cr3 value map to physical memory? (Note, we
* catch an invalid cr3 even in real-mode, because it would
@@ -603,46 +575,73 @@ void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
*/
if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT)))
inject_gp(vcpu);
- else
+ else {
+ vcpu->cr3 = cr3;
vcpu->mmu.new_cr3(vcpu);
- spin_unlock(&vcpu->kvm->lock);
+ }
+ mutex_unlock(&vcpu->kvm->lock);
}
EXPORT_SYMBOL_GPL(set_cr3);
void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
{
- if ( cr8 & CR8_RESEVED_BITS) {
+ if (cr8 & CR8_RESERVED_BITS) {
printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8);
inject_gp(vcpu);
return;
}
- vcpu->cr8 = cr8;
+ if (irqchip_in_kernel(vcpu->kvm))
+ kvm_lapic_set_tpr(vcpu, cr8);
+ else
+ vcpu->cr8 = cr8;
}
EXPORT_SYMBOL_GPL(set_cr8);
-void fx_init(struct kvm_vcpu *vcpu)
+unsigned long get_cr8(struct kvm_vcpu *vcpu)
+{
+ if (irqchip_in_kernel(vcpu->kvm))
+ return kvm_lapic_get_cr8(vcpu);
+ else
+ return vcpu->cr8;
+}
+EXPORT_SYMBOL_GPL(get_cr8);
+
+u64 kvm_get_apic_base(struct kvm_vcpu *vcpu)
{
- struct __attribute__ ((__packed__)) fx_image_s {
- u16 control; //fcw
- u16 status; //fsw
- u16 tag; // ftw
- u16 opcode; //fop
- u64 ip; // fpu ip
- u64 operand;// fpu dp
- u32 mxcsr;
- u32 mxcsr_mask;
+ if (irqchip_in_kernel(vcpu->kvm))
+ return vcpu->apic_base;
+ else
+ return vcpu->apic_base;
+}
+EXPORT_SYMBOL_GPL(kvm_get_apic_base);
- } *fx_image;
+void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data)
+{
+ /* TODO: reserve bits check */
+ if (irqchip_in_kernel(vcpu->kvm))
+ kvm_lapic_set_base(vcpu, data);
+ else
+ vcpu->apic_base = data;
+}
+EXPORT_SYMBOL_GPL(kvm_set_apic_base);
+
+void fx_init(struct kvm_vcpu *vcpu)
+{
+ unsigned after_mxcsr_mask;
- fx_save(vcpu->host_fx_image);
+ /* Initialize guest FPU by resetting ours and saving into guest's */
+ preempt_disable();
+ fx_save(&vcpu->host_fx_image);
fpu_init();
- fx_save(vcpu->guest_fx_image);
- fx_restore(vcpu->host_fx_image);
+ fx_save(&vcpu->guest_fx_image);
+ fx_restore(&vcpu->host_fx_image);
+ preempt_enable();
- fx_image = (struct fx_image_s *)vcpu->guest_fx_image;
- fx_image->mxcsr = 0x1f80;
- memset(vcpu->guest_fx_image + sizeof(struct fx_image_s),
- 0, FX_IMAGE_SIZE - sizeof(struct fx_image_s));
+ vcpu->cr0 |= X86_CR0_ET;
+ after_mxcsr_mask = offsetof(struct i387_fxsave_struct, st_space);
+ vcpu->guest_fx_image.mxcsr = 0x1f80;
+ memset((void *)&vcpu->guest_fx_image + after_mxcsr_mask,
+ 0, sizeof(struct i387_fxsave_struct) - after_mxcsr_mask);
}
EXPORT_SYMBOL_GPL(fx_init);
@@ -661,7 +660,6 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
unsigned long i;
struct kvm_memory_slot *memslot;
struct kvm_memory_slot old, new;
- int memory_config_version;
r = -EINVAL;
/* General sanity checks */
@@ -681,10 +679,8 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
if (!npages)
mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES;
-raced:
- spin_lock(&kvm->lock);
+ mutex_lock(&kvm->lock);
- memory_config_version = kvm->memory_config_version;
new = old = *memslot;
new.base_gfn = base_gfn;
@@ -707,11 +703,6 @@ raced:
(base_gfn >= s->base_gfn + s->npages)))
goto out_unlock;
}
- /*
- * Do memory allocations outside lock. memory_config_version will
- * detect any races.
- */
- spin_unlock(&kvm->lock);
/* Deallocate if slot is being removed */
if (!npages)
@@ -728,14 +719,14 @@ raced:
new.phys_mem = vmalloc(npages * sizeof(struct page *));
if (!new.phys_mem)
- goto out_free;
+ goto out_unlock;
memset(new.phys_mem, 0, npages * sizeof(struct page *));
for (i = 0; i < npages; ++i) {
new.phys_mem[i] = alloc_page(GFP_HIGHUSER
| __GFP_ZERO);
if (!new.phys_mem[i])
- goto out_free;
+ goto out_unlock;
set_page_private(new.phys_mem[i],0);
}
}
@@ -746,39 +737,25 @@ raced:
new.dirty_bitmap = vmalloc(dirty_bytes);
if (!new.dirty_bitmap)
- goto out_free;
+ goto out_unlock;
memset(new.dirty_bitmap, 0, dirty_bytes);
}
- spin_lock(&kvm->lock);
-
- if (memory_config_version != kvm->memory_config_version) {
- spin_unlock(&kvm->lock);
- kvm_free_physmem_slot(&new, &old);
- goto raced;
- }
-
- r = -EAGAIN;
- if (kvm->busy)
- goto out_unlock;
-
if (mem->slot >= kvm->nmemslots)
kvm->nmemslots = mem->slot + 1;
*memslot = new;
- ++kvm->memory_config_version;
kvm_mmu_slot_remove_write_access(kvm, mem->slot);
kvm_flush_remote_tlbs(kvm);
- spin_unlock(&kvm->lock);
+ mutex_unlock(&kvm->lock);
kvm_free_physmem_slot(&old, &new);
return 0;
out_unlock:
- spin_unlock(&kvm->lock);
-out_free:
+ mutex_unlock(&kvm->lock);
kvm_free_physmem_slot(&new, &old);
out:
return r;
@@ -795,14 +772,8 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
int n;
unsigned long any = 0;
- spin_lock(&kvm->lock);
+ mutex_lock(&kvm->lock);
- /*
- * Prevent changes to guest memory configuration even while the lock
- * is not taken.
- */
- ++kvm->busy;
- spin_unlock(&kvm->lock);
r = -EINVAL;
if (log->slot >= KVM_MEMORY_SLOTS)
goto out;
@@ -821,18 +792,17 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
goto out;
- spin_lock(&kvm->lock);
- kvm_mmu_slot_remove_write_access(kvm, log->slot);
- kvm_flush_remote_tlbs(kvm);
- memset(memslot->dirty_bitmap, 0, n);
- spin_unlock(&kvm->lock);
+ /* If nothing is dirty, don't bother messing with page tables. */
+ if (any) {
+ kvm_mmu_slot_remove_write_access(kvm, log->slot);
+ kvm_flush_remote_tlbs(kvm);
+ memset(memslot->dirty_bitmap, 0, n);
+ }
r = 0;
out:
- spin_lock(&kvm->lock);
- --kvm->busy;
- spin_unlock(&kvm->lock);
+ mutex_unlock(&kvm->lock);
return r;
}
@@ -862,7 +832,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
< alias->target_phys_addr)
goto out;
- spin_lock(&kvm->lock);
+ mutex_lock(&kvm->lock);
p = &kvm->aliases[alias->slot];
p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
@@ -876,7 +846,7 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
kvm_mmu_zap_all(kvm);
- spin_unlock(&kvm->lock);
+ mutex_unlock(&kvm->lock);
return 0;
@@ -884,6 +854,63 @@ out:
return r;
}
+static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
+{
+ int r;
+
+ r = 0;
+ switch (chip->chip_id) {
+ case KVM_IRQCHIP_PIC_MASTER:
+ memcpy (&chip->chip.pic,
+ &pic_irqchip(kvm)->pics[0],
+ sizeof(struct kvm_pic_state));
+ break;
+ case KVM_IRQCHIP_PIC_SLAVE:
+ memcpy (&chip->chip.pic,
+ &pic_irqchip(kvm)->pics[1],
+ sizeof(struct kvm_pic_state));
+ break;
+ case KVM_IRQCHIP_IOAPIC:
+ memcpy (&chip->chip.ioapic,
+ ioapic_irqchip(kvm),
+ sizeof(struct kvm_ioapic_state));
+ break;
+ default:
+ r = -EINVAL;
+ break;
+ }
+ return r;
+}
+
+static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip)
+{
+ int r;
+
+ r = 0;
+ switch (chip->chip_id) {
+ case KVM_IRQCHIP_PIC_MASTER:
+ memcpy (&pic_irqchip(kvm)->pics[0],
+ &chip->chip.pic,
+ sizeof(struct kvm_pic_state));
+ break;
+ case KVM_IRQCHIP_PIC_SLAVE:
+ memcpy (&pic_irqchip(kvm)->pics[1],
+ &chip->chip.pic,
+ sizeof(struct kvm_pic_state));
+ break;
+ case KVM_IRQCHIP_IOAPIC:
+ memcpy (ioapic_irqchip(kvm),
+ &chip->chip.ioapic,
+ sizeof(struct kvm_ioapic_state));
+ break;
+ default:
+ r = -EINVAL;
+ break;
+ }
+ kvm_pic_update_irq(pic_irqchip(kvm));
+ return r;
+}
+
static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
{
int i;
@@ -930,37 +957,26 @@ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
}
EXPORT_SYMBOL_GPL(gfn_to_page);
+/* WARNING: Does not work on aliased pages. */
void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
{
- int i;
struct kvm_memory_slot *memslot;
- unsigned long rel_gfn;
-
- for (i = 0; i < kvm->nmemslots; ++i) {
- memslot = &kvm->memslots[i];
-
- if (gfn >= memslot->base_gfn
- && gfn < memslot->base_gfn + memslot->npages) {
- if (!memslot->dirty_bitmap)
- return;
+ memslot = __gfn_to_memslot(kvm, gfn);
+ if (memslot && memslot->dirty_bitmap) {
+ unsigned long rel_gfn = gfn - memslot->base_gfn;
- rel_gfn = gfn - memslot->base_gfn;
-
- /* avoid RMW */
- if (!test_bit(rel_gfn, memslot->dirty_bitmap))
- set_bit(rel_gfn, memslot->dirty_bitmap);
- return;
- }
+ /* avoid RMW */
+ if (!test_bit(rel_gfn, memslot->dirty_bitmap))
+ set_bit(rel_gfn, memslot->dirty_bitmap);
}
}
-static int emulator_read_std(unsigned long addr,
+int emulator_read_std(unsigned long addr,
void *val,
unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
+ struct kvm_vcpu *vcpu)
{
- struct kvm_vcpu *vcpu = ctxt->vcpu;
void *data = val;
while (bytes) {
@@ -990,26 +1006,42 @@ static int emulator_read_std(unsigned long addr,
return X86EMUL_CONTINUE;
}
+EXPORT_SYMBOL_GPL(emulator_read_std);
static int emulator_write_std(unsigned long addr,
const void *val,
unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
+ struct kvm_vcpu *vcpu)
{
- printk(KERN_ERR "emulator_write_std: addr %lx n %d\n",
- addr, bytes);
+ pr_unimpl(vcpu, "emulator_write_std: addr %lx n %d\n", addr, bytes);
return X86EMUL_UNHANDLEABLE;
}
+/*
+ * Only apic need an MMIO device hook, so shortcut now..
+ */
+static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu,
+ gpa_t addr)
+{
+ struct kvm_io_device *dev;
+
+ if (vcpu->apic) {
+ dev = &vcpu->apic->dev;
+ if (dev->in_range(dev, addr))
+ return dev;
+ }
+ return NULL;
+}
+
static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
gpa_t addr)
{
- /*
- * Note that its important to have this wrapper function because
- * in the very near future we will be checking for MMIOs against
- * the LAPIC as well as the general MMIO bus
- */
- return kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
+ struct kvm_io_device *dev;
+
+ dev = vcpu_find_pervcpu_dev(vcpu, addr);
+ if (dev == NULL)
+ dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
+ return dev;
}
static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
@@ -1021,9 +1053,8 @@ static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
static int emulator_read_emulated(unsigned long addr,
void *val,
unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
+ struct kvm_vcpu *vcpu)
{
- struct kvm_vcpu *vcpu = ctxt->vcpu;
struct kvm_io_device *mmio_dev;
gpa_t gpa;
@@ -1031,7 +1062,7 @@ static int emulator_read_emulated(unsigned long addr,
memcpy(val, vcpu->mmio_data, bytes);
vcpu->mmio_read_completed = 0;
return X86EMUL_CONTINUE;
- } else if (emulator_read_std(addr, val, bytes, ctxt)
+ } else if (emulator_read_std(addr, val, bytes, vcpu)
== X86EMUL_CONTINUE)
return X86EMUL_CONTINUE;
@@ -1061,7 +1092,6 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
{
struct page *page;
void *virt;
- unsigned offset = offset_in_page(gpa);
if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT))
return 0;
@@ -1070,7 +1100,7 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
return 0;
mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
virt = kmap_atomic(page, KM_USER0);
- kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes);
+ kvm_mmu_pte_write(vcpu, gpa, val, bytes);
memcpy(virt + offset_in_page(gpa), val, bytes);
kunmap_atomic(virt, KM_USER0);
return 1;
@@ -1079,14 +1109,13 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
static int emulator_write_emulated_onepage(unsigned long addr,
const void *val,
unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
+ struct kvm_vcpu *vcpu)
{
- struct kvm_vcpu *vcpu = ctxt->vcpu;
struct kvm_io_device *mmio_dev;
gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
if (gpa == UNMAPPED_GVA) {
- kvm_arch_ops->inject_page_fault(vcpu, addr, 2);
+ kvm_x86_ops->inject_page_fault(vcpu, addr, 2);
return X86EMUL_PROPAGATE_FAULT;
}
@@ -1111,31 +1140,32 @@ static int emulator_write_emulated_onepage(unsigned long addr,
return X86EMUL_CONTINUE;
}
-static int emulator_write_emulated(unsigned long addr,
+int emulator_write_emulated(unsigned long addr,
const void *val,
unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
+ struct kvm_vcpu *vcpu)
{
/* Crossing a page boundary? */
if (((addr + bytes - 1) ^ addr) & PAGE_MASK) {
int rc, now;
now = -addr & ~PAGE_MASK;
- rc = emulator_write_emulated_onepage(addr, val, now, ctxt);
+ rc = emulator_write_emulated_onepage(addr, val, now, vcpu);
if (rc != X86EMUL_CONTINUE)
return rc;
addr += now;
val += now;
bytes -= now;
}
- return emulator_write_emulated_onepage(addr, val, bytes, ctxt);
+ return emulator_write_emulated_onepage(addr, val, bytes, vcpu);
}
+EXPORT_SYMBOL_GPL(emulator_write_emulated);
static int emulator_cmpxchg_emulated(unsigned long addr,
const void *old,
const void *new,
unsigned int bytes,
- struct x86_emulate_ctxt *ctxt)
+ struct kvm_vcpu *vcpu)
{
static int reported;
@@ -1143,12 +1173,12 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
reported = 1;
printk(KERN_WARNING "kvm: emulating exchange as write\n");
}
- return emulator_write_emulated(addr, new, bytes, ctxt);
+ return emulator_write_emulated(addr, new, bytes, vcpu);
}
static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
{
- return kvm_arch_ops->get_segment_base(vcpu, seg);
+ return kvm_x86_ops->get_segment_base(vcpu, seg);
}
int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
@@ -1158,10 +1188,8 @@ int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
int emulate_clts(struct kvm_vcpu *vcpu)
{
- unsigned long cr0;
-
- cr0 = vcpu->cr0 & ~CR0_TS_MASK;
- kvm_arch_ops->set_cr0(vcpu, cr0);
+ vcpu->cr0 &= ~X86_CR0_TS;
+ kvm_x86_ops->set_cr0(vcpu, vcpu->cr0);
return X86EMUL_CONTINUE;
}
@@ -1171,11 +1199,10 @@ int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, unsigned long *dest)
switch (dr) {
case 0 ... 3:
- *dest = kvm_arch_ops->get_dr(vcpu, dr);
+ *dest = kvm_x86_ops->get_dr(vcpu, dr);
return X86EMUL_CONTINUE;
default:
- printk(KERN_DEBUG "%s: unexpected dr %u\n",
- __FUNCTION__, dr);
+ pr_unimpl(vcpu, "%s: unexpected dr %u\n", __FUNCTION__, dr);
return X86EMUL_UNHANDLEABLE;
}
}
@@ -1185,7 +1212,7 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U;
int exception;
- kvm_arch_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception);
+ kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception);
if (exception) {
/* FIXME: better handling */
return X86EMUL_UNHANDLEABLE;
@@ -1193,25 +1220,25 @@ int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
return X86EMUL_CONTINUE;
}
-static void report_emulation_failure(struct x86_emulate_ctxt *ctxt)
+void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)
{
static int reported;
u8 opcodes[4];
- unsigned long rip = ctxt->vcpu->rip;
+ unsigned long rip = vcpu->rip;
unsigned long rip_linear;
- rip_linear = rip + get_segment_base(ctxt->vcpu, VCPU_SREG_CS);
+ rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS);
if (reported)
return;
- emulator_read_std(rip_linear, (void *)opcodes, 4, ctxt);
+ emulator_read_std(rip_linear, (void *)opcodes, 4, vcpu);
- printk(KERN_ERR "emulation failed but !mmio_needed?"
- " rip %lx %02x %02x %02x %02x\n",
- rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
+ printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n",
+ context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]);
reported = 1;
}
+EXPORT_SYMBOL_GPL(kvm_report_emulation_failure);
struct x86_emulate_ops emulate_ops = {
.read_std = emulator_read_std,
@@ -1231,12 +1258,12 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
int cs_db, cs_l;
vcpu->mmio_fault_cr2 = cr2;
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
- kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
+ kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
emulate_ctxt.vcpu = vcpu;
- emulate_ctxt.eflags = kvm_arch_ops->get_rflags(vcpu);
+ emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
emulate_ctxt.cr2 = cr2;
emulate_ctxt.mode = (emulate_ctxt.eflags & X86_EFLAGS_VM)
? X86EMUL_MODE_REAL : cs_l
@@ -1259,9 +1286,13 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
emulate_ctxt.fs_base = get_segment_base(vcpu, VCPU_SREG_FS);
vcpu->mmio_is_write = 0;
+ vcpu->pio.string = 0;
r = x86_emulate_memop(&emulate_ctxt, &emulate_ops);
+ if (vcpu->pio.string)
+ return EMULATE_DO_MMIO;
if ((r || vcpu->mmio_is_write) && run) {
+ run->exit_reason = KVM_EXIT_MMIO;
run->mmio.phys_addr = vcpu->mmio_phys_addr;
memcpy(run->mmio.data, vcpu->mmio_data, 8);
run->mmio.len = vcpu->mmio_size;
@@ -1272,14 +1303,14 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
if (kvm_mmu_unprotect_page_virt(vcpu, cr2))
return EMULATE_DONE;
if (!vcpu->mmio_needed) {
- report_emulation_failure(&emulate_ctxt);
+ kvm_report_emulation_failure(vcpu, "mmio");
return EMULATE_FAIL;
}
return EMULATE_DO_MMIO;
}
- kvm_arch_ops->decache_regs(vcpu);
- kvm_arch_ops->set_rflags(vcpu, emulate_ctxt.eflags);
+ kvm_x86_ops->decache_regs(vcpu);
+ kvm_x86_ops->set_rflags(vcpu, emulate_ctxt.eflags);
if (vcpu->mmio_is_write) {
vcpu->mmio_needed = 0;
@@ -1290,14 +1321,45 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
}
EXPORT_SYMBOL_GPL(emulate_instruction);
-int kvm_emulate_halt(struct kvm_vcpu *vcpu)
+/*
+ * The vCPU has executed a HLT instruction with in-kernel mode enabled.
+ */
+static void kvm_vcpu_block(struct kvm_vcpu *vcpu)
{
- if (vcpu->irq_summary)
- return 1;
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(&vcpu->wq, &wait);
- vcpu->run->exit_reason = KVM_EXIT_HLT;
+ /*
+ * We will block until either an interrupt or a signal wakes us up
+ */
+ while (!kvm_cpu_has_interrupt(vcpu)
+ && !signal_pending(current)
+ && vcpu->mp_state != VCPU_MP_STATE_RUNNABLE
+ && vcpu->mp_state != VCPU_MP_STATE_SIPI_RECEIVED) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ vcpu_put(vcpu);
+ schedule();
+ vcpu_load(vcpu);
+ }
+
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&vcpu->wq, &wait);
+}
+
+int kvm_emulate_halt(struct kvm_vcpu *vcpu)
+{
++vcpu->stat.halt_exits;
- return 0;
+ if (irqchip_in_kernel(vcpu->kvm)) {
+ vcpu->mp_state = VCPU_MP_STATE_HALTED;
+ kvm_vcpu_block(vcpu);
+ if (vcpu->mp_state != VCPU_MP_STATE_RUNNABLE)
+ return -EINTR;
+ return 1;
+ } else {
+ vcpu->run->exit_reason = KVM_EXIT_HLT;
+ return 0;
+ }
}
EXPORT_SYMBOL_GPL(kvm_emulate_halt);
@@ -1305,7 +1367,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
unsigned long nr, a0, a1, a2, a3, a4, a5, ret;
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
ret = -KVM_EINVAL;
#ifdef CONFIG_X86_64
if (is_long_mode(vcpu)) {
@@ -1329,6 +1391,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
}
switch (nr) {
default:
+ run->hypercall.nr = nr;
run->hypercall.args[0] = a0;
run->hypercall.args[1] = a1;
run->hypercall.args[2] = a2;
@@ -1337,11 +1400,11 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
run->hypercall.args[5] = a5;
run->hypercall.ret = ret;
run->hypercall.longmode = is_long_mode(vcpu);
- kvm_arch_ops->decache_regs(vcpu);
+ kvm_x86_ops->decache_regs(vcpu);
return 0;
}
vcpu->regs[VCPU_REGS_RAX] = ret;
- kvm_arch_ops->decache_regs(vcpu);
+ kvm_x86_ops->decache_regs(vcpu);
return 1;
}
EXPORT_SYMBOL_GPL(kvm_hypercall);
@@ -1355,26 +1418,26 @@ void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
{
struct descriptor_table dt = { limit, base };
- kvm_arch_ops->set_gdt(vcpu, &dt);
+ kvm_x86_ops->set_gdt(vcpu, &dt);
}
void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
{
struct descriptor_table dt = { limit, base };
- kvm_arch_ops->set_idt(vcpu, &dt);
+ kvm_x86_ops->set_idt(vcpu, &dt);
}
void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
unsigned long *rflags)
{
lmsw(vcpu, msw);
- *rflags = kvm_arch_ops->get_rflags(vcpu);
+ *rflags = kvm_x86_ops->get_rflags(vcpu);
}
unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
{
- kvm_arch_ops->decache_cr4_guest_bits(vcpu);
+ kvm_x86_ops->decache_cr4_guest_bits(vcpu);
switch (cr) {
case 0:
return vcpu->cr0;
@@ -1396,7 +1459,7 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
switch (cr) {
case 0:
set_cr0(vcpu, mk_cr_64(vcpu->cr0, val));
- *rflags = kvm_arch_ops->get_rflags(vcpu);
+ *rflags = kvm_x86_ops->get_rflags(vcpu);
break;
case 2:
vcpu->cr2 = val;
@@ -1439,7 +1502,7 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa)
mark_page_dirty(vcpu->kvm, para_state_gpa >> PAGE_SHIFT);
para_state_page = pfn_to_page(para_state_hpa >> PAGE_SHIFT);
- para_state = kmap_atomic(para_state_page, KM_USER0);
+ para_state = kmap(para_state_page);
printk(KERN_DEBUG ".... guest version: %d\n", para_state->guest_version);
printk(KERN_DEBUG ".... size: %d\n", para_state->size);
@@ -1470,12 +1533,12 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa)
mark_page_dirty(vcpu->kvm, hypercall_gpa >> PAGE_SHIFT);
hypercall = kmap_atomic(pfn_to_page(hypercall_hpa >> PAGE_SHIFT),
KM_USER1) + (hypercall_hpa & ~PAGE_MASK);
- kvm_arch_ops->patch_hypercall(vcpu, hypercall);
+ kvm_x86_ops->patch_hypercall(vcpu, hypercall);
kunmap_atomic(hypercall, KM_USER1);
para_state->ret = 0;
err_kunmap_skip:
- kunmap_atomic(para_state, KM_USER0);
+ kunmap(para_state_page);
return 0;
err_gp:
return 1;
@@ -1511,7 +1574,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
data = 3;
break;
case MSR_IA32_APICBASE:
- data = vcpu->apic_base;
+ data = kvm_get_apic_base(vcpu);
break;
case MSR_IA32_MISC_ENABLE:
data = vcpu->ia32_misc_enable_msr;
@@ -1522,7 +1585,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
break;
#endif
default:
- printk(KERN_ERR "kvm: unhandled rdmsr: 0x%x\n", msr);
+ pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr);
return 1;
}
*pdata = data;
@@ -1537,7 +1600,7 @@ EXPORT_SYMBOL_GPL(kvm_get_msr_common);
*/
int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
{
- return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
+ return kvm_x86_ops->get_msr(vcpu, msr_index, pdata);
}
#ifdef CONFIG_X86_64
@@ -1558,7 +1621,7 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
return;
}
- kvm_arch_ops->set_efer(vcpu, efer);
+ kvm_x86_ops->set_efer(vcpu, efer);
efer &= ~EFER_LMA;
efer |= vcpu->shadow_efer & EFER_LMA;
@@ -1577,11 +1640,11 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
break;
#endif
case MSR_IA32_MC0_STATUS:
- printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n",
+ pr_unimpl(vcpu, "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n",
__FUNCTION__, data);
break;
case MSR_IA32_MCG_STATUS:
- printk(KERN_WARNING "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n",
+ pr_unimpl(vcpu, "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n",
__FUNCTION__, data);
break;
case MSR_IA32_UCODE_REV:
@@ -1589,7 +1652,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
case 0x200 ... 0x2ff: /* MTRRs */
break;
case MSR_IA32_APICBASE:
- vcpu->apic_base = data;
+ kvm_set_apic_base(vcpu, data);
break;
case MSR_IA32_MISC_ENABLE:
vcpu->ia32_misc_enable_msr = data;
@@ -1601,7 +1664,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
return vcpu_register_para(vcpu, data);
default:
- printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr);
+ pr_unimpl(vcpu, "unhandled wrmsr: 0x%x\n", msr);
return 1;
}
return 0;
@@ -1615,44 +1678,24 @@ EXPORT_SYMBOL_GPL(kvm_set_msr_common);
*/
int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
{
- return kvm_arch_ops->set_msr(vcpu, msr_index, data);
+ return kvm_x86_ops->set_msr(vcpu, msr_index, data);
}
void kvm_resched(struct kvm_vcpu *vcpu)
{
if (!need_resched())
return;
- vcpu_put(vcpu);
cond_resched();
- vcpu_load(vcpu);
}
EXPORT_SYMBOL_GPL(kvm_resched);
-void load_msrs(struct vmx_msr_entry *e, int n)
-{
- int i;
-
- for (i = 0; i < n; ++i)
- wrmsrl(e[i].index, e[i].data);
-}
-EXPORT_SYMBOL_GPL(load_msrs);
-
-void save_msrs(struct vmx_msr_entry *e, int n)
-{
- int i;
-
- for (i = 0; i < n; ++i)
- rdmsrl(e[i].index, e[i].data);
-}
-EXPORT_SYMBOL_GPL(save_msrs);
-
void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
{
int i;
u32 function;
struct kvm_cpuid_entry *e, *best;
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
function = vcpu->regs[VCPU_REGS_RAX];
vcpu->regs[VCPU_REGS_RAX] = 0;
vcpu->regs[VCPU_REGS_RBX] = 0;
@@ -1678,8 +1721,8 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
vcpu->regs[VCPU_REGS_RCX] = best->ecx;
vcpu->regs[VCPU_REGS_RDX] = best->edx;
}
- kvm_arch_ops->decache_regs(vcpu);
- kvm_arch_ops->skip_emulated_instruction(vcpu);
+ kvm_x86_ops->decache_regs(vcpu);
+ kvm_x86_ops->skip_emulated_instruction(vcpu);
}
EXPORT_SYMBOL_GPL(kvm_emulate_cpuid);
@@ -1690,11 +1733,9 @@ static int pio_copy_data(struct kvm_vcpu *vcpu)
unsigned bytes;
int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1;
- kvm_arch_ops->vcpu_put(vcpu);
q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE,
PAGE_KERNEL);
if (!q) {
- kvm_arch_ops->vcpu_load(vcpu);
free_pio_guest_pages(vcpu);
return -ENOMEM;
}
@@ -1706,7 +1747,6 @@ static int pio_copy_data(struct kvm_vcpu *vcpu)
memcpy(p, q, bytes);
q -= vcpu->pio.guest_page_offset;
vunmap(q);
- kvm_arch_ops->vcpu_load(vcpu);
free_pio_guest_pages(vcpu);
return 0;
}
@@ -1717,7 +1757,7 @@ static int complete_pio(struct kvm_vcpu *vcpu)
long delta;
int r;
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
if (!io->string) {
if (io->in)
@@ -1727,7 +1767,7 @@ static int complete_pio(struct kvm_vcpu *vcpu)
if (io->in) {
r = pio_copy_data(vcpu);
if (r) {
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
return r;
}
}
@@ -1750,79 +1790,109 @@ static int complete_pio(struct kvm_vcpu *vcpu)
vcpu->regs[VCPU_REGS_RSI] += delta;
}
- kvm_arch_ops->decache_regs(vcpu);
+ kvm_x86_ops->decache_regs(vcpu);
io->count -= io->cur_count;
io->cur_count = 0;
- if (!io->count)
- kvm_arch_ops->skip_emulated_instruction(vcpu);
return 0;
}
-void kernel_pio(struct kvm_io_device *pio_dev, struct kvm_vcpu *vcpu)
+static void kernel_pio(struct kvm_io_device *pio_dev,
+ struct kvm_vcpu *vcpu,
+ void *pd)
{
/* TODO: String I/O for in kernel device */
+ mutex_lock(&vcpu->kvm->lock);
if (vcpu->pio.in)
kvm_iodevice_read(pio_dev, vcpu->pio.port,
vcpu->pio.size,
- vcpu->pio_data);
+ pd);
else
kvm_iodevice_write(pio_dev, vcpu->pio.port,
vcpu->pio.size,
- vcpu->pio_data);
+ pd);
+ mutex_unlock(&vcpu->kvm->lock);
+}
+
+static void pio_string_write(struct kvm_io_device *pio_dev,
+ struct kvm_vcpu *vcpu)
+{
+ struct kvm_pio_request *io = &vcpu->pio;
+ void *pd = vcpu->pio_data;
+ int i;
+
+ mutex_lock(&vcpu->kvm->lock);
+ for (i = 0; i < io->cur_count; i++) {
+ kvm_iodevice_write(pio_dev, io->port,
+ io->size,
+ pd);
+ pd += io->size;
+ }
+ mutex_unlock(&vcpu->kvm->lock);
}
-int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
- int size, unsigned long count, int string, int down,
+int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+ int size, unsigned port)
+{
+ struct kvm_io_device *pio_dev;
+
+ vcpu->run->exit_reason = KVM_EXIT_IO;
+ vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
+ vcpu->run->io.size = vcpu->pio.size = size;
+ vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
+ vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = 1;
+ vcpu->run->io.port = vcpu->pio.port = port;
+ vcpu->pio.in = in;
+ vcpu->pio.string = 0;
+ vcpu->pio.down = 0;
+ vcpu->pio.guest_page_offset = 0;
+ vcpu->pio.rep = 0;
+
+ kvm_x86_ops->cache_regs(vcpu);
+ memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
+ kvm_x86_ops->decache_regs(vcpu);
+
+ kvm_x86_ops->skip_emulated_instruction(vcpu);
+
+ pio_dev = vcpu_find_pio_dev(vcpu, port);
+ if (pio_dev) {
+ kernel_pio(pio_dev, vcpu, vcpu->pio_data);
+ complete_pio(vcpu);
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_emulate_pio);
+
+int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+ int size, unsigned long count, int down,
gva_t address, int rep, unsigned port)
{
unsigned now, in_page;
- int i;
+ int i, ret = 0;
int nr_pages = 1;
struct page *page;
struct kvm_io_device *pio_dev;
vcpu->run->exit_reason = KVM_EXIT_IO;
vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
- vcpu->run->io.size = size;
+ vcpu->run->io.size = vcpu->pio.size = size;
vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
- vcpu->run->io.count = count;
- vcpu->run->io.port = port;
- vcpu->pio.count = count;
- vcpu->pio.cur_count = count;
- vcpu->pio.size = size;
+ vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = count;
+ vcpu->run->io.port = vcpu->pio.port = port;
vcpu->pio.in = in;
- vcpu->pio.port = port;
- vcpu->pio.string = string;
+ vcpu->pio.string = 1;
vcpu->pio.down = down;
vcpu->pio.guest_page_offset = offset_in_page(address);
vcpu->pio.rep = rep;
- pio_dev = vcpu_find_pio_dev(vcpu, port);
- if (!string) {
- kvm_arch_ops->cache_regs(vcpu);
- memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
- kvm_arch_ops->decache_regs(vcpu);
- if (pio_dev) {
- kernel_pio(pio_dev, vcpu);
- complete_pio(vcpu);
- return 1;
- }
- return 0;
- }
- /* TODO: String I/O for in kernel device */
- if (pio_dev)
- printk(KERN_ERR "kvm_setup_pio: no string io support\n");
-
if (!count) {
- kvm_arch_ops->skip_emulated_instruction(vcpu);
+ kvm_x86_ops->skip_emulated_instruction(vcpu);
return 1;
}
- now = min(count, PAGE_SIZE / size);
-
if (!down)
in_page = PAGE_SIZE - offset_in_page(address);
else
@@ -1841,20 +1911,23 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
/*
* String I/O in reverse. Yuck. Kill the guest, fix later.
*/
- printk(KERN_ERR "kvm: guest string pio down\n");
+ pr_unimpl(vcpu, "guest string pio down\n");
inject_gp(vcpu);
return 1;
}
vcpu->run->io.count = now;
vcpu->pio.cur_count = now;
+ if (vcpu->pio.cur_count == vcpu->pio.count)
+ kvm_x86_ops->skip_emulated_instruction(vcpu);
+
for (i = 0; i < nr_pages; ++i) {
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
page = gva_to_page(vcpu, address + i * PAGE_SIZE);
if (page)
get_page(page);
vcpu->pio.guest_pages[i] = page;
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
if (!page) {
inject_gp(vcpu);
free_pio_guest_pages(vcpu);
@@ -1862,11 +1935,156 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
}
}
- if (!vcpu->pio.in)
- return pio_copy_data(vcpu);
- return 0;
+ pio_dev = vcpu_find_pio_dev(vcpu, port);
+ if (!vcpu->pio.in) {
+ /* string PIO write */
+ ret = pio_copy_data(vcpu);
+ if (ret >= 0 && pio_dev) {
+ pio_string_write(pio_dev, vcpu);
+ complete_pio(vcpu);
+ if (vcpu->pio.count == 0)
+ ret = 1;
+ }
+ } else if (pio_dev)
+ pr_unimpl(vcpu, "no string pio read support yet, "
+ "port %x size %d count %ld\n",
+ port, size, count);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(kvm_emulate_pio_string);
+
+/*
+ * Check if userspace requested an interrupt window, and that the
+ * interrupt window is open.
+ *
+ * No need to exit to userspace if we already have an interrupt queued.
+ */
+static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ return (!vcpu->irq_summary &&
+ kvm_run->request_interrupt_window &&
+ vcpu->interrupt_window_open &&
+ (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF));
+}
+
+static void post_kvm_run_save(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
+{
+ kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0;
+ kvm_run->cr8 = get_cr8(vcpu);
+ kvm_run->apic_base = kvm_get_apic_base(vcpu);
+ if (irqchip_in_kernel(vcpu->kvm))
+ kvm_run->ready_for_interrupt_injection = 1;
+ else
+ kvm_run->ready_for_interrupt_injection =
+ (vcpu->interrupt_window_open &&
+ vcpu->irq_summary == 0);
+}
+
+static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ int r;
+
+ if (unlikely(vcpu->mp_state == VCPU_MP_STATE_SIPI_RECEIVED)) {
+ printk("vcpu %d received sipi with vector # %x\n",
+ vcpu->vcpu_id, vcpu->sipi_vector);
+ kvm_lapic_reset(vcpu);
+ kvm_x86_ops->vcpu_reset(vcpu);
+ vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+ }
+
+preempted:
+ if (vcpu->guest_debug.enabled)
+ kvm_x86_ops->guest_debug_pre(vcpu);
+
+again:
+ r = kvm_mmu_reload(vcpu);
+ if (unlikely(r))
+ goto out;
+
+ preempt_disable();
+
+ kvm_x86_ops->prepare_guest_switch(vcpu);
+ kvm_load_guest_fpu(vcpu);
+
+ local_irq_disable();
+
+ if (signal_pending(current)) {
+ local_irq_enable();
+ preempt_enable();
+ r = -EINTR;
+ kvm_run->exit_reason = KVM_EXIT_INTR;
+ ++vcpu->stat.signal_exits;
+ goto out;
+ }
+
+ if (irqchip_in_kernel(vcpu->kvm))
+ kvm_x86_ops->inject_pending_irq(vcpu);
+ else if (!vcpu->mmio_read_completed)
+ kvm_x86_ops->inject_pending_vectors(vcpu, kvm_run);
+
+ vcpu->guest_mode = 1;
+ kvm_guest_enter();
+
+ if (vcpu->requests)
+ if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
+ kvm_x86_ops->tlb_flush(vcpu);
+
+ kvm_x86_ops->run(vcpu, kvm_run);
+
+ vcpu->guest_mode = 0;
+ local_irq_enable();
+
+ ++vcpu->stat.exits;
+
+ /*
+ * We must have an instruction between local_irq_enable() and
+ * kvm_guest_exit(), so the timer interrupt isn't delayed by
+ * the interrupt shadow. The stat.exits increment will do nicely.
+ * But we need to prevent reordering, hence this barrier():
+ */
+ barrier();
+
+ kvm_guest_exit();
+
+ preempt_enable();
+
+ /*
+ * Profile KVM exit RIPs:
+ */
+ if (unlikely(prof_on == KVM_PROFILING)) {
+ kvm_x86_ops->cache_regs(vcpu);
+ profile_hit(KVM_PROFILING, (void *)vcpu->rip);
+ }
+
+ r = kvm_x86_ops->handle_exit(kvm_run, vcpu);
+
+ if (r > 0) {
+ if (dm_request_for_irq_injection(vcpu, kvm_run)) {
+ r = -EINTR;
+ kvm_run->exit_reason = KVM_EXIT_INTR;
+ ++vcpu->stat.request_irq_exits;
+ goto out;
+ }
+ if (!need_resched()) {
+ ++vcpu->stat.light_exits;
+ goto again;
+ }
+ }
+
+out:
+ if (r > 0) {
+ kvm_resched(vcpu);
+ goto preempted;
+ }
+
+ post_kvm_run_save(vcpu, kvm_run);
+
+ return r;
}
-EXPORT_SYMBOL_GPL(kvm_setup_pio);
+
static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
@@ -1875,11 +2093,18 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vcpu_load(vcpu);
+ if (unlikely(vcpu->mp_state == VCPU_MP_STATE_UNINITIALIZED)) {
+ kvm_vcpu_block(vcpu);
+ vcpu_put(vcpu);
+ return -EAGAIN;
+ }
+
if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
/* re-sync apic's tpr */
- vcpu->cr8 = kvm_run->cr8;
+ if (!irqchip_in_kernel(vcpu->kvm))
+ set_cr8(vcpu, kvm_run->cr8);
if (vcpu->pio.cur_count) {
r = complete_pio(vcpu);
@@ -1897,19 +2122,18 @@ static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
/*
* Read-modify-write. Back to userspace.
*/
- kvm_run->exit_reason = KVM_EXIT_MMIO;
r = 0;
goto out;
}
}
if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL) {
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
vcpu->regs[VCPU_REGS_RAX] = kvm_run->hypercall.ret;
- kvm_arch_ops->decache_regs(vcpu);
+ kvm_x86_ops->decache_regs(vcpu);
}
- r = kvm_arch_ops->run(vcpu, kvm_run);
+ r = __vcpu_run(vcpu, kvm_run);
out:
if (vcpu->sigset_active)
@@ -1924,7 +2148,7 @@ static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu,
{
vcpu_load(vcpu);
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_x86_ops->cache_regs(vcpu);
regs->rax = vcpu->regs[VCPU_REGS_RAX];
regs->rbx = vcpu->regs[VCPU_REGS_RBX];
@@ -1946,7 +2170,7 @@ static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu,
#endif
regs->rip = vcpu->rip;
- regs->rflags = kvm_arch_ops->get_rflags(vcpu);
+ regs->rflags = kvm_x86_ops->get_rflags(vcpu);
/*
* Don't leak debug flags in case they were set for guest debugging
@@ -1984,9 +2208,9 @@ static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu,
#endif
vcpu->rip = regs->rip;
- kvm_arch_ops->set_rflags(vcpu, regs->rflags);
+ kvm_x86_ops->set_rflags(vcpu, regs->rflags);
- kvm_arch_ops->decache_regs(vcpu);
+ kvm_x86_ops->decache_regs(vcpu);
vcpu_put(vcpu);
@@ -1996,13 +2220,14 @@ static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu,
static void get_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg)
{
- return kvm_arch_ops->get_segment(vcpu, var, seg);
+ return kvm_x86_ops->get_segment(vcpu, var, seg);
}
static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
struct descriptor_table dt;
+ int pending_vec;
vcpu_load(vcpu);
@@ -2016,24 +2241,31 @@ static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
get_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
- kvm_arch_ops->get_idt(vcpu, &dt);
+ kvm_x86_ops->get_idt(vcpu, &dt);
sregs->idt.limit = dt.limit;
sregs->idt.base = dt.base;
- kvm_arch_ops->get_gdt(vcpu, &dt);
+ kvm_x86_ops->get_gdt(vcpu, &dt);
sregs->gdt.limit = dt.limit;
sregs->gdt.base = dt.base;
- kvm_arch_ops->decache_cr4_guest_bits(vcpu);
+ kvm_x86_ops->decache_cr4_guest_bits(vcpu);
sregs->cr0 = vcpu->cr0;
sregs->cr2 = vcpu->cr2;
sregs->cr3 = vcpu->cr3;
sregs->cr4 = vcpu->cr4;
- sregs->cr8 = vcpu->cr8;
+ sregs->cr8 = get_cr8(vcpu);
sregs->efer = vcpu->shadow_efer;
- sregs->apic_base = vcpu->apic_base;
-
- memcpy(sregs->interrupt_bitmap, vcpu->irq_pending,
- sizeof sregs->interrupt_bitmap);
+ sregs->apic_base = kvm_get_apic_base(vcpu);
+
+ if (irqchip_in_kernel(vcpu->kvm)) {
+ memset(sregs->interrupt_bitmap, 0,
+ sizeof sregs->interrupt_bitmap);
+ pending_vec = kvm_x86_ops->get_irq(vcpu);
+ if (pending_vec >= 0)
+ set_bit(pending_vec, (unsigned long *)sregs->interrupt_bitmap);
+ } else
+ memcpy(sregs->interrupt_bitmap, vcpu->irq_pending,
+ sizeof sregs->interrupt_bitmap);
vcpu_put(vcpu);
@@ -2043,56 +2275,69 @@ static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
static void set_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg)
{
- return kvm_arch_ops->set_segment(vcpu, var, seg);
+ return kvm_x86_ops->set_segment(vcpu, var, seg);
}
static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
int mmu_reset_needed = 0;
- int i;
+ int i, pending_vec, max_bits;
struct descriptor_table dt;
vcpu_load(vcpu);
dt.limit = sregs->idt.limit;
dt.base = sregs->idt.base;
- kvm_arch_ops->set_idt(vcpu, &dt);
+ kvm_x86_ops->set_idt(vcpu, &dt);
dt.limit = sregs->gdt.limit;
dt.base = sregs->gdt.base;
- kvm_arch_ops->set_gdt(vcpu, &dt);
+ kvm_x86_ops->set_gdt(vcpu, &dt);
vcpu->cr2 = sregs->cr2;
mmu_reset_needed |= vcpu->cr3 != sregs->cr3;
vcpu->cr3 = sregs->cr3;
- vcpu->cr8 = sregs->cr8;
+ set_cr8(vcpu, sregs->cr8);
mmu_reset_needed |= vcpu->shadow_efer != sregs->efer;
#ifdef CONFIG_X86_64
- kvm_arch_ops->set_efer(vcpu, sregs->efer);
+ kvm_x86_ops->set_efer(vcpu, sregs->efer);
#endif
- vcpu->apic_base = sregs->apic_base;
+ kvm_set_apic_base(vcpu, sregs->apic_base);
- kvm_arch_ops->decache_cr4_guest_bits(vcpu);
+ kvm_x86_ops->decache_cr4_guest_bits(vcpu);
mmu_reset_needed |= vcpu->cr0 != sregs->cr0;
- kvm_arch_ops->set_cr0(vcpu, sregs->cr0);
+ vcpu->cr0 = sregs->cr0;
+ kvm_x86_ops->set_cr0(vcpu, sregs->cr0);
mmu_reset_needed |= vcpu->cr4 != sregs->cr4;
- kvm_arch_ops->set_cr4(vcpu, sregs->cr4);
+ kvm_x86_ops->set_cr4(vcpu, sregs->cr4);
if (!is_long_mode(vcpu) && is_pae(vcpu))
load_pdptrs(vcpu, vcpu->cr3);
if (mmu_reset_needed)
kvm_mmu_reset_context(vcpu);
- memcpy(vcpu->irq_pending, sregs->interrupt_bitmap,
- sizeof vcpu->irq_pending);
- vcpu->irq_summary = 0;
- for (i = 0; i < NR_IRQ_WORDS; ++i)
- if (vcpu->irq_pending[i])
- __set_bit(i, &vcpu->irq_summary);
+ if (!irqchip_in_kernel(vcpu->kvm)) {
+ memcpy(vcpu->irq_pending, sregs->interrupt_bitmap,
+ sizeof vcpu->irq_pending);
+ vcpu->irq_summary = 0;
+ for (i = 0; i < ARRAY_SIZE(vcpu->irq_pending); ++i)
+ if (vcpu->irq_pending[i])
+ __set_bit(i, &vcpu->irq_summary);
+ } else {
+ max_bits = (sizeof sregs->interrupt_bitmap) << 3;
+ pending_vec = find_first_bit(
+ (const unsigned long *)sregs->interrupt_bitmap,
+ max_bits);
+ /* Only pending external irq is handled here */
+ if (pending_vec < max_bits) {
+ kvm_x86_ops->set_irq(vcpu, pending_vec);
+ printk("Set back pending irq %d\n", pending_vec);
+ }
+ }
set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
@@ -2109,6 +2354,16 @@ static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
return 0;
}
+void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
+{
+ struct kvm_segment cs;
+
+ get_segment(vcpu, &cs, VCPU_SREG_CS);
+ *db = cs.db;
+ *l = cs.l;
+}
+EXPORT_SYMBOL_GPL(kvm_get_cs_db_l_bits);
+
/*
* List of msr numbers which we expose to userspace through KVM_GET_MSRS
* and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST.
@@ -2236,13 +2491,13 @@ static int kvm_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
gpa_t gpa;
vcpu_load(vcpu);
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
gpa = vcpu->mmu.gva_to_gpa(vcpu, vaddr);
tr->physical_address = gpa;
tr->valid = gpa != UNMAPPED_GVA;
tr->writeable = 1;
tr->usermode = 0;
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
vcpu_put(vcpu);
return 0;
@@ -2253,6 +2508,8 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
{
if (irq->irq < 0 || irq->irq >= 256)
return -EINVAL;
+ if (irqchip_in_kernel(vcpu->kvm))
+ return -ENXIO;
vcpu_load(vcpu);
set_bit(irq->irq, vcpu->irq_pending);
@@ -2270,7 +2527,7 @@ static int kvm_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
vcpu_load(vcpu);
- r = kvm_arch_ops->set_guest_debug(vcpu, dbg);
+ r = kvm_x86_ops->set_guest_debug(vcpu, dbg);
vcpu_put(vcpu);
@@ -2285,7 +2542,6 @@ static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma,
unsigned long pgoff;
struct page *page;
- *type = VM_FAULT_MINOR;
pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
if (pgoff == 0)
page = virt_to_page(vcpu->run);
@@ -2294,6 +2550,9 @@ static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma,
else
return NOPAGE_SIGBUS;
get_page(page);
+ if (type != NULL)
+ *type = VM_FAULT_MINOR;
+
return page;
}
@@ -2346,74 +2605,52 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
{
int r;
struct kvm_vcpu *vcpu;
- struct page *page;
- r = -EINVAL;
if (!valid_vcpu(n))
- goto out;
-
- vcpu = &kvm->vcpus[n];
-
- mutex_lock(&vcpu->mutex);
-
- if (vcpu->vmcs) {
- mutex_unlock(&vcpu->mutex);
- return -EEXIST;
- }
-
- page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- r = -ENOMEM;
- if (!page)
- goto out_unlock;
- vcpu->run = page_address(page);
-
- page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- r = -ENOMEM;
- if (!page)
- goto out_free_run;
- vcpu->pio_data = page_address(page);
+ return -EINVAL;
- vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
- FX_IMAGE_ALIGN);
- vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
- vcpu->cr0 = 0x10;
+ vcpu = kvm_x86_ops->vcpu_create(kvm, n);
+ if (IS_ERR(vcpu))
+ return PTR_ERR(vcpu);
- r = kvm_arch_ops->vcpu_create(vcpu);
- if (r < 0)
- goto out_free_vcpus;
+ preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops);
- r = kvm_mmu_create(vcpu);
- if (r < 0)
- goto out_free_vcpus;
+ /* We do fxsave: this must be aligned. */
+ BUG_ON((unsigned long)&vcpu->host_fx_image & 0xF);
- kvm_arch_ops->vcpu_load(vcpu);
+ vcpu_load(vcpu);
r = kvm_mmu_setup(vcpu);
- if (r >= 0)
- r = kvm_arch_ops->vcpu_setup(vcpu);
vcpu_put(vcpu);
-
if (r < 0)
- goto out_free_vcpus;
+ goto free_vcpu;
+
+ mutex_lock(&kvm->lock);
+ if (kvm->vcpus[n]) {
+ r = -EEXIST;
+ mutex_unlock(&kvm->lock);
+ goto mmu_unload;
+ }
+ kvm->vcpus[n] = vcpu;
+ mutex_unlock(&kvm->lock);
+ /* Now it's all set up, let userspace reach it */
r = create_vcpu_fd(vcpu);
if (r < 0)
- goto out_free_vcpus;
+ goto unlink;
+ return r;
- spin_lock(&kvm_lock);
- if (n >= kvm->nvcpus)
- kvm->nvcpus = n + 1;
- spin_unlock(&kvm_lock);
+unlink:
+ mutex_lock(&kvm->lock);
+ kvm->vcpus[n] = NULL;
+ mutex_unlock(&kvm->lock);
- return r;
+mmu_unload:
+ vcpu_load(vcpu);
+ kvm_mmu_unload(vcpu);
+ vcpu_put(vcpu);
-out_free_vcpus:
- kvm_free_vcpu(vcpu);
-out_free_run:
- free_page((unsigned long)vcpu->run);
- vcpu->run = NULL;
-out_unlock:
- mutex_unlock(&vcpu->mutex);
-out:
+free_vcpu:
+ kvm_x86_ops->vcpu_free(vcpu);
return r;
}
@@ -2493,7 +2730,7 @@ struct fxsave {
static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+ struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image;
vcpu_load(vcpu);
@@ -2513,7 +2750,7 @@ static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
{
- struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+ struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image;
vcpu_load(vcpu);
@@ -2531,6 +2768,27 @@ static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
return 0;
}
+static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
+ struct kvm_lapic_state *s)
+{
+ vcpu_load(vcpu);
+ memcpy(s->regs, vcpu->apic->regs, sizeof *s);
+ vcpu_put(vcpu);
+
+ return 0;
+}
+
+static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
+ struct kvm_lapic_state *s)
+{
+ vcpu_load(vcpu);
+ memcpy(vcpu->apic->regs, s->regs, sizeof *s);
+ kvm_apic_post_state_restore(vcpu);
+ vcpu_put(vcpu);
+
+ return 0;
+}
+
static long kvm_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -2700,6 +2958,31 @@ static long kvm_vcpu_ioctl(struct file *filp,
r = 0;
break;
}
+ case KVM_GET_LAPIC: {
+ struct kvm_lapic_state lapic;
+
+ memset(&lapic, 0, sizeof lapic);
+ r = kvm_vcpu_ioctl_get_lapic(vcpu, &lapic);
+ if (r)
+ goto out;
+ r = -EFAULT;
+ if (copy_to_user(argp, &lapic, sizeof lapic))
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_SET_LAPIC: {
+ struct kvm_lapic_state lapic;
+
+ r = -EFAULT;
+ if (copy_from_user(&lapic, argp, sizeof lapic))
+ goto out;
+ r = kvm_vcpu_ioctl_set_lapic(vcpu, &lapic);;
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
default:
;
}
@@ -2753,6 +3036,75 @@ static long kvm_vm_ioctl(struct file *filp,
goto out;
break;
}
+ case KVM_CREATE_IRQCHIP:
+ r = -ENOMEM;
+ kvm->vpic = kvm_create_pic(kvm);
+ if (kvm->vpic) {
+ r = kvm_ioapic_init(kvm);
+ if (r) {
+ kfree(kvm->vpic);
+ kvm->vpic = NULL;
+ goto out;
+ }
+ }
+ else
+ goto out;
+ break;
+ case KVM_IRQ_LINE: {
+ struct kvm_irq_level irq_event;
+
+ r = -EFAULT;
+ if (copy_from_user(&irq_event, argp, sizeof irq_event))
+ goto out;
+ if (irqchip_in_kernel(kvm)) {
+ mutex_lock(&kvm->lock);
+ if (irq_event.irq < 16)
+ kvm_pic_set_irq(pic_irqchip(kvm),
+ irq_event.irq,
+ irq_event.level);
+ kvm_ioapic_set_irq(kvm->vioapic,
+ irq_event.irq,
+ irq_event.level);
+ mutex_unlock(&kvm->lock);
+ r = 0;
+ }
+ break;
+ }
+ case KVM_GET_IRQCHIP: {
+ /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
+ struct kvm_irqchip chip;
+
+ r = -EFAULT;
+ if (copy_from_user(&chip, argp, sizeof chip))
+ goto out;
+ r = -ENXIO;
+ if (!irqchip_in_kernel(kvm))
+ goto out;
+ r = kvm_vm_ioctl_get_irqchip(kvm, &chip);
+ if (r)
+ goto out;
+ r = -EFAULT;
+ if (copy_to_user(argp, &chip, sizeof chip))
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_SET_IRQCHIP: {
+ /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
+ struct kvm_irqchip chip;
+
+ r = -EFAULT;
+ if (copy_from_user(&chip, argp, sizeof chip))
+ goto out;
+ r = -ENXIO;
+ if (!irqchip_in_kernel(kvm))
+ goto out;
+ r = kvm_vm_ioctl_set_irqchip(kvm, &chip);
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
default:
;
}
@@ -2768,12 +3120,14 @@ static struct page *kvm_vm_nopage(struct vm_area_struct *vma,
unsigned long pgoff;
struct page *page;
- *type = VM_FAULT_MINOR;
pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
page = gfn_to_page(kvm, pgoff);
if (!page)
return NOPAGE_SIGBUS;
get_page(page);
+ if (type != NULL)
+ *type = VM_FAULT_MINOR;
+
return page;
}
@@ -2861,12 +3215,20 @@ static long kvm_dev_ioctl(struct file *filp,
r = 0;
break;
}
- case KVM_CHECK_EXTENSION:
- /*
- * No extensions defined at present.
- */
- r = 0;
+ case KVM_CHECK_EXTENSION: {
+ int ext = (long)argp;
+
+ switch (ext) {
+ case KVM_CAP_IRQCHIP:
+ case KVM_CAP_HLT:
+ r = 1;
+ break;
+ default:
+ r = 0;
+ break;
+ }
break;
+ }
case KVM_GET_VCPU_MMAP_SIZE:
r = -EINVAL;
if (arg)
@@ -2881,8 +3243,6 @@ out:
}
static struct file_operations kvm_chardev_ops = {
- .open = kvm_dev_open,
- .release = kvm_dev_release,
.unlocked_ioctl = kvm_dev_ioctl,
.compat_ioctl = kvm_dev_ioctl,
};
@@ -2893,25 +3253,6 @@ static struct miscdevice kvm_dev = {
&kvm_chardev_ops,
};
-static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
- void *v)
-{
- if (val == SYS_RESTART) {
- /*
- * Some (well, at least mine) BIOSes hang on reboot if
- * in vmx root mode.
- */
- printk(KERN_INFO "kvm: exiting hardware virtualization\n");
- on_each_cpu(hardware_disable, NULL, 0, 1);
- }
- return NOTIFY_OK;
-}
-
-static struct notifier_block kvm_reboot_notifier = {
- .notifier_call = kvm_reboot,
- .priority = 0,
-};
-
/*
* Make sure that a cpu that is being hot-unplugged does not have any vcpus
* cached on it.
@@ -2925,7 +3266,9 @@ static void decache_vcpus_on_cpu(int cpu)
spin_lock(&kvm_lock);
list_for_each_entry(vm, &vm_list, vm_list)
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = &vm->vcpus[i];
+ vcpu = vm->vcpus[i];
+ if (!vcpu)
+ continue;
/*
* If the vcpu is locked, then it is running on some
* other cpu and therefore it is not cached on the
@@ -2936,7 +3279,7 @@ static void decache_vcpus_on_cpu(int cpu)
*/
if (mutex_trylock(&vcpu->mutex)) {
if (vcpu->cpu == cpu) {
- kvm_arch_ops->vcpu_decache(vcpu);
+ kvm_x86_ops->vcpu_decache(vcpu);
vcpu->cpu = -1;
}
mutex_unlock(&vcpu->mutex);
@@ -2952,7 +3295,7 @@ static void hardware_enable(void *junk)
if (cpu_isset(cpu, cpus_hardware_enabled))
return;
cpu_set(cpu, cpus_hardware_enabled);
- kvm_arch_ops->hardware_enable(NULL);
+ kvm_x86_ops->hardware_enable(NULL);
}
static void hardware_disable(void *junk)
@@ -2963,7 +3306,7 @@ static void hardware_disable(void *junk)
return;
cpu_clear(cpu, cpus_hardware_enabled);
decache_vcpus_on_cpu(cpu);
- kvm_arch_ops->hardware_disable(NULL);
+ kvm_x86_ops->hardware_disable(NULL);
}
static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
@@ -2994,6 +3337,25 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
return NOTIFY_OK;
}
+static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
+ void *v)
+{
+ if (val == SYS_RESTART) {
+ /*
+ * Some (well, at least mine) BIOSes hang on reboot if
+ * in vmx root mode.
+ */
+ printk(KERN_INFO "kvm: exiting hardware virtualization\n");
+ on_each_cpu(hardware_disable, NULL, 0, 1);
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block kvm_reboot_notifier = {
+ .notifier_call = kvm_reboot,
+ .priority = 0,
+};
+
void kvm_io_bus_init(struct kvm_io_bus *bus)
{
memset(bus, 0, sizeof(*bus));
@@ -3047,18 +3409,15 @@ static u64 stat_get(void *_offset)
spin_lock(&kvm_lock);
list_for_each_entry(kvm, &vm_list, vm_list)
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- vcpu = &kvm->vcpus[i];
- total += *(u32 *)((void *)vcpu + offset);
+ vcpu = kvm->vcpus[i];
+ if (vcpu)
+ total += *(u32 *)((void *)vcpu + offset);
}
spin_unlock(&kvm_lock);
return total;
}
-static void stat_set(void *offset, u64 val)
-{
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, stat_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, NULL, "%llu\n");
static __init void kvm_init_debug(void)
{
@@ -3105,11 +3464,34 @@ static struct sys_device kvm_sysdev = {
hpa_t bad_page_address;
-int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
+static inline
+struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn)
+{
+ return container_of(pn, struct kvm_vcpu, preempt_notifier);
+}
+
+static void kvm_sched_in(struct preempt_notifier *pn, int cpu)
+{
+ struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
+
+ kvm_x86_ops->vcpu_load(vcpu, cpu);
+}
+
+static void kvm_sched_out(struct preempt_notifier *pn,
+ struct task_struct *next)
+{
+ struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
+
+ kvm_x86_ops->vcpu_put(vcpu);
+}
+
+int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size,
+ struct module *module)
{
int r;
+ int cpu;
- if (kvm_arch_ops) {
+ if (kvm_x86_ops) {
printk(KERN_ERR "kvm: already loaded the other module\n");
return -EEXIST;
}
@@ -3123,12 +3505,20 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
return -EOPNOTSUPP;
}
- kvm_arch_ops = ops;
+ kvm_x86_ops = ops;
- r = kvm_arch_ops->hardware_setup();
+ r = kvm_x86_ops->hardware_setup();
if (r < 0)
goto out;
+ for_each_online_cpu(cpu) {
+ smp_call_function_single(cpu,
+ kvm_x86_ops->check_processor_compatibility,
+ &r, 0, 1);
+ if (r < 0)
+ goto out_free_0;
+ }
+
on_each_cpu(hardware_enable, NULL, 0, 1);
r = register_cpu_notifier(&kvm_cpu_notifier);
if (r)
@@ -3143,6 +3533,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
if (r)
goto out_free_3;
+ /* A kmem cache lets us meet the alignment requirements of fx_save. */
+ kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size,
+ __alignof__(struct kvm_vcpu), 0, 0);
+ if (!kvm_vcpu_cache) {
+ r = -ENOMEM;
+ goto out_free_4;
+ }
+
kvm_chardev_ops.owner = module;
r = misc_register(&kvm_dev);
@@ -3151,9 +3549,14 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
goto out_free;
}
+ kvm_preempt_ops.sched_in = kvm_sched_in;
+ kvm_preempt_ops.sched_out = kvm_sched_out;
+
return r;
out_free:
+ kmem_cache_destroy(kvm_vcpu_cache);
+out_free_4:
sysdev_unregister(&kvm_sysdev);
out_free_3:
sysdev_class_unregister(&kvm_sysdev_class);
@@ -3162,22 +3565,24 @@ out_free_2:
unregister_cpu_notifier(&kvm_cpu_notifier);
out_free_1:
on_each_cpu(hardware_disable, NULL, 0, 1);
- kvm_arch_ops->hardware_unsetup();
+out_free_0:
+ kvm_x86_ops->hardware_unsetup();
out:
- kvm_arch_ops = NULL;
+ kvm_x86_ops = NULL;
return r;
}
-void kvm_exit_arch(void)
+void kvm_exit_x86(void)
{
misc_deregister(&kvm_dev);
+ kmem_cache_destroy(kvm_vcpu_cache);
sysdev_unregister(&kvm_sysdev);
sysdev_class_unregister(&kvm_sysdev_class);
unregister_reboot_notifier(&kvm_reboot_notifier);
unregister_cpu_notifier(&kvm_cpu_notifier);
on_each_cpu(hardware_disable, NULL, 0, 1);
- kvm_arch_ops->hardware_unsetup();
- kvm_arch_ops = NULL;
+ kvm_x86_ops->hardware_unsetup();
+ kvm_x86_ops = NULL;
}
static __init int kvm_init(void)
@@ -3220,5 +3625,5 @@ static __exit void kvm_exit(void)
module_init(kvm_init)
module_exit(kvm_exit)
-EXPORT_SYMBOL_GPL(kvm_init_arch);
-EXPORT_SYMBOL_GPL(kvm_exit_arch);
+EXPORT_SYMBOL_GPL(kvm_init_x86);
+EXPORT_SYMBOL_GPL(kvm_exit_x86);
diff --git a/drivers/kvm/kvm_svm.h b/drivers/kvm/kvm_svm.h
index a869983d683..a0e415daef5 100644
--- a/drivers/kvm/kvm_svm.h
+++ b/drivers/kvm/kvm_svm.h
@@ -20,7 +20,10 @@ static const u32 host_save_user_msrs[] = {
#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
#define NUM_DB_REGS 4
+struct kvm_vcpu;
+
struct vcpu_svm {
+ struct kvm_vcpu vcpu;
struct vmcb *vmcb;
unsigned long vmcb_pa;
struct svm_cpu_data *svm_data;
diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c
new file mode 100644
index 00000000000..238fcad3cec
--- /dev/null
+++ b/drivers/kvm/lapic.c
@@ -0,0 +1,1080 @@
+
+/*
+ * Local APIC virtualization
+ *
+ * Copyright (C) 2006 Qumranet, Inc.
+ * Copyright (C) 2007 Novell
+ * Copyright (C) 2007 Intel
+ *
+ * Authors:
+ * Dor Laor <dor.laor@qumranet.com>
+ * Gregory Haskins <ghaskins@novell.com>
+ * Yaozu (Eddie) Dong <eddie.dong@intel.com>
+ *
+ * Based on Xen 3.1 code, Copyright (c) 2004, Intel Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "kvm.h"
+#include <linux/kvm.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/smp.h>
+#include <linux/hrtimer.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/page.h>
+#include <asm/current.h>
+#include <asm/apicdef.h>
+#include <asm/atomic.h>
+#include <asm/div64.h>
+#include "irq.h"
+
+#define PRId64 "d"
+#define PRIx64 "llx"
+#define PRIu64 "u"
+#define PRIo64 "o"
+
+#define APIC_BUS_CYCLE_NS 1
+
+/* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */
+#define apic_debug(fmt, arg...)
+
+#define APIC_LVT_NUM 6
+/* 14 is the version for Xeon and Pentium 8.4.8*/
+#define APIC_VERSION (0x14UL | ((APIC_LVT_NUM - 1) << 16))
+#define LAPIC_MMIO_LENGTH (1 << 12)
+/* followed define is not in apicdef.h */
+#define APIC_SHORT_MASK 0xc0000
+#define APIC_DEST_NOSHORT 0x0
+#define APIC_DEST_MASK 0x800
+#define MAX_APIC_VECTOR 256
+
+#define VEC_POS(v) ((v) & (32 - 1))
+#define REG_POS(v) (((v) >> 5) << 4)
+static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off)
+{
+ return *((u32 *) (apic->regs + reg_off));
+}
+
+static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val)
+{
+ *((u32 *) (apic->regs + reg_off)) = val;
+}
+
+static inline int apic_test_and_set_vector(int vec, void *bitmap)
+{
+ return test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline int apic_test_and_clear_vector(int vec, void *bitmap)
+{
+ return test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline void apic_set_vector(int vec, void *bitmap)
+{
+ set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline void apic_clear_vector(int vec, void *bitmap)
+{
+ clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline int apic_hw_enabled(struct kvm_lapic *apic)
+{
+ return (apic)->vcpu->apic_base & MSR_IA32_APICBASE_ENABLE;
+}
+
+static inline int apic_sw_enabled(struct kvm_lapic *apic)
+{
+ return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED;
+}
+
+static inline int apic_enabled(struct kvm_lapic *apic)
+{
+ return apic_sw_enabled(apic) && apic_hw_enabled(apic);
+}
+
+#define LVT_MASK \
+ (APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK)
+
+#define LINT_MASK \
+ (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \
+ APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER)
+
+static inline int kvm_apic_id(struct kvm_lapic *apic)
+{
+ return (apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
+}
+
+static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type)
+{
+ return !(apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED);
+}
+
+static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type)
+{
+ return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK;
+}
+
+static inline int apic_lvtt_period(struct kvm_lapic *apic)
+{
+ return apic_get_reg(apic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC;
+}
+
+static unsigned int apic_lvt_mask[APIC_LVT_NUM] = {
+ LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */
+ LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */
+ LVT_MASK | APIC_MODE_MASK, /* LVTPC */
+ LINT_MASK, LINT_MASK, /* LVT0-1 */
+ LVT_MASK /* LVTERR */
+};
+
+static int find_highest_vector(void *bitmap)
+{
+ u32 *word = bitmap;
+ int word_offset = MAX_APIC_VECTOR >> 5;
+
+ while ((word_offset != 0) && (word[(--word_offset) << 2] == 0))
+ continue;
+
+ if (likely(!word_offset && !word[0]))
+ return -1;
+ else
+ return fls(word[word_offset << 2]) - 1 + (word_offset << 5);
+}
+
+static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic)
+{
+ return apic_test_and_set_vector(vec, apic->regs + APIC_IRR);
+}
+
+static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
+{
+ apic_clear_vector(vec, apic->regs + APIC_IRR);
+}
+
+static inline int apic_find_highest_irr(struct kvm_lapic *apic)
+{
+ int result;
+
+ result = find_highest_vector(apic->regs + APIC_IRR);
+ ASSERT(result == -1 || result >= 16);
+
+ return result;
+}
+
+int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+ int highest_irr;
+
+ if (!apic)
+ return 0;
+ highest_irr = apic_find_highest_irr(apic);
+
+ return highest_irr;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr);
+
+int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig)
+{
+ if (!apic_test_and_set_irr(vec, apic)) {
+ /* a new pending irq is set in IRR */
+ if (trig)
+ apic_set_vector(vec, apic->regs + APIC_TMR);
+ else
+ apic_clear_vector(vec, apic->regs + APIC_TMR);
+ kvm_vcpu_kick(apic->vcpu);
+ return 1;
+ }
+ return 0;
+}
+
+static inline int apic_find_highest_isr(struct kvm_lapic *apic)
+{
+ int result;
+
+ result = find_highest_vector(apic->regs + APIC_ISR);
+ ASSERT(result == -1 || result >= 16);
+
+ return result;
+}
+
+static void apic_update_ppr(struct kvm_lapic *apic)
+{
+ u32 tpr, isrv, ppr;
+ int isr;
+
+ tpr = apic_get_reg(apic, APIC_TASKPRI);
+ isr = apic_find_highest_isr(apic);
+ isrv = (isr != -1) ? isr : 0;
+
+ if ((tpr & 0xf0) >= (isrv & 0xf0))
+ ppr = tpr & 0xff;
+ else
+ ppr = isrv & 0xf0;
+
+ apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x",
+ apic, ppr, isr, isrv);
+
+ apic_set_reg(apic, APIC_PROCPRI, ppr);
+}
+
+static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr)
+{
+ apic_set_reg(apic, APIC_TASKPRI, tpr);
+ apic_update_ppr(apic);
+}
+
+int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest)
+{
+ return kvm_apic_id(apic) == dest;
+}
+
+int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
+{
+ int result = 0;
+ u8 logical_id;
+
+ logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR));
+
+ switch (apic_get_reg(apic, APIC_DFR)) {
+ case APIC_DFR_FLAT:
+ if (logical_id & mda)
+ result = 1;
+ break;
+ case APIC_DFR_CLUSTER:
+ if (((logical_id >> 4) == (mda >> 0x4))
+ && (logical_id & mda & 0xf))
+ result = 1;
+ break;
+ default:
+ printk(KERN_WARNING "Bad DFR vcpu %d: %08x\n",
+ apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR));
+ break;
+ }
+
+ return result;
+}
+
+static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
+ int short_hand, int dest, int dest_mode)
+{
+ int result = 0;
+ struct kvm_lapic *target = vcpu->apic;
+
+ apic_debug("target %p, source %p, dest 0x%x, "
+ "dest_mode 0x%x, short_hand 0x%x",
+ target, source, dest, dest_mode, short_hand);
+
+ ASSERT(!target);
+ switch (short_hand) {
+ case APIC_DEST_NOSHORT:
+ if (dest_mode == 0) {
+ /* Physical mode. */
+ if ((dest == 0xFF) || (dest == kvm_apic_id(target)))
+ result = 1;
+ } else
+ /* Logical mode. */
+ result = kvm_apic_match_logical_addr(target, dest);
+ break;
+ case APIC_DEST_SELF:
+ if (target == source)
+ result = 1;
+ break;
+ case APIC_DEST_ALLINC:
+ result = 1;
+ break;
+ case APIC_DEST_ALLBUT:
+ if (target != source)
+ result = 1;
+ break;
+ default:
+ printk(KERN_WARNING "Bad dest shorthand value %x\n",
+ short_hand);
+ break;
+ }
+
+ return result;
+}
+
+/*
+ * Add a pending IRQ into lapic.
+ * Return 1 if successfully added and 0 if discarded.
+ */
+static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
+ int vector, int level, int trig_mode)
+{
+ int orig_irr, result = 0;
+ struct kvm_vcpu *vcpu = apic->vcpu;
+
+ switch (delivery_mode) {
+ case APIC_DM_FIXED:
+ case APIC_DM_LOWEST:
+ /* FIXME add logic for vcpu on reset */
+ if (unlikely(!apic_enabled(apic)))
+ break;
+
+ orig_irr = apic_test_and_set_irr(vector, apic);
+ if (orig_irr && trig_mode) {
+ apic_debug("level trig mode repeatedly for vector %d",
+ vector);
+ break;
+ }
+
+ if (trig_mode) {
+ apic_debug("level trig mode for vector %d", vector);
+ apic_set_vector(vector, apic->regs + APIC_TMR);
+ } else
+ apic_clear_vector(vector, apic->regs + APIC_TMR);
+
+ if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE)
+ kvm_vcpu_kick(vcpu);
+ else if (vcpu->mp_state == VCPU_MP_STATE_HALTED) {
+ vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+ if (waitqueue_active(&vcpu->wq))
+ wake_up_interruptible(&vcpu->wq);
+ }
+
+ result = (orig_irr == 0);
+ break;
+
+ case APIC_DM_REMRD:
+ printk(KERN_DEBUG "Ignoring delivery mode 3\n");
+ break;
+
+ case APIC_DM_SMI:
+ printk(KERN_DEBUG "Ignoring guest SMI\n");
+ break;
+ case APIC_DM_NMI:
+ printk(KERN_DEBUG "Ignoring guest NMI\n");
+ break;
+
+ case APIC_DM_INIT:
+ if (level) {
+ if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE)
+ printk(KERN_DEBUG
+ "INIT on a runnable vcpu %d\n",
+ vcpu->vcpu_id);
+ vcpu->mp_state = VCPU_MP_STATE_INIT_RECEIVED;
+ kvm_vcpu_kick(vcpu);
+ } else {
+ printk(KERN_DEBUG
+ "Ignoring de-assert INIT to vcpu %d\n",
+ vcpu->vcpu_id);
+ }
+
+ break;
+
+ case APIC_DM_STARTUP:
+ printk(KERN_DEBUG "SIPI to vcpu %d vector 0x%02x\n",
+ vcpu->vcpu_id, vector);
+ if (vcpu->mp_state == VCPU_MP_STATE_INIT_RECEIVED) {
+ vcpu->sipi_vector = vector;
+ vcpu->mp_state = VCPU_MP_STATE_SIPI_RECEIVED;
+ if (waitqueue_active(&vcpu->wq))
+ wake_up_interruptible(&vcpu->wq);
+ }
+ break;
+
+ default:
+ printk(KERN_ERR "TODO: unsupported delivery mode %x\n",
+ delivery_mode);
+ break;
+ }
+ return result;
+}
+
+struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
+ unsigned long bitmap)
+{
+ int vcpu_id;
+ int last;
+ int next;
+ struct kvm_lapic *apic;
+
+ last = kvm->round_robin_prev_vcpu;
+ next = last;
+
+ do {
+ if (++next == KVM_MAX_VCPUS)
+ next = 0;
+ if (kvm->vcpus[next] == NULL || !test_bit(next, &bitmap))
+ continue;
+ apic = kvm->vcpus[next]->apic;
+ if (apic && apic_enabled(apic))
+ break;
+ apic = NULL;
+ } while (next != last);
+ kvm->round_robin_prev_vcpu = next;
+
+ if (!apic) {
+ vcpu_id = ffs(bitmap) - 1;
+ if (vcpu_id < 0) {
+ vcpu_id = 0;
+ printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n");
+ }
+ apic = kvm->vcpus[vcpu_id]->apic;
+ }
+
+ return apic;
+}
+
+static void apic_set_eoi(struct kvm_lapic *apic)
+{
+ int vector = apic_find_highest_isr(apic);
+
+ /*
+ * Not every write EOI will has corresponding ISR,
+ * one example is when Kernel check timer on setup_IO_APIC
+ */
+ if (vector == -1)
+ return;
+
+ apic_clear_vector(vector, apic->regs + APIC_ISR);
+ apic_update_ppr(apic);
+
+ if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR))
+ kvm_ioapic_update_eoi(apic->vcpu->kvm, vector);
+}
+
+static void apic_send_ipi(struct kvm_lapic *apic)
+{
+ u32 icr_low = apic_get_reg(apic, APIC_ICR);
+ u32 icr_high = apic_get_reg(apic, APIC_ICR2);
+
+ unsigned int dest = GET_APIC_DEST_FIELD(icr_high);
+ unsigned int short_hand = icr_low & APIC_SHORT_MASK;
+ unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG;
+ unsigned int level = icr_low & APIC_INT_ASSERT;
+ unsigned int dest_mode = icr_low & APIC_DEST_MASK;
+ unsigned int delivery_mode = icr_low & APIC_MODE_MASK;
+ unsigned int vector = icr_low & APIC_VECTOR_MASK;
+
+ struct kvm_lapic *target;
+ struct kvm_vcpu *vcpu;
+ unsigned long lpr_map = 0;
+ int i;
+
+ apic_debug("icr_high 0x%x, icr_low 0x%x, "
+ "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
+ "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n",
+ icr_high, icr_low, short_hand, dest,
+ trig_mode, level, dest_mode, delivery_mode, vector);
+
+ for (i = 0; i < KVM_MAX_VCPUS; i++) {
+ vcpu = apic->vcpu->kvm->vcpus[i];
+ if (!vcpu)
+ continue;
+
+ if (vcpu->apic &&
+ apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) {
+ if (delivery_mode == APIC_DM_LOWEST)
+ set_bit(vcpu->vcpu_id, &lpr_map);
+ else
+ __apic_accept_irq(vcpu->apic, delivery_mode,
+ vector, level, trig_mode);
+ }
+ }
+
+ if (delivery_mode == APIC_DM_LOWEST) {
+ target = kvm_apic_round_robin(vcpu->kvm, vector, lpr_map);
+ if (target != NULL)
+ __apic_accept_irq(target, delivery_mode,
+ vector, level, trig_mode);
+ }
+}
+
+static u32 apic_get_tmcct(struct kvm_lapic *apic)
+{
+ u64 counter_passed;
+ ktime_t passed, now;
+ u32 tmcct;
+
+ ASSERT(apic != NULL);
+
+ now = apic->timer.dev.base->get_time();
+ tmcct = apic_get_reg(apic, APIC_TMICT);
+
+ /* if initial count is 0, current count should also be 0 */
+ if (tmcct == 0)
+ return 0;
+
+ if (unlikely(ktime_to_ns(now) <=
+ ktime_to_ns(apic->timer.last_update))) {
+ /* Wrap around */
+ passed = ktime_add(( {
+ (ktime_t) {
+ .tv64 = KTIME_MAX -
+ (apic->timer.last_update).tv64}; }
+ ), now);
+ apic_debug("time elapsed\n");
+ } else
+ passed = ktime_sub(now, apic->timer.last_update);
+
+ counter_passed = div64_64(ktime_to_ns(passed),
+ (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
+
+ if (counter_passed > tmcct) {
+ if (unlikely(!apic_lvtt_period(apic))) {
+ /* one-shot timers stick at 0 until reset */
+ tmcct = 0;
+ } else {
+ /*
+ * periodic timers reset to APIC_TMICT when they
+ * hit 0. The while loop simulates this happening N
+ * times. (counter_passed %= tmcct) would also work,
+ * but might be slower or not work on 32-bit??
+ */
+ while (counter_passed > tmcct)
+ counter_passed -= tmcct;
+ tmcct -= counter_passed;
+ }
+ } else {
+ tmcct -= counter_passed;
+ }
+
+ return tmcct;
+}
+
+static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
+{
+ u32 val = 0;
+
+ if (offset >= LAPIC_MMIO_LENGTH)
+ return 0;
+
+ switch (offset) {
+ case APIC_ARBPRI:
+ printk(KERN_WARNING "Access APIC ARBPRI register "
+ "which is for P6\n");
+ break;
+
+ case APIC_TMCCT: /* Timer CCR */
+ val = apic_get_tmcct(apic);
+ break;
+
+ default:
+ apic_update_ppr(apic);
+ val = apic_get_reg(apic, offset);
+ break;
+ }
+
+ return val;
+}
+
+static void apic_mmio_read(struct kvm_io_device *this,
+ gpa_t address, int len, void *data)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
+ unsigned int offset = address - apic->base_address;
+ unsigned char alignment = offset & 0xf;
+ u32 result;
+
+ if ((alignment + len) > 4) {
+ printk(KERN_ERR "KVM_APIC_READ: alignment error %lx %d",
+ (unsigned long)address, len);
+ return;
+ }
+ result = __apic_read(apic, offset & ~0xf);
+
+ switch (len) {
+ case 1:
+ case 2:
+ case 4:
+ memcpy(data, (char *)&result + alignment, len);
+ break;
+ default:
+ printk(KERN_ERR "Local APIC read with len = %x, "
+ "should be 1,2, or 4 instead\n", len);
+ break;
+ }
+}
+
+static void update_divide_count(struct kvm_lapic *apic)
+{
+ u32 tmp1, tmp2, tdcr;
+
+ tdcr = apic_get_reg(apic, APIC_TDCR);
+ tmp1 = tdcr & 0xf;
+ tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
+ apic->timer.divide_count = 0x1 << (tmp2 & 0x7);
+
+ apic_debug("timer divide count is 0x%x\n",
+ apic->timer.divide_count);
+}
+
+static void start_apic_timer(struct kvm_lapic *apic)
+{
+ ktime_t now = apic->timer.dev.base->get_time();
+
+ apic->timer.last_update = now;
+
+ apic->timer.period = apic_get_reg(apic, APIC_TMICT) *
+ APIC_BUS_CYCLE_NS * apic->timer.divide_count;
+ atomic_set(&apic->timer.pending, 0);
+ hrtimer_start(&apic->timer.dev,
+ ktime_add_ns(now, apic->timer.period),
+ HRTIMER_MODE_ABS);
+
+ apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016"
+ PRIx64 ", "
+ "timer initial count 0x%x, period %lldns, "
+ "expire @ 0x%016" PRIx64 ".\n", __FUNCTION__,
+ APIC_BUS_CYCLE_NS, ktime_to_ns(now),
+ apic_get_reg(apic, APIC_TMICT),
+ apic->timer.period,
+ ktime_to_ns(ktime_add_ns(now,
+ apic->timer.period)));
+}
+
+static void apic_mmio_write(struct kvm_io_device *this,
+ gpa_t address, int len, const void *data)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
+ unsigned int offset = address - apic->base_address;
+ unsigned char alignment = offset & 0xf;
+ u32 val;
+
+ /*
+ * APIC register must be aligned on 128-bits boundary.
+ * 32/64/128 bits registers must be accessed thru 32 bits.
+ * Refer SDM 8.4.1
+ */
+ if (len != 4 || alignment) {
+ if (printk_ratelimit())
+ printk(KERN_ERR "apic write: bad size=%d %lx\n",
+ len, (long)address);
+ return;
+ }
+
+ val = *(u32 *) data;
+
+ /* too common printing */
+ if (offset != APIC_EOI)
+ apic_debug("%s: offset 0x%x with length 0x%x, and value is "
+ "0x%x\n", __FUNCTION__, offset, len, val);
+
+ offset &= 0xff0;
+
+ switch (offset) {
+ case APIC_ID: /* Local APIC ID */
+ apic_set_reg(apic, APIC_ID, val);
+ break;
+
+ case APIC_TASKPRI:
+ apic_set_tpr(apic, val & 0xff);
+ break;
+
+ case APIC_EOI:
+ apic_set_eoi(apic);
+ break;
+
+ case APIC_LDR:
+ apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK);
+ break;
+
+ case APIC_DFR:
+ apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF);
+ break;
+
+ case APIC_SPIV:
+ apic_set_reg(apic, APIC_SPIV, val & 0x3ff);
+ if (!(val & APIC_SPIV_APIC_ENABLED)) {
+ int i;
+ u32 lvt_val;
+
+ for (i = 0; i < APIC_LVT_NUM; i++) {
+ lvt_val = apic_get_reg(apic,
+ APIC_LVTT + 0x10 * i);
+ apic_set_reg(apic, APIC_LVTT + 0x10 * i,
+ lvt_val | APIC_LVT_MASKED);
+ }
+ atomic_set(&apic->timer.pending, 0);
+
+ }
+ break;
+
+ case APIC_ICR:
+ /* No delay here, so we always clear the pending bit */
+ apic_set_reg(apic, APIC_ICR, val & ~(1 << 12));
+ apic_send_ipi(apic);
+ break;
+
+ case APIC_ICR2:
+ apic_set_reg(apic, APIC_ICR2, val & 0xff000000);
+ break;
+
+ case APIC_LVTT:
+ case APIC_LVTTHMR:
+ case APIC_LVTPC:
+ case APIC_LVT0:
+ case APIC_LVT1:
+ case APIC_LVTERR:
+ /* TODO: Check vector */
+ if (!apic_sw_enabled(apic))
+ val |= APIC_LVT_MASKED;
+
+ val &= apic_lvt_mask[(offset - APIC_LVTT) >> 4];
+ apic_set_reg(apic, offset, val);
+
+ break;
+
+ case APIC_TMICT:
+ hrtimer_cancel(&apic->timer.dev);
+ apic_set_reg(apic, APIC_TMICT, val);
+ start_apic_timer(apic);
+ return;
+
+ case APIC_TDCR:
+ if (val & 4)
+ printk(KERN_ERR "KVM_WRITE:TDCR %x\n", val);
+ apic_set_reg(apic, APIC_TDCR, val);
+ update_divide_count(apic);
+ break;
+
+ default:
+ apic_debug("Local APIC Write to read-only register %x\n",
+ offset);
+ break;
+ }
+
+}
+
+static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
+ int ret = 0;
+
+
+ if (apic_hw_enabled(apic) &&
+ (addr >= apic->base_address) &&
+ (addr < (apic->base_address + LAPIC_MMIO_LENGTH)))
+ ret = 1;
+
+ return ret;
+}
+
+void kvm_free_apic(struct kvm_lapic *apic)
+{
+ if (!apic)
+ return;
+
+ hrtimer_cancel(&apic->timer.dev);
+
+ if (apic->regs_page) {
+ __free_page(apic->regs_page);
+ apic->regs_page = 0;
+ }
+
+ kfree(apic);
+}
+
+/*
+ *----------------------------------------------------------------------
+ * LAPIC interface
+ *----------------------------------------------------------------------
+ */
+
+void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+
+ if (!apic)
+ return;
+ apic_set_tpr(apic, ((cr8 & 0x0f) << 4));
+}
+
+u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+ u64 tpr;
+
+ if (!apic)
+ return 0;
+ tpr = (u64) apic_get_reg(apic, APIC_TASKPRI);
+
+ return (tpr & 0xf0) >> 4;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_get_cr8);
+
+void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+
+ if (!apic) {
+ value |= MSR_IA32_APICBASE_BSP;
+ vcpu->apic_base = value;
+ return;
+ }
+ if (apic->vcpu->vcpu_id)
+ value &= ~MSR_IA32_APICBASE_BSP;
+
+ vcpu->apic_base = value;
+ apic->base_address = apic->vcpu->apic_base &
+ MSR_IA32_APICBASE_BASE;
+
+ /* with FSB delivery interrupt, we can restart APIC functionality */
+ apic_debug("apic base msr is 0x%016" PRIx64 ", and base address is "
+ "0x%lx.\n", apic->apic_base, apic->base_address);
+
+}
+
+u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu)
+{
+ return vcpu->apic_base;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_get_base);
+
+void kvm_lapic_reset(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic;
+ int i;
+
+ apic_debug("%s\n", __FUNCTION__);
+
+ ASSERT(vcpu);
+ apic = vcpu->apic;
+ ASSERT(apic != NULL);
+
+ /* Stop the timer in case it's a reset to an active apic */
+ hrtimer_cancel(&apic->timer.dev);
+
+ apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24);
+ apic_set_reg(apic, APIC_LVR, APIC_VERSION);
+
+ for (i = 0; i < APIC_LVT_NUM; i++)
+ apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
+ apic_set_reg(apic, APIC_LVT0,
+ SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
+
+ apic_set_reg(apic, APIC_DFR, 0xffffffffU);
+ apic_set_reg(apic, APIC_SPIV, 0xff);
+ apic_set_reg(apic, APIC_TASKPRI, 0);
+ apic_set_reg(apic, APIC_LDR, 0);
+ apic_set_reg(apic, APIC_ESR, 0);
+ apic_set_reg(apic, APIC_ICR, 0);
+ apic_set_reg(apic, APIC_ICR2, 0);
+ apic_set_reg(apic, APIC_TDCR, 0);
+ apic_set_reg(apic, APIC_TMICT, 0);
+ for (i = 0; i < 8; i++) {
+ apic_set_reg(apic, APIC_IRR + 0x10 * i, 0);
+ apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
+ apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
+ }
+ update_divide_count(apic);
+ atomic_set(&apic->timer.pending, 0);
+ if (vcpu->vcpu_id == 0)
+ vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
+ apic_update_ppr(apic);
+
+ apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr="
+ "0x%016" PRIx64 ", base_address=0x%0lx.\n", __FUNCTION__,
+ vcpu, kvm_apic_id(apic),
+ vcpu->apic_base, apic->base_address);
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_reset);
+
+int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+ int ret = 0;
+
+ if (!apic)
+ return 0;
+ ret = apic_enabled(apic);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(kvm_lapic_enabled);
+
+/*
+ *----------------------------------------------------------------------
+ * timer interface
+ *----------------------------------------------------------------------
+ */
+
+/* TODO: make sure __apic_timer_fn runs in current pCPU */
+static int __apic_timer_fn(struct kvm_lapic *apic)
+{
+ int result = 0;
+ wait_queue_head_t *q = &apic->vcpu->wq;
+
+ atomic_inc(&apic->timer.pending);
+ if (waitqueue_active(q))
+ {
+ apic->vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+ wake_up_interruptible(q);
+ }
+ if (apic_lvtt_period(apic)) {
+ result = 1;
+ apic->timer.dev.expires = ktime_add_ns(
+ apic->timer.dev.expires,
+ apic->timer.period);
+ }
+ return result;
+}
+
+static int __inject_apic_timer_irq(struct kvm_lapic *apic)
+{
+ int vector;
+
+ vector = apic_lvt_vector(apic, APIC_LVTT);
+ return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0);
+}
+
+static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)
+{
+ struct kvm_lapic *apic;
+ int restart_timer = 0;
+
+ apic = container_of(data, struct kvm_lapic, timer.dev);
+
+ restart_timer = __apic_timer_fn(apic);
+
+ if (restart_timer)
+ return HRTIMER_RESTART;
+ else
+ return HRTIMER_NORESTART;
+}
+
+int kvm_create_lapic(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic;
+
+ ASSERT(vcpu != NULL);
+ apic_debug("apic_init %d\n", vcpu->vcpu_id);
+
+ apic = kzalloc(sizeof(*apic), GFP_KERNEL);
+ if (!apic)
+ goto nomem;
+
+ vcpu->apic = apic;
+
+ apic->regs_page = alloc_page(GFP_KERNEL);
+ if (apic->regs_page == NULL) {
+ printk(KERN_ERR "malloc apic regs error for vcpu %x\n",
+ vcpu->vcpu_id);
+ goto nomem;
+ }
+ apic->regs = page_address(apic->regs_page);
+ memset(apic->regs, 0, PAGE_SIZE);
+ apic->vcpu = vcpu;
+
+ hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ apic->timer.dev.function = apic_timer_fn;
+ apic->base_address = APIC_DEFAULT_PHYS_BASE;
+ vcpu->apic_base = APIC_DEFAULT_PHYS_BASE;
+
+ kvm_lapic_reset(vcpu);
+ apic->dev.read = apic_mmio_read;
+ apic->dev.write = apic_mmio_write;
+ apic->dev.in_range = apic_mmio_range;
+ apic->dev.private = apic;
+
+ return 0;
+nomem:
+ kvm_free_apic(apic);
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(kvm_create_lapic);
+
+int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = vcpu->apic;
+ int highest_irr;
+
+ if (!apic || !apic_enabled(apic))
+ return -1;
+
+ apic_update_ppr(apic);
+ highest_irr = apic_find_highest_irr(apic);
+ if ((highest_irr == -1) ||
+ ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI)))
+ return -1;
+ return highest_irr;
+}
+
+int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
+{
+ u32 lvt0 = apic_get_reg(vcpu->apic, APIC_LVT0);
+ int r = 0;
+
+ if (vcpu->vcpu_id == 0) {
+ if (!apic_hw_enabled(vcpu->apic))
+ r = 1;
+ if ((lvt0 & APIC_LVT_MASKED) == 0 &&
+ GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
+ r = 1;
+ }
+ return r;
+}
+
+void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = vcpu->apic;
+
+ if (apic && apic_lvt_enabled(apic, APIC_LVTT) &&
+ atomic_read(&apic->timer.pending) > 0) {
+ if (__inject_apic_timer_irq(apic))
+ atomic_dec(&apic->timer.pending);
+ }
+}
+
+void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
+{
+ struct kvm_lapic *apic = vcpu->apic;
+
+ if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec)
+ apic->timer.last_update = ktime_add_ns(
+ apic->timer.last_update,
+ apic->timer.period);
+}
+
+int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
+{
+ int vector = kvm_apic_has_interrupt(vcpu);
+ struct kvm_lapic *apic = vcpu->apic;
+
+ if (vector == -1)
+ return -1;
+
+ apic_set_vector(vector, apic->regs + APIC_ISR);
+ apic_update_ppr(apic);
+ apic_clear_irr(vector, apic);
+ return vector;
+}
+
+void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = vcpu->apic;
+
+ apic->base_address = vcpu->apic_base &
+ MSR_IA32_APICBASE_BASE;
+ apic_set_reg(apic, APIC_LVR, APIC_VERSION);
+ apic_update_ppr(apic);
+ hrtimer_cancel(&apic->timer.dev);
+ update_divide_count(apic);
+ start_apic_timer(apic);
+}
+
+void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
+{
+ struct kvm_lapic *apic = vcpu->apic;
+ struct hrtimer *timer;
+
+ if (!apic)
+ return;
+
+ timer = &apic->timer.dev;
+ if (hrtimer_cancel(timer))
+ hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS);
+}
+EXPORT_SYMBOL_GPL(kvm_migrate_apic_timer);
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index 23965aa5ee7..feb5ac986c5 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -158,7 +158,7 @@ static struct kmem_cache *mmu_page_header_cache;
static int is_write_protection(struct kvm_vcpu *vcpu)
{
- return vcpu->cr0 & CR0_WP_MASK;
+ return vcpu->cr0 & X86_CR0_WP;
}
static int is_cpuid_PSE36(void)
@@ -202,15 +202,14 @@ static void set_shadow_pte(u64 *sptep, u64 spte)
}
static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
- struct kmem_cache *base_cache, int min,
- gfp_t gfp_flags)
+ struct kmem_cache *base_cache, int min)
{
void *obj;
if (cache->nobjs >= min)
return 0;
while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
- obj = kmem_cache_zalloc(base_cache, gfp_flags);
+ obj = kmem_cache_zalloc(base_cache, GFP_KERNEL);
if (!obj)
return -ENOMEM;
cache->objects[cache->nobjs++] = obj;
@@ -225,14 +224,14 @@ static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
}
static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
- int min, gfp_t gfp_flags)
+ int min)
{
struct page *page;
if (cache->nobjs >= min)
return 0;
while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
- page = alloc_page(gfp_flags);
+ page = alloc_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
set_page_private(page, 0);
@@ -247,44 +246,28 @@ static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc)
free_page((unsigned long)mc->objects[--mc->nobjs]);
}
-static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
+static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
{
int r;
+ kvm_mmu_free_some_pages(vcpu);
r = mmu_topup_memory_cache(&vcpu->mmu_pte_chain_cache,
- pte_chain_cache, 4, gfp_flags);
+ pte_chain_cache, 4);
if (r)
goto out;
r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache,
- rmap_desc_cache, 1, gfp_flags);
+ rmap_desc_cache, 1);
if (r)
goto out;
- r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4, gfp_flags);
+ r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4);
if (r)
goto out;
r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache,
- mmu_page_header_cache, 4, gfp_flags);
+ mmu_page_header_cache, 4);
out:
return r;
}
-static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
-{
- int r;
-
- r = __mmu_topup_memory_caches(vcpu, GFP_NOWAIT);
- kvm_mmu_free_some_pages(vcpu);
- if (r < 0) {
- spin_unlock(&vcpu->kvm->lock);
- kvm_arch_ops->vcpu_put(vcpu);
- r = __mmu_topup_memory_caches(vcpu, GFP_KERNEL);
- kvm_arch_ops->vcpu_load(vcpu);
- spin_lock(&vcpu->kvm->lock);
- kvm_mmu_free_some_pages(vcpu);
- }
- return r;
-}
-
static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
{
mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
@@ -969,7 +952,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu)
static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu)
{
++vcpu->stat.tlb_flush;
- kvm_arch_ops->tlb_flush(vcpu);
+ kvm_x86_ops->tlb_flush(vcpu);
}
static void paging_new_cr3(struct kvm_vcpu *vcpu)
@@ -982,7 +965,7 @@ static void inject_page_fault(struct kvm_vcpu *vcpu,
u64 addr,
u32 err_code)
{
- kvm_arch_ops->inject_page_fault(vcpu, addr, err_code);
+ kvm_x86_ops->inject_page_fault(vcpu, addr, err_code);
}
static void paging_free(struct kvm_vcpu *vcpu)
@@ -1066,20 +1049,21 @@ int kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
destroy_kvm_mmu(vcpu);
return init_kvm_mmu(vcpu);
}
+EXPORT_SYMBOL_GPL(kvm_mmu_reset_context);
int kvm_mmu_load(struct kvm_vcpu *vcpu)
{
int r;
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
r = mmu_topup_memory_caches(vcpu);
if (r)
goto out;
mmu_alloc_roots(vcpu);
- kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
+ kvm_x86_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
kvm_mmu_flush_tlb(vcpu);
out:
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
return r;
}
EXPORT_SYMBOL_GPL(kvm_mmu_load);
@@ -1105,7 +1089,7 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
mmu_page_remove_parent_pte(child, spte);
}
}
- *spte = 0;
+ set_shadow_pte(spte, 0);
kvm_flush_remote_tlbs(vcpu->kvm);
}
@@ -1124,7 +1108,7 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
}
void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
- const u8 *old, const u8 *new, int bytes)
+ const u8 *new, int bytes)
{
gfn_t gfn = gpa >> PAGE_SHIFT;
struct kvm_mmu_page *page;
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index 4b5391c717f..6b094b44f8f 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -58,7 +58,10 @@ struct guest_walker {
int level;
gfn_t table_gfn[PT_MAX_FULL_LEVELS];
pt_element_t *table;
+ pt_element_t pte;
pt_element_t *ptep;
+ struct page *page;
+ int index;
pt_element_t inherited_ar;
gfn_t gfn;
u32 error_code;
@@ -80,11 +83,14 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
pgprintk("%s: addr %lx\n", __FUNCTION__, addr);
walker->level = vcpu->mmu.root_level;
walker->table = NULL;
+ walker->page = NULL;
+ walker->ptep = NULL;
root = vcpu->cr3;
#if PTTYPE == 64
if (!is_long_mode(vcpu)) {
walker->ptep = &vcpu->pdptrs[(addr >> 30) & 3];
root = *walker->ptep;
+ walker->pte = root;
if (!(root & PT_PRESENT_MASK))
goto not_present;
--walker->level;
@@ -96,10 +102,11 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
walker->level - 1, table_gfn);
slot = gfn_to_memslot(vcpu->kvm, table_gfn);
hpa = safe_gpa_to_hpa(vcpu, root & PT64_BASE_ADDR_MASK);
- walker->table = kmap_atomic(pfn_to_page(hpa >> PAGE_SHIFT), KM_USER0);
+ walker->page = pfn_to_page(hpa >> PAGE_SHIFT);
+ walker->table = kmap_atomic(walker->page, KM_USER0);
ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) ||
- (vcpu->cr3 & ~(PAGE_MASK | CR3_FLAGS_MASK)) == 0);
+ (vcpu->cr3 & CR3_NONPAE_RESERVED_BITS) == 0);
walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK;
@@ -108,6 +115,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
hpa_t paddr;
ptep = &walker->table[index];
+ walker->index = index;
ASSERT(((unsigned long)walker->table & PAGE_MASK) ==
((unsigned long)ptep & PAGE_MASK));
@@ -148,16 +156,20 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
walker->inherited_ar &= walker->table[index];
table_gfn = (*ptep & PT_BASE_ADDR_MASK) >> PAGE_SHIFT;
- paddr = safe_gpa_to_hpa(vcpu, *ptep & PT_BASE_ADDR_MASK);
kunmap_atomic(walker->table, KM_USER0);
- walker->table = kmap_atomic(pfn_to_page(paddr >> PAGE_SHIFT),
- KM_USER0);
+ paddr = safe_gpa_to_hpa(vcpu, table_gfn << PAGE_SHIFT);
+ walker->page = pfn_to_page(paddr >> PAGE_SHIFT);
+ walker->table = kmap_atomic(walker->page, KM_USER0);
--walker->level;
walker->table_gfn[walker->level - 1 ] = table_gfn;
pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__,
walker->level - 1, table_gfn);
}
- walker->ptep = ptep;
+ walker->pte = *ptep;
+ if (walker->page)
+ walker->ptep = NULL;
+ if (walker->table)
+ kunmap_atomic(walker->table, KM_USER0);
pgprintk("%s: pte %llx\n", __FUNCTION__, (u64)*ptep);
return 1;
@@ -175,13 +187,9 @@ err:
walker->error_code |= PFERR_USER_MASK;
if (fetch_fault)
walker->error_code |= PFERR_FETCH_MASK;
- return 0;
-}
-
-static void FNAME(release_walker)(struct guest_walker *walker)
-{
if (walker->table)
kunmap_atomic(walker->table, KM_USER0);
+ return 0;
}
static void FNAME(mark_pagetable_dirty)(struct kvm *kvm,
@@ -193,7 +201,7 @@ static void FNAME(mark_pagetable_dirty)(struct kvm *kvm,
static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
u64 *shadow_pte,
gpa_t gaddr,
- pt_element_t *gpte,
+ pt_element_t gpte,
u64 access_bits,
int user_fault,
int write_fault,
@@ -202,23 +210,34 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
gfn_t gfn)
{
hpa_t paddr;
- int dirty = *gpte & PT_DIRTY_MASK;
+ int dirty = gpte & PT_DIRTY_MASK;
u64 spte = *shadow_pte;
int was_rmapped = is_rmap_pte(spte);
pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d"
" user_fault %d gfn %lx\n",
- __FUNCTION__, spte, (u64)*gpte, access_bits,
+ __FUNCTION__, spte, (u64)gpte, access_bits,
write_fault, user_fault, gfn);
if (write_fault && !dirty) {
- *gpte |= PT_DIRTY_MASK;
+ pt_element_t *guest_ent, *tmp = NULL;
+
+ if (walker->ptep)
+ guest_ent = walker->ptep;
+ else {
+ tmp = kmap_atomic(walker->page, KM_USER0);
+ guest_ent = &tmp[walker->index];
+ }
+
+ *guest_ent |= PT_DIRTY_MASK;
+ if (!walker->ptep)
+ kunmap_atomic(tmp, KM_USER0);
dirty = 1;
FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
}
spte |= PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_DIRTY_MASK;
- spte |= *gpte & PT64_NX_MASK;
+ spte |= gpte & PT64_NX_MASK;
if (!dirty)
access_bits &= ~PT_WRITABLE_MASK;
@@ -255,7 +274,7 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
access_bits &= ~PT_WRITABLE_MASK;
if (is_writeble_pte(spte)) {
spte &= ~PT_WRITABLE_MASK;
- kvm_arch_ops->tlb_flush(vcpu);
+ kvm_x86_ops->tlb_flush(vcpu);
}
if (write_fault)
*ptwrite = 1;
@@ -273,13 +292,13 @@ unshadowed:
rmap_add(vcpu, shadow_pte);
}
-static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t *gpte,
+static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte,
u64 *shadow_pte, u64 access_bits,
int user_fault, int write_fault, int *ptwrite,
struct guest_walker *walker, gfn_t gfn)
{
- access_bits &= *gpte;
- FNAME(set_pte_common)(vcpu, shadow_pte, *gpte & PT_BASE_ADDR_MASK,
+ access_bits &= gpte;
+ FNAME(set_pte_common)(vcpu, shadow_pte, gpte & PT_BASE_ADDR_MASK,
gpte, access_bits, user_fault, write_fault,
ptwrite, walker, gfn);
}
@@ -295,22 +314,22 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK))
return;
pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte);
- FNAME(set_pte)(vcpu, &gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0,
+ FNAME(set_pte)(vcpu, gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0,
0, NULL, NULL,
(gpte & PT_BASE_ADDR_MASK) >> PAGE_SHIFT);
}
-static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t *gpde,
+static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t gpde,
u64 *shadow_pte, u64 access_bits,
int user_fault, int write_fault, int *ptwrite,
struct guest_walker *walker, gfn_t gfn)
{
gpa_t gaddr;
- access_bits &= *gpde;
+ access_bits &= gpde;
gaddr = (gpa_t)gfn << PAGE_SHIFT;
if (PTTYPE == 32 && is_cpuid_PSE36())
- gaddr |= (*gpde & PT32_DIR_PSE36_MASK) <<
+ gaddr |= (gpde & PT32_DIR_PSE36_MASK) <<
(32 - PT32_DIR_PSE36_SHIFT);
FNAME(set_pte_common)(vcpu, shadow_pte, gaddr,
gpde, access_bits, user_fault, write_fault,
@@ -328,9 +347,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
int level;
u64 *shadow_ent;
u64 *prev_shadow_ent = NULL;
- pt_element_t *guest_ent = walker->ptep;
- if (!is_present_pte(*guest_ent))
+ if (!is_present_pte(walker->pte))
return NULL;
shadow_addr = vcpu->mmu.root_hpa;
@@ -364,12 +382,12 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
if (level - 1 == PT_PAGE_TABLE_LEVEL
&& walker->level == PT_DIRECTORY_LEVEL) {
metaphysical = 1;
- hugepage_access = *guest_ent;
+ hugepage_access = walker->pte;
hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK;
- if (*guest_ent & PT64_NX_MASK)
+ if (walker->pte & PT64_NX_MASK)
hugepage_access |= (1 << 2);
hugepage_access >>= PT_WRITABLE_SHIFT;
- table_gfn = (*guest_ent & PT_BASE_ADDR_MASK)
+ table_gfn = (walker->pte & PT_BASE_ADDR_MASK)
>> PAGE_SHIFT;
} else {
metaphysical = 0;
@@ -386,12 +404,12 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
}
if (walker->level == PT_DIRECTORY_LEVEL) {
- FNAME(set_pde)(vcpu, guest_ent, shadow_ent,
+ FNAME(set_pde)(vcpu, walker->pte, shadow_ent,
walker->inherited_ar, user_fault, write_fault,
ptwrite, walker, walker->gfn);
} else {
ASSERT(walker->level == PT_PAGE_TABLE_LEVEL);
- FNAME(set_pte)(vcpu, guest_ent, shadow_ent,
+ FNAME(set_pte)(vcpu, walker->pte, shadow_ent,
walker->inherited_ar, user_fault, write_fault,
ptwrite, walker, walker->gfn);
}
@@ -442,7 +460,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
if (!r) {
pgprintk("%s: guest page fault\n", __FUNCTION__);
inject_page_fault(vcpu, addr, walker.error_code);
- FNAME(release_walker)(&walker);
vcpu->last_pt_write_count = 0; /* reset fork detector */
return 0;
}
@@ -452,8 +469,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __FUNCTION__,
shadow_pte, *shadow_pte, write_pt);
- FNAME(release_walker)(&walker);
-
if (!write_pt)
vcpu->last_pt_write_count = 0; /* reset fork detector */
@@ -482,7 +497,6 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr)
gpa |= vaddr & ~PAGE_MASK;
}
- FNAME(release_walker)(&walker);
return gpa;
}
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index bc818cc126e..7a6eead63a6 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -16,12 +16,12 @@
#include "kvm_svm.h"
#include "x86_emulate.h"
+#include "irq.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/vmalloc.h>
#include <linux/highmem.h>
-#include <linux/profile.h>
#include <linux/sched.h>
#include <asm/desc.h>
@@ -38,7 +38,6 @@ MODULE_LICENSE("GPL");
#define DR7_GD_MASK (1 << 13)
#define DR6_BD_MASK (1 << 13)
-#define CR4_DE_MASK (1UL << 3)
#define SEG_TYPE_LDT 2
#define SEG_TYPE_BUSY_TSS16 3
@@ -50,6 +49,13 @@ MODULE_LICENSE("GPL");
#define SVM_FEATURE_LBRV (1 << 1)
#define SVM_DEATURE_SVML (1 << 2)
+static void kvm_reput_irq(struct vcpu_svm *svm);
+
+static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
+{
+ return container_of(vcpu, struct vcpu_svm, vcpu);
+}
+
unsigned long iopm_base;
unsigned long msrpm_base;
@@ -94,20 +100,6 @@ static inline u32 svm_has(u32 feat)
return svm_features & feat;
}
-static unsigned get_addr_size(struct kvm_vcpu *vcpu)
-{
- struct vmcb_save_area *sa = &vcpu->svm->vmcb->save;
- u16 cs_attrib;
-
- if (!(sa->cr0 & CR0_PE_MASK) || (sa->rflags & X86_EFLAGS_VM))
- return 2;
-
- cs_attrib = sa->cs.attrib;
-
- return (cs_attrib & SVM_SELECTOR_L_MASK) ? 8 :
- (cs_attrib & SVM_SELECTOR_DB_MASK) ? 4 : 2;
-}
-
static inline u8 pop_irq(struct kvm_vcpu *vcpu)
{
int word_index = __ffs(vcpu->irq_summary);
@@ -182,7 +174,7 @@ static inline void write_dr7(unsigned long val)
static inline void force_new_asid(struct kvm_vcpu *vcpu)
{
- vcpu->svm->asid_generation--;
+ to_svm(vcpu)->asid_generation--;
}
static inline void flush_guest_tlb(struct kvm_vcpu *vcpu)
@@ -195,22 +187,24 @@ static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
if (!(efer & KVM_EFER_LMA))
efer &= ~KVM_EFER_LME;
- vcpu->svm->vmcb->save.efer = efer | MSR_EFER_SVME_MASK;
+ to_svm(vcpu)->vmcb->save.efer = efer | MSR_EFER_SVME_MASK;
vcpu->shadow_efer = efer;
}
static void svm_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
{
- vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
SVM_EVTINJ_VALID_ERR |
SVM_EVTINJ_TYPE_EXEPT |
GP_VECTOR;
- vcpu->svm->vmcb->control.event_inj_err = error_code;
+ svm->vmcb->control.event_inj_err = error_code;
}
static void inject_ud(struct kvm_vcpu *vcpu)
{
- vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
+ to_svm(vcpu)->vmcb->control.event_inj = SVM_EVTINJ_VALID |
SVM_EVTINJ_TYPE_EXEPT |
UD_VECTOR;
}
@@ -229,19 +223,21 @@ static int is_external_interrupt(u32 info)
static void skip_emulated_instruction(struct kvm_vcpu *vcpu)
{
- if (!vcpu->svm->next_rip) {
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ if (!svm->next_rip) {
printk(KERN_DEBUG "%s: NOP\n", __FUNCTION__);
return;
}
- if (vcpu->svm->next_rip - vcpu->svm->vmcb->save.rip > 15) {
+ if (svm->next_rip - svm->vmcb->save.rip > MAX_INST_SIZE) {
printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n",
__FUNCTION__,
- vcpu->svm->vmcb->save.rip,
- vcpu->svm->next_rip);
+ svm->vmcb->save.rip,
+ svm->next_rip);
}
- vcpu->rip = vcpu->svm->vmcb->save.rip = vcpu->svm->next_rip;
- vcpu->svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
+ vcpu->rip = svm->vmcb->save.rip = svm->next_rip;
+ svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK;
vcpu->interrupt_window_open = 1;
}
@@ -351,8 +347,8 @@ err_1:
}
-static int set_msr_interception(u32 *msrpm, unsigned msr,
- int read, int write)
+static void set_msr_interception(u32 *msrpm, unsigned msr,
+ int read, int write)
{
int i;
@@ -367,11 +363,10 @@ static int set_msr_interception(u32 *msrpm, unsigned msr,
u32 mask = ((write) ? 0 : 2) | ((read) ? 0 : 1);
*base = (*base & ~(0x3 << msr_shift)) |
(mask << msr_shift);
- return 1;
+ return;
}
}
- printk(KERN_DEBUG "%s: not found 0x%x\n", __FUNCTION__, msr);
- return 0;
+ BUG();
}
static __init int svm_hardware_setup(void)
@@ -382,8 +377,6 @@ static __init int svm_hardware_setup(void)
void *iopm_va, *msrpm_va;
int r;
- kvm_emulator_want_group7_invlpg();
-
iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER);
if (!iopm_pages)
@@ -458,11 +451,6 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
seg->base = 0;
}
-static int svm_vcpu_setup(struct kvm_vcpu *vcpu)
-{
- return 0;
-}
-
static void init_vmcb(struct vmcb *vmcb)
{
struct vmcb_control_area *control = &vmcb->control;
@@ -506,6 +494,7 @@ static void init_vmcb(struct vmcb *vmcb)
*/
/* (1ULL << INTERCEPT_SELECTIVE_CR0) | */
(1ULL << INTERCEPT_CPUID) |
+ (1ULL << INTERCEPT_INVD) |
(1ULL << INTERCEPT_HLT) |
(1ULL << INTERCEPT_INVLPGA) |
(1ULL << INTERCEPT_IOIO_PROT) |
@@ -519,6 +508,7 @@ static void init_vmcb(struct vmcb *vmcb)
(1ULL << INTERCEPT_STGI) |
(1ULL << INTERCEPT_CLGI) |
(1ULL << INTERCEPT_SKINIT) |
+ (1ULL << INTERCEPT_WBINVD) |
(1ULL << INTERCEPT_MONITOR) |
(1ULL << INTERCEPT_MWAIT);
@@ -563,59 +553,89 @@ static void init_vmcb(struct vmcb *vmcb)
* cr0 val on cpu init should be 0x60000010, we enable cpu
* cache by default. the orderly way is to enable cache in bios.
*/
- save->cr0 = 0x00000010 | CR0_PG_MASK | CR0_WP_MASK;
- save->cr4 = CR4_PAE_MASK;
+ save->cr0 = 0x00000010 | X86_CR0_PG | X86_CR0_WP;
+ save->cr4 = X86_CR4_PAE;
/* rdx = ?? */
}
-static int svm_create_vcpu(struct kvm_vcpu *vcpu)
+static void svm_vcpu_reset(struct kvm_vcpu *vcpu)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ init_vmcb(svm->vmcb);
+
+ if (vcpu->vcpu_id != 0) {
+ svm->vmcb->save.rip = 0;
+ svm->vmcb->save.cs.base = svm->vcpu.sipi_vector << 12;
+ svm->vmcb->save.cs.selector = svm->vcpu.sipi_vector << 8;
+ }
+}
+
+static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
+{
+ struct vcpu_svm *svm;
struct page *page;
- int r;
+ int err;
+
+ svm = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+ if (!svm) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = kvm_vcpu_init(&svm->vcpu, kvm, id);
+ if (err)
+ goto free_svm;
+
+ if (irqchip_in_kernel(kvm)) {
+ err = kvm_create_lapic(&svm->vcpu);
+ if (err < 0)
+ goto free_svm;
+ }
- r = -ENOMEM;
- vcpu->svm = kzalloc(sizeof *vcpu->svm, GFP_KERNEL);
- if (!vcpu->svm)
- goto out1;
page = alloc_page(GFP_KERNEL);
- if (!page)
- goto out2;
-
- vcpu->svm->vmcb = page_address(page);
- clear_page(vcpu->svm->vmcb);
- vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
- vcpu->svm->asid_generation = 0;
- memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs));
- init_vmcb(vcpu->svm->vmcb);
-
- fx_init(vcpu);
- vcpu->fpu_active = 1;
- vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
- if (vcpu == &vcpu->kvm->vcpus[0])
- vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
+ if (!page) {
+ err = -ENOMEM;
+ goto uninit;
+ }
- return 0;
+ svm->vmcb = page_address(page);
+ clear_page(svm->vmcb);
+ svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
+ svm->asid_generation = 0;
+ memset(svm->db_regs, 0, sizeof(svm->db_regs));
+ init_vmcb(svm->vmcb);
-out2:
- kfree(vcpu->svm);
-out1:
- return r;
+ fx_init(&svm->vcpu);
+ svm->vcpu.fpu_active = 1;
+ svm->vcpu.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
+ if (svm->vcpu.vcpu_id == 0)
+ svm->vcpu.apic_base |= MSR_IA32_APICBASE_BSP;
+
+ return &svm->vcpu;
+
+uninit:
+ kvm_vcpu_uninit(&svm->vcpu);
+free_svm:
+ kmem_cache_free(kvm_vcpu_cache, svm);
+out:
+ return ERR_PTR(err);
}
static void svm_free_vcpu(struct kvm_vcpu *vcpu)
{
- if (!vcpu->svm)
- return;
- if (vcpu->svm->vmcb)
- __free_page(pfn_to_page(vcpu->svm->vmcb_pa >> PAGE_SHIFT));
- kfree(vcpu->svm);
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ __free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT));
+ kvm_vcpu_uninit(vcpu);
+ kmem_cache_free(kvm_vcpu_cache, svm);
}
-static void svm_vcpu_load(struct kvm_vcpu *vcpu)
+static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
- int cpu, i;
+ struct vcpu_svm *svm = to_svm(vcpu);
+ int i;
- cpu = get_cpu();
if (unlikely(cpu != vcpu->cpu)) {
u64 tsc_this, delta;
@@ -625,23 +645,24 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu)
*/
rdtscll(tsc_this);
delta = vcpu->host_tsc - tsc_this;
- vcpu->svm->vmcb->control.tsc_offset += delta;
+ svm->vmcb->control.tsc_offset += delta;
vcpu->cpu = cpu;
+ kvm_migrate_apic_timer(vcpu);
}
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
- rdmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]);
+ rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
}
static void svm_vcpu_put(struct kvm_vcpu *vcpu)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
int i;
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
- wrmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]);
+ wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
rdtscll(vcpu->host_tsc);
- put_cpu();
}
static void svm_vcpu_decache(struct kvm_vcpu *vcpu)
@@ -650,31 +671,34 @@ static void svm_vcpu_decache(struct kvm_vcpu *vcpu)
static void svm_cache_regs(struct kvm_vcpu *vcpu)
{
- vcpu->regs[VCPU_REGS_RAX] = vcpu->svm->vmcb->save.rax;
- vcpu->regs[VCPU_REGS_RSP] = vcpu->svm->vmcb->save.rsp;
- vcpu->rip = vcpu->svm->vmcb->save.rip;
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ vcpu->regs[VCPU_REGS_RAX] = svm->vmcb->save.rax;
+ vcpu->regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
+ vcpu->rip = svm->vmcb->save.rip;
}
static void svm_decache_regs(struct kvm_vcpu *vcpu)
{
- vcpu->svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX];
- vcpu->svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP];
- vcpu->svm->vmcb->save.rip = vcpu->rip;
+ struct vcpu_svm *svm = to_svm(vcpu);
+ svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX];
+ svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP];
+ svm->vmcb->save.rip = vcpu->rip;
}
static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu)
{
- return vcpu->svm->vmcb->save.rflags;
+ return to_svm(vcpu)->vmcb->save.rflags;
}
static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
{
- vcpu->svm->vmcb->save.rflags = rflags;
+ to_svm(vcpu)->vmcb->save.rflags = rflags;
}
static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg)
{
- struct vmcb_save_area *save = &vcpu->svm->vmcb->save;
+ struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save;
switch (seg) {
case VCPU_SREG_CS: return &save->cs;
@@ -716,36 +740,36 @@ static void svm_get_segment(struct kvm_vcpu *vcpu,
var->unusable = !var->present;
}
-static void svm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
-{
- struct vmcb_seg *s = svm_seg(vcpu, VCPU_SREG_CS);
-
- *db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1;
- *l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1;
-}
-
static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
{
- dt->limit = vcpu->svm->vmcb->save.idtr.limit;
- dt->base = vcpu->svm->vmcb->save.idtr.base;
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ dt->limit = svm->vmcb->save.idtr.limit;
+ dt->base = svm->vmcb->save.idtr.base;
}
static void svm_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
{
- vcpu->svm->vmcb->save.idtr.limit = dt->limit;
- vcpu->svm->vmcb->save.idtr.base = dt->base ;
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm->vmcb->save.idtr.limit = dt->limit;
+ svm->vmcb->save.idtr.base = dt->base ;
}
static void svm_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
{
- dt->limit = vcpu->svm->vmcb->save.gdtr.limit;
- dt->base = vcpu->svm->vmcb->save.gdtr.base;
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ dt->limit = svm->vmcb->save.gdtr.limit;
+ dt->base = svm->vmcb->save.gdtr.base;
}
static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
{
- vcpu->svm->vmcb->save.gdtr.limit = dt->limit;
- vcpu->svm->vmcb->save.gdtr.base = dt->base ;
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm->vmcb->save.gdtr.limit = dt->limit;
+ svm->vmcb->save.gdtr.base = dt->base ;
}
static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
@@ -754,39 +778,42 @@ static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
#ifdef CONFIG_X86_64
if (vcpu->shadow_efer & KVM_EFER_LME) {
- if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK)) {
+ if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
vcpu->shadow_efer |= KVM_EFER_LMA;
- vcpu->svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME;
+ svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME;
}
- if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK) ) {
+ if (is_paging(vcpu) && !(cr0 & X86_CR0_PG) ) {
vcpu->shadow_efer &= ~KVM_EFER_LMA;
- vcpu->svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME);
+ svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME);
}
}
#endif
- if ((vcpu->cr0 & CR0_TS_MASK) && !(cr0 & CR0_TS_MASK)) {
- vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
+ if ((vcpu->cr0 & X86_CR0_TS) && !(cr0 & X86_CR0_TS)) {
+ svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
vcpu->fpu_active = 1;
}
vcpu->cr0 = cr0;
- cr0 |= CR0_PG_MASK | CR0_WP_MASK;
- cr0 &= ~(CR0_CD_MASK | CR0_NW_MASK);
- vcpu->svm->vmcb->save.cr0 = cr0;
+ cr0 |= X86_CR0_PG | X86_CR0_WP;
+ cr0 &= ~(X86_CR0_CD | X86_CR0_NW);
+ svm->vmcb->save.cr0 = cr0;
}
static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
{
vcpu->cr4 = cr4;
- vcpu->svm->vmcb->save.cr4 = cr4 | CR4_PAE_MASK;
+ to_svm(vcpu)->vmcb->save.cr4 = cr4 | X86_CR4_PAE;
}
static void svm_set_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
struct vmcb_seg *s = svm_seg(vcpu, seg);
s->base = var->base;
@@ -805,16 +832,16 @@ static void svm_set_segment(struct kvm_vcpu *vcpu,
s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
}
if (seg == VCPU_SREG_CS)
- vcpu->svm->vmcb->save.cpl
- = (vcpu->svm->vmcb->save.cs.attrib
+ svm->vmcb->save.cpl
+ = (svm->vmcb->save.cs.attrib
>> SVM_SELECTOR_DPL_SHIFT) & 3;
}
/* FIXME:
- vcpu->svm->vmcb->control.int_ctl &= ~V_TPR_MASK;
- vcpu->svm->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK);
+ svm(vcpu)->vmcb->control.int_ctl &= ~V_TPR_MASK;
+ svm(vcpu)->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK);
*/
@@ -823,61 +850,68 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
return -EOPNOTSUPP;
}
+static int svm_get_irq(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u32 exit_int_info = svm->vmcb->control.exit_int_info;
+
+ if (is_external_interrupt(exit_int_info))
+ return exit_int_info & SVM_EVTINJ_VEC_MASK;
+ return -1;
+}
+
static void load_host_msrs(struct kvm_vcpu *vcpu)
{
#ifdef CONFIG_X86_64
- wrmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base);
+ wrmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base);
#endif
}
static void save_host_msrs(struct kvm_vcpu *vcpu)
{
#ifdef CONFIG_X86_64
- rdmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base);
+ rdmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base);
#endif
}
-static void new_asid(struct kvm_vcpu *vcpu, struct svm_cpu_data *svm_data)
+static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data)
{
if (svm_data->next_asid > svm_data->max_asid) {
++svm_data->asid_generation;
svm_data->next_asid = 1;
- vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
+ svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID;
}
- vcpu->cpu = svm_data->cpu;
- vcpu->svm->asid_generation = svm_data->asid_generation;
- vcpu->svm->vmcb->control.asid = svm_data->next_asid++;
-}
-
-static void svm_invlpg(struct kvm_vcpu *vcpu, gva_t address)
-{
- invlpga(address, vcpu->svm->vmcb->control.asid); // is needed?
+ svm->vcpu.cpu = svm_data->cpu;
+ svm->asid_generation = svm_data->asid_generation;
+ svm->vmcb->control.asid = svm_data->next_asid++;
}
static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr)
{
- return vcpu->svm->db_regs[dr];
+ return to_svm(vcpu)->db_regs[dr];
}
static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
int *exception)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
*exception = 0;
- if (vcpu->svm->vmcb->save.dr7 & DR7_GD_MASK) {
- vcpu->svm->vmcb->save.dr7 &= ~DR7_GD_MASK;
- vcpu->svm->vmcb->save.dr6 |= DR6_BD_MASK;
+ if (svm->vmcb->save.dr7 & DR7_GD_MASK) {
+ svm->vmcb->save.dr7 &= ~DR7_GD_MASK;
+ svm->vmcb->save.dr6 |= DR6_BD_MASK;
*exception = DB_VECTOR;
return;
}
switch (dr) {
case 0 ... 3:
- vcpu->svm->db_regs[dr] = value;
+ svm->db_regs[dr] = value;
return;
case 4 ... 5:
- if (vcpu->cr4 & CR4_DE_MASK) {
+ if (vcpu->cr4 & X86_CR4_DE) {
*exception = UD_VECTOR;
return;
}
@@ -886,7 +920,7 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
*exception = GP_VECTOR;
return;
}
- vcpu->svm->vmcb->save.dr7 = value;
+ svm->vmcb->save.dr7 = value;
return;
}
default:
@@ -897,42 +931,44 @@ static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value,
}
}
-static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- u32 exit_int_info = vcpu->svm->vmcb->control.exit_int_info;
+ u32 exit_int_info = svm->vmcb->control.exit_int_info;
+ struct kvm *kvm = svm->vcpu.kvm;
u64 fault_address;
u32 error_code;
enum emulation_result er;
int r;
- if (is_external_interrupt(exit_int_info))
- push_irq(vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
+ if (!irqchip_in_kernel(kvm) &&
+ is_external_interrupt(exit_int_info))
+ push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&kvm->lock);
- fault_address = vcpu->svm->vmcb->control.exit_info_2;
- error_code = vcpu->svm->vmcb->control.exit_info_1;
- r = kvm_mmu_page_fault(vcpu, fault_address, error_code);
+ fault_address = svm->vmcb->control.exit_info_2;
+ error_code = svm->vmcb->control.exit_info_1;
+ r = kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code);
if (r < 0) {
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&kvm->lock);
return r;
}
if (!r) {
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&kvm->lock);
return 1;
}
- er = emulate_instruction(vcpu, kvm_run, fault_address, error_code);
- spin_unlock(&vcpu->kvm->lock);
+ er = emulate_instruction(&svm->vcpu, kvm_run, fault_address,
+ error_code);
+ mutex_unlock(&kvm->lock);
switch (er) {
case EMULATE_DONE:
return 1;
case EMULATE_DO_MMIO:
- ++vcpu->stat.mmio_exits;
- kvm_run->exit_reason = KVM_EXIT_MMIO;
+ ++svm->vcpu.stat.mmio_exits;
return 0;
case EMULATE_FAIL:
- vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__);
+ kvm_report_emulation_failure(&svm->vcpu, "pagetable");
break;
default:
BUG();
@@ -942,252 +978,142 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 0;
}
-static int nm_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
- if (!(vcpu->cr0 & CR0_TS_MASK))
- vcpu->svm->vmcb->save.cr0 &= ~CR0_TS_MASK;
- vcpu->fpu_active = 1;
+ svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
+ if (!(svm->vcpu.cr0 & X86_CR0_TS))
+ svm->vmcb->save.cr0 &= ~X86_CR0_TS;
+ svm->vcpu.fpu_active = 1;
- return 1;
+ return 1;
}
-static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
/*
* VMCB is undefined after a SHUTDOWN intercept
* so reinitialize it.
*/
- clear_page(vcpu->svm->vmcb);
- init_vmcb(vcpu->svm->vmcb);
+ clear_page(svm->vmcb);
+ init_vmcb(svm->vmcb);
kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
return 0;
}
-static int io_get_override(struct kvm_vcpu *vcpu,
- struct vmcb_seg **seg,
- int *addr_override)
-{
- u8 inst[MAX_INST_SIZE];
- unsigned ins_length;
- gva_t rip;
- int i;
-
- rip = vcpu->svm->vmcb->save.rip;
- ins_length = vcpu->svm->next_rip - rip;
- rip += vcpu->svm->vmcb->save.cs.base;
-
- if (ins_length > MAX_INST_SIZE)
- printk(KERN_DEBUG
- "%s: inst length err, cs base 0x%llx rip 0x%llx "
- "next rip 0x%llx ins_length %u\n",
- __FUNCTION__,
- vcpu->svm->vmcb->save.cs.base,
- vcpu->svm->vmcb->save.rip,
- vcpu->svm->vmcb->control.exit_info_2,
- ins_length);
-
- if (kvm_read_guest(vcpu, rip, ins_length, inst) != ins_length)
- /* #PF */
- return 0;
-
- *addr_override = 0;
- *seg = NULL;
- for (i = 0; i < ins_length; i++)
- switch (inst[i]) {
- case 0xf0:
- case 0xf2:
- case 0xf3:
- case 0x66:
- continue;
- case 0x67:
- *addr_override = 1;
- continue;
- case 0x2e:
- *seg = &vcpu->svm->vmcb->save.cs;
- continue;
- case 0x36:
- *seg = &vcpu->svm->vmcb->save.ss;
- continue;
- case 0x3e:
- *seg = &vcpu->svm->vmcb->save.ds;
- continue;
- case 0x26:
- *seg = &vcpu->svm->vmcb->save.es;
- continue;
- case 0x64:
- *seg = &vcpu->svm->vmcb->save.fs;
- continue;
- case 0x65:
- *seg = &vcpu->svm->vmcb->save.gs;
- continue;
- default:
- return 1;
- }
- printk(KERN_DEBUG "%s: unexpected\n", __FUNCTION__);
- return 0;
-}
-
-static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, gva_t *address)
+static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- unsigned long addr_mask;
- unsigned long *reg;
- struct vmcb_seg *seg;
- int addr_override;
- struct vmcb_save_area *save_area = &vcpu->svm->vmcb->save;
- u16 cs_attrib = save_area->cs.attrib;
- unsigned addr_size = get_addr_size(vcpu);
-
- if (!io_get_override(vcpu, &seg, &addr_override))
- return 0;
-
- if (addr_override)
- addr_size = (addr_size == 2) ? 4: (addr_size >> 1);
+ u32 io_info = svm->vmcb->control.exit_info_1; //address size bug?
+ int size, down, in, string, rep;
+ unsigned port;
- if (ins) {
- reg = &vcpu->regs[VCPU_REGS_RDI];
- seg = &vcpu->svm->vmcb->save.es;
- } else {
- reg = &vcpu->regs[VCPU_REGS_RSI];
- seg = (seg) ? seg : &vcpu->svm->vmcb->save.ds;
- }
+ ++svm->vcpu.stat.io_exits;
- addr_mask = ~0ULL >> (64 - (addr_size * 8));
+ svm->next_rip = svm->vmcb->control.exit_info_2;
- if ((cs_attrib & SVM_SELECTOR_L_MASK) &&
- !(vcpu->svm->vmcb->save.rflags & X86_EFLAGS_VM)) {
- *address = (*reg & addr_mask);
- return addr_mask;
- }
+ string = (io_info & SVM_IOIO_STR_MASK) != 0;
- if (!(seg->attrib & SVM_SELECTOR_P_SHIFT)) {
- svm_inject_gp(vcpu, 0);
- return 0;
+ if (string) {
+ if (emulate_instruction(&svm->vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO)
+ return 0;
+ return 1;
}
- *address = (*reg & addr_mask) + seg->base;
- return addr_mask;
-}
-
-static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
-{
- u32 io_info = vcpu->svm->vmcb->control.exit_info_1; //address size bug?
- int size, down, in, string, rep;
- unsigned port;
- unsigned long count;
- gva_t address = 0;
-
- ++vcpu->stat.io_exits;
-
- vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2;
-
in = (io_info & SVM_IOIO_TYPE_MASK) != 0;
port = io_info >> 16;
size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
- string = (io_info & SVM_IOIO_STR_MASK) != 0;
rep = (io_info & SVM_IOIO_REP_MASK) != 0;
- count = 1;
- down = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0;
-
- if (string) {
- unsigned addr_mask;
+ down = (svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0;
- addr_mask = io_adress(vcpu, in, &address);
- if (!addr_mask) {
- printk(KERN_DEBUG "%s: get io address failed\n",
- __FUNCTION__);
- return 1;
- }
-
- if (rep)
- count = vcpu->regs[VCPU_REGS_RCX] & addr_mask;
- }
- return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down,
- address, rep, port);
+ return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port);
}
-static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
return 1;
}
-static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int halt_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1;
- skip_emulated_instruction(vcpu);
- return kvm_emulate_halt(vcpu);
+ svm->next_rip = svm->vmcb->save.rip + 1;
+ skip_emulated_instruction(&svm->vcpu);
+ return kvm_emulate_halt(&svm->vcpu);
}
-static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int vmmcall_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 3;
- skip_emulated_instruction(vcpu);
- return kvm_hypercall(vcpu, kvm_run);
+ svm->next_rip = svm->vmcb->save.rip + 3;
+ skip_emulated_instruction(&svm->vcpu);
+ return kvm_hypercall(&svm->vcpu, kvm_run);
}
-static int invalid_op_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int invalid_op_interception(struct vcpu_svm *svm,
+ struct kvm_run *kvm_run)
{
- inject_ud(vcpu);
+ inject_ud(&svm->vcpu);
return 1;
}
-static int task_switch_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int task_switch_interception(struct vcpu_svm *svm,
+ struct kvm_run *kvm_run)
{
- printk(KERN_DEBUG "%s: task swiche is unsupported\n", __FUNCTION__);
+ pr_unimpl(&svm->vcpu, "%s: task switch is unsupported\n", __FUNCTION__);
kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
return 0;
}
-static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
- kvm_emulate_cpuid(vcpu);
+ svm->next_rip = svm->vmcb->save.rip + 2;
+ kvm_emulate_cpuid(&svm->vcpu);
return 1;
}
-static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int emulate_on_interception(struct vcpu_svm *svm,
+ struct kvm_run *kvm_run)
{
- if (emulate_instruction(vcpu, NULL, 0, 0) != EMULATE_DONE)
- printk(KERN_ERR "%s: failed\n", __FUNCTION__);
+ if (emulate_instruction(&svm->vcpu, NULL, 0, 0) != EMULATE_DONE)
+ pr_unimpl(&svm->vcpu, "%s: failed\n", __FUNCTION__);
return 1;
}
static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
switch (ecx) {
case MSR_IA32_TIME_STAMP_COUNTER: {
u64 tsc;
rdtscll(tsc);
- *data = vcpu->svm->vmcb->control.tsc_offset + tsc;
+ *data = svm->vmcb->control.tsc_offset + tsc;
break;
}
case MSR_K6_STAR:
- *data = vcpu->svm->vmcb->save.star;
+ *data = svm->vmcb->save.star;
break;
#ifdef CONFIG_X86_64
case MSR_LSTAR:
- *data = vcpu->svm->vmcb->save.lstar;
+ *data = svm->vmcb->save.lstar;
break;
case MSR_CSTAR:
- *data = vcpu->svm->vmcb->save.cstar;
+ *data = svm->vmcb->save.cstar;
break;
case MSR_KERNEL_GS_BASE:
- *data = vcpu->svm->vmcb->save.kernel_gs_base;
+ *data = svm->vmcb->save.kernel_gs_base;
break;
case MSR_SYSCALL_MASK:
- *data = vcpu->svm->vmcb->save.sfmask;
+ *data = svm->vmcb->save.sfmask;
break;
#endif
case MSR_IA32_SYSENTER_CS:
- *data = vcpu->svm->vmcb->save.sysenter_cs;
+ *data = svm->vmcb->save.sysenter_cs;
break;
case MSR_IA32_SYSENTER_EIP:
- *data = vcpu->svm->vmcb->save.sysenter_eip;
+ *data = svm->vmcb->save.sysenter_eip;
break;
case MSR_IA32_SYSENTER_ESP:
- *data = vcpu->svm->vmcb->save.sysenter_esp;
+ *data = svm->vmcb->save.sysenter_esp;
break;
default:
return kvm_get_msr_common(vcpu, ecx, data);
@@ -1195,57 +1121,59 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
return 0;
}
-static int rdmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int rdmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- u32 ecx = vcpu->regs[VCPU_REGS_RCX];
+ u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX];
u64 data;
- if (svm_get_msr(vcpu, ecx, &data))
- svm_inject_gp(vcpu, 0);
+ if (svm_get_msr(&svm->vcpu, ecx, &data))
+ svm_inject_gp(&svm->vcpu, 0);
else {
- vcpu->svm->vmcb->save.rax = data & 0xffffffff;
- vcpu->regs[VCPU_REGS_RDX] = data >> 32;
- vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
- skip_emulated_instruction(vcpu);
+ svm->vmcb->save.rax = data & 0xffffffff;
+ svm->vcpu.regs[VCPU_REGS_RDX] = data >> 32;
+ svm->next_rip = svm->vmcb->save.rip + 2;
+ skip_emulated_instruction(&svm->vcpu);
}
return 1;
}
static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
switch (ecx) {
case MSR_IA32_TIME_STAMP_COUNTER: {
u64 tsc;
rdtscll(tsc);
- vcpu->svm->vmcb->control.tsc_offset = data - tsc;
+ svm->vmcb->control.tsc_offset = data - tsc;
break;
}
case MSR_K6_STAR:
- vcpu->svm->vmcb->save.star = data;
+ svm->vmcb->save.star = data;
break;
#ifdef CONFIG_X86_64
case MSR_LSTAR:
- vcpu->svm->vmcb->save.lstar = data;
+ svm->vmcb->save.lstar = data;
break;
case MSR_CSTAR:
- vcpu->svm->vmcb->save.cstar = data;
+ svm->vmcb->save.cstar = data;
break;
case MSR_KERNEL_GS_BASE:
- vcpu->svm->vmcb->save.kernel_gs_base = data;
+ svm->vmcb->save.kernel_gs_base = data;
break;
case MSR_SYSCALL_MASK:
- vcpu->svm->vmcb->save.sfmask = data;
+ svm->vmcb->save.sfmask = data;
break;
#endif
case MSR_IA32_SYSENTER_CS:
- vcpu->svm->vmcb->save.sysenter_cs = data;
+ svm->vmcb->save.sysenter_cs = data;
break;
case MSR_IA32_SYSENTER_EIP:
- vcpu->svm->vmcb->save.sysenter_eip = data;
+ svm->vmcb->save.sysenter_eip = data;
break;
case MSR_IA32_SYSENTER_ESP:
- vcpu->svm->vmcb->save.sysenter_esp = data;
+ svm->vmcb->save.sysenter_esp = data;
break;
default:
return kvm_set_msr_common(vcpu, ecx, data);
@@ -1253,37 +1181,39 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
return 0;
}
-static int wrmsr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- u32 ecx = vcpu->regs[VCPU_REGS_RCX];
- u64 data = (vcpu->svm->vmcb->save.rax & -1u)
- | ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32);
- vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
- if (svm_set_msr(vcpu, ecx, data))
- svm_inject_gp(vcpu, 0);
+ u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX];
+ u64 data = (svm->vmcb->save.rax & -1u)
+ | ((u64)(svm->vcpu.regs[VCPU_REGS_RDX] & -1u) << 32);
+ svm->next_rip = svm->vmcb->save.rip + 2;
+ if (svm_set_msr(&svm->vcpu, ecx, data))
+ svm_inject_gp(&svm->vcpu, 0);
else
- skip_emulated_instruction(vcpu);
+ skip_emulated_instruction(&svm->vcpu);
return 1;
}
-static int msr_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
{
- if (vcpu->svm->vmcb->control.exit_info_1)
- return wrmsr_interception(vcpu, kvm_run);
+ if (svm->vmcb->control.exit_info_1)
+ return wrmsr_interception(svm, kvm_run);
else
- return rdmsr_interception(vcpu, kvm_run);
+ return rdmsr_interception(svm, kvm_run);
}
-static int interrupt_window_interception(struct kvm_vcpu *vcpu,
+static int interrupt_window_interception(struct vcpu_svm *svm,
struct kvm_run *kvm_run)
{
+ svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR);
+ svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
/*
* If the user space waits to inject interrupts, exit as soon as
* possible
*/
if (kvm_run->request_interrupt_window &&
- !vcpu->irq_summary) {
- ++vcpu->stat.irq_window_exits;
+ !svm->vcpu.irq_summary) {
+ ++svm->vcpu.stat.irq_window_exits;
kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
return 0;
}
@@ -1291,7 +1221,7 @@ static int interrupt_window_interception(struct kvm_vcpu *vcpu,
return 1;
}
-static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
+static int (*svm_exit_handlers[])(struct vcpu_svm *svm,
struct kvm_run *kvm_run) = {
[SVM_EXIT_READ_CR0] = emulate_on_interception,
[SVM_EXIT_READ_CR3] = emulate_on_interception,
@@ -1319,6 +1249,7 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
[SVM_EXIT_VINTR] = interrupt_window_interception,
/* [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, */
[SVM_EXIT_CPUID] = cpuid_interception,
+ [SVM_EXIT_INVD] = emulate_on_interception,
[SVM_EXIT_HLT] = halt_interception,
[SVM_EXIT_INVLPG] = emulate_on_interception,
[SVM_EXIT_INVLPGA] = invalid_op_interception,
@@ -1333,20 +1264,31 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
[SVM_EXIT_STGI] = invalid_op_interception,
[SVM_EXIT_CLGI] = invalid_op_interception,
[SVM_EXIT_SKINIT] = invalid_op_interception,
+ [SVM_EXIT_WBINVD] = emulate_on_interception,
[SVM_EXIT_MONITOR] = invalid_op_interception,
[SVM_EXIT_MWAIT] = invalid_op_interception,
};
-static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
{
- u32 exit_code = vcpu->svm->vmcb->control.exit_code;
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u32 exit_code = svm->vmcb->control.exit_code;
+
+ kvm_reput_irq(svm);
- if (is_external_interrupt(vcpu->svm->vmcb->control.exit_int_info) &&
+ if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
+ kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+ kvm_run->fail_entry.hardware_entry_failure_reason
+ = svm->vmcb->control.exit_code;
+ return 0;
+ }
+
+ if (is_external_interrupt(svm->vmcb->control.exit_int_info) &&
exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR)
printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x "
"exit_code 0x%x\n",
- __FUNCTION__, vcpu->svm->vmcb->control.exit_int_info,
+ __FUNCTION__, svm->vmcb->control.exit_int_info,
exit_code);
if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
@@ -1356,7 +1298,7 @@ static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 0;
}
- return svm_exit_handlers[exit_code](vcpu, kvm_run);
+ return svm_exit_handlers[exit_code](svm, kvm_run);
}
static void reload_tss(struct kvm_vcpu *vcpu)
@@ -1368,93 +1310,126 @@ static void reload_tss(struct kvm_vcpu *vcpu)
load_TR_desc();
}
-static void pre_svm_run(struct kvm_vcpu *vcpu)
+static void pre_svm_run(struct vcpu_svm *svm)
{
int cpu = raw_smp_processor_id();
struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu);
- vcpu->svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
- if (vcpu->cpu != cpu ||
- vcpu->svm->asid_generation != svm_data->asid_generation)
- new_asid(vcpu, svm_data);
+ svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING;
+ if (svm->vcpu.cpu != cpu ||
+ svm->asid_generation != svm_data->asid_generation)
+ new_asid(svm, svm_data);
}
-static inline void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
+static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
{
struct vmcb_control_area *control;
- control = &vcpu->svm->vmcb->control;
- control->int_vector = pop_irq(vcpu);
+ control = &svm->vmcb->control;
+ control->int_vector = irq;
control->int_ctl &= ~V_INTR_PRIO_MASK;
control->int_ctl |= V_IRQ_MASK |
((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT);
}
-static void kvm_reput_irq(struct kvm_vcpu *vcpu)
+static void svm_set_irq(struct kvm_vcpu *vcpu, int irq)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm_inject_irq(svm, irq);
+}
+
+static void svm_intr_assist(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ struct vmcb *vmcb = svm->vmcb;
+ int intr_vector = -1;
+
+ kvm_inject_pending_timer_irqs(vcpu);
+ if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) &&
+ ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) {
+ intr_vector = vmcb->control.exit_int_info &
+ SVM_EVTINJ_VEC_MASK;
+ vmcb->control.exit_int_info = 0;
+ svm_inject_irq(svm, intr_vector);
+ return;
+ }
+
+ if (vmcb->control.int_ctl & V_IRQ_MASK)
+ return;
+
+ if (!kvm_cpu_has_interrupt(vcpu))
+ return;
+
+ if (!(vmcb->save.rflags & X86_EFLAGS_IF) ||
+ (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) ||
+ (vmcb->control.event_inj & SVM_EVTINJ_VALID)) {
+ /* unable to deliver irq, set pending irq */
+ vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR);
+ svm_inject_irq(svm, 0x0);
+ return;
+ }
+ /* Okay, we can deliver the interrupt: grab it and update PIC state. */
+ intr_vector = kvm_cpu_get_interrupt(vcpu);
+ svm_inject_irq(svm, intr_vector);
+ kvm_timer_intr_post(vcpu, intr_vector);
+}
+
+static void kvm_reput_irq(struct vcpu_svm *svm)
{
- struct vmcb_control_area *control = &vcpu->svm->vmcb->control;
+ struct vmcb_control_area *control = &svm->vmcb->control;
- if (control->int_ctl & V_IRQ_MASK) {
+ if ((control->int_ctl & V_IRQ_MASK)
+ && !irqchip_in_kernel(svm->vcpu.kvm)) {
control->int_ctl &= ~V_IRQ_MASK;
- push_irq(vcpu, control->int_vector);
+ push_irq(&svm->vcpu, control->int_vector);
}
- vcpu->interrupt_window_open =
+ svm->vcpu.interrupt_window_open =
!(control->int_state & SVM_INTERRUPT_SHADOW_MASK);
}
+static void svm_do_inject_vector(struct vcpu_svm *svm)
+{
+ struct kvm_vcpu *vcpu = &svm->vcpu;
+ int word_index = __ffs(vcpu->irq_summary);
+ int bit_index = __ffs(vcpu->irq_pending[word_index]);
+ int irq = word_index * BITS_PER_LONG + bit_index;
+
+ clear_bit(bit_index, &vcpu->irq_pending[word_index]);
+ if (!vcpu->irq_pending[word_index])
+ clear_bit(word_index, &vcpu->irq_summary);
+ svm_inject_irq(svm, irq);
+}
+
static void do_interrupt_requests(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run)
{
- struct vmcb_control_area *control = &vcpu->svm->vmcb->control;
+ struct vcpu_svm *svm = to_svm(vcpu);
+ struct vmcb_control_area *control = &svm->vmcb->control;
- vcpu->interrupt_window_open =
+ svm->vcpu.interrupt_window_open =
(!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) &&
- (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF));
+ (svm->vmcb->save.rflags & X86_EFLAGS_IF));
- if (vcpu->interrupt_window_open && vcpu->irq_summary)
+ if (svm->vcpu.interrupt_window_open && svm->vcpu.irq_summary)
/*
* If interrupts enabled, and not blocked by sti or mov ss. Good.
*/
- kvm_do_inject_irq(vcpu);
+ svm_do_inject_vector(svm);
/*
* Interrupts blocked. Wait for unblock.
*/
- if (!vcpu->interrupt_window_open &&
- (vcpu->irq_summary || kvm_run->request_interrupt_window)) {
+ if (!svm->vcpu.interrupt_window_open &&
+ (svm->vcpu.irq_summary || kvm_run->request_interrupt_window)) {
control->intercept |= 1ULL << INTERCEPT_VINTR;
} else
control->intercept &= ~(1ULL << INTERCEPT_VINTR);
}
-static void post_kvm_run_save(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
-{
- kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open &&
- vcpu->irq_summary == 0);
- kvm_run->if_flag = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF) != 0;
- kvm_run->cr8 = vcpu->cr8;
- kvm_run->apic_base = vcpu->apic_base;
-}
-
-/*
- * Check if userspace requested an interrupt window, and that the
- * interrupt window is open.
- *
- * No need to exit to userspace if we already have an interrupt queued.
- */
-static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
-{
- return (!vcpu->irq_summary &&
- kvm_run->request_interrupt_window &&
- vcpu->interrupt_window_open &&
- (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_IF));
-}
-
static void save_db_regs(unsigned long *db_regs)
{
asm volatile ("mov %%dr0, %0" : "=r"(db_regs[0]));
@@ -1476,49 +1451,37 @@ static void svm_flush_tlb(struct kvm_vcpu *vcpu)
force_new_asid(vcpu);
}
-static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu)
{
+}
+
+static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
u16 fs_selector;
u16 gs_selector;
u16 ldt_selector;
- int r;
-
-again:
- r = kvm_mmu_reload(vcpu);
- if (unlikely(r))
- return r;
- if (!vcpu->mmio_read_completed)
- do_interrupt_requests(vcpu, kvm_run);
-
- clgi();
-
- vcpu->guest_mode = 1;
- if (vcpu->requests)
- if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
- svm_flush_tlb(vcpu);
-
- pre_svm_run(vcpu);
+ pre_svm_run(svm);
save_host_msrs(vcpu);
fs_selector = read_fs();
gs_selector = read_gs();
ldt_selector = read_ldt();
- vcpu->svm->host_cr2 = kvm_read_cr2();
- vcpu->svm->host_dr6 = read_dr6();
- vcpu->svm->host_dr7 = read_dr7();
- vcpu->svm->vmcb->save.cr2 = vcpu->cr2;
+ svm->host_cr2 = kvm_read_cr2();
+ svm->host_dr6 = read_dr6();
+ svm->host_dr7 = read_dr7();
+ svm->vmcb->save.cr2 = vcpu->cr2;
- if (vcpu->svm->vmcb->save.dr7 & 0xff) {
+ if (svm->vmcb->save.dr7 & 0xff) {
write_dr7(0);
- save_db_regs(vcpu->svm->host_db_regs);
- load_db_regs(vcpu->svm->db_regs);
+ save_db_regs(svm->host_db_regs);
+ load_db_regs(svm->db_regs);
}
- if (vcpu->fpu_active) {
- fx_save(vcpu->host_fx_image);
- fx_restore(vcpu->guest_fx_image);
- }
+ clgi();
+
+ local_irq_enable();
asm volatile (
#ifdef CONFIG_X86_64
@@ -1532,34 +1495,33 @@ again:
#endif
#ifdef CONFIG_X86_64
- "mov %c[rbx](%[vcpu]), %%rbx \n\t"
- "mov %c[rcx](%[vcpu]), %%rcx \n\t"
- "mov %c[rdx](%[vcpu]), %%rdx \n\t"
- "mov %c[rsi](%[vcpu]), %%rsi \n\t"
- "mov %c[rdi](%[vcpu]), %%rdi \n\t"
- "mov %c[rbp](%[vcpu]), %%rbp \n\t"
- "mov %c[r8](%[vcpu]), %%r8 \n\t"
- "mov %c[r9](%[vcpu]), %%r9 \n\t"
- "mov %c[r10](%[vcpu]), %%r10 \n\t"
- "mov %c[r11](%[vcpu]), %%r11 \n\t"
- "mov %c[r12](%[vcpu]), %%r12 \n\t"
- "mov %c[r13](%[vcpu]), %%r13 \n\t"
- "mov %c[r14](%[vcpu]), %%r14 \n\t"
- "mov %c[r15](%[vcpu]), %%r15 \n\t"
+ "mov %c[rbx](%[svm]), %%rbx \n\t"
+ "mov %c[rcx](%[svm]), %%rcx \n\t"
+ "mov %c[rdx](%[svm]), %%rdx \n\t"
+ "mov %c[rsi](%[svm]), %%rsi \n\t"
+ "mov %c[rdi](%[svm]), %%rdi \n\t"
+ "mov %c[rbp](%[svm]), %%rbp \n\t"
+ "mov %c[r8](%[svm]), %%r8 \n\t"
+ "mov %c[r9](%[svm]), %%r9 \n\t"
+ "mov %c[r10](%[svm]), %%r10 \n\t"
+ "mov %c[r11](%[svm]), %%r11 \n\t"
+ "mov %c[r12](%[svm]), %%r12 \n\t"
+ "mov %c[r13](%[svm]), %%r13 \n\t"
+ "mov %c[r14](%[svm]), %%r14 \n\t"
+ "mov %c[r15](%[svm]), %%r15 \n\t"
#else
- "mov %c[rbx](%[vcpu]), %%ebx \n\t"
- "mov %c[rcx](%[vcpu]), %%ecx \n\t"
- "mov %c[rdx](%[vcpu]), %%edx \n\t"
- "mov %c[rsi](%[vcpu]), %%esi \n\t"
- "mov %c[rdi](%[vcpu]), %%edi \n\t"
- "mov %c[rbp](%[vcpu]), %%ebp \n\t"
+ "mov %c[rbx](%[svm]), %%ebx \n\t"
+ "mov %c[rcx](%[svm]), %%ecx \n\t"
+ "mov %c[rdx](%[svm]), %%edx \n\t"
+ "mov %c[rsi](%[svm]), %%esi \n\t"
+ "mov %c[rdi](%[svm]), %%edi \n\t"
+ "mov %c[rbp](%[svm]), %%ebp \n\t"
#endif
#ifdef CONFIG_X86_64
/* Enter guest mode */
"push %%rax \n\t"
- "mov %c[svm](%[vcpu]), %%rax \n\t"
- "mov %c[vmcb](%%rax), %%rax \n\t"
+ "mov %c[vmcb](%[svm]), %%rax \n\t"
SVM_VMLOAD "\n\t"
SVM_VMRUN "\n\t"
SVM_VMSAVE "\n\t"
@@ -1567,8 +1529,7 @@ again:
#else
/* Enter guest mode */
"push %%eax \n\t"
- "mov %c[svm](%[vcpu]), %%eax \n\t"
- "mov %c[vmcb](%%eax), %%eax \n\t"
+ "mov %c[vmcb](%[svm]), %%eax \n\t"
SVM_VMLOAD "\n\t"
SVM_VMRUN "\n\t"
SVM_VMSAVE "\n\t"
@@ -1577,73 +1538,65 @@ again:
/* Save guest registers, load host registers */
#ifdef CONFIG_X86_64
- "mov %%rbx, %c[rbx](%[vcpu]) \n\t"
- "mov %%rcx, %c[rcx](%[vcpu]) \n\t"
- "mov %%rdx, %c[rdx](%[vcpu]) \n\t"
- "mov %%rsi, %c[rsi](%[vcpu]) \n\t"
- "mov %%rdi, %c[rdi](%[vcpu]) \n\t"
- "mov %%rbp, %c[rbp](%[vcpu]) \n\t"
- "mov %%r8, %c[r8](%[vcpu]) \n\t"
- "mov %%r9, %c[r9](%[vcpu]) \n\t"
- "mov %%r10, %c[r10](%[vcpu]) \n\t"
- "mov %%r11, %c[r11](%[vcpu]) \n\t"
- "mov %%r12, %c[r12](%[vcpu]) \n\t"
- "mov %%r13, %c[r13](%[vcpu]) \n\t"
- "mov %%r14, %c[r14](%[vcpu]) \n\t"
- "mov %%r15, %c[r15](%[vcpu]) \n\t"
+ "mov %%rbx, %c[rbx](%[svm]) \n\t"
+ "mov %%rcx, %c[rcx](%[svm]) \n\t"
+ "mov %%rdx, %c[rdx](%[svm]) \n\t"
+ "mov %%rsi, %c[rsi](%[svm]) \n\t"
+ "mov %%rdi, %c[rdi](%[svm]) \n\t"
+ "mov %%rbp, %c[rbp](%[svm]) \n\t"
+ "mov %%r8, %c[r8](%[svm]) \n\t"
+ "mov %%r9, %c[r9](%[svm]) \n\t"
+ "mov %%r10, %c[r10](%[svm]) \n\t"
+ "mov %%r11, %c[r11](%[svm]) \n\t"
+ "mov %%r12, %c[r12](%[svm]) \n\t"
+ "mov %%r13, %c[r13](%[svm]) \n\t"
+ "mov %%r14, %c[r14](%[svm]) \n\t"
+ "mov %%r15, %c[r15](%[svm]) \n\t"
"pop %%r15; pop %%r14; pop %%r13; pop %%r12;"
"pop %%r11; pop %%r10; pop %%r9; pop %%r8;"
"pop %%rbp; pop %%rdi; pop %%rsi;"
"pop %%rdx; pop %%rcx; pop %%rbx; \n\t"
#else
- "mov %%ebx, %c[rbx](%[vcpu]) \n\t"
- "mov %%ecx, %c[rcx](%[vcpu]) \n\t"
- "mov %%edx, %c[rdx](%[vcpu]) \n\t"
- "mov %%esi, %c[rsi](%[vcpu]) \n\t"
- "mov %%edi, %c[rdi](%[vcpu]) \n\t"
- "mov %%ebp, %c[rbp](%[vcpu]) \n\t"
+ "mov %%ebx, %c[rbx](%[svm]) \n\t"
+ "mov %%ecx, %c[rcx](%[svm]) \n\t"
+ "mov %%edx, %c[rdx](%[svm]) \n\t"
+ "mov %%esi, %c[rsi](%[svm]) \n\t"
+ "mov %%edi, %c[rdi](%[svm]) \n\t"
+ "mov %%ebp, %c[rbp](%[svm]) \n\t"
"pop %%ebp; pop %%edi; pop %%esi;"
"pop %%edx; pop %%ecx; pop %%ebx; \n\t"
#endif
:
- : [vcpu]"a"(vcpu),
- [svm]"i"(offsetof(struct kvm_vcpu, svm)),
+ : [svm]"a"(svm),
[vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)),
- [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])),
- [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])),
- [rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])),
- [rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])),
- [rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])),
- [rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP]))
+ [rbx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBX])),
+ [rcx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RCX])),
+ [rdx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDX])),
+ [rsi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RSI])),
+ [rdi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDI])),
+ [rbp]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBP]))
#ifdef CONFIG_X86_64
- ,[r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])),
- [r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])),
- [r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])),
- [r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])),
- [r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])),
- [r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])),
- [r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])),
- [r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15]))
+ ,[r8 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R8])),
+ [r9 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R9 ])),
+ [r10]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R10])),
+ [r11]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R11])),
+ [r12]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R12])),
+ [r13]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R13])),
+ [r14]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R14])),
+ [r15]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R15]))
#endif
: "cc", "memory" );
- vcpu->guest_mode = 0;
-
- if (vcpu->fpu_active) {
- fx_save(vcpu->guest_fx_image);
- fx_restore(vcpu->host_fx_image);
- }
-
- if ((vcpu->svm->vmcb->save.dr7 & 0xff))
- load_db_regs(vcpu->svm->host_db_regs);
+ if ((svm->vmcb->save.dr7 & 0xff))
+ load_db_regs(svm->host_db_regs);
- vcpu->cr2 = vcpu->svm->vmcb->save.cr2;
+ vcpu->cr2 = svm->vmcb->save.cr2;
- write_dr6(vcpu->svm->host_dr6);
- write_dr7(vcpu->svm->host_dr7);
- kvm_write_cr2(vcpu->svm->host_cr2);
+ write_dr6(svm->host_dr6);
+ write_dr7(svm->host_dr7);
+ kvm_write_cr2(svm->host_cr2);
load_fs(fs_selector);
load_gs(gs_selector);
@@ -1652,57 +1605,23 @@ again:
reload_tss(vcpu);
- /*
- * Profile KVM exit RIPs:
- */
- if (unlikely(prof_on == KVM_PROFILING))
- profile_hit(KVM_PROFILING,
- (void *)(unsigned long)vcpu->svm->vmcb->save.rip);
+ local_irq_disable();
stgi();
- kvm_reput_irq(vcpu);
-
- vcpu->svm->next_rip = 0;
-
- if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
- kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
- kvm_run->fail_entry.hardware_entry_failure_reason
- = vcpu->svm->vmcb->control.exit_code;
- post_kvm_run_save(vcpu, kvm_run);
- return 0;
- }
-
- r = handle_exit(vcpu, kvm_run);
- if (r > 0) {
- if (signal_pending(current)) {
- ++vcpu->stat.signal_exits;
- post_kvm_run_save(vcpu, kvm_run);
- kvm_run->exit_reason = KVM_EXIT_INTR;
- return -EINTR;
- }
-
- if (dm_request_for_irq_injection(vcpu, kvm_run)) {
- ++vcpu->stat.request_irq_exits;
- post_kvm_run_save(vcpu, kvm_run);
- kvm_run->exit_reason = KVM_EXIT_INTR;
- return -EINTR;
- }
- kvm_resched(vcpu);
- goto again;
- }
- post_kvm_run_save(vcpu, kvm_run);
- return r;
+ svm->next_rip = 0;
}
static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
{
- vcpu->svm->vmcb->save.cr3 = root;
+ struct vcpu_svm *svm = to_svm(vcpu);
+
+ svm->vmcb->save.cr3 = root;
force_new_asid(vcpu);
if (vcpu->fpu_active) {
- vcpu->svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR);
- vcpu->svm->vmcb->save.cr0 |= CR0_TS_MASK;
+ svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR);
+ svm->vmcb->save.cr0 |= X86_CR0_TS;
vcpu->fpu_active = 0;
}
}
@@ -1711,26 +1630,27 @@ static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
unsigned long addr,
uint32_t err_code)
{
- uint32_t exit_int_info = vcpu->svm->vmcb->control.exit_int_info;
+ struct vcpu_svm *svm = to_svm(vcpu);
+ uint32_t exit_int_info = svm->vmcb->control.exit_int_info;
++vcpu->stat.pf_guest;
if (is_page_fault(exit_int_info)) {
- vcpu->svm->vmcb->control.event_inj_err = 0;
- vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
- SVM_EVTINJ_VALID_ERR |
- SVM_EVTINJ_TYPE_EXEPT |
- DF_VECTOR;
+ svm->vmcb->control.event_inj_err = 0;
+ svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
+ SVM_EVTINJ_VALID_ERR |
+ SVM_EVTINJ_TYPE_EXEPT |
+ DF_VECTOR;
return;
}
vcpu->cr2 = addr;
- vcpu->svm->vmcb->save.cr2 = addr;
- vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
- SVM_EVTINJ_VALID_ERR |
- SVM_EVTINJ_TYPE_EXEPT |
- PF_VECTOR;
- vcpu->svm->vmcb->control.event_inj_err = err_code;
+ svm->vmcb->save.cr2 = addr;
+ svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
+ SVM_EVTINJ_VALID_ERR |
+ SVM_EVTINJ_TYPE_EXEPT |
+ PF_VECTOR;
+ svm->vmcb->control.event_inj_err = err_code;
}
@@ -1757,17 +1677,25 @@ svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
hypercall[3] = 0xc3;
}
-static struct kvm_arch_ops svm_arch_ops = {
+static void svm_check_processor_compat(void *rtn)
+{
+ *(int *)rtn = 0;
+}
+
+static struct kvm_x86_ops svm_x86_ops = {
.cpu_has_kvm_support = has_svm,
.disabled_by_bios = is_disabled,
.hardware_setup = svm_hardware_setup,
.hardware_unsetup = svm_hardware_unsetup,
+ .check_processor_compatibility = svm_check_processor_compat,
.hardware_enable = svm_hardware_enable,
.hardware_disable = svm_hardware_disable,
.vcpu_create = svm_create_vcpu,
.vcpu_free = svm_free_vcpu,
+ .vcpu_reset = svm_vcpu_reset,
+ .prepare_guest_switch = svm_prepare_guest_switch,
.vcpu_load = svm_vcpu_load,
.vcpu_put = svm_vcpu_put,
.vcpu_decache = svm_vcpu_decache,
@@ -1778,7 +1706,7 @@ static struct kvm_arch_ops svm_arch_ops = {
.get_segment_base = svm_get_segment_base,
.get_segment = svm_get_segment,
.set_segment = svm_set_segment,
- .get_cs_db_l_bits = svm_get_cs_db_l_bits,
+ .get_cs_db_l_bits = kvm_get_cs_db_l_bits,
.decache_cr4_guest_bits = svm_decache_cr4_guest_bits,
.set_cr0 = svm_set_cr0,
.set_cr3 = svm_set_cr3,
@@ -1795,26 +1723,30 @@ static struct kvm_arch_ops svm_arch_ops = {
.get_rflags = svm_get_rflags,
.set_rflags = svm_set_rflags,
- .invlpg = svm_invlpg,
.tlb_flush = svm_flush_tlb,
.inject_page_fault = svm_inject_page_fault,
.inject_gp = svm_inject_gp,
.run = svm_vcpu_run,
+ .handle_exit = handle_exit,
.skip_emulated_instruction = skip_emulated_instruction,
- .vcpu_setup = svm_vcpu_setup,
.patch_hypercall = svm_patch_hypercall,
+ .get_irq = svm_get_irq,
+ .set_irq = svm_set_irq,
+ .inject_pending_irq = svm_intr_assist,
+ .inject_pending_vectors = do_interrupt_requests,
};
static int __init svm_init(void)
{
- return kvm_init_arch(&svm_arch_ops, THIS_MODULE);
+ return kvm_init_x86(&svm_x86_ops, sizeof(struct vcpu_svm),
+ THIS_MODULE);
}
static void __exit svm_exit(void)
{
- kvm_exit_arch();
+ kvm_exit_x86();
}
module_init(svm_init)
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index 80628f69916..bb56ae3f89b 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -16,6 +16,8 @@
*/
#include "kvm.h"
+#include "x86_emulate.h"
+#include "irq.h"
#include "vmx.h"
#include "segment_descriptor.h"
@@ -23,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/highmem.h>
-#include <linux/profile.h>
#include <linux/sched.h>
#include <asm/io.h>
@@ -32,6 +33,39 @@
MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
+struct vmcs {
+ u32 revision_id;
+ u32 abort;
+ char data[0];
+};
+
+struct vcpu_vmx {
+ struct kvm_vcpu vcpu;
+ int launched;
+ u8 fail;
+ struct kvm_msr_entry *guest_msrs;
+ struct kvm_msr_entry *host_msrs;
+ int nmsrs;
+ int save_nmsrs;
+ int msr_offset_efer;
+#ifdef CONFIG_X86_64
+ int msr_offset_kernel_gs_base;
+#endif
+ struct vmcs *vmcs;
+ struct {
+ int loaded;
+ u16 fs_sel, gs_sel, ldt_sel;
+ int gs_ldt_reload_needed;
+ int fs_reload_needed;
+ }host_state;
+
+};
+
+static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
+{
+ return container_of(vcpu, struct vcpu_vmx, vcpu);
+}
+
static int init_rmode_tss(struct kvm *kvm);
static DEFINE_PER_CPU(struct vmcs *, vmxarea);
@@ -40,18 +74,17 @@ static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
static struct page *vmx_io_bitmap_a;
static struct page *vmx_io_bitmap_b;
-#ifdef CONFIG_X86_64
-#define HOST_IS_64 1
-#else
-#define HOST_IS_64 0
-#endif
#define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE)
-static struct vmcs_descriptor {
+static struct vmcs_config {
int size;
int order;
u32 revision_id;
-} vmcs_descriptor;
+ u32 pin_based_exec_ctrl;
+ u32 cpu_based_exec_ctrl;
+ u32 vmexit_ctrl;
+ u32 vmentry_ctrl;
+} vmcs_config;
#define VMX_SEGMENT_FIELD(seg) \
[VCPU_SREG_##seg] = { \
@@ -89,16 +122,32 @@ static const u32 vmx_msr_index[] = {
};
#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
-static inline u64 msr_efer_save_restore_bits(struct vmx_msr_entry msr)
+static void load_msrs(struct kvm_msr_entry *e, int n)
+{
+ int i;
+
+ for (i = 0; i < n; ++i)
+ wrmsrl(e[i].index, e[i].data);
+}
+
+static void save_msrs(struct kvm_msr_entry *e, int n)
+{
+ int i;
+
+ for (i = 0; i < n; ++i)
+ rdmsrl(e[i].index, e[i].data);
+}
+
+static inline u64 msr_efer_save_restore_bits(struct kvm_msr_entry msr)
{
return (u64)msr.data & EFER_SAVE_RESTORE_BITS;
}
-static inline int msr_efer_need_save_restore(struct kvm_vcpu *vcpu)
+static inline int msr_efer_need_save_restore(struct vcpu_vmx *vmx)
{
- int efer_offset = vcpu->msr_offset_efer;
- return msr_efer_save_restore_bits(vcpu->host_msrs[efer_offset]) !=
- msr_efer_save_restore_bits(vcpu->guest_msrs[efer_offset]);
+ int efer_offset = vmx->msr_offset_efer;
+ return msr_efer_save_restore_bits(vmx->host_msrs[efer_offset]) !=
+ msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]);
}
static inline int is_page_fault(u32 intr_info)
@@ -121,23 +170,33 @@ static inline int is_external_interrupt(u32 intr_info)
== (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
}
-static int __find_msr_index(struct kvm_vcpu *vcpu, u32 msr)
+static inline int cpu_has_vmx_tpr_shadow(void)
+{
+ return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW);
+}
+
+static inline int vm_need_tpr_shadow(struct kvm *kvm)
+{
+ return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm)));
+}
+
+static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr)
{
int i;
- for (i = 0; i < vcpu->nmsrs; ++i)
- if (vcpu->guest_msrs[i].index == msr)
+ for (i = 0; i < vmx->nmsrs; ++i)
+ if (vmx->guest_msrs[i].index == msr)
return i;
return -1;
}
-static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr)
+static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr)
{
int i;
- i = __find_msr_index(vcpu, msr);
+ i = __find_msr_index(vmx, msr);
if (i >= 0)
- return &vcpu->guest_msrs[i];
+ return &vmx->guest_msrs[i];
return NULL;
}
@@ -156,23 +215,24 @@ static void vmcs_clear(struct vmcs *vmcs)
static void __vcpu_clear(void *arg)
{
- struct kvm_vcpu *vcpu = arg;
+ struct vcpu_vmx *vmx = arg;
int cpu = raw_smp_processor_id();
- if (vcpu->cpu == cpu)
- vmcs_clear(vcpu->vmcs);
- if (per_cpu(current_vmcs, cpu) == vcpu->vmcs)
+ if (vmx->vcpu.cpu == cpu)
+ vmcs_clear(vmx->vmcs);
+ if (per_cpu(current_vmcs, cpu) == vmx->vmcs)
per_cpu(current_vmcs, cpu) = NULL;
- rdtscll(vcpu->host_tsc);
+ rdtscll(vmx->vcpu.host_tsc);
}
-static void vcpu_clear(struct kvm_vcpu *vcpu)
+static void vcpu_clear(struct vcpu_vmx *vmx)
{
- if (vcpu->cpu != raw_smp_processor_id() && vcpu->cpu != -1)
- smp_call_function_single(vcpu->cpu, __vcpu_clear, vcpu, 0, 1);
+ if (vmx->vcpu.cpu != raw_smp_processor_id() && vmx->vcpu.cpu != -1)
+ smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear,
+ vmx, 0, 1);
else
- __vcpu_clear(vcpu);
- vcpu->launched = 0;
+ __vcpu_clear(vmx);
+ vmx->launched = 0;
}
static unsigned long vmcs_readl(unsigned long field)
@@ -282,121 +342,122 @@ static void reload_tss(void)
#endif
}
-static void load_transition_efer(struct kvm_vcpu *vcpu)
+static void load_transition_efer(struct vcpu_vmx *vmx)
{
u64 trans_efer;
- int efer_offset = vcpu->msr_offset_efer;
+ int efer_offset = vmx->msr_offset_efer;
- trans_efer = vcpu->host_msrs[efer_offset].data;
+ trans_efer = vmx->host_msrs[efer_offset].data;
trans_efer &= ~EFER_SAVE_RESTORE_BITS;
- trans_efer |= msr_efer_save_restore_bits(
- vcpu->guest_msrs[efer_offset]);
+ trans_efer |= msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]);
wrmsrl(MSR_EFER, trans_efer);
- vcpu->stat.efer_reload++;
+ vmx->vcpu.stat.efer_reload++;
}
static void vmx_save_host_state(struct kvm_vcpu *vcpu)
{
- struct vmx_host_state *hs = &vcpu->vmx_host_state;
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
- if (hs->loaded)
+ if (vmx->host_state.loaded)
return;
- hs->loaded = 1;
+ vmx->host_state.loaded = 1;
/*
* Set host fs and gs selectors. Unfortunately, 22.2.3 does not
* allow segment selectors with cpl > 0 or ti == 1.
*/
- hs->ldt_sel = read_ldt();
- hs->fs_gs_ldt_reload_needed = hs->ldt_sel;
- hs->fs_sel = read_fs();
- if (!(hs->fs_sel & 7))
- vmcs_write16(HOST_FS_SELECTOR, hs->fs_sel);
- else {
+ vmx->host_state.ldt_sel = read_ldt();
+ vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel;
+ vmx->host_state.fs_sel = read_fs();
+ if (!(vmx->host_state.fs_sel & 7)) {
+ vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel);
+ vmx->host_state.fs_reload_needed = 0;
+ } else {
vmcs_write16(HOST_FS_SELECTOR, 0);
- hs->fs_gs_ldt_reload_needed = 1;
+ vmx->host_state.fs_reload_needed = 1;
}
- hs->gs_sel = read_gs();
- if (!(hs->gs_sel & 7))
- vmcs_write16(HOST_GS_SELECTOR, hs->gs_sel);
+ vmx->host_state.gs_sel = read_gs();
+ if (!(vmx->host_state.gs_sel & 7))
+ vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel);
else {
vmcs_write16(HOST_GS_SELECTOR, 0);
- hs->fs_gs_ldt_reload_needed = 1;
+ vmx->host_state.gs_ldt_reload_needed = 1;
}
#ifdef CONFIG_X86_64
vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE));
vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE));
#else
- vmcs_writel(HOST_FS_BASE, segment_base(hs->fs_sel));
- vmcs_writel(HOST_GS_BASE, segment_base(hs->gs_sel));
+ vmcs_writel(HOST_FS_BASE, segment_base(vmx->host_state.fs_sel));
+ vmcs_writel(HOST_GS_BASE, segment_base(vmx->host_state.gs_sel));
#endif
#ifdef CONFIG_X86_64
- if (is_long_mode(vcpu)) {
- save_msrs(vcpu->host_msrs + vcpu->msr_offset_kernel_gs_base, 1);
+ if (is_long_mode(&vmx->vcpu)) {
+ save_msrs(vmx->host_msrs +
+ vmx->msr_offset_kernel_gs_base, 1);
}
#endif
- load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
- if (msr_efer_need_save_restore(vcpu))
- load_transition_efer(vcpu);
+ load_msrs(vmx->guest_msrs, vmx->save_nmsrs);
+ if (msr_efer_need_save_restore(vmx))
+ load_transition_efer(vmx);
}
-static void vmx_load_host_state(struct kvm_vcpu *vcpu)
+static void vmx_load_host_state(struct vcpu_vmx *vmx)
{
- struct vmx_host_state *hs = &vcpu->vmx_host_state;
+ unsigned long flags;
- if (!hs->loaded)
+ if (!vmx->host_state.loaded)
return;
- hs->loaded = 0;
- if (hs->fs_gs_ldt_reload_needed) {
- load_ldt(hs->ldt_sel);
- load_fs(hs->fs_sel);
+ vmx->host_state.loaded = 0;
+ if (vmx->host_state.fs_reload_needed)
+ load_fs(vmx->host_state.fs_sel);
+ if (vmx->host_state.gs_ldt_reload_needed) {
+ load_ldt(vmx->host_state.ldt_sel);
/*
* If we have to reload gs, we must take care to
* preserve our gs base.
*/
- local_irq_disable();
- load_gs(hs->gs_sel);
+ local_irq_save(flags);
+ load_gs(vmx->host_state.gs_sel);
#ifdef CONFIG_X86_64
wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
#endif
- local_irq_enable();
-
- reload_tss();
+ local_irq_restore(flags);
}
- save_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
- load_msrs(vcpu->host_msrs, vcpu->save_nmsrs);
- if (msr_efer_need_save_restore(vcpu))
- load_msrs(vcpu->host_msrs + vcpu->msr_offset_efer, 1);
+ reload_tss();
+ save_msrs(vmx->guest_msrs, vmx->save_nmsrs);
+ load_msrs(vmx->host_msrs, vmx->save_nmsrs);
+ if (msr_efer_need_save_restore(vmx))
+ load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1);
}
/*
* Switches to specified vcpu, until a matching vcpu_put(), but assumes
* vcpu mutex is already taken.
*/
-static void vmx_vcpu_load(struct kvm_vcpu *vcpu)
+static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
- u64 phys_addr = __pa(vcpu->vmcs);
- int cpu;
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ u64 phys_addr = __pa(vmx->vmcs);
u64 tsc_this, delta;
- cpu = get_cpu();
-
- if (vcpu->cpu != cpu)
- vcpu_clear(vcpu);
+ if (vcpu->cpu != cpu) {
+ vcpu_clear(vmx);
+ kvm_migrate_apic_timer(vcpu);
+ }
- if (per_cpu(current_vmcs, cpu) != vcpu->vmcs) {
+ if (per_cpu(current_vmcs, cpu) != vmx->vmcs) {
u8 error;
- per_cpu(current_vmcs, cpu) = vcpu->vmcs;
+ per_cpu(current_vmcs, cpu) = vmx->vmcs;
asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0"
: "=g"(error) : "a"(&phys_addr), "m"(phys_addr)
: "cc");
if (error)
printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n",
- vcpu->vmcs, phys_addr);
+ vmx->vmcs, phys_addr);
}
if (vcpu->cpu != cpu) {
@@ -426,9 +487,8 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu)
static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
{
- vmx_load_host_state(vcpu);
+ vmx_load_host_state(to_vmx(vcpu));
kvm_put_guest_fpu(vcpu);
- put_cpu();
}
static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
@@ -436,9 +496,9 @@ static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
if (vcpu->fpu_active)
return;
vcpu->fpu_active = 1;
- vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
- if (vcpu->cr0 & CR0_TS_MASK)
- vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+ vmcs_clear_bits(GUEST_CR0, X86_CR0_TS);
+ if (vcpu->cr0 & X86_CR0_TS)
+ vmcs_set_bits(GUEST_CR0, X86_CR0_TS);
update_exception_bitmap(vcpu);
}
@@ -447,13 +507,13 @@ static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu)
if (!vcpu->fpu_active)
return;
vcpu->fpu_active = 0;
- vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+ vmcs_set_bits(GUEST_CR0, X86_CR0_TS);
update_exception_bitmap(vcpu);
}
static void vmx_vcpu_decache(struct kvm_vcpu *vcpu)
{
- vcpu_clear(vcpu);
+ vcpu_clear(to_vmx(vcpu));
}
static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
@@ -463,6 +523,8 @@ static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
{
+ if (vcpu->rmode.active)
+ rflags |= IOPL_MASK | X86_EFLAGS_VM;
vmcs_writel(GUEST_RFLAGS, rflags);
}
@@ -501,59 +563,62 @@ static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
/*
* Swap MSR entry in host/guest MSR entry array.
*/
-void move_msr_up(struct kvm_vcpu *vcpu, int from, int to)
+#ifdef CONFIG_X86_64
+static void move_msr_up(struct vcpu_vmx *vmx, int from, int to)
{
- struct vmx_msr_entry tmp;
- tmp = vcpu->guest_msrs[to];
- vcpu->guest_msrs[to] = vcpu->guest_msrs[from];
- vcpu->guest_msrs[from] = tmp;
- tmp = vcpu->host_msrs[to];
- vcpu->host_msrs[to] = vcpu->host_msrs[from];
- vcpu->host_msrs[from] = tmp;
+ struct kvm_msr_entry tmp;
+
+ tmp = vmx->guest_msrs[to];
+ vmx->guest_msrs[to] = vmx->guest_msrs[from];
+ vmx->guest_msrs[from] = tmp;
+ tmp = vmx->host_msrs[to];
+ vmx->host_msrs[to] = vmx->host_msrs[from];
+ vmx->host_msrs[from] = tmp;
}
+#endif
/*
* Set up the vmcs to automatically save and restore system
* msrs. Don't touch the 64-bit msrs if the guest is in legacy
* mode, as fiddling with msrs is very expensive.
*/
-static void setup_msrs(struct kvm_vcpu *vcpu)
+static void setup_msrs(struct vcpu_vmx *vmx)
{
int save_nmsrs;
save_nmsrs = 0;
#ifdef CONFIG_X86_64
- if (is_long_mode(vcpu)) {
+ if (is_long_mode(&vmx->vcpu)) {
int index;
- index = __find_msr_index(vcpu, MSR_SYSCALL_MASK);
+ index = __find_msr_index(vmx, MSR_SYSCALL_MASK);
if (index >= 0)
- move_msr_up(vcpu, index, save_nmsrs++);
- index = __find_msr_index(vcpu, MSR_LSTAR);
+ move_msr_up(vmx, index, save_nmsrs++);
+ index = __find_msr_index(vmx, MSR_LSTAR);
if (index >= 0)
- move_msr_up(vcpu, index, save_nmsrs++);
- index = __find_msr_index(vcpu, MSR_CSTAR);
+ move_msr_up(vmx, index, save_nmsrs++);
+ index = __find_msr_index(vmx, MSR_CSTAR);
if (index >= 0)
- move_msr_up(vcpu, index, save_nmsrs++);
- index = __find_msr_index(vcpu, MSR_KERNEL_GS_BASE);
+ move_msr_up(vmx, index, save_nmsrs++);
+ index = __find_msr_index(vmx, MSR_KERNEL_GS_BASE);
if (index >= 0)
- move_msr_up(vcpu, index, save_nmsrs++);
+ move_msr_up(vmx, index, save_nmsrs++);
/*
* MSR_K6_STAR is only needed on long mode guests, and only
* if efer.sce is enabled.
*/
- index = __find_msr_index(vcpu, MSR_K6_STAR);
- if ((index >= 0) && (vcpu->shadow_efer & EFER_SCE))
- move_msr_up(vcpu, index, save_nmsrs++);
+ index = __find_msr_index(vmx, MSR_K6_STAR);
+ if ((index >= 0) && (vmx->vcpu.shadow_efer & EFER_SCE))
+ move_msr_up(vmx, index, save_nmsrs++);
}
#endif
- vcpu->save_nmsrs = save_nmsrs;
+ vmx->save_nmsrs = save_nmsrs;
#ifdef CONFIG_X86_64
- vcpu->msr_offset_kernel_gs_base =
- __find_msr_index(vcpu, MSR_KERNEL_GS_BASE);
+ vmx->msr_offset_kernel_gs_base =
+ __find_msr_index(vmx, MSR_KERNEL_GS_BASE);
#endif
- vcpu->msr_offset_efer = __find_msr_index(vcpu, MSR_EFER);
+ vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER);
}
/*
@@ -589,7 +654,7 @@ static void guest_write_tsc(u64 guest_tsc)
static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
{
u64 data;
- struct vmx_msr_entry *msr;
+ struct kvm_msr_entry *msr;
if (!pdata) {
printk(KERN_ERR "BUG: get_msr called with NULL pdata\n");
@@ -620,7 +685,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
data = vmcs_readl(GUEST_SYSENTER_ESP);
break;
default:
- msr = find_msr_entry(vcpu, msr_index);
+ msr = find_msr_entry(to_vmx(vcpu), msr_index);
if (msr) {
data = msr->data;
break;
@@ -639,15 +704,16 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
*/
static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
{
- struct vmx_msr_entry *msr;
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ struct kvm_msr_entry *msr;
int ret = 0;
switch (msr_index) {
#ifdef CONFIG_X86_64
case MSR_EFER:
ret = kvm_set_msr_common(vcpu, msr_index, data);
- if (vcpu->vmx_host_state.loaded)
- load_transition_efer(vcpu);
+ if (vmx->host_state.loaded)
+ load_transition_efer(vmx);
break;
case MSR_FS_BASE:
vmcs_writel(GUEST_FS_BASE, data);
@@ -669,11 +735,11 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
guest_write_tsc(data);
break;
default:
- msr = find_msr_entry(vcpu, msr_index);
+ msr = find_msr_entry(vmx, msr_index);
if (msr) {
msr->data = data;
- if (vcpu->vmx_host_state.loaded)
- load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
+ if (vmx->host_state.loaded)
+ load_msrs(vmx->guest_msrs, vmx->save_nmsrs);
break;
}
ret = kvm_set_msr_common(vcpu, msr_index, data);
@@ -740,6 +806,20 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
return 0;
}
+static int vmx_get_irq(struct kvm_vcpu *vcpu)
+{
+ u32 idtv_info_field;
+
+ idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+ if (idtv_info_field & INTR_INFO_VALID_MASK) {
+ if (is_external_interrupt(idtv_info_field))
+ return idtv_info_field & VECTORING_INFO_VECTOR_MASK;
+ else
+ printk("pending exception: not handled yet\n");
+ }
+ return -1;
+}
+
static __init int cpu_has_kvm_support(void)
{
unsigned long ecx = cpuid_ecx(1);
@@ -751,7 +831,10 @@ static __init int vmx_disabled_by_bios(void)
u64 msr;
rdmsrl(MSR_IA32_FEATURE_CONTROL, msr);
- return (msr & 5) == 1; /* locked but not enabled */
+ return (msr & (MSR_IA32_FEATURE_CONTROL_LOCKED |
+ MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED))
+ == MSR_IA32_FEATURE_CONTROL_LOCKED;
+ /* locked but not enabled */
}
static void hardware_enable(void *garbage)
@@ -761,10 +844,15 @@ static void hardware_enable(void *garbage)
u64 old;
rdmsrl(MSR_IA32_FEATURE_CONTROL, old);
- if ((old & 5) != 5)
+ if ((old & (MSR_IA32_FEATURE_CONTROL_LOCKED |
+ MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED))
+ != (MSR_IA32_FEATURE_CONTROL_LOCKED |
+ MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED))
/* enable and lock */
- wrmsrl(MSR_IA32_FEATURE_CONTROL, old | 5);
- write_cr4(read_cr4() | CR4_VMXE); /* FIXME: not cpu hotplug safe */
+ wrmsrl(MSR_IA32_FEATURE_CONTROL, old |
+ MSR_IA32_FEATURE_CONTROL_LOCKED |
+ MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED);
+ write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */
asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr)
: "memory", "cc");
}
@@ -774,14 +862,102 @@ static void hardware_disable(void *garbage)
asm volatile (ASM_VMX_VMXOFF : : : "cc");
}
-static __init void setup_vmcs_descriptor(void)
+static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt,
+ u32 msr, u32* result)
{
u32 vmx_msr_low, vmx_msr_high;
+ u32 ctl = ctl_min | ctl_opt;
+
+ rdmsr(msr, vmx_msr_low, vmx_msr_high);
+
+ ctl &= vmx_msr_high; /* bit == 0 in high word ==> must be zero */
+ ctl |= vmx_msr_low; /* bit == 1 in low word ==> must be one */
+
+ /* Ensure minimum (required) set of control bits are supported. */
+ if (ctl_min & ~ctl)
+ return -EIO;
+
+ *result = ctl;
+ return 0;
+}
+
+static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
+{
+ u32 vmx_msr_low, vmx_msr_high;
+ u32 min, opt;
+ u32 _pin_based_exec_control = 0;
+ u32 _cpu_based_exec_control = 0;
+ u32 _vmexit_control = 0;
+ u32 _vmentry_control = 0;
+
+ min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING;
+ opt = 0;
+ if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS,
+ &_pin_based_exec_control) < 0)
+ return -EIO;
+
+ min = CPU_BASED_HLT_EXITING |
+#ifdef CONFIG_X86_64
+ CPU_BASED_CR8_LOAD_EXITING |
+ CPU_BASED_CR8_STORE_EXITING |
+#endif
+ CPU_BASED_USE_IO_BITMAPS |
+ CPU_BASED_MOV_DR_EXITING |
+ CPU_BASED_USE_TSC_OFFSETING;
+#ifdef CONFIG_X86_64
+ opt = CPU_BASED_TPR_SHADOW;
+#else
+ opt = 0;
+#endif
+ if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS,
+ &_cpu_based_exec_control) < 0)
+ return -EIO;
+#ifdef CONFIG_X86_64
+ if ((_cpu_based_exec_control & CPU_BASED_TPR_SHADOW))
+ _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING &
+ ~CPU_BASED_CR8_STORE_EXITING;
+#endif
+
+ min = 0;
+#ifdef CONFIG_X86_64
+ min |= VM_EXIT_HOST_ADDR_SPACE_SIZE;
+#endif
+ opt = 0;
+ if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS,
+ &_vmexit_control) < 0)
+ return -EIO;
+
+ min = opt = 0;
+ if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS,
+ &_vmentry_control) < 0)
+ return -EIO;
rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high);
- vmcs_descriptor.size = vmx_msr_high & 0x1fff;
- vmcs_descriptor.order = get_order(vmcs_descriptor.size);
- vmcs_descriptor.revision_id = vmx_msr_low;
+
+ /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */
+ if ((vmx_msr_high & 0x1fff) > PAGE_SIZE)
+ return -EIO;
+
+#ifdef CONFIG_X86_64
+ /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */
+ if (vmx_msr_high & (1u<<16))
+ return -EIO;
+#endif
+
+ /* Require Write-Back (WB) memory type for VMCS accesses. */
+ if (((vmx_msr_high >> 18) & 15) != 6)
+ return -EIO;
+
+ vmcs_conf->size = vmx_msr_high & 0x1fff;
+ vmcs_conf->order = get_order(vmcs_config.size);
+ vmcs_conf->revision_id = vmx_msr_low;
+
+ vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control;
+ vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control;
+ vmcs_conf->vmexit_ctrl = _vmexit_control;
+ vmcs_conf->vmentry_ctrl = _vmentry_control;
+
+ return 0;
}
static struct vmcs *alloc_vmcs_cpu(int cpu)
@@ -790,12 +966,12 @@ static struct vmcs *alloc_vmcs_cpu(int cpu)
struct page *pages;
struct vmcs *vmcs;
- pages = alloc_pages_node(node, GFP_KERNEL, vmcs_descriptor.order);
+ pages = alloc_pages_node(node, GFP_KERNEL, vmcs_config.order);
if (!pages)
return NULL;
vmcs = page_address(pages);
- memset(vmcs, 0, vmcs_descriptor.size);
- vmcs->revision_id = vmcs_descriptor.revision_id; /* vmcs revision id */
+ memset(vmcs, 0, vmcs_config.size);
+ vmcs->revision_id = vmcs_config.revision_id; /* vmcs revision id */
return vmcs;
}
@@ -806,7 +982,7 @@ static struct vmcs *alloc_vmcs(void)
static void free_vmcs(struct vmcs *vmcs)
{
- free_pages((unsigned long)vmcs, vmcs_descriptor.order);
+ free_pages((unsigned long)vmcs, vmcs_config.order);
}
static void free_kvm_area(void)
@@ -817,8 +993,6 @@ static void free_kvm_area(void)
free_vmcs(per_cpu(vmxarea, cpu));
}
-extern struct vmcs *alloc_vmcs_cpu(int cpu);
-
static __init int alloc_kvm_area(void)
{
int cpu;
@@ -839,7 +1013,8 @@ static __init int alloc_kvm_area(void)
static __init int hardware_setup(void)
{
- setup_vmcs_descriptor();
+ if (setup_vmcs_config(&vmcs_config) < 0)
+ return -EIO;
return alloc_kvm_area();
}
@@ -879,8 +1054,8 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
flags |= (vcpu->rmode.save_iopl << IOPL_SHIFT);
vmcs_writel(GUEST_RFLAGS, flags);
- vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~CR4_VME_MASK) |
- (vmcs_readl(CR4_READ_SHADOW) & CR4_VME_MASK));
+ vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) |
+ (vmcs_readl(CR4_READ_SHADOW) & X86_CR4_VME));
update_exception_bitmap(vcpu);
@@ -897,7 +1072,7 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
}
-static int rmode_tss_base(struct kvm* kvm)
+static gva_t rmode_tss_base(struct kvm* kvm)
{
gfn_t base_gfn = kvm->memslots[0].base_gfn + kvm->memslots[0].npages - 3;
return base_gfn << PAGE_SHIFT;
@@ -937,7 +1112,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
flags |= IOPL_MASK | X86_EFLAGS_VM;
vmcs_writel(GUEST_RFLAGS, flags);
- vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | CR4_VME_MASK);
+ vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME);
update_exception_bitmap(vcpu);
vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) >> 4);
@@ -955,6 +1130,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
fix_rmode_seg(VCPU_SREG_GS, &vcpu->rmode.gs);
fix_rmode_seg(VCPU_SREG_FS, &vcpu->rmode.fs);
+ kvm_mmu_reset_context(vcpu);
init_rmode_tss(vcpu->kvm);
}
@@ -975,10 +1151,10 @@ static void enter_lmode(struct kvm_vcpu *vcpu)
vcpu->shadow_efer |= EFER_LMA;
- find_msr_entry(vcpu, MSR_EFER)->data |= EFER_LMA | EFER_LME;
+ find_msr_entry(to_vmx(vcpu), MSR_EFER)->data |= EFER_LMA | EFER_LME;
vmcs_write32(VM_ENTRY_CONTROLS,
vmcs_read32(VM_ENTRY_CONTROLS)
- | VM_ENTRY_CONTROLS_IA32E_MASK);
+ | VM_ENTRY_IA32E_MODE);
}
static void exit_lmode(struct kvm_vcpu *vcpu)
@@ -987,7 +1163,7 @@ static void exit_lmode(struct kvm_vcpu *vcpu)
vmcs_write32(VM_ENTRY_CONTROLS,
vmcs_read32(VM_ENTRY_CONTROLS)
- & ~VM_ENTRY_CONTROLS_IA32E_MASK);
+ & ~VM_ENTRY_IA32E_MODE);
}
#endif
@@ -1002,17 +1178,17 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
{
vmx_fpu_deactivate(vcpu);
- if (vcpu->rmode.active && (cr0 & CR0_PE_MASK))
+ if (vcpu->rmode.active && (cr0 & X86_CR0_PE))
enter_pmode(vcpu);
- if (!vcpu->rmode.active && !(cr0 & CR0_PE_MASK))
+ if (!vcpu->rmode.active && !(cr0 & X86_CR0_PE))
enter_rmode(vcpu);
#ifdef CONFIG_X86_64
if (vcpu->shadow_efer & EFER_LME) {
- if (!is_paging(vcpu) && (cr0 & CR0_PG_MASK))
+ if (!is_paging(vcpu) && (cr0 & X86_CR0_PG))
enter_lmode(vcpu);
- if (is_paging(vcpu) && !(cr0 & CR0_PG_MASK))
+ if (is_paging(vcpu) && !(cr0 & X86_CR0_PG))
exit_lmode(vcpu);
}
#endif
@@ -1022,14 +1198,14 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
(cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
vcpu->cr0 = cr0;
- if (!(cr0 & CR0_TS_MASK) || !(cr0 & CR0_PE_MASK))
+ if (!(cr0 & X86_CR0_TS) || !(cr0 & X86_CR0_PE))
vmx_fpu_activate(vcpu);
}
static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
{
vmcs_writel(GUEST_CR3, cr3);
- if (vcpu->cr0 & CR0_PE_MASK)
+ if (vcpu->cr0 & X86_CR0_PE)
vmx_fpu_deactivate(vcpu);
}
@@ -1045,23 +1221,24 @@ static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
{
- struct vmx_msr_entry *msr = find_msr_entry(vcpu, MSR_EFER);
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ struct kvm_msr_entry *msr = find_msr_entry(vmx, MSR_EFER);
vcpu->shadow_efer = efer;
if (efer & EFER_LMA) {
vmcs_write32(VM_ENTRY_CONTROLS,
vmcs_read32(VM_ENTRY_CONTROLS) |
- VM_ENTRY_CONTROLS_IA32E_MASK);
+ VM_ENTRY_IA32E_MODE);
msr->data = efer;
} else {
vmcs_write32(VM_ENTRY_CONTROLS,
vmcs_read32(VM_ENTRY_CONTROLS) &
- ~VM_ENTRY_CONTROLS_IA32E_MASK);
+ ~VM_ENTRY_IA32E_MODE);
msr->data = efer & ~EFER_LME;
}
- setup_msrs(vcpu);
+ setup_msrs(vmx);
}
#endif
@@ -1210,17 +1387,6 @@ static int init_rmode_tss(struct kvm* kvm)
return 1;
}
-static void vmcs_write32_fixedbits(u32 msr, u32 vmcs_field, u32 val)
-{
- u32 msr_high, msr_low;
-
- rdmsr(msr, msr_low, msr_high);
-
- val &= msr_high;
- val |= msr_low;
- vmcs_write32(vmcs_field, val);
-}
-
static void seg_setup(int seg)
{
struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
@@ -1234,7 +1400,7 @@ static void seg_setup(int seg)
/*
* Sets up the vmcs for emulated real mode.
*/
-static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
+static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
{
u32 host_sysenter_cs;
u32 junk;
@@ -1243,27 +1409,36 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
int i;
int ret = 0;
unsigned long kvm_vmx_return;
+ u64 msr;
+ u32 exec_control;
- if (!init_rmode_tss(vcpu->kvm)) {
+ if (!init_rmode_tss(vmx->vcpu.kvm)) {
ret = -ENOMEM;
goto out;
}
- memset(vcpu->regs, 0, sizeof(vcpu->regs));
- vcpu->regs[VCPU_REGS_RDX] = get_rdx_init_val();
- vcpu->cr8 = 0;
- vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
- if (vcpu == &vcpu->kvm->vcpus[0])
- vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
+ vmx->vcpu.rmode.active = 0;
- fx_init(vcpu);
+ vmx->vcpu.regs[VCPU_REGS_RDX] = get_rdx_init_val();
+ set_cr8(&vmx->vcpu, 0);
+ msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
+ if (vmx->vcpu.vcpu_id == 0)
+ msr |= MSR_IA32_APICBASE_BSP;
+ kvm_set_apic_base(&vmx->vcpu, msr);
+
+ fx_init(&vmx->vcpu);
/*
* GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode
* insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4. Sigh.
*/
- vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
- vmcs_writel(GUEST_CS_BASE, 0x000f0000);
+ if (vmx->vcpu.vcpu_id == 0) {
+ vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
+ vmcs_writel(GUEST_CS_BASE, 0x000f0000);
+ } else {
+ vmcs_write16(GUEST_CS_SELECTOR, vmx->vcpu.sipi_vector << 8);
+ vmcs_writel(GUEST_CS_BASE, vmx->vcpu.sipi_vector << 12);
+ }
vmcs_write32(GUEST_CS_LIMIT, 0xffff);
vmcs_write32(GUEST_CS_AR_BYTES, 0x9b);
@@ -1288,7 +1463,10 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
vmcs_writel(GUEST_SYSENTER_EIP, 0);
vmcs_writel(GUEST_RFLAGS, 0x02);
- vmcs_writel(GUEST_RIP, 0xfff0);
+ if (vmx->vcpu.vcpu_id == 0)
+ vmcs_writel(GUEST_RIP, 0xfff0);
+ else
+ vmcs_writel(GUEST_RIP, 0);
vmcs_writel(GUEST_RSP, 0);
//todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0
@@ -1316,20 +1494,18 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
/* Control */
- vmcs_write32_fixedbits(MSR_IA32_VMX_PINBASED_CTLS,
- PIN_BASED_VM_EXEC_CONTROL,
- PIN_BASED_EXT_INTR_MASK /* 20.6.1 */
- | PIN_BASED_NMI_EXITING /* 20.6.1 */
- );
- vmcs_write32_fixedbits(MSR_IA32_VMX_PROCBASED_CTLS,
- CPU_BASED_VM_EXEC_CONTROL,
- CPU_BASED_HLT_EXITING /* 20.6.2 */
- | CPU_BASED_CR8_LOAD_EXITING /* 20.6.2 */
- | CPU_BASED_CR8_STORE_EXITING /* 20.6.2 */
- | CPU_BASED_ACTIVATE_IO_BITMAP /* 20.6.2 */
- | CPU_BASED_MOV_DR_EXITING
- | CPU_BASED_USE_TSC_OFFSETING /* 21.3 */
- );
+ vmcs_write32(PIN_BASED_VM_EXEC_CONTROL,
+ vmcs_config.pin_based_exec_ctrl);
+
+ exec_control = vmcs_config.cpu_based_exec_ctrl;
+ if (!vm_need_tpr_shadow(vmx->vcpu.kvm)) {
+ exec_control &= ~CPU_BASED_TPR_SHADOW;
+#ifdef CONFIG_X86_64
+ exec_control |= CPU_BASED_CR8_STORE_EXITING |
+ CPU_BASED_CR8_LOAD_EXITING;
+#endif
+ }
+ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control);
vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0);
vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0);
@@ -1377,46 +1553,48 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
u32 index = vmx_msr_index[i];
u32 data_low, data_high;
u64 data;
- int j = vcpu->nmsrs;
+ int j = vmx->nmsrs;
if (rdmsr_safe(index, &data_low, &data_high) < 0)
continue;
if (wrmsr_safe(index, data_low, data_high) < 0)
continue;
data = data_low | ((u64)data_high << 32);
- vcpu->host_msrs[j].index = index;
- vcpu->host_msrs[j].reserved = 0;
- vcpu->host_msrs[j].data = data;
- vcpu->guest_msrs[j] = vcpu->host_msrs[j];
- ++vcpu->nmsrs;
+ vmx->host_msrs[j].index = index;
+ vmx->host_msrs[j].reserved = 0;
+ vmx->host_msrs[j].data = data;
+ vmx->guest_msrs[j] = vmx->host_msrs[j];
+ ++vmx->nmsrs;
}
- setup_msrs(vcpu);
+ setup_msrs(vmx);
- vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS, VM_EXIT_CONTROLS,
- (HOST_IS_64 << 9)); /* 22.2,1, 20.7.1 */
+ vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl);
/* 22.2.1, 20.8.1 */
- vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS,
- VM_ENTRY_CONTROLS, 0);
+ vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl);
+
vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */
#ifdef CONFIG_X86_64
- vmcs_writel(VIRTUAL_APIC_PAGE_ADDR, 0);
- vmcs_writel(TPR_THRESHOLD, 0);
+ vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0);
+ if (vm_need_tpr_shadow(vmx->vcpu.kvm))
+ vmcs_write64(VIRTUAL_APIC_PAGE_ADDR,
+ page_to_phys(vmx->vcpu.apic->regs_page));
+ vmcs_write32(TPR_THRESHOLD, 0);
#endif
vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
- vcpu->cr0 = 0x60000010;
- vmx_set_cr0(vcpu, vcpu->cr0); // enter rmode
- vmx_set_cr4(vcpu, 0);
+ vmx->vcpu.cr0 = 0x60000010;
+ vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); // enter rmode
+ vmx_set_cr4(&vmx->vcpu, 0);
#ifdef CONFIG_X86_64
- vmx_set_efer(vcpu, 0);
+ vmx_set_efer(&vmx->vcpu, 0);
#endif
- vmx_fpu_activate(vcpu);
- update_exception_bitmap(vcpu);
+ vmx_fpu_activate(&vmx->vcpu);
+ update_exception_bitmap(&vmx->vcpu);
return 0;
@@ -1424,6 +1602,13 @@ out:
return ret;
}
+static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+ vmx_vcpu_setup(vmx);
+}
+
static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
{
u16 ent[2];
@@ -1443,8 +1628,8 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
return;
}
- if (kvm_read_guest(vcpu, irq * sizeof(ent), sizeof(ent), &ent) !=
- sizeof(ent)) {
+ if (emulator_read_std(irq * sizeof(ent), &ent, sizeof(ent), vcpu) !=
+ X86EMUL_CONTINUE) {
vcpu_printf(vcpu, "%s: read guest err\n", __FUNCTION__);
return;
}
@@ -1454,9 +1639,9 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
ip = vmcs_readl(GUEST_RIP);
- if (kvm_write_guest(vcpu, ss_base + sp - 2, 2, &flags) != 2 ||
- kvm_write_guest(vcpu, ss_base + sp - 4, 2, &cs) != 2 ||
- kvm_write_guest(vcpu, ss_base + sp - 6, 2, &ip) != 2) {
+ if (emulator_write_emulated(ss_base + sp - 2, &flags, 2, vcpu) != X86EMUL_CONTINUE ||
+ emulator_write_emulated(ss_base + sp - 4, &cs, 2, vcpu) != X86EMUL_CONTINUE ||
+ emulator_write_emulated(ss_base + sp - 6, &ip, 2, vcpu) != X86EMUL_CONTINUE) {
vcpu_printf(vcpu, "%s: write guest err\n", __FUNCTION__);
return;
}
@@ -1469,6 +1654,16 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6));
}
+static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq)
+{
+ if (vcpu->rmode.active) {
+ inject_rmode_irq(vcpu, irq);
+ return;
+ }
+ vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+ irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+}
+
static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
{
int word_index = __ffs(vcpu->irq_summary);
@@ -1478,13 +1673,7 @@ static void kvm_do_inject_irq(struct kvm_vcpu *vcpu)
clear_bit(bit_index, &vcpu->irq_pending[word_index]);
if (!vcpu->irq_pending[word_index])
clear_bit(word_index, &vcpu->irq_summary);
-
- if (vcpu->rmode.active) {
- inject_rmode_irq(vcpu, irq);
- return;
- }
- vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
- irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
+ vmx_inject_irq(vcpu, irq);
}
@@ -1568,16 +1757,14 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
"intr info 0x%x\n", __FUNCTION__, vect_info, intr_info);
}
- if (is_external_interrupt(vect_info)) {
+ if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) {
int irq = vect_info & VECTORING_INFO_VECTOR_MASK;
set_bit(irq, vcpu->irq_pending);
set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary);
}
- if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) { /* nmi */
- asm ("int $2");
- return 1;
- }
+ if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */
+ return 1; /* already handled by vmx_vcpu_run() */
if (is_no_device(intr_info)) {
vmx_fpu_activate(vcpu);
@@ -1591,29 +1778,28 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (is_page_fault(intr_info)) {
cr2 = vmcs_readl(EXIT_QUALIFICATION);
- spin_lock(&vcpu->kvm->lock);
+ mutex_lock(&vcpu->kvm->lock);
r = kvm_mmu_page_fault(vcpu, cr2, error_code);
if (r < 0) {
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
return r;
}
if (!r) {
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
return 1;
}
er = emulate_instruction(vcpu, kvm_run, cr2, error_code);
- spin_unlock(&vcpu->kvm->lock);
+ mutex_unlock(&vcpu->kvm->lock);
switch (er) {
case EMULATE_DONE:
return 1;
case EMULATE_DO_MMIO:
++vcpu->stat.mmio_exits;
- kvm_run->exit_reason = KVM_EXIT_MMIO;
return 0;
case EMULATE_FAIL:
- vcpu_printf(vcpu, "%s: emulate fail\n", __FUNCTION__);
+ kvm_report_emulation_failure(vcpu, "pagetable");
break;
default:
BUG();
@@ -1653,80 +1839,29 @@ static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 0;
}
-static int get_io_count(struct kvm_vcpu *vcpu, unsigned long *count)
-{
- u64 inst;
- gva_t rip;
- int countr_size;
- int i, n;
-
- if ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_VM)) {
- countr_size = 2;
- } else {
- u32 cs_ar = vmcs_read32(GUEST_CS_AR_BYTES);
-
- countr_size = (cs_ar & AR_L_MASK) ? 8:
- (cs_ar & AR_DB_MASK) ? 4: 2;
- }
-
- rip = vmcs_readl(GUEST_RIP);
- if (countr_size != 8)
- rip += vmcs_readl(GUEST_CS_BASE);
-
- n = kvm_read_guest(vcpu, rip, sizeof(inst), &inst);
-
- for (i = 0; i < n; i++) {
- switch (((u8*)&inst)[i]) {
- case 0xf0:
- case 0xf2:
- case 0xf3:
- case 0x2e:
- case 0x36:
- case 0x3e:
- case 0x26:
- case 0x64:
- case 0x65:
- case 0x66:
- break;
- case 0x67:
- countr_size = (countr_size == 2) ? 4: (countr_size >> 1);
- default:
- goto done;
- }
- }
- return 0;
-done:
- countr_size *= 8;
- *count = vcpu->regs[VCPU_REGS_RCX] & (~0ULL >> (64 - countr_size));
- //printk("cx: %lx\n", vcpu->regs[VCPU_REGS_RCX]);
- return 1;
-}
-
static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- u64 exit_qualification;
+ unsigned long exit_qualification;
int size, down, in, string, rep;
unsigned port;
- unsigned long count;
- gva_t address;
++vcpu->stat.io_exits;
- exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
- in = (exit_qualification & 8) != 0;
- size = (exit_qualification & 7) + 1;
+ exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
string = (exit_qualification & 16) != 0;
+
+ if (string) {
+ if (emulate_instruction(vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO)
+ return 0;
+ return 1;
+ }
+
+ size = (exit_qualification & 7) + 1;
+ in = (exit_qualification & 8) != 0;
down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0;
- count = 1;
rep = (exit_qualification & 32) != 0;
port = exit_qualification >> 16;
- address = 0;
- if (string) {
- if (rep && !get_io_count(vcpu, &count))
- return 1;
- address = vmcs_readl(GUEST_LINEAR_ADDRESS);
- }
- return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down,
- address, rep, port);
+
+ return kvm_emulate_pio(vcpu, kvm_run, in, size, port);
}
static void
@@ -1743,11 +1878,11 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- u64 exit_qualification;
+ unsigned long exit_qualification;
int cr;
int reg;
- exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+ exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
cr = exit_qualification & 15;
reg = (exit_qualification >> 8) & 15;
switch ((exit_qualification >> 4) & 3) {
@@ -1772,13 +1907,14 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
vcpu_load_rsp_rip(vcpu);
set_cr8(vcpu, vcpu->regs[reg]);
skip_emulated_instruction(vcpu);
- return 1;
+ kvm_run->exit_reason = KVM_EXIT_SET_TPR;
+ return 0;
};
break;
case 2: /* clts */
vcpu_load_rsp_rip(vcpu);
vmx_fpu_deactivate(vcpu);
- vcpu->cr0 &= ~CR0_TS_MASK;
+ vcpu->cr0 &= ~X86_CR0_TS;
vmcs_writel(CR0_READ_SHADOW, vcpu->cr0);
vmx_fpu_activate(vcpu);
skip_emulated_instruction(vcpu);
@@ -1793,7 +1929,7 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
case 8:
vcpu_load_rsp_rip(vcpu);
- vcpu->regs[reg] = vcpu->cr8;
+ vcpu->regs[reg] = get_cr8(vcpu);
vcpu_put_rsp_rip(vcpu);
skip_emulated_instruction(vcpu);
return 1;
@@ -1808,14 +1944,14 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
break;
}
kvm_run->exit_reason = 0;
- printk(KERN_ERR "kvm: unhandled control register: op %d cr %d\n",
+ pr_unimpl(vcpu, "unhandled control register: op %d cr %d\n",
(int)(exit_qualification >> 4) & 3, cr);
return 0;
}
static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- u64 exit_qualification;
+ unsigned long exit_qualification;
unsigned long val;
int dr, reg;
@@ -1823,7 +1959,7 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
* FIXME: this code assumes the host is debugging the guest.
* need to deal with guest debugging itself too.
*/
- exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
+ exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
dr = exit_qualification & 7;
reg = (exit_qualification >> 8) & 15;
vcpu_load_rsp_rip(vcpu);
@@ -1886,19 +2022,21 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
}
-static void post_kvm_run_save(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
+static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu,
+ struct kvm_run *kvm_run)
{
- kvm_run->if_flag = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) != 0;
- kvm_run->cr8 = vcpu->cr8;
- kvm_run->apic_base = vcpu->apic_base;
- kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open &&
- vcpu->irq_summary == 0);
+ return 1;
}
static int handle_interrupt_window(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run)
{
+ u32 cpu_based_vm_exec_control;
+
+ /* clear pending irq */
+ cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
+ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
/*
* If the user space waits to inject interrupts, exit as soon as
* possible
@@ -1943,6 +2081,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
[EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window,
[EXIT_REASON_HLT] = handle_halt,
[EXIT_REASON_VMCALL] = handle_vmcall,
+ [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold
};
static const int kvm_vmx_max_exit_handlers =
@@ -1956,6 +2095,14 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
{
u32 vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
u32 exit_reason = vmcs_read32(VM_EXIT_REASON);
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+ if (unlikely(vmx->fail)) {
+ kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+ kvm_run->fail_entry.hardware_entry_failure_reason
+ = vmcs_read32(VM_INSTRUCTION_ERROR);
+ return 0;
+ }
if ( (vectoring_info & VECTORING_INFO_VALID_MASK) &&
exit_reason != EXIT_REASON_EXCEPTION_NMI )
@@ -1971,57 +2118,92 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
return 0;
}
-/*
- * Check if userspace requested an interrupt window, and that the
- * interrupt window is open.
- *
- * No need to exit to userspace if we already have an interrupt queued.
- */
-static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
- struct kvm_run *kvm_run)
+static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
{
- return (!vcpu->irq_summary &&
- kvm_run->request_interrupt_window &&
- vcpu->interrupt_window_open &&
- (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF));
}
-static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
+static void update_tpr_threshold(struct kvm_vcpu *vcpu)
{
+ int max_irr, tpr;
+
+ if (!vm_need_tpr_shadow(vcpu->kvm))
+ return;
+
+ if (!kvm_lapic_enabled(vcpu) ||
+ ((max_irr = kvm_lapic_find_highest_irr(vcpu)) == -1)) {
+ vmcs_write32(TPR_THRESHOLD, 0);
+ return;
+ }
+
+ tpr = (kvm_lapic_get_cr8(vcpu) & 0x0f) << 4;
+ vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4);
}
-static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+static void enable_irq_window(struct kvm_vcpu *vcpu)
{
- u8 fail;
- int r;
+ u32 cpu_based_vm_exec_control;
-preempted:
- if (vcpu->guest_debug.enabled)
- kvm_guest_debug_pre(vcpu);
+ cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
+ cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
+ vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control);
+}
-again:
- if (!vcpu->mmio_read_completed)
- do_interrupt_requests(vcpu, kvm_run);
+static void vmx_intr_assist(struct kvm_vcpu *vcpu)
+{
+ u32 idtv_info_field, intr_info_field;
+ int has_ext_irq, interrupt_window_open;
+ int vector;
- vmx_save_host_state(vcpu);
- kvm_load_guest_fpu(vcpu);
+ kvm_inject_pending_timer_irqs(vcpu);
+ update_tpr_threshold(vcpu);
- r = kvm_mmu_reload(vcpu);
- if (unlikely(r))
- goto out;
+ has_ext_irq = kvm_cpu_has_interrupt(vcpu);
+ intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD);
+ idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+ if (intr_info_field & INTR_INFO_VALID_MASK) {
+ if (idtv_info_field & INTR_INFO_VALID_MASK) {
+ /* TODO: fault when IDT_Vectoring */
+ printk(KERN_ERR "Fault when IDT_Vectoring\n");
+ }
+ if (has_ext_irq)
+ enable_irq_window(vcpu);
+ return;
+ }
+ if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) {
+ vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
+ vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
+ vmcs_read32(VM_EXIT_INSTRUCTION_LEN));
+
+ if (unlikely(idtv_info_field & INTR_INFO_DELIEVER_CODE_MASK))
+ vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
+ vmcs_read32(IDT_VECTORING_ERROR_CODE));
+ if (unlikely(has_ext_irq))
+ enable_irq_window(vcpu);
+ return;
+ }
+ if (!has_ext_irq)
+ return;
+ interrupt_window_open =
+ ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
+ (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0);
+ if (interrupt_window_open) {
+ vector = kvm_cpu_get_interrupt(vcpu);
+ vmx_inject_irq(vcpu, vector);
+ kvm_timer_intr_post(vcpu, vector);
+ } else
+ enable_irq_window(vcpu);
+}
+
+static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ u32 intr_info;
/*
* Loading guest fpu may have cleared host cr0.ts
*/
vmcs_writel(HOST_CR0, read_cr0());
- local_irq_disable();
-
- vcpu->guest_mode = 1;
- if (vcpu->requests)
- if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
- vmx_flush_tlb(vcpu);
-
asm (
/* Store host registers */
#ifdef CONFIG_X86_64
@@ -2115,8 +2297,8 @@ again:
"pop %%ecx; popa \n\t"
#endif
"setbe %0 \n\t"
- : "=q" (fail)
- : "r"(vcpu->launched), "d"((unsigned long)HOST_RSP),
+ : "=q" (vmx->fail)
+ : "r"(vmx->launched), "d"((unsigned long)HOST_RSP),
"c"(vcpu),
[rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])),
[rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])),
@@ -2138,59 +2320,16 @@ again:
[cr2]"i"(offsetof(struct kvm_vcpu, cr2))
: "cc", "memory" );
- vcpu->guest_mode = 0;
- local_irq_enable();
-
- ++vcpu->stat.exits;
-
vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
+ vmx->launched = 1;
- if (unlikely(fail)) {
- kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
- kvm_run->fail_entry.hardware_entry_failure_reason
- = vmcs_read32(VM_INSTRUCTION_ERROR);
- r = 0;
- goto out;
- }
- /*
- * Profile KVM exit RIPs:
- */
- if (unlikely(prof_on == KVM_PROFILING))
- profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
-
- vcpu->launched = 1;
- r = kvm_handle_exit(kvm_run, vcpu);
- if (r > 0) {
- /* Give scheduler a change to reschedule. */
- if (signal_pending(current)) {
- r = -EINTR;
- kvm_run->exit_reason = KVM_EXIT_INTR;
- ++vcpu->stat.signal_exits;
- goto out;
- }
-
- if (dm_request_for_irq_injection(vcpu, kvm_run)) {
- r = -EINTR;
- kvm_run->exit_reason = KVM_EXIT_INTR;
- ++vcpu->stat.request_irq_exits;
- goto out;
- }
- if (!need_resched()) {
- ++vcpu->stat.light_exits;
- goto again;
- }
- }
-
-out:
- if (r > 0) {
- kvm_resched(vcpu);
- goto preempted;
- }
+ intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
- post_kvm_run_save(vcpu, kvm_run);
- return r;
+ /* We need to handle NMIs before interrupts are enabled */
+ if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */
+ asm("int $2");
}
static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
@@ -2225,67 +2364,118 @@ static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
static void vmx_free_vmcs(struct kvm_vcpu *vcpu)
{
- if (vcpu->vmcs) {
- on_each_cpu(__vcpu_clear, vcpu, 0, 1);
- free_vmcs(vcpu->vmcs);
- vcpu->vmcs = NULL;
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+ if (vmx->vmcs) {
+ on_each_cpu(__vcpu_clear, vmx, 0, 1);
+ free_vmcs(vmx->vmcs);
+ vmx->vmcs = NULL;
}
}
static void vmx_free_vcpu(struct kvm_vcpu *vcpu)
{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
vmx_free_vmcs(vcpu);
+ kfree(vmx->host_msrs);
+ kfree(vmx->guest_msrs);
+ kvm_vcpu_uninit(vcpu);
+ kmem_cache_free(kvm_vcpu_cache, vmx);
}
-static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
+static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
{
- struct vmcs *vmcs;
+ int err;
+ struct vcpu_vmx *vmx = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
+ int cpu;
- vcpu->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!vcpu->guest_msrs)
- return -ENOMEM;
+ if (!vmx)
+ return ERR_PTR(-ENOMEM);
- vcpu->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!vcpu->host_msrs)
- goto out_free_guest_msrs;
+ err = kvm_vcpu_init(&vmx->vcpu, kvm, id);
+ if (err)
+ goto free_vcpu;
- vmcs = alloc_vmcs();
- if (!vmcs)
- goto out_free_msrs;
+ if (irqchip_in_kernel(kvm)) {
+ err = kvm_create_lapic(&vmx->vcpu);
+ if (err < 0)
+ goto free_vcpu;
+ }
- vmcs_clear(vmcs);
- vcpu->vmcs = vmcs;
- vcpu->launched = 0;
+ vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!vmx->guest_msrs) {
+ err = -ENOMEM;
+ goto uninit_vcpu;
+ }
- return 0;
+ vmx->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!vmx->host_msrs)
+ goto free_guest_msrs;
-out_free_msrs:
- kfree(vcpu->host_msrs);
- vcpu->host_msrs = NULL;
+ vmx->vmcs = alloc_vmcs();
+ if (!vmx->vmcs)
+ goto free_msrs;
-out_free_guest_msrs:
- kfree(vcpu->guest_msrs);
- vcpu->guest_msrs = NULL;
+ vmcs_clear(vmx->vmcs);
- return -ENOMEM;
+ cpu = get_cpu();
+ vmx_vcpu_load(&vmx->vcpu, cpu);
+ err = vmx_vcpu_setup(vmx);
+ vmx_vcpu_put(&vmx->vcpu);
+ put_cpu();
+ if (err)
+ goto free_vmcs;
+
+ return &vmx->vcpu;
+
+free_vmcs:
+ free_vmcs(vmx->vmcs);
+free_msrs:
+ kfree(vmx->host_msrs);
+free_guest_msrs:
+ kfree(vmx->guest_msrs);
+uninit_vcpu:
+ kvm_vcpu_uninit(&vmx->vcpu);
+free_vcpu:
+ kmem_cache_free(kvm_vcpu_cache, vmx);
+ return ERR_PTR(err);
+}
+
+static void __init vmx_check_processor_compat(void *rtn)
+{
+ struct vmcs_config vmcs_conf;
+
+ *(int *)rtn = 0;
+ if (setup_vmcs_config(&vmcs_conf) < 0)
+ *(int *)rtn = -EIO;
+ if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) {
+ printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n",
+ smp_processor_id());
+ *(int *)rtn = -EIO;
+ }
}
-static struct kvm_arch_ops vmx_arch_ops = {
+static struct kvm_x86_ops vmx_x86_ops = {
.cpu_has_kvm_support = cpu_has_kvm_support,
.disabled_by_bios = vmx_disabled_by_bios,
.hardware_setup = hardware_setup,
.hardware_unsetup = hardware_unsetup,
+ .check_processor_compatibility = vmx_check_processor_compat,
.hardware_enable = hardware_enable,
.hardware_disable = hardware_disable,
.vcpu_create = vmx_create_vcpu,
.vcpu_free = vmx_free_vcpu,
+ .vcpu_reset = vmx_vcpu_reset,
+ .prepare_guest_switch = vmx_save_host_state,
.vcpu_load = vmx_vcpu_load,
.vcpu_put = vmx_vcpu_put,
.vcpu_decache = vmx_vcpu_decache,
.set_guest_debug = set_guest_debug,
+ .guest_debug_pre = kvm_guest_debug_pre,
.get_msr = vmx_get_msr,
.set_msr = vmx_set_msr,
.get_segment_base = vmx_get_segment_base,
@@ -2314,9 +2504,13 @@ static struct kvm_arch_ops vmx_arch_ops = {
.inject_gp = vmx_inject_gp,
.run = vmx_vcpu_run,
+ .handle_exit = kvm_handle_exit,
.skip_emulated_instruction = skip_emulated_instruction,
- .vcpu_setup = vmx_vcpu_setup,
.patch_hypercall = vmx_patch_hypercall,
+ .get_irq = vmx_get_irq,
+ .set_irq = vmx_inject_irq,
+ .inject_pending_irq = vmx_intr_assist,
+ .inject_pending_vectors = do_interrupt_requests,
};
static int __init vmx_init(void)
@@ -2347,7 +2541,7 @@ static int __init vmx_init(void)
memset(iova, 0xff, PAGE_SIZE);
kunmap(vmx_io_bitmap_b);
- r = kvm_init_arch(&vmx_arch_ops, THIS_MODULE);
+ r = kvm_init_x86(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE);
if (r)
goto out1;
@@ -2365,7 +2559,7 @@ static void __exit vmx_exit(void)
__free_page(vmx_io_bitmap_b);
__free_page(vmx_io_bitmap_a);
- kvm_exit_arch();
+ kvm_exit_x86();
}
module_init(vmx_init)
diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h
index d0dc93df411..fd4e1466608 100644
--- a/drivers/kvm/vmx.h
+++ b/drivers/kvm/vmx.h
@@ -25,29 +25,36 @@
*
*/
-#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004
-#define CPU_BASED_USE_TSC_OFFSETING 0x00000008
-#define CPU_BASED_HLT_EXITING 0x00000080
-#define CPU_BASED_INVDPG_EXITING 0x00000200
-#define CPU_BASED_MWAIT_EXITING 0x00000400
-#define CPU_BASED_RDPMC_EXITING 0x00000800
-#define CPU_BASED_RDTSC_EXITING 0x00001000
-#define CPU_BASED_CR8_LOAD_EXITING 0x00080000
-#define CPU_BASED_CR8_STORE_EXITING 0x00100000
-#define CPU_BASED_TPR_SHADOW 0x00200000
-#define CPU_BASED_MOV_DR_EXITING 0x00800000
-#define CPU_BASED_UNCOND_IO_EXITING 0x01000000
-#define CPU_BASED_ACTIVATE_IO_BITMAP 0x02000000
-#define CPU_BASED_MSR_BITMAPS 0x10000000
-#define CPU_BASED_MONITOR_EXITING 0x20000000
-#define CPU_BASED_PAUSE_EXITING 0x40000000
+#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004
+#define CPU_BASED_USE_TSC_OFFSETING 0x00000008
+#define CPU_BASED_HLT_EXITING 0x00000080
+#define CPU_BASED_INVLPG_EXITING 0x00000200
+#define CPU_BASED_MWAIT_EXITING 0x00000400
+#define CPU_BASED_RDPMC_EXITING 0x00000800
+#define CPU_BASED_RDTSC_EXITING 0x00001000
+#define CPU_BASED_CR8_LOAD_EXITING 0x00080000
+#define CPU_BASED_CR8_STORE_EXITING 0x00100000
+#define CPU_BASED_TPR_SHADOW 0x00200000
+#define CPU_BASED_MOV_DR_EXITING 0x00800000
+#define CPU_BASED_UNCOND_IO_EXITING 0x01000000
+#define CPU_BASED_USE_IO_BITMAPS 0x02000000
+#define CPU_BASED_USE_MSR_BITMAPS 0x10000000
+#define CPU_BASED_MONITOR_EXITING 0x20000000
+#define CPU_BASED_PAUSE_EXITING 0x40000000
+#define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS 0x80000000
-#define PIN_BASED_EXT_INTR_MASK 0x1
-#define PIN_BASED_NMI_EXITING 0x8
+#define PIN_BASED_EXT_INTR_MASK 0x00000001
+#define PIN_BASED_NMI_EXITING 0x00000008
+#define PIN_BASED_VIRTUAL_NMIS 0x00000020
-#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000
-#define VM_EXIT_HOST_ADD_SPACE_SIZE 0x00000200
+#define VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200
+#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000
+#define VM_ENTRY_IA32E_MODE 0x00000200
+#define VM_ENTRY_SMM 0x00000400
+#define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800
+
+#define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001
/* VMCS Encodings */
enum vmcs_field {
@@ -206,6 +213,7 @@ enum vmcs_field {
#define EXIT_REASON_MSR_READ 31
#define EXIT_REASON_MSR_WRITE 32
#define EXIT_REASON_MWAIT_INSTRUCTION 36
+#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
/*
* Interruption-information format
@@ -261,9 +269,6 @@ enum vmcs_field {
/* segment AR */
#define SEGMENT_AR_L_MASK (1 << 13)
-/* entry controls */
-#define VM_ENTRY_CONTROLS_IA32E_MASK (1 << 9)
-
#define AR_TYPE_ACCESSES_MASK 1
#define AR_TYPE_READABLE_MASK (1 << 1)
#define AR_TYPE_WRITEABLE_MASK (1 << 2)
@@ -285,13 +290,21 @@ enum vmcs_field {
#define AR_RESERVD_MASK 0xfffe0f00
-#define CR4_VMXE 0x2000
+#define MSR_IA32_VMX_BASIC 0x480
+#define MSR_IA32_VMX_PINBASED_CTLS 0x481
+#define MSR_IA32_VMX_PROCBASED_CTLS 0x482
+#define MSR_IA32_VMX_EXIT_CTLS 0x483
+#define MSR_IA32_VMX_ENTRY_CTLS 0x484
+#define MSR_IA32_VMX_MISC 0x485
+#define MSR_IA32_VMX_CR0_FIXED0 0x486
+#define MSR_IA32_VMX_CR0_FIXED1 0x487
+#define MSR_IA32_VMX_CR4_FIXED0 0x488
+#define MSR_IA32_VMX_CR4_FIXED1 0x489
+#define MSR_IA32_VMX_VMCS_ENUM 0x48a
+#define MSR_IA32_VMX_PROCBASED_CTLS2 0x48b
-#define MSR_IA32_VMX_BASIC 0x480
-#define MSR_IA32_FEATURE_CONTROL 0x03a
-#define MSR_IA32_VMX_PINBASED_CTLS 0x481
-#define MSR_IA32_VMX_PROCBASED_CTLS 0x482
-#define MSR_IA32_VMX_EXIT_CTLS 0x483
-#define MSR_IA32_VMX_ENTRY_CTLS 0x484
+#define MSR_IA32_FEATURE_CONTROL 0x3a
+#define MSR_IA32_FEATURE_CONTROL_LOCKED 0x1
+#define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED 0x4
#endif
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index 4b8a0cc9665..33b18145155 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -6,7 +6,7 @@
* Copyright (c) 2005 Keir Fraser
*
* Linux coding style, mod r/m decoder, segment base fixes, real-mode
- * privieged instructions:
+ * privileged instructions:
*
* Copyright (C) 2006 Qumranet
*
@@ -83,7 +83,7 @@ static u8 opcode_table[256] = {
/* 0x20 - 0x27 */
ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
- 0, 0, 0, 0,
+ SrcImmByte, SrcImm, 0, 0,
/* 0x28 - 0x2F */
ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
@@ -99,15 +99,24 @@ static u8 opcode_table[256] = {
/* 0x40 - 0x4F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x50 - 0x57 */
- 0, 0, 0, 0, 0, 0, 0, 0,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x58 - 0x5F */
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
- /* 0x60 - 0x6F */
+ /* 0x60 - 0x67 */
0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x70 - 0x7F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ /* 0x68 - 0x6F */
+ 0, 0, ImplicitOps|Mov, 0,
+ SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */
+ SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */
+ /* 0x70 - 0x77 */
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ /* 0x78 - 0x7F */
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x80 - 0x87 */
ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
@@ -116,9 +125,9 @@ static u8 opcode_table[256] = {
/* 0x88 - 0x8F */
ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
- 0, 0, 0, DstMem | SrcNone | ModRM | Mov,
+ 0, ModRM | DstReg, 0, DstMem | SrcNone | ModRM | Mov,
/* 0x90 - 0x9F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps, ImplicitOps, 0, 0,
/* 0xA0 - 0xA7 */
ByteOp | DstReg | SrcMem | Mov, DstReg | SrcMem | Mov,
ByteOp | DstMem | SrcReg | Mov, DstMem | SrcReg | Mov,
@@ -142,8 +151,10 @@ static u8 opcode_table[256] = {
0, 0, 0, 0,
/* 0xD8 - 0xDF */
0, 0, 0, 0, 0, 0, 0, 0,
- /* 0xE0 - 0xEF */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xE0 - 0xE7 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xE8 - 0xEF */
+ ImplicitOps, SrcImm|ImplicitOps, 0, SrcImmByte|ImplicitOps, 0, 0, 0, 0,
/* 0xF0 - 0xF7 */
0, 0, 0, 0,
ImplicitOps, 0,
@@ -156,7 +167,7 @@ static u8 opcode_table[256] = {
static u16 twobyte_table[256] = {
/* 0x00 - 0x0F */
0, SrcMem | ModRM | DstReg, 0, 0, 0, 0, ImplicitOps, 0,
- 0, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0,
+ ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0,
/* 0x10 - 0x1F */
0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0,
/* 0x20 - 0x2F */
@@ -181,7 +192,10 @@ static u16 twobyte_table[256] = {
/* 0x70 - 0x7F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x80 - 0x8F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x90 - 0x9F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xA0 - 0xA7 */
@@ -198,7 +212,8 @@ static u16 twobyte_table[256] = {
0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
DstReg | SrcMem16 | ModRM | Mov,
/* 0xC0 - 0xCF */
- 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, DstMem | SrcReg | ModRM | Mov, 0, 0, 0, ImplicitOps | ModRM,
+ 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xD0 - 0xDF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xE0 - 0xEF */
@@ -207,19 +222,6 @@ static u16 twobyte_table[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
-/*
- * Tell the emulator that of the Group 7 instructions (sgdt, lidt, etc.) we
- * are interested only in invlpg and not in any of the rest.
- *
- * invlpg is a special instruction in that the data it references may not
- * be mapped.
- */
-void kvm_emulator_want_group7_invlpg(void)
-{
- twobyte_table[1] &= ~SrcMem;
-}
-EXPORT_SYMBOL_GPL(kvm_emulator_want_group7_invlpg);
-
/* Type, address-of, and value of an instruction's operand. */
struct operand {
enum { OP_REG, OP_MEM, OP_IMM } type;
@@ -420,7 +422,7 @@ struct operand {
#define insn_fetch(_type, _size, _eip) \
({ unsigned long _x; \
rc = ops->read_std((unsigned long)(_eip) + ctxt->cs_base, &_x, \
- (_size), ctxt); \
+ (_size), ctxt->vcpu); \
if ( rc != 0 ) \
goto done; \
(_eip) += (_size); \
@@ -428,10 +430,11 @@ struct operand {
})
/* Access/update address held in a register, based on addressing mode. */
+#define address_mask(reg) \
+ ((ad_bytes == sizeof(unsigned long)) ? \
+ (reg) : ((reg) & ((1UL << (ad_bytes << 3)) - 1)))
#define register_address(base, reg) \
- ((base) + ((ad_bytes == sizeof(unsigned long)) ? (reg) : \
- ((reg) & ((1UL << (ad_bytes << 3)) - 1))))
-
+ ((base) + address_mask(reg))
#define register_address_increment(reg, inc) \
do { \
/* signed type ensures sign extension to long */ \
@@ -443,8 +446,19 @@ struct operand {
(((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \
} while (0)
-void *decode_register(u8 modrm_reg, unsigned long *regs,
- int highbyte_regs)
+#define JMP_REL(rel) \
+ do { \
+ _eip += (int)(rel); \
+ _eip = ((op_bytes == 2) ? (uint16_t)_eip : (uint32_t)_eip); \
+ } while (0)
+
+/*
+ * Given the 'reg' portion of a ModRM byte, and a register block, return a
+ * pointer into the block that addresses the relevant register.
+ * @highbyte_regs specifies whether to decode AH,CH,DH,BH.
+ */
+static void *decode_register(u8 modrm_reg, unsigned long *regs,
+ int highbyte_regs)
{
void *p;
@@ -464,13 +478,50 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt,
if (op_bytes == 2)
op_bytes = 3;
*address = 0;
- rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, ctxt);
+ rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2,
+ ctxt->vcpu);
if (rc)
return rc;
- rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, ctxt);
+ rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes,
+ ctxt->vcpu);
return rc;
}
+static int test_cc(unsigned int condition, unsigned int flags)
+{
+ int rc = 0;
+
+ switch ((condition & 15) >> 1) {
+ case 0: /* o */
+ rc |= (flags & EFLG_OF);
+ break;
+ case 1: /* b/c/nae */
+ rc |= (flags & EFLG_CF);
+ break;
+ case 2: /* z/e */
+ rc |= (flags & EFLG_ZF);
+ break;
+ case 3: /* be/na */
+ rc |= (flags & (EFLG_CF|EFLG_ZF));
+ break;
+ case 4: /* s */
+ rc |= (flags & EFLG_SF);
+ break;
+ case 5: /* p/pe */
+ rc |= (flags & EFLG_PF);
+ break;
+ case 7: /* le/ng */
+ rc |= (flags & EFLG_ZF);
+ /* fall through */
+ case 6: /* l/nge */
+ rc |= (!(flags & EFLG_SF) != !(flags & EFLG_OF));
+ break;
+ }
+
+ /* Odd condition identifiers (lsb == 1) have inverted sense. */
+ return (!!rc ^ (condition & 1));
+}
+
int
x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
{
@@ -546,11 +597,10 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
case 0xf0: /* LOCK */
lock_prefix = 1;
break;
+ case 0xf2: /* REPNE/REPNZ */
case 0xf3: /* REP/REPE/REPZ */
rep_prefix = 1;
break;
- case 0xf2: /* REPNE/REPNZ */
- break;
default:
goto done_prefixes;
}
@@ -771,11 +821,23 @@ done_prefixes:
goto srcmem_common;
case SrcMem:
src.bytes = (d & ByteOp) ? 1 : op_bytes;
+ /* Don't fetch the address for invlpg: it could be unmapped. */
+ if (twobyte && b == 0x01 && modrm_reg == 7)
+ break;
srcmem_common:
+ /*
+ * For instructions with a ModR/M byte, switch to register
+ * access if Mod = 3.
+ */
+ if ((d & ModRM) && modrm_mod == 3) {
+ src.type = OP_REG;
+ break;
+ }
src.type = OP_MEM;
src.ptr = (unsigned long *)cr2;
+ src.val = 0;
if ((rc = ops->read_emulated((unsigned long)src.ptr,
- &src.val, src.bytes, ctxt)) != 0)
+ &src.val, src.bytes, ctxt->vcpu)) != 0)
goto done;
src.orig_val = src.val;
break;
@@ -814,7 +876,7 @@ done_prefixes:
case DstReg:
dst.type = OP_REG;
if ((d & ByteOp)
- && !(twobyte_table && (b == 0xb6 || b == 0xb7))) {
+ && !(twobyte && (b == 0xb6 || b == 0xb7))) {
dst.ptr = decode_register(modrm_reg, _regs,
(rex_prefix == 0));
dst.val = *(u8 *) dst.ptr;
@@ -838,6 +900,15 @@ done_prefixes:
dst.type = OP_MEM;
dst.ptr = (unsigned long *)cr2;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
+ dst.val = 0;
+ /*
+ * For instructions with a ModR/M byte, switch to register
+ * access if Mod = 3.
+ */
+ if ((d & ModRM) && modrm_mod == 3) {
+ dst.type = OP_REG;
+ break;
+ }
if (d & BitOp) {
unsigned long mask = ~(dst.bytes * 8 - 1);
@@ -845,7 +916,7 @@ done_prefixes:
}
if (!(d & Mov) && /* optimisation - avoid slow emulated read */
((rc = ops->read_emulated((unsigned long)dst.ptr,
- &dst.val, dst.bytes, ctxt)) != 0))
+ &dst.val, dst.bytes, ctxt->vcpu)) != 0))
goto done;
break;
}
@@ -871,10 +942,27 @@ done_prefixes:
sbb: /* sbb */
emulate_2op_SrcV("sbb", src, dst, _eflags);
break;
- case 0x20 ... 0x25:
+ case 0x20 ... 0x23:
and: /* and */
emulate_2op_SrcV("and", src, dst, _eflags);
break;
+ case 0x24: /* and al imm8 */
+ dst.type = OP_REG;
+ dst.ptr = &_regs[VCPU_REGS_RAX];
+ dst.val = *(u8 *)dst.ptr;
+ dst.bytes = 1;
+ dst.orig_val = dst.val;
+ goto and;
+ case 0x25: /* and ax imm16, or eax imm32 */
+ dst.type = OP_REG;
+ dst.bytes = op_bytes;
+ dst.ptr = &_regs[VCPU_REGS_RAX];
+ if (op_bytes == 2)
+ dst.val = *(u16 *)dst.ptr;
+ else
+ dst.val = *(u32 *)dst.ptr;
+ dst.orig_val = dst.val;
+ goto and;
case 0x28 ... 0x2d:
sub: /* sub */
emulate_2op_SrcV("sub", src, dst, _eflags);
@@ -939,18 +1027,10 @@ done_prefixes:
dst.val = src.val;
lock_prefix = 1;
break;
- case 0xa0 ... 0xa1: /* mov */
- dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
- dst.val = src.val;
- _eip += ad_bytes; /* skip src displacement */
- break;
- case 0xa2 ... 0xa3: /* mov */
- dst.val = (unsigned long)_regs[VCPU_REGS_RAX];
- _eip += ad_bytes; /* skip dst displacement */
- break;
case 0x88 ... 0x8b: /* mov */
- case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
- dst.val = src.val;
+ goto mov;
+ case 0x8d: /* lea r16/r32, m */
+ dst.val = modrm_val;
break;
case 0x8f: /* pop (sole member of Grp1a) */
/* 64-bit mode: POP always pops a 64-bit operand. */
@@ -958,10 +1038,19 @@ done_prefixes:
dst.bytes = 8;
if ((rc = ops->read_std(register_address(ctxt->ss_base,
_regs[VCPU_REGS_RSP]),
- &dst.val, dst.bytes, ctxt)) != 0)
+ &dst.val, dst.bytes, ctxt->vcpu)) != 0)
goto done;
register_address_increment(_regs[VCPU_REGS_RSP], dst.bytes);
break;
+ case 0xa0 ... 0xa1: /* mov */
+ dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
+ dst.val = src.val;
+ _eip += ad_bytes; /* skip src displacement */
+ break;
+ case 0xa2 ... 0xa3: /* mov */
+ dst.val = (unsigned long)_regs[VCPU_REGS_RAX];
+ _eip += ad_bytes; /* skip dst displacement */
+ break;
case 0xc0 ... 0xc1:
grp2: /* Grp2 */
switch (modrm_reg) {
@@ -989,6 +1078,10 @@ done_prefixes:
break;
}
break;
+ case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */
+ mov:
+ dst.val = src.val;
+ break;
case 0xd0 ... 0xd1: /* Grp2 */
src.val = 1;
goto grp2;
@@ -1037,13 +1130,19 @@ done_prefixes:
case 1: /* dec */
emulate_1op("dec", dst, _eflags);
break;
+ case 4: /* jmp abs */
+ if (b == 0xff)
+ _eip = dst.val;
+ else
+ goto cannot_emulate;
+ break;
case 6: /* push */
/* 64-bit mode: PUSH always pushes a 64-bit operand. */
if (mode == X86EMUL_MODE_PROT64) {
dst.bytes = 8;
if ((rc = ops->read_std((unsigned long)dst.ptr,
&dst.val, 8,
- ctxt)) != 0)
+ ctxt->vcpu)) != 0)
goto done;
}
register_address_increment(_regs[VCPU_REGS_RSP],
@@ -1051,7 +1150,7 @@ done_prefixes:
if ((rc = ops->write_std(
register_address(ctxt->ss_base,
_regs[VCPU_REGS_RSP]),
- &dst.val, dst.bytes, ctxt)) != 0)
+ &dst.val, dst.bytes, ctxt->vcpu)) != 0)
goto done;
no_wb = 1;
break;
@@ -1086,11 +1185,11 @@ writeback:
rc = ops->cmpxchg_emulated((unsigned long)dst.
ptr, &dst.orig_val,
&dst.val, dst.bytes,
- ctxt);
+ ctxt->vcpu);
else
rc = ops->write_emulated((unsigned long)dst.ptr,
&dst.val, dst.bytes,
- ctxt);
+ ctxt->vcpu);
if (rc != 0)
goto done;
default:
@@ -1109,6 +1208,92 @@ done:
special_insn:
if (twobyte)
goto twobyte_special_insn;
+ switch(b) {
+ case 0x50 ... 0x57: /* push reg */
+ if (op_bytes == 2)
+ src.val = (u16) _regs[b & 0x7];
+ else
+ src.val = (u32) _regs[b & 0x7];
+ dst.type = OP_MEM;
+ dst.bytes = op_bytes;
+ dst.val = src.val;
+ register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes);
+ dst.ptr = (void *) register_address(
+ ctxt->ss_base, _regs[VCPU_REGS_RSP]);
+ break;
+ case 0x58 ... 0x5f: /* pop reg */
+ dst.ptr = (unsigned long *)&_regs[b & 0x7];
+ pop_instruction:
+ if ((rc = ops->read_std(register_address(ctxt->ss_base,
+ _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt->vcpu))
+ != 0)
+ goto done;
+
+ register_address_increment(_regs[VCPU_REGS_RSP], op_bytes);
+ no_wb = 1; /* Disable writeback. */
+ break;
+ case 0x6a: /* push imm8 */
+ src.val = 0L;
+ src.val = insn_fetch(s8, 1, _eip);
+ push:
+ dst.type = OP_MEM;
+ dst.bytes = op_bytes;
+ dst.val = src.val;
+ register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes);
+ dst.ptr = (void *) register_address(ctxt->ss_base,
+ _regs[VCPU_REGS_RSP]);
+ break;
+ case 0x6c: /* insb */
+ case 0x6d: /* insw/insd */
+ if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+ 1, /* in */
+ (d & ByteOp) ? 1 : op_bytes, /* size */
+ rep_prefix ?
+ address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */
+ (_eflags & EFLG_DF), /* down */
+ register_address(ctxt->es_base,
+ _regs[VCPU_REGS_RDI]), /* address */
+ rep_prefix,
+ _regs[VCPU_REGS_RDX] /* port */
+ ) == 0)
+ return -1;
+ return 0;
+ case 0x6e: /* outsb */
+ case 0x6f: /* outsw/outsd */
+ if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+ 0, /* in */
+ (d & ByteOp) ? 1 : op_bytes, /* size */
+ rep_prefix ?
+ address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */
+ (_eflags & EFLG_DF), /* down */
+ register_address(override_base ?
+ *override_base : ctxt->ds_base,
+ _regs[VCPU_REGS_RSI]), /* address */
+ rep_prefix,
+ _regs[VCPU_REGS_RDX] /* port */
+ ) == 0)
+ return -1;
+ return 0;
+ case 0x70 ... 0x7f: /* jcc (short) */ {
+ int rel = insn_fetch(s8, 1, _eip);
+
+ if (test_cc(b, _eflags))
+ JMP_REL(rel);
+ break;
+ }
+ case 0x9c: /* pushf */
+ src.val = (unsigned long) _eflags;
+ goto push;
+ case 0x9d: /* popf */
+ dst.ptr = (unsigned long *) &_eflags;
+ goto pop_instruction;
+ case 0xc3: /* ret */
+ dst.ptr = &_eip;
+ goto pop_instruction;
+ case 0xf4: /* hlt */
+ ctxt->vcpu->halt_request = 1;
+ goto done;
+ }
if (rep_prefix) {
if (_regs[VCPU_REGS_RCX] == 0) {
ctxt->vcpu->rip = _eip;
@@ -1125,7 +1310,7 @@ special_insn:
_regs[VCPU_REGS_RDI]);
if ((rc = ops->read_emulated(register_address(
override_base ? *override_base : ctxt->ds_base,
- _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt)) != 0)
+ _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt->vcpu)) != 0)
goto done;
register_address_increment(_regs[VCPU_REGS_RSI],
(_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
@@ -1147,7 +1332,8 @@ special_insn:
dst.type = OP_REG;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
- if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes, ctxt)) != 0)
+ if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes,
+ ctxt->vcpu)) != 0)
goto done;
register_address_increment(_regs[VCPU_REGS_RSI],
(_eflags & EFLG_DF) ? -dst.bytes : dst.bytes);
@@ -1155,23 +1341,33 @@ special_insn:
case 0xae ... 0xaf: /* scas */
DPRINTF("Urk! I don't handle SCAS.\n");
goto cannot_emulate;
- case 0xf4: /* hlt */
- ctxt->vcpu->halt_request = 1;
- goto done;
- case 0xc3: /* ret */
- dst.ptr = &_eip;
- goto pop_instruction;
- case 0x58 ... 0x5f: /* pop reg */
- dst.ptr = (unsigned long *)&_regs[b & 0x7];
-
-pop_instruction:
- if ((rc = ops->read_std(register_address(ctxt->ss_base,
- _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt)) != 0)
- goto done;
-
- register_address_increment(_regs[VCPU_REGS_RSP], op_bytes);
+ case 0xe8: /* call (near) */ {
+ long int rel;
+ switch (op_bytes) {
+ case 2:
+ rel = insn_fetch(s16, 2, _eip);
+ break;
+ case 4:
+ rel = insn_fetch(s32, 4, _eip);
+ break;
+ case 8:
+ rel = insn_fetch(s64, 8, _eip);
+ break;
+ default:
+ DPRINTF("Call: Invalid op_bytes\n");
+ goto cannot_emulate;
+ }
+ src.val = (unsigned long) _eip;
+ JMP_REL(rel);
+ goto push;
+ }
+ case 0xe9: /* jmp rel */
+ case 0xeb: /* jmp rel short */
+ JMP_REL(src.val);
no_wb = 1; /* Disable writeback. */
break;
+
+
}
goto writeback;
@@ -1230,40 +1426,50 @@ twobyte_insn:
break;
case 0x40 ... 0x4f: /* cmov */
dst.val = dst.orig_val = src.val;
- d &= ~Mov; /* default to no move */
+ no_wb = 1;
/*
* First, assume we're decoding an even cmov opcode
* (lsb == 0).
*/
switch ((b & 15) >> 1) {
case 0: /* cmovo */
- d |= (_eflags & EFLG_OF) ? Mov : 0;
+ no_wb = (_eflags & EFLG_OF) ? 0 : 1;
break;
case 1: /* cmovb/cmovc/cmovnae */
- d |= (_eflags & EFLG_CF) ? Mov : 0;
+ no_wb = (_eflags & EFLG_CF) ? 0 : 1;
break;
case 2: /* cmovz/cmove */
- d |= (_eflags & EFLG_ZF) ? Mov : 0;
+ no_wb = (_eflags & EFLG_ZF) ? 0 : 1;
break;
case 3: /* cmovbe/cmovna */
- d |= (_eflags & (EFLG_CF | EFLG_ZF)) ? Mov : 0;
+ no_wb = (_eflags & (EFLG_CF | EFLG_ZF)) ? 0 : 1;
break;
case 4: /* cmovs */
- d |= (_eflags & EFLG_SF) ? Mov : 0;
+ no_wb = (_eflags & EFLG_SF) ? 0 : 1;
break;
case 5: /* cmovp/cmovpe */
- d |= (_eflags & EFLG_PF) ? Mov : 0;
+ no_wb = (_eflags & EFLG_PF) ? 0 : 1;
break;
case 7: /* cmovle/cmovng */
- d |= (_eflags & EFLG_ZF) ? Mov : 0;
+ no_wb = (_eflags & EFLG_ZF) ? 0 : 1;
/* fall through */
case 6: /* cmovl/cmovnge */
- d |= (!(_eflags & EFLG_SF) !=
- !(_eflags & EFLG_OF)) ? Mov : 0;
+ no_wb &= (!(_eflags & EFLG_SF) !=
+ !(_eflags & EFLG_OF)) ? 0 : 1;
break;
}
/* Odd cmov opcodes (lsb == 1) have inverted sense. */
- d ^= (b & 1) ? Mov : 0;
+ no_wb ^= b & 1;
+ break;
+ case 0xa3:
+ bt: /* bt */
+ src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+ emulate_2op_SrcV_nobyte("bt", src, dst, _eflags);
+ break;
+ case 0xab:
+ bts: /* bts */
+ src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+ emulate_2op_SrcV_nobyte("bts", src, dst, _eflags);
break;
case 0xb0 ... 0xb1: /* cmpxchg */
/*
@@ -1273,8 +1479,6 @@ twobyte_insn:
src.orig_val = src.val;
src.val = _regs[VCPU_REGS_RAX];
emulate_2op_SrcV("cmp", src, dst, _eflags);
- /* Always write back. The question is: where to? */
- d |= Mov;
if (_eflags & EFLG_ZF) {
/* Success: write back to memory. */
dst.val = src.orig_val;
@@ -1284,30 +1488,15 @@ twobyte_insn:
dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX];
}
break;
- case 0xa3:
- bt: /* bt */
- src.val &= (dst.bytes << 3) - 1; /* only subword offset */
- emulate_2op_SrcV_nobyte("bt", src, dst, _eflags);
- break;
case 0xb3:
btr: /* btr */
src.val &= (dst.bytes << 3) - 1; /* only subword offset */
emulate_2op_SrcV_nobyte("btr", src, dst, _eflags);
break;
- case 0xab:
- bts: /* bts */
- src.val &= (dst.bytes << 3) - 1; /* only subword offset */
- emulate_2op_SrcV_nobyte("bts", src, dst, _eflags);
- break;
case 0xb6 ... 0xb7: /* movzx */
dst.bytes = op_bytes;
dst.val = (d & ByteOp) ? (u8) src.val : (u16) src.val;
break;
- case 0xbb:
- btc: /* btc */
- src.val &= (dst.bytes << 3) - 1; /* only subword offset */
- emulate_2op_SrcV_nobyte("btc", src, dst, _eflags);
- break;
case 0xba: /* Grp8 */
switch (modrm_reg & 3) {
case 0:
@@ -1320,10 +1509,19 @@ twobyte_insn:
goto btc;
}
break;
+ case 0xbb:
+ btc: /* btc */
+ src.val &= (dst.bytes << 3) - 1; /* only subword offset */
+ emulate_2op_SrcV_nobyte("btc", src, dst, _eflags);
+ break;
case 0xbe ... 0xbf: /* movsx */
dst.bytes = op_bytes;
dst.val = (d & ByteOp) ? (s8) src.val : (s16) src.val;
break;
+ case 0xc3: /* movnti */
+ dst.bytes = op_bytes;
+ dst.val = (op_bytes == 4) ? (u32) src.val : (u64) src.val;
+ break;
}
goto writeback;
@@ -1331,14 +1529,16 @@ twobyte_special_insn:
/* Disable writeback. */
no_wb = 1;
switch (b) {
+ case 0x06:
+ emulate_clts(ctxt->vcpu);
+ break;
+ case 0x08: /* invd */
+ break;
case 0x09: /* wbinvd */
break;
case 0x0d: /* GrpP (prefetch) */
case 0x18: /* Grp16 (prefetch/nop) */
break;
- case 0x06:
- emulate_clts(ctxt->vcpu);
- break;
case 0x20: /* mov cr, reg */
if (modrm_mod != 3)
goto cannot_emulate;
@@ -1355,7 +1555,7 @@ twobyte_special_insn:
| ((u64)_regs[VCPU_REGS_RDX] << 32);
rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data);
if (rc) {
- kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+ kvm_x86_ops->inject_gp(ctxt->vcpu, 0);
_eip = ctxt->vcpu->rip;
}
rc = X86EMUL_CONTINUE;
@@ -1364,7 +1564,7 @@ twobyte_special_insn:
/* rdmsr */
rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data);
if (rc) {
- kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+ kvm_x86_ops->inject_gp(ctxt->vcpu, 0);
_eip = ctxt->vcpu->rip;
} else {
_regs[VCPU_REGS_RAX] = (u32)msr_data;
@@ -1372,10 +1572,32 @@ twobyte_special_insn:
}
rc = X86EMUL_CONTINUE;
break;
+ case 0x80 ... 0x8f: /* jnz rel, etc*/ {
+ long int rel;
+
+ switch (op_bytes) {
+ case 2:
+ rel = insn_fetch(s16, 2, _eip);
+ break;
+ case 4:
+ rel = insn_fetch(s32, 4, _eip);
+ break;
+ case 8:
+ rel = insn_fetch(s64, 8, _eip);
+ break;
+ default:
+ DPRINTF("jnz: Invalid op_bytes\n");
+ goto cannot_emulate;
+ }
+ if (test_cc(b, _eflags))
+ JMP_REL(rel);
+ break;
+ }
case 0xc7: /* Grp9 (cmpxchg8b) */
{
u64 old, new;
- if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0)
+ if ((rc = ops->read_emulated(cr2, &old, 8, ctxt->vcpu))
+ != 0)
goto done;
if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) ||
((u32) (old >> 32) != (u32) _regs[VCPU_REGS_RDX])) {
@@ -1386,7 +1608,7 @@ twobyte_special_insn:
new = ((u64)_regs[VCPU_REGS_RCX] << 32)
| (u32) _regs[VCPU_REGS_RBX];
if ((rc = ops->cmpxchg_emulated(cr2, &old,
- &new, 8, ctxt)) != 0)
+ &new, 8, ctxt->vcpu)) != 0)
goto done;
_eflags |= EFLG_ZF;
}
diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h
index ea3407d7fee..92c73aa7f9a 100644
--- a/drivers/kvm/x86_emulate.h
+++ b/drivers/kvm/x86_emulate.h
@@ -60,7 +60,7 @@ struct x86_emulate_ops {
* @bytes: [IN ] Number of bytes to read from memory.
*/
int (*read_std)(unsigned long addr, void *val,
- unsigned int bytes, struct x86_emulate_ctxt * ctxt);
+ unsigned int bytes, struct kvm_vcpu *vcpu);
/*
* write_std: Write bytes of standard (non-emulated/special) memory.
@@ -71,7 +71,7 @@ struct x86_emulate_ops {
* @bytes: [IN ] Number of bytes to write to memory.
*/
int (*write_std)(unsigned long addr, const void *val,
- unsigned int bytes, struct x86_emulate_ctxt * ctxt);
+ unsigned int bytes, struct kvm_vcpu *vcpu);
/*
* read_emulated: Read bytes from emulated/special memory area.
@@ -82,7 +82,7 @@ struct x86_emulate_ops {
int (*read_emulated) (unsigned long addr,
void *val,
unsigned int bytes,
- struct x86_emulate_ctxt * ctxt);
+ struct kvm_vcpu *vcpu);
/*
* write_emulated: Read bytes from emulated/special memory area.
@@ -94,7 +94,7 @@ struct x86_emulate_ops {
int (*write_emulated) (unsigned long addr,
const void *val,
unsigned int bytes,
- struct x86_emulate_ctxt * ctxt);
+ struct kvm_vcpu *vcpu);
/*
* cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an
@@ -108,12 +108,10 @@ struct x86_emulate_ops {
const void *old,
const void *new,
unsigned int bytes,
- struct x86_emulate_ctxt * ctxt);
+ struct kvm_vcpu *vcpu);
};
-struct cpu_user_regs;
-
struct x86_emulate_ctxt {
/* Register state before/after emulation. */
struct kvm_vcpu *vcpu;
@@ -154,12 +152,4 @@ struct x86_emulate_ctxt {
int x86_emulate_memop(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops);
-/*
- * Given the 'reg' portion of a ModRM byte, and a register block, return a
- * pointer into the block that addresses the relevant register.
- * @highbyte_regs specifies whether to decode AH,CH,DH,BH.
- */
-void *decode_register(u8 modrm_reg, unsigned long *regs,
- int highbyte_regs);
-
#endif /* __X86_EMULATE_H__ */
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 4468cb3a8d2..ec568fa1c6c 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -83,15 +83,22 @@ config LEDS_WRAP
config LEDS_H1940
tristate "LED Support for iPAQ H1940 device"
- depends LEDS_CLASS && ARCH_H1940
+ depends on LEDS_CLASS && ARCH_H1940
help
This option enables support for the LEDs on the h1940.
-config LEDS_COBALT
- tristate "LED Support for Cobalt Server front LED"
+config LEDS_COBALT_QUBE
+ tristate "LED Support for the Cobalt Qube series front LED"
depends on LEDS_CLASS && MIPS_COBALT
help
- This option enables support for the front LED on Cobalt Server
+ This option enables support for the front LED on Cobalt Qube series
+
+config LEDS_COBALT_RAQ
+ bool "LED Support for the Cobalt Raq series"
+ depends on LEDS_CLASS && MIPS_COBALT
+ select LEDS_TRIGGERS
+ help
+ This option enables support for the Cobalt Raq series LEDs.
config LEDS_GPIO
tristate "LED Support for GPIO connected LEDs"
@@ -101,6 +108,12 @@ config LEDS_GPIO
outputs. To be useful the particular board must have LEDs
and they must be connected to the GPIO lines.
+config LEDS_CM_X270
+ tristate "LED Support for the CM-X270 LEDs"
+ depends on LEDS_CLASS && MACH_ARMCORE
+ help
+ This option enables support for the CM-X270 LEDs.
+
comment "LED Triggers"
config LEDS_TRIGGERS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index f8995c9bc2e..a60de1b46c2 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -15,8 +15,10 @@ obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
-obj-$(CONFIG_LEDS_COBALT) += leds-cobalt.o
+obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
+obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
+obj-$(CONFIG_LEDS_CM_X270) += leds-cm-x270.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
diff --git a/drivers/leds/leds-cm-x270.c b/drivers/leds/leds-cm-x270.c
new file mode 100644
index 00000000000..9aebef02a97
--- /dev/null
+++ b/drivers/leds/leds-cm-x270.c
@@ -0,0 +1,122 @@
+/*
+ * drivers/leds/leds-cm-x270.c
+ *
+ * Copyright 2007 CompuLab Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on leds-corgi.c
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+
+#define GPIO_RED_LED (93)
+#define GPIO_GREEN_LED (94)
+
+static void cmx270_red_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (value)
+ GPCR(GPIO_RED_LED) = GPIO_bit(GPIO_RED_LED);
+ else
+ GPSR(GPIO_RED_LED) = GPIO_bit(GPIO_RED_LED);
+}
+
+static void cmx270_green_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (value)
+ GPCR(GPIO_GREEN_LED) = GPIO_bit(GPIO_GREEN_LED);
+ else
+ GPSR(GPIO_GREEN_LED) = GPIO_bit(GPIO_GREEN_LED);
+}
+
+static struct led_classdev cmx270_red_led = {
+ .name = "cm-x270:red",
+ .default_trigger = "nand-disk",
+ .brightness_set = cmx270_red_set,
+};
+
+static struct led_classdev cmx270_green_led = {
+ .name = "cm-x270:green",
+ .default_trigger = "heartbeat",
+ .brightness_set = cmx270_green_set,
+};
+
+#ifdef CONFIG_PM
+static int cmx270led_suspend(struct platform_device *dev, pm_message_t state)
+{
+ led_classdev_suspend(&cmx270_red_led);
+ led_classdev_suspend(&cmx270_green_led);
+ return 0;
+}
+
+static int cmx270led_resume(struct platform_device *dev)
+{
+ led_classdev_resume(&cmx270_red_led);
+ led_classdev_resume(&cmx270_green_led);
+ return 0;
+}
+#endif
+
+static int cmx270led_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = led_classdev_register(&pdev->dev, &cmx270_red_led);
+ if (ret < 0)
+ return ret;
+
+ ret = led_classdev_register(&pdev->dev, &cmx270_green_led);
+ if (ret < 0)
+ led_classdev_unregister(&cmx270_red_led);
+
+ return ret;
+}
+
+static int cmx270led_remove(struct platform_device *pdev)
+{
+ led_classdev_unregister(&cmx270_red_led);
+ led_classdev_unregister(&cmx270_green_led);
+ return 0;
+}
+
+static struct platform_driver cmx270led_driver = {
+ .probe = cmx270led_probe,
+ .remove = cmx270led_remove,
+#ifdef CONFIG_PM
+ .suspend = cmx270led_suspend,
+ .resume = cmx270led_resume,
+#endif
+ .driver = {
+ .name = "cm-x270-led",
+ },
+};
+
+static int __init cmx270led_init(void)
+{
+ return platform_driver_register(&cmx270led_driver);
+}
+
+static void __exit cmx270led_exit(void)
+{
+ platform_driver_unregister(&cmx270led_driver);
+}
+
+module_init(cmx270led_init);
+module_exit(cmx270led_exit);
+
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("CM-x270 LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-cobalt-qube.c b/drivers/leds/leds-cobalt-qube.c
new file mode 100644
index 00000000000..d2b54b53d80
--- /dev/null
+++ b/drivers/leds/leds-cobalt-qube.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2006 - Florian Fainelli <florian@openwrt.org>
+ *
+ * Control the Cobalt Qube/RaQ front LED
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#define LED_FRONT_LEFT 0x01
+#define LED_FRONT_RIGHT 0x02
+
+static void __iomem *led_port;
+static u8 led_value;
+
+static void qube_front_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ if (brightness)
+ led_value = LED_FRONT_LEFT | LED_FRONT_RIGHT;
+ else
+ led_value = ~(LED_FRONT_LEFT | LED_FRONT_RIGHT);
+ writeb(led_value, led_port);
+}
+
+static struct led_classdev qube_front_led = {
+ .name = "qube-front",
+ .brightness = LED_FULL,
+ .brightness_set = qube_front_led_set,
+ .default_trigger = "ide-disk",
+};
+
+static int __devinit cobalt_qube_led_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int retval;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EBUSY;
+
+ led_port = ioremap(res->start, res->end - res->start + 1);
+ if (!led_port)
+ return -ENOMEM;
+
+ led_value = LED_FRONT_LEFT | LED_FRONT_RIGHT;
+ writeb(led_value, led_port);
+
+ retval = led_classdev_register(&pdev->dev, &qube_front_led);
+ if (retval)
+ goto err_iounmap;
+
+ return 0;
+
+err_iounmap:
+ iounmap(led_port);
+ led_port = NULL;
+
+ return retval;
+}
+
+static int __devexit cobalt_qube_led_remove(struct platform_device *pdev)
+{
+ led_classdev_unregister(&qube_front_led);
+
+ if (led_port) {
+ iounmap(led_port);
+ led_port = NULL;
+ }
+
+ return 0;
+}
+
+static struct platform_driver cobalt_qube_led_driver = {
+ .probe = cobalt_qube_led_probe,
+ .remove = __devexit_p(cobalt_qube_led_remove),
+ .driver = {
+ .name = "cobalt-qube-leds",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cobalt_qube_led_init(void)
+{
+ return platform_driver_register(&cobalt_qube_led_driver);
+}
+
+static void __exit cobalt_qube_led_exit(void)
+{
+ platform_driver_unregister(&cobalt_qube_led_driver);
+}
+
+module_init(cobalt_qube_led_init);
+module_exit(cobalt_qube_led_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Front LED support for Cobalt Server");
+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
diff --git a/drivers/leds/leds-cobalt-raq.c b/drivers/leds/leds-cobalt-raq.c
new file mode 100644
index 00000000000..6ebfff341e6
--- /dev/null
+++ b/drivers/leds/leds-cobalt-raq.c
@@ -0,0 +1,138 @@
+/*
+ * LEDs driver for the Cobalt Raq series.
+ *
+ * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#define LED_WEB 0x04
+#define LED_POWER_OFF 0x08
+
+static void __iomem *led_port;
+static u8 led_value;
+static DEFINE_SPINLOCK(led_value_lock);
+
+static void raq_web_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&led_value_lock, flags);
+
+ if (brightness)
+ led_value |= LED_WEB;
+ else
+ led_value &= ~LED_WEB;
+ writeb(led_value, led_port);
+
+ spin_unlock_irqrestore(&led_value_lock, flags);
+}
+
+static struct led_classdev raq_web_led = {
+ .name = "raq-web",
+ .brightness_set = raq_web_led_set,
+};
+
+static void raq_power_off_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&led_value_lock, flags);
+
+ if (brightness)
+ led_value |= LED_POWER_OFF;
+ else
+ led_value &= ~LED_POWER_OFF;
+ writeb(led_value, led_port);
+
+ spin_unlock_irqrestore(&led_value_lock, flags);
+}
+
+static struct led_classdev raq_power_off_led = {
+ .name = "raq-power-off",
+ .brightness_set = raq_power_off_led_set,
+ .default_trigger = "power-off",
+};
+
+static int __devinit cobalt_raq_led_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int retval;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EBUSY;
+
+ led_port = ioremap(res->start, res->end - res->start + 1);
+ if (!led_port)
+ return -ENOMEM;
+
+ retval = led_classdev_register(&pdev->dev, &raq_power_off_led);
+ if (retval)
+ goto err_iounmap;
+
+ retval = led_classdev_register(&pdev->dev, &raq_web_led);
+ if (retval)
+ goto err_unregister;
+
+ return 0;
+
+err_unregister:
+ led_classdev_unregister(&raq_power_off_led);
+
+err_iounmap:
+ iounmap(led_port);
+ led_port = NULL;
+
+ return retval;
+}
+
+static int __devexit cobalt_raq_led_remove(struct platform_device *pdev)
+{
+ led_classdev_unregister(&raq_power_off_led);
+ led_classdev_unregister(&raq_web_led);
+
+ if (led_port) {
+ iounmap(led_port);
+ led_port = NULL;
+ }
+
+ return 0;
+}
+
+static struct platform_driver cobalt_raq_led_driver = {
+ .probe = cobalt_raq_led_probe,
+ .remove = __devexit_p(cobalt_raq_led_remove),
+ .driver = {
+ .name = "cobalt-raq-leds",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cobalt_raq_led_init(void)
+{
+ return platform_driver_register(&cobalt_raq_led_driver);
+}
+
+module_init(cobalt_raq_led_init);
diff --git a/drivers/leds/leds-cobalt.c b/drivers/leds/leds-cobalt.c
deleted file mode 100644
index d16439ce5da..00000000000
--- a/drivers/leds/leds-cobalt.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2006 - Florian Fainelli <florian@openwrt.org>
- *
- * Control the Cobalt Qube/RaQ front LED
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/leds.h>
-#include <asm/mach-cobalt/cobalt.h>
-
-static void cobalt_led_set(struct led_classdev *led_cdev, enum led_brightness brightness)
-{
- if (brightness)
- COBALT_LED_PORT = COBALT_LED_BAR_LEFT | COBALT_LED_BAR_RIGHT;
- else
- COBALT_LED_PORT = 0;
-}
-
-static struct led_classdev cobalt_led = {
- .name = "cobalt-front-led",
- .brightness_set = cobalt_led_set,
- .default_trigger = "ide-disk",
-};
-
-static int __init cobalt_led_init(void)
-{
- return led_classdev_register(NULL, &cobalt_led);
-}
-
-static void __exit cobalt_led_exit(void)
-{
- led_classdev_unregister(&cobalt_led);
-}
-
-module_init(cobalt_led_init);
-module_exit(cobalt_led_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Front LED support for Cobalt Server");
-MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 47d90db280c..99bc50059d3 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -60,7 +60,7 @@ static void gpio_led_set(struct led_classdev *led_cdev,
gpio_set_value(led_dat->gpio, level);
}
-static int __init gpio_led_probe(struct platform_device *pdev)
+static int gpio_led_probe(struct platform_device *pdev)
{
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
struct gpio_led *cur_led;
@@ -93,13 +93,13 @@ static int __init gpio_led_probe(struct platform_device *pdev)
gpio_direction_output(led_dat->gpio, led_dat->active_low);
+ INIT_WORK(&led_dat->work, gpio_led_work);
+
ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
if (ret < 0) {
gpio_free(led_dat->gpio);
goto err;
}
-
- INIT_WORK(&led_dat->work, gpio_led_work);
}
platform_set_drvdata(pdev, leds_data);
@@ -110,17 +110,17 @@ err:
if (i > 0) {
for (i = i - 1; i >= 0; i--) {
led_classdev_unregister(&leds_data[i].cdev);
+ cancel_work_sync(&leds_data[i].work);
gpio_free(leds_data[i].gpio);
}
}
- flush_scheduled_work();
kfree(leds_data);
return ret;
}
-static int __exit gpio_led_remove(struct platform_device *pdev)
+static int __devexit gpio_led_remove(struct platform_device *pdev)
{
int i;
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
@@ -130,9 +130,10 @@ static int __exit gpio_led_remove(struct platform_device *pdev)
for (i = 0; i < pdata->num_leds; i++) {
led_classdev_unregister(&leds_data[i].cdev);
+ cancel_work_sync(&leds_data[i].work);
gpio_free(leds_data[i].gpio);
}
-
+
kfree(leds_data);
return 0;
@@ -144,7 +145,7 @@ static int gpio_led_suspend(struct platform_device *pdev, pm_message_t state)
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
struct gpio_led_data *leds_data;
int i;
-
+
leds_data = platform_get_drvdata(pdev);
for (i = 0; i < pdata->num_leds; i++)
@@ -172,7 +173,8 @@ static int gpio_led_resume(struct platform_device *pdev)
#endif
static struct platform_driver gpio_led_driver = {
- .remove = __exit_p(gpio_led_remove),
+ .probe = gpio_led_probe,
+ .remove = __devexit_p(gpio_led_remove),
.suspend = gpio_led_suspend,
.resume = gpio_led_resume,
.driver = {
@@ -183,7 +185,7 @@ static struct platform_driver gpio_led_driver = {
static int __init gpio_led_init(void)
{
- return platform_driver_probe(&gpio_led_driver, gpio_led_probe);
+ return platform_driver_register(&gpio_led_driver);
}
static void __exit gpio_led_exit(void)
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index 50914439d86..0fd64075129 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -43,7 +43,7 @@ static void s3c24xx_led_set(struct led_classdev *led_cdev,
struct s3c24xx_gpio_led *led = to_gpio(led_cdev);
struct s3c24xx_led_platdata *pd = led->pdata;
- /* there will be a sort delay between setting the output and
+ /* there will be a short delay between setting the output and
* going from output to input when using tristate. */
s3c2410_gpio_setpin(pd->gpio, (value ? 1 : 0) ^
diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig
index 41e2250613a..7eb9ecff8f4 100644
--- a/drivers/lguest/Kconfig
+++ b/drivers/lguest/Kconfig
@@ -1,7 +1,6 @@
config LGUEST
tristate "Linux hypervisor example code"
- depends on X86 && PARAVIRT && EXPERIMENTAL && !X86_PAE && FUTEX
- select LGUEST_GUEST
+ depends on X86_32 && EXPERIMENTAL && !X86_PAE && FUTEX && !(X86_VISWS || X86_VOYAGER)
select HVC_DRIVER
---help---
This is a very simple module which allows you to run
@@ -18,13 +17,3 @@ config LGUEST_GUEST
The guest needs code built-in, even if the host has lguest
support as a module. The drivers are tiny, so we build them
in too.
-
-config LGUEST_NET
- tristate
- default y
- depends on LGUEST_GUEST && NET
-
-config LGUEST_BLOCK
- tristate
- default y
- depends on LGUEST_GUEST && BLOCK
diff --git a/drivers/lguest/Makefile b/drivers/lguest/Makefile
index e5047471c33..5e8272d296d 100644
--- a/drivers/lguest/Makefile
+++ b/drivers/lguest/Makefile
@@ -1,10 +1,12 @@
-# Guest requires the paravirt_ops replacement and the bus driver.
-obj-$(CONFIG_LGUEST_GUEST) += lguest.o lguest_asm.o lguest_bus.o
+# Guest requires the device configuration and probing code.
+obj-$(CONFIG_LGUEST_GUEST) += lguest_device.o
# Host requires the other files, which can be a module.
obj-$(CONFIG_LGUEST) += lg.o
-lg-y := core.o hypercalls.o page_tables.o interrupts_and_traps.o \
- segments.o io.o lguest_user.o switcher.o
+lg-y = core.o hypercalls.o page_tables.o interrupts_and_traps.o \
+ segments.o lguest_user.o
+
+lg-$(CONFIG_X86_32) += x86/switcher_32.o x86/core.o
Preparation Preparation!: PREFIX=P
Guest: PREFIX=G
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
index 4a315f08a56..cb4c67025d5 100644
--- a/drivers/lguest/core.c
+++ b/drivers/lguest/core.c
@@ -11,58 +11,20 @@
#include <linux/vmalloc.h>
#include <linux/cpu.h>
#include <linux/freezer.h>
+#include <linux/highmem.h>
#include <asm/paravirt.h>
-#include <asm/desc.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/poll.h>
-#include <asm/highmem.h>
#include <asm/asm-offsets.h>
-#include <asm/i387.h>
#include "lg.h"
-/* Found in switcher.S */
-extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
-extern unsigned long default_idt_entries[];
-
-/* Every guest maps the core switcher code. */
-#define SHARED_SWITCHER_PAGES \
- DIV_ROUND_UP(end_switcher_text - start_switcher_text, PAGE_SIZE)
-/* Pages for switcher itself, then two pages per cpu */
-#define TOTAL_SWITCHER_PAGES (SHARED_SWITCHER_PAGES + 2 * NR_CPUS)
-
-/* We map at -4M for ease of mapping into the guest (one PTE page). */
-#define SWITCHER_ADDR 0xFFC00000
static struct vm_struct *switcher_vma;
static struct page **switcher_page;
-static int cpu_had_pge;
-static struct {
- unsigned long offset;
- unsigned short segment;
-} lguest_entry;
-
/* This One Big lock protects all inter-guest data structures. */
DEFINE_MUTEX(lguest_lock);
-static DEFINE_PER_CPU(struct lguest *, last_guest);
-
-/* FIXME: Make dynamic. */
-#define MAX_LGUEST_GUESTS 16
-struct lguest lguests[MAX_LGUEST_GUESTS];
-
-/* Offset from where switcher.S was compiled to where we've copied it */
-static unsigned long switcher_offset(void)
-{
- return SWITCHER_ADDR - (unsigned long)start_switcher_text;
-}
-
-/* This cpu's struct lguest_pages. */
-static struct lguest_pages *lguest_pages(unsigned int cpu)
-{
- return &(((struct lguest_pages *)
- (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]);
-}
/*H:010 We need to set up the Switcher at a high virtual address. Remember the
* Switcher is a few hundred bytes of assembler code which actually changes the
@@ -73,9 +35,7 @@ static struct lguest_pages *lguest_pages(unsigned int cpu)
* Host since it will be running as the switchover occurs.
*
* Trying to map memory at a particular address is an unusual thing to do, so
- * it's not a simple one-liner. We also set up the per-cpu parts of the
- * Switcher here.
- */
+ * it's not a simple one-liner. */
static __init int map_switcher(void)
{
int i, err;
@@ -132,90 +92,11 @@ static __init int map_switcher(void)
goto free_vma;
}
- /* Now the switcher is mapped at the right address, we can't fail!
- * Copy in the compiled-in Switcher code (from switcher.S). */
+ /* Now the Switcher is mapped at the right address, we can't fail!
+ * Copy in the compiled-in Switcher code (from <arch>_switcher.S). */
memcpy(switcher_vma->addr, start_switcher_text,
end_switcher_text - start_switcher_text);
- /* Most of the switcher.S doesn't care that it's been moved; on Intel,
- * jumps are relative, and it doesn't access any references to external
- * code or data.
- *
- * The only exception is the interrupt handlers in switcher.S: their
- * addresses are placed in a table (default_idt_entries), so we need to
- * update the table with the new addresses. switcher_offset() is a
- * convenience function which returns the distance between the builtin
- * switcher code and the high-mapped copy we just made. */
- for (i = 0; i < IDT_ENTRIES; i++)
- default_idt_entries[i] += switcher_offset();
-
- /*
- * Set up the Switcher's per-cpu areas.
- *
- * Each CPU gets two pages of its own within the high-mapped region
- * (aka. "struct lguest_pages"). Much of this can be initialized now,
- * but some depends on what Guest we are running (which is set up in
- * copy_in_guest_info()).
- */
- for_each_possible_cpu(i) {
- /* lguest_pages() returns this CPU's two pages. */
- struct lguest_pages *pages = lguest_pages(i);
- /* This is a convenience pointer to make the code fit one
- * statement to a line. */
- struct lguest_ro_state *state = &pages->state;
-
- /* The Global Descriptor Table: the Host has a different one
- * for each CPU. We keep a descriptor for the GDT which says
- * where it is and how big it is (the size is actually the last
- * byte, not the size, hence the "-1"). */
- state->host_gdt_desc.size = GDT_SIZE-1;
- state->host_gdt_desc.address = (long)get_cpu_gdt_table(i);
-
- /* All CPUs on the Host use the same Interrupt Descriptor
- * Table, so we just use store_idt(), which gets this CPU's IDT
- * descriptor. */
- store_idt(&state->host_idt_desc);
-
- /* The descriptors for the Guest's GDT and IDT can be filled
- * out now, too. We copy the GDT & IDT into ->guest_gdt and
- * ->guest_idt before actually running the Guest. */
- state->guest_idt_desc.size = sizeof(state->guest_idt)-1;
- state->guest_idt_desc.address = (long)&state->guest_idt;
- state->guest_gdt_desc.size = sizeof(state->guest_gdt)-1;
- state->guest_gdt_desc.address = (long)&state->guest_gdt;
-
- /* We know where we want the stack to be when the Guest enters
- * the switcher: in pages->regs. The stack grows upwards, so
- * we start it at the end of that structure. */
- state->guest_tss.esp0 = (long)(&pages->regs + 1);
- /* And this is the GDT entry to use for the stack: we keep a
- * couple of special LGUEST entries. */
- state->guest_tss.ss0 = LGUEST_DS;
-
- /* x86 can have a finegrained bitmap which indicates what I/O
- * ports the process can use. We set it to the end of our
- * structure, meaning "none". */
- state->guest_tss.io_bitmap_base = sizeof(state->guest_tss);
-
- /* Some GDT entries are the same across all Guests, so we can
- * set them up now. */
- setup_default_gdt_entries(state);
- /* Most IDT entries are the same for all Guests, too.*/
- setup_default_idt_entries(state, default_idt_entries);
-
- /* The Host needs to be able to use the LGUEST segments on this
- * CPU, too, so put them in the Host GDT. */
- get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
- get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
- }
-
- /* In the Switcher, we want the %cs segment register to use the
- * LGUEST_CS GDT entry: we've put that in the Host and Guest GDTs, so
- * it will be undisturbed when we switch. To change %cs and jump we
- * need this structure to feed to Intel's "lcall" instruction. */
- lguest_entry.offset = (long)switch_to_guest + switcher_offset();
- lguest_entry.segment = LGUEST_CS;
-
printk(KERN_INFO "lguest: mapped switcher at %p\n",
switcher_vma->addr);
/* And we succeeded... */
@@ -247,86 +128,15 @@ static void unmap_switcher(void)
__free_pages(switcher_page[i], 0);
}
-/*H:130 Our Guest is usually so well behaved; it never tries to do things it
- * isn't allowed to. Unfortunately, "struct paravirt_ops" isn't quite
- * complete, because it doesn't contain replacements for the Intel I/O
- * instructions. As a result, the Guest sometimes fumbles across one during
- * the boot process as it probes for various things which are usually attached
- * to a PC.
- *
- * When the Guest uses one of these instructions, we get trap #13 (General
- * Protection Fault) and come here. We see if it's one of those troublesome
- * instructions and skip over it. We return true if we did. */
-static int emulate_insn(struct lguest *lg)
-{
- u8 insn;
- unsigned int insnlen = 0, in = 0, shift = 0;
- /* The eip contains the *virtual* address of the Guest's instruction:
- * guest_pa just subtracts the Guest's page_offset. */
- unsigned long physaddr = guest_pa(lg, lg->regs->eip);
-
- /* The guest_pa() function only works for Guest kernel addresses, but
- * that's all we're trying to do anyway. */
- if (lg->regs->eip < lg->page_offset)
- return 0;
-
- /* Decoding x86 instructions is icky. */
- lgread(lg, &insn, physaddr, 1);
-
- /* 0x66 is an "operand prefix". It means it's using the upper 16 bits
- of the eax register. */
- if (insn == 0x66) {
- shift = 16;
- /* The instruction is 1 byte so far, read the next byte. */
- insnlen = 1;
- lgread(lg, &insn, physaddr + insnlen, 1);
- }
-
- /* We can ignore the lower bit for the moment and decode the 4 opcodes
- * we need to emulate. */
- switch (insn & 0xFE) {
- case 0xE4: /* in <next byte>,%al */
- insnlen += 2;
- in = 1;
- break;
- case 0xEC: /* in (%dx),%al */
- insnlen += 1;
- in = 1;
- break;
- case 0xE6: /* out %al,<next byte> */
- insnlen += 2;
- break;
- case 0xEE: /* out %al,(%dx) */
- insnlen += 1;
- break;
- default:
- /* OK, we don't know what this is, can't emulate. */
- return 0;
- }
-
- /* If it was an "IN" instruction, they expect the result to be read
- * into %eax, so we change %eax. We always return all-ones, which
- * traditionally means "there's nothing there". */
- if (in) {
- /* Lower bit tells is whether it's a 16 or 32 bit access */
- if (insn & 0x1)
- lg->regs->eax = 0xFFFFFFFF;
- else
- lg->regs->eax |= (0xFFFF << shift);
- }
- /* Finally, we've "done" the instruction, so move past it. */
- lg->regs->eip += insnlen;
- /* Success! */
- return 1;
-}
-/*:*/
-
-/*L:305
+/*H:032
* Dealing With Guest Memory.
*
+ * Before we go too much further into the Host, we need to grok the routines
+ * we use to deal with Guest memory.
+ *
* When the Guest gives us (what it thinks is) a physical address, we can use
- * the normal copy_from_user() & copy_to_user() on that address: remember,
- * Guest physical == Launcher virtual.
+ * the normal copy_from_user() & copy_to_user() on the corresponding place in
+ * the memory region allocated by the Launcher.
*
* But we can't trust the Guest: it might be trying to access the Launcher
* code. We have to check that the range is below the pfn_limit the Launcher
@@ -338,148 +148,27 @@ int lguest_address_ok(const struct lguest *lg,
return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
}
-/* This is a convenient routine to get a 32-bit value from the Guest (a very
- * common operation). Here we can see how useful the kill_lguest() routine we
- * met in the Launcher can be: we return a random value (0) instead of needing
- * to return an error. */
-u32 lgread_u32(struct lguest *lg, unsigned long addr)
-{
- u32 val = 0;
-
- /* Don't let them access lguest binary. */
- if (!lguest_address_ok(lg, addr, sizeof(val))
- || get_user(val, (u32 __user *)addr) != 0)
- kill_guest(lg, "bad read address %#lx", addr);
- return val;
-}
-
-/* Same thing for writing a value. */
-void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val)
-{
- if (!lguest_address_ok(lg, addr, sizeof(val))
- || put_user(val, (u32 __user *)addr) != 0)
- kill_guest(lg, "bad write address %#lx", addr);
-}
-
-/* This routine is more generic, and copies a range of Guest bytes into a
- * buffer. If the copy_from_user() fails, we fill the buffer with zeroes, so
- * the caller doesn't end up using uninitialized kernel memory. */
-void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
+/* This routine copies memory from the Guest. Here we can see how useful the
+ * kill_lguest() routine we met in the Launcher can be: we return a random
+ * value (all zeroes) instead of needing to return an error. */
+void __lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
{
if (!lguest_address_ok(lg, addr, bytes)
- || copy_from_user(b, (void __user *)addr, bytes) != 0) {
+ || copy_from_user(b, lg->mem_base + addr, bytes) != 0) {
/* copy_from_user should do this, but as we rely on it... */
memset(b, 0, bytes);
kill_guest(lg, "bad read address %#lx len %u", addr, bytes);
}
}
-/* Similarly, our generic routine to copy into a range of Guest bytes. */
-void lgwrite(struct lguest *lg, unsigned long addr, const void *b,
- unsigned bytes)
+/* This is the write (copy into guest) version. */
+void __lgwrite(struct lguest *lg, unsigned long addr, const void *b,
+ unsigned bytes)
{
if (!lguest_address_ok(lg, addr, bytes)
- || copy_to_user((void __user *)addr, b, bytes) != 0)
+ || copy_to_user(lg->mem_base + addr, b, bytes) != 0)
kill_guest(lg, "bad write address %#lx len %u", addr, bytes);
}
-/* (end of memory access helper routines) :*/
-
-static void set_ts(void)
-{
- u32 cr0;
-
- cr0 = read_cr0();
- if (!(cr0 & 8))
- write_cr0(cr0|8);
-}
-
-/*S:010
- * We are getting close to the Switcher.
- *
- * Remember that each CPU has two pages which are visible to the Guest when it
- * runs on that CPU. This has to contain the state for that Guest: we copy the
- * state in just before we run the Guest.
- *
- * Each Guest has "changed" flags which indicate what has changed in the Guest
- * since it last ran. We saw this set in interrupts_and_traps.c and
- * segments.c.
- */
-static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
-{
- /* Copying all this data can be quite expensive. We usually run the
- * same Guest we ran last time (and that Guest hasn't run anywhere else
- * meanwhile). If that's not the case, we pretend everything in the
- * Guest has changed. */
- if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) {
- __get_cpu_var(last_guest) = lg;
- lg->last_pages = pages;
- lg->changed = CHANGED_ALL;
- }
-
- /* These copies are pretty cheap, so we do them unconditionally: */
- /* Save the current Host top-level page directory. */
- pages->state.host_cr3 = __pa(current->mm->pgd);
- /* Set up the Guest's page tables to see this CPU's pages (and no
- * other CPU's pages). */
- map_switcher_in_guest(lg, pages);
- /* Set up the two "TSS" members which tell the CPU what stack to use
- * for traps which do directly into the Guest (ie. traps at privilege
- * level 1). */
- pages->state.guest_tss.esp1 = lg->esp1;
- pages->state.guest_tss.ss1 = lg->ss1;
-
- /* Copy direct-to-Guest trap entries. */
- if (lg->changed & CHANGED_IDT)
- copy_traps(lg, pages->state.guest_idt, default_idt_entries);
-
- /* Copy all GDT entries which the Guest can change. */
- if (lg->changed & CHANGED_GDT)
- copy_gdt(lg, pages->state.guest_gdt);
- /* If only the TLS entries have changed, copy them. */
- else if (lg->changed & CHANGED_GDT_TLS)
- copy_gdt_tls(lg, pages->state.guest_gdt);
-
- /* Mark the Guest as unchanged for next time. */
- lg->changed = 0;
-}
-
-/* Finally: the code to actually call into the Switcher to run the Guest. */
-static void run_guest_once(struct lguest *lg, struct lguest_pages *pages)
-{
- /* This is a dummy value we need for GCC's sake. */
- unsigned int clobber;
-
- /* Copy the guest-specific information into this CPU's "struct
- * lguest_pages". */
- copy_in_guest_info(lg, pages);
-
- /* Set the trap number to 256 (impossible value). If we fault while
- * switching to the Guest (bad segment registers or bug), this will
- * cause us to abort the Guest. */
- lg->regs->trapnum = 256;
-
- /* Now: we push the "eflags" register on the stack, then do an "lcall".
- * This is how we change from using the kernel code segment to using
- * the dedicated lguest code segment, as well as jumping into the
- * Switcher.
- *
- * The lcall also pushes the old code segment (KERNEL_CS) onto the
- * stack, then the address of this call. This stack layout happens to
- * exactly match the stack of an interrupt... */
- asm volatile("pushf; lcall *lguest_entry"
- /* This is how we tell GCC that %eax ("a") and %ebx ("b")
- * are changed by this routine. The "=" means output. */
- : "=a"(clobber), "=b"(clobber)
- /* %eax contains the pages pointer. ("0" refers to the
- * 0-th argument above, ie "a"). %ebx contains the
- * physical address of the Guest's top-level page
- * directory. */
- : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir))
- /* We tell gcc that all these registers could change,
- * which means we don't have to save and restore them in
- * the Switcher. */
- : "memory", "%edx", "%ecx", "%edi", "%esi");
-}
/*:*/
/*H:030 Let's jump straight to the the main loop which runs the Guest.
@@ -489,22 +178,16 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
{
/* We stop running once the Guest is dead. */
while (!lg->dead) {
- /* We need to initialize this, otherwise gcc complains. It's
- * not (yet) clever enough to see that it's initialized when we
- * need it. */
- unsigned int cr2 = 0; /* Damn gcc */
-
- /* First we run any hypercalls the Guest wants done: either in
- * the hypercall ring in "struct lguest_data", or directly by
- * using int 31 (LGUEST_TRAP_ENTRY). */
- do_hypercalls(lg);
- /* It's possible the Guest did a SEND_DMA hypercall to the
+ /* First we run any hypercalls the Guest wants done. */
+ if (lg->hcall)
+ do_hypercalls(lg);
+
+ /* It's possible the Guest did a NOTIFY hypercall to the
* Launcher, in which case we return from the read() now. */
- if (lg->dma_is_pending) {
- if (put_user(lg->pending_dma, user) ||
- put_user(lg->pending_key, user+1))
+ if (lg->pending_notify) {
+ if (put_user(lg->pending_notify, user))
return -EFAULT;
- return sizeof(unsigned long)*2;
+ return sizeof(lg->pending_notify);
}
/* Check for signals */
@@ -542,144 +225,20 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
* the "Do Not Disturb" sign: */
local_irq_disable();
- /* Remember the awfully-named TS bit? If the Guest has asked
- * to set it we set it now, so we can trap and pass that trap
- * to the Guest if it uses the FPU. */
- if (lg->ts)
- set_ts();
-
- /* SYSENTER is an optimized way of doing system calls. We
- * can't allow it because it always jumps to privilege level 0.
- * A normal Guest won't try it because we don't advertise it in
- * CPUID, but a malicious Guest (or malicious Guest userspace
- * program) could, so we tell the CPU to disable it before
- * running the Guest. */
- if (boot_cpu_has(X86_FEATURE_SEP))
- wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
-
- /* Now we actually run the Guest. It will pop back out when
- * something interesting happens, and we can examine its
- * registers to see what it was doing. */
- run_guest_once(lg, lguest_pages(raw_smp_processor_id()));
-
- /* The "regs" pointer contains two extra entries which are not
- * really registers: a trap number which says what interrupt or
- * trap made the switcher code come back, and an error code
- * which some traps set. */
-
- /* If the Guest page faulted, then the cr2 register will tell
- * us the bad virtual address. We have to grab this now,
- * because once we re-enable interrupts an interrupt could
- * fault and thus overwrite cr2, or we could even move off to a
- * different CPU. */
- if (lg->regs->trapnum == 14)
- cr2 = read_cr2();
- /* Similarly, if we took a trap because the Guest used the FPU,
- * we have to restore the FPU it expects to see. */
- else if (lg->regs->trapnum == 7)
- math_state_restore();
-
- /* Restore SYSENTER if it's supposed to be on. */
- if (boot_cpu_has(X86_FEATURE_SEP))
- wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
+ /* Actually run the Guest until something happens. */
+ lguest_arch_run_guest(lg);
/* Now we're ready to be interrupted or moved to other CPUs */
local_irq_enable();
- /* OK, so what happened? */
- switch (lg->regs->trapnum) {
- case 13: /* We've intercepted a GPF. */
- /* Check if this was one of those annoying IN or OUT
- * instructions which we need to emulate. If so, we
- * just go back into the Guest after we've done it. */
- if (lg->regs->errcode == 0) {
- if (emulate_insn(lg))
- continue;
- }
- break;
- case 14: /* We've intercepted a page fault. */
- /* The Guest accessed a virtual address that wasn't
- * mapped. This happens a lot: we don't actually set
- * up most of the page tables for the Guest at all when
- * we start: as it runs it asks for more and more, and
- * we set them up as required. In this case, we don't
- * even tell the Guest that the fault happened.
- *
- * The errcode tells whether this was a read or a
- * write, and whether kernel or userspace code. */
- if (demand_page(lg, cr2, lg->regs->errcode))
- continue;
-
- /* OK, it's really not there (or not OK): the Guest
- * needs to know. We write out the cr2 value so it
- * knows where the fault occurred.
- *
- * Note that if the Guest were really messed up, this
- * could happen before it's done the INITIALIZE
- * hypercall, so lg->lguest_data will be NULL, so
- * &lg->lguest_data->cr2 will be address 8. Writing
- * into that address won't hurt the Host at all,
- * though. */
- if (put_user(cr2, &lg->lguest_data->cr2))
- kill_guest(lg, "Writing cr2");
- break;
- case 7: /* We've intercepted a Device Not Available fault. */
- /* If the Guest doesn't want to know, we already
- * restored the Floating Point Unit, so we just
- * continue without telling it. */
- if (!lg->ts)
- continue;
- break;
- case 32 ... 255:
- /* These values mean a real interrupt occurred, in
- * which case the Host handler has already been run.
- * We just do a friendly check if another process
- * should now be run, then fall through to loop
- * around: */
- cond_resched();
- case LGUEST_TRAP_ENTRY: /* Handled at top of loop */
- continue;
- }
-
- /* If we get here, it's a trap the Guest wants to know
- * about. */
- if (deliver_trap(lg, lg->regs->trapnum))
- continue;
-
- /* If the Guest doesn't have a handler (either it hasn't
- * registered any yet, or it's one of the faults we don't let
- * it handle), it dies with a cryptic error message. */
- kill_guest(lg, "unhandled trap %li at %#lx (%#lx)",
- lg->regs->trapnum, lg->regs->eip,
- lg->regs->trapnum == 14 ? cr2 : lg->regs->errcode);
+ /* Now we deal with whatever happened to the Guest. */
+ lguest_arch_handle_trap(lg);
}
+
/* The Guest is dead => "No such file or directory" */
return -ENOENT;
}
-/* Now we can look at each of the routines this calls, in increasing order of
- * complexity: do_hypercalls(), emulate_insn(), maybe_do_interrupt(),
- * deliver_trap() and demand_page(). After all those, we'll be ready to
- * examine the Switcher, and our philosophical understanding of the Host/Guest
- * duality will be complete. :*/
-
-int find_free_guest(void)
-{
- unsigned int i;
- for (i = 0; i < MAX_LGUEST_GUESTS; i++)
- if (!lguests[i].tsk)
- return i;
- return -1;
-}
-
-static void adjust_pge(void *on)
-{
- if (on)
- write_cr4(read_cr4() | X86_CR4_PGE);
- else
- write_cr4(read_cr4() & ~X86_CR4_PGE);
-}
-
/*H:000
* Welcome to the Host!
*
@@ -694,79 +253,57 @@ static int __init init(void)
/* Lguest can't run under Xen, VMI or itself. It does Tricky Stuff. */
if (paravirt_enabled()) {
- printk("lguest is afraid of %s\n", paravirt_ops.name);
+ printk("lguest is afraid of %s\n", pv_info.name);
return -EPERM;
}
/* First we put the Switcher up in very high virtual memory. */
err = map_switcher();
if (err)
- return err;
+ goto out;
/* Now we set up the pagetable implementation for the Guests. */
err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES);
- if (err) {
- unmap_switcher();
- return err;
- }
+ if (err)
+ goto unmap;
- /* The I/O subsystem needs some things initialized. */
- lguest_io_init();
+ /* We might need to reserve an interrupt vector. */
+ err = init_interrupts();
+ if (err)
+ goto free_pgtables;
/* /dev/lguest needs to be registered. */
err = lguest_device_init();
- if (err) {
- free_pagetables();
- unmap_switcher();
- return err;
- }
+ if (err)
+ goto free_interrupts;
- /* Finally, we need to turn off "Page Global Enable". PGE is an
- * optimization where page table entries are specially marked to show
- * they never change. The Host kernel marks all the kernel pages this
- * way because it's always present, even when userspace is running.
- *
- * Lguest breaks this: unbeknownst to the rest of the Host kernel, we
- * switch to the Guest kernel. If you don't disable this on all CPUs,
- * you'll get really weird bugs that you'll chase for two days.
- *
- * I used to turn PGE off every time we switched to the Guest and back
- * on when we return, but that slowed the Switcher down noticibly. */
-
- /* We don't need the complexity of CPUs coming and going while we're
- * doing this. */
- lock_cpu_hotplug();
- if (cpu_has_pge) { /* We have a broader idea of "global". */
- /* Remember that this was originally set (for cleanup). */
- cpu_had_pge = 1;
- /* adjust_pge is a helper function which sets or unsets the PGE
- * bit on its CPU, depending on the argument (0 == unset). */
- on_each_cpu(adjust_pge, (void *)0, 0, 1);
- /* Turn off the feature in the global feature set. */
- clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
- }
- unlock_cpu_hotplug();
+ /* Finally we do some architecture-specific setup. */
+ lguest_arch_host_init();
/* All good! */
return 0;
+
+free_interrupts:
+ free_interrupts();
+free_pgtables:
+ free_pagetables();
+unmap:
+ unmap_switcher();
+out:
+ return err;
}
/* Cleaning up is just the same code, backwards. With a little French. */
static void __exit fini(void)
{
lguest_device_remove();
+ free_interrupts();
free_pagetables();
unmap_switcher();
- /* If we had PGE before we started, turn it back on now. */
- lock_cpu_hotplug();
- if (cpu_had_pge) {
- set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
- /* adjust_pge's argument "1" means set PGE. */
- on_each_cpu(adjust_pge, (void *)1, 0, 1);
- }
- unlock_cpu_hotplug();
+ lguest_arch_host_fini();
}
+/*:*/
/* The Host side of lguest can be a module. This is a nice way for people to
* play with it. */
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
index db6caace3b9..b478affe8f9 100644
--- a/drivers/lguest/hypercalls.c
+++ b/drivers/lguest/hypercalls.c
@@ -25,17 +25,13 @@
#include <linux/mm.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <irq_vectors.h>
#include "lg.h"
-/*H:120 This is the core hypercall routine: where the Guest gets what it
- * wants. Or gets killed. Or, in the case of LHCALL_CRASH, both.
- *
- * Remember from the Guest: %eax == which call to make, and the arguments are
- * packed into %edx, %ebx and %ecx if needed. */
-static void do_hcall(struct lguest *lg, struct lguest_regs *regs)
+/*H:120 This is the core hypercall routine: where the Guest gets what it wants.
+ * Or gets killed. Or, in the case of LHCALL_CRASH, both. */
+static void do_hcall(struct lguest *lg, struct hcall_args *args)
{
- switch (regs->eax) {
+ switch (args->arg0) {
case LHCALL_FLUSH_ASYNC:
/* This call does nothing, except by breaking out of the Guest
* it makes us process all the asynchronous hypercalls. */
@@ -51,7 +47,7 @@ static void do_hcall(struct lguest *lg, struct lguest_regs *regs)
char msg[128];
/* If the lgread fails, it will call kill_guest() itself; the
* kill_guest() with the message will be ignored. */
- lgread(lg, msg, regs->edx, sizeof(msg));
+ __lgread(lg, msg, args->arg1, sizeof(msg));
msg[sizeof(msg)-1] = '\0';
kill_guest(lg, "CRASH: %s", msg);
break;
@@ -59,67 +55,50 @@ static void do_hcall(struct lguest *lg, struct lguest_regs *regs)
case LHCALL_FLUSH_TLB:
/* FLUSH_TLB comes in two flavors, depending on the
* argument: */
- if (regs->edx)
+ if (args->arg1)
guest_pagetable_clear_all(lg);
else
guest_pagetable_flush_user(lg);
break;
- case LHCALL_BIND_DMA:
- /* BIND_DMA really wants four arguments, but it's the only call
- * which does. So the Guest packs the number of buffers and
- * the interrupt number into the final argument, and we decode
- * it here. This can legitimately fail, since we currently
- * place a limit on the number of DMA pools a Guest can have.
- * So we return true or false from this call. */
- regs->eax = bind_dma(lg, regs->edx, regs->ebx,
- regs->ecx >> 8, regs->ecx & 0xFF);
- break;
/* All these calls simply pass the arguments through to the right
* routines. */
- case LHCALL_SEND_DMA:
- send_dma(lg, regs->edx, regs->ebx);
- break;
- case LHCALL_LOAD_GDT:
- load_guest_gdt(lg, regs->edx, regs->ebx);
- break;
- case LHCALL_LOAD_IDT_ENTRY:
- load_guest_idt_entry(lg, regs->edx, regs->ebx, regs->ecx);
- break;
case LHCALL_NEW_PGTABLE:
- guest_new_pagetable(lg, regs->edx);
+ guest_new_pagetable(lg, args->arg1);
break;
case LHCALL_SET_STACK:
- guest_set_stack(lg, regs->edx, regs->ebx, regs->ecx);
+ guest_set_stack(lg, args->arg1, args->arg2, args->arg3);
break;
case LHCALL_SET_PTE:
- guest_set_pte(lg, regs->edx, regs->ebx, mkgpte(regs->ecx));
+ guest_set_pte(lg, args->arg1, args->arg2, __pte(args->arg3));
break;
case LHCALL_SET_PMD:
- guest_set_pmd(lg, regs->edx, regs->ebx);
- break;
- case LHCALL_LOAD_TLS:
- guest_load_tls(lg, regs->edx);
+ guest_set_pmd(lg, args->arg1, args->arg2);
break;
case LHCALL_SET_CLOCKEVENT:
- guest_set_clockevent(lg, regs->edx);
+ guest_set_clockevent(lg, args->arg1);
break;
-
case LHCALL_TS:
/* This sets the TS flag, as we saw used in run_guest(). */
- lg->ts = regs->edx;
+ lg->ts = args->arg1;
break;
case LHCALL_HALT:
/* Similarly, this sets the halted flag for run_guest(). */
lg->halted = 1;
break;
+ case LHCALL_NOTIFY:
+ lg->pending_notify = args->arg1;
+ break;
default:
- kill_guest(lg, "Bad hypercall %li\n", regs->eax);
+ /* It should be an architecture-specific hypercall. */
+ if (lguest_arch_do_hcall(lg, args))
+ kill_guest(lg, "Bad hypercall %li\n", args->arg0);
}
}
+/*:*/
-/* Asynchronous hypercalls are easy: we just look in the array in the Guest's
- * "struct lguest_data" and see if there are any new ones marked "ready".
+/*H:124 Asynchronous hypercalls are easy: we just look in the array in the
+ * Guest's "struct lguest_data" to see if any new ones are marked "ready".
*
* We are careful to do these in order: obviously we respect the order the
* Guest put them in the ring, but we also promise the Guest that they will
@@ -134,10 +113,9 @@ static void do_async_hcalls(struct lguest *lg)
if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st)))
return;
-
/* We process "struct lguest_data"s hcalls[] ring once. */
for (i = 0; i < ARRAY_SIZE(st); i++) {
- struct lguest_regs regs;
+ struct hcall_args args;
/* We remember where we were up to from last time. This makes
* sure that the hypercalls are done in the order the Guest
* places them in the ring. */
@@ -152,18 +130,16 @@ static void do_async_hcalls(struct lguest *lg)
if (++lg->next_hcall == LHCALL_RING_SIZE)
lg->next_hcall = 0;
- /* We copy the hypercall arguments into a fake register
- * structure. This makes life simple for do_hcall(). */
- if (get_user(regs.eax, &lg->lguest_data->hcalls[n].eax)
- || get_user(regs.edx, &lg->lguest_data->hcalls[n].edx)
- || get_user(regs.ecx, &lg->lguest_data->hcalls[n].ecx)
- || get_user(regs.ebx, &lg->lguest_data->hcalls[n].ebx)) {
+ /* Copy the hypercall arguments into a local copy of
+ * the hcall_args struct. */
+ if (copy_from_user(&args, &lg->lguest_data->hcalls[n],
+ sizeof(struct hcall_args))) {
kill_guest(lg, "Fetching async hypercalls");
break;
}
/* Do the hypercall, same as a normal one. */
- do_hcall(lg, &regs);
+ do_hcall(lg, &args);
/* Mark the hypercall done. */
if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) {
@@ -171,9 +147,9 @@ static void do_async_hcalls(struct lguest *lg)
break;
}
- /* Stop doing hypercalls if we've just done a DMA to the
- * Launcher: it needs to service this first. */
- if (lg->dma_is_pending)
+ /* Stop doing hypercalls if they want to notify the Launcher:
+ * it needs to service this first. */
+ if (lg->pending_notify)
break;
}
}
@@ -182,76 +158,35 @@ static void do_async_hcalls(struct lguest *lg)
* Guest makes a hypercall, we end up here to set things up: */
static void initialize(struct lguest *lg)
{
- u32 tsc_speed;
-
/* You can't do anything until you're initialized. The Guest knows the
* rules, so we're unforgiving here. */
- if (lg->regs->eax != LHCALL_LGUEST_INIT) {
- kill_guest(lg, "hypercall %li before LGUEST_INIT",
- lg->regs->eax);
+ if (lg->hcall->arg0 != LHCALL_LGUEST_INIT) {
+ kill_guest(lg, "hypercall %li before INIT", lg->hcall->arg0);
return;
}
- /* We insist that the Time Stamp Counter exist and doesn't change with
- * cpu frequency. Some devious chip manufacturers decided that TSC
- * changes could be handled in software. I decided that time going
- * backwards might be good for benchmarks, but it's bad for users.
- *
- * We also insist that the TSC be stable: the kernel detects unreliable
- * TSCs for its own purposes, and we use that here. */
- if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && !check_tsc_unstable())
- tsc_speed = tsc_khz;
- else
- tsc_speed = 0;
-
- /* The pointer to the Guest's "struct lguest_data" is the only
- * argument. */
- lg->lguest_data = (struct lguest_data __user *)lg->regs->edx;
- /* If we check the address they gave is OK now, we can simply
- * copy_to_user/from_user from now on rather than using lgread/lgwrite.
- * I put this in to show that I'm not immune to writing stupid
- * optimizations. */
- if (!lguest_address_ok(lg, lg->regs->edx, sizeof(*lg->lguest_data))) {
+ if (lguest_arch_init_hypercalls(lg))
kill_guest(lg, "bad guest page %p", lg->lguest_data);
- return;
- }
+
/* The Guest tells us where we're not to deliver interrupts by putting
* the range of addresses into "struct lguest_data". */
if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start)
- || get_user(lg->noirq_end, &lg->lguest_data->noirq_end)
- /* We tell the Guest that it can't use the top 4MB of virtual
- * addresses used by the Switcher. */
- || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem)
- || put_user(tsc_speed, &lg->lguest_data->tsc_khz)
- /* We also give the Guest a unique id, as used in lguest_net.c. */
- || put_user(lg->guestid, &lg->lguest_data->guestid))
+ || get_user(lg->noirq_end, &lg->lguest_data->noirq_end))
kill_guest(lg, "bad guest page %p", lg->lguest_data);
- /* We write the current time into the Guest's data page once now. */
+ /* We write the current time into the Guest's data page once so it can
+ * set its clock. */
write_timestamp(lg);
+ /* page_tables.c will also do some setup. */
+ page_table_guest_data_init(lg);
+
/* This is the one case where the above accesses might have been the
* first write to a Guest page. This may have caused a copy-on-write
- * fault, but the Guest might be referring to the old (read-only)
- * page. */
+ * fault, but the old page might be (read-only) in the Guest
+ * pagetable. */
guest_pagetable_clear_all(lg);
}
-/* Now we've examined the hypercall code; our Guest can make requests. There
- * is one other way we can do things for the Guest, as we see in
- * emulate_insn(). */
-
-/*H:110 Tricky point: we mark the hypercall as "done" once we've done it.
- * Normally we don't need to do this: the Guest will run again and update the
- * trap number before we come back around the run_guest() loop to
- * do_hypercalls().
- *
- * However, if we are signalled or the Guest sends DMA to the Launcher, that
- * loop will exit without running the Guest. When it comes back it would try
- * to re-run the hypercall. */
-static void clear_hcall(struct lguest *lg)
-{
- lg->regs->trapnum = 255;
-}
/*H:100
* Hypercalls
@@ -261,16 +196,12 @@ static void clear_hcall(struct lguest *lg)
*/
void do_hypercalls(struct lguest *lg)
{
- /* Not initialized yet? */
+ /* Not initialized yet? This hypercall must do it. */
if (unlikely(!lg->lguest_data)) {
- /* Did the Guest make a hypercall? We might have come back for
- * some other reason (an interrupt, a different trap). */
- if (lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
- /* Set up the "struct lguest_data" */
- initialize(lg);
- /* The hypercall is done. */
- clear_hcall(lg);
- }
+ /* Set up the "struct lguest_data" */
+ initialize(lg);
+ /* Hcall is done. */
+ lg->hcall = NULL;
return;
}
@@ -280,12 +211,21 @@ void do_hypercalls(struct lguest *lg)
do_async_hcalls(lg);
/* If we stopped reading the hypercall ring because the Guest did a
- * SEND_DMA to the Launcher, we want to return now. Otherwise if the
- * Guest asked us to do a hypercall, we do it. */
- if (!lg->dma_is_pending && lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
- do_hcall(lg, lg->regs);
- /* The hypercall is done. */
- clear_hcall(lg);
+ * NOTIFY to the Launcher, we want to return now. Otherwise we do
+ * the hypercall. */
+ if (!lg->pending_notify) {
+ do_hcall(lg, lg->hcall);
+ /* Tricky point: we reset the hcall pointer to mark the
+ * hypercall as "done". We use the hcall pointer rather than
+ * the trap number to indicate a hypercall is pending.
+ * Normally it doesn't matter: the Guest will run again and
+ * update the trap number before we come back here.
+ *
+ * However, if we are signalled or the Guest sends I/O to the
+ * Launcher, the run_guest() loop will exit without running the
+ * Guest. When it comes back it would try to re-run the
+ * hypercall. */
+ lg->hcall = NULL;
}
}
@@ -295,6 +235,6 @@ void write_timestamp(struct lguest *lg)
{
struct timespec now;
ktime_get_real_ts(&now);
- if (put_user(now, &lg->lguest_data->time))
+ if (copy_to_user(&lg->lguest_data->time, &now, sizeof(struct timespec)))
kill_guest(lg, "Writing timestamp");
}
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
index 39731232d82..2b66f79c208 100644
--- a/drivers/lguest/interrupts_and_traps.c
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -12,8 +12,14 @@
* them first, so we also have a way of "reflecting" them into the Guest as if
* they had been delivered to it directly. :*/
#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
#include "lg.h"
+/* Allow Guests to use a non-128 (ie. non-Linux) syscall trap. */
+static unsigned int syscall_vector = SYSCALL_VECTOR;
+module_param(syscall_vector, uint, 0444);
+
/* The address of the interrupt handler is split into two bits: */
static unsigned long idt_address(u32 lo, u32 hi)
{
@@ -39,7 +45,7 @@ static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val)
{
/* Stack grows upwards: move stack then write value. */
*gstack -= 4;
- lgwrite_u32(lg, *gstack, val);
+ lgwrite(lg, *gstack, u32, val);
}
/*H:210 The set_guest_interrupt() routine actually delivers the interrupt or
@@ -56,8 +62,9 @@ static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val)
* it). */
static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
{
- unsigned long gstack;
+ unsigned long gstack, origstack;
u32 eflags, ss, irq_enable;
+ unsigned long virtstack;
/* There are two cases for interrupts: one where the Guest is already
* in the kernel, and a more complex one where the Guest is in
@@ -65,8 +72,10 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
if ((lg->regs->ss&0x3) != GUEST_PL) {
/* The Guest told us their kernel stack with the SET_STACK
* hypercall: both the virtual address and the segment */
- gstack = guest_pa(lg, lg->esp1);
+ virtstack = lg->esp1;
ss = lg->ss1;
+
+ origstack = gstack = guest_pa(lg, virtstack);
/* We push the old stack segment and pointer onto the new
* stack: when the Guest does an "iret" back from the interrupt
* handler the CPU will notice they're dropping privilege
@@ -75,14 +84,16 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
push_guest_stack(lg, &gstack, lg->regs->esp);
} else {
/* We're staying on the same Guest (kernel) stack. */
- gstack = guest_pa(lg, lg->regs->esp);
+ virtstack = lg->regs->esp;
ss = lg->regs->ss;
+
+ origstack = gstack = guest_pa(lg, virtstack);
}
/* Remember that we never let the Guest actually disable interrupts, so
* the "Interrupt Flag" bit is always set. We copy that bit from the
- * Guest's "irq_enabled" field into the eflags word: the Guest copies
- * it back in "lguest_iret". */
+ * Guest's "irq_enabled" field into the eflags word: we saw the Guest
+ * copy it back in "lguest_iret". */
eflags = lg->regs->eflags;
if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0
&& !(irq_enable & X86_EFLAGS_IF))
@@ -102,7 +113,7 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
/* Now we've pushed all the old state, we change the stack, the code
* segment and the address to execute. */
lg->regs->ss = ss;
- lg->regs->esp = gstack + lg->page_offset;
+ lg->regs->esp = virtstack + (gstack - origstack);
lg->regs->cs = (__KERNEL_CS|GUEST_PL);
lg->regs->eip = idt_address(lo, hi);
@@ -113,7 +124,7 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
kill_guest(lg, "Disabling interrupts");
}
-/*H:200
+/*H:205
* Virtual Interrupts.
*
* maybe_do_interrupt() gets called before every entry to the Guest, to see if
@@ -165,7 +176,7 @@ void maybe_do_interrupt(struct lguest *lg)
/* Look at the IDT entry the Guest gave us for this interrupt. The
* first 32 (FIRST_EXTERNAL_VECTOR) entries are for traps, so we skip
* over them. */
- idt = &lg->idt[FIRST_EXTERNAL_VECTOR+irq];
+ idt = &lg->arch.idt[FIRST_EXTERNAL_VECTOR+irq];
/* If they don't have a handler (yet?), we just ignore it */
if (idt_present(idt->a, idt->b)) {
/* OK, mark it no longer pending and deliver it. */
@@ -183,6 +194,47 @@ void maybe_do_interrupt(struct lguest *lg)
* timer interrupt. */
write_timestamp(lg);
}
+/*:*/
+
+/* Linux uses trap 128 for system calls. Plan9 uses 64, and Ron Minnich sent
+ * me a patch, so we support that too. It'd be a big step for lguest if half
+ * the Plan 9 user base were to start using it.
+ *
+ * Actually now I think of it, it's possible that Ron *is* half the Plan 9
+ * userbase. Oh well. */
+static bool could_be_syscall(unsigned int num)
+{
+ /* Normal Linux SYSCALL_VECTOR or reserved vector? */
+ return num == SYSCALL_VECTOR || num == syscall_vector;
+}
+
+/* The syscall vector it wants must be unused by Host. */
+bool check_syscall_vector(struct lguest *lg)
+{
+ u32 vector;
+
+ if (get_user(vector, &lg->lguest_data->syscall_vec))
+ return false;
+
+ return could_be_syscall(vector);
+}
+
+int init_interrupts(void)
+{
+ /* If they want some strange system call vector, reserve it now */
+ if (syscall_vector != SYSCALL_VECTOR
+ && test_and_set_bit(syscall_vector, used_vectors)) {
+ printk("lg: couldn't reserve syscall %u\n", syscall_vector);
+ return -EBUSY;
+ }
+ return 0;
+}
+
+void free_interrupts(void)
+{
+ if (syscall_vector != SYSCALL_VECTOR)
+ clear_bit(syscall_vector, used_vectors);
+}
/*H:220 Now we've got the routines to deliver interrupts, delivering traps
* like page fault is easy. The only trick is that Intel decided that some
@@ -197,49 +249,43 @@ int deliver_trap(struct lguest *lg, unsigned int num)
{
/* Trap numbers are always 8 bit, but we set an impossible trap number
* for traps inside the Switcher, so check that here. */
- if (num >= ARRAY_SIZE(lg->idt))
+ if (num >= ARRAY_SIZE(lg->arch.idt))
return 0;
/* Early on the Guest hasn't set the IDT entries (or maybe it put a
* bogus one in): if we fail here, the Guest will be killed. */
- if (!idt_present(lg->idt[num].a, lg->idt[num].b))
+ if (!idt_present(lg->arch.idt[num].a, lg->arch.idt[num].b))
return 0;
- set_guest_interrupt(lg, lg->idt[num].a, lg->idt[num].b, has_err(num));
+ set_guest_interrupt(lg, lg->arch.idt[num].a, lg->arch.idt[num].b,
+ has_err(num));
return 1;
}
/*H:250 Here's the hard part: returning to the Host every time a trap happens
* and then calling deliver_trap() and re-entering the Guest is slow.
- * Particularly because Guest userspace system calls are traps (trap 128).
+ * Particularly because Guest userspace system calls are traps (usually trap
+ * 128).
*
* So we'd like to set up the IDT to tell the CPU to deliver traps directly
* into the Guest. This is possible, but the complexities cause the size of
* this file to double! However, 150 lines of code is worth writing for taking
* system calls down from 1750ns to 270ns. Plus, if lguest didn't do it, all
- * the other hypervisors would tease it.
+ * the other hypervisors would beat it up at lunchtime.
*
- * This routine determines if a trap can be delivered directly. */
-static int direct_trap(const struct lguest *lg,
- const struct desc_struct *trap,
- unsigned int num)
+ * This routine indicates if a particular trap number could be delivered
+ * directly. */
+static int direct_trap(unsigned int num)
{
/* Hardware interrupts don't go to the Guest at all (except system
* call). */
- if (num >= FIRST_EXTERNAL_VECTOR && num != SYSCALL_VECTOR)
+ if (num >= FIRST_EXTERNAL_VECTOR && !could_be_syscall(num))
return 0;
/* The Host needs to see page faults (for shadow paging and to save the
* fault address), general protection faults (in/out emulation) and
* device not available (TS handling), and of course, the hypercall
* trap. */
- if (num == 14 || num == 13 || num == 7 || num == LGUEST_TRAP_ENTRY)
- return 0;
-
- /* Only trap gates (type 15) can go direct to the Guest. Interrupt
- * gates (type 14) disable interrupts as they are entered, which we
- * never let the Guest do. Not present entries (type 0x0) also can't
- * go direct, of course 8) */
- return idt_type(trap->a, trap->b) == 0xF;
+ return num != 14 && num != 13 && num != 7 && num != LGUEST_TRAP_ENTRY;
}
/*:*/
@@ -287,7 +333,7 @@ void pin_stack_pages(struct lguest *lg)
* change stacks on each context switch. */
void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages)
{
- /* You are not allowd have a stack segment with privilege level 0: bad
+ /* You are not allowed have a stack segment with privilege level 0: bad
* Guest! */
if ((seg & 0x3) != GUEST_PL)
kill_guest(lg, "bad stack segment %i", seg);
@@ -306,7 +352,7 @@ void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages)
* part of the Host: page table handling. */
/*H:235 This is the routine which actually checks the Guest's IDT entry and
- * transfers it into our entry in "struct lguest": */
+ * transfers it into the entry in "struct lguest": */
static void set_trap(struct lguest *lg, struct desc_struct *trap,
unsigned int num, u32 lo, u32 hi)
{
@@ -348,15 +394,11 @@ void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi)
* to copy this again. */
lg->changed |= CHANGED_IDT;
- /* The IDT which we keep in "struct lguest" only contains 32 entries
- * for the traps and LGUEST_IRQS (32) entries for interrupts. We
- * ignore attempts to set handlers for higher interrupt numbers, except
- * for the system call "interrupt" at 128: we have a special IDT entry
- * for that. */
- if (num < ARRAY_SIZE(lg->idt))
- set_trap(lg, &lg->idt[num], num, lo, hi);
- else if (num == SYSCALL_VECTOR)
- set_trap(lg, &lg->syscall_idt, num, lo, hi);
+ /* Check that the Guest doesn't try to step outside the bounds. */
+ if (num >= ARRAY_SIZE(lg->arch.idt))
+ kill_guest(lg, "Setting idt entry %u", num);
+ else
+ set_trap(lg, &lg->arch.idt[num], num, lo, hi);
}
/* The default entry for each interrupt points into the Switcher routines which
@@ -399,22 +441,35 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt,
/* We can simply copy the direct traps, otherwise we use the default
* ones in the Switcher: they will return to the Host. */
- for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) {
- if (direct_trap(lg, &lg->idt[i], i))
- idt[i] = lg->idt[i];
+ for (i = 0; i < ARRAY_SIZE(lg->arch.idt); i++) {
+ /* If no Guest can ever override this trap, leave it alone. */
+ if (!direct_trap(i))
+ continue;
+
+ /* Only trap gates (type 15) can go direct to the Guest.
+ * Interrupt gates (type 14) disable interrupts as they are
+ * entered, which we never let the Guest do. Not present
+ * entries (type 0x0) also can't go direct, of course. */
+ if (idt_type(lg->arch.idt[i].a, lg->arch.idt[i].b) == 0xF)
+ idt[i] = lg->arch.idt[i];
else
+ /* Reset it to the default. */
default_idt_entry(&idt[i], i, def[i]);
}
-
- /* Don't forget the system call trap! The IDT entries for other
- * interupts never change, so no need to copy them. */
- i = SYSCALL_VECTOR;
- if (direct_trap(lg, &lg->syscall_idt, i))
- idt[i] = lg->syscall_idt;
- else
- default_idt_entry(&idt[i], i, def[i]);
}
+/*H:200
+ * The Guest Clock.
+ *
+ * There are two sources of virtual interrupts. We saw one in lguest_user.c:
+ * the Launcher sending interrupts for virtual devices. The other is the Guest
+ * timer interrupt.
+ *
+ * The Guest uses the LHCALL_SET_CLOCKEVENT hypercall to tell us how long to
+ * the next timer interrupt (in nanoseconds). We use the high-resolution timer
+ * infrastructure to set a callback at that time.
+ *
+ * 0 means "turn off the clock". */
void guest_set_clockevent(struct lguest *lg, unsigned long delta)
{
ktime_t expires;
@@ -425,20 +480,27 @@ void guest_set_clockevent(struct lguest *lg, unsigned long delta)
return;
}
+ /* We use wallclock time here, so the Guest might not be running for
+ * all the time between now and the timer interrupt it asked for. This
+ * is almost always the right thing to do. */
expires = ktime_add_ns(ktime_get_real(), delta);
hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS);
}
+/* This is the function called when the Guest's timer expires. */
static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
{
struct lguest *lg = container_of(timer, struct lguest, hrt);
+ /* Remember the first interrupt is the timer interrupt. */
set_bit(0, lg->irqs_pending);
+ /* If the Guest is actually stopped, we need to wake it up. */
if (lg->halted)
wake_up_process(lg->tsk);
return HRTIMER_NORESTART;
}
+/* This sets up the timer for this Guest. */
void init_clockdev(struct lguest *lg)
{
hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS);
diff --git a/drivers/lguest/io.c b/drivers/lguest/io.c
deleted file mode 100644
index ea68613b43f..00000000000
--- a/drivers/lguest/io.c
+++ /dev/null
@@ -1,626 +0,0 @@
-/*P:300 The I/O mechanism in lguest is simple yet flexible, allowing the Guest
- * to talk to the Launcher or directly to another Guest. It uses familiar
- * concepts of DMA and interrupts, plus some neat code stolen from
- * futexes... :*/
-
-/* Copyright (C) 2006 Rusty Russell IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <linux/types.h>
-#include <linux/futex.h>
-#include <linux/jhash.h>
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/uaccess.h>
-#include "lg.h"
-
-/*L:300
- * I/O
- *
- * Getting data in and out of the Guest is quite an art. There are numerous
- * ways to do it, and they all suck differently. We try to keep things fairly
- * close to "real" hardware so our Guest's drivers don't look like an alien
- * visitation in the middle of the Linux code, and yet make sure that Guests
- * can talk directly to other Guests, not just the Launcher.
- *
- * To do this, the Guest gives us a key when it binds or sends DMA buffers.
- * The key corresponds to a "physical" address inside the Guest (ie. a virtual
- * address inside the Launcher process). We don't, however, use this key
- * directly.
- *
- * We want Guests which share memory to be able to DMA to each other: two
- * Launchers can mmap memory the same file, then the Guests can communicate.
- * Fortunately, the futex code provides us with a way to get a "union
- * futex_key" corresponding to the memory lying at a virtual address: if the
- * two processes share memory, the "union futex_key" for that memory will match
- * even if the memory is mapped at different addresses in each. So we always
- * convert the keys to "union futex_key"s to compare them.
- *
- * Before we dive into this though, we need to look at another set of helper
- * routines used throughout the Host kernel code to access Guest memory.
- :*/
-static struct list_head dma_hash[61];
-
-/* An unfortunate side effect of the Linux double-linked list implementation is
- * that there's no good way to statically initialize an array of linked
- * lists. */
-void lguest_io_init(void)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(dma_hash); i++)
- INIT_LIST_HEAD(&dma_hash[i]);
-}
-
-/* FIXME: allow multi-page lengths. */
-static int check_dma_list(struct lguest *lg, const struct lguest_dma *dma)
-{
- unsigned int i;
-
- for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
- if (!dma->len[i])
- return 1;
- if (!lguest_address_ok(lg, dma->addr[i], dma->len[i]))
- goto kill;
- if (dma->len[i] > PAGE_SIZE)
- goto kill;
- /* We could do over a page, but is it worth it? */
- if ((dma->addr[i] % PAGE_SIZE) + dma->len[i] > PAGE_SIZE)
- goto kill;
- }
- return 1;
-
-kill:
- kill_guest(lg, "bad DMA entry: %u@%#lx", dma->len[i], dma->addr[i]);
- return 0;
-}
-
-/*L:330 This is our hash function, using the wonderful Jenkins hash.
- *
- * The futex key is a union with three parts: an unsigned long word, a pointer,
- * and an int "offset". We could use jhash_2words() which takes three u32s.
- * (Ok, the hash functions are great: the naming sucks though).
- *
- * It's nice to be portable to 64-bit platforms, so we use the more generic
- * jhash2(), which takes an array of u32, the number of u32s, and an initial
- * u32 to roll in. This is uglier, but breaks down to almost the same code on
- * 32-bit platforms like this one.
- *
- * We want a position in the array, so we modulo ARRAY_SIZE(dma_hash) (ie. 61).
- */
-static unsigned int hash(const union futex_key *key)
-{
- return jhash2((u32*)&key->both.word,
- (sizeof(key->both.word)+sizeof(key->both.ptr))/4,
- key->both.offset)
- % ARRAY_SIZE(dma_hash);
-}
-
-/* This is a convenience routine to compare two keys. It's a much bemoaned C
- * weakness that it doesn't allow '==' on structures or unions, so we have to
- * open-code it like this. */
-static inline int key_eq(const union futex_key *a, const union futex_key *b)
-{
- return (a->both.word == b->both.word
- && a->both.ptr == b->both.ptr
- && a->both.offset == b->both.offset);
-}
-
-/*L:360 OK, when we need to actually free up a Guest's DMA array we do several
- * things, so we have a convenient function to do it.
- *
- * The caller must hold a read lock on dmainfo owner's current->mm->mmap_sem
- * for the drop_futex_key_refs(). */
-static void unlink_dma(struct lguest_dma_info *dmainfo)
-{
- /* You locked this too, right? */
- BUG_ON(!mutex_is_locked(&lguest_lock));
- /* This is how we know that the entry is free. */
- dmainfo->interrupt = 0;
- /* Remove it from the hash table. */
- list_del(&dmainfo->list);
- /* Drop the references we were holding (to the inode or mm). */
- drop_futex_key_refs(&dmainfo->key);
-}
-
-/*L:350 This is the routine which we call when the Guest asks to unregister a
- * DMA array attached to a given key. Returns true if the array was found. */
-static int unbind_dma(struct lguest *lg,
- const union futex_key *key,
- unsigned long dmas)
-{
- int i, ret = 0;
-
- /* We don't bother with the hash table, just look through all this
- * Guest's DMA arrays. */
- for (i = 0; i < LGUEST_MAX_DMA; i++) {
- /* In theory it could have more than one array on the same key,
- * or one array on multiple keys, so we check both */
- if (key_eq(key, &lg->dma[i].key) && dmas == lg->dma[i].dmas) {
- unlink_dma(&lg->dma[i]);
- ret = 1;
- break;
- }
- }
- return ret;
-}
-
-/*L:340 BIND_DMA: this is the hypercall which sets up an array of "struct
- * lguest_dma" for receiving I/O.
- *
- * The Guest wants to bind an array of "struct lguest_dma"s to a particular key
- * to receive input. This only happens when the Guest is setting up a new
- * device, so it doesn't have to be very fast.
- *
- * It returns 1 on a successful registration (it can fail if we hit the limit
- * of registrations for this Guest).
- */
-int bind_dma(struct lguest *lg,
- unsigned long ukey, unsigned long dmas, u16 numdmas, u8 interrupt)
-{
- unsigned int i;
- int ret = 0;
- union futex_key key;
- /* Futex code needs the mmap_sem. */
- struct rw_semaphore *fshared = &current->mm->mmap_sem;
-
- /* Invalid interrupt? (We could kill the guest here). */
- if (interrupt >= LGUEST_IRQS)
- return 0;
-
- /* We need to grab the Big Lguest Lock, because other Guests may be
- * trying to look through this Guest's DMAs to send something while
- * we're doing this. */
- mutex_lock(&lguest_lock);
- down_read(fshared);
- if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
- kill_guest(lg, "bad dma key %#lx", ukey);
- goto unlock;
- }
-
- /* We want to keep this key valid once we drop mmap_sem, so we have to
- * hold a reference. */
- get_futex_key_refs(&key);
-
- /* If the Guest specified an interrupt of 0, that means they want to
- * unregister this array of "struct lguest_dma"s. */
- if (interrupt == 0)
- ret = unbind_dma(lg, &key, dmas);
- else {
- /* Look through this Guest's dma array for an unused entry. */
- for (i = 0; i < LGUEST_MAX_DMA; i++) {
- /* If the interrupt is non-zero, the entry is already
- * used. */
- if (lg->dma[i].interrupt)
- continue;
-
- /* OK, a free one! Fill on our details. */
- lg->dma[i].dmas = dmas;
- lg->dma[i].num_dmas = numdmas;
- lg->dma[i].next_dma = 0;
- lg->dma[i].key = key;
- lg->dma[i].guestid = lg->guestid;
- lg->dma[i].interrupt = interrupt;
-
- /* Now we add it to the hash table: the position
- * depends on the futex key that we got. */
- list_add(&lg->dma[i].list, &dma_hash[hash(&key)]);
- /* Success! */
- ret = 1;
- goto unlock;
- }
- }
- /* If we didn't find a slot to put the key in, drop the reference
- * again. */
- drop_futex_key_refs(&key);
-unlock:
- /* Unlock and out. */
- up_read(fshared);
- mutex_unlock(&lguest_lock);
- return ret;
-}
-
-/*L:385 Note that our routines to access a different Guest's memory are called
- * lgread_other() and lgwrite_other(): these names emphasize that they are only
- * used when the Guest is *not* the current Guest.
- *
- * The interface for copying from another process's memory is called
- * access_process_vm(), with a final argument of 0 for a read, and 1 for a
- * write.
- *
- * We need lgread_other() to read the destination Guest's "struct lguest_dma"
- * array. */
-static int lgread_other(struct lguest *lg,
- void *buf, u32 addr, unsigned bytes)
-{
- if (!lguest_address_ok(lg, addr, bytes)
- || access_process_vm(lg->tsk, addr, buf, bytes, 0) != bytes) {
- memset(buf, 0, bytes);
- kill_guest(lg, "bad address in registered DMA struct");
- return 0;
- }
- return 1;
-}
-
-/* "lgwrite()" to another Guest: used to update the destination "used_len" once
- * we've transferred data into the buffer. */
-static int lgwrite_other(struct lguest *lg, u32 addr,
- const void *buf, unsigned bytes)
-{
- if (!lguest_address_ok(lg, addr, bytes)
- || (access_process_vm(lg->tsk, addr, (void *)buf, bytes, 1)
- != bytes)) {
- kill_guest(lg, "bad address writing to registered DMA");
- return 0;
- }
- return 1;
-}
-
-/*L:400 This is the generic engine which copies from a source "struct
- * lguest_dma" from this Guest into another Guest's "struct lguest_dma". The
- * destination Guest's pages have already been mapped, as contained in the
- * pages array.
- *
- * If you're wondering if there's a nice "copy from one process to another"
- * routine, so was I. But Linux isn't really set up to copy between two
- * unrelated processes, so we have to write it ourselves.
- */
-static u32 copy_data(struct lguest *srclg,
- const struct lguest_dma *src,
- const struct lguest_dma *dst,
- struct page *pages[])
-{
- unsigned int totlen, si, di, srcoff, dstoff;
- void *maddr = NULL;
-
- /* We return the total length transferred. */
- totlen = 0;
-
- /* We keep indexes into the source and destination "struct lguest_dma",
- * and an offset within each region. */
- si = di = 0;
- srcoff = dstoff = 0;
-
- /* We loop until the source or destination is exhausted. */
- while (si < LGUEST_MAX_DMA_SECTIONS && src->len[si]
- && di < LGUEST_MAX_DMA_SECTIONS && dst->len[di]) {
- /* We can only transfer the rest of the src buffer, or as much
- * as will fit into the destination buffer. */
- u32 len = min(src->len[si] - srcoff, dst->len[di] - dstoff);
-
- /* For systems using "highmem" we need to use kmap() to access
- * the page we want. We often use the same page over and over,
- * so rather than kmap() it on every loop, we set the maddr
- * pointer to NULL when we need to move to the next
- * destination page. */
- if (!maddr)
- maddr = kmap(pages[di]);
-
- /* Copy directly from (this Guest's) source address to the
- * destination Guest's kmap()ed buffer. Note that maddr points
- * to the start of the page: we need to add the offset of the
- * destination address and offset within the buffer. */
-
- /* FIXME: This is not completely portable. I looked at
- * copy_to_user_page(), and some arch's seem to need special
- * flushes. x86 is fine. */
- if (copy_from_user(maddr + (dst->addr[di] + dstoff)%PAGE_SIZE,
- (void __user *)src->addr[si], len) != 0) {
- /* If a copy failed, it's the source's fault. */
- kill_guest(srclg, "bad address in sending DMA");
- totlen = 0;
- break;
- }
-
- /* Increment the total and src & dst offsets */
- totlen += len;
- srcoff += len;
- dstoff += len;
-
- /* Presumably we reached the end of the src or dest buffers: */
- if (srcoff == src->len[si]) {
- /* Move to the next buffer at offset 0 */
- si++;
- srcoff = 0;
- }
- if (dstoff == dst->len[di]) {
- /* We need to unmap that destination page and reset
- * maddr ready for the next one. */
- kunmap(pages[di]);
- maddr = NULL;
- di++;
- dstoff = 0;
- }
- }
-
- /* If we still had a page mapped at the end, unmap now. */
- if (maddr)
- kunmap(pages[di]);
-
- return totlen;
-}
-
-/*L:390 This is how we transfer a "struct lguest_dma" from the source Guest
- * (the current Guest which called SEND_DMA) to another Guest. */
-static u32 do_dma(struct lguest *srclg, const struct lguest_dma *src,
- struct lguest *dstlg, const struct lguest_dma *dst)
-{
- int i;
- u32 ret;
- struct page *pages[LGUEST_MAX_DMA_SECTIONS];
-
- /* We check that both source and destination "struct lguest_dma"s are
- * within the bounds of the source and destination Guests */
- if (!check_dma_list(dstlg, dst) || !check_dma_list(srclg, src))
- return 0;
-
- /* We need to map the pages which correspond to each parts of
- * destination buffer. */
- for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
- if (dst->len[i] == 0)
- break;
- /* get_user_pages() is a complicated function, especially since
- * we only want a single page. But it works, and returns the
- * number of pages. Note that we're holding the destination's
- * mmap_sem, as get_user_pages() requires. */
- if (get_user_pages(dstlg->tsk, dstlg->mm,
- dst->addr[i], 1, 1, 1, pages+i, NULL)
- != 1) {
- /* This means the destination gave us a bogus buffer */
- kill_guest(dstlg, "Error mapping DMA pages");
- ret = 0;
- goto drop_pages;
- }
- }
-
- /* Now copy the data until we run out of src or dst. */
- ret = copy_data(srclg, src, dst, pages);
-
-drop_pages:
- while (--i >= 0)
- put_page(pages[i]);
- return ret;
-}
-
-/*L:380 Transferring data from one Guest to another is not as simple as I'd
- * like. We've found the "struct lguest_dma_info" bound to the same address as
- * the send, we need to copy into it.
- *
- * This function returns true if the destination array was empty. */
-static int dma_transfer(struct lguest *srclg,
- unsigned long udma,
- struct lguest_dma_info *dst)
-{
- struct lguest_dma dst_dma, src_dma;
- struct lguest *dstlg;
- u32 i, dma = 0;
-
- /* From the "struct lguest_dma_info" we found in the hash, grab the
- * Guest. */
- dstlg = &lguests[dst->guestid];
- /* Read in the source "struct lguest_dma" handed to SEND_DMA. */
- lgread(srclg, &src_dma, udma, sizeof(src_dma));
-
- /* We need the destination's mmap_sem, and we already hold the source's
- * mmap_sem for the futex key lookup. Normally this would suggest that
- * we could deadlock if the destination Guest was trying to send to
- * this source Guest at the same time, which is another reason that all
- * I/O is done under the big lguest_lock. */
- down_read(&dstlg->mm->mmap_sem);
-
- /* Look through the destination DMA array for an available buffer. */
- for (i = 0; i < dst->num_dmas; i++) {
- /* We keep a "next_dma" pointer which often helps us avoid
- * looking at lots of previously-filled entries. */
- dma = (dst->next_dma + i) % dst->num_dmas;
- if (!lgread_other(dstlg, &dst_dma,
- dst->dmas + dma * sizeof(struct lguest_dma),
- sizeof(dst_dma))) {
- goto fail;
- }
- if (!dst_dma.used_len)
- break;
- }
-
- /* If we found a buffer, we do the actual data copy. */
- if (i != dst->num_dmas) {
- unsigned long used_lenp;
- unsigned int ret;
-
- ret = do_dma(srclg, &src_dma, dstlg, &dst_dma);
- /* Put used length in the source "struct lguest_dma"'s used_len
- * field. It's a little tricky to figure out where that is,
- * though. */
- lgwrite_u32(srclg,
- udma+offsetof(struct lguest_dma, used_len), ret);
- /* Tranferring 0 bytes is OK if the source buffer was empty. */
- if (ret == 0 && src_dma.len[0] != 0)
- goto fail;
-
- /* The destination Guest might be running on a different CPU:
- * we have to make sure that it will see the "used_len" field
- * change to non-zero *after* it sees the data we copied into
- * the buffer. Hence a write memory barrier. */
- wmb();
- /* Figuring out where the destination's used_len field for this
- * "struct lguest_dma" in the array is also a little ugly. */
- used_lenp = dst->dmas
- + dma * sizeof(struct lguest_dma)
- + offsetof(struct lguest_dma, used_len);
- lgwrite_other(dstlg, used_lenp, &ret, sizeof(ret));
- /* Move the cursor for next time. */
- dst->next_dma++;
- }
- up_read(&dstlg->mm->mmap_sem);
-
- /* We trigger the destination interrupt, even if the destination was
- * empty and we didn't transfer anything: this gives them a chance to
- * wake up and refill. */
- set_bit(dst->interrupt, dstlg->irqs_pending);
- /* Wake up the destination process. */
- wake_up_process(dstlg->tsk);
- /* If we passed the last "struct lguest_dma", the receive had no
- * buffers left. */
- return i == dst->num_dmas;
-
-fail:
- up_read(&dstlg->mm->mmap_sem);
- return 0;
-}
-
-/*L:370 This is the counter-side to the BIND_DMA hypercall; the SEND_DMA
- * hypercall. We find out who's listening, and send to them. */
-void send_dma(struct lguest *lg, unsigned long ukey, unsigned long udma)
-{
- union futex_key key;
- int empty = 0;
- struct rw_semaphore *fshared = &current->mm->mmap_sem;
-
-again:
- mutex_lock(&lguest_lock);
- down_read(fshared);
- /* Get the futex key for the key the Guest gave us */
- if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
- kill_guest(lg, "bad sending DMA key");
- goto unlock;
- }
- /* Since the key must be a multiple of 4, the futex key uses the lower
- * bit of the "offset" field (which would always be 0) to indicate a
- * mapping which is shared with other processes (ie. Guests). */
- if (key.shared.offset & 1) {
- struct lguest_dma_info *i;
- /* Look through the hash for other Guests. */
- list_for_each_entry(i, &dma_hash[hash(&key)], list) {
- /* Don't send to ourselves. */
- if (i->guestid == lg->guestid)
- continue;
- if (!key_eq(&key, &i->key))
- continue;
-
- /* If dma_transfer() tells us the destination has no
- * available buffers, we increment "empty". */
- empty += dma_transfer(lg, udma, i);
- break;
- }
- /* If the destination is empty, we release our locks and
- * give the destination Guest a brief chance to restock. */
- if (empty == 1) {
- /* Give any recipients one chance to restock. */
- up_read(&current->mm->mmap_sem);
- mutex_unlock(&lguest_lock);
- /* Next time, we won't try again. */
- empty++;
- goto again;
- }
- } else {
- /* Private mapping: Guest is sending to its Launcher. We set
- * the "dma_is_pending" flag so that the main loop will exit
- * and the Launcher's read() from /dev/lguest will return. */
- lg->dma_is_pending = 1;
- lg->pending_dma = udma;
- lg->pending_key = ukey;
- }
-unlock:
- up_read(fshared);
- mutex_unlock(&lguest_lock);
-}
-/*:*/
-
-void release_all_dma(struct lguest *lg)
-{
- unsigned int i;
-
- BUG_ON(!mutex_is_locked(&lguest_lock));
-
- down_read(&lg->mm->mmap_sem);
- for (i = 0; i < LGUEST_MAX_DMA; i++) {
- if (lg->dma[i].interrupt)
- unlink_dma(&lg->dma[i]);
- }
- up_read(&lg->mm->mmap_sem);
-}
-
-/*M:007 We only return a single DMA buffer to the Launcher, but it would be
- * more efficient to return a pointer to the entire array of DMA buffers, which
- * it can cache and choose one whenever it wants.
- *
- * Currently the Launcher uses a write to /dev/lguest, and the return value is
- * the address of the DMA structure with the interrupt number placed in
- * dma->used_len. If we wanted to return the entire array, we need to return
- * the address, array size and interrupt number: this seems to require an
- * ioctl(). :*/
-
-/*L:320 This routine looks for a DMA buffer registered by the Guest on the
- * given key (using the BIND_DMA hypercall). */
-unsigned long get_dma_buffer(struct lguest *lg,
- unsigned long ukey, unsigned long *interrupt)
-{
- unsigned long ret = 0;
- union futex_key key;
- struct lguest_dma_info *i;
- struct rw_semaphore *fshared = &current->mm->mmap_sem;
-
- /* Take the Big Lguest Lock to stop other Guests sending this Guest DMA
- * at the same time. */
- mutex_lock(&lguest_lock);
- /* To match between Guests sharing the same underlying memory we steal
- * code from the futex infrastructure. This requires that we hold the
- * "mmap_sem" for our process (the Launcher), and pass it to the futex
- * code. */
- down_read(fshared);
-
- /* This can fail if it's not a valid address, or if the address is not
- * divisible by 4 (the futex code needs that, we don't really). */
- if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
- kill_guest(lg, "bad registered DMA buffer");
- goto unlock;
- }
- /* Search the hash table for matching entries (the Launcher can only
- * send to its own Guest for the moment, so the entry must be for this
- * Guest) */
- list_for_each_entry(i, &dma_hash[hash(&key)], list) {
- if (key_eq(&key, &i->key) && i->guestid == lg->guestid) {
- unsigned int j;
- /* Look through the registered DMA array for an
- * available buffer. */
- for (j = 0; j < i->num_dmas; j++) {
- struct lguest_dma dma;
-
- ret = i->dmas + j * sizeof(struct lguest_dma);
- lgread(lg, &dma, ret, sizeof(dma));
- if (dma.used_len == 0)
- break;
- }
- /* Store the interrupt the Guest wants when the buffer
- * is used. */
- *interrupt = i->interrupt;
- break;
- }
- }
-unlock:
- up_read(fshared);
- mutex_unlock(&lguest_lock);
- return ret;
-}
-/*:*/
-
-/*L:410 This really has completed the Launcher. Not only have we now finished
- * the longest chapter in our journey, but this also means we are over halfway
- * through!
- *
- * Enough prevaricating around the bush: it is time for us to dive into the
- * core of the Host, in "make Host".
- */
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
index 64f0abed317..86924891b5e 100644
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -1,119 +1,25 @@
#ifndef _LGUEST_H
#define _LGUEST_H
-#include <asm/desc.h>
-
-#define GDT_ENTRY_LGUEST_CS 10
-#define GDT_ENTRY_LGUEST_DS 11
-#define LGUEST_CS (GDT_ENTRY_LGUEST_CS * 8)
-#define LGUEST_DS (GDT_ENTRY_LGUEST_DS * 8)
-
#ifndef __ASSEMBLY__
#include <linux/types.h>
#include <linux/init.h>
#include <linux/stringify.h>
-#include <linux/binfmts.h>
-#include <linux/futex.h>
#include <linux/lguest.h>
#include <linux/lguest_launcher.h>
#include <linux/wait.h>
#include <linux/err.h>
#include <asm/semaphore.h>
-#include "irq_vectors.h"
-#define GUEST_PL 1
-
-struct lguest_regs
-{
- /* Manually saved part. */
- unsigned long ebx, ecx, edx;
- unsigned long esi, edi, ebp;
- unsigned long gs;
- unsigned long eax;
- unsigned long fs, ds, es;
- unsigned long trapnum, errcode;
- /* Trap pushed part */
- unsigned long eip;
- unsigned long cs;
- unsigned long eflags;
- unsigned long esp;
- unsigned long ss;
-};
+#include <asm/lguest.h>
void free_pagetables(void);
int init_pagetables(struct page **switcher_page, unsigned int pages);
-/* Full 4G segment descriptors, suitable for CS and DS. */
-#define FULL_EXEC_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9b00})
-#define FULL_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9300})
-
-struct lguest_dma_info
-{
- struct list_head list;
- union futex_key key;
- unsigned long dmas;
- u16 next_dma;
- u16 num_dmas;
- u16 guestid;
- u8 interrupt; /* 0 when not registered */
-};
-
-/*H:310 The page-table code owes a great debt of gratitude to Andi Kleen. He
- * reviewed the original code which used "u32" for all page table entries, and
- * insisted that it would be far clearer with explicit typing. I thought it
- * was overkill, but he was right: it is much clearer than it was before.
- *
- * We have separate types for the Guest's ptes & pgds and the shadow ptes &
- * pgds. There's already a Linux type for these (pte_t and pgd_t) but they
- * change depending on kernel config options (PAE). */
-
-/* Each entry is identical: lower 12 bits of flags and upper 20 bits for the
- * "page frame number" (0 == first physical page, etc). They are different
- * types so the compiler will warn us if we mix them improperly. */
-typedef union {
- struct { unsigned flags:12, pfn:20; };
- struct { unsigned long val; } raw;
-} spgd_t;
-typedef union {
- struct { unsigned flags:12, pfn:20; };
- struct { unsigned long val; } raw;
-} spte_t;
-typedef union {
- struct { unsigned flags:12, pfn:20; };
- struct { unsigned long val; } raw;
-} gpgd_t;
-typedef union {
- struct { unsigned flags:12, pfn:20; };
- struct { unsigned long val; } raw;
-} gpte_t;
-
-/* We have two convenient macros to convert a "raw" value as handed to us by
- * the Guest into the correct Guest PGD or PTE type. */
-#define mkgpte(_val) ((gpte_t){.raw.val = _val})
-#define mkgpgd(_val) ((gpgd_t){.raw.val = _val})
-/*:*/
-
struct pgdir
{
- unsigned long cr3;
- spgd_t *pgdir;
-};
-
-/* This is a guest-specific page (mapped ro) into the guest. */
-struct lguest_ro_state
-{
- /* Host information we need to restore when we switch back. */
- u32 host_cr3;
- struct Xgt_desc_struct host_idt_desc;
- struct Xgt_desc_struct host_gdt_desc;
- u32 host_sp;
-
- /* Fields which are used when guest is running. */
- struct Xgt_desc_struct guest_idt_desc;
- struct Xgt_desc_struct guest_gdt_desc;
- struct i386_hw_tss guest_tss;
- struct desc_struct guest_idt[IDT_ENTRIES];
- struct desc_struct guest_gdt[GDT_ENTRIES];
+ unsigned long gpgdir;
+ pgd_t *pgdir;
};
/* We have two pages shared with guests, per cpu. */
@@ -141,9 +47,11 @@ struct lguest
struct lguest_data __user *lguest_data;
struct task_struct *tsk;
struct mm_struct *mm; /* == tsk->mm, but that becomes NULL on exit */
- u16 guestid;
u32 pfn_limit;
- u32 page_offset;
+ /* This provides the offset to the base of guest-physical
+ * memory in the Launcher. */
+ void __user *mem_base;
+ unsigned long kernel_address;
u32 cr2;
int halted;
int ts;
@@ -151,6 +59,9 @@ struct lguest
u32 esp1;
u8 ss1;
+ /* If a hypercall was asked for, this points to the arguments. */
+ struct hcall_args *hcall;
+
/* Do we need to stop what we're doing and return to userspace? */
int break_out;
wait_queue_head_t break_wq;
@@ -163,28 +74,16 @@ struct lguest
u32 pgdidx;
struct pgdir pgdirs[4];
- /* Cached wakeup: we hold a reference to this task. */
- struct task_struct *wake;
-
unsigned long noirq_start, noirq_end;
- int dma_is_pending;
- unsigned long pending_dma; /* struct lguest_dma */
- unsigned long pending_key; /* address they're sending to */
+ unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */
unsigned int stack_pages;
u32 tsc_khz;
- struct lguest_dma_info dma[LGUEST_MAX_DMA];
-
/* Dead? */
const char *dead;
- /* The GDT entries copied into lguest_ro_state when running. */
- struct desc_struct gdt[GDT_ENTRIES];
-
- /* The IDT entries: some copied into lguest_ro_state when running. */
- struct desc_struct idt[FIRST_EXTERNAL_VECTOR+LGUEST_IRQS];
- struct desc_struct syscall_idt;
+ struct lguest_arch arch;
/* Virtual clock device */
struct hrtimer hrt;
@@ -193,19 +92,38 @@ struct lguest
DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
};
-extern struct lguest lguests[];
extern struct mutex lguest_lock;
/* core.c: */
-u32 lgread_u32(struct lguest *lg, unsigned long addr);
-void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val);
-void lgread(struct lguest *lg, void *buf, unsigned long addr, unsigned len);
-void lgwrite(struct lguest *lg, unsigned long, const void *buf, unsigned len);
-int find_free_guest(void);
int lguest_address_ok(const struct lguest *lg,
unsigned long addr, unsigned long len);
+void __lgread(struct lguest *, void *, unsigned long, unsigned);
+void __lgwrite(struct lguest *, unsigned long, const void *, unsigned);
+
+/*H:035 Using memory-copy operations like that is usually inconvient, so we
+ * have the following helper macros which read and write a specific type (often
+ * an unsigned long).
+ *
+ * This reads into a variable of the given type then returns that. */
+#define lgread(lg, addr, type) \
+ ({ type _v; __lgread((lg), &_v, (addr), sizeof(_v)); _v; })
+
+/* This checks that the variable is of the given type, then writes it out. */
+#define lgwrite(lg, addr, type, val) \
+ do { \
+ typecheck(type, val); \
+ __lgwrite((lg), (addr), &(val), sizeof(val)); \
+ } while(0)
+/* (end of memory access helper routines) :*/
+
int run_guest(struct lguest *lg, unsigned long __user *user);
+/* Helper macros to obtain the first 12 or the last 20 bits, this is only the
+ * first step in the migration to the kernel types. pte_pfn is already defined
+ * in the kernel. */
+#define pgd_flags(x) (pgd_val(x) & ~PAGE_MASK)
+#define pte_flags(x) (pte_val(x) & ~PAGE_MASK)
+#define pgd_pfn(x) (pgd_val(x) >> PAGE_SHIFT)
/* interrupts_and_traps.c: */
void maybe_do_interrupt(struct lguest *lg);
@@ -219,6 +137,9 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt,
const unsigned long *def);
void guest_set_clockevent(struct lguest *lg, unsigned long delta);
void init_clockdev(struct lguest *lg);
+bool check_syscall_vector(struct lguest *lg);
+int init_interrupts(void);
+void free_interrupts(void);
/* segments.c: */
void setup_default_gdt_entries(struct lguest_ro_state *state);
@@ -232,28 +153,33 @@ void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt);
int init_guest_pagetable(struct lguest *lg, unsigned long pgtable);
void free_guest_pagetable(struct lguest *lg);
void guest_new_pagetable(struct lguest *lg, unsigned long pgtable);
-void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 i);
+void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i);
void guest_pagetable_clear_all(struct lguest *lg);
void guest_pagetable_flush_user(struct lguest *lg);
-void guest_set_pte(struct lguest *lg, unsigned long cr3,
- unsigned long vaddr, gpte_t val);
+void guest_set_pte(struct lguest *lg, unsigned long gpgdir,
+ unsigned long vaddr, pte_t val);
void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages);
int demand_page(struct lguest *info, unsigned long cr2, int errcode);
void pin_page(struct lguest *lg, unsigned long vaddr);
+unsigned long guest_pa(struct lguest *lg, unsigned long vaddr);
+void page_table_guest_data_init(struct lguest *lg);
+
+/* <arch>/core.c: */
+void lguest_arch_host_init(void);
+void lguest_arch_host_fini(void);
+void lguest_arch_run_guest(struct lguest *lg);
+void lguest_arch_handle_trap(struct lguest *lg);
+int lguest_arch_init_hypercalls(struct lguest *lg);
+int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args);
+void lguest_arch_setup_regs(struct lguest *lg, unsigned long start);
+
+/* <arch>/switcher.S: */
+extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
/* lguest_user.c: */
int lguest_device_init(void);
void lguest_device_remove(void);
-/* io.c: */
-void lguest_io_init(void);
-int bind_dma(struct lguest *lg,
- unsigned long key, unsigned long udma, u16 numdmas, u8 interrupt);
-void send_dma(struct lguest *info, unsigned long key, unsigned long udma);
-void release_all_dma(struct lguest *lg);
-unsigned long get_dma_buffer(struct lguest *lg, unsigned long key,
- unsigned long *interrupt);
-
/* hypercalls.c: */
void do_hypercalls(struct lguest *lg);
void write_timestamp(struct lguest *lg);
@@ -262,7 +188,7 @@ void write_timestamp(struct lguest *lg);
* Let's step aside for the moment, to study one important routine that's used
* widely in the Host code.
*
- * There are many cases where the Guest does something invalid, like pass crap
+ * There are many cases where the Guest can do something invalid, like pass crap
* to a hypercall. Since only the Guest kernel can make hypercalls, it's quite
* acceptable to simply terminate the Guest and give the Launcher a nicely
* formatted reason. It's also simpler for the Guest itself, which doesn't
@@ -292,9 +218,5 @@ do { \
} while(0)
/* (End of aside) :*/
-static inline unsigned long guest_pa(struct lguest *lg, unsigned long vaddr)
-{
- return vaddr - lg->page_offset;
-}
#endif /* __ASSEMBLY__ */
#endif /* _LGUEST_H */
diff --git a/drivers/lguest/lguest.c b/drivers/lguest/lguest.c
deleted file mode 100644
index ee1c6d05c3d..00000000000
--- a/drivers/lguest/lguest.c
+++ /dev/null
@@ -1,1102 +0,0 @@
-/*P:010
- * A hypervisor allows multiple Operating Systems to run on a single machine.
- * To quote David Wheeler: "Any problem in computer science can be solved with
- * another layer of indirection."
- *
- * We keep things simple in two ways. First, we start with a normal Linux
- * kernel and insert a module (lg.ko) which allows us to run other Linux
- * kernels the same way we'd run processes. We call the first kernel the Host,
- * and the others the Guests. The program which sets up and configures Guests
- * (such as the example in Documentation/lguest/lguest.c) is called the
- * Launcher.
- *
- * Secondly, we only run specially modified Guests, not normal kernels. When
- * you set CONFIG_LGUEST to 'y' or 'm', this automatically sets
- * CONFIG_LGUEST_GUEST=y, which compiles this file into the kernel so it knows
- * how to be a Guest. This means that you can use the same kernel you boot
- * normally (ie. as a Host) as a Guest.
- *
- * These Guests know that they cannot do privileged operations, such as disable
- * interrupts, and that they have to ask the Host to do such things explicitly.
- * This file consists of all the replacements for such low-level native
- * hardware operations: these special Guest versions call the Host.
- *
- * So how does the kernel know it's a Guest? The Guest starts at a special
- * entry point marked with a magic string, which sets up a few things then
- * calls here. We replace the native functions in "struct paravirt_ops"
- * with our Guest versions, then boot like normal. :*/
-
-/*
- * Copyright (C) 2006, Rusty Russell <rusty@rustcorp.com.au> IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include <linux/kernel.h>
-#include <linux/start_kernel.h>
-#include <linux/string.h>
-#include <linux/console.h>
-#include <linux/screen_info.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-#include <linux/lguest.h>
-#include <linux/lguest_launcher.h>
-#include <linux/lguest_bus.h>
-#include <asm/paravirt.h>
-#include <asm/param.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/desc.h>
-#include <asm/setup.h>
-#include <asm/e820.h>
-#include <asm/mce.h>
-#include <asm/io.h>
-
-/*G:010 Welcome to the Guest!
- *
- * The Guest in our tale is a simple creature: identical to the Host but
- * behaving in simplified but equivalent ways. In particular, the Guest is the
- * same kernel as the Host (or at least, built from the same source code). :*/
-
-/* Declarations for definitions in lguest_guest.S */
-extern char lguest_noirq_start[], lguest_noirq_end[];
-extern const char lgstart_cli[], lgend_cli[];
-extern const char lgstart_sti[], lgend_sti[];
-extern const char lgstart_popf[], lgend_popf[];
-extern const char lgstart_pushf[], lgend_pushf[];
-extern const char lgstart_iret[], lgend_iret[];
-extern void lguest_iret(void);
-
-struct lguest_data lguest_data = {
- .hcall_status = { [0 ... LHCALL_RING_SIZE-1] = 0xFF },
- .noirq_start = (u32)lguest_noirq_start,
- .noirq_end = (u32)lguest_noirq_end,
- .blocked_interrupts = { 1 }, /* Block timer interrupts */
-};
-struct lguest_device_desc *lguest_devices;
-static cycle_t clock_base;
-
-/*G:035 Notice the lazy_hcall() above, rather than hcall(). This is our first
- * real optimization trick!
- *
- * When lazy_mode is set, it means we're allowed to defer all hypercalls and do
- * them as a batch when lazy_mode is eventually turned off. Because hypercalls
- * are reasonably expensive, batching them up makes sense. For example, a
- * large mmap might update dozens of page table entries: that code calls
- * lguest_lazy_mode(PARAVIRT_LAZY_MMU), does the dozen updates, then calls
- * lguest_lazy_mode(PARAVIRT_LAZY_NONE).
- *
- * So, when we're in lazy mode, we call async_hypercall() to store the call for
- * future processing. When lazy mode is turned off we issue a hypercall to
- * flush the stored calls.
- *
- * There's also a hack where "mode" is set to "PARAVIRT_LAZY_FLUSH" which
- * indicates we're to flush any outstanding calls immediately. This is used
- * when an interrupt handler does a kmap_atomic(): the page table changes must
- * happen immediately even if we're in the middle of a batch. Usually we're
- * not, though, so there's nothing to do. */
-static enum paravirt_lazy_mode lazy_mode; /* Note: not SMP-safe! */
-static void lguest_lazy_mode(enum paravirt_lazy_mode mode)
-{
- if (mode == PARAVIRT_LAZY_FLUSH) {
- if (unlikely(lazy_mode != PARAVIRT_LAZY_NONE))
- hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0);
- } else {
- lazy_mode = mode;
- if (mode == PARAVIRT_LAZY_NONE)
- hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0);
- }
-}
-
-static void lazy_hcall(unsigned long call,
- unsigned long arg1,
- unsigned long arg2,
- unsigned long arg3)
-{
- if (lazy_mode == PARAVIRT_LAZY_NONE)
- hcall(call, arg1, arg2, arg3);
- else
- async_hcall(call, arg1, arg2, arg3);
-}
-
-/* async_hcall() is pretty simple: I'm quite proud of it really. We have a
- * ring buffer of stored hypercalls which the Host will run though next time we
- * do a normal hypercall. Each entry in the ring has 4 slots for the hypercall
- * arguments, and a "hcall_status" word which is 0 if the call is ready to go,
- * and 255 once the Host has finished with it.
- *
- * If we come around to a slot which hasn't been finished, then the table is
- * full and we just make the hypercall directly. This has the nice side
- * effect of causing the Host to run all the stored calls in the ring buffer
- * which empties it for next time! */
-void async_hcall(unsigned long call,
- unsigned long arg1, unsigned long arg2, unsigned long arg3)
-{
- /* Note: This code assumes we're uniprocessor. */
- static unsigned int next_call;
- unsigned long flags;
-
- /* Disable interrupts if not already disabled: we don't want an
- * interrupt handler making a hypercall while we're already doing
- * one! */
- local_irq_save(flags);
- if (lguest_data.hcall_status[next_call] != 0xFF) {
- /* Table full, so do normal hcall which will flush table. */
- hcall(call, arg1, arg2, arg3);
- } else {
- lguest_data.hcalls[next_call].eax = call;
- lguest_data.hcalls[next_call].edx = arg1;
- lguest_data.hcalls[next_call].ebx = arg2;
- lguest_data.hcalls[next_call].ecx = arg3;
- /* Arguments must all be written before we mark it to go */
- wmb();
- lguest_data.hcall_status[next_call] = 0;
- if (++next_call == LHCALL_RING_SIZE)
- next_call = 0;
- }
- local_irq_restore(flags);
-}
-/*:*/
-
-/* Wrappers for the SEND_DMA and BIND_DMA hypercalls. This is mainly because
- * Jeff Garzik complained that __pa() should never appear in drivers, and this
- * helps remove most of them. But also, it wraps some ugliness. */
-void lguest_send_dma(unsigned long key, struct lguest_dma *dma)
-{
- /* The hcall might not write this if something goes wrong */
- dma->used_len = 0;
- hcall(LHCALL_SEND_DMA, key, __pa(dma), 0);
-}
-
-int lguest_bind_dma(unsigned long key, struct lguest_dma *dmas,
- unsigned int num, u8 irq)
-{
- /* This is the only hypercall which actually wants 5 arguments, and we
- * only support 4. Fortunately the interrupt number is always less
- * than 256, so we can pack it with the number of dmas in the final
- * argument. */
- if (!hcall(LHCALL_BIND_DMA, key, __pa(dmas), (num << 8) | irq))
- return -ENOMEM;
- return 0;
-}
-
-/* Unbinding is the same hypercall as binding, but with 0 num & irq. */
-void lguest_unbind_dma(unsigned long key, struct lguest_dma *dmas)
-{
- hcall(LHCALL_BIND_DMA, key, __pa(dmas), 0);
-}
-
-/* For guests, device memory can be used as normal memory, so we cast away the
- * __iomem to quieten sparse. */
-void *lguest_map(unsigned long phys_addr, unsigned long pages)
-{
- return (__force void *)ioremap(phys_addr, PAGE_SIZE*pages);
-}
-
-void lguest_unmap(void *addr)
-{
- iounmap((__force void __iomem *)addr);
-}
-
-/*G:033
- * Here are our first native-instruction replacements: four functions for
- * interrupt control.
- *
- * The simplest way of implementing these would be to have "turn interrupts
- * off" and "turn interrupts on" hypercalls. Unfortunately, this is too slow:
- * these are by far the most commonly called functions of those we override.
- *
- * So instead we keep an "irq_enabled" field inside our "struct lguest_data",
- * which the Guest can update with a single instruction. The Host knows to
- * check there when it wants to deliver an interrupt.
- */
-
-/* save_flags() is expected to return the processor state (ie. "eflags"). The
- * eflags word contains all kind of stuff, but in practice Linux only cares
- * about the interrupt flag. Our "save_flags()" just returns that. */
-static unsigned long save_fl(void)
-{
- return lguest_data.irq_enabled;
-}
-
-/* "restore_flags" just sets the flags back to the value given. */
-static void restore_fl(unsigned long flags)
-{
- lguest_data.irq_enabled = flags;
-}
-
-/* Interrupts go off... */
-static void irq_disable(void)
-{
- lguest_data.irq_enabled = 0;
-}
-
-/* Interrupts go on... */
-static void irq_enable(void)
-{
- lguest_data.irq_enabled = X86_EFLAGS_IF;
-}
-/*:*/
-/*M:003 Note that we don't check for outstanding interrupts when we re-enable
- * them (or when we unmask an interrupt). This seems to work for the moment,
- * since interrupts are rare and we'll just get the interrupt on the next timer
- * tick, but when we turn on CONFIG_NO_HZ, we should revisit this. One way
- * would be to put the "irq_enabled" field in a page by itself, and have the
- * Host write-protect it when an interrupt comes in when irqs are disabled.
- * There will then be a page fault as soon as interrupts are re-enabled. :*/
-
-/*G:034
- * The Interrupt Descriptor Table (IDT).
- *
- * The IDT tells the processor what to do when an interrupt comes in. Each
- * entry in the table is a 64-bit descriptor: this holds the privilege level,
- * address of the handler, and... well, who cares? The Guest just asks the
- * Host to make the change anyway, because the Host controls the real IDT.
- */
-static void lguest_write_idt_entry(struct desc_struct *dt,
- int entrynum, u32 low, u32 high)
-{
- /* Keep the local copy up to date. */
- write_dt_entry(dt, entrynum, low, high);
- /* Tell Host about this new entry. */
- hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, low, high);
-}
-
-/* Changing to a different IDT is very rare: we keep the IDT up-to-date every
- * time it is written, so we can simply loop through all entries and tell the
- * Host about them. */
-static void lguest_load_idt(const struct Xgt_desc_struct *desc)
-{
- unsigned int i;
- struct desc_struct *idt = (void *)desc->address;
-
- for (i = 0; i < (desc->size+1)/8; i++)
- hcall(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b);
-}
-
-/*
- * The Global Descriptor Table.
- *
- * The Intel architecture defines another table, called the Global Descriptor
- * Table (GDT). You tell the CPU where it is (and its size) using the "lgdt"
- * instruction, and then several other instructions refer to entries in the
- * table. There are three entries which the Switcher needs, so the Host simply
- * controls the entire thing and the Guest asks it to make changes using the
- * LOAD_GDT hypercall.
- *
- * This is the opposite of the IDT code where we have a LOAD_IDT_ENTRY
- * hypercall and use that repeatedly to load a new IDT. I don't think it
- * really matters, but wouldn't it be nice if they were the same?
- */
-static void lguest_load_gdt(const struct Xgt_desc_struct *desc)
-{
- BUG_ON((desc->size+1)/8 != GDT_ENTRIES);
- hcall(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES, 0);
-}
-
-/* For a single GDT entry which changes, we do the lazy thing: alter our GDT,
- * then tell the Host to reload the entire thing. This operation is so rare
- * that this naive implementation is reasonable. */
-static void lguest_write_gdt_entry(struct desc_struct *dt,
- int entrynum, u32 low, u32 high)
-{
- write_dt_entry(dt, entrynum, low, high);
- hcall(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES, 0);
-}
-
-/* OK, I lied. There are three "thread local storage" GDT entries which change
- * on every context switch (these three entries are how glibc implements
- * __thread variables). So we have a hypercall specifically for this case. */
-static void lguest_load_tls(struct thread_struct *t, unsigned int cpu)
-{
- /* There's one problem which normal hardware doesn't have: the Host
- * can't handle us removing entries we're currently using. So we clear
- * the GS register here: if it's needed it'll be reloaded anyway. */
- loadsegment(gs, 0);
- lazy_hcall(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu, 0);
-}
-
-/*G:038 That's enough excitement for now, back to ploughing through each of
- * the paravirt_ops (we're about 1/3 of the way through).
- *
- * This is the Local Descriptor Table, another weird Intel thingy. Linux only
- * uses this for some strange applications like Wine. We don't do anything
- * here, so they'll get an informative and friendly Segmentation Fault. */
-static void lguest_set_ldt(const void *addr, unsigned entries)
-{
-}
-
-/* This loads a GDT entry into the "Task Register": that entry points to a
- * structure called the Task State Segment. Some comments scattered though the
- * kernel code indicate that this used for task switching in ages past, along
- * with blood sacrifice and astrology.
- *
- * Now there's nothing interesting in here that we don't get told elsewhere.
- * But the native version uses the "ltr" instruction, which makes the Host
- * complain to the Guest about a Segmentation Fault and it'll oops. So we
- * override the native version with a do-nothing version. */
-static void lguest_load_tr_desc(void)
-{
-}
-
-/* The "cpuid" instruction is a way of querying both the CPU identity
- * (manufacturer, model, etc) and its features. It was introduced before the
- * Pentium in 1993 and keeps getting extended by both Intel and AMD. As you
- * might imagine, after a decade and a half this treatment, it is now a giant
- * ball of hair. Its entry in the current Intel manual runs to 28 pages.
- *
- * This instruction even it has its own Wikipedia entry. The Wikipedia entry
- * has been translated into 4 languages. I am not making this up!
- *
- * We could get funky here and identify ourselves as "GenuineLguest", but
- * instead we just use the real "cpuid" instruction. Then I pretty much turned
- * off feature bits until the Guest booted. (Don't say that: you'll damage
- * lguest sales!) Shut up, inner voice! (Hey, just pointing out that this is
- * hardly future proof.) Noone's listening! They don't like you anyway,
- * parenthetic weirdo!
- *
- * Replacing the cpuid so we can turn features off is great for the kernel, but
- * anyone (including userspace) can just use the raw "cpuid" instruction and
- * the Host won't even notice since it isn't privileged. So we try not to get
- * too worked up about it. */
-static void lguest_cpuid(unsigned int *eax, unsigned int *ebx,
- unsigned int *ecx, unsigned int *edx)
-{
- int function = *eax;
-
- native_cpuid(eax, ebx, ecx, edx);
- switch (function) {
- case 1: /* Basic feature request. */
- /* We only allow kernel to see SSE3, CMPXCHG16B and SSSE3 */
- *ecx &= 0x00002201;
- /* SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, FPU. */
- *edx &= 0x07808101;
- /* The Host can do a nice optimization if it knows that the
- * kernel mappings (addresses above 0xC0000000 or whatever
- * PAGE_OFFSET is set to) haven't changed. But Linux calls
- * flush_tlb_user() for both user and kernel mappings unless
- * the Page Global Enable (PGE) feature bit is set. */
- *edx |= 0x00002000;
- break;
- case 0x80000000:
- /* Futureproof this a little: if they ask how much extended
- * processor information there is, limit it to known fields. */
- if (*eax > 0x80000008)
- *eax = 0x80000008;
- break;
- }
-}
-
-/* Intel has four control registers, imaginatively named cr0, cr2, cr3 and cr4.
- * I assume there's a cr1, but it hasn't bothered us yet, so we'll not bother
- * it. The Host needs to know when the Guest wants to change them, so we have
- * a whole series of functions like read_cr0() and write_cr0().
- *
- * We start with CR0. CR0 allows you to turn on and off all kinds of basic
- * features, but Linux only really cares about one: the horrifically-named Task
- * Switched (TS) bit at bit 3 (ie. 8)
- *
- * What does the TS bit do? Well, it causes the CPU to trap (interrupt 7) if
- * the floating point unit is used. Which allows us to restore FPU state
- * lazily after a task switch, and Linux uses that gratefully, but wouldn't a
- * name like "FPUTRAP bit" be a little less cryptic?
- *
- * We store cr0 (and cr3) locally, because the Host never changes it. The
- * Guest sometimes wants to read it and we'd prefer not to bother the Host
- * unnecessarily. */
-static unsigned long current_cr0, current_cr3;
-static void lguest_write_cr0(unsigned long val)
-{
- /* 8 == TS bit. */
- lazy_hcall(LHCALL_TS, val & 8, 0, 0);
- current_cr0 = val;
-}
-
-static unsigned long lguest_read_cr0(void)
-{
- return current_cr0;
-}
-
-/* Intel provided a special instruction to clear the TS bit for people too cool
- * to use write_cr0() to do it. This "clts" instruction is faster, because all
- * the vowels have been optimized out. */
-static void lguest_clts(void)
-{
- lazy_hcall(LHCALL_TS, 0, 0, 0);
- current_cr0 &= ~8U;
-}
-
-/* CR2 is the virtual address of the last page fault, which the Guest only ever
- * reads. The Host kindly writes this into our "struct lguest_data", so we
- * just read it out of there. */
-static unsigned long lguest_read_cr2(void)
-{
- return lguest_data.cr2;
-}
-
-/* CR3 is the current toplevel pagetable page: the principle is the same as
- * cr0. Keep a local copy, and tell the Host when it changes. */
-static void lguest_write_cr3(unsigned long cr3)
-{
- lazy_hcall(LHCALL_NEW_PGTABLE, cr3, 0, 0);
- current_cr3 = cr3;
-}
-
-static unsigned long lguest_read_cr3(void)
-{
- return current_cr3;
-}
-
-/* CR4 is used to enable and disable PGE, but we don't care. */
-static unsigned long lguest_read_cr4(void)
-{
- return 0;
-}
-
-static void lguest_write_cr4(unsigned long val)
-{
-}
-
-/*
- * Page Table Handling.
- *
- * Now would be a good time to take a rest and grab a coffee or similarly
- * relaxing stimulant. The easy parts are behind us, and the trek gradually
- * winds uphill from here.
- *
- * Quick refresher: memory is divided into "pages" of 4096 bytes each. The CPU
- * maps virtual addresses to physical addresses using "page tables". We could
- * use one huge index of 1 million entries: each address is 4 bytes, so that's
- * 1024 pages just to hold the page tables. But since most virtual addresses
- * are unused, we use a two level index which saves space. The CR3 register
- * contains the physical address of the top level "page directory" page, which
- * contains physical addresses of up to 1024 second-level pages. Each of these
- * second level pages contains up to 1024 physical addresses of actual pages,
- * or Page Table Entries (PTEs).
- *
- * Here's a diagram, where arrows indicate physical addresses:
- *
- * CR3 ---> +---------+
- * | --------->+---------+
- * | | | PADDR1 |
- * Top-level | | PADDR2 |
- * (PMD) page | | |
- * | | Lower-level |
- * | | (PTE) page |
- * | | | |
- * .... ....
- *
- * So to convert a virtual address to a physical address, we look up the top
- * level, which points us to the second level, which gives us the physical
- * address of that page. If the top level entry was not present, or the second
- * level entry was not present, then the virtual address is invalid (we
- * say "the page was not mapped").
- *
- * Put another way, a 32-bit virtual address is divided up like so:
- *
- * 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- * |<---- 10 bits ---->|<---- 10 bits ---->|<------ 12 bits ------>|
- * Index into top Index into second Offset within page
- * page directory page pagetable page
- *
- * The kernel spends a lot of time changing both the top-level page directory
- * and lower-level pagetable pages. The Guest doesn't know physical addresses,
- * so while it maintains these page tables exactly like normal, it also needs
- * to keep the Host informed whenever it makes a change: the Host will create
- * the real page tables based on the Guests'.
- */
-
-/* The Guest calls this to set a second-level entry (pte), ie. to map a page
- * into a process' address space. We set the entry then tell the Host the
- * toplevel and address this corresponds to. The Guest uses one pagetable per
- * process, so we need to tell the Host which one we're changing (mm->pgd). */
-static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, pte_t pteval)
-{
- *ptep = pteval;
- lazy_hcall(LHCALL_SET_PTE, __pa(mm->pgd), addr, pteval.pte_low);
-}
-
-/* The Guest calls this to set a top-level entry. Again, we set the entry then
- * tell the Host which top-level page we changed, and the index of the entry we
- * changed. */
-static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
-{
- *pmdp = pmdval;
- lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK,
- (__pa(pmdp)&(PAGE_SIZE-1))/4, 0);
-}
-
-/* There are a couple of legacy places where the kernel sets a PTE, but we
- * don't know the top level any more. This is useless for us, since we don't
- * know which pagetable is changing or what address, so we just tell the Host
- * to forget all of them. Fortunately, this is very rare.
- *
- * ... except in early boot when the kernel sets up the initial pagetables,
- * which makes booting astonishingly slow. So we don't even tell the Host
- * anything changed until we've done the first page table switch.
- */
-static void lguest_set_pte(pte_t *ptep, pte_t pteval)
-{
- *ptep = pteval;
- /* Don't bother with hypercall before initial setup. */
- if (current_cr3)
- lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
-}
-
-/* Unfortunately for Lguest, the paravirt_ops for page tables were based on
- * native page table operations. On native hardware you can set a new page
- * table entry whenever you want, but if you want to remove one you have to do
- * a TLB flush (a TLB is a little cache of page table entries kept by the CPU).
- *
- * So the lguest_set_pte_at() and lguest_set_pmd() functions above are only
- * called when a valid entry is written, not when it's removed (ie. marked not
- * present). Instead, this is where we come when the Guest wants to remove a
- * page table entry: we tell the Host to set that entry to 0 (ie. the present
- * bit is zero). */
-static void lguest_flush_tlb_single(unsigned long addr)
-{
- /* Simply set it to zero: if it was not, it will fault back in. */
- lazy_hcall(LHCALL_SET_PTE, current_cr3, addr, 0);
-}
-
-/* This is what happens after the Guest has removed a large number of entries.
- * This tells the Host that any of the page table entries for userspace might
- * have changed, ie. virtual addresses below PAGE_OFFSET. */
-static void lguest_flush_tlb_user(void)
-{
- lazy_hcall(LHCALL_FLUSH_TLB, 0, 0, 0);
-}
-
-/* This is called when the kernel page tables have changed. That's not very
- * common (unless the Guest is using highmem, which makes the Guest extremely
- * slow), so it's worth separating this from the user flushing above. */
-static void lguest_flush_tlb_kernel(void)
-{
- lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
-}
-
-/*
- * The Unadvanced Programmable Interrupt Controller.
- *
- * This is an attempt to implement the simplest possible interrupt controller.
- * I spent some time looking though routines like set_irq_chip_and_handler,
- * set_irq_chip_and_handler_name, set_irq_chip_data and set_phasers_to_stun and
- * I *think* this is as simple as it gets.
- *
- * We can tell the Host what interrupts we want blocked ready for using the
- * lguest_data.interrupts bitmap, so disabling (aka "masking") them is as
- * simple as setting a bit. We don't actually "ack" interrupts as such, we
- * just mask and unmask them. I wonder if we should be cleverer?
- */
-static void disable_lguest_irq(unsigned int irq)
-{
- set_bit(irq, lguest_data.blocked_interrupts);
-}
-
-static void enable_lguest_irq(unsigned int irq)
-{
- clear_bit(irq, lguest_data.blocked_interrupts);
-}
-
-/* This structure describes the lguest IRQ controller. */
-static struct irq_chip lguest_irq_controller = {
- .name = "lguest",
- .mask = disable_lguest_irq,
- .mask_ack = disable_lguest_irq,
- .unmask = enable_lguest_irq,
-};
-
-/* This sets up the Interrupt Descriptor Table (IDT) entry for each hardware
- * interrupt (except 128, which is used for system calls), and then tells the
- * Linux infrastructure that each interrupt is controlled by our level-based
- * lguest interrupt controller. */
-static void __init lguest_init_IRQ(void)
-{
- unsigned int i;
-
- for (i = 0; i < LGUEST_IRQS; i++) {
- int vector = FIRST_EXTERNAL_VECTOR + i;
- if (vector != SYSCALL_VECTOR) {
- set_intr_gate(vector, interrupt[i]);
- set_irq_chip_and_handler(i, &lguest_irq_controller,
- handle_level_irq);
- }
- }
- /* This call is required to set up for 4k stacks, where we have
- * separate stacks for hard and soft interrupts. */
- irq_ctx_init(smp_processor_id());
-}
-
-/*
- * Time.
- *
- * It would be far better for everyone if the Guest had its own clock, but
- * until then the Host gives us the time on every interrupt.
- */
-static unsigned long lguest_get_wallclock(void)
-{
- return lguest_data.time.tv_sec;
-}
-
-static cycle_t lguest_clock_read(void)
-{
- unsigned long sec, nsec;
-
- /* If the Host tells the TSC speed, we can trust that. */
- if (lguest_data.tsc_khz)
- return native_read_tsc();
-
- /* If we can't use the TSC, we read the time value written by the Host.
- * Since it's in two parts (seconds and nanoseconds), we risk reading
- * it just as it's changing from 99 & 0.999999999 to 100 and 0, and
- * getting 99 and 0. As Linux tends to come apart under the stress of
- * time travel, we must be careful: */
- do {
- /* First we read the seconds part. */
- sec = lguest_data.time.tv_sec;
- /* This read memory barrier tells the compiler and the CPU that
- * this can't be reordered: we have to complete the above
- * before going on. */
- rmb();
- /* Now we read the nanoseconds part. */
- nsec = lguest_data.time.tv_nsec;
- /* Make sure we've done that. */
- rmb();
- /* Now if the seconds part has changed, try again. */
- } while (unlikely(lguest_data.time.tv_sec != sec));
-
- /* Our non-TSC clock is in real nanoseconds. */
- return sec*1000000000ULL + nsec;
-}
-
-/* This is what we tell the kernel is our clocksource. */
-static struct clocksource lguest_clock = {
- .name = "lguest",
- .rating = 400,
- .read = lguest_clock_read,
- .mask = CLOCKSOURCE_MASK(64),
- .mult = 1 << 22,
- .shift = 22,
-};
-
-/* The "scheduler clock" is just our real clock, adjusted to start at zero */
-static unsigned long long lguest_sched_clock(void)
-{
- return cyc2ns(&lguest_clock, lguest_clock_read() - clock_base);
-}
-
-/* We also need a "struct clock_event_device": Linux asks us to set it to go
- * off some time in the future. Actually, James Morris figured all this out, I
- * just applied the patch. */
-static int lguest_clockevent_set_next_event(unsigned long delta,
- struct clock_event_device *evt)
-{
- if (delta < LG_CLOCK_MIN_DELTA) {
- if (printk_ratelimit())
- printk(KERN_DEBUG "%s: small delta %lu ns\n",
- __FUNCTION__, delta);
- return -ETIME;
- }
- hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0);
- return 0;
-}
-
-static void lguest_clockevent_set_mode(enum clock_event_mode mode,
- struct clock_event_device *evt)
-{
- switch (mode) {
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- /* A 0 argument shuts the clock down. */
- hcall(LHCALL_SET_CLOCKEVENT, 0, 0, 0);
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- /* This is what we expect. */
- break;
- case CLOCK_EVT_MODE_PERIODIC:
- BUG();
- case CLOCK_EVT_MODE_RESUME:
- break;
- }
-}
-
-/* This describes our primitive timer chip. */
-static struct clock_event_device lguest_clockevent = {
- .name = "lguest",
- .features = CLOCK_EVT_FEAT_ONESHOT,
- .set_next_event = lguest_clockevent_set_next_event,
- .set_mode = lguest_clockevent_set_mode,
- .rating = INT_MAX,
- .mult = 1,
- .shift = 0,
- .min_delta_ns = LG_CLOCK_MIN_DELTA,
- .max_delta_ns = LG_CLOCK_MAX_DELTA,
-};
-
-/* This is the Guest timer interrupt handler (hardware interrupt 0). We just
- * call the clockevent infrastructure and it does whatever needs doing. */
-static void lguest_time_irq(unsigned int irq, struct irq_desc *desc)
-{
- unsigned long flags;
-
- /* Don't interrupt us while this is running. */
- local_irq_save(flags);
- lguest_clockevent.event_handler(&lguest_clockevent);
- local_irq_restore(flags);
-}
-
-/* At some point in the boot process, we get asked to set up our timing
- * infrastructure. The kernel doesn't expect timer interrupts before this, but
- * we cleverly initialized the "blocked_interrupts" field of "struct
- * lguest_data" so that timer interrupts were blocked until now. */
-static void lguest_time_init(void)
-{
- /* Set up the timer interrupt (0) to go to our simple timer routine */
- set_irq_handler(0, lguest_time_irq);
-
- /* Our clock structure look like arch/i386/kernel/tsc.c if we can use
- * the TSC, otherwise it's a dumb nanosecond-resolution clock. Either
- * way, the "rating" is initialized so high that it's always chosen
- * over any other clocksource. */
- if (lguest_data.tsc_khz) {
- lguest_clock.mult = clocksource_khz2mult(lguest_data.tsc_khz,
- lguest_clock.shift);
- lguest_clock.flags = CLOCK_SOURCE_IS_CONTINUOUS;
- }
- clock_base = lguest_clock_read();
- clocksource_register(&lguest_clock);
-
- /* Now we've set up our clock, we can use it as the scheduler clock */
- paravirt_ops.sched_clock = lguest_sched_clock;
-
- /* We can't set cpumask in the initializer: damn C limitations! Set it
- * here and register our timer device. */
- lguest_clockevent.cpumask = cpumask_of_cpu(0);
- clockevents_register_device(&lguest_clockevent);
-
- /* Finally, we unblock the timer interrupt. */
- enable_lguest_irq(0);
-}
-
-/*
- * Miscellaneous bits and pieces.
- *
- * Here is an oddball collection of functions which the Guest needs for things
- * to work. They're pretty simple.
- */
-
-/* The Guest needs to tell the host what stack it expects traps to use. For
- * native hardware, this is part of the Task State Segment mentioned above in
- * lguest_load_tr_desc(), but to help hypervisors there's this special call.
- *
- * We tell the Host the segment we want to use (__KERNEL_DS is the kernel data
- * segment), the privilege level (we're privilege level 1, the Host is 0 and
- * will not tolerate us trying to use that), the stack pointer, and the number
- * of pages in the stack. */
-static void lguest_load_esp0(struct tss_struct *tss,
- struct thread_struct *thread)
-{
- lazy_hcall(LHCALL_SET_STACK, __KERNEL_DS|0x1, thread->esp0,
- THREAD_SIZE/PAGE_SIZE);
-}
-
-/* Let's just say, I wouldn't do debugging under a Guest. */
-static void lguest_set_debugreg(int regno, unsigned long value)
-{
- /* FIXME: Implement */
-}
-
-/* There are times when the kernel wants to make sure that no memory writes are
- * caught in the cache (that they've all reached real hardware devices). This
- * doesn't matter for the Guest which has virtual hardware.
- *
- * On the Pentium 4 and above, cpuid() indicates that the Cache Line Flush
- * (clflush) instruction is available and the kernel uses that. Otherwise, it
- * uses the older "Write Back and Invalidate Cache" (wbinvd) instruction.
- * Unlike clflush, wbinvd can only be run at privilege level 0. So we can
- * ignore clflush, but replace wbinvd.
- */
-static void lguest_wbinvd(void)
-{
-}
-
-/* If the Guest expects to have an Advanced Programmable Interrupt Controller,
- * we play dumb by ignoring writes and returning 0 for reads. So it's no
- * longer Programmable nor Controlling anything, and I don't think 8 lines of
- * code qualifies for Advanced. It will also never interrupt anything. It
- * does, however, allow us to get through the Linux boot code. */
-#ifdef CONFIG_X86_LOCAL_APIC
-static void lguest_apic_write(unsigned long reg, unsigned long v)
-{
-}
-
-static unsigned long lguest_apic_read(unsigned long reg)
-{
- return 0;
-}
-#endif
-
-/* STOP! Until an interrupt comes in. */
-static void lguest_safe_halt(void)
-{
- hcall(LHCALL_HALT, 0, 0, 0);
-}
-
-/* Perhaps CRASH isn't the best name for this hypercall, but we use it to get a
- * message out when we're crashing as well as elegant termination like powering
- * off.
- *
- * Note that the Host always prefers that the Guest speak in physical addresses
- * rather than virtual addresses, so we use __pa() here. */
-static void lguest_power_off(void)
-{
- hcall(LHCALL_CRASH, __pa("Power down"), 0, 0);
-}
-
-/*
- * Panicing.
- *
- * Don't. But if you did, this is what happens.
- */
-static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p)
-{
- hcall(LHCALL_CRASH, __pa(p), 0, 0);
- /* The hcall won't return, but to keep gcc happy, we're "done". */
- return NOTIFY_DONE;
-}
-
-static struct notifier_block paniced = {
- .notifier_call = lguest_panic
-};
-
-/* Setting up memory is fairly easy. */
-static __init char *lguest_memory_setup(void)
-{
- /* We do this here and not earlier because lockcheck barfs if we do it
- * before start_kernel() */
- atomic_notifier_chain_register(&panic_notifier_list, &paniced);
-
- /* The Linux bootloader header contains an "e820" memory map: the
- * Launcher populated the first entry with our memory limit. */
- add_memory_region(E820_MAP->addr, E820_MAP->size, E820_MAP->type);
-
- /* This string is for the boot messages. */
- return "LGUEST";
-}
-
-/*G:050
- * Patching (Powerfully Placating Performance Pedants)
- *
- * We have already seen that "struct paravirt_ops" lets us replace simple
- * native instructions with calls to the appropriate back end all throughout
- * the kernel. This allows the same kernel to run as a Guest and as a native
- * kernel, but it's slow because of all the indirect branches.
- *
- * Remember that David Wheeler quote about "Any problem in computer science can
- * be solved with another layer of indirection"? The rest of that quote is
- * "... But that usually will create another problem." This is the first of
- * those problems.
- *
- * Our current solution is to allow the paravirt back end to optionally patch
- * over the indirect calls to replace them with something more efficient. We
- * patch the four most commonly called functions: disable interrupts, enable
- * interrupts, restore interrupts and save interrupts. We usually have 10
- * bytes to patch into: the Guest versions of these operations are small enough
- * that we can fit comfortably.
- *
- * First we need assembly templates of each of the patchable Guest operations,
- * and these are in lguest_asm.S. */
-
-/*G:060 We construct a table from the assembler templates: */
-static const struct lguest_insns
-{
- const char *start, *end;
-} lguest_insns[] = {
- [PARAVIRT_PATCH(irq_disable)] = { lgstart_cli, lgend_cli },
- [PARAVIRT_PATCH(irq_enable)] = { lgstart_sti, lgend_sti },
- [PARAVIRT_PATCH(restore_fl)] = { lgstart_popf, lgend_popf },
- [PARAVIRT_PATCH(save_fl)] = { lgstart_pushf, lgend_pushf },
-};
-
-/* Now our patch routine is fairly simple (based on the native one in
- * paravirt.c). If we have a replacement, we copy it in and return how much of
- * the available space we used. */
-static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf,
- unsigned long addr, unsigned len)
-{
- unsigned int insn_len;
-
- /* Don't do anything special if we don't have a replacement */
- if (type >= ARRAY_SIZE(lguest_insns) || !lguest_insns[type].start)
- return paravirt_patch_default(type, clobber, ibuf, addr, len);
-
- insn_len = lguest_insns[type].end - lguest_insns[type].start;
-
- /* Similarly if we can't fit replacement (shouldn't happen, but let's
- * be thorough). */
- if (len < insn_len)
- return paravirt_patch_default(type, clobber, ibuf, addr, len);
-
- /* Copy in our instructions. */
- memcpy(ibuf, lguest_insns[type].start, insn_len);
- return insn_len;
-}
-
-/*G:030 Once we get to lguest_init(), we know we're a Guest. The paravirt_ops
- * structure in the kernel provides a single point for (almost) every routine
- * we have to override to avoid privileged instructions. */
-__init void lguest_init(void *boot)
-{
- /* Copy boot parameters first: the Launcher put the physical location
- * in %esi, and head.S converted that to a virtual address and handed
- * it to us. We use "__memcpy" because "memcpy" sometimes tries to do
- * tricky things to go faster, and we're not ready for that. */
- __memcpy(&boot_params, boot, PARAM_SIZE);
- /* The boot parameters also tell us where the command-line is: save
- * that, too. */
- __memcpy(boot_command_line, __va(boot_params.hdr.cmd_line_ptr),
- COMMAND_LINE_SIZE);
-
- /* We're under lguest, paravirt is enabled, and we're running at
- * privilege level 1, not 0 as normal. */
- paravirt_ops.name = "lguest";
- paravirt_ops.paravirt_enabled = 1;
- paravirt_ops.kernel_rpl = 1;
-
- /* We set up all the lguest overrides for sensitive operations. These
- * are detailed with the operations themselves. */
- paravirt_ops.save_fl = save_fl;
- paravirt_ops.restore_fl = restore_fl;
- paravirt_ops.irq_disable = irq_disable;
- paravirt_ops.irq_enable = irq_enable;
- paravirt_ops.load_gdt = lguest_load_gdt;
- paravirt_ops.memory_setup = lguest_memory_setup;
- paravirt_ops.cpuid = lguest_cpuid;
- paravirt_ops.write_cr3 = lguest_write_cr3;
- paravirt_ops.flush_tlb_user = lguest_flush_tlb_user;
- paravirt_ops.flush_tlb_single = lguest_flush_tlb_single;
- paravirt_ops.flush_tlb_kernel = lguest_flush_tlb_kernel;
- paravirt_ops.set_pte = lguest_set_pte;
- paravirt_ops.set_pte_at = lguest_set_pte_at;
- paravirt_ops.set_pmd = lguest_set_pmd;
-#ifdef CONFIG_X86_LOCAL_APIC
- paravirt_ops.apic_write = lguest_apic_write;
- paravirt_ops.apic_write_atomic = lguest_apic_write;
- paravirt_ops.apic_read = lguest_apic_read;
-#endif
- paravirt_ops.load_idt = lguest_load_idt;
- paravirt_ops.iret = lguest_iret;
- paravirt_ops.load_esp0 = lguest_load_esp0;
- paravirt_ops.load_tr_desc = lguest_load_tr_desc;
- paravirt_ops.set_ldt = lguest_set_ldt;
- paravirt_ops.load_tls = lguest_load_tls;
- paravirt_ops.set_debugreg = lguest_set_debugreg;
- paravirt_ops.clts = lguest_clts;
- paravirt_ops.read_cr0 = lguest_read_cr0;
- paravirt_ops.write_cr0 = lguest_write_cr0;
- paravirt_ops.init_IRQ = lguest_init_IRQ;
- paravirt_ops.read_cr2 = lguest_read_cr2;
- paravirt_ops.read_cr3 = lguest_read_cr3;
- paravirt_ops.read_cr4 = lguest_read_cr4;
- paravirt_ops.write_cr4 = lguest_write_cr4;
- paravirt_ops.write_gdt_entry = lguest_write_gdt_entry;
- paravirt_ops.write_idt_entry = lguest_write_idt_entry;
- paravirt_ops.patch = lguest_patch;
- paravirt_ops.safe_halt = lguest_safe_halt;
- paravirt_ops.get_wallclock = lguest_get_wallclock;
- paravirt_ops.time_init = lguest_time_init;
- paravirt_ops.set_lazy_mode = lguest_lazy_mode;
- paravirt_ops.wbinvd = lguest_wbinvd;
- /* Now is a good time to look at the implementations of these functions
- * before returning to the rest of lguest_init(). */
-
- /*G:070 Now we've seen all the paravirt_ops, we return to
- * lguest_init() where the rest of the fairly chaotic boot setup
- * occurs.
- *
- * The Host expects our first hypercall to tell it where our "struct
- * lguest_data" is, so we do that first. */
- hcall(LHCALL_LGUEST_INIT, __pa(&lguest_data), 0, 0);
-
- /* The native boot code sets up initial page tables immediately after
- * the kernel itself, and sets init_pg_tables_end so they're not
- * clobbered. The Launcher places our initial pagetables somewhere at
- * the top of our physical memory, so we don't need extra space: set
- * init_pg_tables_end to the end of the kernel. */
- init_pg_tables_end = __pa(pg0);
-
- /* Load the %fs segment register (the per-cpu segment register) with
- * the normal data segment to get through booting. */
- asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_DS) : "memory");
-
- /* Clear the part of the kernel data which is expected to be zero.
- * Normally it will be anyway, but if we're loading from a bzImage with
- * CONFIG_RELOCATALE=y, the relocations will be sitting here. */
- memset(__bss_start, 0, __bss_stop - __bss_start);
-
- /* The Host uses the top of the Guest's virtual address space for the
- * Host<->Guest Switcher, and it tells us how much it needs in
- * lguest_data.reserve_mem, set up on the LGUEST_INIT hypercall. */
- reserve_top_address(lguest_data.reserve_mem);
-
- /* If we don't initialize the lock dependency checker now, it crashes
- * paravirt_disable_iospace. */
- lockdep_init();
-
- /* The IDE code spends about 3 seconds probing for disks: if we reserve
- * all the I/O ports up front it can't get them and so doesn't probe.
- * Other device drivers are similar (but less severe). This cuts the
- * kernel boot time on my machine from 4.1 seconds to 0.45 seconds. */
- paravirt_disable_iospace();
-
- /* This is messy CPU setup stuff which the native boot code does before
- * start_kernel, so we have to do, too: */
- cpu_detect(&new_cpu_data);
- /* head.S usually sets up the first capability word, so do it here. */
- new_cpu_data.x86_capability[0] = cpuid_edx(1);
-
- /* Math is always hard! */
- new_cpu_data.hard_math = 1;
-
-#ifdef CONFIG_X86_MCE
- mce_disabled = 1;
-#endif
-#ifdef CONFIG_ACPI
- acpi_disabled = 1;
- acpi_ht = 0;
-#endif
-
- /* We set the perferred console to "hvc". This is the "hypervisor
- * virtual console" driver written by the PowerPC people, which we also
- * adapted for lguest's use. */
- add_preferred_console("hvc", 0, NULL);
-
- /* Last of all, we set the power management poweroff hook to point to
- * the Guest routine to power off. */
- pm_power_off = lguest_power_off;
-
- /* Now we're set up, call start_kernel() in init/main.c and we proceed
- * to boot as normal. It never returns. */
- start_kernel();
-}
-/*
- * This marks the end of stage II of our journey, The Guest.
- *
- * It is now time for us to explore the nooks and crannies of the three Guest
- * devices and complete our understanding of the Guest in "make Drivers".
- */
diff --git a/drivers/lguest/lguest_asm.S b/drivers/lguest/lguest_asm.S
deleted file mode 100644
index 1ddcd5cd20f..00000000000
--- a/drivers/lguest/lguest_asm.S
+++ /dev/null
@@ -1,93 +0,0 @@
-#include <linux/linkage.h>
-#include <linux/lguest.h>
-#include <asm/asm-offsets.h>
-#include <asm/thread_info.h>
-#include <asm/processor-flags.h>
-
-/*G:020 This is where we begin: we have a magic signature which the launcher
- * looks for. The plan is that the Linux boot protocol will be extended with a
- * "platform type" field which will guide us here from the normal entry point,
- * but for the moment this suffices. The normal boot code uses %esi for the
- * boot header, so we do too. We convert it to a virtual address by adding
- * PAGE_OFFSET, and hand it to lguest_init() as its argument (ie. %eax).
- *
- * The .section line puts this code in .init.text so it will be discarded after
- * boot. */
-.section .init.text, "ax", @progbits
-.ascii "GenuineLguest"
- /* Set up initial stack. */
- movl $(init_thread_union+THREAD_SIZE),%esp
- movl %esi, %eax
- addl $__PAGE_OFFSET, %eax
- jmp lguest_init
-
-/*G:055 We create a macro which puts the assembler code between lgstart_ and
- * lgend_ markers. These templates are put in the .text section: they can't be
- * discarded after boot as we may need to patch modules, too. */
-.text
-#define LGUEST_PATCH(name, insns...) \
- lgstart_##name: insns; lgend_##name:; \
- .globl lgstart_##name; .globl lgend_##name
-
-LGUEST_PATCH(cli, movl $0, lguest_data+LGUEST_DATA_irq_enabled)
-LGUEST_PATCH(sti, movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled)
-LGUEST_PATCH(popf, movl %eax, lguest_data+LGUEST_DATA_irq_enabled)
-LGUEST_PATCH(pushf, movl lguest_data+LGUEST_DATA_irq_enabled, %eax)
-/*:*/
-
-/* These demark the EIP range where host should never deliver interrupts. */
-.global lguest_noirq_start
-.global lguest_noirq_end
-
-/*M:004 When the Host reflects a trap or injects an interrupt into the Guest,
- * it sets the eflags interrupt bit on the stack based on
- * lguest_data.irq_enabled, so the Guest iret logic does the right thing when
- * restoring it. However, when the Host sets the Guest up for direct traps,
- * such as system calls, the processor is the one to push eflags onto the
- * stack, and the interrupt bit will be 1 (in reality, interrupts are always
- * enabled in the Guest).
- *
- * This turns out to be harmless: the only trap which should happen under Linux
- * with interrupts disabled is Page Fault (due to our lazy mapping of vmalloc
- * regions), which has to be reflected through the Host anyway. If another
- * trap *does* go off when interrupts are disabled, the Guest will panic, and
- * we'll never get to this iret! :*/
-
-/*G:045 There is one final paravirt_op that the Guest implements, and glancing
- * at it you can see why I left it to last. It's *cool*! It's in *assembler*!
- *
- * The "iret" instruction is used to return from an interrupt or trap. The
- * stack looks like this:
- * old address
- * old code segment & privilege level
- * old processor flags ("eflags")
- *
- * The "iret" instruction pops those values off the stack and restores them all
- * at once. The only problem is that eflags includes the Interrupt Flag which
- * the Guest can't change: the CPU will simply ignore it when we do an "iret".
- * So we have to copy eflags from the stack to lguest_data.irq_enabled before
- * we do the "iret".
- *
- * There are two problems with this: firstly, we need to use a register to do
- * the copy and secondly, the whole thing needs to be atomic. The first
- * problem is easy to solve: push %eax on the stack so we can use it, and then
- * restore it at the end just before the real "iret".
- *
- * The second is harder: copying eflags to lguest_data.irq_enabled will turn
- * interrupts on before we're finished, so we could be interrupted before we
- * return to userspace or wherever. Our solution to this is to surround the
- * code with lguest_noirq_start: and lguest_noirq_end: labels. We tell the
- * Host that it is *never* to interrupt us there, even if interrupts seem to be
- * enabled. */
-ENTRY(lguest_iret)
- pushl %eax
- movl 12(%esp), %eax
-lguest_noirq_start:
- /* Note the %ss: segment prefix here. Normal data accesses use the
- * "ds" segment, but that will have already been restored for whatever
- * we're returning to (such as userspace): we can't trust it. The %ss:
- * prefix makes sure we use the stack segment, which is still valid. */
- movl %eax,%ss:lguest_data+LGUEST_DATA_irq_enabled
- popl %eax
- iret
-lguest_noirq_end:
diff --git a/drivers/lguest/lguest_bus.c b/drivers/lguest/lguest_bus.c
deleted file mode 100644
index 9e7752cc800..00000000000
--- a/drivers/lguest/lguest_bus.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*P:050 Lguest guests use a very simple bus for devices. It's a simple array
- * of device descriptors contained just above the top of normal memory. The
- * lguest bus is 80% tedious boilerplate code. :*/
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/lguest_bus.h>
-#include <asm/io.h>
-#include <asm/paravirt.h>
-
-static ssize_t type_show(struct device *_dev,
- struct device_attribute *attr, char *buf)
-{
- struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
- return sprintf(buf, "%hu", lguest_devices[dev->index].type);
-}
-static ssize_t features_show(struct device *_dev,
- struct device_attribute *attr, char *buf)
-{
- struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
- return sprintf(buf, "%hx", lguest_devices[dev->index].features);
-}
-static ssize_t pfn_show(struct device *_dev,
- struct device_attribute *attr, char *buf)
-{
- struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
- return sprintf(buf, "%u", lguest_devices[dev->index].pfn);
-}
-static ssize_t status_show(struct device *_dev,
- struct device_attribute *attr, char *buf)
-{
- struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
- return sprintf(buf, "%hx", lguest_devices[dev->index].status);
-}
-static ssize_t status_store(struct device *_dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
- if (sscanf(buf, "%hi", &lguest_devices[dev->index].status) != 1)
- return -EINVAL;
- return count;
-}
-static struct device_attribute lguest_dev_attrs[] = {
- __ATTR_RO(type),
- __ATTR_RO(features),
- __ATTR_RO(pfn),
- __ATTR(status, 0644, status_show, status_store),
- __ATTR_NULL
-};
-
-/*D:130 The generic bus infrastructure requires a function which says whether a
- * device matches a driver. For us, it is simple: "struct lguest_driver"
- * contains a "device_type" field which indicates what type of device it can
- * handle, so we just cast the args and compare: */
-static int lguest_dev_match(struct device *_dev, struct device_driver *_drv)
-{
- struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
- struct lguest_driver *drv = container_of(_drv,struct lguest_driver,drv);
-
- return (drv->device_type == lguest_devices[dev->index].type);
-}
-/*:*/
-
-struct lguest_bus {
- struct bus_type bus;
- struct device dev;
-};
-
-static struct lguest_bus lguest_bus = {
- .bus = {
- .name = "lguest",
- .match = lguest_dev_match,
- .dev_attrs = lguest_dev_attrs,
- },
- .dev = {
- .parent = NULL,
- .bus_id = "lguest",
- }
-};
-
-/*D:140 This is the callback which occurs once the bus infrastructure matches
- * up a device and driver, ie. in response to add_lguest_device() calling
- * device_register(), or register_lguest_driver() calling driver_register().
- *
- * At the moment it's always the latter: the devices are added first, since
- * scan_devices() is called from a "core_initcall", and the drivers themselves
- * called later as a normal "initcall". But it would work the other way too.
- *
- * So now we have the happy couple, we add the status bit to indicate that we
- * found a driver. If the driver truly loves the device, it will return
- * happiness from its probe function (ok, perhaps this wasn't my greatest
- * analogy), and we set the final "driver ok" bit so the Host sees it's all
- * green. */
-static int lguest_dev_probe(struct device *_dev)
-{
- int ret;
- struct lguest_device*dev = container_of(_dev,struct lguest_device,dev);
- struct lguest_driver*drv = container_of(dev->dev.driver,
- struct lguest_driver, drv);
-
- lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER;
- ret = drv->probe(dev);
- if (ret == 0)
- lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER_OK;
- return ret;
-}
-
-/* The last part of the bus infrastructure is the function lguest drivers use
- * to register themselves. Firstly, we do nothing if there's no lguest bus
- * (ie. this is not a Guest), otherwise we fill in the embedded generic "struct
- * driver" fields and call the generic driver_register(). */
-int register_lguest_driver(struct lguest_driver *drv)
-{
- if (!lguest_devices)
- return 0;
-
- drv->drv.bus = &lguest_bus.bus;
- drv->drv.name = drv->name;
- drv->drv.owner = drv->owner;
- drv->drv.probe = lguest_dev_probe;
-
- return driver_register(&drv->drv);
-}
-
-/* At the moment we build all the drivers into the kernel because they're so
- * simple: 8144 bytes for all three of them as I type this. And as the console
- * really needs to be built in, it's actually only 3527 bytes for the network
- * and block drivers.
- *
- * If they get complex it will make sense for them to be modularized, so we
- * need to explicitly export the symbol.
- *
- * I don't think non-GPL modules make sense, so it's a GPL-only export.
- */
-EXPORT_SYMBOL_GPL(register_lguest_driver);
-
-/*D:120 This is the core of the lguest bus: actually adding a new device.
- * It's a separate function because it's neater that way, and because an
- * earlier version of the code supported hotplug and unplug. They were removed
- * early on because they were never used.
- *
- * As Andrew Tridgell says, "Untested code is buggy code".
- *
- * It's worth reading this carefully: we start with an index into the array of
- * "struct lguest_device_desc"s indicating the device which is new: */
-static void add_lguest_device(unsigned int index)
-{
- struct lguest_device *new;
-
- /* Each "struct lguest_device_desc" has a "status" field, which the
- * Guest updates as the device is probed. In the worst case, the Host
- * can look at these bits to tell what part of device setup failed,
- * even if the console isn't available. */
- lguest_devices[index].status |= LGUEST_DEVICE_S_ACKNOWLEDGE;
- new = kmalloc(sizeof(struct lguest_device), GFP_KERNEL);
- if (!new) {
- printk(KERN_EMERG "Cannot allocate lguest device %u\n", index);
- lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED;
- return;
- }
-
- /* The "struct lguest_device" setup is pretty straight-forward example
- * code. */
- new->index = index;
- new->private = NULL;
- memset(&new->dev, 0, sizeof(new->dev));
- new->dev.parent = &lguest_bus.dev;
- new->dev.bus = &lguest_bus.bus;
- sprintf(new->dev.bus_id, "%u", index);
-
- /* device_register() causes the bus infrastructure to look for a
- * matching driver. */
- if (device_register(&new->dev) != 0) {
- printk(KERN_EMERG "Cannot register lguest device %u\n", index);
- lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED;
- kfree(new);
- }
-}
-
-/*D:110 scan_devices() simply iterates through the device array. The type 0
- * is reserved to mean "no device", and anything else means we have found a
- * device: add it. */
-static void scan_devices(void)
-{
- unsigned int i;
-
- for (i = 0; i < LGUEST_MAX_DEVICES; i++)
- if (lguest_devices[i].type)
- add_lguest_device(i);
-}
-
-/*D:100 Fairly early in boot, lguest_bus_init() is called to set up the lguest
- * bus. We check that we are a Guest by checking paravirt_ops.name: there are
- * other ways of checking, but this seems most obvious to me.
- *
- * So we can access the array of "struct lguest_device_desc"s easily, we map
- * that memory and store the pointer in the global "lguest_devices". Then we
- * register the bus with the core. Doing two registrations seems clunky to me,
- * but it seems to be the correct sysfs incantation.
- *
- * Finally we call scan_devices() which adds all the devices found in the
- * "struct lguest_device_desc" array. */
-static int __init lguest_bus_init(void)
-{
- if (strcmp(paravirt_ops.name, "lguest") != 0)
- return 0;
-
- /* Devices are in a single page above top of "normal" mem */
- lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1);
-
- if (bus_register(&lguest_bus.bus) != 0
- || device_register(&lguest_bus.dev) != 0)
- panic("lguest bus registration failed");
-
- scan_devices();
- return 0;
-}
-/* Do this after core stuff, before devices. */
-postcore_initcall(lguest_bus_init);
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
new file mode 100644
index 00000000000..66f38722253
--- /dev/null
+++ b/drivers/lguest/lguest_device.c
@@ -0,0 +1,377 @@
+/*P:050 Lguest guests use a very simple method to describe devices. It's a
+ * series of device descriptors contained just above the top of normal
+ * memory.
+ *
+ * We use the standard "virtio" device infrastructure, which provides us with a
+ * console, a network and a block driver. Each one expects some configuration
+ * information and a "virtqueue" mechanism to send and receive data. :*/
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/lguest_launcher.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/interrupt.h>
+#include <linux/virtio_ring.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <asm/paravirt.h>
+#include <asm/lguest_hcall.h>
+
+/* The pointer to our (page) of device descriptions. */
+static void *lguest_devices;
+
+/* Unique numbering for lguest devices. */
+static unsigned int dev_index;
+
+/* For Guests, device memory can be used as normal memory, so we cast away the
+ * __iomem to quieten sparse. */
+static inline void *lguest_map(unsigned long phys_addr, unsigned long pages)
+{
+ return (__force void *)ioremap(phys_addr, PAGE_SIZE*pages);
+}
+
+static inline void lguest_unmap(void *addr)
+{
+ iounmap((__force void __iomem *)addr);
+}
+
+/*D:100 Each lguest device is just a virtio device plus a pointer to its entry
+ * in the lguest_devices page. */
+struct lguest_device {
+ struct virtio_device vdev;
+
+ /* The entry in the lguest_devices page for this device. */
+ struct lguest_device_desc *desc;
+};
+
+/* Since the virtio infrastructure hands us a pointer to the virtio_device all
+ * the time, it helps to have a curt macro to get a pointer to the struct
+ * lguest_device it's enclosed in. */
+#define to_lgdev(vdev) container_of(vdev, struct lguest_device, vdev)
+
+/*D:130
+ * Device configurations
+ *
+ * The configuration information for a device consists of a series of fields.
+ * We don't really care what they are: the Launcher set them up, and the driver
+ * will look at them during setup.
+ *
+ * For us these fields come immediately after that device's descriptor in the
+ * lguest_devices page.
+ *
+ * Each field starts with a "type" byte, a "length" byte, then that number of
+ * bytes of configuration information. The device descriptor tells us the
+ * total configuration length so we know when we've reached the last field. */
+
+/* type + length bytes */
+#define FHDR_LEN 2
+
+/* This finds the first field of a given type for a device's configuration. */
+static void *lg_find(struct virtio_device *vdev, u8 type, unsigned int *len)
+{
+ struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
+ int i;
+
+ for (i = 0; i < desc->config_len; i += FHDR_LEN + desc->config[i+1]) {
+ if (desc->config[i] == type) {
+ /* Mark it used, so Host can know we looked at it, and
+ * also so we won't find the same one twice. */
+ desc->config[i] |= 0x80;
+ /* Remember, the second byte is the length. */
+ *len = desc->config[i+1];
+ /* We return a pointer to the field header. */
+ return desc->config + i;
+ }
+ }
+
+ /* Not found: return NULL for failure. */
+ return NULL;
+}
+
+/* Once they've found a field, getting a copy of it is easy. */
+static void lg_get(struct virtio_device *vdev, void *token,
+ void *buf, unsigned len)
+{
+ /* Check they didn't ask for more than the length of the field! */
+ BUG_ON(len > ((u8 *)token)[1]);
+ memcpy(buf, token + FHDR_LEN, len);
+}
+
+/* Setting the contents is also trivial. */
+static void lg_set(struct virtio_device *vdev, void *token,
+ const void *buf, unsigned len)
+{
+ BUG_ON(len > ((u8 *)token)[1]);
+ memcpy(token + FHDR_LEN, buf, len);
+}
+
+/* The operations to get and set the status word just access the status field
+ * of the device descriptor. */
+static u8 lg_get_status(struct virtio_device *vdev)
+{
+ return to_lgdev(vdev)->desc->status;
+}
+
+static void lg_set_status(struct virtio_device *vdev, u8 status)
+{
+ to_lgdev(vdev)->desc->status = status;
+}
+
+/*
+ * Virtqueues
+ *
+ * The other piece of infrastructure virtio needs is a "virtqueue": a way of
+ * the Guest device registering buffers for the other side to read from or
+ * write into (ie. send and receive buffers). Each device can have multiple
+ * virtqueues: for example the console driver uses one queue for sending and
+ * another for receiving.
+ *
+ * Fortunately for us, a very fast shared-memory-plus-descriptors virtqueue
+ * already exists in virtio_ring.c. We just need to connect it up.
+ *
+ * We start with the information we need to keep about each virtqueue.
+ */
+
+/*D:140 This is the information we remember about each virtqueue. */
+struct lguest_vq_info
+{
+ /* A copy of the information contained in the device config. */
+ struct lguest_vqconfig config;
+
+ /* The address where we mapped the virtio ring, so we can unmap it. */
+ void *pages;
+};
+
+/* When the virtio_ring code wants to prod the Host, it calls us here and we
+ * make a hypercall. We hand the page number of the virtqueue so the Host
+ * knows which virtqueue we're talking about. */
+static void lg_notify(struct virtqueue *vq)
+{
+ /* We store our virtqueue information in the "priv" pointer of the
+ * virtqueue structure. */
+ struct lguest_vq_info *lvq = vq->priv;
+
+ hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0);
+}
+
+/* This routine finds the first virtqueue described in the configuration of
+ * this device and sets it up.
+ *
+ * This is kind of an ugly duckling. It'd be nicer to have a standard
+ * representation of a virtqueue in the configuration space, but it seems that
+ * everyone wants to do it differently. The KVM coders want the Guest to
+ * allocate its own pages and tell the Host where they are, but for lguest it's
+ * simpler for the Host to simply tell us where the pages are.
+ *
+ * So we provide devices with a "find virtqueue and set it up" function. */
+static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
+ bool (*callback)(struct virtqueue *vq))
+{
+ struct lguest_vq_info *lvq;
+ struct virtqueue *vq;
+ unsigned int len;
+ void *token;
+ int err;
+
+ /* Look for a field of the correct type to mark a virtqueue. Note that
+ * if this succeeds, then the type will be changed so it won't be found
+ * again, and future lg_find_vq() calls will find the next
+ * virtqueue (if any). */
+ token = vdev->config->find(vdev, VIRTIO_CONFIG_F_VIRTQUEUE, &len);
+ if (!token)
+ return ERR_PTR(-ENOENT);
+
+ lvq = kmalloc(sizeof(*lvq), GFP_KERNEL);
+ if (!lvq)
+ return ERR_PTR(-ENOMEM);
+
+ /* Note: we could use a configuration space inside here, just like we
+ * do for the device. This would allow expansion in future, because
+ * our configuration system is designed to be expansible. But this is
+ * way easier. */
+ if (len != sizeof(lvq->config)) {
+ dev_err(&vdev->dev, "Unexpected virtio config len %u\n", len);
+ err = -EIO;
+ goto free_lvq;
+ }
+ /* Make a copy of the "struct lguest_vqconfig" field. We need a copy
+ * because the config space might not be aligned correctly. */
+ vdev->config->get(vdev, token, &lvq->config, sizeof(lvq->config));
+
+ /* Figure out how many pages the ring will take, and map that memory */
+ lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT,
+ DIV_ROUND_UP(vring_size(lvq->config.num,
+ PAGE_SIZE),
+ PAGE_SIZE));
+ if (!lvq->pages) {
+ err = -ENOMEM;
+ goto free_lvq;
+ }
+
+ /* OK, tell virtio_ring.c to set up a virtqueue now we know its size
+ * and we've got a pointer to its pages. */
+ vq = vring_new_virtqueue(lvq->config.num, vdev, lvq->pages,
+ lg_notify, callback);
+ if (!vq) {
+ err = -ENOMEM;
+ goto unmap;
+ }
+
+ /* Tell the interrupt for this virtqueue to go to the virtio_ring
+ * interrupt handler. */
+ /* FIXME: We used to have a flag for the Host to tell us we could use
+ * the interrupt as a source of randomness: it'd be nice to have that
+ * back.. */
+ err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED,
+ vdev->dev.bus_id, vq);
+ if (err)
+ goto destroy_vring;
+
+ /* Last of all we hook up our 'struct lguest_vq_info" to the
+ * virtqueue's priv pointer. */
+ vq->priv = lvq;
+ return vq;
+
+destroy_vring:
+ vring_del_virtqueue(vq);
+unmap:
+ lguest_unmap(lvq->pages);
+free_lvq:
+ kfree(lvq);
+ return ERR_PTR(err);
+}
+/*:*/
+
+/* Cleaning up a virtqueue is easy */
+static void lg_del_vq(struct virtqueue *vq)
+{
+ struct lguest_vq_info *lvq = vq->priv;
+
+ /* Tell virtio_ring.c to free the virtqueue. */
+ vring_del_virtqueue(vq);
+ /* Unmap the pages containing the ring. */
+ lguest_unmap(lvq->pages);
+ /* Free our own queue information. */
+ kfree(lvq);
+}
+
+/* The ops structure which hooks everything together. */
+static struct virtio_config_ops lguest_config_ops = {
+ .find = lg_find,
+ .get = lg_get,
+ .set = lg_set,
+ .get_status = lg_get_status,
+ .set_status = lg_set_status,
+ .find_vq = lg_find_vq,
+ .del_vq = lg_del_vq,
+};
+
+/* The root device for the lguest virtio devices. This makes them appear as
+ * /sys/devices/lguest/0,1,2 not /sys/devices/0,1,2. */
+static struct device lguest_root = {
+ .parent = NULL,
+ .bus_id = "lguest",
+};
+
+/*D:120 This is the core of the lguest bus: actually adding a new device.
+ * It's a separate function because it's neater that way, and because an
+ * earlier version of the code supported hotplug and unplug. They were removed
+ * early on because they were never used.
+ *
+ * As Andrew Tridgell says, "Untested code is buggy code".
+ *
+ * It's worth reading this carefully: we start with a pointer to the new device
+ * descriptor in the "lguest_devices" page. */
+static void add_lguest_device(struct lguest_device_desc *d)
+{
+ struct lguest_device *ldev;
+
+ /* Start with zeroed memory; Linux's device layer seems to count on
+ * it. */
+ ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
+ if (!ldev) {
+ printk(KERN_EMERG "Cannot allocate lguest dev %u\n",
+ dev_index++);
+ return;
+ }
+
+ /* This devices' parent is the lguest/ dir. */
+ ldev->vdev.dev.parent = &lguest_root;
+ /* We have a unique device index thanks to the dev_index counter. */
+ ldev->vdev.index = dev_index++;
+ /* The device type comes straight from the descriptor. There's also a
+ * device vendor field in the virtio_device struct, which we leave as
+ * 0. */
+ ldev->vdev.id.device = d->type;
+ /* We have a simple set of routines for querying the device's
+ * configuration information and setting its status. */
+ ldev->vdev.config = &lguest_config_ops;
+ /* And we remember the device's descriptor for lguest_config_ops. */
+ ldev->desc = d;
+
+ /* register_virtio_device() sets up the generic fields for the struct
+ * virtio_device and calls device_register(). This makes the bus
+ * infrastructure look for a matching driver. */
+ if (register_virtio_device(&ldev->vdev) != 0) {
+ printk(KERN_ERR "Failed to register lguest device %u\n",
+ ldev->vdev.index);
+ kfree(ldev);
+ }
+}
+
+/*D:110 scan_devices() simply iterates through the device page. The type 0 is
+ * reserved to mean "end of devices". */
+static void scan_devices(void)
+{
+ unsigned int i;
+ struct lguest_device_desc *d;
+
+ /* We start at the page beginning, and skip over each entry. */
+ for (i = 0; i < PAGE_SIZE; i += sizeof(*d) + d->config_len) {
+ d = lguest_devices + i;
+
+ /* Once we hit a zero, stop. */
+ if (d->type == 0)
+ break;
+
+ add_lguest_device(d);
+ }
+}
+
+/*D:105 Fairly early in boot, lguest_devices_init() is called to set up the
+ * lguest device infrastructure. We check that we are a Guest by checking
+ * pv_info.name: there are other ways of checking, but this seems most
+ * obvious to me.
+ *
+ * So we can access the "struct lguest_device_desc"s easily, we map that memory
+ * and store the pointer in the global "lguest_devices". Then we register a
+ * root device from which all our devices will hang (this seems to be the
+ * correct sysfs incantation).
+ *
+ * Finally we call scan_devices() which adds all the devices found in the
+ * lguest_devices page. */
+static int __init lguest_devices_init(void)
+{
+ if (strcmp(pv_info.name, "lguest") != 0)
+ return 0;
+
+ if (device_register(&lguest_root) != 0)
+ panic("Could not register lguest root");
+
+ /* Devices are in a single page above top of "normal" mem */
+ lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1);
+
+ scan_devices();
+ return 0;
+}
+/* We do this after core stuff, but before the drivers. */
+postcore_initcall(lguest_devices_init);
+
+/*D:150 At this point in the journey we used to now wade through the lguest
+ * devices themselves: net, block and console. Since they're all now virtio
+ * devices rather than lguest-specific, I've decided to ignore them. Mostly,
+ * they're kind of boring. But this does mean you'll never experience the
+ * thrill of reading the forbidden love scene buried deep in the block driver.
+ *
+ * "make Launcher" beckons, where we answer questions like "Where do Guests
+ * come from?", and "What do you do when someone asks for optimization?". */
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
index 80d1b58c769..3b92a61ba8d 100644
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -1,83 +1,29 @@
/*P:200 This contains all the /dev/lguest code, whereby the userspace launcher
* controls and communicates with the Guest. For example, the first write will
- * tell us the memory size, pagetable, entry point and kernel address offset.
- * A read will run the Guest until a signal is pending (-EINTR), or the Guest
- * does a DMA out to the Launcher. Writes are also used to get a DMA buffer
- * registered by the Guest and to send the Guest an interrupt. :*/
+ * tell us the Guest's memory layout, pagetable, entry point and kernel address
+ * offset. A read will run the Guest until something happens, such as a signal
+ * or the Guest doing a NOTIFY out to the Launcher. :*/
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include "lg.h"
-/*L:030 setup_regs() doesn't really belong in this file, but it gives us an
- * early glimpse deeper into the Host so it's worth having here.
- *
- * Most of the Guest's registers are left alone: we used get_zeroed_page() to
- * allocate the structure, so they will be 0. */
-static void setup_regs(struct lguest_regs *regs, unsigned long start)
-{
- /* There are four "segment" registers which the Guest needs to boot:
- * The "code segment" register (cs) refers to the kernel code segment
- * __KERNEL_CS, and the "data", "extra" and "stack" segment registers
- * refer to the kernel data segment __KERNEL_DS.
- *
- * The privilege level is packed into the lower bits. The Guest runs
- * at privilege level 1 (GUEST_PL).*/
- regs->ds = regs->es = regs->ss = __KERNEL_DS|GUEST_PL;
- regs->cs = __KERNEL_CS|GUEST_PL;
-
- /* The "eflags" register contains miscellaneous flags. Bit 1 (0x002)
- * is supposed to always be "1". Bit 9 (0x200) controls whether
- * interrupts are enabled. We always leave interrupts enabled while
- * running the Guest. */
- regs->eflags = 0x202;
-
- /* The "Extended Instruction Pointer" register says where the Guest is
- * running. */
- regs->eip = start;
-
- /* %esi points to our boot information, at physical address 0, so don't
- * touch it. */
-}
-
-/*L:310 To send DMA into the Guest, the Launcher needs to be able to ask for a
- * DMA buffer. This is done by writing LHREQ_GETDMA and the key to
- * /dev/lguest. */
-static long user_get_dma(struct lguest *lg, const u32 __user *input)
-{
- unsigned long key, udma, irq;
-
- /* Fetch the key they wrote to us. */
- if (get_user(key, input) != 0)
- return -EFAULT;
- /* Look for a free Guest DMA buffer bound to that key. */
- udma = get_dma_buffer(lg, key, &irq);
- if (!udma)
- return -ENOENT;
-
- /* We need to tell the Launcher what interrupt the Guest expects after
- * the buffer is filled. We stash it in udma->used_len. */
- lgwrite_u32(lg, udma + offsetof(struct lguest_dma, used_len), irq);
-
- /* The (guest-physical) address of the DMA buffer is returned from
- * the write(). */
- return udma;
-}
-
-/*L:315 To force the Guest to stop running and return to the Launcher, the
- * Waker sets writes LHREQ_BREAK and the value "1" to /dev/lguest. The
- * Launcher then writes LHREQ_BREAK and "0" to release the Waker. */
-static int break_guest_out(struct lguest *lg, const u32 __user *input)
+/*L:055 When something happens, the Waker process needs a way to stop the
+ * kernel running the Guest and return to the Launcher. So the Waker writes
+ * LHREQ_BREAK and the value "1" to /dev/lguest to do this. Once the Launcher
+ * has done whatever needs attention, it writes LHREQ_BREAK and "0" to release
+ * the Waker. */
+static int break_guest_out(struct lguest *lg, const unsigned long __user *input)
{
unsigned long on;
- /* Fetch whether they're turning break on or off.. */
+ /* Fetch whether they're turning break on or off. */
if (get_user(on, input) != 0)
return -EFAULT;
if (on) {
lg->break_out = 1;
- /* Pop it out (may be running on different CPU) */
+ /* Pop it out of the Guest (may be running on different CPU) */
wake_up_process(lg->tsk);
/* Wait for them to reset it */
return wait_event_interruptible(lg->break_wq, !lg->break_out);
@@ -90,9 +36,9 @@ static int break_guest_out(struct lguest *lg, const u32 __user *input)
/*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt
* number to /dev/lguest. */
-static int user_send_irq(struct lguest *lg, const u32 __user *input)
+static int user_send_irq(struct lguest *lg, const unsigned long __user *input)
{
- u32 irq;
+ unsigned long irq;
if (get_user(irq, input) != 0)
return -EFAULT;
@@ -114,7 +60,7 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
if (!lg)
return -EINVAL;
- /* If you're not the task which owns the guest, go away. */
+ /* If you're not the task which owns the Guest, go away. */
if (current != lg->tsk)
return -EPERM;
@@ -133,43 +79,39 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
return len;
}
- /* If we returned from read() last time because the Guest sent DMA,
+ /* If we returned from read() last time because the Guest notified,
* clear the flag. */
- if (lg->dma_is_pending)
- lg->dma_is_pending = 0;
+ if (lg->pending_notify)
+ lg->pending_notify = 0;
/* Run the Guest until something interesting happens. */
return run_guest(lg, (unsigned long __user *)user);
}
-/*L:020 The initialization write supplies 4 32-bit values (in addition to the
- * 32-bit LHREQ_INITIALIZE value). These are:
+/*L:020 The initialization write supplies 4 pointer sized (32 or 64 bit)
+ * values (in addition to the LHREQ_INITIALIZE value). These are:
+ *
+ * base: The start of the Guest-physical memory inside the Launcher memory.
*
* pfnlimit: The highest (Guest-physical) page number the Guest should be
- * allowed to access. The Launcher has to live in Guest memory, so it sets
- * this to ensure the Guest can't reach it.
+ * allowed to access. The Guest memory lives inside the Launcher, so it sets
+ * this to ensure the Guest can only reach its own memory.
*
* pgdir: The (Guest-physical) address of the top of the initial Guest
* pagetables (which are set up by the Launcher).
*
* start: The first instruction to execute ("eip" in x86-speak).
- *
- * page_offset: The PAGE_OFFSET constant in the Guest kernel. We should
- * probably wean the code off this, but it's a very useful constant! Any
- * address above this is within the Guest kernel, and any kernel address can
- * quickly converted from physical to virtual by adding PAGE_OFFSET. It's
- * 0xC0000000 (3G) by default, but it's configurable at kernel build time.
*/
-static int initialize(struct file *file, const u32 __user *input)
+static int initialize(struct file *file, const unsigned long __user *input)
{
/* "struct lguest" contains everything we (the Host) know about a
* Guest. */
struct lguest *lg;
- int err, i;
- u32 args[4];
+ int err;
+ unsigned long args[4];
- /* We grab the Big Lguest lock, which protects the global array
- * "lguests" and multiple simultaneous initializations. */
+ /* We grab the Big Lguest lock, which protects against multiple
+ * simultaneous initializations. */
mutex_lock(&lguest_lock);
/* You can't initialize twice! Close the device and start again... */
if (file->private_data) {
@@ -182,20 +124,15 @@ static int initialize(struct file *file, const u32 __user *input)
goto unlock;
}
- /* Find an unused guest. */
- i = find_free_guest();
- if (i < 0) {
- err = -ENOSPC;
+ lg = kzalloc(sizeof(*lg), GFP_KERNEL);
+ if (!lg) {
+ err = -ENOMEM;
goto unlock;
}
- /* OK, we have an index into the "lguest" array: "lg" is a convenient
- * pointer. */
- lg = &lguests[i];
/* Populate the easy fields of our "struct lguest" */
- lg->guestid = i;
- lg->pfn_limit = args[0];
- lg->page_offset = args[3];
+ lg->mem_base = (void __user *)(long)args[0];
+ lg->pfn_limit = args[1];
/* We need a complete page for the Guest registers: they are accessible
* to the Guest and we can only grant it access to whole pages. */
@@ -210,17 +147,13 @@ static int initialize(struct file *file, const u32 __user *input)
/* Initialize the Guest's shadow page tables, using the toplevel
* address the Launcher gave us. This allocates memory, so can
* fail. */
- err = init_guest_pagetable(lg, args[1]);
+ err = init_guest_pagetable(lg, args[2]);
if (err)
goto free_regs;
/* Now we initialize the Guest's registers, handing it the start
* address. */
- setup_regs(lg->regs, args[2]);
-
- /* There are a couple of GDT entries the Guest expects when first
- * booting. */
- setup_guest_gdt(lg);
+ lguest_arch_setup_regs(lg, args[3]);
/* The timer for lguest's clock needs initialization. */
init_clockdev(lg);
@@ -251,27 +184,28 @@ static int initialize(struct file *file, const u32 __user *input)
free_regs:
free_page(lg->regs_page);
release_guest:
- memset(lg, 0, sizeof(*lg));
+ kfree(lg);
unlock:
mutex_unlock(&lguest_lock);
return err;
}
/*L:010 The first operation the Launcher does must be a write. All writes
- * start with a 32 bit number: for the first write this must be
+ * start with an unsigned long number: for the first write this must be
* LHREQ_INITIALIZE to set up the Guest. After that the Launcher can use
- * writes of other values to get DMA buffers and send interrupts. */
-static ssize_t write(struct file *file, const char __user *input,
+ * writes of other values to send interrupts. */
+static ssize_t write(struct file *file, const char __user *in,
size_t size, loff_t *off)
{
/* Once the guest is initialized, we hold the "struct lguest" in the
* file private data. */
struct lguest *lg = file->private_data;
- u32 req;
+ const unsigned long __user *input = (const unsigned long __user *)in;
+ unsigned long req;
if (get_user(req, input) != 0)
return -EFAULT;
- input += sizeof(req);
+ input++;
/* If you haven't initialized, you must do that first. */
if (req != LHREQ_INITIALIZE && !lg)
@@ -287,13 +221,11 @@ static ssize_t write(struct file *file, const char __user *input,
switch (req) {
case LHREQ_INITIALIZE:
- return initialize(file, (const u32 __user *)input);
- case LHREQ_GETDMA:
- return user_get_dma(lg, (const u32 __user *)input);
+ return initialize(file, input);
case LHREQ_IRQ:
- return user_send_irq(lg, (const u32 __user *)input);
+ return user_send_irq(lg, input);
case LHREQ_BREAK:
- return break_guest_out(lg, (const u32 __user *)input);
+ return break_guest_out(lg, input);
default:
return -EINVAL;
}
@@ -319,8 +251,6 @@ static int close(struct inode *inode, struct file *file)
mutex_lock(&lguest_lock);
/* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
hrtimer_cancel(&lg->hrt);
- /* Free any DMA buffers the Guest had bound. */
- release_all_dma(lg);
/* Free up the shadow page tables for the Guest. */
free_guest_pagetable(lg);
/* Now all the memory cleanups are done, it's safe to release the
@@ -347,8 +277,7 @@ static int close(struct inode *inode, struct file *file)
* The Launcher is the Host userspace program which sets up, runs and services
* the Guest. In fact, many comments in the Drivers which refer to "the Host"
* doing things are inaccurate: the Launcher does all the device handling for
- * the Guest. The Guest can't tell what's done by the the Launcher and what by
- * the Host.
+ * the Guest, but the Guest can't know that.
*
* Just to confuse you: to the Host kernel, the Launcher *is* the Guest and we
* shall see more of that later.
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
index b7a924ace68..fffabb32715 100644
--- a/drivers/lguest/page_tables.c
+++ b/drivers/lguest/page_tables.c
@@ -13,6 +13,7 @@
#include <linux/random.h>
#include <linux/percpu.h>
#include <asm/tlbflush.h>
+#include <asm/uaccess.h>
#include "lg.h"
/*M:008 We hold reference to pages, which prevents them from being swapped.
@@ -25,7 +26,8 @@
*
* We use two-level page tables for the Guest. If you're not entirely
* comfortable with virtual addresses, physical addresses and page tables then
- * I recommend you review lguest.c's "Page Table Handling" (with diagrams!).
+ * I recommend you review arch/x86/lguest/boot.c's "Page Table Handling" (with
+ * diagrams!).
*
* The Guest keeps page tables, but we maintain the actual ones here: these are
* called "shadow" page tables. Which is a very Guest-centric name: these are
@@ -35,53 +37,40 @@
*
* Anyway, this is the most complicated part of the Host code. There are seven
* parts to this:
- * (i) Setting up a page table entry for the Guest when it faults,
- * (ii) Setting up the page table entry for the Guest stack,
- * (iii) Setting up a page table entry when the Guest tells us it has changed,
+ * (i) Looking up a page table entry when the Guest faults,
+ * (ii) Making sure the Guest stack is mapped,
+ * (iii) Setting up a page table entry when the Guest tells us one has changed,
* (iv) Switching page tables,
- * (v) Flushing (thowing away) page tables,
+ * (v) Flushing (throwing away) page tables,
* (vi) Mapping the Switcher when the Guest is about to run,
* (vii) Setting up the page tables initially.
:*/
-/* Pages a 4k long, and each page table entry is 4 bytes long, giving us 1024
- * (or 2^10) entries per page. */
-#define PTES_PER_PAGE_SHIFT 10
-#define PTES_PER_PAGE (1 << PTES_PER_PAGE_SHIFT)
/* 1024 entries in a page table page maps 1024 pages: 4MB. The Switcher is
* conveniently placed at the top 4MB, so it uses a separate, complete PTE
* page. */
-#define SWITCHER_PGD_INDEX (PTES_PER_PAGE - 1)
+#define SWITCHER_PGD_INDEX (PTRS_PER_PGD - 1)
/* We actually need a separate PTE page for each CPU. Remember that after the
* Switcher code itself comes two pages for each CPU, and we don't want this
* CPU's guest to see the pages of any other CPU. */
-static DEFINE_PER_CPU(spte_t *, switcher_pte_pages);
+static DEFINE_PER_CPU(pte_t *, switcher_pte_pages);
#define switcher_pte_page(cpu) per_cpu(switcher_pte_pages, cpu)
-/*H:320 With our shadow and Guest types established, we need to deal with
- * them: the page table code is curly enough to need helper functions to keep
- * it clear and clean.
+/*H:320 The page table code is curly enough to need helper functions to keep it
+ * clear and clean.
*
- * The first helper takes a virtual address, and says which entry in the top
- * level page table deals with that address. Since each top level entry deals
- * with 4M, this effectively divides by 4M. */
-static unsigned vaddr_to_pgd_index(unsigned long vaddr)
-{
- return vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT);
-}
-
-/* There are two functions which return pointers to the shadow (aka "real")
+ * There are two functions which return pointers to the shadow (aka "real")
* page tables.
*
* spgd_addr() takes the virtual address and returns a pointer to the top-level
- * page directory entry for that address. Since we keep track of several page
- * tables, the "i" argument tells us which one we're interested in (it's
+ * page directory entry (PGD) for that address. Since we keep track of several
+ * page tables, the "i" argument tells us which one we're interested in (it's
* usually the current one). */
-static spgd_t *spgd_addr(struct lguest *lg, u32 i, unsigned long vaddr)
+static pgd_t *spgd_addr(struct lguest *lg, u32 i, unsigned long vaddr)
{
- unsigned int index = vaddr_to_pgd_index(vaddr);
+ unsigned int index = pgd_index(vaddr);
/* We kill any Guest trying to touch the Switcher addresses. */
if (index >= SWITCHER_PGD_INDEX) {
@@ -92,31 +81,31 @@ static spgd_t *spgd_addr(struct lguest *lg, u32 i, unsigned long vaddr)
return &lg->pgdirs[i].pgdir[index];
}
-/* This routine then takes the PGD entry given above, which contains the
- * address of the PTE page. It then returns a pointer to the PTE entry for the
- * given address. */
-static spte_t *spte_addr(struct lguest *lg, spgd_t spgd, unsigned long vaddr)
+/* This routine then takes the page directory entry returned above, which
+ * contains the address of the page table entry (PTE) page. It then returns a
+ * pointer to the PTE entry for the given address. */
+static pte_t *spte_addr(struct lguest *lg, pgd_t spgd, unsigned long vaddr)
{
- spte_t *page = __va(spgd.pfn << PAGE_SHIFT);
+ pte_t *page = __va(pgd_pfn(spgd) << PAGE_SHIFT);
/* You should never call this if the PGD entry wasn't valid */
- BUG_ON(!(spgd.flags & _PAGE_PRESENT));
- return &page[(vaddr >> PAGE_SHIFT) % PTES_PER_PAGE];
+ BUG_ON(!(pgd_flags(spgd) & _PAGE_PRESENT));
+ return &page[(vaddr >> PAGE_SHIFT) % PTRS_PER_PTE];
}
/* These two functions just like the above two, except they access the Guest
* page tables. Hence they return a Guest address. */
static unsigned long gpgd_addr(struct lguest *lg, unsigned long vaddr)
{
- unsigned int index = vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT);
- return lg->pgdirs[lg->pgdidx].cr3 + index * sizeof(gpgd_t);
+ unsigned int index = vaddr >> (PGDIR_SHIFT);
+ return lg->pgdirs[lg->pgdidx].gpgdir + index * sizeof(pgd_t);
}
static unsigned long gpte_addr(struct lguest *lg,
- gpgd_t gpgd, unsigned long vaddr)
+ pgd_t gpgd, unsigned long vaddr)
{
- unsigned long gpage = gpgd.pfn << PAGE_SHIFT;
- BUG_ON(!(gpgd.flags & _PAGE_PRESENT));
- return gpage + ((vaddr>>PAGE_SHIFT) % PTES_PER_PAGE) * sizeof(gpte_t);
+ unsigned long gpage = pgd_pfn(gpgd) << PAGE_SHIFT;
+ BUG_ON(!(pgd_flags(gpgd) & _PAGE_PRESENT));
+ return gpage + ((vaddr>>PAGE_SHIFT) % PTRS_PER_PTE) * sizeof(pte_t);
}
/*H:350 This routine takes a page number given by the Guest and converts it to
@@ -149,58 +138,60 @@ static unsigned long get_pfn(unsigned long virtpfn, int write)
* entry can be a little tricky. The flags are (almost) the same, but the
* Guest PTE contains a virtual page number: the CPU needs the real page
* number. */
-static spte_t gpte_to_spte(struct lguest *lg, gpte_t gpte, int write)
+static pte_t gpte_to_spte(struct lguest *lg, pte_t gpte, int write)
{
- spte_t spte;
- unsigned long pfn;
+ unsigned long pfn, base, flags;
/* The Guest sets the global flag, because it thinks that it is using
* PGE. We only told it to use PGE so it would tell us whether it was
* flushing a kernel mapping or a userspace mapping. We don't actually
* use the global bit, so throw it away. */
- spte.flags = (gpte.flags & ~_PAGE_GLOBAL);
+ flags = (pte_flags(gpte) & ~_PAGE_GLOBAL);
+
+ /* The Guest's pages are offset inside the Launcher. */
+ base = (unsigned long)lg->mem_base / PAGE_SIZE;
/* We need a temporary "unsigned long" variable to hold the answer from
* get_pfn(), because it returns 0xFFFFFFFF on failure, which wouldn't
* fit in spte.pfn. get_pfn() finds the real physical number of the
* page, given the virtual number. */
- pfn = get_pfn(gpte.pfn, write);
+ pfn = get_pfn(base + pte_pfn(gpte), write);
if (pfn == -1UL) {
- kill_guest(lg, "failed to get page %u", gpte.pfn);
+ kill_guest(lg, "failed to get page %lu", pte_pfn(gpte));
/* When we destroy the Guest, we'll go through the shadow page
* tables and release_pte() them. Make sure we don't think
* this one is valid! */
- spte.flags = 0;
+ flags = 0;
}
- /* Now we assign the page number, and our shadow PTE is complete. */
- spte.pfn = pfn;
- return spte;
+ /* Now we assemble our shadow PTE from the page number and flags. */
+ return pfn_pte(pfn, __pgprot(flags));
}
/*H:460 And to complete the chain, release_pte() looks like this: */
-static void release_pte(spte_t pte)
+static void release_pte(pte_t pte)
{
/* Remember that get_user_pages() took a reference to the page, in
* get_pfn()? We have to put it back now. */
- if (pte.flags & _PAGE_PRESENT)
- put_page(pfn_to_page(pte.pfn));
+ if (pte_flags(pte) & _PAGE_PRESENT)
+ put_page(pfn_to_page(pte_pfn(pte)));
}
/*:*/
-static void check_gpte(struct lguest *lg, gpte_t gpte)
+static void check_gpte(struct lguest *lg, pte_t gpte)
{
- if ((gpte.flags & (_PAGE_PWT|_PAGE_PSE)) || gpte.pfn >= lg->pfn_limit)
+ if ((pte_flags(gpte) & (_PAGE_PWT|_PAGE_PSE))
+ || pte_pfn(gpte) >= lg->pfn_limit)
kill_guest(lg, "bad page table entry");
}
-static void check_gpgd(struct lguest *lg, gpgd_t gpgd)
+static void check_gpgd(struct lguest *lg, pgd_t gpgd)
{
- if ((gpgd.flags & ~_PAGE_TABLE) || gpgd.pfn >= lg->pfn_limit)
+ if ((pgd_flags(gpgd) & ~_PAGE_TABLE) || pgd_pfn(gpgd) >= lg->pfn_limit)
kill_guest(lg, "bad page directory entry");
}
/*H:330
- * (i) Setting up a page table entry for the Guest when it faults
+ * (i) Looking up a page table entry when the Guest faults.
*
* We saw this call in run_guest(): when we see a page fault in the Guest, we
* come here. That's because we only set up the shadow page tables lazily as
@@ -208,24 +199,24 @@ static void check_gpgd(struct lguest *lg, gpgd_t gpgd)
* and return to the Guest without it knowing.
*
* If we fixed up the fault (ie. we mapped the address), this routine returns
- * true. */
+ * true. Otherwise, it was a real fault and we need to tell the Guest. */
int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
{
- gpgd_t gpgd;
- spgd_t *spgd;
+ pgd_t gpgd;
+ pgd_t *spgd;
unsigned long gpte_ptr;
- gpte_t gpte;
- spte_t *spte;
+ pte_t gpte;
+ pte_t *spte;
/* First step: get the top-level Guest page table entry. */
- gpgd = mkgpgd(lgread_u32(lg, gpgd_addr(lg, vaddr)));
+ gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t);
/* Toplevel not present? We can't map it in. */
- if (!(gpgd.flags & _PAGE_PRESENT))
+ if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
return 0;
/* Now look at the matching shadow entry. */
spgd = spgd_addr(lg, lg->pgdidx, vaddr);
- if (!(spgd->flags & _PAGE_PRESENT)) {
+ if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) {
/* No shadow entry: allocate a new shadow PTE page. */
unsigned long ptepage = get_zeroed_page(GFP_KERNEL);
/* This is not really the Guest's fault, but killing it is
@@ -238,34 +229,35 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
check_gpgd(lg, gpgd);
/* And we copy the flags to the shadow PGD entry. The page
* number in the shadow PGD is the page we just allocated. */
- spgd->raw.val = (__pa(ptepage) | gpgd.flags);
+ *spgd = __pgd(__pa(ptepage) | pgd_flags(gpgd));
}
/* OK, now we look at the lower level in the Guest page table: keep its
* address, because we might update it later. */
gpte_ptr = gpte_addr(lg, gpgd, vaddr);
- gpte = mkgpte(lgread_u32(lg, gpte_ptr));
+ gpte = lgread(lg, gpte_ptr, pte_t);
/* If this page isn't in the Guest page tables, we can't page it in. */
- if (!(gpte.flags & _PAGE_PRESENT))
+ if (!(pte_flags(gpte) & _PAGE_PRESENT))
return 0;
/* Check they're not trying to write to a page the Guest wants
* read-only (bit 2 of errcode == write). */
- if ((errcode & 2) && !(gpte.flags & _PAGE_RW))
+ if ((errcode & 2) && !(pte_flags(gpte) & _PAGE_RW))
return 0;
- /* User access to a kernel page? (bit 3 == user access) */
- if ((errcode & 4) && !(gpte.flags & _PAGE_USER))
+ /* User access to a kernel-only page? (bit 3 == user access) */
+ if ((errcode & 4) && !(pte_flags(gpte) & _PAGE_USER))
return 0;
/* Check that the Guest PTE flags are OK, and the page number is below
* the pfn_limit (ie. not mapping the Launcher binary). */
check_gpte(lg, gpte);
+
/* Add the _PAGE_ACCESSED and (for a write) _PAGE_DIRTY flag */
- gpte.flags |= _PAGE_ACCESSED;
+ gpte = pte_mkyoung(gpte);
if (errcode & 2)
- gpte.flags |= _PAGE_DIRTY;
+ gpte = pte_mkdirty(gpte);
/* Get the pointer to the shadow PTE entry we're going to set. */
spte = spte_addr(lg, *spgd, vaddr);
@@ -275,47 +267,50 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
/* If this is a write, we insist that the Guest page is writable (the
* final arg to gpte_to_spte()). */
- if (gpte.flags & _PAGE_DIRTY)
+ if (pte_dirty(gpte))
*spte = gpte_to_spte(lg, gpte, 1);
- else {
+ else
/* If this is a read, don't set the "writable" bit in the page
* table entry, even if the Guest says it's writable. That way
- * we come back here when a write does actually ocur, so we can
- * update the Guest's _PAGE_DIRTY flag. */
- gpte_t ro_gpte = gpte;
- ro_gpte.flags &= ~_PAGE_RW;
- *spte = gpte_to_spte(lg, ro_gpte, 0);
- }
+ * we will come back here when a write does actually occur, so
+ * we can update the Guest's _PAGE_DIRTY flag. */
+ *spte = gpte_to_spte(lg, pte_wrprotect(gpte), 0);
/* Finally, we write the Guest PTE entry back: we've set the
* _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */
- lgwrite_u32(lg, gpte_ptr, gpte.raw.val);
+ lgwrite(lg, gpte_ptr, pte_t, gpte);
- /* We succeeded in mapping the page! */
+ /* The fault is fixed, the page table is populated, the mapping
+ * manipulated, the result returned and the code complete. A small
+ * delay and a trace of alliteration are the only indications the Guest
+ * has that a page fault occurred at all. */
return 1;
}
-/*H:360 (ii) Setting up the page table entry for the Guest stack.
+/*H:360
+ * (ii) Making sure the Guest stack is mapped.
*
- * Remember pin_stack_pages() which makes sure the stack is mapped? It could
- * simply call demand_page(), but as we've seen that logic is quite long, and
- * usually the stack pages are already mapped anyway, so it's not required.
+ * Remember that direct traps into the Guest need a mapped Guest kernel stack.
+ * pin_stack_pages() calls us here: we could simply call demand_page(), but as
+ * we've seen that logic is quite long, and usually the stack pages are already
+ * mapped, so it's overkill.
*
* This is a quick version which answers the question: is this virtual address
* mapped by the shadow page tables, and is it writable? */
static int page_writable(struct lguest *lg, unsigned long vaddr)
{
- spgd_t *spgd;
+ pgd_t *spgd;
unsigned long flags;
- /* Look at the top level entry: is it present? */
+ /* Look at the current top level entry: is it present? */
spgd = spgd_addr(lg, lg->pgdidx, vaddr);
- if (!(spgd->flags & _PAGE_PRESENT))
+ if (!(pgd_flags(*spgd) & _PAGE_PRESENT))
return 0;
/* Check the flags on the pte entry itself: it must be present and
* writable. */
- flags = spte_addr(lg, *spgd, vaddr)->flags;
+ flags = pte_flags(*(spte_addr(lg, *spgd, vaddr)));
+
return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW);
}
@@ -329,39 +324,40 @@ void pin_page(struct lguest *lg, unsigned long vaddr)
}
/*H:450 If we chase down the release_pgd() code, it looks like this: */
-static void release_pgd(struct lguest *lg, spgd_t *spgd)
+static void release_pgd(struct lguest *lg, pgd_t *spgd)
{
/* If the entry's not present, there's nothing to release. */
- if (spgd->flags & _PAGE_PRESENT) {
+ if (pgd_flags(*spgd) & _PAGE_PRESENT) {
unsigned int i;
/* Converting the pfn to find the actual PTE page is easy: turn
* the page number into a physical address, then convert to a
* virtual address (easy for kernel pages like this one). */
- spte_t *ptepage = __va(spgd->pfn << PAGE_SHIFT);
+ pte_t *ptepage = __va(pgd_pfn(*spgd) << PAGE_SHIFT);
/* For each entry in the page, we might need to release it. */
- for (i = 0; i < PTES_PER_PAGE; i++)
+ for (i = 0; i < PTRS_PER_PTE; i++)
release_pte(ptepage[i]);
/* Now we can free the page of PTEs */
free_page((long)ptepage);
- /* And zero out the PGD entry we we never release it twice. */
- spgd->raw.val = 0;
+ /* And zero out the PGD entry so we never release it twice. */
+ *spgd = __pgd(0);
}
}
-/*H:440 (v) Flushing (thowing away) page tables,
- *
- * We saw flush_user_mappings() called when we re-used a top-level pgdir page.
- * It simply releases every PTE page from 0 up to the kernel address. */
+/*H:445 We saw flush_user_mappings() twice: once from the flush_user_mappings()
+ * hypercall and once in new_pgdir() when we re-used a top-level pgdir page.
+ * It simply releases every PTE page from 0 up to the Guest's kernel address. */
static void flush_user_mappings(struct lguest *lg, int idx)
{
unsigned int i;
/* Release every pgd entry up to the kernel's address. */
- for (i = 0; i < vaddr_to_pgd_index(lg->page_offset); i++)
+ for (i = 0; i < pgd_index(lg->kernel_address); i++)
release_pgd(lg, lg->pgdirs[idx].pgdir + i);
}
-/* The Guest also has a hypercall to do this manually: it's used when a large
- * number of mappings have been changed. */
+/*H:440 (v) Flushing (throwing away) page tables,
+ *
+ * The Guest has a hypercall to throw away the page tables: it's used when a
+ * large number of mappings have been changed. */
void guest_pagetable_flush_user(struct lguest *lg)
{
/* Drop the userspace part of the current page table. */
@@ -369,6 +365,25 @@ void guest_pagetable_flush_user(struct lguest *lg)
}
/*:*/
+/* We walk down the guest page tables to get a guest-physical address */
+unsigned long guest_pa(struct lguest *lg, unsigned long vaddr)
+{
+ pgd_t gpgd;
+ pte_t gpte;
+
+ /* First step: get the top-level Guest page table entry. */
+ gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t);
+ /* Toplevel not present? We can't map it in. */
+ if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
+ kill_guest(lg, "Bad address %#lx", vaddr);
+
+ gpte = lgread(lg, gpte_addr(lg, gpgd, vaddr), pte_t);
+ if (!(pte_flags(gpte) & _PAGE_PRESENT))
+ kill_guest(lg, "Bad address %#lx", vaddr);
+
+ return pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK);
+}
+
/* We keep several page tables. This is a simple routine to find the page
* table (if any) corresponding to this top-level address the Guest has given
* us. */
@@ -376,7 +391,7 @@ static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
- if (lg->pgdirs[i].cr3 == pgtable)
+ if (lg->pgdirs[i].gpgdir == pgtable)
break;
return i;
}
@@ -385,7 +400,7 @@ static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable)
* allocate a new one (and so the kernel parts are not there), we set
* blank_pgdir. */
static unsigned int new_pgdir(struct lguest *lg,
- unsigned long cr3,
+ unsigned long gpgdir,
int *blank_pgdir)
{
unsigned int next;
@@ -395,7 +410,7 @@ static unsigned int new_pgdir(struct lguest *lg,
next = random32() % ARRAY_SIZE(lg->pgdirs);
/* If it's never been allocated at all before, try now. */
if (!lg->pgdirs[next].pgdir) {
- lg->pgdirs[next].pgdir = (spgd_t *)get_zeroed_page(GFP_KERNEL);
+ lg->pgdirs[next].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL);
/* If the allocation fails, just keep using the one we have */
if (!lg->pgdirs[next].pgdir)
next = lg->pgdidx;
@@ -405,7 +420,7 @@ static unsigned int new_pgdir(struct lguest *lg,
*blank_pgdir = 1;
}
/* Record which Guest toplevel this shadows. */
- lg->pgdirs[next].cr3 = cr3;
+ lg->pgdirs[next].gpgdir = gpgdir;
/* Release all the non-kernel mappings. */
flush_user_mappings(lg, next);
@@ -414,8 +429,9 @@ static unsigned int new_pgdir(struct lguest *lg,
/*H:430 (iv) Switching page tables
*
- * This is what happens when the Guest changes page tables (ie. changes the
- * top-level pgdir). This happens on almost every context switch. */
+ * Now we've seen all the page table setting and manipulation, let's see what
+ * what happens when the Guest changes page tables (ie. changes the top-level
+ * pgdir). This occurs on almost every context switch. */
void guest_new_pagetable(struct lguest *lg, unsigned long pgtable)
{
int newpgdir, repin = 0;
@@ -434,7 +450,8 @@ void guest_new_pagetable(struct lguest *lg, unsigned long pgtable)
}
/*H:470 Finally, a routine which throws away everything: all PGD entries in all
- * the shadow page tables. This is used when we destroy the Guest. */
+ * the shadow page tables, including the Guest's kernel mappings. This is used
+ * when we destroy the Guest. */
static void release_all_pagetables(struct lguest *lg)
{
unsigned int i, j;
@@ -449,13 +466,22 @@ static void release_all_pagetables(struct lguest *lg)
/* We also throw away everything when a Guest tells us it's changed a kernel
* mapping. Since kernel mappings are in every page table, it's easiest to
- * throw them all away. This is amazingly slow, but thankfully rare. */
+ * throw them all away. This traps the Guest in amber for a while as
+ * everything faults back in, but it's rare. */
void guest_pagetable_clear_all(struct lguest *lg)
{
release_all_pagetables(lg);
/* We need the Guest kernel stack mapped again. */
pin_stack_pages(lg);
}
+/*:*/
+/*M:009 Since we throw away all mappings when a kernel mapping changes, our
+ * performance sucks for guests using highmem. In fact, a guest with
+ * PAGE_OFFSET 0xc0000000 (the default) and more than about 700MB of RAM is
+ * usually slower than a Guest with less memory.
+ *
+ * This, of course, cannot be fixed. It would take some kind of... well, I
+ * don't know, but the term "puissant code-fu" comes to mind. :*/
/*H:420 This is the routine which actually sets the page table entry for then
* "idx"'th shadow page table.
@@ -472,26 +498,28 @@ void guest_pagetable_clear_all(struct lguest *lg)
* they set _PAGE_DIRTY then we can put a writable PTE entry in immediately.
*/
static void do_set_pte(struct lguest *lg, int idx,
- unsigned long vaddr, gpte_t gpte)
+ unsigned long vaddr, pte_t gpte)
{
- /* Look up the matching shadow page directot entry. */
- spgd_t *spgd = spgd_addr(lg, idx, vaddr);
+ /* Look up the matching shadow page directory entry. */
+ pgd_t *spgd = spgd_addr(lg, idx, vaddr);
/* If the top level isn't present, there's no entry to update. */
- if (spgd->flags & _PAGE_PRESENT) {
+ if (pgd_flags(*spgd) & _PAGE_PRESENT) {
/* Otherwise, we start by releasing the existing entry. */
- spte_t *spte = spte_addr(lg, *spgd, vaddr);
+ pte_t *spte = spte_addr(lg, *spgd, vaddr);
release_pte(*spte);
/* If they're setting this entry as dirty or accessed, we might
* as well put that entry they've given us in now. This shaves
* 10% off a copy-on-write micro-benchmark. */
- if (gpte.flags & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
+ if (pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
check_gpte(lg, gpte);
- *spte = gpte_to_spte(lg, gpte, gpte.flags&_PAGE_DIRTY);
+ *spte = gpte_to_spte(lg, gpte,
+ pte_flags(gpte) & _PAGE_DIRTY);
} else
- /* Otherwise we can demand_page() it in later. */
- spte->raw.val = 0;
+ /* Otherwise kill it and we can demand_page() it in
+ * later. */
+ *spte = __pte(0);
}
}
@@ -506,18 +534,18 @@ static void do_set_pte(struct lguest *lg, int idx,
* The benefit is that when we have to track a new page table, we can copy keep
* all the kernel mappings. This speeds up context switch immensely. */
void guest_set_pte(struct lguest *lg,
- unsigned long cr3, unsigned long vaddr, gpte_t gpte)
+ unsigned long gpgdir, unsigned long vaddr, pte_t gpte)
{
/* Kernel mappings must be changed on all top levels. Slow, but
* doesn't happen often. */
- if (vaddr >= lg->page_offset) {
+ if (vaddr >= lg->kernel_address) {
unsigned int i;
for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
if (lg->pgdirs[i].pgdir)
do_set_pte(lg, i, vaddr, gpte);
} else {
/* Is this page table one we have a shadow for? */
- int pgdir = find_pgdir(lg, cr3);
+ int pgdir = find_pgdir(lg, gpgdir);
if (pgdir != ARRAY_SIZE(lg->pgdirs))
/* If so, do the update. */
do_set_pte(lg, pgdir, vaddr, gpte);
@@ -525,7 +553,7 @@ void guest_set_pte(struct lguest *lg,
}
/*H:400
- * (iii) Setting up a page table entry when the Guest tells us it has changed.
+ * (iii) Setting up a page table entry when the Guest tells us one has changed.
*
* Just like we did in interrupts_and_traps.c, it makes sense for us to deal
* with the other side of page tables while we're here: what happens when the
@@ -538,7 +566,7 @@ void guest_set_pte(struct lguest *lg,
*
* So with that in mind here's our code to to update a (top-level) PGD entry:
*/
-void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 idx)
+void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 idx)
{
int pgdir;
@@ -548,7 +576,7 @@ void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 idx)
return;
/* If they're talking about a page table we have a shadow for... */
- pgdir = find_pgdir(lg, cr3);
+ pgdir = find_pgdir(lg, gpgdir);
if (pgdir < ARRAY_SIZE(lg->pgdirs))
/* ... throw it away. */
release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx);
@@ -560,21 +588,34 @@ void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 idx)
* its first page table is. We set some things up here: */
int init_guest_pagetable(struct lguest *lg, unsigned long pgtable)
{
- /* In flush_user_mappings() we loop from 0 to
- * "vaddr_to_pgd_index(lg->page_offset)". This assumes it won't hit
- * the Switcher mappings, so check that now. */
- if (vaddr_to_pgd_index(lg->page_offset) >= SWITCHER_PGD_INDEX)
- return -EINVAL;
/* We start on the first shadow page table, and give it a blank PGD
* page. */
lg->pgdidx = 0;
- lg->pgdirs[lg->pgdidx].cr3 = pgtable;
- lg->pgdirs[lg->pgdidx].pgdir = (spgd_t*)get_zeroed_page(GFP_KERNEL);
+ lg->pgdirs[lg->pgdidx].gpgdir = pgtable;
+ lg->pgdirs[lg->pgdidx].pgdir = (pgd_t*)get_zeroed_page(GFP_KERNEL);
if (!lg->pgdirs[lg->pgdidx].pgdir)
return -ENOMEM;
return 0;
}
+/* When the Guest calls LHCALL_LGUEST_INIT we do more setup. */
+void page_table_guest_data_init(struct lguest *lg)
+{
+ /* We get the kernel address: above this is all kernel memory. */
+ if (get_user(lg->kernel_address, &lg->lguest_data->kernel_address)
+ /* We tell the Guest that it can't use the top 4MB of virtual
+ * addresses used by the Switcher. */
+ || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem)
+ || put_user(lg->pgdirs[lg->pgdidx].gpgdir,&lg->lguest_data->pgdir))
+ kill_guest(lg, "bad guest page %p", lg->lguest_data);
+
+ /* In flush_user_mappings() we loop from 0 to
+ * "pgd_index(lg->kernel_address)". This assumes it won't hit the
+ * Switcher mappings, so check that now. */
+ if (pgd_index(lg->kernel_address) >= SWITCHER_PGD_INDEX)
+ kill_guest(lg, "bad kernel address %#lx", lg->kernel_address);
+}
+
/* When a Guest dies, our cleanup is fairly simple. */
void free_guest_pagetable(struct lguest *lg)
{
@@ -589,19 +630,20 @@ void free_guest_pagetable(struct lguest *lg)
/*H:480 (vi) Mapping the Switcher when the Guest is about to run.
*
- * The Switcher and the two pages for this CPU need to be available to the
+ * The Switcher and the two pages for this CPU need to be visible in the
* Guest (and not the pages for other CPUs). We have the appropriate PTE pages
- * for each CPU already set up, we just need to hook them in. */
+ * for each CPU already set up, we just need to hook them in now we know which
+ * Guest is about to run on this CPU. */
void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages)
{
- spte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
- spgd_t switcher_pgd;
- spte_t regs_pte;
+ pte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
+ pgd_t switcher_pgd;
+ pte_t regs_pte;
/* Make the last PGD entry for this Guest point to the Switcher's PTE
* page for this CPU (with appropriate flags). */
- switcher_pgd.pfn = __pa(switcher_pte_page) >> PAGE_SHIFT;
- switcher_pgd.flags = _PAGE_KERNEL;
+ switcher_pgd = __pgd(__pa(switcher_pte_page) | _PAGE_KERNEL);
+
lg->pgdirs[lg->pgdidx].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd;
/* We also change the Switcher PTE page. When we're running the Guest,
@@ -611,10 +653,8 @@ void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages)
* CPU's "struct lguest_pages": if we make sure the Guest's register
* page is already mapped there, we don't have to copy them out
* again. */
- regs_pte.pfn = __pa(lg->regs_page) >> PAGE_SHIFT;
- regs_pte.flags = _PAGE_KERNEL;
- switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTES_PER_PAGE]
- = regs_pte;
+ regs_pte = pfn_pte (__pa(lg->regs_page) >> PAGE_SHIFT, __pgprot(_PAGE_KERNEL));
+ switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTRS_PER_PTE] = regs_pte;
}
/*:*/
@@ -635,26 +675,39 @@ static __init void populate_switcher_pte_page(unsigned int cpu,
unsigned int pages)
{
unsigned int i;
- spte_t *pte = switcher_pte_page(cpu);
+ pte_t *pte = switcher_pte_page(cpu);
/* The first entries are easy: they map the Switcher code. */
for (i = 0; i < pages; i++) {
- pte[i].pfn = page_to_pfn(switcher_page[i]);
- pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED;
+ pte[i] = mk_pte(switcher_page[i],
+ __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED));
}
/* The only other thing we map is this CPU's pair of pages. */
i = pages + cpu*2;
/* First page (Guest registers) is writable from the Guest */
- pte[i].pfn = page_to_pfn(switcher_page[i]);
- pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW;
+ pte[i] = pfn_pte(page_to_pfn(switcher_page[i]),
+ __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW));
+
/* The second page contains the "struct lguest_ro_state", and is
* read-only. */
- pte[i+1].pfn = page_to_pfn(switcher_page[i+1]);
- pte[i+1].flags = _PAGE_PRESENT|_PAGE_ACCESSED;
+ pte[i+1] = pfn_pte(page_to_pfn(switcher_page[i+1]),
+ __pgprot(_PAGE_PRESENT|_PAGE_ACCESSED));
}
+/* We've made it through the page table code. Perhaps our tired brains are
+ * still processing the details, or perhaps we're simply glad it's over.
+ *
+ * If nothing else, note that all this complexity in juggling shadow page
+ * tables in sync with the Guest's page tables is for one reason: for most
+ * Guests this page table dance determines how bad performance will be. This
+ * is why Xen uses exotic direct Guest pagetable manipulation, and why both
+ * Intel and AMD have implemented shadow page table support directly into
+ * hardware.
+ *
+ * There is just one file remaining in the Host. */
+
/*H:510 At boot or module load time, init_pagetables() allocates and populates
* the Switcher PTE page for each CPU. */
__init int init_pagetables(struct page **switcher_page, unsigned int pages)
@@ -662,7 +715,7 @@ __init int init_pagetables(struct page **switcher_page, unsigned int pages)
unsigned int i;
for_each_possible_cpu(i) {
- switcher_pte_page(i) = (spte_t *)get_zeroed_page(GFP_KERNEL);
+ switcher_pte_page(i) = (pte_t *)get_zeroed_page(GFP_KERNEL);
if (!switcher_pte_page(i)) {
free_switcher_pte_pages();
return -ENOMEM;
diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c
index 9b81119f46e..9e189cbec7d 100644
--- a/drivers/lguest/segments.c
+++ b/drivers/lguest/segments.c
@@ -12,8 +12,6 @@
#include "lg.h"
/*H:600
- * We've almost completed the Host; there's just one file to go!
- *
* Segments & The Global Descriptor Table
*
* (That title sounds like a bad Nerdcore group. Not to suggest that there are
@@ -55,7 +53,7 @@ static int ignored_gdt(unsigned int num)
|| num == GDT_ENTRY_DOUBLEFAULT_TSS);
}
-/*H:610 Once the GDT has been changed, we fix the new entries up a little. We
+/*H:630 Once the Guest gave us new GDT entries, we fix them up a little. We
* don't care if they're invalid: the worst that can happen is a General
* Protection Fault in the Switcher when it restores a Guest segment register
* which tries to use that entry. Then we kill the Guest for causing such a
@@ -73,63 +71,68 @@ static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end)
/* Segment descriptors contain a privilege level: the Guest is
* sometimes careless and leaves this as 0, even though it's
* running at privilege level 1. If so, we fix it here. */
- if ((lg->gdt[i].b & 0x00006000) == 0)
- lg->gdt[i].b |= (GUEST_PL << 13);
+ if ((lg->arch.gdt[i].b & 0x00006000) == 0)
+ lg->arch.gdt[i].b |= (GUEST_PL << 13);
/* Each descriptor has an "accessed" bit. If we don't set it
* now, the CPU will try to set it when the Guest first loads
* that entry into a segment register. But the GDT isn't
* writable by the Guest, so bad things can happen. */
- lg->gdt[i].b |= 0x00000100;
+ lg->arch.gdt[i].b |= 0x00000100;
}
}
-/* This routine is called at boot or modprobe time for each CPU to set up the
- * "constant" GDT entries for Guests running on that CPU. */
+/*H:610 Like the IDT, we never simply use the GDT the Guest gives us. We keep
+ * a GDT for each CPU, and copy across the Guest's entries each time we want to
+ * run the Guest on that CPU.
+ *
+ * This routine is called at boot or modprobe time for each CPU to set up the
+ * constant GDT entries: the ones which are the same no matter what Guest we're
+ * running. */
void setup_default_gdt_entries(struct lguest_ro_state *state)
{
struct desc_struct *gdt = state->guest_gdt;
unsigned long tss = (unsigned long)&state->guest_tss;
- /* The hypervisor segments are full 0-4G segments, privilege level 0 */
+ /* The Switcher segments are full 0-4G segments, privilege level 0 */
gdt[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
gdt[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
- /* The TSS segment refers to the TSS entry for this CPU, so we cannot
- * copy it from the Guest. Forgive the magic flags */
+ /* The TSS segment refers to the TSS entry for this particular CPU.
+ * Forgive the magic flags: the 0x8900 means the entry is Present, it's
+ * privilege level 0 Available 386 TSS system segment, and the 0x67
+ * means Saturn is eclipsed by Mercury in the twelfth house. */
gdt[GDT_ENTRY_TSS].a = 0x00000067 | (tss << 16);
gdt[GDT_ENTRY_TSS].b = 0x00008900 | (tss & 0xFF000000)
| ((tss >> 16) & 0x000000FF);
}
-/* This routine is called before the Guest is run for the first time. */
+/* This routine sets up the initial Guest GDT for booting. All entries start
+ * as 0 (unusable). */
void setup_guest_gdt(struct lguest *lg)
{
/* Start with full 0-4G segments... */
- lg->gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
- lg->gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
+ lg->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
+ lg->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
/* ...except the Guest is allowed to use them, so set the privilege
* level appropriately in the flags. */
- lg->gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13);
- lg->gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
+ lg->arch.gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13);
+ lg->arch.gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
}
-/* Like the IDT, we never simply use the GDT the Guest gives us. We set up the
- * GDTs for each CPU, then we copy across the entries each time we want to run
- * a different Guest on that CPU. */
-
-/* A partial GDT load, for the three "thead-local storage" entries. Otherwise
- * it's just like load_guest_gdt(). So much, in fact, it would probably be
- * neater to have a single hypercall to cover both. */
+/*H:650 An optimization of copy_gdt(), for just the three "thead-local storage"
+ * entries. */
void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt)
{
unsigned int i;
for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++)
- gdt[i] = lg->gdt[i];
+ gdt[i] = lg->arch.gdt[i];
}
-/* This is the full version */
+/*H:640 When the Guest is run on a different CPU, or the GDT entries have
+ * changed, copy_gdt() is called to copy the Guest's GDT entries across to this
+ * CPU's GDT. */
void copy_gdt(const struct lguest *lg, struct desc_struct *gdt)
{
unsigned int i;
@@ -138,35 +141,42 @@ void copy_gdt(const struct lguest *lg, struct desc_struct *gdt)
* replaced. See ignored_gdt() above. */
for (i = 0; i < GDT_ENTRIES; i++)
if (!ignored_gdt(i))
- gdt[i] = lg->gdt[i];
+ gdt[i] = lg->arch.gdt[i];
}
-/* This is where the Guest asks us to load a new GDT (LHCALL_LOAD_GDT). */
+/*H:620 This is where the Guest asks us to load a new GDT (LHCALL_LOAD_GDT).
+ * We copy it from the Guest and tweak the entries. */
void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num)
{
/* We assume the Guest has the same number of GDT entries as the
* Host, otherwise we'd have to dynamically allocate the Guest GDT. */
- if (num > ARRAY_SIZE(lg->gdt))
+ if (num > ARRAY_SIZE(lg->arch.gdt))
kill_guest(lg, "too many gdt entries %i", num);
/* We read the whole thing in, then fix it up. */
- lgread(lg, lg->gdt, table, num * sizeof(lg->gdt[0]));
- fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->gdt));
+ __lgread(lg, lg->arch.gdt, table, num * sizeof(lg->arch.gdt[0]));
+ fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->arch.gdt));
/* Mark that the GDT changed so the core knows it has to copy it again,
* even if the Guest is run on the same CPU. */
lg->changed |= CHANGED_GDT;
}
+/* This is the fast-track version for just changing the three TLS entries.
+ * Remember that this happens on every context switch, so it's worth
+ * optimizing. But wouldn't it be neater to have a single hypercall to cover
+ * both cases? */
void guest_load_tls(struct lguest *lg, unsigned long gtls)
{
- struct desc_struct *tls = &lg->gdt[GDT_ENTRY_TLS_MIN];
+ struct desc_struct *tls = &lg->arch.gdt[GDT_ENTRY_TLS_MIN];
- lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES);
+ __lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES);
fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1);
+ /* Note that just the TLS entries have changed. */
lg->changed |= CHANGED_GDT_TLS;
}
+/*:*/
-/*
+/*H:660
* With this, we have finished the Host.
*
* Five of the seven parts of our task are complete. You have made it through
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
new file mode 100644
index 00000000000..482aec2a963
--- /dev/null
+++ b/drivers/lguest/x86/core.c
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C) 2006, Rusty Russell <rusty@rustcorp.com.au> IBM Corporation.
+ * Copyright (C) 2007, Jes Sorensen <jes@sgi.com> SGI.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/start_kernel.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <linux/screen_info.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/cpu.h>
+#include <linux/lguest.h>
+#include <linux/lguest_launcher.h>
+#include <asm/paravirt.h>
+#include <asm/param.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/desc.h>
+#include <asm/setup.h>
+#include <asm/lguest.h>
+#include <asm/uaccess.h>
+#include <asm/i387.h>
+#include "../lg.h"
+
+static int cpu_had_pge;
+
+static struct {
+ unsigned long offset;
+ unsigned short segment;
+} lguest_entry;
+
+/* Offset from where switcher.S was compiled to where we've copied it */
+static unsigned long switcher_offset(void)
+{
+ return SWITCHER_ADDR - (unsigned long)start_switcher_text;
+}
+
+/* This cpu's struct lguest_pages. */
+static struct lguest_pages *lguest_pages(unsigned int cpu)
+{
+ return &(((struct lguest_pages *)
+ (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]);
+}
+
+static DEFINE_PER_CPU(struct lguest *, last_guest);
+
+/*S:010
+ * We approach the Switcher.
+ *
+ * Remember that each CPU has two pages which are visible to the Guest when it
+ * runs on that CPU. This has to contain the state for that Guest: we copy the
+ * state in just before we run the Guest.
+ *
+ * Each Guest has "changed" flags which indicate what has changed in the Guest
+ * since it last ran. We saw this set in interrupts_and_traps.c and
+ * segments.c.
+ */
+static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
+{
+ /* Copying all this data can be quite expensive. We usually run the
+ * same Guest we ran last time (and that Guest hasn't run anywhere else
+ * meanwhile). If that's not the case, we pretend everything in the
+ * Guest has changed. */
+ if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) {
+ __get_cpu_var(last_guest) = lg;
+ lg->last_pages = pages;
+ lg->changed = CHANGED_ALL;
+ }
+
+ /* These copies are pretty cheap, so we do them unconditionally: */
+ /* Save the current Host top-level page directory. */
+ pages->state.host_cr3 = __pa(current->mm->pgd);
+ /* Set up the Guest's page tables to see this CPU's pages (and no
+ * other CPU's pages). */
+ map_switcher_in_guest(lg, pages);
+ /* Set up the two "TSS" members which tell the CPU what stack to use
+ * for traps which do directly into the Guest (ie. traps at privilege
+ * level 1). */
+ pages->state.guest_tss.esp1 = lg->esp1;
+ pages->state.guest_tss.ss1 = lg->ss1;
+
+ /* Copy direct-to-Guest trap entries. */
+ if (lg->changed & CHANGED_IDT)
+ copy_traps(lg, pages->state.guest_idt, default_idt_entries);
+
+ /* Copy all GDT entries which the Guest can change. */
+ if (lg->changed & CHANGED_GDT)
+ copy_gdt(lg, pages->state.guest_gdt);
+ /* If only the TLS entries have changed, copy them. */
+ else if (lg->changed & CHANGED_GDT_TLS)
+ copy_gdt_tls(lg, pages->state.guest_gdt);
+
+ /* Mark the Guest as unchanged for next time. */
+ lg->changed = 0;
+}
+
+/* Finally: the code to actually call into the Switcher to run the Guest. */
+static void run_guest_once(struct lguest *lg, struct lguest_pages *pages)
+{
+ /* This is a dummy value we need for GCC's sake. */
+ unsigned int clobber;
+
+ /* Copy the guest-specific information into this CPU's "struct
+ * lguest_pages". */
+ copy_in_guest_info(lg, pages);
+
+ /* Set the trap number to 256 (impossible value). If we fault while
+ * switching to the Guest (bad segment registers or bug), this will
+ * cause us to abort the Guest. */
+ lg->regs->trapnum = 256;
+
+ /* Now: we push the "eflags" register on the stack, then do an "lcall".
+ * This is how we change from using the kernel code segment to using
+ * the dedicated lguest code segment, as well as jumping into the
+ * Switcher.
+ *
+ * The lcall also pushes the old code segment (KERNEL_CS) onto the
+ * stack, then the address of this call. This stack layout happens to
+ * exactly match the stack layout created by an interrupt... */
+ asm volatile("pushf; lcall *lguest_entry"
+ /* This is how we tell GCC that %eax ("a") and %ebx ("b")
+ * are changed by this routine. The "=" means output. */
+ : "=a"(clobber), "=b"(clobber)
+ /* %eax contains the pages pointer. ("0" refers to the
+ * 0-th argument above, ie "a"). %ebx contains the
+ * physical address of the Guest's top-level page
+ * directory. */
+ : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir))
+ /* We tell gcc that all these registers could change,
+ * which means we don't have to save and restore them in
+ * the Switcher. */
+ : "memory", "%edx", "%ecx", "%edi", "%esi");
+}
+/*:*/
+
+/*M:002 There are hooks in the scheduler which we can register to tell when we
+ * get kicked off the CPU (preempt_notifier_register()). This would allow us
+ * to lazily disable SYSENTER which would regain some performance, and should
+ * also simplify copy_in_guest_info(). Note that we'd still need to restore
+ * things when we exit to Launcher userspace, but that's fairly easy.
+ *
+ * The hooks were designed for KVM, but we can also put them to good use. :*/
+
+/*H:040 This is the i386-specific code to setup and run the Guest. Interrupts
+ * are disabled: we own the CPU. */
+void lguest_arch_run_guest(struct lguest *lg)
+{
+ /* Remember the awfully-named TS bit? If the Guest has asked to set it
+ * we set it now, so we can trap and pass that trap to the Guest if it
+ * uses the FPU. */
+ if (lg->ts)
+ lguest_set_ts();
+
+ /* SYSENTER is an optimized way of doing system calls. We can't allow
+ * it because it always jumps to privilege level 0. A normal Guest
+ * won't try it because we don't advertise it in CPUID, but a malicious
+ * Guest (or malicious Guest userspace program) could, so we tell the
+ * CPU to disable it before running the Guest. */
+ if (boot_cpu_has(X86_FEATURE_SEP))
+ wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
+
+ /* Now we actually run the Guest. It will return when something
+ * interesting happens, and we can examine its registers to see what it
+ * was doing. */
+ run_guest_once(lg, lguest_pages(raw_smp_processor_id()));
+
+ /* Note that the "regs" pointer contains two extra entries which are
+ * not really registers: a trap number which says what interrupt or
+ * trap made the switcher code come back, and an error code which some
+ * traps set. */
+
+ /* If the Guest page faulted, then the cr2 register will tell us the
+ * bad virtual address. We have to grab this now, because once we
+ * re-enable interrupts an interrupt could fault and thus overwrite
+ * cr2, or we could even move off to a different CPU. */
+ if (lg->regs->trapnum == 14)
+ lg->arch.last_pagefault = read_cr2();
+ /* Similarly, if we took a trap because the Guest used the FPU,
+ * we have to restore the FPU it expects to see. */
+ else if (lg->regs->trapnum == 7)
+ math_state_restore();
+
+ /* Restore SYSENTER if it's supposed to be on. */
+ if (boot_cpu_has(X86_FEATURE_SEP))
+ wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
+}
+
+/*H:130 Now we've examined the hypercall code; our Guest can make requests.
+ * Our Guest is usually so well behaved; it never tries to do things it isn't
+ * allowed to, and uses hypercalls instead. Unfortunately, Linux's paravirtual
+ * infrastructure isn't quite complete, because it doesn't contain replacements
+ * for the Intel I/O instructions. As a result, the Guest sometimes fumbles
+ * across one during the boot process as it probes for various things which are
+ * usually attached to a PC.
+ *
+ * When the Guest uses one of these instructions, we get a trap (General
+ * Protection Fault) and come here. We see if it's one of those troublesome
+ * instructions and skip over it. We return true if we did. */
+static int emulate_insn(struct lguest *lg)
+{
+ u8 insn;
+ unsigned int insnlen = 0, in = 0, shift = 0;
+ /* The eip contains the *virtual* address of the Guest's instruction:
+ * guest_pa just subtracts the Guest's page_offset. */
+ unsigned long physaddr = guest_pa(lg, lg->regs->eip);
+
+ /* This must be the Guest kernel trying to do something, not userspace!
+ * The bottom two bits of the CS segment register are the privilege
+ * level. */
+ if ((lg->regs->cs & 3) != GUEST_PL)
+ return 0;
+
+ /* Decoding x86 instructions is icky. */
+ insn = lgread(lg, physaddr, u8);
+
+ /* 0x66 is an "operand prefix". It means it's using the upper 16 bits
+ of the eax register. */
+ if (insn == 0x66) {
+ shift = 16;
+ /* The instruction is 1 byte so far, read the next byte. */
+ insnlen = 1;
+ insn = lgread(lg, physaddr + insnlen, u8);
+ }
+
+ /* We can ignore the lower bit for the moment and decode the 4 opcodes
+ * we need to emulate. */
+ switch (insn & 0xFE) {
+ case 0xE4: /* in <next byte>,%al */
+ insnlen += 2;
+ in = 1;
+ break;
+ case 0xEC: /* in (%dx),%al */
+ insnlen += 1;
+ in = 1;
+ break;
+ case 0xE6: /* out %al,<next byte> */
+ insnlen += 2;
+ break;
+ case 0xEE: /* out %al,(%dx) */
+ insnlen += 1;
+ break;
+ default:
+ /* OK, we don't know what this is, can't emulate. */
+ return 0;
+ }
+
+ /* If it was an "IN" instruction, they expect the result to be read
+ * into %eax, so we change %eax. We always return all-ones, which
+ * traditionally means "there's nothing there". */
+ if (in) {
+ /* Lower bit tells is whether it's a 16 or 32 bit access */
+ if (insn & 0x1)
+ lg->regs->eax = 0xFFFFFFFF;
+ else
+ lg->regs->eax |= (0xFFFF << shift);
+ }
+ /* Finally, we've "done" the instruction, so move past it. */
+ lg->regs->eip += insnlen;
+ /* Success! */
+ return 1;
+}
+
+/*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */
+void lguest_arch_handle_trap(struct lguest *lg)
+{
+ switch (lg->regs->trapnum) {
+ case 13: /* We've intercepted a General Protection Fault. */
+ /* Check if this was one of those annoying IN or OUT
+ * instructions which we need to emulate. If so, we just go
+ * back into the Guest after we've done it. */
+ if (lg->regs->errcode == 0) {
+ if (emulate_insn(lg))
+ return;
+ }
+ break;
+ case 14: /* We've intercepted a Page Fault. */
+ /* The Guest accessed a virtual address that wasn't mapped.
+ * This happens a lot: we don't actually set up most of the
+ * page tables for the Guest at all when we start: as it runs
+ * it asks for more and more, and we set them up as
+ * required. In this case, we don't even tell the Guest that
+ * the fault happened.
+ *
+ * The errcode tells whether this was a read or a write, and
+ * whether kernel or userspace code. */
+ if (demand_page(lg, lg->arch.last_pagefault, lg->regs->errcode))
+ return;
+
+ /* OK, it's really not there (or not OK): the Guest needs to
+ * know. We write out the cr2 value so it knows where the
+ * fault occurred.
+ *
+ * Note that if the Guest were really messed up, this could
+ * happen before it's done the LHCALL_LGUEST_INIT hypercall, so
+ * lg->lguest_data could be NULL */
+ if (lg->lguest_data &&
+ put_user(lg->arch.last_pagefault, &lg->lguest_data->cr2))
+ kill_guest(lg, "Writing cr2");
+ break;
+ case 7: /* We've intercepted a Device Not Available fault. */
+ /* If the Guest doesn't want to know, we already restored the
+ * Floating Point Unit, so we just continue without telling
+ * it. */
+ if (!lg->ts)
+ return;
+ break;
+ case 32 ... 255:
+ /* These values mean a real interrupt occurred, in which case
+ * the Host handler has already been run. We just do a
+ * friendly check if another process should now be run, then
+ * return to run the Guest again */
+ cond_resched();
+ return;
+ case LGUEST_TRAP_ENTRY:
+ /* Our 'struct hcall_args' maps directly over our regs: we set
+ * up the pointer now to indicate a hypercall is pending. */
+ lg->hcall = (struct hcall_args *)lg->regs;
+ return;
+ }
+
+ /* We didn't handle the trap, so it needs to go to the Guest. */
+ if (!deliver_trap(lg, lg->regs->trapnum))
+ /* If the Guest doesn't have a handler (either it hasn't
+ * registered any yet, or it's one of the faults we don't let
+ * it handle), it dies with a cryptic error message. */
+ kill_guest(lg, "unhandled trap %li at %#lx (%#lx)",
+ lg->regs->trapnum, lg->regs->eip,
+ lg->regs->trapnum == 14 ? lg->arch.last_pagefault
+ : lg->regs->errcode);
+}
+
+/* Now we can look at each of the routines this calls, in increasing order of
+ * complexity: do_hypercalls(), emulate_insn(), maybe_do_interrupt(),
+ * deliver_trap() and demand_page(). After all those, we'll be ready to
+ * examine the Switcher, and our philosophical understanding of the Host/Guest
+ * duality will be complete. :*/
+static void adjust_pge(void *on)
+{
+ if (on)
+ write_cr4(read_cr4() | X86_CR4_PGE);
+ else
+ write_cr4(read_cr4() & ~X86_CR4_PGE);
+}
+
+/*H:020 Now the Switcher is mapped and every thing else is ready, we need to do
+ * some more i386-specific initialization. */
+void __init lguest_arch_host_init(void)
+{
+ int i;
+
+ /* Most of the i386/switcher.S doesn't care that it's been moved; on
+ * Intel, jumps are relative, and it doesn't access any references to
+ * external code or data.
+ *
+ * The only exception is the interrupt handlers in switcher.S: their
+ * addresses are placed in a table (default_idt_entries), so we need to
+ * update the table with the new addresses. switcher_offset() is a
+ * convenience function which returns the distance between the builtin
+ * switcher code and the high-mapped copy we just made. */
+ for (i = 0; i < IDT_ENTRIES; i++)
+ default_idt_entries[i] += switcher_offset();
+
+ /*
+ * Set up the Switcher's per-cpu areas.
+ *
+ * Each CPU gets two pages of its own within the high-mapped region
+ * (aka. "struct lguest_pages"). Much of this can be initialized now,
+ * but some depends on what Guest we are running (which is set up in
+ * copy_in_guest_info()).
+ */
+ for_each_possible_cpu(i) {
+ /* lguest_pages() returns this CPU's two pages. */
+ struct lguest_pages *pages = lguest_pages(i);
+ /* This is a convenience pointer to make the code fit one
+ * statement to a line. */
+ struct lguest_ro_state *state = &pages->state;
+
+ /* The Global Descriptor Table: the Host has a different one
+ * for each CPU. We keep a descriptor for the GDT which says
+ * where it is and how big it is (the size is actually the last
+ * byte, not the size, hence the "-1"). */
+ state->host_gdt_desc.size = GDT_SIZE-1;
+ state->host_gdt_desc.address = (long)get_cpu_gdt_table(i);
+
+ /* All CPUs on the Host use the same Interrupt Descriptor
+ * Table, so we just use store_idt(), which gets this CPU's IDT
+ * descriptor. */
+ store_idt(&state->host_idt_desc);
+
+ /* The descriptors for the Guest's GDT and IDT can be filled
+ * out now, too. We copy the GDT & IDT into ->guest_gdt and
+ * ->guest_idt before actually running the Guest. */
+ state->guest_idt_desc.size = sizeof(state->guest_idt)-1;
+ state->guest_idt_desc.address = (long)&state->guest_idt;
+ state->guest_gdt_desc.size = sizeof(state->guest_gdt)-1;
+ state->guest_gdt_desc.address = (long)&state->guest_gdt;
+
+ /* We know where we want the stack to be when the Guest enters
+ * the switcher: in pages->regs. The stack grows upwards, so
+ * we start it at the end of that structure. */
+ state->guest_tss.esp0 = (long)(&pages->regs + 1);
+ /* And this is the GDT entry to use for the stack: we keep a
+ * couple of special LGUEST entries. */
+ state->guest_tss.ss0 = LGUEST_DS;
+
+ /* x86 can have a finegrained bitmap which indicates what I/O
+ * ports the process can use. We set it to the end of our
+ * structure, meaning "none". */
+ state->guest_tss.io_bitmap_base = sizeof(state->guest_tss);
+
+ /* Some GDT entries are the same across all Guests, so we can
+ * set them up now. */
+ setup_default_gdt_entries(state);
+ /* Most IDT entries are the same for all Guests, too.*/
+ setup_default_idt_entries(state, default_idt_entries);
+
+ /* The Host needs to be able to use the LGUEST segments on this
+ * CPU, too, so put them in the Host GDT. */
+ get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
+ get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
+ }
+
+ /* In the Switcher, we want the %cs segment register to use the
+ * LGUEST_CS GDT entry: we've put that in the Host and Guest GDTs, so
+ * it will be undisturbed when we switch. To change %cs and jump we
+ * need this structure to feed to Intel's "lcall" instruction. */
+ lguest_entry.offset = (long)switch_to_guest + switcher_offset();
+ lguest_entry.segment = LGUEST_CS;
+
+ /* Finally, we need to turn off "Page Global Enable". PGE is an
+ * optimization where page table entries are specially marked to show
+ * they never change. The Host kernel marks all the kernel pages this
+ * way because it's always present, even when userspace is running.
+ *
+ * Lguest breaks this: unbeknownst to the rest of the Host kernel, we
+ * switch to the Guest kernel. If you don't disable this on all CPUs,
+ * you'll get really weird bugs that you'll chase for two days.
+ *
+ * I used to turn PGE off every time we switched to the Guest and back
+ * on when we return, but that slowed the Switcher down noticibly. */
+
+ /* We don't need the complexity of CPUs coming and going while we're
+ * doing this. */
+ lock_cpu_hotplug();
+ if (cpu_has_pge) { /* We have a broader idea of "global". */
+ /* Remember that this was originally set (for cleanup). */
+ cpu_had_pge = 1;
+ /* adjust_pge is a helper function which sets or unsets the PGE
+ * bit on its CPU, depending on the argument (0 == unset). */
+ on_each_cpu(adjust_pge, (void *)0, 0, 1);
+ /* Turn off the feature in the global feature set. */
+ clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+ }
+ unlock_cpu_hotplug();
+};
+/*:*/
+
+void __exit lguest_arch_host_fini(void)
+{
+ /* If we had PGE before we started, turn it back on now. */
+ lock_cpu_hotplug();
+ if (cpu_had_pge) {
+ set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+ /* adjust_pge's argument "1" means set PGE. */
+ on_each_cpu(adjust_pge, (void *)1, 0, 1);
+ }
+ unlock_cpu_hotplug();
+}
+
+
+/*H:122 The i386-specific hypercalls simply farm out to the right functions. */
+int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args)
+{
+ switch (args->arg0) {
+ case LHCALL_LOAD_GDT:
+ load_guest_gdt(lg, args->arg1, args->arg2);
+ break;
+ case LHCALL_LOAD_IDT_ENTRY:
+ load_guest_idt_entry(lg, args->arg1, args->arg2, args->arg3);
+ break;
+ case LHCALL_LOAD_TLS:
+ guest_load_tls(lg, args->arg1);
+ break;
+ default:
+ /* Bad Guest. Bad! */
+ return -EIO;
+ }
+ return 0;
+}
+
+/*H:126 i386-specific hypercall initialization: */
+int lguest_arch_init_hypercalls(struct lguest *lg)
+{
+ u32 tsc_speed;
+
+ /* The pointer to the Guest's "struct lguest_data" is the only
+ * argument. We check that address now. */
+ if (!lguest_address_ok(lg, lg->hcall->arg1, sizeof(*lg->lguest_data)))
+ return -EFAULT;
+
+ /* Having checked it, we simply set lg->lguest_data to point straight
+ * into the Launcher's memory at the right place and then use
+ * copy_to_user/from_user from now on, instead of lgread/write. I put
+ * this in to show that I'm not immune to writing stupid
+ * optimizations. */
+ lg->lguest_data = lg->mem_base + lg->hcall->arg1;
+
+ /* We insist that the Time Stamp Counter exist and doesn't change with
+ * cpu frequency. Some devious chip manufacturers decided that TSC
+ * changes could be handled in software. I decided that time going
+ * backwards might be good for benchmarks, but it's bad for users.
+ *
+ * We also insist that the TSC be stable: the kernel detects unreliable
+ * TSCs for its own purposes, and we use that here. */
+ if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && !check_tsc_unstable())
+ tsc_speed = tsc_khz;
+ else
+ tsc_speed = 0;
+ if (put_user(tsc_speed, &lg->lguest_data->tsc_khz))
+ return -EFAULT;
+
+ /* The interrupt code might not like the system call vector. */
+ if (!check_syscall_vector(lg))
+ kill_guest(lg, "bad syscall vector");
+
+ return 0;
+}
+
+/*L:030 lguest_arch_setup_regs()
+ *
+ * Most of the Guest's registers are left alone: we used get_zeroed_page() to
+ * allocate the structure, so they will be 0. */
+void lguest_arch_setup_regs(struct lguest *lg, unsigned long start)
+{
+ struct lguest_regs *regs = lg->regs;
+
+ /* There are four "segment" registers which the Guest needs to boot:
+ * The "code segment" register (cs) refers to the kernel code segment
+ * __KERNEL_CS, and the "data", "extra" and "stack" segment registers
+ * refer to the kernel data segment __KERNEL_DS.
+ *
+ * The privilege level is packed into the lower bits. The Guest runs
+ * at privilege level 1 (GUEST_PL).*/
+ regs->ds = regs->es = regs->ss = __KERNEL_DS|GUEST_PL;
+ regs->cs = __KERNEL_CS|GUEST_PL;
+
+ /* The "eflags" register contains miscellaneous flags. Bit 1 (0x002)
+ * is supposed to always be "1". Bit 9 (0x200) controls whether
+ * interrupts are enabled. We always leave interrupts enabled while
+ * running the Guest. */
+ regs->eflags = X86_EFLAGS_IF | 0x2;
+
+ /* The "Extended Instruction Pointer" register says where the Guest is
+ * running. */
+ regs->eip = start;
+
+ /* %esi points to our boot information, at physical address 0, so don't
+ * touch it. */
+
+ /* There are a couple of GDT entries the Guest expects when first
+ * booting. */
+ setup_guest_gdt(lg);
+}
diff --git a/drivers/lguest/switcher.S b/drivers/lguest/x86/switcher_32.S
index 7c9c230cc84..0af8baaa0d4 100644
--- a/drivers/lguest/switcher.S
+++ b/drivers/lguest/x86/switcher_32.S
@@ -6,6 +6,37 @@
* are feeling invigorated and refreshed then the next, more challenging stage
* can be found in "make Guest". :*/
+/*M:012 Lguest is meant to be simple: my rule of thumb is that 1% more LOC must
+ * gain at least 1% more performance. Since neither LOC nor performance can be
+ * measured beforehand, it generally means implementing a feature then deciding
+ * if it's worth it. And once it's implemented, who can say no?
+ *
+ * This is why I haven't implemented this idea myself. I want to, but I
+ * haven't. You could, though.
+ *
+ * The main place where lguest performance sucks is Guest page faulting. When
+ * a Guest userspace process hits an unmapped page we switch back to the Host,
+ * walk the page tables, find it's not mapped, switch back to the Guest page
+ * fault handler, which calls a hypercall to set the page table entry, then
+ * finally returns to userspace. That's two round-trips.
+ *
+ * If we had a small walker in the Switcher, we could quickly check the Guest
+ * page table and if the page isn't mapped, immediately reflect the fault back
+ * into the Guest. This means the Switcher would have to know the top of the
+ * Guest page table and the page fault handler address.
+ *
+ * For simplicity, the Guest should only handle the case where the privilege
+ * level of the fault is 3 and probably only not present or write faults. It
+ * should also detect recursive faults, and hand the original fault to the
+ * Host (which is actually really easy).
+ *
+ * Two questions remain. Would the performance gain outweigh the complexity?
+ * And who would write the verse documenting it? :*/
+
+/*M:011 Lguest64 handles NMI. This gave me NMI envy (until I looked at their
+ * code). It's worth doing though, since it would let us use oprofile in the
+ * Host when a Guest is running. :*/
+
/*S:100
* Welcome to the Switcher itself!
*
@@ -48,7 +79,8 @@
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/page.h>
-#include "lg.h"
+#include <asm/segment.h>
+#include <asm/lguest.h>
// We mark the start of the code to copy
// It's placed in .text tho it's never run here
@@ -87,7 +119,7 @@ ENTRY(switch_to_guest)
// All saved and there's now five steps before us:
// Stack, GDT, IDT, TSS
- // And last of all the page tables are flipped.
+ // Then last of all the page tables are flipped.
// Yet beware that our stack pointer must be
// Always valid lest an NMI hits
@@ -102,25 +134,25 @@ ENTRY(switch_to_guest)
lgdt LGUEST_PAGES_guest_gdt_desc(%eax)
// The Guest's IDT we did partially
- // Move to the "struct lguest_pages" as well.
+ // Copy to "struct lguest_pages" as well.
lidt LGUEST_PAGES_guest_idt_desc(%eax)
// The TSS entry which controls traps
// Must be loaded up with "ltr" now:
+ // The GDT entry that TSS uses
+ // Changes type when we load it: damn Intel!
// For after we switch over our page tables
- // It (as the rest) will be writable no more.
- // (The GDT entry TSS needs
- // Changes type when we load it: damn Intel!)
+ // That entry will be read-only: we'd crash.
movl $(GDT_ENTRY_TSS*8), %edx
ltr %dx
// Look back now, before we take this last step!
// The Host's TSS entry was also marked used;
- // Let's clear it again, ere we return.
+ // Let's clear it again for our return.
// The GDT descriptor of the Host
// Points to the table after two "size" bytes
movl (LGUEST_PAGES_host_gdt_desc+2)(%eax), %edx
- // Clear the type field of "used" (byte 5, bit 2)
+ // Clear "used" from type field (byte 5, bit 2)
andb $0xFD, (GDT_ENTRY_TSS*8 + 5)(%edx)
// Once our page table's switched, the Guest is live!
@@ -130,8 +162,9 @@ ENTRY(switch_to_guest)
// The page table change did one tricky thing:
// The Guest's register page has been mapped
- // Writable onto our %esp (stack) --
+ // Writable under our %esp (stack) --
// We can simply pop off all Guest regs.
+ popl %eax
popl %ebx
popl %ecx
popl %edx
@@ -139,7 +172,6 @@ ENTRY(switch_to_guest)
popl %edi
popl %ebp
popl %gs
- popl %eax
popl %fs
popl %ds
popl %es
@@ -151,23 +183,21 @@ ENTRY(switch_to_guest)
addl $8, %esp
// The last five stack slots hold return address
- // And everything needed to change privilege
- // Into the Guest privilege level of 1,
+ // And everything needed to switch privilege
+ // From Switcher's level 0 to Guest's 1,
// And the stack where the Guest had last left it.
// Interrupts are turned back on: we are Guest.
iret
-// There are two paths where we switch to the Host
+// We treat two paths to switch back to the Host
+// Yet both must save Guest state and restore Host
// So we put the routine in a macro.
-// We are on our way home, back to the Host
-// Interrupted out of the Guest, we come here.
#define SWITCH_TO_HOST \
/* We save the Guest state: all registers first \
* Laid out just as "struct lguest_regs" defines */ \
pushl %es; \
pushl %ds; \
pushl %fs; \
- pushl %eax; \
pushl %gs; \
pushl %ebp; \
pushl %edi; \
@@ -175,6 +205,7 @@ ENTRY(switch_to_guest)
pushl %edx; \
pushl %ecx; \
pushl %ebx; \
+ pushl %eax; \
/* Our stack and our code are using segments \
* Set in the TSS and IDT \
* Yet if we were to touch data we'd use \
@@ -193,7 +224,7 @@ ENTRY(switch_to_guest)
movl %esp, %eax; \
andl $(~(1 << PAGE_SHIFT - 1)), %eax; \
/* Save our trap number: the switch will obscure it \
- * (The Guest regs are not mapped here in the Host) \
+ * (In the Host the Guest regs are not mapped here) \
* %ebx holds it safe for deliver_to_host */ \
movl LGUEST_PAGES_regs_trapnum(%eax), %ebx; \
/* The Host GDT, IDT and stack! \
@@ -209,9 +240,9 @@ ENTRY(switch_to_guest)
/* Switch to Host's GDT, IDT. */ \
lgdt LGUEST_PAGES_host_gdt_desc(%eax); \
lidt LGUEST_PAGES_host_idt_desc(%eax); \
- /* Restore the Host's stack where it's saved regs lie */ \
+ /* Restore the Host's stack where its saved regs lie */ \
movl LGUEST_PAGES_host_sp(%eax), %esp; \
- /* Last the TSS: our Host is complete */ \
+ /* Last the TSS: our Host is returned */ \
movl $(GDT_ENTRY_TSS*8), %edx; \
ltr %dx; \
/* Restore now the regs saved right at the first. */ \
@@ -221,14 +252,15 @@ ENTRY(switch_to_guest)
popl %ds; \
popl %es
-// Here's where we come when the Guest has just trapped:
-// (Which trap we'll see has been pushed on the stack).
+// The first path is trod when the Guest has trapped:
+// (Which trap it was has been pushed on the stack).
// We need only switch back, and the Host will decode
// Why we came home, and what needs to be done.
return_to_host:
SWITCH_TO_HOST
iret
+// We are lead to the second path like so:
// An interrupt, with some cause external
// Has ajerked us rudely from the Guest's code
// Again we must return home to the Host
@@ -237,7 +269,7 @@ deliver_to_host:
// But now we must go home via that place
// Where that interrupt was supposed to go
// Had we not been ensconced, running the Guest.
- // Here we see the cleverness of our stack:
+ // Here we see the trickness of run_guest_once():
// The Host stack is formed like an interrupt
// With EIP, CS and EFLAGS layered.
// Interrupt handlers end with "iret"
@@ -262,7 +294,7 @@ deliver_to_host:
xorw %ax, %ax
orl %eax, %edx
// Now the address of the handler's in %edx
- // We call it now: its "iret" takes us home.
+ // We call it now: its "iret" drops us home.
jmp *%edx
// Every interrupt can come to us here
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 56cd8998fe4..77f50b63a97 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -172,6 +172,7 @@ config INPUT_ADBHID
config MAC_EMUMOUSEBTN
bool "Support for mouse button 2+3 emulation"
+ select INPUT
help
This provides generic support for emulating the 2nd and 3rd mouse
button with keypresses. If you say Y here, the emulation is still
diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c
index 17ef5d3c01b..44469662517 100644
--- a/drivers/macintosh/adb-iop.c
+++ b/drivers/macintosh/adb-iop.c
@@ -19,7 +19,6 @@
#include <linux/init.h>
#include <linux/proc_fs.h>
-#include <asm/bootinfo.h>
#include <asm/macintosh.h>
#include <asm/macints.h>
#include <asm/mac_iop.h>
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index b46817f699f..883da72b536 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -52,6 +52,11 @@
MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");
+static int restore_capslock_events;
+module_param(restore_capslock_events, int, 0644);
+MODULE_PARM_DESC(restore_capslock_events,
+ "Produce keypress events for capslock on both keyup and keydown.");
+
#define KEYB_KEYREG 0 /* register # for key up/down data */
#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */
#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */
@@ -70,7 +75,7 @@ static struct notifier_block adbhid_adb_notifier = {
#define ADB_KEY_POWER_OLD 0x7e
#define ADB_KEY_POWER 0x7f
-u8 adb_to_linux_keycodes[128] = {
+u16 adb_to_linux_keycodes[128] = {
/* 0x00 */ KEY_A, /* 30 */
/* 0x01 */ KEY_S, /* 31 */
/* 0x02 */ KEY_D, /* 32 */
@@ -134,7 +139,7 @@ u8 adb_to_linux_keycodes[128] = {
/* 0x3c */ KEY_RIGHT, /* 106 */
/* 0x3d */ KEY_DOWN, /* 108 */
/* 0x3e */ KEY_UP, /* 103 */
- /* 0x3f */ 0,
+ /* 0x3f */ KEY_FN, /* 0x1d0 */
/* 0x40 */ 0,
/* 0x41 */ KEY_KPDOT, /* 83 */
/* 0x42 */ 0,
@@ -208,7 +213,7 @@ struct adbhid {
int original_handler_id;
int current_handler_id;
int mouse_kind;
- unsigned char *keycode;
+ u16 *keycode;
char name[64];
char phys[32];
int flags;
@@ -217,6 +222,8 @@ struct adbhid {
#define FLAG_FN_KEY_PRESSED 0x00000001
#define FLAG_POWER_FROM_FN 0x00000002
#define FLAG_EMU_FWDEL_DOWN 0x00000004
+#define FLAG_CAPSLOCK_TRANSLATE 0x00000008
+#define FLAG_CAPSLOCK_DOWN 0x00000010
static struct adbhid *adbhid[16];
@@ -272,19 +279,50 @@ adbhid_keyboard_input(unsigned char *data, int nb, int apoll)
}
static void
-adbhid_input_keycode(int id, int keycode, int repeat)
+adbhid_input_keycode(int id, int scancode, int repeat)
{
struct adbhid *ahid = adbhid[id];
- int up_flag;
-
- up_flag = (keycode & 0x80);
- keycode &= 0x7f;
+ int keycode, up_flag, key;
+
+ keycode = scancode & 0x7f;
+ up_flag = scancode & 0x80;
+
+ if (restore_capslock_events) {
+ if (keycode == ADB_KEY_CAPSLOCK && !up_flag) {
+ /* Key pressed, turning on the CapsLock LED.
+ * The next 0xff will be interpreted as a release. */
+ ahid->flags |= FLAG_CAPSLOCK_TRANSLATE
+ | FLAG_CAPSLOCK_DOWN;
+ } else if (scancode == 0xff) {
+ /* Scancode 0xff usually signifies that the capslock
+ * key was either pressed or released. */
+ if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE) {
+ keycode = ADB_KEY_CAPSLOCK;
+ if (ahid->flags & FLAG_CAPSLOCK_DOWN) {
+ /* Key released */
+ up_flag = 1;
+ ahid->flags &= ~FLAG_CAPSLOCK_DOWN;
+ } else {
+ /* Key pressed */
+ up_flag = 0;
+ ahid->flags &= ~FLAG_CAPSLOCK_TRANSLATE;
+ }
+ } else {
+ printk(KERN_INFO "Spurious caps lock event "
+ "(scancode 0xff).");
+ }
+ }
+ }
switch (keycode) {
- case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */
- input_report_key(ahid->input, KEY_CAPSLOCK, 1);
- input_report_key(ahid->input, KEY_CAPSLOCK, 0);
- input_sync(ahid->input);
+ case ADB_KEY_CAPSLOCK:
+ if (!restore_capslock_events) {
+ /* Generate down/up events for CapsLock everytime. */
+ input_report_key(ahid->input, KEY_CAPSLOCK, 1);
+ input_sync(ahid->input);
+ input_report_key(ahid->input, KEY_CAPSLOCK, 0);
+ input_sync(ahid->input);
+ }
return;
#ifdef CONFIG_PPC_PMAC
case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */
@@ -296,7 +334,7 @@ adbhid_input_keycode(int id, int keycode, int repeat)
keycode = ADB_KEY_POWER;
}
break;
- case ADB_KEY_POWER:
+ case ADB_KEY_POWER:
/* Fn + Command will produce a bogus "power" keycode */
if (ahid->flags & FLAG_FN_KEY_PRESSED) {
keycode = ADB_KEY_CMD;
@@ -321,8 +359,7 @@ adbhid_input_keycode(int id, int keycode, int repeat)
}
} else
ahid->flags |= FLAG_FN_KEY_PRESSED;
- /* Swallow the key press */
- return;
+ break;
case ADB_KEY_DEL:
/* Emulate Fn+delete = forward delete */
if (ahid->flags & FLAG_FN_KEY_PRESSED) {
@@ -336,9 +373,9 @@ adbhid_input_keycode(int id, int keycode, int repeat)
#endif /* CONFIG_PPC_PMAC */
}
- if (adbhid[id]->keycode[keycode]) {
- input_report_key(adbhid[id]->input,
- adbhid[id]->keycode[keycode], !up_flag);
+ key = adbhid[id]->keycode[keycode];
+ if (key) {
+ input_report_key(adbhid[id]->input, key, !up_flag);
input_sync(adbhid[id]->input);
} else
printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode,
@@ -754,26 +791,30 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
if (hid->keycode[i])
set_bit(hid->keycode[i], input_dev->keybit);
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
- input_dev->ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
+ BIT_MASK(EV_REP);
+ input_dev->ledbit[0] = BIT_MASK(LED_SCROLLL) |
+ BIT_MASK(LED_CAPSL) | BIT_MASK(LED_NUML);
input_dev->event = adbhid_kbd_event;
- input_dev->keycodemax = 127;
- input_dev->keycodesize = 1;
+ input_dev->keycodemax = KEY_FN;
+ input_dev->keycodesize = sizeof(hid->keycode[0]);
break;
case ADB_MOUSE:
sprintf(hid->name, "ADB mouse");
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
- input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
+ input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
break;
case ADB_MISC:
switch (original_handler_id) {
case 0x02: /* Adjustable keyboard button device */
sprintf(hid->name, "ADB adjustable keyboard buttons");
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) |
+ BIT_MASK(EV_REP);
set_bit(KEY_SOUND, input_dev->keybit);
set_bit(KEY_MUTE, input_dev->keybit);
set_bit(KEY_VOLUMEUP, input_dev->keybit);
@@ -781,7 +822,8 @@ adbhid_input_register(int id, int default_id, int original_handler_id,
break;
case 0x1f: /* Powerbook button device */
sprintf(hid->name, "ADB Powerbook buttons");
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) |
+ BIT_MASK(EV_REP);
set_bit(KEY_MUTE, input_dev->keybit);
set_bit(KEY_VOLUMEUP, input_dev->keybit);
set_bit(KEY_VOLUMEDOWN, input_dev->keybit);
diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c
index e54c4d9f636..73c50bc0209 100644
--- a/drivers/macintosh/ans-lcd.c
+++ b/drivers/macintosh/ans-lcd.c
@@ -14,9 +14,10 @@
#include <asm/uaccess.h>
#include <asm/sections.h>
#include <asm/prom.h>
-#include <asm/ans-lcd.h>
#include <asm/io.h>
+#include "ans-lcd.h"
+
#define ANSLCD_ADDR 0xf301c000
#define ANSLCD_CTRL_IX 0x00
#define ANSLCD_DATA_IX 0x10
diff --git a/drivers/macintosh/ans-lcd.h b/drivers/macintosh/ans-lcd.h
new file mode 100644
index 00000000000..d795b9fd2db
--- /dev/null
+++ b/drivers/macintosh/ans-lcd.h
@@ -0,0 +1,11 @@
+#ifndef _PPC_ANS_LCD_H
+#define _PPC_ANS_LCD_H
+
+#define ANSLCD_MINOR 156
+
+#define ANSLCD_CLEAR 0x01
+#define ANSLCD_SENDCTRL 0x02
+#define ANSLCD_SETSHORTDELAY 0x03
+#define ANSLCD_SETLONGDELAY 0x04
+
+#endif
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
index 33dee3a773e..89302309da9 100644
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -117,9 +117,10 @@ static int emumousebtn_input_register(void)
emumousebtn->id.product = 0x0001;
emumousebtn->id.version = 0x0100;
- emumousebtn->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- emumousebtn->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
- emumousebtn->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ emumousebtn->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ emumousebtn->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
+ emumousebtn->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
ret = input_register_device(emumousebtn);
if (ret)
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index c803d2bba65..48d647abea4 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -563,7 +563,7 @@ static void media_bay_step(int i)
ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL);
hw.irq = bay->cd_irq;
hw.chipset = ide_pmac;
- bay->cd_index = ide_register_hw(&hw, 0, NULL);
+ bay->cd_index = ide_register_hw(&hw, NULL, 0, NULL);
pmu_resume();
}
if (bay->cd_index == -1) {
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index f25685b9b7c..276945d5151 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -379,13 +379,10 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
if (thermostat)
return 0;
- th = (struct thermostat *)
- kmalloc(sizeof(struct thermostat), GFP_KERNEL);
-
+ th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
if (!th)
return -ENOMEM;
- memset(th, 0, sizeof(*th));
th->clt.addr = addr;
th->clt.adapter = adapter;
th->clt.driver = &thermostat_driver;
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 04f3973e387..dc741d3a453 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -410,7 +410,7 @@ static int __init via_pmu_start(void)
irq = irq_of_parse_and_map(vias, 0);
if (irq == NO_IRQ) {
- printk(KERN_ERR "via-pmu: can't map interruptn");
+ printk(KERN_ERR "via-pmu: can't map interrupt\n");
return -ENODEV;
}
if (request_irq(irq, via_pmu_interrupt, 0, "VIA-PMU", (void *)0)) {
@@ -1521,7 +1521,7 @@ pmu_sr_intr(void)
req = current_req;
/*
* For PMU sleep and freq change requests, we lock the
- * PMU until it's explicitely unlocked. This avoids any
+ * PMU until it's explicitly unlocked. This avoids any
* spurrious event polling getting in
*/
current_req = req->next;
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index 516d943227e..075b4d99e35 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -94,7 +94,9 @@ static int wf_thread_func(void *data)
DBG("wf: thread started\n");
set_freezable();
- while(!kthread_should_stop()) {
+ while (!kthread_should_stop()) {
+ try_to_freeze();
+
if (time_after_eq(jiffies, next)) {
wf_notify(WF_EVENT_TICK, NULL);
if (wf_overtemp) {
@@ -116,12 +118,6 @@ static int wf_thread_func(void *data)
delay = next - jiffies;
if (delay <= HZ)
schedule_timeout_interruptible(delay);
-
- /* there should be no non-suspend signal, but oh well */
- if (signal_pending(current) && !try_to_freeze()) {
- printk(KERN_WARNING "windfarm: thread got sigl !\n");
- break;
- }
}
DBG("wf: thread stopped\n");
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index 351982bcec1..f449d775cdf 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -380,10 +380,12 @@ static int __init sat_sensors_init(void)
return i2c_add_driver(&wf_sat_driver);
}
+#if 0 /* uncomment when module_exit() below is uncommented */
static void __exit sat_sensors_exit(void)
{
i2c_del_driver(&wf_sat_driver);
}
+#endif
module_init(sat_sensors_init);
/*module_exit(sat_sensors_exit); Uncomment when cleanup is implemented */
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 34a8c60a254..9b6fbf044fd 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -267,6 +267,12 @@ config DM_MULTIPATH_RDAC
---help---
Multipath support for LSI/Engenio RDAC.
+config DM_MULTIPATH_HP
+ tristate "HP MSA multipath support (EXPERIMENTAL)"
+ depends on DM_MULTIPATH && BLK_DEV_DM && EXPERIMENTAL
+ ---help---
+ Multipath support for HP MSA (Active/Passive) series hardware.
+
config DM_DELAY
tristate "I/O delaying target (EXPERIMENTAL)"
depends on BLK_DEV_DM && EXPERIMENTAL
@@ -276,4 +282,10 @@ config DM_DELAY
If unsure, say N.
+config DM_UEVENT
+ bool "DM uevents (EXPERIMENTAL)"
+ depends on BLK_DEV_DM && EXPERIMENTAL
+ ---help---
+ Generate udev events for DM events.
+
endif # MD
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index c49366cdc05..d9aa7edb878 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -8,6 +8,7 @@ dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o
dm-snapshot-objs := dm-snap.o dm-exception-store.o
dm-mirror-objs := dm-log.o dm-raid1.o
dm-rdac-objs := dm-mpath-rdac.o
+dm-hp-sw-objs := dm-mpath-hp-sw.o
md-mod-objs := md.o bitmap.o
raid456-objs := raid5.o raid6algos.o raid6recov.o raid6tables.o \
raid6int1.o raid6int2.o raid6int4.o \
@@ -35,6 +36,7 @@ obj-$(CONFIG_DM_CRYPT) += dm-crypt.o
obj-$(CONFIG_DM_DELAY) += dm-delay.o
obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o
obj-$(CONFIG_DM_MULTIPATH_EMC) += dm-emc.o
+obj-$(CONFIG_DM_MULTIPATH_HP) += dm-hp-sw.o
obj-$(CONFIG_DM_MULTIPATH_RDAC) += dm-rdac.o
obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o
obj-$(CONFIG_DM_MIRROR) += dm-mirror.o
@@ -48,6 +50,10 @@ ifeq ($(CONFIG_ALTIVEC),y)
altivec_flags := -maltivec -mabi=altivec
endif
+ifeq ($(CONFIG_DM_UEVENT),y)
+dm-mod-objs += dm-uevent.o
+endif
+
targets += raid6int1.c
$(obj)/raid6int1.c: UNROLL := 1
$(obj)/raid6int1.c: $(src)/raid6int.uc $(src)/unroll.pl FORCE
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 927cb34c480..1b1ef3130e6 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -274,7 +274,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
if (bitmap->offset < 0) {
/* DATA BITMAP METADATA */
if (bitmap->offset
- + page->index * (PAGE_SIZE/512)
+ + (long)(page->index * (PAGE_SIZE/512))
+ size/512 > 0)
/* bitmap runs in to metadata */
return -EINVAL;
@@ -1207,8 +1207,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
prepare_to_wait(&bitmap->overflow_wait, &__wait,
TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&bitmap->lock);
- bitmap->mddev->queue
- ->unplug_fn(bitmap->mddev->queue);
+ blk_unplug(bitmap->mddev->queue);
schedule();
finish_wait(&bitmap->overflow_wait, &__wait);
continue;
diff --git a/drivers/md/dm-bio-list.h b/drivers/md/dm-bio-list.h
index 3f7b827649e..d4509be0fe6 100644
--- a/drivers/md/dm-bio-list.h
+++ b/drivers/md/dm-bio-list.h
@@ -21,11 +21,6 @@ static inline int bio_list_empty(const struct bio_list *bl)
return bl->head == NULL;
}
-#define BIO_LIST_INIT { .head = NULL, .tail = NULL }
-
-#define BIO_LIST(bl) \
- struct bio_list bl = BIO_LIST_INIT
-
static inline void bio_list_init(struct bio_list *bl)
{
bl->head = bl->tail = NULL;
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index bdc52d6922b..28c6ae095c5 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -36,7 +36,6 @@ struct dm_crypt_io {
struct work_struct work;
atomic_t pending;
int error;
- int post_process;
};
/*
@@ -57,7 +56,7 @@ struct crypt_config;
struct crypt_iv_operations {
int (*ctr)(struct crypt_config *cc, struct dm_target *ti,
- const char *opts);
+ const char *opts);
void (*dtr)(struct crypt_config *cc);
const char *(*status)(struct crypt_config *cc);
int (*generator)(struct crypt_config *cc, u8 *iv, sector_t sector);
@@ -80,6 +79,8 @@ struct crypt_config {
mempool_t *page_pool;
struct bio_set *bs;
+ struct workqueue_struct *io_queue;
+ struct workqueue_struct *crypt_queue;
/*
* crypto related data
*/
@@ -112,7 +113,7 @@ static void clone_init(struct dm_crypt_io *, struct bio *);
* Different IV generation algorithms:
*
* plain: the initial vector is the 32-bit little-endian version of the sector
- * number, padded with zeros if neccessary.
+ * number, padded with zeros if necessary.
*
* essiv: "encrypted sector|salt initial vector", the sector number is
* encrypted with the bulk cipher using a salt as key. The salt
@@ -137,7 +138,7 @@ static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
}
static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
- const char *opts)
+ const char *opts)
{
struct crypto_cipher *essiv_tfm;
struct crypto_hash *hash_tfm;
@@ -167,7 +168,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
return -ENOMEM;
}
- sg_set_buf(&sg, cc->key, cc->key_size);
+ sg_init_one(&sg, cc->key, cc->key_size);
desc.tfm = hash_tfm;
desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
err = crypto_hash_digest(&desc, &sg, cc->key_size, salt);
@@ -175,6 +176,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
if (err) {
ti->error = "Error calculating hash in ESSIV";
+ kfree(salt);
return err;
}
@@ -188,7 +190,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
if (crypto_cipher_blocksize(essiv_tfm) !=
crypto_blkcipher_ivsize(cc->tfm)) {
ti->error = "Block size of ESSIV cipher does "
- "not match IV size of block cipher";
+ "not match IV size of block cipher";
crypto_free_cipher(essiv_tfm);
kfree(salt);
return -EINVAL;
@@ -319,10 +321,10 @@ crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
return r;
}
-static void
-crypt_convert_init(struct crypt_config *cc, struct convert_context *ctx,
- struct bio *bio_out, struct bio *bio_in,
- sector_t sector, int write)
+static void crypt_convert_init(struct crypt_config *cc,
+ struct convert_context *ctx,
+ struct bio *bio_out, struct bio *bio_in,
+ sector_t sector, int write)
{
ctx->bio_in = bio_in;
ctx->bio_out = bio_out;
@@ -338,7 +340,7 @@ crypt_convert_init(struct crypt_config *cc, struct convert_context *ctx,
* Encrypt / decrypt data from one bio to another one (can be the same one)
*/
static int crypt_convert(struct crypt_config *cc,
- struct convert_context *ctx)
+ struct convert_context *ctx)
{
int r = 0;
@@ -346,16 +348,13 @@ static int crypt_convert(struct crypt_config *cc,
ctx->idx_out < ctx->bio_out->bi_vcnt) {
struct bio_vec *bv_in = bio_iovec_idx(ctx->bio_in, ctx->idx_in);
struct bio_vec *bv_out = bio_iovec_idx(ctx->bio_out, ctx->idx_out);
- struct scatterlist sg_in = {
- .page = bv_in->bv_page,
- .offset = bv_in->bv_offset + ctx->offset_in,
- .length = 1 << SECTOR_SHIFT
- };
- struct scatterlist sg_out = {
- .page = bv_out->bv_page,
- .offset = bv_out->bv_offset + ctx->offset_out,
- .length = 1 << SECTOR_SHIFT
- };
+ struct scatterlist sg_in, sg_out;
+
+ sg_init_table(&sg_in, 1);
+ sg_set_page(&sg_in, bv_in->bv_page, 1 << SECTOR_SHIFT, bv_in->bv_offset + ctx->offset_in);
+
+ sg_init_table(&sg_out, 1);
+ sg_set_page(&sg_out, bv_out->bv_page, 1 << SECTOR_SHIFT, bv_out->bv_offset + ctx->offset_out);
ctx->offset_in += sg_in.length;
if (ctx->offset_in >= bv_in->bv_len) {
@@ -370,7 +369,7 @@ static int crypt_convert(struct crypt_config *cc,
}
r = crypt_convert_scatterlist(cc, &sg_out, &sg_in, sg_in.length,
- ctx->write, ctx->sector);
+ ctx->write, ctx->sector);
if (r < 0)
break;
@@ -380,13 +379,13 @@ static int crypt_convert(struct crypt_config *cc,
return r;
}
- static void dm_crypt_bio_destructor(struct bio *bio)
- {
+static void dm_crypt_bio_destructor(struct bio *bio)
+{
struct dm_crypt_io *io = bio->bi_private;
struct crypt_config *cc = io->target->private;
bio_free(bio, cc->bs);
- }
+}
/*
* Generate a new unfragmented bio with the given size
@@ -441,33 +440,12 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
return clone;
}
-static void crypt_free_buffer_pages(struct crypt_config *cc,
- struct bio *clone, unsigned int bytes)
+static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone)
{
- unsigned int i, start, end;
+ unsigned int i;
struct bio_vec *bv;
- /*
- * This is ugly, but Jens Axboe thinks that using bi_idx in the
- * endio function is too dangerous at the moment, so I calculate the
- * correct position using bi_vcnt and bi_size.
- * The bv_offset and bv_len fields might already be modified but we
- * know that we always allocated whole pages.
- * A fix to the bi_idx issue in the kernel is in the works, so
- * we will hopefully be able to revert to the cleaner solution soon.
- */
- i = clone->bi_vcnt - 1;
- bv = bio_iovec_idx(clone, i);
- end = (i << PAGE_SHIFT) + (bv->bv_offset + bv->bv_len) - clone->bi_size;
- start = end - bytes;
-
- start >>= PAGE_SHIFT;
- if (!clone->bi_size)
- end = clone->bi_vcnt;
- else
- end >>= PAGE_SHIFT;
-
- for (i = start; i < end; i++) {
+ for (i = 0; i < clone->bi_vcnt; i++) {
bv = bio_iovec_idx(clone, i);
BUG_ON(!bv->bv_page);
mempool_free(bv->bv_page, cc->page_pool);
@@ -479,7 +457,7 @@ static void crypt_free_buffer_pages(struct crypt_config *cc,
* One of the bios was finished. Check for completion of
* the whole request and correctly clean up the buffer.
*/
-static void dec_pending(struct dm_crypt_io *io, int error)
+static void crypt_dec_pending(struct dm_crypt_io *io, int error)
{
struct crypt_config *cc = (struct crypt_config *) io->target->private;
@@ -489,45 +467,57 @@ static void dec_pending(struct dm_crypt_io *io, int error)
if (!atomic_dec_and_test(&io->pending))
return;
- bio_endio(io->base_bio, io->base_bio->bi_size, io->error);
+ bio_endio(io->base_bio, io->error);
mempool_free(io, cc->io_pool);
}
/*
- * kcryptd:
+ * kcryptd/kcryptd_io:
*
* Needed because it would be very unwise to do decryption in an
* interrupt context.
+ *
+ * kcryptd performs the actual encryption or decryption.
+ *
+ * kcryptd_io performs the IO submission.
+ *
+ * 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.
*/
-static struct workqueue_struct *_kcryptd_workqueue;
static void kcryptd_do_work(struct work_struct *work);
+static void kcryptd_do_crypt(struct work_struct *work);
static void kcryptd_queue_io(struct dm_crypt_io *io)
{
+ struct crypt_config *cc = io->target->private;
+
INIT_WORK(&io->work, kcryptd_do_work);
- queue_work(_kcryptd_workqueue, &io->work);
+ queue_work(cc->io_queue, &io->work);
}
-static int crypt_endio(struct bio *clone, unsigned int done, int error)
+static void kcryptd_queue_crypt(struct dm_crypt_io *io)
+{
+ struct crypt_config *cc = io->target->private;
+
+ INIT_WORK(&io->work, kcryptd_do_crypt);
+ queue_work(cc->crypt_queue, &io->work);
+}
+
+static void crypt_endio(struct bio *clone, int error)
{
struct dm_crypt_io *io = clone->bi_private;
struct crypt_config *cc = io->target->private;
unsigned read_io = bio_data_dir(clone) == READ;
/*
- * free the processed pages, even if
- * it's only a partially completed write
+ * free the processed pages
*/
- if (!read_io)
- crypt_free_buffer_pages(cc, clone, done);
-
- /* keep going - not finished yet */
- if (unlikely(clone->bi_size))
- return 1;
-
- if (!read_io)
+ if (!read_io) {
+ crypt_free_buffer_pages(cc, clone);
goto out;
+ }
if (unlikely(!bio_flagged(clone, BIO_UPTODATE))) {
error = -EIO;
@@ -535,14 +525,12 @@ static int crypt_endio(struct bio *clone, unsigned int done, int error)
}
bio_put(clone);
- io->post_process = 1;
- kcryptd_queue_io(io);
- return 0;
+ kcryptd_queue_crypt(io);
+ return;
out:
bio_put(clone);
- dec_pending(io, error);
- return error;
+ crypt_dec_pending(io, error);
}
static void clone_init(struct dm_crypt_io *io, struct bio *clone)
@@ -572,7 +560,7 @@ static void process_read(struct dm_crypt_io *io)
*/
clone = bio_alloc_bioset(GFP_NOIO, bio_segments(base_bio), cc->bs);
if (unlikely(!clone)) {
- dec_pending(io, -ENOMEM);
+ crypt_dec_pending(io, -ENOMEM);
return;
}
@@ -607,7 +595,7 @@ static void process_write(struct dm_crypt_io *io)
while (remaining) {
clone = crypt_alloc_buffer(io, remaining);
if (unlikely(!clone)) {
- dec_pending(io, -ENOMEM);
+ crypt_dec_pending(io, -ENOMEM);
return;
}
@@ -615,9 +603,9 @@ static void process_write(struct dm_crypt_io *io)
ctx.idx_out = 0;
if (unlikely(crypt_convert(cc, &ctx) < 0)) {
- crypt_free_buffer_pages(cc, clone, clone->bi_size);
+ crypt_free_buffer_pages(cc, clone);
bio_put(clone);
- dec_pending(io, -EIO);
+ crypt_dec_pending(io, -EIO);
return;
}
@@ -652,17 +640,23 @@ static void process_read_endio(struct dm_crypt_io *io)
crypt_convert_init(cc, &ctx, io->base_bio, io->base_bio,
io->base_bio->bi_sector - io->target->begin, 0);
- dec_pending(io, crypt_convert(cc, &ctx));
+ crypt_dec_pending(io, crypt_convert(cc, &ctx));
}
static void kcryptd_do_work(struct work_struct *work)
{
struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
- if (io->post_process)
- process_read_endio(io);
- else if (bio_data_dir(io->base_bio) == READ)
+ if (bio_data_dir(io->base_bio) == READ)
process_read(io);
+}
+
+static void kcryptd_do_crypt(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)
+ process_read_endio(io);
else
process_write(io);
}
@@ -718,7 +712,7 @@ static int crypt_set_key(struct crypt_config *cc, char *key)
cc->key_size = key_size; /* initial settings */
if ((!key_size && strcmp(key, "-")) ||
- (key_size && crypt_decode_key(cc->key, key, key_size) < 0))
+ (key_size && crypt_decode_key(cc->key, key, key_size) < 0))
return -EINVAL;
set_bit(DM_CRYPT_KEY_VALID, &cc->flags);
@@ -774,7 +768,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (crypt_set_key(cc, argv[1])) {
ti->error = "Error decoding key";
- goto bad1;
+ goto bad_cipher;
}
/* Compatiblity mode for old dm-crypt cipher strings */
@@ -785,19 +779,19 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (strcmp(chainmode, "ecb") && !ivmode) {
ti->error = "This chaining mode requires an IV mechanism";
- goto bad1;
+ goto bad_cipher;
}
- if (snprintf(cc->cipher, CRYPTO_MAX_ALG_NAME, "%s(%s)", chainmode,
- cipher) >= CRYPTO_MAX_ALG_NAME) {
+ if (snprintf(cc->cipher, CRYPTO_MAX_ALG_NAME, "%s(%s)",
+ chainmode, cipher) >= CRYPTO_MAX_ALG_NAME) {
ti->error = "Chain mode + cipher name is too long";
- goto bad1;
+ goto bad_cipher;
}
tfm = crypto_alloc_blkcipher(cc->cipher, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm)) {
ti->error = "Error allocating crypto tfm";
- goto bad1;
+ goto bad_cipher;
}
strcpy(cc->cipher, cipher);
@@ -821,18 +815,18 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
cc->iv_gen_ops = &crypt_iv_null_ops;
else {
ti->error = "Invalid IV mode";
- goto bad2;
+ goto bad_ivmode;
}
if (cc->iv_gen_ops && cc->iv_gen_ops->ctr &&
cc->iv_gen_ops->ctr(cc, ti, ivopts) < 0)
- goto bad2;
+ goto bad_ivmode;
cc->iv_size = crypto_blkcipher_ivsize(tfm);
if (cc->iv_size)
/* at least a 64 bit sector number should fit in our buffer */
cc->iv_size = max(cc->iv_size,
- (unsigned int)(sizeof(u64) / sizeof(u8)));
+ (unsigned int)(sizeof(u64) / sizeof(u8)));
else {
if (cc->iv_gen_ops) {
DMWARN("Selected cipher does not support IVs");
@@ -845,13 +839,13 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool);
if (!cc->io_pool) {
ti->error = "Cannot allocate crypt io mempool";
- goto bad3;
+ goto bad_slab_pool;
}
cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
if (!cc->page_pool) {
ti->error = "Cannot allocate page mempool";
- goto bad4;
+ goto bad_page_pool;
}
cc->bs = bioset_create(MIN_IOS, MIN_IOS);
@@ -862,25 +856,25 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (crypto_blkcipher_setkey(tfm, cc->key, key_size) < 0) {
ti->error = "Error setting key";
- goto bad5;
+ goto bad_device;
}
if (sscanf(argv[2], "%llu", &tmpll) != 1) {
ti->error = "Invalid iv_offset sector";
- goto bad5;
+ goto bad_device;
}
cc->iv_offset = tmpll;
if (sscanf(argv[4], "%llu", &tmpll) != 1) {
ti->error = "Invalid device sector";
- goto bad5;
+ goto bad_device;
}
cc->start = tmpll;
if (dm_get_device(ti, argv[3], cc->start, ti->len,
- dm_table_get_mode(ti->table), &cc->dev)) {
+ dm_table_get_mode(ti->table), &cc->dev)) {
ti->error = "Device lookup failed";
- goto bad5;
+ goto bad_device;
}
if (ivmode && cc->iv_gen_ops) {
@@ -889,27 +883,45 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
cc->iv_mode = kmalloc(strlen(ivmode) + 1, GFP_KERNEL);
if (!cc->iv_mode) {
ti->error = "Error kmallocing iv_mode string";
- goto bad5;
+ goto bad_ivmode_string;
}
strcpy(cc->iv_mode, ivmode);
} else
cc->iv_mode = NULL;
+ cc->io_queue = create_singlethread_workqueue("kcryptd_io");
+ if (!cc->io_queue) {
+ ti->error = "Couldn't create kcryptd io queue";
+ goto bad_io_queue;
+ }
+
+ cc->crypt_queue = create_singlethread_workqueue("kcryptd");
+ if (!cc->crypt_queue) {
+ ti->error = "Couldn't create kcryptd queue";
+ goto bad_crypt_queue;
+ }
+
ti->private = cc;
return 0;
-bad5:
+bad_crypt_queue:
+ destroy_workqueue(cc->io_queue);
+bad_io_queue:
+ kfree(cc->iv_mode);
+bad_ivmode_string:
+ dm_put_device(ti, cc->dev);
+bad_device:
bioset_free(cc->bs);
bad_bs:
mempool_destroy(cc->page_pool);
-bad4:
+bad_page_pool:
mempool_destroy(cc->io_pool);
-bad3:
+bad_slab_pool:
if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
cc->iv_gen_ops->dtr(cc);
-bad2:
+bad_ivmode:
crypto_free_blkcipher(tfm);
-bad1:
+bad_cipher:
/* Must zero key material before freeing */
memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8));
kfree(cc);
@@ -920,7 +932,8 @@ static void crypt_dtr(struct dm_target *ti)
{
struct crypt_config *cc = (struct crypt_config *) ti->private;
- flush_workqueue(_kcryptd_workqueue);
+ destroy_workqueue(cc->io_queue);
+ destroy_workqueue(cc->crypt_queue);
bioset_free(cc->bs);
mempool_destroy(cc->page_pool);
@@ -946,9 +959,13 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
io = mempool_alloc(cc->io_pool, GFP_NOIO);
io->target = ti;
io->base_bio = bio;
- io->error = io->post_process = 0;
+ io->error = 0;
atomic_set(&io->pending, 0);
- kcryptd_queue_io(io);
+
+ if (bio_data_dir(io->base_bio) == READ)
+ kcryptd_queue_io(io);
+ else
+ kcryptd_queue_crypt(io);
return DM_MAPIO_SUBMITTED;
}
@@ -1065,25 +1082,12 @@ static int __init dm_crypt_init(void)
if (!_crypt_io_pool)
return -ENOMEM;
- _kcryptd_workqueue = create_workqueue("kcryptd");
- if (!_kcryptd_workqueue) {
- r = -ENOMEM;
- DMERR("couldn't create kcryptd");
- goto bad1;
- }
-
r = dm_register_target(&crypt_target);
if (r < 0) {
DMERR("register failed %d", r);
- goto bad2;
+ kmem_cache_destroy(_crypt_io_pool);
}
- return 0;
-
-bad2:
- destroy_workqueue(_kcryptd_workqueue);
-bad1:
- kmem_cache_destroy(_crypt_io_pool);
return r;
}
@@ -1094,7 +1098,6 @@ static void __exit dm_crypt_exit(void)
if (r < 0)
DMERR("unregister failed %d", r);
- destroy_workqueue(_kcryptd_workqueue);
kmem_cache_destroy(_crypt_io_pool);
}
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
index 6928c136d3c..bdd37f881c4 100644
--- a/drivers/md/dm-delay.c
+++ b/drivers/md/dm-delay.c
@@ -83,7 +83,7 @@ static struct bio *flush_delayed_bios(struct delay_c *dc, int flush_all)
struct dm_delay_info *delayed, *next;
unsigned long next_expires = 0;
int start_timer = 0;
- BIO_LIST(flush_bios);
+ struct bio_list flush_bios = { };
mutex_lock(&delayed_bios_lock);
list_for_each_entry_safe(delayed, next, &dc->delayed_bios, list) {
@@ -163,34 +163,32 @@ static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad;
}
- if (argc == 3) {
- dc->dev_write = NULL;
+ dc->dev_write = NULL;
+ if (argc == 3)
goto out;
- }
if (sscanf(argv[4], "%llu", &tmpll) != 1) {
ti->error = "Invalid write device sector";
- goto bad;
+ goto bad_dev_read;
}
dc->start_write = tmpll;
if (sscanf(argv[5], "%u", &dc->write_delay) != 1) {
ti->error = "Invalid write delay";
- goto bad;
+ goto bad_dev_read;
}
if (dm_get_device(ti, argv[3], dc->start_write, ti->len,
dm_table_get_mode(ti->table), &dc->dev_write)) {
ti->error = "Write device lookup failed";
- dm_put_device(ti, dc->dev_read);
- goto bad;
+ goto bad_dev_read;
}
out:
dc->delayed_pool = mempool_create_slab_pool(128, delayed_cache);
if (!dc->delayed_pool) {
DMERR("Couldn't create delayed bio pool.");
- goto bad;
+ goto bad_dev_write;
}
setup_timer(&dc->delay_timer, handle_delayed_timer, (unsigned long)dc);
@@ -203,6 +201,11 @@ out:
ti->private = dc;
return 0;
+bad_dev_write:
+ if (dc->dev_write)
+ dm_put_device(ti, dc->dev_write);
+bad_dev_read:
+ dm_put_device(ti, dc->dev_read);
bad:
kfree(dc);
return -EINVAL;
@@ -305,7 +308,7 @@ static int delay_status(struct dm_target *ti, status_type_t type,
(unsigned long long) dc->start_read,
dc->read_delay);
if (dc->dev_write)
- DMEMIT("%s %llu %u", dc->dev_write->name,
+ DMEMIT(" %s %llu %u", dc->dev_write->name,
(unsigned long long) dc->start_write,
dc->write_delay);
break;
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c
index 265c467854d..6b91b9ab1d4 100644
--- a/drivers/md/dm-emc.c
+++ b/drivers/md/dm-emc.c
@@ -38,13 +38,10 @@ static inline void free_bio(struct bio *bio)
bio_put(bio);
}
-static int emc_endio(struct bio *bio, unsigned int bytes_done, int error)
+static void emc_endio(struct bio *bio, int error)
{
struct dm_path *path = bio->bi_private;
- if (bio->bi_size)
- return 1;
-
/* We also need to look at the sense keys here whether or not to
* switch to the next PG etc.
*
@@ -57,8 +54,6 @@ static int emc_endio(struct bio *bio, unsigned int bytes_done, int error)
/* request is freed in block layer */
free_bio(bio);
-
- return 0;
}
static struct bio *get_failover_bio(struct dm_path *path, unsigned data_size)
@@ -86,7 +81,7 @@ static struct bio *get_failover_bio(struct dm_path *path, unsigned data_size)
}
if (bio_add_page(bio, page, data_size, 0) != data_size) {
- DMERR("get_failover_bio: alloc_page() failed.");
+ DMERR("get_failover_bio: bio_add_page() failed.");
__free_page(page);
bio_put(bio);
return NULL;
@@ -109,15 +104,7 @@ static struct request *get_failover_req(struct emc_handler *h,
return NULL;
}
- rq->bio = rq->biotail = bio;
- blk_rq_bio_prep(q, rq, bio);
-
- rq->rq_disk = bdev->bd_contains->bd_disk;
-
- /* bio backed don't set data */
- rq->buffer = rq->data = NULL;
- /* rq data_len used for pc cmd's request_bufflen */
- rq->data_len = bio->bi_size;
+ blk_rq_append_bio(q, rq, bio);
rq->sense = h->sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
@@ -224,12 +211,10 @@ fail_path:
static struct emc_handler *alloc_emc_handler(void)
{
- struct emc_handler *h = kmalloc(sizeof(*h), GFP_KERNEL);
+ struct emc_handler *h = kzalloc(sizeof(*h), GFP_KERNEL);
- if (h) {
- memset(h, 0, sizeof(*h));
+ if (h)
spin_lock_init(&h->lock);
- }
return h;
}
diff --git a/drivers/md/dm-hw-handler.c b/drivers/md/dm-hw-handler.c
index baafaaba4d4..2ee84d8aa0b 100644
--- a/drivers/md/dm-hw-handler.c
+++ b/drivers/md/dm-hw-handler.c
@@ -91,12 +91,10 @@ void dm_put_hw_handler(struct hw_handler_type *hwht)
static struct hwh_internal *_alloc_hw_handler(struct hw_handler_type *hwht)
{
- struct hwh_internal *hwhi = kmalloc(sizeof(*hwhi), GFP_KERNEL);
+ struct hwh_internal *hwhi = kzalloc(sizeof(*hwhi), GFP_KERNEL);
- if (hwhi) {
- memset(hwhi, 0, sizeof(*hwhi));
+ if (hwhi)
hwhi->hwht = *hwht;
- }
return hwhi;
}
diff --git a/drivers/md/dm-hw-handler.h b/drivers/md/dm-hw-handler.h
index e0832e6fcf3..46809dcb121 100644
--- a/drivers/md/dm-hw-handler.h
+++ b/drivers/md/dm-hw-handler.h
@@ -58,5 +58,6 @@ unsigned dm_scsi_err_handler(struct hw_handler *hwh, struct bio *bio);
#define MP_FAIL_PATH 1
#define MP_BYPASS_PG 2
#define MP_ERROR_IO 4 /* Don't retry this I/O */
+#define MP_RETRY 8
#endif
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index f3a77248643..b8e342fe758 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -124,15 +124,11 @@ static void dec_count(struct io *io, unsigned int region, int error)
}
}
-static int endio(struct bio *bio, unsigned int done, int error)
+static void endio(struct bio *bio, int error)
{
struct io *io;
unsigned region;
- /* keep going until we've finished */
- if (bio->bi_size)
- return 1;
-
if (error && bio_data_dir(bio) == READ)
zero_fill_bio(bio);
@@ -146,8 +142,6 @@ static int endio(struct bio *bio, unsigned int done, int error)
bio_put(bio);
dec_count(io, region, error);
-
- return 0;
}
/*-----------------------------------------------------------------
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index b441d82c338..138200bf5e0 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -700,7 +700,7 @@ static int dev_rename(struct dm_ioctl *param, size_t param_size)
int r;
char *new_name = (char *) param + param->data_start;
- if (new_name < (char *) (param + 1) ||
+ if (new_name < (char *) param->data ||
invalid_str(new_name, (void *) param + param_size)) {
DMWARN("Invalid new logical volume name supplied.");
return -EINVAL;
@@ -726,7 +726,7 @@ static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
if (!md)
return -ENXIO;
- if (geostr < (char *) (param + 1) ||
+ if (geostr < (char *) param->data ||
invalid_str(geostr, (void *) param + param_size)) {
DMWARN("Invalid geometry supplied.");
goto out;
@@ -1233,7 +1233,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
if (r)
goto out;
- if (tmsg < (struct dm_target_msg *) (param + 1) ||
+ if (tmsg < (struct dm_target_msg *) param->data ||
invalid_str(tmsg->message, (void *) param + param_size)) {
DMWARN("Invalid target message parameters.");
r = -EINVAL;
@@ -1358,7 +1358,7 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param)
if (tmp.data_size < sizeof(tmp))
return -EINVAL;
- dmi = (struct dm_ioctl *) vmalloc(tmp.data_size);
+ dmi = vmalloc(tmp.data_size);
if (!dmi)
return -ENOMEM;
@@ -1515,3 +1515,35 @@ void dm_interface_exit(void)
dm_hash_exit();
}
+
+/**
+ * dm_copy_name_and_uuid - Copy mapped device name & uuid into supplied buffers
+ * @md: Pointer to mapped_device
+ * @name: Buffer (size DM_NAME_LEN) for name
+ * @uuid: Buffer (size DM_UUID_LEN) for uuid or empty string if uuid not defined
+ */
+int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid)
+{
+ int r = 0;
+ struct hash_cell *hc;
+
+ if (!md)
+ return -ENXIO;
+
+ dm_get(md);
+ down_read(&_hash_lock);
+ hc = dm_get_mdptr(md);
+ if (!hc || hc->md != md) {
+ r = -ENXIO;
+ goto out;
+ }
+
+ strcpy(name, hc->name);
+ strcpy(uuid, hc->uuid ? : "");
+
+out:
+ up_read(&_hash_lock);
+ dm_put(md);
+
+ return r;
+}
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index a66428d860f..072ee4353ea 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -696,7 +696,7 @@ static struct dirty_log_type _disk_type = {
.module = THIS_MODULE,
.ctr = disk_ctr,
.dtr = disk_dtr,
- .suspend = disk_flush,
+ .postsuspend = disk_flush,
.resume = disk_resume,
.get_region_size = core_get_region_size,
.is_clean = core_is_clean,
diff --git a/drivers/md/dm-log.h b/drivers/md/dm-log.h
index 86a301c8daf..3fae87eb596 100644
--- a/drivers/md/dm-log.h
+++ b/drivers/md/dm-log.h
@@ -32,7 +32,8 @@ struct dirty_log_type {
* There are times when we don't want the log to touch
* the disk.
*/
- int (*suspend)(struct dirty_log *log);
+ int (*presuspend)(struct dirty_log *log);
+ int (*postsuspend)(struct dirty_log *log);
int (*resume)(struct dirty_log *log);
/*
diff --git a/drivers/md/dm-mpath-hp-sw.c b/drivers/md/dm-mpath-hp-sw.c
new file mode 100644
index 00000000000..204bf42c944
--- /dev/null
+++ b/drivers/md/dm-mpath-hp-sw.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2005 Mike Christie, All rights reserved.
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+ * Authors: Mike Christie
+ * Dave Wysochanski
+ *
+ * This file is released under the GPL.
+ *
+ * This module implements the specific path activation code for
+ * HP StorageWorks and FSC FibreCat Asymmetric (Active/Passive)
+ * storage arrays.
+ * These storage arrays have controller-based failover, not
+ * LUN-based failover. However, LUN-based failover is the design
+ * of dm-multipath. Thus, this module is written for LUN-based failover.
+ */
+#include <linux/blkdev.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+
+#include "dm.h"
+#include "dm-hw-handler.h"
+
+#define DM_MSG_PREFIX "multipath hp-sw"
+#define DM_HP_HWH_NAME "hp-sw"
+#define DM_HP_HWH_VER "1.0.0"
+
+struct hp_sw_context {
+ unsigned char sense[SCSI_SENSE_BUFFERSIZE];
+};
+
+/*
+ * hp_sw_error_is_retryable - Is an HP-specific check condition retryable?
+ * @req: path activation request
+ *
+ * Examine error codes of request and determine whether the error is retryable.
+ * Some error codes are already retried by scsi-ml (see
+ * scsi_decide_disposition), but some HP specific codes are not.
+ * The intent of this routine is to supply the logic for the HP specific
+ * check conditions.
+ *
+ * Returns:
+ * 1 - command completed with retryable error
+ * 0 - command completed with non-retryable error
+ *
+ * Possible optimizations
+ * 1. More hardware-specific error codes
+ */
+static int hp_sw_error_is_retryable(struct request *req)
+{
+ /*
+ * NOT_READY is known to be retryable
+ * For now we just dump out the sense data and call it retryable
+ */
+ if (status_byte(req->errors) == CHECK_CONDITION)
+ __scsi_print_sense(DM_HP_HWH_NAME, req->sense, req->sense_len);
+
+ /*
+ * At this point we don't have complete information about all the error
+ * codes from this hardware, so we are just conservative and retry
+ * when in doubt.
+ */
+ return 1;
+}
+
+/*
+ * hp_sw_end_io - Completion handler for HP path activation.
+ * @req: path activation request
+ * @error: scsi-ml error
+ *
+ * Check sense data, free request structure, and notify dm that
+ * pg initialization has completed.
+ *
+ * Context: scsi-ml softirq
+ *
+ */
+static void hp_sw_end_io(struct request *req, int error)
+{
+ struct dm_path *path = req->end_io_data;
+ unsigned err_flags = 0;
+
+ if (!error) {
+ DMDEBUG("%s path activation command - success",
+ path->dev->name);
+ goto out;
+ }
+
+ if (hp_sw_error_is_retryable(req)) {
+ DMDEBUG("%s path activation command - retry",
+ path->dev->name);
+ err_flags = MP_RETRY;
+ goto out;
+ }
+
+ DMWARN("%s path activation fail - error=0x%x",
+ path->dev->name, error);
+ err_flags = MP_FAIL_PATH;
+
+out:
+ req->end_io_data = NULL;
+ __blk_put_request(req->q, req);
+ dm_pg_init_complete(path, err_flags);
+}
+
+/*
+ * hp_sw_get_request - Allocate an HP specific path activation request
+ * @path: path on which request will be sent (needed for request queue)
+ *
+ * The START command is used for path activation request.
+ * These arrays are controller-based failover, not LUN based.
+ * One START command issued to a single path will fail over all
+ * LUNs for the same controller.
+ *
+ * Possible optimizations
+ * 1. Make timeout configurable
+ * 2. Preallocate request
+ */
+static struct request *hp_sw_get_request(struct dm_path *path)
+{
+ struct request *req;
+ struct block_device *bdev = path->dev->bdev;
+ struct request_queue *q = bdev_get_queue(bdev);
+ struct hp_sw_context *h = path->hwhcontext;
+
+ req = blk_get_request(q, WRITE, GFP_NOIO);
+ if (!req)
+ goto out;
+
+ req->timeout = 60 * HZ;
+
+ req->errors = 0;
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ req->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
+ req->end_io_data = path;
+ req->sense = h->sense;
+ memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
+
+ memset(&req->cmd, 0, BLK_MAX_CDB);
+ req->cmd[0] = START_STOP;
+ req->cmd[4] = 1;
+ req->cmd_len = COMMAND_SIZE(req->cmd[0]);
+
+out:
+ return req;
+}
+
+/*
+ * hp_sw_pg_init - HP path activation implementation.
+ * @hwh: hardware handler specific data
+ * @bypassed: unused; is the path group bypassed? (see dm-mpath.c)
+ * @path: path to send initialization command
+ *
+ * Send an HP-specific path activation command on 'path'.
+ * Do not try to optimize in any way, just send the activation command.
+ * More than one path activation command may be sent to the same controller.
+ * This seems to work fine for basic failover support.
+ *
+ * Possible optimizations
+ * 1. Detect an in-progress activation request and avoid submitting another one
+ * 2. Model the controller and only send a single activation request at a time
+ * 3. Determine the state of a path before sending an activation request
+ *
+ * Context: kmpathd (see process_queued_ios() in dm-mpath.c)
+ */
+static void hp_sw_pg_init(struct hw_handler *hwh, unsigned bypassed,
+ struct dm_path *path)
+{
+ struct request *req;
+ struct hp_sw_context *h;
+
+ path->hwhcontext = hwh->context;
+ h = hwh->context;
+
+ req = hp_sw_get_request(path);
+ if (!req) {
+ DMERR("%s path activation command - allocation fail",
+ path->dev->name);
+ goto retry;
+ }
+
+ DMDEBUG("%s path activation command - sent", path->dev->name);
+
+ blk_execute_rq_nowait(req->q, NULL, req, 1, hp_sw_end_io);
+ return;
+
+retry:
+ dm_pg_init_complete(path, MP_RETRY);
+}
+
+static int hp_sw_create(struct hw_handler *hwh, unsigned argc, char **argv)
+{
+ struct hp_sw_context *h;
+
+ h = kmalloc(sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return -ENOMEM;
+
+ hwh->context = h;
+
+ return 0;
+}
+
+static void hp_sw_destroy(struct hw_handler *hwh)
+{
+ struct hp_sw_context *h = hwh->context;
+
+ kfree(h);
+}
+
+static struct hw_handler_type hp_sw_hwh = {
+ .name = DM_HP_HWH_NAME,
+ .module = THIS_MODULE,
+ .create = hp_sw_create,
+ .destroy = hp_sw_destroy,
+ .pg_init = hp_sw_pg_init,
+};
+
+static int __init hp_sw_init(void)
+{
+ int r;
+
+ r = dm_register_hw_handler(&hp_sw_hwh);
+ if (r < 0)
+ DMERR("register failed %d", r);
+ else
+ DMINFO("version " DM_HP_HWH_VER " loaded");
+
+ return r;
+}
+
+static void __exit hp_sw_exit(void)
+{
+ int r;
+
+ r = dm_unregister_hw_handler(&hp_sw_hwh);
+ if (r < 0)
+ DMERR("unregister failed %d", r);
+}
+
+module_init(hp_sw_init);
+module_exit(hp_sw_exit);
+
+MODULE_DESCRIPTION("DM Multipath HP StorageWorks / FSC FibreCat (A/P) support");
+MODULE_AUTHOR("Mike Christie, Dave Wysochanski <dm-devel@redhat.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DM_HP_HWH_VER);
diff --git a/drivers/md/dm-mpath-rdac.c b/drivers/md/dm-mpath-rdac.c
index 16b16134577..e04eb5c697f 100644
--- a/drivers/md/dm-mpath-rdac.c
+++ b/drivers/md/dm-mpath-rdac.c
@@ -664,20 +664,21 @@ static struct hw_handler_type rdac_handler = {
static int __init rdac_init(void)
{
- int r = dm_register_hw_handler(&rdac_handler);
-
- if (r < 0) {
- DMERR("%s: register failed %d", RDAC_DM_HWH_NAME, r);
- return r;
- }
+ int r;
rdac_wkqd = create_singlethread_workqueue("rdac_wkqd");
if (!rdac_wkqd) {
DMERR("Failed to create workqueue rdac_wkqd.");
- dm_unregister_hw_handler(&rdac_handler);
return -ENOMEM;
}
+ r = dm_register_hw_handler(&rdac_handler);
+ if (r < 0) {
+ DMERR("%s: register failed %d", RDAC_DM_HWH_NAME, r);
+ destroy_workqueue(rdac_wkqd);
+ return r;
+ }
+
DMINFO("%s: version %s loaded", RDAC_DM_HWH_NAME, RDAC_DM_HWH_VER);
return 0;
}
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index d6ca9d0a6fd..24b2b1e32fa 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -10,6 +10,7 @@
#include "dm-hw-handler.h"
#include "dm-bio-list.h"
#include "dm-bio-record.h"
+#include "dm-uevent.h"
#include <linux/ctype.h>
#include <linux/init.h>
@@ -75,6 +76,8 @@ struct multipath {
unsigned queue_io; /* Must we queue all I/O? */
unsigned queue_if_no_path; /* Queue I/O if last path fails? */
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 */
struct work_struct process_queued_ios;
struct bio_list queued_ios;
@@ -225,6 +228,8 @@ static void __switch_pg(struct multipath *m, struct pgpath *pgpath)
m->pg_init_required = 0;
m->queue_io = 0;
}
+
+ m->pg_init_count = 0;
}
static int __choose_path_in_pg(struct multipath *m, struct priority_group *pg)
@@ -390,11 +395,11 @@ static void dispatch_queued_ios(struct multipath *m)
r = map_io(m, bio, mpio, 1);
if (r < 0)
- bio_endio(bio, bio->bi_size, r);
+ bio_endio(bio, r);
else if (r == DM_MAPIO_REMAPPED)
generic_make_request(bio);
else if (r == DM_MAPIO_REQUEUE)
- bio_endio(bio, bio->bi_size, -EIO);
+ bio_endio(bio, -EIO);
bio = next;
}
@@ -424,6 +429,7 @@ static void process_queued_ios(struct work_struct *work)
must_queue = 0;
if (m->pg_init_required && !m->pg_init_in_progress) {
+ m->pg_init_count++;
m->pg_init_required = 0;
m->pg_init_in_progress = 1;
init_required = 1;
@@ -689,9 +695,11 @@ static int parse_features(struct arg_set *as, struct multipath *m)
int r;
unsigned argc;
struct dm_target *ti = m->ti;
+ const char *param_name;
static struct param _params[] = {
- {0, 1, "invalid number of feature args"},
+ {0, 3, "invalid number of feature args"},
+ {1, 50, "pg_init_retries must be between 1 and 50"},
};
r = read_param(_params, shift(as), &argc, &ti->error);
@@ -701,12 +709,28 @@ static int parse_features(struct arg_set *as, struct multipath *m)
if (!argc)
return 0;
- if (!strnicmp(shift(as), MESG_STR("queue_if_no_path")))
- return queue_if_no_path(m, 1, 0);
- else {
+ do {
+ param_name = shift(as);
+ argc--;
+
+ if (!strnicmp(param_name, MESG_STR("queue_if_no_path"))) {
+ r = queue_if_no_path(m, 1, 0);
+ continue;
+ }
+
+ if (!strnicmp(param_name, MESG_STR("pg_init_retries")) &&
+ (argc >= 1)) {
+ r = read_param(_params + 1, shift(as),
+ &m->pg_init_retries, &ti->error);
+ argc--;
+ continue;
+ }
+
ti->error = "Unrecognised multipath feature request";
- return -EINVAL;
- }
+ r = -EINVAL;
+ } while (argc && !r);
+
+ return r;
}
static int multipath_ctr(struct dm_target *ti, unsigned int argc,
@@ -834,6 +858,9 @@ static int fail_path(struct pgpath *pgpath)
if (pgpath == m->current_pgpath)
m->current_pgpath = NULL;
+ dm_path_uevent(DM_UEVENT_PATH_FAILED, m->ti,
+ pgpath->path.dev->name, m->nr_valid_paths);
+
queue_work(kmultipathd, &m->trigger_event);
out:
@@ -873,6 +900,9 @@ static int reinstate_path(struct pgpath *pgpath)
if (!m->nr_valid_paths++ && m->queue_size)
queue_work(kmultipathd, &m->process_queued_ios);
+ dm_path_uevent(DM_UEVENT_PATH_REINSTATED, m->ti,
+ pgpath->path.dev->name, m->nr_valid_paths);
+
queue_work(kmultipathd, &m->trigger_event);
out:
@@ -976,6 +1006,26 @@ static int bypass_pg_num(struct multipath *m, const char *pgstr, int bypassed)
}
/*
+ * Should we retry pg_init immediately?
+ */
+static int pg_init_limit_reached(struct multipath *m, struct pgpath *pgpath)
+{
+ unsigned long flags;
+ int limit_reached = 0;
+
+ spin_lock_irqsave(&m->lock, flags);
+
+ if (m->pg_init_count <= m->pg_init_retries)
+ m->pg_init_required = 1;
+ else
+ limit_reached = 1;
+
+ spin_unlock_irqrestore(&m->lock, flags);
+
+ return limit_reached;
+}
+
+/*
* pg_init must call this when it has completed its initialisation
*/
void dm_pg_init_complete(struct dm_path *path, unsigned err_flags)
@@ -985,8 +1035,14 @@ void dm_pg_init_complete(struct dm_path *path, unsigned err_flags)
struct multipath *m = pg->m;
unsigned long flags;
- /* We insist on failing the path if the PG is already bypassed. */
- if (err_flags && pg->bypassed)
+ /*
+ * If requested, retry pg_init until maximum number of retries exceeded.
+ * If retry not requested and PG already bypassed, always fail the path.
+ */
+ if (err_flags & MP_RETRY) {
+ if (pg_init_limit_reached(m, pgpath))
+ err_flags |= MP_FAIL_PATH;
+ } else if (err_flags && pg->bypassed)
err_flags |= MP_FAIL_PATH;
if (err_flags & MP_FAIL_PATH)
@@ -996,7 +1052,7 @@ void dm_pg_init_complete(struct dm_path *path, unsigned err_flags)
bypass_pg(m, pg, 1);
spin_lock_irqsave(&m->lock, flags);
- if (err_flags) {
+ if (err_flags & ~MP_RETRY) {
m->current_pgpath = NULL;
m->current_pg = NULL;
} else if (!m->pg_init_required)
@@ -1148,11 +1204,15 @@ static int multipath_status(struct dm_target *ti, status_type_t type,
/* Features */
if (type == STATUSTYPE_INFO)
- DMEMIT("1 %u ", m->queue_size);
- else if (m->queue_if_no_path)
- DMEMIT("1 queue_if_no_path ");
- else
- DMEMIT("0 ");
+ 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);
+ 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 (hwh->type && hwh->type->status)
sz += hwh->type->status(hwh, type, result + sz, maxlen - sz);
diff --git a/drivers/md/dm-path-selector.c b/drivers/md/dm-path-selector.c
index f10a0c89b3f..ca1bb636a3e 100644
--- a/drivers/md/dm-path-selector.c
+++ b/drivers/md/dm-path-selector.c
@@ -94,12 +94,10 @@ out:
static struct ps_internal *_alloc_path_selector(struct path_selector_type *pst)
{
- struct ps_internal *psi = kmalloc(sizeof(*psi), GFP_KERNEL);
+ struct ps_internal *psi = kzalloc(sizeof(*psi), GFP_KERNEL);
- if (psi) {
- memset(psi, 0, sizeof(*psi));
+ if (psi)
psi->pst = *pst;
- }
return psi;
}
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 144071e70a9..31123d4a6b9 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -19,6 +19,7 @@
#include <linux/time.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
+#include <linux/log2.h>
#define DM_MSG_PREFIX "raid1"
#define DM_IO_PAGES 64
@@ -113,6 +114,7 @@ struct region {
* Mirror set structures.
*---------------------------------------------------------------*/
struct mirror {
+ struct mirror_set *ms;
atomic_t error_count;
struct dm_dev *dev;
sector_t offset;
@@ -820,7 +822,7 @@ static void write_callback(unsigned long error, void *context)
break;
}
}
- bio_endio(bio, bio->bi_size, 0);
+ bio_endio(bio, 0);
}
static void do_write(struct mirror_set *ms, struct bio *bio)
@@ -900,7 +902,7 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
*/
if (unlikely(ms->log_failure))
while ((bio = bio_list_pop(&sync)))
- bio_endio(bio, bio->bi_size, -EIO);
+ bio_endio(bio, -EIO);
else while ((bio = bio_list_pop(&sync)))
do_write(ms, bio);
@@ -974,6 +976,7 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) {
ti->error = "Error creating dirty region hash";
+ dm_io_client_destroy(ms->io_client);
kfree(ms);
return NULL;
}
@@ -994,7 +997,7 @@ static void free_context(struct mirror_set *ms, struct dm_target *ti,
static inline int _check_region_size(struct dm_target *ti, uint32_t size)
{
- return !(size % (PAGE_SIZE >> 9) || (size & (size - 1)) ||
+ return !(size % (PAGE_SIZE >> 9) || !is_power_of_2(size) ||
size > ti->len);
}
@@ -1015,6 +1018,7 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
return -ENXIO;
}
+ ms->mirror[mirror].ms = ms;
ms->mirror[mirror].offset = offset;
return 0;
@@ -1163,16 +1167,14 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ms->kmirrord_wq = create_singlethread_workqueue("kmirrord");
if (!ms->kmirrord_wq) {
DMERR("couldn't start kmirrord");
- free_context(ms, ti, m);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto err_free_context;
}
INIT_WORK(&ms->kmirrord_work, do_mirror);
r = parse_features(ms, argc, argv, &args_used);
- if (r) {
- free_context(ms, ti, ms->nr_mirrors);
- return r;
- }
+ if (r)
+ goto err_destroy_wq;
argv += args_used;
argc -= args_used;
@@ -1188,19 +1190,22 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (argc) {
ti->error = "Too many mirror arguments";
- free_context(ms, ti, ms->nr_mirrors);
- return -EINVAL;
+ r = -EINVAL;
+ goto err_destroy_wq;
}
r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
- if (r) {
- destroy_workqueue(ms->kmirrord_wq);
- free_context(ms, ti, ms->nr_mirrors);
- return r;
- }
+ if (r)
+ goto err_destroy_wq;
wake(ms);
return 0;
+
+err_destroy_wq:
+ destroy_workqueue(ms->kmirrord_wq);
+err_free_context:
+ free_context(ms, ti, ms->nr_mirrors);
+ return r;
}
static void mirror_dtr(struct dm_target *ti)
@@ -1302,7 +1307,7 @@ static void mirror_postsuspend(struct dm_target *ti)
wait_event(_kmirrord_recovery_stopped,
!atomic_read(&ms->rh.recovery_in_flight));
- if (log->type->suspend && log->type->suspend(log))
+ if (log->type->postsuspend && log->type->postsuspend(log))
/* FIXME: need better error handling */
DMWARN("log suspend failed");
}
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 83ddbfe6b8a..cee16fadd9e 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <linux/log2.h>
#include "dm-snap.h"
#include "dm-bio-list.h"
@@ -415,7 +416,7 @@ static int set_chunk_size(struct dm_snapshot *s, const char *chunk_size_arg,
chunk_size = round_up(chunk_size, PAGE_SIZE >> 9);
/* Check chunk_size is a power of 2 */
- if (chunk_size & (chunk_size - 1)) {
+ if (!is_power_of_2(chunk_size)) {
*error = "Chunk size is not a power of 2";
return -EINVAL;
}
@@ -636,7 +637,7 @@ static void error_bios(struct bio *bio)
while (bio) {
n = bio->bi_next;
bio->bi_next = NULL;
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
bio = n;
}
}
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 51f5e076001..969944a8aba 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -11,6 +11,7 @@
#include <linux/blkdev.h>
#include <linux/bio.h>
#include <linux/slab.h>
+#include <linux/log2.h>
#define DM_MSG_PREFIX "striped"
@@ -99,7 +100,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
/*
* chunk_size is a power of two
*/
- if (!chunk_size || (chunk_size & (chunk_size - 1)) ||
+ if (!is_power_of_2(chunk_size) ||
(chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) {
ti->error = "Invalid chunk size";
return -EINVAL;
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 2bcde5798b5..e298d8d11f2 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -102,6 +102,8 @@ static void combine_restrictions_low(struct io_restrictions *lhs,
lhs->seg_boundary_mask =
min_not_zero(lhs->seg_boundary_mask, rhs->seg_boundary_mask);
+ lhs->bounce_pfn = min_not_zero(lhs->bounce_pfn, rhs->bounce_pfn);
+
lhs->no_cluster |= rhs->no_cluster;
}
@@ -213,12 +215,11 @@ static int alloc_targets(struct dm_table *t, unsigned int num)
int dm_table_create(struct dm_table **result, int mode,
unsigned num_targets, struct mapped_device *md)
{
- struct dm_table *t = kmalloc(sizeof(*t), GFP_KERNEL);
+ struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL);
if (!t)
return -ENOMEM;
- memset(t, 0, sizeof(*t));
INIT_LIST_HEAD(&t->devices);
atomic_set(&t->holders, 1);
@@ -567,6 +568,8 @@ void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
min_not_zero(rs->seg_boundary_mask,
q->seg_boundary_mask);
+ rs->bounce_pfn = min_not_zero(rs->bounce_pfn, q->bounce_pfn);
+
rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
}
EXPORT_SYMBOL_GPL(dm_set_device_limits);
@@ -708,6 +711,8 @@ static void check_for_valid_limits(struct io_restrictions *rs)
rs->max_segment_size = MAX_SEGMENT_SIZE;
if (!rs->seg_boundary_mask)
rs->seg_boundary_mask = -1;
+ if (!rs->bounce_pfn)
+ rs->bounce_pfn = -1;
}
int dm_table_add_target(struct dm_table *t, const char *type,
@@ -892,6 +897,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q)
q->hardsect_size = t->limits.hardsect_size;
q->max_segment_size = t->limits.max_segment_size;
q->seg_boundary_mask = t->limits.seg_boundary_mask;
+ q->bounce_pfn = t->limits.bounce_pfn;
if (t->limits.no_cluster)
q->queue_flags &= ~(1 << QUEUE_FLAG_CLUSTER);
else
@@ -994,38 +1000,10 @@ void dm_table_unplug_all(struct dm_table *t)
struct dm_dev *dd = list_entry(d, struct dm_dev, list);
struct request_queue *q = bdev_get_queue(dd->bdev);
- if (q->unplug_fn)
- q->unplug_fn(q);
+ blk_unplug(q);
}
}
-int dm_table_flush_all(struct dm_table *t)
-{
- struct list_head *d, *devices = dm_table_get_devices(t);
- int ret = 0;
- unsigned i;
-
- for (i = 0; i < t->num_targets; i++)
- if (t->targets[i].type->flush)
- t->targets[i].type->flush(&t->targets[i]);
-
- for (d = devices->next; d != devices; d = d->next) {
- struct dm_dev *dd = list_entry(d, struct dm_dev, list);
- struct request_queue *q = bdev_get_queue(dd->bdev);
- int err;
-
- if (!q->issue_flush_fn)
- err = -EOPNOTSUPP;
- else
- err = q->issue_flush_fn(q, dd->bdev->bd_disk, NULL);
-
- if (!ret)
- ret = err;
- }
-
- return ret;
-}
-
struct mapped_device *dm_table_get_md(struct dm_table *t)
{
dm_get(t->md);
@@ -1043,4 +1021,3 @@ EXPORT_SYMBOL(dm_table_get_md);
EXPORT_SYMBOL(dm_table_put);
EXPORT_SYMBOL(dm_table_get);
EXPORT_SYMBOL(dm_table_unplug_all);
-EXPORT_SYMBOL(dm_table_flush_all);
diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c
index 477a041a41c..835cf95b857 100644
--- a/drivers/md/dm-target.c
+++ b/drivers/md/dm-target.c
@@ -88,12 +88,10 @@ void dm_put_target_type(struct target_type *t)
static struct tt_internal *alloc_target(struct target_type *t)
{
- struct tt_internal *ti = kmalloc(sizeof(*ti), GFP_KERNEL);
+ struct tt_internal *ti = kzalloc(sizeof(*ti), GFP_KERNEL);
- if (ti) {
- memset(ti, 0, sizeof(*ti));
+ if (ti)
ti->tt = *t;
- }
return ti;
}
diff --git a/drivers/md/dm-uevent.c b/drivers/md/dm-uevent.c
new file mode 100644
index 00000000000..50377e5dc2a
--- /dev/null
+++ b/drivers/md/dm-uevent.c
@@ -0,0 +1,222 @@
+/*
+ * Device Mapper Uevent Support (dm-uevent)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You 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.
+ *
+ * Copyright IBM Corporation, 2007
+ * Author: Mike Anderson <andmike@linux.vnet.ibm.com>
+ */
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/kobject.h>
+#include <linux/dm-ioctl.h>
+
+#include "dm.h"
+#include "dm-uevent.h"
+
+#define DM_MSG_PREFIX "uevent"
+
+static const struct {
+ enum dm_uevent_type type;
+ enum kobject_action action;
+ char *name;
+} _dm_uevent_type_names[] = {
+ {DM_UEVENT_PATH_FAILED, KOBJ_CHANGE, "PATH_FAILED"},
+ {DM_UEVENT_PATH_REINSTATED, KOBJ_CHANGE, "PATH_REINSTATED"},
+};
+
+static struct kmem_cache *_dm_event_cache;
+
+struct dm_uevent {
+ struct mapped_device *md;
+ enum kobject_action action;
+ struct kobj_uevent_env ku_env;
+ struct list_head elist;
+ char name[DM_NAME_LEN];
+ char uuid[DM_UUID_LEN];
+};
+
+static void dm_uevent_free(struct dm_uevent *event)
+{
+ kmem_cache_free(_dm_event_cache, event);
+}
+
+static struct dm_uevent *dm_uevent_alloc(struct mapped_device *md)
+{
+ struct dm_uevent *event;
+
+ event = kmem_cache_zalloc(_dm_event_cache, GFP_ATOMIC);
+ if (!event)
+ return NULL;
+
+ INIT_LIST_HEAD(&event->elist);
+ event->md = md;
+
+ return event;
+}
+
+static struct dm_uevent *dm_build_path_uevent(struct mapped_device *md,
+ struct dm_target *ti,
+ enum kobject_action action,
+ const char *dm_action,
+ const char *path,
+ unsigned nr_valid_paths)
+{
+ struct dm_uevent *event;
+
+ event = dm_uevent_alloc(md);
+ if (!event) {
+ DMERR("%s: dm_uevent_alloc() failed", __FUNCTION__);
+ goto err_nomem;
+ }
+
+ event->action = action;
+
+ if (add_uevent_var(&event->ku_env, "DM_TARGET=%s", ti->type->name)) {
+ DMERR("%s: add_uevent_var() for DM_TARGET failed",
+ __FUNCTION__);
+ goto err_add;
+ }
+
+ if (add_uevent_var(&event->ku_env, "DM_ACTION=%s", dm_action)) {
+ DMERR("%s: add_uevent_var() for DM_ACTION failed",
+ __FUNCTION__);
+ goto err_add;
+ }
+
+ if (add_uevent_var(&event->ku_env, "DM_SEQNUM=%u",
+ dm_next_uevent_seq(md))) {
+ DMERR("%s: add_uevent_var() for DM_SEQNUM failed",
+ __FUNCTION__);
+ goto err_add;
+ }
+
+ if (add_uevent_var(&event->ku_env, "DM_PATH=%s", path)) {
+ DMERR("%s: add_uevent_var() for DM_PATH failed", __FUNCTION__);
+ goto err_add;
+ }
+
+ if (add_uevent_var(&event->ku_env, "DM_NR_VALID_PATHS=%d",
+ nr_valid_paths)) {
+ DMERR("%s: add_uevent_var() for DM_NR_VALID_PATHS failed",
+ __FUNCTION__);
+ goto err_add;
+ }
+
+ return event;
+
+err_add:
+ dm_uevent_free(event);
+err_nomem:
+ return ERR_PTR(-ENOMEM);
+}
+
+/**
+ * dm_send_uevents - send uevents for given list
+ *
+ * @events: list of events to send
+ * @kobj: kobject generating event
+ *
+ */
+void dm_send_uevents(struct list_head *events, struct kobject *kobj)
+{
+ int r;
+ struct dm_uevent *event, *next;
+
+ list_for_each_entry_safe(event, next, events, elist) {
+ list_del_init(&event->elist);
+
+ /*
+ * Need to call dm_copy_name_and_uuid from here for now.
+ * Context of previous var adds and locking used for
+ * hash_cell not compatable.
+ */
+ if (dm_copy_name_and_uuid(event->md, event->name,
+ event->uuid)) {
+ DMERR("%s: dm_copy_name_and_uuid() failed",
+ __FUNCTION__);
+ goto uevent_free;
+ }
+
+ if (add_uevent_var(&event->ku_env, "DM_NAME=%s", event->name)) {
+ DMERR("%s: add_uevent_var() for DM_NAME failed",
+ __FUNCTION__);
+ goto uevent_free;
+ }
+
+ if (add_uevent_var(&event->ku_env, "DM_UUID=%s", event->uuid)) {
+ DMERR("%s: add_uevent_var() for DM_UUID failed",
+ __FUNCTION__);
+ goto uevent_free;
+ }
+
+ r = kobject_uevent_env(kobj, event->action, event->ku_env.envp);
+ if (r)
+ DMERR("%s: kobject_uevent_env failed", __FUNCTION__);
+uevent_free:
+ dm_uevent_free(event);
+ }
+}
+EXPORT_SYMBOL_GPL(dm_send_uevents);
+
+/**
+ * dm_path_uevent - called to create a new path event and queue it
+ *
+ * @event_type: path event type enum
+ * @ti: pointer to a dm_target
+ * @path: string containing pathname
+ * @nr_valid_paths: number of valid paths remaining
+ *
+ */
+void dm_path_uevent(enum dm_uevent_type event_type, struct dm_target *ti,
+ const char *path, unsigned nr_valid_paths)
+{
+ struct mapped_device *md = dm_table_get_md(ti->table);
+ struct dm_uevent *event;
+
+ if (event_type >= ARRAY_SIZE(_dm_uevent_type_names)) {
+ DMERR("%s: Invalid event_type %d", __FUNCTION__, event_type);
+ goto out;
+ }
+
+ event = dm_build_path_uevent(md, ti,
+ _dm_uevent_type_names[event_type].action,
+ _dm_uevent_type_names[event_type].name,
+ path, nr_valid_paths);
+ if (IS_ERR(event))
+ goto out;
+
+ dm_uevent_add(md, &event->elist);
+
+out:
+ dm_put(md);
+}
+EXPORT_SYMBOL_GPL(dm_path_uevent);
+
+int dm_uevent_init(void)
+{
+ _dm_event_cache = KMEM_CACHE(dm_uevent, 0);
+ if (!_dm_event_cache)
+ return -ENOMEM;
+
+ DMINFO("version 1.0.3");
+
+ return 0;
+}
+
+void dm_uevent_exit(void)
+{
+ kmem_cache_destroy(_dm_event_cache);
+}
diff --git a/drivers/md/dm-uevent.h b/drivers/md/dm-uevent.h
new file mode 100644
index 00000000000..2eccc8bd671
--- /dev/null
+++ b/drivers/md/dm-uevent.h
@@ -0,0 +1,59 @@
+/*
+ * Device Mapper Uevent Support
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright IBM Corporation, 2007
+ * Author: Mike Anderson <andmike@linux.vnet.ibm.com>
+ */
+#ifndef DM_UEVENT_H
+#define DM_UEVENT_H
+
+enum dm_uevent_type {
+ DM_UEVENT_PATH_FAILED,
+ DM_UEVENT_PATH_REINSTATED,
+};
+
+#ifdef CONFIG_DM_UEVENT
+
+extern int dm_uevent_init(void);
+extern void dm_uevent_exit(void);
+extern void dm_send_uevents(struct list_head *events, struct kobject *kobj);
+extern void dm_path_uevent(enum dm_uevent_type event_type,
+ struct dm_target *ti, const char *path,
+ unsigned nr_valid_paths);
+
+#else
+
+static inline int dm_uevent_init(void)
+{
+ return 0;
+}
+static inline void dm_uevent_exit(void)
+{
+}
+static inline void dm_send_uevents(struct list_head *events,
+ struct kobject *kobj)
+{
+}
+static inline void dm_path_uevent(enum dm_uevent_type event_type,
+ struct dm_target *ti, const char *path,
+ unsigned nr_valid_paths)
+{
+}
+
+#endif /* CONFIG_DM_UEVENT */
+
+#endif /* DM_UEVENT_H */
diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c
index f314d7dc9c2..bdec206c404 100644
--- a/drivers/md/dm-zero.c
+++ b/drivers/md/dm-zero.c
@@ -43,7 +43,7 @@ static int zero_map(struct dm_target *ti, struct bio *bio,
break;
}
- bio_endio(bio, bio->bi_size, 0);
+ bio_endio(bio, 0);
/* accepted bio, don't make new request */
return DM_MAPIO_SUBMITTED;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 2120155929a..07cbbb8eb3e 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -7,6 +7,7 @@
#include "dm.h"
#include "dm-bio-list.h"
+#include "dm-uevent.h"
#include <linux/init.h>
#include <linux/module.h>
@@ -112,6 +113,9 @@ struct mapped_device {
*/
atomic_t event_nr;
wait_queue_head_t eventq;
+ atomic_t uevent_seq;
+ struct list_head uevent_list;
+ spinlock_t uevent_lock; /* Protect access to uevent_list */
/*
* freeze/thaw support require holding onto a super block
@@ -143,11 +147,19 @@ static int __init local_init(void)
return -ENOMEM;
}
+ r = dm_uevent_init();
+ if (r) {
+ kmem_cache_destroy(_tio_cache);
+ kmem_cache_destroy(_io_cache);
+ return r;
+ }
+
_major = major;
r = register_blkdev(_major, _name);
if (r < 0) {
kmem_cache_destroy(_tio_cache);
kmem_cache_destroy(_io_cache);
+ dm_uevent_exit();
return r;
}
@@ -162,6 +174,7 @@ static void local_exit(void)
kmem_cache_destroy(_tio_cache);
kmem_cache_destroy(_io_cache);
unregister_blkdev(_major, _name);
+ dm_uevent_exit();
_major = 0;
@@ -484,23 +497,20 @@ static void dec_pending(struct dm_io *io, int error)
blk_add_trace_bio(io->md->queue, io->bio,
BLK_TA_COMPLETE);
- bio_endio(io->bio, io->bio->bi_size, io->error);
+ bio_endio(io->bio, io->error);
}
free_io(io->md, io);
}
}
-static int clone_endio(struct bio *bio, unsigned int done, int error)
+static void clone_endio(struct bio *bio, int error)
{
int r = 0;
struct dm_target_io *tio = bio->bi_private;
struct mapped_device *md = tio->io->md;
dm_endio_fn endio = tio->ti->type->end_io;
- if (bio->bi_size)
- return 1;
-
if (!bio_flagged(bio, BIO_UPTODATE) && !error)
error = -EIO;
@@ -514,7 +524,7 @@ static int clone_endio(struct bio *bio, unsigned int done, int error)
error = r;
else if (r == DM_ENDIO_INCOMPLETE)
/* The target will handle the io */
- return 1;
+ return;
else if (r) {
DMWARN("unimplemented target endio return value: %d", r);
BUG();
@@ -530,7 +540,6 @@ static int clone_endio(struct bio *bio, unsigned int done, int error)
bio_put(bio);
free_tio(md, tio);
- return r;
}
static sector_t max_io_len(struct mapped_device *md,
@@ -755,15 +764,13 @@ static void __clone_and_map(struct clone_info *ci)
/*
* Split the bio into several clones.
*/
-static void __split_bio(struct mapped_device *md, struct bio *bio)
+static int __split_bio(struct mapped_device *md, struct bio *bio)
{
struct clone_info ci;
ci.map = dm_get_table(md);
- if (!ci.map) {
- bio_io_error(bio, bio->bi_size);
- return;
- }
+ if (unlikely(!ci.map))
+ return -EIO;
ci.md = md;
ci.bio = bio;
@@ -783,6 +790,8 @@ static void __split_bio(struct mapped_device *md, struct bio *bio)
/* drop the extra reference count */
dec_pending(ci.io, 0);
dm_table_put(ci.map);
+
+ return 0;
}
/*-----------------------------------------------------------------
* CRUD END
@@ -794,7 +803,7 @@ static void __split_bio(struct mapped_device *md, struct bio *bio)
*/
static int dm_request(struct request_queue *q, struct bio *bio)
{
- int r;
+ int r = -EIO;
int rw = bio_data_dir(bio);
struct mapped_device *md = q->queuedata;
@@ -803,7 +812,7 @@ static int dm_request(struct request_queue *q, struct bio *bio)
* guarantee it is (or can be) handled by the targets correctly.
*/
if (unlikely(bio_barrier(bio))) {
- bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -819,18 +828,11 @@ static int dm_request(struct request_queue *q, struct bio *bio)
while (test_bit(DMF_BLOCK_IO, &md->flags)) {
up_read(&md->io_lock);
- if (bio_rw(bio) == READA) {
- bio_io_error(bio, bio->bi_size);
- return 0;
- }
-
- r = queue_io(md, bio);
- if (r < 0) {
- bio_io_error(bio, bio->bi_size);
- return 0;
+ if (bio_rw(bio) != READA)
+ r = queue_io(md, bio);
- } else if (r == 0)
- return 0; /* deferred successfully */
+ if (r <= 0)
+ goto out_req;
/*
* We're in a while loop, because someone could suspend
@@ -839,24 +841,14 @@ static int dm_request(struct request_queue *q, struct bio *bio)
down_read(&md->io_lock);
}
- __split_bio(md, bio);
+ r = __split_bio(md, bio);
up_read(&md->io_lock);
- return 0;
-}
-
-static int dm_flush_all(struct request_queue *q, struct gendisk *disk,
- sector_t *error_sector)
-{
- struct mapped_device *md = q->queuedata;
- struct dm_table *map = dm_get_table(md);
- int ret = -ENXIO;
- if (map) {
- ret = dm_table_flush_all(map);
- dm_table_put(map);
- }
+out_req:
+ if (r < 0)
+ bio_io_error(bio);
- return ret;
+ return 0;
}
static void dm_unplug_all(struct request_queue *q)
@@ -996,6 +988,9 @@ static struct mapped_device *alloc_dev(int minor)
atomic_set(&md->holders, 1);
atomic_set(&md->open_count, 0);
atomic_set(&md->event_nr, 0);
+ atomic_set(&md->uevent_seq, 0);
+ INIT_LIST_HEAD(&md->uevent_list);
+ spin_lock_init(&md->uevent_lock);
md->queue = blk_alloc_queue(GFP_KERNEL);
if (!md->queue)
@@ -1007,7 +1002,6 @@ static struct mapped_device *alloc_dev(int minor)
blk_queue_make_request(md->queue, dm_request);
blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY);
md->queue->unplug_fn = dm_unplug_all;
- md->queue->issue_flush_fn = dm_flush_all;
md->io_pool = mempool_create_slab_pool(MIN_IOS, _io_cache);
if (!md->io_pool)
@@ -1064,12 +1058,14 @@ static struct mapped_device *alloc_dev(int minor)
return NULL;
}
+static void unlock_fs(struct mapped_device *md);
+
static void free_dev(struct mapped_device *md)
{
int minor = md->disk->first_minor;
if (md->suspended_bdev) {
- thaw_bdev(md->suspended_bdev, NULL);
+ unlock_fs(md);
bdput(md->suspended_bdev);
}
mempool_destroy(md->tio_pool);
@@ -1093,8 +1089,16 @@ static void free_dev(struct mapped_device *md)
*/
static void event_callback(void *context)
{
+ unsigned long flags;
+ LIST_HEAD(uevents);
struct mapped_device *md = (struct mapped_device *) context;
+ spin_lock_irqsave(&md->uevent_lock, flags);
+ list_splice_init(&md->uevent_list, &uevents);
+ spin_unlock_irqrestore(&md->uevent_lock, flags);
+
+ dm_send_uevents(&uevents, &md->disk->kobj);
+
atomic_inc(&md->event_nr);
wake_up(&md->eventq);
}
@@ -1253,7 +1257,8 @@ static void __flush_deferred_io(struct mapped_device *md, struct bio *c)
while (c) {
n = c->bi_next;
c->bi_next = NULL;
- __split_bio(md, c);
+ if (__split_bio(md, c))
+ bio_io_error(c);
c = n;
}
}
@@ -1511,6 +1516,11 @@ out:
/*-----------------------------------------------------------------
* Event notification.
*---------------------------------------------------------------*/
+uint32_t dm_next_uevent_seq(struct mapped_device *md)
+{
+ return atomic_add_return(1, &md->uevent_seq);
+}
+
uint32_t dm_get_event_nr(struct mapped_device *md)
{
return atomic_read(&md->event_nr);
@@ -1522,6 +1532,15 @@ int dm_wait_event(struct mapped_device *md, int event_nr)
(event_nr != atomic_read(&md->event_nr)));
}
+void dm_uevent_add(struct mapped_device *md, struct list_head *elist)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&md->uevent_lock, flags);
+ list_add(elist, &md->uevent_list);
+ spin_unlock_irqrestore(&md->uevent_lock, flags);
+}
+
/*
* The gendisk is only valid as long as you have a reference
* count on 'md'.
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 462ee652a89..4b3faa45277 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -111,7 +111,6 @@ void dm_table_postsuspend_targets(struct dm_table *t);
int dm_table_resume_targets(struct dm_table *t);
int dm_table_any_congested(struct dm_table *t, int bdi_bits);
void dm_table_unplug_all(struct dm_table *t);
-int dm_table_flush_all(struct dm_table *t);
/*-----------------------------------------------------------------
* A registry of target types.
diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c
index cb059cf14c2..cf2ddce3411 100644
--- a/drivers/md/faulty.c
+++ b/drivers/md/faulty.c
@@ -65,18 +65,16 @@
#include <linux/raid/md.h>
-static int faulty_fail(struct bio *bio, unsigned int bytes_done, int error)
+static void faulty_fail(struct bio *bio, int error)
{
struct bio *b = bio->bi_private;
b->bi_size = bio->bi_size;
b->bi_sector = bio->bi_sector;
- if (bio->bi_size == 0)
- bio_put(bio);
+ bio_put(bio);
- clear_bit(BIO_UPTODATE, &b->bi_flags);
- return (b->bi_end_io)(b, bytes_done, -EIO);
+ bio_io_error(b);
}
typedef struct faulty_conf {
@@ -179,7 +177,7 @@ static int make_request(struct request_queue *q, struct bio *bio)
/* special case - don't decrement, don't generic_make_request,
* just fail immediately
*/
- bio_endio(bio, bio->bi_size, -EIO);
+ bio_endio(bio, -EIO);
return 0;
}
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c
index 7e052378c47..f3831f31223 100644
--- a/drivers/md/kcopyd.c
+++ b/drivers/md/kcopyd.c
@@ -198,7 +198,7 @@ struct kcopyd_job {
* These fields are only used if the job has been split
* into more manageable parts.
*/
- struct semaphore lock;
+ struct mutex lock;
atomic_t sub_jobs;
sector_t progress;
};
@@ -456,7 +456,7 @@ static void segment_complete(int read_err,
sector_t count = 0;
struct kcopyd_job *job = (struct kcopyd_job *) context;
- down(&job->lock);
+ mutex_lock(&job->lock);
/* update the error */
if (read_err)
@@ -480,7 +480,7 @@ static void segment_complete(int read_err,
job->progress += count;
}
}
- up(&job->lock);
+ mutex_unlock(&job->lock);
if (count) {
int i;
@@ -562,7 +562,7 @@ int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from,
dispatch_job(job);
else {
- init_MUTEX(&job->lock);
+ mutex_init(&job->lock);
job->progress = 0;
split_job(job);
}
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 17f795c3e0a..3dac1cfb818 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -87,30 +87,10 @@ static void linear_unplug(struct request_queue *q)
for (i=0; i < mddev->raid_disks; i++) {
struct request_queue *r_queue = bdev_get_queue(conf->disks[i].rdev->bdev);
- if (r_queue->unplug_fn)
- r_queue->unplug_fn(r_queue);
+ blk_unplug(r_queue);
}
}
-static int linear_issue_flush(struct request_queue *q, struct gendisk *disk,
- sector_t *error_sector)
-{
- mddev_t *mddev = q->queuedata;
- linear_conf_t *conf = mddev_to_conf(mddev);
- int i, ret = 0;
-
- for (i=0; i < mddev->raid_disks && ret == 0; i++) {
- struct block_device *bdev = conf->disks[i].rdev->bdev;
- struct request_queue *r_queue = bdev_get_queue(bdev);
-
- if (!r_queue->issue_flush_fn)
- ret = -EOPNOTSUPP;
- else
- ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
- }
- return ret;
-}
-
static int linear_congested(void *data, int bits)
{
mddev_t *mddev = data;
@@ -279,7 +259,6 @@ static int linear_run (mddev_t *mddev)
blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec);
mddev->queue->unplug_fn = linear_unplug;
- mddev->queue->issue_flush_fn = linear_issue_flush;
mddev->queue->backing_dev_info.congested_fn = linear_congested;
mddev->queue->backing_dev_info.congested_data = mddev;
return 0;
@@ -338,7 +317,7 @@ static int linear_make_request (struct request_queue *q, struct bio *bio)
sector_t block;
if (unlikely(bio_barrier(bio))) {
- bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -358,7 +337,7 @@ static int linear_make_request (struct request_queue *q, struct bio *bio)
bdevname(tmp_dev->rdev->bdev, b),
(unsigned long long)tmp_dev->size,
(unsigned long long)tmp_dev->offset);
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
if (unlikely(bio->bi_sector + (bio->bi_size >> 9) >
diff --git a/drivers/md/md.c b/drivers/md/md.c
index f883b7e37f3..cef9ebd5a04 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -213,7 +213,7 @@ static DEFINE_SPINLOCK(all_mddevs_lock);
static int md_fail_request (struct request_queue *q, struct bio *bio)
{
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
@@ -384,12 +384,10 @@ static void free_disk_sb(mdk_rdev_t * rdev)
}
-static int super_written(struct bio *bio, unsigned int bytes_done, int error)
+static void super_written(struct bio *bio, int error)
{
mdk_rdev_t *rdev = bio->bi_private;
mddev_t *mddev = rdev->mddev;
- if (bio->bi_size)
- return 1;
if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags)) {
printk("md: super_written gets error=%d, uptodate=%d\n",
@@ -401,16 +399,13 @@ static int super_written(struct bio *bio, unsigned int bytes_done, int error)
if (atomic_dec_and_test(&mddev->pending_writes))
wake_up(&mddev->sb_wait);
bio_put(bio);
- return 0;
}
-static int super_written_barrier(struct bio *bio, unsigned int bytes_done, int error)
+static void super_written_barrier(struct bio *bio, int error)
{
struct bio *bio2 = bio->bi_private;
mdk_rdev_t *rdev = bio2->bi_private;
mddev_t *mddev = rdev->mddev;
- if (bio->bi_size)
- return 1;
if (!test_bit(BIO_UPTODATE, &bio->bi_flags) &&
error == -EOPNOTSUPP) {
@@ -424,11 +419,11 @@ static int super_written_barrier(struct bio *bio, unsigned int bytes_done, int e
spin_unlock_irqrestore(&mddev->write_lock, flags);
wake_up(&mddev->sb_wait);
bio_put(bio);
- return 0;
+ } else {
+ bio_put(bio2);
+ bio->bi_private = rdev;
+ super_written(bio, error);
}
- bio_put(bio2);
- bio->bi_private = rdev;
- return super_written(bio, bytes_done, error);
}
void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
@@ -489,13 +484,9 @@ void md_super_wait(mddev_t *mddev)
finish_wait(&mddev->sb_wait, &wq);
}
-static int bi_complete(struct bio *bio, unsigned int bytes_done, int error)
+static void bi_complete(struct bio *bio, int error)
{
- if (bio->bi_size)
- return 1;
-
complete((struct completion*)bio->bi_private);
- return 0;
}
int sync_page_io(struct block_device *bdev, sector_t sector, int size,
@@ -2723,7 +2714,7 @@ action_show(mddev_t *mddev, char *page)
{
char *type = "idle";
if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
- test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) {
+ (!mddev->ro && test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))) {
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
type = "reshape";
else if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
@@ -2842,6 +2833,12 @@ sync_max_store(mddev_t *mddev, const char *buf, size_t len)
static struct md_sysfs_entry md_sync_max =
__ATTR(sync_speed_max, S_IRUGO|S_IWUSR, sync_max_show, sync_max_store);
+static ssize_t
+degraded_show(mddev_t *mddev, char *page)
+{
+ return sprintf(page, "%d\n", mddev->degraded);
+}
+static struct md_sysfs_entry md_degraded = __ATTR_RO(degraded);
static ssize_t
sync_speed_show(mddev_t *mddev, char *page)
@@ -2985,6 +2982,7 @@ static struct attribute *md_redundancy_attrs[] = {
&md_suspend_lo.attr,
&md_suspend_hi.attr,
&md_bitmap.attr,
+ &md_degraded.attr,
NULL,
};
static struct attribute_group md_redundancy_group = {
@@ -3085,8 +3083,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
mddev->gendisk = disk;
mutex_unlock(&disks_mutex);
mddev->kobj.parent = &disk->kobj;
- mddev->kobj.k_name = NULL;
- snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md");
+ kobject_set_name(&mddev->kobj, "%s", "md");
mddev->kobj.ktype = &md_ktype;
if (kobject_register(&mddev->kobj))
printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
@@ -3473,7 +3470,6 @@ static int do_md_stop(mddev_t * mddev, int mode)
mddev->pers->stop(mddev);
mddev->queue->merge_bvec_fn = NULL;
mddev->queue->unplug_fn = NULL;
- mddev->queue->issue_flush_fn = NULL;
mddev->queue->backing_dev_info.congested_fn = NULL;
if (mddev->pers->sync_request)
sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
@@ -4721,7 +4717,7 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev,
void md_unregister_thread(mdk_thread_t *thread)
{
- dprintk("interrupting MD-thread pid %d\n", thread->tsk->pid);
+ dprintk("interrupting MD-thread pid %d\n", task_pid_nr(thread->tsk));
kthread_stop(thread->tsk);
kfree(thread);
@@ -5449,7 +5445,7 @@ void md_do_sync(mddev_t *mddev)
* about not overloading the IO subsystem. (things like an
* e2fsck being done on the RAID array should execute fast)
*/
- mddev->queue->unplug_fn(mddev->queue);
+ blk_unplug(mddev->queue);
cond_resched();
currspeed = ((unsigned long)(io_sectors-mddev->resync_mark_cnt))/2
@@ -5468,7 +5464,7 @@ void md_do_sync(mddev_t *mddev)
* this also signals 'finished resyncing' to md_stop
*/
out:
- mddev->queue->unplug_fn(mddev->queue);
+ blk_unplug(mddev->queue);
wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active));
@@ -5781,26 +5777,47 @@ static int __init md_init(void)
* Searches all registered partitions for autorun RAID arrays
* at boot time.
*/
-static dev_t detected_devices[128];
-static int dev_cnt;
+
+static LIST_HEAD(all_detected_devices);
+struct detected_devices_node {
+ struct list_head list;
+ dev_t dev;
+};
void md_autodetect_dev(dev_t dev)
{
- if (dev_cnt >= 0 && dev_cnt < 127)
- detected_devices[dev_cnt++] = dev;
+ struct detected_devices_node *node_detected_dev;
+
+ node_detected_dev = kzalloc(sizeof(*node_detected_dev), GFP_KERNEL);
+ if (node_detected_dev) {
+ node_detected_dev->dev = dev;
+ list_add_tail(&node_detected_dev->list, &all_detected_devices);
+ } else {
+ printk(KERN_CRIT "md: md_autodetect_dev: kzalloc failed"
+ ", skipping dev(%d,%d)\n", MAJOR(dev), MINOR(dev));
+ }
}
static void autostart_arrays(int part)
{
mdk_rdev_t *rdev;
- int i;
+ struct detected_devices_node *node_detected_dev;
+ dev_t dev;
+ int i_scanned, i_passed;
- printk(KERN_INFO "md: Autodetecting RAID arrays.\n");
+ i_scanned = 0;
+ i_passed = 0;
- for (i = 0; i < dev_cnt; i++) {
- dev_t dev = detected_devices[i];
+ printk(KERN_INFO "md: Autodetecting RAID arrays.\n");
+ while (!list_empty(&all_detected_devices) && i_scanned < INT_MAX) {
+ i_scanned++;
+ node_detected_dev = list_entry(all_detected_devices.next,
+ struct detected_devices_node, list);
+ list_del(&node_detected_dev->list);
+ dev = node_detected_dev->dev;
+ kfree(node_detected_dev);
rdev = md_import_device(dev,0, 90);
if (IS_ERR(rdev))
continue;
@@ -5810,8 +5827,11 @@ static void autostart_arrays(int part)
continue;
}
list_add(&rdev->same_set, &pending_raid_disks);
+ i_passed++;
}
- dev_cnt = 0;
+
+ printk(KERN_INFO "md: Scanned %d and added %d devices.\n",
+ i_scanned, i_passed);
autorun_devices(part);
}
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 1e2af43a73b..eb631ebed68 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -82,21 +82,17 @@ static void multipath_end_bh_io (struct multipath_bh *mp_bh, int err)
struct bio *bio = mp_bh->master_bio;
multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev);
- bio_endio(bio, bio->bi_size, err);
+ bio_endio(bio, err);
mempool_free(mp_bh, conf->pool);
}
-static int multipath_end_request(struct bio *bio, unsigned int bytes_done,
- int error)
+static void multipath_end_request(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct multipath_bh * mp_bh = (struct multipath_bh *)(bio->bi_private);
multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev);
mdk_rdev_t *rdev = conf->multipaths[mp_bh->path].rdev;
- if (bio->bi_size)
- return 1;
-
if (uptodate)
multipath_end_bh_io(mp_bh, 0);
else if (!bio_rw_ahead(bio)) {
@@ -112,7 +108,6 @@ static int multipath_end_request(struct bio *bio, unsigned int bytes_done,
} else
multipath_end_bh_io(mp_bh, error);
rdev_dec_pending(rdev, conf->mddev);
- return 0;
}
static void unplug_slaves(mddev_t *mddev)
@@ -130,8 +125,7 @@ static void unplug_slaves(mddev_t *mddev)
atomic_inc(&rdev->nr_pending);
rcu_read_unlock();
- if (r_queue->unplug_fn)
- r_queue->unplug_fn(r_queue);
+ blk_unplug(r_queue);
rdev_dec_pending(rdev, mddev);
rcu_read_lock();
@@ -155,7 +149,7 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio)
const int rw = bio_data_dir(bio);
if (unlikely(bio_barrier(bio))) {
- bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -169,7 +163,7 @@ static int multipath_make_request (struct request_queue *q, struct bio * bio)
mp_bh->path = multipath_map(conf);
if (mp_bh->path < 0) {
- bio_endio(bio, bio->bi_size, -EIO);
+ bio_endio(bio, -EIO);
mempool_free(mp_bh, conf->pool);
return 0;
}
@@ -199,35 +193,6 @@ static void multipath_status (struct seq_file *seq, mddev_t *mddev)
seq_printf (seq, "]");
}
-static int multipath_issue_flush(struct request_queue *q, struct gendisk *disk,
- sector_t *error_sector)
-{
- mddev_t *mddev = q->queuedata;
- multipath_conf_t *conf = mddev_to_conf(mddev);
- int i, ret = 0;
-
- rcu_read_lock();
- for (i=0; i<mddev->raid_disks && ret == 0; i++) {
- mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
- if (rdev && !test_bit(Faulty, &rdev->flags)) {
- struct block_device *bdev = rdev->bdev;
- struct request_queue *r_queue = bdev_get_queue(bdev);
-
- if (!r_queue->issue_flush_fn)
- ret = -EOPNOTSUPP;
- else {
- atomic_inc(&rdev->nr_pending);
- rcu_read_unlock();
- ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk,
- error_sector);
- rdev_dec_pending(rdev, mddev);
- rcu_read_lock();
- }
- }
- }
- rcu_read_unlock();
- return ret;
-}
static int multipath_congested(void *data, int bits)
{
mddev_t *mddev = data;
@@ -532,7 +497,6 @@ static int multipath_run (mddev_t *mddev)
mddev->array_size = mddev->size;
mddev->queue->unplug_fn = multipath_unplug;
- mddev->queue->issue_flush_fn = multipath_issue_flush;
mddev->queue->backing_dev_info.congested_fn = multipath_congested;
mddev->queue->backing_dev_info.congested_data = mddev;
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index b8216bc6db4..f8e591708d1 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -35,31 +35,10 @@ static void raid0_unplug(struct request_queue *q)
for (i=0; i<mddev->raid_disks; i++) {
struct request_queue *r_queue = bdev_get_queue(devlist[i]->bdev);
- if (r_queue->unplug_fn)
- r_queue->unplug_fn(r_queue);
+ blk_unplug(r_queue);
}
}
-static int raid0_issue_flush(struct request_queue *q, struct gendisk *disk,
- sector_t *error_sector)
-{
- mddev_t *mddev = q->queuedata;
- raid0_conf_t *conf = mddev_to_conf(mddev);
- mdk_rdev_t **devlist = conf->strip_zone[0].dev;
- int i, ret = 0;
-
- for (i=0; i<mddev->raid_disks && ret == 0; i++) {
- struct block_device *bdev = devlist[i]->bdev;
- struct request_queue *r_queue = bdev_get_queue(bdev);
-
- if (!r_queue->issue_flush_fn)
- ret = -EOPNOTSUPP;
- else
- ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
- }
- return ret;
-}
-
static int raid0_congested(void *data, int bits)
{
mddev_t *mddev = data;
@@ -250,7 +229,6 @@ static int create_strip_zones (mddev_t *mddev)
mddev->queue->unplug_fn = raid0_unplug;
- mddev->queue->issue_flush_fn = raid0_issue_flush;
mddev->queue->backing_dev_info.congested_fn = raid0_congested;
mddev->queue->backing_dev_info.congested_data = mddev;
@@ -420,7 +398,7 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio)
const int rw = bio_data_dir(bio);
if (unlikely(bio_barrier(bio))) {
- bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -490,10 +468,10 @@ bad_map:
" or bigger than %dk %llu %d\n", chunk_size,
(unsigned long long)bio->bi_sector, bio->bi_size >> 10);
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
-
+
static void raid0_status (struct seq_file *seq, mddev_t *mddev)
{
#undef MD_DEBUG
@@ -501,18 +479,18 @@ static void raid0_status (struct seq_file *seq, mddev_t *mddev)
int j, k, h;
char b[BDEVNAME_SIZE];
raid0_conf_t *conf = mddev_to_conf(mddev);
-
+
h = 0;
for (j = 0; j < conf->nr_strip_zones; j++) {
seq_printf(seq, " z%d", j);
if (conf->hash_table[h] == conf->strip_zone+j)
- seq_printf("(h%d)", h++);
+ seq_printf(seq, "(h%d)", h++);
seq_printf(seq, "=[");
for (k = 0; k < conf->strip_zone[j].nb_dev; k++)
- seq_printf (seq, "%s/", bdevname(
+ seq_printf(seq, "%s/", bdevname(
conf->strip_zone[j].dev[k]->bdev,b));
- seq_printf (seq, "] zo=%d do=%d s=%d\n",
+ seq_printf(seq, "] zo=%d do=%d s=%d\n",
conf->strip_zone[j].zone_offset,
conf->strip_zone[j].dev_offset,
conf->strip_zone[j].size);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index f33a729960c..4a69c416e04 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -9,7 +9,7 @@
*
* Better read-balancing code written by Mika Kuoppala <miku@iki.fi>, 2000
*
- * Fixes to reconstruction by Jakob Østergaard" <jakob@ostenfeld.dk>
+ * Fixes to reconstruction by Jakob Østergaard" <jakob@ostenfeld.dk>
* Various fixes by Neil Brown <neilb@cse.unsw.edu.au>
*
* Changes by Peter T. Breuer <ptb@it.uc3m.es> 31/1/2003 to support
@@ -238,7 +238,7 @@ static void raid_end_bio_io(r1bio_t *r1_bio)
(unsigned long long) bio->bi_sector +
(bio->bi_size >> 9) - 1);
- bio_endio(bio, bio->bi_size,
+ bio_endio(bio,
test_bit(R1BIO_Uptodate, &r1_bio->state) ? 0 : -EIO);
}
free_r1bio(r1_bio);
@@ -255,16 +255,13 @@ static inline void update_head_pos(int disk, r1bio_t *r1_bio)
r1_bio->sector + (r1_bio->sectors);
}
-static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int error)
+static void raid1_end_read_request(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
int mirror;
conf_t *conf = mddev_to_conf(r1_bio->mddev);
- if (bio->bi_size)
- return 1;
-
mirror = r1_bio->read_disk;
/*
* this branch is our 'one mirror IO has finished' event handler:
@@ -301,10 +298,9 @@ static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int
}
rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
- return 0;
}
-static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int error)
+static void raid1_end_write_request(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
@@ -312,8 +308,6 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
conf_t *conf = mddev_to_conf(r1_bio->mddev);
struct bio *to_put = NULL;
- if (bio->bi_size)
- return 1;
for (mirror = 0; mirror < conf->raid_disks; mirror++)
if (r1_bio->bios[mirror] == bio)
@@ -366,7 +360,7 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
(unsigned long long) mbio->bi_sector,
(unsigned long long) mbio->bi_sector +
(mbio->bi_size >> 9) - 1);
- bio_endio(mbio, mbio->bi_size, 0);
+ bio_endio(mbio, 0);
}
}
}
@@ -400,8 +394,6 @@ static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int
if (to_put)
bio_put(to_put);
-
- return 0;
}
@@ -557,8 +549,7 @@ static void unplug_slaves(mddev_t *mddev)
atomic_inc(&rdev->nr_pending);
rcu_read_unlock();
- if (r_queue->unplug_fn)
- r_queue->unplug_fn(r_queue);
+ blk_unplug(r_queue);
rdev_dec_pending(rdev, mddev);
rcu_read_lock();
@@ -575,36 +566,6 @@ static void raid1_unplug(struct request_queue *q)
md_wakeup_thread(mddev->thread);
}
-static int raid1_issue_flush(struct request_queue *q, struct gendisk *disk,
- sector_t *error_sector)
-{
- mddev_t *mddev = q->queuedata;
- conf_t *conf = mddev_to_conf(mddev);
- int i, ret = 0;
-
- rcu_read_lock();
- for (i=0; i<mddev->raid_disks && ret == 0; i++) {
- mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
- if (rdev && !test_bit(Faulty, &rdev->flags)) {
- struct block_device *bdev = rdev->bdev;
- struct request_queue *r_queue = bdev_get_queue(bdev);
-
- if (!r_queue->issue_flush_fn)
- ret = -EOPNOTSUPP;
- else {
- atomic_inc(&rdev->nr_pending);
- rcu_read_unlock();
- ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk,
- error_sector);
- rdev_dec_pending(rdev, mddev);
- rcu_read_lock();
- }
- }
- }
- rcu_read_unlock();
- return ret;
-}
-
static int raid1_congested(void *data, int bits)
{
mddev_t *mddev = data;
@@ -796,7 +757,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
if (unlikely(!mddev->barriers_work && bio_barrier(bio))) {
if (rw == WRITE)
md_write_end(mddev);
- bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -1137,14 +1098,11 @@ abort:
}
-static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
+static void end_sync_read(struct bio *bio, int error)
{
r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
int i;
- if (bio->bi_size)
- return 1;
-
for (i=r1_bio->mddev->raid_disks; i--; )
if (r1_bio->bios[i] == bio)
break;
@@ -1160,10 +1118,9 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
if (atomic_dec_and_test(&r1_bio->remaining))
reschedule_retry(r1_bio);
- return 0;
}
-static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
+static void end_sync_write(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
@@ -1172,9 +1129,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
int i;
int mirror=0;
- if (bio->bi_size)
- return 1;
-
for (i = 0; i < conf->raid_disks; i++)
if (r1_bio->bios[i] == bio) {
mirror = i;
@@ -1200,7 +1154,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
md_done_sync(mddev, r1_bio->sectors, uptodate);
put_buf(r1_bio);
}
- return 0;
}
static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
@@ -1260,7 +1213,8 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
j = 0;
if (j >= 0)
mddev->resync_mismatches += r1_bio->sectors;
- if (j < 0 || test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) {
+ if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)
+ && test_bit(BIO_UPTODATE, &sbio->bi_flags))) {
sbio->bi_end_io = NULL;
rdev_dec_pending(conf->mirrors[i].rdev, mddev);
} else {
@@ -2013,7 +1967,6 @@ static int run(mddev_t *mddev)
mddev->array_size = mddev->size;
mddev->queue->unplug_fn = raid1_unplug;
- mddev->queue->issue_flush_fn = raid1_issue_flush;
mddev->queue->backing_dev_info.congested_fn = raid1_congested;
mddev->queue->backing_dev_info.congested_data = mddev;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 4e53792aa52..5cdcc938620 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -227,7 +227,7 @@ static void raid_end_bio_io(r10bio_t *r10_bio)
{
struct bio *bio = r10_bio->master_bio;
- bio_endio(bio, bio->bi_size,
+ bio_endio(bio,
test_bit(R10BIO_Uptodate, &r10_bio->state) ? 0 : -EIO);
free_r10bio(r10_bio);
}
@@ -243,15 +243,13 @@ static inline void update_head_pos(int slot, r10bio_t *r10_bio)
r10_bio->devs[slot].addr + (r10_bio->sectors);
}
-static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int error)
+static void raid10_end_read_request(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
int slot, dev;
conf_t *conf = mddev_to_conf(r10_bio->mddev);
- if (bio->bi_size)
- return 1;
slot = r10_bio->read_slot;
dev = r10_bio->devs[slot].devnum;
@@ -284,19 +282,15 @@ static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int
}
rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
- return 0;
}
-static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, int error)
+static void raid10_end_write_request(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
int slot, dev;
conf_t *conf = mddev_to_conf(r10_bio->mddev);
- if (bio->bi_size)
- return 1;
-
for (slot = 0; slot < conf->copies; slot++)
if (r10_bio->devs[slot].bio == bio)
break;
@@ -339,7 +333,6 @@ static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, in
}
rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
- return 0;
}
@@ -600,8 +593,7 @@ static void unplug_slaves(mddev_t *mddev)
atomic_inc(&rdev->nr_pending);
rcu_read_unlock();
- if (r_queue->unplug_fn)
- r_queue->unplug_fn(r_queue);
+ blk_unplug(r_queue);
rdev_dec_pending(rdev, mddev);
rcu_read_lock();
@@ -618,36 +610,6 @@ static void raid10_unplug(struct request_queue *q)
md_wakeup_thread(mddev->thread);
}
-static int raid10_issue_flush(struct request_queue *q, struct gendisk *disk,
- sector_t *error_sector)
-{
- mddev_t *mddev = q->queuedata;
- conf_t *conf = mddev_to_conf(mddev);
- int i, ret = 0;
-
- rcu_read_lock();
- for (i=0; i<mddev->raid_disks && ret == 0; i++) {
- mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
- if (rdev && !test_bit(Faulty, &rdev->flags)) {
- struct block_device *bdev = rdev->bdev;
- struct request_queue *r_queue = bdev_get_queue(bdev);
-
- if (!r_queue->issue_flush_fn)
- ret = -EOPNOTSUPP;
- else {
- atomic_inc(&rdev->nr_pending);
- rcu_read_unlock();
- ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk,
- error_sector);
- rdev_dec_pending(rdev, mddev);
- rcu_read_lock();
- }
- }
- }
- rcu_read_unlock();
- return ret;
-}
-
static int raid10_congested(void *data, int bits)
{
mddev_t *mddev = data;
@@ -787,7 +749,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
unsigned long flags;
if (unlikely(bio_barrier(bio))) {
- bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ bio_endio(bio, -EOPNOTSUPP);
return 0;
}
@@ -819,7 +781,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
" or bigger than %dk %llu %d\n", chunk_sects/2,
(unsigned long long)bio->bi_sector, bio->bi_size >> 10);
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
@@ -1155,15 +1117,12 @@ abort:
}
-static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
+static void end_sync_read(struct bio *bio, int error)
{
r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
conf_t *conf = mddev_to_conf(r10_bio->mddev);
int i,d;
- if (bio->bi_size)
- return 1;
-
for (i=0; i<conf->copies; i++)
if (r10_bio->devs[i].bio == bio)
break;
@@ -1192,10 +1151,9 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
reschedule_retry(r10_bio);
}
rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev);
- return 0;
}
-static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
+static void end_sync_write(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
@@ -1203,9 +1161,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
conf_t *conf = mddev_to_conf(mddev);
int i,d;
- if (bio->bi_size)
- return 1;
-
for (i = 0; i < conf->copies; i++)
if (r10_bio->devs[i].bio == bio)
break;
@@ -1228,7 +1183,6 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
}
}
rdev_dec_pending(conf->mirrors[d].rdev, mddev);
- return 0;
}
/*
@@ -1374,7 +1328,7 @@ static void recovery_request_write(mddev_t *mddev, r10bio_t *r10_bio)
if (test_bit(R10BIO_Uptodate, &r10_bio->state))
generic_make_request(wbio);
else
- bio_endio(wbio, wbio->bi_size, -EIO);
+ bio_endio(wbio, -EIO);
}
@@ -2133,7 +2087,6 @@ static int run(mddev_t *mddev)
mddev->resync_max_sectors = size << conf->chunk_shift;
mddev->queue->unplug_fn = raid10_unplug;
- mddev->queue->issue_flush_fn = raid10_issue_flush;
mddev->queue->backing_dev_info.congested_fn = raid10_congested;
mddev->queue->backing_dev_info.congested_data = mddev;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index f96dea975fa..a5aad8cad84 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -108,12 +108,11 @@ static void return_io(struct bio *return_bi)
{
struct bio *bi = return_bi;
while (bi) {
- int bytes = bi->bi_size;
return_bi = bi->bi_next;
bi->bi_next = NULL;
bi->bi_size = 0;
- bi->bi_end_io(bi, bytes,
+ bi->bi_end_io(bi,
test_bit(BIO_UPTODATE, &bi->bi_flags)
? 0 : -EIO);
bi = return_bi;
@@ -377,15 +376,20 @@ static unsigned long get_stripe_work(struct stripe_head *sh)
ack++;
sh->ops.count -= ack;
- BUG_ON(sh->ops.count < 0);
+ if (unlikely(sh->ops.count < 0)) {
+ printk(KERN_ERR "pending: %#lx ops.pending: %#lx ops.ack: %#lx "
+ "ops.complete: %#lx\n", pending, sh->ops.pending,
+ sh->ops.ack, sh->ops.complete);
+ BUG();
+ }
return pending;
}
-static int
-raid5_end_read_request(struct bio *bi, unsigned int bytes_done, int error);
-static int
-raid5_end_write_request (struct bio *bi, unsigned int bytes_done, int error);
+static void
+raid5_end_read_request(struct bio *bi, int error);
+static void
+raid5_end_write_request(struct bio *bi, int error);
static void ops_run_io(struct stripe_head *sh)
{
@@ -551,8 +555,7 @@ static void ops_complete_biofill(void *stripe_head_ref)
}
}
}
- clear_bit(STRIPE_OP_BIOFILL, &sh->ops.ack);
- clear_bit(STRIPE_OP_BIOFILL, &sh->ops.pending);
+ set_bit(STRIPE_OP_BIOFILL, &sh->ops.complete);
return_io(return_bi);
@@ -685,7 +688,8 @@ ops_run_prexor(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
}
static struct dma_async_tx_descriptor *
-ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
+ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx,
+ unsigned long pending)
{
int disks = sh->disks;
int pd_idx = sh->pd_idx, i;
@@ -693,7 +697,7 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
/* check if prexor is active which means only process blocks
* that are part of a read-modify-write (Wantprexor)
*/
- int prexor = test_bit(STRIPE_OP_PREXOR, &sh->ops.pending);
+ int prexor = test_bit(STRIPE_OP_PREXOR, &pending);
pr_debug("%s: stripe %llu\n", __FUNCTION__,
(unsigned long long)sh->sector);
@@ -770,7 +774,8 @@ static void ops_complete_write(void *stripe_head_ref)
}
static void
-ops_run_postxor(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
+ops_run_postxor(struct stripe_head *sh, struct dma_async_tx_descriptor *tx,
+ unsigned long pending)
{
/* kernel stack size limits the total number of disks */
int disks = sh->disks;
@@ -778,7 +783,7 @@ ops_run_postxor(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
int count = 0, pd_idx = sh->pd_idx, i;
struct page *xor_dest;
- int prexor = test_bit(STRIPE_OP_PREXOR, &sh->ops.pending);
+ int prexor = test_bit(STRIPE_OP_PREXOR, &pending);
unsigned long flags;
dma_async_tx_callback callback;
@@ -805,7 +810,7 @@ ops_run_postxor(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
}
/* check whether this postxor is part of a write */
- callback = test_bit(STRIPE_OP_BIODRAIN, &sh->ops.pending) ?
+ callback = test_bit(STRIPE_OP_BIODRAIN, &pending) ?
ops_complete_write : ops_complete_postxor;
/* 1/ if we prexor'd then the dest is reused as a source
@@ -893,12 +898,12 @@ static void raid5_run_ops(struct stripe_head *sh, unsigned long pending)
tx = ops_run_prexor(sh, tx);
if (test_bit(STRIPE_OP_BIODRAIN, &pending)) {
- tx = ops_run_biodrain(sh, tx);
+ tx = ops_run_biodrain(sh, tx, pending);
overlap_clear++;
}
if (test_bit(STRIPE_OP_POSTXOR, &pending))
- ops_run_postxor(sh, tx);
+ ops_run_postxor(sh, tx, pending);
if (test_bit(STRIPE_OP_CHECK, &pending))
ops_run_check(sh);
@@ -1110,8 +1115,7 @@ static void shrink_stripes(raid5_conf_t *conf)
conf->slab_cache = NULL;
}
-static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
- int error)
+static void raid5_end_read_request(struct bio * bi, int error)
{
struct stripe_head *sh = bi->bi_private;
raid5_conf_t *conf = sh->raid_conf;
@@ -1120,8 +1124,6 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
char b[BDEVNAME_SIZE];
mdk_rdev_t *rdev;
- if (bi->bi_size)
- return 1;
for (i=0 ; i<disks; i++)
if (bi == &sh->dev[i].req)
@@ -1132,7 +1134,7 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
uptodate);
if (i == disks) {
BUG();
- return 0;
+ return;
}
if (uptodate) {
@@ -1185,20 +1187,15 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
clear_bit(R5_LOCKED, &sh->dev[i].flags);
set_bit(STRIPE_HANDLE, &sh->state);
release_stripe(sh);
- return 0;
}
-static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
- int error)
+static void raid5_end_write_request (struct bio *bi, int error)
{
struct stripe_head *sh = bi->bi_private;
raid5_conf_t *conf = sh->raid_conf;
int disks = sh->disks, i;
int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
- if (bi->bi_size)
- return 1;
-
for (i=0 ; i<disks; i++)
if (bi == &sh->dev[i].req)
break;
@@ -1208,7 +1205,7 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
uptodate);
if (i == disks) {
BUG();
- return 0;
+ return;
}
if (!uptodate)
@@ -1219,7 +1216,6 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
clear_bit(R5_LOCKED, &sh->dev[i].flags);
set_bit(STRIPE_HANDLE, &sh->state);
release_stripe(sh);
- return 0;
}
@@ -2630,6 +2626,13 @@ static void handle_stripe5(struct stripe_head *sh)
s.expanded = test_bit(STRIPE_EXPAND_READY, &sh->state);
/* Now to look around and see what can be done */
+ /* clean-up completed biofill operations */
+ if (test_bit(STRIPE_OP_BIOFILL, &sh->ops.complete)) {
+ clear_bit(STRIPE_OP_BIOFILL, &sh->ops.pending);
+ clear_bit(STRIPE_OP_BIOFILL, &sh->ops.ack);
+ clear_bit(STRIPE_OP_BIOFILL, &sh->ops.complete);
+ }
+
rcu_read_lock();
for (i=disks; i--; ) {
mdk_rdev_t *rdev;
@@ -3185,8 +3188,7 @@ static void unplug_slaves(mddev_t *mddev)
atomic_inc(&rdev->nr_pending);
rcu_read_unlock();
- if (r_queue->unplug_fn)
- r_queue->unplug_fn(r_queue);
+ blk_unplug(r_queue);
rdev_dec_pending(rdev, mddev);
rcu_read_lock();
@@ -3214,36 +3216,6 @@ static void raid5_unplug_device(struct request_queue *q)
unplug_slaves(mddev);
}
-static int raid5_issue_flush(struct request_queue *q, struct gendisk *disk,
- sector_t *error_sector)
-{
- mddev_t *mddev = q->queuedata;
- raid5_conf_t *conf = mddev_to_conf(mddev);
- int i, ret = 0;
-
- rcu_read_lock();
- for (i=0; i<mddev->raid_disks && ret == 0; i++) {
- mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
- if (rdev && !test_bit(Faulty, &rdev->flags)) {
- struct block_device *bdev = rdev->bdev;
- struct request_queue *r_queue = bdev_get_queue(bdev);
-
- if (!r_queue->issue_flush_fn)
- ret = -EOPNOTSUPP;
- else {
- atomic_inc(&rdev->nr_pending);
- rcu_read_unlock();
- ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk,
- error_sector);
- rdev_dec_pending(rdev, mddev);
- rcu_read_lock();
- }
- }
- }
- rcu_read_unlock();
- return ret;
-}
-
static int raid5_congested(void *data, int bits)
{
mddev_t *mddev = data;
@@ -3340,7 +3312,7 @@ static struct bio *remove_bio_from_retry(raid5_conf_t *conf)
* first).
* If the read failed..
*/
-static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error)
+static void raid5_align_endio(struct bio *bi, int error)
{
struct bio* raid_bi = bi->bi_private;
mddev_t *mddev;
@@ -3348,8 +3320,6 @@ static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error)
int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
mdk_rdev_t *rdev;
- if (bi->bi_size)
- return 1;
bio_put(bi);
mddev = raid_bi->bi_bdev->bd_disk->queue->queuedata;
@@ -3360,17 +3330,16 @@ static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error)
rdev_dec_pending(rdev, conf->mddev);
if (!error && uptodate) {
- bio_endio(raid_bi, bytes, 0);
+ bio_endio(raid_bi, 0);
if (atomic_dec_and_test(&conf->active_aligned_reads))
wake_up(&conf->wait_for_stripe);
- return 0;
+ return;
}
pr_debug("raid5_align_endio : io error...handing IO for a retry\n");
add_bio_to_retry(raid_bi, conf);
- return 0;
}
static int bio_fits_rdev(struct bio *bi)
@@ -3476,7 +3445,7 @@ static int make_request(struct request_queue *q, struct bio * bi)
int remaining;
if (unlikely(bio_barrier(bi))) {
- bio_endio(bi, bi->bi_size, -EOPNOTSUPP);
+ bio_endio(bi, -EOPNOTSUPP);
return 0;
}
@@ -3592,12 +3561,11 @@ static int make_request(struct request_queue *q, struct bio * bi)
remaining = --bi->bi_phys_segments;
spin_unlock_irq(&conf->device_lock);
if (remaining == 0) {
- int bytes = bi->bi_size;
if ( rw == WRITE )
md_write_end(mddev);
- bi->bi_size = 0;
- bi->bi_end_io(bi, bytes,
+
+ bi->bi_end_io(bi,
test_bit(BIO_UPTODATE, &bi->bi_flags)
? 0 : -EIO);
}
@@ -3875,10 +3843,8 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio)
remaining = --raid_bio->bi_phys_segments;
spin_unlock_irq(&conf->device_lock);
if (remaining == 0) {
- int bytes = raid_bio->bi_size;
- raid_bio->bi_size = 0;
- raid_bio->bi_end_io(raid_bio, bytes,
+ raid_bio->bi_end_io(raid_bio,
test_bit(BIO_UPTODATE, &raid_bio->bi_flags)
? 0 : -EIO);
}
@@ -4279,7 +4245,6 @@ static int run(mddev_t *mddev)
mdname(mddev));
mddev->queue->unplug_fn = raid5_unplug_device;
- mddev->queue->issue_flush_fn = raid5_issue_flush;
mddev->queue->backing_dev_info.congested_data = mddev;
mddev->queue->backing_dev_info.congested_fn = raid5_congested;
diff --git a/drivers/md/raid6algos.c b/drivers/md/raid6algos.c
index 92657615657..77a6e4bf503 100644
--- a/drivers/md/raid6algos.c
+++ b/drivers/md/raid6algos.c
@@ -52,7 +52,7 @@ const struct raid6_calls * const raid6_algos[] = {
&raid6_intx16,
&raid6_intx32,
#endif
-#if defined(__i386__)
+#if defined(__i386__) && !defined(__arch_um__)
&raid6_mmxx1,
&raid6_mmxx2,
&raid6_sse1x1,
@@ -60,7 +60,7 @@ const struct raid6_calls * const raid6_algos[] = {
&raid6_sse2x1,
&raid6_sse2x2,
#endif
-#if defined(__x86_64__)
+#if defined(__x86_64__) && !defined(__arch_um__)
&raid6_sse2x1,
&raid6_sse2x2,
&raid6_sse2x4,
diff --git a/drivers/md/raid6mmx.c b/drivers/md/raid6mmx.c
index 6181a5a3365..d4e4a1bd70a 100644
--- a/drivers/md/raid6mmx.c
+++ b/drivers/md/raid6mmx.c
@@ -16,7 +16,7 @@
* MMX implementation of RAID-6 syndrome functions
*/
-#if defined(__i386__)
+#if defined(__i386__) && !defined(__arch_um__)
#include "raid6.h"
#include "raid6x86.h"
diff --git a/drivers/md/raid6sse1.c b/drivers/md/raid6sse1.c
index f0a1ba8f40b..0666237276f 100644
--- a/drivers/md/raid6sse1.c
+++ b/drivers/md/raid6sse1.c
@@ -21,7 +21,7 @@
* worthwhile as a separate implementation.
*/
-#if defined(__i386__)
+#if defined(__i386__) && !defined(__arch_um__)
#include "raid6.h"
#include "raid6x86.h"
diff --git a/drivers/md/raid6sse2.c b/drivers/md/raid6sse2.c
index 0f019762a7c..b034ad86803 100644
--- a/drivers/md/raid6sse2.c
+++ b/drivers/md/raid6sse2.c
@@ -17,7 +17,7 @@
*
*/
-#if defined(__i386__) || defined(__x86_64__)
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__)
#include "raid6.h"
#include "raid6x86.h"
@@ -161,7 +161,7 @@ const struct raid6_calls raid6_sse2x2 = {
#endif
-#ifdef __x86_64__
+#if defined(__x86_64__) && !defined(__arch_um__)
/*
* Unrolled-by-4 SSE2 implementation
diff --git a/drivers/md/raid6x86.h b/drivers/md/raid6x86.h
index 9111950414f..99fea7a70ca 100644
--- a/drivers/md/raid6x86.h
+++ b/drivers/md/raid6x86.h
@@ -19,7 +19,7 @@
#ifndef LINUX_RAID_RAID6X86_H
#define LINUX_RAID_RAID6X86_H
-#if defined(__i386__) || defined(__x86_64__)
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__)
#ifdef __KERNEL__ /* Real code */
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index d9d033e07e1..1604f049040 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -69,13 +69,79 @@ source "drivers/media/common/Kconfig"
config VIDEO_TUNER
tristate
depends on I2C
+ select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE
+ select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE
+ select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE
+ select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE
+ select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE
+
+menuconfig VIDEO_TUNER_CUSTOMIZE
+ bool "Customize analog tuner modules to build"
+ depends on VIDEO_TUNER
+ help
+ This allows the user to deselect tuner drivers unnecessary
+ for their hardware from the build. Use this option with care
+ as deselecting tuner drivers which are in fact necessary will
+ result in V4L devices which cannot be tuned due to lack of
+ driver support
+
+ If unsure say N.
+
+if VIDEO_TUNER_CUSTOMIZE
+
+config TUNER_MT20XX
+ tristate "Microtune 2032 / 2050 tuners"
+ depends on I2C
+ default m if VIDEO_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for the MT2032 / MT2050 tuner.
+
+config TUNER_TDA8290
+ tristate "TDA 8290+8275(a) tuner combo"
+ depends on I2C
+ default m if VIDEO_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for Philips TDA8290+8275(a) tuner.
+
+config TUNER_TEA5761
+ tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
+ depends on I2C && EXPERIMENTAL
+ default m if VIDEO_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for the Philips TEA5761 radio tuner.
+
+config TUNER_TEA5767
+ tristate "TEA 5767 radio tuner"
+ depends on I2C
+ default m if VIDEO_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for the Philips TEA5767 radio tuner.
+
+config TUNER_SIMPLE
+ tristate "Simple tuner support"
+ depends on I2C
+ default m if VIDEO_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for various simple tuners.
-config VIDEO_BUF
+endif # VIDEO_TUNER_CUSTOMIZE
+
+config VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_DMA_SG
depends on PCI
+ select VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_VMALLOC
+ select VIDEOBUF_GEN
tristate
-config VIDEO_BUF_DVB
+config VIDEOBUF_DVB
tristate
+ select VIDEOBUF_GEN
+ select VIDEOBUF_DMA_SG
config VIDEO_BTCX
tristate
@@ -85,6 +151,7 @@ config VIDEO_IR_I2C
config VIDEO_IR
tristate
+ depends on INPUT
select VIDEO_IR_I2C if I2C
config VIDEO_TVEEPROM
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 5c63c8e24ee..c5092ef1082 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -5,5 +5,5 @@ config VIDEO_SAA7146
config VIDEO_SAA7146_VV
tristate
depends on VIDEO_DEV
- select VIDEO_BUF
+ select VIDEOBUF_DMA_SG
select VIDEO_SAA7146
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index a3292e955aa..e7c3ab951a4 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -21,7 +21,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/jiffies.h>
#include <media/ir-common.h>
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index cbd1184b521..185e8a860c1 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -20,7 +20,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/input.h>
#include <media/ir-common.h>
@@ -1075,41 +1074,41 @@ EXPORT_SYMBOL_GPL(ir_codes_manli);
/* Mike Baikov <mike@baikov.com> */
IR_KEYTAB_TYPE ir_codes_gotview7135[IR_KEYTAB_SIZE] = {
- [ 0x21 ] = KEY_POWER,
- [ 0x69 ] = KEY_TV,
- [ 0x33 ] = KEY_0,
- [ 0x51 ] = KEY_1,
- [ 0x31 ] = KEY_2,
- [ 0x71 ] = KEY_3,
- [ 0x3b ] = KEY_4,
- [ 0x58 ] = KEY_5,
- [ 0x41 ] = KEY_6,
- [ 0x48 ] = KEY_7,
- [ 0x30 ] = KEY_8,
- [ 0x53 ] = KEY_9,
- [ 0x73 ] = KEY_AGAIN, /* LOOP */
- [ 0x0a ] = KEY_AUDIO,
- [ 0x61 ] = KEY_PRINT, /* PREVIEW */
- [ 0x7a ] = KEY_VIDEO,
- [ 0x20 ] = KEY_CHANNELUP,
- [ 0x40 ] = KEY_CHANNELDOWN,
- [ 0x18 ] = KEY_VOLUMEDOWN,
- [ 0x50 ] = KEY_VOLUMEUP,
- [ 0x10 ] = KEY_MUTE,
- [ 0x4a ] = KEY_SEARCH,
- [ 0x7b ] = KEY_SHUFFLE, /* SNAPSHOT */
- [ 0x22 ] = KEY_RECORD,
- [ 0x62 ] = KEY_STOP,
- [ 0x78 ] = KEY_PLAY,
- [ 0x39 ] = KEY_REWIND,
- [ 0x59 ] = KEY_PAUSE,
- [ 0x19 ] = KEY_FORWARD,
- [ 0x09 ] = KEY_ZOOM,
-
- [ 0x52 ] = KEY_F21, /* LIVE TIMESHIFT */
- [ 0x1a ] = KEY_F22, /* MIN TIMESHIFT */
- [ 0x3a ] = KEY_F23, /* TIMESHIFT */
- [ 0x70 ] = KEY_F24, /* NORMAL TIMESHIFT */
+ [ 0x11 ] = KEY_POWER,
+ [ 0x35 ] = KEY_TV,
+ [ 0x1b ] = KEY_0,
+ [ 0x29 ] = KEY_1,
+ [ 0x19 ] = KEY_2,
+ [ 0x39 ] = KEY_3,
+ [ 0x1f ] = KEY_4,
+ [ 0x2c ] = KEY_5,
+ [ 0x21 ] = KEY_6,
+ [ 0x24 ] = KEY_7,
+ [ 0x18 ] = KEY_8,
+ [ 0x2b ] = KEY_9,
+ [ 0x3b ] = KEY_AGAIN, /* LOOP */
+ [ 0x06 ] = KEY_AUDIO,
+ [ 0x31 ] = KEY_PRINT, /* PREVIEW */
+ [ 0x3e ] = KEY_VIDEO,
+ [ 0x10 ] = KEY_CHANNELUP,
+ [ 0x20 ] = KEY_CHANNELDOWN,
+ [ 0x0c ] = KEY_VOLUMEDOWN,
+ [ 0x28 ] = KEY_VOLUMEUP,
+ [ 0x08 ] = KEY_MUTE,
+ [ 0x26 ] = KEY_SEARCH, /*SCAN*/
+ [ 0x3f ] = KEY_SHUFFLE, /* SNAPSHOT */
+ [ 0x12 ] = KEY_RECORD,
+ [ 0x32 ] = KEY_STOP,
+ [ 0x3c ] = KEY_PLAY,
+ [ 0x1d ] = KEY_REWIND,
+ [ 0x2d ] = KEY_PAUSE,
+ [ 0x0d ] = KEY_FORWARD,
+ [ 0x05 ] = KEY_ZOOM, /*FULL*/
+
+ [ 0x2a ] = KEY_F21, /* LIVE TIMESHIFT */
+ [ 0x0e ] = KEY_F22, /* MIN TIMESHIFT */
+ [ 0x1e ] = KEY_F23, /* TIMESHIFT */
+ [ 0x38 ] = KEY_F24, /* NORMAL TIMESHIFT */
};
EXPORT_SYMBOL_GPL(ir_codes_gotview7135);
@@ -1783,3 +1782,64 @@ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
};
EXPORT_SYMBOL_GPL(ir_codes_tt_1500);
+
+/* DViCO FUSION HDTV MCE remote */
+IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = {
+
+ [ 0x0b ] = KEY_1,
+ [ 0x17 ] = KEY_2,
+ [ 0x1b ] = KEY_3,
+ [ 0x07 ] = KEY_4,
+ [ 0x50 ] = KEY_5,
+ [ 0x54 ] = KEY_6,
+ [ 0x48 ] = KEY_7,
+ [ 0x4c ] = KEY_8,
+ [ 0x58 ] = KEY_9,
+ [ 0x03 ] = KEY_0,
+
+ [ 0x5e ] = KEY_OK,
+ [ 0x51 ] = KEY_UP,
+ [ 0x53 ] = KEY_DOWN,
+ [ 0x5b ] = KEY_LEFT,
+ [ 0x5f ] = KEY_RIGHT,
+
+ [ 0x02 ] = KEY_TV, /* Labeled DTV on remote */
+ [ 0x0e ] = KEY_MP3,
+ [ 0x1a ] = KEY_DVD,
+ [ 0x1e ] = KEY_FAVORITES, /* Labeled CPF on remote */
+ [ 0x16 ] = KEY_SETUP,
+ [ 0x46 ] = KEY_POWER2, /* TV On/Off button on remote */
+ [ 0x0a ] = KEY_EPG, /* Labeled Guide on remote */
+
+ [ 0x49 ] = KEY_BACK,
+ [ 0x59 ] = KEY_INFO, /* Labeled MORE on remote */
+ [ 0x4d ] = KEY_MENU, /* Labeled DVDMENU on remote */
+ [ 0x55 ] = KEY_CYCLEWINDOWS, /* Labeled ALT-TAB on remote */
+
+ [ 0x0f ] = KEY_PREVIOUSSONG, /* Labeled |<< REPLAY on remote */
+ [ 0x12 ] = KEY_NEXTSONG, /* Labeled >>| SKIP on remote */
+ [ 0x42 ] = KEY_ENTER, /* Labeled START with a green
+ * MS windows logo on remote */
+
+ [ 0x15 ] = KEY_VOLUMEUP,
+ [ 0x05 ] = KEY_VOLUMEDOWN,
+ [ 0x11 ] = KEY_CHANNELUP,
+ [ 0x09 ] = KEY_CHANNELDOWN,
+
+ [ 0x52 ] = KEY_CAMERA,
+ [ 0x5a ] = KEY_TUNER,
+ [ 0x19 ] = KEY_OPEN,
+
+ [ 0x13 ] = KEY_MODE, /* 4:3 16:9 select */
+ [ 0x1f ] = KEY_ZOOM,
+
+ [ 0x43 ] = KEY_REWIND,
+ [ 0x47 ] = KEY_PLAYPAUSE,
+ [ 0x4f ] = KEY_FASTFORWARD,
+ [ 0x57 ] = KEY_MUTE,
+ [ 0x0d ] = KEY_STOP,
+ [ 0x01 ] = KEY_RECORD,
+ [ 0x4e ] = KEY_POWER,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce);
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index ba6701e9767..7d04a6fd1ac 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -59,48 +59,94 @@ void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
}
/* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */
-int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
+static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
+ unsigned long us1, unsigned long us2)
{
- unsigned long start;
+ unsigned long timeout;
int err;
/* wait for registers to be programmed */
- start = jiffies;
+ timeout = jiffies + usecs_to_jiffies(us1);
while (1) {
- err = time_after(jiffies, start + HZ/20);
+ err = time_after(jiffies, timeout);
if (saa7146_read(dev, MC2) & 2)
break;
if (err) {
- DEB_S(("timed out while waiting for registers getting programmed\n"));
+ printk(KERN_ERR "%s: %s timed out while waiting for "
+ "registers getting programmed\n",
+ dev->name, __FUNCTION__);
return -ETIMEDOUT;
}
- if (nobusyloop)
- msleep(1);
+ msleep(1);
}
/* wait for transfer to complete */
- start = jiffies;
+ timeout = jiffies + usecs_to_jiffies(us2);
while (1) {
- err = time_after(jiffies, start + HZ/4);
+ err = time_after(jiffies, timeout);
if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
break;
saa7146_read(dev, MC2);
if (err) {
- DEB_S(("timed out while waiting for transfer completion\n"));
+ DEB_S(("%s: %s timed out while waiting for transfer "
+ "completion\n", dev->name, __FUNCTION__));
return -ETIMEDOUT;
}
- if (nobusyloop)
- msleep(1);
+ msleep(1);
}
return 0;
}
+static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,
+ unsigned long us1, unsigned long us2)
+{
+ unsigned long loops;
+
+ /* wait for registers to be programmed */
+ loops = us1;
+ while (1) {
+ if (saa7146_read(dev, MC2) & 2)
+ break;
+ if (!loops--) {
+ printk(KERN_ERR "%s: %s timed out while waiting for "
+ "registers getting programmed\n",
+ dev->name, __FUNCTION__);
+ return -ETIMEDOUT;
+ }
+ udelay(1);
+ }
+
+ /* wait for transfer to complete */
+ loops = us2 / 5;
+ while (1) {
+ if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
+ break;
+ saa7146_read(dev, MC2);
+ if (!loops--) {
+ DEB_S(("%s: %s timed out while waiting for transfer "
+ "completion\n", dev->name, __FUNCTION__));
+ return -ETIMEDOUT;
+ }
+ udelay(5);
+ }
+
+ return 0;
+}
+
+int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
+{
+ if (nobusyloop)
+ return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000);
+ else
+ return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000);
+}
+
/****************************************************************************
* general helper functions
****************************************************************************/
-/* this is videobuf_vmalloc_to_sg() from video-buf.c
+/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c
make sure virt has been allocated with vmalloc_32(), otherwise the BUG()
may be triggered on highmem machines */
static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
@@ -112,13 +158,13 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
if (NULL == sglist)
return NULL;
+ sg_init_table(sglist, nr_pages);
for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
pg = vmalloc_to_page(virt);
if (NULL == pg)
goto err;
BUG_ON(PageHighMem(pg));
- sglist[i].page = pg;
- sglist[i].length = PAGE_SIZE;
+ sg_set_page(&sglist[i], pg, PAGE_SIZE, 0);
}
return sglist;
@@ -248,10 +294,11 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt
static irqreturn_t interrupt_hw(int irq, void *dev_id)
{
struct saa7146_dev *dev = dev_id;
- u32 isr = 0;
+ u32 isr;
+ u32 ack_isr;
/* read out the interrupt status register */
- isr = saa7146_read(dev, ISR);
+ ack_isr = isr = saa7146_read(dev, ISR);
/* is this our interrupt? */
if ( 0 == isr ) {
@@ -259,8 +306,6 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
return IRQ_NONE;
}
- saa7146_write(dev, ISR, isr);
-
if( 0 != (dev->ext)) {
if( 0 != (dev->ext->irq_mask & isr )) {
if( 0 != dev->ext->irq_func ) {
@@ -283,21 +328,16 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
isr &= ~MASK_28;
}
if (0 != (isr & (MASK_16|MASK_17))) {
- u32 status = saa7146_read(dev, I2C_STATUS);
- if( (0x3 == (status & 0x3)) || (0 == (status & 0x1)) ) {
- SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
- /* only wake up if we expect something */
- if( 0 != dev->i2c_op ) {
- u32 psr = (saa7146_read(dev, PSR) >> 16) & 0x2;
- u32 ssr = (saa7146_read(dev, SSR) >> 17) & 0x1f;
- DEB_I2C(("irq: i2c, status: 0x%08x, psr:0x%02x, ssr:0x%02x).\n",status,psr,ssr));
- dev->i2c_op = 0;
- wake_up(&dev->i2c_wq);
- } else {
- DEB_I2C(("unexpected irq: i2c, status: 0x%08x, isr %#x\n",status, isr));
- }
+ SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
+ /* only wake up if we expect something */
+ if (0 != dev->i2c_op) {
+ dev->i2c_op = 0;
+ wake_up(&dev->i2c_wq);
} else {
- DEB_I2C(("unhandled irq: i2c, status: 0x%08x, isr %#x\n",status, isr));
+ u32 psr = saa7146_read(dev, PSR);
+ u32 ssr = saa7146_read(dev, SSR);
+ printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
+ dev->name, isr, psr, ssr);
}
isr &= ~(MASK_16|MASK_17);
}
@@ -306,6 +346,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
ERR(("disabling interrupt source(s)!\n"));
SAA7146_IER_DISABLE(dev,isr);
}
+ saa7146_write(dev, ISR, ack_isr);
return IRQ_HANDLED;
}
@@ -548,7 +589,6 @@ EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);
EXPORT_SYMBOL_GPL(saa7146_setgpio);
-EXPORT_SYMBOL_GPL(saa7146_i2c_transfer);
EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);
EXPORT_SYMBOL_GPL(saa7146_debug);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index b4770aecc01..67d1b1b1b25 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -53,13 +53,14 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
struct saa7146_buf *buf)
{
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
DEB_EE(("dev:%p, buf:%p\n",dev,buf));
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, &buf->vb.dma);
- videobuf_dma_free(&buf->vb.dma);
+ videobuf_dma_unmap(q, dma);
+ videobuf_dma_free(dma);
buf->vb.state = STATE_NEEDS_INIT;
}
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c
index d2905720eb7..9c905399a23 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146_hlp.c
@@ -312,7 +312,7 @@ static int sort_and_eliminate(u32* values, int* count)
return -EINVAL;
}
- /* bubble sort the first ´count´ items of the array ´values´ */
+ /* bubble sort the first @count items of the array @values */
for( top = *count; top > 0; top--) {
for( low = 0, high = 1; high < top; low++, high++) {
if( values[low] > values[high] ) {
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
index 8c85efc2652..7e7689afae6 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -202,7 +202,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
/* a signal arrived */
return -ERESTARTSYS;
- printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for end of xfer\n");
+ printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n",
+ dev->name, __FUNCTION__);
return -EIO;
}
status = saa7146_read(dev, I2C_STATUS);
@@ -219,7 +220,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
break;
}
if (time_after(jiffies,timeout)) {
- printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for MC2\n");
+ printk(KERN_WARNING "%s %s: timed out waiting for MC2\n",
+ dev->name, __FUNCTION__);
return -EIO;
}
}
@@ -235,7 +237,8 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
/* this is normal when probing the bus
* (no answer from nonexisistant device...)
*/
- DEB_I2C(("saa7146_i2c_writeout: timed out waiting for end of xfer\n"));
+ printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n",
+ dev->name, __FUNCTION__);
return -EIO;
}
if (++trial < 50 && short_delay)
@@ -246,8 +249,16 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
}
/* give a detailed status report */
- if ( 0 != (status & SAA7146_I2C_ERR)) {
-
+ if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR |
+ SAA7146_I2C_DTERR | SAA7146_I2C_DRERR |
+ SAA7146_I2C_AL | SAA7146_I2C_ERR |
+ SAA7146_I2C_BUSY)) ) {
+
+ if ( 0 == (status & SAA7146_I2C_ERR) ||
+ 0 == (status & SAA7146_I2C_BUSY) ) {
+ /* it may take some time until ERR goes high - ignore */
+ DEB_I2C(("unexpected i2c status %04x\n", status));
+ }
if( 0 != (status & SAA7146_I2C_SPERR) ) {
DEB_I2C(("error due to invalid start/stop condition.\n"));
}
@@ -277,7 +288,7 @@ static int saa7146_i2c_writeout(struct saa7146_dev *dev, u32* dword, int short_d
return 0;
}
-int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
+static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
{
int i = 0, count = 0;
u32* buffer = dev->d_i2c.cpu_addr;
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index 063608462eb..6103484e444 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -165,7 +165,7 @@ static void saa7146_set_vbi_capture(struct saa7146_dev *dev, struct saa7146_buf
/* we don't wait here for the first field anymore. this is different from the video
capture and might cause that the first buffer is only half filled (with only
one field). but since this is some sort of streaming data, this is not that negative.
- but by doing this, we can use the whole engine from video-buf.c... */
+ but by doing this, we can use the whole engine from videobuf-dma-sg.c... */
/*
WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait);
@@ -239,6 +239,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
saa7146_dma_free(dev,q,buf);
if (STATE_NEEDS_INIT == buf->vb.state) {
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
buf->vb.width = llength;
buf->vb.height = lines;
buf->vb.size = size;
@@ -250,7 +252,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e
err = videobuf_iolock(q,&buf->vb, NULL);
if (err)
goto oops;
- err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], buf->vb.dma.sglist, buf->vb.dma.sglen);
+ err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2],
+ dma->sglist, dma->sglen);
if (0 != err)
return err;
}
@@ -404,7 +407,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
fh->vbi_fmt.start[1] = 312;
fh->vbi_fmt.count[1] = 16;
- videobuf_queue_init(&fh->vbi_q, &vbi_qops,
+ videobuf_queue_pci_init(&fh->vbi_q, &vbi_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 664280c78ff..f245a3b2ef4 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -594,8 +594,9 @@ static int set_control(struct saa7146_fh *fh, struct v4l2_control *c)
static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
{
struct pci_dev *pci = dev->pci;
- struct scatterlist *list = buf->vb.dma.sglist;
- int length = buf->vb.dma.sglen;
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+ struct scatterlist *list = dma->sglist;
+ int length = dma->sglen;
struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length));
@@ -655,7 +656,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
/* if we have a user buffer, the first page may not be
aligned to a page boundary. */
- pt1->offset = buf->vb.dma.sglist->offset;
+ pt1->offset = list->offset;
pt2->offset = pt1->offset+o1;
pt3->offset = pt1->offset+o2;
@@ -1211,6 +1212,8 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
mutex_unlock(&q->lock);
return err;
}
+
+ gbuffers = err;
memset(mbuf,0,sizeof(*mbuf));
mbuf->frames = gbuffers;
mbuf->size = gbuffers * gbufsize;
@@ -1411,7 +1414,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8;
- videobuf_queue_init(&fh->video_q, &video_qops,
+ videobuf_queue_pci_init(&fh->video_q, &video_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index df72b4b8ee1..85e36a1d6d7 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -28,7 +28,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <asm/io.h>
@@ -281,7 +280,7 @@ static irqreturn_t bt878_irq(int irq, void *dev_id)
if (!(astat = (stat & mask)))
return IRQ_NONE; /* this interrupt is not for me */
/* dprintk("bt878(%d) debug: irq count %d, stat 0x%8.8x, mask 0x%8.8x\n",bt->nr,count,stat,mask); */
- btwrite(astat, BT878_AINT_STAT); /* try to clear interupt condition */
+ btwrite(astat, BT878_AINT_STAT); /* try to clear interrupt condition */
if (astat & (BT878_ASCERR | BT878_AOCERR)) {
diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h
index f685bc12960..d593bc14562 100644
--- a/drivers/media/dvb/bt8xx/bt878.h
+++ b/drivers/media/dvb/bt8xx/bt878.h
@@ -149,11 +149,10 @@ void bt878_start(struct bt878 *bt, u32 controlreg, u32 op_sync_orin,
void bt878_stop(struct bt878 *bt);
#if defined(__powerpc__) /* big-endian */
-extern __inline__ void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
+static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
{
- __asm__ __volatile__("stwbrx %1,0,%2":"=m"(*addr):"r"(val),
- "r"(addr));
- __asm__ __volatile__("eieio":::"memory");
+ st_le32(addr, val);
+ eieio();
}
#define bmtwrite(dat,adr) io_st_le32((adr),(dat))
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 67613eb6fa3..dedd30a8356 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -21,7 +21,6 @@
#include <linux/bitops.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 28929b618e2..db08b0a8888 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -1,5 +1,5 @@
/*
- * TerraTec Cinergy T²/qanu USB2 DVB-T adapter.
+ * TerraTec Cinergy T²/qanu USB2 DVB-T adapter.
*
* Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
* Holger Waechtler <holger@qanu.de>
@@ -345,7 +345,9 @@ static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed)
struct dvb_demux *demux = dvbdmxfeed->demux;
struct cinergyt2 *cinergyt2 = demux->priv;
- if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending)
+ return -EAGAIN;
+ if (mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
if (cinergyt2->streaming == 0)
@@ -361,7 +363,9 @@ static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
struct dvb_demux *demux = dvbdmxfeed->demux;
struct cinergyt2 *cinergyt2 = demux->priv;
- if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending)
+ return -EAGAIN;
+ if (mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
if (--cinergyt2->streaming == 0)
@@ -481,12 +485,16 @@ static int cinergyt2_open (struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
- int err = -ERESTARTSYS;
+ int err = -EAGAIN;
- if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->wq_sem))
+ if (cinergyt2->disconnect_pending)
+ goto out;
+ err = mutex_lock_interruptible(&cinergyt2->wq_sem);
+ if (err)
goto out;
- if (mutex_lock_interruptible(&cinergyt2->sem))
+ err = mutex_lock_interruptible(&cinergyt2->sem);
+ if (err)
goto out_unlock1;
if ((err = dvb_generic_open(inode, file)))
@@ -548,19 +556,21 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
{
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
- unsigned int mask = 0;
+ unsigned int mask = 0;
- if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending)
+ return -EAGAIN;
+ if (mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
poll_wait(file, &cinergyt2->poll_wq, wait);
- if (cinergyt2->pending_fe_events != 0)
+ if (cinergyt2->pending_fe_events != 0)
mask |= (POLLIN | POLLRDNORM | POLLPRI);
mutex_unlock(&cinergyt2->sem);
- return mask;
+ return mask;
}
@@ -625,7 +635,9 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file,
if (copy_from_user(&p, (void __user*) arg, sizeof(p)))
return -EFAULT;
- if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
+ if (cinergyt2->disconnect_pending)
+ return -EAGAIN;
+ if (mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
@@ -820,7 +832,7 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
input_dev->name = DRIVER_NAME " remote control";
input_dev->phys = cinergyt2->phys;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
for (i = 0; i < ARRAY_SIZE(rc_keys); i += 3)
set_bit(rc_keys[i + 2], input_dev->keybit);
input_dev->keycodesize = 0;
@@ -996,7 +1008,9 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
{
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
- if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->wq_sem))
+ if (cinergyt2->disconnect_pending)
+ return -EAGAIN;
+ if (mutex_lock_interruptible(&cinergyt2->wq_sem))
return -ERESTARTSYS;
cinergyt2_suspend_rc(cinergyt2);
@@ -1008,6 +1022,8 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
cinergyt2_sleep(cinergyt2, 1);
mutex_unlock(&cinergyt2->sem);
+ mutex_unlock(&cinergyt2->wq_sem);
+
return 0;
}
@@ -1015,16 +1031,18 @@ static int cinergyt2_resume (struct usb_interface *intf)
{
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
struct dvbt_set_parameters_msg *param = &cinergyt2->param;
- int err = -ERESTARTSYS;
+ int err = -EAGAIN;
- if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->wq_sem))
+ if (cinergyt2->disconnect_pending)
+ goto out;
+ err = mutex_lock_interruptible(&cinergyt2->wq_sem);
+ if (err)
goto out;
- if (mutex_lock_interruptible(&cinergyt2->sem))
+ err = mutex_lock_interruptible(&cinergyt2->sem);
+ if (err)
goto out_unlock1;
- err = 0;
-
if (!cinergyt2->sleeping) {
cinergyt2_sleep(cinergyt2, 0);
cinergyt2_command(cinergyt2, (char *) param, sizeof(*param), NULL, 0);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 5394de2e4ce..f94bc31e3b3 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -24,7 +24,6 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/poll.h>
#include <linux/ioctl.h>
#include <linux/wait.h>
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 4fadddb264d..89437fdab8b 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -32,11 +32,11 @@
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
+#include <linux/kthread.h>
#include "dvb_ca_en50221.h"
#include "dvb_ringbuffer.h"
@@ -140,13 +140,7 @@ struct dvb_ca_private {
wait_queue_head_t wait_queue;
/* PID of the monitoring thread */
- pid_t thread_pid;
-
- /* Wait queue used when shutting thread down */
- wait_queue_head_t thread_queue;
-
- /* Flag indicating when thread should exit */
- unsigned int exit:1;
+ struct task_struct *thread;
/* Flag indicating if the CA device is open */
unsigned int open:1;
@@ -902,28 +896,10 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
ca->wakeup = 1;
mb();
- wake_up_interruptible(&ca->thread_queue);
+ wake_up_process(ca->thread);
}
/**
- * Used by the CA thread to determine if an early wakeup is necessary
- *
- * @param ca CA instance.
- */
-static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private *ca)
-{
- if (ca->wakeup) {
- ca->wakeup = 0;
- return 1;
- }
- if (ca->exit)
- return 1;
-
- return 0;
-}
-
-
-/**
* Update the delay used by the thread.
*
* @param ca CA instance.
@@ -982,7 +958,6 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
static int dvb_ca_en50221_thread(void *data)
{
struct dvb_ca_private *ca = data;
- char name[15];
int slot;
int flags;
int status;
@@ -991,28 +966,17 @@ static int dvb_ca_en50221_thread(void *data)
dprintk("%s\n", __FUNCTION__);
- /* setup kernel thread */
- snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id);
-
- lock_kernel();
- daemonize(name);
- sigfillset(&current->blocked);
- unlock_kernel();
-
/* choose the correct initial delay */
dvb_ca_en50221_thread_update_delay(ca);
/* main loop */
- while (!ca->exit) {
+ while (!kthread_should_stop()) {
/* sleep for a bit */
if (!ca->wakeup) {
- flags = wait_event_interruptible_timeout(ca->thread_queue,
- dvb_ca_en50221_thread_should_wakeup(ca),
- ca->delay);
- if ((flags == -ERESTARTSYS) || ca->exit) {
- /* got signal or quitting */
- break;
- }
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(ca->delay);
+ if (kthread_should_stop())
+ return 0;
}
ca->wakeup = 0;
@@ -1181,10 +1145,6 @@ static int dvb_ca_en50221_thread(void *data)
}
}
- /* completed */
- ca->thread_pid = 0;
- mb();
- wake_up_interruptible(&ca->thread_queue);
return 0;
}
@@ -1536,8 +1496,10 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
return -EIO;
err = dvb_generic_open(inode, file);
- if (err < 0)
+ if (err < 0) {
+ module_put(ca->pub->owner);
return err;
+ }
for (i = 0; i < ca->slot_count; i++) {
@@ -1570,7 +1532,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_ca_private *ca = dvbdev->priv;
- int err = 0;
+ int err;
dprintk("%s\n", __FUNCTION__);
@@ -1582,7 +1544,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
module_put(ca->pub->owner);
- return 0;
+ return err;
}
@@ -1682,9 +1644,6 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
goto error;
}
init_waitqueue_head(&ca->wait_queue);
- ca->thread_pid = 0;
- init_waitqueue_head(&ca->thread_queue);
- ca->exit = 0;
ca->open = 0;
ca->wakeup = 0;
ca->next_read_slot = 0;
@@ -1710,14 +1669,14 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
mb();
/* create a kthread for monitoring this CA device */
-
- ret = kernel_thread(dvb_ca_en50221_thread, ca, 0);
-
- if (ret < 0) {
- printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret);
+ ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i",
+ ca->dvbdev->adapter->num, ca->dvbdev->id);
+ if (IS_ERR(ca->thread)) {
+ ret = PTR_ERR(ca->thread);
+ printk("dvb_ca_init: failed to start kernel_thread (%d)\n",
+ ret);
goto error;
}
- ca->thread_pid = ret;
return 0;
error:
@@ -1748,17 +1707,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
dprintk("%s\n", __FUNCTION__);
/* shutdown the thread if there was one */
- if (ca->thread_pid) {
- if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) {
- printk("dvb_ca_release adapter %d: thread PID %d already died\n",
- ca->dvbdev->adapter->num, ca->thread_pid);
- } else {
- ca->exit = 1;
- mb();
- dvb_ca_en50221_thread_wakeup(ca);
- wait_event_interruptible(ca->thread_queue, ca->thread_pid == 0);
- }
- }
+ kthread_stop(ca->thread);
for (i = 0; i < ca->slot_count; i++) {
dvb_ca_en50221_slot_shutdown(ca, i);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index cb6987fce26..7959020f931 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -373,13 +373,10 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
{
struct dvb_demux_feed *feed;
- struct list_head *pos, *head = &demux->feed_list;
u16 pid = ts_pid(buf);
int dvr_done = 0;
- list_for_each(pos, head) {
- feed = list_entry(pos, struct dvb_demux_feed, list_head);
-
+ list_for_each_entry(feed, &demux->feed_list, list_head) {
if ((feed->pid != pid) && (feed->pid != 0x2000))
continue;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index b6c7f6610ec..445f0266557 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -32,7 +32,6 @@
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/list.h>
#include <linux/freezer.h>
#include <linux/jiffies.h>
@@ -43,7 +42,7 @@
#include "dvbdev.h"
static int dvb_frontend_debug;
-static int dvb_shutdown_timeout = 5;
+static int dvb_shutdown_timeout;
static int dvb_force_auto_inversion;
static int dvb_override_tune_delay;
static int dvb_powerdown_on_sleep = 1;
@@ -138,7 +137,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
dprintk ("%s\n", __FUNCTION__);
- if (down_interruptible (&events->sem))
+ if (mutex_lock_interruptible (&events->mtx))
return;
wp = (events->eventw + 1) % MAX_EVENT;
@@ -159,7 +158,7 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
events->eventw = wp;
- up (&events->sem);
+ mutex_unlock(&events->mtx);
e->status = status;
@@ -197,7 +196,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
return ret;
}
- if (down_interruptible (&events->sem))
+ if (mutex_lock_interruptible (&events->mtx))
return -ERESTARTSYS;
memcpy (event, &events->events[events->eventr],
@@ -205,7 +204,7 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe,
events->eventr = (events->eventr + 1) % MAX_EVENT;
- up (&events->sem);
+ mutex_unlock(&events->mtx);
return 0;
}
@@ -528,7 +527,8 @@ static int dvb_frontend_thread(void *data)
up(&fepriv->sem); /* is locked when we enter the thread... */
restart:
timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
- dvb_frontend_should_wakeup(fe) || kthread_should_stop(),
+ dvb_frontend_should_wakeup(fe) || kthread_should_stop()
+ || freezing(current),
fepriv->delay);
if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
@@ -574,10 +574,9 @@ restart:
dvb_frontend_swzigzag(fe);
}
- if (dvb_shutdown_timeout) {
- if (dvb_powerdown_on_sleep)
- if (fe->ops.set_voltage)
- fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
+ if (dvb_powerdown_on_sleep) {
+ if (fe->ops.set_voltage)
+ fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
if (fe->ops.tuner_ops.sleep) {
fe->ops.tuner_ops.sleep(fe);
if (fe->ops.i2c_gate_ctrl)
@@ -697,6 +696,65 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
return 0;
}
+static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
+ u32 *freq_min, u32 *freq_max)
+{
+ *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
+
+ if (fe->ops.info.frequency_max == 0)
+ *freq_max = fe->ops.tuner_ops.info.frequency_max;
+ else if (fe->ops.tuner_ops.info.frequency_max == 0)
+ *freq_max = fe->ops.info.frequency_max;
+ else
+ *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
+
+ if (*freq_min == 0 || *freq_max == 0)
+ printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n",
+ fe->dvb->num);
+}
+
+static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *parms)
+{
+ u32 freq_min;
+ u32 freq_max;
+
+ /* range check: frequency */
+ dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
+ if ((freq_min && parms->frequency < freq_min) ||
+ (freq_max && parms->frequency > freq_max)) {
+ printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n",
+ fe->dvb->num, parms->frequency, freq_min, freq_max);
+ return -EINVAL;
+ }
+
+ /* range check: symbol rate */
+ if (fe->ops.info.type == FE_QPSK) {
+ if ((fe->ops.info.symbol_rate_min &&
+ parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
+ (fe->ops.info.symbol_rate_max &&
+ parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {
+ printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
+ fe->dvb->num, parms->u.qpsk.symbol_rate,
+ fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
+ return -EINVAL;
+ }
+
+ } else if (fe->ops.info.type == FE_QAM) {
+ if ((fe->ops.info.symbol_rate_min &&
+ parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||
+ (fe->ops.info.symbol_rate_max &&
+ parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {
+ printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
+ fe->dvb->num, parms->u.qam.symbol_rate,
+ fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
@@ -707,7 +765,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
dprintk ("%s\n", __FUNCTION__);
- if (!fe || fepriv->exit)
+ if (fepriv->exit)
return -ENODEV;
if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
@@ -722,6 +780,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
case FE_GET_INFO: {
struct dvb_frontend_info* info = parg;
memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
+ dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max);
/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
* do it, it is done for it. */
@@ -883,6 +942,11 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
case FE_SET_FRONTEND: {
struct dvb_frontend_tune_settings fetunesettings;
+ if (dvb_frontend_check_parameters(fe, parg) < 0) {
+ err = -EINVAL;
+ break;
+ }
+
memcpy (&fepriv->parameters, parg,
sizeof (struct dvb_frontend_parameters));
@@ -992,18 +1056,15 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
dprintk ("%s\n", __FUNCTION__);
- if ((ret = dvb_generic_open (inode, file)) < 0)
- return ret;
-
- if (fe->ops.ts_bus_ctrl) {
- if ((ret = fe->ops.ts_bus_ctrl (fe, 1)) < 0) {
- dvb_generic_release (inode, file);
+ if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
+ if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
return ret;
- }
}
- if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+ if ((ret = dvb_generic_open (inode, file)) < 0)
+ goto err1;
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
/* normal tune mode when opened R/W */
fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
fepriv->tone = -1;
@@ -1011,13 +1072,20 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
ret = dvb_frontend_start (fe);
if (ret)
- dvb_generic_release (inode, file);
+ goto err2;
/* empty event queue */
fepriv->events.eventr = fepriv->events.eventw = 0;
}
return ret;
+
+err2:
+ dvb_generic_release(inode, file);
+err1:
+ if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
+ fe->ops.ts_bus_ctrl(fe, 0);
+ return ret;
}
static int dvb_frontend_release(struct inode *inode, struct file *file)
@@ -1032,16 +1100,18 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
if ((file->f_flags & O_ACCMODE) != O_RDONLY)
fepriv->release_jiffies = jiffies;
- if (fe->ops.ts_bus_ctrl)
- fe->ops.ts_bus_ctrl (fe, 0);
-
ret = dvb_generic_release (inode, file);
- if (dvbdev->users==-1 && fepriv->exit==1) {
- fops_put(file->f_op);
- file->f_op = NULL;
- wake_up(&dvbdev->wait_queue);
+ if (dvbdev->users == -1) {
+ if (fepriv->exit == 1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ wake_up(&dvbdev->wait_queue);
+ }
+ if (fe->ops.ts_bus_ctrl)
+ fe->ops.ts_bus_ctrl(fe, 0);
}
+
return ret;
}
@@ -1080,7 +1150,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
init_MUTEX (&fepriv->sem);
init_waitqueue_head (&fepriv->wait_queue);
init_waitqueue_head (&fepriv->events.wait_queue);
- init_MUTEX (&fepriv->events.sem);
+ mutex_init(&fepriv->events.mtx);
fe->dvb = dvb;
fepriv->inversion = INVERSION_OFF;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index a770a87b9a9..a5262e852c8 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -35,6 +35,7 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/delay.h>
+#include <linux/mutex.h>
#include <linux/dvb/frontend.h>
@@ -61,6 +62,13 @@ struct dvb_tuner_info {
u32 bandwidth_step;
};
+struct analog_parameters {
+ unsigned int frequency;
+ unsigned int mode;
+ unsigned int audmode;
+ u64 std;
+};
+
struct dvb_tuner_ops {
struct dvb_tuner_info info;
@@ -71,6 +79,7 @@ struct dvb_tuner_ops {
/** This is for simple PLLs - set all parameters in one go. */
int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+ int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
@@ -79,7 +88,9 @@ struct dvb_tuner_ops {
int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
#define TUNER_STATUS_LOCKED 1
+#define TUNER_STATUS_STEREO 2
int (*get_status)(struct dvb_frontend *fe, u32 *status);
+ int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
/** These are provided seperately from set_params in order to facilitate silicon
* tuners which require sophisticated tuning loops, controlling each parameter seperately. */
@@ -142,7 +153,7 @@ struct dvb_fe_events {
int eventr;
int overflow;
wait_queue_head_t wait_queue;
- struct semaphore sem;
+ struct mutex mtx;
};
struct dvb_frontend {
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index bdd797071cb..a33eb5988c4 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -357,11 +357,6 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
static unsigned char *ule_where = ule_hist, ule_dump = 0;
#endif
- if (dev == NULL) {
- printk( KERN_ERR "NO netdev struct!\n" );
- return;
- }
-
/* For all TS cells in current buffer.
* Appearently, we are called for every single TS cell.
*/
@@ -800,8 +795,8 @@ static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
}
-static void dvb_net_sec(struct net_device *dev, const u8 *pkt, int
-pkt_len)
+static void dvb_net_sec(struct net_device *dev,
+ const u8 *pkt, int pkt_len)
{
u8 *eth;
struct sk_buff *skb;
@@ -1225,10 +1220,17 @@ static struct net_device_stats * dvb_net_get_stats(struct net_device *dev)
return &((struct dvb_net_priv*) dev->priv)->stats;
}
+static const struct header_ops dvb_header_ops = {
+ .create = eth_header,
+ .parse = eth_header_parse,
+ .rebuild = eth_rebuild_header,
+};
+
static void dvb_net_setup(struct net_device *dev)
{
ether_setup(dev);
+ dev->header_ops = &dvb_header_ops;
dev->open = dvb_net_open;
dev->stop = dvb_net_stop;
dev->hard_start_xmit = dvb_net_tx;
@@ -1237,7 +1239,7 @@ static void dvb_net_setup(struct net_device *dev)
dev->set_mac_address = dvb_net_set_mac;
dev->mtu = 4096;
dev->mc_count = 0;
- dev->hard_header_cache = NULL;
+
dev->flags |= IFF_NOARP;
}
@@ -1446,18 +1448,9 @@ static int dvb_net_close(struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data;
struct dvb_net *dvbnet = dvbdev->priv;
- if (!dvbdev)
- return -ENODEV;
-
- if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
- dvbdev->readers++;
- } else {
- dvbdev->writers++;
- }
-
- dvbdev->users++;
+ dvb_generic_release(inode, file);
- if(dvbdev->users == 1 && dvbnet->exit==1) {
+ if(dvbdev->users == 1 && dvbnet->exit == 1) {
fops_put(file->f_op);
file->f_op = NULL;
wake_up(&dvbdev->wait_queue);
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 9ef0c00605e..18738faecbb 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -25,7 +25,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -59,18 +58,13 @@ static struct class *dvb_class;
static struct dvb_device* dvbdev_find_device (int minor)
{
- struct list_head *entry;
+ struct dvb_adapter *adap;
- list_for_each (entry, &dvb_adapter_list) {
- struct list_head *entry0;
- struct dvb_adapter *adap;
- adap = list_entry (entry, struct dvb_adapter, list_head);
- list_for_each (entry0, &adap->device_list) {
- struct dvb_device *dev;
- dev = list_entry (entry0, struct dvb_device, list_head);
+ list_for_each_entry(adap, &dvb_adapter_list, list_head) {
+ struct dvb_device *dev;
+ list_for_each_entry(dev, &adap->device_list, list_head)
if (nums2minor(adap->num, dev->type, dev->id) == minor)
return dev;
- }
}
return NULL;
@@ -109,10 +103,7 @@ static struct file_operations dvb_device_fops =
.open = dvb_device_open,
};
-static struct cdev dvb_device_cdev = {
- .kobj = {.name = "dvb", },
- .owner = THIS_MODULE,
-};
+static struct cdev dvb_device_cdev;
int dvb_generic_open(struct inode *inode, struct file *file)
{
@@ -180,13 +171,10 @@ static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
u32 id = 0;
while (id < DVB_MAX_IDS) {
- struct list_head *entry;
- list_for_each (entry, &adap->device_list) {
- struct dvb_device *dev;
- dev = list_entry (entry, struct dvb_device, list_head);
+ struct dvb_device *dev;
+ list_for_each_entry(dev, &adap->device_list, list_head)
if (dev->type == type && dev->id == id)
goto skip;
- }
return id;
skip:
id++;
@@ -200,7 +188,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
{
struct dvb_device *dvbdev;
struct file_operations *dvbdevfops;
- struct class_device *clsdev;
+ struct device *clsdev;
int id;
mutex_lock(&dvbdev_register_lock);
@@ -242,10 +230,9 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
mutex_unlock(&dvbdev_register_lock);
- clsdev = class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR,
- nums2minor(adap->num, type, id)),
- adap->device, "dvb%d.%s%d", adap->num,
- dnames[type], id);
+ clsdev = device_create(dvb_class, adap->device,
+ MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
+ "dvb%d.%s%d", adap->num, dnames[type], id);
if (IS_ERR(clsdev)) {
printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
__FUNCTION__, adap->num, dnames[type], id, PTR_ERR(clsdev));
@@ -266,8 +253,8 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
if (!dvbdev)
return;
- class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
- dvbdev->type, dvbdev->id)));
+ device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
+ dvbdev->type, dvbdev->id)));
list_del (&dvbdev->list_head);
kfree (dvbdev->fops);
@@ -281,13 +268,10 @@ static int dvbdev_get_free_adapter_num (void)
int num = 0;
while (num < DVB_MAX_ADAPTERS) {
- struct list_head *entry;
- list_for_each (entry, &dvb_adapter_list) {
- struct dvb_adapter *adap;
- adap = list_entry (entry, struct dvb_adapter, list_head);
+ struct dvb_adapter *adap;
+ list_for_each_entry(adap, &dvb_adapter_list, list_head)
if (adap->num == num)
goto skip;
- }
return num;
skip:
num++;
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 40e41f2f5af..d73934dd4c5 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -74,6 +74,8 @@ config DVB_USB_DIB0700
select DVB_DIB7000M
select DVB_DIB3000MC
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_DIB0070
help
Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
USB bridge is also present in devices having the DiB7700 DVB-T-USB
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index cda3adea24f..4a903ea9589 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -30,17 +30,19 @@ extern int dvb_usb_dib0700_debug;
// 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
// 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
// 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " )
+#define REQUEST_SET_RC 0x11
#define REQUEST_GET_VERSION 0x15
struct dib0700_state {
u8 channel_state;
u16 mt2060_if1[2];
-
+ u8 rc_toggle;
u8 is_dib7000pc;
};
extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
+extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
extern struct i2c_algorithm dib0700_i2c_algo;
@@ -50,5 +52,4 @@ extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device
extern int dib0700_device_count;
extern struct dvb_usb_device_properties dib0700_devices[];
extern struct usb_device_id dib0700_usb_id_table[];
-
#endif
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index dddf164f269..3ea294eb96b 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -13,6 +13,10 @@ int dvb_usb_dib0700_debug;
module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
+static int dvb_usb_dib0700_ir_proto = 1;
+module_param(dvb_usb_dib0700_ir_proto, int, 0644);
+MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6).");
+
/* expecting rx buffer: request data[0] data[1] ... data[2] */
static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
{
@@ -32,7 +36,7 @@ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
}
/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */
-static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
+int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
{
u16 index, value;
int status;
@@ -260,14 +264,29 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
return dib0700_ctrl_wr(adap->dev, b, 4);
}
+static int dib0700_rc_setup(struct dvb_usb_device *d)
+{
+ u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
+ int i = dib0700_ctrl_wr(d, rc_setup, 3);
+ if (i<0) {
+ err("ir protocol setup failed");
+ return -1;
+ }
+ return 0;
+}
+
static int dib0700_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
int i;
+ struct dvb_usb_device *dev;
for (i = 0; i < dib0700_device_count; i++)
- if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0)
+ if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, &dev) == 0)
+ {
+ dib0700_rc_setup(dev);
return 0;
+ }
return -ENODEV;
}
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 2208757d901..58452b52002 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -4,7 +4,7 @@
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
- * Copyright (C) 2005-6 DiBcom, SA
+ * Copyright (C) 2005-7 DiBcom, SA
*/
#include "dib0700.h"
@@ -12,13 +12,19 @@
#include "dib7000m.h"
#include "dib7000p.h"
#include "mt2060.h"
+#include "mt2266.h"
+#include "dib0070.h"
static int force_lna_activation;
module_param(force_lna_activation, int, 0644);
MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), "
"if applicable for the device (default: 0=automatic/off).");
-/* Hauppauge Nova-T 500
+struct dib0700_adapter_state {
+ int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *);
+};
+
+/* Hauppauge Nova-T 500 (aka Bristol)
* has a LNA on GPIO0 which is enabled by setting 1 */
static struct mt2060_config bristol_mt2060_config[2] = {
{
@@ -96,6 +102,321 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
}
+/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */
+
+/* MT226x */
+static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = {
+ {
+ BAND_UHF, // band_caps
+
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
+ * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+ (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
+
+ 1130, // inv_gain
+ 21, // time_stabiliz
+
+ 0, // alpha_level
+ 118, // thlock
+
+ 0, // wbd_inv
+ 3530, // wbd_ref
+ 1, // wbd_sel
+ 0, // wbd_alpha
+
+ 65535, // agc1_max
+ 33770, // agc1_min
+ 65535, // agc2_max
+ 23592, // agc2_min
+
+ 0, // agc1_pt1
+ 62, // agc1_pt2
+ 255, // agc1_pt3
+ 64, // agc1_slope1
+ 64, // agc1_slope2
+ 132, // agc2_pt1
+ 192, // agc2_pt2
+ 80, // agc2_slope1
+ 80, // agc2_slope2
+
+ 17, // alpha_mant
+ 27, // alpha_exp
+ 23, // beta_mant
+ 51, // beta_exp
+
+ 1, // perform_agc_softsplit
+ }, {
+ BAND_VHF | BAND_LBAND, // band_caps
+
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
+ * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+ (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
+
+ 2372, // inv_gain
+ 21, // time_stabiliz
+
+ 0, // alpha_level
+ 118, // thlock
+
+ 0, // wbd_inv
+ 3530, // wbd_ref
+ 1, // wbd_sel
+ 0, // wbd_alpha
+
+ 65535, // agc1_max
+ 0, // agc1_min
+ 65535, // agc2_max
+ 23592, // agc2_min
+
+ 0, // agc1_pt1
+ 128, // agc1_pt2
+ 128, // agc1_pt3
+ 128, // agc1_slope1
+ 0, // agc1_slope2
+ 128, // agc2_pt1
+ 253, // agc2_pt2
+ 81, // agc2_slope1
+ 0, // agc2_slope2
+
+ 17, // alpha_mant
+ 27, // alpha_exp
+ 23, // beta_mant
+ 51, // beta_exp
+
+ 1, // perform_agc_softsplit
+ }
+};
+
+static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = {
+ 60000, 30000, // internal, sampling
+ 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
+ 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
+ (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
+ 0, // ifreq
+ 20452225, // timf
+};
+
+static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = {
+ { .output_mpeg2_in_188_bytes = 1,
+ .hostbus_diversity = 1,
+ .tuner_is_baseband = 1,
+
+ .agc_config_count = 2,
+ .agc = stk7700d_7000p_mt2266_agc_config,
+ .bw = &stk7700d_mt2266_pll_config,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+ },
+ { .output_mpeg2_in_188_bytes = 1,
+ .hostbus_diversity = 1,
+ .tuner_is_baseband = 1,
+
+ .agc_config_count = 2,
+ .agc = stk7700d_7000p_mt2266_agc_config,
+ .bw = &stk7700d_mt2266_pll_config,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+ }
+};
+
+static struct mt2266_config stk7700d_mt2266_config[2] = {
+ { .i2c_address = 0x60
+ },
+ { .i2c_address = 0x60
+ }
+};
+
+static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ if (adap->id == 0) {
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+ dib7000p_i2c_enumeration(&adap->dev->i2c_adap,2,18,stk7700d_dib7000p_mt2266_config);
+ }
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
+ &stk7700d_dib7000p_mt2266_config[adap->id]);
+
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct i2c_adapter *tun_i2c;
+ tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+ return dvb_attach(mt2266_attach, adap->fe, tun_i2c,
+ &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;;
+}
+
+#define DEFAULT_RC_INTERVAL 150
+
+static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
+
+static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ u8 key[4];
+ int i;
+ struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct dib0700_state *st = d->priv;
+ *event = 0;
+ *state = REMOTE_NO_KEY_PRESSED;
+ i=dib0700_ctrl_rd(d,rc_request,2,key,4);
+ if (i<=0) {
+ err("RC Query Failed");
+ return -1;
+ }
+ if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0;
+ if (key[3-1]!=st->rc_toggle) {
+ for (i=0;i<d->props.rc_key_map_size; i++) {
+ if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
+ *event = keymap[i].event;
+ *state = REMOTE_KEY_PRESSED;
+ st->rc_toggle=key[3-1];
+ return 0;
+ }
+ }
+ err("Unknown remote controller key : %2X %2X",(int)key[3-2],(int)key[3-3]);
+ }
+ return 0;
+}
+
+static struct dvb_usb_rc_key dib0700_rc_keys[] = {
+ /* Key codes for the tiny Pinnacle remote*/
+ { 0x07, 0x00, KEY_MUTE },
+ { 0x07, 0x01, KEY_MENU }, // Pinnacle logo
+ { 0x07, 0x39, KEY_POWER },
+ { 0x07, 0x03, KEY_VOLUMEUP },
+ { 0x07, 0x09, KEY_VOLUMEDOWN },
+ { 0x07, 0x06, KEY_CHANNELUP },
+ { 0x07, 0x0c, KEY_CHANNELDOWN },
+ { 0x07, 0x0f, KEY_1 },
+ { 0x07, 0x15, KEY_2 },
+ { 0x07, 0x10, KEY_3 },
+ { 0x07, 0x18, KEY_4 },
+ { 0x07, 0x1b, KEY_5 },
+ { 0x07, 0x1e, KEY_6 },
+ { 0x07, 0x11, KEY_7 },
+ { 0x07, 0x21, KEY_8 },
+ { 0x07, 0x12, KEY_9 },
+ { 0x07, 0x27, KEY_0 },
+ { 0x07, 0x24, KEY_SCREEN }, // 'Square' key
+ { 0x07, 0x2a, KEY_TEXT }, // 'T' key
+ { 0x07, 0x2d, KEY_REWIND },
+ { 0x07, 0x30, KEY_PLAY },
+ { 0x07, 0x33, KEY_FASTFORWARD },
+ { 0x07, 0x36, KEY_RECORD },
+ { 0x07, 0x3c, KEY_STOP },
+ { 0x07, 0x3f, KEY_CANCEL }, // '?' key
+ /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
+ { 0xeb, 0x01, KEY_POWER },
+ { 0xeb, 0x02, KEY_1 },
+ { 0xeb, 0x03, KEY_2 },
+ { 0xeb, 0x04, KEY_3 },
+ { 0xeb, 0x05, KEY_4 },
+ { 0xeb, 0x06, KEY_5 },
+ { 0xeb, 0x07, KEY_6 },
+ { 0xeb, 0x08, KEY_7 },
+ { 0xeb, 0x09, KEY_8 },
+ { 0xeb, 0x0a, KEY_9 },
+ { 0xeb, 0x0b, KEY_VIDEO },
+ { 0xeb, 0x0c, KEY_0 },
+ { 0xeb, 0x0d, KEY_REFRESH },
+ { 0xeb, 0x0f, KEY_EPG },
+ { 0xeb, 0x10, KEY_UP },
+ { 0xeb, 0x11, KEY_LEFT },
+ { 0xeb, 0x12, KEY_OK },
+ { 0xeb, 0x13, KEY_RIGHT },
+ { 0xeb, 0x14, KEY_DOWN },
+ { 0xeb, 0x16, KEY_INFO },
+ { 0xeb, 0x17, KEY_RED },
+ { 0xeb, 0x18, KEY_GREEN },
+ { 0xeb, 0x19, KEY_YELLOW },
+ { 0xeb, 0x1a, KEY_BLUE },
+ { 0xeb, 0x1b, KEY_CHANNELUP },
+ { 0xeb, 0x1c, KEY_VOLUMEUP },
+ { 0xeb, 0x1d, KEY_MUTE },
+ { 0xeb, 0x1e, KEY_VOLUMEDOWN },
+ { 0xeb, 0x1f, KEY_CHANNELDOWN },
+ { 0xeb, 0x40, KEY_PAUSE },
+ { 0xeb, 0x41, KEY_HOME },
+ { 0xeb, 0x42, KEY_MENU }, /* DVD Menu */
+ { 0xeb, 0x43, KEY_SUBTITLE },
+ { 0xeb, 0x44, KEY_TEXT }, /* Teletext */
+ { 0xeb, 0x45, KEY_DELETE },
+ { 0xeb, 0x46, KEY_TV },
+ { 0xeb, 0x47, KEY_DVD },
+ { 0xeb, 0x48, KEY_STOP },
+ { 0xeb, 0x49, KEY_VIDEO },
+ { 0xeb, 0x4a, KEY_AUDIO }, /* Music */
+ { 0xeb, 0x4b, KEY_SCREEN }, /* Pic */
+ { 0xeb, 0x4c, KEY_PLAY },
+ { 0xeb, 0x4d, KEY_BACK },
+ { 0xeb, 0x4e, KEY_REWIND },
+ { 0xeb, 0x4f, KEY_FASTFORWARD },
+ { 0xeb, 0x54, KEY_PREVIOUS },
+ { 0xeb, 0x58, KEY_RECORD },
+ { 0xeb, 0x5c, KEY_NEXT },
+
+ /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
+ { 0x1e, 0x00, KEY_0 },
+ { 0x1e, 0x01, KEY_1 },
+ { 0x1e, 0x02, KEY_2 },
+ { 0x1e, 0x03, KEY_3 },
+ { 0x1e, 0x04, KEY_4 },
+ { 0x1e, 0x05, KEY_5 },
+ { 0x1e, 0x06, KEY_6 },
+ { 0x1e, 0x07, KEY_7 },
+ { 0x1e, 0x08, KEY_8 },
+ { 0x1e, 0x09, KEY_9 },
+ { 0x1e, 0x0a, KEY_KPASTERISK },
+ { 0x1e, 0x0b, KEY_RED },
+ { 0x1e, 0x0c, KEY_RADIO },
+ { 0x1e, 0x0d, KEY_MENU },
+ { 0x1e, 0x0e, KEY_GRAVE }, /* # */
+ { 0x1e, 0x0f, KEY_MUTE },
+ { 0x1e, 0x10, KEY_VOLUMEUP },
+ { 0x1e, 0x11, KEY_VOLUMEDOWN },
+ { 0x1e, 0x12, KEY_CHANNEL },
+ { 0x1e, 0x14, KEY_UP },
+ { 0x1e, 0x15, KEY_DOWN },
+ { 0x1e, 0x16, KEY_LEFT },
+ { 0x1e, 0x17, KEY_RIGHT },
+ { 0x1e, 0x18, KEY_VIDEO },
+ { 0x1e, 0x19, KEY_AUDIO },
+ { 0x1e, 0x1a, KEY_MEDIA },
+ { 0x1e, 0x1b, KEY_EPG },
+ { 0x1e, 0x1c, KEY_TV },
+ { 0x1e, 0x1e, KEY_NEXT },
+ { 0x1e, 0x1f, KEY_BACK },
+ { 0x1e, 0x20, KEY_CHANNELUP },
+ { 0x1e, 0x21, KEY_CHANNELDOWN },
+ { 0x1e, 0x24, KEY_LAST }, /* Skip backwards */
+ { 0x1e, 0x25, KEY_OK },
+ { 0x1e, 0x29, KEY_BLUE},
+ { 0x1e, 0x2e, KEY_GREEN },
+ { 0x1e, 0x30, KEY_PAUSE },
+ { 0x1e, 0x32, KEY_REWIND },
+ { 0x1e, 0x34, KEY_FASTFORWARD },
+ { 0x1e, 0x35, KEY_PLAY },
+ { 0x1e, 0x36, KEY_STOP },
+ { 0x1e, 0x37, KEY_RECORD },
+ { 0x1e, 0x38, KEY_YELLOW },
+ { 0x1e, 0x3b, KEY_GOTO },
+ { 0x1e, 0x3d, KEY_POWER },
+};
+
/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
BAND_UHF | BAND_VHF, // band_caps
@@ -194,6 +515,7 @@ static struct dibx000_bandwidth_config stk7700p_pll_config = {
(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
60258167, // ifreq
20452225, // timf
+ 30000000, // xtal
};
static struct dib7000m_config stk7700p_dib7000m_config = {
@@ -213,6 +535,7 @@ static struct dib7000m_config stk7700p_dib7000m_config = {
static struct dib7000p_config stk7700p_dib7000p_config = {
.output_mpeg2_in_188_bytes = 1,
+ .agc_config_count = 1,
.agc = &stk7700p_7000p_mt2060_agc_config,
.bw = &stk7700p_pll_config,
@@ -267,27 +590,245 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
}
+/* DIB7070 generic */
+static struct dibx000_agc_config dib7070_agc_config = {
+ BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+ * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+ (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
+
+ 600, // inv_gain
+ 10, // time_stabiliz
+
+ 0, // alpha_level
+ 118, // thlock
+
+ 0, // wbd_inv
+ 3530, // wbd_ref
+ 1, // wbd_sel
+ 5, // wbd_alpha
+
+ 65535, // agc1_max
+ 0, // agc1_min
+
+ 65535, // agc2_max
+ 0, // agc2_min
+
+ 0, // agc1_pt1
+ 40, // agc1_pt2
+ 183, // agc1_pt3
+ 206, // agc1_slope1
+ 255, // agc1_slope2
+ 72, // agc2_pt1
+ 152, // agc2_pt2
+ 88, // agc2_slope1
+ 90, // agc2_slope2
+
+ 17, // alpha_mant
+ 27, // alpha_exp
+ 23, // beta_mant
+ 51, // beta_exp
+
+ 0, // perform_agc_softsplit
+};
+
+static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+ return dib7000p_set_gpio(fe, 8, 0, !onoff);
+}
+
+static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+ return dib7000p_set_gpio(fe, 9, 0, onoff);
+}
+
+static struct dib0070_config dib7070p_dib0070_config[2] = {
+ {
+ .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+ .reset = dib7070_tuner_reset,
+ .sleep = dib7070_tuner_sleep,
+ .clock_khz = 12000,
+ .clock_pad_drive = 4
+ }, {
+ .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+ .reset = dib7070_tuner_reset,
+ .sleep = dib7070_tuner_sleep,
+ .clock_khz = 12000,
+
+ }
+};
+
+static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ u16 offset;
+ u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+ switch (band) {
+ case BAND_VHF: offset = 950; break;
+ case BAND_UHF:
+ default: offset = 550; break;
+ }
+ deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
+ dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
+ return state->set_param_save(fe, fep);
+}
+
+static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct dib0700_adapter_state *st = adap->priv;
+ struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+
+ if (adap->id == 0) {
+ if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL)
+ return -ENODEV;
+ } else {
+ if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL)
+ return -ENODEV;
+ }
+
+ st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+ adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override;
+ return 0;
+}
+
+static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
+ 60000, 15000, // internal, sampling
+ 1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
+ 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
+ (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
+ (0 << 25) | 0, // ifreq = 0.000000 MHz
+ 20452225, // timf
+ 12000000, // xtal_hz
+};
+
+static struct dib7000p_config dib7070p_dib7000p_config = {
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_config_count = 1,
+ .agc = &dib7070_agc_config,
+ .bw = &dib7070_bw_config_12_mhz,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .hostbus_diversity = 1,
+};
+
+/* STK7070P */
+static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+ dib0700_ctrl_clock(adap->dev, 72, 1);
+
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+ dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &dib7070p_dib7000p_config);
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config);
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
+/* STK7070PD */
+static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
+ {
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_config_count = 1,
+ .agc = &dib7070_agc_config,
+ .bw = &dib7070_bw_config_12_mhz,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .hostbus_diversity = 1,
+ }, {
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_config_count = 1,
+ .agc = &dib7070_agc_config,
+ .bw = &dib7070_bw_config_12_mhz,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .hostbus_diversity = 1,
+ }
+};
+
+static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
+{
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+ dib0700_ctrl_clock(adap->dev, 72, 1);
+
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+ dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, stk7070pd_dib7000p_config);
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]);
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
+{
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]);
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
+/* DVB-USB and USB stuff follows */
struct usb_device_id dib0700_usb_id_table[] = {
- { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) },
+/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) },
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) },
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
- { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
+/* 5 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
{ USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) },
{ USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) },
{ USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
- { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
- { } /* Terminating entry */
+/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) },
+ { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) },
+/* 15 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070P) },
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) },
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
+ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) },
+/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) },
+ { 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
#define DIB0700_DEFAULT_DEVICE_PROPERTIES \
.caps = DVB_USB_IS_AN_I2C_ADAPTER, \
.usb_ctrl = DEVICE_SPECIFIC, \
- .firmware = "dvb-usb-dib0700-01.fw", \
+ .firmware = "dvb-usb-dib0700-1.10.fw", \
.download_firmware = dib0700_download_firmware, \
.no_reconnect = 1, \
.size_of_priv = sizeof(struct dib0700_state), \
@@ -321,7 +862,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .num_device_descs = 6,
+ .num_device_descs = 7,
.devices = {
{ "DiBcom STK7700P reference design",
{ &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
@@ -336,7 +877,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
},
{ "Compro Videomate U500",
- { &dib0700_usb_id_table[6], NULL },
+ { &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] },
{ NULL },
},
{ "Uniwill STK7700P based (Hama and others)",
@@ -346,8 +887,17 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ "Leadtek Winfast DTV Dongle (STK7700P based)",
{ &dib0700_usb_id_table[8], NULL },
{ NULL },
+ },
+ { "AVerMedia AVerTV DVB-T Express",
+ { &dib0700_usb_id_table[20] },
+ { NULL },
}
- }
+ },
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dib0700_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
+ .rc_query = dib0700_rc_query
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 2,
@@ -371,8 +921,112 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL },
{ NULL },
},
+ },
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dib0700_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
+ .rc_query = dib0700_rc_query
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 2,
+ .adapter = {
+ {
+ .frontend_attach = stk7700d_frontend_attach,
+ .tuner_attach = stk7700d_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+ }, {
+ .frontend_attach = stk7700d_frontend_attach,
+ .tuner_attach = stk7700d_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+ }
+ },
+
+ .num_device_descs = 4,
+ .devices = {
+ { "Pinnacle PCTV 2000e",
+ { &dib0700_usb_id_table[11], NULL },
+ { NULL },
+ },
+ { "Terratec Cinergy DT XS Diversity",
+ { &dib0700_usb_id_table[12], NULL },
+ { NULL },
+ },
+ { "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity",
+ { &dib0700_usb_id_table[13], NULL },
+ { NULL },
+ },
+ { "DiBcom STK7700D reference design",
+ { &dib0700_usb_id_table[14], NULL },
+ { NULL },
+ },
+ },
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dib0700_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
+ .rc_query = dib0700_rc_query
+
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .frontend_attach = stk7070p_frontend_attach,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ },
+ },
+
+ .num_device_descs = 2,
+ .devices = {
+ { "DiBcom STK7070P reference design",
+ { &dib0700_usb_id_table[15], NULL },
+ { NULL },
+ },
+ { "Pinnacle PCTV DVB-T Flash Stick",
+ { &dib0700_usb_id_table[16], NULL },
+ { NULL },
+ },
}
- }
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 2,
+ .adapter = {
+ {
+ .frontend_attach = stk7070pd_frontend_attach0,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ }, {
+ .frontend_attach = stk7070pd_frontend_attach1,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ }
+ },
+
+ .num_device_descs = 2,
+ .devices = {
+ { "DiBcom STK7070PD reference design",
+ { &dib0700_usb_id_table[17], NULL },
+ { NULL },
+ },
+ { "Pinnacle PCTV Dual DVB-T Diversity Stick",
+ { &dib0700_usb_id_table[18], NULL },
+ { NULL },
+ },
+ }
+ },
};
int dib0700_device_count = ARRAY_SIZE(dib0700_devices);
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index 7dbe1432101..d86cf9bee91 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -1,5 +1,5 @@
/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
- * Typhoon/ Yuan DVB-T USB2.0 receiver.
+ * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver.
*
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
@@ -96,6 +96,7 @@ static struct dvb_usb_device_properties dtt200u_properties;
static struct dvb_usb_device_properties wt220u_fc_properties;
static struct dvb_usb_device_properties wt220u_properties;
static struct dvb_usb_device_properties wt220u_zl0353_properties;
+static struct dvb_usb_device_properties wt220u_miglia_properties;
static int dtt200u_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -103,7 +104,8 @@ static int dtt200u_usb_probe(struct usb_interface *intf,
if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 ||
dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 ||
dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 ||
- dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0)
+ dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0 ||
+ dvb_usb_device_init(intf,&wt220u_miglia_properties,THIS_MODULE,NULL) == 0)
return 0;
return -ENODEV;
@@ -119,6 +121,7 @@ static struct usb_device_id dtt200u_usb_table [] = {
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) },
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) },
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) },
+ { USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD) },
{ 0 },
};
MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
@@ -303,6 +306,25 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
}
};
+static struct dvb_usb_device_properties wt220u_miglia_properties = {
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-wt220u-miglia-01.fw",
+
+ .num_adapters = 1,
+ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .num_device_descs = 1,
+ .devices = {
+ { .name = "WideView WT-220U PenType Receiver (Miglia)",
+ .cold_ids = { &dtt200u_usb_table[9], NULL },
+ /* This device turns into WT220U_ZL0353_WARM when fw
+ has been uploaded */
+ .warm_ids = { NULL },
+ },
+ { NULL },
+ }
+};
+
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver dtt200u_usb_driver = {
.name = "dvb_usb_dtt200u",
@@ -333,6 +355,6 @@ module_init(dtt200u_usb_module_init);
module_exit(dtt200u_usb_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D DVB-T USB2.0 devices");
+MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 4dfab02a8a0..4fa3e895028 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -12,7 +12,7 @@
/* Vendor IDs */
#define USB_VID_ADSTECH 0x06e1
#define USB_VID_AFATECH 0x15a4
-#define USB_VID_ALCOR_MICRO 0x058f
+#define USB_VID_ALCOR_MICRO 0x058f
#define USB_VID_ALINK 0x05e3
#define USB_VID_ANCHOR 0x0547
#define USB_VID_ANUBIS_ELECTRONIC 0x10fd
@@ -34,6 +34,7 @@
#define USB_VID_LEADTEK 0x0413
#define USB_VID_LITEON 0x04ca
#define USB_VID_MEDION 0x1660
+#define USB_VID_MIGLIA 0x18f3
#define USB_VID_MSI 0x0db0
#define USB_VID_OPERA1 0x695c
#define USB_VID_PINNACLE 0x2304
@@ -58,6 +59,7 @@
#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c
#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
#define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78
+#define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80
#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064
#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
@@ -66,6 +68,9 @@
#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7
#define USB_PID_DIBCOM_STK7700P 0x1e14
#define USB_PID_DIBCOM_STK7700P_PC 0x1e78
+#define USB_PID_DIBCOM_STK7700D 0x1ef0
+#define USB_PID_DIBCOM_STK7070P 0x1ebc
+#define USB_PID_DIBCOM_STK7070PD 0x1ebe
#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
#define USB_PID_DPOSH_M9206_COLD 0x9206
#define USB_PID_DPOSH_M9206_WARM 0xa090
@@ -115,8 +120,17 @@
#define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950
#define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050
#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060
+#define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580
+#define USB_PID_AVERMEDIA_EXPRESS 0xb568
#define USB_PID_AVERMEDIA_VOLAR 0xa807
#define USB_PID_AVERMEDIA_VOLAR_2 0xb808
+#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
+#define USB_PID_PINNACLE_PCTV2000E 0x022c
+#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228
+#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229
+#define USB_PID_PCTV_200E 0x020e
+#define USB_PID_PCTV_400E 0x020f
+#define USB_PID_PCTV_450E 0x0222
#define USB_PID_NEBULA_DIGITV 0x0201
#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820
#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500
@@ -136,9 +150,6 @@
#define USB_PID_MSI_MEGASKY580_55801 0x5581
#define USB_PID_KYE_DVB_T_COLD 0x701e
#define USB_PID_KYE_DVB_T_WARM 0x701f
-#define USB_PID_PCTV_200E 0x020e
-#define USB_PID_PCTV_400E 0x020f
-#define USB_PID_PCTV_450E 0x0222
#define USB_PID_LITEON_DVB_T_COLD 0xf000
#define USB_PID_LITEON_DVB_T_WARM 0xf001
#define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360
@@ -148,8 +159,11 @@
#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025
#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00
-#define USB_PID_GENPIX_8PSK_COLD 0x0200
-#define USB_PID_GENPIX_8PSK_WARM 0x0201
+#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200
+#define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201
+#define USB_PID_GENPIX_8PSK_REV_2 0x0202
+#define USB_PID_GENPIX_SKYWALKER_1 0x0203
+#define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204
#define USB_PID_SIGMATEK_DVB_110 0x6610
#define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513
#define USB_PID_OPERA1_COLD 0x2830
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index ffdde83d1e7..cdd717c3fe4 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -24,7 +24,7 @@ MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0
static int dvb_usb_force_pid_filter_usage;
module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
-MODULE_PARM_DESC(disable_rc_polling, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
+MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
static int dvb_usb_adapter_init(struct dvb_usb_device *d)
{
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 7b9f35bfb4f..c0c2c22ddd8 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -106,7 +106,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
if (!input_dev)
return -ENOMEM;
- input_dev->evbit[0] = BIT(EV_KEY);
+ 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);
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
index 6ccbdc9cd77..e37142d9271 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -1,7 +1,8 @@
/* DVB USB compliant Linux driver for the
- * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
*
- * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
*
* Thanks to GENPIX for the sample code used to implement this module.
*
@@ -17,27 +18,39 @@
struct gp8psk_fe_state {
struct dvb_frontend fe;
-
struct dvb_usb_device *d;
-
+ u8 lock;
u16 snr;
-
- unsigned long next_snr_check;
+ unsigned long next_status_check;
+ unsigned long status_check_interval;
};
+static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
+{
+ u8 buf[6];
+ if (time_after(jiffies,st->next_status_check)) {
+ gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1);
+ gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6);
+ st->snr = (buf[1]) << 8 | buf[0];
+ st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
+ }
+ return 0;
+}
+
static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
{
struct gp8psk_fe_state *st = fe->demodulator_priv;
- u8 lock;
+ gp8psk_fe_update_status(st);
- if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1))
- return -EINVAL;
-
- if (lock)
+ if (st->lock)
*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
else
*status = 0;
+ if (*status & FE_HAS_LOCK)
+ st->status_check_interval = 1000;
+ else
+ st->status_check_interval = 100;
return 0;
}
@@ -60,33 +73,29 @@ static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
{
struct gp8psk_fe_state *st = fe->demodulator_priv;
- u8 buf[2];
-
- if (time_after(jiffies,st->next_snr_check)) {
- gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2);
- *snr = (int)(buf[1]) << 8 | buf[0];
- /* snr is reported in dBu*256 */
- /* snr / 38.4 ~= 100% strength */
- /* snr * 17 returns 100% strength as 65535 */
- if (*snr <= 3855)
- *snr = (*snr<<4) + *snr; // snr * 17
- else
- *snr = 65535;
- st->next_snr_check = jiffies + (10*HZ)/1000;
- } else {
- *snr = st->snr;
- }
+ gp8psk_fe_update_status(st);
+ /* snr is reported in dBu*256 */
+ *snr = st->snr;
return 0;
}
static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
{
- return gp8psk_fe_read_snr(fe, strength);
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+ gp8psk_fe_update_status(st);
+ /* snr is reported in dBu*256 */
+ /* snr / 38.4 ~= 100% strength */
+ /* snr * 17 returns 100% strength as 65535 */
+ if (st->snr > 0xf00)
+ *strength = 0xffff;
+ else
+ *strength = (st->snr << 4) + st->snr; /* snr*17 */
+ return 0;
}
static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{
- tune->min_delay_ms = 800;
+ tune->min_delay_ms = 200;
return 0;
}
@@ -124,7 +133,9 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
- state->next_snr_check = jiffies;
+ state->lock = 0;
+ state->next_status_check = jiffies;
+ state->status_check_interval = 200;
return 0;
}
@@ -190,6 +201,12 @@ static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t volt
return 0;
}
+static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff)
+{
+ struct gp8psk_fe_state* state = fe->demodulator_priv;
+ return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0);
+}
+
static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
{
struct gp8psk_fe_state* state = fe->demodulator_priv;
@@ -235,10 +252,10 @@ success:
static struct dvb_frontend_ops gp8psk_fe_ops = {
.info = {
- .name = "Genpix 8psk-USB DVB-S",
+ .name = "Genpix 8psk-to-USB2 DVB-S",
.type = FE_QPSK,
- .frequency_min = 950000,
- .frequency_max = 2150000,
+ .frequency_min = 800000,
+ .frequency_max = 2250000,
.frequency_stepsize = 100,
.symbol_rate_min = 1000000,
.symbol_rate_max = 45000000,
@@ -269,4 +286,5 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
.set_tone = gp8psk_fe_set_tone,
.set_voltage = gp8psk_fe_set_voltage,
.dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
+ .enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage
};
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
index 518d67fca5e..92147ee3e14 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -1,7 +1,8 @@
/* DVB USB compliant Linux driver for the
- * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
*
- * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
*
* Thanks to GENPIX for the sample code used to implement this module.
*
@@ -40,7 +41,7 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
}
if (ret < 0 || ret != blen) {
- warn("usb in operation failed.");
+ warn("usb in %d operation failed.", req);
ret = -EIO;
} else
ret = 0;
@@ -97,10 +98,10 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
goto out_rel_fw;
- info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware);
+ info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware);
ptr = fw->data;
- buf = kmalloc(512, GFP_KERNEL | GFP_DMA);
+ buf = kmalloc(64, GFP_KERNEL | GFP_DMA);
while (ptr[0] != 0xff) {
u16 buflen = ptr[0] + 4;
@@ -129,25 +130,34 @@ out_rel_fw:
static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
{
u8 status, buf;
+ int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
+
if (onoff) {
gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
- if (! (status & 0x01)) /* started */
+ if (! (status & bm8pskStarted)) { /* started */
+ if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
+ gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0);
if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
return -EINVAL;
+ }
- if (! (status & 0x02)) /* BCM4500 firmware loaded */
- if(gp8psk_load_bcm4500fw(d))
- return EINVAL;
+ if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+ if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */
+ if(gp8psk_load_bcm4500fw(d))
+ return EINVAL;
- if (! (status & 0x04)) /* LNB Power */
+ if (! (status & bmIntersilOn)) /* LNB Power */
if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
&buf, 1))
return EINVAL;
- /* Set DVB mode */
- if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
- return -EINVAL;
- gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+ /* Set DVB mode to 1 */
+ if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+ if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
+ return EINVAL;
+ /* Abort possible TS (if previous tune crashed) */
+ if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0))
+ return EINVAL;
} else {
/* Turn off LNB power */
if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
@@ -155,11 +165,28 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
/* Turn off 8psk power */
if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
return -EINVAL;
-
+ if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
+ gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0);
}
return 0;
}
+int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
+{
+ u8 buf;
+ int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
+ /* Turn off 8psk power */
+ if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+ return -EINVAL;
+ /* Turn On 8psk power */
+ if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
+ return -EINVAL;
+ /* load BCM4500 firmware */
+ if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+ if (gp8psk_load_bcm4500fw(d))
+ return EINVAL;
+ return 0;
+}
static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
@@ -177,12 +204,22 @@ static struct dvb_usb_device_properties gp8psk_properties;
static int gp8psk_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+ int ret;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ ret = dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+ if (ret == 0) {
+ info("found Genpix USB device pID = %x (hex)",
+ le16_to_cpu(udev->descriptor.idProduct));
+ }
+ return ret;
}
static struct usb_device_id gp8psk_usb_table [] = {
- { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) },
- { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) },
{ 0 },
};
MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
@@ -213,12 +250,24 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .num_device_descs = 1,
+ .num_device_descs = 4,
.devices = {
- { .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver",
+ { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
.cold_ids = { &gp8psk_usb_table[0], NULL },
.warm_ids = { &gp8psk_usb_table[1], NULL },
},
+ { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver",
+ .cold_ids = { NULL },
+ .warm_ids = { &gp8psk_usb_table[2], NULL },
+ },
+ { .name = "Genpix SkyWalker-1 DVB-S receiver",
+ .cold_ids = { NULL },
+ .warm_ids = { &gp8psk_usb_table[3], NULL },
+ },
+ { .name = "Genpix SkyWalker-CW3K DVB-S receiver",
+ .cold_ids = { NULL },
+ .warm_ids = { &gp8psk_usb_table[4], NULL },
+ },
{ NULL },
}
};
@@ -253,6 +302,6 @@ module_init(gp8psk_usb_module_init);
module_exit(gp8psk_usb_module_exit);
MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
-MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0");
-MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("Driver for Genpix 8psk-to-USB2 DVB-S");
+MODULE_VERSION("1.1");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h
index 3eba7061011..e83a57506cf 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.h
+++ b/drivers/media/dvb/dvb-usb/gp8psk.h
@@ -1,7 +1,8 @@
/* DVB USB compliant Linux driver for the
- * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
*
* Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
*
* Thanks to GENPIX for the sample code used to implement this module.
*
@@ -30,21 +31,37 @@ extern int dvb_usb_gp8psk_debug;
#define TH_COMMAND_IN 0xC0
#define TH_COMMAND_OUT 0xC1
-/* command bytes */
-#define GET_8PSK_CONFIG 0x80
+/* gp8psk commands */
+
+#define GET_8PSK_CONFIG 0x80 /* in */
#define SET_8PSK_CONFIG 0x81
+#define I2C_WRITE 0x83
+#define I2C_READ 0x84
#define ARM_TRANSFER 0x85
#define TUNE_8PSK 0x86
-#define GET_SIGNAL_STRENGTH 0x87
+#define GET_SIGNAL_STRENGTH 0x87 /* in */
#define LOAD_BCM4500 0x88
-#define BOOT_8PSK 0x89
-#define START_INTERSIL 0x8A
+#define BOOT_8PSK 0x89 /* in */
+#define START_INTERSIL 0x8A /* in */
#define SET_LNB_VOLTAGE 0x8B
#define SET_22KHZ_TONE 0x8C
#define SEND_DISEQC_COMMAND 0x8D
#define SET_DVB_MODE 0x8E
#define SET_DN_SWITCH 0x8F
-#define GET_SIGNAL_LOCK 0x90
+#define GET_SIGNAL_LOCK 0x90 /* in */
+#define GET_SERIAL_NUMBER 0x93 /* in */
+#define USE_EXTRA_VOLT 0x94
+#define CW3K_INIT 0x9d
+
+/* PSK_configuration bits */
+#define bm8pskStarted 0x01
+#define bm8pskFW_Loaded 0x02
+#define bmIntersilOn 0x04
+#define bmDVBmode 0x08
+#define bm22kHz 0x10
+#define bmSEL18V 0x20
+#define bmDCtuned 0x40
+#define bmArmed 0x80
/* Satellite modulation modes */
#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */
@@ -75,5 +92,6 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
u16 index, u8 *b, int blen);
+extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
#endif
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 69a46b3607a..5bbd2d5192f 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -159,7 +159,7 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return 0;
}
- for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++)
+ for (i = 0; i < ARRAY_SIZE(vp7045_rc_keys); i++)
if (vp7045_rc_keys[i].data == key) {
*state = REMOTE_KEY_PRESSED;
*event = vp7045_rc_keys[i].event;
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index ff448761dce..59b9ed1f1ae 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -283,6 +283,14 @@ config DVB_LGDT330X
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
+config DVB_S5H1409
+ tristate "Samsung S5H1409 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
comment "Tuners/PLL support"
depends on DVB_CORE
@@ -291,7 +299,7 @@ config DVB_PLL
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
- This module driver a number of tuners based on PLL chips with a
+ This module drives a number of tuners based on PLL chips with a
common I2C interface. Say Y when you want to support these tuners.
config DVB_TDA826X
@@ -322,6 +330,29 @@ config DVB_TUNER_MT2060
help
A driver for the silicon IF tuner MT2060 from Microtune.
+config DVB_TUNER_MT2266
+ tristate "Microtune MT2266 silicon tuner"
+ depends on I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon baseband tuner MT2266 from Microtune.
+
+config DVB_TUNER_MT2131
+ tristate "Microtune MT2131 silicon tuner"
+ depends on I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon baseband tuner MT2131 from Microtune.
+
+config DVB_TUNER_DIB0070
+ tristate "DiBcom DiB0070 silicon base-band tuner"
+ depends on I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon baseband tuner DiB0070 from DiBcom.
+ This device is only used inside a SiP called togther with a
+ demodulator for now.
+
comment "Miscellaneous devices"
depends on DVB_CORE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 156b062e02c..4b8ad1f132a 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -40,5 +40,9 @@ obj-$(CONFIG_DVB_TDA10086) += tda10086.o
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
obj-$(CONFIG_DVB_TDA827X) += tda827x.o
obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
+obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o
+obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
+obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
+obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
index baeb311de89..a913f49c062 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -33,7 +33,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/jiffies.h>
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c
index 13ad1bfae66..11a4968f18c 100644
--- a/drivers/media/dvb/frontends/cx22700.c
+++ b/drivers/media/dvb/frontends/cx22700.c
@@ -23,7 +23,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
#include "dvb_frontend.h"
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index 10fc0c8316d..b03d8283c37 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -25,7 +25,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include "dvb_frontend.h"
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 0834c0677fe..d74fdbd6336 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -23,7 +23,6 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include "dvb_frontend.h"
diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c
new file mode 100644
index 00000000000..481eaa68415
--- /dev/null
+++ b/drivers/media/dvb/frontends/dib0070.c
@@ -0,0 +1,580 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "dib0070.h"
+#include "dibx000_common.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB0070: "); printk(args); printk("\n"); } } while (0)
+
+#define DIB0070_P1D 0x00
+#define DIB0070_P1F 0x01
+#define DIB0070_P1G 0x03
+#define DIB0070S_P1A 0x02
+
+struct dib0070_state {
+ struct i2c_adapter *i2c;
+ struct dvb_frontend *fe;
+ const struct dib0070_config *cfg;
+ u16 wbd_ff_offset;
+ u8 revision;
+};
+
+static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
+{
+ u8 b[2];
+ struct i2c_msg msg[2] = {
+ { .addr = state->cfg->i2c_address, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 },
+ };
+ if (i2c_transfer(state->i2c, msg, 2) != 2) {
+ printk(KERN_WARNING "DiB0070 I2C read failed\n");
+ return 0;
+ }
+ return (b[0] << 8) | b[1];
+}
+
+static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
+{
+ u8 b[3] = { reg, val >> 8, val & 0xff };
+ struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 };
+ if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "DiB0070 I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+#define HARD_RESET(state) do { if (state->cfg->reset) { state->cfg->reset(state->fe,1); msleep(10); state->cfg->reset(state->fe,0); msleep(10); } } while (0)
+
+static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ u16 tmp = 0;
+ tmp = dib0070_read_reg(st, 0x02) & 0x3fff;
+
+ switch(BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)) {
+ case 8000:
+ tmp |= (0 << 14);
+ break;
+ case 7000:
+ tmp |= (1 << 14);
+ break;
+ case 6000:
+ tmp |= (2 << 14);
+ break;
+ case 5000:
+ default:
+ tmp |= (3 << 14);
+ break;
+ }
+ dib0070_write_reg(st, 0x02, tmp);
+ return 0;
+}
+
+static void dib0070_captrim(struct dib0070_state *st, u16 LO4)
+{
+ int8_t captrim, fcaptrim, step_sign, step;
+ u16 adc, adc_diff = 3000;
+
+
+
+ dib0070_write_reg(st, 0x0f, 0xed10);
+ dib0070_write_reg(st, 0x17, 0x0034);
+
+ dib0070_write_reg(st, 0x18, 0x0032);
+ msleep(2);
+
+ step = captrim = fcaptrim = 64;
+
+ do {
+ step /= 2;
+ dib0070_write_reg(st, 0x14, LO4 | captrim);
+ msleep(1);
+ adc = dib0070_read_reg(st, 0x19);
+
+ dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", captrim, adc, (u32) adc*(u32)1800/(u32)1024);
+
+ if (adc >= 400) {
+ adc -= 400;
+ step_sign = -1;
+ } else {
+ adc = 400 - adc;
+ step_sign = 1;
+ }
+
+ if (adc < adc_diff) {
+ dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", captrim, adc, adc_diff);
+ adc_diff = adc;
+ fcaptrim = captrim;
+
+
+
+ }
+ captrim += (step_sign * step);
+ } while (step >= 1);
+
+ dib0070_write_reg(st, 0x14, LO4 | fcaptrim);
+ dib0070_write_reg(st, 0x18, 0x07ff);
+}
+
+#define LPF 100 // define for the loop filter 100kHz by default 16-07-06
+#define LO4_SET_VCO_HFDIV(l, v, h) l |= ((v) << 11) | ((h) << 7)
+#define LO4_SET_SD(l, s) l |= ((s) << 14) | ((s) << 12)
+#define LO4_SET_CTRIM(l, c) l |= (c) << 10
+static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ u32 freq = ch->frequency/1000 + (BAND_OF_FREQUENCY(ch->frequency/1000) == BAND_VHF ? st->cfg->freq_offset_khz_vhf : st->cfg->freq_offset_khz_uhf);
+
+ u8 band = BAND_OF_FREQUENCY(freq), c;
+
+ /*******************VCO***********************************/
+ u16 lo4 = 0;
+
+ u8 REFDIV, PRESC = 2;
+ u32 FBDiv, Rest, FREF, VCOF_kHz;
+ u16 Num, Den;
+ /*******************FrontEnd******************************/
+ u16 value = 0;
+
+ dprintk( "Tuning for Band: %hd (%d kHz)", band, freq);
+
+
+ dib0070_write_reg(st, 0x17, 0x30);
+
+ dib0070_set_bandwidth(fe, ch); /* c is used as HF */
+ switch (st->revision) {
+ case DIB0070S_P1A:
+ switch (band) {
+ case BAND_LBAND:
+ LO4_SET_VCO_HFDIV(lo4, 1, 1);
+ c = 2;
+ break;
+ case BAND_SBAND:
+ LO4_SET_VCO_HFDIV(lo4, 0, 0);
+ LO4_SET_CTRIM(lo4, 1);;
+ c = 1;
+ break;
+ case BAND_UHF:
+ default:
+ if (freq < 570000) {
+ LO4_SET_VCO_HFDIV(lo4, 1, 3);
+ PRESC = 6; c = 6;
+ } else if (freq < 680000) {
+ LO4_SET_VCO_HFDIV(lo4, 0, 2);
+ c = 4;
+ } else {
+ LO4_SET_VCO_HFDIV(lo4, 1, 2);
+ c = 4;
+ }
+ break;
+ } break;
+
+ case DIB0070_P1G:
+ case DIB0070_P1F:
+ default:
+ switch (band) {
+ case BAND_FM:
+ LO4_SET_VCO_HFDIV(lo4, 0, 7);
+ c = 24;
+ break;
+ case BAND_LBAND:
+ LO4_SET_VCO_HFDIV(lo4, 1, 0);
+ c = 2;
+ break;
+ case BAND_VHF:
+ if (freq < 180000) {
+ LO4_SET_VCO_HFDIV(lo4, 0, 3);
+ c = 16;
+ } else if (freq < 190000) {
+ LO4_SET_VCO_HFDIV(lo4, 1, 3);
+ c = 16;
+ } else {
+ LO4_SET_VCO_HFDIV(lo4, 0, 6);
+ c = 12;
+ }
+ break;
+
+ case BAND_UHF:
+ default:
+ if (freq < 570000) {
+ LO4_SET_VCO_HFDIV(lo4, 1, 5);
+ c = 6;
+ } else if (freq < 700000) {
+ LO4_SET_VCO_HFDIV(lo4, 0, 1);
+ c = 4;
+ } else {
+ LO4_SET_VCO_HFDIV(lo4, 1, 1);
+ c = 4;
+ }
+ break;
+ }
+ break;
+ }
+
+ dprintk( "HFDIV code: %hd", (lo4 >> 7) & 0xf);
+ dprintk( "VCO = %hd", (lo4 >> 11) & 0x3);
+
+
+ VCOF_kHz = (c * freq) * 2;
+ dprintk( "VCOF in kHz: %d ((%hd*%d) << 1))",VCOF_kHz, c, freq);
+
+ switch (band) {
+ case BAND_VHF:
+ REFDIV = (u8) ((st->cfg->clock_khz + 9999) / 10000);
+ break;
+ case BAND_FM:
+ REFDIV = (u8) ((st->cfg->clock_khz) / 1000);
+ break;
+ default:
+ REFDIV = (u8) ( st->cfg->clock_khz / 10000);
+ break;
+ }
+ FREF = st->cfg->clock_khz / REFDIV;
+
+ dprintk( "REFDIV: %hd, FREF: %d", REFDIV, FREF);
+
+
+
+ switch (st->revision) {
+ case DIB0070S_P1A:
+ FBDiv = (VCOF_kHz / PRESC / FREF);
+ Rest = (VCOF_kHz / PRESC) - FBDiv * FREF;
+ break;
+
+ case DIB0070_P1G:
+ case DIB0070_P1F:
+ default:
+ FBDiv = (freq / (FREF / 2));
+ Rest = 2 * freq - FBDiv * FREF;
+ break;
+ }
+
+
+ if (Rest < LPF) Rest = 0;
+ else if (Rest < 2 * LPF) Rest = 2 * LPF;
+ else if (Rest > (FREF - LPF)) { Rest = 0 ; FBDiv += 1; }
+ else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF;
+ Rest = (Rest * 6528) / (FREF / 10);
+ dprintk( "FBDIV: %d, Rest: %d", FBDiv, Rest);
+
+ Num = 0;
+ Den = 1;
+
+ if (Rest > 0) {
+ LO4_SET_SD(lo4, 1);
+ Den = 255;
+ Num = (u16)Rest;
+ }
+ dprintk( "Num: %hd, Den: %hd, SD: %hd",Num, Den, (lo4 >> 12) & 0x1);
+
+
+
+ dib0070_write_reg(st, 0x11, (u16)FBDiv);
+
+
+ dib0070_write_reg(st, 0x12, (Den << 8) | REFDIV);
+
+
+ dib0070_write_reg(st, 0x13, Num);
+
+
+ value = 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001;
+
+ switch (band) {
+ case BAND_UHF: value |= 0x4000 | 0x0800; break;
+ case BAND_LBAND: value |= 0x2000 | 0x0400; break;
+ default: value |= 0x8000 | 0x1000; break;
+ }
+ dib0070_write_reg(st, 0x20, value);
+
+ dib0070_captrim(st, lo4);
+ if (st->revision == DIB0070S_P1A) {
+ if (band == BAND_SBAND)
+ dib0070_write_reg(st, 0x15, 0x16e2);
+ else
+ dib0070_write_reg(st, 0x15, 0x56e5);
+ }
+
+
+
+ switch (band) {
+ case BAND_UHF: value = 0x7c82; break;
+ case BAND_LBAND: value = 0x7c84; break;
+ default: value = 0x7c81; break;
+ }
+ dib0070_write_reg(st, 0x0f, value);
+ dib0070_write_reg(st, 0x06, 0x3fff);
+
+ /* Front End */
+ /* c == TUNE, value = SWITCH */
+ c = 0;
+ value = 0;
+ switch (band) {
+ case BAND_FM:
+ c = 0; value = 1;
+ break;
+
+ case BAND_VHF:
+ if (freq <= 180000) c = 0;
+ else if (freq <= 188200) c = 1;
+ else if (freq <= 196400) c = 2;
+ else c = 3;
+ value = 1;
+ break;
+
+ case BAND_LBAND:
+ if (freq <= 1500000) c = 0;
+ else if (freq <= 1600000) c = 1;
+ else c = 3;
+ break;
+
+ case BAND_SBAND:
+ c = 7;
+ dib0070_write_reg(st, 0x1d,0xFFFF);
+ break;
+
+ case BAND_UHF:
+ default:
+ if (st->cfg->flip_chip) {
+ if (freq <= 550000) c = 0;
+ else if (freq <= 590000) c = 1;
+ else if (freq <= 666000) c = 3;
+ else c = 5;
+ } else {
+ if (freq <= 550000) c = 2;
+ else if (freq <= 650000) c = 3;
+ else if (freq <= 750000) c = 5;
+ else if (freq <= 850000) c = 6;
+ else c = 7;
+ }
+ value = 2;
+ break;
+ }
+
+ /* default: LNA_MATCH=7, BIAS=3 */
+ dib0070_write_reg(st, 0x07, (value << 11) | (7 << 8) | (c << 3) | (3 << 0));
+ dib0070_write_reg(st, 0x08, (c << 10) | (3 << 7) | (127));
+ dib0070_write_reg(st, 0x0d, 0x0d80);
+
+
+ dib0070_write_reg(st, 0x18, 0x07ff);
+ dib0070_write_reg(st, 0x17, 0x0033);
+
+ return 0;
+}
+
+static int dib0070_wakeup(struct dvb_frontend *fe)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ if (st->cfg->sleep)
+ st->cfg->sleep(fe, 0);
+ return 0;
+}
+
+static int dib0070_sleep(struct dvb_frontend *fe)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ if (st->cfg->sleep)
+ st->cfg->sleep(fe, 1);
+ return 0;
+}
+
+static u16 dib0070_p1f_defaults[] =
+
+{
+ 7, 0x02,
+ 0x0008,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0000,
+ 0x0002,
+ 0x0100,
+
+ 3, 0x0d,
+ 0x0d80,
+ 0x0001,
+ 0x0000,
+
+ 4, 0x11,
+ 0x0000,
+ 0x0103,
+ 0x0000,
+ 0x0000,
+
+ 3, 0x16,
+ 0x0004 | 0x0040,
+ 0x0030,
+ 0x07ff,
+
+ 6, 0x1b,
+ 0x4112,
+ 0xff00,
+ 0xc07f,
+ 0x0000,
+ 0x0180,
+ 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
+
+ 0,
+};
+
+static void dib0070_wbd_calibration(struct dib0070_state *state)
+{
+ u16 wbd_offs;
+ dib0070_write_reg(state, 0x0f, 0x6d81);
+ dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
+ msleep(9);
+ wbd_offs = dib0070_read_reg(state, 0x19);
+ dib0070_write_reg(state, 0x20, 0);
+ state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2);
+ dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset);
+}
+
+u16 dib0070_wbd_offset(struct dvb_frontend *fe)
+{
+ struct dib0070_state *st = fe->tuner_priv;
+ return st->wbd_ff_offset;
+}
+
+EXPORT_SYMBOL(dib0070_wbd_offset);
+static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
+{
+ struct dib0070_state *state = fe->tuner_priv;
+ u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
+ dprintk( "CTRL_LO5: 0x%x", lo5);
+ return dib0070_write_reg(state, 0x15, lo5);
+}
+
+#define pgm_read_word(w) (*w)
+static int dib0070_reset(struct dib0070_state *state)
+{
+ u16 l, r, *n;
+
+ HARD_RESET(state);
+
+
+#ifndef FORCE_SBAND_TUNER
+ if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
+ state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
+ else
+#endif
+ state->revision = DIB0070S_P1A;
+
+ /* P1F or not */
+ dprintk( "Revision: %x", state->revision);
+
+ if (state->revision == DIB0070_P1D) {
+ dprintk( "Error: this driver is not to be used meant for P1D or earlier");
+ return -EINVAL;
+ }
+
+ n = (u16 *) dib0070_p1f_defaults;
+ l = pgm_read_word(n++);
+ while (l) {
+ r = pgm_read_word(n++);
+ do {
+ dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
+ r++;
+ } while (--l);
+ l = pgm_read_word(n++);
+ }
+
+ if (state->cfg->force_crystal_mode != 0)
+ r = state->cfg->force_crystal_mode;
+ else if (state->cfg->clock_khz >= 24000)
+ r = 1;
+ else
+ r = 2;
+
+ r |= state->cfg->osc_buffer_state << 3;
+
+ dib0070_write_reg(state, 0x10, r);
+ dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 4));
+
+ if (state->cfg->invert_iq) {
+ r = dib0070_read_reg(state, 0x02) & 0xffdf;
+ dib0070_write_reg(state, 0x02, r | (1 << 5));
+ }
+
+
+ if (state->revision == DIB0070S_P1A)
+ dib0070_set_ctrl_lo5(state->fe, 4, 7, 3, 1);
+ else
+ dib0070_set_ctrl_lo5(state->fe, 4, 4, 2, 0);
+
+ dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
+ return 0;
+}
+
+
+static int dib0070_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static struct dvb_tuner_ops dib0070_ops = {
+ .info = {
+ .name = "DiBcom DiB0070",
+ .frequency_min = 45000000,
+ .frequency_max = 860000000,
+ .frequency_step = 1000,
+ },
+ .release = dib0070_release,
+
+ .init = dib0070_wakeup,
+ .sleep = dib0070_sleep,
+ .set_params = dib0070_tune_digital,
+// .get_frequency = dib0070_get_frequency,
+// .get_bandwidth = dib0070_get_bandwidth
+};
+
+struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
+{
+ struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
+ if (state == NULL)
+ return NULL;
+
+ state->cfg = cfg;
+ state->i2c = i2c;
+ state->fe = fe;
+ fe->tuner_priv = state;
+
+ if (dib0070_reset(state) != 0)
+ goto free_mem;
+
+ dib0070_wbd_calibration(state);
+
+ printk(KERN_INFO "DiB0070: successfully identified\n");
+ memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = state;
+ return fe;
+
+free_mem:
+ kfree(state);
+ fe->tuner_priv = NULL;
+ return NULL;
+}
+EXPORT_SYMBOL(dib0070_attach);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h
new file mode 100644
index 00000000000..786e37d3388
--- /dev/null
+++ b/drivers/media/dvb/frontends/dib0070.h
@@ -0,0 +1,44 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+#ifndef DIB0070_H
+#define DIB0070_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+#define DEFAULT_DIB0070_I2C_ADDRESS 0x60
+
+struct dib0070_config {
+ u8 i2c_address;
+
+ /* tuner pins controlled externally */
+ int (*reset) (struct dvb_frontend *, int);
+ int (*sleep) (struct dvb_frontend *, int);
+
+ /* offset in kHz */
+ int freq_offset_khz_uhf;
+ int freq_offset_khz_vhf;
+
+ u8 osc_buffer_state; /* 0= normal, 1= tri-state */
+ u32 clock_khz;
+ u8 clock_pad_drive; /* (Drive + 1) * 2mA */
+
+ u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */
+
+ u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */
+
+ u8 flip_chip;
+};
+
+extern struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg);
+extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open);
+extern u16 dib0070_wbd_offset(struct dvb_frontend *);
+
+#endif
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index b6adea5ffeb..136b9d2164d 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -23,7 +23,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 054d7e6d966..edae0be063f 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -1,7 +1,7 @@
/*
* Driver for DiBcom DiB3000MC/P-demodulator.
*
- * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/)
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
* This code is partially based on the previous dib3000mc.c .
@@ -13,10 +13,6 @@
#include <linux/kernel.h>
#include <linux/i2c.h>
-//#include <linux/init.h>
-//#include <linux/delay.h>
-//#include <linux/string.h>
-//#include <linux/slab.h>
#include "dvb_frontend.h"
@@ -26,7 +22,11 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0)
+static int buggy_sfn_workaround;
+module_param(buggy_sfn_workaround, int, 0644);
+MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0)
struct dib3000mc_state {
struct dvb_frontend demod;
@@ -42,6 +42,8 @@ struct dib3000mc_state {
fe_bandwidth_t current_bandwidth;
u16 dev_id;
+
+ u8 sfn_workaround_active :1;
};
static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
@@ -71,7 +73,6 @@ static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
}
-
static int dib3000mc_identify(struct dib3000mc_state *state)
{
u16 value;
@@ -92,7 +93,7 @@ static int dib3000mc_identify(struct dib3000mc_state *state)
return 0;
}
-static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset)
+static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset)
{
u32 timf;
@@ -103,7 +104,7 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw,
} else
timf = state->timf;
- timf *= (BW_INDEX_TO_KHZ(bw) / 1000);
+ timf *= (bw / 1000);
if (update_offset) {
s16 tim_offs = dib3000mc_read_word(state, 416);
@@ -111,17 +112,17 @@ static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw,
if (tim_offs & 0x2000)
tim_offs -= 0x4000;
- if (nfft == 0)
+ if (nfft == TRANSMISSION_MODE_2K)
tim_offs *= 4;
timf += tim_offs;
- state->timf = timf / (BW_INDEX_TO_KHZ(bw) / 1000);
+ state->timf = timf / (bw / 1000);
}
dprintk("timf: %d\n", timf);
- dib3000mc_write_word(state, 23, timf >> 16);
- dib3000mc_write_word(state, 24, timf & 0xffff);
+ dib3000mc_write_word(state, 23, (u16) (timf >> 16));
+ dib3000mc_write_word(state, 24, (u16) (timf ) & 0xffff);
return 0;
}
@@ -209,31 +210,30 @@ static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode)
return ret;
}
-static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
+static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw)
{
- struct dib3000mc_state *state = demod->demodulator_priv;
u16 bw_cfg[6] = { 0 };
u16 imp_bw_cfg[3] = { 0 };
u16 reg;
/* settings here are for 27.7MHz */
switch (bw) {
- case BANDWIDTH_8_MHZ:
+ case 8000:
bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
break;
- case BANDWIDTH_7_MHZ:
+ case 7000:
bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
break;
- case BANDWIDTH_6_MHZ:
+ case 6000:
bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
break;
- case 255 /* BANDWIDTH_5_MHZ */:
+ case 5000:
bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
break;
@@ -257,7 +257,7 @@ static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
// Timing configuration
- dib3000mc_set_timing(state, 0, bw, 0);
+ dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0);
return 0;
}
@@ -276,7 +276,7 @@ static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode,
for (i = 58; i < 87; i++)
dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
- if (nfft == 1) {
+ if (nfft == TRANSMISSION_MODE_8K) {
dib3000mc_write_word(state, 58, 0x3b);
dib3000mc_write_word(state, 84, 0x00);
dib3000mc_write_word(state, 85, 0x8200);
@@ -376,7 +376,7 @@ static int dib3000mc_init(struct dvb_frontend *demod)
// P_search_maxtrial=1
dib3000mc_write_word(state, 5, 1);
- dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+ dib3000mc_set_bandwidth(state, 8000);
// div_lock_mask
dib3000mc_write_word(state, 4, 0x814);
@@ -397,7 +397,7 @@ static int dib3000mc_init(struct dvb_frontend *demod)
dib3000mc_write_word(state, 180, 0x2FF0);
// Impulse noise configuration
- dib3000mc_set_impulse_noise(state, 0, 1);
+ dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K);
// output mode set-up
dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
@@ -423,13 +423,13 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
{
u16 cfg[4] = { 0 },reg;
switch (qam) {
- case 0:
+ case QPSK:
cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
break;
- case 1:
+ case QAM_16:
cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
break;
- case 2:
+ case QAM_64:
cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
break;
}
@@ -437,11 +437,11 @@ static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
dib3000mc_write_word(state, reg, cfg[reg - 129]);
}
-static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq)
+static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq)
{
- u16 tmp;
-
- dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0);
+ u16 value;
+ dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+ dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0);
// if (boost)
// dib3000mc_write_word(state, 100, (11 << 6) + 6);
@@ -455,7 +455,7 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx
dib3000mc_write_word(state, 26, 0x6680);
dib3000mc_write_word(state, 29, 0x1273);
dib3000mc_write_word(state, 33, 5);
- dib3000mc_set_adp_cfg(state, 1);
+ dib3000mc_set_adp_cfg(state, QAM_16);
dib3000mc_write_word(state, 133, 15564);
dib3000mc_write_word(state, 12 , 0x0);
@@ -470,52 +470,98 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx
dib3000mc_write_word(state, 97,0);
dib3000mc_write_word(state, 98,0);
- dib3000mc_set_impulse_noise(state, 0, chan->nfft);
-
- tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
- dib3000mc_write_word(state, 0, tmp);
+ dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode);
+ value = 0;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+ }
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+ case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+ case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
+ default:
+ case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
+ }
+ switch (ch->u.ofdm.constellation) {
+ case QPSK: value |= (0 << 3); break;
+ case QAM_16: value |= (1 << 3); break;
+ default:
+ case QAM_64: value |= (2 << 3); break;
+ }
+ switch (HIERARCHY_1) {
+ case HIERARCHY_2: value |= 2; break;
+ case HIERARCHY_4: value |= 4; break;
+ default:
+ case HIERARCHY_1: value |= 1; break;
+ }
+ dib3000mc_write_word(state, 0, value);
dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
- tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
- if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
- tmp |= chan->vit_code_rate_hp << 1;
- else
- tmp |= chan->vit_code_rate_lp << 1;
- dib3000mc_write_word(state, 181, tmp);
+ value = 0;
+ if (ch->u.ofdm.hierarchy_information == 1)
+ value |= (1 << 4);
+ if (1 == 1)
+ value |= 1;
+ switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+ case FEC_2_3: value |= (2 << 1); break;
+ case FEC_3_4: value |= (3 << 1); break;
+ case FEC_5_6: value |= (5 << 1); break;
+ case FEC_7_8: value |= (7 << 1); break;
+ default:
+ case FEC_1_2: value |= (1 << 1); break;
+ }
+ dib3000mc_write_word(state, 181, value);
- // diversity synchro delay
- tmp = dib3000mc_read_word(state, 180) & 0x000f;
- tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin
- dib3000mc_write_word(state, 180, tmp);
+ // diversity synchro delay add 50% SFN margin
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_8K: value = 256; break;
+ case TRANSMISSION_MODE_2K:
+ default: value = 64; break;
+ }
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_16: value *= 2; break;
+ case GUARD_INTERVAL_1_8: value *= 4; break;
+ case GUARD_INTERVAL_1_4: value *= 8; break;
+ default:
+ case GUARD_INTERVAL_1_32: value *= 1; break;
+ }
+ value <<= 4;
+ value |= dib3000mc_read_word(state, 180) & 0x000f;
+ dib3000mc_write_word(state, 180, value);
// restart demod
- tmp = dib3000mc_read_word(state, 0);
- dib3000mc_write_word(state, 0, tmp | (1 << 9));
- dib3000mc_write_word(state, 0, tmp);
+ value = dib3000mc_read_word(state, 0);
+ dib3000mc_write_word(state, 0, value | (1 << 9));
+ dib3000mc_write_word(state, 0, value);
msleep(30);
- dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft);
+ dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode);
}
-static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan)
+static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan)
{
struct dib3000mc_state *state = demod->demodulator_priv;
u16 reg;
// u32 val;
- struct dibx000_ofdm_channel fchan;
+ struct dvb_frontend_parameters schan;
- INIT_OFDM_CHANNEL(&fchan);
- fchan = *chan;
+ schan = *chan;
+ /* TODO what is that ? */
/* a channel for autosearch */
- fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2;
- fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2;
- fchan.vit_hrch = 0; fchan.vit_select_hp = 1;
+ schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ schan.u.ofdm.constellation = QAM_64;
+ schan.u.ofdm.code_rate_HP = FEC_2_3;
+ schan.u.ofdm.code_rate_LP = FEC_2_3;
+ schan.u.ofdm.hierarchy_information = 0;
- dib3000mc_set_channel_cfg(state, &fchan, 11);
+ dib3000mc_set_channel_cfg(state, &schan, 11);
reg = dib3000mc_read_word(state, 0);
dib3000mc_write_word(state, 0, reg | (1 << 8));
@@ -539,7 +585,7 @@ static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
return 0; // still pending
}
-static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib3000mc_state *state = demod->demodulator_priv;
@@ -547,11 +593,17 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe
dib3000mc_set_channel_cfg(state, ch, 0);
// activates isi
- dib3000mc_write_word(state, 29, 0x1073);
-
- dib3000mc_set_adp_cfg(state, (u8)ch->nqam);
+ if (state->sfn_workaround_active) {
+ dprintk("SFN workaround is active\n");
+ dib3000mc_write_word(state, 29, 0x1273);
+ dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift
+ } else {
+ dib3000mc_write_word(state, 29, 0x1073);
+ dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift
+ }
- if (ch->nfft == 1) {
+ dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation);
+ if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) {
dib3000mc_write_word(state, 26, 38528);
dib3000mc_write_word(state, 33, 8);
} else {
@@ -560,7 +612,7 @@ static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channe
}
if (dib3000mc_read_word(state, 509) & 0x80)
- dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1);
+ dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1);
return 0;
}
@@ -632,13 +684,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dib3000mc_state *state = fe->demodulator_priv;
- struct dibx000_ofdm_channel ch;
-
- INIT_OFDM_CHANNEL(&ch);
- FEP2DIB(fep,&ch);
state->current_bandwidth = fep->u.ofdm.bandwidth;
- dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+ dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+
+ /* maybe the parameter has been changed */
+ state->sfn_workaround_active = buggy_sfn_workaround;
if (fe->ops.tuner_ops.set_params) {
fe->ops.tuner_ops.set_params(fe, fep);
@@ -651,7 +702,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
fep->u.ofdm.code_rate_HP == FEC_AUTO) {
int i = 100, found;
- dib3000mc_autosearch_start(fe, &ch);
+ dib3000mc_autosearch_start(fe, fep);
do {
msleep(1);
found = dib3000mc_autosearch_is_irq(fe);
@@ -662,13 +713,12 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
return 0; // no channel found
dib3000mc_get_frontend(fe, fep);
- FEP2DIB(fep,&ch);
}
/* make this a config parameter */
dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
- return dib3000mc_tune(fe, &ch);
+ return dib3000mc_tune(fe, fep);
}
static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
index f64546c6aeb..fb18441a8c5 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -2,7 +2,7 @@
* Linux-DVB Driver for DiBcom's DiB7000M and
* first generation DiB7000P-demodulator-family.
*
- * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -19,7 +19,7 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M:"); printk(args); } } while (0)
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0)
struct dib7000m_state {
struct dvb_frontend demod;
@@ -39,8 +39,16 @@ struct dib7000m_state {
fe_bandwidth_t current_bandwidth;
struct dibx000_agc_config *current_agc;
u32 timf;
+ u32 timf_default;
+ u32 internal_clk;
+
+ u8 div_force_off : 1;
+ u8 div_state : 1;
+ u16 div_sync_wait;
u16 revision;
+
+ u8 agc_state;
};
enum dib7000m_power_mode {
@@ -63,7 +71,7 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
};
if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
- dprintk("i2c read error on %d\n",reg);
+ dprintk("i2c read error on %d",reg);
return (rb[0] << 8) | rb[1];
}
@@ -79,6 +87,25 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
};
return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
}
+static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
+{
+ u16 l = 0, r, *n;
+ n = buf;
+ l = *n++;
+ while (l) {
+ r = *n++;
+
+ if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC
+ r++;
+
+ do {
+ dib7000m_write_word(state, r, *n++);
+ r++;
+ } while (--l);
+ l = *n++;
+ }
+}
+
static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
{
int ret = 0;
@@ -89,8 +116,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
fifo_threshold = 1792;
smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1);
- dprintk("-I- Setting output mode for demod %p to %d\n",
- &state->demod, mode);
+ dprintk( "setting output mode for demod %p to %d", &state->demod, mode);
switch (mode) {
case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
@@ -117,7 +143,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
outreg = 0;
break;
default:
- dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+ dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
break;
}
@@ -129,13 +155,20 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
ret |= dib7000m_write_word(state, 1795, outreg);
ret |= dib7000m_write_word(state, 1805, sram);
+ if (state->revision == 0x4003) {
+ u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd;
+ if (mode == OUTMODE_DIVERSITY)
+ clk_cfg1 |= (1 << 1); // P_O_CLK_en
+ dib7000m_write_word(state, 909, clk_cfg1);
+ }
return ret;
}
-static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
+static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
{
/* by default everything is going to be powered off */
u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906 = 0x3fff;
+ u8 offset = 0;
/* now, depending on the requested mode, we power on */
switch (mode) {
@@ -170,16 +203,17 @@ static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_p
if (!state->cfg.mobile_mode)
reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
- /* P_sdio_select_clk = 0 on MC */
+ /* P_sdio_select_clk = 0 on MC and after*/
if (state->revision != 0x4000)
reg_906 <<= 1;
- dib7000m_write_word(state, 903, reg_903);
- dib7000m_write_word(state, 904, reg_904);
- dib7000m_write_word(state, 905, reg_905);
- dib7000m_write_word(state, 906, reg_906);
+ if (state->revision == 0x4003)
+ offset = 1;
- return 0;
+ dib7000m_write_word(state, 903 + offset, reg_903);
+ dib7000m_write_word(state, 904 + offset, reg_904);
+ dib7000m_write_word(state, 905 + offset, reg_905);
+ dib7000m_write_word(state, 906 + offset, reg_906);
}
static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no)
@@ -230,34 +264,55 @@ static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc
break;
}
-// dprintk("-D- 913: %x, 914: %x\n", reg_913, reg_914);
-
+// dprintk( "913: %x, 914: %x", reg_913, reg_914);
ret |= dib7000m_write_word(state, 913, reg_913);
ret |= dib7000m_write_word(state, 914, reg_914);
return ret;
}
-static int dib7000m_set_bandwidth(struct dvb_frontend *demod, u8 bw_idx)
+static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw)
{
- struct dib7000m_state *state = demod->demodulator_priv;
u32 timf;
// store the current bandwidth for later use
- state->current_bandwidth = bw_idx;
+ state->current_bandwidth = bw;
if (state->timf == 0) {
- dprintk("-D- Using default timf\n");
- timf = state->cfg.bw->timf;
+ dprintk( "using default timf");
+ timf = state->timf_default;
} else {
- dprintk("-D- Using updated timf\n");
+ dprintk( "using updated timf");
timf = state->timf;
}
- timf = timf * (BW_INDEX_TO_KHZ(bw_idx) / 100) / 80;
+ timf = timf * (bw / 50) / 160;
- dib7000m_write_word(state, 23, (timf >> 16) & 0xffff);
- dib7000m_write_word(state, 24, (timf ) & 0xffff);
+ dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
+ dib7000m_write_word(state, 24, (u16) ((timf ) & 0xffff));
+
+ return 0;
+}
+
+static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff)
+{
+ struct dib7000m_state *state = demod->demodulator_priv;
+
+ if (state->div_force_off) {
+ dprintk( "diversity combination deactivated - forced by COFDM parameters");
+ onoff = 0;
+ }
+ state->div_state = (u8)onoff;
+
+ if (onoff) {
+ dib7000m_write_word(state, 263 + state->reg_offs, 6);
+ dib7000m_write_word(state, 264 + state->reg_offs, 6);
+ dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
+ } else {
+ dib7000m_write_word(state, 263 + state->reg_offs, 1);
+ dib7000m_write_word(state, 264 + state->reg_offs, 0);
+ dib7000m_write_word(state, 266 + state->reg_offs, 0);
+ }
return 0;
}
@@ -266,7 +321,7 @@ static int dib7000m_sad_calib(struct dib7000m_state *state)
{
/* internal */
-// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
+// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
@@ -281,10 +336,10 @@ static int dib7000m_sad_calib(struct dib7000m_state *state)
static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw)
{
- dib7000m_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff);
- dib7000m_write_word(state, 19, (bw->internal*1000) & 0xffff);
- dib7000m_write_word(state, 21, (bw->ifreq >> 16) & 0xffff);
- dib7000m_write_word(state, 22, bw->ifreq & 0xffff);
+ dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
+ dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000) & 0xffff));
+ dib7000m_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff));
+ dib7000m_write_word(state, 22, (u16) ( bw->ifreq & 0xffff));
dib7000m_write_word(state, 928, bw->sad_cfg);
}
@@ -325,15 +380,19 @@ static void dib7000m_reset_pll(struct dib7000m_state *state)
static void dib7000mc_reset_pll(struct dib7000m_state *state)
{
const struct dibx000_bandwidth_config *bw = state->cfg.bw;
+ u16 clk_cfg1;
// clk_cfg0
dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0));
// clk_cfg1
//dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) |
- dib7000m_write_word(state, 908, (0 << 14) | (3 << 12) |(0 << 11) |
+ clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) |
(bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) |
- (bw->pll_bypass << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0));
+ (1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0);
+ dib7000m_write_word(state, 908, clk_cfg1);
+ clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3);
+ dib7000m_write_word(state, 908, clk_cfg1);
// smpl_cfg
dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7));
@@ -344,9 +403,6 @@ static void dib7000mc_reset_pll(struct dib7000m_state *state)
static int dib7000m_reset_gpio(struct dib7000m_state *st)
{
/* reset the GPIOs */
- dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",
- st->cfg.gpio_dir, st->cfg.gpio_val,st->cfg.gpio_pwm_pos);
-
dib7000m_write_word(st, 773, st->cfg.gpio_dir);
dib7000m_write_word(st, 774, st->cfg.gpio_val);
@@ -358,6 +414,107 @@ static int dib7000m_reset_gpio(struct dib7000m_state *st)
return 0;
}
+static u16 dib7000m_defaults_common[] =
+
+{
+ // auto search configuration
+ 3, 2,
+ 0x0004,
+ 0x1000,
+ 0x0814,
+
+ 12, 6,
+ 0x001b,
+ 0x7740,
+ 0x005b,
+ 0x8d80,
+ 0x01c9,
+ 0xc380,
+ 0x0000,
+ 0x0080,
+ 0x0000,
+ 0x0090,
+ 0x0001,
+ 0xd4c0,
+
+ 1, 26,
+ 0x6680, // P_corm_thres Lock algorithms configuration
+
+ 1, 170,
+ 0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
+
+ 8, 173,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ 1, 182,
+ 8192, // P_fft_nb_to_cut
+
+ 2, 195,
+ 0x0ccd, // P_pha3_thres
+ 0, // P_cti_use_cpe, P_cti_use_prog
+
+ 1, 205,
+ 0x200f, // P_cspu_regul, P_cspu_win_cut
+
+ 5, 214,
+ 0x023d, // P_adp_regul_cnt
+ 0x00a4, // P_adp_noise_cnt
+ 0x00a4, // P_adp_regul_ext
+ 0x7ff0, // P_adp_noise_ext
+ 0x3ccc, // P_adp_fil
+
+ 1, 226,
+ 0, // P_2d_byp_ti_num
+
+ 1, 255,
+ 0x800, // P_equal_thres_wgn
+
+ 1, 263,
+ 0x0001,
+
+ 1, 281,
+ 0x0010, // P_fec_*
+
+ 1, 294,
+ 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+
+ 0
+};
+
+static u16 dib7000m_defaults[] =
+
+{
+ /* set ADC level to -16 */
+ 11, 76,
+ (1 << 13) - 825 - 117,
+ (1 << 13) - 837 - 117,
+ (1 << 13) - 811 - 117,
+ (1 << 13) - 766 - 117,
+ (1 << 13) - 737 - 117,
+ (1 << 13) - 693 - 117,
+ (1 << 13) - 648 - 117,
+ (1 << 13) - 619 - 117,
+ (1 << 13) - 575 - 117,
+ (1 << 13) - 531 - 117,
+ (1 << 13) - 501 - 117,
+
+ // Tuner IO bank: max drive (14mA)
+ 1, 912,
+ 0x2c8a,
+
+ 1, 1817,
+ 1,
+
+ 0,
+};
+
static int dib7000m_demod_reset(struct dib7000m_state *state)
{
dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
@@ -382,22 +539,47 @@ static int dib7000m_demod_reset(struct dib7000m_state *state)
dib7000mc_reset_pll(state);
if (dib7000m_reset_gpio(state) != 0)
- dprintk("-E- GPIO reset was not successful.\n");
+ dprintk( "GPIO reset was not successful.");
if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
- dprintk("-E- OUTPUT_MODE could not be resetted.\n");
+ dprintk( "OUTPUT_MODE could not be reset.");
/* unforce divstr regardless whether i2c enumeration was done or not */
dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) );
- dib7000m_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+ dib7000m_set_bandwidth(state, 8000);
dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON);
dib7000m_sad_calib(state);
dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+ if (state->cfg.dvbt_mode)
+ dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
+
+ if (state->cfg.mobile_mode)
+ dib7000m_write_word(state, 261 + state->reg_offs, 2);
+ else
+ dib7000m_write_word(state, 224 + state->reg_offs, 1);
+
+ // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
+ if(state->cfg.tuner_is_baseband)
+ dib7000m_write_word(state, 36, 0x0755);
+ else
+ dib7000m_write_word(state, 36, 0x1f55);
+
+ // P_divclksel=3 P_divbitsel=1
+ if (state->revision == 0x4000)
+ dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
+ else
+ dib7000m_write_word(state, 909, (3 << 4) | 1);
+
+ dib7000m_write_tab(state, dib7000m_defaults_common);
+ dib7000m_write_tab(state, dib7000m_defaults);
+
dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY);
+ state->internal_clk = state->cfg.bw->internal;
+
return 0;
}
@@ -427,7 +609,7 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state)
(agc - state->current_agc->split.min_thres) /
(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
- dprintk("AGC split_offset: %d\n",split_offset);
+ dprintk( "AGC split_offset: %d",split_offset);
// P_agc_force_split and P_agc_split_offset
return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset);
@@ -435,35 +617,26 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state)
static int dib7000m_update_lna(struct dib7000m_state *state)
{
- int i;
u16 dyn_gain;
- // when there is no LNA to program return immediatly
- if (state->cfg.update_lna == NULL)
- return 0;
-
- msleep(60);
- for (i = 0; i < 20; i++) {
- // read dyn_gain here (because it is demod-dependent and not tuner)
+ if (state->cfg.update_lna) {
+ // read dyn_gain here (because it is demod-dependent and not fe)
dyn_gain = dib7000m_read_word(state, 390);
- dprintk("agc global: %d\n", dyn_gain);
-
if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
dib7000m_restart_agc(state);
- msleep(60);
- } else
- break;
+ return 1;
+ }
}
return 0;
}
-static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
+static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
{
struct dibx000_agc_config *agc = NULL;
int i;
- if (state->current_band == band)
- return;
+ if (state->current_band == band && state->current_agc != NULL)
+ return 0;
state->current_band = band;
for (i = 0; i < state->cfg.agc_config_count; i++)
@@ -473,8 +646,8 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
}
if (agc == NULL) {
- dprintk("-E- No valid AGC configuration found for band 0x%02x\n",band);
- return;
+ dprintk( "no valid AGC configuration found for band 0x%02x",band);
+ return -EINVAL;
}
state->current_agc = agc;
@@ -489,7 +662,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp);
dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp);
- dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
+ dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
/* AGC continued */
@@ -510,7 +683,7 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
if (state->revision > 0x4000) { // settings for the MC
dib7000m_write_word(state, 71, agc->agc1_pt3);
-// dprintk("-D- 929: %x %d %d\n",
+// dprintk( "929: %x %d %d",
// (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel);
dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
} else {
@@ -519,33 +692,160 @@ static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
for (i = 0; i < 9; i++)
dib7000m_write_word(state, 88 + i, b[i]);
}
+ return 0;
}
-static void dib7000m_update_timf_freq(struct dib7000m_state *state)
+static void dib7000m_update_timf(struct dib7000m_state *state)
{
u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437);
- state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100);
+ state->timf = timf * 160 / (state->current_bandwidth / 50);
dib7000m_write_word(state, 23, (u16) (timf >> 16));
dib7000m_write_word(state, 24, (u16) (timf & 0xffff));
- dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf);
+ dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default);
+}
+
+static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+{
+ struct dib7000m_state *state = demod->demodulator_priv;
+ u16 cfg_72 = dib7000m_read_word(state, 72);
+ int ret = -1;
+ u8 *agc_state = &state->agc_state;
+ u8 agc_split;
+
+ switch (state->agc_state) {
+ case 0:
+ // set power-up level: interf+analog+AGC
+ dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
+ dib7000m_set_adc_state(state, DIBX000_ADC_ON);
+
+ if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
+ return -1;
+
+ ret = 7; /* ADC power up */
+ (*agc_state)++;
+ break;
+
+ case 1:
+ /* AGC initialization */
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 1);
+
+ dib7000m_write_word(state, 75, 32768);
+ if (!state->current_agc->perform_agc_softsplit) {
+ /* we are using the wbd - so slow AGC startup */
+ dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */
+ (*agc_state)++;
+ ret = 5;
+ } else {
+ /* default AGC startup */
+ (*agc_state) = 4;
+ /* wait AGC rough lock time */
+ ret = 7;
+ }
+
+ dib7000m_restart_agc(state);
+ break;
+
+ case 2: /* fast split search path after 5sec */
+ dib7000m_write_word(state, 72, cfg_72 | (1 << 4)); /* freeze AGC loop */
+ dib7000m_write_word(state, 103, 2 << 9); /* fast split search 0.25kHz */
+ (*agc_state)++;
+ ret = 14;
+ break;
+
+ case 3: /* split search ended */
+ agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */
+ dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */
+
+ dib7000m_write_word(state, 72, cfg_72 & ~(1 << 4)); /* std AGC loop */
+ dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
+
+ dib7000m_restart_agc(state);
+
+ dprintk( "SPLIT %p: %hd", demod, agc_split);
+
+ (*agc_state)++;
+ ret = 5;
+ break;
+
+ case 4: /* LNA startup */
+ /* wait AGC accurate lock time */
+ ret = 7;
+
+ if (dib7000m_update_lna(state))
+ // wait only AGC rough lock time
+ ret = 5;
+ else
+ (*agc_state)++;
+ break;
+
+ case 5:
+ dib7000m_agc_soft_split(state);
+
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 0);
+
+ (*agc_state)++;
+ break;
+
+ default:
+ break;
+ }
+ return ret;
}
-static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_ofdm_channel *ch, u8 seq)
+static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq)
{
u16 value, est[4];
- dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->RF_kHz));
+ dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
/* nfft, guard, qam, alpha */
- dib7000m_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha));
+ value = 0;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+ case /* 4K MODE */ 255: value |= (2 << 7); break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+ }
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+ case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+ case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
+ default:
+ case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
+ }
+ switch (ch->u.ofdm.constellation) {
+ case QPSK: value |= (0 << 3); break;
+ case QAM_16: value |= (1 << 3); break;
+ default:
+ case QAM_64: value |= (2 << 3); break;
+ }
+ switch (HIERARCHY_1) {
+ case HIERARCHY_2: value |= 2; break;
+ case HIERARCHY_4: value |= 4; break;
+ default:
+ case HIERARCHY_1: value |= 1; break;
+ }
+ dib7000m_write_word(state, 0, value);
dib7000m_write_word(state, 5, (seq << 4));
- /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */
- value = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1);
- if (ch->vit_hrch == 0 || ch->vit_select_hp == 1)
- value |= (ch->vit_code_rate_hp << 1);
- else
- value |= (ch->vit_code_rate_lp << 1);
+ /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
+ value = 0;
+ if (1 != 0)
+ value |= (1 << 6);
+ if (ch->u.ofdm.hierarchy_information == 1)
+ value |= (1 << 4);
+ if (1 == 1)
+ value |= 1;
+ switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+ case FEC_2_3: value |= (2 << 1); break;
+ case FEC_3_4: value |= (3 << 1); break;
+ case FEC_5_6: value |= (5 << 1); break;
+ case FEC_7_8: value |= (7 << 1); break;
+ default:
+ case FEC_1_2: value |= (1 << 1); break;
+ }
dib7000m_write_word(state, 267 + state->reg_offs, value);
/* offset loop parameters */
@@ -563,32 +863,38 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of
dib7000m_write_word(state, 33, (0 << 4) | 0x5);
/* P_dvsy_sync_wait */
- switch (ch->nfft) {
- case 1: value = 256; break;
- case 2: value = 128; break;
- case 0:
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_8K: value = 256; break;
+ case /* 4K MODE */ 255: value = 128; break;
+ case TRANSMISSION_MODE_2K:
default: value = 64; break;
}
- value *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin
- value <<= 4;
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_16: value *= 2; break;
+ case GUARD_INTERVAL_1_8: value *= 4; break;
+ case GUARD_INTERVAL_1_4: value *= 8; break;
+ default:
+ case GUARD_INTERVAL_1_32: value *= 1; break;
+ }
+ state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
/* deactive the possibility of diversity reception if extended interleave - not for 7000MC */
/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
- if (ch->intlv_native || state->revision > 0x4000)
- value |= (1 << 2) | (2 << 0);
+ if (1 == 1 || state->revision > 0x4000)
+ state->div_force_off = 0;
else
- value |= 0;
- dib7000m_write_word(state, 266 + state->reg_offs, value);
+ state->div_force_off = 1;
+ dib7000m_set_diversity_in(&state->demod, state->div_state);
/* channel estimation fine configuration */
- switch (ch->nqam) {
- case 2:
+ switch (ch->u.ofdm.constellation) {
+ case QAM_64:
est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
break;
- case 1:
+ case QAM_16:
est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
@@ -604,70 +910,48 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_of
for (value = 0; value < 4; value++)
dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]);
- // set power-up level: interf+analog+AGC
- dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
- dib7000m_set_adc_state(state, DIBX000_ADC_ON);
-
- msleep(7);
-
- //AGC initialization
- if (state->cfg.agc_control)
- state->cfg.agc_control(&state->demod, 1);
-
- dib7000m_restart_agc(state);
-
- // wait AGC rough lock time
- msleep(5);
-
- dib7000m_update_lna(state);
- dib7000m_agc_soft_split(state);
-
- // wait AGC accurate lock time
- msleep(7);
-
- if (state->cfg.agc_control)
- state->cfg.agc_control(&state->demod, 0);
-
// set power-up level: autosearch
dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
}
-static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib7000m_state *state = demod->demodulator_priv;
- struct dibx000_ofdm_channel auto_ch;
+ struct dvb_frontend_parameters schan;
int ret = 0;
- u32 value;
-
- INIT_OFDM_CHANNEL(&auto_ch);
- auto_ch.RF_kHz = ch->RF_kHz;
- auto_ch.Bw = ch->Bw;
- auto_ch.nqam = 2;
- auto_ch.guard = 0;
- auto_ch.nfft = 1;
- auto_ch.vit_alpha = 1;
- auto_ch.vit_select_hp = 1;
- auto_ch.vit_code_rate_hp = 2;
- auto_ch.vit_code_rate_lp = 3;
- auto_ch.vit_hrch = 0;
- auto_ch.intlv_native = 1;
-
- dib7000m_set_channel(state, &auto_ch, 7);
+ u32 value, factor;
+
+ schan = *ch;
+
+ schan.u.ofdm.constellation = QAM_64;
+ schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ schan.u.ofdm.code_rate_HP = FEC_2_3;
+ schan.u.ofdm.code_rate_LP = FEC_3_4;
+ schan.u.ofdm.hierarchy_information = 0;
+
+ dib7000m_set_channel(state, &schan, 7);
+
+ factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
+ if (factor >= 5000)
+ factor = 1;
+ else
+ factor = 6;
// always use the setting for 8MHz here lock_time for 7,6 MHz are longer
- value = 30 * state->cfg.bw->internal;
+ value = 30 * state->internal_clk * factor;
ret |= dib7000m_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
ret |= dib7000m_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
- value = 100 * state->cfg.bw->internal;
+ value = 100 * state->internal_clk * factor;
ret |= dib7000m_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
ret |= dib7000m_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
- value = 500 * state->cfg.bw->internal;
+ value = 500 * state->internal_clk * factor;
ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
ret |= dib7000m_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
// start search
value = dib7000m_read_word(state, 0);
- ret |= dib7000m_write_word(state, 0, value | (1 << 9));
+ ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9)));
/* clear n_irq_pending */
if (state->revision == 0x4000)
@@ -685,12 +969,12 @@ static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg)
u16 irq_pending = dib7000m_read_word(state, reg);
if (irq_pending & 0x1) { // failed
- dprintk("#\n");
+ dprintk( "autosearch failed");
return 1;
}
if (irq_pending & 0x2) { // succeeded
- dprintk("!\n");
+ dprintk( "autosearch succeeded");
return 2;
}
return 0; // still pending
@@ -705,7 +989,7 @@ static int dib7000m_autosearch_is_irq(struct dvb_frontend *demod)
return dib7000m_autosearch_irq(state, 537);
}
-static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib7000m_state *state = demod->demodulator_priv;
int ret = 0;
@@ -722,182 +1006,103 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel
ret |= dib7000m_write_word(state, 898, 0x0000);
msleep(45);
- ret |= dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
+ dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
- // never achieved a lock with that bandwidth so far - wait for timfreq to update
+ // never achieved a lock before - wait for timfreq to update
if (state->timf == 0)
msleep(200);
//dump_reg(state);
/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
value = (6 << 8) | 0x80;
- switch (ch->nfft) {
- case 0: value |= (7 << 12); break;
- case 1: value |= (9 << 12); break;
- case 2: value |= (8 << 12); break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
+ case /* 4K MODE */ 255: value |= (8 << 12); break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= (9 << 12); break;
}
ret |= dib7000m_write_word(state, 26, value);
/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
value = (0 << 4);
- switch (ch->nfft) {
- case 0: value |= 0x6; break;
- case 1: value |= 0x8; break;
- case 2: value |= 0x7; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= 0x6; break;
+ case /* 4K MODE */ 255: value |= 0x7; break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= 0x8; break;
}
ret |= dib7000m_write_word(state, 32, value);
/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
value = (0 << 4);
- switch (ch->nfft) {
- case 0: value |= 0x6; break;
- case 1: value |= 0x8; break;
- case 2: value |= 0x7; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= 0x6; break;
+ case /* 4K MODE */ 255: value |= 0x7; break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= 0x8; break;
}
ret |= dib7000m_write_word(state, 33, value);
- // we achieved a lock - it's time to update the osc freq
+ // we achieved a lock - it's time to update the timf freq
if ((dib7000m_read_word(state, 535) >> 6) & 0x1)
- dib7000m_update_timf_freq(state);
+ dib7000m_update_timf(state);
+ dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
return ret;
}
-static int dib7000m_init(struct dvb_frontend *demod)
+static int dib7000m_wakeup(struct dvb_frontend *demod)
{
struct dib7000m_state *state = demod->demodulator_priv;
- int ret = 0;
- u8 o = state->reg_offs;
dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
- dprintk("-E- could not start Slow ADC\n");
-
- if (state->cfg.dvbt_mode)
- dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
-
- if (state->cfg.mobile_mode)
- ret |= dib7000m_write_word(state, 261 + o, 2);
- else
- ret |= dib7000m_write_word(state, 224 + o, 1);
-
- ret |= dib7000m_write_word(state, 173 + o, 0);
- ret |= dib7000m_write_word(state, 174 + o, 0);
- ret |= dib7000m_write_word(state, 175 + o, 0);
- ret |= dib7000m_write_word(state, 176 + o, 0);
- ret |= dib7000m_write_word(state, 177 + o, 0);
- ret |= dib7000m_write_word(state, 178 + o, 0);
- ret |= dib7000m_write_word(state, 179 + o, 0);
- ret |= dib7000m_write_word(state, 180 + o, 0);
-
- // P_corm_thres Lock algorithms configuration
- ret |= dib7000m_write_word(state, 26, 0x6680);
-
- // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
- ret |= dib7000m_write_word(state, 170 + o, 0x0410);
- // P_fft_nb_to_cut
- ret |= dib7000m_write_word(state, 182 + o, 8192);
- // P_pha3_thres
- ret |= dib7000m_write_word(state, 195 + o, 0x0ccd);
- // P_cti_use_cpe, P_cti_use_prog
- ret |= dib7000m_write_word(state, 196 + o, 0);
- // P_cspu_regul, P_cspu_win_cut
- ret |= dib7000m_write_word(state, 205 + o, 0x200f);
- // P_adp_regul_cnt
- ret |= dib7000m_write_word(state, 214 + o, 0x023d);
- // P_adp_noise_cnt
- ret |= dib7000m_write_word(state, 215 + o, 0x00a4);
- // P_adp_regul_ext
- ret |= dib7000m_write_word(state, 216 + o, 0x00a4);
- // P_adp_noise_ext
- ret |= dib7000m_write_word(state, 217 + o, 0x7ff0);
- // P_adp_fil
- ret |= dib7000m_write_word(state, 218 + o, 0x3ccc);
-
- // P_2d_byp_ti_num
- ret |= dib7000m_write_word(state, 226 + o, 0);
-
- // P_fec_*
- ret |= dib7000m_write_word(state, 281 + o, 0x0010);
- // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
- ret |= dib7000m_write_word(state, 294 + o,0x0062);
-
- // P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
- if(state->cfg.tuner_is_baseband)
- ret |= dib7000m_write_word(state, 36, 0x0755);
- else
- ret |= dib7000m_write_word(state, 36, 0x1f55);
-
- // auto search configuration
- ret |= dib7000m_write_word(state, 2, 0x0004);
- ret |= dib7000m_write_word(state, 3, 0x1000);
- ret |= dib7000m_write_word(state, 4, 0x0814);
- ret |= dib7000m_write_word(state, 6, 0x001b);
- ret |= dib7000m_write_word(state, 7, 0x7740);
- ret |= dib7000m_write_word(state, 8, 0x005b);
- ret |= dib7000m_write_word(state, 9, 0x8d80);
- ret |= dib7000m_write_word(state, 10, 0x01c9);
- ret |= dib7000m_write_word(state, 11, 0xc380);
- ret |= dib7000m_write_word(state, 12, 0x0000);
- ret |= dib7000m_write_word(state, 13, 0x0080);
- ret |= dib7000m_write_word(state, 14, 0x0000);
- ret |= dib7000m_write_word(state, 15, 0x0090);
- ret |= dib7000m_write_word(state, 16, 0x0001);
- ret |= dib7000m_write_word(state, 17, 0xd4c0);
- ret |= dib7000m_write_word(state, 263 + o,0x0001);
-
- // P_divclksel=3 P_divbitsel=1
- if (state->revision == 0x4000)
- dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
- else
- dib7000m_write_word(state, 909, (3 << 4) | 1);
-
- // Tuner IO bank: max drive (14mA)
- ret |= dib7000m_write_word(state, 912 ,0x2c8a);
+ dprintk( "could not start Slow ADC");
- ret |= dib7000m_write_word(state, 1817, 1);
-
- return ret;
+ return 0;
}
static int dib7000m_sleep(struct dvb_frontend *demod)
{
struct dib7000m_state *st = demod->demodulator_priv;
dib7000m_set_output_mode(st, OUTMODE_HIGH_Z);
- return dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY) |
- dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
+ dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY);
+ return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
dib7000m_set_adc_state(st, DIBX000_ADC_OFF);
}
static int dib7000m_identify(struct dib7000m_state *state)
{
u16 value;
+
if ((value = dib7000m_read_word(state, 896)) != 0x01b3) {
- dprintk("-E- DiB7000M: wrong Vendor ID (read=0x%x)\n",value);
+ dprintk( "wrong Vendor ID (0x%x)",value);
return -EREMOTEIO;
}
state->revision = dib7000m_read_word(state, 897);
if (state->revision != 0x4000 &&
state->revision != 0x4001 &&
- state->revision != 0x4002) {
- dprintk("-E- DiB7000M: wrong Device ID (%x)\n",value);
+ state->revision != 0x4002 &&
+ state->revision != 0x4003) {
+ dprintk( "wrong Device ID (0x%x)",value);
return -EREMOTEIO;
}
/* protect this driver to be used with 7000PC */
if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) {
- dprintk("-E- DiB7000M: this driver does not work with DiB7000PC\n");
+ dprintk( "this driver does not work with DiB7000PC");
return -EREMOTEIO;
}
switch (state->revision) {
- case 0x4000: dprintk("-I- found DiB7000MA/PA/MB/PB\n"); break;
- case 0x4001: state->reg_offs = 1; dprintk("-I- found DiB7000HC\n"); break;
- case 0x4002: state->reg_offs = 1; dprintk("-I- found DiB7000MC\n"); break;
+ case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break;
+ case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break;
+ case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break;
+ case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break;
}
return 0;
@@ -966,41 +1171,45 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dib7000m_state *state = fe->demodulator_priv;
- struct dibx000_ofdm_channel ch;
-
- INIT_OFDM_CHANNEL(&ch);
- FEP2DIB(fep,&ch);
+ int time;
state->current_bandwidth = fep->u.ofdm.bandwidth;
- dib7000m_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+ dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe, fep);
+ /* start up the AGC */
+ state->agc_state = 0;
+ do {
+ time = dib7000m_agc_startup(fe, fep);
+ if (time != -1)
+ msleep(time);
+ } while (time != -1);
+
if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
fep->u.ofdm.constellation == QAM_AUTO ||
fep->u.ofdm.code_rate_HP == FEC_AUTO) {
int i = 800, found;
- dib7000m_autosearch_start(fe, &ch);
+ dib7000m_autosearch_start(fe, fep);
do {
msleep(1);
found = dib7000m_autosearch_is_irq(fe);
} while (found == 0 && i--);
- dprintk("autosearch returns: %d\n",found);
+ dprintk("autosearch returns: %d",found);
if (found == 0 || found == 1)
return 0; // no channel found
dib7000m_get_frontend(fe, fep);
- FEP2DIB(fep, &ch);
}
/* make this a config parameter */
dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
- return dib7000m_tune(fe, &ch);
+ return dib7000m_tune(fe, fep);
}
static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@@ -1087,7 +1296,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
if (dib7000m_identify(&st) != 0) {
st.i2c_addr = default_addr;
if (dib7000m_identify(&st) != 0) {
- dprintk("DiB7000M #%d: not identified\n", k);
+ dprintk("DiB7000M #%d: not identified", k);
return -EIO;
}
}
@@ -1100,7 +1309,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
/* set new i2c address and force divstart */
dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2);
- dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
+ dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
}
for (k = 0; k < no_of_demods; k++) {
@@ -1135,6 +1344,8 @@ struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
demod->demodulator_priv = st;
memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
+ st->timf_default = cfg->bw->timf;
+
if (dib7000m_identify(st) != 0)
goto error;
@@ -1172,7 +1383,7 @@ static struct dvb_frontend_ops dib7000m_ops = {
.release = dib7000m_release,
- .init = dib7000m_init,
+ .init = dib7000m_wakeup,
.sleep = dib7000m_sleep,
.set_frontend = dib7000m_set_frontend,
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index aece458cfe1..f45bcfc51cf 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -1,7 +1,7 @@
/*
* Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
*
- * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -18,7 +18,11 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P:"); printk(args); } } while (0)
+static int buggy_sfn_workaround;
+module_param(buggy_sfn_workaround, int, 0644);
+MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
struct dib7000p_state {
struct dvb_frontend demod;
@@ -36,12 +40,21 @@ struct dib7000p_state {
struct dibx000_agc_config *current_agc;
u32 timf;
+ u8 div_force_off : 1;
+ u8 div_state : 1;
+ u16 div_sync_wait;
+
+ u8 agc_state;
+
u16 gpio_dir;
u16 gpio_val;
+
+ u8 sfn_workaround_active :1;
};
enum dib7000p_power_mode {
DIB7000P_POWER_ALL = 0,
+ DIB7000P_POWER_ANALOG_ADC,
DIB7000P_POWER_INTERFACE_ONLY,
};
@@ -55,7 +68,7 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
};
if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
- dprintk("i2c read error on %d\n",reg);
+ dprintk("i2c read error on %d",reg);
return (rb[0] << 8) | rb[1];
}
@@ -71,6 +84,22 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
};
return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
}
+static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf)
+{
+ u16 l = 0, r, *n;
+ n = buf;
+ l = *n++;
+ while (l) {
+ r = *n++;
+
+ do {
+ dib7000p_write_word(state, r, *n++);
+ r++;
+ } while (--l);
+ l = *n++;
+ }
+}
+
static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
{
int ret = 0;
@@ -80,7 +109,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
fifo_threshold = 1792;
smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1);
- dprintk("-I- Setting output mode for demod %p to %d\n",
+ dprintk( "setting output mode for demod %p to %d",
&state->demod, mode);
switch (mode) {
@@ -104,11 +133,14 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
fifo_threshold = 512;
outreg = (1 << 10) | (5 << 6);
break;
+ case OUTMODE_ANALOG_ADC:
+ outreg = (1 << 10) | (3 << 6);
+ break;
case OUTMODE_HIGH_Z: // disable
outreg = 0;
break;
default:
- dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+ dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
break;
}
@@ -122,6 +154,30 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
return ret;
}
+static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+
+ if (state->div_force_off) {
+ dprintk( "diversity combination deactivated - forced by COFDM parameters");
+ onoff = 0;
+ }
+ state->div_state = (u8)onoff;
+
+ if (onoff) {
+ dib7000p_write_word(state, 204, 6);
+ dib7000p_write_word(state, 205, 16);
+ /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
+ dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
+ } else {
+ dib7000p_write_word(state, 204, 1);
+ dib7000p_write_word(state, 205, 0);
+ dib7000p_write_word(state, 207, 0);
+ }
+
+ return 0;
+}
+
static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
{
/* by default everything is powered off */
@@ -134,10 +190,21 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p
case DIB7000P_POWER_ALL:
reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff;
break;
+
+ case DIB7000P_POWER_ANALOG_ADC:
+ /* dem, cfg, iqc, sad, agc */
+ reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
+ /* nud */
+ reg_776 &= ~((1 << 0));
+ /* Dout */
+ reg_1280 &= ~((1 << 11));
+ /* fall through wanted to enable the interfaces */
+
/* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
break;
+
/* TODO following stuff is just converted from the dib7000-driver - check when is used what */
}
@@ -188,34 +255,31 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad
break;
}
-// dprintk("908: %x, 909: %x\n", reg_908, reg_909);
+// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
dib7000p_write_word(state, 908, reg_908);
dib7000p_write_word(state, 909, reg_909);
}
-static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx)
+static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
{
- struct dib7000p_state *state = demod->demodulator_priv;
u32 timf;
// store the current bandwidth for later use
- state->current_bandwidth = BW_Idx;
+ state->current_bandwidth = bw;
if (state->timf == 0) {
- dprintk("-D- Using default timf\n");
+ dprintk( "using default timf");
timf = state->cfg.bw->timf;
} else {
- dprintk("-D- Using updated timf\n");
+ dprintk( "using updated timf");
timf = state->timf;
}
- timf = timf * (BW_INDEX_TO_KHZ(BW_Idx) / 100) / 80;
-
- dprintk("timf: %d\n",timf);
+ timf = timf * (bw / 50) / 160;
- dib7000p_write_word(state, 23, (timf >> 16) & 0xffff);
- dib7000p_write_word(state, 24, (timf ) & 0xffff);
+ dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
+ dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff));
return 0;
}
@@ -223,7 +287,7 @@ static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx)
static int dib7000p_sad_calib(struct dib7000p_state *state)
{
/* internal */
-// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
+// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
@@ -236,18 +300,37 @@ static int dib7000p_sad_calib(struct dib7000p_state *state)
return 0;
}
+int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+ if (value > 4095)
+ value = 4095;
+ state->wbd_ref = value;
+ return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
+}
+
+EXPORT_SYMBOL(dib7000p_set_wbd_ref);
static void dib7000p_reset_pll(struct dib7000p_state *state)
{
struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
+ u16 clk_cfg0;
+
+ /* force PLL bypass */
+ clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
+ (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) |
+ (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
+ dib7000p_write_word(state, 900, clk_cfg0);
+
+ /* P_pll_cfg */
dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
- dib7000p_write_word(state, 900, ((bw->pll_ratio & 0x3f) << 9) | (bw->pll_bypass << 15) | (bw->modulo << 7) | (bw->ADClkSrc << 6) |
- (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0));
+ clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
+ dib7000p_write_word(state, 900, clk_cfg0);
- dib7000p_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff);
- dib7000p_write_word(state, 19, (bw->internal*1000 ) & 0xffff);
- dib7000p_write_word(state, 21, (bw->ifreq >> 16) & 0xffff);
- dib7000p_write_word(state, 22, (bw->ifreq ) & 0xffff);
+ dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
+ dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff));
+ dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff));
+ dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff));
dib7000p_write_word(state, 72, bw->sad_cfg);
}
@@ -255,7 +338,7 @@ static void dib7000p_reset_pll(struct dib7000p_state *state)
static int dib7000p_reset_gpio(struct dib7000p_state *st)
{
/* reset the GPIOs */
- dprintk("-D- gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos);
+ dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos);
dib7000p_write_word(st, 1029, st->gpio_dir);
dib7000p_write_word(st, 1030, st->gpio_val);
@@ -268,6 +351,120 @@ static int dib7000p_reset_gpio(struct dib7000p_state *st)
return 0;
}
+static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
+{
+ st->gpio_dir = dib7000p_read_word(st, 1029);
+ st->gpio_dir &= ~(1 << num); /* reset the direction bit */
+ st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */
+ dib7000p_write_word(st, 1029, st->gpio_dir);
+
+ st->gpio_val = dib7000p_read_word(st, 1030);
+ st->gpio_val &= ~(1 << num); /* reset the direction bit */
+ st->gpio_val |= (val & 0x01) << num; /* set the new value */
+ dib7000p_write_word(st, 1030, st->gpio_val);
+
+ return 0;
+}
+
+int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+ return dib7000p_cfg_gpio(state, num, dir, val);
+}
+
+EXPORT_SYMBOL(dib7000p_set_gpio);
+static u16 dib7000p_defaults[] =
+
+{
+ // auto search configuration
+ 3, 2,
+ 0x0004,
+ 0x1000,
+ 0x0814, /* Equal Lock */
+
+ 12, 6,
+ 0x001b,
+ 0x7740,
+ 0x005b,
+ 0x8d80,
+ 0x01c9,
+ 0xc380,
+ 0x0000,
+ 0x0080,
+ 0x0000,
+ 0x0090,
+ 0x0001,
+ 0xd4c0,
+
+ 1, 26,
+ 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
+
+ /* set ADC level to -16 */
+ 11, 79,
+ (1 << 13) - 825 - 117,
+ (1 << 13) - 837 - 117,
+ (1 << 13) - 811 - 117,
+ (1 << 13) - 766 - 117,
+ (1 << 13) - 737 - 117,
+ (1 << 13) - 693 - 117,
+ (1 << 13) - 648 - 117,
+ (1 << 13) - 619 - 117,
+ (1 << 13) - 575 - 117,
+ (1 << 13) - 531 - 117,
+ (1 << 13) - 501 - 117,
+
+ 1, 142,
+ 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
+
+ /* disable power smoothing */
+ 8, 145,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+
+ 1, 154,
+ 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0
+
+ 1, 168,
+ 0x0ccd, // P_pha3_thres, default 0x3000
+
+// 1, 169,
+// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
+
+ 1, 183,
+ 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
+
+ 5, 187,
+ 0x023d, // P_adp_regul_cnt=573, default: 410
+ 0x00a4, // P_adp_noise_cnt=
+ 0x00a4, // P_adp_regul_ext
+ 0x7ff0, // P_adp_noise_ext
+ 0x3ccc, // P_adp_fil
+
+ 1, 198,
+ 0x800, // P_equal_thres_wgn
+
+ 1, 222,
+ 0x0010, // P_fec_ber_rs_len=2
+
+ 1, 235,
+ 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+
+ 2, 901,
+ 0x0006, // P_clk_cfg1
+ (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1
+
+ 1, 905,
+ 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive
+
+ 0,
+};
+
static int dib7000p_demod_reset(struct dib7000p_state *state)
{
dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
@@ -292,111 +489,307 @@ static int dib7000p_demod_reset(struct dib7000p_state *state)
dib7000p_reset_pll(state);
if (dib7000p_reset_gpio(state) != 0)
- dprintk("-E- GPIO reset was not successful.\n");
+ dprintk( "GPIO reset was not successful.");
if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
- dprintk("-E- OUTPUT_MODE could not be resetted.\n");
+ dprintk( "OUTPUT_MODE could not be reset.");
/* unforce divstr regardless whether i2c enumeration was done or not */
dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) );
+ dib7000p_set_bandwidth(state, 8000);
+
+ dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
+ dib7000p_sad_calib(state);
+ dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+
+ // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
+ if(state->cfg.tuner_is_baseband)
+ dib7000p_write_word(state, 36,0x0755);
+ else
+ dib7000p_write_word(state, 36,0x1f55);
+
+ dib7000p_write_tab(state, dib7000p_defaults);
+
dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
+
return 0;
}
+static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
+{
+ u16 tmp = 0;
+ tmp = dib7000p_read_word(state, 903);
+ dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll
+ tmp = dib7000p_read_word(state, 900);
+ dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock
+}
+
static void dib7000p_restart_agc(struct dib7000p_state *state)
{
// P_restart_iqc & P_restart_agc
- dib7000p_write_word(state, 770, 0x0c00);
+ dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
dib7000p_write_word(state, 770, 0x0000);
}
-static void dib7000p_update_lna(struct dib7000p_state *state)
+static int dib7000p_update_lna(struct dib7000p_state *state)
{
- int i;
u16 dyn_gain;
// when there is no LNA to program return immediatly
- if (state->cfg.update_lna == NULL)
- return;
-
- for (i = 0; i < 5; i++) {
- // read dyn_gain here (because it is demod-dependent and not tuner)
+ if (state->cfg.update_lna) {
+ // read dyn_gain here (because it is demod-dependent and not fe)
dyn_gain = dib7000p_read_word(state, 394);
-
if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
dib7000p_restart_agc(state);
- msleep(5);
- } else
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
+{
+ struct dibx000_agc_config *agc = NULL;
+ int i;
+ if (state->current_band == band && state->current_agc != NULL)
+ return 0;
+ state->current_band = band;
+
+ for (i = 0; i < state->cfg.agc_config_count; i++)
+ if (state->cfg.agc[i].band_caps & band) {
+ agc = &state->cfg.agc[i];
break;
+ }
+
+ if (agc == NULL) {
+ dprintk( "no valid AGC configuration found for band 0x%02x",band);
+ return -EINVAL;
}
+
+ state->current_agc = agc;
+
+ /* AGC */
+ dib7000p_write_word(state, 75 , agc->setup );
+ dib7000p_write_word(state, 76 , agc->inv_gain );
+ dib7000p_write_word(state, 77 , agc->time_stabiliz );
+ dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
+
+ // Demod AGC loop configuration
+ dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
+ dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
+
+ /* AGC continued */
+ dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
+ state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
+
+ if (state->wbd_ref != 0)
+ dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
+ else
+ dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
+
+ dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
+
+ dib7000p_write_word(state, 107, agc->agc1_max);
+ dib7000p_write_word(state, 108, agc->agc1_min);
+ dib7000p_write_word(state, 109, agc->agc2_max);
+ dib7000p_write_word(state, 110, agc->agc2_min);
+ dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
+ dib7000p_write_word(state, 112, agc->agc1_pt3);
+ dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+ dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
+ dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+ return 0;
}
-static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
+static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
- u16 tmp = 0;
- tmp = dib7000p_read_word(state, 903);
- dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll
- tmp = dib7000p_read_word(state, 900);
- dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock
+ struct dib7000p_state *state = demod->demodulator_priv;
+ int ret = -1;
+ u8 *agc_state = &state->agc_state;
+ u8 agc_split;
+
+ switch (state->agc_state) {
+ case 0:
+ // set power-up level: interf+analog+AGC
+ dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+ dib7000p_set_adc_state(state, DIBX000_ADC_ON);
+ dib7000p_pll_clk_cfg(state);
+
+ if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
+ return -1;
+
+ ret = 7;
+ (*agc_state)++;
+ break;
+
+ case 1:
+ // AGC initialization
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 1);
+
+ dib7000p_write_word(state, 78, 32768);
+ if (!state->current_agc->perform_agc_softsplit) {
+ /* we are using the wbd - so slow AGC startup */
+ /* force 0 split on WBD and restart AGC */
+ dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
+ (*agc_state)++;
+ ret = 5;
+ } else {
+ /* default AGC startup */
+ (*agc_state) = 4;
+ /* wait AGC rough lock time */
+ ret = 7;
+ }
+
+ dib7000p_restart_agc(state);
+ break;
+
+ case 2: /* fast split search path after 5sec */
+ dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
+ dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
+ (*agc_state)++;
+ ret = 14;
+ break;
+
+ case 3: /* split search ended */
+ agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */
+ dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
+
+ dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */
+ dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
+
+ dib7000p_restart_agc(state);
+
+ dprintk( "SPLIT %p: %hd", demod, agc_split);
+
+ (*agc_state)++;
+ ret = 5;
+ break;
+
+ case 4: /* LNA startup */
+ // wait AGC accurate lock time
+ ret = 7;
+
+ if (dib7000p_update_lna(state))
+ // wait only AGC rough lock time
+ ret = 5;
+ else // nothing was done, go to the next state
+ (*agc_state)++;
+ break;
+
+ case 5:
+ if (state->cfg.agc_control)
+ state->cfg.agc_control(&state->demod, 0);
+ (*agc_state)++;
+ break;
+ default:
+ break;
+ }
+ return ret;
}
-static void dib7000p_update_timf_freq(struct dib7000p_state *state)
+static void dib7000p_update_timf(struct dib7000p_state *state)
{
u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
- state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100);
+ state->timf = timf * 160 / (state->current_bandwidth / 50);
dib7000p_write_word(state, 23, (u16) (timf >> 16));
dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
- dprintk("-D- Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf);
+ dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf);
+
}
-static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_ofdm_channel *ch, u8 seq)
+static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
{
- u16 tmp, est[4]; // reg_26, reg_32, reg_33, reg_187, reg_188, reg_189, reg_190, reg_207, reg_208;
+ u16 value, est[4];
+
+ dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
/* nfft, guard, qam, alpha */
- dib7000p_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha));
+ value = 0;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+ case /* 4K MODE */ 255: value |= (2 << 7); break;
+ default:
+ case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+ }
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+ case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+ case GUARD_INTERVAL_1_4: value |= (3 << 5); break;
+ default:
+ case GUARD_INTERVAL_1_8: value |= (2 << 5); break;
+ }
+ switch (ch->u.ofdm.constellation) {
+ case QPSK: value |= (0 << 3); break;
+ case QAM_16: value |= (1 << 3); break;
+ default:
+ case QAM_64: value |= (2 << 3); break;
+ }
+ switch (HIERARCHY_1) {
+ case HIERARCHY_2: value |= 2; break;
+ case HIERARCHY_4: value |= 4; break;
+ default:
+ case HIERARCHY_1: value |= 1; break;
+ }
+ dib7000p_write_word(state, 0, value);
dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
- /* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */
- tmp = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1);
- if (ch->vit_hrch == 0 || ch->vit_select_hp == 1)
- tmp |= (ch->vit_code_rate_hp << 1);
- else
- tmp |= (ch->vit_code_rate_lp << 1);
- dib7000p_write_word(state, 208, tmp);
+ /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
+ value = 0;
+ if (1 != 0)
+ value |= (1 << 6);
+ if (ch->u.ofdm.hierarchy_information == 1)
+ value |= (1 << 4);
+ if (1 == 1)
+ value |= 1;
+ switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+ case FEC_2_3: value |= (2 << 1); break;
+ case FEC_3_4: value |= (3 << 1); break;
+ case FEC_5_6: value |= (5 << 1); break;
+ case FEC_7_8: value |= (7 << 1); break;
+ default:
+ case FEC_1_2: value |= (1 << 1); break;
+ }
+ dib7000p_write_word(state, 208, value);
+
+ /* offset loop parameters */
+ dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
+ dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
+ dib7000p_write_word(state, 29, 0x1273); // isi
+ dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
/* P_dvsy_sync_wait */
- switch (ch->nfft) {
- case 1: tmp = 256; break;
- case 2: tmp = 128; break;
- case 0:
- default: tmp = 64; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_8K: value = 256; break;
+ case /* 4K MODE */ 255: value = 128; break;
+ case TRANSMISSION_MODE_2K:
+ default: value = 64; break;
}
- tmp *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin
- tmp <<= 4;
-
- /* deactive the possibility of diversity reception if extended interleave */
- /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
- if (ch->intlv_native || ch->nfft == 1)
- tmp |= (1 << 2) | (2 << 0);
- dib7000p_write_word(state, 207, tmp);
+ switch (ch->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_16: value *= 2; break;
+ case GUARD_INTERVAL_1_8: value *= 4; break;
+ case GUARD_INTERVAL_1_4: value *= 8; break;
+ default:
+ case GUARD_INTERVAL_1_32: value *= 1; break;
+ }
+ state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
- dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
- dib7000p_write_word(state, 29, 0x1273); // isi inh1273 on1073
- dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
- dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
+ /* deactive the possibility of diversity reception if extended interleaver */
+ state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
+ dib7000p_set_diversity_in(&state->demod, state->div_state);
/* channel estimation fine configuration */
- switch (ch->nqam) {
- case 2:
+ switch (ch->u.ofdm.constellation) {
+ case QAM_64:
est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */
est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */
est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */
break;
- case 1:
+ case QAM_16:
est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */
est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */
est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */
@@ -409,66 +802,45 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_of
est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */
break;
}
- for (tmp = 0; tmp < 4; tmp++)
- dib7000p_write_word(state, 187 + tmp, est[tmp]);
-
- // set power-up level: interf+analog+AGC
- dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
- dib7000p_set_adc_state(state, DIBX000_ADC_ON);
- dib7000p_pll_clk_cfg(state);
- msleep(7);
-
- // AGC initialization
- if (state->cfg.agc_control)
- state->cfg.agc_control(&state->demod, 1);
-
- dib7000p_restart_agc(state);
-
- // wait AGC rough lock time
- msleep(5);
-
- dib7000p_update_lna(state);
-
- // wait AGC accurate lock time
- msleep(7);
- if (state->cfg.agc_control)
- state->cfg.agc_control(&state->demod, 0);
+ for (value = 0; value < 4; value++)
+ dib7000p_write_word(state, 187 + value, est[value]);
}
-static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib7000p_state *state = demod->demodulator_priv;
- struct dibx000_ofdm_channel auto_ch;
- u32 value;
-
- INIT_OFDM_CHANNEL(&auto_ch);
- auto_ch.RF_kHz = ch->RF_kHz;
- auto_ch.Bw = ch->Bw;
- auto_ch.nqam = 2;
- auto_ch.guard = 0;
- auto_ch.nfft = 1;
- auto_ch.vit_alpha = 1;
- auto_ch.vit_select_hp = 1;
- auto_ch.vit_code_rate_hp = 2;
- auto_ch.vit_code_rate_lp = 3;
- auto_ch.vit_hrch = 0;
- auto_ch.intlv_native = 1;
-
- dib7000p_set_channel(state, &auto_ch, 7);
+ struct dvb_frontend_parameters schan;
+ u32 value, factor;
+
+ schan = *ch;
+ schan.u.ofdm.constellation = QAM_64;
+ schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ schan.u.ofdm.code_rate_HP = FEC_2_3;
+ schan.u.ofdm.code_rate_LP = FEC_3_4;
+ schan.u.ofdm.hierarchy_information = 0;
+
+ dib7000p_set_channel(state, &schan, 7);
+
+ factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
+ if (factor >= 5000)
+ factor = 1;
+ else
+ factor = 6;
// always use the setting for 8MHz here lock_time for 7,6 MHz are longer
- value = 30 * state->cfg.bw->internal;
+ value = 30 * state->cfg.bw->internal * factor;
dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time
dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time
- value = 100 * state->cfg.bw->internal;
+ value = 100 * state->cfg.bw->internal * factor;
dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time
dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time
- value = 500 * state->cfg.bw->internal;
+ value = 500 * state->cfg.bw->internal * factor;
dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time
value = dib7000p_read_word(state, 0);
- dib7000p_write_word(state, 0, (1 << 9) | value);
+ dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
dib7000p_read_word(state, 1284);
dib7000p_write_word(state, 0, (u16) value);
@@ -489,7 +861,95 @@ static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod)
return 0; // still pending
}
-static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
+{
+ static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392};
+ static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
+ 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
+ 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
+ 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
+ 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
+ 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
+ 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
+ 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
+ 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
+ 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
+ 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
+ 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
+ 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
+ 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
+ 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
+ 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255};
+
+ u32 xtal = state->cfg.bw->xtal_hz / 1000;
+ int f_rel = ( (rf_khz + xtal/2) / xtal) * xtal - rf_khz;
+ int k;
+ int coef_re[8],coef_im[8];
+ int bw_khz = bw;
+ u32 pha;
+
+ dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
+
+
+ if (f_rel < -bw_khz/2 || f_rel > bw_khz/2)
+ return;
+
+ bw_khz /= 100;
+
+ dib7000p_write_word(state, 142 ,0x0610);
+
+ for (k = 0; k < 8; k++) {
+ pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff;
+
+ if (pha==0) {
+ coef_re[k] = 256;
+ coef_im[k] = 0;
+ } else if(pha < 256) {
+ coef_re[k] = sine[256-(pha&0xff)];
+ coef_im[k] = sine[pha&0xff];
+ } else if (pha == 256) {
+ coef_re[k] = 0;
+ coef_im[k] = 256;
+ } else if (pha < 512) {
+ coef_re[k] = -sine[pha&0xff];
+ coef_im[k] = sine[256 - (pha&0xff)];
+ } else if (pha == 512) {
+ coef_re[k] = -256;
+ coef_im[k] = 0;
+ } else if (pha < 768) {
+ coef_re[k] = -sine[256-(pha&0xff)];
+ coef_im[k] = -sine[pha&0xff];
+ } else if (pha == 768) {
+ coef_re[k] = 0;
+ coef_im[k] = -256;
+ } else {
+ coef_re[k] = sine[pha&0xff];
+ coef_im[k] = -sine[256 - (pha&0xff)];
+ }
+
+ coef_re[k] *= notch[k];
+ coef_re[k] += (1<<14);
+ if (coef_re[k] >= (1<<24))
+ coef_re[k] = (1<<24) - 1;
+ coef_re[k] /= (1<<15);
+
+ coef_im[k] *= notch[k];
+ coef_im[k] += (1<<14);
+ if (coef_im[k] >= (1<<24))
+ coef_im[k] = (1<<24)-1;
+ coef_im[k] /= (1<<15);
+
+ dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
+
+ dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
+ dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
+ dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
+ }
+ dib7000p_write_word(state,143 ,0);
+}
+
+static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
{
struct dib7000p_state *state = demod->demodulator_priv;
u16 tmp = 0;
@@ -505,7 +965,15 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel
msleep(45);
/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
- dib7000p_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
+ tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
+ if (state->sfn_workaround_active) {
+ dprintk( "SFN workaround is active");
+ tmp |= (1 << 9);
+ dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift
+ } else {
+ dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift
+ }
+ dib7000p_write_word(state, 29, tmp);
// never achieved a lock with that bandwidth so far - wait for osc-freq to update
if (state->timf == 0)
@@ -515,28 +983,31 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel
/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
tmp = (6 << 8) | 0x80;
- switch (ch->nfft) {
- case 0: tmp |= (7 << 12); break;
- case 1: tmp |= (9 << 12); break;
- case 2: tmp |= (8 << 12); break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break;
+ case /* 4K MODE */ 255: tmp |= (8 << 12); break;
+ default:
+ case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break;
}
dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */
/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
tmp = (0 << 4);
- switch (ch->nfft) {
- case 0: tmp |= 0x6; break;
- case 1: tmp |= 0x8; break;
- case 2: tmp |= 0x7; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
+ case /* 4K MODE */ 255: tmp |= 0x7; break;
+ default:
+ case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
}
dib7000p_write_word(state, 32, tmp);
/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
tmp = (0 << 4);
- switch (ch->nfft) {
- case 0: tmp |= 0x6; break;
- case 1: tmp |= 0x8; break;
- case 2: tmp |= 0x7; break;
+ switch (ch->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
+ case /* 4K MODE */ 255: tmp |= 0x7; break;
+ default:
+ case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
}
dib7000p_write_word(state, 33, tmp);
@@ -552,131 +1023,21 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel
// we achieved a lock - it's time to update the osc freq
if ((tmp >> 6) & 0x1)
- dib7000p_update_timf_freq(state);
+ dib7000p_update_timf(state);
+ if (state->cfg.spur_protect)
+ dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+
+ dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
return 0;
}
-static int dib7000p_init(struct dvb_frontend *demod)
+static int dib7000p_wakeup(struct dvb_frontend *demod)
{
- struct dibx000_agc_config *agc;
struct dib7000p_state *state = demod->demodulator_priv;
- int ret = 0;
-
- // Demodulator default configuration
- agc = state->cfg.agc;
-
dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
-
- /* AGC */
- ret |= dib7000p_write_word(state, 75 , agc->setup );
- ret |= dib7000p_write_word(state, 76 , agc->inv_gain );
- ret |= dib7000p_write_word(state, 77 , agc->time_stabiliz );
- ret |= dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
-
- // Demod AGC loop configuration
- ret |= dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
- ret |= dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp);
-
- /* AGC continued */
- dprintk("-D- WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
- state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
-
- if (state->wbd_ref != 0)
- ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
- else
- ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
-
- ret |= dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
-
- ret |= dib7000p_write_word(state, 107, agc->agc1_max);
- ret |= dib7000p_write_word(state, 108, agc->agc1_min);
- ret |= dib7000p_write_word(state, 109, agc->agc2_max);
- ret |= dib7000p_write_word(state, 110, agc->agc2_min);
- ret |= dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
- ret |= dib7000p_write_word(state, 112, agc->agc1_pt3);
- ret |= dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
- ret |= dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
- ret |= dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
-
- /* disable power smoothing */
- ret |= dib7000p_write_word(state, 145, 0);
- ret |= dib7000p_write_word(state, 146, 0);
- ret |= dib7000p_write_word(state, 147, 0);
- ret |= dib7000p_write_word(state, 148, 0);
- ret |= dib7000p_write_word(state, 149, 0);
- ret |= dib7000p_write_word(state, 150, 0);
- ret |= dib7000p_write_word(state, 151, 0);
- ret |= dib7000p_write_word(state, 152, 0);
-
- // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
- ret |= dib7000p_write_word(state, 26 ,0x6680);
-
- // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
- ret |= dib7000p_write_word(state, 142,0x0410);
- // P_fft_freq_dir=1, P_fft_nb_to_cut=0
- ret |= dib7000p_write_word(state, 154,1 << 13);
- // P_pha3_thres, default 0x3000
- ret |= dib7000p_write_word(state, 168,0x0ccd);
- // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
- //ret |= dib7000p_write_word(state, 169,0x0010);
- // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
- ret |= dib7000p_write_word(state, 183,0x200f);
- // P_adp_regul_cnt=573, default: 410
- ret |= dib7000p_write_word(state, 187,0x023d);
- // P_adp_noise_cnt=
- ret |= dib7000p_write_word(state, 188,0x00a4);
- // P_adp_regul_ext
- ret |= dib7000p_write_word(state, 189,0x00a4);
- // P_adp_noise_ext
- ret |= dib7000p_write_word(state, 190,0x7ff0);
- // P_adp_fil
- ret |= dib7000p_write_word(state, 191,0x3ccc);
-
- ret |= dib7000p_write_word(state, 222,0x0010);
- // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
- ret |= dib7000p_write_word(state, 235,0x0062);
-
- // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
- if(state->cfg.tuner_is_baseband)
- ret |= dib7000p_write_word(state, 36,0x0755);
- else
- ret |= dib7000p_write_word(state, 36,0x1f55);
-
- // auto search configuration
- ret |= dib7000p_write_word(state, 2 ,0x0004);
- ret |= dib7000p_write_word(state, 3 ,0x1000);
-
- /* Equal Lock */
- ret |= dib7000p_write_word(state, 4 ,0x0814);
-
- ret |= dib7000p_write_word(state, 6 ,0x001b);
- ret |= dib7000p_write_word(state, 7 ,0x7740);
- ret |= dib7000p_write_word(state, 8 ,0x005b);
- ret |= dib7000p_write_word(state, 9 ,0x8d80);
- ret |= dib7000p_write_word(state, 10 ,0x01c9);
- ret |= dib7000p_write_word(state, 11 ,0xc380);
- ret |= dib7000p_write_word(state, 12 ,0x0000);
- ret |= dib7000p_write_word(state, 13 ,0x0080);
- ret |= dib7000p_write_word(state, 14 ,0x0000);
- ret |= dib7000p_write_word(state, 15 ,0x0090);
- ret |= dib7000p_write_word(state, 16 ,0x0001);
- ret |= dib7000p_write_word(state, 17 ,0xd4c0);
-
- // P_clk_cfg1
- ret |= dib7000p_write_word(state, 901, 0x0006);
-
- // P_divclksel=3 P_divbitsel=1
- ret |= dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
-
- // Tuner IO bank: max drive (14mA) + divout pads max drive
- ret |= dib7000p_write_word(state, 905, 0x2c8e);
-
- ret |= dib7000p_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
- dib7000p_sad_calib(state);
-
- return ret;
+ return 0;
}
static int dib7000p_sleep(struct dvb_frontend *demod)
@@ -688,16 +1049,16 @@ static int dib7000p_sleep(struct dvb_frontend *demod)
static int dib7000p_identify(struct dib7000p_state *st)
{
u16 value;
- dprintk("-I- DiB7000PC: checking demod on I2C address: %d (%x)\n",
+ dprintk( "checking demod on I2C address: %d (%x)",
st->i2c_addr, st->i2c_addr);
if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
- dprintk("-E- DiB7000PC: wrong Vendor ID (read=0x%x)\n",value);
+ dprintk( "wrong Vendor ID (read=0x%x)",value);
return -EREMOTEIO;
}
if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
- dprintk("-E- DiB7000PC: wrong Device ID (%x)\n",value);
+ dprintk( "wrong Device ID (%x)",value);
return -EREMOTEIO;
}
@@ -767,41 +1128,48 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dib7000p_state *state = fe->demodulator_priv;
- struct dibx000_ofdm_channel ch;
-
- INIT_OFDM_CHANNEL(&ch);
- FEP2DIB(fep,&ch);
+ int time;
state->current_bandwidth = fep->u.ofdm.bandwidth;
- dib7000p_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+ dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+
+ /* maybe the parameter has been changed */
+ state->sfn_workaround_active = buggy_sfn_workaround;
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe, fep);
+ /* start up the AGC */
+ state->agc_state = 0;
+ do {
+ time = dib7000p_agc_startup(fe, fep);
+ if (time != -1)
+ msleep(time);
+ } while (time != -1);
+
if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
fep->u.ofdm.constellation == QAM_AUTO ||
fep->u.ofdm.code_rate_HP == FEC_AUTO) {
int i = 800, found;
- dib7000p_autosearch_start(fe, &ch);
+ dib7000p_autosearch_start(fe, fep);
do {
msleep(1);
found = dib7000p_autosearch_is_irq(fe);
} while (found == 0 && i--);
- dprintk("autosearch returns: %d\n",found);
+ dprintk("autosearch returns: %d",found);
if (found == 0 || found == 1)
return 0; // no channel found
dib7000p_get_frontend(fe, fep);
- FEP2DIB(fep, &ch);
}
/* make this a config parameter */
dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO);
- return dib7000p_tune(fe, &ch);
+ return dib7000p_tune(fe, fep);
}
static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@@ -879,7 +1247,7 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap)
if (i2c_transfer(i2c_adap, msg, 2) == 2)
if (rx[0] == 0x01 && rx[1] == 0xb3) {
- dprintk("-D- DiB7000PC detected\n");
+ dprintk("-D- DiB7000PC detected");
return 1;
}
@@ -887,11 +1255,11 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap)
if (i2c_transfer(i2c_adap, msg, 2) == 2)
if (rx[0] == 0x01 && rx[1] == 0xb3) {
- dprintk("-D- DiB7000PC detected\n");
+ dprintk("-D- DiB7000PC detected");
return 1;
}
- dprintk("-D- DiB7000PC not detected\n");
+ dprintk("-D- DiB7000PC not detected");
return 0;
}
EXPORT_SYMBOL(dib7000pc_detection);
@@ -929,7 +1297,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
/* set new i2c address and force divstart */
dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2);
- dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
+ dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
}
for (k = 0; k < no_of_demods; k++) {
@@ -1000,7 +1368,7 @@ static struct dvb_frontend_ops dib7000p_ops = {
.release = dib7000p_release,
- .init = dib7000p_init,
+ .init = dib7000p_wakeup,
.sleep = dib7000p_sleep,
.set_frontend = dib7000p_set_frontend,
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
index 79465cf1ace..eefcac8b524 100644
--- a/drivers/media/dvb/frontends/dib7000p.h
+++ b/drivers/media/dvb/frontends/dib7000p.h
@@ -9,6 +9,7 @@ struct dib7000p_config {
u8 tuner_is_baseband;
int (*update_lna) (struct dvb_frontend *, u16 agc_global);
+ u8 agc_config_count;
struct dibx000_agc_config *agc;
struct dibx000_bandwidth_config *bw;
@@ -27,20 +28,19 @@ struct dib7000p_config {
u8 quartz_direct;
+ u8 spur_protect;
+
int (*agc_control) (struct dvb_frontend *, u8 before);
};
#define DEFAULT_DIB7000P_I2C_ADDRESS 18
extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
+extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
+
extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
-
-/* TODO
-extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val);
-extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod);
-extern void dib7000p_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff);
-extern USHORT dib7000p_get_current_agc_global(struct dibDemod *demod);
-*/
+extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
+extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
#endif
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
index a1df604366c..5e17275afd2 100644
--- a/drivers/media/dvb/frontends/dibx000_common.h
+++ b/drivers/media/dvb/frontends/dibx000_common.h
@@ -111,6 +111,8 @@ struct dibx000_bandwidth_config {
u32 ifreq;
u32 timf;
+
+ u32 xtal_hz;
};
enum dibx000_adc_states {
@@ -122,56 +124,17 @@ enum dibx000_adc_states {
DIBX000_VBG_DISABLE,
};
-#define BW_INDEX_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \
+#define BANDWIDTH_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \
(v) == BANDWIDTH_7_MHZ ? 7000 : \
(v) == BANDWIDTH_6_MHZ ? 6000 : 8000 )
/* Chip output mode. */
-#define OUTMODE_HIGH_Z 0
-#define OUTMODE_MPEG2_PAR_GATED_CLK 1
-#define OUTMODE_MPEG2_PAR_CONT_CLK 2
-#define OUTMODE_MPEG2_SERIAL 7
-#define OUTMODE_DIVERSITY 4
-#define OUTMODE_MPEG2_FIFO 5
-
-/* I hope I can get rid of the following kludge in the near future */
-struct dibx000_ofdm_channel {
- u32 RF_kHz;
- u8 Bw;
- s16 nfft;
- s16 guard;
- s16 nqam;
- s16 vit_hrch;
- s16 vit_select_hp;
- s16 vit_alpha;
- s16 vit_code_rate_hp;
- s16 vit_code_rate_lp;
- u8 intlv_native;
-};
-
-#define FEP2DIB(fep,ch) \
- (ch)->RF_kHz = (fep)->frequency / 1000; \
- (ch)->Bw = (fep)->u.ofdm.bandwidth; \
- (ch)->nfft = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \
- (ch)->guard = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \
- (ch)->nqam = (fep)->u.ofdm.constellation == QAM_AUTO ? -1 : (fep)->u.ofdm.constellation == QAM_64 ? 2 : (fep)->u.ofdm.constellation; \
- (ch)->vit_hrch = 0; /* linux-dvb is not prepared for HIERARCHICAL TRANSMISSION */ \
- (ch)->vit_select_hp = 1; \
- (ch)->vit_alpha = 1; \
- (ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \
- (ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP; \
- (ch)->intlv_native = 1;
-
-#define INIT_OFDM_CHANNEL(ch) do {\
- (ch)->Bw = 0; \
- (ch)->nfft = -1; \
- (ch)->guard = -1; \
- (ch)->nqam = -1; \
- (ch)->vit_hrch = -1; \
- (ch)->vit_select_hp = -1; \
- (ch)->vit_alpha = -1; \
- (ch)->vit_code_rate_hp = -1; \
- (ch)->vit_code_rate_lp = -1; \
-} while (0)
+#define OUTMODE_HIGH_Z 0
+#define OUTMODE_MPEG2_PAR_GATED_CLK 1
+#define OUTMODE_MPEG2_PAR_CONT_CLK 2
+#define OUTMODE_MPEG2_SERIAL 7
+#define OUTMODE_DIVERSITY 4
+#define OUTMODE_MPEG2_FIFO 5
+#define OUTMODE_ANALOG_ADC 6
#endif
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 11f7d5939bd..8c8d7342d0b 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -24,12 +24,48 @@
#include "dvb-pll.h"
+struct dvb_pll_priv {
+ /* pll number */
+ int nr;
+
+ /* i2c details */
+ int pll_i2c_address;
+ struct i2c_adapter *i2c;
+
+ /* the PLL descriptor */
+ struct dvb_pll_desc *pll_desc;
+
+ /* cached frequency/bandwidth */
+ u32 frequency;
+ u32 bandwidth;
+};
+
+#define DVB_PLL_MAX 64
+
+static unsigned int dvb_pll_devcount;
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static unsigned int input[DVB_PLL_MAX] = { [ 0 ... (DVB_PLL_MAX-1) ] = 0 };
+module_param_array(input, int, NULL, 0644);
+MODULE_PARM_DESC(input,"specify rf input choice, 0 for autoselect (default)");
+
+static unsigned int id[DVB_PLL_MAX] =
+ { [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED };
+module_param_array(id, int, NULL, 0644);
+MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)");
+
+/* ----------------------------------------------------------- */
+
struct dvb_pll_desc {
char *name;
u32 min;
u32 max;
u32 iffreq;
- void (*set)(u8 *buf, const struct dvb_frontend_parameters *params);
+ void (*set)(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params);
u8 *initdata;
u8 *sleepdata;
int count;
@@ -89,7 +125,7 @@ static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
},
};
-static void thomson_dtt759x_bw(u8 *buf,
+static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf,
const struct dvb_frontend_parameters *params)
{
if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth)
@@ -210,7 +246,8 @@ static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
/* Philips TDA6650/TDA6651
* used in Panasonic ENV77H11D5
*/
-static void tda665x_bw(u8 *buf, const struct dvb_frontend_parameters *params)
+static void tda665x_bw(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[3] |= 0x08;
@@ -243,7 +280,8 @@ static struct dvb_pll_desc dvb_pll_tda665x = {
/* Infineon TUA6034
* used in LG TDTP E102P
*/
-static void tua6034_bw(u8 *buf, const struct dvb_frontend_parameters *params)
+static void tua6034_bw(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth)
buf[3] |= 0x08;
@@ -283,7 +321,8 @@ static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
/* Philips FMD1216ME
* used in Medion Hybrid PCMCIA card and USB Box
*/
-static void fmd1216me_bw(u8 *buf, const struct dvb_frontend_parameters *params)
+static void fmd1216me_bw(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
params->frequency >= 158870000)
@@ -313,7 +352,8 @@ static struct dvb_pll_desc dvb_pll_fmd1216me = {
/* ALPS TDED4
* used in Nebula-Cards and USB boxes
*/
-static void tded4_bw(u8 *buf, const struct dvb_frontend_parameters *params)
+static void tded4_bw(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[3] |= 0x04;
@@ -354,16 +394,35 @@ static struct dvb_pll_desc dvb_pll_tdhu2 = {
/* Philips TUV1236D
* used in ATI HDTV Wonder
*/
-static void tuv1236d_rf(u8 *buf, const struct dvb_frontend_parameters *params)
+static void tuv1236d_rf(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
- switch (params->u.vsb.modulation) {
- case QAM_64:
- case QAM_256:
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ unsigned int new_rf = input[priv->nr];
+
+ if ((new_rf == 0) || (new_rf > 2)) {
+ switch (params->u.vsb.modulation) {
+ case QAM_64:
+ case QAM_256:
+ new_rf = 1;
+ break;
+ case VSB_8:
+ default:
+ new_rf = 2;
+ }
+ }
+
+ switch (new_rf) {
+ case 1:
buf[3] |= 0x08;
break;
- case VSB_8:
- default:
+ case 2:
buf[3] &= ~0x08;
+ break;
+ default:
+ printk(KERN_WARNING
+ "%s: unhandled rf input selection: %d",
+ __FUNCTION__, new_rf);
}
}
@@ -420,7 +479,8 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
/*
* Philips TD1316 Tuner.
*/
-static void td1316_bw(u8 *buf, const struct dvb_frontend_parameters *params)
+static void td1316_bw(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
u8 band;
@@ -474,7 +534,8 @@ static struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
}
};
-static void opera1_bw(u8 *buf, const struct dvb_frontend_parameters *params)
+static void opera1_bw(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[2] |= 0x08;
@@ -546,30 +607,13 @@ static struct dvb_pll_desc *pll_list[] = {
};
/* ----------------------------------------------------------- */
-
-struct dvb_pll_priv {
- /* i2c details */
- int pll_i2c_address;
- struct i2c_adapter *i2c;
-
- /* the PLL descriptor */
- struct dvb_pll_desc *pll_desc;
-
- /* cached frequency/bandwidth */
- u32 frequency;
- u32 bandwidth;
-};
-
-/* ----------------------------------------------------------- */
/* code */
-static int debug = 0;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf,
const struct dvb_frontend_parameters *params)
{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ struct dvb_pll_desc *desc = priv->pll_desc;
u32 div;
int i;
@@ -597,7 +641,7 @@ static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
buf[3] = desc->entries[i].cb;
if (desc->set)
- desc->set(buf, params);
+ desc->set(fe, buf, params);
if (debug)
printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
@@ -654,7 +698,7 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
if (priv->i2c == NULL)
return -EINVAL;
- if ((result = dvb_pll_configure(priv->pll_desc, buf, params)) < 0)
+ if ((result = dvb_pll_configure(fe, buf, params)) < 0)
return result;
else
frequency = result;
@@ -682,7 +726,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
if (buf_len < 5)
return -EINVAL;
- if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params)) < 0)
+ if ((result = dvb_pll_configure(fe, buf+1, params)) < 0)
return result;
else
frequency = result;
@@ -755,6 +799,10 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
int ret;
struct dvb_pll_desc *desc;
+ if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) &&
+ (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list)))
+ pll_desc_id = id[dvb_pll_devcount];
+
BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list));
desc = pll_list[pll_desc_id];
@@ -777,6 +825,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
priv->pll_i2c_address = pll_addr;
priv->i2c = i2c;
priv->pll_desc = desc;
+ priv->nr = dvb_pll_devcount++;
memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops,
sizeof(struct dvb_tuner_ops));
@@ -791,6 +840,30 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
fe->ops.tuner_ops.sleep = NULL;
fe->tuner_priv = priv;
+
+ if ((debug) || (id[priv->nr] == pll_desc_id)) {
+ printk("dvb-pll[%d]", priv->nr);
+ if (i2c != NULL)
+ printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
+ printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name,
+ id[priv->nr] == pll_desc_id ?
+ "insmod option" : "autodetected");
+ }
+ if ((debug) || (input[priv->nr] > 0)) {
+ printk("dvb-pll[%d]", priv->nr);
+ if (i2c != NULL)
+ printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
+ printk(": tuner rf input will be ");
+ switch (input[priv->nr]) {
+ case 0:
+ printk("autoselected\n");
+ break;
+ default:
+ printk("set to input %d (insmod option)\n",
+ input[priv->nr]);
+ }
+ }
+
return fe;
}
EXPORT_SYMBOL(dvb_pll_attach);
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c
index 6271b1e7f6a..fed09dfb2b7 100644
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c
@@ -20,7 +20,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>
diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c
index c967148a594..684c8ec166c 100644
--- a/drivers/media/dvb/frontends/isl6421.c
+++ b/drivers/media/dvb/frontends/isl6421.c
@@ -29,7 +29,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 1aeacb1c4af..443d9045d4c 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
#include "dvb_frontend.h"
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index e25286e2d43..bdc9fa88b86 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -35,7 +35,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
index 2d2f58c2622..76f935d9755 100644
--- a/drivers/media/dvb/frontends/lnbp21.c
+++ b/drivers/media/dvb/frontends/lnbp21.c
@@ -28,7 +28,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/dvb/frontends/mt2060.c
index 450fad8d9b6..1305b0e63ce 100644
--- a/drivers/media/dvb/frontends/mt2060.c
+++ b/drivers/media/dvb/frontends/mt2060.c
@@ -22,7 +22,6 @@
/* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/dvb/frontend.h>
#include <linux/i2c.h>
diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c
new file mode 100644
index 00000000000..13cf1666817
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2131.c
@@ -0,0 +1,314 @@
+/*
+ * Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "mt2131.h"
+#include "mt2131_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_INFO "%s: " fmt, "mt2131", ## arg)
+
+static u8 mt2131_config1[] = {
+ 0x01,
+ 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88,
+ 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32,
+ 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80,
+ 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00
+};
+
+static u8 mt2131_config2[] = {
+ 0x10,
+ 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04
+};
+
+static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2] = {
+ { .addr = priv->cfg->i2c_address, .flags = 0,
+ .buf = &reg, .len = 1 },
+ { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
+ .buf = val, .len = 1 },
+ };
+
+ if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ printk(KERN_WARNING "mt2131 I2C read failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val)
+{
+ u8 buf[2] = { reg, val };
+ struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0,
+ .buf = buf, .len = 2 };
+
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "mt2131 I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len)
+{
+ struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+ .flags = 0, .buf = buf, .len = len };
+
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",
+ (int)len);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int mt2131_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct mt2131_priv *priv;
+ int ret=0, i;
+ u32 freq;
+ u8 if_band_center;
+ u32 f_lo1, f_lo2;
+ u32 div1, num1, div2, num2;
+ u8 b[8];
+ u8 lockval = 0;
+
+ priv = fe->tuner_priv;
+ if (fe->ops.info.type == FE_OFDM)
+ priv->bandwidth = params->u.ofdm.bandwidth;
+ else
+ priv->bandwidth = 0;
+
+ freq = params->frequency / 1000; // Hz -> kHz
+ dprintk(1, "%s() freq=%d\n", __FUNCTION__, freq);
+
+ f_lo1 = freq + MT2131_IF1 * 1000;
+ f_lo1 = (f_lo1 / 250) * 250;
+ f_lo2 = f_lo1 - freq - MT2131_IF2;
+
+ priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000;
+
+ /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */
+ num1 = f_lo1 * 64 / (MT2131_FREF / 128);
+ div1 = num1 / 8192;
+ num1 &= 0x1fff;
+
+ /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */
+ num2 = f_lo2 * 64 / (MT2131_FREF / 128);
+ div2 = num2 / 8192;
+ num2 &= 0x1fff;
+
+ if (freq <= 82500) if_band_center = 0x00; else
+ if (freq <= 137500) if_band_center = 0x01; else
+ if (freq <= 192500) if_band_center = 0x02; else
+ if (freq <= 247500) if_band_center = 0x03; else
+ if (freq <= 302500) if_band_center = 0x04; else
+ if (freq <= 357500) if_band_center = 0x05; else
+ if (freq <= 412500) if_band_center = 0x06; else
+ if (freq <= 467500) if_band_center = 0x07; else
+ if (freq <= 522500) if_band_center = 0x08; else
+ if (freq <= 577500) if_band_center = 0x09; else
+ if (freq <= 632500) if_band_center = 0x0A; else
+ if (freq <= 687500) if_band_center = 0x0B; else
+ if (freq <= 742500) if_band_center = 0x0C; else
+ if (freq <= 797500) if_band_center = 0x0D; else
+ if (freq <= 852500) if_band_center = 0x0E; else
+ if (freq <= 907500) if_band_center = 0x0F; else
+ if (freq <= 962500) if_band_center = 0x10; else
+ if (freq <= 1017500) if_band_center = 0x11; else
+ if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13;
+
+ b[0] = 1;
+ b[1] = (num1 >> 5) & 0xFF;
+ b[2] = (num1 & 0x1F);
+ b[3] = div1;
+ b[4] = (num2 >> 5) & 0xFF;
+ b[5] = num2 & 0x1F;
+ b[6] = div2;
+
+ dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2);
+ dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center);
+ dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2);
+ dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n",
+ (int)div1, (int)num1, (int)div2, (int)num2);
+ dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n",
+ (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5],
+ (int)b[6]);
+
+ ret = mt2131_writeregs(priv,b,7);
+ if (ret < 0)
+ return ret;
+
+ mt2131_writereg(priv, 0x0b, if_band_center);
+
+ /* Wait for lock */
+ i = 0;
+ do {
+ mt2131_readreg(priv, 0x08, &lockval);
+ if ((lockval & 0x88) == 0x88)
+ break;
+ msleep(4);
+ i++;
+ } while (i < 10);
+
+ return ret;
+}
+
+static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct mt2131_priv *priv = fe->tuner_priv;
+ dprintk(1, "%s()\n", __FUNCTION__);
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct mt2131_priv *priv = fe->tuner_priv;
+ dprintk(1, "%s()\n", __FUNCTION__);
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+static int mt2131_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct mt2131_priv *priv = fe->tuner_priv;
+ u8 lock_status = 0;
+ u8 afc_status = 0;
+
+ *status = 0;
+
+ mt2131_readreg(priv, 0x08, &lock_status);
+ if ((lock_status & 0x88) == 0x88)
+ *status = TUNER_STATUS_LOCKED;
+
+ mt2131_readreg(priv, 0x09, &afc_status);
+ dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n",
+ __FUNCTION__, lock_status, afc_status);
+
+ return 0;
+}
+
+static int mt2131_init(struct dvb_frontend *fe)
+{
+ struct mt2131_priv *priv = fe->tuner_priv;
+ int ret;
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ if ((ret = mt2131_writeregs(priv, mt2131_config1,
+ sizeof(mt2131_config1))) < 0)
+ return ret;
+
+ mt2131_writereg(priv, 0x0b, 0x09);
+ mt2131_writereg(priv, 0x15, 0x47);
+ mt2131_writereg(priv, 0x07, 0xf2);
+ mt2131_writereg(priv, 0x0b, 0x01);
+
+ if ((ret = mt2131_writeregs(priv, mt2131_config2,
+ sizeof(mt2131_config2))) < 0)
+ return ret;
+
+ return ret;
+}
+
+static int mt2131_release(struct dvb_frontend *fe)
+{
+ dprintk(1, "%s()\n", __FUNCTION__);
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static const struct dvb_tuner_ops mt2131_tuner_ops = {
+ .info = {
+ .name = "Microtune MT2131",
+ .frequency_min = 48000000,
+ .frequency_max = 860000000,
+ .frequency_step = 50000,
+ },
+
+ .release = mt2131_release,
+ .init = mt2131_init,
+
+ .set_params = mt2131_set_params,
+ .get_frequency = mt2131_get_frequency,
+ .get_bandwidth = mt2131_get_bandwidth,
+ .get_status = mt2131_get_status
+};
+
+struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct mt2131_config *cfg, u16 if1)
+{
+ struct mt2131_priv *priv = NULL;
+ u8 id = 0;
+
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->bandwidth = 6000000; /* 6MHz */
+ priv->i2c = i2c;
+
+ if (mt2131_readreg(priv, 0, &id) != 0) {
+ kfree(priv);
+ return NULL;
+ }
+ if ( (id != 0x3E) && (id != 0x3F) ) {
+ printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n",
+ cfg->i2c_address);
+ kfree(priv);
+ return NULL;
+ }
+
+ printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n",
+ cfg->i2c_address);
+ memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = priv;
+ return fe;
+}
+EXPORT_SYMBOL(mt2131_attach);
+
+MODULE_AUTHOR("Steven Toth");
+MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h
new file mode 100644
index 00000000000..1e4ffe7dc8c
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2131.h
@@ -0,0 +1,54 @@
+/*
+ * Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MT2131_H__
+#define __MT2131_H__
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mt2131_config {
+ u8 i2c_address;
+ u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
+};
+
+#if defined(CONFIG_DVB_TUNER_MT2131) || (defined(CONFIG_DVB_TUNER_MT2131_MODULE) && defined(MODULE))
+extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct mt2131_config *cfg,
+ u16 if1);
+#else
+static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ struct mt2131_config *cfg,
+ u16 if1)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_TUNER_MT2131 */
+
+#endif /* __MT2131_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/dvb/frontends/mt2131_priv.h
new file mode 100644
index 00000000000..e930759c2c0
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2131_priv.h
@@ -0,0 +1,49 @@
+/*
+ * Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MT2131_PRIV_H__
+#define __MT2131_PRIV_H__
+
+/* Regs */
+#define MT2131_PWR 0x07
+#define MT2131_UPC_1 0x0b
+#define MT2131_AGC_RL 0x10
+#define MT2131_MISC_2 0x15
+
+/* frequency values in KHz */
+#define MT2131_IF1 1220
+#define MT2131_IF2 44000
+#define MT2131_FREF 16000
+
+struct mt2131_priv {
+ struct mt2131_config *cfg;
+ struct i2c_adapter *i2c;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+#endif /* __MT2131_PRIV_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c
new file mode 100644
index 00000000000..03fe8265745
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2266.c
@@ -0,0 +1,287 @@
+/*
+ * Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
+ *
+ * Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+#include "mt2266.h"
+
+#define I2C_ADDRESS 0x60
+
+#define REG_PART_REV 0
+#define REG_TUNE 1
+#define REG_BAND 6
+#define REG_BANDWIDTH 8
+#define REG_LOCK 0x12
+
+#define PART_REV 0x85
+
+struct mt2266_priv {
+ struct mt2266_config *cfg;
+ struct i2c_adapter *i2c;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0)
+
+// Reads a single register
+static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2] = {
+ { .addr = priv->cfg->i2c_address, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 },
+ };
+ if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ printk(KERN_WARNING "MT2266 I2C read failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+// Writes a single register
+static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val)
+{
+ u8 buf[2] = { reg, val };
+ struct i2c_msg msg = {
+ .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
+ };
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "MT2266 I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+// Writes a set of consecutive registers
+static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
+{
+ struct i2c_msg msg = {
+ .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
+ };
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+// Initialisation sequences
+static u8 mt2266_init1[] = {
+ REG_TUNE,
+ 0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f };
+
+static u8 mt2266_init2[] = {
+ 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a,
+ 0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d };
+
+static u8 mt2266_init_8mhz[] = {
+ REG_BANDWIDTH,
+ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 };
+
+static u8 mt2266_init_7mhz[] = {
+ REG_BANDWIDTH,
+ 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 };
+
+static u8 mt2266_init_6mhz[] = {
+ REG_BANDWIDTH,
+ 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 };
+
+#define FREF 30000 // Quartz oscillator 30 MHz
+
+static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct mt2266_priv *priv;
+ int ret=0;
+ u32 freq;
+ u32 tune;
+ u8 lnaband;
+ u8 b[10];
+ int i;
+
+ priv = fe->tuner_priv;
+
+ mt2266_writereg(priv,0x17,0x6d);
+ mt2266_writereg(priv,0x1c,0xff);
+
+ freq = params->frequency / 1000; // Hz -> kHz
+ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+ priv->frequency = freq * 1000;
+ tune=2 * freq * (8192/16) / (FREF/16);
+
+ if (freq <= 495000) lnaband = 0xEE; else
+ if (freq <= 525000) lnaband = 0xDD; else
+ if (freq <= 550000) lnaband = 0xCC; else
+ if (freq <= 580000) lnaband = 0xBB; else
+ if (freq <= 605000) lnaband = 0xAA; else
+ if (freq <= 630000) lnaband = 0x99; else
+ if (freq <= 655000) lnaband = 0x88; else
+ if (freq <= 685000) lnaband = 0x77; else
+ if (freq <= 710000) lnaband = 0x66; else
+ if (freq <= 735000) lnaband = 0x55; else
+ if (freq <= 765000) lnaband = 0x44; else
+ if (freq <= 802000) lnaband = 0x33; else
+ if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11;
+
+ msleep(100);
+ mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz:
+ (params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz:
+ mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
+
+ b[0] = REG_TUNE;
+ b[1] = (tune >> 8) & 0x1F;
+ b[2] = tune & 0xFF;
+ b[3] = tune >> 13;
+ mt2266_writeregs(priv,b,4);
+
+ dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband);
+ dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]);
+
+ b[0] = 0x05;
+ b[1] = 0x62;
+ b[2] = lnaband;
+ mt2266_writeregs(priv,b,3);
+
+ //Waits for pll lock or timeout
+ i = 0;
+ do {
+ mt2266_readreg(priv,REG_LOCK,b);
+ if ((b[0] & 0x40)==0x40)
+ break;
+ msleep(10);
+ i++;
+ } while (i<10);
+ dprintk("Lock when i=%i",(int)i);
+ return ret;
+}
+
+static void mt2266_calibrate(struct mt2266_priv *priv)
+{
+ mt2266_writereg(priv,0x11,0x03);
+ mt2266_writereg(priv,0x11,0x01);
+
+ mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1));
+ mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2));
+
+ mt2266_writereg(priv,0x33,0x5e);
+ mt2266_writereg(priv,0x10,0x10);
+ mt2266_writereg(priv,0x10,0x00);
+
+ mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
+
+ msleep(25);
+ mt2266_writereg(priv,0x17,0x6d);
+ mt2266_writereg(priv,0x1c,0x00);
+ msleep(75);
+ mt2266_writereg(priv,0x17,0x6d);
+ mt2266_writereg(priv,0x1c,0xff);
+}
+
+static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct mt2266_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct mt2266_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+static int mt2266_init(struct dvb_frontend *fe)
+{
+ struct mt2266_priv *priv = fe->tuner_priv;
+ mt2266_writereg(priv,0x17,0x6d);
+ mt2266_writereg(priv,0x1c,0xff);
+ return 0;
+}
+
+static int mt2266_sleep(struct dvb_frontend *fe)
+{
+ struct mt2266_priv *priv = fe->tuner_priv;
+ mt2266_writereg(priv,0x17,0x6d);
+ mt2266_writereg(priv,0x1c,0x00);
+ return 0;
+}
+
+static int mt2266_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static const struct dvb_tuner_ops mt2266_tuner_ops = {
+ .info = {
+ .name = "Microtune MT2266",
+ .frequency_min = 470000000,
+ .frequency_max = 860000000,
+ .frequency_step = 50000,
+ },
+ .release = mt2266_release,
+ .init = mt2266_init,
+ .sleep = mt2266_sleep,
+ .set_params = mt2266_set_params,
+ .get_frequency = mt2266_get_frequency,
+ .get_bandwidth = mt2266_get_bandwidth
+};
+
+struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
+{
+ struct mt2266_priv *priv = NULL;
+ u8 id = 0;
+
+ priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+
+ if (mt2266_readreg(priv,0,&id) != 0) {
+ kfree(priv);
+ return NULL;
+ }
+ if (id != PART_REV) {
+ kfree(priv);
+ return NULL;
+ }
+ printk(KERN_INFO "MT2266: successfully identified\n");
+ memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = priv;
+ mt2266_calibrate(priv);
+ return fe;
+}
+EXPORT_SYMBOL(mt2266_attach);
+
+MODULE_AUTHOR("Olivier DANET");
+MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/mt2266.h b/drivers/media/dvb/frontends/mt2266.h
new file mode 100644
index 00000000000..f31dd613ad3
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2266.h
@@ -0,0 +1,37 @@
+/*
+ * Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
+ *
+ * Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MT2266_H
+#define MT2266_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mt2266_config {
+ u8 i2c_address;
+};
+
+#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_TUNER_MT2266_MODULE) && defined(MODULE))
+extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg);
+#else
+static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_TUNER_MT2266
+
+#endif
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index 1ef82182564..0606b9a5b61 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -28,7 +28,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index 87e31ca7e10..5dd9b731f6f 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -32,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
index ddc84899cf8..fcf964fe1d6 100644
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -44,7 +44,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index 3cc8b444b8f..b314a1f2dee 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -36,7 +36,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index f46d5a46683..f02bd944595 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -32,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
new file mode 100644
index 00000000000..8dee7ec9456
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -0,0 +1,805 @@
+/*
+ Samsung S5H1409 VSB/QAM demodulator driver
+
+ Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "s5h1409.h"
+
+struct s5h1409_state {
+
+ struct i2c_adapter* i2c;
+
+ /* configuration settings */
+ const struct s5h1409_config* config;
+
+ struct dvb_frontend frontend;
+
+ /* previous uncorrected block counter */
+ fe_modulation_t current_modulation;
+
+ u32 current_frequency;
+
+ u32 is_qam_locked;
+ u32 qam_state;
+};
+
+static int debug = 0;
+#define dprintk if (debug) printk
+
+/* Register values to initialise the demod, this will set VSB by default */
+static struct init_tab {
+ u8 reg;
+ u16 data;
+} init_tab[] = {
+ { 0x00, 0x0071, },
+ { 0x01, 0x3213, },
+ { 0x09, 0x0025, },
+ { 0x1c, 0x001d, },
+ { 0x1f, 0x002d, },
+ { 0x20, 0x001d, },
+ { 0x22, 0x0022, },
+ { 0x23, 0x0020, },
+ { 0x29, 0x110f, },
+ { 0x2a, 0x10b4, },
+ { 0x2b, 0x10ae, },
+ { 0x2c, 0x0031, },
+ { 0x31, 0x010d, },
+ { 0x32, 0x0100, },
+ { 0x44, 0x0510, },
+ { 0x54, 0x0104, },
+ { 0x58, 0x2222, },
+ { 0x59, 0x1162, },
+ { 0x5a, 0x3211, },
+ { 0x5d, 0x0370, },
+ { 0x5e, 0x0296, },
+ { 0x61, 0x0010, },
+ { 0x63, 0x4a00, },
+ { 0x65, 0x0800, },
+ { 0x71, 0x0003, },
+ { 0x72, 0x0470, },
+ { 0x81, 0x0002, },
+ { 0x82, 0x0600, },
+ { 0x86, 0x0002, },
+ { 0x8a, 0x2c38, },
+ { 0x8b, 0x2a37, },
+ { 0x92, 0x302f, },
+ { 0x93, 0x3332, },
+ { 0x96, 0x000c, },
+ { 0x99, 0x0101, },
+ { 0x9c, 0x2e37, },
+ { 0x9d, 0x2c37, },
+ { 0x9e, 0x2c37, },
+ { 0xab, 0x0100, },
+ { 0xac, 0x1003, },
+ { 0xad, 0x103f, },
+ { 0xe2, 0x0100, },
+ { 0xe3, 0x0000, },
+ { 0x28, 0x1010, },
+ { 0xb1, 0x000e, },
+};
+
+/* VSB SNR lookup table */
+static struct vsb_snr_tab {
+ u16 val;
+ u16 data;
+} vsb_snr_tab[] = {
+ { 1023, 770, },
+ { 923, 300, },
+ { 918, 295, },
+ { 915, 290, },
+ { 911, 285, },
+ { 906, 280, },
+ { 901, 275, },
+ { 896, 270, },
+ { 891, 265, },
+ { 885, 260, },
+ { 879, 255, },
+ { 873, 250, },
+ { 864, 245, },
+ { 858, 240, },
+ { 850, 235, },
+ { 841, 230, },
+ { 832, 225, },
+ { 823, 220, },
+ { 812, 215, },
+ { 802, 210, },
+ { 788, 205, },
+ { 778, 200, },
+ { 767, 195, },
+ { 753, 190, },
+ { 740, 185, },
+ { 725, 180, },
+ { 707, 175, },
+ { 689, 170, },
+ { 671, 165, },
+ { 656, 160, },
+ { 637, 155, },
+ { 616, 150, },
+ { 542, 145, },
+ { 519, 140, },
+ { 507, 135, },
+ { 497, 130, },
+ { 492, 125, },
+ { 474, 120, },
+ { 300, 111, },
+ { 0, 0, },
+};
+
+/* QAM64 SNR lookup table */
+static struct qam64_snr_tab {
+ u16 val;
+ u16 data;
+} qam64_snr_tab[] = {
+ { 12, 300, },
+ { 15, 290, },
+ { 18, 280, },
+ { 22, 270, },
+ { 23, 268, },
+ { 24, 266, },
+ { 25, 264, },
+ { 27, 262, },
+ { 28, 260, },
+ { 29, 258, },
+ { 30, 256, },
+ { 32, 254, },
+ { 33, 252, },
+ { 34, 250, },
+ { 35, 249, },
+ { 36, 248, },
+ { 37, 247, },
+ { 38, 246, },
+ { 39, 245, },
+ { 40, 244, },
+ { 41, 243, },
+ { 42, 241, },
+ { 43, 240, },
+ { 44, 239, },
+ { 45, 238, },
+ { 46, 237, },
+ { 47, 236, },
+ { 48, 235, },
+ { 49, 234, },
+ { 50, 233, },
+ { 51, 232, },
+ { 52, 231, },
+ { 53, 230, },
+ { 55, 229, },
+ { 56, 228, },
+ { 57, 227, },
+ { 58, 226, },
+ { 59, 225, },
+ { 60, 224, },
+ { 62, 223, },
+ { 63, 222, },
+ { 65, 221, },
+ { 66, 220, },
+ { 68, 219, },
+ { 69, 218, },
+ { 70, 217, },
+ { 72, 216, },
+ { 73, 215, },
+ { 75, 214, },
+ { 76, 213, },
+ { 78, 212, },
+ { 80, 211, },
+ { 81, 210, },
+ { 83, 209, },
+ { 84, 208, },
+ { 85, 207, },
+ { 87, 206, },
+ { 89, 205, },
+ { 91, 204, },
+ { 93, 203, },
+ { 95, 202, },
+ { 96, 201, },
+ { 104, 200, },
+};
+
+/* QAM256 SNR lookup table */
+static struct qam256_snr_tab {
+ u16 val;
+ u16 data;
+} qam256_snr_tab[] = {
+ { 12, 400, },
+ { 13, 390, },
+ { 15, 380, },
+ { 17, 360, },
+ { 19, 350, },
+ { 22, 348, },
+ { 23, 346, },
+ { 24, 344, },
+ { 25, 342, },
+ { 26, 340, },
+ { 27, 336, },
+ { 28, 334, },
+ { 29, 332, },
+ { 30, 330, },
+ { 31, 328, },
+ { 32, 326, },
+ { 33, 325, },
+ { 34, 322, },
+ { 35, 320, },
+ { 37, 318, },
+ { 39, 316, },
+ { 40, 314, },
+ { 41, 312, },
+ { 42, 310, },
+ { 43, 308, },
+ { 46, 306, },
+ { 47, 304, },
+ { 49, 302, },
+ { 51, 300, },
+ { 53, 298, },
+ { 54, 297, },
+ { 55, 296, },
+ { 56, 295, },
+ { 57, 294, },
+ { 59, 293, },
+ { 60, 292, },
+ { 61, 291, },
+ { 63, 290, },
+ { 64, 289, },
+ { 65, 288, },
+ { 66, 287, },
+ { 68, 286, },
+ { 69, 285, },
+ { 71, 284, },
+ { 72, 283, },
+ { 74, 282, },
+ { 75, 281, },
+ { 76, 280, },
+ { 77, 279, },
+ { 78, 278, },
+ { 81, 277, },
+ { 83, 276, },
+ { 84, 275, },
+ { 86, 274, },
+ { 87, 273, },
+ { 89, 272, },
+ { 90, 271, },
+ { 92, 270, },
+ { 93, 269, },
+ { 95, 268, },
+ { 96, 267, },
+ { 98, 266, },
+ { 100, 265, },
+ { 102, 264, },
+ { 104, 263, },
+ { 105, 262, },
+ { 106, 261, },
+ { 110, 260, },
+};
+
+/* 8 bit registers, 16 bit values */
+static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data)
+{
+ int ret;
+ u8 buf [] = { reg, data >> 8, data & 0xff };
+
+ struct i2c_msg msg = { .addr = state->config->demod_address,
+ .flags = 0, .buf = buf, .len = 3 };
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1)
+ printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+ "ret == %i)\n", __FUNCTION__, reg, data, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg)
+{
+ int ret;
+ u8 b0 [] = { reg };
+ u8 b1 [] = { 0, 0 };
+
+ struct i2c_msg msg [] = {
+ { .addr = state->config->demod_address, .flags = 0,
+ .buf = b0, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD,
+ .buf = b1, .len = 2 } };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2)
+ printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+ return (b1[0] << 8) | b1[1];
+}
+
+static int s5h1409_softreset(struct dvb_frontend* fe)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s()\n", __FUNCTION__);
+
+ s5h1409_writereg(state, 0xf5, 0);
+ s5h1409_writereg(state, 0xf5, 1);
+ state->is_qam_locked = 0;
+ state->qam_state = 0;
+ return 0;
+}
+
+static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+ int ret = 0;
+
+ dprintk("%s(%d KHz)\n", __FUNCTION__, KHz);
+
+ if( (KHz == 44000) || (KHz == 5380) ) {
+ s5h1409_writereg(state, 0x87, 0x01be);
+ s5h1409_writereg(state, 0x88, 0x0436);
+ s5h1409_writereg(state, 0x89, 0x054d);
+ } else
+ if (KHz == 4000) {
+ s5h1409_writereg(state, 0x87, 0x014b);
+ s5h1409_writereg(state, 0x88, 0x0cb5);
+ s5h1409_writereg(state, 0x89, 0x03e2);
+ } else {
+ printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s(%d)\n", __FUNCTION__, inverted);
+
+ if(inverted == 1)
+ return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
+ else
+ return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */
+}
+
+static int s5h1409_enable_modulation(struct dvb_frontend* fe,
+ fe_modulation_t m)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s(0x%08x)\n", __FUNCTION__, m);
+
+ switch(m) {
+ case VSB_8:
+ dprintk("%s() VSB_8\n", __FUNCTION__);
+ s5h1409_writereg(state, 0xf4, 0);
+ break;
+ case QAM_64:
+ case QAM_256:
+ dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__);
+ s5h1409_writereg(state, 0xf4, 1);
+ s5h1409_writereg(state, 0x85, 0x110);
+ break;
+ default:
+ dprintk("%s() Invalid modulation\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ state->current_modulation = m;
+ s5h1409_softreset(fe);
+
+ return 0;
+}
+
+static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s(%d)\n", __FUNCTION__, enable);
+
+ if (enable)
+ return s5h1409_writereg(state, 0xf3, 1);
+ else
+ return s5h1409_writereg(state, 0xf3, 0);
+}
+
+static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s(%d)\n", __FUNCTION__, enable);
+
+ if (enable)
+ return s5h1409_writereg(state, 0xe3, 0x1100);
+ else
+ return s5h1409_writereg(state, 0xe3, 0x1000);
+}
+
+static int s5h1409_sleep(struct dvb_frontend* fe, int enable)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s(%d)\n", __FUNCTION__, enable);
+
+ return s5h1409_writereg(state, 0xf2, enable);
+}
+
+static int s5h1409_register_reset(struct dvb_frontend* fe)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s()\n", __FUNCTION__);
+
+ return s5h1409_writereg(state, 0xfa, 0);
+}
+
+static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe)
+{
+ struct s5h1409_state *state = fe->demodulator_priv;
+ u16 reg;
+
+ if (state->is_qam_locked)
+ return;
+
+ /* QAM EQ lock check */
+ reg = s5h1409_readreg(state, 0xf0);
+
+ if ((reg >> 13) & 0x1) {
+
+ state->is_qam_locked = 1;
+ reg &= 0xff;
+
+ s5h1409_writereg(state, 0x96, 0x00c);
+ if ((reg < 0x38) || (reg > 0x68) ) {
+ s5h1409_writereg(state, 0x93, 0x3332);
+ s5h1409_writereg(state, 0x9e, 0x2c37);
+ } else {
+ s5h1409_writereg(state, 0x93, 0x3130);
+ s5h1409_writereg(state, 0x9e, 0x2836);
+ }
+
+ } else {
+ s5h1409_writereg(state, 0x96, 0x0008);
+ s5h1409_writereg(state, 0x93, 0x3332);
+ s5h1409_writereg(state, 0x9e, 0x2c37);
+ }
+}
+
+static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
+{
+ struct s5h1409_state *state = fe->demodulator_priv;
+ u16 reg, reg1, reg2;
+
+ reg = s5h1409_readreg(state, 0xf1);
+
+ /* Master lock */
+ if ((reg >> 15) & 0x1) {
+ if (state->qam_state != 2) {
+ state->qam_state = 2;
+ reg1 = s5h1409_readreg(state, 0xb2);
+ reg2 = s5h1409_readreg(state, 0xad);
+
+ s5h1409_writereg(state, 0x96, 0x20);
+ s5h1409_writereg(state, 0xad,
+ ( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) );
+ s5h1409_writereg(state, 0xab, 0x1100);
+ }
+ } else {
+ if (state->qam_state != 1) {
+ state->qam_state = 1;
+ s5h1409_writereg(state, 0x96, 0x08);
+ s5h1409_writereg(state, 0xab, 0x1101);
+ }
+ }
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int s5h1409_set_frontend (struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ dprintk("%s(frequency=%d)\n", __FUNCTION__, p->frequency);
+
+ s5h1409_softreset(fe);
+
+ state->current_frequency = p->frequency;
+
+ s5h1409_enable_modulation(fe, p->u.vsb.modulation);
+
+ /* Allow the demod to settle */
+ msleep(100);
+
+ if (fe->ops.tuner_ops.set_params) {
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ /* Optimize the demod for QAM */
+ if (p->u.vsb.modulation != VSB_8) {
+ s5h1409_set_qam_amhum_mode(fe);
+ s5h1409_set_qam_interleave_mode(fe);
+ }
+
+ return 0;
+}
+
+/* Reset the demod hardware and reset all of the configuration registers
+ to a default state. */
+static int s5h1409_init (struct dvb_frontend* fe)
+{
+ int i;
+
+ struct s5h1409_state* state = fe->demodulator_priv;
+ dprintk("%s()\n", __FUNCTION__);
+
+ s5h1409_sleep(fe, 0);
+ s5h1409_register_reset(fe);
+
+ for (i=0; i < ARRAY_SIZE(init_tab); i++)
+ s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data);
+
+ /* The datasheet says that after initialisation, VSB is default */
+ state->current_modulation = VSB_8;
+
+ if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
+ s5h1409_writereg(state, 0xab, 0x100); /* Serial */
+ else
+ s5h1409_writereg(state, 0xab, 0x0); /* Parallel */
+
+ s5h1409_set_spectralinversion(fe, state->config->inversion);
+ s5h1409_set_if_freq(fe, state->config->if_freq);
+ s5h1409_set_gpio(fe, state->config->gpio);
+ s5h1409_softreset(fe);
+
+ /* Note: Leaving the I2C gate closed. */
+ s5h1409_i2c_gate_ctrl(fe, 0);
+
+ return 0;
+}
+
+static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+ u16 reg;
+ u32 tuner_status = 0;
+
+ *status = 0;
+
+ /* Get the demodulator status */
+ reg = s5h1409_readreg(state, 0xf1);
+ if(reg & 0x1000)
+ *status |= FE_HAS_VITERBI;
+ if(reg & 0x8000)
+ *status |= FE_HAS_LOCK | FE_HAS_SYNC;
+
+ switch(state->config->status_mode) {
+ case S5H1409_DEMODLOCKING:
+ if (*status & FE_HAS_VITERBI)
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ break;
+ case S5H1409_TUNERLOCKING:
+ /* Get the tuner status */
+ if (fe->ops.tuner_ops.get_status) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ fe->ops.tuner_ops.get_status(fe, &tuner_status);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (tuner_status)
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ break;
+ }
+
+ dprintk("%s() status 0x%08x\n", __FUNCTION__, *status);
+
+ return 0;
+}
+
+static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+{
+ int i, ret = -EINVAL;
+ dprintk("%s()\n", __FUNCTION__);
+
+ for (i=0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
+ if (v < qam256_snr_tab[i].val) {
+ *snr = qam256_snr_tab[i].data;
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+{
+ int i, ret = -EINVAL;
+ dprintk("%s()\n", __FUNCTION__);
+
+ for (i=0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
+ if (v < qam64_snr_tab[i].val) {
+ *snr = qam64_snr_tab[i].data;
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+{
+ int i, ret = -EINVAL;
+ dprintk("%s()\n", __FUNCTION__);
+
+ for (i=0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
+ if (v > vsb_snr_tab[i].val) {
+ *snr = vsb_snr_tab[i].data;
+ ret = 0;
+ break;
+ }
+ }
+ dprintk("%s() snr=%d\n", __FUNCTION__, *snr);
+ return ret;
+}
+
+static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+ u16 reg;
+ dprintk("%s()\n", __FUNCTION__);
+
+ reg = s5h1409_readreg(state, 0xf1) & 0x1ff;
+
+ switch(state->current_modulation) {
+ case QAM_64:
+ return s5h1409_qam64_lookup_snr(fe, snr, reg);
+ case QAM_256:
+ return s5h1409_qam256_lookup_snr(fe, snr, reg);
+ case VSB_8:
+ return s5h1409_vsb_lookup_snr(fe, snr, reg);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int s5h1409_read_signal_strength(struct dvb_frontend* fe,
+ u16* signal_strength)
+{
+ return s5h1409_read_snr(fe, signal_strength);
+}
+
+static int s5h1409_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ *ucblocks = s5h1409_readreg(state, 0xb5);
+
+ return 0;
+}
+
+static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ return s5h1409_read_ucblocks(fe, ber);
+}
+
+static int s5h1409_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+
+ p->frequency = state->current_frequency;
+ p->u.vsb.modulation = state->current_modulation;
+
+ return 0;
+}
+
+static int s5h1409_get_tune_settings(struct dvb_frontend* fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 1000;
+ return 0;
+}
+
+static void s5h1409_release(struct dvb_frontend* fe)
+{
+ struct s5h1409_state* state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1409_ops;
+
+struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct s5h1409_state* state = NULL;
+
+ /* allocate memory for the internal state */
+ state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ state->current_modulation = 0;
+
+ /* check if the demod exists */
+ if (s5h1409_readreg(state, 0x04) != 0x0066)
+ goto error;
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &s5h1409_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ /* Note: Leaving the I2C gate open here. */
+ s5h1409_writereg(state, 0xf3, 1);
+
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops s5h1409_ops = {
+
+ .info = {
+ .name = "Samsung S5H1409 QAM/8VSB Frontend",
+ .type = FE_ATSC,
+ .frequency_min = 54000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 62500,
+ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+
+ .init = s5h1409_init,
+ .i2c_gate_ctrl = s5h1409_i2c_gate_ctrl,
+ .set_frontend = s5h1409_set_frontend,
+ .get_frontend = s5h1409_get_frontend,
+ .get_tune_settings = s5h1409_get_tune_settings,
+ .read_status = s5h1409_read_status,
+ .read_ber = s5h1409_read_ber,
+ .read_signal_strength = s5h1409_read_signal_strength,
+ .read_snr = s5h1409_read_snr,
+ .read_ucblocks = s5h1409_read_ucblocks,
+ .release = s5h1409_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(s5h1409_attach);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
new file mode 100644
index 00000000000..20f9af1af44
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1409.h
@@ -0,0 +1,73 @@
+/*
+ Samsung S5H1409 VSB/QAM demodulator driver
+
+ Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __S5H1409_H__
+#define __S5H1409_H__
+
+#include <linux/dvb/frontend.h>
+
+struct s5h1409_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* serial/parallel output */
+#define S5H1409_PARALLEL_OUTPUT 0
+#define S5H1409_SERIAL_OUTPUT 1
+ u8 output_mode;
+
+ /* GPIO Setting */
+#define S5H1409_GPIO_OFF 0
+#define S5H1409_GPIO_ON 1
+ u8 gpio;
+
+ /* IF Freq in KHz */
+ u16 if_freq;
+
+ /* Spectral Inversion */
+#define S5H1409_INVERSION_OFF 0
+#define S5H1409_INVERSION_ON 1
+ u8 inversion;
+
+ /* Return lock status based on tuner lock, or demod lock */
+#define S5H1409_TUNERLOCKING 0
+#define S5H1409_DEMODLOCKING 1
+ u8 status_mode;
+};
+
+#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE))
+extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+ struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_S5H1409 */
+
+#endif /* __S5H1409_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index d98fd5c2e13..da876f7bfe3 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -29,7 +29,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/delay.h>
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index 5c2f8f4e0ae..1aa2539f509 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -12,7 +12,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index 9a343972ff5..7c23775f77d 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -358,11 +358,23 @@ static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber)
static int stv0297_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
{
struct stv0297_state *state = fe->demodulator_priv;
- u8 STRENGTH[2];
-
- stv0297_readregs(state, 0x41, STRENGTH, 2);
- *strength = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0];
-
+ u8 STRENGTH[3];
+ u16 tmp;
+
+ stv0297_readregs(state, 0x41, STRENGTH, 3);
+ tmp = (STRENGTH[1] & 0x03) << 8 | STRENGTH[0];
+ if (STRENGTH[2] & 0x20) {
+ if (tmp < 0x200)
+ tmp = 0;
+ else
+ tmp = tmp - 0x200;
+ } else {
+ if (tmp > 0x1ff)
+ tmp = 0;
+ else
+ tmp = 0x1ff - tmp;
+ }
+ *strength = (tmp << 7) | (tmp >> 2);
return 0;
}
@@ -680,8 +692,8 @@ static struct dvb_frontend_ops stv0297_ops = {
.info = {
.name = "ST STV0297 DVB-C",
.type = FE_QAM,
- .frequency_min = 64000000,
- .frequency_max = 1300000000,
+ .frequency_min = 47000000,
+ .frequency_max = 862000000,
.frequency_stepsize = 62500,
.symbol_rate_min = 870000,
.symbol_rate_max = 11700000,
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 6c607302c1b..035dd7ba651 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -45,7 +45,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index e725f612a6b..45137d2ebfb 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -301,6 +301,8 @@ static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber)
u32 _ber = tda10021_readreg(state, 0x14) |
(tda10021_readreg(state, 0x15) << 8) |
((tda10021_readreg(state, 0x16) & 0x0f) << 16);
+ _tda10021_writereg(state, 0x10, (tda10021_readreg(state, 0x10) & ~0xc0)
+ | (tda10021_inittab[0x10] & 0xc0));
*ber = 10 * _ber;
return 0;
@@ -310,7 +312,11 @@ static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength)
{
struct tda10021_state* state = fe->demodulator_priv;
+ u8 config = tda10021_readreg(state, 0x02);
u8 gain = tda10021_readreg(state, 0x17);
+ if (config & 0x02)
+ /* the agc value is inverted */
+ gain = ~gain;
*strength = (gain << 8) | gain;
return 0;
@@ -439,8 +445,8 @@ static struct dvb_frontend_ops tda10021_ops = {
.name = "Philips TDA10021 DVB-C",
.type = FE_QAM,
.frequency_stepsize = 62500,
- .frequency_min = 51000000,
- .frequency_max = 858000000,
+ .frequency_min = 47000000,
+ .frequency_max = 862000000,
.symbol_rate_min = (XIN/2)/64, /* SACLK/64 == (XIN/2)/64 */
.symbol_rate_max = (XIN/2)/4, /* SACLK/4 */
#if 0
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
index 4bb06f97938..364bc01971a 100644
--- a/drivers/media/dvb/frontends/tda10023.c
+++ b/drivers/media/dvb/frontends/tda10023.c
@@ -215,12 +215,6 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
s16 SFIL=0;
u16 NDEC = 0;
- if (sr > (SYSCLK/(2*4)))
- sr=SYSCLK/(2*4);
-
- if (sr<870000)
- sr=870000;
-
if (sr < (u32)(SYSCLK/98.40)) {
NDEC=3;
SFIL=1;
@@ -506,8 +500,8 @@ static struct dvb_frontend_ops tda10023_ops = {
.name = "Philips TDA10023 DVB-C",
.type = FE_QAM,
.frequency_stepsize = 62500,
- .frequency_min = 51000000,
- .frequency_max = 858000000,
+ .frequency_min = 47000000,
+ .frequency_max = 862000000,
.symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */
.symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */
.caps = 0x400 | //FE_CAN_QAM_4
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 33a84372c9e..8415a8a5247 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -31,7 +31,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/jiffies.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c
index 0f2d4b41556..9a8ddc537f8 100644
--- a/drivers/media/dvb/frontends/tda10086.c
+++ b/drivers/media/dvb/frontends/tda10086.c
@@ -22,7 +22,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/jiffies.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
index 67415c9db6f..011b74f798a 100644
--- a/drivers/media/dvb/frontends/tda8083.c
+++ b/drivers/media/dvb/frontends/tda8083.c
@@ -27,7 +27,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
@@ -443,12 +442,12 @@ static struct dvb_frontend_ops tda8083_ops = {
.info = {
.name = "Philips TDA8083 DVB-S",
.type = FE_QPSK,
- .frequency_min = 950000, /* FIXME: guessed! */
- .frequency_max = 1400000, /* FIXME: guessed! */
+ .frequency_min = 920000, /* TDA8060 */
+ .frequency_max = 2200000, /* TDA8060 */
.frequency_stepsize = 125, /* kHz for QPSK frontends */
/* .frequency_tolerance = ???,*/
- .symbol_rate_min = 1000000, /* FIXME: guessed! */
- .symbol_rate_max = 45000000, /* FIXME: guessed! */
+ .symbol_rate_min = 12000000,
+ .symbol_rate_max = 30000000,
/* .symbol_rate_tolerance = ???,*/
.caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
index 9b57576bfeb..60433b5011f 100644
--- a/drivers/media/dvb/frontends/ves1820.c
+++ b/drivers/media/dvb/frontends/ves1820.c
@@ -47,7 +47,7 @@ struct ves1820_state {
static int verbose;
static u8 ves1820_inittab[] = {
- 0x69, 0x6A, 0x93, 0x12, 0x12, 0x46, 0x26, 0x1A,
+ 0x69, 0x6A, 0x93, 0x1A, 0x12, 0x46, 0x26, 0x1A,
0x43, 0x6A, 0xAA, 0xAA, 0x1E, 0x85, 0x43, 0x20,
0xE0, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
@@ -410,8 +410,8 @@ static struct dvb_frontend_ops ves1820_ops = {
.name = "VLSI VES1820 DVB-C",
.type = FE_QAM,
.frequency_stepsize = 62500,
- .frequency_min = 51000000,
- .frequency_max = 858000000,
+ .frequency_min = 47000000,
+ .frequency_max = 862000000,
.caps = FE_CAN_QAM_16 |
FE_CAN_QAM_32 |
FE_CAN_QAM_64 |
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index 245f9b7dddf..a97a7fd2c89 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -21,7 +21,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/string.h>
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 6d53289b327..54b91f26ca6 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -84,7 +84,7 @@ config DVB_BUDGET
config DVB_BUDGET_CI
tristate "Budget cards with onboard CI connector"
- depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
+ depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 && INPUT
select VIDEO_SAA7146
select DVB_STV0297 if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 8178832d14a..8b8144f77a7 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -40,7 +40,6 @@
#include <linux/smp_lock.h>
#include <linux/kernel.h>
-#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
@@ -1543,7 +1542,7 @@ static int get_firmware(struct av7110* av7110)
}
/* check if the firmware is available */
- av7110->bin_fw = (unsigned char *) vmalloc(fw->size);
+ av7110->bin_fw = vmalloc(fw->size);
if (NULL == av7110->bin_fw) {
dprintk(1, "out of memory\n");
release_firmware(fw);
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 515e8232e02..a468aa2e485 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -978,24 +978,24 @@ static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 ble
static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
{
- int i;
- int length = last - first + 1;
+ int i;
+ int length = last - first + 1;
- if (length * 4 > DATA_BUFF3_SIZE)
- return -EINVAL;
+ if (length * 4 > DATA_BUFF3_SIZE)
+ return -EINVAL;
- for (i = 0; i < length; i++) {
- u32 color, blend, yuv;
+ for (i = 0; i < length; i++) {
+ u32 color, blend, yuv;
- if (get_user(color, colors + i))
- return -EFAULT;
- blend = (color & 0xF0000000) >> 4;
- yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
+ if (get_user(color, colors + i))
+ return -EFAULT;
+ blend = (color & 0xF0000000) >> 4;
+ yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
(color >> 16) & 0xFF) | blend : 0;
- yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
- wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
- }
- return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
+ yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
+ wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
+ }
+ return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
av7110->osdwin,
bpp2pal[av7110->osdbpp[av7110->osdwin]],
first, last);
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index 6322800ee12..a283e1de83f 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -25,10 +25,9 @@
#include <linux/types.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
#include "av7110.h"
#include "av7110_hw.h"
@@ -280,7 +279,7 @@ static int av7110_ir_write_proc(struct file *file, const char __user *buffer,
if (count < size)
return -EINVAL;
- page = (char *) vmalloc(size);
+ page = vmalloc(size);
if (!page)
return -ENOMEM;
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index 87afaebc070..76cca003252 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -129,23 +129,25 @@ static struct v4l2_input inputs[4] = {
static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
{
+ struct av7110 *av7110 = dev->ext_priv;
u8 buf[] = { 0x00, reg, data };
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
dprintk(4, "dev: %p\n", dev);
- if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
+ if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
return -1;
return 0;
}
static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
{
+ struct av7110 *av7110 = dev->ext_priv;
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
dprintk(4, "dev: %p\n", dev);
- if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
+ if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
return -1;
return 0;
}
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 0aee7a13a07..3439c9864f6 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -1232,7 +1232,7 @@ static struct saa7146_ext_vv vv_data = {
.capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113
.flags = 0,
.stds = &standard[0],
- .num_stds = sizeof(standard) / sizeof(struct saa7146_standard),
+ .num_stds = ARRAY_SIZE(standard),
.ioctls = &ioctls[0],
.ioctl = av_ioctl,
};
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 873c3ba296f..509349211d4 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -214,7 +214,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
case 0x100f:
case 0x1011:
case 0x1012:
- case 0x1017:
/* The hauppauge keymap is a superset of these remotes */
ir_input_init(input_dev, &budget_ci->ir.state,
IR_TYPE_RC5, ir_codes_hauppauge_new);
@@ -225,6 +224,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
budget_ci->ir.rc5_device = rc5_device;
break;
case 0x1010:
+ case 0x1017:
/* for the Technotrend 1500 bundled remote */
ir_input_init(input_dev, &budget_ci->ir.state,
IR_TYPE_RC5, ir_codes_tt_1500);
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index b611f2b1f8b..0252081f013 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -34,7 +34,6 @@
* the project's page is at http://www.linuxtv.org/dvb/
*/
-#include <linux/moduleparam.h>
#include "budget.h"
#include "ttpci-eeprom.h"
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index b60cdc93d6d..7902ae1d9a1 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -13,7 +13,6 @@
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/usb.h>
#include <linux/delay.h>
#include <linux/time.h>
@@ -129,7 +128,7 @@ struct ttusb {
struct dvb_frontend* fe;
};
-/* ugly workaround ... don't know why it's neccessary to read */
+/* ugly workaround ... don't know why it's necessary to read */
/* all result codes. */
#define DEBUG 0
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 78c98b08997..1ec981d98b9 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -22,7 +22,6 @@
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -1199,7 +1198,7 @@ static int ttusb_init_rc( struct ttusb_dec *dec)
input_dev->name = "ttusb_dec remote control";
input_dev->phys = dec->rc_phys;
- input_dev->evbit[0] = BIT(EV_KEY);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY);
input_dev->keycodesize = sizeof(u16);
input_dev->keycodemax = 0x1a;
input_dev->keycode = rc_keys;
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index f8bf9fe37d3..11e962f1a97 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -111,11 +111,16 @@ config RADIO_AZTECH_PORT
jumper sets the card to 0x358.
config RADIO_GEMTEK
- tristate "GemTek Radio Card support"
+ tristate "GemTek Radio card (or compatible) support"
depends on ISA && VIDEO_V4L2
---help---
Choose Y here if you have this FM radio card, and then fill in the
- port address below.
+ I/O port address and settings below. The following cards either have
+ GemTek Radio tuner or are rebranded GemTek Radio cards:
+
+ - Sound Vision 16 Gold with FM Radio
+ - Typhoon Radio card (some models)
+ - Hama Radio card
In order to control your radio card, you will need to use programs
that are compatible with the Video For Linux API. Information on
@@ -126,14 +131,25 @@ config RADIO_GEMTEK
module will be called radio-gemtek.
config RADIO_GEMTEK_PORT
- hex "GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)"
+ hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)"
depends on RADIO_GEMTEK=y
default "34c"
help
Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is
0x34c, if you haven't changed the jumper setting on the card. On
Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O
- port is 0x28c.
+ port is 0x20c, 0x248 or 0x28c.
+ If automatic I/O port probing is enabled this port will be used only
+ in case of automatic probing failure, ie. as a fallback.
+
+config RADIO_GEMTEK_PROBE
+ bool "Automatic I/O port probing"
+ depends on RADIO_GEMTEK=y
+ default y
+ help
+ Say Y here to enable automatic probing for GemTek Radio card. The
+ following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and
+ 0x28c.
config RADIO_GEMTEK_PCI
tristate "GemTek PCI Radio Card support"
diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c
index c7c9d1dc069..3ae56fef8c9 100644
--- a/drivers/media/radio/miropcm20-radio.c
+++ b/drivers/media/radio/miropcm20-radio.c
@@ -229,7 +229,6 @@ static struct video_device pcm20_radio = {
.owner = THIS_MODULE,
.name = "Miro PCM 20 radio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_RTRACK,
.fops = &pcm20_fops,
.priv = &pcm20_unit
};
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index eab8c80a2e4..5e4b9ddb23c 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -26,143 +26,383 @@
#include <media/v4l2-common.h>
#include <linux/spinlock.h>
-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,0,3)
+#define RADIO_BANNER "GemTek Radio card driver: v0.0.3"
-static struct v4l2_queryctrl radio_qctrl[] = {
- {
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .default_value = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535,
- .default_value = 0xff,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }
-};
+/*
+ * Module info.
+ */
+
+MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>");
+MODULE_DESCRIPTION("A driver for the GemTek Radio card.");
+MODULE_LICENSE("GPL");
+
+/*
+ * Module params.
+ */
#ifndef CONFIG_RADIO_GEMTEK_PORT
#define CONFIG_RADIO_GEMTEK_PORT -1
#endif
+#ifndef CONFIG_RADIO_GEMTEK_PROBE
+#define CONFIG_RADIO_GEMTEK_PROBE 1
+#endif
-static int io = CONFIG_RADIO_GEMTEK_PORT;
-static int radio_nr = -1;
-static spinlock_t lock;
+static int io = CONFIG_RADIO_GEMTEK_PORT;
+static int probe = CONFIG_RADIO_GEMTEK_PROBE;
+static int hardmute;
+static int shutdown = 1;
+static int keepmuted = 1;
+static int initmute = 1;
+static int radio_nr = -1;
-struct gemtek_device
-{
- int port;
- unsigned long curfreq;
+module_param(io, int, 0444);
+MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic"
+ "probing is disabled or fails. The most common I/O ports are: 0x20c "
+ "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
+ " work for the combined sound/radiocard).");
+
+module_param(probe, bool, 0444);
+MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most "
+ "common I/O ports used by the card are probed.");
+
+module_param(hardmute, bool, 0644);
+MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may "
+ "reduce static noise.");
+
+module_param(shutdown, bool, 0644);
+MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when "
+ "module is unloaded.");
+
+module_param(keepmuted, bool, 0644);
+MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed.");
+
+module_param(initmute, bool, 0444);
+MODULE_PARM_DESC(initmute, "Mute card when module is loaded.");
+
+module_param(radio_nr, int, 0444);
+
+/*
+ * Functions for controlling the card.
+ */
+#define GEMTEK_LOWFREQ (87*16000)
+#define GEMTEK_HIGHFREQ (108*16000)
+
+/*
+ * Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal
+ * value 10.7 MHz), reference divisor 6.39 kHz (nominal 6.25 kHz).
+ */
+#define FSCALE 8
+#define IF_OFFSET ((unsigned int)(10.52 * 16000 * (1<<FSCALE)))
+#define REF_FREQ ((unsigned int)(6.39 * 16 * (1<<FSCALE)))
+
+#define GEMTEK_CK 0x01 /* Clock signal */
+#define GEMTEK_DA 0x02 /* Serial data */
+#define GEMTEK_CE 0x04 /* Chip enable */
+#define GEMTEK_NS 0x08 /* No signal */
+#define GEMTEK_MT 0x10 /* Line mute */
+#define GEMTEK_STDF_3_125_KHZ 0x01 /* Standard frequency 3.125 kHz */
+#define GEMTEK_PLL_OFF 0x07 /* PLL off */
+
+#define BU2614_BUS_SIZE 32 /* BU2614 / BU2614FS bus size */
+
+#define SHORT_DELAY 5 /* usec */
+#define LONG_DELAY 75 /* usec */
+
+struct gemtek_device {
+ unsigned long lastfreq;
int muted;
+ u32 bu2614data;
};
+#define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */
+#define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */
+#define BU2614_VOID_BITS 4 /* unused */
+#define BU2614_FMES_BITS 1 /* CT, Frequency measurement beginning data */
+#define BU2614_STDF_BITS 3 /* R0..R2, Standard frequency data */
+#define BU2614_SWIN_BITS 1 /* S, Switch between FMIN / AMIN */
+#define BU2614_SWAL_BITS 1 /* PS, Swallow counter division (AMIN only)*/
+#define BU2614_VOID2_BITS 1 /* unused */
+#define BU2614_FMUN_BITS 1 /* GT, Frequency measurement time & unlock */
+#define BU2614_TEST_BITS 1 /* TS, Test data is input */
+
+#define BU2614_FREQ_SHIFT 0
+#define BU2614_PORT_SHIFT (BU2614_FREQ_BITS + BU2614_FREQ_SHIFT)
+#define BU2614_VOID_SHIFT (BU2614_PORT_BITS + BU2614_PORT_SHIFT)
+#define BU2614_FMES_SHIFT (BU2614_VOID_BITS + BU2614_VOID_SHIFT)
+#define BU2614_STDF_SHIFT (BU2614_FMES_BITS + BU2614_FMES_SHIFT)
+#define BU2614_SWIN_SHIFT (BU2614_STDF_BITS + BU2614_STDF_SHIFT)
+#define BU2614_SWAL_SHIFT (BU2614_SWIN_BITS + BU2614_SWIN_SHIFT)
+#define BU2614_VOID2_SHIFT (BU2614_SWAL_BITS + BU2614_SWAL_SHIFT)
+#define BU2614_FMUN_SHIFT (BU2614_VOID2_BITS + BU2614_VOID2_SHIFT)
+#define BU2614_TEST_SHIFT (BU2614_FMUN_BITS + BU2614_FMUN_SHIFT)
+
+#define MKMASK(field) (((1<<BU2614_##field##_BITS) - 1) << \
+ BU2614_##field##_SHIFT)
+#define BU2614_PORT_MASK MKMASK(PORT)
+#define BU2614_FREQ_MASK MKMASK(FREQ)
+#define BU2614_VOID_MASK MKMASK(VOID)
+#define BU2614_FMES_MASK MKMASK(FMES)
+#define BU2614_STDF_MASK MKMASK(STDF)
+#define BU2614_SWIN_MASK MKMASK(SWIN)
+#define BU2614_SWAL_MASK MKMASK(SWAL)
+#define BU2614_VOID2_MASK MKMASK(VOID2)
+#define BU2614_FMUN_MASK MKMASK(FMUN)
+#define BU2614_TEST_MASK MKMASK(TEST)
-/* local things */
+static struct gemtek_device gemtek_unit;
-/* the correct way to mute the gemtek may be to write the last written
- * frequency || 0x10, but just writing 0x10 once seems to do it as well
+static spinlock_t lock;
+
+/*
+ * Set data which will be sent to BU2614FS.
*/
-static void gemtek_mute(struct gemtek_device *dev)
+#define gemtek_bu2614_set(dev, field, data) ((dev)->bu2614data = \
+ ((dev)->bu2614data & ~field##_MASK) | ((data) << field##_SHIFT))
+
+/*
+ * Transmit settings to BU2614FS over GemTek IC.
+ */
+static void gemtek_bu2614_transmit(struct gemtek_device *dev)
{
- if(dev->muted)
- return;
+ int i, bit, q, mute;
+
spin_lock(&lock);
- outb(0x10, io);
+
+ mute = dev->muted ? GEMTEK_MT : 0x00;
+
+ outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
+ udelay(SHORT_DELAY);
+ outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
+ udelay(LONG_DELAY);
+
+ for (i = 0, q = dev->bu2614data; i < 32; i++, q >>= 1) {
+ bit = (q & 1) ? GEMTEK_DA : 0;
+ outb_p(mute | GEMTEK_CE | bit, io);
+ udelay(SHORT_DELAY);
+ outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, io);
+ udelay(SHORT_DELAY);
+ }
+
+ outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
+ udelay(SHORT_DELAY);
+ outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
+ udelay(LONG_DELAY);
+
spin_unlock(&lock);
- dev->muted = 1;
}
-static void gemtek_unmute(struct gemtek_device *dev)
+/*
+ * Calculate divisor from FM-frequency for BU2614FS (3.125 KHz STDF expected).
+ */
+static unsigned long gemtek_convfreq(unsigned long freq)
{
- if(dev->muted == 0)
+ return ((freq<<FSCALE) + IF_OFFSET + REF_FREQ/2) / REF_FREQ;
+}
+
+/*
+ * Set FM-frequency.
+ */
+static void gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
+{
+
+ if (keepmuted && hardmute && dev->muted)
return;
- spin_lock(&lock);
- outb(0x20, io);
- spin_unlock(&lock);
+
+ if (freq < GEMTEK_LOWFREQ)
+ freq = GEMTEK_LOWFREQ;
+ else if (freq > GEMTEK_HIGHFREQ)
+ freq = GEMTEK_HIGHFREQ;
+
+ dev->lastfreq = freq;
dev->muted = 0;
+
+ gemtek_bu2614_set(dev, BU2614_PORT, 0);
+ gemtek_bu2614_set(dev, BU2614_FMES, 0);
+ gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */
+ gemtek_bu2614_set(dev, BU2614_SWAL, 0);
+ gemtek_bu2614_set(dev, BU2614_FMUN, 1); /* GT bit set */
+ gemtek_bu2614_set(dev, BU2614_TEST, 0);
+
+ gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_STDF_3_125_KHZ);
+ gemtek_bu2614_set(dev, BU2614_FREQ, gemtek_convfreq(freq));
+
+ gemtek_bu2614_transmit(dev);
}
-static void zero(void)
+/*
+ * Set mute flag.
+ */
+static void gemtek_mute(struct gemtek_device *dev)
{
- outb_p(0x04, io);
- udelay(5);
- outb_p(0x05, io);
- udelay(5);
+ int i;
+ dev->muted = 1;
+
+ if (hardmute) {
+ /* Turn off PLL, disable data output */
+ gemtek_bu2614_set(dev, BU2614_PORT, 0);
+ gemtek_bu2614_set(dev, BU2614_FMES, 0); /* CT bit off */
+ gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */
+ gemtek_bu2614_set(dev, BU2614_SWAL, 0);
+ gemtek_bu2614_set(dev, BU2614_FMUN, 0); /* GT bit off */
+ gemtek_bu2614_set(dev, BU2614_TEST, 0);
+ gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_PLL_OFF);
+ gemtek_bu2614_set(dev, BU2614_FREQ, 0);
+ gemtek_bu2614_transmit(dev);
+ } else {
+ spin_lock(&lock);
+
+ /* Read bus contents (CE, CK and DA). */
+ i = inb_p(io);
+ /* Write it back with mute flag set. */
+ outb_p((i >> 5) | GEMTEK_MT, io);
+ udelay(SHORT_DELAY);
+
+ spin_unlock(&lock);
+ }
}
-static void one(void)
+/*
+ * Unset mute flag.
+ */
+static void gemtek_unmute(struct gemtek_device *dev)
{
- outb_p(0x06, io);
- udelay(5);
- outb_p(0x07, io);
- udelay(5);
+ int i;
+ dev->muted = 0;
+
+ if (hardmute) {
+ /* Turn PLL back on. */
+ gemtek_setfreq(dev, dev->lastfreq);
+ } else {
+ spin_lock(&lock);
+
+ i = inb_p(io);
+ outb_p(i >> 5, io);
+ udelay(SHORT_DELAY);
+
+ spin_unlock(&lock);
+ }
}
-static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
+/*
+ * Get signal strength (= stereo status).
+ */
+static inline int gemtek_getsigstr(void)
{
- int i;
+ return inb_p(io) & GEMTEK_NS ? 0 : 1;
+}
-/* freq = 78.25*((float)freq/16000.0 + 10.52); */
+/*
+ * Check if requested card acts like GemTek Radio card.
+ */
+static int gemtek_verify(int port)
+{
+ static int verified = -1;
+ int i, q;
- freq /= 16;
- freq += 10520;
- freq *= 7825;
- freq /= 100000;
+ if (verified == port)
+ return 1;
spin_lock(&lock);
- /* 2 start bits */
- outb_p(0x03, io);
- udelay(5);
- outb_p(0x07, io);
- udelay(5);
+ q = inb_p(port); /* Read bus contents before probing. */
+ /* Try to turn on CE, CK and DA respectively and check if card responds
+ properly. */
+ for (i = 0; i < 3; ++i) {
+ outb_p(1 << i, port);
+ udelay(SHORT_DELAY);
- /* 28 frequency bits (lsb first) */
- for (i = 0; i < 14; i++)
- if (freq & (1 << i))
- one();
- else
- zero();
- /* 36 unknown bits */
- for (i = 0; i < 11; i++)
- zero();
- one();
- for (i = 0; i < 4; i++)
- zero();
- one();
- zero();
-
- /* 2 end bits */
- outb_p(0x03, io);
- udelay(5);
- outb_p(0x07, io);
- udelay(5);
+ if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) {
+ spin_unlock(&lock);
+ return 0;
+ }
+ }
+ outb_p(q >> 5, port); /* Write bus contents back. */
+ udelay(SHORT_DELAY);
spin_unlock(&lock);
+ verified = port;
- return 0;
+ return 1;
}
-static int gemtek_getsigstr(struct gemtek_device *dev)
+/*
+ * Automatic probing for card.
+ */
+static int gemtek_probe(void)
{
- spin_lock(&lock);
- inb(io);
- udelay(5);
- spin_unlock(&lock);
- if (inb(io) & 8) /* bit set = no signal present */
- return 0;
- return 1; /* signal present */
+ int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
+ int i;
+
+ if (!probe) {
+ printk(KERN_INFO "Automatic device probing disabled.\n");
+ return -1;
+ }
+
+ printk(KERN_INFO "Automatic device probing enabled.\n");
+
+ for (i = 0; i < ARRAY_SIZE(ioports); ++i) {
+ printk(KERN_INFO "Trying I/O port 0x%x...\n", ioports[i]);
+
+ if (!request_region(ioports[i], 1, "gemtek-probe")) {
+ printk(KERN_WARNING "I/O port 0x%x busy!\n",
+ ioports[i]);
+ continue;
+ }
+
+ if (gemtek_verify(ioports[i])) {
+ printk(KERN_INFO "Card found from I/O port "
+ "0x%x!\n", ioports[i]);
+
+ release_region(ioports[i], 1);
+
+ io = ioports[i];
+ return io;
+ }
+
+ release_region(ioports[i], 1);
+ }
+
+ printk(KERN_ERR "Automatic probing failed!\n");
+
+ return -1;
}
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
+/*
+ * Video 4 Linux stuff.
+ */
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ }, {
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535,
+ .default_value = 0xff,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
+};
+
+static struct file_operations gemtek_fops = {
+ .owner = THIS_MODULE,
+ .open = video_exclusive_open,
+ .release = video_exclusive_release,
+ .ioctl = video_ioctl2,
+ .compat_ioctl = v4l_compat_ioctl32,
+ .llseek = no_llseek
+};
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *v)
{
strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
strlcpy(v->card, "GemTek", sizeof(v->card));
@@ -172,28 +412,29 @@ static int vidioc_querycap(struct file *file, void *priv,
return 0;
}
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
{
- struct video_device *dev = video_devdata(file);
- struct gemtek_device *rt = dev->priv;
-
if (v->index > 0)
return -EINVAL;
strcpy(v->name, "FM");
v->type = V4L2_TUNER_RADIO;
- v->rangelow = (87*16000);
- v->rangehigh = (108*16000);
- v->rxsubchans = V4L2_TUNER_SUB_MONO;
- v->capability = V4L2_TUNER_CAP_LOW;
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = 0xffff*gemtek_getsigstr(rt);
+ v->rangelow = GEMTEK_LOWFREQ;
+ v->rangehigh = GEMTEK_HIGHFREQ;
+ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ v->signal = 0xffff * gemtek_getsigstr();
+ if (v->signal) {
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ v->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ } else {
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->rxsubchans = V4L2_TUNER_SUB_MONO;
+ }
+
return 0;
}
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
{
if (v->index > 0)
return -EINVAL;
@@ -201,38 +442,35 @@ static int vidioc_s_tuner(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ struct v4l2_frequency *f)
{
struct video_device *dev = video_devdata(file);
struct gemtek_device *rt = dev->priv;
- rt->curfreq = f->frequency;
- /* needs to be called twice in order for getsigstr to work */
- gemtek_setfreq(rt, rt->curfreq);
- gemtek_setfreq(rt, rt->curfreq);
+ gemtek_setfreq(rt, f->frequency);
+
return 0;
}
static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ struct v4l2_frequency *f)
{
struct video_device *dev = video_devdata(file);
struct gemtek_device *rt = dev->priv;
f->type = V4L2_TUNER_RADIO;
- f->frequency = rt->curfreq;
+ f->frequency = rt->lastfreq;
return 0;
}
static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
+ struct v4l2_queryctrl *qc)
{
int i;
- for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); ++i) {
if (qc->id && qc->id == radio_qctrl[i].id) {
- memcpy(qc, &(radio_qctrl[i]),
- sizeof(*qc));
+ memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
return 0;
}
}
@@ -240,7 +478,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
}
static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+ struct v4l2_control *ctrl)
{
struct video_device *dev = video_devdata(file);
struct gemtek_device *rt = dev->priv;
@@ -260,7 +498,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
}
static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+ struct v4l2_control *ctrl)
{
struct video_device *dev = video_devdata(file);
struct gemtek_device *rt = dev->priv;
@@ -282,8 +520,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
return -EINVAL;
}
-static int vidioc_g_audio (struct file *file, void *priv,
- struct v4l2_audio *a)
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
if (a->index > 1)
return -EINVAL;
@@ -306,99 +543,101 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
return 0;
}
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
if (a->index != 0)
return -EINVAL;
return 0;
}
-static struct gemtek_device gemtek_unit;
-
-static const struct file_operations gemtek_fops = {
- .owner = THIS_MODULE,
- .open = video_exclusive_open,
- .release = video_exclusive_release,
- .ioctl = video_ioctl2,
- .compat_ioctl = v4l_compat_ioctl32,
- .llseek = no_llseek,
+static struct video_device gemtek_radio = {
+ .owner = THIS_MODULE,
+ .name = "GemTek Radio card",
+ .type = VID_TYPE_TUNER,
+ .fops = &gemtek_fops,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_s_audio = vidioc_s_audio,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl
};
-static struct video_device gemtek_radio=
-{
- .owner = THIS_MODULE,
- .name = "GemTek radio",
- .type = VID_TYPE_TUNER,
- .fops = &gemtek_fops,
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
-};
+/*
+ * Initialization / cleanup related stuff.
+ */
+/*
+ * Initilize card.
+ */
static int __init gemtek_init(void)
{
- if(io==-1)
- {
- printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (io=0x020c or io=0x248 for the combined sound/radiocard)\n");
- return -EINVAL;
- }
+ printk(KERN_INFO RADIO_BANNER "\n");
- if (!request_region(io, 4, "gemtek"))
- {
- printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
- return -EBUSY;
- }
+ spin_lock_init(&lock);
- gemtek_radio.priv=&gemtek_unit;
+ gemtek_probe();
+ if (io) {
+ if (!request_region(io, 1, "gemtek")) {
+ printk(KERN_ERR "I/O port 0x%x already in use.\n", io);
+ return -EBUSY;
+ }
- if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1)
- {
- release_region(io, 4);
+ if (!gemtek_verify(io))
+ printk(KERN_WARNING "Card at I/O port 0x%x does not "
+ "respond properly, check your "
+ "configuration.\n", io);
+ else
+ printk(KERN_INFO "Using I/O port 0x%x.\n", io);
+ } else if (probe) {
+ printk(KERN_ERR "Automatic probing failed and no "
+ "fixed I/O port defined.\n");
+ return -ENODEV;
+ } else {
+ printk(KERN_ERR "Automatic probing disabled but no fixed "
+ "I/O port defined.");
return -EINVAL;
}
- printk(KERN_INFO "GemTek Radio Card driver.\n");
- spin_lock_init(&lock);
+ gemtek_radio.priv = &gemtek_unit;
- /* this is _maybe_ unnecessary */
- outb(0x01, io);
+ if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO,
+ radio_nr) == -1) {
+ release_region(io, 1);
+ return -EBUSY;
+ }
- /* mute card - prevents noisy bootups */
- gemtek_unit.muted = 0;
- gemtek_mute(&gemtek_unit);
+ /* Set defaults */
+ gemtek_unit.lastfreq = GEMTEK_LOWFREQ;
+ gemtek_unit.bu2614data = 0;
+
+ if (initmute)
+ gemtek_mute(&gemtek_unit);
return 0;
}
-MODULE_AUTHOR("Jonas Munsin");
-MODULE_DESCRIPTION("A driver for the GemTek Radio Card");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard)).");
-module_param(radio_nr, int, 0);
-
-static void __exit gemtek_cleanup(void)
+/*
+ * Module cleanup
+ */
+static void __exit gemtek_exit(void)
{
+ if (shutdown) {
+ hardmute = 1; /* Turn off PLL */
+ gemtek_mute(&gemtek_unit);
+ } else {
+ printk(KERN_INFO "Module unloaded but card not muted!\n");
+ }
+
video_unregister_device(&gemtek_radio);
- release_region(io,4);
+ release_region(io, 1);
}
module_init(gemtek_init);
-module_exit(gemtek_cleanup);
-
-/*
- Local variables:
- compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c"
- End:
-*/
+module_exit(gemtek_exit);
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index 7e1911c3d54..535ffe8c810 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -173,7 +173,7 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
i--;
p--;
temp = temp/2;
- }
+ }
spin_lock(&lock);
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index e204e7b4028..c9f14bfc854 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -148,6 +148,15 @@ config VIDEO_WM8739
To compile this driver as a module, choose M here: the
module will be called wm8739.
+config VIDEO_VP27SMPX
+ tristate "Panasonic VP27s internal MPX"
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ ---help---
+ Support for the internal MPX of the Panasonic VP27s tuner.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vp27smpx.
+
comment "Video decoders"
config VIDEO_BT819
@@ -197,6 +206,13 @@ config VIDEO_OV7670
OV7670 VGA camera. It currently only works with the M88ALP01
controller.
+config VIDEO_TCM825X
+ tristate "TCM825x camera sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a driver for the Toshiba TCM825x VGA camera sensor.
+ It is used for example in Nokia N800.
+
config VIDEO_SAA7110
tristate "Philips SAA7110 video decoder"
depends on VIDEO_V4L1 && I2C
@@ -347,8 +363,8 @@ endmenu # encoder / decoder chips
config VIDEO_VIVI
tristate "Virtual Video Driver"
- depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI
- select VIDEO_BUF
+ depends on VIDEO_V4L2 && !SPARC32 && !SPARC64
+ select VIDEOBUF_VMALLOC
default n
---help---
Enables a virtual video driver. This device shows a color bar
@@ -489,15 +505,6 @@ config TUNER_3036
Say Y here to include support for Philips SAB3036 compatible tuners.
If in doubt, say N.
-config TUNER_TEA5761
- bool "TEA 5761 radio tuner (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- depends on I2C
- select VIDEO_TUNER
- help
- Say Y here to include support for Philips TEA5761 radio tuner.
- If in doubt, say N.
-
config VIDEO_VINO
tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
@@ -661,6 +668,8 @@ config VIDEO_HEXIUM_GEMINI
source "drivers/media/video/cx88/Kconfig"
+source "drivers/media/video/cx23885/Kconfig"
+
source "drivers/media/video/ivtv/Kconfig"
config VIDEO_M32R_AR
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 10b4d446901..b5a064163e0 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -4,14 +4,12 @@
zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o
-tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \
- mt20xx.o tda8290.o tea5767.o tda9887.o
-
-tuner-$(CONFIG_TUNER_TEA5761) += tea5761.o
+tuner-objs := tuner-core.o tuner-types.o tda9887.o
msp3400-objs := msp3400-driver.o msp3400-kthreads.o
-obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o
+obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \
+ v4l2-int-device.o
ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
@@ -63,7 +61,6 @@ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
obj-$(CONFIG_VIDEO_MEYE) += meye.o
obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
-obj-$(CONFIG_VIDEO_IVTV) += ivtv/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
@@ -73,6 +70,7 @@ obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
+obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
obj-$(CONFIG_VIDEO_MXB) += mxb.o
@@ -82,8 +80,17 @@ obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
obj-$(CONFIG_TUNER_3036) += tuner-3036.o
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
-obj-$(CONFIG_VIDEO_BUF) += video-buf.o
-obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o
+
+obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o
+obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o
+obj-$(CONFIG_TUNER_TDA8290) += tda8290.o
+obj-$(CONFIG_TUNER_TEA5767) += tea5767.o
+obj-$(CONFIG_TUNER_TEA5761) += tea5761.o
+
+obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
+obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
+obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
+obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
@@ -97,6 +104,8 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_OV511) += ov511.o
obj-$(CONFIG_USB_SE401) += se401.o
@@ -114,6 +123,9 @@ obj-$(CONFIG_USB_KONICAWC) += usbvideo/
obj-$(CONFIG_USB_VICAM) += usbvideo/
obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
+obj-$(CONFIG_VIDEO_IVTV) += ivtv/
+
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
+obj-$(CONFIG_VIDEO_CX23885) += cx23885/
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 649f52f9ad2..c94a4d0f280 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -23,7 +23,6 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
@@ -442,7 +441,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file,
{
struct video_window *w = arg;
DEBUG(1, "VIDIOCGWIN:\n");
- memset(w, 0, sizeof(w));
+ memset(w, 0, sizeof(*w));
w->width = ar->width;
w->height = ar->height;
return 0;
@@ -756,7 +755,6 @@ static struct video_device ar_template = {
.owner = THIS_MODULE,
.name = "Colour AR VGA",
.type = VID_TYPE_CAPTURE,
- .hardware = VID_HARDWARE_ARV,
.fops = &ar_fops,
.release = ar_release,
.minor = -1,
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index 58eae887a62..2ca162b390a 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -4,7 +4,7 @@ config VIDEO_BT848
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_BTCX
- select VIDEO_BUF
+ select VIDEOBUF_DMA_SG
select VIDEO_IR
select VIDEO_TUNER
select VIDEO_TVEEPROM
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index f6715007d40..3abd9fa54d2 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -27,7 +27,6 @@
#include <linux/delay.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -1260,7 +1259,7 @@ struct tvcard bttv_tvcards[] = {
.has_radio = 1,
},
[BTTV_BOARD_LIFETEC_9415] = {
- /* Tim Röstermundt <rosterm@uni-muenster.de>
+ /* Tim Röstermundt <rosterm@uni-muenster.de>
in de.comp.os.unix.linux.hardware:
options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
gpiomux =0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
@@ -2825,7 +2824,7 @@ struct tvcard bttv_tvcards[] = {
},
/* ---- card 0x8b ---------------------------------- */
[BTTV_BOARD_PV_M4900] = {
- /* Sérgio Fortier <sergiofortier@yahoo.com.br> */
+ /* Sérgio Fortier <sergiofortier@yahoo.com.br> */
.name = "Prolink PixelView PlayTV MPEG2 PV-M4900",
.video_inputs = 3,
.audio_inputs = 1,
@@ -2989,6 +2988,23 @@ struct tvcard bttv_tvcards[] = {
.no_tda9875 = 1,
.no_tda7432 = 1,
},
+ /* ---- card 0x95---------------------------------- */
+ [BTTV_BOARD_TYPHOON_TVTUNERPCI] = {
+ .name = "Typhoon TV-Tuner PCI (50684)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x3014f,
+ .muxsel = { 2, 3, 1, 1 },
+ .gpiomux = { 0x20001,0x10001, 0, 0 },
+ .gpiomute = 10,
+ .needs_tvaudio = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3276,15 +3292,15 @@ static void eagle_muxsel(struct bttv *btv, unsigned int input)
btaor((2)<<5, ~(3<<5), BT848_IFORM);
gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]);
- /* composite */
- /* set chroma ADC to sleep */
- btor(BT848_ADC_C_SLEEP, BT848_ADC);
- /* set to composite video */
- btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
- btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
+ /* composite */
+ /* set chroma ADC to sleep */
+ btor(BT848_ADC_C_SLEEP, BT848_ADC);
+ /* set to composite video */
+ btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
+ btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
- /* switch sync drive off */
- gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
+ /* switch sync drive off */
+ gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
}
static void gvc1100_muxsel(struct bttv *btv, unsigned int input)
@@ -3453,7 +3469,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr);
}
break;
- case BTTV_BOARD_STB2:
+ case BTTV_BOARD_STB2:
if (btv->cardid == 0x3060121a) {
/* Fix up entry for 3DFX VoodooTV 100,
which is an OEM STB card variant. */
@@ -3784,7 +3800,7 @@ static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
for (i = 12; i < 21; i++)
serial *= 10, serial += ee[i] - '0';
}
- } else {
+ } else {
unsigned short type;
for (i = 4*16; i < 8*16; i += 16) {
@@ -4693,18 +4709,18 @@ adtvk503_audio(struct bttv *btv, struct video_audio *v, int set)
*
* The board hardwire Y0 (xpoint) to MUX1 and MUXOUT to Yin.
* GPIO pins are wired as:
- * GPIO[0:3] - AX[0:3] (xpoint) - P1[0:3] (microcontroler)
- * GPIO[4:6] - AY[0:2] (xpoint) - P1[4:6] (microcontroler)
- * GPIO[7] - DATA (xpoint) - P1[7] (microcontroler)
- * GPIO[8] - - P3[5] (microcontroler)
- * GPIO[9] - RESET (xpoint) - P3[6] (microcontroler)
- * GPIO[10] - STROBE (xpoint) - P3[7] (microcontroler)
- * GPINTR - - P3[4] (microcontroler)
+ * GPIO[0:3] - AX[0:3] (xpoint) - P1[0:3] (microcontroller)
+ * GPIO[4:6] - AY[0:2] (xpoint) - P1[4:6] (microcontroller)
+ * GPIO[7] - DATA (xpoint) - P1[7] (microcontroller)
+ * GPIO[8] - - P3[5] (microcontroller)
+ * GPIO[9] - RESET (xpoint) - P3[6] (microcontroller)
+ * GPIO[10] - STROBE (xpoint) - P3[7] (microcontroller)
+ * GPINTR - - P3[4] (microcontroller)
*
- * The microcontroler is a 80C32 like. It should be possible to change xpoint
- * configuration either directly (as we are doing) or using the microcontroler
+ * The microcontroller is a 80C32 like. It should be possible to change xpoint
+ * configuration either directly (as we are doing) or using the microcontroller
* which is also wired to I2C interface. I have no further info on the
- * microcontroler features, one would need to disassembly the firmware.
+ * microcontroller features, one would need to disassembly the firmware.
* note: the vendor refused to give any information on this product, all
* that stuff was found using a multimeter! :)
*/
@@ -4772,7 +4788,7 @@ static void tibetCS16_init(struct bttv *btv)
* The analog switch is controlled by the "master", but the detection order
* of the four BT878A chips is in an order which I just don't understand.
* The "master" is actually the second controller to be detected. The
- * logic on the board uses logical numbers for the 4 controlers, but
+ * logic on the board uses logical numbers for the 4 controllers, but
* those numbers are different from the detection sequence. When working
* with the analog switch, we need to "map" from the detection sequence
* over to the board's logical controller number. This mapping sequence
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index cb555f2c40f..a88b56e6ca0 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -30,7 +30,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -155,13 +154,14 @@ MODULE_LICENSE("GPL");
/* ----------------------------------------------------------------------- */
/* sysfs */
-static ssize_t show_card(struct class_device *cd, char *buf)
+static ssize_t show_card(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vfd = to_video_device(cd);
struct bttv *btv = dev_get_drvdata(vfd->dev);
return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
}
-static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
+static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
/* ----------------------------------------------------------------------- */
/* dvb auto-load setup */
@@ -2583,7 +2583,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
if (check_btres(fh, RESOURCE_OVERLAY)) {
struct bttv_buffer *new;
- new = videobuf_alloc(sizeof(*new));
+ new = videobuf_pci_alloc(sizeof(*new));
new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv,fh,new);
@@ -2881,10 +2881,6 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (NULL == fmt)
return -EINVAL;
mutex_lock(&fh->cap.lock);
- if (fmt->depth != pic->depth) {
- retval = -EINVAL;
- goto fh_unlock_and_return;
- }
if (fmt->flags & FORMAT_FLAGS_RAW) {
/* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL *
RAW_LINES * 2. F1 is stored at offset 0, F2
@@ -3049,7 +3045,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
mutex_lock(&fh->cap.lock);
if (*on) {
fh->ov.tvnorm = btv->tvnorm;
- new = videobuf_alloc(sizeof(*new));
+ new = videobuf_pci_alloc(sizeof(*new));
new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
} else {
@@ -3072,6 +3068,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
V4L2_MEMORY_MMAP);
if (retval < 0)
goto fh_unlock_and_return;
+
+ gbuffers = retval;
memset(mbuf,0,sizeof(*mbuf));
mbuf->frames = gbuffers;
mbuf->size = gbuffers * gbufsize;
@@ -3115,6 +3113,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
vm->width,vm->height,field);
if (0 != retval)
goto fh_unlock_and_return;
+ btv->init.width = vm->width;
+ btv->init.height = vm->height;
spin_lock_irqsave(&btv->s_lock,flags);
buffer_queue(&fh->cap,&buf->vb);
spin_unlock_irqrestore(&btv->s_lock,flags);
@@ -3142,9 +3142,12 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
retval = -EIO;
/* fall through */
case STATE_DONE:
- videobuf_dma_sync(&fh->cap,&buf->vb.dma);
+ {
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+ videobuf_dma_sync(&fh->cap,dma);
bttv_dma_free(&fh->cap,btv,buf);
break;
+ }
default:
retval = -EINVAL;
break;
@@ -3338,7 +3341,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (check_btres(fh, RESOURCE_OVERLAY)) {
struct bttv_buffer *new;
- new = videobuf_alloc(sizeof(*new));
+ new = videobuf_pci_alloc(sizeof(*new));
new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
retval = bttv_switch_overlay(btv,fh,new);
@@ -3697,7 +3700,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
mutex_unlock(&fh->cap.lock);
return POLLERR;
}
- fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
+ fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize);
if (NULL == fh->cap.read_buf) {
mutex_unlock(&fh->cap.lock);
return POLLERR;
@@ -3764,13 +3767,13 @@ static int bttv_open(struct inode *inode, struct file *file)
fh->ov.setup_ok = 0;
v4l2_prio_open(&btv->prio,&fh->prio);
- videobuf_queue_init(&fh->cap, &bttv_video_qops,
+ videobuf_queue_pci_init(&fh->cap, &bttv_video_qops,
btv->c.pci, &btv->s_lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct bttv_buffer),
fh);
- videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
+ videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops,
btv->c.pci, &btv->s_lock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
@@ -3872,7 +3875,6 @@ static struct video_device bttv_video_template =
.name = "UNSET",
.type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
VID_TYPE_CLIPPING|VID_TYPE_SCALES,
- .hardware = VID_HARDWARE_BT848,
.fops = &bttv_fops,
.minor = -1,
};
@@ -3881,7 +3883,6 @@ static struct video_device bttv_vbi_template =
{
.name = "bt848/878 vbi",
.type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
- .hardware = VID_HARDWARE_BT848,
.fops = &bttv_fops,
.minor = -1,
};
@@ -4029,7 +4030,6 @@ static struct video_device radio_template =
{
.name = "bt848/878 radio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_BT848,
.fops = &radio_fops,
.minor = -1,
};
@@ -4613,9 +4613,9 @@ static int __devinit bttv_register_video(struct bttv *btv)
goto err;
printk(KERN_INFO "bttv%d: registered device video%d\n",
btv->c.nr,btv->video_dev->minor & 0x1f);
- if (class_device_create_file(&btv->video_dev->class_dev,
- &class_device_attr_card)<0) {
- printk(KERN_ERR "bttv%d: class_device_create_file 'card' "
+ if (device_create_file(&btv->video_dev->class_dev,
+ &dev_attr_card)<0) {
+ printk(KERN_ERR "bttv%d: device_create_file 'card' "
"failed\n", btv->c.nr);
goto err;
}
diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c
index 84154c26f9c..dce6dae5740 100644
--- a/drivers/media/video/bt8xx/bttv-gpio.c
+++ b/drivers/media/video/bt8xx/bttv-gpio.c
@@ -106,11 +106,9 @@ int bttv_sub_add_device(struct bttv_core *core, char *name)
int bttv_sub_del_devices(struct bttv_core *core)
{
- struct bttv_sub_device *sub;
- struct list_head *item,*save;
+ struct bttv_sub_device *sub, *save;
- list_for_each_safe(item,save,&core->subs) {
- sub = list_entry(item,struct bttv_sub_device,list);
+ list_for_each_entry_safe(sub, save, &core->subs, list) {
list_del(&sub->list);
device_unregister(&sub->dev);
}
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 0dfa49b6641..4d5b8035e46 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -28,7 +28,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
@@ -125,12 +124,6 @@ static struct i2c_adapter bttv_i2c_adap_sw_template = {
/* ----------------------------------------------------------------------- */
/* I2C functions - hardware i2c */
-static int algo_control(struct i2c_adapter *adapter,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
static u32 functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_SMBUS_EMUL;
@@ -279,7 +272,6 @@ static int bttv_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int
static struct i2c_algorithm bttv_algo = {
.master_xfer = bttv_i2c_xfer,
- .algo_control = algo_control,
.functionality = functionality,
};
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 4201552bc3c..e7c521b8444 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -19,7 +19,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index e7104d9cb4b..58986f1a5f1 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -574,10 +574,12 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc,
void
bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
{
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, &buf->vb.dma);
- videobuf_dma_free(&buf->vb.dma);
+ videobuf_dma_unmap(q, dma);
+ videobuf_dma_free(dma);
btcx_riscmem_free(btv->c.pci,&buf->bottom);
btcx_riscmem_free(btv->c.pci,&buf->top);
buf->vb.state = STATE_NEEDS_INIT;
@@ -699,6 +701,7 @@ int
bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
{
const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
dprintk(KERN_DEBUG
"bttv%d: buffer field: %s format: %s size: %dx%d\n",
@@ -716,25 +719,25 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
- bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
+ bttv_risc_packed(btv,&buf->top,dma->sglist,
/* offset */ 0,bpl,
/* padding */ 0,/* skip_lines */ 0,
buf->vb.height);
break;
case V4L2_FIELD_BOTTOM:
- bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
+ bttv_risc_packed(btv,&buf->bottom,dma->sglist,
0,bpl,0,0,buf->vb.height);
break;
case V4L2_FIELD_INTERLACED:
- bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
+ bttv_risc_packed(btv,&buf->top,dma->sglist,
0,bpl,bpl,0,buf->vb.height >> 1);
- bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
+ bttv_risc_packed(btv,&buf->bottom,dma->sglist,
bpl,bpl,bpl,0,buf->vb.height >> 1);
break;
case V4L2_FIELD_SEQ_TB:
- bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
+ bttv_risc_packed(btv,&buf->top,dma->sglist,
0,bpl,0,0,buf->vb.height >> 1);
- bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
+ bttv_risc_packed(btv,&buf->bottom,dma->sglist,
bpf,bpl,0,0,buf->vb.height >> 1);
break;
default:
@@ -767,7 +770,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,/* both_fields */ 0,
tvnorm,&buf->crop);
- bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
+ bttv_risc_planar(btv, &buf->top, dma->sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
buf->fmt->vshift,0);
@@ -776,7 +779,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
buf->vb.height,0,
tvnorm,&buf->crop);
- bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
+ bttv_risc_planar(btv, &buf->bottom, dma->sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
buf->fmt->vshift,0);
@@ -789,14 +792,14 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
bttv_risc_planar(btv,&buf->top,
- buf->vb.dma.sglist,
+ dma->sglist,
0,buf->vb.width,ypadding,lines,
uoffset,voffset,
buf->fmt->hshift,
buf->fmt->vshift,
cpadding);
bttv_risc_planar(btv,&buf->bottom,
- buf->vb.dma.sglist,
+ dma->sglist,
ypadding,buf->vb.width,ypadding,lines,
uoffset+cpadding,
voffset+cpadding,
@@ -812,7 +815,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
bttv_risc_planar(btv,&buf->top,
- buf->vb.dma.sglist,
+ dma->sglist,
0,buf->vb.width,0,lines,
uoffset >> 1,
voffset >> 1,
@@ -820,7 +823,7 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
buf->fmt->vshift,
0);
bttv_risc_planar(btv,&buf->bottom,
- buf->vb.dma.sglist,
+ dma->sglist,
lines * ypadding,buf->vb.width,0,lines,
lines * ypadding + (uoffset >> 1),
lines * ypadding + (voffset >> 1),
@@ -839,10 +842,10 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
buf->vb.field = V4L2_FIELD_SEQ_TB;
bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
1,tvnorm,&buf->crop);
- bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
+ bttv_risc_packed(btv, &buf->top, dma->sglist,
/* offset */ 0, RAW_BPL, /* padding */ 0,
/* skip_lines */ 0, RAW_LINES);
- bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
+ bttv_risc_packed(btv, &buf->bottom, dma->sglist,
buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
}
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
index 93e35de5a18..346ce019bdc 100644
--- a/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/drivers/media/video/bt8xx/bttv-vbi.c
@@ -24,7 +24,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
@@ -151,13 +150,14 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
if (redo_dma_risc) {
unsigned int bpl, padding, offset;
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
bpl = 2044; /* max. vbipack */
padding = VBI_BPL - bpl;
if (fh->vbi_fmt.fmt.count[0] > 0) {
rc = bttv_risc_packed(btv, &buf->top,
- buf->vb.dma.sglist,
+ dma->sglist,
/* offset */ 0, bpl,
padding, skip_lines0,
fh->vbi_fmt.fmt.count[0]);
@@ -169,7 +169,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
rc = bttv_risc_packed(btv, &buf->bottom,
- buf->vb.dma.sglist,
+ dma->sglist,
offset, bpl,
padding, skip_lines1,
fh->vbi_fmt.fmt.count[1]);
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index dcc847dc248..19e75d50a10 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -172,6 +172,8 @@
#define BTTV_BOARD_SSAI_ULTRASOUND 0x92
#define BTTV_BOARD_VOODOOTV_200 0x93
#define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94
+#define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95
+
/* more card-specific defines */
#define PT2254_L_CHANNEL 0x10
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 5b25faca150..d4ac4c4b49b 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -36,12 +36,12 @@
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/mutex.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <asm/io.h>
#include <media/v4l2-common.h>
#include <linux/device.h>
-#include <media/video-buf.h>
+#include <media/videobuf-dma-sg.h>
#include <media/tuner.h>
#include <media/tveeprom.h>
#include <media/ir-common.h>
diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c
index b4aca724927..ce0840ccd59 100644
--- a/drivers/media/video/btcx-risc.c
+++ b/drivers/media/video/btcx-risc.c
@@ -23,7 +23,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 7d47cbe6ad2..58423525591 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -104,6 +104,17 @@ static inline void write_lpdata(struct qcam_device *q, int d)
static inline void write_lpcontrol(struct qcam_device *q, int d)
{
+ if (d & 0x20) {
+ /* Set bidirectional mode to reverse (data in) */
+ parport_data_reverse(q->pport);
+ } else {
+ /* Set bidirectional mode to forward (data out) */
+ parport_data_forward(q->pport);
+ }
+
+ /* Now issue the regular port command, but strip out the
+ * direction flag */
+ d &= ~0x20;
parport_write_control(q->pport, d);
}
@@ -344,10 +355,13 @@ static int qc_detect(struct qcam_device *q)
/* Be (even more) liberal in what you accept... */
/* if (count > 30 && count < 200) */
- if (count > 20 && count < 300)
+ if (count > 20 && count < 400) {
return 1; /* found */
- else
+ } else {
+ printk(KERN_ERR "No Quickcam found on port %s\n",
+ q->pport->name);
return 0; /* not found */
+ }
}
@@ -885,7 +899,6 @@ static struct video_device qcam_template=
.owner = THIS_MODULE,
.name = "Connectix Quickcam",
.type = VID_TYPE_CAPTURE,
- .hardware = VID_HARDWARE_QCAM_BW,
.fops = &qcam_fops,
};
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index f76c6a6c376..cf1546b5a7f 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -699,7 +699,6 @@ static struct video_device qcam_template=
.owner = THIS_MODULE,
.name = "Colour QuickCam",
.type = VID_TYPE_CAPTURE,
- .hardware = VID_HARDWARE_QCAM_C,
.fops = &qcam_fops,
};
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index ef5361824f8..7ae499c9c54 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -3,6 +3,9 @@
* multifunction chip. Currently works with the Omnivision OV7670
* sensor.
*
+ * The data sheet for this device can be found at:
+ * http://www.marvell.com/products/pcconn/88ALP01.jsp
+ *
* Copyright 2006 One Laptop Per Child Association, Inc.
* Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
*
@@ -14,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/pci.h>
@@ -63,13 +65,13 @@ MODULE_SUPPORTED_DEVICE("Video");
*/
#define MAX_DMA_BUFS 3
-static int alloc_bufs_at_load = 0;
-module_param(alloc_bufs_at_load, bool, 0444);
-MODULE_PARM_DESC(alloc_bufs_at_load,
- "Non-zero value causes DMA buffers to be allocated at module "
- "load time. This increases the chances of successfully getting "
- "those buffers, but at the cost of nailing down the memory from "
- "the outset.");
+static int alloc_bufs_at_read = 0;
+module_param(alloc_bufs_at_read, bool, 0444);
+MODULE_PARM_DESC(alloc_bufs_at_read,
+ "Non-zero value causes DMA buffers to be allocated when the "
+ "video capture device is read, rather than at module load "
+ "time. This saves memory, but decreases the chances of "
+ "successfully getting those buffers.");
static int n_dma_bufs = 3;
module_param(n_dma_bufs, uint, 0644);
@@ -1198,7 +1200,7 @@ static int cafe_setup_siobuf(struct cafe_camera *cam, int index)
buf->v4lbuf.field = V4L2_FIELD_NONE;
buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
/*
- * Offset: must be 32-bit even on a 64-bit system. video-buf
+ * Offset: must be 32-bit even on a 64-bit system. videobuf-dma-sg
* just uses the length times the index, but the spec warns
* against doing just that - vma merging problems. So we
* leave a gap between each pair of buffers.
@@ -1503,7 +1505,7 @@ static int cafe_v4l_release(struct inode *inode, struct file *filp)
}
if (cam->users == 0) {
cafe_ctlr_power_down(cam);
- if (! alloc_bufs_at_load)
+ if (alloc_bufs_at_read)
cafe_free_dma_bufs(cam);
}
mutex_unlock(&cam->s_mutex);
@@ -2162,7 +2164,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
/*
* If so requested, try to get our DMA buffers now.
*/
- if (alloc_bufs_at_load) {
+ if (!alloc_bufs_at_read) {
if (cafe_alloc_dma_bufs(cam, 1))
cam_warn(cam, "Unable to alloc DMA buffers at load"
" will try again later.");
@@ -2233,13 +2235,16 @@ static int cafe_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct cafe_camera *cam = cafe_find_by_pdev(pdev);
int ret;
+ enum cafe_state cstate;
ret = pci_save_state(pdev);
if (ret)
return ret;
+ cstate = cam->state; /* HACK - stop_dma sets to idle */
cafe_ctlr_stop_dma(cam);
cafe_ctlr_power_down(cam);
pci_disable_device(pdev);
+ cam->state = cstate;
return 0;
}
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
index f065ad12cc6..cefd1381e8d 100644
--- a/drivers/media/video/compat_ioctl32.c
+++ b/drivers/media/video/compat_ioctl32.c
@@ -848,6 +848,8 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOCSFREQ32:
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
+ case VIDIOCGVBIFMT:
+ case VIDIOCSVBIFMT:
#endif
case VIDIOC_QUERYCAP:
case VIDIOC_ENUM_FMT:
@@ -874,7 +876,10 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOC_ENUMINPUT:
case VIDIOC_ENUMINPUT32:
case VIDIOC_G_CTRL:
+ case VIDIOC_S_CTRL:
case VIDIOC_S_CTRL32:
+ case VIDIOC_S_FREQUENCY:
+ case VIDIOC_G_FREQUENCY:
case VIDIOC_QUERYCTRL:
case VIDIOC_G_INPUT32:
case VIDIOC_S_INPUT32:
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 78c9699eafb..7c630f5ee72 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -28,7 +28,6 @@
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/vmalloc.h>
@@ -66,10 +65,6 @@ MODULE_PARM_DESC(colorspace_conv,
#define ABOUT "V4L-Driver for Vision CPiA based cameras"
-#ifndef VID_HARDWARE_CPIA
-#define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
-#endif
-
#define CPIA_MODULE_CPIA (0<<5)
#define CPIA_MODULE_SYSTEM (1<<5)
#define CPIA_MODULE_VP_CTRL (5<<5)
@@ -3805,7 +3800,6 @@ static struct video_device cpia_template = {
.owner = THIS_MODULE,
.name = "CPiA Camera",
.type = VID_TYPE_CAPTURE,
- .hardware = VID_HARDWARE_CPIA,
.fops = &cpia_fops,
};
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 92778cd1d73..e378abec806 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -37,7 +37,6 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
-#include <linux/moduleparam.h>
#include "cpia2.h"
#include "cpia2dev.h"
@@ -87,10 +86,6 @@ MODULE_LICENSE("GPL");
#define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
-#ifndef VID_HARDWARE_CPIA2
-#error "VID_HARDWARE_CPIA2 should have been defined in linux/videodev.h"
-#endif
-
struct control_menu_info {
int value;
char name[32];
@@ -1943,7 +1938,6 @@ static struct video_device cpia2_template = {
.type= VID_TYPE_CAPTURE,
.type2 = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING,
- .hardware= VID_HARDWARE_CPIA2,
.minor= -1,
.fops= &fops_template,
.release= video_device_release,
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index d73c86aeeaa..62304255dca 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -191,17 +190,21 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
/* Map the control ID to the correct field in the cx2341x_mpeg_params
struct. Return -EINVAL if the ID is unknown, else return 0. */
-static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
+static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
struct v4l2_ext_control *ctrl)
{
switch (ctrl->id) {
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ if (busy)
+ return -EBUSY;
params->audio_sampling_freq = ctrl->value;
break;
case V4L2_CID_MPEG_AUDIO_ENCODING:
params->audio_encoding = ctrl->value;
break;
case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ if (busy)
+ return -EBUSY;
params->audio_l2_bitrate = ctrl->value;
break;
case V4L2_CID_MPEG_AUDIO_MODE:
@@ -246,6 +249,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
params->video_gop_closure = ctrl->value;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ if (busy)
+ return -EBUSY;
/* MPEG-1 only allows CBR */
if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
@@ -253,9 +258,13 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
params->video_bitrate_mode = ctrl->value;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE:
+ if (busy)
+ return -EBUSY;
params->video_bitrate = ctrl->value;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ if (busy)
+ return -EBUSY;
params->video_bitrate_peak = ctrl->value;
break;
case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
@@ -268,6 +277,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
params->video_mute_yuv = ctrl->value;
break;
case V4L2_CID_MPEG_STREAM_TYPE:
+ if (busy)
+ return -EBUSY;
params->stream_type = ctrl->value;
params->video_encoding =
(params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
@@ -632,7 +643,7 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
(params->audio_crc << 14);
}
-int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
struct v4l2_ext_controls *ctrls, unsigned int cmd)
{
int err = 0;
@@ -664,7 +675,7 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
if (err)
break;
- err = cx2341x_set_ctrl(params, ctrl);
+ err = cx2341x_set_ctrl(params, busy, ctrl);
if (err)
break;
}
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
new file mode 100644
index 00000000000..d8b1ccb4491
--- /dev/null
+++ b/drivers/media/video/cx23885/Kconfig
@@ -0,0 +1,20 @@
+config VIDEO_CX23885
+ tristate "Conexant cx23885 (2388x successor) support"
+ depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT
+ select I2C_ALGOBIT
+ select FW_LOADER
+ select VIDEO_BTCX
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_IR
+ select VIDEOBUF_DVB
+ select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE
+ select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+ select DVB_PLL if !DVB_FE_CUSTOMISE
+ ---help---
+ This is a video4linux driver for Conexant 23885 based
+ TV cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx23885
+
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
new file mode 100644
index 00000000000..665067022d2
--- /dev/null
+++ b/drivers/media/video/cx23885/Makefile
@@ -0,0 +1,9 @@
+cx23885-objs := cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
+
+obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
new file mode 100644
index 00000000000..b9012acabb2
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -0,0 +1,280 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "cx23885.h"
+
+/* ------------------------------------------------------------------ */
+/* board config info */
+
+struct cx23885_board cx23885_boards[] = {
+ [CX23885_BOARD_UNKNOWN] = {
+ .name = "UNKNOWN/GENERIC",
+ .input = {{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = 0,
+ },{
+ .type = CX23885_VMUX_COMPOSITE2,
+ .vmux = 1,
+ },{
+ .type = CX23885_VMUX_COMPOSITE3,
+ .vmux = 2,
+ },{
+ .type = CX23885_VMUX_COMPOSITE4,
+ .vmux = 3,
+ }},
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1800lp] = {
+ .name = "Hauppauge WinTV-HVR1800lp",
+ .portc = CX23885_MPEG_DVB,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0xff00,
+ },{
+ .type = CX23885_VMUX_DEBUG,
+ .vmux = 0,
+ .gpio0 = 0xff01,
+ },{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0xff02,
+ },{
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0xff02,
+ }},
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1800] = {
+ .name = "Hauppauge WinTV-HVR1800",
+ .portc = CX23885_MPEG_DVB,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0xff00,
+ },{
+ .type = CX23885_VMUX_DEBUG,
+ .vmux = 0,
+ .gpio0 = 0xff01,
+ },{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0xff02,
+ },{
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0xff02,
+ }},
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1250] = {
+ .name = "Hauppauge WinTV-HVR1250",
+ .portc = CX23885_MPEG_DVB,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0xff00,
+ },{
+ .type = CX23885_VMUX_DEBUG,
+ .vmux = 0,
+ .gpio0 = 0xff01,
+ },{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0xff02,
+ },{
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0xff02,
+ }},
+ },
+ [CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = {
+ .name = "DViCO FusionHDTV5 Express",
+ .portb = CX23885_MPEG_DVB,
+ },
+};
+const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
+
+/* ------------------------------------------------------------------ */
+/* PCI subsystem IDs */
+
+struct cx23885_subid cx23885_subids[] = {
+ {
+ .subvendor = 0x0070,
+ .subdevice = 0x3400,
+ .card = CX23885_BOARD_UNKNOWN,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x7600,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1800lp,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x7800,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1800,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x7801,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1800,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x7911,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1250,
+ },{
+ .subvendor = 0x18ac,
+ .subdevice = 0xd500,
+ .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP,
+ },
+};
+const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
+
+void cx23885_card_list(struct cx23885_dev *dev)
+{
+ int i;
+
+ if (0 == dev->pci->subsystem_vendor &&
+ 0 == dev->pci->subsystem_device) {
+ printk("%s: Your board has no valid PCIe Subsystem ID and thus can't\n"
+ "%s: be autodetected. Please pass card=<n> insmod option to\n"
+ "%s: workaround that. Redirect complaints to the vendor of\n"
+ "%s: the TV card. Best regards,\n"
+ "%s: -- tux\n",
+ dev->name, dev->name, dev->name, dev->name, dev->name);
+ } else {
+ printk("%s: Your board isn't known (yet) to the driver. You can\n"
+ "%s: try to pick one of the existing card configs via\n"
+ "%s: card=<n> insmod option. Updating to the latest\n"
+ "%s: version might help as well.\n",
+ dev->name, dev->name, dev->name, dev->name);
+ }
+ printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+ dev->name);
+ for (i = 0; i < cx23885_bcount; i++)
+ printk("%s: card=%d -> %s\n",
+ dev->name, i, cx23885_boards[i].name);
+}
+
+static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
+{
+ struct tveeprom tv;
+
+ tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, eeprom_data);
+
+ /* Make sure we support the board model */
+ switch (tv.model)
+ {
+ case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */
+ case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
+ case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
+ case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
+ break;
+ default:
+ printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model);
+ break;
+ }
+
+ printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+ dev->name, tv.model);
+}
+
+void cx23885_gpio_setup(struct cx23885_dev *dev)
+{
+ switch(dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ /* GPIO-0 cx24227 demodulator reset */
+ cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ /* GPIO-0 656_CLK */
+ /* GPIO-1 656_D0 */
+ /* GPIO-2 8295A Reset */
+ /* GPIO-3-10 cx23417 data0-7 */
+ /* GPIO-11-14 cx23417 addr0-3 */
+ /* GPIO-15-18 cx23417 READY, CS, RD, WR */
+ /* GPIO-19 IR_RX */
+ // FIXME: Analog requires the tuner is brought out of reset
+ break;
+ }
+}
+
+int cx23885_ir_init(struct cx23885_dev *dev)
+{
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ /* FIXME: Implement me */
+ break;
+ }
+
+ return 0;
+}
+
+void cx23885_card_setup(struct cx23885_dev *dev)
+{
+ struct cx23885_tsport *ts1 = &dev->ts1;
+ struct cx23885_tsport *ts2 = &dev->ts2;
+
+ static u8 eeprom[256];
+
+ if (dev->i2c_bus[0].i2c_rc == 0) {
+ dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+ tveeprom_read(&dev->i2c_bus[0].i2c_client,
+ eeprom, sizeof(eeprom));
+ }
+
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ if (dev->i2c_bus[0].i2c_rc == 0)
+ hauppauge_eeprom(dev, eeprom+0x80);
+ break;
+ }
+
+ switch (dev->board) {
+ case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
+ ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ default:
+ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ }
+
+}
+
+/* ------------------------------------------------------------------ */
+
+EXPORT_SYMBOL(cx23885_boards);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
new file mode 100644
index 00000000000..3cdd136477e
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -0,0 +1,1526 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/div64.h>
+
+#include "cx23885.h"
+
+MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
+MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug = 0;
+module_param(debug,int,0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+module_param_array(card, int, NULL, 0444);
+MODULE_PARM_DESC(card,"card type");
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg)
+
+static unsigned int cx23885_devcount;
+
+static DEFINE_MUTEX(devlist);
+static LIST_HEAD(cx23885_devlist);
+
+#define NO_SYNC_LINE (-1U)
+
+/*
+ * CX23885 Assumptions
+ * 1 line = 16 bytes of CDT
+ * cmds size = 80
+ * cdt size = 16 * linesize
+ * iqsize = 64
+ * maxlines = 6
+ *
+ * Address Space:
+ * 0x00000000 0x00008fff FIFO clusters
+ * 0x00010000 0x000104af Channel Management Data Structures
+ * 0x000104b0 0x000104ff Free
+ * 0x00010500 0x000108bf 15 channels * iqsize
+ * 0x000108c0 0x000108ff Free
+ * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables
+ * 15 channels * (iqsize + (maxlines * linesize))
+ * 0x00010ea0 0x00010xxx Free
+ */
+
+struct sram_channel cx23885_sram_channels[] = {
+ [SRAM_CH01] = {
+ .name = "test ch1",
+ .cmds_start = 0x10000,
+ .ctrl_start = 0x10500,
+ .cdt = 0x10900,
+ .fifo_start = 0x3000,
+ .fifo_size = 0x1000,
+ .ptr1_reg = DMA1_PTR1,
+ .ptr2_reg = DMA1_PTR2,
+ .cnt1_reg = DMA1_CNT1,
+ .cnt2_reg = DMA1_CNT2,
+ .jumponly = 1,
+ },
+ [SRAM_CH02] = {
+ .name = "ch2",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA2_PTR1,
+ .ptr2_reg = DMA2_PTR2,
+ .cnt1_reg = DMA2_CNT1,
+ .cnt2_reg = DMA2_CNT2,
+ },
+ [SRAM_CH03] = {
+ .name = "TS1 B",
+ .cmds_start = 0x100A0,
+ .ctrl_start = 0x10780,
+ .cdt = 0x10400,
+ .fifo_start = 0x5000,
+ .fifo_size = 0x1000,
+ .ptr1_reg = DMA3_PTR1,
+ .ptr2_reg = DMA3_PTR2,
+ .cnt1_reg = DMA3_CNT1,
+ .cnt2_reg = DMA3_CNT2,
+ },
+ [SRAM_CH04] = {
+ .name = "ch4",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA4_PTR1,
+ .ptr2_reg = DMA4_PTR2,
+ .cnt1_reg = DMA4_CNT1,
+ .cnt2_reg = DMA4_CNT2,
+ },
+ [SRAM_CH05] = {
+ .name = "ch5",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA5_PTR1,
+ .ptr2_reg = DMA5_PTR2,
+ .cnt1_reg = DMA5_CNT1,
+ .cnt2_reg = DMA5_CNT2,
+ },
+ [SRAM_CH06] = {
+ .name = "TS2 C",
+ .cmds_start = 0x10140,
+ .ctrl_start = 0x10680,
+ .cdt = 0x10480,
+ .fifo_start = 0x6000,
+ .fifo_size = 0x1000,
+ .ptr1_reg = DMA5_PTR1,
+ .ptr2_reg = DMA5_PTR2,
+ .cnt1_reg = DMA5_CNT1,
+ .cnt2_reg = DMA5_CNT2,
+ },
+ [SRAM_CH07] = {
+ .name = "ch7",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA6_PTR1,
+ .ptr2_reg = DMA6_PTR2,
+ .cnt1_reg = DMA6_CNT1,
+ .cnt2_reg = DMA6_CNT2,
+ },
+ [SRAM_CH08] = {
+ .name = "ch8",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA7_PTR1,
+ .ptr2_reg = DMA7_PTR2,
+ .cnt1_reg = DMA7_CNT1,
+ .cnt2_reg = DMA7_CNT2,
+ },
+ [SRAM_CH09] = {
+ .name = "ch9",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA8_PTR1,
+ .ptr2_reg = DMA8_PTR2,
+ .cnt1_reg = DMA8_CNT1,
+ .cnt2_reg = DMA8_CNT2,
+ },
+};
+
+/* FIXME, these allocations will change when
+ * analog arrives. The be reviewed.
+ * CX23887 Assumptions
+ * 1 line = 16 bytes of CDT
+ * cmds size = 80
+ * cdt size = 16 * linesize
+ * iqsize = 64
+ * maxlines = 6
+ *
+ * Address Space:
+ * 0x00000000 0x00008fff FIFO clusters
+ * 0x00010000 0x000104af Channel Management Data Structures
+ * 0x000104b0 0x000104ff Free
+ * 0x00010500 0x000108bf 15 channels * iqsize
+ * 0x000108c0 0x000108ff Free
+ * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables
+ * 15 channels * (iqsize + (maxlines * linesize))
+ * 0x00010ea0 0x00010xxx Free
+ */
+
+struct sram_channel cx23887_sram_channels[] = {
+ [SRAM_CH01] = {
+ .name = "test ch1",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA1_PTR1,
+ .ptr2_reg = DMA1_PTR2,
+ .cnt1_reg = DMA1_CNT1,
+ .cnt2_reg = DMA1_CNT2,
+ },
+ [SRAM_CH02] = {
+ .name = "ch2",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA2_PTR1,
+ .ptr2_reg = DMA2_PTR2,
+ .cnt1_reg = DMA2_CNT1,
+ .cnt2_reg = DMA2_CNT2,
+ },
+ [SRAM_CH03] = {
+ .name = "ch3",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA3_PTR1,
+ .ptr2_reg = DMA3_PTR2,
+ .cnt1_reg = DMA3_CNT1,
+ .cnt2_reg = DMA3_CNT2,
+ },
+ [SRAM_CH04] = {
+ .name = "ch4",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA4_PTR1,
+ .ptr2_reg = DMA4_PTR2,
+ .cnt1_reg = DMA4_CNT1,
+ .cnt2_reg = DMA4_CNT2,
+ },
+ [SRAM_CH05] = {
+ .name = "ch5",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA5_PTR1,
+ .ptr2_reg = DMA5_PTR2,
+ .cnt1_reg = DMA5_CNT1,
+ .cnt2_reg = DMA5_CNT2,
+ },
+ [SRAM_CH06] = {
+ .name = "TS2 C",
+ .cmds_start = 0x10140,
+ .ctrl_start = 0x10680,
+ .cdt = 0x108d0,
+ .fifo_start = 0x6000,
+ .fifo_size = 0x1000,
+ .ptr1_reg = DMA5_PTR1,
+ .ptr2_reg = DMA5_PTR2,
+ .cnt1_reg = DMA5_CNT1,
+ .cnt2_reg = DMA5_CNT2,
+ },
+ [SRAM_CH07] = {
+ .name = "ch7",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA6_PTR1,
+ .ptr2_reg = DMA6_PTR2,
+ .cnt1_reg = DMA6_CNT1,
+ .cnt2_reg = DMA6_CNT2,
+ },
+ [SRAM_CH08] = {
+ .name = "ch8",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA7_PTR1,
+ .ptr2_reg = DMA7_PTR2,
+ .cnt1_reg = DMA7_CNT1,
+ .cnt2_reg = DMA7_CNT2,
+ },
+ [SRAM_CH09] = {
+ .name = "ch9",
+ .cmds_start = 0x0,
+ .ctrl_start = 0x0,
+ .cdt = 0x0,
+ .fifo_start = 0x0,
+ .fifo_size = 0x0,
+ .ptr1_reg = DMA8_PTR1,
+ .ptr2_reg = DMA8_PTR2,
+ .cnt1_reg = DMA8_CNT1,
+ .cnt2_reg = DMA8_CNT2,
+ },
+};
+
+static int cx23885_risc_decode(u32 risc)
+{
+ static char *instr[16] = {
+ [ RISC_SYNC >> 28 ] = "sync",
+ [ RISC_WRITE >> 28 ] = "write",
+ [ RISC_WRITEC >> 28 ] = "writec",
+ [ RISC_READ >> 28 ] = "read",
+ [ RISC_READC >> 28 ] = "readc",
+ [ RISC_JUMP >> 28 ] = "jump",
+ [ RISC_SKIP >> 28 ] = "skip",
+ [ RISC_WRITERM >> 28 ] = "writerm",
+ [ RISC_WRITECM >> 28 ] = "writecm",
+ [ RISC_WRITECR >> 28 ] = "writecr",
+ };
+ static int incr[16] = {
+ [ RISC_WRITE >> 28 ] = 3,
+ [ RISC_JUMP >> 28 ] = 3,
+ [ RISC_SKIP >> 28 ] = 1,
+ [ RISC_SYNC >> 28 ] = 1,
+ [ RISC_WRITERM >> 28 ] = 3,
+ [ RISC_WRITECM >> 28 ] = 3,
+ [ RISC_WRITECR >> 28 ] = 4,
+ };
+ static char *bits[] = {
+ "12", "13", "14", "resync",
+ "cnt0", "cnt1", "18", "19",
+ "20", "21", "22", "23",
+ "irq1", "irq2", "eol", "sol",
+ };
+ int i;
+
+ printk("0x%08x [ %s", risc,
+ instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
+ for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--)
+ if (risc & (1 << (i + 12)))
+ printk(" %s", bits[i]);
+ printk(" count=%d ]\n", risc & 0xfff);
+ return incr[risc >> 28] ? incr[risc >> 28] : 1;
+}
+
+void cx23885_wakeup(struct cx23885_tsport *port,
+ struct cx23885_dmaqueue *q, u32 count)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_buffer *buf;
+ int bc;
+
+ for (bc = 0;; bc++) {
+ if (list_empty(&q->active))
+ break;
+ buf = list_entry(q->active.next,
+ struct cx23885_buffer, vb.queue);
+
+ /* count comes from the hw and is is 16bit wide --
+ * this trick handles wrap-arounds correctly for
+ * up to 32767 buffers in flight... */
+ if ((s16) (count - buf->count) < 0)
+ break;
+
+ do_gettimeofday(&buf->vb.ts);
+ dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
+ count, buf->count);
+ buf->vb.state = STATE_DONE;
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+ }
+ if (list_empty(&q->active)) {
+ del_timer(&q->timeout);
+ } else {
+ mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+ }
+ if (bc != 1)
+ printk("%s: %d buffers handled (should be 1)\n",
+ __FUNCTION__, bc);
+}
+void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+ struct sram_channel *ch);
+
+int cx23885_sram_channel_setup(struct cx23885_dev *dev,
+ struct sram_channel *ch,
+ unsigned int bpl, u32 risc)
+{
+ unsigned int i, lines;
+ u32 cdt;
+
+ if (ch->cmds_start == 0)
+ {
+ dprintk(1, "%s() Erasing channel [%s]\n", __FUNCTION__,
+ ch->name);
+ cx_write(ch->ptr1_reg, 0);
+ cx_write(ch->ptr2_reg, 0);
+ cx_write(ch->cnt2_reg, 0);
+ cx_write(ch->cnt1_reg, 0);
+ return 0;
+ } else {
+ dprintk(1, "%s() Configuring channel [%s]\n", __FUNCTION__,
+ ch->name);
+ }
+
+ bpl = (bpl + 7) & ~7; /* alignment */
+ cdt = ch->cdt;
+ lines = ch->fifo_size / bpl;
+ if (lines > 6)
+ lines = 6;
+ BUG_ON(lines < 2);
+
+ cx_write(8 + 0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) );
+ cx_write(8 + 4, cpu_to_le32(8) );
+ cx_write(8 + 8, cpu_to_le32(0) );
+
+ /* write CDT */
+ for (i = 0; i < lines; i++) {
+ dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i,
+ ch->fifo_start + bpl*i);
+ cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
+ cx_write(cdt + 16*i + 4, 0);
+ cx_write(cdt + 16*i + 8, 0);
+ cx_write(cdt + 16*i + 12, 0);
+ }
+
+ /* write CMDS */
+ if (ch->jumponly)
+ cx_write(ch->cmds_start + 0, 8);
+ else
+ cx_write(ch->cmds_start + 0, risc);
+ cx_write(ch->cmds_start + 4, 0); /* 64 bits 63-32 */
+ cx_write(ch->cmds_start + 8, cdt);
+ cx_write(ch->cmds_start + 12, (lines*16) >> 3);
+ cx_write(ch->cmds_start + 16, ch->ctrl_start);
+ if (ch->jumponly)
+ cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2) );
+ else
+ cx_write(ch->cmds_start + 20, 64 >> 2);
+ for (i = 24; i < 80; i += 4)
+ cx_write(ch->cmds_start + i, 0);
+
+ /* fill registers */
+ cx_write(ch->ptr1_reg, ch->fifo_start);
+ cx_write(ch->ptr2_reg, cdt);
+ cx_write(ch->cnt2_reg, (lines*16) >> 3);
+ cx_write(ch->cnt1_reg, (bpl >> 3) -1);
+
+ dprintk(2,"[bridge %d] sram setup %s: bpl=%d lines=%d\n",
+ dev->bridge,
+ ch->name,
+ bpl,
+ lines);
+
+ return 0;
+}
+
+void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+ struct sram_channel *ch)
+{
+ static char *name[] = {
+ "init risc lo",
+ "init risc hi",
+ "cdt base",
+ "cdt size",
+ "iq base",
+ "iq size",
+ "risc pc lo",
+ "risc pc hi",
+ "iq wr ptr",
+ "iq rd ptr",
+ "cdt current",
+ "pci target lo",
+ "pci target hi",
+ "line / byte",
+ };
+ u32 risc;
+ unsigned int i, j, n;
+
+ printk("%s: %s - dma channel status dump\n",
+ dev->name, ch->name);
+ for (i = 0; i < ARRAY_SIZE(name); i++)
+ printk("%s: cmds: %-15s: 0x%08x\n",
+ dev->name, name[i],
+ cx_read(ch->cmds_start + 4*i));
+
+ for (i = 0; i < 4; i++) {
+ risc = cx_read(ch->cmds_start + 4 * (i + 14));
+ printk("%s: risc%d: ", dev->name, i);
+ cx23885_risc_decode(risc);
+ }
+ for (i = 0; i < (64 >> 2); i += n) {
+ risc = cx_read(ch->ctrl_start + 4 * i);
+ /* No consideration for bits 63-32 */
+
+ printk("%s: (0x%08x) iq %x: ", dev->name,
+ ch->ctrl_start + 4 * i, i);
+ n = cx23885_risc_decode(risc);
+ for (j = 1; j < n; j++) {
+ risc = cx_read(ch->ctrl_start + 4 * (i + j));
+ printk("%s: iq %x: 0x%08x [ arg #%d ]\n",
+ dev->name, i+j, risc, j);
+ }
+ }
+
+ printk("%s: fifo: 0x%08x -> 0x%x\n",
+ dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
+ printk("%s: ctrl: 0x%08x -> 0x%x\n",
+ dev->name, ch->ctrl_start, ch->ctrl_start + 6*16);
+ printk("%s: ptr1_reg: 0x%08x\n",
+ dev->name, cx_read(ch->ptr1_reg));
+ printk("%s: ptr2_reg: 0x%08x\n",
+ dev->name, cx_read(ch->ptr2_reg));
+ printk("%s: cnt1_reg: 0x%08x\n",
+ dev->name, cx_read(ch->cnt1_reg));
+ printk("%s: cnt2_reg: 0x%08x\n",
+ dev->name, cx_read(ch->cnt2_reg));
+}
+
+void cx23885_risc_disasm(struct cx23885_tsport *port,
+ struct btcx_riscmem *risc)
+{
+ struct cx23885_dev *dev = port->dev;
+ unsigned int i, j, n;
+
+ printk("%s: risc disasm: %p [dma=0x%08lx]\n",
+ dev->name, risc->cpu, (unsigned long)risc->dma);
+ for (i = 0; i < (risc->size >> 2); i += n) {
+ printk("%s: %04d: ", dev->name, i);
+ n = cx23885_risc_decode(risc->cpu[i]);
+ for (j = 1; j < n; j++)
+ printk("%s: %04d: 0x%08x [ arg #%d ]\n",
+ dev->name, i + j, risc->cpu[i + j], j);
+ if (risc->cpu[i] == RISC_JUMP)
+ break;
+ }
+}
+
+void cx23885_shutdown(struct cx23885_dev *dev)
+{
+ /* disable RISC controller */
+ cx_write(DEV_CNTRL2, 0);
+
+ /* Disable all IR activity */
+ cx_write(IR_CNTRL_REG, 0);
+
+ /* Disable Video A/B activity */
+ cx_write(VID_A_DMA_CTL, 0);
+ cx_write(VID_B_DMA_CTL, 0);
+ cx_write(VID_C_DMA_CTL, 0);
+
+ /* Disable Audio activity */
+ cx_write(AUD_INT_DMA_CTL, 0);
+ cx_write(AUD_EXT_DMA_CTL, 0);
+
+ /* Disable Serial port */
+ cx_write(UART_CTL, 0);
+
+ /* Disable Interrupts */
+ cx_write(PCI_INT_MSK, 0);
+ cx_write(VID_A_INT_MSK, 0);
+ cx_write(VID_B_INT_MSK, 0);
+ cx_write(VID_C_INT_MSK, 0);
+ cx_write(AUDIO_INT_INT_MSK, 0);
+ cx_write(AUDIO_EXT_INT_MSK, 0);
+
+}
+
+void cx23885_reset(struct cx23885_dev *dev)
+{
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ cx23885_shutdown(dev);
+
+ cx_write(PCI_INT_STAT, 0xffffffff);
+ cx_write(VID_A_INT_STAT, 0xffffffff);
+ cx_write(VID_B_INT_STAT, 0xffffffff);
+ cx_write(VID_C_INT_STAT, 0xffffffff);
+ cx_write(AUDIO_INT_INT_STAT, 0xffffffff);
+ cx_write(AUDIO_EXT_INT_STAT, 0xffffffff);
+ cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000);
+
+ mdelay(100);
+
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 188*4, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0);
+ cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0);
+
+ cx23885_gpio_setup(dev);
+}
+
+
+static int cx23885_pci_quirks(struct cx23885_dev *dev)
+{
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ /* The cx23885 bridge has a weird bug which causes NMI to be asserted
+ * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not
+ * occur on the cx23887 bridge.
+ */
+ if(dev->bridge == CX23885_BRIDGE_885)
+ cx_clear(RDR_TLCTL0, 1 << 4);
+
+ return 0;
+}
+
+static int get_resources(struct cx23885_dev *dev)
+{
+ if (request_mem_region(pci_resource_start(dev->pci,0),
+ pci_resource_len(dev->pci,0),
+ dev->name))
+ return 0;
+
+ printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+ dev->name, (unsigned long long)pci_resource_start(dev->pci,0));
+
+ return -EBUSY;
+}
+
+static void cx23885_timeout(unsigned long data);
+int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+ u32 reg, u32 mask, u32 value);
+
+static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno)
+{
+ dprintk(1, "%s(portno=%d)\n", __FUNCTION__, portno);
+
+ /* Transport bus init dma queue - Common settings */
+ port->dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */
+ port->ts_int_msk_val = 0x1111; /* TS port bits for RISC */
+
+ spin_lock_init(&port->slock);
+ port->dev = dev;
+ port->nr = portno;
+
+ INIT_LIST_HEAD(&port->mpegq.active);
+ INIT_LIST_HEAD(&port->mpegq.queued);
+ port->mpegq.timeout.function = cx23885_timeout;
+ port->mpegq.timeout.data = (unsigned long)port;
+ init_timer(&port->mpegq.timeout);
+
+ switch(portno) {
+ case 1:
+ port->reg_gpcnt = VID_B_GPCNT;
+ port->reg_gpcnt_ctl = VID_B_GPCNT_CTL;
+ port->reg_dma_ctl = VID_B_DMA_CTL;
+ port->reg_lngth = VID_B_LNGTH;
+ port->reg_hw_sop_ctrl = VID_B_HW_SOP_CTL;
+ port->reg_gen_ctrl = VID_B_GEN_CTL;
+ port->reg_bd_pkt_status = VID_B_BD_PKT_STATUS;
+ port->reg_sop_status = VID_B_SOP_STATUS;
+ port->reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT;
+ port->reg_vld_misc = VID_B_VLD_MISC;
+ port->reg_ts_clk_en = VID_B_TS_CLK_EN;
+ port->reg_src_sel = VID_B_SRC_SEL;
+ port->reg_ts_int_msk = VID_B_INT_MSK;
+ port->reg_ts_int_stat = VID_B_INT_STAT;
+ port->sram_chno = SRAM_CH03; /* VID_B */
+ port->pci_irqmask = 0x02; /* VID_B bit1 */
+ break;
+ case 2:
+ port->reg_gpcnt = VID_C_GPCNT;
+ port->reg_gpcnt_ctl = VID_C_GPCNT_CTL;
+ port->reg_dma_ctl = VID_C_DMA_CTL;
+ port->reg_lngth = VID_C_LNGTH;
+ port->reg_hw_sop_ctrl = VID_C_HW_SOP_CTL;
+ port->reg_gen_ctrl = VID_C_GEN_CTL;
+ port->reg_bd_pkt_status = VID_C_BD_PKT_STATUS;
+ port->reg_sop_status = VID_C_SOP_STATUS;
+ port->reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT;
+ port->reg_vld_misc = VID_C_VLD_MISC;
+ port->reg_ts_clk_en = VID_C_TS_CLK_EN;
+ port->reg_src_sel = 0;
+ port->reg_ts_int_msk = VID_C_INT_MSK;
+ port->reg_ts_int_stat = VID_C_INT_STAT;
+ port->sram_chno = SRAM_CH06; /* VID_C */
+ port->pci_irqmask = 0x04; /* VID_C bit2 */
+ break;
+ default:
+ BUG();
+ }
+
+ cx23885_risc_stopper(dev->pci, &port->mpegq.stopper,
+ port->reg_dma_ctl, port->dma_ctl_val, 0x00);
+
+ return 0;
+}
+
+static int cx23885_dev_setup(struct cx23885_dev *dev)
+{
+ int i;
+
+ mutex_init(&dev->lock);
+
+ atomic_inc(&dev->refcount);
+
+ dev->nr = cx23885_devcount++;
+ sprintf(dev->name, "cx23885[%d]", dev->nr);
+
+ mutex_lock(&devlist);
+ list_add_tail(&dev->devlist, &cx23885_devlist);
+ mutex_unlock(&devlist);
+
+ /* Configure the internal memory */
+ if(dev->pci->device == 0x8880) {
+ dev->bridge = CX23885_BRIDGE_887;
+ dev->sram_channels = cx23887_sram_channels;
+ } else
+ if(dev->pci->device == 0x8852) {
+ dev->bridge = CX23885_BRIDGE_885;
+ dev->sram_channels = cx23885_sram_channels;
+ } else
+ BUG();
+
+ dprintk(1, "%s() Memory configured for PCIe bridge type %d\n",
+ __FUNCTION__, dev->bridge);
+
+ /* board config */
+ dev->board = UNSET;
+ if (card[dev->nr] < cx23885_bcount)
+ dev->board = card[dev->nr];
+ for (i = 0; UNSET == dev->board && i < cx23885_idcount; i++)
+ if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor &&
+ dev->pci->subsystem_device == cx23885_subids[i].subdevice)
+ dev->board = cx23885_subids[i].card;
+ if (UNSET == dev->board) {
+ dev->board = CX23885_BOARD_UNKNOWN;
+ cx23885_card_list(dev);
+ }
+
+ dev->pci_bus = dev->pci->bus->number;
+ dev->pci_slot = PCI_SLOT(dev->pci->devfn);
+ dev->pci_irqmask = 0x001f00;
+
+ /* External Master 1 Bus */
+ dev->i2c_bus[0].nr = 0;
+ dev->i2c_bus[0].dev = dev;
+ dev->i2c_bus[0].reg_stat = I2C1_STAT;
+ dev->i2c_bus[0].reg_ctrl = I2C1_CTRL;
+ dev->i2c_bus[0].reg_addr = I2C1_ADDR;
+ dev->i2c_bus[0].reg_rdata = I2C1_RDATA;
+ dev->i2c_bus[0].reg_wdata = I2C1_WDATA;
+ dev->i2c_bus[0].i2c_period = (0x9d << 24); /* 100kHz */
+
+ /* External Master 2 Bus */
+ dev->i2c_bus[1].nr = 1;
+ dev->i2c_bus[1].dev = dev;
+ dev->i2c_bus[1].reg_stat = I2C2_STAT;
+ dev->i2c_bus[1].reg_ctrl = I2C2_CTRL;
+ dev->i2c_bus[1].reg_addr = I2C2_ADDR;
+ dev->i2c_bus[1].reg_rdata = I2C2_RDATA;
+ dev->i2c_bus[1].reg_wdata = I2C2_WDATA;
+ dev->i2c_bus[1].i2c_period = (0x9d << 24); /* 100kHz */
+
+ /* Internal Master 3 Bus */
+ dev->i2c_bus[2].nr = 2;
+ dev->i2c_bus[2].dev = dev;
+ dev->i2c_bus[2].reg_stat = I2C3_STAT;
+ dev->i2c_bus[2].reg_ctrl = I2C3_CTRL;
+ dev->i2c_bus[2].reg_addr = I2C3_ADDR;
+ dev->i2c_bus[2].reg_rdata = I2C3_RDATA;
+ dev->i2c_bus[2].reg_wdata = I2C3_WDATA;
+ dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */
+
+ if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+ cx23885_init_tsport(dev, &dev->ts1, 1);
+
+ if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+ cx23885_init_tsport(dev, &dev->ts2, 2);
+
+ if (get_resources(dev) < 0) {
+ printk(KERN_ERR "CORE %s No more PCIe resources for "
+ "subsystem: %04x:%04x\n",
+ dev->name, dev->pci->subsystem_vendor,
+ dev->pci->subsystem_device);
+
+ cx23885_devcount--;
+ return -ENODEV;
+ }
+
+ /* PCIe stuff */
+ dev->lmmio = ioremap(pci_resource_start(dev->pci,0),
+ pci_resource_len(dev->pci,0));
+
+ dev->bmmio = (u8 __iomem *)dev->lmmio;
+
+ printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ dev->name, dev->pci->subsystem_vendor,
+ dev->pci->subsystem_device, cx23885_boards[dev->board].name,
+ dev->board, card[dev->nr] == dev->board ?
+ "insmod option" : "autodetected");
+
+ cx23885_pci_quirks(dev);
+
+ /* init hardware */
+ cx23885_reset(dev);
+
+ cx23885_i2c_register(&dev->i2c_bus[0]);
+ cx23885_i2c_register(&dev->i2c_bus[1]);
+ cx23885_i2c_register(&dev->i2c_bus[2]);
+ cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
+ cx23885_card_setup(dev);
+ cx23885_ir_init(dev);
+
+ if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
+ if (cx23885_dvb_register(&dev->ts1) < 0) {
+ printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n",
+ __FUNCTION__);
+ }
+ }
+
+ if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
+ if (cx23885_dvb_register(&dev->ts2) < 0) {
+ printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n",
+ __FUNCTION__);
+ }
+ }
+
+ return 0;
+}
+
+void cx23885_dev_unregister(struct cx23885_dev *dev)
+{
+ release_mem_region(pci_resource_start(dev->pci,0),
+ pci_resource_len(dev->pci,0));
+
+ if (!atomic_dec_and_test(&dev->refcount))
+ return;
+
+ if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+ cx23885_dvb_unregister(&dev->ts1);
+
+ if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+ cx23885_dvb_unregister(&dev->ts2);
+
+ cx23885_i2c_unregister(&dev->i2c_bus[2]);
+ cx23885_i2c_unregister(&dev->i2c_bus[1]);
+ cx23885_i2c_unregister(&dev->i2c_bus[0]);
+
+ iounmap(dev->lmmio);
+}
+
+static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist,
+ unsigned int offset, u32 sync_line,
+ unsigned int bpl, unsigned int padding,
+ unsigned int lines)
+{
+ struct scatterlist *sg;
+ unsigned int line, todo;
+
+ /* sync instruction */
+ if (sync_line != NO_SYNC_LINE)
+ *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
+
+ /* scan lines */
+ sg = sglist;
+ for (line = 0; line < lines; line++) {
+ while (offset && offset >= sg_dma_len(sg)) {
+ offset -= sg_dma_len(sg);
+ sg++;
+ }
+ if (bpl <= sg_dma_len(sg)-offset) {
+ /* fits into current chunk */
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+ offset+=bpl;
+ } else {
+ /* scanline needs to be split */
+ todo = bpl;
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+ (sg_dma_len(sg)-offset));
+ *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+ *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+ todo -= (sg_dma_len(sg)-offset);
+ offset = 0;
+ sg++;
+ while (todo > sg_dma_len(sg)) {
+ *(rp++)=cpu_to_le32(RISC_WRITE|
+ sg_dma_len(sg));
+ *(rp++)=cpu_to_le32(sg_dma_address(sg));
+ *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+ todo -= sg_dma_len(sg);
+ sg++;
+ }
+ *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
+ *(rp++)=cpu_to_le32(sg_dma_address(sg));
+ *(rp++)=cpu_to_le32(0); /* bits 63-32 */
+ offset += todo;
+ }
+ offset += padding;
+ }
+
+ return rp;
+}
+
+int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+ struct scatterlist *sglist, unsigned int top_offset,
+ unsigned int bottom_offset, unsigned int bpl,
+ unsigned int padding, unsigned int lines)
+{
+ u32 instructions, fields;
+ u32 *rp;
+ int rc;
+
+ fields = 0;
+ if (UNSET != top_offset)
+ fields++;
+ if (UNSET != bottom_offset)
+ fields++;
+
+ /* estimate risc mem: worst case is one write per page border +
+ one write per scan line + syncs + jump (all 2 dwords). Padding
+ can cause next bpl to start close to a page border. First DMA
+ region may be smaller than PAGE_SIZE */
+ /* write and jump need and extra dword */
+ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
+ instructions += 2;
+ if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0)
+ return rc;
+
+ /* write risc instructions */
+ rp = risc->cpu;
+ if (UNSET != top_offset)
+ rp = cx23885_risc_field(rp, sglist, top_offset, 0,
+ bpl, padding, lines);
+ if (UNSET != bottom_offset)
+ rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
+ bpl, padding, lines);
+
+ /* save pointer to jmp instruction address */
+ risc->jmp = rp;
+ BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+ return 0;
+}
+
+int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+ struct scatterlist *sglist, unsigned int bpl,
+ unsigned int lines)
+{
+ u32 instructions;
+ u32 *rp;
+ int rc;
+
+ /* estimate risc mem: worst case is one write per page border +
+ one write per scan line + syncs + jump (all 2 dwords). Here
+ there is no padding and no sync. First DMA region may be smaller
+ than PAGE_SIZE */
+ /* Jump and write need an extra dword */
+ instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
+ instructions += 1;
+
+ if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0)
+ return rc;
+
+ /* write risc instructions */
+ rp = risc->cpu;
+ rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
+
+ /* save pointer to jmp instruction address */
+ risc->jmp = rp;
+ BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+ return 0;
+}
+
+int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+ u32 reg, u32 mask, u32 value)
+{
+ u32 *rp;
+ int rc;
+
+ if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
+ return rc;
+
+ /* write risc instructions */
+ rp = risc->cpu;
+ *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2);
+ *(rp++) = cpu_to_le32(reg);
+ *(rp++) = cpu_to_le32(value);
+ *(rp++) = cpu_to_le32(mask);
+ *(rp++) = cpu_to_le32(RISC_JUMP);
+ *(rp++) = cpu_to_le32(risc->dma);
+ *(rp++) = cpu_to_le32(0); /* bits 63-32 */
+ return 0;
+}
+
+void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
+{
+ struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+
+ BUG_ON(in_interrupt());
+ videobuf_waiton(&buf->vb, 0, 0);
+ videobuf_dma_unmap(q, dma);
+ videobuf_dma_free(dma);
+ btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
+ buf->vb.state = STATE_NEEDS_INIT;
+}
+
+static int cx23885_start_dma(struct cx23885_tsport *port,
+ struct cx23885_dmaqueue *q,
+ struct cx23885_buffer *buf)
+{
+ struct cx23885_dev *dev = port->dev;
+
+ dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__,
+ buf->vb.width, buf->vb.height, buf->vb.field);
+
+ /* setup fifo + format */
+ cx23885_sram_channel_setup(dev,
+ &dev->sram_channels[ port->sram_chno ],
+ port->ts_packet_size, buf->risc.dma);
+ if(debug > 5) {
+ cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] );
+ cx23885_risc_disasm(port, &buf->risc);
+ }
+
+ /* write TS length to chip */
+ cx_write(port->reg_lngth, buf->vb.width);
+
+ if ( (!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
+ (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) ) {
+ printk( "%s() Failed. Unsupported value in .portb/c (0x%08x)/(0x%08x)\n",
+ __FUNCTION__,
+ cx23885_boards[dev->board].portb,
+ cx23885_boards[dev->board].portc );
+ return -EINVAL;
+ }
+
+ udelay(100);
+
+ /* If the port supports SRC SELECT, configure it */
+ if(port->reg_src_sel)
+ cx_write(port->reg_src_sel, port->src_sel_val);
+
+ cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4);
+ cx_write(port->reg_ts_clk_en, port->ts_clk_en_val);
+ cx_write(port->reg_vld_misc, 0x00);
+ cx_write(port->reg_gen_ctrl, port->gen_ctrl_val);
+ udelay(100);
+
+ // NOTE: this is 2 (reserved) for portb, does it matter?
+ /* reset counter to zero */
+ cx_write(port->reg_gpcnt_ctl, 3);
+ q->count = 1;
+
+ switch(dev->bridge) {
+ case CX23885_BRIDGE_885:
+ case CX23885_BRIDGE_887:
+ /* enable irqs */
+ dprintk(1, "%s() enabling TS int's and DMA\n", __FUNCTION__ );
+ cx_set(port->reg_ts_int_msk, port->ts_int_msk_val);
+ cx_set(port->reg_dma_ctl, port->dma_ctl_val);
+ cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask);
+ break;
+ default:
+ BUG();
+ }
+
+ cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
+
+ return 0;
+}
+
+static int cx23885_stop_dma(struct cx23885_tsport *port)
+{
+ struct cx23885_dev *dev = port->dev;
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ /* Stop interrupts and DMA */
+ cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val);
+ cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+
+ return 0;
+}
+
+static int cx23885_restart_queue(struct cx23885_tsport *port,
+ struct cx23885_dmaqueue *q)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_buffer *buf;
+
+ dprintk(5, "%s()\n", __FUNCTION__);
+ if (list_empty(&q->active))
+ {
+ struct cx23885_buffer *prev;
+ prev = NULL;
+
+ dprintk(5, "%s() queue is empty\n", __FUNCTION__);
+
+ for (;;) {
+ if (list_empty(&q->queued))
+ return 0;
+ buf = list_entry(q->queued.next, struct cx23885_buffer,
+ vb.queue);
+ if (NULL == prev) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue, &q->active);
+ cx23885_start_dma(port, q, buf);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(5, "[%p/%d] restart_queue - first active\n",
+ buf, buf->vb.i);
+
+ } else if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue, &q->active);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
+ dprintk(5,"[%p/%d] restart_queue - move to active\n",
+ buf, buf->vb.i);
+ } else {
+ return 0;
+ }
+ prev = buf;
+ }
+ return 0;
+ }
+
+ buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
+ dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+ buf, buf->vb.i);
+ cx23885_start_dma(port, q, buf);
+ list_for_each_entry(buf, &q->active, vb.queue)
+ buf->count = q->count++;
+ mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
+ struct cx23885_buffer *buf, enum v4l2_field field)
+{
+ struct cx23885_dev *dev = port->dev;
+ int size = port->ts_packet_size * port->ts_packet_count;
+ int rc;
+
+ dprintk(1, "%s: %p\n", __FUNCTION__, buf);
+ if (0 != buf->vb.baddr && buf->vb.bsize < size)
+ return -EINVAL;
+
+ if (STATE_NEEDS_INIT == buf->vb.state) {
+ buf->vb.width = port->ts_packet_size;
+ buf->vb.height = port->ts_packet_count;
+ buf->vb.size = size;
+ buf->vb.field = field /*V4L2_FIELD_TOP*/;
+
+ if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
+ goto fail;
+ cx23885_risc_databuffer(dev->pci, &buf->risc,
+ videobuf_to_dma(&buf->vb)->sglist,
+ buf->vb.width, buf->vb.height);
+ }
+ buf->vb.state = STATE_PREPARED;
+ return 0;
+
+ fail:
+ cx23885_free_buffer(q, buf);
+ return rc;
+}
+
+void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
+{
+ struct cx23885_buffer *prev;
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_dmaqueue *cx88q = &port->mpegq;
+
+ /* add jump to stopper */
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+ buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
+ buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+ if (list_empty(&cx88q->active)) {
+ dprintk( 1, "queue is empty - first active\n" );
+ list_add_tail(&buf->vb.queue, &cx88q->active);
+ cx23885_start_dma(port, cx88q, buf);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = cx88q->count++;
+ mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
+ dprintk(1, "[%p/%d] %s - first active\n",
+ buf, buf->vb.i, __FUNCTION__);
+ } else {
+ dprintk( 1, "queue is not empty - append to active\n" );
+ prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
+ vb.queue);
+ list_add_tail(&buf->vb.queue, &cx88q->active);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = cx88q->count++;
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
+ dprintk( 1, "[%p/%d] %s - append to active\n",
+ buf, buf->vb.i, __FUNCTION__);
+ }
+}
+
+/* ----------------------------------------------------------- */
+
+static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
+ int restart)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_dmaqueue *q = &port->mpegq;
+ struct cx23885_buffer *buf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->slock, flags);
+ while (!list_empty(&q->active)) {
+ buf = list_entry(q->active.next, struct cx23885_buffer,
+ vb.queue);
+ list_del(&buf->vb.queue);
+ buf->vb.state = STATE_ERROR;
+ wake_up(&buf->vb.done);
+ dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
+ buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
+ }
+ if (restart) {
+ dprintk(1, "restarting queue\n" );
+ cx23885_restart_queue(port, q);
+ }
+ spin_unlock_irqrestore(&port->slock, flags);
+}
+
+void cx23885_cancel_buffers(struct cx23885_tsport *port)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_dmaqueue *q = &port->mpegq;
+
+ dprintk(1, "%s()\n", __FUNCTION__);
+ del_timer_sync(&q->timeout);
+ cx23885_stop_dma(port);
+ do_cancel_buffers(port, "cancel", 0);
+}
+
+static void cx23885_timeout(unsigned long data)
+{
+ struct cx23885_tsport *port = (struct cx23885_tsport *)data;
+ struct cx23885_dev *dev = port->dev;
+
+ dprintk(1, "%s()\n",__FUNCTION__);
+
+ if (debug > 5)
+ cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
+
+ cx23885_stop_dma(port);
+ do_cancel_buffers(port, "timeout", 1);
+}
+
+static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
+{
+ struct cx23885_dev *dev = port->dev;
+ int handled = 0;
+ u32 count;
+
+ if ( (status & VID_BC_MSK_OPC_ERR) ||
+ (status & VID_BC_MSK_BAD_PKT) ||
+ (status & VID_BC_MSK_SYNC) ||
+ (status & VID_BC_MSK_OF))
+ {
+ if (status & VID_BC_MSK_OPC_ERR)
+ dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR);
+ if (status & VID_BC_MSK_BAD_PKT)
+ dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", VID_BC_MSK_BAD_PKT);
+ if (status & VID_BC_MSK_SYNC)
+ dprintk(7, " (VID_BC_MSK_SYNC 0x%08x)\n", VID_BC_MSK_SYNC);
+ if (status & VID_BC_MSK_OF)
+ dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", VID_BC_MSK_OF);
+
+ printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name);
+
+ cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+ cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
+
+ } else if (status & VID_BC_MSK_RISCI1) {
+
+ dprintk(7, " (RISCI1 0x%08x)\n", VID_BC_MSK_RISCI1);
+
+ spin_lock(&port->slock);
+ count = cx_read(port->reg_gpcnt);
+ cx23885_wakeup(port, &port->mpegq, count);
+ spin_unlock(&port->slock);
+
+ } else if (status & VID_BC_MSK_RISCI2) {
+
+ dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2);
+
+ spin_lock(&port->slock);
+ cx23885_restart_queue(port, &port->mpegq);
+ spin_unlock(&port->slock);
+
+ }
+ if (status) {
+ cx_write(port->reg_ts_int_stat, status);
+ handled = 1;
+ }
+
+ return handled;
+}
+
+static irqreturn_t cx23885_irq(int irq, void *dev_id)
+{
+ struct cx23885_dev *dev = dev_id;
+ struct cx23885_tsport *ts1 = &dev->ts1;
+ struct cx23885_tsport *ts2 = &dev->ts2;
+ u32 pci_status, pci_mask;
+ u32 ts1_status, ts1_mask;
+ u32 ts2_status, ts2_mask;
+ int ts1_count = 0, ts2_count = 0, handled = 0;
+
+ pci_status = cx_read(PCI_INT_STAT);
+ pci_mask = cx_read(PCI_INT_MSK);
+ ts1_status = cx_read(VID_B_INT_STAT);
+ ts1_mask = cx_read(VID_B_INT_MSK);
+ ts2_status = cx_read(VID_C_INT_STAT);
+ ts2_mask = cx_read(VID_C_INT_MSK);
+
+ if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) )
+ goto out;
+
+ ts1_count = cx_read(ts1->reg_gpcnt);
+ ts2_count = cx_read(ts2->reg_gpcnt);
+ dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask );
+ dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count );
+ dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, ts2_count );
+
+ if ( (pci_status & PCI_MSK_RISC_RD) ||
+ (pci_status & PCI_MSK_RISC_WR) ||
+ (pci_status & PCI_MSK_AL_RD) ||
+ (pci_status & PCI_MSK_AL_WR) ||
+ (pci_status & PCI_MSK_APB_DMA) ||
+ (pci_status & PCI_MSK_VID_C) ||
+ (pci_status & PCI_MSK_VID_B) ||
+ (pci_status & PCI_MSK_VID_A) ||
+ (pci_status & PCI_MSK_AUD_INT) ||
+ (pci_status & PCI_MSK_AUD_EXT) )
+ {
+
+ if (pci_status & PCI_MSK_RISC_RD)
+ dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n", PCI_MSK_RISC_RD);
+ if (pci_status & PCI_MSK_RISC_WR)
+ dprintk(7, " (PCI_MSK_RISC_WR 0x%08x)\n", PCI_MSK_RISC_WR);
+ if (pci_status & PCI_MSK_AL_RD)
+ dprintk(7, " (PCI_MSK_AL_RD 0x%08x)\n", PCI_MSK_AL_RD);
+ if (pci_status & PCI_MSK_AL_WR)
+ dprintk(7, " (PCI_MSK_AL_WR 0x%08x)\n", PCI_MSK_AL_WR);
+ if (pci_status & PCI_MSK_APB_DMA)
+ dprintk(7, " (PCI_MSK_APB_DMA 0x%08x)\n", PCI_MSK_APB_DMA);
+ if (pci_status & PCI_MSK_VID_C)
+ dprintk(7, " (PCI_MSK_VID_C 0x%08x)\n", PCI_MSK_VID_C);
+ if (pci_status & PCI_MSK_VID_B)
+ dprintk(7, " (PCI_MSK_VID_B 0x%08x)\n", PCI_MSK_VID_B);
+ if (pci_status & PCI_MSK_VID_A)
+ dprintk(7, " (PCI_MSK_VID_A 0x%08x)\n", PCI_MSK_VID_A);
+ if (pci_status & PCI_MSK_AUD_INT)
+ dprintk(7, " (PCI_MSK_AUD_INT 0x%08x)\n", PCI_MSK_AUD_INT);
+ if (pci_status & PCI_MSK_AUD_EXT)
+ dprintk(7, " (PCI_MSK_AUD_EXT 0x%08x)\n", PCI_MSK_AUD_EXT);
+
+ }
+
+ if (ts1_status)
+ handled += cx23885_irq_ts(ts1, ts1_status);
+
+ if (ts2_status)
+ handled += cx23885_irq_ts(ts2, ts2_status);
+
+ if (handled)
+ cx_write(PCI_INT_STAT, pci_status);
+out:
+ return IRQ_RETVAL(handled);
+}
+
+static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ struct cx23885_dev *dev;
+ int err;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (NULL == dev)
+ return -ENOMEM;
+
+ /* pci init */
+ dev->pci = pci_dev;
+ if (pci_enable_device(pci_dev)) {
+ err = -EIO;
+ goto fail_free;
+ }
+
+ if (cx23885_dev_setup(dev) < 0) {
+ err = -EINVAL;
+ goto fail_free;
+ }
+
+ /* print pci info */
+ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+ pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
+ printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
+ "latency: %d, mmio: 0x%llx\n", dev->name,
+ pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+ dev->pci_lat, (unsigned long long)pci_resource_start(pci_dev,0));
+
+ pci_set_master(pci_dev);
+ if (!pci_dma_supported(pci_dev, 0xffffffff)) {
+ printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
+ err = -EIO;
+ goto fail_irq;
+ }
+
+ err = request_irq(pci_dev->irq, cx23885_irq,
+ IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+ if (err < 0) {
+ printk(KERN_ERR "%s: can't get IRQ %d\n",
+ dev->name, pci_dev->irq);
+ goto fail_irq;
+ }
+
+ pci_set_drvdata(pci_dev, dev);
+ return 0;
+
+fail_irq:
+ cx23885_dev_unregister(dev);
+fail_free:
+ kfree(dev);
+ return err;
+}
+
+static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
+{
+ struct cx23885_dev *dev = pci_get_drvdata(pci_dev);
+
+ cx23885_shutdown(dev);
+
+ pci_disable_device(pci_dev);
+
+ /* unregister stuff */
+ free_irq(pci_dev->irq, dev);
+ pci_set_drvdata(pci_dev, NULL);
+
+ mutex_lock(&devlist);
+ list_del(&dev->devlist);
+ mutex_unlock(&devlist);
+
+ cx23885_dev_unregister(dev);
+ kfree(dev);
+}
+
+static struct pci_device_id cx23885_pci_tbl[] = {
+ {
+ /* CX23885 */
+ .vendor = 0x14f1,
+ .device = 0x8852,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },{
+ /* CX23887 Rev 2 */
+ .vendor = 0x14f1,
+ .device = 0x8880,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },{
+ /* --- end of list --- */
+ }
+};
+MODULE_DEVICE_TABLE(pci, cx23885_pci_tbl);
+
+static struct pci_driver cx23885_pci_driver = {
+ .name = "cx23885",
+ .id_table = cx23885_pci_tbl,
+ .probe = cx23885_initdev,
+ .remove = __devexit_p(cx23885_finidev),
+ /* TODO */
+ .suspend = NULL,
+ .resume = NULL,
+};
+
+static int cx23885_init(void)
+{
+ printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n",
+ (CX23885_VERSION_CODE >> 16) & 0xff,
+ (CX23885_VERSION_CODE >> 8) & 0xff,
+ CX23885_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+ printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n",
+ SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+ return pci_register_driver(&cx23885_pci_driver);
+}
+
+static void cx23885_fini(void)
+{
+ pci_unregister_driver(&cx23885_pci_driver);
+}
+
+module_init(cx23885_init);
+module_exit(cx23885_fini);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
new file mode 100644
index 00000000000..eda8c05d093
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -0,0 +1,213 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/file.h>
+#include <linux/suspend.h>
+
+#include "cx23885.h"
+#include <media/v4l2-common.h>
+
+#include "s5h1409.h"
+#include "mt2131.h"
+#include "lgdt330x.h"
+#include "dvb-pll.h"
+
+static unsigned int debug = 0;
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static int dvb_buf_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct cx23885_tsport *port = q->priv_data;
+
+ port->ts_packet_size = 188 * 4;
+ port->ts_packet_count = 32;
+
+ *size = port->ts_packet_size * port->ts_packet_count;
+ *count = 32;
+ return 0;
+}
+
+static int dvb_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct cx23885_tsport *port = q->priv_data;
+ return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb, field);
+}
+
+static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ struct cx23885_tsport *port = q->priv_data;
+ cx23885_buf_queue(port, (struct cx23885_buffer*)vb);
+}
+
+static void dvb_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ cx23885_free_buffer(q, (struct cx23885_buffer*)vb);
+}
+
+static struct videobuf_queue_ops dvb_qops = {
+ .buf_setup = dvb_buf_setup,
+ .buf_prepare = dvb_buf_prepare,
+ .buf_queue = dvb_buf_queue,
+ .buf_release = dvb_buf_release,
+};
+
+static struct s5h1409_config hauppauge_generic_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_ON,
+ .if_freq = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING
+};
+
+static struct s5h1409_config hauppauge_hvr1800lp_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_OFF,
+ .if_freq = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING
+};
+
+static struct mt2131_config hauppauge_generic_tunerconfig = {
+ 0x61
+};
+
+static struct lgdt330x_config fusionhdtv_5_express = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x40,
+};
+
+static int dvb_register(struct cx23885_tsport *port)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_i2c *i2c_bus = NULL;
+
+ /* init struct videobuf_dvb */
+ port->dvb.name = dev->name;
+
+ /* init frontend */
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ i2c_bus = &dev->i2c_bus[0];
+ port->dvb.frontend = dvb_attach(s5h1409_attach,
+ &hauppauge_generic_config,
+ &i2c_bus->i2c_adap);
+ if (port->dvb.frontend != NULL) {
+ dvb_attach(mt2131_attach, port->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_generic_tunerconfig, 0);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ i2c_bus = &dev->i2c_bus[0];
+ port->dvb.frontend = dvb_attach(s5h1409_attach,
+ &hauppauge_hvr1800lp_config,
+ &i2c_bus->i2c_adap);
+ if (port->dvb.frontend != NULL) {
+ dvb_attach(mt2131_attach, port->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_generic_tunerconfig, 0);
+ }
+ break;
+ case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
+ i2c_bus = &dev->i2c_bus[0];
+ port->dvb.frontend = dvb_attach(lgdt330x_attach,
+ &fusionhdtv_5_express,
+ &i2c_bus->i2c_adap);
+ if (port->dvb.frontend != NULL) {
+ dvb_attach(dvb_pll_attach, port->dvb.frontend, 0x61,
+ &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
+ }
+ break;
+ default:
+ printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
+ dev->name);
+ break;
+ }
+ if (NULL == port->dvb.frontend) {
+ printk("%s: frontend initialization failed\n", dev->name);
+ return -1;
+ }
+
+ /* Put the analog decoder in standby to keep it quiet */
+ cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
+
+ /* register everything */
+ return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
+ &dev->pci->dev);
+}
+
+int cx23885_dvb_register(struct cx23885_tsport *port)
+{
+ struct cx23885_dev *dev = port->dev;
+ int err;
+
+ dprintk(1, "%s\n", __FUNCTION__);
+ dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
+ dev->board,
+ dev->name,
+ dev->pci_bus,
+ dev->pci_slot);
+
+ err = -ENODEV;
+
+ /* dvb stuff */
+ printk("%s: cx23885 based dvb card\n", dev->name);
+ videobuf_queue_pci_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
+ sizeof(struct cx23885_buffer), port);
+ err = dvb_register(port);
+ if (err != 0)
+ printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err);
+
+ return err;
+}
+
+int cx23885_dvb_unregister(struct cx23885_tsport *port)
+{
+ /* dvb */
+ if(port->dvb.frontend)
+ videobuf_dvb_unregister(&port->dvb);
+
+ return 0;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+*/
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
new file mode 100644
index 00000000000..71da528932d
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -0,0 +1,375 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include "cx23885.h"
+
+#include <media/v4l2-common.h>
+
+static unsigned int i2c_debug = 0;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+static unsigned int i2c_scan = 0;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \
+ printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
+
+#define I2C_WAIT_DELAY 32
+#define I2C_WAIT_RETRY 64
+
+#define I2C_EXTEND (1 << 3)
+#define I2C_NOSTOP (1 << 4)
+
+static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap)
+{
+ struct cx23885_i2c *bus = i2c_adap->algo_data;
+ struct cx23885_dev *dev = bus->dev;
+ return cx_read(bus->reg_stat) & 0x01;
+}
+
+static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
+{
+ struct cx23885_i2c *bus = i2c_adap->algo_data;
+ struct cx23885_dev *dev = bus->dev;
+ return cx_read(bus->reg_stat) & 0x02 ? 1 : 0;
+}
+
+static int i2c_wait_done(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (!i2c_is_busy(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg, int last)
+{
+ struct cx23885_i2c *bus = i2c_adap->algo_data;
+ struct cx23885_dev *dev = bus->dev;
+ u32 wdata, addr, ctrl;
+ int retval, cnt;
+
+ dprintk(1, "%s()\n", __FUNCTION__);
+ /* Deal with i2c probe functions with zero payload */
+ if (msg->len == 0) {
+ cx_write(bus->reg_addr, msg->addr << 25);
+ cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2));
+ if (!i2c_wait_done(i2c_adap))
+ return -EIO;
+ if (!i2c_slave_did_ack(i2c_adap))
+ return -EIO;
+
+ dprintk(1, "%s() returns 0\n", __FUNCTION__);
+ return 0;
+ }
+
+
+ /* dev, reg + first byte */
+ addr = (msg->addr << 25) | msg->buf[0];
+ wdata = msg->buf[0];
+ ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
+
+ if (msg->len > 1)
+ ctrl |= I2C_NOSTOP | I2C_EXTEND;
+
+ cx_write(bus->reg_addr, addr);
+ cx_write(bus->reg_wdata, wdata);
+ cx_write(bus->reg_ctrl, ctrl);
+
+ retval = i2c_wait_done(i2c_adap);
+ if (retval < 0)
+ goto err;
+ if (retval == 0)
+ goto eio;
+ if (i2c_debug) {
+ printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]);
+ if (!(ctrl & I2C_NOSTOP))
+ printk(" >\n");
+ }
+
+ for (cnt = 1; cnt < msg->len; cnt++ ) {
+ /* following bytes */
+ wdata = msg->buf[cnt];
+ ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
+
+ if (cnt < msg->len-1 || !last)
+ ctrl |= I2C_NOSTOP | I2C_EXTEND;
+
+ cx_write(bus->reg_addr, addr);
+ cx_write(bus->reg_wdata, wdata);
+ cx_write(bus->reg_ctrl, ctrl);
+
+ retval = i2c_wait_done(i2c_adap);
+ if (retval < 0)
+ goto err;
+ if (retval == 0)
+ goto eio;
+ if (i2c_debug) {
+ printk(" %02x", msg->buf[cnt]);
+ if (!(ctrl & I2C_NOSTOP))
+ printk(" >\n");
+ }
+ }
+ return msg->len;
+
+ eio:
+ retval = -EIO;
+ err:
+ printk(" ERR: %d\n", retval);
+ return retval;
+}
+
+static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg, int last)
+{
+ struct cx23885_i2c *bus = i2c_adap->algo_data;
+ struct cx23885_dev *dev = bus->dev;
+ u32 ctrl, cnt;
+ int retval;
+
+ dprintk(1, "%s()\n", __FUNCTION__);
+
+ /* Deal with i2c probe functions with zero payload */
+ if (msg->len == 0) {
+ cx_write(bus->reg_addr, msg->addr << 25);
+ cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1);
+ if (!i2c_wait_done(i2c_adap))
+ return -EIO;
+ if (!i2c_slave_did_ack(i2c_adap))
+ return -EIO;
+
+
+ dprintk(1, "%s() returns 0\n", __FUNCTION__);
+ return 0;
+ }
+
+ for(cnt = 0; cnt < msg->len; cnt++) {
+
+ ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1;
+
+ if (cnt < msg->len-1 || !last)
+ ctrl |= I2C_NOSTOP | I2C_EXTEND;
+
+ cx_write(bus->reg_addr, msg->addr << 25);
+ cx_write(bus->reg_ctrl, ctrl);
+
+ retval = i2c_wait_done(i2c_adap);
+ if (retval < 0)
+ goto err;
+ if (retval == 0)
+ goto eio;
+ msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
+ if (i2c_debug) {
+ if (!(ctrl & I2C_NOSTOP))
+ printk(" <R %02x", (msg->addr << 1) +1);
+ printk(" =%02x", msg->buf[cnt]);
+ if (!(ctrl & I2C_NOSTOP))
+ printk(" >\n");
+ }
+ }
+ return msg->len;
+
+ eio:
+ retval = -EIO;
+ err:
+ printk(" ERR: %d\n", retval);
+ return retval;
+}
+
+static int i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct cx23885_i2c *bus = i2c_adap->algo_data;
+ struct cx23885_dev *dev = bus->dev;
+ int i, retval = 0;
+
+ dprintk(1, "%s(num = %d)\n", __FUNCTION__, num);
+
+ for (i = 0 ; i < num; i++) {
+ dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n",
+ __FUNCTION__, num, msgs[i].addr, msgs[i].len);
+ if (msgs[i].flags & I2C_M_RD) {
+ /* read */
+ retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num);
+ if (retval < 0)
+ goto err;
+ } else {
+ /* write */
+ retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num);
+ if (retval < 0)
+ goto err;
+ }
+ }
+ return num;
+
+ err:
+ return retval;
+}
+
+static int attach_inform(struct i2c_client *client)
+{
+ struct cx23885_dev *dev = i2c_get_adapdata(client->adapter);
+
+ dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+ client->driver->driver.name, client->addr, client->name);
+
+ if (!client->driver->command)
+ return 0;
+
+ return 0;
+}
+
+static int detach_inform(struct i2c_client *client)
+{
+ struct cx23885_dev *dev = i2c_get_adapdata(client->adapter);
+
+ dprintk(1, "i2c detach [client=%s]\n", client->name);
+
+ return 0;
+}
+
+void cx23885_call_i2c_clients(struct cx23885_i2c *bus,
+ unsigned int cmd, void *arg)
+{
+ if (bus->i2c_rc != 0)
+ return;
+
+ i2c_clients_command(&bus->i2c_adap, cmd, arg);
+}
+
+static u32 cx23885_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm cx23885_i2c_algo_template = {
+ .master_xfer = i2c_xfer,
+ .functionality = cx23885_functionality,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter cx23885_i2c_adap_template = {
+ .name = "cx23885",
+ .owner = THIS_MODULE,
+ .id = I2C_HW_B_CX23885,
+ .algo = &cx23885_i2c_algo_template,
+ .client_register = attach_inform,
+ .client_unregister = detach_inform,
+};
+
+static struct i2c_client cx23885_i2c_client_template = {
+ .name = "cx23885 internal",
+};
+
+static char *i2c_devs[128] = {
+ [ 0x1c >> 1 ] = "lgdt3303",
+ [ 0x86 >> 1 ] = "tda9887",
+ [ 0x32 >> 1 ] = "cx24227",
+ [ 0x88 >> 1 ] = "cx25837",
+ [ 0x84 >> 1 ] = "tda8295",
+ [ 0xa0 >> 1 ] = "eeprom",
+ [ 0xc0 >> 1 ] = "tuner/mt2131/tda8275",
+ [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+ unsigned char buf;
+ int i, rc;
+
+ for (i = 0; i < 128; i++) {
+ c->addr = i;
+ rc = i2c_master_recv(c, &buf, 0);
+ if (rc < 0)
+ continue;
+ printk("%s: i2c scan: found device @ 0x%x [%s]\n",
+ name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+ }
+}
+
+/* init + register i2c algo-bit adapter */
+int cx23885_i2c_register(struct cx23885_i2c *bus)
+{
+ struct cx23885_dev *dev = bus->dev;
+
+ dprintk(1, "%s(bus = %d)\n", __FUNCTION__, bus->nr);
+
+ memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template,
+ sizeof(bus->i2c_adap));
+ memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template,
+ sizeof(bus->i2c_algo));
+ memcpy(&bus->i2c_client, &cx23885_i2c_client_template,
+ sizeof(bus->i2c_client));
+
+ bus->i2c_adap.dev.parent = &dev->pci->dev;
+
+ strlcpy(bus->i2c_adap.name, bus->dev->name,
+ sizeof(bus->i2c_adap.name));
+
+ bus->i2c_algo.data = bus;
+ bus->i2c_adap.algo_data = bus;
+ i2c_add_adapter(&bus->i2c_adap);
+
+ bus->i2c_client.adapter = &bus->i2c_adap;
+
+ if (0 == bus->i2c_rc) {
+ printk("%s: i2c bus %d registered\n", dev->name, bus->nr);
+ if (i2c_scan)
+ do_i2c_scan(dev->name, &bus->i2c_client);
+ } else
+ printk("%s: i2c bus %d register FAILED\n", dev->name, bus->nr);
+
+ return bus->i2c_rc;
+}
+
+int cx23885_i2c_unregister(struct cx23885_i2c *bus)
+{
+ i2c_del_adapter(&bus->i2c_adap);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+EXPORT_SYMBOL(cx23885_call_i2c_clients);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h
new file mode 100644
index 00000000000..162169f9091
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-reg.h
@@ -0,0 +1,431 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CX23885_REG_H_
+#define _CX23885_REG_H_
+
+/*
+Address Map
+0x00000000 -> 0x00009000 TX SRAM (Fifos)
+0x00010000 -> 0x00013c00 RX SRAM CMDS + CDT
+
+EACH CMDS struct is 0x80 bytes long
+
+DMAx_PTR1 = 0x03040 address of first cluster
+DMAx_PTR2 = 0x10600 address of the CDT
+DMAx_CNT1 = cluster size in (bytes >> 4) -1
+DMAx_CNT2 = total cdt size for all entries >> 3
+
+Cluster Descriptor entry = 4 DWORDS
+ DWORD 0 -> ptr to cluster
+ DWORD 1 Reserved
+ DWORD 2 Reserved
+ DWORD 3 Reserved
+
+Channel manager Data Structure entry = 20 DWORD
+ 0 IntialProgramCounterLow
+ 1 IntialProgramCounterHigh
+ 2 ClusterDescriptorTableBase
+ 3 ClusterDescriptorTableSize
+ 4 InstructionQueueBase
+ 5 InstructionQueueSize
+... Reserved
+ 19 Reserved
+*/
+
+/* Risc Instructions */
+#define RISC_CNT_INC 0x00010000
+#define RISC_CNT_RESET 0x00030000
+#define RISC_IRQ1 0x01000000
+#define RISC_IRQ2 0x02000000
+#define RISC_EOL 0x04000000
+#define RISC_SOL 0x08000000
+#define RISC_WRITE 0x10000000
+#define RISC_SKIP 0x20000000
+#define RISC_JUMP 0x70000000
+#define RISC_SYNC 0x80000000
+#define RISC_RESYNC 0x80008000
+#define RISC_READ 0x90000000
+#define RISC_WRITERM 0xB0000000
+#define RISC_WRITECM 0xC0000000
+#define RISC_WRITECR 0xD0000000
+#define RISC_WRITEC 0x50000000
+#define RISC_READC 0xA0000000
+
+
+/* Audio and Video Core */
+#define HOST_REG1 0x00000000
+#define HOST_REG2 0x00000001
+#define HOST_REG3 0x00000002
+
+/* Chip Configuration Registers */
+#define CHIP_CTRL 0x00000100
+#define AFE_CTRL 0x00000104
+#define VID_PLL_INT_POST 0x00000108
+#define VID_PLL_FRAC 0x0000010C
+#define AUX_PLL_INT_POST 0x00000110
+#define AUX_PLL_FRAC 0x00000114
+#define SYS_PLL_INT_POST 0x00000118
+#define SYS_PLL_FRAC 0x0000011C
+#define PIN_CTRL 0x00000120
+#define AUD_IO_CTRL 0x00000124
+#define AUD_LOCK1 0x00000128
+#define AUD_LOCK2 0x0000012C
+#define POWER_CTRL 0x00000130
+#define AFE_DIAG_CTRL1 0x00000134
+#define AFE_DIAG_CTRL3 0x0000013C
+#define PLL_DIAG_CTRL 0x00000140
+#define AFE_CLK_OUT_CTRL 0x00000144
+#define DLL1_DIAG_CTRL 0x0000015C
+
+/* GPIO[23:19] Output Enable */
+#define GPIO2_OUT_EN_REG 0x00000160
+/* GPIO[23:19] Data Registers */
+#define GPIO2 0x00000164
+
+#define IFADC_CTRL 0x00000180
+
+/* Infrared Remote Registers */
+#define IR_CNTRL_REG 0x00000200
+#define IR_TXCLK_REG 0x00000204
+#define IR_RXCLK_REG 0x00000208
+#define IR_CDUTY_REG 0x0000020C
+#define IR_STAT_REG 0x00000210
+#define IR_IRQEN_REG 0x00000214
+#define IR_FILTR_REG 0x00000218
+#define IR_FIFO_REG 0x0000023C
+
+/* Video Decoder Registers */
+#define MODE_CTRL 0x00000400
+#define OUT_CTRL1 0x00000404
+#define OUT_CTRL2 0x00000408
+#define GEN_STAT 0x0000040C
+#define INT_STAT_MASK 0x00000410
+#define LUMA_CTRL 0x00000414
+#define HSCALE_CTRL 0x00000418
+#define VSCALE_CTRL 0x0000041C
+#define CHROMA_CTRL 0x00000420
+#define VBI_LINE_CTRL1 0x00000424
+#define VBI_LINE_CTRL2 0x00000428
+#define VBI_LINE_CTRL3 0x0000042C
+#define VBI_LINE_CTRL4 0x00000430
+#define VBI_LINE_CTRL5 0x00000434
+#define VBI_FC_CFG 0x00000438
+#define VBI_MISC_CFG1 0x0000043C
+#define VBI_MISC_CFG2 0x00000440
+#define VBI_PAY1 0x00000444
+#define VBI_PAY2 0x00000448
+#define VBI_CUST1_CFG1 0x0000044C
+#define VBI_CUST1_CFG2 0x00000450
+#define VBI_CUST1_CFG3 0x00000454
+#define VBI_CUST2_CFG1 0x00000458
+#define VBI_CUST2_CFG2 0x0000045C
+#define VBI_CUST2_CFG3 0x00000460
+#define VBI_CUST3_CFG1 0x00000464
+#define VBI_CUST3_CFG2 0x00000468
+#define VBI_CUST3_CFG3 0x0000046C
+#define HORIZ_TIM_CTRL 0x00000470
+#define VERT_TIM_CTRL 0x00000474
+#define SRC_COMB_CFG 0x00000478
+#define CHROMA_VBIOFF_CFG 0x0000047C
+#define FIELD_COUNT 0x00000480
+#define MISC_TIM_CTRL 0x00000484
+#define DFE_CTRL1 0x00000488
+#define DFE_CTRL2 0x0000048C
+#define DFE_CTRL3 0x00000490
+#define PLL_CTRL 0x00000494
+#define HTL_CTRL 0x00000498
+#define COMB_CTRL 0x0000049C
+#define CRUSH_CTRL 0x000004A0
+#define SOFT_RST_CTRL 0x000004A4
+#define CX885_VERSION 0x000004B4
+#define VBI_PASS_CTRL 0x000004BC
+
+/* Audio Decoder Registers */
+/* 8051 Configuration */
+#define DL_CTL 0x00000800
+#define STD_DET_STATUS 0x00000804
+#define STD_DET_CTL 0x00000808
+#define DW8051_INT 0x0000080C
+#define GENERAL_CTL 0x00000810
+#define AAGC_CTL 0x00000814
+#define DEMATRIX_CTL 0x000008CC
+#define PATH1_CTL1 0x000008D0
+#define PATH1_VOL_CTL 0x000008D4
+#define PATH1_EQ_CTL 0x000008D8
+#define PATH1_SC_CTL 0x000008DC
+#define PATH2_CTL1 0x000008E0
+#define PATH2_VOL_CTL 0x000008E4
+#define PATH2_EQ_CTL 0x000008E8
+#define PATH2_SC_CTL 0x000008EC
+
+/* Sample Rate Converter */
+#define SRC_CTL 0x000008F0
+#define SRC_LF_COEF 0x000008F4
+#define SRC1_CTL 0x000008F8
+#define SRC2_CTL 0x000008FC
+#define SRC3_CTL 0x00000900
+#define SRC4_CTL 0x00000904
+#define SRC5_CTL 0x00000908
+#define SRC6_CTL 0x0000090C
+#define BAND_OUT_SEL 0x00000910
+#define I2S_N_CTL 0x00000914
+#define I2S_OUT_CTL 0x00000918
+#define AUTOCONFIG_REG 0x000009C4
+
+/* Audio ADC Registers */
+#define DSM_CTRL1 0x00000000
+#define DSM_CTRL2 0x00000001
+#define CHP_EN_CTRL 0x00000002
+#define CHP_CLK_CTRL1 0x00000004
+#define CHP_CLK_CTRL2 0x00000005
+#define BG_REF_CTRL 0x00000006
+#define SD2_SW_CTRL1 0x00000008
+#define SD2_SW_CTRL2 0x00000009
+#define SD2_BIAS_CTRL 0x0000000A
+#define AMP_BIAS_CTRL 0x0000000C
+#define CH_PWR_CTRL1 0x0000000E
+#define CH_PWR_CTRL2 0x0000000F
+#define DSM_STATUS1 0x00000010
+#define DSM_STATUS2 0x00000011
+#define DIG_CTL1 0x00000012
+#define DIG_CTL2 0x00000013
+#define I2S_TX_CFG 0x0000001A
+
+#define DEV_CNTRL2 0x00040000
+
+#define PCI_MSK_APB_DMA (1 << 12)
+#define PCI_MSK_AL_WR (1 << 11)
+#define PCI_MSK_AL_RD (1 << 10)
+#define PCI_MSK_RISC_WR (1 << 9)
+#define PCI_MSK_RISC_RD (1 << 8)
+#define PCI_MSK_AUD_EXT (1 << 4)
+#define PCI_MSK_AUD_INT (1 << 3)
+#define PCI_MSK_VID_C (1 << 2)
+#define PCI_MSK_VID_B (1 << 1)
+#define PCI_MSK_VID_A 1
+#define PCI_INT_MSK 0x00040010
+
+#define PCI_INT_STAT 0x00040014
+#define PCI_INT_MSTAT 0x00040018
+
+#define VID_A_INT_MSK 0x00040020
+#define VID_A_INT_STAT 0x00040024
+#define VID_A_INT_MSTAT 0x00040028
+#define VID_A_INT_SSTAT 0x0004002C
+
+#define VID_B_INT_MSK 0x00040030
+#define VID_B_INT_STAT 0x00040034
+#define VID_B_INT_MSTAT 0x00040038
+#define VID_B_INT_SSTAT 0x0004003C
+
+#define VID_B_MSK_BAD_PKT (1 << 20)
+#define VID_B_MSK_OPC_ERR (1 << 16)
+#define VID_B_MSK_SYNC (1 << 12)
+#define VID_B_MSK_OF (1 << 8)
+#define VID_B_MSK_RISCI2 (1 << 4)
+#define VID_B_MSK_RISCI1 1
+
+#define VID_C_MSK_BAD_PKT (1 << 20)
+#define VID_C_MSK_OPC_ERR (1 << 16)
+#define VID_C_MSK_SYNC (1 << 12)
+#define VID_C_MSK_OF (1 << 8)
+#define VID_C_MSK_RISCI2 (1 << 4)
+#define VID_C_MSK_RISCI1 1
+
+/* A superset for testing purposes */
+#define VID_BC_MSK_BAD_PKT (1 << 20)
+#define VID_BC_MSK_OPC_ERR (1 << 16)
+#define VID_BC_MSK_SYNC (1 << 12)
+#define VID_BC_MSK_OF (1 << 8)
+#define VID_BC_MSK_RISCI2 (1 << 4)
+#define VID_BC_MSK_RISCI1 1
+
+#define VID_C_INT_MSK 0x00040040
+#define VID_C_INT_STAT 0x00040044
+#define VID_C_INT_MSTAT 0x00040048
+#define VID_C_INT_SSTAT 0x0004004C
+
+#define AUDIO_INT_INT_MSK 0x00040050
+#define AUDIO_INT_INT_STAT 0x00040054
+#define AUDIO_INT_INT_MSTAT 0x00040058
+#define AUDIO_INT_INT_SSTAT 0x0004005C
+
+#define AUDIO_EXT_INT_MSK 0x00040060
+#define AUDIO_EXT_INT_STAT 0x00040064
+#define AUDIO_EXT_INT_MSTAT 0x00040068
+#define AUDIO_EXT_INT_SSTAT 0x0004006C
+
+#define RDR_CFG0 0x00050000
+#define RDR_CFG1 0x00050004
+#define RDR_TLCTL0 0x00050318
+
+/* APB DMAC Current Buffer Pointer */
+#define DMA1_PTR1 0x00100000
+#define DMA2_PTR1 0x00100004
+#define DMA3_PTR1 0x00100008
+#define DMA4_PTR1 0x0010000C
+#define DMA5_PTR1 0x00100010
+#define DMA6_PTR1 0x00100014
+#define DMA7_PTR1 0x00100018
+#define DMA8_PTR1 0x0010001C
+
+/* APB DMAC Current Table Pointer */
+#define DMA1_PTR2 0x00100040
+#define DMA2_PTR2 0x00100044
+#define DMA3_PTR2 0x00100048
+#define DMA4_PTR2 0x0010004C
+#define DMA5_PTR2 0x00100050
+#define DMA6_PTR2 0x00100054
+#define DMA7_PTR2 0x00100058
+#define DMA8_PTR2 0x0010005C
+
+/* APB DMAC Buffer Limit */
+#define DMA1_CNT1 0x00100080
+#define DMA2_CNT1 0x00100084
+#define DMA3_CNT1 0x00100088
+#define DMA4_CNT1 0x0010008C
+#define DMA5_CNT1 0x00100090
+#define DMA6_CNT1 0x00100094
+#define DMA7_CNT1 0x00100098
+#define DMA8_CNT1 0x0010009C
+
+/* APB DMAC Table Size */
+#define DMA1_CNT2 0x001000C0
+#define DMA2_CNT2 0x001000C4
+#define DMA3_CNT2 0x001000C8
+#define DMA4_CNT2 0x001000CC
+#define DMA5_CNT2 0x001000D0
+#define DMA6_CNT2 0x001000D4
+#define DMA7_CNT2 0x001000D8
+#define DMA8_CNT2 0x001000DC
+
+/* Timer Counters */
+#define TM_CNT_LDW 0x00110000
+#define TM_CNT_UW 0x00110004
+#define TM_LMT_LDW 0x00110008
+#define TM_LMT_UW 0x0011000C
+
+/* GPIO */
+#define GP0_IO 0x00110010
+#define GPIO_ISM 0x00110014
+#define SOFT_RESET 0x0011001C
+
+/* GPIO (417 Microsoftcontroller) RW Data */
+#define MC417_RWD 0x00110020
+
+/* GPIO (417 Microsoftcontroller) Output Enable, Low Active */
+#define MC417_OEN 0x00110024
+#define MC417_CTL 0x00110028
+#define CLK_DELAY 0x00110048
+#define PAD_CTRL 0x0011004C
+
+/* Video A Interface */
+#define VID_A_GPCNT 0x00130020
+#define VBI_A_GPCNT 0x00130024
+#define VID_A_GPCNT_CTL 0x00130030
+#define VBI_A_GPCNT_CTL 0x00130034
+#define VID_A_DMA_CTL 0x00130040
+#define VID_A_VIP_CTRL 0x00130080
+#define VID_A_PIXEL_FRMT 0x00130084
+#define VID_A_VBI_CTRL 0x00130088
+
+/* Video B Interface */
+#define VID_B_DMA 0x00130100
+#define VBI_B_DMA 0x00130108
+#define VID_B_GPCNT 0x00130120
+#define VBI_B_GPCNT 0x00130124
+#define VID_B_GPCNT_CTL 0x00130134
+#define VBI_B_GPCNT_CTL 0x00130138
+#define VID_B_DMA_CTL 0x00130140
+#define VID_B_SRC_SEL 0x00130144
+#define VID_B_LNGTH 0x00130150
+#define VID_B_HW_SOP_CTL 0x00130154
+#define VID_B_GEN_CTL 0x00130158
+#define VID_B_BD_PKT_STATUS 0x0013015C
+#define VID_B_SOP_STATUS 0x00130160
+#define VID_B_FIFO_OVFL_STAT 0x00130164
+#define VID_B_VLD_MISC 0x00130168
+#define VID_B_TS_CLK_EN 0x0013016C
+#define VID_B_VIP_CTRL 0x00130180
+#define VID_B_PIXEL_FRMT 0x00130184
+
+/* Video C Interface */
+#define VID_C_GPCNT 0x00130220
+#define VID_C_GPCNT_CTL 0x00130230
+#define VBI_C_GPCNT_CTL 0x00130234
+#define VID_C_DMA_CTL 0x00130240
+#define VID_C_LNGTH 0x00130250
+#define VID_C_HW_SOP_CTL 0x00130254
+#define VID_C_GEN_CTL 0x00130258
+#define VID_C_BD_PKT_STATUS 0x0013025C
+#define VID_C_SOP_STATUS 0x00130260
+#define VID_C_FIFO_OVFL_STAT 0x00130264
+#define VID_C_VLD_MISC 0x00130268
+#define VID_C_TS_CLK_EN 0x0013026C
+
+/* Internal Audio Interface */
+#define AUD_INT_A_GPCNT 0x00140020
+#define AUD_INT_B_GPCNT 0x00140024
+#define AUD_INT_A_GPCNT_CTL 0x00140030
+#define AUD_INT_B_GPCNT_CTL 0x00140034
+#define AUD_INT_DMA_CTL 0x00140040
+#define AUD_INT_A_LNGTH 0x00140050
+#define AUD_INT_B_LNGTH 0x00140054
+#define AUD_INT_A_MODE 0x00140058
+#define AUD_INT_B_MODE 0x0014005C
+
+/* External Audio Interface */
+#define AUD_EXT_DMA 0x00140100
+#define AUD_EXT_GPCNT 0x00140120
+#define AUD_EXT_GPCNT_CTL 0x00140130
+#define AUD_EXT_DMA_CTL 0x00140140
+#define AUD_EXT_LNGTH 0x00140150
+#define AUD_EXT_A_MODE 0x00140158
+
+/* I2C Bus 1 */
+#define I2C1_ADDR 0x00180000
+#define I2C1_WDATA 0x00180004
+#define I2C1_CTRL 0x00180008
+#define I2C1_RDATA 0x0018000C
+#define I2C1_STAT 0x00180010
+
+/* I2C Bus 2 */
+#define I2C2_ADDR 0x00190000
+#define I2C2_WDATA 0x00190004
+#define I2C2_CTRL 0x00190008
+#define I2C2_RDATA 0x0019000C
+#define I2C2_STAT 0x00190010
+
+/* I2C Bus 3 */
+#define I2C3_ADDR 0x001A0000
+#define I2C3_WDATA 0x001A0004
+#define I2C3_CTRL 0x001A0008
+#define I2C3_RDATA 0x001A000C
+#define I2C3_STAT 0x001A0010
+
+/* UART */
+#define UART_CTL 0x001B0000
+#define UART_BRD 0x001B0004
+#define UART_ISR 0x001B000C
+#define UART_CNT 0x001B0010
+
+#endif /* _CX23885_REG_H_ */
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
new file mode 100644
index 00000000000..dec4dc2fcbb
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -0,0 +1,301 @@
+/*
+ * Driver for the Conexant CX23885 PCIe bridge
+ *
+ * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/kdev_t.h>
+
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <media/tveeprom.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-dvb.h>
+
+#include "btcx-risc.h"
+#include "cx23885-reg.h"
+
+#include <linux/version.h>
+#include <linux/mutex.h>
+
+#define CX23885_VERSION_CODE KERNEL_VERSION(0,0,1)
+
+#define UNSET (-1U)
+
+#define CX23885_MAXBOARDS 8
+
+/* Max number of inputs by card */
+#define MAX_CX23885_INPUT 8
+
+#define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */
+
+#define CX23885_BOARD_NOAUTO UNSET
+#define CX23885_BOARD_UNKNOWN 0
+#define CX23885_BOARD_HAUPPAUGE_HVR1800lp 1
+#define CX23885_BOARD_HAUPPAUGE_HVR1800 2
+#define CX23885_BOARD_HAUPPAUGE_HVR1250 3
+#define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4
+
+enum cx23885_itype {
+ CX23885_VMUX_COMPOSITE1 = 1,
+ CX23885_VMUX_COMPOSITE2,
+ CX23885_VMUX_COMPOSITE3,
+ CX23885_VMUX_COMPOSITE4,
+ CX23885_VMUX_SVIDEO,
+ CX23885_VMUX_TELEVISION,
+ CX23885_VMUX_CABLE,
+ CX23885_VMUX_DVB,
+ CX23885_VMUX_DEBUG,
+ CX23885_RADIO,
+};
+
+enum cx23885_src_sel_type {
+ CX23885_SRC_SEL_EXT_656_VIDEO = 0,
+ CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO
+};
+
+/* buffer for one video frame */
+struct cx23885_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
+ /* cx23885 specific */
+ unsigned int bpl;
+ struct btcx_riscmem risc;
+ struct cx23885_fmt *fmt;
+ u32 count;
+};
+
+struct cx23885_input {
+ enum cx23885_itype type;
+ unsigned int vmux;
+ u32 gpio0, gpio1, gpio2, gpio3;
+};
+
+typedef enum {
+ CX23885_MPEG_UNDEFINED = 0,
+ CX23885_MPEG_DVB
+} port_t;
+
+struct cx23885_board {
+ char *name;
+ port_t portb, portc;
+ struct cx23885_input input[MAX_CX23885_INPUT];
+};
+
+struct cx23885_subid {
+ u16 subvendor;
+ u16 subdevice;
+ u32 card;
+};
+
+struct cx23885_i2c {
+ struct cx23885_dev *dev;
+
+ int nr;
+
+ /* i2c i/o */
+ struct i2c_adapter i2c_adap;
+ struct i2c_algo_bit_data i2c_algo;
+ struct i2c_client i2c_client;
+ u32 i2c_rc;
+
+ /* 885 registers used for raw addess */
+ u32 i2c_period;
+ u32 reg_ctrl;
+ u32 reg_stat;
+ u32 reg_addr;
+ u32 reg_rdata;
+ u32 reg_wdata;
+};
+
+struct cx23885_dmaqueue {
+ struct list_head active;
+ struct list_head queued;
+ struct timer_list timeout;
+ struct btcx_riscmem stopper;
+ u32 count;
+};
+
+struct cx23885_tsport {
+ struct cx23885_dev *dev;
+
+ int nr;
+ int sram_chno;
+
+ struct videobuf_dvb dvb;
+
+ /* dma queues */
+ struct cx23885_dmaqueue mpegq;
+ u32 ts_packet_size;
+ u32 ts_packet_count;
+
+ int width;
+ int height;
+
+ spinlock_t slock;
+
+ /* registers */
+ u32 reg_gpcnt;
+ u32 reg_gpcnt_ctl;
+ u32 reg_dma_ctl;
+ u32 reg_lngth;
+ u32 reg_hw_sop_ctrl;
+ u32 reg_gen_ctrl;
+ u32 reg_bd_pkt_status;
+ u32 reg_sop_status;
+ u32 reg_fifo_ovfl_stat;
+ u32 reg_vld_misc;
+ u32 reg_ts_clk_en;
+ u32 reg_ts_int_msk;
+ u32 reg_ts_int_stat;
+ u32 reg_src_sel;
+
+ /* Default register vals */
+ int pci_irqmask;
+ u32 dma_ctl_val;
+ u32 ts_int_msk_val;
+ u32 gen_ctrl_val;
+ u32 ts_clk_en_val;
+ u32 src_sel_val;
+};
+
+struct cx23885_dev {
+ struct list_head devlist;
+ atomic_t refcount;
+
+ /* pci stuff */
+ struct pci_dev *pci;
+ unsigned char pci_rev, pci_lat;
+ int pci_bus, pci_slot;
+ u32 __iomem *lmmio;
+ u8 __iomem *bmmio;
+ int pci_irqmask;
+
+ /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
+ struct cx23885_i2c i2c_bus[3];
+
+ int nr;
+ struct mutex lock;
+
+ /* board details */
+ unsigned int board;
+ char name[32];
+
+ struct cx23885_tsport ts1, ts2;
+
+ /* sram configuration */
+ struct sram_channel *sram_channels;
+
+ enum {
+ CX23885_BRIDGE_UNDEFINED = 0,
+ CX23885_BRIDGE_885 = 885,
+ CX23885_BRIDGE_887 = 887,
+ } bridge;
+};
+
+#define SRAM_CH01 0 /* Video A */
+#define SRAM_CH02 1 /* VBI A */
+#define SRAM_CH03 2 /* Video B */
+#define SRAM_CH04 3 /* Transport via B */
+#define SRAM_CH05 4 /* VBI B */
+#define SRAM_CH06 5 /* Video C */
+#define SRAM_CH07 6 /* Transport via C */
+#define SRAM_CH08 7 /* Audio Internal A */
+#define SRAM_CH09 8 /* Audio Internal B */
+#define SRAM_CH10 9 /* Audio External */
+#define SRAM_CH11 10 /* COMB_3D_N */
+#define SRAM_CH12 11 /* Comb 3D N1 */
+#define SRAM_CH13 12 /* Comb 3D N2 */
+#define SRAM_CH14 13 /* MOE Vid */
+#define SRAM_CH15 14 /* MOE RSLT */
+
+struct sram_channel {
+ char *name;
+ u32 cmds_start;
+ u32 ctrl_start;
+ u32 cdt;
+ u32 fifo_start;;
+ u32 fifo_size;
+ u32 ptr1_reg;
+ u32 ptr2_reg;
+ u32 cnt1_reg;
+ u32 cnt2_reg;
+ u32 jumponly;
+};
+
+/* ----------------------------------------------------------- */
+
+#define cx_read(reg) readl(dev->lmmio + ((reg)>>2))
+#define cx_write(reg,value) writel((value), dev->lmmio + ((reg)>>2))
+
+#define cx_andor(reg,mask,value) \
+ writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
+ ((value) & (mask)), dev->lmmio+((reg)>>2))
+
+#define cx_set(reg,bit) cx_andor((reg),(bit),(bit))
+#define cx_clear(reg,bit) cx_andor((reg),(bit),0)
+
+extern int cx23885_sram_channel_setup(struct cx23885_dev *dev,
+ struct sram_channel *ch,
+ unsigned int bpl, u32 risc);
+
+/* ----------------------------------------------------------- */
+/* cx23885-cards.c */
+
+extern struct cx23885_board cx23885_boards[];
+extern const unsigned int cx23885_bcount;
+
+extern struct cx23885_subid cx23885_subids[];
+extern const unsigned int cx23885_idcount;
+
+extern void cx23885_card_list(struct cx23885_dev *dev);
+extern int cx23885_ir_init(struct cx23885_dev *dev);
+extern void cx23885_gpio_setup(struct cx23885_dev *dev);
+extern void cx23885_card_setup(struct cx23885_dev *dev);
+extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev);
+
+extern int cx23885_dvb_register(struct cx23885_tsport *port);
+extern int cx23885_dvb_unregister(struct cx23885_tsport *port);
+
+extern int cx23885_buf_prepare(struct videobuf_queue *q,
+ struct cx23885_tsport *port,
+ struct cx23885_buffer *buf,
+ enum v4l2_field field);
+
+extern void cx23885_buf_queue(struct cx23885_tsport *port,
+ struct cx23885_buffer *buf);
+extern void cx23885_free_buffer(struct videobuf_queue *q,
+ struct cx23885_buffer *buf);
+
+/* ----------------------------------------------------------- */
+/* cx23885-i2c.c */
+extern int cx23885_i2c_register(struct cx23885_i2c *bus);
+extern int cx23885_i2c_unregister(struct cx23885_i2c *bus);
+extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd,
+ void *arg);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index f897c1ebd5f..3d46a776df3 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -157,13 +157,12 @@ void cx25840_audio_set_path(struct i2c_client *client)
{
struct cx25840_state *state = i2c_get_clientdata(client);
+ /* assert soft reset */
+ cx25840_and_or(client, 0x810, ~0x1, 0x01);
+
/* stop microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0);
- /* assert soft reset */
- if (!state->is_cx25836)
- cx25840_and_or(client, 0x810, ~0x1, 0x01);
-
/* Mute everything to prevent the PFFT! */
cx25840_write(client, 0x8d3, 0x1f);
@@ -181,32 +180,46 @@ void cx25840_audio_set_path(struct i2c_client *client)
set_audclk_freq(client, state->audclk_freq);
- /* deassert soft reset */
- if (!state->is_cx25836)
- cx25840_and_or(client, 0x810, ~0x1, 0x00);
-
if (state->aud_input != CX25840_AUDIO_SERIAL) {
/* When the microcontroller detects the
* audio format, it will unmute the lines */
cx25840_and_or(client, 0x803, ~0x10, 0x10);
}
+
+ /* deassert soft reset */
+ cx25840_and_or(client, 0x810, ~0x1, 0x00);
}
static int get_volume(struct i2c_client *client)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+ int vol;
+
+ if (state->unmute_volume >= 0)
+ return state->unmute_volume;
+
/* Volume runs +18dB to -96dB in 1/2dB steps
* change to fit the msp3400 -114dB to +12dB range */
/* check PATH1_VOLUME */
- int vol = 228 - cx25840_read(client, 0x8d4);
+ vol = 228 - cx25840_read(client, 0x8d4);
vol = (vol / 2) + 23;
return vol << 9;
}
static void set_volume(struct i2c_client *client, int volume)
{
- /* First convert the volume to msp3400 values (0-127) */
- int vol = volume >> 9;
+ struct cx25840_state *state = i2c_get_clientdata(client);
+ int vol;
+
+ if (state->unmute_volume >= 0) {
+ state->unmute_volume = volume;
+ return;
+ }
+
+ /* Convert the volume to msp3400 values (0-127) */
+ vol = volume >> 9;
+
/* now scale it up to cx25840 values
* -114dB to -96dB maps to 0
* this should be 19, but in my testing that was 4dB too loud */
@@ -284,30 +297,26 @@ static void set_balance(struct i2c_client *client, int balance)
static int get_mute(struct i2c_client *client)
{
- /* check SRC1_MUTE_EN */
- return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0;
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ return state->unmute_volume >= 0;
}
static void set_mute(struct i2c_client *client, int mute)
{
struct cx25840_state *state = i2c_get_clientdata(client);
- if (state->aud_input != CX25840_AUDIO_SERIAL) {
- /* Must turn off microcontroller in order to mute sound.
- * Not sure if this is the best method, but it does work.
- * If the microcontroller is running, then it will undo any
- * changes to the mute register. */
- if (mute) {
- /* disable microcontroller */
- cx25840_and_or(client, 0x803, ~0x10, 0x00);
- cx25840_write(client, 0x8d3, 0x1f);
- } else {
- /* enable microcontroller */
- cx25840_and_or(client, 0x803, ~0x10, 0x10);
- }
- } else {
- /* SRC1_MUTE_EN */
- cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
+ if (mute && state->unmute_volume == -1) {
+ int vol = get_volume(client);
+
+ set_volume(client, 0);
+ state->unmute_volume = vol;
+ }
+ else if (!mute && state->unmute_volume != -1) {
+ int vol = state->unmute_volume;
+
+ state->unmute_volume = -1;
+ set_volume(client, vol);
}
}
@@ -319,18 +328,18 @@ int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
switch (cmd) {
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 1);
if (state->aud_input != CX25840_AUDIO_SERIAL) {
cx25840_and_or(client, 0x803, ~0x10, 0);
cx25840_write(client, 0x8d3, 0x1f);
}
- if (!state->is_cx25836)
- cx25840_and_or(client, 0x810, ~0x1, 1);
retval = set_audclk_freq(client, *(u32 *)arg);
- if (!state->is_cx25836)
- cx25840_and_or(client, 0x810, ~0x1, 0);
if (state->aud_input != CX25840_AUDIO_SERIAL) {
cx25840_and_or(client, 0x803, ~0x10, 0x10);
}
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 0);
return retval;
case VIDIOC_G_CTRL:
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 67bda9f9a44..15f191e170d 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -34,6 +34,7 @@
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/i2c.h>
+#include <linux/delay.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/cx25840.h>
@@ -133,7 +134,9 @@ static void init_dll1(struct i2c_client *client)
cx25840_write(client, 0x159, 0x23);
cx25840_write(client, 0x15a, 0x87);
cx25840_write(client, 0x15b, 0x06);
+ udelay(10);
cx25840_write(client, 0x159, 0xe1);
+ udelay(10);
cx25840_write(client, 0x15a, 0x86);
cx25840_write(client, 0x159, 0xe0);
cx25840_write(client, 0x159, 0xe1);
@@ -147,6 +150,7 @@ static void init_dll2(struct i2c_client *client)
cx25840_write(client, 0x15d, 0xe3);
cx25840_write(client, 0x15e, 0x86);
cx25840_write(client, 0x15f, 0x06);
+ udelay(10);
cx25840_write(client, 0x15d, 0xe1);
cx25840_write(client, 0x15d, 0xe0);
cx25840_write(client, 0x15d, 0xe1);
@@ -165,9 +169,7 @@ static void cx25836_initialize(struct i2c_client *client)
/* 3c. */
cx25840_and_or(client, 0x159, ~0x02, 0x02);
/* 3d. */
- /* There should be a 10-us delay here, but since the
- i2c bus already has a 10-us delay we don't need to do
- anything */
+ udelay(10);
/* 3e. */
cx25840_and_or(client, 0x159, ~0x02, 0x00);
/* 3f. */
@@ -179,9 +181,18 @@ static void cx25836_initialize(struct i2c_client *client)
cx25840_and_or(client, 0x15b, ~0x1e, 0x10);
}
-static void cx25840_initialize(struct i2c_client *client, int loadfw)
+static void cx25840_work_handler(struct work_struct *work)
{
+ struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work);
+ cx25840_loadfw(state->c);
+ wake_up(&state->fw_wait);
+}
+
+static void cx25840_initialize(struct i2c_client *client)
+{
+ DEFINE_WAIT(wait);
struct cx25840_state *state = i2c_get_clientdata(client);
+ struct workqueue_struct *q;
/* datasheet startup in numbered steps, refer to page 3-77 */
/* 2. */
@@ -197,8 +208,19 @@ static void cx25840_initialize(struct i2c_client *client, int loadfw)
cx25840_write(client, 0x13c, 0x01);
cx25840_write(client, 0x13c, 0x00);
/* 5. */
- if (loadfw)
- cx25840_loadfw(client);
+ /* Do the firmware load in a work handler to prevent.
+ Otherwise the kernel is blocked waiting for the
+ bit-banging i2c interface to finish uploading the
+ firmware. */
+ INIT_WORK(&state->fw_work, cx25840_work_handler);
+ init_waitqueue_head(&state->fw_wait);
+ q = create_singlethread_workqueue("cx25840_fw");
+ prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+ queue_work(q, &state->fw_work);
+ schedule();
+ finish_wait(&state->fw_wait, &wait);
+ destroy_workqueue(q);
+
/* 6. */
cx25840_write(client, 0x115, 0x8c);
cx25840_write(client, 0x116, 0x07);
@@ -251,8 +273,13 @@ static void input_change(struct i2c_client *client)
}
cx25840_and_or(client, 0x401, ~0x60, 0);
cx25840_and_or(client, 0x401, ~0x60, 0x60);
+ cx25840_and_or(client, 0x810, ~0x01, 1);
- if (std & V4L2_STD_525_60) {
+ if (state->radio) {
+ cx25840_write(client, 0x808, 0xf9);
+ cx25840_write(client, 0x80b, 0x00);
+ }
+ else if (std & V4L2_STD_525_60) {
/* Certain Hauppauge PVR150 models have a hardware bug
that causes audio to drop out. For these models the
audio standard must be set explicitly.
@@ -281,11 +308,7 @@ static void input_change(struct i2c_client *client)
cx25840_write(client, 0x80b, 0x10);
}
- if (cx25840_read(client, 0x803) & 0x10) {
- /* restart audio decoder microcontroller */
- cx25840_and_or(client, 0x803, ~0x10, 0x00);
- cx25840_and_or(client, 0x803, ~0x10, 0x10);
- }
+ cx25840_and_or(client, 0x810, ~0x01, 0);
}
static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
@@ -625,6 +648,22 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
struct v4l2_tuner *vt = arg;
struct v4l2_routing *route = arg;
+ /* ignore these commands */
+ switch (cmd) {
+ case TUNER_SET_TYPE_ADDR:
+ return 0;
+ }
+
+ if (!state->is_initialized) {
+ v4l_dbg(1, cx25840_debug, client, "cmd %08x triggered fw load\n", cmd);
+ /* initialize on first use */
+ state->is_initialized = 1;
+ if (state->is_cx25836)
+ cx25836_initialize(client);
+ else
+ cx25840_initialize(client);
+ }
+
switch (cmd) {
#ifdef CONFIG_VIDEO_ADV_DEBUG
/* ioctls to allow direct access to the
@@ -825,7 +864,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
if (state->is_cx25836)
cx25836_initialize(client);
else
- cx25840_initialize(client, 0);
+ cx25840_initialize(client);
break;
case VIDIOC_G_CHIP_IDENT:
@@ -856,17 +895,16 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
return 0;
- state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
- if (state == 0)
+ client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
return -ENOMEM;
- client = &state->c;
client->addr = address;
client->adapter = adapter;
client->driver = &i2c_driver_cx25840;
snprintf(client->name, sizeof(client->name) - 1, "cx25840");
- v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", address << 1);
+ v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1);
device_id = cx25840_read(client, 0x101) << 8;
device_id |= cx25840_read(client, 0x100);
@@ -875,42 +913,44 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
* 0x83 for the cx2583x and 0x84 for the cx2584x */
if ((device_id & 0xff00) == 0x8300) {
id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
- state->is_cx25836 = 1;
}
else if ((device_id & 0xff00) == 0x8400) {
id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
- state->is_cx25836 = 0;
}
else {
v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
- kfree(state);
+ kfree(client);
return 0;
}
+ state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+
/* Note: revision '(device_id & 0x0f) == 2' was never built. The
marking skips from 0x1 == 22 to 0x3 == 23. */
v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
(device_id & 0xfff0) >> 4,
(device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f),
- address << 1, adapter->name);
+ client->addr << 1, client->adapter->name);
i2c_set_clientdata(client, state);
+ state->c = client;
+ state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
state->vid_input = CX25840_COMPOSITE7;
state->aud_input = CX25840_AUDIO8;
state->audclk_freq = 48000;
state->pvr150_workaround = 0;
state->audmode = V4L2_TUNER_MODE_LANG1;
+ state->unmute_volume = -1;
state->vbi_line_offset = 8;
state->id = id;
state->rev = device_id;
i2c_attach_client(client);
- if (state->is_cx25836)
- cx25836_initialize(client);
- else
- cx25840_initialize(client, 1);
-
return 0;
}
@@ -932,6 +972,7 @@ static int cx25840_detach_client(struct i2c_client *client)
}
kfree(state);
+ kfree(client);
return 0;
}
@@ -1056,9 +1097,10 @@ static void log_audio_status(struct i2c_client *client)
}
v4l_info(client, "Detected audio standard: %s\n", p);
v4l_info(client, "Audio muted: %s\n",
- (mute_ctl & 0x2) ? "yes" : "no");
+ (state->unmute_volume >= 0) ? "yes" : "no");
v4l_info(client, "Audio microcontroller: %s\n",
- (download_ctl & 0x10) ? "running" : "stopped");
+ (download_ctl & 0x10) ?
+ ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
switch (audio_config >> 4) {
case 0x00: p = "undefined"; break;
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index f4b56d2fd6b..ea669b1f084 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -35,17 +35,21 @@ extern int cx25840_debug;
#define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0)
struct cx25840_state {
- struct i2c_client c;
+ struct i2c_client *c;
int pvr150_workaround;
int radio;
enum cx25840_video_input vid_input;
enum cx25840_audio_input aud_input;
u32 audclk_freq;
int audmode;
+ int unmute_volume; /* -1 if not muted */
int vbi_line_offset;
u32 id;
u32 rev;
int is_cx25836;
+ int is_initialized;
+ wait_queue_head_t fw_wait; /* wake up when the fw load is finished */
+ struct work_struct fw_work; /* work entry for fw load */
};
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index f750a543c96..ceb31d4a251 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -1,10 +1,10 @@
config VIDEO_CX88
tristate "Conexant 2388x (bt878 successor) support"
- depends on VIDEO_DEV && PCI && I2C
+ depends on VIDEO_DEV && PCI && I2C && INPUT
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_BTCX
- select VIDEO_BUF
+ select VIDEOBUF_DMA_SG
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_IR
@@ -46,7 +46,7 @@ config VIDEO_CX88_BLACKBIRD
config VIDEO_CX88_DVB
tristate "DVB/ATSC Support for cx2388x based TV cards"
depends on VIDEO_CX88 && DVB_CORE
- select VIDEO_BUF_DVB
+ select VIDEOBUF_DVB
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 2d666b56020..40ffd7a5579 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -3,10 +3,11 @@
* Support for audio capture
* PCI function #1 of the cx2388x.
*
+ * (c) 2007 Trent Piepho <xyzzy@speakeasy.org>
* (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
* (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
* Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
- * Based on dummy.c by Jaroslav Kysela <perex@suse.cz>
+ * Based on dummy.c by Jaroslav Kysela <perex@perex.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
@@ -27,7 +28,9 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
#include <linux/dma-mapping.h>
+#include <linux/pci.h>
#include <asm/delay.h>
#include <sound/driver.h>
@@ -36,6 +39,7 @@
#include <sound/pcm_params.h>
#include <sound/control.h>
#include <sound/initval.h>
+#include <sound/tlv.h>
#include "cx88.h"
#include "cx88-reg.h"
@@ -46,21 +50,16 @@
#define dprintk_core(level,fmt, arg...) if (debug >= level) \
printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg)
-
/****************************************************************************
Data type declarations - Can be moded to a header file later
****************************************************************************/
-/* These can be replaced after done */
-#define MIXER_ADDR_LAST MAX_CX88_INPUT
-
struct cx88_audio_dev {
struct cx88_core *core;
struct cx88_dmaqueue q;
/* pci i/o */
struct pci_dev *pci;
- unsigned char pci_rev,pci_lat;
/* audio controls */
int irq;
@@ -68,29 +67,23 @@ struct cx88_audio_dev {
struct snd_card *card;
spinlock_t reg_lock;
+ atomic_t count;
unsigned int dma_size;
unsigned int period_size;
unsigned int num_periods;
- struct videobuf_dmabuf dma_risc;
-
- int mixer_volume[MIXER_ADDR_LAST+1][2];
- int capture_source[MIXER_ADDR_LAST+1][2];
+ struct videobuf_dmabuf *dma_risc;
- long int read_count;
- long int read_offset;
-
- struct cx88_buffer *buf;
-
- long opened;
- struct snd_pcm_substream *substream;
+ struct cx88_buffer *buf;
+ struct snd_pcm_substream *substream;
};
typedef struct cx88_audio_dev snd_cx88_card_t;
+
/****************************************************************************
Module global static vars
****************************************************************************/
@@ -98,7 +91,6 @@ typedef struct cx88_audio_dev snd_cx88_card_t;
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
-static struct snd_card *snd_cx88_cards[SNDRV_CARDS];
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
@@ -136,38 +128,39 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip)
struct cx88_core *core=chip->core;
struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
-
- dprintk(1, "Starting audio DMA for %i bytes/line and %i (%i) lines at address %08x\n",buf->bpl, chip->num_periods, audio_ch->fifo_size / buf->bpl, audio_ch->fifo_start);
+ /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
+ cx_clear(MO_AUD_DMACNTRL, 0x11);
/* setup fifo + format - out channel */
- cx88_sram_channel_setup(chip->core, &cx88_sram_channels[SRAM_CH25],
- buf->bpl, buf->risc.dma);
+ cx88_sram_channel_setup(chip->core, audio_ch, buf->bpl, buf->risc.dma);
/* sets bpl size */
cx_write(MO_AUDD_LNGTH, buf->bpl);
/* reset counter */
- cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET);
-
- dprintk(1,"Enabling IRQ, setting mask from 0x%x to 0x%x\n",chip->core->pci_irqmask,(chip->core->pci_irqmask | 0x02));
- /* enable irqs */
- cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | 0x02);
+ cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
+ atomic_set(&chip->count, 0);
+ dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d "
+ "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1,
+ chip->num_periods, buf->bpl * chip->num_periods);
/* Enables corresponding bits at AUD_INT_STAT */
- cx_write(MO_AUD_INTMSK,
- (1<<16)|
- (1<<12)|
- (1<<4)|
- (1<<0)
- );
+ cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+ AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
+
+ /* Clean any pending interrupt bits already set */
+ cx_write(MO_AUD_INTSTAT, ~0);
+
+ /* enable audio irqs */
+ cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT);
/* start dma */
cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */
if (debug)
- cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
+ cx88_sram_channel_dump(chip->core, audio_ch);
return 0;
}
@@ -184,13 +177,9 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
cx_clear(MO_AUD_DMACNTRL, 0x11);
/* disable irqs */
- cx_clear(MO_PCI_INTMSK, 0x02);
- cx_clear(MO_AUD_INTMSK,
- (1<<16)|
- (1<<12)|
- (1<<4)|
- (1<<0)
- );
+ cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
+ cx_clear(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+ AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
if (debug)
cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
@@ -198,7 +187,7 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
return 0;
}
-#define MAX_IRQ_LOOP 10
+#define MAX_IRQ_LOOP 50
/*
* BOARD Specific: IRQ dma bits
@@ -223,42 +212,32 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip)
{
struct cx88_core *core = chip->core;
u32 status, mask;
- u32 count;
status = cx_read(MO_AUD_INTSTAT);
mask = cx_read(MO_AUD_INTMSK);
- if (0 == (status & mask)) {
- spin_unlock(&chip->reg_lock);
+ if (0 == (status & mask))
return;
- }
cx_write(MO_AUD_INTSTAT, status);
if (debug > 1 || (status & mask & ~0xff))
cx88_print_irqbits(core->name, "irq aud",
cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs),
status, mask);
/* risc op code error */
- if (status & (1 << 16)) {
- printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name);
+ if (status & AUD_INT_OPC_ERR) {
+ printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name);
cx_clear(MO_AUD_DMACNTRL, 0x11);
cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]);
}
-
- /* risc1 downstream */
- if (status & 0x01) {
- spin_lock(&chip->reg_lock);
- count = cx_read(MO_AUDD_GPCNT);
- spin_unlock(&chip->reg_lock);
- if (chip->read_count == 0)
- chip->read_count += chip->dma_size;
+ if (status & AUD_INT_DN_SYNC) {
+ dprintk(1, "Downstream sync error\n");
+ cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
+ return;
}
-
- if (chip->read_count >= chip->period_size) {
- dprintk(2, "Elapsing period\n");
+ /* risc1 downstream */
+ if (status & AUD_INT_DN_RISCI1) {
+ atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT));
snd_pcm_period_elapsed(chip->substream);
}
-
- dprintk(3,"Leaving audio IRQ handler...\n");
-
/* FIXME: Any other status should deserve a special handling? */
}
@@ -273,27 +252,26 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id)
int loop, handled = 0;
for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
- status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02);
+ status = cx_read(MO_PCI_INTSTAT) &
+ (core->pci_irqmask | PCI_INT_AUDINT);
if (0 == status)
goto out;
- dprintk( 3, "cx8801_irq\n" );
- dprintk( 3, " loop: %d/%d\n", loop, MAX_IRQ_LOOP );
- dprintk( 3, " status: %d\n", status );
+ dprintk(3, "cx8801_irq loop %d/%d, status %x\n",
+ loop, MAX_IRQ_LOOP, status);
handled = 1;
cx_write(MO_PCI_INTSTAT, status);
- if (status & 0x02)
- {
- dprintk( 2, " ALSA IRQ handling\n" );
+ if (status & core->pci_irqmask)
+ cx88_core_irq(core, status);
+ if (status & PCI_INT_AUDINT)
cx8801_aud_irq(chip);
- }
- };
+ }
if (MAX_IRQ_LOOP == loop) {
- dprintk( 0, "clearing mask\n" );
- dprintk(1,"%s/0: irq loop -- clearing mask\n",
+ printk(KERN_ERR
+ "%s/1: IRQ loop detected, disabling interrupts\n",
core->name);
- cx_clear(MO_PCI_INTMSK,0x02);
+ cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
}
out:
@@ -306,14 +284,15 @@ static int dsp_buffer_free(snd_cx88_card_t *chip)
BUG_ON(!chip->dma_size);
dprintk(2,"Freeing buffer\n");
- videobuf_pci_dma_unmap(chip->pci, &chip->dma_risc);
- videobuf_dma_free(&chip->dma_risc);
+ videobuf_pci_dma_unmap(chip->pci, chip->dma_risc);
+ videobuf_dma_free(chip->dma_risc);
btcx_riscmem_free(chip->pci,&chip->buf->risc);
kfree(chip->buf);
+ chip->dma_risc = NULL;
chip->dma_size = 0;
- return 0;
+ return 0;
}
/****************************************************************************
@@ -323,6 +302,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip)
/*
* Digital hardware definition
*/
+#define DEFAULT_FIFO_SIZE 4096
static struct snd_pcm_hardware snd_cx88_digital_hw = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
@@ -333,22 +313,18 @@ static struct snd_pcm_hardware snd_cx88_digital_hw = {
.rates = SNDRV_PCM_RATE_48000,
.rate_min = 48000,
.rate_max = 48000,
- .channels_min = 1,
+ .channels_min = 2,
.channels_max = 2,
- .buffer_bytes_max = (2*2048),
- .period_bytes_min = 2048,
- .period_bytes_max = 2048,
- .periods_min = 2,
- .periods_max = 2,
+ /* Analog audio output will be full of clicks and pops if there
+ are not exactly four lines in the SRAM FIFO buffer. */
+ .period_bytes_min = DEFAULT_FIFO_SIZE/4,
+ .period_bytes_max = DEFAULT_FIFO_SIZE/4,
+ .periods_min = 1,
+ .periods_max = 1024,
+ .buffer_bytes_max = (1024*1024),
};
/*
- * audio pcm capture runtime free
- */
-static void snd_card_cx88_runtime_free(struct snd_pcm_runtime *runtime)
-{
-}
-/*
* audio pcm capture open callback
*/
static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
@@ -357,26 +333,24 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
int err;
- if (test_and_set_bit(0, &chip->opened))
- return -EBUSY;
-
- err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS);
if (err < 0)
goto _error;
chip->substream = substream;
- chip->read_count = 0;
- chip->read_offset = 0;
-
- runtime->private_free = snd_card_cx88_runtime_free;
runtime->hw = snd_cx88_digital_hw;
+ if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) {
+ unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4;
+ bpl &= ~7; /* must be multiple of 8 */
+ runtime->hw.period_bytes_min = bpl;
+ runtime->hw.period_bytes_max = bpl;
+ }
+
return 0;
_error:
dprintk(1,"Error opening PCM!\n");
- clear_bit(0, &chip->opened);
- smp_mb__after_clear_bit();
return err;
}
@@ -385,11 +359,6 @@ _error:
*/
static int snd_cx88_close(struct snd_pcm_substream *substream)
{
- snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
-
- clear_bit(0, &chip->opened);
- smp_mb__after_clear_bit();
-
return 0;
}
@@ -400,55 +369,67 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
struct snd_pcm_hw_params * hw_params)
{
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ struct videobuf_dmabuf *dma;
+
struct cx88_buffer *buf;
+ int ret;
if (substream->runtime->dma_area) {
dsp_buffer_free(chip);
substream->runtime->dma_area = NULL;
}
-
chip->period_size = params_period_bytes(hw_params);
chip->num_periods = params_periods(hw_params);
chip->dma_size = chip->period_size * params_periods(hw_params);
BUG_ON(!chip->dma_size);
+ BUG_ON(chip->num_periods & (chip->num_periods-1));
- dprintk(1,"Setting buffer\n");
-
- buf = kzalloc(sizeof(*buf),GFP_KERNEL);
+ buf = videobuf_pci_alloc(sizeof(*buf));
if (NULL == buf)
return -ENOMEM;
buf->vb.memory = V4L2_MEMORY_MMAP;
+ buf->vb.field = V4L2_FIELD_NONE;
buf->vb.width = chip->period_size;
+ buf->bpl = chip->period_size;
buf->vb.height = chip->num_periods;
buf->vb.size = chip->dma_size;
- buf->vb.field = V4L2_FIELD_NONE;
- videobuf_dma_init(&buf->vb.dma);
- videobuf_dma_init_kernel(&buf->vb.dma,PCI_DMA_FROMDEVICE,
+ dma=videobuf_to_dma(&buf->vb);
+ videobuf_dma_init(dma);
+ ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
(PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
+ if (ret < 0)
+ goto error;
- videobuf_pci_dma_map(chip->pci,&buf->vb.dma);
-
+ ret = videobuf_pci_dma_map(chip->pci,dma);
+ if (ret < 0)
+ goto error;
- cx88_risc_databuffer(chip->pci, &buf->risc,
- buf->vb.dma.sglist,
- buf->vb.width, buf->vb.height);
+ ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
+ buf->vb.width, buf->vb.height, 1);
+ if (ret < 0)
+ goto error;
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+ /* Loop back to start of program */
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
buf->vb.state = STATE_PREPARED;
- buf->bpl = chip->period_size;
chip->buf = buf;
- chip->dma_risc = buf->vb.dma;
+ chip->dma_risc = dma;
- dprintk(1,"Buffer ready at %u\n",chip->dma_risc.nr_pages);
- substream->runtime->dma_area = chip->dma_risc.vmalloc;
+ substream->runtime->dma_area = chip->dma_risc->vmalloc;
+ substream->runtime->dma_bytes = chip->dma_size;
+ substream->runtime->dma_addr = 0;
return 0;
+
+error:
+ kfree(buf);
+ return ret;
}
/*
@@ -475,7 +456,6 @@ static int snd_cx88_prepare(struct snd_pcm_substream *substream)
return 0;
}
-
/*
* trigger callback
*/
@@ -484,6 +464,7 @@ static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd)
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
int err;
+ /* Local interrupts are already disabled by ALSA */
spin_lock(&chip->reg_lock);
switch (cmd) {
@@ -510,17 +491,24 @@ static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream)
{
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
+ u16 count;
- if (chip->read_count) {
- chip->read_count -= snd_pcm_lib_period_bytes(substream);
- chip->read_offset += snd_pcm_lib_period_bytes(substream);
- if (chip->read_offset == chip->dma_size)
- chip->read_offset = 0;
- }
+ count = atomic_read(&chip->count);
- dprintk(2, "Pointer time, will return %li, read %li\n",chip->read_offset,chip->read_count);
- return bytes_to_frames(runtime, chip->read_offset);
+// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __FUNCTION__,
+// count, new, count & (runtime->periods-1),
+// runtime->period_size * (count & (runtime->periods-1)));
+ return runtime->period_size * (count & (runtime->periods-1));
+}
+/*
+ * page callback (needed for mmap)
+ */
+static struct page *snd_cx88_page(struct snd_pcm_substream *substream,
+ unsigned long offset)
+{
+ void *pageptr = substream->runtime->dma_area + offset;
+ return vmalloc_to_page(pageptr);
}
/*
@@ -535,6 +523,7 @@ static struct snd_pcm_ops snd_cx88_pcm_ops = {
.prepare = snd_cx88_prepare,
.trigger = snd_cx88_card_trigger,
.pointer = snd_cx88_pointer,
+ .page = snd_cx88_page,
};
/*
@@ -558,55 +547,126 @@ static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, char *name)
/****************************************************************************
CONTROL INTERFACE
****************************************************************************/
-static int snd_cx88_capture_volume_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *info)
+static int snd_cx88_volume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
{
info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- info->count = 1;
+ info->count = 2;
info->value.integer.min = 0;
info->value.integer.max = 0x3f;
return 0;
}
-/* OK - TODO: test it */
-static int snd_cx88_capture_volume_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
+static int snd_cx88_volume_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;
+ int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f),
+ bal = cx_read(AUD_BAL_CTL);
- value->value.integer.value[0] = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
+ value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol;
+ vol -= (bal & 0x3f);
+ value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol;
return 0;
}
/* OK - TODO: test it */
-static int snd_cx88_capture_volume_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
+static int snd_cx88_volume_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;
- int v;
- u32 old_control;
-
+ int v, b;
+ int changed = 0;
+ u32 old;
+
+ b = value->value.integer.value[1] - value->value.integer.value[0];
+ if (b < 0) {
+ v = 0x3f - value->value.integer.value[0];
+ b = (-b) | 0x40;
+ } else {
+ v = 0x3f - value->value.integer.value[1];
+ }
+ /* Do we really know this will always be called with IRQs on? */
spin_lock_irq(&chip->reg_lock);
- old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
- v = 0x3f - (value->value.integer.value[0] & 0x3f);
- cx_andor(AUD_VOL_CTL, 0x3f, v);
+ old = cx_read(AUD_VOL_CTL);
+ if (v != (old & 0x3f)) {
+ cx_write(AUD_VOL_CTL, (old & ~0x3f) | v);
+ changed = 1;
+ }
+ if (cx_read(AUD_BAL_CTL) != b) {
+ cx_write(AUD_BAL_CTL, b);
+ changed = 1;
+ }
spin_unlock_irq(&chip->reg_lock);
- return v != old_control;
+ return changed;
}
-static struct snd_kcontrol_new snd_cx88_capture_volume = {
+static const DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0);
+
+static struct snd_kcontrol_new snd_cx88_volume = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Capture Volume",
- .info = snd_cx88_capture_volume_info,
- .get = snd_cx88_capture_volume_get,
- .put = snd_cx88_capture_volume_put,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .name = "Playback Volume",
+ .info = snd_cx88_volume_info,
+ .get = snd_cx88_volume_get,
+ .put = snd_cx88_volume_put,
+ .tlv.p = snd_cx88_db_scale,
};
+static int snd_cx88_switch_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;
+ u32 bit = kcontrol->private_value;
+
+ value->value.integer.value[0] = !(cx_read(AUD_VOL_CTL) & bit);
+ return 0;
+}
+
+static int snd_cx88_switch_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;
+ u32 bit = kcontrol->private_value;
+ int ret = 0;
+ u32 vol;
+
+ spin_lock_irq(&chip->reg_lock);
+ vol = cx_read(AUD_VOL_CTL);
+ if (value->value.integer.value[0] != !(vol & bit)) {
+ vol ^= bit;
+ cx_write(AUD_VOL_CTL, vol);
+ ret = 1;
+ }
+ spin_unlock_irq(&chip->reg_lock);
+ return ret;
+}
+
+static struct snd_kcontrol_new snd_cx88_dac_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Playback Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = snd_cx88_switch_get,
+ .put = snd_cx88_switch_put,
+ .private_value = (1<<8),
+};
+
+static struct snd_kcontrol_new snd_cx88_source_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = snd_cx88_switch_get,
+ .put = snd_cx88_switch_put,
+ .private_value = (1<<6),
+};
/****************************************************************************
Basic Flow for Sound Devices
@@ -665,6 +725,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,
snd_cx88_card_t *chip;
struct cx88_core *core;
int err;
+ unsigned char pci_lat;
*rchip = NULL;
@@ -709,13 +770,12 @@ static int __devinit snd_cx88_create(struct snd_card *card,
}
/* print pci info */
- pci_read_config_byte(pci, PCI_CLASS_REVISION, &chip->pci_rev);
- pci_read_config_byte(pci, PCI_LATENCY_TIMER, &chip->pci_lat);
+ pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat);
dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", core->name, devno,
- pci_name(pci), chip->pci_rev, pci->irq,
- chip->pci_lat,(unsigned long long)pci_resource_start(pci,0));
+ pci_name(pci), pci->revision, pci->irq,
+ pci_lat, (unsigned long long)pci_resource_start(pci,0));
chip->irq = pci->irq;
synchronize_irq(chip->irq);
@@ -753,17 +813,18 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
return (err);
err = snd_cx88_pcm(chip, 0, "CX88 Digital");
+ if (err < 0)
+ goto error;
- if (err < 0) {
- snd_card_free(card);
- return (err);
- }
-
- err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip));
- if (err < 0) {
- snd_card_free(card);
- return (err);
- }
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_volume, chip));
+ if (err < 0)
+ goto error;
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_dac_switch, chip));
+ if (err < 0)
+ goto error;
+ err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_source_switch, chip));
+ if (err < 0)
+ goto error;
strcpy (card->driver, "CX88x");
sprintf(card->shortname, "Conexant CX%x", pci->device);
@@ -775,16 +836,16 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
card->driver,devno);
err = snd_card_register(card);
- if (err < 0) {
- snd_card_free(card);
- return (err);
- }
- snd_cx88_cards[devno] = card;
-
+ if (err < 0)
+ goto error;
pci_set_drvdata(pci,card);
devno++;
return 0;
+
+error:
+ snd_card_free(card);
+ return err;
}
/*
* ALSA destructor
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index f2fcdb92ecc..f33f0b47142 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -27,7 +27,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
@@ -528,44 +527,6 @@ static void blackbird_codec_settings(struct cx8802_dev *dev)
cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params);
}
-static struct v4l2_mpeg_compression default_mpeg_params = {
- .st_type = V4L2_MPEG_PS_2,
- .st_bitrate = {
- .mode = V4L2_BITRATE_CBR,
- .min = 0,
- .target = 0,
- .max = 0
- },
- .ts_pid_pmt = 16,
- .ts_pid_audio = 260,
- .ts_pid_video = 256,
- .ts_pid_pcr = 259,
- .ps_size = 0,
- .au_type = V4L2_MPEG_AU_2_II,
- .au_bitrate = {
- .mode = V4L2_BITRATE_CBR,
- .min = 224,
- .target = 224,
- .max = 224
- },
- .au_sample_rate = 48000,
- .au_pesid = 0,
- .vi_type = V4L2_MPEG_VI_2,
- .vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3,
- .vi_bitrate = {
- .mode = V4L2_BITRATE_CBR,
- .min = 4000,
- .target = 4500,
- .max = 6000
- },
- .vi_frame_rate = 25,
- .vi_frames_per_gop = 12,
- .vi_bframes_count = 2,
- .vi_pesid = 0,
- .closed_gops = 1,
- .pulldown = 0
-};
-
static int blackbird_initialize_codec(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
@@ -734,14 +695,14 @@ static int vidioc_querycap (struct file *file, void *priv,
struct cx88_core *core = dev->core;
strcpy(cap->driver, "cx88_blackbird");
- strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card));
+ strlcpy(cap->card, core->board.name, sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
cap->version = CX88_VERSION_CODE;
cap->capabilities =
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
- if (UNSET != core->tuner_type)
+ if (UNSET != core->board.tuner_type)
cap->capabilities |= V4L2_CAP_TUNER;
return 0;
}
@@ -853,23 +814,6 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
return videobuf_streamoff(&fh->mpegq);
}
-static int vidioc_g_mpegcomp (struct file *file, void *fh,
- struct v4l2_mpeg_compression *f)
-{
- printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
- "Replace with VIDIOC_G_EXT_CTRLS!");
- memcpy(f,&default_mpeg_params,sizeof(*f));
- return 0;
-}
-
-static int vidioc_s_mpegcomp (struct file *file, void *fh,
- struct v4l2_mpeg_compression *f)
-{
- printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
- "Replace with VIDIOC_S_EXT_CTRLS!");
- return 0;
-}
-
static int vidioc_g_ext_ctrls (struct file *file, void *priv,
struct v4l2_ext_controls *f)
{
@@ -877,7 +821,7 @@ static int vidioc_g_ext_ctrls (struct file *file, void *priv,
if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
- return cx2341x_ext_ctrls(&dev->params, f, VIDIOC_G_EXT_CTRLS);
+ return cx2341x_ext_ctrls(&dev->params, 0, f, VIDIOC_G_EXT_CTRLS);
}
static int vidioc_s_ext_ctrls (struct file *file, void *priv,
@@ -890,7 +834,7 @@ static int vidioc_s_ext_ctrls (struct file *file, void *priv,
if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
p = dev->params;
- err = cx2341x_ext_ctrls(&p, f, VIDIOC_S_EXT_CTRLS);
+ err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
if (!err) {
err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
dev->params = p;
@@ -908,7 +852,7 @@ static int vidioc_try_ext_ctrls (struct file *file, void *priv,
if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
p = dev->params;
- err = cx2341x_ext_ctrls(&p, f, VIDIOC_TRY_EXT_CTRLS);
+ err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
return err;
}
@@ -990,7 +934,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
struct cx8802_fh *fh = priv;
struct cx88_core *core = fh->dev->core;
- if (unlikely(UNSET == core->tuner_type))
+ if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
f->type = V4L2_TUNER_ANALOG_TV;
@@ -1028,7 +972,7 @@ static int vidioc_g_tuner (struct file *file, void *priv,
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
u32 reg;
- if (unlikely(UNSET == core->tuner_type))
+ if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
if (0 != t->index)
return -EINVAL;
@@ -1049,7 +993,7 @@ static int vidioc_s_tuner (struct file *file, void *priv,
{
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
- if (UNSET == core->tuner_type)
+ if (UNSET == core->board.tuner_type)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
@@ -1078,7 +1022,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
struct cx8802_driver *drv = NULL;
int err;
- dev = cx8802_get_device(inode);
+ dev = cx8802_get_device(inode);
dprintk( 1, "%s\n", __FUNCTION__);
@@ -1112,7 +1056,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
file->private_data = fh;
fh->dev = dev;
- videobuf_queue_init(&fh->mpegq, &blackbird_qops,
+ videobuf_queue_pci_init(&fh->mpegq, &blackbird_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
@@ -1217,8 +1161,6 @@ static struct video_device cx8802_mpeg_template =
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
- .vidioc_g_mpegcomp = vidioc_g_mpegcomp,
- .vidioc_s_mpegcomp = vidioc_s_mpegcomp,
.vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
.vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
.vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
@@ -1235,7 +1177,7 @@ static struct video_device cx8802_mpeg_template =
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_s_std = vidioc_s_std,
.tvnorms = CX88_NORMS,
- .current_norm = V4L2_STD_NTSC_M,
+ .current_norm = V4L2_STD_NTSC_M,
};
/* ------------------------------------------------------------------ */
@@ -1246,7 +1188,7 @@ static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv)
struct cx88_core *core = drv->core;
int err = 0;
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
/* By default, core setup will leave the cx22702 out of reset, on the bus.
* We left the hardware on power up with the cx22702 active.
@@ -1268,7 +1210,7 @@ static int cx8802_blackbird_advise_release(struct cx8802_driver *drv)
struct cx88_core *core = drv->core;
int err = 0;
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
/* Exit leaving the cx23416 on the bus */
break;
@@ -1316,13 +1258,13 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
dprintk( 1, "%s\n", __FUNCTION__);
dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
- core->board,
+ core->boardnr,
core->name,
core->pci_bus,
core->pci_slot);
err = -ENODEV;
- if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))
+ if (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))
goto fail_core;
dev->width = 720;
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 6a136ddbccf..a4eb6a87a76 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -27,10 +27,26 @@
#include "cx88.h"
+static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(tuner, int, NULL, 0444);
+module_param_array(radio, int, NULL, 0444);
+module_param_array(card, int, NULL, 0444);
+
+MODULE_PARM_DESC(tuner,"tuner type");
+MODULE_PARM_DESC(radio,"radio tuner type");
+MODULE_PARM_DESC(card,"card type");
+
+static unsigned int latency = UNSET;
+module_param(latency,int,0444);
+MODULE_PARM_DESC(latency,"pci latency timer");
+
/* ------------------------------------------------------------------ */
/* board config info */
-struct cx88_board cx88_boards[] = {
+static const struct cx88_board cx88_boards[] = {
[CX88_BOARD_UNKNOWN] = {
.name = "UNKNOWN/GENERIC",
.tuner_type = UNSET,
@@ -575,35 +591,34 @@ struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ /* GPIO[2] = audio source for analog audio out connector
+ * 0 = analog audio input connector
+ * 1 = CX88 audio DACs
+ *
+ * GPIO[7] = input to CX88's audio/chroma ADC
+ * 0 = FM 10.7 MHz IF
+ * 1 = Sound 4.5 MHz IF
+ *
+ * GPIO[1,5,6] = Oren 51132 pins 27,35,28 respectively
+ *
+ * GPIO[16] = Remote control input
+ */
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
.gpio0 = 0x00008484,
- .gpio1 = 0x00000000,
- .gpio2 = 0x00000000,
- .gpio3 = 0x00000000,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x00008400,
- .gpio1 = 0x00000000,
- .gpio2 = 0x00000000,
- .gpio3 = 0x00000000,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x00008400,
- .gpio1 = 0x00000000,
- .gpio2 = 0x00000000,
- .gpio3 = 0x00000000,
}},
.radio = {
.type = CX88_RADIO,
- .vmux = 2,
- .gpio0 = 0x00008400,
- .gpio1 = 0x00000000,
- .gpio2 = 0x00000000,
- .gpio3 = 0x00000000,
+ .gpio0 = 0x00008404,
},
.mpeg = CX88_MPEG_DVB,
},
@@ -1356,12 +1371,11 @@ struct cx88_board cx88_boards[] = {
}},
},
};
-const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
/* ------------------------------------------------------------------ */
/* PCI subsystem IDs */
-struct cx88_subid cx88_subids[] = {
+static const struct cx88_subid cx88_subids[] = {
{
.subvendor = 0x0070,
.subdevice = 0x3400,
@@ -1667,7 +1681,6 @@ struct cx88_subid cx88_subids[] = {
.card = CX88_BOARD_ADSTECH_PTV_390,
},
};
-const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
/* ----------------------------------------------------------------------- */
/* some leadtek specific stuff */
@@ -1688,12 +1701,12 @@ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
return;
}
- core->has_radio = 1;
- core->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38;
+ core->board.tuner_type = (eeprom_data[6] == 0x13) ?
+ TUNER_PHILIPS_FM1236_MK3 : TUNER_PHILIPS_FM1216ME_MK3;
printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: "
"tuner=%d, eeprom[0]=0x%02x\n",
- core->name, core->tuner_type, eeprom_data[0]);
+ core->name, core->board.tuner_type, eeprom_data[0]);
}
static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
@@ -1701,9 +1714,9 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
struct tveeprom tv;
tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data);
- core->tuner_type = tv.tuner_type;
+ core->board.tuner_type = tv.tuner_type;
core->tuner_formats = tv.tuner_formats;
- core->has_radio = tv.has_radio;
+ core->board.radio.type = tv.has_radio ? CX88_RADIO : 0;
/* Make sure we support the board model */
switch (tv.model)
@@ -1793,8 +1806,9 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data)
name ? name : "unknown");
if (NULL == name)
return;
- core->tuner_type = gdi_tuner[eeprom_data[0x0d]].id;
- core->has_radio = gdi_tuner[eeprom_data[0x0d]].fm;
+ core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id;
+ core->board.radio.type = gdi_tuner[eeprom_data[0x0d]].fm ?
+ CX88_RADIO : 0;
}
/* ----------------------------------------------------------------------- */
@@ -1833,7 +1847,7 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core)
/* ----------------------------------------------------------------------- */
-void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
+static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
{
int i;
@@ -1854,14 +1868,14 @@ void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
}
printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
core->name);
- for (i = 0; i < cx88_bcount; i++)
+ for (i = 0; i < ARRAY_SIZE(cx88_boards); i++)
printk("%s: card=%d -> %s\n",
core->name, i, cx88_boards[i].name);
}
-void cx88_card_setup_pre_i2c(struct cx88_core *core)
+static void cx88_card_setup_pre_i2c(struct cx88_core *core)
{
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
/* Bring the 702 demod up before i2c scanning/attach or devices are hidden */
/* We leave here with the 702 on the bus */
@@ -1875,7 +1889,7 @@ void cx88_card_setup_pre_i2c(struct cx88_core *core)
}
}
-void cx88_card_setup(struct cx88_core *core)
+static void cx88_card_setup(struct cx88_core *core)
{
static u8 eeprom[256];
@@ -1884,7 +1898,7 @@ void cx88_card_setup(struct cx88_core *core)
tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom));
}
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE:
case CX88_BOARD_HAUPPAUGE_ROSLYN:
if (0 == core->i2c_rc)
@@ -1928,7 +1942,7 @@ void cx88_card_setup(struct cx88_core *core)
msleep(1);
cx_set(MO_GP0_IO, 0x00000101);
if (0 == core->i2c_rc &&
- core->board == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID)
+ core->boardnr == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID)
dvico_fusionhdtv_hybrid_init(core);
break;
case CX88_BOARD_KWORLD_DVB_T:
@@ -1966,13 +1980,148 @@ void cx88_card_setup(struct cx88_core *core)
}
break;
}
- if (cx88_boards[core->board].radio.type == CX88_RADIO)
- core->has_radio = 1;
}
/* ------------------------------------------------------------------ */
-EXPORT_SYMBOL(cx88_boards);
+static int cx88_pci_quirks(const char *name, struct pci_dev *pci)
+{
+ unsigned int lat = UNSET;
+ u8 ctrl = 0;
+ u8 value;
+
+ /* check pci quirks */
+ if (pci_pci_problems & PCIPCI_TRITON) {
+ printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
+ name);
+ ctrl |= CX88X_EN_TBFX;
+ }
+ if (pci_pci_problems & PCIPCI_NATOMA) {
+ printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
+ name);
+ ctrl |= CX88X_EN_TBFX;
+ }
+ if (pci_pci_problems & PCIPCI_VIAETBF) {
+ printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
+ name);
+ ctrl |= CX88X_EN_TBFX;
+ }
+ if (pci_pci_problems & PCIPCI_VSFX) {
+ printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
+ name);
+ ctrl |= CX88X_EN_VSFX;
+ }
+#ifdef PCIPCI_ALIMAGIK
+ if (pci_pci_problems & PCIPCI_ALIMAGIK) {
+ printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
+ name);
+ lat = 0x0A;
+ }
+#endif
+
+ /* check insmod options */
+ if (UNSET != latency)
+ lat = latency;
+
+ /* apply stuff */
+ if (ctrl) {
+ pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
+ value |= ctrl;
+ pci_write_config_byte(pci, CX88X_DEVCTRL, value);
+ }
+ if (UNSET != lat) {
+ printk(KERN_INFO "%s: setting pci latency timer to %d\n",
+ name, latency);
+ pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
+ }
+ return 0;
+}
+
+int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci)
+{
+ if (request_mem_region(pci_resource_start(pci,0),
+ pci_resource_len(pci,0),
+ core->name))
+ return 0;
+ printk(KERN_ERR
+ "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n",
+ core->name, PCI_FUNC(pci->devfn),
+ (unsigned long long)pci_resource_start(pci, 0),
+ pci->subsystem_vendor, pci->subsystem_device);
+ return -EBUSY;
+}
+
+/* Allocate and initialize the cx88 core struct. One should hold the
+ * devlist mutex before calling this. */
+struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
+{
+ struct cx88_core *core;
+ int i;
+
+ core = kzalloc(sizeof(*core), GFP_KERNEL);
+
+ atomic_inc(&core->refcount);
+ core->pci_bus = pci->bus->number;
+ core->pci_slot = PCI_SLOT(pci->devfn);
+ core->pci_irqmask = PCI_INT_RISC_RD_BERRINT | PCI_INT_RISC_WR_BERRINT |
+ PCI_INT_BRDG_BERRINT | PCI_INT_SRC_DMA_BERRINT |
+ PCI_INT_DST_DMA_BERRINT | PCI_INT_IPB_DMA_BERRINT;
+ mutex_init(&core->lock);
+
+ core->nr = nr;
+ sprintf(core->name, "cx88[%d]", core->nr);
+ if (0 != cx88_get_resources(core, pci)) {
+ kfree(core);
+ return NULL;
+ }
+
+ /* PCI stuff */
+ cx88_pci_quirks(core->name, pci);
+ core->lmmio = ioremap(pci_resource_start(pci, 0),
+ pci_resource_len(pci, 0));
+ core->bmmio = (u8 __iomem *)core->lmmio;
+
+ /* board config */
+ core->boardnr = UNSET;
+ if (card[core->nr] < ARRAY_SIZE(cx88_boards))
+ core->boardnr = card[core->nr];
+ for (i = 0; UNSET == core->boardnr && i < ARRAY_SIZE(cx88_subids); i++)
+ if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
+ pci->subsystem_device == cx88_subids[i].subdevice)
+ core->boardnr = cx88_subids[i].card;
+ if (UNSET == core->boardnr) {
+ core->boardnr = CX88_BOARD_UNKNOWN;
+ cx88_card_list(core, pci);
+ }
+
+ memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board));
+
+ printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ core->name,pci->subsystem_vendor,
+ pci->subsystem_device, core->board.name,
+ core->boardnr, card[core->nr] == core->boardnr ?
+ "insmod option" : "autodetected");
+
+ if (tuner[core->nr] != UNSET)
+ core->board.tuner_type = tuner[core->nr];
+ if (radio[core->nr] != UNSET)
+ core->board.radio_type = radio[core->nr];
+
+ printk(KERN_INFO "%s: TV tuner type %d, Radio tuner type %d\n",
+ core->name, core->board.tuner_type, core->board.radio_type);
+
+ /* init hardware */
+ cx88_reset(core);
+ cx88_card_setup_pre_i2c(core);
+ cx88_i2c_init(core, pci);
+ cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
+ cx88_card_setup(core);
+ cx88_ir_init(core, pci);
+
+ return core;
+}
+
+/* ------------------------------------------------------------------ */
/*
* Local variables:
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index f31ec96924b..62e8dd24c5f 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -28,7 +28,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/kmod.h>
@@ -52,22 +51,6 @@ static unsigned int core_debug = 0;
module_param(core_debug,int,0644);
MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
-static unsigned int latency = UNSET;
-module_param(latency,int,0444);
-MODULE_PARM_DESC(latency,"pci latency timer");
-
-static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-
-module_param_array(tuner, int, NULL, 0444);
-module_param_array(radio, int, NULL, 0444);
-module_param_array(card, int, NULL, 0444);
-
-MODULE_PARM_DESC(tuner,"tuner type");
-MODULE_PARM_DESC(radio,"radio tuner type");
-MODULE_PARM_DESC(card,"card type");
-
static unsigned int nicam = 0;
module_param(nicam,int,0644);
MODULE_PARM_DESC(nicam,"tv audio is nicam");
@@ -85,13 +68,15 @@ static DEFINE_MUTEX(devlist);
#define NO_SYNC_LINE (-1U)
+/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be
+ generated _after_ lpi lines are transferred. */
static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
- unsigned int lines)
+ unsigned int lines, unsigned int lpi)
{
struct scatterlist *sg;
- unsigned int line,todo;
+ unsigned int line,todo,sol;
/* sync instruction */
if (sync_line != NO_SYNC_LINE)
@@ -104,15 +89,19 @@ static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
offset -= sg_dma_len(sg);
sg++;
}
+ if (lpi && line>0 && !(line % lpi))
+ sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
+ else
+ sol = RISC_SOL;
if (bpl <= sg_dma_len(sg)-offset) {
/* fits into current chunk */
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+ *(rp++)=cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl);
*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
offset+=bpl;
} else {
/* scanline needs to be split */
todo = bpl;
- *(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+ *(rp++)=cpu_to_le32(RISC_WRITE|sol|
(sg_dma_len(sg)-offset));
*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
todo -= (sg_dma_len(sg)-offset);
@@ -163,10 +152,10 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
rp = risc->cpu;
if (UNSET != top_offset)
rp = cx88_risc_field(rp, sglist, top_offset, 0,
- bpl, padding, lines);
+ bpl, padding, lines, 0);
if (UNSET != bottom_offset)
rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
- bpl, padding, lines);
+ bpl, padding, lines, 0);
/* save pointer to jmp instruction address */
risc->jmp = rp;
@@ -176,7 +165,7 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
struct scatterlist *sglist, unsigned int bpl,
- unsigned int lines)
+ unsigned int lines, unsigned int lpi)
{
u32 instructions;
u32 *rp;
@@ -193,7 +182,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
/* write risc instructions */
rp = risc->cpu;
- rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
+ rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi);
/* save pointer to jmp instruction address */
risc->jmp = rp;
@@ -224,10 +213,12 @@ int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
void
cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
{
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, &buf->vb.dma);
- videobuf_dma_free(&buf->vb.dma);
+ videobuf_dma_unmap(q, dma);
+ videobuf_dma_free(dma);
btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
buf->vb.state = STATE_NEEDS_INIT;
}
@@ -451,10 +442,13 @@ void cx88_sram_channel_dump(struct cx88_core *core,
printk("%s: cmds: %-12s: 0x%08x\n",
core->name,name[i],
cx_read(ch->cmds_start + 4*i));
- for (i = 0; i < 4; i++) {
+ for (n = 1, i = 0; i < 4; i++) {
risc = cx_read(ch->cmds_start + 4 * (i+11));
printk("%s: risc%d: ", core->name, i);
- cx88_risc_decode(risc);
+ if (--n)
+ printk("0x%08x [ arg #%d ]\n", risc, n);
+ else
+ n = cx88_risc_decode(risc);
}
for (i = 0; i < 16; i += n) {
risc = cx_read(ch->ctrl_start + 4 * i);
@@ -514,7 +508,7 @@ int cx88_core_irq(struct cx88_core *core, u32 status)
{
int handled = 0;
- if (status & (1<<18)) {
+ if (status & PCI_INT_IR_SMPINT) {
cx88_ir_irq(core);
handled++;
}
@@ -738,7 +732,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
value |= (1 << 15);
value |= (1 << 16);
}
- if (INPUT(core->input)->type == CX88_VMUX_SVIDEO)
+ if (INPUT(core->input).type == CX88_VMUX_SVIDEO)
value |= (1 << 13) | (1 << 5);
if (V4L2_FIELD_INTERLACED == field)
value |= (1 << 3); // VINT (interlaced vertical scaling)
@@ -833,7 +827,7 @@ static int set_tvaudio(struct cx88_core *core)
{
v4l2_std_id norm = core->tvnorm;
- if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
+ if (CX88_VMUX_TELEVISION != INPUT(core->input).type)
return 0;
if (V4L2_STD_PAL_BG & norm) {
@@ -997,61 +991,6 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
/* ------------------------------------------------------------------ */
-static int cx88_pci_quirks(char *name, struct pci_dev *pci)
-{
- unsigned int lat = UNSET;
- u8 ctrl = 0;
- u8 value;
-
- /* check pci quirks */
- if (pci_pci_problems & PCIPCI_TRITON) {
- printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
- name);
- ctrl |= CX88X_EN_TBFX;
- }
- if (pci_pci_problems & PCIPCI_NATOMA) {
- printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
- name);
- ctrl |= CX88X_EN_TBFX;
- }
- if (pci_pci_problems & PCIPCI_VIAETBF) {
- printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
- name);
- ctrl |= CX88X_EN_TBFX;
- }
- if (pci_pci_problems & PCIPCI_VSFX) {
- printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
- name);
- ctrl |= CX88X_EN_VSFX;
- }
-#ifdef PCIPCI_ALIMAGIK
- if (pci_pci_problems & PCIPCI_ALIMAGIK) {
- printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
- name);
- lat = 0x0A;
- }
-#endif
-
- /* check insmod options */
- if (UNSET != latency)
- lat = latency;
-
- /* apply stuff */
- if (ctrl) {
- pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
- value |= ctrl;
- pci_write_config_byte(pci, CX88X_DEVCTRL, value);
- }
- if (UNSET != lat) {
- printk(KERN_INFO "%s: setting pci latency timer to %d\n",
- name, latency);
- pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
- }
- return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
struct video_device *cx88_vdev_init(struct cx88_core *core,
struct pci_dev *pci,
struct video_device *template,
@@ -1067,122 +1006,38 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
vfd->dev = &pci->dev;
vfd->release = video_device_release;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
- core->name, type, cx88_boards[core->board].name);
+ core->name, type, core->board.name);
return vfd;
}
-static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
-{
- if (request_mem_region(pci_resource_start(pci,0),
- pci_resource_len(pci,0),
- core->name))
- return 0;
- printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
- core->name,(unsigned long long)pci_resource_start(pci,0));
- return -EBUSY;
-}
-
struct cx88_core* cx88_core_get(struct pci_dev *pci)
{
struct cx88_core *core;
- struct list_head *item;
- int i;
mutex_lock(&devlist);
- list_for_each(item,&cx88_devlist) {
- core = list_entry(item, struct cx88_core, devlist);
+ list_for_each_entry(core, &cx88_devlist, devlist) {
if (pci->bus->number != core->pci_bus)
continue;
if (PCI_SLOT(pci->devfn) != core->pci_slot)
continue;
- if (0 != get_ressources(core,pci))
- goto fail_unlock;
+ if (0 != cx88_get_resources(core, pci)) {
+ mutex_unlock(&devlist);
+ return NULL;
+ }
atomic_inc(&core->refcount);
mutex_unlock(&devlist);
return core;
}
- core = kzalloc(sizeof(*core),GFP_KERNEL);
- if (NULL == core)
- goto fail_unlock;
-
- atomic_inc(&core->refcount);
- core->pci_bus = pci->bus->number;
- core->pci_slot = PCI_SLOT(pci->devfn);
- core->pci_irqmask = 0x00fc00;
- mutex_init(&core->lock);
-
- core->nr = cx88_devcount++;
- sprintf(core->name,"cx88[%d]",core->nr);
- if (0 != get_ressources(core,pci)) {
- printk(KERN_ERR "CORE %s No more PCI ressources for "
- "subsystem: %04x:%04x, board: %s\n",
- core->name,pci->subsystem_vendor,
- pci->subsystem_device,
- cx88_boards[core->board].name);
-
- cx88_devcount--;
- goto fail_free;
- }
- list_add_tail(&core->devlist,&cx88_devlist);
-
- /* PCI stuff */
- cx88_pci_quirks(core->name, pci);
- core->lmmio = ioremap(pci_resource_start(pci,0),
- pci_resource_len(pci,0));
- core->bmmio = (u8 __iomem *)core->lmmio;
-
- /* board config */
- core->board = UNSET;
- if (card[core->nr] < cx88_bcount)
- core->board = card[core->nr];
- for (i = 0; UNSET == core->board && i < cx88_idcount; i++)
- if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
- pci->subsystem_device == cx88_subids[i].subdevice)
- core->board = cx88_subids[i].card;
- if (UNSET == core->board) {
- core->board = CX88_BOARD_UNKNOWN;
- cx88_card_list(core,pci);
+
+ core = cx88_core_create(pci, cx88_devcount);
+ if (NULL != core) {
+ cx88_devcount++;
+ list_add_tail(&core->devlist, &cx88_devlist);
}
- printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
- core->name,pci->subsystem_vendor,
- pci->subsystem_device,cx88_boards[core->board].name,
- core->board, card[core->nr] == core->board ?
- "insmod option" : "autodetected");
-
- core->tuner_type = tuner[core->nr];
- core->radio_type = radio[core->nr];
- if (UNSET == core->tuner_type)
- core->tuner_type = cx88_boards[core->board].tuner_type;
- if (UNSET == core->radio_type)
- core->radio_type = cx88_boards[core->board].radio_type;
- if (!core->tuner_addr)
- core->tuner_addr = cx88_boards[core->board].tuner_addr;
- if (!core->radio_addr)
- core->radio_addr = cx88_boards[core->board].radio_addr;
-
- printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
- core->tuner_type, core->tuner_addr<<1,
- core->radio_type, core->radio_addr<<1);
-
- core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
-
- /* init hardware */
- cx88_reset(core);
- cx88_card_setup_pre_i2c(core);
- cx88_i2c_init(core,pci);
- cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
- cx88_card_setup(core);
- cx88_ir_init(core,pci);
mutex_unlock(&devlist);
return core;
-
-fail_free:
- kfree(core);
-fail_unlock:
- mutex_unlock(&devlist);
- return NULL;
}
void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
@@ -1229,6 +1084,9 @@ EXPORT_SYMBOL(cx88_vdev_init);
EXPORT_SYMBOL(cx88_core_get);
EXPORT_SYMBOL(cx88_core_put);
+EXPORT_SYMBOL(cx88_ir_start);
+EXPORT_SYMBOL(cx88_ir_stop);
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 1773b40467d..fce19caf9d0 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -378,7 +378,7 @@ static int dvb_register(struct cx8802_dev *dev)
dev->ts_gen_cntrl = 0x0c;
/* init frontend */
- switch (dev->core->board) {
+ switch (dev->core->boardnr) {
case CX88_BOARD_HAUPPAUGE_DVB_T1:
dev->dvb.frontend = dvb_attach(cx22702_attach,
&connexant_refboard_config,
@@ -475,14 +475,15 @@ static int dvb_register(struct cx8802_dev *dev)
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
+ /* MT352 is on a secondary I2C bus made from some GPIO lines */
dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
- &((struct vp3054_i2c_state *)dev->card_priv)->adap);
+ &dev->vp3054->adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap, DVB_PLL_FMD1216ME);
}
#else
- printk("%s: built without vp3054 support\n", dev->core->name);
+ printk(KERN_ERR "%s/2: built without vp3054 support\n", dev->core->name);
#endif
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
@@ -625,12 +626,12 @@ static int dvb_register(struct cx8802_dev *dev)
}
break;
default:
- printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
+ printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->core->name);
break;
}
if (NULL == dev->dvb.frontend) {
- printk("%s: frontend initialization failed\n",dev->core->name);
+ printk(KERN_ERR "%s/2: frontend initialization failed\n", dev->core->name);
return -1;
}
@@ -653,7 +654,7 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
int err = 0;
dprintk( 1, "%s\n", __FUNCTION__);
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
/* We arrive here with either the cx23416 or the cx22702
* on the bus. Take the bus from the cx23416 and enable the
@@ -676,7 +677,7 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
int err = 0;
dprintk( 1, "%s\n", __FUNCTION__);
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
/* Do Nothing, leave the cx22702 on the bus. */
break;
@@ -694,13 +695,13 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
dprintk( 1, "%s\n", __FUNCTION__);
dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
- core->board,
+ core->boardnr,
core->name,
core->pci_bus,
core->pci_slot);
err = -ENODEV;
- if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
+ if (!(core->board.mpeg & CX88_MPEG_DVB))
goto fail_core;
/* If vp3054 isn't enabled, a stub will just return 0 */
@@ -709,8 +710,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
goto fail_core;
/* dvb stuff */
- printk("%s/2: cx2388x based dvb card\n", core->name);
- videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops,
+ printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name);
+ videobuf_queue_pci_init(&dev->dvb.dvbq, &dvb_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_TOP,
@@ -718,7 +719,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
dev);
err = dvb_register(dev);
if (err != 0)
- printk("%s dvb_register failed err = %d\n", __FUNCTION__, err);
+ printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n",
+ core->name, err);
fail_core:
return err;
@@ -747,7 +749,7 @@ static struct cx8802_driver cx8802_dvb_driver = {
static int dvb_init(void)
{
- printk(KERN_INFO "cx2388x dvb driver version %d.%d.%d loaded\n",
+ printk(KERN_INFO "cx88/2: cx2388x dvb driver version %d.%d.%d loaded\n",
(CX88_VERSION_CODE >> 16) & 0xff,
(CX88_VERSION_CODE >> 8) & 0xff,
CX88_VERSION_CODE & 0xff);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 78bbcfab967..c8b1c50625f 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -28,7 +28,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <asm/io.h>
@@ -108,28 +107,28 @@ static int attach_inform(struct i2c_client *client)
if (!client->driver->command)
return 0;
- if (core->radio_type != UNSET) {
- if ((core->radio_addr==ADDR_UNSET)||(core->radio_addr==client->addr)) {
+ if (core->board.radio_type != UNSET) {
+ if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) {
tun_setup.mode_mask = T_RADIO;
- tun_setup.type = core->radio_type;
- tun_setup.addr = core->radio_addr;
+ tun_setup.type = core->board.radio_type;
+ tun_setup.addr = core->board.radio_addr;
client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
}
}
- if (core->tuner_type != UNSET) {
- if ((core->tuner_addr==ADDR_UNSET)||(core->tuner_addr==client->addr)) {
+ if (core->board.tuner_type != UNSET) {
+ if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) {
tun_setup.mode_mask = T_ANALOG_TV;
- tun_setup.type = core->tuner_type;
- tun_setup.addr = core->tuner_addr;
+ tun_setup.type = core->board.tuner_type;
+ tun_setup.addr = core->board.tuner_addr;
client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
}
}
- if (core->tda9887_conf)
- client->driver->command(client, TDA9887_SET_CONFIG, &core->tda9887_conf);
+ if (core->board.tda9887_conf)
+ client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf);
return 0;
}
@@ -146,7 +145,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
if (0 != core->i2c_rc)
return;
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) {
if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
@@ -204,9 +203,9 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
sizeof(core->i2c_algo));
- if (core->tuner_type != TUNER_ABSENT)
+ if (core->board.tuner_type != TUNER_ABSENT)
core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
- if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB)
+ if (core->board.mpeg & CX88_MPEG_DVB)
core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
core->i2c_adap.dev.parent = &pci->dev;
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index f5d4a565346..e52de3968c6 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -27,7 +27,6 @@
#include <linux/input.h>
#include <linux/pci.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include "cx88.h"
#include <media/ir-common.h>
@@ -74,7 +73,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
/* read gpio value */
gpio = cx_read(ir->gpio_addr);
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
/* This board apparently uses a combination of 2 GPIO
to represent the keys. Additionally, the second GPIO
@@ -113,7 +112,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
(gpio & ir->mask_keydown) ? " down" : "",
(gpio & ir->mask_keyup) ? " up" : "");
- if (ir->core->board == CX88_BOARD_NORWOOD_MICRO) {
+ if (ir->core->boardnr == CX88_BOARD_NORWOOD_MICRO) {
u32 gpio_key = cx_read(MO_GP0_IO);
data = (data << 4) | ((gpio_key & 0xf0) >> 4);
@@ -159,7 +158,7 @@ static void cx88_ir_work(struct work_struct *work)
mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
-static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
+void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
{
if (ir->polling) {
setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
@@ -167,17 +166,17 @@ static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
schedule_work(&ir->work);
}
if (ir->sampling) {
- core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */
+ core->pci_irqmask |= PCI_INT_IR_SMPINT;
cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */
cx_write(MO_DDSCFG_IO, 0x5); /* enable */
}
}
-static void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
+void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
{
if (ir->sampling) {
cx_write(MO_DDSCFG_IO, 0x0);
- core->pci_irqmask &= ~(1 << 18);
+ core->pci_irqmask &= ~PCI_INT_IR_SMPINT;
}
if (ir->polling) {
@@ -204,7 +203,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->input = input_dev;
/* detect & configure */
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_DNTV_LIVE_DVB_T:
case CX88_BOARD_KWORLD_DVB_T:
case CX88_BOARD_KWORLD_DVB_T_CX22702:
@@ -314,8 +313,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
}
/* init input device */
- snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)",
- cx88_boards[core->board].name);
+ snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
@@ -406,7 +404,7 @@ void cx88_ir_irq(struct cx88_core *core)
ir_dump_samples(ir->samples, ir->scount);
/* decode it */
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4);
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index da7a6b591a6..448c6738094 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -23,12 +23,10 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
#include <asm/delay.h>
#include "cx88.h"
@@ -56,9 +54,9 @@ static void request_module_async(struct work_struct *work)
{
struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk);
- if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_DVB)
+ if (dev->core->board.mpeg & CX88_MPEG_DVB)
request_module("cx88-dvb");
- if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_BLACKBIRD)
+ if (dev->core->board.mpeg & CX88_MPEG_BLACKBIRD)
request_module("cx88-blackbird");
}
@@ -81,7 +79,8 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
{
struct cx88_core *core = dev->core;
- dprintk(1, "cx8802_start_dma w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
+ dprintk(1, "cx8802_start_dma w: %d, h: %d, f: %d\n",
+ buf->vb.width, buf->vb.height, buf->vb.field);
/* setup fifo + format */
cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
@@ -96,7 +95,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id);
if ( (core->active_type_id == CX88_MPEG_DVB) &&
- (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) ) {
+ (core->board.mpeg & CX88_MPEG_DVB) ) {
dprintk( 1, "cx8802_start_dma doing .dvb\n");
/* negedge driven & software reset */
@@ -104,7 +103,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
udelay(100);
cx_write(MO_PINMUX_IO, 0x00);
cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01);
- switch (core->board) {
+ switch (core->boardnr) {
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
@@ -125,7 +124,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl);
udelay(100);
} else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) &&
- (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) ) {
+ (core->board.mpeg & CX88_MPEG_BLACKBIRD) ) {
dprintk( 1, "cx8802_start_dma doing .blackbird\n");
cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
@@ -139,7 +138,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
udelay(100);
} else {
printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__,
- cx88_boards[core->board].mpeg );
+ core->board.mpeg );
return -EINVAL;
}
@@ -149,7 +148,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
/* enable irqs */
dprintk( 1, "setting the interrupt mask\n" );
- cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04);
+ cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT);
cx_set(MO_TS_INTMSK, 0x1f0011);
/* start dma */
@@ -167,7 +166,7 @@ static int cx8802_stop_dma(struct cx8802_dev *dev)
cx_clear(MO_TS_DMACNTRL, 0x11);
/* disable irqs */
- cx_clear(MO_PCI_INTMSK, 0x000004);
+ cx_clear(MO_PCI_INTMSK, PCI_INT_TSINT);
cx_clear(MO_TS_INTMSK, 0x1f0011);
/* Reset the controller */
@@ -179,45 +178,44 @@ static int cx8802_restart_queue(struct cx8802_dev *dev,
struct cx88_dmaqueue *q)
{
struct cx88_buffer *buf;
- struct list_head *item;
- dprintk( 1, "cx8802_restart_queue\n" );
+ dprintk( 1, "cx8802_restart_queue\n" );
if (list_empty(&q->active))
{
- struct cx88_buffer *prev;
- prev = NULL;
-
- dprintk(1, "cx8802_restart_queue: queue is empty\n" );
-
- for (;;) {
- if (list_empty(&q->queued))
- return 0;
- buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
- if (NULL == prev) {
- list_del(&buf->vb.queue);
- list_add_tail(&buf->vb.queue,&q->active);
- cx8802_start_dma(dev, q, buf);
- buf->vb.state = STATE_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(1,"[%p/%d] restart_queue - first active\n",
- buf,buf->vb.i);
-
- } else if (prev->vb.width == buf->vb.width &&
- prev->vb.height == buf->vb.height &&
- prev->fmt == buf->fmt) {
- list_del(&buf->vb.queue);
- list_add_tail(&buf->vb.queue,&q->active);
- buf->vb.state = STATE_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- dprintk(1,"[%p/%d] restart_queue - move to active\n",
- buf,buf->vb.i);
- } else {
- return 0;
- }
- prev = buf;
- }
+ struct cx88_buffer *prev;
+ prev = NULL;
+
+ dprintk(1, "cx8802_restart_queue: queue is empty\n" );
+
+ for (;;) {
+ if (list_empty(&q->queued))
+ return 0;
+ buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
+ if (NULL == prev) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue,&q->active);
+ cx8802_start_dma(dev, q, buf);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(1,"[%p/%d] restart_queue - first active\n",
+ buf,buf->vb.i);
+
+ } else if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue,&q->active);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ dprintk(1,"[%p/%d] restart_queue - move to active\n",
+ buf,buf->vb.i);
+ } else {
+ return 0;
+ }
+ prev = buf;
+ }
return 0;
}
@@ -225,10 +223,8 @@ static int cx8802_restart_queue(struct cx8802_dev *dev,
dprintk(2,"restart_queue [%p/%d]: restart dma\n",
buf, buf->vb.i);
cx8802_start_dma(dev, q, buf);
- list_for_each(item,&q->active) {
- buf = list_entry(item, struct cx88_buffer, vb.queue);
+ list_for_each_entry(buf, &q->active, vb.queue)
buf->count = q->count++;
- }
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
return 0;
}
@@ -239,6 +235,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
struct cx88_buffer *buf, enum v4l2_field field)
{
int size = dev->ts_packet_size * dev->ts_packet_count;
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
int rc;
dprintk(1, "%s: %p\n", __FUNCTION__, buf);
@@ -254,8 +251,8 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
goto fail;
cx88_risc_databuffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist,
- buf->vb.width, buf->vb.height);
+ dma->sglist,
+ buf->vb.width, buf->vb.height, 0);
}
buf->vb.state = STATE_PREPARED;
return 0;
@@ -414,7 +411,8 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id)
int loop, handled = 0;
for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
- status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x04);
+ status = cx_read(MO_PCI_INTSTAT) &
+ (core->pci_irqmask | PCI_INT_TSINT);
if (0 == status)
goto out;
dprintk( 1, "cx8802_irq\n" );
@@ -425,7 +423,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id)
if (status & core->pci_irqmask)
cx88_core_irq(core,status);
- if (status & 0x04)
+ if (status & PCI_INT_TSINT)
cx8802_mpeg_irq(dev);
};
if (MAX_IRQ_LOOP == loop) {
@@ -572,42 +570,29 @@ int cx8802_resume_common(struct pci_dev *pci_dev)
return 0;
}
+#if defined(CONFIG_VIDEO_CX88_BLACKBIRD) || \
+ defined(CONFIG_VIDEO_CX88_BLACKBIRD_MODULE)
struct cx8802_dev * cx8802_get_device(struct inode *inode)
{
int minor = iminor(inode);
- struct cx8802_dev *h = NULL;
- struct list_head *list;
+ struct cx8802_dev *dev;
- list_for_each(list,&cx8802_devlist) {
- h = list_entry(list, struct cx8802_dev, devlist);
- if (h->mpeg_dev && h->mpeg_dev->minor == minor)
- return h;
- }
+ list_for_each_entry(dev, &cx8802_devlist, devlist)
+ if (dev->mpeg_dev && dev->mpeg_dev->minor == minor)
+ return dev;
return NULL;
}
+EXPORT_SYMBOL(cx8802_get_device);
+#endif
struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype)
{
- struct cx8802_dev *h = NULL;
- struct cx8802_driver *d = NULL;
- struct list_head *list;
- struct list_head *list2;
-
- list_for_each(list,&cx8802_devlist) {
- h = list_entry(list, struct cx8802_dev, devlist);
- if (h != dev)
- continue;
-
- list_for_each(list2, &h->drvlist.devlist) {
- d = list_entry(list2, struct cx8802_driver, devlist);
+ struct cx8802_driver *d;
- /* only unregister the correct driver type */
- if (d->type_id == btype) {
- return d;
- }
- }
- }
+ list_for_each_entry(d, &dev->drvlist, drvlist)
+ if (d->type_id == btype)
+ return d;
return NULL;
}
@@ -671,27 +656,26 @@ static int cx8802_check_driver(struct cx8802_driver *drv)
int cx8802_register_driver(struct cx8802_driver *drv)
{
- struct cx8802_dev *h;
+ struct cx8802_dev *dev;
struct cx8802_driver *driver;
- struct list_head *list;
- int err = 0, i = 0;
+ int err, i = 0;
- printk(KERN_INFO "%s() ->registering driver type=%s access=%s\n", __FUNCTION__ ,
- drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
- drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
+ printk(KERN_INFO
+ "cx88/2: registering cx8802 driver, type: %s access: %s\n",
+ drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
+ drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
if ((err = cx8802_check_driver(drv)) != 0) {
- printk(KERN_INFO "%s() cx8802_driver is invalid\n", __FUNCTION__ );
+ printk(KERN_ERR "cx88/2: cx8802_driver is invalid\n");
return err;
}
- list_for_each(list,&cx8802_devlist) {
- h = list_entry(list, struct cx8802_dev, devlist);
-
- printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n",
- h->core->name,h->pci->subsystem_vendor,
- h->pci->subsystem_device,cx88_boards[h->core->board].name,
- h->core->board);
+ list_for_each_entry(dev, &cx8802_devlist, devlist) {
+ printk(KERN_INFO
+ "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
+ dev->core->name, dev->pci->subsystem_vendor,
+ dev->pci->subsystem_device, dev->core->board.name,
+ dev->core->boardnr);
/* Bring up a new struct for each driver instance */
driver = kzalloc(sizeof(*drv),GFP_KERNEL);
@@ -699,7 +683,7 @@ int cx8802_register_driver(struct cx8802_driver *drv)
return -ENOMEM;
/* Snapshot of the driver registration data */
- drv->core = h->core;
+ drv->core = dev->core;
drv->suspend = cx8802_suspend_common;
drv->resume = cx8802_resume_common;
drv->request_acquire = cx8802_request_acquire;
@@ -710,44 +694,38 @@ int cx8802_register_driver(struct cx8802_driver *drv)
if (err == 0) {
i++;
mutex_lock(&drv->core->lock);
- list_add_tail(&driver->devlist,&h->drvlist.devlist);
+ list_add_tail(&driver->drvlist, &dev->drvlist);
mutex_unlock(&drv->core->lock);
} else {
- printk(KERN_ERR "%s() ->probe failed err = %d\n", __FUNCTION__, err);
+ printk(KERN_ERR
+ "%s/2: cx8802 probe failed, err = %d\n",
+ dev->core->name, err);
}
}
- if (i == 0)
- err = -ENODEV;
- else
- err = 0;
- return err;
+ return i ? 0 : -ENODEV;
}
int cx8802_unregister_driver(struct cx8802_driver *drv)
{
- struct cx8802_dev *h;
- struct cx8802_driver *d;
- struct list_head *list;
- struct list_head *list2, *q;
- int err = 0, i = 0;
-
- printk(KERN_INFO "%s() ->unregistering driver type=%s\n", __FUNCTION__ ,
- drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird");
-
- list_for_each(list,&cx8802_devlist) {
- i++;
- h = list_entry(list, struct cx8802_dev, devlist);
-
- printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n",
- h->core->name,h->pci->subsystem_vendor,
- h->pci->subsystem_device,cx88_boards[h->core->board].name,
- h->core->board);
-
- list_for_each_safe(list2, q, &h->drvlist.devlist) {
- d = list_entry(list2, struct cx8802_driver, devlist);
-
+ struct cx8802_dev *dev;
+ struct cx8802_driver *d, *dtmp;
+ int err = 0;
+
+ printk(KERN_INFO
+ "cx88/2: unregistering cx8802 driver, type: %s access: %s\n",
+ drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
+ drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
+
+ list_for_each_entry(dev, &cx8802_devlist, devlist) {
+ printk(KERN_INFO
+ "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
+ dev->core->name, dev->pci->subsystem_vendor,
+ dev->pci->subsystem_device, dev->core->board.name,
+ dev->core->boardnr);
+
+ list_for_each_entry_safe(d, dtmp, &dev->drvlist, drvlist) {
/* only unregister the correct driver type */
if (d->type_id != drv->type_id)
continue;
@@ -755,11 +733,12 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
err = d->remove(d);
if (err == 0) {
mutex_lock(&drv->core->lock);
- list_del(list2);
+ list_del(&d->drvlist);
mutex_unlock(&drv->core->lock);
+ kfree(d);
} else
- printk(KERN_ERR "%s() ->remove failed err = %d\n", __FUNCTION__, err);
-
+ printk(KERN_ERR "%s/2: cx8802 driver remove "
+ "failed (%d)\n", dev->core->name, err);
}
}
@@ -783,7 +762,7 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
printk("%s/2: cx2388x 8802 Driver Manager\n", core->name);
err = -ENODEV;
- if (!cx88_boards[core->board].mpeg)
+ if (!core->board.mpeg)
goto fail_core;
err = -ENOMEM;
@@ -797,7 +776,7 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
if (err != 0)
goto fail_free;
- INIT_LIST_HEAD(&dev->drvlist.devlist);
+ INIT_LIST_HEAD(&dev->drvlist);
list_add_tail(&dev->devlist,&cx8802_devlist);
/* Maintain a reference so cx88-video can query the 8802 device. */
@@ -817,23 +796,30 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
static void __devexit cx8802_remove(struct pci_dev *pci_dev)
{
struct cx8802_dev *dev;
- struct cx8802_driver *h;
- struct list_head *list;
dev = pci_get_drvdata(pci_dev);
dprintk( 1, "%s\n", __FUNCTION__);
- list_for_each(list,&dev->drvlist.devlist) {
- h = list_entry(list, struct cx8802_driver, devlist);
- dprintk( 1, " ->driver\n");
- if (h->remove == NULL) {
- printk(KERN_ERR "%s .. skipping driver, no probe function\n", __FUNCTION__);
- continue;
+ if (!list_empty(&dev->drvlist)) {
+ struct cx8802_driver *drv, *tmp;
+ int err;
+
+ printk(KERN_WARNING "%s/2: Trying to remove cx8802 driver "
+ "while cx8802 sub-drivers still loaded?!\n",
+ dev->core->name);
+
+ list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) {
+ err = drv->remove(drv);
+ if (err == 0) {
+ mutex_lock(&drv->core->lock);
+ list_del(&drv->drvlist);
+ mutex_unlock(&drv->core->lock);
+ } else
+ printk(KERN_ERR "%s/2: cx8802 driver remove "
+ "failed (%d)\n", dev->core->name, err);
+ kfree(drv);
}
- printk(KERN_INFO "%s .. Removing driver type %d\n", __FUNCTION__, h->type_id);
- cx8802_unregister_driver(h);
- list_del(&dev->drvlist.devlist);
}
/* Destroy any 8802 reference. */
@@ -866,7 +852,7 @@ static struct pci_driver cx8802_pci_driver = {
static int cx8802_init(void)
{
- printk(KERN_INFO "cx2388x cx88-mpeg Driver Manager version %d.%d.%d loaded\n",
+ printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %d.%d.%d loaded\n",
(CX88_VERSION_CODE >> 16) & 0xff,
(CX88_VERSION_CODE >> 8) & 0xff,
CX88_VERSION_CODE & 0xff);
@@ -893,7 +879,6 @@ EXPORT_SYMBOL(cx8802_fini_common);
EXPORT_SYMBOL(cx8802_register_driver);
EXPORT_SYMBOL(cx8802_unregister_driver);
-EXPORT_SYMBOL(cx8802_get_device);
EXPORT_SYMBOL(cx8802_get_driver);
/* ----------------------------------------------------------- */
/*
diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h
index d3bf5b17b1d..2ec52d1cdea 100644
--- a/drivers/media/video/cx88/cx88-reg.h
+++ b/drivers/media/video/cx88/cx88-reg.h
@@ -582,6 +582,28 @@
/* ---------------------------------------------------------------------- */
/* various constants */
+// DMA
+/* Interrupt mask/status */
+#define PCI_INT_VIDINT (1 << 0)
+#define PCI_INT_AUDINT (1 << 1)
+#define PCI_INT_TSINT (1 << 2)
+#define PCI_INT_VIPINT (1 << 3)
+#define PCI_INT_HSTINT (1 << 4)
+#define PCI_INT_TM1INT (1 << 5)
+#define PCI_INT_SRCDMAINT (1 << 6)
+#define PCI_INT_DSTDMAINT (1 << 7)
+#define PCI_INT_RISC_RD_BERRINT (1 << 10)
+#define PCI_INT_RISC_WR_BERRINT (1 << 11)
+#define PCI_INT_BRDG_BERRINT (1 << 12)
+#define PCI_INT_SRC_DMA_BERRINT (1 << 13)
+#define PCI_INT_DST_DMA_BERRINT (1 << 14)
+#define PCI_INT_IPB_DMA_BERRINT (1 << 15)
+#define PCI_INT_I2CDONE (1 << 16)
+#define PCI_INT_I2CRACK (1 << 17)
+#define PCI_INT_IR_SMPINT (1 << 18)
+#define PCI_INT_GPIO_INT0 (1 << 19)
+#define PCI_INT_GPIO_INT1 (1 << 20)
+
#define SEL_BTSC 0x01
#define SEL_EIAJ 0x02
#define SEL_A2 0x04
@@ -590,6 +612,19 @@
#define SEL_FMRADIO 0x20
// AUD_CTL
+#define AUD_INT_DN_RISCI1 (1 << 0)
+#define AUD_INT_UP_RISCI1 (1 << 1)
+#define AUD_INT_RDS_DN_RISCI1 (1 << 2)
+#define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */
+#define AUD_INT_UP_RISCI2 (1 << 5)
+#define AUD_INT_RDS_DN_RISCI2 (1 << 6)
+#define AUD_INT_DN_SYNC (1 << 12)
+#define AUD_INT_UP_SYNC (1 << 13)
+#define AUD_INT_RDS_DN_SYNC (1 << 14)
+#define AUD_INT_OPC_ERR (1 << 16)
+#define AUD_INT_BER_IRQ (1 << 20)
+#define AUD_INT_MCHG_IRQ (1 << 21)
+
#define EN_BTSC_FORCE_MONO 0
#define EN_BTSC_FORCE_STEREO 1
#define EN_BTSC_FORCE_SAP 2
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 1cc2d286a1c..76e5c78d8ae 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -36,7 +36,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/freezer.h>
#include <linux/kernel.h>
@@ -62,6 +61,10 @@ static unsigned int always_analog = 0;
module_param(always_analog,int,0644);
MODULE_PARM_DESC(always_analog,"force analog audio out");
+static unsigned int radio_deemphasis = 0;
+module_param(radio_deemphasis,int,0644);
+MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, "
+ "0=None, 1=50us (elsewhere), 2=75us (USA)");
#define dprintk(fmt, arg...) if (audio_debug) \
printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
@@ -140,7 +143,7 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
cx88_start_audio_dma(core);
- if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
+ if (core->board.mpeg & CX88_MPEG_BLACKBIRD) {
cx_write(AUD_I2SINPUTCNTL, 4);
cx_write(AUD_BAUDRATE, 1);
/* 'pass-thru mode': this enables the i2s output to the mpeg encoder */
@@ -149,7 +152,7 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
cx_write(AUD_I2SCNTL, 0);
/* cx_write(AUD_APB_IN_RATE_ADJ, 0); */
}
- if ((always_analog) || (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))) {
+ if ((always_analog) || (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))) {
ctl |= EN_DAC_ENABLE;
cx_write(AUD_CTL, ctl);
}
@@ -678,6 +681,10 @@ static void set_audio_standard_FM(struct cx88_core *core,
};
/* It is enough to leave default values? */
+ /* No, it's not! The deemphasis registers are reset to the 75us
+ * values by default. Analyzing the spectrum of the decoded audio
+ * reveals that "no deemphasis" is the same as 75 us, while the 50 us
+ * setting results in less deemphasis. */
static const struct rlist fm_no_deemph[] = {
{AUD_POLYPH80SCALEFAC, 0x0003},
@@ -688,6 +695,7 @@ static void set_audio_standard_FM(struct cx88_core *core,
set_audio_start(core, SEL_FMRADIO);
switch (deemph) {
+ default:
case FM_NO_DEEMPH:
set_audio_registers(core, fm_no_deemph);
break;
@@ -757,7 +765,7 @@ void cx88_set_tvaudio(struct cx88_core *core)
set_audio_standard_EIAJ(core);
break;
case WW_FM:
- set_audio_standard_FM(core, FM_NO_DEEMPH);
+ set_audio_standard_FM(core, radio_deemphasis);
break;
case WW_NONE:
default:
@@ -790,9 +798,9 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
core->astat = reg;
/* TODO
- Reading from AUD_STATUS is not enough
- for auto-detecting sap/dual-fm/nicam.
- Add some code here later.
+ Reading from AUD_STATUS is not enough
+ for auto-detecting sap/dual-fm/nicam.
+ Add some code here later.
*/
return;
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index 86c1cf8334b..babb0855640 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -2,7 +2,6 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -67,7 +66,7 @@ static int cx8800_start_vbi_dma(struct cx8800_dev *dev,
q->count = 1;
/* enable irqs */
- cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01);
+ cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT);
cx_set(MO_VID_INTMSK, 0x0f0088);
/* enable capture */
@@ -91,7 +90,7 @@ int cx8800_stop_vbi_dma(struct cx8800_dev *dev)
cx_clear(VID_CAPTURE_CONTROL,0x18);
/* disable irqs */
- cx_clear(MO_PCI_INTMSK, 0x000001);
+ cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT);
cx_clear(MO_VID_INTMSK, 0x0f0088);
return 0;
}
@@ -100,7 +99,6 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
struct cx88_dmaqueue *q)
{
struct cx88_buffer *buf;
- struct list_head *item;
if (list_empty(&q->active))
return 0;
@@ -109,10 +107,8 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
dprintk(2,"restart_queue [%p/%d]: restart dma\n",
buf, buf->vb.i);
cx8800_start_vbi_dma(dev, q, buf);
- list_for_each(item,&q->active) {
- buf = list_entry(item, struct cx88_buffer, vb.queue);
+ list_for_each_entry(buf, &q->active, vb.queue)
buf->count = q->count++;
- }
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
return 0;
}
@@ -173,6 +169,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
return -EINVAL;
if (STATE_NEEDS_INIT == buf->vb.state) {
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
buf->vb.width = VBI_LINE_LENGTH;
buf->vb.height = VBI_LINE_COUNT;
buf->vb.size = size;
@@ -181,7 +178,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
goto fail;
cx88_risc_buffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist,
+ dma->sglist,
0, buf->vb.width * buf->vb.height,
buf->vb.width, 0,
buf->vb.height);
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 06b233a7b20..5ee05f8f3fa 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -28,7 +28,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kmod.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -36,7 +35,6 @@
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/kthread.h>
-#include <linux/dma-mapping.h>
#include <asm/div64.h>
#include "cx88.h"
@@ -369,17 +367,17 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
/* struct cx88_core *core = dev->core; */
dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n",
- input, INPUT(input)->vmux,
- INPUT(input)->gpio0,INPUT(input)->gpio1,
- INPUT(input)->gpio2,INPUT(input)->gpio3);
+ input, INPUT(input).vmux,
+ INPUT(input).gpio0,INPUT(input).gpio1,
+ INPUT(input).gpio2,INPUT(input).gpio3);
core->input = input;
- cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input)->vmux << 14);
- cx_write(MO_GP3_IO, INPUT(input)->gpio3);
- cx_write(MO_GP0_IO, INPUT(input)->gpio0);
- cx_write(MO_GP1_IO, INPUT(input)->gpio1);
- cx_write(MO_GP2_IO, INPUT(input)->gpio2);
+ cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14);
+ cx_write(MO_GP3_IO, INPUT(input).gpio3);
+ cx_write(MO_GP0_IO, INPUT(input).gpio0);
+ cx_write(MO_GP1_IO, INPUT(input).gpio1);
+ cx_write(MO_GP2_IO, INPUT(input).gpio2);
- switch (INPUT(input)->type) {
+ switch (INPUT(input).type) {
case CX88_VMUX_SVIDEO:
cx_set(MO_AFECFG_IO, 0x00000001);
cx_set(MO_INPUT_FORMAT, 0x00010010);
@@ -394,9 +392,9 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input)
break;
}
- if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
+ if (core->board.mpeg & CX88_MPEG_BLACKBIRD) {
/* sets sound input from external adc */
- if (INPUT(input)->extadc)
+ if (INPUT(input).extadc)
cx_set(AUD_CTL, EN_I2SIN_ENABLE);
else
cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
@@ -424,7 +422,7 @@ static int start_video_dma(struct cx8800_dev *dev,
q->count = 1;
/* enable irqs */
- cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01);
+ cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT);
/* Enables corresponding bits at PCI_INT_STAT:
bits 0 to 4: video, audio, transport stream, VIP, Host
@@ -457,7 +455,7 @@ static int stop_video_dma(struct cx8800_dev *dev)
cx_clear(VID_CAPTURE_CONTROL,0x06);
/* disable irqs */
- cx_clear(MO_PCI_INTMSK, 0x000001);
+ cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT);
cx_clear(MO_VID_INTMSK, 0x0f0011);
return 0;
}
@@ -468,17 +466,14 @@ static int restart_video_queue(struct cx8800_dev *dev,
{
struct cx88_core *core = dev->core;
struct cx88_buffer *buf, *prev;
- struct list_head *item;
if (!list_empty(&q->active)) {
buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
dprintk(2,"restart_queue [%p/%d]: restart dma\n",
buf, buf->vb.i);
start_video_dma(dev, q, buf);
- list_for_each(item,&q->active) {
- buf = list_entry(item, struct cx88_buffer, vb.queue);
- buf->count = q->count++;
- }
+ list_for_each_entry(buf, &q->active, vb.queue)
+ buf->count = q->count++;
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
return 0;
}
@@ -536,6 +531,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
struct cx8800_dev *dev = fh->dev;
struct cx88_core *core = dev->core;
struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
int rc, init_buffer = 0;
BUG_ON(NULL == fh->fmt);
@@ -568,30 +564,30 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
cx88_risc_buffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist, 0, UNSET,
+ dma->sglist, 0, UNSET,
buf->bpl, 0, buf->vb.height);
break;
case V4L2_FIELD_BOTTOM:
cx88_risc_buffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist, UNSET, 0,
+ dma->sglist, UNSET, 0,
buf->bpl, 0, buf->vb.height);
break;
case V4L2_FIELD_INTERLACED:
cx88_risc_buffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist, 0, buf->bpl,
+ dma->sglist, 0, buf->bpl,
buf->bpl, buf->bpl,
buf->vb.height >> 1);
break;
case V4L2_FIELD_SEQ_TB:
cx88_risc_buffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist,
+ dma->sglist,
0, buf->bpl * (buf->vb.height >> 1),
buf->bpl, 0,
buf->vb.height >> 1);
break;
case V4L2_FIELD_SEQ_BT:
cx88_risc_buffer(dev->pci, &buf->risc,
- buf->vb.dma.sglist,
+ dma->sglist,
buf->bpl * (buf->vb.height >> 1), 0,
buf->bpl, 0,
buf->vb.height >> 1);
@@ -714,12 +710,10 @@ static int video_open(struct inode *inode, struct file *file)
struct cx8800_dev *h,*dev = NULL;
struct cx88_core *core;
struct cx8800_fh *fh;
- struct list_head *list;
enum v4l2_buf_type type = 0;
int radio = 0;
- list_for_each(list,&cx8800_devlist) {
- h = list_entry(list, struct cx8800_dev, devlist);
+ list_for_each_entry(h, &cx8800_devlist, devlist) {
if (h->video_dev->minor == minor) {
dev = h;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -754,13 +748,13 @@ static int video_open(struct inode *inode, struct file *file)
fh->height = 240;
fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
- videobuf_queue_init(&fh->vidq, &cx8800_video_qops,
+ videobuf_queue_pci_init(&fh->vidq, &cx8800_video_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct cx88_buffer),
fh);
- videobuf_queue_init(&fh->vbiq, &cx8800_vbi_qops,
+ videobuf_queue_pci_init(&fh->vbiq, &cx8800_vbi_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
@@ -768,12 +762,11 @@ static int video_open(struct inode *inode, struct file *file)
fh);
if (fh->radio) {
- int board = core->board;
dprintk(1,"video_open: setting radio device\n");
- cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3);
- cx_write(MO_GP0_IO, cx88_boards[board].radio.gpio0);
- cx_write(MO_GP1_IO, cx88_boards[board].radio.gpio1);
- cx_write(MO_GP2_IO, cx88_boards[board].radio.gpio2);
+ cx_write(MO_GP3_IO, core->board.radio.gpio3);
+ cx_write(MO_GP0_IO, core->board.radio.gpio0);
+ cx_write(MO_GP1_IO, core->board.radio.gpio1);
+ cx_write(MO_GP2_IO, core->board.radio.gpio2);
core->tvaudio = WW_FM;
cx88_set_tvaudio(core);
cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
@@ -1079,8 +1072,7 @@ static int vidioc_querycap (struct file *file, void *priv,
struct cx88_core *core = dev->core;
strcpy(cap->driver, "cx8800");
- strlcpy(cap->card, cx88_boards[core->board].name,
- sizeof(cap->card));
+ strlcpy(cap->card, core->board.name, sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
cap->version = CX88_VERSION_CODE;
cap->capabilities =
@@ -1088,7 +1080,7 @@ static int vidioc_querycap (struct file *file, void *priv,
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
V4L2_CAP_VBI_CAPTURE;
- if (UNSET != core->tuner_type)
+ if (UNSET != core->board.tuner_type)
cap->capabilities |= V4L2_CAP_TUNER;
return 0;
}
@@ -1108,28 +1100,9 @@ static int vidioc_enum_fmt_cap (struct file *file, void *priv,
#ifdef CONFIG_VIDEO_V4L1_COMPAT
static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
{
- struct cx8800_fh *fh = priv;
- struct videobuf_queue *q;
- struct v4l2_requestbuffers req;
- unsigned int i;
- int err;
+ struct cx8800_fh *fh = priv;
- q = get_queue(fh);
- memset(&req,0,sizeof(req));
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- err = videobuf_reqbufs(q,&req);
- if (err < 0)
- return err;
-
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- return 0;
+ return videobuf_cgmbuf (get_queue(fh), mbuf, 8);
}
#endif
@@ -1222,14 +1195,14 @@ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i)
n = i->index;
if (n >= 4)
return -EINVAL;
- if (0 == INPUT(n)->type)
+ if (0 == INPUT(n).type)
return -EINVAL;
memset(i,0,sizeof(*i));
i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name,iname[INPUT(n)->type]);
- if ((CX88_VMUX_TELEVISION == INPUT(n)->type) ||
- (CX88_VMUX_CABLE == INPUT(n)->type))
+ strcpy(i->name,iname[INPUT(n).type]);
+ if ((CX88_VMUX_TELEVISION == INPUT(n).type) ||
+ (CX88_VMUX_CABLE == INPUT(n).type))
i->type = V4L2_INPUT_TYPE_TUNER;
i->std = CX88_NORMS;
return 0;
@@ -1298,7 +1271,7 @@ static int vidioc_g_tuner (struct file *file, void *priv,
struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
u32 reg;
- if (unlikely(UNSET == core->tuner_type))
+ if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
if (0 != t->index)
return -EINVAL;
@@ -1319,7 +1292,7 @@ static int vidioc_s_tuner (struct file *file, void *priv,
{
struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- if (UNSET == core->tuner_type)
+ if (UNSET == core->board.tuner_type)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
@@ -1334,7 +1307,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
struct cx8800_fh *fh = priv;
struct cx88_core *core = fh->dev->core;
- if (unlikely(UNSET == core->tuner_type))
+ if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
/* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
@@ -1349,7 +1322,7 @@ static int vidioc_g_frequency (struct file *file, void *priv,
int cx88_set_freq (struct cx88_core *core,
struct v4l2_frequency *f)
{
- if (unlikely(UNSET == core->tuner_type))
+ if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
if (unlikely(f->tuner != 0))
return -EINVAL;
@@ -1420,8 +1393,7 @@ static int radio_querycap (struct file *file, void *priv,
struct cx88_core *core = dev->core;
strcpy(cap->driver, "cx8800");
- strlcpy(cap->card, cx88_boards[core->board].name,
- sizeof(cap->card));
+ strlcpy(cap->card, core->board.name, sizeof(cap->card));
sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
cap->version = CX88_VERSION_CODE;
cap->capabilities = V4L2_CAP_TUNER;
@@ -1608,7 +1580,8 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id)
int loop, handled = 0;
for (loop = 0; loop < 10; loop++) {
- status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x01);
+ status = cx_read(MO_PCI_INTSTAT) &
+ (core->pci_irqmask | PCI_INT_VIDINT);
if (0 == status)
goto out;
cx_write(MO_PCI_INTSTAT, status);
@@ -1616,7 +1589,7 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id)
if (status & core->pci_irqmask)
cx88_core_irq(core,status);
- if (status & 0x01)
+ if (status & PCI_INT_VIDINT)
cx8800_vid_irq(dev);
};
if (10 == loop) {
@@ -1702,7 +1675,6 @@ static struct video_device cx8800_radio_template =
{
.name = "cx8800-radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &radio_fops,
.minor = -1,
.vidioc_querycap = radio_querycap,
@@ -1717,6 +1689,10 @@ static struct video_device cx8800_radio_template =
.vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
};
/* ----------------------------------------------------------- */
@@ -1818,26 +1794,32 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
err = request_irq(pci_dev->irq, cx8800_irq,
IRQF_SHARED | IRQF_DISABLED, core->name, dev);
if (err < 0) {
- printk(KERN_ERR "%s: can't get IRQ %d\n",
+ printk(KERN_ERR "%s/0: can't get IRQ %d\n",
core->name,pci_dev->irq);
goto fail_core;
}
cx_set(MO_PCI_INTMSK, core->pci_irqmask);
/* load and configure helper modules */
- if (TUNER_ABSENT != core->tuner_type)
+ if (TUNER_ABSENT != core->board.tuner_type)
request_module("tuner");
- if (cx88_boards[ core->board ].audio_chip == AUDIO_CHIP_WM8775)
+ if (core->board.audio_chip == AUDIO_CHIP_WM8775)
request_module("wm8775");
+ switch (core->boardnr) {
+ case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
+ request_module("ir-kbd-i2c");
+ request_module("rtc-isl1208");
+ }
+
/* register v4l devices */
dev->video_dev = cx88_vdev_init(core,dev->pci,
&cx8800_video_template,"video");
err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
video_nr[core->nr]);
if (err < 0) {
- printk(KERN_INFO "%s: can't register video device\n",
+ printk(KERN_ERR "%s/0: can't register video device\n",
core->name);
goto fail_unreg;
}
@@ -1848,20 +1830,20 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
vbi_nr[core->nr]);
if (err < 0) {
- printk(KERN_INFO "%s/0: can't register vbi device\n",
+ printk(KERN_ERR "%s/0: can't register vbi device\n",
core->name);
goto fail_unreg;
}
printk(KERN_INFO "%s/0: registered device vbi%d\n",
core->name,dev->vbi_dev->minor & 0x1f);
- if (core->has_radio) {
+ if (core->board.radio.type == CX88_RADIO) {
dev->radio_dev = cx88_vdev_init(core,dev->pci,
&cx8800_radio_template,"radio");
err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
radio_nr[core->nr]);
if (err < 0) {
- printk(KERN_INFO "%s/0: can't register radio device\n",
+ printk(KERN_ERR "%s/0: can't register radio device\n",
core->name);
goto fail_unreg;
}
@@ -1881,12 +1863,12 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
mutex_unlock(&core->lock);
/* start tvaudio thread */
- if (core->tuner_type != TUNER_ABSENT) {
+ if (core->board.tuner_type != TUNER_ABSENT) {
core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
if (IS_ERR(core->kthread)) {
err = PTR_ERR(core->kthread);
- printk(KERN_ERR "Failed to create cx88 audio thread, err=%d\n",
- err);
+ printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n",
+ core->name, err);
}
}
return 0;
@@ -1937,17 +1919,19 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
/* stop video+vbi capture */
spin_lock(&dev->slock);
if (!list_empty(&dev->vidq.active)) {
- printk("%s: suspend video\n", core->name);
+ printk("%s/0: suspend video\n", core->name);
stop_video_dma(dev);
del_timer(&dev->vidq.timeout);
}
if (!list_empty(&dev->vbiq.active)) {
- printk("%s: suspend vbi\n", core->name);
+ printk("%s/0: suspend vbi\n", core->name);
cx8800_stop_vbi_dma(dev);
del_timer(&dev->vbiq.timeout);
}
spin_unlock(&dev->slock);
+ if (core->ir)
+ cx88_ir_stop(core, core->ir);
/* FIXME -- shutdown device */
cx88_shutdown(core);
@@ -1968,8 +1952,8 @@ static int cx8800_resume(struct pci_dev *pci_dev)
if (dev->state.disabled) {
err=pci_enable_device(pci_dev);
if (err) {
- printk(KERN_ERR "%s: can't enable device\n",
- core->name);
+ printk(KERN_ERR "%s/0: can't enable device\n",
+ core->name);
return err;
}
@@ -1977,9 +1961,7 @@ static int cx8800_resume(struct pci_dev *pci_dev)
}
err= pci_set_power_state(pci_dev, PCI_D0);
if (err) {
- printk(KERN_ERR "%s: can't enable device\n",
- core->name);
-
+ printk(KERN_ERR "%s/0: can't set power state\n", core->name);
pci_disable_device(pci_dev);
dev->state.disabled = 1;
@@ -1989,15 +1971,19 @@ static int cx8800_resume(struct pci_dev *pci_dev)
/* FIXME: re-initialize hardware */
cx88_reset(core);
+ if (core->ir)
+ cx88_ir_start(core, core->ir);
+
+ cx_set(MO_PCI_INTMSK, core->pci_irqmask);
/* restart video+vbi capture */
spin_lock(&dev->slock);
if (!list_empty(&dev->vidq.active)) {
- printk("%s: resume video\n", core->name);
+ printk("%s/0: resume video\n", core->name);
restart_video_queue(dev,&dev->vidq);
}
if (!list_empty(&dev->vbiq.active)) {
- printk("%s: resume vbi\n", core->name);
+ printk("%s/0: resume vbi\n", core->name);
cx8800_restart_vbi_queue(dev,&dev->vbiq);
}
spin_unlock(&dev->slock);
@@ -2033,7 +2019,7 @@ static struct pci_driver cx8800_pci_driver = {
static int cx8800_init(void)
{
- printk(KERN_INFO "cx2388x v4l2 driver version %d.%d.%d loaded\n",
+ printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n",
(CX88_VERSION_CODE >> 16) & 0xff,
(CX88_VERSION_CODE >> 8) & 0xff,
CX88_VERSION_CODE & 0xff);
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
index cd0877636a3..6ce5af48847 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -23,7 +23,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <asm/io.h>
@@ -42,7 +41,7 @@ static void vp3054_bit_setscl(void *data, int state)
{
struct cx8802_dev *dev = data;
struct cx88_core *core = dev->core;
- struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+ struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
if (state) {
vp3054_i2c->state |= 0x0001; /* SCL high */
@@ -59,7 +58,7 @@ static void vp3054_bit_setsda(void *data, int state)
{
struct cx8802_dev *dev = data;
struct cx88_core *core = dev->core;
- struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+ struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
if (state) {
vp3054_i2c->state |= 0x0002; /* SDA high */
@@ -111,13 +110,13 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
struct vp3054_i2c_state *vp3054_i2c;
int rc;
- if (core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+ if (core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
return 0;
- dev->card_priv = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL);
- if (dev->card_priv == NULL)
+ vp3054_i2c = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL);
+ if (vp3054_i2c == NULL)
return -ENOMEM;
- vp3054_i2c = dev->card_priv;
+ dev->vp3054 = vp3054_i2c;
memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
sizeof(vp3054_i2c->algo));
@@ -140,8 +139,8 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
if (0 != rc) {
printk("%s: vp3054_i2c register FAILED\n", core->name);
- kfree(dev->card_priv);
- dev->card_priv = NULL;
+ kfree(dev->vp3054);
+ dev->vp3054 = NULL;
}
return rc;
@@ -149,10 +148,10 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
void vp3054_i2c_remove(struct cx8802_dev *dev)
{
- struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
+ struct vp3054_i2c_state *vp3054_i2c = dev->vp3054;
if (vp3054_i2c == NULL ||
- dev->core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+ dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
return;
i2c_del_adapter(&vp3054_i2c->adap);
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 809126866a3..eb296bdecb1 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -28,11 +28,11 @@
#include <media/v4l2-common.h>
#include <media/tuner.h>
#include <media/tveeprom.h>
-#include <media/video-buf.h>
+#include <media/videobuf-dma-sg.h>
#include <media/cx2341x.h>
#include <media/audiochip.h>
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
-#include <media/video-buf-dvb.h>
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
+#include <media/videobuf-dvb.h>
#endif
#include "btcx-risc.h"
@@ -226,8 +226,8 @@ enum cx88_itype {
struct cx88_input {
enum cx88_itype type;
- unsigned int vmux;
u32 gpio0, gpio1, gpio2, gpio3;
+ unsigned int vmux:2;
unsigned int extadc:1;
};
@@ -250,7 +250,7 @@ struct cx88_subid {
u32 card;
};
-#define INPUT(nr) (&cx88_boards[core->board].input[nr])
+#define INPUT(nr) (core->board.input[nr])
/* ----------------------------------------------------------- */
/* device / file handle status */
@@ -304,19 +304,14 @@ struct cx88_core {
u32 i2c_state, i2c_rc;
/* config info -- analog */
- unsigned int board;
- unsigned int tuner_type;
- unsigned int radio_type;
- unsigned char tuner_addr;
- unsigned char radio_addr;
- unsigned int tda9887_conf;
- unsigned int has_radio;
+ unsigned int boardnr;
+ struct cx88_board board;
/* Supported V4L _STD_ tuner formats */
unsigned int tuner_formats;
/* config info -- dvb */
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
#endif
@@ -417,7 +412,9 @@ struct cx8802_suspend_state {
struct cx8802_driver {
struct cx88_core *core;
- struct list_head devlist;
+
+ /* List of drivers attached to device */
+ struct list_head drvlist;
/* Type of driver and access required */
enum cx88_board_type type_id;
@@ -458,27 +455,33 @@ struct cx8802_dev {
/* for blackbird only */
struct list_head devlist;
+#if defined(CONFIG_VIDEO_CX88_BLACKBIRD) || \
+ defined(CONFIG_VIDEO_CX88_BLACKBIRD_MODULE)
struct video_device *mpeg_dev;
u32 mailbox;
int width;
int height;
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
+ /* mpeg params */
+ struct cx2341x_mpeg_params params;
+#endif
+
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
/* for dvb only */
struct videobuf_dvb dvb;
+#endif
- void *card_priv;
+#if defined(CONFIG_VIDEO_CX88_VP3054) || \
+ defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+ /* For VP3045 secondary I2C bus support */
+ struct vp3054_i2c_state *vp3054;
#endif
/* for switching modulation types */
unsigned char ts_gen_cntrl;
- /* mpeg params */
- struct cx2341x_mpeg_params params;
-
/* List of attached drivers */
- struct cx8802_driver drvlist;
- struct work_struct request_module_wk;
-
+ struct list_head drvlist;
+ struct work_struct request_module_wk;
};
/* ----------------------------------------------------------- */
@@ -524,7 +527,7 @@ cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
extern int
cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
struct scatterlist *sglist, unsigned int bpl,
- unsigned int lines);
+ unsigned int lines, unsigned int lpi);
extern int
cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
u32 reg, u32 mask, u32 value);
@@ -585,15 +588,9 @@ extern void cx88_call_i2c_clients(struct cx88_core *core,
/* ----------------------------------------------------------- */
/* cx88-cards.c */
-extern struct cx88_board cx88_boards[];
-extern const unsigned int cx88_bcount;
-
-extern struct cx88_subid cx88_subids[];
-extern const unsigned int cx88_idcount;
-
-extern void cx88_card_list(struct cx88_core *core, struct pci_dev *pci);
-extern void cx88_card_setup(struct cx88_core *core);
-extern void cx88_card_setup_pre_i2c(struct cx88_core *core);
+extern int cx88_get_resources(const struct cx88_core *core,
+ struct pci_dev *pci);
+extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr);
/* ----------------------------------------------------------- */
/* cx88-tvaudio.c */
@@ -625,6 +622,8 @@ struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board
int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci);
int cx88_ir_fini(struct cx88_core *core);
void cx88_ir_irq(struct cx88_core *core);
+void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir);
+void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir);
/* ----------------------------------------------------------- */
/* cx88-mpeg.c */
diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
index 0fcc935828f..255dae30370 100644
--- a/drivers/media/video/dpc7146.c
+++ b/drivers/media/video/dpc7146.c
@@ -92,7 +92,6 @@ static int dpc_probe(struct saa7146_dev* dev)
{
struct dpc* dpc = NULL;
struct i2c_client *client;
- struct list_head *item;
dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL);
if( NULL == dpc ) {
@@ -116,11 +115,9 @@ static int dpc_probe(struct saa7146_dev* dev)
}
/* loop through all i2c-devices on the bus and look who is there */
- list_for_each(item,&dpc->i2c_adapter.clients) {
- client = list_entry(item, struct i2c_client, list);
+ list_for_each_entry(client, &dpc->i2c_adapter.clients, list)
if( I2C_SAA7111A == client->addr )
dpc->saa7111a = client;
- }
/* check if all devices are present */
if( 0 == dpc->saa7111a ) {
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index 5b6a4037160..c1127802ad9 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_EM28XX
tristate "Empia EM2800/2820/2840 USB video capture support"
- depends on VIDEO_V4L1 && I2C
+ depends on VIDEO_V4L1 && I2C && INPUT
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_IR
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 255a47dfb84..d56484f2046 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -24,7 +24,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/usb.h>
#include <linux/vmalloc.h>
@@ -649,7 +648,7 @@ void em28xx_uninit_isoc(struct em28xx *dev)
*/
int em28xx_init_isoc(struct em28xx *dev)
{
- /* change interface to 3 which allowes the biggest packet sizes */
+ /* change interface to 3 which allows the biggest packet sizes */
int i, errCode;
const int sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
@@ -674,6 +673,7 @@ int em28xx_init_isoc(struct em28xx *dev)
("unable to allocate %i bytes for transfer buffer %i\n",
sb_size, i);
em28xx_uninit_isoc(dev);
+ usb_free_urb(urb);
return -ENOMEM;
}
memset(dev->transfer_buffer[i], 0, sb_size);
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 54ccc6e1f92..e3a4aa7a9df 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -383,15 +383,6 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
/* ----------------------------------------------------------- */
/*
- * algo_control()
- */
-static int algo_control(struct i2c_adapter *adapter,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
-/*
* functionality()
*/
static u32 functionality(struct i2c_adapter *adap)
@@ -425,8 +416,10 @@ static int attach_inform(struct i2c_client *client)
struct em28xx *dev = client->adapter->algo_data;
switch (client->addr << 1) {
- case 0x43:
- case 0x4b:
+ case 0x86:
+ case 0x84:
+ case 0x96:
+ case 0x94:
{
struct tuner_setup tun_setup;
@@ -475,7 +468,6 @@ static int attach_inform(struct i2c_client *client)
static struct i2c_algorithm em28xx_algo = {
.master_xfer = em28xx_i2c_xfer,
- .algo_control = algo_control,
.functionality = functionality,
};
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 55d45b0032c..e3894b68c4e 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -22,7 +22,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 40307f3f6fe..2529c298b86 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -32,6 +32,7 @@
#include <linux/usb.h>
#include <linux/i2c.h>
#include <linux/version.h>
+#include <linux/mm.h>
#include <linux/video_decoder.h>
#include <linux/mutex.h>
@@ -252,10 +253,8 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
int minor = iminor(inode);
int errCode = 0;
struct em28xx *h,*dev = NULL;
- struct list_head *list;
- list_for_each(list,&em28xx_devlist) {
- h = list_entry(list, struct em28xx, devlist);
+ list_for_each_entry(h, &em28xx_devlist, devlist) {
if (h->vdev->minor == minor) {
dev = h;
dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -268,8 +267,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
if (NULL == dev)
return -ENODEV;
- filp->private_data=dev;
-
em28xx_videodbg("open minor=%d type=%s users=%d\n",
minor,v4l2_type_names[dev->type],dev->users);
@@ -911,7 +908,7 @@ static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_form
/* stop io in case it is already in progress */
if (dev->stream == STREAM_ON) {
- em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n");
+ em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n");
if ((ret = em28xx_stream_interrupt(dev)))
return ret;
}
@@ -1621,7 +1618,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
/* Fills VBI device info */
dev->vbi_dev->type = VFL_TYPE_VBI;
- dev->vbi_dev->hardware = 0;
dev->vbi_dev->fops = &em28xx_v4l_fops;
dev->vbi_dev->minor = -1;
dev->vbi_dev->dev = &dev->udev->dev;
@@ -1633,7 +1629,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->vdev->type = VID_TYPE_CAPTURE;
if (dev->has_tuner)
dev->vdev->type |= VID_TYPE_TUNER;
- dev->vdev->hardware = 0;
dev->vdev->fops = &em28xx_v4l_fops;
dev->vdev->minor = -1;
dev->vdev->dev = &dev->udev->dev;
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index 585bd1fe076..d19d73b81ed 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -22,7 +22,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/param.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/device.h>
@@ -707,7 +706,8 @@ static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
NOTE 2: buffers are PAGE_SIZE long
*/
-static ssize_t et61x251_show_reg(struct class_device* cd, char* buf)
+static ssize_t et61x251_show_reg(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct et61x251_device* cam;
ssize_t count;
@@ -730,7 +730,8 @@ static ssize_t et61x251_show_reg(struct class_device* cd, char* buf)
static ssize_t
-et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
+et61x251_store_reg(struct device* cd,
+ struct device_attribute *attr, const char* buf, size_t len)
{
struct et61x251_device* cam;
u8 index;
@@ -762,7 +763,8 @@ et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
}
-static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
+static ssize_t et61x251_show_val(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct et61x251_device* cam;
ssize_t count;
@@ -793,7 +795,8 @@ static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
static ssize_t
-et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
+et61x251_store_val(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct et61x251_device* cam;
u8 value;
@@ -831,7 +834,8 @@ et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
}
-static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
+static ssize_t et61x251_show_i2c_reg(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct et61x251_device* cam;
ssize_t count;
@@ -856,7 +860,8 @@ static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
static ssize_t
-et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
+et61x251_store_i2c_reg(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct et61x251_device* cam;
u8 index;
@@ -888,7 +893,8 @@ et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
}
-static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
+static ssize_t et61x251_show_i2c_val(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct et61x251_device* cam;
ssize_t count;
@@ -924,7 +930,8 @@ static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
static ssize_t
-et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
+et61x251_store_i2c_val(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct et61x251_device* cam;
u8 value;
@@ -967,42 +974,40 @@ et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
}
-static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
- et61x251_show_reg, et61x251_store_reg);
-static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
- et61x251_show_val, et61x251_store_val);
-static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
- et61x251_show_i2c_reg, et61x251_store_i2c_reg);
-static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
- et61x251_show_i2c_val, et61x251_store_i2c_val);
+static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
+ et61x251_show_reg, et61x251_store_reg);
+static DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
+ et61x251_show_val, et61x251_store_val);
+static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
+ et61x251_show_i2c_reg, et61x251_store_i2c_reg);
+static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
+ et61x251_show_i2c_val, et61x251_store_i2c_val);
static int et61x251_create_sysfs(struct et61x251_device* cam)
{
- struct class_device *classdev = &(cam->v4ldev->class_dev);
+ struct device *classdev = &(cam->v4ldev->class_dev);
int err = 0;
- if ((err = class_device_create_file(classdev, &class_device_attr_reg)))
+ if ((err = device_create_file(classdev, &dev_attr_reg)))
goto err_out;
- if ((err = class_device_create_file(classdev, &class_device_attr_val)))
+ if ((err = device_create_file(classdev, &dev_attr_val)))
goto err_reg;
if (cam->sensor.sysfs_ops) {
- if ((err = class_device_create_file(classdev,
- &class_device_attr_i2c_reg)))
+ if ((err = device_create_file(classdev, &dev_attr_i2c_reg)))
goto err_val;
- if ((err = class_device_create_file(classdev,
- &class_device_attr_i2c_val)))
+ if ((err = device_create_file(classdev, &dev_attr_i2c_val)))
goto err_i2c_reg;
}
err_i2c_reg:
if (cam->sensor.sysfs_ops)
- class_device_remove_file(classdev, &class_device_attr_i2c_reg);
+ device_remove_file(classdev, &dev_attr_i2c_reg);
err_val:
- class_device_remove_file(classdev, &class_device_attr_val);
+ device_remove_file(classdev, &dev_attr_val);
err_reg:
- class_device_remove_file(classdev, &class_device_attr_reg);
+ device_remove_file(classdev, &dev_attr_reg);
err_out:
return err;
}
@@ -2580,7 +2585,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera");
cam->v4ldev->owner = THIS_MODULE;
cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
- cam->v4ldev->hardware = 0;
cam->v4ldev->fops = &et61x251_fops;
cam->v4ldev->minor = video_nr[dev_nr];
cam->v4ldev->release = video_device_release;
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 2d709e06467..29779d8bf7f 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -10,6 +10,8 @@
* Ulrich Mueller <ulrich.mueller42@web.de>
* modified for em2820 based USB TV tuners by
* Markus Rechberger <mrechberger@gmail.com>
+ * modified for DViCO Fusion HDTV 5 RT GOLD by
+ * Chaogui Zhang <czhang1974@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,7 +30,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -142,6 +143,30 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
+static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char buf[4];
+
+ /* poll IR chip */
+ if (4 != i2c_master_recv(&ir->c,buf,4)) {
+ dprintk(1,"read error\n");
+ return -EIO;
+ }
+
+ if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0)
+ dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __FUNCTION__,
+ buf[0], buf[1], buf[2], buf[3]);
+
+ /* no key pressed or signal from other ir remote */
+ if(buf[0] != 0x1 || buf[1] != 0xfe)
+ return 0;
+
+ *ir_key = buf[2];
+ *ir_raw = (buf[2] << 8) | buf[3];
+
+ return 1;
+}
+
static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char b;
@@ -364,6 +389,12 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
ir_type = IR_TYPE_OTHER;
ir_codes = ir_codes_empty;
break;
+ case 0x6b:
+ name = "FusionHDTV";
+ ir->get_key = get_key_fusionhdtv;
+ ir_type = IR_TYPE_RC5;
+ ir_codes = ir_codes_fusionhdtv_mce;
+ break;
case 0x7a:
case 0x47:
case 0x71:
@@ -475,7 +506,8 @@ static int ir_probe(struct i2c_adapter *adap)
static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 };
static const int probe_em28XX[] = { 0x30, 0x47, -1 };
- static const int probe_cx88[] = { 0x18, 0x71, -1 };
+ static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
+ static const int probe_cx23885[] = { 0x6b, -1 };
const int *probe = NULL;
struct i2c_client c;
unsigned char buf;
@@ -497,6 +529,9 @@ static int ir_probe(struct i2c_adapter *adap)
case I2C_HW_B_CX2388x:
probe = probe_cx88;
break;
+ case I2C_HW_B_CX23885:
+ probe = probe_cx23885;
+ break;
}
if (NULL == probe)
return 0;
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
index e43beb2c9cb..854cc9c30ca 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -14,6 +14,7 @@ config VIDEO_IVTV
select VIDEO_CS53L32A
select VIDEO_WM8775
select VIDEO_WM8739
+ select VIDEO_VP27SMPX
select VIDEO_UPD64031A
select VIDEO_UPD64083
---help---
@@ -25,3 +26,19 @@ config VIDEO_IVTV
To compile this driver as a module, choose M here: the
module will be called ivtv.
+
+config VIDEO_FB_IVTV
+ tristate "Conexant cx23415 framebuffer support"
+ depends on VIDEO_IVTV && FB && EXPERIMENTAL
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ This is a framebuffer driver for the Conexant cx23415 MPEG
+ encoder/decoder.
+
+ This is used in the Hauppauge PVR-350 card. There is a driver
+ homepage at <http://www.ivtvdriver.org>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ivtvfb.
diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile
index 7e95148fbf4..e8eefd96d89 100644
--- a/drivers/media/video/ivtv/Makefile
+++ b/drivers/media/video/ivtv/Makefile
@@ -1,7 +1,8 @@
-ivtv-objs := ivtv-audio.o ivtv-cards.o ivtv-controls.o \
+ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \
ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \
ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \
ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \
- ivtv-vbi.o ivtv-video.o ivtv-yuv.o
+ ivtv-vbi.o ivtv-yuv.o
obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
+obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
diff --git a/drivers/media/video/ivtv/ivtv-audio.c b/drivers/media/video/ivtv/ivtv-audio.c
deleted file mode 100644
index d702b8b539a..00000000000
--- a/drivers/media/video/ivtv/ivtv-audio.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- Audio-related ivtv functions.
- Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
- Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "ivtv-driver.h"
-#include "ivtv-mailbox.h"
-#include "ivtv-i2c.h"
-#include "ivtv-gpio.h"
-#include "ivtv-cards.h"
-#include "ivtv-audio.h"
-#include <media/msp3400.h>
-#include <linux/videodev.h>
-
-/* Selects the audio input and output according to the current
- settings. */
-int ivtv_audio_set_io(struct ivtv *itv)
-{
- struct v4l2_routing route;
- u32 audio_input;
- int mux_input;
-
- /* Determine which input to use */
- if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
- audio_input = itv->card->radio_input.audio_input;
- mux_input = itv->card->radio_input.muxer_input;
- } else {
- audio_input = itv->card->audio_inputs[itv->audio_input].audio_input;
- mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input;
- }
-
- /* handle muxer chips */
- route.input = mux_input;
- route.output = 0;
- ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
-
- route.input = audio_input;
- if (itv->card->hw_audio & IVTV_HW_MSP34XX) {
- route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
- }
- return ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
-}
-
-void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route)
-{
- ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
-}
-
-void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq)
-{
- static u32 freqs[3] = { 44100, 48000, 32000 };
-
- /* The audio clock of the digitizer must match the codec sample
- rate otherwise you get some very strange effects. */
- if (freq > 2)
- return;
- ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]);
-}
-
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index 8eab0208388..b6a8be622d3 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -616,7 +616,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = {
.hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
.hw_audio = IVTV_HW_GPIO,
.hw_audio_ctrl = IVTV_HW_WM8739,
- .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TVAUDIO |
+ .hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_VP27SMPX |
IVTV_HW_TUNER | IVTV_HW_WM8739 |
IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
.video_inputs = {
@@ -654,7 +654,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = {
.hw_audio = IVTV_HW_GPIO,
.hw_audio_ctrl = IVTV_HW_WM8739,
.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER |
- IVTV_HW_TVAUDIO | IVTV_HW_WM8739,
+ IVTV_HW_VP27SMPX | IVTV_HW_WM8739,
.video_inputs = {
{ IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 },
{ IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 },
@@ -823,9 +823,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = {
/* ------------------------------------------------------------------------- */
-#ifdef HAVE_XC3028
-
-/* Yuan PG600-2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 cards */
+/* Yuan PG600-2/GotView PCI DVD Lite cards */
static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = {
{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 },
@@ -835,29 +833,87 @@ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = {
static const struct ivtv_card ivtv_card_pg600v2 = {
.type = IVTV_CARD_PG600V2,
- .name = "Yuan PG600-2, GotView PCI DVD Lite, Club3D ZAP-TV1x01",
+ .name = "Yuan PG600-2, GotView PCI DVD Lite",
.v4l2_capabilities = IVTV_CAP_ENCODER,
.hw_video = IVTV_HW_CX25840,
.hw_audio = IVTV_HW_CX25840,
.hw_audio_ctrl = IVTV_HW_CX25840,
.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
.video_inputs = {
- { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 },
- { IVTV_CARD_INPUT_SVIDEO1, 1,
+ { IVTV_CARD_INPUT_SVIDEO1, 0,
CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
},
.audio_inputs = {
- { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL },
},
- .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
.tuners = {
{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
},
- .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */
.pci_list = ivtv_pci_pg600v2,
};
-#endif
+
+/* ------------------------------------------------------------------------- */
+
+/* Club3D ZAP-TV1x01 cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_club3d[] = {
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3, 0x0600 },
+ { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_club3d = {
+ .type = IVTV_CARD_CLUB3D,
+ .name = "Club3D ZAP-TV1x01",
+ .v4l2_capabilities = IVTV_CAP_ENCODER,
+ .hw_video = IVTV_HW_CX25840,
+ .hw_audio = IVTV_HW_CX25840,
+ .hw_audio_ctrl = IVTV_HW_CX25840,
+ .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+ .video_inputs = {
+ { IVTV_CARD_INPUT_SVIDEO1, 0,
+ CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE3 },
+ },
+ .audio_inputs = {
+ { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL },
+ },
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
+ },
+ .pci_list = ivtv_pci_club3d,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerTV MCE 116 Plus (M116) card */
+
+static const struct ivtv_card_pci_info ivtv_pci_avertv_mce116[] = {
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc439 },
+ { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_avertv_mce116 = {
+ .type = IVTV_CARD_AVERTV_MCE116,
+ .name = "AVerTV MCE 116 Plus",
+ .v4l2_capabilities = IVTV_CAP_ENCODER,
+ .hw_video = IVTV_HW_CX25840,
+ .hw_audio = IVTV_HW_CX25840,
+ .hw_audio_ctrl = IVTV_HW_CX25840,
+ .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
+ .video_inputs = {
+ { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+ },
+ .audio_inputs = {
+ { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 },
+ },
+ .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
+ },
+ .pci_list = ivtv_pci_avertv_mce116,
+};
static const struct ivtv_card *ivtv_card_list[] = {
&ivtv_card_pvr250,
@@ -878,9 +934,9 @@ static const struct ivtv_card *ivtv_card_list[] = {
&ivtv_card_gotview_pci_dvd2,
&ivtv_card_yuan_mpc622,
&ivtv_card_dctmvtvp1,
-#ifdef HAVE_XC3028
&ivtv_card_pg600v2,
-#endif
+ &ivtv_card_club3d,
+ &ivtv_card_avertv_mce116,
/* Variations of standard cards but with the same PCI IDs.
These cards must come last in this list. */
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 91e9e90c14a..ff46e5ae865 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -18,6 +18,68 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_CARDS_H
+#define IVTV_CARDS_H
+
+/* Supported cards */
+#define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */
+#define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */
+#define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two
+ PVR150s on one PCI board) */
+#define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */
+#define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */
+#define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160
+ cx23415 based, but does not have tv-out */
+#define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */
+#define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */
+#define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */
+#define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */
+#define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */
+#define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
+#define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */
+#define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */
+#define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */
+#define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */
+#define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */
+#define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */
+#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */
+#define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */
+#define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */
+#define IVTV_CARD_LAST 20
+
+/* Variants of existing cards but with the same PCI IDs. The driver
+ detects these based on other device information.
+ These cards must always come last.
+ New cards must be inserted above, and the indices of the cards below
+ must be adjusted accordingly. */
+
+/* PVR-350 V1 (uses saa7114) */
+#define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1)
+/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
+#define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2)
+#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3)
+
+/* system vendor and device IDs */
+#define PCI_VENDOR_ID_ICOMP 0x4444
+#define PCI_DEVICE_ID_IVTV15 0x0803
+#define PCI_DEVICE_ID_IVTV16 0x0016
+
+/* subsystem vendor ID */
+#define IVTV_PCI_ID_HAUPPAUGE 0x0070
+#define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270
+#define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070
+#define IVTV_PCI_ID_ADAPTEC 0x9005
+#define IVTV_PCI_ID_AVERMEDIA 0x1461
+#define IVTV_PCI_ID_YUAN1 0x12ab
+#define IVTV_PCI_ID_YUAN2 0xff01
+#define IVTV_PCI_ID_YUAN3 0xffab
+#define IVTV_PCI_ID_YUAN4 0xfbab
+#define IVTV_PCI_ID_DIAMONDMM 0xff92
+#define IVTV_PCI_ID_IODATA 0x10fc
+#define IVTV_PCI_ID_MELCO 0x1154
+#define IVTV_PCI_ID_GOTVIEW1 0xffac
+#define IVTV_PCI_ID_GOTVIEW2 0xffad
+
/* hardware flags */
#define IVTV_HW_CX25840 (1 << 0)
#define IVTV_HW_SAA7115 (1 << 1)
@@ -33,7 +95,8 @@
#define IVTV_HW_UPD6408X (1 << 11)
#define IVTV_HW_SAA717X (1 << 12)
#define IVTV_HW_WM8739 (1 << 13)
-#define IVTV_HW_GPIO (1 << 14)
+#define IVTV_HW_VP27SMPX (1 << 14)
+#define IVTV_HW_GPIO (1 << 15)
#define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114)
@@ -205,3 +268,5 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output);
int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *input);
int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *output);
const struct ivtv_card *ivtv_get_card(u16 index);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
index 7a876c3e5b1..8c02fa66159 100644
--- a/drivers/media/video/ivtv/ivtv-controls.c
+++ b/drivers/media/video/ivtv/ivtv-controls.c
@@ -21,7 +21,7 @@
#include "ivtv-driver.h"
#include "ivtv-cards.h"
#include "ivtv-ioctl.h"
-#include "ivtv-audio.h"
+#include "ivtv-routing.h"
#include "ivtv-i2c.h"
#include "ivtv-mailbox.h"
#include "ivtv-controls.h"
@@ -231,8 +231,10 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg)
}
IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ static u32 freqs[3] = { 44100, 48000, 32000 };
struct cx2341x_mpeg_params p = itv->params;
- int err = cx2341x_ext_ctrls(&p, arg, cmd);
+ int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd);
+ unsigned idx;
if (err)
return err;
@@ -254,7 +256,11 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg)
}
itv->params = p;
itv->dualwatch_stereo_mode = p.audio_properties & 0x0300;
- ivtv_audio_set_audio_clock_freq(itv, p.audio_properties & 0x03);
+ idx = p.audio_properties & 0x03;
+ /* The audio clock of the digitizer must match the codec sample
+ rate otherwise you get some very strange effects. */
+ if (idx < sizeof(freqs))
+ ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]);
return err;
}
return -EINVAL;
@@ -282,7 +288,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg)
}
IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
- return cx2341x_ext_ctrls(&itv->params, arg, cmd);
+ return cx2341x_ext_ctrls(&itv->params, 0, arg, cmd);
return -EINVAL;
}
@@ -292,7 +298,7 @@ int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg)
IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
- return cx2341x_ext_ctrls(&itv->params, arg, cmd);
+ return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), arg, cmd);
return -EINVAL;
}
diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h
index 5a11149725a..bb8a6a5ed2b 100644
--- a/drivers/media/video/ivtv/ivtv-controls.h
+++ b/drivers/media/video/ivtv/ivtv-controls.h
@@ -18,4 +18,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_CONTROLS_H
+#define IVTV_CONTROLS_H
+
int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index d73d433a4ff..6d2dd8764f8 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -52,11 +52,12 @@
#include "ivtv-ioctl.h"
#include "ivtv-cards.h"
#include "ivtv-vbi.h"
-#include "ivtv-audio.h"
+#include "ivtv-routing.h"
#include "ivtv-gpio.h"
#include "ivtv-yuv.h"
#include <media/tveeprom.h>
+#include <media/saa7115.h>
#include <media/v4l2-chip-ident.h>
/* var to keep track of the number of array elements in use */
@@ -86,26 +87,37 @@ static struct pci_device_id ivtv_pci_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl);
-const u32 yuv_offset[4] = {
- IVTV_YUV_BUFFER_OFFSET,
- IVTV_YUV_BUFFER_OFFSET_1,
- IVTV_YUV_BUFFER_OFFSET_2,
- IVTV_YUV_BUFFER_OFFSET_3
-};
-
/* Parameter declarations */
static int cardtype[IVTV_MAX_CARDS];
-static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
-static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
-
-static int cardtype_c = 1;
-static int tuner_c = 1;
-static int radio_c = 1;
+static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 };
+static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 };
+
+static unsigned int cardtype_c = 1;
+static unsigned int tuner_c = 1;
+static unsigned int radio_c = 1;
static char pal[] = "--";
static char secam[] = "--";
static char ntsc[] = "-";
/* Buffers */
+
+/* DMA Buffers, Default size in MB allocated */
+#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4
+#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2
+#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1
+/* Exception: size in kB for this stream (MB is overkill) */
+#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320
+#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1
+#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1
+/* Exception: size in kB for this stream (MB is way overkill) */
+#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64
+
static int enc_mpg_buffers = IVTV_DEFAULT_ENC_MPG_BUFFERS;
static int enc_yuv_buffers = IVTV_DEFAULT_ENC_YUV_BUFFERS;
static int enc_vbi_buffers = IVTV_DEFAULT_ENC_VBI_BUFFERS;
@@ -170,17 +182,27 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t16 = GOTVIEW PCI DVD2 Deluxe\n"
"\t\t\t17 = Yuan MPC622\n"
"\t\t\t18 = Digital Cowboy DCT-MTVP1\n"
-#ifdef HAVE_XC3028
- "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01\n"
-#endif
+ "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n"
+ "\t\t\t20 = Club3D ZAP-TV1x01\n"
+ "\t\t\t21 = AverTV MCE 116 Plus\n"
"\t\t\t 0 = Autodetect (default)\n"
"\t\t\t-1 = Ignore this card\n\t\t");
MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
MODULE_PARM_DESC(debug,
- "Debug level (bitmask). Default: errors only\n"
- "\t\t\t(debug = 1023 gives full debugging)");
+ "Debug level (bitmask). Default: 0\n"
+ "\t\t\t 1/0x0001: warning\n"
+ "\t\t\t 2/0x0002: info\n"
+ "\t\t\t 4/0x0004: mailbox\n"
+ "\t\t\t 8/0x0008: ioctl\n"
+ "\t\t\t 16/0x0010: file\n"
+ "\t\t\t 32/0x0020: dma\n"
+ "\t\t\t 64/0x0040: irq\n"
+ "\t\t\t 128/0x0080: decoder\n"
+ "\t\t\t 256/0x0100: yuv\n"
+ "\t\t\t 512/0x0200: i2c\n"
+ "\t\t\t1024/0x0400: high volume\n");
MODULE_PARM_DESC(ivtv_pci_latency,
"Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
"\t\t\tDefault: Yes");
@@ -201,7 +223,7 @@ MODULE_PARM_DESC(enc_vbi_buffers,
"Encoder VBI Buffers (in MB)\n"
"\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS));
MODULE_PARM_DESC(enc_pcm_buffers,
- "Encoder PCM buffers (in MB)\n"
+ "Encoder PCM buffers (in kB)\n"
"\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS));
MODULE_PARM_DESC(dec_mpg_buffers,
"Decoder MPG buffers (in MB)\n"
@@ -210,7 +232,7 @@ MODULE_PARM_DESC(dec_yuv_buffers,
"Decoder YUV buffers (in MB)\n"
"\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS));
MODULE_PARM_DESC(dec_vbi_buffers,
- "Decoder VBI buffers (in MB)\n"
+ "Decoder VBI buffers (in kB)\n"
"\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS));
MODULE_PARM_DESC(newi2c,
"Use new I2C implementation\n"
@@ -540,13 +562,13 @@ static void ivtv_process_options(struct ivtv *itv)
const char *chipname;
int i, j;
- itv->options.megabytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
- itv->options.megabytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
- itv->options.megabytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
- itv->options.megabytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
- itv->options.megabytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers;
- itv->options.megabytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers;
- itv->options.megabytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers;
+ itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers * 1024;
+ itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers * 1024;
+ itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers * 1024;
+ itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
+ itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers * 1024;
+ itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers * 1024;
+ itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers;
itv->options.cardtype = cardtype[itv->num];
itv->options.tuner = tuner[itv->num];
itv->options.radio = radio[itv->num];
@@ -645,7 +667,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
cx2341x_fill_defaults(&itv->params);
itv->params.port = CX2341X_PORT_MEMORY;
itv->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
- init_waitqueue_head(&itv->cap_w);
+ init_waitqueue_head(&itv->eos_waitq);
init_waitqueue_head(&itv->event_waitq);
init_waitqueue_head(&itv->vsync_waitq);
init_waitqueue_head(&itv->dma_waitq);
@@ -691,14 +713,6 @@ static void __devinit ivtv_init_struct2(struct ivtv *itv)
break;
itv->nof_audio_inputs = i;
- /* 0x00EF = saa7114(239) 0x00F0 = saa7115(240) 0x0106 = micro */
- if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X))
- itv->digitizer = 0xF1;
- else if (itv->card->hw_all & IVTV_HW_SAA7114)
- itv->digitizer = 0xEF;
- else /* cx25840 */
- itv->digitizer = 0x140;
-
if (itv->card->hw_all & IVTV_HW_CX25840) {
itv->vbi.sliced_size = 288; /* multiple of 16, real size = 284 */
} else {
@@ -727,6 +741,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
const struct pci_device_id *pci_id)
{
u16 cmd;
+ u8 card_rev;
unsigned char pci_latency;
IVTV_DEBUG_INFO("Enabling pci device\n");
@@ -773,7 +788,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
}
IVTV_DEBUG_INFO("Bus Mastering Enabled.\n");
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &itv->card_rev);
+ pci_read_config_byte(dev, PCI_CLASS_REVISION, &card_rev);
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
if (pci_latency < 64 && ivtv_pci_latency) {
@@ -790,7 +805,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev,
IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, "
"irq: %d, latency: %d, memory: 0x%lx\n",
- itv->dev->device, itv->card_rev, dev->bus->number,
+ itv->dev->device, card_rev, dev->bus->number,
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
itv->dev->irq, pci_latency, (unsigned long)itv->base_addr);
@@ -808,18 +823,19 @@ static void ivtv_request_module(struct ivtv *itv, const char *name)
static void ivtv_load_and_init_modules(struct ivtv *itv)
{
- struct v4l2_control ctrl;
u32 hw = itv->card->hw_all;
int i;
/* load modules */
#ifndef CONFIG_VIDEO_TUNER
if (hw & IVTV_HW_TUNER) {
- ivtv_request_module(itv, "tuner");
-#ifdef HAVE_XC3028
- if (itv->options.tuner == TUNER_XCEIVE_XC3028)
- ivtv_request_module(itv, "xc3028-tuner");
-#endif
+ if (itv->options.tuner == TUNER_XCEIVE_XC3028) {
+ IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n");
+ itv->tunerid = 1;
+ }
+ else {
+ ivtv_request_module(itv, "tuner");
+ }
}
#endif
#ifndef CONFIG_VIDEO_CX25840
@@ -848,6 +864,10 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
if (hw & IVTV_HW_MSP34XX)
ivtv_request_module(itv, "msp3400");
#endif
+#ifndef CONFIG_VIDEO_VP27SMPX
+ if (hw & IVTV_HW_VP27SMPX)
+ ivtv_request_module(itv, "vp27smpx");
+#endif
if (hw & IVTV_HW_TVAUDIO)
ivtv_request_module(itv, "tvaudio");
#ifndef CONFIG_VIDEO_WM8775
@@ -888,13 +908,17 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
else if ((hw & IVTV_HW_UPD64031A) == 0)
itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGR);
}
+ else if (itv->card->type == IVTV_CARD_GV_MVPRX ||
+ itv->card->type == IVTV_CARD_GV_MVPRX2E) {
+ struct v4l2_crystal_freq crystal_freq;
+
+ /* The crystal frequency of GVMVPRX is 24.576MHz */
+ crystal_freq.freq = SAA7115_FREQ_24_576_MHZ;
+ crystal_freq.flags = SAA7115_FREQ_FL_UCGC;
+ itv->video_dec_func(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
+ }
if (hw & IVTV_HW_CX25840) {
- /* CX25840_CID_ENABLE_PVR150_WORKAROUND */
- ctrl.id = V4L2_CID_PRIVATE_BASE;
- ctrl.value = itv->pvr150_workaround;
- itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl);
-
itv->vbi.raw_decoder_line_size = 1444;
itv->vbi.raw_decoder_sav_odd_field = 0x20;
itv->vbi.raw_decoder_sav_even_field = 0x60;
@@ -940,12 +964,9 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
const struct pci_device_id *pci_id)
{
int retval = 0;
- int video_input;
int yuv_buf_size;
int vbi_buf_size;
- int fw_retry_count = 3;
struct ivtv *itv;
- struct v4l2_frequency vf;
spin_lock(&ivtv_cards_lock);
@@ -1032,22 +1053,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
goto free_io;
}
- while (--fw_retry_count > 0) {
- /* load firmware */
- if (ivtv_firmware_init(itv) == 0)
- break;
- if (fw_retry_count > 1)
- IVTV_WARN("Retry loading firmware\n");
- }
- if (fw_retry_count == 0) {
- IVTV_ERR("Error initializing firmware\n");
- goto free_i2c;
- }
-
- /* Try and get firmware versions */
- IVTV_DEBUG_INFO("Getting firmware version..\n");
- ivtv_firmware_versions(itv);
-
/* Check yuv output filter table */
if (itv->has_cx23415) ivtv_yuv_filter_check(itv);
@@ -1057,7 +1062,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
IVTV_DEBUG_INFO("activating i2c...\n");
if (init_ivtv_i2c(itv)) {
IVTV_ERR("Could not initialize i2c\n");
- goto free_irq;
+ goto free_io;
}
IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active);
@@ -1135,43 +1140,22 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
if (itv->options.radio > 0)
itv->v4l2_cap |= V4L2_CAP_RADIO;
- if (itv->options.tuner > -1) {
+ if (itv->options.tuner > -1 && itv->tunerid == 0) {
struct tuner_setup setup;
setup.addr = ADDR_UNSET;
setup.type = itv->options.tuner;
setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */
-#ifdef HAVE_XC3028
- setup.initmode = V4L2_TUNER_ANALOG_TV;
- if (itv->options.tuner == TUNER_XCEIVE_XC3028) {
- setup.gpio_write = ivtv_reset_tuner_gpio;
- setup.gpio_priv = itv;
- }
-#endif
ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup);
}
- vf.tuner = 0;
- vf.type = V4L2_TUNER_ANALOG_TV;
- vf.frequency = 6400; /* the tuner 'baseline' frequency */
- if (itv->std & V4L2_STD_NTSC_M) {
- /* Why on earth? */
- vf.frequency = 1076; /* ch. 4 67250*16/1000 */
- }
-
/* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
are not. */
itv->tuner_std = itv->std;
- video_input = itv->active_input;
- itv->active_input++; /* Force update of input */
- ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input);
-
- /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
- in one place. */
- itv->std++; /* Force full standard initialization */
- itv->std_out = itv->std;
- ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf);
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std);
+ }
retval = ivtv_streams_setup(itv);
if (retval) {
@@ -1179,11 +1163,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
goto free_i2c;
}
- if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) {
- ivtv_init_mpeg_decoder(itv);
- }
- ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std);
-
IVTV_DEBUG_IRQ("Masking interrupts\n");
/* clear interrupt mask, effectively disabling interrupts */
ivtv_set_irq_mask(itv, 0xffffffff);
@@ -1195,26 +1174,12 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
IVTV_ERR("Failed to register irq %d\n", retval);
goto free_streams;
}
-
- /* On a cx23416 this seems to be able to enable DMA to the chip? */
- if (!itv->has_cx23415)
- write_reg_sync(0x03, IVTV_REG_DMACONTROL);
-
- /* Default interrupts enabled. For the PVR350 this includes the
- decoder VSYNC interrupt, which is always on. It is not only used
- during decoding but also by the OSD.
- Some old PVR250 cards had a cx23415, so testing for that is too
- general. Instead test if the card has video output capability. */
- if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
- ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC);
- else
- ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT);
-
- if (itv->has_cx23415)
- ivtv_set_osd_alpha(itv);
-
+ retval = ivtv_streams_register(itv);
+ if (retval) {
+ IVTV_ERR("Error %d registering devices\n", retval);
+ goto free_irq;
+ }
IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
-
return 0;
free_irq:
@@ -1237,60 +1202,140 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
retval = -ENODEV;
IVTV_ERR("Error %d on initialization\n", retval);
+ spin_lock(&ivtv_cards_lock);
kfree(ivtv_cards[ivtv_cards_active]);
ivtv_cards[ivtv_cards_active] = NULL;
+ spin_unlock(&ivtv_cards_lock);
return retval;
}
+int ivtv_init_on_first_open(struct ivtv *itv)
+{
+ struct v4l2_frequency vf;
+ int fw_retry_count = 3;
+ int video_input;
+
+ if (test_bit(IVTV_F_I_FAILED, &itv->i_flags))
+ return -ENXIO;
+
+ if (test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags))
+ return 0;
+
+ while (--fw_retry_count > 0) {
+ /* load firmware */
+ if (ivtv_firmware_init(itv) == 0)
+ break;
+ if (fw_retry_count > 1)
+ IVTV_WARN("Retry loading firmware\n");
+ }
+
+ if (fw_retry_count == 0) {
+ set_bit(IVTV_F_I_FAILED, &itv->i_flags);
+ return -ENXIO;
+ }
+
+ /* Try and get firmware versions */
+ IVTV_DEBUG_INFO("Getting firmware version..\n");
+ ivtv_firmware_versions(itv);
+
+ if (itv->card->hw_all & IVTV_HW_CX25840) {
+ struct v4l2_control ctrl;
+
+ /* CX25840_CID_ENABLE_PVR150_WORKAROUND */
+ ctrl.id = V4L2_CID_PRIVATE_BASE;
+ ctrl.value = itv->pvr150_workaround;
+ itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl);
+ }
+
+ vf.tuner = 0;
+ vf.type = V4L2_TUNER_ANALOG_TV;
+ vf.frequency = 6400; /* the tuner 'baseline' frequency */
+
+ /* Set initial frequency. For PAL/SECAM broadcasts no
+ 'default' channel exists AFAIK. */
+ if (itv->std == V4L2_STD_NTSC_M_JP) {
+ vf.frequency = 1460; /* ch. 1 91250*16/1000 */
+ }
+ else if (itv->std & V4L2_STD_NTSC_M) {
+ vf.frequency = 1076; /* ch. 4 67250*16/1000 */
+ }
+
+ video_input = itv->active_input;
+ itv->active_input++; /* Force update of input */
+ ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input);
+
+ /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
+ in one place. */
+ itv->std++; /* Force full standard initialization */
+ itv->std_out = itv->std;
+ ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf);
+
+ if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) {
+ ivtv_init_mpeg_decoder(itv);
+ }
+ ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std);
+
+ /* On a cx23416 this seems to be able to enable DMA to the chip? */
+ if (!itv->has_cx23415)
+ write_reg_sync(0x03, IVTV_REG_DMACONTROL);
+
+ /* Default interrupts enabled. For the PVR350 this includes the
+ decoder VSYNC interrupt, which is always on. It is not only used
+ during decoding but also by the OSD.
+ Some old PVR250 cards had a cx23415, so testing for that is too
+ general. Instead test if the card has video output capability. */
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC);
+ ivtv_set_osd_alpha(itv);
+ }
+ else
+ ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT);
+ return 0;
+}
+
static void ivtv_remove(struct pci_dev *pci_dev)
{
struct ivtv *itv = pci_get_drvdata(pci_dev);
IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num);
- /* Stop all captures */
- IVTV_DEBUG_INFO("Stopping all streams\n");
- if (atomic_read(&itv->capturing) > 0)
- ivtv_stop_all_captures(itv);
-
- /* Stop all decoding */
- IVTV_DEBUG_INFO("Stopping decoding\n");
- if (atomic_read(&itv->decoding) > 0) {
- int type;
-
- if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
- type = IVTV_DEC_STREAM_TYPE_YUV;
- else
- type = IVTV_DEC_STREAM_TYPE_MPG;
- ivtv_stop_v4l2_decode_stream(&itv->streams[type],
- VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+ if (test_bit(IVTV_F_I_INITED, &itv->i_flags)) {
+ /* Stop all captures */
+ IVTV_DEBUG_INFO("Stopping all streams\n");
+ if (atomic_read(&itv->capturing) > 0)
+ ivtv_stop_all_captures(itv);
+
+ /* Stop all decoding */
+ IVTV_DEBUG_INFO("Stopping decoding\n");
+ if (atomic_read(&itv->decoding) > 0) {
+ int type;
+
+ if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+ type = IVTV_DEC_STREAM_TYPE_YUV;
+ else
+ type = IVTV_DEC_STREAM_TYPE_MPG;
+ ivtv_stop_v4l2_decode_stream(&itv->streams[type],
+ VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+ }
+ ivtv_halt_firmware(itv);
}
/* Interrupts */
- IVTV_DEBUG_INFO("Disabling interrupts\n");
ivtv_set_irq_mask(itv, 0xffffffff);
del_timer_sync(&itv->dma_timer);
/* Stop all Work Queues */
- IVTV_DEBUG_INFO("Stop Work Queues\n");
flush_workqueue(itv->irq_work_queues);
destroy_workqueue(itv->irq_work_queues);
- IVTV_DEBUG_INFO("Stopping Firmware\n");
- ivtv_halt_firmware(itv);
-
- IVTV_DEBUG_INFO("Unregistering v4l devices\n");
ivtv_streams_cleanup(itv);
- IVTV_DEBUG_INFO("Freeing dma resources\n");
ivtv_udma_free(itv);
exit_ivtv_i2c(itv);
- IVTV_DEBUG_INFO(" Releasing irq\n");
free_irq(itv->dev->irq, (void *)itv);
ivtv_iounmap(itv);
- IVTV_DEBUG_INFO(" Releasing mem\n");
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (itv->has_cx23415)
@@ -1322,9 +1367,9 @@ static int module_start(void)
return -1;
}
- if (ivtv_debug < 0 || ivtv_debug > 1023) {
+ if (ivtv_debug < 0 || ivtv_debug > 2047) {
ivtv_debug = 0;
- printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 1023\n");
+ printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 2047\n");
}
if (pci_register_driver(&ivtv_pci_driver)) {
@@ -1341,6 +1386,7 @@ static void module_cleanup(void)
pci_unregister_driver(&ivtv_pci_driver);
+ spin_lock(&ivtv_cards_lock);
for (i = 0; i < ivtv_cards_active; i++) {
if (ivtv_cards[i] == NULL)
continue;
@@ -1349,13 +1395,15 @@ static void module_cleanup(void)
}
kfree(ivtv_cards[i]);
}
+ spin_unlock(&ivtv_cards_lock);
}
-/* Note: These symbols are exported because they are used by the ivtv-fb
+/* Note: These symbols are exported because they are used by the ivtvfb
framebuffer module and an infrared module for the IR-blaster. */
EXPORT_SYMBOL(ivtv_set_irq_mask);
EXPORT_SYMBOL(ivtv_cards_active);
EXPORT_SYMBOL(ivtv_cards);
+EXPORT_SYMBOL(ivtv_cards_lock);
EXPORT_SYMBOL(ivtv_api);
EXPORT_SYMBOL(ivtv_vapi);
EXPORT_SYMBOL(ivtv_vapi_result);
@@ -1366,6 +1414,7 @@ EXPORT_SYMBOL(ivtv_udma_setup);
EXPORT_SYMBOL(ivtv_udma_unmap);
EXPORT_SYMBOL(ivtv_udma_alloc);
EXPORT_SYMBOL(ivtv_udma_prepare);
+EXPORT_SYMBOL(ivtv_init_on_first_open);
module_init(module_start);
module_exit(module_cleanup);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 8abb34a3581..49ce14d14a5 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -38,7 +38,6 @@
#include <linux/version.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/sched.h>
@@ -52,6 +51,7 @@
#include <linux/unistd.h>
#include <linux/byteorder/swab.h>
#include <linux/pagemap.h>
+#include <linux/scatterlist.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
@@ -63,77 +63,20 @@
#include <media/tuner.h>
#include <media/cx2341x.h>
-/* #define HAVE_XC3028 1 */
+#include <linux/ivtv.h>
-#include <media/ivtv.h>
+/* Memory layout */
#define IVTV_ENCODER_OFFSET 0x00000000
-#define IVTV_ENCODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */
-
+#define IVTV_ENCODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */
#define IVTV_DECODER_OFFSET 0x01000000
-#define IVTV_DECODER_SIZE 0x00800000 /* Last half isn't needed 0x01000000 */
-
+#define IVTV_DECODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */
#define IVTV_REG_OFFSET 0x02000000
#define IVTV_REG_SIZE 0x00010000
-/* Buffers on hardware offsets */
-#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */
-#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */
-
-/* Offset to filter table in firmware */
-#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8
-#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358
-
-extern const u32 yuv_offset[4];
-
-/* Maximum ivtv driver instances.
- Based on 6 PVR500s each with two PVR15s...
- TODO: make this dynamic. I believe it is only a global in order to support
- ivtv-fb. There must be a better way to do that. */
-#define IVTV_MAX_CARDS 12
-
-/* Supported cards */
-#define IVTV_CARD_PVR_250 0 /* WinTV PVR 250 */
-#define IVTV_CARD_PVR_350 1 /* encoder, decoder, tv-out */
-#define IVTV_CARD_PVR_150 2 /* WinTV PVR 150 and PVR 500 (really just two
- PVR150s on one PCI board) */
-#define IVTV_CARD_M179 3 /* AVerMedia M179 (encoder only) */
-#define IVTV_CARD_MPG600 4 /* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */
-#define IVTV_CARD_MPG160 5 /* Kuroutoshikou ITVC15-STVLP/YUAN MPG160
- cx23415 based, but does not have tv-out */
-#define IVTV_CARD_PG600 6 /* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */
-#define IVTV_CARD_AVC2410 7 /* Adaptec AVC-2410 */
-#define IVTV_CARD_AVC2010 8 /* Adaptec AVD-2010 (No Tuner) */
-#define IVTV_CARD_TG5000TV 9 /* NAGASE TRANSGEAR 5000TV, encoder only */
-#define IVTV_CARD_VA2000MAX_SNT6 10 /* VA2000MAX-STN6 */
-#define IVTV_CARD_CX23416GYC 11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
-#define IVTV_CARD_GV_MVPRX 12 /* I/O Data GV-MVP/RX, RX2, RX2W */
-#define IVTV_CARD_GV_MVPRX2E 13 /* I/O Data GV-MVP/RX2E */
-#define IVTV_CARD_GOTVIEW_PCI_DVD 14 /* GotView PCI DVD */
-#define IVTV_CARD_GOTVIEW_PCI_DVD2 15 /* GotView PCI DVD2 */
-#define IVTV_CARD_YUAN_MPC622 16 /* Yuan MPC622 miniPCI */
-#define IVTV_CARD_DCTMTVP1 17 /* DIGITAL COWBOY DCT-MTVP1 */
-#ifdef HAVE_XC3028
-#define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 */
-#define IVTV_CARD_LAST 18
-#else
-#define IVTV_CARD_LAST 17
-#endif
-
-/* Variants of existing cards but with the same PCI IDs. The driver
- detects these based on other device information.
- These cards must always come last.
- New cards must be inserted above, and the indices of the cards below
- must be adjusted accordingly. */
-
-/* PVR-350 V1 (uses saa7114) */
-#define IVTV_CARD_PVR_350_V1 (IVTV_CARD_LAST+1)
-/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
-#define IVTV_CARD_CX23416GYC_NOGR (IVTV_CARD_LAST+2)
-#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3)
+/* Maximum ivtv driver instances. Some people have a huge number of
+ capture cards, so set this to a high value. */
+#define IVTV_MAX_CARDS 32
#define IVTV_ENC_STREAM_TYPE_MPG 0
#define IVTV_ENC_STREAM_TYPE_YUV 1
@@ -146,70 +89,8 @@ extern const u32 yuv_offset[4];
#define IVTV_DEC_STREAM_TYPE_YUV 8
#define IVTV_MAX_STREAMS 9
-#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */
-#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */
-#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */
-#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */
-#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */
-#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */
-
-#define IVTV_ENC_MEM_START 0x00000000
-#define IVTV_DEC_MEM_START 0x01000000
-
-/* system vendor and device IDs */
-#define PCI_VENDOR_ID_ICOMP 0x4444
-#define PCI_DEVICE_ID_IVTV15 0x0803
-#define PCI_DEVICE_ID_IVTV16 0x0016
-
-/* subsystem vendor ID */
-#define IVTV_PCI_ID_HAUPPAUGE 0x0070
-#define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270
-#define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070
-#define IVTV_PCI_ID_ADAPTEC 0x9005
-#define IVTV_PCI_ID_AVERMEDIA 0x1461
-#define IVTV_PCI_ID_YUAN1 0x12ab
-#define IVTV_PCI_ID_YUAN2 0xff01
-#define IVTV_PCI_ID_YUAN3 0xffab
-#define IVTV_PCI_ID_YUAN4 0xfbab
-#define IVTV_PCI_ID_DIAMONDMM 0xff92
-#define IVTV_PCI_ID_IODATA 0x10fc
-#define IVTV_PCI_ID_MELCO 0x1154
-#define IVTV_PCI_ID_GOTVIEW1 0xffac
-#define IVTV_PCI_ID_GOTVIEW2 0xffad
-
-/* Decoder Buffer hardware size on Chip */
-#define IVTV_DEC_MAX_BUF 0x00100000 /* max bytes in decoder buffer */
-#define IVTV_DEC_MIN_BUF 0x00010000 /* min bytes in dec buffer */
-
-/* ======================================================================== */
-/* ========================== START USER SETTABLE DMA VARIABLES =========== */
-/* ======================================================================== */
-
#define IVTV_DMA_SG_OSD_ENT (2883584/PAGE_SIZE) /* sg entities */
-/* DMA Buffers, Default size in MB allocated */
-#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4
-#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2
-#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1
-#define IVTV_DEFAULT_ENC_PCM_BUFFERS 1
-#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1
-#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1
-#define IVTV_DEFAULT_DEC_VBI_BUFFERS 1
-
-/* ======================================================================== */
-/* ========================== END USER SETTABLE DMA VARIABLES ============= */
-/* ======================================================================== */
-
-/* Decoder Status Register */
-#define IVTV_DMA_ERR_LIST 0x00000010
-#define IVTV_DMA_ERR_WRITE 0x00000008
-#define IVTV_DMA_ERR_READ 0x00000004
-#define IVTV_DMA_SUCCESS_WRITE 0x00000002
-#define IVTV_DMA_SUCCESS_READ 0x00000001
-#define IVTV_DMA_READ_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_READ)
-#define IVTV_DMA_WRITE_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE)
-#define IVTV_DMA_ERR (IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE | IVTV_DMA_ERR_READ)
-
/* DMA Registers */
#define IVTV_REG_DMAXFER (0x0000)
#define IVTV_REG_DMASTATUS (0x0004)
@@ -232,44 +113,24 @@ extern const u32 yuv_offset[4];
#define IVTV_REG_VPU (0x9058)
#define IVTV_REG_APU (0xA064)
-#define IVTV_IRQ_ENC_START_CAP (0x1 << 31)
-#define IVTV_IRQ_ENC_EOS (0x1 << 30)
-#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29)
-#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28)
-#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27)
-#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25)
-#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24)
-#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22)
-#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20)
-#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19)
-#define IVTV_IRQ_DMA_ERR (0x1 << 18)
-#define IVTV_IRQ_DMA_WRITE (0x1 << 17)
-#define IVTV_IRQ_DMA_READ (0x1 << 16)
-#define IVTV_IRQ_DEC_VSYNC (0x1 << 10)
-
-/* IRQ Masks */
-#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\
- IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE)
-
-#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS)
-#define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG)
-
/* i2c stuff */
#define I2C_CLIENTS_MAX 16
/* debugging */
+extern int ivtv_debug;
-#define IVTV_DBGFLG_WARN (1 << 0)
-#define IVTV_DBGFLG_INFO (1 << 1)
-#define IVTV_DBGFLG_API (1 << 2)
-#define IVTV_DBGFLG_DMA (1 << 3)
-#define IVTV_DBGFLG_IOCTL (1 << 4)
-#define IVTV_DBGFLG_I2C (1 << 5)
-#define IVTV_DBGFLG_IRQ (1 << 6)
-#define IVTV_DBGFLG_DEC (1 << 7)
-#define IVTV_DBGFLG_YUV (1 << 8)
+#define IVTV_DBGFLG_WARN (1 << 0)
+#define IVTV_DBGFLG_INFO (1 << 1)
+#define IVTV_DBGFLG_MB (1 << 2)
+#define IVTV_DBGFLG_IOCTL (1 << 3)
+#define IVTV_DBGFLG_FILE (1 << 4)
+#define IVTV_DBGFLG_DMA (1 << 5)
+#define IVTV_DBGFLG_IRQ (1 << 6)
+#define IVTV_DBGFLG_DEC (1 << 7)
+#define IVTV_DBGFLG_YUV (1 << 8)
+#define IVTV_DBGFLG_I2C (1 << 9)
/* Flag to turn on high volume debugging */
-#define IVTV_DBGFLG_HIGHVOL (1 << 9)
+#define IVTV_DBGFLG_HIGHVOL (1 << 10)
/* NOTE: extra space before comma in 'itv->num , ## args' is required for
gcc-2.95, otherwise it won't compile. */
@@ -278,58 +139,37 @@ extern const u32 yuv_offset[4];
if ((x) & ivtv_debug) \
printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
} while (0)
-#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args)
-#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info",fmt , ## args)
-#define IVTV_DEBUG_API(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args)
-#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
+#define IVTV_DEBUG_WARN(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_WARN, "warn", fmt , ## args)
+#define IVTV_DEBUG_INFO(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args)
+#define IVTV_DEBUG_MB(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_MB, "mb", fmt , ## args)
+#define IVTV_DEBUG_DMA(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
#define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
-#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
-#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
-#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
-#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+#define IVTV_DEBUG_FILE(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_FILE, "file", fmt , ## args)
+#define IVTV_DEBUG_I2C(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
+#define IVTV_DEBUG_IRQ(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
+#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
+#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
#define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
do { \
if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \
printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
} while (0)
-#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warning", fmt , ## args)
-#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info",fmt , ## args)
-#define IVTV_DEBUG_HI_API(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_API, "api", fmt , ## args)
-#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
+#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warn", fmt , ## args)
+#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info", fmt , ## args)
+#define IVTV_DEBUG_HI_MB(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_MB, "mb", fmt , ## args)
+#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
#define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
-#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
-#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
-#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
-#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
-
-#define IVTV_FB_DEBUG(x, type, fmt, args...) \
- do { \
- if ((x) & ivtv_debug) \
- printk(KERN_INFO "ivtv%d-fb " type ": " fmt, itv->num , ## args); \
- } while (0)
-#define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args)
-#define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args)
-#define IVTV_FB_DEBUG_API(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args)
-#define IVTV_FB_DEBUG_DMA(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
-#define IVTV_FB_DEBUG_IOCTL(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
-#define IVTV_FB_DEBUG_I2C(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
-#define IVTV_FB_DEBUG_IRQ(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
-#define IVTV_FB_DEBUG_DEC(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
-#define IVTV_FB_DEBUG_YUV(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+#define IVTV_DEBUG_HI_FILE(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_FILE, "file", fmt , ## args)
+#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
+#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
+#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
+#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
/* Standard kernel messages */
#define IVTV_ERR(fmt, args...) printk(KERN_ERR "ivtv%d: " fmt, itv->num , ## args)
#define IVTV_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args)
#define IVTV_INFO(fmt, args...) printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args)
-#define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv%d-fb: " fmt, itv->num , ## args)
-#define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv%d-fb: " fmt, itv->num , ## args)
-#define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv%d-fb: " fmt, itv->num , ## args)
-
-/* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */
-#define MPEG_FRAME_TYPE_IFRAME 1
-#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3
-#define MPEG_FRAME_TYPE_ALL 7
/* output modes (cx23415 only) */
#define OUT_NONE 0
@@ -340,22 +180,14 @@ extern const u32 yuv_offset[4];
#define IVTV_MAX_PGM_INDEX (400)
-extern int ivtv_debug;
-
-
struct ivtv_options {
- int megabytes[IVTV_MAX_STREAMS]; /* Size in megabytes of each stream */
- int cardtype; /* force card type on load */
- int tuner; /* set tuner on load */
- int radio; /* enable/disable radio */
- int newi2c; /* New I2C algorithm */
+ int kilobytes[IVTV_MAX_STREAMS]; /* size in kilobytes of each stream */
+ int cardtype; /* force card type on load */
+ int tuner; /* set tuner on load */
+ int radio; /* enable/disable radio */
+ int newi2c; /* new I2C algorithm */
};
-#define IVTV_MBOX_DMA_START 6
-#define IVTV_MBOX_DMA_END 8
-#define IVTV_MBOX_DMA 9
-#define IVTV_MBOX_FIELD_DISPLAYED 8
-
/* ivtv-specific mailbox template */
struct ivtv_mailbox {
u32 flags;
@@ -379,7 +211,7 @@ struct ivtv_mailbox_data {
};
/* per-buffer bit flags */
-#define IVTV_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */
+#define IVTV_F_B_NEED_BUF_SWAP (1 << 0) /* this buffer should be byte swapped */
/* per-stream, s_flags */
#define IVTV_F_S_DMA_PENDING 0 /* this stream has pending DMA */
@@ -400,24 +232,25 @@ struct ivtv_mailbox_data {
#define IVTV_F_I_DMA 0 /* DMA in progress */
#define IVTV_F_I_UDMA 1 /* UDMA in progress */
#define IVTV_F_I_UDMA_PENDING 2 /* UDMA pending */
-#define IVTV_F_I_SPEED_CHANGE 3 /* A speed change is in progress */
-#define IVTV_F_I_EOS 4 /* End of encoder stream reached */
-#define IVTV_F_I_RADIO_USER 5 /* The radio tuner is selected */
-#define IVTV_F_I_DIG_RST 6 /* Reset digitizer */
+#define IVTV_F_I_SPEED_CHANGE 3 /* a speed change is in progress */
+#define IVTV_F_I_EOS 4 /* end of encoder stream reached */
+#define IVTV_F_I_RADIO_USER 5 /* the radio tuner is selected */
+#define IVTV_F_I_DIG_RST 6 /* reset digitizer */
#define IVTV_F_I_DEC_YUV 7 /* YUV instead of MPG is being decoded */
-#define IVTV_F_I_ENC_VBI 8 /* VBI DMA */
#define IVTV_F_I_UPDATE_CC 9 /* CC should be updated */
#define IVTV_F_I_UPDATE_WSS 10 /* WSS should be updated */
#define IVTV_F_I_UPDATE_VPS 11 /* VPS should be updated */
#define IVTV_F_I_DECODING_YUV 12 /* this stream is YUV frame decoding */
#define IVTV_F_I_ENC_PAUSED 13 /* the encoder is paused */
#define IVTV_F_I_VALID_DEC_TIMINGS 14 /* last_dec_timing is valid */
-#define IVTV_F_I_HAVE_WORK 15 /* Used in the interrupt handler: there is work to be done */
+#define IVTV_F_I_HAVE_WORK 15 /* used in the interrupt handler: there is work to be done */
#define IVTV_F_I_WORK_HANDLER_VBI 16 /* there is work to be done for VBI */
#define IVTV_F_I_WORK_HANDLER_YUV 17 /* there is work to be done for YUV */
#define IVTV_F_I_WORK_HANDLER_PIO 18 /* there is work to be done for PIO */
#define IVTV_F_I_PIO 19 /* PIO in progress */
#define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */
+#define IVTV_F_I_INITED 21 /* set after first open */
+#define IVTV_F_I_FAILED 22 /* set if first open failed */
/* Event notifications */
#define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */
@@ -426,7 +259,7 @@ struct ivtv_mailbox_data {
#define IVTV_F_I_EV_VSYNC_ENABLED 31 /* VSYNC event enabled */
/* Scatter-Gather array element, used in DMA transfers */
-struct ivtv_SG_element {
+struct ivtv_sg_element {
u32 src;
u32 dst;
u32 size;
@@ -436,9 +269,11 @@ struct ivtv_user_dma {
struct mutex lock;
int page_count;
struct page *map[IVTV_DMA_SG_OSD_ENT];
+ /* Needed when dealing with highmem userspace buffers */
+ struct page *bouncemap[IVTV_DMA_SG_OSD_ENT];
/* Base Dev SG Array for cx23415/6 */
- struct ivtv_SG_element SGarray[IVTV_DMA_SG_OSD_ENT];
+ struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT];
dma_addr_t SG_handle;
int SG_length;
@@ -458,21 +293,21 @@ struct ivtv_dma_page_info {
struct ivtv_buffer {
struct list_head list;
dma_addr_t dma_handle;
- unsigned long b_flags;
+ unsigned short b_flags;
+ unsigned short dma_xfer_cnt;
char *buf;
-
u32 bytesused;
u32 readpos;
};
struct ivtv_queue {
- struct list_head list;
- u32 buffers;
- u32 length;
- u32 bytesused;
+ struct list_head list; /* the list of buffers in this queue */
+ u32 buffers; /* number of buffers in this queue */
+ u32 length; /* total number of bytes of available buffer space */
+ u32 bytesused; /* total number of bytes used in this queue */
};
-struct ivtv; /* forward reference */
+struct ivtv; /* forward reference */
struct ivtv_stream {
/* These first four fields are always set, even if the stream
@@ -483,11 +318,13 @@ struct ivtv_stream {
int type; /* stream type */
u32 id;
- spinlock_t qlock; /* locks access to the queues */
- unsigned long s_flags; /* status flags, see above */
- int dma; /* can be PCI_DMA_TODEVICE,
- PCI_DMA_FROMDEVICE or
- PCI_DMA_NONE */
+ spinlock_t qlock; /* locks access to the queues */
+ unsigned long s_flags; /* status flags, see above */
+ int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */
+ u32 pending_offset;
+ u32 pending_backup;
+ u64 pending_pts;
+
u32 dma_offset;
u32 dma_backup;
u64 dma_pts;
@@ -508,47 +345,53 @@ struct ivtv_stream {
struct ivtv_queue q_dma; /* waiting for DMA */
struct ivtv_queue q_predma; /* waiting for DMA */
+ /* DMA xfer counter, buffers belonging to the same DMA
+ xfer will have the same dma_xfer_cnt. */
+ u16 dma_xfer_cnt;
+
/* Base Dev SG Array for cx23415/6 */
- struct ivtv_SG_element *SGarray;
- struct ivtv_SG_element *PIOarray;
- dma_addr_t SG_handle;
- int SG_length;
+ struct ivtv_sg_element *sg_pending;
+ struct ivtv_sg_element *sg_processing;
+ struct ivtv_sg_element *sg_dma;
+ dma_addr_t sg_handle;
+ int sg_pending_size;
+ int sg_processing_size;
+ int sg_processed;
/* SG List of Buffers */
struct scatterlist *SGlist;
};
struct ivtv_open_id {
- u32 open_id;
- int type;
- enum v4l2_priority prio;
+ u32 open_id; /* unique ID for this file descriptor */
+ int type; /* stream type */
+ int yuv_frames; /* 1: started OUT_UDMA_YUV output mode */
+ enum v4l2_priority prio; /* priority */
struct ivtv *itv;
};
-#define IVTV_YUV_UPDATE_HORIZONTAL 0x01
-#define IVTV_YUV_UPDATE_VERTICAL 0x02
-
struct yuv_frame_info
{
u32 update;
- int src_x;
- int src_y;
- unsigned int src_w;
- unsigned int src_h;
- int dst_x;
- int dst_y;
- unsigned int dst_w;
- unsigned int dst_h;
- int pan_x;
- int pan_y;
+ s32 src_x;
+ s32 src_y;
+ u32 src_w;
+ u32 src_h;
+ s32 dst_x;
+ s32 dst_y;
+ u32 dst_w;
+ u32 dst_h;
+ s32 pan_x;
+ s32 pan_y;
u32 vis_w;
u32 vis_h;
u32 interlaced_y;
u32 interlaced_uv;
- int tru_x;
+ s32 tru_x;
u32 tru_w;
u32 tru_h;
u32 offset_y;
+ s32 lace_mode;
};
#define IVTV_YUV_MODE_INTERLACED 0x00
@@ -621,7 +464,6 @@ struct yuv_playback_info
int decode_height;
int frame_interlaced;
- int frame_interlaced_last;
int lace_mode;
int lace_threshold;
@@ -632,6 +474,11 @@ struct yuv_playback_info
u32 yuv_forced_update;
int update_frame;
+
+ int sync_field[4]; /* Field to sync on */
+ int field_delay[4]; /* Flag to extend duration of previous frame */
+ u8 fields_lapsed; /* Counter used when delaying a frame */
+
struct yuv_frame_info new_frame_info[4];
struct yuv_frame_info old_frame_info;
struct yuv_frame_info old_frame_info_args;
@@ -643,37 +490,61 @@ struct yuv_playback_info
#define IVTV_VBI_FRAMES 32
/* VBI data */
+struct vbi_cc {
+ u8 odd[2]; /* two-byte payload of odd field */
+ u8 even[2]; /* two-byte payload of even field */;
+};
+
+struct vbi_vps {
+ u8 data[5]; /* five-byte VPS payload */
+};
+
struct vbi_info {
- u32 dec_start;
- u32 enc_start, enc_size;
- int fpi;
- u32 frame;
- u32 dma_offset;
- u8 cc_data_odd[256];
- u8 cc_data_even[256];
- int cc_pos;
- u8 cc_no_update;
- u8 vps[5];
- u8 vps_found;
- int wss;
- u8 wss_found;
- u8 wss_no_update;
- u32 raw_decoder_line_size;
- u8 raw_decoder_sav_odd_field;
- u8 raw_decoder_sav_even_field;
- u32 sliced_decoder_line_size;
- u8 sliced_decoder_sav_odd_field;
- u8 sliced_decoder_sav_even_field;
- struct v4l2_format in;
- /* convenience pointer to sliced struct in vbi_in union */
- struct v4l2_sliced_vbi_format *sliced_in;
- u32 service_set_in;
- int insert_mpeg;
-
- /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
- One for /dev/vbi0 and one for /dev/vbi8 */
- struct v4l2_sliced_vbi_data sliced_data[36];
- struct v4l2_sliced_vbi_data sliced_dec_data[36];
+ /* VBI general data, does not change during streaming */
+
+ u32 raw_decoder_line_size; /* raw VBI line size from digitizer */
+ u8 raw_decoder_sav_odd_field; /* raw VBI Start Active Video digitizer code of odd field */
+ u8 raw_decoder_sav_even_field; /* raw VBI Start Active Video digitizer code of even field */
+ u32 sliced_decoder_line_size; /* sliced VBI line size from digitizer */
+ u8 sliced_decoder_sav_odd_field; /* sliced VBI Start Active Video digitizer code of odd field */
+ u8 sliced_decoder_sav_even_field; /* sliced VBI Start Active Video digitizer code of even field */
+
+ u32 start[2]; /* start of first VBI line in the odd/even fields */
+ u32 count; /* number of VBI lines per field */
+ u32 raw_size; /* size of raw VBI line from the digitizer */
+ u32 sliced_size; /* size of sliced VBI line from the digitizer */
+
+ u32 dec_start; /* start in decoder memory of VBI re-insertion buffers */
+ u32 enc_start; /* start in encoder memory of VBI capture buffers */
+ u32 enc_size; /* size of VBI capture area */
+ int fpi; /* number of VBI frames per interrupt */
+
+ struct v4l2_format in; /* current VBI capture format */
+ struct v4l2_sliced_vbi_format *sliced_in; /* convenience pointer to sliced struct in vbi.in union */
+ int insert_mpeg; /* if non-zero, then embed VBI data in MPEG stream */
+
+ /* Raw VBI compatibility hack */
+
+ u32 frame; /* frame counter hack needed for backwards compatibility
+ of old VBI software */
+
+ /* Sliced VBI output data */
+
+ struct vbi_cc cc_payload[256]; /* sliced VBI CC payload array: it is an array to
+ prevent dropping CC data if they couldn't be
+ processed fast enough */
+ int cc_payload_idx; /* index in cc_payload */
+ u8 cc_missing_cnt; /* counts number of frames without CC for passthrough mode */
+ int wss_payload; /* sliced VBI WSS payload */
+ u8 wss_missing_cnt; /* counts number of frames without WSS for passthrough mode */
+ struct vbi_vps vps_payload; /* sliced VBI VPS payload */
+
+ /* Sliced VBI capture data */
+
+ struct v4l2_sliced_vbi_data sliced_data[36]; /* sliced VBI storage for VBI encoder stream */
+ struct v4l2_sliced_vbi_data sliced_dec_data[36];/* sliced VBI storage for VBI decoder stream */
+
+ /* VBI Embedding data */
/* Buffer for VBI data inserted into MPEG stream.
The first byte is a dummy byte that's never used.
@@ -690,12 +561,9 @@ struct vbi_info {
This pointer array will allocate 2049 bytes to store each VBI frame. */
u8 *sliced_mpeg_data[IVTV_VBI_FRAMES];
u32 sliced_mpeg_size[IVTV_VBI_FRAMES];
- struct ivtv_buffer sliced_mpeg_buf;
- u32 inserted_frame;
-
- u32 start[2], count;
- u32 raw_size;
- u32 sliced_size;
+ struct ivtv_buffer sliced_mpeg_buf; /* temporary buffer holding data from sliced_mpeg_data */
+ u32 inserted_frame; /* index in sliced_mpeg_size of next sliced data
+ to be inserted in the MPEG stream */
};
/* forward declaration of struct defined in ivtv-cards.h */
@@ -703,131 +571,132 @@ struct ivtv_card;
/* Struct to hold info about ivtv cards */
struct ivtv {
- int num; /* board number, -1 during init! */
- char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */
- struct pci_dev *dev; /* PCI device */
+ /* General fixed card data */
+ int num; /* board number, -1 during init! */
+ char name[8]; /* board name for printk and interrupts (e.g. 'ivtv0') */
+ struct pci_dev *dev; /* PCI device */
const struct ivtv_card *card; /* card information */
- const char *card_name; /* full name of the card */
- u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */
- u8 is_50hz;
- u8 is_60hz;
- u8 is_out_50hz;
- u8 is_out_60hz;
- u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */
- u8 nof_inputs; /* number of video inputs */
- u8 nof_audio_inputs; /* number of audio inputs */
- u32 v4l2_cap; /* V4L2 capabilities of card */
- u32 hw_flags; /* Hardware description of the board */
-
- /* controlling Video decoder function */
+ const char *card_name; /* full name of the card */
+ u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */
+ u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */
+ u8 nof_inputs; /* number of video inputs */
+ u8 nof_audio_inputs; /* number of audio inputs */
+ u32 v4l2_cap; /* V4L2 capabilities of card */
+ u32 hw_flags; /* hardware description of the board */
+ int tunerid; /* userspace tuner ID for experimental Xceive tuner support */
+ v4l2_std_id tuner_std; /* the norm of the card's tuner (fixed) */
+ /* controlling video decoder function */
int (*video_dec_func)(struct ivtv *, unsigned int, void *);
+ u32 base_addr; /* PCI resource base address */
+ volatile void __iomem *enc_mem; /* pointer to mapped encoder memory */
+ volatile void __iomem *dec_mem; /* pointer to mapped decoder memory */
+ volatile void __iomem *reg_mem; /* pointer to mapped registers */
+ struct ivtv_options options; /* user options */
+
+
+ /* High-level state info */
+ unsigned long i_flags; /* global ivtv flags */
+ u8 is_50hz; /* 1 if the current capture standard is 50 Hz */
+ u8 is_60hz /* 1 if the current capture standard is 60 Hz */;
+ u8 is_out_50hz /* 1 if the current TV output standard is 50 Hz */;
+ u8 is_out_60hz /* 1 if the current TV output standard is 60 Hz */;
+ int output_mode; /* decoder output mode: NONE, MPG, YUV, UDMA YUV, passthrough */
+ u32 audio_input; /* current audio input */
+ u32 active_input; /* current video input */
+ u32 active_output; /* current video output */
+ v4l2_std_id std; /* current capture TV standard */
+ v4l2_std_id std_out; /* current TV output standard */
+ u8 audio_stereo_mode; /* decoder setting how to handle stereo MPEG audio */
+ u8 audio_bilingual_mode; /* decoder setting how to handle bilingual MPEG audio */
+ struct cx2341x_mpeg_params params; /* current encoder parameters */
+
+
+ /* Locking */
+ spinlock_t lock; /* lock access to this struct */
+ struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */
+
+
+ /* Streams */
+ int stream_buf_size[IVTV_MAX_STREAMS]; /* stream buffer size */
+ struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* stream data */
+ atomic_t capturing; /* count number of active capture streams */
+ atomic_t decoding; /* count number of active decoding streams */
+
+
+ /* Interrupts & DMA */
+ u32 irqmask; /* active interrupts */
+ u32 irq_rr_idx; /* round-robin stream index */
+ struct workqueue_struct *irq_work_queues; /* workqueue for PIO/YUV/VBI actions */
+ struct work_struct irq_work_queue; /* work entry */
+ spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
+ int cur_dma_stream; /* index of current stream doing DMA (-1 if none) */
+ int cur_pio_stream; /* index of current stream doing PIO (-1 if none) */
+ u32 dma_data_req_offset; /* store offset in decoder memory of current DMA request */
+ u32 dma_data_req_size; /* store size of current DMA request */
+ int dma_retries; /* current DMA retry attempt */
+ struct ivtv_user_dma udma; /* user based DMA for OSD */
+ struct timer_list dma_timer; /* timer used to catch unfinished DMAs */
+ u32 last_vsync_field; /* last seen vsync field */
+ wait_queue_head_t dma_waitq; /* wake up when the current DMA is finished */
+ wait_queue_head_t eos_waitq; /* wake up when EOS arrives */
+ wait_queue_head_t event_waitq; /* wake up when the next decoder event arrives */
+ wait_queue_head_t vsync_waitq; /* wake up when the next decoder vsync arrives */
+
+
+ /* Mailbox */
+ struct ivtv_mailbox_data enc_mbox; /* encoder mailboxes */
+ struct ivtv_mailbox_data dec_mbox; /* decoder mailboxes */
+ struct ivtv_api_cache api_cache[256]; /* cached API commands */
+
+
+ /* I2C */
+ struct i2c_adapter i2c_adap;
+ struct i2c_algo_bit_data i2c_algo;
+ struct i2c_client i2c_client;
+ struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];/* pointers to all I2C clients */
+ int i2c_state; /* i2c bit state */
+ struct mutex i2c_bus_lock; /* lock i2c bus */
+
+
+ /* Program Index information */
+ u32 pgm_info_offset; /* start of pgm info in encoder memory */
+ u32 pgm_info_num; /* number of elements in the pgm cyclic buffer in encoder memory */
+ u32 pgm_info_write_idx; /* last index written by the card that was transferred to pgm_info[] */
+ u32 pgm_info_read_idx; /* last index in pgm_info read by the application */
+ struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; /* filled from the pgm cyclic buffer on the card */
+
+
+ /* Miscellaneous */
+ u32 open_id; /* incremented each time an open occurs, is >= 1 */
+ struct v4l2_prio_state prio; /* priority state */
+ int search_pack_header; /* 1 if ivtv_copy_buf_to_user() is scanning for a pack header (0xba) */
+ int speed; /* current playback speed setting */
+ u8 speed_mute_audio; /* 1 if audio should be muted when fast forward */
+ u64 mpg_data_received; /* number of bytes received from the MPEG stream */
+ u64 vbi_data_inserted; /* number of VBI bytes inserted into the MPEG stream */
+ u32 last_dec_timing[3]; /* cache last retrieved pts/scr/frame values */
+ unsigned long dualwatch_jiffies;/* jiffies value of the previous dualwatch check */
+ u16 dualwatch_stereo_mode; /* current detected dualwatch stereo mode */
+
+
+ /* VBI state info */
+ struct vbi_info vbi; /* VBI-specific data */
+
+
+ /* YUV playback */
+ struct yuv_playback_info yuv_info; /* YUV playback data */
- struct ivtv_options options; /* User options */
- int stream_buf_size[IVTV_MAX_STREAMS]; /* Stream buffer size */
- struct ivtv_stream streams[IVTV_MAX_STREAMS]; /* Stream data */
- int speed;
- u8 speed_mute_audio;
- unsigned long i_flags; /* global ivtv flags */
- atomic_t capturing; /* count number of active capture streams */
- atomic_t decoding; /* count number of active decoding streams */
- u32 irq_rr_idx; /* Round-robin stream index */
- int cur_dma_stream; /* index of stream doing DMA */
- int cur_pio_stream; /* index of stream doing PIO */
- u32 dma_data_req_offset;
- u32 dma_data_req_size;
- int output_mode; /* NONE, MPG, YUV, UDMA YUV, passthrough */
- spinlock_t lock; /* lock access to this struct */
- int search_pack_header;
-
- spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
- struct mutex serialize_lock; /* lock used to serialize starting streams */
-
- /* User based DMA for OSD */
- struct ivtv_user_dma udma;
-
- int open_id; /* incremented each time an open occurs, used as unique ID.
- starts at 1, so 0 can be used as uninitialized value
- in the stream->id. */
-
- u32 base_addr;
- u32 irqmask;
-
- struct v4l2_prio_state prio;
- struct workqueue_struct *irq_work_queues;
- struct work_struct irq_work_queue;
- struct timer_list dma_timer; /* Timer used to catch unfinished DMAs */
-
- struct vbi_info vbi;
-
- struct ivtv_mailbox_data enc_mbox;
- struct ivtv_mailbox_data dec_mbox;
- struct ivtv_api_cache api_cache[256]; /* Cached API Commands */
-
- u8 card_rev;
- volatile void __iomem *enc_mem, *dec_mem, *reg_mem;
-
- u32 pgm_info_offset;
- u32 pgm_info_num;
- u32 pgm_info_write_idx;
- u32 pgm_info_read_idx;
- struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX];
-
- u64 mpg_data_received;
- u64 vbi_data_inserted;
-
- wait_queue_head_t cap_w;
- /* when the next decoder event arrives this queue is woken up */
- wait_queue_head_t event_waitq;
- /* when the next decoder vsync arrives this queue is woken up */
- wait_queue_head_t vsync_waitq;
- /* when the current DMA is finished this queue is woken up */
- wait_queue_head_t dma_waitq;
/* OSD support */
unsigned long osd_video_pbase;
- int osd_global_alpha_state; /* 0=off : 1=on */
- int osd_local_alpha_state; /* 0=off : 1=on */
- int osd_color_key_state; /* 0=off : 1=on */
- u8 osd_global_alpha; /* Current global alpha */
- u32 osd_color_key; /* Current color key */
- u32 osd_pixelformat; /* Current pixel format */
- struct v4l2_rect osd_rect; /* Current OSD position and size */
- struct v4l2_rect main_rect; /* Current Main window position and size */
-
- u32 last_dec_timing[3]; /* Store last retrieved pts/scr/frame values */
-
- /* i2c */
- struct i2c_adapter i2c_adap;
- struct i2c_algo_bit_data i2c_algo;
- struct i2c_client i2c_client;
- struct mutex i2c_bus_lock;
- int i2c_state;
- struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
-
- /* v4l2 and User settings */
-
- /* codec settings */
- struct cx2341x_mpeg_params params;
- u32 audio_input;
- u32 active_input;
- u32 active_output;
- v4l2_std_id std;
- v4l2_std_id std_out;
- v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */
- u8 audio_stereo_mode;
- u8 audio_bilingual_mode;
-
- /* dualwatch */
- unsigned long dualwatch_jiffies;
- u16 dualwatch_stereo_mode;
-
- /* Digitizer type */
- int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */
-
- u32 lastVsyncFrame;
-
- struct yuv_playback_info yuv_info;
- struct osd_info *osd_info;
+ int osd_global_alpha_state; /* 1 = global alpha is on */
+ int osd_local_alpha_state; /* 1 = local alpha is on */
+ int osd_chroma_key_state; /* 1 = chroma-keying is on */
+ u8 osd_global_alpha; /* current global alpha */
+ u32 osd_chroma_key; /* current chroma key */
+ struct v4l2_rect osd_rect; /* current OSD position and size */
+ struct v4l2_rect main_rect; /* current Main window position and size */
+ struct osd_info *osd_info; /* ivtvfb private OSD info */
};
/* Globals */
@@ -858,6 +727,9 @@ int ivtv_waitq(wait_queue_head_t *waitq);
struct tveeprom; /* forward reference */
void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv);
+/* First-open initialization: load firmware, init cx25840, etc. */
+int ivtv_init_on_first_open(struct ivtv *itv);
+
/* This is a PCI post thing, where if the pci register is not read, then
the write doesn't always take effect right away. By reading back the
register any pending PCI writes will be performed (in order), and so
@@ -885,4 +757,4 @@ void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv);
#define write_dec_sync(val, addr) \
do { write_dec(val, addr); read_dec(addr); } while (0)
-#endif /* IVTV_DRIVER_H */
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 66ea3cbc369..a200a8a95a2 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -27,10 +27,9 @@
#include "ivtv-irq.h"
#include "ivtv-vbi.h"
#include "ivtv-mailbox.h"
-#include "ivtv-audio.h"
+#include "ivtv-routing.h"
#include "ivtv-streams.h"
#include "ivtv-yuv.h"
-#include "ivtv-controls.h"
#include "ivtv-ioctl.h"
#include "ivtv-cards.h"
#include <media/saa7115.h>
@@ -247,8 +246,9 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
/* do we have new data? */
buf = ivtv_dequeue(s, &s->q_full);
if (buf) {
- if (!test_and_clear_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags))
+ if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0)
return buf;
+ buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP;
if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
/* byteswap MPG data */
ivtv_buf_swap(buf);
@@ -258,19 +258,19 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
}
return buf;
}
- /* return if file was opened with O_NONBLOCK */
- if (non_block) {
- *err = -EAGAIN;
- return NULL;
- }
/* return if end of stream */
if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
- clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
IVTV_DEBUG_INFO("EOS %s\n", s->name);
return NULL;
}
+ /* return if file was opened with O_NONBLOCK */
+ if (non_block) {
+ *err = -EAGAIN;
+ return NULL;
+ }
+
/* wait for more data to arrive */
prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
/* New buffers might have become available before we were added to the waitqueue */
@@ -378,10 +378,20 @@ static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_co
int rc;
buf = ivtv_get_buffer(s, non_block, &rc);
- if (buf == NULL && rc == -EAGAIN && tot_written)
- break;
- if (buf == NULL)
+ /* if there is no data available... */
+ if (buf == NULL) {
+ /* if we got data, then return that regardless */
+ if (tot_written)
+ break;
+ /* EOS condition */
+ if (rc == 0) {
+ clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+ clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ ivtv_release_stream(s);
+ }
+ /* set errno */
return rc;
+ }
rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written);
if (buf != &itv->vbi.sliced_mpeg_buf) {
ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io);
@@ -408,7 +418,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co
ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0;
struct ivtv *itv = s->itv;
- IVTV_DEBUG_HI_INFO("read %zd from %s, got %zd\n", count, s->name, rc);
+ IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);
if (rc > 0)
pos += rc;
return rc;
@@ -499,9 +509,11 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_
struct ivtv_stream *s = &itv->streams[id->type];
int rc;
- IVTV_DEBUG_HI_IOCTL("read %zd bytes from %s\n", count, s->name);
+ IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
+ mutex_lock(&itv->serialize_lock);
rc = ivtv_start_capture(id);
+ mutex_unlock(&itv->serialize_lock);
if (rc)
return rc;
return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
@@ -537,7 +549,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
int rc;
DEFINE_WAIT(wait);
- IVTV_DEBUG_HI_IOCTL("write %zd bytes to %s\n", count, s->name);
+ IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name);
if (s->type != IVTV_DEC_STREAM_TYPE_MPG &&
s->type != IVTV_DEC_STREAM_TYPE_YUV &&
@@ -551,8 +563,11 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
/* This stream does not need to start any decoding */
if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) {
+ int elems = count / sizeof(struct v4l2_sliced_vbi_data);
+
set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- return ivtv_write_vbi(itv, user_buf, count);
+ ivtv_write_vbi(itv, (const struct v4l2_sliced_vbi_data *)user_buf, elems);
+ return elems * sizeof(struct v4l2_sliced_vbi_data);
}
mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV;
@@ -612,7 +627,9 @@ retry:
}
/* Start decoder (returns 0 if already started) */
+ mutex_lock(&itv->serialize_lock);
rc = ivtv_start_decoding(id, itv->speed);
+ mutex_unlock(&itv->serialize_lock);
if (rc) {
IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
@@ -645,7 +662,7 @@ retry:
to transfer the rest. */
if (count && !(filp->f_flags & O_NONBLOCK))
goto retry;
- IVTV_DEBUG_HI_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+ IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
return bytes_written;
}
@@ -657,6 +674,7 @@ unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait)
int res = 0;
/* add stream's waitq to the poll list */
+ IVTV_DEBUG_HI_FILE("Decoder poll\n");
poll_wait(filp, &s->waitq, wait);
set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
@@ -679,16 +697,21 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
/* Start a capture if there is none */
if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
- int rc = ivtv_start_capture(id);
+ int rc;
+ mutex_lock(&itv->serialize_lock);
+ rc = ivtv_start_capture(id);
+ mutex_unlock(&itv->serialize_lock);
if (rc) {
IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n",
s->name, rc);
return POLLERR;
}
+ IVTV_DEBUG_FILE("Encoder poll started capture\n");
}
/* add stream's waitq to the poll list */
+ IVTV_DEBUG_HI_FILE("Encoder poll\n");
poll_wait(filp, &s->waitq, wait);
if (eof || s->q_full.length)
@@ -701,7 +724,7 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end)
struct ivtv *itv = id->itv;
struct ivtv_stream *s = &itv->streams[id->type];
- IVTV_DEBUG_IOCTL("close() of %s\n", s->name);
+ IVTV_DEBUG_FILE("close() of %s\n", s->name);
/* 'Unclaim' this stream */
@@ -728,10 +751,11 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end)
ivtv_stop_v4l2_encode_stream(s, gop_end);
}
}
- clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
-
- ivtv_release_stream(s);
+ if (!gop_end) {
+ clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+ clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+ ivtv_release_stream(s);
+ }
}
static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
@@ -739,13 +763,14 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
struct ivtv *itv = id->itv;
struct ivtv_stream *s = &itv->streams[id->type];
- IVTV_DEBUG_IOCTL("close() of %s\n", s->name);
+ IVTV_DEBUG_FILE("close() of %s\n", s->name);
/* Stop decoding */
if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
IVTV_DEBUG_INFO("close stopping decode\n");
ivtv_stop_v4l2_decode_stream(s, flags, pts);
+ itv->output_mode = OUT_NONE;
}
clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
@@ -753,11 +778,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
/* Restore registers we've changed & clean up any mess we've made */
ivtv_yuv_close(itv);
}
- if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_YUV)
- itv->output_mode = OUT_NONE;
- else if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_UDMA_YUV)
- itv->output_mode = OUT_NONE;
- else if (s->type == IVTV_DEC_STREAM_TYPE_MPG && itv->output_mode == OUT_MPG)
+ if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames)
itv->output_mode = OUT_NONE;
itv->speed = 0;
@@ -771,7 +792,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
struct ivtv *itv = id->itv;
struct ivtv_stream *s = &itv->streams[id->type];
- IVTV_DEBUG_IOCTL("close() of %s\n", s->name);
+ IVTV_DEBUG_FILE("close %s\n", s->name);
v4l2_prio_close(&itv->prio, &id->prio);
@@ -784,6 +805,7 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
/* 'Unclaim' this stream */
/* Stop radio */
+ mutex_lock(&itv->serialize_lock);
if (id->type == IVTV_ENC_STREAM_TYPE_RAD) {
/* Closing radio device, return to TV mode */
ivtv_mute(itv);
@@ -800,6 +822,11 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
crystal_freq.flags = 0;
ivtv_saa7115(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
}
+ if (atomic_read(&itv->capturing) > 0) {
+ /* Undo video mute */
+ ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,
+ itv->params.video_mute | (itv->params.video_mute_yuv << 8));
+ }
/* Done! Unmute and continue. */
ivtv_unmute(itv);
ivtv_release_stream(s);
@@ -809,56 +836,35 @@ int ivtv_v4l2_close(struct inode *inode, struct file *filp)
ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
/* If all output streams are closed, and if the user doesn't have
- IVTV_DEC_STREAM_TYPE_VOUT open, then disable VBI on TV-out. */
+ IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */
if (itv->output_mode == OUT_NONE && !test_bit(IVTV_F_S_APPL_IO, &s_vout->s_flags)) {
- /* disable VBI on TV-out */
- ivtv_disable_vbi(itv);
+ /* disable CC on TV-out */
+ ivtv_disable_cc(itv);
}
} else {
ivtv_stop_capture(id, 0);
}
kfree(id);
+ mutex_unlock(&itv->serialize_lock);
return 0;
}
-int ivtv_v4l2_open(struct inode *inode, struct file *filp)
+static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
{
- int x, y = 0;
+ struct ivtv *itv = s->itv;
struct ivtv_open_id *item;
- struct ivtv *itv = NULL;
- struct ivtv_stream *s = NULL;
- int minor = iminor(inode);
- /* Find which card this open was on */
- spin_lock(&ivtv_cards_lock);
- for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {
- /* find out which stream this open was on */
- for (y = 0; y < IVTV_MAX_STREAMS; y++) {
- s = &ivtv_cards[x]->streams[y];
- if (s->v4l2dev && s->v4l2dev->minor == minor) {
- itv = ivtv_cards[x];
- break;
- }
- }
- }
- spin_unlock(&ivtv_cards_lock);
+ IVTV_DEBUG_FILE("open %s\n", s->name);
- if (itv == NULL) {
- /* Couldn't find a device registered
- on that minor, shouldn't happen! */
- printk(KERN_WARNING "ivtv: No ivtv device found on minor %d\n", minor);
- return -ENXIO;
- }
-
- if (y == IVTV_DEC_STREAM_TYPE_MPG &&
+ if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
return -EBUSY;
- if (y == IVTV_DEC_STREAM_TYPE_YUV &&
+ if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags))
return -EBUSY;
- if (y == IVTV_DEC_STREAM_TYPE_YUV) {
+ if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
if (read_reg(0x82c) == 0) {
IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n");
/* return -ENODEV; */
@@ -873,7 +879,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
return -ENOMEM;
}
item->itv = itv;
- item->type = y;
+ item->type = s->type;
v4l2_prio_open(&itv->prio, &item->prio);
item->open_id = itv->open_id++;
@@ -887,12 +893,21 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
return -EBUSY;
}
+ if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+ if (atomic_read(&itv->capturing) > 0) {
+ /* switching to radio while capture is
+ in progress is not polite */
+ ivtv_release_stream(s);
+ kfree(item);
+ return -EBUSY;
+ }
+ }
+ /* Mark that the radio is being used. */
+ set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
/* We have the radio */
ivtv_mute(itv);
/* Switch tuner to radio */
ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL);
- /* Mark that the radio is being used. */
- set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
/* Select the correct audio input (i.e. radio tuner) */
ivtv_audio_set_io(itv);
if (itv->hw_flags & IVTV_HW_SAA711X)
@@ -907,45 +922,65 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
}
/* YUV or MPG Decoding Mode? */
- if (y == IVTV_DEC_STREAM_TYPE_MPG)
+ if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
- else if (y == IVTV_DEC_STREAM_TYPE_YUV)
- {
+ else if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
- }
-
return 0;
}
-void ivtv_mute(struct ivtv *itv)
+int ivtv_v4l2_open(struct inode *inode, struct file *filp)
{
- struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 1 };
+ int res, x, y = 0;
+ struct ivtv *itv = NULL;
+ struct ivtv_stream *s = NULL;
+ int minor = iminor(inode);
+
+ /* Find which card this open was on */
+ spin_lock(&ivtv_cards_lock);
+ for (x = 0; itv == NULL && x < ivtv_cards_active; x++) {
+ /* find out which stream this open was on */
+ for (y = 0; y < IVTV_MAX_STREAMS; y++) {
+ s = &ivtv_cards[x]->streams[y];
+ if (s->v4l2dev && s->v4l2dev->minor == minor) {
+ itv = ivtv_cards[x];
+ break;
+ }
+ }
+ }
+ spin_unlock(&ivtv_cards_lock);
+
+ if (itv == NULL) {
+ /* Couldn't find a device registered
+ on that minor, shouldn't happen! */
+ printk(KERN_WARNING "No ivtv device found on minor %d\n", minor);
+ return -ENXIO;
+ }
- /* Mute sound to avoid pop */
- ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl);
+ mutex_lock(&itv->serialize_lock);
+ if (ivtv_init_on_first_open(itv)) {
+ IVTV_ERR("Failed to initialize on minor %d\n", minor);
+ mutex_unlock(&itv->serialize_lock);
+ return -ENXIO;
+ }
+ res = ivtv_serialized_open(s, filp);
+ mutex_unlock(&itv->serialize_lock);
+ return res;
+}
+void ivtv_mute(struct ivtv *itv)
+{
if (atomic_read(&itv->capturing))
ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1);
-
IVTV_DEBUG_INFO("Mute\n");
}
void ivtv_unmute(struct ivtv *itv)
{
- struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 0 };
-
- /* initialize or refresh input */
- if (atomic_read(&itv->capturing) == 0)
- ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-
- ivtv_msleep_timeout(100, 0);
-
if (atomic_read(&itv->capturing)) {
+ ivtv_msleep_timeout(100, 0);
ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0);
}
-
- /* Unmute */
- ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl);
IVTV_DEBUG_INFO("Unmute\n");
}
diff --git a/drivers/media/video/ivtv/ivtv-fileops.h b/drivers/media/video/ivtv/ivtv-fileops.h
index 74a1745fabb..2c8d5186c9c 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.h
+++ b/drivers/media/video/ivtv/ivtv-fileops.h
@@ -18,6 +18,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_FILEOPS_H
+#define IVTV_FILEOPS_H
+
/* Testing/Debugging */
int ivtv_v4l2_open(struct inode *inode, struct file *filp);
ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count,
@@ -42,3 +45,5 @@ int ivtv_claim_stream(struct ivtv_open_id *id, int type);
/* Release a previously claimed stream. */
void ivtv_release_stream(struct ivtv_stream *s);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h
index 8b2ffe65890..041ba94e65b 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.h
+++ b/drivers/media/video/ivtv/ivtv-firmware.h
@@ -19,7 +19,12 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_FIRMWARE_H
+#define IVTV_FIRMWARE_H
+
int ivtv_firmware_init(struct ivtv *itv);
void ivtv_firmware_versions(struct ivtv *itv);
void ivtv_halt_firmware(struct ivtv *itv);
void ivtv_init_mpeg_decoder(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index 6a5a7aa6697..132fb5f7136 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -122,30 +122,6 @@ void ivtv_reset_ir_gpio(struct ivtv *itv)
write_reg(curdir, IVTV_REG_GPIO_DIR);
}
-#ifdef HAVE_XC3028
-int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr)
-{
- int curdir, curout;
- struct ivtv *itv = (struct ivtv *) priv;
-
- if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028)
- return -EINVAL;
- IVTV_INFO("Resetting tuner\n");
- curout = read_reg(IVTV_REG_GPIO_OUT);
- curdir = read_reg(IVTV_REG_GPIO_DIR);
- curdir |= (1 << 12); /* GPIO bit 12 */
-
- curout &= ~(1 << 12);
- write_reg(curout, IVTV_REG_GPIO_OUT);
- schedule_timeout_interruptible(msecs_to_jiffies(1));
-
- curout |= (1 << 12);
- write_reg(curout, IVTV_REG_GPIO_OUT);
- schedule_timeout_interruptible(msecs_to_jiffies(1));
-
- return 0;
-}
-#endif
void ivtv_gpio_init(struct ivtv *itv)
{
diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h
index c301d2a3934..964a265d91a 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.h
+++ b/drivers/media/video/ivtv/ivtv-gpio.h
@@ -18,8 +18,13 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_GPIO_H
+#define IVTV_GPIO_H
+
/* GPIO stuff */
void ivtv_gpio_init(struct ivtv *itv);
void ivtv_reset_ir_gpio(struct ivtv *itv);
-int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr);
+int ivtv_reset_tuner_gpio(void *dev, int cmd, int value);
int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index b3557435456..623eea2652c 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -109,6 +109,7 @@ static const u8 hw_driverids[] = {
I2C_DRIVERID_UPD64083,
I2C_DRIVERID_SAA717X,
I2C_DRIVERID_WM8739,
+ I2C_DRIVERID_VP27SMPX,
0 /* IVTV_HW_GPIO dummy driver ID */
};
@@ -128,6 +129,7 @@ static const char * const hw_drivernames[] = {
"upd64083",
"saa717x",
"wm8739",
+ "vp27smpx",
"gpio",
};
@@ -534,14 +536,13 @@ static struct i2c_adapter ivtv_i2c_adap_template = {
#endif
};
-static struct i2c_algo_bit_data ivtv_i2c_algo_template = {
- NULL, /* ?? */
- ivtv_setsda_old, /* setsda function */
- ivtv_setscl_old, /* " */
- ivtv_getsda_old, /* " */
- ivtv_getscl_old, /* " */
- 10, /* udelay */
- 200 /* timeout */
+static const struct i2c_algo_bit_data ivtv_i2c_algo_template = {
+ .setsda = ivtv_setsda_old,
+ .setscl = ivtv_setscl_old,
+ .getsda = ivtv_getsda_old,
+ .getscl = ivtv_getscl_old,
+ .udelay = 5,
+ .timeout = 200,
};
static struct i2c_client ivtv_i2c_client_template = {
@@ -740,7 +741,7 @@ int __devinit init_ivtv_i2c(struct ivtv *itv)
return i2c_bit_add_bus(&itv->i2c_adap);
}
-void __devexit exit_ivtv_i2c(struct ivtv *itv)
+void exit_ivtv_i2c(struct ivtv *itv)
{
IVTV_DEBUG_I2C("i2c exit\n");
diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h
index 5d210adb5c5..de6a0744229 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.h
+++ b/drivers/media/video/ivtv/ivtv-i2c.h
@@ -18,6 +18,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_I2C_H
+#define IVTV_I2C_H
+
int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg);
int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg);
int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg);
@@ -33,4 +36,6 @@ void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg);
/* init + register i2c algo-bit adapter */
int __devinit init_ivtv_i2c(struct ivtv *itv);
-void __devexit exit_ivtv_i2c(struct ivtv *itv);
+void exit_ivtv_i2c(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index dfe0aedc60f..fd6826f472e 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -25,8 +25,7 @@
#include "ivtv-queue.h"
#include "ivtv-fileops.h"
#include "ivtv-vbi.h"
-#include "ivtv-audio.h"
-#include "ivtv-video.h"
+#include "ivtv-routing.h"
#include "ivtv-streams.h"
#include "ivtv-yuv.h"
#include "ivtv-ioctl.h"
@@ -164,7 +163,7 @@ void ivtv_set_osd_alpha(struct ivtv *itv)
{
ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3,
itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state);
- ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_color_key_state, itv->osd_color_key);
+ ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key);
}
int ivtv_set_speed(struct ivtv *itv, int speed)
@@ -427,7 +426,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
- fmt->fmt.win.chromakey = itv->osd_color_key;
+ fmt->fmt.win.chromakey = itv->osd_chroma_key;
fmt->fmt.win.global_alpha = itv->osd_global_alpha;
break;
@@ -547,7 +546,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
if (set_fmt) {
- itv->osd_color_key = fmt->fmt.win.chromakey;
+ itv->osd_chroma_key = fmt->fmt.win.chromakey;
itv->osd_global_alpha = fmt->fmt.win.global_alpha;
ivtv_set_osd_alpha(itv);
}
@@ -556,6 +555,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
/* set window size */
if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ struct cx2341x_mpeg_params *p = &itv->params;
int w = fmt->fmt.pix.width;
int h = fmt->fmt.pix.height;
@@ -567,26 +567,26 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
fmt->fmt.pix.width = w;
fmt->fmt.pix.height = h;
- if (!set_fmt || (itv->params.width == w && itv->params.height == h))
+ if (!set_fmt || (p->width == w && p->height == h))
return 0;
if (atomic_read(&itv->capturing) > 0)
return -EBUSY;
- itv->params.width = w;
- itv->params.height = h;
+ p->width = w;
+ p->height = h;
if (w != 720 || h != (itv->is_50hz ? 576 : 480))
- itv->params.video_temporal_filter = 0;
+ p->video_temporal_filter = 0;
else
- itv->params.video_temporal_filter = 8;
+ p->video_temporal_filter = 8;
+ if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ fmt->fmt.pix.width /= 2;
itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
return ivtv_get_fmt(itv, streamtype, fmt);
}
/* set raw VBI format */
if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (set_fmt && streamtype == IVTV_ENC_STREAM_TYPE_VBI &&
- itv->vbi.sliced_in->service_set &&
- atomic_read(&itv->capturing) > 0) {
+ if (set_fmt && atomic_read(&itv->capturing) > 0) {
return -EBUSY;
}
if (set_fmt) {
@@ -624,7 +624,7 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
return 0;
if (set == 0)
return -EINVAL;
- if (atomic_read(&itv->capturing) > 0 && itv->vbi.sliced_in->service_set == 0) {
+ if (atomic_read(&itv->capturing) > 0) {
return -EBUSY;
}
itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
@@ -677,13 +677,21 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
case VIDIOC_INT_S_AUDIO_ROUTING: {
struct v4l2_routing *route = arg;
- ivtv_audio_set_route(itv, route);
+ ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
break;
}
- case VIDIOC_INT_RESET:
- ivtv_reset_ir_gpio(itv);
+ case VIDIOC_INT_RESET: {
+ u32 val = *(u32 *)arg;
+
+ if ((val == 0 && itv->options.newi2c) || (val & 0x01)) {
+ ivtv_reset_ir_gpio(itv);
+ }
+ if (val & 0x02) {
+ itv->video_dec_func(itv, cmd, 0);
+ }
break;
+ }
default:
return -EINVAL;
@@ -694,6 +702,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg)
{
struct ivtv_open_id *id = NULL;
+ u32 data[CX2341X_MBOX_MAX_DATA];
if (filp) id = (struct ivtv_open_id *)filp->private_data;
@@ -898,6 +907,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
IVTV_DEBUG_INFO("Input unchanged\n");
break;
}
+ if (atomic_read(&itv->capturing) > 0) {
+ return -EBUSY;
+ }
IVTV_DEBUG_INFO("Changing input from %d to %d\n",
itv->active_input, inp);
@@ -1127,12 +1139,14 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
memset(&enc->raw, 0, sizeof(enc->raw));
switch (enc->cmd) {
case V4L2_ENC_CMD_START:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
enc->flags = 0;
if (try)
return 0;
return ivtv_start_capture(id);
case V4L2_ENC_CMD_STOP:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
if (try)
return 0;
@@ -1140,6 +1154,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
return 0;
case V4L2_ENC_CMD_PAUSE:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
enc->flags = 0;
if (try)
return 0;
@@ -1152,6 +1167,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
break;
case V4L2_ENC_CMD_RESUME:
+ IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
enc->flags = 0;
if (try)
return 0;
@@ -1163,6 +1179,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
ivtv_unmute(itv);
break;
default:
+ IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
return -EINVAL;
}
break;
@@ -1170,22 +1187,58 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
case VIDIOC_G_FBUF: {
struct v4l2_framebuffer *fb = arg;
+ int pixfmt;
+ static u32 pixel_format[16] = {
+ V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
+ V4L2_PIX_FMT_RGB565,
+ V4L2_PIX_FMT_RGB555,
+ V4L2_PIX_FMT_RGB444,
+ V4L2_PIX_FMT_RGB32,
+ 0,
+ 0,
+ 0,
+ V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
+ V4L2_PIX_FMT_YUV565,
+ V4L2_PIX_FMT_YUV555,
+ V4L2_PIX_FMT_YUV444,
+ V4L2_PIX_FMT_YUV32,
+ 0,
+ 0,
+ 0,
+ };
memset(fb, 0, sizeof(*fb));
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
return -EINVAL;
fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
- V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA;
- fb->fmt.pixelformat = itv->osd_pixelformat;
+ V4L2_FBUF_CAP_GLOBAL_ALPHA;
+ ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+ data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+ pixfmt = (data[0] >> 3) & 0xf;
+ fb->fmt.pixelformat = pixel_format[pixfmt];
fb->fmt.width = itv->osd_rect.width;
fb->fmt.height = itv->osd_rect.height;
fb->base = (void *)itv->osd_video_pbase;
+ if (itv->osd_chroma_key_state)
+ fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
if (itv->osd_global_alpha_state)
fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
- if (itv->osd_local_alpha_state)
- fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
- if (itv->osd_color_key_state)
- fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+ pixfmt &= 7;
+ /* no local alpha for RGB565 or unknown formats */
+ if (pixfmt == 1 || pixfmt > 4)
+ break;
+ /* 16-bit formats have inverted local alpha */
+ if (pixfmt == 2 || pixfmt == 3)
+ fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+ else
+ fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
+ if (itv->osd_local_alpha_state) {
+ /* 16-bit formats have inverted local alpha */
+ if (pixfmt == 2 || pixfmt == 3)
+ fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
+ else
+ fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+ }
break;
}
@@ -1195,12 +1248,22 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
return -EINVAL;
itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
- itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0;
- itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+ itv->osd_local_alpha_state =
+ (fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
+ itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
ivtv_set_osd_alpha(itv);
break;
}
+ case VIDIOC_OVERLAY: {
+ int *on = arg;
+
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+ return -EINVAL;
+ ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0);
+ break;
+ }
+
case VIDIOC_LOG_STATUS:
{
int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
@@ -1209,6 +1272,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
int i;
IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num);
+ IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
if (itv->hw_flags & IVTV_HW_TVEEPROM) {
struct tveeprom tv;
@@ -1217,32 +1281,72 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
ivtv_get_input(itv, itv->active_input, &vidin);
ivtv_get_audio_input(itv, itv->audio_input, &audin);
- IVTV_INFO("Video Input: %s\n", vidin.name);
- IVTV_INFO("Audio Input: %s\n", audin.name);
+ IVTV_INFO("Video Input: %s\n", vidin.name);
+ IVTV_INFO("Audio Input: %s%s\n", audin.name,
+ (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : "");
if (has_output) {
struct v4l2_output vidout;
struct v4l2_audioout audout;
int mode = itv->output_mode;
- static const char * const output_modes[] = {
+ static const char * const output_modes[5] = {
"None",
"MPEG Streaming",
"YUV Streaming",
"YUV Frames",
"Passthrough",
};
+ static const char * const audio_modes[5] = {
+ "Stereo",
+ "Left",
+ "Right",
+ "Mono",
+ "Swapped"
+ };
+ static const char * const alpha_mode[4] = {
+ "None",
+ "Global",
+ "Local",
+ "Global and Local"
+ };
+ static const char * const pixel_format[16] = {
+ "ARGB Indexed",
+ "RGB 5:6:5",
+ "ARGB 1:5:5:5",
+ "ARGB 1:4:4:4",
+ "ARGB 8:8:8:8",
+ "5",
+ "6",
+ "7",
+ "AYUV Indexed",
+ "YUV 5:6:5",
+ "AYUV 1:5:5:5",
+ "AYUV 1:4:4:4",
+ "AYUV 8:8:8:8",
+ "13",
+ "14",
+ "15",
+ };
ivtv_get_output(itv, itv->active_output, &vidout);
ivtv_get_audio_output(itv, 0, &audout);
IVTV_INFO("Video Output: %s\n", vidout.name);
- IVTV_INFO("Audio Output: %s\n", audout.name);
+ IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
+ audio_modes[itv->audio_stereo_mode],
+ audio_modes[itv->audio_bilingual_mode]);
if (mode < 0 || mode > OUT_PASSTHROUGH)
mode = OUT_NONE;
- IVTV_INFO("Output Mode: %s\n", output_modes[mode]);
+ IVTV_INFO("Output Mode: %s\n", output_modes[mode]);
+ ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+ data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+ IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n",
+ data[0] & 1 ? "On" : "Off",
+ alpha_mode[(data[0] >> 1) & 0x3],
+ pixel_format[(data[0] >> 3) & 0xf]);
}
- IVTV_INFO("Tuner: %s\n",
+ IVTV_INFO("Tuner: %s\n",
test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
cx2341x_log_status(&itv->params, itv->name);
- IVTV_INFO("Version: %s Status flags: 0x%08lx\n", IVTV_VERSION, itv->i_flags);
+ IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags);
for (i = 0; i < IVTV_MAX_STREAMS; i++) {
struct ivtv_stream *s = &itv->streams[i];
@@ -1252,7 +1356,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
(s->buffers - s->q_free.buffers) * 100 / s->buffers,
(s->buffers * s->buf_size) / 1024, s->buffers);
}
- IVTV_INFO("Read MPEG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
+ IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num);
break;
}
@@ -1288,6 +1392,8 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
ivtv_release_stream(s);
return -EBUSY;
}
+ /* Mark that this file handle started the UDMA_YUV mode */
+ id->yuv_frames = 1;
if (args->y_source == NULL)
return 0;
return ivtv_yuv_prep_frame(itv, args);
@@ -1396,9 +1502,9 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
int try = (cmd == VIDEO_TRY_COMMAND);
if (try)
- IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND\n");
+ IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd);
else
- IVTV_DEBUG_IOCTL("VIDEO_COMMAND\n");
+ IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd);
return ivtv_video_command(itv, id, vc, try);
}
@@ -1429,11 +1535,15 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
return 0;
if (nonblocking)
return -EAGAIN;
- /* wait for event */
+ /* Wait for event. Note that serialize_lock is locked,
+ so to allow other processes to access the driver while
+ we are waiting unlock first and later lock again. */
+ mutex_unlock(&itv->serialize_lock);
prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE);
if ((itv->i_flags & (IVTV_F_I_EV_DEC_STOPPED|IVTV_F_I_EV_VSYNC)) == 0)
schedule();
finish_wait(&itv->event_waitq, &wait);
+ mutex_lock(&itv->serialize_lock);
if (signal_pending(current)) {
/* return if a signal was received */
IVTV_DEBUG_INFO("User stopped wait for event\n");
@@ -1470,6 +1580,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
case VIDIOC_S_AUDOUT:
case VIDIOC_S_EXT_CTRLS:
case VIDIOC_S_FBUF:
+ case VIDIOC_OVERLAY:
ret = v4l2_prio_check(&itv->prio, &id->prio);
if (ret)
return ret;
@@ -1523,6 +1634,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
case VIDIOC_TRY_ENCODER_CMD:
case VIDIOC_G_FBUF:
case VIDIOC_S_FBUF:
+ case VIDIOC_OVERLAY:
if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
v4l_printk_ioctl(cmd);
@@ -1563,12 +1675,9 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
return 0;
}
-int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
- struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
- struct ivtv *itv = id->itv;
-
/* Filter dvb ioctls that cannot be handled by video_usercopy */
switch (cmd) {
case VIDEO_SELECT_SOURCE:
@@ -1603,3 +1712,16 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
}
return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl);
}
+
+int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+ struct ivtv *itv = id->itv;
+ int res;
+
+ mutex_lock(&itv->serialize_lock);
+ res = ivtv_serialized_ioctl(itv, inode, filp, cmd, arg);
+ mutex_unlock(&itv->serialize_lock);
+ return res;
+}
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h
index cbccf7a9f65..a03351b6853 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.h
+++ b/drivers/media/video/ivtv/ivtv-ioctl.h
@@ -18,6 +18,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_IOCTL_H
+#define IVTV_IOCTL_H
+
u16 service2vbi(int type);
void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
u16 get_service_set(struct v4l2_sliced_vbi_format *fmt);
@@ -26,3 +29,5 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg);
void ivtv_set_osd_alpha(struct ivtv *itv);
int ivtv_set_speed(struct ivtv *itv, int speed);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index fcd6e7f5f12..fd1688e4757 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -19,12 +19,9 @@
*/
#include "ivtv-driver.h"
-#include "ivtv-firmware.h"
-#include "ivtv-fileops.h"
#include "ivtv-queue.h"
#include "ivtv-udma.h"
#include "ivtv-irq.h"
-#include "ivtv-ioctl.h"
#include "ivtv-mailbox.h"
#include "ivtv-vbi.h"
#include "ivtv-yuv.h"
@@ -45,7 +42,6 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
{
struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream];
struct ivtv_buffer *buf;
- struct list_head *p;
int i = 0;
IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
@@ -57,21 +53,19 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
return;
}
IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name);
- buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list);
- list_for_each(p, &s->q_dma.list) {
- struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
- u32 size = s->PIOarray[i].size & 0x3ffff;
+ list_for_each_entry(buf, &s->q_dma.list, list) {
+ u32 size = s->sg_processing[i].size & 0x3ffff;
/* Copy the data from the card to the buffer */
if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
- memcpy_fromio(buf->buf, itv->dec_mem + s->PIOarray[i].src - IVTV_DECODER_OFFSET, size);
+ memcpy_fromio(buf->buf, itv->dec_mem + s->sg_processing[i].src - IVTV_DECODER_OFFSET, size);
}
else {
- memcpy_fromio(buf->buf, itv->enc_mem + s->PIOarray[i].src, size);
+ memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size);
}
- if (s->PIOarray[i].size & 0x80000000)
- break;
i++;
+ if (i == s->sg_processing_size)
+ break;
}
write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
}
@@ -100,12 +94,11 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
{
struct ivtv *itv = s->itv;
struct ivtv_buffer *buf;
- struct list_head *p;
u32 bytes_needed = 0;
u32 offset, size;
u32 UVoffset = 0, UVsize = 0;
int skip_bufs = s->q_predma.buffers;
- int idx = s->SG_length;
+ int idx = s->sg_pending_size;
int rc;
/* sanity checks */
@@ -123,7 +116,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
case IVTV_ENC_STREAM_TYPE_MPG:
offset = data[1];
size = data[2];
- s->dma_pts = 0;
+ s->pending_pts = 0;
break;
case IVTV_ENC_STREAM_TYPE_YUV:
@@ -131,13 +124,13 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
size = data[2];
UVoffset = data[3];
UVsize = data[4];
- s->dma_pts = ((u64) data[5] << 32) | data[6];
+ s->pending_pts = ((u64) data[5] << 32) | data[6];
break;
case IVTV_ENC_STREAM_TYPE_PCM:
offset = data[1] + 12;
size = data[2] - 12;
- s->dma_pts = read_dec(offset - 8) |
+ s->pending_pts = read_dec(offset - 8) |
((u64)(read_dec(offset - 12)) << 32);
if (itv->has_cx23415)
offset += IVTV_DECODER_OFFSET;
@@ -150,13 +143,13 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
IVTV_DEBUG_INFO("VBI offset == 0\n");
return -1;
}
- s->dma_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32);
+ s->pending_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32);
break;
case IVTV_DEC_STREAM_TYPE_VBI:
size = read_dec(itv->vbi.dec_start + 4) + 8;
offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start;
- s->dma_pts = 0;
+ s->pending_pts = 0;
offset += IVTV_DECODER_OFFSET;
break;
default:
@@ -165,17 +158,17 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
}
/* if this is the start of the DMA then fill in the magic cookie */
- if (s->SG_length == 0) {
+ if (s->sg_pending_size == 0 && ivtv_use_dma(s)) {
if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
- s->dma_backup = read_dec(offset - IVTV_DECODER_OFFSET);
+ s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET);
write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET);
}
else {
- s->dma_backup = read_enc(offset);
+ s->pending_backup = read_enc(offset);
write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset);
}
- s->dma_offset = offset;
+ s->pending_offset = offset;
}
bytes_needed = size;
@@ -202,18 +195,17 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
}
s->buffers_stolen = rc;
- /* got the buffers, now fill in SGarray (DMA) */
+ /* got the buffers, now fill in sg_pending */
buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
memset(buf->buf, 0, 128);
- list_for_each(p, &s->q_predma.list) {
- struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
-
+ list_for_each_entry(buf, &s->q_predma.list, list) {
if (skip_bufs-- > 0)
continue;
- s->SGarray[idx].dst = cpu_to_le32(buf->dma_handle);
- s->SGarray[idx].src = cpu_to_le32(offset);
- s->SGarray[idx].size = cpu_to_le32(s->buf_size);
+ s->sg_pending[idx].dst = buf->dma_handle;
+ s->sg_pending[idx].src = offset;
+ s->sg_pending[idx].size = s->buf_size;
buf->bytesused = (size < s->buf_size) ? size : s->buf_size;
+ buf->dma_xfer_cnt = s->dma_xfer_cnt;
s->q_predma.bytesused += buf->bytesused;
size -= buf->bytesused;
@@ -229,7 +221,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
}
idx++;
}
- s->SG_length = idx;
+ s->sg_pending_size = idx;
return 0;
}
@@ -251,7 +243,7 @@ static void dma_post(struct ivtv_stream *s)
/* Sync Buffer */
ivtv_buf_sync_for_cpu(s, buf);
- if (x == 0) {
+ if (x == 0 && ivtv_use_dma(s)) {
offset = s->dma_last_offset;
if (u32buf[offset / 4] != DMA_MAGIC_COOKIE)
{
@@ -286,14 +278,12 @@ static void dma_post(struct ivtv_stream *s)
/* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */
if (s->type == IVTV_ENC_STREAM_TYPE_MPG ||
s->type == IVTV_ENC_STREAM_TYPE_VBI)
- set_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags);
+ buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP;
}
if (buf)
buf->bytesused += s->dma_last_offset;
if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) {
- list_for_each(p, &s->q_dma.list) {
- buf = list_entry(p, struct ivtv_buffer, list);
-
+ list_for_each_entry(buf, &s->q_dma.list, list) {
/* Parse and Groom VBI Data */
s->q_dma.bytesused -= buf->bytesused;
ivtv_process_vbi_data(itv, buf, 0, s->type);
@@ -313,7 +303,6 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
{
struct ivtv *itv = s->itv;
struct ivtv_buffer *buf;
- struct list_head *p;
u32 y_size = itv->params.height * itv->params.width;
u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
int y_done = 0;
@@ -322,18 +311,15 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
int idx = 0;
IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
- buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
- list_for_each(p, &s->q_predma.list) {
- struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
-
+ list_for_each_entry(buf, &s->q_predma.list, list) {
/* YUV UV Offset from Y Buffer */
if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) {
offset = uv_offset;
y_done = 1;
}
- s->SGarray[idx].src = cpu_to_le32(buf->dma_handle);
- s->SGarray[idx].dst = cpu_to_le32(offset);
- s->SGarray[idx].size = cpu_to_le32(buf->bytesused);
+ s->sg_pending[idx].src = buf->dma_handle;
+ s->sg_pending[idx].dst = offset;
+ s->sg_pending[idx].size = buf->bytesused;
offset += buf->bytesused;
bytes_written += buf->bytesused;
@@ -342,10 +328,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
ivtv_buf_sync_for_device(s, buf);
idx++;
}
- s->SG_length = idx;
-
- /* Mark last buffer size for Interrupt flag */
- s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
+ s->sg_pending_size = idx;
/* Sync Hardware SG List of buffers */
ivtv_stream_sync_for_device(s);
@@ -361,6 +344,34 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
spin_unlock_irqrestore(&itv->dma_reg_lock, flags);
}
+static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s)
+{
+ struct ivtv *itv = s->itv;
+
+ s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
+ s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
+ s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
+ s->sg_processed++;
+ /* Sync Hardware SG List of buffers */
+ ivtv_stream_sync_for_device(s);
+ write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR);
+ write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
+}
+
+static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s)
+{
+ struct ivtv *itv = s->itv;
+
+ s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
+ s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
+ s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
+ s->sg_processed++;
+ /* Sync Hardware SG List of buffers */
+ ivtv_stream_sync_for_device(s);
+ write_reg(s->sg_handle, IVTV_REG_DECDMAADDR);
+ write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
+}
+
/* start the encoder DMA */
static void ivtv_dma_enc_start(struct ivtv_stream *s)
{
@@ -374,8 +385,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
if (ivtv_use_dma(s))
- s->SGarray[s->SG_length - 1].size =
- cpu_to_le32(le32_to_cpu(s->SGarray[s->SG_length - 1].size) + 256);
+ s->sg_pending[s->sg_pending_size - 1].size += 256;
/* If this is an MPEG stream, and VBI data is also pending, then append the
VBI DMA to the MPEG DMA and transfer both sets of data at once.
@@ -386,43 +396,39 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
sure we only use the MPEG DMA to transfer the VBI DMA if both are in
use. This way no conflicts occur. */
clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
- if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->SG_length &&
- s->SG_length + s_vbi->SG_length <= s->buffers) {
+ if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size &&
+ s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) {
ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused);
if (ivtv_use_dma(s_vbi))
- s_vbi->SGarray[s_vbi->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s_vbi->SGarray[s->SG_length - 1].size) + 256);
- for (i = 0; i < s_vbi->SG_length; i++) {
- s->SGarray[s->SG_length++] = s_vbi->SGarray[i];
+ s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256;
+ for (i = 0; i < s_vbi->sg_pending_size; i++) {
+ s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i];
}
- itv->vbi.dma_offset = s_vbi->dma_offset;
- s_vbi->SG_length = 0;
+ s_vbi->dma_offset = s_vbi->pending_offset;
+ s_vbi->sg_pending_size = 0;
+ s_vbi->dma_xfer_cnt++;
set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name);
}
- /* Mark last buffer size for Interrupt flag */
- s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
-
- if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
- set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
- else
- clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+ s->dma_xfer_cnt++;
+ memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size);
+ s->sg_processing_size = s->sg_pending_size;
+ s->sg_pending_size = 0;
+ s->sg_processed = 0;
+ s->dma_offset = s->pending_offset;
+ s->dma_backup = s->pending_backup;
+ s->dma_pts = s->pending_pts;
if (ivtv_use_pio(s)) {
- for (i = 0; i < s->SG_length; i++) {
- s->PIOarray[i].src = le32_to_cpu(s->SGarray[i].src);
- s->PIOarray[i].size = le32_to_cpu(s->SGarray[i].size);
- }
set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags);
set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
set_bit(IVTV_F_I_PIO, &itv->i_flags);
itv->cur_pio_stream = s->type;
}
else {
- /* Sync Hardware SG List of buffers */
- ivtv_stream_sync_for_device(s);
- write_reg(s->SG_handle, IVTV_REG_ENCDMAADDR);
- write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
+ itv->dma_retries = 0;
+ ivtv_dma_enc_start_xfer(s);
set_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = s->type;
itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
@@ -436,10 +442,15 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s)
if (s->q_predma.bytesused)
ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
+ s->dma_xfer_cnt++;
+ memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size);
+ s->sg_processing_size = s->sg_pending_size;
+ s->sg_pending_size = 0;
+ s->sg_processed = 0;
+
IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name);
- /* put SG Handle into register 0x0c */
- write_reg(s->SG_handle, IVTV_REG_DECDMAADDR);
- write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
+ itv->dma_retries = 0;
+ ivtv_dma_dec_start_xfer(s);
set_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = s->type;
itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
@@ -450,27 +461,44 @@ static void ivtv_irq_dma_read(struct ivtv *itv)
{
struct ivtv_stream *s = NULL;
struct ivtv_buffer *buf;
- int hw_stream_type;
+ int hw_stream_type = 0;
IVTV_DEBUG_HI_IRQ("DEC DMA READ\n");
- del_timer(&itv->dma_timer);
- if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
- IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS));
- write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+ if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0) {
+ del_timer(&itv->dma_timer);
+ return;
}
+
if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
- if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
- s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
- hw_stream_type = 2;
+ s = &itv->streams[itv->cur_dma_stream];
+ ivtv_stream_sync_for_cpu(s);
+
+ if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
+ IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n",
+ read_reg(IVTV_REG_DMASTATUS),
+ s->sg_processed, s->sg_processing_size, itv->dma_retries);
+ write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+ if (itv->dma_retries == 3) {
+ /* Too many retries, give up on this frame */
+ itv->dma_retries = 0;
+ s->sg_processed = s->sg_processing_size;
+ }
+ else {
+ /* Retry, starting with the first xfer segment.
+ Just retrying the current segment is not sufficient. */
+ s->sg_processed = 0;
+ itv->dma_retries++;
+ }
}
- else {
- s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
- hw_stream_type = 0;
+ if (s->sg_processed < s->sg_processing_size) {
+ /* DMA next buffer */
+ ivtv_dma_dec_start_xfer(s);
+ return;
}
+ if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
+ hw_stream_type = 2;
IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
- ivtv_stream_sync_for_cpu(s);
-
/* For some reason must kick the firmware, like PIO mode,
I think this tells the firmware we are done and the size
of the xfer so it can calculate what we need next.
@@ -487,6 +515,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv)
}
wake_up(&s->waitq);
}
+ del_timer(&itv->dma_timer);
clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
clear_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = -1;
@@ -498,33 +527,46 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv)
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv_stream *s;
- del_timer(&itv->dma_timer);
ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
- IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]);
- if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags))
- data[1] = 3;
- else if (data[1] > 2)
+ IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream);
+ if (itv->cur_dma_stream < 0) {
+ del_timer(&itv->dma_timer);
return;
- s = &itv->streams[ivtv_stream_map[data[1]]];
+ }
+ s = &itv->streams[itv->cur_dma_stream];
+ ivtv_stream_sync_for_cpu(s);
+
if (data[0] & 0x18) {
- IVTV_DEBUG_WARN("ENC DMA ERROR %x\n", data[0]);
+ IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0],
+ s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries);
write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
- ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[1]);
+ if (itv->dma_retries == 3) {
+ /* Too many retries, give up on this frame */
+ itv->dma_retries = 0;
+ s->sg_processed = s->sg_processing_size;
+ }
+ else {
+ /* Retry, starting with the first xfer segment.
+ Just retrying the current segment is not sufficient. */
+ s->sg_processed = 0;
+ itv->dma_retries++;
+ }
+ }
+ if (s->sg_processed < s->sg_processing_size) {
+ /* DMA next buffer */
+ ivtv_dma_enc_start_xfer(s);
+ return;
}
- s->SG_length = 0;
+ del_timer(&itv->dma_timer);
clear_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = -1;
dma_post(s);
- ivtv_stream_sync_for_cpu(s);
if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
- u32 tmp;
-
s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
- tmp = s->dma_offset;
- s->dma_offset = itv->vbi.dma_offset;
dma_post(s);
- s->dma_offset = tmp;
}
+ s->sg_processing_size = 0;
+ s->sg_processed = 0;
wake_up(&itv->dma_waitq);
}
@@ -538,8 +580,6 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv)
}
s = &itv->streams[itv->cur_pio_stream];
IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name);
- s->SG_length = 0;
- clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
clear_bit(IVTV_F_I_PIO, &itv->i_flags);
itv->cur_pio_stream = -1;
dma_post(s);
@@ -551,13 +591,8 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv)
ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2);
clear_bit(IVTV_F_I_PIO, &itv->i_flags);
if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
- u32 tmp;
-
s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
- tmp = s->dma_offset;
- s->dma_offset = itv->vbi.dma_offset;
dma_post(s);
- s->dma_offset = tmp;
}
wake_up(&itv->dma_waitq);
}
@@ -569,19 +604,23 @@ static void ivtv_irq_dma_err(struct ivtv *itv)
del_timer(&itv->dma_timer);
ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1],
- read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
+ read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
+ write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) &&
itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) {
struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream];
/* retry */
- write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
if (s->type >= IVTV_DEC_STREAM_TYPE_MPG)
ivtv_dma_dec_start(s);
else
ivtv_dma_enc_start(s);
return;
}
+ if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
+ ivtv_udma_start(itv);
+ return;
+ }
clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
clear_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = -1;
@@ -625,14 +664,12 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
DMA the data. Since at most four VBI DMA buffers are available,
we just drop the old requests when there are already three
requests queued. */
- if (s->SG_length > 2) {
- struct list_head *p;
- list_for_each(p, &s->q_predma.list) {
- struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
+ if (s->sg_pending_size > 2) {
+ struct ivtv_buffer *buf;
+ list_for_each_entry(buf, &s->q_predma.list, list)
ivtv_buf_sync_for_cpu(s, buf);
- }
ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0);
- s->SG_length = 0;
+ s->sg_pending_size = 0;
}
/* if we can append the data, and the MPEG stream isn't capturing,
then start a DMA request for just the VBI data. */
@@ -698,23 +735,27 @@ static void ivtv_irq_vsync(struct ivtv *itv)
if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
- if (((frame ^ itv->yuv_info.lace_sync_field) == 0 && ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.lace_sync_field)) ||
- (frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) {
+ if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 &&
+ ((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) ||
+ (frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) {
int next_dma_frame = last_dma_frame;
- if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
- write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
- write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
- write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
- write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
- next_dma_frame = (next_dma_frame + 1) & 0x3;
- atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
+ if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) {
+ if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
+ write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
+ write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
+ write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
+ write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
+ next_dma_frame = (next_dma_frame + 1) & 0x3;
+ atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
+ itv->yuv_info.fields_lapsed = -1;
+ }
}
}
- if (frame != (itv->lastVsyncFrame & 1)) {
+ if (frame != (itv->last_vsync_field & 1)) {
struct ivtv_stream *s = ivtv_get_output_stream(itv);
- itv->lastVsyncFrame += 1;
+ itv->last_vsync_field += 1;
if (frame == 0) {
clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags);
@@ -731,7 +772,10 @@ static void ivtv_irq_vsync(struct ivtv *itv)
wake_up(&s->waitq);
/* Send VBI to saa7127 */
- if (frame) {
+ if (frame && (itv->output_mode == OUT_PASSTHROUGH ||
+ test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) ||
+ test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) ||
+ test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) {
set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags);
set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
}
@@ -749,10 +793,12 @@ static void ivtv_irq_vsync(struct ivtv *itv)
set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
}
}
+
+ itv->yuv_info.fields_lapsed ++;
}
}
-#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ)
+#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_VBI_RE_INSERT)
irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
{
@@ -777,7 +823,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
*/
if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
/* vsync is enabled, see if we're in a new field */
- if ((itv->lastVsyncFrame & 1) != (read_reg(0x28c0) & 1)) {
+ if ((itv->last_vsync_field & 1) != (read_reg(0x28c0) & 1)) {
/* New field, looks like we missed it */
IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16);
vsync_force = 1;
@@ -831,7 +877,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
if (combo & IVTV_IRQ_ENC_EOS) {
IVTV_DEBUG_IRQ("ENC EOS\n");
set_bit(IVTV_F_I_EOS, &itv->i_flags);
- wake_up(&itv->cap_w);
+ wake_up(&itv->eos_waitq);
}
if (combo & IVTV_IRQ_DEC_DATA_REQ) {
@@ -853,8 +899,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
}
if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
+ itv->irq_rr_idx++;
for (i = 0; i < IVTV_MAX_STREAMS; i++) {
- int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS;
+ int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
struct ivtv_stream *s = &itv->streams[idx];
if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags))
@@ -871,8 +918,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
}
if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) {
+ itv->irq_rr_idx++;
for (i = 0; i < IVTV_MAX_STREAMS; i++) {
- int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS;
+ int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
struct ivtv_stream *s = &itv->streams[idx];
if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags))
@@ -883,8 +931,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
}
}
- if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags))
+ if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) {
queue_work(itv->irq_work_queues, &itv->irq_work_queue);
+ }
spin_unlock(&itv->dma_reg_lock);
diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h
index a43348a3030..f879a5822e7 100644
--- a/drivers/media/video/ivtv/ivtv-irq.h
+++ b/drivers/media/video/ivtv/ivtv-irq.h
@@ -19,8 +19,35 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_IRQ_H
+#define IVTV_IRQ_H
+
+#define IVTV_IRQ_ENC_START_CAP (0x1 << 31)
+#define IVTV_IRQ_ENC_EOS (0x1 << 30)
+#define IVTV_IRQ_ENC_VBI_CAP (0x1 << 29)
+#define IVTV_IRQ_ENC_VIM_RST (0x1 << 28)
+#define IVTV_IRQ_ENC_DMA_COMPLETE (0x1 << 27)
+#define IVTV_IRQ_ENC_PIO_COMPLETE (0x1 << 25)
+#define IVTV_IRQ_DEC_AUD_MODE_CHG (0x1 << 24)
+#define IVTV_IRQ_DEC_DATA_REQ (0x1 << 22)
+#define IVTV_IRQ_DEC_DMA_COMPLETE (0x1 << 20)
+#define IVTV_IRQ_DEC_VBI_RE_INSERT (0x1 << 19)
+#define IVTV_IRQ_DMA_ERR (0x1 << 18)
+#define IVTV_IRQ_DMA_WRITE (0x1 << 17)
+#define IVTV_IRQ_DMA_READ (0x1 << 16)
+#define IVTV_IRQ_DEC_VSYNC (0x1 << 10)
+
+/* IRQ Masks */
+#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\
+ IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE)
+
+#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS)
+#define IVTV_IRQ_MASK_DECODE (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG)
+
irqreturn_t ivtv_irq_handler(int irq, void *dev_id);
void ivtv_irq_work_handler(struct work_struct *work);
void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock);
void ivtv_unfinished_dma(unsigned long arg);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index 5e3b679202a..b05436da713 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -225,15 +225,15 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
}
if (args < 0 || args > CX2341X_MBOX_MAX_DATA ||
cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) {
- IVTV_ERR("Invalid API call: cmd = 0x%02x, args = %d\n", cmd, args);
+ IVTV_ERR("Invalid MB call: cmd = 0x%02x, args = %d\n", cmd, args);
return -EINVAL;
}
if (api_info[cmd].flags & API_HIGH_VOL) {
- IVTV_DEBUG_HI_API("API Call: %s\n", api_info[cmd].name);
+ IVTV_DEBUG_HI_MB("MB Call: %s\n", api_info[cmd].name);
}
else {
- IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+ IVTV_DEBUG_MB("MB Call: %s\n", api_info[cmd].name);
}
/* clear possibly uninitialized part of data array */
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h
index 79b8aec1437..71a54eef8fc 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.h
+++ b/drivers/media/video/ivtv/ivtv-mailbox.h
@@ -18,8 +18,16 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_MAILBOX_H
+#define IVTV_MAILBOX_H
+
+#define IVTV_MBOX_DMA_END 8
+#define IVTV_MBOX_DMA 9
+
void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]);
int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c
index a04f9387f63..39a21671324 100644
--- a/drivers/media/video/ivtv/ivtv-queue.c
+++ b/drivers/media/video/ivtv/ivtv-queue.c
@@ -20,9 +20,7 @@
*/
#include "ivtv-driver.h"
-#include "ivtv-streams.h"
#include "ivtv-queue.h"
-#include "ivtv-mailbox.h"
int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes)
{
@@ -60,6 +58,7 @@ void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_qu
buf->bytesused = 0;
buf->readpos = 0;
buf->b_flags = 0;
+ buf->dma_xfer_cnt = 0;
}
spin_lock_irqsave(&s->qlock, flags);
list_add_tail(&buf->list, &q->list);
@@ -87,7 +86,7 @@ struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q)
}
static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
- struct ivtv_queue *to, int clear, int full)
+ struct ivtv_queue *to, int clear)
{
struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list);
@@ -97,13 +96,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
from->bytesused -= buf->bytesused - buf->readpos;
/* special handling for q_free */
if (clear)
- buf->bytesused = buf->readpos = buf->b_flags = 0;
- else if (full) {
- /* special handling for stolen buffers, assume
- all bytes are used. */
- buf->bytesused = s->buf_size;
- buf->readpos = buf->b_flags = 0;
- }
+ buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
to->buffers++;
to->length += s->buf_size;
to->bytesused += buf->bytesused - buf->readpos;
@@ -112,7 +105,7 @@ static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
If 'steal' != NULL, then buffers may also taken from that queue if
- needed.
+ needed, but only if 'from' is the free queue.
The buffer is automatically cleared if it goes to the free queue. It is
also cleared if buffers need to be taken from the 'steal' queue and
@@ -133,7 +126,7 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_
int rc = 0;
int from_free = from == &s->q_free;
int to_free = to == &s->q_free;
- int bytes_available;
+ int bytes_available, bytes_steal;
spin_lock_irqsave(&s->qlock, flags);
if (needed_bytes == 0) {
@@ -142,32 +135,47 @@ int ivtv_queue_move(struct ivtv_stream *s, struct ivtv_queue *from, struct ivtv_
}
bytes_available = from_free ? from->length : from->bytesused;
- bytes_available += steal ? steal->length : 0;
+ bytes_steal = (from_free && steal) ? steal->length : 0;
- if (bytes_available < needed_bytes) {
+ if (bytes_available + bytes_steal < needed_bytes) {
spin_unlock_irqrestore(&s->qlock, flags);
return -ENOMEM;
}
+ while (bytes_available < needed_bytes) {
+ struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
+ u16 dma_xfer_cnt = buf->dma_xfer_cnt;
+
+ /* move buffers from the tail of the 'steal' queue to the tail of the
+ 'from' queue. Always copy all the buffers with the same dma_xfer_cnt
+ value, this ensures that you do not end up with partial frame data
+ if one frame is stored in multiple buffers. */
+ while (dma_xfer_cnt == buf->dma_xfer_cnt) {
+ list_move_tail(steal->list.prev, &from->list);
+ rc++;
+ steal->buffers--;
+ steal->length -= s->buf_size;
+ steal->bytesused -= buf->bytesused - buf->readpos;
+ buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
+ from->buffers++;
+ from->length += s->buf_size;
+ bytes_available += s->buf_size;
+ if (list_empty(&steal->list))
+ break;
+ buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
+ }
+ }
if (from_free) {
u32 old_length = to->length;
while (to->length - old_length < needed_bytes) {
- if (list_empty(&from->list))
- from = steal;
- if (from == steal)
- rc++; /* keep track of 'stolen' buffers */
- ivtv_queue_move_buf(s, from, to, 1, 0);
+ ivtv_queue_move_buf(s, from, to, 1);
}
}
else {
u32 old_bytesused = to->bytesused;
while (to->bytesused - old_bytesused < needed_bytes) {
- if (list_empty(&from->list))
- from = steal;
- if (from == steal)
- rc++; /* keep track of 'stolen' buffers */
- ivtv_queue_move_buf(s, from, to, to_free, rc);
+ ivtv_queue_move_buf(s, from, to, to_free);
}
}
spin_unlock_irqrestore(&s->qlock, flags);
@@ -185,7 +193,7 @@ void ivtv_flush_queues(struct ivtv_stream *s)
int ivtv_stream_alloc(struct ivtv_stream *s)
{
struct ivtv *itv = s->itv;
- int SGsize = sizeof(struct ivtv_SG_element) * s->buffers;
+ int SGsize = sizeof(struct ivtv_sg_element) * s->buffers;
int i;
if (s->buffers == 0)
@@ -195,27 +203,33 @@ int ivtv_stream_alloc(struct ivtv_stream *s)
s->dma != PCI_DMA_NONE ? "DMA " : "",
s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024);
- if (ivtv_might_use_pio(s)) {
- s->PIOarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
- if (s->PIOarray == NULL) {
- IVTV_ERR("Could not allocate PIOarray for %s stream\n", s->name);
- return -ENOMEM;
- }
+ s->sg_pending = kzalloc(SGsize, GFP_KERNEL);
+ if (s->sg_pending == NULL) {
+ IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name);
+ return -ENOMEM;
}
+ s->sg_pending_size = 0;
- /* Allocate DMA SG Arrays */
- s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
- if (s->SGarray == NULL) {
- IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name);
- if (ivtv_might_use_pio(s)) {
- kfree(s->PIOarray);
- s->PIOarray = NULL;
- }
+ s->sg_processing = kzalloc(SGsize, GFP_KERNEL);
+ if (s->sg_processing == NULL) {
+ IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name);
+ kfree(s->sg_pending);
+ s->sg_pending = NULL;
+ return -ENOMEM;
+ }
+ s->sg_processing_size = 0;
+
+ s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL);
+ if (s->sg_dma == NULL) {
+ IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name);
+ kfree(s->sg_pending);
+ s->sg_pending = NULL;
+ kfree(s->sg_processing);
+ s->sg_processing = NULL;
return -ENOMEM;
}
- s->SG_length = 0;
if (ivtv_might_use_dma(s)) {
- s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma);
+ s->sg_handle = pci_map_single(itv->dev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma);
ivtv_stream_sync_for_cpu(s);
}
@@ -262,16 +276,19 @@ void ivtv_stream_free(struct ivtv_stream *s)
}
/* Free SG Array/Lists */
- if (s->SGarray != NULL) {
- if (s->SG_handle != IVTV_DMA_UNMAPPED) {
- pci_unmap_single(s->itv->dev, s->SG_handle,
- sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
- s->SG_handle = IVTV_DMA_UNMAPPED;
+ if (s->sg_dma != NULL) {
+ if (s->sg_handle != IVTV_DMA_UNMAPPED) {
+ pci_unmap_single(s->itv->dev, s->sg_handle,
+ sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
+ s->sg_handle = IVTV_DMA_UNMAPPED;
}
- kfree(s->SGarray);
- kfree(s->PIOarray);
- s->PIOarray = NULL;
- s->SGarray = NULL;
- s->SG_length = 0;
+ kfree(s->sg_pending);
+ kfree(s->sg_processing);
+ kfree(s->sg_dma);
+ s->sg_pending = NULL;
+ s->sg_processing = NULL;
+ s->sg_dma = NULL;
+ s->sg_pending_size = 0;
+ s->sg_processing_size = 0;
}
}
diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h
index 2ed8d548255..7cfc0c9ab05 100644
--- a/drivers/media/video/ivtv/ivtv-queue.h
+++ b/drivers/media/video/ivtv/ivtv-queue.h
@@ -19,6 +19,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_QUEUE_H
+#define IVTV_QUEUE_H
+
#define IVTV_DMA_UNMAPPED ((u32) -1)
#define SLICED_VBI_PIO 1
@@ -79,13 +82,15 @@ void ivtv_stream_free(struct ivtv_stream *s);
static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s)
{
if (ivtv_use_dma(s))
- pci_dma_sync_single_for_cpu(s->itv->dev, s->SG_handle,
- sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
+ pci_dma_sync_single_for_cpu(s->itv->dev, s->sg_handle,
+ sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
}
static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s)
{
if (ivtv_use_dma(s))
- pci_dma_sync_single_for_device(s->itv->dev, s->SG_handle,
- sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
+ pci_dma_sync_single_for_device(s->itv->dev, s->sg_handle,
+ sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
}
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-video.c b/drivers/media/video/ivtv/ivtv-routing.c
index 5858b197d51..398bd33033e 100644
--- a/drivers/media/video/ivtv/ivtv-video.c
+++ b/drivers/media/video/ivtv/ivtv-routing.c
@@ -1,6 +1,7 @@
/*
- saa7127 interface functions
- Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl>
+ Audio/video-routing-related ivtv functions.
+ Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
+ Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,73 +19,46 @@
*/
#include "ivtv-driver.h"
-#include "ivtv-video.h"
#include "ivtv-i2c.h"
-#include "ivtv-gpio.h"
#include "ivtv-cards.h"
+#include "ivtv-gpio.h"
+#include "ivtv-routing.h"
+
+#include <media/msp3400.h>
#include <media/upd64031a.h>
#include <media/upd64083.h>
-void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3,
- u8 vps4, u8 vps5)
+/* Selects the audio input and output according to the current
+ settings. */
+void ivtv_audio_set_io(struct ivtv *itv)
{
- struct v4l2_sliced_vbi_data data;
-
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return;
- data.id = V4L2_SLICED_VPS;
- data.field = 0;
- data.line = enabled ? 16 : 0;
- data.data[4] = vps1;
- data.data[10] = vps2;
- data.data[11] = vps3;
- data.data[12] = vps4;
- data.data[13] = vps5;
- ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
-}
+ struct v4l2_routing route;
+ u32 audio_input;
+ int mux_input;
-void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4)
-{
- struct v4l2_sliced_vbi_data data;
-
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return;
- data.id = V4L2_SLICED_CAPTION_525;
- data.field = 0;
- data.line = (mode & 1) ? 21 : 0;
- data.data[0] = cc1;
- data.data[1] = cc2;
- ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
- data.field = 1;
- data.line = (mode & 2) ? 21 : 0;
- data.data[0] = cc3;
- data.data[1] = cc4;
- ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
-}
+ /* Determine which input to use */
+ if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+ audio_input = itv->card->radio_input.audio_input;
+ mux_input = itv->card->radio_input.muxer_input;
+ } else {
+ audio_input = itv->card->audio_inputs[itv->audio_input].audio_input;
+ mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input;
+ }
-void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
-{
- struct v4l2_sliced_vbi_data data;
-
- if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
- return;
- /* When using a 50 Hz system, always turn on the
- wide screen signal with 4x3 ratio as the default.
- Turning this signal on and off can confuse certain
- TVs. As far as I can tell there is no reason not to
- transmit this signal. */
- if ((itv->std & V4L2_STD_625_50) && !enabled) {
- enabled = 1;
- mode = 0x08; /* 4x3 full format */
+ /* handle muxer chips */
+ route.input = mux_input;
+ route.output = 0;
+ ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+
+ route.input = audio_input;
+ if (itv->card->hw_audio & IVTV_HW_MSP34XX) {
+ route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
}
- data.id = V4L2_SLICED_WSS_625;
- data.field = 0;
- data.line = enabled ? 23 : 0;
- data.data[0] = mode & 0xff;
- data.data[1] = (mode >> 8) & 0xff;
- ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+ ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
}
+/* Selects the video input and output according to the current
+ settings. */
void ivtv_video_set_io(struct ivtv *itv)
{
struct v4l2_routing route;
diff --git a/drivers/media/video/ivtv/ivtv-audio.h b/drivers/media/video/ivtv/ivtv-routing.h
index 9c42846d812..c72a9731ca0 100644
--- a/drivers/media/video/ivtv/ivtv-audio.h
+++ b/drivers/media/video/ivtv/ivtv-routing.h
@@ -1,5 +1,5 @@
/*
- Audio-related ivtv functions.
+ Audio/video-routing-related ivtv functions.
Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl>
@@ -18,6 +18,10 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-int ivtv_audio_set_io(struct ivtv *itv);
-void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route);
-void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq);
+#ifndef IVTV_ROUTING_H
+#define IVTV_ROUTING_H
+
+void ivtv_audio_set_io(struct ivtv *itv);
+void ivtv_video_set_io(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 51df3f85503..aa03e61ef31 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -35,16 +35,13 @@
#include "ivtv-driver.h"
#include "ivtv-fileops.h"
-#include "ivtv-i2c.h"
#include "ivtv-queue.h"
#include "ivtv-mailbox.h"
-#include "ivtv-audio.h"
-#include "ivtv-video.h"
-#include "ivtv-vbi.h"
#include "ivtv-ioctl.h"
#include "ivtv-irq.h"
-#include "ivtv-streams.h"
+#include "ivtv-yuv.h"
#include "ivtv-cards.h"
+#include "ivtv-streams.h"
static struct file_operations ivtv_v4l2_enc_fops = {
.owner = THIS_MODULE,
@@ -66,6 +63,13 @@ static struct file_operations ivtv_v4l2_dec_fops = {
.poll = ivtv_v4l2_dec_poll,
};
+#define IVTV_V4L2_DEC_MPG_OFFSET 16 /* offset from 0 to register decoder mpg v4l2 minors on */
+#define IVTV_V4L2_ENC_PCM_OFFSET 24 /* offset from 0 to register pcm v4l2 minors on */
+#define IVTV_V4L2_ENC_YUV_OFFSET 32 /* offset from 0 to register yuv v4l2 minors on */
+#define IVTV_V4L2_DEC_YUV_OFFSET 48 /* offset from 0 to register decoder yuv v4l2 minors on */
+#define IVTV_V4L2_DEC_VBI_OFFSET 8 /* offset from 0 to register decoder vbi input v4l2 minors on */
+#define IVTV_V4L2_DEC_VOUT_OFFSET 16 /* offset from 0 to register vbi output v4l2 minors on */
+
static struct {
const char *name;
int vfl_type;
@@ -75,7 +79,7 @@ static struct {
struct file_operations *fops;
} ivtv_stream_info[] = {
{ /* IVTV_ENC_STREAM_TYPE_MPG */
- "encoder MPEG",
+ "encoder MPG",
VFL_TYPE_GRABBER, 0,
PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,
&ivtv_v4l2_enc_fops
@@ -93,7 +97,7 @@ static struct {
&ivtv_v4l2_enc_fops
},
{ /* IVTV_ENC_STREAM_TYPE_PCM */
- "encoder PCM audio",
+ "encoder PCM",
VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET,
PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE,
&ivtv_v4l2_enc_fops
@@ -105,7 +109,7 @@ static struct {
&ivtv_v4l2_enc_fops
},
{ /* IVTV_DEC_STREAM_TYPE_MPG */
- "decoder MPEG",
+ "decoder MPG",
VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET,
PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,
&ivtv_v4l2_dec_fops
@@ -150,11 +154,11 @@ static void ivtv_stream_init(struct ivtv *itv, int type)
s->dma = ivtv_stream_info[type].dma;
s->buf_size = itv->stream_buf_size[type];
if (s->buf_size)
- s->buffers = itv->options.megabytes[type] * 1024 * 1024 / s->buf_size;
+ s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size;
spin_lock_init(&s->qlock);
init_waitqueue_head(&s->waitq);
s->id = -1;
- s->SG_handle = IVTV_DMA_UNMAPPED;
+ s->sg_handle = IVTV_DMA_UNMAPPED;
ivtv_queue_init(&s->q_free);
ivtv_queue_init(&s->q_full);
ivtv_queue_init(&s->q_dma);
@@ -162,10 +166,9 @@ static void ivtv_stream_init(struct ivtv *itv, int type)
ivtv_queue_init(&s->q_io);
}
-static int ivtv_reg_dev(struct ivtv *itv, int type)
+static int ivtv_prep_dev(struct ivtv *itv, int type)
{
struct ivtv_stream *s = &itv->streams[type];
- int vfl_type = ivtv_stream_info[type].vfl_type;
int minor_offset = ivtv_stream_info[type].minor_offset;
int minor;
@@ -183,16 +186,13 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return 0;
- if (minor_offset >= 0)
- /* card number + user defined offset + device offset */
- minor = itv->num + ivtv_first_minor + minor_offset;
- else
- minor = -1;
+ /* card number + user defined offset + device offset */
+ minor = itv->num + ivtv_first_minor + minor_offset;
/* User explicitly selected 0 buffers for these streams, so don't
create them. */
- if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE &&
- itv->options.megabytes[type] == 0) {
+ if (ivtv_stream_info[type].dma != PCI_DMA_NONE &&
+ itv->options.kilobytes[type] == 0) {
IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name);
return 0;
}
@@ -219,37 +219,69 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
s->v4l2dev->fops = ivtv_stream_info[type].fops;
s->v4l2dev->release = video_device_release;
- if (minor >= 0) {
- /* Register device. First try the desired minor, then any free one. */
- if (video_register_device(s->v4l2dev, vfl_type, minor) &&
- video_register_device(s->v4l2dev, vfl_type, -1)) {
- IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n",
- s->name, minor);
- video_device_release(s->v4l2dev);
- s->v4l2dev = NULL;
- return -ENOMEM;
- }
+ return 0;
+}
+
+/* Initialize v4l2 variables and prepare v4l2 devices */
+int ivtv_streams_setup(struct ivtv *itv)
+{
+ int type;
+
+ /* Setup V4L2 Devices */
+ for (type = 0; type < IVTV_MAX_STREAMS; type++) {
+ /* Prepare device */
+ if (ivtv_prep_dev(itv, type))
+ break;
+
+ if (itv->streams[type].v4l2dev == NULL)
+ continue;
+
+ /* Allocate Stream */
+ if (ivtv_stream_alloc(&itv->streams[type]))
+ break;
}
- else {
- /* Don't register a 'hidden' stream (OSD) */
- IVTV_INFO("Created framebuffer stream for %s\n", s->name);
+ if (type == IVTV_MAX_STREAMS)
return 0;
+
+ /* One or more streams could not be initialized. Clean 'em all up. */
+ ivtv_streams_cleanup(itv);
+ return -ENOMEM;
+}
+
+static int ivtv_reg_dev(struct ivtv *itv, int type)
+{
+ struct ivtv_stream *s = &itv->streams[type];
+ int vfl_type = ivtv_stream_info[type].vfl_type;
+ int minor;
+
+ if (s->v4l2dev == NULL)
+ return 0;
+
+ minor = s->v4l2dev->minor;
+ /* Register device. First try the desired minor, then any free one. */
+ if (video_register_device(s->v4l2dev, vfl_type, minor) &&
+ video_register_device(s->v4l2dev, vfl_type, -1)) {
+ IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n",
+ s->name, minor);
+ video_device_release(s->v4l2dev);
+ s->v4l2dev = NULL;
+ return -ENOMEM;
}
switch (vfl_type) {
case VFL_TYPE_GRABBER:
- IVTV_INFO("Registered device video%d for %s (%d MB)\n",
- s->v4l2dev->minor, s->name, itv->options.megabytes[type]);
+ IVTV_INFO("Registered device video%d for %s (%d kB)\n",
+ s->v4l2dev->minor, s->name, itv->options.kilobytes[type]);
break;
case VFL_TYPE_RADIO:
IVTV_INFO("Registered device radio%d for %s\n",
s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name);
break;
case VFL_TYPE_VBI:
- if (itv->options.megabytes[type])
- IVTV_INFO("Registered device vbi%d for %s (%d MB)\n",
+ if (itv->options.kilobytes[type])
+ IVTV_INFO("Registered device vbi%d for %s (%d kB)\n",
s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN,
- s->name, itv->options.megabytes[type]);
+ s->name, itv->options.kilobytes[type]);
else
IVTV_INFO("Registered device vbi%d for %s\n",
s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name);
@@ -258,27 +290,18 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
return 0;
}
-/* Initialize v4l2 variables and register v4l2 devices */
-int ivtv_streams_setup(struct ivtv *itv)
+/* Register v4l2 devices */
+int ivtv_streams_register(struct ivtv *itv)
{
int type;
+ int err = 0;
- /* Setup V4L2 Devices */
- for (type = 0; type < IVTV_MAX_STREAMS; type++) {
- /* Register Device */
- if (ivtv_reg_dev(itv, type))
- break;
+ /* Register V4L2 devices */
+ for (type = 0; type < IVTV_MAX_STREAMS; type++)
+ err |= ivtv_reg_dev(itv, type);
- if (itv->streams[type].v4l2dev == NULL)
- continue;
-
- /* Allocate Stream */
- if (ivtv_stream_alloc(&itv->streams[type]))
- break;
- }
- if (type == IVTV_MAX_STREAMS) {
+ if (err == 0)
return 0;
- }
/* One or more streams could not be initialized. Clean 'em all up. */
ivtv_streams_cleanup(itv);
@@ -299,11 +322,8 @@ void ivtv_streams_cleanup(struct ivtv *itv)
continue;
ivtv_stream_free(&itv->streams[type]);
- /* Free Device */
- if (vdev->minor == -1) /* 'Hidden' never registered stream (OSD) */
- video_device_release(vdev);
- else /* All others, just unregister. */
- video_unregister_device(vdev);
+ /* Unregister device */
+ video_unregister_device(vdev);
}
}
@@ -314,28 +334,9 @@ static void ivtv_vbi_setup(struct ivtv *itv)
int lines;
int i;
- /* If Embed then streamtype must be Program */
- /* TODO: should we really do this? */
- if (0 && !raw && itv->vbi.insert_mpeg) {
- itv->params.stream_type = 0;
-
- /* assign stream type */
- ivtv_vapi(itv, CX2341X_ENC_SET_STREAM_TYPE, 1, itv->params.stream_type);
- }
-
/* Reset VBI */
ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0);
- if (itv->is_60hz) {
- itv->vbi.count = 12;
- itv->vbi.start[0] = 10;
- itv->vbi.start[1] = 273;
- } else { /* PAL/SECAM */
- itv->vbi.count = 18;
- itv->vbi.start[0] = 6;
- itv->vbi.start[1] = 318;
- }
-
/* setup VBI registers */
itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
@@ -409,8 +410,8 @@ static void ivtv_vbi_setup(struct ivtv *itv)
if (!itv->vbi.fpi)
itv->vbi.fpi = 1;
- IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d lines 0x%08x\n",
- itv->vbi.enc_start, data[1], itv->vbi.fpi, itv->digitizer);
+ IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n",
+ itv->vbi.enc_start, data[1], itv->vbi.fpi);
/* select VBI lines.
Note that the sliced argument seems to have no effect. */
@@ -440,15 +441,13 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
{
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv *itv = s->itv;
+ struct cx2341x_mpeg_params *p = &itv->params;
int captype = 0, subtype = 0;
int enable_passthrough = 0;
if (s->v4l2dev == NULL)
return -EINVAL;
- /* Big serialization lock to ensure no two streams are started
- simultaneously: that can give all sorts of weird results. */
- mutex_lock(&itv->serialize_lock);
IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
switch (s->type) {
@@ -463,7 +462,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
}
itv->mpg_data_received = itv->vbi_data_inserted = 0;
itv->dualwatch_jiffies = jiffies;
- itv->dualwatch_stereo_mode = itv->params.audio_properties & 0x0300;
+ itv->dualwatch_stereo_mode = p->audio_properties & 0x0300;
itv->search_pack_header = 0;
break;
@@ -490,19 +489,17 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
0, sizeof(itv->vbi.sliced_mpeg_size));
break;
default:
- mutex_unlock(&itv->serialize_lock);
return -EINVAL;
}
s->subtype = subtype;
s->buffers_stolen = 0;
- /* mute/unmute video */
- ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1, test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? 1 : 0);
-
/* Clear Streamoff flags in case left from last capture */
clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
if (atomic_read(&itv->capturing) == 0) {
+ int digitizer;
+
/* Always use frame based mode. Experiments have demonstrated that byte
stream based mode results in dropped frames and corruption. Not often,
but occasionally. Many thanks go to Leonard Orb who spent a lot of
@@ -528,7 +525,14 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, itv->digitizer, itv->digitizer);
+ if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X))
+ digitizer = 0xF1;
+ else if (itv->card->hw_all & IVTV_HW_SAA7114)
+ digitizer = 0xEF;
+ else /* cx25840 */
+ digitizer = 0x140;
+
+ ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, digitizer, digitizer);
/* Setup VBI */
if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) {
@@ -546,7 +550,12 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
itv->pgm_info_offset, itv->pgm_info_num);
/* Setup API for Stream */
- cx2341x_update(itv, ivtv_api_func, NULL, &itv->params);
+ cx2341x_update(itv, ivtv_api_func, NULL, p);
+
+ /* mute if capturing radio */
+ if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags))
+ ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,
+ 1 | (p->video_mute_yuv << 8));
}
/* Vsync Setup */
@@ -563,16 +572,16 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
clear_bit(IVTV_F_I_EOS, &itv->i_flags);
/* Initialize Digitizer for Capture */
+ itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0);
+ ivtv_msleep_timeout(300, 1);
ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-
- ivtv_msleep_timeout(100, 0);
+ itv->video_dec_func(itv, VIDIOC_STREAMON, 0);
}
/* begin_capture */
if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype))
{
IVTV_DEBUG_WARN( "Error starting capture!\n");
- mutex_unlock(&itv->serialize_lock);
return -EINVAL;
}
@@ -588,7 +597,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
/* you're live! sit back and await interrupts :) */
atomic_inc(&itv->capturing);
- mutex_unlock(&itv->serialize_lock);
return 0;
}
@@ -596,6 +604,7 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
{
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv *itv = s->itv;
+ struct cx2341x_mpeg_params *p = &itv->params;
int datatype;
if (s->v4l2dev == NULL)
@@ -634,7 +643,7 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
break;
}
if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype,
- itv->params.width, itv->params.height, itv->params.audio_properties)) {
+ p->width, p->height, p->audio_properties)) {
IVTV_DEBUG_WARN("Couldn't initialize decoder source\n");
}
return 0;
@@ -676,10 +685,10 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
/* Zero out decoder counters */
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[0]);
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[1]);
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[2]);
- writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[3]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[0]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[1]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[2]);
+ writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[3]);
writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]);
writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]);
writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]);
@@ -720,9 +729,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
struct ivtv *itv = s->itv;
DECLARE_WAITQUEUE(wait, current);
int cap_type;
- unsigned long then;
int stopmode;
- u32 data[CX2341X_MBOX_MAX_DATA];
if (s->v4l2dev == NULL)
return -EINVAL;
@@ -764,15 +771,13 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
/* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
- then = jiffies;
-
if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) {
/* only run these if we're shutting down the last cap */
unsigned long duration;
+ unsigned long then = jiffies;
- then = jiffies;
- add_wait_queue(&itv->cap_w, &wait);
+ add_wait_queue(&itv->eos_waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
@@ -798,31 +803,12 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration);
}
set_current_state(TASK_RUNNING);
- remove_wait_queue(&itv->cap_w, &wait);
+ remove_wait_queue(&itv->eos_waitq, &wait);
+ set_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
}
- then = jiffies;
- /* Make sure DMA is complete */
- add_wait_queue(&s->waitq, &wait);
- do {
- /* check if DMA is pending */
- if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */
- (read_reg(IVTV_REG_DMASTATUS) & 0x02)) {
- /* Check for last DMA */
- ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0);
-
- if (data[0] == 1) {
- IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]);
- break;
- }
- } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
- break;
- }
- } while (!ivtv_msleep_timeout(10, 1) &&
- then + msecs_to_jiffies(2000) > jiffies);
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&s->waitq, &wait);
+ /* Handle any pending interrupts */
+ ivtv_msleep_timeout(100, 1);
}
atomic_dec(&itv->capturing);
@@ -830,19 +816,16 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
/* Clear capture and no-read bits */
clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
- /* ensure these global cleanup actions are done only once */
- mutex_lock(&itv->serialize_lock);
-
if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
if (atomic_read(&itv->capturing) > 0) {
- mutex_unlock(&itv->serialize_lock);
return 0;
}
/* Set the following Interrupt mask bits for capture */
ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+ del_timer(&itv->dma_timer);
/* event notification (off) */
if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
@@ -853,7 +836,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
}
wake_up(&s->waitq);
- mutex_unlock(&itv->serialize_lock);
return 0;
}
@@ -900,6 +882,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
+ del_timer(&itv->dma_timer);
clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/video/ivtv/ivtv-streams.h
index 8597b75384a..3d76a415fbd 100644
--- a/drivers/media/video/ivtv/ivtv-streams.h
+++ b/drivers/media/video/ivtv/ivtv-streams.h
@@ -18,7 +18,11 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_STREAMS_H
+#define IVTV_STREAMS_H
+
int ivtv_streams_setup(struct ivtv *itv);
+int ivtv_streams_register(struct ivtv *itv);
void ivtv_streams_cleanup(struct ivtv *itv);
/* Capture related */
@@ -29,3 +33,5 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts);
void ivtv_stop_all_captures(struct ivtv *itv);
int ivtv_passthrough_mode(struct ivtv *itv, int enable);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c
index bd642e1aafc..460db03b0ba 100644
--- a/drivers/media/video/ivtv/ivtv-udma.c
+++ b/drivers/media/video/ivtv/ivtv-udma.c
@@ -21,7 +21,6 @@
*/
#include "ivtv-driver.h"
-#include "ivtv-streams.h"
#include "ivtv-udma.h"
void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size)
@@ -38,19 +37,35 @@ void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long
int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset)
{
int i, offset;
+ unsigned long flags;
+
+ if (map_offset < 0)
+ return map_offset;
offset = dma_page->offset;
/* Fill SG Array with new values */
for (i = 0; i < dma_page->page_count; i++) {
- if (i == dma_page->page_count - 1) {
- dma->SGlist[map_offset].length = dma_page->tail;
+ unsigned int len = (i == dma_page->page_count - 1) ?
+ dma_page->tail : PAGE_SIZE - offset;
+
+ if (PageHighMem(dma->map[map_offset])) {
+ void *src;
+
+ if (dma->bouncemap[map_offset] == NULL)
+ dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL);
+ if (dma->bouncemap[map_offset] == NULL)
+ return -1;
+ local_irq_save(flags);
+ src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset;
+ memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len);
+ kunmap_atomic(src, KM_BOUNCE_READ);
+ local_irq_restore(flags);
+ sg_set_page(&dma->SGlist[map_offset], dma->bouncemap[map_offset], len, offset);
}
else {
- dma->SGlist[map_offset].length = PAGE_SIZE - offset;
+ sg_set_page(&dma->SGlist[map_offset], dma->map[map_offset], len, offset);
}
- dma->SGlist[map_offset].offset = offset;
- dma->SGlist[map_offset].page = dma->map[map_offset];
offset = 0;
map_offset++;
}
@@ -89,7 +104,7 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
{
struct ivtv_dma_page_info user_dma;
struct ivtv_user_dma *dma = &itv->udma;
- int err;
+ int i, err;
IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr);
@@ -123,7 +138,13 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
dma->page_count = user_dma.page_count;
/* Fill SG List with new values */
- ivtv_udma_fill_sg_list(dma, &user_dma, 0);
+ if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) {
+ for (i = 0; i < dma->page_count; i++) {
+ put_page(dma->map[i]);
+ }
+ dma->page_count = 0;
+ return -ENOMEM;
+ }
/* Map SG List */
dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
@@ -166,6 +187,8 @@ void ivtv_udma_unmap(struct ivtv *itv)
void ivtv_udma_free(struct ivtv *itv)
{
+ int i;
+
/* Unmap SG Array */
if (itv->udma.SG_handle) {
pci_unmap_single(itv->dev, itv->udma.SG_handle,
@@ -176,6 +199,11 @@ void ivtv_udma_free(struct ivtv *itv)
if (itv->udma.SG_length) {
pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE);
}
+
+ for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) {
+ if (itv->udma.bouncemap[i])
+ __free_page(itv->udma.bouncemap[i]);
+ }
}
void ivtv_udma_start(struct ivtv *itv)
diff --git a/drivers/media/video/ivtv/ivtv-udma.h b/drivers/media/video/ivtv/ivtv-udma.h
index e131bccedec..df727e23be0 100644
--- a/drivers/media/video/ivtv/ivtv-udma.h
+++ b/drivers/media/video/ivtv/ivtv-udma.h
@@ -18,6 +18,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_UDMA_H
+#define IVTV_UDMA_H
+
/* User DMA functions */
void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size);
int ivtv_udma_fill_sg_list(struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset);
@@ -41,3 +44,5 @@ static inline void ivtv_udma_sync_for_cpu(struct ivtv *itv)
pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev, itv->udma.SG_handle,
sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
}
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index a7282a91bd9..c151bcf5519 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -18,10 +18,69 @@
*/
#include "ivtv-driver.h"
-#include "ivtv-video.h"
-#include "ivtv-vbi.h"
+#include "ivtv-i2c.h"
#include "ivtv-ioctl.h"
#include "ivtv-queue.h"
+#include "ivtv-vbi.h"
+
+static void ivtv_set_vps(struct ivtv *itv, int enabled)
+{
+ struct v4l2_sliced_vbi_data data;
+
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return;
+ data.id = V4L2_SLICED_VPS;
+ data.field = 0;
+ data.line = enabled ? 16 : 0;
+ data.data[2] = itv->vbi.vps_payload.data[0];
+ data.data[8] = itv->vbi.vps_payload.data[1];
+ data.data[9] = itv->vbi.vps_payload.data[2];
+ data.data[10] = itv->vbi.vps_payload.data[3];
+ data.data[11] = itv->vbi.vps_payload.data[4];
+ ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+}
+
+static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
+{
+ struct v4l2_sliced_vbi_data data;
+
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return;
+ data.id = V4L2_SLICED_CAPTION_525;
+ data.field = 0;
+ data.line = (mode & 1) ? 21 : 0;
+ data.data[0] = cc->odd[0];
+ data.data[1] = cc->odd[1];
+ ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+ data.field = 1;
+ data.line = (mode & 2) ? 21 : 0;
+ data.data[0] = cc->even[0];
+ data.data[1] = cc->even[1];
+ ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+}
+
+static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
+{
+ struct v4l2_sliced_vbi_data data;
+
+ if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+ return;
+ /* When using a 50 Hz system, always turn on the
+ wide screen signal with 4x3 ratio as the default.
+ Turning this signal on and off can confuse certain
+ TVs. As far as I can tell there is no reason not to
+ transmit this signal. */
+ if ((itv->std & V4L2_STD_625_50) && !enabled) {
+ enabled = 1;
+ mode = 0x08; /* 4x3 full format */
+ }
+ data.id = V4L2_SLICED_WSS_625;
+ data.field = 0;
+ data.line = enabled ? 23 : 0;
+ data.data[0] = mode & 0xff;
+ data.data[1] = (mode >> 8) & 0xff;
+ ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+}
static int odd_parity(u8 c)
{
@@ -32,62 +91,50 @@ static int odd_parity(u8 c)
return c & 1;
}
-static void passthrough_vbi_data(struct ivtv *itv, int cnt)
+void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t cnt)
{
- int wss = 0;
- u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
- u8 vps[13];
+ struct vbi_info *vi = &itv->vbi;
+ struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
int found_cc = 0;
- int found_wss = 0;
- int found_vps = 0;
- int cc_pos = itv->vbi.cc_pos;
- int i;
+ size_t i;
for (i = 0; i < cnt; i++) {
- struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i;
+ const struct v4l2_sliced_vbi_data *d = sliced + i;
if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
- found_cc = 1;
if (d->field) {
- cc[2] = d->data[0];
- cc[3] = d->data[1];
+ cc.even[0] = d->data[0];
+ cc.even[1] = d->data[1];
} else {
- cc[0] = d->data[0];
- cc[1] = d->data[1];
+ cc.odd[0] = d->data[0];
+ cc.odd[1] = d->data[1];
}
+ found_cc = 1;
}
else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
- memcpy(vps, d->data, sizeof(vps));
- found_vps = 1;
+ struct vbi_vps vps;
+
+ vps.data[0] = d->data[2];
+ vps.data[1] = d->data[8];
+ vps.data[2] = d->data[9];
+ vps.data[3] = d->data[10];
+ vps.data[4] = d->data[11];
+ if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) {
+ vi->vps_payload = vps;
+ set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+ }
}
else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) {
- wss = d->data[0] | d->data[1] << 8;
- found_wss = 1;
- }
- }
-
- if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) {
- itv->vbi.wss = wss;
- itv->vbi.wss_found = found_wss;
- set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
- }
+ int wss = d->data[0] | d->data[1] << 8;
- if (found_vps || itv->vbi.vps_found) {
- itv->vbi.vps[0] = vps[2];
- itv->vbi.vps[1] = vps[8];
- itv->vbi.vps[2] = vps[9];
- itv->vbi.vps[3] = vps[10];
- itv->vbi.vps[4] = vps[11];
- itv->vbi.vps_found = found_vps;
- set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+ if (vi->wss_payload != wss) {
+ vi->wss_payload = wss;
+ set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
+ }
+ }
}
-
- if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
- itv->vbi.cc_data_odd[cc_pos] = cc[0];
- itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
- itv->vbi.cc_data_even[cc_pos] = cc[2];
- itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
- itv->vbi.cc_pos = cc_pos + 2;
+ if (found_cc && vi->cc_payload_idx < sizeof(vi->cc_payload)) {
+ vi->cc_payload[vi->cc_payload_idx++] = cc;
set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
}
}
@@ -163,8 +210,8 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p)
linemask[1] = 0xf;
p += 4;
} else {
- /* unknown VBI data stream */
- return 0;
+ /* unknown VBI data, convert to empty VBI frame */
+ linemask[0] = linemask[1] = 0;
}
for (i = 0; i < 36; i++) {
int err = 0;
@@ -211,69 +258,6 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p)
return line * sizeof(itv->vbi.sliced_dec_data[0]);
}
-ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
-{
- /* Should be a __user pointer, but sparse doesn't parse this bit correctly. */
- const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf;
- u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
- int found_cc = 0;
- int cc_pos = itv->vbi.cc_pos;
-
- while (count >= sizeof(struct v4l2_sliced_vbi_data)) {
- switch (p->id) {
- case V4L2_SLICED_CAPTION_525:
- if (p->line == 21) {
- found_cc = 1;
- if (p->field) {
- cc[2] = p->data[0];
- cc[3] = p->data[1];
- } else {
- cc[0] = p->data[0];
- cc[1] = p->data[1];
- }
- }
- break;
-
- case V4L2_SLICED_VPS:
- if (p->line == 16 && p->field == 0) {
- itv->vbi.vps[0] = p->data[2];
- itv->vbi.vps[1] = p->data[8];
- itv->vbi.vps[2] = p->data[9];
- itv->vbi.vps[3] = p->data[10];
- itv->vbi.vps[4] = p->data[11];
- itv->vbi.vps_found = 1;
- set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
- }
- break;
-
- case V4L2_SLICED_WSS_625:
- if (p->line == 23 && p->field == 0) {
- /* No lock needed for WSS */
- itv->vbi.wss = p->data[0] | (p->data[1] << 8);
- itv->vbi.wss_found = 1;
- set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
- }
- break;
-
- default:
- break;
- }
- count -= sizeof(*p);
- p++;
- }
-
- if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
- itv->vbi.cc_data_odd[cc_pos] = cc[0];
- itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
- itv->vbi.cc_data_even[cc_pos] = cc[2];
- itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
- itv->vbi.cc_pos = cc_pos + 2;
- set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
- }
-
- return (const char __user *)p - ubuf;
-}
-
/* Compress raw VBI format, removes leading SAV codes and surplus space after the
field.
Returns new compressed size. */
@@ -422,108 +406,95 @@ void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt);
buf->bytesused = cnt;
- passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0]));
+ ivtv_write_vbi(itv, itv->vbi.sliced_dec_data,
+ cnt / sizeof(itv->vbi.sliced_dec_data[0]));
return;
}
}
-void ivtv_disable_vbi(struct ivtv *itv)
+void ivtv_disable_cc(struct ivtv *itv)
{
- clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
- clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+ struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+
clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
- ivtv_set_wss(itv, 0, 0);
- ivtv_set_cc(itv, 0, 0, 0, 0, 0);
- ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0);
- itv->vbi.vps_found = itv->vbi.wss_found = 0;
- itv->vbi.wss = 0;
- itv->vbi.cc_pos = 0;
+ ivtv_set_cc(itv, 0, &cc);
+ itv->vbi.cc_payload_idx = 0;
}
void ivtv_vbi_work_handler(struct ivtv *itv)
{
+ struct vbi_info *vi = &itv->vbi;
struct v4l2_sliced_vbi_data data;
+ struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
/* Lock */
if (itv->output_mode == OUT_PASSTHROUGH) {
- /* Note: currently only the saa7115 is used in a PVR350,
- so these commands are for now saa7115 specific. */
if (itv->is_50hz) {
data.id = V4L2_SLICED_WSS_625;
data.field = 0;
if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
ivtv_set_wss(itv, 1, data.data[0] & 0xf);
- itv->vbi.wss_no_update = 0;
- } else if (itv->vbi.wss_no_update == 4) {
+ vi->wss_missing_cnt = 0;
+ } else if (vi->wss_missing_cnt == 4) {
ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */
} else {
- itv->vbi.wss_no_update++;
+ vi->wss_missing_cnt++;
}
}
else {
- u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0;
int mode = 0;
data.id = V4L2_SLICED_CAPTION_525;
data.field = 0;
if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
mode |= 1;
- c1 = data.data[0];
- c2 = data.data[1];
+ cc.odd[0] = data.data[0];
+ cc.odd[1] = data.data[1];
}
data.field = 1;
if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
mode |= 2;
- c3 = data.data[0];
- c4 = data.data[1];
+ cc.even[0] = data.data[0];
+ cc.even[1] = data.data[1];
}
if (mode) {
- itv->vbi.cc_no_update = 0;
- ivtv_set_cc(itv, mode, c1, c2, c3, c4);
- } else if (itv->vbi.cc_no_update == 4) {
- ivtv_set_cc(itv, 0, 0, 0, 0, 0);
+ vi->cc_missing_cnt = 0;
+ ivtv_set_cc(itv, mode, &cc);
+ } else if (vi->cc_missing_cnt == 4) {
+ ivtv_set_cc(itv, 0, &cc);
} else {
- itv->vbi.cc_no_update++;
+ vi->cc_missing_cnt++;
}
}
return;
}
if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) {
- /* Lock */
- ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf);
+ ivtv_set_wss(itv, 1, vi->wss_payload & 0xf);
}
- if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
- if (itv->vbi.cc_pos == 0) {
- ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80);
+ if (test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
+ if (vi->cc_payload_idx == 0) {
+ clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+ ivtv_set_cc(itv, 3, &cc);
}
- while (itv->vbi.cc_pos) {
- u8 cc_odd0 = itv->vbi.cc_data_odd[0];
- u8 cc_odd1 = itv->vbi.cc_data_odd[1];
- u8 cc_even0 = itv->vbi.cc_data_even[0];
- u8 cc_even1 = itv->vbi.cc_data_even[1];
-
- memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2);
- memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2);
- itv->vbi.cc_pos -= 2;
- if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80)
+ while (vi->cc_payload_idx) {
+ cc = vi->cc_payload[0];
+
+ memcpy(vi->cc_payload, vi->cc_payload + 1,
+ sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0]));
+ vi->cc_payload_idx--;
+ if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80)
continue;
- /* Send to Saa7127 */
- ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1);
- if (itv->vbi.cc_pos == 0)
- set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+ ivtv_set_cc(itv, 3, &cc);
break;
}
}
if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) {
- /* Lock */
- ivtv_set_vps(itv, itv->vbi.vps_found,
- itv->vbi.vps[0], itv->vbi.vps[1],
- itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]);
+ ivtv_set_vps(itv, 1);
}
}
diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h
index ec211b49702..970567b9194 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.h
+++ b/drivers/media/video/ivtv/ivtv-vbi.h
@@ -17,10 +17,15 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count);
+#ifndef IVTV_VBI_H
+#define IVTV_VBI_H
+
+void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t count);
void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
u64 pts_stamp, int streamtype);
int ivtv_used_line(struct ivtv *itv, int line, int field);
-void ivtv_disable_vbi(struct ivtv *itv);
+void ivtv_disable_cc(struct ivtv *itv);
void ivtv_set_vbi(unsigned long arg);
void ivtv_vbi_work_handler(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
index 85530a3cd36..d050de2a722 100644
--- a/drivers/media/video/ivtv/ivtv-version.h
+++ b/drivers/media/video/ivtv/ivtv-version.h
@@ -17,10 +17,15 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_VERSION_H
+#define IVTV_VERSION_H
+
#define IVTV_DRIVER_NAME "ivtv"
#define IVTV_DRIVER_VERSION_MAJOR 1
-#define IVTV_DRIVER_VERSION_MINOR 0
+#define IVTV_DRIVER_VERSION_MINOR 1
#define IVTV_DRIVER_VERSION_PATCHLEVEL 0
#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-video.h b/drivers/media/video/ivtv/ivtv-video.h
deleted file mode 100644
index c8ade5d3c41..00000000000
--- a/drivers/media/video/ivtv/ivtv-video.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- saa7127 interface functions
- Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-void ivtv_set_wss(struct ivtv *itv, int enabled, int mode);
-void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4);
-void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3,
- u8 vps4, u8 vps5);
-void ivtv_video_set_io(struct ivtv *itv);
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index bcea09542e5..9091c4837bb 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -19,11 +19,16 @@
*/
#include "ivtv-driver.h"
-#include "ivtv-queue.h"
#include "ivtv-udma.h"
-#include "ivtv-irq.h"
#include "ivtv-yuv.h"
+const u32 yuv_offset[4] = {
+ IVTV_YUV_BUFFER_OFFSET,
+ IVTV_YUV_BUFFER_OFFSET_1,
+ IVTV_YUV_BUFFER_OFFSET_2,
+ IVTV_YUV_BUFFER_OFFSET_3
+};
+
static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
struct ivtv_dma_frame *args)
{
@@ -37,7 +42,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
int y_decode_height, uv_decode_height, y_size;
int frame = atomic_read(&itv->yuv_info.next_fill_frame);
- y_buffer_offset = IVTV_DEC_MEM_START + yuv_offset[frame];
+ y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
y_decode_height = uv_decode_height = args->src.height + args->src.top;
@@ -83,7 +88,14 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
}
/* Fill & map SG List */
- ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0));
+ if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
+ IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
+ for (i = 0; i < dma->page_count; i++) {
+ put_page(dma->map[i]);
+ }
+ dma->page_count = 0;
+ return -ENOMEM;
+ }
dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
/* Fill SG Array with new values */
@@ -94,7 +106,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
if (itv->yuv_info.blanking_dmaptr) {
dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr);
- dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DEC_MEM_START + yuv_offset[frame]);
+ dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
dma->SG_length++;
}
}
@@ -612,7 +624,6 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi
itv->yuv_info.v_filter_2 = v_filter_2;
}
- itv->yuv_info.frame_interlaced_last = itv->yuv_info.frame_interlaced;
}
/* Modify the supplied coordinate information to fit the visible osd area */
@@ -699,7 +710,7 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo
/* If there's nothing to safe to display, we may as well stop now */
if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
- return 0;
+ return IVTV_YUV_UPDATE_INVALID;
}
/* Ensure video remains inside OSD area */
@@ -780,7 +791,7 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo
/* Check again. If there's nothing to safe to display, stop now */
if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
- return 0;
+ return IVTV_YUV_UPDATE_INVALID;
}
/* Both x offset & width are linked, so they have to be done together */
@@ -799,6 +810,7 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo
(itv->yuv_info.old_frame_info.src_y != window->src_y) ||
(itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||
(itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||
+ (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||
(itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||
(itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {
yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
@@ -828,97 +840,118 @@ void ivtv_yuv_work_handler (struct ivtv *itv)
if (!(yuv_update = ivtv_yuv_window_setup (itv, &window)))
return;
- /* Update horizontal settings */
- if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
- ivtv_yuv_handle_horizontal(itv, &window);
+ if (yuv_update & IVTV_YUV_UPDATE_INVALID) {
+ write_reg(0x01008080, 0x2898);
+ } else if (yuv_update) {
+ write_reg(0x00108080, 0x2898);
- if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
- ivtv_yuv_handle_vertical(itv, &window);
+ if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
+ ivtv_yuv_handle_horizontal(itv, &window);
+
+ if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
+ ivtv_yuv_handle_vertical(itv, &window);
+ }
memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));
}
static void ivtv_yuv_init (struct ivtv *itv)
{
+ struct yuv_playback_info *yi = &itv->yuv_info;
+
IVTV_DEBUG_YUV("ivtv_yuv_init\n");
/* Take a snapshot of the current register settings */
- itv->yuv_info.reg_2834 = read_reg(0x02834);
- itv->yuv_info.reg_2838 = read_reg(0x02838);
- itv->yuv_info.reg_283c = read_reg(0x0283c);
- itv->yuv_info.reg_2840 = read_reg(0x02840);
- itv->yuv_info.reg_2844 = read_reg(0x02844);
- itv->yuv_info.reg_2848 = read_reg(0x02848);
- itv->yuv_info.reg_2854 = read_reg(0x02854);
- itv->yuv_info.reg_285c = read_reg(0x0285c);
- itv->yuv_info.reg_2864 = read_reg(0x02864);
- itv->yuv_info.reg_2870 = read_reg(0x02870);
- itv->yuv_info.reg_2874 = read_reg(0x02874);
- itv->yuv_info.reg_2898 = read_reg(0x02898);
- itv->yuv_info.reg_2890 = read_reg(0x02890);
-
- itv->yuv_info.reg_289c = read_reg(0x0289c);
- itv->yuv_info.reg_2918 = read_reg(0x02918);
- itv->yuv_info.reg_291c = read_reg(0x0291c);
- itv->yuv_info.reg_2920 = read_reg(0x02920);
- itv->yuv_info.reg_2924 = read_reg(0x02924);
- itv->yuv_info.reg_2928 = read_reg(0x02928);
- itv->yuv_info.reg_292c = read_reg(0x0292c);
- itv->yuv_info.reg_2930 = read_reg(0x02930);
- itv->yuv_info.reg_2934 = read_reg(0x02934);
- itv->yuv_info.reg_2938 = read_reg(0x02938);
- itv->yuv_info.reg_293c = read_reg(0x0293c);
- itv->yuv_info.reg_2940 = read_reg(0x02940);
- itv->yuv_info.reg_2944 = read_reg(0x02944);
- itv->yuv_info.reg_2948 = read_reg(0x02948);
- itv->yuv_info.reg_294c = read_reg(0x0294c);
- itv->yuv_info.reg_2950 = read_reg(0x02950);
- itv->yuv_info.reg_2954 = read_reg(0x02954);
- itv->yuv_info.reg_2958 = read_reg(0x02958);
- itv->yuv_info.reg_295c = read_reg(0x0295c);
- itv->yuv_info.reg_2960 = read_reg(0x02960);
- itv->yuv_info.reg_2964 = read_reg(0x02964);
- itv->yuv_info.reg_2968 = read_reg(0x02968);
- itv->yuv_info.reg_296c = read_reg(0x0296c);
- itv->yuv_info.reg_2970 = read_reg(0x02970);
-
- itv->yuv_info.v_filter_1 = -1;
- itv->yuv_info.v_filter_2 = -1;
- itv->yuv_info.h_filter = -1;
+ yi->reg_2834 = read_reg(0x02834);
+ yi->reg_2838 = read_reg(0x02838);
+ yi->reg_283c = read_reg(0x0283c);
+ yi->reg_2840 = read_reg(0x02840);
+ yi->reg_2844 = read_reg(0x02844);
+ yi->reg_2848 = read_reg(0x02848);
+ yi->reg_2854 = read_reg(0x02854);
+ yi->reg_285c = read_reg(0x0285c);
+ yi->reg_2864 = read_reg(0x02864);
+ yi->reg_2870 = read_reg(0x02870);
+ yi->reg_2874 = read_reg(0x02874);
+ yi->reg_2898 = read_reg(0x02898);
+ yi->reg_2890 = read_reg(0x02890);
+
+ yi->reg_289c = read_reg(0x0289c);
+ yi->reg_2918 = read_reg(0x02918);
+ yi->reg_291c = read_reg(0x0291c);
+ yi->reg_2920 = read_reg(0x02920);
+ yi->reg_2924 = read_reg(0x02924);
+ yi->reg_2928 = read_reg(0x02928);
+ yi->reg_292c = read_reg(0x0292c);
+ yi->reg_2930 = read_reg(0x02930);
+ yi->reg_2934 = read_reg(0x02934);
+ yi->reg_2938 = read_reg(0x02938);
+ yi->reg_293c = read_reg(0x0293c);
+ yi->reg_2940 = read_reg(0x02940);
+ yi->reg_2944 = read_reg(0x02944);
+ yi->reg_2948 = read_reg(0x02948);
+ yi->reg_294c = read_reg(0x0294c);
+ yi->reg_2950 = read_reg(0x02950);
+ yi->reg_2954 = read_reg(0x02954);
+ yi->reg_2958 = read_reg(0x02958);
+ yi->reg_295c = read_reg(0x0295c);
+ yi->reg_2960 = read_reg(0x02960);
+ yi->reg_2964 = read_reg(0x02964);
+ yi->reg_2968 = read_reg(0x02968);
+ yi->reg_296c = read_reg(0x0296c);
+ yi->reg_2970 = read_reg(0x02970);
+
+ yi->v_filter_1 = -1;
+ yi->v_filter_2 = -1;
+ yi->h_filter = -1;
/* Set some valid size info */
- itv->yuv_info.osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
- itv->yuv_info.osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
+ yi->osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
+ yi->osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
/* Bit 2 of reg 2878 indicates current decoder output format
0 : NTSC 1 : PAL */
if (read_reg(0x2878) & 4)
- itv->yuv_info.decode_height = 576;
+ yi->decode_height = 576;
else
- itv->yuv_info.decode_height = 480;
-
- /* If no visible size set, assume full size */
- if (!itv->yuv_info.osd_vis_w) itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset;
- if (!itv->yuv_info.osd_vis_h) itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
+ yi->decode_height = 480;
+
+ if (!itv->osd_info) {
+ yi->osd_vis_w = 720 - yi->osd_x_offset;
+ yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
+ } else {
+ /* If no visible size set, assume full size */
+ if (!yi->osd_vis_w)
+ yi->osd_vis_w = 720 - yi->osd_x_offset;
+
+ if (!yi->osd_vis_h)
+ yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
+ else {
+ /* If output video standard has changed, requested height may
+ not be legal */
+ if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) {
+ IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
+ yi->osd_vis_h + yi->osd_y_offset,
+ yi->decode_height);
+ yi->osd_vis_h = yi->decode_height - yi->osd_y_offset;
+ }
+ }
+ }
/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
- itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL);
- if (itv->yuv_info.blanking_ptr) {
- itv->yuv_info.blanking_dmaptr = pci_map_single(itv->dev, itv->yuv_info.blanking_ptr, 720*16, PCI_DMA_TODEVICE);
- }
+ yi->blanking_ptr = kzalloc(720*16, GFP_KERNEL);
+ if (yi->blanking_ptr)
+ yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE);
else {
- itv->yuv_info.blanking_dmaptr = 0;
- IVTV_DEBUG_WARN ("Failed to allocate yuv blanking buffer\n");
+ yi->blanking_dmaptr = 0;
+ IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n");
}
- IVTV_DEBUG_WARN("Enable video output\n");
- write_reg_sync(0x00108080, 0x2898);
-
/* Enable YUV decoder output */
write_reg_sync(0x01, IVTV_REG_VDM);
set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
- atomic_set(&itv->yuv_info.next_dma_frame,0);
+ atomic_set(&yi->next_dma_frame, 0);
}
int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
@@ -927,6 +960,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
int rc = 0;
int got_sig = 0;
int frame, next_fill_frame, last_fill_frame;
+ int register_update = 0;
IVTV_DEBUG_INFO("yuv_prep_frame\n");
@@ -940,6 +974,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
/* Buffers are full - Overwrite the last frame */
next_fill_frame = frame;
frame = (frame - 1) & 3;
+ register_update = itv->yuv_info.new_frame_info[frame].update;
}
/* Take a snapshot of the yuv coordinate information */
@@ -955,6 +990,9 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;
itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;
+ /* Snapshot field order */
+ itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field;
+
/* Are we going to offset the Y plane */
if (args->src.height + args->src.top < 512-16)
itv->yuv_info.new_frame_info[frame].offset_y = 1;
@@ -970,6 +1008,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
itv->yuv_info.new_frame_info[frame].update = 0;
itv->yuv_info.new_frame_info[frame].interlaced_y = 0;
itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;
+ itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode;
if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],
sizeof (itv->yuv_info.new_frame_info[frame]))) {
@@ -978,6 +1017,14 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
}
+ itv->yuv_info.new_frame_info[frame].update |= register_update;
+
+ /* Should this frame be delayed ? */
+ if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3])
+ itv->yuv_info.field_delay[frame] = 1;
+ else
+ itv->yuv_info.field_delay[frame] = 0;
+
/* DMA the frame */
mutex_lock(&itv->udma.lock);
diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h
index 88972d3f77c..3b966f0a204 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.h
+++ b/drivers/media/video/ivtv/ivtv-yuv.h
@@ -18,7 +18,29 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef IVTV_YUV_H
+#define IVTV_YUV_H
+
+/* Buffers on hardware offsets */
+#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */
+#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */
+#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */
+#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */
+#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */
+
+/* Offset to filter table in firmware */
+#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8
+#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358
+
+#define IVTV_YUV_UPDATE_HORIZONTAL 0x01
+#define IVTV_YUV_UPDATE_VERTICAL 0x02
+#define IVTV_YUV_UPDATE_INVALID 0x04
+
+extern const u32 yuv_offset[4];
+
int ivtv_yuv_filter_check(struct ivtv *itv);
int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
void ivtv_yuv_close(struct ivtv *itv);
void ivtv_yuv_work_handler (struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
new file mode 100644
index 00000000000..52ffd154a3d
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -0,0 +1,1148 @@
+/*
+ On Screen Display cx23415 Framebuffer driver
+
+ This module presents the cx23415 OSD (onscreen display) framebuffer memory
+ as a standard Linux /dev/fb style framebuffer device. The framebuffer has
+ support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp
+ mode, there is a choice of a three color depths (12, 15 or 16 bits), but no
+ local alpha. The colorspace is selectable between rgb & yuv.
+ Depending on the TV standard configured in the ivtv module at load time,
+ the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp.
+ Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL)
+ or 59.94 (NTSC)
+
+ Copyright (c) 2003 Matt T. Yourst <yourst@yourst.com>
+
+ Derived from drivers/video/vesafb.c
+ Portions (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+
+ 2.6 kernel port:
+ Copyright (C) 2004 Matthias Badaire
+
+ Copyright (C) 2004 Chris Kennedy <c@groovy.org>
+
+ Copyright (C) 2006 Ian Armstrong <ian@iarmst.demon.co.uk>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fb.h>
+#include <linux/ivtvfb.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "ivtv-driver.h"
+#include "ivtv-udma.h"
+#include "ivtv-mailbox.h"
+
+/* card parameters */
+static int ivtvfb_card_id = -1;
+static int ivtvfb_debug = 0;
+static int osd_laced;
+static int osd_depth;
+static int osd_upper;
+static int osd_left;
+static int osd_yres;
+static int osd_xres;
+
+module_param(ivtvfb_card_id, int, 0444);
+module_param_named(debug,ivtvfb_debug, int, 0644);
+module_param(osd_laced, bool, 0444);
+module_param(osd_depth, int, 0444);
+module_param(osd_upper, int, 0444);
+module_param(osd_left, int, 0444);
+module_param(osd_yres, int, 0444);
+module_param(osd_xres, int, 0444);
+
+MODULE_PARM_DESC(ivtvfb_card_id,
+ "Only use framebuffer of the specified ivtv card (0-31)\n"
+ "\t\t\tdefault -1: initialize all available framebuffers");
+
+MODULE_PARM_DESC(debug,
+ "Debug level (bitmask). Default: errors only\n"
+ "\t\t\t(debug = 3 gives full debugging)");
+
+/* Why upper, left, xres, yres, depth, laced ? To match terminology used
+ by fbset.
+ Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
+
+MODULE_PARM_DESC(osd_laced,
+ "Interlaced mode\n"
+ "\t\t\t0=off\n"
+ "\t\t\t1=on\n"
+ "\t\t\tdefault off");
+
+MODULE_PARM_DESC(osd_depth,
+ "Bits per pixel - 8, 16, 32\n"
+ "\t\t\tdefault 8");
+
+MODULE_PARM_DESC(osd_upper,
+ "Vertical start position\n"
+ "\t\t\tdefault 0 (Centered)");
+
+MODULE_PARM_DESC(osd_left,
+ "Horizontal start position\n"
+ "\t\t\tdefault 0 (Centered)");
+
+MODULE_PARM_DESC(osd_yres,
+ "Display height\n"
+ "\t\t\tdefault 480 (PAL)\n"
+ "\t\t\t 400 (NTSC)");
+
+MODULE_PARM_DESC(osd_xres,
+ "Display width\n"
+ "\t\t\tdefault 640");
+
+MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
+MODULE_LICENSE("GPL");
+
+/* --------------------------------------------------------------------- */
+
+#define IVTVFB_DBGFLG_WARN (1 << 0)
+#define IVTVFB_DBGFLG_INFO (1 << 1)
+
+#define IVTVFB_DEBUG(x, type, fmt, args...) \
+ do { \
+ if ((x) & ivtvfb_debug) \
+ printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \
+ } while (0)
+#define IVTVFB_DEBUG_WARN(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args)
+#define IVTVFB_DEBUG_INFO(fmt, args...) IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args)
+
+/* Standard kernel messages */
+#define IVTVFB_ERR(fmt, args...) printk(KERN_ERR "ivtvfb%d: " fmt, itv->num , ## args)
+#define IVTVFB_WARN(fmt, args...) printk(KERN_WARNING "ivtvfb%d: " fmt, itv->num , ## args)
+#define IVTVFB_INFO(fmt, args...) printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args)
+
+/* --------------------------------------------------------------------- */
+
+#define IVTV_OSD_MAX_WIDTH 720
+#define IVTV_OSD_MAX_HEIGHT 576
+
+#define IVTV_OSD_BPP_8 0x00
+#define IVTV_OSD_BPP_16_444 0x03
+#define IVTV_OSD_BPP_16_555 0x02
+#define IVTV_OSD_BPP_16_565 0x01
+#define IVTV_OSD_BPP_32 0x04
+
+struct osd_info {
+ /* Physical base address */
+ unsigned long video_pbase;
+ /* Relative base address (relative to start of decoder memory) */
+ u32 video_rbase;
+ /* Mapped base address */
+ volatile char __iomem *video_vbase;
+ /* Buffer size */
+ u32 video_buffer_size;
+
+#ifdef CONFIG_MTRR
+ /* video_base rounded down as required by hardware MTRRs */
+ unsigned long fb_start_aligned_physaddr;
+ /* video_base rounded up as required by hardware MTRRs */
+ unsigned long fb_end_aligned_physaddr;
+#endif
+
+ /* Store the buffer offset */
+ int set_osd_coords_x;
+ int set_osd_coords_y;
+
+ /* Current dimensions (NOT VISIBLE SIZE!) */
+ int display_width;
+ int display_height;
+ int display_byte_stride;
+
+ /* Current bits per pixel */
+ int bits_per_pixel;
+ int bytes_per_pixel;
+
+ /* Frame buffer stuff */
+ struct fb_info ivtvfb_info;
+ struct fb_var_screeninfo ivtvfb_defined;
+ struct fb_fix_screeninfo ivtvfb_fix;
+};
+
+struct ivtv_osd_coords {
+ unsigned long offset;
+ unsigned long max_offset;
+ int pixel_stride;
+ int lines;
+ int x;
+ int y;
+};
+
+/* --------------------------------------------------------------------- */
+
+/* ivtv API calls for framebuffer related support */
+
+static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
+ u32 *fblength)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ int rc;
+
+ rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
+ *fbbase = data[0];
+ *fblength = data[1];
+ return rc;
+}
+
+static int ivtvfb_get_osd_coords(struct ivtv *itv,
+ struct ivtv_osd_coords *osd)
+{
+ struct osd_info *oi = itv->osd_info;
+ u32 data[CX2341X_MBOX_MAX_DATA];
+
+ ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
+
+ osd->offset = data[0] - oi->video_rbase;
+ osd->max_offset = oi->display_width * oi->display_height * 4;
+ osd->pixel_stride = data[1];
+ osd->lines = data[2];
+ osd->x = data[3];
+ osd->y = data[4];
+ return 0;
+}
+
+static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
+{
+ struct osd_info *oi = itv->osd_info;
+
+ oi->display_width = osd->pixel_stride;
+ oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
+ oi->set_osd_coords_x += osd->x;
+ oi->set_osd_coords_y = osd->y;
+
+ return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
+ osd->offset + oi->video_rbase,
+ osd->pixel_stride,
+ osd->lines, osd->x, osd->y);
+}
+
+static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
+{
+ int osd_height_limit = itv->is_50hz ? 576 : 480;
+
+ /* Only fail if resolution too high, otherwise fudge the start coords. */
+ if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
+ return -EINVAL;
+
+ /* Ensure we don't exceed display limits */
+ if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
+ IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
+ ivtv_window->top, ivtv_window->height);
+ ivtv_window->top = osd_height_limit - ivtv_window->height;
+ }
+
+ if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
+ IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
+ ivtv_window->left, ivtv_window->width);
+ ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
+ }
+
+ /* Set the OSD origin */
+ write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
+
+ /* How much to display */
+ write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
+
+ /* Pass this info back the yuv handler */
+ itv->yuv_info.osd_vis_w = ivtv_window->width;
+ itv->yuv_info.osd_vis_h = ivtv_window->height;
+ itv->yuv_info.osd_x_offset = ivtv_window->left;
+ itv->yuv_info.osd_y_offset = ivtv_window->top;
+
+ return 0;
+}
+
+static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
+ unsigned long ivtv_dest_addr, void __user *userbuf,
+ int size_in_bytes)
+{
+ DEFINE_WAIT(wait);
+ int ret = 0;
+ int got_sig = 0;
+
+ mutex_lock(&itv->udma.lock);
+ /* Map User DMA */
+ if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
+ mutex_unlock(&itv->udma.lock);
+ IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, "
+ "Error with get_user_pages: %d bytes, %d pages returned\n",
+ size_in_bytes, itv->udma.page_count);
+
+ /* get_user_pages must have failed completely */
+ return -EIO;
+ }
+
+ IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
+ size_in_bytes, itv->udma.page_count);
+
+ ivtv_udma_prepare(itv);
+ prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
+ /* if no UDMA is pending and no UDMA is in progress, then the DMA
+ is finished */
+ while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
+ /* don't interrupt if the DMA is in progress but break off
+ a still pending DMA. */
+ got_sig = signal_pending(current);
+ if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
+ break;
+ got_sig = 0;
+ schedule();
+ }
+ finish_wait(&itv->dma_waitq, &wait);
+
+ /* Unmap Last DMA Xfer */
+ ivtv_udma_unmap(itv);
+ mutex_unlock(&itv->udma.lock);
+ if (got_sig) {
+ IVTV_DEBUG_INFO("User stopped OSD\n");
+ return -EINTR;
+ }
+
+ return ret;
+}
+
+static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
+ unsigned long dest_offset, int count)
+{
+ DEFINE_WAIT(wait);
+ struct osd_info *oi = itv->osd_info;
+
+ /* Nothing to do */
+ if (count == 0) {
+ IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n");
+ return -EINVAL;
+ }
+
+ /* Check Total FB Size */
+ if ((dest_offset + count) > oi->video_buffer_size) {
+ IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
+ dest_offset + count, oi->video_buffer_size);
+ return -E2BIG;
+ }
+
+ /* Not fatal, but will have undesirable results */
+ if ((unsigned long)source & 3)
+ IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
+ (unsigned long)source);
+
+ if (dest_offset & 3)
+ IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
+
+ if (count & 3)
+ IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count);
+
+ /* Check Source */
+ if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
+ IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
+ (unsigned long)source);
+
+ IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
+ dest_offset, (unsigned long)source,
+ count);
+ return -EINVAL;
+ }
+
+ /* OSD Address to send DMA to */
+ dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase;
+
+ /* Fill Buffers */
+ return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
+}
+
+static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+{
+ DEFINE_WAIT(wait);
+ struct ivtv *itv = (struct ivtv *)info->par;
+ int rc = 0;
+
+ switch (cmd) {
+ case FBIOGET_VBLANK: {
+ struct fb_vblank vblank;
+ u32 trace;
+
+ vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
+ FB_VBLANK_HAVE_VSYNC;
+ trace = read_reg(0x028c0) >> 16;
+ if (itv->is_50hz && trace > 312) trace -= 312;
+ else if (itv->is_60hz && trace > 262) trace -= 262;
+ if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
+ vblank.count = itv->last_vsync_field;
+ vblank.vcount = trace;
+ vblank.hcount = 0;
+ if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
+ return -EFAULT;
+ return 0;
+ }
+
+ case FBIO_WAITFORVSYNC:
+ prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
+ if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
+ finish_wait(&itv->vsync_waitq, &wait);
+ return rc;
+
+ case IVTVFB_IOC_DMA_FRAME: {
+ struct ivtvfb_dma_frame args;
+
+ IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
+ if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
+ return -EFAULT;
+
+ return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
+ }
+
+ default:
+ IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Framebuffer device handling */
+
+static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
+{
+ struct osd_info *oi = itv->osd_info;
+ struct ivtv_osd_coords ivtv_osd;
+ struct v4l2_rect ivtv_window;
+ int osd_mode = -1;
+
+ IVTVFB_DEBUG_INFO("ivtvfb_set_var\n");
+
+ /* Select color space */
+ if (var->nonstd) /* YUV */
+ write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
+ else /* RGB */
+ write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
+
+ /* Set the color mode */
+ switch (var->bits_per_pixel) {
+ case 8:
+ osd_mode = IVTV_OSD_BPP_8;
+ break;
+ case 32:
+ osd_mode = IVTV_OSD_BPP_32;
+ break;
+ case 16:
+ switch (var->green.length) {
+ case 4:
+ osd_mode = IVTV_OSD_BPP_16_444;
+ break;
+ case 5:
+ osd_mode = IVTV_OSD_BPP_16_555;
+ break;
+ case 6:
+ osd_mode = IVTV_OSD_BPP_16_565;
+ break;
+ default:
+ IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
+ }
+ break;
+ default:
+ IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
+ }
+
+ /* Set video mode. Although rare, the display can become scrambled even
+ if we don't change mode. Always 'bounce' to osd_mode via mode 0 */
+ if (osd_mode != -1) {
+ ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
+ ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
+ }
+
+ oi->bits_per_pixel = var->bits_per_pixel;
+ oi->bytes_per_pixel = var->bits_per_pixel / 8;
+
+ /* Set the flicker filter */
+ switch (var->vmode & FB_VMODE_MASK) {
+ case FB_VMODE_NONINTERLACED: /* Filter on */
+ ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
+ break;
+ case FB_VMODE_INTERLACED: /* Filter off */
+ ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
+ break;
+ default:
+ IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
+ }
+
+ /* Read the current osd info */
+ ivtvfb_get_osd_coords(itv, &ivtv_osd);
+
+ /* Now set the OSD to the size we want */
+ ivtv_osd.pixel_stride = var->xres_virtual;
+ ivtv_osd.lines = var->yres_virtual;
+ ivtv_osd.x = 0;
+ ivtv_osd.y = 0;
+ ivtvfb_set_osd_coords(itv, &ivtv_osd);
+
+ /* Can't seem to find the right API combo for this.
+ Use another function which does what we need through direct register access. */
+ ivtv_window.width = var->xres;
+ ivtv_window.height = var->yres;
+
+ /* Minimum margin cannot be 0, as X won't allow such a mode */
+ if (!var->upper_margin) var->upper_margin++;
+ if (!var->left_margin) var->left_margin++;
+ ivtv_window.top = var->upper_margin - 1;
+ ivtv_window.left = var->left_margin - 1;
+
+ ivtvfb_set_display_window(itv, &ivtv_window);
+
+ /* Force update of yuv registers */
+ itv->yuv_info.yuv_forced_update = 1;
+
+ IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
+ var->xres, var->yres,
+ var->xres_virtual, var->yres_virtual,
+ var->bits_per_pixel);
+
+ IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
+ var->left_margin, var->upper_margin);
+
+ IVTVFB_DEBUG_INFO("Display filter: %s\n",
+ (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
+ IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
+
+ return 0;
+}
+
+static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
+{
+ struct osd_info *oi = itv->osd_info;
+
+ IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id, "cx23415 TV out");
+ fix->smem_start = oi->video_pbase;
+ fix->smem_len = oi->video_buffer_size;
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+ fix->ywrapstep = 0;
+ fix->line_length = oi->display_byte_stride;
+ fix->accel = FB_ACCEL_NONE;
+ return 0;
+}
+
+/* Check the requested display mode, returning -EINVAL if we can't
+ handle it. */
+
+static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
+{
+ struct osd_info *oi = itv->osd_info;
+ int osd_height_limit;
+ u32 pixclock, hlimit, vlimit;
+
+ IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
+
+ /* Set base references for mode calcs. */
+ if (itv->is_50hz) {
+ pixclock = 84316;
+ hlimit = 776;
+ vlimit = 591;
+ osd_height_limit = 576;
+ }
+ else {
+ pixclock = 83926;
+ hlimit = 776;
+ vlimit = 495;
+ osd_height_limit = 480;
+ }
+
+ if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ }
+ else if (var->bits_per_pixel == 16) {
+ /* To find out the true mode, check green length */
+ switch (var->green.length) {
+ case 4:
+ var->red.offset = 8;
+ var->red.length = 4;
+ var->green.offset = 4;
+ var->green.length = 4;
+ var->blue.offset = 0;
+ var->blue.length = 4;
+ var->transp.offset = 12;
+ var->transp.length = 1;
+ break;
+ case 5:
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
+ break;
+ default:
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ }
+ }
+ else {
+ IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ /* Check the resolution */
+ if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
+ IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n",
+ var->xres, var->yres);
+ return -EINVAL;
+ }
+
+ /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
+ if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
+ var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
+ var->xres_virtual < var->xres ||
+ var->yres_virtual < var->yres) {
+ IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
+ var->xres_virtual, var->yres_virtual);
+ return -EINVAL;
+ }
+
+ /* Some extra checks if in 8 bit mode */
+ if (var->bits_per_pixel == 8) {
+ /* Width must be a multiple of 4 */
+ if (var->xres & 3) {
+ IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
+ return -EINVAL;
+ }
+ if (var->xres_virtual & 3) {
+ IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
+ return -EINVAL;
+ }
+ }
+ else if (var->bits_per_pixel == 16) {
+ /* Width must be a multiple of 2 */
+ if (var->xres & 1) {
+ IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
+ return -EINVAL;
+ }
+ if (var->xres_virtual & 1) {
+ IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
+ return -EINVAL;
+ }
+ }
+
+ /* Now check the offsets */
+ if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
+ IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
+ var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
+ return -EINVAL;
+ }
+
+ /* Check pixel format */
+ if (var->nonstd > 1) {
+ IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
+ return -EINVAL;
+ }
+
+ /* Check video mode */
+ if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
+ ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
+ IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
+ return -EINVAL;
+ }
+
+ /* Check the left & upper margins
+ If the margins are too large, just center the screen
+ (enforcing margins causes too many problems) */
+
+ if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
+ var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
+ }
+ if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
+ var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
+ }
+
+ /* Maintain overall 'size' for a constant refresh rate */
+ var->right_margin = hlimit - var->left_margin - var->xres;
+ var->lower_margin = vlimit - var->upper_margin - var->yres;
+
+ /* Fixed sync times */
+ var->hsync_len = 24;
+ var->vsync_len = 2;
+
+ /* Non-interlaced / interlaced mode is used to switch the OSD filter
+ on or off. Adjust the clock timings to maintain a constant
+ vertical refresh rate. */
+ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
+ var->pixclock = pixclock / 2;
+ else
+ var->pixclock = pixclock;
+
+ IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
+ var->xres, var->yres,
+ var->xres_virtual, var->yres_virtual,
+ var->bits_per_pixel);
+
+ IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
+ var->left_margin, var->upper_margin);
+
+ IVTVFB_DEBUG_INFO("Display filter: %s\n",
+ (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
+ IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
+ return 0;
+}
+
+static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct ivtv *itv = (struct ivtv *) info->par;
+ IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
+ return _ivtvfb_check_var(var, itv);
+}
+
+static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ u32 osd_pan_index;
+ struct ivtv *itv = (struct ivtv *) info->par;
+
+ osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
+ write_reg(osd_pan_index, 0x02A0C);
+
+ /* Pass this info back the yuv handler */
+ itv->yuv_info.osd_x_pan = var->xoffset;
+ itv->yuv_info.osd_y_pan = var->yoffset;
+ /* Force update of yuv registers */
+ itv->yuv_info.yuv_forced_update = 1;
+ return 0;
+}
+
+static int ivtvfb_set_par(struct fb_info *info)
+{
+ int rc = 0;
+ struct ivtv *itv = (struct ivtv *) info->par;
+
+ IVTVFB_DEBUG_INFO("ivtvfb_set_par\n");
+
+ rc = ivtvfb_set_var(itv, &info->var);
+ ivtvfb_pan_display(&info->var, info);
+ ivtvfb_get_fix(itv, &info->fix);
+ return rc;
+}
+
+static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ u32 color, *palette;
+ struct ivtv *itv = (struct ivtv *)info->par;
+
+ if (regno >= info->cmap.len)
+ return -EINVAL;
+
+ color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+ if (info->var.bits_per_pixel <= 8) {
+ write_reg(regno, 0x02a30);
+ write_reg(color, 0x02a34);
+ return 0;
+ }
+ if (regno >= 16)
+ return -EINVAL;
+
+ palette = info->pseudo_palette;
+ if (info->var.bits_per_pixel == 16) {
+ switch (info->var.green.length) {
+ case 4:
+ color = ((red & 0xf000) >> 4) |
+ ((green & 0xf000) >> 8) |
+ ((blue & 0xf000) >> 12);
+ break;
+ case 5:
+ color = ((red & 0xf800) >> 1) |
+ ((green & 0xf800) >> 6) |
+ ((blue & 0xf800) >> 11);
+ break;
+ case 6:
+ color = (red & 0xf800 ) |
+ ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11);
+ break;
+ }
+ }
+ palette[regno] = color;
+ return 0;
+}
+
+/* We don't really support blanking. All this does is enable or
+ disable the OSD. */
+static int ivtvfb_blank(int blank_mode, struct fb_info *info)
+{
+ struct ivtv *itv = (struct ivtv *)info->par;
+
+ IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
+ break;
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_POWERDOWN:
+ ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
+ break;
+ }
+ return 0;
+}
+
+static struct fb_ops ivtvfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = ivtvfb_check_var,
+ .fb_set_par = ivtvfb_set_par,
+ .fb_setcolreg = ivtvfb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_cursor = NULL,
+ .fb_ioctl = ivtvfb_ioctl,
+ .fb_pan_display = ivtvfb_pan_display,
+ .fb_blank = ivtvfb_blank,
+};
+
+/* Initialization */
+
+
+/* Setup our initial video mode */
+static int ivtvfb_init_vidmode(struct ivtv *itv)
+{
+ struct osd_info *oi = itv->osd_info;
+ struct v4l2_rect start_window;
+ int max_height;
+
+ /* Color mode */
+
+ if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32)
+ osd_depth = 8;
+ oi->bits_per_pixel = osd_depth;
+ oi->bytes_per_pixel = oi->bits_per_pixel / 8;
+
+ /* Horizontal size & position */
+
+ if (osd_xres > 720)
+ osd_xres = 720;
+
+ /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
+ if (osd_depth == 8)
+ osd_xres &= ~3;
+ else if (osd_depth == 16)
+ osd_xres &= ~1;
+
+ start_window.width = osd_xres ? osd_xres : 640;
+
+ /* Check horizontal start (osd_left). */
+ if (osd_left && osd_left + start_window.width > 721) {
+ IVTVFB_ERR("Invalid osd_left - assuming default\n");
+ osd_left = 0;
+ }
+
+ /* Hardware coords start at 0, user coords start at 1. */
+ osd_left--;
+
+ start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
+
+ oi->display_byte_stride =
+ start_window.width * oi->bytes_per_pixel;
+
+ /* Vertical size & position */
+
+ max_height = itv->is_50hz ? 576 : 480;
+
+ if (osd_yres > max_height)
+ osd_yres = max_height;
+
+ start_window.height = osd_yres ? osd_yres : itv->is_50hz ? 480 : 400;
+
+ /* Check vertical start (osd_upper). */
+ if (osd_upper + start_window.height > max_height + 1) {
+ IVTVFB_ERR("Invalid osd_upper - assuming default\n");
+ osd_upper = 0;
+ }
+
+ /* Hardware coords start at 0, user coords start at 1. */
+ osd_upper--;
+
+ start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
+
+ oi->display_width = start_window.width;
+ oi->display_height = start_window.height;
+
+ /* Generate a valid fb_var_screeninfo */
+
+ oi->ivtvfb_defined.xres = oi->display_width;
+ oi->ivtvfb_defined.yres = oi->display_height;
+ oi->ivtvfb_defined.xres_virtual = oi->display_width;
+ oi->ivtvfb_defined.yres_virtual = oi->display_height;
+ oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
+ oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
+ oi->ivtvfb_defined.left_margin = start_window.left + 1;
+ oi->ivtvfb_defined.upper_margin = start_window.top + 1;
+ oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
+ oi->ivtvfb_defined.nonstd = 0;
+
+ /* We've filled in the most data, let the usual mode check
+ routine fill in the rest. */
+ _ivtvfb_check_var(&oi->ivtvfb_defined, itv);
+
+ /* Generate valid fb_fix_screeninfo */
+
+ ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
+
+ /* Generate valid fb_info */
+
+ oi->ivtvfb_info.node = -1;
+ oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
+ oi->ivtvfb_info.fbops = &ivtvfb_ops;
+ oi->ivtvfb_info.par = itv;
+ oi->ivtvfb_info.var = oi->ivtvfb_defined;
+ oi->ivtvfb_info.fix = oi->ivtvfb_fix;
+ oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
+ oi->ivtvfb_info.fbops = &ivtvfb_ops;
+
+ /* Supply some monitor specs. Bogus values will do for now */
+ oi->ivtvfb_info.monspecs.hfmin = 8000;
+ oi->ivtvfb_info.monspecs.hfmax = 70000;
+ oi->ivtvfb_info.monspecs.vfmin = 10;
+ oi->ivtvfb_info.monspecs.vfmax = 100;
+
+ /* Allocate color map */
+ if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
+ IVTVFB_ERR("abort, unable to alloc cmap\n");
+ return -ENOMEM;
+ }
+
+ /* Allocate the pseudo palette */
+ oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+
+ if (!oi->ivtvfb_info.pseudo_palette) {
+ IVTVFB_ERR("abort, unable to alloc pseudo pallete\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
+
+static int ivtvfb_init_io(struct ivtv *itv)
+{
+ struct osd_info *oi = itv->osd_info;
+
+ mutex_lock(&itv->serialize_lock);
+ if (ivtv_init_on_first_open(itv)) {
+ mutex_unlock(&itv->serialize_lock);
+ IVTVFB_ERR("Failed to initialize ivtv\n");
+ return -ENXIO;
+ }
+ mutex_unlock(&itv->serialize_lock);
+
+ ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
+
+ /* The osd buffer size depends on the number of video buffers allocated
+ on the PVR350 itself. For now we'll hardcode the smallest osd buffer
+ size to prevent any overlap. */
+ oi->video_buffer_size = 1704960;
+
+ oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
+ oi->video_vbase = itv->dec_mem + oi->video_rbase;
+
+ if (!oi->video_vbase) {
+ IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
+ oi->video_buffer_size, oi->video_pbase);
+ return -EIO;
+ }
+
+ IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+ oi->video_pbase, oi->video_vbase,
+ oi->video_buffer_size / 1024);
+
+#ifdef CONFIG_MTRR
+ {
+ /* Find the largest power of two that maps the whole buffer */
+ int size_shift = 31;
+
+ while (!(oi->video_buffer_size & (1 << size_shift))) {
+ size_shift--;
+ }
+ size_shift++;
+ oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
+ oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
+ oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
+ oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
+ if (mtrr_add(oi->fb_start_aligned_physaddr,
+ oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
+ MTRR_TYPE_WRCOMB, 1) < 0) {
+ IVTVFB_INFO("disabled mttr\n");
+ oi->fb_start_aligned_physaddr = 0;
+ oi->fb_end_aligned_physaddr = 0;
+ }
+ }
+#endif
+
+ /* Blank the entire osd. */
+ memset_io(oi->video_vbase, 0, oi->video_buffer_size);
+
+ return 0;
+}
+
+/* Release any memory we've grabbed & remove mtrr entry */
+static void ivtvfb_release_buffers (struct ivtv *itv)
+{
+ struct osd_info *oi = itv->osd_info;
+
+ /* Release cmap */
+ if (oi->ivtvfb_info.cmap.len)
+ fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
+
+ /* Release pseudo palette */
+ if (oi->ivtvfb_info.pseudo_palette)
+ kfree(oi->ivtvfb_info.pseudo_palette);
+
+#ifdef CONFIG_MTRR
+ if (oi->fb_end_aligned_physaddr) {
+ mtrr_del(-1, oi->fb_start_aligned_physaddr,
+ oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
+ }
+#endif
+
+ kfree(oi);
+ itv->osd_info = NULL;
+}
+
+/* Initialize the specified card */
+
+static int ivtvfb_init_card(struct ivtv *itv)
+{
+ int rc;
+
+ if (itv->osd_info) {
+ IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id);
+ return -EBUSY;
+ }
+
+ itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
+ if (itv->osd_info == 0) {
+ IVTVFB_ERR("Failed to allocate memory for osd_info\n");
+ return -ENOMEM;
+ }
+
+ /* Find & setup the OSD buffer */
+ if ((rc = ivtvfb_init_io(itv)))
+ return rc;
+
+ /* Set the startup video mode information */
+ if ((rc = ivtvfb_init_vidmode(itv))) {
+ ivtvfb_release_buffers(itv);
+ return rc;
+ }
+
+ /* Register the framebuffer */
+ if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
+ ivtvfb_release_buffers(itv);
+ return -EINVAL;
+ }
+
+ itv->osd_video_pbase = itv->osd_info->video_pbase;
+
+ /* Set the card to the requested mode */
+ ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
+
+ /* Set color 0 to black */
+ write_reg(0, 0x02a30);
+ write_reg(0, 0x02a34);
+
+ /* Enable the osd */
+ ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
+
+ /* Allocate DMA */
+ ivtv_udma_alloc(itv);
+ return 0;
+
+}
+
+static int __init ivtvfb_init(void)
+{
+ struct ivtv *itv;
+ int i, registered = 0;
+
+ if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
+ printk(KERN_ERR "ivtvfb: ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
+ IVTV_MAX_CARDS - 1);
+ return -EINVAL;
+ }
+
+ /* Locate & initialise all cards supporting an OSD. */
+ for (i = 0; i < ivtv_cards_active; i++) {
+ if (ivtvfb_card_id != -1 && i != ivtvfb_card_id)
+ continue;
+ itv = ivtv_cards[i];
+ if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+ if (ivtvfb_init_card(itv) == 0) {
+ IVTVFB_INFO("Framebuffer registered on ivtv card id %d\n", i);
+ registered++;
+ }
+ }
+ }
+ if (!registered) {
+ printk(KERN_ERR "ivtvfb: no cards found");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void ivtvfb_cleanup(void)
+{
+ struct ivtv *itv;
+ int i;
+
+ printk(KERN_INFO "ivtvfb: Unloading framebuffer module\n");
+
+ for (i = 0; i < ivtv_cards_active; i++) {
+ itv = ivtv_cards[i];
+ if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
+ if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
+ IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n", i);
+ return;
+ }
+ IVTVFB_DEBUG_INFO("Unregister framebuffer %d\n", i);
+ ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
+ ivtvfb_release_buffers(itv);
+ itv->osd_video_pbase = 0;
+ }
+ }
+}
+
+module_init(ivtvfb_init);
+module_exit(ivtvfb_cleanup);
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 7533fc20331..c3116329043 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
*
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
*
* Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
*
@@ -1762,7 +1762,6 @@ static struct video_device meye_template = {
.owner = THIS_MODULE,
.name = "meye",
.type = VID_TYPE_CAPTURE,
- .hardware = VID_HARDWARE_MEYE,
.fops = &meye_fops,
.release = video_device_release,
.minor = -1,
diff --git a/drivers/media/video/meye.h b/drivers/media/video/meye.h
index 323d0074120..d535748df44 100644
--- a/drivers/media/video/meye.h
+++ b/drivers/media/video/meye.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
*
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
*
* Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
*
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 11cfcf18ec3..c0c87e06259 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -244,17 +244,17 @@ int msp_write_dsp(struct i2c_client *client, int addr, int val)
* ----------------------------------------------------------------------- */
static int scarts[3][9] = {
- /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */
+ /* MASK IN1 IN2 IN3 IN4 IN1_DA IN2_DA MONO MUTE */
/* SCART DSP Input select */
- { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 },
+ { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1, -1, 0x0100, 0x0320 },
/* SCART1 Output select */
- { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 },
+ { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 },
/* SCART2 Output select */
- { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 },
+ { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 },
};
static char *scart_names[] = {
- "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute"
+ "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute"
};
void msp_set_scart(struct i2c_client *client, int in, int out)
@@ -813,8 +813,9 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
int msp_rom;
client = kzalloc(sizeof(*client), GFP_KERNEL);
- if (client == NULL)
+ if (!client)
return -ENOMEM;
+
client->addr = address;
client->adapter = adapter;
client->driver = &i2c_driver;
@@ -826,14 +827,14 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
return 0;
}
- state = kmalloc(sizeof(*state), GFP_KERNEL);
- if (state == NULL) {
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state) {
kfree(client);
return -ENOMEM;
}
+
i2c_set_clientdata(client, state);
- memset(state, 0, sizeof(*state));
state->v4l2_std = V4L2_STD_NTSC;
state->audmode = V4L2_TUNER_MODE_STEREO;
state->volume = 58880; /* 0db gain */
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index 7549114aaac..f49d1f4c40d 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -1,13 +1,20 @@
/*
- *
* i2c tv tuner chip device driver
* controls microtune tuners, mt2032 + mt2050 at the moment.
+ *
+ * This "mt20xx" module was split apart from the original "tuner" module.
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/videodev.h>
-#include <linux/moduleparam.h>
-#include "tuner-driver.h"
+#include "tuner-i2c.h"
+#include "mt20xx.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define PREFIX "mt20xx "
/* ---------------------------------------------------------------------- */
@@ -20,9 +27,6 @@ module_param(tv_antenna, int, 0644);
static unsigned int radio_antenna = 0;
module_param(radio_antenna, int, 0644);
-/* from tuner-core.c */
-extern int tuner_debug;
-
/* ---------------------------------------------------------------------- */
#define MT2032 0x04
@@ -38,23 +42,34 @@ static char *microtune_part[] = {
};
struct microtune_priv {
+ struct tuner_i2c_props i2c_props;
+
unsigned int xogc;
- unsigned int radio_if2;
+ //unsigned int radio_if2;
+
+ u32 frequency;
};
-static void microtune_release(struct i2c_client *c)
+static int microtune_release(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
- kfree(t->priv);
- t->priv = NULL;
+ return 0;
+}
+
+static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct microtune_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
}
// IsSpurInBand()?
-static int mt2032_spurcheck(struct i2c_client *c,
+static int mt2032_spurcheck(struct dvb_frontend *fe,
int f1, int f2, int spectrum_from,int spectrum_to)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
int n1=1,n2,f;
f1=f1/1000; //scale to kHz to avoid 32bit overflows
@@ -82,7 +97,7 @@ static int mt2032_spurcheck(struct i2c_client *c,
return 1;
}
-static int mt2032_compute_freq(struct i2c_client *c,
+static int mt2032_compute_freq(struct dvb_frontend *fe,
unsigned int rfin,
unsigned int if1, unsigned int if2,
unsigned int spectrum_from,
@@ -91,7 +106,7 @@ static int mt2032_compute_freq(struct i2c_client *c,
int *ret_sel,
unsigned int xogc) //all in Hz
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
@@ -141,7 +156,7 @@ static int mt2032_compute_freq(struct i2c_client *c,
return(-1);
}
- mt2032_spurcheck(c, lo1freq, desired_lo2, spectrum_from, spectrum_to);
+ mt2032_spurcheck(fe, lo1freq, desired_lo2, spectrum_from, spectrum_to);
// should recalculate lo1 (one step up/down)
// set up MT2032 register map for transfer over i2c
@@ -165,16 +180,16 @@ static int mt2032_compute_freq(struct i2c_client *c,
return 0;
}
-static int mt2032_check_lo_lock(struct i2c_client *c)
+static int mt2032_check_lo_lock(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
int try,lock=0;
unsigned char buf[2];
for(try=0;try<10;try++) {
buf[0]=0x0e;
- i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,1);
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+ tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]);
lock=buf[0] &0x06;
@@ -187,15 +202,15 @@ static int mt2032_check_lo_lock(struct i2c_client *c)
return lock;
}
-static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
+static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
unsigned char buf[2];
int tad1;
buf[0]=0x0f;
- i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,1);
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+ tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]);
tad1=buf[0]&0x07;
@@ -218,58 +233,57 @@ static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
buf[0]=0x0f;
buf[1]=sel;
- i2c_master_send(c,buf,2);
- lock=mt2032_check_lo_lock(c);
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
+ lock=mt2032_check_lo_lock(fe);
return lock;
}
-static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
+static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin,
unsigned int if1, unsigned int if2,
unsigned int from, unsigned int to)
{
unsigned char buf[21];
int lint_try,ret,sel,lock=0;
- struct tuner *t = i2c_get_clientdata(c);
- struct microtune_priv *priv = t->priv;
+ struct microtune_priv *priv = fe->tuner_priv;
tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
rfin,if1,if2,from,to);
buf[0]=0;
- ret=i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,21);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+ tuner_i2c_xfer_recv(&priv->i2c_props,buf,21);
buf[0]=0;
- ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc);
+ ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc);
if (ret<0)
return;
// send only the relevant registers per Rev. 1.2
buf[0]=0;
- ret=i2c_master_send(c,buf,4);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4);
buf[5]=5;
- ret=i2c_master_send(c,buf+5,4);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4);
buf[11]=11;
- ret=i2c_master_send(c,buf+11,3);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3);
if(ret!=3)
tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret);
// wait for PLLs to lock (per manual), retry LINT if not.
for(lint_try=0; lint_try<2; lint_try++) {
- lock=mt2032_check_lo_lock(c);
+ lock=mt2032_check_lo_lock(fe);
if(optimize_vco)
- lock=mt2032_optimize_vco(c,sel,lock);
+ lock=mt2032_optimize_vco(fe,sel,lock);
if(lock==6) break;
tuner_dbg("mt2032: re-init PLLs by LINT\n");
buf[0]=7;
buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs
- i2c_master_send(c,buf,2);
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
mdelay(10);
buf[1]=8+priv->xogc;
- i2c_master_send(c,buf,2);
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
}
if (lock!=6)
@@ -277,19 +291,19 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
buf[0]=2;
buf[1]=0x20; // LOGC for optimal phase noise
- ret=i2c_master_send(c,buf,2);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
if (ret!=2)
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
}
-static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
+static int mt2032_set_tv_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
int if2,from,to;
// signal bandwidth and picture carrier
- if (t->std & V4L2_STD_525_60) {
+ if (params->std & V4L2_STD_525_60) {
// NTSC
from = 40750*1000;
to = 46750*1000;
@@ -301,32 +315,64 @@ static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
if2 = 38900*1000;
}
- mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+ mt2032_set_if_freq(fe, params->frequency*62500,
1090*1000*1000, if2, from, to);
+
+ return 0;
}
-static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
+static int mt2032_set_radio_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
- struct microtune_priv *priv = t->priv;
- int if2 = priv->radio_if2;
+ struct microtune_priv *priv = fe->tuner_priv;
+ int if2;
+
+ if (params->std & V4L2_STD_525_60) {
+ tuner_dbg("pinnacle ntsc\n");
+ if2 = 41300 * 1000;
+ } else {
+ tuner_dbg("pinnacle pal\n");
+ if2 = 33300 * 1000;
+ }
// per Manual for FM tuning: first if center freq. 1085 MHz
- mt2032_set_if_freq(c, freq * 1000 / 16,
- 1085*1000*1000,if2,if2,if2);
+ mt2032_set_if_freq(fe, params->frequency * 125 / 2,
+ 1085*1000*1000,if2,if2,if2);
+
+ return 0;
+}
+
+static int mt2032_set_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct microtune_priv *priv = fe->tuner_priv;
+ int ret = -EINVAL;
+
+ switch (params->mode) {
+ case V4L2_TUNER_RADIO:
+ ret = mt2032_set_radio_freq(fe, params);
+ priv->frequency = params->frequency * 125 / 2;
+ break;
+ case V4L2_TUNER_ANALOG_TV:
+ case V4L2_TUNER_DIGITAL_TV:
+ ret = mt2032_set_tv_freq(fe, params);
+ priv->frequency = params->frequency * 62500;
+ break;
+ }
+
+ return ret;
}
-static struct tuner_operations mt2032_tuner_ops = {
- .set_tv_freq = mt2032_set_tv_freq,
- .set_radio_freq = mt2032_set_radio_freq,
- .release = microtune_release,
+static struct dvb_tuner_ops mt2032_tuner_ops = {
+ .set_analog_params = mt2032_set_params,
+ .release = microtune_release,
+ .get_frequency = microtune_get_frequency,
};
// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
-static int mt2032_init(struct i2c_client *c)
+static int mt2032_init(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
- struct microtune_priv *priv = t->priv;
+ struct microtune_priv *priv = fe->tuner_priv;
unsigned char buf[21];
int ret,xogc,xok=0;
@@ -335,7 +381,7 @@ static int mt2032_init(struct i2c_client *c)
buf[2]=0xff;
buf[3]=0x0f;
buf[4]=0x1f;
- ret=i2c_master_send(c,buf+1,4);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4);
buf[5]=6; // Index register 6
buf[6]=0xe4;
@@ -343,11 +389,11 @@ static int mt2032_init(struct i2c_client *c)
buf[8]=0xc3;
buf[9]=0x4e;
buf[10]=0xec;
- ret=i2c_master_send(c,buf+5,6);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6);
buf[12]=13; // Index register 13
buf[13]=0x32;
- ret=i2c_master_send(c,buf+12,2);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2);
// Adjust XOGC (register 7), wait for XOK
xogc=7;
@@ -355,8 +401,8 @@ static int mt2032_init(struct i2c_client *c)
tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
mdelay(10);
buf[0]=0x0e;
- i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,1);
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+ tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
xok=buf[0]&0x01;
tuner_dbg("mt2032: xok = 0x%02x\n",xok);
if (xok == 1) break;
@@ -369,32 +415,32 @@ static int mt2032_init(struct i2c_client *c)
}
buf[0]=0x07;
buf[1]=0x88 + xogc;
- ret=i2c_master_send(c,buf,2);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
if (ret!=2)
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
} while (xok != 1 );
priv->xogc=xogc;
- memcpy(&t->ops, &mt2032_tuner_ops, sizeof(struct tuner_operations));
+ memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops));
return(1);
}
-static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
+static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
unsigned char buf[2];
int ret;
buf[0] = 6;
buf[1] = antenna ? 0x11 : 0x10;
- ret=i2c_master_send(c,buf,2);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
}
-static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2)
+static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
unsigned int if1=1218*1000*1000;
unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b;
int ret;
@@ -426,7 +472,7 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
div2a=(lo2/8)-1;
div2b=lo2-(div2a+1)*8;
- if (tuner_debug > 1) {
+ if (debug > 1) {
tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2);
tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",
num1,num2,div1a,div1b,div2a,div2b);
@@ -442,7 +488,7 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
buf[5]=div2a;
if(num2!=0) buf[5]=buf[5]|0x40;
- if (tuner_debug > 1) {
+ if (debug > 1) {
int i;
tuner_dbg("bufs is: ");
for(i=0;i<6;i++)
@@ -450,101 +496,131 @@ static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned
printk("\n");
}
- ret=i2c_master_send(c,buf,6);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6);
if (ret!=6)
tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret);
}
-static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq)
+static int mt2050_set_tv_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
unsigned int if2;
- if (t->std & V4L2_STD_525_60) {
+ if (params->std & V4L2_STD_525_60) {
// NTSC
if2 = 45750*1000;
} else {
// PAL
if2 = 38900*1000;
}
- if (V4L2_TUNER_DIGITAL_TV == t->mode) {
+ if (V4L2_TUNER_DIGITAL_TV == params->mode) {
// DVB (pinnacle 300i)
if2 = 36150*1000;
}
- mt2050_set_if_freq(c, freq*62500, if2);
- mt2050_set_antenna(c, tv_antenna);
+ mt2050_set_if_freq(fe, params->frequency*62500, if2);
+ mt2050_set_antenna(fe, tv_antenna);
+
+ return 0;
}
-static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq)
+static int mt2050_set_radio_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
- struct microtune_priv *priv = t->priv;
- int if2 = priv->radio_if2;
+ struct microtune_priv *priv = fe->tuner_priv;
+ int if2;
+
+ if (params->std & V4L2_STD_525_60) {
+ tuner_dbg("pinnacle ntsc\n");
+ if2 = 41300 * 1000;
+ } else {
+ tuner_dbg("pinnacle pal\n");
+ if2 = 33300 * 1000;
+ }
- mt2050_set_if_freq(c, freq * 1000 / 16, if2);
- mt2050_set_antenna(c, radio_antenna);
+ mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2);
+ mt2050_set_antenna(fe, radio_antenna);
+
+ return 0;
}
-static struct tuner_operations mt2050_tuner_ops = {
- .set_tv_freq = mt2050_set_tv_freq,
- .set_radio_freq = mt2050_set_radio_freq,
- .release = microtune_release,
+static int mt2050_set_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct microtune_priv *priv = fe->tuner_priv;
+ int ret = -EINVAL;
+
+ switch (params->mode) {
+ case V4L2_TUNER_RADIO:
+ ret = mt2050_set_radio_freq(fe, params);
+ priv->frequency = params->frequency * 125 / 2;
+ break;
+ case V4L2_TUNER_ANALOG_TV:
+ case V4L2_TUNER_DIGITAL_TV:
+ ret = mt2050_set_tv_freq(fe, params);
+ priv->frequency = params->frequency * 62500;
+ break;
+ }
+
+ return ret;
+}
+
+static struct dvb_tuner_ops mt2050_tuner_ops = {
+ .set_analog_params = mt2050_set_params,
+ .release = microtune_release,
+ .get_frequency = microtune_get_frequency,
};
-static int mt2050_init(struct i2c_client *c)
+static int mt2050_init(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = fe->tuner_priv;
unsigned char buf[2];
int ret;
buf[0]=6;
buf[1]=0x10;
- ret=i2c_master_send(c,buf,2); // power
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // power
buf[0]=0x0f;
buf[1]=0x0f;
- ret=i2c_master_send(c,buf,2); // m1lo
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo
buf[0]=0x0d;
- ret=i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,1);
+ ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+ tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
tuner_dbg("mt2050: sro is %x\n",buf[0]);
- memcpy(&t->ops, &mt2050_tuner_ops, sizeof(struct tuner_operations));
+ memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops));
return 0;
}
-int microtune_init(struct i2c_client *c)
+struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
{
struct microtune_priv *priv = NULL;
- struct tuner *t = i2c_get_clientdata(c);
char *name;
unsigned char buf[21];
int company_code;
priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL);
if (priv == NULL)
- return -ENOMEM;
- t->priv = priv;
+ return NULL;
+ fe->tuner_priv = priv;
+
+ priv->i2c_props.addr = i2c_addr;
+ priv->i2c_props.adap = i2c_adap;
- priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
+ //priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
memset(buf,0,sizeof(buf));
- if (t->std & V4L2_STD_525_60) {
- tuner_dbg("pinnacle ntsc\n");
- priv->radio_if2 = 41300 * 1000;
- } else {
- tuner_dbg("pinnacle pal\n");
- priv->radio_if2 = 33300 * 1000;
- }
name = "unknown";
- i2c_master_send(c,buf,1);
- i2c_master_recv(c,buf,21);
- if (tuner_debug) {
+ tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+ tuner_i2c_xfer_recv(&priv->i2c_props,buf,21);
+ if (debug) {
int i;
tuner_dbg("MT20xx hexdump:");
for(i=0;i<21;i++) {
@@ -563,10 +639,10 @@ int microtune_init(struct i2c_client *c)
name = microtune_part[buf[0x13]];
switch (buf[0x13]) {
case MT2032:
- mt2032_init(c);
+ mt2032_init(fe);
break;
case MT2050:
- mt2050_init(c);
+ mt2050_init(fe);
break;
default:
tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n",
@@ -574,11 +650,18 @@ int microtune_init(struct i2c_client *c)
return 0;
}
- strlcpy(c->name, name, sizeof(c->name));
+ strlcpy(fe->ops.tuner_ops.info.name, name,
+ sizeof(fe->ops.tuner_ops.info.name));
tuner_info("microtune %s found, OK\n",name);
- return 0;
+ return fe;
}
+EXPORT_SYMBOL_GPL(microtune_attach);
+
+MODULE_DESCRIPTION("Microtune tuner driver");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff --git a/drivers/media/video/mt20xx.h b/drivers/media/video/mt20xx.h
new file mode 100644
index 00000000000..5e9c825d2e9
--- /dev/null
+++ b/drivers/media/video/mt20xx.h
@@ -0,0 +1,37 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __MT20XX_H__
+#define __MT20XX_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_TUNER_MT20XX) || (defined(CONFIG_TUNER_MT20XX_MODULE) && defined(MODULE))
+extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr);
+#else
+static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif
+
+#endif /* __MT20XX_H__ */
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 152cc6b3e15..98ad3092a07 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -153,7 +153,6 @@ static int mxb_probe(struct saa7146_dev* dev)
{
struct mxb* mxb = NULL;
struct i2c_client *client;
- struct list_head *item;
int result;
if ((result = request_module("saa7111")) < 0) {
@@ -196,8 +195,7 @@ static int mxb_probe(struct saa7146_dev* dev)
}
/* loop through all i2c-devices on the bus and look who is there */
- list_for_each(item,&mxb->i2c_adapter.clients) {
- client = list_entry(item, struct i2c_client, list);
+ list_for_each_entry(client, &mxb->i2c_adapter.clients, list) {
if( I2C_ADDR_TEA6420_1 == client->addr )
mxb->tea6420_1 = client;
if( I2C_ADDR_TEA6420_2 == client->addr )
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index e5edff1059a..d55d5800efb 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -181,7 +181,7 @@ module_param(force_palette, int, 0);
MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
module_param(backlight, int, 0);
MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
-static int num_uv;
+static unsigned int num_uv;
module_param_array(unit_video, int, &num_uv, 0);
MODULE_PARM_DESC(unit_video,
"Force use of specific minor number(s). 0 is not allowed.");
@@ -4668,7 +4668,6 @@ static struct video_device vdev_template = {
.owner = THIS_MODULE,
.name = "OV511 USB Camera",
.type = VID_TYPE_CAPTURE,
- .hardware = VID_HARDWARE_OV511,
.fops = &ov511_fops,
.release = video_device_release,
.minor = -1,
@@ -5554,41 +5553,46 @@ error:
* sysfs
***************************************************************************/
-static inline struct usb_ov511 *cd_to_ov(struct class_device *cd)
+static inline struct usb_ov511 *cd_to_ov(struct device *cd)
{
struct video_device *vdev = to_video_device(cd);
return video_get_drvdata(vdev);
}
-static ssize_t show_custom_id(struct class_device *cd, char *buf)
+static ssize_t show_custom_id(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
return sprintf(buf, "%d\n", ov->customid);
}
-static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
+static DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
-static ssize_t show_model(struct class_device *cd, char *buf)
+static ssize_t show_model(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
return sprintf(buf, "%s\n", ov->desc);
}
-static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
-static ssize_t show_bridge(struct class_device *cd, char *buf)
+static ssize_t show_bridge(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge));
}
-static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
+static DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
-static ssize_t show_sensor(struct class_device *cd, char *buf)
+static ssize_t show_sensor(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor));
}
-static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
+static DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
-static ssize_t show_brightness(struct class_device *cd, char *buf)
+static ssize_t show_brightness(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
unsigned short x;
@@ -5598,9 +5602,10 @@ static ssize_t show_brightness(struct class_device *cd, char *buf)
sensor_get_brightness(ov, &x);
return sprintf(buf, "%d\n", x >> 8);
}
-static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
+static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
-static ssize_t show_saturation(struct class_device *cd, char *buf)
+static ssize_t show_saturation(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
unsigned short x;
@@ -5610,9 +5615,10 @@ static ssize_t show_saturation(struct class_device *cd, char *buf)
sensor_get_saturation(ov, &x);
return sprintf(buf, "%d\n", x >> 8);
}
-static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
+static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
-static ssize_t show_contrast(struct class_device *cd, char *buf)
+static ssize_t show_contrast(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
unsigned short x;
@@ -5622,9 +5628,10 @@ static ssize_t show_contrast(struct class_device *cd, char *buf)
sensor_get_contrast(ov, &x);
return sprintf(buf, "%d\n", x >> 8);
}
-static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
+static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
-static ssize_t show_hue(struct class_device *cd, char *buf)
+static ssize_t show_hue(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
unsigned short x;
@@ -5634,9 +5641,10 @@ static ssize_t show_hue(struct class_device *cd, char *buf)
sensor_get_hue(ov, &x);
return sprintf(buf, "%d\n", x >> 8);
}
-static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
+static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
-static ssize_t show_exposure(struct class_device *cd, char *buf)
+static ssize_t show_exposure(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct usb_ov511 *ov = cd_to_ov(cd);
unsigned char exp = 0;
@@ -5646,49 +5654,49 @@ static ssize_t show_exposure(struct class_device *cd, char *buf)
sensor_get_exposure(ov, &exp);
return sprintf(buf, "%d\n", exp >> 8);
}
-static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
+static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
static int ov_create_sysfs(struct video_device *vdev)
{
int rc;
- rc = video_device_create_file(vdev, &class_device_attr_custom_id);
+ rc = video_device_create_file(vdev, &dev_attr_custom_id);
if (rc) goto err;
- rc = video_device_create_file(vdev, &class_device_attr_model);
+ rc = video_device_create_file(vdev, &dev_attr_model);
if (rc) goto err_id;
- rc = video_device_create_file(vdev, &class_device_attr_bridge);
+ rc = video_device_create_file(vdev, &dev_attr_bridge);
if (rc) goto err_model;
- rc = video_device_create_file(vdev, &class_device_attr_sensor);
+ rc = video_device_create_file(vdev, &dev_attr_sensor);
if (rc) goto err_bridge;
- rc = video_device_create_file(vdev, &class_device_attr_brightness);
+ rc = video_device_create_file(vdev, &dev_attr_brightness);
if (rc) goto err_sensor;
- rc = video_device_create_file(vdev, &class_device_attr_saturation);
+ rc = video_device_create_file(vdev, &dev_attr_saturation);
if (rc) goto err_bright;
- rc = video_device_create_file(vdev, &class_device_attr_contrast);
+ rc = video_device_create_file(vdev, &dev_attr_contrast);
if (rc) goto err_sat;
- rc = video_device_create_file(vdev, &class_device_attr_hue);
+ rc = video_device_create_file(vdev, &dev_attr_hue);
if (rc) goto err_contrast;
- rc = video_device_create_file(vdev, &class_device_attr_exposure);
+ rc = video_device_create_file(vdev, &dev_attr_exposure);
if (rc) goto err_hue;
return 0;
err_hue:
- video_device_remove_file(vdev, &class_device_attr_hue);
+ video_device_remove_file(vdev, &dev_attr_hue);
err_contrast:
- video_device_remove_file(vdev, &class_device_attr_contrast);
+ video_device_remove_file(vdev, &dev_attr_contrast);
err_sat:
- video_device_remove_file(vdev, &class_device_attr_saturation);
+ video_device_remove_file(vdev, &dev_attr_saturation);
err_bright:
- video_device_remove_file(vdev, &class_device_attr_brightness);
+ video_device_remove_file(vdev, &dev_attr_brightness);
err_sensor:
- video_device_remove_file(vdev, &class_device_attr_sensor);
+ video_device_remove_file(vdev, &dev_attr_sensor);
err_bridge:
- video_device_remove_file(vdev, &class_device_attr_bridge);
+ video_device_remove_file(vdev, &dev_attr_bridge);
err_model:
- video_device_remove_file(vdev, &class_device_attr_model);
+ video_device_remove_file(vdev, &dev_attr_model);
err_id:
- video_device_remove_file(vdev, &class_device_attr_custom_id);
+ video_device_remove_file(vdev, &dev_attr_custom_id);
err:
return rc;
}
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index c4c5bd67f79..2bc6bdc9c1f 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -12,7 +12,6 @@
*/
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
index 3fe9fa04cd8..8063e33f1c8 100644
--- a/drivers/media/video/ovcamchip/ovcamchip_core.c
+++ b/drivers/media/video/ovcamchip/ovcamchip_core.c
@@ -13,7 +13,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include "ovcamchip_priv.h"
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index 4ab1af74a97..36047d4e70f 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -91,7 +91,6 @@ static void planb_close(struct video_device *);
static int planb_ioctl(struct video_device *, unsigned int, void *);
static int planb_init_done(struct video_device *);
static int planb_mmap(struct video_device *, const char *, unsigned long);
-static void planb_irq(int, void *);
static void release_planb(void);
int init_planbs(struct video_init *);
@@ -844,21 +843,21 @@ cmd_tab_mask_end:
/*********************************/
static int palette2fmt[] = {
- 0,
- PLANB_GRAY,
- 0,
- 0,
- 0,
- PLANB_COLOUR32,
- PLANB_COLOUR15,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
+ 0,
+ PLANB_GRAY,
+ 0,
+ 0,
+ 0,
+ PLANB_COLOUR32,
+ PLANB_COLOUR15,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
};
#define PLANB_PALETTE_MAX 15
@@ -1315,7 +1314,7 @@ cmd_tab_data_end:
return c1;
}
-static void planb_irq(int irq, void *dev_id)
+static irqreturn_t planb_irq(int irq, void *dev_id)
{
unsigned int stat, astat;
struct planb *pb = (struct planb *)dev_id;
@@ -1358,13 +1357,14 @@ static void planb_irq(int irq, void *dev_id)
pb->frame_stat[fr] = GBUFFER_DONE;
pb->grabbing--;
wake_up_interruptible(&pb->capq);
- return;
+ return IRQ_HANDLED;
}
/* incorrect interrupts? */
pb->intr_mask = PLANB_CLR_IRQ;
out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
printk(KERN_ERR "PlanB: IRQ lockup, cleared intrrupts"
" unconditionally\n");
+ return IRQ_HANDLED;
}
/*******************************
@@ -2013,7 +2013,6 @@ static struct video_device planb_template=
.owner = THIS_MODULE,
.name = PLANB_DEVICE_NAME,
.type = VID_TYPE_OVERLAY,
- .hardware = VID_HARDWARE_PLANB,
.open = planb_open,
.close = planb_close,
.read = planb_read,
@@ -2091,7 +2090,7 @@ static int init_planb(struct planb *pb)
/* clear interrupt mask */
pb->intr_mask = PLANB_CLR_IRQ;
- result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb);
+ result = request_irq(pb->irq, planb_irq, 0, "PlanB", pb);
if (result < 0) {
if (result==-EINVAL)
printk(KERN_ERR "PlanB: Bad irq number (%d) "
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index b5a67f0dd19..6820c2aabd3 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -895,7 +895,6 @@ static struct video_device pms_template=
.owner = THIS_MODULE,
.name = "Mediavision PMS",
.type = VID_TYPE_CAPTURE,
- .hardware = VID_HARDWARE_PMS,
.fops = &pms_fops,
};
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
index 6bbed88d786..22719ba861a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -33,8 +33,10 @@ static void pvr2_context_destroy(struct pvr2_context *mp)
{
if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp);
- flush_workqueue(mp->workqueue);
- destroy_workqueue(mp->workqueue);
+ if (mp->workqueue) {
+ flush_workqueue(mp->workqueue);
+ destroy_workqueue(mp->workqueue);
+ }
kfree(mp);
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index f569b00201d..46f156fb108 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -410,7 +410,7 @@ static int parse_mtoken(const char *ptr,unsigned int len,
int msk;
*valptr = 0;
for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) {
- if (!msk & valid_bits) continue;
+ if (!(msk & valid_bits)) continue;
valid_bits &= ~msk;
if (!names[idx]) continue;
slen = strlen(names[idx]);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
index d95a8588e4f..da6441b88f3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debug.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h
@@ -26,32 +26,33 @@ extern int pvrusb2_debug;
/* These are listed in *rough* order of decreasing usefulness and
increasing noise level. */
-#define PVR2_TRACE_INFO (1 << 0) // Normal messages
-#define PVR2_TRACE_ERROR_LEGS (1 << 1) // error messages
-#define PVR2_TRACE_TOLERANCE (1 << 2) // track tolerance-affected errors
-#define PVR2_TRACE_TRAP (1 << 3) // Trap & report misbehavior from app
-#define PVR2_TRACE_INIT (1 << 4) // misc initialization steps
-#define PVR2_TRACE_START_STOP (1 << 5) // Streaming start / stop
-#define PVR2_TRACE_CTL (1 << 6) // commit of control changes
-#define PVR2_TRACE_DEBUG (1 << 7) // Temporary debug code
-#define PVR2_TRACE_EEPROM (1 << 8) // eeprom parsing / report
-#define PVR2_TRACE_STRUCT (1 << 9) // internal struct creation
-#define PVR2_TRACE_OPEN_CLOSE (1 << 10) // application open / close
-#define PVR2_TRACE_CREG (1 << 11) // Main critical region entry / exit
-#define PVR2_TRACE_SYSFS (1 << 12) // Sysfs driven I/O
-#define PVR2_TRACE_FIRMWARE (1 << 13) // firmware upload actions
-#define PVR2_TRACE_CHIPS (1 << 14) // chip broadcast operation
-#define PVR2_TRACE_I2C (1 << 15) // I2C related stuff
-#define PVR2_TRACE_I2C_CMD (1 << 16) // Software commands to I2C modules
-#define PVR2_TRACE_I2C_CORE (1 << 17) // I2C core debugging
-#define PVR2_TRACE_I2C_TRAF (1 << 18) // I2C traffic through the adapter
-#define PVR2_TRACE_V4LIOCTL (1 << 19) // v4l ioctl details
-#define PVR2_TRACE_ENCODER (1 << 20) // mpeg2 encoder operation
-#define PVR2_TRACE_BUF_POOL (1 << 21) // Track buffer pool management
-#define PVR2_TRACE_BUF_FLOW (1 << 22) // Track buffer flow in system
-#define PVR2_TRACE_DATA_FLOW (1 << 23) // Track data flow
-#define PVR2_TRACE_DEBUGIFC (1 << 24) // Debug interface actions
-#define PVR2_TRACE_GPIO (1 << 25) // GPIO state bit changes
+#define PVR2_TRACE_INFO (1 << 0) /* Normal messages */
+#define PVR2_TRACE_ERROR_LEGS (1 << 1) /* error messages */
+#define PVR2_TRACE_TOLERANCE (1 << 2) /* track tolerance-affected errors */
+#define PVR2_TRACE_TRAP (1 << 3) /* Trap & report app misbehavior */
+#define PVR2_TRACE_STD (1 << 4) /* Log video standard stuff */
+#define PVR2_TRACE_INIT (1 << 5) /* misc initialization steps */
+#define PVR2_TRACE_START_STOP (1 << 6) /* Streaming start / stop */
+#define PVR2_TRACE_CTL (1 << 7) /* commit of control changes */
+#define PVR2_TRACE_DEBUG (1 << 8) /* Temporary debug code */
+#define PVR2_TRACE_EEPROM (1 << 9) /* eeprom parsing / report */
+#define PVR2_TRACE_STRUCT (1 << 10) /* internal struct creation */
+#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */
+#define PVR2_TRACE_CREG (1 << 12) /* Main critical region entry / exit */
+#define PVR2_TRACE_SYSFS (1 << 13) /* Sysfs driven I/O */
+#define PVR2_TRACE_FIRMWARE (1 << 14) /* firmware upload actions */
+#define PVR2_TRACE_CHIPS (1 << 15) /* chip broadcast operation */
+#define PVR2_TRACE_I2C (1 << 16) /* I2C related stuff */
+#define PVR2_TRACE_I2C_CMD (1 << 17) /* Software commands to I2C modules */
+#define PVR2_TRACE_I2C_CORE (1 << 18) /* I2C core debugging */
+#define PVR2_TRACE_I2C_TRAF (1 << 19) /* I2C traffic through the adapter */
+#define PVR2_TRACE_V4LIOCTL (1 << 20) /* v4l ioctl details */
+#define PVR2_TRACE_ENCODER (1 << 21) /* mpeg2 encoder operation */
+#define PVR2_TRACE_BUF_POOL (1 << 22) /* Track buffer pool management */
+#define PVR2_TRACE_BUF_FLOW (1 << 23) /* Track buffer flow in system */
+#define PVR2_TRACE_DATA_FLOW (1 << 24) /* Track data flow */
+#define PVR2_TRACE_DEBUGIFC (1 << 25) /* Debug interface actions */
+#define PVR2_TRACE_GPIO (1 << 26) /* GPIO state bit changes */
#endif /* __PVRUSB2_HDW_INTERNAL_H */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index e9da9bb8f8d..6f135f4a249 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -397,10 +397,22 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
count -= scnt; buf += scnt;
if (!wptr) return -EINVAL;
if (debugifc_match_keyword(wptr,wlen,"fetch")) {
- pvr2_hdw_cpufw_set_enabled(hdw,!0);
+ scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+ if (scnt && wptr) {
+ count -= scnt; buf += scnt;
+ if (debugifc_match_keyword(wptr,wlen,"prom")) {
+ pvr2_hdw_cpufw_set_enabled(hdw,!0,!0);
+ } else if (debugifc_match_keyword(wptr,wlen,
+ "ram")) {
+ pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
+ } else {
+ return -EINVAL;
+ }
+ }
+ pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
return 0;
} else if (debugifc_match_keyword(wptr,wlen,"done")) {
- pvr2_hdw_cpufw_set_enabled(hdw,0);
+ pvr2_hdw_cpufw_set_enabled(hdw,0,0);
return 0;
} else {
return -EINVAL;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 20b614436d2..205087a3e13 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -209,6 +209,11 @@ static int pvr2_encoder_cmd(void *ctxt,
LOCK_TAKE(hdw->ctl_lock); do {
+ if (!hdw->flag_encoder_ok) {
+ ret = -EIO;
+ break;
+ }
+
retry_flag = 0;
try_count++;
ret = 0;
@@ -273,6 +278,7 @@ static int pvr2_encoder_cmd(void *ctxt,
ret = -EBUSY;
}
if (ret) {
+ hdw->flag_encoder_ok = 0;
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Giving up on command."
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index ce66ab8ff2d..f873994b088 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -225,11 +225,12 @@ struct pvr2_hdw {
unsigned int cmd_debug_write_len; //
unsigned int cmd_debug_read_len; //
- int flag_ok; // device in known good state
- int flag_disconnected; // flag_ok == 0 due to disconnect
- int flag_init_ok; // true if structure is fully initialized
- int flag_streaming_enabled; // true if streaming should be on
- int fw1_state; // current situation with fw1
+ int flag_ok; /* device in known good state */
+ int flag_disconnected; /* flag_ok == 0 due to disconnect */
+ int flag_init_ok; /* true if structure is fully initialized */
+ int flag_streaming_enabled; /* true if streaming should be on */
+ int fw1_state; /* current situation with fw1 */
+ int flag_encoder_ok; /* True if encoder is healthy */
int flag_decoder_is_tuned;
@@ -238,6 +239,7 @@ struct pvr2_hdw {
// CPU firmware info (used to help find / save firmware data)
char *fw_buffer;
unsigned int fw_size;
+ int fw_cpu_flag; /* True if we are dealing with the CPU */
// Which subsystem pieces have been enabled / configured
unsigned long subsys_enabled_mask;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 1311891e7ee..402c5948825 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -492,7 +492,7 @@ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
cs.controls = &c1;
cs.count = 1;
c1.id = cptr->info->v4l_id;
- ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+ ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs,
VIDIOC_G_EXT_CTRLS);
if (ret) return ret;
*vp = c1.value;
@@ -510,7 +510,7 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
cs.count = 1;
c1.id = cptr->info->v4l_id;
c1.value = v;
- ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+ ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs,
VIDIOC_S_EXT_CTRLS);
if (ret) return ret;
cptr->hdw->enc_stale = !0;
@@ -1143,6 +1143,13 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
},
};
+
+ if ((hdw->hdw_type >= ARRAY_SIZE(fw_file_defs)) ||
+ (!fw_file_defs[hdw->hdw_type].lst)) {
+ hdw->fw1_state = FW1_STATE_OK;
+ return 0;
+ }
+
hdw->fw1_state = FW1_STATE_FAILED; // default result
trace_firmware("pvr2_upload_firmware1");
@@ -1224,6 +1231,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
CX2341X_FIRM_ENC_FILENAME,
};
+ if ((hdw->hdw_type != PVR2_HDW_TYPE_29XXX) &&
+ (hdw->hdw_type != PVR2_HDW_TYPE_24XXX)) {
+ return 0;
+ }
+
trace_firmware("pvr2_upload_firmware2");
ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
@@ -1236,6 +1248,8 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
time we configure the encoder, then we'll fully configure it. */
hdw->enc_cur_valid = 0;
+ hdw->flag_encoder_ok = 0;
+
/* First prepare firmware loading */
ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
@@ -1334,6 +1348,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"firmware2 upload post-proc failure");
} else {
+ hdw->flag_encoder_ok = !0;
hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_FIRMWARE);
}
return ret;
@@ -1682,6 +1697,44 @@ static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw)
return result == 0;
}
+struct pvr2_std_hack {
+ v4l2_std_id pat; /* Pattern to match */
+ v4l2_std_id msk; /* Which bits we care about */
+ v4l2_std_id std; /* What additional standards or default to set */
+};
+
+/* This data structure labels specific combinations of standards from
+ tveeprom that we'll try to recognize. If we recognize one, then assume
+ a specified default standard to use. This is here because tveeprom only
+ tells us about available standards not the intended default standard (if
+ any) for the device in question. We guess the default based on what has
+ been reported as available. Note that this is only for guessing a
+ default - which can always be overridden explicitly - and if the user
+ has otherwise named a default then that default will always be used in
+ place of this table. */
+const static struct pvr2_std_hack std_eeprom_maps[] = {
+ { /* PAL(B/G) */
+ .pat = V4L2_STD_B|V4L2_STD_GH,
+ .std = V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_PAL_G,
+ },
+ { /* NTSC(M) */
+ .pat = V4L2_STD_MN,
+ .std = V4L2_STD_NTSC_M,
+ },
+ { /* PAL(I) */
+ .pat = V4L2_STD_PAL_I,
+ .std = V4L2_STD_PAL_I,
+ },
+ { /* SECAM(L/L') */
+ .pat = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC,
+ .std = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC,
+ },
+ { /* PAL(D/D1/K) */
+ .pat = V4L2_STD_DK,
+ .std = V4L2_STD_PAL_D/V4L2_STD_PAL_D1|V4L2_STD_PAL_K,
+ },
+};
+
static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
{
char buf[40];
@@ -1691,7 +1744,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
std1 = get_default_standard(hdw);
bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom);
- pvr2_trace(PVR2_TRACE_INIT,
+ pvr2_trace(PVR2_TRACE_STD,
"Supported video standard(s) reported by eeprom: %.*s",
bcnt,buf);
@@ -1700,7 +1753,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
std2 = std1 & ~hdw->std_mask_avail;
if (std2) {
bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2);
- pvr2_trace(PVR2_TRACE_INIT,
+ pvr2_trace(PVR2_TRACE_STD,
"Expanding supported video standards"
" to include: %.*s",
bcnt,buf);
@@ -1711,7 +1764,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
if (std1) {
bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1);
- pvr2_trace(PVR2_TRACE_INIT,
+ pvr2_trace(PVR2_TRACE_STD,
"Initial video standard forced to %.*s",
bcnt,buf);
hdw->std_mask_cur = std1;
@@ -1720,12 +1773,33 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
return;
}
+ {
+ unsigned int idx;
+ for (idx = 0; idx < ARRAY_SIZE(std_eeprom_maps); idx++) {
+ if (std_eeprom_maps[idx].msk ?
+ ((std_eeprom_maps[idx].pat ^
+ hdw->std_mask_eeprom) &
+ std_eeprom_maps[idx].msk) :
+ (std_eeprom_maps[idx].pat !=
+ hdw->std_mask_eeprom)) continue;
+ bcnt = pvr2_std_id_to_str(buf,sizeof(buf),
+ std_eeprom_maps[idx].std);
+ pvr2_trace(PVR2_TRACE_STD,
+ "Initial video standard guessed as %.*s",
+ bcnt,buf);
+ hdw->std_mask_cur = std_eeprom_maps[idx].std;
+ hdw->std_dirty = !0;
+ pvr2_hdw_internal_find_stdenum(hdw);
+ return;
+ }
+ }
+
if (hdw->std_enum_cnt > 1) {
// Autoselect the first listed standard
hdw->std_enum_cur = 1;
hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id;
hdw->std_dirty = !0;
- pvr2_trace(PVR2_TRACE_INIT,
+ pvr2_trace(PVR2_TRACE_STD,
"Initial video standard auto-selected to %s",
hdw->std_defs[hdw->std_enum_cur-1].name);
return;
@@ -1742,29 +1816,35 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
unsigned int idx;
struct pvr2_ctrl *cptr;
int reloadFl = 0;
- if (!reloadFl) {
- reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
- == 0);
- if (reloadFl) {
- pvr2_trace(PVR2_TRACE_INIT,
- "USB endpoint config looks strange"
- "; possibly firmware needs to be loaded");
+ if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
+ (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
+ if (!reloadFl) {
+ reloadFl =
+ (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
+ == 0);
+ if (reloadFl) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "USB endpoint config looks strange"
+ "; possibly firmware needs to be"
+ " loaded");
+ }
}
- }
- if (!reloadFl) {
- reloadFl = !pvr2_hdw_check_firmware(hdw);
- if (reloadFl) {
- pvr2_trace(PVR2_TRACE_INIT,
- "Check for FX2 firmware failed"
- "; possibly firmware needs to be loaded");
+ if (!reloadFl) {
+ reloadFl = !pvr2_hdw_check_firmware(hdw);
+ if (reloadFl) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Check for FX2 firmware failed"
+ "; possibly firmware needs to be"
+ " loaded");
+ }
}
- }
- if (reloadFl) {
- if (pvr2_upload_firmware1(hdw) != 0) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Failure uploading firmware1");
+ if (reloadFl) {
+ if (pvr2_upload_firmware1(hdw) != 0) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failure uploading firmware1");
+ }
+ return;
}
- return;
}
hdw->fw1_state = FW1_STATE_OK;
@@ -1773,17 +1853,25 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
}
if (!pvr2_hdw_dev_ok(hdw)) return;
- for (idx = 0; idx < pvr2_client_lists[hdw->hdw_type].cnt; idx++) {
- request_module(pvr2_client_lists[hdw->hdw_type].lst[idx]);
+ if (hdw->hdw_type < ARRAY_SIZE(pvr2_client_lists)) {
+ for (idx = 0;
+ idx < pvr2_client_lists[hdw->hdw_type].cnt;
+ idx++) {
+ request_module(
+ pvr2_client_lists[hdw->hdw_type].lst[idx]);
+ }
}
- pvr2_hdw_cmd_powerup(hdw);
- if (!pvr2_hdw_dev_ok(hdw)) return;
+ if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
+ (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
+ pvr2_hdw_cmd_powerup(hdw);
+ if (!pvr2_hdw_dev_ok(hdw)) return;
- if (pvr2_upload_firmware2(hdw)){
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
- pvr2_hdw_render_useless(hdw);
- return;
+ if (pvr2_upload_firmware2(hdw)){
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
+ pvr2_hdw_render_useless(hdw);
+ return;
+ }
}
// This step MUST happen after the earlier powerup step.
@@ -2172,6 +2260,7 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
/* Destroy hardware interaction structure */
void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
{
+ if (!hdw) return;
pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
if (hdw->fw_buffer) {
kfree(hdw->fw_buffer);
@@ -2478,7 +2567,7 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
cs.count = 1;
c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ;
c1.value = hdw->srate_val;
- cx2341x_ext_ctrls(&hdw->enc_ctl_state,&cs,VIDIOC_S_EXT_CTRLS);
+ cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS);
}
/* Scan i2c core at this point - before we clear all the dirty
@@ -2604,7 +2693,85 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
} while (0); LOCK_GIVE(hdw->big_lock);
}
-void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
+
+/* Grab EEPROM contents, needed for direct method. */
+#define EEPROM_SIZE 8192
+#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__)
+static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw)
+{
+ struct i2c_msg msg[2];
+ u8 *eeprom;
+ u8 iadd[2];
+ u8 addr;
+ u16 eepromSize;
+ unsigned int offs;
+ int ret;
+ int mode16 = 0;
+ unsigned pcnt,tcnt;
+ eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL);
+ if (!eeprom) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failed to allocate memory"
+ " required to read eeprom");
+ return NULL;
+ }
+
+ trace_eeprom("Value for eeprom addr from controller was 0x%x",
+ hdw->eeprom_addr);
+ addr = hdw->eeprom_addr;
+ /* Seems that if the high bit is set, then the *real* eeprom
+ address is shifted right now bit position (noticed this in
+ newer PVR USB2 hardware) */
+ if (addr & 0x80) addr >>= 1;
+
+ /* FX2 documentation states that a 16bit-addressed eeprom is
+ expected if the I2C address is an odd number (yeah, this is
+ strange but it's what they do) */
+ mode16 = (addr & 1);
+ eepromSize = (mode16 ? EEPROM_SIZE : 256);
+ trace_eeprom("Examining %d byte eeprom at location 0x%x"
+ " using %d bit addressing",eepromSize,addr,
+ mode16 ? 16 : 8);
+
+ msg[0].addr = addr;
+ msg[0].flags = 0;
+ msg[0].len = mode16 ? 2 : 1;
+ msg[0].buf = iadd;
+ msg[1].addr = addr;
+ msg[1].flags = I2C_M_RD;
+
+ /* We have to do the actual eeprom data fetch ourselves, because
+ (1) we're only fetching part of the eeprom, and (2) if we were
+ getting the whole thing our I2C driver can't grab it in one
+ pass - which is what tveeprom is otherwise going to attempt */
+ memset(eeprom,0,EEPROM_SIZE);
+ for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) {
+ pcnt = 16;
+ if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt;
+ offs = tcnt + (eepromSize - EEPROM_SIZE);
+ if (mode16) {
+ iadd[0] = offs >> 8;
+ iadd[1] = offs;
+ } else {
+ iadd[0] = offs;
+ }
+ msg[1].len = pcnt;
+ msg[1].buf = eeprom+tcnt;
+ if ((ret = i2c_transfer(&hdw->i2c_adap,
+ msg,ARRAY_SIZE(msg))) != 2) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "eeprom fetch set offs err=%d",ret);
+ kfree(eeprom);
+ return NULL;
+ }
+ }
+ return eeprom;
+}
+
+
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw,
+ int prom_flag,
+ int enable_flag)
{
int ret;
u16 address;
@@ -2618,37 +2785,59 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
kfree(hdw->fw_buffer);
hdw->fw_buffer = NULL;
hdw->fw_size = 0;
- /* Now release the CPU. It will disconnect and
- reconnect later. */
- pvr2_hdw_cpureset_assert(hdw,0);
+ if (hdw->fw_cpu_flag) {
+ /* Now release the CPU. It will disconnect
+ and reconnect later. */
+ pvr2_hdw_cpureset_assert(hdw,0);
+ }
break;
}
- pvr2_trace(PVR2_TRACE_FIRMWARE,
- "Preparing to suck out CPU firmware");
- hdw->fw_size = 0x2000;
- hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
- if (!hdw->fw_buffer) {
- hdw->fw_size = 0;
- break;
- }
+ hdw->fw_cpu_flag = (prom_flag == 0);
+ if (hdw->fw_cpu_flag) {
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Preparing to suck out CPU firmware");
+ hdw->fw_size = 0x2000;
+ hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
+ if (!hdw->fw_buffer) {
+ hdw->fw_size = 0;
+ break;
+ }
- /* We have to hold the CPU during firmware upload. */
- pvr2_hdw_cpureset_assert(hdw,1);
+ /* We have to hold the CPU during firmware upload. */
+ pvr2_hdw_cpureset_assert(hdw,1);
- /* download the firmware from address 0000-1fff in 2048
- (=0x800) bytes chunk. */
+ /* download the firmware from address 0000-1fff in 2048
+ (=0x800) bytes chunk. */
- pvr2_trace(PVR2_TRACE_FIRMWARE,"Grabbing CPU firmware");
- pipe = usb_rcvctrlpipe(hdw->usb_dev, 0);
- for(address = 0; address < hdw->fw_size; address += 0x800) {
- ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0xc0,
- address,0,
- hdw->fw_buffer+address,0x800,HZ);
- if (ret < 0) break;
- }
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Grabbing CPU firmware");
+ pipe = usb_rcvctrlpipe(hdw->usb_dev, 0);
+ for(address = 0; address < hdw->fw_size;
+ address += 0x800) {
+ ret = usb_control_msg(hdw->usb_dev,pipe,
+ 0xa0,0xc0,
+ address,0,
+ hdw->fw_buffer+address,
+ 0x800,HZ);
+ if (ret < 0) break;
+ }
- pvr2_trace(PVR2_TRACE_FIRMWARE,"Done grabbing CPU firmware");
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Done grabbing CPU firmware");
+ } else {
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Sucking down EEPROM contents");
+ hdw->fw_buffer = pvr2_full_eeprom_fetch(hdw);
+ if (!hdw->fw_buffer) {
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "EEPROM content suck failed.");
+ break;
+ }
+ hdw->fw_size = EEPROM_SIZE;
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Done sucking down EEPROM contents");
+ }
} while (0); LOCK_GIVE(hdw->big_lock);
}
@@ -3272,7 +3461,6 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
int setFl,u64 *val_ptr)
{
#ifdef CONFIG_VIDEO_ADV_DEBUG
- struct list_head *item;
struct pvr2_i2c_client *cp;
struct v4l2_register req;
int stat = 0;
@@ -3285,8 +3473,7 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
req.reg = reg_id;
if (setFl) req.val = *val_ptr;
mutex_lock(&hdw->i2c_list_lock); do {
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,list);
+ list_for_each_entry(cp, &hdw->i2c_clients, list) {
if (!v4l2_chip_match_i2c_client(
cp->client,
req.match_type, req.match_chip)) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 4dba8d00632..e2f9d5e4cb6 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -197,11 +197,13 @@ void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *);
-/* Enable / disable retrieval of CPU firmware. This must be enabled before
- pvr2_hdw_cpufw_get() will function. Note that doing this may prevent
- the device from running (and leaving this mode may imply a device
- reset). */
-void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, int enable_flag);
+/* Enable / disable retrieval of CPU firmware or prom contents. This must
+ be enabled before pvr2_hdw_cpufw_get() will function. Note that doing
+ this may prevent the device from running (and leaving this mode may
+ imply a device reset). */
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *,
+ int prom_flag,
+ int enable_flag);
/* Return true if we're in a mode for retrieval CPU firmware */
int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 6786d3c0c98..c817c864e6a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -389,10 +389,6 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
ret = -EINVAL;
goto done;
}
- if ((msgs[0].flags & I2C_M_NOSTART)) {
- trace_i2c("i2c refusing I2C_M_NOSTART");
- goto done;
- }
if (msgs[0].addr < PVR2_I2C_FUNC_CNT) {
funcp = hdw->i2c_func[msgs[0].addr];
}
@@ -494,14 +490,12 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
cnt = msgs[idx].len;
printk(KERN_INFO
"pvrusb2 i2c xfer %u/%u:"
- " addr=0x%x len=%d %s%s",
+ " addr=0x%x len=%d %s",
idx+1,num,
msgs[idx].addr,
cnt,
(msgs[idx].flags & I2C_M_RD ?
- "read" : "write"),
- (msgs[idx].flags & I2C_M_NOSTART ?
- " nostart" : ""));
+ "read" : "write"));
if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) {
if (cnt > 8) cnt = 8;
printk(" [");
@@ -526,15 +520,9 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
return ret;
}
-static int pvr2_i2c_control(struct i2c_adapter *adapter,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
{
- return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA;
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
}
static int pvr2_i2c_core_singleton(struct i2c_client *cp,
@@ -576,15 +564,13 @@ int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
{
- struct list_head *item,*nc;
- struct pvr2_i2c_client *cp;
+ struct pvr2_i2c_client *cp, *ncp;
int stat = -EINVAL;
if (!hdw) return stat;
mutex_lock(&hdw->i2c_list_lock);
- list_for_each_safe(item,nc,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,list);
+ list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
if (!cp->recv_enable) continue;
mutex_unlock(&hdw->i2c_list_lock);
stat = pvr2_i2c_client_cmd(cp,cmd,arg);
@@ -608,13 +594,11 @@ static int handler_check(struct pvr2_i2c_client *cp)
void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
{
- struct list_head *item;
struct pvr2_i2c_client *cp;
mutex_lock(&hdw->i2c_list_lock); do {
struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
memset(vtp,0,sizeof(*vtp));
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,list);
+ list_for_each_entry(cp, &hdw->i2c_clients, list) {
if (!cp->detected_flag) continue;
if (!cp->status_poll) continue;
cp->status_poll(cp);
@@ -636,8 +620,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
{
unsigned long msk;
unsigned int idx;
- struct list_head *item,*nc;
- struct pvr2_i2c_client *cp;
+ struct pvr2_i2c_client *cp, *ncp;
if (!hdw->i2c_linked) return;
if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
@@ -655,9 +638,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
buf = kmalloc(BUFSIZE,GFP_KERNEL);
pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,
- list);
+ list_for_each_entry(cp, &hdw->i2c_clients, list) {
if (!cp->detected_flag) {
cp->ctl_mask = 0;
pvr2_i2c_probe(hdw,cp);
@@ -693,9 +674,7 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
"i2c: PEND_STALE (0x%lx)",
hdw->i2c_stale_mask);
hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,
- list);
+ list_for_each_entry(cp, &hdw->i2c_clients, list) {
m2 = hdw->i2c_stale_mask;
m2 &= cp->ctl_mask;
m2 &= ~cp->pend_mask;
@@ -716,9 +695,8 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
and update each one. */
pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
- list_for_each_safe(item,nc,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,
- list);
+ list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients,
+ list) {
if (!cp->handler) continue;
if (!cp->handler->func_table->update) continue;
pvr2_trace(PVR2_TRACE_I2C_CORE,
@@ -750,10 +728,8 @@ void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
if (!(pm & msk)) continue;
pm &= ~msk;
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,
- struct pvr2_i2c_client,
- list);
+ list_for_each_entry(cp, &hdw->i2c_clients,
+ list) {
if (cp->pend_mask & msk) {
cp->pend_mask &= ~msk;
cp->recv_enable = !0;
@@ -777,7 +753,6 @@ int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
unsigned long msk,sm,pm;
unsigned int idx;
const struct pvr2_i2c_op *opf;
- struct list_head *item;
struct pvr2_i2c_client *cp;
unsigned int pt = 0;
@@ -796,11 +771,9 @@ int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
}
if (sm) pt |= PVR2_I2C_PEND_STALE;
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,list);
- if (!handler_check(cp)) continue;
- pt |= PVR2_I2C_PEND_CLIENT;
- }
+ list_for_each_entry(cp, &hdw->i2c_clients, list)
+ if (handler_check(cp))
+ pt |= PVR2_I2C_PEND_CLIENT;
if (pt) {
mutex_lock(&hdw->i2c_list_lock); do {
@@ -888,12 +861,10 @@ unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
char *buf,unsigned int maxlen)
{
unsigned int ccnt,bcnt;
- struct list_head *item;
struct pvr2_i2c_client *cp;
ccnt = 0;
mutex_lock(&hdw->i2c_list_lock); do {
- list_for_each(item,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,list);
+ list_for_each_entry(cp, &hdw->i2c_clients, list) {
bcnt = pvr2_i2c_client_describe(
cp,
(PVR2_I2C_DETAIL_HANDLER|
@@ -931,13 +902,11 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
static int pvr2_i2c_detach_inform(struct i2c_client *client)
{
struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
- struct pvr2_i2c_client *cp;
- struct list_head *item,*nc;
+ struct pvr2_i2c_client *cp, *ncp;
unsigned long amask = 0;
int foundfl = 0;
mutex_lock(&hdw->i2c_list_lock); do {
- list_for_each_safe(item,nc,&hdw->i2c_clients) {
- cp = list_entry(item,struct pvr2_i2c_client,list);
+ list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
if (cp->client == client) {
trace_i2c("pvr2_i2c_detach"
" [client=%s @ 0x%x ctxt=%p]",
@@ -967,7 +936,6 @@ static int pvr2_i2c_detach_inform(struct i2c_client *client)
static struct i2c_algorithm pvr2_i2c_algo_template = {
.master_xfer = pvr2_i2c_xfer,
- .algo_control = pvr2_i2c_control,
.functionality = pvr2_i2c_functionality,
};
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index 9ea41c6699b..11b3b2e84b9 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -24,7 +24,6 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/usb.h>
#include <linux/videodev2.h>
@@ -42,6 +41,7 @@
#define DEFAULT_DEBUG_MASK (PVR2_TRACE_ERROR_LEGS| \
PVR2_TRACE_INFO| \
+ PVR2_TRACE_STD| \
PVR2_TRACE_TOLERANCE| \
PVR2_TRACE_TRAP| \
0)
@@ -136,14 +136,13 @@ static int __init pvr_init(void)
static void __exit pvr_exit(void)
{
-
pvr2_trace(PVR2_TRACE_INIT,"pvr_exit");
+ usb_deregister(&pvr_driver);
+
#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
pvr2_sysfs_class_destroy(class_ptr);
#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
-
- usb_deregister(&pvr_driver);
}
module_init(pvr_init);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
index 81de26ba41d..63e55bb59fc 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -298,7 +298,7 @@ static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id)
std->id = id;
bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id);
std->name[bcnt] = 0;
- pvr2_trace(PVR2_TRACE_INIT,"Set up standard idx=%u name=%s",
+ pvr2_trace(PVR2_TRACE_STD,"Set up standard idx=%u name=%s",
std->index,std->name);
return !0;
}
@@ -320,11 +320,11 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
v4l2_std_id idmsk,cmsk,fmsk;
struct v4l2_standard *stddefs;
- if (pvrusb2_debug & PVR2_TRACE_INIT) {
+ if (pvrusb2_debug & PVR2_TRACE_STD) {
char buf[50];
bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id);
pvr2_trace(
- PVR2_TRACE_INIT,"Mapping standards mask=0x%x (%.*s)",
+ PVR2_TRACE_STD,"Mapping standards mask=0x%x (%.*s)",
(int)id,bcnt,buf);
}
@@ -355,7 +355,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
bcnt,buf);
}
- pvr2_trace(PVR2_TRACE_INIT,"Setting up %u unique standard(s)",
+ pvr2_trace(PVR2_TRACE_STD,"Setting up %u unique standard(s)",
std_cnt);
if (!std_cnt) return NULL; // paranoia
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 7ab79baa1c8..3c57a7d8200 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -33,16 +33,16 @@
struct pvr2_sysfs {
struct pvr2_channel channel;
- struct class_device *class_dev;
+ struct device *class_dev;
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
struct pvr2_sysfs_debugifc *debugifc;
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
struct pvr2_sysfs_ctl_item *item_first;
struct pvr2_sysfs_ctl_item *item_last;
- struct class_device_attribute attr_v4l_minor_number;
- struct class_device_attribute attr_v4l_radio_minor_number;
- struct class_device_attribute attr_unit_number;
- struct class_device_attribute attr_bus_info;
+ struct device_attribute attr_v4l_minor_number;
+ struct device_attribute attr_v4l_radio_minor_number;
+ struct device_attribute attr_unit_number;
+ struct device_attribute attr_bus_info;
int v4l_minor_number_created_ok;
int v4l_radio_minor_number_created_ok;
int unit_number_created_ok;
@@ -51,22 +51,22 @@ struct pvr2_sysfs {
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
struct pvr2_sysfs_debugifc {
- struct class_device_attribute attr_debugcmd;
- struct class_device_attribute attr_debuginfo;
+ struct device_attribute attr_debugcmd;
+ struct device_attribute attr_debuginfo;
int debugcmd_created_ok;
int debuginfo_created_ok;
};
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
struct pvr2_sysfs_ctl_item {
- struct class_device_attribute attr_name;
- struct class_device_attribute attr_type;
- struct class_device_attribute attr_min;
- struct class_device_attribute attr_max;
- struct class_device_attribute attr_enum;
- struct class_device_attribute attr_bits;
- struct class_device_attribute attr_val;
- struct class_device_attribute attr_custom;
+ struct device_attribute attr_name;
+ struct device_attribute attr_type;
+ struct device_attribute attr_min;
+ struct device_attribute attr_max;
+ struct device_attribute attr_enum;
+ struct device_attribute attr_bits;
+ struct device_attribute attr_val;
+ struct device_attribute attr_custom;
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *chptr;
struct pvr2_sysfs_ctl_item *item_next;
@@ -80,13 +80,13 @@ struct pvr2_sysfs_class {
struct class class;
};
-static ssize_t show_name(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_name(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
const char *name;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -99,14 +99,14 @@ static ssize_t show_name(int id,struct class_device *class_dev,char *buf)
return scnprintf(buf,PAGE_SIZE,"%s\n",name);
}
-static ssize_t show_type(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_type(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
const char *name;
enum pvr2_ctl_type tp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -126,13 +126,13 @@ static ssize_t show_type(int id,struct class_device *class_dev,char *buf)
return scnprintf(buf,PAGE_SIZE,"%s\n",name);
}
-static ssize_t show_min(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_min(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
long val;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -143,13 +143,13 @@ static ssize_t show_min(int id,struct class_device *class_dev,char *buf)
return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
}
-static ssize_t show_max(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_max(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
long val;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -160,14 +160,14 @@ static ssize_t show_max(int id,struct class_device *class_dev,char *buf)
return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
}
-static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_val_norm(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
int val,ret;
unsigned int cnt = 0;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -184,14 +184,14 @@ static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf)
return cnt+1;
}
-static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_val_custom(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
int val,ret;
unsigned int cnt = 0;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -208,14 +208,14 @@ static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf)
return cnt+1;
}
-static ssize_t show_enum(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_enum(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
long val;
unsigned int bcnt,ccnt,ecnt;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -233,14 +233,14 @@ static ssize_t show_enum(int id,struct class_device *class_dev,char *buf)
return bcnt;
}
-static ssize_t show_bits(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_bits(int id,struct device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
int valid_bits,msk;
unsigned int bcnt,ccnt;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
if (!cptr) return -EINVAL;
@@ -278,23 +278,23 @@ static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp,
return ret;
}
-static ssize_t store_val_norm(int id,struct class_device *class_dev,
+static ssize_t store_val_norm(int id,struct device *class_dev,
const char *buf,size_t count)
{
struct pvr2_sysfs *sfp;
int ret;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
ret = store_val_any(id,0,sfp,buf,count);
if (!ret) ret = count;
return ret;
}
-static ssize_t store_val_custom(int id,struct class_device *class_dev,
+static ssize_t store_val_custom(int id,struct device *class_dev,
const char *buf,size_t count)
{
struct pvr2_sysfs *sfp;
int ret;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
ret = store_val_any(id,1,sfp,buf,count);
if (!ret) ret = count;
return ret;
@@ -304,7 +304,7 @@ static ssize_t store_val_custom(int id,struct class_device *class_dev,
Mike Isely <isely@pobox.com> 30-April-2005
This next batch of horrible preprocessor hackery is needed because the
- kernel's class_device_attribute mechanism fails to pass the actual
+ kernel's device_attribute mechanism fails to pass the actual
attribute through to the show / store functions, which means we have no
way to package up any attribute-specific parameters, like for example the
control id. So we work around this brain-damage by encoding the control
@@ -314,11 +314,13 @@ static ssize_t store_val_custom(int id,struct class_device *class_dev,
*/
#define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \
-static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,char *buf) \
+static ssize_t sf_name##_##ctl_id(struct device *class_dev, \
+struct device_attribute *attr, char *buf) \
{ return sf_name(ctl_id,class_dev,buf); }
#define CREATE_STORE_INSTANCE(sf_name,ctl_id) \
-static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,const char *buf,size_t count) \
+static ssize_t sf_name##_##ctl_id(struct device *class_dev, \
+struct device_attribute *attr, const char *buf, size_t count) \
{ return sf_name(ctl_id,class_dev,buf,count); }
#define CREATE_BATCH(ctl_id) \
@@ -395,17 +397,27 @@ CREATE_BATCH(58)
CREATE_BATCH(59)
struct pvr2_sysfs_func_set {
- ssize_t (*show_name)(struct class_device *,char *);
- ssize_t (*show_type)(struct class_device *,char *);
- ssize_t (*show_min)(struct class_device *,char *);
- ssize_t (*show_max)(struct class_device *,char *);
- ssize_t (*show_enum)(struct class_device *,char *);
- ssize_t (*show_bits)(struct class_device *,char *);
- ssize_t (*show_val_norm)(struct class_device *,char *);
- ssize_t (*store_val_norm)(struct class_device *,
+ ssize_t (*show_name)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*show_type)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*show_min)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*show_max)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*show_enum)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*show_bits)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*show_val_norm)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*store_val_norm)(struct device *,
+ struct device_attribute *attr,
const char *,size_t);
- ssize_t (*show_val_custom)(struct class_device *,char *);
- ssize_t (*store_val_custom)(struct class_device *,
+ ssize_t (*show_val_custom)(struct device *,
+ struct device_attribute *attr, char *);
+ ssize_t (*store_val_custom)(struct device *,
+ struct device_attribute *attr,
const char *,size_t);
};
@@ -597,9 +609,12 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
}
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
-static ssize_t debuginfo_show(struct class_device *,char *);
-static ssize_t debugcmd_show(struct class_device *,char *);
-static ssize_t debugcmd_store(struct class_device *,const char *,size_t count);
+static ssize_t debuginfo_show(struct device *, struct device_attribute *,
+ char *);
+static ssize_t debugcmd_show(struct device *, struct device_attribute *,
+ char *);
+static ssize_t debugcmd_store(struct device *, struct device_attribute *,
+ const char *, size_t count);
static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
{
@@ -616,16 +631,16 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
dip->attr_debuginfo.attr.mode = S_IRUGO;
dip->attr_debuginfo.show = debuginfo_show;
sfp->debugifc = dip;
- ret = class_device_create_file(sfp->class_dev,&dip->attr_debugcmd);
+ ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd);
if (ret < 0) {
- printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ printk(KERN_WARNING "%s: device_create_file error: %d\n",
__FUNCTION__, ret);
} else {
dip->debugcmd_created_ok = !0;
}
- ret = class_device_create_file(sfp->class_dev,&dip->attr_debuginfo);
+ ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo);
if (ret < 0) {
- printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ printk(KERN_WARNING "%s: device_create_file error: %d\n",
__FUNCTION__, ret);
} else {
dip->debuginfo_created_ok = !0;
@@ -637,11 +652,11 @@ static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp)
{
if (!sfp->debugifc) return;
if (sfp->debugifc->debuginfo_created_ok) {
- class_device_remove_file(sfp->class_dev,
+ device_remove_file(sfp->class_dev,
&sfp->debugifc->attr_debuginfo);
}
if (sfp->debugifc->debugcmd_created_ok) {
- class_device_remove_file(sfp->class_dev,
+ device_remove_file(sfp->class_dev,
&sfp->debugifc->attr_debugcmd);
}
kfree(sfp->debugifc);
@@ -683,7 +698,7 @@ static void pvr2_sysfs_class_release(struct class *class)
}
-static void pvr2_sysfs_release(struct class_device *class_dev)
+static void pvr2_sysfs_release(struct device *class_dev)
{
pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev);
kfree(class_dev);
@@ -698,32 +713,33 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
pvr2_sysfs_tear_down_controls(sfp);
if (sfp->bus_info_created_ok) {
- class_device_remove_file(sfp->class_dev,
+ device_remove_file(sfp->class_dev,
&sfp->attr_bus_info);
}
if (sfp->v4l_minor_number_created_ok) {
- class_device_remove_file(sfp->class_dev,
+ device_remove_file(sfp->class_dev,
&sfp->attr_v4l_minor_number);
}
if (sfp->v4l_radio_minor_number_created_ok) {
- class_device_remove_file(sfp->class_dev,
+ device_remove_file(sfp->class_dev,
&sfp->attr_v4l_radio_minor_number);
}
if (sfp->unit_number_created_ok) {
- class_device_remove_file(sfp->class_dev,
+ device_remove_file(sfp->class_dev,
&sfp->attr_unit_number);
}
pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
- sfp->class_dev->class_data = NULL;
- class_device_unregister(sfp->class_dev);
+ sfp->class_dev->driver_data = NULL;
+ device_unregister(sfp->class_dev);
sfp->class_dev = NULL;
}
-static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf)
+static ssize_t v4l_minor_number_show(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pvr2_sysfs *sfp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
return scnprintf(buf,PAGE_SIZE,"%d\n",
pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
@@ -731,21 +747,23 @@ static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf)
}
-static ssize_t bus_info_show(struct class_device *class_dev,char *buf)
+static ssize_t bus_info_show(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pvr2_sysfs *sfp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
return scnprintf(buf,PAGE_SIZE,"%s\n",
pvr2_hdw_get_bus_info(sfp->channel.hdw));
}
-static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev,
+static ssize_t v4l_radio_minor_number_show(struct device *class_dev,
+ struct device_attribute *attr,
char *buf)
{
struct pvr2_sysfs *sfp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
return scnprintf(buf,PAGE_SIZE,"%d\n",
pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
@@ -753,10 +771,11 @@ static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev,
}
-static ssize_t unit_number_show(struct class_device *class_dev,char *buf)
+static ssize_t unit_number_show(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pvr2_sysfs *sfp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
return scnprintf(buf,PAGE_SIZE,"%d\n",
pvr2_hdw_get_unit_number(sfp->channel.hdw));
@@ -767,7 +786,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
struct pvr2_sysfs_class *class_ptr)
{
struct usb_device *usb_dev;
- struct class_device *class_dev;
+ struct device *class_dev;
int ret;
usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
@@ -779,23 +798,23 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
class_dev->class = &class_ptr->class;
if (pvr2_hdw_get_sn(sfp->channel.hdw)) {
- snprintf(class_dev->class_id,BUS_ID_SIZE,"sn-%lu",
+ snprintf(class_dev->bus_id, BUS_ID_SIZE, "sn-%lu",
pvr2_hdw_get_sn(sfp->channel.hdw));
} else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) {
- snprintf(class_dev->class_id,BUS_ID_SIZE,"unit-%c",
+ snprintf(class_dev->bus_id, BUS_ID_SIZE, "unit-%c",
pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a');
} else {
kfree(class_dev);
return;
}
- class_dev->dev = &usb_dev->dev;
+ class_dev->parent = &usb_dev->dev;
sfp->class_dev = class_dev;
- class_dev->class_data = sfp;
- ret = class_device_register(class_dev);
+ class_dev->driver_data = sfp;
+ ret = device_register(class_dev);
if (ret) {
- printk(KERN_ERR "%s: class_device_register failed\n",
+ printk(KERN_ERR "%s: device_register failed\n",
__FUNCTION__);
kfree(class_dev);
return;
@@ -805,10 +824,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->attr_v4l_minor_number.attr.mode = S_IRUGO;
sfp->attr_v4l_minor_number.show = v4l_minor_number_show;
sfp->attr_v4l_minor_number.store = NULL;
- ret = class_device_create_file(sfp->class_dev,
+ ret = device_create_file(sfp->class_dev,
&sfp->attr_v4l_minor_number);
if (ret < 0) {
- printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ printk(KERN_WARNING "%s: device_create_file error: %d\n",
__FUNCTION__, ret);
} else {
sfp->v4l_minor_number_created_ok = !0;
@@ -818,10 +837,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO;
sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show;
sfp->attr_v4l_radio_minor_number.store = NULL;
- ret = class_device_create_file(sfp->class_dev,
+ ret = device_create_file(sfp->class_dev,
&sfp->attr_v4l_radio_minor_number);
if (ret < 0) {
- printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ printk(KERN_WARNING "%s: device_create_file error: %d\n",
__FUNCTION__, ret);
} else {
sfp->v4l_radio_minor_number_created_ok = !0;
@@ -831,9 +850,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->attr_unit_number.attr.mode = S_IRUGO;
sfp->attr_unit_number.show = unit_number_show;
sfp->attr_unit_number.store = NULL;
- ret = class_device_create_file(sfp->class_dev,&sfp->attr_unit_number);
+ ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number);
if (ret < 0) {
- printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ printk(KERN_WARNING "%s: device_create_file error: %d\n",
__FUNCTION__, ret);
} else {
sfp->unit_number_created_ok = !0;
@@ -843,10 +862,10 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->attr_bus_info.attr.mode = S_IRUGO;
sfp->attr_bus_info.show = bus_info_show;
sfp->attr_bus_info.store = NULL;
- ret = class_device_create_file(sfp->class_dev,
+ ret = device_create_file(sfp->class_dev,
&sfp->attr_bus_info);
if (ret < 0) {
- printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ printk(KERN_WARNING "%s: device_create_file error: %d\n",
__FUNCTION__, ret);
} else {
sfp->bus_info_created_ok = !0;
@@ -886,13 +905,6 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp,
}
-static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp,
- int numenvp,char *buf,int size)
-{
- /* Even though we don't do anything here, we still need this function
- because sysfs will still try to call it. */
- return 0;
-}
struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
{
@@ -902,8 +914,7 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
clp->class.name = "pvrusb2";
clp->class.class_release = pvr2_sysfs_class_release;
- clp->class.release = pvr2_sysfs_release;
- clp->class.uevent = pvr2_sysfs_hotplug;
+ clp->class.dev_release = pvr2_sysfs_release;
if (class_register(&clp->class)) {
pvr2_sysfs_trace(
"Registration failed for pvr2_sysfs_class id=%p",clp);
@@ -921,32 +932,35 @@ void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp)
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
-static ssize_t debuginfo_show(struct class_device *class_dev,char *buf)
+static ssize_t debuginfo_show(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pvr2_sysfs *sfp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
pvr2_hdw_trigger_module_log(sfp->channel.hdw);
return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE);
}
-static ssize_t debugcmd_show(struct class_device *class_dev,char *buf)
+static ssize_t debugcmd_show(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pvr2_sysfs *sfp;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE);
}
-static ssize_t debugcmd_store(struct class_device *class_dev,
- const char *buf,size_t count)
+static ssize_t debugcmd_store(struct device *class_dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct pvr2_sysfs *sfp;
int ret;
- sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ sfp = (struct pvr2_sysfs *)class_dev->driver_data;
if (!sfp) return -EINVAL;
ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 4563b3df8a0..7a596ea7cfe 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -1121,15 +1121,12 @@ static const struct file_operations vdev_fops = {
};
-#define VID_HARDWARE_PVRUSB2 38 /* FIXME : need a good value */
-
static struct video_device vdev_template = {
.owner = THIS_MODULE,
.type = VID_TYPE_CAPTURE | VID_TYPE_TUNER,
.type2 = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE
| V4L2_CAP_TUNER | V4L2_CAP_AUDIO
| V4L2_CAP_READWRITE),
- .hardware = VID_HARDWARE_PVRUSB2,
.fops = &vdev_fops,
};
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 338ced7188f..ea53316d211 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -1648,7 +1648,7 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
ARG_OUT(cmd)
break;
}
- /*
+ /*
case VIDIOCPWCGVIDTABLE:
{
ARG_DEF(struct pwc_table_init_buffer, table);
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 931b274bffc..7300ace8f44 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -64,7 +64,6 @@
#include <linux/vmalloc.h>
#include <linux/version.h>
#include <asm/io.h>
-#include <linux/moduleparam.h>
#include "pwc.h"
#include "pwc-kiara.h"
@@ -127,9 +126,9 @@ static struct usb_driver pwc_driver = {
static int default_size = PSZ_QCIF;
static int default_fps = 10;
static int default_fbufs = 3; /* Default number of frame buffers */
- int pwc_mbufs = 2; /* Default number of mmap() buffers */
+ int pwc_mbufs = 2; /* Default number of mmap() buffers */
#ifdef CONFIG_USB_PWC_DEBUG
- int pwc_trace = PWC_DEBUG_LEVEL;
+ int pwc_trace = PWC_DEBUG_LEVEL;
#endif
static int power_save = 0;
static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
@@ -167,7 +166,6 @@ static struct video_device pwc_template = {
.owner = THIS_MODULE,
.name = "Philips Webcam", /* Filled in later */
.type = VID_TYPE_CAPTURE,
- .hardware = VID_HARDWARE_PWC,
.release = video_device_release,
.fops = &pwc_fops,
.minor = -1,
@@ -908,31 +906,49 @@ int pwc_isoc_init(struct pwc_device *pdev)
return 0;
}
-void pwc_isoc_cleanup(struct pwc_device *pdev)
+static void pwc_iso_stop(struct pwc_device *pdev)
{
int i;
- PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
- if (pdev == NULL)
- return;
- if (pdev->iso_init == 0)
- return;
-
/* Unlinking ISOC buffers one by one */
for (i = 0; i < MAX_ISO_BUFS; i++) {
struct urb *urb;
urb = pdev->sbuf[i].urb;
if (urb != 0) {
- if (pdev->iso_init) {
- PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
- usb_kill_urb(urb);
- }
+ PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
+ usb_kill_urb(urb);
+ }
+ }
+}
+
+static void pwc_iso_free(struct pwc_device *pdev)
+{
+ int i;
+
+ /* Freeing ISOC buffers one by one */
+ for (i = 0; i < MAX_ISO_BUFS; i++) {
+ struct urb *urb;
+
+ urb = pdev->sbuf[i].urb;
+ if (urb != 0) {
PWC_DEBUG_MEMORY("Freeing URB\n");
usb_free_urb(urb);
pdev->sbuf[i].urb = NULL;
}
}
+}
+
+void pwc_isoc_cleanup(struct pwc_device *pdev)
+{
+ PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
+ if (pdev == NULL)
+ return;
+ if (pdev->iso_init == 0)
+ return;
+
+ pwc_iso_stop(pdev);
+ pwc_iso_free(pdev);
/* Stop camera, but only if we are sure the camera is still there (unplug
is signalled by EPIPE)
@@ -979,20 +995,22 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
/*********
* sysfs
*********/
-static struct pwc_device *cd_to_pwc(struct class_device *cd)
+static struct pwc_device *cd_to_pwc(struct device *cd)
{
struct video_device *vdev = to_video_device(cd);
return video_get_drvdata(vdev);
}
-static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf)
+static ssize_t show_pan_tilt(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pwc_device *pdev = cd_to_pwc(class_dev);
return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
}
-static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf,
- size_t count)
+static ssize_t store_pan_tilt(struct device *class_dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct pwc_device *pdev = cd_to_pwc(class_dev);
int pan, tilt;
@@ -1008,10 +1026,11 @@ static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf,
return ret;
return strlen(buf);
}
-static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
- store_pan_tilt);
+static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
+ store_pan_tilt);
-static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf)
+static ssize_t show_snapshot_button_status(struct device *class_dev,
+ struct device_attribute *attr, char *buf)
{
struct pwc_device *pdev = cd_to_pwc(class_dev);
int status = pdev->snapshot_button_status;
@@ -1019,26 +1038,26 @@ static ssize_t show_snapshot_button_status(struct class_device *class_dev, char
return sprintf(buf, "%d\n", status);
}
-static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
- NULL);
+static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
+ NULL);
static int pwc_create_sysfs_files(struct video_device *vdev)
{
struct pwc_device *pdev = video_get_drvdata(vdev);
int rc;
- rc = video_device_create_file(vdev, &class_device_attr_button);
+ rc = video_device_create_file(vdev, &dev_attr_button);
if (rc)
goto err;
if (pdev->features & FEATURE_MOTOR_PANTILT) {
- rc = video_device_create_file(vdev,&class_device_attr_pan_tilt);
+ rc = video_device_create_file(vdev, &dev_attr_pan_tilt);
if (rc) goto err_button;
}
return 0;
err_button:
- video_device_remove_file(vdev, &class_device_attr_button);
+ video_device_remove_file(vdev, &dev_attr_button);
err:
return rc;
}
@@ -1047,8 +1066,8 @@ static void pwc_remove_sysfs_files(struct video_device *vdev)
{
struct pwc_device *pdev = video_get_drvdata(vdev);
if (pdev->features & FEATURE_MOTOR_PANTILT)
- video_device_remove_file(vdev, &class_device_attr_pan_tilt);
- video_device_remove_file(vdev, &class_device_attr_button);
+ video_device_remove_file(vdev, &dev_attr_pan_tilt);
+ video_device_remove_file(vdev, &dev_attr_button);
}
#ifdef CONFIG_USB_PWC_DEBUG
@@ -1212,6 +1231,7 @@ static int pwc_video_close(struct inode *inode, struct file *file)
PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
+ lock_kernel();
pdev = (struct pwc_device *)vdev->priv;
if (pdev->vopen == 0)
PWC_DEBUG_MODULE("video_close() called on closed device?\n");
@@ -1231,7 +1251,6 @@ static int pwc_video_close(struct inode *inode, struct file *file)
pwc_isoc_cleanup(pdev);
pwc_free_buffers(pdev);
- lock_kernel();
/* Turn off LEDS and power down camera, but only when not unplugged */
if (!pdev->unplugged) {
/* Turn LEDs off */
@@ -1277,7 +1296,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
struct pwc_device *pdev;
int noblock = file->f_flags & O_NONBLOCK;
DECLARE_WAITQUEUE(wait, current);
- int bytes_to_read;
+ int bytes_to_read, rv = 0;
void *image_buffer_addr;
PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
@@ -1287,8 +1306,12 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
pdev = vdev->priv;
if (pdev == NULL)
return -EFAULT;
- if (pdev->error_status)
- return -pdev->error_status; /* Something happened, report what. */
+
+ mutex_lock(&pdev->modlock);
+ if (pdev->error_status) {
+ rv = -pdev->error_status; /* Something happened, report what. */
+ goto err_out;
+ }
/* In case we're doing partial reads, we don't have to wait for a frame */
if (pdev->image_read_pos == 0) {
@@ -1299,17 +1322,20 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
if (pdev->error_status) {
remove_wait_queue(&pdev->frameq, &wait);
set_current_state(TASK_RUNNING);
- return -pdev->error_status ;
+ rv = -pdev->error_status ;
+ goto err_out;
}
if (noblock) {
remove_wait_queue(&pdev->frameq, &wait);
set_current_state(TASK_RUNNING);
- return -EWOULDBLOCK;
+ rv = -EWOULDBLOCK;
+ goto err_out;
}
if (signal_pending(current)) {
remove_wait_queue(&pdev->frameq, &wait);
set_current_state(TASK_RUNNING);
- return -ERESTARTSYS;
+ rv = -ERESTARTSYS;
+ goto err_out;
}
schedule();
set_current_state(TASK_INTERRUPTIBLE);
@@ -1318,8 +1344,10 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
set_current_state(TASK_RUNNING);
/* Decompress and release frame */
- if (pwc_handle_frame(pdev))
- return -EFAULT;
+ if (pwc_handle_frame(pdev)) {
+ rv = -EFAULT;
+ goto err_out;
+ }
}
PWC_DEBUG_READ("Copying data to user space.\n");
@@ -1334,14 +1362,20 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
image_buffer_addr = pdev->image_data;
image_buffer_addr += pdev->images[pdev->fill_image].offset;
image_buffer_addr += pdev->image_read_pos;
- if (copy_to_user(buf, image_buffer_addr, count))
- return -EFAULT;
+ if (copy_to_user(buf, image_buffer_addr, count)) {
+ rv = -EFAULT;
+ goto err_out;
+ }
pdev->image_read_pos += count;
if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
pdev->image_read_pos = 0;
pwc_next_image(pdev);
}
+ mutex_unlock(&pdev->modlock);
return count;
+err_out:
+ mutex_unlock(&pdev->modlock);
+ return rv;
}
static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
@@ -1367,7 +1401,20 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
static int pwc_video_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
+ struct video_device *vdev = file->private_data;
+ struct pwc_device *pdev;
+ int r = -ENODEV;
+
+ if (!vdev)
+ goto out;
+ pdev = vdev->priv;
+
+ mutex_lock(&pdev->modlock);
+ if (!pdev->unplugged)
+ r = video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
+ mutex_unlock(&pdev->modlock);
+out:
+ return r;
}
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
@@ -1810,7 +1857,10 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
wake_up_interruptible(&pdev->frameq);
/* Wait until device is closed */
if(pdev->vopen) {
+ mutex_lock(&pdev->modlock);
pdev->unplugged = 1;
+ mutex_unlock(&pdev->modlock);
+ pwc_iso_stop(pdev);
} else {
/* Device is closed, so we can safely unregister it */
PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
@@ -1828,7 +1878,6 @@ disconnect_out:
unlock_kernel();
}
-
/* *grunt* We have to do atoi ourselves :-( */
static int pwc_atoi(const char *s)
{
@@ -1853,9 +1902,9 @@ static int fbufs;
static int mbufs;
static int compression = -1;
static int leds[2] = { -1, -1 };
-static int leds_nargs;
+static unsigned int leds_nargs;
static char *dev_hint[MAX_DEV_HINTS];
-static int dev_hint_nargs;
+static unsigned int dev_hint_nargs;
module_param(size, charp, 0444);
module_param(fps, int, 0444);
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
index e20aa3612a7..ad0232935df 100644
--- a/drivers/media/video/saa5246a.c
+++ b/drivers/media/video/saa5246a.c
@@ -196,10 +196,10 @@ static int i2c_senddata(struct saa5246a_device *t, ...)
return i2c_sendbuf(t, buf[0], ct-1, buf+1);
}
-/* Get count number of bytes from I²C-device at address adr, store them in buf.
+/* Get count number of bytes from I²C-device at address adr, store them in buf.
* Start & stop handshaking is done by this routine, ack will be sent after the
* last byte to inhibit further sending of data. If uaccess is 'true', data is
- * written to user-space with put_user. Returns -1 if I²C-device didn't send
+ * written to user-space with put_user. Returns -1 if I²C-device didn't send
* acknowledge, 0 otherwise
*/
static int i2c_getdata(struct saa5246a_device *t, int count, u8 *buf)
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index 17f1e2e9a66..94bb59a32b1 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -291,10 +291,10 @@ static int i2c_senddata(struct saa5249_device *t, ...)
return i2c_sendbuf(t, buf[0], ct-1, buf+1);
}
-/* Get count number of bytes from I²C-device at address adr, store them in buf. Start & stop
+/* Get count number of bytes from I²C-device at address adr, store them in buf. Start & stop
* handshaking is done by this routine, ack will be sent after the last byte to inhibit further
* sending of data. If uaccess is 'true', data is written to user-space with put_user.
- * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
+ * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
*/
static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index 92eabf88a09..72e344a12c7 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -406,6 +406,7 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind)
kfree(s);
return -ENOMEM;
}
+ spin_lock_init(&s->lock);
s->client = client_template;
s->block_count = 0;
s->wr_index = 0;
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index 9f986930490..e35ef321ec7 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -332,11 +332,11 @@ static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_dat
if (!enable)
return 0;
- state->vps_data[0] = data->data[4];
- state->vps_data[1] = data->data[10];
- state->vps_data[2] = data->data[11];
- state->vps_data[3] = data->data[12];
- state->vps_data[4] = data->data[13];
+ state->vps_data[0] = data->data[2];
+ state->vps_data[1] = data->data[8];
+ state->vps_data[2] = data->data[9];
+ state->vps_data[3] = data->data[10];
+ state->vps_data[4] = data->data[11];
v4l_dbg(1, debug, client, "Set VPS data %02x %02x %02x %02x %02x\n",
state->vps_data[0], state->vps_data[1],
state->vps_data[2], state->vps_data[3],
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 9f1417a4f7d..3aa8cb2b860 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -1,7 +1,7 @@
config VIDEO_SAA7134
tristate "Philips SAA7134 support"
- depends on VIDEO_DEV && PCI && I2C
- select VIDEO_BUF
+ depends on VIDEO_DEV && PCI && I2C && INPUT
+ select VIDEOBUF_DMA_SG
select VIDEO_IR
select VIDEO_TUNER
select CRC32
@@ -38,7 +38,7 @@ config VIDEO_SAA7134_OSS
config VIDEO_SAA7134_DVB
tristate "DVB/ATSC Support for saa7134 based TV cards"
depends on VIDEO_SAA7134 && DVB_CORE
- select VIDEO_BUF_DVB
+ select VIDEOBUF_DVB
select FW_LOADER
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 57f1f5d409e..002e70a33a4 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -71,7 +71,6 @@ static const struct v4l2_format v4l2_format_table[] =
struct saa6752hs_state {
struct i2c_client client;
- struct v4l2_mpeg_compression old_params;
struct saa6752hs_mpeg_params params;
enum saa6752hs_videoformat video_format;
v4l2_std_id standard;
@@ -161,35 +160,6 @@ static struct saa6752hs_mpeg_params param_defaults =
.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
};
-static struct v4l2_mpeg_compression old_param_defaults =
-{
- .st_type = V4L2_MPEG_TS_2,
- .st_bitrate = {
- .mode = V4L2_BITRATE_CBR,
- .target = 7000,
- },
-
- .ts_pid_pmt = 16,
- .ts_pid_video = 260,
- .ts_pid_audio = 256,
- .ts_pid_pcr = 259,
-
- .vi_type = V4L2_MPEG_VI_2,
- .vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3,
- .vi_bitrate = {
- .mode = V4L2_BITRATE_VBR,
- .target = 4000,
- .max = 6000,
- },
-
- .au_type = V4L2_MPEG_AU_2_II,
- .au_bitrate = {
- .mode = V4L2_BITRATE_CBR,
- .target = 256,
- },
-
-};
-
/* ---------------------------------------------------------------------- */
static int saa6752hs_chip_command(struct i2c_client* client,
@@ -362,74 +332,6 @@ static void saa6752hs_set_subsampling(struct i2c_client* client,
}
-static void saa6752hs_old_set_params(struct i2c_client* client,
- struct v4l2_mpeg_compression* params)
-{
- struct saa6752hs_state *h = i2c_get_clientdata(client);
-
- /* check PIDs */
- if (params->ts_pid_pmt <= MPEG_PID_MAX) {
- h->old_params.ts_pid_pmt = params->ts_pid_pmt;
- h->params.ts_pid_pmt = params->ts_pid_pmt;
- }
- if (params->ts_pid_pcr <= MPEG_PID_MAX) {
- h->old_params.ts_pid_pcr = params->ts_pid_pcr;
- h->params.ts_pid_pcr = params->ts_pid_pcr;
- }
- if (params->ts_pid_video <= MPEG_PID_MAX) {
- h->old_params.ts_pid_video = params->ts_pid_video;
- h->params.ts_pid_video = params->ts_pid_video;
- }
- if (params->ts_pid_audio <= MPEG_PID_MAX) {
- h->old_params.ts_pid_audio = params->ts_pid_audio;
- h->params.ts_pid_audio = params->ts_pid_audio;
- }
-
- /* check bitrate parameters */
- if ((params->vi_bitrate.mode == V4L2_BITRATE_CBR) ||
- (params->vi_bitrate.mode == V4L2_BITRATE_VBR)) {
- h->old_params.vi_bitrate.mode = params->vi_bitrate.mode;
- h->params.vi_bitrate_mode = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ?
- V4L2_MPEG_VIDEO_BITRATE_MODE_VBR : V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
- }
- if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
- h->old_params.st_bitrate.target = params->st_bitrate.target;
- if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
- h->old_params.vi_bitrate.target = params->vi_bitrate.target;
- if (params->vi_bitrate.mode == V4L2_BITRATE_VBR)
- h->old_params.vi_bitrate.max = params->vi_bitrate.max;
- if (params->au_bitrate.mode != V4L2_BITRATE_NONE)
- h->old_params.au_bitrate.target = params->au_bitrate.target;
-
- /* aspect ratio */
- if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3 ||
- params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9) {
- h->old_params.vi_aspect_ratio = params->vi_aspect_ratio;
- if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3)
- h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
- else
- h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_16x9;
- }
-
- /* range checks */
- if (h->old_params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
- h->old_params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
- if (h->old_params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
- h->old_params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
- if (h->old_params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
- h->old_params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
- h->params.vi_bitrate = params->vi_bitrate.target;
- h->params.vi_bitrate_peak = params->vi_bitrate.max;
- if (h->old_params.au_bitrate.target <= 256) {
- h->old_params.au_bitrate.target = 256;
- h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
- }
- else {
- h->old_params.au_bitrate.target = 384;
- h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
- }
-}
-
static int handle_ctrl(struct saa6752hs_mpeg_params *params,
struct v4l2_ext_control *ctrl, unsigned int cmd)
{
@@ -697,7 +599,6 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
return -ENOMEM;
h->client = client_template;
h->params = param_defaults;
- h->old_params = old_param_defaults;
h->client.adapter = adap;
h->client.addr = addr;
@@ -734,23 +635,11 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct saa6752hs_state *h = i2c_get_clientdata(client);
struct v4l2_ext_controls *ctrls = arg;
- struct v4l2_mpeg_compression *old_params = arg;
struct saa6752hs_mpeg_params params;
int err = 0;
int i;
switch (cmd) {
- case VIDIOC_S_MPEGCOMP:
- if (NULL == old_params) {
- /* apply settings and start encoder */
- saa6752hs_init(client);
- break;
- }
- saa6752hs_old_set_params(client, old_params);
- /* fall through */
- case VIDIOC_G_MPEGCOMP:
- *old_params = h->old_params;
- break;
case VIDIOC_S_EXT_CTRLS:
if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index 3c0fc9027ad..b9c5cf7dc84 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -20,7 +20,6 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/wait.h>
-#include <linux/moduleparam.h>
#include <linux/module.h>
#include <sound/driver.h>
#include <sound/core.h>
@@ -313,7 +312,7 @@ static int dsp_buffer_free(struct saa7134_dev *dev)
dev->dmasound.blksize = 0;
dev->dmasound.bufsize = 0;
- return 0;
+ return 0;
}
@@ -544,8 +543,10 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
V4L functions, and force ALSA to use that as the DMA area */
substream->runtime->dma_area = dev->dmasound.dma.vmalloc;
+ substream->runtime->dma_bytes = dev->dmasound.bufsize;
+ substream->runtime->dma_addr = 0;
- return 1;
+ return 0;
}
@@ -653,6 +654,17 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
}
/*
+ * page callback (needed for mmap)
+ */
+
+static struct page *snd_card_saa7134_page(struct snd_pcm_substream *substream,
+ unsigned long offset)
+{
+ void *pageptr = substream->runtime->dma_area + offset;
+ return vmalloc_to_page(pageptr);
+}
+
+/*
* ALSA capture callbacks definition
*/
@@ -665,6 +677,7 @@ static struct snd_pcm_ops snd_card_saa7134_capture_ops = {
.prepare = snd_card_saa7134_capture_prepare,
.trigger = snd_card_saa7134_capture_trigger,
.pointer = snd_card_saa7134_capture_pointer,
+ .page = snd_card_saa7134_page,
};
/*
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 25ec1681081..4f3dad9ae6d 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -32,6 +32,7 @@ static char name_mute[] = "mute";
static char name_radio[] = "Radio";
static char name_tv[] = "Television";
static char name_tv_mono[] = "TV (mono only)";
+static char name_comp[] = "Composite";
static char name_comp1[] = "Composite1";
static char name_comp2[] = "Composite2";
static char name_comp3[] = "Composite3";
@@ -1535,12 +1536,7 @@ struct saa7134_board saa7134_boards[] = {
.tv = 1,
.gpio = 0x00,
},{
- .name = name_comp1,
- .vmux = 0,
- .amux = LINE1,
- .gpio = 0x02,
- },{
- .name = name_comp2,
+ .name = name_comp,
.vmux = 3,
.amux = LINE1,
.gpio = 0x02,
@@ -2771,6 +2767,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 1 << 21,
.inputs = {{
.name = name_tv,
.vmux = 1,
@@ -2781,13 +2778,18 @@ struct saa7134_board saa7134_boards[] = {
.vmux = 3,
.amux = LINE1,
},{
- .name = name_svideo,
+ .name = name_comp2,
.vmux = 0,
.amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
}},
.radio = {
.name = name_radio,
- .amux = LINE1,
+ .amux = TV,
+ .gpio = 0x0200000,
},
},
[SAA7134_BOARD_KWORLD_DVBT_210] = {
@@ -2820,7 +2822,7 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_KWORLD_ATSC110] = {
- .name = "Kworld ATSC110",
+ .name = "Kworld ATSC110/115",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_TUV1236D,
.radio_type = UNSET,
@@ -2896,7 +2898,7 @@ struct saa7134_board saa7134_boards[] = {
.radio_addr = ADDR_UNSET,
},
[SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS] = {
- .name = "LifeView FlyDVB-T Hybrid Cardbus",
+ .name = "LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_TDA8290,
.radio_type = UNSET,
@@ -2994,11 +2996,11 @@ struct saa7134_board saa7134_boards[] = {
},{
.name = name_comp1,
.vmux = 0,
- .amux = LINE2,
+ .amux = LINE1,
},{
.name = name_svideo,
.vmux = 8,
- .amux = LINE2,
+ .amux = LINE1,
}},
},
[SAA7134_BOARD_FLYDVBS_LR300] = {
@@ -3534,6 +3536,22 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x3000,
},
},
+ [SAA7134_BOARD_AVERMEDIA_SUPER_007] = {
+ .name = "Avermedia Super 007",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tuner_config = 0,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv, /* FIXME: analog tv untested */
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }},
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4066,6 +4084,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.driver_data = SAA7134_BOARD_KWORLD_ATSC110,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+ .subvendor = 0x17de,
+ .subdevice = 0x7352,
+ .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x1461,
.subdevice = 0x7360,
@@ -4257,6 +4281,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x2304,
.driver_data = SAA7134_BOARD_10MOONSTVMASTER3,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */
+ .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x4e42,
+ .subdevice = 0x3502,
+ .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS
+ },{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -4564,6 +4600,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_PHILIPS_TIGER:
case SAA7134_BOARD_PHILIPS_TIGER_S:
+ case SAA7134_BOARD_AVERMEDIA_SUPER_007:
{
u8 data[] = { 0x3c, 0x33, 0x60};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 25f84701a8e..a499eea379e 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/kmod.h>
@@ -32,6 +31,7 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/dma-mapping.h>
+#include <linux/pm.h>
#include "saa7134-reg.h"
#include "saa7134.h"
@@ -237,9 +237,10 @@ int saa7134_buffer_startpage(struct saa7134_buf *buf)
unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
{
unsigned long base;
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
base = saa7134_buffer_startpage(buf) * 4096;
- base += buf->vb.dma.sglist[0].offset;
+ base += dma->sglist[0].offset;
return base;
}
@@ -287,11 +288,12 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt)
void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
{
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
BUG_ON(in_interrupt());
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, &buf->vb.dma);
- videobuf_dma_free(&buf->vb.dma);
+ videobuf_dma_unmap(q, dma);
+ videobuf_dma_free(dma);
buf->vb.state = STATE_NEEDS_INIT;
}
@@ -391,6 +393,32 @@ void saa7134_buffer_timeout(unsigned long data)
spin_unlock_irqrestore(&dev->slock,flags);
}
+/* resends a current buffer in queue after resume */
+
+int saa7134_buffer_requeue(struct saa7134_dev *dev,
+ struct saa7134_dmaqueue *q)
+{
+ struct saa7134_buf *buf, *next;
+
+ assert_spin_locked(&dev->slock);
+
+ buf = q->curr;
+ next = buf;
+ dprintk("buffer_requeue\n");
+
+ if (!buf)
+ return 0;
+
+ dprintk("buffer_requeue : resending active buffers \n");
+
+ if (!list_empty(&q->queue))
+ next = list_entry(q->queue.next, struct saa7134_buf,
+ vb.queue);
+ buf->activate(dev, buf, next);
+
+ return 0;
+}
+
/* ------------------------------------------------------------------ */
int saa7134_set_dmabits(struct saa7134_dev *dev)
@@ -401,6 +429,9 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
assert_spin_locked(&dev->slock);
+ if (dev->insuspend)
+ return 0;
+
/* video capture -- dma 0 + video task A */
if (dev->video_q.curr) {
task |= 0x01;
@@ -532,6 +563,9 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id)
unsigned long report,status;
int loop, handled = 0;
+ if (dev->insuspend)
+ goto out;
+
for (loop = 0; loop < 10; loop++) {
report = saa_readl(SAA7134_IRQ_REPORT);
status = saa_readl(SAA7134_IRQ_STATUS);
@@ -560,8 +594,10 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id)
print_irqstatus(dev,loop,report,status);
- if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */)
- saa7134_irq_video_intl(dev);
+ if ((report & SAA7134_IRQ_REPORT_RDCAP) ||
+ (report & SAA7134_IRQ_REPORT_INTL))
+ saa7134_irq_video_signalchange(dev);
+
if ((report & SAA7134_IRQ_REPORT_DONE_RA0) &&
(status & 0x60) == 0)
@@ -646,6 +682,39 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id)
/* ------------------------------------------------------------------ */
/* early init (no i2c, no irq) */
+
+static int saa7134_hw_enable1(struct saa7134_dev *dev)
+{
+ /* RAM FIFO config */
+ saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
+ saa_writel(SAA7134_THRESHOULD, 0x02020202);
+
+ /* enable audio + video processing */
+ saa_writel(SAA7134_MAIN_CTRL,
+ SAA7134_MAIN_CTRL_VPLLE |
+ SAA7134_MAIN_CTRL_APLLE |
+ SAA7134_MAIN_CTRL_EXOSC |
+ SAA7134_MAIN_CTRL_EVFE1 |
+ SAA7134_MAIN_CTRL_EVFE2 |
+ SAA7134_MAIN_CTRL_ESFE |
+ SAA7134_MAIN_CTRL_EBDAC);
+
+ /*
+ * Initialize OSS _after_ enabling audio clock PLL and audio processing.
+ * OSS initialization writes to registers via the audio DSP; these
+ * writes will fail unless the audio clock has been started. At worst,
+ * audio will not work.
+ */
+
+ /* enable peripheral devices */
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+
+ /* set vertical line numbering start (vbi needs this) */
+ saa_writeb(SAA7134_SOURCE_TIMING2, 0x20);
+
+ return 0;
+}
+
static int saa7134_hwinit1(struct saa7134_dev *dev)
{
dprintk("hwinit1\n");
@@ -662,44 +731,16 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
saa7134_ts_init1(dev);
saa7134_input_init1(dev);
- /* RAM FIFO config */
- saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
- saa_writel(SAA7134_THRESHOULD,0x02020202);
-
- /* enable audio + video processing */
- saa_writel(SAA7134_MAIN_CTRL,
- SAA7134_MAIN_CTRL_VPLLE |
- SAA7134_MAIN_CTRL_APLLE |
- SAA7134_MAIN_CTRL_EXOSC |
- SAA7134_MAIN_CTRL_EVFE1 |
- SAA7134_MAIN_CTRL_EVFE2 |
- SAA7134_MAIN_CTRL_ESFE |
- SAA7134_MAIN_CTRL_EBDAC);
-
- /*
- * Initialize OSS _after_ enabling audio clock PLL and audio processing.
- * OSS initialization writes to registers via the audio DSP; these
- * writes will fail unless the audio clock has been started. At worst,
- * audio will not work.
- */
-
- /* enable peripheral devices */
- saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
-
- /* set vertical line numbering start (vbi needs this) */
- saa_writeb(SAA7134_SOURCE_TIMING2, 0x20);
+ saa7134_hw_enable1(dev);
return 0;
}
/* late init (with i2c + irq) */
-static int saa7134_hwinit2(struct saa7134_dev *dev)
+static int saa7134_hw_enable2(struct saa7134_dev *dev)
{
- unsigned int irq2_mask;
- dprintk("hwinit2\n");
- saa7134_video_init2(dev);
- saa7134_tvaudio_init2(dev);
+ unsigned int irq2_mask;
/* enable IRQ's */
irq2_mask =
@@ -725,6 +766,20 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
return 0;
}
+static int saa7134_hwinit2(struct saa7134_dev *dev)
+{
+
+ dprintk("hwinit2\n");
+
+ saa7134_video_init2(dev);
+ saa7134_tvaudio_init2(dev);
+
+ saa7134_hw_enable2(dev);
+
+ return 0;
+}
+
+
/* shutdown */
static int saa7134_hwfini(struct saa7134_dev *dev)
{
@@ -838,7 +893,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
struct saa7134_dev *dev;
- struct list_head *item;
struct saa7134_mpeg_ops *mops;
int err;
@@ -1020,15 +1074,13 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
saa7134_devcount++;
mutex_lock(&devlist_lock);
- list_for_each(item,&mops_list) {
- mops = list_entry(item, struct saa7134_mpeg_ops, next);
+ list_for_each_entry(mops, &mops_list, next)
mpeg_ops_attach(mops, dev);
- }
list_add_tail(&dev->devlist,&saa7134_devlist);
mutex_unlock(&devlist_lock);
/* check for signal */
- saa7134_irq_video_intl(dev);
+ saa7134_irq_video_signalchange(dev);
if (saa7134_dmasound_init && !dev->dmasound.priv_data) {
saa7134_dmasound_init(dev);
@@ -1057,7 +1109,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
{
struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
- struct list_head *item;
struct saa7134_mpeg_ops *mops;
/* Release DMA sound modules if present */
@@ -1086,10 +1137,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
/* unregister */
mutex_lock(&devlist_lock);
list_del(&dev->devlist);
- list_for_each(item,&mops_list) {
- mops = list_entry(item, struct saa7134_mpeg_ops, next);
+ list_for_each_entry(mops, &mops_list, next)
mpeg_ops_detach(mops, dev);
- }
mutex_unlock(&devlist_lock);
saa7134_devcount--;
@@ -1117,18 +1166,102 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
kfree(dev);
}
+#ifdef CONFIG_PM
+static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
+{
+
+ struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+
+ /* disable overlay - apps should enable it explicitly on resume*/
+ dev->ovenable = 0;
+
+ /* Disable interrupts, DMA, and rest of the chip*/
+ saa_writel(SAA7134_IRQ1, 0);
+ saa_writel(SAA7134_IRQ2, 0);
+ saa_writel(SAA7134_MAIN_CTRL, 0);
+
+ synchronize_irq(pci_dev->irq);
+ dev->insuspend = 1;
+
+ /* Disable timeout timers - if we have active buffers, we will
+ fill them on resume*/
+
+ del_timer(&dev->video_q.timeout);
+ del_timer(&dev->vbi_q.timeout);
+ del_timer(&dev->ts_q.timeout);
+
+ if (dev->remote)
+ saa7134_ir_stop(dev);
+
+ pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+ pci_save_state(pci_dev);
+
+ return 0;
+}
+
+static int saa7134_resume(struct pci_dev *pci_dev)
+{
+
+ struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+ unsigned int flags;
+
+ pci_restore_state(pci_dev);
+ pci_set_power_state(pci_dev, PCI_D0);
+
+ /* Do things that are done in saa7134_initdev ,
+ except of initializing memory structures.*/
+
+ saa7134_board_init1(dev);
+
+ /* saa7134_hwinit1 */
+ if (saa7134_boards[dev->board].video_out)
+ saa7134_videoport_init(dev);
+ if (card_has_mpeg(dev))
+ saa7134_ts_init_hw(dev);
+ if (dev->remote)
+ saa7134_ir_start(dev, dev->remote);
+ saa7134_hw_enable1(dev);
+
+
+ saa7134_board_init2(dev);
+
+ /*saa7134_hwinit2*/
+ saa7134_set_tvnorm_hw(dev);
+ saa7134_tvaudio_setmute(dev);
+ saa7134_tvaudio_setvolume(dev, dev->ctl_volume);
+ saa7134_tvaudio_do_scan(dev);
+ saa7134_enable_i2s(dev);
+ saa7134_hw_enable2(dev);
+
+ /*resume unfinished buffer(s)*/
+ spin_lock_irqsave(&dev->slock, flags);
+ saa7134_buffer_requeue(dev, &dev->video_q);
+ saa7134_buffer_requeue(dev, &dev->vbi_q);
+ saa7134_buffer_requeue(dev, &dev->ts_q);
+
+ /* FIXME: Disable DMA audio sound - temporary till proper support
+ is implemented*/
+
+ dev->dmasound.dma_running = 0;
+
+ /* start DMA now*/
+ dev->insuspend = 0;
+ saa7134_set_dmabits(dev);
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ return 0;
+}
+#endif
+
/* ----------------------------------------------------------- */
int saa7134_ts_register(struct saa7134_mpeg_ops *ops)
{
- struct list_head *item;
struct saa7134_dev *dev;
mutex_lock(&devlist_lock);
- list_for_each(item,&saa7134_devlist) {
- dev = list_entry(item, struct saa7134_dev, devlist);
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
mpeg_ops_attach(ops, dev);
- }
list_add_tail(&ops->next,&mops_list);
mutex_unlock(&devlist_lock);
return 0;
@@ -1136,15 +1269,12 @@ int saa7134_ts_register(struct saa7134_mpeg_ops *ops)
void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops)
{
- struct list_head *item;
struct saa7134_dev *dev;
mutex_lock(&devlist_lock);
list_del(&ops->next);
- list_for_each(item,&saa7134_devlist) {
- dev = list_entry(item, struct saa7134_dev, devlist);
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
mpeg_ops_detach(ops, dev);
- }
mutex_unlock(&devlist_lock);
}
@@ -1158,6 +1288,10 @@ static struct pci_driver saa7134_pci_driver = {
.id_table = saa7134_pci_tbl,
.probe = saa7134_initdev,
.remove = __devexit_p(saa7134_finidev),
+#ifdef CONFIG_PM
+ .suspend = saa7134_suspend,
+ .resume = saa7134_resume
+#endif
};
static int saa7134_init(void)
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 1f6bd330071..38d87332cc5 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -567,6 +567,7 @@ static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config
}
/* ------------------------------------------------------------------ */
+
static struct tda1004x_config tda827x_lifeview_config = {
.demod_address = 0x08,
.invert = 1,
@@ -746,6 +747,7 @@ static struct tda1004x_config asus_p7131_hybrid_lna_config = {
.antenna_switch= 2,
.request_firmware = philips_tda1004x_request_firmware
};
+
static struct tda1004x_config kworld_dvb_t_210_config = {
.demod_address = 0x08,
.invert = 1,
@@ -760,6 +762,22 @@ static struct tda1004x_config kworld_dvb_t_210_config = {
.antenna_switch= 1,
.request_firmware = philips_tda1004x_request_firmware
};
+
+static struct tda1004x_config avermedia_super_007_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP01_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x60,
+ .tuner_config = 0,
+ .antenna_switch= 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
/* ------------------------------------------------------------------
* special case: this card uses saa713x GPIO22 for the mode switch
*/
@@ -832,7 +850,7 @@ static int dvb_init(struct saa7134_dev *dev)
dev->ts.nr_bufs = 32;
dev->ts.nr_packets = 32*4;
dev->dvb.name = dev->name;
- videobuf_queue_init(&dev->dvb.dvbq, &saa7134_ts_qops,
+ videobuf_queue_pci_init(&dev->dvb.dvbq, &saa7134_ts_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_ALTERNATE,
@@ -1022,6 +1040,9 @@ static int dvb_init(struct saa7134_dev *dev)
case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config);
break;
+ case SAA7134_BOARD_AVERMEDIA_SUPER_007:
+ configure_tda827x_fe(dev, &avermedia_super_007_config);
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index fc260ec8fdc..75d0c5bf46d 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -20,7 +20,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -77,17 +76,14 @@ static int ts_init_encoder(struct saa7134_dev* dev)
static int ts_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
- struct saa7134_dev *h,*dev = NULL;
- struct list_head *list;
+ struct saa7134_dev *dev;
int err;
- list_for_each(list,&saa7134_devlist) {
- h = list_entry(list, struct saa7134_dev, devlist);
- if (h->empress_dev && h->empress_dev->minor == minor)
- dev = h;
- }
- if (NULL == dev)
- return -ENODEV;
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
+ if (dev->empress_dev && dev->empress_dev->minor == minor)
+ goto found;
+ return -ENODEV;
+ found:
dprintk("open minor=%d\n",minor);
err = -EBUSY;
@@ -288,17 +284,6 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_S_CTRL:
return saa7134_common_ioctl(dev, cmd, arg);
- case VIDIOC_S_MPEGCOMP:
- printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
- "Replace with VIDIOC_S_EXT_CTRLS!");
- saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, arg);
- ts_init_encoder(dev);
- return 0;
- case VIDIOC_G_MPEGCOMP:
- printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
- "Replace with VIDIOC_G_EXT_CTRLS!");
- saa7134_i2c_call_clients(dev, VIDIOC_G_MPEGCOMP, arg);
- return 0;
case VIDIOC_S_EXT_CTRLS:
/* count == 0 is abused in saa6752hs.c, so that special
case is handled here explicitly. */
@@ -346,7 +331,6 @@ static struct video_device saa7134_empress_template =
.name = "saa7134-empress",
.type = 0 /* FIXME */,
.type2 = 0 /* FIXME */,
- .hardware = 0,
.fops = &ts_fops,
.minor = -1,
};
@@ -401,7 +385,7 @@ static int empress_init(struct saa7134_dev *dev)
printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
dev->name,dev->empress_dev->minor & 0x1f);
- videobuf_queue_init(&dev->empress_tsq, &saa7134_ts_qops,
+ videobuf_queue_pci_init(&dev->empress_tsq, &saa7134_ts_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_ALTERNATE,
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 1cb8c709ca9..6deaad1a548 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -315,12 +314,6 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
/* ----------------------------------------------------------- */
-static int algo_control(struct i2c_adapter *adapter,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
static u32 functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_SMBUS_EMUL;
@@ -388,7 +381,6 @@ static int attach_inform(struct i2c_client *client)
static struct i2c_algorithm saa7134_algo = {
.master_xfer = saa7134_i2c_xfer,
- .algo_control = algo_control,
.functionality = functionality,
};
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 1b6dfd801cc..3abaa1b8ac9 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -19,7 +19,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
@@ -45,6 +44,14 @@ 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");
+
#define dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
#define i2cdprintk(fmt, arg...) if (ir_debug) \
@@ -60,6 +67,13 @@ static int build_key(struct saa7134_dev *dev)
struct card_ir *ir = dev->remote;
u32 gpio, data;
+ /* here comes the additional handshake steps for some cards */
+ switch (dev->board) {
+ case SAA7134_BOARD_GOTVIEW_7135:
+ saa_setb(SAA7134_GPIO_GPSTATUS1, 0x80);
+ saa_clearb(SAA7134_GPIO_GPSTATUS1, 0x80);
+ break;
+ }
/* rising SAA7134_GPIO_GPRESCAN reads the status */
saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN);
@@ -160,7 +174,7 @@ static void saa7134_input_timer(unsigned long data)
mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
-static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
+void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
{
if (ir->polling) {
setup_timer(&ir->timer, saa7134_input_timer,
@@ -183,7 +197,7 @@ static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
}
}
-static void saa7134_ir_stop(struct saa7134_dev *dev)
+void saa7134_ir_stop(struct saa7134_dev *dev)
{
if (dev->remote->polling)
del_timer_sync(&dev->remote->timer);
@@ -286,10 +300,10 @@ int saa7134_input_init1(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_GOTVIEW_7135:
ir_codes = ir_codes_gotview7135;
- mask_keycode = 0x0003EC;
- mask_keyup = 0x008000;
+ mask_keycode = 0x0003CC;
mask_keydown = 0x000010;
- polling = 50; // ms
+ polling = 5; /* ms */
+ saa_setb(SAA7134_GPIO_GPMODE1, 0x80);
break;
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
@@ -387,6 +401,10 @@ int saa7134_input_init1(struct saa7134_dev *dev)
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:
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index 72444f039e3..aedf04653e0 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -25,7 +25,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -240,17 +239,14 @@ static int dsp_rec_stop(struct saa7134_dev *dev)
static int dsp_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
- struct saa7134_dev *h,*dev = NULL;
- struct list_head *list;
+ struct saa7134_dev *dev;
int err;
- list_for_each(list,&saa7134_devlist) {
- h = list_entry(list, struct saa7134_dev, devlist);
- if (h->dmasound.minor_dsp == minor)
- dev = h;
- }
- if (NULL == dev)
- return -ENODEV;
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
+ if (dev->dmasound.minor_dsp == minor)
+ goto found;
+ return -ENODEV;
+ found:
mutex_lock(&dev->dmasound.lock);
err = -EBUSY;
@@ -681,19 +677,14 @@ mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level)
static int mixer_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
- struct saa7134_dev *h,*dev = NULL;
- struct list_head *list;
+ struct saa7134_dev *dev;
- list_for_each(list,&saa7134_devlist) {
- h = list_entry(list, struct saa7134_dev, devlist);
- if (h->dmasound.minor_mixer == minor)
- dev = h;
- }
- if (NULL == dev)
- return -ENODEV;
-
- file->private_data = dev;
- return 0;
+ list_for_each_entry(dev, &saa7134_devlist, devlist)
+ if (dev->dmasound.minor_mixer == minor) {
+ file->private_data = dev;
+ return 0;
+ }
+ return -ENODEV;
}
static int mixer_release(struct inode *inode, struct file *file)
@@ -1023,18 +1014,14 @@ static int saa7134_oss_init(void)
static void saa7134_oss_exit(void)
{
- struct saa7134_dev *dev = NULL;
- struct list_head *list;
-
- list_for_each(list,&saa7134_devlist) {
- dev = list_entry(list, struct saa7134_dev, devlist);
+ struct saa7134_dev *dev;
+ list_for_each_entry(dev, &saa7134_devlist, devlist) {
/* Device isn't registered by OSS, probably ALSA's */
if (!dev->dmasound.minor_dsp)
continue;
oss_device_exit(dev);
-
}
saa7134_dmasound_init = NULL;
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
index 60a90a2617a..4b63ad3e846 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -93,6 +92,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
}
if (STATE_NEEDS_INIT == buf->vb.state) {
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
buf->vb.width = llength;
buf->vb.height = lines;
buf->vb.size = size;
@@ -102,8 +103,8 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
if (err)
goto oops;
err = saa7134_pgtable_build(dev->pci,buf->pt,
- buf->vb.dma.sglist,
- buf->vb.dma.sglen,
+ dma->sglist,
+ dma->sglen,
saa7134_buffer_startpage(buf));
if (err)
goto oops;
@@ -176,6 +177,22 @@ static unsigned int ts_nr_packets = 64;
module_param(ts_nr_packets, int, 0444);
MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)");
+int saa7134_ts_init_hw(struct saa7134_dev *dev)
+{
+ /* deactivate TS softreset */
+ saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+ /* TSSOP high active, TSVAL high active, TSLOCK ignored */
+ saa_writeb(SAA7134_TS_PARALLEL, 0xec);
+ saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
+ saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
+ saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
+ /* TSNOPIT=0, TSCOLAP=0 */
+ saa_writeb(SAA7134_TS_DMA2,
+ ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00));
+
+ return 0;
+}
+
int saa7134_ts_init1(struct saa7134_dev *dev)
{
/* sanitycheck insmod options */
@@ -199,12 +216,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev)
saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts);
/* init TS hw */
- saa_writeb(SAA7134_TS_SERIAL1, 0x00); /* deactivate TS softreset */
- saa_writeb(SAA7134_TS_PARALLEL, 0xec); /* TSSOP high active, TSVAL high active, TSLOCK ignored */
- saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
- saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
- saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
- saa_writeb(SAA7134_TS_DMA2, ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */
+ saa7134_ts_init_hw(dev);
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 18b4817b4aa..f8e304c7623 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -23,11 +23,11 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/freezer.h>
#include <asm/div64.h>
#include "saa7134-reg.h"
@@ -232,7 +232,7 @@ static void mute_input_7134(struct saa7134_dev *dev)
}
if (dev->hw_mute == mute &&
- dev->hw_input == in) {
+ dev->hw_input == in && !dev->insuspend) {
dprintk("mute/input: nothing to do [mute=%d,input=%s]\n",
mute,in->name);
return;
@@ -503,13 +503,17 @@ static int tvaudio_thread(void *data)
unsigned int i, audio, nscan;
int max1,max2,carrier,rx,mode,lastmode,default_carrier;
- allow_signal(SIGTERM);
+
+ set_freezable();
+
for (;;) {
tvaudio_sleep(dev,-1);
- if (kthread_should_stop() || signal_pending(current))
+ if (kthread_should_stop())
goto done;
restart:
+ try_to_freeze();
+
dev->thread.scan1 = dev->thread.scan2;
dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);
dev->tvaudio = NULL;
@@ -613,9 +617,12 @@ static int tvaudio_thread(void *data)
lastmode = 42;
for (;;) {
+
+ try_to_freeze();
+
if (tvaudio_sleep(dev,5000))
goto restart;
- if (kthread_should_stop() || signal_pending(current))
+ if (kthread_should_stop())
break;
if (UNSET == dev->thread.mode) {
rx = tvaudio_getstereo(dev,&tvaudio[i]);
@@ -631,6 +638,7 @@ static int tvaudio_thread(void *data)
}
done:
+ dev->thread.stopped = 1;
return 0;
}
@@ -778,7 +786,8 @@ static int tvaudio_thread_ddep(void *data)
struct saa7134_dev *dev = data;
u32 value, norms, clock;
- allow_signal(SIGTERM);
+
+ set_freezable();
clock = saa7134_boards[dev->board].audio_clock;
if (UNSET != audio_clock_override)
@@ -791,10 +800,13 @@ static int tvaudio_thread_ddep(void *data)
for (;;) {
tvaudio_sleep(dev,-1);
- if (kthread_should_stop() || signal_pending(current))
+ if (kthread_should_stop())
goto done;
restart:
+
+ try_to_freeze();
+
dev->thread.scan1 = dev->thread.scan2;
dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);
@@ -871,13 +883,14 @@ static int tvaudio_thread_ddep(void *data)
}
done:
+ dev->thread.stopped = 1;
return 0;
}
/* ------------------------------------------------------------------ */
/* common stuff + external entry points */
-static void saa7134_enable_i2s(struct saa7134_dev *dev)
+void saa7134_enable_i2s(struct saa7134_dev *dev)
{
int i2s_format;
@@ -998,7 +1011,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
int saa7134_tvaudio_fini(struct saa7134_dev *dev)
{
/* shutdown tvaudio thread */
- if (dev->thread.thread)
+ if (dev->thread.thread && !dev->thread.stopped)
kthread_stop(dev->thread.thread);
saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */
@@ -1014,7 +1027,9 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
} else if (dev->thread.thread) {
dev->thread.mode = UNSET;
dev->thread.scan2++;
- wake_up_process(dev->thread.thread);
+
+ if (!dev->insuspend && !dev->thread.stopped)
+ wake_up_process(dev->thread.thread);
} else {
dev->automute = 0;
saa7134_tvaudio_setmute(dev);
diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c
index f38366a470f..81a2aedeff5 100644
--- a/drivers/media/video/saa7134/saa7134-vbi.c
+++ b/drivers/media/video/saa7134/saa7134-vbi.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -138,6 +137,8 @@ static int buffer_prepare(struct videobuf_queue *q,
saa7134_dma_free(q,buf);
if (STATE_NEEDS_INIT == buf->vb.state) {
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
buf->vb.width = llength;
buf->vb.height = lines;
buf->vb.size = size;
@@ -147,8 +148,8 @@ static int buffer_prepare(struct videobuf_queue *q,
if (err)
goto oops;
err = saa7134_pgtable_build(dev->pci,buf->pt,
- buf->vb.dma.sglist,
- buf->vb.dma.sglen,
+ dma->sglist,
+ dma->sglen,
saa7134_buffer_startpage(buf));
if (err)
goto oops;
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 9985ded2095..3b9ffb4b648 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sort.h>
@@ -41,7 +40,7 @@
static unsigned int video_debug = 0;
static unsigned int gbuffers = 8;
-static unsigned int noninterlaced = 1;
+static unsigned int noninterlaced = 0;
static unsigned int gbufsize = 720*576*4;
static unsigned int gbufsize_max = 720*576*4;
static char secam[] = "--";
@@ -541,22 +540,12 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
/* ------------------------------------------------------------------ */
-static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
+void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
{
- int luma_control,sync_control,mux;
dprintk("set tv norm = %s\n",norm->name);
dev->tvnorm = norm;
- mux = card_in(dev,dev->ctl_input).vmux;
- luma_control = norm->luma_control;
- sync_control = norm->sync_control;
-
- if (mux > 5)
- luma_control |= 0x80; /* svideo */
- if (noninterlaced || dev->nosignal)
- sync_control |= 0x20;
-
/* setup cropping */
dev->crop_bounds.left = norm->h_start;
dev->crop_defrect.left = norm->h_start;
@@ -571,6 +560,34 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
dev->crop_current = dev->crop_defrect;
+ saa7134_set_tvnorm_hw(dev);
+
+}
+
+static void video_mux(struct saa7134_dev *dev, int input)
+{
+ dprintk("video input = %d [%s]\n", input, card_in(dev, input).name);
+ dev->ctl_input = input;
+ set_tvnorm(dev, dev->tvnorm);
+ saa7134_tvaudio_setinput(dev, &card_in(dev, input));
+}
+
+
+static void saa7134_set_decoder(struct saa7134_dev *dev)
+{
+ int luma_control, sync_control, mux;
+
+ struct saa7134_tvnorm *norm = dev->tvnorm;
+ mux = card_in(dev, dev->ctl_input).vmux;
+
+ luma_control = norm->luma_control;
+ sync_control = norm->sync_control;
+
+ if (mux > 5)
+ luma_control |= 0x80; /* svideo */
+ if (noninterlaced || dev->nosignal)
+ sync_control |= 0x20;
+
/* setup video decoder */
saa_writeb(SAA7134_INCR_DELAY, 0x08);
saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux);
@@ -585,9 +602,13 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
saa_writeb(SAA7134_SYNC_CTRL, sync_control);
saa_writeb(SAA7134_LUMA_CTRL, luma_control);
saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright);
- saa_writeb(SAA7134_DEC_LUMA_CONTRAST, dev->ctl_contrast);
- saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_saturation);
+ saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
+ dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
+
+ saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
+ dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
+
saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue);
saa_writeb(SAA7134_CHROMA_CTRL1, norm->chroma_ctrl1);
saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain);
@@ -601,25 +622,21 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
saa_writeb(SAA7134_MISC_VGATE_MSB, norm->vgate_misc);
saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40);
saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80);
+}
- /* only tell the tuner if this is a tv input */
- if (card_in(dev,dev->ctl_input).tv) {
+void saa7134_set_tvnorm_hw(struct saa7134_dev *dev)
+{
+ saa7134_set_decoder(dev);
+
+ if (card_in(dev, dev->ctl_input).tv) {
if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290)
&& ((card(dev).tuner_config == 1)
|| (card(dev).tuner_config == 2)))
saa7134_set_gpio(dev, 22, 5);
- saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);
+ saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id);
}
}
-static void video_mux(struct saa7134_dev *dev, int input)
-{
- dprintk("video input = %d [%s]\n",input,card_in(dev,input).name);
- dev->ctl_input = input;
- set_tvnorm(dev,dev->tvnorm);
- saa7134_tvaudio_setinput(dev,&card_in(dev,input));
-}
-
static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
{
static const struct {
@@ -1038,6 +1055,8 @@ static int buffer_prepare(struct videobuf_queue *q,
}
if (STATE_NEEDS_INIT == buf->vb.state) {
+ struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
buf->vb.width = fh->width;
buf->vb.height = fh->height;
buf->vb.size = size;
@@ -1049,8 +1068,8 @@ static int buffer_prepare(struct videobuf_queue *q,
if (err)
goto oops;
err = saa7134_pgtable_build(dev->pci,buf->pt,
- buf->vb.dma.sglist,
- buf->vb.dma.sglen,
+ dma->sglist,
+ dma->sglen,
saa7134_buffer_startpage(buf));
if (err)
goto oops;
@@ -1273,26 +1292,24 @@ static int saa7134_resource(struct saa7134_fh *fh)
static int video_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
- struct saa7134_dev *h,*dev = NULL;
+ struct saa7134_dev *dev;
struct saa7134_fh *fh;
- struct list_head *list;
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int radio = 0;
- list_for_each(list,&saa7134_devlist) {
- h = list_entry(list, struct saa7134_dev, devlist);
- if (h->video_dev && (h->video_dev->minor == minor))
- dev = h;
- if (h->radio_dev && (h->radio_dev->minor == minor)) {
+ list_for_each_entry(dev, &saa7134_devlist, devlist) {
+ if (dev->video_dev && (dev->video_dev->minor == minor))
+ goto found;
+ if (dev->radio_dev && (dev->radio_dev->minor == minor)) {
radio = 1;
- dev = h;
+ goto found;
}
- if (h->vbi_dev && (h->vbi_dev->minor == minor)) {
+ if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) {
type = V4L2_BUF_TYPE_VBI_CAPTURE;
- dev = h;
+ goto found;
}
}
- if (NULL == dev)
- return -ENODEV;
+ return -ENODEV;
+ found:
dprintk("open minor=%d radio=%d type=%s\n",minor,radio,
v4l2_type_names[type]);
@@ -1310,13 +1327,13 @@ static int video_open(struct inode *inode, struct file *file)
fh->height = 576;
v4l2_prio_open(&dev->prio,&fh->prio);
- videobuf_queue_init(&fh->cap, &video_qops,
+ videobuf_queue_pci_init(&fh->cap, &video_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct saa7134_buf),
fh);
- videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops,
+ videobuf_queue_pci_init(&fh->vbi, &saa7134_vbi_qops,
dev->pci, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
@@ -1833,7 +1850,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
if (res_check(fh, RESOURCE_OVERLAY)) {
spin_lock_irqsave(&dev->slock,flags);
stop_preview(dev,fh);
+ spin_unlock_irqrestore(&dev->slock, flags);
+
set_tvnorm(dev,&tvnorms[i]);
+
+ spin_lock_irqsave(&dev->slock, flags);
start_preview(dev,fh);
spin_unlock_irqrestore(&dev->slock,flags);
} else
@@ -2138,29 +2159,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
}
#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCGMBUF:
- {
- struct video_mbuf *mbuf = arg;
- struct videobuf_queue *q;
- struct v4l2_requestbuffers req;
- unsigned int i;
-
- q = saa7134_queue(fh);
- memset(&req,0,sizeof(req));
- req.type = q->type;
- req.count = gbuffers;
- req.memory = V4L2_MEMORY_MMAP;
- err = videobuf_reqbufs(q,&req);
- if (err < 0)
- return err;
- memset(mbuf,0,sizeof(*mbuf));
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- return 0;
- }
+ return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers);
#endif
case VIDIOC_REQBUFS:
return videobuf_reqbufs(saa7134_queue(fh),arg);
@@ -2360,7 +2359,6 @@ struct video_device saa7134_video_template =
.name = "saa7134-video",
.type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|
VID_TYPE_CLIPPING|VID_TYPE_SCALES,
- .hardware = 0,
.fops = &video_fops,
.minor = -1,
};
@@ -2369,7 +2367,6 @@ struct video_device saa7134_vbi_template =
{
.name = "saa7134-vbi",
.type = VID_TYPE_TUNER|VID_TYPE_TELETEXT,
- .hardware = 0,
.fops = &video_fops,
.minor = -1,
};
@@ -2378,7 +2375,6 @@ struct video_device saa7134_radio_template =
{
.name = "saa7134-radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &radio_fops,
.minor = -1,
};
@@ -2412,34 +2408,40 @@ int saa7134_video_init1(struct saa7134_dev *dev)
dev->video_q.timeout.data = (unsigned long)(&dev->video_q);
dev->video_q.dev = dev;
- if (saa7134_boards[dev->board].video_out) {
- /* enable video output */
- int vo = saa7134_boards[dev->board].video_out;
- int video_reg;
- unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
- saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
- video_reg = video_out[vo][1];
- if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
- video_reg &= ~VP_T_CODE_P_INVERTED;
- saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
- video_reg = video_out[vo][5];
- if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
- video_reg &= ~VP_CLK_CTRL2_DELAYED;
- if (vid_port_opts & SET_CLOCK_INVERTED)
- video_reg |= VP_CLK_CTRL1_INVERTED;
- saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
- video_reg = video_out[vo][6];
- if (vid_port_opts & SET_VSYNC_OFF) {
- video_reg &= ~VP_VS_TYPE_MASK;
- video_reg |= VP_VS_TYPE_OFF;
- }
- saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
- saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
- }
+ if (saa7134_boards[dev->board].video_out)
+ saa7134_videoport_init(dev);
+
+ return 0;
+}
+
+int saa7134_videoport_init(struct saa7134_dev *dev)
+{
+ /* enable video output */
+ int vo = saa7134_boards[dev->board].video_out;
+ int video_reg;
+ unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
+ video_reg = video_out[vo][1];
+ if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
+ video_reg &= ~VP_T_CODE_P_INVERTED;
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
+ video_reg = video_out[vo][5];
+ if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
+ video_reg &= ~VP_CLK_CTRL2_DELAYED;
+ if (vid_port_opts & SET_CLOCK_INVERTED)
+ video_reg |= VP_CLK_CTRL1_INVERTED;
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
+ video_reg = video_out[vo][6];
+ if (vid_port_opts & SET_VSYNC_OFF) {
+ video_reg &= ~VP_VS_TYPE_MASK;
+ video_reg |= VP_VS_TYPE_OFF;
+ }
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
+ saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
return 0;
}
@@ -2454,7 +2456,7 @@ int saa7134_video_init2(struct saa7134_dev *dev)
return 0;
}
-void saa7134_irq_video_intl(struct saa7134_dev *dev)
+void saa7134_irq_video_signalchange(struct saa7134_dev *dev)
{
static const char *st[] = {
"(no signal)", "NTSC", "PAL", "SECAM" };
@@ -2466,24 +2468,28 @@ void saa7134_irq_video_intl(struct saa7134_dev *dev)
(st1 & 0x40) ? "not locked" : "locked",
(st2 & 0x40) ? "no" : "yes",
st[st1 & 0x03]);
- dev->nosignal = (st1 & 0x40) || (st2 & 0x40);
+ dev->nosignal = (st1 & 0x40) || (st2 & 0x40) || !(st2 & 0x1);
if (dev->nosignal) {
/* no video signal -> mute audio */
if (dev->ctl_automute)
dev->automute = 1;
saa7134_tvaudio_setmute(dev);
- saa_setb(SAA7134_SYNC_CTRL, 0x20);
} else {
/* wake up tvaudio audio carrier scan thread */
saa7134_tvaudio_do_scan(dev);
- if (!noninterlaced)
- saa_clearb(SAA7134_SYNC_CTRL, 0x20);
}
+
+ if ((st2 & 0x80) && !noninterlaced && !dev->nosignal)
+ saa_clearb(SAA7134_SYNC_CTRL, 0x20);
+ else
+ saa_setb(SAA7134_SYNC_CTRL, 0x20);
+
if (dev->mops && dev->mops->signal_change)
dev->mops->signal_change(dev);
}
+
void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
{
enum v4l2_field field;
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 346255468da..66a390c321a 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -37,12 +37,12 @@
#include <media/tuner.h>
#include <media/ir-common.h>
#include <media/ir-kbd-i2c.h>
-#include <media/video-buf.h>
+#include <media/videobuf-dma-sg.h>
#include <sound/driver.h>
#include <sound/core.h>
#include <sound/pcm.h>
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
-#include <media/video-buf-dvb.h>
+#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
+#include <media/videobuf-dvb.h>
#endif
#define UNSET (-1U)
@@ -239,6 +239,7 @@ struct saa7134_format {
#define SAA7134_BOARD_KWORLD_DVBT_210 114
#define SAA7134_BOARD_SABRENT_TV_PCB05 115
#define SAA7134_BOARD_10MOONSTVMASTER3 116
+#define SAA7134_BOARD_AVERMEDIA_SUPER_007 117
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -332,6 +333,7 @@ struct saa7134_thread {
unsigned int scan1;
unsigned int scan2;
unsigned int mode;
+ unsigned int stopped;
};
/* buffer for one video/vbi/ts frame */
@@ -523,6 +525,7 @@ struct saa7134_dev {
unsigned int hw_mute;
int last_carrier;
int nosignal;
+ unsigned int insuspend;
/* SAA7134_MPEG_* */
struct saa7134_ts ts;
@@ -536,7 +539,7 @@ struct saa7134_dev {
struct work_struct empress_workqueue;
int empress_started;
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
+#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
/* SAA7134_MPEG_DVB only */
struct videobuf_dvb dvb;
int (*original_demod_sleep)(struct dvb_frontend* fe);
@@ -593,6 +596,9 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
void saa7134_buffer_timeout(unsigned long data);
void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
+int saa7134_buffer_requeue(struct saa7134_dev *dev,
+ struct saa7134_dmaqueue *q);
+
int saa7134_set_dmabits(struct saa7134_dev *dev);
extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
@@ -625,12 +631,16 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev,
extern struct video_device saa7134_video_template;
extern struct video_device saa7134_radio_template;
+void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm);
+int saa7134_videoport_init(struct saa7134_dev *dev);
+void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
+
int saa7134_common_ioctl(struct saa7134_dev *dev,
unsigned int cmd, void *arg);
int saa7134_video_init1(struct saa7134_dev *dev);
int saa7134_video_init2(struct saa7134_dev *dev);
-void saa7134_irq_video_intl(struct saa7134_dev *dev);
+void saa7134_irq_video_signalchange(struct saa7134_dev *dev);
void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status);
@@ -648,6 +658,8 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status);
int saa7134_ts_register(struct saa7134_mpeg_ops *ops);
void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops);
+int saa7134_ts_init_hw(struct saa7134_dev *dev);
+
/* ----------------------------------------------------------- */
/* saa7134-vbi.c */
@@ -676,6 +688,8 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev);
int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value);
+void saa7134_enable_i2s(struct saa7134_dev *dev);
+
/* ----------------------------------------------------------- */
/* saa7134-oss.c */
@@ -693,6 +707,8 @@ int saa7134_input_init1(struct saa7134_dev *dev);
void saa7134_input_fini(struct saa7134_dev *dev);
void saa7134_input_irq(struct saa7134_dev *dev);
void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir);
+void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir);
+void saa7134_ir_stop(struct saa7134_dev *dev);
/*
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
index 93fb04ed99a..d5d7d6cf734 100644
--- a/drivers/media/video/se401.c
+++ b/drivers/media/video/se401.c
@@ -1231,7 +1231,6 @@ static struct video_device se401_template = {
.owner = THIS_MODULE,
.name = "se401 USB camera",
.type = VID_TYPE_CAPTURE,
- .hardware = VID_HARDWARE_SE401,
.fops = &se401_fops,
};
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 36d8a455e0e..511847912c4 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -22,7 +22,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/param.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/device.h>
@@ -1030,7 +1029,8 @@ static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count)
NOTE 2: buffers are PAGE_SIZE long
*/
-static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_reg(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct sn9c102_device* cam;
ssize_t count;
@@ -1054,7 +1054,8 @@ static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
static ssize_t
-sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_reg(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct sn9c102_device* cam;
u16 index;
@@ -1087,7 +1088,8 @@ sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
}
-static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_val(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct sn9c102_device* cam;
ssize_t count;
@@ -1119,7 +1121,8 @@ static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
static ssize_t
-sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_val(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct sn9c102_device* cam;
u16 value;
@@ -1158,7 +1161,8 @@ sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
}
-static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_i2c_reg(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct sn9c102_device* cam;
ssize_t count;
@@ -1184,7 +1188,8 @@ static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
static ssize_t
-sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct sn9c102_device* cam;
u16 index;
@@ -1217,7 +1222,8 @@ sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
}
-static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_i2c_val(struct device* cd,
+ struct device_attribute *attr, char* buf)
{
struct sn9c102_device* cam;
ssize_t count;
@@ -1254,7 +1260,8 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
static ssize_t
-sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct sn9c102_device* cam;
u16 value;
@@ -1299,7 +1306,8 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
static ssize_t
-sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_green(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
struct sn9c102_device* cam;
enum sn9c102_bridge bridge;
@@ -1330,16 +1338,16 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
case BRIDGE_SN9C102:
if (value > 0x0f)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
- res = sn9c102_store_val(cd, buf, len);
+ if ((res = sn9c102_store_reg(cd, attr, "0x11", 4)) >= 0)
+ res = sn9c102_store_val(cd, attr, buf, len);
break;
case BRIDGE_SN9C103:
case BRIDGE_SN9C105:
case BRIDGE_SN9C120:
if (value > 0x7f)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, "0x07", 4)) >= 0)
- res = sn9c102_store_val(cd, buf, len);
+ if ((res = sn9c102_store_reg(cd, attr, "0x07", 4)) >= 0)
+ res = sn9c102_store_val(cd, attr, buf, len);
break;
}
@@ -1348,7 +1356,8 @@ sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
static ssize_t
-sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_blue(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
ssize_t res = 0;
u16 value;
@@ -1358,15 +1367,16 @@ sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
if (!count || value > 0x7f)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0)
- res = sn9c102_store_val(cd, buf, len);
+ if ((res = sn9c102_store_reg(cd, attr, "0x06", 4)) >= 0)
+ res = sn9c102_store_val(cd, attr, buf, len);
return res;
}
static ssize_t
-sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_red(struct device* cd, struct device_attribute *attr,
+ const char* buf, size_t len)
{
ssize_t res = 0;
u16 value;
@@ -1376,14 +1386,16 @@ sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
if (!count || value > 0x7f)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0)
- res = sn9c102_store_val(cd, buf, len);
+ if ((res = sn9c102_store_reg(cd, attr, "0x05", 4)) >= 0)
+ res = sn9c102_store_val(cd, attr, buf, len);
return res;
}
-static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_frame_header(struct device* cd,
+ struct device_attribute *attr,
+ char* buf)
{
struct sn9c102_device* cam;
ssize_t count;
@@ -1402,72 +1414,63 @@ static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
}
-static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
- sn9c102_show_reg, sn9c102_store_reg);
-static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
- sn9c102_show_val, sn9c102_store_val);
-static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
- sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
-static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
- sn9c102_show_i2c_val, sn9c102_store_i2c_val);
-static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
-static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
-static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
-static CLASS_DEVICE_ATTR(frame_header, S_IRUGO,
- sn9c102_show_frame_header, NULL);
+static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg);
+static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val);
+static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
+ sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
+static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
+ sn9c102_show_i2c_val, sn9c102_store_i2c_val);
+static DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
+static DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
+static DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
+static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL);
static int sn9c102_create_sysfs(struct sn9c102_device* cam)
{
- struct class_device *classdev = &(cam->v4ldev->class_dev);
+ struct device *classdev = &(cam->v4ldev->class_dev);
int err = 0;
- if ((err = class_device_create_file(classdev, &class_device_attr_reg)))
+ if ((err = device_create_file(classdev, &dev_attr_reg)))
goto err_out;
- if ((err = class_device_create_file(classdev, &class_device_attr_val)))
+ if ((err = device_create_file(classdev, &dev_attr_val)))
goto err_reg;
- if ((err = class_device_create_file(classdev,
- &class_device_attr_frame_header)))
+ if ((err = device_create_file(classdev, &dev_attr_frame_header)))
goto err_val;
if (cam->sensor.sysfs_ops) {
- if ((err = class_device_create_file(classdev,
- &class_device_attr_i2c_reg)))
+ if ((err = device_create_file(classdev, &dev_attr_i2c_reg)))
goto err_frame_header;
- if ((err = class_device_create_file(classdev,
- &class_device_attr_i2c_val)))
+ if ((err = device_create_file(classdev, &dev_attr_i2c_val)))
goto err_i2c_reg;
}
if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
- if ((err = class_device_create_file(classdev,
- &class_device_attr_green)))
+ if ((err = device_create_file(classdev, &dev_attr_green)))
goto err_i2c_val;
} else {
- if ((err = class_device_create_file(classdev,
- &class_device_attr_blue)))
+ if ((err = device_create_file(classdev, &dev_attr_blue)))
goto err_i2c_val;
- if ((err = class_device_create_file(classdev,
- &class_device_attr_red)))
+ if ((err = device_create_file(classdev, &dev_attr_red)))
goto err_blue;
}
return 0;
err_blue:
- class_device_remove_file(classdev, &class_device_attr_blue);
+ device_remove_file(classdev, &dev_attr_blue);
err_i2c_val:
if (cam->sensor.sysfs_ops)
- class_device_remove_file(classdev, &class_device_attr_i2c_val);
+ device_remove_file(classdev, &dev_attr_i2c_val);
err_i2c_reg:
if (cam->sensor.sysfs_ops)
- class_device_remove_file(classdev, &class_device_attr_i2c_reg);
+ device_remove_file(classdev, &dev_attr_i2c_reg);
err_frame_header:
- class_device_remove_file(classdev, &class_device_attr_frame_header);
+ device_remove_file(classdev, &dev_attr_frame_header);
err_val:
- class_device_remove_file(classdev, &class_device_attr_val);
+ device_remove_file(classdev, &dev_attr_val);
err_reg:
- class_device_remove_file(classdev, &class_device_attr_reg);
+ device_remove_file(classdev, &dev_attr_reg);
err_out:
return err;
}
@@ -3316,7 +3319,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
strcpy(cam->v4ldev->name, "SN9C1xx PC Camera");
cam->v4ldev->owner = THIS_MODULE;
cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
- cam->v4ldev->hardware = 0;
cam->v4ldev->fops = &sn9c102_fops;
cam->v4ldev->minor = video_nr[dev_nr];
cam->v4ldev->release = video_device_release;
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index eb220461ac7..3fb85af5d1f 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -1917,7 +1917,6 @@ static const struct file_operations saa_fops = {
static struct video_device saa_template = {
.name = "SAA7146A",
.type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY,
- .hardware = VID_HARDWARE_SAA7146,
.fops = &saa_fops,
.minor = -1,
};
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index 4dc5bc714b9..afc32aa56fd 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -499,13 +499,14 @@ exit:
* sysfs
***************************************************************************/
#define stv680_file(name, variable, field) \
-static ssize_t show_##name(struct class_device *class_dev, char *buf) \
+static ssize_t show_##name(struct device *class_dev, \
+ struct device_attribute *attr, char *buf) \
{ \
struct video_device *vdev = to_video_device(class_dev); \
struct usb_stv *stv = video_get_drvdata(vdev); \
return sprintf(buf, field, stv->variable); \
} \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
stv680_file(model, camera_name, "%s\n");
stv680_file(in_use, user, "%d\n");
@@ -520,53 +521,53 @@ static int stv680_create_sysfs_files(struct video_device *vdev)
{
int rc;
- rc = video_device_create_file(vdev, &class_device_attr_model);
+ rc = video_device_create_file(vdev, &dev_attr_model);
if (rc) goto err;
- rc = video_device_create_file(vdev, &class_device_attr_in_use);
+ rc = video_device_create_file(vdev, &dev_attr_in_use);
if (rc) goto err_model;
- rc = video_device_create_file(vdev, &class_device_attr_streaming);
+ rc = video_device_create_file(vdev, &dev_attr_streaming);
if (rc) goto err_inuse;
- rc = video_device_create_file(vdev, &class_device_attr_palette);
+ rc = video_device_create_file(vdev, &dev_attr_palette);
if (rc) goto err_stream;
- rc = video_device_create_file(vdev, &class_device_attr_frames_total);
+ rc = video_device_create_file(vdev, &dev_attr_frames_total);
if (rc) goto err_pal;
- rc = video_device_create_file(vdev, &class_device_attr_frames_read);
+ rc = video_device_create_file(vdev, &dev_attr_frames_read);
if (rc) goto err_framtot;
- rc = video_device_create_file(vdev, &class_device_attr_packets_dropped);
+ rc = video_device_create_file(vdev, &dev_attr_packets_dropped);
if (rc) goto err_framread;
- rc = video_device_create_file(vdev, &class_device_attr_decoding_errors);
+ rc = video_device_create_file(vdev, &dev_attr_decoding_errors);
if (rc) goto err_dropped;
return 0;
err_dropped:
- video_device_remove_file(vdev, &class_device_attr_packets_dropped);
+ video_device_remove_file(vdev, &dev_attr_packets_dropped);
err_framread:
- video_device_remove_file(vdev, &class_device_attr_frames_read);
+ video_device_remove_file(vdev, &dev_attr_frames_read);
err_framtot:
- video_device_remove_file(vdev, &class_device_attr_frames_total);
+ video_device_remove_file(vdev, &dev_attr_frames_total);
err_pal:
- video_device_remove_file(vdev, &class_device_attr_palette);
+ video_device_remove_file(vdev, &dev_attr_palette);
err_stream:
- video_device_remove_file(vdev, &class_device_attr_streaming);
+ video_device_remove_file(vdev, &dev_attr_streaming);
err_inuse:
- video_device_remove_file(vdev, &class_device_attr_in_use);
+ video_device_remove_file(vdev, &dev_attr_in_use);
err_model:
- video_device_remove_file(vdev, &class_device_attr_model);
+ video_device_remove_file(vdev, &dev_attr_model);
err:
return rc;
}
static void stv680_remove_sysfs_files(struct video_device *vdev)
{
- video_device_remove_file(vdev, &class_device_attr_model);
- video_device_remove_file(vdev, &class_device_attr_in_use);
- video_device_remove_file(vdev, &class_device_attr_streaming);
- video_device_remove_file(vdev, &class_device_attr_palette);
- video_device_remove_file(vdev, &class_device_attr_frames_total);
- video_device_remove_file(vdev, &class_device_attr_frames_read);
- video_device_remove_file(vdev, &class_device_attr_packets_dropped);
- video_device_remove_file(vdev, &class_device_attr_decoding_errors);
+ video_device_remove_file(vdev, &dev_attr_model);
+ video_device_remove_file(vdev, &dev_attr_in_use);
+ video_device_remove_file(vdev, &dev_attr_streaming);
+ video_device_remove_file(vdev, &dev_attr_palette);
+ video_device_remove_file(vdev, &dev_attr_frames_total);
+ video_device_remove_file(vdev, &dev_attr_frames_read);
+ video_device_remove_file(vdev, &dev_attr_packets_dropped);
+ video_device_remove_file(vdev, &dev_attr_decoding_errors);
}
/********************************************************************
@@ -1397,7 +1398,6 @@ static struct video_device stv680_template = {
.owner = THIS_MODULE,
.name = "STV0680 USB camera",
.type = VID_TYPE_CAPTURE,
- .hardware = VID_HARDWARE_SE401,
.fops = &stv680_fops,
.release = video_device_release,
.minor = -1,
diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
new file mode 100644
index 00000000000..41cd6a0b048
--- /dev/null
+++ b/drivers/media/video/tcm825x.c
@@ -0,0 +1,928 @@
+/*
+ * drivers/media/video/tcm825x.c
+ *
+ * TCM825X camera sensor driver.
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from David Cohen <david.cohen@indt.org.br>
+ *
+ * This driver was based on ov9640 sensor driver from MontaVista
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/i2c.h>
+#include <media/v4l2-int-device.h>
+
+#include "tcm825x.h"
+
+/*
+ * The sensor has two fps modes: the lower one just gives half the fps
+ * at the same xclk than the high one.
+ */
+#define MAX_FPS 30
+#define MIN_FPS 8
+#define MAX_HALF_FPS (MAX_FPS / 2)
+#define HIGH_FPS_MODE_LOWER_LIMIT 14
+#define DEFAULT_FPS MAX_HALF_FPS
+
+struct tcm825x_sensor {
+ const struct tcm825x_platform_data *platform_data;
+ struct v4l2_int_device *v4l2_int_device;
+ struct i2c_client *i2c_client;
+ struct v4l2_pix_format pix;
+ struct v4l2_fract timeperframe;
+};
+
+/* list of image formats supported by TCM825X sensor */
+const static struct v4l2_fmtdesc tcm825x_formats[] = {
+ {
+ .description = "YUYV (YUV 4:2:2), packed",
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ }, {
+ /* Note: V4L2 defines RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
+ *
+ * We interpret RGB565 as:
+ *
+ * Byte 0 Byte 1
+ * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
+ */
+ .description = "RGB565, le",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ },
+};
+
+#define TCM825X_NUM_CAPTURE_FORMATS ARRAY_SIZE(tcm825x_formats)
+
+/*
+ * TCM825X register configuration for all combinations of pixel format and
+ * image size
+ */
+const static struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ };
+const static struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ };
+const static struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ };
+const static struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ };
+const static struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ };
+const static struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ };
+
+const static struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT };
+const static struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT };
+
+/* Our own specific controls */
+#define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE
+#define V4L2_CID_H_EDGE_EN V4L2_CID_PRIVATE_BASE + 1
+#define V4L2_CID_V_EDGE_EN V4L2_CID_PRIVATE_BASE + 2
+#define V4L2_CID_LENS V4L2_CID_PRIVATE_BASE + 3
+#define V4L2_CID_MAX_EXPOSURE_TIME V4L2_CID_PRIVATE_BASE + 4
+#define V4L2_CID_LAST_PRIV V4L2_CID_MAX_EXPOSURE_TIME
+
+/* Video controls */
+static struct vcontrol {
+ struct v4l2_queryctrl qc;
+ u16 reg;
+ u16 start_bit;
+} video_control[] = {
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+ },
+ .reg = TCM825X_AG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Balance",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ },
+ .reg = TCM825X_MRG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Balance",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ },
+ .reg = TCM825X_MBG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ },
+ .reg = TCM825X_AWBSW,
+ .start_bit = 7,
+ },
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure Time",
+ .minimum = 0,
+ .maximum = 0x1fff,
+ .step = 1,
+ },
+ .reg = TCM825X_ESRSPD_U,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mirror Image",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ },
+ .reg = TCM825X_H_INV,
+ .start_bit = 6,
+ },
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ },
+ .reg = TCM825X_V_INV,
+ .start_bit = 7,
+ },
+ /* Private controls */
+ {
+ {
+ .id = V4L2_CID_ALC,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Luminance Control",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 0,
+ },
+ .reg = TCM825X_ALCSW,
+ .start_bit = 7,
+ },
+ {
+ {
+ .id = V4L2_CID_H_EDGE_EN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Horizontal Edge Enhancement",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ },
+ .reg = TCM825X_HDTG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_V_EDGE_EN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Vertical Edge Enhancement",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ },
+ .reg = TCM825X_VDTG,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_LENS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Lens Shading Compensation",
+ .minimum = 0,
+ .maximum = 0x3f,
+ .step = 1,
+ },
+ .reg = TCM825X_LENS,
+ .start_bit = 0,
+ },
+ {
+ {
+ .id = V4L2_CID_MAX_EXPOSURE_TIME,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Maximum Exposure Time",
+ .minimum = 0,
+ .maximum = 0x3,
+ .step = 1,
+ },
+ .reg = TCM825X_ESRLIM,
+ .start_bit = 5,
+ },
+};
+
+
+const static struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] =
+{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };
+
+const static struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] =
+{ &yuv422, &rgb565 };
+
+/*
+ * Read a value from a register in an TCM825X sensor device. The value is
+ * returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_read_reg(struct i2c_client *client, int reg)
+{
+ int err;
+ struct i2c_msg msg[2];
+ u8 reg_buf, data_buf = 0;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = &reg_buf;
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 1;
+ msg[1].buf = &data_buf;
+
+ reg_buf = reg;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+ if (err < 0)
+ return err;
+ return data_buf;
+}
+
+/*
+ * Write a value to a register in an TCM825X sensor device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+ int err;
+ struct i2c_msg msg[1];
+ unsigned char data[2];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg->addr = client->addr;
+ msg->flags = 0;
+ msg->len = 2;
+ msg->buf = data;
+ data[0] = reg;
+ data[1] = val;
+ err = i2c_transfer(client->adapter, msg, 1);
+ if (err >= 0)
+ return 0;
+ return err;
+}
+
+static int __tcm825x_write_reg_mask(struct i2c_client *client,
+ u8 reg, u8 val, u8 mask)
+{
+ int rc;
+
+ /* need to do read - modify - write */
+ rc = tcm825x_read_reg(client, reg);
+ if (rc < 0)
+ return rc;
+
+ rc &= (~mask); /* Clear the masked bits */
+ val &= mask; /* Enforce mask on value */
+ val |= rc;
+
+ /* write the new value to the register */
+ rc = tcm825x_write_reg(client, reg, val);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+#define tcm825x_write_reg_mask(client, regmask, val) \
+ __tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val, \
+ TCM825X_MASK((regmask)))
+
+
+/*
+ * Initialize a list of TCM825X registers.
+ * The list of registers is terminated by the pair of values
+ * { TCM825X_REG_TERM, TCM825X_VAL_TERM }.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_write_default_regs(struct i2c_client *client,
+ const struct tcm825x_reg *reglist)
+{
+ int err;
+ const struct tcm825x_reg *next = reglist;
+
+ while (!((next->reg == TCM825X_REG_TERM)
+ && (next->val == TCM825X_VAL_TERM))) {
+ err = tcm825x_write_reg(client, next->reg, next->val);
+ if (err) {
+ dev_err(&client->dev, "register writing failed\n");
+ return err;
+ }
+ next++;
+ }
+
+ return 0;
+}
+
+static struct vcontrol *find_vctrl(int id)
+{
+ int i;
+
+ if (id < V4L2_CID_BASE)
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(video_control); i++)
+ if (video_control[i].qc.id == id)
+ return &video_control[i];
+
+ return NULL;
+}
+
+/*
+ * Find the best match for a requested image capture size. The best match
+ * is chosen as the nearest match that has the same number or fewer pixels
+ * as the requested size, or the smallest image size if the requested size
+ * has fewer pixels than the smallest image.
+ */
+static enum image_size tcm825x_find_size(struct v4l2_int_device *s,
+ unsigned int width,
+ unsigned int height)
+{
+ enum image_size isize;
+ unsigned long pixels = width * height;
+ struct tcm825x_sensor *sensor = s->priv;
+
+ for (isize = subQCIF; isize < VGA; isize++) {
+ if (tcm825x_sizes[isize + 1].height
+ * tcm825x_sizes[isize + 1].width > pixels) {
+ dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize);
+
+ return isize;
+ }
+ }
+
+ dev_dbg(&sensor->i2c_client->dev, "format default VGA\n");
+
+ return VGA;
+}
+
+/*
+ * Configure the TCM825X for current image size, pixel format, and
+ * frame period. fper is the frame period (in seconds) expressed as a
+ * fraction. Returns zero if successful, or non-zero otherwise. The
+ * actual frame period is returned in fper.
+ */
+static int tcm825x_configure(struct v4l2_int_device *s)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_pix_format *pix = &sensor->pix;
+ enum image_size isize = tcm825x_find_size(s, pix->width, pix->height);
+ struct v4l2_fract *fper = &sensor->timeperframe;
+ enum pixel_format pfmt;
+ int err;
+ u32 tgt_fps;
+ u8 val;
+
+ /* common register initialization */
+ err = tcm825x_write_default_regs(
+ sensor->i2c_client, sensor->platform_data->default_regs());
+ if (err)
+ return err;
+
+ /* configure image size */
+ val = tcm825x_siz_reg[isize]->val;
+ dev_dbg(&sensor->i2c_client->dev,
+ "configuring image size %d\n", isize);
+ err = tcm825x_write_reg_mask(sensor->i2c_client,
+ tcm825x_siz_reg[isize]->reg, val);
+ if (err)
+ return err;
+
+ /* configure pixel format */
+ switch (pix->pixelformat) {
+ default:
+ case V4L2_PIX_FMT_RGB565:
+ pfmt = RGB565;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ pfmt = YUV422;
+ break;
+ }
+
+ dev_dbg(&sensor->i2c_client->dev,
+ "configuring pixel format %d\n", pfmt);
+ val = tcm825x_fmt_reg[pfmt]->val;
+
+ err = tcm825x_write_reg_mask(sensor->i2c_client,
+ tcm825x_fmt_reg[pfmt]->reg, val);
+ if (err)
+ return err;
+
+ /*
+ * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be
+ * set. Frame rate will be halved from the normal.
+ */
+ tgt_fps = fper->denominator / fper->numerator;
+ if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) {
+ val = tcm825x_read_reg(sensor->i2c_client, 0x02);
+ val |= 0x80;
+ tcm825x_write_reg(sensor->i2c_client, 0x02, val);
+ }
+
+ return 0;
+}
+
+static int ioctl_queryctrl(struct v4l2_int_device *s,
+ struct v4l2_queryctrl *qc)
+{
+ struct vcontrol *control;
+
+ control = find_vctrl(qc->id);
+
+ if (control == NULL)
+ return -EINVAL;
+
+ *qc = control->qc;
+
+ return 0;
+}
+
+static int ioctl_g_ctrl(struct v4l2_int_device *s,
+ struct v4l2_control *vc)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ int val, r;
+ struct vcontrol *lvc;
+
+ /* exposure time is special, spread accross 2 registers */
+ if (vc->id == V4L2_CID_EXPOSURE) {
+ int val_lower, val_upper;
+
+ val_upper = tcm825x_read_reg(client,
+ TCM825X_ADDR(TCM825X_ESRSPD_U));
+ if (val_upper < 0)
+ return val_upper;
+ val_lower = tcm825x_read_reg(client,
+ TCM825X_ADDR(TCM825X_ESRSPD_L));
+ if (val_lower < 0)
+ return val_lower;
+
+ vc->value = ((val_upper & 0x1f) << 8) | (val_lower);
+ return 0;
+ }
+
+ lvc = find_vctrl(vc->id);
+ if (lvc == NULL)
+ return -EINVAL;
+
+ r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg));
+ if (r < 0)
+ return r;
+ val = r & TCM825X_MASK(lvc->reg);
+ val >>= lvc->start_bit;
+
+ if (val < 0)
+ return val;
+
+ vc->value = val;
+ return 0;
+}
+
+static int ioctl_s_ctrl(struct v4l2_int_device *s,
+ struct v4l2_control *vc)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct i2c_client *client = sensor->i2c_client;
+ struct vcontrol *lvc;
+ int val = vc->value;
+
+ /* exposure time is special, spread accross 2 registers */
+ if (vc->id == V4L2_CID_EXPOSURE) {
+ int val_lower, val_upper;
+ val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L);
+ val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U);
+
+ if (tcm825x_write_reg_mask(client,
+ TCM825X_ESRSPD_U, val_upper))
+ return -EIO;
+
+ if (tcm825x_write_reg_mask(client,
+ TCM825X_ESRSPD_L, val_lower))
+ return -EIO;
+
+ return 0;
+ }
+
+ lvc = find_vctrl(vc->id);
+ if (lvc == NULL)
+ return -EINVAL;
+
+ val = val << lvc->start_bit;
+ if (tcm825x_write_reg_mask(client, lvc->reg, val))
+ return -EIO;
+
+ return 0;
+}
+
+static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_fmtdesc *fmt)
+{
+ int index = fmt->index;
+
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (index >= TCM825X_NUM_CAPTURE_FORMATS)
+ return -EINVAL;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ fmt->flags = tcm825x_formats[index].flags;
+ strlcpy(fmt->description, tcm825x_formats[index].description,
+ sizeof(fmt->description));
+ fmt->pixelformat = tcm825x_formats[index].pixelformat;
+
+ return 0;
+}
+
+static int ioctl_try_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ enum image_size isize;
+ int ifmt;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+
+ isize = tcm825x_find_size(s, pix->width, pix->height);
+ dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n",
+ isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS);
+
+ pix->width = tcm825x_sizes[isize].width;
+ pix->height = tcm825x_sizes[isize].height;
+
+ for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++)
+ if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat)
+ break;
+
+ if (ifmt == TCM825X_NUM_CAPTURE_FORMATS)
+ ifmt = 0; /* Default = YUV 4:2:2 */
+
+ pix->pixelformat = tcm825x_formats[ifmt].pixelformat;
+ pix->field = V4L2_FIELD_NONE;
+ pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL;
+ pix->sizeimage = pix->bytesperline * pix->height;
+ pix->priv = 0;
+ dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n",
+ pix->pixelformat);
+
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_UYVY:
+ default:
+ pix->colorspace = V4L2_COLORSPACE_JPEG;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ }
+
+ return 0;
+}
+
+static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ int rval;
+
+ rval = ioctl_try_fmt_cap(s, f);
+ if (rval)
+ return rval;
+
+ rval = tcm825x_configure(s);
+
+ sensor->pix = *pix;
+
+ return rval;
+}
+
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
+ struct v4l2_format *f)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+
+ f->fmt.pix = sensor->pix;
+
+ return 0;
+}
+
+static int ioctl_g_parm(struct v4l2_int_device *s,
+ struct v4l2_streamparm *a)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_captureparm *cparm = &a->parm.capture;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ memset(a, 0, sizeof(*a));
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ cparm->capability = V4L2_CAP_TIMEPERFRAME;
+ cparm->timeperframe = sensor->timeperframe;
+
+ return 0;
+}
+
+static int ioctl_s_parm(struct v4l2_int_device *s,
+ struct v4l2_streamparm *a)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+ u32 tgt_fps; /* target frames per secound */
+ int rval;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if ((timeperframe->numerator == 0)
+ || (timeperframe->denominator == 0)) {
+ timeperframe->denominator = DEFAULT_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ tgt_fps = timeperframe->denominator / timeperframe->numerator;
+
+ if (tgt_fps > MAX_FPS) {
+ timeperframe->denominator = MAX_FPS;
+ timeperframe->numerator = 1;
+ } else if (tgt_fps < MIN_FPS) {
+ timeperframe->denominator = MIN_FPS;
+ timeperframe->numerator = 1;
+ }
+
+ sensor->timeperframe = *timeperframe;
+
+ rval = tcm825x_configure(s);
+
+ return rval;
+}
+
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+
+ return sensor->platform_data->power_set(on);
+}
+
+/*
+ * Given the image capture format in pix, the nominal frame period in
+ * timeperframe, calculate the required xclk frequency.
+ *
+ * TCM825X input frequency characteristics are:
+ * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz
+ */
+
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ struct v4l2_fract *timeperframe = &sensor->timeperframe;
+ u32 tgt_xclk; /* target xclk */
+ u32 tgt_fps; /* target frames per secound */
+ int rval;
+
+ rval = sensor->platform_data->ifparm(p);
+ if (rval)
+ return rval;
+
+ tgt_fps = timeperframe->denominator / timeperframe->numerator;
+
+ tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ?
+ (2457 * tgt_fps) / MAX_HALF_FPS :
+ (2457 * tgt_fps) / MAX_FPS;
+ tgt_xclk *= 10000;
+
+ tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX);
+ tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN);
+
+ p->u.bt656.clock_curr = tgt_xclk;
+
+ return 0;
+}
+
+static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+
+ return sensor->platform_data->needs_reset(s, buf, &sensor->pix);
+}
+
+static int ioctl_reset(struct v4l2_int_device *s)
+{
+ return -EBUSY;
+}
+
+static int ioctl_init(struct v4l2_int_device *s)
+{
+ return tcm825x_configure(s);
+}
+
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+ return 0;
+}
+
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+ struct tcm825x_sensor *sensor = s->priv;
+ int r;
+
+ r = tcm825x_read_reg(sensor->i2c_client, 0x01);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ dev_err(&sensor->i2c_client->dev, "device not detected\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = {
+ { vidioc_int_dev_init_num,
+ (v4l2_int_ioctl_func *)ioctl_dev_init },
+ { vidioc_int_dev_exit_num,
+ (v4l2_int_ioctl_func *)ioctl_dev_exit },
+ { vidioc_int_s_power_num,
+ (v4l2_int_ioctl_func *)ioctl_s_power },
+ { vidioc_int_g_ifparm_num,
+ (v4l2_int_ioctl_func *)ioctl_g_ifparm },
+ { vidioc_int_g_needs_reset_num,
+ (v4l2_int_ioctl_func *)ioctl_g_needs_reset },
+ { vidioc_int_reset_num,
+ (v4l2_int_ioctl_func *)ioctl_reset },
+ { vidioc_int_init_num,
+ (v4l2_int_ioctl_func *)ioctl_init },
+ { vidioc_int_enum_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
+ { vidioc_int_try_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_try_fmt_cap },
+ { vidioc_int_g_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
+ { vidioc_int_s_fmt_cap_num,
+ (v4l2_int_ioctl_func *)ioctl_s_fmt_cap },
+ { vidioc_int_g_parm_num,
+ (v4l2_int_ioctl_func *)ioctl_g_parm },
+ { vidioc_int_s_parm_num,
+ (v4l2_int_ioctl_func *)ioctl_s_parm },
+ { vidioc_int_queryctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_queryctrl },
+ { vidioc_int_g_ctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_g_ctrl },
+ { vidioc_int_s_ctrl_num,
+ (v4l2_int_ioctl_func *)ioctl_s_ctrl },
+};
+
+static struct v4l2_int_slave tcm825x_slave = {
+ .ioctls = tcm825x_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc),
+};
+
+static struct tcm825x_sensor tcm825x;
+
+static struct v4l2_int_device tcm825x_int_device = {
+ .module = THIS_MODULE,
+ .name = TCM825X_NAME,
+ .priv = &tcm825x,
+ .type = v4l2_int_type_slave,
+ .u = {
+ .slave = &tcm825x_slave,
+ },
+};
+
+static int tcm825x_probe(struct i2c_client *client)
+{
+ struct tcm825x_sensor *sensor = &tcm825x;
+ int rval;
+
+ if (i2c_get_clientdata(client))
+ return -EBUSY;
+
+ sensor->platform_data = client->dev.platform_data;
+
+ if (sensor->platform_data == NULL
+ && !sensor->platform_data->is_okay())
+ return -ENODEV;
+
+ sensor->v4l2_int_device = &tcm825x_int_device;
+
+ sensor->i2c_client = client;
+ i2c_set_clientdata(client, sensor);
+
+ /* Make the default capture format QVGA RGB565 */
+ sensor->pix.width = tcm825x_sizes[QVGA].width;
+ sensor->pix.height = tcm825x_sizes[QVGA].height;
+ sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
+
+ rval = v4l2_int_device_register(sensor->v4l2_int_device);
+ if (rval)
+ i2c_set_clientdata(client, NULL);
+
+ return rval;
+}
+
+static int __exit tcm825x_remove(struct i2c_client *client)
+{
+ struct tcm825x_sensor *sensor = i2c_get_clientdata(client);
+
+ if (!client->adapter)
+ return -ENODEV; /* our client isn't attached */
+
+ v4l2_int_device_unregister(sensor->v4l2_int_device);
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+
+static struct i2c_driver tcm825x_i2c_driver = {
+ .driver = {
+ .name = TCM825X_NAME,
+ },
+ .probe = tcm825x_probe,
+ .remove = __exit_p(tcm825x_remove),
+};
+
+static struct tcm825x_sensor tcm825x = {
+ .timeperframe = {
+ .numerator = 1,
+ .denominator = DEFAULT_FPS,
+ },
+};
+
+static int __init tcm825x_init(void)
+{
+ int rval;
+
+ rval = i2c_add_driver(&tcm825x_i2c_driver);
+ if (rval)
+ printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n",
+ __FUNCTION__);
+
+ return rval;
+}
+
+static void __exit tcm825x_exit(void)
+{
+ i2c_del_driver(&tcm825x_i2c_driver);
+}
+
+/*
+ * FIXME: Menelaus isn't ready (?) at module_init stage, so use
+ * late_initcall for now.
+ */
+late_initcall(tcm825x_init);
+module_exit(tcm825x_exit);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("TCM825x camera sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h
new file mode 100644
index 00000000000..966765b66b3
--- /dev/null
+++ b/drivers/media/video/tcm825x.h
@@ -0,0 +1,199 @@
+/*
+ * drivers/media/video/tcm825x.h
+ *
+ * Register definitions for the TCM825X CameraChip.
+ *
+ * Author: David Cohen (david.cohen@indt.org.br)
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * This file was based on ov9640.h from MontaVista
+ */
+
+#ifndef TCM825X_H
+#define TCM825X_H
+
+#include <linux/videodev2.h>
+
+#include <media/v4l2-int-device.h>
+
+#define TCM825X_NAME "tcm825x"
+
+#define TCM825X_MASK(x) x & 0x00ff
+#define TCM825X_ADDR(x) (x & 0xff00) >> 8
+
+/* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */
+#define TCM825X_I2C_ADDR 0x3d
+
+/*
+ * define register offsets for the TCM825X sensor chip
+ * OFFSET(8 bits) + MASK(8 bits)
+ * MASK bit 4 and 3 are used when the register uses more than one address
+ */
+#define TCM825X_FPS 0x0280
+#define TCM825X_ACF 0x0240
+#define TCM825X_DOUTBUF 0x020C
+#define TCM825X_DCLKP 0x0202
+#define TCM825X_ACFDET 0x0201
+#define TCM825X_DOUTSW 0x0380
+#define TCM825X_DATAHZ 0x0340
+#define TCM825X_PICSIZ 0x033c
+#define TCM825X_PICFMT 0x0302
+#define TCM825X_V_INV 0x0480
+#define TCM825X_H_INV 0x0440
+#define TCM825X_ESRLSW 0x0430
+#define TCM825X_V_LENGTH 0x040F
+#define TCM825X_ALCSW 0x0580
+#define TCM825X_ESRLIM 0x0560
+#define TCM825X_ESRSPD_U 0x051F
+#define TCM825X_ESRSPD_L 0x06FF
+#define TCM825X_AG 0x07FF
+#define TCM825X_ESRSPD2 0x06FF
+#define TCM825X_ALCMODE 0x0830
+#define TCM825X_ALCH 0x080F
+#define TCM825X_ALCL 0x09FF
+#define TCM825X_AWBSW 0x0A80
+#define TCM825X_MRG 0x0BFF
+#define TCM825X_MBG 0x0CFF
+#define TCM825X_GAMSW 0x0D80
+#define TCM825X_HDTG 0x0EFF
+#define TCM825X_VDTG 0x0FFF
+#define TCM825X_HDTCORE 0x10F0
+#define TCM825X_VDTCORE 0x100F
+#define TCM825X_CONT 0x11FF
+#define TCM825X_BRIGHT 0x12FF
+#define TCM825X_VHUE 0x137F
+#define TCM825X_UHUE 0x147F
+#define TCM825X_VGAIN 0x153F
+#define TCM825X_UGAIN 0x163F
+#define TCM825X_UVCORE 0x170F
+#define TCM825X_SATU 0x187F
+#define TCM825X_MHMODE 0x1980
+#define TCM825X_MHLPFSEL 0x1940
+#define TCM825X_YMODE 0x1930
+#define TCM825X_MIXHG 0x1907
+#define TCM825X_LENS 0x1A3F
+#define TCM825X_AGLIM 0x1BE0
+#define TCM825X_LENSRPOL 0x1B10
+#define TCM825X_LENSRGAIN 0x1B0F
+#define TCM825X_ES100S 0x1CFF
+#define TCM825X_ES120S 0x1DFF
+#define TCM825X_DMASK 0x1EC0
+#define TCM825X_CODESW 0x1E20
+#define TCM825X_CODESEL 0x1E10
+#define TCM825X_TESPIC 0x1E04
+#define TCM825X_PICSEL 0x1E03
+#define TCM825X_HNUM 0x20FF
+#define TCM825X_VOUTPH 0x287F
+#define TCM825X_ESROUT 0x327F
+#define TCM825X_ESROUT2 0x33FF
+#define TCM825X_AGOUT 0x34FF
+#define TCM825X_DGOUT 0x353F
+#define TCM825X_AGSLOW1 0x39C0
+#define TCM825X_FLLSMODE 0x3930
+#define TCM825X_FLLSLIM 0x390F
+#define TCM825X_DETSEL 0x3AF0
+#define TCM825X_ACDETNC 0x3A0F
+#define TCM825X_AGSLOW2 0x3BC0
+#define TCM825X_DG 0x3B3F
+#define TCM825X_REJHLEV 0x3CFF
+#define TCM825X_ALCLOCK 0x3D80
+#define TCM825X_FPSLNKSW 0x3D40
+#define TCM825X_ALCSPD 0x3D30
+#define TCM825X_REJH 0x3D03
+#define TCM825X_SHESRSW 0x3E80
+#define TCM825X_ESLIMSEL 0x3E40
+#define TCM825X_SHESRSPD 0x3E30
+#define TCM825X_ELSTEP 0x3E0C
+#define TCM825X_ELSTART 0x3E03
+#define TCM825X_AGMIN 0x3FFF
+#define TCM825X_PREGRG 0x423F
+#define TCM825X_PREGBG 0x433F
+#define TCM825X_PRERG 0x443F
+#define TCM825X_PREBG 0x453F
+#define TCM825X_MSKBR 0x477F
+#define TCM825X_MSKGR 0x487F
+#define TCM825X_MSKRB 0x497F
+#define TCM825X_MSKGB 0x4A7F
+#define TCM825X_MSKRG 0x4B7F
+#define TCM825X_MSKBG 0x4C7F
+#define TCM825X_HDTCSW 0x4D80
+#define TCM825X_VDTCSW 0x4D40
+#define TCM825X_DTCYL 0x4D3F
+#define TCM825X_HDTPSW 0x4E80
+#define TCM825X_VDTPSW 0x4E40
+#define TCM825X_DTCGAIN 0x4E3F
+#define TCM825X_DTLLIMSW 0x4F10
+#define TCM825X_DTLYLIM 0x4F0F
+#define TCM825X_YLCUTLMSK 0x5080
+#define TCM825X_YLCUTL 0x503F
+#define TCM825X_YLCUTHMSK 0x5180
+#define TCM825X_YLCUTH 0x513F
+#define TCM825X_UVSKNC 0x527F
+#define TCM825X_UVLJ 0x537F
+#define TCM825X_WBGMIN 0x54FF
+#define TCM825X_WBGMAX 0x55FF
+#define TCM825X_WBSPDUP 0x5603
+#define TCM825X_ALLAREA 0x5820
+#define TCM825X_WBLOCK 0x5810
+#define TCM825X_WB2SP 0x580F
+#define TCM825X_KIZUSW 0x5920
+#define TCM825X_PBRSW 0x5910
+#define TCM825X_ABCSW 0x5903
+#define TCM825X_PBDLV 0x5AFF
+#define TCM825X_PBC1LV 0x5BFF
+
+#define TCM825X_NUM_REGS (TCM825X_ADDR(TCM825X_PBC1LV) + 1)
+
+#define TCM825X_BYTES_PER_PIXEL 2
+
+#define TCM825X_REG_TERM 0xff /* terminating list entry for reg */
+#define TCM825X_VAL_TERM 0xff /* terminating list entry for val */
+
+/* define a structure for tcm825x register initialization values */
+struct tcm825x_reg {
+ u8 val;
+ u16 reg;
+};
+
+enum image_size { subQCIF = 0, QQVGA, QCIF, QVGA, CIF, VGA };
+enum pixel_format { YUV422 = 0, RGB565 };
+#define NUM_IMAGE_SIZES 6
+#define NUM_PIXEL_FORMATS 2
+
+#define TCM825X_XCLK_MIN 11900000
+#define TCM825X_XCLK_MAX 25000000
+
+struct capture_size {
+ unsigned long width;
+ unsigned long height;
+};
+
+struct tcm825x_platform_data {
+ /* Is the sensor usable? Doesn't yet mean it's there, but you
+ * can try! */
+ int (*is_okay)(void);
+ /* Set power state, zero is off, non-zero is on. */
+ int (*power_set)(int power);
+ /* Default registers written after power-on or reset. */
+ const struct tcm825x_reg *(*default_regs)(void);
+ int (*needs_reset)(struct v4l2_int_device *s, void *buf,
+ struct v4l2_pix_format *fmt);
+ int (*ifparm)(struct v4l2_ifparm *p);
+};
+
+/* Array of image sizes supported by TCM825X. These must be ordered from
+ * smallest image size to largest.
+ */
+const static struct capture_size tcm825x_sizes[] = {
+ { 128, 96 }, /* subQCIF */
+ { 160, 120 }, /* QQVGA */
+ { 176, 144 }, /* QCIF */
+ { 320, 240 }, /* QVGA */
+ { 352, 288 }, /* CIF */
+ { 640, 480 }, /* VGA */
+};
+
+#endif /* ifndef TCM825X_H */
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 59cff5a3c59..0e5cf459d3e 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -16,21 +16,37 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ This "tda8290" module was split apart from the original "tuner" module.
*/
#include <linux/i2c.h>
-#include <linux/videodev.h>
#include <linux/delay.h>
-#include "tuner-driver.h"
+#include <linux/videodev.h>
+#include "tuner-i2c.h"
+#include "tda8290.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define PREFIX "tda8290 "
/* ---------------------------------------------------------------------- */
struct tda8290_priv {
+ struct tuner_i2c_props i2c_props;
+
unsigned char tda8290_easy_mode;
unsigned char tda827x_lpsel;
unsigned char tda827x_addr;
unsigned char tda827x_ver;
unsigned int sgIF;
+
+ u32 frequency;
+
+ unsigned int *lna_cfg;
+ int (*tuner_callback) (void *dev, int command,int arg);
};
/* ---------------------------------------------------------------------- */
@@ -79,20 +95,21 @@ static struct tda827x_data tda827x_analog[] = {
{ .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */
};
-static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+static void tda827x_set_analog_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
unsigned char tuner_reg[8];
unsigned char reg2[2];
u32 N;
int i;
- struct tuner *t = i2c_get_clientdata(c);
- struct tda8290_priv *priv = t->priv;
+ struct tda8290_priv *priv = fe->tuner_priv;
struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0};
+ unsigned int freq = params->frequency;
- if (t->mode == V4L2_TUNER_RADIO)
+ if (params->mode == V4L2_TUNER_RADIO)
freq = freq / 1000;
- N = freq + ifc;
+ N = freq + priv->sgIF;
i = 0;
while (tda827x_analog[i].lomax < N) {
if(tda827x_analog[i + 1].lomax == 0)
@@ -114,54 +131,53 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
msg.buf = tuner_reg;
msg.len = 8;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msg.buf= reg2;
msg.len = 2;
reg2[0] = 0x80;
reg2[1] = 0;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
reg2[0] = 0x60;
reg2[1] = 0xbf;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
reg2[0] = 0x30;
reg2[1] = tuner_reg[4] + 0x80;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msleep(1);
reg2[0] = 0x30;
reg2[1] = tuner_reg[4] + 4;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msleep(1);
reg2[0] = 0x30;
reg2[1] = tuner_reg[4];
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msleep(550);
reg2[0] = 0x30;
reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
reg2[0] = 0x60;
reg2[1] = 0x3f;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
reg2[0] = 0x80;
reg2[1] = 0x08; // Vsync en
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
}
-static void tda827x_agcf(struct i2c_client *c)
+static void tda827x_agcf(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
- struct tda8290_priv *priv = t->priv;
+ struct tda8290_priv *priv = fe->tuner_priv;
unsigned char data[] = {0x80, 0x0c};
struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
.flags = 0, .len = 2};
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
}
/* ---------------------------------------------------------------------- */
@@ -204,58 +220,64 @@ static struct tda827xa_data tda827xa_analog[] = {
{ .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */
};
-static void tda827xa_lna_gain(struct i2c_client *c, int high)
+static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = fe->tuner_priv;
unsigned char buf[] = {0x22, 0x01};
int arg;
- struct i2c_msg msg = {.addr = c->addr, .flags = 0, .buf = buf, .len = sizeof(buf)};
- if (t->config) {
+ struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)};
+
+ if ((priv->lna_cfg == NULL) || (priv->tuner_callback == NULL))
+ return;
+
+ if (*priv->lna_cfg) {
if (high)
tuner_dbg("setting LNA to high gain\n");
else
tuner_dbg("setting LNA to low gain\n");
}
- switch (t->config) {
+ switch (*priv->lna_cfg) {
case 0: /* no LNA */
break;
case 1: /* switch is GPIO 0 of tda8290 */
case 2:
/* turn Vsync on */
- if (t->std & V4L2_STD_MN)
+ if (params->std & V4L2_STD_MN)
arg = 1;
else
arg = 0;
- if (t->tuner_callback)
- t->tuner_callback(c->adapter->algo_data, 1, arg);
+ if (priv->tuner_callback)
+ priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg);
buf[1] = high ? 0 : 1;
- if (t->config == 2)
+ if (*priv->lna_cfg == 2)
buf[1] = high ? 1 : 0;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
break;
case 3: /* switch with GPIO of saa713x */
- if (t->tuner_callback)
- t->tuner_callback(c->adapter->algo_data, 0, high);
+ if (priv->tuner_callback)
+ priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high);
break;
}
}
-static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+static void tda827xa_set_analog_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
unsigned char tuner_reg[11];
u32 N;
int i;
- struct tuner *t = i2c_get_clientdata(c);
- struct tda8290_priv *priv = t->priv;
+ struct tda8290_priv *priv = fe->tuner_priv;
struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg};
+ unsigned int freq = params->frequency;
- tda827xa_lna_gain( c, 1);
+ tda827xa_lna_gain(fe, 1, params);
msleep(10);
- if (t->mode == V4L2_TUNER_RADIO)
+ if (params->mode == V4L2_TUNER_RADIO)
freq = freq / 1000;
- N = freq + ifc;
+ N = freq + priv->sgIF;
i = 0;
while (tda827xa_analog[i].lomax < N) {
if(tda827xa_analog[i + 1].lomax == 0)
@@ -278,7 +300,7 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
tuner_reg[9] = 0x20;
tuner_reg[10] = 0x00;
msg.len = 11;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
tuner_reg[0] = 0x90;
tuner_reg[1] = 0xff;
@@ -286,82 +308,131 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
tuner_reg[3] = 0;
tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1);
msg.len = 5;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
tuner_reg[0] = 0xa0;
tuner_reg[1] = 0xc0;
msg.len = 2;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
tuner_reg[0] = 0x30;
tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msg.flags = I2C_M_RD;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msg.flags = 0;
tuner_reg[1] >>= 4;
tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]);
if (tuner_reg[1] < 1)
- tda827xa_lna_gain( c, 0);
+ tda827xa_lna_gain(fe, 0, params);
msleep(100);
tuner_reg[0] = 0x60;
tuner_reg[1] = 0x3c;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
msleep(163);
tuner_reg[0] = 0x50;
tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
tuner_reg[0] = 0x80;
tuner_reg[1] = 0x28;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
tuner_reg[0] = 0xb0;
tuner_reg[1] = 0x01;
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
tuner_reg[0] = 0xc0;
tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1);
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
}
-static void tda827xa_agcf(struct i2c_client *c)
+static void tda827xa_agcf(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
- struct tda8290_priv *priv = t->priv;
+ struct tda8290_priv *priv = fe->tuner_priv;
unsigned char data[] = {0x80, 0x2c};
struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
.flags = 0, .len = 2};
- i2c_transfer(c->adapter, &msg, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
}
/*---------------------------------------------------------------------*/
-static void tda8290_i2c_bridge(struct i2c_client *c, int close)
+static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
{
+ struct tda8290_priv *priv = fe->tuner_priv;
+
unsigned char enable[2] = { 0x21, 0xC0 };
unsigned char disable[2] = { 0x21, 0x00 };
unsigned char *msg;
if(close) {
msg = enable;
- i2c_master_send(c, msg, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
/* let the bridge stabilize */
msleep(20);
} else {
msg = disable;
- i2c_master_send(c, msg, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
}
}
/*---------------------------------------------------------------------*/
-static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+static void set_audio(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct tda8290_priv *priv = fe->tuner_priv;
+ char* mode;
+
+ priv->tda827x_lpsel = 0;
+ if (params->std & V4L2_STD_MN) {
+ priv->sgIF = 92;
+ priv->tda8290_easy_mode = 0x01;
+ priv->tda827x_lpsel = 1;
+ mode = "MN";
+ } else if (params->std & V4L2_STD_B) {
+ priv->sgIF = 108;
+ priv->tda8290_easy_mode = 0x02;
+ mode = "B";
+ } else if (params->std & V4L2_STD_GH) {
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x04;
+ mode = "GH";
+ } else if (params->std & V4L2_STD_PAL_I) {
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x08;
+ mode = "I";
+ } else if (params->std & V4L2_STD_DK) {
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x10;
+ mode = "DK";
+ } else if (params->std & V4L2_STD_SECAM_L) {
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x20;
+ mode = "L";
+ } else if (params->std & V4L2_STD_SECAM_LC) {
+ priv->sgIF = 20;
+ priv->tda8290_easy_mode = 0x40;
+ mode = "LC";
+ } else {
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x10;
+ mode = "xx";
+ }
+
+ if (params->mode == V4L2_TUNER_RADIO)
+ priv->sgIF = 88; /* if frequency is 5.5 MHz */
+
+ tuner_dbg("setting tda8290 to system %s\n", mode);
+}
+
+static int tda8290_set_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
- struct tda8290_priv *priv = t->priv;
+ struct tda8290_priv *priv = fe->tuner_priv;
unsigned char soft_reset[] = { 0x00, 0x00 };
unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode };
unsigned char expert_mode[] = { 0x01, 0x80 };
@@ -384,35 +455,38 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
pll_stat;
int i;
- tuner_dbg("tda827xa config is 0x%02x\n", t->config);
- i2c_master_send(c, easy_mode, 2);
- i2c_master_send(c, agc_out_on, 2);
- i2c_master_send(c, soft_reset, 2);
+ set_audio(fe, params);
+
+ if (priv->lna_cfg)
+ tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg);
+ tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
msleep(1);
expert_mode[1] = priv->tda8290_easy_mode + 0x80;
- i2c_master_send(c, expert_mode, 2);
- i2c_master_send(c, gainset_off, 2);
- i2c_master_send(c, if_agc_spd, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
if (priv->tda8290_easy_mode & 0x60)
- i2c_master_send(c, adc_head_9, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
else
- i2c_master_send(c, adc_head_6, 2);
- i2c_master_send(c, pll_bw_nom, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
- tda8290_i2c_bridge(c, 1);
+ tda8290_i2c_bridge(fe, 1);
if (priv->tda827x_ver != 0)
- tda827xa_tune(c, ifc, freq);
+ tda827xa_set_analog_params(fe, params);
else
- tda827x_tune(c, ifc, freq);
+ tda827x_set_analog_params(fe, params);
for (i = 0; i < 3; i++) {
- i2c_master_send(c, &addr_pll_stat, 1);
- i2c_master_recv(c, &pll_stat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
if (pll_stat & 0x80) {
- i2c_master_send(c, &addr_adc_sat, 1);
- i2c_master_recv(c, &adc_sat, 1);
- i2c_master_send(c, &addr_agc_stat, 1);
- i2c_master_recv(c, &agc_stat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
break;
} else {
@@ -424,28 +498,28 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) {
tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n",
agc_stat, adc_sat, pll_stat & 0x80);
- i2c_master_send(c, gainset_2, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2);
msleep(100);
- i2c_master_send(c, &addr_agc_stat, 1);
- i2c_master_recv(c, &agc_stat, 1);
- i2c_master_send(c, &addr_pll_stat, 1);
- i2c_master_recv(c, &pll_stat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
if ((agc_stat > 115) || !(pll_stat & 0x80)) {
tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
agc_stat, pll_stat & 0x80);
if (priv->tda827x_ver != 0)
- tda827xa_agcf(c);
+ tda827xa_agcf(fe);
else
- tda827x_agcf(c);
+ tda827x_agcf(fe);
msleep(100);
- i2c_master_send(c, &addr_agc_stat, 1);
- i2c_master_recv(c, &agc_stat, 1);
- i2c_master_send(c, &addr_pll_stat, 1);
- i2c_master_recv(c, &pll_stat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
if((agc_stat > 115) || !(pll_stat & 0x80)) {
tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat);
- i2c_master_send(c, adc_head_12, 2);
- i2c_master_send(c, pll_bw_low, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2);
msleep(100);
}
}
@@ -453,132 +527,106 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
/* l/ l' deadlock? */
if(priv->tda8290_easy_mode & 0x60) {
- i2c_master_send(c, &addr_adc_sat, 1);
- i2c_master_recv(c, &adc_sat, 1);
- i2c_master_send(c, &addr_pll_stat, 1);
- i2c_master_recv(c, &pll_stat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
+ tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
+ tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
if ((adc_sat > 20) || !(pll_stat & 0x80)) {
tuner_dbg("trying to resolve SECAM L deadlock\n");
- i2c_master_send(c, agc_rst_on, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2);
msleep(40);
- i2c_master_send(c, agc_rst_off, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2);
}
}
- tda8290_i2c_bridge(c, 0);
- i2c_master_send(c, if_agc_set, 2);
+ tda8290_i2c_bridge(fe, 0);
+ tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2);
+
+ priv->frequency = (V4L2_TUNER_RADIO == params->mode) ?
+ params->frequency * 125 / 2 : params->frequency * 62500;
+
return 0;
}
/*---------------------------------------------------------------------*/
-static void set_audio(struct tuner *t)
+static int tda8290_has_signal(struct dvb_frontend *fe)
{
- struct tda8290_priv *priv = t->priv;
- char* mode;
+ struct tda8290_priv *priv = fe->tuner_priv;
+ int ret;
- priv->tda827x_lpsel = 0;
- if (t->std & V4L2_STD_MN) {
- priv->sgIF = 92;
- priv->tda8290_easy_mode = 0x01;
- priv->tda827x_lpsel = 1;
- mode = "MN";
- } else if (t->std & V4L2_STD_B) {
- priv->sgIF = 108;
- priv->tda8290_easy_mode = 0x02;
- mode = "B";
- } else if (t->std & V4L2_STD_GH) {
- priv->sgIF = 124;
- priv->tda8290_easy_mode = 0x04;
- mode = "GH";
- } else if (t->std & V4L2_STD_PAL_I) {
- priv->sgIF = 124;
- priv->tda8290_easy_mode = 0x08;
- mode = "I";
- } else if (t->std & V4L2_STD_DK) {
- priv->sgIF = 124;
- priv->tda8290_easy_mode = 0x10;
- mode = "DK";
- } else if (t->std & V4L2_STD_SECAM_L) {
- priv->sgIF = 124;
- priv->tda8290_easy_mode = 0x20;
- mode = "L";
- } else if (t->std & V4L2_STD_SECAM_LC) {
- priv->sgIF = 20;
- priv->tda8290_easy_mode = 0x40;
- mode = "LC";
- } else {
- priv->sgIF = 124;
- priv->tda8290_easy_mode = 0x10;
- mode = "xx";
- }
- tuner_dbg("setting tda8290 to system %s\n", mode);
-}
+ unsigned char i2c_get_afc[1] = { 0x1B };
+ unsigned char afc = 0;
-static void set_tv_freq(struct i2c_client *c, unsigned int freq)
-{
- struct tuner *t = i2c_get_clientdata(c);
- struct tda8290_priv *priv = t->priv;
+ /* for now, report based on afc status */
+ tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
+ tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
+
+ ret = (afc & 0x80) ? 65535 : 0;
- set_audio(t);
- tda8290_tune(c, priv->sgIF, freq);
+ tuner_dbg("AFC status: %d\n", ret);
+
+ return ret;
}
-static void set_radio_freq(struct i2c_client *c, unsigned int freq)
+static int tda8290_get_status(struct dvb_frontend *fe, u32 *status)
{
- /* if frequency is 5.5 MHz */
- tda8290_tune(c, 88, freq);
+ *status = 0;
+
+ if (tda8290_has_signal(fe))
+ *status = TUNER_STATUS_LOCKED;
+
+ return 0;
}
-static int has_signal(struct i2c_client *c)
+static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
{
- unsigned char i2c_get_afc[1] = { 0x1B };
- unsigned char afc = 0;
+ *strength = tda8290_has_signal(fe);
- i2c_master_send(c, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
- i2c_master_recv(c, &afc, 1);
- return (afc & 0x80)? 65535:0;
+ return 0;
}
/*---------------------------------------------------------------------*/
-static void standby(struct i2c_client *c)
+static int tda8290_standby(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
- struct tda8290_priv *priv = t->priv;
+ struct tda8290_priv *priv = fe->tuner_priv;
unsigned char cb1[] = { 0x30, 0xD0 };
unsigned char tda8290_standby[] = { 0x00, 0x02 };
unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
- tda8290_i2c_bridge(c, 1);
+ tda8290_i2c_bridge(fe, 1);
if (priv->tda827x_ver != 0)
cb1[1] = 0x90;
- i2c_transfer(c->adapter, &msg, 1);
- tda8290_i2c_bridge(c, 0);
- i2c_master_send(c, tda8290_agc_tri, 2);
- i2c_master_send(c, tda8290_standby, 2);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
+ tda8290_i2c_bridge(fe, 0);
+ tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2);
+
+ return 0;
}
-static void tda8290_init_if(struct i2c_client *c)
+static void tda8290_init_if(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = fe->tuner_priv;
+
unsigned char set_VS[] = { 0x30, 0x6F };
unsigned char set_GP00_CF[] = { 0x20, 0x01 };
unsigned char set_GP01_CF[] = { 0x20, 0x0B };
- if ((t->config == 1) || (t->config == 2))
- i2c_master_send(c, set_GP00_CF, 2);
+ if ((priv->lna_cfg) &&
+ ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2)))
+ tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2);
else
- i2c_master_send(c, set_GP01_CF, 2);
- i2c_master_send(c, set_VS, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2);
+ tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2);
}
-static void tda8290_init_tuner(struct i2c_client *c)
+static void tda8290_init_tuner(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
- struct tda8290_priv *priv = t->priv;
+ struct tda8290_priv *priv = fe->tuner_priv;
unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
@@ -588,33 +636,43 @@ static void tda8290_init_tuner(struct i2c_client *c)
if (priv->tda827x_ver != 0)
msg.buf = tda8275a_init;
- tda8290_i2c_bridge(c, 1);
- i2c_transfer(c->adapter, &msg, 1);
- tda8290_i2c_bridge(c, 0);
+ tda8290_i2c_bridge(fe, 1);
+ i2c_transfer(priv->i2c_props.adap, &msg, 1);
+ tda8290_i2c_bridge(fe, 0);
}
/*---------------------------------------------------------------------*/
-static void tda8290_release(struct i2c_client *c)
+static int tda8290_release(struct dvb_frontend *fe)
{
- struct tuner *t = i2c_get_clientdata(c);
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
- kfree(t->priv);
- t->priv = NULL;
+ return 0;
}
-static struct tuner_operations tda8290_tuner_ops = {
- .set_tv_freq = set_tv_freq,
- .set_radio_freq = set_radio_freq,
- .has_signal = has_signal,
- .standby = standby,
- .release = tda8290_release,
+static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tda8290_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static struct dvb_tuner_ops tda8290_tuner_ops = {
+ .sleep = tda8290_standby,
+ .set_analog_params = tda8290_set_params,
+ .release = tda8290_release,
+ .get_frequency = tda8290_get_frequency,
+ .get_status = tda8290_get_status,
+ .get_rf_strength = tda8290_get_rf_strength,
};
-int tda8290_init(struct i2c_client *c)
+struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr,
+ struct tda8290_config *cfg)
{
struct tda8290_priv *priv = NULL;
- struct tuner *t = i2c_get_clientdata(c);
u8 data;
int i, ret, tuners_found;
u32 tuner_addrs;
@@ -622,16 +680,23 @@ int tda8290_init(struct i2c_client *c)
priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
if (priv == NULL)
- return -ENOMEM;
- t->priv = priv;
+ return NULL;
+ fe->tuner_priv = priv;
+
+ priv->i2c_props.addr = i2c_addr;
+ priv->i2c_props.adap = i2c_adap;
+ if (cfg) {
+ priv->lna_cfg = cfg->lna_cfg;
+ priv->tuner_callback = cfg->tuner_callback;
+ }
- tda8290_i2c_bridge(c, 1);
+ tda8290_i2c_bridge(fe, 1);
/* probe for tuner chip */
tuners_found = 0;
tuner_addrs = 0;
for (i=0x60; i<= 0x63; i++) {
msg.addr = i;
- ret = i2c_transfer(c->adapter, &msg, 1);
+ ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
if (ret == 1) {
tuners_found++;
tuner_addrs = (tuner_addrs << 8) + i;
@@ -641,11 +706,11 @@ int tda8290_init(struct i2c_client *c)
behind the bridge and we choose the highest address that doesn't
give a response now
*/
- tda8290_i2c_bridge(c, 0);
+ tda8290_i2c_bridge(fe, 0);
if(tuners_found > 1)
for (i = 0; i < tuners_found; i++) {
msg.addr = tuner_addrs & 0xff;
- ret = i2c_transfer(c->adapter, &msg, 1);
+ ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
if(ret == 1)
tuner_addrs = tuner_addrs >> 8;
else
@@ -653,40 +718,53 @@ int tda8290_init(struct i2c_client *c)
}
if (tuner_addrs == 0) {
tuner_addrs = 0x61;
- tuner_info ("could not clearly identify tuner address, defaulting to %x\n",
+ tuner_info("could not clearly identify tuner address, defaulting to %x\n",
tuner_addrs);
} else {
tuner_addrs = tuner_addrs & 0xff;
- tuner_info ("setting tuner address to %x\n", tuner_addrs);
+ tuner_info("setting tuner address to %x\n", tuner_addrs);
}
priv->tda827x_addr = tuner_addrs;
msg.addr = tuner_addrs;
- tda8290_i2c_bridge(c, 1);
- ret = i2c_transfer(c->adapter, &msg, 1);
+ tda8290_i2c_bridge(fe, 1);
+ ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
if( ret != 1)
- tuner_warn ("TDA827x access failed!\n");
+ tuner_warn("TDA827x access failed!\n");
+
+ memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
if ((data & 0x3c) == 0) {
- strlcpy(c->name, "tda8290+75", sizeof(c->name));
+ strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75",
+ sizeof(fe->ops.tuner_ops.info.name));
+ fe->ops.tuner_ops.info.frequency_min = 55000000;
+ fe->ops.tuner_ops.info.frequency_max = 860000000;
+ fe->ops.tuner_ops.info.frequency_step = 250000;
priv->tda827x_ver = 0;
} else {
- strlcpy(c->name, "tda8290+75a", sizeof(c->name));
+ strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a",
+ sizeof(fe->ops.tuner_ops.info.name));
+ fe->ops.tuner_ops.info.frequency_min = 44000000;
+ fe->ops.tuner_ops.info.frequency_max = 906000000;
+ fe->ops.tuner_ops.info.frequency_step = 62500;
priv->tda827x_ver = 2;
}
- tuner_info("type set to %s\n", c->name);
-
- memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations));
priv->tda827x_lpsel = 0;
- t->mode = V4L2_TUNER_ANALOG_TV;
- tda8290_init_tuner(c);
- tda8290_init_if(c);
- return 0;
+ tda8290_init_tuner(fe);
+ tda8290_init_if(fe);
+ return fe;
}
-int tda8290_probe(struct i2c_client *c)
+int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
{
+ struct tuner_i2c_props i2c_props = {
+ .adap = i2c_adap,
+ .addr = i2c_addr
+ };
+
unsigned char soft_reset[] = { 0x00, 0x00 };
unsigned char easy_mode_b[] = { 0x01, 0x02 };
unsigned char easy_mode_g[] = { 0x01, 0x04 };
@@ -694,23 +772,30 @@ int tda8290_probe(struct i2c_client *c)
unsigned char addr_dto_lsb = 0x07;
unsigned char data;
- i2c_master_send(c, easy_mode_b, 2);
- i2c_master_send(c, soft_reset, 2);
- i2c_master_send(c, &addr_dto_lsb, 1);
- i2c_master_recv(c, &data, 1);
+ tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2);
+ tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
+ tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
+ tuner_i2c_xfer_recv(&i2c_props, &data, 1);
if (data == 0) {
- i2c_master_send(c, easy_mode_g, 2);
- i2c_master_send(c, soft_reset, 2);
- i2c_master_send(c, &addr_dto_lsb, 1);
- i2c_master_recv(c, &data, 1);
+ tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2);
+ tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
+ tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
+ tuner_i2c_xfer_recv(&i2c_props, &data, 1);
if (data == 0x7b) {
return 0;
}
}
- i2c_master_send(c, restore_9886, 3);
+ tuner_i2c_xfer_send(&i2c_props, restore_9886, 3);
return -1;
}
+EXPORT_SYMBOL_GPL(tda8290_probe);
+EXPORT_SYMBOL_GPL(tda8290_attach);
+
+MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver");
+MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann");
+MODULE_LICENSE("GPL");
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h
new file mode 100644
index 00000000000..107b24b05aa
--- /dev/null
+++ b/drivers/media/video/tda8290.h
@@ -0,0 +1,54 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TDA8290_H__
+#define __TDA8290_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct tda8290_config
+{
+ unsigned int *lna_cfg;
+ int (*tuner_callback) (void *dev, int command,int arg);
+};
+
+#if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE))
+extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr);
+
+extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr,
+ struct tda8290_config *cfg);
+#else
+static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
+{
+ printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+ __FUNCTION__);
+ return -EINVAL;
+}
+
+static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr,
+ struct tda8290_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif
+
+#endif /* __TDA8290_H__ */
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index a8f773274fe..be5387f11af 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -1,14 +1,12 @@
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/types.h>
-#include <linux/videodev.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>
-
+#include <linux/videodev.h>
#include <media/v4l2-common.h>
#include <media/tuner.h>
#include "tuner-driver.h"
@@ -31,6 +29,8 @@
i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
struct tda9887_priv {
+ struct tuner_i2c_props i2c_props;
+
unsigned char data[4];
};
@@ -97,6 +97,8 @@ struct tvnorm {
#define cAudioIF_6_5 0x03 // bit e0:1
+#define cVideoIFMask 0x1c // bit e2:4
+/* Video IF selection in TV Mode (bit B3=0) */
#define cVideoIF_58_75 0x00 // bit e2:4
#define cVideoIF_45_75 0x04 // bit e2:4
#define cVideoIF_38_90 0x08 // bit e2:4
@@ -106,6 +108,13 @@ struct tvnorm {
#define cRadioIF_45_75 0x18 // bit e2:4
#define cRadioIF_38_90 0x1C // bit e2:4
+/* IF1 selection in Radio Mode (bit B3=1) */
+#define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14)
+#define cRadioIF_41_30 0x04 // bit e2,4
+
+/* Output of AFC pin in radio mode when bit E7=1 */
+#define cRadioAGC_SIF 0x00 // bit e3
+#define cRadioAGC_FM 0x08 // bit e3
#define cTunerGainNormal 0x00 // bit e5
#define cTunerGainLow 0x20 // bit e5
@@ -487,9 +496,13 @@ static int tda9887_set_config(struct tuner *t, char *buf)
if (t->tda9887_config & TDA9887_GATING_18)
buf[3] &= ~cGating_36;
- if (t->tda9887_config & TDA9887_GAIN_NORMAL) {
- radio_stereo.e &= ~cTunerGainLow;
- radio_mono.e &= ~cTunerGainLow;
+ if (t->mode == V4L2_TUNER_RADIO) {
+ if (t->tda9887_config & TDA9887_RIF_41_3) {
+ buf[3] &= ~cVideoIFMask;
+ buf[3] |= cRadioIF_41_30;
+ }
+ if (t->tda9887_config & TDA9887_GAIN_NORMAL)
+ buf[3] &= ~cTunerGainLow;
}
return 0;
@@ -499,19 +512,19 @@ static int tda9887_set_config(struct tuner *t, char *buf)
static int tda9887_status(struct tuner *t)
{
+ struct tda9887_priv *priv = t->priv;
unsigned char buf[1];
int rc;
memset(buf,0,sizeof(buf));
- if (1 != (rc = i2c_master_recv(&t->i2c,buf,1)))
+ if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
dump_read_message(t, buf);
return 0;
}
-static void tda9887_configure(struct i2c_client *client)
+static void tda9887_configure(struct tuner *t)
{
- struct tuner *t = i2c_get_clientdata(client);
struct tda9887_priv *priv = t->priv;
int rc;
@@ -546,7 +559,7 @@ static void tda9887_configure(struct i2c_client *client)
if (tuner_debug > 1)
dump_write_message(t, priv->data);
- if (4 != (rc = i2c_master_send(&t->i2c,priv->data,4)))
+ if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
if (tuner_debug > 2) {
@@ -557,16 +570,15 @@ static void tda9887_configure(struct i2c_client *client)
/* ---------------------------------------------------------------------- */
-static void tda9887_tuner_status(struct i2c_client *client)
+static void tda9887_tuner_status(struct tuner *t)
{
- struct tuner *t = i2c_get_clientdata(client);
struct tda9887_priv *priv = t->priv;
tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
}
-static int tda9887_get_afc(struct i2c_client *client)
+static int tda9887_get_afc(struct tuner *t)
{
- struct tuner *t = i2c_get_clientdata(client);
+ struct tda9887_priv *priv = t->priv;
static int AFC_BITS_2_kHz[] = {
-12500, -37500, -62500, -97500,
-112500, -137500, -162500, -187500,
@@ -576,26 +588,24 @@ static int tda9887_get_afc(struct i2c_client *client)
int afc=0;
__u8 reg = 0;
- if (1 == i2c_master_recv(&t->i2c,&reg,1))
+ if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,&reg,1))
afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
return afc;
}
-static void tda9887_standby(struct i2c_client *client)
+static void tda9887_standby(struct tuner *t)
{
- tda9887_configure(client);
+ tda9887_configure(t);
}
-static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
+static void tda9887_set_freq(struct tuner *t, unsigned int freq)
{
- tda9887_configure(client);
+ tda9887_configure(t);
}
-static void tda9887_release(struct i2c_client *c)
+static void tda9887_release(struct tuner *t)
{
- struct tuner *t = i2c_get_clientdata(c);
-
kfree(t->priv);
t->priv = NULL;
}
@@ -609,17 +619,19 @@ static struct tuner_operations tda9887_tuner_ops = {
.release = tda9887_release,
};
-int tda9887_tuner_init(struct i2c_client *c)
+int tda9887_tuner_init(struct tuner *t)
{
struct tda9887_priv *priv = NULL;
- struct tuner *t = i2c_get_clientdata(c);
priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
t->priv = priv;
- strlcpy(c->name, "tda9887", sizeof(c->name));
+ priv->i2c_props.addr = t->i2c.addr;
+ priv->i2c_props.adap = t->i2c.adapter;
+
+ strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name));
tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
t->i2c.driver->driver.name);
diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c
index ae105c2cd0a..2150222a386 100644
--- a/drivers/media/video/tea5761.c
+++ b/drivers/media/video/tea5761.c
@@ -8,15 +8,23 @@
*/
#include <linux/i2c.h>
-#include <linux/videodev.h>
#include <linux/delay.h>
+#include <linux/videodev.h>
#include <media/tuner.h>
-#include "tuner-driver.h"
+#include "tuner-i2c.h"
+#include "tea5761.h"
-#define PREFIX "TEA5761 "
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
-/* from tuner-core.c */
-extern int tuner_debug;
+#define PREFIX "tea5761 "
+
+struct tea5761_priv {
+ struct tuner_i2c_props i2c_props;
+
+ u32 frequency;
+};
/*****************************************************************************/
@@ -114,13 +122,6 @@ extern int tuner_debug;
/*****************************************************************************/
-static void set_tv_freq(struct i2c_client *c, unsigned int freq)
-{
- struct tuner *t = i2c_get_clientdata(c);
-
- tuner_warn("This tuner doesn't support TV freq.\n");
-}
-
#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */
static void tea5761_status_dump(unsigned char *buffer)
{
@@ -135,16 +136,18 @@ static void tea5761_status_dump(unsigned char *buffer)
}
/* Freq should be specifyed at 62.5 Hz */
-static void set_radio_freq(struct i2c_client *c, unsigned int frq)
+static int set_radio_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tea5761_priv *priv = fe->tuner_priv;
+ unsigned int frq = params->frequency;
unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 };
unsigned div;
int rc;
- tuner_dbg (PREFIX "radio freq counter %d\n", frq);
+ tuner_dbg("radio freq counter %d\n", frq);
- if (t->mode == T_STANDBY) {
+ if (params->mode == T_STANDBY) {
tuner_dbg("TEA5761 set to standby mode\n");
buffer[5] |= TEA5761_TNCTRL_MU;
} else {
@@ -152,10 +155,9 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq)
}
- if (t->audmode == V4L2_TUNER_MODE_MONO) {
+ if (params->audmode == V4L2_TUNER_MODE_MONO) {
tuner_dbg("TEA5761 set to mono\n");
buffer[5] |= TEA5761_TNCTRL_MST;
-;
} else {
tuner_dbg("TEA5761 set to stereo\n");
}
@@ -164,80 +166,155 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq)
buffer[1] = (div >> 8) & 0x3f;
buffer[2] = div & 0xff;
- if (tuner_debug)
+ if (debug)
tea5761_status_dump(buffer);
- if (7 != (rc = i2c_master_send(c, buffer, 7)))
+ if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7)))
tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+ priv->frequency = frq * 125 / 2;
+
+ return 0;
}
-static int tea5761_signal(struct i2c_client *c)
+static int tea5761_read_status(struct dvb_frontend *fe, char *buffer)
{
- unsigned char buffer[16];
+ struct tea5761_priv *priv = fe->tuner_priv;
int rc;
- struct tuner *t = i2c_get_clientdata(c);
- memset(buffer, 0, sizeof(buffer));
- if (16 != (rc = i2c_master_recv(c, buffer, 16)))
- tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+ memset(buffer, 0, 16);
+ if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) {
+ tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer)
+{
+ struct tea5761_priv *priv = fe->tuner_priv;
+
+ int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4));
+
+ tuner_dbg("Signal strength: %d\n", signal);
+
+ return signal;
+}
+
+static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer)
+{
+ struct tea5761_priv *priv = fe->tuner_priv;
+
+ int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO;
- return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4));
+ tuner_dbg("Radio ST GET = %02x\n", stereo);
+
+ return (stereo ? V4L2_TUNER_SUB_STEREO : 0);
}
-static int tea5761_stereo(struct i2c_client *c)
+static int tea5761_get_status(struct dvb_frontend *fe, u32 *status)
{
unsigned char buffer[16];
- int rc;
- struct tuner *t = i2c_get_clientdata(c);
- memset(buffer, 0, sizeof(buffer));
- if (16 != (rc = i2c_master_recv(c, buffer, 16)))
- tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+ *status = 0;
+
+ if (0 == tea5761_read_status(fe, buffer)) {
+ if (tea5761_signal(fe, buffer))
+ *status = TUNER_STATUS_LOCKED;
+ if (tea5761_stereo(fe, buffer))
+ *status |= TUNER_STATUS_STEREO;
+ }
+
+ return 0;
+}
+
+static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ unsigned char buffer[16];
- rc = buffer[9] & TEA5761_TUNCHECK_STEREO;
+ *strength = 0;
- tuner_dbg("TEA5761 radio ST GET = %02x\n", rc);
+ if (0 == tea5761_read_status(fe, buffer))
+ *strength = tea5761_signal(fe, buffer);
- return (rc ? V4L2_TUNER_SUB_STEREO : 0);
+ return 0;
}
-int tea5761_autodetection(struct i2c_client *c)
+int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
{
unsigned char buffer[16];
int rc;
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr };
- if (16 != (rc = i2c_master_recv(c, buffer, 16))) {
- tuner_warn("it is not a TEA5761. Received %i chars.\n", rc);
+ if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) {
+ printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc);
return EINVAL;
}
if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) {
- tuner_warn("Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]);
+ printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]);
return EINVAL;
}
- tuner_warn("TEA5761 detected.\n");
+ printk(KERN_WARNING "TEA5761 detected.\n");
return 0;
}
-static struct tuner_operations tea5761_tuner_ops = {
- .set_tv_freq = set_tv_freq,
- .set_radio_freq = set_radio_freq,
- .has_signal = tea5761_signal,
- .is_stereo = tea5761_stereo,
+static int tea5761_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tea5761_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static struct dvb_tuner_ops tea5761_tuner_ops = {
+ .info = {
+ .name = "tea5761", // Philips TEA5761HN FM Radio
+ },
+ .set_analog_params = set_radio_freq,
+ .release = tea5761_release,
+ .get_frequency = tea5761_get_frequency,
+ .get_status = tea5761_get_status,
+ .get_rf_strength = tea5761_get_rf_strength,
};
-int tea5761_tuner_init(struct i2c_client *c)
+struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tea5761_priv *priv = NULL;
- if (tea5761_autodetection(c) == EINVAL)
- return EINVAL;
+ if (tea5761_autodetection(i2c_adap, i2c_addr) == EINVAL)
+ return NULL;
+
+ priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+ fe->tuner_priv = priv;
+
+ priv->i2c_props.addr = i2c_addr;
+ priv->i2c_props.adap = i2c_adap;
- tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5761HN FM Radio");
- strlcpy(c->name, "tea5761", sizeof(c->name));
+ memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
- memcpy(&t->ops, &tea5761_tuner_ops, sizeof(struct tuner_operations));
+ tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio");
- return (0);
+ return fe;
}
+
+
+EXPORT_SYMBOL_GPL(tea5761_attach);
+EXPORT_SYMBOL_GPL(tea5761_autodetection);
+
+MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tea5761.h b/drivers/media/video/tea5761.h
new file mode 100644
index 00000000000..73a03b42784
--- /dev/null
+++ b/drivers/media/video/tea5761.h
@@ -0,0 +1,47 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TEA5761_H__
+#define __TEA5761_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
+extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
+
+extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr);
+#else
+static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
+{
+ printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+ __FUNCTION__);
+ return -EINVAL;
+}
+
+static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif
+
+#endif /* __TEA5761_H__ */
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index 4985d47a508..71df419df7b 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -11,14 +11,22 @@
*/
#include <linux/i2c.h>
-#include <linux/videodev.h>
#include <linux/delay.h>
-#include "tuner-driver.h"
+#include <linux/videodev.h>
+#include "tuner-i2c.h"
+#include "tea5767.h"
-#define PREFIX "TEA5767 "
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
-/* from tuner-core.c */
-extern int tuner_debug;
+#define PREFIX "tea5767 "
+
+struct tea5767_priv {
+ struct tuner_i2c_props i2c_props;
+
+ u32 frequency;
+};
/*****************************************************************************/
@@ -129,13 +137,6 @@ enum tea5767_xtal_freq {
/*****************************************************************************/
-static void set_tv_freq(struct i2c_client *c, unsigned int freq)
-{
- struct tuner *t = i2c_get_clientdata(c);
-
- tuner_warn("This tuner doesn't support TV freq.\n");
-}
-
static void tea5767_status_dump(unsigned char *buffer)
{
unsigned int div, frq;
@@ -190,14 +191,16 @@ static void tea5767_status_dump(unsigned char *buffer)
}
/* Freq should be specifyed at 62.5 Hz */
-static void set_radio_freq(struct i2c_client *c, unsigned int frq)
+static int set_radio_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tea5767_priv *priv = fe->tuner_priv;
+ unsigned int frq = params->frequency;
unsigned char buffer[5];
unsigned div;
int rc;
- tuner_dbg (PREFIX "radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000);
+ tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000);
/* Rounds freq to next decimal value - for 62.5 KHz step */
/* frq = 20*(frq/16)+radio_frq[frq%16]; */
@@ -207,7 +210,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq)
TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND;
buffer[4] = 0;
- if (t->audmode == V4L2_TUNER_MODE_MONO) {
+ if (params->audmode == V4L2_TUNER_MODE_MONO) {
tuner_dbg("TEA5767 set to mono\n");
buffer[2] |= TEA5767_MONO;
} else {
@@ -217,26 +220,26 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq)
/* Should be replaced */
switch (TEA5767_HIGH_LO_32768) {
case TEA5767_HIGH_LO_13MHz:
- tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n");
+ tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n");
buffer[2] |= TEA5767_HIGH_LO_INJECT;
buffer[4] |= TEA5767_PLLREF_ENABLE;
div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000;
break;
case TEA5767_LOW_LO_13MHz:
- tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n");
+ tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n");
buffer[4] |= TEA5767_PLLREF_ENABLE;
div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000;
break;
case TEA5767_LOW_LO_32768:
- tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n");
+ tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n");
buffer[3] |= TEA5767_XTAL_32768;
/* const 700=4000*175 Khz - to adjust freq to right value */
div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15;
break;
case TEA5767_HIGH_LO_32768:
default:
- tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n");
+ tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n");
buffer[2] |= TEA5767_HIGH_LO_INJECT;
buffer[3] |= TEA5767_XTAL_32768;
@@ -246,51 +249,89 @@ static void set_radio_freq(struct i2c_client *c, unsigned int frq)
buffer[0] = (div >> 8) & 0x3f;
buffer[1] = div & 0xff;
- if (5 != (rc = i2c_master_send(c, buffer, 5)))
+ if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5)))
tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
- if (tuner_debug) {
- if (5 != (rc = i2c_master_recv(c, buffer, 5)))
+ if (debug) {
+ if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5)))
tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
else
tea5767_status_dump(buffer);
}
+
+ priv->frequency = frq * 125 / 2;
+
+ return 0;
}
-static int tea5767_signal(struct i2c_client *c)
+static int tea5767_read_status(struct dvb_frontend *fe, char *buffer)
{
- unsigned char buffer[5];
+ struct tea5767_priv *priv = fe->tuner_priv;
int rc;
- struct tuner *t = i2c_get_clientdata(c);
- memset(buffer, 0, sizeof(buffer));
- if (5 != (rc = i2c_master_recv(c, buffer, 5)))
+ memset(buffer, 0, 5);
+ if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) {
tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer)
+{
+ struct tea5767_priv *priv = fe->tuner_priv;
+
+ int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8);
+
+ tuner_dbg("Signal strength: %d\n", signal);
+
+ return signal;
+}
+
+static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer)
+{
+ struct tea5767_priv *priv = fe->tuner_priv;
+
+ int stereo = buffer[2] & TEA5767_STEREO_MASK;
+
+ tuner_dbg("Radio ST GET = %02x\n", stereo);
- return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8);
+ return (stereo ? V4L2_TUNER_SUB_STEREO : 0);
}
-static int tea5767_stereo(struct i2c_client *c)
+static int tea5767_get_status(struct dvb_frontend *fe, u32 *status)
{
unsigned char buffer[5];
- int rc;
- struct tuner *t = i2c_get_clientdata(c);
- memset(buffer, 0, sizeof(buffer));
- if (5 != (rc = i2c_master_recv(c, buffer, 5)))
- tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+ *status = 0;
+
+ if (0 == tea5767_read_status(fe, buffer)) {
+ if (tea5767_signal(fe, buffer))
+ *status = TUNER_STATUS_LOCKED;
+ if (tea5767_stereo(fe, buffer))
+ *status |= TUNER_STATUS_STEREO;
+ }
+
+ return 0;
+}
- rc = buffer[2] & TEA5767_STEREO_MASK;
+static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ unsigned char buffer[5];
- tuner_dbg("TEA5767 radio ST GET = %02x\n", rc);
+ *strength = 0;
- return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0);
+ if (0 == tea5767_read_status(fe, buffer))
+ *strength = tea5767_signal(fe, buffer);
+
+ return 0;
}
-static void tea5767_standby(struct i2c_client *c)
+static int tea5767_standby(struct dvb_frontend *fe)
{
unsigned char buffer[5];
- struct tuner *t = i2c_get_clientdata(c);
+ struct tea5767_priv *priv = fe->tuner_priv;
unsigned div, rc;
div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */
@@ -301,25 +342,27 @@ static void tea5767_standby(struct i2c_client *c)
TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY;
buffer[4] = 0;
- if (5 != (rc = i2c_master_send(c, buffer, 5)))
+ if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5)))
tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+ return 0;
}
-int tea5767_autodetection(struct i2c_client *c)
+int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
{
+ struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr };
unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
int rc;
- struct tuner *t = i2c_get_clientdata(c);
- if ((rc = i2c_master_recv(c, buffer, 7))< 5) {
- tuner_warn("It is not a TEA5767. Received %i bytes.\n", rc);
+ if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) {
+ printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc);
return EINVAL;
}
/* If all bytes are the same then it's a TV tuner and not a tea5767 */
if (buffer[0] == buffer[1] && buffer[0] == buffer[2] &&
buffer[0] == buffer[3] && buffer[0] == buffer[4]) {
- tuner_warn("All bytes are equal. It is not a TEA5767\n");
+ printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n");
return EINVAL;
}
@@ -329,36 +372,74 @@ int tea5767_autodetection(struct i2c_client *c)
* Byte 5: bit 7:0 : == 0
*/
if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) {
- tuner_warn("Chip ID is not zero. It is not a TEA5767\n");
+ printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n");
return EINVAL;
}
/* It seems that tea5767 returns 0xff after the 5th byte */
if ((buffer[5] != 0xff) || (buffer[6] != 0xff)) {
- tuner_warn("Returned more than 5 bytes. It is not a TEA5767\n");
+ printk(KERN_WARNING "Returned more than 5 bytes. It is not a TEA5767\n");
return EINVAL;
}
- tuner_warn("TEA5767 detected.\n");
+ printk(KERN_WARNING "TEA5767 detected.\n");
return 0;
}
-static struct tuner_operations tea5767_tuner_ops = {
- .set_tv_freq = set_tv_freq,
- .set_radio_freq = set_radio_freq,
- .has_signal = tea5767_signal,
- .is_stereo = tea5767_stereo,
- .standby = tea5767_standby,
+static int tea5767_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tea5767_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static struct dvb_tuner_ops tea5767_tuner_ops = {
+ .info = {
+ .name = "tea5767", // Philips TEA5767HN FM Radio
+ },
+
+ .set_analog_params = set_radio_freq,
+ .sleep = tea5767_standby,
+ .release = tea5767_release,
+ .get_frequency = tea5767_get_frequency,
+ .get_status = tea5767_get_status,
+ .get_rf_strength = tea5767_get_rf_strength,
};
-int tea5767_tuner_init(struct i2c_client *c)
+struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tea5767_priv *priv = NULL;
+
+ priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+ fe->tuner_priv = priv;
+
+ priv->i2c_props.addr = i2c_addr;
+ priv->i2c_props.adap = i2c_adap;
- tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio");
- strlcpy(c->name, "tea5767", sizeof(c->name));
+ memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
- memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations));
+ tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio");
- return (0);
+ return fe;
}
+
+
+EXPORT_SYMBOL_GPL(tea5767_attach);
+EXPORT_SYMBOL_GPL(tea5767_autodetection);
+
+MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h
new file mode 100644
index 00000000000..5d78281adcc
--- /dev/null
+++ b/drivers/media/video/tea5767.h
@@ -0,0 +1,47 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TEA5767_H__
+#define __TEA5767_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE))
+extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
+
+extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr);
+#else
+static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
+{
+ printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+ __FUNCTION__);
+ return -EINVAL;
+}
+
+static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
+ struct i2c_adapter* i2c_adap,
+ u8 i2c_addr)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif
+
+#endif /* __TEA5767_H__ */
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index e646465464a..9e99f3636d3 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -5,7 +5,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
@@ -15,18 +14,23 @@
#include <linux/poll.h>
#include <linux/i2c.h>
#include <linux/types.h>
-#include <linux/videodev.h>
#include <linux/init.h>
-
+#include <linux/videodev.h>
#include <media/tuner.h>
+#include <media/tuner-types.h>
#include <media/v4l2-common.h>
#include "tuner-driver.h"
+#include "mt20xx.h"
+#include "tda8290.h"
+#include "tea5761.h"
+#include "tea5767.h"
+#include "tuner-simple.h"
#define UNSET (-1U)
/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
-#ifdef CONFIG_TUNER_TEA5761
+#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
0x10,
#endif
0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
@@ -72,6 +76,51 @@ static struct i2c_client client_template;
/* ---------------------------------------------------------------------- */
+static void fe_set_freq(struct tuner *t, unsigned int freq)
+{
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+ struct analog_parameters params = {
+ .frequency = freq,
+ .mode = t->mode,
+ .audmode = t->audmode,
+ .std = t->std
+ };
+
+ if (NULL == fe_tuner_ops->set_analog_params) {
+ tuner_warn("Tuner frontend module has no way to set freq\n");
+ return;
+ }
+ fe_tuner_ops->set_analog_params(&t->fe, &params);
+}
+
+static void fe_release(struct tuner *t)
+{
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+ if (fe_tuner_ops->release)
+ fe_tuner_ops->release(&t->fe);
+}
+
+static void fe_standby(struct tuner *t)
+{
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+ if (fe_tuner_ops->sleep)
+ fe_tuner_ops->sleep(&t->fe);
+}
+
+static int fe_has_signal(struct tuner *t)
+{
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+ u16 strength = 0;
+
+ if (fe_tuner_ops->get_rf_strength)
+ fe_tuner_ops->get_rf_strength(&t->fe, &strength);
+
+ return strength;
+}
+
/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
static void set_tv_freq(struct i2c_client *c, unsigned int freq)
{
@@ -96,7 +145,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
else
freq = tv_range[1] * 16;
}
- t->ops.set_tv_freq(c, freq);
+ t->ops.set_tv_freq(t, freq);
}
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -123,7 +172,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
freq = radio_range[1] * 16000;
}
- t->ops.set_radio_freq(c, freq);
+ t->ops.set_radio_freq(t, freq);
}
static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -147,11 +196,51 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
}
}
+static void tuner_i2c_address_check(struct tuner *t)
+{
+ if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
+ ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f)))
+ return;
+
+ tuner_warn("====================== WARNING! ======================\n");
+ tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
+ tuner_warn("will soon be dropped. This message indicates that your\n");
+ tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
+ t->i2c.name, t->i2c.addr);
+ tuner_warn("To ensure continued support for your device, please\n");
+ tuner_warn("send a copy of this message, along with full dmesg\n");
+ tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
+ tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
+ tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
+ t->i2c.adapter->name, t->i2c.addr, t->type,
+ tuners[t->type].name);
+ tuner_warn("====================== WARNING! ======================\n");
+}
+
+static void attach_tda8290(struct tuner *t)
+{
+ struct tda8290_config cfg = {
+ .lna_cfg = &t->config,
+ .tuner_callback = t->tuner_callback
+ };
+ tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
+}
+
+static void attach_simple_tuner(struct tuner *t)
+{
+ struct simple_tuner_config cfg = {
+ .type = t->type,
+ .tun = &tuners[t->type]
+ };
+ simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
+}
+
static void set_type(struct i2c_client *c, unsigned int type,
unsigned int new_mode_mask, unsigned int new_config,
int (*tuner_callback) (void *dev, int command,int arg))
{
struct tuner *t = i2c_get_clientdata(c);
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
unsigned char buffer[4];
if (type == UNSET || type == TUNER_ABSENT) {
@@ -180,7 +269,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
/* discard private data, in case set_type() was previously called */
if (t->ops.release)
- t->ops.release(c);
+ t->ops.release(t);
else {
kfree(t->priv);
t->priv = NULL;
@@ -188,29 +277,29 @@ static void set_type(struct i2c_client *c, unsigned int type,
switch (t->type) {
case TUNER_MT2032:
- microtune_init(c);
+ microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr);
break;
case TUNER_PHILIPS_TDA8290:
- tda8290_init(c);
+ {
+ attach_tda8290(t);
break;
+ }
case TUNER_TEA5767:
- if (tea5767_tuner_init(c) == EINVAL) {
+ if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
t->type = TUNER_ABSENT;
t->mode_mask = T_UNINITIALIZED;
return;
}
t->mode_mask = T_RADIO;
break;
-#ifdef CONFIG_TUNER_TEA5761
case TUNER_TEA5761:
- if (tea5761_tuner_init(c) == EINVAL) {
+ if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
t->type = TUNER_ABSENT;
t->mode_mask = T_UNINITIALIZED;
return;
}
t->mode_mask = T_RADIO;
break;
-#endif
case TUNER_PHILIPS_FMD1216ME_MK3:
buffer[0] = 0x0b;
buffer[1] = 0xdc;
@@ -221,7 +310,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[2] = 0x86;
buffer[3] = 0x54;
i2c_master_send(c, buffer, 4);
- default_tuner_init(c);
+ attach_simple_tuner(t);
break;
case TUNER_PHILIPS_TD1316:
buffer[0] = 0x0b;
@@ -229,16 +318,28 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[2] = 0x86;
buffer[3] = 0xa4;
i2c_master_send(c,buffer,4);
- default_tuner_init(c);
+ attach_simple_tuner(t);
break;
case TUNER_TDA9887:
- tda9887_tuner_init(c);
+ tda9887_tuner_init(t);
break;
default:
- default_tuner_init(c);
+ attach_simple_tuner(t);
break;
}
+ if (fe_tuner_ops->set_analog_params) {
+ strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name));
+
+ t->ops.set_tv_freq = fe_set_freq;
+ t->ops.set_radio_freq = fe_set_freq;
+ t->ops.standby = fe_standby;
+ t->ops.release = fe_release;
+ t->ops.has_signal = fe_has_signal;
+ }
+
+ tuner_info("type set to %s\n", t->i2c.name);
+
if (t->mode_mask == T_UNINITIALIZED)
t->mode_mask = new_mode_mask;
@@ -246,6 +347,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
c->adapter->name, c->driver->driver.name, c->addr << 1, type,
t->mode_mask);
+ tuner_i2c_address_check(t);
}
/*
@@ -406,10 +508,10 @@ static int tuner_fixup_std(struct tuner *t)
return 0;
}
-static void tuner_status(struct i2c_client *client)
+static void tuner_status(struct tuner *t)
{
- struct tuner *t = i2c_get_clientdata(client);
unsigned long freq, freq_fraction;
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
const char *p;
switch (t->mode) {
@@ -430,11 +532,20 @@ static void tuner_status(struct i2c_client *client)
tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
if (t->mode != V4L2_TUNER_RADIO)
return;
+ if (fe_tuner_ops->get_status) {
+ u32 tuner_status;
+
+ fe_tuner_ops->get_status(&t->fe, &tuner_status);
+ if (tuner_status & TUNER_STATUS_LOCKED)
+ tuner_info("Tuner is locked.\n");
+ if (tuner_status & TUNER_STATUS_STEREO)
+ tuner_info("Stereo: yes\n");
+ }
if (t->ops.has_signal) {
- tuner_info("Signal strength: %d\n", t->ops.has_signal(client));
+ tuner_info("Signal strength: %d\n", t->ops.has_signal(t));
}
if (t->ops.is_stereo) {
- tuner_info("Stereo: %s\n", t->ops.is_stereo(client) ? "yes" : "no");
+ tuner_info("Stereo: %s\n", t->ops.is_stereo(t) ? "yes" : "no");
}
}
@@ -481,9 +592,8 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
/* autodetection code based on the i2c addr */
if (!no_autodetect) {
switch (addr) {
-#ifdef CONFIG_TUNER_TEA5761
case 0x10:
- if (tea5761_autodetection(&t->i2c) != EINVAL) {
+ if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
t->type = TUNER_TEA5761;
t->mode_mask = T_RADIO;
t->mode = T_STANDBY;
@@ -493,14 +603,13 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
goto register_client;
}
break;
-#endif
case 0x42:
case 0x43:
case 0x4a:
case 0x4b:
/* If chip is not tda8290, don't register.
since it can be tda9887*/
- if (tda8290_probe(&t->i2c) == 0) {
+ if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) {
tuner_dbg("chip at addr %x is a tda8290\n", addr);
} else {
/* Default is being tda9887 */
@@ -511,7 +620,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
}
break;
case 0x60:
- if (tea5767_autodetection(&t->i2c) != EINVAL) {
+ if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
t->type = TUNER_TEA5767;
t->mode_mask = T_RADIO;
t->mode = T_STANDBY;
@@ -548,6 +657,28 @@ static int tuner_probe(struct i2c_adapter *adap)
normal_i2c[1] = I2C_CLIENT_END;
}
+ /* HACK: Ignore 0x6b and 0x6f on cx88 boards.
+ * FusionHDTV5 RT Gold has an ir receiver at 0x6b
+ * and an RTC at 0x6f which can get corrupted if probed.
+ */
+ if ((adap->id == I2C_HW_B_CX2388x) ||
+ (adap->id == I2C_HW_B_CX23885)) {
+ unsigned int i = 0;
+
+ while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
+ i += 2;
+ if (i + 4 < I2C_CLIENT_MAX_OPTS) {
+ ignore[i+0] = adap->nr;
+ ignore[i+1] = 0x6b;
+ ignore[i+2] = adap->nr;
+ ignore[i+3] = 0x6f;
+ ignore[i+4] = I2C_CLIENT_END;
+ } else
+ printk(KERN_WARNING "tuner: "
+ "too many options specified "
+ "in i2c probe ignore list!\n");
+ }
+
default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
if (adap->class & I2C_CLASS_TV_ANALOG)
@@ -568,7 +699,7 @@ static int tuner_detach(struct i2c_client *client)
}
if (t->ops.release)
- t->ops.release(client);
+ t->ops.release(t);
else {
kfree(t->priv);
}
@@ -593,7 +724,7 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
if (check_mode(t, cmd) == EINVAL) {
t->mode = T_STANDBY;
if (t->ops.standby)
- t->ops.standby (client);
+ t->ops.standby(t);
return EINVAL;
}
return 0;
@@ -615,6 +746,7 @@ static inline int check_v4l2(struct tuner *t)
static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct tuner *t = i2c_get_clientdata(client);
+ struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
if (tuner_debug>1)
v4l_i2c_print_ioctl(&(t->i2c),cmd);
@@ -642,7 +774,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
return 0;
t->mode = T_STANDBY;
if (t->ops.standby)
- t->ops.standby (client);
+ t->ops.standby(t);
break;
#ifdef CONFIG_VIDEO_V4L1
case VIDIOCSAUDIO:
@@ -701,16 +833,27 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
return 0;
if (V4L2_TUNER_RADIO == t->mode) {
- if (t->ops.has_signal)
- vt->signal = t->ops.has_signal(client);
- if (t->ops.is_stereo) {
- if (t->ops.is_stereo(client))
- vt->flags |=
- VIDEO_TUNER_STEREO_ON;
+ if (fe_tuner_ops->get_status) {
+ u32 tuner_status;
+
+ fe_tuner_ops->get_status(&t->fe, &tuner_status);
+ if (tuner_status & TUNER_STATUS_STEREO)
+ vt->flags |= VIDEO_TUNER_STEREO_ON;
else
- vt->flags &=
- ~VIDEO_TUNER_STEREO_ON;
+ vt->flags &= ~VIDEO_TUNER_STEREO_ON;
+ } else {
+ if (t->ops.is_stereo) {
+ if (t->ops.is_stereo(t))
+ vt->flags |=
+ VIDEO_TUNER_STEREO_ON;
+ else
+ vt->flags &=
+ ~VIDEO_TUNER_STEREO_ON;
+ }
}
+ if (t->ops.has_signal)
+ vt->signal = t->ops.has_signal(t);
+
vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
vt->rangelow = radio_range[0] * 16000;
@@ -732,9 +875,17 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (check_v4l2(t) == EINVAL)
return 0;
- if (V4L2_TUNER_RADIO == t->mode && t->ops.is_stereo)
- va->mode = t->ops.is_stereo(client)
- ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+ if (V4L2_TUNER_RADIO == t->mode) {
+ if (fe_tuner_ops->get_status) {
+ u32 tuner_status;
+
+ fe_tuner_ops->get_status(&t->fe, &tuner_status);
+ va->mode = (tuner_status & TUNER_STATUS_STEREO)
+ ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+ } else if (t->ops.is_stereo)
+ va->mode = t->ops.is_stereo(t)
+ ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+ }
return 0;
}
#endif
@@ -785,6 +936,15 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
return 0;
switch_v4l2();
f->type = t->mode;
+ if (fe_tuner_ops->get_frequency) {
+ u32 abs_freq;
+
+ fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
+ f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
+ (abs_freq * 2 + 125/2) / 125 :
+ (abs_freq + 62500/2) / 62500;
+ break;
+ }
f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
t->radio_freq : t->tv_freq;
break;
@@ -799,7 +959,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
tuner->type = t->mode;
if (t->ops.get_afc)
- tuner->afc=t->ops.get_afc(client);
+ tuner->afc=t->ops.get_afc(t);
if (t->mode == V4L2_TUNER_ANALOG_TV)
tuner->capability |= V4L2_TUNER_CAP_NORM;
if (t->mode != V4L2_TUNER_RADIO) {
@@ -809,16 +969,22 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
/* radio mode */
- if (t->ops.has_signal)
- tuner->signal = t->ops.has_signal(client);
-
tuner->rxsubchans =
V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- if (t->ops.is_stereo) {
- tuner->rxsubchans = t->ops.is_stereo(client) ?
+ if (fe_tuner_ops->get_status) {
+ u32 tuner_status;
+
+ fe_tuner_ops->get_status(&t->fe, &tuner_status);
+ tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ?
V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+ } else {
+ if (t->ops.is_stereo) {
+ tuner->rxsubchans = t->ops.is_stereo(t) ?
+ V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+ }
}
-
+ if (t->ops.has_signal)
+ tuner->signal = t->ops.has_signal(t);
tuner->capability |=
V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
tuner->audmode = t->audmode;
@@ -844,7 +1010,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
case VIDIOC_LOG_STATUS:
if (t->ops.tuner_status)
- t->ops.tuner_status(client);
+ t->ops.tuner_status(t);
break;
}
diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h
index 0334a912507..28a10da76d1 100644
--- a/drivers/media/video/tuner-driver.h
+++ b/drivers/media/video/tuner-driver.h
@@ -19,23 +19,27 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifndef __TUNER_HW_H__
-#define __TUNER_HW_H__
+#ifndef __TUNER_DRIVER_H__
+#define __TUNER_DRIVER_H__
#include <linux/videodev2.h>
#include <linux/i2c.h>
+#include "tuner-i2c.h"
+#include "dvb_frontend.h"
extern unsigned const int tuner_count;
+struct tuner;
+
struct tuner_operations {
- void (*set_tv_freq)(struct i2c_client *c, unsigned int freq);
- void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
- int (*has_signal)(struct i2c_client *c);
- int (*is_stereo)(struct i2c_client *c);
- int (*get_afc)(struct i2c_client *c);
- void (*tuner_status)(struct i2c_client *c);
- void (*standby)(struct i2c_client *c);
- void (*release)(struct i2c_client *c);
+ void (*set_tv_freq)(struct tuner *t, unsigned int freq);
+ void (*set_radio_freq)(struct tuner *t, unsigned int freq);
+ int (*has_signal)(struct tuner *t);
+ int (*is_stereo)(struct tuner *t);
+ int (*get_afc)(struct tuner *t);
+ void (*tuner_status)(struct tuner *t);
+ void (*standby)(struct tuner *t);
+ void (*release)(struct tuner *t);
};
struct tuner {
@@ -49,13 +53,14 @@ struct tuner {
unsigned int tv_freq; /* keep track of the current settings */
unsigned int radio_freq;
- u16 last_div;
unsigned int audmode;
v4l2_std_id std;
int using_v4l2;
void *priv;
+ struct dvb_frontend fe;
+
/* used by tda9887 */
unsigned int tda9887_config;
@@ -67,20 +72,7 @@ struct tuner {
/* ------------------------------------------------------------------------ */
-extern int default_tuner_init(struct i2c_client *c);
-
-extern int tda9887_tuner_init(struct i2c_client *c);
-
-extern int microtune_init(struct i2c_client *c);
-
-extern int tda8290_init(struct i2c_client *c);
-extern int tda8290_probe(struct i2c_client *c);
-
-extern int tea5761_tuner_init(struct i2c_client *c);
-extern int tea5761_autodetection(struct i2c_client *c);
-
-extern int tea5767_autodetection(struct i2c_client *c);
-extern int tea5767_tuner_init(struct i2c_client *c);
+extern int tda9887_tuner_init(struct tuner *t);
/* ------------------------------------------------------------------------ */
@@ -96,7 +88,7 @@ extern int tea5767_tuner_init(struct i2c_client *c);
printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#endif /* __TUNER_HW_H__ */
+#endif /* __TUNER_DRIVER_H__ */
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h
new file mode 100644
index 00000000000..159019ec337
--- /dev/null
+++ b/drivers/media/video/tuner-i2c.h
@@ -0,0 +1,70 @@
+/*
+ tuner-i2c.h - i2c interface for different tuners
+
+ Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TUNER_I2C_H__
+#define __TUNER_I2C_H__
+
+#include <linux/i2c.h>
+
+struct tuner_i2c_props {
+ u8 addr;
+ struct i2c_adapter *adap;
+};
+
+static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len)
+{
+ struct i2c_msg msg = { .addr = props->addr, .flags = 0,
+ .buf = buf, .len = len };
+ int ret = i2c_transfer(props->adap, &msg, 1);
+
+ return (ret == 1) ? len : ret;
+}
+
+static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len)
+{
+ struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD,
+ .buf = buf, .len = len };
+ int ret = i2c_transfer(props->adap, &msg, 1);
+
+ return (ret == 1) ? len : ret;
+}
+
+#ifndef __TUNER_DRIVER_H__
+#define tuner_warn(fmt, arg...) do {\
+ printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \
+ i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
+#define tuner_info(fmt, arg...) do {\
+ printk(KERN_INFO PREFIX "%d-%04x: " fmt, \
+ i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
+#define tuner_dbg(fmt, arg...) do {\
+ if ((debug)) \
+ printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \
+ i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
+#endif /* __TUNER_DRIVER_H__ */
+
+#endif /* __TUNER_I2C_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 2d57e8bc0db..7b93d3b1f4c 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -1,7 +1,8 @@
/*
- *
* i2c tv tuner chip device driver
* controls all those simple 4-control-bytes style tuners.
+ *
+ * This "tuner-simple" module was split apart from the original "tuner" module.
*/
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -9,7 +10,14 @@
#include <media/tuner.h>
#include <media/v4l2-common.h>
#include <media/tuner-types.h>
-#include "tuner-driver.h"
+#include "tuner-i2c.h"
+#include "tuner-simple.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define PREFIX "tuner-simple "
static int offset = 0;
module_param(offset, int, 0664);
@@ -82,59 +90,102 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
#define TUNER_PLL_LOCKED 0x40
#define TUNER_STEREO_MK3 0x04
+struct tuner_simple_priv {
+ u16 last_div;
+ struct tuner_i2c_props i2c_props;
+
+ unsigned int type;
+ struct tunertype *tun;
+
+ u32 frequency;
+};
+
/* ---------------------------------------------------------------------- */
-static int tuner_getstatus(struct i2c_client *c)
+static int tuner_read_status(struct dvb_frontend *fe)
{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
unsigned char byte;
- if (1 != i2c_master_recv(c,&byte,1))
+ if (1 != tuner_i2c_xfer_recv(&priv->i2c_props,&byte,1))
return 0;
return byte;
}
-static int tuner_signal(struct i2c_client *c)
+static inline int tuner_signal(const int status)
{
- return (tuner_getstatus(c) & TUNER_SIGNAL) << 13;
+ return (status & TUNER_SIGNAL) << 13;
}
-static int tuner_stereo(struct i2c_client *c)
+static inline int tuner_stereo(const int type, const int status)
{
- int stereo, status;
- struct tuner *t = i2c_get_clientdata(c);
-
- status = tuner_getstatus (c);
-
- switch (t->type) {
+ switch (type) {
case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FM1256_IH3:
case TUNER_LG_NTSC_TAPE:
- stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
- break;
+ return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
default:
- stereo = status & TUNER_STEREO;
+ return status & TUNER_STEREO;
}
+}
+
+static inline int tuner_islocked(const int status)
+{
+ return (status & TUNER_FL);
+}
- return stereo;
+static inline int tuner_afcstatus(const int status)
+{
+ return (status & TUNER_AFC) - 2;
}
+static int simple_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ int tuner_status = tuner_read_status(fe);
+
+ *status = 0;
+
+ if (tuner_islocked(tuner_status))
+ *status = TUNER_STATUS_LOCKED;
+ if (tuner_stereo(priv->type, tuner_status))
+ *status |= TUNER_STATUS_STEREO;
+
+ tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status));
+
+ return 0;
+}
+
+static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ int signal = tuner_signal(tuner_read_status(fe));
+
+ *strength = signal;
+
+ tuner_dbg("Signal strength: %d\n", signal);
+
+ return 0;
+}
+
/* ---------------------------------------------------------------------- */
-static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
+static int simple_set_tv_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner_simple_priv *priv = fe->tuner_priv;
u8 config, cb, tuneraddr;
u16 div;
struct tunertype *tun;
u8 buffer[4];
int rc, IFPCoff, i, j;
enum param_type desired_type;
- struct tuner_params *params;
+ struct tuner_params *t_params;
- tun = &tuners[t->type];
+ tun = priv->tun;
/* IFPCoff = Video Intermediate Frequency - Vif:
940 =16*58.75 NTSC/J (Japan)
@@ -148,14 +199,14 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
171.2=16*10.70 FM Radio (at set_radio_freq)
*/
- if (t->std == V4L2_STD_NTSC_M_JP) {
+ if (params->std == V4L2_STD_NTSC_M_JP) {
IFPCoff = 940;
desired_type = TUNER_PARAM_TYPE_NTSC;
- } else if ((t->std & V4L2_STD_MN) &&
- !(t->std & ~V4L2_STD_MN)) {
+ } else if ((params->std & V4L2_STD_MN) &&
+ !(params->std & ~V4L2_STD_MN)) {
IFPCoff = 732;
desired_type = TUNER_PARAM_TYPE_NTSC;
- } else if (t->std == V4L2_STD_SECAM_LC) {
+ } else if (params->std == V4L2_STD_SECAM_LC) {
IFPCoff = 543;
desired_type = TUNER_PARAM_TYPE_SECAM;
} else {
@@ -168,49 +219,49 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
continue;
break;
}
- /* use default tuner_params if desired_type not available */
+ /* use default tuner_t_params if desired_type not available */
if (desired_type != tun->params[j].type) {
- tuner_dbg("IFPCoff = %d: tuner_params undefined for tuner %d\n",
- IFPCoff,t->type);
+ tuner_dbg("IFPCoff = %d: tuner_t_params undefined for tuner %d\n",
+ IFPCoff, priv->type);
j = 0;
}
- params = &tun->params[j];
+ t_params = &tun->params[j];
- for (i = 0; i < params->count; i++) {
- if (freq > params->ranges[i].limit)
+ for (i = 0; i < t_params->count; i++) {
+ if (params->frequency > t_params->ranges[i].limit)
continue;
break;
}
- if (i == params->count) {
+ if (i == t_params->count) {
tuner_dbg("TV frequency out of range (%d > %d)",
- freq, params->ranges[i - 1].limit);
- freq = params->ranges[--i].limit;
+ params->frequency, t_params->ranges[i - 1].limit);
+ params->frequency = t_params->ranges[--i].limit;
}
- config = params->ranges[i].config;
- cb = params->ranges[i].cb;
+ config = t_params->ranges[i].config;
+ cb = t_params->ranges[i].cb;
/* i == 0 -> VHF_LO
* i == 1 -> VHF_HI
* i == 2 -> UHF */
tuner_dbg("tv: param %d, range %d\n",j,i);
- div=freq + IFPCoff + offset;
+ div=params->frequency + IFPCoff + offset;
tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
- freq / 16, freq % 16 * 100 / 16,
+ params->frequency / 16, params->frequency % 16 * 100 / 16,
IFPCoff / 16, IFPCoff % 16 * 100 / 16,
offset / 16, offset % 16 * 100 / 16,
div);
/* tv norm specific stuff for multi-norm tuners */
- switch (t->type) {
+ switch (priv->type) {
case TUNER_PHILIPS_SECAM: // FI1216MF
/* 0x01 -> ??? no change ??? */
/* 0x02 -> PAL BDGHI / SECAM L */
/* 0x04 -> ??? PAL others / SECAM others ??? */
cb &= ~0x03;
- if (t->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM
+ if (params->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM
cb |= PHILIPS_MF_SET_STD_L;
- else if (t->std & V4L2_STD_SECAM_LC)
+ else if (params->std & V4L2_STD_SECAM_LC)
cb |= PHILIPS_MF_SET_STD_LC;
else /* V4L2_STD_B|V4L2_STD_GH */
cb |= PHILIPS_MF_SET_STD_BG;
@@ -219,16 +270,16 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
case TUNER_TEMIC_4046FM5:
cb &= ~0x0f;
- if (t->std & V4L2_STD_PAL_BG) {
+ if (params->std & V4L2_STD_PAL_BG) {
cb |= TEMIC_SET_PAL_BG;
- } else if (t->std & V4L2_STD_PAL_I) {
+ } else if (params->std & V4L2_STD_PAL_I) {
cb |= TEMIC_SET_PAL_I;
- } else if (t->std & V4L2_STD_PAL_DK) {
+ } else if (params->std & V4L2_STD_PAL_DK) {
cb |= TEMIC_SET_PAL_DK;
- } else if (t->std & V4L2_STD_SECAM_L) {
+ } else if (params->std & V4L2_STD_SECAM_L) {
cb |= TEMIC_SET_PAL_L;
}
@@ -237,13 +288,13 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
case TUNER_PHILIPS_FQ1216ME:
cb &= ~0x0f;
- if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
+ if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
cb |= PHILIPS_SET_PAL_BGDK;
- } else if (t->std & V4L2_STD_PAL_I) {
+ } else if (params->std & V4L2_STD_PAL_I) {
cb |= PHILIPS_SET_PAL_I;
- } else if (t->std & V4L2_STD_SECAM_L) {
+ } else if (params->std & V4L2_STD_SECAM_L) {
cb |= PHILIPS_SET_PAL_L;
}
@@ -255,7 +306,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
/* 0x02 -> NTSC antenna input 1 */
/* 0x03 -> NTSC antenna input 2 */
cb &= ~0x03;
- if (!(t->std & V4L2_STD_ATSC))
+ if (!(params->std & V4L2_STD_ATSC))
cb |= 2;
/* FIXME: input */
break;
@@ -275,23 +326,23 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
buffer[2] = 0x17;
buffer[3] = 0x00;
cb &= ~0x40;
- if (t->std & V4L2_STD_ATSC) {
+ if (params->std & V4L2_STD_ATSC) {
cb |= 0x40;
buffer[1] = 0x04;
}
/* set to the correct mode (analog or digital) */
- tuneraddr = c->addr;
- c->addr = 0x0a;
- if (2 != (rc = i2c_master_send(c,&buffer[0],2)))
+ tuneraddr = priv->i2c_props.addr;
+ priv->i2c_props.addr = 0x0a;
+ if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[0],2)))
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
- if (2 != (rc = i2c_master_send(c,&buffer[2],2)))
+ if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[2],2)))
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
- c->addr = tuneraddr;
+ priv->i2c_props.addr = tuneraddr;
/* FIXME: input */
break;
}
- if (params->cb_first_if_lower_freq && div < t->last_div) {
+ if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
buffer[0] = config;
buffer[1] = cb;
buffer[2] = (div>>8) & 0x7f;
@@ -302,53 +353,53 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
buffer[2] = config;
buffer[3] = cb;
}
- t->last_div = div;
- if (params->has_tda9887) {
+ priv->last_div = div;
+ if (t_params->has_tda9887) {
int config = 0;
- int is_secam_l = (t->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
- !(t->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
+ int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
+ !(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
- if (t->std == V4L2_STD_SECAM_LC) {
- if (params->port1_active ^ params->port1_invert_for_secam_lc)
+ if (params->std == V4L2_STD_SECAM_LC) {
+ if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
config |= TDA9887_PORT1_ACTIVE;
- if (params->port2_active ^ params->port2_invert_for_secam_lc)
+ if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
config |= TDA9887_PORT2_ACTIVE;
}
else {
- if (params->port1_active)
+ if (t_params->port1_active)
config |= TDA9887_PORT1_ACTIVE;
- if (params->port2_active)
+ if (t_params->port2_active)
config |= TDA9887_PORT2_ACTIVE;
}
- if (params->intercarrier_mode)
+ if (t_params->intercarrier_mode)
config |= TDA9887_INTERCARRIER;
if (is_secam_l) {
- if (i == 0 && params->default_top_secam_low)
- config |= TDA9887_TOP(params->default_top_secam_low);
- else if (i == 1 && params->default_top_secam_mid)
- config |= TDA9887_TOP(params->default_top_secam_mid);
- else if (params->default_top_secam_high)
- config |= TDA9887_TOP(params->default_top_secam_high);
+ if (i == 0 && t_params->default_top_secam_low)
+ config |= TDA9887_TOP(t_params->default_top_secam_low);
+ else if (i == 1 && t_params->default_top_secam_mid)
+ config |= TDA9887_TOP(t_params->default_top_secam_mid);
+ else if (t_params->default_top_secam_high)
+ config |= TDA9887_TOP(t_params->default_top_secam_high);
}
else {
- if (i == 0 && params->default_top_low)
- config |= TDA9887_TOP(params->default_top_low);
- else if (i == 1 && params->default_top_mid)
- config |= TDA9887_TOP(params->default_top_mid);
- else if (params->default_top_high)
- config |= TDA9887_TOP(params->default_top_high);
+ if (i == 0 && t_params->default_top_low)
+ config |= TDA9887_TOP(t_params->default_top_low);
+ else if (i == 1 && t_params->default_top_mid)
+ config |= TDA9887_TOP(t_params->default_top_mid);
+ else if (t_params->default_top_high)
+ config |= TDA9887_TOP(t_params->default_top_high);
}
- if (params->default_pll_gating_18)
+ if (t_params->default_pll_gating_18)
config |= TDA9887_GATING_18;
- i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config);
+ i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
}
tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3]);
- if (4 != (rc = i2c_master_send(c,buffer,4)))
+ if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
- switch (t->type) {
+ switch (priv->type) {
case TUNER_LG_TDVS_H06XF:
/* Set the Auxiliary Byte. */
buffer[0] = buffer[2];
@@ -357,7 +408,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
buffer[1] = 0x20;
tuner_dbg("tv 0x%02x 0x%02x\n",buffer[0],buffer[1]);
- if (2 != (rc = i2c_master_send(c,buffer,2)))
+ if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,2)))
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
break;
case TUNER_MICROTUNE_4042FI5:
@@ -369,8 +420,8 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
/* Wait until the PLL locks */
for (;;) {
if (time_after(jiffies,timeout))
- return;
- if (1 != (rc = i2c_master_recv(c,&status_byte,1))) {
+ return 0;
+ if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,&status_byte,1))) {
tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc);
break;
}
@@ -388,68 +439,86 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3]);
- if (4 != (rc = i2c_master_send(c,buffer,4)))
+ if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
break;
}
}
+ return 0;
}
-static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
+static int simple_set_radio_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
{
struct tunertype *tun;
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner_simple_priv *priv = fe->tuner_priv;
u8 buffer[4];
u16 div;
int rc, j;
- enum param_type desired_type = TUNER_PARAM_TYPE_RADIO;
- struct tuner_params *params;
+ struct tuner_params *t_params;
+ unsigned int freq = params->frequency;
- tun = &tuners[t->type];
+ tun = priv->tun;
- for (j = 0; j < tun->count-1; j++) {
- if (desired_type != tun->params[j].type)
- continue;
+ for (j = tun->count-1; j > 0; j--)
+ if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO)
+ break;
+ /* default t_params (j=0) will be used if desired type wasn't found */
+ t_params = &tun->params[j];
+
+ /* Select Radio 1st IF used */
+ switch (t_params->radio_if) {
+ case 0: /* 10.7 MHz */
+ freq += (unsigned int)(10.7*16000);
+ break;
+ case 1: /* 33.3 MHz */
+ freq += (unsigned int)(33.3*16000);
break;
+ case 2: /* 41.3 MHz */
+ freq += (unsigned int)(41.3*16000);
+ break;
+ default:
+ tuner_warn("Unsupported radio_if value %d\n", t_params->radio_if);
+ return 0;
}
- /* use default tuner_params if desired_type not available */
- if (desired_type != tun->params[j].type)
- j = 0;
-
- div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */
- params = &tun->params[j];
- buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */
- switch (t->type) {
+ /* Bandswitch byte */
+ switch (priv->type) {
case TUNER_TENA_9533_DI:
case TUNER_YMEC_TVF_5533MF:
- tuner_dbg ("This tuner doesn't have FM. Most cards has a TEA5767 for FM\n");
- return;
+ tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n");
+ return 0;
case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FMD1216ME_MK3:
case TUNER_LG_NTSC_TAPE:
+ case TUNER_PHILIPS_FM1256_IH3:
buffer[3] = 0x19;
break;
case TUNER_TNF_5335MF:
buffer[3] = 0x11;
break;
- case TUNER_PHILIPS_FM1256_IH3:
- div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */
- buffer[3] = 0x19;
- break;
case TUNER_LG_PAL_FM:
buffer[3] = 0xa5;
break;
- case TUNER_MICROTUNE_4049FM5:
- div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */
- buffer[3] = 0xa4;
+ case TUNER_THOMSON_DTT761X:
+ buffer[3] = 0x39;
break;
+ case TUNER_MICROTUNE_4049FM5:
default:
buffer[3] = 0xa4;
break;
}
- if (params->cb_first_if_lower_freq && div < t->last_div) {
+
+ buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
+ TUNER_RATIO_SELECT_50; /* 50 kHz step */
+
+ /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
+ freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
+ freq * (1/800) */
+ div = (freq + 400) / 800;
+
+ if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
buffer[0] = buffer[2];
buffer[1] = buffer[3];
buffer[2] = (div>>8) & 0x7f;
@@ -461,46 +530,108 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3]);
- t->last_div = div;
+ priv->last_div = div;
- if (params->has_tda9887) {
+ if (t_params->has_tda9887) {
int config = 0;
- if (params->port1_active && !params->port1_fm_high_sensitivity)
+ if (t_params->port1_active && !t_params->port1_fm_high_sensitivity)
config |= TDA9887_PORT1_ACTIVE;
- if (params->port2_active && !params->port2_fm_high_sensitivity)
+ if (t_params->port2_active && !t_params->port2_fm_high_sensitivity)
config |= TDA9887_PORT2_ACTIVE;
- if (params->intercarrier_mode)
+ if (t_params->intercarrier_mode)
config |= TDA9887_INTERCARRIER;
-/* if (params->port1_set_for_fm_mono)
+/* if (t_params->port1_set_for_fm_mono)
config &= ~TDA9887_PORT1_ACTIVE;*/
- if (params->fm_gain_normal)
+ if (t_params->fm_gain_normal)
config |= TDA9887_GAIN_NORMAL;
- i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config);
+ if (t_params->radio_if == 2)
+ config |= TDA9887_RIF_41_3;
+ i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
}
- if (4 != (rc = i2c_master_send(c,buffer,4)))
+ if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
+
+ return 0;
}
-static struct tuner_operations simple_tuner_ops = {
- .set_tv_freq = default_set_tv_freq,
- .set_radio_freq = default_set_radio_freq,
- .has_signal = tuner_signal,
- .is_stereo = tuner_stereo,
+static int simple_set_params(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ int ret = -EINVAL;
+
+ switch (params->mode) {
+ case V4L2_TUNER_RADIO:
+ ret = simple_set_radio_freq(fe, params);
+ priv->frequency = params->frequency * 125 / 2;
+ break;
+ case V4L2_TUNER_ANALOG_TV:
+ case V4L2_TUNER_DIGITAL_TV:
+ ret = simple_set_tv_freq(fe, params);
+ priv->frequency = params->frequency * 62500;
+ break;
+ }
+
+ return ret;
+}
+
+
+static int simple_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static struct dvb_tuner_ops simple_tuner_ops = {
+ .set_analog_params = simple_set_params,
+ .release = simple_release,
+ .get_frequency = simple_get_frequency,
+ .get_status = simple_get_status,
+ .get_rf_strength = simple_get_rf_strength,
};
-int default_tuner_init(struct i2c_client *c)
+struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c_adap,
+ u8 i2c_addr,
+ struct simple_tuner_config *cfg)
{
- struct tuner *t = i2c_get_clientdata(c);
+ struct tuner_simple_priv *priv = NULL;
- tuner_info("type set to %d (%s)\n",
- t->type, tuners[t->type].name);
- strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
+ priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+ fe->tuner_priv = priv;
- memcpy(&t->ops, &simple_tuner_ops, sizeof(struct tuner_operations));
+ priv->i2c_props.addr = i2c_addr;
+ priv->i2c_props.adap = i2c_adap;
+ priv->type = cfg->type;
+ priv->tun = cfg->tun;
- return 0;
+ memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+ tuner_info("type set to %d (%s)\n", cfg->type, cfg->tun->name);
+
+ strlcpy(fe->ops.tuner_ops.info.name, cfg->tun->name, sizeof(fe->ops.tuner_ops.info.name));
+
+ return fe;
}
+
+EXPORT_SYMBOL_GPL(simple_tuner_attach);
+
+MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/video/tuner-simple.h
new file mode 100644
index 00000000000..9089939a8c0
--- /dev/null
+++ b/drivers/media/video/tuner-simple.h
@@ -0,0 +1,46 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __TUNER_SIMPLE_H__
+#define __TUNER_SIMPLE_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct simple_tuner_config
+{
+ /* chip type */
+ unsigned int type;
+ struct tunertype *tun;
+};
+
+#if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE))
+extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c_adap,
+ u8 i2c_addr,
+ struct simple_tuner_config *cfg);
+#else
+static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c_adap,
+ u8 i2c_addr,
+ struct simple_tuner_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif
+
+#endif /* __TUNER_SIMPLE_H__ */
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 417f642b435..c6a7934bd5a 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -652,6 +652,7 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = {
.port1_invert_for_secam_lc = 1,
.default_pll_gating_18 = 1,
.fm_gain_normal=1,
+ .radio_if = 1, /* 33.3 MHz */
},
};
@@ -670,6 +671,9 @@ static struct tuner_params tuner_panasonic_vp27_params[] = {
.count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges),
.has_tda9887 = 1,
.intercarrier_mode = 1,
+ .default_top_low = -3,
+ .default_top_mid = -3,
+ .default_top_high = -3,
},
};
@@ -730,6 +734,7 @@ static struct tuner_params tuner_philips_fm1256_ih3_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_fm1236_mk3_ntsc_ranges,
.count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
+ .radio_if = 1, /* 33.3 MHz */
},
};
@@ -856,6 +861,9 @@ static struct tuner_params tuner_thomson_dtt761x_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_thomson_dtt761x_ntsc_ranges,
.count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges),
+ .has_tda9887 = 1,
+ .fm_gain_normal = 1,
+ .radio_if = 2, /* 41.3 MHz */
},
};
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index cffb011590e..a19cdcc17ef 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -15,7 +15,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index fdc3def437b..4b2c4034f5b 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -30,7 +30,6 @@
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index 3ae5a9cd2e2..9fa5b702e07 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -2,7 +2,6 @@
*/
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
@@ -238,13 +237,10 @@ static const struct file_operations tvmixer_fops = {
static int tvmixer_adapters(struct i2c_adapter *adap)
{
- struct list_head *item;
struct i2c_client *client;
- list_for_each(item,&adap->clients) {
- client = list_entry(item, struct i2c_client, list);
+ list_for_each_entry(client, &adap->clients, list)
tvmixer_clients(client);
- }
return 0;
}
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index e2f1c972754..25d0aef88ef 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -799,10 +799,10 @@ static inline void tvp5150_reset(struct i2c_client *c)
tvp5150_write_inittab(c, tvp5150_init_enable);
/* Initialize image preferences */
- tvp5150_write(c, TVP5150_BRIGHT_CTL, decoder->bright >> 8);
- tvp5150_write(c, TVP5150_CONTRAST_CTL, decoder->contrast >> 8);
- tvp5150_write(c, TVP5150_SATURATION_CTL, decoder->contrast >> 8);
- tvp5150_write(c, TVP5150_HUE_CTL, (decoder->hue - 32768) >> 8);
+ tvp5150_write(c, TVP5150_BRIGHT_CTL, decoder->bright);
+ tvp5150_write(c, TVP5150_CONTRAST_CTL, decoder->contrast);
+ tvp5150_write(c, TVP5150_SATURATION_CTL, decoder->contrast);
+ tvp5150_write(c, TVP5150_HUE_CTL, decoder->hue);
tvp5150_set_std(c, decoder->norm);
};
@@ -1077,10 +1077,10 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
core->norm = V4L2_STD_ALL; /* Default is autodetect */
core->route.input = TVP5150_COMPOSITE1;
core->enable = 1;
- core->bright = 32768;
- core->contrast = 32768;
- core->hue = 32768;
- core->sat = 32768;
+ core->bright = 128;
+ core->contrast = 128;
+ core->hue = 0;
+ core->sat = 128;
if (rv) {
kfree(c);
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index 491505d6fde..3e93f805877 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -238,8 +238,8 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev
usb_to_input_id(dev, &input_dev->id);
input_dev->dev.parent = &dev->dev;
- input_dev->evbit[0] = BIT(EV_KEY);
- input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY);
+ input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
input_dev->private = cam;
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index dd1a6d6bbc9..d847273eeba 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -102,8 +102,8 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
usb_to_input_id(dev, &input_dev->id);
input_dev->dev.parent = &dev->dev;
- input_dev->evbit[0] = BIT(EV_KEY);
- input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY);
+ input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
input_dev->private = cam;
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
index 37ce36b9e58..fb434b5602a 100644
--- a/drivers/media/video/usbvideo/usbvideo.c
+++ b/drivers/media/video/usbvideo/usbvideo.c
@@ -952,7 +952,6 @@ static const struct file_operations usbvideo_fops = {
static const struct video_device usbvideo_template = {
.owner = THIS_MODULE,
.type = VID_TYPE_CAPTURE,
- .hardware = VID_HARDWARE_CPIA,
.fops = &usbvideo_fops,
};
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index ff555129c82..da1ba021110 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -955,7 +955,7 @@ read_frame(struct vicam_camera *cam, int framenum)
request[7] = realShutter >> 8;
}
- // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
+ // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
request[8] = 0;
// bytes 9-15 do not seem to affect exposure or image quality
@@ -1074,7 +1074,6 @@ static struct video_device vicam_template = {
.owner = THIS_MODULE,
.name = "ViCam-based USB Camera",
.type = VID_TYPE_CAPTURE,
- .hardware = VID_HARDWARE_VICAM,
.fops = &vicam_fops,
.minor = -1,
};
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index 5b1e346df20..c7d5f9ed22d 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -45,7 +45,6 @@
#include <media/tuner.h>
#include <media/audiochip.h>
-#include <linux/moduleparam.h>
#include <linux/workqueue.h>
#ifdef CONFIG_KMOD
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index 025be555194..aabc42cae9c 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -134,8 +134,6 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap,
addr = (msg->addr << 1);
if (flags & I2C_M_RD)
addr |= 1;
- if (flags & I2C_M_REV_DIR_ADDR)
- addr ^= 1;
add[0] = addr;
if (flags & I2C_M_RD)
@@ -185,14 +183,9 @@ usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
return num;
}
-static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
static u32 functionality(struct i2c_adapter *adap)
{
- return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
}
@@ -201,7 +194,6 @@ static u32 functionality(struct i2c_adapter *adap)
static struct i2c_algorithm usbvision_algo = {
.master_xfer = usbvision_i2c_xfer,
.smbus_xfer = NULL,
- .algo_control = algo_control,
.functionality = functionality,
};
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 0cb006f2943..36e689fa16c 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -68,7 +68,6 @@
#include <media/tuner.h>
#include <media/audiochip.h>
-#include <linux/moduleparam.h>
#include <linux/workqueue.h>
#ifdef CONFIG_KMOD
@@ -183,20 +182,22 @@ MODULE_ALIAS(DRIVER_ALIAS);
#define YES_NO(x) ((x) ? "Yes" : "No")
-static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd)
+static inline struct usb_usbvision *cd_to_usbvision(struct device *cd)
{
struct video_device *vdev =
container_of(cd, struct video_device, class_dev);
return video_get_drvdata(vdev);
}
-static ssize_t show_version(struct class_device *cd, char *buf)
+static ssize_t show_version(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%s\n", USBVISION_VERSION_STRING);
}
-static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
-static ssize_t show_model(struct class_device *cd, char *buf)
+static ssize_t show_model(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vdev =
container_of(cd, struct video_device, class_dev);
@@ -204,9 +205,10 @@ static ssize_t show_model(struct class_device *cd, char *buf)
return sprintf(buf, "%s\n",
usbvision_device_data[usbvision->DevModel].ModelString);
}
-static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
-static ssize_t show_hue(struct class_device *cd, char *buf)
+static ssize_t show_hue(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vdev =
container_of(cd, struct video_device, class_dev);
@@ -218,9 +220,10 @@ static ssize_t show_hue(struct class_device *cd, char *buf)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
-static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
+static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
-static ssize_t show_contrast(struct class_device *cd, char *buf)
+static ssize_t show_contrast(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vdev =
container_of(cd, struct video_device, class_dev);
@@ -232,9 +235,10 @@ static ssize_t show_contrast(struct class_device *cd, char *buf)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
-static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
+static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
-static ssize_t show_brightness(struct class_device *cd, char *buf)
+static ssize_t show_brightness(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vdev =
container_of(cd, struct video_device, class_dev);
@@ -246,9 +250,10 @@ static ssize_t show_brightness(struct class_device *cd, char *buf)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
-static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
+static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
-static ssize_t show_saturation(struct class_device *cd, char *buf)
+static ssize_t show_saturation(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vdev =
container_of(cd, struct video_device, class_dev);
@@ -260,9 +265,10 @@ static ssize_t show_saturation(struct class_device *cd, char *buf)
call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
-static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
+static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
-static ssize_t show_streaming(struct class_device *cd, char *buf)
+static ssize_t show_streaming(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vdev =
container_of(cd, struct video_device, class_dev);
@@ -270,9 +276,10 @@ static ssize_t show_streaming(struct class_device *cd, char *buf)
return sprintf(buf, "%s\n",
YES_NO(usbvision->streaming==Stream_On?1:0));
}
-static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
+static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
-static ssize_t show_compression(struct class_device *cd, char *buf)
+static ssize_t show_compression(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vdev =
container_of(cd, struct video_device, class_dev);
@@ -280,16 +287,17 @@ static ssize_t show_compression(struct class_device *cd, char *buf)
return sprintf(buf, "%s\n",
YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
}
-static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
+static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
-static ssize_t show_device_bridge(struct class_device *cd, char *buf)
+static ssize_t show_device_bridge(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vdev =
container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%d\n", usbvision->bridgeType);
}
-static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);
+static DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);
static void usbvision_create_sysfs(struct video_device *vdev)
{
@@ -297,40 +305,40 @@ static void usbvision_create_sysfs(struct video_device *vdev)
if (!vdev)
return;
do {
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_version);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_version);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_model);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_model);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_hue);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_hue);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_contrast);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_contrast);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_brightness);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_brightness);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_saturation);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_saturation);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_streaming);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_streaming);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_compression);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_compression);
if (res<0)
break;
- res=class_device_create_file(&vdev->class_dev,
- &class_device_attr_bridge);
+ res = device_create_file(&vdev->class_dev,
+ &dev_attr_bridge);
if (res>=0)
return;
} while (0);
@@ -341,24 +349,24 @@ static void usbvision_create_sysfs(struct video_device *vdev)
static void usbvision_remove_sysfs(struct video_device *vdev)
{
if (vdev) {
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_version);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_model);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_hue);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_contrast);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_brightness);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_saturation);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_streaming);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_compression);
- class_device_remove_file(&vdev->class_dev,
- &class_device_attr_bridge);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_version);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_model);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_hue);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_contrast);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_brightness);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_saturation);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_streaming);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_compression);
+ device_remove_file(&vdev->class_dev,
+ &dev_attr_bridge);
}
}
@@ -1392,7 +1400,6 @@ static const struct file_operations usbvision_fops = {
static struct video_device usbvision_video_template = {
.owner = THIS_MODULE,
.type = VID_TYPE_TUNER | VID_TYPE_CAPTURE,
- .hardware = VID_HARDWARE_USBVISION,
.fops = &usbvision_fops,
.name = "usbvision-video",
.release = video_device_release,
@@ -1447,7 +1454,6 @@ static struct video_device usbvision_radio_template=
{
.owner = THIS_MODULE,
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_USBVISION,
.fops = &usbvision_radio_fops,
.name = "usbvision-radio",
.release = video_device_release,
@@ -1484,7 +1490,6 @@ static struct video_device usbvision_vbi_template=
{
.owner = THIS_MODULE,
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_USBVISION,
.fops = &usbvision_vbi_fops,
.release = video_device_release,
.name = "usbvision-vbi",
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index ede8543818b..dcf22a3b672 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -19,7 +19,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -145,7 +144,7 @@ const static unsigned int palette2pixelformat[] = {
[VIDEO_PALETTE_YUV422P] = V4L2_PIX_FMT_YUV422P,
};
-static unsigned int __attribute_pure__
+static unsigned int __pure
palette_to_pixelformat(unsigned int palette)
{
if (palette < ARRAY_SIZE(palette2pixelformat))
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index d2915d3530e..1141b4bf41c 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -37,7 +37,7 @@
* Video4linux 1/2 integration by Justin Schoeman
* <justin@suntiger.ee.up.ac.za>
* 2.4 PROCFS support ported from 2.4 kernels by
- * Iñaki García Etxebarria <garetxe@euskalnet.net>
+ * Iñaki García Etxebarria <garetxe@euskalnet.net>
* Makefile fix by "W. Michael Petullo" <mike@flyn.org>
* 2.4 devfs support ported from 2.4 kernels by
* Dan Merillat <dan@merillat.org>
@@ -65,11 +65,6 @@
#include <linux/kmod.h>
#endif
-#if defined(CONFIG_UST) || defined(CONFIG_UST_MODULE)
-#include <linux/ust.h>
-#endif
-
-
#include <linux/videodev.h>
MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr");
@@ -322,8 +317,6 @@ static const char *v4l2_ioctls[] = {
[_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT",
[_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT",
[_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT",
- [_IOC_NR(VIDIOC_G_MPEGCOMP)] = "VIDIOC_G_MPEGCOMP",
- [_IOC_NR(VIDIOC_S_MPEGCOMP)] = "VIDIOC_S_MPEGCOMP",
[_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS",
[_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF",
[_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF",
@@ -716,6 +709,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_AUDIO_MUTE:
case V4L2_CID_AUDIO_LOUDNESS:
case V4L2_CID_MPEG_AUDIO_MUTE:
+ case V4L2_CID_MPEG_VIDEO_MUTE:
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
case V4L2_CID_MPEG_VIDEO_PULLDOWN:
qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c
new file mode 100644
index 00000000000..8b4ef530a3a
--- /dev/null
+++ b/drivers/media/video/v4l2-int-device.c
@@ -0,0 +1,158 @@
+/*
+ * drivers/media/video/v4l2-int-device.c
+ *
+ * V4L2 internal ioctl interface.
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/sort.h>
+#include <linux/string.h>
+
+#include <media/v4l2-int-device.h>
+
+static DEFINE_MUTEX(mutex);
+static LIST_HEAD(int_list);
+
+static void v4l2_int_device_try_attach_all(void)
+{
+ struct v4l2_int_device *m, *s;
+
+ list_for_each_entry(m, &int_list, head) {
+ if (m->type != v4l2_int_type_master)
+ continue;
+
+ list_for_each_entry(s, &int_list, head) {
+ if (s->type != v4l2_int_type_slave)
+ continue;
+
+ /* Slave is connected? */
+ if (s->u.slave->master)
+ continue;
+
+ /* Slave wants to attach to master? */
+ if (s->u.slave->attach_to[0] != 0
+ && strncmp(m->name, s->u.slave->attach_to,
+ V4L2NAMESIZE))
+ continue;
+
+ if (!try_module_get(m->module))
+ continue;
+
+ if (m->u.master->attach(m, s)) {
+ module_put(m->module);
+ continue;
+ }
+
+ s->u.slave->master = m;
+ }
+ }
+}
+
+static int ioctl_sort_cmp(const void *a, const void *b)
+{
+ const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b;
+
+ if (d1->num > d2->num)
+ return 1;
+
+ if (d1->num < d2->num)
+ return -1;
+
+ return 0;
+}
+
+int v4l2_int_device_register(struct v4l2_int_device *d)
+{
+ if (d->type == v4l2_int_type_slave)
+ sort(d->u.slave->ioctls, d->u.slave->num_ioctls,
+ sizeof(struct v4l2_int_ioctl_desc),
+ &ioctl_sort_cmp, NULL);
+ mutex_lock(&mutex);
+ list_add(&d->head, &int_list);
+ v4l2_int_device_try_attach_all();
+ mutex_unlock(&mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_int_device_register);
+
+void v4l2_int_device_unregister(struct v4l2_int_device *d)
+{
+ mutex_lock(&mutex);
+ list_del(&d->head);
+ if (d->type == v4l2_int_type_slave
+ && d->u.slave->master != NULL) {
+ d->u.slave->master->u.master->detach(d);
+ module_put(d->u.slave->master->module);
+ d->u.slave->master = NULL;
+ }
+ mutex_unlock(&mutex);
+}
+EXPORT_SYMBOL_GPL(v4l2_int_device_unregister);
+
+/* Adapted from search_extable in extable.c. */
+static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd,
+ v4l2_int_ioctl_func *no_such_ioctl)
+{
+ const struct v4l2_int_ioctl_desc *first = slave->ioctls;
+ const struct v4l2_int_ioctl_desc *last =
+ first + slave->num_ioctls - 1;
+
+ while (first <= last) {
+ const struct v4l2_int_ioctl_desc *mid;
+
+ mid = (last - first) / 2 + first;
+
+ if (mid->num < cmd)
+ first = mid + 1;
+ else if (mid->num > cmd)
+ last = mid - 1;
+ else
+ return mid->func;
+ }
+
+ return no_such_ioctl;
+}
+
+static int no_such_ioctl_0(struct v4l2_int_device *d)
+{
+ return -ENOIOCTLCMD;
+}
+
+int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd)
+{
+ return ((v4l2_int_ioctl_func_0 *)
+ find_ioctl(d->u.slave, cmd,
+ (v4l2_int_ioctl_func *)no_such_ioctl_0))(d);
+}
+
+static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg)
+{
+ return ((v4l2_int_ioctl_func_1 *)
+ find_ioctl(d->u.slave, cmd,
+ (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg);
+}
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/videobuf-core.c
index a32dfbe0585..89a44f16f0b 100644
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/videobuf-core.c
@@ -1,313 +1,63 @@
/*
+ * generic helper functions for handling video4linux capture buffers
*
- * generic helper functions for video4linux capture buffers, to handle
- * memory management and PCI DMA.
- * Right now, bttv, saa7134, saa7146 and cx88 use it.
+ * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
*
- * The functions expect the hardware being able to scatter gatter
- * (i.e. the buffers are not linear in physical memory, but fragmented
- * into PAGE_SIZE chunks). They also assume the driver does not need
- * to touch the video data.
- *
- * device specific map/unmap/sync stuff now are mapped as operations
- * to allow its usage by USB and virtual devices.
- *
- * (c) 2001-2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
- * (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * Highly based on video-buf written originally by:
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2006 Mauro Carvalho Chehab, <mchehab@infradead.org>
* (c) 2006 Ted Walther and John Sokol
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation; either version 2
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/vmalloc.h>
-#include <linux/pagemap.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <media/video-buf.h>
+#include <media/videobuf-core.h>
-#define MAGIC_DMABUF 0x19721112
-#define MAGIC_BUFFER 0x20040302
+#define MAGIC_BUFFER 0x20070728
#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \
{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
static int debug = 0;
module_param(debug, int, 0644);
-MODULE_DESCRIPTION("helper module to manage video4linux pci dma buffers");
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_DESCRIPTION("helper module to manage video4linux buffers");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_LICENSE("GPL");
#define dprintk(level, fmt, arg...) if (debug >= level) \
printk(KERN_DEBUG "vbuf: " fmt , ## arg)
-struct scatterlist*
-videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
-{
- struct scatterlist *sglist;
- struct page *pg;
- int i;
-
- sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
- if (NULL == sglist)
- return NULL;
- for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
- pg = vmalloc_to_page(virt);
- if (NULL == pg)
- goto err;
- BUG_ON(PageHighMem(pg));
- sglist[i].page = pg;
- sglist[i].length = PAGE_SIZE;
- }
- return sglist;
-
- err:
- kfree(sglist);
- return NULL;
-}
-
-struct scatterlist*
-videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
-{
- struct scatterlist *sglist;
- int i = 0;
-
- if (NULL == pages[0])
- return NULL;
- sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL);
- if (NULL == sglist)
- return NULL;
-
- if (NULL == pages[0])
- goto nopage;
- if (PageHighMem(pages[0]))
- /* DMA to highmem pages might not work */
- goto highmem;
- sglist[0].page = pages[0];
- sglist[0].offset = offset;
- sglist[0].length = PAGE_SIZE - offset;
- for (i = 1; i < nr_pages; i++) {
- if (NULL == pages[i])
- goto nopage;
- if (PageHighMem(pages[i]))
- goto highmem;
- sglist[i].page = pages[i];
- sglist[i].length = PAGE_SIZE;
- }
- return sglist;
-
- nopage:
- dprintk(2,"sgl: oops - no page\n");
- kfree(sglist);
- return NULL;
-
- highmem:
- dprintk(2,"sgl: oops - highmem page\n");
- kfree(sglist);
- return NULL;
-}
-
/* --------------------------------------------------------------------- */
-void videobuf_dma_init(struct videobuf_dmabuf *dma)
-{
- memset(dma,0,sizeof(*dma));
- dma->magic = MAGIC_DMABUF;
-}
+#define CALL(q, f, arg...) \
+ ( (q->int_ops->f)? q->int_ops->f(arg) : 0)
-int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
- unsigned long data, unsigned long size)
+void* videobuf_alloc(struct videobuf_queue* q)
{
- unsigned long first,last;
- int err, rw = 0;
-
- dma->direction = direction;
- switch (dma->direction) {
- case PCI_DMA_FROMDEVICE: rw = READ; break;
- case PCI_DMA_TODEVICE: rw = WRITE; break;
- default: BUG();
- }
-
- first = (data & PAGE_MASK) >> PAGE_SHIFT;
- last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
- dma->offset = data & ~PAGE_MASK;
- dma->nr_pages = last-first+1;
- dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*),
- GFP_KERNEL);
- if (NULL == dma->pages)
- return -ENOMEM;
- dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
- data,size,dma->nr_pages);
-
- dma->varea = (void *) data;
-
- down_read(&current->mm->mmap_sem);
- err = get_user_pages(current,current->mm,
- data & PAGE_MASK, dma->nr_pages,
- rw == READ, 1, /* force */
- dma->pages, NULL);
- up_read(&current->mm->mmap_sem);
- if (err != dma->nr_pages) {
- dma->nr_pages = (err >= 0) ? err : 0;
- dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages);
- return err < 0 ? err : -EINVAL;
- }
- return 0;
-}
-
-int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
- int nr_pages)
-{
- dprintk(1,"init kernel [%d pages]\n",nr_pages);
- dma->direction = direction;
- dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
- if (NULL == dma->vmalloc) {
- dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages);
- return -ENOMEM;
- }
- dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
- (unsigned long)dma->vmalloc,
- nr_pages << PAGE_SHIFT);
- memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT);
- dma->nr_pages = nr_pages;
- return 0;
-}
-
-int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
- dma_addr_t addr, int nr_pages)
-{
- dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n",
- nr_pages,(unsigned long)addr);
- dma->direction = direction;
- if (0 == addr)
- return -EINVAL;
-
- dma->bus_addr = addr;
- dma->nr_pages = nr_pages;
- return 0;
-}
-
-int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
-{
- void *dev=q->dev;
-
- MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
- BUG_ON(0 == dma->nr_pages);
-
- if (dma->pages) {
- dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
- dma->offset);
- }
- if (dma->vmalloc) {
- dma->sglist = videobuf_vmalloc_to_sg
- (dma->vmalloc,dma->nr_pages);
- }
- if (dma->bus_addr) {
- dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL);
- if (NULL != dma->sglist) {
- dma->sglen = 1;
- sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK;
- dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK;
- sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE;
- }
- }
- if (NULL == dma->sglist) {
- dprintk(1,"scatterlist is NULL\n");
- return -ENOMEM;
- }
- if (!dma->bus_addr) {
- if (q->ops->vb_map_sg) {
- dma->sglen = q->ops->vb_map_sg(dev,dma->sglist,
- dma->nr_pages, dma->direction);
- }
- if (0 == dma->sglen) {
- printk(KERN_WARNING
- "%s: videobuf_map_sg failed\n",__FUNCTION__);
- kfree(dma->sglist);
- dma->sglist = NULL;
- dma->sglen = 0;
- return -EIO;
- }
- }
- return 0;
-}
-
-int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
-{
- void *dev=q->dev;
-
- MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
- BUG_ON(!dma->sglen);
-
- if (!dma->bus_addr && q->ops->vb_dma_sync_sg)
- q->ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages,
- dma->direction);
-
- return 0;
-}
-
-int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
-{
- void *dev=q->dev;
-
- MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
- if (!dma->sglen)
- return 0;
-
- if (!dma->bus_addr && q->ops->vb_unmap_sg)
- q->ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages,
- dma->direction);
- kfree(dma->sglist);
- dma->sglist = NULL;
- dma->sglen = 0;
- return 0;
-}
-
-int videobuf_dma_free(struct videobuf_dmabuf *dma)
-{
- MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
- BUG_ON(dma->sglen);
-
- if (dma->pages) {
- int i;
- for (i=0; i < dma->nr_pages; i++)
- page_cache_release(dma->pages[i]);
- kfree(dma->pages);
- dma->pages = NULL;
- }
+ struct videobuf_buffer *vb;
- vfree(dma->vmalloc);
- dma->vmalloc = NULL;
- dma->varea = NULL;
+ BUG_ON (q->msize<sizeof(*vb));
- if (dma->bus_addr) {
- dma->bus_addr = 0;
+ if (!q->int_ops || !q->int_ops->alloc) {
+ printk(KERN_ERR "No specific ops defined!\n");
+ BUG();
}
- dma->direction = PCI_DMA_NONE;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-void* videobuf_alloc(unsigned int size)
-{
- struct videobuf_buffer *vb;
+ vb = q->int_ops->alloc(q->msize);
- vb = kzalloc(size,GFP_KERNEL);
if (NULL != vb) {
- videobuf_dma_init(&vb->dma);
init_waitqueue_head(&vb->done);
vb->magic = MAGIC_BUFFER;
}
+
return vb;
}
@@ -338,127 +88,65 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
return retval;
}
-int
-videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
- struct v4l2_framebuffer *fbuf)
+int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
+ struct v4l2_framebuffer *fbuf)
{
- int err,pages;
- dma_addr_t bus;
-
MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
- switch (vb->memory) {
- case V4L2_MEMORY_MMAP:
- case V4L2_MEMORY_USERPTR:
- if (0 == vb->baddr) {
- /* no userspace addr -- kernel bounce buffer */
- pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
- err = videobuf_dma_init_kernel(&vb->dma,PCI_DMA_FROMDEVICE,
- pages);
- if (0 != err)
- return err;
- } else {
- /* dma directly to userspace */
- err = videobuf_dma_init_user(&vb->dma,PCI_DMA_FROMDEVICE,
- vb->baddr,vb->bsize);
- if (0 != err)
- return err;
- }
- break;
- case V4L2_MEMORY_OVERLAY:
- if (NULL == fbuf)
- return -EINVAL;
- /* FIXME: need sanity checks for vb->boff */
- /*
- * Using a double cast to avoid compiler warnings when
- * building for PAE. Compiler doesn't like direct casting
- * of a 32 bit ptr to 64 bit integer.
- */
- bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff;
- pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
- err = videobuf_dma_init_overlay(&vb->dma,PCI_DMA_FROMDEVICE,
- bus, pages);
- if (0 != err)
- return err;
- break;
- default:
- BUG();
- }
- err = videobuf_dma_map(q,&vb->dma);
- if (0 != err)
- return err;
-
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
-void videobuf_queue_pci(struct videobuf_queue* q)
-{
- /* If not specified, defaults to PCI map sg */
- if (!q->ops->vb_map_sg)
- q->ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg;
-
- if (!q->ops->vb_dma_sync_sg)
- q->ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu;
- if (!q->ops->vb_unmap_sg)
- q->ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
-}
-
-int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma)
-{
- struct videobuf_queue q;
- struct videobuf_queue_ops qops;
+ /* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper()
+ method should be called before _iolock.
+ On some cases, the mmap_mapper() is called only after scheduling.
- q.dev=pci;
- qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg;
- qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
- q.ops = &qops;
+ However, this way is just too dirty! Better to wait for some event.
+ */
+ schedule_timeout(HZ);
- return (videobuf_dma_map(&q,dma));
+ return CALL(q,iolock,q,vb,fbuf);
}
-int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma)
-{
- struct videobuf_queue q;
- struct videobuf_queue_ops qops;
-
- q.dev=pci;
- qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg;
- qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
- q.ops = &qops;
+/* --------------------------------------------------------------------- */
- return (videobuf_dma_unmap(&q,dma));
-}
-void videobuf_queue_init(struct videobuf_queue* q,
+void videobuf_queue_core_init(struct videobuf_queue* q,
struct videobuf_queue_ops *ops,
void *dev,
spinlock_t *irqlock,
enum v4l2_buf_type type,
enum v4l2_field field,
unsigned int msize,
- void *priv)
+ void *priv,
+ struct videobuf_qtype_ops *int_ops)
{
memset(q,0,sizeof(*q));
- q->irqlock = irqlock;
- q->dev = dev;
- q->type = type;
- q->field = field;
- q->msize = msize;
- q->ops = ops;
+ q->irqlock = irqlock;
+ q->dev = dev;
+ q->type = type;
+ q->field = field;
+ q->msize = msize;
+ q->ops = ops;
q->priv_data = priv;
+ q->int_ops = int_ops;
- videobuf_queue_pci(q);
+ /* All buffer operations are mandatory */
+ BUG_ON (!q->ops->buf_setup);
+ BUG_ON (!q->ops->buf_prepare);
+ BUG_ON (!q->ops->buf_queue);
+ BUG_ON (!q->ops->buf_release);
+
+ /* Having implementations for abstract methods are mandatory */
+ BUG_ON (!q->int_ops);
mutex_init(&q->lock);
INIT_LIST_HEAD(&q->stream);
}
-int
-videobuf_queue_is_busy(struct videobuf_queue *q)
+int videobuf_queue_is_busy(struct videobuf_queue *q)
{
int i;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
if (q->streaming) {
dprintk(1,"busy: streaming active\n");
return 1;
@@ -490,8 +178,7 @@ videobuf_queue_is_busy(struct videobuf_queue *q)
return 0;
}
-void
-videobuf_queue_cancel(struct videobuf_queue *q)
+void videobuf_queue_cancel(struct videobuf_queue *q)
{
unsigned long flags=0;
int i;
@@ -521,8 +208,7 @@ videobuf_queue_cancel(struct videobuf_queue *q)
/* --------------------------------------------------------------------- */
-enum v4l2_field
-videobuf_next_field(struct videobuf_queue *q)
+enum v4l2_field videobuf_next_field(struct videobuf_queue *q)
{
enum v4l2_field field = q->field;
@@ -540,11 +226,11 @@ videobuf_next_field(struct videobuf_queue *q)
return field;
}
-void
-videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb,
- enum v4l2_buf_type type)
+static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
+ struct videobuf_buffer *vb, enum v4l2_buf_type type)
{
MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
b->index = vb->i;
b->type = type;
@@ -595,8 +281,7 @@ videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb,
b->sequence = vb->field_count >> 1;
}
-int
-videobuf_reqbufs(struct videobuf_queue *q,
+int videobuf_reqbufs(struct videobuf_queue *q,
struct v4l2_requestbuffers *req)
{
unsigned int size,count;
@@ -617,16 +302,18 @@ videobuf_reqbufs(struct videobuf_queue *q,
return -EINVAL;
}
+ mutex_lock(&q->lock);
if (q->streaming) {
dprintk(1,"reqbufs: streaming already exists\n");
- return -EBUSY;
+ retval = -EBUSY;
+ goto done;
}
if (!list_empty(&q->stream)) {
dprintk(1,"reqbufs: stream running\n");
- return -EBUSY;
+ retval = -EBUSY;
+ goto done;
}
- mutex_lock(&q->lock);
count = req->count;
if (count > VIDEO_MAX_FRAME)
count = VIDEO_MAX_FRAME;
@@ -642,15 +329,14 @@ videobuf_reqbufs(struct videobuf_queue *q,
goto done;
}
- req->count = count;
+ req->count = retval;
done:
mutex_unlock(&q->lock);
return retval;
}
-int
-videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
+int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
{
if (unlikely(b->type != q->type)) {
dprintk(1,"querybuf: Wrong type.\n");
@@ -664,12 +350,11 @@ videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
dprintk(1,"querybuf: buffer is null.\n");
return -EINVAL;
}
- videobuf_status(b,q->bufs[b->index],q->type);
+ videobuf_status(q,b,q->bufs[b->index],q->type);
return 0;
}
-int
-videobuf_qbuf(struct videobuf_queue *q,
+int videobuf_qbuf(struct videobuf_queue *q,
struct v4l2_buffer *b)
{
struct videobuf_buffer *buf;
@@ -677,6 +362,11 @@ videobuf_qbuf(struct videobuf_queue *q,
unsigned long flags=0;
int retval;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+ if (b->memory == V4L2_MEMORY_MMAP)
+ down_read(&current->mm->mmap_sem);
+
mutex_lock(&q->lock);
retval = -EBUSY;
if (q->reading) {
@@ -762,16 +452,21 @@ videobuf_qbuf(struct videobuf_queue *q,
done:
mutex_unlock(&q->lock);
+
+ if (b->memory == V4L2_MEMORY_MMAP)
+ up_read(&current->mm->mmap_sem);
+
return retval;
}
-int
-videobuf_dqbuf(struct videobuf_queue *q,
+int videobuf_dqbuf(struct videobuf_queue *q,
struct v4l2_buffer *b, int nonblocking)
{
struct videobuf_buffer *buf;
int retval;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
mutex_lock(&q->lock);
retval = -EBUSY;
if (q->reading) {
@@ -797,12 +492,12 @@ videobuf_dqbuf(struct videobuf_queue *q,
case STATE_ERROR:
dprintk(1,"dqbuf: state is error\n");
retval = -EIO;
- videobuf_dma_sync(q,&buf->dma);
+ CALL(q,sync,q, buf);
buf->state = STATE_IDLE;
break;
case STATE_DONE:
dprintk(1,"dqbuf: state is done\n");
- videobuf_dma_sync(q,&buf->dma);
+ CALL(q,sync,q, buf);
buf->state = STATE_IDLE;
break;
default:
@@ -812,7 +507,7 @@ videobuf_dqbuf(struct videobuf_queue *q,
}
list_del(&buf->stream);
memset(b,0,sizeof(*b));
- videobuf_status(b,buf,q->type);
+ videobuf_status(q,b,buf,q->type);
done:
mutex_unlock(&q->lock);
@@ -822,7 +517,6 @@ videobuf_dqbuf(struct videobuf_queue *q,
int videobuf_streamon(struct videobuf_queue *q)
{
struct videobuf_buffer *buf;
- struct list_head *list;
unsigned long flags=0;
int retval;
@@ -836,11 +530,9 @@ int videobuf_streamon(struct videobuf_queue *q)
q->streaming = 1;
if (q->irqlock)
spin_lock_irqsave(q->irqlock,flags);
- list_for_each(list,&q->stream) {
- buf = list_entry(list, struct videobuf_buffer, stream);
+ list_for_each_entry(buf, &q->stream, stream)
if (buf->state == STATE_PREPARED)
q->ops->buf_queue(q,buf);
- }
if (q->irqlock)
spin_unlock_irqrestore(q->irqlock,flags);
@@ -865,22 +557,25 @@ int videobuf_streamoff(struct videobuf_queue *q)
return retval;
}
-static ssize_t
-videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
- size_t count, loff_t *ppos)
+static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
+ char __user *data,
+ size_t count, loff_t *ppos)
{
enum v4l2_field field;
unsigned long flags=0;
int retval;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
/* setup stuff */
- q->read_buf = videobuf_alloc(q->msize);
+ q->read_buf = videobuf_alloc(q);
if (NULL == q->read_buf)
return -ENOMEM;
q->read_buf->memory = V4L2_MEMORY_USERPTR;
q->read_buf->baddr = (unsigned long)data;
q->read_buf->bsize = count;
+
field = videobuf_next_field(q);
retval = q->ops->buf_prepare(q,q->read_buf,field);
if (0 != retval)
@@ -894,7 +589,7 @@ videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
spin_unlock_irqrestore(q->irqlock,flags);
retval = videobuf_waiton(q->read_buf,0,0);
if (0 == retval) {
- videobuf_dma_sync(q,&q->read_buf->dma);
+ CALL(q,sync,q,q->read_buf);
if (STATE_ERROR == q->read_buf->state)
retval = -EIO;
else
@@ -915,13 +610,16 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
{
enum v4l2_field field;
unsigned long flags=0;
- unsigned size, nbufs, bytes;
+ unsigned size, nbufs;
int retval;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
mutex_lock(&q->lock);
nbufs = 1; size = 0;
q->ops->buf_setup(q,&nbufs,&size);
+
if (NULL == q->read_buf &&
count >= size &&
!nonblocking) {
@@ -935,7 +633,8 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
if (NULL == q->read_buf) {
/* need to capture a new frame */
retval = -ENOMEM;
- q->read_buf = videobuf_alloc(q->msize);
+ q->read_buf = videobuf_alloc(q);
+
dprintk(1,"video alloc=0x%p\n", q->read_buf);
if (NULL == q->read_buf)
goto done;
@@ -943,6 +642,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
q->read_buf->bsize = count; /* preferred size */
field = videobuf_next_field(q);
retval = q->ops->buf_prepare(q,q->read_buf,field);
+
if (0 != retval) {
kfree (q->read_buf);
q->read_buf = NULL;
@@ -950,6 +650,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
}
if (q->irqlock)
spin_lock_irqsave(q->irqlock,flags);
+
q->ops->buf_queue(q,q->read_buf);
if (q->irqlock)
spin_unlock_irqrestore(q->irqlock,flags);
@@ -960,7 +661,8 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
retval = videobuf_waiton(q->read_buf, nonblocking, 1);
if (0 != retval)
goto done;
- videobuf_dma_sync(q,&q->read_buf->dma);
+
+ CALL(q,sync,q,q->read_buf);
if (STATE_ERROR == q->read_buf->state) {
/* catch I/O errors */
@@ -971,16 +673,12 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
goto done;
}
- /* copy to userspace */
- bytes = count;
- if (bytes > q->read_buf->size - q->read_off)
- bytes = q->read_buf->size - q->read_off;
- retval = -EFAULT;
- if (copy_to_user(data, q->read_buf->dma.vmalloc+q->read_off, bytes))
+ /* Copy to userspace */
+ retval=CALL(q,video_copy_to_user,q,data,count,nonblocking);
+ if (retval<0)
goto done;
- retval = bytes;
- q->read_off += bytes;
+ q->read_off += retval;
if (q->read_off == q->read_buf->size) {
/* all data copied, cleanup */
q->ops->buf_release(q,q->read_buf);
@@ -997,7 +695,7 @@ int videobuf_read_start(struct videobuf_queue *q)
{
enum v4l2_field field;
unsigned long flags=0;
- int count = 0, size = 0;
+ unsigned int count = 0, size = 0;
int err, i;
q->ops->buf_setup(q,&count,&size);
@@ -1008,8 +706,11 @@ int videobuf_read_start(struct videobuf_queue *q)
size = PAGE_ALIGN(size);
err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR);
- if (err)
+ if (err < 0)
return err;
+
+ count = err;
+
for (i = 0; i < count; i++) {
field = videobuf_next_field(q);
err = q->ops->buf_prepare(q,q->bufs[i],field);
@@ -1048,10 +749,11 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
char __user *data, size_t count, loff_t *ppos,
int vbihack, int nonblocking)
{
- unsigned int *fc, bytes;
- int err, retval;
+ int rc, retval;
unsigned long flags=0;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
dprintk(2,"%s\n",__FUNCTION__);
mutex_lock(&q->lock);
retval = -EBUSY;
@@ -1073,39 +775,23 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
list_del(&q->read_buf->stream);
q->read_off = 0;
}
- err = videobuf_waiton(q->read_buf, nonblocking, 1);
- if (err < 0) {
+ rc = videobuf_waiton(q->read_buf, nonblocking, 1);
+ if (rc < 0) {
if (0 == retval)
- retval = err;
+ retval = rc;
break;
}
if (q->read_buf->state == STATE_DONE) {
- if (vbihack) {
- /* dirty, undocumented hack -- pass the frame counter
- * within the last four bytes of each vbi data block.
- * We need that one to maintain backward compatibility
- * to all vbi decoding software out there ... */
- fc = (unsigned int*)q->read_buf->dma.vmalloc;
- fc += (q->read_buf->size>>2) -1;
- *fc = q->read_buf->field_count >> 1;
- dprintk(1,"vbihack: %d\n",*fc);
- }
-
- /* copy stuff */
- bytes = count;
- if (bytes > q->read_buf->size - q->read_off)
- bytes = q->read_buf->size - q->read_off;
- if (copy_to_user(data + retval,
- q->read_buf->dma.vmalloc + q->read_off,
- bytes)) {
- if (0 == retval)
- retval = -EFAULT;
+ rc = CALL (q,copy_stream, q, data + retval, count,
+ retval, vbihack, nonblocking);
+ if (rc < 0) {
+ retval = rc;
break;
}
- count -= bytes;
- retval += bytes;
- q->read_off += bytes;
+ retval += rc;
+ count -= rc;
+ q->read_off += rc;
} else {
/* some error */
q->read_off = q->read_buf->size;
@@ -1172,81 +858,6 @@ unsigned int videobuf_poll_stream(struct file *file,
return rc;
}
-/* --------------------------------------------------------------------- */
-
-static void
-videobuf_vm_open(struct vm_area_struct *vma)
-{
- struct videobuf_mapping *map = vma->vm_private_data;
-
- dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map,
- map->count,vma->vm_start,vma->vm_end);
- map->count++;
-}
-
-static void
-videobuf_vm_close(struct vm_area_struct *vma)
-{
- struct videobuf_mapping *map = vma->vm_private_data;
- struct videobuf_queue *q = map->q;
- int i;
-
- dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
- map->count,vma->vm_start,vma->vm_end);
-
- map->count--;
- if (0 == map->count) {
- dprintk(1,"munmap %p q=%p\n",map,q);
- mutex_lock(&q->lock);
- for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- if (NULL == q->bufs[i])
- continue;
- if (q->bufs[i])
- ;
- if (q->bufs[i]->map != map)
- continue;
- q->bufs[i]->map = NULL;
- q->bufs[i]->baddr = 0;
- q->ops->buf_release(q,q->bufs[i]);
- }
- mutex_unlock(&q->lock);
- kfree(map);
- }
- return;
-}
-
-/*
- * Get a anonymous page for the mapping. Make sure we can DMA to that
- * memory location with 32bit PCI devices (i.e. don't use highmem for
- * now ...). Bounce buffers don't work very well for the data rates
- * video capture has.
- */
-static struct page*
-videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
- int *type)
-{
- struct page *page;
-
- dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
- vaddr,vma->vm_start,vma->vm_end);
- if (vaddr > vma->vm_end)
- return NOPAGE_SIGBUS;
- page = alloc_page(GFP_USER | __GFP_DMA32);
- if (!page)
- return NOPAGE_OOM;
- clear_user_page(page_address(page), vaddr, page);
- if (type)
- *type = VM_FAULT_MINOR;
- return page;
-}
-
-static struct vm_operations_struct videobuf_vm_ops =
-{
- .open = videobuf_vm_open,
- .close = videobuf_vm_close,
- .nopage = videobuf_vm_nopage,
-};
-
int videobuf_mmap_setup(struct videobuf_queue *q,
unsigned int bcount, unsigned int bsize,
enum v4l2_memory memory)
@@ -1254,12 +865,19 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
unsigned int i;
int err;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
err = videobuf_mmap_free(q);
if (0 != err)
return err;
+ /* Allocate and initialize buffers */
for (i = 0; i < bcount; i++) {
- q->bufs[i] = videobuf_alloc(q->msize);
+ q->bufs[i] = videobuf_alloc(q);
+
+ if (q->bufs[i] == NULL)
+ break;
+
q->bufs[i]->i = i;
q->bufs[i]->input = UNSET;
q->bufs[i]->memory = memory;
@@ -1274,18 +892,30 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
break;
}
}
+
+ if (!i)
+ return -ENOMEM;
+
dprintk(1,"mmap setup: %d buffers, %d bytes each\n",
- bcount,bsize);
- return 0;
+ i, bsize);
+
+ return i;
}
int videobuf_mmap_free(struct videobuf_queue *q)
{
int i;
+ int rc;
+
+ if (!q)
+ return 0;
+
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+ rc = CALL(q,mmap_free,q);
+ if (rc<0)
+ return rc;
- for (i = 0; i < VIDEO_MAX_FRAME; i++)
- if (q->bufs[i] && q->bufs[i]->map)
- return -EBUSY;
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
continue;
@@ -1293,114 +923,65 @@ int videobuf_mmap_free(struct videobuf_queue *q)
kfree(q->bufs[i]);
q->bufs[i] = NULL;
}
- return 0;
+
+ return rc;
}
int videobuf_mmap_mapper(struct videobuf_queue *q,
struct vm_area_struct *vma)
{
- struct videobuf_mapping *map;
- unsigned int first,last,size,i;
int retval;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
mutex_lock(&q->lock);
- retval = -EINVAL;
- if (!(vma->vm_flags & VM_WRITE)) {
- dprintk(1,"mmap app bug: PROT_WRITE please\n");
- goto done;
- }
- if (!(vma->vm_flags & VM_SHARED)) {
- dprintk(1,"mmap app bug: MAP_SHARED please\n");
- goto done;
- }
+ retval=CALL(q,mmap_mapper,q,vma);
+ mutex_unlock(&q->lock);
- /* look for first buffer to map */
- for (first = 0; first < VIDEO_MAX_FRAME; first++) {
- if (NULL == q->bufs[first])
- continue;
- if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
- continue;
- if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
- break;
- }
- if (VIDEO_MAX_FRAME == first) {
- dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
- (vma->vm_pgoff << PAGE_SHIFT));
- goto done;
- }
+ return retval;
+}
- /* look for last buffer to map */
- for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
- if (NULL == q->bufs[last])
- continue;
- if (V4L2_MEMORY_MMAP != q->bufs[last]->memory)
- continue;
- if (q->bufs[last]->map) {
- retval = -EBUSY;
- goto done;
- }
- size += q->bufs[last]->bsize;
- if (size == (vma->vm_end - vma->vm_start))
- break;
- }
- if (VIDEO_MAX_FRAME == last) {
- dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n",
- (vma->vm_end - vma->vm_start));
- goto done;
- }
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+int videobuf_cgmbuf(struct videobuf_queue *q,
+ struct video_mbuf *mbuf, int count)
+{
+ struct v4l2_requestbuffers req;
+ int rc,i;
- /* create mapping + update buffer list */
- retval = -ENOMEM;
- map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
- if (NULL == map)
- goto done;
- for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) {
- q->bufs[i]->map = map;
- q->bufs[i]->baddr = vma->vm_start + size;
+ MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+ memset(&req,0,sizeof(req));
+ req.type = q->type;
+ req.count = count;
+ req.memory = V4L2_MEMORY_MMAP;
+ rc = videobuf_reqbufs(q,&req);
+ if (rc < 0)
+ return rc;
+
+ mbuf->frames = req.count;
+ mbuf->size = 0;
+ for (i = 0; i < mbuf->frames; i++) {
+ mbuf->offsets[i] = q->bufs[i]->boff;
+ mbuf->size += q->bufs[i]->bsize;
}
- map->count = 1;
- map->start = vma->vm_start;
- map->end = vma->vm_end;
- map->q = q;
- vma->vm_ops = &videobuf_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
- vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
- vma->vm_private_data = map;
- dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n",
- map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last);
- retval = 0;
- done:
- mutex_unlock(&q->lock);
- return retval;
+ return 0;
}
+EXPORT_SYMBOL_GPL(videobuf_cgmbuf);
+#endif
/* --------------------------------------------------------------------- */
-EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
-
-EXPORT_SYMBOL_GPL(videobuf_dma_init);
-EXPORT_SYMBOL_GPL(videobuf_dma_init_user);
-EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);
-EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
-EXPORT_SYMBOL_GPL(videobuf_dma_map);
-EXPORT_SYMBOL_GPL(videobuf_dma_sync);
-EXPORT_SYMBOL_GPL(videobuf_dma_unmap);
-EXPORT_SYMBOL_GPL(videobuf_dma_free);
-
-EXPORT_SYMBOL_GPL(videobuf_pci_dma_map);
-EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap);
-
-EXPORT_SYMBOL_GPL(videobuf_alloc);
EXPORT_SYMBOL_GPL(videobuf_waiton);
EXPORT_SYMBOL_GPL(videobuf_iolock);
-EXPORT_SYMBOL_GPL(videobuf_queue_init);
+EXPORT_SYMBOL_GPL(videobuf_alloc);
+
+EXPORT_SYMBOL_GPL(videobuf_queue_core_init);
EXPORT_SYMBOL_GPL(videobuf_queue_cancel);
EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);
EXPORT_SYMBOL_GPL(videobuf_next_field);
-EXPORT_SYMBOL_GPL(videobuf_status);
EXPORT_SYMBOL_GPL(videobuf_reqbufs);
EXPORT_SYMBOL_GPL(videobuf_querybuf);
EXPORT_SYMBOL_GPL(videobuf_qbuf);
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
new file mode 100644
index 00000000000..44ee408e145
--- /dev/null
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -0,0 +1,725 @@
+/*
+ * helper functions for PCI DMA video4linux capture buffers
+ *
+ * The functions expect the hardware being able to scatter gatter
+ * (i.e. the buffers are not linear in physical memory, but fragmented
+ * into PAGE_SIZE chunks). They also assume the driver does not need
+ * to touch the video data.
+ *
+ * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
+ *
+ * Highly based on video-buf written originally by:
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2006 Mauro Carvalho Chehab, <mchehab@infradead.org>
+ * (c) 2006 Ted Walther and John Sokol
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/scatterlist.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <media/videobuf-dma-sg.h>
+
+#define MAGIC_DMABUF 0x19721112
+#define MAGIC_SG_MEM 0x17890714
+
+#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \
+ { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
+
+static int debug = 0;
+module_param(debug, int, 0644);
+
+MODULE_DESCRIPTION("helper module to manage video4linux pci dma sg buffers");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+
+#define dprintk(level, fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
+
+/* --------------------------------------------------------------------- */
+
+struct scatterlist*
+videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
+{
+ struct scatterlist *sglist;
+ struct page *pg;
+ int i;
+
+ sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
+ if (NULL == sglist)
+ return NULL;
+ sg_init_table(sglist, nr_pages);
+ for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
+ pg = vmalloc_to_page(virt);
+ if (NULL == pg)
+ goto err;
+ BUG_ON(PageHighMem(pg));
+ sg_set_page(&sglist[i], pg, PAGE_SIZE, 0);
+ }
+ return sglist;
+
+ err:
+ kfree(sglist);
+ return NULL;
+}
+
+struct scatterlist*
+videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
+{
+ struct scatterlist *sglist;
+ int i = 0;
+
+ if (NULL == pages[0])
+ return NULL;
+ sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL);
+ if (NULL == sglist)
+ return NULL;
+ sg_init_table(sglist, nr_pages);
+
+ if (NULL == pages[0])
+ goto nopage;
+ if (PageHighMem(pages[0]))
+ /* DMA to highmem pages might not work */
+ goto highmem;
+ sg_set_page(&sglist[0], pages[0], PAGE_SIZE - offset, offset);
+ for (i = 1; i < nr_pages; i++) {
+ if (NULL == pages[i])
+ goto nopage;
+ if (PageHighMem(pages[i]))
+ goto highmem;
+ sg_set_page(&sglist[i], pages[i], PAGE_SIZE, 0);
+ }
+ return sglist;
+
+ nopage:
+ dprintk(2,"sgl: oops - no page\n");
+ kfree(sglist);
+ return NULL;
+
+ highmem:
+ dprintk(2,"sgl: oops - highmem page\n");
+ kfree(sglist);
+ return NULL;
+}
+
+/* --------------------------------------------------------------------- */
+
+struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf)
+{
+ struct videbuf_pci_sg_memory *mem=buf->priv;
+ BUG_ON (!mem);
+
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ return &mem->dma;
+}
+
+void videobuf_dma_init(struct videobuf_dmabuf *dma)
+{
+ memset(dma,0,sizeof(*dma));
+ dma->magic = MAGIC_DMABUF;
+}
+
+static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
+ int direction, unsigned long data, unsigned long size)
+{
+ unsigned long first,last;
+ int err, rw = 0;
+
+ dma->direction = direction;
+ switch (dma->direction) {
+ case PCI_DMA_FROMDEVICE: rw = READ; break;
+ case PCI_DMA_TODEVICE: rw = WRITE; break;
+ default: BUG();
+ }
+
+ first = (data & PAGE_MASK) >> PAGE_SHIFT;
+ last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
+ dma->offset = data & ~PAGE_MASK;
+ dma->nr_pages = last-first+1;
+ dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*),
+ GFP_KERNEL);
+ if (NULL == dma->pages)
+ return -ENOMEM;
+ dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
+ data,size,dma->nr_pages);
+
+ dma->varea = (void *) data;
+
+
+ err = get_user_pages(current,current->mm,
+ data & PAGE_MASK, dma->nr_pages,
+ rw == READ, 1, /* force */
+ dma->pages, NULL);
+
+ if (err != dma->nr_pages) {
+ dma->nr_pages = (err >= 0) ? err : 0;
+ dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages);
+ return err < 0 ? err : -EINVAL;
+ }
+ return 0;
+}
+
+int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
+ unsigned long data, unsigned long size)
+{
+ int ret;
+ down_read(&current->mm->mmap_sem);
+ ret = videobuf_dma_init_user_locked(dma, direction, data, size);
+ up_read(&current->mm->mmap_sem);
+
+ return ret;
+}
+
+int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
+ int nr_pages)
+{
+ dprintk(1,"init kernel [%d pages]\n",nr_pages);
+ dma->direction = direction;
+ dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
+ if (NULL == dma->vmalloc) {
+ dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages);
+ return -ENOMEM;
+ }
+ dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
+ (unsigned long)dma->vmalloc,
+ nr_pages << PAGE_SHIFT);
+ memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT);
+ dma->nr_pages = nr_pages;
+ return 0;
+}
+
+int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
+ dma_addr_t addr, int nr_pages)
+{
+ dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n",
+ nr_pages,(unsigned long)addr);
+ dma->direction = direction;
+ if (0 == addr)
+ return -EINVAL;
+
+ dma->bus_addr = addr;
+ dma->nr_pages = nr_pages;
+ return 0;
+}
+
+int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
+{
+ void *dev=q->dev;
+
+ MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+ BUG_ON(0 == dma->nr_pages);
+
+ if (dma->pages) {
+ dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
+ dma->offset);
+ }
+ if (dma->vmalloc) {
+ dma->sglist = videobuf_vmalloc_to_sg
+ (dma->vmalloc,dma->nr_pages);
+ }
+ if (dma->bus_addr) {
+ dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL);
+ if (NULL != dma->sglist) {
+ dma->sglen = 1;
+ sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK;
+ dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK;
+ sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE;
+ }
+ }
+ if (NULL == dma->sglist) {
+ dprintk(1,"scatterlist is NULL\n");
+ return -ENOMEM;
+ }
+ if (!dma->bus_addr) {
+ dma->sglen = pci_map_sg(dev,dma->sglist,
+ dma->nr_pages, dma->direction);
+ if (0 == dma->sglen) {
+ printk(KERN_WARNING
+ "%s: videobuf_map_sg failed\n",__FUNCTION__);
+ kfree(dma->sglist);
+ dma->sglist = NULL;
+ dma->sglen = 0;
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma)
+{
+ void *dev=q->dev;
+
+ MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+ BUG_ON(!dma->sglen);
+
+ pci_dma_sync_sg_for_cpu (dev,dma->sglist,dma->nr_pages,dma->direction);
+ return 0;
+}
+
+int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
+{
+ void *dev=q->dev;
+
+ MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+ if (!dma->sglen)
+ return 0;
+
+ pci_unmap_sg (dev,dma->sglist,dma->nr_pages,dma->direction);
+
+ kfree(dma->sglist);
+ dma->sglist = NULL;
+ dma->sglen = 0;
+ return 0;
+}
+
+int videobuf_dma_free(struct videobuf_dmabuf *dma)
+{
+ MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+ BUG_ON(dma->sglen);
+
+ if (dma->pages) {
+ int i;
+ for (i=0; i < dma->nr_pages; i++)
+ page_cache_release(dma->pages[i]);
+ kfree(dma->pages);
+ dma->pages = NULL;
+ }
+
+ vfree(dma->vmalloc);
+ dma->vmalloc = NULL;
+ dma->varea = NULL;
+
+ if (dma->bus_addr) {
+ dma->bus_addr = 0;
+ }
+ dma->direction = PCI_DMA_NONE;
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma)
+{
+ struct videobuf_queue q;
+
+ q.dev=pci;
+
+ return (videobuf_dma_map(&q,dma));
+}
+
+int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma)
+{
+ struct videobuf_queue q;
+
+ q.dev=pci;
+
+ return (videobuf_dma_unmap(&q,dma));
+}
+
+/* --------------------------------------------------------------------- */
+
+static void
+videobuf_vm_open(struct vm_area_struct *vma)
+{
+ struct videobuf_mapping *map = vma->vm_private_data;
+
+ dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map,
+ map->count,vma->vm_start,vma->vm_end);
+ map->count++;
+}
+
+static void
+videobuf_vm_close(struct vm_area_struct *vma)
+{
+ struct videobuf_mapping *map = vma->vm_private_data;
+ struct videobuf_queue *q = map->q;
+ struct videbuf_pci_sg_memory *mem;
+ int i;
+
+ dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
+ map->count,vma->vm_start,vma->vm_end);
+
+ map->count--;
+ if (0 == map->count) {
+ dprintk(1,"munmap %p q=%p\n",map,q);
+ mutex_lock(&q->lock);
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == q->bufs[i])
+ continue;
+ mem=q->bufs[i]->priv;
+
+ if (!mem)
+ continue;
+
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ if (q->bufs[i]->map != map)
+ continue;
+ q->bufs[i]->map = NULL;
+ q->bufs[i]->baddr = 0;
+ q->ops->buf_release(q,q->bufs[i]);
+ }
+ mutex_unlock(&q->lock);
+ kfree(map);
+ }
+ return;
+}
+
+/*
+ * Get a anonymous page for the mapping. Make sure we can DMA to that
+ * memory location with 32bit PCI devices (i.e. don't use highmem for
+ * now ...). Bounce buffers don't work very well for the data rates
+ * video capture has.
+ */
+static struct page*
+videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
+ int *type)
+{
+ struct page *page;
+
+ dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
+ vaddr,vma->vm_start,vma->vm_end);
+ if (vaddr > vma->vm_end)
+ return NOPAGE_SIGBUS;
+ page = alloc_page(GFP_USER | __GFP_DMA32);
+ if (!page)
+ return NOPAGE_OOM;
+ clear_user_page(page_address(page), vaddr, page);
+ if (type)
+ *type = VM_FAULT_MINOR;
+ return page;
+}
+
+static struct vm_operations_struct videobuf_vm_ops =
+{
+ .open = videobuf_vm_open,
+ .close = videobuf_vm_close,
+ .nopage = videobuf_vm_nopage,
+};
+
+/* ---------------------------------------------------------------------
+ * PCI handlers for the generic methods
+ */
+
+/* Allocated area consists on 3 parts:
+ struct video_buffer
+ struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
+ struct videobuf_pci_sg_memory
+ */
+
+static void *__videobuf_alloc(size_t size)
+{
+ struct videbuf_pci_sg_memory *mem;
+ struct videobuf_buffer *vb;
+
+ vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
+
+ mem = vb->priv = ((char *)vb)+size;
+ mem->magic=MAGIC_SG_MEM;
+
+ videobuf_dma_init(&mem->dma);
+
+ dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
+ __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
+ mem,(long)sizeof(*mem));
+
+ return vb;
+}
+
+static int __videobuf_iolock (struct videobuf_queue* q,
+ struct videobuf_buffer *vb,
+ struct v4l2_framebuffer *fbuf)
+{
+ int err,pages;
+ dma_addr_t bus;
+ struct videbuf_pci_sg_memory *mem=vb->priv;
+ BUG_ON(!mem);
+
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ switch (vb->memory) {
+ case V4L2_MEMORY_MMAP:
+ case V4L2_MEMORY_USERPTR:
+ if (0 == vb->baddr) {
+ /* no userspace addr -- kernel bounce buffer */
+ pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
+ err = videobuf_dma_init_kernel( &mem->dma,
+ PCI_DMA_FROMDEVICE,
+ pages );
+ if (0 != err)
+ return err;
+ } else if (vb->memory == V4L2_MEMORY_USERPTR) {
+ /* dma directly to userspace */
+ err = videobuf_dma_init_user( &mem->dma,
+ PCI_DMA_FROMDEVICE,
+ vb->baddr,vb->bsize );
+ if (0 != err)
+ return err;
+ } else {
+ /* NOTE: HACK: videobuf_iolock on V4L2_MEMORY_MMAP
+ buffers can only be called from videobuf_qbuf
+ we take current->mm->mmap_sem there, to prevent
+ locking inversion, so don't take it here */
+
+ err = videobuf_dma_init_user_locked(&mem->dma,
+ PCI_DMA_FROMDEVICE,
+ vb->baddr, vb->bsize);
+ if (0 != err)
+ return err;
+ }
+ break;
+ case V4L2_MEMORY_OVERLAY:
+ if (NULL == fbuf)
+ return -EINVAL;
+ /* FIXME: need sanity checks for vb->boff */
+ /*
+ * Using a double cast to avoid compiler warnings when
+ * building for PAE. Compiler doesn't like direct casting
+ * of a 32 bit ptr to 64 bit integer.
+ */
+ bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff;
+ pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
+ err = videobuf_dma_init_overlay(&mem->dma,PCI_DMA_FROMDEVICE,
+ bus, pages);
+ if (0 != err)
+ return err;
+ break;
+ default:
+ BUG();
+ }
+ err = videobuf_dma_map(q,&mem->dma);
+ if (0 != err)
+ return err;
+
+ return 0;
+}
+
+static int __videobuf_sync(struct videobuf_queue *q,
+ struct videobuf_buffer *buf)
+{
+ struct videbuf_pci_sg_memory *mem=buf->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ return videobuf_dma_sync(q,&mem->dma);
+}
+
+static int __videobuf_mmap_free(struct videobuf_queue *q)
+{
+ int i;
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (q->bufs[i]) {
+ if (q->bufs[i]->map)
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+
+static int __videobuf_mmap_mapper(struct videobuf_queue *q,
+ struct vm_area_struct *vma)
+{
+ struct videbuf_pci_sg_memory *mem;
+ struct videobuf_mapping *map;
+ unsigned int first,last,size,i;
+ int retval;
+
+ retval = -EINVAL;
+ if (!(vma->vm_flags & VM_WRITE)) {
+ dprintk(1,"mmap app bug: PROT_WRITE please\n");
+ goto done;
+ }
+ if (!(vma->vm_flags & VM_SHARED)) {
+ dprintk(1,"mmap app bug: MAP_SHARED please\n");
+ goto done;
+ }
+
+ /* look for first buffer to map */
+ for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+ if (NULL == q->bufs[first])
+ continue;
+ mem=q->bufs[first]->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
+ continue;
+ if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+ break;
+ }
+ if (VIDEO_MAX_FRAME == first) {
+ dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
+ (vma->vm_pgoff << PAGE_SHIFT));
+ goto done;
+ }
+
+ /* look for last buffer to map */
+ for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
+ if (NULL == q->bufs[last])
+ continue;
+ if (V4L2_MEMORY_MMAP != q->bufs[last]->memory)
+ continue;
+ if (q->bufs[last]->map) {
+ retval = -EBUSY;
+ goto done;
+ }
+ size += q->bufs[last]->bsize;
+ if (size == (vma->vm_end - vma->vm_start))
+ break;
+ }
+ if (VIDEO_MAX_FRAME == last) {
+ dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n",
+ (vma->vm_end - vma->vm_start));
+ goto done;
+ }
+
+ /* create mapping + update buffer list */
+ retval = -ENOMEM;
+ map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
+ if (NULL == map)
+ goto done;
+ for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) {
+ q->bufs[i]->map = map;
+ q->bufs[i]->baddr = vma->vm_start + size;
+ }
+ map->count = 1;
+ map->start = vma->vm_start;
+ map->end = vma->vm_end;
+ map->q = q;
+ vma->vm_ops = &videobuf_vm_ops;
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+ vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
+ vma->vm_private_data = map;
+ dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n",
+ map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last);
+ retval = 0;
+
+ done:
+ return retval;
+}
+
+static int __videobuf_copy_to_user ( struct videobuf_queue *q,
+ char __user *data, size_t count,
+ int nonblocking )
+{
+ struct videbuf_pci_sg_memory *mem=q->read_buf->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ /* copy to userspace */
+ if (count > q->read_buf->size - q->read_off)
+ count = q->read_buf->size - q->read_off;
+
+ if (copy_to_user(data, mem->dma.vmalloc+q->read_off, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static int __videobuf_copy_stream ( struct videobuf_queue *q,
+ char __user *data, size_t count, size_t pos,
+ int vbihack, int nonblocking )
+{
+ unsigned int *fc;
+ struct videbuf_pci_sg_memory *mem=q->read_buf->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+ if (vbihack) {
+ /* dirty, undocumented hack -- pass the frame counter
+ * within the last four bytes of each vbi data block.
+ * We need that one to maintain backward compatibility
+ * to all vbi decoding software out there ... */
+ fc = (unsigned int*)mem->dma.vmalloc;
+ fc += (q->read_buf->size>>2) -1;
+ *fc = q->read_buf->field_count >> 1;
+ dprintk(1,"vbihack: %d\n",*fc);
+ }
+
+ /* copy stuff using the common method */
+ count = __videobuf_copy_to_user (q,data,count,nonblocking);
+
+ if ( (count==-EFAULT) && (0 == pos) )
+ return -EFAULT;
+
+ return count;
+}
+
+static struct videobuf_qtype_ops pci_ops = {
+ .magic = MAGIC_QTYPE_OPS,
+
+ .alloc = __videobuf_alloc,
+ .iolock = __videobuf_iolock,
+ .sync = __videobuf_sync,
+ .mmap_free = __videobuf_mmap_free,
+ .mmap_mapper = __videobuf_mmap_mapper,
+ .video_copy_to_user = __videobuf_copy_to_user,
+ .copy_stream = __videobuf_copy_stream,
+};
+
+void *videobuf_pci_alloc (size_t size)
+{
+ struct videobuf_queue q;
+
+ /* Required to make generic handler to call __videobuf_alloc */
+ q.int_ops=&pci_ops;
+
+ q.msize=size;
+
+ return videobuf_alloc (&q);
+}
+
+void videobuf_queue_pci_init(struct videobuf_queue* q,
+ struct videobuf_queue_ops *ops,
+ void *dev,
+ spinlock_t *irqlock,
+ enum v4l2_buf_type type,
+ enum v4l2_field field,
+ unsigned int msize,
+ void *priv)
+{
+ videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
+ priv, &pci_ops);
+}
+
+/* --------------------------------------------------------------------- */
+
+EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
+
+EXPORT_SYMBOL_GPL(videobuf_to_dma);
+EXPORT_SYMBOL_GPL(videobuf_dma_init);
+EXPORT_SYMBOL_GPL(videobuf_dma_init_user);
+EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);
+EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
+EXPORT_SYMBOL_GPL(videobuf_dma_map);
+EXPORT_SYMBOL_GPL(videobuf_dma_sync);
+EXPORT_SYMBOL_GPL(videobuf_dma_unmap);
+EXPORT_SYMBOL_GPL(videobuf_dma_free);
+
+EXPORT_SYMBOL_GPL(videobuf_pci_dma_map);
+EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap);
+EXPORT_SYMBOL_GPL(videobuf_pci_alloc);
+
+EXPORT_SYMBOL_GPL(videobuf_queue_pci_init);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/videobuf-dvb.c
index e617925ba31..880317e04a0 100644
--- a/drivers/media/video/video-buf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -22,8 +22,8 @@
#include <linux/file.h>
#include <linux/freezer.h>
-#include <media/video-buf.h>
-#include <media/video-buf-dvb.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-dvb.h>
/* ------------------------------------------------------------------ */
@@ -45,6 +45,7 @@ static int videobuf_dvb_thread(void *data)
struct videobuf_buffer *buf;
unsigned long flags;
int err;
+ struct videobuf_dmabuf *dma;
dprintk("dvb thread started\n");
set_freezable();
@@ -56,7 +57,6 @@ static int videobuf_dvb_thread(void *data)
struct videobuf_buffer, stream);
list_del(&buf->stream);
err = videobuf_waiton(buf,0,1);
- BUG_ON(0 != err);
/* no more feeds left or stop_feed() asked us to quit */
if (0 == dvb->nfeeds)
@@ -66,8 +66,9 @@ static int videobuf_dvb_thread(void *data)
try_to_freeze();
/* feed buffer data to demux */
+ dma=videobuf_to_dma(buf);
if (buf->state == STATE_DONE)
- dvb_dmx_swfilter(&dvb->demux, buf->dma.vmalloc,
+ dvb_dmx_swfilter(&dvb->demux, dma->vmalloc,
buf->size);
/* requeue buffer */
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
new file mode 100644
index 00000000000..cd74341c984
--- /dev/null
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -0,0 +1,370 @@
+/*
+ * helper functions for vmalloc video4linux capture buffers
+ *
+ * The functions expect the hardware being able to scatter gatter
+ * (i.e. the buffers are not linear in physical memory, but fragmented
+ * into PAGE_SIZE chunks). They also assume the driver does not need
+ * to touch the video data.
+ *
+ * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <media/videobuf-vmalloc.h>
+
+#define MAGIC_DMABUF 0x17760309
+#define MAGIC_VMAL_MEM 0x18221223
+
+#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \
+ { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
+
+static int debug = 0;
+module_param(debug, int, 0644);
+
+MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+
+#define dprintk(level, fmt, arg...) if (debug >= level) \
+ printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
+
+
+/***************************************************************************/
+
+static void
+videobuf_vm_open(struct vm_area_struct *vma)
+{
+ struct videobuf_mapping *map = vma->vm_private_data;
+
+ dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map,
+ map->count,vma->vm_start,vma->vm_end);
+
+ map->count++;
+}
+
+static void
+videobuf_vm_close(struct vm_area_struct *vma)
+{
+ struct videobuf_mapping *map = vma->vm_private_data;
+ struct videobuf_queue *q = map->q;
+ int i;
+
+ dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
+ map->count,vma->vm_start,vma->vm_end);
+
+ map->count--;
+ if (0 == map->count) {
+ dprintk(1,"munmap %p q=%p\n",map,q);
+ mutex_lock(&q->lock);
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == q->bufs[i])
+ continue;
+
+ if (q->bufs[i]->map != map)
+ continue;
+
+ q->ops->buf_release(q,q->bufs[i]);
+
+ q->bufs[i]->map = NULL;
+ q->bufs[i]->baddr = 0;
+ }
+ mutex_unlock(&q->lock);
+ kfree(map);
+ }
+ return;
+}
+
+static struct vm_operations_struct videobuf_vm_ops =
+{
+ .open = videobuf_vm_open,
+ .close = videobuf_vm_close,
+};
+
+/* ---------------------------------------------------------------------
+ * vmalloc handlers for the generic methods
+ */
+
+/* Allocated area consists on 3 parts:
+ struct video_buffer
+ struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
+ struct videobuf_pci_sg_memory
+ */
+
+static void *__videobuf_alloc(size_t size)
+{
+ struct videbuf_vmalloc_memory *mem;
+ struct videobuf_buffer *vb;
+
+ vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
+
+ mem = vb->priv = ((char *)vb)+size;
+ mem->magic=MAGIC_VMAL_MEM;
+
+ dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
+ __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
+ mem,(long)sizeof(*mem));
+
+ return vb;
+}
+
+static int __videobuf_iolock (struct videobuf_queue* q,
+ struct videobuf_buffer *vb,
+ struct v4l2_framebuffer *fbuf)
+{
+ int pages;
+
+ struct videbuf_vmalloc_memory *mem=vb->priv;
+
+
+ BUG_ON(!mem);
+
+ MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+ pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
+
+ /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
+ if ((vb->memory != V4L2_MEMORY_MMAP) &&
+ (vb->memory != V4L2_MEMORY_USERPTR) ) {
+ printk(KERN_ERR "Method currently unsupported.\n");
+ return -EINVAL;
+ }
+
+ /* FIXME: should be tested with kernel mmap mem */
+ mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size));
+ if (NULL == mem->vmalloc) {
+ printk(KERN_ERR "vmalloc (%d pages) failed\n",pages);
+ return -ENOMEM;
+ }
+
+ dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
+ (unsigned long)mem->vmalloc,
+ pages << PAGE_SHIFT);
+
+ /* It seems that some kernel versions need to do remap *after*
+ the mmap() call
+ */
+ if (mem->vma) {
+ int retval=remap_vmalloc_range(mem->vma, mem->vmalloc,0);
+ kfree(mem->vma);
+ mem->vma=NULL;
+ if (retval<0) {
+ dprintk(1,"mmap app bug: remap_vmalloc_range area %p error %d\n",
+ mem->vmalloc,retval);
+ return retval;
+ }
+ }
+
+ return 0;
+}
+
+static int __videobuf_sync(struct videobuf_queue *q,
+ struct videobuf_buffer *buf)
+{
+ return 0;
+}
+
+static int __videobuf_mmap_free(struct videobuf_queue *q)
+{
+ unsigned int i;
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (q->bufs[i]) {
+ if (q->bufs[i]->map)
+ return -EBUSY;
+ }
+ }
+
+ return 0;
+}
+
+static int __videobuf_mmap_mapper(struct videobuf_queue *q,
+ struct vm_area_struct *vma)
+{
+ struct videbuf_vmalloc_memory *mem;
+ struct videobuf_mapping *map;
+ unsigned int first;
+ int retval;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ /* look for first buffer to map */
+ for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+ if (NULL == q->bufs[first])
+ continue;
+
+ if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
+ continue;
+ if (q->bufs[first]->boff == offset)
+ break;
+ }
+ if (VIDEO_MAX_FRAME == first) {
+ dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
+ (vma->vm_pgoff << PAGE_SHIFT));
+ return -EINVAL;
+ }
+
+ /* create mapping + update buffer list */
+ map = q->bufs[first]->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
+ if (NULL == map)
+ return -ENOMEM;
+
+ map->start = vma->vm_start;
+ map->end = vma->vm_end;
+ map->q = q;
+
+ q->bufs[first]->baddr = vma->vm_start;
+
+ vma->vm_ops = &videobuf_vm_ops;
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+ vma->vm_private_data = map;
+
+ mem=q->bufs[first]->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+ /* Try to remap memory */
+ retval=remap_vmalloc_range(vma, mem->vmalloc,0);
+ if (retval<0) {
+ dprintk(1,"mmap: postponing remap_vmalloc_range\n");
+
+ mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL);
+ if (!mem->vma) {
+ kfree(map);
+ q->bufs[first]->map=NULL;
+ return -ENOMEM;
+ }
+ memcpy(mem->vma,vma,sizeof(*vma));
+ }
+
+ dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
+ map,q,vma->vm_start,vma->vm_end,
+ (long int) q->bufs[first]->bsize,
+ vma->vm_pgoff,first);
+
+ videobuf_vm_open(vma);
+
+ return (0);
+}
+
+static int __videobuf_copy_to_user ( struct videobuf_queue *q,
+ char __user *data, size_t count,
+ int nonblocking )
+{
+ struct videbuf_vmalloc_memory *mem=q->read_buf->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+ BUG_ON (!mem->vmalloc);
+
+ /* copy to userspace */
+ if (count > q->read_buf->size - q->read_off)
+ count = q->read_buf->size - q->read_off;
+
+ if (copy_to_user(data, mem->vmalloc+q->read_off, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static int __videobuf_copy_stream ( struct videobuf_queue *q,
+ char __user *data, size_t count, size_t pos,
+ int vbihack, int nonblocking )
+{
+ unsigned int *fc;
+ struct videbuf_vmalloc_memory *mem=q->read_buf->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+ if (vbihack) {
+ /* dirty, undocumented hack -- pass the frame counter
+ * within the last four bytes of each vbi data block.
+ * We need that one to maintain backward compatibility
+ * to all vbi decoding software out there ... */
+ fc = (unsigned int*)mem->vmalloc;
+ fc += (q->read_buf->size>>2) -1;
+ *fc = q->read_buf->field_count >> 1;
+ dprintk(1,"vbihack: %d\n",*fc);
+ }
+
+ /* copy stuff using the common method */
+ count = __videobuf_copy_to_user (q,data,count,nonblocking);
+
+ if ( (count==-EFAULT) && (0 == pos) )
+ return -EFAULT;
+
+ return count;
+}
+
+static struct videobuf_qtype_ops qops = {
+ .magic = MAGIC_QTYPE_OPS,
+
+ .alloc = __videobuf_alloc,
+ .iolock = __videobuf_iolock,
+ .sync = __videobuf_sync,
+ .mmap_free = __videobuf_mmap_free,
+ .mmap_mapper = __videobuf_mmap_mapper,
+ .video_copy_to_user = __videobuf_copy_to_user,
+ .copy_stream = __videobuf_copy_stream,
+};
+
+void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
+ struct videobuf_queue_ops *ops,
+ void *dev,
+ spinlock_t *irqlock,
+ enum v4l2_buf_type type,
+ enum v4l2_field field,
+ unsigned int msize,
+ void *priv)
+{
+ videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
+ priv, &qops);
+}
+
+EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
+
+void *videobuf_to_vmalloc (struct videobuf_buffer *buf)
+{
+ struct videbuf_vmalloc_memory *mem=buf->priv;
+ BUG_ON (!mem);
+ MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+ return mem->vmalloc;
+}
+EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
+
+void videobuf_vmalloc_free (struct videobuf_buffer *buf)
+{
+ struct videbuf_vmalloc_memory *mem=buf->priv;
+ BUG_ON (!mem);
+
+ MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+ vfree(mem->vmalloc);
+ mem->vmalloc=NULL;
+
+ return;
+}
+EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/videocodec.c b/drivers/media/video/videocodec.c
index f2bbd7a4d56..87951ec8254 100644
--- a/drivers/media/video/videocodec.c
+++ b/drivers/media/video/videocodec.c
@@ -86,8 +86,8 @@ videocodec_attach (struct videocodec_master *master)
}
dprintk(2,
- "videocodec_attach: '%s', type: %x, flags %lx, magic %lx\n",
- master->name, master->type, master->flags, master->magic);
+ "videocodec_attach: '%s', flags %lx, magic %lx\n",
+ master->name, master->flags, master->magic);
if (!h) {
dprintk(1,
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index b876aca69c7..9611c399028 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -54,15 +54,14 @@
* sysfs stuff
*/
-static ssize_t show_name(struct class_device *cd, char *buf)
+static ssize_t show_name(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
struct video_device *vfd = container_of(cd, struct video_device,
- class_dev);
- return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name);
+ class_dev);
+ return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
}
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-
struct video_device *video_device_alloc(void)
{
struct video_device *vfd;
@@ -76,7 +75,7 @@ void video_device_release(struct video_device *vfd)
kfree(vfd);
}
-static void video_release(struct class_device *cd)
+static void video_release(struct device *cd)
{
struct video_device *vfd = container_of(cd, struct video_device,
class_dev);
@@ -89,9 +88,15 @@ static void video_release(struct class_device *cd)
vfd->release(vfd);
}
+static struct device_attribute video_device_attrs[] = {
+ __ATTR(name, S_IRUGO, show_name, NULL),
+ __ATTR_NULL
+};
+
static struct class video_class = {
.name = VIDEO_NAME,
- .release = video_release,
+ .dev_attrs = video_device_attrs,
+ .dev_release = video_release,
};
/*
@@ -448,7 +453,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
if (cmd == VIDIOCGMBUF) {
struct video_mbuf *p=arg;
- memset(p,0,sizeof(p));
+ memset(p, 0, sizeof(*p));
if (!vfd->vidiocgmbuf)
return ret;
@@ -1308,48 +1313,6 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
ret=vfd->vidioc_cropcap(file, fh, p);
break;
}
- case VIDIOC_G_MPEGCOMP:
- {
- struct v4l2_mpeg_compression *p=arg;
-
- /*FIXME: Several fields not shown */
- if (!vfd->vidioc_g_mpegcomp)
- break;
- ret=vfd->vidioc_g_mpegcomp(file, fh, p);
- if (!ret)
- dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d,"
- " ts_pid_video=%d, ts_pid_pcr=%d, "
- "ps_size=%d, au_sample_rate=%d, "
- "au_pesid=%c, vi_frame_rate=%d, "
- "vi_frames_per_gop=%d, "
- "vi_bframes_count=%d, vi_pesid=%c\n",
- p->ts_pid_pmt,p->ts_pid_audio,
- p->ts_pid_video,p->ts_pid_pcr,
- p->ps_size, p->au_sample_rate,
- p->au_pesid, p->vi_frame_rate,
- p->vi_frames_per_gop,
- p->vi_bframes_count, p->vi_pesid);
- break;
- }
- case VIDIOC_S_MPEGCOMP:
- {
- struct v4l2_mpeg_compression *p=arg;
- /*FIXME: Several fields not shown */
- if (!vfd->vidioc_s_mpegcomp)
- break;
- dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d, "
- "ts_pid_video=%d, ts_pid_pcr=%d, ps_size=%d, "
- "au_sample_rate=%d, au_pesid=%c, "
- "vi_frame_rate=%d, vi_frames_per_gop=%d, "
- "vi_bframes_count=%d, vi_pesid=%c\n",
- p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
- p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
- p->au_pesid, p->vi_frame_rate,
- p->vi_frames_per_gop, p->vi_bframes_count,
- p->vi_pesid);
- ret=vfd->vidioc_s_mpegcomp(file, fh, p);
- break;
- }
case VIDIOC_G_JPEGCOMP:
{
struct v4l2_jpegcompression *p=arg;
@@ -1753,22 +1716,16 @@ int video_register_device(struct video_device *vfd, int type, int nr)
/* sysfs class */
memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
if (vfd->dev)
- vfd->class_dev.dev = vfd->dev;
+ vfd->class_dev.parent = vfd->dev;
vfd->class_dev.class = &video_class;
vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
- sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base);
- ret = class_device_register(&vfd->class_dev);
+ sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base);
+ ret = device_register(&vfd->class_dev);
if (ret < 0) {
- printk(KERN_ERR "%s: class_device_register failed\n",
+ printk(KERN_ERR "%s: device_register failed\n",
__FUNCTION__);
goto fail_minor;
}
- ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name);
- if (ret < 0) {
- printk(KERN_ERR "%s: class_device_create_file 'name' failed\n",
- __FUNCTION__);
- goto fail_classdev;
- }
#if 1
/* needed until all drivers are fixed */
@@ -1779,8 +1736,6 @@ int video_register_device(struct video_device *vfd, int type, int nr)
#endif
return 0;
-fail_classdev:
- class_device_unregister(&vfd->class_dev);
fail_minor:
mutex_lock(&videodev_lock);
video_device[vfd->minor] = NULL;
@@ -1804,7 +1759,7 @@ void video_unregister_device(struct video_device *vfd)
panic("videodev: bad unregister");
video_device[vfd->minor]=NULL;
- class_device_unregister(&vfd->class_dev);
+ device_unregister(&vfd->class_dev);
mutex_unlock(&videodev_lock);
}
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index a0c1647a2ba..9a03dc82c6c 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -28,7 +28,6 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mm.h>
-#include <linux/moduleparam.h>
#include <linux/time.h>
#include <linux/version.h>
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index f6d3a9460cc..ee73dc75131 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -33,7 +33,7 @@
#include <linux/videodev.h>
#endif
#include <linux/interrupt.h>
-#include <media/video-buf.h>
+#include <media/videobuf-vmalloc.h>
#include <media/v4l2-common.h>
#include <linux/kthread.h>
#include <linux/highmem.h>
@@ -145,7 +145,6 @@ struct vivi_buffer {
struct videobuf_buffer vb;
struct vivi_fmt *fmt;
-
};
struct vivi_dmaqueue {
@@ -171,7 +170,6 @@ struct vivi_dev {
int users;
/* various device info */
- unsigned int resources;
struct video_device vfd;
struct vivi_dmaqueue vidq;
@@ -230,9 +228,8 @@ static u8 bars[8][3] = {
#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
#define TSTAMP_MIN_X 64
-
static void gen_line(char *basep,int inipos,int wmax,
- int hmax, int line, char *timestr)
+ int hmax, int line, int count, char *timestr)
{
int w,i,j,pos=inipos,y;
char *p,*s;
@@ -243,9 +240,10 @@ static void gen_line(char *basep,int inipos,int wmax,
/* Generate a standard color bar pattern */
for (w=0;w<wmax;w++) {
- r=bars[w*7/wmax][0];
- g=bars[w*7/wmax][1];
- b=bars[w*7/wmax][2];
+ int colorpos=((w+count)*8/(wmax+1)) % 8;
+ r=bars[colorpos][0];
+ g=bars[colorpos][1];
+ b=bars[colorpos][2];
for (color=0;color<4;color++) {
p=basep+pos;
@@ -326,27 +324,27 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
int hmax = buf->vb.height;
int wmax = buf->vb.width;
struct timeval ts;
- char *tmpbuf;
-
- if (buf->vb.dma.varea) {
- tmpbuf=kmalloc (wmax*2, GFP_KERNEL);
- } else {
- tmpbuf=buf->vb.dma.vmalloc;
- }
+ char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL);
+ void *vbuf=videobuf_to_vmalloc (&buf->vb);
+ /* FIXME: move to dev struct */
+ static int mv_count=0;
+ if (!tmpbuf)
+ return;
for (h=0;h<hmax;h++) {
- if (buf->vb.dma.varea) {
- gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr);
- /* FIXME: replacing to __copy_to_user */
- if (copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2)!=0)
- dprintk(2,"vivifill copy_to_user failed.\n");
- } else {
- gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr);
- }
+ gen_line(tmpbuf,0,wmax,hmax,h,mv_count,
+ dev->timestr);
+ /* FIXME: replacing to __copy_to_user */
+ if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0)
+ dprintk(2,"vivifill copy_to_user failed.\n");
pos += wmax*2;
}
+ mv_count++;
+
+ kfree(tmpbuf);
+
/* Updates stream time */
dev->us+=jiffies_to_usecs(jiffies-dev->jiffies);
@@ -369,7 +367,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
dev->h,dev->m,dev->s,(dev->us+500)/1000);
dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
- (unsigned long)buf->vb.dma.varea,pos);
+ (unsigned long)tmpbuf,pos);
/* Advice that buffer was filled */
buf->vb.state = STATE_DONE;
@@ -509,7 +507,6 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
static int restart_video_queue(struct vivi_dmaqueue *dma_q)
{
struct vivi_buffer *buf, *prev;
- struct list_head *item;
dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
@@ -523,9 +520,7 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q)
// vivi_start_thread(dma_q);
/* cancel all outstanding capture / vbi requests */
- list_for_each(item,&dma_q->active) {
- buf = list_entry(item, struct vivi_buffer, vb.queue);
-
+ list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) {
list_del(&buf->vb.queue);
buf->vb.state = STATE_ERROR;
wake_up(&buf->vb.done);
@@ -597,8 +592,12 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
if (0 == *count)
*count = 32;
+
while (*size * *count > vid_limit * 1024 * 1024)
(*count)--;
+
+ dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size);
+
return 0;
}
@@ -609,10 +608,8 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
if (in_interrupt())
BUG();
-
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(vq, &buf->vb.dma);
- videobuf_dma_free(&buf->vb.dma);
+ videobuf_vmalloc_free(&buf->vb);
buf->vb.state = STATE_NEEDS_INIT;
}
@@ -626,7 +623,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb);
int rc, init_buffer = 0;
-// dprintk(1,"%s, field=%d\n",__FUNCTION__,field);
+ dprintk(1,"%s, field=%d\n",__FUNCTION__,field);
BUG_ON(NULL == fh->fmt);
if (fh->width < 48 || fh->width > norm_maxw() ||
@@ -718,54 +715,14 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
free_buffer(vq,buf);
}
-
static struct videobuf_queue_ops vivi_video_qops = {
.buf_setup = buffer_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
.buf_release = buffer_release,
-
- /* Non-pci handling routines */
-// .vb_map_sg = vivi_map_sg,
-// .vb_dma_sync_sg = vivi_dma_sync_sg,
-// .vb_unmap_sg = vivi_unmap_sg,
};
/* ------------------------------------------------------------------
- IOCTL handling
- ------------------------------------------------------------------*/
-
-
-static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
-{
- /* is it free? */
- mutex_lock(&dev->lock);
- if (dev->resources) {
- /* no, someone else uses it */
- mutex_unlock(&dev->lock);
- return 0;
- }
- /* it's free, grab it */
- dev->resources =1;
- dprintk(1,"res: get\n");
- mutex_unlock(&dev->lock);
- return 1;
-}
-
-static int res_locked(struct vivi_dev *dev)
-{
- return (dev->resources);
-}
-
-static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
-{
- mutex_lock(&dev->lock);
- dev->resources = 0;
- dprintk(1,"res: put\n");
- mutex_lock(&dev->lock);
-}
-
-/* ------------------------------------------------------------------
IOCTL vidioc handling
------------------------------------------------------------------*/
static int vidioc_querycap (struct file *file, void *priv,
@@ -825,8 +782,7 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv,
field = f->fmt.pix.field;
if (field == V4L2_FIELD_ANY) {
-// field=V4L2_FIELD_INTERLACED;
- field=V4L2_FIELD_SEQ_TB;
+ field=V4L2_FIELD_INTERLACED;
} else if (V4L2_FIELD_INTERLACED != field) {
dprintk(1,"Field type invalid.\n");
return -EINVAL;
@@ -904,57 +860,33 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
{
struct vivi_fh *fh=priv;
- struct videobuf_queue *q=&fh->vb_vidq;
- struct v4l2_requestbuffers req;
- unsigned int i;
- int ret;
-
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- ret = videobuf_reqbufs(q,&req);
- if (ret < 0)
- return (ret);
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- return (0);
+ return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);
}
#endif
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct vivi_fh *fh=priv;
- struct vivi_dev *dev = fh->dev;
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (i != fh->type)
return -EINVAL;
- if (!res_get(dev,fh))
- return -EBUSY;
- return (videobuf_streamon(&fh->vb_vidq));
+ return videobuf_streamon(&fh->vb_vidq);
}
static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct vivi_fh *fh=priv;
- struct vivi_dev *dev = fh->dev;
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (i != fh->type)
return -EINVAL;
- videobuf_streamoff(&fh->vb_vidq);
- res_free(dev,fh);
-
- return (0);
+ return videobuf_streamoff(&fh->vb_vidq);
}
static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i)
@@ -1047,31 +979,25 @@ static int vidioc_s_ctrl (struct file *file, void *priv,
static int vivi_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
- struct vivi_dev *h,*dev = NULL;
+ struct vivi_dev *dev;
struct vivi_fh *fh;
- struct list_head *list;
- enum v4l2_buf_type type = 0;
int i;
printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor);
- list_for_each(list,&vivi_devlist) {
- h = list_entry(list, struct vivi_dev, vivi_devlist);
- if (h->vfd.minor == minor) {
- dev = h;
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- }
- }
- if (NULL == dev)
- return -ENODEV;
+ list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
+ if (dev->vfd.minor == minor)
+ goto found;
+ return -ENODEV;
+found:
/* If more than one user, mutex should be added */
dev->users++;
- dprintk(1,"open minor=%d type=%s users=%d\n",
- minor,v4l2_type_names[type],dev->users);
+ dprintk(1, "open minor=%d type=%s users=%d\n", minor,
+ v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh),GFP_KERNEL);
@@ -1106,7 +1032,7 @@ static int vivi_open(struct inode *inode, struct file *file)
sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
dev->h,dev->m,dev->s,(dev->us+500)/1000);
- videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops,
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
NULL, NULL,
fh->type,
V4L2_FIELD_INTERLACED,
@@ -1121,9 +1047,7 @@ vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
struct vivi_fh *fh = file->private_data;
if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (res_locked(fh->dev))
- return -EBUSY;
- return videobuf_read_one(&fh->vb_vidq, data, count, ppos,
+ return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
file->f_flags & O_NONBLOCK);
}
return 0;
@@ -1133,31 +1057,14 @@ static unsigned int
vivi_poll(struct file *file, struct poll_table_struct *wait)
{
struct vivi_fh *fh = file->private_data;
- struct vivi_buffer *buf;
+ struct videobuf_queue *q = &fh->vb_vidq;
dprintk(1,"%s\n",__FUNCTION__);
if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
return POLLERR;
- if (res_get(fh->dev,fh)) {
- dprintk(1,"poll: mmap interface\n");
- /* streaming capture */
- if (list_empty(&fh->vb_vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vb_vidq.stream.next,struct vivi_buffer,vb.stream);
- } else {
- dprintk(1,"poll: read() interface\n");
- /* read() capture */
- buf = (struct vivi_buffer*)fh->vb_vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == STATE_DONE ||
- buf->vb.state == STATE_ERROR)
- return POLLIN|POLLRDNORM;
- return 0;
+ return videobuf_poll_stream(file, q, wait);
}
static int vivi_release(struct inode *inode, struct file *file)
@@ -1205,14 +1112,13 @@ static const struct file_operations vivi_fops = {
.read = vivi_read,
.poll = vivi_poll,
.ioctl = video_ioctl2, /* V4L2 ioctl handler */
- .mmap = vivi_mmap,
+ .mmap = vivi_mmap,
.llseek = no_llseek,
};
static struct video_device vivi = {
.name = "vivi",
.type = VID_TYPE_CAPTURE,
- .hardware = 0,
.fops = &vivi_fops,
.minor = -1,
// .release = video_device_release,
diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c
new file mode 100644
index 00000000000..63002e0ac76
--- /dev/null
+++ b/drivers/media/video/vp27smpx.c
@@ -0,0 +1,212 @@
+/*
+ * vp27smpx - driver version 0.0.1
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Based on a tvaudio patch from Takahiro Adachi <tadachi@tadachi-net.com>
+ * and Kazuhiko Kawakami <kazz-0@mail.goo.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("vp27smpx driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+struct vp27smpx_state {
+ int radio;
+ u32 audmode;
+};
+
+static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode)
+{
+ struct vp27smpx_state *state = i2c_get_clientdata(client);
+ u8 data[3] = { 0x00, 0x00, 0x04 };
+
+ switch (audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ case V4L2_TUNER_MODE_LANG1:
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ case V4L2_TUNER_MODE_LANG1_LANG2:
+ data[1] = 0x01;
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ data[1] = 0x02;
+ break;
+ }
+
+ if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) {
+ v4l_err(client, "%s: I/O error setting audmode\n", client->name);
+ }
+ else {
+ state->audmode = audmode;
+ }
+}
+
+static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ struct vp27smpx_state *state = i2c_get_clientdata(client);
+ struct v4l2_tuner *vt = arg;
+
+ switch (cmd) {
+ case AUDC_SET_RADIO:
+ state->radio = 1;
+ break;
+
+ case VIDIOC_S_STD:
+ state->radio = 0;
+ break;
+
+ case VIDIOC_S_TUNER:
+ if (!state->radio)
+ vp27smpx_set_audmode(client, vt->audmode);
+ break;
+
+ case VIDIOC_G_TUNER:
+ if (state->radio)
+ break;
+ vt->audmode = state->audmode;
+ vt->capability = V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+ vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+ break;
+
+ case VIDIOC_G_CHIP_IDENT:
+ return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0);
+
+ case VIDIOC_LOG_STATUS:
+ v4l_info(client, "Audio Mode: %u%s\n", state->audmode,
+ state->radio ? " (Radio)" : "");
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct vp27smpx_state *state;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver;
+ snprintf(client->name, sizeof(client->name) - 1, "vp27smpx");
+
+ v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+ state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ state->audmode = V4L2_TUNER_MODE_STEREO;
+ i2c_set_clientdata(client, state);
+
+ /* initialize vp27smpx */
+ vp27smpx_set_audmode(client, state->audmode);
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int vp27smpx_probe(struct i2c_adapter *adapter)
+{
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+ return i2c_probe(adapter, &addr_data, vp27smpx_attach);
+ return 0;
+}
+
+static int vp27smpx_detach(struct i2c_client *client)
+{
+ struct vp27smpx_state *state = i2c_get_clientdata(client);
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+ kfree(state);
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+ .driver = {
+ .name = "vp27smpx",
+ },
+ .id = I2C_DRIVERID_VP27SMPX,
+ .attach_adapter = vp27smpx_probe,
+ .detach_client = vp27smpx_detach,
+ .command = vp27smpx_command,
+};
+
+
+static int __init vp27smpx_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit vp27smpx_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver);
+}
+
+module_init(vp27smpx_init_module);
+module_exit(vp27smpx_cleanup_module);
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 47366408637..08aaae07c7e 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -196,7 +196,6 @@ static struct video_device w9966_template = {
.owner = THIS_MODULE,
.name = W9966_DRIVERNAME,
.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
- .hardware = VID_HARDWARE_W9966,
.fops = &w9966_fops,
};
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index 8f31613b990..2ae1430f5f7 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -42,7 +42,6 @@
#include <asm/page.h>
#include <asm/uaccess.h>
#include <linux/page-flags.h>
-#include <linux/moduleparam.h>
#include "w9968cf.h"
#include "w9968cf_decoder.h"
@@ -445,8 +444,6 @@ static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
static u32 w9968cf_i2c_func(struct i2c_adapter*);
static int w9968cf_i2c_attach_inform(struct i2c_client*);
static int w9968cf_i2c_detach_inform(struct i2c_client*);
-static int w9968cf_i2c_control(struct i2c_adapter*, unsigned int cmd,
- unsigned long arg);
/* Memory management */
static void* rvmalloc(unsigned long size);
@@ -1544,21 +1541,12 @@ static int w9968cf_i2c_detach_inform(struct i2c_client* client)
}
-static int
-w9968cf_i2c_control(struct i2c_adapter* adapter, unsigned int cmd,
- unsigned long arg)
-{
- return 0;
-}
-
-
static int w9968cf_i2c_init(struct w9968cf_device* cam)
{
int err = 0;
static struct i2c_algorithm algo = {
.smbus_xfer = w9968cf_i2c_smbus_xfer,
- .algo_control = w9968cf_i2c_control,
.functionality = w9968cf_i2c_func,
};
@@ -2680,7 +2668,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp)
/* This the only safe way to prevent race conditions with disconnect */
if (!down_read_trylock(&w9968cf_disconnect))
- return -ERESTARTSYS;
+ return -EAGAIN;
cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
@@ -3561,7 +3549,6 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
strcpy(cam->v4ldev->name, symbolic(camlist, mod_id));
cam->v4ldev->owner = THIS_MODULE;
cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
- cam->v4ldev->hardware = VID_HARDWARE_W9968CF;
cam->v4ldev->fops = &w9968cf_fops;
cam->v4ldev->minor = video_nr[dev_nr];
cam->v4ldev->release = video_device_release;
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 703b741e46d..2c5665c8244 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -26,7 +26,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/param.h>
-#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/device.h>
@@ -656,7 +655,7 @@ static int zc0301_open(struct inode* inode, struct file* filp)
int err = 0;
if (!down_read_trylock(&zc0301_dev_lock))
- return -ERESTARTSYS;
+ return -EAGAIN;
cam = video_get_drvdata(video_devdata(filp));
@@ -1986,7 +1985,6 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera");
cam->v4ldev->owner = THIS_MODULE;
cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
- cam->v4ldev->hardware = 0;
cam->v4ldev->fops = &zc0301_fops;
cam->v4ldev->minor = video_nr[dev_nr];
cam->v4ldev->release = video_device_release;
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 73162a3a61d..6e0ac4c5c37 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -64,15 +64,15 @@
extern const struct zoran_format zoran_formats[];
static int card[BUZ_MAX] = { -1, -1, -1, -1 };
-module_param_array(card, int, NULL, 0);
+module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(card, "The type of card");
static int encoder[BUZ_MAX] = { -1, -1, -1, -1 };
-module_param_array(encoder, int, NULL, 0);
+module_param_array(encoder, int, NULL, 0444);
MODULE_PARM_DESC(encoder, "i2c TV encoder");
static int decoder[BUZ_MAX] = { -1, -1, -1, -1 };
-module_param_array(decoder, int, NULL, 0);
+module_param_array(decoder, int, NULL, 0444);
MODULE_PARM_DESC(decoder, "i2c TV decoder");
/*
@@ -84,29 +84,31 @@ MODULE_PARM_DESC(decoder, "i2c TV decoder");
*/
static unsigned long vidmem = 0; /* Video memory base address */
-module_param(vidmem, ulong, 0);
+module_param(vidmem, ulong, 0444);
+MODULE_PARM_DESC(vidmem, "Default video memory base address");
/*
Default input and video norm at startup of the driver.
*/
-static int default_input = 0; /* 0=Composite, 1=S-Video */
-module_param(default_input, int, 0);
+static unsigned int default_input = 0; /* 0=Composite, 1=S-Video */
+module_param(default_input, uint, 0444);
MODULE_PARM_DESC(default_input,
"Default input (0=Composite, 1=S-Video, 2=Internal)");
static int default_mux = 1; /* 6 Eyes input selection */
-module_param(default_mux, int, 0);
+module_param(default_mux, int, 0644);
MODULE_PARM_DESC(default_mux,
"Default 6 Eyes mux setting (Input selection)");
static int default_norm = 0; /* 0=PAL, 1=NTSC 2=SECAM */
-module_param(default_norm, int, 0);
+module_param(default_norm, int, 0444);
MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
-static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
-module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr, "video device number");
+/* /dev/videoN, -1 for autodetect */
+static int video_nr[BUZ_MAX] = {-1, -1, -1, -1};
+module_param_array(video_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)");
/*
Number and size of grab buffers for Video 4 Linux
@@ -127,28 +129,27 @@ MODULE_PARM_DESC(video_nr, "video device number");
int v4l_nbufs = 2;
int v4l_bufsize = 128; /* Everybody should be able to work with this setting */
-module_param(v4l_nbufs, int, 0);
+module_param(v4l_nbufs, int, 0644);
MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use");
-module_param(v4l_bufsize, int, 0);
+module_param(v4l_bufsize, int, 0644);
MODULE_PARM_DESC(v4l_bufsize, "Maximum size per V4L buffer (in kB)");
int jpg_nbufs = 32;
int jpg_bufsize = 512; /* max size for 100% quality full-PAL frame */
-module_param(jpg_nbufs, int, 0);
+module_param(jpg_nbufs, int, 0644);
MODULE_PARM_DESC(jpg_nbufs, "Maximum number of JPG buffers to use");
-module_param(jpg_bufsize, int, 0);
+module_param(jpg_bufsize, int, 0644);
MODULE_PARM_DESC(jpg_bufsize, "Maximum size per JPG buffer (in kB)");
int pass_through = 0; /* 1=Pass through TV signal when device is not used */
/* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */
-module_param(pass_through, int, 0);
+module_param(pass_through, int, 0644);
MODULE_PARM_DESC(pass_through,
"Pass TV signal through to TV-out when idling");
-static int debug = 1;
-int *zr_debug = &debug;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level (0-4)");
+int zr36067_debug = 1;
+module_param_named(debug, zr36067_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-5)");
MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver");
MODULE_AUTHOR("Serguei Miridonov");
@@ -161,12 +162,6 @@ static struct pci_device_id zr36067_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl);
-#define dprintk(num, format, args...) \
- do { \
- if (*zr_debug >= num) \
- printk(format, ##args); \
- } while (0)
-
int zoran_num; /* number of Buzs in use */
struct zoran zoran[BUZ_MAX];
@@ -1075,7 +1070,7 @@ test_interrupts (struct zoran *zr)
if (timeout) {
dprintk(1, ": time spent: %d\n", 1 * HZ - timeout);
}
- if (*zr_debug > 1)
+ if (zr36067_debug > 1)
print_interrupts(zr);
btwrite(icr, ZR36057_ICR);
}
@@ -1121,7 +1116,14 @@ zr36057_init (struct zoran *zr)
zr->timing = zr->card.tvn[zr->norm];
}
- zr->input = default_input = (default_input ? 1 : 0);
+ if (default_input > zr->card.inputs-1) {
+ dprintk(1,
+ KERN_WARNING
+ "%s: default_input value %d out of range (0-%d)\n",
+ ZR_DEVNAME(zr), default_input, zr->card.inputs-1);
+ default_input = 0;
+ }
+ zr->input = default_input;
/* Should the following be reset at every open ? */
zr->hue = 32768;
@@ -1153,12 +1155,12 @@ zr36057_init (struct zoran *zr)
*/
memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template));
strcpy(zr->video_dev->name, ZR_DEVNAME(zr));
- err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr);
+ err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]);
if (err < 0)
goto exit_unregister;
zoran_init_hardware(zr);
- if (*zr_debug > 2)
+ if (zr36067_debug > 2)
detect_guest_activity(zr);
test_interrupts(zr);
if (!pass_through) {
@@ -1233,8 +1235,14 @@ zoran_setup_videocodec (struct zoran *zr,
return m;
}
- m->magic = 0L; /* magic not used */
- m->type = VID_HARDWARE_ZR36067;
+ /* magic and type are unused for master struct. Makes sense only at
+ codec structs.
+ In the past, .type were initialized to the old V4L1 .hardware
+ value, as VID_HARDWARE_ZR36067
+ */
+ m->magic = 0L;
+ m->type = 0;
+
m->flags = CODEC_FLAG_ENCODER | CODEC_FLAG_DECODER;
strncpy(m->name, ZR_DEVNAME(zr), sizeof(m->name));
m->data = zr;
@@ -1620,7 +1628,7 @@ init_dc10_cards (void)
}
/* random nonsense */
- dprintk(5, KERN_DEBUG "Jotti is een held!\n");
+ dprintk(6, KERN_DEBUG "Jotti is een held!\n");
/* some mainboards might not do PCI-PCI data transfer well */
if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) {
diff --git a/drivers/media/video/zoran_card.h b/drivers/media/video/zoran_card.h
index ad997c30bee..8444ca0a5f3 100644
--- a/drivers/media/video/zoran_card.h
+++ b/drivers/media/video/zoran_card.h
@@ -30,6 +30,14 @@
#ifndef __ZORAN_CARD_H__
#define __ZORAN_CARD_H__
+extern int zr36067_debug;
+
+#define dprintk(num, format, args...) \
+ do { \
+ if (zr36067_debug >= num) \
+ printk(format, ##args); \
+ } while (0)
+
/* Anybody who uses more than four? */
#define BUZ_MAX 4
extern int zoran_num;
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
index ba2f4ed2948..68c7c505587 100644
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -52,6 +52,7 @@
#include "videocodec.h"
#include "zoran.h"
#include "zoran_device.h"
+#include "zoran_card.h"
#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | \
ZR36057_ISR_GIRQ1 | \
@@ -59,14 +60,6 @@
extern const struct zoran_format zoran_formats[];
-extern int *zr_debug;
-
-#define dprintk(num, format, args...) \
- do { \
- if (*zr_debug >= num) \
- printk(format, ##args); \
- } while (0)
-
static int lml33dpath = 0; /* 1 will use digital path in capture
* mode instead of analog. It can be
* used for picture adjustments using
@@ -76,7 +69,7 @@ static int lml33dpath = 0; /* 1 will use digital path in capture
* load on Bt819 input, there will be
* some image imperfections */
-module_param(lml33dpath, bool, 0);
+module_param(lml33dpath, bool, 0644);
MODULE_PARM_DESC(lml33dpath,
"Use digital path capture mode (on LML33 cards)");
@@ -174,7 +167,7 @@ post_office_read (struct zoran *zr,
static void
dump_guests (struct zoran *zr)
{
- if (*zr_debug > 2) {
+ if (zr36067_debug > 2) {
int i, guest[8];
for (i = 1; i < 8; i++) { // Don't read jpeg codec here
@@ -1271,7 +1264,7 @@ error_handler (struct zoran *zr,
zr->num_errors++;
/* Report error */
- if (*zr_debug > 1 && zr->num_errors <= 8) {
+ if (zr36067_debug > 1 && zr->num_errors <= 8) {
long frame;
frame =
zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
@@ -1531,7 +1524,7 @@ zoran_irq (int irq,
if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
- if (*zr_debug > 1 &&
+ if (zr36067_debug > 1 &&
(!zr->frame_num || zr->JPEG_error)) {
printk(KERN_INFO
"%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n",
@@ -1568,7 +1561,7 @@ zoran_irq (int irq,
zr->JPEG_missed;
}
- if (*zr_debug > 2 && zr->frame_num < 6) {
+ if (zr36067_debug > 2 && zr->frame_num < 6) {
int i;
printk("%s: seq=%ld stat_com:",
ZR_DEVNAME(zr), zr->jpg_seq_num);
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index 72a037b75d6..dd3d7d2c8b0 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -60,7 +60,6 @@
#include <linux/spinlock.h>
#define MAP_NR(x) virt_to_page(x)
-#define ZORAN_HARDWARE VID_HARDWARE_ZR36067
#define ZORAN_VID_TYPE ( \
VID_TYPE_CAPTURE | \
VID_TYPE_OVERLAY | \
@@ -200,14 +199,6 @@ const struct zoran_format zoran_formats[] = {
// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
-extern int *zr_debug;
-
-#define dprintk(num, format, args...) \
- do { \
- if (*zr_debug >= num) \
- printk(format, ##args); \
- } while (0)
-
extern int v4l_nbufs;
extern int v4l_bufsize;
extern int jpg_nbufs;
@@ -215,8 +206,8 @@ extern int jpg_bufsize;
extern int pass_through;
static int lock_norm = 0; /* 1=Don't change TV standard (norm) */
-module_param(lock_norm, int, 0);
-MODULE_PARM_DESC(lock_norm, "Users can't change norm");
+module_param(lock_norm, int, 0644);
+MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)");
#ifdef CONFIG_VIDEO_V4L2
/* small helper function for calculating buffersizes for v4l2
@@ -347,10 +338,7 @@ v4l_fbuffer_alloc (struct file *file)
if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) {
/* Use kmalloc */
- mem =
- (unsigned char *) kmalloc(fh->v4l_buffers.
- buffer_size,
- GFP_KERNEL);
+ mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL);
if (mem == 0) {
dprintk(1,
KERN_ERR
@@ -1106,12 +1094,10 @@ jpg_sync (struct file *file,
frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
/* buffer should now be in BUZ_STATE_DONE */
- if (*zr_debug > 0)
- if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE)
- dprintk(2,
- KERN_ERR
- "%s: jpg_sync() - internal state error\n",
- ZR_DEVNAME(zr));
+ if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE)
+ dprintk(2,
+ KERN_ERR "%s: jpg_sync() - internal state error\n",
+ ZR_DEVNAME(zr));
*bs = zr->jpg_buffers.buffer[frame].bs;
bs->frame = frame;
@@ -1298,7 +1284,7 @@ zoran_open (struct inode *inode,
}
dprintk(1, KERN_INFO "%s: zoran_open(%s, pid=[%d]), users(-)=%d\n",
- ZR_DEVNAME(zr), current->comm, current->pid, zr->user);
+ ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user);
/* now, create the open()-specific file_ops struct */
fh = kzalloc(sizeof(struct zoran_fh), GFP_KERNEL);
@@ -1371,7 +1357,7 @@ zoran_close (struct inode *inode,
struct zoran *zr = fh->zr;
dprintk(1, KERN_INFO "%s: zoran_close(%s, pid=[%d]), users(+)=%d\n",
- ZR_DEVNAME(zr), current->comm, current->pid, zr->user);
+ ZR_DEVNAME(zr), current->comm, task_pid_nr(current), zr->user);
/* kernel locks (fs/device.c), so don't do that ourselves
* (prevents deadlocks) */
@@ -1389,7 +1375,7 @@ zoran_close (struct inode *inode,
/* disable interrupts */
btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
- if (*zr_debug > 1)
+ if (zr36067_debug > 1)
print_interrupts(zr);
/* Overlay off */
@@ -3206,7 +3192,7 @@ zoran_do_ioctl (struct inode *inode,
"%s: VIDIOC_QUERYBUF - index=%d, type=%d\n",
ZR_DEVNAME(zr), buf->index, buf->type);
- memset(buf, 0, sizeof(buf));
+ memset(buf, 0, sizeof(*buf));
buf->type = type;
buf->index = index;
@@ -4672,7 +4658,6 @@ struct video_device zoran_template __devinitdata = {
#ifdef CONFIG_VIDEO_V4L2
.type2 = ZORAN_V4L2_VID_FLAGS,
#endif
- .hardware = ZORAN_HARDWARE,
.fops = &zoran_fops,
.release = &zoran_vdev_release,
.minor = -1
diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c
index 446ae8d5c3d..328ed6e7ac6 100644
--- a/drivers/media/video/zoran_procfs.c
+++ b/drivers/media/video/zoran_procfs.c
@@ -48,14 +48,7 @@
#include "videocodec.h"
#include "zoran.h"
#include "zoran_procfs.h"
-
-extern int *zr_debug;
-
-#define dprintk(num, format, args...) \
- do { \
- if (*zr_debug >= num) \
- printk(format, ##args); \
- } while (0)
+#include "zoran_card.h"
#ifdef CONFIG_PROC_FS
struct procfs_params_zr36067 {
diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c
index 62f77584fb8..dd084555da8 100644
--- a/drivers/media/video/zr36016.c
+++ b/drivers/media/video/zr36016.c
@@ -38,11 +38,11 @@
#include<linux/videodev.h> */
/* I/O commands, error codes */
-#include<asm/io.h>
+#include <asm/io.h>
//#include<errno.h>
/* v4l API */
-#include<linux/videodev.h>
+#include <linux/videodev.h>
/* headerfile of this module */
#include"zr36016.h"
diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c
index a6bbd125631..9f622e00c47 100644
--- a/drivers/media/video/zr36050.c
+++ b/drivers/media/video/zr36050.c
@@ -38,14 +38,14 @@
#include<linux/videodev.h> */
/* I/O commands, error codes */
-#include<asm/io.h>
+#include <asm/io.h>
//#include<errno.h>
/* headerfile of this module */
-#include"zr36050.h"
+#include "zr36050.h"
/* codec io API */
-#include"videocodec.h"
+#include "videocodec.h"
/* it doesn't make sense to have more than 20 or so,
just to prevent some unwanted loops */
diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zr36060.c
index 97c8f9b9dc1..1ef14fef08e 100644
--- a/drivers/media/video/zr36060.c
+++ b/drivers/media/video/zr36060.c
@@ -38,14 +38,14 @@
#include<linux/videodev.h> */
/* I/O commands, error codes */
-#include<asm/io.h>
+#include <asm/io.h>
//#include<errno.h>
/* headerfile of this module */
-#include"zr36060.h"
+#include "zr36060.h"
/* codec io API */
-#include"videocodec.h"
+#include "videocodec.h"
/* it doesn't make sense to have more than 20 or so,
just to prevent some unwanted loops */
diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig
index f55cc03a75c..a34a11d2fef 100644
--- a/drivers/message/fusion/Kconfig
+++ b/drivers/message/fusion/Kconfig
@@ -1,15 +1,19 @@
-menu "Fusion MPT device support"
+menuconfig FUSION
+ bool "Fusion MPT device support"
depends on PCI
+ ---help---
+ Say Y here to get to see options for Fusion Message
+ Passing Technology (MPT) drivers.
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
-config FUSION
- bool
- default n
+if FUSION
config FUSION_SPI
tristate "Fusion MPT ScsiHost drivers for SPI"
depends on PCI && SCSI
- select FUSION
select SCSI_SPI_ATTRS
---help---
SCSI HOST support for a parallel SCSI host adapters.
@@ -20,11 +24,11 @@ config FUSION_SPI
LSI53C1020A
LSI53C1030
LSI53C1035
+ ATTO UL4D
config FUSION_FC
tristate "Fusion MPT ScsiHost drivers for FC"
depends on PCI && SCSI
- select FUSION
select SCSI_FC_ATTRS
---help---
SCSI HOST support for a Fiber Channel host adapters.
@@ -37,12 +41,13 @@ config FUSION_FC
LSIFC929
LSIFC929X
LSIFC929XL
+ LSIFC949X
+ LSIFC949E
Brocade FC 410/420
config FUSION_SAS
tristate "Fusion MPT ScsiHost drivers for SAS"
depends on PCI && SCSI
- select FUSION
select SCSI_SAS_ATTRS
---help---
SCSI HOST support for a SAS host adapters.
@@ -53,10 +58,10 @@ config FUSION_SAS
LSISAS1068
LSISAS1064E
LSISAS1068E
+ LSISAS1078
config FUSION_MAX_SGE
int "Maximum number of scatter gather entries (16 - 128)"
- depends on FUSION
default "128"
range 16 128
help
@@ -104,7 +109,6 @@ config FUSION_LAN
config FUSION_LOGGING
bool "Fusion MPT logging facility"
- depends on FUSION
---help---
This turns on a logging facility that can be used to debug a number
of Fusion MPT related problems.
@@ -113,7 +117,7 @@ config FUSION_LOGGING
echo [level] > /sys/class/scsi_host/host#/debug_level
- There are various debug levels that an be found in the source:
+ There are various debug levels that can be found in the source:
file:drivers/message/fusion/mptdebug.h
-endmenu
+endif # FUSION
diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h
index 6a92e3d118f..1acbdd61b67 100644
--- a/drivers/message/fusion/lsi/mpi.h
+++ b/drivers/message/fusion/lsi/mpi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2007 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Corporation.
*
*
* Name: mpi.h
diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
index eda769730e3..2bd8adae0f0 100644
--- a/drivers/message/fusion/lsi/mpi_cnfg.h
+++ b/drivers/message/fusion/lsi/mpi_cnfg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2007 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Corporation.
*
*
* Name: mpi_cnfg.h
diff --git a/drivers/message/fusion/lsi/mpi_fc.h b/drivers/message/fusion/lsi/mpi_fc.h
index 51a6aeb990b..627acfbb862 100644
--- a/drivers/message/fusion/lsi/mpi_fc.h
+++ b/drivers/message/fusion/lsi/mpi_fc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 LSI Logic Corporation.
+ * Copyright (c) 2000-2004 LSI Corporation.
*
*
* Name: mpi_fc.h
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt
index a1f479057ea..241592ab13a 100644
--- a/drivers/message/fusion/lsi/mpi_history.txt
+++ b/drivers/message/fusion/lsi/mpi_history.txt
@@ -3,7 +3,7 @@
MPI Header File Change History
==============================
- Copyright (c) 2000-2007 LSI Logic Corporation.
+ Copyright (c) 2000-2007 LSI Corporation.
---------------------------------------
Header Set Release Version: 01.05.16
diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h
index 3a02615f12d..a9e3693601a 100644
--- a/drivers/message/fusion/lsi/mpi_init.h
+++ b/drivers/message/fusion/lsi/mpi_init.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2007 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Corporation.
*
*
* Name: mpi_init.h
diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h
index b1893d185bc..5cbb6bd048e 100644
--- a/drivers/message/fusion/lsi/mpi_ioc.h
+++ b/drivers/message/fusion/lsi/mpi_ioc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2007 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Corporation.
*
*
* Name: mpi_ioc.h
diff --git a/drivers/message/fusion/lsi/mpi_lan.h b/drivers/message/fusion/lsi/mpi_lan.h
index dc0b52ae83d..03253b53b78 100644
--- a/drivers/message/fusion/lsi/mpi_lan.h
+++ b/drivers/message/fusion/lsi/mpi_lan.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 LSI Logic Corporation.
+ * Copyright (c) 2000-2004 LSI Corporation.
*
*
* Name: mpi_lan.h
diff --git a/drivers/message/fusion/lsi/mpi_log_fc.h b/drivers/message/fusion/lsi/mpi_log_fc.h
index dc98d46f907..e4dafcefeec 100644
--- a/drivers/message/fusion/lsi/mpi_log_fc.h
+++ b/drivers/message/fusion/lsi/mpi_log_fc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved.
+ * Copyright (c) 2000-2001 LSI Corporation. All rights reserved.
*
* NAME: fc_log.h
* SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips
diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h
index 635bbe04513..6be1f6b6577 100644
--- a/drivers/message/fusion/lsi/mpi_log_sas.h
+++ b/drivers/message/fusion/lsi/mpi_log_sas.h
@@ -1,6 +1,6 @@
/***************************************************************************
* *
- * Copyright 2003 LSI Logic Corporation. All rights reserved. *
+ * Copyright 2003 LSI Corporation. All rights reserved. *
* *
* Description *
* ------------ *
diff --git a/drivers/message/fusion/lsi/mpi_raid.h b/drivers/message/fusion/lsi/mpi_raid.h
index 32819b1ec8e..2856108421d 100644
--- a/drivers/message/fusion/lsi/mpi_raid.h
+++ b/drivers/message/fusion/lsi/mpi_raid.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2007 LSI Logic Corporation.
+ * Copyright (c) 2001-2007 LSI Corporation.
*
*
* Name: mpi_raid.h
diff --git a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h
index 8e990a0fa7a..33fca83cefc 100644
--- a/drivers/message/fusion/lsi/mpi_sas.h
+++ b/drivers/message/fusion/lsi/mpi_sas.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 LSI Logic Corporation.
+ * Copyright (c) 2004-2006 LSI Corporation.
*
*
* Name: mpi_sas.h
diff --git a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h
index 20b66731577..ff8c37d3fdc 100644
--- a/drivers/message/fusion/lsi/mpi_targ.h
+++ b/drivers/message/fusion/lsi/mpi_targ.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 LSI Logic Corporation.
+ * Copyright (c) 2000-2004 LSI Corporation.
*
*
* Name: mpi_targ.h
diff --git a/drivers/message/fusion/lsi/mpi_tool.h b/drivers/message/fusion/lsi/mpi_tool.h
index aa9053da1f5..8834ae6ce0f 100644
--- a/drivers/message/fusion/lsi/mpi_tool.h
+++ b/drivers/message/fusion/lsi/mpi_tool.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2005 LSI Logic Corporation.
+ * Copyright (c) 2001-2005 LSI Corporation.
*
*
* Name: mpi_tool.h
diff --git a/drivers/message/fusion/lsi/mpi_type.h b/drivers/message/fusion/lsi/mpi_type.h
index 32cc9b1151b..08dad9c1e44 100644
--- a/drivers/message/fusion/lsi/mpi_type.h
+++ b/drivers/message/fusion/lsi/mpi_type.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 LSI Logic Corporation.
+ * Copyright (c) 2000-2004 LSI Corporation.
*
*
* Name: mpi_type.h
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 414c109f4cf..52fb216dfe7 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -2,10 +2,10 @@
* linux/drivers/message/fusion/mptbase.c
* This is the Fusion MPT base driver which supports multiple
* (SCSI + LAN) specialized protocol drivers.
- * For use with LSI Logic PCI chip/adapter(s)
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI PCI chip/adapter(s)
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -102,8 +102,6 @@ static int mfcounter = 0;
/*
* Public data...
*/
-int mpt_lan_index = -1;
-int mpt_stm_index = -1;
struct proc_dir_entry *mpt_proc_root_dir;
@@ -125,11 +123,14 @@ static MPT_EVHANDLER MptEvHandlers[MPT_MAX_PROTOCOL_DRIVERS];
static MPT_RESETHANDLER MptResetHandlers[MPT_MAX_PROTOCOL_DRIVERS];
static struct mpt_pci_driver *MptDeviceDriverHandlers[MPT_MAX_PROTOCOL_DRIVERS];
-static int mpt_base_index = -1;
-static int last_drv_idx = -1;
-
static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
+/*
+ * Driver Callback Index's
+ */
+static u8 mpt_base_index = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 last_drv_idx;
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* Forward protos...
@@ -235,6 +236,23 @@ static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
return 0;
}
+/**
+ * mpt_get_cb_idx - obtain cb_idx for registered driver
+ * @dclass: class driver enum
+ *
+ * Returns cb_idx, or zero means it wasn't found
+ **/
+static u8
+mpt_get_cb_idx(MPT_DRIVER_CLASS dclass)
+{
+ u8 cb_idx;
+
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--)
+ if (MptDriverClass[cb_idx] == dclass)
+ return cb_idx;
+ return 0;
+}
+
/*
* Process turbo (context) reply...
*/
@@ -243,8 +261,8 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
{
MPT_FRAME_HDR *mf = NULL;
MPT_FRAME_HDR *mr = NULL;
- int req_idx = 0;
- int cb_idx;
+ u16 req_idx = 0;
+ u8 cb_idx;
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
ioc->name, pa));
@@ -256,7 +274,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
break;
case MPI_CONTEXT_REPLY_TYPE_LAN:
- cb_idx = mpt_lan_index;
+ cb_idx = mpt_get_cb_idx(MPTLAN_DRIVER);
/*
* Blind set of mf to NULL here was fatal
* after lan_reply says "freeme"
@@ -277,7 +295,7 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
break;
case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET:
- cb_idx = mpt_stm_index;
+ cb_idx = mpt_get_cb_idx(MPTSTM_DRIVER);
mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa);
break;
default:
@@ -286,8 +304,8 @@ mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa)
}
/* Check for (valid) IO callback! */
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
- MptCallbacks[cb_idx] == NULL) {
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
+ MptCallbacks[cb_idx] == NULL) {
printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
__FUNCTION__, ioc->name, cb_idx);
goto out;
@@ -304,8 +322,8 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
{
MPT_FRAME_HDR *mf;
MPT_FRAME_HDR *mr;
- int req_idx;
- int cb_idx;
+ u16 req_idx;
+ u8 cb_idx;
int freeme;
u32 reply_dma_low;
@@ -331,7 +349,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
- DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr)
+ DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr);
/* Check/log IOC log info
*/
@@ -350,8 +368,8 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
/* Check for (valid) IO callback! */
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
- MptCallbacks[cb_idx] == NULL) {
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
+ MptCallbacks[cb_idx] == NULL) {
printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n",
__FUNCTION__, ioc->name, cb_idx);
freeme = 0;
@@ -433,8 +451,9 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
#ifdef CONFIG_FUSION_LOGGING
if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
- dmfprintk(ioc, printk(KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
- DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf)
+ dmfprintk(ioc, printk(MYIOC_s_INFO_FMT ": Original request frame (@%p) header\n",
+ ioc->name, mf));
+ DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf);
}
#endif
@@ -499,8 +518,8 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
u16 status;
status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
- dcprintk(ioc, printk(KERN_NOTICE " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
- status, le32_to_cpu(pReply->IOCLogInfo)));
+ dcprintk(ioc, printk(MYIOC_s_NOTE_FMT " IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+ ioc->name, status, le32_to_cpu(pReply->IOCLogInfo)));
pCfg->status = status;
if (status == MPI_IOCSTATUS_SUCCESS) {
@@ -563,28 +582,27 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
* in order to register separate callbacks; one for "normal" SCSI IO;
* one for MptScsiTaskMgmt requests; one for Scan/DV requests.
*
- * Returns a positive integer valued "handle" in the
- * range (and S.O.D. order) {N,...,7,6,5,...,1} if successful.
- * Any non-positive return value (including zero!) should be considered
- * an error by the caller.
+ * Returns u8 valued "handle" in the range (and S.O.D. order)
+ * {N,...,7,6,5,...,1} if successful.
+ * A return value of MPT_MAX_PROTOCOL_DRIVERS (including zero!) should be
+ * considered an error by the caller.
*/
-int
+u8
mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
{
- int i;
-
- last_drv_idx = -1;
+ u8 cb_idx;
+ last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS;
/*
* Search for empty callback slot in this order: {N,...,7,6,5,...,1}
* (slot/handle 0 is reserved!)
*/
- for (i = MPT_MAX_PROTOCOL_DRIVERS-1; i; i--) {
- if (MptCallbacks[i] == NULL) {
- MptCallbacks[i] = cbfunc;
- MptDriverClass[i] = dclass;
- MptEvHandlers[i] = NULL;
- last_drv_idx = i;
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if (MptCallbacks[cb_idx] == NULL) {
+ MptCallbacks[cb_idx] = cbfunc;
+ MptDriverClass[cb_idx] = dclass;
+ MptEvHandlers[cb_idx] = NULL;
+ last_drv_idx = cb_idx;
break;
}
}
@@ -601,9 +619,9 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass)
* module is unloaded.
*/
void
-mpt_deregister(int cb_idx)
+mpt_deregister(u8 cb_idx)
{
- if ((cb_idx >= 0) && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
+ if (cb_idx && (cb_idx < MPT_MAX_PROTOCOL_DRIVERS)) {
MptCallbacks[cb_idx] = NULL;
MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
MptEvHandlers[cb_idx] = NULL;
@@ -625,9 +643,9 @@ mpt_deregister(int cb_idx)
* Returns 0 for success.
*/
int
-mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
+mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc)
{
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return -1;
MptEvHandlers[cb_idx] = ev_cbfunc;
@@ -645,9 +663,9 @@ mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc)
* or when its module is unloaded.
*/
void
-mpt_event_deregister(int cb_idx)
+mpt_event_deregister(u8 cb_idx)
{
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return;
MptEvHandlers[cb_idx] = NULL;
@@ -665,9 +683,9 @@ mpt_event_deregister(int cb_idx)
* Returns 0 for success.
*/
int
-mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
+mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func)
{
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return -1;
MptResetHandlers[cb_idx] = reset_func;
@@ -684,9 +702,9 @@ mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func)
* or when its module is unloaded.
*/
void
-mpt_reset_deregister(int cb_idx)
+mpt_reset_deregister(u8 cb_idx)
{
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return;
MptResetHandlers[cb_idx] = NULL;
@@ -699,12 +717,12 @@ mpt_reset_deregister(int cb_idx)
* @cb_idx: MPT protocol driver index
*/
int
-mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
+mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx)
{
MPT_ADAPTER *ioc;
const struct pci_device_id *id;
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return -EINVAL;
MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
@@ -726,12 +744,12 @@ mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
* @cb_idx: MPT protocol driver index
*/
void
-mpt_device_driver_deregister(int cb_idx)
+mpt_device_driver_deregister(u8 cb_idx)
{
struct mpt_pci_driver *dd_cbfunc;
MPT_ADAPTER *ioc;
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
+ if (!cb_idx || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return;
dd_cbfunc = MptDeviceDriverHandlers[cb_idx];
@@ -749,14 +767,14 @@ mpt_device_driver_deregister(int cb_idx)
/**
* mpt_get_msg_frame - Obtain a MPT request frame from the pool (of 1024)
* allocated per MPT adapter.
- * @handle: Handle of registered MPT protocol driver
+ * @cb_idx: Handle of registered MPT protocol driver
* @ioc: Pointer to MPT adapter structure
*
* Returns pointer to a MPT request frame or %NULL if none are available
* or IOC is not active.
*/
MPT_FRAME_HDR*
-mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
+mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc)
{
MPT_FRAME_HDR *mf;
unsigned long flags;
@@ -766,7 +784,8 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
#ifdef MFCNT
if (!ioc->active)
- printk(KERN_WARNING "IOC Not Active! mpt_get_msg_frame returning NULL!\n");
+ printk(MYIOC_s_WARN_FMT "IOC Not Active! mpt_get_msg_frame "
+ "returning NULL!\n", ioc->name);
#endif
/* If interrupts are not attached, do not return a request frame */
@@ -781,13 +800,14 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
u.frame.linkage.list);
list_del(&mf->u.frame.linkage.list);
mf->u.frame.linkage.arg1 = 0;
- mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
/* u16! */
req_idx = req_offset / ioc->req_sz;
mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
- ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame; /* Default, will be changed if necessary in SG generation */
+ /* Default, will be changed if necessary in SG generation */
+ ioc->RequestNB[req_idx] = ioc->NB_for_64_byte_frame;
#ifdef MFCNT
ioc->mfcnt++;
#endif
@@ -798,14 +818,17 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
#ifdef MFCNT
if (mf == NULL)
- printk(KERN_WARNING "IOC Active. No free Msg Frames! Count 0x%x Max 0x%x\n", ioc->mfcnt, ioc->req_depth);
+ printk(MYIOC_s_WARN_FMT "IOC Active. No free Msg Frames! "
+ "Count 0x%x Max 0x%x\n", ioc->name, ioc->mfcnt,
+ ioc->req_depth);
mfcounter++;
if (mfcounter == PRINT_MF_COUNT)
- printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
+ printk(MYIOC_s_INFO_FMT "MF Count 0x%x Max 0x%x \n", ioc->name,
+ ioc->mfcnt, ioc->req_depth);
#endif
- dmfprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
- ioc->name, handle, ioc->id, mf));
+ dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_get_msg_frame(%d,%d), got mf=%p\n",
+ ioc->name, cb_idx, ioc->id, mf));
return mf;
}
@@ -813,7 +836,7 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
/**
* mpt_put_msg_frame - Send a protocol specific MPT request frame
* to a IOC.
- * @handle: Handle of registered MPT protocol driver
+ * @cb_idx: Handle of registered MPT protocol driver
* @ioc: Pointer to MPT adapter structure
* @mf: Pointer to MPT request frame
*
@@ -821,14 +844,14 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc)
* specific MPT adapter.
*/
void
-mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
+mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
{
u32 mf_dma_addr;
int req_offset;
u16 req_idx; /* Request index */
/* ensure values are reset properly! */
- mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx; /* byte */
req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
/* u16! */
req_idx = req_offset / ioc->req_sz;
@@ -838,10 +861,44 @@ mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
- dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d "
+ "RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx,
+ ioc->RequestNB[req_idx]));
CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
}
+/**
+ * mpt_put_msg_frame_hi_pri - Send a protocol specific MPT request frame
+ * to a IOC using hi priority request queue.
+ * @cb_idx: Handle of registered MPT protocol driver
+ * @ioc: Pointer to MPT adapter structure
+ * @mf: Pointer to MPT request frame
+ *
+ * This routine posts a MPT request frame to the request post FIFO of a
+ * specific MPT adapter.
+ **/
+void
+mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf)
+{
+ u32 mf_dma_addr;
+ int req_offset;
+ u16 req_idx; /* Request index */
+
+ /* ensure values are reset properly! */
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
+ req_offset = (u8 *)mf - (u8 *)ioc->req_frames;
+ req_idx = req_offset / ioc->req_sz;
+ mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
+ mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
+
+ DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
+
+ mf_dma_addr = (ioc->req_frames_low_dma + req_offset);
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d\n",
+ ioc->name, mf_dma_addr, req_idx));
+ CHIPREG_WRITE32(&ioc->chip->RequestHiPriFifo, mf_dma_addr);
+}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_free_msg_frame - Place MPT request frame back on FreeQ.
@@ -899,7 +956,7 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_send_handshake_request - Send MPT request via doorbell handshake method.
- * @handle: Handle of registered MPT protocol driver
+ * @cb_idx: Handle of registered MPT protocol driver
* @ioc: Pointer to MPT adapter structure
* @reqBytes: Size of the request in bytes
* @req: Pointer to MPT request frame
@@ -914,7 +971,7 @@ mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr)
* Returns 0 for success, non-zero for failure.
*/
int
-mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
+mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag)
{
int r = 0;
u8 *req_as_bytes;
@@ -934,7 +991,7 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req,
if (reqBytes >= 12 && ii >= 0 && ii < ioc->req_depth) {
MPT_FRAME_HDR *mf = (MPT_FRAME_HDR*)req;
mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(ii);
- mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle;
+ mf->u.frame.hwhdr.msgctxu.fld.cb_idx = cb_idx;
}
/* Make sure there are no doorbells */
@@ -953,7 +1010,7 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req,
if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
return -5;
- dhsprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
+ dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_send_handshake_request start, WaitCnt=%d\n",
ioc->name, ii));
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
@@ -1395,11 +1452,13 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
{
MPT_ADAPTER *ioc;
u8 __iomem *mem;
+ u8 __iomem *pmem;
unsigned long mem_phys;
unsigned long port;
u32 msize;
u32 psize;
int ii;
+ u8 cb_idx;
int r = -ENODEV;
u8 revision;
u8 pcixcmd;
@@ -1408,35 +1467,39 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
struct proc_dir_entry *dent, *ent;
#endif
+ if (mpt_debug_level)
+ printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
+
+ if (pci_enable_device(pdev))
+ return r;
+
ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
if (ioc == NULL) {
printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
return -ENOMEM;
}
-
ioc->debug_level = mpt_debug_level;
- if (mpt_debug_level)
- printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
-
- if (pci_enable_device(pdev))
- return r;
+ ioc->id = mpt_ids++;
+ sprintf(ioc->name, "ioc%d", ioc->id);
- dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name));
if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
- dprintk(ioc, printk(KERN_INFO MYNAM
- ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT
+ ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n", ioc->name));
} else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
+ printk(MYIOC_s_WARN_FMT ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n",
+ ioc->name);
+ kfree(ioc);
return r;
}
if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
- dprintk(ioc, printk(KERN_INFO MYNAM
- ": Using 64 bit consistent mask\n"));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT
+ ": Using 64 bit consistent mask\n", ioc->name));
} else {
- dprintk(ioc, printk(KERN_INFO MYNAM
- ": Not using 64 bit consistent mask\n"));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT
+ ": Not using 64 bit consistent mask\n", ioc->name));
}
ioc->alloc_total = sizeof(MPT_ADAPTER);
@@ -1475,7 +1538,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
/* Find lookup slot. */
INIT_LIST_HEAD(&ioc->list);
- ioc->id = mpt_ids++;
mem_phys = msize = 0;
port = psize = 0;
@@ -1501,25 +1563,23 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
/*mem = ioremap(mem_phys, msize);*/
mem = ioremap(mem_phys, msize);
if (mem == NULL) {
- printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
+ printk(MYIOC_s_ERR_FMT "Unable to map adapter memory!\n", ioc->name);
kfree(ioc);
return -EINVAL;
}
ioc->memmap = mem;
- dinitprintk(ioc, printk(KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "mem = %p, mem_phys = %lx\n", ioc->name, mem, mem_phys));
- dinitprintk(ioc, printk(KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
- &ioc->facts, &ioc->pfacts[0]));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "facts @ %p, pfacts[0] @ %p\n",
+ ioc->name, &ioc->facts, &ioc->pfacts[0]));
ioc->mem_phys = mem_phys;
ioc->chip = (SYSIF_REGS __iomem *)mem;
/* Save Port IO values in case we need to do downloadboot */
- {
- u8 *pmem = (u8*)port;
- ioc->pio_mem_phys = port;
- ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
- }
+ ioc->pio_mem_phys = port;
+ pmem = (u8 __iomem *)port;
+ ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
@@ -1591,8 +1651,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
if (ioc->errata_flag_1064)
pci_disable_io_access(pdev);
- sprintf(ioc->name, "ioc%d", ioc->id);
-
spin_lock_init(&ioc->FreeQlock);
/* Disable all! */
@@ -1609,9 +1667,8 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
CAN_SLEEP)) != 0){
- printk(KERN_WARNING MYNAM
- ": WARNING - %s did not initialize properly! (%d)\n",
- ioc->name, r);
+ printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
+ ioc->name, r);
list_del(&ioc->list);
if (ioc->alt_ioc)
@@ -1623,10 +1680,10 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* call per device driver probe entry point */
- for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
- if(MptDeviceDriverHandlers[ii] &&
- MptDeviceDriverHandlers[ii]->probe) {
- MptDeviceDriverHandlers[ii]->probe(pdev,id);
+ for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
+ if(MptDeviceDriverHandlers[cb_idx] &&
+ MptDeviceDriverHandlers[cb_idx]->probe) {
+ MptDeviceDriverHandlers[cb_idx]->probe(pdev,id);
}
}
@@ -1663,7 +1720,7 @@ mpt_detach(struct pci_dev *pdev)
{
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
char pname[32];
- int ii;
+ u8 cb_idx;
sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
remove_proc_entry(pname, NULL);
@@ -1673,10 +1730,10 @@ mpt_detach(struct pci_dev *pdev)
remove_proc_entry(pname, NULL);
/* call per device driver remove entry point */
- for(ii=0; ii<MPT_MAX_PROTOCOL_DRIVERS; ii++) {
- if(MptDeviceDriverHandlers[ii] &&
- MptDeviceDriverHandlers[ii]->remove) {
- MptDeviceDriverHandlers[ii]->remove(pdev);
+ for(cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
+ if(MptDeviceDriverHandlers[cb_idx] &&
+ MptDeviceDriverHandlers[cb_idx]->remove) {
+ MptDeviceDriverHandlers[cb_idx]->remove(pdev);
}
}
@@ -1788,7 +1845,7 @@ mpt_resume(struct pci_dev *pdev)
#endif
static int
-mpt_signal_reset(int index, MPT_ADAPTER *ioc, int reset_phase)
+mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase)
{
if ((MptDriverClass[index] == MPTSPI_DRIVER &&
ioc->bus_type != SPI) ||
@@ -1830,14 +1887,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
int hard;
int rc=0;
int ii;
+ u8 cb_idx;
int handlers;
int ret = 0;
int reset_alt_ioc_active = 0;
int irq_allocated = 0;
u8 *a;
- printk(KERN_INFO MYNAM ": Initiating %s %s\n",
- ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
+ printk(MYIOC_s_INFO_FMT "Initiating %s\n", ioc->name,
+ reason == MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
/* Disable reply interrupts (also blocks FreeQ) */
CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
@@ -1858,21 +1916,19 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) {
if (hard_reset_done == -4) {
- printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n",
- ioc->name);
+ printk(MYIOC_s_WARN_FMT "Owned by PEER..skipping!\n",
+ ioc->name);
if (reset_alt_ioc_active && ioc->alt_ioc) {
/* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
- dprintk(ioc, printk(KERN_INFO MYNAM
- ": alt-%s reply irq re-enabled\n",
- ioc->alt_ioc->name));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT
+ "alt_ioc reply irq re-enabled\n", ioc->alt_ioc->name));
CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
ioc->alt_ioc->active = 1;
}
} else {
- printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n",
- ioc->name);
+ printk(MYIOC_s_WARN_FMT "NOT READY!\n", ioc->name);
}
return -1;
}
@@ -1884,9 +1940,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if ((rc = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0)
alt_ioc_ready = 1;
else
- printk(KERN_WARNING MYNAM
- ": alt-%s: Not ready WARNING!\n",
- ioc->alt_ioc->name);
+ printk(MYIOC_s_WARN_FMT "alt_ioc not ready!\n", ioc->alt_ioc->name);
}
for (ii=0; ii<5; ii++) {
@@ -1897,7 +1951,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if (ii == 5) {
- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Retry IocFacts failed rc=%x\n", ioc->name, rc));
ret = -2;
} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
MptDisplayIocCapabilities(ioc);
@@ -1906,14 +1961,14 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if (alt_ioc_ready) {
if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
+ "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
/* Retry - alt IOC was initialized once
*/
rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
}
if (rc) {
dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
+ "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
alt_ioc_ready = 0;
reset_alt_ioc_active = 0;
} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
@@ -1931,13 +1986,12 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if (ioc->pcidev->irq) {
if (mpt_msi_enable && !pci_enable_msi(ioc->pcidev))
printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
- ioc->name);
+ ioc->name);
rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
- IRQF_SHARED, ioc->name, ioc);
+ IRQF_SHARED, ioc->name, ioc);
if (rc < 0) {
printk(MYIOC_s_ERR_FMT "Unable to allocate "
- "interrupt %d!\n", ioc->name,
- ioc->pcidev->irq);
+ "interrupt %d!\n", ioc->name, ioc->pcidev->irq);
if (mpt_msi_enable)
pci_disable_msi(ioc->pcidev);
return -EBUSY;
@@ -1946,8 +2000,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
ioc->pci_irq = ioc->pcidev->irq;
pci_set_master(ioc->pcidev); /* ?? */
pci_set_drvdata(ioc->pcidev, ioc);
- dprintk(ioc, printk(KERN_INFO MYNAM ": %s installed at interrupt "
- "%d\n", ioc->name, ioc->pcidev->irq));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt "
+ "%d\n", ioc->name, ioc->pcidev->irq));
}
}
@@ -1966,8 +2020,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
ret = -4;
// NEW!
if (alt_ioc_ready && ((rc = PrimeIocFifos(ioc->alt_ioc)) != 0)) {
- printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n",
- ioc->alt_ioc->name, rc);
+ printk(MYIOC_s_WARN_FMT ": alt_ioc (%d) FIFO mgmt alloc!\n",
+ ioc->alt_ioc->name, rc);
alt_ioc_ready = 0;
reset_alt_ioc_active = 0;
}
@@ -1976,16 +2030,15 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if ((rc = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) {
alt_ioc_ready = 0;
reset_alt_ioc_active = 0;
- printk(KERN_WARNING MYNAM
- ": alt-%s: (%d) init failure WARNING!\n",
- ioc->alt_ioc->name, rc);
+ printk(MYIOC_s_WARN_FMT "alt_ioc (%d) init failure!\n",
+ ioc->alt_ioc->name, rc);
}
}
if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
if (ioc->upload_fw) {
ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "firmware upload required!\n", ioc->name));
+ "firmware upload required!\n", ioc->name));
/* Controller is not operational, cannot do upload
*/
@@ -2001,12 +2054,13 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
* mpt_diag_reset)
*/
ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- ": mpt_upload: alt_%s has cached_fw=%p \n",
- ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
+ "mpt_upload: alt_%s has cached_fw=%p \n",
+ ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
ioc->alt_ioc->cached_fw = NULL;
}
} else {
- printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
+ printk(MYIOC_s_WARN_FMT
+ "firmware upload failure!\n", ioc->name);
ret = -5;
}
}
@@ -2021,8 +2075,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
if (reset_alt_ioc_active && ioc->alt_ioc) {
/* (re)Enable alt-IOC! (reply interrupt) */
- dinitprintk(ioc, printk(KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
- ioc->alt_ioc->name));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "alt_ioc reply irq re-enabled\n",
+ ioc->alt_ioc->name));
CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
ioc->alt_ioc->active = 1;
}
@@ -2075,10 +2129,8 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
(void) GetLanConfigPages(ioc);
a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "LanAddr = %02X:%02X:%02X:"
- "%02X:%02X:%02X\n",
- ioc->name, a[5], a[4],
- a[3], a[2], a[1], a[0] ));
+ "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
+ ioc->name, a[5], a[4], a[3], a[2], a[1], a[0]));
}
} else {
@@ -2114,20 +2166,20 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
*/
if (hard_reset_done) {
rc = handlers = 0;
- for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
- if ((ret == 0) && MptResetHandlers[ii]) {
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if ((ret == 0) && MptResetHandlers[cb_idx]) {
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Calling IOC post_reset handler #%d\n",
- ioc->name, ii));
- rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
+ "Calling IOC post_reset handler #%d\n",
+ ioc->name, cb_idx));
+ rc += mpt_signal_reset(cb_idx, ioc, MPT_IOC_POST_RESET);
handlers++;
}
- if (alt_ioc_ready && MptResetHandlers[ii]) {
+ if (alt_ioc_ready && MptResetHandlers[cb_idx]) {
drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "Calling alt-%s post_reset handler #%d\n",
- ioc->name, ioc->alt_ioc->name, ii));
- rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
+ "Calling IOC post_reset handler #%d\n",
+ ioc->alt_ioc->name, cb_idx));
+ rc += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_POST_RESET);
handlers++;
}
}
@@ -2166,8 +2218,8 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
" searching for devfn match on %x or %x\n",
- ioc->name, pci_name(pdev), pdev->bus->number,
- pdev->devfn, func-1, func+1));
+ ioc->name, pci_name(pdev), pdev->bus->number,
+ pdev->devfn, func-1, func+1));
peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1));
if (!peer) {
@@ -2181,15 +2233,15 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev)
if (_pcidev == peer) {
/* Paranoia checks */
if (ioc->alt_ioc != NULL) {
- printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+ printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
ioc->name, ioc->alt_ioc->name);
break;
} else if (ioc_srch->alt_ioc != NULL) {
- printk(KERN_WARNING MYNAM ": Oops, already bound (%s <==> %s)!\n",
+ printk(MYIOC_s_WARN_FMT "Oops, already bound to %s!\n",
ioc_srch->name, ioc_srch->alt_ioc->name);
break;
}
- dprintk(ioc, printk(KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT "FOUND! binding to %s\n",
ioc->name, ioc_srch->name));
ioc_srch->alt_ioc = ioc;
ioc->alt_ioc = ioc_srch;
@@ -2210,10 +2262,11 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
int ret;
if (ioc->cached_fw != NULL) {
- ddlprintk(ioc, printk(KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
+ ddlprintk(ioc, printk(MYIOC_s_INFO_FMT
+ "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name));
if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
- printk(KERN_WARNING MYNAM
- ": firmware downloadboot failure (%d)!\n", ret);
+ printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n",
+ ioc->name, ret);
}
}
@@ -2225,8 +2278,8 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
if (ioc->alloc != NULL) {
sz = ioc->alloc_sz;
- dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s.free @ %p, sz=%d bytes\n",
- ioc->name, ioc->alloc, ioc->alloc_sz));
+ dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "free @ %p, sz=%d bytes\n",
+ ioc->name, ioc->alloc, ioc->alloc_sz));
pci_free_consistent(ioc->pcidev, sz,
ioc->alloc, ioc->alloc_dma);
ioc->reply_frames = NULL;
@@ -2286,15 +2339,14 @@ mpt_adapter_disable(MPT_ADAPTER *ioc)
if (ioc->HostPageBuffer != NULL) {
if((ret = mpt_host_page_access_control(ioc,
MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) {
- printk(KERN_ERR MYNAM
- ": %s: host page buffers free failed (%d)!\n",
- __FUNCTION__, ret);
+ printk(MYIOC_s_ERR_FMT
+ "host page buffers free failed (%d)!\n",
+ ioc->name, ret);
}
- dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n",
+ dexitprintk(ioc, printk(MYIOC_s_INFO_FMT "HostPageBuffer free @ %p, sz=%d bytes\n",
ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
- ioc->HostPageBuffer,
- ioc->HostPageBuffer_dma);
+ ioc->HostPageBuffer, ioc->HostPageBuffer_dma);
ioc->HostPageBuffer = NULL;
ioc->HostPageBuffer_sz = 0;
ioc->alloc_total -= ioc->HostPageBuffer_sz;
@@ -2336,7 +2388,7 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
#if defined(CONFIG_MTRR) && 0
if (ioc->mtrr_reg > 0) {
mtrr_del(ioc->mtrr_reg, 0, 0);
- dprintk(ioc, printk(KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT "MTRR region de-registered\n", ioc->name));
}
#endif
@@ -2344,8 +2396,8 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc)
list_del(&ioc->list);
sz_last = ioc->alloc_total;
- dprintk(ioc, printk(KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
- ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
+ dprintk(ioc, printk(MYIOC_s_INFO_FMT "free'd %d of %d bytes\n",
+ ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
if (ioc->alt_ioc)
ioc->alt_ioc->alt_ioc = NULL;
@@ -2424,7 +2476,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
/* Get current [raw] IOC state */
ioc_state = mpt_GetIocState(ioc, 0);
- dhsprintk(ioc, printk(KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
+ dhsprintk(ioc, printk(MYIOC_s_INFO_FMT "MakeIocReady [raw] state=%08x\n", ioc->name, ioc_state));
/*
* Check to see if IOC got left/stuck in doorbell handshake
@@ -2446,9 +2498,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
statefault = 2;
printk(MYIOC_s_WARN_FMT "IOC is in FAULT state!!!\n",
- ioc->name);
- printk(KERN_WARNING " FAULT code = %04xh\n",
- ioc_state & MPI_DOORBELL_DATA_MASK);
+ ioc->name);
+ printk(MYIOC_s_WARN_FMT " FAULT code = %04xh\n",
+ ioc->name, ioc_state & MPI_DOORBELL_DATA_MASK);
}
/*
@@ -2464,9 +2516,9 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag)
* Else, fall through to KickStart case
*/
whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
- dinitprintk(ioc, printk(KERN_INFO MYNAM
- ": whoinit 0x%x statefault %d force %d\n",
- whoinit, statefault, force));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT
+ "whoinit 0x%x statefault %d force %d\n",
+ ioc->name, whoinit, statefault, force));
if (whoinit == MPI_WHOINIT_PCI_PEER)
return -4;
else {
@@ -2549,7 +2601,6 @@ mpt_GetIocState(MPT_ADAPTER *ioc, int cooked)
/* Get! */
s = CHIPREG_READ32(&ioc->chip->Doorbell);
-// dprintk((MYIOC_s_INFO_FMT "raw state = %08x\n", ioc->name, s));
sc = s & MPI_IOC_STATE_MASK;
/* Save! */
@@ -2581,9 +2632,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
/* IOC *must* NOT be in RESET state! */
if (ioc->last_state == MPI_IOC_STATE_RESET) {
- printk(KERN_ERR MYNAM ": ERROR - Can't get IOCFacts, %s NOT READY! (%08x)\n",
- ioc->name,
- ioc->last_state );
+ printk(MYIOC_s_ERR_FMT "Can't get IOCFacts NOT READY! (%08x)\n",
+ ioc->name, ioc->last_state );
return -44;
}
@@ -2703,8 +2753,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason)
}
ioc->NBShiftFactor = shiftFactor;
dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
- ioc->name, vv, shiftFactor, r));
+ "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
+ ioc->name, vv, shiftFactor, r));
if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
/*
@@ -2757,9 +2807,8 @@ GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag)
/* IOC *must* NOT be in RESET state! */
if (ioc->last_state == MPI_IOC_STATE_RESET) {
- printk(KERN_ERR MYNAM ": ERROR - Can't get PortFacts, %s NOT READY! (%08x)\n",
- ioc->name,
- ioc->last_state );
+ printk(MYIOC_s_ERR_FMT "Can't get PortFacts NOT READY! (%08x)\n",
+ ioc->name, ioc->last_state );
return -4;
}
@@ -2934,7 +2983,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
state = mpt_GetIocState(ioc, 1);
count++;
}
- dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wait IOC_OPERATIONAL state (cnt=%d)\n",
ioc->name, count));
ioc->aen_event_read_flag=0;
@@ -3027,10 +3076,9 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc)
int sz;
sz = ioc->facts.FWImageSize;
- dinitprintk(ioc, printk(KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
- ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
- pci_free_consistent(ioc->pcidev, sz,
- ioc->cached_fw, ioc->cached_fw_dma);
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n",
+ ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
+ pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma);
ioc->cached_fw = NULL;
return;
@@ -3054,7 +3102,6 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc)
static int
mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
{
- u8 request[ioc->req_sz];
u8 reply[sizeof(FWUploadReply_t)];
FWUpload_t *prequest;
FWUploadReply_t *preply;
@@ -3071,8 +3118,8 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
mpt_alloc_fw_memory(ioc, sz);
- dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
- ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n",
+ ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
if (ioc->cached_fw == NULL) {
/* Major Failure.
@@ -3080,11 +3127,16 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
return -ENOMEM;
}
- prequest = (FWUpload_t *)&request;
- preply = (FWUploadReply_t *)&reply;
+ prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) :
+ kzalloc(ioc->req_sz, GFP_KERNEL);
+ if (!prequest) {
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "fw upload failed "
+ "while allocating memory \n", ioc->name));
+ mpt_free_fw_memory(ioc);
+ return -ENOMEM;
+ }
- /* Destination... */
- memset(prequest, 0, ioc->req_sz);
+ preply = (FWUploadReply_t *)&reply;
reply_sz = sizeof(reply);
memset(preply, 0, reply_sz);
@@ -3096,21 +3148,22 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
ptcsge->DetailsLength = 12;
ptcsge->Flags = MPI_SGE_FLAGS_TRANSACTION_ELEMENT;
ptcsge->ImageSize = cpu_to_le32(sz);
+ ptcsge++;
sgeoffset = sizeof(FWUpload_t) - sizeof(SGE_MPI_UNION) + sizeof(FWUploadTCSGE_t);
flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | sz;
- mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
+ mpt_add_sge((char *)ptcsge, flagsLength, ioc->cached_fw_dma);
sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
- dinitprintk(ioc, printk(KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
- prequest, sgeoffset));
- DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest)
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
+ ioc->name, prequest, sgeoffset));
+ DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest);
ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
- dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
+ dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Upload completed rc=%x \n", ioc->name, ii));
cmdStatus = -EFAULT;
if (ii == 0) {
@@ -3135,6 +3188,7 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag)
ioc->name));
mpt_free_fw_memory(ioc);
}
+ kfree(prequest);
return cmdStatus;
}
@@ -3381,7 +3435,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
u32 ioc_state=0;
int cnt,cntdn;
- dinitprintk(ioc, printk(KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
+ dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStarting!\n", ioc->name));
if (ioc->bus_type == SPI) {
/* Always issue a Msg Unit Reset first. This will clear some
* SCSI bus hang conditions.
@@ -3400,7 +3454,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
return hard_reset_done;
dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
- ioc->name));
+ ioc->name));
cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2; /* 2 seconds */
for (cnt=0; cnt<cntdn; cnt++) {
@@ -3417,8 +3471,8 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
}
}
- printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
- ioc->name, ioc_state);
+ dinitprintk(ioc, printk(MYIOC_s_ERR_FMT "Failed to come READY after reset! IocState=%x\n",
+ ioc->name, mpt_GetIocState(ioc, 0)));
return -1;
}
@@ -3560,20 +3614,20 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
* MptResetHandlers[] registered yet.
*/
{
- int ii;
+ u8 cb_idx;
int r = 0;
- for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
- if (MptResetHandlers[ii]) {
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if (MptResetHandlers[cb_idx]) {
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Calling IOC pre_reset handler #%d\n",
- ioc->name, ii));
- r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
+ ioc->name, cb_idx));
+ r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_PRE_RESET);
if (ioc->alt_ioc) {
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Calling alt-%s pre_reset handler #%d\n",
- ioc->name, ioc->alt_ioc->name, ii));
- r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
+ ioc->name, ioc->alt_ioc->name, cb_idx));
+ r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_PRE_RESET);
}
}
}
@@ -3606,8 +3660,8 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
}
if ((count = mpt_downloadboot(ioc,
(MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
- printk(KERN_WARNING MYNAM
- ": firmware downloadboot failure (%d)!\n", count);
+ printk(MYIOC_s_WARN_FMT
+ "firmware downloadboot failure (%d)!\n", ioc->name, count);
}
} else {
@@ -3750,8 +3804,8 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag)
if (sleepFlag != CAN_SLEEP)
count *= 10;
- printk(KERN_ERR MYNAM ": %s: ERROR - Wait IOC_READY state timeout(%d)!\n",
- ioc->name, (int)((count+5)/HZ));
+ printk(MYIOC_s_ERR_FMT "Wait IOC_READY state timeout(%d)!\n",
+ ioc->name, (int)((count+5)/HZ));
return -ETIME;
}
@@ -4144,7 +4198,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req,
}
dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
- DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req)
+ DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req);
dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
@@ -4349,7 +4403,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
#endif
dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
- DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply)
+ DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply);
dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
ioc->name, t, u16cnt/2));
@@ -4824,8 +4878,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
- ddvprintk(ioc, printk(KERN_INFO MYNAM
- " :%s noQas due to Capabilities=%x\n",
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "noQas due to Capabilities=%x\n",
ioc->name, pPP0->Capabilities));
}
ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
@@ -4888,6 +4942,38 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum)
/* Nvram data is left with INVALID mark
*/
rc = 1;
+ } else if (ioc->pcidev->vendor == PCI_VENDOR_ID_ATTO) {
+
+ /* This is an ATTO adapter, read Page2 accordingly
+ */
+ ATTO_SCSIPortPage2_t *pPP2 = (ATTO_SCSIPortPage2_t *) pbuf;
+ ATTODeviceInfo_t *pdevice = NULL;
+ u16 ATTOFlags;
+
+ /* Save the Port Page 2 data
+ * (reformat into a 32bit quantity)
+ */
+ for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) {
+ pdevice = &pPP2->DeviceSettings[ii];
+ ATTOFlags = le16_to_cpu(pdevice->ATTOFlags);
+ data = 0;
+
+ /* Translate ATTO device flags to LSI format
+ */
+ if (ATTOFlags & ATTOFLAG_DISC)
+ data |= (MPI_SCSIPORTPAGE2_DEVICE_DISCONNECT_ENABLE);
+ if (ATTOFlags & ATTOFLAG_ID_ENB)
+ data |= (MPI_SCSIPORTPAGE2_DEVICE_ID_SCAN_ENABLE);
+ if (ATTOFlags & ATTOFLAG_LUN_ENB)
+ data |= (MPI_SCSIPORTPAGE2_DEVICE_LUN_SCAN_ENABLE);
+ if (ATTOFlags & ATTOFLAG_TAGGED)
+ data |= (MPI_SCSIPORTPAGE2_DEVICE_TAG_QUEUE_ENABLE);
+ if (!(ATTOFlags & ATTOFLAG_WIDE_ENB))
+ data |= (MPI_SCSIPORTPAGE2_DEVICE_WIDE_DISABLE);
+
+ data = (data << 16) | (pdevice->Period << 8) | 10;
+ ioc->spi_data.nvram[ii] = data;
+ }
} else {
SCSIPortPage2_t *pPP2 = (SCSIPortPage2_t *) pbuf;
MpiDeviceInfo_t *pdevice = NULL;
@@ -5701,10 +5787,10 @@ mpt_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
CONFIGPARMS *pCfg;
unsigned long flags;
- dprintk(ioc, printk(KERN_DEBUG MYNAM
- ": IOC %s_reset routed to MPT base driver!\n",
- reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ ": IOC %s_reset routed to MPT base driver!\n",
+ ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+ reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
if (reset_phase == MPT_IOC_SETUP_RESET) {
;
@@ -5843,7 +5929,7 @@ procmpt_summary_read(char *buf, char **start, off_t offset, int request, int *eo
static int
procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eof, void *data)
{
- int ii;
+ u8 cb_idx;
int scsi, fc, sas, lan, ctl, targ, dmp;
char *drvname;
int len;
@@ -5852,10 +5938,10 @@ procmpt_version_read(char *buf, char **start, off_t offset, int request, int *eo
len += sprintf(buf+len, " Fusion MPT base driver\n");
scsi = fc = sas = lan = ctl = targ = dmp = 0;
- for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
drvname = NULL;
- if (MptCallbacks[ii]) {
- switch (MptDriverClass[ii]) {
+ if (MptCallbacks[cb_idx]) {
+ switch (MptDriverClass[cb_idx]) {
case MPTSPI_DRIVER:
if (!scsi++) drvname = "SPI host";
break;
@@ -6099,26 +6185,25 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
* For all other protocol drivers, this is a no-op.
*/
{
- int ii;
+ u8 cb_idx;
int r = 0;
- for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
- if (MptResetHandlers[ii]) {
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if (MptResetHandlers[cb_idx]) {
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
- ioc->name, ii));
- r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
+ ioc->name, cb_idx));
+ r += mpt_signal_reset(cb_idx, ioc, MPT_IOC_SETUP_RESET);
if (ioc->alt_ioc) {
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
- ioc->name, ioc->alt_ioc->name, ii));
- r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
+ ioc->name, ioc->alt_ioc->name, cb_idx));
+ r += mpt_signal_reset(cb_idx, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
}
}
}
}
if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) {
- printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n",
- rc, ioc->name);
+ printk(MYIOC_s_WARN_FMT "Cannot recover rc = %d!\n", ioc->name, rc);
}
ioc->reload_fw = 0;
if (ioc->alt_ioc)
@@ -6515,6 +6600,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
u32 evData0 = 0;
// u32 evCtx;
int ii;
+ u8 cb_idx;
int r = 0;
int handlers = 0;
char evStr[EVENT_DESCR_STR_SZ];
@@ -6537,12 +6623,12 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
evStr));
#ifdef CONFIG_FUSION_LOGGING
- devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
- ": Event data:\n"));
+ devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ ": Event data:\n", ioc->name));
for (ii = 0; ii < evDataLen; ii++)
devtverboseprintk(ioc, printk(" %08x",
le32_to_cpu(pEventReply->Data[ii])));
- devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
+ devtverboseprintk(ioc, printk("\n"));
#endif
/*
@@ -6595,11 +6681,11 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
/*
* Call each currently registered protocol event handler.
*/
- for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
- if (MptEvHandlers[ii]) {
+ for (cb_idx = MPT_MAX_PROTOCOL_DRIVERS-1; cb_idx; cb_idx--) {
+ if (MptEvHandlers[cb_idx]) {
devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
- ioc->name, ii));
- r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
+ ioc->name, cb_idx));
+ r += (*(MptEvHandlers[cb_idx]))(ioc, pEventReply);
handlers++;
}
}
@@ -7034,8 +7120,8 @@ mpt_iocstatus_info_config(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
if (!desc)
return;
- printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
- ioc->name, ioc_status, desc, extend_desc);
+ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s: %s\n",
+ ioc->name, ioc_status, desc, extend_desc));
}
/**
@@ -7261,7 +7347,8 @@ mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
if (!desc)
return;
- printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc);
+ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOCStatus(0x%04X): %s\n",
+ ioc->name, status, desc));
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -7283,14 +7370,13 @@ EXPORT_SYMBOL(mpt_device_driver_register);
EXPORT_SYMBOL(mpt_device_driver_deregister);
EXPORT_SYMBOL(mpt_get_msg_frame);
EXPORT_SYMBOL(mpt_put_msg_frame);
+EXPORT_SYMBOL(mpt_put_msg_frame_hi_pri);
EXPORT_SYMBOL(mpt_free_msg_frame);
EXPORT_SYMBOL(mpt_add_sge);
EXPORT_SYMBOL(mpt_send_handshake_request);
EXPORT_SYMBOL(mpt_verify_adapter);
EXPORT_SYMBOL(mpt_GetIocState);
EXPORT_SYMBOL(mpt_print_ioc_summary);
-EXPORT_SYMBOL(mpt_lan_index);
-EXPORT_SYMBOL(mpt_stm_index);
EXPORT_SYMBOL(mpt_HardResetHandler);
EXPORT_SYMBOL(mpt_config);
EXPORT_SYMBOL(mpt_findImVolumes);
@@ -7308,16 +7394,16 @@ EXPORT_SYMBOL(mpt_raid_phys_disk_pg0);
static int __init
fusion_init(void)
{
- int i;
+ u8 cb_idx;
show_mptmod_ver(my_NAME, my_VERSION);
printk(KERN_INFO COPYRIGHT "\n");
- for (i = 0; i < MPT_MAX_PROTOCOL_DRIVERS; i++) {
- MptCallbacks[i] = NULL;
- MptDriverClass[i] = MPTUNKNOWN_DRIVER;
- MptEvHandlers[i] = NULL;
- MptResetHandlers[i] = NULL;
+ for (cb_idx = 0; cb_idx < MPT_MAX_PROTOCOL_DRIVERS; cb_idx++) {
+ MptCallbacks[cb_idx] = NULL;
+ MptDriverClass[cb_idx] = MPTUNKNOWN_DRIVER;
+ MptEvHandlers[cb_idx] = NULL;
+ MptResetHandlers[cb_idx] = NULL;
}
/* Register ourselves (mptbase) in order to facilitate
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 15ff2264584..d7682e083f5 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -3,9 +3,9 @@
* High performance SCSI + LAN / Fibre Channel device drivers.
* For use with PCI chip/adapter(s):
* LSIFC9xx/LSI409xx Fibre Channel
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -68,15 +68,15 @@
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#ifndef MODULEAUTHOR
-#define MODULEAUTHOR "LSI Logic Corporation"
+#define MODULEAUTHOR "LSI Corporation"
#endif
#ifndef COPYRIGHT
#define COPYRIGHT "Copyright (c) 1999-2007 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.04.05"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.05"
+#define MPT_LINUX_VERSION_COMMON "3.04.06"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.06"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
@@ -186,6 +186,7 @@
* MPT drivers. NOTE: Users of these macro defs must
* themselves define their own MYNAM.
*/
+#define MYIOC_s_FMT MYNAM ": %s: "
#define MYIOC_s_DEBUG_FMT KERN_DEBUG MYNAM ": %s: "
#define MYIOC_s_INFO_FMT KERN_INFO MYNAM ": %s: "
#define MYIOC_s_NOTE_FMT KERN_NOTICE MYNAM ": %s: "
@@ -194,6 +195,35 @@
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
+ * ATTO UL4D associated structures and defines
+ */
+#define ATTOFLAG_DISC 0x0001
+#define ATTOFLAG_TAGGED 0x0002
+#define ATTOFLAG_WIDE_ENB 0x0008
+#define ATTOFLAG_ID_ENB 0x0010
+#define ATTOFLAG_LUN_ENB 0x0060
+
+typedef struct _ATTO_DEVICE_INFO
+{
+ u8 Offset; /* 00h */
+ u8 Period; /* 01h */
+ u16 ATTOFlags; /* 02h */
+} ATTO_DEVICE_INFO, MPI_POINTER PTR_ATTO_DEVICE_INFO,
+ ATTODeviceInfo_t, MPI_POINTER pATTODeviceInfo_t;
+
+typedef struct _ATTO_CONFIG_PAGE_SCSI_PORT_2
+{
+ CONFIG_PAGE_HEADER Header; /* 00h */
+ u16 PortFlags; /* 04h */
+ u16 Unused1; /* 06h */
+ u32 Unused2; /* 08h */
+ ATTO_DEVICE_INFO DeviceSettings[16]; /* 0Ch */
+} fATTO_CONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_ATTO_CONFIG_PAGE_SCSI_PORT_2,
+ ATTO_SCSIPortPage2_t, MPI_POINTER pATTO_SCSIPortPage2_t;
+
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
* MPT protocol driver defs...
*/
typedef enum {
@@ -307,7 +337,8 @@ typedef struct _SYSIF_REGS
u32 Reserved2[2]; /* 38-3F reserved for future use */
u32 RequestFifo; /* 40 Request Post/Free FIFO */
u32 ReplyFifo; /* 44 Reply Post/Free FIFO */
- u32 Reserved3[2]; /* 48-4F reserved for future use */
+ u32 RequestHiPriFifo; /* 48 Hi Priority Request FIFO */
+ u32 Reserved3; /* 4C-4F reserved for future use */
u32 HostIndex; /* 50 Host Index register */
u32 Reserved4[15]; /* 54-8F */
u32 Fubar; /* 90 For Fubar usage */
@@ -649,9 +680,9 @@ typedef struct _MPT_ADAPTER
u8 reload_fw; /* Force a FW Reload on next reset */
u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */
u8 pad1[4];
- int DoneCtx;
- int TaskCtx;
- int InternalCtx;
+ u8 DoneCtx;
+ u8 TaskCtx;
+ u8 InternalCtx;
spinlock_t initializing_hba_lock;
int initializing_hba_lock_flag;
struct list_head list;
@@ -668,10 +699,14 @@ typedef struct _MPT_ADAPTER
struct work_struct fc_setup_reset_work;
struct list_head fc_rports;
+ struct work_struct fc_lsc_work;
+ u8 fc_link_speed[2];
spinlock_t fc_rescan_work_lock;
struct work_struct fc_rescan_work;
char fc_rescan_work_q_name[KOBJ_NAME_LEN];
struct workqueue_struct *fc_rescan_work_q;
+ struct scsi_cmnd **ScsiLookup;
+ spinlock_t scsi_lookup_lock;
} MPT_ADAPTER;
/*
@@ -785,7 +820,6 @@ typedef struct _MPT_SCSI_HOST {
MPT_ADAPTER *ioc;
int port;
u32 pad0;
- struct scsi_cmnd **ScsiLookup;
MPT_LOCAL_REPLY *pLocal; /* used for internal commands */
struct timer_list timer;
/* Pool of memory for holding SCpnts before doing
@@ -853,20 +887,21 @@ extern void mpt_detach(struct pci_dev *pdev);
extern int mpt_suspend(struct pci_dev *pdev, pm_message_t state);
extern int mpt_resume(struct pci_dev *pdev);
#endif
-extern int mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
-extern void mpt_deregister(int cb_idx);
-extern int mpt_event_register(int cb_idx, MPT_EVHANDLER ev_cbfunc);
-extern void mpt_event_deregister(int cb_idx);
-extern int mpt_reset_register(int cb_idx, MPT_RESETHANDLER reset_func);
-extern void mpt_reset_deregister(int cb_idx);
-extern int mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx);
-extern void mpt_device_driver_deregister(int cb_idx);
-extern MPT_FRAME_HDR *mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc);
+extern u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass);
+extern void mpt_deregister(u8 cb_idx);
+extern int mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc);
+extern void mpt_event_deregister(u8 cb_idx);
+extern int mpt_reset_register(u8 cb_idx, MPT_RESETHANDLER reset_func);
+extern void mpt_reset_deregister(u8 cb_idx);
+extern int mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, u8 cb_idx);
+extern void mpt_device_driver_deregister(u8 cb_idx);
+extern MPT_FRAME_HDR *mpt_get_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc);
extern void mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
-extern void mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
+extern void mpt_put_msg_frame(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
+extern void mpt_put_msg_frame_hi_pri(u8 cb_idx, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf);
extern void mpt_add_sge(char *pAddr, u32 flagslength, dma_addr_t dma_addr);
-extern int mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag);
+extern int mpt_send_handshake_request(u8 cb_idx, MPT_ADAPTER *ioc, int reqBytes, u32 *req, int sleepFlag);
extern int mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp);
extern u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked);
extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan);
@@ -884,9 +919,6 @@ extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhys
extern struct list_head ioc_list;
extern struct proc_dir_entry *mpt_proc_root_dir;
-extern int mpt_lan_index; /* needed by mptlan.c */
-extern int mpt_stm_index; /* needed by mptstm.c */
-
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#endif /* } __KERNEL__ */
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 89695e705bd..6029509702d 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -1,10 +1,10 @@
/*
* linux/drivers/message/fusion/mptctl.c
* mpt Ioctl driver.
- * For use with LSI Logic PCI chip/adapters
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI PCI chip/adapters
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -66,8 +66,8 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
-#define COPYRIGHT "Copyright (c) 1999-2007 LSI Logic Corporation"
-#define MODULEAUTHOR "LSI Logic Corporation"
+#define COPYRIGHT "Copyright (c) 1999-2007 LSI Corporation"
+#define MODULEAUTHOR "LSI Corporation"
#include "mptbase.h"
#include "mptctl.h"
@@ -83,7 +83,7 @@ MODULE_VERSION(my_VERSION);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int mptctl_id = -1;
+static u8 mptctl_id = MPT_MAX_PROTOCOL_DRIVERS;
static DECLARE_WAIT_QUEUE_HEAD ( mptctl_wait );
@@ -181,7 +181,6 @@ static inline int
mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
{
int rc = 0;
-// dctlprintk(ioc, printk(KERN_DEBUG MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));
if (nonblock) {
if (!mutex_trylock(&ioc->ioctl->ioctl_mutex))
@@ -190,7 +189,6 @@ mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex))
rc = -ERESTARTSYS;
}
-// dctlprintk(ioc, printk(KERN_DEBUG MYNAM "::mptctl_syscall_down return %d\n", rc));
return rc;
}
@@ -342,7 +340,7 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl)
SCSITaskMgmt_t *pScsiTm;
MPT_SCSI_HOST *hd;
int ii;
- int retval;
+ int retval=0;
ioctl->reset &= ~MPTCTL_RESET_OK;
@@ -350,7 +348,7 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl)
if (ioctl->ioc->sh == NULL)
return -EPERM;
- hd = (MPT_SCSI_HOST *) ioctl->ioc->sh->hostdata;
+ hd = shost_priv(ioctl->ioc->sh);
if (hd == NULL)
return -EPERM;
@@ -395,12 +393,19 @@ static int mptctl_bus_reset(MPT_IOCTL *ioctl)
DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf);
ioctl->wait_done=0;
- if ((retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
- sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
- dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
- " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
- hd->ioc, mf));
- goto mptctl_bus_reset_done;
+
+ if ((ioctl->ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+ (ioctl->ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+ mpt_put_msg_frame_hi_pri(mptctl_id, ioctl->ioc, mf);
+ else {
+ retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
+ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+ if (retval != 0) {
+ dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
+ " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
+ hd->ioc, mf));
+ goto mptctl_bus_reset_done;
+ }
}
/* Now wait for the command to complete */
@@ -444,7 +449,7 @@ mptctl_free_tm_flags(MPT_ADAPTER *ioc)
MPT_SCSI_HOST * hd;
unsigned long flags;
- hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+ hd = shost_priv(ioc->sh);
if (hd == NULL)
return;
@@ -468,7 +473,7 @@ static int
mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
{
MPT_IOCTL *ioctl = ioc->ioctl;
- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": IOC %s_reset routed to IOCTL driver!\n",ioc->name,
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC %s_reset routed to IOCTL driver!\n", ioc->name,
reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
@@ -574,7 +579,7 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
MPT_ADAPTER *iocp = NULL;
if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {
- printk(KERN_ERR "%s::mptctl_ioctl() @%d - "
+ printk(KERN_ERR MYNAM "%s::mptctl_ioctl() @%d - "
"Unable to copy mpt_ioctl_header data @ %p\n",
__FILE__, __LINE__, uhdr);
return -EFAULT;
@@ -587,13 +592,13 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
iocnumX = khdr.iocnum & 0xFF;
if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
(iocp == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnumX);
return -ENODEV;
}
if (!iocp->active) {
- printk(KERN_DEBUG "%s::mptctl_ioctl() @%d - Controller disabled.\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_ioctl() @%d - Controller disabled.\n",
__FILE__, __LINE__);
return -EFAULT;
}
@@ -660,14 +665,14 @@ static int mptctl_do_reset(unsigned long arg)
MPT_ADAPTER *iocp;
if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) {
- printk(KERN_ERR "%s@%d::mptctl_do_reset - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_do_reset - "
"Unable to copy mpt_ioctl_diag_reset struct @ %p\n",
__FILE__, __LINE__, urinfo);
return -EFAULT;
}
if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
- printk(KERN_DEBUG "%s@%d::mptctl_do_reset - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n",
__FILE__, __LINE__, krinfo.hdr.iocnum);
return -ENODEV; /* (-6) No such device or address */
}
@@ -676,8 +681,8 @@ static int mptctl_do_reset(unsigned long arg)
iocp->name));
if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) {
- printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n",
- __FILE__, __LINE__);
+ printk (MYIOC_s_ERR_FMT "%s@%d::mptctl_do_reset - reset failed.\n",
+ iocp->name, __FILE__, __LINE__);
return -1;
}
@@ -708,7 +713,7 @@ mptctl_fw_download(unsigned long arg)
struct mpt_fw_xfer kfwdl;
if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {
- printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
+ printk(KERN_ERR MYNAM "%s@%d::_ioctl_fwdl - "
"Unable to copy mpt_fw_xfer struct @ %p\n",
__FILE__, __LINE__, ufwdl);
return -EFAULT;
@@ -756,7 +761,8 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
pFWDownloadReply_t ReplyMsg = NULL;
if (mpt_verify_adapter(ioc, &iocp) < 0) {
- printk(KERN_DEBUG "ioctl_fwdl - ioc%d not found!\n", ioc);
+ printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n",
+ ioc);
return -ENODEV; /* (-6) No such device or address */
} else {
@@ -868,9 +874,9 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
mpt_add_sge(sgOut, sgIn->FlagsLength, sgIn->Address);
n++;
if (copy_from_user(bl->kptr, ufwbuf+fw_bytes_copied, bl->len)) {
- printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
- "Unable to copy f/w buffer hunk#%d @ %p\n",
- __FILE__, __LINE__, n, ufwbuf);
+ printk(MYIOC_s_ERR_FMT "%s@%d::_ioctl_fwdl - "
+ "Unable to copy f/w buffer hunk#%d @ %p\n",
+ iocp->name, __FILE__, __LINE__, n, ufwbuf);
goto fwdl_out;
}
fw_bytes_copied += bl->len;
@@ -906,21 +912,22 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen)
ReplyMsg = (pFWDownloadReply_t)iocp->ioctl->ReplyFrame;
iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK;
if (iocstat == MPI_IOCSTATUS_SUCCESS) {
- printk(KERN_INFO MYNAM ": F/W update successfully sent to %s!\n", iocp->name);
+ printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name);
return 0;
} else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) {
- printk(KERN_WARNING MYNAM ": ?Hmmm... %s says it doesn't support F/W download!?!\n",
- iocp->name);
- printk(KERN_WARNING MYNAM ": (time to go bang on somebodies door)\n");
+ printk(MYIOC_s_WARN_FMT "Hmmm... F/W download not supported!?!\n",
+ iocp->name);
+ printk(MYIOC_s_WARN_FMT "(time to go bang on somebodies door)\n",
+ iocp->name);
return -EBADRQC;
} else if (iocstat == MPI_IOCSTATUS_BUSY) {
- printk(KERN_WARNING MYNAM ": Warning! %s says: IOC_BUSY!\n", iocp->name);
- printk(KERN_WARNING MYNAM ": (try again later?)\n");
+ printk(MYIOC_s_WARN_FMT "IOC_BUSY!\n", iocp->name);
+ printk(MYIOC_s_WARN_FMT "(try again later?)\n", iocp->name);
return -EBUSY;
} else {
- printk(KERN_WARNING MYNAM "::ioctl_fwdl() ERROR! %s returned [bad] status = %04xh\n",
- iocp->name, iocstat);
- printk(KERN_WARNING MYNAM ": (bad VooDoo)\n");
+ printk(MYIOC_s_WARN_FMT "ioctl_fwdl() returned [bad] status = %04xh\n",
+ iocp->name, iocstat);
+ printk(MYIOC_s_WARN_FMT "(bad VooDoo)\n", iocp->name);
return -ENOMSG;
}
return 0;
@@ -970,10 +977,9 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
* structures for the SG elements.
*/
i = MAX_SGL_BYTES / 8;
- buflist = kmalloc(i, GFP_USER);
- if (buflist == NULL)
+ buflist = kzalloc(i, GFP_USER);
+ if (!buflist)
return NULL;
- memset(buflist, 0, i);
buflist_ent = 0;
/* Allocate a single block of memory to store the sg elements and
@@ -1008,10 +1014,10 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
if (buflist[buflist_ent].kptr == NULL) {
alloc_sz = alloc_sz / 2;
if (alloc_sz == 0) {
- printk(KERN_WARNING MYNAM "-SG: No can do - "
- "not enough memory! :-(\n");
- printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
- numfrags);
+ printk(MYIOC_s_WARN_FMT "-SG: No can do - "
+ "not enough memory! :-(\n", ioc->name);
+ printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
+ ioc->name, numfrags);
goto free_and_fail;
}
continue;
@@ -1034,18 +1040,19 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
/* Need to chain? */
if (fragcnt == sg_spill) {
- printk(KERN_WARNING MYNAM "-SG: No can do - " "Chain required! :-(\n");
- printk(KERN_WARNING MYNAM "(freeing %d frags)\n", numfrags);
+ printk(MYIOC_s_WARN_FMT
+ "-SG: No can do - " "Chain required! :-(\n", ioc->name);
+ printk(MYIOC_s_WARN_FMT "(freeing %d frags)\n", ioc->name, numfrags);
goto free_and_fail;
}
/* overflow check... */
if (numfrags*8 > MAX_SGL_BYTES){
/* GRRRRR... */
- printk(KERN_WARNING MYNAM "-SG: No can do - "
- "too many SG frags! :-(\n");
- printk(KERN_WARNING MYNAM "-SG: (freeing %d frags)\n",
- numfrags);
+ printk(MYIOC_s_WARN_FMT "-SG: No can do - "
+ "too many SG frags! :-(\n", ioc->name);
+ printk(MYIOC_s_WARN_FMT "-SG: (freeing %d frags)\n",
+ ioc->name, numfrags);
goto free_and_fail;
}
}
@@ -1066,8 +1073,6 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
free_and_fail:
if (sglbuf != NULL) {
- int i;
-
for (i = 0; i < numfrags; i++) {
dma_addr_t dma_addr;
u8 *kptr;
@@ -1170,7 +1175,7 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
int cim_rev;
u8 revision;
struct scsi_device *sdev;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
/* Add of PCI INFO results in unaligned access for
* IA64 and Sparc. Reset long to int. Return no PCI
@@ -1189,13 +1194,13 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
karg = kmalloc(data_size, GFP_KERNEL);
if (karg == NULL) {
- printk(KERN_ERR "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n",
+ printk(KERN_ERR MYNAM "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n",
__FILE__, __LINE__);
return -ENOMEM;
}
if (copy_from_user(karg, uarg, data_size)) {
- printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_getiocinfo - "
"Unable to read in mpt_ioctl_iocinfo struct @ %p\n",
__FILE__, __LINE__, uarg);
kfree(karg);
@@ -1204,7 +1209,7 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
kfree(karg);
return -ENODEV;
@@ -1212,9 +1217,9 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
/* Verify the data transfer size is correct. */
if (karg->hdr.maxDataSize != data_size) {
- printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
"Structure size mismatch. Command not completed.\n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
kfree(karg);
return -EFAULT;
}
@@ -1265,8 +1270,8 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
karg->numDevices = 0;
if (ioc->sh) {
shost_for_each_device(sdev, ioc->sh) {
- vdev = sdev->hostdata;
- if (vdev->vtarget->tflags &
+ vdevice = sdev->hostdata;
+ if (vdevice->vtarget->tflags &
MPT_TARGET_FLAGS_RAID_COMPONENT)
continue;
karg->numDevices++;
@@ -1290,9 +1295,9 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size)
/* Copy the data from kernel memory to user memory
*/
if (copy_to_user((char __user *)arg, karg, data_size)) {
- printk(KERN_ERR "%s@%d::mptctl_getiocinfo - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - "
"Unable to write out mpt_ioctl_iocinfo struct @ %p\n",
- __FILE__, __LINE__, uarg);
+ ioc->name, __FILE__, __LINE__, uarg);
kfree(karg);
return -EFAULT;
}
@@ -1317,7 +1322,7 @@ mptctl_gettargetinfo (unsigned long arg)
struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg;
struct mpt_ioctl_targetinfo karg;
MPT_ADAPTER *ioc;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
char *pmem;
int *pdata;
int iocnum;
@@ -1329,7 +1334,7 @@ mptctl_gettargetinfo (unsigned long arg)
struct scsi_device *sdev;
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
- printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_gettargetinfo - "
"Unable to read in mpt_ioctl_targetinfo struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1337,7 +1342,7 @@ mptctl_gettargetinfo (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1353,8 +1358,8 @@ mptctl_gettargetinfo (unsigned long arg)
port = karg.hdr.port;
if (maxWordsLeft <= 0) {
- printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
- __FILE__, __LINE__);
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
+ ioc->name, __FILE__, __LINE__);
return -ENOMEM;
}
@@ -1372,13 +1377,12 @@ mptctl_gettargetinfo (unsigned long arg)
* 15- 8: Bus Number
* 7- 0: Target ID
*/
- pmem = kmalloc(numBytes, GFP_KERNEL);
- if (pmem == NULL) {
- printk(KERN_ERR "%s::mptctl_gettargetinfo() @%d - no memory available!\n",
- __FILE__, __LINE__);
+ pmem = kzalloc(numBytes, GFP_KERNEL);
+ if (!pmem) {
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo() - no memory available!\n",
+ ioc->name, __FILE__, __LINE__);
return -ENOMEM;
}
- memset(pmem, 0, numBytes);
pdata = (int *) pmem;
/* Get number of devices
@@ -1387,13 +1391,13 @@ mptctl_gettargetinfo (unsigned long arg)
shost_for_each_device(sdev, ioc->sh) {
if (!maxWordsLeft)
continue;
- vdev = sdev->hostdata;
- if (vdev->vtarget->tflags &
+ vdevice = sdev->hostdata;
+ if (vdevice->vtarget->tflags &
MPT_TARGET_FLAGS_RAID_COMPONENT)
continue;
- lun = (vdev->vtarget->raidVolume) ? 0x80 : vdev->lun;
- *pdata = (((u8)lun << 16) + (vdev->vtarget->channel << 8) +
- (vdev->vtarget->id ));
+ lun = (vdevice->vtarget->raidVolume) ? 0x80 : vdevice->lun;
+ *pdata = (((u8)lun << 16) + (vdevice->vtarget->channel << 8) +
+ (vdevice->vtarget->id ));
pdata++;
numDevices++;
--maxWordsLeft;
@@ -1405,9 +1409,9 @@ mptctl_gettargetinfo (unsigned long arg)
*/
if (copy_to_user((char __user *)arg, &karg,
sizeof(struct mpt_ioctl_targetinfo))) {
- printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - "
"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
- __FILE__, __LINE__, uarg);
+ ioc->name, __FILE__, __LINE__, uarg);
kfree(pmem);
return -EFAULT;
}
@@ -1415,9 +1419,9 @@ mptctl_gettargetinfo (unsigned long arg)
/* Copy the remaining data from kernel memory to user memory
*/
if (copy_to_user(uarg->targetInfo, pmem, numBytes)) {
- printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_gettargetinfo - "
"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
- __FILE__, __LINE__, pdata);
+ ioc->name, __FILE__, __LINE__, pdata);
kfree(pmem);
return -EFAULT;
}
@@ -1444,7 +1448,7 @@ mptctl_readtest (unsigned long arg)
int iocnum;
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) {
- printk(KERN_ERR "%s@%d::mptctl_readtest - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_readtest - "
"Unable to read in mpt_ioctl_test struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1452,7 +1456,7 @@ mptctl_readtest (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_readtest() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1476,9 +1480,9 @@ mptctl_readtest (unsigned long arg)
/* Copy the data from kernel memory to user memory
*/
if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_test))) {
- printk(KERN_ERR "%s@%d::mptctl_readtest - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_readtest - "
"Unable to write out mpt_ioctl_test struct @ %p\n",
- __FILE__, __LINE__, uarg);
+ ioc->name, __FILE__, __LINE__, uarg);
return -EFAULT;
}
@@ -1505,7 +1509,7 @@ mptctl_eventquery (unsigned long arg)
int iocnum;
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
- printk(KERN_ERR "%s@%d::mptctl_eventquery - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_eventquery - "
"Unable to read in mpt_ioctl_eventquery struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1513,7 +1517,7 @@ mptctl_eventquery (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1526,9 +1530,9 @@ mptctl_eventquery (unsigned long arg)
/* Copy the data from kernel memory to user memory
*/
if (copy_to_user((char __user *)arg, &karg, sizeof(struct mpt_ioctl_eventquery))) {
- printk(KERN_ERR "%s@%d::mptctl_eventquery - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventquery - "
"Unable to write out mpt_ioctl_eventquery struct @ %p\n",
- __FILE__, __LINE__, uarg);
+ ioc->name, __FILE__, __LINE__, uarg);
return -EFAULT;
}
return 0;
@@ -1544,7 +1548,7 @@ mptctl_eventenable (unsigned long arg)
int iocnum;
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
- printk(KERN_ERR "%s@%d::mptctl_eventenable - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_eventenable - "
"Unable to read in mpt_ioctl_eventenable struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1552,7 +1556,7 @@ mptctl_eventenable (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1563,12 +1567,13 @@ mptctl_eventenable (unsigned long arg)
/* Have not yet allocated memory - do so now.
*/
int sz = MPTCTL_EVENT_LOG_SIZE * sizeof(MPT_IOCTL_EVENTS);
- ioc->events = kmalloc(sz, GFP_KERNEL);
- if (ioc->events == NULL) {
- printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
+ ioc->events = kzalloc(sz, GFP_KERNEL);
+ if (!ioc->events) {
+ printk(MYIOC_s_ERR_FMT
+ ": ERROR - Insufficient memory to add adapter!\n",
+ ioc->name);
return -ENOMEM;
}
- memset(ioc->events, 0, sz);
ioc->alloc_total += sz;
ioc->eventContext = 0;
@@ -1592,7 +1597,7 @@ mptctl_eventreport (unsigned long arg)
int numBytes, maxEvents, max;
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
- printk(KERN_ERR "%s@%d::mptctl_eventreport - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_eventreport - "
"Unable to read in mpt_ioctl_eventreport struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1600,7 +1605,7 @@ mptctl_eventreport (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1626,9 +1631,9 @@ mptctl_eventreport (unsigned long arg)
*/
numBytes = max * sizeof(MPT_IOCTL_EVENTS);
if (copy_to_user(uarg->eventData, ioc->events, numBytes)) {
- printk(KERN_ERR "%s@%d::mptctl_eventreport - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_eventreport - "
"Unable to write out mpt_ioctl_eventreport struct @ %p\n",
- __FILE__, __LINE__, ioc->events);
+ ioc->name, __FILE__, __LINE__, ioc->events);
return -EFAULT;
}
@@ -1646,7 +1651,7 @@ mptctl_replace_fw (unsigned long arg)
int newFwSize;
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
- printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_replace_fw - "
"Unable to read in mpt_ioctl_replace_fw struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1654,7 +1659,7 @@ mptctl_replace_fw (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1684,9 +1689,9 @@ mptctl_replace_fw (unsigned long arg)
/* Copy the data from user memory to kernel space
*/
if (copy_from_user(ioc->cached_fw, uarg->newImage, newFwSize)) {
- printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_replace_fw - "
"Unable to read in mpt_ioctl_replace_fw image "
- "@ %p\n", __FILE__, __LINE__, uarg);
+ "@ %p\n", ioc->name, __FILE__, __LINE__, uarg);
mpt_free_fw_memory(ioc);
return -EFAULT;
}
@@ -1720,7 +1725,7 @@ mptctl_mpt_command (unsigned long arg)
if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) {
- printk(KERN_ERR "%s@%d::mptctl_mpt_command - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_mpt_command - "
"Unable to read in mpt_ioctl_command struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -1728,7 +1733,7 @@ mptctl_mpt_command (unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -1769,21 +1774,24 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
ulong timeout;
struct scsi_device *sdev;
+ /* bufIn and bufOut are used for user to kernel space transfers
+ */
bufIn.kptr = bufOut.kptr = NULL;
+ bufIn.len = bufOut.len = 0;
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
if (!ioc->ioctl) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
"No memory available during driver init.\n",
__FILE__, __LINE__);
return -ENOMEM;
} else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_do_mpt_command - "
"Busy with IOC Reset \n", __FILE__, __LINE__);
return -EBUSY;
}
@@ -1797,9 +1805,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
sz += sizeof(dma_addr_t) + sizeof(u32);
if (sz > ioc->req_sz) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Request frame too large (%d) maximum (%d)\n",
- __FILE__, __LINE__, sz, ioc->req_sz);
+ ioc->name, __FILE__, __LINE__, sz, ioc->req_sz);
return -EFAULT;
}
@@ -1817,9 +1825,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
* Request frame in user space
*/
if (copy_from_user(mf, mfPtr, karg.dataSgeOffset * 4)) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Unable to read MF from mpt_ioctl_command struct @ %p\n",
- __FILE__, __LINE__, mfPtr);
+ ioc->name, __FILE__, __LINE__, mfPtr);
rc = -EFAULT;
goto done_free_mem;
}
@@ -1870,17 +1878,17 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
id = (ioc->devices_per_bus == 0) ? 256 : ioc->devices_per_bus;
if (pScsiReq->TargetID > id) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Target ID out of bounds. \n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -ENODEV;
goto done_free_mem;
}
if (pScsiReq->Bus >= ioc->number_of_buses) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Target Bus out of bounds. \n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -ENODEV;
goto done_free_mem;
}
@@ -1932,9 +1940,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
ioc->ioctl->id = pScsiReq->TargetID;
} else {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"SCSI driver is not loaded. \n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -EFAULT;
goto done_free_mem;
}
@@ -1951,9 +1959,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
case MPI_FUNCTION_SATA_PASSTHROUGH:
if (!ioc->sh) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"SCSI driver is not loaded. \n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -EFAULT;
goto done_free_mem;
}
@@ -2010,9 +2018,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
ioc->ioctl->reset = MPTCTL_RESET_OK;
ioc->ioctl->id = pScsiReq->TargetID;
} else {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"SCSI driver is not loaded. \n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -EFAULT;
goto done_free_mem;
}
@@ -2021,10 +2029,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
case MPI_FUNCTION_SCSI_TASK_MGMT:
{
MPT_SCSI_HOST *hd = NULL;
- if ((ioc->sh == NULL) || ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ if ((ioc->sh == NULL) || ((hd = shost_priv(ioc->sh)) == NULL)) {
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"SCSI driver not loaded or SCSI host not found. \n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -EFAULT;
goto done_free_mem;
} else if (mptctl_set_tm_flags(hd) != 0) {
@@ -2055,9 +2063,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
(pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) ||
(pInit->HostMfaHighAddr != high_addr) ||
(pInit->SenseBufferHighAddr != sense_high)) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"IOC_INIT issued with 1 or more incorrect parameters. Rejected.\n",
- __FILE__, __LINE__);
+ ioc->name, __FILE__, __LINE__);
rc = -EFAULT;
goto done_free_mem;
}
@@ -2088,9 +2096,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
MPI_FUNCTION_LAN_RESET
*/
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Illegal request (function 0x%x) \n",
- __FILE__, __LINE__, hdr->Function);
+ ioc->name, __FILE__, __LINE__, hdr->Function);
rc = -EFAULT;
goto done_free_mem;
}
@@ -2103,11 +2111,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
psge = (char *) (((int *) mf) + karg.dataSgeOffset);
flagsLength = 0;
- /* bufIn and bufOut are used for user to kernel space transfers
- */
- bufIn.kptr = bufOut.kptr = NULL;
- bufIn.len = bufOut.len = 0;
-
if (karg.dataOutSize > 0)
sgSize ++;
@@ -2147,11 +2150,11 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
if (copy_from_user(bufOut.kptr,
karg.dataOutBufPtr,
bufOut.len)) {
- printk(KERN_ERR
+ printk(MYIOC_s_ERR_FMT
"%s@%d::mptctl_do_mpt_command - Unable "
"to read user data "
"struct @ %p\n",
- __FILE__, __LINE__,karg.dataOutBufPtr);
+ ioc->name, __FILE__, __LINE__,karg.dataOutBufPtr);
rc = -EFAULT;
goto done_free_mem;
}
@@ -2187,15 +2190,20 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
- if (mpt_send_handshake_request(mptctl_id, ioc,
- sizeof(SCSITaskMgmt_t), (u32*)mf,
- CAN_SLEEP) != 0) {
- dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
- " (ioc %p, mf %p) \n", ioc->name,
- ioc, mf));
- mptctl_free_tm_flags(ioc);
- rc = -ENODATA;
- goto done_free_mem;
+ if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+ (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+ mpt_put_msg_frame_hi_pri(mptctl_id, ioc, mf);
+ else {
+ rc =mpt_send_handshake_request(mptctl_id, ioc,
+ sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP);
+ if (rc != 0) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "_send_handshake FAILED! (ioc %p, mf %p)\n",
+ ioc->name, ioc, mf));
+ mptctl_free_tm_flags(ioc);
+ rc = -ENODATA;
+ goto done_free_mem;
+ }
}
} else
@@ -2233,10 +2241,10 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
if (sz > 0) {
if (copy_to_user(karg.replyFrameBufPtr,
&ioc->ioctl->ReplyFrame, sz)){
- printk(KERN_ERR
+ printk(MYIOC_s_ERR_FMT
"%s@%d::mptctl_do_mpt_command - "
"Unable to write out reply frame %p\n",
- __FILE__, __LINE__, karg.replyFrameBufPtr);
+ ioc->name, __FILE__, __LINE__, karg.replyFrameBufPtr);
rc = -ENODATA;
goto done_free_mem;
}
@@ -2249,9 +2257,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
sz = min(karg.maxSenseBytes, MPT_SENSE_BUFFER_SIZE);
if (sz > 0) {
if (copy_to_user(karg.senseDataPtr, ioc->ioctl->sense, sz)) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Unable to write sense data to user %p\n",
- __FILE__, __LINE__,
+ ioc->name, __FILE__, __LINE__,
karg.senseDataPtr);
rc = -ENODATA;
goto done_free_mem;
@@ -2267,9 +2275,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)
if (copy_to_user(karg.dataInBufPtr,
bufIn.kptr, karg.dataInSize)) {
- printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_do_mpt_command - "
"Unable to write data to user %p\n",
- __FILE__, __LINE__,
+ ioc->name, __FILE__, __LINE__,
karg.dataInBufPtr);
rc = -ENODATA;
}
@@ -2340,7 +2348,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
return -EFAULT;
if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) {
- printk(KERN_ERR "%s@%d::mptctl_hp_host_info - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_host_info - "
"Unable to read in hp_host_info struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -2348,7 +2356,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
@@ -2456,7 +2464,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
karg.soft_resets = 0;
karg.timeouts = 0;
if (ioc->sh != NULL) {
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
if (hd && (cim_rev == 1)) {
karg.hard_resets = hd->hard_resets;
@@ -2529,9 +2537,9 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
/* Copy the data from kernel memory to user memory
*/
if (copy_to_user((char __user *)arg, &karg, sizeof(hp_host_info_t))) {
- printk(KERN_ERR "%s@%d::mptctl_hpgethostinfo - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hpgethostinfo - "
"Unable to write out hp_host_info @ %p\n",
- __FILE__, __LINE__, uarg);
+ ioc->name, __FILE__, __LINE__, uarg);
return -EFAULT;
}
@@ -2567,7 +2575,7 @@ mptctl_hp_targetinfo(unsigned long arg)
int tmp, np, rc = 0;
if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) {
- printk(KERN_ERR "%s@%d::mptctl_hp_targetinfo - "
+ printk(KERN_ERR MYNAM "%s@%d::mptctl_hp_targetinfo - "
"Unable to read in hp_host_targetinfo struct @ %p\n",
__FILE__, __LINE__, uarg);
return -EFAULT;
@@ -2575,11 +2583,11 @@ mptctl_hp_targetinfo(unsigned long arg)
if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
(ioc == NULL)) {
- printk(KERN_DEBUG "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
+ printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
__FILE__, __LINE__, iocnum);
return -ENODEV;
}
- dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_targetinfo called.\n",
+ dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
ioc->name));
/* There is nothing to do for FCP parts.
@@ -2673,16 +2681,16 @@ mptctl_hp_targetinfo(unsigned long arg)
pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma);
}
}
- hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+ hd = shost_priv(ioc->sh);
if (hd != NULL)
karg.select_timeouts = hd->sel_timeout[karg.hdr.id];
/* Copy the data from kernel memory to user memory
*/
if (copy_to_user((char __user *)arg, &karg, sizeof(hp_target_info_t))) {
- printk(KERN_ERR "%s@%d::mptctl_hp_target_info - "
+ printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_hp_target_info - "
"Unable to write out mpt_ioctl_targetinfo struct @ %p\n",
- __FILE__, __LINE__, uarg);
+ ioc->name, __FILE__, __LINE__, uarg);
return -EFAULT;
}
@@ -2732,7 +2740,7 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd,
if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
(iocp == NULL)) {
printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
- __LINE__, iocnumX);
+ __LINE__, iocnumX);
return -ENODEV;
}
@@ -2772,7 +2780,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd,
if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
(iocp == NULL)) {
printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
- __LINE__, iocnumX);
+ __LINE__, iocnumX);
return -ENODEV;
}
@@ -2853,31 +2861,22 @@ static long compat_mpctl_ioctl(struct file *f, unsigned int cmd, unsigned long a
static int
mptctl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
- int err;
- int sz;
- u8 *mem;
+ MPT_IOCTL *mem;
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
/*
* Allocate and inite a MPT_IOCTL structure
*/
- sz = sizeof (MPT_IOCTL);
- mem = kmalloc(sz, GFP_KERNEL);
- if (mem == NULL) {
- err = -ENOMEM;
- goto out_fail;
+ mem = kzalloc(sizeof(MPT_IOCTL), GFP_KERNEL);
+ if (!mem) {
+ mptctl_remove(pdev);
+ return -ENOMEM;
}
- memset(mem, 0, sz);
- ioc->ioctl = (MPT_IOCTL *) mem;
+ ioc->ioctl = mem;
ioc->ioctl->ioc = ioc;
mutex_init(&ioc->ioctl->ioctl_mutex);
return 0;
-
-out_fail:
-
- mptctl_remove(pdev);
- return err;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2924,7 +2923,8 @@ static int __init mptctl_init(void)
* Install our handler
*/
++where;
- if ((mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER)) < 0) {
+ mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER);
+ if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) {
printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n");
misc_deregister(&mptctl_miscdev);
err = -EBUSY;
diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
index 180b3c15624..2c1890127e1 100644
--- a/drivers/message/fusion/mptctl.h
+++ b/drivers/message/fusion/mptctl.h
@@ -3,9 +3,9 @@
* Fusion MPT misc device (ioctl) driver.
* For use with PCI chip/adapter(s):
* LSIFC9xx/LSI409xx Fibre Channel
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index 8422c25e4a3..3cdd4e96211 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -1,9 +1,9 @@
/*
* linux/drivers/message/fusion/mptfc.c
- * For use with LSI Logic PCI chip/adapter(s)
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI PCI chip/adapter(s)
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -90,9 +90,9 @@ static int max_lun = MPTFC_MAX_LUN;
module_param(max_lun, int, 0);
MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
-static int mptfcDoneCtx = -1;
-static int mptfcTaskCtx = -1;
-static int mptfcInternalCtx = -1; /* Used only for internal commands */
+static u8 mptfcDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptfcTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
+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);
@@ -194,37 +194,36 @@ mptfc_block_error_handler(struct scsi_cmnd *SCpnt,
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
unsigned long flags;
int ready;
+ MPT_ADAPTER *ioc;
- hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
+ hd = shost_priv(SCpnt->device->host);
+ ioc = hd->ioc;
spin_lock_irqsave(shost->host_lock, flags);
while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
spin_unlock_irqrestore(shost->host_lock, flags);
- dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
"mptfc_block_error_handler.%d: %d:%d, port status is "
"DID_IMM_RETRY, deferring %s recovery.\n",
- ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
- ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
- SCpnt->device->id,SCpnt->device->lun,caller));
+ ioc->name, ioc->sh->host_no,
+ SCpnt->device->id, SCpnt->device->lun, caller));
msleep(1000);
spin_lock_irqsave(shost->host_lock, flags);
}
spin_unlock_irqrestore(shost->host_lock, flags);
if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
- dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
"%s.%d: %d:%d, failing recovery, "
- "port state %d, vdev %p.\n", caller,
- ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
- ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
- SCpnt->device->id,SCpnt->device->lun,ready,
+ "port state %d, vdevice %p.\n", caller,
+ ioc->name, ioc->sh->host_no,
+ SCpnt->device->id, SCpnt->device->lun, ready,
SCpnt->device->hostdata));
return FAILED;
}
- dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
"%s.%d: %d:%d, executing recovery.\n", caller,
- ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
- ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
- SCpnt->device->id,SCpnt->device->lun));
+ ioc->name, ioc->sh->host_no,
+ SCpnt->device->id, SCpnt->device->lun));
return (*func)(SCpnt);
}
@@ -470,7 +469,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
/*
* if already mapped, remap here. If not mapped,
* target_alloc will allocate vtarget and map,
- * slave_alloc will fill in vdev from vtarget.
+ * slave_alloc will fill in vdevice from vtarget.
*/
if (ri->starget) {
vtarget = ri->starget->hostdata;
@@ -602,10 +601,10 @@ mptfc_slave_alloc(struct scsi_device *sdev)
{
MPT_SCSI_HOST *hd;
VirtTarget *vtarget;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
struct scsi_target *starget;
struct fc_rport *rport;
-
+ MPT_ADAPTER *ioc;
starget = scsi_target(sdev);
rport = starget_to_rport(starget);
@@ -613,31 +612,32 @@ mptfc_slave_alloc(struct scsi_device *sdev)
if (!rport || fc_remote_port_chkready(rport))
return -ENXIO;
- hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+ hd = shost_priv(sdev->host);
+ ioc = hd->ioc;
- vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
- if (!vdev) {
+ vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+ if (!vdevice) {
printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
- hd->ioc->name, sizeof(VirtDevice));
+ ioc->name, sizeof(VirtDevice));
return -ENOMEM;
}
- sdev->hostdata = vdev;
+ sdev->hostdata = vdevice;
vtarget = starget->hostdata;
if (vtarget->num_luns == 0) {
- vtarget->ioc_id = hd->ioc->id;
+ vtarget->ioc_id = ioc->id;
vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
}
- vdev->vtarget = vtarget;
- vdev->lun = sdev->lun;
+ vdevice->vtarget = vtarget;
+ vdevice->lun = sdev->lun;
vtarget->num_luns++;
- mptfc_dump_lun_info(hd->ioc, rport, sdev, vtarget);
+ mptfc_dump_lun_info(ioc, rport, sdev, vtarget);
return 0;
}
@@ -648,9 +648,9 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
struct mptfc_rport_info *ri;
struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
int err;
- VirtDevice *vdev = SCpnt->device->hostdata;
+ VirtDevice *vdevice = SCpnt->device->hostdata;
- if (!vdev || !vdev->vtarget) {
+ if (!vdevice || !vdevice->vtarget) {
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
@@ -675,6 +675,50 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
}
/*
+ * mptfc_display_port_link_speed - displaying link speed
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @portnum: IOC Port number
+ * @pp0dest: port page0 data payload
+ *
+ */
+static void
+mptfc_display_port_link_speed(MPT_ADAPTER *ioc, int portnum, FCPortPage0_t *pp0dest)
+{
+ u8 old_speed, new_speed, state;
+ char *old, *new;
+
+ if (portnum >= 2)
+ return;
+
+ old_speed = ioc->fc_link_speed[portnum];
+ new_speed = pp0dest->CurrentSpeed;
+ state = pp0dest->PortState;
+
+ if (state != MPI_FCPORTPAGE0_PORTSTATE_OFFLINE &&
+ new_speed != MPI_FCPORTPAGE0_CURRENT_SPEED_UKNOWN) {
+
+ old = old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" :
+ old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" :
+ old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" :
+ "Unknown";
+ new = new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" :
+ new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" :
+ new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" :
+ "Unknown";
+ if (old_speed == 0)
+ printk(MYIOC_s_NOTE_FMT
+ "FC Link Established, Speed = %s\n",
+ ioc->name, new);
+ else if (old_speed != new_speed)
+ printk(MYIOC_s_WARN_FMT
+ "FC Link Speed Change, Old Speed = %s, New Speed = %s\n",
+ ioc->name, old, new);
+
+ ioc->fc_link_speed[portnum] = new_speed;
+ }
+}
+
+/*
* mptfc_GetFcPortPage0 - Fetch FCPort config Page0.
* @ioc: Pointer to MPT_ADAPTER structure
* @portnum: IOC Port number
@@ -773,6 +817,7 @@ mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
" complete.\n",
ioc->name);
}
+ mptfc_display_port_link_speed(ioc, portnum, pp0dest);
}
pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
@@ -1023,6 +1068,18 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
}
static void
+mptfc_link_status_change(struct work_struct *work)
+{
+ MPT_ADAPTER *ioc =
+ container_of(work, MPT_ADAPTER, fc_rescan_work);
+ int ii;
+
+ for (ii=0; ii < ioc->facts.NumberOfPorts; ii++)
+ (void) mptfc_GetFcPortPage0(ioc, ii);
+
+}
+
+static void
mptfc_setup_reset(struct work_struct *work)
{
MPT_ADAPTER *ioc =
@@ -1163,6 +1220,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&ioc->fc_rescan_work_lock);
INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices);
INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset);
+ INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change);
spin_lock_irqsave(&ioc->FreeQlock, flags);
@@ -1218,20 +1276,21 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
- hd = (MPT_SCSI_HOST *) sh->hostdata;
+ hd = shost_priv(sh);
hd->ioc = ioc;
/* SCSI needs scsi_cmnd lookup table!
* (with size equal to req_depth*PtrSz!)
*/
- hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
- if (!hd->ScsiLookup) {
+ ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+ if (!ioc->ScsiLookup) {
error = -ENOMEM;
goto out_mptfc_probe;
}
+ spin_lock_init(&ioc->scsi_lookup_lock);
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
- ioc->name, hd->ScsiLookup));
+ ioc->name, ioc->ScsiLookup));
/* Clear the TM flags
*/
@@ -1262,8 +1321,8 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sh->transportt = mptfc_transport_template;
error = scsi_add_host (sh, &ioc->pcidev->dev);
if(error) {
- dprintk(ioc, printk(KERN_ERR MYNAM
- "scsi_add_host failed\n"));
+ dprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "scsi_add_host failed\n", ioc->name));
goto out_mptfc_probe;
}
@@ -1325,7 +1384,7 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
ioc->name, event));
if (ioc->sh == NULL ||
- ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
+ ((hd = shost_priv(ioc->sh)) == NULL))
return 1;
switch (event) {
@@ -1337,6 +1396,14 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
}
spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
break;
+ case MPI_EVENT_LINK_STATUS_CHANGE:
+ spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
+ if (ioc->fc_rescan_work_q) {
+ queue_work(ioc->fc_rescan_work_q,
+ &ioc->fc_lsc_work);
+ }
+ spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
+ break;
default:
rc = mptscsih_event_process(ioc,pEvReply);
break;
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index 01fc397fdd9..7950fc678ed 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -1,10 +1,10 @@
/*
* linux/drivers/message/fusion/mptlan.c
* IP Over Fibre Channel device driver.
- * For use with LSI Logic Fibre Channel PCI chip/adapters
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI Fibre Channel PCI chip/adapters
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 2000-2007 LSI Logic Corporation
+ * Copyright (c) 2000-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -154,7 +154,7 @@ static unsigned short mpt_lan_type_trans(struct sk_buff *skb,
/*
* Fusion MPT LAN private data
*/
-static int LanCtx = -1;
+static u8 LanCtx = MPT_MAX_PROTOCOL_DRIVERS;
static u32 max_buckets_out = 127;
static u32 tx_max_out_p = 127 - 16;
@@ -165,12 +165,6 @@ DEFINE_RWLOCK(bad_naa_lock);
#endif
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * Fusion MPT LAN external data
- */
-extern int mpt_lan_index;
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* lan_reply - Handle all data sent from the hardware.
* @ioc: Pointer to MPT_ADAPTER structure
@@ -1230,6 +1224,8 @@ mpt_lan_post_receive_buckets(struct mpt_lan_priv *priv)
}
pRecvReq = (LANReceivePostRequest_t *) mf;
+ i = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
+ mpt_dev->RequestNB[i] = 0;
count = buckets;
if (count > max)
count = max;
@@ -1351,10 +1347,11 @@ mpt_lan_post_receive_buckets_work(struct work_struct *work)
static struct net_device *
mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
{
- struct net_device *dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
- struct mpt_lan_priv *priv = NULL;
+ struct net_device *dev;
+ struct mpt_lan_priv *priv;
u8 HWaddr[FC_ALEN], *a;
+ dev = alloc_fcdev(sizeof(struct mpt_lan_priv));
if (!dev)
return NULL;
@@ -1366,7 +1363,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
priv->mpt_dev = mpt_dev;
priv->pnum = pnum;
- memset(&priv->post_buckets_task, 0, sizeof(priv->post_buckets_task));
INIT_DELAYED_WORK(&priv->post_buckets_task,
mpt_lan_post_receive_buckets_work);
priv->post_buckets_active = 0;
@@ -1391,8 +1387,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
spin_lock_init(&priv->txfidx_lock);
spin_lock_init(&priv->rxfidx_lock);
- memset(&priv->stats, 0, sizeof(priv->stats));
-
/* Grab pre-fetched LANPage1 stuff. :-) */
a = (u8 *) &mpt_dev->lan_cnfg_page1.HardwareAddressLow;
@@ -1427,8 +1421,6 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
dlprintk((KERN_INFO MYNAM ": Finished registering dev "
"and setting initial values\n"));
- SET_MODULE_OWNER(dev);
-
if (register_netdev(dev) != 0) {
free_netdev(dev);
dev = NULL;
@@ -1510,9 +1502,6 @@ static int __init mpt_lan_init (void)
return -EBUSY;
}
- /* Set the callback index to be used by driver core for turbo replies */
- mpt_lan_index = LanCtx;
-
dlprintk((KERN_INFO MYNAM ": assigned context of %d\n", LanCtx));
if (mpt_reset_register(LanCtx, mpt_lan_ioc_reset)) {
@@ -1533,10 +1522,9 @@ static void __exit mpt_lan_exit(void)
mpt_device_driver_deregister(MPTLAN_DRIVER);
mpt_reset_deregister(LanCtx);
- if (LanCtx >= 0) {
+ if (LanCtx) {
mpt_deregister(LanCtx);
- LanCtx = -1;
- mpt_lan_index = 0;
+ LanCtx = MPT_MAX_PROTOCOL_DRIVERS;
}
}
diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h
index 8d08c2bed24..bafb67fc818 100644
--- a/drivers/message/fusion/mptlan.h
+++ b/drivers/message/fusion/mptlan.h
@@ -1,10 +1,10 @@
/*
* linux/drivers/message/fusion/mptlan.h
* IP Over Fibre Channel device driver.
- * For use with LSI Logic Fibre Channel PCI chip/adapters
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI Fibre Channel PCI chip/adapters
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 2000-2007 LSI Logic Corporation
+ * Copyright (c) 2000-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -75,7 +75,7 @@
#include <asm/io.h>
/* Override mptbase.h by pre-defining these! */
-#define MODULEAUTHOR "LSI Logic Corporation"
+#define MODULEAUTHOR "LSI Corporation"
#include "mptbase.h"
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index b9c69bff218..e4c94f93de1 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -1,11 +1,10 @@
/*
* linux/drivers/message/fusion/mptsas.c
- * For use with LSI Logic PCI chip/adapter(s)
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI PCI chip/adapter(s)
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
- * Copyright (c) 2005-2007 Dell
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
@@ -61,6 +60,7 @@
#include "mptbase.h"
#include "mptscsih.h"
+#include "mptsas.h"
#define my_NAME "Fusion MPT SAS Host driver"
@@ -89,134 +89,35 @@ static int max_lun = MPTSAS_MAX_LUN;
module_param(max_lun, int, 0);
MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
-static int mptsasDoneCtx = -1;
-static int mptsasTaskCtx = -1;
-static int mptsasInternalCtx = -1; /* Used only for internal commands */
-static int mptsasMgmtCtx = -1;
+static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
+static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
static void mptsas_hotplug_work(struct work_struct *work);
-struct mptsas_target_reset_event {
- struct list_head list;
- EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
- u8 target_reset_issued;
-};
-
-enum mptsas_hotplug_action {
- MPTSAS_ADD_DEVICE,
- MPTSAS_DEL_DEVICE,
- MPTSAS_ADD_RAID,
- MPTSAS_DEL_RAID,
- MPTSAS_ADD_INACTIVE_VOLUME,
- MPTSAS_IGNORE_EVENT,
-};
-
-struct mptsas_hotplug_event {
- struct work_struct work;
- MPT_ADAPTER *ioc;
- enum mptsas_hotplug_action event_type;
- u64 sas_address;
- u8 channel;
- u8 id;
- u32 device_info;
- u16 handle;
- u16 parent_handle;
- u8 phy_id;
- u8 phys_disk_num_valid; /* hrc (hidden raid component) */
- u8 phys_disk_num; /* hrc - unique index*/
- u8 hidden_raid_component; /* hrc - don't expose*/
-};
-
-struct mptsas_discovery_event {
- struct work_struct work;
- MPT_ADAPTER *ioc;
-};
-
-/*
- * SAS topology structures
- *
- * The MPT Fusion firmware interface spreads information about the
- * SAS topology over many manufacture pages, thus we need some data
- * structure to collect it and process it for the SAS transport class.
- */
-
-struct mptsas_devinfo {
- u16 handle; /* unique id to address this device */
- u16 handle_parent; /* unique id to address parent device */
- u16 handle_enclosure; /* enclosure identifier of the enclosure */
- u16 slot; /* physical slot in enclosure */
- u8 phy_id; /* phy number of parent device */
- u8 port_id; /* sas physical port this device
- is assoc'd with */
- u8 id; /* logical target id of this device */
- u32 phys_disk_num; /* phys disk id, for csmi-ioctls */
- u8 channel; /* logical bus number of this device */
- u64 sas_address; /* WWN of this device,
- SATA is assigned by HBA,expander */
- u32 device_info; /* bitfield detailed info about this device */
-};
-
-/*
- * Specific details on ports, wide/narrow
- */
-struct mptsas_portinfo_details{
- u16 num_phys; /* number of phys belong to this port */
- u64 phy_bitmask; /* TODO, extend support for 255 phys */
- struct sas_rphy *rphy; /* transport layer rphy object */
- struct sas_port *port; /* transport layer port object */
- struct scsi_target *starget;
- struct mptsas_portinfo *port_info;
-};
-
-struct mptsas_phyinfo {
- u16 handle; /* unique id to address this */
- u8 phy_id; /* phy index */
- u8 port_id; /* firmware port identifier */
- u8 negotiated_link_rate; /* nego'd link rate for this phy */
- u8 hw_link_rate; /* hardware max/min phys link rate */
- u8 programmed_link_rate; /* programmed max/min phy link rate */
- u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/
- struct mptsas_devinfo identify; /* point to phy device info */
- struct mptsas_devinfo attached; /* point to attached device info */
- struct sas_phy *phy; /* transport layer phy object */
- struct mptsas_portinfo *portinfo;
- struct mptsas_portinfo_details * port_details;
-};
-
-struct mptsas_portinfo {
- struct list_head list;
- u16 num_phys; /* number of phys */
- struct mptsas_phyinfo *phy_info;
-};
-
-struct mptsas_enclosure {
- u64 enclosure_logical_id; /* The WWN for the enclosure */
- u16 enclosure_handle; /* unique id to address this */
- u16 flags; /* details enclosure management */
- u16 num_slot; /* num slots */
- u16 start_slot; /* first slot */
- u8 start_id; /* starting logical target id */
- u8 start_channel; /* starting logical channel id */
- u8 sep_id; /* SEP device logical target id */
- u8 sep_channel; /* SEP channel logical channel id */
-};
-
static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
{
- dsasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n"));
- dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n",
- le16_to_cpu(phy_data->AttachedDeviceHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n",
- le16_to_cpu(phy_data->ControllerDevHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n", phy_data->Port));
- dsasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n", phy_data->PortFlags));
- dsasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n", phy_data->PhyFlags));
- dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate));
- dsasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n",
- le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
- dsasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n\n",
- le32_to_cpu(phy_data->DiscoveryStatus)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "---- IO UNIT PAGE 0 ------------\n", ioc->name));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
+ ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
+ ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
+ ioc->name, phy_data->Port));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
+ ioc->name, phy_data->PortFlags));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
+ ioc->name, phy_data->PhyFlags));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
+ ioc->name, phy_data->NegotiatedLinkRate));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Controller PHY Device Info=0x%X\n", ioc->name,
+ le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
+ ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
}
static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
@@ -225,27 +126,41 @@ static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
- dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n"));
- dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n",
- le16_to_cpu(pg0->AttachedDevHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n",
- (unsigned long long)le64_to_cpu(sas_address)));
- dsasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier));
- dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n",
- le32_to_cpu(pg0->AttachedDeviceInfo)));
- dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate));
- dsasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n", pg0->ChangeCount));
- dsasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n\n", le32_to_cpu(pg0->PhyInfo)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "---- SAS PHY PAGE 0 ------------\n", ioc->name));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Attached Device Handle=0x%X\n", ioc->name,
+ le16_to_cpu(pg0->AttachedDevHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
+ ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Attached PHY Identifier=0x%X\n", ioc->name,
+ pg0->AttachedPhyIdentifier));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
+ ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
+ ioc->name, pg0->ProgrammedLinkRate));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
+ ioc->name, pg0->ChangeCount));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
+ ioc->name, le32_to_cpu(pg0->PhyInfo)));
}
static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
{
- dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n"));
- dsasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount));
- dsasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n",
- pg1->RunningDisparityErrorCount));
- dsasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount));
- dsasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n\n", pg1->PhyResetProblemCount));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "---- SAS PHY PAGE 1 ------------\n", ioc->name));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
+ ioc->name, pg1->InvalidDwordCount));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Running Disparity Error Count=0x%x\n", ioc->name,
+ pg1->RunningDisparityErrorCount));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Loss Dword Synch Count=0x%x\n", ioc->name,
+ pg1->LossDwordSynchCount));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "PHY Reset Problem Count=0x%x\n\n", ioc->name,
+ pg1->PhyResetProblemCount));
}
static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
@@ -254,37 +169,53 @@ static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
- dsasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 0 ---------\n"));
- dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "Slot=0x%X\n", le16_to_cpu(pg0->Slot)));
- dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", (unsigned long long)
- le64_to_cpu(sas_address)));
- dsasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%X\n", pg0->TargetID));
- dsasprintk(ioc, printk(KERN_DEBUG "Bus=0x%X\n", pg0->Bus));
- /* The PhyNum field specifies the PHY number of the parent
- * device this device is linked to
- */
- dsasprintk(ioc, printk(KERN_DEBUG "Parent Phy Num=0x%X\n", pg0->PhyNum));
- dsasprintk(ioc, printk(KERN_DEBUG "Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus)));
- dsasprintk(ioc, printk(KERN_DEBUG "Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo)));
- dsasprintk(ioc, printk(KERN_DEBUG "Flags=0x%X\n", le16_to_cpu(pg0->Flags)));
- dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n\n", pg0->PhysicalPort));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
+ ioc->name, le16_to_cpu(pg0->DevHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
+ ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
+ ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
+ ioc->name, le16_to_cpu(pg0->Slot)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
+ ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
+ ioc->name, pg0->TargetID));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
+ ioc->name, pg0->Bus));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
+ ioc->name, pg0->PhyNum));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
+ ioc->name, le16_to_cpu(pg0->AccessStatus)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
+ ioc->name, le32_to_cpu(pg0->DeviceInfo)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
+ ioc->name, le16_to_cpu(pg0->Flags)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
+ ioc->name, pg0->PhysicalPort));
}
static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
{
- dsasprintk(ioc, printk(KERN_DEBUG "---- SAS EXPANDER PAGE 1 ------------\n"));
- dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n", pg1->PhysicalPort));
- dsasprintk(ioc, printk(KERN_DEBUG "PHY Identifier=0x%X\n", pg1->PhyIdentifier));
- dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate));
- dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate));
- dsasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n", pg1->HwLinkRate));
- dsasprintk(ioc, printk(KERN_DEBUG "Owner Device Handle=0x%X\n",
- le16_to_cpu(pg1->OwnerDevHandle)));
- dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n\n",
- le16_to_cpu(pg1->AttachedDevHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
+ ioc->name, pg1->PhysicalPort));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
+ ioc->name, pg1->PhyIdentifier));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
+ ioc->name, pg1->NegotiatedLinkRate));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
+ ioc->name, pg1->ProgrammedLinkRate));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
+ ioc->name, pg1->HwLinkRate));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
+ ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
+ dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Attached Device Handle=0x%X\n\n", ioc->name,
+ le16_to_cpu(pg1->AttachedDevHandle)));
}
static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
@@ -354,8 +285,8 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai
port_info = port_details->port_info;
phy_info = port_info->phy_info;
- dsaswideprintk(ioc, printk(KERN_DEBUG "%s: [%p]: num_phys=%02d "
- "bitmask=0x%016llX\n", __FUNCTION__, port_details,
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
+ "bitmask=0x%016llX\n", ioc->name, __FUNCTION__, port_details,
port_details->num_phys, (unsigned long long)
port_details->phy_bitmask));
@@ -382,14 +313,15 @@ mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rp
{
if (phy_info->port_details) {
phy_info->port_details->rphy = rphy;
- dsaswideprintk(ioc, printk(KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
+ ioc->name, rphy));
}
if (rphy) {
dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
- &rphy->dev, "add:"));
- dsaswideprintk(ioc, printk(KERN_DEBUG "rphy=%p release=%p\n",
- rphy, rphy->dev.release));
+ &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
+ ioc->name, rphy, rphy->dev.release));
}
}
@@ -410,9 +342,9 @@ mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_po
if (port) {
dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
- &port->dev, "add:"));
- dsaswideprintk(ioc, printk(KERN_DEBUG "port=%p release=%p\n",
- port, port->dev.release));
+ &port->dev, MYIOC_s_FMT "add:", ioc->name));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
+ ioc->name, port, port->dev.release));
}
}
@@ -463,9 +395,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
* Removing a phy from a port, letting the last
* phy be removed by firmware events.
*/
- dsaswideprintk(ioc, printk(KERN_DEBUG
- "%s: [%p]: deleting phy = %d\n",
- __FUNCTION__, port_details, i));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s: [%p]: deleting phy = %d\n",
+ ioc->name, __FUNCTION__, port_details, i));
port_details->num_phys--;
port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
@@ -479,8 +411,8 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
phy_info = port_info->phy_info;
for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
sas_address = phy_info->attached.sas_address;
- dsaswideprintk(ioc, printk(KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
- i, (unsigned long long)sas_address));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
+ ioc->name, i, (unsigned long long)sas_address));
if (!sas_address)
continue;
port_details = phy_info->port_details;
@@ -498,9 +430,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
port_details->phy_bitmask |=
(1 << phy_info->phy_id);
phy_info->sas_port_add_phy=1;
- dsaswideprintk(ioc, printk(KERN_DEBUG "\t\tForming port\n\t\t"
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
"phy_id=%d sas_address=0x%018llX\n",
- i, (unsigned long long)sas_address));
+ ioc->name, i, (unsigned long long)sas_address));
phy_info->port_details = port_details;
}
@@ -515,9 +447,9 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
continue;
if (phy_info_cmp->port_details == port_details )
continue;
- dsaswideprintk(ioc, printk(KERN_DEBUG
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"\t\tphy_id=%d sas_address=0x%018llX\n",
- j, (unsigned long long)
+ ioc->name, j, (unsigned long long)
phy_info_cmp->attached.sas_address));
if (phy_info_cmp->port_details) {
port_details->rphy =
@@ -549,15 +481,15 @@ mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
port_details = port_info->phy_info[i].port_details;
if (!port_details)
continue;
- dsaswideprintk(ioc, printk(KERN_DEBUG
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"%s: [%p]: phy_id=%02d num_phys=%02d "
- "bitmask=0x%016llX\n", __FUNCTION__,
+ "bitmask=0x%016llX\n", ioc->name, __FUNCTION__,
port_details, i, port_details->num_phys,
(unsigned long long)port_details->phy_bitmask));
- dsaswideprintk(ioc, printk(KERN_DEBUG"\t\tport = %p rphy=%p\n",
- port_details->port, port_details->rphy));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
+ ioc->name, port_details->port, port_details->rphy));
}
- dsaswideprintk(ioc, printk(KERN_DEBUG"\n"));
+ dsaswideprintk(ioc, printk("\n"));
mutex_unlock(&ioc->sas_topology_mutex);
}
@@ -573,15 +505,15 @@ static VirtTarget *
mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
{
struct scsi_device *sdev;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
VirtTarget *vtarget = NULL;
shost_for_each_device(sdev, ioc->sh) {
- if ((vdev = sdev->hostdata) == NULL)
+ if ((vdevice = sdev->hostdata) == NULL)
continue;
- if (vdev->vtarget->id == id &&
- vdev->vtarget->channel == channel)
- vtarget = vdev->vtarget;
+ if (vdevice->vtarget->id == id &&
+ vdevice->vtarget->channel == channel)
+ vtarget = vdevice->vtarget;
}
return vtarget;
}
@@ -623,13 +555,7 @@ mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
- if (mpt_send_handshake_request(ioc->TaskCtx, ioc,
- sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) {
- mpt_free_msg_frame(ioc, mf);
- dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
- ioc->name,__FUNCTION__, __LINE__));
- return 0;
- }
+ mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
return 1;
}
@@ -649,7 +575,7 @@ static void
mptsas_target_reset_queue(MPT_ADAPTER *ioc,
EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
{
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
VirtTarget *vtarget = NULL;
struct mptsas_target_reset_event *target_reset_list;
u8 id, channel;
@@ -696,7 +622,7 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
static void
mptsas_dev_reset_complete(MPT_ADAPTER *ioc)
{
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
struct list_head *head = &hd->target_reset_list;
struct mptsas_target_reset_event *target_reset_list;
struct mptsas_hotplug_event *ev;
@@ -813,7 +739,7 @@ mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
if (!ioc->sh || !ioc->sh->hostdata)
goto out;
- hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ hd = shost_priv(ioc->sh);
if (!hd->ioc)
goto out;
@@ -913,19 +839,20 @@ static int
mptsas_target_alloc(struct scsi_target *starget)
{
struct Scsi_Host *host = dev_to_shost(&starget->dev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
VirtTarget *vtarget;
u8 id, channel;
struct sas_rphy *rphy;
struct mptsas_portinfo *p;
int i;
+ MPT_ADAPTER *ioc = hd->ioc;
vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
if (!vtarget)
return -ENOMEM;
vtarget->starget = starget;
- vtarget->ioc_id = hd->ioc->id;
+ vtarget->ioc_id = ioc->id;
vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
id = starget->id;
channel = 0;
@@ -934,15 +861,15 @@ mptsas_target_alloc(struct scsi_target *starget)
* RAID volumes placed beyond the last expected port.
*/
if (starget->channel == MPTSAS_RAID_CHANNEL) {
- for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
- if (id == hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
- channel = hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
+ for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
+ if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
+ channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
goto out;
}
rphy = dev_to_rphy(starget->dev.parent);
- mutex_lock(&hd->ioc->sas_topology_mutex);
- list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+ mutex_lock(&ioc->sas_topology_mutex);
+ list_for_each_entry(p, &ioc->sas_topology, list) {
for (i = 0; i < p->num_phys; i++) {
if (p->phy_info[i].attached.sas_address !=
rphy->identify.sas_address)
@@ -954,18 +881,18 @@ mptsas_target_alloc(struct scsi_target *starget)
/*
* Exposing hidden raid components
*/
- if (mptscsih_is_phys_disk(hd->ioc, channel, id)) {
- id = mptscsih_raid_id_to_num(hd->ioc,
+ if (mptscsih_is_phys_disk(ioc, channel, id)) {
+ id = mptscsih_raid_id_to_num(ioc,
channel, id);
vtarget->tflags |=
MPT_TARGET_FLAGS_RAID_COMPONENT;
p->phy_info[i].attached.phys_disk_num = id;
}
- mutex_unlock(&hd->ioc->sas_topology_mutex);
+ mutex_unlock(&ioc->sas_topology_mutex);
goto out;
}
}
- mutex_unlock(&hd->ioc->sas_topology_mutex);
+ mutex_unlock(&ioc->sas_topology_mutex);
kfree(vtarget);
return -ENXIO;
@@ -981,10 +908,11 @@ static void
mptsas_target_destroy(struct scsi_target *starget)
{
struct Scsi_Host *host = dev_to_shost(&starget->dev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
struct sas_rphy *rphy;
struct mptsas_portinfo *p;
int i;
+ MPT_ADAPTER *ioc = hd->ioc;
if (!starget->hostdata)
return;
@@ -993,7 +921,7 @@ mptsas_target_destroy(struct scsi_target *starget)
goto out;
rphy = dev_to_rphy(starget->dev.parent);
- list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+ list_for_each_entry(p, &ioc->sas_topology, list) {
for (i = 0; i < p->num_phys; i++) {
if (p->phy_info[i].attached.sas_address !=
rphy->identify.sas_address)
@@ -1013,61 +941,62 @@ static int
mptsas_slave_alloc(struct scsi_device *sdev)
{
struct Scsi_Host *host = sdev->host;
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
struct sas_rphy *rphy;
struct mptsas_portinfo *p;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
struct scsi_target *starget;
int i;
+ MPT_ADAPTER *ioc = hd->ioc;
- vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
- if (!vdev) {
+ vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+ if (!vdevice) {
printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
- hd->ioc->name, sizeof(VirtDevice));
+ ioc->name, sizeof(VirtDevice));
return -ENOMEM;
}
starget = scsi_target(sdev);
- vdev->vtarget = starget->hostdata;
+ vdevice->vtarget = starget->hostdata;
if (sdev->channel == MPTSAS_RAID_CHANNEL)
goto out;
rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
- mutex_lock(&hd->ioc->sas_topology_mutex);
- list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+ mutex_lock(&ioc->sas_topology_mutex);
+ list_for_each_entry(p, &ioc->sas_topology, list) {
for (i = 0; i < p->num_phys; i++) {
if (p->phy_info[i].attached.sas_address !=
rphy->identify.sas_address)
continue;
- vdev->lun = sdev->lun;
+ vdevice->lun = sdev->lun;
/*
* Exposing hidden raid components
*/
- if (mptscsih_is_phys_disk(hd->ioc,
+ if (mptscsih_is_phys_disk(ioc,
p->phy_info[i].attached.channel,
p->phy_info[i].attached.id))
sdev->no_uld_attach = 1;
- mutex_unlock(&hd->ioc->sas_topology_mutex);
+ mutex_unlock(&ioc->sas_topology_mutex);
goto out;
}
}
- mutex_unlock(&hd->ioc->sas_topology_mutex);
+ mutex_unlock(&ioc->sas_topology_mutex);
- kfree(vdev);
+ kfree(vdevice);
return -ENXIO;
out:
- vdev->vtarget->num_luns++;
- sdev->hostdata = vdev;
+ vdevice->vtarget->num_luns++;
+ sdev->hostdata = vdevice;
return 0;
}
static int
mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
- VirtDevice *vdev = SCpnt->device->hostdata;
+ VirtDevice *vdevice = SCpnt->device->hostdata;
- if (!vdev || !vdev->vtarget || vdev->vtarget->deleted) {
+ if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
@@ -1239,10 +1168,8 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
/* process the completed Reply Message Frame */
reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
- printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
- __FUNCTION__,
- reply->IOCStatus,
- reply->IOCLogInfo);
+ printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
+ ioc->name, __FUNCTION__, reply->IOCStatus, reply->IOCLogInfo);
error = -ENXIO;
goto out_unlock;
}
@@ -1328,16 +1255,16 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
u64 sas_address = 0;
if (!rsp) {
- printk(KERN_ERR "%s: the smp response space is missing\n",
- __FUNCTION__);
+ printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
+ ioc->name, __FUNCTION__);
return -EINVAL;
}
/* do we need to support multiple segments? */
if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
- printk(KERN_ERR "%s: multiple segments req %u %u, rsp %u %u\n",
- __FUNCTION__, req->bio->bi_vcnt, req->data_len,
- rsp->bio->bi_vcnt, rsp->data_len);
+ printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
+ ioc->name, __FUNCTION__, req->bio->bi_vcnt, req->data_len,
+ rsp->bio->bi_vcnt, rsp->data_len);
return -EINVAL;
}
@@ -1402,7 +1329,7 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
if (!timeleft) {
- printk(KERN_ERR "%s: smp timeout!\n", __FUNCTION__);
+ printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __FUNCTION__);
/* On timeout reset the board */
mpt_HardResetHandler(ioc, CAN_SLEEP);
ret = -ETIMEDOUT;
@@ -1417,8 +1344,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
memcpy(req->sense, smprep, sizeof(*smprep));
req->sense_len = sizeof(*smprep);
} else {
- printk(KERN_ERR "%s: smp passthru reply failed to be returned\n",
- __FUNCTION__);
+ printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n",
+ ioc->name, __FUNCTION__);
ret = -ENXIO;
}
unmap:
@@ -2062,12 +1989,12 @@ static int mptsas_probe_one_phy(struct device *dev,
goto out;
}
mptsas_set_port(ioc, phy_info, port);
- dsaswideprintk(ioc, printk(KERN_DEBUG
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"sas_port_alloc: port=%p dev=%p port_id=%d\n",
- port, dev, port->port_identifier));
+ ioc->name, port, dev, port->port_identifier));
}
- dsaswideprintk(ioc, printk(KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
- phy_info->phy_id));
+ dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",
+ ioc->name, phy_info->phy_id));
sas_port_add_phy(port, phy_info->phy);
phy_info->sas_port_add_phy = 0;
}
@@ -2369,8 +2296,9 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
expander_sas_address)
continue;
dsaswideprintk(ioc,
- dev_printk(KERN_DEBUG, &port->dev,
- "delete port (%d)\n", port->port_identifier));
+ dev_printk(KERN_DEBUG, &port->dev,
+ MYIOC_s_FMT "delete port (%d)\n", ioc->name,
+ port->port_identifier));
sas_port_delete(port);
mptsas_port_delete(ioc, phy_info->port_details);
}
@@ -2613,7 +2541,7 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
- printk(KERN_WARNING "mptsas: lost hotplug event\n");
+ printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name);
goto out;
}
@@ -2754,8 +2682,8 @@ mptsas_hotplug_work(struct work_struct *work)
printk(MYIOC_s_INFO_FMT
"removing %s device, channel %d, id %d, phy %d\n",
ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
- dev_printk(KERN_DEBUG, &port->dev,
- "delete port (%d)\n", port->port_identifier);
+ dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
+ "delete port (%d)\n", ioc->name, port->port_identifier);
sas_port_delete(port);
mptsas_port_delete(ioc, phy_info->port_details);
break;
@@ -2796,8 +2724,8 @@ mptsas_hotplug_work(struct work_struct *work)
if (!vtarget) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
- "%s: exit at line=%d\n", ioc->name,
- __FUNCTION__, __LINE__));
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
break;
}
/*
@@ -2930,7 +2858,7 @@ mptsas_send_sas_event(MPT_ADAPTER *ioc,
case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
- printk(KERN_WARNING "mptsas: lost hotplug event\n");
+ printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
break;
}
@@ -2989,7 +2917,7 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc,
ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
- printk(KERN_WARNING "mptsas: lost hotplug event\n");
+ printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name);
return;
}
@@ -3288,20 +3216,22 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sh->sg_tablesize = numSGE;
}
- hd = (MPT_SCSI_HOST *) sh->hostdata;
+ hd = shost_priv(sh);
hd->ioc = ioc;
/* SCSI needs scsi_cmnd lookup table!
* (with size equal to req_depth*PtrSz!)
*/
- hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
- if (!hd->ScsiLookup) {
+ ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+ if (!ioc->ScsiLookup) {
error = -ENOMEM;
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
goto out_mptsas_probe;
}
+ spin_lock_init(&ioc->scsi_lookup_lock);
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
- ioc->name, hd->ScsiLookup));
+ ioc->name, ioc->ScsiLookup));
/* Clear the TM flags
*/
@@ -3340,8 +3270,8 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
error = scsi_add_host(sh, &ioc->pcidev->dev);
if (error) {
- dprintk(ioc, printk(KERN_ERR MYNAM
- "scsi_add_host failed\n"));
+ dprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "scsi_add_host failed\n", ioc->name));
goto out_mptsas_probe;
}
diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h
new file mode 100644
index 00000000000..7c150f50629
--- /dev/null
+++ b/drivers/message/fusion/mptsas.h
@@ -0,0 +1,158 @@
+/*
+ * linux/drivers/message/fusion/mptsas.h
+ * High performance SCSI + LAN / Fibre Channel device drivers.
+ * For use with PCI chip/adapter(s):
+ * LSIFC9xx/LSI409xx Fibre Channel
+ * running LSI MPT (Message Passing Technology) firmware.
+ *
+ * Copyright (c) 1999-2007 LSI Corporation
+ * (mailto:DL-MPTFusionLinux@lsi.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.
+
+ NO WARRANTY
+ THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ solely responsible for determining the appropriateness of using and
+ distributing the Program and assumes all risks associated with its
+ exercise of rights under this Agreement, including but not limited to
+ the risks and costs of program errors, damage to or loss of data,
+ programs or equipment, and unavailability or interruption of operations.
+
+ DISCLAIMER OF LIABILITY
+ NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef MPTSAS_H_INCLUDED
+#define MPTSAS_H_INCLUDED
+/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+struct mptsas_target_reset_event {
+ struct list_head list;
+ EVENT_DATA_SAS_DEVICE_STATUS_CHANGE sas_event_data;
+ u8 target_reset_issued;
+};
+
+enum mptsas_hotplug_action {
+ MPTSAS_ADD_DEVICE,
+ MPTSAS_DEL_DEVICE,
+ MPTSAS_ADD_RAID,
+ MPTSAS_DEL_RAID,
+ MPTSAS_ADD_INACTIVE_VOLUME,
+ MPTSAS_IGNORE_EVENT,
+};
+
+struct mptsas_hotplug_event {
+ struct work_struct work;
+ MPT_ADAPTER *ioc;
+ enum mptsas_hotplug_action event_type;
+ u64 sas_address;
+ u8 channel;
+ u8 id;
+ u32 device_info;
+ u16 handle;
+ u16 parent_handle;
+ u8 phy_id;
+ u8 phys_disk_num_valid; /* hrc (hidden raid component) */
+ u8 phys_disk_num; /* hrc - unique index*/
+ u8 hidden_raid_component; /* hrc - don't expose*/
+};
+
+struct mptsas_discovery_event {
+ struct work_struct work;
+ MPT_ADAPTER *ioc;
+};
+
+/*
+ * SAS topology structures
+ *
+ * The MPT Fusion firmware interface spreads information about the
+ * SAS topology over many manufacture pages, thus we need some data
+ * structure to collect it and process it for the SAS transport class.
+ */
+
+struct mptsas_devinfo {
+ u16 handle; /* unique id to address this device */
+ u16 handle_parent; /* unique id to address parent device */
+ u16 handle_enclosure; /* enclosure identifier of the enclosure */
+ u16 slot; /* physical slot in enclosure */
+ u8 phy_id; /* phy number of parent device */
+ u8 port_id; /* sas physical port this device
+ is assoc'd with */
+ u8 id; /* logical target id of this device */
+ u32 phys_disk_num; /* phys disk id, for csmi-ioctls */
+ u8 channel; /* logical bus number of this device */
+ u64 sas_address; /* WWN of this device,
+ SATA is assigned by HBA,expander */
+ u32 device_info; /* bitfield detailed info about this device */
+};
+
+/*
+ * Specific details on ports, wide/narrow
+ */
+struct mptsas_portinfo_details{
+ u16 num_phys; /* number of phys belong to this port */
+ u64 phy_bitmask; /* TODO, extend support for 255 phys */
+ struct sas_rphy *rphy; /* transport layer rphy object */
+ struct sas_port *port; /* transport layer port object */
+ struct scsi_target *starget;
+ struct mptsas_portinfo *port_info;
+};
+
+struct mptsas_phyinfo {
+ u16 handle; /* unique id to address this */
+ u8 phy_id; /* phy index */
+ u8 port_id; /* firmware port identifier */
+ u8 negotiated_link_rate; /* nego'd link rate for this phy */
+ u8 hw_link_rate; /* hardware max/min phys link rate */
+ u8 programmed_link_rate; /* programmed max/min phy link rate */
+ u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/
+ struct mptsas_devinfo identify; /* point to phy device info */
+ struct mptsas_devinfo attached; /* point to attached device info */
+ struct sas_phy *phy; /* transport layer phy object */
+ struct mptsas_portinfo *portinfo;
+ struct mptsas_portinfo_details * port_details;
+};
+
+struct mptsas_portinfo {
+ struct list_head list;
+ u16 num_phys; /* number of phys */
+ struct mptsas_phyinfo *phy_info;
+};
+
+struct mptsas_enclosure {
+ u64 enclosure_logical_id; /* The WWN for the enclosure */
+ u16 enclosure_handle; /* unique id to address this */
+ u16 flags; /* details enclosure management */
+ u16 num_slot; /* num slots */
+ u16 start_slot; /* first slot */
+ u8 start_id; /* starting logical target id */
+ u8 start_channel; /* starting logical channel id */
+ u8 sep_id; /* SEP device logical target id */
+ u8 sep_channel; /* SEP channel logical channel id */
+};
+
+/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#endif
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 5431529741a..626bb3c9af2 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -1,9 +1,9 @@
/*
* linux/drivers/message/fusion/mptscsih.c
- * For use with LSI Logic PCI chip/adapter(s)
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI PCI chip/adapter(s)
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -80,6 +80,10 @@ MODULE_VERSION(my_VERSION);
/*
* Other private/forward protos...
*/
+static struct scsi_cmnd * mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i);
+static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i);
+static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd);
+static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd);
int mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
static void mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSIIORequest_t *pScsiReq);
int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
@@ -90,7 +94,6 @@ static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
-static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
@@ -192,7 +195,7 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
int chain_idx;
dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
- ioc->name));
+ ioc->name));
spin_lock_irqsave(&ioc->FreeQlock, flags);
if (!list_empty(&ioc->FreeChainQ)) {
int offset;
@@ -203,13 +206,14 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex)
offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
chain_idx = offset / ioc->req_sz;
rc = SUCCESS;
- dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
- ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
+ ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
} else {
rc = FAILED;
chain_idx = MPT_HOST_NO_CHAIN;
- dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer failed\n",
- ioc->name));
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n",
+ ioc->name));
}
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
@@ -289,7 +293,7 @@ nextSGEset:
for (ii=0; ii < (numSgeThisFrame-1); ii++) {
thisxfer = sg_dma_len(sg);
if (thisxfer == 0) {
- sg ++; /* Get next SG element from the OS */
+ sg = sg_next(sg); /* Get next SG element from the OS */
sg_done++;
continue;
}
@@ -297,7 +301,7 @@ nextSGEset:
v2 = sg_dma_address(sg);
mptscsih_add_sge(psge, sgflags | thisxfer, v2);
- sg++; /* Get next SG element from the OS */
+ sg = sg_next(sg); /* Get next SG element from the OS */
psge += (sizeof(u32) + sizeof(dma_addr_t));
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
sg_done++;
@@ -318,7 +322,7 @@ nextSGEset:
v2 = sg_dma_address(sg);
mptscsih_add_sge(psge, sgflags | thisxfer, v2);
/*
- sg++;
+ sg = sg_next(sg);
psge += (sizeof(u32) + sizeof(dma_addr_t));
*/
sgeOffset += (sizeof(u32) + sizeof(dma_addr_t));
@@ -419,8 +423,8 @@ nextSGEset:
* out the Address and Flags fields.
*/
chainSge = (char *) psge;
- dsgprintk(ioc, printk(KERN_DEBUG " Current buff @ %p (index 0x%x)",
- psge, req_idx));
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Current buff @ %p (index 0x%x)",
+ ioc->name, psge, req_idx));
/* Start the SGE for the next buffer
*/
@@ -428,8 +432,8 @@ nextSGEset:
sgeOffset = 0;
sg_done = 0;
- dsgprintk(ioc, printk(KERN_DEBUG " Chain buff @ %p (index 0x%x)\n",
- psge, chain_idx));
+ dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Chain buff @ %p (index 0x%x)\n",
+ ioc->name, psge, chain_idx));
/* Start the SGE for the next buffer
*/
@@ -588,18 +592,17 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc
}
scsi_print_command(sc);
- printk(KERN_DEBUG "\tfw_channel = %d, fw_id = %d\n",
- pScsiReply->Bus, pScsiReply->TargetID);
- printk(KERN_DEBUG "\trequest_len = %d, underflow = %d, resid = %d\n",
- scsi_bufflen(sc), sc->underflow, scsi_get_resid(sc));
- printk(KERN_DEBUG "\ttag = %d, transfer_count = %d, sc->result = %08X\n",
- le16_to_cpu(pScsiReply->TaskTag),
+ printk(MYIOC_s_DEBUG_FMT "\tfw_channel = %d, fw_id = %d\n",
+ ioc->name, pScsiReply->Bus, pScsiReply->TargetID);
+ printk(MYIOC_s_DEBUG_FMT "\trequest_len = %d, underflow = %d, "
+ "resid = %d\n", ioc->name, scsi_bufflen(sc), sc->underflow,
+ scsi_get_resid(sc));
+ printk(MYIOC_s_DEBUG_FMT "\ttag = %d, transfer_count = %d, "
+ "sc->result = %08X\n", ioc->name, le16_to_cpu(pScsiReply->TaskTag),
le32_to_cpu(pScsiReply->TransferCount), sc->result);
-
- printk(KERN_DEBUG "\tiocstatus = %s (0x%04x), "
+ printk(MYIOC_s_DEBUG_FMT "\tiocstatus = %s (0x%04x), "
"scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
- desc, ioc_status,
- desc1, pScsiReply->SCSIStatus,
+ ioc->name, desc, ioc_status, desc1, pScsiReply->SCSIStatus,
pScsiReply->SCSIState);
if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
@@ -607,9 +610,8 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc
asc = sc->sense_buffer[12];
ascq = sc->sense_buffer[13];
- printk(KERN_DEBUG "\t[sense_key,asc,ascq]: "
- "[0x%02x,0x%02x,0x%02x]\n",
- skey, asc, ascq);
+ printk(MYIOC_s_DEBUG_FMT "\t[sense_key,asc,ascq]: "
+ "[0x%02x,0x%02x,0x%02x]\n", ioc->name, skey, asc, ascq);
}
/*
@@ -617,8 +619,8 @@ mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pSc
*/
if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
pScsiReply->ResponseInfo)
- printk(KERN_DEBUG "response_info = %08xh\n",
- le32_to_cpu(pScsiReply->ResponseInfo));
+ printk(MYIOC_s_DEBUG_FMT "response_info = %08xh\n",
+ ioc->name, le32_to_cpu(pScsiReply->ResponseInfo));
}
#endif
@@ -645,11 +647,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
SCSIIORequest_t *pScsiReq;
SCSIIOReply_t *pScsiReply;
u16 req_idx, req_idx_MR;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
VirtTarget *vtarget;
- hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
-
+ hd = shost_priv(ioc->sh);
req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
req_idx_MR = (mr != NULL) ?
le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx) : req_idx;
@@ -660,12 +661,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
printk (MYIOC_s_ERR_FMT
"req_idx=%x req_idx_MR=%x mf=%p mr=%p sc=%p\n",
ioc->name, req_idx, req_idx_MR, mf, mr,
- hd->ScsiLookup[req_idx_MR]);
+ mptscsih_get_scsi_lookup(ioc, req_idx_MR));
return 0;
}
- sc = hd->ScsiLookup[req_idx];
- hd->ScsiLookup[req_idx] = NULL;
+ sc = mptscsih_getclear_scsi_lookup(ioc, req_idx);
if (sc == NULL) {
MPIHeader_t *hdr = (MPIHeader_t *)mf;
@@ -738,8 +738,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
*/
if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
pScsiReply->ResponseInfo) {
- printk(KERN_NOTICE "[%d:%d:%d:%d] "
- "FCP_ResponseInfo=%08xh\n",
+ printk(MYIOC_s_NOTE_FMT "[%d:%d:%d:%d] "
+ "FCP_ResponseInfo=%08xh\n", ioc->name,
sc->device->host->host_no, sc->device->channel,
sc->device->id, sc->device->lun,
le32_to_cpu(pScsiReply->ResponseInfo));
@@ -771,10 +771,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
hd->sel_timeout[pScsiReq->TargetID]++;
- vdev = sc->device->hostdata;
- if (!vdev)
+ vdevice = sc->device->hostdata;
+ if (!vdevice)
break;
- vtarget = vdev->vtarget;
+ vtarget = vdevice->vtarget;
if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
mptscsih_issue_sep_command(ioc, vtarget,
MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
@@ -824,9 +824,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
sc->result=DID_SOFT_ERROR << 16;
else /* Sufficient data transfer occurred */
sc->result = (DID_OK << 16) | scsi_status;
- dreplyprintk(ioc, printk(KERN_DEBUG
+ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
- sc->result, sc->device->channel, sc->device->id));
+ ioc->name, sc->result, sc->device->channel, sc->device->id));
break;
case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */
@@ -858,9 +858,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
}
- dreplyprintk(ioc, printk(KERN_DEBUG " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
- sc->underflow));
- dreplyprintk(ioc, printk(KERN_DEBUG " ActBytesXferd=%02xh\n", xfer_cnt));
+ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ " sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
+ ioc->name, sc->underflow));
+ dreplyprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ " ActBytesXferd=%02xh\n", ioc->name, xfer_cnt));
/* Report Queue Full
*/
@@ -969,48 +971,32 @@ static void
mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
{
MPT_ADAPTER *ioc = hd->ioc;
- struct scsi_cmnd *SCpnt;
- MPT_FRAME_HDR *mf;
+ struct scsi_cmnd *sc;
+ SCSIIORequest_t *mf = NULL;
int ii;
- int max = ioc->req_depth;
-
- dprintk(ioc, printk(KERN_DEBUG MYNAM ": flush_ScsiLookup called\n"));
- for (ii= 0; ii < max; ii++) {
- if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
+ int channel, id;
- /* Command found.
- */
-
- /* Null ScsiLookup index
- */
- hd->ScsiLookup[ii] = NULL;
-
- mf = MPT_INDEX_2_MFPTR(ioc, ii);
- dmfprintk(ioc, printk(KERN_DEBUG MYNAM ": flush: ScsiDone (mf=%p,sc=%p)\n",
- mf, SCpnt));
-
- /* Free Chain buffers */
- mptscsih_freeChainBuffers(ioc, ii);
-
- /* Free Message frames */
- mpt_free_msg_frame(ioc, mf);
-
- if ((unsigned char *)mf != SCpnt->host_scribble)
- continue;
-
- /* Set status, free OS resources (SG DMA buffers)
- * Do OS callback
- */
- scsi_dma_unmap(SCpnt);
-
- SCpnt->result = DID_RESET << 16;
- SCpnt->host_scribble = NULL;
-
- SCpnt->scsi_done(SCpnt); /* Issue the command callback */
- }
+ for (ii= 0; ii < ioc->req_depth; ii++) {
+ sc = mptscsih_getclear_scsi_lookup(ioc, ii);
+ if (!sc)
+ continue;
+ mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
+ if (!mf)
+ continue;
+ channel = mf->Bus;
+ id = mf->TargetID;
+ mptscsih_freeChainBuffers(ioc, ii);
+ mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
+ if ((unsigned char *)mf != sc->host_scribble)
+ continue;
+ scsi_dma_unmap(sc);
+ sc->result = DID_RESET << 16;
+ sc->host_scribble = NULL;
+ sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT
+ "completing cmds: fw_channel %d, fw_id %d, sc=%p,"
+ " mf = %p, idx=%x\n", ioc->name, channel, id, sc, mf, ii);
+ sc->scsi_done(sc);
}
-
- return;
}
/*
@@ -1032,17 +1018,16 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
{
SCSIIORequest_t *mf = NULL;
int ii;
- int max = hd->ioc->req_depth;
struct scsi_cmnd *sc;
struct scsi_lun lun;
+ MPT_ADAPTER *ioc = hd->ioc;
+ unsigned long flags;
- dsprintk(hd->ioc, printk(KERN_DEBUG MYNAM ": search_running channel %d id %d lun %d max %d\n",
- vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
-
- for (ii=0; ii < max; ii++) {
- if ((sc = hd->ScsiLookup[ii]) != NULL) {
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ for (ii = 0; ii < ioc->req_depth; ii++) {
+ if ((sc = ioc->ScsiLookup[ii]) != NULL) {
- mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
+ mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(ioc, ii);
if (mf == NULL)
continue;
/* If the device is a hidden raid component, then its
@@ -1059,22 +1044,23 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
memcmp(lun.scsi_lun, mf->LUN, 8))
continue;
- /* Cleanup
- */
- hd->ScsiLookup[ii] = NULL;
- mptscsih_freeChainBuffers(hd->ioc, ii);
- mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
if ((unsigned char *)mf != sc->host_scribble)
continue;
+ ioc->ScsiLookup[ii] = NULL;
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ mptscsih_freeChainBuffers(ioc, ii);
+ mpt_free_msg_frame(ioc, (MPT_FRAME_HDR *)mf);
scsi_dma_unmap(sc);
sc->host_scribble = NULL;
sc->result = DID_NO_CONNECT << 16;
- sdev_printk(KERN_INFO, sc->device, "completing cmds: fw_channel %d,"
- "fw_id %d, sc=%p, mf = %p, idx=%x\n", vdevice->vtarget->channel,
+ sdev_printk(KERN_INFO, sc->device, MYIOC_s_FMT "completing cmds: fw_channel %d,"
+ "fw_id %d, sc=%p, mf = %p, idx=%x\n", ioc->name, vdevice->vtarget->channel,
vdevice->vtarget->id, sc, mf, ii);
sc->scsi_done(sc);
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
}
}
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
return;
}
@@ -1097,17 +1083,18 @@ mptscsih_report_queue_full(struct scsi_cmnd *sc, SCSIIOReply_t *pScsiReply, SCSI
{
long time = jiffies;
MPT_SCSI_HOST *hd;
+ MPT_ADAPTER *ioc;
if (sc->device == NULL)
return;
if (sc->device->host == NULL)
return;
- if ((hd = (MPT_SCSI_HOST *)sc->device->host->hostdata) == NULL)
+ if ((hd = shost_priv(sc->device->host)) == NULL)
return;
-
+ ioc = hd->ioc;
if (time - hd->last_queue_full > 10 * HZ) {
- dprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
- hd->ioc->name, 0, sc->device->id, sc->device->lun));
+ dprintk(ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
+ ioc->name, 0, sc->device->id, sc->device->lun));
hd->last_queue_full = time;
}
}
@@ -1134,28 +1121,28 @@ mptscsih_remove(struct pci_dev *pdev)
scsi_remove_host(host);
- if((hd = (MPT_SCSI_HOST *)host->hostdata) == NULL)
+ if((hd = shost_priv(host)) == NULL)
return;
mptscsih_shutdown(pdev);
sz1=0;
- if (hd->ScsiLookup != NULL) {
- sz1 = hd->ioc->req_depth * sizeof(void *);
- kfree(hd->ScsiLookup);
- hd->ScsiLookup = NULL;
+ if (ioc->ScsiLookup != NULL) {
+ sz1 = ioc->req_depth * sizeof(void *);
+ kfree(ioc->ScsiLookup);
+ ioc->ScsiLookup = NULL;
}
- dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Free'd ScsiLookup (%d) memory\n",
- hd->ioc->name, sz1));
+ ioc->name, sz1));
kfree(hd->info_kbuf);
/* NULL the Scsi_Host pointer
*/
- hd->ioc->sh = NULL;
+ ioc->sh = NULL;
scsi_host_put(host);
@@ -1171,15 +1158,6 @@ mptscsih_remove(struct pci_dev *pdev)
void
mptscsih_shutdown(struct pci_dev *pdev)
{
- MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
- struct Scsi_Host *host = ioc->sh;
- MPT_SCSI_HOST *hd;
-
- if(!host)
- return;
-
- hd = (MPT_SCSI_HOST *)host->hostdata;
-
}
#ifdef CONFIG_PM
@@ -1225,7 +1203,7 @@ mptscsih_info(struct Scsi_Host *SChost)
MPT_SCSI_HOST *h;
int size = 0;
- h = (MPT_SCSI_HOST *)SChost->hostdata;
+ h = shost_priv(SChost);
if (h) {
if (h->info_kbuf == NULL)
@@ -1319,7 +1297,7 @@ int
mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
int length, int func)
{
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
int size = 0;
@@ -1358,7 +1336,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
MPT_SCSI_HOST *hd;
MPT_FRAME_HDR *mf;
SCSIIORequest_t *pScsiReq;
- VirtDevice *vdev = SCpnt->device->hostdata;
+ VirtDevice *vdevice = SCpnt->device->hostdata;
int lun;
u32 datalen;
u32 scsictl;
@@ -1368,7 +1346,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
int ii;
MPT_ADAPTER *ioc;
- hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
+ hd = shost_priv(SCpnt->device->host);
ioc = hd->ioc;
lun = SCpnt->device->lun;
SCpnt->scsi_done = done;
@@ -1385,7 +1363,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
/*
* Put together a MPT SCSI request...
*/
- if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
+ if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
ioc->name));
return SCSI_MLQUEUE_HOST_BUSY;
@@ -1415,8 +1393,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
/* Default to untagged. Once a target structure has been allocated,
* use the Inquiry data to determine if device supports tagged.
*/
- if (vdev
- && (vdev->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
+ if (vdevice
+ && (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_Q_YES)
&& (SCpnt->device->tagged_supported)) {
scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ;
} else {
@@ -1425,10 +1403,10 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
/* Use the above information to set up the message frame
*/
- pScsiReq->TargetID = (u8) vdev->vtarget->id;
- pScsiReq->Bus = vdev->vtarget->channel;
+ pScsiReq->TargetID = (u8) vdevice->vtarget->id;
+ pScsiReq->Bus = vdevice->vtarget->channel;
pScsiReq->ChainOffset = 0;
- if (vdev->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
+ if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
pScsiReq->Function = MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
else
pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST;
@@ -1453,7 +1431,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
pScsiReq->DataLength = cpu_to_le32(datalen);
/* SenseBuffer low address */
- pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+ pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
/* Now add the SG list
@@ -1465,23 +1443,22 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
(dma_addr_t) -1);
} else {
/* Add a 32 or 64 bit SGE */
- if (mptscsih_AddSGE(hd->ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
+ if (mptscsih_AddSGE(ioc, SCpnt, pScsiReq, my_idx) != SUCCESS)
goto fail;
}
SCpnt->host_scribble = (unsigned char *)mf;
- hd->ScsiLookup[my_idx] = SCpnt;
+ mptscsih_set_scsi_lookup(ioc, my_idx, SCpnt);
- mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
+ mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
ioc->name, SCpnt, mf, my_idx));
- DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf)
+ DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf);
return 0;
fail:
- hd->ScsiLookup[my_idx] = NULL;
- mptscsih_freeChainBuffers(hd->ioc, my_idx);
- mpt_free_msg_frame(hd->ioc, mf);
+ mptscsih_freeChainBuffers(ioc, my_idx);
+ mpt_free_msg_frame(ioc, mf);
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -1590,38 +1567,38 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int c
*/
if (mptscsih_tm_pending_wait(hd) == FAILED) {
if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
- dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler abort: "
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler abort: "
"Timed out waiting for last TM (%d) to complete! \n",
ioc->name, hd->tmPending));
return FAILED;
} else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
- dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler target "
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler target "
"reset: Timed out waiting for last TM (%d) "
"to complete! \n", ioc->name,
hd->tmPending));
return FAILED;
} else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
- dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler bus reset: "
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler bus reset: "
"Timed out waiting for last TM (%d) to complete! \n",
ioc->name, hd->tmPending));
return FAILED;
}
} else {
- spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
hd->tmPending |= (1 << type);
- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
}
- ioc_raw_state = mpt_GetIocState(hd->ioc, 0);
+ ioc_raw_state = mpt_GetIocState(ioc, 0);
if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) {
printk(MYIOC_s_WARN_FMT
"TM Handler for type=%x: IOC Not operational (0x%x)!\n",
ioc->name, type, ioc_raw_state);
- printk(KERN_WARNING " Issuing HardReset!!\n");
+ printk(MYIOC_s_WARN_FMT " Issuing HardReset!!\n", ioc->name);
if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0)
- printk((KERN_WARNING "TMHandler: HardReset "
- "FAILED!!\n"));
+ printk(MYIOC_s_WARN_FMT "TMHandler: HardReset "
+ "FAILED!!\n", ioc->name);
return FAILED;
}
@@ -1680,16 +1657,17 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
SCSITaskMgmt_t *pScsiTm;
int ii;
int retval;
+ MPT_ADAPTER *ioc = hd->ioc;
/* Return Fail to calling function if no message frames available.
*/
- if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
- dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
- hd->ioc->name));
+ if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
+ ioc->name));
return FAILED;
}
- dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
- hd->ioc->name, mf));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
+ ioc->name, mf));
/* Format the Request
*/
@@ -1712,28 +1690,34 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
pScsiTm->TaskMsgContext = ctx2abort;
- dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
- "type=%d\n", hd->ioc->name, ctx2abort, type));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
+ "type=%d\n", ioc->name, ctx2abort, type));
DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
- if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
- sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
- dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
- " (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
- hd->ioc, mf, retval));
- goto fail_out;
+ if ((ioc->facts.IOCCapabilities & MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q) &&
+ (ioc->facts.MsgVersion >= MPI_VERSION_01_05))
+ mpt_put_msg_frame_hi_pri(ioc->TaskCtx, ioc, mf);
+ else {
+ retval = mpt_send_handshake_request(ioc->TaskCtx, ioc,
+ sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP);
+ if (retval) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
+ " (hd %p, ioc %p, mf %p, rc=%d) \n", ioc->name, hd,
+ ioc, mf, retval));
+ goto fail_out;
+ }
}
if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
- dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
- " (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
- hd->ioc, mf));
- dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
- hd->ioc->name));
- retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
- dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
- hd->ioc->name, retval));
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
+ " (hd %p, ioc %p, mf %p) \n", ioc->name, hd,
+ ioc, mf));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
+ ioc->name));
+ retval = mpt_HardResetHandler(ioc, CAN_SLEEP);
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
+ ioc->name, retval));
goto fail_out;
}
@@ -1754,7 +1738,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, i
/*
* Free task managment mf, and corresponding tm flags
*/
- mpt_free_msg_frame(hd->ioc, mf);
+ mpt_free_msg_frame(ioc, mf);
hd->tmPending = 0;
hd->tmState = TM_STATE_NONE;
return FAILED;
@@ -1797,11 +1781,11 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
/* If we can't locate our host adapter structure, return FAILED status.
*/
- if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
+ if ((hd = shost_priv(SCpnt->device->host)) == NULL) {
SCpnt->result = DID_RESET << 16;
SCpnt->scsi_done(SCpnt);
- printk(KERN_DEBUG MYNAM ": mptscsih_abort: Can't locate "
- "host! (sc=%p)\n", SCpnt);
+ printk(KERN_ERR MYNAM ": task abort: "
+ "can't locate host! (sc=%p)\n", SCpnt);
return FAILED;
}
@@ -1812,8 +1796,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
vdevice = SCpnt->device->hostdata;
if (!vdevice || !vdevice->vtarget) {
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: device has been "
- "deleted (sc=%p)\n", ioc->name, SCpnt));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "task abort: device has been deleted (sc=%p)\n",
+ ioc->name, SCpnt));
SCpnt->result = DID_NO_CONNECT << 16;
SCpnt->scsi_done(SCpnt);
retval = 0;
@@ -1823,8 +1808,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
/* Task aborts are not supported for hidden raid components.
*/
if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
- dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: hidden raid "
- "component (sc=%p)\n", ioc->name, SCpnt));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "task abort: hidden raid component (sc=%p)\n",
+ ioc->name, SCpnt));
SCpnt->result = DID_RESET << 16;
retval = FAILED;
goto out;
@@ -1832,12 +1818,12 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
/* Find this command
*/
- if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
+ if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(ioc, SCpnt)) < 0) {
/* Cmd not found in ScsiLookup.
* Do OS callback.
*/
SCpnt->result = DID_RESET << 16;
- dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: mptscsih_abort: "
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: "
"Command not in the active list! (sc=%p)\n", ioc->name,
SCpnt));
retval = 0;
@@ -1859,7 +1845,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
* swap it here either. It is an opaque cookie to
* the controller, so it does not matter. -DaveM
*/
- mf = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx);
+ mf = MPT_INDEX_2_MFPTR(ioc, scpnt_idx);
ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext;
hd->abortSCpnt = SCpnt;
@@ -1868,7 +1854,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
ctx2abort, mptscsih_get_tm_timeout(ioc));
- if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
+ if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
SCpnt->serial_number == sn)
retval = FAILED;
@@ -1901,9 +1887,9 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
/* If we can't locate our host adapter structure, return FAILED status.
*/
- if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- printk(KERN_DEBUG MYNAM ": mptscsih_dev_reset: Can't "
- "locate host! (sc=%p)\n", SCpnt);
+ if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+ printk(KERN_ERR MYNAM ": target reset: "
+ "Can't locate host! (sc=%p)\n", SCpnt);
return FAILED;
}
@@ -1959,14 +1945,14 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
{
MPT_SCSI_HOST *hd;
int retval;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
MPT_ADAPTER *ioc;
/* If we can't locate our host adapter structure, return FAILED status.
*/
- if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- printk(KERN_DEBUG MYNAM ": mptscsih_bus_reset: Can't "
- "locate host! (sc=%p)\n", SCpnt );
+ if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+ printk(KERN_ERR MYNAM ": bus reset: "
+ "Can't locate host! (sc=%p)\n", SCpnt);
return FAILED;
}
@@ -1978,9 +1964,9 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
if (hd->timeouts < -1)
hd->timeouts++;
- vdev = SCpnt->device->hostdata;
+ vdevice = SCpnt->device->hostdata;
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
- vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
+ vdevice->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
@@ -2008,9 +1994,9 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt)
MPT_ADAPTER *ioc;
/* If we can't locate the host to reset, then we failed. */
- if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- printk( KERN_DEBUG MYNAM ": mptscsih_host_reset: Can't "
- "locate host! (sc=%p)\n", SCpnt);
+ if ((hd = shost_priv(SCpnt->device->host)) == NULL){
+ printk(KERN_ERR MYNAM ": host reset: "
+ "Can't locate host! (sc=%p)\n", SCpnt);
return FAILED;
}
@@ -2021,7 +2007,7 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt)
/* If our attempts to reset the host failed, then return a failed
* status. The host will be taken off line by the SCSI mid-layer.
*/
- if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
+ if (mpt_HardResetHandler(ioc, CAN_SLEEP) < 0) {
retval = FAILED;
} else {
/* Make sure TM pending is cleared and TM state is set to
@@ -2051,17 +2037,18 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
unsigned long flags;
int loop_count = 4 * 10; /* Wait 10 seconds */
int status = FAILED;
+ MPT_ADAPTER *ioc = hd->ioc;
do {
- spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
if (hd->tmState == TM_STATE_NONE) {
hd->tmState = TM_STATE_IN_PROGRESS;
hd->tmPending = 1;
- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
status = SUCCESS;
break;
}
- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
msleep(250);
} while (--loop_count);
@@ -2082,15 +2069,16 @@ mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout )
unsigned long flags;
int loop_count = 4 * timeout;
int status = FAILED;
+ MPT_ADAPTER *ioc = hd->ioc;
do {
- spin_lock_irqsave(&hd->ioc->FreeQlock, flags);
+ spin_lock_irqsave(&ioc->FreeQlock, flags);
if(hd->tmPending == 0) {
status = SUCCESS;
- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
break;
}
- spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags);
+ spin_unlock_irqrestore(&ioc->FreeQlock, flags);
msleep(250);
} while (--loop_count);
@@ -2172,7 +2160,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
return 1;
}
- hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+ hd = shost_priv(ioc->sh);
pScsiTmReply = (SCSITaskMgmtReply_t*)mr;
pScsiTmReq = (SCSITaskMgmt_t*)mf;
tmType = pScsiTmReq->TaskType;
@@ -2223,7 +2211,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
if (iocstatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED ||
hd->cmdPtr)
if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
- printk((KERN_WARNING " Firmware Reload FAILED!!\n"));
+ printk(MYIOC_s_WARN_FMT " Firmware Reload FAILED!!\n", ioc->name);
break;
case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
@@ -2366,7 +2354,7 @@ void
mptscsih_slave_destroy(struct scsi_device *sdev)
{
struct Scsi_Host *host = sdev->host;
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
VirtTarget *vtarget;
VirtDevice *vdevice;
struct scsi_target *starget;
@@ -2393,16 +2381,17 @@ mptscsih_slave_destroy(struct scsi_device *sdev)
int
mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(sdev->host);
VirtTarget *vtarget;
struct scsi_target *starget;
int max_depth;
int tagged;
+ MPT_ADAPTER *ioc = hd->ioc;
starget = scsi_target(sdev);
vtarget = starget->hostdata;
- if (hd->ioc->bus_type == SPI) {
+ if (ioc->bus_type == SPI) {
if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
max_depth = 1;
else if (sdev->type == TYPE_DISK &&
@@ -2437,19 +2426,20 @@ mptscsih_slave_configure(struct scsi_device *sdev)
VirtTarget *vtarget;
VirtDevice *vdevice;
struct scsi_target *starget;
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(sh);
+ MPT_ADAPTER *ioc = hd->ioc;
starget = scsi_target(sdev);
vtarget = starget->hostdata;
vdevice = sdev->hostdata;
- dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"device @ %p, channel=%d, id=%d, lun=%d\n",
- hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
- if (hd->ioc->bus_type == SPI)
- dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
+ if (ioc->bus_type == SPI)
+ dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"sdtr %d wdtr %d ppr %d inq length=%d\n",
- hd->ioc->name, sdev->sdtr, sdev->wdtr,
+ ioc->name, sdev->sdtr, sdev->wdtr,
sdev->ppr, sdev->inquiry_len));
if (sdev->id > sh->max_id) {
@@ -2461,21 +2451,21 @@ mptscsih_slave_configure(struct scsi_device *sdev)
vdevice->configured_lun = 1;
mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
- dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Queue depth=%d, tflags=%x\n",
- hd->ioc->name, sdev->queue_depth, vtarget->tflags));
+ ioc->name, sdev->queue_depth, vtarget->tflags));
- if (hd->ioc->bus_type == SPI)
- dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ if (ioc->bus_type == SPI)
+ dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
- hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
+ ioc->name, vtarget->negoFlags, vtarget->maxOffset,
vtarget->minSyncFactor));
slave_configure_exit:
- dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
+ dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"tagged %d, simple %d, ordered %d\n",
- hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
+ ioc->name,sdev->tagged_supported, sdev->simple_tags,
sdev->ordered_tags));
return 0;
@@ -2494,14 +2484,15 @@ slave_configure_exit:
static void
mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply)
{
- VirtDevice *vdev;
+ VirtDevice *vdevice;
SCSIIORequest_t *pReq;
u32 sense_count = le32_to_cpu(pScsiReply->SenseCount);
+ MPT_ADAPTER *ioc = hd->ioc;
/* Get target structure
*/
pReq = (SCSIIORequest_t *) mf;
- vdev = sc->device->hostdata;
+ vdevice = sc->device->hostdata;
if (sense_count) {
u8 *sense_data;
@@ -2509,15 +2500,14 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
/* Copy the sense received into the scsi command block. */
req_index = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
- sense_data = ((u8 *)hd->ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
+ sense_data = ((u8 *)ioc->sense_buf_pool + (req_index * MPT_SENSE_BUFFER_ALLOC));
memcpy(sc->sense_buffer, sense_data, SNS_LEN(sc));
/* Log SMART data (asc = 0x5D, non-IM case only) if required.
*/
- if ((hd->ioc->events) && (hd->ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
- if ((sense_data[12] == 0x5D) && (vdev->vtarget->raidVolume == 0)) {
+ if ((ioc->events) && (ioc->eventTypes & (1 << MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE))) {
+ if ((sense_data[12] == 0x5D) && (vdevice->vtarget->raidVolume == 0)) {
int idx;
- MPT_ADAPTER *ioc = hd->ioc;
idx = ioc->eventContext % MPTCTL_EVENT_LOG_SIZE;
ioc->events[idx].event = MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE;
@@ -2530,36 +2520,112 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
ioc->events[idx].data[1] = (sense_data[13] << 8) | sense_data[12];
ioc->eventContext++;
- if (hd->ioc->pcidev->vendor ==
+ if (ioc->pcidev->vendor ==
PCI_VENDOR_ID_IBM) {
- mptscsih_issue_sep_command(hd->ioc,
- vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
- vdev->vtarget->tflags |=
+ mptscsih_issue_sep_command(ioc,
+ vdevice->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
+ vdevice->vtarget->tflags |=
MPT_TARGET_FLAGS_LED_ON;
}
}
}
} else {
- dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
- hd->ioc->name));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
+ ioc->name));
}
}
-static int
-SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
+/**
+ * mptscsih_get_scsi_lookup
+ *
+ * retrieves scmd entry from ScsiLookup[] array list
+ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @i: index into the array
+ *
+ * Returns the scsi_cmd pointer
+ *
+ **/
+static struct scsi_cmnd *
+mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i)
{
- MPT_SCSI_HOST *hd;
- int i;
+ unsigned long flags;
+ struct scsi_cmnd *scmd;
+
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ scmd = ioc->ScsiLookup[i];
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+
+ return scmd;
+}
+
+/**
+ * mptscsih_getclear_scsi_lookup
+ *
+ * retrieves and clears scmd entry from ScsiLookup[] array list
+ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @i: index into the array
+ *
+ * Returns the scsi_cmd pointer
+ *
+ **/
+static struct scsi_cmnd *
+mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i)
+{
+ unsigned long flags;
+ struct scsi_cmnd *scmd;
- hd = (MPT_SCSI_HOST *) sc->device->host->hostdata;
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ scmd = ioc->ScsiLookup[i];
+ ioc->ScsiLookup[i] = NULL;
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- for (i = 0; i < hd->ioc->req_depth; i++) {
- if (hd->ScsiLookup[i] == sc) {
- return i;
+ return scmd;
+}
+
+/**
+ * mptscsih_set_scsi_lookup
+ *
+ * writes a scmd entry into the ScsiLookup[] array list
+ *
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @i: index into the array
+ * @scmd: scsi_cmnd pointer
+ *
+ **/
+static void
+mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ ioc->ScsiLookup[i] = scmd;
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+}
+
+/**
+ * SCPNT_TO_LOOKUP_IDX - searches for a given scmd in the ScsiLookup[] array list
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @sc: scsi_cmnd pointer
+ */
+static int
+SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *sc)
+{
+ unsigned long flags;
+ int i, index=-1;
+
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ for (i = 0; i < ioc->req_depth; i++) {
+ if (ioc->ScsiLookup[i] == sc) {
+ index = i;
+ goto out;
}
}
- return -1;
+ out:
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return index;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -2568,21 +2634,20 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
{
MPT_SCSI_HOST *hd;
unsigned long flags;
- int ii;
- dtmprintk(ioc, printk(KERN_DEBUG MYNAM
- ": IOC %s_reset routed to SCSI host driver!\n",
- reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
- reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
+ dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ ": IOC %s_reset routed to SCSI host driver!\n",
+ ioc->name, reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
+ reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
/* If a FW reload request arrives after base installed but
* before all scsi hosts have been attached, then an alt_ioc
* may have a NULL sh pointer.
*/
- if ((ioc->sh == NULL) || (ioc->sh->hostdata == NULL))
+ if (ioc->sh == NULL || shost_priv(ioc->sh) == NULL)
return 0;
else
- hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+ hd = shost_priv(ioc->sh);
if (reset_phase == MPT_IOC_SETUP_RESET) {
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
@@ -2624,11 +2689,6 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
* Init all control structures.
*/
- /* ScsiLookup initialization
- */
- for (ii=0; ii < hd->ioc->req_depth; ii++)
- hd->ScsiLookup[ii] = NULL;
-
/* 2. Chain Buffer initialization
*/
@@ -2675,7 +2735,7 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
ioc->name, event));
if (ioc->sh == NULL ||
- ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL))
+ ((hd = shost_priv(ioc->sh)) == NULL))
return 1;
switch (event) {
@@ -2713,7 +2773,8 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
case MPI_EVENT_STATE_CHANGE: /* 02 */
case MPI_EVENT_EVENT_CHANGE: /* 0A */
default:
- dprintk(ioc, printk(KERN_DEBUG MYNAM ": Ignoring event (=%02Xh)\n", event));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": Ignoring event (=%02Xh)\n",
+ ioc->name, event));
break;
}
@@ -2753,7 +2814,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
int completionCode;
u16 req_idx;
- hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
+ hd = shost_priv(ioc->sh);
if ((mf == NULL) ||
(mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) {
@@ -2765,17 +2826,17 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
del_timer(&hd->timer);
req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx);
- hd->ScsiLookup[req_idx] = NULL;
+ mptscsih_set_scsi_lookup(ioc, req_idx, NULL);
pReq = (SCSIIORequest_t *) mf;
if (mf != hd->cmdPtr) {
printk(MYIOC_s_WARN_FMT "ScanDvComplete (mf=%p, cmdPtr=%p, idx=%d)\n",
- hd->ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
+ ioc->name, (void *)mf, (void *) hd->cmdPtr, req_idx);
}
hd->cmdPtr = NULL;
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
- hd->ioc->name, mf, mr, req_idx));
+ ioc->name, mf, mr, req_idx));
hd->pLocal = &hd->localReply;
hd->pLocal->scsiStatus = 0;
@@ -2839,15 +2900,15 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
*/
completionCode = MPT_SCANDV_SENSE;
hd->pLocal->scsiStatus = scsi_status;
- sense_data = ((u8 *)hd->ioc->sense_buf_pool +
+ sense_data = ((u8 *)ioc->sense_buf_pool +
(req_idx * MPT_SENSE_BUFFER_ALLOC));
sz = min_t(int, pReq->SenseBufferLength,
SCSI_STD_SENSE_BYTES);
memcpy(hd->pLocal->sense, sense_data, sz);
- ddvprintk(ioc, printk(KERN_DEBUG " Check Condition, sense ptr %p\n",
- sense_data));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT " Check Condition, sense ptr %p\n",
+ ioc->name, sense_data));
} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
if (pReq->CDB[0] == INQUIRY)
completionCode = MPT_SCANDV_ISSUE_SENSE;
@@ -2906,8 +2967,9 @@ void
mptscsih_timer_expired(unsigned long data)
{
MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
+ MPT_ADAPTER *ioc = hd->ioc;
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", ioc->name, hd->cmdPtr));
if (hd->cmdPtr) {
MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
@@ -2921,13 +2983,13 @@ mptscsih_timer_expired(unsigned long data)
*/
} else {
/* Perform a FW reload */
- if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
- printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", hd->ioc->name);
+ if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0) {
+ printk(MYIOC_s_WARN_FMT "Firmware Reload FAILED!\n", ioc->name);
}
}
} else {
/* This should NEVER happen */
- printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", hd->ioc->name);
+ printk(MYIOC_s_WARN_FMT "Null cmdPtr!!!!\n", ioc->name);
}
/* No more processing.
@@ -2935,7 +2997,7 @@ mptscsih_timer_expired(unsigned long data)
* The FW will reply to all outstanding commands, callback will finish cleanup.
* Hard reset clean-up will free all resources.
*/
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", hd->ioc->name));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", ioc->name));
return;
}
@@ -2973,11 +3035,12 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
char cmdLen;
char CDB[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
char cmd = io->cmd;
+ MPT_ADAPTER *ioc = hd->ioc;
in_isr = in_interrupt();
if (in_isr) {
- dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
- hd->ioc->name));
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
+ ioc->name));
return -EPERM;
}
@@ -3078,9 +3141,9 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
/* Get and Populate a free Frame
*/
- if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "No msg frames!\n",
- hd->ioc->name));
+ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
+ dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "No msg frames!\n",
+ ioc->name));
return -EBUSY;
}
@@ -3119,19 +3182,19 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
if (cmd == REQUEST_SENSE) {
pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
- hd->ioc->name, cmd));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
+ ioc->name, cmd));
}
for (ii=0; ii < 16; ii++)
pScsiReq->CDB[ii] = CDB[ii];
pScsiReq->DataLength = cpu_to_le32(io->size);
- pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
+ pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma
+ (my_idx * MPT_SENSE_BUFFER_ALLOC));
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
- hd->ioc->name, cmd, io->channel, io->id, io->lun));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
+ ioc->name, cmd, io->channel, io->id, io->lun));
if (dir == MPI_SCSIIO_CONTROL_READ) {
mpt_add_sge((char *) &pScsiReq->SGL,
@@ -3166,7 +3229,7 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
hd->cmdPtr = mf;
add_timer(&hd->timer);
- mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
+ mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
wait_event(hd->scandv_waitq, hd->scandv_wait_done);
if (hd->pLocal) {
@@ -3182,8 +3245,8 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io)
} else {
rc = -EFAULT;
/* This should never happen. */
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
- hd->ioc->name));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
+ ioc->name));
}
return rc;
@@ -3235,7 +3298,7 @@ static ssize_t
mptscsih_version_fw_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
@@ -3250,7 +3313,7 @@ static ssize_t
mptscsih_version_bios_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
@@ -3265,7 +3328,7 @@ static ssize_t
mptscsih_version_mpi_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
@@ -3276,7 +3339,7 @@ static ssize_t
mptscsih_version_product_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
@@ -3288,7 +3351,7 @@ static ssize_t
mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02xh\n",
@@ -3301,7 +3364,7 @@ static ssize_t
mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
@@ -3313,7 +3376,7 @@ static ssize_t
mptscsih_board_name_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
@@ -3324,7 +3387,7 @@ static ssize_t
mptscsih_board_assembly_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
@@ -3336,7 +3399,7 @@ static ssize_t
mptscsih_board_tracer_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
@@ -3348,7 +3411,7 @@ static ssize_t
mptscsih_io_delay_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
@@ -3360,7 +3423,7 @@ static ssize_t
mptscsih_device_delay_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
@@ -3372,7 +3435,7 @@ static ssize_t
mptscsih_debug_level_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
@@ -3382,7 +3445,7 @@ mptscsih_debug_level_store(struct class_device *cdev, const char *buf,
size_t count)
{
struct Scsi_Host *host = class_to_shost(cdev);
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
int val = 0;
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index 67b088db2f1..d289e97cfe8 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -3,9 +3,9 @@
* High performance SCSI / Fibre Channel SCSI Host device driver.
* For use with PCI chip/adapter(s):
* LSIFC9xx/LSI409xx Fibre Channel
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 8c98420640a..25bcfcf36f2 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -1,9 +1,9 @@
/*
* linux/drivers/message/fusion/mptspi.c
- * For use with LSI Logic PCI chip/adapter(s)
- * running LSI Logic Fusion MPT (Message Passing Technology) firmware.
+ * For use with LSI PCI chip/adapter(s)
+ * running LSI Fusion MPT (Message Passing Technology) firmware.
*
- * Copyright (c) 1999-2007 LSI Logic Corporation
+ * Copyright (c) 1999-2007 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
@@ -90,9 +90,9 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *,
static struct scsi_transport_template *mptspi_transport_template = NULL;
-static int mptspiDoneCtx = -1;
-static int mptspiTaskCtx = -1;
-static int mptspiInternalCtx = -1; /* Used only for internal commands */
+static u8 mptspiDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptspiTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
+static u8 mptspiInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
/**
* mptspi_setTargetNegoParms - Update the target negotiation parameters
@@ -107,7 +107,8 @@ static void
mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
struct scsi_device *sdev)
{
- SpiCfgData *pspi_data = &hd->ioc->spi_data;
+ MPT_ADAPTER *ioc = hd->ioc;
+ SpiCfgData *pspi_data = &ioc->spi_data;
int id = (int) target->id;
int nvram;
u8 width = MPT_NARROW;
@@ -138,9 +139,10 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
else {
factor = MPT_ULTRA320;
if (scsi_device_qas(sdev)) {
- ddvprintk(hd->ioc,
- printk(KERN_DEBUG "Enabling QAS due to "
- "byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
+ ddvprintk(ioc,
+ printk(MYIOC_s_DEBUG_FMT "Enabling QAS due to "
+ "byte56=%02x on id=%d!\n", ioc->name,
+ scsi_device_qas(sdev), id));
noQas = 0;
}
if (sdev->type == TYPE_TAPE &&
@@ -227,8 +229,8 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
/* Disable QAS in a mixed configuration case
*/
- ddvprintk(hd->ioc, printk(KERN_DEBUG
- "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "Disabling QAS due to noQas=%02x on id=%d!\n", ioc->name, noQas, id));
}
}
@@ -302,7 +304,7 @@ mptspi_writeIOCPage4(MPT_SCSI_HOST *hd, u8 channel , u8 id)
ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
- ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
+ ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
@@ -374,14 +376,15 @@ static int
mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
{
int i, rc = 0;
+ MPT_ADAPTER *ioc = hd->ioc;
- if (!hd->ioc->raid_data.pIocPg2)
+ if (!ioc->raid_data.pIocPg2)
goto out;
- if (!hd->ioc->raid_data.pIocPg2->NumActiveVolumes)
+ if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
goto out;
- for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
- if (hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) {
+ for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+ if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) {
rc = 1;
goto out;
}
@@ -394,17 +397,19 @@ mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
static int mptspi_target_alloc(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(shost);
VirtTarget *vtarget;
+ MPT_ADAPTER *ioc;
if (hd == NULL)
return -ENODEV;
+ ioc = hd->ioc;
vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
if (!vtarget)
return -ENOMEM;
- vtarget->ioc_id = hd->ioc->id;
+ vtarget->ioc_id = ioc->id;
vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
vtarget->id = (u8)starget->id;
vtarget->channel = (u8)starget->channel;
@@ -412,34 +417,34 @@ static int mptspi_target_alloc(struct scsi_target *starget)
starget->hostdata = vtarget;
if (starget->channel == 1) {
- if (mptscsih_is_phys_disk(hd->ioc, 0, starget->id) == 0)
+ if (mptscsih_is_phys_disk(ioc, 0, starget->id) == 0)
return 0;
vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
/* The real channel for this device is zero */
vtarget->channel = 0;
/* The actual physdisknum (for RAID passthrough) */
- vtarget->id = mptscsih_raid_id_to_num(hd->ioc, 0,
+ vtarget->id = mptscsih_raid_id_to_num(ioc, 0,
starget->id);
}
if (starget->channel == 0 &&
mptspi_is_raid(hd, starget->id)) {
vtarget->raidVolume = 1;
- ddvprintk(hd->ioc, printk(KERN_DEBUG
- "RAID Volume @ channel=%d id=%d\n", starget->channel,
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "RAID Volume @ channel=%d id=%d\n", ioc->name, starget->channel,
starget->id));
}
- if (hd->ioc->spi_data.nvram &&
- hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) {
- u32 nvram = hd->ioc->spi_data.nvram[starget->id];
+ if (ioc->spi_data.nvram &&
+ ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) {
+ u32 nvram = ioc->spi_data.nvram[starget->id];
spi_min_period(starget) = (nvram & MPT_NVRAM_SYNC_MASK) >> MPT_NVRAM_SYNC_SHIFT;
spi_max_width(starget) = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1;
} else {
- spi_min_period(starget) = hd->ioc->spi_data.minSyncFactor;
- spi_max_width(starget) = hd->ioc->spi_data.maxBusWidth;
+ spi_min_period(starget) = ioc->spi_data.minSyncFactor;
+ spi_max_width(starget) = ioc->spi_data.maxBusWidth;
}
- spi_max_offset(starget) = hd->ioc->spi_data.maxSyncOffset;
+ spi_max_offset(starget) = ioc->spi_data.maxSyncOffset;
spi_offset(starget) = 0;
mptspi_write_width(starget, 0);
@@ -509,10 +514,10 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(shost);
struct _MPT_ADAPTER *ioc = hd->ioc;
- struct _CONFIG_PAGE_SCSI_DEVICE_0 *pg0;
- dma_addr_t pg0_dma;
+ struct _CONFIG_PAGE_SCSI_DEVICE_0 *spi_dev_pg0;
+ dma_addr_t spi_dev_pg0_dma;
int size;
struct _x_config_parms cfg;
struct _CONFIG_PAGE_HEADER hdr;
@@ -530,9 +535,10 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
size += 2048;
*/
- pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg0_dma, GFP_KERNEL);
- if (pg0 == NULL) {
- starget_printk(KERN_ERR, starget, "dma_alloc_coherent for parameters failed\n");
+ spi_dev_pg0 = dma_alloc_coherent(&ioc->pcidev->dev, size, &spi_dev_pg0_dma, GFP_KERNEL);
+ if (spi_dev_pg0 == NULL) {
+ starget_printk(KERN_ERR, starget, MYIOC_s_FMT
+ "dma_alloc_coherent for parameters failed\n", ioc->name);
return -EINVAL;
}
@@ -546,22 +552,22 @@ static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
memset(&cfg, 0, sizeof(cfg));
cfg.cfghdr.hdr = &hdr;
- cfg.physAddr = pg0_dma;
+ cfg.physAddr = spi_dev_pg0_dma;
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
cfg.dir = 0;
cfg.pageAddr = starget->id;
if (mpt_config(ioc, &cfg)) {
- starget_printk(KERN_ERR, starget, "mpt_config failed\n");
+ starget_printk(KERN_ERR, starget, MYIOC_s_FMT "mpt_config failed\n", ioc->name);
goto out_free;
}
err = 0;
- memcpy(pass_pg0, pg0, size);
+ memcpy(pass_pg0, spi_dev_pg0, size);
- mptspi_print_read_nego(hd, starget, le32_to_cpu(pg0->NegotiatedParameters));
+ mptspi_print_read_nego(hd, starget, le32_to_cpu(spi_dev_pg0->NegotiatedParameters));
out_free:
- dma_free_coherent(&ioc->pcidev->dev, size, pg0, pg0_dma);
+ dma_free_coherent(&ioc->pcidev->dev, size, spi_dev_pg0, spi_dev_pg0_dma);
return err;
}
@@ -588,11 +594,11 @@ static u32 mptspi_getRP(struct scsi_target *starget)
static void mptspi_read_parameters(struct scsi_target *starget)
{
int nego;
- struct _CONFIG_PAGE_SCSI_DEVICE_0 pg0;
+ struct _CONFIG_PAGE_SCSI_DEVICE_0 spi_dev_pg0;
- mptspi_read_spi_device_pg0(starget, &pg0);
+ mptspi_read_spi_device_pg0(starget, &spi_dev_pg0);
- nego = le32_to_cpu(pg0.NegotiatedParameters);
+ nego = le32_to_cpu(spi_dev_pg0.NegotiatedParameters);
spi_iu(starget) = (nego & MPI_SCSIDEVPAGE0_NP_IU) ? 1 : 0;
spi_dt(starget) = (nego & MPI_SCSIDEVPAGE0_NP_DT) ? 1 : 0;
@@ -612,12 +618,13 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
{
MpiRaidActionRequest_t *pReq;
MPT_FRAME_HDR *mf;
+ MPT_ADAPTER *ioc = hd->ioc;
/* Get and Populate a free Frame
*/
- if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
- ddvprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
- hd->ioc->name));
+ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
+ ddvprintk(ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
+ ioc->name));
return -EAGAIN;
}
pReq = (MpiRaidActionRequest_t *)mf;
@@ -638,8 +645,8 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
mpt_add_sge((char *)&pReq->ActionDataSGE,
MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
- ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
- hd->ioc->name, pReq->Action, channel, id));
+ ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
+ ioc->name, pReq->Action, channel, id));
hd->pLocal = NULL;
hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
@@ -651,7 +658,7 @@ mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
hd->cmdPtr = mf;
add_timer(&hd->timer);
- mpt_put_msg_frame(hd->ioc->InternalCtx, hd->ioc, mf);
+ mpt_put_msg_frame(ioc->InternalCtx, ioc, mf);
wait_event(hd->scandv_waitq, hd->scandv_wait_done);
if ((hd->pLocal == NULL) || (hd->pLocal->completion != 0))
@@ -664,6 +671,7 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
struct scsi_device *sdev)
{
VirtTarget *vtarget = scsi_target(sdev)->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
/* no DV on RAID devices */
if (sdev->channel == 0 &&
@@ -673,8 +681,8 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
/* If this is a piece of a RAID, then quiesce first */
if (sdev->channel == 1 &&
mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) {
- starget_printk(KERN_ERR, scsi_target(sdev),
- "Integrated RAID quiesce failed\n");
+ starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
+ "Integrated RAID quiesce failed\n", ioc->name);
return;
}
@@ -684,8 +692,8 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
if (sdev->channel == 1 &&
mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
- starget_printk(KERN_ERR, scsi_target(sdev),
- "Integrated RAID resume failed\n");
+ starget_printk(KERN_ERR, scsi_target(sdev), MYIOC_s_FMT
+ "Integrated RAID resume failed\n", ioc->name);
mptspi_read_parameters(sdev->sdev_target);
spi_display_xfer_agreement(sdev->sdev_target);
@@ -694,28 +702,29 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
static int mptspi_slave_alloc(struct scsi_device *sdev)
{
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+ MPT_SCSI_HOST *hd = shost_priv(sdev->host);
VirtTarget *vtarget;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
struct scsi_target *starget;
+ MPT_ADAPTER *ioc = hd->ioc;
if (sdev->channel == 1 &&
- mptscsih_is_phys_disk(hd->ioc, 0, sdev->id) == 0)
+ mptscsih_is_phys_disk(ioc, 0, sdev->id) == 0)
return -ENXIO;
- vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
- if (!vdev) {
+ vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+ if (!vdevice) {
printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
- hd->ioc->name, sizeof(VirtDevice));
+ ioc->name, sizeof(VirtDevice));
return -ENOMEM;
}
- vdev->lun = sdev->lun;
- sdev->hostdata = vdev;
+ vdevice->lun = sdev->lun;
+ sdev->hostdata = vdevice;
starget = scsi_target(sdev);
vtarget = starget->hostdata;
- vdev->vtarget = vtarget;
+ vdevice->vtarget = vtarget;
vtarget->num_luns++;
if (sdev->channel == 1)
@@ -726,8 +735,7 @@ static int mptspi_slave_alloc(struct scsi_device *sdev)
static int mptspi_slave_configure(struct scsi_device *sdev)
{
- struct _MPT_SCSI_HOST *hd =
- (struct _MPT_SCSI_HOST *)sdev->host->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(sdev->host);
VirtTarget *vtarget = scsi_target(sdev)->hostdata;
int ret;
@@ -755,24 +763,25 @@ static int mptspi_slave_configure(struct scsi_device *sdev)
static int
mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
- struct _MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
- VirtDevice *vdev = SCpnt->device->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(SCpnt->device->host);
+ VirtDevice *vdevice = SCpnt->device->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
- if (!vdev || !vdev->vtarget) {
+ if (!vdevice || !vdevice->vtarget) {
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
}
if (SCpnt->device->channel == 1 &&
- mptscsih_is_phys_disk(hd->ioc, 0, SCpnt->device->id) == 0) {
+ mptscsih_is_phys_disk(ioc, 0, SCpnt->device->id) == 0) {
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
}
if (spi_dv_pending(scsi_target(SCpnt->device)))
- ddvprintk(hd->ioc, scsi_print_command(SCpnt));
+ ddvprintk(ioc, scsi_print_command(SCpnt));
return mptscsih_qcmd(SCpnt,done);
}
@@ -829,7 +838,7 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
struct _CONFIG_PAGE_SCSI_DEVICE_1 *pass_pg1)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(shost);
struct _MPT_ADAPTER *ioc = hd->ioc;
struct _CONFIG_PAGE_SCSI_DEVICE_1 *pg1;
dma_addr_t pg1_dma;
@@ -847,7 +856,8 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
pg1 = dma_alloc_coherent(&ioc->pcidev->dev, size, &pg1_dma, GFP_KERNEL);
if (pg1 == NULL) {
- starget_printk(KERN_ERR, starget, "dma_alloc_coherent for parameters failed\n");
+ starget_printk(KERN_ERR, starget, MYIOC_s_FMT
+ "dma_alloc_coherent for parameters failed\n", ioc->name);
return -EINVAL;
}
@@ -876,7 +886,8 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters));
if (mpt_config(ioc, &cfg)) {
- starget_printk(KERN_ERR, starget, "mpt_config failed\n");
+ starget_printk(KERN_ERR, starget, MYIOC_s_FMT
+ "mpt_config failed\n", ioc->name);
goto out_free;
}
err = 0;
@@ -1015,7 +1026,7 @@ static void mptspi_write_qas(struct scsi_target *starget, int qas)
{
struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(shost);
VirtTarget *vtarget = starget->hostdata;
u32 nego;
@@ -1067,15 +1078,16 @@ static void mpt_work_wrapper(struct work_struct *work)
struct work_queue_wrapper *wqw =
container_of(work, struct work_queue_wrapper, work);
struct _MPT_SCSI_HOST *hd = wqw->hd;
- struct Scsi_Host *shost = hd->ioc->sh;
+ MPT_ADAPTER *ioc = hd->ioc;
+ struct Scsi_Host *shost = ioc->sh;
struct scsi_device *sdev;
int disk = wqw->disk;
struct _CONFIG_PAGE_IOC_3 *pg3;
kfree(wqw);
- mpt_findImVolumes(hd->ioc);
- pg3 = hd->ioc->raid_data.pIocPg3;
+ mpt_findImVolumes(ioc);
+ pg3 = ioc->raid_data.pIocPg3;
if (!pg3)
return;
@@ -1092,24 +1104,25 @@ static void mpt_work_wrapper(struct work_struct *work)
if(vtarget->id != disk)
continue;
- starget_printk(KERN_INFO, vtarget->starget,
- "Integrated RAID requests DV of new device\n");
+ starget_printk(KERN_INFO, vtarget->starget, MYIOC_s_FMT
+ "Integrated RAID requests DV of new device\n", ioc->name);
mptspi_dv_device(hd, sdev);
}
- shost_printk(KERN_INFO, shost,
- "Integrated RAID detects new device %d\n", disk);
- scsi_scan_target(&hd->ioc->sh->shost_gendev, 1, disk, 0, 1);
+ shost_printk(KERN_INFO, shost, MYIOC_s_FMT
+ "Integrated RAID detects new device %d\n", ioc->name, disk);
+ scsi_scan_target(&ioc->sh->shost_gendev, 1, disk, 0, 1);
}
static void mpt_dv_raid(struct _MPT_SCSI_HOST *hd, int disk)
{
struct work_queue_wrapper *wqw = kmalloc(sizeof(*wqw), GFP_ATOMIC);
+ MPT_ADAPTER *ioc = hd->ioc;
if (!wqw) {
- shost_printk(KERN_ERR, hd->ioc->sh,
- "Failed to act on RAID event for physical disk %d\n",
- disk);
+ shost_printk(KERN_ERR, ioc->sh, MYIOC_s_FMT
+ "Failed to act on RAID event for physical disk %d\n",
+ ioc->name, disk);
return;
}
INIT_WORK(&wqw->work, mpt_work_wrapper);
@@ -1123,7 +1136,7 @@ static int
mptspi_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
{
u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
if (hd && event == MPI_EVENT_INTEGRATED_RAID) {
int reason
@@ -1190,6 +1203,8 @@ static struct spi_function_template mptspi_transport_functions = {
static struct pci_device_id mptspi_pci_table[] = {
{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030,
PCI_ANY_ID, PCI_ANY_ID },
+ { PCI_VENDOR_ID_ATTO, MPI_MANUFACTPAGE_DEVID_53C1030,
+ PCI_ANY_ID, PCI_ANY_ID },
{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035,
PCI_ANY_ID, PCI_ANY_ID },
{0} /* Terminating entry */
@@ -1210,11 +1225,12 @@ mptspi_dv_renegotiate_work(struct work_struct *work)
struct scsi_target *starget;
struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
u32 nego;
+ MPT_ADAPTER *ioc = hd->ioc;
kfree(wqw);
if (hd->spi_pending) {
- shost_for_each_device(sdev, hd->ioc->sh) {
+ shost_for_each_device(sdev, ioc->sh) {
if (hd->spi_pending & (1 << sdev->id))
continue;
starget = scsi_target(sdev);
@@ -1225,7 +1241,7 @@ mptspi_dv_renegotiate_work(struct work_struct *work)
mptspi_write_spi_device_pg1(starget, &pg1);
}
} else {
- shost_for_each_device(sdev, hd->ioc->sh)
+ shost_for_each_device(sdev, ioc->sh)
mptspi_dv_device(hd, sdev);
}
}
@@ -1250,7 +1266,7 @@ mptspi_dv_renegotiate(struct _MPT_SCSI_HOST *hd)
static int
mptspi_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
{
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
int rc;
rc = mptscsih_ioc_reset(ioc, reset_phase);
@@ -1269,7 +1285,7 @@ static int
mptspi_resume(struct pci_dev *pdev)
{
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
- struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)ioc->sh->hostdata;
+ struct _MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
int rc;
rc = mptscsih_resume(pdev);
@@ -1416,7 +1432,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (numSGE < sh->sg_tablesize) {
/* Reset this value */
- dprintk(ioc, printk(MYIOC_s_INFO_FMT
+ dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Resetting sg_tablesize to %d from %d\n",
ioc->name, numSGE, sh->sg_tablesize));
sh->sg_tablesize = numSGE;
@@ -1424,20 +1440,21 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_unlock_irqrestore(&ioc->FreeQlock, flags);
- hd = (MPT_SCSI_HOST *) sh->hostdata;
+ hd = shost_priv(sh);
hd->ioc = ioc;
/* SCSI needs scsi_cmnd lookup table!
* (with size equal to req_depth*PtrSz!)
*/
- hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
- if (!hd->ScsiLookup) {
+ ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
+ if (!ioc->ScsiLookup) {
error = -ENOMEM;
goto out_mptspi_probe;
}
+ spin_lock_init(&ioc->scsi_lookup_lock);
dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
- ioc->name, hd->ScsiLookup));
+ ioc->name, ioc->ScsiLookup));
/* Clear the TM flags
*/
@@ -1477,13 +1494,13 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* Some versions of the firmware don't support page 0; without
* that we can't get the parameters */
- if (hd->ioc->spi_data.sdp0length != 0)
+ if (ioc->spi_data.sdp0length != 0)
sh->transportt = mptspi_transport_template;
error = scsi_add_host (sh, &ioc->pcidev->dev);
if(error) {
- dprintk(ioc, printk(KERN_ERR MYNAM
- "scsi_add_host failed\n"));
+ dprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "scsi_add_host failed\n", ioc->name));
goto out_mptspi_probe;
}
diff --git a/drivers/message/i2o/README b/drivers/message/i2o/README
index a81f851f7b5..911fc3021e3 100644
--- a/drivers/message/i2o/README
+++ b/drivers/message/i2o/README
@@ -30,13 +30,13 @@ Juha Sievanen, University of Helsinki Finland
Bug fixes
Core code extensions
-Auvo Häkkinen, University of Helsinki Finland
+Auvo Häkkinen, University of Helsinki Finland
LAN OSM code
/Proc interface to LAN class
Bug fixes
Core code extensions
-Taneli Vähäkangas, University of Helsinki Finland
+Taneli Vähäkangas, University of Helsinki Finland
Fixes to i2o_config
CREDITS
diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c
index 8c83ee3b092..6cbcc21de51 100644
--- a/drivers/message/i2o/exec-osm.c
+++ b/drivers/message/i2o/exec-osm.c
@@ -15,8 +15,8 @@
*
* Fixes/additions:
* Philipp Rumpf
- * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
* Deepak Saxena <deepak@plexity.net>
* Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
* Alan Cox <alan@redhat.com>:
@@ -41,8 +41,6 @@
struct i2o_driver i2o_exec_driver;
-static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind);
-
/* global wait list for POST WAIT */
static LIST_HEAD(i2o_exec_wait_list);
@@ -369,6 +367,53 @@ static int i2o_exec_remove(struct device *dev)
return 0;
};
+#ifdef CONFIG_I2O_LCT_NOTIFY_ON_CHANGES
+/**
+ * i2o_exec_lct_notify - Send a asynchronus LCT NOTIFY request
+ * @c: I2O controller to which the request should be send
+ * @change_ind: change indicator
+ *
+ * This function sends a LCT NOTIFY request to the I2O controller with
+ * the change indicator change_ind. If the change_ind == 0 the controller
+ * replies immediately after the request. If change_ind > 0 the reply is
+ * send after change indicator of the LCT is > change_ind.
+ */
+static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
+{
+ i2o_status_block *sb = c->status_block.virt;
+ struct device *dev;
+ struct i2o_message *msg;
+
+ mutex_lock(&c->lct_lock);
+
+ dev = &c->pdev->dev;
+
+ if (i2o_dma_realloc
+ (dev, &c->dlct, le32_to_cpu(sb->expected_lct_size), GFP_KERNEL))
+ return -ENOMEM;
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
+ msg->u.head[1] = cpu_to_le32(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 |
+ ADAPTER_TID);
+ msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
+ msg->u.s.tcntxt = cpu_to_le32(0x00000000);
+ msg->body[0] = cpu_to_le32(0xffffffff);
+ msg->body[1] = cpu_to_le32(change_ind);
+ msg->body[2] = cpu_to_le32(0xd0000000 | c->dlct.len);
+ msg->body[3] = cpu_to_le32(c->dlct.phys);
+
+ i2o_msg_post(c, msg);
+
+ mutex_unlock(&c->lct_lock);
+
+ return 0;
+}
+#endif
+
/**
* i2o_exec_lct_modified - Called on LCT NOTIFY reply
* @_work: work struct for a specific controller
@@ -525,51 +570,6 @@ int i2o_exec_lct_get(struct i2o_controller *c)
return rc;
}
-/**
- * i2o_exec_lct_notify - Send a asynchronus LCT NOTIFY request
- * @c: I2O controller to which the request should be send
- * @change_ind: change indicator
- *
- * This function sends a LCT NOTIFY request to the I2O controller with
- * the change indicator change_ind. If the change_ind == 0 the controller
- * replies immediately after the request. If change_ind > 0 the reply is
- * send after change indicator of the LCT is > change_ind.
- */
-static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
-{
- i2o_status_block *sb = c->status_block.virt;
- struct device *dev;
- struct i2o_message *msg;
-
- mutex_lock(&c->lct_lock);
-
- dev = &c->pdev->dev;
-
- if (i2o_dma_realloc
- (dev, &c->dlct, le32_to_cpu(sb->expected_lct_size), GFP_KERNEL))
- return -ENOMEM;
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
- msg->u.head[1] = cpu_to_le32(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 |
- ADAPTER_TID);
- msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
- msg->u.s.tcntxt = cpu_to_le32(0x00000000);
- msg->body[0] = cpu_to_le32(0xffffffff);
- msg->body[1] = cpu_to_le32(change_ind);
- msg->body[2] = cpu_to_le32(0xd0000000 | c->dlct.len);
- msg->body[3] = cpu_to_le32(c->dlct.phys);
-
- i2o_msg_post(c, msg);
-
- mutex_unlock(&c->lct_lock);
-
- return 0;
-};
-
/* Exec OSM driver struct */
struct i2o_driver i2o_exec_driver = {
.name = OSM_NAME,
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index 50b2c733441..e4ad7a1c4fb 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -149,29 +149,6 @@ static int i2o_block_device_flush(struct i2o_device *dev)
};
/**
- * i2o_block_issue_flush - device-flush interface for block-layer
- * @queue: the request queue of the device which should be flushed
- * @disk: gendisk
- * @error_sector: error offset
- *
- * Helper function to provide flush functionality to block-layer.
- *
- * Returns 0 on success or negative error code on failure.
- */
-
-static int i2o_block_issue_flush(struct request_queue * queue, struct gendisk *disk,
- sector_t * error_sector)
-{
- struct i2o_block_device *i2o_blk_dev = queue->queuedata;
- int rc = -ENODEV;
-
- if (likely(i2o_blk_dev))
- rc = i2o_block_device_flush(i2o_blk_dev->i2o_dev);
-
- return rc;
-}
-
-/**
* i2o_block_device_mount - Mount (load) the media of device dev
* @dev: I2O device which should receive the mount request
* @media_id: Media Identifier
@@ -307,6 +284,7 @@ static inline struct i2o_block_request *i2o_block_request_alloc(void)
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&ireq->queue);
+ sg_init_table(ireq->sg_table, I2O_MAX_PHYS_SEGMENTS);
return ireq;
};
@@ -1009,7 +987,6 @@ static struct i2o_block_device *i2o_block_device_alloc(void)
}
blk_queue_prep_rq(queue, i2o_block_prep_req_fn);
- blk_queue_issue_flush_fn(queue, i2o_block_issue_flush);
gd->major = I2O_MAJOR;
gd->queue = queue;
@@ -1100,8 +1077,8 @@ static int i2o_block_probe(struct device *dev)
blk_queue_max_sectors(queue, max_sectors);
blk_queue_max_hw_segments(queue, i2o_sg_tablesize(c, body_size));
- osm_debug("max sectors = %d\n", queue->max_phys_segments);
- osm_debug("phys segments = %d\n", queue->max_sectors);
+ osm_debug("max sectors = %d\n", queue->max_sectors);
+ osm_debug("phys segments = %d\n", queue->max_phys_segments);
osm_debug("max hw segments = %d\n", queue->max_hw_segments);
/*
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
index 84e046e94f5..c0fb77dc19b 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -10,12 +10,12 @@
* Added basic ioctl() support
* Deepak Saxena (06/07/1999):
* Added software download ioctl (still testing)
- * Auvo Häkkinen (09/10/1999):
+ * Auvo Häkkinen (09/10/1999):
* Changes to i2o_cfg_reply(), ioctl_parms()
* Added ioct_validate()
- * Taneli Vähäkangas (09/30/1999):
+ * Taneli Vähäkangas (09/30/1999):
* Fixed ioctl_swdl()
- * Taneli Vähäkangas (10/04/1999):
+ * Taneli Vähäkangas (10/04/1999):
* Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()
* Deepak Saxena (11/18/1999):
* Added event managmenet support
diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c
index 06892ac2286..6fdd072201f 100644
--- a/drivers/message/i2o/i2o_proc.c
+++ b/drivers/message/i2o/i2o_proc.c
@@ -19,8 +19,8 @@
*
*
* Fixes/additions:
- * Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI),
- * Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI)
+ * Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI),
+ * Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI)
* University of Helsinki, Department of Computer Science
* LAN entries
* Markus Lidel <Markus.Lidel@shadowconnect.com>
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
index a1ec16a075c..7814a06ae97 100644
--- a/drivers/message/i2o/iop.c
+++ b/drivers/message/i2o/iop.c
@@ -15,8 +15,8 @@
*
* Fixes/additions:
* Philipp Rumpf
- * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
* Deepak Saxena <deepak@plexity.net>
* Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
* Alan Cox <alan@redhat.com>:
diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
index 3661e6e065d..685a89547a5 100644
--- a/drivers/message/i2o/pci.c
+++ b/drivers/message/i2o/pci.c
@@ -15,8 +15,8 @@
*
* Fixes/additions:
* Philipp Rumpf
- * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
* Deepak Saxena <deepak@plexity.net>
* Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
* Alan Cox <alan@redhat.com>:
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index a20a51efe11..25716193a53 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -10,8 +10,8 @@ config MFD_SM501
---help---
This is the core driver for the Silicon Motion SM501 multimedia
companion chip. This device is a multifunction device which may
- provide numerous interfaces including USB host controller USB gadget,
- Asyncronous Serial ports, Audio functions and a dual display video
+ provide numerous interfaces including USB host controller, USB gadget,
+ asynchronous serial ports, audio functions, and a dual display video
interface. The device may be connected by PCI or local bus with
varying functions enabled.
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 73e248fb2ff..b5e67c0ff43 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -111,6 +111,21 @@ config ASUS_LAPTOP
If you have an ACPI-compatible ASUS laptop, say Y or M here.
+config FUJITSU_LAPTOP
+ tristate "Fujitsu Laptop Extras"
+ depends on X86
+ depends on ACPI
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This is a driver for laptops built by Fujitsu:
+
+ * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks
+ * Possibly other Fujitsu laptop models
+
+ It adds support for LCD brightness control.
+
+ If you have a Fujitsu laptop, say Y or M here.
+
config MSI_LAPTOP
tristate "MSI Laptop Extras"
depends on X86
@@ -134,6 +149,7 @@ config SONY_LAPTOP
tristate "Sony Laptop Extras"
depends on X86 && ACPI
select BACKLIGHT_CLASS_DEVICE
+ depends on INPUT
---help---
This mini-driver drives the SNC and SPIC devices present in the ACPI
BIOS of the Sony Vaio laptops.
@@ -156,6 +172,7 @@ config THINKPAD_ACPI
select BACKLIGHT_CLASS_DEVICE
select HWMON
select NVRAM
+ depends on INPUT
---help---
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video
@@ -163,7 +180,7 @@ config THINKPAD_ACPI
For more information about this driver see
<file:Documentation/thinkpad-acpi.txt> and <http://ibm-acpi.sf.net/> .
- This driver was formely known as ibm-acpi.
+ This driver was formerly known as ibm-acpi.
If you have an IBM or Lenovo ThinkPad laptop, say Y or M here.
@@ -197,10 +214,22 @@ config THINKPAD_ACPI_BAY
default y
---help---
Allows the thinkpad_acpi driver to handle removable bays. It will
- eletrically disable the device in the bay, and also generate
+ electrically disable the device in the bay, and also generate
notifications when the bay lever is ejected or inserted.
If you are not sure, say Y here.
+config ATMEL_SSC
+ tristate "Device driver for Atmel SSC peripheral"
+ depends on AVR32 || ARCH_AT91
+ ---help---
+ This option enables device driver support for Atmel Syncronized
+ Serial Communication peripheral (SSC).
+
+ The SSC peripheral supports a wide variety of serial frame based
+ communications, i.e. I2S, SPI, etc.
+
+ If unsure, say N.
+
endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b5ce0e3dba8..87f2685d728 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
+obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
@@ -14,4 +15,5 @@ obj-$(CONFIG_PHANTOM) += phantom.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
+obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
new file mode 100644
index 00000000000..058ccac700d
--- /dev/null
+++ b/drivers/misc/atmel-ssc.c
@@ -0,0 +1,174 @@
+/*
+ * Atmel SSC driver
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/atmel-ssc.h>
+
+/* Serialize access to ssc_list and user count */
+static DEFINE_SPINLOCK(user_lock);
+static LIST_HEAD(ssc_list);
+
+struct ssc_device *ssc_request(unsigned int ssc_num)
+{
+ int ssc_valid = 0;
+ struct ssc_device *ssc;
+
+ spin_lock(&user_lock);
+ list_for_each_entry(ssc, &ssc_list, list) {
+ if (ssc->pdev->id == ssc_num) {
+ ssc_valid = 1;
+ break;
+ }
+ }
+
+ if (!ssc_valid) {
+ spin_unlock(&user_lock);
+ dev_dbg(&ssc->pdev->dev, "could not find requested device\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ if (ssc->user) {
+ spin_unlock(&user_lock);
+ dev_dbg(&ssc->pdev->dev, "module busy\n");
+ return ERR_PTR(-EBUSY);
+ }
+ ssc->user++;
+ spin_unlock(&user_lock);
+
+ clk_enable(ssc->clk);
+
+ return ssc;
+}
+EXPORT_SYMBOL(ssc_request);
+
+void ssc_free(struct ssc_device *ssc)
+{
+ spin_lock(&user_lock);
+ if (ssc->user) {
+ ssc->user--;
+ clk_disable(ssc->clk);
+ } else {
+ dev_dbg(&ssc->pdev->dev, "device already free\n");
+ }
+ spin_unlock(&user_lock);
+}
+EXPORT_SYMBOL(ssc_free);
+
+static int __init ssc_probe(struct platform_device *pdev)
+{
+ int retval = 0;
+ struct resource *regs;
+ struct ssc_device *ssc;
+
+ ssc = kzalloc(sizeof(struct ssc_device), GFP_KERNEL);
+ if (!ssc) {
+ dev_dbg(&pdev->dev, "out of memory\n");
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_dbg(&pdev->dev, "no mmio resource defined\n");
+ retval = -ENXIO;
+ goto out_free;
+ }
+
+ ssc->clk = clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(ssc->clk)) {
+ dev_dbg(&pdev->dev, "no pclk clock defined\n");
+ retval = -ENXIO;
+ goto out_free;
+ }
+
+ ssc->pdev = pdev;
+ ssc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!ssc->regs) {
+ dev_dbg(&pdev->dev, "ioremap failed\n");
+ retval = -EINVAL;
+ goto out_clk;
+ }
+
+ /* disable all interrupts */
+ clk_enable(ssc->clk);
+ ssc_writel(ssc->regs, IDR, ~0UL);
+ ssc_readl(ssc->regs, SR);
+ clk_disable(ssc->clk);
+
+ ssc->irq = platform_get_irq(pdev, 0);
+ if (!ssc->irq) {
+ dev_dbg(&pdev->dev, "could not get irq\n");
+ retval = -ENXIO;
+ goto out_unmap;
+ }
+
+ spin_lock(&user_lock);
+ list_add_tail(&ssc->list, &ssc_list);
+ spin_unlock(&user_lock);
+
+ platform_set_drvdata(pdev, ssc);
+
+ dev_info(&pdev->dev, "Atmel SSC device at 0x%p (irq %d)\n",
+ ssc->regs, ssc->irq);
+
+ goto out;
+
+out_unmap:
+ iounmap(ssc->regs);
+out_clk:
+ clk_put(ssc->clk);
+out_free:
+ kfree(ssc);
+out:
+ return retval;
+}
+
+static int __devexit ssc_remove(struct platform_device *pdev)
+{
+ struct ssc_device *ssc = platform_get_drvdata(pdev);
+
+ spin_lock(&user_lock);
+ iounmap(ssc->regs);
+ clk_put(ssc->clk);
+ list_del(&ssc->list);
+ kfree(ssc);
+ spin_unlock(&user_lock);
+
+ return 0;
+}
+
+static struct platform_driver ssc_driver = {
+ .remove = __devexit_p(ssc_remove),
+ .driver = {
+ .name = "ssc",
+ },
+};
+
+static int __init ssc_init(void)
+{
+ return platform_driver_probe(&ssc_driver, ssc_probe);
+}
+module_init(ssc_init);
+
+static void __exit ssc_exit(void)
+{
+ platform_driver_unregister(&ssc_driver);
+}
+module_exit(ssc_exit);
+
+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
+MODULE_DESCRIPTION("SSC driver for Atmel AVR32 and AT91");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c
new file mode 100644
index 00000000000..c8d62c268b1
--- /dev/null
+++ b/drivers/misc/fujitsu-laptop.c
@@ -0,0 +1,355 @@
+/*-*-linux-c-*-*/
+
+/*
+ Copyright (C) 2007 Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+ Based on earlier work:
+ Copyright (C) 2003 Shane Spencer <shane@bogomip.com>
+ Adrian Yee <brewt-fujitsu@brewt.org>
+
+ Templated from msi-laptop.c which is copyright by its respective authors.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+ */
+
+/*
+ * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional
+ * features made available on a range of Fujitsu laptops including the
+ * P2xxx/P5xxx/S6xxx/S7xxx series.
+ *
+ * This driver exports a few files in /sys/devices/platform/fujitsu-laptop/;
+ * others may be added at a later date.
+ *
+ * lcd_level - Screen brightness: contains a single integer in the
+ * range 0..7. (rw)
+ *
+ * In addition to these platform device attributes the driver
+ * registers itself in the Linux backlight control subsystem and is
+ * available to userspace under /sys/class/backlight/fujitsu-laptop/.
+ *
+ * This driver has been tested on a Fujitsu Lifebook S7020. It should
+ * work on most P-series and S-series Lifebooks, but YMMV.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/autoconf.h>
+
+#define FUJITSU_DRIVER_VERSION "0.3"
+
+#define FUJITSU_LCD_N_LEVELS 8
+
+#define ACPI_FUJITSU_CLASS "fujitsu"
+#define ACPI_FUJITSU_HID "FUJ02B1"
+#define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI extras driver"
+#define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1"
+
+struct fujitsu_t {
+ acpi_handle acpi_handle;
+ struct backlight_device *bl_device;
+ struct platform_device *pf_device;
+
+ unsigned long fuj02b1_state;
+ unsigned int brightness_changed;
+ unsigned int brightness_level;
+};
+
+static struct fujitsu_t *fujitsu;
+
+/* Hardware access */
+
+static int set_lcd_level(int level)
+{
+ acpi_status status = AE_OK;
+ union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+ struct acpi_object_list arg_list = { 1, &arg0 };
+ acpi_handle handle = NULL;
+
+ if (level < 0 || level >= FUJITSU_LCD_N_LEVELS)
+ return -EINVAL;
+
+ if (!fujitsu)
+ return -EINVAL;
+
+ status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SBLL not present\n"));
+ return -ENODEV;
+ }
+
+ arg0.integer.value = level;
+
+ status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ return 0;
+}
+
+static int get_lcd_level(void)
+{
+ unsigned long state = 0;
+ acpi_status status = AE_OK;
+
+ // Get the Brightness
+ status =
+ acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state);
+ if (status < 0)
+ return status;
+
+ fujitsu->fuj02b1_state = state;
+ fujitsu->brightness_level = state & 0x0fffffff;
+
+ if (state & 0x80000000)
+ fujitsu->brightness_changed = 1;
+ else
+ fujitsu->brightness_changed = 0;
+
+ return fujitsu->brightness_level;
+}
+
+/* Backlight device stuff */
+
+static int bl_get_brightness(struct backlight_device *b)
+{
+ return get_lcd_level();
+}
+
+static int bl_update_status(struct backlight_device *b)
+{
+ return set_lcd_level(b->props.brightness);
+}
+
+static struct backlight_ops fujitsubl_ops = {
+ .get_brightness = bl_get_brightness,
+ .update_status = bl_update_status,
+};
+
+/* Platform device */
+
+static ssize_t show_lcd_level(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ int ret;
+
+ ret = get_lcd_level();
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%i\n", ret);
+}
+
+static ssize_t store_lcd_level(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+
+ int level, ret;
+
+ if (sscanf(buf, "%i", &level) != 1
+ || (level < 0 || level >= FUJITSU_LCD_N_LEVELS))
+ return -EINVAL;
+
+ ret = set_lcd_level(level);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
+
+static struct attribute *fujitsupf_attributes[] = {
+ &dev_attr_lcd_level.attr,
+ NULL
+};
+
+static struct attribute_group fujitsupf_attribute_group = {
+ .attrs = fujitsupf_attributes
+};
+
+static struct platform_driver fujitsupf_driver = {
+ .driver = {
+ .name = "fujitsu-laptop",
+ .owner = THIS_MODULE,
+ }
+};
+
+/* ACPI device */
+
+static int acpi_fujitsu_add(struct acpi_device *device)
+{
+ int result = 0;
+ int state = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_fujitsu_add");
+
+ if (!device)
+ return -EINVAL;
+
+ fujitsu->acpi_handle = device->handle;
+ sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME);
+ sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS);
+ acpi_driver_data(device) = fujitsu;
+
+ result = acpi_bus_get_power(fujitsu->acpi_handle, &state);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error reading power state\n"));
+ goto end;
+ }
+
+ printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
+ acpi_device_name(device), acpi_device_bid(device),
+ !device->power.state ? "on" : "off");
+
+ end:
+
+ return result;
+}
+
+static int acpi_fujitsu_remove(struct acpi_device *device, int type)
+{
+ ACPI_FUNCTION_TRACE("acpi_fujitsu_remove");
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+ fujitsu->acpi_handle = 0;
+
+ return 0;
+}
+
+static const struct acpi_device_id fujitsu_device_ids[] = {
+ {ACPI_FUJITSU_HID, 0},
+ {"", 0},
+};
+
+static struct acpi_driver acpi_fujitsu_driver = {
+ .name = ACPI_FUJITSU_DRIVER_NAME,
+ .class = ACPI_FUJITSU_CLASS,
+ .ids = fujitsu_device_ids,
+ .ops = {
+ .add = acpi_fujitsu_add,
+ .remove = acpi_fujitsu_remove,
+ },
+};
+
+/* Initialization */
+
+static int __init fujitsu_init(void)
+{
+ int ret, result;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ fujitsu = kmalloc(sizeof(struct fujitsu_t), GFP_KERNEL);
+ if (!fujitsu)
+ return -ENOMEM;
+ memset(fujitsu, 0, sizeof(struct fujitsu_t));
+
+ result = acpi_bus_register_driver(&acpi_fujitsu_driver);
+ if (result < 0) {
+ ret = -ENODEV;
+ goto fail_acpi;
+ }
+
+ /* Register backlight stuff */
+
+ fujitsu->bl_device =
+ backlight_device_register("fujitsu-laptop", NULL, NULL,
+ &fujitsubl_ops);
+ if (IS_ERR(fujitsu->bl_device))
+ return PTR_ERR(fujitsu->bl_device);
+
+ fujitsu->bl_device->props.max_brightness = FUJITSU_LCD_N_LEVELS - 1;
+ ret = platform_driver_register(&fujitsupf_driver);
+ if (ret)
+ goto fail_backlight;
+
+ /* Register platform stuff */
+
+ fujitsu->pf_device = platform_device_alloc("fujitsu-laptop", -1);
+ if (!fujitsu->pf_device) {
+ ret = -ENOMEM;
+ goto fail_platform_driver;
+ }
+
+ ret = platform_device_add(fujitsu->pf_device);
+ if (ret)
+ goto fail_platform_device1;
+
+ ret =
+ sysfs_create_group(&fujitsu->pf_device->dev.kobj,
+ &fujitsupf_attribute_group);
+ if (ret)
+ goto fail_platform_device2;
+
+ printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION
+ " successfully loaded.\n");
+
+ return 0;
+
+ fail_platform_device2:
+
+ platform_device_del(fujitsu->pf_device);
+
+ fail_platform_device1:
+
+ platform_device_put(fujitsu->pf_device);
+
+ fail_platform_driver:
+
+ platform_driver_unregister(&fujitsupf_driver);
+
+ fail_backlight:
+
+ backlight_device_unregister(fujitsu->bl_device);
+
+ fail_acpi:
+
+ kfree(fujitsu);
+
+ return ret;
+}
+
+static void __exit fujitsu_cleanup(void)
+{
+ sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
+ &fujitsupf_attribute_group);
+ platform_device_unregister(fujitsu->pf_device);
+ platform_driver_unregister(&fujitsupf_driver);
+ backlight_device_unregister(fujitsu->bl_device);
+
+ acpi_bus_unregister_driver(&acpi_fujitsu_driver);
+
+ kfree(fujitsu);
+
+ printk(KERN_INFO "fujitsu-laptop: driver unloaded.\n");
+}
+
+module_init(fujitsu_init);
+module_exit(fujitsu_cleanup);
+
+MODULE_AUTHOR("Jonathan Woithe");
+MODULE_DESCRIPTION("Fujitsu laptop extras support");
+MODULE_VERSION(FUJITSU_DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
index 276ba3c5143..aa8ce7abe92 100644
--- a/drivers/misc/hdpuftrs/hdpu_cpustate.c
+++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c
@@ -19,16 +19,41 @@
#include <linux/spinlock.h>
#include <linux/miscdevice.h>
#include <linux/proc_fs.h>
+#include <linux/hdpu_features.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
-#include <linux/hdpu_features.h>
+#include <linux/seq_file.h>
+#include <asm/io.h>
#define SKY_CPUSTATE_VERSION "1.1"
static int hdpu_cpustate_probe(struct platform_device *pdev);
static int hdpu_cpustate_remove(struct platform_device *pdev);
-struct cpustate_t cpustate;
+static unsigned char cpustate_get_state(void);
+static int cpustate_proc_open(struct inode *inode, struct file *file);
+static int cpustate_proc_read(struct seq_file *seq, void *offset);
+
+static struct cpustate_t cpustate;
+
+static const struct file_operations proc_cpustate = {
+ .open = cpustate_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int cpustate_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cpustate_proc_read, NULL);
+}
+
+static int cpustate_proc_read(struct seq_file *seq, void *offset)
+{
+ seq_printf(seq, "CPU State: %04x\n", cpustate_get_state());
+ return 0;
+}
static int cpustate_get_ref(int excl)
{
@@ -66,13 +91,13 @@ static int cpustate_free_ref(void)
return 0;
}
-unsigned char cpustate_get_state(void)
+static unsigned char cpustate_get_state(void)
{
return cpustate.cached_val;
}
-void cpustate_set_state(unsigned char new_state)
+static void cpustate_set_state(unsigned char new_state)
{
unsigned int state = (new_state << 21);
@@ -134,29 +159,6 @@ static int cpustate_release(struct inode *inode, struct file *file)
return cpustate_free_ref();
}
-/*
- * Info exported via "/proc/sky_cpustate".
- */
-static int cpustate_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- char *p = page;
- int len = 0;
-
- p += sprintf(p, "CPU State: %04x\n", cpustate_get_state());
- len = p - page;
-
- if (len <= off + count)
- *eof = 1;
- *start = page + off;
- len -= off;
- if (len > count)
- len = count;
- if (len < 0)
- len = 0;
- return len;
-}
-
static struct platform_driver hdpu_cpustate_driver = {
.probe = hdpu_cpustate_probe,
.remove = hdpu_cpustate_remove,
@@ -169,22 +171,18 @@ static struct platform_driver hdpu_cpustate_driver = {
* The various file operations we support.
*/
static const struct file_operations cpustate_fops = {
- owner:THIS_MODULE,
- open:cpustate_open,
- release:cpustate_release,
- read:cpustate_read,
- write:cpustate_write,
- fasync:NULL,
- poll:NULL,
- ioctl:NULL,
- llseek:no_llseek,
-
+ .owner = THIS_MODULE,
+ .open = cpustate_open,
+ .release = cpustate_release,
+ .read = cpustate_read,
+ .write = cpustate_write,
+ .llseek = no_llseek,
};
static struct miscdevice cpustate_dev = {
- MISC_DYNAMIC_MINOR,
- "sky_cpustate",
- &cpustate_fops
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "sky_cpustate",
+ .fops = &cpustate_fops,
};
static int hdpu_cpustate_probe(struct platform_device *pdev)
@@ -194,23 +192,31 @@ static int hdpu_cpustate_probe(struct platform_device *pdev)
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ printk(KERN_ERR "sky_cpustate: "
+ "Invalid memory resource.\n");
+ return -EINVAL;
+ }
cpustate.set_addr = (unsigned long *)res->start;
cpustate.clr_addr = (unsigned long *)res->end - 1;
ret = misc_register(&cpustate_dev);
if (ret) {
- printk(KERN_WARNING "sky_cpustate: Unable to register misc "
- "device.\n");
+ printk(KERN_WARNING "sky_cpustate: "
+ "Unable to register misc device.\n");
cpustate.set_addr = NULL;
cpustate.clr_addr = NULL;
return ret;
}
- proc_de = create_proc_read_entry("sky_cpustate", 0, 0,
- cpustate_read_proc, NULL);
- if (proc_de == NULL)
- printk(KERN_WARNING "sky_cpustate: Unable to create proc "
- "dir entry\n");
+ proc_de = create_proc_entry("sky_cpustate", 0666, &proc_root);
+ if (!proc_de) {
+ printk(KERN_WARNING "sky_cpustate: "
+ "Unable to create proc entry\n");
+ } else {
+ proc_de->proc_fops = &proc_cpustate;
+ proc_de->owner = THIS_MODULE;
+ }
printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n");
return 0;
@@ -218,21 +224,18 @@ static int hdpu_cpustate_probe(struct platform_device *pdev)
static int hdpu_cpustate_remove(struct platform_device *pdev)
{
-
cpustate.set_addr = NULL;
cpustate.clr_addr = NULL;
remove_proc_entry("sky_cpustate", NULL);
misc_deregister(&cpustate_dev);
- return 0;
+ return 0;
}
static int __init cpustate_init(void)
{
- int rc;
- rc = platform_driver_register(&hdpu_cpustate_driver);
- return rc;
+ return platform_driver_register(&hdpu_cpustate_driver);
}
static void __exit cpustate_exit(void)
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c
index 60c8b26f067..2887b214798 100644
--- a/drivers/misc/hdpuftrs/hdpu_nexus.c
+++ b/drivers/misc/hdpuftrs/hdpu_nexus.c
@@ -18,17 +18,38 @@
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/hdpu_features.h>
-
#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <asm/io.h>
static int hdpu_nexus_probe(struct platform_device *pdev);
static int hdpu_nexus_remove(struct platform_device *pdev);
+static int hdpu_slot_id_open(struct inode *inode, struct file *file);
+static int hdpu_slot_id_read(struct seq_file *seq, void *offset);
+static int hdpu_chassis_id_open(struct inode *inode, struct file *file);
+static int hdpu_chassis_id_read(struct seq_file *seq, void *offset);
static struct proc_dir_entry *hdpu_slot_id;
static struct proc_dir_entry *hdpu_chassis_id;
static int slot_id = -1;
static int chassis_id = -1;
+static const struct file_operations proc_slot_id = {
+ .open = hdpu_slot_id_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations proc_chassis_id = {
+ .open = hdpu_chassis_id_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
static struct platform_driver hdpu_nexus_driver = {
.probe = hdpu_nexus_probe,
.remove = hdpu_nexus_remove,
@@ -37,43 +58,67 @@ static struct platform_driver hdpu_nexus_driver = {
},
};
-int hdpu_slot_id_read(char *buffer, char **buffer_location, off_t offset,
- int buffer_length, int *zero, void *ptr)
+static int hdpu_slot_id_open(struct inode *inode, struct file *file)
{
+ return single_open(file, hdpu_slot_id_read, NULL);
+}
- if (offset > 0)
- return 0;
- return sprintf(buffer, "%d\n", slot_id);
+static int hdpu_slot_id_read(struct seq_file *seq, void *offset)
+{
+ seq_printf(seq, "%d\n", slot_id);
+ return 0;
}
-int hdpu_chassis_id_read(char *buffer, char **buffer_location, off_t offset,
- int buffer_length, int *zero, void *ptr)
+static int hdpu_chassis_id_open(struct inode *inode, struct file *file)
{
+ return single_open(file, hdpu_chassis_id_read, NULL);
+}
- if (offset > 0)
- return 0;
- return sprintf(buffer, "%d\n", chassis_id);
+static int hdpu_chassis_id_read(struct seq_file *seq, void *offset)
+{
+ seq_printf(seq, "%d\n", chassis_id);
+ return 0;
}
static int hdpu_nexus_probe(struct platform_device *pdev)
{
struct resource *res;
+ int *nexus_id_addr;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- int *nexus_id_addr;
- nexus_id_addr =
- ioremap(res->start, (unsigned long)(res->end - res->start));
+ if (!res) {
+ printk(KERN_ERR "sky_nexus: "
+ "Invalid memory resource.\n");
+ return -EINVAL;
+ }
+ nexus_id_addr = ioremap(res->start,
+ (unsigned long)(res->end - res->start));
if (nexus_id_addr) {
slot_id = (*nexus_id_addr >> 8) & 0x1f;
chassis_id = *nexus_id_addr & 0xff;
iounmap(nexus_id_addr);
- } else
- printk("Could not map slot id\n");
+ } else {
+ printk(KERN_ERR "sky_nexus: Could not map slot id\n");
+ }
+
hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root);
- hdpu_slot_id->read_proc = hdpu_slot_id_read;
+ if (!hdpu_slot_id) {
+ printk(KERN_WARNING "sky_nexus: "
+ "Unable to create proc dir entry: sky_slot_id\n");
+ } else {
+ hdpu_slot_id->proc_fops = &proc_slot_id;
+ hdpu_slot_id->owner = THIS_MODULE;
+ }
hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root);
- hdpu_chassis_id->read_proc = hdpu_chassis_id_read;
+ if (!hdpu_chassis_id) {
+ printk(KERN_WARNING "sky_nexus: "
+ "Unable to create proc dir entry: sky_chassis_id\n");
+ } else {
+ hdpu_chassis_id->proc_fops = &proc_chassis_id;
+ hdpu_chassis_id->owner = THIS_MODULE;
+ }
+
return 0;
}
@@ -81,18 +126,19 @@ static int hdpu_nexus_remove(struct platform_device *pdev)
{
slot_id = -1;
chassis_id = -1;
+
remove_proc_entry("sky_slot_id", &proc_root);
remove_proc_entry("sky_chassis_id", &proc_root);
+
hdpu_slot_id = 0;
hdpu_chassis_id = 0;
+
return 0;
}
static int __init nexus_init(void)
{
- int rc;
- rc = platform_driver_register(&hdpu_nexus_driver);
- return rc;
+ return platform_driver_register(&hdpu_nexus_driver);
}
static void __exit nexus_exit(void)
diff --git a/drivers/misc/ibmasm/remote.c b/drivers/misc/ibmasm/remote.c
index 0550ce075fc..477bb43c899 100644
--- a/drivers/misc/ibmasm/remote.c
+++ b/drivers/misc/ibmasm/remote.c
@@ -17,7 +17,7 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Authors: Max Asböck <amax@us.ibm.com>
+ * Authors: Max Asböck <amax@us.ibm.com>
* Vernon Mauery <vernux@us.ibm.com>
*
*/
@@ -226,9 +226,9 @@ int ibmasm_init_remote_input_dev(struct service_processor *sp)
mouse_dev->id.product = pdev->device;
mouse_dev->id.version = 1;
mouse_dev->dev.parent = sp->dev;
- mouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- mouse_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) |
- BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+ mouse_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ mouse_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);
set_bit(BTN_TOUCH, mouse_dev->keybit);
mouse_dev->name = "ibmasm RSA I remote mouse";
input_set_abs_params(mouse_dev, ABS_X, 0, MOUSE_X_MAX, 0, 0);
@@ -239,7 +239,7 @@ int ibmasm_init_remote_input_dev(struct service_processor *sp)
keybd_dev->id.product = pdev->device;
keybd_dev->id.version = 2;
keybd_dev->dev.parent = sp->dev;
- keybd_dev->evbit[0] = BIT(EV_KEY);
+ keybd_dev->evbit[0] = BIT_MASK(EV_KEY);
keybd_dev->name = "ibmasm RSA I remote keyboard";
for (i = 0; i < XLATE_SIZE; i++) {
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c
index 6a5a05d1f39..05172d2613d 100644
--- a/drivers/misc/ioc4.c
+++ b/drivers/misc/ioc4.c
@@ -244,10 +244,11 @@ ioc4_variant(struct ioc4_driver_data *idd)
idd->idd_pdev->bus->number == pdev->bus->number &&
3 == PCI_SLOT(pdev->devfn))
found = 1;
- pci_dev_put(pdev);
} while (pdev && !found);
- if (NULL != pdev)
+ if (NULL != pdev) {
+ pci_dev_put(pdev);
return IOC4_VARIANT_IO9;
+ }
/* IO10: Look for a Vitesse VSC 7174 at the same bus and slot 3. */
pdev = NULL;
@@ -258,10 +259,11 @@ ioc4_variant(struct ioc4_driver_data *idd)
idd->idd_pdev->bus->number == pdev->bus->number &&
3 == PCI_SLOT(pdev->devfn))
found = 1;
- pci_dev_put(pdev);
} while (pdev && !found);
- if (NULL != pdev)
+ if (NULL != pdev) {
+ pci_dev_put(pdev);
return IOC4_VARIANT_IO10;
+ }
/* PCI-RT: No SCSI/SATA controller will be present */
return IOC4_VARIANT_PCI_RT;
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
index 349be934db7..83679c76292 100644
--- a/drivers/misc/msi-laptop.c
+++ b/drivers/misc/msi-laptop.c
@@ -283,7 +283,7 @@ static struct platform_device *msipf_device;
/* Initialization */
-static int dmi_check_cb(struct dmi_system_id *id)
+static int dmi_check_cb(const struct dmi_system_id *id)
{
printk("msi-laptop: Identified laptop model '%s'.\n", id->ident);
return 0;
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
index 5108b7c576d..cd221fd0fb9 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -9,6 +9,7 @@
* You need an userspace library to cooperate with this driver. It (and other
* info) may be obtained here:
* http://www.fi.muni.cz/~xslaby/phantom.html
+ * or alternatively, you might use OpenHaptics provided by Sensable.
*/
#include <linux/kernel.h>
@@ -24,13 +25,14 @@
#include <asm/atomic.h>
#include <asm/io.h>
-#define PHANTOM_VERSION "n0.9.5"
+#define PHANTOM_VERSION "n0.9.7"
#define PHANTOM_MAX_MINORS 8
#define PHN_IRQCTL 0x4c /* irq control in caddr space */
#define PHB_RUNNING 1
+#define PHB_NOT_OH 2
static struct class *phantom_class;
static int phantom_major;
@@ -47,7 +49,11 @@ struct phantom_device {
struct cdev cdev;
struct mutex open_lock;
- spinlock_t ioctl_lock;
+ spinlock_t regs_lock;
+
+ /* used in NOT_OH mode */
+ struct phm_regs oregs;
+ u32 ctl_reg;
};
static unsigned char phantom_devices[PHANTOM_MAX_MINORS];
@@ -82,6 +88,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
struct phm_regs rs;
struct phm_reg r;
void __user *argp = (void __user *)arg;
+ unsigned long flags;
unsigned int i;
if (_IOC_TYPE(cmd) != PH_IOC_MAGIC ||
@@ -96,32 +103,45 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
if (r.reg > 7)
return -EINVAL;
- spin_lock(&dev->ioctl_lock);
+ spin_lock_irqsave(&dev->regs_lock, flags);
if (r.reg == PHN_CONTROL && (r.value & PHN_CTL_IRQ) &&
phantom_status(dev, dev->status | PHB_RUNNING)){
- spin_unlock(&dev->ioctl_lock);
+ spin_unlock_irqrestore(&dev->regs_lock, flags);
return -ENODEV;
}
pr_debug("phantom: writing %x to %u\n", r.value, r.reg);
+
+ /* preserve amp bit (don't allow to change it when in NOT_OH) */
+ if (r.reg == PHN_CONTROL && (dev->status & PHB_NOT_OH)) {
+ r.value &= ~PHN_CTL_AMP;
+ r.value |= dev->ctl_reg & PHN_CTL_AMP;
+ dev->ctl_reg = r.value;
+ }
+
iowrite32(r.value, dev->iaddr + r.reg);
ioread32(dev->iaddr); /* PCI posting */
if (r.reg == PHN_CONTROL && !(r.value & PHN_CTL_IRQ))
phantom_status(dev, dev->status & ~PHB_RUNNING);
- spin_unlock(&dev->ioctl_lock);
+ spin_unlock_irqrestore(&dev->regs_lock, flags);
break;
case PHN_SET_REGS:
if (copy_from_user(&rs, argp, sizeof(rs)))
return -EFAULT;
pr_debug("phantom: SRS %u regs %x\n", rs.count, rs.mask);
- spin_lock(&dev->ioctl_lock);
- for (i = 0; i < min(rs.count, 8U); i++)
- if ((1 << i) & rs.mask)
- iowrite32(rs.values[i], dev->oaddr + i);
- ioread32(dev->iaddr); /* PCI posting */
- spin_unlock(&dev->ioctl_lock);
+ spin_lock_irqsave(&dev->regs_lock, flags);
+ if (dev->status & PHB_NOT_OH)
+ memcpy(&dev->oregs, &rs, sizeof(rs));
+ else {
+ u32 m = min(rs.count, 8U);
+ for (i = 0; i < m; i++)
+ if (rs.mask & BIT(i))
+ iowrite32(rs.values[i], dev->oaddr + i);
+ ioread32(dev->iaddr); /* PCI posting */
+ }
+ spin_unlock_irqrestore(&dev->regs_lock, flags);
break;
case PHN_GET_REG:
if (copy_from_user(&r, argp, sizeof(r)))
@@ -135,20 +155,35 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
if (copy_to_user(argp, &r, sizeof(r)))
return -EFAULT;
break;
- case PHN_GET_REGS:
+ case PHN_GET_REGS: {
+ u32 m;
+
if (copy_from_user(&rs, argp, sizeof(rs)))
return -EFAULT;
+ m = min(rs.count, 8U);
+
pr_debug("phantom: GRS %u regs %x\n", rs.count, rs.mask);
- spin_lock(&dev->ioctl_lock);
- for (i = 0; i < min(rs.count, 8U); i++)
- if ((1 << i) & rs.mask)
+ spin_lock_irqsave(&dev->regs_lock, flags);
+ for (i = 0; i < m; i++)
+ if (rs.mask & BIT(i))
rs.values[i] = ioread32(dev->iaddr + i);
- spin_unlock(&dev->ioctl_lock);
+ spin_unlock_irqrestore(&dev->regs_lock, flags);
if (copy_to_user(argp, &rs, sizeof(rs)))
return -EFAULT;
break;
+ } case PHN_NOT_OH:
+ spin_lock_irqsave(&dev->regs_lock, flags);
+ if (dev->status & PHB_RUNNING) {
+ printk(KERN_ERR "phantom: you need to set NOT_OH "
+ "before you start the device!\n");
+ spin_unlock_irqrestore(&dev->regs_lock, flags);
+ return -EINVAL;
+ }
+ dev->status |= PHB_NOT_OH;
+ spin_unlock_irqrestore(&dev->regs_lock, flags);
+ break;
default:
return -ENOTTY;
}
@@ -171,8 +206,11 @@ static int phantom_open(struct inode *inode, struct file *file)
return -EINVAL;
}
+ WARN_ON(dev->status & PHB_NOT_OH);
+
file->private_data = dev;
+ atomic_set(&dev->counter, 0);
dev->opened++;
mutex_unlock(&dev->open_lock);
@@ -187,6 +225,7 @@ static int phantom_release(struct inode *inode, struct file *file)
dev->opened = 0;
phantom_status(dev, dev->status & ~PHB_RUNNING);
+ dev->status &= ~PHB_NOT_OH;
mutex_unlock(&dev->open_lock);
@@ -220,12 +259,32 @@ static struct file_operations phantom_file_ops = {
static irqreturn_t phantom_isr(int irq, void *data)
{
struct phantom_device *dev = data;
+ unsigned int i;
+ u32 ctl;
- if (!(ioread32(dev->iaddr + PHN_CONTROL) & PHN_CTL_IRQ))
+ spin_lock(&dev->regs_lock);
+ ctl = ioread32(dev->iaddr + PHN_CONTROL);
+ if (!(ctl & PHN_CTL_IRQ)) {
+ spin_unlock(&dev->regs_lock);
return IRQ_NONE;
+ }
iowrite32(0, dev->iaddr);
iowrite32(0xc0, dev->iaddr);
+
+ if (dev->status & PHB_NOT_OH) {
+ struct phm_regs *r = &dev->oregs;
+ u32 m = min(r->count, 8U);
+
+ for (i = 0; i < m; i++)
+ if (r->mask & BIT(i))
+ iowrite32(r->values[i], dev->oaddr + i);
+
+ dev->ctl_reg ^= PHN_CTL_AMP;
+ iowrite32(dev->ctl_reg, dev->iaddr + PHN_CONTROL);
+ }
+ spin_unlock(&dev->regs_lock);
+
ioread32(dev->iaddr); /* PCI posting */
atomic_inc(&dev->counter);
@@ -297,7 +356,7 @@ static int __devinit phantom_probe(struct pci_dev *pdev,
}
mutex_init(&pht->open_lock);
- spin_lock_init(&pht->ioctl_lock);
+ spin_lock_init(&pht->regs_lock);
init_waitqueue_head(&pht->wait);
cdev_init(&pht->cdev, &phantom_file_ops);
pht->cdev.owner = THIS_MODULE;
@@ -378,6 +437,8 @@ static int phantom_suspend(struct pci_dev *pdev, pm_message_t state)
iowrite32(0, dev->caddr + PHN_IRQCTL);
ioread32(dev->caddr + PHN_IRQCTL); /* PCI posting */
+ synchronize_irq(pdev->irq);
+
return 0;
}
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index d38ddce592c..bb13858f60a 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -14,7 +14,7 @@
*
* Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
*
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
*
* Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
*
@@ -277,7 +277,7 @@ static void do_sony_laptop_release_key(struct work_struct *work)
static DECLARE_WORK(sony_laptop_release_key_work,
do_sony_laptop_release_key);
-/* forward event to the input subsytem */
+/* forward event to the input subsystem */
static void sony_laptop_report_input_event(u8 event)
{
struct input_dev *jog_dev = sony_laptop_input.jog_dev;
@@ -411,9 +411,9 @@ static int sony_laptop_setup_input(void)
jog_dev->id.bustype = BUS_ISA;
jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
- jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
- jog_dev->relbit[0] = BIT(REL_WHEEL);
+ jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+ jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE);
+ jog_dev->relbit[0] = BIT_MASK(REL_WHEEL);
error = input_register_device(jog_dev);
if (error)
@@ -807,7 +807,7 @@ static struct sony_nc_event *sony_nc_events;
/* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence
* for Fn keys
*/
-static int sony_nc_C_enable(struct dmi_system_id *id)
+static int sony_nc_C_enable(const struct dmi_system_id *id)
{
int result = 0;
@@ -845,7 +845,7 @@ static struct sony_nc_event sony_C_events[] = {
};
/* SNC-only model map */
-static struct dmi_system_id sony_nc_ids[] = {
+static const struct dmi_system_id sony_nc_ids[] = {
{
.ident = "Sony Vaio FE Series",
.callback = sony_nc_C_enable,
@@ -1173,7 +1173,8 @@ static struct acpi_driver sony_nc_driver = {
#define SONYPI_TYPE3_OFFSET 0x12
struct sony_pic_ioport {
- struct acpi_resource_io io;
+ struct acpi_resource_io io1;
+ struct acpi_resource_io io2;
struct list_head list;
};
@@ -1443,11 +1444,11 @@ static u8 sony_pic_call1(u8 dev)
{
u8 v1, v2;
- wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+ wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
ITERATIONS_LONG);
- outb(dev, spic_dev.cur_ioport->io.minimum + 4);
- v1 = inb_p(spic_dev.cur_ioport->io.minimum + 4);
- v2 = inb_p(spic_dev.cur_ioport->io.minimum);
+ outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
+ v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
+ v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1);
return v2;
}
@@ -1456,13 +1457,13 @@ static u8 sony_pic_call2(u8 dev, u8 fn)
{
u8 v1;
- wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+ wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
ITERATIONS_LONG);
- outb(dev, spic_dev.cur_ioport->io.minimum + 4);
- wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+ outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
ITERATIONS_LONG);
- outb(fn, spic_dev.cur_ioport->io.minimum);
- v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+ outb(fn, spic_dev.cur_ioport->io1.minimum);
+ v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
dprintk("sony_pic_call2: 0x%.4x\n", v1);
return v1;
}
@@ -1471,13 +1472,13 @@ static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
{
u8 v1;
- wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
- outb(dev, spic_dev.cur_ioport->io.minimum + 4);
- wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
- outb(fn, spic_dev.cur_ioport->io.minimum);
- wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
- outb(v, spic_dev.cur_ioport->io.minimum);
- v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
+ outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
+ outb(fn, spic_dev.cur_ioport->io1.minimum);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
+ outb(v, spic_dev.cur_ioport->io1.minimum);
+ v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
dprintk("sony_pic_call3: 0x%.4x\n", v1);
return v1;
}
@@ -2074,7 +2075,18 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
switch (resource->type) {
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+ {
+ /* start IO enumeration */
+ struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
+ if (!ioport)
+ return AE_ERROR;
+
+ list_add(&ioport->list, &dev->ioports);
+ return AE_OK;
+ }
+
case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+ /* end IO enumeration */
return AE_OK;
case ACPI_RESOURCE_TYPE_IRQ:
@@ -2101,7 +2113,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
if (!interrupt)
return AE_ERROR;
- list_add_tail(&interrupt->list, &dev->interrupts);
+ list_add(&interrupt->list, &dev->interrupts);
interrupt->irq.triggering = p->triggering;
interrupt->irq.polarity = p->polarity;
interrupt->irq.sharable = p->sharable;
@@ -2113,18 +2125,27 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
case ACPI_RESOURCE_TYPE_IO:
{
struct acpi_resource_io *io = &resource->data.io;
- struct sony_pic_ioport *ioport = NULL;
+ struct sony_pic_ioport *ioport =
+ list_first_entry(&dev->ioports, struct sony_pic_ioport, list);
if (!io) {
dprintk("Blank IO resource\n");
return AE_OK;
}
- ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
- if (!ioport)
+ if (!ioport->io1.minimum) {
+ memcpy(&ioport->io1, io, sizeof(*io));
+ dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
+ ioport->io1.address_length);
+ }
+ else if (!ioport->io2.minimum) {
+ memcpy(&ioport->io2, io, sizeof(*io));
+ dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,
+ ioport->io2.address_length);
+ }
+ else {
+ printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n");
return AE_ERROR;
-
- list_add_tail(&ioport->list, &dev->ioports);
- memcpy(&ioport->io, io, sizeof(*io));
+ }
return AE_OK;
}
default:
@@ -2199,10 +2220,22 @@ static int sony_pic_enable(struct acpi_device *device,
{
acpi_status status;
int result = 0;
+ /* Type 1 resource layout is:
+ * IO
+ * IO
+ * IRQNoFlags
+ * End
+ *
+ * Type 2 and 3 resource layout is:
+ * IO
+ * IRQNoFlags
+ * End
+ */
struct {
- struct acpi_resource io_res;
- struct acpi_resource irq_res;
- struct acpi_resource end;
+ struct acpi_resource res1;
+ struct acpi_resource res2;
+ struct acpi_resource res3;
+ struct acpi_resource res4;
} *resource;
struct acpi_buffer buffer = { 0, NULL };
@@ -2217,21 +2250,49 @@ static int sony_pic_enable(struct acpi_device *device,
buffer.length = sizeof(*resource) + 1;
buffer.pointer = resource;
- /* setup io resource */
- resource->io_res.type = ACPI_RESOURCE_TYPE_IO;
- resource->io_res.length = sizeof(struct acpi_resource);
- memcpy(&resource->io_res.data.io, &ioport->io,
- sizeof(struct acpi_resource_io));
+ /* setup Type 1 resources */
+ if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
- /* setup irq resource */
- resource->irq_res.type = ACPI_RESOURCE_TYPE_IRQ;
- resource->irq_res.length = sizeof(struct acpi_resource);
- memcpy(&resource->irq_res.data.irq, &irq->irq,
- sizeof(struct acpi_resource_irq));
- /* we requested a shared irq */
- resource->irq_res.data.irq.sharable = ACPI_SHARED;
+ /* setup io resources */
+ resource->res1.type = ACPI_RESOURCE_TYPE_IO;
+ resource->res1.length = sizeof(struct acpi_resource);
+ memcpy(&resource->res1.data.io, &ioport->io1,
+ sizeof(struct acpi_resource_io));
- resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
+ resource->res2.type = ACPI_RESOURCE_TYPE_IO;
+ resource->res2.length = sizeof(struct acpi_resource);
+ memcpy(&resource->res2.data.io, &ioport->io2,
+ sizeof(struct acpi_resource_io));
+
+ /* setup irq resource */
+ resource->res3.type = ACPI_RESOURCE_TYPE_IRQ;
+ resource->res3.length = sizeof(struct acpi_resource);
+ memcpy(&resource->res3.data.irq, &irq->irq,
+ sizeof(struct acpi_resource_irq));
+ /* we requested a shared irq */
+ resource->res3.data.irq.sharable = ACPI_SHARED;
+
+ resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;
+
+ }
+ /* setup Type 2/3 resources */
+ else {
+ /* setup io resource */
+ resource->res1.type = ACPI_RESOURCE_TYPE_IO;
+ resource->res1.length = sizeof(struct acpi_resource);
+ memcpy(&resource->res1.data.io, &ioport->io1,
+ sizeof(struct acpi_resource_io));
+
+ /* setup irq resource */
+ resource->res2.type = ACPI_RESOURCE_TYPE_IRQ;
+ resource->res2.length = sizeof(struct acpi_resource);
+ memcpy(&resource->res2.data.irq, &irq->irq,
+ sizeof(struct acpi_resource_irq));
+ /* we requested a shared irq */
+ resource->res2.data.irq.sharable = ACPI_SHARED;
+
+ resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;
+ }
/* Attempt to set the resource */
dprintk("Evaluating _SRS\n");
@@ -2239,7 +2300,7 @@ static int sony_pic_enable(struct acpi_device *device,
/* check for total failure */
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR DRV_PFX "Error evaluating _SRS");
+ printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n");
result = -ENODEV;
goto end;
}
@@ -2268,11 +2329,14 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
- ev = inb_p(dev->cur_ioport->io.minimum);
- data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset);
+ ev = inb_p(dev->cur_ioport->io1.minimum);
+ if (dev->cur_ioport->io2.minimum)
+ data_mask = inb_p(dev->cur_ioport->io2.minimum);
+ else
+ data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset);
dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
- ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset);
+ ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset);
if (ev == 0x00 || ev == 0xff)
return IRQ_HANDLED;
@@ -2323,8 +2387,11 @@ static int sony_pic_remove(struct acpi_device *device, int type)
}
free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
- release_region(spic_dev.cur_ioport->io.minimum,
- spic_dev.cur_ioport->io.address_length);
+ release_region(spic_dev.cur_ioport->io1.minimum,
+ spic_dev.cur_ioport->io1.address_length);
+ if (spic_dev.cur_ioport->io2.minimum)
+ release_region(spic_dev.cur_ioport->io2.minimum,
+ spic_dev.cur_ioport->io2.address_length);
sonypi_compat_exit();
@@ -2397,14 +2464,36 @@ static int sony_pic_add(struct acpi_device *device)
goto err_remove_input;
/* request io port */
- list_for_each_entry(io, &spic_dev.ioports, list) {
- if (request_region(io->io.minimum, io->io.address_length,
+ list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
+ if (request_region(io->io1.minimum, io->io1.address_length,
"Sony Programable I/O Device")) {
- dprintk("I/O port: 0x%.4x (0x%.4x) + 0x%.2x\n",
- io->io.minimum, io->io.maximum,
- io->io.address_length);
- spic_dev.cur_ioport = io;
- break;
+ dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
+ io->io1.minimum, io->io1.maximum,
+ io->io1.address_length);
+ /* Type 1 have 2 ioports */
+ if (io->io2.minimum) {
+ if (request_region(io->io2.minimum,
+ io->io2.address_length,
+ "Sony Programable I/O Device")) {
+ dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
+ io->io2.minimum, io->io2.maximum,
+ io->io2.address_length);
+ spic_dev.cur_ioport = io;
+ break;
+ }
+ else {
+ dprintk("Unable to get I/O port2: "
+ "0x%.4x (0x%.4x) + 0x%.2x\n",
+ io->io2.minimum, io->io2.maximum,
+ io->io2.address_length);
+ release_region(io->io1.minimum,
+ io->io1.address_length);
+ }
+ }
+ else {
+ spic_dev.cur_ioport = io;
+ break;
+ }
}
}
if (!spic_dev.cur_ioport) {
@@ -2414,7 +2503,7 @@ static int sony_pic_add(struct acpi_device *device)
}
/* request IRQ */
- list_for_each_entry(irq, &spic_dev.interrupts, list) {
+ list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
IRQF_SHARED, "sony-laptop", &spic_dev)) {
dprintk("IRQ: %d - triggering: %d - "
@@ -2462,8 +2551,11 @@ err_free_irq:
free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
err_release_region:
- release_region(spic_dev.cur_ioport->io.minimum,
- spic_dev.cur_ioport->io.address_length);
+ release_region(spic_dev.cur_ioport->io1.minimum,
+ spic_dev.cur_ioport->io1.address_length);
+ if (spic_dev.cur_ioport->io2.minimum)
+ release_region(spic_dev.cur_ioport->io2.minimum,
+ spic_dev.cur_ioport->io2.address_length);
err_remove_compat:
sonypi_compat_exit();
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 0222bbaf7b7..e953276664a 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -22,7 +22,7 @@
*/
#define IBM_VERSION "0.16"
-#define TPACPI_SYSFS_VERSION 0x010000
+#define TPACPI_SYSFS_VERSION 0x020000
/*
* Changelog:
@@ -117,6 +117,12 @@ IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
#define __unused __attribute__ ((unused))
+static enum {
+ TPACPI_LIFE_INIT = 0,
+ TPACPI_LIFE_RUNNING,
+ TPACPI_LIFE_EXITING,
+} tpacpi_lifecycle;
+
/****************************************************************************
****************************************************************************
*
@@ -342,6 +348,9 @@ static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data)
{
struct ibm_struct *ibm = data;
+ if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
+ return;
+
if (!ibm || !ibm->acpi || !ibm->acpi->notify)
return;
@@ -517,8 +526,10 @@ static char *next_cmd(char **cmds)
****************************************************************************/
static struct platform_device *tpacpi_pdev;
-static struct class_device *tpacpi_hwmon;
+static struct platform_device *tpacpi_sensors_pdev;
+static struct device *tpacpi_hwmon;
static struct input_dev *tpacpi_inputdev;
+static struct mutex tpacpi_inputdev_send_mutex;
static int tpacpi_resume_handler(struct platform_device *pdev)
@@ -543,6 +554,12 @@ static struct platform_driver tpacpi_pdriver = {
.resume = tpacpi_resume_handler,
};
+static struct platform_driver tpacpi_hwmon_pdriver = {
+ .driver = {
+ .name = IBM_HWMON_DRVR_NAME,
+ .owner = THIS_MODULE,
+ },
+};
/*************************************************************************
* thinkpad-acpi driver attributes
@@ -692,6 +709,8 @@ static int parse_strtoul(const char *buf,
{
char *endp;
+ while (*buf && isspace(*buf))
+ buf++;
*value = simple_strtoul(buf, &endp, 0);
while (*endp && isspace(*endp))
endp++;
@@ -945,15 +964,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
KEY_UNKNOWN, /* 0x0D: FN+INSERT */
KEY_UNKNOWN, /* 0x0E: FN+DELETE */
- KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
+ KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */
/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
- KEY_RESERVED, /* 0x10: FN+END (brightness down) */
+ KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
- KEY_RESERVED, /* 0x14: VOLUME UP */
- KEY_RESERVED, /* 0x15: VOLUME DOWN */
- KEY_RESERVED, /* 0x16: MUTE */
+ KEY_VOLUMEUP, /* 0x14: VOLUME UP */
+ KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */
+ KEY_MUTE, /* 0x16: MUTE */
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
/* (assignments unknown, please report if found) */
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -974,9 +993,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
- KEY_RESERVED, /* 0x14: VOLUME UP */
- KEY_RESERVED, /* 0x15: VOLUME DOWN */
- KEY_RESERVED, /* 0x16: MUTE */
+ KEY_VOLUMEUP, /* 0x14: VOLUME UP */
+ KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */
+ KEY_MUTE, /* 0x16: MUTE */
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
/* (assignments unknown, please report if found) */
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
@@ -989,6 +1008,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
int res, i;
int status;
+ int hkeyv;
vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
@@ -1014,18 +1034,35 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
return res;
/* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
- A30, R30, R31, T20-22, X20-21, X22-24 */
- tp_features.hotkey_mask =
- acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
+ A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking
+ for HKEY interface version 0x100 */
+ if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {
+ if ((hkeyv >> 8) != 1) {
+ printk(IBM_ERR "unknown version of the "
+ "HKEY interface: 0x%x\n", hkeyv);
+ printk(IBM_ERR "please report this to %s\n",
+ IBM_MAIL);
+ } else {
+ /*
+ * MHKV 0x100 in A31, R40, R40e,
+ * T4x, X31, and later
+ * */
+ tp_features.hotkey_mask = 1;
+ }
+ }
vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
str_supported(tp_features.hotkey_mask));
if (tp_features.hotkey_mask) {
- /* MHKA available in A31, R40, R40e, T4x, X31, and later */
if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
- "MHKA", "qd"))
+ "MHKA", "qd")) {
+ printk(IBM_ERR
+ "missing MHKA handler, "
+ "please report this to %s\n",
+ IBM_MAIL);
hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
+ }
}
res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
@@ -1131,6 +1168,8 @@ static void tpacpi_input_send_key(unsigned int scancode,
unsigned int keycode)
{
if (keycode != KEY_RESERVED) {
+ mutex_lock(&tpacpi_inputdev_send_mutex);
+
input_report_key(tpacpi_inputdev, keycode, 1);
if (keycode == KEY_UNKNOWN)
input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
@@ -1142,6 +1181,8 @@ static void tpacpi_input_send_key(unsigned int scancode,
input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
scancode);
input_sync(tpacpi_inputdev);
+
+ mutex_unlock(&tpacpi_inputdev_send_mutex);
}
}
@@ -1149,18 +1190,47 @@ static void tpacpi_input_send_radiosw(void)
{
int wlsw;
- if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw))
+ mutex_lock(&tpacpi_inputdev_send_mutex);
+
+ if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
input_report_switch(tpacpi_inputdev,
SW_RADIO, !!wlsw);
+ input_sync(tpacpi_inputdev);
+ }
+
+ mutex_unlock(&tpacpi_inputdev_send_mutex);
}
static void hotkey_notify(struct ibm_struct *ibm, u32 event)
{
u32 hkey;
unsigned int keycode, scancode;
- int send_acpi_ev = 0;
+ int send_acpi_ev;
+ int ignore_acpi_ev;
+
+ if (event != 0x80) {
+ printk(IBM_ERR "unknown HKEY notification event %d\n", event);
+ /* forward it to userspace, maybe it knows how to handle it */
+ acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+ ibm->acpi->device->dev.bus_id,
+ event, 0);
+ return;
+ }
+
+ while (1) {
+ if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
+ printk(IBM_ERR "failed to retrieve HKEY event\n");
+ return;
+ }
+
+ if (hkey == 0) {
+ /* queue empty */
+ return;
+ }
+
+ send_acpi_ev = 0;
+ ignore_acpi_ev = 0;
- if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
switch (hkey >> 12) {
case 1:
/* 0x1000-0x1FFF: key presses */
@@ -1182,9 +1252,11 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
* eat up known LID events */
if (hkey != 0x5001 && hkey != 0x5002) {
printk(IBM_ERR
- "unknown LID-related hotkey event: 0x%04x\n",
- hkey);
+ "unknown LID-related HKEY event: 0x%04x\n",
+ hkey);
send_acpi_ev = 1;
+ } else {
+ ignore_acpi_ev = 1;
}
break;
case 7:
@@ -1202,21 +1274,18 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey);
send_acpi_ev = 1;
}
- } else {
- printk(IBM_ERR "unknown hotkey notification event %d\n", event);
- hkey = 0;
- send_acpi_ev = 1;
- }
- /* Legacy events */
- if (send_acpi_ev || hotkey_report_mode < 2)
- acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
+ /* Legacy events */
+ if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) {
+ acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
+ }
- /* netlink events */
- if (send_acpi_ev) {
- acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
- ibm->acpi->device->dev.bus_id,
- event, hkey);
+ /* netlink events */
+ if (!ignore_acpi_ev && send_acpi_ev) {
+ acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+ ibm->acpi->device->dev.bus_id,
+ event, hkey);
+ }
}
}
@@ -2812,7 +2881,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
switch(thermal_read_mode) {
case TPACPI_THERMAL_TPEC_16:
- res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
&thermal_temp_input16_group);
if (res)
return res;
@@ -2820,7 +2889,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
case TPACPI_THERMAL_TPEC_8:
case TPACPI_THERMAL_ACPI_TMP07:
case TPACPI_THERMAL_ACPI_UPDT:
- res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
&thermal_temp_input8_group);
if (res)
return res;
@@ -2837,13 +2906,13 @@ static void thermal_exit(void)
{
switch(thermal_read_mode) {
case TPACPI_THERMAL_TPEC_16:
- sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+ sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
&thermal_temp_input16_group);
break;
case TPACPI_THERMAL_TPEC_8:
case TPACPI_THERMAL_ACPI_TMP07:
case TPACPI_THERMAL_ACPI_UPDT:
- sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+ sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
&thermal_temp_input16_group);
break;
case TPACPI_THERMAL_NONE:
@@ -3626,7 +3695,7 @@ static struct device_attribute dev_attr_fan_fan1_input =
__ATTR(fan1_input, S_IRUGO,
fan_fan1_input_show, NULL);
-/* sysfs fan fan_watchdog (driver) ------------------------------------- */
+/* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */
static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
char *buf)
{
@@ -3768,10 +3837,10 @@ static int __init fan_init(struct ibm_init_struct *iibm)
if (fan_status_access_mode != TPACPI_FAN_NONE ||
fan_control_access_mode != TPACPI_FAN_WR_NONE) {
- rc = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,
&fan_attr_group);
if (!(rc < 0))
- rc = driver_create_file(&tpacpi_pdriver.driver,
+ rc = driver_create_file(&tpacpi_hwmon_pdriver.driver,
&driver_attr_fan_watchdog);
if (rc < 0)
return rc;
@@ -3854,8 +3923,8 @@ static void fan_exit(void)
vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n");
/* FIXME: can we really do this unconditionally? */
- sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group);
- driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog);
+ sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group);
+ driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog);
cancel_delayed_work(&fan_watchdog_task);
flush_scheduled_work();
@@ -3888,6 +3957,9 @@ static void fan_watchdog_fire(struct work_struct *ignored)
{
int rc;
+ if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING)
+ return;
+
printk(IBM_NOTICE "fan watchdog: enabling fan\n");
rc = fan_set_enable();
if (rc < 0) {
@@ -3908,7 +3980,8 @@ static void fan_watchdog_reset(void)
if (fan_watchdog_active)
cancel_delayed_work(&fan_watchdog_task);
- if (fan_watchdog_maxinterval > 0) {
+ if (fan_watchdog_maxinterval > 0 &&
+ tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
fan_watchdog_active = 1;
if (!schedule_delayed_work(&fan_watchdog_task,
msecs_to_jiffies(fan_watchdog_maxinterval
@@ -4302,6 +4375,19 @@ static struct ibm_struct fan_driver_data = {
****************************************************************************
****************************************************************************/
+/* sysfs name ---------------------------------------------------------- */
+static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME);
+}
+
+static struct device_attribute dev_attr_thinkpad_acpi_pdev_name =
+ __ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL);
+
+/* --------------------------------------------------------------------- */
+
/* /proc support */
static struct proc_dir_entry *proc_dir;
@@ -4448,7 +4534,7 @@ static void ibm_exit(struct ibm_struct *ibm)
static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
{
- struct dmi_device *dev = NULL;
+ const struct dmi_device *dev = NULL;
char ec_fw_string[18];
if (!tp)
@@ -4674,6 +4760,8 @@ static int __init thinkpad_acpi_module_init(void)
{
int ret, i;
+ tpacpi_lifecycle = TPACPI_LIFE_INIT;
+
/* Parameter checking */
if (hotkey_report_mode > 2)
return -EINVAL;
@@ -4702,19 +4790,31 @@ static int __init thinkpad_acpi_module_init(void)
ret = platform_driver_register(&tpacpi_pdriver);
if (ret) {
- printk(IBM_ERR "unable to register platform driver\n");
+ printk(IBM_ERR "unable to register main platform driver\n");
thinkpad_acpi_module_exit();
return ret;
}
tp_features.platform_drv_registered = 1;
+ ret = platform_driver_register(&tpacpi_hwmon_pdriver);
+ if (ret) {
+ printk(IBM_ERR "unable to register hwmon platform driver\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ tp_features.sensors_pdrv_registered = 1;
+
ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
+ if (!ret) {
+ tp_features.platform_drv_attrs_registered = 1;
+ ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_pdriver.driver);
+ }
if (ret) {
printk(IBM_ERR "unable to create sysfs driver attributes\n");
thinkpad_acpi_module_exit();
return ret;
}
- tp_features.platform_drv_attrs_registered = 1;
+ tp_features.sensors_pdrv_attrs_registered = 1;
/* Device initialization */
@@ -4727,7 +4827,26 @@ static int __init thinkpad_acpi_module_init(void)
thinkpad_acpi_module_exit();
return ret;
}
- tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev);
+ tpacpi_sensors_pdev = platform_device_register_simple(
+ IBM_HWMON_DRVR_NAME,
+ -1, NULL, 0);
+ if (IS_ERR(tpacpi_sensors_pdev)) {
+ ret = PTR_ERR(tpacpi_sensors_pdev);
+ tpacpi_sensors_pdev = NULL;
+ printk(IBM_ERR "unable to register hwmon platform device\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ ret = device_create_file(&tpacpi_sensors_pdev->dev,
+ &dev_attr_thinkpad_acpi_pdev_name);
+ if (ret) {
+ printk(IBM_ERR
+ "unable to create sysfs hwmon device attributes\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ tp_features.sensors_pdev_attrs_registered = 1;
+ tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev);
if (IS_ERR(tpacpi_hwmon)) {
ret = PTR_ERR(tpacpi_hwmon);
tpacpi_hwmon = NULL;
@@ -4735,6 +4854,7 @@ static int __init thinkpad_acpi_module_init(void)
thinkpad_acpi_module_exit();
return ret;
}
+ mutex_init(&tpacpi_inputdev_send_mutex);
tpacpi_inputdev = input_allocate_device();
if (!tpacpi_inputdev) {
printk(IBM_ERR "unable to allocate input device\n");
@@ -4769,6 +4889,7 @@ static int __init thinkpad_acpi_module_init(void)
tp_features.input_device_registered = 1;
}
+ tpacpi_lifecycle = TPACPI_LIFE_RUNNING;
return 0;
}
@@ -4776,6 +4897,8 @@ static void thinkpad_acpi_module_exit(void)
{
struct ibm_struct *ibm, *itmp;
+ tpacpi_lifecycle = TPACPI_LIFE_EXITING;
+
list_for_each_entry_safe_reverse(ibm, itmp,
&tpacpi_all_drivers,
all_drivers) {
@@ -4794,12 +4917,22 @@ static void thinkpad_acpi_module_exit(void)
if (tpacpi_hwmon)
hwmon_device_unregister(tpacpi_hwmon);
+ if (tp_features.sensors_pdev_attrs_registered)
+ device_remove_file(&tpacpi_sensors_pdev->dev,
+ &dev_attr_thinkpad_acpi_pdev_name);
+ if (tpacpi_sensors_pdev)
+ platform_device_unregister(tpacpi_sensors_pdev);
if (tpacpi_pdev)
platform_device_unregister(tpacpi_pdev);
+ if (tp_features.sensors_pdrv_attrs_registered)
+ tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver);
if (tp_features.platform_drv_attrs_registered)
tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
+ if (tp_features.sensors_pdrv_registered)
+ platform_driver_unregister(&tpacpi_hwmon_pdriver);
+
if (tp_features.platform_drv_registered)
platform_driver_unregister(&tpacpi_pdriver);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
index 082a1cbc16c..3abcc812063 100644
--- a/drivers/misc/thinkpad_acpi.h
+++ b/drivers/misc/thinkpad_acpi.h
@@ -58,13 +58,14 @@
#define IBM_NAME "thinkpad"
#define IBM_DESC "ThinkPad ACPI Extras"
-#define IBM_FILE "thinkpad_acpi"
+#define IBM_FILE IBM_NAME "_acpi"
#define IBM_URL "http://ibm-acpi.sf.net/"
#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net"
#define IBM_PROC_DIR "ibm"
#define IBM_ACPI_EVENT_PREFIX "ibm"
#define IBM_DRVR_NAME IBM_FILE
+#define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon"
#define IBM_LOG IBM_FILE ": "
#define IBM_ERR KERN_ERR IBM_LOG
@@ -171,7 +172,8 @@ static int parse_strtoul(const char *buf, unsigned long max,
/* Device model */
static struct platform_device *tpacpi_pdev;
-static struct class_device *tpacpi_hwmon;
+static struct platform_device *tpacpi_sensors_pdev;
+static struct device *tpacpi_hwmon;
static struct platform_driver tpacpi_pdriver;
static struct input_dev *tpacpi_inputdev;
static int tpacpi_create_driver_attributes(struct device_driver *drv);
@@ -233,22 +235,25 @@ struct ibm_init_struct {
static struct {
#ifdef CONFIG_THINKPAD_ACPI_BAY
- u16 bay_status:1;
- u16 bay_eject:1;
- u16 bay_status2:1;
- u16 bay_eject2:1;
+ u32 bay_status:1;
+ u32 bay_eject:1;
+ u32 bay_status2:1;
+ u32 bay_eject2:1;
#endif
- u16 bluetooth:1;
- u16 hotkey:1;
- u16 hotkey_mask:1;
- u16 hotkey_wlsw:1;
- u16 light:1;
- u16 light_status:1;
- u16 wan:1;
- u16 fan_ctrl_status_undef:1;
- u16 input_device_registered:1;
- u16 platform_drv_registered:1;
- u16 platform_drv_attrs_registered:1;
+ u32 bluetooth:1;
+ u32 hotkey:1;
+ u32 hotkey_mask:1;
+ u32 hotkey_wlsw:1;
+ u32 light:1;
+ u32 light_status:1;
+ u32 wan:1;
+ u32 fan_ctrl_status_undef:1;
+ u32 input_device_registered:1;
+ u32 platform_drv_registered:1;
+ u32 platform_drv_attrs_registered:1;
+ u32 sensors_pdrv_registered:1;
+ u32 sensors_pdrv_attrs_registered:1;
+ u32 sensors_pdev_attrs_registered:1;
} tp_features;
struct thinkpad_id_data {
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index d195fb088f4..8f77949f93d 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -57,16 +57,11 @@ static int tifm_bus_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static int tifm_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
- int i = 0;
- int length = 0;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "TIFM_CARD_TYPE=%s",
- tifm_media_type_name(sock->type, 1)))
+ if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1)))
return -ENOMEM;
return 0;
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index a49cb9737cd..aa8a4e46194 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -32,3 +32,10 @@ config MMC_BLOCK_BOUNCE
If unsure, say Y here.
+config SDIO_UART
+ tristate "SDIO UART/GPS class support"
+ depends on MMC
+ help
+ SDIO function driver for SDIO cards that implements the UART
+ class, as well as the GPS class which appears like a UART.
+
diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile
index cf8c939867f..fc5a784cfa1 100644
--- a/drivers/mmc/card/Makefile
+++ b/drivers/mmc/card/Makefile
@@ -9,3 +9,5 @@ endif
obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
mmc_block-objs := block.o queue.o
+obj-$(CONFIG_SDIO_UART) += sdio_uart.o
+
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 93fe2e5dd61..e38d5a3b2a8 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -151,17 +151,19 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
cmd.opcode = MMC_APP_CMD;
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD))
+ if (err)
+ return (u32)-1;
+ if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
return (u32)-1;
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
memset(&data, 0, sizeof(struct mmc_data));
@@ -192,7 +194,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
mmc_wait_for_req(card->host, &mrq);
- if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE)
+ if (cmd.error || data.error)
return (u32)-1;
blocks = ntohl(blocks);
@@ -220,17 +222,15 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.cmd.arg = req->sector;
if (!mmc_card_blockaddr(card))
brq.cmd.arg <<= 9;
- brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
brq.data.blksz = 1 << md->block_bits;
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
- brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
if (brq.data.blocks > card->host->max_blk_count)
brq.data.blocks = card->host->max_blk_count;
- mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
-
/*
* If the host doesn't support multiple block writes, force
* block writes to single block. SD cards are excepted from
@@ -243,8 +243,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.data.blocks = 1;
if (brq.data.blocks > 1) {
- brq.data.flags |= MMC_DATA_MULTI;
- brq.mrq.stop = &brq.stop;
+ /* SPI multiblock writes terminate using a special
+ * token, not a STOP_TRANSMISSION request.
+ */
+ if (!mmc_host_is_spi(card->host)
+ || rq_data_dir(req) == READ)
+ brq.mrq.stop = &brq.stop;
readcmd = MMC_READ_MULTIPLE_BLOCK;
writecmd = MMC_WRITE_MULTIPLE_BLOCK;
} else {
@@ -261,6 +265,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.data.flags |= MMC_DATA_WRITE;
}
+ mmc_set_data_timeout(&brq.data, card);
+
brq.data.sg = mq->sg;
brq.data.sg_len = mmc_queue_map_sg(mq);
@@ -302,7 +308,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
goto cmd_err;
}
- if (rq_data_dir(req) != READ) {
+ if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
do {
int err;
@@ -510,7 +516,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
mmc_claim_host(card->host);
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = 1 << md->block_bits;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
mmc_release_host(card->host);
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index b0abc7d9280..1b9c9b6da5b 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -13,6 +13,7 @@
#include <linux/blkdev.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
+#include <linux/scatterlist.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -159,6 +160,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
ret = -ENOMEM;
goto cleanup_queue;
}
+ sg_init_table(mq->sg, 1);
mq->bounce_sg = kmalloc(sizeof(struct scatterlist) *
bouncesz / 512, GFP_KERNEL);
@@ -166,6 +168,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
ret = -ENOMEM;
goto cleanup_queue;
}
+ sg_init_table(mq->bounce_sg, bouncesz / 512);
}
}
#endif
@@ -177,7 +180,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
- mq->sg = kmalloc(sizeof(struct scatterlist) *
+ mq->sg = kzalloc(sizeof(struct scatterlist) *
host->max_phys_segs, GFP_KERNEL);
if (!mq->sg) {
ret = -ENOMEM;
@@ -302,12 +305,12 @@ static void copy_sg(struct scatterlist *dst, unsigned int dst_len,
BUG_ON(dst_len == 0);
if (dst_size == 0) {
- dst_buf = page_address(dst->page) + dst->offset;
+ dst_buf = sg_virt(dst);
dst_size = dst->length;
}
if (src_size == 0) {
- src_buf = page_address(src->page) + src->offset;
+ src_buf = sg_virt(src);
src_size = src->length;
}
@@ -353,9 +356,7 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
return 1;
}
- mq->sg[0].page = virt_to_page(mq->bounce_buf);
- mq->sg[0].offset = offset_in_page(mq->bounce_buf);
- mq->sg[0].length = 0;
+ sg_init_one(mq->sg, mq->bounce_buf, 0);
while (sg_len) {
mq->sg[0].length += mq->bounce_sg[sg_len - 1].length;
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
new file mode 100644
index 00000000000..d552de68311
--- /dev/null
+++ b/drivers/mmc/card/sdio_uart.c
@@ -0,0 +1,1158 @@
+/*
+ * linux/drivers/mmc/card/sdio_uart.c - SDIO UART/GPS driver
+ *
+ * Based on drivers/serial/8250.c and drivers/serial/serial_core.c
+ * by Russell King.
+ *
+ * Author: Nicolas Pitre
+ * Created: June 15, 2007
+ * Copyright: MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+/*
+ * Note: Although this driver assumes a 16550A-like UART implementation,
+ * it is not possible to leverage the common 8250/16550 driver, nor the
+ * core UART infrastructure, as they assumes direct access to the hardware
+ * registers, often under a spinlock. This is not possible in the SDIO
+ * context as SDIO access functions must be able to sleep.
+ *
+ * Because we need to lock the SDIO host to ensure an exclusive access to
+ * the card, we simply rely on that lock to also prevent and serialize
+ * concurrent access to the same port.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/serial_reg.h>
+#include <linux/circ_buf.h>
+#include <linux/gfp.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+
+#define UART_NR 8 /* Number of UARTs this driver can handle */
+
+
+#define UART_XMIT_SIZE PAGE_SIZE
+#define WAKEUP_CHARS 256
+
+#define circ_empty(circ) ((circ)->head == (circ)->tail)
+#define circ_clear(circ) ((circ)->head = (circ)->tail = 0)
+
+#define circ_chars_pending(circ) \
+ (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE))
+
+#define circ_chars_free(circ) \
+ (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))
+
+
+struct uart_icount {
+ __u32 cts;
+ __u32 dsr;
+ __u32 rng;
+ __u32 dcd;
+ __u32 rx;
+ __u32 tx;
+ __u32 frame;
+ __u32 overrun;
+ __u32 parity;
+ __u32 brk;
+};
+
+struct sdio_uart_port {
+ struct kref kref;
+ struct tty_struct *tty;
+ unsigned int index;
+ unsigned int opened;
+ struct mutex open_lock;
+ struct sdio_func *func;
+ struct mutex func_lock;
+ struct task_struct *in_sdio_uart_irq;
+ unsigned int regs_offset;
+ struct circ_buf xmit;
+ spinlock_t write_lock;
+ struct uart_icount icount;
+ unsigned int uartclk;
+ unsigned int mctrl;
+ unsigned int read_status_mask;
+ unsigned int ignore_status_mask;
+ unsigned char x_char;
+ unsigned char ier;
+ unsigned char lcr;
+};
+
+static struct sdio_uart_port *sdio_uart_table[UART_NR];
+static DEFINE_SPINLOCK(sdio_uart_table_lock);
+
+static int sdio_uart_add_port(struct sdio_uart_port *port)
+{
+ int index, ret = -EBUSY;
+
+ kref_init(&port->kref);
+ mutex_init(&port->open_lock);
+ mutex_init(&port->func_lock);
+ spin_lock_init(&port->write_lock);
+
+ spin_lock(&sdio_uart_table_lock);
+ for (index = 0; index < UART_NR; index++) {
+ if (!sdio_uart_table[index]) {
+ port->index = index;
+ sdio_uart_table[index] = port;
+ ret = 0;
+ break;
+ }
+ }
+ spin_unlock(&sdio_uart_table_lock);
+
+ return ret;
+}
+
+static struct sdio_uart_port *sdio_uart_port_get(unsigned index)
+{
+ struct sdio_uart_port *port;
+
+ if (index >= UART_NR)
+ return NULL;
+
+ spin_lock(&sdio_uart_table_lock);
+ port = sdio_uart_table[index];
+ if (port)
+ kref_get(&port->kref);
+ spin_unlock(&sdio_uart_table_lock);
+
+ return port;
+}
+
+static void sdio_uart_port_destroy(struct kref *kref)
+{
+ struct sdio_uart_port *port =
+ container_of(kref, struct sdio_uart_port, kref);
+ kfree(port);
+}
+
+static void sdio_uart_port_put(struct sdio_uart_port *port)
+{
+ kref_put(&port->kref, sdio_uart_port_destroy);
+}
+
+static void sdio_uart_port_remove(struct sdio_uart_port *port)
+{
+ struct sdio_func *func;
+
+ BUG_ON(sdio_uart_table[port->index] != port);
+
+ spin_lock(&sdio_uart_table_lock);
+ sdio_uart_table[port->index] = NULL;
+ spin_unlock(&sdio_uart_table_lock);
+
+ /*
+ * We're killing a port that potentially still is in use by
+ * the tty layer. Be careful to prevent any further access
+ * to the SDIO function and arrange for the tty layer to
+ * give up on that port ASAP.
+ * Beware: the lock ordering is critical.
+ */
+ mutex_lock(&port->open_lock);
+ mutex_lock(&port->func_lock);
+ func = port->func;
+ sdio_claim_host(func);
+ port->func = NULL;
+ mutex_unlock(&port->func_lock);
+ if (port->opened)
+ tty_hangup(port->tty);
+ mutex_unlock(&port->open_lock);
+ sdio_release_irq(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+
+ sdio_uart_port_put(port);
+}
+
+static int sdio_uart_claim_func(struct sdio_uart_port *port)
+{
+ mutex_lock(&port->func_lock);
+ if (unlikely(!port->func)) {
+ mutex_unlock(&port->func_lock);
+ return -ENODEV;
+ }
+ if (likely(port->in_sdio_uart_irq != current))
+ sdio_claim_host(port->func);
+ mutex_unlock(&port->func_lock);
+ return 0;
+}
+
+static inline void sdio_uart_release_func(struct sdio_uart_port *port)
+{
+ if (likely(port->in_sdio_uart_irq != current))
+ sdio_release_host(port->func);
+}
+
+static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset)
+{
+ unsigned char c;
+ c = sdio_readb(port->func, port->regs_offset + offset, NULL);
+ return c;
+}
+
+static inline void sdio_out(struct sdio_uart_port *port, int offset, int value)
+{
+ sdio_writeb(port->func, value, port->regs_offset + offset, NULL);
+}
+
+static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
+{
+ unsigned char status;
+ unsigned int ret;
+
+ status = sdio_in(port, UART_MSR);
+
+ ret = 0;
+ if (status & UART_MSR_DCD)
+ ret |= TIOCM_CAR;
+ if (status & UART_MSR_RI)
+ ret |= TIOCM_RNG;
+ if (status & UART_MSR_DSR)
+ ret |= TIOCM_DSR;
+ if (status & UART_MSR_CTS)
+ ret |= TIOCM_CTS;
+ return ret;
+}
+
+static void sdio_uart_write_mctrl(struct sdio_uart_port *port, unsigned int mctrl)
+{
+ unsigned char mcr = 0;
+
+ if (mctrl & TIOCM_RTS)
+ mcr |= UART_MCR_RTS;
+ if (mctrl & TIOCM_DTR)
+ mcr |= UART_MCR_DTR;
+ if (mctrl & TIOCM_OUT1)
+ mcr |= UART_MCR_OUT1;
+ if (mctrl & TIOCM_OUT2)
+ mcr |= UART_MCR_OUT2;
+ if (mctrl & TIOCM_LOOP)
+ mcr |= UART_MCR_LOOP;
+
+ sdio_out(port, UART_MCR, mcr);
+}
+
+static inline void sdio_uart_update_mctrl(struct sdio_uart_port *port,
+ unsigned int set, unsigned int clear)
+{
+ unsigned int old;
+
+ old = port->mctrl;
+ port->mctrl = (old & ~clear) | set;
+ if (old != port->mctrl)
+ sdio_uart_write_mctrl(port, port->mctrl);
+}
+
+#define sdio_uart_set_mctrl(port, x) sdio_uart_update_mctrl(port, x, 0)
+#define sdio_uart_clear_mctrl(port, x) sdio_uart_update_mctrl(port, 0, x)
+
+static void sdio_uart_change_speed(struct sdio_uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned char cval, fcr = 0;
+ unsigned int baud, quot;
+
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ cval = UART_LCR_WLEN5;
+ break;
+ case CS6:
+ cval = UART_LCR_WLEN6;
+ break;
+ case CS7:
+ cval = UART_LCR_WLEN7;
+ break;
+ default:
+ case CS8:
+ cval = UART_LCR_WLEN8;
+ break;
+ }
+
+ if (termios->c_cflag & CSTOPB)
+ cval |= UART_LCR_STOP;
+ if (termios->c_cflag & PARENB)
+ cval |= UART_LCR_PARITY;
+ if (!(termios->c_cflag & PARODD))
+ cval |= UART_LCR_EPAR;
+
+ for (;;) {
+ baud = tty_termios_baud_rate(termios);
+ if (baud == 0)
+ baud = 9600; /* Special case: B0 rate. */
+ if (baud <= port->uartclk)
+ break;
+ /*
+ * Oops, the quotient was zero. Try again with the old
+ * baud rate if possible, otherwise default to 9600.
+ */
+ termios->c_cflag &= ~CBAUD;
+ if (old) {
+ termios->c_cflag |= old->c_cflag & CBAUD;
+ old = NULL;
+ } else
+ termios->c_cflag |= B9600;
+ }
+ quot = (2 * port->uartclk + baud) / (2 * baud);
+
+ if (baud < 2400)
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+ else
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
+
+ port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= UART_LSR_BI;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= UART_LSR_BI;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= UART_LSR_OE;
+ }
+
+ /*
+ * ignore all characters if CREAD is not set
+ */
+ if ((termios->c_cflag & CREAD) == 0)
+ port->ignore_status_mask |= UART_LSR_DR;
+
+ /*
+ * CTS flow control flag and modem status interrupts
+ */
+ port->ier &= ~UART_IER_MSI;
+ if ((termios->c_cflag & CRTSCTS) || !(termios->c_cflag & CLOCAL))
+ port->ier |= UART_IER_MSI;
+
+ port->lcr = cval;
+
+ sdio_out(port, UART_IER, port->ier);
+ sdio_out(port, UART_LCR, cval | UART_LCR_DLAB);
+ sdio_out(port, UART_DLL, quot & 0xff);
+ sdio_out(port, UART_DLM, quot >> 8);
+ sdio_out(port, UART_LCR, cval);
+ sdio_out(port, UART_FCR, fcr);
+
+ sdio_uart_write_mctrl(port, port->mctrl);
+}
+
+static void sdio_uart_start_tx(struct sdio_uart_port *port)
+{
+ if (!(port->ier & UART_IER_THRI)) {
+ port->ier |= UART_IER_THRI;
+ sdio_out(port, UART_IER, port->ier);
+ }
+}
+
+static void sdio_uart_stop_tx(struct sdio_uart_port *port)
+{
+ if (port->ier & UART_IER_THRI) {
+ port->ier &= ~UART_IER_THRI;
+ sdio_out(port, UART_IER, port->ier);
+ }
+}
+
+static void sdio_uart_stop_rx(struct sdio_uart_port *port)
+{
+ port->ier &= ~UART_IER_RLSI;
+ port->read_status_mask &= ~UART_LSR_DR;
+ sdio_out(port, UART_IER, port->ier);
+}
+
+static void sdio_uart_receive_chars(struct sdio_uart_port *port, int *status)
+{
+ struct tty_struct *tty = port->tty;
+ unsigned int ch, flag;
+ int max_count = 256;
+
+ do {
+ ch = sdio_in(port, UART_RX);
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+ UART_LSR_FE | UART_LSR_OE))) {
+ /*
+ * For statistics only
+ */
+ if (*status & UART_LSR_BI) {
+ *status &= ~(UART_LSR_FE | UART_LSR_PE);
+ port->icount.brk++;
+ } else if (*status & UART_LSR_PE)
+ port->icount.parity++;
+ else if (*status & UART_LSR_FE)
+ port->icount.frame++;
+ if (*status & UART_LSR_OE)
+ port->icount.overrun++;
+
+ /*
+ * Mask off conditions which should be ignored.
+ */
+ *status &= port->read_status_mask;
+ if (*status & UART_LSR_BI) {
+ flag = TTY_BREAK;
+ } else if (*status & UART_LSR_PE)
+ flag = TTY_PARITY;
+ else if (*status & UART_LSR_FE)
+ flag = TTY_FRAME;
+ }
+
+ if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
+ tty_insert_flip_char(tty, ch, flag);
+
+ /*
+ * Overrun is special. Since it's reported immediately,
+ * it doesn't affect the current character.
+ */
+ if (*status & ~port->ignore_status_mask & UART_LSR_OE)
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+ *status = sdio_in(port, UART_LSR);
+ } while ((*status & UART_LSR_DR) && (max_count-- > 0));
+ tty_flip_buffer_push(tty);
+}
+
+static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
+{
+ struct circ_buf *xmit = &port->xmit;
+ int count;
+
+ if (port->x_char) {
+ sdio_out(port, UART_TX, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+ if (circ_empty(xmit) || port->tty->stopped || port->tty->hw_stopped) {
+ sdio_uart_stop_tx(port);
+ return;
+ }
+
+ count = 16;
+ do {
+ sdio_out(port, UART_TX, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if (circ_empty(xmit))
+ break;
+ } while (--count > 0);
+
+ if (circ_chars_pending(xmit) < WAKEUP_CHARS)
+ tty_wakeup(port->tty);
+
+ if (circ_empty(xmit))
+ sdio_uart_stop_tx(port);
+}
+
+static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
+{
+ int status;
+
+ status = sdio_in(port, UART_MSR);
+
+ if ((status & UART_MSR_ANY_DELTA) == 0)
+ return;
+
+ if (status & UART_MSR_TERI)
+ port->icount.rng++;
+ if (status & UART_MSR_DDSR)
+ port->icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ port->icount.dcd++;
+ if (status & UART_MSR_DCTS) {
+ port->icount.cts++;
+ if (port->tty->termios->c_cflag & CRTSCTS) {
+ int cts = (status & UART_MSR_CTS);
+ if (port->tty->hw_stopped) {
+ if (cts) {
+ port->tty->hw_stopped = 0;
+ sdio_uart_start_tx(port);
+ tty_wakeup(port->tty);
+ }
+ } else {
+ if (!cts) {
+ port->tty->hw_stopped = 1;
+ sdio_uart_stop_tx(port);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static void sdio_uart_irq(struct sdio_func *func)
+{
+ struct sdio_uart_port *port = sdio_get_drvdata(func);
+ unsigned int iir, lsr;
+
+ /*
+ * In a few places sdio_uart_irq() is called directly instead of
+ * waiting for the actual interrupt to be raised and the SDIO IRQ
+ * thread scheduled in order to reduce latency. However, some
+ * interaction with the tty core may end up calling us back
+ * (serial echo, flow control, etc.) through those same places
+ * causing undesirable effects. Let's stop the recursion here.
+ */
+ if (unlikely(port->in_sdio_uart_irq == current))
+ return;
+
+ iir = sdio_in(port, UART_IIR);
+ if (iir & UART_IIR_NO_INT)
+ return;
+
+ port->in_sdio_uart_irq = current;
+ lsr = sdio_in(port, UART_LSR);
+ if (lsr & UART_LSR_DR)
+ sdio_uart_receive_chars(port, &lsr);
+ sdio_uart_check_modem_status(port);
+ if (lsr & UART_LSR_THRE)
+ sdio_uart_transmit_chars(port);
+ port->in_sdio_uart_irq = NULL;
+}
+
+static int sdio_uart_startup(struct sdio_uart_port *port)
+{
+ unsigned long page;
+ int ret;
+
+ /*
+ * Set the TTY IO error marker - we will only clear this
+ * once we have successfully opened the port.
+ */
+ set_bit(TTY_IO_ERROR, &port->tty->flags);
+
+ /* Initialise and allocate the transmit buffer. */
+ page = __get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+ port->xmit.buf = (unsigned char *)page;
+ circ_clear(&port->xmit);
+
+ ret = sdio_uart_claim_func(port);
+ if (ret)
+ goto err1;
+ ret = sdio_enable_func(port->func);
+ if (ret)
+ goto err2;
+ ret = sdio_claim_irq(port->func, sdio_uart_irq);
+ if (ret)
+ goto err3;
+
+ /*
+ * Clear the FIFO buffers and disable them.
+ * (they will be reenabled in sdio_change_speed())
+ */
+ sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO);
+ sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+ sdio_out(port, UART_FCR, 0);
+
+ /*
+ * Clear the interrupt registers.
+ */
+ (void) sdio_in(port, UART_LSR);
+ (void) sdio_in(port, UART_RX);
+ (void) sdio_in(port, UART_IIR);
+ (void) sdio_in(port, UART_MSR);
+
+ /*
+ * Now, initialize the UART
+ */
+ sdio_out(port, UART_LCR, UART_LCR_WLEN8);
+
+ port->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
+ port->mctrl = TIOCM_OUT2;
+
+ sdio_uart_change_speed(port, port->tty->termios, NULL);
+
+ if (port->tty->termios->c_cflag & CBAUD)
+ sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
+
+ if (port->tty->termios->c_cflag & CRTSCTS)
+ if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
+ port->tty->hw_stopped = 1;
+
+ clear_bit(TTY_IO_ERROR, &port->tty->flags);
+
+ /* Kick the IRQ handler once while we're still holding the host lock */
+ sdio_uart_irq(port->func);
+
+ sdio_uart_release_func(port);
+ return 0;
+
+err3:
+ sdio_disable_func(port->func);
+err2:
+ sdio_uart_release_func(port);
+err1:
+ free_page((unsigned long)port->xmit.buf);
+ return ret;
+}
+
+static void sdio_uart_shutdown(struct sdio_uart_port *port)
+{
+ int ret;
+
+ ret = sdio_uart_claim_func(port);
+ if (ret)
+ goto skip;
+
+ sdio_uart_stop_rx(port);
+
+ /* TODO: wait here for TX FIFO to drain */
+
+ /* Turn off DTR and RTS early. */
+ if (port->tty->termios->c_cflag & HUPCL)
+ sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+
+ /* Disable interrupts from this port */
+ sdio_release_irq(port->func);
+ port->ier = 0;
+ sdio_out(port, UART_IER, 0);
+
+ sdio_uart_clear_mctrl(port, TIOCM_OUT2);
+
+ /* Disable break condition and FIFOs. */
+ port->lcr &= ~UART_LCR_SBC;
+ sdio_out(port, UART_LCR, port->lcr);
+ sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT);
+ sdio_out(port, UART_FCR, 0);
+
+ sdio_disable_func(port->func);
+
+ sdio_uart_release_func(port);
+
+skip:
+ /* Free the transmit buffer page. */
+ free_page((unsigned long)port->xmit.buf);
+}
+
+static int sdio_uart_open (struct tty_struct *tty, struct file * filp)
+{
+ struct sdio_uart_port *port;
+ int ret;
+
+ port = sdio_uart_port_get(tty->index);
+ if (!port)
+ return -ENODEV;
+
+ mutex_lock(&port->open_lock);
+
+ /*
+ * Make sure not to mess up with a dead port
+ * which has not been closed yet.
+ */
+ if (tty->driver_data && tty->driver_data != port) {
+ mutex_unlock(&port->open_lock);
+ sdio_uart_port_put(port);
+ return -EBUSY;
+ }
+
+ if (!port->opened) {
+ tty->driver_data = port;
+ port->tty = tty;
+ ret = sdio_uart_startup(port);
+ if (ret) {
+ tty->driver_data = NULL;
+ port->tty = NULL;
+ mutex_unlock(&port->open_lock);
+ sdio_uart_port_put(port);
+ return ret;
+ }
+ }
+ port->opened++;
+ mutex_unlock(&port->open_lock);
+ return 0;
+}
+
+static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+
+ if (!port)
+ return;
+
+ mutex_lock(&port->open_lock);
+ BUG_ON(!port->opened);
+
+ /*
+ * This is messy. The tty layer calls us even when open()
+ * returned an error. Ignore this close request if tty->count
+ * is larger than port->count.
+ */
+ if (tty->count > port->opened) {
+ mutex_unlock(&port->open_lock);
+ return;
+ }
+
+ if (--port->opened == 0) {
+ tty->closing = 1;
+ sdio_uart_shutdown(port);
+ tty_ldisc_flush(tty);
+ port->tty = NULL;
+ tty->driver_data = NULL;
+ tty->closing = 0;
+ }
+ mutex_unlock(&port->open_lock);
+ sdio_uart_port_put(port);
+}
+
+static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
+ int count)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+ struct circ_buf *circ = &port->xmit;
+ int c, ret = 0;
+
+ if (!port->func)
+ return -ENODEV;
+
+ spin_lock(&port->write_lock);
+ while (1) {
+ c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+ memcpy(circ->buf + circ->head, buf, c);
+ circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ spin_unlock(&port->write_lock);
+
+ if ( !(port->ier & UART_IER_THRI)) {
+ int err = sdio_uart_claim_func(port);
+ if (!err) {
+ sdio_uart_start_tx(port);
+ sdio_uart_irq(port->func);
+ sdio_uart_release_func(port);
+ } else
+ ret = err;
+ }
+
+ return ret;
+}
+
+static int sdio_uart_write_room(struct tty_struct *tty)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+ return port ? circ_chars_free(&port->xmit) : 0;
+}
+
+static int sdio_uart_chars_in_buffer(struct tty_struct *tty)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+ return port ? circ_chars_pending(&port->xmit) : 0;
+}
+
+static void sdio_uart_send_xchar(struct tty_struct *tty, char ch)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+
+ port->x_char = ch;
+ if (ch && !(port->ier & UART_IER_THRI)) {
+ if (sdio_uart_claim_func(port) != 0)
+ return;
+ sdio_uart_start_tx(port);
+ sdio_uart_irq(port->func);
+ sdio_uart_release_func(port);
+ }
+}
+
+static void sdio_uart_throttle(struct tty_struct *tty)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+
+ if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
+ return;
+
+ if (sdio_uart_claim_func(port) != 0)
+ return;
+
+ if (I_IXOFF(tty)) {
+ port->x_char = STOP_CHAR(tty);
+ sdio_uart_start_tx(port);
+ }
+
+ if (tty->termios->c_cflag & CRTSCTS)
+ sdio_uart_clear_mctrl(port, TIOCM_RTS);
+
+ sdio_uart_irq(port->func);
+ sdio_uart_release_func(port);
+}
+
+static void sdio_uart_unthrottle(struct tty_struct *tty)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+
+ if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
+ return;
+
+ if (sdio_uart_claim_func(port) != 0)
+ return;
+
+ if (I_IXOFF(tty)) {
+ if (port->x_char) {
+ port->x_char = 0;
+ } else {
+ port->x_char = START_CHAR(tty);
+ sdio_uart_start_tx(port);
+ }
+ }
+
+ if (tty->termios->c_cflag & CRTSCTS)
+ sdio_uart_set_mctrl(port, TIOCM_RTS);
+
+ sdio_uart_irq(port->func);
+ sdio_uart_release_func(port);
+}
+
+static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+ unsigned int cflag = tty->termios->c_cflag;
+
+#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+ if ((cflag ^ old_termios->c_cflag) == 0 &&
+ RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
+ return;
+
+ if (sdio_uart_claim_func(port) != 0)
+ return;
+
+ sdio_uart_change_speed(port, tty->termios, old_termios);
+
+ /* Handle transition to B0 status */
+ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
+ sdio_uart_clear_mctrl(port, TIOCM_RTS | TIOCM_DTR);
+
+ /* Handle transition away from B0 status */
+ if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+ unsigned int mask = TIOCM_DTR;
+ if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags))
+ mask |= TIOCM_RTS;
+ sdio_uart_set_mctrl(port, mask);
+ }
+
+ /* Handle turning off CRTSCTS */
+ if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ sdio_uart_start_tx(port);
+ }
+
+ /* Handle turning on CRTSCTS */
+ if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
+ if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) {
+ tty->hw_stopped = 1;
+ sdio_uart_stop_tx(port);
+ }
+ }
+
+ sdio_uart_release_func(port);
+}
+
+static void sdio_uart_break_ctl(struct tty_struct *tty, int break_state)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+
+ if (sdio_uart_claim_func(port) != 0)
+ return;
+
+ if (break_state == -1)
+ port->lcr |= UART_LCR_SBC;
+ else
+ port->lcr &= ~UART_LCR_SBC;
+ sdio_out(port, UART_LCR, port->lcr);
+
+ sdio_uart_release_func(port);
+}
+
+static int sdio_uart_tiocmget(struct tty_struct *tty, struct file *file)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+ int result;
+
+ result = sdio_uart_claim_func(port);
+ if (!result) {
+ result = port->mctrl | sdio_uart_get_mctrl(port);
+ sdio_uart_release_func(port);
+ }
+
+ return result;
+}
+
+static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct sdio_uart_port *port = tty->driver_data;
+ int result;
+
+ result =sdio_uart_claim_func(port);
+ if(!result) {
+ sdio_uart_update_mctrl(port, set, clear);
+ sdio_uart_release_func(port);
+ }
+
+ return result;
+}
+
+static int sdio_uart_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int i, len = 0;
+ off_t begin = 0;
+
+ len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n",
+ "", "", "");
+ for (i = 0; i < UART_NR && len < PAGE_SIZE - 96; i++) {
+ struct sdio_uart_port *port = sdio_uart_port_get(i);
+ if (port) {
+ len += sprintf(page+len, "%d: uart:SDIO", i);
+ if(capable(CAP_SYS_ADMIN)) {
+ len += sprintf(page + len, " tx:%d rx:%d",
+ port->icount.tx, port->icount.rx);
+ if (port->icount.frame)
+ len += sprintf(page + len, " fe:%d",
+ port->icount.frame);
+ if (port->icount.parity)
+ len += sprintf(page + len, " pe:%d",
+ port->icount.parity);
+ if (port->icount.brk)
+ len += sprintf(page + len, " brk:%d",
+ port->icount.brk);
+ if (port->icount.overrun)
+ len += sprintf(page + len, " oe:%d",
+ port->icount.overrun);
+ if (port->icount.cts)
+ len += sprintf(page + len, " cts:%d",
+ port->icount.cts);
+ if (port->icount.dsr)
+ len += sprintf(page + len, " dsr:%d",
+ port->icount.dsr);
+ if (port->icount.rng)
+ len += sprintf(page + len, " rng:%d",
+ port->icount.rng);
+ if (port->icount.dcd)
+ len += sprintf(page + len, " dcd:%d",
+ port->icount.dcd);
+ }
+ strcat(page, "\n");
+ len++;
+ sdio_uart_port_put(port);
+ }
+
+ if (len + begin > off + count)
+ goto done;
+ if (len + begin < off) {
+ begin += len;
+ len = 0;
+ }
+ }
+ *eof = 1;
+
+done:
+ if (off >= len + begin)
+ return 0;
+ *start = page + (off - begin);
+ return (count < begin + len - off) ? count : (begin + len - off);
+}
+
+static const struct tty_operations sdio_uart_ops = {
+ .open = sdio_uart_open,
+ .close = sdio_uart_close,
+ .write = sdio_uart_write,
+ .write_room = sdio_uart_write_room,
+ .chars_in_buffer = sdio_uart_chars_in_buffer,
+ .send_xchar = sdio_uart_send_xchar,
+ .throttle = sdio_uart_throttle,
+ .unthrottle = sdio_uart_unthrottle,
+ .set_termios = sdio_uart_set_termios,
+ .break_ctl = sdio_uart_break_ctl,
+ .tiocmget = sdio_uart_tiocmget,
+ .tiocmset = sdio_uart_tiocmset,
+ .read_proc = sdio_uart_read_proc,
+};
+
+static struct tty_driver *sdio_uart_tty_driver;
+
+static int sdio_uart_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ struct sdio_uart_port *port;
+ int ret;
+
+ port = kzalloc(sizeof(struct sdio_uart_port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ if (func->class == SDIO_CLASS_UART) {
+ printk(KERN_WARNING "%s: need info on UART class basic setup\n",
+ sdio_func_id(func));
+ kfree(port);
+ return -ENOSYS;
+ } else if (func->class == SDIO_CLASS_GPS) {
+ /*
+ * We need tuple 0x91. It contains SUBTPL_SIOREG
+ * and SUBTPL_RCVCAPS.
+ */
+ struct sdio_func_tuple *tpl;
+ for (tpl = func->tuples; tpl; tpl = tpl->next) {
+ if (tpl->code != 0x91)
+ continue;
+ if (tpl->size < 10)
+ continue;
+ if (tpl->data[1] == 0) /* SUBTPL_SIOREG */
+ break;
+ }
+ if (!tpl) {
+ printk(KERN_WARNING
+ "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
+ sdio_func_id(func));
+ kfree(port);
+ return -EINVAL;
+ }
+ printk(KERN_DEBUG "%s: Register ID = 0x%02x, Exp ID = 0x%02x\n",
+ sdio_func_id(func), tpl->data[2], tpl->data[3]);
+ port->regs_offset = (tpl->data[4] << 0) |
+ (tpl->data[5] << 8) |
+ (tpl->data[6] << 16);
+ printk(KERN_DEBUG "%s: regs offset = 0x%x\n",
+ sdio_func_id(func), port->regs_offset);
+ port->uartclk = tpl->data[7] * 115200;
+ if (port->uartclk == 0)
+ port->uartclk = 115200;
+ printk(KERN_DEBUG "%s: clk %d baudcode %u 4800-div %u\n",
+ sdio_func_id(func), port->uartclk,
+ tpl->data[7], tpl->data[8] | (tpl->data[9] << 8));
+ } else {
+ kfree(port);
+ return -EINVAL;
+ }
+
+ port->func = func;
+ sdio_set_drvdata(func, port);
+
+ ret = sdio_uart_add_port(port);
+ if (ret) {
+ kfree(port);
+ } else {
+ struct device *dev;
+ dev = tty_register_device(sdio_uart_tty_driver, port->index, &func->dev);
+ if (IS_ERR(dev)) {
+ sdio_uart_port_remove(port);
+ ret = PTR_ERR(dev);
+ }
+ }
+
+ return ret;
+}
+
+static void sdio_uart_remove(struct sdio_func *func)
+{
+ struct sdio_uart_port *port = sdio_get_drvdata(func);
+
+ tty_unregister_device(sdio_uart_tty_driver, port->index);
+ sdio_uart_port_remove(port);
+}
+
+static const struct sdio_device_id sdio_uart_ids[] = {
+ { SDIO_DEVICE_CLASS(SDIO_CLASS_UART) },
+ { SDIO_DEVICE_CLASS(SDIO_CLASS_GPS) },
+ { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(sdio, sdio_uart_ids);
+
+static struct sdio_driver sdio_uart_driver = {
+ .probe = sdio_uart_probe,
+ .remove = sdio_uart_remove,
+ .name = "sdio_uart",
+ .id_table = sdio_uart_ids,
+};
+
+static int __init sdio_uart_init(void)
+{
+ int ret;
+ struct tty_driver *tty_drv;
+
+ sdio_uart_tty_driver = tty_drv = alloc_tty_driver(UART_NR);
+ if (!tty_drv)
+ return -ENOMEM;
+
+ tty_drv->owner = THIS_MODULE;
+ tty_drv->driver_name = "sdio_uart";
+ tty_drv->name = "ttySDIO";
+ tty_drv->major = 0; /* dynamically allocated */
+ tty_drv->minor_start = 0;
+ tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
+ tty_drv->subtype = SERIAL_TYPE_NORMAL;
+ tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty_drv->init_termios = tty_std_termios;
+ tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty_drv->init_termios.c_ispeed = 4800;
+ tty_drv->init_termios.c_ospeed = 4800;
+ tty_set_operations(tty_drv, &sdio_uart_ops);
+
+ ret = tty_register_driver(tty_drv);
+ if (ret)
+ goto err1;
+
+ ret = sdio_register_driver(&sdio_uart_driver);
+ if (ret)
+ goto err2;
+
+ return 0;
+
+err2:
+ tty_unregister_driver(tty_drv);
+err1:
+ put_tty_driver(tty_drv);
+ return ret;
+}
+
+static void __exit sdio_uart_exit(void)
+{
+ sdio_unregister_driver(&sdio_uart_driver);
+ tty_unregister_driver(sdio_uart_tty_driver);
+ put_tty_driver(sdio_uart_tty_driver);
+}
+
+module_init(sdio_uart_init);
+module_exit(sdio_uart_exit);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 3fdd08c7f14..4985807257a 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -8,5 +8,7 @@ endif
obj-$(CONFIG_MMC) += mmc_core.o
mmc_core-y := core.o sysfs.o bus.o host.o \
- mmc.o mmc_ops.o sd.o sd_ops.o
+ mmc.o mmc_ops.o sd.o sd_ops.o \
+ sdio.o sdio_ops.o sdio_bus.o \
+ sdio_cis.o sdio_io.o sdio_irq.o
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 817a79462b3..b0c22cad942 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -19,6 +19,7 @@
#include "sysfs.h"
#include "core.h"
+#include "sdio_cis.h"
#include "bus.h"
#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
@@ -34,6 +35,8 @@ static ssize_t mmc_type_show(struct device *dev,
return sprintf(buf, "MMC\n");
case MMC_TYPE_SD:
return sprintf(buf, "SD\n");
+ case MMC_TYPE_SDIO:
+ return sprintf(buf, "SDIO\n");
default:
return -EFAULT;
}
@@ -55,36 +58,35 @@ static int mmc_bus_match(struct device *dev, struct device_driver *drv)
}
static int
-mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
- int buf_size)
+mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct mmc_card *card = dev_to_mmc_card(dev);
- int retval = 0, i = 0, length = 0;
-
-#define add_env(fmt,val) do { \
- retval = add_uevent_var(envp, num_envp, &i, \
- buf, buf_size, &length, \
- fmt, val); \
- if (retval) \
- return retval; \
-} while (0);
+ const char *type;
+ int retval = 0;
switch (card->type) {
case MMC_TYPE_MMC:
- add_env("MMC_TYPE=%s", "MMC");
+ type = "MMC";
break;
case MMC_TYPE_SD:
- add_env("MMC_TYPE=%s", "SD");
+ type = "SD";
break;
+ case MMC_TYPE_SDIO:
+ type = "SDIO";
+ break;
+ default:
+ type = NULL;
}
- add_env("MMC_NAME=%s", mmc_card_name(card));
-
-#undef add_env
+ if (type) {
+ retval = add_uevent_var(env, "MMC_TYPE=%s", type);
+ if (retval)
+ return retval;
+ }
- envp[i] = NULL;
+ retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card));
- return 0;
+ return retval;
}
static int mmc_bus_probe(struct device *dev)
@@ -176,6 +178,11 @@ static void mmc_release_card(struct device *dev)
{
struct mmc_card *card = dev_to_mmc_card(dev);
+ sdio_free_common_cis(card);
+
+ if (card->info)
+ kfree(card->info);
+
kfree(card);
}
@@ -221,15 +228,25 @@ int mmc_add_card(struct mmc_card *card)
if (mmc_card_blockaddr(card))
type = "SDHC";
break;
+ case MMC_TYPE_SDIO:
+ type = "SDIO";
+ break;
default:
type = "?";
break;
}
- printk(KERN_INFO "%s: new %s%s card at address %04x\n",
- mmc_hostname(card->host),
- mmc_card_highspeed(card) ? "high speed " : "",
- type, card->rca);
+ if (mmc_host_is_spi(card->host)) {
+ printk(KERN_INFO "%s: new %s%s card on SPI\n",
+ mmc_hostname(card->host),
+ mmc_card_highspeed(card) ? "high speed " : "",
+ type);
+ } else {
+ printk(KERN_INFO "%s: new %s%s card at address %04x\n",
+ mmc_hostname(card->host),
+ mmc_card_highspeed(card) ? "high speed " : "",
+ type, card->rca);
+ }
card->dev.uevent_suppress = 1;
@@ -261,8 +278,13 @@ int mmc_add_card(struct mmc_card *card)
void mmc_remove_card(struct mmc_card *card)
{
if (mmc_card_present(card)) {
- printk(KERN_INFO "%s: card %04x removed\n",
- mmc_hostname(card->host), card->rca);
+ if (mmc_host_is_spi(card->host)) {
+ printk(KERN_INFO "%s: SPI card removed\n",
+ mmc_hostname(card->host));
+ } else {
+ printk(KERN_INFO "%s: card %04x removed\n",
+ mmc_hostname(card->host), card->rca);
+ }
if (card->host->bus_ops->sysfs_remove)
card->host->bus_ops->sysfs_remove(card->host, card);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index bfd2ae5bd66..b96667448eb 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -18,7 +18,7 @@
#include <linux/delay.h>
#include <linux/pagemap.h>
#include <linux/err.h>
-#include <asm/scatterlist.h>
+#include <linux/leds.h>
#include <linux/scatterlist.h>
#include <linux/mmc/card.h>
@@ -29,16 +29,27 @@
#include "core.h"
#include "bus.h"
#include "host.h"
+#include "sdio_bus.h"
#include "mmc_ops.h"
#include "sd_ops.h"
+#include "sdio_ops.h"
extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
extern int mmc_attach_sd(struct mmc_host *host, u32 ocr);
+extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
static struct workqueue_struct *workqueue;
/*
+ * Enabling software CRCs on the data blocks can be a significant (30%)
+ * performance cost, and for other reasons may not always be desired.
+ * So we allow it it to be disabled.
+ */
+int use_spi_crc = 1;
+module_param(use_spi_crc, bool, 0);
+
+/*
* Internal function. Schedule delayed work in the MMC work queue.
*/
static int mmc_schedule_delayed_work(struct delayed_work *work,
@@ -68,6 +79,11 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
struct mmc_command *cmd = mrq->cmd;
int err = cmd->error;
+ if (err && cmd->retries && mmc_host_is_spi(host)) {
+ if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
+ cmd->retries = 0;
+ }
+
if (err && cmd->retries) {
pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
mmc_hostname(host), cmd->opcode, err);
@@ -76,6 +92,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
cmd->error = 0;
host->ops->request(host, mrq);
} else {
+ led_trigger_event(host->led, LED_OFF);
+
pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
mmc_hostname(host), cmd->opcode, err,
cmd->resp[0], cmd->resp[1],
@@ -118,7 +136,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
"tsac %d ms nsac %d\n",
mmc_hostname(host), mrq->data->blksz,
mrq->data->blocks, mrq->data->flags,
- mrq->data->timeout_ns / 10000000,
+ mrq->data->timeout_ns / 1000000,
mrq->data->timeout_clks);
}
@@ -130,6 +148,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
WARN_ON(!host->claimed);
+ led_trigger_event(host->led, LED_FULL);
+
mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
if (mrq->data) {
@@ -199,7 +219,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
{
struct mmc_request mrq;
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
memset(&mrq, 0, sizeof(struct mmc_request));
@@ -220,17 +240,24 @@ EXPORT_SYMBOL(mmc_wait_for_cmd);
* mmc_set_data_timeout - set the timeout for a data command
* @data: data phase for command
* @card: the MMC card associated with the data transfer
- * @write: flag to differentiate reads from writes
*
* Computes the data timeout parameters according to the
* correct algorithm given the card type.
*/
-void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
- int write)
+void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
{
unsigned int mult;
/*
+ * SDIO cards only define an upper 1 s limit on access.
+ */
+ if (mmc_card_sdio(card)) {
+ data->timeout_ns = 1000000000;
+ data->timeout_clks = 0;
+ return;
+ }
+
+ /*
* SD cards use a 100 multiplier rather than 10
*/
mult = mmc_card_sd(card) ? 100 : 10;
@@ -239,7 +266,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
* Scale up the multiplier (and therefore the timeout) by
* the r2w factor for writes.
*/
- if (write)
+ if (data->flags & MMC_DATA_WRITE)
mult <<= card->csd.r2w_factor;
data->timeout_ns = card->csd.tacc_ns * mult;
@@ -255,7 +282,7 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
timeout_us += data->timeout_clks * 1000 /
(card->host->ios.clock / 1000);
- if (write)
+ if (data->flags & MMC_DATA_WRITE)
limit_us = 250000;
else
limit_us = 100000;
@@ -272,15 +299,20 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
EXPORT_SYMBOL(mmc_set_data_timeout);
/**
- * mmc_claim_host - exclusively claim a host
+ * __mmc_claim_host - exclusively claim a host
* @host: mmc host to claim
+ * @abort: whether or not the operation should be aborted
*
- * Claim a host for a set of operations.
+ * Claim a host for a set of operations. If @abort is non null and
+ * dereference a non-zero value then this will return prematurely with
+ * that non-zero value without acquiring the lock. Returns zero
+ * with the lock held otherwise.
*/
-void mmc_claim_host(struct mmc_host *host)
+int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
{
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
+ int stop;
might_sleep();
@@ -288,19 +320,24 @@ void mmc_claim_host(struct mmc_host *host)
spin_lock_irqsave(&host->lock, flags);
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
- if (!host->claimed)
+ stop = abort ? atomic_read(abort) : 0;
+ if (stop || !host->claimed)
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule();
spin_lock_irqsave(&host->lock, flags);
}
set_current_state(TASK_RUNNING);
- host->claimed = 1;
+ if (!stop)
+ host->claimed = 1;
+ else
+ wake_up(&host->wq);
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
+ return stop;
}
-EXPORT_SYMBOL(mmc_claim_host);
+EXPORT_SYMBOL(__mmc_claim_host);
/**
* mmc_release_host - release a host
@@ -313,7 +350,7 @@ void mmc_release_host(struct mmc_host *host)
{
unsigned long flags;
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
host->claimed = 0;
@@ -433,19 +470,32 @@ static void mmc_power_up(struct mmc_host *host)
int bit = fls(host->ocr_avail) - 1;
host->ios.vdd = bit;
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- host->ios.chip_select = MMC_CS_DONTCARE;
+ if (mmc_host_is_spi(host)) {
+ host->ios.chip_select = MMC_CS_HIGH;
+ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+ } else {
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+ }
host->ios.power_mode = MMC_POWER_UP;
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
- mmc_delay(1);
+ /*
+ * This delay should be sufficient to allow the power supply
+ * to reach the minimum voltage.
+ */
+ mmc_delay(2);
host->ios.clock = host->f_min;
host->ios.power_mode = MMC_POWER_ON;
mmc_set_ios(host);
+ /*
+ * This delay must be at least 74 clock sizes, or 1 ms, or the
+ * time required to reach a stable voltage.
+ */
mmc_delay(2);
}
@@ -453,8 +503,10 @@ static void mmc_power_off(struct mmc_host *host)
{
host->ios.clock = 0;
host->ios.vdd = 0;
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- host->ios.chip_select = MMC_CS_DONTCARE;
+ if (!mmc_host_is_spi(host)) {
+ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ }
host->ios.power_mode = MMC_POWER_OFF;
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
@@ -511,7 +563,7 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
BUG_ON(!host);
BUG_ON(!ops);
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
@@ -535,8 +587,8 @@ void mmc_detach_bus(struct mmc_host *host)
BUG_ON(!host);
- BUG_ON(!host->claimed);
- BUG_ON(!host->bus_ops);
+ WARN_ON(!host->claimed);
+ WARN_ON(!host->bus_ops);
spin_lock_irqsave(&host->lock, flags);
@@ -564,7 +616,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
#ifdef CONFIG_MMC_DEBUG
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
- BUG_ON(host->removed);
+ WARN_ON(host->removed);
spin_unlock_irqrestore(&host->lock, flags);
#endif
@@ -597,24 +649,38 @@ void mmc_rescan(struct work_struct *work)
mmc_send_if_cond(host, host->ocr_avail);
+ /*
+ * First we search for SDIO...
+ */
+ err = mmc_send_io_op_cond(host, 0, &ocr);
+ if (!err) {
+ if (mmc_attach_sdio(host, ocr))
+ mmc_power_off(host);
+ return;
+ }
+
+ /*
+ * ...then normal SD...
+ */
err = mmc_send_app_op_cond(host, 0, &ocr);
- if (err == MMC_ERR_NONE) {
+ if (!err) {
if (mmc_attach_sd(host, ocr))
mmc_power_off(host);
- } else {
- /*
- * If we fail to detect any SD cards then try
- * searching for MMC cards.
- */
- err = mmc_send_op_cond(host, 0, &ocr);
- if (err == MMC_ERR_NONE) {
- if (mmc_attach_mmc(host, ocr))
- mmc_power_off(host);
- } else {
+ return;
+ }
+
+ /*
+ * ...and finally MMC.
+ */
+ err = mmc_send_op_cond(host, 0, &ocr);
+ if (!err) {
+ if (mmc_attach_mmc(host, ocr))
mmc_power_off(host);
- mmc_release_host(host);
- }
+ return;
}
+
+ mmc_release_host(host);
+ mmc_power_off(host);
} else {
if (host->bus_ops->detect && !host->bus_dead)
host->bus_ops->detect(host);
@@ -725,22 +791,38 @@ static int __init mmc_init(void)
return -ENOMEM;
ret = mmc_register_bus();
- if (ret == 0) {
- ret = mmc_register_host_class();
- if (ret)
- mmc_unregister_bus();
- }
+ if (ret)
+ goto destroy_workqueue;
+
+ ret = mmc_register_host_class();
+ if (ret)
+ goto unregister_bus;
+
+ ret = sdio_register_bus();
+ if (ret)
+ goto unregister_host_class;
+
+ return 0;
+
+unregister_host_class:
+ mmc_unregister_host_class();
+unregister_bus:
+ mmc_unregister_bus();
+destroy_workqueue:
+ destroy_workqueue(workqueue);
+
return ret;
}
static void __exit mmc_exit(void)
{
+ sdio_unregister_bus();
mmc_unregister_host_class();
mmc_unregister_bus();
destroy_workqueue(workqueue);
}
-module_init(mmc_init);
+subsys_initcall(mmc_init);
module_exit(mmc_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index bb2774af9ea..39daf2fb5dc 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -48,5 +48,7 @@ void mmc_rescan(struct work_struct *work);
void mmc_start_host(struct mmc_host *host);
void mmc_stop_host(struct mmc_host *host);
+extern int use_spi_crc;
+
#endif
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 2c7ce8f43a9..c65d203a846 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/idr.h>
#include <linux/pagemap.h>
+#include <linux/leds.h>
#include <linux/mmc/host.h>
@@ -100,6 +101,9 @@ int mmc_add_host(struct mmc_host *host)
{
int err;
+ WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
+ !host->ops->enable_sdio_irq);
+
if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
return -ENOMEM;
@@ -112,6 +116,8 @@ int mmc_add_host(struct mmc_host *host)
snprintf(host->class_dev.bus_id, BUS_ID_SIZE,
"mmc%d", host->index);
+ led_trigger_register_simple(host->class_dev.bus_id, &host->led);
+
err = device_add(&host->class_dev);
if (err)
return err;
@@ -137,6 +143,8 @@ void mmc_remove_host(struct mmc_host *host)
device_del(&host->class_dev);
+ led_trigger_unregister_simple(host->led);
+
spin_lock(&mmc_host_lock);
idr_remove(&mmc_host_idr, host->index);
spin_unlock(&mmc_host_lock);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 21d7f48e1d4..68c0e3b2f0e 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -161,13 +161,12 @@ static int mmc_read_ext_csd(struct mmc_card *card)
{
int err;
u8 *ext_csd;
+ unsigned int ext_csd_struct;
BUG_ON(!card);
- err = MMC_ERR_FAILED;
-
if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
- return MMC_ERR_NONE;
+ return 0;
/*
* As the ext_csd is so large and mostly unused, we don't store the
@@ -176,13 +175,19 @@ static int mmc_read_ext_csd(struct mmc_card *card)
ext_csd = kmalloc(512, GFP_KERNEL);
if (!ext_csd) {
printk(KERN_ERR "%s: could not allocate a buffer to "
- "receive the ext_csd. mmc v4 cards will be "
- "treated as v3.\n", mmc_hostname(card->host));
- return MMC_ERR_FAILED;
+ "receive the ext_csd.\n", mmc_hostname(card->host));
+ return -ENOMEM;
}
err = mmc_send_ext_csd(card, ext_csd);
- if (err != MMC_ERR_NONE) {
+ if (err) {
+ /*
+ * We all hosts that cannot perform the command
+ * to fail more gracefully
+ */
+ if (err != -EINVAL)
+ goto out;
+
/*
* High capacity cards should have this "magic" size
* stored in their CSD.
@@ -197,18 +202,30 @@ static int mmc_read_ext_csd(struct mmc_card *card)
"EXT_CSD, performance might "
"suffer.\n",
mmc_hostname(card->host));
- err = MMC_ERR_NONE;
+ err = 0;
}
+
goto out;
}
- card->ext_csd.sectors =
- ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
- ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
- ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
- ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
- if (card->ext_csd.sectors)
- mmc_card_set_blockaddr(card);
+ ext_csd_struct = ext_csd[EXT_CSD_REV];
+ if (ext_csd_struct > 2) {
+ printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
+ "version %d\n", mmc_hostname(card->host),
+ ext_csd_struct);
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (ext_csd_struct >= 2) {
+ card->ext_csd.sectors =
+ ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
+ ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
+ ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
+ ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+ if (card->ext_csd.sectors)
+ mmc_card_set_blockaddr(card);
+ }
switch (ext_csd[EXT_CSD_CARD_TYPE]) {
case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
@@ -246,7 +263,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
unsigned int max_dtr;
BUG_ON(!host);
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
/*
* Since we're changing the OCR value, we seem to
@@ -258,19 +275,33 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
/* The extra bit indicates that we support high capacity */
err = mmc_send_op_cond(host, ocr | (1 << 30), NULL);
- if (err != MMC_ERR_NONE)
+ if (err)
goto err;
/*
+ * For SPI, enable CRC as appropriate.
+ */
+ if (mmc_host_is_spi(host)) {
+ err = mmc_spi_set_crc(host, use_spi_crc);
+ if (err)
+ goto err;
+ }
+
+ /*
* Fetch CID from card.
*/
- err = mmc_all_send_cid(host, cid);
- if (err != MMC_ERR_NONE)
+ if (mmc_host_is_spi(host))
+ err = mmc_send_cid(host, cid);
+ else
+ err = mmc_all_send_cid(host, cid);
+ if (err)
goto err;
if (oldcard) {
- if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
+ if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
+ err = -ENOENT;
goto err;
+ }
card = oldcard;
} else {
@@ -278,8 +309,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* Allocate card structure.
*/
card = mmc_alloc_card(host);
- if (IS_ERR(card))
+ if (IS_ERR(card)) {
+ err = PTR_ERR(card);
goto err;
+ }
card->type = MMC_TYPE_MMC;
card->rca = 1;
@@ -287,43 +320,47 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
/*
- * Set card RCA.
+ * For native busses: set card RCA and quit open drain mode.
*/
- err = mmc_set_relative_addr(card);
- if (err != MMC_ERR_NONE)
- goto free_card;
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_set_relative_addr(card);
+ if (err)
+ goto free_card;
- mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+ mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+ }
if (!oldcard) {
/*
* Fetch CSD from card.
*/
err = mmc_send_csd(card, card->raw_csd);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
err = mmc_decode_csd(card);
- if (err < 0)
+ if (err)
goto free_card;
err = mmc_decode_cid(card);
- if (err < 0)
+ if (err)
goto free_card;
}
/*
* Select card, as all following commands rely on that.
*/
- err = mmc_select_card(card);
- if (err != MMC_ERR_NONE)
- goto free_card;
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_select_card(card);
+ if (err)
+ goto free_card;
+ }
if (!oldcard) {
/*
- * Fetch and process extened CSD.
+ * Fetch and process extended CSD.
*/
err = mmc_read_ext_csd(card);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
}
@@ -334,7 +371,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, 1);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
mmc_card_set_highspeed(card);
@@ -363,7 +400,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
(host->caps & MMC_CAP_4_BIT_DATA)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
@@ -372,14 +409,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (!oldcard)
host->card = card;
- return MMC_ERR_NONE;
+ return 0;
free_card:
if (!oldcard)
mmc_remove_card(card);
err:
- return MMC_ERR_FAILED;
+ return err;
}
/*
@@ -413,7 +450,7 @@ static void mmc_detect(struct mmc_host *host)
mmc_release_host(host);
- if (err != MMC_ERR_NONE) {
+ if (err) {
mmc_remove(host);
mmc_claim_host(host);
@@ -480,7 +517,8 @@ static void mmc_suspend(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
- mmc_deselect_cards(host);
+ if (!mmc_host_is_spi(host))
+ mmc_deselect_cards(host);
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_release_host(host);
}
@@ -502,7 +540,7 @@ static void mmc_resume(struct mmc_host *host)
err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
- if (err != MMC_ERR_NONE) {
+ if (err) {
mmc_remove(host);
mmc_claim_host(host);
@@ -536,11 +574,20 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
int err;
BUG_ON(!host);
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
mmc_attach_bus(host, &mmc_ops);
/*
+ * We need to get OCR a different way for SPI.
+ */
+ if (mmc_host_is_spi(host)) {
+ err = mmc_spi_read_ocr(host, 1, &ocr);
+ if (err)
+ goto err;
+ }
+
+ /*
* Sanity check the voltages that the card claims to
* support.
*/
@@ -565,7 +612,7 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
* Detect and init the card.
*/
err = mmc_init_card(host, host->ocr, NULL);
- if (err != MMC_ERR_NONE)
+ if (err)
goto err;
mmc_release_host(host);
@@ -587,6 +634,6 @@ err:
printk(KERN_ERR "%s: error %d whilst initialising MMC card\n",
mmc_hostname(host), err);
- return 0;
+ return err;
}
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 913e75f0084..64b05c6270f 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -10,7 +10,6 @@
*/
#include <linux/types.h>
-#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
#include <linux/mmc/host.h>
@@ -40,10 +39,10 @@ static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
}
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
- return MMC_ERR_NONE;
+ return 0;
}
int mmc_select_card(struct mmc_card *card)
@@ -63,23 +62,36 @@ int mmc_go_idle(struct mmc_host *host)
int err;
struct mmc_command cmd;
- mmc_set_chip_select(host, MMC_CS_HIGH);
-
- mmc_delay(1);
+ /*
+ * Non-SPI hosts need to prevent chipselect going active during
+ * GO_IDLE; that would put chips into SPI mode. Remind them of
+ * that in case of hardware that won't pull up DAT3/nCS otherwise.
+ *
+ * SPI hosts ignore ios.chip_select; it's managed according to
+ * rules that must accomodate non-MMC slaves which this layer
+ * won't even know about.
+ */
+ if (!mmc_host_is_spi(host)) {
+ mmc_set_chip_select(host, MMC_CS_HIGH);
+ mmc_delay(1);
+ }
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_GO_IDLE_STATE;
cmd.arg = 0;
- cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
err = mmc_wait_for_cmd(host, &cmd, 0);
mmc_delay(1);
- mmc_set_chip_select(host, MMC_CS_DONTCARE);
+ if (!mmc_host_is_spi(host)) {
+ mmc_set_chip_select(host, MMC_CS_DONTCARE);
+ mmc_delay(1);
+ }
- mmc_delay(1);
+ host->use_spi_crc = 0;
return err;
}
@@ -94,23 +106,33 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_OP_COND;
- cmd.arg = ocr;
- cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+ cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
for (i = 100; i; i--) {
err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err != MMC_ERR_NONE)
+ if (err)
break;
- if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+ /* if we're just probing, do a single pass */
+ if (ocr == 0)
break;
- err = MMC_ERR_TIMEOUT;
+ /* otherwise wait until reset completes */
+ if (mmc_host_is_spi(host)) {
+ if (!(cmd.resp[0] & R1_SPI_IDLE))
+ break;
+ } else {
+ if (cmd.resp[0] & MMC_CARD_BUSY)
+ break;
+ }
+
+ err = -ETIMEDOUT;
mmc_delay(10);
}
- if (rocr)
+ if (rocr && !mmc_host_is_spi(host))
*rocr = cmd.resp[0];
return err;
@@ -131,12 +153,12 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
memcpy(cid, cmd.resp, sizeof(u32) * 4);
- return MMC_ERR_NONE;
+ return 0;
}
int mmc_set_relative_addr(struct mmc_card *card)
@@ -154,46 +176,52 @@ int mmc_set_relative_addr(struct mmc_card *card)
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
- return MMC_ERR_NONE;
+ return 0;
}
-int mmc_send_csd(struct mmc_card *card, u32 *csd)
+static int
+mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
{
int err;
struct mmc_command cmd;
- BUG_ON(!card);
- BUG_ON(!card->host);
- BUG_ON(!csd);
+ BUG_ON(!host);
+ BUG_ON(!cxd);
memset(&cmd, 0, sizeof(struct mmc_command));
- cmd.opcode = MMC_SEND_CSD;
- cmd.arg = card->rca << 16;
+ cmd.opcode = opcode;
+ cmd.arg = arg;
cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+ if (err)
return err;
- memcpy(csd, cmd.resp, sizeof(u32) * 4);
+ memcpy(cxd, cmd.resp, sizeof(u32) * 4);
- return MMC_ERR_NONE;
+ return 0;
}
-int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+static int
+mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
+ u32 opcode, void *buf, unsigned len)
{
struct mmc_request mrq;
struct mmc_command cmd;
struct mmc_data data;
struct scatterlist sg;
+ void *data_buf;
- BUG_ON(!card);
- BUG_ON(!card->host);
- BUG_ON(!ext_csd);
+ /* dma onto stack is unsafe/nonportable, but callers to this
+ * routine normally provide temporary on-stack buffers ...
+ */
+ data_buf = kmalloc(len, GFP_KERNEL);
+ if (data_buf == NULL)
+ return -ENOMEM;
memset(&mrq, 0, sizeof(struct mmc_request));
memset(&cmd, 0, sizeof(struct mmc_command));
@@ -202,28 +230,117 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
mrq.cmd = &cmd;
mrq.data = &data;
- cmd.opcode = MMC_SEND_EXT_CSD;
+ cmd.opcode = opcode;
cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- data.blksz = 512;
+ /* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we
+ * rely on callers to never use this with "native" calls for reading
+ * CSD or CID. Native versions of those commands use the R2 type,
+ * not R1 plus a data block.
+ */
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = len;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = &sg;
data.sg_len = 1;
- sg_init_one(&sg, ext_csd, 512);
+ sg_init_one(&sg, data_buf, len);
+
+ if (card)
+ mmc_set_data_timeout(&data, card);
- mmc_set_data_timeout(&data, card, 0);
+ mmc_wait_for_req(host, &mrq);
- mmc_wait_for_req(card->host, &mrq);
+ memcpy(buf, data_buf, len);
+ kfree(data_buf);
- if (cmd.error != MMC_ERR_NONE)
+ if (cmd.error)
return cmd.error;
- if (data.error != MMC_ERR_NONE)
+ if (data.error)
return data.error;
- return MMC_ERR_NONE;
+ return 0;
+}
+
+int mmc_send_csd(struct mmc_card *card, u32 *csd)
+{
+ int ret, i;
+
+ if (!mmc_host_is_spi(card->host))
+ return mmc_send_cxd_native(card->host, card->rca << 16,
+ csd, MMC_SEND_CSD);
+
+ ret = mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16);
+ if (ret)
+ return ret;
+
+ for (i = 0;i < 4;i++)
+ csd[i] = be32_to_cpu(csd[i]);
+
+ return 0;
+}
+
+int mmc_send_cid(struct mmc_host *host, u32 *cid)
+{
+ int ret, i;
+
+ if (!mmc_host_is_spi(host)) {
+ if (!host->card)
+ return -EINVAL;
+ return mmc_send_cxd_native(host, host->card->rca << 16,
+ cid, MMC_SEND_CID);
+ }
+
+ ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16);
+ if (ret)
+ return ret;
+
+ for (i = 0;i < 4;i++)
+ cid[i] = be32_to_cpu(cid[i]);
+
+ return 0;
+}
+
+int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+ return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
+ ext_csd, 512);
+}
+
+int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
+{
+ struct mmc_command cmd;
+ int err;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SPI_READ_OCR;
+ cmd.arg = highcap ? (1 << 30) : 0;
+ cmd.flags = MMC_RSP_SPI_R3;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+
+ *ocrp = cmd.resp[1];
+ return err;
+}
+
+int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
+{
+ struct mmc_command cmd;
+ int err;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SPI_CRC_ON_OFF;
+ cmd.flags = MMC_RSP_SPI_R1;
+ cmd.arg = use_crc;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (!err)
+ host->use_spi_crc = use_crc;
+ return err;
}
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
@@ -241,13 +358,13 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
(index << 16) |
(value << 8) |
set;
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
- return MMC_ERR_NONE;
+ return 0;
}
int mmc_send_status(struct mmc_card *card, u32 *status)
@@ -261,16 +378,20 @@ int mmc_send_status(struct mmc_card *card, u32 *status)
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_STATUS;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ if (!mmc_host_is_spi(card->host))
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
+ /* NOTE: callers are required to understand the difference
+ * between "native" and SPI format status words!
+ */
if (status)
*status = cmd.resp[0];
- return MMC_ERR_NONE;
+ return 0;
}
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 76d09a93c5d..17854bf7cf0 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -22,6 +22,9 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd);
int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
int mmc_send_status(struct mmc_card *card, u32 *status);
+int mmc_send_cid(struct mmc_host *host, u32 *cid);
+int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
+int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
#endif
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 1edc62b1e5c..d1c1e0f592f 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -166,8 +166,6 @@ static int mmc_decode_scr(struct mmc_card *card)
unsigned int scr_struct;
u32 resp[4];
- BUG_ON(!mmc_card_sd(card));
-
resp[3] = card->raw_scr[1];
resp[2] = card->raw_scr[0];
@@ -193,30 +191,38 @@ static int mmc_read_switch(struct mmc_card *card)
u8 *status;
if (card->scr.sda_vsn < SCR_SPEC_VER_1)
- return MMC_ERR_NONE;
+ return 0;
if (!(card->csd.cmdclass & CCC_SWITCH)) {
printk(KERN_WARNING "%s: card lacks mandatory switch "
"function, performance might suffer.\n",
mmc_hostname(card->host));
- return MMC_ERR_NONE;
+ return 0;
}
- err = MMC_ERR_FAILED;
+ err = -EIO;
status = kmalloc(64, GFP_KERNEL);
if (!status) {
printk(KERN_ERR "%s: could not allocate a buffer for "
"switch capabilities.\n", mmc_hostname(card->host));
- return err;
+ return -ENOMEM;
}
err = mmc_sd_switch(card, 0, 0, 1, status);
- if (err != MMC_ERR_NONE) {
+ if (err) {
+ /*
+ * We all hosts that cannot perform the command
+ * to fail more gracefully
+ */
+ if (err != -EINVAL)
+ goto out;
+
printk(KERN_WARNING "%s: problem reading switch "
"capabilities, performance might suffer.\n",
mmc_hostname(card->host));
- err = MMC_ERR_NONE;
+ err = 0;
+
goto out;
}
@@ -238,28 +244,28 @@ static int mmc_switch_hs(struct mmc_card *card)
u8 *status;
if (card->scr.sda_vsn < SCR_SPEC_VER_1)
- return MMC_ERR_NONE;
+ return 0;
if (!(card->csd.cmdclass & CCC_SWITCH))
- return MMC_ERR_NONE;
+ return 0;
if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
- return MMC_ERR_NONE;
+ return 0;
if (card->sw_caps.hs_max_dtr == 0)
- return MMC_ERR_NONE;
+ return 0;
- err = MMC_ERR_FAILED;
+ err = -EIO;
status = kmalloc(64, GFP_KERNEL);
if (!status) {
printk(KERN_ERR "%s: could not allocate a buffer for "
"switch capabilities.\n", mmc_hostname(card->host));
- return err;
+ return -ENOMEM;
}
err = mmc_sd_switch(card, 1, 0, 1, status);
- if (err != MMC_ERR_NONE)
+ if (err)
goto out;
if ((status[16] & 0xF) != 1) {
@@ -292,7 +298,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
unsigned int max_dtr;
BUG_ON(!host);
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
/*
* Since we're changing the OCR value, we seem to
@@ -309,23 +315,37 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
* block-addressed SDHC cards.
*/
err = mmc_send_if_cond(host, ocr);
- if (err == MMC_ERR_NONE)
+ if (!err)
ocr |= 1 << 30;
err = mmc_send_app_op_cond(host, ocr, NULL);
- if (err != MMC_ERR_NONE)
+ if (err)
goto err;
/*
+ * For SPI, enable CRC as appropriate.
+ */
+ if (mmc_host_is_spi(host)) {
+ err = mmc_spi_set_crc(host, use_spi_crc);
+ if (err)
+ goto err;
+ }
+
+ /*
* Fetch CID from card.
*/
- err = mmc_all_send_cid(host, cid);
- if (err != MMC_ERR_NONE)
+ if (mmc_host_is_spi(host))
+ err = mmc_send_cid(host, cid);
+ else
+ err = mmc_all_send_cid(host, cid);
+ if (err)
goto err;
if (oldcard) {
- if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
+ if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
+ err = -ENOENT;
goto err;
+ }
card = oldcard;
} else {
@@ -333,32 +353,36 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
* Allocate card structure.
*/
card = mmc_alloc_card(host);
- if (IS_ERR(card))
+ if (IS_ERR(card)) {
+ err = PTR_ERR(card);
goto err;
+ }
card->type = MMC_TYPE_SD;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
}
/*
- * Set card RCA.
+ * For native busses: get card RCA and quit open drain mode.
*/
- err = mmc_send_relative_addr(host, &card->rca);
- if (err != MMC_ERR_NONE)
- goto free_card;
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_send_relative_addr(host, &card->rca);
+ if (err)
+ goto free_card;
- mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+ mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+ }
if (!oldcard) {
/*
* Fetch CSD from card.
*/
err = mmc_send_csd(card, card->raw_csd);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
err = mmc_decode_csd(card);
- if (err < 0)
+ if (err)
goto free_card;
mmc_decode_cid(card);
@@ -367,16 +391,18 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
/*
* Select card, as all following commands rely on that.
*/
- err = mmc_select_card(card);
- if (err != MMC_ERR_NONE)
- goto free_card;
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_select_card(card);
+ if (err)
+ goto free_card;
+ }
if (!oldcard) {
/*
* Fetch SCR from card.
*/
err = mmc_app_send_scr(card, card->raw_scr);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
err = mmc_decode_scr(card);
@@ -387,7 +413,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
* Fetch switch information from card.
*/
err = mmc_read_switch(card);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
}
@@ -395,7 +421,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
* Attempt to change to high-speed (if supported)
*/
err = mmc_switch_hs(card);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
/*
@@ -418,7 +444,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
if ((host->caps & MMC_CAP_4_BIT_DATA) &&
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
- if (err != MMC_ERR_NONE)
+ if (err)
goto free_card;
mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
@@ -442,14 +468,14 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
if (!oldcard)
host->card = card;
- return MMC_ERR_NONE;
+ return 0;
free_card:
if (!oldcard)
mmc_remove_card(card);
err:
- return MMC_ERR_FAILED;
+ return err;
}
/*
@@ -483,7 +509,7 @@ static void mmc_sd_detect(struct mmc_host *host)
mmc_release_host(host);
- if (err != MMC_ERR_NONE) {
+ if (err) {
mmc_sd_remove(host);
mmc_claim_host(host);
@@ -552,7 +578,8 @@ static void mmc_sd_suspend(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
- mmc_deselect_cards(host);
+ if (!mmc_host_is_spi(host))
+ mmc_deselect_cards(host);
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_release_host(host);
}
@@ -574,7 +601,7 @@ static void mmc_sd_resume(struct mmc_host *host)
err = mmc_sd_init_card(host, host->ocr, host->card);
mmc_release_host(host);
- if (err != MMC_ERR_NONE) {
+ if (err) {
mmc_sd_remove(host);
mmc_claim_host(host);
@@ -608,11 +635,22 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
int err;
BUG_ON(!host);
- BUG_ON(!host->claimed);
+ WARN_ON(!host->claimed);
mmc_attach_bus(host, &mmc_sd_ops);
/*
+ * We need to get OCR a different way for SPI.
+ */
+ if (mmc_host_is_spi(host)) {
+ mmc_go_idle(host);
+
+ err = mmc_spi_read_ocr(host, 0, &ocr);
+ if (err)
+ goto err;
+ }
+
+ /*
* Sanity check the voltages that the card claims to
* support.
*/
@@ -644,7 +682,7 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
* Detect and init the card.
*/
err = mmc_sd_init_card(host, host->ocr, NULL);
- if (err != MMC_ERR_NONE)
+ if (err)
goto err;
mmc_release_host(host);
@@ -666,6 +704,6 @@ err:
printk(KERN_ERR "%s: error %d whilst initialising SD card\n",
mmc_hostname(host), err);
- return 0;
+ return err;
}
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 342f340ebc2..0d96080d44b 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -10,7 +10,6 @@
*/
#include <linux/types.h>
-#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
#include <linux/mmc/host.h>
@@ -33,21 +32,21 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
if (card) {
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
} else {
cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR;
}
err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
/* Check that card supported application commands */
- if (!(cmd.resp[0] & R1_APP_CMD))
- return MMC_ERR_FAILED;
+ if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD))
+ return -EOPNOTSUPP;
- return MMC_ERR_NONE;
+ return 0;
}
/**
@@ -73,7 +72,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
BUG_ON(!cmd);
BUG_ON(retries < 0);
- err = MMC_ERR_INVALID;
+ err = -EIO;
/*
* We have to resend MMC_APP_CMD for each attempt so
@@ -83,8 +82,14 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
memset(&mrq, 0, sizeof(struct mmc_request));
err = mmc_app_cmd(host, card);
- if (err != MMC_ERR_NONE)
+ if (err) {
+ /* no point in retrying; no APP commands allowed */
+ if (mmc_host_is_spi(host)) {
+ if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
+ break;
+ }
continue;
+ }
memset(&mrq, 0, sizeof(struct mmc_request));
@@ -97,8 +102,14 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
mmc_wait_for_req(host, &mrq);
err = cmd->error;
- if (cmd->error == MMC_ERR_NONE)
+ if (!cmd->error)
break;
+
+ /* no point in retrying illegal APP commands */
+ if (mmc_host_is_spi(host)) {
+ if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
+ break;
+ }
}
return err;
@@ -127,14 +138,14 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
cmd.arg = SD_BUS_WIDTH_4;
break;
default:
- return MMC_ERR_INVALID;
+ return -EINVAL;
}
err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
- return MMC_ERR_NONE;
+ return 0;
}
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
@@ -147,23 +158,36 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = SD_APP_OP_COND;
- cmd.arg = ocr;
- cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+ if (mmc_host_is_spi(host))
+ cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
+ else
+ cmd.arg = ocr;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
for (i = 100; i; i--) {
err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
break;
- if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+ /* if we're just probing, do a single pass */
+ if (ocr == 0)
break;
- err = MMC_ERR_TIMEOUT;
+ /* otherwise wait until reset completes */
+ if (mmc_host_is_spi(host)) {
+ if (!(cmd.resp[0] & R1_SPI_IDLE))
+ break;
+ } else {
+ if (cmd.resp[0] & MMC_CARD_BUSY)
+ break;
+ }
+
+ err = -ETIMEDOUT;
mmc_delay(10);
}
- if (rocr)
+ if (rocr && !mmc_host_is_spi(host))
*rocr = cmd.resp[0];
return err;
@@ -174,6 +198,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
struct mmc_command cmd;
int err;
static const u8 test_pattern = 0xAA;
+ u8 result_pattern;
/*
* To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
@@ -182,16 +207,21 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
*/
cmd.opcode = SD_SEND_IF_COND;
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
- cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+ cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
- if ((cmd.resp[0] & 0xFF) != test_pattern)
- return MMC_ERR_FAILED;
+ if (mmc_host_is_spi(host))
+ result_pattern = cmd.resp[1] & 0xFF;
+ else
+ result_pattern = cmd.resp[0] & 0xFF;
+
+ if (result_pattern != test_pattern)
+ return -EIO;
- return MMC_ERR_NONE;
+ return 0;
}
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
@@ -209,12 +239,12 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
*rca = cmd.resp[0] >> 16;
- return MMC_ERR_NONE;
+ return 0;
}
int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
@@ -229,8 +259,10 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
BUG_ON(!card->host);
BUG_ON(!scr);
+ /* NOTE: caller guarantees scr is heap-allocated */
+
err = mmc_app_cmd(card->host, card);
- if (err != MMC_ERR_NONE)
+ if (err)
return err;
memset(&mrq, 0, sizeof(struct mmc_request));
@@ -242,7 +274,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
cmd.opcode = SD_APP_SEND_SCR;
cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = 8;
data.blocks = 1;
@@ -252,19 +284,19 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
sg_init_one(&sg, scr, 8);
- mmc_set_data_timeout(&data, card, 0);
+ mmc_set_data_timeout(&data, card);
mmc_wait_for_req(card->host, &mrq);
- if (cmd.error != MMC_ERR_NONE)
+ if (cmd.error)
return cmd.error;
- if (data.error != MMC_ERR_NONE)
+ if (data.error)
return data.error;
- scr[0] = ntohl(scr[0]);
- scr[1] = ntohl(scr[1]);
+ scr[0] = be32_to_cpu(scr[0]);
+ scr[1] = be32_to_cpu(scr[1]);
- return MMC_ERR_NONE;
+ return 0;
}
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
@@ -278,6 +310,8 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
BUG_ON(!card);
BUG_ON(!card->host);
+ /* NOTE: caller guarantees resp is heap-allocated */
+
mode = !!mode;
value &= 0xF;
@@ -292,7 +326,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
cmd.arg = mode << 31 | 0x00FFFFFF;
cmd.arg &= ~(0xF << (group * 4));
cmd.arg |= value << (group * 4);
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
data.blksz = 64;
data.blocks = 1;
@@ -302,15 +336,15 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
sg_init_one(&sg, resp, 64);
- mmc_set_data_timeout(&data, card, 0);
+ mmc_set_data_timeout(&data, card);
mmc_wait_for_req(card->host, &mrq);
- if (cmd.error != MMC_ERR_NONE)
+ if (cmd.error)
return cmd.error;
- if (data.error != MMC_ERR_NONE)
+ if (data.error)
return data.error;
- return MMC_ERR_NONE;
+ return 0;
}
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
new file mode 100644
index 00000000000..87a50f456ef
--- /dev/null
+++ b/drivers/mmc/core/sdio.c
@@ -0,0 +1,395 @@
+/*
+ * linux/drivers/mmc/sdio.c
+ *
+ * Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/err.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "core.h"
+#include "bus.h"
+#include "sdio_bus.h"
+#include "mmc_ops.h"
+#include "sd_ops.h"
+#include "sdio_ops.h"
+#include "sdio_cis.h"
+
+static int sdio_read_fbr(struct sdio_func *func)
+{
+ int ret;
+ unsigned char data;
+
+ ret = mmc_io_rw_direct(func->card, 0, 0,
+ SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data);
+ if (ret)
+ goto out;
+
+ data &= 0x0f;
+
+ if (data == 0x0f) {
+ ret = mmc_io_rw_direct(func->card, 0, 0,
+ SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF_EXT, 0, &data);
+ if (ret)
+ goto out;
+ }
+
+ func->class = data;
+
+out:
+ return ret;
+}
+
+static int sdio_init_func(struct mmc_card *card, unsigned int fn)
+{
+ int ret;
+ struct sdio_func *func;
+
+ BUG_ON(fn > SDIO_MAX_FUNCS);
+
+ func = sdio_alloc_func(card);
+ if (IS_ERR(func))
+ return PTR_ERR(func);
+
+ func->num = fn;
+
+ ret = sdio_read_fbr(func);
+ if (ret)
+ goto fail;
+
+ ret = sdio_read_func_cis(func);
+ if (ret)
+ goto fail;
+
+ card->sdio_func[fn - 1] = func;
+
+ return 0;
+
+fail:
+ /*
+ * It is okay to remove the function here even though we hold
+ * the host lock as we haven't registered the device yet.
+ */
+ sdio_remove_func(func);
+ return ret;
+}
+
+static int sdio_read_cccr(struct mmc_card *card)
+{
+ int ret;
+ int cccr_vsn;
+ unsigned char data;
+
+ memset(&card->cccr, 0, sizeof(struct sdio_cccr));
+
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data);
+ if (ret)
+ goto out;
+
+ cccr_vsn = data & 0x0f;
+
+ if (cccr_vsn > SDIO_CCCR_REV_1_20) {
+ printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n",
+ mmc_hostname(card->host), cccr_vsn);
+ return -EINVAL;
+ }
+
+ card->cccr.sdio_vsn = (data & 0xf0) >> 4;
+
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data);
+ if (ret)
+ goto out;
+
+ if (data & SDIO_CCCR_CAP_SMB)
+ card->cccr.multi_block = 1;
+ if (data & SDIO_CCCR_CAP_LSC)
+ card->cccr.low_speed = 1;
+ if (data & SDIO_CCCR_CAP_4BLS)
+ card->cccr.wide_bus = 1;
+
+ if (cccr_vsn >= SDIO_CCCR_REV_1_10) {
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data);
+ if (ret)
+ goto out;
+
+ if (data & SDIO_POWER_SMPC)
+ card->cccr.high_power = 1;
+ }
+
+ if (cccr_vsn >= SDIO_CCCR_REV_1_20) {
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data);
+ if (ret)
+ goto out;
+
+ if (data & SDIO_SPEED_SHS)
+ card->cccr.high_speed = 1;
+ }
+
+out:
+ return ret;
+}
+
+static int sdio_enable_wide(struct mmc_card *card)
+{
+ int ret;
+ u8 ctrl;
+
+ if (!(card->host->caps & MMC_CAP_4_BIT_DATA))
+ return 0;
+
+ if (card->cccr.low_speed && !card->cccr.wide_bus)
+ return 0;
+
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
+ if (ret)
+ return ret;
+
+ ctrl |= SDIO_BUS_WIDTH_4BIT;
+
+ ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
+ if (ret)
+ return ret;
+
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+
+ return 0;
+}
+
+/*
+ * Host is being removed. Free up the current card.
+ */
+static void mmc_sdio_remove(struct mmc_host *host)
+{
+ int i;
+
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ for (i = 0;i < host->card->sdio_funcs;i++) {
+ if (host->card->sdio_func[i]) {
+ sdio_remove_func(host->card->sdio_func[i]);
+ host->card->sdio_func[i] = NULL;
+ }
+ }
+
+ mmc_remove_card(host->card);
+ host->card = NULL;
+}
+
+/*
+ * Card detection callback from host.
+ */
+static void mmc_sdio_detect(struct mmc_host *host)
+{
+ int err;
+
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_claim_host(host);
+
+ /*
+ * Just check if our card has been removed.
+ */
+ err = mmc_select_card(host->card);
+
+ mmc_release_host(host);
+
+ if (err) {
+ mmc_sdio_remove(host);
+
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+ }
+}
+
+
+static const struct mmc_bus_ops mmc_sdio_ops = {
+ .remove = mmc_sdio_remove,
+ .detect = mmc_sdio_detect,
+};
+
+
+/*
+ * Starting point for SDIO card init.
+ */
+int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
+{
+ int err;
+ int i, funcs;
+ struct mmc_card *card;
+
+ BUG_ON(!host);
+ WARN_ON(!host->claimed);
+
+ mmc_attach_bus(host, &mmc_sdio_ops);
+
+ /*
+ * Sanity check the voltages that the card claims to
+ * support.
+ */
+ if (ocr & 0x7F) {
+ printk(KERN_WARNING "%s: card claims to support voltages "
+ "below the defined range. These will be ignored.\n",
+ mmc_hostname(host));
+ ocr &= ~0x7F;
+ }
+
+ if (ocr & MMC_VDD_165_195) {
+ printk(KERN_WARNING "%s: SDIO card claims to support the "
+ "incompletely defined 'low voltage range'. This "
+ "will be ignored.\n", mmc_hostname(host));
+ ocr &= ~MMC_VDD_165_195;
+ }
+
+ host->ocr = mmc_select_voltage(host, ocr);
+
+ /*
+ * Can we support the voltage(s) of the card(s)?
+ */
+ if (!host->ocr) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ /*
+ * Inform the card of the voltage
+ */
+ err = mmc_send_io_op_cond(host, host->ocr, &ocr);
+ if (err)
+ goto err;
+
+ /*
+ * For SPI, enable CRC as appropriate.
+ */
+ if (mmc_host_is_spi(host)) {
+ err = mmc_spi_set_crc(host, use_spi_crc);
+ if (err)
+ goto err;
+ }
+
+ /*
+ * The number of functions on the card is encoded inside
+ * the ocr.
+ */
+ funcs = (ocr & 0x70000000) >> 28;
+
+ /*
+ * Allocate card structure.
+ */
+ card = mmc_alloc_card(host);
+ if (IS_ERR(card)) {
+ err = PTR_ERR(card);
+ goto err;
+ }
+
+ card->type = MMC_TYPE_SDIO;
+ card->sdio_funcs = funcs;
+
+ host->card = card;
+
+ /*
+ * For native busses: set card RCA and quit open drain mode.
+ */
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_send_relative_addr(host, &card->rca);
+ if (err)
+ goto remove;
+
+ mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+ }
+
+ /*
+ * Select card, as all following commands rely on that.
+ */
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_select_card(card);
+ if (err)
+ goto remove;
+ }
+
+ /*
+ * Read the common registers.
+ */
+ err = sdio_read_cccr(card);
+ if (err)
+ goto remove;
+
+ /*
+ * Read the common CIS tuples.
+ */
+ err = sdio_read_common_cis(card);
+ if (err)
+ goto remove;
+
+ /*
+ * No support for high-speed yet, so just set
+ * the card's maximum speed.
+ */
+ mmc_set_clock(host, card->cis.max_dtr);
+
+ /*
+ * Switch to wider bus (if supported).
+ */
+ err = sdio_enable_wide(card);
+ if (err)
+ goto remove;
+
+ /*
+ * Initialize (but don't add) all present functions.
+ */
+ for (i = 0;i < funcs;i++) {
+ err = sdio_init_func(host->card, i + 1);
+ if (err)
+ goto remove;
+ }
+
+ mmc_release_host(host);
+
+ /*
+ * First add the card to the driver model...
+ */
+ err = mmc_add_card(host->card);
+ if (err)
+ goto remove_added;
+
+ /*
+ * ...then the SDIO functions.
+ */
+ for (i = 0;i < funcs;i++) {
+ err = sdio_add_func(host->card->sdio_func[i]);
+ if (err)
+ goto remove_added;
+ }
+
+ return 0;
+
+
+remove_added:
+ /* Remove without lock if the device has been added. */
+ mmc_sdio_remove(host);
+ mmc_claim_host(host);
+remove:
+ /* And with lock if it hasn't been added. */
+ if (host->card)
+ mmc_sdio_remove(host);
+err:
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+
+ printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n",
+ mmc_hostname(host), err);
+
+ return err;
+}
+
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
new file mode 100644
index 00000000000..233d0f9b3c4
--- /dev/null
+++ b/drivers/mmc/core/sdio_bus.c
@@ -0,0 +1,263 @@
+/*
+ * linux/drivers/mmc/core/sdio_bus.c
+ *
+ * Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * SDIO function driver model
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "sdio_cis.h"
+#include "sdio_bus.h"
+
+#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
+#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
+
+/* show configuration fields */
+#define sdio_config_attr(field, format_string) \
+static ssize_t \
+field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct sdio_func *func; \
+ \
+ func = dev_to_sdio_func (dev); \
+ return sprintf (buf, format_string, func->field); \
+}
+
+sdio_config_attr(class, "0x%02x\n");
+sdio_config_attr(vendor, "0x%04x\n");
+sdio_config_attr(device, "0x%04x\n");
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sdio_func *func = dev_to_sdio_func (dev);
+
+ return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",
+ func->class, func->vendor, func->device);
+}
+
+static struct device_attribute sdio_dev_attrs[] = {
+ __ATTR_RO(class),
+ __ATTR_RO(vendor),
+ __ATTR_RO(device),
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
+};
+
+static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
+ return NULL;
+ if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
+ return NULL;
+ if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
+ return NULL;
+ return id;
+}
+
+static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
+ struct sdio_driver *sdrv)
+{
+ const struct sdio_device_id *ids;
+
+ ids = sdrv->id_table;
+
+ if (ids) {
+ while (ids->class || ids->vendor || ids->device) {
+ if (sdio_match_one(func, ids))
+ return ids;
+ ids++;
+ }
+ }
+
+ return NULL;
+}
+
+static int sdio_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct sdio_driver *sdrv = to_sdio_driver(drv);
+
+ if (sdio_match_device(func, sdrv))
+ return 1;
+
+ return 0;
+}
+
+static int
+sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+
+ if (add_uevent_var(env,
+ "SDIO_CLASS=%02X", func->class))
+ return -ENOMEM;
+
+ if (add_uevent_var(env,
+ "SDIO_ID=%04X:%04X", func->vendor, func->device))
+ return -ENOMEM;
+
+ if (add_uevent_var(env,
+ "MODALIAS=sdio:c%02Xv%04Xd%04X",
+ func->class, func->vendor, func->device))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int sdio_bus_probe(struct device *dev)
+{
+ struct sdio_driver *drv = to_sdio_driver(dev->driver);
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ const struct sdio_device_id *id;
+ int ret;
+
+ id = sdio_match_device(func, drv);
+ if (!id)
+ return -ENODEV;
+
+ /* Set the default block size so the driver is sure it's something
+ * sensible. */
+ sdio_claim_host(func);
+ ret = sdio_set_block_size(func, 0);
+ sdio_release_host(func);
+ if (ret)
+ return ret;
+
+ return drv->probe(func, id);
+}
+
+static int sdio_bus_remove(struct device *dev)
+{
+ struct sdio_driver *drv = to_sdio_driver(dev->driver);
+ struct sdio_func *func = dev_to_sdio_func(dev);
+
+ drv->remove(func);
+
+ if (func->irq_handler) {
+ printk(KERN_WARNING "WARNING: driver %s did not remove "
+ "its interrupt handler!\n", drv->name);
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_release_host(func);
+ }
+
+ return 0;
+}
+
+static struct bus_type sdio_bus_type = {
+ .name = "sdio",
+ .dev_attrs = sdio_dev_attrs,
+ .match = sdio_bus_match,
+ .uevent = sdio_bus_uevent,
+ .probe = sdio_bus_probe,
+ .remove = sdio_bus_remove,
+};
+
+int sdio_register_bus(void)
+{
+ return bus_register(&sdio_bus_type);
+}
+
+void sdio_unregister_bus(void)
+{
+ bus_unregister(&sdio_bus_type);
+}
+
+/**
+ * sdio_register_driver - register a function driver
+ * @drv: SDIO function driver
+ */
+int sdio_register_driver(struct sdio_driver *drv)
+{
+ drv->drv.name = drv->name;
+ drv->drv.bus = &sdio_bus_type;
+ return driver_register(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(sdio_register_driver);
+
+/**
+ * sdio_unregister_driver - unregister a function driver
+ * @drv: SDIO function driver
+ */
+void sdio_unregister_driver(struct sdio_driver *drv)
+{
+ drv->drv.bus = &sdio_bus_type;
+ driver_unregister(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(sdio_unregister_driver);
+
+static void sdio_release_func(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+
+ sdio_free_func_cis(func);
+
+ if (func->info)
+ kfree(func->info);
+
+ kfree(func);
+}
+
+/*
+ * Allocate and initialise a new SDIO function structure.
+ */
+struct sdio_func *sdio_alloc_func(struct mmc_card *card)
+{
+ struct sdio_func *func;
+
+ func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL);
+ if (!func)
+ return ERR_PTR(-ENOMEM);
+
+ func->card = card;
+
+ device_initialize(&func->dev);
+
+ func->dev.parent = &card->dev;
+ func->dev.bus = &sdio_bus_type;
+ func->dev.release = sdio_release_func;
+
+ return func;
+}
+
+/*
+ * Register a new SDIO function with the driver model.
+ */
+int sdio_add_func(struct sdio_func *func)
+{
+ int ret;
+
+ snprintf(func->dev.bus_id, sizeof(func->dev.bus_id),
+ "%s:%d", mmc_card_id(func->card), func->num);
+
+ ret = device_add(&func->dev);
+ if (ret == 0)
+ sdio_func_set_present(func);
+
+ return ret;
+}
+
+/*
+ * Unregister a SDIO function with the driver model, and
+ * (eventually) free it.
+ */
+void sdio_remove_func(struct sdio_func *func)
+{
+ if (sdio_func_present(func))
+ device_del(&func->dev);
+
+ put_device(&func->dev);
+}
+
diff --git a/drivers/mmc/core/sdio_bus.h b/drivers/mmc/core/sdio_bus.h
new file mode 100644
index 00000000000..567a76821ba
--- /dev/null
+++ b/drivers/mmc/core/sdio_bus.h
@@ -0,0 +1,22 @@
+/*
+ * linux/drivers/mmc/core/sdio_bus.h
+ *
+ * Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+#ifndef _MMC_CORE_SDIO_BUS_H
+#define _MMC_CORE_SDIO_BUS_H
+
+struct sdio_func *sdio_alloc_func(struct mmc_card *card);
+int sdio_add_func(struct sdio_func *func);
+void sdio_remove_func(struct sdio_func *func);
+
+int sdio_register_bus(void);
+void sdio_unregister_bus(void);
+
+#endif
+
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
new file mode 100644
index 00000000000..d5e51b1c7b3
--- /dev/null
+++ b/drivers/mmc/core/sdio_cis.c
@@ -0,0 +1,346 @@
+/*
+ * linux/drivers/mmc/core/sdio_cis.c
+ *
+ * Author: Nicolas Pitre
+ * Created: June 11, 2007
+ * Copyright: MontaVista Software Inc.
+ *
+ * Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/kernel.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "sdio_cis.h"
+#include "sdio_ops.h"
+
+static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
+ const unsigned char *buf, unsigned size)
+{
+ unsigned i, nr_strings;
+ char **buffer, *string;
+
+ buf += 2;
+ size -= 2;
+
+ nr_strings = 0;
+ for (i = 0; i < size; i++) {
+ if (buf[i] == 0xff)
+ break;
+ if (buf[i] == 0)
+ nr_strings++;
+ }
+
+ if (buf[i-1] != '\0') {
+ printk(KERN_WARNING "SDIO: ignoring broken CISTPL_VERS_1\n");
+ return 0;
+ }
+
+ size = i;
+
+ buffer = kzalloc(sizeof(char*) * nr_strings + size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ string = (char*)(buffer + nr_strings);
+
+ for (i = 0; i < nr_strings; i++) {
+ buffer[i] = string;
+ strcpy(string, buf);
+ string += strlen(string) + 1;
+ buf += strlen(buf) + 1;
+ }
+
+ if (func) {
+ func->num_info = nr_strings;
+ func->info = (const char**)buffer;
+ } else {
+ card->num_info = nr_strings;
+ card->info = (const char**)buffer;
+ }
+
+ return 0;
+}
+
+static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func,
+ const unsigned char *buf, unsigned size)
+{
+ unsigned int vendor, device;
+
+ /* TPLMID_MANF */
+ vendor = buf[0] | (buf[1] << 8);
+
+ /* TPLMID_CARD */
+ device = buf[2] | (buf[3] << 8);
+
+ if (func) {
+ func->vendor = vendor;
+ func->device = device;
+ } else {
+ card->cis.vendor = vendor;
+ card->cis.device = device;
+ }
+
+ return 0;
+}
+
+static const unsigned char speed_val[16] =
+ { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
+static const unsigned int speed_unit[8] =
+ { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
+
+static int cistpl_funce_common(struct mmc_card *card,
+ const unsigned char *buf, unsigned size)
+{
+ if (size < 0x04 || buf[0] != 0)
+ return -EINVAL;
+
+ /* TPLFE_FN0_BLK_SIZE */
+ card->cis.blksize = buf[1] | (buf[2] << 8);
+
+ /* TPLFE_MAX_TRAN_SPEED */
+ card->cis.max_dtr = speed_val[(buf[3] >> 3) & 15] *
+ speed_unit[buf[3] & 7];
+
+ return 0;
+}
+
+static int cistpl_funce_func(struct sdio_func *func,
+ const unsigned char *buf, unsigned size)
+{
+ unsigned vsn;
+ unsigned min_size;
+
+ vsn = func->card->cccr.sdio_vsn;
+ min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
+
+ if (size < min_size || buf[0] != 1)
+ return -EINVAL;
+
+ /* TPLFE_MAX_BLK_SIZE */
+ func->max_blksize = buf[12] | (buf[13] << 8);
+
+ return 0;
+}
+
+static int cistpl_funce(struct mmc_card *card, struct sdio_func *func,
+ const unsigned char *buf, unsigned size)
+{
+ int ret;
+
+ /*
+ * There should be two versions of the CISTPL_FUNCE tuple,
+ * one for the common CIS (function 0) and a version used by
+ * the individual function's CIS (1-7). Yet, the later has a
+ * different length depending on the SDIO spec version.
+ */
+ if (func)
+ ret = cistpl_funce_func(func, buf, size);
+ else
+ ret = cistpl_funce_common(card, buf, size);
+
+ if (ret) {
+ printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u "
+ "type %u\n", mmc_hostname(card->host), size, buf[0]);
+ return ret;
+ }
+
+ return 0;
+}
+
+typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,
+ const unsigned char *, unsigned);
+
+struct cis_tpl {
+ unsigned char code;
+ unsigned char min_size;
+ tpl_parse_t *parse;
+};
+
+static const struct cis_tpl cis_tpl_list[] = {
+ { 0x15, 3, cistpl_vers_1 },
+ { 0x20, 4, cistpl_manfid },
+ { 0x21, 2, /* cistpl_funcid */ },
+ { 0x22, 0, cistpl_funce },
+};
+
+static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
+{
+ int ret;
+ struct sdio_func_tuple *this, **prev;
+ unsigned i, ptr = 0;
+
+ /*
+ * Note that this works for the common CIS (function number 0) as
+ * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS
+ * have the same offset.
+ */
+ for (i = 0; i < 3; i++) {
+ unsigned char x, fn;
+
+ if (func)
+ fn = func->num;
+ else
+ fn = 0;
+
+ ret = mmc_io_rw_direct(card, 0, 0,
+ SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x);
+ if (ret)
+ return ret;
+ ptr |= x << (i * 8);
+ }
+
+ if (func)
+ prev = &func->tuples;
+ else
+ prev = &card->tuples;
+
+ BUG_ON(*prev);
+
+ do {
+ unsigned char tpl_code, tpl_link;
+
+ ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code);
+ if (ret)
+ break;
+
+ /* 0xff means we're done */
+ if (tpl_code == 0xff)
+ break;
+
+ ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link);
+ if (ret)
+ break;
+
+ this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL);
+ if (!this)
+ return -ENOMEM;
+
+ for (i = 0; i < tpl_link; i++) {
+ ret = mmc_io_rw_direct(card, 0, 0,
+ ptr + i, 0, &this->data[i]);
+ if (ret)
+ break;
+ }
+ if (ret) {
+ kfree(this);
+ break;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
+ if (cis_tpl_list[i].code == tpl_code)
+ break;
+ if (i >= ARRAY_SIZE(cis_tpl_list)) {
+ /* this tuple is unknown to the core */
+ this->next = NULL;
+ this->code = tpl_code;
+ this->size = tpl_link;
+ *prev = this;
+ prev = &this->next;
+ printk(KERN_DEBUG
+ "%s: queuing CIS tuple 0x%02x length %u\n",
+ mmc_hostname(card->host), tpl_code, tpl_link);
+ } else {
+ const struct cis_tpl *tpl = cis_tpl_list + i;
+ if (tpl_link < tpl->min_size) {
+ printk(KERN_ERR
+ "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n",
+ mmc_hostname(card->host),
+ tpl_code, tpl_link, tpl->min_size);
+ ret = -EINVAL;
+ } else if (tpl->parse) {
+ ret = tpl->parse(card, func,
+ this->data, tpl_link);
+ }
+ kfree(this);
+ }
+
+ ptr += tpl_link;
+ } while (!ret);
+
+ /*
+ * Link in all unknown tuples found in the common CIS so that
+ * drivers don't have to go digging in two places.
+ */
+ if (func)
+ *prev = card->tuples;
+
+ return ret;
+}
+
+int sdio_read_common_cis(struct mmc_card *card)
+{
+ return sdio_read_cis(card, NULL);
+}
+
+void sdio_free_common_cis(struct mmc_card *card)
+{
+ struct sdio_func_tuple *tuple, *victim;
+
+ tuple = card->tuples;
+
+ while (tuple) {
+ victim = tuple;
+ tuple = tuple->next;
+ kfree(victim);
+ }
+
+ card->tuples = NULL;
+}
+
+int sdio_read_func_cis(struct sdio_func *func)
+{
+ int ret;
+
+ ret = sdio_read_cis(func->card, func);
+ if (ret)
+ return ret;
+
+ /*
+ * Since we've linked to tuples in the card structure,
+ * we must make sure we have a reference to it.
+ */
+ get_device(&func->card->dev);
+
+ /*
+ * Vendor/device id is optional for function CIS, so
+ * copy it from the card structure as needed.
+ */
+ if (func->vendor == 0) {
+ func->vendor = func->card->cis.vendor;
+ func->device = func->card->cis.device;
+ }
+
+ return 0;
+}
+
+void sdio_free_func_cis(struct sdio_func *func)
+{
+ struct sdio_func_tuple *tuple, *victim;
+
+ tuple = func->tuples;
+
+ while (tuple && tuple != func->card->tuples) {
+ victim = tuple;
+ tuple = tuple->next;
+ kfree(victim);
+ }
+
+ func->tuples = NULL;
+
+ /*
+ * We have now removed the link to the tuples in the
+ * card structure, so remove the reference.
+ */
+ put_device(&func->card->dev);
+}
+
diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h
new file mode 100644
index 00000000000..4d903c2e425
--- /dev/null
+++ b/drivers/mmc/core/sdio_cis.h
@@ -0,0 +1,23 @@
+/*
+ * linux/drivers/mmc/core/sdio_cis.h
+ *
+ * Author: Nicolas Pitre
+ * Created: June 11, 2007
+ * Copyright: MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef _MMC_SDIO_CIS_H
+#define _MMC_SDIO_CIS_H
+
+int sdio_read_common_cis(struct mmc_card *card);
+void sdio_free_common_cis(struct mmc_card *card);
+
+int sdio_read_func_cis(struct sdio_func *func);
+void sdio_free_func_cis(struct sdio_func *func);
+
+#endif
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
new file mode 100644
index 00000000000..625b92ce9ce
--- /dev/null
+++ b/drivers/mmc/core/sdio_io.c
@@ -0,0 +1,548 @@
+/*
+ * linux/drivers/mmc/core/sdio_io.c
+ *
+ * Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "sdio_ops.h"
+
+/**
+ * sdio_claim_host - exclusively claim a bus for a certain SDIO function
+ * @func: SDIO function that will be accessed
+ *
+ * Claim a bus for a set of operations. The SDIO function given
+ * is used to figure out which bus is relevant.
+ */
+void sdio_claim_host(struct sdio_func *func)
+{
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ mmc_claim_host(func->card->host);
+}
+EXPORT_SYMBOL_GPL(sdio_claim_host);
+
+/**
+ * sdio_release_host - release a bus for a certain SDIO function
+ * @func: SDIO function that was accessed
+ *
+ * Release a bus, allowing others to claim the bus for their
+ * operations.
+ */
+void sdio_release_host(struct sdio_func *func)
+{
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ mmc_release_host(func->card->host);
+}
+EXPORT_SYMBOL_GPL(sdio_release_host);
+
+/**
+ * sdio_enable_func - enables a SDIO function for usage
+ * @func: SDIO function to enable
+ *
+ * Powers up and activates a SDIO function so that register
+ * access is possible.
+ */
+int sdio_enable_func(struct sdio_func *func)
+{
+ int ret;
+ unsigned char reg;
+ unsigned long timeout;
+
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ pr_debug("SDIO: Enabling device %s...\n", sdio_func_id(func));
+
+ ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, &reg);
+ if (ret)
+ goto err;
+
+ reg |= 1 << func->num;
+
+ ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL);
+ if (ret)
+ goto err;
+
+ /*
+ * FIXME: This should timeout based on information in the CIS,
+ * but we don't have card to parse that yet.
+ */
+ timeout = jiffies + HZ;
+
+ while (1) {
+ ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IORx, 0, &reg);
+ if (ret)
+ goto err;
+ if (reg & (1 << func->num))
+ break;
+ ret = -ETIME;
+ if (time_after(jiffies, timeout))
+ goto err;
+ }
+
+ pr_debug("SDIO: Enabled device %s\n", sdio_func_id(func));
+
+ return 0;
+
+err:
+ pr_debug("SDIO: Failed to enable device %s\n", sdio_func_id(func));
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sdio_enable_func);
+
+/**
+ * sdio_disable_func - disable a SDIO function
+ * @func: SDIO function to disable
+ *
+ * Powers down and deactivates a SDIO function. Register access
+ * to this function will fail until the function is reenabled.
+ */
+int sdio_disable_func(struct sdio_func *func)
+{
+ int ret;
+ unsigned char reg;
+
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ pr_debug("SDIO: Disabling device %s...\n", sdio_func_id(func));
+
+ ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, &reg);
+ if (ret)
+ goto err;
+
+ reg &= ~(1 << func->num);
+
+ ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL);
+ if (ret)
+ goto err;
+
+ pr_debug("SDIO: Disabled device %s\n", sdio_func_id(func));
+
+ return 0;
+
+err:
+ pr_debug("SDIO: Failed to disable device %s\n", sdio_func_id(func));
+ return -EIO;
+}
+EXPORT_SYMBOL_GPL(sdio_disable_func);
+
+/**
+ * sdio_set_block_size - set the block size of an SDIO function
+ * @func: SDIO function to change
+ * @blksz: new block size or 0 to use the default.
+ *
+ * The default block size is the largest supported by both the function
+ * and the host, with a maximum of 512 to ensure that arbitrarily sized
+ * data transfer use the optimal (least) number of commands.
+ *
+ * A driver may call this to override the default block size set by the
+ * core. This can be used to set a block size greater than the maximum
+ * that reported by the card; it is the driver's responsibility to ensure
+ * it uses a value that the card supports.
+ *
+ * Returns 0 on success, -EINVAL if the host does not support the
+ * requested block size, or -EIO (etc.) if one of the resultant FBR block
+ * size register writes failed.
+ *
+ */
+int sdio_set_block_size(struct sdio_func *func, unsigned blksz)
+{
+ int ret;
+
+ if (blksz > func->card->host->max_blk_size)
+ return -EINVAL;
+
+ if (blksz == 0) {
+ blksz = min(min(
+ func->max_blksize,
+ func->card->host->max_blk_size),
+ 512u);
+ }
+
+ ret = mmc_io_rw_direct(func->card, 1, 0,
+ SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE,
+ blksz & 0xff, NULL);
+ if (ret)
+ return ret;
+ ret = mmc_io_rw_direct(func->card, 1, 0,
+ SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE + 1,
+ (blksz >> 8) & 0xff, NULL);
+ if (ret)
+ return ret;
+ func->cur_blksize = blksz;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(sdio_set_block_size);
+
+/* Split an arbitrarily sized data transfer into several
+ * IO_RW_EXTENDED commands. */
+static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
+ unsigned addr, int incr_addr, u8 *buf, unsigned size)
+{
+ unsigned remainder = size;
+ unsigned max_blocks;
+ int ret;
+
+ /* Do the bulk of the transfer using block mode (if supported). */
+ if (func->card->cccr.multi_block) {
+ /* Blocks per command is limited by host count, host transfer
+ * size (we only use a single sg entry) and the maximum for
+ * IO_RW_EXTENDED of 511 blocks. */
+ max_blocks = min(min(
+ func->card->host->max_blk_count,
+ func->card->host->max_seg_size / func->cur_blksize),
+ 511u);
+
+ while (remainder > func->cur_blksize) {
+ unsigned blocks;
+
+ blocks = remainder / func->cur_blksize;
+ if (blocks > max_blocks)
+ blocks = max_blocks;
+ size = blocks * func->cur_blksize;
+
+ ret = mmc_io_rw_extended(func->card, write,
+ func->num, addr, incr_addr, buf,
+ blocks, func->cur_blksize);
+ if (ret)
+ return ret;
+
+ remainder -= size;
+ buf += size;
+ if (incr_addr)
+ addr += size;
+ }
+ }
+
+ /* Write the remainder using byte mode. */
+ while (remainder > 0) {
+ size = remainder;
+ if (size > func->cur_blksize)
+ size = func->cur_blksize;
+ if (size > 512)
+ size = 512; /* maximum size for byte mode */
+
+ ret = mmc_io_rw_extended(func->card, write, func->num, addr,
+ incr_addr, buf, 1, size);
+ if (ret)
+ return ret;
+
+ remainder -= size;
+ buf += size;
+ if (incr_addr)
+ addr += size;
+ }
+ return 0;
+}
+
+/**
+ * sdio_readb - read a single byte from a SDIO function
+ * @func: SDIO function to access
+ * @addr: address to read
+ * @err_ret: optional status value from transfer
+ *
+ * Reads a single byte from the address space of a given SDIO
+ * function. If there is a problem reading the address, 0xff
+ * is returned and @err_ret will contain the error code.
+ */
+unsigned char sdio_readb(struct sdio_func *func, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+ unsigned char val;
+
+ BUG_ON(!func);
+
+ if (err_ret)
+ *err_ret = 0;
+
+ ret = mmc_io_rw_direct(func->card, 0, func->num, addr, 0, &val);
+ if (ret) {
+ if (err_ret)
+ *err_ret = ret;
+ return 0xFF;
+ }
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(sdio_readb);
+
+/**
+ * sdio_writeb - write a single byte to a SDIO function
+ * @func: SDIO function to access
+ * @b: byte to write
+ * @addr: address to write to
+ * @err_ret: optional status value from transfer
+ *
+ * Writes a single byte to the address space of a given SDIO
+ * function. @err_ret will contain the status of the actual
+ * transfer.
+ */
+void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+
+ BUG_ON(!func);
+
+ ret = mmc_io_rw_direct(func->card, 1, func->num, addr, b, NULL);
+ if (err_ret)
+ *err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_writeb);
+
+/**
+ * sdio_memcpy_fromio - read a chunk of memory from a SDIO function
+ * @func: SDIO function to access
+ * @dst: buffer to store the data
+ * @addr: address to begin reading from
+ * @count: number of bytes to read
+ *
+ * Reads from the address space of a given SDIO function. Return
+ * value indicates if the transfer succeeded or not.
+ */
+int sdio_memcpy_fromio(struct sdio_func *func, void *dst,
+ unsigned int addr, int count)
+{
+ return sdio_io_rw_ext_helper(func, 0, addr, 1, dst, count);
+}
+EXPORT_SYMBOL_GPL(sdio_memcpy_fromio);
+
+/**
+ * sdio_memcpy_toio - write a chunk of memory to a SDIO function
+ * @func: SDIO function to access
+ * @addr: address to start writing to
+ * @src: buffer that contains the data to write
+ * @count: number of bytes to write
+ *
+ * Writes to the address space of a given SDIO function. Return
+ * value indicates if the transfer succeeded or not.
+ */
+int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr,
+ void *src, int count)
+{
+ return sdio_io_rw_ext_helper(func, 1, addr, 1, src, count);
+}
+EXPORT_SYMBOL_GPL(sdio_memcpy_toio);
+
+/**
+ * sdio_readsb - read from a FIFO on a SDIO function
+ * @func: SDIO function to access
+ * @dst: buffer to store the data
+ * @addr: address of (single byte) FIFO
+ * @count: number of bytes to read
+ *
+ * Reads from the specified FIFO of a given SDIO function. Return
+ * value indicates if the transfer succeeded or not.
+ */
+int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr,
+ int count)
+{
+ return sdio_io_rw_ext_helper(func, 0, addr, 0, dst, count);
+}
+
+EXPORT_SYMBOL_GPL(sdio_readsb);
+
+/**
+ * sdio_writesb - write to a FIFO of a SDIO function
+ * @func: SDIO function to access
+ * @addr: address of (single byte) FIFO
+ * @src: buffer that contains the data to write
+ * @count: number of bytes to write
+ *
+ * Writes to the specified FIFO of a given SDIO function. Return
+ * value indicates if the transfer succeeded or not.
+ */
+int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src,
+ int count)
+{
+ return sdio_io_rw_ext_helper(func, 1, addr, 0, src, count);
+}
+EXPORT_SYMBOL_GPL(sdio_writesb);
+
+/**
+ * sdio_readw - read a 16 bit integer from a SDIO function
+ * @func: SDIO function to access
+ * @addr: address to read
+ * @err_ret: optional status value from transfer
+ *
+ * Reads a 16 bit integer from the address space of a given SDIO
+ * function. If there is a problem reading the address, 0xffff
+ * is returned and @err_ret will contain the error code.
+ */
+unsigned short sdio_readw(struct sdio_func *func, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+
+ if (err_ret)
+ *err_ret = 0;
+
+ ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 2);
+ if (ret) {
+ if (err_ret)
+ *err_ret = ret;
+ return 0xFFFF;
+ }
+
+ return le16_to_cpu(*(u16*)func->tmpbuf);
+}
+EXPORT_SYMBOL_GPL(sdio_readw);
+
+/**
+ * sdio_writew - write a 16 bit integer to a SDIO function
+ * @func: SDIO function to access
+ * @b: integer to write
+ * @addr: address to write to
+ * @err_ret: optional status value from transfer
+ *
+ * Writes a 16 bit integer to the address space of a given SDIO
+ * function. @err_ret will contain the status of the actual
+ * transfer.
+ */
+void sdio_writew(struct sdio_func *func, unsigned short b, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+
+ *(u16*)func->tmpbuf = cpu_to_le16(b);
+
+ ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 2);
+ if (err_ret)
+ *err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_writew);
+
+/**
+ * sdio_readl - read a 32 bit integer from a SDIO function
+ * @func: SDIO function to access
+ * @addr: address to read
+ * @err_ret: optional status value from transfer
+ *
+ * Reads a 32 bit integer from the address space of a given SDIO
+ * function. If there is a problem reading the address,
+ * 0xffffffff is returned and @err_ret will contain the error
+ * code.
+ */
+unsigned long sdio_readl(struct sdio_func *func, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+
+ if (err_ret)
+ *err_ret = 0;
+
+ ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 4);
+ if (ret) {
+ if (err_ret)
+ *err_ret = ret;
+ return 0xFFFFFFFF;
+ }
+
+ return le32_to_cpu(*(u32*)func->tmpbuf);
+}
+EXPORT_SYMBOL_GPL(sdio_readl);
+
+/**
+ * sdio_writel - write a 32 bit integer to a SDIO function
+ * @func: SDIO function to access
+ * @b: integer to write
+ * @addr: address to write to
+ * @err_ret: optional status value from transfer
+ *
+ * Writes a 32 bit integer to the address space of a given SDIO
+ * function. @err_ret will contain the status of the actual
+ * transfer.
+ */
+void sdio_writel(struct sdio_func *func, unsigned long b, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+
+ *(u32*)func->tmpbuf = cpu_to_le32(b);
+
+ ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 4);
+ if (err_ret)
+ *err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_writel);
+
+/**
+ * sdio_f0_readb - read a single byte from SDIO function 0
+ * @func: an SDIO function of the card
+ * @addr: address to read
+ * @err_ret: optional status value from transfer
+ *
+ * Reads a single byte from the address space of SDIO function 0.
+ * If there is a problem reading the address, 0xff is returned
+ * and @err_ret will contain the error code.
+ */
+unsigned char sdio_f0_readb(struct sdio_func *func, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+ unsigned char val;
+
+ BUG_ON(!func);
+
+ if (err_ret)
+ *err_ret = 0;
+
+ ret = mmc_io_rw_direct(func->card, 0, 0, addr, 0, &val);
+ if (ret) {
+ if (err_ret)
+ *err_ret = ret;
+ return 0xFF;
+ }
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(sdio_f0_readb);
+
+/**
+ * sdio_f0_writeb - write a single byte to SDIO function 0
+ * @func: an SDIO function of the card
+ * @b: byte to write
+ * @addr: address to write to
+ * @err_ret: optional status value from transfer
+ *
+ * Writes a single byte to the address space of SDIO function 0.
+ * @err_ret will contain the status of the actual transfer.
+ *
+ * Only writes to the vendor specific CCCR registers (0xF0 -
+ * 0xFF) are permiited; @err_ret will be set to -EINVAL for *
+ * writes outside this range.
+ */
+void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
+ int *err_ret)
+{
+ int ret;
+
+ BUG_ON(!func);
+
+ if (addr < 0xF0 || addr > 0xFF) {
+ if (err_ret)
+ *err_ret = -EINVAL;
+ return;
+ }
+
+ ret = mmc_io_rw_direct(func->card, 1, 0, addr, b, NULL);
+ if (err_ret)
+ *err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_f0_writeb);
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
new file mode 100644
index 00000000000..3bd3021f5e8
--- /dev/null
+++ b/drivers/mmc/core/sdio_irq.c
@@ -0,0 +1,267 @@
+/*
+ * linux/drivers/mmc/core/sdio_irq.c
+ *
+ * Author: Nicolas Pitre
+ * Created: June 18, 2007
+ * Copyright: MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "sdio_ops.h"
+
+static int process_sdio_pending_irqs(struct mmc_card *card)
+{
+ int i, ret, count;
+ unsigned char pending;
+
+ ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
+ if (ret) {
+ printk(KERN_DEBUG "%s: error %d reading SDIO_CCCR_INTx\n",
+ mmc_card_id(card), ret);
+ return ret;
+ }
+
+ count = 0;
+ for (i = 1; i <= 7; i++) {
+ if (pending & (1 << i)) {
+ struct sdio_func *func = card->sdio_func[i - 1];
+ if (!func) {
+ printk(KERN_WARNING "%s: pending IRQ for "
+ "non-existant function\n",
+ mmc_card_id(card));
+ ret = -EINVAL;
+ } else if (func->irq_handler) {
+ func->irq_handler(func);
+ count++;
+ } else {
+ printk(KERN_WARNING "%s: pending IRQ with no handler\n",
+ sdio_func_id(func));
+ ret = -EINVAL;
+ }
+ }
+ }
+
+ if (count)
+ return count;
+
+ return ret;
+}
+
+static int sdio_irq_thread(void *_host)
+{
+ struct mmc_host *host = _host;
+ struct sched_param param = { .sched_priority = 1 };
+ unsigned long period, idle_period;
+ int ret;
+
+ sched_setscheduler(current, SCHED_FIFO, &param);
+
+ /*
+ * We want to allow for SDIO cards to work even on non SDIO
+ * aware hosts. One thing that non SDIO host cannot do is
+ * asynchronous notification of pending SDIO card interrupts
+ * hence we poll for them in that case.
+ */
+ idle_period = msecs_to_jiffies(10);
+ period = (host->caps & MMC_CAP_SDIO_IRQ) ?
+ MAX_SCHEDULE_TIMEOUT : idle_period;
+
+ pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n",
+ mmc_hostname(host), period);
+
+ do {
+ /*
+ * We claim the host here on drivers behalf for a couple
+ * reasons:
+ *
+ * 1) it is already needed to retrieve the CCCR_INTx;
+ * 2) we want the driver(s) to clear the IRQ condition ASAP;
+ * 3) we need to control the abort condition locally.
+ *
+ * Just like traditional hard IRQ handlers, we expect SDIO
+ * IRQ handlers to be quick and to the point, so that the
+ * holding of the host lock does not cover too much work
+ * that doesn't require that lock to be held.
+ */
+ ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
+ if (ret)
+ break;
+ ret = process_sdio_pending_irqs(host->card);
+ mmc_release_host(host);
+
+ /*
+ * Give other threads a chance to run in the presence of
+ * errors. FIXME: determine if due to card removal and
+ * possibly exit this thread if so.
+ */
+ if (ret < 0)
+ ssleep(1);
+
+ /*
+ * Adaptive polling frequency based on the assumption
+ * that an interrupt will be closely followed by more.
+ * This has a substantial benefit for network devices.
+ */
+ if (!(host->caps & MMC_CAP_SDIO_IRQ)) {
+ if (ret > 0)
+ period /= 2;
+ else {
+ period++;
+ if (period > idle_period)
+ period = idle_period;
+ }
+ }
+
+ set_task_state(current, TASK_INTERRUPTIBLE);
+ if (host->caps & MMC_CAP_SDIO_IRQ)
+ host->ops->enable_sdio_irq(host, 1);
+ if (!kthread_should_stop())
+ schedule_timeout(period);
+ set_task_state(current, TASK_RUNNING);
+ } while (!kthread_should_stop());
+
+ if (host->caps & MMC_CAP_SDIO_IRQ)
+ host->ops->enable_sdio_irq(host, 0);
+
+ pr_debug("%s: IRQ thread exiting with code %d\n",
+ mmc_hostname(host), ret);
+
+ return ret;
+}
+
+static int sdio_card_irq_get(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+
+ WARN_ON(!host->claimed);
+
+ if (!host->sdio_irqs++) {
+ atomic_set(&host->sdio_irq_thread_abort, 0);
+ host->sdio_irq_thread =
+ kthread_run(sdio_irq_thread, host, "ksdiorqd");
+ if (IS_ERR(host->sdio_irq_thread)) {
+ int err = PTR_ERR(host->sdio_irq_thread);
+ host->sdio_irqs--;
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int sdio_card_irq_put(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+
+ WARN_ON(!host->claimed);
+ BUG_ON(host->sdio_irqs < 1);
+
+ if (!--host->sdio_irqs) {
+ atomic_set(&host->sdio_irq_thread_abort, 1);
+ kthread_stop(host->sdio_irq_thread);
+ }
+
+ return 0;
+}
+
+/**
+ * sdio_claim_irq - claim the IRQ for a SDIO function
+ * @func: SDIO function
+ * @handler: IRQ handler callback
+ *
+ * Claim and activate the IRQ for the given SDIO function. The provided
+ * handler will be called when that IRQ is asserted. The host is always
+ * claimed already when the handler is called so the handler must not
+ * call sdio_claim_host() nor sdio_release_host().
+ */
+int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
+{
+ int ret;
+ unsigned char reg;
+
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func));
+
+ if (func->irq_handler) {
+ pr_debug("SDIO: IRQ for %s already in use.\n", sdio_func_id(func));
+ return -EBUSY;
+ }
+
+ ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
+ if (ret)
+ return ret;
+
+ reg |= 1 << func->num;
+
+ reg |= 1; /* Master interrupt enable */
+
+ ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
+ if (ret)
+ return ret;
+
+ func->irq_handler = handler;
+ ret = sdio_card_irq_get(func->card);
+ if (ret)
+ func->irq_handler = NULL;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sdio_claim_irq);
+
+/**
+ * sdio_release_irq - release the IRQ for a SDIO function
+ * @func: SDIO function
+ *
+ * Disable and release the IRQ for the given SDIO function.
+ */
+int sdio_release_irq(struct sdio_func *func)
+{
+ int ret;
+ unsigned char reg;
+
+ BUG_ON(!func);
+ BUG_ON(!func->card);
+
+ pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func));
+
+ if (func->irq_handler) {
+ func->irq_handler = NULL;
+ sdio_card_irq_put(func->card);
+ }
+
+ ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
+ if (ret)
+ return ret;
+
+ reg &= ~(1 << func->num);
+
+ /* Disable master interrupt with the last function interrupt */
+ if (!(reg & 0xFE))
+ reg = 0;
+
+ ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sdio_release_irq);
+
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
new file mode 100644
index 00000000000..e1fca588e38
--- /dev/null
+++ b/drivers/mmc/core/sdio_ops.c
@@ -0,0 +1,175 @@
+/*
+ * linux/drivers/mmc/sdio_ops.c
+ *
+ * Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/scatterlist.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+
+#include "core.h"
+
+int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+ struct mmc_command cmd;
+ int i, err = 0;
+
+ BUG_ON(!host);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_IO_SEND_OP_COND;
+ cmd.arg = ocr;
+ cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;
+
+ for (i = 100; i; i--) {
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+ if (err)
+ break;
+
+ /* if we're just probing, do a single pass */
+ if (ocr == 0)
+ break;
+
+ /* otherwise wait until reset completes */
+ if (mmc_host_is_spi(host)) {
+ /*
+ * Both R1_SPI_IDLE and MMC_CARD_BUSY indicate
+ * an initialized card under SPI, but some cards
+ * (Marvell's) only behave when looking at this
+ * one.
+ */
+ if (cmd.resp[1] & MMC_CARD_BUSY)
+ break;
+ } else {
+ if (cmd.resp[0] & MMC_CARD_BUSY)
+ break;
+ }
+
+ err = -ETIMEDOUT;
+
+ mmc_delay(10);
+ }
+
+ if (rocr)
+ *rocr = cmd.resp[mmc_host_is_spi(host) ? 1 : 0];
+
+ return err;
+}
+
+int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
+ unsigned addr, u8 in, u8* out)
+{
+ struct mmc_command cmd;
+ int err;
+
+ BUG_ON(!card);
+ BUG_ON(fn > 7);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_IO_RW_DIRECT;
+ cmd.arg = write ? 0x80000000 : 0x00000000;
+ cmd.arg |= fn << 28;
+ cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
+ cmd.arg |= addr << 9;
+ cmd.arg |= in;
+ cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if (err)
+ return err;
+
+ if (mmc_host_is_spi(card->host)) {
+ /* host driver already reported errors */
+ } else {
+ if (cmd.resp[0] & R5_ERROR)
+ return -EIO;
+ if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+ return -EINVAL;
+ if (cmd.resp[0] & R5_OUT_OF_RANGE)
+ return -ERANGE;
+ }
+
+ if (out) {
+ if (mmc_host_is_spi(card->host))
+ *out = (cmd.resp[0] >> 8) & 0xFF;
+ else
+ *out = cmd.resp[0] & 0xFF;
+ }
+
+ return 0;
+}
+
+int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
+ unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
+{
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ struct scatterlist sg;
+
+ BUG_ON(!card);
+ BUG_ON(fn > 7);
+ BUG_ON(blocks == 1 && blksz > 512);
+ WARN_ON(blocks == 0);
+ WARN_ON(blksz == 0);
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ cmd.opcode = SD_IO_RW_EXTENDED;
+ cmd.arg = write ? 0x80000000 : 0x00000000;
+ cmd.arg |= fn << 28;
+ cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
+ cmd.arg |= addr << 9;
+ if (blocks == 1 && blksz <= 512)
+ cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */
+ else
+ cmd.arg |= 0x08000000 | blocks; /* block mode */
+ cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
+
+ data.blksz = blksz;
+ data.blocks = blocks;
+ data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ sg_init_one(&sg, buf, blksz * blocks);
+
+ mmc_set_data_timeout(&data, card);
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ if (cmd.error)
+ return cmd.error;
+ if (data.error)
+ return data.error;
+
+ if (mmc_host_is_spi(card->host)) {
+ /* host driver already reported errors */
+ } else {
+ if (cmd.resp[0] & R5_ERROR)
+ return -EIO;
+ if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+ return -EINVAL;
+ if (cmd.resp[0] & R5_OUT_OF_RANGE)
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h
new file mode 100644
index 00000000000..e2e74b0d17d
--- /dev/null
+++ b/drivers/mmc/core/sdio_ops.h
@@ -0,0 +1,22 @@
+/*
+ * linux/drivers/mmc/sdio_ops.c
+ *
+ * Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef _MMC_SDIO_OPS_H
+#define _MMC_SDIO_OPS_H
+
+int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
+int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
+ unsigned addr, u8 in, u8* out);
+int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
+ unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
+
+#endif
+
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index e23082fe88d..5fef6783c71 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -35,6 +35,23 @@ config MMC_SDHCI
If unsure, say N.
+config MMC_RICOH_MMC
+ tristate "Ricoh MMC Controller Disabler (EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL && MMC_SDHCI
+ help
+ This selects the disabler for the Ricoh MMC Controller. This
+ proprietary controller is unnecessary because the SDHCI driver
+ supports MMC cards on the SD controller, but if it is not
+ disabled, it will steal the MMC cards away - rendering them
+ useless. It is safe to select this driver even if you don't
+ have a Ricoh based card reader.
+
+
+ To compile this driver as a module, choose M here:
+ the module will be called ricoh_mmc.
+
+ If unsure, say Y.
+
config MMC_OMAP
tristate "TI OMAP Multimedia Card Interface support"
depends on ARCH_OMAP
@@ -100,3 +117,16 @@ config MMC_TIFM_SD
To compile this driver as a module, choose M here: the
module will be called tifm_sd.
+config MMC_SPI
+ tristate "MMC/SD over SPI (EXPERIMENTAL)"
+ depends on MMC && SPI_MASTER && !HIGHMEM && EXPERIMENTAL
+ select CRC7
+ select CRC_ITU_T
+ help
+ Some systems accss MMC/SD cards using a SPI controller instead of
+ using a "native" MMC/SD controller. This has a disadvantage of
+ being relatively high overhead, but a compensating advantage of
+ working on many systems without dedicated MMC/SD controllers.
+
+ If unsure, or if your system has no SPI master driver, say N.
+
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 6685f64345b..3877c87e6da 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -10,9 +10,11 @@ obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_IMX) += imxmmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
+obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_AT91) += at91_mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
+obj-$(CONFIG_MMC_SPI) += mmc_spi.o
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 955ea60583b..b1edcefdd4f 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -149,7 +149,7 @@ static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data
sg = &data->sg[i];
- sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+ sgbuffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
amount = min(size, sg->length);
size -= amount;
@@ -226,7 +226,7 @@ static void at91_mci_pre_dma_read(struct at91mci_host *host)
sg = &data->sg[host->transfer_index++];
pr_debug("sg = %p\n", sg);
- sg->dma_address = dma_map_page(NULL, sg->page, sg->offset, sg->length, DMA_FROM_DEVICE);
+ sg->dma_address = dma_map_page(NULL, sg_page(sg), sg->offset, sg->length, DMA_FROM_DEVICE);
pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
@@ -283,7 +283,7 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
int index;
/* Swap the contents of the buffer */
- buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+ buffer = kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
pr_debug("buffer = %p, length = %d\n", buffer, sg->length);
for (index = 0; index < (sg->length / 4); index++)
@@ -292,7 +292,7 @@ static void at91_mci_post_dma_read(struct at91mci_host *host)
kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
}
- flush_dcache_page(sg->page);
+ flush_dcache_page(sg_page(sg));
}
/* Is there another transfer to trigger? */
@@ -328,7 +328,7 @@ static void at91_mci_handle_transmitted(struct at91mci_host *host)
data = cmd->data;
if (!data) return;
- if (cmd->data->flags & MMC_DATA_MULTI) {
+ if (cmd->data->blocks > 1) {
pr_debug("multiple write : wait for BLKE...\n");
at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE);
} else
@@ -428,6 +428,14 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command
}
if (data) {
+
+ if ( data->blksz & 0x3 ) {
+ pr_debug("Unsupported block size\n");
+ cmd->error = -EINVAL;
+ mmc_request_done(host->mmc, host->request);
+ return;
+ }
+
block_length = data->blksz;
blocks = data->blocks;
@@ -439,7 +447,7 @@ static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command
if (data->flags & MMC_DATA_STREAM)
cmdr |= AT91_MCI_TRTYP_STREAM;
- if (data->flags & MMC_DATA_MULTI)
+ if (data->blocks > 1)
cmdr |= AT91_MCI_TRTYP_MULTIPLE;
}
else {
@@ -573,28 +581,24 @@ static void at91_mci_completed_command(struct at91mci_host *host)
pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
- if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE |
- AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |
- AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {
+ if (status & AT91_MCI_ERRORS) {
if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) {
- cmd->error = MMC_ERR_NONE;
+ cmd->error = 0;
}
else {
if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE))
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ETIMEDOUT;
else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE))
- cmd->error = MMC_ERR_BADCRC;
- else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE))
- cmd->error = MMC_ERR_FIFO;
+ cmd->error = -EILSEQ;
else
- cmd->error = MMC_ERR_FAILED;
+ cmd->error = -EIO;
pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n",
cmd->error, cmd->opcode, cmd->retries);
}
}
else
- cmd->error = MMC_ERR_NONE;
+ cmd->error = 0;
at91_mci_process_next(host);
}
@@ -836,7 +840,6 @@ static int __init at91_mci_probe(struct platform_device *pdev)
mmc->f_min = 375000;
mmc->f_max = 25000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = MMC_CAP_BYTEBLOCK;
mmc->max_blk_size = 4095;
mmc->max_blk_count = mmc->max_req_size;
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index 34c99d4ea04..c3926eb3bf4 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -40,13 +40,13 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
#include <linux/mmc/host.h>
#include <asm/io.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
#include <asm/mach-au1x00/au1100_mmc.h>
-#include <asm/scatterlist.h>
#include <au1xxx.h>
#include "au1xmmc.h"
@@ -186,7 +186,7 @@ static void au1xmmc_tasklet_finish(unsigned long param)
}
static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
- struct mmc_command *cmd, unsigned int flags)
+ struct mmc_command *cmd, struct mmc_data *data)
{
u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
@@ -208,19 +208,21 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
default:
printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
mmc_resp_type(cmd));
- return MMC_ERR_INVALID;
+ return -EINVAL;
}
- if (flags & MMC_DATA_READ) {
- if (flags & MMC_DATA_MULTI)
- mmccmd |= SD_CMD_CT_4;
- else
- mmccmd |= SD_CMD_CT_2;
- } else if (flags & MMC_DATA_WRITE) {
- if (flags & MMC_DATA_MULTI)
- mmccmd |= SD_CMD_CT_3;
- else
- mmccmd |= SD_CMD_CT_1;
+ if (data) {
+ if (data->flags & MMC_DATA_READ) {
+ if (data->blocks > 1)
+ mmccmd |= SD_CMD_CT_4;
+ else
+ mmccmd |= SD_CMD_CT_2;
+ } else if (data->flags & MMC_DATA_WRITE) {
+ if (data->blocks > 1)
+ mmccmd |= SD_CMD_CT_3;
+ else
+ mmccmd |= SD_CMD_CT_1;
+ }
}
au_writel(cmd->arg, HOST_CMDARG(host));
@@ -253,7 +255,7 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
IRQ_ON(host, SD_CONFIG_CR);
}
- return MMC_ERR_NONE;
+ return 0;
}
static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
@@ -278,7 +280,7 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
status = au_readl(HOST_STATUS(host));
- data->error = MMC_ERR_NONE;
+ data->error = 0;
dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir);
/* Process any errors */
@@ -288,14 +290,14 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
crc |= ((status & 0x07) == 0x02) ? 0 : 1;
if (crc)
- data->error = MMC_ERR_BADCRC;
+ data->error = -EILSEQ;
/* Clear the CRC bits */
au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host));
data->bytes_xfered = 0;
- if (data->error == MMC_ERR_NONE) {
+ if (!data->error) {
if (host->flags & HOST_F_DMA) {
u32 chan = DMA_CHANNEL(host);
@@ -338,7 +340,7 @@ static void au1xmmc_send_pio(struct au1xmmc_host *host)
/* This is the pointer to the data buffer */
sg = &data->sg[host->pio.index];
- sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
+ sg_ptr = sg_virt(sg) + host->pio.offset;
/* This is the space left inside the buffer */
sg_len = data->sg[host->pio.index].length - host->pio.offset;
@@ -398,7 +400,7 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host)
if (host->pio.index < host->dma.len) {
sg = &data->sg[host->pio.index];
- sg_ptr = page_address(sg->page) + sg->offset + host->pio.offset;
+ sg_ptr = sg_virt(sg) + host->pio.offset;
/* This is the space left inside the buffer */
sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
@@ -475,7 +477,7 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
return;
cmd = mrq->cmd;
- cmd->error = MMC_ERR_NONE;
+ cmd->error = 0;
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) {
@@ -512,11 +514,11 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
/* Figure out errors */
if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC))
- cmd->error = MMC_ERR_BADCRC;
+ cmd->error = -EILSEQ;
trans = host->flags & (HOST_F_XMIT | HOST_F_RECV);
- if (!trans || cmd->error != MMC_ERR_NONE) {
+ if (!trans || cmd->error) {
IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA|SD_CONFIG_RF);
tasklet_schedule(&host->finish_task);
@@ -589,7 +591,7 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
data->sg_len, host->dma.dir);
if (host->dma.len == 0)
- return MMC_ERR_TIMEOUT;
+ return -ETIMEDOUT;
au_writel(data->blksz - 1, HOST_BLKSIZE(host));
@@ -611,14 +613,11 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
if (host->flags & HOST_F_XMIT){
ret = au1xxx_dbdma_put_source_flags(channel,
- (void *) (page_address(sg->page) +
- sg->offset),
- len, flags);
+ (void *) sg_virt(sg), len, flags);
}
else {
ret = au1xxx_dbdma_put_dest_flags(channel,
- (void *) (page_address(sg->page) +
- sg->offset),
+ (void *) sg_virt(sg),
len, flags);
}
@@ -640,11 +639,11 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data)
//IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF);
}
- return MMC_ERR_NONE;
+ return 0;
dataerr:
dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir);
- return MMC_ERR_TIMEOUT;
+ return -ETIMEDOUT;
}
/* static void au1xmmc_request
@@ -656,7 +655,7 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
struct au1xmmc_host *host = mmc_priv(mmc);
unsigned int flags = 0;
- int ret = MMC_ERR_NONE;
+ int ret = 0;
WARN_ON(irqs_disabled());
WARN_ON(host->status != HOST_S_IDLE);
@@ -672,10 +671,10 @@ static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
ret = au1xmmc_prepare_data(host, mrq->data);
}
- if (ret == MMC_ERR_NONE)
- ret = au1xmmc_send_command(host, 0, mrq->cmd, flags);
+ if (!ret)
+ ret = au1xmmc_send_command(host, 0, mrq->cmd, mrq->data);
- if (ret != MMC_ERR_NONE) {
+ if (ret) {
mrq->cmd->error = ret;
au1xmmc_finish_request(host);
}
@@ -764,10 +763,10 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
if (host->mrq && (status & STATUS_TIMEOUT)) {
if (status & SD_STATUS_RAT)
- host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+ host->mrq->cmd->error = -ETIMEDOUT;
else if (status & SD_STATUS_DT)
- host->mrq->data->error = MMC_ERR_TIMEOUT;
+ host->mrq->data->error = -ETIMEDOUT;
/* In PIO mode, interrupts might still be enabled */
IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c
index 54bfc9f2559..f2070a19cfa 100644
--- a/drivers/mmc/host/imxmmc.c
+++ b/drivers/mmc/host/imxmmc.c
@@ -262,7 +262,7 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
}
/* Convert back to virtual address */
- host->data_ptr = (u16*)(page_address(data->sg->page) + data->sg->offset);
+ host->data_ptr = (u16*)sg_virt(data->sg);
host->data_cnt = 0;
clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
@@ -428,11 +428,11 @@ static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat)
if ( stat & STATUS_ERR_MASK ) {
dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",stat);
if(stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR))
- data->error = MMC_ERR_BADCRC;
+ data->error = -EILSEQ;
else if(stat & STATUS_TIME_OUT_READ)
- data->error = MMC_ERR_TIMEOUT;
+ data->error = -ETIMEDOUT;
else
- data->error = MMC_ERR_FAILED;
+ data->error = -EIO;
} else {
data->bytes_xfered = host->dma_size;
}
@@ -458,10 +458,10 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
if (stat & STATUS_TIME_OUT_RESP) {
dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n");
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ETIMEDOUT;
} else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
dev_dbg(mmc_dev(host->mmc), "cmd crc error\n");
- cmd->error = MMC_ERR_BADCRC;
+ cmd->error = -EILSEQ;
}
if(cmd->flags & MMC_RSP_PRESENT) {
@@ -482,7 +482,7 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n",
cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error);
- if (data && (cmd->error == MMC_ERR_NONE) && !(stat & STATUS_ERR_MASK)) {
+ if (data && !cmd->error && !(stat & STATUS_ERR_MASK)) {
if (host->req->data->flags & MMC_DATA_WRITE) {
/* Wait for FIFO to be empty before starting DMA write */
@@ -491,7 +491,7 @@ static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
if(imxmci_busy_wait_for_status(host, &stat,
STATUS_APPL_BUFF_FE,
40, "imxmci_cmd_done DMA WR") < 0) {
- cmd->error = MMC_ERR_FIFO;
+ cmd->error = -EIO;
imxmci_finish_data(host, stat);
if(host->req)
imxmci_finish_request(host, host->req);
@@ -884,9 +884,21 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
}
+static int imxmci_get_ro(struct mmc_host *mmc)
+{
+ struct imxmci_host *host = mmc_priv(mmc);
+
+ if (host->pdata && host->pdata->get_ro)
+ return host->pdata->get_ro(mmc_dev(mmc));
+ /* Host doesn't support read only detection so assume writeable */
+ return 0;
+}
+
+
static const struct mmc_host_ops imxmci_ops = {
.request = imxmci_request,
.set_ios = imxmci_set_ios,
+ .get_ro = imxmci_get_ro,
};
static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr)
@@ -913,7 +925,7 @@ static void imxmci_check_status(unsigned long data)
{
struct imxmci_host *host = (struct imxmci_host *)data;
- if( host->pdata->card_present() != host->present ) {
+ if( host->pdata->card_present(mmc_dev(host->mmc)) != host->present ) {
host->present ^= 1;
dev_info(mmc_dev(host->mmc), "card %s\n",
host->present ? "inserted" : "removed");
@@ -963,7 +975,7 @@ static int imxmci_probe(struct platform_device *pdev)
mmc->f_min = 150000;
mmc->f_max = CLK_RATE/2;
mmc->ocr_avail = MMC_VDD_32_33;
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_BYTEBLOCK;
+ mmc->caps = MMC_CAP_4_BIT_DATA;
/* MMC core transfer sizes tunable parameters */
mmc->max_hw_segs = 64;
@@ -1022,7 +1034,7 @@ static int imxmci_probe(struct platform_device *pdev)
if (ret)
goto out;
- host->present = host->pdata->card_present();
+ host->present = host->pdata->card_present(mmc_dev(mmc));
init_timer(&host->timer);
host->timer.data = (unsigned long)host;
host->timer.function = imxmci_check_status;
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
new file mode 100644
index 00000000000..a6469218f19
--- /dev/null
+++ b/drivers/mmc/host/mmc_spi.c
@@ -0,0 +1,1423 @@
+/*
+ * mmc_spi.c - Access SD/MMC cards through SPI master controllers
+ *
+ * (C) Copyright 2005, Intec Automation,
+ * Mike Lavender (mike@steroidmicros)
+ * (C) Copyright 2006-2007, David Brownell
+ * (C) Copyright 2007, Axis Communications,
+ * Hans-Peter Nilsson (hp@axis.com)
+ * (C) Copyright 2007, ATRON electronic GmbH,
+ * Jan Nikitenko <jan.nikitenko@gmail.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/bio.h>
+#include <linux/dma-mapping.h>
+#include <linux/crc7.h>
+#include <linux/crc-itu-t.h>
+#include <linux/scatterlist.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h> /* for R1_SPI_* bit values */
+
+#include <linux/spi/spi.h>
+#include <linux/spi/mmc_spi.h>
+
+#include <asm/unaligned.h>
+
+
+/* NOTES:
+ *
+ * - For now, we won't try to interoperate with a real mmc/sd/sdio
+ * controller, although some of them do have hardware support for
+ * SPI protocol. The main reason for such configs would be mmc-ish
+ * cards like DataFlash, which don't support that "native" protocol.
+ *
+ * We don't have a "DataFlash/MMC/SD/SDIO card slot" abstraction to
+ * switch between driver stacks, and in any case if "native" mode
+ * is available, it will be faster and hence preferable.
+ *
+ * - MMC depends on a different chipselect management policy than the
+ * SPI interface currently supports for shared bus segments: it needs
+ * to issue multiple spi_message requests with the chipselect active,
+ * using the results of one message to decide the next one to issue.
+ *
+ * Pending updates to the programming interface, this driver expects
+ * that it not share the bus with other drivers (precluding conflicts).
+ *
+ * - We tell the controller to keep the chipselect active from the
+ * beginning of an mmc_host_ops.request until the end. So beware
+ * of SPI controller drivers that mis-handle the cs_change flag!
+ *
+ * However, many cards seem OK with chipselect flapping up/down
+ * during that time ... at least on unshared bus segments.
+ */
+
+
+/*
+ * Local protocol constants, internal to data block protocols.
+ */
+
+/* Response tokens used to ack each block written: */
+#define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f)
+#define SPI_RESPONSE_ACCEPTED ((2 << 1)|1)
+#define SPI_RESPONSE_CRC_ERR ((5 << 1)|1)
+#define SPI_RESPONSE_WRITE_ERR ((6 << 1)|1)
+
+/* Read and write blocks start with these tokens and end with crc;
+ * on error, read tokens act like a subset of R2_SPI_* values.
+ */
+#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */
+#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */
+#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */
+
+#define MMC_SPI_BLOCKSIZE 512
+
+
+/* These fixed timeouts come from the latest SD specs, which say to ignore
+ * the CSD values. The R1B value is for card erase (e.g. the "I forgot the
+ * card's password" scenario); it's mostly applied to STOP_TRANSMISSION after
+ * reads which takes nowhere near that long. Older cards may be able to use
+ * shorter timeouts ... but why bother?
+ */
+#define readblock_timeout ktime_set(0, 100 * 1000 * 1000)
+#define writeblock_timeout ktime_set(0, 250 * 1000 * 1000)
+#define r1b_timeout ktime_set(3, 0)
+
+
+/****************************************************************************/
+
+/*
+ * Local Data Structures
+ */
+
+/* "scratch" is per-{command,block} data exchanged with the card */
+struct scratch {
+ u8 status[29];
+ u8 data_token;
+ __be16 crc_val;
+};
+
+struct mmc_spi_host {
+ struct mmc_host *mmc;
+ struct spi_device *spi;
+
+ unsigned char power_mode;
+ u16 powerup_msecs;
+
+ struct mmc_spi_platform_data *pdata;
+
+ /* for bulk data transfers */
+ struct spi_transfer token, t, crc, early_status;
+ struct spi_message m;
+
+ /* for status readback */
+ struct spi_transfer status;
+ struct spi_message readback;
+
+ /* underlying DMA-aware controller, or null */
+ struct device *dma_dev;
+
+ /* buffer used for commands and for message "overhead" */
+ struct scratch *data;
+ dma_addr_t data_dma;
+
+ /* Specs say to write ones most of the time, even when the card
+ * has no need to read its input data; and many cards won't care.
+ * This is our source of those ones.
+ */
+ void *ones;
+ dma_addr_t ones_dma;
+};
+
+
+/****************************************************************************/
+
+/*
+ * MMC-over-SPI protocol glue, used by the MMC stack interface
+ */
+
+static inline int mmc_cs_off(struct mmc_spi_host *host)
+{
+ /* chipselect will always be inactive after setup() */
+ return spi_setup(host->spi);
+}
+
+static int
+mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len)
+{
+ int status;
+
+ if (len > sizeof(*host->data)) {
+ WARN_ON(1);
+ return -EIO;
+ }
+
+ host->status.len = len;
+
+ if (host->dma_dev)
+ dma_sync_single_for_device(host->dma_dev,
+ host->data_dma, sizeof(*host->data),
+ DMA_FROM_DEVICE);
+
+ status = spi_sync(host->spi, &host->readback);
+ if (status == 0)
+ status = host->readback.status;
+
+ if (host->dma_dev)
+ dma_sync_single_for_cpu(host->dma_dev,
+ host->data_dma, sizeof(*host->data),
+ DMA_FROM_DEVICE);
+
+ return status;
+}
+
+static int
+mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte)
+{
+ u8 *cp = host->data->status;
+
+ timeout = ktime_add(timeout, ktime_get());
+
+ while (1) {
+ int status;
+ unsigned i;
+
+ status = mmc_spi_readbytes(host, n);
+ if (status < 0)
+ return status;
+
+ for (i = 0; i < n; i++) {
+ if (cp[i] != byte)
+ return cp[i];
+ }
+
+ /* REVISIT investigate msleep() to avoid busy-wait I/O
+ * in at least some cases.
+ */
+ if (ktime_to_ns(ktime_sub(ktime_get(), timeout)) > 0)
+ break;
+ }
+ return -ETIMEDOUT;
+}
+
+static inline int
+mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout)
+{
+ return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);
+}
+
+static int mmc_spi_readtoken(struct mmc_spi_host *host)
+{
+ return mmc_spi_skip(host, readblock_timeout, 1, 0xff);
+}
+
+
+/*
+ * Note that for SPI, cmd->resp[0] is not the same data as "native" protocol
+ * hosts return! The low byte holds R1_SPI bits. The next byte may hold
+ * R2_SPI bits ... for SEND_STATUS, or after data read errors.
+ *
+ * cmd->resp[1] holds any four-byte response, for R3 (READ_OCR) and on
+ * newer cards R7 (IF_COND).
+ */
+
+static char *maptype(struct mmc_command *cmd)
+{
+ switch (mmc_spi_resp_type(cmd)) {
+ case MMC_RSP_SPI_R1: return "R1";
+ case MMC_RSP_SPI_R1B: return "R1B";
+ case MMC_RSP_SPI_R2: return "R2/R5";
+ case MMC_RSP_SPI_R3: return "R3/R4/R7";
+ default: return "?";
+ }
+}
+
+/* return zero, else negative errno after setting cmd->error */
+static int mmc_spi_response_get(struct mmc_spi_host *host,
+ struct mmc_command *cmd, int cs_on)
+{
+ u8 *cp = host->data->status;
+ u8 *end = cp + host->t.len;
+ int value = 0;
+ char tag[32];
+
+ snprintf(tag, sizeof(tag), " ... CMD%d response SPI_%s",
+ cmd->opcode, maptype(cmd));
+
+ /* Except for data block reads, the whole response will already
+ * be stored in the scratch buffer. It's somewhere after the
+ * command and the first byte we read after it. We ignore that
+ * first byte. After STOP_TRANSMISSION command it may include
+ * two data bits, but otherwise it's all ones.
+ */
+ cp += 8;
+ while (cp < end && *cp == 0xff)
+ cp++;
+
+ /* Data block reads (R1 response types) may need more data... */
+ if (cp == end) {
+ unsigned i;
+
+ cp = host->data->status;
+
+ /* Card sends N(CR) (== 1..8) bytes of all-ones then one
+ * status byte ... and we already scanned 2 bytes.
+ *
+ * REVISIT block read paths use nasty byte-at-a-time I/O
+ * so it can always DMA directly into the target buffer.
+ * It'd probably be better to memcpy() the first chunk and
+ * avoid extra i/o calls...
+ */
+ for (i = 2; i < 9; i++) {
+ value = mmc_spi_readbytes(host, 1);
+ if (value < 0)
+ goto done;
+ if (*cp != 0xff)
+ goto checkstatus;
+ }
+ value = -ETIMEDOUT;
+ goto done;
+ }
+
+checkstatus:
+ if (*cp & 0x80) {
+ dev_dbg(&host->spi->dev, "%s: INVALID RESPONSE, %02x\n",
+ tag, *cp);
+ value = -EBADR;
+ goto done;
+ }
+
+ cmd->resp[0] = *cp++;
+ cmd->error = 0;
+
+ /* Status byte: the entire seven-bit R1 response. */
+ if (cmd->resp[0] != 0) {
+ if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS
+ | R1_SPI_ILLEGAL_COMMAND)
+ & cmd->resp[0])
+ value = -EINVAL;
+ else if (R1_SPI_COM_CRC & cmd->resp[0])
+ value = -EILSEQ;
+ else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET)
+ & cmd->resp[0])
+ value = -EIO;
+ /* else R1_SPI_IDLE, "it's resetting" */
+ }
+
+ switch (mmc_spi_resp_type(cmd)) {
+
+ /* SPI R1B == R1 + busy; STOP_TRANSMISSION (for multiblock reads)
+ * and less-common stuff like various erase operations.
+ */
+ case MMC_RSP_SPI_R1B:
+ /* maybe we read all the busy tokens already */
+ while (cp < end && *cp == 0)
+ cp++;
+ if (cp == end)
+ mmc_spi_wait_unbusy(host, r1b_timeout);
+ break;
+
+ /* SPI R2 == R1 + second status byte; SEND_STATUS
+ * SPI R5 == R1 + data byte; IO_RW_DIRECT
+ */
+ case MMC_RSP_SPI_R2:
+ cmd->resp[0] |= *cp << 8;
+ break;
+
+ /* SPI R3, R4, or R7 == R1 + 4 bytes */
+ case MMC_RSP_SPI_R3:
+ cmd->resp[1] = be32_to_cpu(get_unaligned((u32 *)cp));
+ break;
+
+ /* SPI R1 == just one status byte */
+ case MMC_RSP_SPI_R1:
+ break;
+
+ default:
+ dev_dbg(&host->spi->dev, "bad response type %04x\n",
+ mmc_spi_resp_type(cmd));
+ if (value >= 0)
+ value = -EINVAL;
+ goto done;
+ }
+
+ if (value < 0)
+ dev_dbg(&host->spi->dev, "%s: resp %04x %08x\n",
+ tag, cmd->resp[0], cmd->resp[1]);
+
+ /* disable chipselect on errors and some success cases */
+ if (value >= 0 && cs_on)
+ return value;
+done:
+ if (value < 0)
+ cmd->error = value;
+ mmc_cs_off(host);
+ return value;
+}
+
+/* Issue command and read its response.
+ * Returns zero on success, negative for error.
+ *
+ * On error, caller must cope with mmc core retry mechanism. That
+ * means immediate low-level resubmit, which affects the bus lock...
+ */
+static int
+mmc_spi_command_send(struct mmc_spi_host *host,
+ struct mmc_request *mrq,
+ struct mmc_command *cmd, int cs_on)
+{
+ struct scratch *data = host->data;
+ u8 *cp = data->status;
+ u32 arg = cmd->arg;
+ int status;
+ struct spi_transfer *t;
+
+ /* We can handle most commands (except block reads) in one full
+ * duplex I/O operation before either starting the next transfer
+ * (data block or command) or else deselecting the card.
+ *
+ * First, write 7 bytes:
+ * - an all-ones byte to ensure the card is ready
+ * - opcode byte (plus start and transmission bits)
+ * - four bytes of big-endian argument
+ * - crc7 (plus end bit) ... always computed, it's cheap
+ *
+ * We init the whole buffer to all-ones, which is what we need
+ * to write while we're reading (later) response data.
+ */
+ memset(cp++, 0xff, sizeof(data->status));
+
+ *cp++ = 0x40 | cmd->opcode;
+ *cp++ = (u8)(arg >> 24);
+ *cp++ = (u8)(arg >> 16);
+ *cp++ = (u8)(arg >> 8);
+ *cp++ = (u8)arg;
+ *cp++ = (crc7(0, &data->status[1], 5) << 1) | 0x01;
+
+ /* Then, read up to 13 bytes (while writing all-ones):
+ * - N(CR) (== 1..8) bytes of all-ones
+ * - status byte (for all response types)
+ * - the rest of the response, either:
+ * + nothing, for R1 or R1B responses
+ * + second status byte, for R2 responses
+ * + four data bytes, for R3 and R7 responses
+ *
+ * Finally, read some more bytes ... in the nice cases we know in
+ * advance how many, and reading 1 more is always OK:
+ * - N(EC) (== 0..N) bytes of all-ones, before deselect/finish
+ * - N(RC) (== 1..N) bytes of all-ones, before next command
+ * - N(WR) (== 1..N) bytes of all-ones, before data write
+ *
+ * So in those cases one full duplex I/O of at most 21 bytes will
+ * handle the whole command, leaving the card ready to receive a
+ * data block or new command. We do that whenever we can, shaving
+ * CPU and IRQ costs (especially when using DMA or FIFOs).
+ *
+ * There are two other cases, where it's not generally practical
+ * to rely on a single I/O:
+ *
+ * - R1B responses need at least N(EC) bytes of all-zeroes.
+ *
+ * In this case we can *try* to fit it into one I/O, then
+ * maybe read more data later.
+ *
+ * - Data block reads are more troublesome, since a variable
+ * number of padding bytes precede the token and data.
+ * + N(CX) (== 0..8) bytes of all-ones, before CSD or CID
+ * + N(AC) (== 1..many) bytes of all-ones
+ *
+ * In this case we currently only have minimal speedups here:
+ * when N(CR) == 1 we can avoid I/O in response_get().
+ */
+ if (cs_on && (mrq->data->flags & MMC_DATA_READ)) {
+ cp += 2; /* min(N(CR)) + status */
+ /* R1 */
+ } else {
+ cp += 10; /* max(N(CR)) + status + min(N(RC),N(WR)) */
+ if (cmd->flags & MMC_RSP_SPI_S2) /* R2/R5 */
+ cp++;
+ else if (cmd->flags & MMC_RSP_SPI_B4) /* R3/R4/R7 */
+ cp += 4;
+ else if (cmd->flags & MMC_RSP_BUSY) /* R1B */
+ cp = data->status + sizeof(data->status);
+ /* else: R1 (most commands) */
+ }
+
+ dev_dbg(&host->spi->dev, " mmc_spi: CMD%d, resp %s\n",
+ cmd->opcode, maptype(cmd));
+
+ /* send command, leaving chipselect active */
+ spi_message_init(&host->m);
+
+ t = &host->t;
+ memset(t, 0, sizeof(*t));
+ t->tx_buf = t->rx_buf = data->status;
+ t->tx_dma = t->rx_dma = host->data_dma;
+ t->len = cp - data->status;
+ t->cs_change = 1;
+ spi_message_add_tail(t, &host->m);
+
+ if (host->dma_dev) {
+ host->m.is_dma_mapped = 1;
+ dma_sync_single_for_device(host->dma_dev,
+ host->data_dma, sizeof(*host->data),
+ DMA_BIDIRECTIONAL);
+ }
+ status = spi_sync(host->spi, &host->m);
+ if (status == 0)
+ status = host->m.status;
+
+ if (host->dma_dev)
+ dma_sync_single_for_cpu(host->dma_dev,
+ host->data_dma, sizeof(*host->data),
+ DMA_BIDIRECTIONAL);
+ if (status < 0) {
+ dev_dbg(&host->spi->dev, " ... write returned %d\n", status);
+ cmd->error = status;
+ return status;
+ }
+
+ /* after no-data commands and STOP_TRANSMISSION, chipselect off */
+ return mmc_spi_response_get(host, cmd, cs_on);
+}
+
+/* Build data message with up to four separate transfers. For TX, we
+ * start by writing the data token. And in most cases, we finish with
+ * a status transfer.
+ *
+ * We always provide TX data for data and CRC. The MMC/SD protocol
+ * requires us to write ones; but Linux defaults to writing zeroes;
+ * so we explicitly initialize it to all ones on RX paths.
+ *
+ * We also handle DMA mapping, so the underlying SPI controller does
+ * not need to (re)do it for each message.
+ */
+static void
+mmc_spi_setup_data_message(
+ struct mmc_spi_host *host,
+ int multiple,
+ enum dma_data_direction direction)
+{
+ struct spi_transfer *t;
+ struct scratch *scratch = host->data;
+ dma_addr_t dma = host->data_dma;
+
+ spi_message_init(&host->m);
+ if (dma)
+ host->m.is_dma_mapped = 1;
+
+ /* for reads, readblock() skips 0xff bytes before finding
+ * the token; for writes, this transfer issues that token.
+ */
+ if (direction == DMA_TO_DEVICE) {
+ t = &host->token;
+ memset(t, 0, sizeof(*t));
+ t->len = 1;
+ if (multiple)
+ scratch->data_token = SPI_TOKEN_MULTI_WRITE;
+ else
+ scratch->data_token = SPI_TOKEN_SINGLE;
+ t->tx_buf = &scratch->data_token;
+ if (dma)
+ t->tx_dma = dma + offsetof(struct scratch, data_token);
+ spi_message_add_tail(t, &host->m);
+ }
+
+ /* Body of transfer is buffer, then CRC ...
+ * either TX-only, or RX with TX-ones.
+ */
+ t = &host->t;
+ memset(t, 0, sizeof(*t));
+ t->tx_buf = host->ones;
+ t->tx_dma = host->ones_dma;
+ /* length and actual buffer info are written later */
+ spi_message_add_tail(t, &host->m);
+
+ t = &host->crc;
+ memset(t, 0, sizeof(*t));
+ t->len = 2;
+ if (direction == DMA_TO_DEVICE) {
+ /* the actual CRC may get written later */
+ t->tx_buf = &scratch->crc_val;
+ if (dma)
+ t->tx_dma = dma + offsetof(struct scratch, crc_val);
+ } else {
+ t->tx_buf = host->ones;
+ t->tx_dma = host->ones_dma;
+ t->rx_buf = &scratch->crc_val;
+ if (dma)
+ t->rx_dma = dma + offsetof(struct scratch, crc_val);
+ }
+ spi_message_add_tail(t, &host->m);
+
+ /*
+ * A single block read is followed by N(EC) [0+] all-ones bytes
+ * before deselect ... don't bother.
+ *
+ * Multiblock reads are followed by N(AC) [1+] all-ones bytes before
+ * the next block is read, or a STOP_TRANSMISSION is issued. We'll
+ * collect that single byte, so readblock() doesn't need to.
+ *
+ * For a write, the one-byte data response follows immediately, then
+ * come zero or more busy bytes, then N(WR) [1+] all-ones bytes.
+ * Then single block reads may deselect, and multiblock ones issue
+ * the next token (next data block, or STOP_TRAN). We can try to
+ * minimize I/O ops by using a single read to collect end-of-busy.
+ */
+ if (multiple || direction == DMA_TO_DEVICE) {
+ t = &host->early_status;
+ memset(t, 0, sizeof(*t));
+ t->len = (direction == DMA_TO_DEVICE)
+ ? sizeof(scratch->status)
+ : 1;
+ t->tx_buf = host->ones;
+ t->tx_dma = host->ones_dma;
+ t->rx_buf = scratch->status;
+ if (dma)
+ t->rx_dma = dma + offsetof(struct scratch, status);
+ t->cs_change = 1;
+ spi_message_add_tail(t, &host->m);
+ }
+}
+
+/*
+ * Write one block:
+ * - caller handled preceding N(WR) [1+] all-ones bytes
+ * - data block
+ * + token
+ * + data bytes
+ * + crc16
+ * - an all-ones byte ... card writes a data-response byte
+ * - followed by N(EC) [0+] all-ones bytes, card writes zero/'busy'
+ *
+ * Return negative errno, else success.
+ */
+static int
+mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
+{
+ struct spi_device *spi = host->spi;
+ int status, i;
+ struct scratch *scratch = host->data;
+
+ if (host->mmc->use_spi_crc)
+ scratch->crc_val = cpu_to_be16(
+ crc_itu_t(0, t->tx_buf, t->len));
+ if (host->dma_dev)
+ dma_sync_single_for_device(host->dma_dev,
+ host->data_dma, sizeof(*scratch),
+ DMA_BIDIRECTIONAL);
+
+ status = spi_sync(spi, &host->m);
+ if (status == 0)
+ status = host->m.status;
+
+ if (status != 0) {
+ dev_dbg(&spi->dev, "write error (%d)\n", status);
+ return status;
+ }
+
+ if (host->dma_dev)
+ dma_sync_single_for_cpu(host->dma_dev,
+ host->data_dma, sizeof(*scratch),
+ DMA_BIDIRECTIONAL);
+
+ /*
+ * Get the transmission data-response reply. It must follow
+ * immediately after the data block we transferred. This reply
+ * doesn't necessarily tell whether the write operation succeeded;
+ * it just says if the transmission was ok and whether *earlier*
+ * writes succeeded; see the standard.
+ */
+ switch (SPI_MMC_RESPONSE_CODE(scratch->status[0])) {
+ case SPI_RESPONSE_ACCEPTED:
+ status = 0;
+ break;
+ case SPI_RESPONSE_CRC_ERR:
+ /* host shall then issue MMC_STOP_TRANSMISSION */
+ status = -EILSEQ;
+ break;
+ case SPI_RESPONSE_WRITE_ERR:
+ /* host shall then issue MMC_STOP_TRANSMISSION,
+ * and should MMC_SEND_STATUS to sort it out
+ */
+ status = -EIO;
+ break;
+ default:
+ status = -EPROTO;
+ break;
+ }
+ if (status != 0) {
+ dev_dbg(&spi->dev, "write error %02x (%d)\n",
+ scratch->status[0], status);
+ return status;
+ }
+
+ t->tx_buf += t->len;
+ if (host->dma_dev)
+ t->tx_dma += t->len;
+
+ /* Return when not busy. If we didn't collect that status yet,
+ * we'll need some more I/O.
+ */
+ for (i = 1; i < sizeof(scratch->status); i++) {
+ if (scratch->status[i] != 0)
+ return 0;
+ }
+ return mmc_spi_wait_unbusy(host, writeblock_timeout);
+}
+
+/*
+ * Read one block:
+ * - skip leading all-ones bytes ... either
+ * + N(AC) [1..f(clock,CSD)] usually, else
+ * + N(CX) [0..8] when reading CSD or CID
+ * - data block
+ * + token ... if error token, no data or crc
+ * + data bytes
+ * + crc16
+ *
+ * After single block reads, we're done; N(EC) [0+] all-ones bytes follow
+ * before dropping chipselect.
+ *
+ * For multiblock reads, caller either reads the next block or issues a
+ * STOP_TRANSMISSION command.
+ */
+static int
+mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
+{
+ struct spi_device *spi = host->spi;
+ int status;
+ struct scratch *scratch = host->data;
+
+ /* At least one SD card sends an all-zeroes byte when N(CX)
+ * applies, before the all-ones bytes ... just cope with that.
+ */
+ status = mmc_spi_readbytes(host, 1);
+ if (status < 0)
+ return status;
+ status = scratch->status[0];
+ if (status == 0xff || status == 0)
+ status = mmc_spi_readtoken(host);
+
+ if (status == SPI_TOKEN_SINGLE) {
+ if (host->dma_dev) {
+ dma_sync_single_for_device(host->dma_dev,
+ host->data_dma, sizeof(*scratch),
+ DMA_BIDIRECTIONAL);
+ dma_sync_single_for_device(host->dma_dev,
+ t->rx_dma, t->len,
+ DMA_FROM_DEVICE);
+ }
+
+ status = spi_sync(spi, &host->m);
+ if (status == 0)
+ status = host->m.status;
+
+ if (host->dma_dev) {
+ dma_sync_single_for_cpu(host->dma_dev,
+ host->data_dma, sizeof(*scratch),
+ DMA_BIDIRECTIONAL);
+ dma_sync_single_for_cpu(host->dma_dev,
+ t->rx_dma, t->len,
+ DMA_FROM_DEVICE);
+ }
+
+ } else {
+ dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status);
+
+ /* we've read extra garbage, timed out, etc */
+ if (status < 0)
+ return status;
+
+ /* low four bits are an R2 subset, fifth seems to be
+ * vendor specific ... map them all to generic error..
+ */
+ return -EIO;
+ }
+
+ if (host->mmc->use_spi_crc) {
+ u16 crc = crc_itu_t(0, t->rx_buf, t->len);
+
+ be16_to_cpus(&scratch->crc_val);
+ if (scratch->crc_val != crc) {
+ dev_dbg(&spi->dev, "read - crc error: crc_val=0x%04x, "
+ "computed=0x%04x len=%d\n",
+ scratch->crc_val, crc, t->len);
+ return -EILSEQ;
+ }
+ }
+
+ t->rx_buf += t->len;
+ if (host->dma_dev)
+ t->rx_dma += t->len;
+
+ return 0;
+}
+
+/*
+ * An MMC/SD data stage includes one or more blocks, optional CRCs,
+ * and inline handshaking. That handhaking makes it unlike most
+ * other SPI protocol stacks.
+ */
+static void
+mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
+ struct mmc_data *data, u32 blk_size)
+{
+ struct spi_device *spi = host->spi;
+ struct device *dma_dev = host->dma_dev;
+ struct spi_transfer *t;
+ enum dma_data_direction direction;
+ struct scatterlist *sg;
+ unsigned n_sg;
+ int multiple = (data->blocks > 1);
+
+ if (data->flags & MMC_DATA_READ)
+ direction = DMA_FROM_DEVICE;
+ else
+ direction = DMA_TO_DEVICE;
+ mmc_spi_setup_data_message(host, multiple, direction);
+ t = &host->t;
+
+ /* Handle scatterlist segments one at a time, with synch for
+ * each 512-byte block
+ */
+ for (sg = data->sg, n_sg = data->sg_len; n_sg; n_sg--, sg++) {
+ int status = 0;
+ dma_addr_t dma_addr = 0;
+ void *kmap_addr;
+ unsigned length = sg->length;
+ enum dma_data_direction dir = direction;
+
+ /* set up dma mapping for controller drivers that might
+ * use DMA ... though they may fall back to PIO
+ */
+ if (dma_dev) {
+ /* never invalidate whole *shared* pages ... */
+ if ((sg->offset != 0 || length != PAGE_SIZE)
+ && dir == DMA_FROM_DEVICE)
+ dir = DMA_BIDIRECTIONAL;
+
+ dma_addr = dma_map_page(dma_dev, sg_page(sg), 0,
+ PAGE_SIZE, dir);
+ if (direction == DMA_TO_DEVICE)
+ t->tx_dma = dma_addr + sg->offset;
+ else
+ t->rx_dma = dma_addr + sg->offset;
+ }
+
+ /* allow pio too; we don't allow highmem */
+ kmap_addr = kmap(sg_page(sg));
+ if (direction == DMA_TO_DEVICE)
+ t->tx_buf = kmap_addr + sg->offset;
+ else
+ t->rx_buf = kmap_addr + sg->offset;
+
+ /* transfer each block, and update request status */
+ while (length) {
+ t->len = min(length, blk_size);
+
+ dev_dbg(&host->spi->dev,
+ " mmc_spi: %s block, %d bytes\n",
+ (direction == DMA_TO_DEVICE)
+ ? "write"
+ : "read",
+ t->len);
+
+ if (direction == DMA_TO_DEVICE)
+ status = mmc_spi_writeblock(host, t);
+ else
+ status = mmc_spi_readblock(host, t);
+ if (status < 0)
+ break;
+
+ data->bytes_xfered += t->len;
+ length -= t->len;
+
+ if (!multiple)
+ break;
+ }
+
+ /* discard mappings */
+ if (direction == DMA_FROM_DEVICE)
+ flush_kernel_dcache_page(sg_page(sg));
+ kunmap(sg_page(sg));
+ if (dma_dev)
+ dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir);
+
+ if (status < 0) {
+ data->error = status;
+ dev_dbg(&spi->dev, "%s status %d\n",
+ (direction == DMA_TO_DEVICE)
+ ? "write" : "read",
+ status);
+ break;
+ }
+ }
+
+ /* NOTE some docs describe an MMC-only SET_BLOCK_COUNT (CMD23) that
+ * can be issued before multiblock writes. Unlike its more widely
+ * documented analogue for SD cards (SET_WR_BLK_ERASE_COUNT, ACMD23),
+ * that can affect the STOP_TRAN logic. Complete (and current)
+ * MMC specs should sort that out before Linux starts using CMD23.
+ */
+ if (direction == DMA_TO_DEVICE && multiple) {
+ struct scratch *scratch = host->data;
+ int tmp;
+ const unsigned statlen = sizeof(scratch->status);
+
+ dev_dbg(&spi->dev, " mmc_spi: STOP_TRAN\n");
+
+ /* Tweak the per-block message we set up earlier by morphing
+ * it to hold single buffer with the token followed by some
+ * all-ones bytes ... skip N(BR) (0..1), scan the rest for
+ * "not busy any longer" status, and leave chip selected.
+ */
+ INIT_LIST_HEAD(&host->m.transfers);
+ list_add(&host->early_status.transfer_list,
+ &host->m.transfers);
+
+ memset(scratch->status, 0xff, statlen);
+ scratch->status[0] = SPI_TOKEN_STOP_TRAN;
+
+ host->early_status.tx_buf = host->early_status.rx_buf;
+ host->early_status.tx_dma = host->early_status.rx_dma;
+ host->early_status.len = statlen;
+
+ if (host->dma_dev)
+ dma_sync_single_for_device(host->dma_dev,
+ host->data_dma, sizeof(*scratch),
+ DMA_BIDIRECTIONAL);
+
+ tmp = spi_sync(spi, &host->m);
+ if (tmp == 0)
+ tmp = host->m.status;
+
+ if (host->dma_dev)
+ dma_sync_single_for_cpu(host->dma_dev,
+ host->data_dma, sizeof(*scratch),
+ DMA_BIDIRECTIONAL);
+
+ if (tmp < 0) {
+ if (!data->error)
+ data->error = tmp;
+ return;
+ }
+
+ /* Ideally we collected "not busy" status with one I/O,
+ * avoiding wasteful byte-at-a-time scanning... but more
+ * I/O is often needed.
+ */
+ for (tmp = 2; tmp < statlen; tmp++) {
+ if (scratch->status[tmp] != 0)
+ return;
+ }
+ tmp = mmc_spi_wait_unbusy(host, writeblock_timeout);
+ if (tmp < 0 && !data->error)
+ data->error = tmp;
+ }
+}
+
+/****************************************************************************/
+
+/*
+ * MMC driver implementation -- the interface to the MMC stack
+ */
+
+static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct mmc_spi_host *host = mmc_priv(mmc);
+ int status = -EINVAL;
+
+#ifdef DEBUG
+ /* MMC core and layered drivers *MUST* issue SPI-aware commands */
+ {
+ struct mmc_command *cmd;
+ int invalid = 0;
+
+ cmd = mrq->cmd;
+ if (!mmc_spi_resp_type(cmd)) {
+ dev_dbg(&host->spi->dev, "bogus command\n");
+ cmd->error = -EINVAL;
+ invalid = 1;
+ }
+
+ cmd = mrq->stop;
+ if (cmd && !mmc_spi_resp_type(cmd)) {
+ dev_dbg(&host->spi->dev, "bogus STOP command\n");
+ cmd->error = -EINVAL;
+ invalid = 1;
+ }
+
+ if (invalid) {
+ dump_stack();
+ mmc_request_done(host->mmc, mrq);
+ return;
+ }
+ }
+#endif
+
+ /* issue command; then optionally data and stop */
+ status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL);
+ if (status == 0 && mrq->data) {
+ mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz);
+ if (mrq->stop)
+ status = mmc_spi_command_send(host, mrq, mrq->stop, 0);
+ else
+ mmc_cs_off(host);
+ }
+
+ mmc_request_done(host->mmc, mrq);
+}
+
+/* See Section 6.4.1, in SD "Simplified Physical Layer Specification 2.0"
+ *
+ * NOTE that here we can't know that the card has just been powered up;
+ * not all MMC/SD sockets support power switching.
+ *
+ * FIXME when the card is still in SPI mode, e.g. from a previous kernel,
+ * this doesn't seem to do the right thing at all...
+ */
+static void mmc_spi_initsequence(struct mmc_spi_host *host)
+{
+ /* Try to be very sure any previous command has completed;
+ * wait till not-busy, skip debris from any old commands.
+ */
+ mmc_spi_wait_unbusy(host, r1b_timeout);
+ mmc_spi_readbytes(host, 10);
+
+ /*
+ * Do a burst with chipselect active-high. We need to do this to
+ * meet the requirement of 74 clock cycles with both chipselect
+ * and CMD (MOSI) high before CMD0 ... after the card has been
+ * powered up to Vdd(min), and so is ready to take commands.
+ *
+ * Some cards are particularly needy of this (e.g. Viking "SD256")
+ * while most others don't seem to care.
+ *
+ * Note that this is one of the places MMC/SD plays games with the
+ * SPI protocol. Another is that when chipselect is released while
+ * the card returns BUSY status, the clock must issue several cycles
+ * with chipselect high before the card will stop driving its output.
+ */
+ host->spi->mode |= SPI_CS_HIGH;
+ if (spi_setup(host->spi) != 0) {
+ /* Just warn; most cards work without it. */
+ dev_warn(&host->spi->dev,
+ "can't change chip-select polarity\n");
+ host->spi->mode &= ~SPI_CS_HIGH;
+ } else {
+ mmc_spi_readbytes(host, 18);
+
+ host->spi->mode &= ~SPI_CS_HIGH;
+ if (spi_setup(host->spi) != 0) {
+ /* Wot, we can't get the same setup we had before? */
+ dev_err(&host->spi->dev,
+ "can't restore chip-select polarity\n");
+ }
+ }
+}
+
+static char *mmc_powerstring(u8 power_mode)
+{
+ switch (power_mode) {
+ case MMC_POWER_OFF: return "off";
+ case MMC_POWER_UP: return "up";
+ case MMC_POWER_ON: return "on";
+ }
+ return "?";
+}
+
+static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct mmc_spi_host *host = mmc_priv(mmc);
+
+ if (host->power_mode != ios->power_mode) {
+ int canpower;
+
+ canpower = host->pdata && host->pdata->setpower;
+
+ dev_dbg(&host->spi->dev, "mmc_spi: power %s (%d)%s\n",
+ mmc_powerstring(ios->power_mode),
+ ios->vdd,
+ canpower ? ", can switch" : "");
+
+ /* switch power on/off if possible, accounting for
+ * max 250msec powerup time if needed.
+ */
+ if (canpower) {
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ case MMC_POWER_UP:
+ host->pdata->setpower(&host->spi->dev,
+ ios->vdd);
+ if (ios->power_mode == MMC_POWER_UP)
+ msleep(host->powerup_msecs);
+ }
+ }
+
+ /* See 6.4.1 in the simplified SD card physical spec 2.0 */
+ if (ios->power_mode == MMC_POWER_ON)
+ mmc_spi_initsequence(host);
+
+ /* If powering down, ground all card inputs to avoid power
+ * delivery from data lines! On a shared SPI bus, this
+ * will probably be temporary; 6.4.2 of the simplified SD
+ * spec says this must last at least 1msec.
+ *
+ * - Clock low means CPOL 0, e.g. mode 0
+ * - MOSI low comes from writing zero
+ * - Chipselect is usually active low...
+ */
+ if (canpower && ios->power_mode == MMC_POWER_OFF) {
+ int mres;
+
+ host->spi->mode &= ~(SPI_CPOL|SPI_CPHA);
+ mres = spi_setup(host->spi);
+ if (mres < 0)
+ dev_dbg(&host->spi->dev,
+ "switch to SPI mode 0 failed\n");
+
+ if (spi_w8r8(host->spi, 0x00) < 0)
+ dev_dbg(&host->spi->dev,
+ "put spi signals to low failed\n");
+
+ /*
+ * Now clock should be low due to spi mode 0;
+ * MOSI should be low because of written 0x00;
+ * chipselect should be low (it is active low)
+ * power supply is off, so now MMC is off too!
+ *
+ * FIXME no, chipselect can be high since the
+ * device is inactive and SPI_CS_HIGH is clear...
+ */
+ msleep(10);
+ if (mres == 0) {
+ host->spi->mode |= (SPI_CPOL|SPI_CPHA);
+ mres = spi_setup(host->spi);
+ if (mres < 0)
+ dev_dbg(&host->spi->dev,
+ "switch back to SPI mode 3"
+ " failed\n");
+ }
+ }
+
+ host->power_mode = ios->power_mode;
+ }
+
+ if (host->spi->max_speed_hz != ios->clock && ios->clock != 0) {
+ int status;
+
+ host->spi->max_speed_hz = ios->clock;
+ status = spi_setup(host->spi);
+ dev_dbg(&host->spi->dev,
+ "mmc_spi: clock to %d Hz, %d\n",
+ host->spi->max_speed_hz, status);
+ }
+}
+
+static int mmc_spi_get_ro(struct mmc_host *mmc)
+{
+ struct mmc_spi_host *host = mmc_priv(mmc);
+
+ if (host->pdata && host->pdata->get_ro)
+ return host->pdata->get_ro(mmc->parent);
+ /* board doesn't support read only detection; assume writeable */
+ return 0;
+}
+
+
+static const struct mmc_host_ops mmc_spi_ops = {
+ .request = mmc_spi_request,
+ .set_ios = mmc_spi_set_ios,
+ .get_ro = mmc_spi_get_ro,
+};
+
+
+/****************************************************************************/
+
+/*
+ * SPI driver implementation
+ */
+
+static irqreturn_t
+mmc_spi_detect_irq(int irq, void *mmc)
+{
+ struct mmc_spi_host *host = mmc_priv(mmc);
+ u16 delay_msec = max(host->pdata->detect_delay, (u16)100);
+
+ mmc_detect_change(mmc, msecs_to_jiffies(delay_msec));
+ return IRQ_HANDLED;
+}
+
+struct count_children {
+ unsigned n;
+ struct bus_type *bus;
+};
+
+static int maybe_count_child(struct device *dev, void *c)
+{
+ struct count_children *ccp = c;
+
+ if (dev->bus == ccp->bus) {
+ if (ccp->n)
+ return -EBUSY;
+ ccp->n++;
+ }
+ return 0;
+}
+
+static int mmc_spi_probe(struct spi_device *spi)
+{
+ void *ones;
+ struct mmc_host *mmc;
+ struct mmc_spi_host *host;
+ int status;
+
+ /* MMC and SD specs only seem to care that sampling is on the
+ * rising edge ... meaning SPI modes 0 or 3. So either SPI mode
+ * should be legit. We'll use mode 0 since it seems to be a
+ * bit less troublesome on some hardware ... unclear why.
+ */
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 8;
+
+ status = spi_setup(spi);
+ if (status < 0) {
+ dev_dbg(&spi->dev, "needs SPI mode %02x, %d KHz; %d\n",
+ spi->mode, spi->max_speed_hz / 1000,
+ status);
+ return status;
+ }
+
+ /* We can use the bus safely iff nobody else will interfere with us.
+ * Most commands consist of one SPI message to issue a command, then
+ * several more to collect its response, then possibly more for data
+ * transfer. Clocking access to other devices during that period will
+ * corrupt the command execution.
+ *
+ * Until we have software primitives which guarantee non-interference,
+ * we'll aim for a hardware-level guarantee.
+ *
+ * REVISIT we can't guarantee another device won't be added later...
+ */
+ if (spi->master->num_chipselect > 1) {
+ struct count_children cc;
+
+ cc.n = 0;
+ cc.bus = spi->dev.bus;
+ status = device_for_each_child(spi->dev.parent, &cc,
+ maybe_count_child);
+ if (status < 0) {
+ dev_err(&spi->dev, "can't share SPI bus\n");
+ return status;
+ }
+
+ dev_warn(&spi->dev, "ASSUMING SPI bus stays unshared!\n");
+ }
+
+ /* We need a supply of ones to transmit. This is the only time
+ * the CPU touches these, so cache coherency isn't a concern.
+ *
+ * NOTE if many systems use more than one MMC-over-SPI connector
+ * it'd save some memory to share this. That's evidently rare.
+ */
+ status = -ENOMEM;
+ ones = kmalloc(MMC_SPI_BLOCKSIZE, GFP_KERNEL);
+ if (!ones)
+ goto nomem;
+ memset(ones, 0xff, MMC_SPI_BLOCKSIZE);
+
+ mmc = mmc_alloc_host(sizeof(*host), &spi->dev);
+ if (!mmc)
+ goto nomem;
+
+ mmc->ops = &mmc_spi_ops;
+ mmc->max_blk_size = MMC_SPI_BLOCKSIZE;
+
+ /* As long as we keep track of the number of successfully
+ * transmitted blocks, we're good for multiwrite.
+ */
+ mmc->caps = MMC_CAP_SPI | MMC_CAP_MULTIWRITE;
+
+ /* SPI doesn't need the lowspeed device identification thing for
+ * MMC or SD cards, since it never comes up in open drain mode.
+ * That's good; some SPI masters can't handle very low speeds!
+ *
+ * However, low speed SDIO cards need not handle over 400 KHz;
+ * that's the only reason not to use a few MHz for f_min (until
+ * the upper layer reads the target frequency from the CSD).
+ */
+ mmc->f_min = 400000;
+ mmc->f_max = spi->max_speed_hz;
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->spi = spi;
+
+ host->ones = ones;
+
+ /* Platform data is used to hook up things like card sensing
+ * and power switching gpios.
+ */
+ host->pdata = spi->dev.platform_data;
+ if (host->pdata)
+ mmc->ocr_avail = host->pdata->ocr_mask;
+ if (!mmc->ocr_avail) {
+ dev_warn(&spi->dev, "ASSUMING 3.2-3.4 V slot power\n");
+ mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+ }
+ if (host->pdata && host->pdata->setpower) {
+ host->powerup_msecs = host->pdata->powerup_msecs;
+ if (!host->powerup_msecs || host->powerup_msecs > 250)
+ host->powerup_msecs = 250;
+ }
+
+ dev_set_drvdata(&spi->dev, mmc);
+
+ /* preallocate dma buffers */
+ host->data = kmalloc(sizeof(*host->data), GFP_KERNEL);
+ if (!host->data)
+ goto fail_nobuf1;
+
+ if (spi->master->dev.parent->dma_mask) {
+ struct device *dev = spi->master->dev.parent;
+
+ host->dma_dev = dev;
+ host->ones_dma = dma_map_single(dev, ones,
+ MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
+ host->data_dma = dma_map_single(dev, host->data,
+ sizeof(*host->data), DMA_BIDIRECTIONAL);
+
+ /* REVISIT in theory those map operations can fail... */
+
+ dma_sync_single_for_cpu(host->dma_dev,
+ host->data_dma, sizeof(*host->data),
+ DMA_BIDIRECTIONAL);
+ }
+
+ /* setup message for status/busy readback */
+ spi_message_init(&host->readback);
+ host->readback.is_dma_mapped = (host->dma_dev != NULL);
+
+ spi_message_add_tail(&host->status, &host->readback);
+ host->status.tx_buf = host->ones;
+ host->status.tx_dma = host->ones_dma;
+ host->status.rx_buf = &host->data->status;
+ host->status.rx_dma = host->data_dma + offsetof(struct scratch, status);
+ host->status.cs_change = 1;
+
+ /* register card detect irq */
+ if (host->pdata && host->pdata->init) {
+ status = host->pdata->init(&spi->dev, mmc_spi_detect_irq, mmc);
+ if (status != 0)
+ goto fail_glue_init;
+ }
+
+ status = mmc_add_host(mmc);
+ if (status != 0)
+ goto fail_add_host;
+
+ dev_info(&spi->dev, "SD/MMC host %s%s%s%s\n",
+ mmc->class_dev.bus_id,
+ host->dma_dev ? "" : ", no DMA",
+ (host->pdata && host->pdata->get_ro)
+ ? "" : ", no WP",
+ (host->pdata && host->pdata->setpower)
+ ? "" : ", no poweroff");
+ return 0;
+
+fail_add_host:
+ mmc_remove_host (mmc);
+fail_glue_init:
+ if (host->dma_dev)
+ dma_unmap_single(host->dma_dev, host->data_dma,
+ sizeof(*host->data), DMA_BIDIRECTIONAL);
+ kfree(host->data);
+
+fail_nobuf1:
+ mmc_free_host(mmc);
+ dev_set_drvdata(&spi->dev, NULL);
+
+nomem:
+ kfree(ones);
+ return status;
+}
+
+
+static int __devexit mmc_spi_remove(struct spi_device *spi)
+{
+ struct mmc_host *mmc = dev_get_drvdata(&spi->dev);
+ struct mmc_spi_host *host;
+
+ if (mmc) {
+ host = mmc_priv(mmc);
+
+ /* prevent new mmc_detect_change() calls */
+ if (host->pdata && host->pdata->exit)
+ host->pdata->exit(&spi->dev, mmc);
+
+ mmc_remove_host(mmc);
+
+ if (host->dma_dev) {
+ dma_unmap_single(host->dma_dev, host->ones_dma,
+ MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
+ dma_unmap_single(host->dma_dev, host->data_dma,
+ sizeof(*host->data), DMA_BIDIRECTIONAL);
+ }
+
+ kfree(host->data);
+ kfree(host->ones);
+
+ spi->max_speed_hz = mmc->f_max;
+ mmc_free_host(mmc);
+ dev_set_drvdata(&spi->dev, NULL);
+ }
+ return 0;
+}
+
+
+static struct spi_driver mmc_spi_driver = {
+ .driver = {
+ .name = "mmc_spi",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = mmc_spi_probe,
+ .remove = __devexit_p(mmc_spi_remove),
+};
+
+
+static int __init mmc_spi_init(void)
+{
+ return spi_register_driver(&mmc_spi_driver);
+}
+module_init(mmc_spi_init);
+
+
+static void __exit mmc_spi_exit(void)
+{
+ spi_unregister_driver(&mmc_spi_driver);
+}
+module_exit(mmc_spi_exit);
+
+
+MODULE_AUTHOR("Mike Lavender, David Brownell, "
+ "Hans-Peter Nilsson, Jan Nikitenko");
+MODULE_DESCRIPTION("SPI SD/MMC host driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index be730c0a035..95244a7e735 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -16,14 +16,15 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/highmem.h>
+#include <linux/log2.h>
#include <linux/mmc/host.h>
#include <linux/amba/bus.h>
#include <linux/clk.h>
+#include <linux/scatterlist.h>
#include <asm/cacheflush.h>
#include <asm/div64.h>
#include <asm/io.h>
-#include <asm/scatterlist.h>
#include <asm/sizes.h>
#include <asm/mach/mmc.h>
@@ -154,11 +155,11 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
}
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
if (status & MCI_DATACRCFAIL)
- data->error = MMC_ERR_BADCRC;
+ data->error = -EILSEQ;
else if (status & MCI_DATATIMEOUT)
- data->error = MMC_ERR_TIMEOUT;
+ data->error = -ETIMEDOUT;
else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
- data->error = MMC_ERR_FIFO;
+ data->error = -EIO;
status |= MCI_DATAEND;
/*
@@ -166,7 +167,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
* partially written to a page is properly coherent.
*/
if (host->sg_len && data->flags & MMC_DATA_READ)
- flush_dcache_page(host->sg_ptr->page);
+ flush_dcache_page(sg_page(host->sg_ptr));
}
if (status & MCI_DATAEND) {
mmci_stop_data(host);
@@ -193,12 +194,12 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
cmd->resp[3] = readl(base + MMCIRESPONSE3);
if (status & MCI_CMDTIMEOUT) {
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ETIMEDOUT;
} else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
- cmd->error = MMC_ERR_BADCRC;
+ cmd->error = -EILSEQ;
}
- if (!cmd->data || cmd->error != MMC_ERR_NONE) {
+ if (!cmd->data || cmd->error) {
if (host->data)
mmci_stop_data(host);
mmci_request_end(host, cmd->mrq);
@@ -318,7 +319,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
* page, ensure that the data cache is coherent.
*/
if (status & MCI_RXACTIVE)
- flush_dcache_page(host->sg_ptr->page);
+ flush_dcache_page(sg_page(host->sg_ptr));
if (!mmci_next_sg(host))
break;
@@ -391,6 +392,14 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
WARN_ON(host->mrq != NULL);
+ if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
+ printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n",
+ mmc_hostname(mmc), mrq->data->blksz);
+ mrq->cmd->error = -EINVAL;
+ mmc_request_done(mmc, mrq);
+ return;
+ }
+
spin_lock_irq(&host->lock);
host->mrq = mrq;
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 000e6a91978..0f39c490f02 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -169,7 +169,7 @@ static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flag
struct scatterlist *sg = host->sg_ptr;
local_irq_save(*flags);
- return kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
+ return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
}
static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags)
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 0cf97edc5f5..971e18b91f4 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -24,10 +24,10 @@
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/clk.h>
+#include <linux/scatterlist.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/scatterlist.h>
#include <asm/mach-types.h>
#include <asm/arch/board.h>
@@ -263,7 +263,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
enum dma_data_direction dma_data_dir;
BUG_ON(host->dma_ch < 0);
- if (data->error != MMC_ERR_NONE)
+ if (data->error)
omap_stop_dma(host->dma_ch);
/* Release DMA channel lazily */
mod_timer(&host->dma_timer, jiffies + HZ);
@@ -368,7 +368,7 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
}
}
- if (host->data == NULL || cmd->error != MMC_ERR_NONE) {
+ if (host->data == NULL || cmd->error) {
host->mrq = NULL;
clk_disable(host->fclk);
mmc_request_done(host->mmc, cmd->mrq);
@@ -383,7 +383,7 @@ mmc_omap_sg_to_buf(struct mmc_omap_host *host)
sg = host->data->sg + host->sg_idx;
host->buffer_bytes_left = sg->length;
- host->buffer = page_address(sg->page) + sg->offset;
+ host->buffer = sg_virt(sg);
if (host->buffer_bytes_left > host->total_bytes_left)
host->buffer_bytes_left = host->total_bytes_left;
}
@@ -475,14 +475,14 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
if (status & OMAP_MMC_STAT_DATA_TOUT) {
dev_dbg(mmc_dev(host->mmc), "data timeout\n");
if (host->data) {
- host->data->error |= MMC_ERR_TIMEOUT;
+ host->data->error = -ETIMEDOUT;
transfer_error = 1;
}
}
if (status & OMAP_MMC_STAT_DATA_CRC) {
if (host->data) {
- host->data->error |= MMC_ERR_BADCRC;
+ host->data->error = -EILSEQ;
dev_dbg(mmc_dev(host->mmc),
"data CRC error, bytes left %d\n",
host->total_bytes_left);
@@ -504,7 +504,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
dev_err(mmc_dev(host->mmc),
"command timeout, CMD %d\n",
host->cmd->opcode);
- host->cmd->error = MMC_ERR_TIMEOUT;
+ host->cmd->error = -ETIMEDOUT;
end_command = 1;
}
}
@@ -514,7 +514,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
dev_err(mmc_dev(host->mmc),
"command CRC error (CMD%d, arg 0x%08x)\n",
host->cmd->opcode, host->cmd->arg);
- host->cmd->error = MMC_ERR_BADCRC;
+ host->cmd->error = -EILSEQ;
end_command = 1;
} else
dev_err(mmc_dev(host->mmc),
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index ff960334b33..1654a333034 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -23,11 +23,12 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/mmc/host.h>
#include <asm/dma.h>
#include <asm/io.h>
-#include <asm/scatterlist.h>
#include <asm/sizes.h>
#include <asm/arch/pxa-regs.h>
@@ -38,12 +39,15 @@
#define DRIVER_NAME "pxa2xx-mci"
#define NR_SG 1
+#define CLKRT_OFF (~0)
struct pxamci_host {
struct mmc_host *mmc;
spinlock_t lock;
struct resource *res;
void __iomem *base;
+ struct clk *clk;
+ unsigned long clkrate;
int irq;
int dma;
unsigned int clkrt;
@@ -119,7 +123,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
writel(nob, host->base + MMC_NOB);
writel(data->blksz, host->base + MMC_BLKLEN);
- clks = (unsigned long long)data->timeout_ns * CLOCKRATE;
+ clks = (unsigned long long)data->timeout_ns * host->clkrate;
do_div(clks, 1000000000UL);
timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
writel((timeout + 255) / 256, host->base + MMC_RDTO);
@@ -142,6 +146,10 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
host->dma_dir);
for (i = 0; i < host->dma_len; i++) {
+ unsigned int length = sg_dma_len(&data->sg[i]);
+ host->sg_cpu[i].dcmd = dcmd | length;
+ if (length & 31 && !(data->flags & MMC_DATA_READ))
+ host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
if (data->flags & MMC_DATA_READ) {
host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
@@ -149,7 +157,6 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
}
- host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]);
host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
sizeof(struct pxa_dma_desc);
}
@@ -226,7 +233,7 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
}
if (stat & STAT_TIME_OUT_RESPONSE) {
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ETIMEDOUT;
} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
#ifdef CONFIG_PXA27x
/*
@@ -239,11 +246,11 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode);
} else
#endif
- cmd->error = MMC_ERR_BADCRC;
+ cmd->error = -EILSEQ;
}
pxamci_disable_irq(host, END_CMD_RES);
- if (host->data && cmd->error == MMC_ERR_NONE) {
+ if (host->data && !cmd->error) {
pxamci_enable_irq(host, DATA_TRAN_DONE);
} else {
pxamci_finish_request(host, host->mrq);
@@ -264,9 +271,9 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
host->dma_dir);
if (stat & STAT_READ_TIME_OUT)
- data->error = MMC_ERR_TIMEOUT;
+ data->error = -ETIMEDOUT;
else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
- data->error = MMC_ERR_BADCRC;
+ data->error = -EILSEQ;
/*
* There appears to be a hardware design bug here. There seems to
@@ -274,7 +281,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
* This means that if there was an error on any block, we mark all
* data blocks as being in error.
*/
- if (data->error == MMC_ERR_NONE)
+ if (!data->error)
data->bytes_xfered = data->blocks * data->blksz;
else
data->bytes_xfered = 0;
@@ -284,7 +291,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
host->data = NULL;
if (host->mrq->stop) {
pxamci_stop_clock(host);
- pxamci_start_cmd(host, host->mrq->stop, 0);
+ pxamci_start_cmd(host, host->mrq->stop, host->cmdat);
} else {
pxamci_finish_request(host, host->mrq);
}
@@ -298,7 +305,7 @@ static irqreturn_t pxamci_irq(int irq, void *devid)
unsigned int ireg;
int handled = 0;
- ireg = readl(host->base + MMC_I_REG);
+ ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK);
if (ireg) {
unsigned stat = readl(host->base + MMC_STAT);
@@ -309,6 +316,10 @@ static irqreturn_t pxamci_irq(int irq, void *devid)
handled |= pxamci_cmd_done(host, stat);
if (ireg & DATA_TRAN_DONE)
handled |= pxamci_data_done(host, stat);
+ if (ireg & SDIO_INT) {
+ mmc_signal_sdio_irq(host->mmc);
+ handled = 1;
+ }
}
return IRQ_RETVAL(handled);
@@ -358,18 +369,30 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct pxamci_host *host = mmc_priv(mmc);
if (ios->clock) {
- unsigned int clk = CLOCKRATE / ios->clock;
- if (CLOCKRATE / clk > ios->clock)
+ unsigned long rate = host->clkrate;
+ unsigned int clk = rate / ios->clock;
+
+ if (host->clkrt == CLKRT_OFF)
+ clk_enable(host->clk);
+
+ /*
+ * clk might result in a lower divisor than we
+ * desire. check for that condition and adjust
+ * as appropriate.
+ */
+ if (rate / clk > ios->clock)
clk <<= 1;
host->clkrt = fls(clk) - 1;
- pxa_set_cken(CKEN_MMC, 1);
/*
* we write clkrt on the next command
*/
} else {
pxamci_stop_clock(host);
- pxa_set_cken(CKEN_MMC, 0);
+ if (host->clkrt != CLKRT_OFF) {
+ host->clkrt = CLKRT_OFF;
+ clk_disable(host->clk);
+ }
}
if (host->power_mode != ios->power_mode) {
@@ -382,20 +405,46 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->cmdat |= CMDAT_INIT;
}
+ if (ios->bus_width == MMC_BUS_WIDTH_4)
+ host->cmdat |= CMDAT_SD_4DAT;
+ else
+ host->cmdat &= ~CMDAT_SD_4DAT;
+
pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
host->clkrt, host->cmdat);
}
+static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
+{
+ struct pxamci_host *pxa_host = mmc_priv(host);
+
+ if (enable)
+ pxamci_enable_irq(pxa_host, SDIO_INT);
+ else
+ pxamci_disable_irq(pxa_host, SDIO_INT);
+}
+
static const struct mmc_host_ops pxamci_ops = {
- .request = pxamci_request,
- .get_ro = pxamci_get_ro,
- .set_ios = pxamci_set_ios,
+ .request = pxamci_request,
+ .get_ro = pxamci_get_ro,
+ .set_ios = pxamci_set_ios,
+ .enable_sdio_irq = pxamci_enable_sdio_irq,
};
static void pxamci_dma_irq(int dma, void *devid)
{
- printk(KERN_ERR "DMA%d: IRQ???\n", dma);
- DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
+ struct pxamci_host *host = devid;
+ int dcsr = DCSR(dma);
+ DCSR(dma) = dcsr & ~DCSR_STOPIRQEN;
+
+ if (dcsr & DCSR_ENDINTR) {
+ writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
+ } else {
+ printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
+ mmc_hostname(host->mmc), dma, dcsr);
+ host->data->error = -EIO;
+ pxamci_data_done(host, 0);
+ }
}
static irqreturn_t pxamci_detect_irq(int irq, void *devid)
@@ -429,8 +478,6 @@ static int pxamci_probe(struct platform_device *pdev)
}
mmc->ops = &pxamci_ops;
- mmc->f_min = CLOCKRATE_MIN;
- mmc->f_max = CLOCKRATE_MAX;
/*
* We can do SG-DMA, but we don't because we never know how much
@@ -444,9 +491,9 @@ static int pxamci_probe(struct platform_device *pdev)
mmc->max_seg_size = PAGE_SIZE;
/*
- * Block length register is 10 bits.
+ * Block length register is only 10 bits before PXA27x.
*/
- mmc->max_blk_size = 1023;
+ mmc->max_blk_size = (cpu_is_pxa21x() || cpu_is_pxa25x()) ? 1023 : 2048;
/*
* Block count register is 16 bits.
@@ -457,9 +504,32 @@ static int pxamci_probe(struct platform_device *pdev)
host->mmc = mmc;
host->dma = -1;
host->pdata = pdev->dev.platform_data;
+ host->clkrt = CLKRT_OFF;
+
+ host->clk = clk_get(&pdev->dev, "MMCCLK");
+ if (IS_ERR(host->clk)) {
+ ret = PTR_ERR(host->clk);
+ host->clk = NULL;
+ goto out;
+ }
+
+ host->clkrate = clk_get_rate(host->clk);
+
+ /*
+ * Calculate minimum clock rate, rounding up.
+ */
+ mmc->f_min = (host->clkrate + 63) / 64;
+ mmc->f_max = host->clkrate;
+
mmc->ocr_avail = host->pdata ?
host->pdata->ocr_mask :
MMC_VDD_32_33|MMC_VDD_33_34;
+ mmc->caps = 0;
+ host->cmdat = 0;
+ if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) {
+ mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
+ host->cmdat |= CMDAT_SDIO_INT_EN;
+ }
host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
if (!host->sg_cpu) {
@@ -515,6 +585,8 @@ static int pxamci_probe(struct platform_device *pdev)
iounmap(host->base);
if (host->sg_cpu)
dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+ if (host->clk)
+ clk_put(host->clk);
}
if (mmc)
mmc_free_host(mmc);
@@ -549,6 +621,8 @@ static int pxamci_remove(struct platform_device *pdev)
iounmap(host->base);
dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+ clk_put(host->clk);
+
release_resource(host->res);
mmc_free_host(mmc);
diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h
index df17c281278..748c7706f23 100644
--- a/drivers/mmc/host/pxamci.h
+++ b/drivers/mmc/host/pxamci.h
@@ -25,6 +25,8 @@
#define SPI_EN (1 << 0)
#define MMC_CMDAT 0x0010
+#define CMDAT_SDIO_INT_EN (1 << 11)
+#define CMDAT_SD_4DAT (1 << 8)
#define CMDAT_DMAEN (1 << 7)
#define CMDAT_INIT (1 << 6)
#define CMDAT_BUSY (1 << 5)
@@ -86,17 +88,3 @@
#define MMC_RXFIFO 0x0040 /* 8 bit */
#define MMC_TXFIFO 0x0044 /* 8 bit */
-
-/*
- * The base MMC clock rate
- */
-#ifdef CONFIG_PXA27x
-#define CLOCKRATE_MIN 304688
-#define CLOCKRATE_MAX 19500000
-#else
-#define CLOCKRATE_MIN 312500
-#define CLOCKRATE_MAX 20000000
-#endif
-
-#define CLOCKRATE CLOCKRATE_MAX
-
diff --git a/drivers/mmc/host/ricoh_mmc.c b/drivers/mmc/host/ricoh_mmc.c
new file mode 100644
index 00000000000..1e8704533bc
--- /dev/null
+++ b/drivers/mmc/host/ricoh_mmc.c
@@ -0,0 +1,151 @@
+/*
+ * ricoh_mmc.c - Dummy driver to disable the Rioch MMC controller.
+ *
+ * Copyright (C) 2007 Philip Langdale, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+/*
+ * This is a conceptually ridiculous driver, but it is required by the way
+ * the Ricoh multi-function R5C832 works. This chip implements firewire
+ * and four different memory card controllers. Two of those controllers are
+ * an SDHCI controller and a proprietary MMC controller. The linux SDHCI
+ * driver supports MMC cards but the chip detects MMC cards in hardware
+ * and directs them to the MMC controller - so the SDHCI driver never sees
+ * them. To get around this, we must disable the useless MMC controller.
+ * At that point, the SDHCI controller will start seeing them. As a bonus,
+ * a detection event occurs immediately, even if the MMC card is already
+ * in the reader.
+ *
+ * The relevant registers live on the firewire function, so this is unavoidably
+ * ugly. Such is life.
+ */
+
+#include <linux/pci.h>
+
+#define DRIVER_NAME "ricoh-mmc"
+
+static const struct pci_device_id pci_ids[] __devinitdata = {
+ {
+ .vendor = PCI_VENDOR_ID_RICOH,
+ .device = PCI_DEVICE_ID_RICOH_R5C843,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static int __devinit ricoh_mmc_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ u8 rev;
+
+ struct pci_dev *fw_dev = NULL;
+
+ BUG_ON(pdev == NULL);
+ BUG_ON(ent == NULL);
+
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
+
+ printk(KERN_INFO DRIVER_NAME
+ ": Ricoh MMC controller found at %s [%04x:%04x] (rev %x)\n",
+ pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
+ (int)rev);
+
+ while ((fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) {
+ if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) &&
+ pdev->bus == fw_dev->bus) {
+ u8 write_enable;
+ u8 disable;
+
+ pci_read_config_byte(fw_dev, 0xCB, &disable);
+ if (disable & 0x02) {
+ printk(KERN_INFO DRIVER_NAME
+ ": Controller already disabled. Nothing to do.\n");
+ return -ENODEV;
+ }
+
+ pci_read_config_byte(fw_dev, 0xCA, &write_enable);
+ pci_write_config_byte(fw_dev, 0xCA, 0x57);
+ pci_write_config_byte(fw_dev, 0xCB, disable | 0x02);
+ pci_write_config_byte(fw_dev, 0xCA, write_enable);
+
+ pci_set_drvdata(pdev, fw_dev);
+
+ printk(KERN_INFO DRIVER_NAME
+ ": Controller is now disabled.\n");
+
+ break;
+ }
+ }
+
+ if (pci_get_drvdata(pdev) == NULL) {
+ printk(KERN_WARNING DRIVER_NAME
+ ": Main firewire function not found. Cannot disable controller.\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __devexit ricoh_mmc_remove(struct pci_dev *pdev)
+{
+ u8 write_enable;
+ u8 disable;
+ struct pci_dev *fw_dev = NULL;
+
+ fw_dev = pci_get_drvdata(pdev);
+ BUG_ON(fw_dev == NULL);
+
+ pci_read_config_byte(fw_dev, 0xCA, &write_enable);
+ pci_read_config_byte(fw_dev, 0xCB, &disable);
+ pci_write_config_byte(fw_dev, 0xCA, 0x57);
+ pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02);
+ pci_write_config_byte(fw_dev, 0xCA, write_enable);
+
+ printk(KERN_INFO DRIVER_NAME
+ ": Controller is now re-enabled.\n");
+
+ pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_driver ricoh_mmc_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pci_ids,
+ .probe = ricoh_mmc_probe,
+ .remove = __devexit_p(ricoh_mmc_remove),
+};
+
+/*****************************************************************************\
+ * *
+ * Driver init/exit *
+ * *
+\*****************************************************************************/
+
+static int __init ricoh_mmc_drv_init(void)
+{
+ printk(KERN_INFO DRIVER_NAME
+ ": Ricoh MMC Controller disabling driver\n");
+ printk(KERN_INFO DRIVER_NAME ": Copyright(c) Philip Langdale\n");
+
+ return pci_register_driver(&ricoh_mmc_driver);
+}
+
+static void __exit ricoh_mmc_drv_exit(void)
+{
+ pci_unregister_driver(&ricoh_mmc_driver);
+}
+
+module_init(ricoh_mmc_drv_init);
+module_exit(ricoh_mmc_drv_exit);
+
+MODULE_AUTHOR("Philip Langdale <philipl@alumni.utexas.net>");
+MODULE_DESCRIPTION("Ricoh MMC Controller disabling driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 20a7d89e01b..ff59d2e0475 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -13,11 +13,10 @@
#include <linux/highmem.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
#include <linux/mmc/host.h>
-#include <asm/scatterlist.h>
-
#include "sdhci.h"
#define DRIVER_NAME "sdhci"
@@ -25,8 +24,6 @@
#define DBG(f, x...) \
pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
-static unsigned int debug_nodma = 0;
-static unsigned int debug_forcedma = 0;
static unsigned int debug_quirks = 0;
#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0)
@@ -35,6 +32,7 @@ static unsigned int debug_quirks = 0;
#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3)
#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4)
+#define SDHCI_QUIRK_BROKEN_DMA (1<<5)
static const struct pci_device_id pci_ids[] __devinitdata = {
{
@@ -68,7 +66,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.device = PCI_DEVICE_ID_ENE_CB712_SD,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE,
+ .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE |
+ SDHCI_QUIRK_BROKEN_DMA,
},
{
@@ -76,7 +75,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.device = PCI_DEVICE_ID_ENE_CB712_SD_2,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE,
+ .driver_data = SDHCI_QUIRK_SINGLE_POWER_WRITE |
+ SDHCI_QUIRK_BROKEN_DMA,
},
{
@@ -132,7 +132,7 @@ static void sdhci_dumpregs(struct sdhci_host *host)
readb(host->ioaddr + SDHCI_POWER_CONTROL),
readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL));
printk(KERN_DEBUG DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n",
- readb(host->ioaddr + SDHCI_WALK_UP_CONTROL),
+ readb(host->ioaddr + SDHCI_WAKE_UP_CONTROL),
readw(host->ioaddr + SDHCI_CLOCK_CONTROL));
printk(KERN_DEBUG DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n",
readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL),
@@ -230,7 +230,7 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
{
- return page_address(host->cur_sg->page) + host->cur_sg->offset;
+ return sg_virt(host->cur_sg);
}
static inline int sdhci_next_sg(struct sdhci_host* host)
@@ -481,16 +481,16 @@ static void sdhci_finish_data(struct sdhci_host *host)
* Controller doesn't count down when in single block mode.
*/
if (data->blocks == 1)
- blocks = (data->error == MMC_ERR_NONE) ? 0 : 1;
+ blocks = (data->error == 0) ? 0 : 1;
else
blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
data->bytes_xfered = data->blksz * (data->blocks - blocks);
- if ((data->error == MMC_ERR_NONE) && blocks) {
+ if (!data->error && blocks) {
printk(KERN_ERR "%s: Controller signalled completion even "
"though there were blocks left.\n",
mmc_hostname(host->mmc));
- data->error = MMC_ERR_FAILED;
+ data->error = -EIO;
}
if (data->stop) {
@@ -498,7 +498,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
* The controller needs a reset of internal state machines
* upon error conditions.
*/
- if (data->error != MMC_ERR_NONE) {
+ if (data->error) {
sdhci_reset(host, SDHCI_RESET_CMD);
sdhci_reset(host, SDHCI_RESET_DATA);
}
@@ -533,7 +533,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
printk(KERN_ERR "%s: Controller never released "
"inhibit bit(s).\n", mmc_hostname(host->mmc));
sdhci_dumpregs(host);
- cmd->error = MMC_ERR_FAILED;
+ cmd->error = -EIO;
tasklet_schedule(&host->finish_tasklet);
return;
}
@@ -554,7 +554,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
printk(KERN_ERR "%s: Unsupported response type!\n",
mmc_hostname(host->mmc));
- cmd->error = MMC_ERR_INVALID;
+ cmd->error = -EINVAL;
tasklet_schedule(&host->finish_tasklet);
return;
}
@@ -601,7 +601,7 @@ static void sdhci_finish_command(struct sdhci_host *host)
}
}
- host->cmd->error = MMC_ERR_NONE;
+ host->cmd->error = 0;
if (host->data && host->data_early)
sdhci_finish_data(host);
@@ -722,7 +722,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = mrq;
if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
- host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+ host->mrq->cmd->error = -ENOMEDIUM;
tasklet_schedule(&host->finish_tasklet);
} else
sdhci_send_command(host, mrq->cmd);
@@ -800,10 +800,35 @@ static int sdhci_get_ro(struct mmc_host *mmc)
return !(present & SDHCI_WRITE_PROTECT);
}
+static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct sdhci_host *host;
+ unsigned long flags;
+ u32 ier;
+
+ host = mmc_priv(mmc);
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ ier = readl(host->ioaddr + SDHCI_INT_ENABLE);
+
+ ier &= ~SDHCI_INT_CARD_INT;
+ if (enable)
+ ier |= SDHCI_INT_CARD_INT;
+
+ writel(ier, host->ioaddr + SDHCI_INT_ENABLE);
+ writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+
+ mmiowb();
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
static const struct mmc_host_ops sdhci_ops = {
.request = sdhci_request,
.set_ios = sdhci_set_ios,
.get_ro = sdhci_get_ro,
+ .enable_sdio_irq = sdhci_enable_sdio_irq,
};
/*****************************************************************************\
@@ -831,7 +856,7 @@ static void sdhci_tasklet_card(unsigned long param)
sdhci_reset(host, SDHCI_RESET_CMD);
sdhci_reset(host, SDHCI_RESET_DATA);
- host->mrq->cmd->error = MMC_ERR_FAILED;
+ host->mrq->cmd->error = -ENOMEDIUM;
tasklet_schedule(&host->finish_tasklet);
}
}
@@ -859,9 +884,9 @@ static void sdhci_tasklet_finish(unsigned long param)
* The controller needs a reset of internal state machines
* upon error conditions.
*/
- if ((mrq->cmd->error != MMC_ERR_NONE) ||
- (mrq->data && ((mrq->data->error != MMC_ERR_NONE) ||
- (mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) {
+ if (mrq->cmd->error ||
+ (mrq->data && (mrq->data->error ||
+ (mrq->data->stop && mrq->data->stop->error)))) {
/* Some controllers need this kick or reset won't work here */
if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
@@ -906,13 +931,13 @@ static void sdhci_timeout_timer(unsigned long data)
sdhci_dumpregs(host);
if (host->data) {
- host->data->error = MMC_ERR_TIMEOUT;
+ host->data->error = -ETIMEDOUT;
sdhci_finish_data(host);
} else {
if (host->cmd)
- host->cmd->error = MMC_ERR_TIMEOUT;
+ host->cmd->error = -ETIMEDOUT;
else
- host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+ host->mrq->cmd->error = -ETIMEDOUT;
tasklet_schedule(&host->finish_tasklet);
}
@@ -941,13 +966,12 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
}
if (intmask & SDHCI_INT_TIMEOUT)
- host->cmd->error = MMC_ERR_TIMEOUT;
- else if (intmask & SDHCI_INT_CRC)
- host->cmd->error = MMC_ERR_BADCRC;
- else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX))
- host->cmd->error = MMC_ERR_FAILED;
+ host->cmd->error = -ETIMEDOUT;
+ else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
+ SDHCI_INT_INDEX))
+ host->cmd->error = -EILSEQ;
- if (host->cmd->error != MMC_ERR_NONE)
+ if (host->cmd->error)
tasklet_schedule(&host->finish_tasklet);
else if (intmask & SDHCI_INT_RESPONSE)
sdhci_finish_command(host);
@@ -974,13 +998,11 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
}
if (intmask & SDHCI_INT_DATA_TIMEOUT)
- host->data->error = MMC_ERR_TIMEOUT;
- else if (intmask & SDHCI_INT_DATA_CRC)
- host->data->error = MMC_ERR_BADCRC;
- else if (intmask & SDHCI_INT_DATA_END_BIT)
- host->data->error = MMC_ERR_FAILED;
+ host->data->error = -ETIMEDOUT;
+ else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
+ host->data->error = -EILSEQ;
- if (host->data->error != MMC_ERR_NONE)
+ if (host->data->error)
sdhci_finish_data(host);
else {
if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
@@ -1015,6 +1037,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
irqreturn_t result;
struct sdhci_host* host = dev_id;
u32 intmask;
+ int cardint = 0;
spin_lock(&host->lock);
@@ -1059,6 +1082,11 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
intmask &= ~SDHCI_INT_BUS_POWER;
+ if (intmask & SDHCI_INT_CARD_INT)
+ cardint = 1;
+
+ intmask &= ~SDHCI_INT_CARD_INT;
+
if (intmask) {
printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",
mmc_hostname(host->mmc), intmask);
@@ -1073,6 +1101,12 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
out:
spin_unlock(&host->lock);
+ /*
+ * We have to delay this as it calls back into the driver.
+ */
+ if (cardint)
+ mmc_signal_sdio_irq(host->mmc);
+
return result;
}
@@ -1258,20 +1292,26 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
- if (debug_nodma)
- DBG("DMA forced off\n");
- else if (debug_forcedma) {
- DBG("DMA forced on\n");
- host->flags |= SDHCI_USE_DMA;
- } else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
+ if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
host->flags |= SDHCI_USE_DMA;
- else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA)
- DBG("Controller doesn't have DMA interface\n");
else if (!(caps & SDHCI_CAN_DO_DMA))
DBG("Controller doesn't have DMA capability\n");
else
host->flags |= SDHCI_USE_DMA;
+ if ((chip->quirks & SDHCI_QUIRK_BROKEN_DMA) &&
+ (host->flags & SDHCI_USE_DMA)) {
+ DBG("Disabling DMA as it is marked broken\n");
+ host->flags &= ~SDHCI_USE_DMA;
+ }
+
+ if (((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) &&
+ (host->flags & SDHCI_USE_DMA)) {
+ printk(KERN_WARNING "%s: Will use DMA "
+ "mode even though HW doesn't fully "
+ "claim to support it.\n", host->slot_descr);
+ }
+
if (host->flags & SDHCI_USE_DMA) {
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_WARNING "%s: No suitable DMA available. "
@@ -1312,7 +1352,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
mmc->ops = &sdhci_ops;
mmc->f_min = host->max_clk / 256;
mmc->f_max = host->max_clk;
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SDIO_IRQ;
if (caps & SDHCI_CAN_DO_HISPD)
mmc->caps |= MMC_CAP_SD_HIGHSPEED;
@@ -1565,14 +1605,10 @@ static void __exit sdhci_drv_exit(void)
module_init(sdhci_drv_init);
module_exit(sdhci_drv_exit);
-module_param(debug_nodma, uint, 0444);
-module_param(debug_forcedma, uint, 0444);
module_param(debug_quirks, uint, 0444);
MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
MODULE_LICENSE("GPL");
-MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");
-MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)");
MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index e28987d6d2e..05195ea900f 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -81,7 +81,7 @@
#define SDHCI_BLOCK_GAP_CONTROL 0x2A
-#define SDHCI_WALK_UP_CONTROL 0x2B
+#define SDHCI_WAKE_UP_CONTROL 0x2B
#define SDHCI_CLOCK_CONTROL 0x2C
#define SDHCI_DIVIDER_SHIFT 8
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index 8b736e96844..c11a3d25605 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -16,6 +16,7 @@
#include <linux/mmc/host.h>
#include <linux/highmem.h>
#include <linux/scatterlist.h>
+#include <linux/log2.h>
#include <asm/io.h>
#define DRIVER_NAME "tifm_sd"
@@ -191,7 +192,7 @@ static void tifm_sd_transfer_data(struct tifm_sd *host)
}
off = sg[host->sg_pos].offset + host->block_pos;
- pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
+ pg = nth_page(sg_page(&sg[host->sg_pos]), off >> PAGE_SHIFT);
p_off = offset_in_page(off);
p_cnt = PAGE_SIZE - p_off;
p_cnt = min(p_cnt, cnt);
@@ -240,18 +241,18 @@ static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data)
}
off = sg[host->sg_pos].offset + host->block_pos;
- pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
+ pg = nth_page(sg_page(&sg[host->sg_pos]), off >> PAGE_SHIFT);
p_off = offset_in_page(off);
p_cnt = PAGE_SIZE - p_off;
p_cnt = min(p_cnt, cnt);
p_cnt = min(p_cnt, t_size);
if (r_data->flags & MMC_DATA_WRITE)
- tifm_sd_copy_page(host->bounce_buf.page,
+ tifm_sd_copy_page(sg_page(&host->bounce_buf),
r_data->blksz - t_size,
pg, p_off, p_cnt);
else if (r_data->flags & MMC_DATA_READ)
- tifm_sd_copy_page(pg, p_off, host->bounce_buf.page,
+ tifm_sd_copy_page(pg, p_off, sg_page(&host->bounce_buf),
r_data->blksz - t_size, p_cnt);
t_size -= p_cnt;
@@ -404,14 +405,14 @@ static void tifm_sd_check_status(struct tifm_sd *host)
struct tifm_dev *sock = host->dev;
struct mmc_command *cmd = host->req->cmd;
- if (cmd->error != MMC_ERR_NONE)
+ if (cmd->error)
goto finish_request;
if (!(host->cmd_flags & CMD_READY))
return;
if (cmd->data) {
- if (cmd->data->error != MMC_ERR_NONE) {
+ if (cmd->data->error) {
if ((host->cmd_flags & SCMD_ACTIVE)
&& !(host->cmd_flags & SCMD_READY))
return;
@@ -504,7 +505,7 @@ static void tifm_sd_card_event(struct tifm_dev *sock)
{
struct tifm_sd *host;
unsigned int host_status = 0;
- int cmd_error = MMC_ERR_NONE;
+ int cmd_error = 0;
struct mmc_command *cmd = NULL;
unsigned long flags;
@@ -521,15 +522,15 @@ static void tifm_sd_card_event(struct tifm_dev *sock)
writel(host_status & TIFM_MMCSD_ERRMASK,
sock->addr + SOCK_MMCSD_STATUS);
if (host_status & TIFM_MMCSD_CTO)
- cmd_error = MMC_ERR_TIMEOUT;
+ cmd_error = -ETIMEDOUT;
else if (host_status & TIFM_MMCSD_CCRC)
- cmd_error = MMC_ERR_BADCRC;
+ cmd_error = -EILSEQ;
if (cmd->data) {
if (host_status & TIFM_MMCSD_DTO)
- cmd->data->error = MMC_ERR_TIMEOUT;
+ cmd->data->error = -ETIMEDOUT;
else if (host_status & TIFM_MMCSD_DCRC)
- cmd->data->error = MMC_ERR_BADCRC;
+ cmd->data->error = -EILSEQ;
}
writel(TIFM_FIFO_INT_SETALL,
@@ -626,14 +627,21 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
spin_lock_irqsave(&sock->lock, flags);
if (host->eject) {
- spin_unlock_irqrestore(&sock->lock, flags);
+ mrq->cmd->error = -ENOMEDIUM;
goto err_out;
}
if (host->req) {
printk(KERN_ERR "%s : unfinished request detected\n",
sock->dev.bus_id);
- spin_unlock_irqrestore(&sock->lock, flags);
+ mrq->cmd->error = -ETIMEDOUT;
+ goto err_out;
+ }
+
+ if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
+ printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n",
+ sock->dev.bus_id, mrq->data->blksz);
+ mrq->cmd->error = -EINVAL;
goto err_out;
}
@@ -722,7 +730,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
return;
err_out:
- mrq->cmd->error = MMC_ERR_TIMEOUT;
+ spin_unlock_irqrestore(&sock->lock, flags);
mmc_request_done(mmc, mrq);
}
@@ -1012,9 +1020,9 @@ static void tifm_sd_remove(struct tifm_dev *sock)
writel(TIFM_FIFO_INT_SETALL,
sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
- host->req->cmd->error = MMC_ERR_TIMEOUT;
+ host->req->cmd->error = -ENOMEDIUM;
if (host->req->stop)
- host->req->stop->error = MMC_ERR_TIMEOUT;
+ host->req->stop->error = -ENOMEDIUM;
tasklet_schedule(&host->finish_tasklet);
}
spin_unlock_irqrestore(&sock->lock, flags);
diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c
index 9bf2a877113..4d5f3742187 100644
--- a/drivers/mmc/host/wbsd.c
+++ b/drivers/mmc/host/wbsd.c
@@ -33,10 +33,10 @@
#include <linux/pnp.h>
#include <linux/highmem.h>
#include <linux/mmc/host.h>
+#include <linux/scatterlist.h>
#include <asm/io.h>
#include <asm/dma.h>
-#include <asm/scatterlist.h>
#include "wbsd.h"
@@ -269,7 +269,7 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
{
- return page_address(host->cur_sg->page) + host->cur_sg->offset;
+ return sg_virt(host->cur_sg);
}
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
@@ -283,7 +283,7 @@ static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
len = data->sg_len;
for (i = 0; i < len; i++) {
- sgbuf = page_address(sg[i].page) + sg[i].offset;
+ sgbuf = sg_virt(&sg[i]);
memcpy(dmabuf, sgbuf, sg[i].length);
dmabuf += sg[i].length;
}
@@ -300,7 +300,7 @@ static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
len = data->sg_len;
for (i = 0; i < len; i++) {
- sgbuf = page_address(sg[i].page) + sg[i].offset;
+ sgbuf = sg_virt(&sg[i]);
memcpy(sgbuf, dmabuf, sg[i].length);
dmabuf += sg[i].length;
}
@@ -317,7 +317,7 @@ static inline void wbsd_get_short_reply(struct wbsd_host *host,
* Correct response type?
*/
if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) {
- cmd->error = MMC_ERR_INVALID;
+ cmd->error = -EILSEQ;
return;
}
@@ -337,7 +337,7 @@ static inline void wbsd_get_long_reply(struct wbsd_host *host,
* Correct response type?
*/
if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) {
- cmd->error = MMC_ERR_INVALID;
+ cmd->error = -EILSEQ;
return;
}
@@ -372,7 +372,7 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
for (i = 3; i >= 0; i--)
outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR);
- cmd->error = MMC_ERR_NONE;
+ cmd->error = 0;
/*
* Wait for the request to complete.
@@ -392,13 +392,13 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
/* Card removed? */
if (isr & WBSD_INT_CARD)
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ENOMEDIUM;
/* Timeout? */
else if (isr & WBSD_INT_TIMEOUT)
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ETIMEDOUT;
/* CRC? */
else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC))
- cmd->error = MMC_ERR_BADCRC;
+ cmd->error = -EILSEQ;
/* All ok */
else {
if (cmd->flags & MMC_RSP_136)
@@ -585,7 +585,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH);
wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
} else {
- data->error = MMC_ERR_INVALID;
+ data->error = -EINVAL;
return;
}
@@ -607,7 +607,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
*/
BUG_ON(size > 0x10000);
if (size > 0x10000) {
- data->error = MMC_ERR_INVALID;
+ data->error = -EINVAL;
return;
}
@@ -669,7 +669,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
}
}
- data->error = MMC_ERR_NONE;
+ data->error = 0;
}
static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
@@ -724,8 +724,8 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
"%d bytes left.\n",
mmc_hostname(host->mmc), count);
- if (data->error == MMC_ERR_NONE)
- data->error = MMC_ERR_FAILED;
+ if (!data->error)
+ data->error = -EIO;
} else {
/*
* Transfer data from DMA buffer to
@@ -735,7 +735,7 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
wbsd_dma_to_sg(host, data);
}
- if (data->error != MMC_ERR_NONE) {
+ if (data->error) {
if (data->bytes_xfered)
data->bytes_xfered -= data->blksz;
}
@@ -767,11 +767,10 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = mrq;
/*
- * If there is no card in the slot then
- * timeout immediatly.
+ * Check that there is actually a card in the slot.
*/
if (!(host->flags & WBSD_FCARD_PRESENT)) {
- cmd->error = MMC_ERR_TIMEOUT;
+ cmd->error = -ENOMEDIUM;
goto done;
}
@@ -807,7 +806,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
"supported by this controller.\n",
mmc_hostname(host->mmc), cmd->opcode);
#endif
- cmd->error = MMC_ERR_INVALID;
+ cmd->error = -EINVAL;
goto done;
};
@@ -819,7 +818,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (cmd->data) {
wbsd_prepare_data(host, cmd->data);
- if (cmd->data->error != MMC_ERR_NONE)
+ if (cmd->data->error)
goto done;
}
@@ -830,7 +829,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
* will be finished after the data has
* transfered.
*/
- if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
+ if (cmd->data && !cmd->error) {
/*
* Dirty fix for hardware bug.
*/
@@ -1033,7 +1032,7 @@ static void wbsd_tasklet_card(unsigned long param)
mmc_hostname(host->mmc));
wbsd_reset(host);
- host->mrq->cmd->error = MMC_ERR_FAILED;
+ host->mrq->cmd->error = -ENOMEDIUM;
tasklet_schedule(&host->finish_tasklet);
}
@@ -1097,7 +1096,7 @@ static void wbsd_tasklet_crc(unsigned long param)
DBGF("CRC error\n");
- data->error = MMC_ERR_BADCRC;
+ data->error = -EILSEQ;
tasklet_schedule(&host->finish_tasklet);
@@ -1121,7 +1120,7 @@ static void wbsd_tasklet_timeout(unsigned long param)
DBGF("Timeout\n");
- data->error = MMC_ERR_TIMEOUT;
+ data->error = -ETIMEDOUT;
tasklet_schedule(&host->finish_tasklet);
@@ -1220,7 +1219,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
mmc->f_min = 375000;
mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
spin_lock_init(&host->lock);
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index fbec8cd55e3..8848e8ac705 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -278,6 +278,14 @@ config SSFDC
This enables read only access to SmartMedia formatted NAND
flash. You can mount it with FAT file system.
+config MTD_OOPS
+ tristate "Log panic/oops to an MTD buffer"
+ depends on MTD
+ help
+ This enables panic and oops messages to be logged to a circular
+ buffer in a flash partition where it can be read back at some
+ later point.
+
source "drivers/mtd/chips/Kconfig"
source "drivers/mtd/maps/Kconfig"
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 6d958a4566f..7f0b04b4caa 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_NFTL) += nftl.o
obj-$(CONFIG_INFTL) += inftl.o
obj-$(CONFIG_RFD_FTL) += rfd_ftl.o
obj-$(CONFIG_SSFDC) += ssfdc.o
+obj-$(CONFIG_MTD_OOPS) += mtdoops.o
nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 2f19fa78d24..a9eb1c51624 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -85,6 +85,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
size_t len);
+static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
#include "fwh_lock.h"
@@ -526,7 +527,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
struct cfi_pri_intelext *extp = cfi->cmdset_priv;
/*
- * Probing of multi-partition flash ships.
+ * Probing of multi-partition flash chips.
*
* To support multiple partitions when available, we simply arrange
* for each of them to have their own flchip structure even if they
@@ -641,73 +642,13 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
/*
* *********** CHIP ACCESS FUNCTIONS ***********
*/
-
-static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
+static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
{
DECLARE_WAITQUEUE(wait, current);
struct cfi_private *cfi = map->fldrv_priv;
map_word status, status_OK = CMD(0x80), status_PWS = CMD(0x01);
- unsigned long timeo;
struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
-
- resettime:
- timeo = jiffies + HZ;
- retry:
- if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) {
- /*
- * OK. We have possibility for contension on the write/erase
- * operations which are global to the real chip and not per
- * partition. So let's fight it over in the partition which
- * currently has authority on the operation.
- *
- * The rules are as follows:
- *
- * - any write operation must own shared->writing.
- *
- * - any erase operation must own _both_ shared->writing and
- * shared->erasing.
- *
- * - contension arbitration is handled in the owner's context.
- *
- * The 'shared' struct can be read and/or written only when
- * its lock is taken.
- */
- struct flchip_shared *shared = chip->priv;
- struct flchip *contender;
- spin_lock(&shared->lock);
- contender = shared->writing;
- if (contender && contender != chip) {
- /*
- * The engine to perform desired operation on this
- * partition is already in use by someone else.
- * Let's fight over it in the context of the chip
- * currently using it. If it is possible to suspend,
- * that other partition will do just that, otherwise
- * it'll happily send us to sleep. In any case, when
- * get_chip returns success we're clear to go ahead.
- */
- int ret = spin_trylock(contender->mutex);
- spin_unlock(&shared->lock);
- if (!ret)
- goto retry;
- spin_unlock(chip->mutex);
- ret = get_chip(map, contender, contender->start, mode);
- spin_lock(chip->mutex);
- if (ret) {
- spin_unlock(contender->mutex);
- return ret;
- }
- timeo = jiffies + HZ;
- spin_lock(&shared->lock);
- spin_unlock(contender->mutex);
- }
-
- /* We now own it */
- shared->writing = chip;
- if (mode == FL_ERASING)
- shared->erasing = chip;
- spin_unlock(&shared->lock);
- }
+ unsigned long timeo = jiffies + HZ;
switch (chip->state) {
@@ -722,16 +663,11 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
if (chip->priv && map_word_andequal(map, status, status_PWS, status_PWS))
break;
- if (time_after(jiffies, timeo)) {
- printk(KERN_ERR "%s: Waiting for chip to be ready timed out. Status %lx\n",
- map->name, status.x[0]);
- return -EIO;
- }
spin_unlock(chip->mutex);
cfi_udelay(1);
spin_lock(chip->mutex);
/* Someone else might have been playing with it. */
- goto retry;
+ return -EAGAIN;
}
case FL_READY:
@@ -798,6 +734,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
if (mode == FL_READY && chip->oldstate == FL_READY)
return 0;
+ case FL_SHUTDOWN:
+ /* The machine is rebooting now,so no one can get chip anymore */
+ return -EIO;
default:
sleep:
set_current_state(TASK_UNINTERRUPTIBLE);
@@ -806,10 +745,82 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
schedule();
remove_wait_queue(&chip->wq, &wait);
spin_lock(chip->mutex);
- goto resettime;
+ return -EAGAIN;
}
}
+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
+{
+ int ret;
+
+ retry:
+ if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING
+ || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
+ /*
+ * OK. We have possibility for contention on the write/erase
+ * operations which are global to the real chip and not per
+ * partition. So let's fight it over in the partition which
+ * currently has authority on the operation.
+ *
+ * The rules are as follows:
+ *
+ * - any write operation must own shared->writing.
+ *
+ * - any erase operation must own _both_ shared->writing and
+ * shared->erasing.
+ *
+ * - contention arbitration is handled in the owner's context.
+ *
+ * The 'shared' struct can be read and/or written only when
+ * its lock is taken.
+ */
+ struct flchip_shared *shared = chip->priv;
+ struct flchip *contender;
+ spin_lock(&shared->lock);
+ contender = shared->writing;
+ if (contender && contender != chip) {
+ /*
+ * The engine to perform desired operation on this
+ * partition is already in use by someone else.
+ * Let's fight over it in the context of the chip
+ * currently using it. If it is possible to suspend,
+ * that other partition will do just that, otherwise
+ * it'll happily send us to sleep. In any case, when
+ * get_chip returns success we're clear to go ahead.
+ */
+ ret = spin_trylock(contender->mutex);
+ spin_unlock(&shared->lock);
+ if (!ret)
+ goto retry;
+ spin_unlock(chip->mutex);
+ ret = chip_ready(map, contender, contender->start, mode);
+ spin_lock(chip->mutex);
+
+ if (ret == -EAGAIN) {
+ spin_unlock(contender->mutex);
+ goto retry;
+ }
+ if (ret) {
+ spin_unlock(contender->mutex);
+ return ret;
+ }
+ spin_lock(&shared->lock);
+ spin_unlock(contender->mutex);
+ }
+
+ /* We now own it */
+ shared->writing = chip;
+ if (mode == FL_ERASING)
+ shared->erasing = chip;
+ spin_unlock(&shared->lock);
+ }
+ ret = chip_ready(map, chip, adr, mode);
+ if (ret == -EAGAIN)
+ goto retry;
+
+ return ret;
+}
+
static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
{
struct cfi_private *cfi = map->fldrv_priv;
@@ -1166,28 +1177,34 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
- unsigned long ofs;
+ unsigned long ofs, last_end = 0;
int chipnum;
int ret = 0;
if (!map->virt || (from + len > mtd->size))
return -EINVAL;
- *mtdbuf = (void *)map->virt + from;
- *retlen = 0;
-
/* Now lock the chip(s) to POINT state */
/* ofs: offset within the first chip that the first read should start */
chipnum = (from >> cfi->chipshift);
ofs = from - (chipnum << cfi->chipshift);
+ *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs;
+ *retlen = 0;
+
while (len) {
unsigned long thislen;
if (chipnum >= cfi->numchips)
break;
+ /* We cannot point across chips that are virtually disjoint */
+ if (!last_end)
+ last_end = cfi->chips[chipnum].start;
+ else if (cfi->chips[chipnum].start != last_end)
+ break;
+
if ((len + ofs -1) >> cfi->chipshift)
thislen = (1<<cfi->chipshift) - ofs;
else
@@ -1201,6 +1218,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
len -= thislen;
ofs = 0;
+ last_end += 1 << cfi->chipshift;
chipnum++;
}
return 0;
@@ -1780,7 +1798,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
return ret;
}
-int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+static int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
{
unsigned long ofs, len;
int ret;
@@ -1930,7 +1948,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
__FUNCTION__, ofs, len);
cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
- ofs, len, 0);
+ ofs, len, NULL);
#endif
ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
@@ -1940,7 +1958,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
__FUNCTION__, ret);
cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
- ofs, len, 0);
+ ofs, len, NULL);
#endif
return ret;
@@ -1954,7 +1972,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
__FUNCTION__, ofs, len);
cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
- ofs, len, 0);
+ ofs, len, NULL);
#endif
ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
@@ -1964,7 +1982,7 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
__FUNCTION__, ret);
cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
- ofs, len, 0);
+ ofs, len, NULL);
#endif
return ret;
@@ -2255,7 +2273,7 @@ static void cfi_intelext_save_locks(struct mtd_info *mtd)
adr = region->offset + block * len;
status = cfi_varsize_frob(mtd,
- do_getlockstatus_oneblock, adr, len, 0);
+ do_getlockstatus_oneblock, adr, len, NULL);
if (status)
set_bit(block, region->lockmap);
else
@@ -2402,10 +2420,10 @@ static int cfi_intelext_reset(struct mtd_info *mtd)
and switch to array mode so any bootloader in
flash is accessible for soft reboot. */
spin_lock(chip->mutex);
- ret = get_chip(map, chip, chip->start, FL_SYNCING);
+ ret = get_chip(map, chip, chip->start, FL_SHUTDOWN);
if (!ret) {
map_write(map, CMD(0xff), chip->start);
- chip->state = FL_READY;
+ chip->state = FL_SHUTDOWN;
}
spin_unlock(chip->mutex);
}
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 1f644584046..389acc600f5 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -1609,7 +1609,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
}
-int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
{
unsigned long ofs, len;
int ret;
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index 58e561e8769..a67b23b87fc 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -17,7 +17,6 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
@@ -70,6 +69,7 @@
/* Fujitsu */
#define MBM29F040C 0x00A4
+#define MBM29F800BA 0x2258
#define MBM29LV650UE 0x22D7
#define MBM29LV320TE 0x22F6
#define MBM29LV320BE 0x22F9
@@ -129,6 +129,7 @@
#define LH28F640BF 0x00b0
/* ST - www.st.com */
+#define M29F800AB 0x0058
#define M29W800DT 0x00D7
#define M29W800DB 0x005B
#define M29W160DT 0x22C4
@@ -646,6 +647,23 @@ static const struct amd_flash_info jedec_table[] = {
}
}, {
.mfr_id = MANUFACTURER_FUJITSU,
+ .dev_id = MBM29F800BA,
+ .name = "Fujitsu MBM29F800BA",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
+ },
+ .DevSize = SIZE_1MiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x04000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x10000,15),
+ }
+ }, {
+ .mfr_id = MANUFACTURER_FUJITSU,
.dev_id = MBM29LV650UE,
.name = "Fujitsu MBM29LV650UE",
.uaddr = {
@@ -1510,6 +1528,23 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x1000,256)
}
+ }, {
+ .mfr_id = MANUFACTURER_ST,
+ .dev_id = M29F800AB,
+ .name = "ST M29F800AB",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
+ },
+ .DevSize = SIZE_1MiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 4,
+ .regions = {
+ ERASEINFO(0x04000,1),
+ ERASEINFO(0x02000,2),
+ ERASEINFO(0x08000,1),
+ ERASEINFO(0x10000,15),
+ }
}, {
.mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
.dev_id = M29W800DT,
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index ff642f8fbee..811d56fd890 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -60,21 +60,22 @@ config MTD_DATAFLASH
Sometimes DataFlash chips are packaged inside MMC-format
cards; at this writing, the MMC stack won't handle those.
-config MTD_DATAFLASH26
- tristate "AT91RM9200 DataFlash AT26xxx"
- depends on MTD && ARCH_AT91RM9200 && AT91_SPI
- help
- This enables access to the DataFlash chip (AT26xxx) on an
- AT91RM9200-based board.
- If you have such a board and such a DataFlash, say 'Y'.
-
config MTD_M25P80
- tristate "Support for M25 SPI Flash"
+ tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
depends on SPI_MASTER && EXPERIMENTAL
help
- This enables access to ST M25P80 and similar SPI flash chips,
- used for program and data storage. Set up your spi devices
- with the right board-specific platform data.
+ This enables access to most modern SPI flash chips, used for
+ program and data storage. Series supported include Atmel AT26DF,
+ Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X. Other chips
+ are supported as well. See the driver source for the current list,
+ or to add other chips.
+
+ Note that the original DataFlash chips (AT45 series, not AT26DF),
+ need an entirely different driver.
+
+ Set up your spi devices with the right board-specific platform data,
+ if you want to specify device partitioning or to use a device which
+ doesn't support the JEDEC ID instruction.
config MTD_SLRAM
tristate "Uncached system RAM"
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 8ab568b3f53..0f788d5c4bf 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -16,5 +16,4 @@ obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
obj-$(CONFIG_MTD_LART) += lart.o
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
-obj-$(CONFIG_MTD_DATAFLASH26) += at91_dataflash26.o
obj-$(CONFIG_MTD_M25P80) += m25p80.o
diff --git a/drivers/mtd/devices/at91_dataflash26.c b/drivers/mtd/devices/at91_dataflash26.c
deleted file mode 100644
index 64ce37f986f..00000000000
--- a/drivers/mtd/devices/at91_dataflash26.c
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder)
- * This is a largely modified version of at91_dataflash.c that
- * supports AT26xxx dataflash chips. The original driver supports
- * AT45xxx chips.
- *
- * Note: This driver was only tested with an AT26F004. It should be
- * easy to make it work with other AT26xxx dataflash devices, though.
- *
- * Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de>
- * original Copyright (C) SAN People (Pty) Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/mtd/mtd.h>
-
-#include <asm/arch/at91_spi.h>
-
-#define DATAFLASH_MAX_DEVICES 4 /* max number of dataflash devices */
-
-#define MANUFACTURER_ID_ATMEL 0x1F
-
-/* command codes */
-
-#define AT26_OP_READ_STATUS 0x05
-#define AT26_OP_READ_DEV_ID 0x9F
-#define AT26_OP_ERASE_PAGE_4K 0x20
-#define AT26_OP_READ_ARRAY_FAST 0x0B
-#define AT26_OP_SEQUENTIAL_WRITE 0xAF
-#define AT26_OP_WRITE_ENABLE 0x06
-#define AT26_OP_WRITE_DISABLE 0x04
-#define AT26_OP_SECTOR_PROTECT 0x36
-#define AT26_OP_SECTOR_UNPROTECT 0x39
-
-/* status register bits */
-
-#define AT26_STATUS_BUSY 0x01
-#define AT26_STATUS_WRITE_ENABLE 0x02
-
-struct dataflash_local
-{
- int spi; /* SPI chip-select number */
- unsigned int page_size; /* number of bytes per page */
-};
-
-
-/* Detected DataFlash devices */
-static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES];
-static int nr_devices = 0;
-
-/* Allocate a single SPI transfer descriptor. We're assuming that if multiple
- SPI transfers occur at the same time, spi_access_bus() will serialize them.
- If this is not valid, then either (i) each dataflash 'priv' structure
- needs it's own transfer descriptor, (ii) we lock this one, or (iii) use
- another mechanism. */
-static struct spi_transfer_list* spi_transfer_desc;
-
-/*
- * Perform a SPI transfer to access the DataFlash device.
- */
-static int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len,
- char* txnext, int txnext_len, char* rxnext, int rxnext_len)
-{
- struct spi_transfer_list* list = spi_transfer_desc;
-
- list->tx[0] = tx; list->txlen[0] = tx_len;
- list->rx[0] = rx; list->rxlen[0] = rx_len;
-
- list->tx[1] = txnext; list->txlen[1] = txnext_len;
- list->rx[1] = rxnext; list->rxlen[1] = rxnext_len;
-
- list->nr_transfers = nr;
- /* Note: spi_transfer() always returns 0, there are no error checks */
- return spi_transfer(list);
-}
-
-/*
- * Return the status of the DataFlash device.
- */
-static unsigned char at91_dataflash26_status(void)
-{
- unsigned char command[2];
-
- command[0] = AT26_OP_READ_STATUS;
- command[1] = 0;
-
- do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0);
-
- return command[1];
-}
-
-/*
- * Poll the DataFlash device until it is READY.
- */
-static unsigned char at91_dataflash26_waitready(void)
-{
- unsigned char status;
-
- while (1) {
- status = at91_dataflash26_status();
- if (!(status & AT26_STATUS_BUSY))
- return status;
- }
-}
-
-/*
- * Enable/disable write access
- */
- static void at91_dataflash26_write_enable(int enable)
-{
- unsigned char cmd[2];
-
- DEBUG(MTD_DEBUG_LEVEL3, "write_enable: enable=%i\n", enable);
-
- if (enable)
- cmd[0] = AT26_OP_WRITE_ENABLE;
- else
- cmd[0] = AT26_OP_WRITE_DISABLE;
- cmd[1] = 0;
-
- do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0);
-}
-
-/*
- * Protect/unprotect sector
- */
- static void at91_dataflash26_sector_protect(loff_t addr, int protect)
-{
- unsigned char cmd[4];
-
- DEBUG(MTD_DEBUG_LEVEL3, "sector_protect: addr=0x%06x prot=%d\n",
- addr, protect);
-
- if (protect)
- cmd[0] = AT26_OP_SECTOR_PROTECT;
- else
- cmd[0] = AT26_OP_SECTOR_UNPROTECT;
- cmd[1] = (addr & 0x00FF0000) >> 16;
- cmd[2] = (addr & 0x0000FF00) >> 8;
- cmd[3] = (addr & 0x000000FF);
-
- do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0);
-}
-
-/*
- * Erase blocks of flash.
- */
-static int at91_dataflash26_erase(struct mtd_info *mtd,
- struct erase_info *instr)
-{
- struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
- unsigned char cmd[4];
-
- DEBUG(MTD_DEBUG_LEVEL1, "dataflash_erase: addr=0x%06x len=%i\n",
- instr->addr, instr->len);
-
- /* Sanity checks */
- if (priv->page_size != 4096)
- return -EINVAL; /* Can't handle other sizes at the moment */
-
- if ( ((instr->len % mtd->erasesize) != 0)
- || ((instr->len % priv->page_size) != 0)
- || ((instr->addr % priv->page_size) != 0)
- || ((instr->addr + instr->len) > mtd->size))
- return -EINVAL;
-
- spi_access_bus(priv->spi);
-
- while (instr->len > 0) {
- at91_dataflash26_write_enable(1);
- at91_dataflash26_sector_protect(instr->addr, 0);
- at91_dataflash26_write_enable(1);
- cmd[0] = AT26_OP_ERASE_PAGE_4K;
- cmd[1] = (instr->addr & 0x00FF0000) >> 16;
- cmd[2] = (instr->addr & 0x0000FF00) >> 8;
- cmd[3] = (instr->addr & 0x000000FF);
-
- DEBUG(MTD_DEBUG_LEVEL3, "ERASE: (0x%02x) 0x%02x 0x%02x"
- "0x%02x\n",
- cmd[0], cmd[1], cmd[2], cmd[3]);
-
- do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0);
- at91_dataflash26_waitready();
-
- instr->addr += priv->page_size; /* next page */
- instr->len -= priv->page_size;
- }
-
- at91_dataflash26_write_enable(0);
- spi_release_bus(priv->spi);
-
- /* Inform MTD subsystem that erase is complete */
- instr->state = MTD_ERASE_DONE;
- if (instr->callback)
- instr->callback(instr);
-
- return 0;
-}
-
-/*
- * Read from the DataFlash device.
- * from : Start offset in flash device
- * len : Number of bytes to read
- * retlen : Number of bytes actually read
- * buf : Buffer that will receive data
- */
-static int at91_dataflash26_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
-{
- struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
- unsigned char cmd[5];
-
- DEBUG(MTD_DEBUG_LEVEL1, "dataflash_read: %lli .. %lli\n",
- from, from+len);
-
- *retlen = 0;
-
- /* Sanity checks */
- if (!len)
- return 0;
- if (from + len > mtd->size)
- return -EINVAL;
-
- cmd[0] = AT26_OP_READ_ARRAY_FAST;
- cmd[1] = (from & 0x00FF0000) >> 16;
- cmd[2] = (from & 0x0000FF00) >> 8;
- cmd[3] = (from & 0x000000FF);
- /* cmd[4] is a "Don't care" byte */
-
- DEBUG(MTD_DEBUG_LEVEL3, "READ: (0x%02x) 0x%02x 0x%02x 0x%02x\n",
- cmd[0], cmd[1], cmd[2], cmd[3]);
-
- spi_access_bus(priv->spi);
- do_spi_transfer(2, cmd, 5, cmd, 5, buf, len, buf, len);
- spi_release_bus(priv->spi);
-
- *retlen = len;
- return 0;
-}
-
-/*
- * Write to the DataFlash device.
- * to : Start offset in flash device
- * len : Number of bytes to write
- * retlen : Number of bytes actually written
- * buf : Buffer containing the data
- */
-static int at91_dataflash26_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
-{
- struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
- unsigned int addr, buf_index = 0;
- int ret = -EIO, sector, last_sector;
- unsigned char status, cmd[5];
-
- DEBUG(MTD_DEBUG_LEVEL1, "dataflash_write: %lli .. %lli\n", to, to+len);
-
- *retlen = 0;
-
- /* Sanity checks */
- if (!len)
- return 0;
- if (to + len > mtd->size)
- return -EINVAL;
-
- spi_access_bus(priv->spi);
-
- addr = to;
- last_sector = -1;
-
- while (buf_index < len) {
- sector = addr / priv->page_size;
- /* Write first byte if a new sector begins */
- if (sector != last_sector) {
- at91_dataflash26_write_enable(1);
- at91_dataflash26_sector_protect(addr, 0);
- at91_dataflash26_write_enable(1);
-
- /* Program first byte of a new sector */
- cmd[0] = AT26_OP_SEQUENTIAL_WRITE;
- cmd[1] = (addr & 0x00FF0000) >> 16;
- cmd[2] = (addr & 0x0000FF00) >> 8;
- cmd[3] = (addr & 0x000000FF);
- cmd[4] = buf[buf_index++];
- do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0);
- status = at91_dataflash26_waitready();
- addr++;
- /* On write errors, the chip resets the write enable
- flag. This also happens after the last byte of a
- sector is successfully programmed. */
- if ( ( !(status & AT26_STATUS_WRITE_ENABLE))
- && ((addr % priv->page_size) != 0) ) {
- DEBUG(MTD_DEBUG_LEVEL1,
- "write error1: addr=0x%06x, "
- "status=0x%02x\n", addr, status);
- goto write_err;
- }
- (*retlen)++;
- last_sector = sector;
- }
-
- /* Write subsequent bytes in the same sector */
- cmd[0] = AT26_OP_SEQUENTIAL_WRITE;
- cmd[1] = buf[buf_index++];
- do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0);
- status = at91_dataflash26_waitready();
- addr++;
-
- if ( ( !(status & AT26_STATUS_WRITE_ENABLE))
- && ((addr % priv->page_size) != 0) ) {
- DEBUG(MTD_DEBUG_LEVEL1, "write error2: addr=0x%06x, "
- "status=0x%02x\n", addr, status);
- goto write_err;
- }
-
- (*retlen)++;
- }
-
- ret = 0;
- at91_dataflash26_write_enable(0);
-write_err:
- spi_release_bus(priv->spi);
- return ret;
-}
-
-/*
- * Initialize and register DataFlash device with MTD subsystem.
- */
-static int __init add_dataflash(int channel, char *name, int nr_pages,
- int pagesize)
-{
- struct mtd_info *device;
- struct dataflash_local *priv;
-
- if (nr_devices >= DATAFLASH_MAX_DEVICES) {
- printk(KERN_ERR "at91_dataflash26: Too many devices "
- "detected\n");
- return 0;
- }
-
- device = kzalloc(sizeof(struct mtd_info) + strlen(name) + 8,
- GFP_KERNEL);
- if (!device)
- return -ENOMEM;
-
- device->name = (char *)&device[1];
- sprintf(device->name, "%s.spi%d", name, channel);
- device->size = nr_pages * pagesize;
- device->erasesize = pagesize;
- device->owner = THIS_MODULE;
- device->type = MTD_DATAFLASH;
- device->flags = MTD_CAP_NORFLASH;
- device->erase = at91_dataflash26_erase;
- device->read = at91_dataflash26_read;
- device->write = at91_dataflash26_write;
-
- priv = (struct dataflash_local *)kzalloc(sizeof(struct dataflash_local),
- GFP_KERNEL);
- if (!priv) {
- kfree(device);
- return -ENOMEM;
- }
-
- priv->spi = channel;
- priv->page_size = pagesize;
- device->priv = priv;
-
- mtd_devices[nr_devices] = device;
- nr_devices++;
- printk(KERN_INFO "at91_dataflash26: %s detected [spi%i] (%i bytes)\n",
- name, channel, device->size);
-
- return add_mtd_device(device);
-}
-
-/*
- * Detect and initialize DataFlash device connected to specified SPI channel.
- *
- */
-
-struct dataflash26_types {
- unsigned char id0;
- unsigned char id1;
- char *name;
- int pagesize;
- int nr_pages;
-};
-
-struct dataflash26_types df26_types[] = {
- {
- .id0 = 0x04,
- .id1 = 0x00,
- .name = "AT26F004",
- .pagesize = 4096,
- .nr_pages = 128,
- },
- {
- .id0 = 0x45,
- .id1 = 0x01,
- .name = "AT26DF081A", /* Not tested ! */
- .pagesize = 4096,
- .nr_pages = 256,
- },
-};
-
-static int __init at91_dataflash26_detect(int channel)
-{
- unsigned char status, cmd[5];
- int i;
-
- spi_access_bus(channel);
- status = at91_dataflash26_status();
-
- if (status == 0 || status == 0xff) {
- printk(KERN_ERR "at91_dataflash26_detect: status error %d\n",
- status);
- spi_release_bus(channel);
- return -ENODEV;
- }
-
- cmd[0] = AT26_OP_READ_DEV_ID;
- do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0);
- spi_release_bus(channel);
-
- if (cmd[1] != MANUFACTURER_ID_ATMEL)
- return -ENODEV;
-
- for (i = 0; i < ARRAY_SIZE(df26_types); i++) {
- if ( cmd[2] == df26_types[i].id0
- && cmd[3] == df26_types[i].id1)
- return add_dataflash(channel,
- df26_types[i].name,
- df26_types[i].nr_pages,
- df26_types[i].pagesize);
- }
-
- printk(KERN_ERR "at91_dataflash26_detect: Unsupported device "
- "(0x%02x/0x%02x)\n", cmd[2], cmd[3]);
- return -ENODEV;
-}
-
-static int __init at91_dataflash26_init(void)
-{
- spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list),
- GFP_KERNEL);
- if (!spi_transfer_desc)
- return -ENOMEM;
-
- /* DataFlash (SPI chip select 0) */
- at91_dataflash26_detect(0);
-
-#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
- /* DataFlash card (SPI chip select 3) */
- at91_dataflash26_detect(3);
-#endif
- return 0;
-}
-
-static void __exit at91_dataflash26_exit(void)
-{
- int i;
-
- for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) {
- if (mtd_devices[i]) {
- del_mtd_device(mtd_devices[i]);
- kfree(mtd_devices[i]->priv);
- kfree(mtd_devices[i]);
- }
- }
- nr_devices = 0;
- kfree(spi_transfer_desc);
-}
-
-module_init(at91_dataflash26_init);
-module_exit(at91_dataflash26_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Hans J. Koch");
-MODULE_DESCRIPTION("DataFlash AT26xxx driver for Atmel AT91RM9200");
diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c
index 54aa7590764..d8cc94ec4e5 100644
--- a/drivers/mtd/devices/docprobe.c
+++ b/drivers/mtd/devices/docprobe.c
@@ -81,9 +81,7 @@ static unsigned long __initdata doc_locations[] = {
#endif /* CONFIG_MTD_DOCPROBE_HIGH */
#elif defined(__PPC__)
0xe4000000,
-#elif defined(CONFIG_MOMENCO_OCELOT_G)
- 0xff000000,
-##else
+#else
#warning Unknown architecture for DiskOnChip. No default probe locations defined
#endif
0xffffffff };
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 78c2511ae9e..98df5bcc02f 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -1,5 +1,5 @@
/*
- * MTD SPI driver for ST M25Pxx flash chips
+ * MTD SPI driver for ST M25Pxx (and similar) serial flash chips
*
* Author: Mike Lavender, mike@steroidmicros.com
*
@@ -19,33 +19,32 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrupt.h>
-#include <linux/interrupt.h>
+#include <linux/mutex.h>
+
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
-#include <asm/semaphore.h>
-
-
-/* NOTE: AT 25F and SST 25LF series are very similar,
- * but commands for sector erase and chip id differ...
- */
#define FLASH_PAGESIZE 256
/* Flash opcodes. */
-#define OPCODE_WREN 6 /* Write enable */
-#define OPCODE_RDSR 5 /* Read status register */
-#define OPCODE_READ 3 /* Read data bytes */
-#define OPCODE_PP 2 /* Page program */
-#define OPCODE_SE 0xd8 /* Sector erase */
-#define OPCODE_RES 0xab /* Read Electronic Signature */
+#define OPCODE_WREN 0x06 /* Write enable */
+#define OPCODE_RDSR 0x05 /* Read status register */
+#define OPCODE_READ 0x03 /* Read data bytes (low frequency) */
+#define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */
+#define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */
+#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */
+#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */
+#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
#define OPCODE_RDID 0x9f /* Read JEDEC ID */
/* Status Register bits. */
#define SR_WIP 1 /* Write in progress */
#define SR_WEL 2 /* Write enable latch */
+/* meaning of other SR_* bits may differ between vendors */
#define SR_BP0 4 /* Block protect 0 */
#define SR_BP1 8 /* Block protect 1 */
#define SR_BP2 0x10 /* Block protect 2 */
@@ -65,9 +64,10 @@
struct m25p {
struct spi_device *spi;
- struct semaphore lock;
+ struct mutex lock;
struct mtd_info mtd;
- unsigned partitioned;
+ unsigned partitioned:1;
+ u8 erase_opcode;
u8 command[4];
};
@@ -150,8 +150,9 @@ static int wait_till_ready(struct m25p *flash)
*/
static int erase_sector(struct m25p *flash, u32 offset)
{
- DEBUG(MTD_DEBUG_LEVEL3, "%s: %s at 0x%08x\n", flash->spi->dev.bus_id,
- __FUNCTION__, offset);
+ DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB at 0x%08x\n",
+ flash->spi->dev.bus_id, __FUNCTION__,
+ flash->mtd.erasesize / 1024, offset);
/* Wait until finished previous write command. */
if (wait_till_ready(flash))
@@ -161,7 +162,7 @@ static int erase_sector(struct m25p *flash, u32 offset)
write_enable(flash);
/* Set up command buffer. */
- flash->command[0] = OPCODE_SE;
+ flash->command[0] = flash->erase_opcode;
flash->command[1] = offset >> 16;
flash->command[2] = offset >> 8;
flash->command[3] = offset;
@@ -201,13 +202,17 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
addr = instr->addr;
len = instr->len;
- down(&flash->lock);
+ mutex_lock(&flash->lock);
+
+ /* REVISIT in some cases we could speed up erasing large regions
+ * by using OPCODE_SE instead of OPCODE_BE_4K
+ */
/* now erase those sectors */
while (len) {
if (erase_sector(flash, addr)) {
instr->state = MTD_ERASE_FAILED;
- up(&flash->lock);
+ mutex_unlock(&flash->lock);
return -EIO;
}
@@ -215,7 +220,7 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
len -= mtd->erasesize;
}
- up(&flash->lock);
+ mutex_unlock(&flash->lock);
instr->state = MTD_ERASE_DONE;
mtd_erase_callback(instr);
@@ -260,16 +265,19 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
if (retlen)
*retlen = 0;
- down(&flash->lock);
+ mutex_lock(&flash->lock);
/* Wait till previous write/erase is done. */
if (wait_till_ready(flash)) {
/* REVISIT status return?? */
- up(&flash->lock);
+ mutex_unlock(&flash->lock);
return 1;
}
- /* NOTE: OPCODE_FAST_READ (if available) is faster... */
+ /* FIXME switch to OPCODE_FAST_READ. It's required for higher
+ * clocks; and at this writing, every chip this driver handles
+ * supports that opcode.
+ */
/* Set up the write data buffer. */
flash->command[0] = OPCODE_READ;
@@ -281,7 +289,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
*retlen = m.actual_length - sizeof(flash->command);
- up(&flash->lock);
+ mutex_unlock(&flash->lock);
return 0;
}
@@ -323,7 +331,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
t[1].tx_buf = buf;
spi_message_add_tail(&t[1], &m);
- down(&flash->lock);
+ mutex_lock(&flash->lock);
/* Wait until finished previous write command. */
if (wait_till_ready(flash))
@@ -381,10 +389,10 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
if (retlen)
*retlen += m.actual_length
- sizeof(flash->command);
- }
- }
+ }
+ }
- up(&flash->lock);
+ mutex_unlock(&flash->lock);
return 0;
}
@@ -398,24 +406,118 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
struct flash_info {
char *name;
- u8 id;
- u16 jedec_id;
+
+ /* JEDEC id zero means "no ID" (most older chips); otherwise it has
+ * a high byte of zero plus three data bytes: the manufacturer id,
+ * then a two byte device id.
+ */
+ u32 jedec_id;
+
+ /* The size listed here is what works with OPCODE_SE, which isn't
+ * necessarily called a "sector" by the vendor.
+ */
unsigned sector_size;
- unsigned n_sectors;
+ u16 n_sectors;
+
+ u16 flags;
+#define SECT_4K 0x01 /* OPCODE_BE_4K works uniformly */
};
+
+/* NOTE: double check command sets and memory organization when you add
+ * more flash chips. This current list focusses on newer chips, which
+ * have been converging on command sets which including JEDEC ID.
+ */
static struct flash_info __devinitdata m25p_data [] = {
- /* REVISIT: fill in JEDEC ids, for parts that have them */
- { "m25p05", 0x05, 0x2010, 32 * 1024, 2 },
- { "m25p10", 0x10, 0x2011, 32 * 1024, 4 },
- { "m25p20", 0x11, 0x2012, 64 * 1024, 4 },
- { "m25p40", 0x12, 0x2013, 64 * 1024, 8 },
- { "m25p80", 0x13, 0x0000, 64 * 1024, 16 },
- { "m25p16", 0x14, 0x2015, 64 * 1024, 32 },
- { "m25p32", 0x15, 0x2016, 64 * 1024, 64 },
- { "m25p64", 0x16, 0x2017, 64 * 1024, 128 },
+
+ /* Atmel -- some are (confusingly) marketed as "DataFlash" */
+ { "at25fs010", 0x1f6601, 32 * 1024, 4, SECT_4K, },
+ { "at25fs040", 0x1f6604, 64 * 1024, 8, SECT_4K, },
+
+ { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, },
+
+ { "at26f004", 0x1f0400, 64 * 1024, 8, SECT_4K, },
+ { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, },
+ { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, },
+ { "at26df321", 0x1f4701, 64 * 1024, 64, SECT_4K, },
+
+ /* Spansion -- single (large) sector size only, at least
+ * for the chips listed here (without boot sectors).
+ */
+ { "s25sl004a", 0x010212, 64 * 1024, 8, },
+ { "s25sl008a", 0x010213, 64 * 1024, 16, },
+ { "s25sl016a", 0x010214, 64 * 1024, 32, },
+ { "s25sl032a", 0x010215, 64 * 1024, 64, },
+ { "s25sl064a", 0x010216, 64 * 1024, 128, },
+
+ /* SST -- large erase sizes are "overlays", "sectors" are 4K */
+ { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, },
+ { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, },
+ { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, },
+ { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, },
+
+ /* ST Microelectronics -- newer production may have feature updates */
+ { "m25p05", 0x202010, 32 * 1024, 2, },
+ { "m25p10", 0x202011, 32 * 1024, 4, },
+ { "m25p20", 0x202012, 64 * 1024, 4, },
+ { "m25p40", 0x202013, 64 * 1024, 8, },
+ { "m25p80", 0, 64 * 1024, 16, },
+ { "m25p16", 0x202015, 64 * 1024, 32, },
+ { "m25p32", 0x202016, 64 * 1024, 64, },
+ { "m25p64", 0x202017, 64 * 1024, 128, },
+ { "m25p128", 0x202018, 256 * 1024, 64, },
+
+ { "m45pe80", 0x204014, 64 * 1024, 16, },
+ { "m45pe16", 0x204015, 64 * 1024, 32, },
+
+ { "m25pe80", 0x208014, 64 * 1024, 16, },
+ { "m25pe16", 0x208015, 64 * 1024, 32, SECT_4K, },
+
+ /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
+ { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, },
+ { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, },
+ { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, },
+ { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, },
+ { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, },
+ { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, },
+ { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, },
};
+static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
+{
+ int tmp;
+ u8 code = OPCODE_RDID;
+ u8 id[3];
+ u32 jedec;
+ struct flash_info *info;
+
+ /* JEDEC also defines an optional "extended device information"
+ * string for after vendor-specific data, after the three bytes
+ * we use here. Supporting some chips might require using it.
+ */
+ tmp = spi_write_then_read(spi, &code, 1, id, 3);
+ if (tmp < 0) {
+ DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n",
+ spi->dev.bus_id, tmp);
+ return NULL;
+ }
+ jedec = id[0];
+ jedec = jedec << 8;
+ jedec |= id[1];
+ jedec = jedec << 8;
+ jedec |= id[2];
+
+ for (tmp = 0, info = m25p_data;
+ tmp < ARRAY_SIZE(m25p_data);
+ tmp++, info++) {
+ if (info->jedec_id == jedec)
+ return info;
+ }
+ dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
+ return NULL;
+}
+
+
/*
* board specific setup should have ensured the SPI clock used here
* matches what the READ command supports, at least until this driver
@@ -429,37 +531,51 @@ static int __devinit m25p_probe(struct spi_device *spi)
unsigned i;
/* Platform data helps sort out which chip type we have, as
- * well as how this board partitions it.
+ * well as how this board partitions it. If we don't have
+ * a chip ID, try the JEDEC id commands; they'll work for most
+ * newer chips, even if we don't recognize the particular chip.
*/
data = spi->dev.platform_data;
- if (!data || !data->type) {
- /* FIXME some chips can identify themselves with RES
- * or JEDEC get-id commands. Try them ...
- */
- DEBUG(MTD_DEBUG_LEVEL1, "%s: no chip id\n",
- spi->dev.bus_id);
- return -ENODEV;
- }
+ if (data && data->type) {
+ for (i = 0, info = m25p_data;
+ i < ARRAY_SIZE(m25p_data);
+ i++, info++) {
+ if (strcmp(data->type, info->name) == 0)
+ break;
+ }
- for (i = 0, info = m25p_data; i < ARRAY_SIZE(m25p_data); i++, info++) {
- if (strcmp(data->type, info->name) == 0)
- break;
- }
- if (i == ARRAY_SIZE(m25p_data)) {
- DEBUG(MTD_DEBUG_LEVEL1, "%s: unrecognized id %s\n",
- spi->dev.bus_id, data->type);
+ /* unrecognized chip? */
+ if (i == ARRAY_SIZE(m25p_data)) {
+ DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n",
+ spi->dev.bus_id, data->type);
+ info = NULL;
+
+ /* recognized; is that chip really what's there? */
+ } else if (info->jedec_id) {
+ struct flash_info *chip = jedec_probe(spi);
+
+ if (!chip || chip != info) {
+ dev_warn(&spi->dev, "found %s, expected %s\n",
+ chip ? chip->name : "UNKNOWN",
+ info->name);
+ info = NULL;
+ }
+ }
+ } else
+ info = jedec_probe(spi);
+
+ if (!info)
return -ENODEV;
- }
flash = kzalloc(sizeof *flash, GFP_KERNEL);
if (!flash)
return -ENOMEM;
flash->spi = spi;
- init_MUTEX(&flash->lock);
+ mutex_init(&flash->lock);
dev_set_drvdata(&spi->dev, flash);
- if (data->name)
+ if (data && data->name)
flash->mtd.name = data->name;
else
flash->mtd.name = spi->dev.bus_id;
@@ -468,17 +584,25 @@ static int __devinit m25p_probe(struct spi_device *spi)
flash->mtd.writesize = 1;
flash->mtd.flags = MTD_CAP_NORFLASH;
flash->mtd.size = info->sector_size * info->n_sectors;
- flash->mtd.erasesize = info->sector_size;
flash->mtd.erase = m25p80_erase;
flash->mtd.read = m25p80_read;
flash->mtd.write = m25p80_write;
+ /* prefer "small sector" erase if possible */
+ if (info->flags & SECT_4K) {
+ flash->erase_opcode = OPCODE_BE_4K;
+ flash->mtd.erasesize = 4096;
+ } else {
+ flash->erase_opcode = OPCODE_SE;
+ flash->mtd.erasesize = info->sector_size;
+ }
+
dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name,
flash->mtd.size / 1024);
DEBUG(MTD_DEBUG_LEVEL2,
- "mtd .name = %s, .size = 0x%.8x (%uM) "
- ".erasesize = 0x%.8x (%uK) .numeraseregions = %d\n",
+ "mtd .name = %s, .size = 0x%.8x (%uMiB) "
+ ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
flash->mtd.name,
flash->mtd.size, flash->mtd.size / (1024*1024),
flash->mtd.erasesize, flash->mtd.erasesize / 1024,
@@ -488,7 +612,7 @@ static int __devinit m25p_probe(struct spi_device *spi)
for (i = 0; i < flash->mtd.numeraseregions; i++)
DEBUG(MTD_DEBUG_LEVEL2,
"mtd.eraseregions[%d] = { .offset = 0x%.8x, "
- ".erasesize = 0x%.8x (%uK), "
+ ".erasesize = 0x%.8x (%uKiB), "
".numblocks = %d }\n",
i, flash->mtd.eraseregions[i].offset,
flash->mtd.eraseregions[i].erasesize,
@@ -516,14 +640,14 @@ static int __devinit m25p_probe(struct spi_device *spi)
}
if (nr_parts > 0) {
- for (i = 0; i < data->nr_parts; i++) {
+ for (i = 0; i < nr_parts; i++) {
DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
"{.name = %s, .offset = 0x%.8x, "
- ".size = 0x%.8x (%uK) }\n",
- i, data->parts[i].name,
- data->parts[i].offset,
- data->parts[i].size,
- data->parts[i].size / 1024);
+ ".size = 0x%.8x (%uKiB) }\n",
+ i, parts[i].name,
+ parts[i].offset,
+ parts[i].size,
+ parts[i].size / 1024);
}
flash->partitioned = 1;
return add_mtd_partitions(&flash->mtd, parts, nr_parts);
@@ -560,6 +684,11 @@ static struct spi_driver m25p80_driver = {
},
.probe = m25p_probe,
.remove = __devexit_p(m25p_remove),
+
+ /* REVISIT: many of these chips have deep power-down modes, which
+ * should clearly be entered on suspend() to minimize power use.
+ * And also when they're otherwise idle...
+ */
};
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index a987e917f4e..a5ed6d232c3 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/mutex.h>
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
@@ -89,7 +90,7 @@ struct dataflash {
unsigned short page_offset; /* offset in flash address */
unsigned int page_size; /* of bytes per page */
- struct semaphore lock;
+ struct mutex lock;
struct spi_device *spi;
struct mtd_info mtd;
@@ -167,7 +168,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
x.len = 4;
spi_message_add_tail(&x, &msg);
- down(&priv->lock);
+ mutex_lock(&priv->lock);
while (instr->len > 0) {
unsigned int pageaddr;
int status;
@@ -210,7 +211,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
instr->len -= priv->page_size;
}
}
- up(&priv->lock);
+ mutex_unlock(&priv->lock);
/* Inform MTD subsystem that erase is complete */
instr->state = MTD_ERASE_DONE;
@@ -266,7 +267,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
x[1].len = len;
spi_message_add_tail(&x[1], &msg);
- down(&priv->lock);
+ mutex_lock(&priv->lock);
/* Continuous read, max clock = f(car) which may be less than
* the peak rate available. Some chips support commands with
@@ -279,7 +280,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
/* plus 4 "don't care" bytes */
status = spi_sync(priv->spi, &msg);
- up(&priv->lock);
+ mutex_unlock(&priv->lock);
if (status >= 0) {
*retlen = msg.actual_length - 8;
@@ -336,7 +337,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
else
writelen = len;
- down(&priv->lock);
+ mutex_lock(&priv->lock);
while (remaining > 0) {
DEBUG(MTD_DEBUG_LEVEL3, "write @ %i:%i len=%i\n",
pageaddr, offset, writelen);
@@ -441,7 +442,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
else
writelen = remaining;
}
- up(&priv->lock);
+ mutex_unlock(&priv->lock);
return status;
}
@@ -463,7 +464,7 @@ add_dataflash(struct spi_device *spi, char *name,
if (!priv)
return -ENOMEM;
- init_MUTEX(&priv->lock);
+ mutex_init(&priv->lock);
priv->spi = spi;
priv->page_size = pagesize;
priv->page_offset = pageoffset;
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index e8f686f7a35..7060a0895ce 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -30,8 +30,8 @@
*
* Notes:
* Due to what I assume is more buggy SROM, the 64M PMC551 I
- * have available claims that all 4 of it's DRAM banks have 64M
- * of ram configured (making a grand total of 256M onboard).
+ * have available claims that all 4 of its DRAM banks have 64MiB
+ * of ram configured (making a grand total of 256MiB onboard).
* This is slightly annoying since the BAR0 size reflects the
* aperture size, not the dram size, and the V370PDC supplies no
* other method for memory size discovery. This problem is
@@ -70,7 +70,7 @@
* made the memory unusable, added a fix to code to touch up
* the DRAM some.
*
- * Bugs/FIXME's:
+ * Bugs/FIXMEs:
* * MUST fix the init function to not spin on a register
* waiting for it to set .. this does not safely handle busted
* devices that never reset the register correctly which will
@@ -562,10 +562,10 @@ static u32 fixup_pmc551(struct pci_dev *dev)
/*
* Some screen fun
*/
- printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at "
+ printk(KERN_DEBUG "pmc551: %d%sB (0x%x) of %sprefetchable memory at "
"0x%llx\n", (size < 1024) ? size : (size < 1048576) ?
size >> 10 : size >> 20,
- (size < 1024) ? 'B' : (size < 1048576) ? 'K' : 'M', size,
+ (size < 1024) ? "" : (size < 1048576) ? "Ki" : "Mi", size,
((dcmd & (0x1 << 3)) == 0) ? "non-" : "",
(unsigned long long)pci_resource_start(dev, 0));
@@ -649,14 +649,10 @@ MODULE_DESCRIPTION(PMC551_VERSION);
* Stuff these outside the ifdef so as to not bust compiled in driver support
*/
static int msize = 0;
-#if defined(CONFIG_MTD_PMC551_APERTURE_SIZE)
-static int asize = CONFIG_MTD_PMC551_APERTURE_SIZE;
-#else
static int asize = 0;
-#endif
module_param(msize, int, 0);
-MODULE_PARM_DESC(msize, "memory size in Megabytes [1 - 1024]");
+MODULE_PARM_DESC(msize, "memory size in MiB [1 - 1024]");
module_param(asize, int, 0);
MODULE_PARM_DESC(asize, "aperture size, must be <= memsize [1-1024]");
@@ -799,8 +795,7 @@ static int __init init_pmc551(void)
mtd->owner = THIS_MODULE;
if (add_mtd_device(mtd)) {
- printk(KERN_NOTICE "pmc551: Failed to register new "
- "device\n");
+ printk(KERN_NOTICE "pmc551: Failed to register new device\n");
pci_iounmap(PCI_Device, priv->start);
kfree(mtd->priv);
kfree(mtd);
@@ -811,13 +806,13 @@ static int __init init_pmc551(void)
pci_dev_get(PCI_Device);
printk(KERN_NOTICE "Registered pmc551 memory device.\n");
- printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n",
+ printk(KERN_NOTICE "Mapped %dMiB of memory from 0x%p to 0x%p\n",
priv->asize >> 20,
priv->start, priv->start + priv->asize);
- printk(KERN_NOTICE "Total memory is %d%c\n",
+ printk(KERN_NOTICE "Total memory is %d%sB\n",
(length < 1024) ? length :
(length < 1048576) ? length >> 10 : length >> 20,
- (length < 1024) ? 'B' : (length < 1048576) ? 'K' : 'M');
+ (length < 1024) ? "" : (length < 1048576) ? "Ki" : "Mi");
priv->nextpmc551 = pmc551list;
pmc551list = mtd;
found++;
@@ -850,7 +845,7 @@ static void __exit cleanup_pmc551(void)
pmc551list = priv->nextpmc551;
if (priv->start) {
- printk(KERN_DEBUG "pmc551: unmapping %dM starting at "
+ printk(KERN_DEBUG "pmc551: unmapping %dMiB starting at "
"0x%p\n", priv->asize >> 20, priv->start);
pci_iounmap(priv->dev, priv->start);
}
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
index ecac0e438f4..b8917beeb65 100644
--- a/drivers/mtd/inftlmount.c
+++ b/drivers/mtd/inftlmount.c
@@ -580,14 +580,13 @@ int INFTL_mount(struct INFTLrecord *s)
logical_block = block = BLOCK_NIL;
/* Temporary buffer to store ANAC numbers. */
- ANACtable = kmalloc(s->nb_blocks * sizeof(u8), GFP_KERNEL);
+ ANACtable = kcalloc(s->nb_blocks, sizeof(u8), GFP_KERNEL);
if (!ANACtable) {
printk(KERN_WARNING "INFTL: allocation of ANACtable "
"failed (%zd bytes)\n",
s->nb_blocks * sizeof(u8));
return -ENOMEM;
}
- memset(ANACtable, 0, s->nb_blocks);
/*
* First pass is to explore each physical unit, and construct the
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index cc6c7344243..a592fc04cf7 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -54,7 +54,7 @@ config MTD_PHYSMAP_BANKWIDTH
help
This is the total width of the data bus of the flash devices
in octets. For example, if you have a data bus width of 32
- bits, you would set the bus width octect value to 4. This is
+ bits, you would set the bus width octet value to 4. This is
used internally by the CFI drivers.
Ignore this option if you use run-time physmap configuration
(i.e., run-time calling physmap_configure()).
@@ -73,12 +73,12 @@ config MTD_PMC_MSP_EVM
depends on PMC_MSP && MTD_CFI
select MTD_PARTITIONS
help
- This provides a 'mapping' driver which support the way
- in which user-programmable flash chips are connected on the
- PMC-Sierra MSP eval/demo boards
+ This provides a 'mapping' driver which supports the way
+ in which user-programmable flash chips are connected on the
+ PMC-Sierra MSP eval/demo boards.
choice
- prompt "Maximum mappable memory avialable for flash IO"
+ prompt "Maximum mappable memory available for flash IO"
depends on MTD_PMC_MSP_EVM
default MSP_FLASH_MAP_LIMIT_32M
@@ -163,20 +163,12 @@ config MTD_SBC_GXX
More info at
<http://www.arcomcontrols.com/products/icp/pc104/processors/SBC_GX1.htm>.
-config MTD_LUBBOCK
- tristate "CFI Flash device mapped on Intel Lubbock XScale eval board"
- depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS
- help
- This provides a driver for the on-board flash of the Intel
- 'Lubbock' XScale evaluation board.
-
-config MTD_MAINSTONE
- tristate "CFI Flash device mapped on Intel Mainstone XScale eval board"
- depends on MACH_MAINSTONE && MTD_CFI_INTELEXT
+config MTD_PXA2XX
+ tristate "CFI Flash device mapped on Intel XScale PXA2xx based boards"
+ depends on (PXA25x || PXA27x) && MTD_CFI_INTELEXT
select MTD_PARTITIONS
help
- This provides a driver for the on-board flash of the Intel
- 'Mainstone PXA27x evaluation board.
+ This provides a driver for the NOR flash attached to a PXA2xx chip.
config MTD_OCTAGON
tristate "JEDEC Flash device mapped on Octagon 5066 SBC"
@@ -354,7 +346,7 @@ config MTD_CFI_FLAGADM
config MTD_WALNUT
tristate "Flash device mapped on IBM 405GP Walnut"
- depends on MTD_JEDECPROBE && WALNUT
+ depends on MTD_JEDECPROBE && WALNUT && !PPC_MERGE
help
This enables access routines for the flash chips on the IBM 405GP
Walnut board. If you have one of these boards and would like to
@@ -362,7 +354,7 @@ config MTD_WALNUT
config MTD_EBONY
tristate "Flash devices mapped on IBM 440GP Ebony"
- depends on MTD_JEDECPROBE && EBONY
+ depends on MTD_JEDECPROBE && EBONY && !PPC_MERGE
help
This enables access routines for the flash chips on the IBM 440GP
Ebony board. If you have one of these boards and would like to
@@ -370,7 +362,7 @@ config MTD_EBONY
config MTD_OCOTEA
tristate "Flash devices mapped on IBM 440GX Ocotea"
- depends on MTD_CFI && OCOTEA
+ depends on MTD_CFI && OCOTEA && !PPC_MERGE
help
This enables access routines for the flash chips on the IBM 440GX
Ocotea board. If you have one of these boards and would like to
@@ -384,22 +376,6 @@ config MTD_REDWOOD
Redwood board. If you have one of these boards and would like to
use the flash chips on it, say 'Y'.
-config MTD_TQM834x
- tristate "Flash device mapped on TQ Components TQM834x Boards"
- depends on MTD_CFI && TQM834x
- help
- This enables access routines for the flash chips on the
- TQ Components TQM834x boards. If you have one of these boards
- and would like to use the flash chips on it, say 'Y'.
-
-config MTD_OCELOT
- tristate "Momenco Ocelot boot flash device"
- depends on MOMENCO_OCELOT
- help
- This enables access routines for the boot flash device and for the
- NVRAM on the Momenco Ocelot board. If you have one of these boards
- and would like access to either of these, say 'Y'.
-
config MTD_SOLUTIONENGINE
tristate "CFI Flash device mapped on Hitachi SolutionEngine"
depends on SUPERH && MTD_CFI && MTD_REDBOOT_PARTS
@@ -605,6 +581,13 @@ config MTD_SHARP_SL
help
This enables access to the flash chip on the Sharp SL Series of PDAs.
+config MTD_INTEL_VR_NOR
+ tristate "NOR flash on Intel Vermilion Range Expansion Bus CS0"
+ depends on PCI
+ help
+ Map driver for a NOR flash bank located on the Expansion Bus of the
+ Intel Vermilion Range chipset.
+
config MTD_PLATRAM
tristate "Map driver for platform device RAM (mtd-ram)"
select MTD_RAM
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 970b189271a..316382a1401 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -20,8 +20,7 @@ obj-$(CONFIG_MTD_ESB2ROM) += esb2rom.o
obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o
obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
-obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o
-obj-$(CONFIG_MTD_MAINSTONE) += mainstone-flash.o
+obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o
obj-$(CONFIG_MTD_MBX860) += mbx860.o
obj-$(CONFIG_MTD_CEIVA) += ceiva.o
obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
@@ -43,7 +42,6 @@ obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o
obj-$(CONFIG_MTD_VMAX) += vmax301.o
obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o
-obj-$(CONFIG_MTD_OCELOT) += ocelot.o
obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
obj-$(CONFIG_MTD_PCI) += pci.o
obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o
@@ -70,4 +68,4 @@ obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o
obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o
obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o
obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o
-obj-$(CONFIG_MTD_TQM834x) += tqm834x.o
+obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c
index 84fbe0e8c47..82811bcb043 100644
--- a/drivers/mtd/maps/alchemy-flash.c
+++ b/drivers/mtd/maps/alchemy-flash.c
@@ -75,13 +75,6 @@
#define BOARD_FLASH_WIDTH 2 /* 16-bits */
#endif
-#ifdef CONFIG_MIPS_HYDROGEN3
-#define BOARD_MAP_NAME "Hydrogen3 Flash"
-#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
-#define BOARD_FLASH_WIDTH 4 /* 32-bits */
-#define USE_LOCAL_ACCESSORS /* why? */
-#endif
-
#ifdef CONFIG_MIPS_BOSPORUS
#define BOARD_MAP_NAME "Bosporus Flash"
#define BOARD_FLASH_SIZE 0x01000000 /* 16MB */
@@ -130,13 +123,6 @@ int __init alchemy_mtd_init(void)
window_addr = 0x20000000 - BOARD_FLASH_SIZE;
window_size = BOARD_FLASH_SIZE;
-#ifdef CONFIG_MIPS_MIRAGE_WHY
- /* Boot ROM flash bank only; no user bank */
- window_addr = 0x1C000000;
- window_size = 0x04000000;
- /* USERFS from 0x1C00 0000 to 0x1FC00000 */
- alchemy_partitions[0].size = 0x03C00000;
-#endif
/*
* Static partition definition selection
diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c
new file mode 100644
index 00000000000..1e7814ae212
--- /dev/null
+++ b/drivers/mtd/maps/intel_vr_nor.c
@@ -0,0 +1,298 @@
+/*
+ * drivers/mtd/maps/intel_vr_nor.c
+ *
+ * An MTD map driver for a NOR flash bank on the Expansion Bus of the Intel
+ * Vermilion Range chipset.
+ *
+ * The Vermilion Range Expansion Bus supports four chip selects, each of which
+ * has 64MiB of address space. The 2nd BAR of the Expansion Bus PCI Device
+ * is a 256MiB memory region containing the address spaces for all four of the
+ * chip selects, with start addresses hardcoded on 64MiB boundaries.
+ *
+ * This map driver only supports NOR flash on chip select 0. The buswidth
+ * (either 8 bits or 16 bits) is determined by reading the Expansion Bus Timing
+ * and Control Register for Chip Select 0 (EXP_TIMING_CS0). This driver does
+ * not modify the value in the EXP_TIMING_CS0 register except to enable writing
+ * and disable boot acceleration. The timing parameters in the register are
+ * assumed to have been properly initialized by the BIOS. The reset default
+ * timing parameters are maximally conservative (slow), so access to the flash
+ * will be slower than it should be if the BIOS has not initialized the timing
+ * parameters.
+ *
+ * Author: Andy Lowe <alowe@mvista.com>
+ *
+ * 2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/flashchip.h>
+
+#define DRV_NAME "vr_nor"
+
+struct vr_nor_mtd {
+ void __iomem *csr_base;
+ struct map_info map;
+ struct mtd_info *info;
+ int nr_parts;
+ struct pci_dev *dev;
+};
+
+/* Expansion Bus Configuration and Status Registers are in BAR 0 */
+#define EXP_CSR_MBAR 0
+/* Expansion Bus Memory Window is BAR 1 */
+#define EXP_WIN_MBAR 1
+/* Maximum address space for Chip Select 0 is 64MiB */
+#define CS0_SIZE 0x04000000
+/* Chip Select 0 is at offset 0 in the Memory Window */
+#define CS0_START 0x0
+/* Chip Select 0 Timing Register is at offset 0 in CSR */
+#define EXP_TIMING_CS0 0x00
+#define TIMING_CS_EN (1 << 31) /* Chip Select Enable */
+#define TIMING_BOOT_ACCEL_DIS (1 << 8) /* Boot Acceleration Disable */
+#define TIMING_WR_EN (1 << 1) /* Write Enable */
+#define TIMING_BYTE_EN (1 << 0) /* 8-bit vs 16-bit bus */
+#define TIMING_MASK 0x3FFF0000
+
+static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p)
+{
+ if (p->nr_parts > 0) {
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+ del_mtd_partitions(p->info);
+#endif
+ } else
+ del_mtd_device(p->info);
+}
+
+static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p)
+{
+ int err = 0;
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+ struct mtd_partition *parts;
+ static const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+ /* register the flash bank */
+#if defined(CONFIG_MTD_PARTITIONS) || defined(CONFIG_MTD_PARTITIONS_MODULE)
+ /* partition the flash bank */
+ p->nr_parts = parse_mtd_partitions(p->info, part_probes, &parts, 0);
+ if (p->nr_parts > 0)
+ err = add_mtd_partitions(p->info, parts, p->nr_parts);
+#endif
+ if (p->nr_parts <= 0)
+ err = add_mtd_device(p->info);
+
+ return err;
+}
+
+static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p)
+{
+ map_destroy(p->info);
+}
+
+static int __devinit vr_nor_mtd_setup(struct vr_nor_mtd *p)
+{
+ static const char *probe_types[] =
+ { "cfi_probe", "jedec_probe", NULL };
+ const char **type;
+
+ for (type = probe_types; !p->info && *type; type++)
+ p->info = do_map_probe(*type, &p->map);
+ if (!p->info)
+ return -ENODEV;
+
+ p->info->owner = THIS_MODULE;
+
+ return 0;
+}
+
+static void __devexit vr_nor_destroy_maps(struct vr_nor_mtd *p)
+{
+ unsigned int exp_timing_cs0;
+
+ /* write-protect the flash bank */
+ exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
+ exp_timing_cs0 &= ~TIMING_WR_EN;
+ writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
+
+ /* unmap the flash window */
+ iounmap(p->map.virt);
+
+ /* unmap the csr window */
+ iounmap(p->csr_base);
+}
+
+/*
+ * Initialize the map_info structure and map the flash.
+ * Returns 0 on success, nonzero otherwise.
+ */
+static int __devinit vr_nor_init_maps(struct vr_nor_mtd *p)
+{
+ unsigned long csr_phys, csr_len;
+ unsigned long win_phys, win_len;
+ unsigned int exp_timing_cs0;
+ int err;
+
+ csr_phys = pci_resource_start(p->dev, EXP_CSR_MBAR);
+ csr_len = pci_resource_len(p->dev, EXP_CSR_MBAR);
+ win_phys = pci_resource_start(p->dev, EXP_WIN_MBAR);
+ win_len = pci_resource_len(p->dev, EXP_WIN_MBAR);
+
+ if (!csr_phys || !csr_len || !win_phys || !win_len)
+ return -ENODEV;
+
+ if (win_len < (CS0_START + CS0_SIZE))
+ return -ENXIO;
+
+ p->csr_base = ioremap_nocache(csr_phys, csr_len);
+ if (!p->csr_base)
+ return -ENOMEM;
+
+ exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
+ if (!(exp_timing_cs0 & TIMING_CS_EN)) {
+ dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 "
+ "is disabled.\n");
+ err = -ENODEV;
+ goto release;
+ }
+ if ((exp_timing_cs0 & TIMING_MASK) == TIMING_MASK) {
+ dev_warn(&p->dev->dev, "Expansion Bus Chip Select 0 "
+ "is configured for maximally slow access times.\n");
+ }
+ p->map.name = DRV_NAME;
+ p->map.bankwidth = (exp_timing_cs0 & TIMING_BYTE_EN) ? 1 : 2;
+ p->map.phys = win_phys + CS0_START;
+ p->map.size = CS0_SIZE;
+ p->map.virt = ioremap_nocache(p->map.phys, p->map.size);
+ if (!p->map.virt) {
+ err = -ENOMEM;
+ goto release;
+ }
+ simple_map_init(&p->map);
+
+ /* Enable writes to flash bank */
+ exp_timing_cs0 |= TIMING_BOOT_ACCEL_DIS | TIMING_WR_EN;
+ writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
+
+ return 0;
+
+ release:
+ iounmap(p->csr_base);
+ return err;
+}
+
+static struct pci_device_id vr_nor_pci_ids[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x500D)},
+ {0,}
+};
+
+static void __devexit vr_nor_pci_remove(struct pci_dev *dev)
+{
+ struct vr_nor_mtd *p = pci_get_drvdata(dev);
+
+ pci_set_drvdata(dev, NULL);
+ vr_nor_destroy_partitions(p);
+ vr_nor_destroy_mtd_setup(p);
+ vr_nor_destroy_maps(p);
+ kfree(p);
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+}
+
+static int __devinit
+vr_nor_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct vr_nor_mtd *p = NULL;
+ unsigned int exp_timing_cs0;
+ int err;
+
+ err = pci_enable_device(dev);
+ if (err)
+ goto out;
+
+ err = pci_request_regions(dev, DRV_NAME);
+ if (err)
+ goto disable_dev;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ err = -ENOMEM;
+ if (!p)
+ goto release;
+
+ p->dev = dev;
+
+ err = vr_nor_init_maps(p);
+ if (err)
+ goto release;
+
+ err = vr_nor_mtd_setup(p);
+ if (err)
+ goto destroy_maps;
+
+ err = vr_nor_init_partitions(p);
+ if (err)
+ goto destroy_mtd_setup;
+
+ pci_set_drvdata(dev, p);
+
+ return 0;
+
+ destroy_mtd_setup:
+ map_destroy(p->info);
+
+ destroy_maps:
+ /* write-protect the flash bank */
+ exp_timing_cs0 = readl(p->csr_base + EXP_TIMING_CS0);
+ exp_timing_cs0 &= ~TIMING_WR_EN;
+ writel(exp_timing_cs0, p->csr_base + EXP_TIMING_CS0);
+
+ /* unmap the flash window */
+ iounmap(p->map.virt);
+
+ /* unmap the csr window */
+ iounmap(p->csr_base);
+
+ release:
+ kfree(p);
+ pci_release_regions(dev);
+
+ disable_dev:
+ pci_disable_device(dev);
+
+ out:
+ return err;
+}
+
+static struct pci_driver vr_nor_pci_driver = {
+ .name = DRV_NAME,
+ .probe = vr_nor_pci_probe,
+ .remove = __devexit_p(vr_nor_pci_remove),
+ .id_table = vr_nor_pci_ids,
+};
+
+static int __init vr_nor_mtd_init(void)
+{
+ return pci_register_driver(&vr_nor_pci_driver);
+}
+
+static void __exit vr_nor_mtd_exit(void)
+{
+ pci_unregister_driver(&vr_nor_pci_driver);
+}
+
+module_init(vr_nor_mtd_init);
+module_exit(vr_nor_mtd_exit);
+
+MODULE_AUTHOR("Andy Lowe");
+MODULE_DESCRIPTION("MTD map driver for NOR flash on Intel Vermilion Range");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, vr_nor_pci_ids);
diff --git a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c
deleted file mode 100644
index e8560683b97..00000000000
--- a/drivers/mtd/maps/lubbock-flash.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * $Id: lubbock-flash.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $
- *
- * Map driver for the Lubbock developer platform.
- *
- * Author: Nicolas Pitre
- * Copyright: (C) 2001 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/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/hardware.h>
-#include <asm/arch/pxa-regs.h>
-#include <asm/arch/lubbock.h>
-#include <asm/cacheflush.h>
-
-#define ROM_ADDR 0x00000000
-#define FLASH_ADDR 0x04000000
-
-#define WINDOW_SIZE 64*1024*1024
-
-static void lubbock_map_inval_cache(struct map_info *map, unsigned long from, ssize_t len)
-{
- flush_ioremap_region(map->phys, map->cached, from, len);
-}
-
-static struct map_info lubbock_maps[2] = { {
- .size = WINDOW_SIZE,
- .phys = 0x00000000,
- .inval_cache = lubbock_map_inval_cache,
-}, {
- .size = WINDOW_SIZE,
- .phys = 0x04000000,
- .inval_cache = lubbock_map_inval_cache,
-} };
-
-static struct mtd_partition lubbock_partitions[] = {
- {
- .name = "Bootloader",
- .size = 0x00040000,
- .offset = 0,
- .mask_flags = MTD_WRITEABLE /* force read-only */
- },{
- .name = "Kernel",
- .size = 0x00100000,
- .offset = 0x00040000,
- },{
- .name = "Filesystem",
- .size = MTDPART_SIZ_FULL,
- .offset = 0x00140000
- }
-};
-
-static struct mtd_info *mymtds[2];
-static struct mtd_partition *parsed_parts[2];
-static int nr_parsed_parts[2];
-
-static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-
-static int __init init_lubbock(void)
-{
- int flashboot = (LUB_CONF_SWITCHES & 1);
- int ret = 0, i;
-
- lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth =
- (BOOT_DEF & 1) ? 2 : 4;
-
- /* Compensate for the nROMBT switch which swaps the flash banks */
- printk(KERN_NOTICE "Lubbock configured to boot from %s (bank %d)\n",
- flashboot?"Flash":"ROM", flashboot);
-
- lubbock_maps[flashboot^1].name = "Lubbock Application Flash";
- lubbock_maps[flashboot].name = "Lubbock Boot ROM";
-
- for (i = 0; i < 2; i++) {
- lubbock_maps[i].virt = ioremap(lubbock_maps[i].phys, WINDOW_SIZE);
- if (!lubbock_maps[i].virt) {
- printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name);
- if (!ret)
- ret = -ENOMEM;
- continue;
- }
- lubbock_maps[i].cached = ioremap_cached(lubbock_maps[i].phys, WINDOW_SIZE);
- if (!lubbock_maps[i].cached)
- printk(KERN_WARNING "Failed to ioremap cached %s\n", lubbock_maps[i].name);
- simple_map_init(&lubbock_maps[i]);
-
- printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n",
- lubbock_maps[i].name, lubbock_maps[i].phys,
- lubbock_maps[i].bankwidth * 8);
-
- mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]);
-
- if (!mymtds[i]) {
- iounmap((void *)lubbock_maps[i].virt);
- if (lubbock_maps[i].cached)
- iounmap(lubbock_maps[i].cached);
- if (!ret)
- ret = -EIO;
- continue;
- }
- mymtds[i]->owner = THIS_MODULE;
-
- ret = parse_mtd_partitions(mymtds[i], probes,
- &parsed_parts[i], 0);
-
- if (ret > 0)
- nr_parsed_parts[i] = ret;
- }
-
- if (!mymtds[0] && !mymtds[1])
- return ret;
-
- for (i = 0; i < 2; i++) {
- if (!mymtds[i]) {
- printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name);
- } else if (nr_parsed_parts[i]) {
- add_mtd_partitions(mymtds[i], parsed_parts[i], nr_parsed_parts[i]);
- } else if (!i) {
- printk("Using static partitions on %s\n", lubbock_maps[i].name);
- add_mtd_partitions(mymtds[i], lubbock_partitions, ARRAY_SIZE(lubbock_partitions));
- } else {
- printk("Registering %s as whole device\n", lubbock_maps[i].name);
- add_mtd_device(mymtds[i]);
- }
- }
- return 0;
-}
-
-static void __exit cleanup_lubbock(void)
-{
- int i;
- for (i = 0; i < 2; i++) {
- if (!mymtds[i])
- continue;
-
- if (nr_parsed_parts[i] || !i)
- del_mtd_partitions(mymtds[i]);
- else
- del_mtd_device(mymtds[i]);
-
- map_destroy(mymtds[i]);
- iounmap((void *)lubbock_maps[i].virt);
- if (lubbock_maps[i].cached)
- iounmap(lubbock_maps[i].cached);
-
- kfree(parsed_parts[i]);
- }
-}
-
-module_init(init_lubbock);
-module_exit(cleanup_lubbock);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
-MODULE_DESCRIPTION("MTD map driver for Intel Lubbock");
diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c
deleted file mode 100644
index d76487d82dc..00000000000
--- a/drivers/mtd/maps/mainstone-flash.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * $Id: $
- *
- * Map driver for the Mainstone developer platform.
- *
- * Author: Nicolas Pitre
- * Copyright: (C) 2001 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/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/hardware.h>
-#include <asm/arch/pxa-regs.h>
-#include <asm/arch/mainstone.h>
-#include <asm/cacheflush.h>
-
-
-#define ROM_ADDR 0x00000000
-#define FLASH_ADDR 0x04000000
-
-#define WINDOW_SIZE 0x04000000
-
-static void mainstone_map_inval_cache(struct map_info *map, unsigned long from,
- ssize_t len)
-{
- flush_ioremap_region(map->phys, map->cached, from, len);
-}
-
-static struct map_info mainstone_maps[2] = { {
- .size = WINDOW_SIZE,
- .phys = PXA_CS0_PHYS,
- .inval_cache = mainstone_map_inval_cache,
-}, {
- .size = WINDOW_SIZE,
- .phys = PXA_CS1_PHYS,
- .inval_cache = mainstone_map_inval_cache,
-} };
-
-static struct mtd_partition mainstone_partitions[] = {
- {
- .name = "Bootloader",
- .size = 0x00040000,
- .offset = 0,
- .mask_flags = MTD_WRITEABLE /* force read-only */
- },{
- .name = "Kernel",
- .size = 0x00400000,
- .offset = 0x00040000,
- },{
- .name = "Filesystem",
- .size = MTDPART_SIZ_FULL,
- .offset = 0x00440000
- }
-};
-
-static struct mtd_info *mymtds[2];
-static struct mtd_partition *parsed_parts[2];
-static int nr_parsed_parts[2];
-
-static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-
-static int __init init_mainstone(void)
-{
- int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */
- int ret = 0, i;
-
- mainstone_maps[0].bankwidth = (BOOT_DEF & 1) ? 2 : 4;
- mainstone_maps[1].bankwidth = 4;
-
- /* Compensate for SW7 which swaps the flash banks */
- mainstone_maps[SW7].name = "processor flash";
- mainstone_maps[SW7 ^ 1].name = "main board flash";
-
- printk(KERN_NOTICE "Mainstone configured to boot from %s\n",
- mainstone_maps[0].name);
-
- for (i = 0; i < 2; i++) {
- mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys,
- WINDOW_SIZE);
- if (!mainstone_maps[i].virt) {
- printk(KERN_WARNING "Failed to ioremap %s\n",
- mainstone_maps[i].name);
- if (!ret)
- ret = -ENOMEM;
- continue;
- }
- mainstone_maps[i].cached =
- ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE);
- if (!mainstone_maps[i].cached)
- printk(KERN_WARNING "Failed to ioremap cached %s\n",
- mainstone_maps[i].name);
- simple_map_init(&mainstone_maps[i]);
-
- printk(KERN_NOTICE
- "Probing %s at physical address 0x%08lx"
- " (%d-bit bankwidth)\n",
- mainstone_maps[i].name, mainstone_maps[i].phys,
- mainstone_maps[i].bankwidth * 8);
-
- mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]);
-
- if (!mymtds[i]) {
- iounmap((void *)mainstone_maps[i].virt);
- if (mainstone_maps[i].cached)
- iounmap(mainstone_maps[i].cached);
- if (!ret)
- ret = -EIO;
- continue;
- }
- mymtds[i]->owner = THIS_MODULE;
-
- ret = parse_mtd_partitions(mymtds[i], probes,
- &parsed_parts[i], 0);
-
- if (ret > 0)
- nr_parsed_parts[i] = ret;
- }
-
- if (!mymtds[0] && !mymtds[1])
- return ret;
-
- for (i = 0; i < 2; i++) {
- if (!mymtds[i]) {
- printk(KERN_WARNING "%s is absent. Skipping\n",
- mainstone_maps[i].name);
- } else if (nr_parsed_parts[i]) {
- add_mtd_partitions(mymtds[i], parsed_parts[i],
- nr_parsed_parts[i]);
- } else if (!i) {
- printk("Using static partitions on %s\n",
- mainstone_maps[i].name);
- add_mtd_partitions(mymtds[i], mainstone_partitions,
- ARRAY_SIZE(mainstone_partitions));
- } else {
- printk("Registering %s as whole device\n",
- mainstone_maps[i].name);
- add_mtd_device(mymtds[i]);
- }
- }
- return 0;
-}
-
-static void __exit cleanup_mainstone(void)
-{
- int i;
- for (i = 0; i < 2; i++) {
- if (!mymtds[i])
- continue;
-
- if (nr_parsed_parts[i] || !i)
- del_mtd_partitions(mymtds[i]);
- else
- del_mtd_device(mymtds[i]);
-
- map_destroy(mymtds[i]);
- iounmap((void *)mainstone_maps[i].virt);
- if (mainstone_maps[i].cached)
- iounmap(mainstone_maps[i].cached);
- kfree(parsed_parts[i]);
- }
-}
-
-module_init(init_mainstone);
-module_exit(cleanup_mainstone);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
-MODULE_DESCRIPTION("MTD map driver for Intel Mainstone");
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
index 7b96cd02f82..0c9b305a72e 100644
--- a/drivers/mtd/maps/nettel.c
+++ b/drivers/mtd/maps/nettel.c
@@ -158,68 +158,11 @@ static struct notifier_block nettel_notifier_block = {
nettel_reboot_notifier, NULL, 0
};
-/*
- * Erase the configuration file system.
- * Used to support the software reset button.
- */
-static void nettel_erasecallback(struct erase_info *done)
-{
- wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
- wake_up(wait_q);
-}
-
-static struct erase_info nettel_erase;
-
-int nettel_eraseconfig(void)
-{
- struct mtd_info *mtd;
- DECLARE_WAITQUEUE(wait, current);
- wait_queue_head_t wait_q;
- int ret;
-
- init_waitqueue_head(&wait_q);
- mtd = get_mtd_device(NULL, 2);
- if (!IS_ERR(mtd)) {
- nettel_erase.mtd = mtd;
- nettel_erase.callback = nettel_erasecallback;
- nettel_erase.callback = NULL;
- nettel_erase.addr = 0;
- nettel_erase.len = mtd->size;
- nettel_erase.priv = (u_long) &wait_q;
- nettel_erase.priv = 0;
-
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&wait_q, &wait);
-
- ret = mtd->erase(mtd, &nettel_erase);
- if (ret) {
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&wait_q, &wait);
- put_mtd_device(mtd);
- return(ret);
- }
-
- schedule(); /* Wait for erase to finish. */
- remove_wait_queue(&wait_q, &wait);
-
- put_mtd_device(mtd);
- }
-
- return(0);
-}
-
-#else
-
-int nettel_eraseconfig(void)
-{
- return(0);
-}
-
#endif
/****************************************************************************/
-int __init nettel_init(void)
+static int __init nettel_init(void)
{
volatile unsigned long *amdpar;
unsigned long amdaddr, maxsize;
@@ -421,10 +364,6 @@ int __init nettel_init(void)
intel_mtd->owner = THIS_MODULE;
-#ifndef CONFIG_BLK_DEV_INITRD
- ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1);
-#endif
-
num_intel_partitions = sizeof(nettel_intel_partitions) /
sizeof(nettel_intel_partitions[0]);
@@ -477,7 +416,7 @@ out_unmap2:
/****************************************************************************/
-void __exit nettel_cleanup(void)
+static void __exit nettel_cleanup(void)
{
#ifdef CONFIG_MTD_CFI_INTELEXT
unregister_reboot_notifier(&nettel_notifier_block);
diff --git a/drivers/mtd/maps/ocelot.c b/drivers/mtd/maps/ocelot.c
deleted file mode 100644
index 6977963d789..00000000000
--- a/drivers/mtd/maps/ocelot.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * $Id: ocelot.c,v 1.17 2005/11/07 11:14:27 gleixner Exp $
- *
- * Flash on Momenco Ocelot
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#define OCELOT_PLD 0x2c000000
-#define FLASH_WINDOW_ADDR 0x2fc00000
-#define FLASH_WINDOW_SIZE 0x00080000
-#define FLASH_BUSWIDTH 1
-#define NVRAM_WINDOW_ADDR 0x2c800000
-#define NVRAM_WINDOW_SIZE 0x00007FF0
-#define NVRAM_BUSWIDTH 1
-
-static unsigned int cacheflush = 0;
-
-static struct mtd_info *flash_mtd;
-static struct mtd_info *nvram_mtd;
-
-static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
-{
- struct map_info *map = mtd->priv;
- size_t done = 0;
-
- /* If we use memcpy, it does word-wide writes. Even though we told the
- GT64120A that it's an 8-bit wide region, word-wide writes don't work.
- We end up just writing the first byte of the four to all four bytes.
- So we have this loop instead */
- *retlen = len;
- while(len) {
- __raw_writeb(*(unsigned char *) from, map->virt + to);
- from++;
- to++;
- len--;
- }
-}
-
-static struct mtd_partition *parsed_parts;
-
-struct map_info ocelot_flash_map = {
- .name = "Ocelot boot flash",
- .size = FLASH_WINDOW_SIZE,
- .bankwidth = FLASH_BUSWIDTH,
- .phys = FLASH_WINDOW_ADDR,
-};
-
-struct map_info ocelot_nvram_map = {
- .name = "Ocelot NVRAM",
- .size = NVRAM_WINDOW_SIZE,
- .bankwidth = NVRAM_BUSWIDTH,
- .phys = NVRAM_WINDOW_ADDR,
-};
-
-static const char *probes[] = { "RedBoot", NULL };
-
-static int __init init_ocelot_maps(void)
-{
- void *pld;
- int nr_parts;
- unsigned char brd_status;
-
- printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n",
- FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR);
-
- /* First check whether the flash jumper is present */
- pld = ioremap(OCELOT_PLD, 0x10);
- if (!pld) {
- printk(KERN_NOTICE "Failed to ioremap Ocelot PLD\n");
- return -EIO;
- }
- brd_status = readb(pld+4);
- iounmap(pld);
-
- /* Now ioremap the NVRAM space */
- ocelot_nvram_map.virt = ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
- if (!ocelot_nvram_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n");
- return -EIO;
- }
-
- simple_map_init(&ocelot_nvram_map);
-
- /* And do the RAM probe on it to get an MTD device */
- nvram_mtd = do_map_probe("map_ram", &ocelot_nvram_map);
- if (!nvram_mtd) {
- printk("NVRAM probe failed\n");
- goto fail_1;
- }
- nvram_mtd->owner = THIS_MODULE;
- nvram_mtd->erasesize = 16;
- /* Override the write() method */
- nvram_mtd->write = ocelot_ram_write;
-
- /* Now map the flash space */
- ocelot_flash_map.virt = ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
- if (!ocelot_flash_map.virt) {
- printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n");
- goto fail_2;
- }
- /* Now the cached version */
- ocelot_flash_map.cached = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0);
-
- simple_map_init(&ocelot_flash_map);
-
- /* Only probe for flash if the write jumper is present */
- if (brd_status & 0x40) {
- flash_mtd = do_map_probe("jedec", &ocelot_flash_map);
- } else {
- printk(KERN_NOTICE "Ocelot flash write jumper not present. Treating as ROM\n");
- }
- /* If that failed or the jumper's absent, pretend it's ROM */
- if (!flash_mtd) {
- flash_mtd = do_map_probe("map_rom", &ocelot_flash_map);
- /* If we're treating it as ROM, set the erase size */
- if (flash_mtd)
- flash_mtd->erasesize = 0x10000;
- }
- if (!flash_mtd)
- goto fail3;
-
- add_mtd_device(nvram_mtd);
-
- flash_mtd->owner = THIS_MODULE;
- nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0);
-
- if (nr_parts > 0)
- add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
- else
- add_mtd_device(flash_mtd);
-
- return 0;
-
- fail3:
- iounmap((void *)ocelot_flash_map.virt);
- if (ocelot_flash_map.cached)
- iounmap((void *)ocelot_flash_map.cached);
- fail_2:
- map_destroy(nvram_mtd);
- fail_1:
- iounmap((void *)ocelot_nvram_map.virt);
-
- return -ENXIO;
-}
-
-static void __exit cleanup_ocelot_maps(void)
-{
- del_mtd_device(nvram_mtd);
- map_destroy(nvram_mtd);
- iounmap((void *)ocelot_nvram_map.virt);
-
- if (parsed_parts)
- del_mtd_partitions(flash_mtd);
- else
- del_mtd_device(flash_mtd);
- map_destroy(flash_mtd);
- iounmap((void *)ocelot_flash_map.virt);
- if (ocelot_flash_map.cached)
- iounmap((void *)ocelot_flash_map.cached);
-}
-
-module_init(init_ocelot_maps);
-module_exit(cleanup_ocelot_maps);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>");
-MODULE_DESCRIPTION("MTD map driver for Momenco Ocelot board");
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index bbb42c35b69..aeed9ea7971 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -1,9 +1,12 @@
/*
- * Normal mappings of chips in physical memory for OF devices
+ * Flash mappings described by the OF (or flattened) device tree
*
* Copyright (C) 2006 MontaVista Software Inc.
* Author: Vitaly Wool <vwool@ru.mvista.com>
*
+ * Revised to handle newer style flash binding by:
+ * Copyright (C) 2007 David Gibson, IBM Corporation.
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
@@ -12,102 +15,157 @@
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/slab.h>
#include <linux/device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
-#include <asm/of_platform.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
-struct physmap_flash_info {
+struct of_flash {
struct mtd_info *mtd;
struct map_info map;
struct resource *res;
#ifdef CONFIG_MTD_PARTITIONS
- int nr_parts;
struct mtd_partition *parts;
#endif
};
-static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
#ifdef CONFIG_MTD_PARTITIONS
-static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
-#endif
+#define OF_FLASH_PARTS(info) ((info)->parts)
-#ifdef CONFIG_MTD_PARTITIONS
-static int parse_flash_partitions(struct device_node *node,
- struct mtd_partition **parts)
+static int parse_obsolete_partitions(struct of_device *dev,
+ struct of_flash *info,
+ struct device_node *dp)
{
- int i, plen, retval = -ENOMEM;
- const u32 *part;
- const char *name;
-
- part = of_get_property(node, "partitions", &plen);
- if (part == NULL)
- goto err;
-
- retval = plen / (2 * sizeof(u32));
- *parts = kzalloc(retval * sizeof(struct mtd_partition), GFP_KERNEL);
- if (*parts == NULL) {
- printk(KERN_ERR "Can't allocate the flash partition data!\n");
- goto err;
- }
+ int i, plen, nr_parts;
+ const struct {
+ u32 offset, len;
+ } *part;
+ const char *names;
+
+ part = of_get_property(dp, "partitions", &plen);
+ if (!part)
+ return 0; /* No partitions found */
+
+ dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n");
+
+ nr_parts = plen / sizeof(part[0]);
+
+ info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL);
+ if (!info->parts)
+ return -ENOMEM;
- name = of_get_property(node, "partition-names", &plen);
+ names = of_get_property(dp, "partition-names", &plen);
- for (i = 0; i < retval; i++) {
- (*parts)[i].offset = *part++;
- (*parts)[i].size = *part & ~1;
- if (*part++ & 1) /* bit 0 set signifies read only partition */
- (*parts)[i].mask_flags = MTD_WRITEABLE;
+ for (i = 0; i < nr_parts; i++) {
+ info->parts[i].offset = part->offset;
+ info->parts[i].size = part->len & ~1;
+ if (part->len & 1) /* bit 0 set signifies read only partition */
+ info->parts[i].mask_flags = MTD_WRITEABLE;
- if (name != NULL && plen > 0) {
- int len = strlen(name) + 1;
+ if (names && (plen > 0)) {
+ int len = strlen(names) + 1;
- (*parts)[i].name = (char *)name;
+ info->parts[i].name = (char *)names;
plen -= len;
- name += len;
- } else
- (*parts)[i].name = "unnamed";
+ names += len;
+ } else {
+ info->parts[i].name = "unnamed";
+ }
+
+ part++;
}
-err:
- return retval;
+
+ return nr_parts;
}
-#endif
-static int of_physmap_remove(struct of_device *dev)
+static int __devinit parse_partitions(struct of_flash *info,
+ struct of_device *dev)
+{
+ const char *partname;
+ static const char *part_probe_types[]
+ = { "cmdlinepart", "RedBoot", NULL };
+ struct device_node *dp = dev->node, *pp;
+ int nr_parts, i;
+
+ /* First look for RedBoot table or partitions on the command
+ * line, these take precedence over device tree information */
+ nr_parts = parse_mtd_partitions(info->mtd, part_probe_types,
+ &info->parts, 0);
+ if (nr_parts > 0) {
+ add_mtd_partitions(info->mtd, info->parts, nr_parts);
+ return 0;
+ }
+
+ /* First count the subnodes */
+ nr_parts = 0;
+ for (pp = dp->child; pp; pp = pp->sibling)
+ nr_parts++;
+
+ if (nr_parts == 0)
+ return parse_obsolete_partitions(dev, info, dp);
+
+ info->parts = kzalloc(nr_parts * sizeof(*info->parts),
+ GFP_KERNEL);
+ if (!info->parts)
+ return -ENOMEM;
+
+ for (pp = dp->child, i = 0; pp; pp = pp->sibling, i++) {
+ const u32 *reg;
+ int len;
+
+ reg = of_get_property(pp, "reg", &len);
+ if (!reg || (len != 2*sizeof(u32))) {
+ dev_err(&dev->dev, "Invalid 'reg' on %s\n",
+ dp->full_name);
+ kfree(info->parts);
+ info->parts = NULL;
+ return -EINVAL;
+ }
+ info->parts[i].offset = reg[0];
+ info->parts[i].size = reg[1];
+
+ partname = of_get_property(pp, "label", &len);
+ if (!partname)
+ partname = of_get_property(pp, "name", &len);
+ info->parts[i].name = (char *)partname;
+
+ if (of_get_property(pp, "read-only", &len))
+ info->parts[i].mask_flags = MTD_WRITEABLE;
+ }
+
+ return nr_parts;
+}
+#else /* MTD_PARTITIONS */
+#define OF_FLASH_PARTS(info) (0)
+#define parse_partitions(info, dev) (0)
+#endif /* MTD_PARTITIONS */
+
+static int of_flash_remove(struct of_device *dev)
{
- struct physmap_flash_info *info;
+ struct of_flash *info;
info = dev_get_drvdata(&dev->dev);
- if (info == NULL)
+ if (!info)
return 0;
dev_set_drvdata(&dev->dev, NULL);
- if (info->mtd != NULL) {
-#ifdef CONFIG_MTD_PARTITIONS
- if (info->nr_parts) {
+ if (info->mtd) {
+ if (OF_FLASH_PARTS(info)) {
del_mtd_partitions(info->mtd);
- kfree(info->parts);
+ kfree(OF_FLASH_PARTS(info));
} else {
del_mtd_device(info->mtd);
}
-#else
- del_mtd_device(info->mtd);
-#endif
map_destroy(info->mtd);
}
- if (info->map.virt != NULL)
+ if (info->map.virt)
iounmap(info->map.virt);
- if (info->res != NULL) {
+ if (info->res) {
release_resource(info->res);
kfree(info->res);
}
@@ -115,48 +173,78 @@ static int of_physmap_remove(struct of_device *dev)
return 0;
}
-static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match)
+/* Helper function to handle probing of the obsolete "direct-mapped"
+ * compatible binding, which has an extra "probe-type" property
+ * describing the type of flash probe necessary. */
+static struct mtd_info * __devinit obsolete_probe(struct of_device *dev,
+ struct map_info *map)
{
struct device_node *dp = dev->node;
- struct resource res;
- struct physmap_flash_info *info;
- const char **probe_type;
const char *of_probe;
+ struct mtd_info *mtd;
+ static const char *rom_probe_types[]
+ = { "cfi_probe", "jedec_probe", "map_rom"};
+ int i;
+
+ dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
+ "flash binding\n");
+
+ of_probe = of_get_property(dp, "probe-type", NULL);
+ if (!of_probe) {
+ for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
+ mtd = do_map_probe(rom_probe_types[i], map);
+ if (mtd)
+ return mtd;
+ }
+ return NULL;
+ } else if (strcmp(of_probe, "CFI") == 0) {
+ return do_map_probe("cfi_probe", map);
+ } else if (strcmp(of_probe, "JEDEC") == 0) {
+ return do_map_probe("jedec_probe", map);
+ } else {
+ if (strcmp(of_probe, "ROM") != 0)
+ dev_warn(&dev->dev, "obsolete_probe: don't know probe "
+ "type '%s', mapping as rom\n", of_probe);
+ return do_map_probe("mtd_rom", map);
+ }
+}
+
+static int __devinit of_flash_probe(struct of_device *dev,
+ const struct of_device_id *match)
+{
+ struct device_node *dp = dev->node;
+ struct resource res;
+ struct of_flash *info;
+ const char *probe_type = match->data;
const u32 *width;
int err;
-
+ err = -ENXIO;
if (of_address_to_resource(dp, 0, &res)) {
- dev_err(&dev->dev, "Can't get the flash mapping!\n");
- err = -EINVAL;
+ dev_err(&dev->dev, "Can't get IO address from device tree\n");
goto err_out;
}
- dev_dbg(&dev->dev, "physmap flash device: %.8llx at %.8llx\n",
- (unsigned long long)res.end - res.start + 1,
- (unsigned long long)res.start);
+ dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
+ (unsigned long long)res.start, (unsigned long long)res.end);
- info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
- if (info == NULL) {
- err = -ENOMEM;
+ err = -ENOMEM;
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
goto err_out;
- }
- memset(info, 0, sizeof(*info));
dev_set_drvdata(&dev->dev, info);
+ err = -EBUSY;
info->res = request_mem_region(res.start, res.end - res.start + 1,
- dev->dev.bus_id);
- if (info->res == NULL) {
- dev_err(&dev->dev, "Could not reserve memory region\n");
- err = -ENOMEM;
+ dev->dev.bus_id);
+ if (!info->res)
goto err_out;
- }
+ err = -ENXIO;
width = of_get_property(dp, "bank-width", NULL);
- if (width == NULL) {
- dev_err(&dev->dev, "Can't get the flash bank width!\n");
- err = -EINVAL;
+ if (!width) {
+ dev_err(&dev->dev, "Can't get bank width from device tree\n");
goto err_out;
}
@@ -165,91 +253,87 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev
info->map.size = res.end - res.start + 1;
info->map.bankwidth = *width;
+ err = -ENOMEM;
info->map.virt = ioremap(info->map.phys, info->map.size);
- if (info->map.virt == NULL) {
- dev_err(&dev->dev, "Failed to ioremap flash region\n");
- err = EIO;
+ if (!info->map.virt) {
+ dev_err(&dev->dev, "Failed to ioremap() flash region\n");
goto err_out;
}
simple_map_init(&info->map);
- of_probe = of_get_property(dp, "probe-type", NULL);
- if (of_probe == NULL) {
- probe_type = rom_probe_types;
- for (; info->mtd == NULL && *probe_type != NULL; probe_type++)
- info->mtd = do_map_probe(*probe_type, &info->map);
- } else if (!strcmp(of_probe, "CFI"))
- info->mtd = do_map_probe("cfi_probe", &info->map);
- else if (!strcmp(of_probe, "JEDEC"))
- info->mtd = do_map_probe("jedec_probe", &info->map);
- else {
- if (strcmp(of_probe, "ROM"))
- dev_dbg(&dev->dev, "map_probe: don't know probe type "
- "'%s', mapping as rom\n", of_probe);
- info->mtd = do_map_probe("mtd_rom", &info->map);
- }
- if (info->mtd == NULL) {
- dev_err(&dev->dev, "map_probe failed\n");
- err = -ENXIO;
+ if (probe_type)
+ info->mtd = do_map_probe(probe_type, &info->map);
+ else
+ info->mtd = obsolete_probe(dev, &info->map);
+
+ err = -ENXIO;
+ if (!info->mtd) {
+ dev_err(&dev->dev, "do_map_probe() failed\n");
goto err_out;
}
info->mtd->owner = THIS_MODULE;
-#ifdef CONFIG_MTD_PARTITIONS
- err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0);
- if (err > 0) {
- add_mtd_partitions(info->mtd, info->parts, err);
- } else if ((err = parse_flash_partitions(dp, &info->parts)) > 0) {
- dev_info(&dev->dev, "Using OF partition information\n");
- add_mtd_partitions(info->mtd, info->parts, err);
- info->nr_parts = err;
- } else
-#endif
+ err = parse_partitions(info, dev);
+ if (err < 0)
+ goto err_out;
+
+ if (err > 0)
+ add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err);
+ else
+ add_mtd_device(info->mtd);
- add_mtd_device(info->mtd);
return 0;
err_out:
- of_physmap_remove(dev);
+ of_flash_remove(dev);
return err;
-
- return 0;
-
-
}
-static struct of_device_id of_physmap_match[] = {
+static struct of_device_id of_flash_match[] = {
+ {
+ .compatible = "cfi-flash",
+ .data = (void *)"cfi_probe",
+ },
+ {
+ /* FIXME: JEDEC chips can't be safely and reliably
+ * probed, although the mtd code gets it right in
+ * practice most of the time. We should use the
+ * vendor and device ids specified by the binding to
+ * bypass the heuristic probe code, but the mtd layer
+ * provides, at present, no interface for doing so
+ * :(. */
+ .compatible = "jedec-flash",
+ .data = (void *)"jedec_probe",
+ },
{
.type = "rom",
.compatible = "direct-mapped"
},
{ },
};
+MODULE_DEVICE_TABLE(of, of_flash_match);
-MODULE_DEVICE_TABLE(of, of_physmap_match);
-
-
-static struct of_platform_driver of_physmap_flash_driver = {
- .name = "physmap-flash",
- .match_table = of_physmap_match,
- .probe = of_physmap_probe,
- .remove = of_physmap_remove,
+static struct of_platform_driver of_flash_driver = {
+ .name = "of-flash",
+ .match_table = of_flash_match,
+ .probe = of_flash_probe,
+ .remove = of_flash_remove,
};
-static int __init of_physmap_init(void)
+static int __init of_flash_init(void)
{
- return of_register_platform_driver(&of_physmap_flash_driver);
+ return of_register_platform_driver(&of_flash_driver);
}
-static void __exit of_physmap_exit(void)
+static void __exit of_flash_exit(void)
{
- of_unregister_platform_driver(&of_physmap_flash_driver);
+ of_unregister_platform_driver(&of_flash_driver);
}
-module_init(of_physmap_init);
-module_exit(of_physmap_exit);
+module_init(of_flash_init);
+module_exit(of_flash_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
-MODULE_DESCRIPTION("Configurable MTD map driver for OF");
+MODULE_DESCRIPTION("Device tree based MTD map driver");
diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c
index 7e0377ec1c4..02bde8c982e 100644
--- a/drivers/mtd/maps/pmcmsp-flash.c
+++ b/drivers/mtd/maps/pmcmsp-flash.c
@@ -73,13 +73,16 @@ int __init init_msp_flash(void)
return -ENXIO;
printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt);
- msp_flash = (struct mtd_info **)kmalloc(
- fcnt * sizeof(struct map_info *), GFP_KERNEL);
- msp_parts = (struct mtd_partition **)kmalloc(
- fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
- msp_maps = (struct map_info *)kmalloc(
- fcnt * sizeof(struct mtd_info), GFP_KERNEL);
- memset(msp_maps, 0, fcnt * sizeof(struct mtd_info));
+
+ msp_flash = kmalloc(fcnt * sizeof(struct map_info *), GFP_KERNEL);
+ msp_parts = kmalloc(fcnt * sizeof(struct mtd_partition *), GFP_KERNEL);
+ msp_maps = kcalloc(fcnt, sizeof(struct mtd_info), GFP_KERNEL);
+ if (!msp_flash || !msp_parts || !msp_maps) {
+ kfree(msp_maps);
+ kfree(msp_parts);
+ kfree(msp_flash);
+ return -ENOMEM;
+ }
/* loop over the flash devices, initializing each */
for (i = 0; i < fcnt; i++) {
@@ -95,9 +98,8 @@ int __init init_msp_flash(void)
continue;
}
- msp_parts[i] = (struct mtd_partition *)kmalloc(
- pcnt * sizeof(struct mtd_partition), GFP_KERNEL);
- memset(msp_parts[i], 0, pcnt * sizeof(struct mtd_partition));
+ msp_parts[i] = kcalloc(pcnt, sizeof(struct mtd_partition),
+ GFP_KERNEL);
/* now initialize the devices proper */
flash_name[5] = '0' + i;
diff --git a/drivers/mtd/maps/pmcmsp-ramroot.c b/drivers/mtd/maps/pmcmsp-ramroot.c
index 18049bceba8..30de5c0c09a 100644
--- a/drivers/mtd/maps/pmcmsp-ramroot.c
+++ b/drivers/mtd/maps/pmcmsp-ramroot.c
@@ -79,7 +79,6 @@ static int __init init_rrmap(void)
rr_mtd->owner = THIS_MODULE;
add_mtd_device(rr_mtd);
- ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, rr_mtd->index);
return 0;
}
diff --git a/drivers/mtd/maps/pq2fads.c b/drivers/mtd/maps/pq2fads.c
deleted file mode 100644
index fb78d87cc13..00000000000
--- a/drivers/mtd/maps/pq2fads.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * drivers/mtd/maps/pq2fads.c
- *
- * Mapping for the flash SIMM on 8272ADS and PQ2FADS board
- *
- * Author: Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/ppcboot.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-
-/*
- NOTE: bank width and interleave relative to the installed flash
- should have been chosen within MTD_CFI_GEOMETRY options.
- */
-#define PQ2FADS_BANK_WIDTH 4
-
-static struct mtd_partition pq2fads_partitions[] = {
- {
-#ifdef CONFIG_ADS8272
- .name = "HRCW",
- .size = 0x40000,
- .offset = 0,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
- .name = "User FS",
- .size = 0x5c0000,
- .offset = 0x40000,
-#else
- .name = "User FS",
- .size = 0x600000,
- .offset = 0,
-#endif
- }, {
- .name = "uImage",
- .size = 0x100000,
- .offset = 0x600000,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
- .name = "bootloader",
- .size = 0x40000,
- .offset = 0x700000,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- }, {
- .name = "bootloader env",
- .size = 0x40000,
- .offset = 0x740000,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- }
-};
-
-
-/* pointer to MPC885ADS board info data */
-extern unsigned char __res[];
-
-static int __init init_pq2fads_mtd(void)
-{
- bd_t *bd = (bd_t *)__res;
- physmap_configure(bd->bi_flashstart, bd->bi_flashsize, PQ2FADS_BANK_WIDTH, NULL);
-
- physmap_set_partitions(pq2fads_partitions,
- sizeof (pq2fads_partitions) /
- sizeof (pq2fads_partitions[0]));
- return 0;
-}
-
-static void __exit cleanup_pq2fads_mtd(void)
-{
-}
-
-module_init(init_pq2fads_mtd);
-module_exit(cleanup_pq2fads_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("MTD map and partitions for MPC8272ADS boards");
diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c
new file mode 100644
index 00000000000..82113295c26
--- /dev/null
+++ b/drivers/mtd/maps/pxa2xx-flash.c
@@ -0,0 +1,200 @@
+/*
+ * Map driver for Intel XScale PXA2xx platforms.
+ *
+ * Author: Nicolas Pitre
+ * Copyright: (C) 2001 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/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/cacheflush.h>
+
+#include <asm/mach/flash.h>
+
+static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from,
+ ssize_t len)
+{
+ flush_ioremap_region(map->phys, map->cached, from, len);
+}
+
+struct pxa2xx_flash_info {
+ struct mtd_partition *parts;
+ int nr_parts;
+ struct mtd_info *mtd;
+ struct map_info map;
+};
+
+
+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
+
+
+static int __init pxa2xx_flash_probe(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct flash_platform_data *flash = pdev->dev.platform_data;
+ struct pxa2xx_flash_info *info;
+ struct mtd_partition *parts;
+ struct resource *res;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ info = kmalloc(sizeof(struct pxa2xx_flash_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ memset(info, 0, sizeof(struct pxa2xx_flash_info));
+ info->map.name = (char *) flash->name;
+ info->map.bankwidth = flash->width;
+ info->map.phys = res->start;
+ info->map.size = res->end - res->start + 1;
+ info->parts = flash->parts;
+ info->nr_parts = flash->nr_parts;
+
+ info->map.virt = ioremap(info->map.phys, info->map.size);
+ if (!info->map.virt) {
+ printk(KERN_WARNING "Failed to ioremap %s\n",
+ info->map.name);
+ return -ENOMEM;
+ }
+ info->map.cached =
+ ioremap_cached(info->map.phys, info->map.size);
+ if (!info->map.cached)
+ printk(KERN_WARNING "Failed to ioremap cached %s\n",
+ info->map.name);
+ info->map.inval_cache = pxa2xx_map_inval_cache;
+ simple_map_init(&info->map);
+
+ printk(KERN_NOTICE
+ "Probing %s at physical address 0x%08lx"
+ " (%d-bit bankwidth)\n",
+ info->map.name, (unsigned long)info->map.phys,
+ info->map.bankwidth * 8);
+
+ info->mtd = do_map_probe(flash->map_name, &info->map);
+
+ if (!info->mtd) {
+ iounmap((void *)info->map.virt);
+ if (info->map.cached)
+ iounmap(info->map.cached);
+ return -EIO;
+ }
+ info->mtd->owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+ ret = parse_mtd_partitions(info->mtd, probes, &parts, 0);
+
+ if (ret > 0) {
+ info->nr_parts = ret;
+ info->parts = parts;
+ }
+#endif
+
+ if (info->nr_parts) {
+ add_mtd_partitions(info->mtd, info->parts,
+ info->nr_parts);
+ } else {
+ printk("Registering %s as whole device\n",
+ info->map.name);
+ add_mtd_device(info->mtd);
+ }
+
+ dev_set_drvdata(dev, info);
+ return 0;
+}
+
+static int __exit pxa2xx_flash_remove(struct device *dev)
+{
+ struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+
+ dev_set_drvdata(dev, NULL);
+
+#ifdef CONFIG_MTD_PARTITIONS
+ if (info->nr_parts)
+ del_mtd_partitions(info->mtd);
+ else
+#endif
+ del_mtd_device(info->mtd);
+
+ map_destroy(info->mtd);
+ iounmap(info->map.virt);
+ if (info->map.cached)
+ iounmap(info->map.cached);
+ kfree(info->parts);
+ kfree(info);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int pxa2xx_flash_suspend(struct device *dev, pm_message_t state)
+{
+ struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (info->mtd && info->mtd->suspend)
+ ret = info->mtd->suspend(info->mtd);
+ return ret;
+}
+
+static int pxa2xx_flash_resume(struct device *dev)
+{
+ struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+
+ if (info->mtd && info->mtd->resume)
+ info->mtd->resume(info->mtd);
+ return 0;
+}
+static void pxa2xx_flash_shutdown(struct device *dev)
+{
+ struct pxa2xx_flash_info *info = dev_get_drvdata(dev);
+
+ if (info && info->mtd->suspend(info->mtd) == 0)
+ info->mtd->resume(info->mtd);
+}
+#else
+#define pxa2xx_flash_suspend NULL
+#define pxa2xx_flash_resume NULL
+#define pxa2xx_flash_shutdown NULL
+#endif
+
+static struct device_driver pxa2xx_flash_driver = {
+ .name = "pxa2xx-flash",
+ .bus = &platform_bus_type,
+ .probe = pxa2xx_flash_probe,
+ .remove = __exit_p(pxa2xx_flash_remove),
+ .suspend = pxa2xx_flash_suspend,
+ .resume = pxa2xx_flash_resume,
+ .shutdown = pxa2xx_flash_shutdown,
+};
+
+static int __init init_pxa2xx_flash(void)
+{
+ return driver_register(&pxa2xx_flash_driver);
+}
+
+static void __exit cleanup_pxa2xx_flash(void)
+{
+ driver_unregister(&pxa2xx_flash_driver);
+}
+
+module_init(init_pxa2xx_flash);
+module_exit(cleanup_pxa2xx_flash);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
+MODULE_DESCRIPTION("MTD map driver for Intel XScale PXA2xx");
diff --git a/drivers/mtd/maps/tqm834x.c b/drivers/mtd/maps/tqm834x.c
deleted file mode 100644
index 9adc970e55e..00000000000
--- a/drivers/mtd/maps/tqm834x.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * drivers/mtd/maps/tqm834x.c
- *
- * MTD mapping driver for TQM834x boards
- *
- * Copyright 2005 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <asm/ppcboot.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#define FLASH_BANK_MAX 2
-
-extern unsigned char __res[];
-
-/* trivial struct to describe partition information */
-struct mtd_part_def
-{
- int nums;
- unsigned char *type;
- struct mtd_partition* mtd_part;
-};
-
-static struct mtd_info* mtd_banks[FLASH_BANK_MAX];
-static struct map_info* map_banks[FLASH_BANK_MAX];
-static struct mtd_part_def part_banks[FLASH_BANK_MAX];
-
-static unsigned long num_banks;
-static unsigned long start_scan_addr;
-
-#ifdef CONFIG_MTD_PARTITIONS
-/*
- * The following defines the partition layout of TQM834x boards.
- *
- * See include/linux/mtd/partitions.h for definition of the
- * mtd_partition structure.
- *
- * Assume minimal initial size of 4 MiB per bank, will be updated
- * later in init_tqm834x_mtd() routine.
- */
-
-/* Partition definition for the first flash bank which is always present. */
-static struct mtd_partition tqm834x_partitions_bank1[] = {
- {
- .name = "u-boot", /* u-boot firmware */
- .offset = 0x00000000,
- .size = 0x00040000, /* 256 KiB */
- /*mask_flags: MTD_WRITEABLE, * force read-only */
- },
- {
- .name = "env", /* u-boot environment */
- .offset = 0x00040000,
- .size = 0x00020000, /* 128 KiB */
- /*mask_flags: MTD_WRITEABLE, * force read-only */
- },
- {
- .name = "kernel", /* linux kernel image */
- .offset = 0x00060000,
- .size = 0x00100000, /* 1 MiB */
- /*mask_flags: MTD_WRITEABLE, * force read-only */
- },
- {
- .name = "initrd", /* ramdisk image */
- .offset = 0x00160000,
- .size = 0x00200000, /* 2 MiB */
- },
- {
- .name = "user", /* user data */
- .offset = 0x00360000,
- .size = 0x000a0000, /* remaining space */
- /* NOTE: this parttion size is re-calcated in */
- /* init_tqm834x_mtd() to cover actual remaining space. */
- },
-};
-
-/* Partition definition for the second flash bank which may be present on some
- * TQM834x boards.
- */
-static struct mtd_partition tqm834x_partitions_bank2[] = {
- {
- .name = "jffs2", /* jffs2 filesystem */
- .offset = 0x00000000,
- .size = 0x00400000, /* whole device */
- /* NOTE: this parttion size is re-calcated in */
- /* init_tqm834x_mtd() to cover actual device size. */
- },
-};
-
-#endif /* CONFIG_MTD_PARTITIONS */
-
-static int __init init_tqm834x_mtd(void)
-{
- int idx = 0, ret = 0;
- unsigned long flash_addr, flash_size, mtd_size = 0;
-
- /* pointer to TQM834x board info data */
- bd_t *bd = (bd_t *)__res;
-#ifdef CONFIG_MTD_CMDLINE_PARTS
- int n;
- char mtdid[4];
- const char *part_probes[] = { "cmdlinepart", NULL };
-#endif
-
- flash_addr = bd->bi_flashstart;
- flash_size = bd->bi_flashsize;
-
- /* request maximum flash size address space */
- start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size);
- if (!start_scan_addr) {
- printk("%s: Failed to ioremap address: 0x%lx\n",
- __FUNCTION__, flash_addr);
- return -EIO;
- }
-
- for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
- if (mtd_size >= flash_size)
- break;
-
- pr_debug("%s: chip probing count %d\n", __FUNCTION__, idx);
-
- map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL);
- if (map_banks[idx] == NULL) {
- ret = -ENOMEM;
- goto error_mem;
- }
- map_banks[idx]->name = kzalloc(16, GFP_KERNEL);
- if (map_banks[idx]->name == NULL) {
- ret = -ENOMEM;
- goto error_mem;
- }
-
- sprintf(map_banks[idx]->name, "TQM834x-%d", idx);
- map_banks[idx]->size = flash_size;
- map_banks[idx]->bankwidth = 4;
-
- simple_map_init(map_banks[idx]);
-
- map_banks[idx]->virt = (void __iomem *)
- (start_scan_addr + ((idx > 0) ?
- (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0));
- map_banks[idx]->phys =
- flash_addr + ((idx > 0) ?
- (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0);
-
- /* start to probe flash chips */
- mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]);
- if (mtd_banks[idx]) {
- mtd_banks[idx]->owner = THIS_MODULE;
- mtd_size += mtd_banks[idx]->size;
- num_banks++;
- pr_debug("%s: bank %ld, name: %s, size: %d bytes \n",
- __FUNCTION__, num_banks,
- mtd_banks[idx]->name, mtd_banks[idx]->size);
- }
- }
-
- /* no supported flash chips found */
- if (!num_banks) {
- printk("TQM834x: No supported flash chips found!\n");
- ret = -ENXIO;
- goto error_mem;
- }
-
-#ifdef CONFIG_MTD_PARTITIONS
- /*
- * Select static partition definitions
- */
- n = ARRAY_SIZE(tqm834x_partitions_bank1);
- part_banks[0].mtd_part = tqm834x_partitions_bank1;
- part_banks[0].type = "static image bank1";
- part_banks[0].nums = n;
-
- /* update last partition size to cover actual remaining space */
- tqm834x_partitions_bank1[n - 1].size =
- mtd_banks[0]->size -
- tqm834x_partitions_bank1[n - 1].offset;
-
- /* check if we have second bank? */
- if (num_banks == 2) {
- n = ARRAY_SIZE(tqm834x_partitions_bank2);
- part_banks[1].mtd_part = tqm834x_partitions_bank2;
- part_banks[1].type = "static image bank2";
- part_banks[1].nums = n;
-
- /* update last partition size to cover actual remaining space */
- tqm834x_partitions_bank2[n - 1].size =
- mtd_banks[1]->size -
- tqm834x_partitions_bank2[n - 1].offset;
- }
-
- for(idx = 0; idx < num_banks ; idx++) {
-#ifdef CONFIG_MTD_CMDLINE_PARTS
- sprintf(mtdid, "%d", idx);
- n = parse_mtd_partitions(mtd_banks[idx],
- part_probes,
- &part_banks[idx].mtd_part,
- 0);
- pr_debug("%s: %d command line partitions on bank %s\n",
- __FUNCTION__, n, mtdid);
- if (n > 0) {
- part_banks[idx].type = "command line";
- part_banks[idx].nums = n;
- }
-#endif /* CONFIG_MTD_CMDLINE_PARTS */
- if (part_banks[idx].nums == 0) {
- printk(KERN_NOTICE
- "TQM834x flash bank %d: no partition info "
- "available, registering whole device\n", idx);
- add_mtd_device(mtd_banks[idx]);
- } else {
- printk(KERN_NOTICE
- "TQM834x flash bank %d: Using %s partition "
- "definition\n", idx, part_banks[idx].type);
- add_mtd_partitions(mtd_banks[idx],
- part_banks[idx].mtd_part,
- part_banks[idx].nums);
- }
- }
-#else /* ! CONFIG_MTD_PARTITIONS */
- printk(KERN_NOTICE "TQM834x flash: registering %d flash banks "
- "at once\n", num_banks);
-
- for(idx = 0 ; idx < num_banks ; idx++)
- add_mtd_device(mtd_banks[idx]);
-
-#endif /* CONFIG_MTD_PARTITIONS */
-
- return 0;
-error_mem:
- for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
- if (map_banks[idx] != NULL) {
- if (map_banks[idx]->name != NULL) {
- kfree(map_banks[idx]->name);
- map_banks[idx]->name = NULL;
- }
- kfree(map_banks[idx]);
- map_banks[idx] = NULL;
- }
- }
-
- iounmap((void *)start_scan_addr);
-
- return ret;
-}
-
-static void __exit cleanup_tqm834x_mtd(void)
-{
- unsigned int idx = 0;
- for(idx = 0 ; idx < num_banks ; idx++) {
- /* destroy mtd_info previously allocated */
- if (mtd_banks[idx]) {
- del_mtd_partitions(mtd_banks[idx]);
- map_destroy(mtd_banks[idx]);
- }
-
- /* release map_info not used anymore */
- kfree(map_banks[idx]->name);
- kfree(map_banks[idx]);
- }
-
- if (start_scan_addr) {
- iounmap((void *)start_scan_addr);
- start_scan_addr = 0;
- }
-}
-
-module_init(init_tqm834x_mtd);
-module_exit(cleanup_tqm834x_mtd);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Wolfgang Denk <wd@denx.de>");
-MODULE_DESCRIPTION("MTD map driver for TQM834x boards");
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index ef89780eb9d..74d9d30edab 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -24,10 +24,9 @@
#include <linux/kthread.h>
#include <asm/uaccess.h>
-static LIST_HEAD(blktrans_majors);
+#include "mtdcore.h"
-extern struct mutex mtd_table_mutex;
-extern struct mtd_info *mtd_table[];
+static LIST_HEAD(blktrans_majors);
struct mtd_blkcore_priv {
struct task_struct *thread;
@@ -202,7 +201,7 @@ static int blktrans_ioctl(struct inode *inode, struct file *file,
}
}
-struct block_device_operations mtd_blktrans_ops = {
+static struct block_device_operations mtd_blktrans_ops = {
.owner = THIS_MODULE,
.open = blktrans_open,
.release = blktrans_release,
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index d091b2430b4..22ed96c4b7b 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -136,7 +136,8 @@ static int mtd_close(struct inode *inode, struct file *file)
DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
- if (mtd->sync)
+ /* Only sync if opened RW */
+ if ((file->f_mode & 2) && mtd->sync)
mtd->sync(mtd);
put_mtd_device(mtd);
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 41844ea0246..d563dcd4b26 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -178,7 +178,7 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
/* Check alignment */
if (mtd->writesize > 1) {
- loff_t __to = to;
+ uint64_t __to = to;
if (do_div(__to, mtd->writesize) || (total_len % mtd->writesize))
return -EINVAL;
}
@@ -726,6 +726,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.size = subdev[0]->size;
concat->mtd.erasesize = subdev[0]->erasesize;
concat->mtd.writesize = subdev[0]->writesize;
+ concat->mtd.subpage_sft = subdev[0]->subpage_sft;
concat->mtd.oobsize = subdev[0]->oobsize;
concat->mtd.oobavail = subdev[0]->oobavail;
if (subdev[0]->writev)
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index c153b64a830..6c2645e2837 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -22,6 +22,8 @@
#include <linux/mtd/mtd.h>
+#include "mtdcore.h"
+
/* These are exported solely for the purpose of mtd_blkdevs.c. You
should not use them for _anything_ else */
DEFINE_MUTEX(mtd_table_mutex);
diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h
new file mode 100644
index 00000000000..a33251f4b87
--- /dev/null
+++ b/drivers/mtd/mtdcore.h
@@ -0,0 +1,11 @@
+/* linux/drivers/mtd/mtdcore.h
+ *
+ * Header file for driver private mtdcore exports
+ *
+ */
+
+/* These are exported solely for the purpose of mtd_blkdevs.c. You
+ should not use them for _anything_ else */
+
+extern struct mutex mtd_table_mutex;
+extern struct mtd_info *mtd_table[MAX_MTD_DEVICES];
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
new file mode 100644
index 00000000000..f8af627f0b9
--- /dev/null
+++ b/drivers/mtd/mtdoops.c
@@ -0,0 +1,376 @@
+/*
+ * MTD Oops/Panic logger
+ *
+ * Copyright (C) 2007 Nokia Corporation. All rights reserved.
+ *
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/mtd/mtd.h>
+
+#define OOPS_PAGE_SIZE 4096
+
+static struct mtdoops_context {
+ int mtd_index;
+ struct work_struct work;
+ struct mtd_info *mtd;
+ int oops_pages;
+ int nextpage;
+ int nextcount;
+
+ void *oops_buf;
+ int ready;
+ int writecount;
+} oops_cxt;
+
+static void mtdoops_erase_callback(struct erase_info *done)
+{
+ wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
+ wake_up(wait_q);
+}
+
+static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
+{
+ struct erase_info erase;
+ DECLARE_WAITQUEUE(wait, current);
+ wait_queue_head_t wait_q;
+ int ret;
+
+ init_waitqueue_head(&wait_q);
+ erase.mtd = mtd;
+ erase.callback = mtdoops_erase_callback;
+ erase.addr = offset;
+ if (mtd->erasesize < OOPS_PAGE_SIZE)
+ erase.len = OOPS_PAGE_SIZE;
+ else
+ erase.len = mtd->erasesize;
+ erase.priv = (u_long)&wait_q;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&wait_q, &wait);
+
+ ret = mtd->erase(mtd, &erase);
+ if (ret) {
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&wait_q, &wait);
+ printk (KERN_WARNING "mtdoops: erase of region [0x%x, 0x%x] "
+ "on \"%s\" failed\n",
+ erase.addr, erase.len, mtd->name);
+ return ret;
+ }
+
+ schedule(); /* Wait for erase to finish. */
+ remove_wait_queue(&wait_q, &wait);
+
+ return 0;
+}
+
+static int mtdoops_inc_counter(struct mtdoops_context *cxt)
+{
+ struct mtd_info *mtd = cxt->mtd;
+ size_t retlen;
+ u32 count;
+ int ret;
+
+ cxt->nextpage++;
+ if (cxt->nextpage > cxt->oops_pages)
+ cxt->nextpage = 0;
+ cxt->nextcount++;
+ if (cxt->nextcount == 0xffffffff)
+ cxt->nextcount = 0;
+
+ ret = mtd->read(mtd, cxt->nextpage * OOPS_PAGE_SIZE, 4,
+ &retlen, (u_char *) &count);
+ if ((retlen != 4) || (ret < 0)) {
+ printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)"
+ ", err %d.\n", cxt->nextpage * OOPS_PAGE_SIZE,
+ retlen, ret);
+ return 1;
+ }
+
+ /* See if we need to erase the next block */
+ if (count != 0xffffffff)
+ return 1;
+
+ printk(KERN_DEBUG "mtdoops: Ready %d, %d (no erase)\n",
+ cxt->nextpage, cxt->nextcount);
+ cxt->ready = 1;
+ return 0;
+}
+
+static void mtdoops_prepare(struct mtdoops_context *cxt)
+{
+ struct mtd_info *mtd = cxt->mtd;
+ int i = 0, j, ret, mod;
+
+ /* We were unregistered */
+ if (!mtd)
+ return;
+
+ mod = (cxt->nextpage * OOPS_PAGE_SIZE) % mtd->erasesize;
+ if (mod != 0) {
+ cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / OOPS_PAGE_SIZE);
+ if (cxt->nextpage > cxt->oops_pages)
+ cxt->nextpage = 0;
+ }
+
+ while (mtd->block_isbad &&
+ mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE)) {
+badblock:
+ printk(KERN_WARNING "mtdoops: Bad block at %08x\n",
+ cxt->nextpage * OOPS_PAGE_SIZE);
+ i++;
+ cxt->nextpage = cxt->nextpage + (mtd->erasesize / OOPS_PAGE_SIZE);
+ if (cxt->nextpage > cxt->oops_pages)
+ cxt->nextpage = 0;
+ if (i == (cxt->oops_pages / (mtd->erasesize / OOPS_PAGE_SIZE))) {
+ printk(KERN_ERR "mtdoops: All blocks bad!\n");
+ return;
+ }
+ }
+
+ for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
+ ret = mtdoops_erase_block(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+
+ if (ret < 0) {
+ if (mtd->block_markbad)
+ mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+ goto badblock;
+ }
+
+ printk(KERN_DEBUG "mtdoops: Ready %d, %d \n", cxt->nextpage, cxt->nextcount);
+
+ cxt->ready = 1;
+}
+
+static void mtdoops_workfunc(struct work_struct *work)
+{
+ struct mtdoops_context *cxt =
+ container_of(work, struct mtdoops_context, work);
+
+ mtdoops_prepare(cxt);
+}
+
+static int find_next_position(struct mtdoops_context *cxt)
+{
+ struct mtd_info *mtd = cxt->mtd;
+ int page, maxpos = 0;
+ u32 count, maxcount = 0xffffffff;
+ size_t retlen;
+
+ for (page = 0; page < cxt->oops_pages; page++) {
+ mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count);
+ if (count == 0xffffffff)
+ continue;
+ if (maxcount == 0xffffffff) {
+ maxcount = count;
+ maxpos = page;
+ } else if ((count < 0x40000000) && (maxcount > 0xc0000000)) {
+ maxcount = count;
+ maxpos = page;
+ } else if ((count > maxcount) && (count < 0xc0000000)) {
+ maxcount = count;
+ maxpos = page;
+ } else if ((count > maxcount) && (count > 0xc0000000)
+ && (maxcount > 0x80000000)) {
+ maxcount = count;
+ maxpos = page;
+ }
+ }
+ if (maxcount == 0xffffffff) {
+ cxt->nextpage = 0;
+ cxt->nextcount = 1;
+ cxt->ready = 1;
+ printk(KERN_DEBUG "mtdoops: Ready %d, %d (first init)\n",
+ cxt->nextpage, cxt->nextcount);
+ return 0;
+ }
+
+ cxt->nextpage = maxpos;
+ cxt->nextcount = maxcount;
+
+ return mtdoops_inc_counter(cxt);
+}
+
+
+static void mtdoops_notify_add(struct mtd_info *mtd)
+{
+ struct mtdoops_context *cxt = &oops_cxt;
+ int ret;
+
+ if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0)
+ return;
+
+ if (mtd->size < (mtd->erasesize * 2)) {
+ printk(KERN_ERR "MTD partition %d not big enough for mtdoops\n",
+ mtd->index);
+ return;
+ }
+
+ cxt->mtd = mtd;
+ cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE;
+
+ ret = find_next_position(cxt);
+ if (ret == 1)
+ mtdoops_prepare(cxt);
+
+ printk(KERN_DEBUG "mtdoops: Attached to MTD device %d\n", mtd->index);
+}
+
+static void mtdoops_notify_remove(struct mtd_info *mtd)
+{
+ struct mtdoops_context *cxt = &oops_cxt;
+
+ if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0)
+ return;
+
+ cxt->mtd = NULL;
+ flush_scheduled_work();
+}
+
+static void mtdoops_console_sync(void)
+{
+ struct mtdoops_context *cxt = &oops_cxt;
+ struct mtd_info *mtd = cxt->mtd;
+ size_t retlen;
+ int ret;
+
+ if (!cxt->ready || !mtd)
+ return;
+
+ if (cxt->writecount == 0)
+ return;
+
+ if (cxt->writecount < OOPS_PAGE_SIZE)
+ memset(cxt->oops_buf + cxt->writecount, 0xff,
+ OOPS_PAGE_SIZE - cxt->writecount);
+
+ ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
+ OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+ cxt->ready = 0;
+ cxt->writecount = 0;
+
+ if ((retlen != OOPS_PAGE_SIZE) || (ret < 0))
+ printk(KERN_ERR "mtdoops: Write failure at %d (%td of %d written), err %d.\n",
+ cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret);
+
+ ret = mtdoops_inc_counter(cxt);
+ if (ret == 1)
+ schedule_work(&cxt->work);
+}
+
+static void
+mtdoops_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct mtdoops_context *cxt = co->data;
+ struct mtd_info *mtd = cxt->mtd;
+ int i;
+
+ if (!oops_in_progress) {
+ mtdoops_console_sync();
+ return;
+ }
+
+ if (!cxt->ready || !mtd)
+ return;
+
+ if (cxt->writecount == 0) {
+ u32 *stamp = cxt->oops_buf;
+ *stamp = cxt->nextcount;
+ cxt->writecount = 4;
+ }
+
+ if ((count + cxt->writecount) > OOPS_PAGE_SIZE)
+ count = OOPS_PAGE_SIZE - cxt->writecount;
+
+ for (i = 0; i < count; i++, s++)
+ *((char *)(cxt->oops_buf) + cxt->writecount + i) = *s;
+
+ cxt->writecount = cxt->writecount + count;
+}
+
+static int __init mtdoops_console_setup(struct console *co, char *options)
+{
+ struct mtdoops_context *cxt = co->data;
+
+ if (cxt->mtd_index != -1)
+ return -EBUSY;
+ if (co->index == -1)
+ return -EINVAL;
+
+ cxt->mtd_index = co->index;
+ return 0;
+}
+
+static struct mtd_notifier mtdoops_notifier = {
+ .add = mtdoops_notify_add,
+ .remove = mtdoops_notify_remove,
+};
+
+static struct console mtdoops_console = {
+ .name = "ttyMTD",
+ .write = mtdoops_console_write,
+ .setup = mtdoops_console_setup,
+ .unblank = mtdoops_console_sync,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &oops_cxt,
+};
+
+static int __init mtdoops_console_init(void)
+{
+ struct mtdoops_context *cxt = &oops_cxt;
+
+ cxt->mtd_index = -1;
+ cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE);
+
+ if (!cxt->oops_buf) {
+ printk(KERN_ERR "Failed to allocate oops buffer workspace\n");
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&cxt->work, mtdoops_workfunc);
+
+ register_console(&mtdoops_console);
+ register_mtd_user(&mtdoops_notifier);
+ return 0;
+}
+
+static void __exit mtdoops_console_exit(void)
+{
+ struct mtdoops_context *cxt = &oops_cxt;
+
+ unregister_mtd_user(&mtdoops_notifier);
+ unregister_console(&mtdoops_console);
+ vfree(cxt->oops_buf);
+}
+
+
+subsys_initcall(mtdoops_console_init);
+module_exit(mtdoops_console_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
+MODULE_DESCRIPTION("MTD Oops/Panic console logger/driver");
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index f1d60b6f048..246d4512f64 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -91,6 +91,25 @@ config MTD_NAND_AU1550
This enables the driver for the NAND flash controller on the
AMD/Alchemy 1550 SOC.
+config MTD_NAND_BF5XX
+ tristate "Blackfin on-chip NAND Flash Controller driver"
+ depends on BF54x && MTD_NAND
+ help
+ This enables the Blackfin on-chip NAND flash controller
+
+ No board specific support is done by this driver, each board
+ must advertise a platform_device for the driver to attach.
+
+ This driver can also be built as a module. If so, the module
+ will be called bf5xx-nand.
+
+config MTD_NAND_BF5XX_HWECC
+ bool "BF5XX NAND Hardware ECC"
+ depends on MTD_NAND_BF5XX
+ help
+ Enable the use of the BF5XX's internal ECC generator when
+ using NAND.
+
config MTD_NAND_RTC_FROM4
tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)"
depends on SH_SOLUTION_ENGINE
@@ -134,10 +153,10 @@ config MTD_NAND_S3C2410_HWECC
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
- depends on 44x
+ depends on 4xx && !PPC_MERGE
select MTD_NAND_ECC_SMC
help
- NDFC Nand Flash Controllers are integrated in EP44x SoCs
+ NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
config MTD_NAND_S3C2410_CLKSTOP
bool "S3C2410 NAND IDLE clock stop"
@@ -237,7 +256,7 @@ config MTD_NAND_CAFE
select REED_SOLOMON
select REED_SOLOMON_DEC16
help
- Use NAND flash attached to the CAFÉ chip designed for the $100
+ Use NAND flash attached to the CAFÉ chip designed for the OLPC
laptop.
config MTD_NAND_CS553X
@@ -280,5 +299,11 @@ config MTD_NAND_PLATFORM
devices. You will need to provide platform-specific functions
via platform_data.
+config MTD_ALAUDA
+ tristate "MTD driver for Olympus MAUSB-10 and Fujifilm DPC-R1"
+ depends on MTD_NAND && USB
+ help
+ These two (and possibly other) Alauda-based cardreaders for
+ SmartMedia and xD allow raw flash access.
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index edba1db14bf..3ad6c0165da 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_NAND_TOTO) += toto.o
obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
+obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
@@ -27,5 +28,6 @@ obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
+obj-$(CONFIG_MTD_ALAUDA) += alauda.o
nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c
new file mode 100644
index 00000000000..257937cd99b
--- /dev/null
+++ b/drivers/mtd/nand/alauda.c
@@ -0,0 +1,742 @@
+/*
+ * MTD driver for Alauda chips
+ *
+ * Copyright (C) 2007 Joern Engel <joern@logfs.org>
+ *
+ * Based on drivers/usb/usb-skeleton.c which is:
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ * and on drivers/usb/storage/alauda.c, which is:
+ * (c) 2005 Daniel Drake <dsd@gentoo.org>
+ *
+ * Idea and initial work by Arnd Bergmann <arnd@arndb.de>
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand_ecc.h>
+
+/* Control commands */
+#define ALAUDA_GET_XD_MEDIA_STATUS 0x08
+#define ALAUDA_ACK_XD_MEDIA_CHANGE 0x0a
+#define ALAUDA_GET_XD_MEDIA_SIG 0x86
+
+/* Common prefix */
+#define ALAUDA_BULK_CMD 0x40
+
+/* The two ports */
+#define ALAUDA_PORT_XD 0x00
+#define ALAUDA_PORT_SM 0x01
+
+/* Bulk commands */
+#define ALAUDA_BULK_READ_PAGE 0x84
+#define ALAUDA_BULK_READ_OOB 0x85 /* don't use, there's a chip bug */
+#define ALAUDA_BULK_READ_BLOCK 0x94
+#define ALAUDA_BULK_ERASE_BLOCK 0xa3
+#define ALAUDA_BULK_WRITE_PAGE 0xa4
+#define ALAUDA_BULK_WRITE_BLOCK 0xb4
+#define ALAUDA_BULK_RESET_MEDIA 0xe0
+
+/* Address shifting */
+#define PBA_LO(pba) ((pba & 0xF) << 5)
+#define PBA_HI(pba) (pba >> 3)
+#define PBA_ZONE(pba) (pba >> 11)
+
+#define TIMEOUT HZ
+
+static struct usb_device_id alauda_table [] = {
+ { USB_DEVICE(0x0584, 0x0008) }, /* Fujifilm DPC-R1 */
+ { USB_DEVICE(0x07b4, 0x010a) }, /* Olympus MAUSB-10 */
+ { }
+};
+MODULE_DEVICE_TABLE(usb, alauda_table);
+
+struct alauda_card {
+ u8 id; /* id byte */
+ u8 chipshift; /* 1<<chipshift total size */
+ u8 pageshift; /* 1<<pageshift page size */
+ u8 blockshift; /* 1<<blockshift block size */
+};
+
+struct alauda {
+ struct usb_device *dev;
+ struct usb_interface *interface;
+ struct mtd_info *mtd;
+ struct alauda_card *card;
+ struct mutex card_mutex;
+ u32 pagemask;
+ u32 bytemask;
+ u32 blockmask;
+ unsigned int write_out;
+ unsigned int bulk_in;
+ unsigned int bulk_out;
+ u8 port;
+ struct kref kref;
+};
+
+static struct alauda_card alauda_card_ids[] = {
+ /* NAND flash */
+ { 0x6e, 20, 8, 12}, /* 1 MB */
+ { 0xe8, 20, 8, 12}, /* 1 MB */
+ { 0xec, 20, 8, 12}, /* 1 MB */
+ { 0x64, 21, 8, 12}, /* 2 MB */
+ { 0xea, 21, 8, 12}, /* 2 MB */
+ { 0x6b, 22, 9, 13}, /* 4 MB */
+ { 0xe3, 22, 9, 13}, /* 4 MB */
+ { 0xe5, 22, 9, 13}, /* 4 MB */
+ { 0xe6, 23, 9, 13}, /* 8 MB */
+ { 0x73, 24, 9, 14}, /* 16 MB */
+ { 0x75, 25, 9, 14}, /* 32 MB */
+ { 0x76, 26, 9, 14}, /* 64 MB */
+ { 0x79, 27, 9, 14}, /* 128 MB */
+ { 0x71, 28, 9, 14}, /* 256 MB */
+
+ /* MASK ROM */
+ { 0x5d, 21, 9, 13}, /* 2 MB */
+ { 0xd5, 22, 9, 13}, /* 4 MB */
+ { 0xd6, 23, 9, 13}, /* 8 MB */
+ { 0x57, 24, 9, 13}, /* 16 MB */
+ { 0x58, 25, 9, 13}, /* 32 MB */
+ { }
+};
+
+static struct alauda_card *get_card(u8 id)
+{
+ struct alauda_card *card;
+
+ for (card = alauda_card_ids; card->id; card++)
+ if (card->id == id)
+ return card;
+ return NULL;
+}
+
+static void alauda_delete(struct kref *kref)
+{
+ struct alauda *al = container_of(kref, struct alauda, kref);
+
+ if (al->mtd) {
+ del_mtd_device(al->mtd);
+ kfree(al->mtd);
+ }
+ usb_put_dev(al->dev);
+ kfree(al);
+}
+
+static int alauda_get_media_status(struct alauda *al, void *buf)
+{
+ int ret;
+
+ mutex_lock(&al->card_mutex);
+ ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),
+ ALAUDA_GET_XD_MEDIA_STATUS, 0xc0, 0, 1, buf, 2, HZ);
+ mutex_unlock(&al->card_mutex);
+ return ret;
+}
+
+static int alauda_ack_media(struct alauda *al)
+{
+ int ret;
+
+ mutex_lock(&al->card_mutex);
+ ret = usb_control_msg(al->dev, usb_sndctrlpipe(al->dev, 0),
+ ALAUDA_ACK_XD_MEDIA_CHANGE, 0x40, 0, 1, NULL, 0, HZ);
+ mutex_unlock(&al->card_mutex);
+ return ret;
+}
+
+static int alauda_get_media_signatures(struct alauda *al, void *buf)
+{
+ int ret;
+
+ mutex_lock(&al->card_mutex);
+ ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),
+ ALAUDA_GET_XD_MEDIA_SIG, 0xc0, 0, 0, buf, 4, HZ);
+ mutex_unlock(&al->card_mutex);
+ return ret;
+}
+
+static void alauda_reset(struct alauda *al)
+{
+ u8 command[] = {
+ ALAUDA_BULK_CMD, ALAUDA_BULK_RESET_MEDIA, 0, 0,
+ 0, 0, 0, 0, al->port
+ };
+ mutex_lock(&al->card_mutex);
+ usb_bulk_msg(al->dev, al->bulk_out, command, 9, NULL, HZ);
+ mutex_unlock(&al->card_mutex);
+}
+
+static void correct_data(void *buf, void *read_ecc,
+ int *corrected, int *uncorrected)
+{
+ u8 calc_ecc[3];
+ int err;
+
+ nand_calculate_ecc(NULL, buf, calc_ecc);
+ err = nand_correct_data(NULL, buf, read_ecc, calc_ecc);
+ if (err) {
+ if (err > 0)
+ (*corrected)++;
+ else
+ (*uncorrected)++;
+ }
+}
+
+struct alauda_sg_request {
+ struct urb *urb[3];
+ struct completion comp;
+};
+
+static void alauda_complete(struct urb *urb)
+{
+ struct completion *comp = urb->context;
+
+ if (comp)
+ complete(comp);
+}
+
+static int __alauda_read_page(struct mtd_info *mtd, loff_t from, void *buf,
+ void *oob)
+{
+ struct alauda_sg_request sg;
+ struct alauda *al = mtd->priv;
+ u32 pba = from >> al->card->blockshift;
+ u32 page = (from >> al->card->pageshift) & al->pagemask;
+ u8 command[] = {
+ ALAUDA_BULK_CMD, ALAUDA_BULK_READ_PAGE, PBA_HI(pba),
+ PBA_ZONE(pba), 0, PBA_LO(pba) + page, 1, 0, al->port
+ };
+ int i, err;
+
+ for (i=0; i<3; i++)
+ sg.urb[i] = NULL;
+
+ err = -ENOMEM;
+ for (i=0; i<3; i++) {
+ sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
+ if (!sg.urb[i])
+ goto out;
+ }
+ init_completion(&sg.comp);
+ usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
+ alauda_complete, NULL);
+ usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, mtd->writesize,
+ alauda_complete, NULL);
+ usb_fill_bulk_urb(sg.urb[2], al->dev, al->bulk_in, oob, 16,
+ alauda_complete, &sg.comp);
+
+ mutex_lock(&al->card_mutex);
+ for (i=0; i<3; i++) {
+ err = usb_submit_urb(sg.urb[i], GFP_NOIO);
+ if (err)
+ goto cancel;
+ }
+ if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
+ err = -ETIMEDOUT;
+cancel:
+ for (i=0; i<3; i++) {
+ usb_kill_urb(sg.urb[i]);
+ }
+ }
+ mutex_unlock(&al->card_mutex);
+
+out:
+ usb_free_urb(sg.urb[0]);
+ usb_free_urb(sg.urb[1]);
+ usb_free_urb(sg.urb[2]);
+ return err;
+}
+
+static int alauda_read_page(struct mtd_info *mtd, loff_t from,
+ void *buf, u8 *oob, int *corrected, int *uncorrected)
+{
+ int err;
+
+ err = __alauda_read_page(mtd, from, buf, oob);
+ if (err)
+ return err;
+ correct_data(buf, oob+13, corrected, uncorrected);
+ correct_data(buf+256, oob+8, corrected, uncorrected);
+ return 0;
+}
+
+static int alauda_write_page(struct mtd_info *mtd, loff_t to, void *buf,
+ void *oob)
+{
+ struct alauda_sg_request sg;
+ struct alauda *al = mtd->priv;
+ u32 pba = to >> al->card->blockshift;
+ u32 page = (to >> al->card->pageshift) & al->pagemask;
+ u8 command[] = {
+ ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_PAGE, PBA_HI(pba),
+ PBA_ZONE(pba), 0, PBA_LO(pba) + page, 32, 0, al->port
+ };
+ int i, err;
+
+ for (i=0; i<3; i++)
+ sg.urb[i] = NULL;
+
+ err = -ENOMEM;
+ for (i=0; i<3; i++) {
+ sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
+ if (!sg.urb[i])
+ goto out;
+ }
+ init_completion(&sg.comp);
+ usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
+ alauda_complete, NULL);
+ usb_fill_bulk_urb(sg.urb[1], al->dev, al->write_out, buf,mtd->writesize,
+ alauda_complete, NULL);
+ usb_fill_bulk_urb(sg.urb[2], al->dev, al->write_out, oob, 16,
+ alauda_complete, &sg.comp);
+
+ mutex_lock(&al->card_mutex);
+ for (i=0; i<3; i++) {
+ err = usb_submit_urb(sg.urb[i], GFP_NOIO);
+ if (err)
+ goto cancel;
+ }
+ if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
+ err = -ETIMEDOUT;
+cancel:
+ for (i=0; i<3; i++) {
+ usb_kill_urb(sg.urb[i]);
+ }
+ }
+ mutex_unlock(&al->card_mutex);
+
+out:
+ usb_free_urb(sg.urb[0]);
+ usb_free_urb(sg.urb[1]);
+ usb_free_urb(sg.urb[2]);
+ return err;
+}
+
+static int alauda_erase_block(struct mtd_info *mtd, loff_t ofs)
+{
+ struct alauda_sg_request sg;
+ struct alauda *al = mtd->priv;
+ u32 pba = ofs >> al->card->blockshift;
+ u8 command[] = {
+ ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba),
+ PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, al->port
+ };
+ u8 buf[2];
+ int i, err;
+
+ for (i=0; i<2; i++)
+ sg.urb[i] = NULL;
+
+ err = -ENOMEM;
+ for (i=0; i<2; i++) {
+ sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
+ if (!sg.urb[i])
+ goto out;
+ }
+ init_completion(&sg.comp);
+ usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
+ alauda_complete, NULL);
+ usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, 2,
+ alauda_complete, &sg.comp);
+
+ mutex_lock(&al->card_mutex);
+ for (i=0; i<2; i++) {
+ err = usb_submit_urb(sg.urb[i], GFP_NOIO);
+ if (err)
+ goto cancel;
+ }
+ if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
+ err = -ETIMEDOUT;
+cancel:
+ for (i=0; i<2; i++) {
+ usb_kill_urb(sg.urb[i]);
+ }
+ }
+ mutex_unlock(&al->card_mutex);
+
+out:
+ usb_free_urb(sg.urb[0]);
+ usb_free_urb(sg.urb[1]);
+ return err;
+}
+
+static int alauda_read_oob(struct mtd_info *mtd, loff_t from, void *oob)
+{
+ static u8 ignore_buf[512]; /* write only */
+
+ return __alauda_read_page(mtd, from, ignore_buf, oob);
+}
+
+static int popcount8(u8 c)
+{
+ int ret = 0;
+
+ for ( ; c; c>>=1)
+ ret += c & 1;
+ return ret;
+}
+
+static int alauda_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+ u8 oob[16];
+ int err;
+
+ err = alauda_read_oob(mtd, ofs, oob);
+ if (err)
+ return err;
+
+ /* A block is marked bad if two or more bits are zero */
+ return popcount8(oob[5]) >= 7 ? 0 : 1;
+}
+
+static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct alauda *al = mtd->priv;
+ void *bounce_buf;
+ int err, corrected=0, uncorrected=0;
+
+ bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL);
+ if (!bounce_buf)
+ return -ENOMEM;
+
+ *retlen = len;
+ while (len) {
+ u8 oob[16];
+ size_t byte = from & al->bytemask;
+ size_t cplen = min(len, mtd->writesize - byte);
+
+ err = alauda_read_page(mtd, from, bounce_buf, oob,
+ &corrected, &uncorrected);
+ if (err)
+ goto out;
+
+ memcpy(buf, bounce_buf + byte, cplen);
+ buf += cplen;
+ from += cplen;
+ len -= cplen;
+ }
+ err = 0;
+ if (corrected)
+ err = -EUCLEAN;
+ if (uncorrected)
+ err = -EBADMSG;
+out:
+ kfree(bounce_buf);
+ return err;
+}
+
+static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct alauda *al = mtd->priv;
+ int err, corrected=0, uncorrected=0;
+
+ if ((from & al->bytemask) || (len & al->bytemask))
+ return alauda_bounce_read(mtd, from, len, retlen, buf);
+
+ *retlen = len;
+ while (len) {
+ u8 oob[16];
+
+ err = alauda_read_page(mtd, from, buf, oob,
+ &corrected, &uncorrected);
+ if (err)
+ return err;
+
+ buf += mtd->writesize;
+ from += mtd->writesize;
+ len -= mtd->writesize;
+ }
+ err = 0;
+ if (corrected)
+ err = -EUCLEAN;
+ if (uncorrected)
+ err = -EBADMSG;
+ return err;
+}
+
+static int alauda_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct alauda *al = mtd->priv;
+ int err;
+
+ if ((to & al->bytemask) || (len & al->bytemask))
+ return -EINVAL;
+
+ *retlen = len;
+ while (len) {
+ u32 page = (to >> al->card->pageshift) & al->pagemask;
+ u8 oob[16] = { 'h', 'e', 'l', 'l', 'o', 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ /* don't write to bad blocks */
+ if (page == 0) {
+ err = alauda_isbad(mtd, to);
+ if (err) {
+ return -EIO;
+ }
+ }
+ nand_calculate_ecc(mtd, buf, &oob[13]);
+ nand_calculate_ecc(mtd, buf+256, &oob[8]);
+
+ err = alauda_write_page(mtd, to, (void*)buf, oob);
+ if (err)
+ return err;
+
+ buf += mtd->writesize;
+ to += mtd->writesize;
+ len -= mtd->writesize;
+ }
+ return 0;
+}
+
+static int __alauda_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct alauda *al = mtd->priv;
+ u32 ofs = instr->addr;
+ u32 len = instr->len;
+ int err;
+
+ if ((ofs & al->blockmask) || (len & al->blockmask))
+ return -EINVAL;
+
+ while (len) {
+ /* don't erase bad blocks */
+ err = alauda_isbad(mtd, ofs);
+ if (err > 0)
+ err = -EIO;
+ if (err < 0)
+ return err;
+
+ err = alauda_erase_block(mtd, ofs);
+ if (err < 0)
+ return err;
+
+ ofs += mtd->erasesize;
+ len -= mtd->erasesize;
+ }
+ return 0;
+}
+
+static int alauda_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ int err;
+
+ err = __alauda_erase(mtd, instr);
+ instr->state = err ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+ return err;
+}
+
+static int alauda_init_media(struct alauda *al)
+{
+ u8 buf[4], *b0=buf, *b1=buf+1;
+ struct alauda_card *card;
+ struct mtd_info *mtd;
+ int err;
+
+ mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
+ if (!mtd)
+ return -ENOMEM;
+
+ for (;;) {
+ err = alauda_get_media_status(al, buf);
+ if (err < 0)
+ goto error;
+ if (*b0 & 0x10)
+ break;
+ msleep(20);
+ }
+
+ err = alauda_ack_media(al);
+ if (err)
+ goto error;
+
+ msleep(10);
+
+ err = alauda_get_media_status(al, buf);
+ if (err < 0)
+ goto error;
+
+ if (*b0 != 0x14) {
+ /* media not ready */
+ err = -EIO;
+ goto error;
+ }
+ err = alauda_get_media_signatures(al, buf);
+ if (err < 0)
+ goto error;
+
+ card = get_card(*b1);
+ if (!card) {
+ printk(KERN_ERR"Alauda: unknown card id %02x\n", *b1);
+ err = -EIO;
+ goto error;
+ }
+ printk(KERN_INFO"pagesize=%x\nerasesize=%x\nsize=%xMiB\n",
+ 1<<card->pageshift, 1<<card->blockshift,
+ 1<<(card->chipshift-20));
+ al->card = card;
+ al->pagemask = (1 << (card->blockshift - card->pageshift)) - 1;
+ al->bytemask = (1 << card->pageshift) - 1;
+ al->blockmask = (1 << card->blockshift) - 1;
+
+ mtd->name = "alauda";
+ mtd->size = 1<<card->chipshift;
+ mtd->erasesize = 1<<card->blockshift;
+ mtd->writesize = 1<<card->pageshift;
+ mtd->type = MTD_NANDFLASH;
+ mtd->flags = MTD_CAP_NANDFLASH;
+ mtd->read = alauda_read;
+ mtd->write = alauda_write;
+ mtd->erase = alauda_erase;
+ mtd->block_isbad = alauda_isbad;
+ mtd->priv = al;
+ mtd->owner = THIS_MODULE;
+
+ err = add_mtd_device(mtd);
+ if (err) {
+ err = -ENFILE;
+ goto error;
+ }
+
+ al->mtd = mtd;
+ alauda_reset(al); /* no clue whether this is necessary */
+ return 0;
+error:
+ kfree(mtd);
+ return err;
+}
+
+static int alauda_check_media(struct alauda *al)
+{
+ u8 buf[2], *b0 = buf, *b1 = buf+1;
+ int err;
+
+ err = alauda_get_media_status(al, buf);
+ if (err < 0)
+ return err;
+
+ if ((*b1 & 0x01) == 0) {
+ /* door open */
+ return -EIO;
+ }
+ if ((*b0 & 0x80) || ((*b0 & 0x1F) == 0x10)) {
+ /* no media ? */
+ return -EIO;
+ }
+ if (*b0 & 0x08) {
+ /* media change ? */
+ return alauda_init_media(al);
+ }
+ return 0;
+}
+
+static int alauda_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct alauda *al;
+ struct usb_host_interface *iface;
+ struct usb_endpoint_descriptor *ep,
+ *ep_in=NULL, *ep_out=NULL, *ep_wr=NULL;
+ int i, err = -ENOMEM;
+
+ al = kzalloc(2*sizeof(*al), GFP_KERNEL);
+ if (!al)
+ goto error;
+
+ kref_init(&al->kref);
+ usb_set_intfdata(interface, al);
+
+ al->dev = usb_get_dev(interface_to_usbdev(interface));
+ al->interface = interface;
+
+ iface = interface->cur_altsetting;
+ for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
+ ep = &iface->endpoint[i].desc;
+
+ if (usb_endpoint_is_bulk_in(ep)) {
+ ep_in = ep;
+ } else if (usb_endpoint_is_bulk_out(ep)) {
+ if (i==0)
+ ep_wr = ep;
+ else
+ ep_out = ep;
+ }
+ }
+ err = -EIO;
+ if (!ep_wr || !ep_in || !ep_out)
+ goto error;
+
+ al->write_out = usb_sndbulkpipe(al->dev,
+ ep_wr->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ al->bulk_in = usb_rcvbulkpipe(al->dev,
+ ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ al->bulk_out = usb_sndbulkpipe(al->dev,
+ ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+
+ /* second device is identical up to now */
+ memcpy(al+1, al, sizeof(*al));
+
+ mutex_init(&al[0].card_mutex);
+ mutex_init(&al[1].card_mutex);
+
+ al[0].port = ALAUDA_PORT_XD;
+ al[1].port = ALAUDA_PORT_SM;
+
+ info("alauda probed");
+ alauda_check_media(al);
+ alauda_check_media(al+1);
+
+ return 0;
+
+error:
+ if (al)
+ kref_put(&al->kref, alauda_delete);
+ return err;
+}
+
+static void alauda_disconnect(struct usb_interface *interface)
+{
+ struct alauda *al;
+
+ al = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ /* FIXME: prevent more I/O from starting */
+
+ /* decrement our usage count */
+ if (al)
+ kref_put(&al->kref, alauda_delete);
+
+ info("alauda gone");
+}
+
+static struct usb_driver alauda_driver = {
+ .name = "alauda",
+ .probe = alauda_probe,
+ .disconnect = alauda_disconnect,
+ .id_table = alauda_table,
+};
+
+static int __init alauda_init(void)
+{
+ return usb_register(&alauda_driver);
+}
+
+static void __exit alauda_exit(void)
+{
+ usb_deregister(&alauda_driver);
+}
+
+module_init(alauda_init);
+module_exit(alauda_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
new file mode 100644
index 00000000000..1657ecd7488
--- /dev/null
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -0,0 +1,788 @@
+/* linux/drivers/mtd/nand/bf5xx_nand.c
+ *
+ * Copyright 2006-2007 Analog Devices Inc.
+ * http://blackfin.uclinux.org/
+ * Bryan Wu <bryan.wu@analog.com>
+ *
+ * Blackfin BF5xx on-chip NAND flash controler driver
+ *
+ * Derived from drivers/mtd/nand/s3c2410.c
+ * Copyright (c) 2007 Ben Dooks <ben@simtec.co.uk>
+ *
+ * Derived from drivers/mtd/nand/cafe.c
+ * Copyright © 2006 Red Hat, Inc.
+ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Changelog:
+ * 12-Jun-2007 Bryan Wu: Initial version
+ * 18-Jul-2007 Bryan Wu:
+ * - ECC_HW and ECC_SW supported
+ * - DMA supported in ECC_HW
+ * - YAFFS tested as rootfs in both ECC_HW and ECC_SW
+ *
+ * TODO:
+ * Enable JFFS2 over NAND as rootfs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/blackfin.h>
+#include <asm/dma.h>
+#include <asm/cacheflush.h>
+#include <asm/nand.h>
+#include <asm/portmux.h>
+
+#define DRV_NAME "bf5xx-nand"
+#define DRV_VERSION "1.2"
+#define DRV_AUTHOR "Bryan Wu <bryan.wu@analog.com>"
+#define DRV_DESC "BF5xx on-chip NAND FLash Controller Driver"
+
+#ifdef CONFIG_MTD_NAND_BF5XX_HWECC
+static int hardware_ecc = 1;
+#else
+static int hardware_ecc;
+#endif
+
+static unsigned short bfin_nfc_pin_req[] = {P_NAND_CE, P_NAND_RB, 0};
+
+/*
+ * Data structures for bf5xx nand flash controller driver
+ */
+
+/* bf5xx nand info */
+struct bf5xx_nand_info {
+ /* mtd info */
+ struct nand_hw_control controller;
+ struct mtd_info mtd;
+ struct nand_chip chip;
+
+ /* platform info */
+ struct bf5xx_nand_platform *platform;
+
+ /* device info */
+ struct device *device;
+
+ /* DMA stuff */
+ struct completion dma_completion;
+};
+
+/*
+ * Conversion functions
+ */
+static struct bf5xx_nand_info *mtd_to_nand_info(struct mtd_info *mtd)
+{
+ return container_of(mtd, struct bf5xx_nand_info, mtd);
+}
+
+static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
+{
+ return platform_get_drvdata(pdev);
+}
+
+static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
+{
+ return pdev->dev.platform_data;
+}
+
+/*
+ * struct nand_chip interface function pointers
+ */
+
+/*
+ * bf5xx_nand_hwcontrol
+ *
+ * Issue command and address cycles to the chip
+ */
+static void bf5xx_nand_hwcontrol(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ while (bfin_read_NFC_STAT() & WB_FULL)
+ cpu_relax();
+
+ if (ctrl & NAND_CLE)
+ bfin_write_NFC_CMD(cmd);
+ else
+ bfin_write_NFC_ADDR(cmd);
+ SSYNC();
+}
+
+/*
+ * bf5xx_nand_devready()
+ *
+ * returns 0 if the nand is busy, 1 if it is ready
+ */
+static int bf5xx_nand_devready(struct mtd_info *mtd)
+{
+ unsigned short val = bfin_read_NFC_IRQSTAT();
+
+ if ((val & NBUSYIRQ) == NBUSYIRQ)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * ECC functions
+ * These allow the bf5xx to use the controller's ECC
+ * generator block to ECC the data as it passes through
+ */
+
+/*
+ * ECC error correction function
+ */
+static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+ u32 syndrome[5];
+ u32 calced, stored;
+ int i;
+ unsigned short failing_bit, failing_byte;
+ u_char data;
+
+ calced = calc_ecc[0] | (calc_ecc[1] << 8) | (calc_ecc[2] << 16);
+ stored = read_ecc[0] | (read_ecc[1] << 8) | (read_ecc[2] << 16);
+
+ syndrome[0] = (calced ^ stored);
+
+ /*
+ * syndrome 0: all zero
+ * No error in data
+ * No action
+ */
+ if (!syndrome[0] || !calced || !stored)
+ return 0;
+
+ /*
+ * sysdrome 0: only one bit is one
+ * ECC data was incorrect
+ * No action
+ */
+ if (hweight32(syndrome[0]) == 1) {
+ dev_err(info->device, "ECC data was incorrect!\n");
+ return 1;
+ }
+
+ syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF);
+ syndrome[2] = (calced & 0x7FF) ^ ((calced >> 11) & 0x7FF);
+ syndrome[3] = (stored & 0x7FF) ^ ((stored >> 11) & 0x7FF);
+ syndrome[4] = syndrome[2] ^ syndrome[3];
+
+ for (i = 0; i < 5; i++)
+ dev_info(info->device, "syndrome[%d] 0x%08x\n", i, syndrome[i]);
+
+ dev_info(info->device,
+ "calced[0x%08x], stored[0x%08x]\n",
+ calced, stored);
+
+ /*
+ * sysdrome 0: exactly 11 bits are one, each parity
+ * and parity' pair is 1 & 0 or 0 & 1.
+ * 1-bit correctable error
+ * Correct the error
+ */
+ if (hweight32(syndrome[0]) == 11 && syndrome[4] == 0x7FF) {
+ dev_info(info->device,
+ "1-bit correctable error, correct it.\n");
+ dev_info(info->device,
+ "syndrome[1] 0x%08x\n", syndrome[1]);
+
+ failing_bit = syndrome[1] & 0x7;
+ failing_byte = syndrome[1] >> 0x3;
+ data = *(dat + failing_byte);
+ data = data ^ (0x1 << failing_bit);
+ *(dat + failing_byte) = data;
+
+ return 0;
+ }
+
+ /*
+ * sysdrome 0: random data
+ * More than 1-bit error, non-correctable error
+ * Discard data, mark bad block
+ */
+ dev_err(info->device,
+ "More than 1-bit error, non-correctable error.\n");
+ dev_err(info->device,
+ "Please discard data, mark bad block\n");
+
+ return 1;
+}
+
+static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+ struct bf5xx_nand_platform *plat = info->platform;
+ unsigned short page_size = (plat->page_size ? 512 : 256);
+ int ret;
+
+ ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+
+ /* If page size is 512, correct second 256 bytes */
+ if (page_size == 512) {
+ dat += 256;
+ read_ecc += 8;
+ calc_ecc += 8;
+ ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc);
+ }
+
+ return ret;
+}
+
+static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ return;
+}
+
+static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd,
+ const u_char *dat, u_char *ecc_code)
+{
+ struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+ struct bf5xx_nand_platform *plat = info->platform;
+ u16 page_size = (plat->page_size ? 512 : 256);
+ u16 ecc0, ecc1;
+ u32 code[2];
+ u8 *p;
+ int bytes = 3, i;
+
+ /* first 4 bytes ECC code for 256 page size */
+ ecc0 = bfin_read_NFC_ECC0();
+ ecc1 = bfin_read_NFC_ECC1();
+
+ code[0] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11);
+
+ dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]);
+
+ /* second 4 bytes ECC code for 512 page size */
+ if (page_size == 512) {
+ ecc0 = bfin_read_NFC_ECC2();
+ ecc1 = bfin_read_NFC_ECC3();
+ code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11);
+ bytes = 6;
+ dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]);
+ }
+
+ p = (u8 *)code;
+ for (i = 0; i < bytes; i++)
+ ecc_code[i] = p[i];
+
+ return 0;
+}
+
+/*
+ * PIO mode for buffer writing and reading
+ */
+static void bf5xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ int i;
+ unsigned short val;
+
+ /*
+ * Data reads are requested by first writing to NFC_DATA_RD
+ * and then reading back from NFC_READ.
+ */
+ for (i = 0; i < len; i++) {
+ while (bfin_read_NFC_STAT() & WB_FULL)
+ cpu_relax();
+
+ /* Contents do not matter */
+ bfin_write_NFC_DATA_RD(0x0000);
+ SSYNC();
+
+ while ((bfin_read_NFC_IRQSTAT() & RD_RDY) != RD_RDY)
+ cpu_relax();
+
+ buf[i] = bfin_read_NFC_READ();
+
+ val = bfin_read_NFC_IRQSTAT();
+ val |= RD_RDY;
+ bfin_write_NFC_IRQSTAT(val);
+ SSYNC();
+ }
+}
+
+static uint8_t bf5xx_nand_read_byte(struct mtd_info *mtd)
+{
+ uint8_t val;
+
+ bf5xx_nand_read_buf(mtd, &val, 1);
+
+ return val;
+}
+
+static void bf5xx_nand_write_buf(struct mtd_info *mtd,
+ const uint8_t *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ while (bfin_read_NFC_STAT() & WB_FULL)
+ cpu_relax();
+
+ bfin_write_NFC_DATA_WR(buf[i]);
+ SSYNC();
+ }
+}
+
+static void bf5xx_nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ int i;
+ u16 *p = (u16 *) buf;
+ len >>= 1;
+
+ /*
+ * Data reads are requested by first writing to NFC_DATA_RD
+ * and then reading back from NFC_READ.
+ */
+ bfin_write_NFC_DATA_RD(0x5555);
+
+ SSYNC();
+
+ for (i = 0; i < len; i++)
+ p[i] = bfin_read_NFC_READ();
+}
+
+static void bf5xx_nand_write_buf16(struct mtd_info *mtd,
+ const uint8_t *buf, int len)
+{
+ int i;
+ u16 *p = (u16 *) buf;
+ len >>= 1;
+
+ for (i = 0; i < len; i++)
+ bfin_write_NFC_DATA_WR(p[i]);
+
+ SSYNC();
+}
+
+/*
+ * DMA functions for buffer writing and reading
+ */
+static irqreturn_t bf5xx_nand_dma_irq(int irq, void *dev_id)
+{
+ struct bf5xx_nand_info *info = dev_id;
+
+ clear_dma_irqstat(CH_NFC);
+ disable_dma(CH_NFC);
+ complete(&info->dma_completion);
+
+ return IRQ_HANDLED;
+}
+
+static int bf5xx_nand_dma_rw(struct mtd_info *mtd,
+ uint8_t *buf, int is_read)
+{
+ struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+ struct bf5xx_nand_platform *plat = info->platform;
+ unsigned short page_size = (plat->page_size ? 512 : 256);
+ unsigned short val;
+
+ dev_dbg(info->device, " mtd->%p, buf->%p, is_read %d\n",
+ mtd, buf, is_read);
+
+ /*
+ * Before starting a dma transfer, be sure to invalidate/flush
+ * the cache over the address range of your DMA buffer to
+ * prevent cache coherency problems. Otherwise very subtle bugs
+ * can be introduced to your driver.
+ */
+ if (is_read)
+ invalidate_dcache_range((unsigned int)buf,
+ (unsigned int)(buf + page_size));
+ else
+ flush_dcache_range((unsigned int)buf,
+ (unsigned int)(buf + page_size));
+
+ /*
+ * This register must be written before each page is
+ * transferred to generate the correct ECC register
+ * values.
+ */
+ bfin_write_NFC_RST(0x1);
+ SSYNC();
+
+ disable_dma(CH_NFC);
+ clear_dma_irqstat(CH_NFC);
+
+ /* setup DMA register with Blackfin DMA API */
+ set_dma_config(CH_NFC, 0x0);
+ set_dma_start_addr(CH_NFC, (unsigned long) buf);
+ set_dma_x_count(CH_NFC, (page_size >> 2));
+ set_dma_x_modify(CH_NFC, 4);
+
+ /* setup write or read operation */
+ val = DI_EN | WDSIZE_32;
+ if (is_read)
+ val |= WNR;
+ set_dma_config(CH_NFC, val);
+ enable_dma(CH_NFC);
+
+ /* Start PAGE read/write operation */
+ if (is_read)
+ bfin_write_NFC_PGCTL(0x1);
+ else
+ bfin_write_NFC_PGCTL(0x2);
+ wait_for_completion(&info->dma_completion);
+
+ return 0;
+}
+
+static void bf5xx_nand_dma_read_buf(struct mtd_info *mtd,
+ uint8_t *buf, int len)
+{
+ struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+ struct bf5xx_nand_platform *plat = info->platform;
+ unsigned short page_size = (plat->page_size ? 512 : 256);
+
+ dev_dbg(info->device, "mtd->%p, buf->%p, int %d\n", mtd, buf, len);
+
+ if (len == page_size)
+ bf5xx_nand_dma_rw(mtd, buf, 1);
+ else
+ bf5xx_nand_read_buf(mtd, buf, len);
+}
+
+static void bf5xx_nand_dma_write_buf(struct mtd_info *mtd,
+ const uint8_t *buf, int len)
+{
+ struct bf5xx_nand_info *info = mtd_to_nand_info(mtd);
+ struct bf5xx_nand_platform *plat = info->platform;
+ unsigned short page_size = (plat->page_size ? 512 : 256);
+
+ dev_dbg(info->device, "mtd->%p, buf->%p, len %d\n", mtd, buf, len);
+
+ if (len == page_size)
+ bf5xx_nand_dma_rw(mtd, (uint8_t *)buf, 0);
+ else
+ bf5xx_nand_write_buf(mtd, buf, len);
+}
+
+/*
+ * System initialization functions
+ */
+
+static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
+{
+ int ret;
+ unsigned short val;
+
+ /* Do not use dma */
+ if (!hardware_ecc)
+ return 0;
+
+ init_completion(&info->dma_completion);
+
+ /* Setup DMAC1 channel mux for NFC which shared with SDH */
+ val = bfin_read_DMAC1_PERIMUX();
+ val &= 0xFFFE;
+ bfin_write_DMAC1_PERIMUX(val);
+ SSYNC();
+
+ /* Request NFC DMA channel */
+ ret = request_dma(CH_NFC, "BF5XX NFC driver");
+ if (ret < 0) {
+ dev_err(info->device, " unable to get DMA channel\n");
+ return ret;
+ }
+
+ set_dma_callback(CH_NFC, (void *) bf5xx_nand_dma_irq, (void *) info);
+
+ /* Turn off the DMA channel first */
+ disable_dma(CH_NFC);
+ return 0;
+}
+
+/*
+ * BF5XX NFC hardware initialization
+ * - pin mux setup
+ * - clear interrupt status
+ */
+static int bf5xx_nand_hw_init(struct bf5xx_nand_info *info)
+{
+ int err = 0;
+ unsigned short val;
+ struct bf5xx_nand_platform *plat = info->platform;
+
+ /* setup NFC_CTL register */
+ dev_info(info->device,
+ "page_size=%d, data_width=%d, wr_dly=%d, rd_dly=%d\n",
+ (plat->page_size ? 512 : 256),
+ (plat->data_width ? 16 : 8),
+ plat->wr_dly, plat->rd_dly);
+
+ val = (plat->page_size << NFC_PG_SIZE_OFFSET) |
+ (plat->data_width << NFC_NWIDTH_OFFSET) |
+ (plat->rd_dly << NFC_RDDLY_OFFSET) |
+ (plat->rd_dly << NFC_WRDLY_OFFSET);
+ dev_dbg(info->device, "NFC_CTL is 0x%04x\n", val);
+
+ bfin_write_NFC_CTL(val);
+ SSYNC();
+
+ /* clear interrupt status */
+ bfin_write_NFC_IRQMASK(0x0);
+ SSYNC();
+ val = bfin_read_NFC_IRQSTAT();
+ bfin_write_NFC_IRQSTAT(val);
+ SSYNC();
+
+ if (peripheral_request_list(bfin_nfc_pin_req, DRV_NAME)) {
+ printk(KERN_ERR DRV_NAME
+ ": Requesting Peripherals failed\n");
+ return -EFAULT;
+ }
+
+ /* DMA initialization */
+ if (bf5xx_nand_dma_init(info))
+ err = -ENXIO;
+
+ return err;
+}
+
+/*
+ * Device management interface
+ */
+static int bf5xx_nand_add_partition(struct bf5xx_nand_info *info)
+{
+ struct mtd_info *mtd = &info->mtd;
+
+#ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *parts = info->platform->partitions;
+ int nr = info->platform->nr_partitions;
+
+ return add_mtd_partitions(mtd, parts, nr);
+#else
+ return add_mtd_device(mtd);
+#endif
+}
+
+static int bf5xx_nand_remove(struct platform_device *pdev)
+{
+ struct bf5xx_nand_info *info = to_nand_info(pdev);
+ struct mtd_info *mtd = NULL;
+
+ platform_set_drvdata(pdev, NULL);
+
+ /* first thing we need to do is release all our mtds
+ * and their partitions, then go through freeing the
+ * resources used
+ */
+ mtd = &info->mtd;
+ if (mtd) {
+ nand_release(mtd);
+ kfree(mtd);
+ }
+
+ peripheral_free_list(bfin_nfc_pin_req);
+
+ /* free the common resources */
+ kfree(info);
+
+ return 0;
+}
+
+/*
+ * bf5xx_nand_probe
+ *
+ * called by device layer when it finds a device matching
+ * one our driver can handled. This code checks to see if
+ * it can allocate all necessary resources then calls the
+ * nand layer to look for devices
+ */
+static int bf5xx_nand_probe(struct platform_device *pdev)
+{
+ struct bf5xx_nand_platform *plat = to_nand_plat(pdev);
+ struct bf5xx_nand_info *info = NULL;
+ struct nand_chip *chip = NULL;
+ struct mtd_info *mtd = NULL;
+ int err = 0;
+
+ dev_dbg(&pdev->dev, "(%p)\n", pdev);
+
+ if (!plat) {
+ dev_err(&pdev->dev, "no platform specific information\n");
+ goto exit_error;
+ }
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL) {
+ dev_err(&pdev->dev, "no memory for flash info\n");
+ err = -ENOMEM;
+ goto exit_error;
+ }
+
+ platform_set_drvdata(pdev, info);
+
+ spin_lock_init(&info->controller.lock);
+ init_waitqueue_head(&info->controller.wq);
+
+ info->device = &pdev->dev;
+ info->platform = plat;
+
+ /* initialise chip data struct */
+ chip = &info->chip;
+
+ if (plat->data_width)
+ chip->options |= NAND_BUSWIDTH_16;
+
+ chip->options |= NAND_CACHEPRG | NAND_SKIP_BBTSCAN;
+
+ chip->read_buf = (plat->data_width) ?
+ bf5xx_nand_read_buf16 : bf5xx_nand_read_buf;
+ chip->write_buf = (plat->data_width) ?
+ bf5xx_nand_write_buf16 : bf5xx_nand_write_buf;
+
+ chip->read_byte = bf5xx_nand_read_byte;
+
+ chip->cmd_ctrl = bf5xx_nand_hwcontrol;
+ chip->dev_ready = bf5xx_nand_devready;
+
+ chip->priv = &info->mtd;
+ chip->controller = &info->controller;
+
+ chip->IO_ADDR_R = (void __iomem *) NFC_READ;
+ chip->IO_ADDR_W = (void __iomem *) NFC_DATA_WR;
+
+ chip->chip_delay = 0;
+
+ /* initialise mtd info data struct */
+ mtd = &info->mtd;
+ mtd->priv = chip;
+ mtd->owner = THIS_MODULE;
+
+ /* initialise the hardware */
+ err = bf5xx_nand_hw_init(info);
+ if (err != 0)
+ goto exit_error;
+
+ /* setup hardware ECC data struct */
+ if (hardware_ecc) {
+ if (plat->page_size == NFC_PG_SIZE_256) {
+ chip->ecc.bytes = 3;
+ chip->ecc.size = 256;
+ } else if (plat->page_size == NFC_PG_SIZE_512) {
+ chip->ecc.bytes = 6;
+ chip->ecc.size = 512;
+ }
+
+ chip->read_buf = bf5xx_nand_dma_read_buf;
+ chip->write_buf = bf5xx_nand_dma_write_buf;
+ chip->ecc.calculate = bf5xx_nand_calculate_ecc;
+ chip->ecc.correct = bf5xx_nand_correct_data;
+ chip->ecc.mode = NAND_ECC_HW;
+ chip->ecc.hwctl = bf5xx_nand_enable_hwecc;
+ } else {
+ chip->ecc.mode = NAND_ECC_SOFT;
+ }
+
+ /* scan hardware nand chip and setup mtd info data struct */
+ if (nand_scan(mtd, 1)) {
+ err = -ENXIO;
+ goto exit_error;
+ }
+
+ /* add NAND partition */
+ bf5xx_nand_add_partition(info);
+
+ dev_dbg(&pdev->dev, "initialised ok\n");
+ return 0;
+
+exit_error:
+ bf5xx_nand_remove(pdev);
+
+ if (err == 0)
+ err = -EINVAL;
+ return err;
+}
+
+/* PM Support */
+#ifdef CONFIG_PM
+
+static int bf5xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
+{
+ struct bf5xx_nand_info *info = platform_get_drvdata(dev);
+
+ return 0;
+}
+
+static int bf5xx_nand_resume(struct platform_device *dev)
+{
+ struct bf5xx_nand_info *info = platform_get_drvdata(dev);
+
+ if (info)
+ bf5xx_nand_hw_init(info);
+
+ return 0;
+}
+
+#else
+#define bf5xx_nand_suspend NULL
+#define bf5xx_nand_resume NULL
+#endif
+
+/* driver device registration */
+static struct platform_driver bf5xx_nand_driver = {
+ .probe = bf5xx_nand_probe,
+ .remove = bf5xx_nand_remove,
+ .suspend = bf5xx_nand_suspend,
+ .resume = bf5xx_nand_resume,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init bf5xx_nand_init(void)
+{
+ printk(KERN_INFO "%s, Version %s (c) 2007 Analog Devices, Inc.\n",
+ DRV_DESC, DRV_VERSION);
+
+ return platform_driver_register(&bf5xx_nand_driver);
+}
+
+static void __exit bf5xx_nand_exit(void)
+{
+ platform_driver_unregister(&bf5xx_nand_driver);
+}
+
+module_init(bf5xx_nand_init);
+module_exit(bf5xx_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index 6f32a35eb10..1e811715211 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -80,7 +80,7 @@ module_param(regdebug, int, 0644);
static int checkecc = 1;
module_param(checkecc, int, 0644);
-static int numtimings;
+static unsigned int numtimings;
static int timing[3];
module_param_array(timing, int, &numtimings, 0644);
@@ -623,6 +623,11 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
uint32_t ctrl;
int err = 0;
+ /* Very old versions shared the same PCI ident for all three
+ functions on the chip. Verify the class too... */
+ if ((pdev->class >> 8) != PCI_CLASS_MEMORY_FLASH)
+ return -ENODEV;
+
err = pci_enable_device(pdev);
if (err)
return err;
@@ -816,21 +821,57 @@ static void __devexit cafe_nand_remove(struct pci_dev *pdev)
}
static struct pci_device_id cafe_nand_tbl[] = {
- { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 },
- { 0, }
+ { 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID },
+ { }
};
MODULE_DEVICE_TABLE(pci, cafe_nand_tbl);
+static int cafe_nand_resume(struct pci_dev *pdev)
+{
+ uint32_t ctrl;
+ struct mtd_info *mtd = pci_get_drvdata(pdev);
+ struct cafe_priv *cafe = mtd->priv;
+
+ /* Start off by resetting the NAND controller completely */
+ cafe_writel(cafe, 1, NAND_RESET);
+ cafe_writel(cafe, 0, NAND_RESET);
+ cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK);
+
+ /* Restore timing configuration */
+ cafe_writel(cafe, timing[0], NAND_TIMING1);
+ cafe_writel(cafe, timing[1], NAND_TIMING2);
+ cafe_writel(cafe, timing[2], NAND_TIMING3);
+
+ /* Disable master reset, enable NAND clock */
+ ctrl = cafe_readl(cafe, GLOBAL_CTRL);
+ ctrl &= 0xffffeff0;
+ ctrl |= 0x00007000;
+ cafe_writel(cafe, ctrl | 0x05, GLOBAL_CTRL);
+ cafe_writel(cafe, ctrl | 0x0a, GLOBAL_CTRL);
+ cafe_writel(cafe, 0, NAND_DMA_CTRL);
+ cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
+ cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
+
+ /* Set up DMA address */
+ cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
+ if (sizeof(cafe->dmaaddr) > 4)
+ /* Shift in two parts to shut the compiler up */
+ cafe_writel(cafe, (cafe->dmaaddr >> 16) >> 16, NAND_DMA_ADDR1);
+ else
+ cafe_writel(cafe, 0, NAND_DMA_ADDR1);
+
+ /* Enable NAND IRQ in global IRQ mask register */
+ cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
+ return 0;
+}
+
static struct pci_driver cafe_nand_pci_driver = {
.name = "CAFÉ NAND",
.id_table = cafe_nand_tbl,
.probe = cafe_nand_probe,
.remove = __devexit_p(cafe_nand_remove),
-#ifdef CONFIG_PMx
- .suspend = cafe_nand_suspend,
.resume = cafe_nand_resume,
-#endif
};
static int cafe_nand_init(void)
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index e96259f22cc..0e72153b329 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -56,8 +56,6 @@ static unsigned long __initdata doc_locations[] = {
#endif /* CONFIG_MTD_DOCPROBE_HIGH */
#elif defined(__PPC__)
0xe4000000,
-#elif defined(CONFIG_MOMENCO_OCELOT_G)
- 0xff000000,
#else
#warning Unknown architecture for DiskOnChip. No default probe locations defined
#endif
@@ -222,7 +220,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
}
}
/* If the parity is wrong, no rescue possible */
- return parity ? -1 : nerr;
+ return parity ? -EBADMSG : nerr;
}
static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
@@ -1036,7 +1034,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
else
WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
- if (no_ecc_failures && (ret == -1)) {
+ if (no_ecc_failures && (ret == -EBADMSG)) {
printk(KERN_ERR "suppressing ECC failure\n");
ret = 0;
}
diff --git a/drivers/mtd/nand/excite_nandflash.c b/drivers/mtd/nand/excite_nandflash.c
index 7e9afc4c775..bed87290dec 100644
--- a/drivers/mtd/nand/excite_nandflash.c
+++ b/drivers/mtd/nand/excite_nandflash.c
@@ -27,7 +27,6 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/kernel.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 24ac6778b1a..e29c1da7f56 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -7,7 +7,7 @@
* Basic support for AG-AND chips is provided.
*
* Additional technical information is available on
- * http://www.linux-mtd.infradead.org/tech/nand.html
+ * http://www.linux-mtd.infradead.org/doc/nand.html
*
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
* 2002-2006 Thomas Gleixner (tglx@linutronix.de)
@@ -789,7 +789,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
int stat;
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
- if (stat == -1)
+ if (stat < 0)
mtd->ecc_stats.failed++;
else
mtd->ecc_stats.corrected += stat;
@@ -833,7 +833,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
int stat;
stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
- if (stat == -1)
+ if (stat < 0)
mtd->ecc_stats.failed++;
else
mtd->ecc_stats.corrected += stat;
@@ -874,7 +874,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
chip->read_buf(mtd, oob, eccbytes);
stat = chip->ecc.correct(mtd, p, oob, NULL);
- if (stat == -1)
+ if (stat < 0)
mtd->ecc_stats.failed++;
else
mtd->ecc_stats.corrected += stat;
@@ -2069,13 +2069,14 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
erase_exit:
ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
- /* Do call back function */
- if (!ret)
- mtd_erase_callback(instr);
/* Deselect and wake up anyone waiting on the device */
nand_release_device(mtd);
+ /* Do call back function */
+ if (!ret)
+ mtd_erase_callback(instr);
+
/*
* If BBT requires refresh and erase was successful, rewrite any
* selected bad block tables
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index fde593e5e63..9003a135e05 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -189,7 +189,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat,
if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1)
return 1;
- return -1;
+ return -EBADMSG;
}
EXPORT_SYMBOL(nand_correct_data);
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 2fc674a190c..a3e3ab0185d 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -141,6 +141,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_STMICRO, "ST Micro"},
{NAND_MFR_HYNIX, "Hynix"},
{NAND_MFR_MICRON, "Micron"},
+ {NAND_MFR_AMD, "AMD"},
{0x0, "Unknown"}
};
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 205df0f771f..10490b48d9f 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -511,7 +511,7 @@ static int init_nandsim(struct mtd_info *mtd)
}
if (ns->options & OPT_SMALLPAGE) {
- if (ns->geom.totsz < (64 << 20)) {
+ if (ns->geom.totsz < (32 << 20)) {
ns->geom.pgaddrbytes = 3;
ns->geom.secaddrbytes = 2;
} else {
@@ -1272,7 +1272,13 @@ static int prog_page(struct nandsim *ns, int num)
mypage = NS_GET_PAGE(ns);
if (mypage->byte == NULL) {
NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
- mypage->byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
+ /*
+ * We allocate memory with GFP_NOFS because a flash FS may
+ * utilize this. If it is holding an FS lock, then gets here,
+ * then kmalloc runs writeback which goes to the FS again
+ * and deadlocks. This was seen in practice.
+ */
+ mypage->byte = kmalloc(ns->geom.pgszoob, GFP_NOFS);
if (mypage->byte == NULL) {
NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
return -1;
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index fd7a8d5ba29..1c0e89f00e8 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -24,7 +24,11 @@
#include <linux/platform_device.h>
#include <asm/io.h>
+#ifdef CONFIG_40x
+#include <asm/ibm405.h>
+#else
#include <asm/ibm44x.h>
+#endif
struct ndfc_nand_mtd {
struct mtd_info mtd;
@@ -230,7 +234,11 @@ static int ndfc_nand_probe(struct platform_device *pdev)
struct ndfc_controller *ndfc = &ndfc_ctrl;
unsigned long long phys = settings->ndfc_erpn | res->start;
+#ifndef CONFIG_PHYS_64BIT
+ ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1);
+#else
ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1);
+#endif
if (!ndfc->ndfcbase) {
printk(KERN_ERR "NDFC: ioremap failed\n");
return -EIO;
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 5fac4c421a2..66f76e9618d 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -60,8 +60,8 @@
#include <asm/io.h>
-#include <asm/arch/regs-nand.h>
-#include <asm/arch/nand.h>
+#include <asm/plat-s3c/regs-nand.h>
+#include <asm/plat-s3c/nand.h>
#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
static int hardware_ecc = 1;
@@ -488,12 +488,24 @@ static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
readsb(this->IO_ADDR_R, buf, len);
}
+static void s3c2440_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ readsl(info->regs + S3C2440_NFDATA, buf, len / 4);
+}
+
static void s3c2410_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
writesb(this->IO_ADDR_W, buf, len);
}
+static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ writesl(info->regs + S3C2440_NFDATA, buf, len / 4);
+}
+
/* device management functions */
static int s3c2410_nand_remove(struct platform_device *pdev)
@@ -604,6 +616,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
info->sel_bit = S3C2440_NFCONT_nFCE;
chip->cmd_ctrl = s3c2440_nand_hwcontrol;
chip->dev_ready = s3c2440_nand_devready;
+ chip->read_buf = s3c2440_nand_read_buf;
+ chip->write_buf = s3c2440_nand_write_buf;
break;
case TYPE_S3C2412:
@@ -696,7 +710,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev,
info->clk = clk_get(&pdev->dev, "nand");
if (IS_ERR(info->clk)) {
- dev_err(&pdev->dev, "failed to get clock");
+ dev_err(&pdev->dev, "failed to get clock\n");
err = -ENOENT;
goto exit_error;
}
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index c257d397d08..cb41cbca64f 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -40,4 +40,27 @@ config MTD_ONENAND_OTP
OTP block is fully-guaranteed to be a valid block.
+config MTD_ONENAND_2X_PROGRAM
+ bool "OneNAND 2X program support"
+ help
+ The 2X Program is an extension of Program Operation.
+ Since the device is equipped with two DataRAMs, and two-plane NAND
+ Flash memory array, these two component enables simultaneous program
+ of 4KiB. Plane1 has only even blocks such as block0, block2, block4
+ while Plane2 has only odd blocks such as block1, block3, block5.
+ So MTD regards it as 4KiB page size and 256KiB block size
+
+ Now the following chips support it. (KFXXX16Q2M)
+ Demux: KFG2G16Q2M, KFH4G16Q2M, KFW8G16Q2M,
+ Mux: KFM2G16Q2M, KFN4G16Q2M,
+
+ And more recent chips
+
+config MTD_ONENAND_SIM
+ tristate "OneNAND simulator support"
+ depends on MTD_PARTITIONS
+ help
+ The simulator may simulate various OneNAND flash chips for the
+ OneNAND MTD layer.
+
endif # MTD_ONENAND
diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile
index 269cfe46734..4d2eacfd7e1 100644
--- a/drivers/mtd/onenand/Makefile
+++ b/drivers/mtd/onenand/Makefile
@@ -8,4 +8,7 @@ obj-$(CONFIG_MTD_ONENAND) += onenand.o
# Board specific.
obj-$(CONFIG_MTD_ONENAND_GENERIC) += generic.o
+# Simulator
+obj-$(CONFIG_MTD_ONENAND_SIM) += onenand_sim.o
+
onenand-objs = onenand_base.o onenand_bbt.o
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 0537fac8de7..1b0b3201141 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -206,6 +206,15 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
default:
block = (int) (addr >> this->erase_shift);
page = (int) (addr >> this->page_shift);
+
+ if (ONENAND_IS_2PLANE(this)) {
+ /* Make the even block number */
+ block &= ~1;
+ /* Is it the odd plane? */
+ if (addr & this->writesize)
+ block++;
+ page >>= 1;
+ }
page &= this->page_mask;
break;
}
@@ -216,8 +225,12 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
value = onenand_bufferram_address(this, block);
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
- /* Switch to the next data buffer */
- ONENAND_SET_NEXT_BUFFERRAM(this);
+ if (ONENAND_IS_2PLANE(this))
+ /* It is always BufferRAM0 */
+ ONENAND_SET_BUFFERRAM0(this);
+ else
+ /* Switch to the next data buffer */
+ ONENAND_SET_NEXT_BUFFERRAM(this);
return 0;
}
@@ -247,6 +260,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
break;
default:
+ if (ONENAND_IS_2PLANE(this) && cmd == ONENAND_CMD_PROG)
+ cmd = ONENAND_CMD_2X_PROG;
dataram = ONENAND_CURRENT_BUFFERRAM(this);
break;
}
@@ -312,18 +327,20 @@ static int onenand_wait(struct mtd_info *mtd, int state)
printk(KERN_ERR "onenand_wait: controller error = 0x%04x\n", ctrl);
if (ctrl & ONENAND_CTRL_LOCK)
printk(KERN_ERR "onenand_wait: it's locked error.\n");
- return ctrl;
+ return -EIO;
}
if (interrupt & ONENAND_INT_READ) {
int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
if (ecc) {
- printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc);
if (ecc & ONENAND_ECC_2BIT_ALL) {
+ printk(KERN_ERR "onenand_wait: ECC error = 0x%04x\n", ecc);
mtd->ecc_stats.failed++;
- return ecc;
- } else if (ecc & ONENAND_ECC_1BIT_ALL)
+ return -EBADMSG;
+ } else if (ecc & ONENAND_ECC_1BIT_ALL) {
+ printk(KERN_INFO "onenand_wait: correctable ECC error = 0x%04x\n", ecc);
mtd->ecc_stats.corrected++;
+ }
}
} else if (state == FL_READING) {
printk(KERN_ERR "onenand_wait: read timeout! ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
@@ -342,7 +359,7 @@ static int onenand_wait(struct mtd_info *mtd, int state)
*/
static irqreturn_t onenand_interrupt(int irq, void *data)
{
- struct onenand_chip *this = (struct onenand_chip *) data;
+ struct onenand_chip *this = data;
/* To handle shared interrupt */
if (!this->complete.done)
@@ -445,8 +462,9 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)
struct onenand_chip *this = mtd->priv;
if (ONENAND_CURRENT_BUFFERRAM(this)) {
+ /* Note: the 'this->writesize' is a real page size */
if (area == ONENAND_DATARAM)
- return mtd->writesize;
+ return this->writesize;
if (area == ONENAND_SPARERAM)
return mtd->oobsize;
}
@@ -572,6 +590,30 @@ static int onenand_write_bufferram(struct mtd_info *mtd, int area,
}
/**
+ * onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode
+ * @param mtd MTD data structure
+ * @param addr address to check
+ * @return blockpage address
+ *
+ * Get blockpage address at 2x program mode
+ */
+static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr)
+{
+ struct onenand_chip *this = mtd->priv;
+ int blockpage, block, page;
+
+ /* Calculate the even block number */
+ block = (int) (addr >> this->erase_shift) & ~1;
+ /* Is it the odd plane? */
+ if (addr & this->writesize)
+ block++;
+ page = (int) (addr >> (this->page_shift + 1)) & this->page_mask;
+ blockpage = (block << 7) | page;
+
+ return blockpage;
+}
+
+/**
* onenand_check_bufferram - [GENERIC] Check BufferRAM information
* @param mtd MTD data structure
* @param addr address to check
@@ -585,7 +627,10 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
int blockpage, found = 0;
unsigned int i;
- blockpage = (int) (addr >> this->page_shift);
+ if (ONENAND_IS_2PLANE(this))
+ blockpage = onenand_get_2x_blockpage(mtd, addr);
+ else
+ blockpage = (int) (addr >> this->page_shift);
/* Is there valid data? */
i = ONENAND_CURRENT_BUFFERRAM(this);
@@ -625,7 +670,10 @@ static void onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
int blockpage;
unsigned int i;
- blockpage = (int) (addr >> this->page_shift);
+ if (ONENAND_IS_2PLANE(this))
+ blockpage = onenand_get_2x_blockpage(mtd, addr);
+ else
+ blockpage = (int) (addr >> this->page_shift);
/* Invalidate another BufferRAM */
i = ONENAND_NEXT_BUFFERRAM(this);
@@ -717,36 +765,86 @@ static void onenand_release_device(struct mtd_info *mtd)
}
/**
- * onenand_read - [MTD Interface] Read data from flash
+ * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
+ * @param mtd MTD device structure
+ * @param buf destination address
+ * @param column oob offset to read from
+ * @param thislen oob length to read
+ */
+static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column,
+ int thislen)
+{
+ struct onenand_chip *this = mtd->priv;
+ struct nand_oobfree *free;
+ int readcol = column;
+ int readend = column + thislen;
+ int lastgap = 0;
+ unsigned int i;
+ uint8_t *oob_buf = this->oob_buf;
+
+ free = this->ecclayout->oobfree;
+ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+ if (readcol >= lastgap)
+ readcol += free->offset - lastgap;
+ if (readend >= lastgap)
+ readend += free->offset - lastgap;
+ lastgap = free->offset + free->length;
+ }
+ this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
+ free = this->ecclayout->oobfree;
+ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+ int free_end = free->offset + free->length;
+ if (free->offset < readend && free_end > readcol) {
+ int st = max_t(int,free->offset,readcol);
+ int ed = min_t(int,free_end,readend);
+ int n = ed - st;
+ memcpy(buf, oob_buf + st, n);
+ buf += n;
+ } else if (column == 0)
+ break;
+ }
+ return 0;
+}
+
+/**
+ * onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
* @param mtd MTD device structure
* @param from offset to read from
- * @param len number of bytes to read
- * @param retlen pointer to variable to store the number of read bytes
- * @param buf the databuffer to put data
+ * @param ops: oob operation description structure
*
- * Read with ecc
-*/
-static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
+ * OneNAND read main and/or out-of-band data
+ */
+static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
{
struct onenand_chip *this = mtd->priv;
struct mtd_ecc_stats stats;
- int read = 0, column;
- int thislen;
+ size_t len = ops->len;
+ size_t ooblen = ops->ooblen;
+ u_char *buf = ops->datbuf;
+ u_char *oobbuf = ops->oobbuf;
+ int read = 0, column, thislen;
+ int oobread = 0, oobcolumn, thisooblen, oobsize;
int ret = 0, boundary = 0;
+ int writesize = this->writesize;
+
+ DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+ if (ops->mode == MTD_OOB_AUTO)
+ oobsize = this->ecclayout->oobavail;
+ else
+ oobsize = mtd->oobsize;
+
+ oobcolumn = from & (mtd->oobsize - 1);
/* Do not allow reads past end of device */
if ((from + len) > mtd->size) {
- printk(KERN_ERR "onenand_read: Attempt read beyond end of device\n");
- *retlen = 0;
+ printk(KERN_ERR "onenand_read_ops_nolock: Attempt read beyond end of device\n");
+ ops->retlen = 0;
+ ops->oobretlen = 0;
return -EINVAL;
}
- /* Grab the lock and see if the device is available */
- onenand_get_device(mtd, FL_READING);
-
stats = mtd->ecc_stats;
/* Read-while-load method */
@@ -754,22 +852,22 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
/* Do first load to bufferRAM */
if (read < len) {
if (!onenand_check_bufferram(mtd, from)) {
- this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
+ this->command(mtd, ONENAND_CMD_READ, from, writesize);
ret = this->wait(mtd, FL_READING);
onenand_update_bufferram(mtd, from, !ret);
}
}
- thislen = min_t(int, mtd->writesize, len - read);
- column = from & (mtd->writesize - 1);
- if (column + thislen > mtd->writesize)
- thislen = mtd->writesize - column;
+ thislen = min_t(int, writesize, len - read);
+ column = from & (writesize - 1);
+ if (column + thislen > writesize)
+ thislen = writesize - column;
while (!ret) {
/* If there is more to load then start next load */
from += thislen;
if (read + thislen < len) {
- this->command(mtd, ONENAND_CMD_READ, from, mtd->writesize);
+ this->command(mtd, ONENAND_CMD_READ, from, writesize);
/*
* Chip boundary handling in DDP
* Now we issued chip 1 read and pointed chip 1
@@ -785,6 +883,21 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
}
/* While load is going, read from last bufferRAM */
this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
+
+ /* Read oob area if needed */
+ if (oobbuf) {
+ thisooblen = oobsize - oobcolumn;
+ thisooblen = min_t(int, thisooblen, ooblen - oobread);
+
+ if (ops->mode == MTD_OOB_AUTO)
+ onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen);
+ else
+ this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);
+ oobread += thisooblen;
+ oobbuf += thisooblen;
+ oobcolumn = 0;
+ }
+
/* See if we are done */
read += thislen;
if (read == len)
@@ -794,7 +907,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
ONENAND_SET_NEXT_BUFFERRAM(this);
buf += thislen;
- thislen = min_t(int, mtd->writesize, len - read);
+ thislen = min_t(int, writesize, len - read);
column = 0;
cond_resched();
/* Now wait for load */
@@ -802,15 +915,13 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
onenand_update_bufferram(mtd, from, !ret);
}
- /* Deselect and wake up anyone waiting on the device */
- onenand_release_device(mtd);
-
/*
* Return success, if no ECC failures, else -EBADMSG
* fs driver will take care of that, because
* retlen == desired len and result == -EBADMSG
*/
- *retlen = read;
+ ops->retlen = read;
+ ops->oobretlen = oobread;
if (mtd->ecc_stats.failed - stats.failed)
return -EBADMSG;
@@ -822,69 +933,29 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
}
/**
- * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer
- * @param mtd MTD device structure
- * @param buf destination address
- * @param column oob offset to read from
- * @param thislen oob length to read
- */
-static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column,
- int thislen)
-{
- struct onenand_chip *this = mtd->priv;
- struct nand_oobfree *free;
- int readcol = column;
- int readend = column + thislen;
- int lastgap = 0;
- unsigned int i;
- uint8_t *oob_buf = this->oob_buf;
-
- free = this->ecclayout->oobfree;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
- if (readcol >= lastgap)
- readcol += free->offset - lastgap;
- if (readend >= lastgap)
- readend += free->offset - lastgap;
- lastgap = free->offset + free->length;
- }
- this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);
- free = this->ecclayout->oobfree;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
- int free_end = free->offset + free->length;
- if (free->offset < readend && free_end > readcol) {
- int st = max_t(int,free->offset,readcol);
- int ed = min_t(int,free_end,readend);
- int n = ed - st;
- memcpy(buf, oob_buf + st, n);
- buf += n;
- } else if (column == 0)
- break;
- }
- return 0;
-}
-
-/**
- * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band
+ * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band
* @param mtd MTD device structure
* @param from offset to read from
- * @param len number of bytes to read
- * @param retlen pointer to variable to store the number of read bytes
- * @param buf the databuffer to put data
- * @param mode operation mode
+ * @param ops: oob operation description structure
*
* OneNAND read out-of-band data from the spare area
*/
-static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf, mtd_oob_mode_t mode)
+static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
+ struct mtd_oob_ops *ops)
{
struct onenand_chip *this = mtd->priv;
int read = 0, thislen, column, oobsize;
+ size_t len = ops->ooblen;
+ mtd_oob_mode_t mode = ops->mode;
+ u_char *buf = ops->oobbuf;
int ret = 0;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+ from += ops->ooboffs;
+
+ DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
/* Initialize return length value */
- *retlen = 0;
+ ops->oobretlen = 0;
if (mode == MTD_OOB_AUTO)
oobsize = this->ecclayout->oobavail;
@@ -894,7 +965,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
column = from & (mtd->oobsize - 1);
if (unlikely(column >= oobsize)) {
- printk(KERN_ERR "onenand_read_oob: Attempted to start read outside oob\n");
+ printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n");
return -EINVAL;
}
@@ -902,13 +973,10 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
if (unlikely(from >= mtd->size ||
column + len > ((mtd->size >> this->page_shift) -
(from >> this->page_shift)) * oobsize)) {
- printk(KERN_ERR "onenand_read_oob: Attempted to read beyond end of device\n");
+ printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n");
return -EINVAL;
}
- /* Grab the lock and see if the device is available */
- onenand_get_device(mtd, FL_READING);
-
while (read < len) {
cond_resched();
@@ -928,7 +996,7 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
if (ret) {
- printk(KERN_ERR "onenand_read_oob: read failed = 0x%x\n", ret);
+ printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
break;
}
@@ -947,22 +1015,52 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
}
}
- /* Deselect and wake up anyone waiting on the device */
+ ops->oobretlen = read;
+ return ret;
+}
+
+/**
+ * onenand_read - [MTD Interface] Read data from flash
+ * @param mtd MTD device structure
+ * @param from offset to read from
+ * @param len number of bytes to read
+ * @param retlen pointer to variable to store the number of read bytes
+ * @param buf the databuffer to put data
+ *
+ * Read with ecc
+*/
+static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct mtd_oob_ops ops = {
+ .len = len,
+ .ooblen = 0,
+ .datbuf = buf,
+ .oobbuf = NULL,
+ };
+ int ret;
+
+ onenand_get_device(mtd, FL_READING);
+ ret = onenand_read_ops_nolock(mtd, from, &ops);
onenand_release_device(mtd);
- *retlen = read;
+ *retlen = ops.retlen;
return ret;
}
/**
- * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band
+ * onenand_read_oob - [MTD Interface] Read main and/or out-of-band
* @param mtd: MTD device structure
* @param from: offset to read from
* @param ops: oob operation description structure
+
+ * Read main and/or out-of-band
*/
static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
+ int ret;
+
switch (ops->mode) {
case MTD_OOB_PLACE:
case MTD_OOB_AUTO:
@@ -972,8 +1070,15 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
default:
return -EINVAL;
}
- return onenand_do_read_oob(mtd, from + ops->ooboffs, ops->ooblen,
- &ops->oobretlen, ops->oobbuf, ops->mode);
+
+ onenand_get_device(mtd, FL_READING);
+ if (ops->datbuf)
+ ret = onenand_read_ops_nolock(mtd, from, ops);
+ else
+ ret = onenand_read_oob_nolock(mtd, from, ops);
+ onenand_release_device(mtd);
+
+ return ret;
}
/**
@@ -1079,7 +1184,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
/* Read more? */
if (read < len) {
/* Update Page size */
- from += mtd->writesize;
+ from += this->writesize;
column = 0;
}
}
@@ -1097,7 +1202,6 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
* @param mtd MTD device structure
* @param buf the databuffer to verify
* @param to offset to read from
- *
*/
static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to)
{
@@ -1125,7 +1229,6 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
* @param buf the databuffer to verify
* @param addr offset to read from
* @param len number of bytes to read and compare
- *
*/
static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len)
{
@@ -1135,12 +1238,12 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
int thislen, column;
while (len != 0) {
- thislen = min_t(int, mtd->writesize, len);
- column = addr & (mtd->writesize - 1);
- if (column + thislen > mtd->writesize)
- thislen = mtd->writesize - column;
+ thislen = min_t(int, this->writesize, len);
+ column = addr & (this->writesize - 1);
+ if (column + thislen > this->writesize)
+ thislen = this->writesize - column;
- this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize);
+ this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
onenand_update_bufferram(mtd, addr, 0);
@@ -1171,50 +1274,101 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
#define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0)
/**
- * onenand_write - [MTD Interface] write buffer to FLASH
+ * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
+ * @param mtd MTD device structure
+ * @param oob_buf oob buffer
+ * @param buf source address
+ * @param column oob offset to write to
+ * @param thislen oob length to write
+ */
+static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
+ const u_char *buf, int column, int thislen)
+{
+ struct onenand_chip *this = mtd->priv;
+ struct nand_oobfree *free;
+ int writecol = column;
+ int writeend = column + thislen;
+ int lastgap = 0;
+ unsigned int i;
+
+ free = this->ecclayout->oobfree;
+ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+ if (writecol >= lastgap)
+ writecol += free->offset - lastgap;
+ if (writeend >= lastgap)
+ writeend += free->offset - lastgap;
+ lastgap = free->offset + free->length;
+ }
+ free = this->ecclayout->oobfree;
+ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
+ int free_end = free->offset + free->length;
+ if (free->offset < writeend && free_end > writecol) {
+ int st = max_t(int,free->offset,writecol);
+ int ed = min_t(int,free_end,writeend);
+ int n = ed - st;
+ memcpy(oob_buf + st, buf, n);
+ buf += n;
+ } else if (column == 0)
+ break;
+ }
+ return 0;
+}
+
+/**
+ * onenand_write_ops_nolock - [OneNAND Interface] write main and/or out-of-band
* @param mtd MTD device structure
* @param to offset to write to
- * @param len number of bytes to write
- * @param retlen pointer to variable to store the number of written bytes
- * @param buf the data to write
+ * @param ops oob operation description structure
*
- * Write with ECC
+ * Write main and/or oob with ECC
*/
-static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
+static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
{
struct onenand_chip *this = mtd->priv;
- int written = 0;
+ int written = 0, column, thislen, subpage;
+ int oobwritten = 0, oobcolumn, thisooblen, oobsize;
+ size_t len = ops->len;
+ size_t ooblen = ops->ooblen;
+ const u_char *buf = ops->datbuf;
+ const u_char *oob = ops->oobbuf;
+ u_char *oobbuf;
int ret = 0;
- int column, subpage;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+ DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
/* Initialize retlen, in case of early exit */
- *retlen = 0;
+ ops->retlen = 0;
+ ops->oobretlen = 0;
/* Do not allow writes past end of device */
if (unlikely((to + len) > mtd->size)) {
- printk(KERN_ERR "onenand_write: Attempt write to past end of device\n");
+ printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");
return -EINVAL;
}
/* Reject writes, which are not page aligned */
if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
- printk(KERN_ERR "onenand_write: Attempt to write not page aligned data\n");
+ printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");
return -EINVAL;
}
- column = to & (mtd->writesize - 1);
+ if (ops->mode == MTD_OOB_AUTO)
+ oobsize = this->ecclayout->oobavail;
+ else
+ oobsize = mtd->oobsize;
- /* Grab the lock and see if the device is available */
- onenand_get_device(mtd, FL_WRITING);
+ oobcolumn = to & (mtd->oobsize - 1);
+
+ column = to & (mtd->writesize - 1);
/* Loop until all data write */
while (written < len) {
- int thislen = min_t(int, mtd->writesize - column, len - written);
u_char *wbuf = (u_char *) buf;
+ thislen = min_t(int, mtd->writesize - column, len - written);
+ thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);
+
cond_resched();
this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);
@@ -1228,7 +1382,25 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
}
this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize);
- this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
+
+ if (oob) {
+ oobbuf = this->oob_buf;
+
+ /* We send data to spare ram with oobsize
+ * to prevent byte access */
+ memset(oobbuf, 0xff, mtd->oobsize);
+ if (ops->mode == MTD_OOB_AUTO)
+ onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
+ else
+ memcpy(oobbuf + oobcolumn, oob, thisooblen);
+
+ oobwritten += thisooblen;
+ oob += thisooblen;
+ oobcolumn = 0;
+ } else
+ oobbuf = (u_char *) ffchars;
+
+ this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);
@@ -1236,16 +1408,20 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
/* In partial page write we don't update bufferram */
onenand_update_bufferram(mtd, to, !ret && !subpage);
+ if (ONENAND_IS_2PLANE(this)) {
+ ONENAND_SET_BUFFERRAM1(this);
+ onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
+ }
if (ret) {
- printk(KERN_ERR "onenand_write: write filaed %d\n", ret);
+ printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);
break;
}
/* Only check verify write turn on */
ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen);
if (ret) {
- printk(KERN_ERR "onenand_write: verify failed %d\n", ret);
+ printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);
break;
}
@@ -1262,54 +1438,14 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
/* Deselect and wake up anyone waiting on the device */
onenand_release_device(mtd);
- *retlen = written;
+ ops->retlen = written;
return ret;
}
-/**
- * onenand_fill_auto_oob - [Internal] oob auto-placement transfer
- * @param mtd MTD device structure
- * @param oob_buf oob buffer
- * @param buf source address
- * @param column oob offset to write to
- * @param thislen oob length to write
- */
-static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
- const u_char *buf, int column, int thislen)
-{
- struct onenand_chip *this = mtd->priv;
- struct nand_oobfree *free;
- int writecol = column;
- int writeend = column + thislen;
- int lastgap = 0;
- unsigned int i;
-
- free = this->ecclayout->oobfree;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
- if (writecol >= lastgap)
- writecol += free->offset - lastgap;
- if (writeend >= lastgap)
- writeend += free->offset - lastgap;
- lastgap = free->offset + free->length;
- }
- free = this->ecclayout->oobfree;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) {
- int free_end = free->offset + free->length;
- if (free->offset < writeend && free_end > writecol) {
- int st = max_t(int,free->offset,writecol);
- int ed = min_t(int,free_end,writeend);
- int n = ed - st;
- memcpy(oob_buf + st, buf, n);
- buf += n;
- } else if (column == 0)
- break;
- }
- return 0;
-}
/**
- * onenand_do_write_oob - [Internal] OneNAND write out-of-band
+ * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band
* @param mtd MTD device structure
* @param to offset to write to
* @param len number of bytes to write
@@ -1319,18 +1455,23 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf,
*
* OneNAND write out-of-band
*/
-static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf, mtd_oob_mode_t mode)
+static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
{
struct onenand_chip *this = mtd->priv;
int column, ret = 0, oobsize;
int written = 0;
u_char *oobbuf;
+ size_t len = ops->ooblen;
+ const u_char *buf = ops->oobbuf;
+ mtd_oob_mode_t mode = ops->mode;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+ to += ops->ooboffs;
+
+ DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
/* Initialize retlen, in case of early exit */
- *retlen = 0;
+ ops->oobretlen = 0;
if (mode == MTD_OOB_AUTO)
oobsize = this->ecclayout->oobavail;
@@ -1340,13 +1481,13 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
column = to & (mtd->oobsize - 1);
if (unlikely(column >= oobsize)) {
- printk(KERN_ERR "onenand_write_oob: Attempted to start write outside oob\n");
+ printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n");
return -EINVAL;
}
/* For compatibility with NAND: Do not allow write past end of page */
if (unlikely(column + len > oobsize)) {
- printk(KERN_ERR "onenand_write_oob: "
+ printk(KERN_ERR "onenand_write_oob_nolock: "
"Attempt to write past end of page\n");
return -EINVAL;
}
@@ -1355,13 +1496,10 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
if (unlikely(to >= mtd->size ||
column + len > ((mtd->size >> this->page_shift) -
(to >> this->page_shift)) * oobsize)) {
- printk(KERN_ERR "onenand_write_oob: Attempted to write past end of device\n");
+ printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n");
return -EINVAL;
}
- /* Grab the lock and see if the device is available */
- onenand_get_device(mtd, FL_WRITING);
-
oobbuf = this->oob_buf;
/* Loop until all data write */
@@ -1384,16 +1522,20 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
onenand_update_bufferram(mtd, to, 0);
+ if (ONENAND_IS_2PLANE(this)) {
+ ONENAND_SET_BUFFERRAM1(this);
+ onenand_update_bufferram(mtd, to + this->writesize, 0);
+ }
ret = this->wait(mtd, FL_WRITING);
if (ret) {
- printk(KERN_ERR "onenand_write_oob: write failed %d\n", ret);
+ printk(KERN_ERR "onenand_write_oob_nolock: write failed %d\n", ret);
break;
}
ret = onenand_verify_oob(mtd, oobbuf, to);
if (ret) {
- printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret);
+ printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret);
break;
}
@@ -1406,11 +1548,37 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
column = 0;
}
- /* Deselect and wake up anyone waiting on the device */
- onenand_release_device(mtd);
+ ops->oobretlen = written;
- *retlen = written;
+ return ret;
+}
+/**
+ * onenand_write - [MTD Interface] write buffer to FLASH
+ * @param mtd MTD device structure
+ * @param to offset to write to
+ * @param len number of bytes to write
+ * @param retlen pointer to variable to store the number of written bytes
+ * @param buf the data to write
+ *
+ * Write with ECC
+ */
+static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct mtd_oob_ops ops = {
+ .len = len,
+ .ooblen = 0,
+ .datbuf = (u_char *) buf,
+ .oobbuf = NULL,
+ };
+ int ret;
+
+ onenand_get_device(mtd, FL_WRITING);
+ ret = onenand_write_ops_nolock(mtd, to, &ops);
+ onenand_release_device(mtd);
+
+ *retlen = ops.retlen;
return ret;
}
@@ -1423,6 +1591,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
+ int ret;
+
switch (ops->mode) {
case MTD_OOB_PLACE:
case MTD_OOB_AUTO:
@@ -1432,21 +1602,27 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to,
default:
return -EINVAL;
}
- return onenand_do_write_oob(mtd, to + ops->ooboffs, ops->ooblen,
- &ops->oobretlen, ops->oobbuf, ops->mode);
+
+ onenand_get_device(mtd, FL_WRITING);
+ if (ops->datbuf)
+ ret = onenand_write_ops_nolock(mtd, to, ops);
+ else
+ ret = onenand_write_oob_nolock(mtd, to, ops);
+ onenand_release_device(mtd);
+
+ return ret;
}
/**
- * onenand_block_checkbad - [GENERIC] Check if a block is marked bad
+ * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad
* @param mtd MTD device structure
* @param ofs offset from device start
- * @param getchip 0, if the chip is already selected
* @param allowbbt 1, if its allowed to access the bbt area
*
* Check, if the block is bad. Either by reading the bad block table or
* calling of the scan function.
*/
-static int onenand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
+static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt)
{
struct onenand_chip *this = mtd->priv;
struct bbm_info *bbm = this->bbm;
@@ -1507,7 +1683,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
cond_resched();
/* Check if we have a bad block, we do not erase bad blocks */
- if (onenand_block_checkbad(mtd, addr, 0, 0)) {
+ if (onenand_block_isbad_nolock(mtd, addr, 0)) {
printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr);
instr->state = MTD_ERASE_FAILED;
goto erase_exit;
@@ -1535,13 +1711,14 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
erase_exit:
ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
- /* Do call back function */
- if (!ret)
- mtd_erase_callback(instr);
/* Deselect and wake up anyone waiting on the device */
onenand_release_device(mtd);
+ /* Do call back function */
+ if (!ret)
+ mtd_erase_callback(instr);
+
return ret;
}
@@ -1571,11 +1748,16 @@ static void onenand_sync(struct mtd_info *mtd)
*/
static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
{
+ int ret;
+
/* Check for invalid offset */
if (ofs > mtd->size)
return -EINVAL;
- return onenand_block_checkbad(mtd, ofs, 1, 0);
+ onenand_get_device(mtd, FL_READING);
+ ret = onenand_block_isbad_nolock(mtd, ofs, 0);
+ onenand_release_device(mtd);
+ return ret;
}
/**
@@ -1591,7 +1773,12 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
struct onenand_chip *this = mtd->priv;
struct bbm_info *bbm = this->bbm;
u_char buf[2] = {0, 0};
- size_t retlen;
+ struct mtd_oob_ops ops = {
+ .mode = MTD_OOB_PLACE,
+ .ooblen = 2,
+ .oobbuf = buf,
+ .ooboffs = 0,
+ };
int block;
/* Get block number */
@@ -1601,7 +1788,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
/* We write two bytes, so we dont have to mess with 16 bit access */
ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
- return onenand_do_write_oob(mtd, ofs , 2, &retlen, buf, MTD_OOB_PLACE);
+ return onenand_write_oob_nolock(mtd, ofs, &ops);
}
/**
@@ -1624,7 +1811,10 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
return ret;
}
- return this->block_markbad(mtd, ofs);
+ onenand_get_device(mtd, FL_WRITING);
+ ret = this->block_markbad(mtd, ofs);
+ onenand_release_device(mtd);
+ return ret;
}
/**
@@ -1715,7 +1905,12 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int
*/
static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
{
- return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
+ int ret;
+
+ onenand_get_device(mtd, FL_LOCKING);
+ ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_LOCK);
+ onenand_release_device(mtd);
+ return ret;
}
/**
@@ -1728,7 +1923,12 @@ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
*/
static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
{
- return onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
+ int ret;
+
+ onenand_get_device(mtd, FL_LOCKING);
+ ret = onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
+ onenand_release_device(mtd);
+ return ret;
}
/**
@@ -1790,7 +1990,7 @@ static int onenand_unlock_all(struct mtd_info *mtd)
loff_t ofs = this->chipsize >> 1;
size_t len = mtd->erasesize;
- onenand_unlock(mtd, ofs, len);
+ onenand_do_lock_cmd(mtd, ofs, len, ONENAND_CMD_UNLOCK);
}
onenand_check_lock_status(this);
@@ -1798,7 +1998,7 @@ static int onenand_unlock_all(struct mtd_info *mtd)
return 0;
}
- onenand_unlock(mtd, 0x0, this->chipsize);
+ onenand_do_lock_cmd(mtd, 0x0, this->chipsize, ONENAND_CMD_UNLOCK);
return 0;
}
@@ -1823,13 +2023,19 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct onenand_chip *this = mtd->priv;
+ struct mtd_oob_ops ops = {
+ .len = len,
+ .ooblen = 0,
+ .datbuf = buf,
+ .oobbuf = NULL,
+ };
int ret;
/* Enter OTP access mode */
this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
this->wait(mtd, FL_OTPING);
- ret = mtd->read(mtd, from, len, retlen, buf);
+ ret = onenand_read_ops_nolock(mtd, from, &ops);
/* Exit OTP access mode */
this->command(mtd, ONENAND_CMD_RESET, 0, 0);
@@ -1841,19 +2047,20 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,
/**
* do_otp_write - [DEFAULT] Write OTP block area
* @param mtd MTD device structure
- * @param from The offset to write
+ * @param to The offset to write
* @param len number of bytes to write
* @param retlen pointer to variable to store the number of write bytes
* @param buf the databuffer to put/get data
*
* Write OTP block area.
*/
-static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len,
+static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, u_char *buf)
{
struct onenand_chip *this = mtd->priv;
unsigned char *pbuf = buf;
int ret;
+ struct mtd_oob_ops ops;
/* Force buffer page aligned */
if (len < mtd->writesize) {
@@ -1867,7 +2074,12 @@ static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len,
this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
this->wait(mtd, FL_OTPING);
- ret = mtd->write(mtd, from, len, retlen, pbuf);
+ ops.len = len;
+ ops.ooblen = 0;
+ ops.datbuf = pbuf;
+ ops.oobbuf = NULL;
+ ret = onenand_write_ops_nolock(mtd, to, &ops);
+ *retlen = ops.retlen;
/* Exit OTP access mode */
this->command(mtd, ONENAND_CMD_RESET, 0, 0);
@@ -1890,13 +2102,21 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct onenand_chip *this = mtd->priv;
+ struct mtd_oob_ops ops = {
+ .mode = MTD_OOB_PLACE,
+ .ooblen = len,
+ .oobbuf = buf,
+ .ooboffs = 0,
+ };
int ret;
/* Enter OTP access mode */
this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);
this->wait(mtd, FL_OTPING);
- ret = onenand_do_write_oob(mtd, from, len, retlen, buf, MTD_OOB_PLACE);
+ ret = onenand_write_oob_nolock(mtd, from, &ops);
+
+ *retlen = ops.oobretlen;
/* Exit OTP access mode */
this->command(mtd, ONENAND_CMD_RESET, 0, 0);
@@ -1943,13 +2163,16 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
if (((mtd->writesize * otp_pages) - (from + len)) < 0)
return 0;
+ onenand_get_device(mtd, FL_OTPING);
while (len > 0 && otp_pages > 0) {
if (!action) { /* OTP Info functions */
struct otp_info *otpinfo;
len -= sizeof(struct otp_info);
- if (len <= 0)
- return -ENOSPC;
+ if (len <= 0) {
+ ret = -ENOSPC;
+ break;
+ }
otpinfo = (struct otp_info *) buf;
otpinfo->start = from;
@@ -1969,13 +2192,14 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
len -= size;
*retlen += size;
- if (ret < 0)
- return ret;
+ if (ret)
+ break;
}
otp_pages--;
}
+ onenand_release_device(mtd);
- return 0;
+ return ret;
}
/**
@@ -2107,6 +2331,7 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
*
* Check and set OneNAND features
* - lock scheme
+ * - two plane
*/
static void onenand_check_features(struct mtd_info *mtd)
{
@@ -2118,19 +2343,35 @@ static void onenand_check_features(struct mtd_info *mtd)
process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
/* Lock scheme */
- if (density >= ONENAND_DEVICE_DENSITY_1Gb) {
+ switch (density) {
+ case ONENAND_DEVICE_DENSITY_4Gb:
+ this->options |= ONENAND_HAS_2PLANE;
+
+ case ONENAND_DEVICE_DENSITY_2Gb:
+ /* 2Gb DDP don't have 2 plane */
+ if (!ONENAND_IS_DDP(this))
+ this->options |= ONENAND_HAS_2PLANE;
+ this->options |= ONENAND_HAS_UNLOCK_ALL;
+
+ case ONENAND_DEVICE_DENSITY_1Gb:
/* A-Die has all block unlock */
- if (process) {
- printk(KERN_DEBUG "Chip support all block unlock\n");
+ if (process)
this->options |= ONENAND_HAS_UNLOCK_ALL;
- }
- } else {
- /* Some OneNAND has continues lock scheme */
- if (!process) {
- printk(KERN_DEBUG "Lock scheme is Continues Lock\n");
+ break;
+
+ default:
+ /* Some OneNAND has continuous lock scheme */
+ if (!process)
this->options |= ONENAND_HAS_CONT_LOCK;
- }
+ break;
}
+
+ if (this->options & ONENAND_HAS_CONT_LOCK)
+ printk(KERN_DEBUG "Lock scheme is Continuous Lock\n");
+ if (this->options & ONENAND_HAS_UNLOCK_ALL)
+ printk(KERN_DEBUG "Chip support all block unlock\n");
+ if (this->options & ONENAND_HAS_2PLANE)
+ printk(KERN_DEBUG "Chip has 2 plane\n");
}
/**
@@ -2154,7 +2395,7 @@ static void onenand_print_device_info(int device, int version)
(16 << density),
vcc ? "2.65/3.3" : "1.8",
device);
- printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version);
+ printk(KERN_INFO "OneNAND version = 0x%04x\n", version);
}
static const struct onenand_manufacturers onenand_manuf_ids[] = {
@@ -2257,6 +2498,8 @@ static int onenand_probe(struct mtd_info *mtd)
this->erase_shift = ffs(mtd->erasesize) - 1;
this->page_shift = ffs(mtd->writesize) - 1;
this->page_mask = (1 << (this->erase_shift - this->page_shift)) - 1;
+ /* It's real page size */
+ this->writesize = mtd->writesize;
/* REVIST: Multichip handling */
@@ -2265,6 +2508,17 @@ static int onenand_probe(struct mtd_info *mtd)
/* Check OneNAND features */
onenand_check_features(mtd);
+ /*
+ * We emulate the 4KiB page and 256KiB erase block size
+ * But oobsize is still 64 bytes.
+ * It is only valid if you turn on 2X program support,
+ * Otherwise it will be ignored by compiler.
+ */
+ if (ONENAND_IS_2PLANE(this)) {
+ mtd->writesize <<= 1;
+ mtd->erasesize <<= 1;
+ }
+
return 0;
}
diff --git a/drivers/mtd/onenand/onenand_sim.c b/drivers/mtd/onenand/onenand_sim.c
new file mode 100644
index 00000000000..d64200b7c94
--- /dev/null
+++ b/drivers/mtd/onenand/onenand_sim.c
@@ -0,0 +1,495 @@
+/*
+ * linux/drivers/mtd/onenand/onenand_sim.c
+ *
+ * The OneNAND simulator
+ *
+ * Copyright © 2005-2007 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/onenand.h>
+
+#include <linux/io.h>
+
+#ifndef CONFIG_ONENAND_SIM_MANUFACTURER
+#define CONFIG_ONENAND_SIM_MANUFACTURER 0xec
+#endif
+#ifndef CONFIG_ONENAND_SIM_DEVICE_ID
+#define CONFIG_ONENAND_SIM_DEVICE_ID 0x04
+#endif
+#ifndef CONFIG_ONENAND_SIM_VERSION_ID
+#define CONFIG_ONENAND_SIM_VERSION_ID 0x1e
+#endif
+
+static int manuf_id = CONFIG_ONENAND_SIM_MANUFACTURER;
+static int device_id = CONFIG_ONENAND_SIM_DEVICE_ID;
+static int version_id = CONFIG_ONENAND_SIM_VERSION_ID;
+
+struct onenand_flash {
+ void __iomem *base;
+ void __iomem *data;
+};
+
+#define ONENAND_CORE(flash) (flash->data)
+#define ONENAND_CORE_SPARE(flash, this, offset) \
+ ((flash->data) + (this->chipsize) + (offset >> 5))
+
+#define ONENAND_MAIN_AREA(this, offset) \
+ (this->base + ONENAND_DATARAM + offset)
+
+#define ONENAND_SPARE_AREA(this, offset) \
+ (this->base + ONENAND_SPARERAM + offset)
+
+#define ONENAND_GET_WP_STATUS(this) \
+ (readw(this->base + ONENAND_REG_WP_STATUS))
+
+#define ONENAND_SET_WP_STATUS(v, this) \
+ (writew(v, this->base + ONENAND_REG_WP_STATUS))
+
+/* It has all 0xff chars */
+#define MAX_ONENAND_PAGESIZE (2048 + 64)
+static unsigned char *ffchars;
+
+static struct mtd_partition os_partitions[] = {
+ {
+ .name = "OneNAND simulator partition",
+ .offset = 0,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+/*
+ * OneNAND simulator mtd
+ */
+struct onenand_info {
+ struct mtd_info mtd;
+ struct mtd_partition *parts;
+ struct onenand_chip onenand;
+ struct onenand_flash flash;
+};
+
+static struct onenand_info *info;
+
+#define DPRINTK(format, args...) \
+do { \
+ printk(KERN_DEBUG "%s[%d]: " format "\n", __func__, \
+ __LINE__, ##args); \
+} while (0)
+
+/**
+ * onenand_lock_handle - Handle Lock scheme
+ * @this: OneNAND device structure
+ * @cmd: The command to be sent
+ *
+ * Send lock command to OneNAND device.
+ * The lock scheme depends on chip type.
+ */
+static void onenand_lock_handle(struct onenand_chip *this, int cmd)
+{
+ int block_lock_scheme;
+ int status;
+
+ status = ONENAND_GET_WP_STATUS(this);
+ block_lock_scheme = !(this->options & ONENAND_HAS_CONT_LOCK);
+
+ switch (cmd) {
+ case ONENAND_CMD_UNLOCK:
+ if (block_lock_scheme)
+ ONENAND_SET_WP_STATUS(ONENAND_WP_US, this);
+ else
+ ONENAND_SET_WP_STATUS(status | ONENAND_WP_US, this);
+ break;
+
+ case ONENAND_CMD_LOCK:
+ if (block_lock_scheme)
+ ONENAND_SET_WP_STATUS(ONENAND_WP_LS, this);
+ else
+ ONENAND_SET_WP_STATUS(status | ONENAND_WP_LS, this);
+ break;
+
+ case ONENAND_CMD_LOCK_TIGHT:
+ if (block_lock_scheme)
+ ONENAND_SET_WP_STATUS(ONENAND_WP_LTS, this);
+ else
+ ONENAND_SET_WP_STATUS(status | ONENAND_WP_LTS, this);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * onenand_bootram_handle - Handle BootRAM area
+ * @this: OneNAND device structure
+ * @cmd: The command to be sent
+ *
+ * Emulate BootRAM area. It is possible to do basic operation using BootRAM.
+ */
+static void onenand_bootram_handle(struct onenand_chip *this, int cmd)
+{
+ switch (cmd) {
+ case ONENAND_CMD_READID:
+ writew(manuf_id, this->base);
+ writew(device_id, this->base + 2);
+ writew(version_id, this->base + 4);
+ break;
+
+ default:
+ /* REVIST: Handle other commands */
+ break;
+ }
+}
+
+/**
+ * onenand_update_interrupt - Set interrupt register
+ * @this: OneNAND device structure
+ * @cmd: The command to be sent
+ *
+ * Update interrupt register. The status depends on command.
+ */
+static void onenand_update_interrupt(struct onenand_chip *this, int cmd)
+{
+ int interrupt = ONENAND_INT_MASTER;
+
+ switch (cmd) {
+ case ONENAND_CMD_READ:
+ case ONENAND_CMD_READOOB:
+ interrupt |= ONENAND_INT_READ;
+ break;
+
+ case ONENAND_CMD_PROG:
+ case ONENAND_CMD_PROGOOB:
+ interrupt |= ONENAND_INT_WRITE;
+ break;
+
+ case ONENAND_CMD_ERASE:
+ interrupt |= ONENAND_INT_ERASE;
+ break;
+
+ case ONENAND_CMD_RESET:
+ interrupt |= ONENAND_INT_RESET;
+ break;
+
+ default:
+ break;
+ }
+
+ writew(interrupt, this->base + ONENAND_REG_INTERRUPT);
+}
+
+/**
+ * onenand_check_overwrite - Check if over-write happened
+ * @dest: The destination pointer
+ * @src: The source pointer
+ * @count: The length to be check
+ *
+ * Returns: 0 on same, otherwise 1
+ *
+ * Compare the source with destination
+ */
+static int onenand_check_overwrite(void *dest, void *src, size_t count)
+{
+ unsigned int *s = (unsigned int *) src;
+ unsigned int *d = (unsigned int *) dest;
+ int i;
+
+ count >>= 2;
+ for (i = 0; i < count; i++)
+ if ((*s++ ^ *d++) != 0)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * onenand_data_handle - Handle OneNAND Core and DataRAM
+ * @this: OneNAND device structure
+ * @cmd: The command to be sent
+ * @dataram: Which dataram used
+ * @offset: The offset to OneNAND Core
+ *
+ * Copy data from OneNAND Core to DataRAM (read)
+ * Copy data from DataRAM to OneNAND Core (write)
+ * Erase the OneNAND Core (erase)
+ */
+static void onenand_data_handle(struct onenand_chip *this, int cmd,
+ int dataram, unsigned int offset)
+{
+ struct mtd_info *mtd = &info->mtd;
+ struct onenand_flash *flash = this->priv;
+ int main_offset, spare_offset;
+ void __iomem *src;
+ void __iomem *dest;
+ unsigned int i;
+
+ if (dataram) {
+ main_offset = mtd->writesize;
+ spare_offset = mtd->oobsize;
+ } else {
+ main_offset = 0;
+ spare_offset = 0;
+ }
+
+ switch (cmd) {
+ case ONENAND_CMD_READ:
+ src = ONENAND_CORE(flash) + offset;
+ dest = ONENAND_MAIN_AREA(this, main_offset);
+ memcpy(dest, src, mtd->writesize);
+ /* Fall through */
+
+ case ONENAND_CMD_READOOB:
+ src = ONENAND_CORE_SPARE(flash, this, offset);
+ dest = ONENAND_SPARE_AREA(this, spare_offset);
+ memcpy(dest, src, mtd->oobsize);
+ break;
+
+ case ONENAND_CMD_PROG:
+ src = ONENAND_MAIN_AREA(this, main_offset);
+ dest = ONENAND_CORE(flash) + offset;
+ /* To handle partial write */
+ for (i = 0; i < (1 << mtd->subpage_sft); i++) {
+ int off = i * this->subpagesize;
+ if (!memcmp(src + off, ffchars, this->subpagesize))
+ continue;
+ if (memcmp(dest + off, ffchars, this->subpagesize) &&
+ onenand_check_overwrite(dest + off, src + off, this->subpagesize))
+ printk(KERN_ERR "over-write happend at 0x%08x\n", offset);
+ memcpy(dest + off, src + off, this->subpagesize);
+ }
+ /* Fall through */
+
+ case ONENAND_CMD_PROGOOB:
+ src = ONENAND_SPARE_AREA(this, spare_offset);
+ /* Check all data is 0xff chars */
+ if (!memcmp(src, ffchars, mtd->oobsize))
+ break;
+
+ dest = ONENAND_CORE_SPARE(flash, this, offset);
+ if (memcmp(dest, ffchars, mtd->oobsize) &&
+ onenand_check_overwrite(dest, src, mtd->oobsize))
+ printk(KERN_ERR "OOB: over-write happend at 0x%08x\n",
+ offset);
+ memcpy(dest, src, mtd->oobsize);
+ break;
+
+ case ONENAND_CMD_ERASE:
+ memset(ONENAND_CORE(flash) + offset, 0xff, mtd->erasesize);
+ memset(ONENAND_CORE_SPARE(flash, this, offset), 0xff,
+ (mtd->erasesize >> 5));
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ * onenand_command_handle - Handle command
+ * @this: OneNAND device structure
+ * @cmd: The command to be sent
+ *
+ * Emulate OneNAND command.
+ */
+static void onenand_command_handle(struct onenand_chip *this, int cmd)
+{
+ unsigned long offset = 0;
+ int block = -1, page = -1, bufferram = -1;
+ int dataram = 0;
+
+ switch (cmd) {
+ case ONENAND_CMD_UNLOCK:
+ case ONENAND_CMD_LOCK:
+ case ONENAND_CMD_LOCK_TIGHT:
+ case ONENAND_CMD_UNLOCK_ALL:
+ onenand_lock_handle(this, cmd);
+ break;
+
+ case ONENAND_CMD_BUFFERRAM:
+ /* Do nothing */
+ return;
+
+ default:
+ block = (int) readw(this->base + ONENAND_REG_START_ADDRESS1);
+ if (block & (1 << ONENAND_DDP_SHIFT)) {
+ block &= ~(1 << ONENAND_DDP_SHIFT);
+ /* The half of chip block */
+ block += this->chipsize >> (this->erase_shift + 1);
+ }
+ if (cmd == ONENAND_CMD_ERASE)
+ break;
+
+ page = (int) readw(this->base + ONENAND_REG_START_ADDRESS8);
+ page = (page >> ONENAND_FPA_SHIFT);
+ bufferram = (int) readw(this->base + ONENAND_REG_START_BUFFER);
+ bufferram >>= ONENAND_BSA_SHIFT;
+ bufferram &= ONENAND_BSA_DATARAM1;
+ dataram = (bufferram == ONENAND_BSA_DATARAM1) ? 1 : 0;
+ break;
+ }
+
+ if (block != -1)
+ offset += block << this->erase_shift;
+
+ if (page != -1)
+ offset += page << this->page_shift;
+
+ onenand_data_handle(this, cmd, dataram, offset);
+
+ onenand_update_interrupt(this, cmd);
+}
+
+/**
+ * onenand_writew - [OneNAND Interface] Emulate write operation
+ * @value: value to write
+ * @addr: address to write
+ *
+ * Write OneNAND register with value
+ */
+static void onenand_writew(unsigned short value, void __iomem * addr)
+{
+ struct onenand_chip *this = info->mtd.priv;
+
+ /* BootRAM handling */
+ if (addr < this->base + ONENAND_DATARAM) {
+ onenand_bootram_handle(this, value);
+ return;
+ }
+ /* Command handling */
+ if (addr == this->base + ONENAND_REG_COMMAND)
+ onenand_command_handle(this, value);
+
+ writew(value, addr);
+}
+
+/**
+ * flash_init - Initialize OneNAND simulator
+ * @flash: OneNAND simulator data strucutres
+ *
+ * Initialize OneNAND simulator.
+ */
+static int __init flash_init(struct onenand_flash *flash)
+{
+ int density, size;
+ int buffer_size;
+
+ flash->base = kzalloc(131072, GFP_KERNEL);
+ if (!flash->base) {
+ printk(KERN_ERR "Unable to allocate base address.\n");
+ return -ENOMEM;
+ }
+
+ density = device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+ size = ((16 << 20) << density);
+
+ ONENAND_CORE(flash) = vmalloc(size + (size >> 5));
+ if (!ONENAND_CORE(flash)) {
+ printk(KERN_ERR "Unable to allocate nand core address.\n");
+ kfree(flash->base);
+ return -ENOMEM;
+ }
+
+ memset(ONENAND_CORE(flash), 0xff, size + (size >> 5));
+
+ /* Setup registers */
+ writew(manuf_id, flash->base + ONENAND_REG_MANUFACTURER_ID);
+ writew(device_id, flash->base + ONENAND_REG_DEVICE_ID);
+ writew(version_id, flash->base + ONENAND_REG_VERSION_ID);
+
+ if (density < 2)
+ buffer_size = 0x0400; /* 1KiB page */
+ else
+ buffer_size = 0x0800; /* 2KiB page */
+ writew(buffer_size, flash->base + ONENAND_REG_DATA_BUFFER_SIZE);
+
+ return 0;
+}
+
+/**
+ * flash_exit - Clean up OneNAND simulator
+ * @flash: OneNAND simulator data structures
+ *
+ * Clean up OneNAND simulator.
+ */
+static void flash_exit(struct onenand_flash *flash)
+{
+ vfree(ONENAND_CORE(flash));
+ kfree(flash->base);
+}
+
+static int __init onenand_sim_init(void)
+{
+ /* Allocate all 0xff chars pointer */
+ ffchars = kmalloc(MAX_ONENAND_PAGESIZE, GFP_KERNEL);
+ if (!ffchars) {
+ printk(KERN_ERR "Unable to allocate ff chars.\n");
+ return -ENOMEM;
+ }
+ memset(ffchars, 0xff, MAX_ONENAND_PAGESIZE);
+
+ /* Allocate OneNAND simulator mtd pointer */
+ info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL);
+ if (!info) {
+ printk(KERN_ERR "Unable to allocate core structures.\n");
+ kfree(ffchars);
+ return -ENOMEM;
+ }
+
+ /* Override write_word function */
+ info->onenand.write_word = onenand_writew;
+
+ if (flash_init(&info->flash)) {
+ printk(KERN_ERR "Unable to allocate flash.\n");
+ kfree(ffchars);
+ kfree(info);
+ return -ENOMEM;
+ }
+
+ info->parts = os_partitions;
+
+ info->onenand.base = info->flash.base;
+ info->onenand.priv = &info->flash;
+
+ info->mtd.name = "OneNAND simulator";
+ info->mtd.priv = &info->onenand;
+ info->mtd.owner = THIS_MODULE;
+
+ if (onenand_scan(&info->mtd, 1)) {
+ flash_exit(&info->flash);
+ kfree(ffchars);
+ kfree(info);
+ return -ENXIO;
+ }
+
+ add_mtd_partitions(&info->mtd, info->parts, ARRAY_SIZE(os_partitions));
+
+ return 0;
+}
+
+static void __exit onenand_sim_exit(void)
+{
+ struct onenand_chip *this = info->mtd.priv;
+ struct onenand_flash *flash = this->priv;
+
+ onenand_release(&info->mtd);
+ flash_exit(flash);
+ kfree(ffchars);
+ kfree(info);
+}
+
+module_init(onenand_sim_init);
+module_exit(onenand_sim_exit);
+
+MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
+MODULE_DESCRIPTION("The OneNAND flash simulator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index 006c03aacb5..823fba4e6d2 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -779,10 +779,8 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
else {
if (!mtd->erasesize) {
printk(KERN_WARNING PREFIX "please provide block_size");
- kfree(part);
- return;
- }
- else
+ goto out;
+ } else
part->block_size = mtd->erasesize;
}
@@ -804,7 +802,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
if (!add_mtd_blktrans_dev((void*)part))
return;
}
-
+out:
kfree(part);
}
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 1cb22bfae75..023653977a1 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -565,7 +565,7 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
}
ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!ubi) {
err = -ENOMEM;
goto out_mtd;
@@ -583,6 +583,22 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
if (err)
goto out_free;
+ mutex_init(&ubi->buf_mutex);
+ ubi->peb_buf1 = vmalloc(ubi->peb_size);
+ if (!ubi->peb_buf1)
+ goto out_free;
+
+ ubi->peb_buf2 = vmalloc(ubi->peb_size);
+ if (!ubi->peb_buf2)
+ goto out_free;
+
+#ifdef CONFIG_MTD_UBI_DEBUG
+ mutex_init(&ubi->dbg_buf_mutex);
+ ubi->dbg_peb_buf = vmalloc(ubi->peb_size);
+ if (!ubi->dbg_peb_buf)
+ goto out_free;
+#endif
+
err = attach_by_scanning(ubi);
if (err) {
dbg_err("failed to attach by scanning, error %d", err);
@@ -630,6 +646,11 @@ out_detach:
ubi_wl_close(ubi);
vfree(ubi->vtbl);
out_free:
+ vfree(ubi->peb_buf1);
+ vfree(ubi->peb_buf2);
+#ifdef CONFIG_MTD_UBI_DEBUG
+ vfree(ubi->dbg_peb_buf);
+#endif
kfree(ubi);
out_mtd:
put_mtd_device(mtd);
@@ -651,6 +672,11 @@ static void detach_mtd_dev(struct ubi_device *ubi)
ubi_wl_close(ubi);
vfree(ubi->vtbl);
put_mtd_device(ubi->mtd);
+ vfree(ubi->peb_buf1);
+ vfree(ubi->peb_buf2);
+#ifdef CONFIG_MTD_UBI_DEBUG
+ vfree(ubi->dbg_peb_buf);
+#endif
kfree(ubi_devices[ubi_num]);
ubi_devices[ubi_num] = NULL;
ubi_devices_cnt -= 1;
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 310341e5cd4..56956ec2845 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -42,7 +42,8 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset));
dbg_msg("hdr_crc %#08x", be32_to_cpu(ec_hdr->hdr_crc));
dbg_msg("erase counter header hexdump:");
- ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+ ec_hdr, UBI_EC_HDR_SIZE, 1);
}
/**
@@ -187,38 +188,4 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
dbg_msg("the 1st 16 characters of the name: %s", nm);
}
-#define BYTES_PER_LINE 32
-
-/**
- * ubi_dbg_hexdump - dump a buffer.
- * @ptr: the buffer to dump
- * @size: buffer size which must be multiple of 4 bytes
- */
-void ubi_dbg_hexdump(const void *ptr, int size)
-{
- int i, k = 0, rows, columns;
- const uint8_t *p = ptr;
-
- size = ALIGN(size, 4);
- rows = size/BYTES_PER_LINE + size % BYTES_PER_LINE;
- for (i = 0; i < rows; i++) {
- int j;
-
- cond_resched();
- columns = min(size - k, BYTES_PER_LINE) / 4;
- if (columns == 0)
- break;
- printk(KERN_DEBUG "%5d: ", i * BYTES_PER_LINE);
- for (j = 0; j < columns; j++) {
- int n, N;
-
- N = size - k > 4 ? 4 : size - k;
- for (n = 0; n < N; n++)
- printk("%02x", p[k++]);
- printk(" ");
- }
- printk("\n");
- }
-}
-
#endif /* CONFIG_MTD_UBI_DEBUG_MSG */
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index ff8f39548cd..467722eb618 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -59,7 +59,6 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
-void ubi_dbg_hexdump(const void *buf, int size);
#else
@@ -72,7 +71,6 @@ void ubi_dbg_hexdump(const void *buf, int size);
#define ubi_dbg_dump_sv(sv) ({})
#define ubi_dbg_dump_seb(seb, type) ({})
#define ubi_dbg_dump_mkvol_req(req) ({})
-#define ubi_dbg_hexdump(buf, size) ({})
#endif /* CONFIG_MTD_UBI_DEBUG_MSG */
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 7c5e29eaf11..880fa369035 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -46,6 +46,9 @@
#include <linux/err.h>
#include "ubi.h"
+/* Number of physical eraseblocks reserved for atomic LEB change operation */
+#define EBA_RESERVED_PEBS 1
+
/**
* struct ltree_entry - an entry in the lock tree.
* @rb: links RB-tree nodes
@@ -157,7 +160,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id,
{
struct ltree_entry *le, *le1, *le_free;
- le = kmem_cache_alloc(ltree_slab, GFP_KERNEL);
+ le = kmem_cache_alloc(ltree_slab, GFP_NOFS);
if (!le)
return ERR_PTR(-ENOMEM);
@@ -397,7 +400,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
retry:
if (check) {
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) {
err = -ENOMEM;
goto out_unlock;
@@ -495,16 +498,18 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0;
struct ubi_volume *vol = ubi->volumes[idx];
struct ubi_vid_hdr *vid_hdr;
- unsigned char *new_buf;
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) {
return -ENOMEM;
}
+ mutex_lock(&ubi->buf_mutex);
+
retry:
new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN);
if (new_pnum < 0) {
+ mutex_unlock(&ubi->buf_mutex);
ubi_free_vid_hdr(ubi, vid_hdr);
return new_pnum;
}
@@ -524,31 +529,22 @@ retry:
goto write_error;
data_size = offset + len;
- new_buf = vmalloc(data_size);
- if (!new_buf) {
- err = -ENOMEM;
- goto out_put;
- }
- memset(new_buf + offset, 0xFF, len);
+ memset(ubi->peb_buf1 + offset, 0xFF, len);
/* Read everything before the area where the write failure happened */
if (offset > 0) {
- err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset);
- if (err && err != UBI_IO_BITFLIPS) {
- vfree(new_buf);
+ err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset);
+ if (err && err != UBI_IO_BITFLIPS)
goto out_put;
- }
}
- memcpy(new_buf + offset, buf, len);
+ memcpy(ubi->peb_buf1 + offset, buf, len);
- err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size);
- if (err) {
- vfree(new_buf);
+ err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size);
+ if (err)
goto write_error;
- }
- vfree(new_buf);
+ mutex_unlock(&ubi->buf_mutex);
ubi_free_vid_hdr(ubi, vid_hdr);
vol->eba_tbl[lnum] = new_pnum;
@@ -558,6 +554,7 @@ retry:
return 0;
out_put:
+ mutex_unlock(&ubi->buf_mutex);
ubi_wl_put_peb(ubi, new_pnum, 1);
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
@@ -570,6 +567,7 @@ write_error:
ubi_warn("failed to write to PEB %d", new_pnum);
ubi_wl_put_peb(ubi, new_pnum, 1);
if (++tries > UBI_IO_RETRIES) {
+ mutex_unlock(&ubi->buf_mutex);
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
}
@@ -627,7 +625,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
* The logical eraseblock is not mapped. We have to get a free physical
* eraseblock and write the volume identifier header there first.
*/
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr) {
leb_write_unlock(ubi, vol_id, lnum);
return -ENOMEM;
@@ -738,7 +736,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
else
ubi_assert(len % ubi->min_io_size == 0);
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr)
return -ENOMEM;
@@ -832,6 +830,9 @@ write_error:
* data, which has to be aligned. This function guarantees that in case of an
* unclean reboot the old contents is preserved. Returns zero in case of
* success and a negative error code in case of failure.
+ *
+ * UBI reserves one LEB for the "atomic LEB change" operation, so only one
+ * LEB change may be done at a time. This is ensured by @ubi->alc_mutex.
*/
int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
const void *buf, int len, int dtype)
@@ -844,15 +845,14 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
if (ubi->ro_mode)
return -EROFS;
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr)
return -ENOMEM;
+ mutex_lock(&ubi->alc_mutex);
err = leb_write_lock(ubi, vol_id, lnum);
- if (err) {
- ubi_free_vid_hdr(ubi, vid_hdr);
- return err;
- }
+ if (err)
+ goto out_mutex;
vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
vid_hdr->vol_id = cpu_to_be32(vol_id);
@@ -869,9 +869,8 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
retry:
pnum = ubi_wl_get_peb(ubi, dtype);
if (pnum < 0) {
- ubi_free_vid_hdr(ubi, vid_hdr);
- leb_write_unlock(ubi, vol_id, lnum);
- return pnum;
+ err = pnum;
+ goto out_leb_unlock;
}
dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d",
@@ -893,17 +892,18 @@ retry:
if (vol->eba_tbl[lnum] >= 0) {
err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
- if (err) {
- ubi_free_vid_hdr(ubi, vid_hdr);
- leb_write_unlock(ubi, vol_id, lnum);
- return err;
- }
+ if (err)
+ goto out_leb_unlock;
}
vol->eba_tbl[lnum] = pnum;
+
+out_leb_unlock:
leb_write_unlock(ubi, vol_id, lnum);
+out_mutex:
+ mutex_unlock(&ubi->alc_mutex);
ubi_free_vid_hdr(ubi, vid_hdr);
- return 0;
+ return err;
write_error:
if (err != -EIO || !ubi->bad_allowed) {
@@ -913,17 +913,13 @@ write_error:
* mode just in case.
*/
ubi_ro_mode(ubi);
- leb_write_unlock(ubi, vol_id, lnum);
- ubi_free_vid_hdr(ubi, vid_hdr);
- return err;
+ goto out_leb_unlock;
}
err = ubi_wl_put_peb(ubi, pnum, 1);
if (err || ++tries > UBI_IO_RETRIES) {
ubi_ro_mode(ubi);
- leb_write_unlock(ubi, vol_id, lnum);
- ubi_free_vid_hdr(ubi, vid_hdr);
- return err;
+ goto out_leb_unlock;
}
vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
@@ -937,8 +933,7 @@ write_error:
* @cache: the lock tree entry slab cache
* @flags: constructor flags
*/
-static void ltree_entry_ctor(void *obj, struct kmem_cache *cache,
- unsigned long flags)
+static void ltree_entry_ctor(struct kmem_cache *cache, void *obj)
{
struct ltree_entry *le = obj;
@@ -965,7 +960,6 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
int err, vol_id, lnum, data_size, aldata_size, pnum, idx;
struct ubi_volume *vol;
uint32_t crc;
- void *buf, *buf1 = NULL;
vol_id = be32_to_cpu(vid_hdr->vol_id);
lnum = be32_to_cpu(vid_hdr->lnum);
@@ -979,19 +973,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
data_size = aldata_size =
ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
- buf = vmalloc(aldata_size);
- if (!buf)
- return -ENOMEM;
-
/*
* We do not want anybody to write to this logical eraseblock while we
* are moving it, so we lock it.
*/
err = leb_write_lock(ubi, vol_id, lnum);
- if (err) {
- vfree(buf);
+ if (err)
return err;
- }
+
+ mutex_lock(&ubi->buf_mutex);
/*
* But the logical eraseblock might have been put by this time.
@@ -1023,7 +1013,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
/* OK, now the LEB is locked and we can safely start moving it */
dbg_eba("read %d bytes of data", aldata_size);
- err = ubi_io_read_data(ubi, buf, from, 0, aldata_size);
+ err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size);
if (err && err != UBI_IO_BITFLIPS) {
ubi_warn("error %d while reading data from PEB %d",
err, from);
@@ -1042,10 +1032,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
*/
if (vid_hdr->vol_type == UBI_VID_DYNAMIC)
aldata_size = data_size =
- ubi_calc_data_len(ubi, buf, data_size);
+ ubi_calc_data_len(ubi, ubi->peb_buf1, data_size);
cond_resched();
- crc = crc32(UBI_CRC32_INIT, buf, data_size);
+ crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size);
cond_resched();
/*
@@ -1076,23 +1066,18 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
}
if (data_size > 0) {
- err = ubi_io_write_data(ubi, buf, to, 0, aldata_size);
+ err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size);
if (err)
goto out_unlock;
+ cond_resched();
+
/*
* We've written the data and are going to read it back to make
* sure it was written correctly.
*/
- buf1 = vmalloc(aldata_size);
- if (!buf1) {
- err = -ENOMEM;
- goto out_unlock;
- }
-
- cond_resched();
- err = ubi_io_read_data(ubi, buf1, to, 0, aldata_size);
+ err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size);
if (err) {
if (err != UBI_IO_BITFLIPS)
ubi_warn("cannot read data back from PEB %d",
@@ -1102,7 +1087,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
cond_resched();
- if (memcmp(buf, buf1, aldata_size)) {
+ if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) {
ubi_warn("read data back from PEB %d - it is different",
to);
goto out_unlock;
@@ -1112,16 +1097,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
ubi_assert(vol->eba_tbl[lnum] == from);
vol->eba_tbl[lnum] = to;
- leb_write_unlock(ubi, vol_id, lnum);
- vfree(buf);
- vfree(buf1);
-
- return 0;
-
out_unlock:
+ mutex_unlock(&ubi->buf_mutex);
leb_write_unlock(ubi, vol_id, lnum);
- vfree(buf);
- vfree(buf1);
return err;
}
@@ -1144,6 +1122,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
dbg_eba("initialize EBA unit");
spin_lock_init(&ubi->ltree_lock);
+ mutex_init(&ubi->alc_mutex);
ubi->ltree = RB_ROOT;
if (ubi_devices_cnt == 0) {
@@ -1205,6 +1184,15 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
ubi->rsvd_pebs += ubi->beb_rsvd_pebs;
}
+ if (ubi->avail_pebs < EBA_RESERVED_PEBS) {
+ ubi_err("no enough physical eraseblocks (%d, need %d)",
+ ubi->avail_pebs, EBA_RESERVED_PEBS);
+ err = -ENOSPC;
+ goto out_free;
+ }
+ ubi->avail_pebs -= EBA_RESERVED_PEBS;
+ ubi->rsvd_pebs += EBA_RESERVED_PEBS;
+
dbg_eba("EBA unit is initialized");
return 0;
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index b0d8f4cede9..7c304eec78b 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -98,8 +98,8 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
const struct ubi_vid_hdr *vid_hdr);
-static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
- int offset, int len);
+static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
+ int len);
#else
#define paranoid_check_not_bad(ubi, pnum) 0
#define paranoid_check_peb_ec_hdr(ubi, pnum) 0
@@ -202,8 +202,8 @@ retry:
* Note, in case of an error, it is possible that something was still written
* to the flash media, but may be some garbage.
*/
-int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum,
- int offset, int len)
+int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
+ int len)
{
int err;
size_t written;
@@ -285,7 +285,7 @@ static void erase_callback(struct erase_info *ei)
* zero in case of success and a negative error code in case of failure. If
* %-EIO is returned, the physical eraseblock most probably went bad.
*/
-static int do_sync_erase(const struct ubi_device *ubi, int pnum)
+static int do_sync_erase(struct ubi_device *ubi, int pnum)
{
int err, retries = 0;
struct erase_info ei;
@@ -377,29 +377,25 @@ static uint8_t patterns[] = {0xa5, 0x5a, 0x0};
* test, a positive number of erase operations done if the test was
* successfully passed, and other negative error codes in case of other errors.
*/
-static int torture_peb(const struct ubi_device *ubi, int pnum)
+static int torture_peb(struct ubi_device *ubi, int pnum)
{
- void *buf;
int err, i, patt_count;
- buf = vmalloc(ubi->peb_size);
- if (!buf)
- return -ENOMEM;
-
patt_count = ARRAY_SIZE(patterns);
ubi_assert(patt_count > 0);
+ mutex_lock(&ubi->buf_mutex);
for (i = 0; i < patt_count; i++) {
err = do_sync_erase(ubi, pnum);
if (err)
goto out;
/* Make sure the PEB contains only 0xFF bytes */
- err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size);
+ err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
if (err)
goto out;
- err = check_pattern(buf, 0xFF, ubi->peb_size);
+ err = check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size);
if (err == 0) {
ubi_err("erased PEB %d, but a non-0xFF byte found",
pnum);
@@ -408,17 +404,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
}
/* Write a pattern and check it */
- memset(buf, patterns[i], ubi->peb_size);
- err = ubi_io_write(ubi, buf, pnum, 0, ubi->peb_size);
+ memset(ubi->peb_buf1, patterns[i], ubi->peb_size);
+ err = ubi_io_write(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
if (err)
goto out;
- memset(buf, ~patterns[i], ubi->peb_size);
- err = ubi_io_read(ubi, buf, pnum, 0, ubi->peb_size);
+ memset(ubi->peb_buf1, ~patterns[i], ubi->peb_size);
+ err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size);
if (err)
goto out;
- err = check_pattern(buf, patterns[i], ubi->peb_size);
+ err = check_pattern(ubi->peb_buf1, patterns[i], ubi->peb_size);
if (err == 0) {
ubi_err("pattern %x checking failed for PEB %d",
patterns[i], pnum);
@@ -430,14 +426,17 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
err = patt_count;
out:
- if (err == UBI_IO_BITFLIPS || err == -EBADMSG)
+ mutex_unlock(&ubi->buf_mutex);
+ if (err == UBI_IO_BITFLIPS || err == -EBADMSG) {
/*
* If a bit-flip or data integrity error was detected, the test
* has not passed because it happened on a freshly erased
* physical eraseblock which means something is wrong with it.
*/
+ ubi_err("read problems on freshly erased PEB %d, must be bad",
+ pnum);
err = -EIO;
- vfree(buf);
+ }
return err;
}
@@ -457,7 +456,7 @@ out:
* codes in case of other errors. Note, %-EIO means that the physical
* eraseblock is bad.
*/
-int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture)
+int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
{
int err, ret = 0;
@@ -614,7 +613,7 @@ bad:
* o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty;
* o a negative error code in case of failure.
*/
-int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
struct ubi_ec_hdr *ec_hdr, int verbose)
{
int err, read_err = 0;
@@ -720,7 +719,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
* case of failure. If %-EIO is returned, the physical eraseblock most probably
* went bad.
*/
-int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
struct ubi_ec_hdr *ec_hdr)
{
int err;
@@ -886,7 +885,7 @@ bad:
* header there);
* o a negative error code in case of failure.
*/
-int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr, int verbose)
{
int err, read_err = 0;
@@ -993,7 +992,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
* case of failure. If %-EIO is returned, the physical eraseblock probably went
* bad.
*/
-int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr)
{
int err;
@@ -1096,7 +1095,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
uint32_t crc, hdr_crc;
struct ubi_ec_hdr *ec_hdr;
- ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr)
return -ENOMEM;
@@ -1176,7 +1175,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
struct ubi_vid_hdr *vid_hdr;
void *p;
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr)
return -ENOMEM;
@@ -1216,44 +1215,40 @@ exit:
* @offset of the physical eraseblock @pnum, %1 if not, and a negative error
* code if an error occurred.
*/
-static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
- int offset, int len)
+static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
+ int len)
{
size_t read;
int err;
- void *buf;
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
- buf = vmalloc(len);
- if (!buf)
- return -ENOMEM;
- memset(buf, 0, len);
-
- err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
+ mutex_lock(&ubi->dbg_buf_mutex);
+ err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf);
if (err && err != -EUCLEAN) {
ubi_err("error %d while reading %d bytes from PEB %d:%d, "
"read %zd bytes", err, len, pnum, offset, read);
goto error;
}
- err = check_pattern(buf, 0xFF, len);
+ err = check_pattern(ubi->dbg_peb_buf, 0xFF, len);
if (err == 0) {
ubi_err("flash region at PEB %d:%d, length %d does not "
"contain all 0xFF bytes", pnum, offset, len);
goto fail;
}
+ mutex_unlock(&ubi->dbg_buf_mutex);
- vfree(buf);
return 0;
fail:
ubi_err("paranoid check failed for PEB %d", pnum);
dbg_msg("hex dump of the %d-%d region", offset, offset + len);
- ubi_dbg_hexdump(buf, len);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
+ ubi->dbg_peb_buf, len, 1);
err = 1;
error:
ubi_dbg_dump_stack();
- vfree(buf);
+ mutex_unlock(&ubi->dbg_buf_mutex);
return err;
}
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 4a458e83e4e..03c774f4154 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -99,16 +99,21 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
{
int err;
struct ubi_volume_desc *desc;
- struct ubi_device *ubi = ubi_devices[ubi_num];
+ struct ubi_device *ubi;
struct ubi_volume *vol;
dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode);
err = -ENODEV;
+ if (ubi_num < 0)
+ return ERR_PTR(err);
+
+ ubi = ubi_devices[ubi_num];
+
if (!try_module_get(THIS_MODULE))
return ERR_PTR(err);
- if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi)
+ if (ubi_num >= UBI_MAX_DEVICES || !ubi)
goto out_put;
err = -EINVAL;
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 94ee5493441..c7b0afc9d28 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -45,8 +45,7 @@
#include "ubi.h"
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
-static int paranoid_check_si(const struct ubi_device *ubi,
- struct ubi_scan_info *si);
+static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si);
#else
#define paranoid_check_si(ubi, si) 0
#endif
@@ -259,14 +258,13 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
* o bit 2 is cleared: the older LEB is not corrupted;
* o bit 2 is set: the older LEB is corrupted.
*/
-static int compare_lebs(const struct ubi_device *ubi,
- const struct ubi_scan_leb *seb, int pnum,
- const struct ubi_vid_hdr *vid_hdr)
+static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
+ int pnum, const struct ubi_vid_hdr *vid_hdr)
{
void *buf;
int len, err, second_is_newer, bitflips = 0, corrupted = 0;
uint32_t data_crc, crc;
- struct ubi_vid_hdr *vidh = NULL;
+ struct ubi_vid_hdr *vh = NULL;
unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
if (seb->sqnum == 0 && sqnum2 == 0) {
@@ -323,11 +321,11 @@ static int compare_lebs(const struct ubi_device *ubi,
} else {
pnum = seb->pnum;
- vidh = ubi_zalloc_vid_hdr(ubi);
- if (!vidh)
+ vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
+ if (!vh)
return -ENOMEM;
- err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0);
+ err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);
if (err) {
if (err == UBI_IO_BITFLIPS)
bitflips = 1;
@@ -341,7 +339,7 @@ static int compare_lebs(const struct ubi_device *ubi,
}
}
- if (!vidh->copy_flag) {
+ if (!vh->copy_flag) {
/* It is not a copy, so it is newer */
dbg_bld("first PEB %d is newer, copy_flag is unset",
pnum);
@@ -349,7 +347,7 @@ static int compare_lebs(const struct ubi_device *ubi,
goto out_free_vidh;
}
- vid_hdr = vidh;
+ vid_hdr = vh;
}
/* Read the data of the copy and check the CRC */
@@ -379,7 +377,7 @@ static int compare_lebs(const struct ubi_device *ubi,
}
vfree(buf);
- ubi_free_vid_hdr(ubi, vidh);
+ ubi_free_vid_hdr(ubi, vh);
if (second_is_newer)
dbg_bld("second PEB %d is newer, copy_flag is set", pnum);
@@ -391,7 +389,7 @@ static int compare_lebs(const struct ubi_device *ubi,
out_free_buf:
vfree(buf);
out_free_vidh:
- ubi_free_vid_hdr(ubi, vidh);
+ ubi_free_vid_hdr(ubi, vh);
ubi_assert(err < 0);
return err;
}
@@ -413,7 +411,7 @@ out_free_vidh:
* to be picked, while the older one has to be dropped. This function returns
* zero in case of success and a negative error code in case of failure.
*/
-int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
+int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
int bitflips)
{
@@ -667,16 +665,12 @@ void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
* function returns zero in case of success and a negative error code in case
* of failure.
*/
-int ubi_scan_erase_peb(const struct ubi_device *ubi,
- const struct ubi_scan_info *si, int pnum, int ec)
+int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
+ int pnum, int ec)
{
int err;
struct ubi_ec_hdr *ec_hdr;
- ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
- if (!ec_hdr)
- return -ENOMEM;
-
if ((long long)ec >= UBI_MAX_ERASECOUNTER) {
/*
* Erase counter overflow. Upgrade UBI and use 64-bit
@@ -686,6 +680,10 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi,
return -EINVAL;
}
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ if (!ec_hdr)
+ return -ENOMEM;
+
ec_hdr->ec = cpu_to_be64(ec);
err = ubi_io_sync_erase(ubi, pnum, 0);
@@ -712,7 +710,7 @@ out_free:
* This function returns scanning physical eraseblock information in case of
* success and an error code in case of failure.
*/
-struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
+struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
struct ubi_scan_info *si)
{
int err = 0, i;
@@ -948,7 +946,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
if (!ech)
goto out_si;
- vidh = ubi_zalloc_vid_hdr(ubi);
+ vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vidh)
goto out_ech;
@@ -1110,8 +1108,7 @@ void ubi_scan_destroy_si(struct ubi_scan_info *si)
* This function returns zero if the scanning information is all right, %1 if
* not and a negative error code if an error occurred.
*/
-static int paranoid_check_si(const struct ubi_device *ubi,
- struct ubi_scan_info *si)
+static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
{
int pnum, err, vols_found = 0;
struct rb_node *rb1, *rb2;
@@ -1314,11 +1311,10 @@ static int paranoid_check_si(const struct ubi_device *ubi,
* Make sure that all the physical eraseblocks are in one of the lists
* or trees.
*/
- buf = kmalloc(ubi->peb_count, GFP_KERNEL);
+ buf = kzalloc(ubi->peb_count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- memset(buf, 1, ubi->peb_count);
for (pnum = 0; pnum < ubi->peb_count; pnum++) {
err = ubi_io_is_bad(ubi, pnum);
if (err < 0) {
@@ -1326,28 +1322,28 @@ static int paranoid_check_si(const struct ubi_device *ubi,
return err;
}
else if (err)
- buf[pnum] = 0;
+ buf[pnum] = 1;
}
ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb)
ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
- buf[seb->pnum] = 0;
+ buf[seb->pnum] = 1;
list_for_each_entry(seb, &si->free, u.list)
- buf[seb->pnum] = 0;
+ buf[seb->pnum] = 1;
list_for_each_entry(seb, &si->corr, u.list)
- buf[seb->pnum] = 0;
+ buf[seb->pnum] = 1;
list_for_each_entry(seb, &si->erase, u.list)
- buf[seb->pnum] = 0;
+ buf[seb->pnum] = 1;
list_for_each_entry(seb, &si->alien, u.list)
- buf[seb->pnum] = 0;
+ buf[seb->pnum] = 1;
err = 0;
for (pnum = 0; pnum < ubi->peb_count; pnum++)
- if (buf[pnum]) {
+ if (!buf[pnum]) {
ubi_err("PEB %d is not referred", pnum);
err = 1;
}
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
index 140e82e2653..46d444af471 100644
--- a/drivers/mtd/ubi/scan.h
+++ b/drivers/mtd/ubi/scan.h
@@ -147,7 +147,7 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
list_add_tail(&seb->u.list, list);
}
-int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
+int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
int bitflips);
struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
@@ -155,10 +155,10 @@ struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
int lnum);
void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv);
-struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
+struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
struct ubi_scan_info *si);
-int ubi_scan_erase_peb(const struct ubi_device *ubi,
- const struct ubi_scan_info *si, int pnum, int ec);
+int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
+ int pnum, int ec);
struct ubi_scan_info *ubi_scan(struct ubi_device *ubi);
void ubi_scan_destroy_si(struct ubi_scan_info *si);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 5959f91be24..5e941a63303 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -221,14 +221,15 @@ struct ubi_wl_entry;
* @vtbl_slots: how many slots are available in the volume table
* @vtbl_size: size of the volume table in bytes
* @vtbl: in-RAM volume table copy
+ * @vtbl_mutex: protects on-flash volume table
*
* @max_ec: current highest erase counter value
* @mean_ec: current mean erase counter value
*
- * global_sqnum: global sequence number
+ * @global_sqnum: global sequence number
* @ltree_lock: protects the lock tree and @global_sqnum
* @ltree: the lock tree
- * @vtbl_mutex: protects on-flash volume table
+ * @alc_mutex: serializes "atomic LEB change" operations
*
* @used: RB-tree of used physical eraseblocks
* @free: RB-tree of free physical eraseblocks
@@ -274,6 +275,12 @@ struct ubi_wl_entry;
* @bad_allowed: whether the MTD device admits of bad physical eraseblocks or
* not
* @mtd: MTD device descriptor
+ *
+ * @peb_buf1: a buffer of PEB size used for different purposes
+ * @peb_buf2: another buffer of PEB size used for different purposes
+ * @buf_mutex: proptects @peb_buf1 and @peb_buf2
+ * @dbg_peb_buf: buffer of PEB size used for debugging
+ * @dbg_buf_mutex: proptects @dbg_peb_buf
*/
struct ubi_device {
struct cdev cdev;
@@ -302,6 +309,7 @@ struct ubi_device {
unsigned long long global_sqnum;
spinlock_t ltree_lock;
struct rb_root ltree;
+ struct mutex alc_mutex;
/* Wear-leveling unit's stuff */
struct rb_root used;
@@ -343,6 +351,14 @@ struct ubi_device {
int vid_hdr_shift;
int bad_allowed;
struct mtd_info *mtd;
+
+ void *peb_buf1;
+ void *peb_buf2;
+ struct mutex buf_mutex;
+#ifdef CONFIG_MTD_UBI_DEBUG
+ void *dbg_peb_buf;
+ struct mutex dbg_buf_mutex;
+#endif
};
extern struct file_operations ubi_cdev_operations;
@@ -409,18 +425,18 @@ void ubi_wl_close(struct ubi_device *ubi);
/* io.c */
int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
int len);
-int ubi_io_write(const struct ubi_device *ubi, const void *buf, int pnum,
- int offset, int len);
-int ubi_io_sync_erase(const struct ubi_device *ubi, int pnum, int torture);
+int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
+ int len);
+int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture);
int ubi_io_is_bad(const struct ubi_device *ubi, int pnum);
int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum);
-int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
struct ubi_ec_hdr *ec_hdr, int verbose);
-int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
struct ubi_ec_hdr *ec_hdr);
-int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr, int verbose);
-int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
+int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
struct ubi_vid_hdr *vid_hdr);
/*
@@ -439,16 +455,18 @@ int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
/**
* ubi_zalloc_vid_hdr - allocate a volume identifier header object.
* @ubi: UBI device description object
+ * @gfp_flags: GFP flags to allocate with
*
* This function returns a pointer to the newly allocated and zero-filled
* volume identifier header object in case of success and %NULL in case of
* failure.
*/
-static inline struct ubi_vid_hdr *ubi_zalloc_vid_hdr(const struct ubi_device *ubi)
+static inline struct ubi_vid_hdr *
+ubi_zalloc_vid_hdr(const struct ubi_device *ubi, gfp_t gfp_flags)
{
void *vid_hdr;
- vid_hdr = kzalloc(ubi->vid_hdr_alsize, GFP_KERNEL);
+ vid_hdr = kzalloc(ubi->vid_hdr_alsize, gfp_flags);
if (!vid_hdr)
return NULL;
@@ -492,7 +510,7 @@ static inline int ubi_io_read_data(const struct ubi_device *ubi, void *buf,
* the beginning of the logical eraseblock, not to the beginning of the
* physical eraseblock.
*/
-static inline int ubi_io_write_data(const struct ubi_device *ubi, const void *buf,
+static inline int ubi_io_write_data(struct ubi_device *ubi, const void *buf,
int pnum, int offset, int len)
{
ubi_assert(offset >= 0);
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index ea0d5c825ab..88629a320c2 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -37,21 +37,21 @@ static ssize_t vol_attribute_show(struct device *dev,
struct device_attribute *attr, char *buf);
/* Device attributes corresponding to files in '/<sysfs>/class/ubi/ubiX_Y' */
-static struct device_attribute vol_reserved_ebs =
+static struct device_attribute attr_vol_reserved_ebs =
__ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_type =
+static struct device_attribute attr_vol_type =
__ATTR(type, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_name =
+static struct device_attribute attr_vol_name =
__ATTR(name, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_corrupted =
+static struct device_attribute attr_vol_corrupted =
__ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_alignment =
+static struct device_attribute attr_vol_alignment =
__ATTR(alignment, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_usable_eb_size =
+static struct device_attribute attr_vol_usable_eb_size =
__ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_data_bytes =
+static struct device_attribute attr_vol_data_bytes =
__ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL);
-static struct device_attribute vol_upd_marker =
+static struct device_attribute attr_vol_upd_marker =
__ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL);
/*
@@ -78,23 +78,27 @@ static ssize_t vol_attribute_show(struct device *dev,
spin_unlock(&vol->ubi->volumes_lock);
return -ENODEV;
}
- if (attr == &vol_reserved_ebs)
+ if (attr == &attr_vol_reserved_ebs)
ret = sprintf(buf, "%d\n", vol->reserved_pebs);
- else if (attr == &vol_type) {
+ else if (attr == &attr_vol_type) {
const char *tp;
- tp = vol->vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static";
+
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+ tp = "dynamic";
+ else
+ tp = "static";
ret = sprintf(buf, "%s\n", tp);
- } else if (attr == &vol_name)
+ } else if (attr == &attr_vol_name)
ret = sprintf(buf, "%s\n", vol->name);
- else if (attr == &vol_corrupted)
+ else if (attr == &attr_vol_corrupted)
ret = sprintf(buf, "%d\n", vol->corrupted);
- else if (attr == &vol_alignment)
+ else if (attr == &attr_vol_alignment)
ret = sprintf(buf, "%d\n", vol->alignment);
- else if (attr == &vol_usable_eb_size) {
+ else if (attr == &attr_vol_usable_eb_size) {
ret = sprintf(buf, "%d\n", vol->usable_leb_size);
- } else if (attr == &vol_data_bytes)
+ } else if (attr == &attr_vol_data_bytes)
ret = sprintf(buf, "%lld\n", vol->used_bytes);
- else if (attr == &vol_upd_marker)
+ else if (attr == &attr_vol_upd_marker)
ret = sprintf(buf, "%d\n", vol->upd_marker);
else
BUG();
@@ -126,28 +130,28 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
{
int err;
- err = device_create_file(&vol->dev, &vol_reserved_ebs);
+ err = device_create_file(&vol->dev, &attr_vol_reserved_ebs);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_type);
+ err = device_create_file(&vol->dev, &attr_vol_type);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_name);
+ err = device_create_file(&vol->dev, &attr_vol_name);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_corrupted);
+ err = device_create_file(&vol->dev, &attr_vol_corrupted);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_alignment);
+ err = device_create_file(&vol->dev, &attr_vol_alignment);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_usable_eb_size);
+ err = device_create_file(&vol->dev, &attr_vol_usable_eb_size);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_data_bytes);
+ err = device_create_file(&vol->dev, &attr_vol_data_bytes);
if (err)
return err;
- err = device_create_file(&vol->dev, &vol_upd_marker);
+ err = device_create_file(&vol->dev, &attr_vol_upd_marker);
if (err)
return err;
return 0;
@@ -159,14 +163,14 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol)
*/
static void volume_sysfs_close(struct ubi_volume *vol)
{
- device_remove_file(&vol->dev, &vol_upd_marker);
- device_remove_file(&vol->dev, &vol_data_bytes);
- device_remove_file(&vol->dev, &vol_usable_eb_size);
- device_remove_file(&vol->dev, &vol_alignment);
- device_remove_file(&vol->dev, &vol_corrupted);
- device_remove_file(&vol->dev, &vol_name);
- device_remove_file(&vol->dev, &vol_type);
- device_remove_file(&vol->dev, &vol_reserved_ebs);
+ device_remove_file(&vol->dev, &attr_vol_upd_marker);
+ device_remove_file(&vol->dev, &attr_vol_data_bytes);
+ device_remove_file(&vol->dev, &attr_vol_usable_eb_size);
+ device_remove_file(&vol->dev, &attr_vol_alignment);
+ device_remove_file(&vol->dev, &attr_vol_corrupted);
+ device_remove_file(&vol->dev, &attr_vol_name);
+ device_remove_file(&vol->dev, &attr_vol_type);
+ device_remove_file(&vol->dev, &attr_vol_reserved_ebs);
device_unregister(&vol->dev);
}
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index bc5df50813d..25b3bd61c7e 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -254,7 +254,7 @@ bad:
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
-static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si,
+static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
int copy, void *vtbl)
{
int err, tries = 0;
@@ -264,7 +264,7 @@ static int create_vtbl(const struct ubi_device *ubi, struct ubi_scan_info *si,
ubi_msg("create volume table (copy #%d)", copy + 1);
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vid_hdr)
return -ENOMEM;
@@ -339,7 +339,7 @@ out_free:
* not corrupted, and recovering from corruptions if needed. Returns volume
* table in case of success and a negative error code in case of failure.
*/
-static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
+static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
struct ubi_scan_info *si,
struct ubi_scan_volume *sv)
{
@@ -453,7 +453,7 @@ out_free:
* This function returns volume table contents in case of success and a
* negative error code in case of failure.
*/
-static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
+static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
struct ubi_scan_info *si)
{
int i;
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index a5a9b8d8730..6330c8cc72b 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -208,7 +208,7 @@ struct ubi_work {
};
#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID
-static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec);
+static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec);
static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
struct rb_root *root);
#else
@@ -220,17 +220,6 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e,
static struct kmem_cache *wl_entries_slab;
/**
- * tree_empty - a helper function to check if an RB-tree is empty.
- * @root: the root of the tree
- *
- * This function returns non-zero if the RB-tree is empty and zero if not.
- */
-static inline int tree_empty(struct rb_root *root)
-{
- return root->rb_node == NULL;
-}
-
-/**
* wl_tree_add - add a wear-leveling entry to a WL RB-tree.
* @e: the wear-leveling entry to add
* @root: the root of the tree
@@ -266,45 +255,6 @@ static void wl_tree_add(struct ubi_wl_entry *e, struct rb_root *root)
rb_insert_color(&e->rb, root);
}
-
-/*
- * Helper functions to add and delete wear-leveling entries from different
- * trees.
- */
-
-static void free_tree_add(struct ubi_device *ubi, struct ubi_wl_entry *e)
-{
- wl_tree_add(e, &ubi->free);
-}
-static inline void used_tree_add(struct ubi_device *ubi,
- struct ubi_wl_entry *e)
-{
- wl_tree_add(e, &ubi->used);
-}
-static inline void scrub_tree_add(struct ubi_device *ubi,
- struct ubi_wl_entry *e)
-{
- wl_tree_add(e, &ubi->scrub);
-}
-static inline void free_tree_del(struct ubi_device *ubi,
- struct ubi_wl_entry *e)
-{
- paranoid_check_in_wl_tree(e, &ubi->free);
- rb_erase(&e->rb, &ubi->free);
-}
-static inline void used_tree_del(struct ubi_device *ubi,
- struct ubi_wl_entry *e)
-{
- paranoid_check_in_wl_tree(e, &ubi->used);
- rb_erase(&e->rb, &ubi->used);
-}
-static inline void scrub_tree_del(struct ubi_device *ubi,
- struct ubi_wl_entry *e)
-{
- paranoid_check_in_wl_tree(e, &ubi->scrub);
- rb_erase(&e->rb, &ubi->scrub);
-}
-
/**
* do_work - do one pending work.
* @ubi: UBI device description object
@@ -358,7 +308,7 @@ static int produce_free_peb(struct ubi_device *ubi)
int err;
spin_lock(&ubi->wl_lock);
- while (tree_empty(&ubi->free)) {
+ while (!ubi->free.rb_node) {
spin_unlock(&ubi->wl_lock);
dbg_wl("do one work synchronously");
@@ -508,13 +458,13 @@ int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
dtype == UBI_UNKNOWN);
- pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_KERNEL);
+ pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_NOFS);
if (!pe)
return -ENOMEM;
retry:
spin_lock(&ubi->wl_lock);
- if (tree_empty(&ubi->free)) {
+ if (!ubi->free.rb_node) {
if (ubi->works_count == 0) {
ubi_assert(list_empty(&ubi->works));
ubi_err("no free eraseblocks");
@@ -585,7 +535,8 @@ retry:
* Move the physical eraseblock to the protection trees where it will
* be protected from being moved for some time.
*/
- free_tree_del(ubi, e);
+ paranoid_check_in_wl_tree(e, &ubi->free);
+ rb_erase(&e->rb, &ubi->free);
prot_tree_add(ubi, e, pe, protect);
dbg_wl("PEB %d EC %d, protection %d", e->pnum, e->ec, protect);
@@ -645,7 +596,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int tortur
if (err > 0)
return -EINVAL;
- ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr)
return -ENOMEM;
@@ -704,7 +655,7 @@ static void check_protection_over(struct ubi_device *ubi)
*/
while (1) {
spin_lock(&ubi->wl_lock);
- if (tree_empty(&ubi->prot.aec)) {
+ if (!ubi->prot.aec.rb_node) {
spin_unlock(&ubi->wl_lock);
break;
}
@@ -721,7 +672,7 @@ static void check_protection_over(struct ubi_device *ubi)
pe->e->pnum, ubi->abs_ec, pe->abs_ec);
rb_erase(&pe->rb_aec, &ubi->prot.aec);
rb_erase(&pe->rb_pnum, &ubi->prot.pnum);
- used_tree_add(ubi, pe->e);
+ wl_tree_add(pe->e, &ubi->used);
spin_unlock(&ubi->wl_lock);
kfree(pe);
@@ -768,7 +719,7 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
dbg_wl("schedule erasure of PEB %d, EC %d, torture %d",
e->pnum, e->ec, torture);
- wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL);
+ wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
if (!wl_wrk)
return -ENOMEM;
@@ -802,7 +753,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
if (cancel)
return 0;
- vid_hdr = ubi_zalloc_vid_hdr(ubi);
+ vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
if (!vid_hdr)
return -ENOMEM;
@@ -812,8 +763,8 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
* Only one WL worker at a time is supported at this implementation, so
* make sure a PEB is not being moved already.
*/
- if (ubi->move_to || tree_empty(&ubi->free) ||
- (tree_empty(&ubi->used) && tree_empty(&ubi->scrub))) {
+ if (ubi->move_to || !ubi->free.rb_node ||
+ (!ubi->used.rb_node && !ubi->scrub.rb_node)) {
/*
* Only one WL worker at a time is supported at this
* implementation, so if a LEB is already being moved, cancel.
@@ -828,14 +779,14 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
* triggered again.
*/
dbg_wl("cancel WL, a list is empty: free %d, used %d",
- tree_empty(&ubi->free), tree_empty(&ubi->used));
+ !ubi->free.rb_node, !ubi->used.rb_node);
ubi->wl_scheduled = 0;
spin_unlock(&ubi->wl_lock);
ubi_free_vid_hdr(ubi, vid_hdr);
return 0;
}
- if (tree_empty(&ubi->scrub)) {
+ if (!ubi->scrub.rb_node) {
/*
* Now pick the least worn-out used physical eraseblock and a
* highly worn-out free physical eraseblock. If the erase
@@ -852,17 +803,20 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
ubi_free_vid_hdr(ubi, vid_hdr);
return 0;
}
- used_tree_del(ubi, e1);
+ paranoid_check_in_wl_tree(e1, &ubi->used);
+ rb_erase(&e1->rb, &ubi->used);
dbg_wl("move PEB %d EC %d to PEB %d EC %d",
e1->pnum, e1->ec, e2->pnum, e2->ec);
} else {
e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, rb);
e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
- scrub_tree_del(ubi, e1);
+ paranoid_check_in_wl_tree(e1, &ubi->scrub);
+ rb_erase(&e1->rb, &ubi->scrub);
dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum);
}
- free_tree_del(ubi, e2);
+ paranoid_check_in_wl_tree(e2, &ubi->free);
+ rb_erase(&e2->rb, &ubi->free);
ubi_assert(!ubi->move_from && !ubi->move_to);
ubi_assert(!ubi->move_to_put && !ubi->move_from_put);
ubi->move_from = e1;
@@ -908,7 +862,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
ubi_free_vid_hdr(ubi, vid_hdr);
spin_lock(&ubi->wl_lock);
if (!ubi->move_to_put)
- used_tree_add(ubi, e2);
+ wl_tree_add(e2, &ubi->used);
else
put = 1;
ubi->move_from = ubi->move_to = NULL;
@@ -953,7 +907,7 @@ error:
if (ubi->move_from_put)
put = 1;
else
- used_tree_add(ubi, e1);
+ wl_tree_add(e1, &ubi->used);
ubi->move_from = ubi->move_to = NULL;
ubi->move_from_put = ubi->move_to_put = 0;
spin_unlock(&ubi->wl_lock);
@@ -1005,8 +959,8 @@ static int ensure_wear_leveling(struct ubi_device *ubi)
* If the ubi->scrub tree is not empty, scrubbing is needed, and the
* the WL worker has to be scheduled anyway.
*/
- if (tree_empty(&ubi->scrub)) {
- if (tree_empty(&ubi->used) || tree_empty(&ubi->free))
+ if (!ubi->scrub.rb_node) {
+ if (!ubi->used.rb_node || !ubi->free.rb_node)
/* No physical eraseblocks - no deal */
goto out_unlock;
@@ -1028,7 +982,7 @@ static int ensure_wear_leveling(struct ubi_device *ubi)
ubi->wl_scheduled = 1;
spin_unlock(&ubi->wl_lock);
- wrk = kmalloc(sizeof(struct ubi_work), GFP_KERNEL);
+ wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
if (!wrk) {
err = -ENOMEM;
goto out_cancel;
@@ -1079,7 +1033,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
spin_lock(&ubi->wl_lock);
ubi->abs_ec += 1;
- free_tree_add(ubi, e);
+ wl_tree_add(e, &ubi->free);
spin_unlock(&ubi->wl_lock);
/*
@@ -1093,6 +1047,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
return err;
}
+ ubi_err("failed to erase PEB %d, error %d", pnum, err);
kfree(wl_wrk);
kmem_cache_free(wl_entries_slab, e);
@@ -1211,11 +1166,13 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
spin_unlock(&ubi->wl_lock);
return 0;
} else {
- if (in_wl_tree(e, &ubi->used))
- used_tree_del(ubi, e);
- else if (in_wl_tree(e, &ubi->scrub))
- scrub_tree_del(ubi, e);
- else
+ if (in_wl_tree(e, &ubi->used)) {
+ paranoid_check_in_wl_tree(e, &ubi->used);
+ rb_erase(&e->rb, &ubi->used);
+ } else if (in_wl_tree(e, &ubi->scrub)) {
+ paranoid_check_in_wl_tree(e, &ubi->scrub);
+ rb_erase(&e->rb, &ubi->scrub);
+ } else
prot_tree_del(ubi, e->pnum);
}
spin_unlock(&ubi->wl_lock);
@@ -1223,7 +1180,7 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
err = schedule_erase(ubi, e, torture);
if (err) {
spin_lock(&ubi->wl_lock);
- used_tree_add(ubi, e);
+ wl_tree_add(e, &ubi->used);
spin_unlock(&ubi->wl_lock);
}
@@ -1267,12 +1224,13 @@ retry:
goto retry;
}
- if (in_wl_tree(e, &ubi->used))
- used_tree_del(ubi, e);
- else
+ if (in_wl_tree(e, &ubi->used)) {
+ paranoid_check_in_wl_tree(e, &ubi->used);
+ rb_erase(&e->rb, &ubi->used);
+ } else
prot_tree_del(ubi, pnum);
- scrub_tree_add(ubi, e);
+ wl_tree_add(e, &ubi->scrub);
spin_unlock(&ubi->wl_lock);
/*
@@ -1351,7 +1309,7 @@ static int ubi_thread(void *u)
struct ubi_device *ubi = u;
ubi_msg("background thread \"%s\" started, PID %d",
- ubi->bgt_name, current->pid);
+ ubi->bgt_name, task_pid_nr(current));
set_freezable();
for (;;) {
@@ -1488,7 +1446,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
e->pnum = seb->pnum;
e->ec = seb->ec;
ubi_assert(e->ec >= 0);
- free_tree_add(ubi, e);
+ wl_tree_add(e, &ubi->free);
ubi->lookuptbl[e->pnum] = e;
}
@@ -1522,16 +1480,16 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
if (!seb->scrub) {
dbg_wl("add PEB %d EC %d to the used tree",
e->pnum, e->ec);
- used_tree_add(ubi, e);
+ wl_tree_add(e, &ubi->used);
} else {
dbg_wl("add PEB %d EC %d to the scrub tree",
e->pnum, e->ec);
- scrub_tree_add(ubi, e);
+ wl_tree_add(e, &ubi->scrub);
}
}
}
- if (WL_RESERVED_PEBS > ubi->avail_pebs) {
+ if (ubi->avail_pebs < WL_RESERVED_PEBS) {
ubi_err("no enough physical eraseblocks (%d, need %d)",
ubi->avail_pebs, WL_RESERVED_PEBS);
goto out_free;
@@ -1624,13 +1582,13 @@ void ubi_wl_close(struct ubi_device *ubi)
* is equivalent to @ec, %1 if not, and a negative error code if an error
* occurred.
*/
-static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec)
+static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
{
int err;
long long read_ec;
struct ubi_ec_hdr *ec_hdr;
- ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
+ ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS);
if (!ec_hdr)
return -ENOMEM;
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 4bee99ba7db..be71868d151 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -174,8 +174,6 @@ struct net_device * __init el1_probe(int unit)
mem_start = dev->mem_start & 7;
}
- SET_MODULE_OWNER(dev);
-
if (io > 0x1ff) { /* Check a single specified location. */
err = el1_probe1(dev, io);
} else if (io != 0) {
@@ -317,7 +315,6 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr)
dev->tx_timeout = &el_timeout;
dev->watchdog_timeo = HZ;
dev->stop = &el1_close;
- dev->get_stats = &el1_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->ethtool_ops = &netdev_ethtool_ops;
return 0;
@@ -376,7 +373,7 @@ static void el_timeout(struct net_device *dev)
if (el_debug)
printk (KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS));
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
outb(TX_NORM, TX_CMD);
outb(RX_NORM, RX_CMD);
outb(AX_OFF, AX_CMD); /* Just trigger a false interrupt. */
@@ -443,7 +440,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
lp->tx_pkt_start = gp_start;
lp->collisions = 0;
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
/*
* Command mode with status cleared should [in theory]
@@ -590,7 +587,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id)
printk (KERN_DEBUG "%s: Transmit failed 16 times, Ethernet jammed?\n",dev->name);
outb(AX_SYS, AX_CMD);
lp->txing = 0;
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
netif_wake_queue(dev);
}
else if (txsr & TX_COLLISION)
@@ -608,7 +605,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id)
outb(AX_SYS, AX_CMD);
outw(lp->tx_pkt_start, GP_LOW);
outb(AX_XMIT, AX_CMD);
- lp->stats.collisions++;
+ dev->stats.collisions++;
spin_unlock(&lp->lock);
goto out;
}
@@ -617,7 +614,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id)
/*
* It worked.. we will now fall through and receive
*/
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
if (el_debug > 6)
printk(KERN_DEBUG " Tx succeeded %s\n",
(txsr & TX_RDY) ? "." : "but tx is busy!");
@@ -642,10 +639,10 @@ static irqreturn_t el_interrupt(int irq, void *dev_id)
* Just reading rx_status fixes most errors.
*/
if (rxsr & RX_MISSED)
- lp->stats.rx_missed_errors++;
+ dev->stats.rx_missed_errors++;
else if (rxsr & RX_RUNT)
{ /* Handled to avoid board lock-up. */
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (el_debug > 5)
printk(KERN_DEBUG " runt.\n");
}
@@ -696,7 +693,6 @@ out:
static void el_receive(struct net_device *dev)
{
- struct net_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int pkt_len;
struct sk_buff *skb;
@@ -710,7 +706,7 @@ static void el_receive(struct net_device *dev)
{
if (el_debug)
printk(KERN_DEBUG "%s: bogus packet, length=%d\n", dev->name, pkt_len);
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
return;
}
@@ -729,7 +725,7 @@ static void el_receive(struct net_device *dev)
if (skb == NULL)
{
printk(KERN_INFO "%s: Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
else
@@ -744,8 +740,8 @@ static void el_receive(struct net_device *dev)
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes+=pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes+=pkt_len;
}
return;
}
@@ -813,23 +809,6 @@ static int el1_close(struct net_device *dev)
}
/**
- * el1_get_stats:
- * @dev: The card to get the statistics for
- *
- * In smarter devices this function is needed to pull statistics off the
- * board itself. The 3c501 has no hardware statistics. We maintain them all
- * so they are by definition always up to date.
- *
- * Returns the statistics for the card from the card private data
- */
-
-static struct net_device_stats *el1_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
-/**
* set_multicast_list:
* @dev: The device to adjust
*
diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h
index c56a2c62f7d..cfec64efff7 100644
--- a/drivers/net/3c501.h
+++ b/drivers/net/3c501.h
@@ -11,7 +11,6 @@ static irqreturn_t el_interrupt(int irq, void *dev_id);
static void el_receive(struct net_device *dev);
static void el_reset(struct net_device *dev);
static int el1_close(struct net_device *dev);
-static struct net_device_stats *el1_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static const struct ethtool_ops netdev_ethtool_ops;
@@ -29,7 +28,6 @@ static int el_debug = EL_DEBUG;
struct net_local
{
- struct net_device_stats stats;
int tx_pkt_start; /* The length of the current Tx packet. */
int collisions; /* Tx collisions this packet */
int loading; /* Spot buffer load collisions */
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index bc7e906571d..9c23336750e 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -95,8 +95,6 @@ static int __init do_el2_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) /* Check a single specified location. */
return el2_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
@@ -179,6 +177,7 @@ el2_probe1(struct net_device *dev, int ioaddr)
int i, iobase_reg, membase_reg, saved_406, wordlength, retval;
static unsigned version_printed;
unsigned long vendor_id;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, EL2_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -228,7 +227,8 @@ el2_probe1(struct net_device *dev, int ioaddr)
/* Retrieve and print the ethernet address. */
for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+ dev->dev_addr[i] = inb(ioaddr + i);
+ printk("%s", print_mac(mac, dev->dev_addr));
/* Map the 8390 back into the window. */
outb(ECNTRL_THIN, ioaddr + 0x406);
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index e985a85a562..9c6573419f5 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -169,21 +169,6 @@ static int elp_debug;
/*****************************************************************
*
- * useful macros
- *
- *****************************************************************/
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-
-/*****************************************************************
- *
* List of I/O-addresses we try to auto-sense
* Last element MUST BE 0!
*****************************************************************/
@@ -270,7 +255,7 @@ static inline void set_hsf(struct net_device *dev, int hsf)
spin_unlock_irqrestore(&adapter->lock, flags);
}
-static int start_receive(struct net_device *, pcb_struct *);
+static bool start_receive(struct net_device *, pcb_struct *);
static inline void adapter_reset(struct net_device *dev)
{
@@ -328,28 +313,28 @@ static inline void check_3c505_dma(struct net_device *dev)
}
/* Primitive functions used by send_pcb() */
-static inline unsigned int send_pcb_slow(unsigned int base_addr, unsigned char byte)
+static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte)
{
unsigned long timeout;
outb_command(byte, base_addr);
for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
if (inb_status(base_addr) & HCRE)
- return FALSE;
+ return false;
}
printk(KERN_WARNING "3c505: send_pcb_slow timed out\n");
- return TRUE;
+ return true;
}
-static inline unsigned int send_pcb_fast(unsigned int base_addr, unsigned char byte)
+static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte)
{
unsigned int timeout;
outb_command(byte, base_addr);
for (timeout = 0; timeout < 40000; timeout++) {
if (inb_status(base_addr) & HCRE)
- return FALSE;
+ return false;
}
printk(KERN_WARNING "3c505: send_pcb_fast timed out\n");
- return TRUE;
+ return true;
}
/* Check to see if the receiver needs restarting, and kick it if so */
@@ -386,7 +371,7 @@ static inline void prime_rx(struct net_device *dev)
* timeout is reduced to 500us).
*/
-static int send_pcb(struct net_device *dev, pcb_struct * pcb)
+static bool send_pcb(struct net_device *dev, pcb_struct * pcb)
{
int i;
unsigned long timeout;
@@ -396,14 +381,14 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb)
check_3c505_dma(dev);
if (adapter->dmaing && adapter->current_dma.direction == 0)
- return FALSE;
+ return false;
/* Avoid contention */
if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
if (elp_debug >= 3) {
printk(KERN_DEBUG "%s: send_pcb entered while threaded\n", dev->name);
}
- return FALSE;
+ return false;
}
/*
* load each byte into the command register and
@@ -435,7 +420,7 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb)
switch (GET_ASF(dev->base_addr)) {
case ASF_PCB_ACK:
adapter->send_pcb_semaphore = 0;
- return TRUE;
+ return true;
case ASF_PCB_NAK:
#ifdef ELP_DEBUG
@@ -453,7 +438,7 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb)
spin_unlock_irqrestore(&adapter->lock, flags);
abort:
adapter->send_pcb_semaphore = 0;
- return FALSE;
+ return false;
}
@@ -470,7 +455,7 @@ static int send_pcb(struct net_device *dev, pcb_struct * pcb)
*
*****************************************************************/
-static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
+static bool receive_pcb(struct net_device *dev, pcb_struct * pcb)
{
int i, j;
int total_length;
@@ -487,7 +472,7 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
if (time_after_eq(jiffies, timeout)) {
TIMEOUT_MSG(__LINE__);
- return FALSE;
+ return false;
}
pcb->command = inb_command(dev->base_addr);
@@ -497,14 +482,14 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
if (time_after_eq(jiffies, timeout)) {
TIMEOUT_MSG(__LINE__);
printk(KERN_INFO "%s: status %02x\n", dev->name, stat);
- return FALSE;
+ return false;
}
pcb->length = inb_command(dev->base_addr);
if (pcb->length > MAX_PCB_DATA) {
INVALID_PCB_MSG(pcb->length);
adapter_reset(dev);
- return FALSE;
+ return false;
}
/* read the data */
spin_lock_irqsave(&adapter->lock, flags);
@@ -519,7 +504,7 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
spin_unlock_irqrestore(&adapter->lock, flags);
if (j >= 20000) {
TIMEOUT_MSG(__LINE__);
- return FALSE;
+ return false;
}
/* woops, the last "data" byte was really the length! */
total_length = pcb->data.raw[--i];
@@ -529,7 +514,7 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
if (elp_debug >= 2)
printk(KERN_WARNING "%s: mangled PCB received\n", dev->name);
set_hsf(dev, HSF_PCB_NAK);
- return FALSE;
+ return false;
}
if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
@@ -538,14 +523,14 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
set_hsf(dev, HSF_PCB_NAK);
printk(KERN_WARNING "%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
pcb->command = 0;
- return TRUE;
+ return true;
} else {
pcb->command = 0xff;
}
}
}
set_hsf(dev, HSF_PCB_ACK);
- return TRUE;
+ return true;
}
/******************************************************
@@ -555,9 +540,9 @@ static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
*
******************************************************/
-static int start_receive(struct net_device *dev, pcb_struct * tx_pcb)
+static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb)
{
- int status;
+ bool status;
elp_device *adapter = dev->priv;
if (elp_debug >= 3)
@@ -984,7 +969,7 @@ static int elp_open(struct net_device *dev)
*
******************************************************/
-static int send_packet(struct net_device *dev, struct sk_buff *skb)
+static bool send_packet(struct net_device *dev, struct sk_buff *skb)
{
elp_device *adapter = dev->priv;
unsigned long target;
@@ -998,7 +983,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb)
if (test_and_set_bit(0, (void *) &adapter->busy)) {
if (elp_debug >= 2)
printk(KERN_DEBUG "%s: transmit blocked\n", dev->name);
- return FALSE;
+ return false;
}
adapter->stats.tx_bytes += nlen;
@@ -1015,7 +1000,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb)
if (!send_pcb(dev, &adapter->tx_pcb)) {
adapter->busy = 0;
- return FALSE;
+ return false;
}
/* if this happens, we die */
if (test_and_set_bit(0, (void *) &adapter->dmaing))
@@ -1047,7 +1032,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb)
if (elp_debug >= 3)
printk(KERN_DEBUG "%s: DMA transfer started\n", dev->name);
- return TRUE;
+ return true;
}
/*
@@ -1401,8 +1386,7 @@ static int __init elplus_setup(struct net_device *dev)
unsigned long timeout;
unsigned long cookie = 0;
int err = -ENODEV;
-
- SET_MODULE_OWNER(dev);
+ DECLARE_MAC_BUF(mac);
/*
* setup adapter structure
@@ -1538,11 +1522,10 @@ static int __init elplus_setup(struct net_device *dev)
/*
* print remainder of startup message
*/
- printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, ",
- dev->name, dev->base_addr, dev->irq, dev->dma);
- printk("addr %02x:%02x:%02x:%02x:%02x:%02x, ",
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, "
+ "addr %s, ",
+ dev->name, dev->base_addr, dev->irq, dev->dma,
+ print_mac(mac, dev->dev_addr));
/*
* read more information from the adapter
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index eed4299dc42..964d31ac944 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -118,7 +118,6 @@ enum commands {
/* Information that need to be kept for each board. */
struct net_local {
- struct net_device_stats stats;
int last_restart;
ushort rx_head;
ushort rx_tail;
@@ -289,7 +288,6 @@ static int el16_send_packet(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t el16_interrupt(int irq, void *dev_id);
static void el16_rx(struct net_device *dev);
static int el16_close(struct net_device *dev);
-static struct net_device_stats *el16_get_stats(struct net_device *dev);
static void el16_tx_timeout (struct net_device *dev);
static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
@@ -327,8 +325,6 @@ struct net_device * __init el16_probe(int unit)
mem_start = dev->mem_start & 15;
}
- SET_MODULE_OWNER(dev);
-
if (io > 0x1ff) /* Check a single specified location. */
err = el16_probe1(dev, io);
else if (io != 0)
@@ -361,6 +357,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
static unsigned char init_ID_done, version_printed;
int i, irq, irqval, retval;
struct net_local *lp;
+ DECLARE_MAC_BUF(mac);
if (init_ID_done == 0) {
ushort lrs_state = 0xff;
@@ -406,10 +403,9 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
dev->base_addr = ioaddr;
outb(0x01, ioaddr + MISC_CTRL);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
dev->dev_addr[i] = inb(ioaddr + i);
- printk(" %02x", dev->dev_addr[i]);
- }
+ printk(" %s", print_mac(mac, dev->dev_addr));
if (mem_start)
net_debug = mem_start & 7;
@@ -457,7 +453,6 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
dev->open = el16_open;
dev->stop = el16_close;
dev->hard_start_xmit = el16_send_packet;
- dev->get_stats = el16_get_stats;
dev->tx_timeout = el16_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
dev->ethtool_ops = &netdev_ethtool_ops;
@@ -491,7 +486,7 @@ static void el16_tx_timeout (struct net_device *dev)
readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
"network cable problem");
/* Try to restart the adaptor. */
- if (lp->last_restart == lp->stats.tx_packets) {
+ if (lp->last_restart == dev->stats.tx_packets) {
if (net_debug > 1)
printk ("Resetting board.\n");
/* Completely reset the adaptor. */
@@ -503,7 +498,7 @@ static void el16_tx_timeout (struct net_device *dev)
printk ("Kicking board.\n");
writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);
outb (0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */
- lp->last_restart = lp->stats.tx_packets;
+ lp->last_restart = dev->stats.tx_packets;
}
dev->trans_start = jiffies;
netif_wake_queue (dev);
@@ -522,7 +517,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave (&lp->lock, flags);
- lp->stats.tx_bytes += length;
+ dev->stats.tx_bytes += length;
/* Disable the 82586's input to the interrupt line. */
outb (0x80, ioaddr + MISC_CTRL);
@@ -581,14 +576,14 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id)
}
/* Tx unsuccessful or some interesting status bit set. */
if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) {
- lp->stats.tx_errors++;
- if (tx_status & 0x0600) lp->stats.tx_carrier_errors++;
- if (tx_status & 0x0100) lp->stats.tx_fifo_errors++;
- if (!(tx_status & 0x0040)) lp->stats.tx_heartbeat_errors++;
- if (tx_status & 0x0020) lp->stats.tx_aborted_errors++;
- lp->stats.collisions += tx_status & 0xf;
+ dev->stats.tx_errors++;
+ if (tx_status & 0x0600) dev->stats.tx_carrier_errors++;
+ if (tx_status & 0x0100) dev->stats.tx_fifo_errors++;
+ if (!(tx_status & 0x0040)) dev->stats.tx_heartbeat_errors++;
+ if (tx_status & 0x0020) dev->stats.tx_aborted_errors++;
+ dev->stats.collisions += tx_status & 0xf;
}
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
if (net_debug > 5)
printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
lp->tx_reap += TX_BUF_SIZE;
@@ -667,17 +662,6 @@ static int el16_close(struct net_device *dev)
return 0;
}
-/* Get the current statistics. This may be called with the card open or
- closed. */
-static struct net_device_stats *el16_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
-
- /* ToDo: decide if there are any useful statistics from the SCB. */
-
- return &lp->stats;
-}
-
/* Initialize the Rx-block list. */
static void init_rx_bufs(struct net_device *dev)
{
@@ -854,12 +838,12 @@ static void el16_rx(struct net_device *dev)
pkt_len);
} else if ((frame_status & 0x2000) == 0) {
/* Frame Rxed, but with error. */
- lp->stats.rx_errors++;
- if (frame_status & 0x0800) lp->stats.rx_crc_errors++;
- if (frame_status & 0x0400) lp->stats.rx_frame_errors++;
- if (frame_status & 0x0200) lp->stats.rx_fifo_errors++;
- if (frame_status & 0x0100) lp->stats.rx_over_errors++;
- if (frame_status & 0x0080) lp->stats.rx_length_errors++;
+ dev->stats.rx_errors++;
+ if (frame_status & 0x0800) dev->stats.rx_crc_errors++;
+ if (frame_status & 0x0400) dev->stats.rx_frame_errors++;
+ if (frame_status & 0x0200) dev->stats.rx_fifo_errors++;
+ if (frame_status & 0x0100) dev->stats.rx_over_errors++;
+ if (frame_status & 0x0080) dev->stats.rx_length_errors++;
} else {
/* Malloc up new buffer. */
struct sk_buff *skb;
@@ -868,7 +852,7 @@ static void el16_rx(struct net_device *dev)
skb = dev_alloc_skb(pkt_len+2);
if (skb == NULL) {
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
@@ -880,8 +864,8 @@ static void el16_rx(struct net_device *dev)
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
/* Clear the status word and set End-of-List on the rx frame. */
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 127f60841b1..edda6e10ebe 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -299,7 +299,7 @@ static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
{ } /* terminate list */
};
-static u16 el3_isapnp_phys_addr[8][3];
+static __be16 el3_isapnp_phys_addr[8][3];
static int nopnp;
#endif /* __ISAPNP__ */
@@ -313,8 +313,9 @@ static int nopnp;
static int __init el3_common_init(struct net_device *dev)
{
struct el3_private *lp = netdev_priv(dev);
- short i;
int err;
+ DECLARE_MAC_BUF(mac);
+ const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
spin_lock_init(&lp->lock);
@@ -346,17 +347,10 @@ static int __init el3_common_init(struct net_device *dev)
return err;
}
- {
- const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
- printk("%s: 3c5x9 found at %#3.3lx, %s port, address ",
- dev->name, dev->base_addr,
- if_names[(dev->if_port & 0x03)]);
- }
-
- /* Read in the station address. */
- for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i]);
- printk(", IRQ %d.\n", dev->irq);
+ printk(KERN_INFO "%s: 3c5x9 found at %#3.3lx, %s port, "
+ "address %s, IRQ %d.\n",
+ dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)],
+ print_mac(mac, dev->dev_addr), dev->irq);
if (el3_debug > 0)
printk(KERN_INFO "%s", version);
@@ -385,7 +379,7 @@ static int __init el3_probe(int card_idx)
struct el3_private *lp;
short lrs_state = 0xff, i;
int ioaddr, irq, if_port;
- u16 phys_addr[3];
+ __be16 phys_addr[3];
static int current_tag;
int err = -ENODEV;
#if defined(__ISAPNP__)
@@ -432,7 +426,6 @@ __again:
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &idev->dev);
pnp_cards++;
@@ -524,8 +517,6 @@ no_pnp:
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
-
netdev_boot_setup_check(dev);
/* Set passed-in IRQ or I/O Addr. */
@@ -644,7 +635,6 @@ static int __init el3_mca_probe(struct device *device)
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
netdev_boot_setup_check(dev);
memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
@@ -704,8 +694,6 @@ static int __init el3_eisa_probe (struct device *device)
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
-
netdev_boot_setup_check(dev);
memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 290166d5e7d..275e7510eba 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -501,8 +501,6 @@ static struct net_device *corkscrew_scan(int unit)
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
-
#ifdef __ISAPNP__
if(nopnp == 1)
goto no_pnp;
@@ -571,6 +569,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr,
unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */
int i;
int irq;
+ DECLARE_MAC_BUF(mac);
if (idev) {
irq = pnp_irq(idev, 0);
@@ -632,8 +631,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr,
checksum = (checksum ^ (checksum >> 8)) & 0xff;
if (checksum != 0x00)
printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
- for (i = 0; i < 6; i++)
- printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
+ printk(" %s", print_mac(mac, dev->dev_addr));
if (eeprom[16] == 0x11c7) { /* Corkscrew */
if (request_dma(dev->dma, "3c515")) {
printk(", DMA %d allocation failed", dev->dma);
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index ab18343e58e..239fc42fb8d 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -383,8 +383,8 @@ void alloc586(struct net_device *dev)
static int elmc_getinfo(char *buf, int slot, void *d)
{
int len = 0;
- struct net_device *dev = (struct net_device *) d;
- int i;
+ struct net_device *dev = d;
+ DECLARE_MAC_BUF(mac);
if (dev == NULL)
return len;
@@ -399,12 +399,8 @@ static int elmc_getinfo(char *buf, int slot, void *d)
len += sprintf(buf + len, "Transceiver: %s\n", dev->if_port ?
"External" : "Internal");
len += sprintf(buf + len, "Device: %s\n", dev->name);
- len += sprintf(buf + len, "Hardware Address:");
- for (i = 0; i < 6; i++) {
- len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
- }
- buf[len++] = '\n';
- buf[len] = 0;
+ len += sprintf(buf + len, "Hardware Address: %s\n",
+ print_mac(mac, dev->dev_addr));
return len;
} /* elmc_getinfo() */
@@ -422,8 +418,8 @@ static int __init do_elmc_probe(struct net_device *dev)
unsigned int size = 0;
int retval;
struct priv *pr = dev->priv;
+ DECLARE_MAC_BUF(mac);
- SET_MODULE_OWNER(dev);
if (MCA_bus == 0) {
return -ENODEV;
}
@@ -545,12 +541,11 @@ static int __init do_elmc_probe(struct net_device *dev)
/* The hardware address for the 3c523 is stored in the first six
bytes of the IO address. */
- printk(KERN_INFO "%s: hardware address ", dev->name);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
dev->dev_addr[i] = inb(dev->base_addr + i);
- printk(" %02x", dev->dev_addr[i]);
- }
- printk("\n");
+
+ printk(KERN_INFO "%s: hardware address %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
dev->open = &elmc_open;
dev->stop = &elmc_close;
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index c7b571be20e..b72b89d53ec 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -257,8 +257,6 @@ struct net_device *__init mc32_probe(int unit)
if (unit >= 0)
sprintf(dev->name, "eth%d", unit);
- SET_MODULE_OWNER(dev);
-
/* Do not check any supplied i/o locations.
POS registers usually don't fail :) */
@@ -338,6 +336,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
"82586 initialisation failure",
"Adapter list configuration error"
};
+ DECLARE_MAC_BUF(mac);
/* Time to play MCA games */
@@ -398,17 +397,17 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
* Go PROM browsing
*/
- printk("%s: Address ", dev->name);
-
/* Retrieve and print the ethernet address. */
for (i = 0; i < 6; i++)
{
mca_write_pos(slot, 6, i+12);
mca_write_pos(slot, 7, 0);
- printk(" %2.2x", dev->dev_addr[i] = mca_read_pos(slot,3));
+ dev->dev_addr[i] = mca_read_pos(slot,3);
}
+ printk("%s: Address %s", dev->name, print_mac(mac, dev->dev_addr));
+
mca_write_pos(slot, 6, 0);
mca_write_pos(slot, 7, 0);
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index a8c0f436cdd..6f8e7d4cf74 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -538,10 +538,10 @@ enum MasterCtrl {
#define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */
#define DN_COMPLETE 0x00010000 /* This packet has been downloaded */
struct boom_rx_desc {
- u32 next; /* Last entry points to 0. */
- s32 status;
- u32 addr; /* Up to 63 addr/len pairs possible. */
- s32 length; /* Set LAST_FRAG to indicate last pair. */
+ __le32 next; /* Last entry points to 0. */
+ __le32 status;
+ __le32 addr; /* Up to 63 addr/len pairs possible. */
+ __le32 length; /* Set LAST_FRAG to indicate last pair. */
};
/* Values for the Rx status entry. */
enum rx_desc_status {
@@ -558,16 +558,16 @@ enum rx_desc_status {
#endif
struct boom_tx_desc {
- u32 next; /* Last entry points to 0. */
- s32 status; /* bits 0:12 length, others see below. */
+ __le32 next; /* Last entry points to 0. */
+ __le32 status; /* bits 0:12 length, others see below. */
#if DO_ZEROCOPY
struct {
- u32 addr;
- s32 length;
+ __le32 addr;
+ __le32 length;
} frag[1+MAX_SKB_FRAGS];
#else
- u32 addr;
- s32 length;
+ __le32 addr;
+ __le32 length;
#endif
};
@@ -705,7 +705,7 @@ static struct {
static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
int chip_idx, int card_idx);
-static void vortex_up(struct net_device *dev);
+static int vortex_up(struct net_device *dev);
static void vortex_down(struct net_device *dev, int final);
static int vortex_open(struct net_device *dev);
static void mdio_sync(void __iomem *ioaddr, int bits);
@@ -841,8 +841,11 @@ static int vortex_resume(struct pci_dev *pdev)
return -EBUSY;
}
if (netif_running(dev)) {
- vortex_up(dev);
- netif_device_attach(dev);
+ err = vortex_up(dev);
+ if (err)
+ return err;
+ else
+ netif_device_attach(dev);
}
}
return 0;
@@ -1011,6 +1014,7 @@ static int __devinit vortex_probe1(struct device *gendev,
char *print_name = "3c59x";
struct pci_dev *pdev = NULL;
struct eisa_device *edev = NULL;
+ DECLARE_MAC_BUF(mac);
if (!printed_version) {
printk (version);
@@ -1033,7 +1037,6 @@ static int __devinit vortex_probe1(struct device *gendev,
printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n");
goto out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, gendev);
vp = netdev_priv(dev);
@@ -1128,7 +1131,7 @@ static int __devinit vortex_probe1(struct device *gendev,
+ sizeof(struct boom_tx_desc) * TX_RING_SIZE,
&vp->rx_ring_dma);
retval = -ENOMEM;
- if (vp->rx_ring == 0)
+ if (!vp->rx_ring)
goto free_region;
vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE);
@@ -1201,12 +1204,10 @@ static int __devinit vortex_probe1(struct device *gendev,
if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO))
printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
for (i = 0; i < 3; i++)
- ((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
+ ((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
- if (print_info) {
- for (i = 0; i < 6; i++)
- printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
- }
+ if (print_info)
+ printk(" %s", print_mac(mac, dev->dev_addr));
/* Unfortunately an all zero eeprom passes the checksum and this
gets found in the wild in failure cases. Crypto is hard 8) */
if (!is_valid_ether_addr(dev->dev_addr)) {
@@ -1484,19 +1485,24 @@ static void vortex_check_media(struct net_device *dev, unsigned int init)
}
}
-static void
+static int
vortex_up(struct net_device *dev)
{
struct vortex_private *vp = netdev_priv(dev);
void __iomem *ioaddr = vp->ioaddr;
unsigned int config;
- int i, mii_reg1, mii_reg5;
+ int i, mii_reg1, mii_reg5, err = 0;
if (VORTEX_PCI(vp)) {
pci_set_power_state(VORTEX_PCI(vp), PCI_D0); /* Go active */
if (vp->pm_state_valid)
pci_restore_state(VORTEX_PCI(vp));
- pci_enable_device(VORTEX_PCI(vp));
+ err = pci_enable_device(VORTEX_PCI(vp));
+ if (err) {
+ printk(KERN_WARNING "%s: Could not enable device \n",
+ dev->name);
+ goto err_out;
+ }
}
/* Before initializing select the active media port. */
@@ -1661,6 +1667,8 @@ vortex_up(struct net_device *dev)
if (vp->cb_fn_base) /* The PCMCIA people are idiots. */
iowrite32(0x8000, vp->cb_fn_base + 4);
netif_start_queue (dev);
+err_out:
+ return err;
}
static int
@@ -1674,7 +1682,7 @@ vortex_open(struct net_device *dev)
if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ?
&boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev))) {
printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
- goto out;
+ goto err;
}
if (vp->full_bus_master_rx) { /* Boomerang bus master. */
@@ -1703,20 +1711,22 @@ vortex_open(struct net_device *dev)
}
}
retval = -ENOMEM;
- goto out_free_irq;
+ goto err_free_irq;
}
/* Wrap the ring. */
vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
}
- vortex_up(dev);
- return 0;
+ retval = vortex_up(dev);
+ if (!retval)
+ goto out;
-out_free_irq:
+err_free_irq:
free_irq(dev->irq, dev);
-out:
+err:
if (vortex_debug > 1)
printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval);
+out:
return retval;
}
@@ -2490,7 +2500,7 @@ boomerang_rx(struct net_device *dev)
/* Check if the packet is long enough to just accept without
copying to a properly sized skbuff. */
- if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
+ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
/* 'skb_put()' points to the start of sk_buff data area. */
@@ -2823,9 +2833,14 @@ static void vortex_set_msglevel(struct net_device *dev, u32 dbg)
vortex_debug = dbg;
}
-static int vortex_get_stats_count(struct net_device *dev)
+static int vortex_get_sset_count(struct net_device *dev, int sset)
{
- return VORTEX_NUM_STATS;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return VORTEX_NUM_STATS;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void vortex_get_ethtool_stats(struct net_device *dev,
@@ -2882,7 +2897,7 @@ static const struct ethtool_ops vortex_ethtool_ops = {
.get_msglevel = vortex_get_msglevel,
.set_msglevel = vortex_set_msglevel,
.get_ethtool_stats = vortex_get_ethtool_stats,
- .get_stats_count = vortex_get_stats_count,
+ .get_sset_count = vortex_get_sset_count,
.get_settings = vortex_get_settings,
.set_settings = vortex_set_settings,
.get_link = ethtool_op_get_link,
@@ -2899,7 +2914,7 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
struct vortex_private *vp = netdev_priv(dev);
void __iomem *ioaddr = vp->ioaddr;
unsigned long flags;
- int state = 0;
+ pci_power_t state = 0;
if(VORTEX_PCI(vp))
state = VORTEX_PCI(vp)->current_state;
@@ -3103,7 +3118,13 @@ static void acpi_set_WOL(struct net_device *dev)
iowrite16(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
iowrite16(RxEnable, ioaddr + EL3_CMD);
- pci_enable_wake(VORTEX_PCI(vp), 0, 1);
+ if (pci_enable_wake(VORTEX_PCI(vp), PCI_D3hot, 1)) {
+ printk(KERN_INFO "%s: WOL not supported.\n",
+ pci_name(VORTEX_PCI(vp)));
+
+ vp->enable_wol = 0;
+ return;
+ }
/* Change the power state to D3; RxEnable doesn't take effect. */
pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot);
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index e89ace109a5..224e0bff1ae 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -305,18 +305,18 @@ static int lance_rx (struct net_device *dev)
/* We got an incomplete frame? */
if ((bits & LE_R1_POK) != LE_R1_POK) {
- lp->stats.rx_over_errors++;
- lp->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
continue;
} else if (bits & LE_R1_ERR) {
/* Count only the end frame as a rx error,
* not the beginning
*/
- if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
- if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
- if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
- if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
- if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+ if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++;
+ if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++;
+ if (bits & LE_R1_OFL) dev->stats.rx_over_errors++;
+ if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
+ if (bits & LE_R1_EOP) dev->stats.rx_errors++;
} else {
len = (rd->mblength & 0xfff) - 4;
skb = dev_alloc_skb (len+2);
@@ -324,7 +324,7 @@ static int lance_rx (struct net_device *dev)
if (skb == 0) {
printk ("%s: Memory squeeze, deferring packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
rd->mblength = 0;
rd->rmd1_bits = LE_R1_OWN;
lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
@@ -339,8 +339,8 @@ static int lance_rx (struct net_device *dev)
skb->protocol = eth_type_trans (skb, dev);
netif_rx (skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
}
/* Return the packet to the pool */
@@ -377,12 +377,12 @@ static int lance_tx (struct net_device *dev)
if (td->tmd1_bits & LE_T1_ERR) {
status = td->misc;
- lp->stats.tx_errors++;
- if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
- if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
+ if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) dev->stats.tx_window_errors++;
if (status & LE_T3_CLOS) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (lp->auto_select) {
lp->tpe = 1 - lp->tpe;
printk("%s: Carrier Lost, trying %s\n",
@@ -400,7 +400,7 @@ static int lance_tx (struct net_device *dev)
/* buffer errors and underflows turn off the transmitter */
/* Restart the adapter */
if (status & (LE_T3_BUF|LE_T3_UFL)) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
dev->name);
@@ -420,13 +420,13 @@ static int lance_tx (struct net_device *dev)
/* One collision before packet was sent. */
if (td->tmd1_bits & LE_T1_EONE)
- lp->stats.collisions++;
+ dev->stats.collisions++;
/* More than one collision, be optimistic. */
if (td->tmd1_bits & LE_T1_EMORE)
- lp->stats.collisions += 2;
+ dev->stats.collisions += 2;
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
j = (j + 1) & lp->tx_ring_mod_mask;
@@ -471,9 +471,9 @@ lance_interrupt (int irq, void *dev_id)
/* Log misc errors. */
if (csr0 & LE_C0_BABL)
- lp->stats.tx_errors++; /* Tx babble. */
+ dev->stats.tx_errors++; /* Tx babble. */
if (csr0 & LE_C0_MISS)
- lp->stats.rx_errors++; /* Missed a Rx frame. */
+ dev->stats.rx_errors++; /* Missed a Rx frame. */
if (csr0 & LE_C0_MERR) {
printk("%s: Bus master arbitration failure, status %4.4x.\n",
dev->name, csr0);
@@ -589,13 +589,6 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
return 0;
}
-struct net_device_stats *lance_get_stats (struct net_device *dev)
-{
- struct lance_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/* taken from the depca driver via a2065.c */
static void lance_load_multicast (struct net_device *dev)
{
diff --git a/drivers/net/7990.h b/drivers/net/7990.h
index b1212b5ed92..0a5837b9642 100644
--- a/drivers/net/7990.h
+++ b/drivers/net/7990.h
@@ -111,7 +111,6 @@ struct lance_private
int lance_log_rx_bufs, lance_log_tx_bufs;
int rx_ring_mod_mask, tx_ring_mod_mask;
- struct net_device_stats stats;
int tpe; /* TPE is selected */
int auto_select; /* cable-selection is by carrier */
unsigned short busmaster_regval;
@@ -246,7 +245,6 @@ struct lance_private
extern int lance_open(struct net_device *dev);
extern int lance_close (struct net_device *dev);
extern int lance_start_xmit (struct sk_buff *skb, struct net_device *dev);
-extern struct net_device_stats *lance_get_stats (struct net_device *dev);
extern void lance_set_multicast (struct net_device *dev);
extern void lance_tx_timeout(struct net_device *dev);
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index a79f28c7a10..a453eda834d 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -78,7 +78,7 @@
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#define CP_VLAN_TAG_USED 1
#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \
- do { (tx_desc)->opts2 = (vlan_tag_value); } while (0)
+ do { (tx_desc)->opts2 = cpu_to_le32(vlan_tag_value); } while (0)
#else
#define CP_VLAN_TAG_USED 0
#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \
@@ -303,25 +303,25 @@ static const unsigned int cp_rx_config =
(RX_DMA_BURST << RxCfgDMAShift);
struct cp_desc {
- u32 opts1;
- u32 opts2;
- u64 addr;
+ __le32 opts1;
+ __le32 opts2;
+ __le64 addr;
};
struct cp_dma_stats {
- u64 tx_ok;
- u64 rx_ok;
- u64 tx_err;
- u32 rx_err;
- u16 rx_fifo;
- u16 frame_align;
- u32 tx_ok_1col;
- u32 tx_ok_mcol;
- u64 rx_ok_phys;
- u64 rx_ok_bcast;
- u32 rx_ok_mcast;
- u16 tx_abort;
- u16 tx_underrun;
+ __le64 tx_ok;
+ __le64 rx_ok;
+ __le64 tx_err;
+ __le32 rx_err;
+ __le16 rx_fifo;
+ __le16 frame_align;
+ __le32 tx_ok_1col;
+ __le32 tx_ok_mcol;
+ __le64 rx_ok_phys;
+ __le64 rx_ok_bcast;
+ __le32 rx_ok_mcast;
+ __le16 tx_abort;
+ __le16 tx_underrun;
} __attribute__((packed));
struct cp_extra_stats {
@@ -334,6 +334,8 @@ struct cp_private {
spinlock_t lock;
u32 msg_enable;
+ struct napi_struct napi;
+
struct pci_dev *pdev;
u32 rx_config;
u16 cpcmd;
@@ -460,9 +462,9 @@ static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb,
cp->dev->last_rx = jiffies;
#if CP_VLAN_TAG_USED
- if (cp->vlgrp && (desc->opts2 & RxVlanTagged)) {
+ if (cp->vlgrp && (desc->opts2 & cpu_to_le32(RxVlanTagged))) {
vlan_hwaccel_receive_skb(skb, cp->vlgrp,
- be16_to_cpu(desc->opts2 & 0xffff));
+ swab16(le32_to_cpu(desc->opts2) & 0xffff));
} else
#endif
netif_receive_skb(skb);
@@ -501,12 +503,12 @@ static inline unsigned int cp_rx_csum_ok (u32 status)
return 0;
}
-static int cp_rx_poll (struct net_device *dev, int *budget)
+static int cp_rx_poll(struct napi_struct *napi, int budget)
{
- struct cp_private *cp = netdev_priv(dev);
- unsigned rx_tail = cp->rx_tail;
- unsigned rx_work = dev->quota;
- unsigned rx;
+ struct cp_private *cp = container_of(napi, struct cp_private, napi);
+ struct net_device *dev = cp->dev;
+ unsigned int rx_tail = cp->rx_tail;
+ int rx;
rx_status_loop:
rx = 0;
@@ -560,7 +562,7 @@ rx_status_loop:
skb_reserve(new_skb, RX_OFFSET);
- pci_unmap_single(cp->pdev, mapping,
+ dma_unmap_single(&cp->pdev->dev, mapping,
buflen, PCI_DMA_FROMDEVICE);
/* Handle checksum offloading for incoming packets. */
@@ -571,7 +573,7 @@ rx_status_loop:
skb_put(skb, len);
- mapping = pci_map_single(cp->pdev, new_skb->data, buflen,
+ mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen,
PCI_DMA_FROMDEVICE);
cp->rx_skb[rx_tail] = new_skb;
@@ -588,33 +590,28 @@ rx_next:
desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
rx_tail = NEXT_RX(rx_tail);
- if (!rx_work--)
+ if (rx >= budget)
break;
}
cp->rx_tail = rx_tail;
- dev->quota -= rx;
- *budget -= rx;
-
/* if we did not reach work limit, then we're done with
* this round of polling
*/
- if (rx_work) {
+ if (rx < budget) {
unsigned long flags;
if (cpr16(IntrStatus) & cp_rx_intr_mask)
goto rx_status_loop;
- local_irq_save(flags);
+ spin_lock_irqsave(&cp->lock, flags);
cpw16_f(IntrMask, cp_intr_mask);
- __netif_rx_complete(dev);
- local_irq_restore(flags);
-
- return 0; /* done */
+ __netif_rx_complete(dev, napi);
+ spin_unlock_irqrestore(&cp->lock, flags);
}
- return 1; /* not done */
+ return rx;
}
static irqreturn_t cp_interrupt (int irq, void *dev_instance)
@@ -647,9 +644,9 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
}
if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &cp->napi)) {
cpw16_f(IntrMask, cp_norx_intr_mask);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &cp->napi);
}
if (status & (TxOK | TxErr | TxEmpty | SWInt))
@@ -704,7 +701,7 @@ static void cp_tx (struct cp_private *cp)
skb = cp->tx_skb[tx_tail];
BUG_ON(!skb);
- pci_unmap_single(cp->pdev, le64_to_cpu(txd->addr),
+ dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
le32_to_cpu(txd->opts1) & 0xffff,
PCI_DMA_TODEVICE);
@@ -768,7 +765,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
#if CP_VLAN_TAG_USED
if (cp->vlgrp && vlan_tx_tag_present(skb))
- vlan_tag = TxVlanTag | cpu_to_be16(vlan_tx_tag_get(skb));
+ vlan_tag = TxVlanTag | swab16(vlan_tx_tag_get(skb));
#endif
entry = cp->tx_head;
@@ -782,7 +779,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
dma_addr_t mapping;
len = skb->len;
- mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+ mapping = dma_map_single(&cp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
CP_VLAN_TX_TAG(txd, vlan_tag);
txd->addr = cpu_to_le64(mapping);
wmb();
@@ -818,7 +815,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
*/
first_eor = eor;
first_len = skb_headlen(skb);
- first_mapping = pci_map_single(cp->pdev, skb->data,
+ first_mapping = dma_map_single(&cp->pdev->dev, skb->data,
first_len, PCI_DMA_TODEVICE);
cp->tx_skb[entry] = skb;
entry = NEXT_TX(entry);
@@ -830,7 +827,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
dma_addr_t mapping;
len = this_frag->size;
- mapping = pci_map_single(cp->pdev,
+ mapping = dma_map_single(&cp->pdev->dev,
((void *) page_address(this_frag->page) +
this_frag->page_offset),
len, PCI_DMA_TODEVICE);
@@ -1021,8 +1018,8 @@ static void cp_init_hw (struct cp_private *cp)
cpw8_f (Cfg9346, Cfg9346_Unlock);
/* Restore our idea of the MAC address. */
- cpw32_f (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
- cpw32_f (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+ cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0)));
+ cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4)));
cp_start_hw(cp);
cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */
@@ -1069,8 +1066,8 @@ static int cp_refill_rx (struct cp_private *cp)
skb_reserve(skb, RX_OFFSET);
- mapping = pci_map_single(cp->pdev, skb->data, cp->rx_buf_sz,
- PCI_DMA_FROMDEVICE);
+ mapping = dma_map_single(&cp->pdev->dev, skb->data,
+ cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
cp->rx_skb[i] = skb;
cp->rx_ring[i].opts2 = 0;
@@ -1110,7 +1107,8 @@ static int cp_alloc_rings (struct cp_private *cp)
{
void *mem;
- mem = pci_alloc_consistent(cp->pdev, CP_RING_BYTES, &cp->ring_dma);
+ mem = dma_alloc_coherent(&cp->pdev->dev, CP_RING_BYTES,
+ &cp->ring_dma, GFP_KERNEL);
if (!mem)
return -ENOMEM;
@@ -1128,7 +1126,7 @@ static void cp_clean_rings (struct cp_private *cp)
for (i = 0; i < CP_RX_RING_SIZE; i++) {
if (cp->rx_skb[i]) {
desc = cp->rx_ring + i;
- pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr),
+ dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
dev_kfree_skb(cp->rx_skb[i]);
}
@@ -1139,7 +1137,7 @@ static void cp_clean_rings (struct cp_private *cp)
struct sk_buff *skb = cp->tx_skb[i];
desc = cp->tx_ring + i;
- pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr),
+ dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
le32_to_cpu(desc->opts1) & 0xffff,
PCI_DMA_TODEVICE);
if (le32_to_cpu(desc->opts1) & LastFrag)
@@ -1158,7 +1156,8 @@ static void cp_clean_rings (struct cp_private *cp)
static void cp_free_rings (struct cp_private *cp)
{
cp_clean_rings(cp);
- pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma);
+ dma_free_coherent(&cp->pdev->dev, CP_RING_BYTES, cp->rx_ring,
+ cp->ring_dma);
cp->rx_ring = NULL;
cp->tx_ring = NULL;
}
@@ -1175,6 +1174,8 @@ static int cp_open (struct net_device *dev)
if (rc)
return rc;
+ napi_enable(&cp->napi);
+
cp_init_hw(cp);
rc = request_irq(dev->irq, cp_interrupt, IRQF_SHARED, dev->name, dev);
@@ -1188,6 +1189,7 @@ static int cp_open (struct net_device *dev)
return 0;
err_out_hw:
+ napi_disable(&cp->napi);
cp_stop_hw(cp);
cp_free_rings(cp);
return rc;
@@ -1198,6 +1200,8 @@ static int cp_close (struct net_device *dev)
struct cp_private *cp = netdev_priv(dev);
unsigned long flags;
+ napi_disable(&cp->napi);
+
if (netif_msg_ifdown(cp))
printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
@@ -1379,9 +1383,14 @@ static int cp_get_regs_len(struct net_device *dev)
return CP_REGS_SIZE;
}
-static int cp_get_stats_count (struct net_device *dev)
+static int cp_get_sset_count (struct net_device *dev, int sset)
{
- return CP_NUM_STATS;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return CP_NUM_STATS;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static int cp_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -1517,7 +1526,8 @@ static void cp_get_ethtool_stats (struct net_device *dev,
dma_addr_t dma;
int i;
- nic_stats = pci_alloc_consistent(cp->pdev, sizeof(*nic_stats), &dma);
+ nic_stats = dma_alloc_coherent(&cp->pdev->dev, sizeof(*nic_stats),
+ &dma, GFP_KERNEL);
if (!nic_stats)
return;
@@ -1552,13 +1562,13 @@ static void cp_get_ethtool_stats (struct net_device *dev,
tmp_stats[i++] = cp->cp_stats.rx_frags;
BUG_ON(i != CP_NUM_STATS);
- pci_free_consistent(cp->pdev, sizeof(*nic_stats), nic_stats, dma);
+ dma_free_coherent(&cp->pdev->dev, sizeof(*nic_stats), nic_stats, dma);
}
static const struct ethtool_ops cp_ethtool_ops = {
.get_drvinfo = cp_get_drvinfo,
.get_regs_len = cp_get_regs_len,
- .get_stats_count = cp_get_stats_count,
+ .get_sset_count = cp_get_sset_count,
.get_settings = cp_get_settings,
.set_settings = cp_set_settings,
.nway_reset = cp_nway_reset,
@@ -1567,11 +1577,8 @@ static const struct ethtool_ops cp_ethtool_ops = {
.set_msglevel = cp_set_msglevel,
.get_rx_csum = cp_get_rx_csum,
.set_rx_csum = cp_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum, /* local! */
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_regs = cp_get_regs,
.get_wol = cp_get_wol,
@@ -1821,6 +1828,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
void __iomem *regs;
resource_size_t pciaddr;
unsigned int addr_len, i, pci_using_dac;
+ DECLARE_MAC_BUF(mac);
#ifndef MODULE
static int version_printed;
@@ -1840,7 +1848,6 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
dev = alloc_etherdev(sizeof(struct cp_private));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
cp = netdev_priv(dev);
@@ -1923,8 +1930,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
/* read MAC address from EEPROM */
addr_len = read_eeprom (regs, 0, 8) == 0x8129 ? 8 : 6;
for (i = 0; i < 3; i++)
- ((u16 *) (dev->dev_addr))[i] =
- le16_to_cpu (read_eeprom (regs, i + 7, addr_len));
+ ((__le16 *) (dev->dev_addr))[i] =
+ cpu_to_le16(read_eeprom (regs, i + 7, addr_len));
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
dev->open = cp_open;
@@ -1933,11 +1940,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
dev->hard_start_xmit = cp_start_xmit;
dev->get_stats = cp_get_stats;
dev->do_ioctl = cp_ioctl;
- dev->poll = cp_rx_poll;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = cp_poll_controller;
#endif
- dev->weight = 16; /* arbitrary? from NAPI_HOWTO.txt. */
+ netif_napi_add(dev, &cp->napi, cp_rx_poll, 16);
#ifdef BROKEN
dev->change_mtu = cp_change_mtu;
#endif
@@ -1964,13 +1970,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_iomap;
printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, "
- "%02x:%02x:%02x:%02x:%02x:%02x, "
- "IRQ %d\n",
+ "%s, IRQ %d\n",
dev->name,
dev->base_addr,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5],
+ print_mac(mac, dev->dev_addr),
dev->irq);
pci_set_drvdata(pdev, dev);
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index f4e4298d24b..eef6fecfff2 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -73,7 +73,7 @@
Jean-Jacques Michel - bug fix
- Tobias Ringström - Rx interrupt status checking suggestion
+ Tobias Ringström - Rx interrupt status checking suggestion
Andrew Morton - Clear blocked signals, avoid
buffer overrun setting current->comm.
@@ -291,198 +291,197 @@ static struct {
/* Symbolic offsets to registers. */
enum RTL8139_registers {
- MAC0 = 0, /* Ethernet hardware address. */
- MAR0 = 8, /* Multicast filter. */
- TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */
- TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
- RxBuf = 0x30,
- ChipCmd = 0x37,
- RxBufPtr = 0x38,
- RxBufAddr = 0x3A,
- IntrMask = 0x3C,
- IntrStatus = 0x3E,
- TxConfig = 0x40,
- RxConfig = 0x44,
- Timer = 0x48, /* A general-purpose counter. */
- RxMissed = 0x4C, /* 24 bits valid, write clears. */
- Cfg9346 = 0x50,
- Config0 = 0x51,
- Config1 = 0x52,
- FlashReg = 0x54,
- MediaStatus = 0x58,
- Config3 = 0x59,
- Config4 = 0x5A, /* absent on RTL-8139A */
- HltClk = 0x5B,
- MultiIntr = 0x5C,
- TxSummary = 0x60,
- BasicModeCtrl = 0x62,
- BasicModeStatus = 0x64,
- NWayAdvert = 0x66,
- NWayLPAR = 0x68,
- NWayExpansion = 0x6A,
+ MAC0 = 0, /* Ethernet hardware address. */
+ MAR0 = 8, /* Multicast filter. */
+ TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */
+ TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
+ RxBuf = 0x30,
+ ChipCmd = 0x37,
+ RxBufPtr = 0x38,
+ RxBufAddr = 0x3A,
+ IntrMask = 0x3C,
+ IntrStatus = 0x3E,
+ TxConfig = 0x40,
+ RxConfig = 0x44,
+ Timer = 0x48, /* A general-purpose counter. */
+ RxMissed = 0x4C, /* 24 bits valid, write clears. */
+ Cfg9346 = 0x50,
+ Config0 = 0x51,
+ Config1 = 0x52,
+ FlashReg = 0x54,
+ MediaStatus = 0x58,
+ Config3 = 0x59,
+ Config4 = 0x5A, /* absent on RTL-8139A */
+ HltClk = 0x5B,
+ MultiIntr = 0x5C,
+ TxSummary = 0x60,
+ BasicModeCtrl = 0x62,
+ BasicModeStatus = 0x64,
+ NWayAdvert = 0x66,
+ NWayLPAR = 0x68,
+ NWayExpansion = 0x6A,
/* Undocumented registers, but required for proper operation. */
- FIFOTMS = 0x70, /* FIFO Control and test. */
- CSCR = 0x74, /* Chip Status and Configuration Register. */
- PARA78 = 0x78,
- PARA7c = 0x7c, /* Magic transceiver parameter register. */
- Config5 = 0xD8, /* absent on RTL-8139A */
+ FIFOTMS = 0x70, /* FIFO Control and test. */
+ CSCR = 0x74, /* Chip Status and Configuration Register. */
+ PARA78 = 0x78,
+ PARA7c = 0x7c, /* Magic transceiver parameter register. */
+ Config5 = 0xD8, /* absent on RTL-8139A */
};
enum ClearBitMasks {
- MultiIntrClear = 0xF000,
- ChipCmdClear = 0xE2,
- Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
+ MultiIntrClear = 0xF000,
+ ChipCmdClear = 0xE2,
+ Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
};
enum ChipCmdBits {
- CmdReset = 0x10,
- CmdRxEnb = 0x08,
- CmdTxEnb = 0x04,
- RxBufEmpty = 0x01,
+ CmdReset = 0x10,
+ CmdRxEnb = 0x08,
+ CmdTxEnb = 0x04,
+ RxBufEmpty = 0x01,
};
/* Interrupt register bits, using my own meaningful names. */
enum IntrStatusBits {
- PCIErr = 0x8000,
- PCSTimeout = 0x4000,
- RxFIFOOver = 0x40,
- RxUnderrun = 0x20,
- RxOverflow = 0x10,
- TxErr = 0x08,
- TxOK = 0x04,
- RxErr = 0x02,
- RxOK = 0x01,
-
- RxAckBits = RxFIFOOver | RxOverflow | RxOK,
+ PCIErr = 0x8000,
+ PCSTimeout = 0x4000,
+ RxFIFOOver = 0x40,
+ RxUnderrun = 0x20,
+ RxOverflow = 0x10,
+ TxErr = 0x08,
+ TxOK = 0x04,
+ RxErr = 0x02,
+ RxOK = 0x01,
+
+ RxAckBits = RxFIFOOver | RxOverflow | RxOK,
};
enum TxStatusBits {
- TxHostOwns = 0x2000,
- TxUnderrun = 0x4000,
- TxStatOK = 0x8000,
- TxOutOfWindow = 0x20000000,
- TxAborted = 0x40000000,
- TxCarrierLost = 0x80000000,
+ TxHostOwns = 0x2000,
+ TxUnderrun = 0x4000,
+ TxStatOK = 0x8000,
+ TxOutOfWindow = 0x20000000,
+ TxAborted = 0x40000000,
+ TxCarrierLost = 0x80000000,
};
enum RxStatusBits {
- RxMulticast = 0x8000,
- RxPhysical = 0x4000,
- RxBroadcast = 0x2000,
- RxBadSymbol = 0x0020,
- RxRunt = 0x0010,
- RxTooLong = 0x0008,
- RxCRCErr = 0x0004,
- RxBadAlign = 0x0002,
- RxStatusOK = 0x0001,
+ RxMulticast = 0x8000,
+ RxPhysical = 0x4000,
+ RxBroadcast = 0x2000,
+ RxBadSymbol = 0x0020,
+ RxRunt = 0x0010,
+ RxTooLong = 0x0008,
+ RxCRCErr = 0x0004,
+ RxBadAlign = 0x0002,
+ RxStatusOK = 0x0001,
};
/* Bits in RxConfig. */
enum rx_mode_bits {
- AcceptErr = 0x20,
- AcceptRunt = 0x10,
- AcceptBroadcast = 0x08,
- AcceptMulticast = 0x04,
- AcceptMyPhys = 0x02,
- AcceptAllPhys = 0x01,
+ AcceptErr = 0x20,
+ AcceptRunt = 0x10,
+ AcceptBroadcast = 0x08,
+ AcceptMulticast = 0x04,
+ AcceptMyPhys = 0x02,
+ AcceptAllPhys = 0x01,
};
/* Bits in TxConfig. */
enum tx_config_bits {
-
/* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
- TxIFGShift = 24,
- TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
- TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
- TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
- TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
-
- TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
- TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
- TxClearAbt = (1 << 0), /* Clear abort (WO) */
- TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */
- TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */
-
- TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
+ TxIFGShift = 24,
+ TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
+ TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
+ TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
+ TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
+
+ TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
+ TxCRC = (1 << 16), /* DISABLE Tx pkt CRC append */
+ TxClearAbt = (1 << 0), /* Clear abort (WO) */
+ TxDMAShift = 8, /* DMA burst value (0-7) is shifted X many bits */
+ TxRetryShift = 4, /* TXRR value (0-15) is shifted X many bits */
+
+ TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
};
/* Bits in Config1 */
enum Config1Bits {
- Cfg1_PM_Enable = 0x01,
- Cfg1_VPD_Enable = 0x02,
- Cfg1_PIO = 0x04,
- Cfg1_MMIO = 0x08,
- LWAKE = 0x10, /* not on 8139, 8139A */
+ Cfg1_PM_Enable = 0x01,
+ Cfg1_VPD_Enable = 0x02,
+ Cfg1_PIO = 0x04,
+ Cfg1_MMIO = 0x08,
+ LWAKE = 0x10, /* not on 8139, 8139A */
Cfg1_Driver_Load = 0x20,
- Cfg1_LED0 = 0x40,
- Cfg1_LED1 = 0x80,
- SLEEP = (1 << 1), /* only on 8139, 8139A */
- PWRDN = (1 << 0), /* only on 8139, 8139A */
+ Cfg1_LED0 = 0x40,
+ Cfg1_LED1 = 0x80,
+ SLEEP = (1 << 1), /* only on 8139, 8139A */
+ PWRDN = (1 << 0), /* only on 8139, 8139A */
};
/* Bits in Config3 */
enum Config3Bits {
- Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */
- Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
- Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
- Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */
- Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */
- Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
- Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */
- Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
+ Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */
+ Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
+ Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
+ Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */
+ Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */
+ Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
+ Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */
+ Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
};
/* Bits in Config4 */
enum Config4Bits {
- LWPTN = (1 << 2), /* not on 8139, 8139A */
+ LWPTN = (1 << 2), /* not on 8139, 8139A */
};
/* Bits in Config5 */
enum Config5Bits {
- Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */
- Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */
- Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */
- Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
- Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */
- Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */
- Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */
+ Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */
+ Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */
+ Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */
+ Cfg5_FIFOAddrPtr= (1 << 3), /* Realtek internal SRAM testing */
+ Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */
+ Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */
+ Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */
};
enum RxConfigBits {
/* rx fifo threshold */
- RxCfgFIFOShift = 13,
- RxCfgFIFONone = (7 << RxCfgFIFOShift),
+ RxCfgFIFOShift = 13,
+ RxCfgFIFONone = (7 << RxCfgFIFOShift),
/* Max DMA burst */
- RxCfgDMAShift = 8,
+ RxCfgDMAShift = 8,
RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
/* rx ring buffer length */
- RxCfgRcv8K = 0,
- RxCfgRcv16K = (1 << 11),
- RxCfgRcv32K = (1 << 12),
- RxCfgRcv64K = (1 << 11) | (1 << 12),
+ RxCfgRcv8K = 0,
+ RxCfgRcv16K = (1 << 11),
+ RxCfgRcv32K = (1 << 12),
+ RxCfgRcv64K = (1 << 11) | (1 << 12),
/* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
- RxNoWrap = (1 << 7),
+ RxNoWrap = (1 << 7),
};
/* Twister tuning parameters from RealTek.
Completely undocumented, but required to tune bad links on some boards. */
enum CSCRBits {
- CSCR_LinkOKBit = 0x0400,
- CSCR_LinkChangeBit = 0x0800,
- CSCR_LinkStatusBits = 0x0f000,
- CSCR_LinkDownOffCmd = 0x003c0,
- CSCR_LinkDownCmd = 0x0f3c0,
+ CSCR_LinkOKBit = 0x0400,
+ CSCR_LinkChangeBit = 0x0800,
+ CSCR_LinkStatusBits = 0x0f000,
+ CSCR_LinkDownOffCmd = 0x003c0,
+ CSCR_LinkDownCmd = 0x0f3c0,
};
enum Cfg9346Bits {
- Cfg9346_Lock = 0x00,
- Cfg9346_Unlock = 0xC0,
+ Cfg9346_Lock = 0x00,
+ Cfg9346_Unlock = 0xC0,
};
typedef enum {
- CH_8139 = 0,
+ CH_8139 = 0,
CH_8139_K,
CH_8139A,
CH_8139A_G,
@@ -495,8 +494,8 @@ typedef enum {
} chip_t;
enum chip_flags {
- HasHltClk = (1 << 0),
- HasLWake = (1 << 1),
+ HasHltClk = (1 << 0),
+ HasLWake = (1 << 1),
};
#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
@@ -569,36 +568,46 @@ struct rtl_extra_stats {
};
struct rtl8139_private {
- void __iomem *mmio_addr;
- int drv_flags;
- struct pci_dev *pci_dev;
- u32 msg_enable;
- struct net_device_stats stats;
- unsigned char *rx_ring;
- unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
- unsigned int tx_flag;
- unsigned long cur_tx;
- unsigned long dirty_tx;
- unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
- unsigned char *tx_bufs; /* Tx bounce buffer region. */
- dma_addr_t rx_ring_dma;
- dma_addr_t tx_bufs_dma;
- signed char phys[4]; /* MII device addresses. */
- char twistie, twist_row, twist_col; /* Twister tune state. */
- unsigned int watchdog_fired : 1;
- unsigned int default_port : 4; /* Last dev->if_port value. */
- unsigned int have_thread : 1;
- spinlock_t lock;
- spinlock_t rx_lock;
- chip_t chipset;
- u32 rx_config;
- struct rtl_extra_stats xstats;
-
- struct delayed_work thread;
-
- struct mii_if_info mii;
- unsigned int regs_len;
- unsigned long fifo_copy_timeout;
+ void __iomem *mmio_addr;
+ int drv_flags;
+ struct pci_dev *pci_dev;
+ u32 msg_enable;
+ struct napi_struct napi;
+ struct net_device *dev;
+ struct net_device_stats stats;
+
+ unsigned char *rx_ring;
+ unsigned int cur_rx; /* RX buf index of next pkt */
+ dma_addr_t rx_ring_dma;
+
+ unsigned int tx_flag;
+ unsigned long cur_tx;
+ unsigned long dirty_tx;
+ unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */
+ unsigned char *tx_bufs; /* Tx bounce buffer region. */
+ dma_addr_t tx_bufs_dma;
+
+ signed char phys[4]; /* MII device addresses. */
+
+ /* Twister tune state. */
+ char twistie, twist_row, twist_col;
+
+ unsigned int watchdog_fired : 1;
+ unsigned int default_port : 4; /* Last dev->if_port value. */
+ unsigned int have_thread : 1;
+
+ spinlock_t lock;
+ spinlock_t rx_lock;
+
+ chip_t chipset;
+ u32 rx_config;
+ struct rtl_extra_stats xstats;
+
+ struct delayed_work thread;
+
+ struct mii_if_info mii;
+ unsigned int regs_len;
+ unsigned long fifo_copy_timeout;
};
MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
@@ -625,10 +634,10 @@ static void rtl8139_tx_timeout (struct net_device *dev);
static void rtl8139_init_ring (struct net_device *dev);
static int rtl8139_start_xmit (struct sk_buff *skb,
struct net_device *dev);
-static int rtl8139_poll(struct net_device *dev, int *budget);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void rtl8139_poll_controller(struct net_device *dev);
#endif
+static int rtl8139_poll(struct napi_struct *napi, int budget);
static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance);
static int rtl8139_close (struct net_device *dev);
static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
@@ -646,24 +655,11 @@ static const struct ethtool_ops rtl8139_ethtool_ops;
#define RTL_W16_F(reg, val16) do { iowrite16 ((val16), ioaddr + (reg)); ioread16 (ioaddr + (reg)); } while (0)
#define RTL_W32_F(reg, val32) do { iowrite32 ((val32), ioaddr + (reg)); ioread32 (ioaddr + (reg)); } while (0)
-
-#define MMIO_FLUSH_AUDIT_COMPLETE 1
-#if MMIO_FLUSH_AUDIT_COMPLETE
-
/* write MMIO register */
#define RTL_W8(reg, val8) iowrite8 ((val8), ioaddr + (reg))
#define RTL_W16(reg, val16) iowrite16 ((val16), ioaddr + (reg))
#define RTL_W32(reg, val32) iowrite32 ((val32), ioaddr + (reg))
-#else
-
-/* write MMIO register, then flush */
-#define RTL_W8 RTL_W8_F
-#define RTL_W16 RTL_W16_F
-#define RTL_W32 RTL_W32_F
-
-#endif /* MMIO_FLUSH_AUDIT_COMPLETE */
-
/* read MMIO register */
#define RTL_R8(reg) ioread8 (ioaddr + (reg))
#define RTL_R16(reg) ioread16 (ioaddr + (reg))
@@ -770,7 +766,6 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
dev_err(&pdev->dev, "Unable to alloc new net device\n");
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
tp = netdev_priv(dev);
@@ -931,6 +926,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
int i, addr_len, option;
void __iomem *ioaddr;
static int board_idx = -1;
+ DECLARE_MAC_BUF(mac);
assert (pdev != NULL);
assert (ent != NULL);
@@ -963,6 +959,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
assert (dev != NULL);
tp = netdev_priv(dev);
+ tp->dev = dev;
ioaddr = tp->mmio_addr;
assert (ioaddr != NULL);
@@ -976,8 +973,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
/* The Rtl8139-specific entries in the device structure. */
dev->open = rtl8139_open;
dev->hard_start_xmit = rtl8139_start_xmit;
- dev->poll = rtl8139_poll;
- dev->weight = 64;
+ netif_napi_add(dev, &tp->napi, rtl8139_poll, 64);
dev->stop = rtl8139_close;
dev->get_stats = rtl8139_get_stats;
dev->set_multicast_list = rtl8139_set_rx_mode;
@@ -1022,14 +1018,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
pci_set_drvdata (pdev, dev);
printk (KERN_INFO "%s: %s at 0x%lx, "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
- "IRQ %d\n",
+ "%s, IRQ %d\n",
dev->name,
board_info[ent->driver_data].name,
dev->base_addr,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5],
+ print_mac(mac, dev->dev_addr),
dev->irq);
printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n",
@@ -1314,24 +1307,26 @@ static int rtl8139_open (struct net_device *dev)
if (retval)
return retval;
- tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
- &tp->tx_bufs_dma);
- tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
- &tp->rx_ring_dma);
+ tp->tx_bufs = dma_alloc_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN,
+ &tp->tx_bufs_dma, GFP_KERNEL);
+ tp->rx_ring = dma_alloc_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN,
+ &tp->rx_ring_dma, GFP_KERNEL);
if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
free_irq(dev->irq, dev);
if (tp->tx_bufs)
- pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
+ dma_free_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN,
tp->tx_bufs, tp->tx_bufs_dma);
if (tp->rx_ring)
- pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
+ dma_free_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN,
tp->rx_ring, tp->rx_ring_dma);
return -ENOMEM;
}
+ napi_enable(&tp->napi);
+
tp->mii.full_duplex = tp->mii.force_media;
tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
@@ -2103,39 +2098,32 @@ static void rtl8139_weird_interrupt (struct net_device *dev,
}
}
-static int rtl8139_poll(struct net_device *dev, int *budget)
+static int rtl8139_poll(struct napi_struct *napi, int budget)
{
- struct rtl8139_private *tp = netdev_priv(dev);
+ struct rtl8139_private *tp = container_of(napi, struct rtl8139_private, napi);
+ struct net_device *dev = tp->dev;
void __iomem *ioaddr = tp->mmio_addr;
- int orig_budget = min(*budget, dev->quota);
- int done = 1;
+ int work_done;
spin_lock(&tp->rx_lock);
- if (likely(RTL_R16(IntrStatus) & RxAckBits)) {
- int work_done;
-
- work_done = rtl8139_rx(dev, tp, orig_budget);
- if (likely(work_done > 0)) {
- *budget -= work_done;
- dev->quota -= work_done;
- done = (work_done < orig_budget);
- }
- }
+ work_done = 0;
+ if (likely(RTL_R16(IntrStatus) & RxAckBits))
+ work_done += rtl8139_rx(dev, tp, budget);
- if (done) {
+ if (work_done < budget) {
unsigned long flags;
/*
* Order is important since data can get interrupted
* again when we think we are done.
*/
- local_irq_save(flags);
+ spin_lock_irqsave(&tp->lock, flags);
RTL_W16_F(IntrMask, rtl8139_intr_mask);
- __netif_rx_complete(dev);
- local_irq_restore(flags);
+ __netif_rx_complete(dev, napi);
+ spin_unlock_irqrestore(&tp->lock, flags);
}
spin_unlock(&tp->rx_lock);
- return !done;
+ return work_done;
}
/* The interrupt handler does all of the Rx thread work and cleans up
@@ -2180,9 +2168,9 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance)
/* Receive packets are processed by poll routine.
If not running start it now. */
if (status & RxAckBits){
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &tp->napi)) {
RTL_W16_F (IntrMask, rtl8139_norx_intr_mask);
- __netif_rx_schedule (dev);
+ __netif_rx_schedule(dev, &tp->napi);
}
}
@@ -2223,7 +2211,8 @@ static int rtl8139_close (struct net_device *dev)
void __iomem *ioaddr = tp->mmio_addr;
unsigned long flags;
- netif_stop_queue (dev);
+ netif_stop_queue(dev);
+ napi_disable(&tp->napi);
if (netif_msg_ifdown(tp))
printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
@@ -2248,10 +2237,10 @@ static int rtl8139_close (struct net_device *dev)
rtl8139_tx_clear (tp);
- pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
- tp->rx_ring, tp->rx_ring_dma);
- pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
- tp->tx_bufs, tp->tx_bufs_dma);
+ dma_free_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN,
+ tp->rx_ring, tp->rx_ring_dma);
+ dma_free_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN,
+ tp->tx_bufs, tp->tx_bufs_dma);
tp->rx_ring = NULL;
tp->tx_bufs = NULL;
@@ -2417,9 +2406,14 @@ static void rtl8139_get_regs(struct net_device *dev, struct ethtool_regs *regs,
}
#endif /* CONFIG_8139TOO_MMIO */
-static int rtl8139_get_stats_count(struct net_device *dev)
+static int rtl8139_get_sset_count(struct net_device *dev, int sset)
{
- return RTL_NUM_STATS;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return RTL_NUM_STATS;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void rtl8139_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
@@ -2450,7 +2444,7 @@ static const struct ethtool_ops rtl8139_ethtool_ops = {
.get_wol = rtl8139_get_wol,
.set_wol = rtl8139_set_wol,
.get_strings = rtl8139_get_strings,
- .get_stats_count = rtl8139_get_stats_count,
+ .get_sset_count = rtl8139_get_sset_count,
.get_ethtool_stats = rtl8139_get_ethtool_stats,
};
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index d915837193c..2797da7eeee 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -326,7 +326,6 @@ struct i596_private {
struct i596_cmd *cmd_head;
int cmd_backlog;
unsigned long last_cmd;
- struct net_device_stats stats;
struct i596_rfd rfds[RX_RING_SIZE];
struct i596_rbd rbds[RX_RING_SIZE];
struct tx_cmd tx_cmds[TX_RING_SIZE];
@@ -360,7 +359,6 @@ static int i596_open(struct net_device *dev);
static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t i596_interrupt(int irq, void *dev_id);
static int i596_close(struct net_device *dev);
-static struct net_device_stats *i596_get_stats(struct net_device *dev);
static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
static void i596_tx_timeout (struct net_device *dev);
static void print_eth(unsigned char *buf, char *str);
@@ -828,7 +826,7 @@ memory_squeeze:
if (skb == NULL) {
/* XXX tulip.c can defer packets here!! */
printk(KERN_WARNING "%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
else {
if (!rx_in_place) {
@@ -844,28 +842,28 @@ memory_squeeze:
#endif
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes+=pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes+=pkt_len;
}
}
else {
DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: Error, rfd.stat = 0x%04x\n",
dev->name, rfd->stat));
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if ((rfd->stat) & 0x0001)
- lp->stats.collisions++;
+ dev->stats.collisions++;
if ((rfd->stat) & 0x0080)
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if ((rfd->stat) & 0x0100)
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if ((rfd->stat) & 0x0200)
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if ((rfd->stat) & 0x0400)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if ((rfd->stat) & 0x0800)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if ((rfd->stat) & 0x1000)
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
/* Clear the buffer descriptor count and EOF + F flags */
@@ -916,8 +914,8 @@ static void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
dev_kfree_skb(skb);
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
ptr->v_next = ptr->b_next = I596_NULL;
tx_cmd->cmd.command = 0; /* Mark as free */
@@ -1038,10 +1036,10 @@ static void i596_tx_timeout (struct net_device *dev)
DEB(DEB_ERRORS,printk(KERN_ERR "%s: transmit timed out, status resetting.\n",
dev->name));
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* Try to restart the adaptor */
- if (lp->last_restart == lp->stats.tx_packets) {
+ if (lp->last_restart == dev->stats.tx_packets) {
DEB(DEB_ERRORS,printk(KERN_ERR "Resetting board.\n"));
/* Shutdown and restart */
i596_reset (dev, lp, ioaddr);
@@ -1050,7 +1048,7 @@ static void i596_tx_timeout (struct net_device *dev)
DEB(DEB_ERRORS,printk(KERN_ERR "Kicking board.\n"));
lp->scb.command = CUC_START | RX_START;
CA (dev);
- lp->last_restart = lp->stats.tx_packets;
+ lp->last_restart = dev->stats.tx_packets;
}
dev->trans_start = jiffies;
@@ -1082,7 +1080,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (tx_cmd->cmd.command) {
printk(KERN_NOTICE "%s: xmit ring full, dropping packet.\n",
dev->name);
- lp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
} else {
@@ -1107,8 +1105,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));
i596_add_cmd(dev, &tx_cmd->cmd);
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += length;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += length;
}
netif_start_queue(dev);
@@ -1118,15 +1116,12 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
static void print_eth(unsigned char *add, char *str)
{
- int i;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
- printk(KERN_DEBUG "i596 0x%p, ", add);
- for (i = 0; i < 6; i++)
- printk(" %02X", add[i + 6]);
- printk(" -->");
- for (i = 0; i < 6; i++)
- printk(" %02X", add[i]);
- printk(" %02X%02X, %s\n", add[12], add[13], str);
+ printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n",
+ add, print_mac(mac, add + 6), print_mac(mac2, add),
+ add[12], add[13], str);
}
static int io = 0x300;
@@ -1197,6 +1192,8 @@ struct net_device * __init i82596_probe(int unit)
goto out;
}
+ dev->base_addr = ioaddr;
+
for (i = 0; i < 8; i++) {
eth_addr[i] = inb(ioaddr + 8 + i);
checksum += eth_addr[i];
@@ -1214,7 +1211,6 @@ struct net_device * __init i82596_probe(int unit)
goto out1;
}
- dev->base_addr = ioaddr;
dev->irq = 10;
}
#endif
@@ -1234,11 +1230,9 @@ struct net_device * __init i82596_probe(int unit)
DEB(DEB_PROBE,printk(KERN_INFO "%s", version));
/* The 82596-specific entries in the device structure. */
- SET_MODULE_OWNER(dev);
dev->open = i596_open;
dev->stop = i596_close;
dev->hard_start_xmit = i596_start_xmit;
- dev->get_stats = i596_get_stats;
dev->set_multicast_list = set_multicast_list;
dev->tx_timeout = i596_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -1344,17 +1338,17 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id)
if ((ptr->status) & STAT_OK) {
DEB(DEB_TXADDR,print_eth(skb->data, "tx-done"));
} else {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if ((ptr->status) & 0x0020)
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (!((ptr->status) & 0x0040))
- lp->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
if ((ptr->status) & 0x0400)
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if ((ptr->status) & 0x0800)
- lp->stats.collisions++;
+ dev->stats.collisions++;
if ((ptr->status) & 0x1000)
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
}
dev_kfree_skb_irq(skb);
@@ -1409,8 +1403,8 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id)
if (netif_running(dev)) {
DEB(DEB_ERRORS,printk(KERN_ERR "%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));
ack_cmd |= RX_START;
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
rebuild_rx_bufs(dev);
}
}
@@ -1493,14 +1487,6 @@ static int i596_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *
- i596_get_stats(struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
-
- return &lp->stats;
-}
-
/*
* Set or clear the multicast filter for this adaptor.
*/
@@ -1551,6 +1537,7 @@ static void set_multicast_list(struct net_device *dev)
struct dev_mc_list *dmi;
unsigned char *cp;
struct mc_cmd *cmd;
+ DECLARE_MAC_BUF(mac);
if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out"))
return;
@@ -1561,8 +1548,8 @@ static void set_multicast_list(struct net_device *dev)
for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) {
memcpy(cp, dmi->dmi_addr, 6);
if (i596_debug > 1)
- DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5]));
+ DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %s\n",
+ dev->name, print_mac(mac, cp)));
}
i596_add_cmd(dev, &cmd->cmd);
}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index c5519250efd..e8d69b0adf9 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -135,6 +135,13 @@ config TUN
If you don't know what to use this for, you don't need it.
+config VETH
+ tristate "Virtual ethernet pair device"
+ ---help---
+ This device is a local ethernet tunnel. Devices are created in pairs.
+ When one end receives the packet it appears on its pair and vice
+ versa.
+
config NET_SB1000
tristate "General Instruments Surfboard 1000"
depends on PNP
@@ -159,6 +166,16 @@ config NET_SB1000
If you don't have this card, of course say N.
+config IP1000
+ tristate "IP1000 Gigabit Ethernet support"
+ depends on PCI && EXPERIMENTAL
+ select MII
+ ---help---
+ This driver supports IP1000 gigabit Ethernet cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ipg. This is recommended.
+
source "drivers/net/arcnet/Kconfig"
source "drivers/net/phy/Kconfig"
@@ -218,13 +235,20 @@ source "drivers/net/arm/Kconfig"
config AX88796
tristate "ASIX AX88796 NE2000 clone support"
- depends on ARM || MIPS
+ depends on ARM || MIPS || SUPERH
select CRC32
select MII
help
AX88796 driver, using platform bus to provide
chip detection and resources
+config AX88796_93CX6
+ bool "ASIX AX88796 external 93CX6 eeprom support"
+ depends on AX88796
+ select EEPROM_93CX6
+ help
+ Select this if your platform comes with an external 93CX6 eeprom.
+
config MACE
tristate "MACE (Power Mac ethernet) support"
depends on PPC_PMAC && PPC32
@@ -342,8 +366,7 @@ config MAC89x0
read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. This module will
+ To compile this driver as a module, choose M here. This module will
be called mac89x0.
config MACSONIC
@@ -356,8 +379,7 @@ config MACSONIC
one of these say Y and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. This module will
+ To compile this driver as a module, choose M here. This module will
be called macsonic.
config MACMACE
@@ -466,10 +488,6 @@ config MIPS_AU1X00_ENET
If you have an Alchemy Semi AU1X00 based system
say Y. Otherwise, say N.
-config NET_SB1250_MAC
- tristate "SB1250 Ethernet support"
- depends on SIBYTE_SB1xxx_SOC
-
config SGI_IOC3_ETH
bool "SGI IOC3 Ethernet"
depends on PCI && SGI_IP27
@@ -480,26 +498,6 @@ config SGI_IOC3_ETH
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
-config SGI_IOC3_ETH_HW_RX_CSUM
- bool "Receive hardware checksums"
- depends on SGI_IOC3_ETH && INET
- default y
- help
- The SGI IOC3 network adapter supports TCP and UDP checksums in
- hardware to offload processing of these checksums from the CPU. At
- the moment only acceleration of IPv4 is supported. This option
- enables offloading for checksums on receive. If unsure, say Y.
-
-config SGI_IOC3_ETH_HW_TX_CSUM
- bool "Transmit hardware checksums"
- depends on SGI_IOC3_ETH && INET
- default y
- help
- The SGI IOC3 network adapter supports TCP and UDP checksums in
- hardware to offload processing of these checksums from the CPU. At
- the moment only acceleration of IPv4 is supported. This option
- enables offloading for checksums on transmit. If unsure, say Y.
-
config MIPS_SIM_NET
tristate "MIPS simulator Network device"
depends on MIPS_SIM
@@ -619,8 +617,7 @@ config EL1
have problems. Some people suggest to ping ("man ping") a nearby
machine every minute ("man cron") when using this card.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called 3c501.
config EL2
@@ -632,8 +629,7 @@ config EL2
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called 3c503.
config ELPLUS
@@ -645,8 +641,7 @@ config ELPLUS
this type, say Y and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called 3c505.
config EL16
@@ -657,8 +652,7 @@ config EL16
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called 3c507.
config EL3
@@ -673,8 +667,7 @@ config EL3
setup disk to disable Plug & Play mode, and to select the default
media type.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called 3c509.
config 3C515
@@ -685,8 +678,7 @@ config 3C515
network card, say Y and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called 3c515.
config ELMC
@@ -697,8 +689,7 @@ config ELMC
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called 3c523.
config ELMC_II
@@ -709,8 +700,7 @@ config ELMC_II
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called 3c527.
config VORTEX
@@ -733,8 +723,7 @@ config VORTEX
<file:Documentation/networking/vortex.txt> and in the comments at
the beginning of <file:drivers/net/3c59x.c>.
- To compile this support as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>.
+ To compile this support as a module, choose M here.
config TYPHOON
tristate "3cr990 series \"Typhoon\" support"
@@ -751,8 +740,7 @@ config TYPHOON
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called typhoon.
config LANCE
@@ -789,8 +777,7 @@ config WD80x3
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called wd.
config ULTRAMCA
@@ -802,8 +789,7 @@ config ULTRAMCA
an MCA based system (PS/2), say Y and read the Ethernet-HOWTO,
available from <http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called smc-mca.
config ULTRA
@@ -822,8 +808,7 @@ config ULTRA
this but keep it in mind if you have such a SCSI card and have
problems.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called smc-ultra.
config ULTRA32
@@ -835,14 +820,15 @@ config ULTRA32
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called smc-ultra32.
config BFIN_MAC
tristate "Blackfin 536/537 on-chip mac support"
depends on NET_ETHERNET && (BF537 || BF536) && (!BF537_PORT_H)
select CRC32
+ select MII
+ select PHYLIB
select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE
help
This is the driver for blackfin on-chip mac device. Say Y if you want it
@@ -855,7 +841,7 @@ config BFIN_MAC_USE_L1
depends on BFIN_MAC && BF537
default y
help
- To get maximum network performace, you should use L1 memory as rx/tx buffers.
+ To get maximum network performance, you should use L1 memory as rx/tx buffers.
Say N here if you want to reserve L1 memory for other uses.
config BFIN_TX_DESC_NUM
@@ -895,8 +881,7 @@ config SMC9194
<file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
available from <http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called smc9194.
config SMC91X
@@ -914,8 +899,7 @@ config SMC91X
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called smc91x. If you want to compile it as a
- module, say M here and read <file:Documentation/kbuild/modules.txt>
- as well as <file:Documentation/networking/net-modules.txt>.
+ module, say M here and read <file:Documentation/kbuild/modules.txt>.
config NET_NETX
tristate "NetX Ethernet support"
@@ -924,8 +908,7 @@ config NET_NETX
help
This is support for the Hilscher netX builtin Ethernet ports
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called netx-eth.
config DM9000
@@ -936,15 +919,14 @@ config DM9000
---help---
Support for DM9000 chipset.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will be
- called dm9000.
+ To compile this driver as a module, choose M here. The module
+ will be called dm9000.
config SMC911X
tristate "SMSC LAN911[5678] support"
select CRC32
select MII
- depends on ARCH_PXA
+ depends on ARCH_PXA || SUPERH
help
This is a driver for SMSC's LAN911x series of Ethernet chipsets
including the new LAN9115, LAN9116, LAN9117, and LAN9118.
@@ -978,8 +960,7 @@ config NI5010
<http://www.tldp.org/docs.html#howto>. Note that this is still
experimental code.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called ni5010.
config NI52
@@ -990,8 +971,7 @@ config NI52
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called ni52.
config NI65
@@ -1002,8 +982,7 @@ config NI65
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called ni65.
source "drivers/net/tulip/Kconfig"
@@ -1017,8 +996,7 @@ config AT1700
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called at1700.
config DEPCA
@@ -1031,8 +1009,7 @@ config DEPCA
<http://www.tldp.org/docs.html#howto> as well as
<file:drivers/net/depca.c>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called depca.
config HP100
@@ -1043,8 +1020,7 @@ config HP100
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called hp100.
config NET_ISA
@@ -1073,8 +1049,7 @@ config E2100
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called e2100.
config EWRK3
@@ -1088,8 +1063,7 @@ config EWRK3
well as the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called ewrk3.
config EEXPRESS
@@ -1103,8 +1077,7 @@ config EEXPRESS
because the driver was very unreliable. We now have a new driver
that should do better.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called eexpress.
config EEXPRESS_PRO
@@ -1117,8 +1090,7 @@ config EEXPRESS_PRO
driver. Please read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called eepro.
config HPLAN_PLUS
@@ -1130,8 +1102,7 @@ config HPLAN_PLUS
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called hp-plus.
config HPLAN
@@ -1143,8 +1114,7 @@ config HPLAN
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called hp.
config LP486E
@@ -1163,8 +1133,7 @@ config ETH16I
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called eth16i.
config NE2000
@@ -1184,8 +1153,7 @@ config NE2000
laptops), say N here and Y to "NE/2 (ne2000 MCA version) support",
below.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called ne.
config ZNET
@@ -1206,8 +1174,7 @@ config SEEQ8005
is for you, read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called seeq8005.
config NE2_MCA
@@ -1219,8 +1186,7 @@ config NE2_MCA
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called ne2.
config IBMLANA
@@ -1231,8 +1197,7 @@ config IBMLANA
CONFIG_MCA to use this driver. It is both available as an in-kernel
driver and as a module.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The only
+ To compile this driver as a module, choose M here. The only
currently supported card is the IBM LAN Adapter/A for Ethernet. It
will both support 16K and 32K memory windows, however a 32K window
gives a better security against packet losses. Usage of multiple
@@ -1246,79 +1211,11 @@ config IBMVETH
This driver supports virtual ethernet adapters on newer IBM iSeries
and pSeries systems.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will
+ To compile this driver as a module, choose M here. The module will
be called ibmveth.
-config IBM_EMAC
- tristate "PowerPC 4xx on-chip Ethernet support"
- depends on 4xx && !PPC_MERGE
- help
- This driver supports the PowerPC 4xx EMAC family of on-chip
- Ethernet controllers.
-
-config IBM_EMAC_RXB
- int "Number of receive buffers"
- depends on IBM_EMAC
- default "128"
-
-config IBM_EMAC_TXB
- int "Number of transmit buffers"
- depends on IBM_EMAC
- default "64"
-
-config IBM_EMAC_POLL_WEIGHT
- int "MAL NAPI polling weight"
- depends on IBM_EMAC
- default "32"
-
-config IBM_EMAC_RX_COPY_THRESHOLD
- int "RX skb copy threshold (bytes)"
- depends on IBM_EMAC
- default "256"
-
-config IBM_EMAC_RX_SKB_HEADROOM
- int "Additional RX skb headroom (bytes)"
- depends on IBM_EMAC
- default "0"
- help
- Additional receive skb headroom. Note, that driver
- will always reserve at least 2 bytes to make IP header
- aligned, so usually there is no need to add any additional
- headroom.
-
- If unsure, set to 0.
-
-config IBM_EMAC_PHY_RX_CLK_FIX
- bool "PHY Rx clock workaround"
- depends on IBM_EMAC && (405EP || 440GX || 440EP || 440GR)
- help
- Enable this if EMAC attached to a PHY which doesn't generate
- RX clock if there is no link, if this is the case, you will
- see "TX disable timeout" or "RX disable timeout" in the system
- log.
-
- If unsure, say N.
-
-config IBM_EMAC_DEBUG
- bool "Debugging"
- depends on IBM_EMAC
- default n
-
-config IBM_EMAC_ZMII
- bool
- depends on IBM_EMAC && (NP405H || NP405L || 44x)
- default y
-
-config IBM_EMAC_RGMII
- bool
- depends on IBM_EMAC && 440GX
- default y
-
-config IBM_EMAC_TAH
- bool
- depends on IBM_EMAC && 440GX
- default y
+source "drivers/net/ibm_emac/Kconfig"
+source "drivers/net/ibm_newemac/Kconfig"
config NET_PCI
bool "EISA, VLB, PCI and on board controllers"
@@ -1344,8 +1241,7 @@ config PCNET32
answer Y here and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called pcnet32.
config PCNET32_NAPI
@@ -1360,9 +1256,6 @@ config PCNET32_NAPI
deployed on potentially unfriendly networks (e.g. in a firewall),
then say Y here.
- See <file:Documentation/networking/NAPI_HOWTO.txt> for more
- information.
-
If in doubt, say N.
config AMD8111_ETH
@@ -1375,12 +1268,11 @@ config AMD8111_ETH
answer Y here and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called amd8111e.
config AMD8111E_NAPI
- bool "Enable NAPI support"
+ bool "Use RX polling (NAPI)"
depends on AMD8111_ETH
help
NAPI is a new driver API designed to reduce CPU and interrupt load
@@ -1391,9 +1283,6 @@ config AMD8111E_NAPI
deployed on potentially unfriendly networks (e.g. in a firewall),
then say Y here.
- See <file:Documentation/networking/NAPI_HOWTO.txt> for more
- information.
-
If in doubt, say N.
config ADAPTEC_STARFIRE
@@ -1422,9 +1311,6 @@ config ADAPTEC_STARFIRE_NAPI
deployed on potentially unfriendly networks (e.g. in a firewall),
then say Y here.
- See <file:Documentation/networking/NAPI_HOWTO.txt> for more
- information.
-
If in doubt, say N.
config AC3200
@@ -1436,8 +1322,7 @@ config AC3200
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called ac3200.
config APRICOT
@@ -1448,22 +1333,40 @@ config APRICOT
read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will be
- called apricot.
+ To compile this driver as a module, choose M here. The module
+ will be called apricot.
config B44
- tristate "Broadcom 4400 ethernet support"
- depends on NET_PCI && PCI
+ tristate "Broadcom 440x/47xx ethernet support"
+ depends on SSB_POSSIBLE
+ select SSB
select MII
help
- If you have a network (Ethernet) controller of this type, say Y and
- read the Ethernet-HOWTO, available from
+ If you have a network (Ethernet) controller of this type, say Y
+ or M and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will be
- called b44.
+ To compile this driver as a module, choose M here. The module
+ will be called b44.
+
+# Auto-select SSB PCI-HOST support, if possible
+config B44_PCI_AUTOSELECT
+ bool
+ depends on B44 && SSB_PCIHOST_POSSIBLE
+ select SSB_PCIHOST
+ default y
+
+# Auto-select SSB PCICORE driver, if possible
+config B44_PCICORE_AUTOSELECT
+ bool
+ depends on B44 && SSB_DRIVER_PCICORE_POSSIBLE
+ select SSB_DRIVER_PCICORE
+ default y
+
+config B44_PCI
+ bool
+ depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT
+ default y
config FORCEDETH
tristate "nForce Ethernet support"
@@ -1473,12 +1376,11 @@ config FORCEDETH
read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will be
- called forcedeth.
+ To compile this driver as a module, choose M here. The module
+ will be called forcedeth.
config FORCEDETH_NAPI
- bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)"
+ bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
depends on FORCEDETH && EXPERIMENTAL
help
NAPI is a new driver API designed to reduce CPU and interrupt load
@@ -1489,9 +1391,6 @@ config FORCEDETH_NAPI
deployed on potentially unfriendly networks (e.g. in a firewall),
then say Y here.
- See <file:Documentation/networking/NAPI_HOWTO.txt> for more
- information.
-
If in doubt, say N.
config CS89x0
@@ -1504,30 +1403,14 @@ config CS89x0
<http://www.tldp.org/docs.html#howto> as well as
<file:Documentation/networking/cs89x0.txt>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will be
- called cs89x0.
+ To compile this driver as a module, choose M here. The module
+ will be called cs89x0.
config TC35815
tristate "TOSHIBA TC35815 Ethernet support"
depends on NET_PCI && PCI && MIPS
select MII
-config DGRS
- tristate "Digi Intl. RightSwitch SE-X support"
- depends on NET_PCI && (PCI || EISA)
- ---help---
- This is support for the Digi International RightSwitch series of
- PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6
- models. If you have a network card of this type, say Y and read the
- Ethernet-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>. More specific
- information is contained in <file:Documentation/networking/dgrs.txt>.
-
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
- will be called dgrs.
-
config EEPRO100
tristate "EtherExpressPro/100 support (eepro100, original Becker driver)"
depends on NET_PCI && PCI
@@ -1537,8 +1420,7 @@ config EEPRO100
card, say Y and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called eepro100.
@@ -1565,8 +1447,7 @@ config E100
More specific information on configuring the driver is in
<file:Documentation/networking/e100.txt>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called e100.
config LNE390
@@ -1578,8 +1459,7 @@ config LNE390
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called lne390.
config FEALNX
@@ -1619,8 +1499,7 @@ config NE2K_PCI
NetVin NV5000SC Via 86C926 SureCom NE34 Winbond
Holtek HT80232 Holtek HT80229
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called ne2k-pci.
config NE3210
@@ -1633,8 +1512,7 @@ config NE3210
<http://www.tldp.org/docs.html#howto>. Note that this driver
will NOT WORK for NE3200 cards as they are completely different.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called ne3210.
config ES3210
@@ -1646,8 +1524,7 @@ config ES3210
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called es3210.
config 8139CP
@@ -1777,8 +1654,7 @@ config TLAN
Compaq NetFlex and Olicom cards. Please read the file
<file:Documentation/networking/tlan.txt> for more details.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called tlan.
Please email feedback to <torben.mathiasen@compaq.com>.
@@ -1818,9 +1694,6 @@ config VIA_RHINE_NAPI
deployed on potentially unfriendly networks (e.g. in a firewall),
then say Y here.
- See <file:Documentation/networking/NAPI_HOWTO.txt> for more
- information.
-
config LAN_SAA9730
bool "Philips SAA9730 Ethernet support"
depends on NET_PCI && PCI && MIPS_ATLAS
@@ -1842,6 +1715,15 @@ config SC92031
To compile this driver as a module, choose M here: the module
will be called sc92031. This is recommended.
+config CPMAC
+ tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)"
+ depends on NET_ETHERNET && EXPERIMENTAL && AR7
+ select PHYLIB
+ select FIXED_PHY
+ select FIXED_MII_100_FDX
+ help
+ TI AR7 CPMAC Ethernet support
+
config NET_POCKET
bool "Pocket and portable adapters"
depends on PARPORT
@@ -1948,6 +1830,28 @@ config FEC2
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_MERGE && PPC_MPC52xx && PPC_BESTCOMM_FEC
+ select CRC32
+ select PHYLIB
+ ---help---
+ This option enables support for the MPC5200's on-chip
+ Fast Ethernet Controller
+ If compiled as module, it will be called 'fec_mpc52xx.ko'.
+
+config FEC_MPC52xx_MDIO
+ bool "MPC52xx FEC MDIO bus driver"
+ depends on FEC_MPC52xx
+ default y
+ ---help---
+ The MPC5200's FEC can connect to the Ethernet either with
+ an external MII PHY chip or 10 Mbps 7-wire interface
+ (Motorola? industry standard).
+ If your board uses an external PHY connected to FEC, enable this.
+ If not sure, enable.
+ If compiled as module, it will be called 'fec_mpc52xx_phy.ko'.
+
config NE_H8300
tristate "NE2000 compatible support for H8/300"
depends on H8300
@@ -2009,14 +1913,15 @@ config ACENIC_OMIT_TIGON_I
The safe and default value for this is N.
config DL2K
- tristate "D-Link DL2000-based Gigabit Ethernet support"
+ tristate "DL2000/TC902x-based Gigabit Ethernet support"
depends on PCI
select CRC32
help
- This driver supports D-Link 2000-based gigabit ethernet cards, which
- includes
+ This driver supports DL2000/TC902x-based Gigabit ethernet cards,
+ which includes
D-Link DGE-550T Gigabit Ethernet Adapter.
D-Link DL2000-based Gigabit Ethernet Adapter.
+ Sundance/Tamarack TC902x Gigabit Ethernet Adapter.
To compile this driver as a module, choose M here: the
module will be called dl2k.
@@ -2039,8 +1944,7 @@ config E1000
More specific information on configuring the driver is in
<file:Documentation/networking/e1000.txt>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called e1000.
config E1000_NAPI
@@ -2055,9 +1959,6 @@ config E1000_NAPI
deployed on potentially unfriendly networks (e.g. in a firewall),
then say Y here.
- See <file:Documentation/networking/NAPI_HOWTO.txt> for more
- information.
-
If in doubt, say N.
config E1000_DISABLE_PACKET_SPLIT
@@ -2069,6 +1970,28 @@ config E1000_DISABLE_PACKET_SPLIT
If in doubt, say N.
+config E1000E
+ tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
+ depends on PCI
+ ---help---
+ This driver supports the PCI-Express Intel(R) PRO/1000 gigabit
+ ethernet family of adapters. For PCI or PCI-X e1000 adapters,
+ use the regular e1000 driver For more information on how to
+ identify your adapter, go to the Adapter & Driver ID Guide at:
+
+ <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+ For general information and support, go to the Intel support
+ website at:
+
+ <http://support.intel.com>
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/e1000e.txt>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called e1000e.
+
source "drivers/net/ixp2000/Kconfig"
config MYRI_SBUS
@@ -2099,8 +2022,7 @@ config HAMACHI
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will be
+ To compile this driver as a module, choose M here. The module will be
called hamachi.
config YELLOWFIN
@@ -2128,7 +2050,7 @@ config R8169
will be called r8169. This is recommended.
config R8169_NAPI
- bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)"
+ bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
depends on R8169 && EXPERIMENTAL
help
NAPI is a new driver API designed to reduce CPU and interrupt load
@@ -2139,9 +2061,6 @@ config R8169_NAPI
deployed on potentially unfriendly networks (e.g. in a firewall),
then say Y here.
- See <file:Documentation/networking/NAPI_HOWTO.txt> for more
- information.
-
If in doubt, say N.
config R8169_VLAN
@@ -2153,6 +2072,19 @@ config R8169_VLAN
If in doubt, say Y.
+config SB1250_MAC
+ tristate "SB1250 Gigabit Ethernet support"
+ depends on SIBYTE_SB1xxx_SOC
+ select PHYLIB
+ ---help---
+ This driver supports Gigabit Ethernet interfaces based on the
+ Broadcom SiByte family of System-On-a-Chip parts. They include
+ the BCM1120, BCM1125, BCM1125H, BCM1250, BCM1255, BCM1280, BCM1455
+ and BCM1480 chips.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sb1250-mac.
+
config SIS190
tristate "SiS190/SiS191 gigabit ethernet support"
depends on PCI
@@ -2189,6 +2121,16 @@ config SKGE
To compile this driver as a module, choose M here: the module
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 debugfs/skge/ethX displays the state of the internal
+ transmit and receive rings.
+
+ If unsure, say N.
+
config SKY2
tristate "SysKonnect Yukon2 support"
depends on PCI
@@ -2370,7 +2312,7 @@ config GIANFAR
and MPC86xx family of chips, and the FEC on the 8540.
config GFAR_NAPI
- bool "NAPI Support"
+ bool "Use Rx Polling (NAPI)"
depends on GIANFAR
config UCC_GETH
@@ -2382,7 +2324,7 @@ config UCC_GETH
which is available on some Freescale SOCs.
config UGETH_NAPI
- bool "NAPI Support"
+ bool "Use Rx Polling (NAPI)"
depends on UCC_GETH
config UGETH_MAGIC_PACKET
@@ -2398,13 +2340,16 @@ config UGETH_TX_ON_DEMAND
depends on UCC_GETH
config MV643XX_ETH
- tristate "MV-643XX Ethernet support"
- depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32)
+ tristate "Marvell Discovery (643XX) and Orion ethernet support"
+ depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || ARCH_ORION
select MII
help
- This driver supports the gigabit Ethernet on the Marvell MV643XX
- chipset which is used in the Momenco Ocelot C and Jaguar ATX and
- Pegasos II, amongst other PPC and MIPS boards.
+ This driver supports the gigabit ethernet MACs in the
+ Marvell Discovery PPC/MIPS chipset family (MV643XX) and
+ in the Marvell Orion ARM SoC family.
+
+ Some boards that use the Discovery chipset are the Momenco
+ Ocelot C and Jaguar ATX and Pegasos II.
config QLA3XXX
tristate "QLogic QLA3XXX Network Driver Support"
@@ -2500,19 +2445,42 @@ config CHELSIO_T3
config EHEA
tristate "eHEA Ethernet support"
- depends on IBMEBUS
+ depends on IBMEBUS && INET
+ select INET_LRO
---help---
This driver supports the IBM pSeries eHEA ethernet adapter.
To compile the driver as a module, choose M here. The module
will be called ehea.
+config IXGBE
+ tristate "Intel(R) 10GbE PCI Express adapters support"
+ depends on PCI
+ ---help---
+ This driver supports Intel(R) 10GbE PCI Express family of
+ adapters. For more information on how to identify your adapter, go
+ to the Adapter & Driver ID Guide at:
+
+ <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+ For general information and support, go to the Intel support
+ website at:
+
+ <http://support.intel.com>
+
+ More specific information on configuring the driver is in
+ <file:Documentation/networking/ixgbe.txt>.
+
+ To compile this driver as a module, choose M here. The module
+ will be called ixgbe.
+
config IXGB
tristate "Intel(R) PRO/10GbE support"
depends on PCI
---help---
- This driver supports Intel(R) PRO/10GbE family of
- adapters. For more information on how to identify your adapter, go
+ This driver supports Intel(R) PRO/10GbE family of adapters for
+ PCI-X type cards. For PCI-E type cards, use the "ixgbe" driver
+ instead. For more information on how to identify your adapter, go
to the Adapter & Driver ID Guide at:
<http://support.intel.com/support/network/adapter/pro100/21397.htm>
@@ -2525,8 +2493,7 @@ config IXGB
More specific information on configuring the driver is in
<file:Documentation/networking/ixgb.txt>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called ixgb.
config IXGB_NAPI
@@ -2541,9 +2508,6 @@ config IXGB_NAPI
deployed on potentially unfriendly networks (e.g. in a firewall),
then say Y here.
- See <file:Documentation/networking/NAPI_HOWTO.txt> for more
- information.
-
If in doubt, say N.
config S2IO
@@ -2566,16 +2530,14 @@ config S2IO_NAPI
deployed on potentially unfriendly networks (e.g. in a firewall),
then say Y here.
- See <file:Documentation/networking/NAPI_HOWTO.txt> for more
- information.
-
If in doubt, say N.
config MYRI10GE
tristate "Myricom Myri-10G Ethernet support"
- depends on PCI
+ depends on PCI && INET
select FW_LOADER
select CRC32
+ select INET_LRO
---help---
This driver supports Myricom Myri-10G Dual Protocol interface in
Ethernet mode. If the eeprom on your board is not recent enough,
@@ -2584,8 +2546,7 @@ config MYRI10GE
<http://www.myri.com/scs/download-Myri10GE.html>
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
+ To compile this driver as a module, choose M here. The module
will be called myri10ge.
config NETXEN_NIC
@@ -2594,6 +2555,13 @@ config NETXEN_NIC
help
This enables the support for NetXen's Gigabit Ethernet card.
+config NIU
+ tristate "Sun Neptune 10Gbit Ethernet support"
+ depends on PCI
+ help
+ This enables support for cards based upon Sun's
+ Neptune chipset.
+
config PASEMI_MAC
tristate "PA Semi 1/10Gbit MAC"
depends on PPC64 && PCI
@@ -2617,6 +2585,12 @@ config MLX4_DEBUG
debug_level module parameter (which can also be set after
the driver is loaded through sysfs).
+config TEHUTI
+ tristate "Tehuti Networks 10G Ethernet"
+ depends on PCI
+ help
+ Tehuti Networks 10G Ethernet NIC
+
endif # NETDEV_10000
source "drivers/net/tokenring/Kconfig"
@@ -2796,10 +2770,9 @@ config PLIP
with the PLIP support in Linux versions 1.0.x. This option enlarges
your kernel by about 8 KB.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will be
- called plip. If unsure, say Y or M, in case you buy a laptop
- later.
+ To compile this driver as a module, choose M here. The module
+ will be called plip. If unsure, say Y or M, in case you buy
+ a laptop later.
config PPP
tristate "PPP (point-to-point protocol) support"
@@ -2829,8 +2802,7 @@ config PPP
If you said Y to "Version information on all symbols" above, then
you cannot compile the PPP driver into the kernel; you can then only
compile it as a module. To compile this driver as a module, choose M
- here and read <file:Documentation/networking/net-modules.txt>.
- The module will be called ppp_generic.
+ here. The module will be called ppp_generic.
config PPP_MULTILINK
bool "PPP multilink support (EXPERIMENTAL)"
@@ -2991,9 +2963,8 @@ config SLIP
<http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). SLIP
support will enlarge your kernel by about 4 KB. If unsure, say N.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will be
- called slip.
+ To compile this driver as a module, choose M here. The module
+ will be called slip.
config SLIP_COMPRESSED
bool "CSLIP compressed headers"
@@ -3074,6 +3045,16 @@ config NETCONSOLE
If you want to log kernel messages over the network, enable this.
See <file:Documentation/networking/netconsole.txt> for details.
+config NETCONSOLE_DYNAMIC
+ bool "Dynamic reconfiguration of logging targets (EXPERIMENTAL)"
+ depends on NETCONSOLE && SYSFS && EXPERIMENTAL
+ select CONFIGFS_FS
+ help
+ This option enables the ability to dynamically reconfigure target
+ parameters (interface, IP addresses, port numbers, MAC addresses)
+ at runtime through a userspace interface exported using configfs.
+ See <file:Documentation/networking/netconsole.txt> for details.
+
config NETPOLL
def_bool NETCONSOLE
@@ -3085,4 +3066,10 @@ config NETPOLL_TRAP
config NET_POLL_CONTROLLER
def_bool NETPOLL
+config VIRTIO_NET
+ tristate "Virtio network driver (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && VIRTIO
+ ---help---
+ This is the virtual network driver for lguest. Say Y or M.
+
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 9c928a84584..0e5fde4a1b2 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -3,14 +3,19 @@
#
obj-$(CONFIG_E1000) += e1000/
+obj-$(CONFIG_E1000E) += e1000e/
obj-$(CONFIG_IBM_EMAC) += ibm_emac/
+obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/
+obj-$(CONFIG_IXGBE) += ixgbe/
obj-$(CONFIG_IXGB) += ixgb/
+obj-$(CONFIG_IP1000) += ipg.o
obj-$(CONFIG_CHELSIO_T1) += chelsio/
obj-$(CONFIG_CHELSIO_T3) += cxgb3/
obj-$(CONFIG_EHEA) += ehea/
obj-$(CONFIG_BONDING) += bonding/
obj-$(CONFIG_ATL1) += atl1/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
+obj-$(CONFIG_TEHUTI) += tehuti.o
gianfar_driver-objs := gianfar.o \
gianfar_ethtool.o \
@@ -39,7 +44,6 @@ obj-$(CONFIG_SUNVNET) += sunvnet.o
obj-$(CONFIG_MACE) += mace.o
obj-$(CONFIG_BMAC) += bmac.o
-obj-$(CONFIG_DGRS) += dgrs.o
obj-$(CONFIG_VORTEX) += 3c59x.o
obj-$(CONFIG_TYPHOON) += typhoon.o
obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
@@ -92,6 +96,10 @@ obj-$(CONFIG_SHAPER) += shaper.o
obj-$(CONFIG_HP100) += hp100.o
obj-$(CONFIG_SMC9194) += smc9194.o
obj-$(CONFIG_FEC) += fec.o
+obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
+ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
+ obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
+endif
obj-$(CONFIG_68360_ENET) += 68360enet.o
obj-$(CONFIG_WD80x3) += wd.o 8390.o
obj-$(CONFIG_EL2) += 3c503.o 8390.o
@@ -106,7 +114,7 @@ obj-$(CONFIG_E2100) += e2100.o 8390.o
obj-$(CONFIG_ES3210) += es3210.o 8390.o
obj-$(CONFIG_LNE390) += lne390.o 8390.o
obj-$(CONFIG_NE3210) += ne3210.o 8390.o
-obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o
+obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
obj-$(CONFIG_B44) += b44.o
obj-$(CONFIG_FORCEDETH) += forcedeth.o
obj-$(CONFIG_NE_H8300) += ne-h8300.o
@@ -155,6 +163,7 @@ obj-$(CONFIG_8139CP) += 8139cp.o
obj-$(CONFIG_8139TOO) += 8139too.o
obj-$(CONFIG_ZNET) += znet.o
obj-$(CONFIG_LAN_SAA9730) += saa9730.o
+obj-$(CONFIG_CPMAC) += cpmac.o
obj-$(CONFIG_DEPCA) += depca.o
obj-$(CONFIG_EWRK3) += ewrk3.o
obj-$(CONFIG_ATP) += atp.o
@@ -178,7 +187,6 @@ obj-$(CONFIG_ZORRO8390) += zorro8390.o
obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
obj-$(CONFIG_EQUALIZER) += eql.o
-obj-$(CONFIG_LGUEST_NET) += lguest_net.o
obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o
@@ -193,6 +201,7 @@ obj-$(CONFIG_MACSONIC) += macsonic.o
obj-$(CONFIG_MACMACE) += macmace.o
obj-$(CONFIG_MAC89x0) += mac89x0.o
obj-$(CONFIG_TUN) += tun.o
+obj-$(CONFIG_VETH) += veth.o
obj-$(CONFIG_NET_NETX) += netx-eth.o
obj-$(CONFIG_DL2K) += dl2k.o
obj-$(CONFIG_R8169) += r8169.o
@@ -236,3 +245,5 @@ obj-$(CONFIG_NETCONSOLE) += netconsole.o
obj-$(CONFIG_FS_ENET) += fs_enet/
obj-$(CONFIG_NETXEN_NIC) += netxen/
+obj-$(CONFIG_NIU) += niu.o
+obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index a45de6975bf..18f7f815f66 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -119,7 +119,6 @@ struct lance_private {
int lance_log_rx_bufs, lance_log_tx_bufs;
int rx_ring_mod_mask, tx_ring_mod_mask;
- struct net_device_stats stats;
int tpe; /* cable-selection is TPE */
int auto_select; /* cable-selection by carrier */
unsigned short busmaster_regval;
@@ -294,18 +293,18 @@ static int lance_rx (struct net_device *dev)
/* We got an incomplete frame? */
if ((bits & LE_R1_POK) != LE_R1_POK) {
- lp->stats.rx_over_errors++;
- lp->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
continue;
} else if (bits & LE_R1_ERR) {
/* Count only the end frame as a rx error,
* not the beginning
*/
- if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
- if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
- if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
- if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
- if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+ if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++;
+ if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++;
+ if (bits & LE_R1_OFL) dev->stats.rx_over_errors++;
+ if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
+ if (bits & LE_R1_EOP) dev->stats.rx_errors++;
} else {
len = (rd->mblength & 0xfff) - 4;
skb = dev_alloc_skb (len+2);
@@ -313,7 +312,7 @@ static int lance_rx (struct net_device *dev)
if (skb == 0) {
printk(KERN_WARNING "%s: Memory squeeze, "
"deferring packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
rd->mblength = 0;
rd->rmd1_bits = LE_R1_OWN;
lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
@@ -328,8 +327,8 @@ static int lance_rx (struct net_device *dev)
skb->protocol = eth_type_trans (skb, dev);
netif_rx (skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
}
/* Return the packet to the pool */
@@ -364,12 +363,12 @@ static int lance_tx (struct net_device *dev)
if (td->tmd1_bits & LE_T1_ERR) {
status = td->misc;
- lp->stats.tx_errors++;
- if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
- if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
+ if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) dev->stats.tx_window_errors++;
if (status & LE_T3_CLOS) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (lp->auto_select) {
lp->tpe = 1 - lp->tpe;
printk(KERN_ERR "%s: Carrier Lost, "
@@ -388,7 +387,7 @@ static int lance_tx (struct net_device *dev)
/* buffer errors and underflows turn off the transmitter */
/* Restart the adapter */
if (status & (LE_T3_BUF|LE_T3_UFL)) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, "
"restarting\n", dev->name);
@@ -408,13 +407,13 @@ static int lance_tx (struct net_device *dev)
/* One collision before packet was sent. */
if (td->tmd1_bits & LE_T1_EONE)
- lp->stats.collisions++;
+ dev->stats.collisions++;
/* More than one collision, be optimistic. */
if (td->tmd1_bits & LE_T1_EMORE)
- lp->stats.collisions += 2;
+ dev->stats.collisions += 2;
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
j = (j + 1) & lp->tx_ring_mod_mask;
@@ -459,9 +458,9 @@ static irqreturn_t lance_interrupt (int irq, void *dev_id)
/* Log misc errors. */
if (csr0 & LE_C0_BABL)
- lp->stats.tx_errors++; /* Tx babble. */
+ dev->stats.tx_errors++; /* Tx babble. */
if (csr0 & LE_C0_MISS)
- lp->stats.rx_errors++; /* Missed a Rx frame. */
+ dev->stats.rx_errors++; /* Missed a Rx frame. */
if (csr0 & LE_C0_MERR) {
printk(KERN_ERR "%s: Bus master arbitration failure, status "
"%4.4x.\n", dev->name, csr0);
@@ -606,7 +605,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
/* Now, give the packet to the lance */
ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
- lp->stats.tx_bytes += skblen;
+ dev->stats.tx_bytes += skblen;
if (TX_BUFFS_AVAIL <= 0)
netif_stop_queue(dev);
@@ -621,13 +620,6 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
return status;
}
-static struct net_device_stats *lance_get_stats (struct net_device *dev)
-{
- struct lance_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/* taken from the depca driver */
static void lance_load_multicast (struct net_device *dev)
{
@@ -724,6 +716,7 @@ static int __devinit a2065_init_one(struct zorro_dev *z,
unsigned long board, base_addr, mem_start;
struct resource *r1, *r2;
int err;
+ DECLARE_MAC_BUF(mac);
board = z->resource.start;
base_addr = board+A2065_LANCE;
@@ -746,7 +739,6 @@ static int __devinit a2065_init_one(struct zorro_dev *z,
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
priv = netdev_priv(dev);
r1->name = dev->name;
@@ -783,7 +775,6 @@ static int __devinit a2065_init_one(struct zorro_dev *z,
dev->hard_start_xmit = &lance_start_xmit;
dev->tx_timeout = &lance_tx_timeout;
dev->watchdog_timeo = 5*HZ;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
dev->dma = 0;
@@ -802,9 +793,8 @@ static int __devinit a2065_init_one(struct zorro_dev *z,
zorro_set_drvdata(z, dev);
printk(KERN_INFO "%s: A2065 at 0x%08lx, Ethernet Address "
- "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ "%s\n", dev->name, board,
+ print_mac(mac, dev->dev_addr));
return 0;
}
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index 644c408515d..5136d94923a 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -103,8 +103,6 @@ static int __init do_ac3200_probe(struct net_device *dev)
int irq = dev->irq;
int mem_start = dev->mem_start;
- SET_MODULE_OWNER(dev);
-
if (ioaddr > 0x1ff) /* Check a single specified location. */
return ac_probe1(ioaddr, dev);
else if (ioaddr > 0) /* Don't probe at all. */
@@ -148,6 +146,7 @@ out:
static int __init ac_probe1(int ioaddr, struct net_device *dev)
{
int i, retval;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -169,10 +168,11 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3));
#endif
- printk("AC3200 in EISA slot %d, node", ioaddr/0x1000);
- for(i = 0; i < 6; i++)
- printk(" %02x", dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i));
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i);
+ printk(KERN_DEBUG "AC3200 in EISA slot %d, node %s",
+ ioaddr/0x1000, print_mac(mac, dev->dev_addr));
#if 0
/* Check the vendor ID/prefix. Redundant after checking the EISA ID */
if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 62e660a7938..6c192650d34 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -406,7 +406,7 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
#define DEF_STAT (2 * TICKS_PER_SEC)
-static int link[ACE_MAX_MOD_PARMS];
+static int link_state[ACE_MAX_MOD_PARMS];
static int trace[ACE_MAX_MOD_PARMS];
static int tx_coal_tick[ACE_MAX_MOD_PARMS];
static int rx_coal_tick[ACE_MAX_MOD_PARMS];
@@ -419,7 +419,7 @@ MODULE_AUTHOR("Jes Sorensen <jes@trained-monkey.org>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
-module_param_array(link, int, NULL, 0);
+module_param_array_named(link, link_state, int, NULL, 0);
module_param_array(trace, int, NULL, 0);
module_param_array(tx_coal_tick, int, NULL, 0);
module_param_array(max_tx_desc, int, NULL, 0);
@@ -465,7 +465,6 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev,
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
ap = dev->priv;
@@ -894,6 +893,7 @@ static int __devinit ace_init(struct net_device *dev)
int board_idx, ecode = 0;
short i;
unsigned char cache_size;
+ DECLARE_MAC_BUF(mac);
ap = netdev_priv(dev);
regs = ap->regs;
@@ -987,36 +987,32 @@ static int __devinit ace_init(struct net_device *dev)
mac1 = 0;
for(i = 0; i < 4; i++) {
- int tmp;
+ int t;
mac1 = mac1 << 8;
- tmp = read_eeprom_byte(dev, 0x8c+i);
- if (tmp < 0) {
+ t = read_eeprom_byte(dev, 0x8c+i);
+ if (t < 0) {
ecode = -EIO;
goto init_error;
} else
- mac1 |= (tmp & 0xff);
+ mac1 |= (t & 0xff);
}
mac2 = 0;
for(i = 4; i < 8; i++) {
- int tmp;
+ int t;
mac2 = mac2 << 8;
- tmp = read_eeprom_byte(dev, 0x8c+i);
- if (tmp < 0) {
+ t = read_eeprom_byte(dev, 0x8c+i);
+ if (t < 0) {
ecode = -EIO;
goto init_error;
} else
- mac2 |= (tmp & 0xff);
+ mac2 |= (t & 0xff);
}
writel(mac1, &regs->MacAddrHi);
writel(mac2, &regs->MacAddrLo);
- printk("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
- (mac1 >> 8) & 0xff, mac1 & 0xff, (mac2 >> 24) &0xff,
- (mac2 >> 16) & 0xff, (mac2 >> 8) & 0xff, mac2 & 0xff);
-
dev->dev_addr[0] = (mac1 >> 8) & 0xff;
dev->dev_addr[1] = mac1 & 0xff;
dev->dev_addr[2] = (mac2 >> 24) & 0xff;
@@ -1024,6 +1020,8 @@ static int __devinit ace_init(struct net_device *dev)
dev->dev_addr[4] = (mac2 >> 8) & 0xff;
dev->dev_addr[5] = mac2 & 0xff;
+ printk("MAC: %s\n", print_mac(mac, dev->dev_addr));
+
/*
* Looks like this is necessary to deal with on all architectures,
* even this %$#%$# N440BX Intel based thing doesn't get it right.
@@ -1307,10 +1305,10 @@ static int __devinit ace_init(struct net_device *dev)
writel(TX_RING_BASE, &regs->WinBase);
if (ACE_IS_TIGON_I(ap)) {
- ap->tx_ring = (struct tx_desc *) regs->Window;
+ ap->tx_ring = (__force struct tx_desc *) regs->Window;
for (i = 0; i < (TIGON_I_TX_RING_ENTRIES
* sizeof(struct tx_desc)) / sizeof(u32); i++)
- writel(0, (void __iomem *)ap->tx_ring + i * 4);
+ writel(0, (__force void __iomem *)ap->tx_ring + i * 4);
set_aceaddr(&info->tx_ctrl.rngptr, TX_RING_BASE);
} else {
@@ -1396,8 +1394,8 @@ static int __devinit ace_init(struct net_device *dev)
/*
* Override link default parameters
*/
- if ((board_idx >= 0) && link[board_idx]) {
- int option = link[board_idx];
+ if ((board_idx >= 0) && link_state[board_idx]) {
+ int option = link_state[board_idx];
tmp = LNK_ENABLE;
@@ -2385,8 +2383,9 @@ static int ace_close(struct net_device *dev)
if (mapping) {
if (ACE_IS_TIGON_I(ap)) {
- struct tx_desc __iomem *tx
- = (struct tx_desc __iomem *) &ap->tx_ring[i];
+ /* NB: TIGON_1 is special, tx_ring is in io space */
+ struct tx_desc __iomem *tx;
+ tx = (__force struct tx_desc __iomem *) &ap->tx_ring[i];
writel(0, &tx->addr.addrhi);
writel(0, &tx->addr.addrlo);
writel(0, &tx->flagsize);
@@ -2446,7 +2445,7 @@ ace_load_tx_bd(struct ace_private *ap, struct tx_desc *desc, u64 addr,
#endif
if (ACE_IS_TIGON_I(ap)) {
- struct tx_desc __iomem *io = (struct tx_desc __iomem *) desc;
+ struct tx_desc __iomem *io = (__force struct tx_desc __iomem *) desc;
writel(addr >> 32, &io->addr.addrhi);
writel(addr & 0xffffffff, &io->addr.addrlo);
writel(flagsize, &io->flagsize);
@@ -2938,7 +2937,7 @@ static void __devinit ace_clear(struct ace_regs __iomem *regs, u32 dest, int siz
* This operation requires the NIC to be halted and is performed with
* interrupts disabled and with the spinlock hold.
*/
-int __devinit ace_load_firmware(struct net_device *dev)
+static int __devinit ace_load_firmware(struct net_device *dev)
{
struct ace_private *ap = netdev_priv(dev);
struct ace_regs __iomem *regs = ap->regs;
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index a61b2f89fc3..eebf5bb2b03 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -709,7 +709,8 @@ static int amd8111e_tx(struct net_device *dev)
lp->tx_complete_idx++;
/*COAL update tx coalescing parameters */
lp->coal_conf.tx_packets++;
- lp->coal_conf.tx_bytes += lp->tx_ring[tx_index].buff_count;
+ lp->coal_conf.tx_bytes +=
+ le16_to_cpu(lp->tx_ring[tx_index].buff_count);
if (netif_queue_stopped(dev) &&
lp->tx_complete_idx > lp->tx_idx - NUM_TX_BUFFERS +2){
@@ -723,9 +724,10 @@ static int amd8111e_tx(struct net_device *dev)
#ifdef CONFIG_AMD8111E_NAPI
/* This function handles the driver receive operation in polling mode */
-static int amd8111e_rx_poll(struct net_device *dev, int * budget)
+static int amd8111e_rx_poll(struct napi_struct *napi, int budget)
{
- struct amd8111e_priv *lp = netdev_priv(dev);
+ struct amd8111e_priv *lp = container_of(napi, struct amd8111e_priv, napi);
+ struct net_device *dev = lp->amd8111e_net_dev;
int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK;
void __iomem *mmio = lp->mmio;
struct sk_buff *skb,*new_skb;
@@ -737,7 +739,7 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget)
#if AMD8111E_VLAN_TAG_USED
short vtag;
#endif
- int rx_pkt_limit = dev->quota;
+ int rx_pkt_limit = budget;
unsigned long flags;
do{
@@ -838,21 +840,14 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget)
} while(intr0 & RINT0);
/* Receive descriptor is empty now */
- dev->quota -= num_rx_pkt;
- *budget -= num_rx_pkt;
-
spin_lock_irqsave(&lp->lock, flags);
- netif_rx_complete(dev);
+ __netif_rx_complete(dev, napi);
writel(VAL0|RINTEN0, mmio + INTEN0);
writel(VAL2 | RDMD0, mmio + CMD0);
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
rx_not_empty:
- /* Do not call a netif_rx_complete */
- dev->quota -= num_rx_pkt;
- *budget -= num_rx_pkt;
- return 1;
+ return num_rx_pkt;
}
#else
@@ -1116,7 +1111,7 @@ static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
return new_stats;
}
-/* This function recalculate the interupt coalescing mode on every interrupt
+/* This function recalculate the interrupt coalescing mode on every interrupt
according to the datarate and the packet rate.
*/
static int amd8111e_calc_coalesce(struct net_device *dev)
@@ -1287,11 +1282,11 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id)
/* Check if Receive Interrupt has occurred. */
#ifdef CONFIG_AMD8111E_NAPI
if(intr0 & RINT0){
- if(netif_rx_schedule_prep(dev)){
+ if(netif_rx_schedule_prep(dev, &lp->napi)){
/* Disable receive interupts */
writel(RINTEN0, mmio + INTEN0);
/* Schedule a polling routine */
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &lp->napi);
}
else if (intren0 & RINTEN0) {
printk("************Driver bug! \
@@ -1345,6 +1340,8 @@ static int amd8111e_close(struct net_device * dev)
struct amd8111e_priv *lp = netdev_priv(dev);
netif_stop_queue(dev);
+ napi_disable(&lp->napi);
+
spin_lock_irq(&lp->lock);
amd8111e_disable_interrupt(lp);
@@ -1375,12 +1372,15 @@ static int amd8111e_open(struct net_device * dev )
dev->name, dev))
return -EAGAIN;
+ napi_enable(&lp->napi);
+
spin_lock_irq(&lp->lock);
amd8111e_init_hw_default(lp);
if(amd8111e_restart(dev)){
spin_unlock_irq(&lp->lock);
+ napi_disable(&lp->napi);
if (dev->irq)
free_irq(dev->irq, dev);
return -ENOMEM;
@@ -1405,7 +1405,7 @@ This function checks if there is any transmit descriptors available to queue mo
static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp )
{
int tx_index = lp->tx_idx & TX_BUFF_MOD_MASK;
- if(lp->tx_skbuff[tx_index] != 0)
+ if (lp->tx_skbuff[tx_index])
return -1;
else
return 0;
@@ -1442,7 +1442,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev)
lp->tx_dma_addr[tx_index] =
pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
lp->tx_ring[tx_index].buff_phy_addr =
- (u32) cpu_to_le32(lp->tx_dma_addr[tx_index]);
+ cpu_to_le32(lp->tx_dma_addr[tx_index]);
/* Set FCS and LTINT bits */
wmb();
@@ -1935,6 +1935,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
unsigned long reg_addr,reg_len;
struct amd8111e_priv* lp;
struct net_device* dev;
+ DECLARE_MAC_BUF(mac);
err = pci_enable_device(pdev);
if(err){
@@ -1983,7 +1984,6 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
goto err_free_reg;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
#if AMD8111E_VLAN_TAG_USED
@@ -1999,7 +1999,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
spin_lock_init(&lp->lock);
lp->mmio = ioremap(reg_addr, reg_len);
- if (lp->mmio == 0) {
+ if (!lp->mmio) {
printk(KERN_ERR "amd8111e: Cannot map device registers, "
"exiting\n");
err = -ENOMEM;
@@ -2008,7 +2008,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
/* Initializing MAC address */
for(i = 0; i < ETH_ADDR_LEN; i++)
- dev->dev_addr[i] =readb(lp->mmio + PADR + i);
+ dev->dev_addr[i] = readb(lp->mmio + PADR + i);
/* Setting user defined parametrs */
lp->ext_phy_option = speed_duplex[card_idx];
@@ -2031,8 +2031,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
dev->tx_timeout = amd8111e_tx_timeout;
dev->watchdog_timeo = AMD8111E_TX_TIMEOUT;
#ifdef CONFIG_AMD8111E_NAPI
- dev->poll = amd8111e_rx_poll;
- dev->weight = 32;
+ netif_napi_add(dev, &lp->napi, amd8111e_rx_poll, 32);
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = amd8111e_poll;
@@ -2078,11 +2077,10 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
/* display driver and device information */
chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28;
- printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n", dev->name,MODULE_VERS);
- printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet ", dev->name, chip_version);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c",dev->dev_addr[i],i == 5 ? ' ' : ':');
- printk( "\n");
+ printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n",
+ dev->name,MODULE_VERS);
+ printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet %s\n",
+ dev->name, chip_version, print_mac(mac, dev->dev_addr));
if (lp->ext_phy_id)
printk(KERN_INFO "%s: Found MII PHY ID 0x%08x at address 0x%02x\n",
dev->name, lp->ext_phy_id, lp->ext_phy_addr);
diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h
index e65080a5994..28c60a71ed5 100644
--- a/drivers/net/amd8111e.h
+++ b/drivers/net/amd8111e.h
@@ -655,32 +655,32 @@ typedef enum {
struct amd8111e_tx_dr{
- u16 buff_count; /* Size of the buffer pointed by this descriptor */
+ __le16 buff_count; /* Size of the buffer pointed by this descriptor */
- u16 tx_flags;
+ __le16 tx_flags;
- u16 tag_ctrl_info;
+ __le16 tag_ctrl_info;
- u16 tag_ctrl_cmd;
+ __le16 tag_ctrl_cmd;
- u32 buff_phy_addr;
+ __le32 buff_phy_addr;
- u32 reserved;
+ __le32 reserved;
};
struct amd8111e_rx_dr{
- u32 reserved;
+ __le32 reserved;
- u16 msg_count; /* Received message len */
+ __le16 msg_count; /* Received message len */
- u16 tag_ctrl_info;
+ __le16 tag_ctrl_info;
- u16 buff_count; /* Len of the buffer pointed by descriptor. */
+ __le16 buff_count; /* Len of the buffer pointed by descriptor. */
- u16 rx_flags;
+ __le16 rx_flags;
- u32 buff_phy_addr;
+ __le32 buff_phy_addr;
};
struct amd8111e_link_config{
@@ -763,6 +763,8 @@ struct amd8111e_priv{
/* Reg memory mapped address */
void __iomem *mmio;
+ struct napi_struct napi;
+
spinlock_t lock; /* Guard lock */
unsigned long rx_idx, tx_idx; /* The next free ring entry */
unsigned long tx_complete_idx;
diff --git a/drivers/net/apne.c b/drivers/net/apne.c
index 954191119d3..c12cbdf368b 100644
--- a/drivers/net/apne.c
+++ b/drivers/net/apne.c
@@ -148,7 +148,6 @@ struct net_device * __init apne_probe(int unit)
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
/* disable pcmcia irq for readtuple */
pcmcia_disable_irq();
@@ -205,6 +204,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
int neX000, ctron;
#endif
static unsigned version_printed;
+ DECLARE_MAC_BUF(mac);
if (ei_debug && version_printed++ == 0)
printk(version);
@@ -247,7 +247,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
{0x00, NE_EN0_RSARHI},
{E8390_RREAD+E8390_START, NE_CMD},
};
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++) {
outb(program_seq[i].value, ioaddr + program_seq[i].offset);
}
@@ -317,12 +317,12 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);
if (i) return i;
- for(i = 0; i < ETHER_ADDR_LEN; i++) {
- printk(" %2.2x", SA_prom[i]);
+ for(i = 0; i < ETHER_ADDR_LEN; i++)
dev->dev_addr[i] = SA_prom[i];
- }
- printk("\n%s: %s found.\n", dev->name, name);
+ printk(" %s\n", print_mac(mac, dev->dev_addr));
+
+ printk("%s: %s found.\n", dev->name, name);
ei_status.name = name;
ei_status.tx_start_page = start_page;
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index da6ffa8cd81..92c3a4cf0bb 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -194,10 +194,6 @@ static void cops_timeout(struct net_device *dev);
static void cops_rx (struct net_device *dev);
static int cops_send_packet (struct sk_buff *skb, struct net_device *dev);
static void set_multicast_list (struct net_device *dev);
-static int cops_hard_header (struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len);
-
static int cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
static int cops_close (struct net_device *dev);
static struct net_device_stats *cops_get_stats (struct net_device *dev);
@@ -235,8 +231,6 @@ struct net_device * __init cops_probe(int unit)
base_addr = dev->base_addr = io;
}
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) { /* Check a single specified location. */
err = cops_probe1(dev, base_addr);
} else if (base_addr != 0) { /* Don't probe at all. */
@@ -333,7 +327,6 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr)
dev->base_addr = ioaddr;
lp = netdev_priv(dev);
- memset(lp, 0, sizeof(struct cops_local));
spin_lock_init(&lp->lock);
/* Copy local board variable to lp struct. */
@@ -342,7 +335,7 @@ static int __init cops_probe1(struct net_device *dev, int ioaddr)
dev->hard_start_xmit = cops_send_packet;
dev->tx_timeout = cops_timeout;
dev->watchdog_timeo = HZ * 2;
- dev->hard_header = cops_hard_header;
+
dev->get_stats = cops_get_stats;
dev->open = cops_open;
dev->stop = cops_close;
@@ -947,19 +940,6 @@ static void set_multicast_list(struct net_device *dev)
}
/*
- * Another Dummy function to keep the Appletalk layer happy.
- */
-
-static int cops_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
-{
- if(cops_debug >= 3)
- printk("%s: cops_hard_header executed. Wow!\n", dev->name);
- return 0;
-}
-
-/*
* System ioctls for the COPS LocalTalk card.
*/
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index f22e46dfd77..1071144edd6 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -65,7 +65,6 @@ static struct net_device * __init ipddp_init(void)
if (!dev)
return ERR_PTR(-ENOMEM);
- SET_MODULE_OWNER(dev);
strcpy(dev->name, "ipddp%d");
if (version_printed++ == 0)
@@ -117,7 +116,7 @@ static struct net_device_stats *ipddp_get_stats(struct net_device *dev)
*/
static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
{
- u32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
+ __be32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
struct ddpehdr *ddp;
struct ipddp_route *rt;
struct atalk_addr *our_addr;
diff --git a/drivers/net/appletalk/ipddp.h b/drivers/net/appletalk/ipddp.h
index 52072fb0c61..531519da99a 100644
--- a/drivers/net/appletalk/ipddp.h
+++ b/drivers/net/appletalk/ipddp.h
@@ -14,7 +14,7 @@
struct ipddp_route
{
struct net_device *dev; /* Carrier device */
- __u32 ip; /* IP address */
+ __be32 ip; /* IP address */
struct atalk_addr at; /* Gateway appletalk address */
int flags;
struct ipddp_route *next;
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index 6a6cbd331a1..6ab2c2d4d67 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -870,15 +870,6 @@ static void set_multicast_list(struct net_device *dev)
/* Actually netatalk needs fixing! */
}
-static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len)
-{
- if(debug & DEBUG_VERBOSE)
- printk("ltpc_hard_header called for device %s\n",
- dev->name);
- return 0;
-}
-
static int ltpc_poll_counter;
static void ltpc_poll(unsigned long l)
@@ -1046,8 +1037,6 @@ struct net_device * __init ltpc_probe(void)
if (!dev)
goto out;
- SET_MODULE_OWNER(dev);
-
/* probe for the I/O port address */
if (io != 0x240 && request_region(0x220,8,"ltpc")) {
@@ -1143,7 +1132,6 @@ struct net_device * __init ltpc_probe(void)
/* Fill in the fields of the device structure with ethernet-generic values. */
dev->hard_start_xmit = ltpc_xmit;
- dev->hard_header = ltpc_hard_header;
dev->get_stats = ltpc_get_stats;
/* add the ltpc-specific things */
diff --git a/drivers/net/arcnet/Kconfig b/drivers/net/arcnet/Kconfig
index 4030274fe78..3b2f7f11546 100644
--- a/drivers/net/arcnet/Kconfig
+++ b/drivers/net/arcnet/Kconfig
@@ -19,8 +19,7 @@ menuconfig ARCNET
from <http://www.tldp.org/docs.html#howto>(even though ARCnet
is not really Ethernet).
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will
+ To compile this driver as a module, choose M here. The module will
be called arcnet.
if ARCNET
@@ -81,8 +80,7 @@ config ARCNET_COM90xx
have always used the old ARCnet driver without knowing what type of
card you had, this is probably the one for you.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will
+ To compile this driver as a module, choose M here. The module will
be called com90xx.
config ARCNET_COM90xxIO
@@ -93,8 +91,7 @@ config ARCNET_COM90xxIO
the normal driver. Only use it if your card doesn't support shared
memory.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will
+ To compile this driver as a module, choose M here. The module will
be called com90io.
config ARCNET_RIM_I
@@ -105,8 +102,7 @@ config ARCNET_RIM_I
driver is completely untested, so if you have one of these cards,
please mail <dwmw2@infradead.org>, especially if it works!
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will
+ To compile this driver as a module, choose M here. The module will
be called arc-rimi.
config ARCNET_COM20020
@@ -116,8 +112,7 @@ config ARCNET_COM20020
things as promiscuous mode, so packet sniffing is possible, and
extra diagnostic information.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will
+ To compile this driver as a module, choose M here. The module will
be called com20020.
config ARCNET_COM20020_ISA
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 681e20b8466..c59c8067de9 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -102,8 +102,8 @@ static int arcnet_close(struct net_device *dev);
static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev);
static void arcnet_timeout(struct net_device *dev);
static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len);
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len);
static int arcnet_rebuild_header(struct sk_buff *skb);
static struct net_device_stats *arcnet_get_stats(struct net_device *dev);
static int go_tx(struct net_device *dev);
@@ -317,11 +317,17 @@ static int choose_mtu(void)
return mtu == 65535 ? XMTU : mtu;
}
+static const struct header_ops arcnet_header_ops = {
+ .create = arcnet_header,
+ .rebuild = arcnet_rebuild_header,
+};
+
/* Setup a struct device for ARCnet. */
static void arcdev_setup(struct net_device *dev)
{
dev->type = ARPHRD_ARCNET;
+ dev->header_ops = &arcnet_header_ops;
dev->hard_header_len = sizeof(struct archdr);
dev->mtu = choose_mtu();
@@ -342,8 +348,6 @@ static void arcdev_setup(struct net_device *dev)
dev->hard_start_xmit = arcnet_send_packet;
dev->tx_timeout = arcnet_timeout;
dev->get_stats = arcnet_get_stats;
- dev->hard_header = arcnet_header;
- dev->rebuild_header = arcnet_rebuild_header;
}
struct net_device *alloc_arcdev(char *name)
@@ -488,10 +492,10 @@ static int arcnet_close(struct net_device *dev)
static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
- struct arcnet_local *lp = dev->priv;
+ const struct arcnet_local *lp = netdev_priv(dev);
uint8_t _daddr, proto_num;
struct ArcProto *proto;
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c
index 1f030273541..6599f1046c7 100644
--- a/drivers/net/arcnet/com90io.c
+++ b/drivers/net/arcnet/com90io.c
@@ -398,8 +398,6 @@ static int __init com90io_init(void)
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
-
dev->base_addr = io;
dev->irq = irq;
if (dev->irq == 2)
diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c
index 2de8877ece2..dab185bc51f 100644
--- a/drivers/net/arcnet/rfc1051.c
+++ b/drivers/net/arcnet/rfc1051.c
@@ -34,7 +34,7 @@
#define VERSION "arcnet: RFC1051 \"simple standard\" (`s') encapsulation support loaded.\n"
-static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev);
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);
static void rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length);
static int build_header(struct sk_buff *skb, struct net_device *dev,
@@ -86,7 +86,7 @@ MODULE_LICENSE("GPL");
*
* With ARCnet we have to convert everything to Ethernet-style stuff.
*/
-static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev)
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct arcnet_local *lp = dev->priv;
struct archdr *pkt = (struct archdr *) skb->data;
diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c
index 460a095000c..6d6d95cc440 100644
--- a/drivers/net/arcnet/rfc1201.c
+++ b/drivers/net/arcnet/rfc1201.c
@@ -34,7 +34,7 @@ MODULE_LICENSE("GPL");
#define VERSION "arcnet: RFC1201 \"standard\" (`a') encapsulation support loaded.\n"
-static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev);
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);
static void rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length);
static int build_header(struct sk_buff *skb, struct net_device *dev,
@@ -88,7 +88,7 @@ module_exit(arcnet_rfc1201_exit);
*
* With ARCnet we have to convert everything to Ethernet-style stuff.
*/
-static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev)
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct archdr *pkt = (struct archdr *) skb->data;
struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
@@ -456,7 +456,7 @@ static void load_pkt(struct net_device *dev, struct arc_hardware *hard,
excsoft.proto = soft->proto;
excsoft.split_flag = 0xff;
- excsoft.sequence = 0xffff;
+ excsoft.sequence = htons(0xffff);
hard->offset[0] = 0;
ofs = 512 - softlen;
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index bc5a38a6705..10f3a196be3 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -1,7 +1,7 @@
/*
* Amiga Linux/m68k Ariadne Ethernet Driver
*
- * © Copyright 1995-2003 by Geert Uytterhoeven (geert@linux-m68k.org)
+ * © Copyright 1995-2003 by Geert Uytterhoeven (geert@linux-m68k.org)
* Peter De Schrijver (p2@mind.be)
*
* ---------------------------------------------------------------------------
@@ -166,6 +166,7 @@ static int __devinit ariadne_init_one(struct zorro_dev *z,
struct net_device *dev;
struct ariadne_private *priv;
int err;
+ DECLARE_MAC_BUF(mac);
r1 = request_mem_region(base_addr, sizeof(struct Am79C960), "Am79C960");
if (!r1)
@@ -183,7 +184,6 @@ static int __devinit ariadne_init_one(struct zorro_dev *z,
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
priv = netdev_priv(dev);
r1->name = dev->name;
@@ -217,9 +217,8 @@ static int __devinit ariadne_init_one(struct zorro_dev *z,
zorro_set_drvdata(z, dev);
printk(KERN_INFO "%s: Ariadne at 0x%08lx, Ethernet Address "
- "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ "%s\n", dev->name, board,
+ print_mac(mac, dev->dev_addr));
return 0;
}
@@ -615,21 +614,17 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Fill in a Tx ring entry */
#if 0
- printk(KERN_DEBUG "TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]);
- {
- int i;
- u_char *ptr = &((u_char *)skb->data)[6];
- for (i = 0; i < 6; i++)
- printk("%02x", ptr[i]);
- }
- printk(" to ");
- {
- int i;
- u_char *ptr = (u_char *)skb->data;
- for (i = 0; i < 6; i++)
- printk("%02x", ptr[i]);
- }
- printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len);
+{
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+
+ printk(KERN_DEBUG "TX pkt type 0x%04x from %s to %s "
+ " data 0x%08x len %d\n",
+ ((u_short *)skb->data)[6],
+ print_mac(mac, ((const u8 *)skb->data)+6),
+ print_mac(mac, (const u8 *)skb->data),
+ (int)skb->data, (int)skb->len);
+}
#endif
local_irq_save(flags);
@@ -749,22 +744,22 @@ static int ariadne_rx(struct net_device *dev)
skb_copy_to_linear_data(skb, (char *)priv->rx_buff[entry], pkt_len);
skb->protocol=eth_type_trans(skb,dev);
#if 0
+{
+ DECLARE_MAC_BUF(mac);
+
printk(KERN_DEBUG "RX pkt type 0x%04x from ",
((u_short *)skb->data)[6]);
{
- int i;
u_char *ptr = &((u_char *)skb->data)[6];
- for (i = 0; i < 6; i++)
- printk("%02x", ptr[i]);
+ printk("%s", print_mac(mac, ptr));
}
printk(" to ");
{
- int i;
u_char *ptr = (u_char *)skb->data;
- for (i = 0; i < 6; i++)
- printk("%02x", ptr[i]);
+ printk("%s", print_mac(mac, ptr));
}
printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len);
+}
#endif
netif_rx(skb);
diff --git a/drivers/net/ariadne.h b/drivers/net/ariadne.h
index f7913d5a39f..bb613f292e0 100644
--- a/drivers/net/ariadne.h
+++ b/drivers/net/ariadne.h
@@ -1,7 +1,7 @@
/*
* Amiga Linux/m68k Ariadne Ethernet Driver
*
- * © Copyright 1995 by Geert Uytterhoeven (geert@linux-m68k.org)
+ * © Copyright 1995 by Geert Uytterhoeven (geert@linux-m68k.org)
* Peter De Schrijver
* (Peter.DeSchrijver@linux.cc.kuleuven.ac.be)
*
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 2143eeb7a2b..ba6bd03a015 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -414,7 +414,7 @@ static void am79c961_setmulticastlist (struct net_device *dev)
/*
* Update the multicast hash table
*/
- for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(multi_hash); i++)
write_rreg(dev->base_addr, i + LADRL, multi_hash[i]);
/*
@@ -741,12 +741,10 @@ static int __init am79c961_probe(struct platform_device *pdev)
ret = register_netdev(dev);
if (ret == 0) {
- printk(KERN_INFO "%s: ether address ", dev->name);
-
- /* Retrive and print the ethernet address. */
- for (i = 0; i < 6; i++)
- printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
+ DECLARE_MAC_BUF(mac);
+ printk(KERN_INFO "%s: ether address %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
return 0;
}
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index ef2cc80256a..25b114a4e2b 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -485,6 +485,7 @@ static void update_mac_address(struct net_device *dev)
static int set_mac_address(struct net_device *dev, void* addr)
{
struct sockaddr *address = addr;
+ DECLARE_MAC_BUF(mac);
if (!is_valid_ether_addr(address->sa_data))
return -EADDRNOTAVAIL;
@@ -492,9 +493,8 @@ static int set_mac_address(struct net_device *dev, void* addr)
memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
update_mac_address(dev);
- printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk("%s: Setting MAC address to %s\n", dev->name,
+ print_mac(mac, dev->dev_addr));
return 0;
}
@@ -979,6 +979,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
struct at91_private *lp;
unsigned int val;
int res;
+ DECLARE_MAC_BUF(mac);
dev = alloc_etherdev(sizeof(struct at91_private));
if (!dev)
@@ -986,7 +987,6 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
dev->base_addr = AT91_VA_BASE_EMAC;
dev->irq = AT91RM9200_ID_EMAC;
- SET_MODULE_OWNER(dev);
/* Install the interrupt handler */
if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) {
@@ -1082,12 +1082,11 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
}
/* Display ethernet banner */
- printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n",
- dev->name, (uint) dev->base_addr, dev->irq,
- at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
- at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%s)\n",
+ dev->name, (uint) dev->base_addr, dev->irq,
+ at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
+ at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
+ print_mac(mac, dev->dev_addr));
if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
else if (phy_type == MII_LXT971A_ID)
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index f6ece1d43f6..91a6590d107 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -169,6 +169,9 @@ struct ep93xx_priv
spinlock_t tx_pending_lock;
unsigned int tx_pending;
+ struct net_device *dev;
+ struct napi_struct napi;
+
struct net_device_stats stats;
struct mii_if_info mii;
@@ -190,15 +193,11 @@ static struct net_device_stats *ep93xx_get_stats(struct net_device *dev)
return &(ep->stats);
}
-static int ep93xx_rx(struct net_device *dev, int *budget)
+static int ep93xx_rx(struct net_device *dev, int processed, int budget)
{
struct ep93xx_priv *ep = netdev_priv(dev);
- int rx_done;
- int processed;
- rx_done = 0;
- processed = 0;
- while (*budget > 0) {
+ while (processed < budget) {
int entry;
struct ep93xx_rstat *rstat;
u32 rstat0;
@@ -211,10 +210,8 @@ static int ep93xx_rx(struct net_device *dev, int *budget)
rstat0 = rstat->rstat0;
rstat1 = rstat->rstat1;
- if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) {
- rx_done = 1;
+ if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP))
break;
- }
rstat->rstat0 = 0;
rstat->rstat1 = 0;
@@ -275,8 +272,6 @@ static int ep93xx_rx(struct net_device *dev, int *budget)
err:
ep->rx_pointer = (entry + 1) & (RX_QUEUE_ENTRIES - 1);
processed++;
- dev->quota--;
- (*budget)--;
}
if (processed) {
@@ -284,7 +279,7 @@ err:
wrw(ep, REG_RXSTSENQ, processed);
}
- return !rx_done;
+ return processed;
}
static int ep93xx_have_more_rx(struct ep93xx_priv *ep)
@@ -293,36 +288,32 @@ static int ep93xx_have_more_rx(struct ep93xx_priv *ep)
return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP));
}
-static int ep93xx_poll(struct net_device *dev, int *budget)
+static int ep93xx_poll(struct napi_struct *napi, int budget)
{
- struct ep93xx_priv *ep = netdev_priv(dev);
-
- /*
- * @@@ Have to stop polling if device is downed while we
- * are polling.
- */
+ struct ep93xx_priv *ep = container_of(napi, struct ep93xx_priv, napi);
+ struct net_device *dev = ep->dev;
+ int rx = 0;
poll_some_more:
- if (ep93xx_rx(dev, budget))
- return 1;
-
- netif_rx_complete(dev);
-
- spin_lock_irq(&ep->rx_lock);
- wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX);
- if (ep93xx_have_more_rx(ep)) {
- wrl(ep, REG_INTEN, REG_INTEN_TX);
- wrl(ep, REG_INTSTSP, REG_INTSTS_RX);
+ rx = ep93xx_rx(dev, rx, budget);
+ if (rx < budget) {
+ int more = 0;
+
+ spin_lock_irq(&ep->rx_lock);
+ __netif_rx_complete(dev, napi);
+ wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX);
+ if (ep93xx_have_more_rx(ep)) {
+ wrl(ep, REG_INTEN, REG_INTEN_TX);
+ wrl(ep, REG_INTSTSP, REG_INTSTS_RX);
+ more = 1;
+ }
spin_unlock_irq(&ep->rx_lock);
- if (netif_rx_reschedule(dev, 0))
+ if (more && netif_rx_reschedule(dev, napi))
goto poll_some_more;
-
- return 0;
}
- spin_unlock_irq(&ep->rx_lock);
- return 0;
+ return rx;
}
static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -426,9 +417,9 @@ static irqreturn_t ep93xx_irq(int irq, void *dev_id)
if (status & REG_INTSTS_RX) {
spin_lock(&ep->rx_lock);
- if (likely(__netif_rx_schedule_prep(dev))) {
+ if (likely(netif_rx_schedule_prep(dev, &ep->napi))) {
wrl(ep, REG_INTEN, REG_INTEN_TX);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &ep->napi);
}
spin_unlock(&ep->rx_lock);
}
@@ -648,7 +639,10 @@ static int ep93xx_open(struct net_device *dev)
dev->dev_addr[4], dev->dev_addr[5]);
}
+ napi_enable(&ep->napi);
+
if (ep93xx_start_hw(dev)) {
+ napi_disable(&ep->napi);
ep93xx_free_buffers(ep);
return -EIO;
}
@@ -662,6 +656,7 @@ static int ep93xx_open(struct net_device *dev)
err = request_irq(ep->irq, ep93xx_irq, IRQF_SHARED, dev->name, dev);
if (err) {
+ napi_disable(&ep->napi);
ep93xx_stop_hw(dev);
ep93xx_free_buffers(ep);
return err;
@@ -678,6 +673,7 @@ static int ep93xx_close(struct net_device *dev)
{
struct ep93xx_priv *ep = netdev_priv(dev);
+ napi_disable(&ep->napi);
netif_stop_queue(dev);
wrl(ep, REG_GIINTMSK, 0);
@@ -788,14 +784,12 @@ struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data)
dev->get_stats = ep93xx_get_stats;
dev->ethtool_ops = &ep93xx_ethtool_ops;
- dev->poll = ep93xx_poll;
dev->hard_start_xmit = ep93xx_xmit;
dev->open = ep93xx_open;
dev->stop = ep93xx_close;
dev->do_ioctl = ep93xx_ioctl;
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
- dev->weight = 64;
return dev;
}
@@ -847,6 +841,8 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
goto err_out;
}
ep = netdev_priv(dev);
+ ep->dev = dev;
+ netif_napi_add(dev, &ep->napi, ep93xx_poll, 64);
platform_set_drvdata(pdev, dev);
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index 80f33b6d571..3bb9e293e2e 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -996,6 +996,7 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
{
struct net_device *dev;
int i, ret = 0;
+ DECLARE_MAC_BUF(mac);
ether1_banner();
@@ -1009,7 +1010,6 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
goto release;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &ec->dev);
dev->irq = ec->irq;
@@ -1044,12 +1044,9 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
if (ret)
goto free;
- printk(KERN_INFO "%s: ether1 in slot %d, ",
- dev->name, ec->slot_no);
+ printk(KERN_INFO "%s: ether1 in slot %d, %s\n",
+ dev->name, ec->slot_no, print_mac(mac, dev->dev_addr));
- for (i = 0; i < 6; i++)
- printk ("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
-
ecard_set_drvdata(ec, dev);
return 0;
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index 3805506a3ab..67e96ae8503 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -775,7 +775,8 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
{
const struct ether3_data *data = id->data;
struct net_device *dev;
- int i, bus_type, ret;
+ int bus_type, ret;
+ DECLARE_MAC_BUF(mac);
ether3_banner();
@@ -789,7 +790,6 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
goto release;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &ec->dev);
priv(dev)->base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
@@ -859,9 +859,8 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
if (ret)
goto free;
- printk("%s: %s in slot %d, ", dev->name, data->name, ec->slot_no);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+ printk("%s: %s in slot %d, %s\n",
+ dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr));
ecard_set_drvdata(ec, dev);
return 0;
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
index 0d37d9d1fd7..00081d2b9cd 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@ -648,6 +648,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
struct net_device *dev;
struct etherh_priv *eh;
int i, ret;
+ DECLARE_MAC_BUF(mac);
etherh_banner();
@@ -661,7 +662,6 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
goto release;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &ec->dev);
dev->open = etherh_open;
@@ -746,11 +746,8 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
if (ret)
goto free;
- printk(KERN_INFO "%s: %s in slot %d, ",
- dev->name, data->name, ec->slot_no);
-
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+ printk(KERN_INFO "%s: %s in slot %d, %s\n",
+ dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr));
ecard_set_drvdata(ec, dev);
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index bed8e0ebaf1..b032c1bf492 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -109,7 +109,6 @@ typedef unsigned char uchar;
/* Information that need to be kept for each board. */
struct net_local {
- struct net_device_stats stats;
spinlock_t lock;
unsigned char mc_filter[8];
uint jumpered:1; /* Set iff the board has jumper config. */
@@ -164,7 +163,6 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t net_interrupt(int irq, void *dev_id);
static void net_rx(struct net_device *dev);
static int net_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static void net_tx_timeout (struct net_device *dev);
@@ -225,8 +223,6 @@ struct net_device * __init at1700_probe(int unit)
dev->irq = irq;
}
- SET_MODULE_OWNER(dev);
-
if (io > 0x1ff) { /* Check a single specified location. */
err = at1700_probe1(dev, io);
} else if (io != 0) { /* Don't probe at all. */
@@ -269,6 +265,7 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr)
unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0;
int slot, ret = -ENODEV;
struct net_local *lp = netdev_priv(dev);
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, AT1700_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -392,16 +389,15 @@ found:
if (is_at1700) {
for(i = 0; i < 3; i++) {
unsigned short eeprom_val = read_eeprom(ioaddr, 4+i);
- printk("%04x", eeprom_val);
((unsigned short *)dev->dev_addr)[i] = ntohs(eeprom_val);
}
} else {
for(i = 0; i < 6; i++) {
unsigned char val = inb(ioaddr + SAPROM + i);
- printk("%02x", val);
dev->dev_addr[i] = val;
}
}
+ printk("%s", print_mac(mac, dev->dev_addr));
/* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals,
rather than 150 ohm shielded twisted pair compensation.
@@ -458,7 +454,6 @@ found:
dev->open = net_open;
dev->stop = net_close;
dev->hard_start_xmit = net_send_packet;
- dev->get_stats = net_get_stats;
dev->set_multicast_list = &set_rx_mode;
dev->tx_timeout = net_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -573,7 +568,7 @@ static void net_tx_timeout (struct net_device *dev)
dev->name, inw(ioaddr + TX_STATUS), inw(ioaddr + TX_INTR), inw(ioaddr + TX_MODE),
inw(ioaddr + CONFIG_0), inw(ioaddr + DATAPORT), inw(ioaddr + TX_START),
inw(ioaddr + MODE13 - 1), inw(ioaddr + RX_CTRL));
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* ToDo: We should try to restart the adaptor... */
outw(0xffff, ioaddr + MODE24);
outw (0xffff, ioaddr + TX_STATUS);
@@ -693,10 +688,10 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
printk("%s: 16 Collision occur during Txing.\n", dev->name);
/* Cancel sending a packet. */
outb(0x03, ioaddr + COL16CNTL);
- lp->stats.collisions++;
+ dev->stats.collisions++;
}
if (status & 0x82) {
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
/* The Tx queue has any packets and is not being
transferred a packet from the host, start
transmitting. */
@@ -721,7 +716,6 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
static void
net_rx(struct net_device *dev)
{
- struct net_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int boguscount = 5;
@@ -740,11 +734,11 @@ net_rx(struct net_device *dev)
#endif
if ((status & 0xF0) != 0x20) { /* There was an error. */
- lp->stats.rx_errors++;
- if (status & 0x08) lp->stats.rx_length_errors++;
- if (status & 0x04) lp->stats.rx_frame_errors++;
- if (status & 0x02) lp->stats.rx_crc_errors++;
- if (status & 0x01) lp->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
+ if (status & 0x08) dev->stats.rx_length_errors++;
+ if (status & 0x04) dev->stats.rx_frame_errors++;
+ if (status & 0x02) dev->stats.rx_crc_errors++;
+ if (status & 0x01) dev->stats.rx_over_errors++;
} else {
/* Malloc up new buffer. */
struct sk_buff *skb;
@@ -755,7 +749,7 @@ net_rx(struct net_device *dev)
/* Prime the FIFO and then flush the packet. */
inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
outb(0x05, ioaddr + RX_CTRL);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
break;
}
skb = dev_alloc_skb(pkt_len+3);
@@ -765,7 +759,7 @@ net_rx(struct net_device *dev)
/* Prime the FIFO and then flush the packet. */
inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
outb(0x05, ioaddr + RX_CTRL);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
skb_reserve(skb,2);
@@ -774,8 +768,8 @@ net_rx(struct net_device *dev)
skb->protocol=eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
if (--boguscount <= 0)
break;
@@ -824,17 +818,6 @@ static int net_close(struct net_device *dev)
return 0;
}
-/* Get the current statistics.
- This may be called with the card open or closed.
- There are no on-chip counters, so this function is trivial.
-*/
-static struct net_device_stats *
-net_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
/*
Set the multicast/promiscuous mode for this adaptor.
*/
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index dfa8b9ba4c8..b74dbeef805 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -224,7 +224,6 @@ struct lance_private {
int dirty_tx; /* Ring entries to be freed. */
/* copy function */
void *(*memcpy_f)( void *, const void *, size_t );
- struct net_device_stats stats;
/* This must be long for set_bit() */
long tx_full;
spinlock_t devlock;
@@ -263,7 +262,7 @@ struct lance_addr {
(highest byte stripped) */
};
-#define N_LANCE_ADDR (sizeof(lance_addr_list)/sizeof(*lance_addr_list))
+#define N_LANCE_ADDR ARRAY_SIZE(lance_addr_list)
/* Definitions for the Lance */
@@ -347,7 +346,6 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
static irqreturn_t lance_interrupt( int irq, void *dev_id );
static int lance_rx( struct net_device *dev );
static int lance_close( struct net_device *dev );
-static struct net_device_stats *lance_get_stats( struct net_device *dev );
static void set_multicast_list( struct net_device *dev );
static int lance_set_mac_address( struct net_device *dev, void *addr );
static void lance_tx_timeout (struct net_device *dev);
@@ -390,7 +388,6 @@ struct net_device * __init atarilance_probe(int unit)
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
for( i = 0; i < N_LANCE_ADDR; ++i ) {
if (lance_probe1( dev, &lance_addr_list[i] )) {
@@ -470,6 +467,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
int i;
static int did_version;
unsigned short save1, save2;
+ DECLARE_MAC_BUF(mac);
PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
(long)memaddr, (long)ioaddr ));
@@ -598,8 +596,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
i = IO->mem;
break;
}
- for( i = 0; i < 6; ++i )
- printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" );
+ printk("%s\n", print_mac(mac, dev->dev_addr));
if (lp->cardtype == OLD_RIEBL) {
printk( "%s: Warning: This is a default ethernet address!\n",
dev->name );
@@ -632,7 +629,6 @@ static unsigned long __init lance_probe1( struct net_device *dev,
dev->open = &lance_open;
dev->hard_start_xmit = &lance_start_xmit;
dev->stop = &lance_close;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->set_mac_address = &lance_set_mac_address;
@@ -640,13 +636,6 @@ static unsigned long __init lance_probe1( struct net_device *dev,
dev->tx_timeout = lance_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
-
-#if 0
- dev->start = 0;
-#endif
-
- memset( &lp->stats, 0, sizeof(lp->stats) );
-
return( 1 );
}
@@ -754,7 +743,7 @@ static void lance_tx_timeout (struct net_device *dev)
* little endian mode.
*/
REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
#ifndef final_version
{ int i;
DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n",
@@ -790,6 +779,8 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
int entry, len;
struct lance_tx_head *head;
unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
dev->name, DREG ));
@@ -812,17 +803,13 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
/* Fill in a Tx ring entry */
if (lance_debug >= 3) {
- u_char *p;
- int i;
- printk( "%s: TX pkt type 0x%04x from ", dev->name,
- ((u_short *)skb->data)[6]);
- for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" to ");
- for( p = (u_char *)skb->data, i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" data at 0x%08x len %d\n", (int)skb->data,
- (int)skb->len );
+ printk( "%s: TX pkt type 0x%04x from "
+ "%s to %s"
+ " data at 0x%08x len %d\n",
+ dev->name, ((u_short *)skb->data)[6],
+ print_mac(mac, &skb->data[6]),
+ print_mac(mac2, skb->data),
+ (int)skb->data, (int)skb->len );
}
/* We're not prepared for the int until the last flags are set/reset. And
@@ -842,7 +829,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
head->misc = 0;
lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
dev_kfree_skb( skb );
lp->cur_tx++;
while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) {
@@ -913,13 +900,13 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id )
if (status & TMD1_ERR) {
/* There was an major error, log it. */
int err_status = MEM->tx_head[entry].misc;
- lp->stats.tx_errors++;
- if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
- if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
- if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
+ if (err_status & TMD3_RTRY) dev->stats.tx_aborted_errors++;
+ if (err_status & TMD3_LCAR) dev->stats.tx_carrier_errors++;
+ if (err_status & TMD3_LCOL) dev->stats.tx_window_errors++;
if (err_status & TMD3_UFLO) {
/* Ackk! On FIFO errors the Tx unit is turned off! */
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
/* Remove this verbosity later! */
DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n",
dev->name, csr0 ));
@@ -928,8 +915,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id )
}
} else {
if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF))
- lp->stats.collisions++;
- lp->stats.tx_packets++;
+ dev->stats.collisions++;
+ dev->stats.tx_packets++;
}
/* XXX MSch: free skb?? */
@@ -956,8 +943,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id )
}
/* Log misc errors. */
- if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
- if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
+ if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */
+ if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */
if (csr0 & CSR0_MERR) {
DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
"status %04x.\n", dev->name, csr0 ));
@@ -998,11 +985,11 @@ static int lance_rx( struct net_device *dev )
buffers it's possible for a jabber packet to use two
buffers, with only the last correctly noting the error. */
if (status & RMD1_ENP) /* Only count a general error at the */
- lp->stats.rx_errors++; /* end of a packet.*/
- if (status & RMD1_FRAM) lp->stats.rx_frame_errors++;
- if (status & RMD1_OFLO) lp->stats.rx_over_errors++;
- if (status & RMD1_CRC) lp->stats.rx_crc_errors++;
- if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++; /* end of a packet.*/
+ if (status & RMD1_FRAM) dev->stats.rx_frame_errors++;
+ if (status & RMD1_OFLO) dev->stats.rx_over_errors++;
+ if (status & RMD1_CRC) dev->stats.rx_crc_errors++;
+ if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++;
head->flag &= (RMD1_ENP|RMD1_STP);
} else {
/* Malloc up new buffer, compatible with net-3. */
@@ -1011,7 +998,7 @@ static int lance_rx( struct net_device *dev )
if (pkt_len < 60) {
printk( "%s: Runt packet!\n", dev->name );
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
else {
skb = dev_alloc_skb( pkt_len+2 );
@@ -1024,7 +1011,7 @@ static int lance_rx( struct net_device *dev )
break;
if (i > RX_RING_SIZE - 2) {
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
head->flag |= RMD1_OWN_CHIP;
lp->cur_rx++;
}
@@ -1032,19 +1019,18 @@ static int lance_rx( struct net_device *dev )
}
if (lance_debug >= 3) {
- u_char *data = PKTBUF_ADDR(head), *p;
- printk( "%s: RX pkt type 0x%04x from ", dev->name,
- ((u_short *)data)[6]);
- for( p = &data[6], i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" to ");
- for( p = data, i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
+ u_char *data = PKTBUF_ADDR(head);
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+
+ printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s "
+ "data %02x %02x %02x %02x %02x %02x %02x %02x "
"len %d\n",
+ dev->name, ((u_short *)data)[6],
+ print_mac(mac, &data[6]), print_mac(mac2, data),
data[15], data[16], data[17], data[18],
data[19], data[20], data[21], data[22],
- pkt_len );
+ pkt_len);
}
skb_reserve( skb, 2 ); /* 16 byte align */
@@ -1053,8 +1039,8 @@ static int lance_rx( struct net_device *dev )
skb->protocol = eth_type_trans( skb, dev );
netif_rx( skb );
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
}
@@ -1091,14 +1077,6 @@ static int lance_close( struct net_device *dev )
}
-static struct net_device_stats *lance_get_stats( struct net_device *dev )
-
-{ struct lance_private *lp = (struct lance_private *)dev->priv;
-
- return &lp->stats;
-}
-
-
/* Set or clear the multicast filter for this adaptor.
num_addrs == -1 Promiscuous mode, receive all packets
num_addrs == 0 Normal mode, clear multicast list
diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c
index 1f616c5c147..68a83be843a 100644
--- a/drivers/net/atl1/atl1_ethtool.c
+++ b/drivers/net/atl1/atl1_ethtool.c
@@ -88,9 +88,14 @@ static void atl1_get_ethtool_stats(struct net_device *netdev,
}
-static int atl1_get_stats_count(struct net_device *netdev)
+static int atl1_get_sset_count(struct net_device *netdev, int sset)
{
- return ARRAY_SIZE(atl1_gstrings_stats);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(atl1_gstrings_stats);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static int atl1_get_settings(struct net_device *netdev,
@@ -489,15 +494,12 @@ const struct ethtool_ops atl1_ethtool_ops = {
.get_pauseparam = atl1_get_pauseparam,
.set_pauseparam = atl1_set_pauseparam,
.get_rx_csum = atl1_get_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_hw_csum,
.get_link = ethtool_op_get_link,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_strings = atl1_get_strings,
.nway_reset = atl1_nway_reset,
.get_ethtool_stats = atl1_get_ethtool_stats,
- .get_stats_count = atl1_get_stats_count,
- .get_tso = ethtool_op_get_tso,
+ .get_sset_count = atl1_get_sset_count,
.set_tso = ethtool_op_set_tso,
};
diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c
index ef886bdeac1..9d3bd22e3a8 100644
--- a/drivers/net/atl1/atl1_hw.c
+++ b/drivers/net/atl1/atl1_hw.c
@@ -603,7 +603,7 @@ static struct atl1_spi_flash_dev flash_table[] = {
static void atl1_init_flash_opcode(struct atl1_hw *hw)
{
- if (hw->flash_vendor >= sizeof(flash_table) / sizeof(flash_table[0]))
+ if (hw->flash_vendor >= ARRAY_SIZE(flash_table))
hw->flash_vendor = 0; /* ATMEL */
/* Init OP table */
diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c
index f23e13c8f9a..35b0a7dd4ef 100644
--- a/drivers/net/atl1/atl1_main.c
+++ b/drivers/net/atl1/atl1_main.c
@@ -76,7 +76,6 @@
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/mii.h>
-#include <linux/interrupt.h>
#include <net/checksum.h>
#include <asm/atomic.h>
@@ -1368,7 +1367,6 @@ rrd_ok:
if (count) {
u32 tpd_next_to_use;
u32 rfd_next_to_use;
- u32 rrd_next_to_clean;
spin_lock(&adapter->mb_lock);
@@ -1513,7 +1511,7 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
unsigned int f;
u16 tpd_next_to_use;
u16 proto_hdr_len;
- u16 i, m, len12;
+ u16 len12;
first_buf_len -= skb->data_len;
nr_frags = skb_shinfo(skb)->nr_frags;
@@ -1537,6 +1535,8 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
tpd_next_to_use = 0;
if (first_buf_len > proto_hdr_len) {
+ int i, m;
+
len12 = first_buf_len - proto_hdr_len;
m = (len12 + ATL1_MAX_TX_BUF_LEN - 1) /
ATL1_MAX_TX_BUF_LEN;
@@ -2210,8 +2210,14 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
return err;
/*
- * 64-bit DMA currently has data corruption problems, so let's just
- * use 32-bit DMA for now. This is a big hack that is probably wrong.
+ * The atl1 chip can DMA to 64-bit addresses, but it uses a single
+ * shared register for the high 32 bits, so only a single, aligned,
+ * 4 GB physical address range can be used at a time.
+ *
+ * Supporting 64-bit DMA on this hardware is more trouble than it's
+ * worth. It is far easier to limit to 32-bit DMA than update
+ * various kernel subsystems to support the mechanics required by a
+ * fixed-high-32-bit system.
*/
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
@@ -2235,7 +2241,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
err = -ENOMEM;
goto err_alloc_etherdev;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
pci_set_drvdata(pdev, netdev);
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 82d78ff8399..62f09e59d9c 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -171,7 +171,6 @@ static char mux_8012[] = { 0xff, 0xf7, 0xff, 0xfb, 0xf3, 0xfb, 0xff, 0xf7,};
struct net_local {
spinlock_t lock;
struct net_device *next_module;
- struct net_device_stats stats;
struct timer_list timer; /* Media selection timer. */
long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */
int saved_tx_size;
@@ -205,7 +204,6 @@ static irqreturn_t atp_interrupt(int irq, void *dev_id);
static void net_rx(struct net_device *dev);
static void read_block(long ioaddr, int length, unsigned char *buffer, int data_mode);
static int net_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
static void set_rx_mode_8002(struct net_device *dev);
static void set_rx_mode_8012(struct net_device *dev);
static void tx_timeout(struct net_device *dev);
@@ -250,6 +248,7 @@ static int __init atp_probe1(long ioaddr)
struct net_local *lp;
int saved_ctrl_reg, status, i;
int res;
+ DECLARE_MAC_BUF(mac);
outb(0xff, ioaddr + PAR_DATA);
/* Save the original value of the Control register, in case we guessed
@@ -299,7 +298,6 @@ static int __init atp_probe1(long ioaddr)
dev = alloc_etherdev(sizeof(struct net_local));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
/* Find the IRQ used by triggering an interrupt. */
write_reg_byte(ioaddr, CMR2, 0x01); /* No accept mode, IRQ out. */
@@ -325,10 +323,9 @@ static int __init atp_probe1(long ioaddr)
printk(KERN_INFO "%s", version);
#endif
- printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, SAPROM "
- "%02X:%02X:%02X:%02X:%02X:%02X.\n", dev->name, dev->base_addr,
- dev->irq, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, "
+ "SAPROM %s.\n",
+ dev->name, dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr));
/* Reset the ethernet hardware and activate the printer pass-through. */
write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX);
@@ -349,7 +346,6 @@ static int __init atp_probe1(long ioaddr)
dev->open = net_open;
dev->stop = net_close;
dev->hard_start_xmit = atp_send_packet;
- dev->get_stats = net_get_stats;
dev->set_multicast_list =
lp->chip_type == RTL8002 ? &set_rx_mode_8002 : &set_rx_mode_8012;
dev->tx_timeout = tx_timeout;
@@ -539,18 +535,17 @@ static void write_packet(long ioaddr, int length, unsigned char *packet, int pad
static void tx_timeout(struct net_device *dev)
{
- struct net_local *np = netdev_priv(dev);
long ioaddr = dev->base_addr;
printk(KERN_WARNING "%s: Transmit timed out, %s?\n", dev->name,
inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem"
: "IRQ conflict");
- np->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* Try to restart the adapter. */
hardware_init(dev);
dev->trans_start = jiffies;
netif_wake_queue(dev);
- np->stats.tx_errors++;
+ dev->stats.tx_errors++;
}
static int atp_send_packet(struct sk_buff *skb, struct net_device *dev)
@@ -630,7 +625,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance)
/* We acknowledged the normal Rx interrupt, so if the interrupt
is still outstanding we must have a Rx error. */
if (read_status & (CMR1_IRQ << 3)) { /* Overrun. */
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
/* Set to no-accept mode long enough to remove a packet. */
write_reg_high(ioaddr, CMR2, CMR2h_OFF);
net_rx(dev);
@@ -650,9 +645,9 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance)
and reinitialize the adapter. */
write_reg(ioaddr, ISR, ISR_TxErr + ISR_TxOK);
if (status & (ISR_TxErr<<3)) {
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (++lp->re_tx > 15) {
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
hardware_init(dev);
break;
}
@@ -661,7 +656,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance)
write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit);
} else {
/* Finish up the transmit. */
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
lp->pac_cnt_in_tx_buf--;
if ( lp->saved_tx_size) {
trigger_send(ioaddr, lp->saved_tx_size);
@@ -679,7 +674,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance)
"%ld jiffies status %02x CMR1 %02x.\n", dev->name,
num_tx_since_rx, jiffies - dev->last_rx, status,
(read_nibble(ioaddr, CMR1) >> 3) & 15);
- lp->stats.rx_missed_errors++;
+ dev->stats.rx_missed_errors++;
hardware_init(dev);
num_tx_since_rx = 0;
break;
@@ -736,13 +731,13 @@ static void atp_timed_checker(unsigned long data)
struct net_local *lp = netdev_priv(atp_timed_dev);
write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
if (i == 2)
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
else if (i == 3)
- lp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
else if (i == 4)
- lp->stats.collisions++;
+ dev->stats.collisions++;
else
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
#endif
}
@@ -766,14 +761,14 @@ static void net_rx(struct net_device *dev)
printk(KERN_DEBUG " rx_count %04x %04x %04x %04x..", rx_head.pad,
rx_head.rx_count, rx_head.rx_status, rx_head.cur_addr);
if ((rx_head.rx_status & 0x77) != 0x01) {
- lp->stats.rx_errors++;
- if (rx_head.rx_status & 0x0004) lp->stats.rx_frame_errors++;
- else if (rx_head.rx_status & 0x0002) lp->stats.rx_crc_errors++;
+ dev->stats.rx_errors++;
+ if (rx_head.rx_status & 0x0004) dev->stats.rx_frame_errors++;
+ else if (rx_head.rx_status & 0x0002) dev->stats.rx_crc_errors++;
if (net_debug > 3)
printk(KERN_DEBUG "%s: Unknown ATP Rx error %04x.\n",
dev->name, rx_head.rx_status);
if (rx_head.rx_status & 0x0020) {
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
write_reg_high(ioaddr, CMR1, CMR1h_TxENABLE);
write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);
} else if (rx_head.rx_status & 0x0050)
@@ -788,7 +783,7 @@ static void net_rx(struct net_device *dev)
if (skb == NULL) {
printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto done;
}
@@ -797,8 +792,8 @@ static void net_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
done:
write_reg(ioaddr, CMR1, CMR1_NextPkt);
@@ -850,15 +845,6 @@ net_close(struct net_device *dev)
return 0;
}
-/* Get the current statistics. This may be called with the card open or
- closed. */
-static struct net_device_stats *
-net_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
/*
* Set or clear the multicast filter for this adapter.
*/
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index e86b3691765..504b7ce2747 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -54,13 +54,16 @@
#include <linux/delay.h>
#include <linux/crc32.h>
#include <linux/phy.h>
+
+#include <asm/cpu.h>
#include <asm/mipsregs.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/processor.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/cpu.h>
+#include <au1000.h>
+#include <prom.h>
+
#include "au1000_eth.h"
#ifdef AU1000_ETH_DEBUG
@@ -90,18 +93,12 @@ static int au1000_rx(struct net_device *);
static irqreturn_t au1000_interrupt(int, void *);
static void au1000_tx_timeout(struct net_device *);
static void set_rx_mode(struct net_device *);
-static struct net_device_stats *au1000_get_stats(struct net_device *);
static int au1000_ioctl(struct net_device *, struct ifreq *, int);
static int mdio_read(struct net_device *, int, int);
static void mdio_write(struct net_device *, int, int, u16);
static void au1000_adjust_link(struct net_device *);
static void enable_mac(struct net_device *, int);
-// externs
-extern int get_ethernet_addr(char *ethernet_addr);
-extern void str2eaddr(unsigned char *ea, unsigned char *str);
-extern char * prom_getcmdline(void);
-
/*
* Theory of operation
*
@@ -545,7 +542,7 @@ static struct {
static int num_ifs;
/*
- * Setup the base address and interupt of the Au1xxx ethernet macs
+ * Setup the base address and interrupt of the Au1xxx ethernet macs
* based on cpu type and whether the interface is enabled in sys_pinfunc
* register. The last interface is enabled if SYS_PF_NI2 (bit 4) is 0.
*/
@@ -620,7 +617,6 @@ static struct net_device * au1000_probe(int port_num)
struct au1000_private *aup = NULL;
struct net_device *dev = NULL;
db_dest_t *pDB, *pDBfree;
- char *pmac, *argptr;
char ethaddr[6];
int irq, i, err;
u32 base, macen;
@@ -678,21 +674,12 @@ static struct net_device * au1000_probe(int port_num)
au_macs[port_num] = aup;
if (port_num == 0) {
- /* Check the environment variables first */
- if (get_ethernet_addr(ethaddr) == 0)
+ if (prom_get_ethernet_addr(ethaddr) == 0)
memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
else {
- /* Check command line */
- argptr = prom_getcmdline();
- if ((pmac = strstr(argptr, "ethaddr=")) == NULL)
- printk(KERN_INFO "%s: No MAC address found\n",
- dev->name);
+ printk(KERN_INFO "%s: No MAC address found\n",
+ dev->name);
/* Use the hard coded MAC addresses */
- else {
- str2eaddr(ethaddr, pmac + strlen("ethaddr="));
- memcpy(au1000_mac_addr, ethaddr,
- sizeof(au1000_mac_addr));
- }
}
setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
@@ -772,7 +759,6 @@ static struct net_device * au1000_probe(int port_num)
dev->open = au1000_open;
dev->hard_start_xmit = au1000_tx;
dev->stop = au1000_close;
- dev->get_stats = au1000_get_stats;
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &au1000_ioctl;
SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
@@ -1038,7 +1024,7 @@ static void __exit au1000_cleanup_module(void)
static void update_tx_stats(struct net_device *dev, u32 status)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
- struct net_device_stats *ps = &aup->stats;
+ struct net_device_stats *ps = &dev->stats;
if (status & TX_FRAME_ABORTED) {
if (!aup->phy_dev || (DUPLEX_FULL == aup->phy_dev->duplex)) {
@@ -1094,7 +1080,7 @@ static void au1000_tx_ack(struct net_device *dev)
static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
- struct net_device_stats *ps = &aup->stats;
+ struct net_device_stats *ps = &dev->stats;
volatile tx_dma_t *ptxd;
u32 buff_stat;
db_dest_t *pDB;
@@ -1148,7 +1134,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
static inline void update_rx_stats(struct net_device *dev, u32 status)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
- struct net_device_stats *ps = &aup->stats;
+ struct net_device_stats *ps = &dev->stats;
ps->rx_packets++;
if (status & RX_MCAST_FRAME)
@@ -1201,7 +1187,7 @@ static int au1000_rx(struct net_device *dev)
printk(KERN_ERR
"%s: Memory squeeze, dropping packet.\n",
dev->name);
- aup->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
continue;
}
skb_reserve(skb, 2); /* 16 byte IP header align */
@@ -1324,18 +1310,5 @@ static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return phy_mii_ioctl(aup->phy_dev, if_mii(rq), cmd);
}
-static struct net_device_stats *au1000_get_stats(struct net_device *dev)
-{
- struct au1000_private *aup = (struct au1000_private *) dev->priv;
-
- if (au1000_debug > 4)
- printk("%s: au1000_get_stats: dev=%p\n", dev->name, dev);
-
- if (netif_device_present(dev)) {
- return &aup->stats;
- }
- return 0;
-}
-
module_init(au1000_init_module);
module_exit(au1000_cleanup_module);
diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h
index 52fe00dd6d2..f3baeaa1285 100644
--- a/drivers/net/au1000_eth.h
+++ b/drivers/net/au1000_eth.h
@@ -115,6 +115,5 @@ struct au1000_private {
u32 vaddr; /* virtual address of rx/tx buffers */
dma_addr_t dma_addr; /* dma address of rx/tx buffers */
- struct net_device_stats stats;
spinlock_t lock; /* Serialise access to device */
};
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index 90e0734e603..7495a9ee8f4 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -24,6 +24,7 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/eeprom_93cx6.h>
#include <net/ax88796.h>
@@ -582,6 +583,37 @@ static const struct ethtool_ops ax_ethtool_ops = {
.get_link = ax_get_link,
};
+#ifdef CONFIG_AX88796_93CX6
+static void ax_eeprom_register_read(struct eeprom_93cx6 *eeprom)
+{
+ struct ei_device *ei_local = eeprom->data;
+ u8 reg = ei_inb(ei_local->mem + AX_MEMR);
+
+ eeprom->reg_data_in = reg & AX_MEMR_EEI;
+ eeprom->reg_data_out = reg & AX_MEMR_EEO; /* Input pin */
+ eeprom->reg_data_clock = reg & AX_MEMR_EECLK;
+ eeprom->reg_chip_select = reg & AX_MEMR_EECS;
+}
+
+static void ax_eeprom_register_write(struct eeprom_93cx6 *eeprom)
+{
+ struct ei_device *ei_local = eeprom->data;
+ u8 reg = ei_inb(ei_local->mem + AX_MEMR);
+
+ reg &= ~(AX_MEMR_EEI | AX_MEMR_EECLK | AX_MEMR_EECS);
+
+ if (eeprom->reg_data_in)
+ reg |= AX_MEMR_EEI;
+ if (eeprom->reg_data_clock)
+ reg |= AX_MEMR_EECLK;
+ if (eeprom->reg_chip_select)
+ reg |= AX_MEMR_EECS;
+
+ ei_outb(reg, ei_local->mem + AX_MEMR);
+ udelay(10);
+}
+#endif
+
/* setup code */
static void ax_initial_setup(struct net_device *dev, struct ei_device *ei_local)
@@ -640,6 +672,23 @@ static int ax_init_dev(struct net_device *dev, int first_init)
memcpy(dev->dev_addr, SA_prom, 6);
}
+#ifdef CONFIG_AX88796_93CX6
+ if (first_init && ax->plat->flags & AXFLG_HAS_93CX6) {
+ unsigned char mac_addr[6];
+ struct eeprom_93cx6 eeprom;
+
+ eeprom.data = ei_local;
+ eeprom.register_read = ax_eeprom_register_read;
+ eeprom.register_write = ax_eeprom_register_write;
+ eeprom.width = PCI_EEPROM_WIDTH_93C56;
+
+ eeprom_93cx6_multiread(&eeprom, 0,
+ (__le16 __force *)mac_addr,
+ sizeof(mac_addr) >> 1);
+
+ memcpy(dev->dev_addr, mac_addr, 6);
+ }
+#endif
if (ax->plat->wordlength == 2) {
/* We must set the 8390 for word mode. */
ei_outb(ax->plat->dcr_val, ei_local->mem + EN0_DCFG);
@@ -851,7 +900,7 @@ static int ax_probe(struct platform_device *pdev)
ax->map2 = ioremap(res->start, size);
if (ax->map2 == NULL) {
- dev_err(&pdev->dev, "cannot map reset register");
+ dev_err(&pdev->dev, "cannot map reset register\n");
ret = -ENXIO;
goto exit_mem2;
}
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 0795df23549..3d247f3f4a3 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1,8 +1,11 @@
-/* b44.c: Broadcom 4400 device driver.
+/* b44.c: Broadcom 44xx/47xx Fast Ethernet device driver.
*
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
- * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
+ * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi)
+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
+ * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org)
* Copyright (C) 2006 Broadcom Corporation.
+ * Copyright (C) 2007 Michael Buesch <mb@bu3sch.de>
*
* Distribute under GPL.
*/
@@ -21,17 +24,18 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
+#include <linux/ssb/ssb.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
+
#include "b44.h"
#define DRV_MODULE_NAME "b44"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.01"
-#define DRV_MODULE_RELDATE "Jun 16, 2006"
+#define DRV_MODULE_VERSION "2.0"
#define B44_DEF_MSG_ENABLE \
(NETIF_MSG_DRV | \
@@ -85,10 +89,10 @@
#define B44_ETHIPV4UDP_HLEN 42
static char version[] __devinitdata =
- DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION "\n";
-MODULE_AUTHOR("Florian Schirmer, Pekka Pietikainen, David S. Miller");
-MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver");
+MODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller");
+MODULE_DESCRIPTION("Broadcom 44xx/47xx 10/100 PCI ethernet driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
@@ -96,18 +100,28 @@ static int b44_debug = -1; /* -1 == use B44_DEF_MSG_ENABLE as value */
module_param(b44_debug, int, 0);
MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
-static struct pci_device_id b44_pci_tbl[] = {
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { } /* terminate list with empty entry */
-};
+#ifdef CONFIG_B44_PCI
+static const struct pci_device_id b44_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1) },
+ { 0 } /* terminate list with empty entry */
+};
MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
+static struct pci_driver b44_pci_driver = {
+ .name = DRV_MODULE_NAME,
+ .id_table = b44_pci_tbl,
+};
+#endif /* CONFIG_B44_PCI */
+
+static const struct ssb_device_id b44_ssb_tbl[] = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV),
+ SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, b44_ssb_tbl);
+
static void b44_halt(struct b44 *);
static void b44_init_rings(struct b44 *);
@@ -119,6 +133,7 @@ static void b44_init_hw(struct b44 *, int);
static int dma_desc_align_mask;
static int dma_desc_sync_size;
+static int instance;
static const char b44_gstrings[][ETH_GSTRING_LEN] = {
#define _B44(x...) # x,
@@ -126,35 +141,35 @@ B44_STAT_REG_DECLARE
#undef _B44
};
-static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev,
- dma_addr_t dma_base,
- unsigned long offset,
- enum dma_data_direction dir)
+static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev,
+ dma_addr_t dma_base,
+ unsigned long offset,
+ enum dma_data_direction dir)
{
- dma_sync_single_range_for_device(&pdev->dev, dma_base,
- offset & dma_desc_align_mask,
- dma_desc_sync_size, dir);
+ dma_sync_single_range_for_device(sdev->dev, dma_base,
+ offset & dma_desc_align_mask,
+ dma_desc_sync_size, dir);
}
-static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev,
- dma_addr_t dma_base,
- unsigned long offset,
- enum dma_data_direction dir)
+static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
+ dma_addr_t dma_base,
+ unsigned long offset,
+ enum dma_data_direction dir)
{
- dma_sync_single_range_for_cpu(&pdev->dev, dma_base,
- offset & dma_desc_align_mask,
- dma_desc_sync_size, dir);
+ dma_sync_single_range_for_cpu(sdev->dev, dma_base,
+ offset & dma_desc_align_mask,
+ dma_desc_sync_size, dir);
}
static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
{
- return readl(bp->regs + reg);
+ return ssb_read32(bp->sdev, reg);
}
static inline void bw32(const struct b44 *bp,
unsigned long reg, unsigned long val)
{
- writel(val, bp->regs + reg);
+ ssb_write32(bp->sdev, reg, val);
}
static int b44_wait_bit(struct b44 *bp, unsigned long reg,
@@ -182,117 +197,29 @@ static int b44_wait_bit(struct b44 *bp, unsigned long reg,
return 0;
}
-/* Sonics SiliconBackplane support routines. ROFL, you should see all the
- * buzz words used on this company's website :-)
- *
- * All of these routines must be invoked with bp->lock held and
- * interrupts disabled.
- */
-
-#define SB_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */
-#define BCM4400_PCI_CORE_ADDR 0x18002000 /* Address of PCI core on BCM4400 cards */
-
-static u32 ssb_get_core_rev(struct b44 *bp)
-{
- return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK);
-}
-
-static u32 ssb_pci_setup(struct b44 *bp, u32 cores)
-{
- u32 bar_orig, pci_rev, val;
-
- pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig);
- pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, BCM4400_PCI_CORE_ADDR);
- pci_rev = ssb_get_core_rev(bp);
-
- val = br32(bp, B44_SBINTVEC);
- val |= cores;
- bw32(bp, B44_SBINTVEC, val);
-
- val = br32(bp, SSB_PCI_TRANS_2);
- val |= SSB_PCI_PREF | SSB_PCI_BURST;
- bw32(bp, SSB_PCI_TRANS_2, val);
-
- pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig);
-
- return pci_rev;
-}
-
-static void ssb_core_disable(struct b44 *bp)
-{
- if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET)
- return;
-
- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK));
- b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0);
- b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1);
- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK |
- SBTMSLOW_REJECT | SBTMSLOW_RESET));
- br32(bp, B44_SBTMSLOW);
- udelay(1);
- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET));
- br32(bp, B44_SBTMSLOW);
- udelay(1);
-}
-
-static void ssb_core_reset(struct b44 *bp)
+static inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index)
{
u32 val;
- ssb_core_disable(bp);
- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC));
- br32(bp, B44_SBTMSLOW);
- udelay(1);
-
- /* Clear SERR if set, this is a hw bug workaround. */
- if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR)
- bw32(bp, B44_SBTMSHIGH, 0);
-
- val = br32(bp, B44_SBIMSTATE);
- if (val & (SBIMSTATE_IBE | SBIMSTATE_TO))
- bw32(bp, B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO));
-
- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC));
- br32(bp, B44_SBTMSLOW);
- udelay(1);
-
- bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK));
- br32(bp, B44_SBTMSLOW);
- udelay(1);
-}
+ bw32(bp, B44_CAM_CTRL, (CAM_CTRL_READ |
+ (index << CAM_CTRL_INDEX_SHIFT)));
-static int ssb_core_unit(struct b44 *bp)
-{
-#if 0
- u32 val = br32(bp, B44_SBADMATCH0);
- u32 base;
+ b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
- type = val & SBADMATCH0_TYPE_MASK;
- switch (type) {
- case 0:
- base = val & SBADMATCH0_BS0_MASK;
- break;
+ val = br32(bp, B44_CAM_DATA_LO);
- case 1:
- base = val & SBADMATCH0_BS1_MASK;
- break;
+ data[2] = (val >> 24) & 0xFF;
+ data[3] = (val >> 16) & 0xFF;
+ data[4] = (val >> 8) & 0xFF;
+ data[5] = (val >> 0) & 0xFF;
- case 2:
- default:
- base = val & SBADMATCH0_BS2_MASK;
- break;
- };
-#endif
- return 0;
-}
+ val = br32(bp, B44_CAM_DATA_HI);
-static int ssb_is_core_up(struct b44 *bp)
-{
- return ((br32(bp, B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK))
- == SBTMSLOW_CLOCK);
+ data[0] = (val >> 8) & 0xFF;
+ data[1] = (val >> 0) & 0xFF;
}
-static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
+static inline void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
{
u32 val;
@@ -328,14 +255,14 @@ static void b44_enable_ints(struct b44 *bp)
bw32(bp, B44_IMASK, bp->imask);
}
-static int b44_readphy(struct b44 *bp, int reg, u32 *val)
+static int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val)
{
int err;
bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
(MDIO_OP_READ << MDIO_DATA_OP_SHIFT) |
- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
+ (phy_addr << MDIO_DATA_PMD_SHIFT) |
(reg << MDIO_DATA_RA_SHIFT) |
(MDIO_TA_VALID << MDIO_DATA_TA_SHIFT)));
err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
@@ -344,29 +271,40 @@ static int b44_readphy(struct b44 *bp, int reg, u32 *val)
return err;
}
-static int b44_writephy(struct b44 *bp, int reg, u32 val)
+static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val)
{
bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
(MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) |
- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
+ (phy_addr << MDIO_DATA_PMD_SHIFT) |
(reg << MDIO_DATA_RA_SHIFT) |
(MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) |
(val & MDIO_DATA_DATA)));
return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
}
+static inline int b44_readphy(struct b44 *bp, int reg, u32 *val)
+{
+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+ return 0;
+
+ return __b44_readphy(bp, bp->phy_addr, reg, val);
+}
+
+static inline int b44_writephy(struct b44 *bp, int reg, u32 val)
+{
+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+ return 0;
+
+ return __b44_writephy(bp, bp->phy_addr, reg, val);
+}
+
/* miilib interface */
-/* FIXME FIXME: phy_id is ignored, bp->phy_addr use is unconditional
- * due to code existing before miilib use was added to this driver.
- * Someone should remove this artificial driver limitation in
- * b44_{read,write}phy. bp->phy_addr itself is fine (and needed).
- */
static int b44_mii_read(struct net_device *dev, int phy_id, int location)
{
u32 val;
struct b44 *bp = netdev_priv(dev);
- int rc = b44_readphy(bp, location, &val);
+ int rc = __b44_readphy(bp, phy_id, location, &val);
if (rc)
return 0xffffffff;
return val;
@@ -376,7 +314,7 @@ static void b44_mii_write(struct net_device *dev, int phy_id, int location,
int val)
{
struct b44 *bp = netdev_priv(dev);
- b44_writephy(bp, location, val);
+ __b44_writephy(bp, phy_id, location, val);
}
static int b44_phy_reset(struct b44 *bp)
@@ -384,6 +322,8 @@ static int b44_phy_reset(struct b44 *bp)
u32 val;
int err;
+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+ return 0;
err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
if (err)
return err;
@@ -442,11 +382,52 @@ static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote)
__b44_set_flow_ctrl(bp, pause_enab);
}
+#ifdef SSB_DRIVER_MIPS
+extern char *nvram_get(char *name);
+static void b44_wap54g10_workaround(struct b44 *bp)
+{
+ const char *str;
+ u32 val;
+ int err;
+
+ /*
+ * workaround for bad hardware design in Linksys WAP54G v1.0
+ * see https://dev.openwrt.org/ticket/146
+ * check and reset bit "isolate"
+ */
+ str = nvram_get("boardnum");
+ if (!str)
+ return;
+ if (simple_strtoul(str, NULL, 0) == 2) {
+ err = __b44_readphy(bp, 0, MII_BMCR, &val);
+ if (err)
+ goto error;
+ if (!(val & BMCR_ISOLATE))
+ return;
+ val &= ~BMCR_ISOLATE;
+ err = __b44_writephy(bp, 0, MII_BMCR, val);
+ if (err)
+ goto error;
+ }
+ return;
+error:
+ printk(KERN_WARNING PFX "PHY: cannot reset MII transceiver isolate bit.\n");
+}
+#else
+static inline void b44_wap54g10_workaround(struct b44 *bp)
+{
+}
+#endif
+
static int b44_setup_phy(struct b44 *bp)
{
u32 val;
int err;
+ b44_wap54g10_workaround(bp);
+
+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+ return 0;
if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
goto out;
if ((err = b44_writephy(bp, B44_MII_ALEDCTRL,
@@ -542,6 +523,19 @@ static void b44_check_phy(struct b44 *bp)
{
u32 bmsr, aux;
+ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
+ bp->flags |= B44_FLAG_100_BASE_T;
+ bp->flags |= B44_FLAG_FULL_DUPLEX;
+ if (!netif_carrier_ok(bp->dev)) {
+ u32 val = br32(bp, B44_TX_CTRL);
+ val |= TX_CTRL_DUPLEX;
+ bw32(bp, B44_TX_CTRL, val);
+ netif_carrier_on(bp->dev);
+ b44_link_report(bp);
+ }
+ return;
+ }
+
if (!b44_readphy(bp, MII_BMSR, &bmsr) &&
!b44_readphy(bp, B44_MII_AUXCTRL, &aux) &&
(bmsr != 0xffff)) {
@@ -617,10 +611,10 @@ static void b44_tx(struct b44 *bp)
BUG_ON(skb == NULL);
- pci_unmap_single(bp->pdev,
- pci_unmap_addr(rp, mapping),
+ dma_unmap_single(bp->sdev->dev,
+ rp->mapping,
skb->len,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
rp->skb = NULL;
dev_kfree_skb_irq(skb);
}
@@ -657,9 +651,9 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
if (skb == NULL)
return -ENOMEM;
- mapping = pci_map_single(bp->pdev, skb->data,
+ mapping = dma_map_single(bp->sdev->dev, skb->data,
RX_PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
/* Hardware bug work-around, the chip is unable to do PCI DMA
to/from anything above 1GB :-( */
@@ -667,18 +661,19 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
/* Sigh... */
if (!dma_mapping_error(mapping))
- pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
+ dma_unmap_single(bp->sdev->dev, mapping,
+ RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
if (skb == NULL)
return -ENOMEM;
- mapping = pci_map_single(bp->pdev, skb->data,
+ mapping = dma_map_single(bp->sdev->dev, skb->data,
RX_PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
if (dma_mapping_error(mapping) ||
mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
if (!dma_mapping_error(mapping))
- pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
+ dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
return -ENOMEM;
}
@@ -691,7 +686,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
rh->flags = 0;
map->skb = skb;
- pci_unmap_addr_set(map, mapping, mapping);
+ map->mapping = mapping;
if (src_map != NULL)
src_map->skb = NULL;
@@ -705,9 +700,9 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
dp->addr = cpu_to_le32((u32) mapping + RX_PKT_OFFSET + bp->dma_offset);
if (bp->flags & B44_FLAG_RX_RING_HACK)
- b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
- dest_idx * sizeof(dp),
- DMA_BIDIRECTIONAL);
+ b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma,
+ dest_idx * sizeof(dp),
+ DMA_BIDIRECTIONAL);
return RX_PKT_BUF_SZ;
}
@@ -730,13 +725,12 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
rh = (struct rx_header *) src_map->skb->data;
rh->len = 0;
rh->flags = 0;
- pci_unmap_addr_set(dest_map, mapping,
- pci_unmap_addr(src_map, mapping));
+ dest_map->mapping = src_map->mapping;
if (bp->flags & B44_FLAG_RX_RING_HACK)
- b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma,
- src_idx * sizeof(src_desc),
- DMA_BIDIRECTIONAL);
+ b44_sync_dma_desc_for_cpu(bp->sdev, bp->rx_ring_dma,
+ src_idx * sizeof(src_desc),
+ DMA_BIDIRECTIONAL);
ctrl = src_desc->ctrl;
if (dest_idx == (B44_RX_RING_SIZE - 1))
@@ -750,13 +744,13 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
src_map->skb = NULL;
if (bp->flags & B44_FLAG_RX_RING_HACK)
- b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
- dest_idx * sizeof(dest_desc),
- DMA_BIDIRECTIONAL);
+ b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma,
+ dest_idx * sizeof(dest_desc),
+ DMA_BIDIRECTIONAL);
- pci_dma_sync_single_for_device(bp->pdev, le32_to_cpu(src_desc->addr),
- RX_PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
+ dma_sync_single_for_device(bp->sdev->dev, le32_to_cpu(src_desc->addr),
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
}
static int b44_rx(struct b44 *bp, int budget)
@@ -772,13 +766,13 @@ static int b44_rx(struct b44 *bp, int budget)
while (cons != prod && budget > 0) {
struct ring_info *rp = &bp->rx_buffers[cons];
struct sk_buff *skb = rp->skb;
- dma_addr_t map = pci_unmap_addr(rp, mapping);
+ dma_addr_t map = rp->mapping;
struct rx_header *rh;
u16 len;
- pci_dma_sync_single_for_cpu(bp->pdev, map,
+ dma_sync_single_for_cpu(bp->sdev->dev, map,
RX_PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
rh = (struct rx_header *) skb->data;
len = le16_to_cpu(rh->len);
if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) ||
@@ -810,8 +804,8 @@ static int b44_rx(struct b44 *bp, int budget)
skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
if (skb_size < 0)
goto drop_it;
- pci_unmap_single(bp->pdev, map,
- skb_size, PCI_DMA_FROMDEVICE);
+ dma_unmap_single(bp->sdev->dev, map,
+ skb_size, DMA_FROM_DEVICE);
/* Leave out rx_header */
skb_put(skb, len + RX_PKT_OFFSET);
skb_pull(skb, RX_PKT_OFFSET);
@@ -848,10 +842,11 @@ static int b44_rx(struct b44 *bp, int budget)
return received;
}
-static int b44_poll(struct net_device *netdev, int *budget)
+static int b44_poll(struct napi_struct *napi, int budget)
{
- struct b44 *bp = netdev_priv(netdev);
- int done;
+ struct b44 *bp = container_of(napi, struct b44, napi);
+ struct net_device *netdev = bp->dev;
+ int work_done;
spin_lock_irq(&bp->lock);
@@ -862,22 +857,9 @@ static int b44_poll(struct net_device *netdev, int *budget)
}
spin_unlock_irq(&bp->lock);
- done = 1;
- if (bp->istat & ISTAT_RX) {
- int orig_budget = *budget;
- int work_done;
-
- if (orig_budget > netdev->quota)
- orig_budget = netdev->quota;
-
- work_done = b44_rx(bp, orig_budget);
-
- *budget -= work_done;
- netdev->quota -= work_done;
-
- if (work_done >= orig_budget)
- done = 0;
- }
+ work_done = 0;
+ if (bp->istat & ISTAT_RX)
+ work_done += b44_rx(bp, budget);
if (bp->istat & ISTAT_ERRORS) {
unsigned long flags;
@@ -888,15 +870,15 @@ static int b44_poll(struct net_device *netdev, int *budget)
b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY);
netif_wake_queue(bp->dev);
spin_unlock_irqrestore(&bp->lock, flags);
- done = 1;
+ work_done = 0;
}
- if (done) {
- netif_rx_complete(netdev);
+ if (work_done < budget) {
+ netif_rx_complete(netdev, napi);
b44_enable_ints(bp);
}
- return (done ? 0 : 1);
+ return work_done;
}
static irqreturn_t b44_interrupt(int irq, void *dev_id)
@@ -924,13 +906,13 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id)
goto irq_ack;
}
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &bp->napi)) {
/* NOTE: These writes are posted by the readback of
* the ISTAT register below.
*/
bp->istat = istat;
__b44_disable_ints(bp);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &bp->napi);
} else {
printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
dev->name);
@@ -982,24 +964,25 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto err_out;
}
- mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+ mapping = dma_map_single(bp->sdev->dev, skb->data, len, DMA_TO_DEVICE);
if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
struct sk_buff *bounce_skb;
/* Chip can't handle DMA to/from >1GB, use bounce buffer */
if (!dma_mapping_error(mapping))
- pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
+ dma_unmap_single(bp->sdev->dev, mapping, len,
+ DMA_TO_DEVICE);
bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA);
if (!bounce_skb)
goto err_out;
- mapping = pci_map_single(bp->pdev, bounce_skb->data,
- len, PCI_DMA_TODEVICE);
+ mapping = dma_map_single(bp->sdev->dev, bounce_skb->data,
+ len, DMA_TO_DEVICE);
if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
if (!dma_mapping_error(mapping))
- pci_unmap_single(bp->pdev, mapping,
- len, PCI_DMA_TODEVICE);
+ dma_unmap_single(bp->sdev->dev, mapping,
+ len, DMA_TO_DEVICE);
dev_kfree_skb_any(bounce_skb);
goto err_out;
}
@@ -1011,7 +994,7 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
entry = bp->tx_prod;
bp->tx_buffers[entry].skb = skb;
- pci_unmap_addr_set(&bp->tx_buffers[entry], mapping, mapping);
+ bp->tx_buffers[entry].mapping = mapping;
ctrl = (len & DESC_CTRL_LEN);
ctrl |= DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF;
@@ -1022,9 +1005,9 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset);
if (bp->flags & B44_FLAG_TX_RING_HACK)
- b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma,
- entry * sizeof(bp->tx_ring[0]),
- DMA_TO_DEVICE);
+ b44_sync_dma_desc_for_device(bp->sdev, bp->tx_ring_dma,
+ entry * sizeof(bp->tx_ring[0]),
+ DMA_TO_DEVICE);
entry = NEXT_TX(entry);
@@ -1097,10 +1080,8 @@ static void b44_free_rings(struct b44 *bp)
if (rp->skb == NULL)
continue;
- pci_unmap_single(bp->pdev,
- pci_unmap_addr(rp, mapping),
- RX_PKT_BUF_SZ,
- PCI_DMA_FROMDEVICE);
+ dma_unmap_single(bp->sdev->dev, rp->mapping, RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
dev_kfree_skb_any(rp->skb);
rp->skb = NULL;
}
@@ -1111,10 +1092,8 @@ static void b44_free_rings(struct b44 *bp)
if (rp->skb == NULL)
continue;
- pci_unmap_single(bp->pdev,
- pci_unmap_addr(rp, mapping),
- rp->skb->len,
- PCI_DMA_TODEVICE);
+ dma_unmap_single(bp->sdev->dev, rp->mapping, rp->skb->len,
+ DMA_TO_DEVICE);
dev_kfree_skb_any(rp->skb);
rp->skb = NULL;
}
@@ -1136,14 +1115,14 @@ static void b44_init_rings(struct b44 *bp)
memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
if (bp->flags & B44_FLAG_RX_RING_HACK)
- dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma,
- DMA_TABLE_BYTES,
- PCI_DMA_BIDIRECTIONAL);
+ dma_sync_single_for_device(bp->sdev->dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
if (bp->flags & B44_FLAG_TX_RING_HACK)
- dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma,
- DMA_TABLE_BYTES,
- PCI_DMA_TODEVICE);
+ dma_sync_single_for_device(bp->sdev->dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
for (i = 0; i < bp->rx_pending; i++) {
if (b44_alloc_rx_skb(bp, -1, i) < 0)
@@ -1163,24 +1142,24 @@ static void b44_free_consistent(struct b44 *bp)
bp->tx_buffers = NULL;
if (bp->rx_ring) {
if (bp->flags & B44_FLAG_RX_RING_HACK) {
- dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma,
- DMA_TABLE_BYTES,
- DMA_BIDIRECTIONAL);
+ dma_unmap_single(bp->sdev->dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
kfree(bp->rx_ring);
} else
- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+ dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES,
bp->rx_ring, bp->rx_ring_dma);
bp->rx_ring = NULL;
bp->flags &= ~B44_FLAG_RX_RING_HACK;
}
if (bp->tx_ring) {
if (bp->flags & B44_FLAG_TX_RING_HACK) {
- dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma,
- DMA_TABLE_BYTES,
- DMA_TO_DEVICE);
+ dma_unmap_single(bp->sdev->dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
kfree(bp->tx_ring);
} else
- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+ dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES,
bp->tx_ring, bp->tx_ring_dma);
bp->tx_ring = NULL;
bp->flags &= ~B44_FLAG_TX_RING_HACK;
@@ -1191,22 +1170,22 @@ static void b44_free_consistent(struct b44 *bp)
* Must not be invoked with interrupt sources disabled and
* the hardware shutdown down. Can sleep.
*/
-static int b44_alloc_consistent(struct b44 *bp)
+static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
{
int size;
size = B44_RX_RING_SIZE * sizeof(struct ring_info);
- bp->rx_buffers = kzalloc(size, GFP_KERNEL);
+ bp->rx_buffers = kzalloc(size, gfp);
if (!bp->rx_buffers)
goto out_err;
size = B44_TX_RING_SIZE * sizeof(struct ring_info);
- bp->tx_buffers = kzalloc(size, GFP_KERNEL);
+ bp->tx_buffers = kzalloc(size, gfp);
if (!bp->tx_buffers)
goto out_err;
size = DMA_TABLE_BYTES;
- bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
+ bp->rx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->rx_ring_dma, gfp);
if (!bp->rx_ring) {
/* Allocation may have failed due to pci_alloc_consistent
insisting on use of GFP_DMA, which is more restrictive
@@ -1214,13 +1193,13 @@ static int b44_alloc_consistent(struct b44 *bp)
struct dma_desc *rx_ring;
dma_addr_t rx_ring_dma;
- rx_ring = kzalloc(size, GFP_KERNEL);
+ rx_ring = kzalloc(size, gfp);
if (!rx_ring)
goto out_err;
- rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring,
- DMA_TABLE_BYTES,
- DMA_BIDIRECTIONAL);
+ rx_ring_dma = dma_map_single(bp->sdev->dev, rx_ring,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
if (dma_mapping_error(rx_ring_dma) ||
rx_ring_dma + size > DMA_30BIT_MASK) {
@@ -1233,21 +1212,21 @@ static int b44_alloc_consistent(struct b44 *bp)
bp->flags |= B44_FLAG_RX_RING_HACK;
}
- bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma);
+ bp->tx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->tx_ring_dma, gfp);
if (!bp->tx_ring) {
- /* Allocation may have failed due to pci_alloc_consistent
+ /* Allocation may have failed due to dma_alloc_coherent
insisting on use of GFP_DMA, which is more restrictive
than necessary... */
struct dma_desc *tx_ring;
dma_addr_t tx_ring_dma;
- tx_ring = kzalloc(size, GFP_KERNEL);
+ tx_ring = kzalloc(size, gfp);
if (!tx_ring)
goto out_err;
- tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring,
- DMA_TABLE_BYTES,
- DMA_TO_DEVICE);
+ tx_ring_dma = dma_map_single(bp->sdev->dev, tx_ring,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
if (dma_mapping_error(tx_ring_dma) ||
tx_ring_dma + size > DMA_30BIT_MASK) {
@@ -1282,7 +1261,9 @@ static void b44_clear_stats(struct b44 *bp)
/* bp->lock is held. */
static void b44_chip_reset(struct b44 *bp)
{
- if (ssb_is_core_up(bp)) {
+ struct ssb_device *sdev = bp->sdev;
+
+ if (ssb_device_is_enabled(bp->sdev)) {
bw32(bp, B44_RCV_LAZY, 0);
bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE);
b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1);
@@ -1294,19 +1275,25 @@ static void b44_chip_reset(struct b44 *bp)
}
bw32(bp, B44_DMARX_CTRL, 0);
bp->rx_prod = bp->rx_cons = 0;
- } else {
- ssb_pci_setup(bp, (bp->core_unit == 0 ?
- SBINTVEC_ENET0 :
- SBINTVEC_ENET1));
- }
-
- ssb_core_reset(bp);
+ } else
+ ssb_pcicore_dev_irqvecs_enable(&sdev->bus->pcicore, sdev);
+ ssb_device_enable(bp->sdev, 0);
b44_clear_stats(bp);
- /* Make PHY accessible. */
- bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
- (0x0d & MDIO_CTRL_MAXF_MASK)));
+ switch (sdev->bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
+ (((ssb_clockspeed(sdev->bus) + (B44_MDC_RATIO / 2)) / B44_MDC_RATIO)
+ & MDIO_CTRL_MAXF_MASK)));
+ break;
+ case SSB_BUSTYPE_PCI:
+ case SSB_BUSTYPE_PCMCIA:
+ bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
+ (0x0d & MDIO_CTRL_MAXF_MASK)));
+ break;
+ }
+
br32(bp, B44_MDIO_CTRL);
if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
@@ -1349,6 +1336,7 @@ static int b44_set_mac_addr(struct net_device *dev, void *p)
{
struct b44 *bp = netdev_priv(dev);
struct sockaddr *addr = p;
+ u32 val;
if (netif_running(dev))
return -EBUSY;
@@ -1359,7 +1347,11 @@ static int b44_set_mac_addr(struct net_device *dev, void *p)
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
spin_lock_irq(&bp->lock);
- __b44_set_mac_addr(bp);
+
+ val = br32(bp, B44_RXCONFIG);
+ if (!(val & RXCONFIG_CAM_ABSENT))
+ __b44_set_mac_addr(bp);
+
spin_unlock_irq(&bp->lock);
return 0;
@@ -1416,10 +1408,12 @@ static int b44_open(struct net_device *dev)
struct b44 *bp = netdev_priv(dev);
int err;
- err = b44_alloc_consistent(bp);
+ err = b44_alloc_consistent(bp, GFP_KERNEL);
if (err)
goto out;
+ napi_enable(&bp->napi);
+
b44_init_rings(bp);
b44_init_hw(bp, B44_FULL_RESET);
@@ -1427,6 +1421,7 @@ static int b44_open(struct net_device *dev)
err = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
if (unlikely(err < 0)) {
+ napi_disable(&bp->napi);
b44_chip_reset(bp);
b44_free_rings(bp);
b44_free_consistent(bp);
@@ -1445,18 +1440,6 @@ out:
return err;
}
-#if 0
-/*static*/ void b44_dump_state(struct b44 *bp)
-{
- u32 val32, val32_2, val32_3, val32_4, val32_5;
- u16 val16;
-
- pci_read_config_word(bp->pdev, PCI_STATUS, &val16);
- printk("DEBUG: PCI status [%04x] \n", val16);
-
-}
-#endif
-
#ifdef CONFIG_NET_POLL_CONTROLLER
/*
* Polling receive - used by netconsole and other diagnostic tools
@@ -1567,10 +1550,24 @@ static void b44_setup_pseudo_magicp(struct b44 *bp)
}
+#ifdef CONFIG_B44_PCI
+static void b44_setup_wol_pci(struct b44 *bp)
+{
+ u16 val;
+
+ if (bp->sdev->bus->bustype != SSB_BUSTYPE_SSB) {
+ bw32(bp, SSB_TMSLOW, br32(bp, SSB_TMSLOW) | SSB_TMSLOW_PE);
+ pci_read_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, &val);
+ pci_write_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, val | SSB_PE);
+ }
+}
+#else
+static inline void b44_setup_wol_pci(struct b44 *bp) { }
+#endif /* CONFIG_B44_PCI */
+
static void b44_setup_wol(struct b44 *bp)
{
u32 val;
- u16 pmval;
bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI);
@@ -1594,13 +1591,7 @@ static void b44_setup_wol(struct b44 *bp)
} else {
b44_setup_pseudo_magicp(bp);
}
-
- val = br32(bp, B44_SBTMSLOW);
- bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE);
-
- pci_read_config_word(bp->pdev, SSB_PMCSR, &pmval);
- pci_write_config_word(bp->pdev, SSB_PMCSR, pmval | SSB_PE);
-
+ b44_setup_wol_pci(bp);
}
static int b44_close(struct net_device *dev)
@@ -1609,15 +1600,12 @@ static int b44_close(struct net_device *dev)
netif_stop_queue(dev);
- netif_poll_disable(dev);
+ napi_disable(&bp->napi);
del_timer_sync(&bp->timer);
spin_lock_irq(&bp->lock);
-#if 0
- b44_dump_state(bp);
-#endif
b44_halt(bp);
b44_free_rings(bp);
netif_carrier_off(dev);
@@ -1626,8 +1614,6 @@ static int b44_close(struct net_device *dev)
free_irq(dev->irq, dev);
- netif_poll_enable(dev);
-
if (bp->flags & B44_FLAG_WOL_ENABLE) {
b44_init_hw(bp, B44_PARTIAL_RESET);
b44_setup_wol(bp);
@@ -1700,7 +1686,7 @@ static void __b44_set_rx_mode(struct net_device *dev)
val = br32(bp, B44_RXCONFIG);
val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
- if (dev->flags & IFF_PROMISC) {
+ if ((dev->flags & IFF_PROMISC) || (val & RXCONFIG_CAM_ABSENT)) {
val |= RXCONFIG_PROMISC;
bw32(bp, B44_RXCONFIG, val);
} else {
@@ -1748,11 +1734,19 @@ static void b44_set_msglevel(struct net_device *dev, u32 value)
static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
{
struct b44 *bp = netdev_priv(dev);
- struct pci_dev *pci_dev = bp->pdev;
+ struct ssb_bus *bus = bp->sdev->bus;
- strcpy (info->driver, DRV_MODULE_NAME);
- strcpy (info->version, DRV_MODULE_VERSION);
- strcpy (info->bus_info, pci_name(pci_dev));
+ strncpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+ strncpy(info->version, DRV_MODULE_VERSION, sizeof(info->driver));
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_PCI:
+ strncpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info));
+ break;
+ case SSB_BUSTYPE_PCMCIA:
+ case SSB_BUSTYPE_SSB:
+ strncpy(info->bus_info, "SSB", sizeof(info->bus_info));
+ break;
+ }
}
static int b44_nway_reset(struct net_device *dev)
@@ -1968,9 +1962,14 @@ static void b44_get_strings(struct net_device *dev, u32 stringset, u8 *data)
}
}
-static int b44_get_stats_count(struct net_device *dev)
+static int b44_get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(b44_gstrings);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(b44_gstrings);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void b44_get_ethtool_stats(struct net_device *dev,
@@ -2031,7 +2030,7 @@ static const struct ethtool_ops b44_ethtool_ops = {
.get_msglevel = b44_get_msglevel,
.set_msglevel = b44_set_msglevel,
.get_strings = b44_get_strings,
- .get_stats_count = b44_get_stats_count,
+ .get_sset_count = b44_get_sset_count,
.get_ethtool_stats = b44_get_ethtool_stats,
};
@@ -2051,33 +2050,23 @@ out:
return err;
}
-/* Read 128-bytes of EEPROM. */
-static int b44_read_eeprom(struct b44 *bp, u8 *data)
-{
- long i;
- __le16 *ptr = (__le16 *) data;
-
- for (i = 0; i < 128; i += 2)
- ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
-
- return 0;
-}
-
static int __devinit b44_get_invariants(struct b44 *bp)
{
- u8 eeprom[128];
- int err;
+ struct ssb_device *sdev = bp->sdev;
+ int err = 0;
+ u8 *addr;
- err = b44_read_eeprom(bp, &eeprom[0]);
- if (err)
- goto out;
+ bp->dma_offset = ssb_dma_translation(sdev);
- bp->dev->dev_addr[0] = eeprom[79];
- bp->dev->dev_addr[1] = eeprom[78];
- bp->dev->dev_addr[2] = eeprom[81];
- bp->dev->dev_addr[3] = eeprom[80];
- bp->dev->dev_addr[4] = eeprom[83];
- bp->dev->dev_addr[5] = eeprom[82];
+ if (sdev->bus->bustype == SSB_BUSTYPE_SSB &&
+ instance > 1) {
+ addr = sdev->bus->sprom.r1.et1mac;
+ bp->phy_addr = sdev->bus->sprom.r1.et1phyaddr;
+ } else {
+ addr = sdev->bus->sprom.r1.et0mac;
+ bp->phy_addr = sdev->bus->sprom.r1.et0phyaddr;
+ }
+ memcpy(bp->dev->dev_addr, addr, 6);
if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){
printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n");
@@ -2086,103 +2075,53 @@ static int __devinit b44_get_invariants(struct b44 *bp)
memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
- bp->phy_addr = eeprom[90] & 0x1f;
-
bp->imask = IMASK_DEF;
- bp->core_unit = ssb_core_unit(bp);
- bp->dma_offset = SB_PCI_DMA;
-
/* XXX - really required?
bp->flags |= B44_FLAG_BUGGY_TXPTR;
- */
+ */
- if (ssb_get_core_rev(bp) >= 7)
- bp->flags |= B44_FLAG_B0_ANDLATER;
+ if (bp->sdev->id.revision >= 7)
+ bp->flags |= B44_FLAG_B0_ANDLATER;
-out:
return err;
}
-static int __devinit b44_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit b44_init_one(struct ssb_device *sdev,
+ const struct ssb_device_id *ent)
{
static int b44_version_printed = 0;
- unsigned long b44reg_base, b44reg_len;
struct net_device *dev;
struct b44 *bp;
- int err, i;
+ int err;
+ DECLARE_MAC_BUF(mac);
+
+ instance++;
if (b44_version_printed++ == 0)
printk(KERN_INFO "%s", version);
- err = pci_enable_device(pdev);
- if (err) {
- dev_err(&pdev->dev, "Cannot enable PCI device, "
- "aborting.\n");
- return err;
- }
-
- if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- dev_err(&pdev->dev,
- "Cannot find proper PCI device "
- "base address, aborting.\n");
- err = -ENODEV;
- goto err_out_disable_pdev;
- }
-
- err = pci_request_regions(pdev, DRV_MODULE_NAME);
- if (err) {
- dev_err(&pdev->dev,
- "Cannot obtain PCI resources, aborting.\n");
- goto err_out_disable_pdev;
- }
-
- pci_set_master(pdev);
-
- err = pci_set_dma_mask(pdev, (u64) DMA_30BIT_MASK);
- if (err) {
- dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
- goto err_out_free_res;
- }
-
- err = pci_set_consistent_dma_mask(pdev, (u64) DMA_30BIT_MASK);
- if (err) {
- dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
- goto err_out_free_res;
- }
-
- b44reg_base = pci_resource_start(pdev, 0);
- b44reg_len = pci_resource_len(pdev, 0);
dev = alloc_etherdev(sizeof(*bp));
if (!dev) {
- dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
+ dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n");
err = -ENOMEM;
- goto err_out_free_res;
+ goto out;
}
- SET_MODULE_OWNER(dev);
- SET_NETDEV_DEV(dev,&pdev->dev);
+ SET_NETDEV_DEV(dev, sdev->dev);
/* No interesting netdevice features in this card... */
dev->features |= 0;
bp = netdev_priv(dev);
- bp->pdev = pdev;
+ bp->sdev = sdev;
bp->dev = dev;
bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE);
spin_lock_init(&bp->lock);
- bp->regs = ioremap(b44reg_base, b44reg_len);
- if (bp->regs == 0UL) {
- dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
- err = -ENOMEM;
- goto err_out_free_dev;
- }
-
bp->rx_pending = B44_DEF_RX_RING_PENDING;
bp->tx_pending = B44_DEF_TX_RING_PENDING;
@@ -2194,23 +2133,34 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
dev->set_mac_address = b44_set_mac_addr;
dev->do_ioctl = b44_ioctl;
dev->tx_timeout = b44_tx_timeout;
- dev->poll = b44_poll;
- dev->weight = 64;
+ netif_napi_add(dev, &bp->napi, b44_poll, 64);
dev->watchdog_timeo = B44_TX_TIMEOUT;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = b44_poll_controller;
#endif
dev->change_mtu = b44_change_mtu;
- dev->irq = pdev->irq;
+ dev->irq = sdev->irq;
SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);
netif_carrier_off(dev);
+ err = ssb_bus_powerup(sdev->bus, 0);
+ if (err) {
+ dev_err(sdev->dev,
+ "Failed to powerup the bus\n");
+ goto err_out_free_dev;
+ }
+ err = ssb_dma_set_mask(sdev, DMA_30BIT_MASK);
+ if (err) {
+ dev_err(sdev->dev,
+ "Required 30BIT DMA mask unsupported by the system.\n");
+ goto err_out_powerdown;
+ }
err = b44_get_invariants(bp);
if (err) {
- dev_err(&pdev->dev,
+ dev_err(sdev->dev,
"Problem fetching invariants of chip, aborting.\n");
- goto err_out_iounmap;
+ goto err_out_powerdown;
}
bp->mii_if.dev = dev;
@@ -2229,61 +2179,49 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = register_netdev(dev);
if (err) {
- dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
- goto err_out_iounmap;
+ dev_err(sdev->dev, "Cannot register net device, aborting.\n");
+ goto err_out_powerdown;
}
- pci_set_drvdata(pdev, dev);
-
- pci_save_state(bp->pdev);
+ ssb_set_drvdata(sdev, dev);
/* Chip reset provides power to the b44 MAC & PCI cores, which
* is necessary for MAC register access.
*/
b44_chip_reset(bp);
- printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- i == 5 ? '\n' : ':');
+ printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
return 0;
-err_out_iounmap:
- iounmap(bp->regs);
+err_out_powerdown:
+ ssb_bus_may_powerdown(sdev->bus);
err_out_free_dev:
free_netdev(dev);
-err_out_free_res:
- pci_release_regions(pdev);
-
-err_out_disable_pdev:
- pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
+out:
return err;
}
-static void __devexit b44_remove_one(struct pci_dev *pdev)
+static void __devexit b44_remove_one(struct ssb_device *sdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct b44 *bp = netdev_priv(dev);
+ struct net_device *dev = ssb_get_drvdata(sdev);
unregister_netdev(dev);
- iounmap(bp->regs);
+ ssb_bus_may_powerdown(sdev->bus);
free_netdev(dev);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
+ ssb_set_drvdata(sdev, NULL);
}
-static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
+static int b44_suspend(struct ssb_device *sdev, pm_message_t state)
{
- struct net_device *dev = pci_get_drvdata(pdev);
+ struct net_device *dev = ssb_get_drvdata(sdev);
struct b44 *bp = netdev_priv(dev);
- if (!netif_running(dev))
- return 0;
+ if (!netif_running(dev))
+ return 0;
del_timer_sync(&bp->timer);
@@ -2301,33 +2239,29 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
b44_init_hw(bp, B44_PARTIAL_RESET);
b44_setup_wol(bp);
}
- pci_disable_device(pdev);
+
return 0;
}
-static int b44_resume(struct pci_dev *pdev)
+static int b44_resume(struct ssb_device *sdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
+ struct net_device *dev = ssb_get_drvdata(sdev);
struct b44 *bp = netdev_priv(dev);
int rc = 0;
- pci_restore_state(pdev);
- rc = pci_enable_device(pdev);
+ rc = ssb_bus_powerup(sdev->bus, 0);
if (rc) {
- printk(KERN_ERR PFX "%s: pci_enable_device failed\n",
- dev->name);
+ dev_err(sdev->dev,
+ "Failed to powerup the bus\n");
return rc;
}
- pci_set_master(pdev);
-
if (!netif_running(dev))
return 0;
rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
if (rc) {
printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name);
- pci_disable_device(pdev);
return rc;
}
@@ -2346,29 +2280,53 @@ static int b44_resume(struct pci_dev *pdev)
return 0;
}
-static struct pci_driver b44_driver = {
+static struct ssb_driver b44_ssb_driver = {
.name = DRV_MODULE_NAME,
- .id_table = b44_pci_tbl,
+ .id_table = b44_ssb_tbl,
.probe = b44_init_one,
.remove = __devexit_p(b44_remove_one),
- .suspend = b44_suspend,
- .resume = b44_resume,
+ .suspend = b44_suspend,
+ .resume = b44_resume,
};
+static inline int b44_pci_init(void)
+{
+ int err = 0;
+#ifdef CONFIG_B44_PCI
+ err = ssb_pcihost_register(&b44_pci_driver);
+#endif
+ return err;
+}
+
+static inline void b44_pci_exit(void)
+{
+#ifdef CONFIG_B44_PCI
+ ssb_pcihost_unregister(&b44_pci_driver);
+#endif
+}
+
static int __init b44_init(void)
{
unsigned int dma_desc_align_size = dma_get_cache_alignment();
+ int err;
/* Setup paramaters for syncing RX/TX DMA descriptors */
dma_desc_align_mask = ~(dma_desc_align_size - 1);
dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
- return pci_register_driver(&b44_driver);
+ err = b44_pci_init();
+ if (err)
+ return err;
+ err = ssb_driver_register(&b44_ssb_driver);
+ if (err)
+ b44_pci_exit();
+ return err;
}
static void __exit b44_cleanup(void)
{
- pci_unregister_driver(&b44_driver);
+ ssb_driver_unregister(&b44_ssb_driver);
+ b44_pci_exit();
}
module_init(b44_init);
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index e537e63f292..7db0c84a795 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -129,6 +129,7 @@
#define RXCONFIG_FLOW 0x00000020 /* Flow Control Enable */
#define RXCONFIG_FLOW_ACCEPT 0x00000040 /* Accept Unicast Flow Control Frame */
#define RXCONFIG_RFILT 0x00000080 /* Reject Filter */
+#define RXCONFIG_CAM_ABSENT 0x00000100 /* CAM Absent */
#define B44_RXMAXLEN 0x0404UL /* EMAC RX Max Packet Length */
#define B44_TXMAXLEN 0x0408UL /* EMAC TX Max Packet Length */
#define B44_MDIO_CTRL 0x0410UL /* EMAC MDIO Control */
@@ -227,76 +228,6 @@
#define B44_RX_PAUSE 0x05D4UL /* MIB RX Pause Packets */
#define B44_RX_NPAUSE 0x05D8UL /* MIB RX Non-Pause Packets */
-/* Silicon backplane register definitions */
-#define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */
-#define SBIMSTATE_PC 0x0000000f /* Pipe Count */
-#define SBIMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */
-#define SBIMSTATE_AP_BOTH 0x00000000 /* Use both timeslices and token */
-#define SBIMSTATE_AP_TS 0x00000010 /* Use timeslices only */
-#define SBIMSTATE_AP_TK 0x00000020 /* Use token only */
-#define SBIMSTATE_AP_RSV 0x00000030 /* Reserved */
-#define SBIMSTATE_IBE 0x00020000 /* In Band Error */
-#define SBIMSTATE_TO 0x00040000 /* Timeout */
-#define B44_SBINTVEC 0x0F94UL /* SB Interrupt Mask */
-#define SBINTVEC_PCI 0x00000001 /* Enable interrupts for PCI */
-#define SBINTVEC_ENET0 0x00000002 /* Enable interrupts for enet 0 */
-#define SBINTVEC_ILINE20 0x00000004 /* Enable interrupts for iline20 */
-#define SBINTVEC_CODEC 0x00000008 /* Enable interrupts for v90 codec */
-#define SBINTVEC_USB 0x00000010 /* Enable interrupts for usb */
-#define SBINTVEC_EXTIF 0x00000020 /* Enable interrupts for external i/f */
-#define SBINTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */
-#define B44_SBTMSLOW 0x0F98UL /* SB Target State Low */
-#define SBTMSLOW_RESET 0x00000001 /* Reset */
-#define SBTMSLOW_REJECT 0x00000002 /* Reject */
-#define SBTMSLOW_CLOCK 0x00010000 /* Clock Enable */
-#define SBTMSLOW_FGC 0x00020000 /* Force Gated Clocks On */
-#define SBTMSLOW_PE 0x40000000 /* Power Management Enable */
-#define SBTMSLOW_BE 0x80000000 /* BIST Enable */
-#define B44_SBTMSHIGH 0x0F9CUL /* SB Target State High */
-#define SBTMSHIGH_SERR 0x00000001 /* S-error */
-#define SBTMSHIGH_INT 0x00000002 /* Interrupt */
-#define SBTMSHIGH_BUSY 0x00000004 /* Busy */
-#define SBTMSHIGH_GCR 0x20000000 /* Gated Clock Request */
-#define SBTMSHIGH_BISTF 0x40000000 /* BIST Failed */
-#define SBTMSHIGH_BISTD 0x80000000 /* BIST Done */
-#define B44_SBIDHIGH 0x0FFCUL /* SB Identification High */
-#define SBIDHIGH_RC_MASK 0x0000000f /* Revision Code */
-#define SBIDHIGH_CC_MASK 0x0000fff0 /* Core Code */
-#define SBIDHIGH_CC_SHIFT 4
-#define SBIDHIGH_VC_MASK 0xffff0000 /* Vendor Code */
-#define SBIDHIGH_VC_SHIFT 16
-
-/* SSB PCI config space registers. */
-#define SSB_PMCSR 0x44
-#define SSB_PE 0x100
-#define SSB_BAR0_WIN 0x80
-#define SSB_BAR1_WIN 0x84
-#define SSB_SPROM_CONTROL 0x88
-#define SSB_BAR1_CONTROL 0x8c
-
-/* SSB core and host control registers. */
-#define SSB_CONTROL 0x0000UL
-#define SSB_ARBCONTROL 0x0010UL
-#define SSB_ISTAT 0x0020UL
-#define SSB_IMASK 0x0024UL
-#define SSB_MBOX 0x0028UL
-#define SSB_BCAST_ADDR 0x0050UL
-#define SSB_BCAST_DATA 0x0054UL
-#define SSB_PCI_TRANS_0 0x0100UL
-#define SSB_PCI_TRANS_1 0x0104UL
-#define SSB_PCI_TRANS_2 0x0108UL
-#define SSB_SPROM 0x0800UL
-
-#define SSB_PCI_MEM 0x00000000
-#define SSB_PCI_IO 0x00000001
-#define SSB_PCI_CFG0 0x00000002
-#define SSB_PCI_CFG1 0x00000003
-#define SSB_PCI_PREF 0x00000004
-#define SSB_PCI_BURST 0x00000008
-#define SSB_PCI_MASK0 0xfc000000
-#define SSB_PCI_MASK1 0xfc000000
-#define SSB_PCI_MASK2 0xc0000000
-
/* 4400 PHY registers */
#define B44_MII_AUXCTRL 24 /* Auxiliary Control */
#define MII_AUXCTRL_DUPLEX 0x0001 /* Full Duplex */
@@ -346,10 +277,12 @@ struct rx_header {
struct ring_info {
struct sk_buff *skb;
- DECLARE_PCI_UNMAP_ADDR(mapping);
+ dma_addr_t mapping;
};
#define B44_MCAST_TABLE_SIZE 32
+#define B44_PHY_ADDR_NO_PHY 30
+#define B44_MDC_RATIO 5000000
#define B44_STAT_REG_DECLARE \
_B44(tx_good_octets) \
@@ -410,6 +343,8 @@ B44_STAT_REG_DECLARE
#undef _B44
};
+struct ssb_device;
+
struct b44 {
spinlock_t lock;
@@ -423,6 +358,8 @@ struct b44 {
struct ring_info *rx_buffers;
struct ring_info *tx_buffers;
+ struct napi_struct napi;
+
u32 dma_offset;
u32 flags;
#define B44_FLAG_B0_ANDLATER 0x00000001
@@ -450,8 +387,7 @@ struct b44 {
struct net_device_stats stats;
struct b44_hw_stats hw_stats;
- void __iomem *regs;
- struct pci_dev *pdev;
+ struct ssb_device *sdev;
struct net_device *dev;
dma_addr_t rx_ring_dma, tx_ring_dma;
@@ -459,7 +395,6 @@ struct b44 {
u32 rx_pending;
u32 tx_pending;
u8 phy_addr;
- u8 core_unit;
struct mii_if_info mii_if;
};
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 2bb97d46468..084acfd6fc5 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -47,15 +47,11 @@
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
-
+#include <linux/phy.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-
#include <linux/platform_device.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
@@ -99,6 +95,9 @@ static struct net_dma_desc_tx *current_tx_ptr;
static struct net_dma_desc_tx *tx_desc;
static struct net_dma_desc_rx *rx_desc;
+static void bf537mac_disable(void);
+static void bf537mac_enable(void);
+
static void desc_list_free(void)
{
struct net_dma_desc_rx *r;
@@ -287,8 +286,11 @@ static int setup_pin_mux(int action)
return 0;
}
+/*
+ * MII operations
+ */
/* Wait until the previous MDC/MDIO transaction has completed */
-static void poll_mdc_done(void)
+static void mdio_poll(void)
{
int timeout_cnt = MAX_TIMEOUT_CNT;
@@ -304,154 +306,199 @@ static void poll_mdc_done(void)
}
/* Read an off-chip register in a PHY through the MDC/MDIO port */
-static u16 read_phy_reg(u16 PHYAddr, u16 RegAddr)
+static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
{
- poll_mdc_done();
+ mdio_poll();
+
/* read mode */
- bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) |
- SET_REGAD(RegAddr) |
+ bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) |
+ SET_REGAD((u16) regnum) |
STABUSY);
- poll_mdc_done();
- return (u16) bfin_read_EMAC_STADAT();
+ mdio_poll();
+
+ return (int) bfin_read_EMAC_STADAT();
}
/* Write an off-chip register in a PHY through the MDC/MDIO port */
-static void raw_write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data)
+static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
+ u16 value)
{
- bfin_write_EMAC_STADAT(Data);
+ mdio_poll();
+
+ bfin_write_EMAC_STADAT((u32) value);
/* write mode */
- bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) |
- SET_REGAD(RegAddr) |
+ bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) |
+ SET_REGAD((u16) regnum) |
STAOP |
STABUSY);
- poll_mdc_done();
+ mdio_poll();
+
+ return 0;
}
-static void write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data)
+static int mdiobus_reset(struct mii_bus *bus)
{
- poll_mdc_done();
- raw_write_phy_reg(PHYAddr, RegAddr, Data);
+ return 0;
}
-/* set up the phy */
-static void bf537mac_setphy(struct net_device *dev)
+static void bf537_adjust_link(struct net_device *dev)
{
- u16 phydat;
struct bf537mac_local *lp = netdev_priv(dev);
+ struct phy_device *phydev = lp->phydev;
+ unsigned long flags;
+ int new_state = 0;
+
+ spin_lock_irqsave(&lp->lock, flags);
+ if (phydev->link) {
+ /* Now we make sure that we can be in full duplex mode.
+ * If not, we operate in half-duplex mode. */
+ if (phydev->duplex != lp->old_duplex) {
+ u32 opmode = bfin_read_EMAC_OPMODE();
+ new_state = 1;
+
+ if (phydev->duplex)
+ opmode |= FDMODE;
+ else
+ opmode &= ~(FDMODE);
+
+ bfin_write_EMAC_OPMODE(opmode);
+ lp->old_duplex = phydev->duplex;
+ }
- /* Program PHY registers */
- pr_debug("start setting up phy\n");
-
- /* issue a reset */
- raw_write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, 0x8000);
-
- /* wait half a second */
- msleep(500);
-
- phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL);
-
- /* advertise flow control supported */
- phydat = read_phy_reg(lp->PhyAddr, PHYREG_ANAR);
- phydat |= (1 << 10);
- write_phy_reg(lp->PhyAddr, PHYREG_ANAR, phydat);
+ if (phydev->speed != lp->old_speed) {
+#if defined(CONFIG_BFIN_MAC_RMII)
+ u32 opmode = bfin_read_EMAC_OPMODE();
+ switch (phydev->speed) {
+ case 10:
+ opmode |= RMII_10;
+ break;
+ case 100:
+ opmode &= ~(RMII_10);
+ break;
+ default:
+ printk(KERN_WARNING
+ "%s: Ack! Speed (%d) is not 10/100!\n",
+ DRV_NAME, phydev->speed);
+ break;
+ }
+ bfin_write_EMAC_OPMODE(opmode);
+#endif
- phydat = 0;
- if (lp->Negotiate)
- phydat |= 0x1000; /* enable auto negotiation */
- else {
- if (lp->FullDuplex)
- phydat |= (1 << 8); /* full duplex */
- else
- phydat &= (~(1 << 8)); /* half duplex */
+ new_state = 1;
+ lp->old_speed = phydev->speed;
+ }
- if (!lp->Port10)
- phydat |= (1 << 13); /* 100 Mbps */
- else
- phydat &= (~(1 << 13)); /* 10 Mbps */
+ if (!lp->old_link) {
+ new_state = 1;
+ lp->old_link = 1;
+ netif_schedule(dev);
+ }
+ } else if (lp->old_link) {
+ new_state = 1;
+ lp->old_link = 0;
+ lp->old_speed = 0;
+ lp->old_duplex = -1;
}
- if (lp->Loopback)
- phydat |= (1 << 14); /* enable TX->RX loopback */
-
- write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, phydat);
- msleep(500);
-
- phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL);
- /* check for SMSC PHY */
- if ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID1) == 0x7) &&
- ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID2) & 0xfff0) == 0xC0A0)) {
- /*
- * we have SMSC PHY so reqest interrupt
- * on link down condition
- */
-
- /* enable interrupts */
- write_phy_reg(lp->PhyAddr, 30, 0x0ff);
+ if (new_state) {
+ u32 opmode = bfin_read_EMAC_OPMODE();
+ phy_print_status(phydev);
+ pr_debug("EMAC_OPMODE = 0x%08x\n", opmode);
}
+
+ spin_unlock_irqrestore(&lp->lock, flags);
}
-/**************************************************************************/
-void setup_system_regs(struct net_device *dev)
+static int mii_probe(struct net_device *dev)
{
- int phyaddr;
- unsigned short sysctl, phydat;
- u32 opmode;
struct bf537mac_local *lp = netdev_priv(dev);
- int count = 0;
-
- phyaddr = lp->PhyAddr;
+ struct phy_device *phydev = NULL;
+ unsigned short sysctl;
+ int i;
- /* Enable PHY output */
+ /* Enable PHY output early */
if (!(bfin_read_VR_CTL() & PHYCLKOE))
bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE);
/* MDC = 2.5 MHz */
- sysctl = SET_MDCDIV(24);
- /* Odd word alignment for Receive Frame DMA word */
- /* Configure checksum support and rcve frame word alignment */
-#if defined(BFIN_MAC_CSUM_OFFLOAD)
- sysctl |= RXDWA | RXCKS;
-#else
- sysctl |= RXDWA;
-#endif
+ sysctl = bfin_read_EMAC_SYSCTL();
+ sysctl |= SET_MDCDIV(24);
bfin_write_EMAC_SYSCTL(sysctl);
- /* auto negotiation on */
- /* full duplex */
- /* 100 Mbps */
- phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET;
- write_phy_reg(phyaddr, PHYREG_MODECTL, phydat);
- /* test if full duplex supported */
- do {
- msleep(100);
- phydat = read_phy_reg(phyaddr, PHYREG_MODESTAT);
- if (count > 30) {
- printk(KERN_NOTICE DRV_NAME ": Link is down\n");
- printk(KERN_NOTICE DRV_NAME
- "please check your network connection\n");
- break;
- }
- count++;
- } while (!(phydat & 0x0004));
+ /* search for connect PHY device */
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ struct phy_device *const tmp_phydev = lp->mii_bus.phy_map[i];
- phydat = read_phy_reg(phyaddr, PHYREG_ANLPAR);
+ if (!tmp_phydev)
+ continue; /* no PHY here... */
- if ((phydat & 0x0100) || (phydat & 0x0040)) {
- opmode = FDMODE;
- } else {
- opmode = 0;
- printk(KERN_INFO DRV_NAME
- ": Network is set to half duplex\n");
+ phydev = tmp_phydev;
+ break; /* found it */
+ }
+
+ /* now we are supposed to have a proper phydev, to attach to... */
+ if (!phydev) {
+ printk(KERN_INFO "%s: Don't found any phy device at all\n",
+ dev->name);
+ return -ENODEV;
}
#if defined(CONFIG_BFIN_MAC_RMII)
- opmode |= RMII; /* For Now only 100MBit are supported */
+ phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
+ PHY_INTERFACE_MODE_RMII);
+#else
+ phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
+ PHY_INTERFACE_MODE_MII);
#endif
- bfin_write_EMAC_OPMODE(opmode);
+ if (IS_ERR(phydev)) {
+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+ return PTR_ERR(phydev);
+ }
+
+ /* mask with MAC supported features */
+ phydev->supported &= (SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_Autoneg
+ | SUPPORTED_Pause | SUPPORTED_Asym_Pause
+ | SUPPORTED_MII
+ | SUPPORTED_TP);
+
+ phydev->advertising = phydev->supported;
+
+ lp->old_link = 0;
+ lp->old_speed = 0;
+ lp->old_duplex = -1;
+ lp->phydev = phydev;
+
+ printk(KERN_INFO "%s: attached PHY driver [%s] "
+ "(mii_bus:phy_addr=%s, irq=%d)\n",
+ DRV_NAME, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+
+ return 0;
+}
+
+/**************************************************************************/
+void setup_system_regs(struct net_device *dev)
+{
+ unsigned short sysctl;
+
+ /*
+ * Odd word alignment for Receive Frame DMA word
+ * Configure checksum support and rcve frame word alignment
+ */
+ sysctl = bfin_read_EMAC_SYSCTL();
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+ sysctl |= RXDWA | RXCKS;
+#else
+ sysctl |= RXDWA;
+#endif
+ bfin_write_EMAC_SYSCTL(sysctl);
bfin_write_EMAC_MMC_CTL(RSTC | CROLL);
@@ -468,7 +515,7 @@ void setup_system_regs(struct net_device *dev)
bfin_write_DMA1_Y_MODIFY(0);
}
-void setup_mac_addr(u8 * mac_addr)
+static void setup_mac_addr(u8 *mac_addr)
{
u32 addr_low = le32_to_cpu(*(__le32 *) & mac_addr[0]);
u16 addr_hi = le16_to_cpu(*(__le16 *) & mac_addr[4]);
@@ -478,6 +525,16 @@ void setup_mac_addr(u8 * mac_addr)
bfin_write_EMAC_ADDRHI(addr_hi);
}
+static int bf537mac_set_mac_address(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+ if (netif_running(dev))
+ return -EBUSY;
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ setup_mac_addr(dev->dev_addr);
+ return 0;
+}
+
static void adjust_tx_list(void)
{
int timeout_cnt = MAX_TIMEOUT_CNT;
@@ -584,8 +641,8 @@ out:
adjust_tx_list();
current_tx_ptr = current_tx_ptr->next;
dev->trans_start = jiffies;
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += (skb->len);
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += (skb->len);
return 0;
}
@@ -601,7 +658,7 @@ static void bf537mac_rx(struct net_device *dev)
if (!new_skb) {
printk(KERN_NOTICE DRV_NAME
": rx: low on mem - packet dropped\n");
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto out;
}
/* reserve 2 bytes for RXDWA padding */
@@ -623,8 +680,8 @@ static void bf537mac_rx(struct net_device *dev)
#endif
netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
current_rx_ptr->status.status_word = 0x00000000;
current_rx_ptr = current_rx_ptr->next;
@@ -667,7 +724,7 @@ static void bf537mac_poll(struct net_device *dev)
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
-static void bf537mac_reset(void)
+static void bf537mac_disable(void)
{
unsigned int opmode;
@@ -681,18 +738,18 @@ static void bf537mac_reset(void)
/*
* Enable Interrupts, Receive, and Transmit
*/
-static int bf537mac_enable(struct net_device *dev)
+static void bf537mac_enable(void)
{
u32 opmode;
- pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+ pr_debug("%s: %s\n", DRV_NAME, __FUNCTION__);
/* Set RX DMA */
bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a));
bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config);
/* Wait MII done */
- poll_mdc_done();
+ mdio_poll();
/* We enable only RX here */
/* ASTP : Enable Automatic Pad Stripping
@@ -716,8 +773,6 @@ static int bf537mac_enable(struct net_device *dev)
#endif
/* Turn on the EMAC rx */
bfin_write_EMAC_OPMODE(opmode);
-
- return 0;
}
/* Our watchdog timed out. Called by the networking layer */
@@ -725,12 +780,12 @@ static void bf537mac_timeout(struct net_device *dev)
{
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
- bf537mac_reset();
+ bf537mac_disable();
/* reset tx queue */
tx_list_tail = tx_list_head->next;
- bf537mac_enable(dev);
+ bf537mac_enable();
/* We can accept TX packets again */
dev->trans_start = jiffies;
@@ -738,20 +793,6 @@ static void bf537mac_timeout(struct net_device *dev)
}
/*
- * Get the current statistics.
- * This may be called with the card open or closed.
- */
-static struct net_device_stats *bf537mac_query_statistics(struct net_device
- *dev)
-{
- struct bf537mac_local *lp = netdev_priv(dev);
-
- pr_debug("%s: %s\n", dev->name, __FUNCTION__);
-
- return &lp->stats;
-}
-
-/*
* This routine will, depending on the values passed to it,
* either make it accept multicast packets, go into
* promiscuous mode (for TCPDUMP and cousins) or accept
@@ -798,6 +839,7 @@ static void bf537mac_shutdown(struct net_device *dev)
*/
static int bf537mac_open(struct net_device *dev)
{
+ struct bf537mac_local *lp = netdev_priv(dev);
int retval;
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
@@ -817,10 +859,10 @@ static int bf537mac_open(struct net_device *dev)
if (retval)
return retval;
- bf537mac_setphy(dev);
+ phy_start(lp->phydev);
setup_system_regs(dev);
- bf537mac_reset();
- bf537mac_enable(dev);
+ bf537mac_disable();
+ bf537mac_enable();
pr_debug("hardware init finished\n");
netif_start_queue(dev);
@@ -837,11 +879,14 @@ static int bf537mac_open(struct net_device *dev)
*/
static int bf537mac_close(struct net_device *dev)
{
+ struct bf537mac_local *lp = netdev_priv(dev);
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
netif_stop_queue(dev);
netif_carrier_off(dev);
+ phy_stop(lp->phydev);
+
/* clear everything */
bf537mac_shutdown(dev);
@@ -855,6 +900,7 @@ static int __init bf537mac_probe(struct net_device *dev)
{
struct bf537mac_local *lp = netdev_priv(dev);
int retval;
+ int i;
/* Grab the MAC address in the MAC */
*(__le32 *) (&(dev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
@@ -871,7 +917,6 @@ static int __init bf537mac_probe(struct net_device *dev)
/* set the GPIO pins to Ethernet mode */
retval = setup_pin_mux(1);
-
if (retval)
return retval;
@@ -889,26 +934,36 @@ static int __init bf537mac_probe(struct net_device *dev)
setup_mac_addr(dev->dev_addr);
+ /* MDIO bus initial */
+ lp->mii_bus.priv = dev;
+ lp->mii_bus.read = mdiobus_read;
+ lp->mii_bus.write = mdiobus_write;
+ lp->mii_bus.reset = mdiobus_reset;
+ lp->mii_bus.name = "bfin_mac_mdio";
+ lp->mii_bus.id = 0;
+ lp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+ for (i = 0; i < PHY_MAX_ADDR; ++i)
+ lp->mii_bus.irq[i] = PHY_POLL;
+
+ mdiobus_register(&lp->mii_bus);
+
+ retval = mii_probe(dev);
+ if (retval)
+ return retval;
+
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
dev->open = bf537mac_open;
dev->stop = bf537mac_close;
dev->hard_start_xmit = bf537mac_hard_start_xmit;
+ dev->set_mac_address = bf537mac_set_mac_address;
dev->tx_timeout = bf537mac_timeout;
- dev->get_stats = bf537mac_query_statistics;
dev->set_multicast_list = bf537mac_set_multicast_list;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = bf537mac_poll;
#endif
- /* fill in some of the fields */
- lp->version = 1;
- lp->PhyAddr = 0x01;
- lp->CLKIN = 25;
- lp->FullDuplex = 0;
- lp->Negotiate = 1;
- lp->FlowControl = 0;
spin_lock_init(&lp->lock);
/* now, enable interrupts */
@@ -921,9 +976,6 @@ static int __init bf537mac_probe(struct net_device *dev)
return -EBUSY;
}
- /* Enable PHY output early */
- if (!(bfin_read_VR_CTL() & PHYCLKOE))
- bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE);
retval = register_netdev(dev);
if (retval == 0) {
@@ -946,7 +998,6 @@ static int bfin_mac_probe(struct platform_device *pdev)
return -ENOMEM;
}
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
platform_set_drvdata(pdev, ndev);
@@ -978,15 +1029,30 @@ static int bfin_mac_remove(struct platform_device *pdev)
return 0;
}
-static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM
+static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg)
{
+ struct net_device *net_dev = platform_get_drvdata(pdev);
+
+ if (netif_running(net_dev))
+ bf537mac_close(net_dev);
+
return 0;
}
static int bfin_mac_resume(struct platform_device *pdev)
{
+ struct net_device *net_dev = platform_get_drvdata(pdev);
+
+ if (netif_running(net_dev))
+ bf537mac_open(net_dev);
+
return 0;
}
+#else
+#define bfin_mac_suspend NULL
+#define bfin_mac_resume NULL
+#endif /* CONFIG_PM */
static struct platform_driver bfin_mac_driver = {
.probe = bfin_mac_probe,
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
index af87189b85f..3a107ad7538 100644
--- a/drivers/net/bfin_mac.h
+++ b/drivers/net/bfin_mac.h
@@ -31,32 +31,6 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/*
- * PHY REGISTER NAMES
- */
-#define PHYREG_MODECTL 0x0000
-#define PHYREG_MODESTAT 0x0001
-#define PHYREG_PHYID1 0x0002
-#define PHYREG_PHYID2 0x0003
-#define PHYREG_ANAR 0x0004
-#define PHYREG_ANLPAR 0x0005
-#define PHYREG_ANER 0x0006
-#define PHYREG_NSR 0x0010
-#define PHYREG_LBREMR 0x0011
-#define PHYREG_REC 0x0012
-#define PHYREG_10CFG 0x0013
-#define PHYREG_PHY1_1 0x0014
-#define PHYREG_PHY1_2 0x0015
-#define PHYREG_PHY2 0x0016
-#define PHYREG_TW_1 0x0017
-#define PHYREG_TW_2 0x0018
-#define PHYREG_TEST 0x0019
-
-#define PHY_RESET 0x8000
-#define PHY_ANEG_EN 0x1000
-#define PHY_DUPLEX 0x0100
-#define PHY_SPD_SET 0x2000
-
#define BFIN_MAC_CSUM_OFFLOAD
struct dma_descriptor {
@@ -106,27 +80,16 @@ struct bf537mac_local {
*/
struct net_device_stats stats;
- int version;
-
- int FlowEnabled; /* record if data flow is active */
- int EtherIntIVG; /* IVG for the ethernet interrupt */
- int RXIVG; /* IVG for the RX completion */
- int TXIVG; /* IVG for the TX completion */
- int PhyAddr; /* PHY address */
- int OpMode; /* set these bits n the OPMODE regs */
- int Port10; /* set port speed to 10 Mbit/s */
- int GenChksums; /* IP checksums to be calculated */
- int NoRcveLnth; /* dont insert recv length at start of buffer */
- int StripPads; /* remove trailing pad bytes */
- int FullDuplex; /* set full duplex mode */
- int Negotiate; /* enable auto negotiation */
- int Loopback; /* loopback at the PHY */
- int Cache; /* Buffers may be cached */
- int FlowControl; /* flow control active */
- int CLKIN; /* clock in value in MHZ */
- unsigned short IntMask; /* interrupt mask */
unsigned char Mac[6]; /* MAC address of the board */
spinlock_t lock;
+
+ /* MII and PHY stuffs */
+ int old_link; /* used by bf537_adjust_link */
+ int old_speed;
+ int old_duplex;
+
+ struct phy_device *phydev;
+ struct mii_bus mii_bus;
};
extern void get_bf537_ether_addr(char *addr);
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 9b8d7d9dbe8..a42bd19646d 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -19,6 +19,7 @@
#include <linux/spinlock.h>
#include <linux/crc32.h>
#include <linux/bitrev.h>
+#include <linux/ethtool.h>
#include <asm/prom.h>
#include <asm/dbdma.h>
#include <asm/io.h>
@@ -74,7 +75,6 @@ struct bmac_data {
int tx_fill;
int tx_empty;
unsigned char tx_fullup;
- struct net_device_stats stats;
struct timer_list tx_timeout;
int timeout_active;
int sleeping;
@@ -144,7 +144,6 @@ static unsigned char *bmac_emergency_rxbuf;
static int bmac_open(struct net_device *dev);
static int bmac_close(struct net_device *dev);
static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *bmac_stats(struct net_device *dev);
static void bmac_set_multicast(struct net_device *dev);
static void bmac_reset_and_enable(struct net_device *dev);
static void bmac_start_chip(struct net_device *dev);
@@ -667,7 +666,7 @@ static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev)
bp->tx_bufs[bp->tx_fill] = skb;
bp->tx_fill = i;
- bp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
dbdma_continue(td);
@@ -706,8 +705,8 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id)
nb = RX_BUFLEN - residual - 2;
if (nb < (ETHERMINPACKET - ETHERCRC)) {
skb = NULL;
- bp->stats.rx_length_errors++;
- bp->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
+ dev->stats.rx_errors++;
} else {
skb = bp->rx_bufs[i];
bp->rx_bufs[i] = NULL;
@@ -718,10 +717,10 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- ++bp->stats.rx_packets;
- bp->stats.rx_bytes += nb;
+ ++dev->stats.rx_packets;
+ dev->stats.rx_bytes += nb;
} else {
- ++bp->stats.rx_dropped;
+ ++dev->stats.rx_dropped;
}
dev->last_rx = jiffies;
if ((skb = bp->rx_bufs[i]) == NULL) {
@@ -784,7 +783,7 @@ static irqreturn_t bmac_txdma_intr(int irq, void *dev_id)
}
if (bp->tx_bufs[bp->tx_empty]) {
- ++bp->stats.tx_packets;
+ ++dev->stats.tx_packets;
dev_kfree_skb_irq(bp->tx_bufs[bp->tx_empty]);
}
bp->tx_bufs[bp->tx_empty] = NULL;
@@ -806,13 +805,6 @@ static irqreturn_t bmac_txdma_intr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static struct net_device_stats *bmac_stats(struct net_device *dev)
-{
- struct bmac_data *p = netdev_priv(dev);
-
- return &p->stats;
-}
-
#ifndef SUNHME_MULTICAST
/* Real fast bit-reversal algorithm, 6-bit values */
static int reverse6[64] = {
@@ -1079,17 +1071,17 @@ static irqreturn_t bmac_misc_intr(int irq, void *dev_id)
}
/* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */
/* bmac_txdma_intr_inner(irq, dev_id); */
- /* if (status & FrameReceived) bp->stats.rx_dropped++; */
- if (status & RxErrorMask) bp->stats.rx_errors++;
- if (status & RxCRCCntExp) bp->stats.rx_crc_errors++;
- if (status & RxLenCntExp) bp->stats.rx_length_errors++;
- if (status & RxOverFlow) bp->stats.rx_over_errors++;
- if (status & RxAlignCntExp) bp->stats.rx_frame_errors++;
-
- /* if (status & FrameSent) bp->stats.tx_dropped++; */
- if (status & TxErrorMask) bp->stats.tx_errors++;
- if (status & TxUnderrun) bp->stats.tx_fifo_errors++;
- if (status & TxNormalCollExp) bp->stats.collisions++;
+ /* if (status & FrameReceived) dev->stats.rx_dropped++; */
+ if (status & RxErrorMask) dev->stats.rx_errors++;
+ if (status & RxCRCCntExp) dev->stats.rx_crc_errors++;
+ if (status & RxLenCntExp) dev->stats.rx_length_errors++;
+ if (status & RxOverFlow) dev->stats.rx_over_errors++;
+ if (status & RxAlignCntExp) dev->stats.rx_frame_errors++;
+
+ /* if (status & FrameSent) dev->stats.tx_dropped++; */
+ if (status & TxErrorMask) dev->stats.tx_errors++;
+ if (status & TxUnderrun) dev->stats.tx_fifo_errors++;
+ if (status & TxNormalCollExp) dev->stats.collisions++;
return IRQ_HANDLED;
}
@@ -1246,6 +1238,17 @@ static void bmac_reset_and_enable(struct net_device *dev)
}
spin_unlock_irqrestore(&bp->lock, flags);
}
+static void bmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ struct bmac_data *bp = netdev_priv(dev);
+ strcpy(info->driver, "bmac");
+ strcpy(info->bus_info, bp->mdev->ofdev.dev.bus_id);
+}
+
+static const struct ethtool_ops bmac_ethtool_ops = {
+ .get_drvinfo = bmac_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+};
static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_id *match)
{
@@ -1255,6 +1258,7 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
unsigned char addr[6];
struct net_device *dev;
int is_bmac_plus = ((int)match->data) != 0;
+ DECLARE_MAC_BUF(mac);
if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n");
@@ -1279,7 +1283,6 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
}
bp = netdev_priv(dev);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
macio_set_drvdata(mdev, dev);
@@ -1311,8 +1314,8 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
dev->open = bmac_open;
dev->stop = bmac_close;
+ dev->ethtool_ops = &bmac_ethtool_ops;
dev->hard_start_xmit = bmac_output;
- dev->get_stats = bmac_stats;
dev->set_multicast_list = bmac_set_multicast;
dev->set_mac_address = bmac_set_address;
@@ -1365,9 +1368,8 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
goto err_out_irq2;
}
- printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": ""));
- for (j = 0; j < 6; ++j)
- printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
+ printk(KERN_INFO "%s: BMAC%s at %s",
+ dev->name, (is_bmac_plus ? "+" : ""), print_mac(mac, dev->dev_addr));
XXDEBUG((", base_addr=%#0lx", dev->base_addr));
printk("\n");
@@ -1530,7 +1532,7 @@ static void bmac_tx_timeout(unsigned long data)
XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n",
bp->tx_empty, bp->tx_fill, bp->tx_fullup));
i = bp->tx_empty;
- ++bp->stats.tx_errors;
+ ++dev->stats.tx_errors;
if (i != bp->tx_fill) {
dev_kfree_skb(bp->tx_bufs[i]);
bp->tx_bufs[i] = NULL;
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 66eed22cbd2..da767d3d5af 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -26,7 +26,7 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/dma-mapping.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/delay.h>
@@ -52,10 +52,12 @@
#include "bnx2_fw.h"
#include "bnx2_fw2.h"
+#define FW_BUF_SIZE 0x8000
+
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.6.5"
-#define DRV_MODULE_RELDATE "September 20, 2007"
+#define DRV_MODULE_VERSION "1.6.8"
+#define DRV_MODULE_RELDATE "October 17, 2007"
#define RUN_AT(x) (jiffies + (x))
@@ -428,7 +430,7 @@ bnx2_netif_stop(struct bnx2 *bp)
{
bnx2_disable_int_sync(bp);
if (netif_running(bp->dev)) {
- netif_poll_disable(bp->dev);
+ napi_disable(&bp->napi);
netif_tx_disable(bp->dev);
bp->dev->trans_start = jiffies; /* prevent tx timeout */
}
@@ -440,7 +442,7 @@ bnx2_netif_start(struct bnx2 *bp)
if (atomic_dec_and_test(&bp->intr_sem)) {
if (netif_running(bp->dev)) {
netif_wake_queue(bp->dev);
- netif_poll_enable(bp->dev);
+ napi_enable(&bp->napi);
bnx2_enable_int(bp);
}
}
@@ -2551,7 +2553,7 @@ bnx2_msi(int irq, void *dev_instance)
if (unlikely(atomic_read(&bp->intr_sem) != 0))
return IRQ_HANDLED;
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &bp->napi);
return IRQ_HANDLED;
}
@@ -2568,7 +2570,7 @@ bnx2_msi_1shot(int irq, void *dev_instance)
if (unlikely(atomic_read(&bp->intr_sem) != 0))
return IRQ_HANDLED;
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &bp->napi);
return IRQ_HANDLED;
}
@@ -2604,9 +2606,9 @@ bnx2_interrupt(int irq, void *dev_instance)
if (unlikely(atomic_read(&bp->intr_sem) != 0))
return IRQ_HANDLED;
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &bp->napi)) {
bp->last_status_idx = sblk->status_idx;
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &bp->napi);
}
return IRQ_HANDLED;
@@ -2631,10 +2633,8 @@ bnx2_has_work(struct bnx2 *bp)
return 0;
}
-static int
-bnx2_poll(struct net_device *dev, int *budget)
+static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget)
{
- struct bnx2 *bp = netdev_priv(dev);
struct status_block *sblk = bp->status_blk;
u32 status_attn_bits = sblk->status_attn_bits;
u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
@@ -2652,44 +2652,54 @@ bnx2_poll(struct net_device *dev, int *budget)
REG_RD(bp, BNX2_HC_COMMAND);
}
- if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
+ if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
bnx2_tx_int(bp);
- if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) {
- int orig_budget = *budget;
- int work_done;
+ if (sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
+ work_done += bnx2_rx_int(bp, budget - work_done);
- if (orig_budget > dev->quota)
- orig_budget = dev->quota;
+ return work_done;
+}
- work_done = bnx2_rx_int(bp, orig_budget);
- *budget -= work_done;
- dev->quota -= work_done;
- }
+static int bnx2_poll(struct napi_struct *napi, int budget)
+{
+ struct bnx2 *bp = container_of(napi, struct bnx2, napi);
+ int work_done = 0;
+ struct status_block *sblk = bp->status_blk;
- bp->last_status_idx = bp->status_blk->status_idx;
- rmb();
+ while (1) {
+ work_done = bnx2_poll_work(bp, work_done, budget);
- if (!bnx2_has_work(bp)) {
- netif_rx_complete(dev);
- if (likely(bp->flags & USING_MSI_FLAG)) {
+ if (unlikely(work_done >= budget))
+ break;
+
+ /* bp->last_status_idx is used below to tell the hw how
+ * much work has been processed, so we must read it before
+ * checking for more work.
+ */
+ bp->last_status_idx = sblk->status_idx;
+ rmb();
+ if (likely(!bnx2_has_work(bp))) {
+ netif_rx_complete(bp->dev, napi);
+ if (likely(bp->flags & USING_MSI_FLAG)) {
+ REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+ BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+ bp->last_status_idx);
+ break;
+ }
REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+ BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
bp->last_status_idx);
- return 0;
- }
- REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
- BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
- BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
- bp->last_status_idx);
- REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
- BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
- bp->last_status_idx);
- return 0;
+ REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+ BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+ bp->last_status_idx);
+ break;
+ }
}
- return 1;
+ return work_done;
}
/* Called with rtnl_lock from vlan functions and also netif_tx_lock
@@ -2767,92 +2777,6 @@ bnx2_set_rx_mode(struct net_device *dev)
spin_unlock_bh(&bp->phy_lock);
}
-#define FW_BUF_SIZE 0x8000
-
-static int
-bnx2_gunzip_init(struct bnx2 *bp)
-{
- if ((bp->gunzip_buf = vmalloc(FW_BUF_SIZE)) == NULL)
- goto gunzip_nomem1;
-
- if ((bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL)) == NULL)
- goto gunzip_nomem2;
-
- bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
- if (bp->strm->workspace == NULL)
- goto gunzip_nomem3;
-
- return 0;
-
-gunzip_nomem3:
- kfree(bp->strm);
- bp->strm = NULL;
-
-gunzip_nomem2:
- vfree(bp->gunzip_buf);
- bp->gunzip_buf = NULL;
-
-gunzip_nomem1:
- printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for "
- "uncompression.\n", bp->dev->name);
- return -ENOMEM;
-}
-
-static void
-bnx2_gunzip_end(struct bnx2 *bp)
-{
- kfree(bp->strm->workspace);
-
- kfree(bp->strm);
- bp->strm = NULL;
-
- if (bp->gunzip_buf) {
- vfree(bp->gunzip_buf);
- bp->gunzip_buf = NULL;
- }
-}
-
-static int
-bnx2_gunzip(struct bnx2 *bp, u8 *zbuf, int len, void **outbuf, int *outlen)
-{
- int n, rc;
-
- /* check gzip header */
- if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED))
- return -EINVAL;
-
- n = 10;
-
-#define FNAME 0x8
- if (zbuf[3] & FNAME)
- while ((zbuf[n++] != 0) && (n < len));
-
- bp->strm->next_in = zbuf + n;
- bp->strm->avail_in = len - n;
- bp->strm->next_out = bp->gunzip_buf;
- bp->strm->avail_out = FW_BUF_SIZE;
-
- rc = zlib_inflateInit2(bp->strm, -MAX_WBITS);
- if (rc != Z_OK)
- return rc;
-
- rc = zlib_inflate(bp->strm, Z_FINISH);
-
- *outlen = FW_BUF_SIZE - bp->strm->avail_out;
- *outbuf = bp->gunzip_buf;
-
- if ((rc != Z_OK) && (rc != Z_STREAM_END))
- printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n",
- bp->dev->name, bp->strm->msg);
-
- zlib_inflateEnd(bp->strm);
-
- if (rc == Z_STREAM_END)
- return 0;
-
- return rc;
-}
-
static void
load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
u32 rv2p_proc)
@@ -2902,19 +2826,13 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
/* Load the Text area. */
offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
if (fw->gz_text) {
- u32 text_len;
- void *text;
+ int j;
- rc = bnx2_gunzip(bp, fw->gz_text, fw->gz_text_len, &text,
- &text_len);
- if (rc)
+ rc = zlib_inflate_blob(fw->text, FW_BUF_SIZE, fw->gz_text,
+ fw->gz_text_len);
+ if (rc < 0)
return rc;
- fw->text = text;
- }
- if (fw->gz_text) {
- int j;
-
for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j]));
}
@@ -2932,21 +2850,21 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
/* Load the SBSS area. */
offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
- if (fw->sbss) {
+ if (fw->sbss_len) {
int j;
for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
- REG_WR_IND(bp, offset, fw->sbss[j]);
+ REG_WR_IND(bp, offset, 0);
}
}
/* Load the BSS area. */
offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
- if (fw->bss) {
+ if (fw->bss_len) {
int j;
for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
- REG_WR_IND(bp, offset, fw->bss[j]);
+ REG_WR_IND(bp, offset, 0);
}
}
@@ -2979,27 +2897,24 @@ bnx2_init_cpus(struct bnx2 *bp)
{
struct cpu_reg cpu_reg;
struct fw_info *fw;
- int rc = 0;
+ int rc;
void *text;
- u32 text_len;
-
- if ((rc = bnx2_gunzip_init(bp)) != 0)
- return rc;
/* Initialize the RV2P processor. */
- rc = bnx2_gunzip(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), &text,
- &text_len);
- if (rc)
+ text = vmalloc(FW_BUF_SIZE);
+ if (!text)
+ return -ENOMEM;
+ rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1));
+ if (rc < 0)
goto init_cpu_err;
- load_rv2p_fw(bp, text, text_len, RV2P_PROC1);
+ load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1);
- rc = bnx2_gunzip(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), &text,
- &text_len);
- if (rc)
+ rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2));
+ if (rc < 0)
goto init_cpu_err;
- load_rv2p_fw(bp, text, text_len, RV2P_PROC2);
+ load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2);
/* Initialize the RX Processor. */
cpu_reg.mode = BNX2_RXP_CPU_MODE;
@@ -3020,6 +2935,7 @@ bnx2_init_cpus(struct bnx2 *bp)
else
fw = &bnx2_rxp_fw_06;
+ fw->text = text;
rc = load_cpu_fw(bp, &cpu_reg, fw);
if (rc)
goto init_cpu_err;
@@ -3043,6 +2959,7 @@ bnx2_init_cpus(struct bnx2 *bp)
else
fw = &bnx2_txp_fw_06;
+ fw->text = text;
rc = load_cpu_fw(bp, &cpu_reg, fw);
if (rc)
goto init_cpu_err;
@@ -3066,6 +2983,7 @@ bnx2_init_cpus(struct bnx2 *bp)
else
fw = &bnx2_tpat_fw_06;
+ fw->text = text;
rc = load_cpu_fw(bp, &cpu_reg, fw);
if (rc)
goto init_cpu_err;
@@ -3089,6 +3007,7 @@ bnx2_init_cpus(struct bnx2 *bp)
else
fw = &bnx2_com_fw_06;
+ fw->text = text;
rc = load_cpu_fw(bp, &cpu_reg, fw);
if (rc)
goto init_cpu_err;
@@ -3110,12 +3029,13 @@ bnx2_init_cpus(struct bnx2 *bp)
if (CHIP_NUM(bp) == CHIP_NUM_5709) {
fw = &bnx2_cp_fw_09;
+ fw->text = text;
rc = load_cpu_fw(bp, &cpu_reg, fw);
if (rc)
goto init_cpu_err;
}
init_cpu_err:
- bnx2_gunzip_end(bp);
+ vfree(text);
return rc;
}
@@ -3159,14 +3079,18 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
autoneg = bp->autoneg;
advertising = bp->advertising;
- bp->autoneg = AUTONEG_SPEED;
- bp->advertising = ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full |
- ADVERTISED_Autoneg;
+ if (bp->phy_port == PORT_TP) {
+ bp->autoneg = AUTONEG_SPEED;
+ bp->advertising = ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_Autoneg;
+ }
- bnx2_setup_copper_phy(bp);
+ spin_lock_bh(&bp->phy_lock);
+ bnx2_setup_phy(bp, bp->phy_port);
+ spin_unlock_bh(&bp->phy_lock);
bp->autoneg = autoneg;
bp->advertising = advertising;
@@ -3177,10 +3101,16 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
/* Enable port mode. */
val &= ~BNX2_EMAC_MODE_PORT;
- val |= BNX2_EMAC_MODE_PORT_MII |
- BNX2_EMAC_MODE_MPKT_RCVD |
+ val |= BNX2_EMAC_MODE_MPKT_RCVD |
BNX2_EMAC_MODE_ACPI_RCVD |
BNX2_EMAC_MODE_MPKT;
+ if (bp->phy_port == PORT_TP)
+ val |= BNX2_EMAC_MODE_PORT_MII;
+ else {
+ val |= BNX2_EMAC_MODE_PORT_GMII;
+ if (bp->line_speed == SPEED_2500)
+ val |= BNX2_EMAC_MODE_25G_MODE;
+ }
REG_WR(bp, BNX2_EMAC_MODE, val);
@@ -3500,7 +3430,7 @@ bnx2_init_nvram(struct bnx2 *bp)
/* Determine the selected interface. */
val = REG_RD(bp, BNX2_NVM_CFG1);
- entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
+ entry_count = ARRAY_SIZE(flash_table);
if (val & 0x40000000) {
@@ -3872,12 +3802,6 @@ bnx2_init_remote_phy(struct bnx2 *bp)
return;
if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
- if (netif_running(bp->dev)) {
- val = BNX2_DRV_ACK_CAP_SIGNATURE |
- BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
- REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB,
- val);
- }
bp->phy_flags |= REMOTE_PHY_CAP_FLAG;
val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
@@ -3885,6 +3809,22 @@ bnx2_init_remote_phy(struct bnx2 *bp)
bp->phy_port = PORT_FIBRE;
else
bp->phy_port = PORT_TP;
+
+ if (netif_running(bp->dev)) {
+ u32 sig;
+
+ if (val & BNX2_LINK_STATUS_LINK_UP) {
+ bp->link_up = 1;
+ netif_carrier_on(bp->dev);
+ } else {
+ bp->link_up = 0;
+ netif_carrier_off(bp->dev);
+ }
+ sig = BNX2_DRV_ACK_CAP_SIGNATURE |
+ BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
+ REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB,
+ sig);
+ }
}
}
@@ -3893,6 +3833,7 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
{
u32 val;
int i, rc = 0;
+ u8 old_port;
/* Wait for the current PCI transaction to complete before
* issuing a reset. */
@@ -3971,8 +3912,9 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
return rc;
spin_lock_bh(&bp->phy_lock);
+ old_port = bp->phy_port;
bnx2_init_remote_phy(bp);
- if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ if ((bp->phy_flags & REMOTE_PHY_CAP_FLAG) && old_port != bp->phy_port)
bnx2_set_default_remote_link(bp);
spin_unlock_bh(&bp->phy_lock);
@@ -4661,6 +4603,9 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
bnx2_set_mac_loopback(bp);
}
else if (loopback_mode == BNX2_PHY_LOOPBACK) {
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return 0;
+
bp->loopback = PHY_LOOPBACK;
bnx2_set_phy_loopback(bp);
}
@@ -4829,6 +4774,11 @@ bnx2_test_link(struct bnx2 *bp)
{
u32 bmsr;
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
+ if (bp->link_up)
+ return 0;
+ return -ENODEV;
+ }
spin_lock_bh(&bp->phy_lock);
bnx2_enable_bmsr1(bp);
bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
@@ -5039,6 +4989,8 @@ bnx2_open(struct net_device *dev)
if (rc)
return rc;
+ napi_enable(&bp->napi);
+
if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) {
if (pci_enable_msi(bp->pdev) == 0) {
bp->flags |= USING_MSI_FLAG;
@@ -5049,6 +5001,7 @@ bnx2_open(struct net_device *dev)
rc = bnx2_request_irq(bp);
if (rc) {
+ napi_disable(&bp->napi);
bnx2_free_mem(bp);
return rc;
}
@@ -5056,6 +5009,7 @@ bnx2_open(struct net_device *dev)
rc = bnx2_init_nic(bp);
if (rc) {
+ napi_disable(&bp->napi);
bnx2_free_irq(bp);
bnx2_free_skbs(bp);
bnx2_free_mem(bp);
@@ -5088,6 +5042,7 @@ bnx2_open(struct net_device *dev)
rc = bnx2_request_irq(bp);
if (rc) {
+ napi_disable(&bp->napi);
bnx2_free_skbs(bp);
bnx2_free_mem(bp);
del_timer_sync(&bp->timer);
@@ -5301,7 +5256,8 @@ bnx2_close(struct net_device *dev)
while (bp->in_reset_task)
msleep(1);
- bnx2_netif_stop(bp);
+ bnx2_disable_int_sync(bp);
+ napi_disable(&bp->napi);
del_timer_sync(&bp->timer);
if (bp->flags & NO_WOL_FLAG)
reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
@@ -6070,9 +6026,16 @@ static struct {
};
static int
-bnx2_self_test_count(struct net_device *dev)
+bnx2_get_sset_count(struct net_device *dev, int sset)
{
- return BNX2_NUM_TESTS;
+ switch (sset) {
+ case ETH_SS_TEST:
+ return BNX2_NUM_TESTS;
+ case ETH_SS_STATS:
+ return BNX2_NUM_STATS;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void
@@ -6146,12 +6109,6 @@ bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
}
}
-static int
-bnx2_get_stats_count(struct net_device *dev)
-{
- return BNX2_NUM_STATS;
-}
-
static void
bnx2_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *buf)
@@ -6259,18 +6216,14 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
.set_pauseparam = bnx2_set_pauseparam,
.get_rx_csum = bnx2_get_rx_csum,
.set_rx_csum = bnx2_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = bnx2_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = bnx2_set_tso,
- .self_test_count = bnx2_self_test_count,
.self_test = bnx2_self_test,
.get_strings = bnx2_get_strings,
.phys_id = bnx2_phys_id,
- .get_stats_count = bnx2_get_stats_count,
.get_ethtool_stats = bnx2_get_ethtool_stats,
+ .get_sset_count = bnx2_get_sset_count,
};
/* Called with rtnl_lock */
@@ -6476,7 +6429,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
u32 reg;
u64 dma_mask, persist_dma_mask;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
bp = netdev_priv(dev);
@@ -6486,7 +6438,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
/* enable device (incl. PCI PM wakeup), and bus-mastering */
rc = pci_enable_device(pdev);
if (rc) {
- dev_err(&pdev->dev, "Cannot enable PCI device, aborting.");
+ dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
goto err_out;
}
@@ -6643,8 +6595,11 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
if (i != 2)
bp->fw_version[j++] = '.';
}
- if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
- BNX2_PORT_FEATURE_ASF_ENABLED) {
+ reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE);
+ if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
+ bp->wol = 1;
+
+ if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
bp->flags |= ASF_ENABLE_FLAG;
for (i = 0; i < 30; i++) {
@@ -6714,11 +6669,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->phy_port = PORT_TP;
if (bp->phy_flags & PHY_SERDES_FLAG) {
bp->phy_port = PORT_FIBRE;
- bp->flags |= NO_WOL_FLAG;
+ reg = REG_RD_IND(bp, bp->shmem_base +
+ BNX2_SHARED_HW_CFG_CONFIG);
+ if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
+ bp->flags |= NO_WOL_FLAG;
+ bp->wol = 0;
+ }
if (CHIP_NUM(bp) != CHIP_NUM_5706) {
bp->phy_addr = 2;
- reg = REG_RD_IND(bp, bp->shmem_base +
- BNX2_SHARED_HW_CFG_CONFIG);
if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG;
}
@@ -6733,8 +6691,10 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
(CHIP_ID(bp) == CHIP_ID_5708_B0) ||
- (CHIP_ID(bp) == CHIP_ID_5708_B1))
+ (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
bp->flags |= NO_WOL_FLAG;
+ bp->wol = 0;
+ }
if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
bp->tx_quick_cons_trip_int =
@@ -6827,8 +6787,9 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
static int version_printed = 0;
struct net_device *dev = NULL;
struct bnx2 *bp;
- int rc, i;
+ int rc;
char str[40];
+ DECLARE_MAC_BUF(mac);
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -6858,11 +6819,10 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef BCM_VLAN
dev->vlan_rx_register = bnx2_vlan_rx_register;
#endif
- dev->poll = bnx2_poll;
dev->ethtool_ops = &bnx2_ethtool_ops;
- dev->weight = 64;
bp = netdev_priv(dev);
+ netif_napi_add(dev, &bp->napi, bnx2_poll, 64);
#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
dev->poll_controller = poll_bnx2;
@@ -6897,19 +6857,14 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
- "IRQ %d, ",
+ "IRQ %d, node addr %s\n",
dev->name,
bp->name,
((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
((CHIP_ID(bp) & 0x0ff0) >> 4),
bnx2_bus_string(bp, str),
dev->base_addr,
- bp->pdev->irq);
-
- printk("node addr ");
- for (i = 0; i < 6; i++)
- printk("%2.2x", dev->dev_addr[i]);
- printk("\n");
+ bp->pdev->irq, print_mac(mac, dev->dev_addr));
return 0;
}
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 102adfe1e92..1dce0d1a258 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -6473,6 +6473,8 @@ struct bnx2 {
struct net_device *dev;
struct pci_dev *pdev;
+ struct napi_struct napi;
+
atomic_t intr_sem;
struct status_block *status_blk;
@@ -6679,9 +6681,6 @@ struct bnx2 {
u32 flash_size;
int status_stats_size;
-
- struct z_stream_s *strm;
- void *gunzip_buf;
};
static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset);
@@ -6753,13 +6752,11 @@ struct fw_info {
const u32 sbss_addr;
const u32 sbss_len;
const u32 sbss_index;
- const u32 *sbss;
/* BSS section. */
const u32 bss_addr;
const u32 bss_len;
const u32 bss_index;
- const u32 *bss;
/* Read-only section. */
const u32 rodata_addr;
@@ -6911,6 +6908,7 @@ struct fw_info {
#define BNX2_SHARED_HW_CFG_LED_MODE_MAC 0
#define BNX2_SHARED_HW_CFG_LED_MODE_GPHY1 0x100
#define BNX2_SHARED_HW_CFG_LED_MODE_GPHY2 0x200
+#define BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX 0x8000
#define BNX2_SHARED_HW_CFG_CONFIG2 0x00000040
#define BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK 0x00fff000
diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h
index b49f439e0f6..a6d78243163 100644
--- a/drivers/net/bnx2_fw.h
+++ b/drivers/net/bnx2_fw.h
@@ -15,7 +15,8 @@
*/
static u8 bnx2_COM_b06FwText[] = {
- 0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5a,
+/* 0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, */
+ 0xdc, 0x5a,
0x6b, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0x33, 0x3b, 0x4b, 0xae, 0xc8, 0x15,
0x35, 0xa2, 0xc6, 0xf4, 0x5a, 0xa2, 0xed, 0x5d, 0x72, 0x28, 0x12, 0x96,
0xec, 0x6e, 0x68, 0xda, 0x62, 0x8c, 0x8d, 0xb4, 0xd9, 0xa5, 0x0c, 0xa1,
@@ -1047,8 +1048,6 @@ static const u32 bnx2_COM_b06FwRodata[(0x88/4) + 1] = {
0x08002bd8, 0x08002c08, 0x08002c38, 0x00000000, 0x080060cc, 0x080060cc,
0x080060cc, 0x080060cc, 0x080060cc, 0x08006100, 0x08006100, 0x08006140,
0x0800614c, 0x0800614c, 0x080060cc, 0x00000000, 0x00000000 };
-static const u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x0 };
-static const u32 bnx2_COM_b06FwSbss[(0x60/4) + 1] = { 0x0 };
static struct fw_info bnx2_com_fw_06 = {
.ver_major = 0x3,
@@ -1071,12 +1070,10 @@ static struct fw_info bnx2_com_fw_06 = {
.sbss_addr = 0x08007e00,
.sbss_len = 0x60,
.sbss_index = 0x0,
- .sbss = bnx2_COM_b06FwSbss,
.bss_addr = 0x08007e60,
.bss_len = 0x88,
.bss_index = 0x0,
- .bss = bnx2_COM_b06FwBss,
.rodata_addr = 0x08007d58,
.rodata_len = 0x88,
@@ -1085,8 +1082,9 @@ static struct fw_info bnx2_com_fw_06 = {
};
static u8 bnx2_RXP_b06FwText[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0xcb, 0xa3, 0x46, 0x45, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xec, 0x5c, 0x6f, 0x6c,
+/* 0x1f, 0x8b, 0x08, 0x08, 0xcb, 0xa3, 0x46, 0x45, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+ 0xec, 0x5c, 0x6f, 0x6c,
0x1c, 0xc7, 0x75, 0x7f, 0x3b, 0xbb, 0xa4, 0x4e, 0xd4, 0x91, 0x5c, 0x1e,
0x4f, 0xf4, 0x49, 0x66, 0x94, 0x5d, 0x71, 0x25, 0x5e, 0x2d, 0xc6, 0x5d,
0x31, 0x57, 0x9b, 0x08, 0xce, 0xf1, 0x79, 0xef, 0x64, 0xb1, 0x86, 0x0a,
@@ -1760,9 +1758,6 @@ static u32 bnx2_RXP_b06FwRodata[(0x278/4) + 1] = {
0x08006030, 0x08006030, 0x08006018, 0x08006030, 0x08006030, 0x08006030,
0x08006024, 0x00000000, 0x00000000 };
-static u32 bnx2_RXP_b06FwBss[(0x13dc/4) + 1] = { 0x0 };
-static u32 bnx2_RXP_b06FwSbss[(0x2c/4) + 1] = { 0x0 };
-
static struct fw_info bnx2_rxp_fw_06 = {
.ver_major = 0x2,
.ver_minor = 0x8,
@@ -1784,12 +1779,10 @@ static struct fw_info bnx2_rxp_fw_06 = {
.sbss_addr = 0x080069c0,
.sbss_len = 0x2c,
.sbss_index = 0x0,
- .sbss = bnx2_RXP_b06FwSbss,
.bss_addr = 0x080069f0,
.bss_len = 0x13dc,
.bss_index = 0x0,
- .bss = bnx2_RXP_b06FwBss,
.rodata_addr = 0x08006728,
.rodata_len = 0x278,
@@ -1798,8 +1791,9 @@ static struct fw_info bnx2_rxp_fw_06 = {
};
static u8 bnx2_rv2p_proc1[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0x5e, 0xd0, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x56, 0xcf, 0x6b,
+/* 0x1f, 0x8b, 0x08, 0x08, 0x5e, 0xd0, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+ 0xc5, 0x56, 0xcf, 0x6b,
0x13, 0x51, 0x10, 0x9e, 0xec, 0x6e, 0xb2, 0xdb, 0x74, 0xbb, 0x1b, 0x2b,
0xda, 0xa0, 0xb1, 0x8d, 0x51, 0x6a, 0x7f, 0xa4, 0xb4, 0x11, 0x0f, 0x82,
0x42, 0x25, 0x3d, 0x04, 0x54, 0x44, 0x7a, 0x28, 0x22, 0x82, 0x36, 0x8a,
@@ -1877,8 +1871,9 @@ static u8 bnx2_rv2p_proc1[] = {
0x12, 0x3d, 0x80, 0x0b, 0x00, 0x00, 0x00 };
static u8 bnx2_rv2p_proc2[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xd1, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xcd, 0x58, 0x5b, 0x6c,
+/* 0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xd1, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+ 0xcd, 0x58, 0x5b, 0x6c,
0x54, 0x55, 0x14, 0x3d, 0xf3, 0xe8, 0xcc, 0x9d, 0xe9, 0xed, 0x9d, 0xf2,
0xb2, 0x03, 0xad, 0x08, 0xe5, 0xd1, 0x56, 0x29, 0xe8, 0x54, 0xab, 0x18,
0x15, 0x2c, 0x5a, 0x8c, 0x26, 0x68, 0xf0, 0xf9, 0x63, 0x14, 0x04, 0xda,
@@ -2057,8 +2052,9 @@ static u8 bnx2_rv2p_proc2[] = {
0x17, 0x00, 0x00, 0x00 };
static u8 bnx2_TPAT_b06FwText[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0x47, 0xd2, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x57, 0x4d, 0x68,
+/* 0x1f, 0x8b, 0x08, 0x08, 0x47, 0xd2, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+ 0xc5, 0x57, 0x4d, 0x68,
0x1c, 0xe7, 0x19, 0x7e, 0xe7, 0x77, 0x47, 0x62, 0x25, 0x8d, 0x93, 0x3d,
0xac, 0x5d, 0xa5, 0x99, 0x91, 0x46, 0x3f, 0x54, 0x26, 0x9e, 0x84, 0xa5,
0x56, 0x61, 0x20, 0xe3, 0x99, 0x95, 0x2c, 0x0c, 0x05, 0x07, 0x42, 0x08,
@@ -2252,8 +2248,6 @@ static u8 bnx2_TPAT_b06FwText[] = {
static u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 };
static u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_TPAT_b06FwBss[(0x250/4) + 1] = { 0x0 };
-static u32 bnx2_TPAT_b06FwSbss[(0x34/4) + 1] = { 0x0 };
static struct fw_info bnx2_tpat_fw_06 = {
.ver_major = 0x1,
@@ -2276,12 +2270,10 @@ static struct fw_info bnx2_tpat_fw_06 = {
.sbss_addr = 0x08001a60,
.sbss_len = 0x34,
.sbss_index = 0x0,
- .sbss = bnx2_TPAT_b06FwSbss,
.bss_addr = 0x08001aa0,
.bss_len = 0x250,
.bss_index = 0x0,
- .bss = bnx2_TPAT_b06FwBss,
.rodata_addr = 0x00000000,
.rodata_len = 0x0,
@@ -2290,8 +2282,9 @@ static struct fw_info bnx2_tpat_fw_06 = {
};
static u8 bnx2_TXP_b06FwText[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0x21, 0xd3, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xed, 0x5c, 0x6d, 0x6c,
+/* 0x1f, 0x8b, 0x08, 0x08, 0x21, 0xd3, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+ 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+ 0xed, 0x5c, 0x6d, 0x6c,
0x1b, 0xf7, 0x79, 0x7f, 0xee, 0x85, 0xd2, 0x51, 0x96, 0xe9, 0x93, 0xc2,
0x78, 0x6c, 0xc0, 0xa6, 0x77, 0xd6, 0x51, 0x66, 0x20, 0xb5, 0xa0, 0x05,
0x36, 0x55, 0x87, 0x43, 0x73, 0x3e, 0x52, 0x2f, 0x4e, 0x5c, 0x57, 0x71,
@@ -2708,8 +2701,6 @@ static u8 bnx2_TXP_b06FwText[] = {
static u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 };
static u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_TXP_b06FwBss[(0x1c4/4) + 1] = { 0x0 };
-static u32 bnx2_TXP_b06FwSbss[(0x38/4) + 1] = { 0x0 };
static struct fw_info bnx2_txp_fw_06 = {
.ver_major = 0x1,
@@ -2732,12 +2723,10 @@ static struct fw_info bnx2_txp_fw_06 = {
.sbss_addr = 0x08005760,
.sbss_len = 0x38,
.sbss_index = 0x0,
- .sbss = bnx2_TXP_b06FwSbss,
.bss_addr = 0x080057a0,
.bss_len = 0x1c4,
.bss_index = 0x0,
- .bss = bnx2_TXP_b06FwBss,
.rodata_addr = 0x00000000,
.rodata_len = 0x0,
diff --git a/drivers/net/bnx2_fw2.h b/drivers/net/bnx2_fw2.h
index 2c067531f03..4b129b7cbfa 100644
--- a/drivers/net/bnx2_fw2.h
+++ b/drivers/net/bnx2_fw2.h
@@ -15,3262 +15,3272 @@
*/
static u8 bnx2_COM_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5b,
- 0x6d, 0x70, 0x5c, 0xd5, 0x79, 0x7e, 0xef, 0xd9, 0xbb, 0xf2, 0x5a, 0x92,
- 0xe5, 0x6b, 0x79, 0x23, 0x16, 0x4b, 0xc0, 0xae, 0x75, 0x6d, 0x69, 0xb0,
- 0x43, 0x16, 0xa1, 0x80, 0x9a, 0xd9, 0xc0, 0xb2, 0x2b, 0x33, 0x9e, 0x0c,
- 0x69, 0x64, 0x50, 0x80, 0xb6, 0x4c, 0x46, 0xec, 0x1a, 0x9a, 0x4e, 0x87,
- 0xd6, 0xa6, 0x6e, 0x9b, 0xc9, 0x34, 0x78, 0x47, 0x1f, 0x8d, 0xa7, 0x15,
- 0xba, 0x06, 0x1b, 0xd9, 0xd3, 0xd0, 0xa0, 0x6a, 0x71, 0xf1, 0x8f, 0x8d,
- 0xaf, 0xf9, 0x48, 0xaa, 0x4c, 0x4d, 0xa5, 0x18, 0x48, 0x69, 0xa7, 0x4d,
- 0xfb, 0xa3, 0x9e, 0xa1, 0x5f, 0x84, 0x32, 0xfd, 0xc1, 0x74, 0xda, 0x4e,
- 0x3a, 0x24, 0x53, 0x08, 0x84, 0xed, 0xf3, 0x9c, 0x7b, 0xee, 0xea, 0x6a,
- 0x25, 0x7f, 0xf1, 0x91, 0x1f, 0xd5, 0xcc, 0xfa, 0xde, 0xf3, 0xfd, 0x9e,
- 0xf7, 0xbc, 0xef, 0xf3, 0x7e, 0xdc, 0xe3, 0x4f, 0x8a, 0xb4, 0x8a, 0xf9,
- 0xdb, 0x80, 0x5f, 0xfa, 0xc1, 0xdf, 0x2c, 0x5f, 0x37, 0x78, 0xdd, 0x0d,
- 0x78, 0xbd, 0x41, 0xc5, 0xec, 0x18, 0xeb, 0xf9, 0x4f, 0x12, 0xbf, 0x01,
- 0xf3, 0xbe, 0xd6, 0x9f, 0x83, 0xdf, 0x9b, 0x68, 0x1c, 0xfb, 0x0f, 0x11,
- 0xeb, 0x3c, 0x7d, 0xa2, 0x7f, 0xf5, 0xfa, 0x85, 0xdb, 0x15, 0x69, 0xb9,
- 0x40, 0x7b, 0x2c, 0x58, 0x52, 0xd3, 0xcc, 0x9f, 0x24, 0x54, 0x6e, 0xec,
- 0xe1, 0x82, 0x2b, 0x89, 0x58, 0x6e, 0xf7, 0xc1, 0xb2, 0x2b, 0x92, 0xaf,
- 0xed, 0x48, 0x17, 0xe5, 0x67, 0xf5, 0x4a, 0xd2, 0x16, 0xd6, 0x5f, 0x95,
- 0x7b, 0xef, 0xc9, 0x17, 0x6e, 0xca, 0xfc, 0x68, 0x2e, 0x26, 0x09, 0x27,
- 0xf7, 0xbc, 0x38, 0xdb, 0x25, 0xd1, 0x83, 0x31, 0x4f, 0xf4, 0xe5, 0x2d,
- 0xe9, 0x08, 0xe7, 0x7a, 0xb3, 0xfe, 0x42, 0x9f, 0x54, 0xb6, 0xe4, 0x12,
- 0xa2, 0x72, 0xdb, 0x5e, 0x2d, 0xc4, 0x9c, 0xb1, 0x58, 0xce, 0x91, 0x45,
- 0x5f, 0x46, 0xee, 0x9f, 0x96, 0x44, 0x22, 0xf7, 0xe5, 0xc4, 0xba, 0x6d,
- 0x92, 0xb0, 0x73, 0x4b, 0x0f, 0xff, 0xbe, 0x7b, 0xb0, 0xae, 0x5c, 0xb7,
- 0x7f, 0x5e, 0xda, 0x87, 0x4e, 0x0c, 0xa2, 0xbd, 0x96, 0xe9, 0x17, 0xb9,
- 0x49, 0x94, 0x5b, 0x69, 0x8f, 0xb9, 0x09, 0x29, 0xf8, 0xae, 0x14, 0x7d,
- 0x91, 0xbf, 0xac, 0x59, 0x72, 0xc2, 0xed, 0x92, 0xf9, 0x9d, 0xef, 0xd5,
- 0xf3, 0xa0, 0xe5, 0xfb, 0xee, 0xd2, 0xc3, 0x93, 0x2e, 0xe9, 0x3d, 0x90,
- 0x08, 0xe8, 0xdd, 0xbb, 0xae, 0xec, 0xda, 0x32, 0x5e, 0x63, 0xdd, 0xa8,
- 0x62, 0x5d, 0x3c, 0x97, 0x68, 0x3d, 0xe1, 0xb6, 0x9b, 0xba, 0x57, 0x6f,
- 0x29, 0x60, 0xbe, 0x89, 0x1a, 0xfb, 0xe6, 0xaf, 0x2f, 0xbb, 0x49, 0x53,
- 0xbf, 0x70, 0x63, 0xc1, 0x4d, 0xa1, 0xbe, 0xc7, 0xb4, 0x8d, 0x3d, 0x58,
- 0x76, 0x5d, 0xd3, 0xf6, 0x76, 0xac, 0xe0, 0xf6, 0x9b, 0xfa, 0xf7, 0x6e,
- 0x2e, 0xbb, 0x3b, 0x4d, 0x7d, 0x0f, 0xe6, 0xca, 0x9a, 0xfa, 0x85, 0x7b,
- 0xca, 0xee, 0xa0, 0xa9, 0xdf, 0x7d, 0x73, 0xc1, 0x1d, 0x32, 0xf5, 0x89,
- 0xa1, 0xb2, 0x9b, 0x43, 0xfd, 0x97, 0x13, 0x6a, 0x9b, 0x23, 0x53, 0xb5,
- 0x34, 0x7e, 0x79, 0xb4, 0x0d, 0xa3, 0x6e, 0x37, 0x7e, 0xb7, 0xe3, 0xf7,
- 0xc8, 0x46, 0xe9, 0x18, 0xc1, 0xf3, 0xbf, 0xba, 0x03, 0xde, 0x81, 0x47,
- 0x5e, 0x42, 0x5e, 0x8f, 0xa5, 0xe4, 0x85, 0xbe, 0xd7, 0xc1, 0x43, 0x47,
- 0x4e, 0xfb, 0x62, 0x8d, 0xf4, 0xa5, 0xc0, 0xbb, 0xa4, 0x3c, 0xe3, 0xb7,
- 0x49, 0xec, 0xb1, 0x18, 0x78, 0xf3, 0xcb, 0x52, 0x4a, 0x26, 0x64, 0xd3,
- 0xac, 0x25, 0x5b, 0x07, 0x12, 0x92, 0x77, 0xb8, 0x36, 0x4e, 0x7b, 0x26,
- 0x29, 0xb1, 0xd9, 0xfc, 0x66, 0x25, 0xdb, 0x9c, 0xa2, 0x54, 0xc0, 0xbb,
- 0x57, 0x29, 0x97, 0x68, 0x4b, 0x4b, 0x71, 0xfa, 0x5a, 0x19, 0x73, 0x48,
- 0xd7, 0x1f, 0x5c, 0x15, 0xac, 0x95, 0xb0, 0x0a, 0xc7, 0x46, 0x65, 0xca,
- 0x6b, 0xb7, 0x8a, 0xc7, 0x6e, 0x96, 0x42, 0x56, 0x92, 0x18, 0x97, 0x2a,
- 0xa1, 0xa5, 0x5a, 0x1b, 0x95, 0x49, 0x4f, 0xac, 0x82, 0x47, 0x7e, 0x76,
- 0xa1, 0xbd, 0x43, 0xf7, 0x45, 0x5d, 0x4f, 0x4c, 0xcf, 0x9d, 0x40, 0xbd,
- 0x83, 0xfa, 0x4e, 0x6b, 0x58, 0xcf, 0xa1, 0xeb, 0xd3, 0x13, 0xd2, 0x2e,
- 0x4f, 0xd5, 0x92, 0xa6, 0x6f, 0xbd, 0x5e, 0xc8, 0x3a, 0xe8, 0x37, 0x2a,
- 0x13, 0x5e, 0x52, 0xc6, 0xf0, 0x1c, 0xf7, 0xb8, 0x7e, 0x0a, 0x32, 0x75,
- 0xdd, 0xc1, 0xd2, 0x51, 0x3d, 0x5f, 0x3a, 0x96, 0xe3, 0x7c, 0x3d, 0xe8,
- 0xf7, 0x12, 0xe8, 0xb2, 0xc4, 0xd6, 0x67, 0x99, 0x97, 0xd2, 0xb4, 0x05,
- 0x79, 0xc3, 0x53, 0xf3, 0x75, 0x18, 0xf4, 0xdb, 0xe2, 0x0e, 0x58, 0x52,
- 0xc6, 0x59, 0x55, 0x1c, 0x94, 0x6b, 0x0b, 0xaa, 0xe0, 0xad, 0x93, 0xa2,
- 0x9d, 0x96, 0xd8, 0x0c, 0x65, 0x69, 0x4c, 0x26, 0x30, 0x46, 0xb9, 0xec,
- 0xf3, 0x0e, 0xf6, 0x3d, 0xa6, 0xcf, 0xa1, 0x25, 0x57, 0x51, 0x45, 0xbf,
- 0x4b, 0xd4, 0xec, 0xbd, 0xf2, 0xd2, 0xb4, 0x38, 0x38, 0xc7, 0x7a, 0xc1,
- 0x9d, 0x54, 0x85, 0xa7, 0x6d, 0x89, 0xcf, 0x58, 0x32, 0xe9, 0x66, 0xa0,
- 0x01, 0x87, 0xd4, 0x2e, 0x7f, 0x01, 0xfd, 0x38, 0x0e, 0xfd, 0x6a, 0x0a,
- 0x7c, 0xe5, 0xfb, 0x0e, 0x47, 0x69, 0x79, 0x66, 0x1f, 0x9c, 0x01, 0xf6,
- 0xf1, 0x8c, 0x87, 0x33, 0xd1, 0x67, 0x94, 0xc6, 0x19, 0x89, 0x35, 0xdc,
- 0x07, 0x99, 0x3a, 0x6a, 0x4b, 0x29, 0x8b, 0x7d, 0xa1, 0x77, 0x29, 0xbb,
- 0x4c, 0xd7, 0xc4, 0x74, 0x33, 0x5d, 0x1c, 0x47, 0xba, 0x02, 0x9a, 0xc6,
- 0x8f, 0x92, 0xbe, 0x65, 0x7a, 0xa6, 0xa6, 0x43, 0x1a, 0xb9, 0x1e, 0x69,
- 0x0b, 0xe9, 0xe2, 0x38, 0xd2, 0xb5, 0x99, 0x67, 0xcd, 0x3f, 0x6b, 0x18,
- 0x74, 0x4c, 0x78, 0x36, 0xce, 0xa8, 0x5d, 0x4a, 0x4e, 0xc5, 0x9a, 0x18,
- 0xda, 0x91, 0x82, 0x36, 0x5b, 0xe3, 0x43, 0xa4, 0xd9, 0xc5, 0x39, 0xb6,
- 0xe8, 0xf3, 0x56, 0xb9, 0x49, 0xf2, 0x0e, 0xfd, 0xb9, 0x3e, 0xde, 0x6b,
- 0x8e, 0x4c, 0xea, 0xf9, 0x48, 0xd3, 0x47, 0x31, 0x0f, 0x69, 0x7d, 0x05,
- 0xb2, 0x3a, 0x08, 0x19, 0xcd, 0xca, 0x5f, 0xf8, 0x3b, 0xe5, 0xcf, 0xfc,
- 0x7e, 0xf9, 0x0e, 0xf4, 0xf6, 0xdb, 0x7e, 0x5a, 0x9e, 0xf7, 0x7b, 0xe4,
- 0x39, 0x3f, 0x25, 0xcf, 0x6a, 0xf9, 0x1d, 0x16, 0xe9, 0xa0, 0x4c, 0xa7,
- 0xa5, 0x13, 0xfa, 0xb3, 0x09, 0xba, 0xf9, 0x38, 0xf8, 0x77, 0xb4, 0x4f,
- 0xf2, 0x9b, 0x73, 0x92, 0xb8, 0x1a, 0xbf, 0x2b, 0xf0, 0xeb, 0xca, 0xd9,
- 0x5a, 0x56, 0xec, 0x1c, 0x79, 0x68, 0x4b, 0x51, 0xef, 0xd9, 0x96, 0x09,
- 0xff, 0x91, 0xab, 0x03, 0xd9, 0x15, 0x19, 0x01, 0x8f, 0xd5, 0xc0, 0x4f,
- 0xea, 0x79, 0x07, 0xfb, 0x18, 0xd8, 0xa1, 0x79, 0xaf, 0x06, 0x28, 0xb3,
- 0x69, 0xc8, 0xbd, 0x6d, 0x15, 0xbd, 0x93, 0xc0, 0x8d, 0x36, 0xab, 0x70,
- 0xa4, 0x22, 0xe5, 0x23, 0x75, 0x29, 0x67, 0xe3, 0xf2, 0x90, 0x53, 0x97,
- 0xe1, 0x6c, 0x8b, 0xec, 0x77, 0xc0, 0xfb, 0x9d, 0xbf, 0x6d, 0x85, 0x98,
- 0xfd, 0xb8, 0xff, 0x3b, 0x78, 0x67, 0x9d, 0xc8, 0x51, 0xfd, 0x1e, 0xd4,
- 0x57, 0xfc, 0xb8, 0xe4, 0x93, 0x95, 0x94, 0x2d, 0x5b, 0x54, 0xb0, 0xee,
- 0x78, 0xd8, 0x06, 0x7e, 0x2c, 0x01, 0x27, 0x33, 0x5a, 0x5f, 0x4a, 0xd3,
- 0xeb, 0xdf, 0xce, 0xeb, 0x6a, 0xf4, 0x77, 0x06, 0xe5, 0xac, 0xe6, 0x67,
- 0x7a, 0xcc, 0xca, 0x25, 0x65, 0x6b, 0x8d, 0xe5, 0x21, 0xeb, 0x4e, 0x9f,
- 0xf2, 0x8c, 0x77, 0x9f, 0x74, 0x5e, 0x89, 0x7e, 0x36, 0x9e, 0x79, 0x43,
- 0x6f, 0x94, 0x46, 0xce, 0x43, 0x1a, 0xf9, 0xfc, 0x66, 0x84, 0xc6, 0x27,
- 0x1b, 0xef, 0x47, 0x23, 0xef, 0x15, 0xff, 0x8f, 0x5a, 0x03, 0xda, 0x86,
- 0xe4, 0x8d, 0x99, 0xaf, 0x98, 0x75, 0xf0, 0x7e, 0x8a, 0xf3, 0x7f, 0xab,
- 0x1e, 0xc8, 0x4b, 0xe5, 0x22, 0xeb, 0x2c, 0x44, 0xd6, 0xf9, 0x6e, 0x64,
- 0x9d, 0xef, 0x46, 0xd6, 0xa9, 0x80, 0xa7, 0xb2, 0x51, 0x41, 0x86, 0x4b,
- 0x34, 0x63, 0x72, 0x08, 0x73, 0xbe, 0x2e, 0xb1, 0x1c, 0xf5, 0x3c, 0xc4,
- 0x9b, 0x73, 0xe8, 0x9f, 0x93, 0xb3, 0x33, 0x15, 0x29, 0x1d, 0x89, 0xcb,
- 0x1d, 0xba, 0xdf, 0x26, 0x43, 0x5f, 0xb4, 0x2d, 0x21, 0x7b, 0x92, 0x7c,
- 0x0f, 0xdb, 0x6c, 0xf0, 0x99, 0xe5, 0x6f, 0x5d, 0x19, 0x94, 0xf9, 0xbe,
- 0x60, 0xf6, 0x32, 0x1a, 0x8c, 0x3b, 0xf5, 0xa6, 0xc6, 0xc3, 0x45, 0x9f,
- 0xb8, 0x25, 0xd9, 0x98, 0x2b, 0xfb, 0x86, 0xb3, 0x5d, 0x32, 0xe1, 0x58,
- 0xd9, 0xf1, 0xfe, 0x75, 0xd4, 0x8b, 0xbc, 0x72, 0xdb, 0x80, 0x0d, 0x92,
- 0x56, 0xc4, 0x7c, 0xbd, 0x2f, 0x4b, 0x05, 0xf4, 0x3b, 0x2c, 0x8f, 0x28,
- 0xb7, 0xb3, 0xa9, 0x9e, 0xba, 0x1d, 0xc3, 0x3b, 0x65, 0x78, 0x97, 0x39,
- 0x63, 0x1b, 0x65, 0xe2, 0xf0, 0x35, 0xa6, 0x1c, 0xb6, 0x6f, 0xb6, 0x57,
- 0x96, 0xcf, 0x76, 0xaf, 0x2c, 0x87, 0x38, 0x11, 0xc5, 0x70, 0xee, 0x15,
- 0xf8, 0xe4, 0x52, 0xee, 0xe2, 0xa0, 0x35, 0x0b, 0x9d, 0x5b, 0x67, 0x68,
- 0xb8, 0xc2, 0xd0, 0x00, 0x5a, 0xfb, 0x20, 0x59, 0x5a, 0x97, 0xb4, 0x68,
- 0x35, 0x95, 0xc9, 0xfb, 0xf0, 0x7d, 0x83, 0x6e, 0x0f, 0x74, 0x2e, 0x7c,
- 0x86, 0xf8, 0xfe, 0x66, 0xc4, 0x5e, 0xf4, 0x40, 0x67, 0x93, 0xe0, 0x55,
- 0x88, 0xf5, 0xc4, 0xe0, 0x14, 0xec, 0x03, 0x64, 0x55, 0x63, 0x7b, 0x3b,
- 0xf0, 0xd0, 0x36, 0xd8, 0x9c, 0x30, 0xd8, 0xdc, 0x0e, 0x5c, 0x66, 0xd9,
- 0x31, 0xe5, 0xa4, 0x29, 0xa7, 0x50, 0x86, 0x1d, 0x9f, 0x25, 0x2e, 0x5f,
- 0x77, 0x70, 0xef, 0x51, 0x8d, 0xf7, 0xb4, 0x15, 0x40, 0x61, 0xe2, 0x35,
- 0x71, 0xbb, 0x47, 0xe6, 0x6b, 0x58, 0xaf, 0x81, 0x8d, 0xdc, 0x7b, 0x94,
- 0x1e, 0xd2, 0xb2, 0x5e, 0x14, 0x6c, 0x57, 0x3e, 0x49, 0x7a, 0x1f, 0xc4,
- 0xde, 0x89, 0x3f, 0xa4, 0xfb, 0x2a, 0xd0, 0xca, 0x7d, 0xfc, 0x3c, 0x69,
- 0xe5, 0x7a, 0xcd, 0xf4, 0x7e, 0x58, 0x1c, 0x24, 0xed, 0x27, 0xb1, 0xe7,
- 0x3c, 0x30, 0x4f, 0xac, 0xd1, 0xbe, 0x51, 0xec, 0x79, 0x04, 0x78, 0x78,
- 0x3b, 0xf0, 0x70, 0x37, 0xf0, 0x70, 0x18, 0x78, 0x98, 0x03, 0x16, 0x0e,
- 0x01, 0x0b, 0x07, 0x81, 0x85, 0x59, 0xf0, 0x26, 0x29, 0x73, 0xc0, 0xc6,
- 0x39, 0x60, 0xe4, 0x1c, 0xe6, 0x18, 0x9f, 0x15, 0xeb, 0x4b, 0xd8, 0xc3,
- 0x63, 0x33, 0x99, 0x93, 0x90, 0xa5, 0x54, 0x45, 0x41, 0xfe, 0xb3, 0x43,
- 0x90, 0xed, 0x7e, 0xa9, 0xfa, 0xb6, 0x94, 0x69, 0x53, 0xb7, 0xf7, 0x42,
- 0xd7, 0x20, 0xef, 0x29, 0x31, 0x7f, 0x1b, 0xcc, 0xf3, 0x1f, 0x45, 0xdc,
- 0xbf, 0xa3, 0x2c, 0xa6, 0x45, 0xce, 0x48, 0xc9, 0xeb, 0x75, 0x0a, 0xaa,
- 0x1f, 0xfd, 0x58, 0xce, 0xaa, 0xfb, 0x8f, 0x5c, 0xaf, 0xf6, 0x1e, 0x21,
- 0x5f, 0xa6, 0x81, 0x57, 0x75, 0x99, 0xcc, 0x52, 0xb7, 0xea, 0x72, 0x22,
- 0x9b, 0x19, 0xaa, 0x48, 0x9b, 0x4c, 0x25, 0xa7, 0xb5, 0xad, 0xb5, 0x73,
- 0x87, 0xb5, 0xbd, 0x2a, 0xbb, 0x78, 0xd6, 0x06, 0x54, 0xe9, 0x08, 0xf7,
- 0xdf, 0x8b, 0x5f, 0x1c, 0xb4, 0x70, 0x7e, 0x5b, 0x86, 0x07, 0x1d, 0xf5,
- 0x40, 0x5f, 0x05, 0x08, 0x96, 0x71, 0xce, 0x62, 0xe5, 0xe2, 0x74, 0x6f,
- 0xaa, 0xa8, 0x6c, 0x19, 0xb3, 0x2d, 0x19, 0x87, 0x7c, 0x0f, 0x67, 0xdf,
- 0xa9, 0x4f, 0x25, 0xd9, 0xbe, 0x4e, 0xbe, 0xae, 0x7d, 0x0e, 0xac, 0x5d,
- 0x3d, 0x8a, 0x75, 0xe3, 0x38, 0x03, 0xae, 0xcb, 0x79, 0x50, 0xae, 0xd9,
- 0x28, 0x67, 0x4e, 0x56, 0xc4, 0x87, 0x9e, 0x6c, 0x94, 0xc2, 0xce, 0x16,
- 0xc9, 0x8f, 0xa4, 0x65, 0x7c, 0xc6, 0x07, 0x4e, 0xe1, 0x1c, 0xdd, 0x56,
- 0x29, 0x8d, 0xa6, 0xe5, 0xd1, 0x19, 0xd6, 0x9d, 0xc6, 0xfe, 0x33, 0x87,
- 0xf2, 0xc2, 0xfd, 0xc7, 0xf5, 0xbe, 0xd2, 0xea, 0xb4, 0xec, 0xf7, 0xde,
- 0x30, 0x7a, 0x14, 0x94, 0xef, 0xc7, 0x99, 0x9e, 0xf0, 0x17, 0xb0, 0x7f,
- 0x57, 0xe6, 0x81, 0xff, 0xc5, 0x23, 0xc0, 0x41, 0xb7, 0x03, 0x98, 0x95,
- 0x59, 0xa0, 0x4d, 0x8d, 0xc1, 0xef, 0xab, 0x6a, 0x5e, 0xf7, 0xc8, 0x91,
- 0x19, 0x25, 0xdf, 0xbe, 0x31, 0x8d, 0x32, 0xb0, 0x31, 0x9b, 0x39, 0x3d,
- 0xa6, 0x7a, 0xe4, 0x86, 0xce, 0x14, 0xc6, 0xe5, 0x54, 0xc9, 0xdb, 0x18,
- 0x03, 0x2f, 0x8f, 0xa7, 0x15, 0xfb, 0x2a, 0x29, 0x66, 0x63, 0x38, 0xff,
- 0x0a, 0xfa, 0xbf, 0x8f, 0xf5, 0x7a, 0x64, 0x16, 0xbe, 0xd6, 0xec, 0x4c,
- 0x1e, 0xe3, 0x88, 0x5d, 0x99, 0xe3, 0x4b, 0x0a, 0x18, 0x33, 0x0b, 0xf9,
- 0x1e, 0x85, 0x2f, 0x33, 0x03, 0xd1, 0x69, 0x4d, 0xe3, 0x4c, 0x7b, 0x9d,
- 0x71, 0xe0, 0x41, 0xbe, 0x87, 0xef, 0x9c, 0xd3, 0x95, 0x13, 0x1e, 0xe5,
- 0x30, 0x2d, 0x4f, 0xf9, 0x1c, 0xd7, 0xbb, 0xf0, 0x1c, 0x7c, 0x9f, 0xdf,
- 0xf5, 0xae, 0x44, 0xff, 0x77, 0xe1, 0x07, 0x3b, 0x52, 0xc5, 0xb9, 0x95,
- 0xc1, 0xcb, 0x7c, 0x2a, 0x28, 0x8f, 0xcf, 0x66, 0x16, 0xde, 0x50, 0x7c,
- 0x77, 0x2b, 0xf3, 0xea, 0x5a, 0x91, 0x4e, 0xf2, 0x33, 0x0b, 0x5e, 0xba,
- 0x8e, 0x52, 0xdb, 0x8d, 0xef, 0x47, 0x3d, 0x72, 0x41, 0x9f, 0x2d, 0xf3,
- 0x03, 0x51, 0x3d, 0xa2, 0x3d, 0x0c, 0xf5, 0x28, 0x93, 0x5a, 0x52, 0x0a,
- 0xed, 0xb6, 0x1c, 0xd6, 0x65, 0x0b, 0xb4, 0x66, 0x52, 0xdc, 0xdf, 0x44,
- 0xad, 0x5f, 0x9e, 0xf2, 0xd8, 0x1f, 0x7c, 0x9e, 0x6e, 0x37, 0xfd, 0x4f,
- 0x83, 0x87, 0xf4, 0xdf, 0xfa, 0x41, 0x73, 0xa0, 0x5b, 0xf3, 0xd3, 0x49,
- 0xdd, 0x36, 0xe5, 0x05, 0x7e, 0x9a, 0x82, 0x2f, 0x37, 0x07, 0x5f, 0xae,
- 0xa8, 0xf5, 0xcc, 0xc9, 0xc3, 0xd7, 0x87, 0x9e, 0x04, 0x3a, 0x56, 0xad,
- 0x91, 0x96, 0xbb, 0x40, 0x5f, 0xa6, 0x02, 0x62, 0x0e, 0xab, 0x1c, 0xce,
- 0x7d, 0x50, 0x2a, 0xf4, 0xf7, 0xce, 0xc6, 0x9e, 0x92, 0xb1, 0x2a, 0xed,
- 0x11, 0x7e, 0x9e, 0xeb, 0x30, 0xbe, 0xc8, 0x6b, 0x5b, 0xd1, 0x0d, 0x39,
- 0x80, 0x1d, 0xc9, 0x6e, 0x32, 0x7e, 0xce, 0x13, 0x38, 0xcf, 0x33, 0x38,
- 0xf7, 0x9a, 0xec, 0x3d, 0xf6, 0x0a, 0x65, 0xba, 0xbf, 0x2a, 0x99, 0xfe,
- 0x29, 0xd9, 0xe1, 0xcc, 0x43, 0x1f, 0xf3, 0xa3, 0xf5, 0x5b, 0x54, 0x8e,
- 0x63, 0x0e, 0x62, 0x0c, 0x9e, 0xd5, 0x57, 0xe4, 0x21, 0x9f, 0x75, 0x0f,
- 0x81, 0x9f, 0xd0, 0x95, 0xc1, 0x27, 0x8c, 0x1e, 0x60, 0x3e, 0x3b, 0x9c,
- 0xef, 0x15, 0x33, 0x1f, 0xfb, 0xb1, 0x0f, 0xc7, 0x2c, 0xcf, 0xbb, 0x8b,
- 0xb6, 0x08, 0x78, 0xb4, 0x4b, 0xd5, 0x6f, 0x89, 0xa3, 0xfd, 0xc4, 0x20,
- 0xdf, 0x31, 0x0f, 0x6c, 0x91, 0xe3, 0x9e, 0x41, 0x5f, 0xf8, 0x7a, 0xde,
- 0x7a, 0x29, 0x74, 0x85, 0xf4, 0x52, 0x06, 0xe8, 0x27, 0x68, 0x1b, 0xbc,
- 0x39, 0xe0, 0xfd, 0x1f, 0xc6, 0x02, 0x99, 0x3c, 0x80, 0x32, 0xf5, 0xef,
- 0x80, 0x14, 0xbd, 0x0c, 0xf6, 0x09, 0x1d, 0xf3, 0x3b, 0xac, 0x60, 0x8f,
- 0xe0, 0xff, 0xc8, 0x39, 0xf0, 0x41, 0x2a, 0x01, 0x6f, 0xc8, 0x17, 0xf2,
- 0xa4, 0x03, 0xb2, 0x0f, 0xb9, 0x87, 0xdc, 0x96, 0x34, 0x0f, 0xfe, 0xbd,
- 0x33, 0xf0, 0x8b, 0x33, 0x95, 0x3c, 0xe3, 0xb9, 0x4e, 0xe2, 0x26, 0x30,
- 0xcc, 0x87, 0x70, 0x60, 0xee, 0x25, 0xb5, 0x9e, 0xf4, 0xa6, 0x97, 0x62,
- 0x7d, 0x2c, 0xf7, 0x2f, 0x41, 0x86, 0xab, 0x38, 0x9f, 0xc2, 0xce, 0x5e,
- 0x83, 0x5b, 0xcf, 0xc6, 0x28, 0xaf, 0x55, 0x60, 0x4c, 0xc9, 0xdb, 0xe1,
- 0xdc, 0x4d, 0xbe, 0x39, 0x8e, 0x3c, 0xe7, 0x45, 0xb1, 0x03, 0xb6, 0xcf,
- 0xa5, 0x1c, 0x26, 0x21, 0x07, 0x36, 0x6c, 0x68, 0x0a, 0x67, 0xfe, 0x6f,
- 0x9d, 0xc1, 0x5e, 0xf8, 0x6e, 0xcb, 0x9c, 0x83, 0x35, 0xbd, 0xc5, 0x8d,
- 0x41, 0x1d, 0xdf, 0xb7, 0xf0, 0x8c, 0x0e, 0xaf, 0xa4, 0x9d, 0xe7, 0xdb,
- 0x7c, 0xa6, 0x27, 0xb0, 0x17, 0xd6, 0xe3, 0x59, 0x3d, 0x2e, 0x7b, 0x89,
- 0x9b, 0x83, 0xdb, 0x52, 0x2f, 0xa2, 0x7f, 0x11, 0x36, 0xa1, 0x62, 0xb3,
- 0xed, 0x6d, 0x6b, 0x79, 0x8c, 0xa2, 0x5f, 0x0a, 0x1f, 0x78, 0xc9, 0xfa,
- 0x92, 0xff, 0x92, 0x55, 0xa8, 0xbe, 0x6d, 0x15, 0x21, 0x27, 0x55, 0x8f,
- 0xf1, 0x0b, 0xf5, 0xc7, 0xc1, 0xda, 0x99, 0xd4, 0x5b, 0xaa, 0x37, 0x3d,
- 0x0f, 0x2c, 0xb8, 0x1f, 0x3a, 0x5d, 0xb4, 0x17, 0xa4, 0xec, 0xd7, 0xa4,
- 0x74, 0x6c, 0x07, 0xf4, 0x2d, 0x1d, 0xa1, 0x8b, 0x78, 0x56, 0xa1, 0x1f,
- 0x6e, 0xed, 0xf2, 0xa4, 0xd2, 0x92, 0x23, 0xae, 0x6d, 0x83, 0xec, 0xa0,
- 0xae, 0xb6, 0x2c, 0x7f, 0xb7, 0xad, 0xa2, 0x15, 0xb1, 0xee, 0xe0, 0x4a,
- 0x7a, 0xab, 0x72, 0x71, 0x7a, 0x77, 0x35, 0xe8, 0x25, 0x66, 0x00, 0xff,
- 0x3d, 0xe0, 0xbf, 0x07, 0xfc, 0xf7, 0x80, 0xff, 0x1e, 0xf0, 0xdf, 0x83,
- 0x6d, 0xf0, 0x60, 0x03, 0x3c, 0xd8, 0x00, 0x0f, 0x36, 0xc0, 0x83, 0x0d,
- 0xf0, 0x0a, 0x38, 0x27, 0xe2, 0x3c, 0x6d, 0xc8, 0x3d, 0x0d, 0xbb, 0x19,
- 0xf8, 0x39, 0x57, 0x1a, 0xdf, 0x01, 0xfa, 0xe7, 0x6c, 0x91, 0xf1, 0xfe,
- 0x2b, 0xb0, 0xb7, 0x56, 0x3c, 0xdb, 0xf0, 0xc4, 0x1a, 0xfd, 0x9f, 0x35,
- 0x7a, 0xf2, 0x55, 0xd0, 0xa5, 0x50, 0xfe, 0x05, 0xc8, 0x61, 0x0b, 0xe8,
- 0xf9, 0x94, 0xf1, 0x31, 0xbe, 0x61, 0x07, 0x72, 0xd8, 0x86, 0xba, 0xcf,
- 0xa0, 0xae, 0x0d, 0x7d, 0xf6, 0xa3, 0x0f, 0x7d, 0x94, 0x0e, 0x53, 0x17,
- 0xed, 0x47, 0x5f, 0xe5, 0x0b, 0x58, 0x2b, 0x83, 0x7e, 0x1d, 0x98, 0xbb,
- 0x07, 0x7d, 0x6e, 0x46, 0x9f, 0xab, 0x50, 0xa6, 0x6f, 0xdb, 0x8d, 0xf2,
- 0xa7, 0x9b, 0xc6, 0x5c, 0x83, 0xba, 0xcf, 0x36, 0xd5, 0x9d, 0x45, 0x1d,
- 0x62, 0x62, 0xe7, 0x45, 0x33, 0xae, 0x82, 0x72, 0x57, 0x53, 0x9f, 0x57,
- 0x50, 0x37, 0x84, 0xba, 0xbf, 0xc2, 0x13, 0xb1, 0xb0, 0x43, 0x9a, 0xc2,
- 0x36, 0xfa, 0xa9, 0x69, 0xd4, 0xc7, 0x8d, 0xaf, 0xf9, 0x24, 0x7d, 0x2f,
- 0xd8, 0xdc, 0x3f, 0xb6, 0x03, 0xdf, 0x0c, 0xde, 0xab, 0x96, 0xc3, 0xb0,
- 0xfc, 0xcd, 0xa6, 0x32, 0xfb, 0x7e, 0xbf, 0xa9, 0xae, 0x6d, 0xd3, 0xca,
- 0xf2, 0x4f, 0xe3, 0xab, 0xc7, 0xdc, 0xdb, 0xd4, 0xe7, 0xeb, 0x9d, 0x2b,
- 0xcb, 0xbb, 0x5b, 0x56, 0x8f, 0xd9, 0xbe, 0x71, 0x65, 0xdd, 0xad, 0x9b,
- 0x57, 0x96, 0xe9, 0x03, 0x26, 0x11, 0xc3, 0x84, 0xfd, 0x77, 0x7e, 0x22,
- 0x68, 0x27, 0x7f, 0x9b, 0x65, 0x49, 0x2b, 0x23, 0xca, 0x0a, 0xe7, 0xb0,
- 0x64, 0x41, 0x9f, 0x1c, 0x95, 0x7b, 0xc9, 0x2a, 0x42, 0xa6, 0x0a, 0x7e,
- 0x38, 0x1f, 0x75, 0xb6, 0x39, 0x4f, 0x10, 0xe6, 0x07, 0xe8, 0x6f, 0xb5,
- 0x43, 0x6e, 0xee, 0xa2, 0x4d, 0x3a, 0x54, 0x91, 0x65, 0xfd, 0xdc, 0xaa,
- 0xce, 0xa7, 0x9f, 0xf7, 0x19, 0x8c, 0x3a, 0x07, 0x3a, 0xeb, 0x32, 0x92,
- 0x5d, 0x47, 0x1b, 0x63, 0xb0, 0x8b, 0xb8, 0x53, 0xaf, 0xc7, 0xb6, 0xd7,
- 0x65, 0x5f, 0xf6, 0xdd, 0xba, 0x68, 0xcc, 0xbb, 0x57, 0xe3, 0x4e, 0x5a,
- 0x75, 0xe3, 0x8c, 0x1c, 0xc4, 0x12, 0x88, 0xed, 0x93, 0xb4, 0x49, 0xc7,
- 0xe9, 0x9f, 0x1c, 0x0c, 0x30, 0x95, 0xb8, 0x83, 0xb2, 0x3f, 0x85, 0x39,
- 0xb9, 0x3e, 0x9e, 0x55, 0xe2, 0xb8, 0xad, 0x6d, 0x4a, 0xc9, 0xe1, 0xbc,
- 0x6b, 0x61, 0xe3, 0xbf, 0xd8, 0xf4, 0x0b, 0x6d, 0xf7, 0x24, 0xec, 0x1b,
- 0xdb, 0xe8, 0x2b, 0x9c, 0xa4, 0x5f, 0x12, 0xc1, 0xaa, 0x9b, 0x62, 0xe2,
- 0x2e, 0x63, 0x66, 0xb0, 0xaf, 0x2d, 0xf4, 0xfb, 0x2f, 0x61, 0xaf, 0x6b,
- 0x63, 0x51, 0xaf, 0xba, 0xb8, 0x6e, 0xef, 0x69, 0xe8, 0x76, 0x28, 0x7b,
- 0x6b, 0xe5, 0x03, 0x5e, 0xd5, 0x67, 0xf1, 0xac, 0x9f, 0x39, 0x5c, 0x81,
- 0x2e, 0x2d, 0xea, 0xd8, 0x37, 0x3c, 0x17, 0xfa, 0x38, 0x99, 0xe3, 0x73,
- 0x90, 0xed, 0xbd, 0x3a, 0x26, 0x60, 0x3c, 0x50, 0x97, 0x5d, 0xd9, 0x4f,
- 0x25, 0xc9, 0x87, 0xbc, 0xfa, 0x71, 0x9c, 0x3e, 0xc3, 0xa2, 0x47, 0x9e,
- 0x65, 0xd1, 0x9e, 0x05, 0x26, 0xfc, 0xab, 0x14, 0x93, 0xac, 0x7b, 0xab,
- 0x3e, 0x0f, 0xbf, 0x4a, 0xfb, 0x47, 0xda, 0xde, 0xd3, 0xbf, 0x83, 0x5d,
- 0xf7, 0xc9, 0xd3, 0x25, 0xf0, 0x39, 0xf4, 0x01, 0x7e, 0x40, 0x1f, 0x55,
- 0x56, 0xfa, 0xd2, 0x22, 0x0f, 0xd5, 0xfe, 0x01, 0x36, 0x47, 0x05, 0xbe,
- 0x0a, 0xe3, 0x65, 0x97, 0xf5, 0x37, 0xc6, 0xe9, 0xcb, 0x05, 0xb6, 0x3e,
- 0x86, 0xf5, 0x10, 0x5f, 0xd7, 0xfe, 0xd3, 0x2a, 0x79, 0x3d, 0xf4, 0xb3,
- 0xb0, 0x7f, 0xf8, 0x50, 0x3e, 0xdb, 0x58, 0x97, 0x30, 0xfe, 0x77, 0xbb,
- 0xf1, 0xb7, 0x1d, 0xe3, 0x6f, 0x6b, 0x3a, 0x12, 0x4e, 0x2e, 0xf4, 0x0b,
- 0x78, 0x66, 0xe9, 0x83, 0x6a, 0x3b, 0xfd, 0x82, 0x0e, 0x59, 0xdb, 0x2f,
- 0x08, 0x69, 0x3a, 0x85, 0x7d, 0xd2, 0xcf, 0xd3, 0x79, 0xa0, 0xce, 0x20,
- 0xf7, 0x44, 0x1a, 0x42, 0xfb, 0xa8, 0xed, 0xf0, 0x21, 0x98, 0x3c, 0xe6,
- 0x24, 0x41, 0xeb, 0x6e, 0x29, 0x4c, 0x9f, 0x32, 0xf6, 0x96, 0x71, 0x04,
- 0x7d, 0xf8, 0x40, 0x66, 0x0b, 0xd9, 0x0e, 0xcb, 0xcc, 0xd3, 0x05, 0x0b,
- 0x19, 0xc9, 0x51, 0x71, 0x2d, 0xfa, 0x31, 0xa1, 0x4f, 0xb3, 0x60, 0x7c,
- 0x9a, 0x33, 0xb2, 0xcf, 0x0b, 0xe2, 0x86, 0x91, 0xda, 0x12, 0xea, 0x34,
- 0xed, 0x29, 0xfa, 0x96, 0x0a, 0x3e, 0x77, 0xfe, 0xde, 0x0c, 0x02, 0x90,
- 0x60, 0x2f, 0x5b, 0xb1, 0x97, 0x6a, 0x63, 0x2f, 0x6d, 0x4b, 0xcd, 0x3e,
- 0x0e, 0xc7, 0x4e, 0xae, 0x1a, 0x2b, 0xd8, 0xc7, 0xdc, 0x79, 0xda, 0xb8,
- 0x47, 0xfa, 0x0d, 0x8e, 0xd9, 0x63, 0x78, 0x4e, 0x8f, 0x63, 0x8f, 0x49,
- 0xab, 0xa4, 0x7d, 0x2d, 0xfa, 0x2d, 0x88, 0xb3, 0x6b, 0x2f, 0xe1, 0x49,
- 0xfd, 0xd0, 0xf3, 0x60, 0x4f, 0xed, 0x7a, 0x4f, 0x53, 0xde, 0x2b, 0x7a,
- 0x1f, 0xf3, 0xb5, 0xbf, 0x91, 0xf2, 0xb1, 0x1f, 0xc0, 0xee, 0x45, 0x73,
- 0x73, 0xcc, 0x6b, 0x92, 0x1f, 0x95, 0x08, 0x7e, 0x72, 0xaf, 0xcc, 0xbb,
- 0xbd, 0x1c, 0x0f, 0xe2, 0x83, 0x69, 0x9c, 0xb1, 0x15, 0xb4, 0xeb, 0xf5,
- 0x43, 0xbe, 0xb6, 0x44, 0xe8, 0xa9, 0xc3, 0xe7, 0x4c, 0x81, 0x86, 0xe8,
- 0x98, 0x03, 0x32, 0xec, 0xf1, 0x3c, 0x7a, 0x53, 0x7b, 0xc5, 0x75, 0x4a,
- 0x12, 0xfa, 0x19, 0x5c, 0x9f, 0x3a, 0x5f, 0x84, 0xe3, 0xcb, 0x5c, 0x6a,
- 0xc8, 0xbb, 0x90, 0x6f, 0xed, 0x4b, 0xcd, 0x32, 0x30, 0x89, 0x58, 0xab,
- 0xec, 0x91, 0x4f, 0xa1, 0x6c, 0x86, 0x6b, 0xbf, 0x6a, 0x71, 0x3f, 0x13,
- 0x3a, 0x7f, 0xf8, 0x4f, 0x0d, 0x19, 0x1d, 0x07, 0x76, 0x04, 0x32, 0xf7,
- 0xf7, 0x86, 0x37, 0xa1, 0x6c, 0xb6, 0x9b, 0x73, 0x66, 0x2c, 0x48, 0xdd,
- 0x09, 0xe5, 0x60, 0x9b, 0x73, 0xa7, 0xe6, 0x05, 0xdb, 0xb4, 0xcf, 0xad,
- 0xcf, 0x72, 0xac, 0x71, 0x96, 0x1b, 0x9a, 0xe4, 0xf2, 0xdd, 0x8d, 0x81,
- 0x1e, 0x52, 0xdf, 0xa0, 0xb7, 0xe0, 0xd7, 0xb3, 0x2b, 0xf4, 0xbb, 0xff,
- 0x3c, 0x39, 0xd9, 0x76, 0x89, 0xcd, 0x7e, 0x0f, 0xbc, 0xbc, 0x06, 0xb1,
- 0x8a, 0x88, 0x3d, 0x43, 0x1c, 0xa2, 0xbf, 0xb1, 0xec, 0xef, 0xce, 0xcb,
- 0x5a, 0xbe, 0xee, 0xc5, 0x7c, 0x8d, 0x4f, 0x5e, 0xa2, 0xaf, 0x31, 0xdc,
- 0x22, 0xad, 0xc4, 0xa2, 0x33, 0xf0, 0x6d, 0x2d, 0x69, 0x71, 0xbf, 0x01,
- 0x1b, 0x76, 0xda, 0x5e, 0xe7, 0x86, 0x98, 0xd0, 0x2e, 0x9b, 0x66, 0xb7,
- 0x68, 0x5c, 0x70, 0x66, 0x96, 0x71, 0x61, 0x1c, 0xbc, 0x1f, 0x09, 0xf2,
- 0xbc, 0xc9, 0x4d, 0x72, 0xa9, 0xf1, 0xf5, 0xb2, 0xdf, 0x3f, 0xd6, 0xf0,
- 0xfb, 0xaf, 0x6c, 0xe2, 0xe3, 0x5a, 0xb8, 0x78, 0x1a, 0x7c, 0xcb, 0x21,
- 0xfe, 0x65, 0x5c, 0x3b, 0x8c, 0x78, 0x98, 0xb1, 0x58, 0x1e, 0x31, 0x71,
- 0xe6, 0xb4, 0xc8, 0x6e, 0xc4, 0xc8, 0x99, 0x1f, 0x31, 0x7f, 0xf5, 0xbc,
- 0x9f, 0x99, 0x13, 0xb9, 0x1d, 0x7c, 0x1d, 0x04, 0x6e, 0x66, 0x81, 0xa3,
- 0x3b, 0xc1, 0xdf, 0x7e, 0x8d, 0x9d, 0xf7, 0x1f, 0x11, 0xeb, 0x0e, 0x9d,
- 0xab, 0xa6, 0x3e, 0x27, 0x61, 0x47, 0xeb, 0xf5, 0xfd, 0xd9, 0x5e, 0xc4,
- 0xf5, 0x69, 0xb9, 0xd5, 0x66, 0x1c, 0x6b, 0xd9, 0x5b, 0x07, 0xe6, 0x63,
- 0x51, 0x9f, 0xb4, 0x70, 0x51, 0x3b, 0xb0, 0x9a, 0xf7, 0x45, 0x6d, 0x0b,
- 0x0e, 0xc7, 0x2e, 0xc4, 0xfb, 0x3b, 0x1a, 0xbc, 0x6f, 0x69, 0x95, 0xd6,
- 0xdb, 0x75, 0x1e, 0x61, 0xeb, 0xc0, 0x7e, 0xe2, 0x55, 0x16, 0x76, 0x1d,
- 0xf6, 0xb7, 0x2e, 0xb7, 0x65, 0xdf, 0xae, 0xbf, 0xe8, 0x6e, 0x94, 0xd2,
- 0xce, 0xfb, 0x0c, 0x66, 0x2f, 0x7d, 0xad, 0xe0, 0x56, 0xa0, 0x1f, 0x41,
- 0xce, 0x70, 0xef, 0x74, 0x02, 0x96, 0x80, 0x7f, 0x9d, 0x32, 0x3f, 0xf4,
- 0x16, 0xce, 0x70, 0xc7, 0x49, 0x26, 0x9c, 0x14, 0x70, 0x78, 0x3e, 0xd9,
- 0xae, 0xf3, 0xc5, 0x9f, 0x70, 0x59, 0xef, 0xe0, 0x4c, 0x47, 0x65, 0x1e,
- 0xfe, 0x43, 0x75, 0x08, 0x34, 0xee, 0xec, 0x42, 0x7f, 0xea, 0x1d, 0x79,
- 0x3e, 0x0a, 0xdb, 0x4b, 0x9e, 0x26, 0xd1, 0x7f, 0x0f, 0xfa, 0x74, 0xe2,
- 0x79, 0x5f, 0x6c, 0xde, 0x61, 0xec, 0xfc, 0x79, 0x94, 0x39, 0x47, 0xd4,
- 0x76, 0x7e, 0x2e, 0x2e, 0x7a, 0x4e, 0x8e, 0xe9, 0xd2, 0xfa, 0xbf, 0xbc,
- 0x16, 0xd7, 0x61, 0xdb, 0xcf, 0xea, 0xd7, 0x0f, 0x0c, 0x45, 0xd6, 0xeb,
- 0x88, 0xac, 0x37, 0x14, 0x59, 0x8f, 0x74, 0x76, 0x46, 0xe8, 0xec, 0xc4,
- 0xf8, 0x22, 0xd6, 0x26, 0x3f, 0xa2, 0x6b, 0x3e, 0x18, 0x59, 0x33, 0xdc,
- 0x5f, 0x57, 0x64, 0xdc, 0xbb, 0x58, 0x8f, 0x75, 0xc9, 0x48, 0x1d, 0x69,
- 0xd8, 0x8c, 0x3a, 0x96, 0x3b, 0x23, 0x74, 0x91, 0xd6, 0x0d, 0xa8, 0xd7,
- 0xfe, 0x13, 0xf8, 0xdc, 0x0a, 0xbb, 0xa5, 0x60, 0x3b, 0x5a, 0xe0, 0x5f,
- 0x35, 0xef, 0xf5, 0x51, 0xac, 0x1b, 0xce, 0x97, 0xc4, 0x1c, 0xec, 0xcf,
- 0xbe, 0x31, 0x33, 0x9e, 0xf5, 0x6c, 0xff, 0xf3, 0xfa, 0x9f, 0x6a, 0xbe,
- 0x6d, 0x06, 0xed, 0x3a, 0xef, 0x22, 0x73, 0x9d, 0x36, 0xce, 0x93, 0xf1,
- 0xb1, 0x25, 0x57, 0xbb, 0xca, 0xea, 0x1d, 0xe0, 0xd9, 0x6f, 0x34, 0x58,
- 0xda, 0x6a, 0x15, 0x8e, 0x30, 0x5f, 0xd0, 0x66, 0x62, 0x3e, 0xc4, 0x1e,
- 0xda, 0xc6, 0xd8, 0xa6, 0x9d, 0x36, 0x86, 0x7e, 0x0b, 0xed, 0xe7, 0x69,
- 0xf3, 0x8e, 0x27, 0x64, 0xf8, 0x81, 0x6a, 0xa7, 0xbc, 0xa8, 0x79, 0xea,
- 0xc8, 0xd9, 0x06, 0x4f, 0xe3, 0xe6, 0xbb, 0xcc, 0x01, 0xf3, 0xcd, 0xa3,
- 0x0f, 0x7e, 0x11, 0xde, 0x6b, 0x79, 0xd0, 0x90, 0x96, 0xde, 0x01, 0xc6,
- 0x6e, 0x15, 0x3c, 0x99, 0xa7, 0xb0, 0xf0, 0x0c, 0xf2, 0x17, 0xbd, 0x03,
- 0xb0, 0x4b, 0xc0, 0xa1, 0xde, 0x81, 0x73, 0x3a, 0x9e, 0xab, 0xfa, 0x8e,
- 0x75, 0x9b, 0x17, 0xe4, 0x88, 0xce, 0xba, 0x17, 0xca, 0x11, 0xdd, 0xb3,
- 0x8e, 0x79, 0x8d, 0x30, 0x47, 0x74, 0x56, 0x74, 0x8e, 0xe8, 0xf8, 0x45,
- 0x72, 0x44, 0xf9, 0x4b, 0xcf, 0x11, 0x71, 0x7e, 0x5b, 0xee, 0x1c, 0x74,
- 0xd4, 0xaf, 0x9a, 0x1c, 0xd1, 0x1b, 0x12, 0xe4, 0x88, 0x5e, 0x94, 0xb5,
- 0x73, 0x44, 0x87, 0x9a, 0x72, 0x44, 0x9b, 0x75, 0x8e, 0x88, 0xf3, 0x04,
- 0x39, 0x22, 0x96, 0x4b, 0x03, 0x43, 0x91, 0x5c, 0x07, 0xf0, 0xd7, 0xbb,
- 0x01, 0x7c, 0x73, 0xac, 0x51, 0x2f, 0xc4, 0x34, 0x62, 0xff, 0x15, 0x0d,
- 0xfb, 0xb5, 0x8c, 0x6f, 0x96, 0x96, 0xb9, 0x8b, 0xe1, 0xdb, 0x68, 0xe0,
- 0x97, 0xac, 0xc0, 0xb6, 0xc9, 0x86, 0xef, 0xe2, 0xad, 0x63, 0x0c, 0x3d,
- 0x51, 0x5b, 0x9e, 0x77, 0x02, 0xbc, 0x1e, 0x6b, 0xe4, 0x49, 0xce, 0xe7,
- 0x1f, 0x25, 0xe5, 0xc0, 0x9a, 0xdf, 0xbd, 0x52, 0xf9, 0xd5, 0xdf, 0xbd,
- 0x2c, 0x49, 0x82, 0xce, 0xd2, 0x40, 0x49, 0xc7, 0x5d, 0xf3, 0xde, 0xaf,
- 0xc8, 0xd2, 0xdd, 0x0e, 0xf0, 0x27, 0xcc, 0x9f, 0xf0, 0x7c, 0x97, 0x6d,
- 0x4a, 0x41, 0x7d, 0x7c, 0x39, 0x94, 0x07, 0x74, 0x0e, 0xe5, 0xc5, 0x75,
- 0xd1, 0x1c, 0xca, 0x59, 0xb9, 0x70, 0x0e, 0xe5, 0x81, 0x35, 0x72, 0x28,
- 0x2f, 0xcb, 0x72, 0x0e, 0xe5, 0x65, 0x09, 0x73, 0x28, 0x31, 0x59, 0xda,
- 0x1c, 0x48, 0xe3, 0x03, 0xfe, 0x12, 0x7e, 0x67, 0xf0, 0x0b, 0x72, 0x2a,
- 0x67, 0x1b, 0xf4, 0xaf, 0x95, 0x53, 0x79, 0x7d, 0xdd, 0x07, 0xc9, 0xa9,
- 0x04, 0x36, 0x20, 0xcc, 0xa9, 0xe0, 0xe7, 0xc0, 0xe6, 0xa8, 0x68, 0x4e,
- 0xe5, 0x27, 0xd4, 0x07, 0xd4, 0xb1, 0xcc, 0x7a, 0xe8, 0x05, 0xec, 0x52,
- 0x5e, 0xe7, 0x38, 0x3e, 0x67, 0x78, 0x38, 0x87, 0x3d, 0xa7, 0x71, 0x16,
- 0xe4, 0x63, 0xaf, 0xf6, 0x2d, 0xf3, 0x76, 0xca, 0x2a, 0xf4, 0xc1, 0x9a,
- 0x4d, 0xf3, 0xbb, 0xb8, 0x6d, 0xed, 0xf5, 0x29, 0xe3, 0x09, 0xab, 0x8c,
- 0xbd, 0x0c, 0x4f, 0xcf, 0xc9, 0x5e, 0x3f, 0xf4, 0xa9, 0x06, 0x1a, 0x73,
- 0x50, 0x37, 0xe7, 0x81, 0xb3, 0xc0, 0x89, 0x4b, 0xb0, 0x51, 0xa7, 0x40,
- 0x73, 0x74, 0x1f, 0x88, 0x89, 0x07, 0x51, 0xa7, 0xcf, 0x9c, 0xbe, 0x65,
- 0x48, 0x4b, 0x9a, 0x7a, 0x7e, 0x09, 0xf3, 0xb1, 0xee, 0x94, 0x8e, 0xc7,
- 0xca, 0x83, 0xdc, 0x2b, 0x6d, 0xdd, 0x22, 0xe8, 0x43, 0x5d, 0x95, 0x31,
- 0x20, 0xed, 0x5e, 0x18, 0xa3, 0xb5, 0xeb, 0x18, 0xad, 0x4b, 0xf3, 0x83,
- 0xbc, 0xbe, 0x35, 0x41, 0xac, 0xec, 0x72, 0xb9, 0x87, 0x33, 0x06, 0xeb,
- 0x58, 0x0e, 0x62, 0xc1, 0xbc, 0xe2, 0xfb, 0xef, 0xe1, 0x5c, 0x99, 0xa7,
- 0x09, 0xcf, 0xef, 0x2b, 0x66, 0xdf, 0x43, 0x52, 0xe9, 0x92, 0xc4, 0x66,
- 0xd0, 0x53, 0x9a, 0xa1, 0xdf, 0xfd, 0x69, 0x1d, 0x83, 0x24, 0xdd, 0xf3,
- 0xeb, 0xed, 0x1d, 0x97, 0xa1, 0xb7, 0x23, 0x17, 0xd4, 0xdb, 0xaf, 0x25,
- 0xa2, 0x7a, 0x7b, 0xc7, 0x65, 0xe8, 0xed, 0xbe, 0xcb, 0xd2, 0x5b, 0xee,
- 0x8d, 0x98, 0x14, 0xe6, 0xc4, 0x56, 0xfb, 0x59, 0xe1, 0xba, 0xe3, 0x58,
- 0x33, 0x7f, 0x9e, 0x35, 0xc7, 0xce, 0x9b, 0x5b, 0x6d, 0xf6, 0xb1, 0x2e,
- 0xe5, 0xbc, 0x19, 0x5b, 0xd1, 0xde, 0xb6, 0x1b, 0xbb, 0x74, 0x9f, 0x89,
- 0xe7, 0xc3, 0xb8, 0x3e, 0xaa, 0x3f, 0x94, 0x0b, 0xca, 0xc2, 0x77, 0xc0,
- 0x2f, 0xca, 0x43, 0xa8, 0x73, 0xdd, 0x4d, 0x32, 0xb8, 0x88, 0x78, 0xbf,
- 0xdb, 0xc8, 0x20, 0xcf, 0xba, 0x4f, 0x7f, 0x67, 0xaa, 0x7a, 0x4f, 0x05,
- 0x71, 0xbe, 0x8b, 0x67, 0x35, 0xd4, 0x35, 0xf0, 0x24, 0x19, 0xb6, 0x91,
- 0x8f, 0x2e, 0x7c, 0x9e, 0x1d, 0xf0, 0xd7, 0xc0, 0x23, 0x5d, 0xbf, 0x32,
- 0x27, 0x7c, 0x61, 0x3c, 0x93, 0x4a, 0x1c, 0x7d, 0x4f, 0x0c, 0x42, 0xc7,
- 0x07, 0x89, 0x51, 0x35, 0xc4, 0x3d, 0x94, 0x43, 0xca, 0xe6, 0xb6, 0xfe,
- 0x5d, 0x8a, 0x3e, 0xd5, 0x13, 0x88, 0x83, 0x29, 0xaf, 0x69, 0xd9, 0xe5,
- 0x6f, 0x3b, 0x7d, 0x56, 0x71, 0x8d, 0x7a, 0xbd, 0xc4, 0x58, 0xd1, 0x11,
- 0xb5, 0x75, 0xe0, 0xbf, 0x13, 0xb4, 0x4b, 0x57, 0xb8, 0x31, 0x23, 0x6b,
- 0x79, 0xbc, 0x53, 0x6e, 0x7f, 0x08, 0x7b, 0xcf, 0xef, 0xfd, 0xaf, 0xa1,
- 0x3e, 0x05, 0x9d, 0xa7, 0x7d, 0x67, 0x3c, 0x72, 0x93, 0xe9, 0xd7, 0xad,
- 0xbf, 0x57, 0x16, 0xb2, 0x37, 0x98, 0x6f, 0x57, 0xb4, 0x3f, 0x19, 0xda,
- 0xec, 0x15, 0xe7, 0xcc, 0xfb, 0x12, 0x45, 0x1d, 0xcf, 0x70, 0xbc, 0x96,
- 0x49, 0xc4, 0x20, 0x76, 0x24, 0x97, 0x9e, 0x30, 0xb1, 0x1b, 0x75, 0xac,
- 0x1d, 0x67, 0xe8, 0x9b, 0x58, 0x85, 0xf1, 0xeb, 0xca, 0x7b, 0x12, 0x6b,
- 0xcb, 0xc0, 0x96, 0x0f, 0x20, 0x03, 0xcd, 0xe7, 0x97, 0x80, 0xee, 0x87,
- 0xe7, 0x17, 0xfa, 0x31, 0x73, 0x66, 0xdf, 0xdd, 0xc1, 0x19, 0xfe, 0xbf,
- 0xd8, 0xa7, 0x15, 0xd9, 0x67, 0x88, 0x47, 0x0f, 0x98, 0x7d, 0xde, 0xd4,
- 0x84, 0x47, 0x23, 0x4d, 0x3a, 0xfb, 0x71, 0xe2, 0xd1, 0x9f, 0xac, 0xff,
- 0xf8, 0xf1, 0x88, 0xfb, 0xea, 0x5e, 0x13, 0x87, 0x82, 0x7d, 0x3c, 0x22,
- 0x2a, 0xf7, 0x51, 0xc6, 0x7b, 0x1f, 0xe4, 0x7c, 0xa2, 0x38, 0xc2, 0x33,
- 0xe9, 0xd0, 0x3e, 0x6c, 0xa0, 0x7b, 0xb0, 0xe5, 0xd5, 0xb8, 0xbc, 0x7e,
- 0x57, 0x42, 0xfe, 0xf7, 0x46, 0x7e, 0x0f, 0xb3, 0x4d, 0x4e, 0x8b, 0xe5,
- 0xd7, 0xd6, 0x07, 0x76, 0xe8, 0xb5, 0x4d, 0x81, 0xdd, 0xe1, 0x98, 0x50,
- 0x9f, 0x1d, 0xb4, 0xb3, 0xad, 0x5b, 0x96, 0x3a, 0x2f, 0x27, 0x06, 0xdc,
- 0xe6, 0xbc, 0xa1, 0xd6, 0x8a, 0x01, 0x2f, 0x9c, 0x0f, 0x5c, 0x8e, 0x01,
- 0x89, 0xb3, 0x9d, 0x5a, 0x36, 0x4a, 0x49, 0xc6, 0x3e, 0x7d, 0x06, 0x3b,
- 0xf9, 0x8e, 0xd8, 0xd6, 0x43, 0xbc, 0xeb, 0x21, 0xd6, 0xf5, 0x10, 0xff,
- 0x7a, 0x88, 0x71, 0x3d, 0xc4, 0xb6, 0x1e, 0x62, 0x5b, 0x0f, 0xb1, 0xad,
- 0xd7, 0x6f, 0x62, 0xe4, 0x11, 0x93, 0xf7, 0xe7, 0x77, 0x72, 0xe6, 0x17,
- 0x2a, 0xb0, 0x25, 0x93, 0xbc, 0xe7, 0xa0, 0x0a, 0xd9, 0xf5, 0x66, 0x7f,
- 0x61, 0x4e, 0xbc, 0xc7, 0xe4, 0x6c, 0x5e, 0xd7, 0x79, 0x43, 0x51, 0xb3,
- 0xad, 0xc1, 0xb7, 0x74, 0xde, 0xc7, 0xf8, 0x2d, 0xf8, 0x25, 0xfa, 0x3e,
- 0x13, 0x75, 0xb4, 0xae, 0x72, 0xcc, 0xc9, 0x88, 0x52, 0xb9, 0xeb, 0x31,
- 0x66, 0x47, 0x10, 0x13, 0x24, 0x25, 0xa6, 0x72, 0x6d, 0xe4, 0xa9, 0xa5,
- 0x72, 0x1b, 0xcc, 0x5c, 0x47, 0x5b, 0x03, 0xdf, 0xaa, 0x8f, 0x65, 0x5b,
- 0xe5, 0x6e, 0xe6, 0x13, 0xe7, 0x1e, 0xd6, 0xf7, 0x74, 0xae, 0x5c, 0x6b,
- 0x4a, 0xe3, 0x7b, 0x21, 0x7b, 0x37, 0xe6, 0xd3, 0xf7, 0x88, 0x1a, 0xfc,
- 0x56, 0xe7, 0xe5, 0xf7, 0x94, 0xe1, 0x77, 0xc0, 0xe3, 0x18, 0xfb, 0xe9,
- 0xbc, 0x30, 0x79, 0x1d, 0xce, 0xa7, 0xf3, 0x7a, 0x58, 0x47, 0xdf, 0xa5,
- 0xc0, 0x53, 0xc5, 0xa5, 0x63, 0xf4, 0x9e, 0xb8, 0x1b, 0x5d, 0x37, 0xfc,
- 0x26, 0x7e, 0x29, 0x6b, 0x76, 0xeb, 0xef, 0x68, 0x81, 0xcd, 0x98, 0xd2,
- 0x32, 0x68, 0xe7, 0xb8, 0xaf, 0xf7, 0x21, 0x7f, 0x53, 0x5a, 0xfe, 0x8a,
- 0x88, 0x63, 0x26, 0x07, 0xb7, 0xa5, 0x6d, 0x75, 0xa0, 0x95, 0xf9, 0xd7,
- 0x61, 0x3f, 0xc4, 0x3d, 0xae, 0xd7, 0x6c, 0xc7, 0x99, 0x57, 0x0b, 0xf1,
- 0x4c, 0xb6, 0x04, 0xf9, 0xb6, 0x0f, 0xa3, 0x4b, 0xad, 0x4d, 0xba, 0x14,
- 0xee, 0x93, 0xfb, 0xe7, 0x73, 0xed, 0x3b, 0x15, 0x8b, 0x7e, 0xe4, 0xfb,
- 0x48, 0x43, 0x36, 0x78, 0xb7, 0xe4, 0x8b, 0x90, 0x41, 0xfd, 0x9d, 0x02,
- 0x7a, 0x54, 0xaf, 0x0f, 0x33, 0xc7, 0xbc, 0xf3, 0x0b, 0xe6, 0xde, 0x82,
- 0x3c, 0xcc, 0xfc, 0x83, 0xbd, 0x2a, 0xff, 0x30, 0x0c, 0x59, 0x81, 0x0f,
- 0xe0, 0x75, 0x68, 0x9f, 0x4e, 0xb9, 0xf4, 0x07, 0x9a, 0xbf, 0xbf, 0x3c,
- 0xda, 0x16, 0xf0, 0xe1, 0xed, 0xd6, 0xe0, 0x1b, 0xc4, 0xdf, 0x26, 0x57,
- 0x96, 0x39, 0xfe, 0x7f, 0x8c, 0xac, 0x1c, 0x86, 0x6d, 0x1e, 0x86, 0x2c,
- 0x22, 0x26, 0xd7, 0xf3, 0x1d, 0x96, 0xd2, 0xd3, 0x0b, 0x9d, 0x2b, 0xfb,
- 0xa3, 0xee, 0x58, 0xd8, 0xff, 0xb1, 0xa6, 0xfe, 0x8f, 0xa1, 0xff, 0x0b,
- 0x4d, 0xfd, 0x1f, 0x8b, 0xf4, 0x3f, 0xda, 0xd4, 0x1f, 0x31, 0xe2, 0xd3,
- 0xff, 0xdc, 0xd4, 0xff, 0x68, 0xa4, 0xff, 0x6c, 0x53, 0xff, 0x59, 0xf4,
- 0x7f, 0xad, 0xa9, 0x3f, 0xea, 0x8e, 0xb5, 0x98, 0xef, 0x62, 0xc4, 0xd8,
- 0x7d, 0x26, 0x16, 0xc7, 0xb3, 0xd6, 0xfc, 0xad, 0x85, 0x72, 0xd7, 0x83,
- 0x33, 0x08, 0xef, 0xb4, 0x51, 0x5f, 0xf3, 0xd0, 0xd7, 0x65, 0x5f, 0x26,
- 0x90, 0xc7, 0xa8, 0x2c, 0x12, 0x1f, 0x2a, 0x12, 0x73, 0x7d, 0xfa, 0x47,
- 0x56, 0xb9, 0x1a, 0xda, 0x24, 0xde, 0x5b, 0xe2, 0x7d, 0xd7, 0xc0, 0xf6,
- 0xc6, 0xdd, 0x45, 0x13, 0x83, 0x5d, 0xd1, 0x06, 0xda, 0x81, 0x97, 0x21,
- 0x66, 0xca, 0xe1, 0x40, 0x6f, 0x28, 0xbf, 0x9c, 0xdf, 0xe8, 0x0f, 0x65,
- 0xd5, 0xac, 0x33, 0xbc, 0x0a, 0xd7, 0xd2, 0xab, 0x72, 0x5b, 0xb1, 0x4b,
- 0xc0, 0xb5, 0x91, 0x06, 0xae, 0x7d, 0x51, 0xe6, 0x1a, 0xf1, 0xf6, 0x19,
- 0xd9, 0xef, 0xed, 0xe1, 0x3d, 0x9d, 0xc3, 0x79, 0xf9, 0x68, 0xe2, 0xed,
- 0x3d, 0x0d, 0x3b, 0xc9, 0x3b, 0x1d, 0xe9, 0x83, 0xbc, 0x83, 0x1b, 0xe6,
- 0x66, 0x27, 0xbd, 0x5f, 0xc7, 0xfe, 0x69, 0x33, 0x2f, 0x37, 0xde, 0xe6,
- 0x7c, 0x49, 0xd9, 0x1f, 0xdc, 0x77, 0x68, 0xcc, 0x5b, 0x69, 0xcc, 0x9b,
- 0x32, 0xfa, 0x46, 0x1b, 0xbc, 0x6c, 0x2f, 0x8b, 0xb0, 0x97, 0x63, 0x88,
- 0xb9, 0x17, 0xbd, 0xb5, 0xf2, 0xa3, 0x97, 0x6b, 0x2f, 0x9b, 0xf3, 0xcc,
- 0xcd, 0xf6, 0x92, 0xeb, 0x34, 0xe7, 0x96, 0xd3, 0x4d, 0xf8, 0x4f, 0x79,
- 0x3a, 0x67, 0x7c, 0x6a, 0x3c, 0xab, 0xe7, 0xa0, 0x8f, 0x4a, 0xc6, 0xb4,
- 0xfc, 0xb2, 0x1c, 0xc6, 0x96, 0xf7, 0x34, 0x62, 0xcb, 0xe5, 0x78, 0x10,
- 0xbe, 0x6b, 0xff, 0x67, 0x0c, 0x3e, 0xd2, 0x47, 0x76, 0xac, 0xb2, 0xb7,
- 0x5b, 0xed, 0xd5, 0x6d, 0xcc, 0x97, 0x5e, 0x2b, 0xb7, 0xea, 0x38, 0xfe,
- 0x8c, 0xc9, 0x4d, 0xcd, 0x69, 0xff, 0x9f, 0xdf, 0x0b, 0xca, 0xd9, 0x4d,
- 0xc6, 0xdf, 0xbb, 0x18, 0xae, 0xae, 0x8c, 0x4d, 0x95, 0x3a, 0x88, 0xb1,
- 0x8c, 0x4d, 0xfb, 0xdb, 0x89, 0xa1, 0x05, 0xff, 0x82, 0xe3, 0x31, 0x8e,
- 0xe3, 0xd9, 0x47, 0xc7, 0xa1, 0xe8, 0xb7, 0x68, 0xc6, 0x07, 0x71, 0x68,
- 0xc1, 0xff, 0x71, 0x5b, 0x80, 0x83, 0x17, 0x8a, 0x59, 0x3e, 0xdf, 0xce,
- 0xbc, 0xde, 0xa2, 0x77, 0x31, 0x5a, 0x57, 0xc7, 0xbd, 0xb1, 0x55, 0x71,
- 0xaf, 0x6d, 0xe2, 0xda, 0x5f, 0xd2, 0x71, 0x6f, 0xc0, 0x63, 0xee, 0x25,
- 0x1a, 0x47, 0xb9, 0xc0, 0x42, 0x7e, 0x53, 0x21, 0x3e, 0xd0, 0x47, 0x81,
- 0x9f, 0x35, 0xfd, 0x8b, 0xe0, 0x73, 0x72, 0x0d, 0xb9, 0xf9, 0xb8, 0xed,
- 0x44, 0xb8, 0xf7, 0x73, 0x12, 0xe4, 0xeb, 0x76, 0x83, 0x16, 0xc6, 0x56,
- 0x71, 0x23, 0x0f, 0x3f, 0x35, 0xf7, 0x2a, 0xc3, 0x7e, 0x61, 0x1c, 0xdf,
- 0xf8, 0xee, 0x5a, 0xc9, 0xaf, 0xc8, 0x9f, 0x74, 0x33, 0x0d, 0x8d, 0x73,
- 0xcf, 0x5f, 0xc6, 0x77, 0x8b, 0x0f, 0x73, 0x3f, 0xa2, 0xd9, 0xae, 0xf1,
- 0xbb, 0x29, 0xbf, 0x95, 0x8a, 0x75, 0x67, 0x9f, 0x0b, 0x1d, 0xe0, 0xbd,
- 0xe1, 0x28, 0xbe, 0x26, 0xa4, 0x34, 0x2b, 0x89, 0x64, 0x8e, 0xdf, 0x00,
- 0x68, 0xff, 0x7f, 0x68, 0xf6, 0x99, 0x92, 0x7d, 0x33, 0x41, 0xce, 0x53,
- 0x5d, 0xf0, 0x5e, 0xdc, 0xe3, 0xe0, 0x43, 0xe6, 0x50, 0x98, 0xf3, 0x54,
- 0xc1, 0xbd, 0xb8, 0x43, 0x1f, 0xdd, 0xbd, 0x38, 0xce, 0x6f, 0xcb, 0x9e,
- 0x35, 0xee, 0xc5, 0xc5, 0x2e, 0xf1, 0x5e, 0xdc, 0x26, 0x9d, 0xf3, 0xe4,
- 0x3c, 0x41, 0xce, 0x93, 0xe5, 0xad, 0x03, 0xcc, 0x95, 0xf0, 0xee, 0xdb,
- 0xa0, 0xbe, 0x2f, 0xbc, 0x75, 0xe0, 0xe7, 0x11, 0xa3, 0xfc, 0x75, 0xfb,
- 0xc7, 0x1f, 0xa3, 0x70, 0x2f, 0xbf, 0x11, 0x7c, 0xdf, 0x95, 0xcb, 0xc9,
- 0x03, 0x7c, 0xb8, 0xbc, 0xe6, 0x3e, 0x9d, 0xd7, 0x7c, 0xa7, 0x3d, 0x9a,
- 0xd7, 0x54, 0x17, 0xb9, 0x1b, 0xb6, 0x6f, 0x8d, 0xbc, 0x66, 0x3c, 0x72,
- 0x37, 0x2c, 0x6e, 0xee, 0x86, 0x6d, 0x72, 0x11, 0x4b, 0x9a, 0x3c, 0xa6,
- 0xba, 0xe0, 0xdd, 0xb0, 0xce, 0x0d, 0x1f, 0x3e, 0x8f, 0xb9, 0xea, 0x6e,
- 0x18, 0x6c, 0xdd, 0x16, 0x49, 0x5f, 0x56, 0xdc, 0xf3, 0x61, 0x62, 0x1e,
- 0xde, 0xab, 0x6f, 0xc1, 0x9e, 0xe3, 0xb2, 0x27, 0x49, 0xf9, 0xe4, 0xdd,
- 0xc6, 0x3e, 0xe8, 0x02, 0x9e, 0x3e, 0xcb, 0xfd, 0x3c, 0x23, 0x6b, 0xa4,
- 0x6f, 0xe5, 0x3d, 0x84, 0xe5, 0x3b, 0xbd, 0x89, 0xc6, 0x9d, 0xde, 0x29,
- 0xc8, 0x8d, 0x9a, 0x49, 0xc8, 0x7c, 0x44, 0xa6, 0x26, 0x3d, 0xf8, 0x4b,
- 0xb3, 0x8e, 0x69, 0xe7, 0xff, 0xef, 0x48, 0x02, 0xf3, 0x78, 0x0f, 0xb8,
- 0x43, 0x62, 0xb3, 0xc1, 0x37, 0xcb, 0xe0, 0xff, 0xb8, 0xa4, 0xd0, 0x87,
- 0x77, 0x3c, 0xe3, 0xb2, 0x5f, 0xe7, 0x2c, 0x42, 0x59, 0xfe, 0x35, 0xf0,
- 0x78, 0x73, 0x7e, 0xb9, 0x9c, 0x5c, 0xc3, 0xee, 0x27, 0xa5, 0x3c, 0x43,
- 0x79, 0xbe, 0xc1, 0xfc, 0xff, 0x82, 0xd3, 0x52, 0xf6, 0x4f, 0x99, 0xf8,
- 0x42, 0x7f, 0xdb, 0x01, 0x2f, 0xb7, 0x18, 0x1b, 0x8c, 0x67, 0x75, 0x0b,
- 0x6d, 0x1e, 0xd6, 0x38, 0x2e, 0xc3, 0xd3, 0x3b, 0x52, 0x7b, 0x81, 0x77,
- 0x63, 0x7a, 0xcd, 0xcb, 0xe1, 0xb9, 0x75, 0x9e, 0xef, 0x8d, 0x97, 0xca,
- 0xf7, 0xd0, 0x3f, 0xae, 0x62, 0x7f, 0x5b, 0x20, 0x1f, 0x5f, 0x95, 0xe2,
- 0xb1, 0x6b, 0x65, 0xf8, 0x68, 0x06, 0xf4, 0xbc, 0x5f, 0x2f, 0x67, 0xe1,
- 0x4b, 0x3f, 0xcd, 0x7b, 0x63, 0xc0, 0x50, 0xf0, 0xed, 0xf9, 0x55, 0xdf,
- 0xb1, 0xa3, 0x77, 0xcd, 0xfa, 0x1b, 0x77, 0x87, 0x9e, 0xf5, 0x25, 0xd1,
- 0x49, 0x9a, 0x67, 0x96, 0xef, 0x8f, 0x2f, 0xfa, 0xbb, 0xb4, 0x6d, 0x7b,
- 0xc6, 0x5f, 0x91, 0xfb, 0xd1, 0x67, 0x38, 0x5e, 0xfb, 0x1e, 0xec, 0xdb,
- 0x39, 0x8b, 0xf6, 0x6d, 0xca, 0x93, 0xab, 0x63, 0xc2, 0xf3, 0x10, 0x0b,
- 0x3c, 0xd0, 0x77, 0x38, 0x82, 0xef, 0xfb, 0x3d, 0xfa, 0x5c, 0x03, 0xac,
- 0x58, 0x88, 0xdc, 0xc1, 0x58, 0x3e, 0xdb, 0xe0, 0x6e, 0x46, 0x70, 0x16,
- 0xc1, 0xfd, 0x11, 0xed, 0x6f, 0x1e, 0xdc, 0xe3, 0x06, 0xf7, 0x47, 0x7a,
- 0x67, 0x59, 0xd7, 0xd5, 0x64, 0xfb, 0x12, 0x90, 0x01, 0xde, 0x3b, 0xe2,
- 0xbd, 0x71, 0xd2, 0xac, 0x73, 0x1d, 0xff, 0x47, 0xdd, 0xd5, 0xc7, 0xb6,
- 0x75, 0x5d, 0xf7, 0xc3, 0x47, 0xea, 0xc3, 0xb4, 0x2c, 0x53, 0x32, 0x25,
- 0xd3, 0x96, 0x2c, 0xbf, 0x27, 0x3d, 0x59, 0x72, 0xac, 0x14, 0xac, 0xab,
- 0xad, 0x02, 0x46, 0xa4, 0x0c, 0x49, 0x7f, 0xb4, 0x08, 0x06, 0xfa, 0xa3,
- 0x99, 0x8b, 0x66, 0xab, 0x4b, 0xd9, 0x4e, 0x0a, 0xf4, 0x0f, 0xb7, 0xc5,
- 0x80, 0x6c, 0x58, 0x60, 0x86, 0xb4, 0x12, 0x63, 0x56, 0x4c, 0xd6, 0x66,
- 0x85, 0x0c, 0xd8, 0x30, 0x4e, 0x54, 0x9c, 0x14, 0x50, 0xc6, 0x04, 0x69,
- 0x83, 0xa2, 0x58, 0x61, 0x45, 0x76, 0x36, 0x6c, 0x7f, 0x65, 0x43, 0xd0,
- 0x05, 0x9b, 0xb3, 0x38, 0x76, 0xb0, 0x06, 0x45, 0xd6, 0x7d, 0x62, 0x18,
- 0xd0, 0x0d, 0xdc, 0xf9, 0xdd, 0x0f, 0xf2, 0xf1, 0xf1, 0x51, 0x1f, 0x89,
- 0x33, 0x60, 0x02, 0x04, 0xbe, 0xf7, 0x78, 0xdf, 0x7b, 0xf7, 0x9e, 0x7b,
- 0xce, 0xb9, 0xbf, 0x73, 0xee, 0x39, 0x87, 0x9e, 0x7b, 0xdb, 0x9b, 0xf3,
- 0xb9, 0xca, 0x77, 0x8e, 0x8a, 0x77, 0x0e, 0x28, 0x9d, 0xa5, 0xe3, 0xc5,
- 0x63, 0xc6, 0x6c, 0x61, 0x22, 0xe2, 0x67, 0xfe, 0x9e, 0xad, 0xc2, 0xbe,
- 0x6e, 0x87, 0xe1, 0xd6, 0xa2, 0x67, 0xbc, 0x85, 0x9e, 0xcd, 0x32, 0xc1,
- 0xf6, 0x78, 0x5d, 0x77, 0x4b, 0xda, 0xc9, 0xeb, 0x88, 0x85, 0xd7, 0x31,
- 0x0e, 0x92, 0x76, 0x75, 0x19, 0xba, 0xe2, 0x8c, 0x6f, 0x68, 0xd0, 0xee,
- 0x74, 0x9d, 0x76, 0x3b, 0xff, 0x1f, 0xd1, 0xee, 0x1d, 0x81, 0x7f, 0x5f,
- 0xad, 0x22, 0x6e, 0x4d, 0x63, 0x00, 0x9d, 0x3b, 0x04, 0x3a, 0x42, 0x9f,
- 0x5a, 0xe5, 0x15, 0x82, 0x4e, 0x45, 0x5c, 0x71, 0xad, 0xf6, 0x5a, 0xb4,
- 0xee, 0xa7, 0x64, 0xbb, 0x04, 0xf6, 0x09, 0xfc, 0x79, 0xed, 0xd7, 0xc8,
- 0x63, 0x1f, 0x6b, 0x8d, 0x04, 0x56, 0x72, 0xdb, 0x27, 0x0c, 0x08, 0x1d,
- 0xf6, 0xc9, 0xb1, 0x4d, 0xda, 0x27, 0xe7, 0xa5, 0x7d, 0x92, 0xdd, 0xb8,
- 0x7d, 0xb2, 0xbb, 0x25, 0xae, 0xab, 0x31, 0x9e, 0xcd, 0xdb, 0x27, 0xc6,
- 0x9a, 0xf6, 0xc9, 0x90, 0xc3, 0x17, 0x83, 0xfe, 0xfe, 0x06, 0x65, 0x8f,
- 0x43, 0xc7, 0x69, 0x3a, 0x83, 0xc6, 0xc7, 0x5d, 0x7e, 0xe1, 0x4f, 0x93,
- 0xd6, 0xbf, 0xf8, 0x3f, 0xa6, 0xf5, 0x50, 0x8b, 0xcf, 0xbb, 0x31, 0x1e,
- 0x0a, 0xef, 0xd8, 0x14, 0x8e, 0x77, 0xd3, 0x7a, 0xa8, 0xad, 0xef, 0xb4,
- 0x7d, 0xcc, 0x62, 0xb3, 0xef, 0x74, 0xd4, 0x68, 0xa7, 0xdb, 0xff, 0xd8,
- 0xe1, 0x53, 0x75, 0xea, 0x77, 0xc8, 0x14, 0xf9, 0x8e, 0x4d, 0xe8, 0x77,
- 0x41, 0x96, 0xac, 0x6c, 0x96, 0x60, 0x33, 0xe1, 0x7d, 0x11, 0x21, 0x6b,
- 0x2e, 0xbc, 0xc5, 0xef, 0x63, 0x7a, 0xbe, 0xf8, 0x87, 0x62, 0x9d, 0x92,
- 0xfe, 0x07, 0xb4, 0x0f, 0xfb, 0xce, 0x88, 0xb6, 0x32, 0xbe, 0x49, 0xf9,
- 0x23, 0x14, 0xf6, 0x6f, 0xe7, 0x87, 0x68, 0x5d, 0xf3, 0x36, 0x67, 0x2b,
- 0x68, 0x19, 0xdf, 0xcb, 0xf3, 0x12, 0x69, 0xb2, 0xb5, 0xa0, 0x3f, 0xcf,
- 0x33, 0x2e, 0x18, 0xad, 0x63, 0x82, 0xe6, 0xb9, 0xb9, 0x28, 0x6c, 0x3a,
- 0xad, 0x3b, 0x57, 0x64, 0xec, 0xa9, 0xb8, 0x0e, 0x9c, 0xa6, 0x75, 0xa7,
- 0x1b, 0x07, 0xef, 0xf5, 0xe0, 0x0b, 0xcf, 0xdc, 0x4f, 0x3d, 0x77, 0x26,
- 0x62, 0xce, 0x53, 0x9e, 0x73, 0x57, 0xcf, 0xe1, 0xca, 0x36, 0xda, 0xca,
- 0xfb, 0x53, 0x62, 0x5c, 0xdf, 0xfc, 0x62, 0x02, 0xb9, 0x6a, 0xf5, 0xfc,
- 0x21, 0x77, 0xce, 0x14, 0xd6, 0x01, 0x2d, 0x87, 0x3a, 0x3f, 0x1b, 0xb4,
- 0x18, 0xf1, 0xc8, 0x99, 0x72, 0xae, 0x25, 0xb8, 0xcf, 0x4d, 0x8b, 0xc6,
- 0x3a, 0x32, 0xa7, 0xd6, 0x91, 0x45, 0x87, 0x1e, 0x6f, 0xc5, 0xed, 0xfd,
- 0x1e, 0xb8, 0xdd, 0x2b, 0x6f, 0x0a, 0x7d, 0x7a, 0x92, 0x71, 0xc8, 0x67,
- 0x80, 0x43, 0x42, 0xc8, 0x5b, 0x92, 0x58, 0x04, 0xdf, 0x17, 0x19, 0x8f,
- 0x44, 0x98, 0x57, 0x7e, 0x44, 0xe7, 0x18, 0x6b, 0x5f, 0xa7, 0xfd, 0xca,
- 0x3e, 0x83, 0xdc, 0xea, 0x38, 0x53, 0xc4, 0xf1, 0xfb, 0x28, 0xfb, 0x98,
- 0x35, 0x19, 0xa7, 0x1f, 0xd1, 0x59, 0x11, 0x33, 0x83, 0xfd, 0x3d, 0xc4,
- 0x1c, 0x3c, 0x20, 0xde, 0x2f, 0x7d, 0x19, 0xf7, 0x23, 0xa6, 0x6e, 0xe3,
- 0xf1, 0xfb, 0x2a, 0xb7, 0x8e, 0xdb, 0xe1, 0x9d, 0x4b, 0x4a, 0xa6, 0xc4,
- 0x35, 0xbe, 0xff, 0x49, 0xa3, 0xf5, 0xfe, 0xb8, 0x91, 0xaa, 0xa6, 0x8c,
- 0x44, 0x05, 0xed, 0x9e, 0x34, 0x92, 0x55, 0xd8, 0x90, 0x9a, 0x47, 0xac,
- 0x28, 0xe4, 0x6d, 0x95, 0xd6, 0xdf, 0x8b, 0x58, 0x24, 0x57, 0x9e, 0xc4,
- 0x06, 0xfa, 0x7d, 0xb8, 0xa9, 0xdf, 0x9a, 0xbe, 0x38, 0x86, 0xbf, 0xe7,
- 0x15, 0xa6, 0xa9, 0xc6, 0xb5, 0x41, 0xf8, 0xd7, 0x27, 0xb3, 0xb4, 0x16,
- 0xae, 0xb5, 0x5a, 0x70, 0xed, 0xe2, 0xba, 0xfd, 0xfe, 0xa4, 0x32, 0x2e,
- 0xf3, 0xa3, 0xfd, 0xb6, 0xc0, 0xaf, 0xdc, 0xef, 0x26, 0x6c, 0xeb, 0xe2,
- 0x29, 0xb4, 0xd1, 0x7e, 0x70, 0xed, 0x07, 0xeb, 0x55, 0xf1, 0xc0, 0x3a,
- 0x3e, 0x21, 0x88, 0x7c, 0xaf, 0x90, 0x8c, 0x6b, 0x85, 0x8d, 0xb5, 0xc2,
- 0xfd, 0x83, 0xbd, 0x05, 0x9f, 0x8f, 0xb0, 0xb7, 0xcc, 0x24, 0x49, 0x5f,
- 0xf7, 0x99, 0xaa, 0xd3, 0xbf, 0xeb, 0x95, 0x4b, 0x39, 0xea, 0x91, 0x4b,
- 0xe9, 0x94, 0xb5, 0x80, 0x43, 0xd6, 0x22, 0x0e, 0xdc, 0x36, 0xcc, 0x76,
- 0x4b, 0x0f, 0xeb, 0x90, 0x1e, 0xb1, 0x6d, 0xe2, 0xbf, 0xea, 0xb4, 0x5b,
- 0xdc, 0x79, 0xf1, 0x90, 0x3b, 0x60, 0x33, 0x69, 0xc3, 0xa4, 0x4a, 0xf5,
- 0x9c, 0x7a, 0x1e, 0x77, 0x23, 0x6f, 0xb1, 0xd2, 0x92, 0x63, 0xe9, 0xd5,
- 0xdf, 0x91, 0x96, 0xfe, 0x62, 0xfd, 0x8a, 0xb7, 0xc5, 0x74, 0x5e, 0x76,
- 0xd5, 0xfd, 0xea, 0x9f, 0x5b, 0x9f, 0xe1, 0x5d, 0xa3, 0xc2, 0xe7, 0x9d,
- 0xad, 0xeb, 0xb2, 0x19, 0xd9, 0xdf, 0x42, 0xb3, 0x9d, 0xe1, 0xbf, 0x42,
- 0x8a, 0x76, 0xde, 0xba, 0x7d, 0x73, 0xfe, 0xb3, 0xad, 0x6e, 0x1c, 0xdc,
- 0x27, 0xfd, 0x62, 0x73, 0x2a, 0x0e, 0x7b, 0x40, 0xd9, 0x7b, 0xeb, 0xf1,
- 0x3b, 0xae, 0xcd, 0x29, 0x5f, 0xa2, 0x65, 0x96, 0x09, 0x7c, 0x7e, 0xfc,
- 0x54, 0x87, 0x1d, 0x52, 0x7b, 0x59, 0xd8, 0xaf, 0x02, 0xdf, 0xeb, 0xe7,
- 0x43, 0x67, 0x6f, 0x64, 0xce, 0xcc, 0x96, 0x39, 0x93, 0x7c, 0x05, 0x5b,
- 0x0b, 0xf1, 0xc5, 0x53, 0xae, 0x18, 0xef, 0x4f, 0x42, 0x8b, 0x5e, 0x8f,
- 0xb8, 0x67, 0xc4, 0x2d, 0xb7, 0xeb, 0xe7, 0x1d, 0x07, 0x2e, 0x47, 0x7f,
- 0x6b, 0xb5, 0x57, 0xa2, 0xbb, 0xe5, 0x5a, 0x5c, 0xf5, 0xc6, 0x48, 0xa1,
- 0x0d, 0xf7, 0xcf, 0xbd, 0xf6, 0xee, 0xda, 0xe0, 0xda, 0x2b, 0xea, 0x8b,
- 0xf8, 0x0e, 0x09, 0x1d, 0xd0, 0x43, 0x95, 0x12, 0xe2, 0xaf, 0x3f, 0x0b,
- 0x99, 0x67, 0x3d, 0xeb, 0xc8, 0x49, 0xf3, 0x9e, 0xc7, 0xfa, 0x9e, 0x4a,
- 0x20, 0x86, 0xbd, 0x3f, 0xc4, 0x96, 0xf4, 0xb3, 0xee, 0x41, 0xfb, 0x71,
- 0xf3, 0x16, 0xfc, 0xbd, 0xca, 0xff, 0x94, 0x52, 0xeb, 0xcb, 0xa1, 0x0d,
- 0xec, 0xad, 0x6c, 0x4e, 0x4f, 0x5b, 0xe6, 0x0a, 0x61, 0xdf, 0x07, 0xf1,
- 0xc2, 0xc7, 0x7a, 0xa9, 0xf7, 0x2b, 0x5d, 0x5d, 0xf6, 0x1f, 0xf4, 0xc9,
- 0xbd, 0x28, 0x7c, 0xd7, 0x43, 0x2f, 0x94, 0x10, 0xcb, 0x8d, 0xef, 0x7e,
- 0x8b, 0xbf, 0xf3, 0xd2, 0x51, 0x3a, 0x16, 0x1d, 0x58, 0x4e, 0xce, 0x4f,
- 0x99, 0x60, 0x2b, 0xd5, 0xe8, 0x6f, 0xa2, 0x9f, 0x93, 0xfb, 0x19, 0xd5,
- 0xfb, 0xbd, 0x57, 0xe3, 0xe5, 0x2f, 0xfc, 0x69, 0xdf, 0xc7, 0x8d, 0x8d,
- 0xfc, 0xd6, 0x86, 0xfc, 0x85, 0xd8, 0xe7, 0xdf, 0xc8, 0x9e, 0x89, 0xde,
- 0x1b, 0x9e, 0x16, 0x39, 0xa7, 0x4e, 0x3e, 0xb8, 0x3f, 0xfb, 0xc3, 0xe0,
- 0x87, 0x91, 0x16, 0x5d, 0xf5, 0xc9, 0xfd, 0xfd, 0x6e, 0xba, 0x06, 0x3d,
- 0x7d, 0x55, 0xde, 0xfb, 0xc0, 0xd8, 0xf3, 0x87, 0x9f, 0xba, 0x4a, 0x67,
- 0xae, 0x81, 0x87, 0x0d, 0xe6, 0xb6, 0x31, 0xca, 0x87, 0x91, 0x57, 0x24,
- 0x72, 0x73, 0xf4, 0xbe, 0xa1, 0xc8, 0x15, 0x3a, 0x23, 0x72, 0x20, 0xc7,
- 0x23, 0xf7, 0x78, 0x3d, 0x3c, 0x53, 0x7d, 0x9b, 0xce, 0x56, 0x82, 0xfc,
- 0xdf, 0xc0, 0xee, 0xad, 0x79, 0x90, 0xcd, 0x3c, 0x7e, 0x4f, 0xf0, 0xf8,
- 0xf0, 0x9a, 0x3c, 0x7e, 0xa4, 0xce, 0xe3, 0x5f, 0xe9, 0x97, 0xfc, 0xdc,
- 0xcb, 0xcf, 0xea, 0xa5, 0x43, 0xe2, 0xb9, 0x6f, 0xf3, 0xf1, 0x56, 0x3a,
- 0x14, 0x92, 0xc7, 0x67, 0x2b, 0xac, 0xe3, 0x0b, 0x6f, 0xd3, 0xb9, 0x6b,
- 0x59, 0x5f, 0x4a, 0xe4, 0x2f, 0x38, 0x6b, 0x69, 0xe8, 0xfb, 0xd1, 0xae,
- 0x1d, 0xff, 0x6b, 0xbd, 0x24, 0x73, 0xae, 0xca, 0x52, 0x3f, 0xd1, 0x5b,
- 0xd1, 0x21, 0x17, 0xff, 0x37, 0xdb, 0x8e, 0xe7, 0xd5, 0x1a, 0x78, 0x7c,
- 0x0d, 0xbf, 0x46, 0x2b, 0x5f, 0xf6, 0x79, 0xe0, 0xe1, 0xa7, 0xfb, 0xe5,
- 0x3e, 0xd5, 0x5a, 0x7e, 0x8d, 0xa6, 0xb8, 0x0e, 0xe7, 0xbe, 0x3d, 0xeb,
- 0xfd, 0x3d, 0x2a, 0x17, 0xf0, 0x87, 0xfd, 0x72, 0xbd, 0x40, 0x7e, 0xe0,
- 0x0a, 0xd3, 0xe1, 0x22, 0x63, 0x95, 0x21, 0xea, 0xbc, 0xaa, 0xc7, 0x3a,
- 0x24, 0xf4, 0xad, 0xd3, 0x4f, 0x73, 0x51, 0xe5, 0x76, 0xe7, 0x1c, 0x63,
- 0xba, 0x28, 0x6c, 0x9c, 0xf6, 0xf2, 0xd6, 0x3e, 0xe6, 0x6a, 0xd8, 0xb5,
- 0x26, 0xb8, 0xf9, 0x0d, 0x75, 0x4a, 0x30, 0xbf, 0x64, 0x48, 0x1c, 0x3c,
- 0xc3, 0xf8, 0x76, 0xb3, 0xfb, 0x45, 0x9f, 0x14, 0x23, 0xba, 0x6b, 0x60,
- 0xb8, 0x8f, 0x31, 0x0f, 0xd2, 0xe6, 0xc8, 0xbc, 0x58, 0x15, 0xba, 0xe0,
- 0xe2, 0x54, 0x8d, 0x92, 0xd1, 0x6d, 0x94, 0x99, 0xe2, 0x77, 0xcf, 0xd8,
- 0x6c, 0x7b, 0xf9, 0x29, 0xcb, 0xf2, 0x9b, 0x99, 0xda, 0xa2, 0xf0, 0xa2,
- 0xf6, 0xa7, 0x77, 0xa9, 0x38, 0x87, 0x5e, 0xb1, 0x2f, 0x29, 0x6b, 0xf5,
- 0xf0, 0x71, 0x45, 0x3f, 0x1b, 0xd7, 0xc1, 0xbb, 0x9d, 0xaa, 0xdd, 0x65,
- 0x47, 0x3b, 0xb4, 0xb9, 0xac, 0xda, 0xe2, 0x99, 0x1a, 0x53, 0x74, 0x2b,
- 0x7d, 0x0b, 0x39, 0x5c, 0x51, 0xb9, 0x7a, 0xc2, 0x7e, 0xa0, 0xd9, 0xfa,
- 0x58, 0x2e, 0x73, 0xdb, 0xff, 0xae, 0xc5, 0x85, 0x2d, 0x77, 0x99, 0x31,
- 0x6f, 0x55, 0xc8, 0x8a, 0xbb, 0x4f, 0x18, 0x8b, 0x5f, 0xec, 0x0f, 0xf1,
- 0xb1, 0x7a, 0xcf, 0xe9, 0x7a, 0x9f, 0x10, 0xa3, 0x61, 0x45, 0xe4, 0xb3,
- 0x74, 0xbb, 0xcb, 0x8e, 0x76, 0x5a, 0x57, 0xe8, 0xfd, 0x87, 0x8f, 0x7c,
- 0xb3, 0x85, 0xdb, 0x3e, 0x19, 0xc3, 0x1b, 0x12, 0xfb, 0xa7, 0x32, 0x46,
- 0x43, 0x1f, 0xc3, 0xbf, 0x8c, 0x98, 0x0a, 0xc4, 0x49, 0x38, 0xf5, 0x8d,
- 0x1c, 0x6f, 0x00, 0x6b, 0x51, 0x15, 0xfb, 0xa6, 0xd8, 0xaf, 0x68, 0x87,
- 0x9d, 0x77, 0x21, 0x36, 0x7f, 0x13, 0x18, 0x74, 0x23, 0xf2, 0x67, 0x7a,
- 0xc8, 0x9f, 0xf3, 0xfd, 0xc8, 0x83, 0x43, 0x3e, 0x5c, 0x76, 0xd2, 0xa0,
- 0x1a, 0xdb, 0x0a, 0x06, 0x95, 0x43, 0x3e, 0x3a, 0x67, 0x5b, 0xd1, 0x8a,
- 0xc0, 0x9a, 0x8f, 0xc0, 0x7f, 0x35, 0xb9, 0x42, 0x07, 0x44, 0xce, 0x38,
- 0x6a, 0x1f, 0x94, 0x79, 0x0d, 0x3e, 0xcd, 0x3c, 0x78, 0x96, 0xed, 0x8f,
- 0xec, 0x49, 0xec, 0xb7, 0xe8, 0x79, 0x41, 0x0e, 0x3c, 0x3e, 0x4d, 0x9e,
- 0xbb, 0xdf, 0xdd, 0x41, 0xc1, 0x38, 0x3f, 0xd3, 0x84, 0x7e, 0xe2, 0xe7,
- 0xa4, 0x29, 0xc1, 0x76, 0x12, 0x6c, 0xd6, 0xd3, 0x27, 0xad, 0x50, 0x99,
- 0x0c, 0x6e, 0x0b, 0xdb, 0x15, 0xcf, 0xc1, 0xfd, 0xf1, 0x50, 0x07, 0xb9,
- 0x73, 0x72, 0x7b, 0x45, 0x9e, 0xe2, 0x5b, 0xd1, 0x07, 0xc9, 0x18, 0x84,
- 0xbe, 0xc2, 0xbc, 0x3d, 0xa0, 0xf6, 0x89, 0xb6, 0xf3, 0xf1, 0x84, 0x3a,
- 0x0e, 0x8a, 0xf9, 0x94, 0xc7, 0x9a, 0xbf, 0xf1, 0xf7, 0xf3, 0x2e, 0xb2,
- 0xfd, 0x6a, 0xfe, 0x9a, 0x62, 0x41, 0x22, 0x63, 0x46, 0x90, 0xce, 0x57,
- 0xd6, 0xf2, 0xbf, 0x78, 0xe5, 0xba, 0x6e, 0xdf, 0x60, 0xae, 0xeb, 0x4f,
- 0x76, 0xc8, 0xdc, 0x32, 0x67, 0x5f, 0xfe, 0x93, 0xfb, 0xe2, 0x85, 0xc9,
- 0x5a, 0x70, 0x22, 0x8f, 0xb7, 0x46, 0x3f, 0x8b, 0x7e, 0x9e, 0xee, 0x84,
- 0x23, 0x2a, 0x66, 0x09, 0x31, 0x4a, 0x0f, 0x2a, 0xbe, 0xd6, 0xba, 0x9f,
- 0x3c, 0x74, 0xff, 0xa3, 0x22, 0x56, 0x53, 0xae, 0x1d, 0x43, 0x8a, 0x1e,
- 0xa0, 0x59, 0xc4, 0x41, 0xb3, 0x01, 0x07, 0xcd, 0x0c, 0x75, 0xbc, 0x4d,
- 0x9c, 0x9f, 0xaf, 0x3c, 0xb5, 0x5d, 0xe6, 0x8b, 0x63, 0x2f, 0xf1, 0x92,
- 0x3a, 0x5e, 0x6f, 0xbc, 0x56, 0x98, 0x82, 0xc2, 0xdf, 0xe4, 0x18, 0xeb,
- 0xcb, 0x44, 0xf6, 0x81, 0x70, 0x2b, 0x0d, 0x5e, 0x73, 0x5c, 0x47, 0x1f,
- 0xc7, 0x1d, 0x7d, 0x1c, 0x75, 0xf4, 0x71, 0x6f, 0x9b, 0x3e, 0xb2, 0x8e,
- 0xe7, 0xf7, 0x9c, 0xad, 0x7e, 0xdc, 0xbe, 0xa2, 0x9f, 0xc8, 0x23, 0x06,
- 0x3d, 0xb7, 0x52, 0x2e, 0x1c, 0x51, 0x6b, 0xc7, 0x2f, 0x55, 0x2e, 0xba,
- 0x57, 0x9f, 0xff, 0x8e, 0xda, 0xcf, 0x9b, 0x93, 0x57, 0x9d, 0xf9, 0xc7,
- 0xdf, 0xa5, 0xa4, 0xcc, 0x23, 0x57, 0xb2, 0x7d, 0xb9, 0x8d, 0x1f, 0x1a,
- 0xf1, 0x1c, 0xc0, 0x20, 0xc2, 0x2e, 0xdc, 0x2d, 0x6b, 0xc1, 0x05, 0x68,
- 0xa9, 0x9e, 0xcb, 0xeb, 0x57, 0xb9, 0x3b, 0xc7, 0xc3, 0xf7, 0x37, 0x8f,
- 0x17, 0xd7, 0xff, 0x4c, 0xf8, 0xf2, 0xe4, 0xfe, 0xd1, 0x8a, 0xca, 0x47,
- 0xb6, 0x4c, 0xc4, 0x06, 0x2c, 0x2e, 0xc3, 0xff, 0xda, 0x2e, 0x77, 0x57,
- 0xea, 0xa2, 0x4c, 0xbd, 0x3e, 0x4a, 0x59, 0xe4, 0x35, 0x48, 0xff, 0x98,
- 0xcc, 0xbf, 0x5d, 0x5c, 0xbe, 0x25, 0x72, 0x5e, 0x13, 0x2a, 0x8f, 0x37,
- 0x43, 0x3d, 0x02, 0xe7, 0x7e, 0xfc, 0xfc, 0xdb, 0x17, 0xc2, 0x9b, 0xcf,
- 0xbf, 0x75, 0xde, 0xb3, 0xb9, 0xfc, 0xdb, 0x10, 0x8f, 0xdd, 0x58, 0x90,
- 0xf9, 0xb7, 0xcd, 0x7b, 0x32, 0x32, 0xff, 0x36, 0xe3, 0xc0, 0x0f, 0x12,
- 0xaf, 0xbf, 0xe5, 0x88, 0xdf, 0x96, 0xb9, 0xb5, 0x8b, 0x75, 0xcc, 0x2a,
- 0x73, 0x6b, 0x65, 0xbc, 0xb7, 0xb3, 0x0e, 0x8c, 0xdc, 0xfb, 0x91, 0xef,
- 0xd9, 0xe6, 0xda, 0xfb, 0x91, 0x39, 0xb5, 0xa6, 0xd1, 0xce, 0x86, 0xc3,
- 0x1a, 0x81, 0x7a, 0x08, 0x71, 0xe6, 0xdd, 0xad, 0x6d, 0xea, 0x21, 0xc4,
- 0xdb, 0xd4, 0x43, 0x70, 0xea, 0x7e, 0x27, 0xc6, 0x02, 0x26, 0xc6, 0xda,
- 0x08, 0x2c, 0x8c, 0x7a, 0x06, 0x51, 0x3a, 0x5f, 0xc7, 0x9e, 0x0f, 0x52,
- 0x5a, 0x61, 0xcf, 0xf3, 0x15, 0xad, 0x8f, 0x46, 0x5d, 0xfa, 0xc8, 0x0b,
- 0x8b, 0x5a, 0x2a, 0xce, 0x47, 0xcb, 0x6b, 0xd6, 0x21, 0xaf, 0x59, 0x0f,
- 0x79, 0xc5, 0x3d, 0xd9, 0x36, 0xfd, 0xfe, 0xa5, 0xba, 0x07, 0xff, 0x4f,
- 0x46, 0x50, 0xb3, 0x85, 0x68, 0xf7, 0x80, 0xc2, 0x7f, 0x0e, 0x79, 0x3d,
- 0xcb, 0xf2, 0xaa, 0xaf, 0xa3, 0xbf, 0xed, 0x6c, 0x00, 0x8d, 0x19, 0x87,
- 0x7c, 0x87, 0xaf, 0xbd, 0x21, 0xe2, 0xa4, 0x9a, 0xed, 0x45, 0x8d, 0x27,
- 0xf6, 0x09, 0x59, 0xba, 0xe3, 0x47, 0xdc, 0x8a, 0xbe, 0x16, 0x52, 0x7e,
- 0x32, 0x4d, 0x8b, 0xce, 0x26, 0xcc, 0xd1, 0xc0, 0x1b, 0x22, 0xc6, 0xd7,
- 0xd1, 0xb7, 0x7f, 0xe5, 0xbe, 0xe9, 0xeb, 0x7a, 0xcd, 0x7c, 0xa7, 0xc9,
- 0x9f, 0x71, 0xa3, 0xa9, 0xee, 0x1f, 0x7c, 0x47, 0xdb, 0xd2, 0x86, 0x9d,
- 0x12, 0x31, 0xa6, 0x7d, 0x36, 0xfc, 0x64, 0x09, 0x96, 0xfd, 0xbe, 0x34,
- 0xe2, 0x99, 0xfb, 0xae, 0x98, 0x74, 0xa2, 0x70, 0x7e, 0x8f, 0xe4, 0x95,
- 0x0b, 0xa2, 0xa6, 0x25, 0x6a, 0x20, 0x26, 0x79, 0x7d, 0x4e, 0x30, 0xe8,
- 0x9c, 0xab, 0x76, 0xd1, 0x22, 0xa3, 0x7b, 0xbf, 0x5d, 0x16, 0xbe, 0x3e,
- 0xd6, 0x49, 0x45, 0xd4, 0x36, 0x35, 0x16, 0x3a, 0xf9, 0xb9, 0x83, 0xb4,
- 0x54, 0x1a, 0x17, 0x35, 0xa1, 0x64, 0x7d, 0x11, 0xb4, 0xf5, 0x51, 0xbf,
- 0xfd, 0x0d, 0xa6, 0xdd, 0xd7, 0x44, 0x8c, 0xe5, 0x62, 0xf1, 0x82, 0xfc,
- 0x2c, 0x3f, 0xa5, 0xde, 0xc1, 0xef, 0xab, 0xfe, 0x98, 0xe2, 0xfd, 0xa6,
- 0xc3, 0x96, 0x73, 0xfe, 0x79, 0xe3, 0x95, 0x63, 0x9b, 0xc2, 0x2b, 0xd9,
- 0x74, 0x03, 0xaf, 0x38, 0x9f, 0xad, 0xb1, 0xcb, 0xe4, 0xa0, 0xac, 0xf7,
- 0x00, 0x1a, 0x6c, 0x05, 0x16, 0x4b, 0x83, 0x96, 0x46, 0xcc, 0x8a, 0x24,
- 0xfc, 0x33, 0x94, 0xaf, 0x5e, 0xa7, 0x4c, 0x11, 0x98, 0x99, 0x3f, 0xcb,
- 0xe7, 0x76, 0x4a, 0x1f, 0x8d, 0xbe, 0x07, 0x7a, 0x65, 0x07, 0xb7, 0xff,
- 0xeb, 0x41, 0x19, 0x97, 0xed, 0xbc, 0xde, 0xcb, 0xd7, 0xbf, 0x10, 0x69,
- 0xbe, 0xbe, 0x85, 0xaf, 0xf7, 0xa7, 0x31, 0x87, 0xc6, 0x15, 0xf8, 0x25,
- 0x27, 0x29, 0xc7, 0xf3, 0x93, 0xaf, 0xf2, 0xda, 0x7a, 0x95, 0xf5, 0x55,
- 0x45, 0xb7, 0x1b, 0x40, 0xce, 0x8e, 0x98, 0x13, 0x83, 0xdb, 0x5c, 0x2c,
- 0x4c, 0x71, 0xbb, 0x21, 0xf2, 0x5f, 0x35, 0x29, 0x5f, 0xd1, 0xbc, 0xaa,
- 0xe3, 0xed, 0xdf, 0x18, 0x90, 0x31, 0x55, 0xef, 0xec, 0x94, 0xf4, 0x9b,
- 0x14, 0x3e, 0x4f, 0xc4, 0x73, 0x3c, 0x23, 0xf8, 0xd0, 0x9a, 0x31, 0xeb,
- 0xef, 0xdf, 0x06, 0xbe, 0x42, 0xdd, 0x54, 0x1e, 0x03, 0xeb, 0xc5, 0x98,
- 0x1d, 0xca, 0xd5, 0x63, 0xd5, 0x9e, 0xdb, 0x2d, 0xef, 0xff, 0xe9, 0x80,
- 0xac, 0x55, 0x7a, 0x5b, 0x9d, 0xeb, 0x35, 0x07, 0xf1, 0xcb, 0x3e, 0x41,
- 0x1b, 0xff, 0x02, 0xf4, 0xa5, 0xc1, 0xc7, 0x3c, 0x9e, 0x34, 0xfa, 0xf8,
- 0xb3, 0x01, 0x5d, 0x9f, 0x50, 0x8e, 0xeb, 0x28, 0xf7, 0x37, 0xc5, 0xe3,
- 0xd2, 0xd7, 0xe3, 0x7c, 0xee, 0x35, 0xbf, 0x78, 0x56, 0x30, 0x2d, 0xeb,
- 0x8b, 0x05, 0xd3, 0x99, 0x49, 0x39, 0xcf, 0x0d, 0x9f, 0x6e, 0xa4, 0xee,
- 0xd3, 0x9d, 0x2b, 0xf4, 0x0f, 0xc2, 0xbf, 0x61, 0x5c, 0xe1, 0xf9, 0x0e,
- 0x3f, 0xc3, 0x6d, 0x91, 0xab, 0x90, 0xe3, 0xcf, 0x1e, 0x15, 0xd7, 0xd3,
- 0xca, 0x2b, 0x32, 0x4e, 0x42, 0xaf, 0x5b, 0xb8, 0x77, 0x80, 0x9f, 0x21,
- 0xd7, 0xae, 0xf6, 0xef, 0xa1, 0x96, 0x38, 0x98, 0x56, 0x1e, 0x5b, 0xcb,
- 0x0f, 0x2b, 0xf6, 0x13, 0x3d, 0xf8, 0x6c, 0xad, 0x7a, 0x06, 0xef, 0x08,
- 0x3f, 0x5a, 0xb2, 0x45, 0x5e, 0x21, 0xc7, 0x01, 0xfa, 0xce, 0x7c, 0x96,
- 0xb6, 0xf0, 0x5c, 0x7d, 0xc3, 0xf8, 0x35, 0xec, 0xb7, 0x93, 0x8c, 0x79,
- 0x62, 0x1a, 0x17, 0xec, 0xc9, 0xb3, 0x06, 0xd3, 0xb9, 0x90, 0xad, 0x05,
- 0xec, 0x1e, 0xea, 0x64, 0x59, 0xfd, 0x22, 0x8d, 0xb1, 0xfd, 0x07, 0x99,
- 0xb5, 0x23, 0x29, 0x82, 0xbc, 0x59, 0xa1, 0xc3, 0xcc, 0x13, 0xc9, 0x2a,
- 0xf8, 0xd9, 0xa0, 0x27, 0x4a, 0x44, 0x8f, 0x97, 0xc6, 0x42, 0xdf, 0x27,
- 0xdb, 0x6c, 0x7c, 0x6f, 0x85, 0x12, 0xdc, 0x8f, 0x54, 0xf5, 0x77, 0xe8,
- 0x43, 0x51, 0xe7, 0x04, 0x74, 0xd4, 0xf3, 0xfe, 0xdb, 0x74, 0x3a, 0x8d,
- 0x7e, 0x6f, 0x5c, 0x3e, 0x4f, 0x6c, 0x4a, 0x3e, 0x83, 0x1e, 0xf2, 0xf9,
- 0xea, 0xa0, 0xe4, 0x9b, 0x1a, 0xf3, 0x68, 0x90, 0x66, 0x8b, 0x88, 0x01,
- 0x7b, 0x18, 0x75, 0xa7, 0x8a, 0x19, 0xd6, 0x4b, 0x99, 0x86, 0x5e, 0xba,
- 0x94, 0xf0, 0xc7, 0x21, 0xe3, 0xa8, 0xcb, 0xa6, 0xe2, 0x7e, 0x30, 0x8e,
- 0xdd, 0x34, 0xb6, 0xb0, 0x95, 0xef, 0xa5, 0x95, 0xc4, 0x74, 0x5c, 0xe5,
- 0xfa, 0x5b, 0x66, 0x92, 0xf5, 0xe3, 0x1c, 0xcb, 0x72, 0xae, 0xf8, 0x00,
- 0x2d, 0x86, 0x87, 0x69, 0x74, 0x41, 0xd7, 0x37, 0xc1, 0x58, 0xff, 0x6d,
- 0x48, 0xea, 0x24, 0x3d, 0xee, 0x5f, 0x11, 0xbe, 0x0b, 0xf3, 0xfa, 0xa7,
- 0x35, 0xee, 0xad, 0xeb, 0xe8, 0xa5, 0xbf, 0x52, 0x32, 0x5b, 0xbb, 0x91,
- 0x88, 0x52, 0x36, 0x31, 0xfd, 0x97, 0x82, 0xff, 0x47, 0xaf, 0xc3, 0x0f,
- 0x07, 0x1d, 0x6d, 0x52, 0xba, 0xe0, 0xa6, 0xc5, 0x30, 0x8f, 0x1b, 0xdf,
- 0xd7, 0xfe, 0x79, 0x36, 0xfa, 0x94, 0x58, 0xfb, 0xc7, 0xae, 0x73, 0x3b,
- 0xb1, 0x36, 0x69, 0xbd, 0xe1, 0xc5, 0x87, 0xba, 0x8e, 0xa5, 0xe6, 0x45,
- 0x19, 0xeb, 0xc9, 0xf8, 0x2d, 0x94, 0xf6, 0xbb, 0x79, 0xf2, 0x23, 0x3a,
- 0x36, 0x6f, 0xd2, 0xf1, 0x82, 0xf5, 0x7c, 0x96, 0x66, 0x58, 0xae, 0x9d,
- 0xeb, 0x05, 0xb7, 0x27, 0xf0, 0x59, 0x8c, 0x65, 0x9f, 0xed, 0xe6, 0xa2,
- 0x29, 0xe3, 0xee, 0x44, 0xed, 0xb9, 0x2e, 0xa1, 0x47, 0x43, 0xf6, 0x3f,
- 0x0d, 0xea, 0xf5, 0x20, 0x53, 0x44, 0x1e, 0x21, 0x7f, 0x96, 0xb9, 0x7d,
- 0x61, 0x90, 0x32, 0x25, 0x3c, 0x07, 0xeb, 0x1d, 0xfa, 0xce, 0xe7, 0x4b,
- 0x72, 0x5e, 0x47, 0xf9, 0xd9, 0xc8, 0xbb, 0x3f, 0x5e, 0x9d, 0x12, 0xb1,
- 0x77, 0xd0, 0xcd, 0x72, 0x3e, 0x63, 0x74, 0xd1, 0x53, 0xaf, 0x28, 0x4c,
- 0xe9, 0x90, 0xef, 0x8c, 0x90, 0xef, 0x98, 0x98, 0x8f, 0x4c, 0xc9, 0x60,
- 0xbc, 0xa6, 0x7d, 0x0f, 0xfd, 0x7c, 0x1e, 0x50, 0x3a, 0x04, 0xdf, 0x0d,
- 0xec, 0x14, 0x71, 0x89, 0x36, 0xae, 0xe3, 0x33, 0x46, 0xcf, 0x30, 0xee,
- 0x7c, 0xb6, 0xd0, 0x45, 0xb7, 0x8a, 0x5d, 0xf4, 0x66, 0x71, 0x98, 0x6e,
- 0xce, 0x6f, 0xa7, 0x8b, 0x8c, 0x99, 0x2f, 0xda, 0x01, 0x33, 0xc7, 0xf6,
- 0xc5, 0x0b, 0x51, 0x11, 0x33, 0xc4, 0x72, 0x87, 0xf6, 0xc0, 0x7f, 0x89,
- 0x5d, 0xcc, 0x73, 0x8c, 0xbd, 0xbb, 0xe9, 0x03, 0x7e, 0x67, 0xae, 0xa0,
- 0x63, 0x1d, 0xe0, 0x93, 0x1f, 0xaf, 0xe3, 0xd7, 0xf5, 0x79, 0x24, 0xb4,
- 0x0e, 0x8f, 0xc4, 0x84, 0xae, 0xcf, 0xcf, 0xf3, 0xf7, 0xf3, 0xf0, 0x9f,
- 0x33, 0xbd, 0x59, 0x3f, 0x7f, 0x3d, 0x80, 0xf6, 0xb8, 0x66, 0xcb, 0x58,
- 0x49, 0x31, 0xb6, 0x08, 0x9f, 0x83, 0xb6, 0x11, 0x45, 0x87, 0x6e, 0x1e,
- 0x9f, 0x4f, 0xb4, 0xcf, 0x2c, 0x75, 0xd3, 0x99, 0x12, 0x63, 0x90, 0x92,
- 0x9f, 0x6d, 0x18, 0xb4, 0x0d, 0xec, 0xd5, 0xf5, 0x5f, 0x2f, 0x72, 0xdf,
- 0x73, 0x25, 0x89, 0x41, 0x72, 0x4b, 0xbd, 0x94, 0x2f, 0xf5, 0xa8, 0xf3,
- 0x07, 0x44, 0x8c, 0xbb, 0xac, 0x63, 0x84, 0xef, 0xd6, 0xd2, 0x6f, 0x6f,
- 0x31, 0x4f, 0x61, 0x4d, 0x95, 0x76, 0x29, 0x74, 0xcd, 0x8d, 0x96, 0xba,
- 0xc4, 0xe0, 0xb9, 0x19, 0xfa, 0x2e, 0xaf, 0xb7, 0xa3, 0x57, 0xe1, 0x3f,
- 0xfe, 0x2a, 0xf8, 0xa6, 0x0c, 0x1e, 0x1b, 0xbd, 0x8a, 0xba, 0x48, 0x7e,
- 0x91, 0xe7, 0x94, 0x0c, 0x4f, 0x8a, 0xdc, 0x10, 0x29, 0xa3, 0x27, 0x45,
- 0x2d, 0xba, 0x1f, 0x0a, 0xdd, 0x64, 0x65, 0x4d, 0x03, 0x78, 0x04, 0x3e,
- 0x18, 0x19, 0x83, 0x75, 0xc2, 0xee, 0x7b, 0x6b, 0x20, 0x36, 0x41, 0xf1,
- 0x41, 0xf0, 0xbd, 0x94, 0x59, 0x55, 0x5f, 0x40, 0xe8, 0xfb, 0xd0, 0x3e,
- 0x9d, 0x2f, 0xa9, 0xcf, 0xf5, 0x5a, 0xa1, 0xcf, 0x7b, 0x5c, 0xdf, 0x87,
- 0x5c, 0xdf, 0xd7, 0xe3, 0xe5, 0x78, 0xcd, 0xe3, 0x75, 0x9e, 0x64, 0x8d,
- 0xa2, 0xcc, 0x82, 0xe4, 0xbf, 0xd0, 0xbe, 0xf1, 0xd0, 0x97, 0x15, 0x06,
- 0xcf, 0x2c, 0x8f, 0x45, 0xfa, 0x8c, 0x1e, 0x7f, 0x66, 0xea, 0xef, 0x6b,
- 0xf1, 0x34, 0x70, 0xd1, 0xdc, 0x4e, 0xa9, 0xe3, 0xd0, 0xaf, 0x6c, 0x14,
- 0xd0, 0xed, 0xe4, 0x72, 0x0f, 0xad, 0x88, 0x9a, 0x5c, 0xc0, 0x18, 0xb8,
- 0x1f, 0xcf, 0xc9, 0x86, 0x3a, 0x08, 0x35, 0xd7, 0x21, 0xe3, 0x07, 0x22,
- 0xd7, 0x79, 0x3e, 0x53, 0xcb, 0xff, 0x55, 0x3b, 0x2d, 0x6a, 0xdc, 0xa0,
- 0x2d, 0x63, 0x48, 0x81, 0xf9, 0x19, 0xbf, 0x34, 0xd9, 0x55, 0x33, 0xe8,
- 0x67, 0x16, 0x7b, 0x2b, 0x86, 0xfd, 0x22, 0xcb, 0x98, 0xdc, 0x2b, 0x4f,
- 0xb9, 0xf6, 0xca, 0x4f, 0x8a, 0xbd, 0x72, 0xec, 0x93, 0x83, 0xae, 0xa0,
- 0xa5, 0x57, 0x4c, 0x0b, 0xe6, 0x31, 0xca, 0xf3, 0x68, 0xd2, 0xc5, 0x6b,
- 0x42, 0xdf, 0x44, 0x93, 0x7e, 0x19, 0x5f, 0x9d, 0xa2, 0xac, 0x88, 0xbf,
- 0x96, 0x9f, 0x71, 0x23, 0x61, 0x5b, 0x93, 0xab, 0x8c, 0x29, 0x2a, 0xc5,
- 0x2d, 0x74, 0xb3, 0xdc, 0xc1, 0x98, 0xef, 0x6f, 0x69, 0xb5, 0x4c, 0x8c,
- 0x0d, 0xb7, 0x53, 0x3e, 0xca, 0xbc, 0x36, 0x19, 0xe4, 0x79, 0x65, 0x7c,
- 0x3b, 0xc9, 0xf2, 0xc7, 0x63, 0xa8, 0x94, 0x6a, 0xef, 0xe7, 0xa2, 0x71,
- 0x33, 0x31, 0xdd, 0xc3, 0xf6, 0x4b, 0x88, 0xff, 0x6d, 0xfe, 0xff, 0x6c,
- 0x04, 0xb4, 0x59, 0x5c, 0xc2, 0xf7, 0x8c, 0x7d, 0x0a, 0xb5, 0xf7, 0x67,
- 0xb9, 0xcd, 0xec, 0x34, 0xec, 0x20, 0xd8, 0x7b, 0x36, 0xff, 0xcb, 0x36,
- 0x15, 0xe6, 0xbb, 0xdc, 0xb5, 0x6c, 0xc4, 0x10, 0x3a, 0x1e, 0x75, 0x5d,
- 0xc6, 0xd4, 0x67, 0xdc, 0x98, 0xe5, 0xbe, 0xdc, 0x24, 0x3c, 0xc3, 0xa4,
- 0x4c, 0x74, 0x1f, 0xcb, 0xc1, 0x76, 0xfe, 0x44, 0x3e, 0xd6, 0x56, 0xca,
- 0x4f, 0x8d, 0xab, 0x7c, 0xac, 0x48, 0x9b, 0x7c, 0x2c, 0xdc, 0xc7, 0x38,
- 0x60, 0xbe, 0x76, 0x6f, 0x36, 0xea, 0x7c, 0x2f, 0x19, 0x99, 0xe8, 0x36,
- 0x81, 0x99, 0x2a, 0x4b, 0xfb, 0xb9, 0x0f, 0x71, 0x33, 0x33, 0xcd, 0x7d,
- 0x2d, 0x39, 0xfb, 0x5f, 0xbb, 0x97, 0x8c, 0xa2, 0x9d, 0xdf, 0xd5, 0x2e,
- 0x4e, 0xa2, 0xed, 0x12, 0xda, 0xd7, 0xfe, 0x27, 0x11, 0xd5, 0xe3, 0x74,
- 0xde, 0x8b, 0xf1, 0x40, 0xbe, 0xf8, 0xb3, 0x72, 0x9b, 0x6e, 0x16, 0x61,
- 0x8f, 0x1b, 0xcc, 0xf7, 0xe8, 0x91, 0x49, 0xd9, 0x0a, 0x63, 0xc0, 0x6b,
- 0x7b, 0x7d, 0xab, 0xc5, 0x37, 0x6a, 0x99, 0xa6, 0xd8, 0x96, 0x66, 0x3f,
- 0xbc, 0xb4, 0xc1, 0x86, 0xc9, 0xbe, 0x82, 0x35, 0x14, 0xeb, 0x67, 0xb6,
- 0xe6, 0xb7, 0x81, 0xf7, 0x60, 0x1b, 0x5d, 0x60, 0xfd, 0x25, 0xe3, 0x93,
- 0x58, 0x97, 0xb2, 0x0e, 0x93, 0xf2, 0x93, 0x6a, 0xfa, 0x39, 0x04, 0xc9,
- 0xc3, 0xa3, 0x8d, 0xb8, 0x48, 0xc7, 0xfe, 0x7a, 0xc0, 0xb1, 0xbf, 0x1e,
- 0x72, 0xc4, 0x45, 0x86, 0x05, 0x3e, 0x6b, 0x60, 0xaa, 0xb0, 0xc2, 0x54,
- 0xc0, 0x5e, 0x52, 0xb7, 0x2d, 0xd6, 0x75, 0xdb, 0x8e, 0x75, 0x74, 0x9b,
- 0x97, 0xad, 0xba, 0xa2, 0xf4, 0x88, 0x15, 0xc5, 0x1a, 0x73, 0x83, 0xf5,
- 0xc5, 0xeb, 0xd5, 0x69, 0xd6, 0x23, 0x51, 0xd6, 0x23, 0x53, 0xac, 0x47,
- 0x26, 0x59, 0x8f, 0xd8, 0x4c, 0x03, 0x93, 0xc7, 0xfe, 0x11, 0xeb, 0x69,
- 0xac, 0x1f, 0x33, 0xf4, 0x4c, 0x15, 0x3a, 0x79, 0x8a, 0x31, 0xd0, 0x47,
- 0xb4, 0x3a, 0xdf, 0xcb, 0xfc, 0x2b, 0x71, 0x4f, 0xb3, 0x5d, 0x83, 0xda,
- 0x2b, 0xf0, 0x17, 0xff, 0x39, 0xf4, 0xce, 0x2b, 0x59, 0x1a, 0xf1, 0xdd,
- 0x2c, 0x82, 0xce, 0xab, 0xa8, 0x55, 0xf1, 0x12, 0x64, 0x1b, 0x35, 0x82,
- 0x7f, 0x30, 0x31, 0xc3, 0x7d, 0x1f, 0xf1, 0xe5, 0x79, 0x5e, 0xbe, 0x1d,
- 0xcd, 0x86, 0xfa, 0x59, 0x06, 0x8e, 0x2b, 0x19, 0x38, 0xde, 0x90, 0x81,
- 0x6c, 0x8e, 0x47, 0xd2, 0xb7, 0xb0, 0x9d, 0xc6, 0x0f, 0x26, 0x76, 0xf5,
- 0xb1, 0xfc, 0x22, 0x66, 0xa2, 0x51, 0xbf, 0xc7, 0x4f, 0xa7, 0xc3, 0x41,
- 0x55, 0xf7, 0xc7, 0x14, 0x39, 0xef, 0xf9, 0xe2, 0xbb, 0x8c, 0x4b, 0x58,
- 0x4e, 0x43, 0x38, 0xbf, 0x0c, 0xbf, 0x28, 0xdb, 0x0d, 0xdd, 0xc2, 0xaf,
- 0xb4, 0x28, 0xda, 0xe2, 0xdc, 0x9a, 0x64, 0x1d, 0x17, 0x5d, 0x31, 0xac,
- 0x99, 0xb8, 0xf1, 0x9b, 0xc3, 0xa8, 0xe1, 0xfe, 0x83, 0xea, 0xe7, 0x86,
- 0xe5, 0xde, 0x5c, 0x72, 0x97, 0xd4, 0x27, 0xcc, 0xa3, 0xe1, 0xb8, 0xb0,
- 0xdd, 0x3a, 0xae, 0xc8, 0xf5, 0x73, 0x91, 0xe7, 0xbb, 0x12, 0x9d, 0xe4,
- 0xf9, 0xee, 0x51, 0x6b, 0x67, 0x96, 0xbf, 0x17, 0xeb, 0x32, 0xaf, 0xa1,
- 0xc3, 0xa8, 0x7f, 0x1f, 0x12, 0x75, 0x22, 0x4e, 0xa2, 0x0e, 0x4f, 0x02,
- 0xcf, 0x63, 0xee, 0x85, 0xfe, 0xf8, 0x07, 0x5e, 0xa3, 0xf1, 0x5e, 0xf0,
- 0x23, 0x1f, 0x97, 0x67, 0xe8, 0x52, 0x41, 0xf7, 0xe1, 0x3d, 0x32, 0xbe,
- 0x8b, 0x7e, 0xf8, 0x68, 0x87, 0xfd, 0x9e, 0xc8, 0x05, 0x31, 0xfe, 0xc4,
- 0xdd, 0xa7, 0xa3, 0xaa, 0x4f, 0xa8, 0x75, 0xd9, 0x85, 0xda, 0x3e, 0x84,
- 0x9a, 0x48, 0x8b, 0xa2, 0x16, 0x65, 0xa7, 0xb0, 0x59, 0x17, 0x85, 0xed,
- 0xb1, 0x7f, 0x57, 0xa3, 0x3e, 0xe6, 0x7e, 0xd7, 0xb5, 0x3b, 0xbc, 0x6e,
- 0x1d, 0x12, 0x18, 0x6d, 0x14, 0xf5, 0xda, 0x45, 0x5e, 0xea, 0x8c, 0xf8,
- 0xce, 0x58, 0xc0, 0x77, 0x0f, 0xa9, 0xef, 0x3e, 0x2f, 0xb0, 0xb1, 0x11,
- 0xeb, 0x66, 0xbd, 0x28, 0xf8, 0x9d, 0xe7, 0xd9, 0x9e, 0x64, 0x7e, 0x8f,
- 0x54, 0xf8, 0xb9, 0xa7, 0x05, 0x3d, 0x35, 0x3d, 0x40, 0x0b, 0xc8, 0x40,
- 0x8f, 0xe2, 0x7f, 0xcb, 0x4c, 0xf9, 0xf5, 0xb8, 0xdb, 0xd1, 0x99, 0xb1,
- 0x4e, 0x01, 0x63, 0xc5, 0x98, 0x4c, 0x5f, 0xbc, 0x1c, 0xf1, 0xe5, 0xe6,
- 0x61, 0xeb, 0x20, 0xdf, 0x65, 0x0f, 0xe2, 0xa9, 0xb8, 0x0f, 0x3b, 0x29,
- 0x9e, 0x46, 0xbf, 0xd0, 0x4e, 0xd3, 0xc0, 0x76, 0xd1, 0xc2, 0x79, 0xdf,
- 0x76, 0x75, 0x5f, 0xb7, 0x98, 0x0b, 0x32, 0xf0, 0x1e, 0xfd, 0x6e, 0xbc,
- 0x17, 0xef, 0xc7, 0x7d, 0x78, 0x9e, 0x7c, 0xee, 0x00, 0xeb, 0xed, 0xc4,
- 0xb4, 0x7c, 0x96, 0x71, 0x5d, 0x7e, 0x37, 0x60, 0x7b, 0xf7, 0x57, 0xce,
- 0x9f, 0x4f, 0xd5, 0xf1, 0xc1, 0xfc, 0x6d, 0xa7, 0xb2, 0xf0, 0x7d, 0xe2,
- 0xbb, 0x11, 0x9f, 0xb0, 0x6b, 0x6d, 0xfe, 0xe4, 0x79, 0x9d, 0xe3, 0xf3,
- 0x33, 0xc5, 0xdb, 0xc2, 0x66, 0xcf, 0xa5, 0x47, 0x7c, 0xe5, 0x32, 0xc6,
- 0x3b, 0xe2, 0x4b, 0xb1, 0x0c, 0x24, 0x8b, 0x89, 0x5a, 0x5e, 0xe2, 0x02,
- 0x3a, 0xdd, 0x6f, 0x85, 0x4e, 0x1b, 0xef, 0x0f, 0xcb, 0x9a, 0xb7, 0x38,
- 0x66, 0x39, 0x2c, 0xb0, 0x1c, 0x16, 0x58, 0x0e, 0x0b, 0x2c, 0x87, 0x6c,
- 0xab, 0xbe, 0x56, 0x60, 0x39, 0xe4, 0xb5, 0xe4, 0x55, 0x5e, 0x4b, 0xa4,
- 0xec, 0xc6, 0x95, 0x7f, 0x53, 0xcb, 0xae, 0x3b, 0x6f, 0x53, 0xcb, 0x2a,
- 0xd6, 0x6f, 0xf2, 0x1d, 0x99, 0x68, 0x96, 0xd9, 0x5b, 0x2c, 0xb3, 0x1d,
- 0xb1, 0x41, 0xba, 0x5b, 0xc2, 0x9c, 0x59, 0xe6, 0x1c, 0xeb, 0xea, 0x94,
- 0x1f, 0x58, 0x2b, 0xc0, 0xf2, 0x04, 0xac, 0x69, 0x31, 0xdd, 0x07, 0xe9,
- 0x1e, 0xeb, 0xeb, 0xbb, 0x25, 0xc8, 0xf0, 0x1e, 0x75, 0x6e, 0xb1, 0x0c,
- 0x63, 0xfd, 0xb3, 0x7d, 0xb7, 0x8a, 0x06, 0x63, 0xb2, 0x40, 0x28, 0x43,
- 0xd0, 0xa7, 0x02, 0xa7, 0xf1, 0xbc, 0xaf, 0xb0, 0xde, 0x87, 0x0f, 0x0f,
- 0xeb, 0xc5, 0x19, 0x1f, 0xaf, 0x17, 0x91, 0x9b, 0xac, 0x4f, 0xcf, 0x97,
- 0x6c, 0x96, 0xfb, 0x7e, 0xfa, 0x56, 0x09, 0xeb, 0x34, 0x68, 0xc4, 0xe7,
- 0x65, 0x12, 0xbe, 0x31, 0x23, 0x86, 0xb1, 0x8f, 0x67, 0x0d, 0xc1, 0x27,
- 0x7f, 0x0a, 0x3a, 0x30, 0xed, 0x5f, 0xdc, 0x85, 0xda, 0xf3, 0x71, 0xa3,
- 0x53, 0xf9, 0x1a, 0x71, 0x8c, 0xf6, 0x68, 0x0b, 0xba, 0xe1, 0xbc, 0xdd,
- 0xbe, 0x24, 0x7e, 0xb3, 0x21, 0x0a, 0xff, 0x9b, 0x4b, 0x7f, 0x5d, 0xe2,
- 0xfb, 0x05, 0xbd, 0x66, 0x12, 0x7e, 0xe4, 0x90, 0xd3, 0xd3, 0xfe, 0xd8,
- 0x0c, 0x3d, 0x5b, 0x45, 0xbf, 0xaf, 0x52, 0x3e, 0x0c, 0x7d, 0x64, 0x45,
- 0xef, 0x90, 0xa4, 0x5d, 0x37, 0xe3, 0xce, 0x27, 0xbc, 0x75, 0x9c, 0x99,
- 0x10, 0x38, 0xb9, 0x8b, 0xf5, 0x0b, 0x68, 0xf3, 0x13, 0xe6, 0x35, 0x7e,
- 0x5f, 0x41, 0xeb, 0xb7, 0x1f, 0xb3, 0xce, 0xc1, 0x9c, 0xe1, 0x7c, 0x6d,
- 0x9d, 0xb6, 0xaa, 0x74, 0x9a, 0xed, 0xd0, 0x69, 0xb9, 0xba, 0x4e, 0x63,
- 0xde, 0x10, 0xba, 0x0c, 0xba, 0xea, 0x51, 0xc6, 0x91, 0xf2, 0x18, 0xf8,
- 0x70, 0x87, 0xd0, 0x5d, 0xac, 0xfb, 0xd9, 0xae, 0x58, 0xac, 0x66, 0x7d,
- 0x87, 0x85, 0x0e, 0xd1, 0xfc, 0xbd, 0x7f, 0xb7, 0x94, 0x8b, 0x6e, 0xa1,
- 0x0f, 0x72, 0x27, 0xa1, 0xb7, 0xbc, 0xda, 0x8f, 0x73, 0x3b, 0xb4, 0xb7,
- 0x23, 0x2f, 0xb1, 0x3e, 0x5b, 0x8c, 0xc2, 0xa6, 0xed, 0x51, 0xb6, 0x0f,
- 0xea, 0x72, 0x61, 0xaf, 0x0b, 0x63, 0xd5, 0xfa, 0x6c, 0x40, 0xf9, 0x35,
- 0xe0, 0x87, 0xc4, 0x9c, 0xb7, 0xc5, 0x08, 0x26, 0x30, 0x02, 0xdf, 0x13,
- 0x60, 0x7a, 0x89, 0x1a, 0xe2, 0x44, 0xef, 0xd2, 0xaa, 0x90, 0x8d, 0x77,
- 0x05, 0x76, 0xc9, 0xf3, 0x77, 0xb3, 0xd3, 0x07, 0x45, 0x3f, 0xf3, 0x4b,
- 0x0d, 0xfd, 0x38, 0x57, 0x78, 0x0f, 0xeb, 0x86, 0xe8, 0x6b, 0x65, 0x42,
- 0xea, 0xc0, 0xc5, 0x32, 0x6a, 0x80, 0x89, 0x3e, 0x73, 0x5f, 0xf5, 0x38,
- 0xd1, 0x0f, 0xad, 0x0f, 0x36, 0x22, 0x7b, 0x8c, 0x6b, 0xfb, 0x31, 0x47,
- 0x59, 0x07, 0x0f, 0x3d, 0xcb, 0xef, 0xc7, 0xb5, 0xf5, 0xc7, 0x73, 0xaf,
- 0x3e, 0x1e, 0xf8, 0xf6, 0x70, 0xcf, 0xbb, 0x74, 0x57, 0x8d, 0xe7, 0x6e,
- 0x7d, 0x3c, 0xcf, 0xa8, 0xf1, 0x50, 0xce, 0x88, 0x0d, 0x28, 0xdc, 0xbf,
- 0xe1, 0x67, 0x77, 0x27, 0x18, 0xc7, 0xe4, 0x96, 0x40, 0xe7, 0xfd, 0x8a,
- 0x9f, 0x9c, 0x7e, 0x54, 0x67, 0x5f, 0xad, 0xc9, 0x3b, 0xac, 0x7f, 0xef,
- 0x09, 0x1c, 0x33, 0xc2, 0x38, 0x06, 0xd7, 0x29, 0x0f, 0x3d, 0x9d, 0x0b,
- 0xa3, 0x4e, 0xed, 0x0c, 0x8f, 0x9b, 0xed, 0xb1, 0x69, 0xfe, 0x14, 0xfe,
- 0x35, 0x3c, 0x47, 0xdf, 0xff, 0x3c, 0xdd, 0x9b, 0x87, 0x2e, 0x07, 0x8e,
- 0x95, 0xb5, 0x6c, 0xef, 0x2d, 0x4b, 0xff, 0x6e, 0xca, 0xd3, 0xbf, 0x0b,
- 0xdf, 0xee, 0x34, 0x70, 0x7e, 0x08, 0x7e, 0xe0, 0xa4, 0xfa, 0xad, 0x8f,
- 0x5c, 0x15, 0xcf, 0xf2, 0xd2, 0x4b, 0x33, 0x8e, 0xd8, 0x38, 0xc4, 0xaa,
- 0x64, 0x59, 0xcf, 0xd8, 0xa1, 0x0e, 0x43, 0xe6, 0xdc, 0xdc, 0xa8, 0x6a,
- 0xec, 0x74, 0x94, 0xe7, 0xcc, 0x8e, 0x1a, 0x46, 0x4a, 0xf8, 0x1a, 0xba,
- 0xed, 0x1e, 0xea, 0xe2, 0x75, 0xf4, 0x2c, 0xa1, 0x96, 0x9a, 0x65, 0x62,
- 0x0f, 0xe0, 0x12, 0xf3, 0x64, 0x3e, 0x6a, 0x45, 0x1e, 0x17, 0x76, 0x29,
- 0xd6, 0x17, 0x03, 0x74, 0x62, 0x5a, 0xa3, 0x0f, 0x7c, 0xbc, 0x84, 0x3a,
- 0x9a, 0x51, 0x1e, 0x3f, 0xfc, 0xc7, 0x63, 0xe6, 0x9b, 0xbc, 0x2e, 0x5d,
- 0x12, 0x7e, 0x99, 0x0b, 0x94, 0x63, 0x39, 0x3d, 0x22, 0xe4, 0xd4, 0x18,
- 0x61, 0x29, 0x62, 0xb9, 0x42, 0x6c, 0xc2, 0xb8, 0xa8, 0xdb, 0x23, 0x6d,
- 0x1d, 0x1e, 0xe5, 0xb2, 0xaa, 0x87, 0x90, 0x86, 0xee, 0xd8, 0xb8, 0x4f,
- 0x22, 0xfd, 0x89, 0x7d, 0x31, 0x4e, 0x4c, 0xe6, 0xf6, 0x7d, 0xc3, 0xae,
- 0x33, 0x45, 0xbd, 0x48, 0xd0, 0x4e, 0xf8, 0x13, 0x8d, 0x29, 0xa6, 0x9b,
- 0xfe, 0xdd, 0x19, 0xa7, 0xdf, 0xe0, 0x9c, 0xc8, 0xeb, 0x7f, 0xa5, 0x2a,
- 0xd7, 0xe0, 0x1c, 0xdb, 0xf4, 0xf9, 0x83, 0x4e, 0x4c, 0x62, 0x15, 0x93,
- 0xc2, 0x97, 0xb3, 0x9b, 0x12, 0x0b, 0x53, 0xf4, 0x68, 0x01, 0x3a, 0x8c,
- 0xee, 0x24, 0x6c, 0xfc, 0xa2, 0x0c, 0x64, 0x7c, 0x8a, 0x52, 0x55, 0xd0,
- 0xc8, 0xc7, 0x58, 0x89, 0x79, 0xaf, 0x88, 0x3d, 0x7f, 0x3e, 0x2e, 0xe3,
- 0x77, 0x54, 0x7e, 0x5d, 0xf9, 0xcb, 0x87, 0x29, 0xb9, 0x40, 0xd9, 0x4c,
- 0xf4, 0x4b, 0xa2, 0xd6, 0x75, 0x26, 0x3a, 0xa1, 0x7c, 0x3b, 0x11, 0xbe,
- 0x0e, 0x7f, 0x99, 0x49, 0x5f, 0x2e, 0x58, 0xd9, 0x0c, 0x49, 0x9f, 0x05,
- 0x71, 0x1f, 0x0c, 0x5e, 0x7b, 0x77, 0xb0, 0x0e, 0x39, 0x21, 0xfc, 0x16,
- 0x8c, 0x54, 0xe6, 0xd1, 0x1e, 0x3e, 0x87, 0x7e, 0x82, 0x9d, 0x96, 0x29,
- 0x3e, 0xa5, 0xda, 0xd6, 0x28, 0xc4, 0xbc, 0x10, 0xfa, 0x55, 0x3b, 0x1b,
- 0x35, 0x1a, 0xf7, 0xc3, 0xe7, 0x71, 0x42, 0xe0, 0xc8, 0x11, 0xb6, 0x79,
- 0x44, 0xbb, 0xda, 0xac, 0xf0, 0x5f, 0xf0, 0x79, 0xf9, 0x81, 0x21, 0xfd,
- 0x9b, 0x08, 0xb8, 0x2e, 0xfd, 0x1a, 0xfc, 0xcc, 0x32, 0xf7, 0xa3, 0x29,
- 0x9e, 0x7e, 0x98, 0xe2, 0x9b, 0xf0, 0x33, 0x9d, 0xbc, 0xaf, 0x7e, 0x26,
- 0xa6, 0x35, 0xaf, 0x3d, 0x37, 0x58, 0x36, 0x5e, 0x5f, 0xd7, 0xfe, 0xfb,
- 0x50, 0xaf, 0xe1, 0x4c, 0xab, 0x90, 0xf8, 0xdd, 0x0c, 0x60, 0xf0, 0x7c,
- 0xf5, 0x71, 0xfc, 0x5e, 0x8c, 0x2f, 0x2d, 0xb0, 0x71, 0x84, 0xb1, 0x0d,
- 0x30, 0xce, 0x98, 0xd8, 0x17, 0x8b, 0x3f, 0x16, 0xf1, 0xe5, 0x97, 0x07,
- 0xc9, 0x0f, 0x7f, 0x9c, 0xad, 0x63, 0x29, 0xba, 0x45, 0xdc, 0xbb, 0xdc,
- 0x8f, 0xc4, 0xfa, 0x0c, 0x9d, 0x78, 0x87, 0xed, 0x86, 0x09, 0x15, 0x87,
- 0xd3, 0x21, 0x6a, 0x53, 0xc9, 0xbd, 0x54, 0xad, 0x53, 0x34, 0xef, 0xe9,
- 0xbd, 0x0e, 0xe7, 0x6f, 0x73, 0x41, 0x76, 0x9d, 0x98, 0x02, 0xfe, 0x29,
- 0x31, 0x47, 0x97, 0x88, 0xe4, 0x1c, 0x37, 0xf6, 0x31, 0xba, 0x78, 0x9e,
- 0x60, 0x0f, 0xc2, 0xef, 0xf7, 0x35, 0xfe, 0xc4, 0x7e, 0xc4, 0xd5, 0x21,
- 0xe0, 0xa8, 0x3e, 0x9b, 0x79, 0x66, 0x1a, 0xe7, 0x83, 0x6c, 0x9f, 0x69,
- 0xdc, 0x2b, 0x7d, 0x51, 0x6c, 0xb3, 0xa9, 0xf9, 0x82, 0x1f, 0x6a, 0x54,
- 0xd5, 0x29, 0xb0, 0xc8, 0xec, 0x07, 0x9d, 0x3e, 0x2d, 0x79, 0x5c, 0x6f,
- 0xef, 0x62, 0x23, 0xb1, 0x4e, 0xf8, 0xdd, 0x30, 0xd4, 0xeb, 0xdc, 0x0b,
- 0xda, 0xf3, 0x1c, 0x39, 0xf7, 0x36, 0x1e, 0xdf, 0xa5, 0x7f, 0xb3, 0xe8,
- 0xfe, 0xcc, 0xdb, 0x16, 0x8f, 0x79, 0xfb, 0xf9, 0x90, 0xdc, 0x3b, 0x7b,
- 0x58, 0xb5, 0xf1, 0x8a, 0x6f, 0x5d, 0xfe, 0x0e, 0xfc, 0x50, 0x8d, 0xfc,
- 0x8b, 0x77, 0x84, 0x5e, 0x69, 0xf5, 0x85, 0x47, 0x58, 0x9f, 0x4a, 0x39,
- 0x3e, 0xe1, 0x21, 0xc7, 0xfd, 0x31, 0xe0, 0x96, 0x8f, 0x2f, 0xc7, 0xc7,
- 0xdb, 0xca, 0xf1, 0x9e, 0x61, 0xe9, 0x8b, 0x6d, 0x95, 0x63, 0xe4, 0x00,
- 0x9d, 0xa8, 0xb6, 0xf3, 0x7b, 0x61, 0x1e, 0x90, 0xcb, 0xee, 0xf4, 0x95,
- 0x80, 0x66, 0xda, 0x5f, 0x82, 0x7d, 0x43, 0xf0, 0x25, 0xf6, 0x5e, 0x4e,
- 0x1a, 0xa9, 0x79, 0xf7, 0x5e, 0xea, 0x46, 0xee, 0xbd, 0xed, 0x71, 0x2f,
- 0xb0, 0x3b, 0x64, 0xc3, 0x8a, 0x48, 0x5f, 0x80, 0xa6, 0xdf, 0xb0, 0xef,
- 0x70, 0xc9, 0xca, 0x96, 0x09, 0xbe, 0xee, 0x30, 0x9d, 0xc3, 0xfe, 0xb4,
- 0xf2, 0x25, 0x1f, 0x2b, 0x48, 0x3a, 0x84, 0x0e, 0x0a, 0xfe, 0x00, 0xbe,
- 0x8d, 0xa4, 0xfd, 0x69, 0x9e, 0x63, 0xe9, 0x47, 0xce, 0x2c, 0x45, 0xd4,
- 0xbc, 0x71, 0x5b, 0x3c, 0xcf, 0x33, 0x5f, 0x10, 0xf3, 0x65, 0x3d, 0xbf,
- 0x52, 0x8f, 0x4f, 0xc6, 0xda, 0x50, 0xa3, 0xff, 0xe0, 0x75, 0xcf, 0x7f,
- 0x30, 0x24, 0x6a, 0x37, 0xdc, 0xa8, 0x1e, 0x64, 0xbc, 0x89, 0x39, 0x85,
- 0x0f, 0x52, 0xfb, 0x88, 0x1f, 0xda, 0x4b, 0xbd, 0x07, 0x18, 0x05, 0x18,
- 0x64, 0x33, 0xbe, 0x34, 0x0e, 0x22, 0xce, 0xdc, 0xe4, 0x7b, 0x50, 0x73,
- 0x6a, 0xdc, 0x4c, 0x51, 0x0f, 0xfc, 0x10, 0xa8, 0x25, 0x6d, 0xe6, 0x9a,
- 0x64, 0xec, 0x94, 0x90, 0xb1, 0xd4, 0xf2, 0x29, 0x25, 0x63, 0xa7, 0x94,
- 0x1f, 0xfe, 0x94, 0x92, 0xb1, 0x53, 0x4a, 0xc6, 0x4e, 0x29, 0x19, 0x3b,
- 0xc5, 0x7c, 0x3e, 0xc6, 0xf8, 0x16, 0x58, 0x44, 0xfb, 0x41, 0x7b, 0x29,
- 0x53, 0xc2, 0x75, 0xac, 0xcf, 0x6e, 0x39, 0x7b, 0x69, 0x44, 0xca, 0x19,
- 0x63, 0x13, 0x19, 0xaf, 0xc7, 0xef, 0xc2, 0x1c, 0xfc, 0x1e, 0xd3, 0xef,
- 0x23, 0x3a, 0x33, 0x8f, 0xbe, 0xfa, 0x28, 0x29, 0x6a, 0xc9, 0x76, 0x50,
- 0xc2, 0x89, 0x85, 0x43, 0xc8, 0x0f, 0x93, 0xb6, 0x5f, 0xb6, 0x6d, 0xae,
- 0x98, 0xe6, 0x93, 0x98, 0x9a, 0x2f, 0xb7, 0x5d, 0xd4, 0x45, 0xe9, 0x22,
- 0xe8, 0x8a, 0x98, 0x4a, 0x93, 0xe7, 0x46, 0xd0, 0x49, 0x86, 0x44, 0xb9,
- 0x68, 0x70, 0x4c, 0xd1, 0xe0, 0xdb, 0x62, 0x8c, 0x88, 0x49, 0x84, 0x2f,
- 0xb3, 0x3d, 0x1d, 0x72, 0x85, 0x31, 0x7e, 0x0e, 0xcb, 0xc2, 0xc1, 0x08,
- 0xeb, 0xa4, 0x8d, 0xd3, 0xa1, 0x31, 0xf6, 0x76, 0xba, 0x67, 0xa3, 0x79,
- 0x39, 0x77, 0x1c, 0x6b, 0x49, 0x44, 0xad, 0x23, 0x12, 0x17, 0x6f, 0xb1,
- 0x6b, 0x74, 0x34, 0xba, 0x97, 0x8f, 0xad, 0x74, 0x96, 0x0e, 0x90, 0xd1,
- 0x57, 0xa3, 0xbf, 0x60, 0x39, 0xe8, 0x66, 0x39, 0x38, 0xaa, 0xec, 0x92,
- 0xa3, 0x75, 0xbb, 0x64, 0xcf, 0x1e, 0xc4, 0x65, 0x64, 0xc4, 0xbe, 0xd7,
- 0x56, 0x55, 0x43, 0x00, 0xbe, 0x6f, 0x9c, 0x77, 0x51, 0x7c, 0x18, 0xe7,
- 0xf8, 0x2d, 0x22, 0x6b, 0x32, 0xee, 0x1b, 0xdf, 0x23, 0xb0, 0xbb, 0xcf,
- 0xc2, 0x3d, 0x47, 0xa5, 0xde, 0xf3, 0x91, 0x7f, 0xfc, 0x36, 0xe3, 0x89,
- 0x1a, 0x3d, 0xc1, 0xef, 0xcc, 0x17, 0xf7, 0xf1, 0xb3, 0x75, 0x4d, 0x09,
- 0x3b, 0x6e, 0xf8, 0xb6, 0x92, 0xbf, 0xaf, 0xdd, 0xbb, 0x2d, 0xc1, 0x8f,
- 0x8c, 0xa7, 0x8d, 0xd9, 0xe8, 0x7b, 0xb5, 0xd3, 0x27, 0xe1, 0x63, 0x87,
- 0x9c, 0x58, 0x21, 0xd3, 0xe7, 0x25, 0x1f, 0x12, 0x2b, 0x35, 0xe2, 0x63,
- 0x21, 0x2f, 0x35, 0xfa, 0x77, 0x1e, 0x5b, 0x88, 0xb0, 0x77, 0x22, 0x9f,
- 0x9f, 0xa6, 0x19, 0x91, 0x83, 0x8d, 0x38, 0xe9, 0x33, 0xf3, 0xfa, 0x5d,
- 0xb6, 0xe2, 0x8d, 0xcf, 0x20, 0xce, 0xad, 0xb8, 0x48, 0x6b, 0xaf, 0x39,
- 0xf0, 0xd7, 0x8d, 0x2d, 0xac, 0xf6, 0x85, 0x45, 0x4e, 0xf8, 0x76, 0xc6,
- 0x48, 0x3a, 0x1e, 0x7a, 0x9c, 0x9f, 0x0f, 0x3f, 0x5e, 0x80, 0x92, 0x57,
- 0xd0, 0xae, 0x93, 0x46, 0x17, 0x6a, 0x5f, 0xe0, 0xef, 0xc5, 0xfe, 0x65,
- 0x86, 0xba, 0xd5, 0xde, 0x44, 0x8f, 0xda, 0xcf, 0x8a, 0xb0, 0xec, 0x35,
- 0x72, 0x9d, 0x47, 0xeb, 0x3e, 0x3d, 0xc8, 0x84, 0xdb, 0xa7, 0xf7, 0xf4,
- 0x3a, 0xeb, 0xd5, 0x7a, 0x72, 0x80, 0x58, 0xd6, 0x2e, 0x52, 0xbe, 0x4a,
- 0x33, 0x4f, 0x1b, 0xcd, 0xe9, 0xdb, 0xf4, 0x3d, 0xdd, 0x9d, 0x31, 0xf3,
- 0xc2, 0x9b, 0x76, 0x50, 0xf1, 0x5f, 0x27, 0x9d, 0x29, 0x05, 0x79, 0xcd,
- 0x87, 0x6e, 0x05, 0xbd, 0xfc, 0xc3, 0xc8, 0x73, 0xf9, 0x7a, 0xa0, 0x93,
- 0x96, 0x96, 0x10, 0x6b, 0xf1, 0x47, 0x7b, 0x64, 0x7c, 0x71, 0x9a, 0xe9,
- 0x72, 0x80, 0xd7, 0x47, 0x43, 0xed, 0x1d, 0xe1, 0x1a, 0x74, 0x89, 0xa8,
- 0x37, 0x1a, 0xf8, 0xd2, 0x44, 0x90, 0xed, 0x02, 0xb9, 0xf7, 0x70, 0x88,
- 0x9f, 0xfd, 0xfd, 0x52, 0x1a, 0xfe, 0xb2, 0xd0, 0x11, 0x7e, 0x7e, 0x92,
- 0xf1, 0x44, 0x9c, 0x3a, 0xa9, 0xb2, 0xd4, 0xc9, 0x76, 0x41, 0x27, 0xe3,
- 0x89, 0xb1, 0xd0, 0xa8, 0x4f, 0xbc, 0x4b, 0xe4, 0xd4, 0x3c, 0x1c, 0x38,
- 0xc0, 0x7c, 0x85, 0x77, 0xbd, 0xae, 0xde, 0xe5, 0x7e, 0xc7, 0x2f, 0x6a,
- 0x38, 0x3f, 0xe2, 0x37, 0x2f, 0xdc, 0xc2, 0xef, 0x51, 0xcd, 0xcf, 0x30,
- 0x76, 0x0e, 0x53, 0x7e, 0xbe, 0x83, 0xc7, 0x10, 0x63, 0x3b, 0x22, 0xca,
- 0xe7, 0x8f, 0x50, 0xb6, 0x7a, 0x92, 0x7e, 0xbf, 0xea, 0xf4, 0x09, 0x3f,
- 0xc2, 0x7d, 0x96, 0x39, 0xfd, 0x5d, 0xdc, 0xaf, 0x0f, 0x6d, 0xb7, 0x8e,
- 0x09, 0x92, 0xff, 0x7b, 0x61, 0xea, 0x7c, 0x0e, 0xbe, 0x97, 0x1a, 0x15,
- 0xa3, 0xd6, 0xa5, 0x3b, 0x24, 0xfd, 0xcf, 0x2f, 0x88, 0xb8, 0x5a, 0xbe,
- 0x9f, 0x9f, 0x39, 0x87, 0x76, 0x2f, 0x98, 0x74, 0xd3, 0x96, 0xf4, 0x7e,
- 0x23, 0x10, 0x26, 0xff, 0xcb, 0x88, 0x7d, 0x02, 0x56, 0x33, 0x2f, 0xd8,
- 0xfb, 0x58, 0xbf, 0x3f, 0x87, 0xfb, 0xf8, 0xf3, 0x65, 0x9c, 0x07, 0x79,
- 0x9c, 0x58, 0xaf, 0x11, 0xef, 0x02, 0xbd, 0x78, 0x20, 0x12, 0x12, 0xfc,
- 0xf7, 0x08, 0xf3, 0x54, 0x87, 0xf0, 0x35, 0xf6, 0xa3, 0xad, 0x3d, 0xc4,
- 0xd8, 0xc2, 0xbc, 0x30, 0xb1, 0x0f, 0xe7, 0xf1, 0x3e, 0x3f, 0xd3, 0x48,
- 0xf2, 0x10, 0xc6, 0xd3, 0xc4, 0xdc, 0x81, 0x43, 0x13, 0xc4, 0xf3, 0x09,
- 0xfc, 0xc1, 0xf3, 0x19, 0x42, 0x7d, 0xa7, 0x20, 0xa5, 0xf8, 0x1d, 0xc9,
- 0x92, 0x1c, 0xf7, 0x5c, 0xd5, 0x4f, 0xd2, 0x4f, 0x75, 0x74, 0x44, 0xff,
- 0x9e, 0x21, 0x0d, 0xe2, 0xd9, 0x5a, 0x56, 0x70, 0xdc, 0x4b, 0x77, 0x4b,
- 0x3d, 0x74, 0x4f, 0xed, 0x69, 0xdd, 0x15, 0x76, 0x19, 0xeb, 0xf0, 0x74,
- 0x2f, 0xdd, 0x59, 0xea, 0x20, 0xea, 0x0f, 0x8a, 0x3d, 0xe7, 0xbb, 0xa5,
- 0x32, 0xbf, 0x3f, 0x31, 0x22, 0xfd, 0x3a, 0x0d, 0x1e, 0xb9, 0xeb, 0xc1,
- 0x23, 0x1f, 0x08, 0x1e, 0xd9, 0x37, 0xb2, 0x36, 0x8f, 0xec, 0x52, 0xb6,
- 0x48, 0x90, 0x3a, 0x15, 0x7f, 0xbc, 0xc4, 0xfc, 0xf1, 0x2c, 0xf3, 0xc7,
- 0xe1, 0x36, 0xfc, 0x61, 0xb8, 0xf8, 0xe3, 0x88, 0xe0, 0x8f, 0x87, 0x46,
- 0xd6, 0xe2, 0x8f, 0xc3, 0xfe, 0xb5, 0x7c, 0x4d, 0xe2, 0xb7, 0x3c, 0x2f,
- 0xcc, 0xd9, 0xbb, 0x99, 0xd7, 0x6d, 0xaa, 0xcc, 0x23, 0x67, 0x61, 0x25,
- 0x6a, 0xd0, 0xbf, 0x08, 0x9b, 0x6c, 0x55, 0xd8, 0xfc, 0x31, 0x11, 0xc3,
- 0xba, 0x28, 0xf8, 0x8b, 0xd7, 0xff, 0x18, 0x72, 0xaa, 0xdc, 0x73, 0xd1,
- 0x4d, 0x37, 0xa3, 0x98, 0x0b, 0x53, 0xcd, 0x05, 0xae, 0x75, 0xe9, 0xfa,
- 0x90, 0x01, 0xbe, 0x7e, 0xe1, 0x03, 0xf0, 0xe8, 0x72, 0x4f, 0x20, 0x59,
- 0xf8, 0xe6, 0x08, 0xf0, 0x5f, 0x7e, 0x99, 0x1c, 0xd7, 0x03, 0x7c, 0x3d,
- 0x2c, 0x7e, 0xfb, 0x09, 0xb2, 0xf2, 0x8f, 0x88, 0x71, 0x64, 0x9e, 0xbc,
- 0x59, 0x1a, 0xa6, 0x5b, 0xa5, 0xdd, 0xb4, 0x5a, 0x1a, 0xa1, 0x37, 0x45,
- 0x2d, 0x0d, 0x99, 0x1b, 0xb9, 0x2a, 0xe6, 0xc8, 0xa0, 0x43, 0x61, 0x6e,
- 0xb3, 0xb4, 0x9b, 0x56, 0x96, 0x34, 0x7f, 0x83, 0xb7, 0xc1, 0x2f, 0xf1,
- 0x3e, 0x99, 0x2f, 0xd7, 0xca, 0x33, 0xc9, 0x26, 0x9e, 0x91, 0xf7, 0x80,
- 0x57, 0xf2, 0xad, 0xb9, 0xbe, 0xdd, 0xa1, 0x18, 0x62, 0xf5, 0x82, 0xd4,
- 0x81, 0xb8, 0x45, 0xc3, 0x9a, 0x3c, 0xe4, 0x07, 0x86, 0xfe, 0x2a, 0xaf,
- 0xb9, 0x3c, 0x67, 0x36, 0xe2, 0x9c, 0x46, 0x18, 0x0f, 0x6f, 0x17, 0xf8,
- 0x37, 0x61, 0x07, 0x22, 0x49, 0xaa, 0x5d, 0x30, 0x6c, 0xd4, 0x73, 0x4c,
- 0xf3, 0xf3, 0x0c, 0xe5, 0x6f, 0xda, 0xe6, 0xe0, 0x3f, 0x37, 0xd6, 0xc5,
- 0x5e, 0xf2, 0x63, 0xdc, 0x67, 0xac, 0xc3, 0x8d, 0xfd, 0x1a, 0xaa, 0xef,
- 0xd7, 0x74, 0xf3, 0xb8, 0xa5, 0xec, 0xcd, 0xda, 0xdc, 0xae, 0xca, 0xed,
- 0xaa, 0xd8, 0xfb, 0xe3, 0xeb, 0x4b, 0xd8, 0x77, 0x1e, 0xa6, 0xd5, 0x79,
- 0xc8, 0x28, 0xfc, 0x21, 0x8d, 0xbd, 0xde, 0xd5, 0x65, 0x5c, 0x87, 0x4f,
- 0xa4, 0xb1, 0xd7, 0xbb, 0xaa, 0xf6, 0x7a, 0x57, 0x97, 0x63, 0x42, 0x6f,
- 0xe7, 0x4b, 0x4c, 0xf7, 0x92, 0x5f, 0xc5, 0x39, 0xee, 0x53, 0xbf, 0x2d,
- 0xf4, 0x98, 0xf0, 0x69, 0xf7, 0xd9, 0x6b, 0xd3, 0xf0, 0x50, 0x0b, 0x0d,
- 0x63, 0x02, 0x67, 0xa5, 0xf8, 0x99, 0xc9, 0xd2, 0x63, 0xff, 0x3b, 0x60,
- 0x78, 0x46, 0x00, 0xf3, 0x9e, 0x30, 0x34, 0xef, 0xc1, 0xe6, 0x8e, 0xf9,
- 0x19, 0x20, 0xf7, 0x14, 0xd9, 0x80, 0xfb, 0x16, 0x90, 0xf2, 0x4a, 0x06,
- 0xad, 0xbc, 0x02, 0xa6, 0x09, 0x75, 0x88, 0xfe, 0xa6, 0xf5, 0x9f, 0xe5,
- 0x60, 0xe3, 0x80, 0x4d, 0x40, 0x73, 0x9b, 0xa7, 0x90, 0x32, 0xf7, 0x0c,
- 0xac, 0x6f, 0xb1, 0xae, 0x6d, 0xb4, 0x01, 0xef, 0xb1, 0x5e, 0x34, 0x85,
- 0x85, 0x61, 0x49, 0x0f, 0x03, 0xb0, 0x7e, 0x00, 0xa5, 0x75, 0x50, 0x1d,
- 0x01, 0x4f, 0xef, 0x02, 0x4d, 0x40, 0xf7, 0x39, 0x01, 0xdb, 0xa2, 0xce,
- 0xfd, 0xca, 0xe0, 0xb5, 0xb2, 0x0d, 0xd0, 0x73, 0xab, 0x16, 0xf5, 0x88,
- 0xc9, 0x83, 0xf2, 0x99, 0x93, 0x0a, 0x03, 0x19, 0x79, 0x81, 0x0d, 0x9a,
- 0x17, 0xc0, 0xe1, 0x04, 0x4c, 0xeb, 0xc0, 0x32, 0x6a, 0x8d, 0x2e, 0xd0,
- 0x3c, 0x1e, 0x16, 0x97, 0x7e, 0x90, 0x18, 0x03, 0x54, 0x8c, 0x05, 0xc8,
- 0x97, 0x01, 0xb6, 0x29, 0x41, 0x7e, 0x05, 0xe5, 0x05, 0x90, 0xd9, 0x20,
- 0xbf, 0x83, 0xca, 0x4e, 0x50, 0x5e, 0x04, 0xb2, 0x97, 0x08, 0x41, 0xfd,
- 0x0c, 0xa4, 0x81, 0xec, 0xe6, 0x29, 0x22, 0x60, 0x7e, 0x52, 0x80, 0x10,
- 0x43, 0x03, 0x3c, 0x1f, 0x10, 0x1b, 0xc6, 0x30, 0xf5, 0x31, 0x64, 0xe4,
- 0x1b, 0x88, 0x19, 0x88, 0x7c, 0xc3, 0xce, 0x70, 0x40, 0x00, 0x16, 0x56,
- 0xff, 0xff, 0x1f, 0x53, 0x61, 0x01, 0xa6, 0x53, 0xd0, 0x3a, 0xd6, 0xdf,
- 0xff, 0x0f, 0x88, 0xb0, 0x30, 0xb4, 0xc0, 0xd7, 0x23, 0xe6, 0xc8, 0x83,
- 0xca, 0xd0, 0x05, 0x40, 0x56, 0x1b, 0xbc, 0x4d, 0xc0, 0x02, 0xbe, 0xef,
- 0x79, 0x01, 0xc3, 0x2f, 0x60, 0x99, 0xf5, 0xff, 0xff, 0x52, 0xb8, 0x5a,
- 0x10, 0x00, 0x00, 0x19, 0x3f, 0x16, 0x21, 0xc4, 0x7d, 0x00, 0x00, 0x00 };
+ 0xdc, 0x5b, 0x6b, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0x33, 0x3b, 0x4b, 0xae,
+ 0xc8, 0x15, 0x35, 0x22, 0x57, 0xd4, 0x9a, 0xa2, 0xed, 0x5d, 0x72, 0x28,
+ 0xb2, 0x96, 0xea, 0xae, 0x29, 0xa6, 0x62, 0xd3, 0x4d, 0xb4, 0xd9, 0xa5,
+ 0x5c, 0xb5, 0x75, 0x5a, 0x4a, 0x26, 0xfc, 0x48, 0x55, 0x83, 0xde, 0xa5,
+ 0x9c, 0xa0, 0xa8, 0x53, 0xc9, 0x76, 0x85, 0x20, 0x05, 0xaa, 0x05, 0x1f,
+ 0x89, 0x52, 0xb0, 0x1c, 0xc5, 0x92, 0x29, 0xb5, 0x71, 0x6b, 0x96, 0xb4,
+ 0x6c, 0x15, 0xd8, 0x6a, 0x65, 0xc7, 0x6d, 0x68, 0x54, 0x2e, 0x65, 0xca,
+ 0x69, 0x95, 0x26, 0x48, 0x8d, 0xa0, 0x42, 0x95, 0x3f, 0x8e, 0xe1, 0xf4,
+ 0x87, 0x5b, 0xf4, 0x87, 0xd1, 0x07, 0x22, 0xd7, 0x8f, 0xed, 0xf7, 0xdd,
+ 0xb9, 0x43, 0x0e, 0x97, 0x14, 0x45, 0xf9, 0xf5, 0xa3, 0x04, 0x56, 0x33,
+ 0xf7, 0x7d, 0xee, 0xb9, 0xe7, 0x7c, 0xe7, 0x31, 0x57, 0x3f, 0x2f, 0x52,
+ 0x27, 0xfa, 0x6f, 0x3d, 0x7e, 0x89, 0x87, 0x7f, 0xaf, 0x70, 0xfb, 0xce,
+ 0xdb, 0x77, 0xe0, 0xf5, 0x0e, 0xd3, 0xa8, 0x0d, 0xb1, 0x9e, 0xff, 0xc4,
+ 0xf0, 0xeb, 0xd6, 0xef, 0x2b, 0xfd, 0xd9, 0xf8, 0xbd, 0x89, 0xc6, 0xc1,
+ 0x7f, 0x17, 0x31, 0xae, 0xd1, 0x27, 0xf8, 0x57, 0xa9, 0xac, 0xde, 0x6e,
+ 0x92, 0x96, 0x55, 0xda, 0x43, 0xde, 0x92, 0x8a, 0x66, 0xfe, 0x24, 0x62,
+ 0xa6, 0x33, 0x47, 0xb2, 0x8e, 0x11, 0x09, 0xa5, 0xbb, 0x8a, 0x05, 0x47,
+ 0x24, 0x53, 0xda, 0x96, 0xc8, 0xc9, 0x7b, 0x95, 0x62, 0xcc, 0x92, 0xac,
+ 0x23, 0x91, 0x9b, 0xd3, 0xef, 0x3e, 0xf5, 0xd2, 0xce, 0xe4, 0x5b, 0x53,
+ 0x21, 0x89, 0xd8, 0xe9, 0x17, 0xc4, 0xde, 0x2a, 0x91, 0x56, 0x8c, 0x79,
+ 0xb2, 0x33, 0x63, 0x48, 0x83, 0x3f, 0xd7, 0x9b, 0x95, 0x97, 0x3a, 0xa5,
+ 0xd8, 0x92, 0x8e, 0x88, 0x99, 0xee, 0xb8, 0x92, 0x0d, 0xd9, 0x83, 0xa1,
+ 0xb4, 0x2d, 0x73, 0x65, 0xe9, 0x3f, 0x30, 0x2e, 0x91, 0x48, 0xfa, 0x4b,
+ 0x91, 0xda, 0x0e, 0x89, 0x58, 0xe9, 0xa9, 0x23, 0x5f, 0x73, 0x8e, 0x54,
+ 0x4c, 0xc7, 0xe9, 0x9a, 0x96, 0x68, 0xef, 0xe9, 0x1e, 0xb4, 0x97, 0x92,
+ 0x5d, 0x22, 0x3b, 0xc5, 0x74, 0x8a, 0xd1, 0x90, 0x13, 0x91, 0x6c, 0xd9,
+ 0x91, 0x5c, 0x59, 0xe4, 0x1f, 0x4a, 0x86, 0x9c, 0x76, 0x9a, 0x65, 0x7a,
+ 0xfb, 0xbb, 0x95, 0x0c, 0x68, 0xf9, 0x7b, 0x67, 0xea, 0xc8, 0xa8, 0x43,
+ 0x7a, 0x1f, 0x8b, 0x90, 0xae, 0x50, 0x7a, 0xa8, 0xb6, 0xe0, 0x58, 0x32,
+ 0x5c, 0x62, 0xdd, 0x80, 0xc9, 0xba, 0x70, 0x3a, 0x52, 0x77, 0xda, 0x89,
+ 0xea, 0xba, 0x52, 0x26, 0x8b, 0xf9, 0x46, 0x4a, 0xec, 0x1b, 0xe9, 0x2e,
+ 0x38, 0x31, 0x5d, 0x3f, 0xba, 0x33, 0xeb, 0xc4, 0x51, 0xdf, 0xaa, 0xdb,
+ 0x7a, 0xbe, 0x5c, 0x70, 0x1c, 0xdd, 0x76, 0x35, 0x94, 0x75, 0xba, 0x74,
+ 0xfd, 0xab, 0xbb, 0x0a, 0xce, 0x76, 0x5d, 0xff, 0xd6, 0xae, 0xac, 0x93,
+ 0xd2, 0xf5, 0xe3, 0xf7, 0x17, 0x9c, 0x1e, 0x5d, 0xdf, 0x8a, 0xfa, 0x5e,
+ 0x5d, 0xff, 0x83, 0xde, 0x82, 0x93, 0x46, 0xfd, 0x97, 0x22, 0x66, 0x87,
+ 0x2d, 0x63, 0xa5, 0x04, 0x7e, 0x19, 0xb4, 0xf5, 0xa1, 0x6e, 0x0f, 0x7e,
+ 0x77, 0xe1, 0x37, 0xbf, 0x41, 0x1a, 0xfa, 0xf1, 0x6c, 0x6b, 0xf5, 0x78,
+ 0x07, 0x1e, 0xb9, 0x11, 0x79, 0x3d, 0x14, 0x97, 0x97, 0x3a, 0x5f, 0x07,
+ 0x0f, 0x6d, 0x39, 0x57, 0x16, 0xa3, 0xbf, 0x33, 0x0e, 0xde, 0xc5, 0xe4,
+ 0xb9, 0x72, 0xbd, 0x84, 0x1e, 0x0f, 0x81, 0x37, 0x5f, 0x90, 0x7c, 0x2c,
+ 0x22, 0x1b, 0x27, 0x0d, 0x69, 0xeb, 0x8e, 0x48, 0xc6, 0xe6, 0xda, 0x38,
+ 0xed, 0x89, 0x98, 0x84, 0x26, 0x33, 0x4d, 0xa6, 0x74, 0xd8, 0x39, 0x29,
+ 0x82, 0x77, 0x57, 0x28, 0x97, 0x68, 0x4b, 0x48, 0x6e, 0xfc, 0x36, 0x19,
+ 0xb4, 0x49, 0xd7, 0xdc, 0xcd, 0xde, 0x5a, 0x11, 0x23, 0x7b, 0x72, 0x40,
+ 0xc6, 0xdc, 0xa8, 0x91, 0x3b, 0xf9, 0x59, 0xc9, 0xa6, 0x24, 0x86, 0x71,
+ 0xf1, 0x3c, 0x5a, 0x66, 0x4a, 0x03, 0x32, 0xea, 0x8a, 0x91, 0x75, 0xc9,
+ 0xcf, 0x66, 0xb4, 0x37, 0xa8, 0xbe, 0xa8, 0x6b, 0x0d, 0xa9, 0xb9, 0x23,
+ 0xa8, 0xb7, 0x51, 0xdf, 0x68, 0xf4, 0xa9, 0x39, 0x54, 0x7d, 0x62, 0x44,
+ 0xa2, 0xf2, 0x74, 0x29, 0xa6, 0xfb, 0x56, 0x2a, 0xd9, 0x94, 0x8d, 0x7e,
+ 0x03, 0x32, 0xe2, 0xc6, 0x64, 0x10, 0xcf, 0x61, 0x97, 0x72, 0x15, 0x87,
+ 0x4c, 0x35, 0x14, 0xf3, 0x27, 0xd4, 0x7c, 0x89, 0x50, 0x9a, 0xf3, 0xb5,
+ 0xa2, 0xdf, 0xdb, 0xa0, 0xcb, 0x10, 0x4b, 0x9d, 0x65, 0x46, 0xf2, 0xe3,
+ 0x06, 0xe4, 0x0d, 0x4f, 0xc5, 0xd7, 0x3e, 0xd0, 0x6f, 0x89, 0xd3, 0x6d,
+ 0x48, 0x01, 0x67, 0x55, 0xb4, 0x51, 0x2e, 0xcd, 0x9a, 0x59, 0xb7, 0x56,
+ 0x72, 0x56, 0x42, 0x42, 0x13, 0x94, 0xa5, 0x41, 0x19, 0xc1, 0x18, 0xd3,
+ 0x61, 0x9f, 0xb7, 0xb1, 0xef, 0x41, 0x75, 0x0e, 0x35, 0xe9, 0xa2, 0x99,
+ 0x2b, 0x37, 0x8b, 0x39, 0xb9, 0x5f, 0x5e, 0x19, 0x17, 0x3b, 0x94, 0x7e,
+ 0xb7, 0x92, 0x75, 0x46, 0xcd, 0xec, 0xb3, 0x96, 0x84, 0x27, 0x0c, 0x19,
+ 0x75, 0x92, 0xd0, 0x80, 0xa3, 0xe6, 0xee, 0xf2, 0x2c, 0xfa, 0x71, 0x1c,
+ 0xfa, 0x95, 0x4c, 0xf0, 0x95, 0xef, 0xdb, 0x6c, 0x53, 0xc9, 0x33, 0xfb,
+ 0xe0, 0x0c, 0xb0, 0x8f, 0xe7, 0x5c, 0x9c, 0x89, 0x3a, 0xa3, 0x04, 0xce,
+ 0x48, 0x8c, 0xbe, 0x4e, 0xc8, 0xd4, 0x09, 0x4b, 0xf2, 0x29, 0xec, 0x0b,
+ 0xbd, 0xf3, 0xa9, 0x45, 0xba, 0x46, 0xc6, 0xab, 0xe9, 0xe2, 0x38, 0xd2,
+ 0xe5, 0xd1, 0x34, 0x7c, 0x82, 0xf4, 0x2d, 0xd2, 0x33, 0x36, 0xee, 0xd3,
+ 0xc8, 0xf5, 0x48, 0x9b, 0x4f, 0x17, 0xc7, 0x91, 0xae, 0x26, 0x9e, 0x35,
+ 0xff, 0x8c, 0x3e, 0xd0, 0x31, 0xe2, 0x5a, 0x38, 0xa3, 0xa8, 0xe4, 0xed,
+ 0xa2, 0x31, 0xd2, 0xbb, 0x2d, 0x0e, 0x6d, 0x36, 0x86, 0x7b, 0x49, 0xb3,
+ 0x83, 0x73, 0xac, 0x51, 0xe7, 0x0d, 0xf9, 0x26, 0xef, 0xd0, 0x9f, 0xeb,
+ 0xe3, 0xbd, 0x64, 0xcb, 0xa8, 0x9a, 0x8f, 0x34, 0x7d, 0x14, 0xf3, 0x90,
+ 0xd6, 0x4b, 0x90, 0xd5, 0x1e, 0xc8, 0x68, 0x4a, 0xfe, 0xae, 0xbc, 0x5d,
+ 0xbe, 0x53, 0xee, 0x92, 0xbf, 0x81, 0xde, 0xfe, 0x75, 0x39, 0x21, 0x2f,
+ 0x94, 0x5b, 0xe5, 0xdb, 0xe5, 0xb8, 0x3c, 0xaf, 0xe4, 0xb7, 0x4f, 0xa4,
+ 0x81, 0x32, 0x9d, 0x90, 0x46, 0xe8, 0xcf, 0x46, 0xe8, 0xe6, 0x13, 0xe0,
+ 0xdf, 0x89, 0x4e, 0xc9, 0x34, 0xa5, 0x25, 0x72, 0x0b, 0x7e, 0x9b, 0xf1,
+ 0x6b, 0x4e, 0x43, 0xee, 0x5c, 0xf2, 0x8e, 0x3c, 0xb4, 0x24, 0xa7, 0xf6,
+ 0x6c, 0xc9, 0x48, 0x79, 0xfe, 0x16, 0x4f, 0x76, 0x45, 0xfa, 0xc1, 0x63,
+ 0xb3, 0xfb, 0x7f, 0x2a, 0x19, 0x1b, 0xfb, 0xe8, 0xde, 0xa6, 0x78, 0x6f,
+ 0x76, 0x53, 0x66, 0x13, 0x90, 0x7b, 0xcb, 0xc8, 0xb9, 0x67, 0x80, 0x1b,
+ 0xf5, 0x46, 0xf6, 0x78, 0x51, 0x0a, 0xc7, 0x2b, 0x52, 0x48, 0x85, 0xe5,
+ 0x11, 0xbb, 0x22, 0x7d, 0xa9, 0x1a, 0x39, 0x64, 0x83, 0xf7, 0xdb, 0x7f,
+ 0xdf, 0xf0, 0x31, 0xfb, 0x89, 0xf2, 0x61, 0xbc, 0xb3, 0x4e, 0xe4, 0x84,
+ 0x7a, 0xf7, 0xea, 0x8b, 0xe5, 0xb0, 0x64, 0x62, 0xc5, 0xb8, 0x25, 0x2d,
+ 0xa6, 0xb7, 0xee, 0xb0, 0xdf, 0x06, 0x7e, 0x4c, 0x01, 0x27, 0x93, 0x4a,
+ 0x5f, 0xf2, 0xe3, 0xeb, 0xae, 0x66, 0x54, 0x35, 0xfa, 0xdb, 0x3d, 0x32,
+ 0xaf, 0xf8, 0x99, 0x18, 0x34, 0xd2, 0x31, 0x69, 0x2b, 0xb1, 0xdc, 0x6b,
+ 0xdc, 0x5d, 0xa6, 0x3c, 0xe3, 0xbd, 0x4c, 0x3a, 0x6f, 0x42, 0x3f, 0x0b,
+ 0xcf, 0x8c, 0xa6, 0x37, 0x48, 0x23, 0xe7, 0x21, 0x8d, 0x7c, 0xfe, 0x79,
+ 0x80, 0xc6, 0xa7, 0x16, 0xde, 0x4f, 0x04, 0xde, 0x8b, 0xe5, 0x4b, 0x75,
+ 0x1e, 0x6d, 0xbd, 0xf2, 0xc6, 0xc4, 0x57, 0xf4, 0x3a, 0x78, 0x3f, 0xcb,
+ 0xf9, 0xff, 0xaa, 0xe2, 0xc9, 0x4b, 0xf1, 0x3a, 0xeb, 0xcc, 0x06, 0xd6,
+ 0x79, 0x31, 0xb0, 0xce, 0x8b, 0x81, 0x75, 0x8a, 0xe0, 0xa9, 0x6c, 0x30,
+ 0x21, 0xc3, 0x79, 0x9a, 0x31, 0x39, 0x8a, 0x39, 0x5f, 0x97, 0x50, 0x9a,
+ 0x7a, 0xee, 0xe3, 0xcd, 0x65, 0xf4, 0x4f, 0xcb, 0xfc, 0x44, 0x51, 0xf2,
+ 0xc7, 0xc3, 0xb2, 0x4f, 0xf5, 0xdb, 0xa5, 0xe9, 0x0b, 0xb6, 0x45, 0x64,
+ 0x6f, 0x8c, 0xef, 0x7e, 0x9b, 0x05, 0x3e, 0xb3, 0xfc, 0xc6, 0x4d, 0x5e,
+ 0x99, 0xef, 0xb3, 0x7a, 0x2f, 0x03, 0xde, 0xb8, 0xb3, 0x6f, 0x2a, 0x3c,
+ 0x9c, 0x2b, 0x13, 0xb7, 0x24, 0x15, 0x72, 0xe4, 0x60, 0x5f, 0xaa, 0x59,
+ 0x46, 0x6c, 0x23, 0x35, 0xdc, 0x55, 0x4b, 0xbd, 0xc8, 0x98, 0x4e, 0x3d,
+ 0xb0, 0x41, 0x12, 0x26, 0x31, 0x5f, 0xed, 0xcb, 0x30, 0x3d, 0xfa, 0x6d,
+ 0x96, 0xfb, 0x4d, 0xa7, 0xb1, 0xaa, 0x9e, 0xba, 0x1d, 0xc2, 0x3b, 0x65,
+ 0x78, 0xb7, 0x3e, 0x63, 0x0b, 0x65, 0xe2, 0xf0, 0xad, 0xba, 0xec, 0xb7,
+ 0xe3, 0xc0, 0x96, 0x94, 0x7f, 0xb6, 0x65, 0x69, 0xd9, 0xc7, 0x89, 0x20,
+ 0x86, 0x73, 0xaf, 0xc0, 0x27, 0x87, 0x72, 0x17, 0x06, 0xad, 0x29, 0xe8,
+ 0x5c, 0xad, 0xa6, 0x61, 0xb3, 0xa6, 0x01, 0xb4, 0x76, 0x42, 0xb2, 0x94,
+ 0x2e, 0x29, 0xd1, 0xaa, 0x2a, 0x93, 0xf7, 0xfe, 0xfb, 0x7a, 0xd5, 0xee,
+ 0xe9, 0x9c, 0xff, 0xf4, 0xf1, 0xfd, 0xcd, 0x80, 0xbd, 0x68, 0x85, 0xce,
+ 0xc6, 0xc0, 0x2b, 0x1f, 0xeb, 0x89, 0xc1, 0x71, 0xd8, 0x07, 0xc8, 0xaa,
+ 0xc2, 0xf6, 0x28, 0xf0, 0xd0, 0xd2, 0xd8, 0x1c, 0xd1, 0xd8, 0x1c, 0x05,
+ 0x2e, 0xb3, 0x6c, 0xeb, 0x72, 0x4c, 0x97, 0xe3, 0x28, 0xc3, 0x8e, 0x4f,
+ 0x12, 0xbb, 0x1b, 0x8a, 0x43, 0x27, 0x14, 0xde, 0xd3, 0x56, 0x00, 0x85,
+ 0x89, 0xd7, 0xc4, 0xed, 0x56, 0x99, 0x2e, 0x61, 0xbd, 0x05, 0x6c, 0xe4,
+ 0xde, 0x83, 0xf4, 0x90, 0x96, 0x75, 0x62, 0xc2, 0x76, 0x65, 0x62, 0xa4,
+ 0xf7, 0x61, 0xec, 0x9d, 0xf8, 0x43, 0xba, 0x6f, 0x06, 0xad, 0xdc, 0xc7,
+ 0x27, 0x49, 0x2b, 0xd7, 0xab, 0xa6, 0xf7, 0xc3, 0xe2, 0x20, 0x69, 0x3f,
+ 0x83, 0x3d, 0x67, 0x80, 0x79, 0x62, 0x0c, 0x74, 0x0e, 0x60, 0xcf, 0xfd,
+ 0xc0, 0xc3, 0xbb, 0x80, 0x87, 0x7b, 0x80, 0x87, 0x7d, 0xc0, 0xc3, 0x34,
+ 0xb0, 0xb0, 0x17, 0x58, 0xd8, 0x03, 0x2c, 0x4c, 0x81, 0x37, 0x31, 0x99,
+ 0x02, 0x36, 0x4e, 0x01, 0x23, 0xa7, 0x30, 0xc7, 0xf0, 0xa4, 0x18, 0x0f,
+ 0x60, 0x0f, 0xdf, 0x9c, 0x48, 0x9e, 0x82, 0x2c, 0xc5, 0x8b, 0x26, 0xe4,
+ 0x3f, 0xd5, 0x0b, 0xd9, 0xee, 0x92, 0x99, 0xb2, 0x25, 0x05, 0xd8, 0xd4,
+ 0xb6, 0xad, 0xed, 0xd0, 0x35, 0xc8, 0x7b, 0x5c, 0xf4, 0xdf, 0x7a, 0xfd,
+ 0xfc, 0xb1, 0x88, 0xf3, 0x4f, 0x94, 0xc5, 0x84, 0xc8, 0x79, 0xc9, 0xbb,
+ 0xed, 0x76, 0x9b, 0xd9, 0x85, 0x7e, 0x2c, 0xa7, 0xcc, 0x03, 0xc7, 0xef,
+ 0x30, 0x87, 0x8e, 0x2b, 0x7f, 0x05, 0x78, 0x55, 0x91, 0xd1, 0x14, 0x75,
+ 0xab, 0x22, 0xa7, 0x53, 0xc9, 0xde, 0xa2, 0xd4, 0xcb, 0x58, 0x6c, 0x5c,
+ 0xd9, 0x5a, 0x2b, 0x7d, 0x4c, 0xd9, 0xab, 0x82, 0x83, 0x67, 0xa9, 0xdb,
+ 0xcc, 0x1f, 0xe7, 0xfe, 0xdb, 0xf1, 0x0b, 0x83, 0x16, 0xce, 0x6f, 0x49,
+ 0x5f, 0x8f, 0x6d, 0x3e, 0xd4, 0x59, 0x84, 0x42, 0x24, 0xed, 0x79, 0xac,
+ 0x9c, 0x1b, 0x6f, 0x8f, 0xb7, 0x9b, 0x96, 0x0c, 0x5a, 0x86, 0x0c, 0x43,
+ 0xbe, 0xfb, 0x52, 0x6f, 0x57, 0xc6, 0x62, 0x6c, 0xaf, 0x95, 0xaf, 0x2b,
+ 0x9f, 0x03, 0x6b, 0xcf, 0x9c, 0xc0, 0xba, 0x61, 0x9c, 0x01, 0xd7, 0xe5,
+ 0x3c, 0x28, 0x97, 0x2c, 0x94, 0x93, 0xa7, 0x8a, 0x52, 0x86, 0x9e, 0x6c,
+ 0x90, 0xec, 0xf6, 0x1a, 0xc9, 0xf4, 0x27, 0x64, 0x78, 0xa2, 0x0c, 0x9c,
+ 0x8a, 0x28, 0x5d, 0xc9, 0x0f, 0x24, 0xe4, 0xf1, 0x09, 0xd6, 0x9d, 0xc3,
+ 0xfe, 0x93, 0xc7, 0x32, 0xc2, 0xfd, 0x1b, 0x92, 0xd9, 0x7f, 0x4e, 0x1e,
+ 0x71, 0xcf, 0xc9, 0x10, 0xce, 0xf0, 0xe9, 0xf2, 0xac, 0x1c, 0x70, 0x1d,
+ 0x39, 0x0d, 0xbc, 0xcf, 0x1d, 0x07, 0xee, 0x39, 0xeb, 0x81, 0x51, 0xc9,
+ 0x73, 0xb4, 0xa1, 0x26, 0xfc, 0xbc, 0x69, 0xf0, 0xf7, 0x89, 0x09, 0xf2,
+ 0xd7, 0x94, 0x47, 0x7f, 0xd1, 0x80, 0x3e, 0x26, 0xc0, 0xcf, 0x56, 0x39,
+ 0xec, 0x26, 0x67, 0x33, 0x26, 0x70, 0x31, 0x65, 0x87, 0xa4, 0x2e, 0x8e,
+ 0x7e, 0x5e, 0x9f, 0x5c, 0x2a, 0x84, 0xb3, 0x2e, 0xa2, 0xef, 0xdb, 0xa0,
+ 0x93, 0x63, 0x63, 0xf8, 0x65, 0xd0, 0x0f, 0xf2, 0x6b, 0x27, 0x67, 0xa7,
+ 0x4c, 0xf6, 0x4f, 0xe0, 0xcc, 0x80, 0x2b, 0x93, 0x00, 0x1e, 0x9b, 0xef,
+ 0x69, 0x33, 0x4f, 0x1a, 0x5c, 0xca, 0x59, 0x02, 0x34, 0x11, 0xd3, 0xda,
+ 0xcf, 0x7d, 0x47, 0xb8, 0xce, 0x46, 0xf4, 0x7f, 0x07, 0x7e, 0xae, 0x2d,
+ 0x33, 0x38, 0x97, 0x9f, 0x82, 0x57, 0x99, 0xb8, 0x57, 0x1e, 0x9e, 0x4c,
+ 0x9e, 0x9b, 0x37, 0xf9, 0xee, 0x14, 0xf3, 0xe6, 0x6d, 0x22, 0x8d, 0xe4,
+ 0x57, 0x0a, 0xbc, 0x72, 0x6c, 0xd3, 0xdc, 0xaa, 0x7d, 0x3b, 0xea, 0x89,
+ 0x03, 0x9a, 0xe0, 0x67, 0x74, 0x07, 0xf5, 0x84, 0xf6, 0xce, 0xd7, 0x93,
+ 0x64, 0x7c, 0xca, 0x84, 0xff, 0xd1, 0x6d, 0xc9, 0x31, 0x55, 0x06, 0x8f,
+ 0x06, 0x92, 0xf1, 0x8c, 0x49, 0x9f, 0xb7, 0x4b, 0x9e, 0x76, 0xd9, 0x1f,
+ 0x7c, 0x1c, 0x8f, 0xea, 0xfe, 0xe7, 0x20, 0x23, 0xf4, 0xcf, 0xba, 0x40,
+ 0xb3, 0xa7, 0x3b, 0xd3, 0xe3, 0x31, 0xd5, 0x36, 0xa6, 0xf6, 0x60, 0x60,
+ 0x5d, 0xc8, 0x26, 0x7c, 0xb5, 0x9c, 0xd2, 0x23, 0x3b, 0x03, 0x5f, 0x1e,
+ 0x7a, 0xe0, 0xe9, 0xd0, 0x4c, 0x89, 0xb4, 0xdc, 0x43, 0x7e, 0x14, 0x41,
+ 0xcc, 0x31, 0x33, 0x8d, 0x73, 0xed, 0x91, 0x22, 0xfd, 0xb9, 0xf9, 0xd0,
+ 0xd3, 0x32, 0x38, 0x43, 0x7b, 0x83, 0x9f, 0xeb, 0xd8, 0x8c, 0x1f, 0x32,
+ 0xca, 0x16, 0x6c, 0xc1, 0x39, 0xc3, 0x4e, 0xa4, 0x36, 0x6a, 0x3f, 0xe6,
+ 0x49, 0x9c, 0xdb, 0x79, 0x9c, 0x6b, 0x49, 0x86, 0x4e, 0x5e, 0xa2, 0xcc,
+ 0x76, 0xcd, 0x48, 0xb2, 0x6b, 0x4c, 0xb6, 0xd9, 0xd3, 0xd0, 0xb7, 0xcc,
+ 0x40, 0x65, 0x97, 0x99, 0xe6, 0x98, 0x23, 0x18, 0x83, 0xe7, 0xcc, 0x25,
+ 0x39, 0x54, 0x66, 0xdd, 0xef, 0x80, 0x9f, 0xb0, 0x3b, 0x3d, 0x4f, 0x6a,
+ 0x39, 0xc7, 0x7c, 0x96, 0x3f, 0xdf, 0x25, 0x3d, 0x1f, 0xfb, 0xb1, 0x0f,
+ 0xc7, 0x2c, 0xce, 0xbb, 0x9b, 0xb6, 0x06, 0x78, 0xd3, 0x61, 0x56, 0x76,
+ 0x85, 0xd1, 0x7e, 0xba, 0x87, 0xef, 0x98, 0x07, 0xb6, 0xc6, 0x76, 0xce,
+ 0xa3, 0x2f, 0xf6, 0xe5, 0xae, 0x93, 0xb6, 0x66, 0x9f, 0x5e, 0x9e, 0x3b,
+ 0xfd, 0x00, 0x96, 0x1f, 0x6e, 0xf2, 0x78, 0x3f, 0x12, 0xf2, 0xb0, 0xfb,
+ 0x2f, 0x51, 0xa6, 0x7e, 0x3d, 0x26, 0x39, 0x37, 0x89, 0x7d, 0x42, 0x87,
+ 0xca, 0x0d, 0x86, 0xb7, 0x47, 0xf0, 0xbf, 0xff, 0x32, 0xf8, 0x20, 0x45,
+ 0x8f, 0x37, 0xe4, 0x0b, 0x79, 0xd2, 0x00, 0xd9, 0xae, 0xc3, 0xbc, 0x58,
+ 0x47, 0xf1, 0xe0, 0x96, 0x26, 0xcf, 0xef, 0x4d, 0x16, 0x33, 0x8c, 0xd7,
+ 0x1a, 0x29, 0xb3, 0xc0, 0xa8, 0xf2, 0xfd, 0x36, 0xe7, 0x9e, 0x32, 0xd7,
+ 0x91, 0xde, 0xc4, 0x85, 0xd0, 0x7e, 0x96, 0xbb, 0xa6, 0x4c, 0xf0, 0x1e,
+ 0xe7, 0x93, 0xdd, 0xde, 0xae, 0x71, 0xe9, 0x99, 0x10, 0x65, 0x94, 0xf2,
+ 0x9c, 0x77, 0xb7, 0xd9, 0xf7, 0x08, 0x65, 0x34, 0x86, 0xf3, 0x26, 0x2e,
+ 0xf0, 0x69, 0xc1, 0x26, 0xc6, 0x71, 0xc6, 0x5b, 0x34, 0xed, 0x7c, 0xb7,
+ 0x64, 0xca, 0xc6, 0x1a, 0xee, 0x7f, 0x6f, 0xf0, 0xea, 0xf8, 0xde, 0xc2,
+ 0x33, 0x39, 0xb6, 0x94, 0x56, 0x9e, 0x67, 0xf5, 0x19, 0x9e, 0x06, 0xed,
+ 0xac, 0xc7, 0x73, 0xe6, 0x14, 0xf4, 0x0f, 0x58, 0xd1, 0xd3, 0x11, 0xbf,
+ 0x88, 0xfe, 0x39, 0x60, 0x7c, 0xd1, 0x62, 0xdb, 0x55, 0x63, 0x71, 0x8c,
+ 0x49, 0x3f, 0x13, 0x3e, 0xed, 0x05, 0xe3, 0x81, 0xf2, 0x2b, 0x46, 0x76,
+ 0xe6, 0xaa, 0x91, 0x83, 0x5c, 0xcc, 0xb8, 0x3b, 0x20, 0xcf, 0xd4, 0x17,
+ 0x1b, 0x6b, 0x27, 0xe3, 0xff, 0x62, 0xb6, 0x27, 0xa6, 0xa1, 0xdb, 0x07,
+ 0xc0, 0x58, 0xef, 0x2c, 0x5b, 0xd5, 0xd9, 0xce, 0x9b, 0x61, 0x8d, 0x75,
+ 0x2c, 0x27, 0xed, 0x7b, 0xe5, 0x35, 0xec, 0x77, 0x16, 0x7c, 0x9e, 0x95,
+ 0x42, 0xb9, 0x24, 0xf9, 0x93, 0xdb, 0xec, 0x61, 0xc4, 0xb8, 0x8b, 0xb4,
+ 0x13, 0xc3, 0x8a, 0xf4, 0xbd, 0x8d, 0xdd, 0xae, 0x14, 0x6b, 0xd2, 0xc4,
+ 0xb2, 0x0e, 0xc8, 0x13, 0xea, 0x4a, 0x8b, 0x32, 0x79, 0xe7, 0xb2, 0xfd,
+ 0x20, 0xbe, 0xed, 0x59, 0xba, 0xa7, 0x19, 0xb9, 0xfe, 0x9e, 0x76, 0x2f,
+ 0xec, 0x89, 0xd8, 0x01, 0xcc, 0x77, 0x81, 0xf9, 0x2e, 0x30, 0xdf, 0x05,
+ 0xe6, 0xbb, 0xc0, 0x7c, 0x17, 0xf6, 0xc0, 0x05, 0xee, 0xbb, 0xc0, 0x7d,
+ 0x17, 0xb8, 0xef, 0x02, 0xf7, 0xdd, 0x2c, 0xce, 0x8e, 0xd8, 0x4e, 0xbb,
+ 0x71, 0xdf, 0x82, 0xad, 0xf4, 0x7c, 0x9b, 0x9b, 0xb4, 0xbf, 0x00, 0x9d,
+ 0xb4, 0x5b, 0x64, 0xb8, 0x6b, 0x33, 0xf6, 0x56, 0x87, 0x67, 0x3d, 0x9e,
+ 0x58, 0xa3, 0xeb, 0x33, 0x5a, 0x77, 0xbe, 0x0a, 0xba, 0x4c, 0x94, 0x7f,
+ 0x09, 0xb2, 0x59, 0x03, 0x7a, 0x7e, 0x41, 0xfb, 0x15, 0xa7, 0x2c, 0x4f,
+ 0x36, 0xeb, 0x51, 0xf7, 0x69, 0xd4, 0xd5, 0xa3, 0xcf, 0x21, 0xf4, 0xa1,
+ 0x5f, 0xd2, 0xa0, 0xeb, 0x82, 0xfd, 0xe8, 0x9f, 0xfc, 0x26, 0xd6, 0x4a,
+ 0xa2, 0x5f, 0x03, 0xe6, 0x6e, 0x45, 0x9f, 0xcf, 0xa2, 0xcf, 0xcd, 0x28,
+ 0xd3, 0x9f, 0xdd, 0x82, 0xf2, 0xa7, 0xaa, 0xc6, 0xdc, 0x8a, 0xba, 0xcf,
+ 0x54, 0xd5, 0xcd, 0xa3, 0x0e, 0x71, 0xb0, 0x7d, 0x51, 0x8f, 0x2b, 0xa2,
+ 0xdc, 0x5c, 0xd5, 0xe7, 0x12, 0xea, 0x7a, 0x51, 0xf7, 0x3d, 0x3c, 0x11,
+ 0xff, 0xda, 0xa4, 0xc9, 0x6f, 0xa3, 0x6f, 0x9a, 0x40, 0x7d, 0x58, 0xfb,
+ 0x97, 0x4f, 0xd2, 0xdf, 0x82, 0x9d, 0xfd, 0x53, 0xcb, 0xf3, 0xc7, 0x9e,
+ 0xb1, 0x3d, 0x59, 0xf5, 0xcb, 0x3f, 0xaa, 0x2a, 0xb3, 0xef, 0xff, 0x56,
+ 0xd5, 0xed, 0xda, 0xb8, 0xb4, 0xfc, 0x7e, 0x78, 0xf9, 0x98, 0xe3, 0x55,
+ 0x7d, 0x5e, 0x6e, 0x5c, 0x5a, 0xfe, 0x7c, 0xcd, 0xf2, 0x31, 0xbf, 0xb5,
+ 0x61, 0x69, 0xdd, 0xe1, 0xa6, 0xa5, 0x65, 0xfa, 0x7d, 0x31, 0xc4, 0x2d,
+ 0x7e, 0xff, 0x07, 0x37, 0x79, 0xed, 0xe4, 0x6f, 0xb5, 0x2c, 0x29, 0xe3,
+ 0x8d, 0xb2, 0x89, 0x73, 0xb8, 0x60, 0x40, 0xe7, 0x6c, 0x33, 0xfd, 0x8a,
+ 0x91, 0x83, 0x4c, 0x65, 0xcb, 0xfe, 0x7c, 0xd4, 0xe5, 0xea, 0xdc, 0x80,
+ 0x9f, 0x13, 0xa0, 0x8f, 0x15, 0x85, 0xdc, 0x00, 0x8b, 0x63, 0xc9, 0xa3,
+ 0x45, 0x59, 0xd4, 0xe1, 0x36, 0xf3, 0x5a, 0x3a, 0x3c, 0xa9, 0x71, 0xeb,
+ 0x32, 0xe8, 0xac, 0x48, 0x7f, 0xaa, 0x96, 0x76, 0x47, 0xe3, 0x19, 0xb1,
+ 0xa8, 0x52, 0x09, 0x6d, 0xad, 0xc8, 0xc1, 0xd4, 0x3b, 0x15, 0x51, 0x38,
+ 0xf8, 0x4d, 0xcd, 0x57, 0xe2, 0xa1, 0x0d, 0xb9, 0x8d, 0x29, 0x3f, 0x2e,
+ 0x94, 0x3e, 0x45, 0x9f, 0xe4, 0x88, 0x87, 0xb3, 0xc4, 0x22, 0x94, 0xcb,
+ 0x63, 0xe8, 0xc3, 0xf5, 0xf1, 0x9c, 0x21, 0xb6, 0x5b, 0xca, 0xce, 0xe4,
+ 0x6d, 0xce, 0xbb, 0x12, 0x5e, 0xfe, 0xd8, 0xa2, 0x2f, 0x68, 0x39, 0x67,
+ 0x60, 0xf3, 0xd8, 0x46, 0xff, 0xe0, 0x0c, 0x7d, 0x91, 0x80, 0x6f, 0xd3,
+ 0x11, 0x12, 0x67, 0x11, 0x47, 0xbd, 0x7d, 0xb5, 0xd0, 0xd7, 0x5f, 0xc3,
+ 0x5e, 0x57, 0xc6, 0xab, 0x76, 0xf3, 0xfa, 0xba, 0xbd, 0x77, 0x41, 0xb7,
+ 0x7d, 0xd9, 0x5b, 0x29, 0x07, 0x70, 0x45, 0x9d, 0xc5, 0xf3, 0xe5, 0xe4,
+ 0xb1, 0x22, 0x74, 0x69, 0x4e, 0xc5, 0xbb, 0xfe, 0xb9, 0xd0, 0xaf, 0x49,
+ 0x9e, 0x9a, 0x82, 0x6c, 0x0f, 0xa9, 0x38, 0x80, 0x31, 0x40, 0x45, 0x76,
+ 0xa7, 0x86, 0x62, 0xe4, 0x43, 0xc6, 0xbc, 0x1a, 0xa6, 0x1f, 0x31, 0xe7,
+ 0x92, 0x67, 0x29, 0xb4, 0xa7, 0xc0, 0xdb, 0x7f, 0x95, 0x5c, 0x8c, 0x75,
+ 0xff, 0x55, 0x99, 0x86, 0xff, 0xa3, 0x7c, 0x22, 0xe5, 0x03, 0xd0, 0xa7,
+ 0x83, 0xad, 0x2f, 0x93, 0xa7, 0x17, 0xc0, 0x67, 0xdf, 0x2f, 0xb8, 0x4c,
+ 0xbf, 0x54, 0x96, 0xfa, 0xcf, 0x22, 0x8f, 0x94, 0xfe, 0x19, 0x76, 0xc8,
+ 0xc4, 0x7c, 0xb4, 0x77, 0xb4, 0x29, 0xac, 0xdf, 0x11, 0xa6, 0xff, 0xe6,
+ 0xd9, 0xff, 0x10, 0xd6, 0x43, 0x4c, 0x5d, 0xfa, 0x0f, 0x23, 0xef, 0xb6,
+ 0xd2, 0xb7, 0xc2, 0xfe, 0x89, 0xab, 0x6c, 0x63, 0x5d, 0x44, 0xfb, 0xdc,
+ 0x51, 0xed, 0x63, 0xdb, 0xda, 0xc7, 0x26, 0x1d, 0x46, 0xc4, 0x4e, 0xfb,
+ 0xbe, 0x02, 0xcf, 0x0c, 0x67, 0xb3, 0x55, 0xf9, 0x0a, 0xb2, 0xb2, 0xaf,
+ 0xe0, 0xd3, 0x74, 0x16, 0xfb, 0xa4, 0x6f, 0xa7, 0x72, 0x3f, 0x8d, 0x5e,
+ 0xbe, 0x89, 0x34, 0xf8, 0x36, 0x53, 0xd9, 0xe6, 0xa3, 0x30, 0x83, 0xd8,
+ 0xdb, 0x6f, 0x83, 0xd6, 0x3d, 0x92, 0x1d, 0x3f, 0xab, 0x6d, 0x30, 0x63,
+ 0x07, 0xfa, 0xed, 0x9e, 0xcc, 0x66, 0x53, 0x0d, 0x86, 0x9e, 0xa7, 0x19,
+ 0x56, 0x33, 0x90, 0x97, 0xe2, 0x5a, 0xf4, 0x6d, 0x7c, 0x3f, 0x67, 0x56,
+ 0xfb, 0x39, 0xe7, 0xe5, 0xa0, 0xeb, 0xc5, 0x0a, 0xfd, 0xa5, 0x0b, 0xa8,
+ 0x53, 0xb4, 0xc7, 0xe9, 0x4f, 0x9a, 0x26, 0xfd, 0xc9, 0x24, 0x82, 0x0e,
+ 0x6f, 0x2f, 0x6d, 0xd8, 0xcb, 0xcc, 0xc2, 0x5e, 0xea, 0x2f, 0x2c, 0xdd,
+ 0x0b, 0xe9, 0xb7, 0xc1, 0x4f, 0x4b, 0xe3, 0x14, 0xe7, 0xfc, 0x46, 0x98,
+ 0x18, 0xd6, 0x4f, 0x9f, 0xc8, 0xf5, 0x7c, 0xb1, 0xa5, 0xf3, 0xc2, 0x63,
+ 0x28, 0x4d, 0x5d, 0xa3, 0x8d, 0xfb, 0xf7, 0xf5, 0xca, 0xd2, 0xd8, 0xce,
+ 0x3d, 0xfc, 0x09, 0xe6, 0x8c, 0x19, 0x79, 0xe5, 0x9b, 0xd1, 0xcf, 0x41,
+ 0xdc, 0x5d, 0x7a, 0x05, 0x4f, 0xea, 0x8e, 0x9a, 0x07, 0xfb, 0x8d, 0xaa,
+ 0xfd, 0x8e, 0xb9, 0x97, 0xd4, 0x1e, 0xa7, 0x4b, 0x3f, 0x90, 0xc2, 0xc9,
+ 0x1f, 0xc2, 0x26, 0x06, 0x73, 0x75, 0xcc, 0x73, 0x92, 0x57, 0xc5, 0x00,
+ 0xb6, 0x92, 0x66, 0xe6, 0xe1, 0xbe, 0x17, 0xf6, 0xe2, 0x85, 0x71, 0x9c,
+ 0xbf, 0xe1, 0xb5, 0xab, 0xf5, 0x7d, 0x9e, 0xd7, 0x04, 0xe8, 0xa9, 0xc0,
+ 0x47, 0x8d, 0x83, 0x86, 0xe0, 0x98, 0xc7, 0xa4, 0xcf, 0xe5, 0x59, 0xb5,
+ 0xc7, 0x87, 0xc4, 0xb1, 0xf3, 0xe2, 0xfb, 0x25, 0x5c, 0x9f, 0x78, 0x90,
+ 0x43, 0x0c, 0xc5, 0xdc, 0xaa, 0xcf, 0x57, 0x9f, 0xa7, 0xd1, 0x0b, 0xd5,
+ 0xf2, 0x31, 0x8a, 0xd8, 0xab, 0xe0, 0x92, 0x4f, 0xbe, 0xdc, 0xfa, 0x6b,
+ 0x5f, 0x31, 0xb8, 0x9f, 0x11, 0x95, 0x4f, 0x7c, 0x6d, 0x41, 0x7e, 0x87,
+ 0x81, 0x2b, 0x9e, 0x3c, 0xbe, 0xaa, 0x79, 0xe3, 0xcb, 0x6d, 0x54, 0xcb,
+ 0x00, 0x63, 0x43, 0xea, 0x95, 0x2f, 0x23, 0x1d, 0xf6, 0xdd, 0x8a, 0x17,
+ 0x6c, 0x53, 0x79, 0x46, 0x75, 0xce, 0x83, 0x0b, 0xe7, 0xbc, 0xbe, 0x4a,
+ 0x66, 0x53, 0xb6, 0xa7, 0xa3, 0xd4, 0x45, 0xe8, 0x34, 0xf8, 0xf5, 0xfc,
+ 0x12, 0xdd, 0xef, 0xba, 0x46, 0x8e, 0x36, 0x2a, 0xa1, 0xc9, 0x97, 0xc1,
+ 0xcb, 0x5b, 0x11, 0xbb, 0x88, 0x58, 0x13, 0xc4, 0x28, 0xfa, 0x22, 0x8b,
+ 0xfe, 0xf1, 0xb4, 0xac, 0xe4, 0x1b, 0x5f, 0xcf, 0x0f, 0xb9, 0x7d, 0x8d,
+ 0x7e, 0xc8, 0xaf, 0xd6, 0x30, 0x96, 0x99, 0x83, 0x9e, 0x1e, 0xc0, 0xf8,
+ 0x1a, 0xe7, 0x47, 0xb0, 0x6f, 0xa7, 0xad, 0x5a, 0xc7, 0xc7, 0x8b, 0xa8,
+ 0x6c, 0x9c, 0xdc, 0xa2, 0x30, 0xc3, 0x9e, 0x58, 0xc4, 0x8c, 0x61, 0x97,
+ 0xf2, 0xab, 0xf4, 0x34, 0xb6, 0x51, 0x7c, 0x8c, 0x78, 0xd6, 0x62, 0xbe,
+ 0x67, 0x65, 0x1c, 0xf0, 0x72, 0xba, 0x2b, 0xc7, 0x0a, 0x37, 0x55, 0xf1,
+ 0x72, 0x25, 0xdc, 0x3c, 0x07, 0xde, 0xa5, 0x11, 0x13, 0x27, 0xcf, 0x88,
+ 0xec, 0x41, 0x9c, 0x9c, 0x7c, 0x4b, 0xa4, 0x0f, 0xb1, 0x72, 0x72, 0x56,
+ 0x24, 0x83, 0x78, 0x99, 0xf1, 0xdb, 0x5d, 0xe0, 0x69, 0x2f, 0xe2, 0xe9,
+ 0x1e, 0x60, 0x6a, 0x0a, 0x18, 0xbb, 0x1d, 0xfc, 0xed, 0x02, 0xbf, 0x6d,
+ 0xc4, 0x5b, 0x65, 0x39, 0x70, 0x5c, 0x8c, 0x7d, 0x2a, 0x7f, 0x4d, 0x7d,
+ 0x8f, 0xc1, 0xce, 0x56, 0x2a, 0x87, 0x52, 0xed, 0x88, 0xf5, 0x13, 0xf2,
+ 0x39, 0x8b, 0xb1, 0xad, 0x61, 0xb5, 0x75, 0x7f, 0x3f, 0x14, 0xf4, 0x6b,
+ 0xb3, 0xd7, 0xb5, 0x13, 0xcb, 0xf9, 0x9f, 0x53, 0xb6, 0xe2, 0xc5, 0xd0,
+ 0x6a, 0xfc, 0xdf, 0xb7, 0xc0, 0xff, 0x9e, 0x3a, 0xa9, 0xbb, 0x4b, 0xe5,
+ 0x16, 0xda, 0xba, 0x0f, 0x11, 0xcf, 0x52, 0xb0, 0xfb, 0xb0, 0xcf, 0x15,
+ 0xb9, 0x33, 0x75, 0xb5, 0x72, 0xd1, 0xd9, 0x20, 0xf9, 0xed, 0x0f, 0x6a,
+ 0x4c, 0x3f, 0xf5, 0x87, 0x59, 0xa7, 0x08, 0x1d, 0xf1, 0xf2, 0x88, 0x43,
+ 0xe3, 0x11, 0x58, 0x0a, 0xfe, 0x35, 0xca, 0x74, 0xef, 0x55, 0x9c, 0xe3,
+ 0xb6, 0x33, 0x4c, 0x42, 0x11, 0x6b, 0xa6, 0x63, 0x51, 0x95, 0x43, 0xde,
+ 0xe4, 0xb0, 0xde, 0xc6, 0xb9, 0x0e, 0xc8, 0x34, 0xfc, 0x8b, 0x99, 0x5e,
+ 0xd0, 0xb8, 0xbd, 0x19, 0xfd, 0xa9, 0x7b, 0xe4, 0xf9, 0x80, 0x0c, 0xc6,
+ 0xc8, 0xd3, 0x18, 0xfa, 0xef, 0x45, 0x9f, 0x46, 0x3c, 0xff, 0x28, 0x34,
+ 0x6d, 0x33, 0x9e, 0xfe, 0x3c, 0xca, 0x9c, 0x23, 0x68, 0x5b, 0x77, 0x85,
+ 0x45, 0xcd, 0xc9, 0x31, 0xcd, 0x0a, 0x03, 0x16, 0xd7, 0xe2, 0x3a, 0x6c,
+ 0x7b, 0xaf, 0x72, 0x47, 0x77, 0x6f, 0x60, 0xbd, 0x86, 0xc0, 0x7a, 0xbd,
+ 0x81, 0xf5, 0x48, 0x67, 0x63, 0x80, 0xce, 0x46, 0x8c, 0xff, 0x5d, 0xac,
+ 0x4d, 0x7e, 0x04, 0xd7, 0xcc, 0x07, 0xd6, 0xf4, 0xf7, 0xd7, 0x1c, 0x18,
+ 0xf7, 0x0e, 0xd6, 0x63, 0x5d, 0x2c, 0x50, 0x47, 0x1a, 0x9a, 0x50, 0xc7,
+ 0x72, 0x63, 0x80, 0xae, 0xa8, 0x8a, 0xf7, 0xa7, 0xd5, 0x19, 0x92, 0xcf,
+ 0x75, 0xb0, 0x6b, 0x26, 0x6c, 0x4b, 0x0d, 0xfc, 0xaf, 0xea, 0xbd, 0x7e,
+ 0x0d, 0xeb, 0xfa, 0xf3, 0xc5, 0x30, 0x07, 0xfb, 0xb3, 0x6f, 0x48, 0x8f,
+ 0x67, 0x3d, 0xdb, 0xff, 0xb6, 0xf2, 0x8c, 0xe2, 0x5b, 0x1a, 0xb4, 0x93,
+ 0xc6, 0x36, 0x99, 0x6a, 0xb4, 0x70, 0x9e, 0xa6, 0xb6, 0xa5, 0xc0, 0xda,
+ 0xb2, 0x69, 0xb4, 0x77, 0xf3, 0xfc, 0x37, 0x68, 0x4c, 0xad, 0x33, 0xb2,
+ 0xc7, 0x99, 0x4b, 0xa8, 0xd7, 0xb1, 0x22, 0xe2, 0x13, 0x65, 0x87, 0x7c,
+ 0x3b, 0x41, 0x3b, 0x44, 0xdf, 0x86, 0x36, 0xf6, 0x9c, 0x7e, 0xc7, 0x13,
+ 0x72, 0xfc, 0xd0, 0x4c, 0xa3, 0x5c, 0x54, 0x7c, 0xb5, 0x65, 0x7e, 0x81,
+ 0xaf, 0x61, 0xfd, 0xbd, 0xe6, 0x31, 0xfd, 0x2d, 0x64, 0x3f, 0x7c, 0x27,
+ 0xbc, 0x97, 0x32, 0xa0, 0x23, 0x21, 0xed, 0xdd, 0xcc, 0x61, 0x14, 0xf1,
+ 0x74, 0xf0, 0x34, 0xf0, 0x84, 0xcd, 0x42, 0x0c, 0xd2, 0xde, 0xcd, 0x58,
+ 0x50, 0x40, 0xdb, 0x15, 0x15, 0x07, 0xce, 0x94, 0x6d, 0xe3, 0x4e, 0xd7,
+ 0xcb, 0x1d, 0xcd, 0x3b, 0xab, 0xe5, 0x8e, 0x1e, 0xa8, 0xc5, 0x79, 0x9c,
+ 0xf2, 0x73, 0x47, 0xf3, 0xa2, 0x72, 0x47, 0xa7, 0xae, 0x93, 0x3b, 0xca,
+ 0xac, 0x3d, 0x77, 0xc4, 0xf9, 0x2d, 0xb9, 0xbb, 0xc7, 0x36, 0xbf, 0xa8,
+ 0x73, 0x47, 0x6f, 0x88, 0x97, 0x3b, 0xba, 0x28, 0x2b, 0xe7, 0x8e, 0x8e,
+ 0x56, 0xe5, 0x8e, 0x9a, 0x54, 0xee, 0x88, 0xf3, 0x78, 0xb9, 0x23, 0x96,
+ 0xf3, 0xdd, 0xbf, 0xac, 0x72, 0xe9, 0xf9, 0x6e, 0x60, 0xb0, 0xeb, 0x63,
+ 0x9c, 0x6d, 0x0c, 0xa8, 0xf8, 0xf2, 0x4a, 0xb8, 0xd9, 0xf1, 0x31, 0x8e,
+ 0xb6, 0x60, 0xf3, 0x82, 0x3d, 0xf3, 0xf1, 0x6e, 0x54, 0xd9, 0xbd, 0xe5,
+ 0xf9, 0xc5, 0x7b, 0xaa, 0xf2, 0x8b, 0x03, 0x9e, 0xdd, 0x50, 0x38, 0x37,
+ 0xa8, 0x71, 0x6e, 0x74, 0xc1, 0xcf, 0x39, 0x59, 0xcb, 0x18, 0x7c, 0xa4,
+ 0x14, 0xc4, 0x51, 0x4b, 0x8d, 0xf5, 0xf2, 0x2c, 0x8b, 0x18, 0x7a, 0xb8,
+ 0x0a, 0x43, 0x1f, 0x5b, 0xf1, 0xbb, 0x58, 0x3c, 0xb3, 0xfc, 0xbb, 0x98,
+ 0x21, 0xcd, 0xf4, 0x39, 0xba, 0xf3, 0xd8, 0x03, 0x63, 0xe6, 0xfd, 0x92,
+ 0x19, 0xb0, 0x81, 0x45, 0x7e, 0xfe, 0x85, 0xe7, 0xbc, 0x68, 0x63, 0xb2,
+ 0xe6, 0xc7, 0x97, 0x83, 0x79, 0x48, 0xe5, 0x60, 0xbe, 0x5f, 0x1b, 0xcc,
+ 0xc1, 0xcc, 0x03, 0xb3, 0x32, 0x16, 0xf3, 0x5b, 0x2b, 0xe7, 0x60, 0x1e,
+ 0x5a, 0x21, 0x07, 0xf3, 0x5d, 0x59, 0xcc, 0xc1, 0x7c, 0x57, 0xfc, 0x1c,
+ 0x0c, 0xe7, 0x08, 0x69, 0x9f, 0x56, 0x30, 0xee, 0x02, 0x7e, 0xe7, 0xf1,
+ 0xf3, 0xf2, 0x32, 0xf3, 0x0b, 0x7b, 0x58, 0x29, 0x2f, 0xf3, 0x6f, 0xb5,
+ 0x1f, 0x24, 0x2f, 0xe3, 0xd9, 0x04, 0x3f, 0x2f, 0x83, 0x9f, 0x0d, 0x1b,
+ 0x64, 0x06, 0xf3, 0x32, 0xef, 0x53, 0x37, 0x50, 0xc7, 0x32, 0xeb, 0xa1,
+ 0x23, 0xb0, 0x53, 0x19, 0xd8, 0x99, 0x69, 0xf7, 0xd7, 0xd5, 0x79, 0xcc,
+ 0xb8, 0x53, 0xd8, 0x77, 0x02, 0xe7, 0x41, 0x5e, 0xb6, 0x2b, 0x5f, 0x34,
+ 0x63, 0xc5, 0x8d, 0x6c, 0x27, 0xac, 0xda, 0x38, 0xbf, 0x9d, 0x5b, 0xc6,
+ 0x50, 0x99, 0xf2, 0x1e, 0x31, 0x0a, 0xd8, 0x4b, 0xdf, 0xf8, 0x94, 0x0c,
+ 0x95, 0x7d, 0x3f, 0xab, 0x5b, 0x9f, 0xc5, 0x94, 0xd2, 0xd3, 0x69, 0xf0,
+ 0x00, 0x98, 0xb1, 0x06, 0x9b, 0x75, 0x16, 0x34, 0x07, 0xf7, 0x81, 0x18,
+ 0xba, 0x07, 0x75, 0xea, 0xdc, 0xe9, 0x6f, 0xfa, 0xb4, 0x24, 0xa8, 0xf3,
+ 0x6b, 0x98, 0x8f, 0x75, 0x67, 0x55, 0xfc, 0x56, 0xe8, 0xe1, 0x5e, 0x69,
+ 0xfb, 0xe6, 0x40, 0x1f, 0xea, 0x66, 0x18, 0x33, 0xd2, 0x0e, 0xfa, 0x31,
+ 0x5d, 0x54, 0xc5, 0x74, 0x9b, 0x15, 0x3f, 0xc8, 0xeb, 0x5f, 0x8b, 0x10,
+ 0x3b, 0x37, 0x3b, 0xdc, 0xc3, 0x79, 0x8d, 0x7b, 0x2c, 0xfb, 0xb1, 0x23,
+ 0xdf, 0xc9, 0xa7, 0xa7, 0x54, 0xde, 0x67, 0xda, 0xf5, 0xcf, 0xf0, 0x5b,
+ 0xd8, 0x3b, 0xcb, 0xbd, 0x72, 0xa1, 0x59, 0x22, 0xb1, 0x34, 0x73, 0xbd,
+ 0xf4, 0xd5, 0x77, 0x30, 0xf7, 0x50, 0xd3, 0xb4, 0x8a, 0xfe, 0xee, 0x5b,
+ 0x45, 0x7f, 0xef, 0xae, 0xd2, 0xdf, 0xfe, 0x55, 0xf5, 0xf7, 0xeb, 0x91,
+ 0xa0, 0xfe, 0xee, 0x5b, 0x45, 0x7f, 0x1f, 0xad, 0xd2, 0xdf, 0x83, 0x37,
+ 0xa4, 0xbf, 0x3a, 0x36, 0x4e, 0xdd, 0xaa, 0x72, 0xc6, 0xc3, 0x13, 0xc4,
+ 0xac, 0x4f, 0xeb, 0xdc, 0xd5, 0x4a, 0xbe, 0x98, 0x4f, 0x43, 0x5b, 0xcd,
+ 0x47, 0xe3, 0x87, 0xfd, 0x23, 0xf6, 0xe9, 0xf9, 0xa3, 0xfd, 0xf0, 0x69,
+ 0xaf, 0xbd, 0xee, 0x1f, 0x8b, 0x99, 0xf6, 0x7d, 0xc0, 0xad, 0x1f, 0xd1,
+ 0xda, 0x6b, 0x91, 0x3f, 0xc6, 0x56, 0xf4, 0x07, 0xa2, 0xda, 0x66, 0x4e,
+ 0x6a, 0x1d, 0xf4, 0xf3, 0x12, 0x41, 0x7d, 0xa6, 0x9c, 0x52, 0x36, 0x7f,
+ 0x8a, 0x3d, 0x51, 0x3e, 0x7d, 0x0c, 0xd8, 0x52, 0xa5, 0x13, 0x73, 0x52,
+ 0x00, 0x6e, 0x79, 0x3a, 0x41, 0x39, 0xeb, 0xc4, 0xbe, 0x61, 0x2b, 0xdd,
+ 0xa7, 0xbd, 0xb3, 0x70, 0xf0, 0x9c, 0xf1, 0x75, 0x3f, 0x81, 0x75, 0xfd,
+ 0x36, 0xda, 0x1e, 0x07, 0x3e, 0xd9, 0x36, 0xf8, 0x93, 0x2d, 0xc0, 0x19,
+ 0xd6, 0x2f, 0xcd, 0x73, 0xaf, 0x8e, 0xb1, 0x52, 0x0c, 0xa3, 0xef, 0xe9,
+ 0x1e, 0x60, 0x4e, 0x0f, 0x71, 0xb3, 0x84, 0xd8, 0x8c, 0x7a, 0x41, 0x5d,
+ 0xe9, 0xe8, 0xda, 0x6d, 0xd2, 0xe7, 0x7b, 0x12, 0x71, 0xfc, 0x2d, 0x4a,
+ 0xaf, 0x76, 0x97, 0x3b, 0x66, 0xdf, 0x30, 0xb9, 0x46, 0xa5, 0x92, 0x57,
+ 0xdf, 0x19, 0xc4, 0x6c, 0xeb, 0xde, 0xb2, 0x8e, 0x36, 0xf3, 0x16, 0x27,
+ 0xa4, 0xe5, 0x3e, 0x83, 0x77, 0xea, 0xd1, 0xeb, 0xf0, 0x47, 0x78, 0x47,
+ 0xe1, 0x27, 0x2a, 0x5f, 0x37, 0xed, 0xd2, 0xf7, 0x60, 0xcc, 0xb4, 0x53,
+ 0xf7, 0xdb, 0xa2, 0xbe, 0xb1, 0x66, 0x53, 0x3b, 0xf4, 0xf7, 0x36, 0xda,
+ 0xc4, 0x24, 0x31, 0x75, 0xc9, 0x79, 0xf3, 0x8e, 0x47, 0x4e, 0xc5, 0x5c,
+ 0x1c, 0xaf, 0x7c, 0x7f, 0xc4, 0x49, 0x56, 0xe0, 0xfb, 0x40, 0x44, 0xc7,
+ 0x97, 0xd4, 0xf9, 0xa8, 0x8a, 0x7d, 0xbd, 0x78, 0x8a, 0xf1, 0xf7, 0xd2,
+ 0xbb, 0x1d, 0x2b, 0xcb, 0x40, 0xcb, 0x07, 0x90, 0x81, 0xea, 0xf3, 0x8b,
+ 0x00, 0x8b, 0xfc, 0xf3, 0xf3, 0x7d, 0xac, 0xbf, 0xd0, 0xfb, 0xde, 0xa2,
+ 0xf5, 0xe9, 0xff, 0xc3, 0x3e, 0x8d, 0xc0, 0x3e, 0x7d, 0x6c, 0xfc, 0xa2,
+ 0xde, 0xe7, 0xce, 0x2a, 0x6c, 0xec, 0x41, 0xfd, 0xe1, 0x9a, 0x8d, 0x1f,
+ 0x10, 0x1b, 0xf7, 0xde, 0x10, 0x36, 0xfe, 0x70, 0xdd, 0x5a, 0xb1, 0xf1,
+ 0xd0, 0x07, 0xc6, 0x46, 0xee, 0x6b, 0x65, 0x3c, 0xda, 0xb7, 0x0c, 0x8f,
+ 0xfe, 0xe0, 0x13, 0xc4, 0xa3, 0xd5, 0xb0, 0x84, 0xe7, 0xd2, 0xa0, 0x7c,
+ 0x6c, 0x4f, 0xff, 0xe0, 0x5f, 0xcc, 0x84, 0xe5, 0xc2, 0xbd, 0x11, 0x79,
+ 0x6d, 0x27, 0xfc, 0x6e, 0xf2, 0x48, 0x9d, 0x07, 0xcb, 0xd1, 0x3a, 0xcf,
+ 0x36, 0xc6, 0x1b, 0xbd, 0x9c, 0x02, 0xc7, 0xf8, 0x3a, 0x6d, 0xa3, 0x9d,
+ 0x6d, 0x5b, 0xe4, 0xf5, 0xc6, 0x1b, 0x89, 0x53, 0xf9, 0x8d, 0x66, 0xa5,
+ 0x38, 0x75, 0xf5, 0x9c, 0xe6, 0x62, 0x9c, 0x4a, 0xac, 0x6d, 0xd4, 0x79,
+ 0x2c, 0xc6, 0x67, 0xfb, 0x35, 0x7e, 0xf2, 0x1d, 0xf1, 0xb8, 0x8b, 0x58,
+ 0xdc, 0x45, 0x1c, 0xee, 0x22, 0x46, 0x87, 0x6d, 0x7e, 0x01, 0x32, 0xf7,
+ 0x6d, 0x17, 0x31, 0xb8, 0x8b, 0x18, 0xdc, 0xed, 0xd2, 0x71, 0x7c, 0xbf,
+ 0xfe, 0x76, 0xc1, 0xef, 0xfb, 0xcc, 0x83, 0x14, 0x61, 0x57, 0x46, 0x79,
+ 0x3f, 0xc3, 0xcc, 0xa6, 0xd6, 0xe9, 0xfd, 0xf9, 0x79, 0xfd, 0x56, 0x9d,
+ 0x5b, 0xda, 0xb4, 0x49, 0xf9, 0x0b, 0xe6, 0x2b, 0x75, 0xde, 0x1d, 0x00,
+ 0xde, 0x23, 0x79, 0x14, 0xbe, 0x92, 0xba, 0x87, 0x45, 0x3d, 0xad, 0x98,
+ 0x69, 0xe6, 0x8e, 0xc4, 0x34, 0xd3, 0x77, 0x60, 0xcc, 0x36, 0x2f, 0x66,
+ 0x89, 0x49, 0xc8, 0x4c, 0xd7, 0x93, 0xa7, 0x86, 0x99, 0x5e, 0xaf, 0xe7,
+ 0x9a, 0xaf, 0xf3, 0xfc, 0xbd, 0x4e, 0x96, 0x2d, 0x33, 0xfd, 0x59, 0x3e,
+ 0x71, 0xee, 0x7e, 0xfd, 0x3d, 0x8d, 0x4b, 0xd7, 0x1a, 0x53, 0x18, 0x9f,
+ 0x4d, 0xdd, 0x8b, 0xf9, 0xd4, 0xfd, 0xa7, 0x05, 0x7e, 0x9b, 0xd7, 0xe4,
+ 0xf7, 0x98, 0xe6, 0xb7, 0xc7, 0xe3, 0x10, 0xfb, 0xa9, 0xdc, 0x36, 0x79,
+ 0xed, 0xcf, 0xa7, 0x72, 0x93, 0x58, 0x47, 0xdd, 0x01, 0xc1, 0xb3, 0x62,
+ 0x49, 0xc3, 0xc0, 0x7d, 0x61, 0x27, 0xb8, 0xae, 0xff, 0x2d, 0x7f, 0x2d,
+ 0x6b, 0x6e, 0x51, 0xdf, 0x07, 0x3d, 0xbb, 0x31, 0xa6, 0x64, 0xd0, 0x4a,
+ 0x73, 0x5f, 0xef, 0x43, 0xfe, 0xc6, 0x94, 0xfc, 0xe5, 0x10, 0x67, 0x8d,
+ 0xf6, 0x74, 0x24, 0x2c, 0x73, 0xba, 0x8e, 0x39, 0xe4, 0xbe, 0xb2, 0x8f,
+ 0x7d, 0x5c, 0xaf, 0xda, 0xa6, 0x33, 0xff, 0xe7, 0x63, 0x9a, 0xb4, 0x78,
+ 0x79, 0xc1, 0xb5, 0xde, 0xa9, 0x58, 0xd4, 0xa5, 0xc1, 0x05, 0x5d, 0xaa,
+ 0xab, 0xd2, 0x25, 0x7f, 0x9f, 0xeb, 0xc5, 0xff, 0xe6, 0xbe, 0xd2, 0x5d,
+ 0x90, 0xb9, 0x72, 0xe0, 0x1b, 0xcf, 0x82, 0x6c, 0xf0, 0x4e, 0xcc, 0x3d,
+ 0x90, 0x41, 0x7e, 0xdf, 0xd8, 0x03, 0x3d, 0xaa, 0x54, 0xfa, 0x98, 0x27,
+ 0xdf, 0xde, 0xaf, 0xef, 0x5b, 0x5c, 0x51, 0x39, 0x12, 0x6b, 0x59, 0x8e,
+ 0xa4, 0x0f, 0xb2, 0x02, 0x3f, 0x00, 0x3a, 0x98, 0x57, 0x67, 0x49, 0x9f,
+ 0xa0, 0xfa, 0x1b, 0xd2, 0xc5, 0x7a, 0x8f, 0x0f, 0x9d, 0xf5, 0xde, 0x77,
+ 0x14, 0x73, 0xd3, 0xd2, 0x32, 0xc7, 0x27, 0xea, 0x3d, 0x59, 0x39, 0x06,
+ 0xfb, 0xdc, 0x07, 0x59, 0xac, 0x91, 0x9c, 0x9a, 0xef, 0x98, 0xe4, 0x9f,
+ 0xfd, 0xcf, 0xc6, 0xa5, 0xfd, 0x51, 0x77, 0xd2, 0xef, 0xff, 0x78, 0x55,
+ 0xff, 0xc7, 0xd1, 0xff, 0x67, 0x55, 0xfd, 0x1f, 0x0f, 0xf4, 0x3f, 0xa1,
+ 0xfb, 0xd7, 0xa2, 0xbf, 0xd2, 0x83, 0x26, 0xdf, 0x2f, 0x36, 0x1d, 0xc4,
+ 0xb3, 0xcf, 0xfa, 0x63, 0x4e, 0x04, 0xc6, 0x4c, 0x56, 0xad, 0x31, 0x89,
+ 0x7e, 0xf1, 0xa6, 0xa5, 0x6b, 0xa0, 0xee, 0x64, 0x8d, 0xfe, 0xbe, 0x47,
+ 0x9f, 0xe5, 0xa0, 0xce, 0x17, 0xe0, 0x59, 0x0a, 0x7e, 0x33, 0xe2, 0x77,
+ 0x0a, 0xca, 0x9e, 0xff, 0x8d, 0xc2, 0xbf, 0x93, 0x47, 0xbd, 0xcd, 0x40,
+ 0x6f, 0x17, 0xfd, 0x1a, 0x4f, 0x2e, 0x83, 0x32, 0x49, 0x9c, 0x28, 0x4a,
+ 0xc8, 0x29, 0xd3, 0x57, 0x32, 0x0a, 0x33, 0xbe, 0x7d, 0xe2, 0xbd, 0x2b,
+ 0xde, 0xd7, 0xf5, 0xec, 0x70, 0xd8, 0x99, 0xd3, 0x31, 0xe2, 0xaf, 0x90,
+ 0x7e, 0xe0, 0xa6, 0x8f, 0x9d, 0x72, 0xcc, 0xd3, 0x1f, 0xca, 0x31, 0xe7,
+ 0xd7, 0x7a, 0x44, 0x99, 0xd5, 0xeb, 0xf4, 0x2d, 0xc3, 0xb7, 0xc4, 0xb2,
+ 0x3c, 0x5c, 0x68, 0x0d, 0xf8, 0xd6, 0xbf, 0x80, 0x6f, 0xf7, 0xca, 0x94,
+ 0x9d, 0x50, 0x79, 0xd0, 0x43, 0x0b, 0x79, 0x81, 0xc3, 0x91, 0x46, 0x87,
+ 0x79, 0x81, 0xe4, 0xa9, 0x8c, 0x7c, 0xb0, 0xbc, 0xc0, 0xbe, 0x2a, 0x1d,
+ 0xd9, 0xbb, 0xaa, 0xed, 0xfc, 0xb3, 0xfa, 0xb5, 0xe6, 0x05, 0x1e, 0xa9,
+ 0xb2, 0x63, 0x87, 0x6e, 0xc0, 0x76, 0xe6, 0x95, 0xed, 0xe4, 0x5e, 0xaf,
+ 0xe7, 0xcb, 0x7f, 0x25, 0xf2, 0xd1, 0xd8, 0xce, 0xd5, 0x72, 0xe2, 0x41,
+ 0x7b, 0x40, 0xb9, 0xba, 0xac, 0xfd, 0x6c, 0x3c, 0x67, 0x2e, 0x43, 0x3f,
+ 0x4d, 0x19, 0x54, 0xb2, 0xcc, 0xb2, 0x1f, 0xff, 0xde, 0xb7, 0x10, 0xff,
+ 0x2e, 0xc6, 0xac, 0xf0, 0x67, 0xbb, 0xfc, 0xd8, 0x88, 0x7e, 0xb3, 0x6d,
+ 0x14, 0xdc, 0x3d, 0xe6, 0x90, 0x6a, 0x63, 0x8e, 0xf7, 0x36, 0xf9, 0x9c,
+ 0xba, 0x27, 0x70, 0x5e, 0xe7, 0xd2, 0xa6, 0x54, 0x4c, 0xc0, 0xef, 0x1c,
+ 0x85, 0xd4, 0x46, 0xed, 0x03, 0x5e, 0x0f, 0x67, 0x97, 0xc6, 0xcf, 0xa6,
+ 0x79, 0x04, 0x63, 0x19, 0x3f, 0x7f, 0x21, 0x4a, 0x4c, 0xcd, 0x96, 0x57,
+ 0x1d, 0x8f, 0x71, 0x1c, 0xcf, 0x3e, 0x2a, 0x56, 0x46, 0xbf, 0x39, 0x3d,
+ 0xde, 0x8b, 0x95, 0xb3, 0xe5, 0xad, 0x51, 0x0f, 0x17, 0x57, 0x8b, 0x63,
+ 0x8e, 0x44, 0x99, 0x8b, 0x9c, 0x73, 0xaf, 0x47, 0xeb, 0xf2, 0xd8, 0x3c,
+ 0xb4, 0x2c, 0x36, 0xb7, 0x74, 0xec, 0x7d, 0xbf, 0x8a, 0xcd, 0x3d, 0x1e,
+ 0x73, 0x2f, 0xc1, 0xd8, 0xca, 0x01, 0x36, 0xf2, 0x5b, 0x10, 0xb1, 0x82,
+ 0x3e, 0x0b, 0xe4, 0x67, 0xfc, 0x37, 0x94, 0x1f, 0xb3, 0x5c, 0x7e, 0x3e,
+ 0x6e, 0xbb, 0xe1, 0xef, 0xfd, 0xb2, 0x78, 0xf9, 0xc5, 0x3d, 0xa0, 0x85,
+ 0xf1, 0x56, 0x58, 0xcb, 0xc3, 0xcf, 0x69, 0xfc, 0xf6, 0xfb, 0xf9, 0xb9,
+ 0x86, 0x85, 0x6f, 0xc9, 0xc5, 0xcc, 0x92, 0x1c, 0xcf, 0x16, 0xa6, 0xce,
+ 0x71, 0xee, 0x99, 0x1b, 0xf8, 0xde, 0xf2, 0x61, 0xee, 0x7c, 0x54, 0xdb,
+ 0xb9, 0x57, 0x21, 0xfb, 0x09, 0x7d, 0xff, 0xaf, 0x0b, 0x3a, 0xc0, 0x3b,
+ 0xd0, 0xd5, 0x58, 0xab, 0xee, 0xf9, 0x45, 0x36, 0xa5, 0xf9, 0xed, 0x82,
+ 0x3e, 0xc1, 0x4f, 0xf4, 0x5e, 0xe3, 0x72, 0x6c, 0xc2, 0xcb, 0xd3, 0x9a,
+ 0xab, 0xde, 0xf1, 0xbb, 0x04, 0x5e, 0x24, 0x8f, 0xfa, 0x79, 0x5a, 0xd3,
+ 0xbb, 0xe3, 0x77, 0xf4, 0xa3, 0xbb, 0xe3, 0xc7, 0xf9, 0x2d, 0xd9, 0xbb,
+ 0xc2, 0x1d, 0xbf, 0xd0, 0x1a, 0xef, 0xf8, 0x6d, 0x54, 0x79, 0x5a, 0xce,
+ 0xe3, 0xe5, 0x69, 0x59, 0x6e, 0xeb, 0xfe, 0x94, 0xc2, 0xa8, 0xe9, 0x09,
+ 0xe6, 0x75, 0x1e, 0x5c, 0xf7, 0xc9, 0xe4, 0x75, 0xde, 0x8b, 0x7e, 0xfc,
+ 0x79, 0x1d, 0x7e, 0x17, 0xf8, 0xb2, 0xf7, 0xdd, 0x5a, 0x6e, 0x24, 0x3f,
+ 0xf0, 0xe1, 0x72, 0xb0, 0x07, 0x55, 0x0e, 0x76, 0xfb, 0xfa, 0x60, 0x0e,
+ 0xd6, 0xbc, 0xce, 0x3d, 0xb8, 0x83, 0x2b, 0xe4, 0x60, 0xc3, 0x81, 0x7b,
+ 0x70, 0x61, 0x7d, 0x0f, 0x6e, 0xa3, 0x83, 0x18, 0x53, 0xe7, 0x5b, 0xcd,
+ 0x55, 0xef, 0xc1, 0xed, 0x5e, 0xff, 0xe1, 0xf3, 0xad, 0xcb, 0xee, 0xc1,
+ 0x1d, 0xcd, 0x48, 0x8b, 0x24, 0x6e, 0x28, 0x16, 0xfa, 0x30, 0x71, 0x10,
+ 0xff, 0x8f, 0x40, 0x0d, 0xf6, 0x0c, 0x99, 0x8f, 0x51, 0x3e, 0x29, 0x77,
+ 0x69, 0x33, 0x5f, 0xe6, 0x7b, 0x17, 0xcf, 0xc7, 0xe8, 0xef, 0x5c, 0x7a,
+ 0xb7, 0x62, 0xf1, 0x6e, 0x72, 0x64, 0xe1, 0x6e, 0xf2, 0x18, 0x64, 0xc6,
+ 0x9c, 0x88, 0xc8, 0x74, 0xc0, 0xb6, 0x8e, 0xba, 0xf0, 0x9b, 0x26, 0x6d,
+ 0xdd, 0xce, 0xff, 0xa7, 0x82, 0xb8, 0xb0, 0xc4, 0xfb, 0xcc, 0x0d, 0x12,
+ 0x9a, 0x54, 0x98, 0x1a, 0xf3, 0xfe, 0xaf, 0x4e, 0x1c, 0x7d, 0x78, 0x77,
+ 0x35, 0x2c, 0x87, 0x62, 0x94, 0x65, 0x5f, 0x8e, 0xbf, 0x05, 0xfe, 0x36,
+ 0x65, 0x16, 0xcb, 0x31, 0x2d, 0xd7, 0x94, 0x69, 0x5f, 0xfe, 0x62, 0x32,
+ 0x32, 0x41, 0x59, 0xde, 0xa1, 0xff, 0x9f, 0xc4, 0x39, 0x29, 0x94, 0xcf,
+ 0xea, 0x78, 0x43, 0x7d, 0x8b, 0x02, 0x1f, 0x5b, 0xb4, 0x0d, 0xc6, 0x73,
+ 0xa6, 0x85, 0x36, 0x8f, 0xdf, 0x1e, 0xa5, 0x6f, 0x7c, 0x5b, 0x7c, 0x08,
+ 0x78, 0x37, 0xa8, 0x72, 0x27, 0x37, 0xc2, 0x6f, 0xe3, 0x1a, 0xdf, 0x48,
+ 0xd7, 0xca, 0x73, 0xdf, 0x5f, 0xbe, 0x8c, 0xfd, 0xb5, 0x40, 0x36, 0xbe,
+ 0x2a, 0xb9, 0x93, 0xb7, 0x49, 0xdf, 0x89, 0x24, 0xe8, 0x79, 0xbf, 0x52,
+ 0x48, 0xc1, 0xb7, 0x7e, 0x96, 0x77, 0xe1, 0x80, 0xa1, 0x2e, 0x30, 0x14,
+ 0xbc, 0x7b, 0x61, 0x99, 0xbf, 0x11, 0xbc, 0x43, 0x97, 0x5a, 0xb8, 0x13,
+ 0xf5, 0x7c, 0x59, 0x22, 0x8d, 0xa4, 0x7b, 0x62, 0xf1, 0x2e, 0xfc, 0x5c,
+ 0x39, 0xa7, 0xec, 0xdb, 0x73, 0xe5, 0x25, 0x39, 0x21, 0x75, 0x8e, 0xc3,
+ 0xa5, 0x97, 0x61, 0xe3, 0x2e, 0x1b, 0xb4, 0x71, 0x63, 0xae, 0xdc, 0x12,
+ 0x12, 0x9e, 0x89, 0x18, 0xe0, 0x83, 0xba, 0x9b, 0xe2, 0xdd, 0x4d, 0x68,
+ 0x55, 0x67, 0xfb, 0x7f, 0xd4, 0x5d, 0x7d, 0x6c, 0x5b, 0xd7, 0x75, 0x3f,
+ 0x7c, 0xa4, 0x3e, 0x4c, 0xcb, 0xd2, 0x93, 0x4c, 0xc9, 0xb4, 0x2d, 0xcb,
+ 0x8f, 0xd2, 0x93, 0xa5, 0xc4, 0x4a, 0xc1, 0x79, 0xda, 0xaa, 0x01, 0x5a,
+ 0xc7, 0x52, 0xf4, 0xc7, 0x82, 0x60, 0xa5, 0x65, 0x25, 0xf3, 0xd2, 0x2c,
+ 0x51, 0x29, 0xdb, 0xc9, 0xfe, 0x18, 0xe0, 0x25, 0xd9, 0x9a, 0xfd, 0x51,
+ 0xe4, 0x95, 0x94, 0x12, 0x63, 0x56, 0x4d, 0xc6, 0xe6, 0x84, 0x02, 0x0b,
+ 0x36, 0x56, 0x92, 0x9d, 0x14, 0x50, 0xc0, 0x24, 0x6d, 0x87, 0x2c, 0x6d,
+ 0x11, 0x55, 0x76, 0xda, 0x7f, 0x8d, 0x2d, 0xc0, 0xb2, 0x2e, 0x69, 0x14,
+ 0x3b, 0xc8, 0x02, 0x2c, 0x58, 0xbb, 0x6e, 0x28, 0xf6, 0x4f, 0xc7, 0x9d,
+ 0xdf, 0xfd, 0x20, 0x1f, 0xc9, 0x47, 0x7d, 0x24, 0x6e, 0x81, 0x09, 0x10,
+ 0xc8, 0xf7, 0xde, 0x7d, 0xef, 0xdd, 0x7b, 0xee, 0xf9, 0xf8, 0x9d, 0x73,
+ 0xcf, 0xb9, 0x94, 0xba, 0xe2, 0x35, 0x57, 0x6e, 0x49, 0x65, 0x7e, 0x65,
+ 0xce, 0x89, 0x9c, 0x0f, 0x95, 0x43, 0x0b, 0x9a, 0x3a, 0x27, 0x6d, 0x99,
+ 0x17, 0x33, 0xb0, 0x80, 0x73, 0x3d, 0x35, 0xf6, 0xaf, 0x95, 0xf9, 0xc0,
+ 0x14, 0x31, 0x85, 0x69, 0x13, 0x7d, 0xde, 0x2b, 0xf4, 0x81, 0xf7, 0xba,
+ 0x7c, 0x40, 0xe9, 0xbc, 0x56, 0xa5, 0xa3, 0x36, 0xc2, 0x6f, 0xf2, 0x9d,
+ 0xfd, 0xe2, 0x9d, 0xdd, 0x4a, 0x67, 0xe9, 0xdc, 0xf7, 0x71, 0x63, 0xba,
+ 0x08, 0x5f, 0x9b, 0xe9, 0x52, 0x87, 0xdf, 0xac, 0x4d, 0xe8, 0xf8, 0xb9,
+ 0x3a, 0x3a, 0x56, 0xcb, 0x03, 0xfb, 0xe6, 0x65, 0x9d, 0x2d, 0x69, 0x26,
+ 0xcf, 0x23, 0x9f, 0x5f, 0xe7, 0x65, 0x48, 0x9a, 0x95, 0xe5, 0xe7, 0x92,
+ 0x3b, 0x27, 0xa3, 0x42, 0xb3, 0xe9, 0x32, 0xcd, 0xf6, 0xfc, 0x3f, 0xa0,
+ 0xd9, 0x4d, 0x81, 0x79, 0x5f, 0x29, 0x22, 0xff, 0x6e, 0x58, 0xe4, 0x2e,
+ 0xac, 0xd2, 0x88, 0xb2, 0xff, 0xee, 0x1a, 0x28, 0xd0, 0x12, 0xba, 0x34,
+ 0x52, 0x58, 0xa7, 0x98, 0x8c, 0x43, 0x98, 0xa5, 0xd2, 0x77, 0xa2, 0x90,
+ 0x3f, 0xf8, 0x24, 0xf0, 0x51, 0x10, 0xdf, 0x3b, 0xc9, 0x63, 0xfb, 0x97,
+ 0x60, 0xd7, 0x06, 0x36, 0xf2, 0xe4, 0x36, 0x7c, 0x94, 0x8a, 0x8d, 0x04,
+ 0x5e, 0x22, 0x27, 0x6e, 0x57, 0xf2, 0x5e, 0x66, 0xb3, 0x3f, 0x6c, 0x67,
+ 0x3f, 0x92, 0x69, 0x5c, 0x79, 0xee, 0xd6, 0x7c, 0x14, 0x3c, 0x4f, 0xda,
+ 0xc9, 0xd9, 0x6c, 0xe5, 0xb9, 0x4e, 0xf9, 0xb9, 0x61, 0x0f, 0x5d, 0x65,
+ 0xd1, 0xcc, 0xa5, 0x7d, 0x75, 0xf9, 0x6a, 0x95, 0xf1, 0x48, 0x5f, 0x45,
+ 0x8f, 0xe7, 0xc9, 0x4d, 0xf1, 0xa5, 0xcc, 0x3b, 0xab, 0xe4, 0xf0, 0xd4,
+ 0xfa, 0x29, 0xfb, 0x5d, 0xf1, 0x19, 0xd0, 0xf8, 0x0f, 0x69, 0x75, 0x12,
+ 0x7a, 0xae, 0x96, 0xd6, 0xef, 0xff, 0x9a, 0x68, 0x1d, 0xe9, 0xf8, 0xf5,
+ 0xd2, 0x7a, 0x7f, 0x5d, 0x2c, 0xbc, 0x32, 0x1e, 0x0a, 0x75, 0x6f, 0x0b,
+ 0xcb, 0xd7, 0xd2, 0x7a, 0x7f, 0xc3, 0x78, 0x6a, 0xe3, 0x5c, 0xcc, 0xea,
+ 0x78, 0x6a, 0xbf, 0xc1, 0x32, 0x92, 0x65, 0x79, 0x69, 0xa8, 0xe3, 0xff,
+ 0xce, 0x15, 0x6f, 0x75, 0xeb, 0x79, 0xc8, 0x1a, 0xf9, 0x4e, 0x0e, 0xe9,
+ 0x77, 0x42, 0xae, 0x22, 0x8e, 0x43, 0xf0, 0x9f, 0xf0, 0x5e, 0xe4, 0x62,
+ 0xd5, 0xe1, 0x2e, 0x7e, 0x2f, 0xcb, 0xff, 0x0b, 0xcf, 0x0b, 0x9b, 0x25,
+ 0x63, 0x12, 0x68, 0x1f, 0xf2, 0x9d, 0x11, 0x6d, 0x65, 0x8e, 0x96, 0x8a,
+ 0x51, 0x28, 0x3f, 0xa0, 0x51, 0x6c, 0xa2, 0xde, 0xfe, 0x6d, 0xcf, 0x6f,
+ 0xd0, 0xf1, 0x88, 0x83, 0x3c, 0x3f, 0xe1, 0x2a, 0xbf, 0x0b, 0xfa, 0xf4,
+ 0x3c, 0x63, 0x84, 0xfe, 0x32, 0x3e, 0xa8, 0x9e, 0xa3, 0x59, 0xe1, 0xdf,
+ 0x69, 0x5d, 0xba, 0x2a, 0x73, 0x6b, 0xc5, 0x79, 0xe0, 0xb5, 0xb2, 0x2e,
+ 0xad, 0xc1, 0xc3, 0x07, 0x3d, 0xf8, 0xc3, 0xb3, 0x9e, 0x55, 0xcf, 0xa1,
+ 0x85, 0x9c, 0xfa, 0x84, 0xe7, 0x1c, 0x96, 0xeb, 0xd2, 0x9c, 0x4a, 0x5b,
+ 0x79, 0x7f, 0x42, 0x8c, 0x6b, 0xea, 0xde, 0x38, 0xea, 0xef, 0xca, 0x35,
+ 0x51, 0xb5, 0x75, 0x60, 0xb0, 0x0b, 0x5a, 0x1e, 0x75, 0xcd, 0x39, 0x68,
+ 0xd1, 0xe7, 0x51, 0x07, 0xe6, 0xb6, 0x2d, 0xb8, 0xaf, 0x96, 0x16, 0x15,
+ 0xbb, 0x32, 0xa7, 0xec, 0xca, 0xa2, 0x4b, 0xaf, 0xd7, 0xe3, 0xf7, 0x2e,
+ 0x0f, 0xfc, 0xee, 0x55, 0x0b, 0x86, 0x3e, 0x3d, 0xc5, 0x98, 0xe4, 0x33,
+ 0xc0, 0x24, 0x26, 0x6a, 0xb1, 0x24, 0x2e, 0xc1, 0xf5, 0x1c, 0x63, 0x93,
+ 0x30, 0xf3, 0xca, 0x6b, 0x74, 0x8e, 0x31, 0xf7, 0x35, 0xba, 0x4b, 0xf9,
+ 0x69, 0x90, 0x5f, 0x9d, 0x47, 0x8b, 0x5a, 0x06, 0x1f, 0x39, 0x0f, 0x45,
+ 0x86, 0x63, 0xf4, 0x1a, 0x9d, 0x15, 0xf9, 0x3e, 0x58, 0xff, 0x43, 0x9e,
+ 0xc4, 0xdd, 0xe2, 0xfd, 0x32, 0xae, 0x71, 0x27, 0xf2, 0x02, 0xb7, 0x5e,
+ 0x9f, 0xa0, 0xea, 0x05, 0xb9, 0x1d, 0xde, 0xb9, 0xac, 0x64, 0x4a, 0x9c,
+ 0xe3, 0xfb, 0x9f, 0x32, 0xea, 0xef, 0x8f, 0x19, 0x89, 0x62, 0xc2, 0x88,
+ 0x2f, 0xa1, 0xdd, 0x53, 0xc6, 0x44, 0x11, 0xbe, 0xa4, 0xe6, 0x91, 0x48,
+ 0x14, 0xf2, 0xb6, 0x46, 0x9b, 0xaf, 0x53, 0x2c, 0x52, 0x4d, 0xad, 0xc8,
+ 0x16, 0xfa, 0x7d, 0xac, 0xaa, 0xdf, 0x9a, 0xbe, 0xf8, 0x8e, 0xd8, 0xcf,
+ 0xcb, 0x4c, 0x53, 0x8d, 0x71, 0x83, 0x88, 0xbd, 0x0f, 0x3b, 0xb4, 0x11,
+ 0xc6, 0x8d, 0xd4, 0x61, 0xdc, 0xc5, 0x4d, 0xfb, 0xfd, 0x69, 0x65, 0x5c,
+ 0xd6, 0x7c, 0xfb, 0x6d, 0x81, 0x65, 0xb9, 0xdf, 0x55, 0x38, 0xb7, 0x86,
+ 0xa7, 0xd0, 0x46, 0xc7, 0xc8, 0x75, 0x4c, 0xac, 0x5d, 0xc5, 0x74, 0x75,
+ 0x3e, 0x45, 0x50, 0xc5, 0xb4, 0x71, 0x1d, 0xbe, 0xd6, 0x2a, 0xf7, 0x0f,
+ 0x7e, 0x17, 0xe2, 0x3f, 0x6e, 0xbf, 0xcb, 0x1d, 0xf3, 0xf5, 0xaa, 0x0d,
+ 0xed, 0xf7, 0xa8, 0x0d, 0x75, 0xcb, 0x59, 0xc0, 0x25, 0x67, 0x61, 0x17,
+ 0x86, 0xeb, 0x65, 0xff, 0xa5, 0x8d, 0xf5, 0x07, 0xfc, 0x97, 0x20, 0xf9,
+ 0x2f, 0xbb, 0xfd, 0x97, 0xda, 0x3a, 0x7f, 0xc8, 0x1c, 0x70, 0x9a, 0xf4,
+ 0x65, 0x12, 0xf9, 0xf2, 0x1e, 0x01, 0x3c, 0xe6, 0x4a, 0x1d, 0xe6, 0x52,
+ 0x5d, 0xcd, 0xa8, 0x57, 0x7f, 0xfb, 0xea, 0xfa, 0x0b, 0x1b, 0x16, 0x6b,
+ 0x88, 0xef, 0xbc, 0xfc, 0xab, 0x3b, 0xd5, 0xbf, 0x5a, 0x5d, 0x86, 0x77,
+ 0xf5, 0x8b, 0x18, 0xb8, 0x53, 0xd6, 0x63, 0x63, 0xb2, 0xbf, 0xd9, 0x6a,
+ 0x5f, 0xc3, 0x7f, 0x89, 0x14, 0xed, 0xbc, 0xf5, 0xfa, 0xf6, 0xe2, 0x68,
+ 0x3b, 0x6b, 0x6c, 0xef, 0x78, 0xa7, 0x8c, 0x8f, 0xcd, 0xa9, 0x3c, 0xf2,
+ 0x6e, 0xe5, 0xf7, 0x6d, 0xc6, 0xeb, 0x38, 0x37, 0xa7, 0x62, 0x8a, 0x11,
+ 0xab, 0x40, 0xe0, 0xf1, 0xc9, 0xd3, 0x4d, 0xb6, 0xa9, 0xd6, 0xb8, 0xb0,
+ 0x8e, 0x05, 0x9e, 0xd7, 0xcf, 0x97, 0x35, 0x65, 0x9b, 0xcf, 0x99, 0x55,
+ 0x37, 0x67, 0x92, 0xaf, 0xe0, 0x6f, 0x21, 0x3f, 0x7a, 0xa4, 0x26, 0x47,
+ 0xfd, 0xd3, 0xd0, 0xa2, 0xdd, 0x23, 0x6f, 0x1b, 0x79, 0xd7, 0x8d, 0xfa,
+ 0xb9, 0xee, 0xc2, 0xea, 0xb2, 0x6e, 0x63, 0x95, 0xd0, 0xef, 0x52, 0xe9,
+ 0xe5, 0x28, 0xb0, 0x69, 0x6f, 0x1d, 0xaf, 0x69, 0xbc, 0x64, 0xba, 0xfa,
+ 0xf9, 0xf8, 0xc6, 0xfd, 0xac, 0xb1, 0xbf, 0x7b, 0x3d, 0xec, 0x6f, 0x23,
+ 0x5f, 0x42, 0xec, 0x9d, 0xe2, 0x3b, 0x2a, 0x74, 0x41, 0x1b, 0x2d, 0xe5,
+ 0x91, 0x4b, 0xfe, 0x1b, 0xa8, 0x67, 0x65, 0x7d, 0xeb, 0xaa, 0xcf, 0xf3,
+ 0x9e, 0xd3, 0xf2, 0x7a, 0x4b, 0x60, 0x1c, 0xeb, 0x83, 0xc8, 0x41, 0xe9,
+ 0x62, 0x1d, 0x84, 0xf6, 0x83, 0xd6, 0x0d, 0xc4, 0x80, 0x55, 0x3c, 0x2a,
+ 0xa1, 0xec, 0xcc, 0xd1, 0x2d, 0xac, 0xbb, 0x6c, 0x4f, 0x5f, 0x47, 0xac,
+ 0x55, 0xc2, 0x9a, 0x10, 0xf2, 0x9e, 0x9d, 0x76, 0x6a, 0xbf, 0xbf, 0xa5,
+ 0xc5, 0xbe, 0xd9, 0x29, 0xd7, 0xaa, 0x70, 0xad, 0x8d, 0xae, 0xe6, 0x91,
+ 0x97, 0x8e, 0x6b, 0x0f, 0xf2, 0x35, 0x2f, 0x7d, 0xf5, 0xb6, 0xe2, 0x25,
+ 0x60, 0x3a, 0x39, 0x47, 0x05, 0x92, 0x73, 0xb6, 0x4e, 0xf0, 0xa5, 0x4a,
+ 0xf4, 0x4f, 0xd1, 0xdf, 0x14, 0xfe, 0x5f, 0x65, 0xae, 0xb6, 0xb7, 0x8e,
+ 0x53, 0x9b, 0x03, 0x31, 0xb9, 0x61, 0x1c, 0xb1, 0xa3, 0x6b, 0xab, 0xeb,
+ 0x38, 0xb5, 0x39, 0x10, 0x8f, 0x6f, 0x29, 0x8e, 0x18, 0xb1, 0xa6, 0x37,
+ 0xac, 0x33, 0x70, 0xaf, 0xa9, 0xe8, 0xb5, 0xe4, 0x51, 0x51, 0x7b, 0xeb,
+ 0xe6, 0x89, 0x3b, 0xb3, 0x9e, 0x0c, 0xde, 0xe8, 0xab, 0xd3, 0x61, 0x77,
+ 0x60, 0x3d, 0xa0, 0x86, 0xb6, 0x41, 0xcf, 0x58, 0x96, 0xf7, 0xba, 0x31,
+ 0x72, 0x04, 0x10, 0xc3, 0x2e, 0xd2, 0x99, 0x2b, 0xe0, 0x67, 0x83, 0x39,
+ 0x6f, 0x80, 0x32, 0x21, 0xd4, 0x52, 0x89, 0xba, 0x28, 0xbd, 0xbe, 0x28,
+ 0xea, 0xa3, 0xce, 0x88, 0xba, 0xcf, 0xc1, 0xf0, 0x6d, 0xb6, 0x91, 0x67,
+ 0x8a, 0x6f, 0xd1, 0xd9, 0xa5, 0x20, 0xff, 0x57, 0xf0, 0x7c, 0x7d, 0xed,
+ 0x67, 0x35, 0xbf, 0xdf, 0x16, 0xfc, 0xde, 0xbb, 0x21, 0xbf, 0x1f, 0x2f,
+ 0xf3, 0x3b, 0x77, 0x28, 0x28, 0x6b, 0x2b, 0x53, 0x57, 0xda, 0xe9, 0xa8,
+ 0x78, 0xee, 0x5b, 0xfc, 0x7d, 0x27, 0x1d, 0x35, 0xe5, 0xf7, 0xb3, 0x4b,
+ 0xac, 0xfb, 0xb3, 0x6f, 0xd1, 0xb9, 0x2b, 0x8e, 0x2f, 0x21, 0xea, 0x32,
+ 0xdc, 0x7b, 0x86, 0xe8, 0xfb, 0xd1, 0xce, 0x4b, 0x16, 0xea, 0xf5, 0x55,
+ 0x41, 0xea, 0x2b, 0xba, 0x29, 0x62, 0x20, 0xde, 0xfa, 0x0a, 0xfc, 0x79,
+ 0x5e, 0xd9, 0xc6, 0xc9, 0x0d, 0x62, 0x1f, 0xf5, 0xbc, 0xd9, 0xe9, 0x81,
+ 0x91, 0xbf, 0xdb, 0x25, 0xd7, 0xb1, 0x36, 0x8a, 0x81, 0x54, 0xe5, 0x81,
+ 0xb8, 0xd7, 0xf9, 0xd9, 0x1e, 0x4c, 0xaa, 0x75, 0xf7, 0x9f, 0x76, 0x49,
+ 0x3b, 0x82, 0x9a, 0xc8, 0x55, 0xa6, 0xc3, 0x3f, 0x30, 0x7e, 0xd9, 0x4f,
+ 0xcd, 0x97, 0xf5, 0x58, 0xf7, 0x0b, 0x7f, 0xc8, 0x1d, 0xcb, 0x99, 0x55,
+ 0x35, 0xee, 0x69, 0xd7, 0x98, 0x66, 0x85, 0xdf, 0xf3, 0x49, 0xd6, 0x31,
+ 0x7b, 0x6b, 0x6c, 0x45, 0x2d, 0xbf, 0x61, 0x3f, 0x16, 0xcc, 0x2f, 0x19,
+ 0x12, 0x1b, 0x8f, 0x31, 0xe6, 0xdd, 0xee, 0x7a, 0xd2, 0xa7, 0xc5, 0x8d,
+ 0xb5, 0x7b, 0x7d, 0xd4, 0x7e, 0xc7, 0x3c, 0x48, 0x3f, 0x24, 0xf5, 0x42,
+ 0x51, 0xe8, 0x82, 0xd9, 0x91, 0x12, 0x4d, 0x44, 0x77, 0x51, 0x6a, 0x84,
+ 0xdf, 0x3d, 0x66, 0xb3, 0x3f, 0xe6, 0x27, 0x87, 0xe5, 0x37, 0x35, 0xb2,
+ 0x43, 0xd5, 0xcc, 0xe9, 0x58, 0x7b, 0x8b, 0xc2, 0x90, 0xed, 0x62, 0xdd,
+ 0x52, 0xee, 0x49, 0xc4, 0xdf, 0x97, 0xf4, 0xb3, 0x71, 0x1e, 0xbc, 0xdb,
+ 0xac, 0xda, 0x5d, 0x74, 0xb5, 0x43, 0x9b, 0x8b, 0xaa, 0x2d, 0x9e, 0xa9,
+ 0xb1, 0x86, 0xae, 0xd3, 0x82, 0x1c, 0xae, 0xaa, 0xfa, 0x44, 0xf9, 0xbc,
+ 0x99, 0xe2, 0x45, 0x6e, 0xd3, 0xa5, 0xae, 0x5f, 0x64, 0xfc, 0x5b, 0x14,
+ 0x32, 0x22, 0xfb, 0xd2, 0x54, 0xee, 0x8b, 0xc4, 0xed, 0xb8, 0xa7, 0x5d,
+ 0xe5, 0x62, 0xbe, 0x25, 0xd7, 0x05, 0x54, 0x1f, 0xe4, 0x75, 0xfe, 0x5c,
+ 0xaa, 0xf6, 0x29, 0xdf, 0x28, 0xea, 0x75, 0x88, 0x8f, 0x7d, 0x33, 0xd9,
+ 0x77, 0x7c, 0x32, 0xe7, 0xd8, 0x14, 0x6b, 0xa9, 0x32, 0x7f, 0x43, 0x7f,
+ 0x47, 0xac, 0x19, 0x39, 0x16, 0xc8, 0x9f, 0x70, 0xeb, 0x16, 0x39, 0xb6,
+ 0x00, 0x6c, 0x50, 0x11, 0x6b, 0xa8, 0x1b, 0xe1, 0xe7, 0xbd, 0xcc, 0x9b,
+ 0xe6, 0x36, 0x70, 0xe8, 0x56, 0x64, 0xcd, 0xf2, 0x90, 0x35, 0xf7, 0xfb,
+ 0x51, 0xcb, 0x87, 0x9a, 0x3e, 0x67, 0xd8, 0xa0, 0x12, 0xfb, 0x0a, 0x06,
+ 0x15, 0x4c, 0x1f, 0x9d, 0xb3, 0x23, 0xd1, 0x25, 0x81, 0x37, 0xef, 0x43,
+ 0xce, 0xcf, 0xf0, 0x2a, 0x1d, 0x36, 0xcf, 0x92, 0xdc, 0xef, 0xa1, 0xc0,
+ 0xb6, 0x77, 0x9a, 0xf9, 0xed, 0x2c, 0xfb, 0x1f, 0xce, 0x14, 0xd6, 0x5d,
+ 0x34, 0xcd, 0xb0, 0x0f, 0x00, 0x3e, 0x2d, 0x9e, 0xa7, 0xe2, 0x6e, 0x0a,
+ 0xc6, 0xf8, 0x99, 0x16, 0x74, 0x11, 0x3f, 0x27, 0x49, 0x71, 0xf6, 0x93,
+ 0xe0, 0xb3, 0x4e, 0x4f, 0x45, 0xcc, 0x02, 0x19, 0xdc, 0x16, 0xbe, 0x2b,
+ 0x9e, 0x83, 0xfb, 0x63, 0x66, 0x13, 0xd5, 0xd6, 0x1c, 0xb7, 0x8b, 0x3a,
+ 0xcc, 0x9b, 0xd1, 0x7b, 0xc8, 0xe8, 0x81, 0x6e, 0xc2, 0x9c, 0xdd, 0xad,
+ 0xd6, 0x8b, 0x3a, 0xf8, 0xfb, 0x90, 0xfa, 0x2e, 0xe7, 0x5a, 0x7e, 0xd7,
+ 0xbc, 0x8c, 0xbf, 0x0f, 0x5b, 0xc8, 0xfe, 0x5d, 0x35, 0x7f, 0xd5, 0xeb,
+ 0x66, 0xfd, 0x46, 0x90, 0xce, 0x7b, 0xae, 0x9b, 0x6d, 0x54, 0xcb, 0xdb,
+ 0xb1, 0xc5, 0x5a, 0xde, 0x9f, 0xef, 0x96, 0xf5, 0x71, 0xee, 0xbe, 0xfc,
+ 0x9c, 0xfb, 0xe2, 0x15, 0x0f, 0x71, 0xeb, 0x5e, 0xad, 0x73, 0x4b, 0xf4,
+ 0x6f, 0xd1, 0xcf, 0xd2, 0x7a, 0x28, 0xac, 0xf2, 0x99, 0x90, 0xbf, 0x74,
+ 0x8f, 0xe2, 0x55, 0xad, 0xe7, 0xc9, 0x43, 0xcf, 0x3f, 0x20, 0xf2, 0x8e,
+ 0xa5, 0x9d, 0xd8, 0xaf, 0xe8, 0x01, 0x9a, 0x85, 0x5d, 0x34, 0xeb, 0x76,
+ 0xd1, 0xcc, 0x50, 0xdf, 0x77, 0x89, 0xe3, 0xf3, 0x4b, 0xaf, 0x76, 0xc8,
+ 0x7a, 0x78, 0xac, 0x29, 0x7e, 0x5f, 0x7d, 0xdf, 0x6c, 0xbc, 0x0f, 0x84,
+ 0x28, 0x28, 0xe2, 0x4d, 0xae, 0xb1, 0xbe, 0x44, 0x64, 0xb3, 0x37, 0x5c,
+ 0x47, 0x83, 0x6f, 0xb9, 0xce, 0xa3, 0x8f, 0x83, 0xae, 0x3e, 0xf6, 0xbb,
+ 0xfa, 0x78, 0xb0, 0x41, 0x1f, 0x59, 0x9f, 0xf3, 0x7b, 0xce, 0x16, 0x3f,
+ 0x69, 0x5f, 0xd1, 0x4f, 0xd4, 0x49, 0x83, 0x9e, 0x3b, 0x29, 0x1d, 0x0a,
+ 0x2b, 0x3b, 0x11, 0x55, 0xf5, 0x03, 0x5e, 0x7d, 0xfe, 0x31, 0x35, 0x9e,
+ 0x37, 0x37, 0xaf, 0xba, 0xeb, 0xab, 0x9f, 0xa3, 0x09, 0x59, 0x27, 0xaf,
+ 0x64, 0xfb, 0x62, 0x83, 0x78, 0x34, 0x72, 0x3b, 0x80, 0x37, 0x84, 0x6f,
+ 0xb8, 0x4f, 0xee, 0x6f, 0x17, 0xa0, 0xe5, 0x72, 0xad, 0xb2, 0x5f, 0xd5,
+ 0xf0, 0x3d, 0x1b, 0xba, 0xb3, 0x75, 0xca, 0x38, 0xff, 0x3d, 0x11, 0xcb,
+ 0x93, 0xeb, 0x48, 0xab, 0xaa, 0xde, 0x3a, 0x62, 0x21, 0x47, 0x60, 0x71,
+ 0x05, 0x71, 0xd8, 0x46, 0xb5, 0xc9, 0x52, 0x17, 0xa5, 0xca, 0x7b, 0xc2,
+ 0x14, 0x44, 0x1d, 0x86, 0x8c, 0x8f, 0xc9, 0x1a, 0xe2, 0xc5, 0x95, 0x1b,
+ 0xa2, 0x6e, 0x37, 0xae, 0x6a, 0x91, 0x53, 0xd4, 0x26, 0x70, 0xed, 0x27,
+ 0xaf, 0x21, 0xfe, 0x71, 0x68, 0xfb, 0x35, 0xc4, 0xee, 0x7b, 0xb6, 0x57,
+ 0x43, 0x6c, 0xf2, 0xd8, 0x8d, 0x05, 0x59, 0x43, 0x5c, 0xbd, 0x46, 0x23,
+ 0x6b, 0x88, 0x53, 0x2e, 0xac, 0x20, 0xf1, 0xf9, 0x4d, 0x57, 0x7e, 0xb7,
+ 0xac, 0x0f, 0x5e, 0x2c, 0xe3, 0x53, 0x59, 0x1f, 0x2c, 0xf3, 0xc1, 0xdd,
+ 0x7b, 0xdf, 0xc8, 0xb5, 0x20, 0xf9, 0x9e, 0x5d, 0x35, 0x6b, 0x41, 0xb2,
+ 0x2e, 0xd8, 0x32, 0xbc, 0xf8, 0x4e, 0xdb, 0x25, 0xec, 0xf7, 0x10, 0x63,
+ 0xde, 0xdd, 0xd9, 0x60, 0xbf, 0x87, 0x58, 0x83, 0xfd, 0x1e, 0xdc, 0xba,
+ 0xdf, 0x8d, 0xa7, 0x80, 0x7f, 0x61, 0x17, 0x81, 0x7b, 0xb1, 0x5f, 0x43,
+ 0x94, 0xce, 0x97, 0x71, 0xe6, 0x3d, 0x94, 0x54, 0x38, 0xf3, 0xfc, 0x92,
+ 0xd6, 0x47, 0xfd, 0x35, 0xfa, 0xc8, 0x0b, 0x77, 0x46, 0x54, 0xce, 0x8f,
+ 0x96, 0x57, 0xc7, 0x25, 0xaf, 0x8e, 0x87, 0xbc, 0xe2, 0x1e, 0xa7, 0x41,
+ 0xbf, 0x41, 0x13, 0xdc, 0x83, 0xff, 0x97, 0xc2, 0xd8, 0xa7, 0x86, 0xe8,
+ 0x0b, 0xdd, 0x0a, 0xeb, 0xb9, 0xe4, 0xf5, 0x2c, 0xcb, 0xab, 0x3e, 0x8f,
+ 0xfe, 0x36, 0xc2, 0xfb, 0x1a, 0x1f, 0xee, 0xf7, 0x1d, 0xbb, 0xf2, 0x0b,
+ 0x91, 0x17, 0x50, 0xed, 0x27, 0x6a, 0x0c, 0x71, 0x48, 0xc8, 0xd2, 0xba,
+ 0x1f, 0xf9, 0x2b, 0xfa, 0x1c, 0x6a, 0xa7, 0x20, 0x7f, 0x9a, 0x16, 0xcd,
+ 0x35, 0x38, 0xa3, 0x5d, 0xe1, 0x08, 0x91, 0xff, 0xeb, 0xea, 0xdb, 0x7f,
+ 0x72, 0xdf, 0xf4, 0x79, 0x6d, 0x33, 0xdf, 0xae, 0x8a, 0x69, 0x54, 0xe7,
+ 0x4d, 0x22, 0x7e, 0xb4, 0x2b, 0x69, 0xd8, 0x09, 0x91, 0x7f, 0xda, 0x69,
+ 0x23, 0x56, 0x16, 0x67, 0xd9, 0xef, 0x4c, 0x22, 0xd7, 0xb9, 0xf3, 0x92,
+ 0x45, 0xa7, 0xb2, 0x57, 0x0f, 0x48, 0x5e, 0x79, 0x5a, 0xec, 0xd3, 0x89,
+ 0x7d, 0x1d, 0x27, 0xd8, 0x3e, 0xc7, 0x19, 0x60, 0xce, 0x15, 0x5b, 0x68,
+ 0x91, 0x91, 0xbc, 0xdf, 0x2e, 0x88, 0x58, 0x1f, 0xeb, 0xa4, 0x1c, 0xf6,
+ 0x6b, 0x35, 0x16, 0x9a, 0xf9, 0xb9, 0x3d, 0xb4, 0x9c, 0x07, 0xcf, 0x35,
+ 0xa9, 0xfd, 0x53, 0xd0, 0xd6, 0x47, 0x5d, 0xf6, 0xdf, 0x32, 0xed, 0x1e,
+ 0x11, 0x79, 0x97, 0x8b, 0xb9, 0xa7, 0xe5, 0x67, 0xe1, 0x55, 0xf5, 0x0e,
+ 0x7e, 0x5f, 0xf1, 0x75, 0x8a, 0x75, 0xb9, 0xf3, 0x00, 0xdd, 0x7f, 0xde,
+ 0x78, 0xe5, 0xe4, 0xb6, 0xf0, 0x8a, 0x93, 0xac, 0xe0, 0x15, 0xf7, 0xb3,
+ 0x35, 0x76, 0xf9, 0xe3, 0x1e, 0xb9, 0x9f, 0x05, 0x68, 0xb0, 0x13, 0x58,
+ 0x2c, 0x09, 0x5a, 0x1a, 0xe3, 0x91, 0x70, 0xdc, 0x3f, 0x46, 0x99, 0xe2,
+ 0x35, 0x4a, 0xe5, 0x60, 0xe7, 0xf9, 0xb3, 0xf0, 0x37, 0x7b, 0x64, 0x9c,
+ 0x46, 0xdf, 0x03, 0xbd, 0xb2, 0x9b, 0xdb, 0x37, 0xef, 0x91, 0x39, 0xdb,
+ 0xee, 0xf3, 0xed, 0x7c, 0xfe, 0xc9, 0x70, 0xf5, 0xf9, 0x1d, 0x7c, 0xbe,
+ 0x2b, 0x89, 0x39, 0x34, 0x2e, 0x21, 0x36, 0x39, 0x4c, 0x69, 0x9e, 0x9f,
+ 0x4c, 0x91, 0x6d, 0xeb, 0x65, 0xd6, 0x57, 0x4b, 0xba, 0x5d, 0x37, 0xb7,
+ 0x0b, 0x89, 0x39, 0x31, 0xb8, 0xcd, 0x6c, 0x76, 0x84, 0xdb, 0xed, 0x27,
+ 0xff, 0x65, 0x8b, 0x32, 0x4b, 0x9a, 0x57, 0x75, 0x2e, 0xfe, 0x2f, 0xba,
+ 0x65, 0x6e, 0xd5, 0xae, 0xb0, 0xa4, 0xdf, 0xb0, 0x88, 0x7b, 0x22, 0xb7,
+ 0xe3, 0x19, 0xc1, 0x87, 0x91, 0x31, 0xab, 0xfc, 0x7e, 0xec, 0x31, 0x26,
+ 0xf6, 0x7c, 0xe5, 0x31, 0xb0, 0x5e, 0x1c, 0xb7, 0xcd, 0x74, 0x39, 0x6f,
+ 0x6d, 0x6d, 0x9f, 0xbc, 0x7f, 0x67, 0x8f, 0xdc, 0x7f, 0xb5, 0x53, 0xed,
+ 0x15, 0xa8, 0x6d, 0xce, 0x17, 0x90, 0xa7, 0x2d, 0x68, 0xe3, 0x5f, 0x80,
+ 0xbe, 0x34, 0xf8, 0x3b, 0x8f, 0x27, 0x89, 0x3e, 0xf6, 0xf6, 0xe8, 0x3d,
+ 0x17, 0xe5, 0xb8, 0x4e, 0x70, 0x7f, 0x13, 0x3c, 0x2e, 0x7d, 0x3e, 0xc6,
+ 0xc7, 0x5e, 0xf3, 0x8b, 0x67, 0x05, 0xf9, 0x39, 0x2c, 0x03, 0x53, 0xc1,
+ 0x64, 0x6a, 0x58, 0xce, 0x73, 0x25, 0xae, 0x1b, 0x2e, 0xc7, 0x75, 0xe7,
+ 0xb2, 0xc7, 0x7b, 0x10, 0xcf, 0x30, 0x2e, 0xf1, 0x7c, 0x87, 0x9e, 0xe1,
+ 0xb6, 0xa8, 0x63, 0x48, 0xf3, 0x67, 0x9b, 0xca, 0xef, 0xa9, 0xe7, 0x15,
+ 0x99, 0x2f, 0xa1, 0xed, 0x16, 0xee, 0xbd, 0x97, 0x9f, 0x21, 0x6d, 0x57,
+ 0xe3, 0xf7, 0x50, 0x5d, 0x4e, 0x4c, 0x3d, 0x8f, 0x6d, 0x14, 0x8b, 0x15,
+ 0xeb, 0x8a, 0x1e, 0x7c, 0xb6, 0x51, 0xac, 0x44, 0xe4, 0x39, 0xfb, 0x26,
+ 0xea, 0xe4, 0x15, 0x72, 0x1c, 0xa0, 0x27, 0xe6, 0x1d, 0xda, 0xc1, 0x73,
+ 0xf5, 0x27, 0x06, 0xea, 0x86, 0x4b, 0x24, 0x73, 0x9f, 0x98, 0xc6, 0x59,
+ 0x7b, 0xf8, 0xac, 0xc1, 0x74, 0xce, 0x3a, 0xa5, 0x80, 0xdd, 0x46, 0xcd,
+ 0x2c, 0xab, 0xbf, 0x4f, 0x03, 0xec, 0xeb, 0x41, 0x66, 0xed, 0x70, 0x82,
+ 0x20, 0x6f, 0x11, 0xf3, 0x18, 0xf3, 0xc4, 0x44, 0x11, 0xfc, 0x6c, 0xd0,
+ 0x63, 0x79, 0xa2, 0x47, 0xf3, 0x03, 0xe6, 0x37, 0xc9, 0xb6, 0x2a, 0xd7,
+ 0x23, 0x66, 0x9c, 0xfb, 0x91, 0x28, 0xfe, 0x25, 0x7d, 0x24, 0xf6, 0x71,
+ 0x01, 0x1d, 0xf5, 0xbc, 0xff, 0x39, 0x4d, 0x27, 0xd1, 0xef, 0xad, 0xcb,
+ 0xe7, 0xa9, 0x6d, 0xc9, 0x67, 0xd0, 0x43, 0x3e, 0x3f, 0x54, 0x7c, 0x53,
+ 0x62, 0x1e, 0x0d, 0xd2, 0x4c, 0x0e, 0xb9, 0x60, 0x9f, 0x47, 0x0d, 0x66,
+ 0x2e, 0xc5, 0x7a, 0x29, 0x55, 0xd1, 0x4b, 0x17, 0xe2, 0xfe, 0x18, 0x64,
+ 0x1c, 0x7b, 0xd1, 0xa9, 0x1c, 0x20, 0x8c, 0x63, 0x1f, 0x0d, 0x2c, 0xec,
+ 0xe4, 0x7b, 0x69, 0x35, 0x3e, 0x1a, 0x53, 0x7b, 0x15, 0x44, 0xac, 0x09,
+ 0xd6, 0x8f, 0x73, 0x2c, 0xcb, 0xe9, 0xdc, 0xdd, 0xb4, 0x18, 0xea, 0xa5,
+ 0xfe, 0x05, 0xbd, 0x7f, 0x0b, 0xc6, 0x3a, 0xd4, 0x2b, 0x75, 0x92, 0x1e,
+ 0xf7, 0x6f, 0x89, 0x38, 0x85, 0x75, 0xed, 0x57, 0x35, 0xee, 0x9d, 0x9b,
+ 0xe8, 0xa5, 0x92, 0x92, 0xd9, 0xd2, 0x1b, 0xf1, 0x28, 0x39, 0xf1, 0xd1,
+ 0xff, 0x15, 0xfc, 0xdf, 0x7f, 0x0d, 0xb5, 0x38, 0xd0, 0xd1, 0x16, 0x25,
+ 0xb3, 0xb5, 0xb4, 0xe8, 0xe5, 0x71, 0xe3, 0x7a, 0xe9, 0xa7, 0x33, 0xd1,
+ 0x57, 0x85, 0xed, 0x1f, 0xb8, 0xc6, 0xed, 0x84, 0x6d, 0xd2, 0x7a, 0xc3,
+ 0x8b, 0x0f, 0xf5, 0xde, 0x9c, 0x9a, 0x17, 0x65, 0xce, 0x27, 0xe3, 0x37,
+ 0x33, 0xe9, 0xaf, 0xe5, 0xc9, 0x8f, 0xe9, 0xe4, 0xbc, 0x45, 0x93, 0x59,
+ 0xec, 0x81, 0x38, 0xc6, 0x72, 0xed, 0xb6, 0x17, 0xdc, 0x9e, 0xc0, 0x67,
+ 0xe3, 0x2c, 0xfb, 0xec, 0xb7, 0xe7, 0x2c, 0x99, 0x7f, 0x27, 0xf6, 0xdb,
+ 0x6b, 0x11, 0x7a, 0xd4, 0xb4, 0xfb, 0xf7, 0x68, 0x7b, 0x90, 0xca, 0xa1,
+ 0xce, 0x90, 0x3f, 0x0b, 0xdc, 0x3e, 0xdb, 0x43, 0xa9, 0x3c, 0x9e, 0x03,
+ 0x7b, 0x87, 0xbe, 0xf3, 0xf1, 0xb2, 0x9c, 0xd7, 0x7e, 0x7e, 0x36, 0xf6,
+ 0x0e, 0x98, 0x2c, 0x8e, 0x88, 0x1c, 0x3c, 0xe8, 0x66, 0x39, 0x9f, 0xe3,
+ 0x34, 0xeb, 0xa9, 0x57, 0x14, 0xa6, 0x74, 0xc9, 0x77, 0x4a, 0xc8, 0xf7,
+ 0xb8, 0x98, 0x8f, 0x54, 0xde, 0x60, 0xbc, 0xa6, 0xe3, 0x0c, 0x5d, 0x7c,
+ 0x1c, 0x50, 0x3a, 0x04, 0xd7, 0xee, 0xdd, 0x23, 0xf2, 0x13, 0x6d, 0x9c,
+ 0xc7, 0xe7, 0x38, 0x3d, 0xc3, 0xb8, 0xf3, 0xd9, 0x6c, 0x0b, 0xdd, 0xc8,
+ 0xb5, 0xd0, 0x9b, 0xb9, 0x5e, 0xba, 0x3e, 0xdf, 0x41, 0xb3, 0x8c, 0x99,
+ 0x67, 0xed, 0x80, 0x95, 0x66, 0xff, 0xe2, 0x6a, 0x54, 0xe4, 0x10, 0xb1,
+ 0xdc, 0xa1, 0x3d, 0xf0, 0x5f, 0x7c, 0x2f, 0xf3, 0x1c, 0x63, 0xef, 0x56,
+ 0xfa, 0x80, 0xdf, 0x99, 0xce, 0xea, 0x9c, 0x07, 0xc4, 0xe3, 0x07, 0xcb,
+ 0xf8, 0x75, 0x73, 0x1e, 0x31, 0x37, 0xe1, 0x91, 0x71, 0xa1, 0xeb, 0x33,
+ 0xf3, 0x7c, 0x7d, 0x1e, 0x71, 0x73, 0x4b, 0xc4, 0x24, 0xbe, 0x14, 0x40,
+ 0x7b, 0x9c, 0xb3, 0x65, 0xce, 0xa4, 0x18, 0x5b, 0x98, 0x8f, 0x41, 0xdb,
+ 0xb0, 0xa2, 0x43, 0x2b, 0x8f, 0x4f, 0xc6, 0x30, 0x52, 0xcb, 0xad, 0x74,
+ 0x26, 0xcf, 0x18, 0x24, 0xef, 0x67, 0x1f, 0x06, 0x6d, 0x7f, 0xe7, 0xa0,
+ 0xde, 0xd3, 0x76, 0x96, 0xfb, 0x9e, 0xce, 0x4b, 0x0c, 0x92, 0x5e, 0x6e,
+ 0xa7, 0x4c, 0xbe, 0x4d, 0x1d, 0xdf, 0x2d, 0xf2, 0xdd, 0xe5, 0xde, 0x12,
+ 0xb8, 0xb6, 0x91, 0x7e, 0x43, 0xae, 0x11, 0x6c, 0xaa, 0xf4, 0x4b, 0xa1,
+ 0x6b, 0xbc, 0xf3, 0x8c, 0xc6, 0xe8, 0x39, 0xb6, 0xb7, 0xfd, 0x97, 0x11,
+ 0x2b, 0xfe, 0x22, 0xf8, 0xa6, 0x00, 0x1e, 0xeb, 0xbf, 0x8c, 0x7d, 0x9f,
+ 0xfc, 0x22, 0xf7, 0x68, 0x22, 0x34, 0x2c, 0x6a, 0x46, 0xa4, 0x8c, 0x4e,
+ 0x89, 0xba, 0xec, 0xef, 0x08, 0xdd, 0x14, 0x71, 0x2c, 0x03, 0x78, 0x24,
+ 0x12, 0x26, 0x92, 0x39, 0x59, 0xa7, 0xec, 0xce, 0x9b, 0xdd, 0xe3, 0x43,
+ 0x14, 0xeb, 0x01, 0xdf, 0x4b, 0x99, 0x95, 0x7b, 0x22, 0x90, 0xd0, 0xf7,
+ 0xe6, 0x21, 0x5d, 0x63, 0xa0, 0x8f, 0xb5, 0xad, 0xd0, 0xc7, 0x6d, 0x35,
+ 0xd7, 0xcd, 0x9a, 0xeb, 0x1a, 0x7f, 0x63, 0xad, 0x8c, 0xed, 0x3c, 0xc9,
+ 0x3d, 0x98, 0x52, 0x0b, 0x92, 0xff, 0xcc, 0x43, 0x83, 0xe6, 0xfd, 0x0a,
+ 0x83, 0xa7, 0x56, 0x06, 0xc2, 0x9d, 0x46, 0x9b, 0x3f, 0x35, 0xf2, 0xaf,
+ 0xa5, 0x58, 0x12, 0xb8, 0xe8, 0xf5, 0x3d, 0x52, 0xc7, 0xa1, 0x5f, 0x4e,
+ 0x14, 0xd0, 0x6d, 0x6a, 0xa5, 0x8d, 0x56, 0xc5, 0x9e, 0x63, 0xc0, 0x18,
+ 0xb8, 0x1f, 0xcf, 0x71, 0xcc, 0x26, 0xc2, 0x3e, 0xf2, 0x90, 0xf1, 0xc3,
+ 0xe1, 0x6b, 0x3c, 0x9f, 0x89, 0x95, 0xff, 0x29, 0x4d, 0x8b, 0x7d, 0x7a,
+ 0xd0, 0x96, 0x31, 0xa4, 0xc0, 0xfc, 0x8c, 0x5f, 0xaa, 0xfc, 0xaa, 0x31,
+ 0xf4, 0xd3, 0xc1, 0x9a, 0x8a, 0x61, 0xbf, 0xc0, 0x32, 0x26, 0xd7, 0xca,
+ 0x13, 0x35, 0x6b, 0xe5, 0x53, 0x62, 0xad, 0x1c, 0xeb, 0xe4, 0x1b, 0xe5,
+ 0x2d, 0xea, 0x3c, 0x16, 0x8b, 0x66, 0xaf, 0x08, 0x7d, 0x13, 0x9d, 0xf0,
+ 0xcb, 0x3c, 0xeb, 0x04, 0xbb, 0x37, 0x86, 0xa8, 0x6d, 0xc0, 0x67, 0xcc,
+ 0x88, 0xdb, 0x91, 0xe1, 0x35, 0xc6, 0x14, 0x4b, 0xb9, 0x1d, 0x74, 0xbd,
+ 0xd0, 0xc4, 0x98, 0xef, 0x9f, 0x69, 0xad, 0x40, 0x8c, 0x0d, 0x3b, 0x28,
+ 0x13, 0x65, 0x5e, 0x1b, 0x0e, 0xf2, 0xbc, 0x32, 0xbe, 0x1d, 0x66, 0xf9,
+ 0xe3, 0x31, 0x2c, 0xe5, 0x4b, 0xef, 0xa7, 0xa3, 0x31, 0x2b, 0x3e, 0xda,
+ 0xc6, 0xfe, 0x8b, 0xc9, 0xff, 0x36, 0xff, 0x9f, 0x0b, 0x83, 0x36, 0x8b,
+ 0xcb, 0xb8, 0xce, 0xd8, 0x27, 0x5b, 0x7a, 0x7f, 0x86, 0xdb, 0xcc, 0x8c,
+ 0xc2, 0x0f, 0x82, 0xbf, 0x67, 0xf3, 0xbf, 0x6c, 0xb3, 0xc4, 0x7c, 0x97,
+ 0xbe, 0xe2, 0x84, 0x0d, 0xa1, 0xe3, 0xb1, 0x2f, 0xcd, 0x80, 0xfa, 0x8c,
+ 0x19, 0x33, 0xdc, 0x97, 0xeb, 0x84, 0x67, 0x58, 0x94, 0x8a, 0x1e, 0x62,
+ 0x39, 0xe8, 0xe0, 0x4f, 0xd4, 0x6a, 0xed, 0xa4, 0xcc, 0xc8, 0xa0, 0xaa,
+ 0xd5, 0xfa, 0x59, 0x83, 0x5a, 0x2d, 0xdc, 0xc7, 0x38, 0x60, 0xbe, 0x74,
+ 0x7b, 0x26, 0xea, 0x7e, 0x2f, 0x19, 0xa9, 0xe8, 0x2e, 0x81, 0x99, 0x96,
+ 0x96, 0x1f, 0xe6, 0x3e, 0xc4, 0xac, 0xd4, 0x28, 0xf7, 0x35, 0xef, 0xee,
+ 0x7f, 0xe9, 0xf6, 0x44, 0x14, 0xed, 0xfc, 0x35, 0xed, 0x62, 0x24, 0xda,
+ 0x2e, 0xa3, 0x7d, 0xe9, 0x97, 0xf1, 0xa8, 0x1e, 0xa7, 0xfb, 0x5e, 0x8c,
+ 0x07, 0xf2, 0xc5, 0x9f, 0x4b, 0xef, 0xd0, 0xf5, 0x1c, 0xfc, 0x71, 0x43,
+ 0xd5, 0x5f, 0x59, 0xe4, 0x2c, 0x31, 0x06, 0xbc, 0x72, 0xd0, 0xb7, 0x96,
+ 0xfb, 0x41, 0x29, 0x55, 0x95, 0xdb, 0x52, 0x1d, 0x73, 0x97, 0x3e, 0x58,
+ 0x2f, 0xd9, 0x97, 0x60, 0x43, 0x61, 0x3f, 0x9d, 0x92, 0xdf, 0x06, 0xde,
+ 0x83, 0x6f, 0xf4, 0x34, 0xeb, 0x2f, 0x99, 0x9f, 0xc4, 0xba, 0x94, 0x75,
+ 0x98, 0x94, 0x9f, 0x44, 0xd5, 0x4f, 0x3c, 0x48, 0x1e, 0xee, 0xaf, 0xe4,
+ 0x49, 0xba, 0xd6, 0xd8, 0x03, 0xae, 0x35, 0x76, 0xd3, 0x95, 0x27, 0x19,
+ 0x12, 0xf8, 0xac, 0x82, 0xa9, 0x42, 0x0a, 0x53, 0x01, 0x7b, 0x49, 0xdd,
+ 0xb6, 0x58, 0xd6, 0x6d, 0xbb, 0x37, 0xd1, 0x6d, 0x5e, 0xbe, 0xea, 0xaa,
+ 0xd2, 0x23, 0x91, 0x28, 0x6c, 0x0c, 0xf6, 0x59, 0xfa, 0xfb, 0xe2, 0x28,
+ 0xeb, 0x91, 0x28, 0xeb, 0x91, 0x11, 0xd6, 0x23, 0xc3, 0xac, 0x47, 0x6c,
+ 0xa6, 0x81, 0xc5, 0x63, 0xff, 0x98, 0xf5, 0x34, 0xec, 0xc7, 0x18, 0x3d,
+ 0x53, 0x84, 0x4e, 0x1e, 0x61, 0x0c, 0xf4, 0x31, 0xad, 0xcd, 0xb7, 0x33,
+ 0xff, 0x4a, 0xdc, 0x53, 0xed, 0xd7, 0x60, 0xdf, 0x18, 0xc4, 0x86, 0x7f,
+ 0x08, 0xbd, 0xf3, 0xb2, 0x43, 0x7d, 0xbe, 0xeb, 0x39, 0xd0, 0x79, 0x0d,
+ 0x7b, 0x6b, 0xbc, 0x08, 0xd9, 0xc6, 0xbe, 0xc7, 0xdf, 0x1e, 0x1a, 0xe3,
+ 0xbe, 0xf7, 0xf9, 0x32, 0x3c, 0x2f, 0x8f, 0x47, 0x1d, 0xb3, 0x8b, 0x65,
+ 0x60, 0x52, 0xc9, 0xc0, 0x64, 0x45, 0x06, 0x9c, 0x34, 0x8f, 0xa4, 0x73,
+ 0xa1, 0x83, 0x06, 0x8f, 0xc4, 0xf7, 0x76, 0xb2, 0xfc, 0x22, 0x67, 0xa2,
+ 0xb2, 0xff, 0x90, 0x9f, 0xa6, 0x43, 0x41, 0xb5, 0x6f, 0x91, 0xc5, 0x76,
+ 0xf3, 0x27, 0x94, 0xc9, 0xbd, 0xcb, 0xb8, 0x84, 0xe5, 0xd4, 0xc4, 0xf1,
+ 0x45, 0xc4, 0x45, 0xd9, 0x6f, 0x68, 0x15, 0x71, 0xa5, 0x45, 0xd1, 0x16,
+ 0xc7, 0x91, 0x61, 0xd6, 0x71, 0xd1, 0x55, 0x23, 0x32, 0x16, 0x33, 0x2e,
+ 0xf7, 0x62, 0x5f, 0xfa, 0x6f, 0x17, 0x1f, 0xeb, 0x95, 0xf5, 0xb9, 0x4f,
+ 0xed, 0x95, 0xfa, 0x84, 0x79, 0x34, 0x14, 0x13, 0xbe, 0x5b, 0xd3, 0x25,
+ 0x69, 0x3f, 0x17, 0x79, 0xbe, 0x97, 0xa2, 0xc3, 0x3c, 0xdf, 0x6d, 0xca,
+ 0x76, 0x3a, 0x7c, 0x5d, 0xd8, 0x65, 0xb6, 0xa1, 0xbd, 0xd8, 0xd3, 0xdf,
+ 0x8c, 0x47, 0x9f, 0xe2, 0x77, 0x62, 0x1f, 0xa1, 0x2f, 0xe3, 0x79, 0xcc,
+ 0xbd, 0xd0, 0x1f, 0x3f, 0x61, 0x1b, 0x8d, 0xf7, 0x82, 0x1f, 0xf9, 0x7b,
+ 0x61, 0x8c, 0x2e, 0x64, 0x75, 0x1f, 0xde, 0x23, 0xe3, 0x39, 0xf4, 0xc3,
+ 0x47, 0xbb, 0xed, 0xf7, 0x44, 0x4d, 0x88, 0xf1, 0x8d, 0xda, 0x3e, 0x7d,
+ 0x45, 0xf5, 0x09, 0x7b, 0x79, 0xb6, 0xf0, 0x18, 0x76, 0x13, 0xf6, 0x74,
+ 0x5a, 0x14, 0x7b, 0x6d, 0x36, 0x0b, 0x9f, 0x75, 0x51, 0xf8, 0x1e, 0x0f,
+ 0xef, 0xad, 0xec, 0xff, 0x79, 0x57, 0xcd, 0xb9, 0x75, 0xb6, 0x5b, 0x47,
+ 0x05, 0x46, 0xeb, 0xc7, 0x1e, 0xf4, 0xa2, 0x66, 0xf5, 0x4f, 0xc5, 0x35,
+ 0x63, 0x01, 0xd7, 0x3e, 0xa7, 0xae, 0x7d, 0x56, 0x60, 0x63, 0x63, 0xbc,
+ 0x95, 0xf5, 0xa2, 0xe0, 0x77, 0x9e, 0x67, 0x7b, 0x98, 0xf9, 0x3d, 0xbc,
+ 0xc4, 0xcf, 0x9d, 0x16, 0xf4, 0xd4, 0xf4, 0x00, 0x2d, 0x20, 0x03, 0x6d,
+ 0x8a, 0xff, 0x23, 0x56, 0xc2, 0xaf, 0xc7, 0xdd, 0x88, 0xce, 0x63, 0xb0,
+ 0xcf, 0x3c, 0x56, 0x8c, 0xc9, 0xf2, 0xc5, 0x0a, 0x61, 0x5f, 0x7a, 0x1e,
+ 0xbe, 0x0e, 0xea, 0x5e, 0x0e, 0x20, 0x9f, 0x8a, 0xfb, 0xb0, 0x87, 0x62,
+ 0x49, 0xf4, 0x0b, 0xed, 0x34, 0x0d, 0xfe, 0xa8, 0x86, 0x16, 0xee, 0xfb,
+ 0x3a, 0xd4, 0x7d, 0xad, 0x62, 0x2e, 0xc8, 0xc0, 0x7b, 0xf4, 0xbb, 0xf1,
+ 0x5e, 0xbc, 0x1f, 0xf7, 0xe1, 0x79, 0xf2, 0xb9, 0xdd, 0xac, 0xb7, 0xe3,
+ 0xa3, 0xf2, 0x59, 0xc6, 0x35, 0x79, 0xad, 0xdb, 0xf6, 0xee, 0xaf, 0x9c,
+ 0x3f, 0x9f, 0xda, 0x83, 0x08, 0xf3, 0xd7, 0x41, 0x05, 0x11, 0xfb, 0xc4,
+ 0xb5, 0x3e, 0x9f, 0xf0, 0x6b, 0x6d, 0xfe, 0xe4, 0x79, 0x9d, 0xe3, 0xe3,
+ 0x33, 0xb9, 0x77, 0x84, 0xcf, 0x9e, 0x4e, 0xf6, 0xf9, 0x0a, 0x05, 0x8c,
+ 0xb7, 0xcf, 0x97, 0x60, 0x19, 0x98, 0xc8, 0xc5, 0x4b, 0x19, 0xa1, 0x6b,
+ 0x18, 0xeb, 0x76, 0x45, 0xcc, 0x69, 0xa3, 0x47, 0x60, 0x3e, 0x7e, 0x1f,
+ 0x7f, 0x67, 0x39, 0xcc, 0xb2, 0x1c, 0x66, 0x59, 0x0e, 0xb3, 0x2c, 0x87,
+ 0xec, 0xab, 0x7e, 0x2b, 0xcb, 0x72, 0xc8, 0xb6, 0xe4, 0x15, 0xb6, 0x25,
+ 0x52, 0x76, 0x63, 0x2a, 0xbe, 0xa9, 0x65, 0x17, 0xeb, 0x7f, 0x6e, 0x1f,
+ 0x47, 0xcb, 0x2a, 0xec, 0x37, 0xf9, 0x8e, 0x0f, 0x55, 0xcb, 0xec, 0x0d,
+ 0x96, 0xd9, 0xa6, 0xf1, 0x1e, 0xba, 0x95, 0xc7, 0x9c, 0x45, 0xac, 0x39,
+ 0xd6, 0xd5, 0x09, 0x3f, 0xb0, 0x56, 0x80, 0xe5, 0x09, 0x58, 0x33, 0xc2,
+ 0x74, 0xef, 0xa1, 0xdb, 0xac, 0xaf, 0x6f, 0xe5, 0x21, 0xc3, 0x07, 0xd4,
+ 0x71, 0x84, 0x65, 0x18, 0xf6, 0xcf, 0xf6, 0xdd, 0xc8, 0x19, 0x8c, 0xc9,
+ 0x02, 0x66, 0x8a, 0xa0, 0x4f, 0x05, 0x4e, 0xe3, 0x79, 0x5f, 0x65, 0xbd,
+ 0x8f, 0x18, 0x1e, 0xec, 0xc5, 0x19, 0x1f, 0xdb, 0x8b, 0xf0, 0x75, 0xd6,
+ 0xa7, 0xe7, 0xf3, 0x36, 0xcb, 0x7d, 0x17, 0xfd, 0x59, 0x1e, 0x76, 0x1a,
+ 0x34, 0xe2, 0xe3, 0x02, 0x89, 0xd8, 0x98, 0x31, 0x8e, 0xb1, 0x0f, 0x3a,
+ 0x86, 0xe0, 0x93, 0xdb, 0x98, 0x23, 0xa6, 0xfd, 0x3b, 0x7b, 0xb1, 0x9f,
+ 0x7e, 0xcc, 0x68, 0x56, 0xb1, 0x46, 0x7c, 0x47, 0xfb, 0x1e, 0x85, 0x4d,
+ 0x71, 0xdc, 0x68, 0x0d, 0x12, 0xbf, 0x43, 0x11, 0x65, 0x7a, 0xd4, 0xea,
+ 0xaf, 0x0b, 0x7c, 0xbf, 0xa0, 0xd7, 0x58, 0xdc, 0x8f, 0xfa, 0x72, 0xfa,
+ 0xaa, 0x7f, 0x7c, 0x8c, 0x9e, 0x2d, 0xa2, 0xdf, 0x97, 0x29, 0x13, 0x82,
+ 0x3e, 0x8a, 0x44, 0xd7, 0x49, 0xd2, 0xae, 0x95, 0x71, 0xe7, 0x63, 0xde,
+ 0x3a, 0xce, 0x8a, 0x0b, 0x9c, 0xdc, 0xc2, 0xfa, 0x05, 0xb4, 0xf9, 0x3e,
+ 0xf3, 0x5a, 0x14, 0x75, 0x69, 0x4a, 0xbf, 0xbd, 0xce, 0x3a, 0x07, 0x73,
+ 0x86, 0xe3, 0x8d, 0x75, 0xda, 0x9a, 0xd2, 0x69, 0xb6, 0x4b, 0xa7, 0xa5,
+ 0xcb, 0x3a, 0x8d, 0x79, 0x43, 0xe8, 0xb2, 0xa0, 0xa8, 0x8d, 0x4e, 0xab,
+ 0xef, 0xc0, 0x87, 0xbb, 0x85, 0xee, 0x62, 0xdd, 0x3f, 0x84, 0x3d, 0xc8,
+ 0x1c, 0xdf, 0x31, 0xa1, 0x43, 0x34, 0x7f, 0x3f, 0xbc, 0x4f, 0xca, 0x45,
+ 0xab, 0xd0, 0x07, 0xe9, 0x29, 0xe8, 0x2d, 0xaf, 0xf6, 0x0f, 0x72, 0x3b,
+ 0xb4, 0xb7, 0xc3, 0x2f, 0xb2, 0x3e, 0x5b, 0x8c, 0xc2, 0xa7, 0x6d, 0x53,
+ 0xbe, 0x0f, 0xf6, 0x14, 0xc3, 0x5a, 0x17, 0xc6, 0xaa, 0xf5, 0x59, 0xb7,
+ 0x8a, 0x6b, 0x20, 0x0e, 0x89, 0x39, 0x6f, 0x88, 0x11, 0x2c, 0x60, 0x04,
+ 0xbe, 0x27, 0xc0, 0xf4, 0x82, 0x7e, 0x61, 0x3b, 0xf0, 0x2e, 0xad, 0x09,
+ 0xd9, 0x78, 0x57, 0x60, 0x97, 0x0c, 0x5f, 0x9b, 0x19, 0x7d, 0x54, 0xf4,
+ 0x33, 0xb3, 0x5c, 0xd1, 0x8f, 0x73, 0xd9, 0xf7, 0x60, 0x37, 0x44, 0x5f,
+ 0x97, 0x86, 0xa4, 0x0e, 0x5c, 0x2c, 0x98, 0xd8, 0xe3, 0x0c, 0x7d, 0xe6,
+ 0xbe, 0xea, 0x71, 0xa2, 0x1f, 0x5a, 0x1f, 0x6c, 0x45, 0xf6, 0x18, 0xd7,
+ 0x76, 0x61, 0x8e, 0x1c, 0x17, 0x0f, 0x7d, 0x8f, 0xdf, 0x8f, 0x73, 0x9b,
+ 0x8f, 0xe7, 0x76, 0x79, 0x3c, 0x88, 0xed, 0xe1, 0x9e, 0x77, 0xe9, 0x96,
+ 0x1a, 0xcf, 0xad, 0xf2, 0x78, 0xbe, 0xab, 0xc6, 0x43, 0x69, 0x63, 0xbc,
+ 0x5b, 0xe1, 0xfe, 0x2d, 0x3f, 0xbb, 0x35, 0xce, 0x38, 0x26, 0xbd, 0x0c,
+ 0x3a, 0xdf, 0xa5, 0xf8, 0xc9, 0x1d, 0x47, 0x75, 0xf7, 0x35, 0x32, 0xbc,
+ 0xce, 0xfa, 0xf7, 0xb6, 0xc0, 0x31, 0x7d, 0x8c, 0x63, 0x70, 0x9e, 0x32,
+ 0xd0, 0xd3, 0xe9, 0x10, 0xf6, 0xe1, 0x1d, 0xe3, 0x71, 0xb3, 0x3f, 0x36,
+ 0xca, 0x9f, 0x22, 0xbe, 0x26, 0xe2, 0xbe, 0xea, 0xfe, 0xaf, 0xd3, 0xed,
+ 0x79, 0xe8, 0x72, 0xe0, 0x58, 0xb9, 0x57, 0xef, 0xed, 0x15, 0x19, 0xdf,
+ 0x4d, 0x78, 0xc6, 0x77, 0x11, 0xdb, 0x1d, 0x05, 0xce, 0x37, 0x11, 0x07,
+ 0x9e, 0x50, 0xbf, 0x5f, 0x92, 0x2e, 0xe2, 0x59, 0x5e, 0x7a, 0x69, 0xcc,
+ 0x95, 0x1f, 0x87, 0xbc, 0x14, 0x87, 0xf5, 0x8c, 0x6d, 0x36, 0x19, 0x47,
+ 0x65, 0x9c, 0xb9, 0xa8, 0xb1, 0xd3, 0x09, 0x9e, 0x33, 0x3b, 0x6a, 0x18,
+ 0x09, 0x11, 0x6b, 0x68, 0xb5, 0xdb, 0xa8, 0x85, 0xed, 0xe8, 0x59, 0xc2,
+ 0x3e, 0x70, 0x11, 0x0b, 0x6b, 0x00, 0x17, 0x98, 0x27, 0x33, 0xd1, 0x48,
+ 0xf8, 0x51, 0xe1, 0x97, 0xc2, 0xbe, 0x18, 0xa0, 0x13, 0xd3, 0x1a, 0x7d,
+ 0xe0, 0xef, 0xcb, 0xd8, 0x0b, 0x34, 0xca, 0xe3, 0x47, 0xfc, 0x78, 0xc0,
+ 0x7a, 0x93, 0xed, 0xd2, 0x05, 0x11, 0x97, 0x79, 0x9a, 0xd2, 0x2c, 0xa7,
+ 0xc7, 0x85, 0x9c, 0x1a, 0x7d, 0x2c, 0x45, 0x2c, 0x57, 0xc8, 0x43, 0x18,
+ 0x44, 0x0c, 0x50, 0xf9, 0x3a, 0x3c, 0xca, 0x15, 0xb5, 0x57, 0x42, 0x12,
+ 0xba, 0x63, 0xeb, 0x31, 0x89, 0xe4, 0xa7, 0x8e, 0xc5, 0xb8, 0x31, 0x59,
+ 0xa3, 0xda, 0x51, 0xf8, 0x69, 0x2a, 0x9e, 0x88, 0xfc, 0xf8, 0xf2, 0x6f,
+ 0xe9, 0xb8, 0xe3, 0x06, 0xe7, 0x44, 0x6e, 0xe8, 0xcb, 0x45, 0x69, 0x83,
+ 0xd3, 0xec, 0xd3, 0x67, 0x8e, 0xb8, 0x31, 0x49, 0x24, 0x37, 0x21, 0x62,
+ 0x39, 0xfb, 0x28, 0xbe, 0x30, 0x42, 0x0f, 0x64, 0xa1, 0xc3, 0x68, 0x3d,
+ 0x6e, 0xe3, 0x57, 0x72, 0x20, 0xe3, 0x23, 0x94, 0x28, 0x82, 0x46, 0x3e,
+ 0xc6, 0x4a, 0xcc, 0x7b, 0x39, 0xac, 0xef, 0xf3, 0xf7, 0x02, 0x7e, 0x1b,
+ 0xe6, 0x0f, 0x54, 0xbc, 0xbc, 0x97, 0x26, 0x16, 0xc8, 0x49, 0x45, 0xef,
+ 0x15, 0x7b, 0x79, 0xa7, 0xa2, 0x43, 0x2a, 0xb6, 0x13, 0xe6, 0xf3, 0x88,
+ 0x97, 0x59, 0x74, 0x7f, 0x36, 0xe2, 0xa4, 0x48, 0xc6, 0x2c, 0x88, 0xfb,
+ 0x60, 0xb0, 0xed, 0xdd, 0xcd, 0x3a, 0xe4, 0x94, 0x88, 0x5b, 0x30, 0x52,
+ 0x99, 0x47, 0x7b, 0xc4, 0x1c, 0xba, 0x08, 0x7e, 0x5a, 0x2a, 0xf7, 0xaa,
+ 0x6a, 0x5b, 0x22, 0x93, 0x79, 0xc1, 0xfc, 0x6d, 0xdb, 0x89, 0x1a, 0x95,
+ 0xfb, 0x11, 0xf3, 0x38, 0x25, 0x70, 0x64, 0x1f, 0xfb, 0x3c, 0xa2, 0x5d,
+ 0x69, 0x46, 0xc4, 0x2f, 0xf8, 0xb8, 0xf0, 0xc8, 0x7e, 0xa9, 0xdb, 0xe4,
+ 0x79, 0x19, 0xd7, 0xe0, 0x67, 0x16, 0xb8, 0x1f, 0x55, 0xf9, 0xf4, 0xbd,
+ 0x14, 0xdb, 0x46, 0x9c, 0x69, 0xea, 0x8e, 0xc6, 0x99, 0x98, 0xd6, 0xc5,
+ 0xcd, 0x6a, 0x1a, 0xb4, 0xff, 0xf7, 0x91, 0xb6, 0xe1, 0x4c, 0x2b, 0x53,
+ 0xfc, 0x16, 0x08, 0x30, 0x78, 0xa6, 0xf8, 0x3c, 0x7e, 0x03, 0xc7, 0x97,
+ 0x14, 0xd8, 0x38, 0xcc, 0xd8, 0x06, 0x18, 0x67, 0x40, 0xac, 0x8b, 0xc5,
+ 0x1e, 0x0a, 0xfb, 0x32, 0x2b, 0x3d, 0xe4, 0x47, 0x3c, 0xce, 0xd6, 0xb9,
+ 0x1c, 0xad, 0x22, 0xef, 0x5d, 0xae, 0x47, 0xc2, 0x3e, 0x43, 0x27, 0xae,
+ 0xb3, 0xdf, 0xf0, 0x90, 0xca, 0xb9, 0x41, 0xcd, 0xa6, 0xce, 0xb9, 0xd1,
+ 0x3a, 0x45, 0xf3, 0x9e, 0x5e, 0xeb, 0x70, 0xff, 0xde, 0x18, 0x64, 0xd7,
+ 0x8d, 0x29, 0x10, 0x9f, 0x12, 0x73, 0x74, 0x81, 0x48, 0xce, 0x71, 0x65,
+ 0x1d, 0xa3, 0x85, 0xe7, 0x09, 0xfe, 0x20, 0xe2, 0x7e, 0x8f, 0xf0, 0x27,
+ 0xd6, 0x23, 0x7e, 0xb4, 0x1f, 0x38, 0xaa, 0xd3, 0x66, 0x9e, 0x19, 0xc5,
+ 0x71, 0x0f, 0xfb, 0x67, 0x1a, 0xf7, 0xca, 0x58, 0x14, 0xfb, 0x6c, 0x6a,
+ 0xbe, 0x10, 0x87, 0xea, 0x97, 0x39, 0x4c, 0xd9, 0x08, 0x59, 0x5d, 0xa0,
+ 0xd3, 0xaf, 0x4a, 0x1e, 0x37, 0x5b, 0xbb, 0xd8, 0x4a, 0x5e, 0x13, 0x7e,
+ 0x0b, 0x0d, 0xfb, 0x8d, 0x1e, 0x04, 0xed, 0x79, 0x8e, 0xdc, 0x6b, 0x1b,
+ 0xcf, 0xef, 0xd5, 0xbf, 0xc3, 0x74, 0x67, 0xe6, 0x6d, 0x87, 0xc7, 0xbc,
+ 0x1d, 0xec, 0x95, 0x6b, 0x67, 0x7f, 0xa1, 0xda, 0x78, 0xe5, 0xb8, 0x3a,
+ 0x4f, 0x22, 0x0e, 0x55, 0xa9, 0xbf, 0x78, 0x5b, 0xe8, 0x95, 0xfa, 0x58,
+ 0x78, 0x98, 0xf5, 0xa9, 0x94, 0xe3, 0x53, 0x1e, 0x72, 0xdc, 0x35, 0x0e,
+ 0xdc, 0xf2, 0xc9, 0xe5, 0x78, 0xb2, 0xa1, 0x1c, 0x4f, 0xf6, 0xca, 0x58,
+ 0x6c, 0xbd, 0x1c, 0xbf, 0x81, 0xbe, 0x14, 0x37, 0xca, 0x81, 0x44, 0x4d,
+ 0xbb, 0x3b, 0x56, 0x02, 0x9a, 0xe9, 0x78, 0x09, 0xd6, 0x0d, 0xc1, 0x97,
+ 0x58, 0x7b, 0x99, 0x32, 0x12, 0xf3, 0xb5, 0x6b, 0xa9, 0x5b, 0xb9, 0x17,
+ 0xeb, 0x34, 0xb5, 0xf7, 0x02, 0xbb, 0x43, 0x36, 0x22, 0x61, 0x19, 0x0b,
+ 0xd0, 0xf4, 0xeb, 0xf5, 0x1d, 0xcb, 0x47, 0x9c, 0x02, 0x21, 0xd6, 0x1d,
+ 0xa2, 0x73, 0x58, 0x9f, 0x56, 0xb1, 0xe4, 0x93, 0x59, 0x49, 0x07, 0xf3,
+ 0x88, 0xe0, 0x0f, 0xe0, 0xdb, 0x70, 0xd2, 0x9f, 0xe4, 0x39, 0x96, 0x71,
+ 0xe4, 0xd4, 0x72, 0x58, 0xcd, 0x1b, 0xb7, 0xc5, 0xf3, 0xaa, 0xf6, 0x92,
+ 0xd7, 0x71, 0x07, 0xcc, 0x57, 0xe4, 0xeb, 0x95, 0xdc, 0x64, 0xd8, 0x86,
+ 0x12, 0xfd, 0x37, 0xdb, 0x3d, 0xff, 0x11, 0x53, 0xec, 0xe3, 0xf0, 0x46,
+ 0xf1, 0x08, 0xe3, 0x4d, 0xcc, 0x29, 0x62, 0x90, 0x3a, 0x46, 0xfc, 0xc4,
+ 0x41, 0x6a, 0x3f, 0xcc, 0x28, 0xc0, 0x20, 0x9b, 0xf1, 0xa5, 0x71, 0x04,
+ 0xb9, 0xe6, 0x16, 0xdf, 0x83, 0xfd, 0xa8, 0x06, 0xad, 0x04, 0xb5, 0x21,
+ 0x0e, 0x81, 0xfd, 0xb0, 0xad, 0x74, 0x95, 0x8c, 0x9d, 0x16, 0x32, 0x96,
+ 0x58, 0x39, 0xad, 0x64, 0xec, 0xb4, 0x8a, 0xc3, 0x9f, 0x56, 0x32, 0x76,
+ 0x5a, 0xc9, 0xd8, 0x69, 0x25, 0x63, 0xa7, 0x99, 0xcf, 0x07, 0x18, 0xdf,
+ 0x02, 0x8b, 0xe8, 0x38, 0x68, 0x3b, 0xa5, 0xf2, 0x38, 0x0f, 0xfb, 0x5c,
+ 0x2b, 0x67, 0xef, 0xf6, 0x49, 0x39, 0x63, 0x6c, 0x22, 0xeb, 0xc9, 0xf8,
+ 0x5d, 0x98, 0x83, 0x57, 0x98, 0xe6, 0x1f, 0xd3, 0x99, 0x79, 0xf4, 0xd5,
+ 0x47, 0x13, 0x62, 0x1f, 0xdc, 0x26, 0x8a, 0xbb, 0xb1, 0xb0, 0xc9, 0x63,
+ 0xcd, 0x4a, 0xdf, 0xcf, 0x31, 0x6c, 0xc1, 0x27, 0xde, 0x7a, 0x15, 0x7c,
+ 0x32, 0xae, 0xe6, 0xab, 0xd6, 0x2f, 0x6a, 0xa1, 0x64, 0x0e, 0x74, 0x45,
+ 0xfe, 0xa4, 0xc5, 0x73, 0x23, 0xe8, 0xe4, 0x98, 0x1e, 0x34, 0x38, 0xa9,
+ 0x68, 0xf0, 0xb8, 0x18, 0x23, 0xf2, 0x0f, 0x11, 0xcb, 0x6c, 0x4c, 0x87,
+ 0x74, 0x76, 0x80, 0x9f, 0xc3, 0xb2, 0x70, 0x24, 0xcc, 0x3a, 0x69, 0xeb,
+ 0x74, 0xa8, 0x8c, 0xbd, 0x91, 0xee, 0xd9, 0x6a, 0x5d, 0xce, 0xba, 0xcb,
+ 0x96, 0x84, 0x95, 0x1d, 0x91, 0xb8, 0x78, 0x87, 0x5d, 0xa2, 0x13, 0xd1,
+ 0x83, 0xfc, 0x3d, 0x92, 0x74, 0xe8, 0x30, 0x19, 0x9d, 0x25, 0xfa, 0x11,
+ 0xcb, 0x41, 0x2b, 0xcb, 0xc1, 0x09, 0xe5, 0x97, 0x9c, 0x28, 0xfb, 0x25,
+ 0x93, 0x07, 0x90, 0x97, 0x91, 0x12, 0xeb, 0x5e, 0x3b, 0xcb, 0xbf, 0xc3,
+ 0x02, 0x3d, 0xb6, 0x88, 0xfd, 0x28, 0x7a, 0x71, 0x6c, 0xd2, 0x55, 0xf6,
+ 0xab, 0x63, 0xbe, 0x07, 0x0f, 0x08, 0xec, 0xee, 0x7b, 0x00, 0xf7, 0x9c,
+ 0x90, 0x7a, 0xcf, 0x47, 0xfe, 0xc1, 0x77, 0x18, 0x4f, 0x94, 0xe8, 0x31,
+ 0x7e, 0x67, 0x26, 0x77, 0x88, 0x9f, 0xad, 0xf7, 0x96, 0xb0, 0x63, 0x86,
+ 0x6f, 0x27, 0xf9, 0x3b, 0x1b, 0xbd, 0x3b, 0x22, 0xf8, 0x91, 0xf1, 0xb4,
+ 0x31, 0x13, 0x7d, 0xaf, 0x34, 0x3d, 0x85, 0x18, 0x3b, 0xe4, 0x24, 0x62,
+ 0x5a, 0x3e, 0x2f, 0xf9, 0x90, 0x58, 0xa9, 0x92, 0x0b, 0x2b, 0xf3, 0xc2,
+ 0xff, 0x8b, 0xc7, 0x66, 0x12, 0xd6, 0x4e, 0xe4, 0xf3, 0x93, 0x04, 0x9f,
+ 0x00, 0xfb, 0x53, 0x58, 0x4c, 0x67, 0xfd, 0x2e, 0x5b, 0xf1, 0xc6, 0x67,
+ 0x90, 0xe7, 0x96, 0x5b, 0xa4, 0x8d, 0x6d, 0x0e, 0xe2, 0x75, 0x03, 0x0b,
+ 0x6b, 0x9d, 0x21, 0x51, 0x1b, 0xde, 0xc1, 0x18, 0x49, 0xe7, 0x3e, 0x0f,
+ 0xf2, 0xf3, 0x11, 0xc7, 0x0b, 0xd0, 0xc4, 0x25, 0xb4, 0x6b, 0xa6, 0xfe,
+ 0x85, 0xd2, 0xef, 0xf1, 0x75, 0xb1, 0x7e, 0x99, 0xa2, 0x56, 0xb5, 0x36,
+ 0xa1, 0xf7, 0xad, 0x08, 0xb3, 0xec, 0x55, 0x6a, 0x9f, 0xfb, 0xcb, 0x31,
+ 0x3d, 0x21, 0x13, 0x35, 0x31, 0xbd, 0xaf, 0x6e, 0x62, 0xaf, 0x36, 0x93,
+ 0x03, 0xe4, 0xd4, 0xb5, 0x90, 0x8a, 0x55, 0x5a, 0x19, 0xda, 0x6a, 0x4d,
+ 0xdf, 0x76, 0xef, 0xf1, 0xb5, 0x36, 0x8f, 0x93, 0xf3, 0xa6, 0x1d, 0x54,
+ 0xfc, 0xd7, 0x4c, 0x67, 0xf2, 0x41, 0xb6, 0xf9, 0xd0, 0xad, 0xa0, 0x97,
+ 0xbf, 0x17, 0xb5, 0x2e, 0x5f, 0x0a, 0x34, 0xd3, 0xf2, 0x32, 0x72, 0x2d,
+ 0xfe, 0xf1, 0x80, 0xcc, 0x25, 0x4e, 0x32, 0x5d, 0x0e, 0xb3, 0x7d, 0x34,
+ 0xd4, 0xda, 0x11, 0xce, 0x41, 0x97, 0x88, 0xdf, 0x21, 0x0a, 0xdc, 0x3b,
+ 0x14, 0x64, 0xbf, 0x40, 0xae, 0x3d, 0x1c, 0xe5, 0x67, 0x7f, 0x33, 0x9f,
+ 0x44, 0xbc, 0xcc, 0x3c, 0xce, 0xcf, 0x9f, 0x60, 0x3c, 0x11, 0xa3, 0x66,
+ 0x5a, 0x5a, 0x6e, 0x66, 0xbf, 0xa0, 0x99, 0xf1, 0xc4, 0x80, 0xd9, 0xef,
+ 0x13, 0xef, 0x12, 0x75, 0x35, 0x9f, 0x0f, 0x1c, 0x66, 0xbe, 0xc2, 0xbb,
+ 0xfe, 0x5d, 0xbd, 0xab, 0xf6, 0x1d, 0xff, 0x51, 0xc2, 0xf1, 0x71, 0x3f,
+ 0x39, 0x37, 0xf0, 0x1b, 0x5c, 0xf3, 0x63, 0x8c, 0x9d, 0x43, 0x94, 0x99,
+ 0x6f, 0xe2, 0x31, 0x8c, 0xb3, 0x1f, 0x11, 0xe5, 0xe3, 0xfb, 0xc8, 0x29,
+ 0x4e, 0xd1, 0x5f, 0x15, 0xdd, 0x31, 0xe1, 0xfb, 0xb8, 0xcf, 0xb2, 0xb6,
+ 0xbf, 0x85, 0xfb, 0xf5, 0x91, 0x5d, 0xab, 0x63, 0x82, 0xe4, 0xff, 0xeb,
+ 0x10, 0x35, 0x7f, 0x0d, 0xb1, 0x97, 0x12, 0xe5, 0xa2, 0xa8, 0x57, 0x90,
+ 0xf1, 0xe7, 0xab, 0x22, 0x87, 0x96, 0xef, 0xe7, 0x67, 0xce, 0xa1, 0xdd,
+ 0x55, 0x8b, 0xae, 0xdb, 0x92, 0xde, 0x3f, 0x08, 0x84, 0xc8, 0xff, 0x12,
+ 0x72, 0x9f, 0xc4, 0xfe, 0x1a, 0x8e, 0x7d, 0x88, 0xf5, 0xfb, 0xd7, 0x70,
+ 0x1f, 0x7f, 0xbe, 0x84, 0xe3, 0x20, 0x8f, 0x13, 0xf6, 0x1a, 0xf9, 0x2e,
+ 0xd0, 0x8b, 0x87, 0xc3, 0xa6, 0xe0, 0xbf, 0xfb, 0x98, 0xa7, 0x9a, 0x44,
+ 0xac, 0xb1, 0x0b, 0x6d, 0xed, 0xfd, 0xc0, 0x16, 0xce, 0xd0, 0x21, 0x1c,
+ 0xc7, 0x3a, 0xfd, 0x4c, 0x23, 0xc9, 0x43, 0x18, 0x4f, 0x15, 0x73, 0x07,
+ 0x8e, 0x0e, 0x11, 0xcf, 0x27, 0xf0, 0xc7, 0x2f, 0xf1, 0x1b, 0x91, 0x4e,
+ 0x3f, 0xbf, 0x23, 0xc1, 0xef, 0x98, 0xc8, 0xcb, 0x71, 0xcf, 0x15, 0xfd,
+ 0x24, 0xe3, 0x54, 0x5f, 0xe9, 0xd3, 0xbf, 0xd1, 0x48, 0x3d, 0x78, 0x76,
+ 0x59, 0x56, 0xf8, 0x7b, 0x3b, 0xdd, 0xca, 0xb7, 0xd1, 0x6d, 0xb5, 0xa6,
+ 0x75, 0x4b, 0xf8, 0x65, 0xac, 0xc3, 0x93, 0xed, 0xb4, 0xbe, 0xdc, 0x44,
+ 0xd4, 0x15, 0x14, 0x6b, 0xce, 0xb7, 0xf2, 0x05, 0x7e, 0xff, 0x97, 0xfb,
+ 0x64, 0x5c, 0xa7, 0xc2, 0x23, 0xb7, 0x3c, 0x78, 0xe4, 0x03, 0xc1, 0x23,
+ 0x5f, 0xec, 0xdb, 0x98, 0x47, 0x50, 0xf3, 0x0f, 0xde, 0x08, 0x52, 0xb3,
+ 0xe2, 0x8f, 0x17, 0x99, 0x3f, 0x9e, 0x65, 0xfe, 0x38, 0xd6, 0x80, 0x3f,
+ 0x8c, 0x1a, 0xfe, 0x38, 0x2e, 0xf8, 0xe3, 0x89, 0xbe, 0x8d, 0xf8, 0xe3,
+ 0x98, 0x7f, 0xa3, 0x58, 0x93, 0xaf, 0x35, 0xc0, 0xef, 0x9e, 0xb3, 0xf7,
+ 0x31, 0xaf, 0xdb, 0xb4, 0x34, 0x8f, 0xfa, 0x84, 0xd5, 0xa8, 0x41, 0x3f,
+ 0x13, 0x3e, 0xd9, 0x9a, 0xf0, 0xf9, 0xc7, 0x45, 0xcd, 0xc1, 0xa2, 0xe0,
+ 0x2f, 0xb6, 0xff, 0xe3, 0xa8, 0xab, 0xaa, 0x9d, 0x8b, 0x56, 0xba, 0x1e,
+ 0xc5, 0x5c, 0x58, 0x7a, 0x2e, 0x08, 0xeb, 0xbb, 0x6a, 0xef, 0xc8, 0x40,
+ 0x3c, 0x4b, 0xce, 0x07, 0xe0, 0xd1, 0x95, 0xb6, 0xc0, 0x44, 0xf6, 0x1b,
+ 0x7d, 0xc0, 0x7f, 0x99, 0x15, 0x72, 0x9d, 0x0f, 0xf0, 0xf9, 0x90, 0xf8,
+ 0x6d, 0x2b, 0xc8, 0xca, 0x87, 0xc8, 0x71, 0x64, 0x9e, 0xbc, 0x9e, 0xef,
+ 0xa5, 0x1b, 0xf9, 0x7d, 0xb4, 0x96, 0xef, 0xa3, 0x37, 0xc5, 0xbe, 0x1a,
+ 0xb2, 0x36, 0x72, 0x4d, 0xcc, 0x91, 0x41, 0x47, 0x43, 0xdc, 0x66, 0x79,
+ 0x1f, 0xad, 0x2e, 0x6b, 0xfe, 0x06, 0x6f, 0x83, 0x5f, 0x62, 0x9d, 0xb2,
+ 0x66, 0xae, 0x9e, 0x67, 0x26, 0xaa, 0x79, 0x46, 0xdc, 0x03, 0x5e, 0xc9,
+ 0xd4, 0xd5, 0xfa, 0x22, 0x5f, 0x11, 0xb9, 0x7a, 0x41, 0x6a, 0x42, 0xde,
+ 0xa2, 0x11, 0x19, 0x3e, 0xea, 0x07, 0x86, 0xce, 0xb1, 0xcd, 0xe5, 0x39,
+ 0xb3, 0x91, 0xe7, 0xd4, 0xc7, 0x78, 0xb8, 0x43, 0xe0, 0xdf, 0xb8, 0x1d,
+ 0x08, 0x4f, 0x50, 0xe9, 0x69, 0xc3, 0xc6, 0x5e, 0x8f, 0x49, 0x7e, 0x9e,
+ 0xa1, 0xe2, 0x4d, 0xbb, 0x5c, 0xfc, 0x57, 0x8b, 0x75, 0xb1, 0x96, 0xfc,
+ 0x10, 0xf7, 0x19, 0x76, 0xb8, 0xb2, 0x5e, 0x43, 0xe5, 0xf5, 0x9a, 0x56,
+ 0x1e, 0xb7, 0x94, 0xbd, 0x19, 0x9b, 0xdb, 0x15, 0xff, 0x6f, 0x40, 0x75,
+ 0xeb, 0x41, 0x73, 0x7f, 0x40, 0xf1, 0x25, 0xa0, 0x79, 0x67, 0x19, 0x86,
+ 0x43, 0x3d, 0xa0, 0x3c, 0x0a, 0x1a, 0x0f, 0x41, 0xcc, 0xf5, 0x1e, 0x5a,
+ 0x03, 0x12, 0x07, 0x8d, 0x89, 0x20, 0xe6, 0x7a, 0x0f, 0x41, 0xe7, 0x7a,
+ 0x0f, 0xad, 0xb1, 0x01, 0x97, 0xdb, 0xcd, 0x53, 0x80, 0xe1, 0x3e, 0x85,
+ 0x19, 0xba, 0xce, 0x51, 0x0d, 0x7a, 0x77, 0x52, 0x0c, 0x78, 0x4c, 0x5b,
+ 0x50, 0x05, 0x7f, 0x18, 0xba, 0x62, 0x84, 0xa1, 0x0d, 0xb8, 0x9d, 0xe5,
+ 0x02, 0x34, 0xd3, 0x79, 0x4a, 0x0c, 0x30, 0x3c, 0x23, 0x80, 0x79, 0x4f,
+ 0x18, 0x9a, 0xf7, 0x60, 0x73, 0xc7, 0xfc, 0x0c, 0x90, 0x7b, 0x98, 0x6c,
+ 0xc0, 0x7d, 0x0b, 0x48, 0x79, 0x25, 0x83, 0x56, 0x5e, 0x01, 0xd3, 0x84,
+ 0x3a, 0x44, 0x7f, 0xd3, 0x7a, 0x0d, 0x79, 0xd8, 0x38, 0x60, 0x13, 0xd0,
+ 0xdc, 0xe6, 0x29, 0xa4, 0xcc, 0x3d, 0x03, 0xeb, 0x5b, 0xac, 0x6b, 0x1b,
+ 0x6d, 0xc0, 0x7b, 0xac, 0x17, 0x4d, 0x61, 0x61, 0x58, 0xd2, 0xc3, 0x00,
+ 0xac, 0x1f, 0x40, 0x69, 0x1d, 0x54, 0x47, 0xc0, 0xd3, 0xbb, 0x40, 0x13,
+ 0xd0, 0x7d, 0x4e, 0xc0, 0xb6, 0xa8, 0x73, 0xbf, 0x32, 0x78, 0xad, 0x6c,
+ 0x03, 0xf4, 0xfc, 0xaa, 0x45, 0x3d, 0xde, 0xf2, 0xa0, 0x7c, 0xe6, 0xa4,
+ 0xc2, 0x40, 0x46, 0x5e, 0x60, 0x83, 0xe6, 0x05, 0x70, 0x38, 0x01, 0xd3,
+ 0x3a, 0xb0, 0x8c, 0x5a, 0x93, 0x04, 0x34, 0x8f, 0x87, 0xc5, 0xa5, 0x1f,
+ 0x24, 0xc6, 0x00, 0x15, 0x63, 0x01, 0xf2, 0x65, 0x80, 0x6d, 0x4a, 0x90,
+ 0x5f, 0x41, 0x79, 0x01, 0x64, 0x36, 0xc8, 0xef, 0xa0, 0xb2, 0x13, 0x94,
+ 0x17, 0x81, 0xec, 0x25, 0x42, 0x50, 0x3f, 0x03, 0x69, 0x20, 0xbb, 0x79,
+ 0x8a, 0x08, 0x98, 0x9f, 0x14, 0x20, 0xc4, 0xd0, 0x00, 0xcf, 0x07, 0xc4,
+ 0x86, 0x31, 0x4c, 0x7d, 0x0c, 0x19, 0xf9, 0x06, 0x62, 0x06, 0x22, 0xdf,
+ 0xb0, 0x33, 0x1c, 0x10, 0x80, 0x85, 0xd5, 0xff, 0xff, 0xc7, 0x54, 0x58,
+ 0x80, 0xe9, 0x14, 0xb4, 0x8e, 0xf5, 0xf7, 0xff, 0x03, 0x22, 0x2c, 0x0c,
+ 0x2d, 0xf0, 0xf5, 0x88, 0x0b, 0xe5, 0x41, 0x65, 0xe8, 0x02, 0x20, 0xab,
+ 0x0d, 0xde, 0x26, 0x60, 0x01, 0xdf, 0x61, 0xbd, 0x80, 0xe1, 0x17, 0xb0,
+ 0xcc, 0xfa, 0xff, 0x7f, 0x29, 0x5c, 0x2d, 0x08, 0x00, 0x00, 0xff, 0x88,
+ 0x78, 0xb5, 0x98, 0x7e, 0x00, 0x00, 0x00 };
static const u32 bnx2_COM_b09FwData[(0x0/4) + 1] = { 0x0 };
static const u32 bnx2_COM_b09FwRodata[(0x88/4) + 1] = {
- 0x08001b68, 0x08001ba4, 0x08001ba4, 0x08001ba4, 0x08001ba4, 0x08001ba4,
- 0x08001ab4, 0x08001ba4, 0x08001b28, 0x08001ba4, 0x08001a3c, 0x08001ba4,
- 0x08001ba4, 0x08001ba4, 0x08001a48, 0x00000000, 0x08002abc, 0x08002b0c,
- 0x08002b3c, 0x08002b6c, 0x08002b9c, 0x00000000, 0x0800604c, 0x0800604c,
- 0x0800604c, 0x0800604c, 0x0800604c, 0x08006078, 0x08006078, 0x080060b8,
- 0x080060c4, 0x080060c4, 0x0800604c, 0x00000000, 0x00000000 };
-static const u32 bnx2_COM_b09FwBss[(0x88/4) + 1] = { 0x0 };
-static const u32 bnx2_COM_b09FwSbss[(0x60/4) + 1] = { 0x0 };
+ 0x08001b7c, 0x08001bb8, 0x08001bb8, 0x08001bb8, 0x08001bb8, 0x08001bb8,
+ 0x08001ac8, 0x08001bb8, 0x08001b3c, 0x08001bb8, 0x08001a50, 0x08001bb8,
+ 0x08001bb8, 0x08001bb8, 0x08001a5c, 0x00000000, 0x08002b74, 0x08002bc4,
+ 0x08002bf4, 0x08002c24, 0x08002c58, 0x00000000, 0x08006120, 0x08006120,
+ 0x08006120, 0x08006120, 0x08006120, 0x0800614c, 0x0800614c, 0x0800618c,
+ 0x08006198, 0x08006198, 0x08006120, 0x00000000, 0x00000000 };
static struct fw_info bnx2_com_fw_09 = {
+ /* Firmware version: 3.7.1 */
.ver_major = 0x3,
- .ver_minor = 0x4,
- .ver_fix = 0x3,
+ .ver_minor = 0x7,
+ .ver_fix = 0x1,
.start_addr = 0x080000b4,
.text_addr = 0x08000000,
- .text_len = 0x7dc0,
+ .text_len = 0x7e94,
.text_index = 0x0,
.gz_text = bnx2_COM_b09FwText,
.gz_text_len = sizeof(bnx2_COM_b09FwText),
- .data_addr = 0x08007e60,
+ .data_addr = 0x08007f40,
.data_len = 0x0,
.data_index = 0x0,
.data = bnx2_COM_b09FwData,
- .sbss_addr = 0x08007e60,
+ .sbss_addr = 0x08007f40,
.sbss_len = 0x60,
.sbss_index = 0x0,
- .sbss = bnx2_COM_b09FwSbss,
- .bss_addr = 0x08007ec0,
+ .bss_addr = 0x08007fa0,
.bss_len = 0x88,
.bss_index = 0x0,
- .bss = bnx2_COM_b09FwBss,
- .rodata_addr = 0x08007dc0,
+ .rodata_addr = 0x08007e98,
.rodata_len = 0x88,
.rodata_index = 0x0,
.rodata = bnx2_COM_b09FwRodata,
};
static u8 bnx2_CP_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x00, 0x0f, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xbd, 0x7d,
- 0x0d, 0x74, 0x5c, 0x57, 0x7d, 0xe7, 0xff, 0xdd, 0x19, 0x49, 0x63, 0x59,
- 0x96, 0x9f, 0xe5, 0x89, 0x32, 0x51, 0x84, 0x3d, 0x23, 0x3d, 0xd9, 0x22,
- 0x12, 0xe1, 0xc5, 0x11, 0xac, 0xda, 0x2a, 0xe9, 0x30, 0x92, 0x3f, 0x12,
- 0x02, 0xab, 0x10, 0x43, 0xb3, 0x1c, 0x4a, 0xc5, 0x48, 0x4e, 0x02, 0x04,
- 0xea, 0x40, 0xe8, 0x86, 0xdd, 0xec, 0x66, 0x32, 0x92, 0x3f, 0x9a, 0x8e,
- 0x3d, 0x93, 0x44, 0x89, 0xbd, 0xdd, 0x9c, 0xad, 0x90, 0x14, 0x3b, 0x74,
- 0x07, 0x4f, 0xe2, 0x98, 0x96, 0x73, 0x0a, 0x8d, 0x50, 0x8c, 0x9b, 0xe6,
- 0xb0, 0xdd, 0xd0, 0xa6, 0x34, 0xdb, 0x86, 0x22, 0x8c, 0x81, 0xf4, 0x2c,
- 0xdd, 0x86, 0x42, 0x77, 0xd3, 0x36, 0xe5, 0xed, 0xef, 0x77, 0xef, 0x7d,
- 0x9a, 0x91, 0x34, 0xce, 0x07, 0xdd, 0xad, 0xcf, 0x79, 0x7e, 0xf3, 0xee,
- 0xbb, 0x1f, 0xff, 0xfb, 0xbf, 0xff, 0xef, 0xfb, 0xbf, 0x4f, 0x97, 0x8b,
- 0x34, 0x8b, 0xfd, 0xb7, 0x01, 0xd7, 0xd5, 0xc9, 0xfd, 0xe3, 0x57, 0x5f,
- 0x39, 0x70, 0x25, 0x9f, 0xa3, 0x91, 0x68, 0x44, 0xde, 0xc4, 0xbf, 0xe4,
- 0x1b, 0xa8, 0x83, 0x0e, 0xdd, 0x70, 0x2c, 0x5e, 0x12, 0x53, 0x43, 0xde,
- 0xfe, 0x8c, 0x27, 0xb1, 0xc8, 0x50, 0xee, 0xce, 0x71, 0x4f, 0x24, 0x5d,
- 0xee, 0x4b, 0x0e, 0xcb, 0x3f, 0x05, 0xb9, 0x78, 0x54, 0x58, 0xfe, 0x96,
- 0xa1, 0x57, 0x7f, 0xeb, 0x2b, 0xff, 0x2a, 0xf5, 0xf2, 0x4c, 0x44, 0x62,
- 0xee, 0xd0, 0xed, 0xe2, 0x6e, 0x93, 0x58, 0xe7, 0x50, 0x72, 0xff, 0x23,
- 0xdb, 0x97, 0x44, 0x5a, 0xc3, 0xbe, 0x5e, 0x0a, 0xbe, 0xb2, 0x5d, 0x72,
- 0x1d, 0x43, 0x89, 0xb1, 0x86, 0x21, 0x57, 0x9e, 0xaa, 0xc8, 0xe8, 0x89,
- 0xc2, 0xcb, 0x41, 0x74, 0x28, 0x88, 0x4c, 0x0d, 0x38, 0x12, 0x19, 0x92,
- 0xb3, 0xe3, 0x03, 0xf7, 0x04, 0xca, 0xf3, 0xfc, 0x45, 0x69, 0x19, 0x3c,
- 0x37, 0x80, 0xf7, 0x65, 0x41, 0xdd, 0xbd, 0xd7, 0x9c, 0x28, 0xc4, 0x44,
- 0x0d, 0xf5, 0xbc, 0x90, 0x89, 0x5c, 0x25, 0x7c, 0x7f, 0x56, 0x7a, 0xfc,
- 0xa7, 0x05, 0xe5, 0xe5, 0x98, 0x64, 0x2a, 0xd2, 0x82, 0x32, 0xdc, 0x9b,
- 0x51, 0x27, 0xe5, 0x66, 0x22, 0xae, 0xe4, 0x2b, 0x3f, 0x5e, 0x67, 0xc6,
- 0x9d, 0xb3, 0xf7, 0xbf, 0x8e, 0x99, 0x3b, 0xc6, 0x2d, 0xc6, 0x64, 0x29,
- 0x92, 0x10, 0xc0, 0x82, 0x79, 0x25, 0x64, 0xb2, 0x98, 0x94, 0x4c, 0x81,
- 0xb0, 0x45, 0x25, 0xeb, 0x12, 0xae, 0x04, 0xda, 0xb7, 0x39, 0xf5, 0xeb,
- 0xb3, 0xee, 0x0b, 0xa8, 0x9b, 0x44, 0xbd, 0x4e, 0x79, 0x12, 0x75, 0x4f,
- 0x57, 0xe2, 0xf2, 0x44, 0xe5, 0x57, 0x25, 0x8d, 0xb6, 0x8f, 0x57, 0x30,
- 0x76, 0xb1, 0x51, 0x86, 0xa7, 0x9b, 0x25, 0x33, 0xdd, 0x9d, 0xc8, 0x4a,
- 0x10, 0x7c, 0xda, 0xff, 0xa8, 0x8c, 0xb5, 0xa1, 0x7e, 0x91, 0xef, 0x12,
- 0x2b, 0xde, 0x65, 0xfd, 0x3e, 0x37, 0xab, 0x1c, 0x49, 0xef, 0x4d, 0x25,
- 0xc6, 0x14, 0x9f, 0x1b, 0x24, 0xd3, 0x8f, 0xe7, 0xd1, 0xa8, 0x44, 0xbc,
- 0x20, 0xb8, 0xc3, 0xbf, 0x0c, 0x70, 0xa4, 0x92, 0x49, 0xc5, 0xb6, 0x6c,
- 0x97, 0xca, 0x25, 0x55, 0x5c, 0x72, 0x95, 0x2b, 0x25, 0xd9, 0x16, 0x04,
- 0xef, 0xf3, 0x3b, 0x51, 0x2e, 0x32, 0x5c, 0x90, 0xfd, 0x58, 0x23, 0xf4,
- 0x29, 0xbe, 0x1a, 0xda, 0x8c, 0x79, 0xf4, 0xb9, 0xc3, 0xd2, 0x28, 0xe9,
- 0xb8, 0xa4, 0xd5, 0x90, 0x24, 0xd5, 0xd0, 0x3a, 0x94, 0x39, 0xd2, 0xe0,
- 0x7d, 0xc1, 0xd2, 0xd2, 0x46, 0x3c, 0xcb, 0xa8, 0x1a, 0x6a, 0x5b, 0x55,
- 0x9e, 0x4a, 0x8a, 0x5a, 0x07, 0x5c, 0xa5, 0x7a, 0xd3, 0x8a, 0x65, 0xb8,
- 0xeb, 0xb2, 0x0f, 0x36, 0xad, 0x2d, 0xdb, 0xef, 0xac, 0x2c, 0xbb, 0xbd,
- 0x85, 0xb0, 0x8a, 0xe2, 0xef, 0xb8, 0x9e, 0x6b, 0x3a, 0xde, 0xed, 0x36,
- 0x60, 0x5e, 0xa3, 0x7e, 0xca, 0xdd, 0xa9, 0x9e, 0x0f, 0xa4, 0x9d, 0x30,
- 0xf3, 0x9d, 0xc2, 0x3b, 0x54, 0x1d, 0xf2, 0xb1, 0x6e, 0xae, 0x1c, 0xc2,
- 0xdc, 0xce, 0x4f, 0xa7, 0xdc, 0x2e, 0x85, 0xfb, 0x3c, 0x7f, 0x07, 0x41,
- 0xc6, 0xcf, 0xe9, 0x35, 0xfd, 0xee, 0x74, 0x02, 0xcf, 0x80, 0x3f, 0x9e,
- 0x4e, 0x6d, 0x92, 0xab, 0xed, 0xba, 0x7c, 0x13, 0x63, 0x76, 0xbb, 0x77,
- 0xa8, 0x6e, 0xd7, 0x57, 0x29, 0x77, 0x56, 0xce, 0xe0, 0x39, 0x08, 0x6e,
- 0xf4, 0x53, 0x89, 0x1c, 0xd6, 0xec, 0x42, 0x21, 0x2e, 0xdf, 0x2b, 0xa4,
- 0x40, 0xc5, 0xa9, 0xde, 0x39, 0xe9, 0xf3, 0xe7, 0x00, 0x6f, 0x1e, 0xd7,
- 0x41, 0xbe, 0x2b, 0xe3, 0x5d, 0x99, 0x6d, 0x83, 0xe0, 0x26, 0xff, 0x37,
- 0x83, 0xb1, 0x76, 0xc3, 0x17, 0x4f, 0x15, 0xb1, 0x9e, 0x80, 0xf9, 0x74,
- 0x11, 0xeb, 0x89, 0xb5, 0x7a, 0x5c, 0xaf, 0x7b, 0x2f, 0xd6, 0x9d, 0xb4,
- 0x41, 0xba, 0xd8, 0x61, 0x69, 0xf9, 0x03, 0xf6, 0x2e, 0x92, 0x29, 0x3a,
- 0x92, 0xf1, 0xff, 0x31, 0x48, 0x6b, 0x7e, 0x11, 0x67, 0xb8, 0x48, 0x5a,
- 0x6c, 0x00, 0xac, 0x7c, 0xcc, 0xda, 0x7a, 0x1b, 0x1d, 0xe0, 0x96, 0xeb,
- 0xc0, 0xf7, 0x31, 0xe5, 0x35, 0xd9, 0xf7, 0x21, 0x5f, 0xf0, 0xdf, 0x26,
- 0x47, 0xbc, 0x6a, 0xbd, 0x0c, 0x69, 0xb2, 0x92, 0x93, 0xec, 0x83, 0x81,
- 0x0c, 0xfb, 0xc0, 0x13, 0xfb, 0x74, 0x7d, 0xd1, 0x6d, 0x5d, 0xd6, 0xd1,
- 0x75, 0xf1, 0x6f, 0x7d, 0x23, 0xc6, 0x70, 0x46, 0x8a, 0xd5, 0xb6, 0x23,
- 0xc5, 0xfc, 0x66, 0x0b, 0x1f, 0x9e, 0x07, 0x9d, 0x4c, 0xe5, 0x82, 0x5d,
- 0xdb, 0x70, 0x1e, 0x57, 0xd7, 0xa1, 0x6d, 0x17, 0x7c, 0xe0, 0x4a, 0xb6,
- 0x30, 0x88, 0x71, 0xe3, 0xb8, 0x07, 0xc1, 0x94, 0x9f, 0x4e, 0x45, 0x65,
- 0x08, 0xcf, 0xa3, 0xe4, 0x3d, 0xe0, 0x4f, 0xa2, 0x99, 0xed, 0xbe, 0x8c,
- 0x80, 0xee, 0xf3, 0x95, 0xd7, 0x97, 0x22, 0x7a, 0x0e, 0xfe, 0x3f, 0x59,
- 0xdc, 0x70, 0x1c, 0x33, 0xe6, 0x54, 0xb1, 0x43, 0xf2, 0xd3, 0x9e, 0x4c,
- 0x16, 0x16, 0x7a, 0x95, 0xbc, 0x4c, 0x7e, 0xc7, 0xfa, 0xa5, 0x40, 0xbb,
- 0x43, 0x32, 0x5c, 0xf1, 0x24, 0x5f, 0xc0, 0xbd, 0xd8, 0x0d, 0xfa, 0x8d,
- 0x4a, 0x3a, 0x61, 0xd6, 0x26, 0x5f, 0x18, 0xc1, 0xfc, 0x80, 0x6b, 0x8f,
- 0xbf, 0x07, 0x2d, 0x4c, 0xae, 0x64, 0x06, 0x48, 0x3f, 0x6f, 0x06, 0x96,
- 0x98, 0xcc, 0xfa, 0xe0, 0x0b, 0xd7, 0xc0, 0x92, 0x2f, 0xc6, 0xa2, 0xc3,
- 0x98, 0xf7, 0x70, 0xf9, 0x57, 0xd0, 0x7f, 0x8b, 0xfe, 0x0d, 0x7e, 0xb2,
- 0x65, 0x51, 0xdc, 0xe3, 0xb8, 0x13, 0xe6, 0x90, 0x56, 0x21, 0x1b, 0xa6,
- 0x3b, 0x65, 0x12, 0xb4, 0x3a, 0x2c, 0xf8, 0x3d, 0xcf, 0xb9, 0x10, 0xae,
- 0x0e, 0xfd, 0x7b, 0x72, 0x7a, 0x8b, 0x7e, 0xce, 0x8e, 0x76, 0x48, 0x6e,
- 0x3e, 0x9c, 0x33, 0xe5, 0x05, 0x65, 0x44, 0xea, 0xb0, 0x08, 0x65, 0x46,
- 0x10, 0x3c, 0xe8, 0x53, 0x6e, 0x04, 0xc1, 0x69, 0x9f, 0x72, 0xe4, 0x0c,
- 0xe4, 0x03, 0x65, 0x07, 0x79, 0xd9, 0x53, 0x5c, 0xab, 0x4c, 0xa1, 0x17,
- 0xeb, 0xd1, 0x28, 0xd9, 0xfe, 0xe3, 0x84, 0x15, 0x72, 0xe7, 0xa5, 0x4f,
- 0x66, 0xbc, 0x5c, 0x22, 0xa2, 0xf1, 0x04, 0xca, 0x82, 0x3c, 0x4c, 0xeb,
- 0x99, 0x75, 0x49, 0xbe, 0xbf, 0x64, 0xeb, 0xc8, 0xaf, 0xb2, 0x4e, 0x74,
- 0x4d, 0x9d, 0x7f, 0xa7, 0x0c, 0x5f, 0xf6, 0x62, 0xdd, 0x3a, 0x14, 0xf1,
- 0xd8, 0xb5, 0x8d, 0xcf, 0x12, 0x6b, 0x18, 0xfa, 0x3d, 0xbc, 0x7b, 0xee,
- 0x53, 0x8f, 0x7a, 0xf5, 0xde, 0xfd, 0x28, 0xba, 0xf6, 0xdd, 0x94, 0x44,
- 0xbd, 0x54, 0xef, 0x8d, 0xea, 0x4f, 0x1a, 0xa4, 0x35, 0x08, 0x1e, 0xf5,
- 0xc3, 0xf2, 0xc6, 0x86, 0xb5, 0x63, 0x5c, 0x55, 0xa7, 0xec, 0x68, 0x9d,
- 0xb2, 0xcf, 0xd7, 0x29, 0x7b, 0x7b, 0xe3, 0xda, 0xb2, 0xdb, 0xeb, 0x94,
- 0xcd, 0xd6, 0x29, 0xfb, 0x69, 0x9d, 0x32, 0x69, 0x5a, 0x5b, 0x16, 0xa9,
- 0x53, 0xd6, 0x57, 0xa7, 0x2c, 0x0a, 0xbe, 0xdb, 0x26, 0xf9, 0xf8, 0xbd,
- 0x9c, 0xbb, 0xc5, 0x4d, 0x29, 0xb2, 0x16, 0x37, 0x0d, 0xa8, 0xd7, 0xb9,
- 0xaa, 0xde, 0x17, 0xeb, 0xd4, 0x6b, 0x44, 0xbd, 0xb6, 0x55, 0xf5, 0x76,
- 0xd4, 0xc1, 0x75, 0x13, 0xea, 0xc5, 0x56, 0xd5, 0x7b, 0xb0, 0x4e, 0x3d,
- 0x96, 0x7f, 0xc6, 0x8e, 0xd3, 0x07, 0x2d, 0xf4, 0x5a, 0xeb, 0xd5, 0x28,
- 0xd2, 0xce, 0xf2, 0x5e, 0xe8, 0x90, 0x0e, 0x65, 0xe4, 0x02, 0x65, 0x10,
- 0xcb, 0x3a, 0x41, 0xe7, 0x71, 0xd0, 0x1d, 0xe5, 0x28, 0xf8, 0x8c, 0x73,
- 0xa9, 0x6c, 0x90, 0xb1, 0x78, 0x9f, 0x7b, 0xb5, 0x6a, 0x01, 0x8d, 0xa5,
- 0xdc, 0xa4, 0x22, 0xff, 0x49, 0x2e, 0x32, 0xe4, 0xe5, 0x86, 0x45, 0xc5,
- 0x95, 0x04, 0x32, 0xe2, 0xab, 0x36, 0x25, 0xf7, 0x80, 0xbf, 0xd2, 0xd0,
- 0x59, 0x37, 0x06, 0xc3, 0x9a, 0xb7, 0x4c, 0xdd, 0x8b, 0xcb, 0x54, 0x5f,
- 0x0e, 0x52, 0x16, 0x0e, 0x8d, 0x7e, 0x2a, 0xe3, 0x2d, 0x0c, 0x36, 0x82,
- 0x66, 0xcf, 0xa3, 0xcd, 0x6e, 0xb4, 0xdc, 0x57, 0x8e, 0xca, 0x48, 0x79,
- 0x00, 0xbc, 0xe0, 0xc8, 0x39, 0x6f, 0xa3, 0x9c, 0xf3, 0x51, 0xb7, 0x12,
- 0x91, 0xc5, 0xb8, 0x23, 0x8b, 0x78, 0xce, 0xf8, 0x78, 0x57, 0x09, 0x79,
- 0x6b, 0x40, 0x0e, 0x14, 0x7d, 0x39, 0x5c, 0xbc, 0x41, 0x85, 0x7a, 0x6d,
- 0xa7, 0xbf, 0x5e, 0x1e, 0x73, 0x4d, 0xdf, 0xbb, 0xbd, 0x05, 0x68, 0xd4,
- 0xa8, 0x9c, 0xf7, 0x52, 0x89, 0x45, 0xcd, 0x13, 0xff, 0x27, 0x18, 0x41,
- 0x3f, 0xb3, 0x5e, 0xca, 0xfd, 0x03, 0x3c, 0x8f, 0x95, 0x69, 0xcb, 0x54,
- 0xfb, 0x9a, 0x44, 0x5f, 0x87, 0x8a, 0x1b, 0xe4, 0x56, 0xdb, 0x7e, 0x97,
- 0xb7, 0xd0, 0x0b, 0x9e, 0x73, 0x4f, 0x50, 0x86, 0x14, 0x00, 0xd7, 0x5e,
- 0xf0, 0x36, 0xda, 0x7e, 0x4d, 0xcb, 0x33, 0xd8, 0x3e, 0x85, 0x8d, 0x90,
- 0xcf, 0x7f, 0x17, 0xdc, 0x1a, 0x67, 0x7d, 0x96, 0x51, 0xe7, 0x48, 0x49,
- 0x0d, 0x41, 0x26, 0x0c, 0x50, 0x66, 0x26, 0x21, 0x2f, 0x21, 0x7b, 0x8a,
- 0x3f, 0x0d, 0xd2, 0xd1, 0x5a, 0x39, 0x28, 0xb9, 0x6a, 0x1d, 0x96, 0x25,
- 0x8d, 0x5c, 0x2d, 0x2e, 0x2d, 0xcb, 0x8a, 0x1c, 0xe4, 0xcb, 0x53, 0x15,
- 0xca, 0x85, 0x0f, 0x82, 0x47, 0x3b, 0x65, 0xa4, 0x90, 0xca, 0xa5, 0x65,
- 0x1b, 0xd6, 0xef, 0xd7, 0xb1, 0xa6, 0x51, 0x5c, 0x0f, 0xad, 0x97, 0x56,
- 0x1f, 0xba, 0x9b, 0xe5, 0xe8, 0xb4, 0x9d, 0x36, 0xd2, 0x6f, 0x03, 0x0f,
- 0x93, 0x5c, 0xf3, 0x44, 0x26, 0xe2, 0x8c, 0xd2, 0x5e, 0x19, 0x85, 0x7c,
- 0xcc, 0x96, 0xd9, 0x37, 0xe1, 0x4d, 0xd8, 0xdf, 0xb0, 0x9b, 0x0a, 0x9d,
- 0xf6, 0x77, 0x0b, 0x7e, 0x27, 0xed, 0x6f, 0xc8, 0xd4, 0x82, 0x67, 0x7f,
- 0xc7, 0xb5, 0x1c, 0x32, 0xbf, 0x13, 0xf8, 0xdd, 0xaf, 0x7f, 0x4f, 0x15,
- 0x77, 0xed, 0x52, 0xde, 0x95, 0x92, 0x9d, 0xef, 0x94, 0x03, 0x85, 0x77,
- 0x58, 0xd9, 0x82, 0x4b, 0xbe, 0xe4, 0x98, 0x79, 0x26, 0xf4, 0xba, 0xe7,
- 0x8b, 0x39, 0x67, 0x94, 0xf0, 0xe3, 0xf7, 0x70, 0xa1, 0xcf, 0xdd, 0x24,
- 0xa4, 0x81, 0x29, 0x67, 0xb8, 0xe2, 0xa4, 0x23, 0x43, 0x3d, 0x89, 0x49,
- 0x39, 0x8c, 0xdf, 0xe2, 0x46, 0x86, 0xbe, 0x84, 0xbb, 0xc1, 0xc1, 0x57,
- 0xb6, 0x43, 0xb6, 0x16, 0x29, 0x2f, 0x3d, 0xcc, 0x3d, 0x29, 0x67, 0x56,
- 0xd8, 0x58, 0xc4, 0x85, 0x92, 0xec, 0x74, 0xea, 0x78, 0x4e, 0x52, 0xb9,
- 0x19, 0x30, 0xc4, 0x8d, 0x7e, 0x54, 0xde, 0xe7, 0x83, 0x76, 0xaf, 0x74,
- 0x64, 0xd7, 0x95, 0x51, 0xd8, 0x44, 0xde, 0xcc, 0x2e, 0xc8, 0x58, 0xc8,
- 0xbe, 0x08, 0xe9, 0x41, 0x9d, 0x92, 0xb1, 0xe8, 0x10, 0xb0, 0x7d, 0xaa,
- 0x7f, 0x64, 0xb2, 0x90, 0xbd, 0x5d, 0x0d, 0xed, 0xff, 0x6c, 0x66, 0xe0,
- 0xad, 0x92, 0xdd, 0xab, 0x80, 0xa3, 0xf6, 0x31, 0xc8, 0x4c, 0xcc, 0x2b,
- 0x08, 0x40, 0xcf, 0x90, 0xe7, 0x37, 0xdd, 0x14, 0x19, 0x6a, 0x90, 0xe1,
- 0xbd, 0xed, 0x68, 0xc3, 0x77, 0xc4, 0xd7, 0x79, 0xe0, 0x33, 0x95, 0x1c,
- 0x11, 0xb9, 0x7b, 0x6a, 0x60, 0xc9, 0x99, 0x2c, 0x7d, 0x10, 0x3c, 0x79,
- 0x15, 0xda, 0x3f, 0x80, 0xf6, 0x2f, 0x3b, 0xf9, 0xe9, 0x57, 0x9c, 0xc9,
- 0xe9, 0xbf, 0x75, 0xa6, 0xa6, 0xb7, 0x6c, 0xd9, 0x39, 0xb8, 0x65, 0xcb,
- 0xf8, 0x60, 0xd4, 0xea, 0x97, 0x2d, 0x5b, 0xa6, 0x06, 0x07, 0x81, 0x83,
- 0x3e, 0x77, 0x44, 0x3c, 0x77, 0x97, 0x80, 0x7f, 0xe2, 0x1c, 0x93, 0xfa,
- 0x27, 0x85, 0xf7, 0x6c, 0xef, 0xe9, 0xf7, 0xc3, 0xd2, 0x97, 0x68, 0x13,
- 0x8e, 0x1f, 0xb1, 0x75, 0xda, 0x01, 0xfb, 0x03, 0x76, 0x7d, 0x0b, 0xaa,
- 0xc1, 0x63, 0x39, 0xe7, 0xc2, 0x72, 0xae, 0xed, 0x8f, 0xac, 0x2d, 0xbb,
- 0x11, 0xe5, 0x7c, 0x26, 0xce, 0x88, 0x17, 0xda, 0x22, 0x0d, 0xda, 0x76,
- 0xcc, 0x16, 0x48, 0x33, 0x51, 0x99, 0x28, 0xb4, 0xa1, 0x0d, 0xe8, 0xe2,
- 0x94, 0xbd, 0x8e, 0x02, 0xb6, 0xbd, 0xe8, 0xeb, 0xe8, 0x21, 0xb4, 0xa3,
- 0xcc, 0x48, 0xf5, 0x8a, 0xfa, 0x04, 0xea, 0xf4, 0xb9, 0x9b, 0x85, 0x36,
- 0xc7, 0x71, 0xc9, 0x16, 0xc9, 0xdf, 0x3d, 0x80, 0x27, 0x26, 0xc9, 0x76,
- 0x3c, 0x57, 0x0e, 0xc0, 0x0e, 0x69, 0xb0, 0x3a, 0x33, 0x94, 0x17, 0xfc,
- 0x77, 0x87, 0x12, 0xef, 0x80, 0x8c, 0xcd, 0x5d, 0x8e, 0x7a, 0x0e, 0xf0,
- 0x42, 0x3b, 0x05, 0x36, 0xcb, 0x5c, 0x5a, 0x32, 0xdb, 0xee, 0xc5, 0xdd,
- 0xc5, 0x73, 0x1e, 0xf7, 0xb7, 0xe0, 0x3e, 0x89, 0x7b, 0x08, 0x27, 0xf0,
- 0xea, 0x47, 0xac, 0xce, 0xba, 0x06, 0x63, 0xff, 0x6b, 0xc9, 0x94, 0x12,
- 0xb4, 0x39, 0x36, 0x66, 0xbc, 0xb4, 0xab, 0x44, 0x6d, 0x56, 0x32, 0x85,
- 0xfa, 0xf0, 0x09, 0xbc, 0x83, 0x32, 0x7e, 0x12, 0xbf, 0x1f, 0xa4, 0x4d,
- 0x3c, 0x25, 0xe3, 0x73, 0x1c, 0xa7, 0x00, 0x98, 0x4a, 0x92, 0x3d, 0xf9,
- 0x00, 0xae, 0x69, 0x5c, 0x0f, 0xe3, 0xe2, 0xdc, 0xd8, 0xff, 0xe2, 0x26,
- 0x05, 0x5c, 0xf3, 0x39, 0x4b, 0x3a, 0xae, 0xe0, 0x37, 0x69, 0xb8, 0x42,
- 0xdb, 0x06, 0xf4, 0x5b, 0x09, 0xe9, 0xda, 0xb7, 0xbf, 0x13, 0x9a, 0xaf,
- 0x73, 0x6d, 0xa0, 0x99, 0xca, 0xa0, 0x96, 0x39, 0x19, 0x0f, 0xf7, 0x0a,
- 0x6c, 0x8f, 0x36, 0xce, 0xd1, 0xb3, 0x65, 0x9e, 0x2e, 0x4b, 0xea, 0xb2,
- 0x7e, 0x5b, 0x86, 0x7b, 0xa5, 0x41, 0xc6, 0xda, 0x01, 0x31, 0xe5, 0xb3,
- 0x84, 0xf8, 0xa4, 0x0c, 0x00, 0xfd, 0xc2, 0x66, 0x38, 0x73, 0x51, 0xf9,
- 0xb7, 0xa4, 0x6d, 0xb1, 0xc7, 0x2b, 0xa4, 0x63, 0xd2, 0x76, 0x10, 0xdc,
- 0xef, 0x37, 0xa1, 0x7f, 0xf2, 0xbc, 0x48, 0xc3, 0xd1, 0xa8, 0xcc, 0xb8,
- 0xa4, 0x85, 0x77, 0xb4, 0x90, 0x06, 0x1a, 0x3d, 0xd2, 0x70, 0x2d, 0x7f,
- 0x71, 0x0d, 0xd9, 0x5f, 0x0e, 0xf6, 0x1d, 0xed, 0xbc, 0x1e, 0xd8, 0xce,
- 0x1c, 0xe3, 0x30, 0x9f, 0x5d, 0x05, 0x9e, 0xca, 0x2c, 0xf3, 0x94, 0xc8,
- 0x6c, 0x81, 0xb8, 0x09, 0xed, 0x3f, 0xae, 0x33, 0xf1, 0xf3, 0x38, 0xe6,
- 0xcc, 0xfb, 0x19, 0x8b, 0xa7, 0x2f, 0x59, 0x3c, 0x7d, 0xd9, 0xde, 0x5d,
- 0x27, 0xab, 0x6d, 0xc1, 0x05, 0x3c, 0x73, 0x7d, 0xa2, 0x1a, 0x67, 0xd9,
- 0xc2, 0x0c, 0xee, 0xa8, 0x5b, 0x7c, 0x5c, 0xc6, 0xb5, 0x9d, 0x16, 0x91,
- 0x77, 0x69, 0xd9, 0x06, 0x21, 0xdd, 0x5c, 0x00, 0xcc, 0x0d, 0x92, 0x8b,
- 0x47, 0xf4, 0xda, 0x47, 0xbd, 0x03, 0x51, 0x43, 0xab, 0xc4, 0xc9, 0x0a,
- 0x5f, 0xaa, 0x06, 0xa6, 0xb8, 0x95, 0x73, 0x84, 0x8b, 0xb4, 0xfb, 0x88,
- 0x86, 0xeb, 0x16, 0xc8, 0xbb, 0x9c, 0xa8, 0xf6, 0x46, 0xb9, 0x0c, 0xb4,
- 0xa0, 0xe2, 0xd0, 0x5c, 0xc1, 0xd3, 0xb0, 0x9b, 0xb2, 0x73, 0xb4, 0xa1,
- 0xbb, 0xe8, 0xb7, 0xc4, 0xb2, 0xfd, 0xad, 0xa4, 0x23, 0xa5, 0x60, 0x7f,
- 0xe1, 0x59, 0x65, 0xfb, 0x35, 0x9d, 0x3a, 0xca, 0x8b, 0x6b, 0x3b, 0x19,
- 0xbc, 0x12, 0xb1, 0xbe, 0x73, 0x54, 0x79, 0x9b, 0x57, 0x97, 0x25, 0xa9,
- 0x87, 0xd1, 0x2e, 0x99, 0xed, 0x6f, 0x27, 0x8f, 0xb9, 0xca, 0x03, 0x2e,
- 0x3d, 0xed, 0x1b, 0xe5, 0xd4, 0xc0, 0xc6, 0x55, 0xf5, 0xf5, 0xdd, 0xb1,
- 0xcf, 0x51, 0x7b, 0x77, 0xed, 0x3d, 0x69, 0xef, 0xb9, 0xe8, 0x00, 0xef,
- 0x8e, 0x44, 0x87, 0x78, 0xc7, 0x1a, 0x0e, 0xb1, 0x0f, 0xcd, 0x57, 0x56,
- 0xce, 0xf4, 0xb8, 0x79, 0x21, 0x5f, 0xfd, 0xa9, 0xdc, 0x32, 0x67, 0xe4,
- 0xef, 0x2e, 0xc8, 0x20, 0xf8, 0x6f, 0xee, 0xa2, 0x00, 0xfe, 0xbd, 0x65,
- 0xb9, 0xa5, 0x42, 0xbc, 0xfd, 0x06, 0xf0, 0xb7, 0x35, 0x4a, 0xde, 0x74,
- 0x85, 0x72, 0xf7, 0x4e, 0xd1, 0xf6, 0x69, 0x81, 0x38, 0x3f, 0x2b, 0x5c,
- 0x9b, 0x7c, 0xe1, 0x19, 0xbd, 0x36, 0x07, 0x0b, 0x8b, 0xc0, 0xcf, 0xd7,
- 0x41, 0xf7, 0x41, 0xb0, 0xe8, 0xe7, 0x41, 0x39, 0x7f, 0x84, 0xdf, 0xe8,
- 0xbb, 0xf0, 0x1c, 0xde, 0xb7, 0x4a, 0xbe, 0x44, 0x9e, 0x8b, 0x5a, 0x1e,
- 0x3e, 0x05, 0x7e, 0xba, 0x0c, 0xfd, 0xa2, 0x6c, 0x80, 0xbf, 0xff, 0x11,
- 0xef, 0x70, 0x9f, 0xc3, 0x22, 0xb6, 0xd3, 0xd6, 0xe1, 0xd8, 0x5c, 0x3b,
- 0xae, 0x59, 0x5c, 0xfb, 0xad, 0x8f, 0x2f, 0xaf, 0x1b, 0xd7, 0x2b, 0xd5,
- 0x9b, 0x93, 0x70, 0xcd, 0x44, 0x1e, 0x2f, 0xb0, 0x3e, 0xe9, 0xff, 0x1f,
- 0x62, 0x46, 0x17, 0xfc, 0xc9, 0x3a, 0x73, 0x5f, 0xdd, 0x96, 0x6b, 0x5e,
- 0x4b, 0x83, 0xf4, 0x6f, 0x52, 0x83, 0x39, 0xc8, 0x9d, 0xa8, 0xd7, 0x2a,
- 0x23, 0xda, 0x27, 0x22, 0x4d, 0x90, 0x06, 0x6e, 0x56, 0x86, 0x36, 0x3f,
- 0xa4, 0x0c, 0x6d, 0x3e, 0x03, 0x5a, 0xc4, 0x55, 0x5c, 0x72, 0x0c, 0x6d,
- 0x7e, 0x1d, 0x77, 0x5c, 0xc5, 0x0b, 0x4e, 0xc8, 0xc7, 0xc3, 0xf0, 0xf9,
- 0x76, 0x15, 0xa2, 0xce, 0x78, 0x05, 0xf4, 0x5b, 0x8c, 0xa1, 0x7c, 0x81,
- 0x38, 0xc7, 0xfc, 0x39, 0xce, 0x56, 0xdb, 0xff, 0xe3, 0x32, 0x51, 0x0c,
- 0xb4, 0x5d, 0x95, 0x9d, 0xbb, 0x17, 0xf7, 0xf5, 0x5a, 0xce, 0x28, 0x2f,
- 0xad, 0x8c, 0xbc, 0x7a, 0x17, 0xee, 0xdd, 0x89, 0x83, 0xd2, 0xed, 0x46,
- 0xe4, 0x39, 0xf4, 0xf5, 0x43, 0x67, 0xa2, 0xf2, 0x32, 0xae, 0x9f, 0xe0,
- 0x7a, 0x15, 0xd7, 0x2b, 0xe8, 0xf7, 0x45, 0x94, 0xaf, 0x97, 0x05, 0xb7,
- 0x19, 0xf5, 0x45, 0x8d, 0x57, 0x5e, 0x70, 0xc6, 0x4e, 0xbe, 0x84, 0x2b,
- 0xaa, 0x26, 0x2a, 0xcf, 0x3b, 0xd9, 0xb9, 0x60, 0xe3, 0xa2, 0x47, 0x19,
- 0xf6, 0xa7, 0x8e, 0xe9, 0x7b, 0x08, 0x73, 0x00, 0x4d, 0x17, 0x17, 0x30,
- 0xf6, 0x33, 0x9a, 0x67, 0x46, 0x20, 0xf3, 0xb3, 0xb0, 0x4b, 0xc6, 0x34,
- 0x4c, 0x97, 0x03, 0x3e, 0xf8, 0xba, 0x03, 0xb8, 0xcf, 0x35, 0xca, 0x52,
- 0x9c, 0x76, 0xe4, 0x97, 0x75, 0xfd, 0x6c, 0xb1, 0x5b, 0xe3, 0x76, 0x66,
- 0x0d, 0xff, 0xd0, 0x3f, 0x0b, 0xe5, 0x81, 0x91, 0xc6, 0xb3, 0x05, 0xca,
- 0x02, 0xe8, 0x9f, 0xc2, 0x14, 0xee, 0x8d, 0x5a, 0x26, 0xe4, 0x25, 0x94,
- 0x07, 0x6c, 0x47, 0x99, 0x50, 0x2b, 0x77, 0x28, 0x6b, 0x28, 0x7b, 0x28,
- 0x4b, 0xcc, 0x7a, 0x8c, 0x3f, 0x48, 0x19, 0x7e, 0x2d, 0xfc, 0x53, 0xda,
- 0x1f, 0x9d, 0xc6, 0x07, 0x99, 0xce, 0x28, 0x23, 0x4f, 0xf7, 0xe8, 0xb5,
- 0x98, 0x28, 0xa8, 0x38, 0x20, 0x47, 0x19, 0xae, 0x63, 0x7b, 0x71, 0xcf,
- 0xaa, 0x09, 0x5c, 0xd9, 0x63, 0x1f, 0xc0, 0x6f, 0xae, 0xcd, 0x04, 0xea,
- 0xe1, 0x2a, 0x8e, 0xe2, 0x8e, 0x0b, 0xb6, 0x99, 0x91, 0x23, 0x5c, 0xd3,
- 0x84, 0x5d, 0xd3, 0x2f, 0x03, 0x0f, 0x9c, 0x9f, 0xd2, 0xf1, 0x07, 0xe5,
- 0xed, 0x00, 0xde, 0x2b, 0xd6, 0xdf, 0x6d, 0x15, 0xc3, 0x83, 0xb8, 0x7a,
- 0xc9, 0xcf, 0x2d, 0x66, 0xbd, 0x34, 0xed, 0x7e, 0x37, 0x6a, 0x78, 0x31,
- 0x8e, 0xb2, 0x08, 0xca, 0xda, 0x45, 0xf3, 0xfe, 0x32, 0x1e, 0xd3, 0x16,
- 0x8f, 0xfc, 0xad, 0xec, 0x6f, 0xd0, 0x13, 0x6c, 0xda, 0x8c, 0x37, 0x80,
- 0x71, 0x31, 0x97, 0x63, 0x7b, 0xd4, 0x38, 0xe4, 0xf7, 0xb8, 0x47, 0x19,
- 0xce, 0x38, 0x03, 0xe7, 0xc7, 0x7e, 0x51, 0xae, 0x71, 0xe0, 0x4b, 0xd5,
- 0x87, 0xff, 0x32, 0xd6, 0xec, 0x71, 0xd9, 0x57, 0xbc, 0x5a, 0xfb, 0xd4,
- 0x8d, 0x47, 0xcd, 0x7a, 0x88, 0x0a, 0xeb, 0xa1, 0xef, 0x38, 0x6d, 0x9b,
- 0x31, 0xfd, 0x3e, 0x7a, 0x94, 0xbf, 0x29, 0x9f, 0x6b, 0xe5, 0xbd, 0xb1,
- 0x6b, 0xf2, 0x2b, 0x64, 0x1d, 0x6d, 0x0b, 0xac, 0x59, 0xb9, 0x16, 0xef,
- 0xf4, 0xf1, 0x29, 0xf3, 0xc8, 0x4f, 0x07, 0xc1, 0x13, 0xaa, 0xc1, 0xf0,
- 0x3e, 0x7d, 0x8d, 0x7a, 0xfc, 0x04, 0xfb, 0x0b, 0xbc, 0x72, 0x02, 0xb6,
- 0xdb, 0xae, 0xe5, 0x3e, 0x20, 0x2b, 0xe3, 0x31, 0x39, 0x59, 0x68, 0x91,
- 0xb9, 0x82, 0x82, 0xc1, 0x60, 0x64, 0x67, 0x44, 0x12, 0x5a, 0xff, 0xd2,
- 0xbe, 0x1b, 0x9e, 0x8e, 0x58, 0xba, 0x83, 0xc3, 0xd2, 0xfc, 0x1b, 0xd0,
- 0xb1, 0x65, 0xe8, 0xd8, 0x56, 0xe8, 0xe0, 0xd5, 0x32, 0xa2, 0xab, 0x61,
- 0xad, 0x8c, 0x60, 0x9b, 0x14, 0xbc, 0xf2, 0x83, 0x68, 0x17, 0xd2, 0x5f,
- 0x4c, 0xd3, 0x5a, 0x56, 0x72, 0xce, 0xae, 0xca, 0x94, 0xb3, 0xbb, 0xb2,
- 0x5a, 0x07, 0xf5, 0xb9, 0x51, 0x31, 0xb0, 0x9e, 0xd4, 0x71, 0xbc, 0x94,
- 0x9f, 0x01, 0x4e, 0x76, 0x83, 0xee, 0x9e, 0x2e, 0xc1, 0x8f, 0xa7, 0x5c,
- 0x06, 0xcc, 0x8f, 0x01, 0xe6, 0xd9, 0x92, 0x13, 0xda, 0x06, 0xc2, 0xe0,
- 0xc9, 0xec, 0x74, 0xbf, 0x2c, 0xce, 0x93, 0x0e, 0x21, 0x03, 0x4a, 0x58,
- 0x4f, 0x7f, 0x1d, 0xec, 0x00, 0x8e, 0x0f, 0xb9, 0x3d, 0xdd, 0xa1, 0xdf,
- 0x19, 0x7d, 0xde, 0x29, 0x8b, 0xe5, 0xf7, 0x58, 0xd8, 0x0e, 0xd7, 0xc0,
- 0xb6, 0x6e, 0x19, 0xb6, 0xdd, 0x80, 0x6d, 0x4f, 0x5d, 0xd8, 0xea, 0xe9,
- 0xe2, 0x2e, 0xd8, 0x34, 0xe4, 0x8f, 0x10, 0xaf, 0xed, 0x96, 0x1e, 0x6e,
- 0xb7, 0xf6, 0x2e, 0x6d, 0xa2, 0x9f, 0x02, 0x1e, 0xd2, 0x18, 0x7e, 0xcf,
- 0x3d, 0x4a, 0x59, 0x86, 0x72, 0x3e, 0x7f, 0x06, 0x75, 0xf0, 0x3c, 0xf7,
- 0xe7, 0x56, 0x0e, 0xde, 0x65, 0x61, 0xa1, 0x9d, 0x90, 0x86, 0x4d, 0x3c,
- 0xe2, 0x64, 0xe6, 0x08, 0x43, 0x0e, 0xf0, 0xe2, 0x5d, 0xa5, 0xb6, 0x4f,
- 0xde, 0xd9, 0xef, 0x15, 0xb6, 0x1f, 0xf6, 0x1d, 0xce, 0x65, 0xbd, 0xd5,
- 0xf3, 0x21, 0x7d, 0x85, 0xf6, 0xf5, 0x94, 0x93, 0x5e, 0x33, 0xaf, 0x5a,
- 0x9a, 0xa3, 0xbc, 0x8d, 0xca, 0x4e, 0xd0, 0xc9, 0xce, 0x15, 0xb4, 0xa6,
- 0xdd, 0x10, 0x4b, 0xc7, 0xeb, 0xec, 0xfc, 0x0e, 0x18, 0xbe, 0xf1, 0x63,
- 0xd0, 0x87, 0x94, 0x37, 0x37, 0x1b, 0xdf, 0x5c, 0x4e, 0x00, 0xd6, 0xf0,
- 0x99, 0xb4, 0xc9, 0xdf, 0x94, 0x49, 0x55, 0x5a, 0x34, 0xbe, 0x4b, 0xa7,
- 0x8e, 0x9f, 0x56, 0xed, 0xf5, 0xa8, 0x8c, 0x9a, 0x35, 0x3f, 0xcc, 0x35,
- 0xa7, 0x2f, 0xd2, 0xfd, 0xc0, 0xa8, 0xe5, 0xaf, 0x54, 0x29, 0x27, 0xbb,
- 0xed, 0xdc, 0xbf, 0x5c, 0x67, 0xed, 0x5a, 0x97, 0xd7, 0x6e, 0xb4, 0xb2,
- 0x7a, 0x8e, 0x22, 0x5d, 0x0f, 0x44, 0xb5, 0x6f, 0x2b, 0xca, 0x97, 0x46,
- 0x8f, 0xf2, 0x93, 0xb6, 0x12, 0xca, 0x67, 0xfb, 0xdc, 0x36, 0xd0, 0xdb,
- 0x53, 0x6b, 0xec, 0xae, 0xa4, 0x95, 0x9b, 0xf4, 0x83, 0xc3, 0x31, 0x72,
- 0x56, 0x4e, 0xe6, 0xd0, 0xff, 0x94, 0xb3, 0xb3, 0x52, 0x4f, 0x5e, 0x86,
- 0x72, 0x92, 0xf3, 0xb9, 0x57, 0xee, 0x78, 0x90, 0x3c, 0x7a, 0xbb, 0xb6,
- 0xaf, 0xaf, 0xda, 0x71, 0x00, 0xf8, 0x23, 0xfc, 0x8b, 0x9b, 0x60, 0x32,
- 0x40, 0xe7, 0xa6, 0x65, 0xdc, 0xae, 0xdb, 0xf8, 0xf2, 0xfa, 0xf3, 0x6a,
- 0xc7, 0x6f, 0xc6, 0x59, 0x95, 0x85, 0x59, 0xdb, 0xb1, 0xb0, 0xeb, 0x56,
- 0xdb, 0xb2, 0x9c, 0x03, 0xed, 0xd9, 0x46, 0x63, 0x0b, 0x16, 0x69, 0x7f,
- 0x52, 0x76, 0xd1, 0xfe, 0x8c, 0x35, 0x4a, 0x33, 0xe7, 0x33, 0x68, 0xcb,
- 0x68, 0xa7, 0xae, 0x9e, 0xdf, 0x6a, 0xff, 0x91, 0x70, 0x12, 0x6e, 0x43,
- 0x5b, 0x49, 0x45, 0xd8, 0x02, 0x19, 0xf5, 0xaf, 0xd5, 0x6b, 0xa0, 0x68,
- 0xbb, 0xee, 0xf8, 0x76, 0x83, 0x89, 0x31, 0x27, 0xd1, 0x3f, 0xc7, 0x24,
- 0xff, 0xf1, 0x4e, 0x3b, 0xbf, 0x9e, 0x2c, 0xab, 0xd5, 0x3d, 0x97, 0x2d,
- 0xe3, 0x6f, 0xe7, 0x8a, 0x35, 0x0a, 0xf1, 0x17, 0xd2, 0x45, 0x2d, 0x0e,
- 0x49, 0x13, 0xa4, 0x85, 0x90, 0x16, 0xb7, 0x5a, 0x7d, 0x13, 0xd2, 0xde,
- 0xa5, 0xa0, 0xbd, 0xfb, 0x80, 0x27, 0xca, 0x70, 0xc6, 0xed, 0x36, 0xe3,
- 0xf9, 0x08, 0x9e, 0x43, 0x3e, 0xb9, 0x98, 0x0c, 0xa7, 0xfc, 0x66, 0x9b,
- 0x8c, 0x95, 0xfb, 0xa1, 0x9f, 0xcb, 0x36, 0x9c, 0x37, 0xe5, 0xff, 0x57,
- 0xe9, 0x77, 0x35, 0x1a, 0x3b, 0xfd, 0x43, 0x8d, 0x94, 0xaf, 0x9b, 0xe4,
- 0x60, 0x4d, 0xd9, 0xc5, 0xe4, 0x77, 0xed, 0x9c, 0x2f, 0xff, 0x7f, 0x30,
- 0xe7, 0xc4, 0xaa, 0x39, 0xbb, 0x76, 0xce, 0x15, 0xbc, 0x6f, 0xc3, 0xfb,
- 0x16, 0xea, 0x82, 0x64, 0x55, 0xde, 0x58, 0x5c, 0xe8, 0x79, 0xd5, 0xca,
- 0x89, 0x50, 0x46, 0x70, 0x5e, 0x1f, 0xb1, 0x73, 0x78, 0xa0, 0x66, 0x5e,
- 0x1f, 0x79, 0x13, 0xf3, 0xea, 0x5c, 0x31, 0xaf, 0x5d, 0x17, 0x9d, 0x57,
- 0x3d, 0x1e, 0x27, 0x2f, 0x87, 0xf3, 0x8b, 0xc9, 0x8d, 0x05, 0xce, 0x71,
- 0x27, 0xe6, 0x48, 0x18, 0xc2, 0x39, 0x0e, 0xd9, 0x39, 0x8a, 0xea, 0xda,
- 0xf1, 0x73, 0xf8, 0x5d, 0x3b, 0x3f, 0xea, 0xfe, 0x1f, 0x83, 0xa6, 0x9b,
- 0x24, 0xd3, 0xdf, 0x64, 0xe5, 0xff, 0x97, 0xe5, 0xd6, 0x22, 0xd7, 0x3a,
- 0x95, 0x16, 0xd9, 0xa3, 0xf6, 0x15, 0x9f, 0x6d, 0x64, 0x8c, 0x7f, 0x97,
- 0x6f, 0xf5, 0x18, 0xf4, 0xc5, 0x6e, 0xd8, 0x7c, 0x3b, 0x0b, 0x6a, 0x20,
- 0x22, 0x41, 0x70, 0x9b, 0xdf, 0x8c, 0xb1, 0x37, 0x6a, 0x5f, 0x75, 0x6d,
- 0x7c, 0xfd, 0x99, 0x46, 0xf1, 0x68, 0x6f, 0x50, 0x9f, 0x43, 0xdf, 0x1d,
- 0xa3, 0x0d, 0x96, 0x81, 0x9d, 0x9c, 0x4e, 0x44, 0xb4, 0x2d, 0x46, 0x9d,
- 0x98, 0x4a, 0xa4, 0xa5, 0x2c, 0xd9, 0x63, 0xe9, 0x84, 0x12, 0x8e, 0x01,
- 0x5b, 0x0d, 0x36, 0xe4, 0xad, 0x90, 0x35, 0xb7, 0x56, 0xf6, 0xaa, 0x5b,
- 0x60, 0xef, 0xdc, 0x72, 0xf2, 0x03, 0xea, 0x36, 0xd8, 0x3a, 0xb7, 0x9d,
- 0xbc, 0x41, 0xed, 0x83, 0x6d, 0xb3, 0x0f, 0x76, 0xce, 0xbe, 0x0a, 0x6d,
- 0xcf, 0x9b, 0x41, 0x7b, 0x9d, 0x35, 0xb4, 0x46, 0x1b, 0x87, 0xf3, 0x23,
- 0xee, 0x8f, 0x71, 0x0d, 0xfc, 0xa4, 0x7a, 0x45, 0xaf, 0x4b, 0xdb, 0x8a,
- 0xb2, 0xd7, 0x92, 0x55, 0xa1, 0x7e, 0xda, 0x60, 0xe3, 0x46, 0x94, 0xb7,
- 0xaf, 0x45, 0x5b, 0xa4, 0x11, 0x17, 0x78, 0x26, 0xfe, 0x48, 0x5b, 0xb5,
- 0xf3, 0xdf, 0xd4, 0x24, 0x5e, 0x67, 0x93, 0x34, 0xdf, 0x0b, 0xf9, 0x5a,
- 0x4b, 0x53, 0xbc, 0xbb, 0x56, 0xd7, 0x90, 0xb6, 0x28, 0x83, 0x43, 0x7a,
- 0xd8, 0xfa, 0x1a, 0xf2, 0xf7, 0xa2, 0xf4, 0x74, 0x4f, 0x64, 0x28, 0x08,
- 0xc6, 0x07, 0x64, 0x23, 0xe3, 0x01, 0x99, 0x4a, 0x35, 0x26, 0xa0, 0xbc,
- 0xda, 0x98, 0x00, 0xfd, 0xac, 0x47, 0x80, 0xdf, 0x19, 0x5c, 0x22, 0x63,
- 0x8c, 0x3b, 0x54, 0x42, 0xbb, 0xfc, 0x1b, 0xd6, 0x2e, 0x0f, 0xe1, 0x48,
- 0x02, 0x0e, 0x23, 0x9f, 0xd7, 0xea, 0xb9, 0x95, 0xfa, 0x3b, 0xb7, 0x6c,
- 0xd3, 0x26, 0xe5, 0xc6, 0x22, 0xe7, 0x4d, 0x19, 0x4c, 0xdc, 0xd4, 0xca,
- 0xe0, 0x84, 0xb5, 0xa3, 0x50, 0x47, 0xcb, 0xcf, 0xb5, 0xb2, 0x93, 0x72,
- 0x8f, 0xf1, 0xf9, 0x07, 0x7c, 0xd2, 0xfa, 0x7b, 0x24, 0xbd, 0x1c, 0x9f,
- 0x17, 0xd0, 0x9b, 0xf8, 0x91, 0x21, 0xbd, 0xdf, 0xe6, 0xce, 0xca, 0x6e,
- 0x19, 0x8e, 0x33, 0xd6, 0xc9, 0x78, 0x9e, 0x97, 0x9b, 0x05, 0x0f, 0x4c,
- 0x16, 0x15, 0x2c, 0xf8, 0x46, 0x19, 0x73, 0x03, 0xd9, 0xe5, 0x3b, 0x3a,
- 0x76, 0x6c, 0x74, 0xed, 0x4c, 0x93, 0xb1, 0x5d, 0x1d, 0x1d, 0xff, 0x5d,
- 0x04, 0xf5, 0x2d, 0x6a, 0xfb, 0x56, 0x69, 0xfd, 0xbb, 0xa0, 0xeb, 0x7c,
- 0xae, 0x29, 0x8c, 0x63, 0x2e, 0xba, 0x11, 0x5b, 0xaf, 0xb6, 0xfc, 0x8b,
- 0x36, 0x3e, 0x9d, 0x84, 0xec, 0x0f, 0xcb, 0xfe, 0xb0, 0x4e, 0xd9, 0xb7,
- 0xea, 0x94, 0xfd, 0xcf, 0x3a, 0x65, 0x26, 0x2e, 0xb8, 0xb3, 0xf0, 0xf7,
- 0x78, 0x37, 0xa5, 0x7d, 0x77, 0xb1, 0xfb, 0x61, 0xb9, 0xe5, 0x3a, 0x1b,
- 0xac, 0x5f, 0xc6, 0x18, 0xb1, 0x89, 0x0d, 0x67, 0x75, 0x6c, 0xb8, 0xcf,
- 0xdd, 0xa1, 0xf4, 0x5e, 0xca, 0x7e, 0xc6, 0x19, 0xf7, 0x69, 0xbc, 0x10,
- 0x27, 0x5f, 0x61, 0x0c, 0x38, 0xc7, 0xbd, 0xd8, 0xa4, 0xba, 0x18, 0x6d,
- 0x57, 0x6d, 0x13, 0xb3, 0x6e, 0xb4, 0x8b, 0x5b, 0x64, 0x04, 0xb6, 0xc2,
- 0xce, 0x42, 0x9b, 0xec, 0x9a, 0x1e, 0x58, 0x47, 0xbd, 0xb5, 0x7b, 0xda,
- 0xf8, 0x83, 0xfb, 0xc0, 0x57, 0x69, 0x21, 0x8c, 0x29, 0x5f, 0x84, 0x36,
- 0xf1, 0x5a, 0x5b, 0xf8, 0xb5, 0xfb, 0xfb, 0xa5, 0x8b, 0xf4, 0xe7, 0xc0,
- 0x76, 0x78, 0xa3, 0xfd, 0x35, 0xcb, 0xc8, 0x74, 0x88, 0x2b, 0xf5, 0x33,
- 0xb6, 0x8b, 0x5c, 0xa4, 0x9d, 0xb6, 0x4b, 0xe4, 0xe9, 0x65, 0x59, 0xbc,
- 0x15, 0x36, 0x93, 0x04, 0x99, 0x01, 0xe9, 0x8c, 0x88, 0x8e, 0xf1, 0xf8,
- 0x46, 0x36, 0xf7, 0x70, 0x6f, 0x07, 0xf4, 0x6f, 0x6c, 0x15, 0x13, 0x37,
- 0x0d, 0xed, 0x94, 0x7a, 0xb4, 0x7b, 0x9d, 0xa5, 0x5d, 0xee, 0xb9, 0xee,
- 0xa6, 0xcc, 0xd5, 0x6b, 0x42, 0x3a, 0xde, 0x55, 0x90, 0x64, 0x48, 0xc7,
- 0x8b, 0x92, 0x5e, 0x41, 0xc7, 0x8b, 0x32, 0xa4, 0xe9, 0xb8, 0x71, 0x05,
- 0x1d, 0x77, 0x5a, 0x3a, 0xde, 0x13, 0x33, 0x74, 0xa1, 0xb4, 0x9e, 0x22,
- 0x9d, 0x1a, 0x3a, 0x76, 0x34, 0x1d, 0x2f, 0xe2, 0x1e, 0xf5, 0xae, 0xb3,
- 0x75, 0x22, 0xb6, 0x8c, 0xbf, 0xc3, 0x32, 0xca, 0xc5, 0x4f, 0xc6, 0x8c,
- 0x5e, 0x1a, 0x02, 0x1d, 0x85, 0xe5, 0xfb, 0x6d, 0xfc, 0xa0, 0xb6, 0xcc,
- 0xc4, 0x47, 0x76, 0x16, 0xc6, 0x62, 0x2b, 0xe9, 0x73, 0x08, 0xf4, 0x19,
- 0xd6, 0x79, 0x2d, 0xfa, 0x6c, 0xb6, 0xfb, 0x16, 0x71, 0xbd, 0x2f, 0x9f,
- 0x8e, 0x1b, 0x5a, 0xbd, 0x45, 0xcf, 0x9d, 0xf3, 0x3e, 0xfb, 0x06, 0x68,
- 0xd5, 0xac, 0xcd, 0xb9, 0xaa, 0xbf, 0xcd, 0x58, 0x54, 0xd2, 0xc4, 0xb0,
- 0x19, 0x27, 0xbd, 0x98, 0xed, 0x68, 0xe4, 0x53, 0x83, 0x96, 0x4f, 0xad,
- 0x63, 0xcc, 0x35, 0xa8, 0xca, 0xec, 0x01, 0xe8, 0x0a, 0xda, 0xd8, 0x5a,
- 0x4e, 0xe3, 0x5d, 0x67, 0x32, 0x53, 0x78, 0x35, 0x88, 0x78, 0x8c, 0x0f,
- 0x71, 0x5f, 0x40, 0xc6, 0x1c, 0x94, 0x75, 0x95, 0xcd, 0xbc, 0x94, 0xd7,
- 0x8a, 0xe7, 0x01, 0xe9, 0x2a, 0x2b, 0xf9, 0xe8, 0x74, 0x8b, 0xec, 0x2f,
- 0x44, 0xe5, 0xe3, 0x68, 0xff, 0xb1, 0x82, 0x0b, 0x7f, 0xfc, 0x4c, 0x8c,
- 0x76, 0xe1, 0xbe, 0x02, 0xf7, 0x27, 0x59, 0x37, 0xbe, 0x6a, 0x7f, 0x36,
- 0x22, 0x5d, 0x3d, 0x79, 0x78, 0x2a, 0x12, 0xdd, 0x03, 0x38, 0x9a, 0x86,
- 0x86, 0xe4, 0x07, 0x03, 0x1b, 0x51, 0xf6, 0xb2, 0x1d, 0x6f, 0xd4, 0x31,
- 0xf1, 0xde, 0x41, 0x79, 0x77, 0x65, 0x48, 0xae, 0xaf, 0x98, 0x3d, 0xd5,
- 0xea, 0x9e, 0x69, 0xca, 0x5d, 0x80, 0xfe, 0x49, 0xbb, 0x41, 0x70, 0xce,
- 0xc3, 0xaa, 0x1f, 0x89, 0x4a, 0xac, 0x27, 0x95, 0x58, 0x10, 0xf3, 0x7c,
- 0xbe, 0xfc, 0x0f, 0xc1, 0x58, 0x3c, 0x2a, 0x3f, 0xf0, 0x38, 0xc7, 0x41,
- 0xb9, 0xae, 0x5c, 0x3b, 0x36, 0x97, 0xf3, 0x0f, 0x63, 0xdc, 0xa7, 0xc8,
- 0x54, 0x16, 0x62, 0x8c, 0xa5, 0xd3, 0xe7, 0xe8, 0x7a, 0x1b, 0xfc, 0x38,
- 0x48, 0xee, 0xae, 0xb7, 0x81, 0x6e, 0xe2, 0xd0, 0xf9, 0x57, 0x01, 0xc6,
- 0xab, 0x18, 0xfb, 0x62, 0xcc, 0x8b, 0xcf, 0x5f, 0xc7, 0xb8, 0x6c, 0xfb,
- 0x1b, 0xd6, 0x5e, 0xe6, 0xfa, 0x1b, 0xde, 0xa9, 0xaf, 0x77, 0x5a, 0xc7,
- 0x62, 0x43, 0xe2, 0xc4, 0xde, 0x91, 0x90, 0x75, 0x5e, 0xed, 0xf8, 0xdc,
- 0x27, 0x86, 0xc5, 0x38, 0x20, 0xd1, 0xdd, 0xdb, 0x07, 0x65, 0x04, 0xf3,
- 0xdb, 0xb9, 0x66, 0x7e, 0xf7, 0x08, 0xe3, 0xab, 0xe7, 0x0b, 0x9c, 0x43,
- 0x75, 0x5e, 0xea, 0x0b, 0x66, 0x5e, 0xb1, 0x9e, 0xd5, 0xf3, 0xd1, 0xed,
- 0xd5, 0x09, 0xc0, 0xf2, 0x35, 0x9d, 0x57, 0x10, 0x04, 0x6f, 0xed, 0x39,
- 0x1f, 0x24, 0x2f, 0x49, 0xf5, 0x2e, 0x54, 0xf7, 0x77, 0xc6, 0x22, 0x43,
- 0x69, 0xad, 0xcf, 0xf0, 0x9c, 0xcc, 0x96, 0xd3, 0x58, 0x47, 0x89, 0x66,
- 0xfb, 0xa3, 0x9a, 0x4f, 0xb2, 0x5e, 0xda, 0xee, 0x61, 0x85, 0x3e, 0x54,
- 0x10, 0x28, 0x6f, 0xb5, 0xdc, 0xa0, 0xbe, 0xc2, 0xdc, 0xe5, 0xdf, 0xda,
- 0x1c, 0x96, 0x5e, 0xc6, 0xb3, 0xc6, 0xa2, 0x43, 0xb1, 0x64, 0xbe, 0xec,
- 0xe1, 0x77, 0x0b, 0xee, 0x3b, 0x60, 0xaf, 0xf8, 0xb0, 0x67, 0x24, 0xae,
- 0x8c, 0x6c, 0x00, 0x2d, 0xf7, 0xe4, 0x94, 0x22, 0x6f, 0xba, 0xc9, 0xc9,
- 0x72, 0x3c, 0x59, 0x2a, 0x7f, 0x96, 0xed, 0x51, 0xb7, 0x5e, 0x2c, 0xcf,
- 0xc8, 0x86, 0xa7, 0x2a, 0x1c, 0x83, 0xfe, 0xef, 0x1b, 0x19, 0x23, 0x6a,
- 0xfb, 0x66, 0x9f, 0x21, 0x5e, 0xa2, 0x74, 0xc9, 0xf1, 0x2f, 0x6d, 0x7d,
- 0x13, 0xce, 0xef, 0xb3, 0x16, 0xee, 0xd5, 0xe3, 0xbe, 0xa0, 0xed, 0x97,
- 0xd3, 0x15, 0xda, 0x8c, 0xdc, 0xdf, 0x49, 0x1d, 0x9f, 0x11, 0xc2, 0x11,
- 0x04, 0xcf, 0xf9, 0x46, 0x77, 0x3f, 0x55, 0xe1, 0x1e, 0x47, 0x10, 0xfc,
- 0x88, 0x76, 0xf1, 0xde, 0x22, 0xc6, 0x0b, 0x71, 0xb0, 0x35, 0x17, 0x85,
- 0x5c, 0x9c, 0x1a, 0x20, 0x7e, 0x05, 0x1e, 0x6a, 0x8f, 0x7b, 0xa3, 0xc4,
- 0x92, 0x9f, 0x2a, 0xb7, 0x24, 0x3f, 0x5d, 0x76, 0x81, 0x67, 0xce, 0x3b,
- 0x9e, 0x9c, 0xb0, 0x73, 0xce, 0x96, 0x89, 0xdf, 0xd7, 0xda, 0x87, 0x7c,
- 0x61, 0x85, 0xbf, 0x44, 0x98, 0xaa, 0xb0, 0x10, 0xb6, 0xa4, 0xc5, 0x4d,
- 0x10, 0xfc, 0xd8, 0x37, 0x6b, 0x3a, 0x55, 0x94, 0x29, 0x8c, 0x9b, 0xdb,
- 0xac, 0x88, 0x87, 0x58, 0xf2, 0x0e, 0x8c, 0xfd, 0x29, 0x8c, 0xbd, 0xbf,
- 0xcc, 0xf1, 0x20, 0x2b, 0x30, 0xf7, 0xa9, 0x4a, 0x08, 0x6f, 0xbd, 0xb1,
- 0xc3, 0x35, 0xef, 0xb5, 0x36, 0x5e, 0xf8, 0xac, 0x11, 0xd9, 0xae, 0xbc,
- 0x7e, 0xd0, 0xd7, 0xe2, 0xa6, 0xa8, 0xfc, 0x22, 0xe4, 0x6e, 0x20, 0x8f,
- 0x42, 0x9e, 0x2d, 0x6a, 0xba, 0xc9, 0x5c, 0xce, 0xff, 0x23, 0xf2, 0xeb,
- 0xeb, 0x18, 0x5f, 0x1e, 0xf6, 0x68, 0xbb, 0x2e, 0x05, 0x8b, 0x1e, 0xe5,
- 0xf3, 0x06, 0x99, 0x71, 0x73, 0xbd, 0xd0, 0x15, 0x28, 0x6b, 0xa5, 0xbf,
- 0x9d, 0xcc, 0x44, 0x52, 0xc9, 0x49, 0x61, 0x3e, 0x14, 0x73, 0x15, 0x98,
- 0x23, 0x44, 0xd9, 0x10, 0x85, 0xcc, 0xe3, 0x1a, 0x9a, 0xf1, 0x26, 0xcb,
- 0xd5, 0xba, 0x07, 0x84, 0x7b, 0x86, 0xa9, 0xc4, 0x3e, 0x6d, 0x9f, 0x88,
- 0x8c, 0x17, 0x58, 0x77, 0x3b, 0xac, 0x13, 0xaf, 0xa6, 0xbe, 0xce, 0xe1,
- 0x02, 0x9f, 0x87, 0x71, 0xac, 0x58, 0x2c, 0x53, 0x90, 0x97, 0x23, 0x03,
- 0xf2, 0x32, 0xed, 0xce, 0x61, 0xd0, 0xb6, 0xeb, 0xf1, 0xbd, 0x29, 0xcf,
- 0xf8, 0xb2, 0x94, 0x19, 0xec, 0xa3, 0x9d, 0x9d, 0x53, 0x9a, 0x27, 0x44,
- 0xa1, 0x6d, 0x2c, 0x5b, 0x96, 0x91, 0x6c, 0xc1, 0xc6, 0x7a, 0x46, 0x39,
- 0xe7, 0x0d, 0x35, 0x73, 0x6f, 0x95, 0x28, 0x60, 0x1a, 0x89, 0x24, 0x9d,
- 0x06, 0xef, 0x23, 0x2d, 0x46, 0xe7, 0x43, 0xee, 0xb7, 0xdd, 0xdf, 0xce,
- 0x3d, 0x53, 0x05, 0x1f, 0x5a, 0xb5, 0xdf, 0x7e, 0x8d, 0x1a, 0xfa, 0xf3,
- 0x04, 0xf4, 0xa0, 0x95, 0x95, 0xb1, 0x91, 0xae, 0x65, 0xfa, 0xe6, 0xf8,
- 0xd2, 0x1e, 0xf1, 0x92, 0x23, 0xc3, 0x65, 0x51, 0x91, 0x21, 0x37, 0x36,
- 0x5c, 0x5e, 0x49, 0xf3, 0x4f, 0x55, 0xfe, 0xbd, 0xb5, 0x05, 0x6b, 0x63,
- 0xaa, 0xb5, 0xef, 0xc8, 0x77, 0x2b, 0xf6, 0x2b, 0x92, 0x26, 0x07, 0x86,
- 0xfb, 0xb4, 0x5c, 0x93, 0xf4, 0x5b, 0x1b, 0xa0, 0x7c, 0x66, 0xb4, 0x8f,
- 0xc6, 0x9c, 0x8b, 0x98, 0xcd, 0x3d, 0x33, 0xb8, 0x4e, 0x97, 0x1d, 0x99,
- 0x82, 0x7c, 0x38, 0x20, 0x7f, 0x1f, 0xa4, 0xe3, 0xe6, 0xbd, 0x59, 0x5f,
- 0xd6, 0xe7, 0x5e, 0x44, 0xb3, 0xe4, 0x4f, 0x46, 0x25, 0x77, 0x92, 0x7b,
- 0x60, 0xcf, 0xed, 0xaf, 0xe6, 0x6d, 0x50, 0x0e, 0x70, 0xbf, 0xd6, 0x91,
- 0x3c, 0xfc, 0xda, 0x11, 0xee, 0xc3, 0xf7, 0xff, 0x1f, 0xf4, 0xc1, 0x7a,
- 0x61, 0xdb, 0x16, 0xb4, 0x6d, 0xb4, 0x6d, 0x47, 0xef, 0x78, 0x73, 0x6d,
- 0x5b, 0xd1, 0x36, 0x16, 0x8e, 0xfb, 0x06, 0xdb, 0x6a, 0x7c, 0x5e, 0x33,
- 0x5c, 0x28, 0x2e, 0xc1, 0x4f, 0x4e, 0x4c, 0x48, 0xda, 0x19, 0x1f, 0xd0,
- 0xf3, 0xb9, 0x66, 0xb8, 0x0c, 0x38, 0xe2, 0x41, 0x90, 0xf7, 0x43, 0x3d,
- 0xcc, 0x7f, 0xc7, 0x44, 0x3c, 0x96, 0x71, 0xdf, 0x92, 0xfe, 0x04, 0xa3,
- 0xa4, 0x2e, 0xf3, 0xd9, 0x24, 0xcf, 0xfd, 0xc9, 0xf8, 0x46, 0xdc, 0x55,
- 0x17, 0x71, 0x92, 0xf5, 0x18, 0xef, 0xdd, 0x68, 0xcb, 0x23, 0x2c, 0x4f,
- 0x45, 0x21, 0x4b, 0x4c, 0x79, 0xc4, 0x96, 0x03, 0x26, 0x3f, 0x9f, 0x04,
- 0xb7, 0xd9, 0x72, 0x3e, 0x2b, 0x5d, 0x6e, 0x9e, 0x0d, 0x0f, 0x8d, 0x09,
- 0xe3, 0x3a, 0x99, 0xeb, 0x1a, 0x64, 0x2b, 0xd6, 0x87, 0x3e, 0xa3, 0x23,
- 0xcd, 0x80, 0xe3, 0x9c, 0xff, 0x76, 0xd8, 0xd6, 0x81, 0xfc, 0xc0, 0x37,
- 0xf4, 0x3f, 0x2b, 0x3d, 0x69, 0xe5, 0x30, 0x07, 0x20, 0x90, 0x9d, 0xfe,
- 0xb6, 0xc4, 0x2e, 0xfc, 0x1e, 0xef, 0x4f, 0xca, 0xec, 0x20, 0xe8, 0xb1,
- 0x9f, 0xbc, 0xb1, 0x15, 0x36, 0x0f, 0x7e, 0xf7, 0xb4, 0xc8, 0x92, 0x9b,
- 0x73, 0xd7, 0xc1, 0x5f, 0x1b, 0xc1, 0xac, 0xe6, 0x0a, 0x9e, 0x7b, 0x1b,
- 0x84, 0x5c, 0xda, 0xed, 0xc1, 0xbd, 0x76, 0xbe, 0xdf, 0xc2, 0x7c, 0x7f,
- 0xad, 0x59, 0x9a, 0x59, 0x5e, 0x5b, 0xb7, 0x51, 0xf6, 0xb8, 0xdb, 0xdd,
- 0xd8, 0x8a, 0xba, 0xe7, 0x51, 0x97, 0x65, 0x9e, 0xcb, 0x1c, 0x9d, 0xd9,
- 0x32, 0xe9, 0xcc, 0xc0, 0xda, 0xd5, 0x13, 0x04, 0xd7, 0xf9, 0x1c, 0x37,
- 0x08, 0xae, 0xf7, 0xfb, 0xdc, 0x67, 0xe5, 0xf9, 0xc0, 0xd8, 0x54, 0x21,
- 0xed, 0x3c, 0x67, 0xe5, 0x75, 0x10, 0xbc, 0xec, 0xf7, 0xca, 0xef, 0x54,
- 0x52, 0x8f, 0xd3, 0xe7, 0x3e, 0x83, 0xe7, 0x33, 0xbe, 0xc9, 0x2b, 0xfa,
- 0x13, 0xb4, 0x8b, 0xab, 0x7e, 0xd0, 0xb0, 0x27, 0x5f, 0xd4, 0x3e, 0x3a,
- 0xf1, 0x67, 0x62, 0xfc, 0x55, 0x18, 0x30, 0x61, 0x2f, 0xb3, 0xc9, 0x65,
- 0x7e, 0xa0, 0xa6, 0xdf, 0xda, 0x77, 0x0a, 0xef, 0x58, 0x16, 0x04, 0x97,
- 0x0c, 0xfc, 0x31, 0xe6, 0x94, 0x2a, 0x71, 0xef, 0xee, 0x03, 0x9a, 0xff,
- 0x04, 0x7e, 0x3d, 0xe9, 0x24, 0xea, 0x2a, 0xe5, 0x1d, 0xee, 0x52, 0xa9,
- 0x9c, 0xc8, 0x5b, 0xb0, 0xfe, 0x5c, 0x63, 0x30, 0x48, 0x1b, 0x60, 0xdf,
- 0xb6, 0xbd, 0xd9, 0xc4, 0x92, 0xe8, 0x4b, 0xa7, 0x37, 0xc1, 0xd7, 0xd5,
- 0xf6, 0x4c, 0x14, 0x7c, 0x3d, 0xd1, 0x16, 0x04, 0xef, 0xf7, 0xc3, 0x35,
- 0xb3, 0xb1, 0x6a, 0xe8, 0xf8, 0x6c, 0xff, 0xb9, 0x66, 0x63, 0xc7, 0x31,
- 0x4f, 0x30, 0xa9, 0xe3, 0xfa, 0xaa, 0x1d, 0x3a, 0x64, 0xdb, 0x57, 0x39,
- 0x7e, 0x8e, 0xe5, 0xef, 0xf3, 0x43, 0x98, 0xaa, 0xed, 0xb3, 0xfd, 0xeb,
- 0xac, 0xcd, 0x19, 0x05, 0x2e, 0x3d, 0xb7, 0x4b, 0xfd, 0x4d, 0x60, 0x74,
- 0x6b, 0x48, 0xc3, 0x7f, 0x17, 0x3c, 0x18, 0x37, 0xcf, 0x99, 0x6d, 0xec,
- 0x63, 0xab, 0x4c, 0x6e, 0xc3, 0x73, 0xf4, 0x5a, 0xdc, 0x87, 0x2f, 0x8b,
- 0xc8, 0x15, 0x89, 0x61, 0xb5, 0xcd, 0x7d, 0x50, 0xfa, 0xac, 0x8c, 0xfb,
- 0x1a, 0xf4, 0x7d, 0x0e, 0xfe, 0x78, 0x93, 0x3c, 0x08, 0x9a, 0x56, 0x03,
- 0xa9, 0xe4, 0x82, 0x4a, 0xf5, 0xce, 0xa8, 0x94, 0x3f, 0xa6, 0xae, 0xe7,
- 0xbc, 0x06, 0x89, 0x8b, 0x19, 0xe2, 0xb7, 0x08, 0xfc, 0x17, 0x81, 0xe3,
- 0x8b, 0xee, 0xf1, 0xfa, 0x56, 0xb7, 0x18, 0xfd, 0x96, 0xd3, 0xb4, 0x69,
- 0xec, 0xf2, 0x3f, 0xf6, 0xc3, 0x35, 0x84, 0x6d, 0xc8, 0x1c, 0x99, 0xba,
- 0x6b, 0x94, 0xe5, 0x1a, 0x41, 0x31, 0xe4, 0x40, 0xf7, 0xa9, 0xe4, 0x84,
- 0x5a, 0x0a, 0x36, 0xed, 0xe8, 0xee, 0x7d, 0x42, 0xf7, 0x93, 0xf2, 0xd3,
- 0x2a, 0x0f, 0x78, 0xb6, 0x4a, 0xd3, 0x0e, 0xe2, 0x99, 0xb0, 0xc6, 0x18,
- 0x4f, 0x72, 0xef, 0x40, 0xdd, 0x31, 0xa5, 0xf7, 0xa0, 0x6d, 0x1d, 0xc2,
- 0x1c, 0x5f, 0x2f, 0xcd, 0xd4, 0x43, 0x8c, 0x93, 0xbd, 0x96, 0x2e, 0x84,
- 0x4c, 0x3a, 0x46, 0x19, 0x18, 0x31, 0xb1, 0xdf, 0xca, 0xcf, 0xa1, 0x9d,
- 0xce, 0x67, 0x89, 0x45, 0x21, 0xa3, 0xa6, 0xc0, 0xc5, 0x87, 0x8e, 0x49,
- 0xb4, 0xc1, 0xfb, 0x5f, 0xcd, 0xc6, 0x6f, 0xa2, 0x0f, 0xc5, 0xb1, 0x1b,
- 0x24, 0xbf, 0x26, 0xde, 0x52, 0x02, 0xfc, 0xcd, 0x32, 0x79, 0x8c, 0x6b,
- 0x11, 0x85, 0xcc, 0xe1, 0xd8, 0x12, 0xcd, 0xf4, 0x07, 0xc1, 0x38, 0xcb,
- 0x4f, 0x92, 0x7f, 0x25, 0xc5, 0x77, 0xb9, 0x93, 0x0b, 0x9b, 0xd4, 0x0a,
- 0x59, 0xdb, 0x62, 0xe1, 0xd0, 0x78, 0x92, 0x92, 0x96, 0x23, 0xd4, 0x37,
- 0xb7, 0xd5, 0xc0, 0x33, 0x7a, 0xc7, 0x94, 0xd7, 0xf8, 0x26, 0xe0, 0xf9,
- 0x3d, 0xc0, 0xd3, 0x62, 0xe1, 0x69, 0x5c, 0x05, 0x4f, 0x4b, 0x08, 0x0f,
- 0xe4, 0x1c, 0xe5, 0x6a, 0xec, 0x9a, 0x74, 0x59, 0x9c, 0xbc, 0x27, 0x9d,
- 0x4a, 0xfb, 0x2f, 0xd4, 0x37, 0x8d, 0xee, 0xf8, 0x80, 0x2b, 0xe3, 0x5a,
- 0xd7, 0x44, 0xaf, 0xe9, 0x2e, 0x2f, 0xc0, 0x7a, 0x15, 0x27, 0xe3, 0x11,
- 0xf6, 0x7a, 0x76, 0xd5, 0x3d, 0x90, 0xff, 0x8b, 0xa9, 0xa8, 0xb5, 0x25,
- 0x4a, 0x3e, 0xfd, 0x96, 0xb8, 0xde, 0xdb, 0xaf, 0xc2, 0xf4, 0x12, 0x60,
- 0x82, 0x3c, 0x3e, 0xd6, 0xe7, 0x8e, 0xca, 0xa5, 0xda, 0x37, 0xb3, 0xb8,
- 0xc6, 0xdc, 0x62, 0x35, 0x73, 0x83, 0xfe, 0x53, 0xe1, 0xdc, 0x20, 0x13,
- 0x51, 0xaf, 0x24, 0xf7, 0x5b, 0x5c, 0xb4, 0x62, 0x4e, 0xb1, 0x9a, 0xf9,
- 0x74, 0x27, 0xf6, 0xb3, 0xcc, 0xcc, 0xa7, 0x27, 0xef, 0xc5, 0x2c, 0x7e,
- 0x57, 0xc3, 0x58, 0xf5, 0x17, 0x67, 0x24, 0x90, 0x29, 0x1f, 0x6b, 0xd4,
- 0x4b, 0xff, 0x24, 0x66, 0xf3, 0x98, 0x15, 0x9e, 0x37, 0x58, 0xfe, 0x72,
- 0x25, 0xaf, 0xfd, 0xb7, 0x2f, 0xad, 0x37, 0x7c, 0x1a, 0xb5, 0xf9, 0x6b,
- 0xfc, 0xdd, 0xb1, 0xde, 0xee, 0xef, 0xe7, 0xd2, 0xf2, 0xfb, 0xeb, 0x69,
- 0x97, 0x34, 0x78, 0x43, 0xab, 0xca, 0x62, 0x28, 0xbb, 0x7d, 0xbd, 0x95,
- 0x0b, 0x28, 0xbb, 0x07, 0x7e, 0x1a, 0xf3, 0x34, 0xf8, 0x8e, 0x32, 0xb8,
- 0x16, 0x27, 0x7d, 0x60, 0x45, 0xf2, 0x3c, 0xe5, 0x22, 0x6d, 0x4a, 0xcc,
- 0x51, 0x7d, 0x27, 0x8c, 0xa3, 0xe3, 0x77, 0x3d, 0xdb, 0x9f, 0xf8, 0x26,
- 0xae, 0xe5, 0xdb, 0x53, 0xe0, 0xfb, 0x03, 0xbe, 0x13, 0x9d, 0x65, 0x1e,
- 0x80, 0xa6, 0xe1, 0xda, 0xbe, 0xaf, 0x47, 0xdf, 0x21, 0x2d, 0x93, 0x5e,
- 0xae, 0xd7, 0x74, 0xd3, 0x44, 0x5d, 0x7c, 0x8c, 0xf4, 0xc7, 0x58, 0x72,
- 0xb3, 0xd6, 0x8f, 0xd5, 0x75, 0x6c, 0x82, 0xae, 0x89, 0x1b, 0x1e, 0x75,
- 0xcd, 0x7e, 0x77, 0xb5, 0xbf, 0x31, 0xf4, 0x47, 0x3b, 0x0d, 0x7e, 0xba,
- 0xc7, 0x68, 0x0e, 0xe5, 0x97, 0x13, 0x55, 0x57, 0x6a, 0x3f, 0x33, 0xa6,
- 0xf3, 0x8e, 0x96, 0xeb, 0x4e, 0xd8, 0xb1, 0x49, 0xb7, 0x26, 0xfe, 0x5f,
- 0x1d, 0x5f, 0x1c, 0xb5, 0x4d, 0x40, 0x65, 0x8d, 0x32, 0x35, 0x40, 0x1a,
- 0xe5, 0xdc, 0xb5, 0x0d, 0x75, 0x0d, 0xed, 0x08, 0x43, 0x9f, 0xb4, 0x9d,
- 0xa2, 0xd7, 0x64, 0x0b, 0x8d, 0xc6, 0x67, 0x89, 0xcb, 0xe6, 0x06, 0x9d,
- 0x47, 0x80, 0xb2, 0x72, 0xa8, 0xcb, 0xa2, 0x32, 0xdb, 0xff, 0xbf, 0x83,
- 0xf4, 0x5e, 0xd6, 0xad, 0xbb, 0x6f, 0x9f, 0x98, 0x11, 0x8d, 0xa7, 0xbf,
- 0xa8, 0xe2, 0xc9, 0xce, 0x2d, 0xbe, 0x7a, 0x6e, 0x05, 0xc0, 0x7b, 0x0f,
- 0x64, 0x27, 0xd7, 0xc9, 0xe4, 0x6f, 0x3f, 0x2e, 0x4e, 0x34, 0xd3, 0x5b,
- 0x6f, 0x6e, 0xa5, 0x10, 0xaf, 0x9c, 0x1b, 0x68, 0x35, 0x9c, 0x17, 0x69,
- 0x3b, 0xae, 0xf7, 0x89, 0x94, 0x22, 0x2c, 0xad, 0xab, 0x70, 0x1b, 0xd2,
- 0x9d, 0xa1, 0xb9, 0xa7, 0x34, 0xcd, 0xb5, 0x58, 0x9a, 0x43, 0x5d, 0x97,
- 0xfb, 0xde, 0xa3, 0x2d, 0x55, 0x9a, 0xdb, 0x60, 0x69, 0xee, 0x99, 0xf5,
- 0x66, 0x4f, 0xfc, 0xfd, 0x2d, 0x66, 0x4f, 0xea, 0x2f, 0x57, 0x3d, 0x6f,
- 0xa2, 0xcd, 0x08, 0x5f, 0x2c, 0x7c, 0xae, 0x85, 0xf5, 0x0c, 0x60, 0xad,
- 0x95, 0x35, 0x4d, 0x36, 0xee, 0xc6, 0xfd, 0x73, 0xfa, 0x7d, 0x51, 0x79,
- 0x14, 0x76, 0x50, 0xbe, 0xfc, 0x8f, 0xc1, 0x02, 0x7c, 0xbf, 0xa9, 0x65,
- 0xdd, 0x7b, 0x5b, 0x0b, 0xf9, 0x6d, 0x06, 0xbf, 0x0e, 0xd6, 0xf8, 0x3c,
- 0x98, 0x2f, 0xca, 0xfe, 0x01, 0xeb, 0x01, 0xb9, 0xbc, 0x5c, 0x97, 0x31,
- 0x0b, 0xe3, 0xe3, 0x30, 0x66, 0x68, 0xf6, 0x13, 0x29, 0xe7, 0xef, 0x84,
- 0x4f, 0x74, 0x0f, 0xf4, 0x24, 0xe9, 0xfb, 0xa5, 0x16, 0x93, 0xe7, 0x1b,
- 0x87, 0x1e, 0xfb, 0x65, 0x9b, 0x0b, 0x75, 0xf8, 0x57, 0xeb, 0xe7, 0xf8,
- 0x82, 0xf6, 0x1d, 0xd2, 0xcc, 0xdf, 0xb7, 0x98, 0x98, 0xf1, 0xb7, 0x5a,
- 0xc8, 0x67, 0x6a, 0xdb, 0x0f, 0x37, 0x68, 0xbe, 0x70, 0xc2, 0xe7, 0xcf,
- 0xb4, 0xae, 0x7c, 0x0e, 0xdb, 0x3d, 0xd9, 0xba, 0xb2, 0x5d, 0x58, 0xfe,
- 0x73, 0x1b, 0x57, 0x96, 0x5f, 0xe3, 0xae, 0x6c, 0xff, 0xf5, 0x55, 0xcf,
- 0x2d, 0x9b, 0x56, 0x3e, 0x5f, 0xbd, 0xea, 0x79, 0x6a, 0xd5, 0xf3, 0x85,
- 0x55, 0xcf, 0x57, 0xb5, 0xad, 0x7c, 0xbe, 0xbd, 0xad, 0x3e, 0xbc, 0x87,
- 0xdb, 0x56, 0xc2, 0x75, 0xa7, 0x8e, 0xf7, 0xcf, 0x54, 0xa2, 0xb2, 0xab,
- 0x80, 0xf7, 0x4e, 0xe7, 0x66, 0xa3, 0xd7, 0x6a, 0xdf, 0x33, 0xbe, 0xf6,
- 0xd7, 0xab, 0xfa, 0xab, 0xb6, 0xdb, 0x5d, 0x6d, 0xe7, 0x57, 0xdb, 0x19,
- 0xd9, 0x36, 0x5b, 0xe1, 0x3b, 0x96, 0x87, 0xfd, 0x9a, 0xb6, 0x53, 0xc5,
- 0x4e, 0x9d, 0x0b, 0x3b, 0xaa, 0x73, 0x61, 0x93, 0xe0, 0xc3, 0x3b, 0x75,
- 0x4c, 0x69, 0x93, 0x42, 0x79, 0xa5, 0x55, 0xc7, 0x95, 0x74, 0x2c, 0xb5,
- 0x30, 0x0a, 0xdb, 0x96, 0x39, 0xb0, 0x81, 0xec, 0xf1, 0xcd, 0xdd, 0xe4,
- 0xc4, 0x1e, 0x0e, 0x86, 0xdd, 0x20, 0x98, 0xf4, 0x6e, 0xb3, 0xf9, 0x62,
- 0xb8, 0x57, 0x4c, 0x1b, 0xea, 0xe0, 0x27, 0xa0, 0x83, 0xab, 0xba, 0xf7,
- 0x4e, 0x8c, 0xb5, 0x00, 0x9a, 0x19, 0x90, 0xdf, 0xad, 0xa4, 0xbe, 0x24,
- 0xfa, 0xcc, 0x4d, 0x3f, 0x6c, 0xb8, 0xa5, 0x4f, 0xbd, 0xdf, 0xf3, 0x61,
- 0xeb, 0x05, 0xf2, 0xb0, 0x3f, 0x08, 0x1a, 0xea, 0x85, 0xbd, 0xe7, 0x69,
- 0xbf, 0xf4, 0xb4, 0xa6, 0x2d, 0xd2, 0x58, 0x8b, 0xce, 0xd7, 0x7f, 0xd4,
- 0x77, 0x62, 0x99, 0xfe, 0x3f, 0x32, 0x71, 0x1a, 0xbf, 0xdb, 0xfd, 0x1a,
- 0xf8, 0x76, 0xa7, 0xb7, 0x05, 0x3e, 0x0a, 0x69, 0x88, 0xf1, 0xaf, 0xcb,
- 0x75, 0x1e, 0x21, 0x03, 0x68, 0x33, 0x51, 0xc6, 0x09, 0x53, 0x83, 0x63,
- 0xc2, 0x79, 0xa7, 0x12, 0x49, 0xa5, 0xed, 0xaa, 0xe0, 0x46, 0x9f, 0x39,
- 0xb6, 0xdc, 0x63, 0x21, 0x3f, 0xef, 0xff, 0xf4, 0x94, 0x97, 0x73, 0x23,
- 0x36, 0x2f, 0x37, 0x53, 0x30, 0xb4, 0x39, 0x41, 0xda, 0x84, 0x3f, 0xb5,
- 0xd8, 0xff, 0xb7, 0x01, 0xed, 0xfb, 0xa4, 0x22, 0xed, 0xff, 0x4d, 0x30,
- 0x17, 0x65, 0x5f, 0x84, 0x7b, 0xff, 0xa7, 0x33, 0x1a, 0x57, 0x77, 0xca,
- 0x81, 0x22, 0x6d, 0xe1, 0x98, 0xce, 0xe7, 0x18, 0xf7, 0x69, 0xa7, 0xc5,
- 0x80, 0xc7, 0x0f, 0x01, 0x7f, 0x2d, 0xb0, 0xb9, 0x47, 0x50, 0x27, 0x22,
- 0x63, 0x60, 0xf1, 0xd9, 0x02, 0xf9, 0x93, 0xf7, 0x28, 0xea, 0xbb, 0x32,
- 0x5f, 0xb8, 0x59, 0xe7, 0xdb, 0x9d, 0x46, 0xdb, 0x27, 0x71, 0xcd, 0x16,
- 0x26, 0xd0, 0x66, 0xaf, 0xae, 0x3f, 0x5b, 0x62, 0x8e, 0xb2, 0x40, 0x2e,
- 0xed, 0x97, 0xfc, 0x5c, 0x97, 0x8c, 0xc5, 0x17, 0x66, 0xa2, 0xcb, 0x71,
- 0x99, 0x8f, 0x6f, 0xe0, 0x1e, 0x47, 0xfe, 0x4a, 0xee, 0x07, 0x4b, 0x74,
- 0x74, 0xbb, 0xea, 0x6d, 0xd3, 0x3e, 0xd7, 0xa0, 0xec, 0xac, 0x0c, 0xc9,
- 0x4d, 0x95, 0xcf, 0x6e, 0x36, 0xb1, 0xa8, 0x15, 0xf1, 0xad, 0xc3, 0xc4,
- 0x8a, 0x3a, 0x1a, 0xe5, 0xb9, 0x25, 0x99, 0x3d, 0x25, 0x12, 0x39, 0x1a,
- 0xc6, 0x12, 0x59, 0xe6, 0x4a, 0xd7, 0x95, 0x80, 0xeb, 0x14, 0x64, 0x6b,
- 0x3c, 0x26, 0x5f, 0xdc, 0x16, 0x8e, 0x95, 0x0b, 0xa6, 0xb7, 0xe5, 0xe4,
- 0xd3, 0xb8, 0xb2, 0x57, 0xa6, 0x4a, 0x19, 0xc5, 0x71, 0xbf, 0x13, 0x50,
- 0x96, 0xa9, 0x21, 0x4f, 0x72, 0x6d, 0xe1, 0xd8, 0xf0, 0x6f, 0x76, 0x84,
- 0xe3, 0xd3, 0xe6, 0x36, 0x67, 0x1e, 0xf2, 0xdc, 0x77, 0x01, 0xfd, 0x45,
- 0x86, 0xee, 0xde, 0x40, 0xdf, 0x61, 0x58, 0xd8, 0x0e, 0x32, 0x5d, 0xb1,
- 0x6f, 0xc2, 0x49, 0xf8, 0x6b, 0xe1, 0x5c, 0x4c, 0xc6, 0x81, 0xa3, 0xdc,
- 0xeb, 0xc2, 0xdb, 0xe7, 0x7a, 0xaa, 0x1e, 0xbc, 0xa3, 0x36, 0x96, 0xc8,
- 0xf8, 0xe0, 0x3a, 0xe0, 0xad, 0x05, 0xe5, 0x1f, 0x94, 0xa9, 0x63, 0x6f,
- 0xdb, 0xcc, 0xbd, 0xec, 0x06, 0xcf, 0xb1, 0x39, 0xa7, 0x3c, 0xbf, 0x73,
- 0x37, 0xea, 0xf0, 0xfd, 0xcd, 0x68, 0x93, 0xca, 0x65, 0x22, 0x9b, 0xe1,
- 0x13, 0x71, 0xdc, 0x20, 0xd2, 0xb5, 0xa3, 0x59, 0xe7, 0x90, 0xca, 0x29,
- 0xea, 0xf3, 0xb0, 0xed, 0xdd, 0x3a, 0x47, 0x03, 0x7e, 0x7b, 0x6e, 0x24,
- 0x42, 0xf9, 0xd5, 0x2b, 0xc3, 0xd4, 0x27, 0xa7, 0x6e, 0xd6, 0xb4, 0xdf,
- 0xbd, 0x8d, 0x67, 0x99, 0xfa, 0x8c, 0x8d, 0x1e, 0x27, 0x8c, 0xa3, 0x28,
- 0x87, 0xfd, 0xfe, 0x9a, 0x30, 0xdc, 0xf5, 0x26, 0x61, 0xb8, 0xeb, 0x4d,
- 0xc2, 0x40, 0x5c, 0x00, 0x8e, 0xca, 0x5f, 0x6c, 0x08, 0x63, 0xd5, 0x97,
- 0x62, 0x1e, 0x07, 0x8b, 0x77, 0xc9, 0xa1, 0xa2, 0xa3, 0xe3, 0x8e, 0x0b,
- 0x8a, 0x32, 0xc1, 0x05, 0x4f, 0x82, 0xf7, 0x8a, 0xe0, 0xcd, 0x22, 0x78,
- 0xb1, 0x08, 0xbe, 0x84, 0xfd, 0x7f, 0x06, 0xf6, 0xff, 0x93, 0x58, 0x9b,
- 0xd3, 0x2b, 0x78, 0x39, 0xad, 0x79, 0x39, 0x5f, 0xa4, 0xaf, 0xd6, 0x7f,
- 0x11, 0x7e, 0x8d, 0xca, 0x70, 0x21, 0x05, 0x55, 0xe2, 0x44, 0xb3, 0xfd,
- 0x9f, 0x24, 0xbf, 0xca, 0x83, 0xfe, 0x0d, 0x68, 0x73, 0x18, 0x34, 0x9e,
- 0xa2, 0x1d, 0x48, 0xfb, 0x27, 0x07, 0xde, 0x3c, 0x4c, 0x5f, 0x4d, 0x5d,
- 0xb9, 0x49, 0xa8, 0x5f, 0xa2, 0x3b, 0x98, 0x7b, 0xc8, 0xb9, 0x26, 0x57,
- 0xe1, 0xc9, 0xf0, 0xef, 0x84, 0x47, 0x3d, 0x43, 0xbe, 0x7d, 0x99, 0x7c,
- 0x5b, 0xc3, 0xab, 0x01, 0xe7, 0x17, 0xb8, 0xdb, 0xea, 0xb5, 0xad, 0xd6,
- 0xdf, 0xb4, 0x5c, 0x5f, 0x8f, 0x5f, 0x22, 0x3f, 0x42, 0x27, 0x11, 0xf7,
- 0xc9, 0x4c, 0x64, 0x8b, 0xc5, 0x3d, 0x6c, 0xb7, 0x1d, 0x97, 0x00, 0xf7,
- 0x9d, 0x92, 0x9b, 0x0f, 0xc4, 0xdb, 0x11, 0xf6, 0x59, 0xed, 0xc7, 0xb5,
- 0xfd, 0x8c, 0x17, 0x1c, 0x19, 0xd9, 0xc6, 0x7d, 0x08, 0x07, 0x7a, 0x3e,
- 0x5c, 0x0f, 0xd8, 0xfb, 0x7a, 0xcd, 0x29, 0x63, 0x29, 0x5b, 0x5b, 0x6c,
- 0xfc, 0x89, 0xfd, 0x1d, 0x5e, 0xb5, 0x4e, 0x17, 0x02, 0x9e, 0x11, 0x9b,
- 0xf2, 0x6e, 0xa8, 0xa1, 0x95, 0xfb, 0x2c, 0xad, 0xa8, 0x55, 0xf3, 0xb8,
- 0xdd, 0xd2, 0x4a, 0x08, 0x6f, 0x3c, 0xa4, 0x95, 0xa6, 0x90, 0x56, 0x72,
- 0x33, 0x21, 0xad, 0xb0, 0xed, 0xed, 0x21, 0xad, 0x24, 0x6b, 0x69, 0x25,
- 0x37, 0xe3, 0xe0, 0x5a, 0x0d, 0x07, 0xe9, 0x85, 0xfd, 0x90, 0x5e, 0x00,
- 0x4b, 0xe5, 0xd6, 0xd6, 0x90, 0x5e, 0xe2, 0xe8, 0xe7, 0x50, 0xd1, 0xe4,
- 0x74, 0xc0, 0xef, 0xb2, 0x3a, 0xc4, 0xc5, 0x9a, 0x1b, 0x1f, 0xb1, 0x3e,
- 0x8d, 0xf8, 0x96, 0x46, 0xaa, 0x79, 0xee, 0xab, 0x68, 0x03, 0xb8, 0x67,
- 0x2e, 0xeb, 0x76, 0x4d, 0x1b, 0xf7, 0xfb, 0x53, 0xa8, 0xbb, 0x07, 0xb4,
- 0x11, 0xe2, 0xe0, 0x7a, 0x8b, 0x83, 0xd5, 0x6b, 0x39, 0x66, 0x71, 0xb0,
- 0xc7, 0xe2, 0x40, 0xf3, 0x4b, 0x8e, 0x6b, 0xa6, 0x34, 0x0e, 0x9a, 0x34,
- 0x0e, 0x44, 0x85, 0x6d, 0xc7, 0xea, 0xe0, 0x80, 0x75, 0xf6, 0xe8, 0xf9,
- 0x47, 0x30, 0xff, 0xfd, 0x98, 0xbf, 0xd2, 0xf3, 0xe7, 0x3a, 0x70, 0xfe,
- 0x80, 0xa5, 0x72, 0x72, 0x79, 0xfe, 0x6d, 0xe8, 0xe3, 0x60, 0x31, 0xa2,
- 0xe7, 0x0f, 0xdb, 0x7e, 0x30, 0x9c, 0xff, 0xe9, 0x8a, 0xc9, 0x7f, 0x3e,
- 0xbd, 0x46, 0xcf, 0x4d, 0x59, 0xde, 0xf0, 0xb4, 0x5f, 0xcc, 0x98, 0xf6,
- 0x19, 0xe8, 0xb6, 0x69, 0x3f, 0x69, 0xcf, 0x43, 0x19, 0x7b, 0xe9, 0x1b,
- 0x3e, 0x79, 0xe7, 0xe3, 0x3a, 0x0f, 0xe5, 0x71, 0xda, 0x4d, 0xc5, 0x36,
- 0x19, 0x99, 0xae, 0x85, 0x9b, 0xf0, 0xe6, 0xb4, 0x1c, 0xcd, 0x62, 0x7e,
- 0xe3, 0x7e, 0x2f, 0xe4, 0x9b, 0xa6, 0x25, 0x94, 0xa7, 0x72, 0xc3, 0x91,
- 0x26, 0x51, 0x0f, 0x7c, 0x08, 0x73, 0x8e, 0xca, 0x66, 0xaf, 0xdb, 0xdd,
- 0xa1, 0xa8, 0x0b, 0x2f, 0xab, 0xd1, 0x85, 0xed, 0x56, 0x17, 0x6e, 0xa2,
- 0x2e, 0x04, 0xdc, 0x77, 0xca, 0xe1, 0x22, 0xd7, 0x2f, 0x97, 0x6c, 0x82,
- 0xfe, 0xff, 0x81, 0xc7, 0xb3, 0x27, 0x3a, 0x6e, 0x96, 0x38, 0xac, 0x69,
- 0x99, 0x3a, 0x2d, 0xa5, 0xcf, 0x6a, 0x2c, 0xd2, 0xc6, 0x8e, 0x33, 0x16,
- 0x4a, 0xbd, 0xf7, 0xe3, 0xe0, 0x73, 0x75, 0xf4, 0xde, 0x64, 0xd1, 0xd8,
- 0x6f, 0x0d, 0xb0, 0x09, 0xe5, 0x44, 0x3b, 0xae, 0x8d, 0x3c, 0xab, 0xd0,
- 0xdb, 0xa3, 0x9a, 0xa5, 0xe1, 0x44, 0xab, 0x4c, 0x4c, 0x1b, 0x1b, 0x57,
- 0x9d, 0x00, 0xfe, 0x4f, 0x30, 0xdf, 0x55, 0x74, 0x7e, 0x7e, 0xb6, 0x04,
- 0x3b, 0x77, 0xf6, 0x4e, 0x93, 0xb7, 0x32, 0xdd, 0xa0, 0x7f, 0xd3, 0x06,
- 0xc9, 0xfb, 0x69, 0xe8, 0xbb, 0x98, 0x4c, 0xa0, 0xcf, 0xee, 0x6d, 0x8d,
- 0x98, 0x73, 0x1c, 0x6d, 0xe9, 0xf3, 0x31, 0x8e, 0xd6, 0x28, 0xd1, 0xd9,
- 0xb8, 0xce, 0xad, 0xe7, 0xd9, 0xd1, 0xcc, 0x60, 0x1b, 0xde, 0x31, 0x9f,
- 0xc1, 0xc5, 0x58, 0xa1, 0xec, 0x47, 0xbf, 0x47, 0xc5, 0xee, 0xf7, 0x0c,
- 0x69, 0xfd, 0x17, 0x39, 0xea, 0xda, 0x33, 0x74, 0x83, 0x58, 0xf7, 0x7a,
- 0x7a, 0xd1, 0x18, 0xb9, 0x19, 0xac, 0x9f, 0x3a, 0x15, 0xc5, 0xbd, 0x13,
- 0xf7, 0xb0, 0xbf, 0x50, 0x8f, 0x40, 0x37, 0xbe, 0xb3, 0x6f, 0xa3, 0x34,
- 0x03, 0xdf, 0xb3, 0x0a, 0xb8, 0x36, 0x39, 0x59, 0x39, 0xcd, 0x0b, 0x55,
- 0x7a, 0x78, 0xf2, 0x75, 0xf9, 0x81, 0x34, 0x41, 0x5a, 0xa0, 0x5c, 0x24,
- 0x6d, 0x50, 0x26, 0x3a, 0xfa, 0x6c, 0x03, 0xe9, 0xe1, 0x09, 0xdf, 0x8b,
- 0x70, 0xdf, 0xde, 0xc4, 0xe5, 0x49, 0x1b, 0xa4, 0xf9, 0xa4, 0x8e, 0xd7,
- 0xa7, 0xe5, 0x7b, 0x92, 0x6e, 0xeb, 0x86, 0x5d, 0xf6, 0x2f, 0xbb, 0xc6,
- 0xe6, 0xdc, 0xad, 0xa6, 0x39, 0xe8, 0x26, 0xe6, 0xd0, 0xf5, 0xca, 0xfb,
- 0x2a, 0x39, 0xe0, 0xe1, 0x5e, 0x28, 0xe5, 0x3b, 0x75, 0x5e, 0xe2, 0xee,
- 0xc2, 0x46, 0xb9, 0xc5, 0x8f, 0xd9, 0xb8, 0xfb, 0x41, 0xd0, 0xc1, 0xa2,
- 0x23, 0x27, 0xce, 0xe2, 0x3a, 0xe7, 0x70, 0xfd, 0xce, 0xfb, 0xe9, 0x94,
- 0x22, 0xb3, 0x7b, 0xd1, 0xc4, 0xa2, 0xf4, 0xb9, 0x13, 0xfa, 0x0c, 0xc8,
- 0x82, 0xd3, 0x74, 0xe2, 0xd0, 0x46, 0xe3, 0x4b, 0x03, 0x16, 0xaf, 0xd1,
- 0x1d, 0xa1, 0x2d, 0xe7, 0x07, 0x41, 0x96, 0x76, 0x83, 0x28, 0xed, 0x23,
- 0xc1, 0xe7, 0x43, 0x19, 0xe3, 0x13, 0x5b, 0x9d, 0xc6, 0x53, 0x2f, 0x5a,
- 0x5a, 0x91, 0x88, 0x1a, 0x7a, 0xc6, 0x69, 0x38, 0x71, 0x9c, 0x6b, 0xa6,
- 0xf3, 0xa4, 0x0d, 0x5d, 0x3d, 0xe7, 0x54, 0xe9, 0xea, 0x1b, 0xf6, 0xb7,
- 0x1a, 0x6a, 0x92, 0x74, 0xaa, 0x09, 0xf3, 0x1d, 0x2e, 0x84, 0x30, 0x7e,
- 0x1f, 0x70, 0x11, 0x1e, 0xd0, 0xed, 0xec, 0x9f, 0xe1, 0x5a, 0x02, 0x2c,
- 0xf7, 0x01, 0xee, 0xf3, 0x80, 0xf9, 0x02, 0x2e, 0xd5, 0x11, 0x91, 0x3f,
- 0x76, 0x22, 0xb3, 0xb5, 0xf0, 0x12, 0xc6, 0xd3, 0x16, 0xde, 0xd7, 0x82,
- 0xd5, 0x95, 0xc5, 0x81, 0x2e, 0xc0, 0x43, 0x38, 0x5f, 0x02, 0x8c, 0xb4,
- 0x5b, 0x9f, 0xc7, 0xb3, 0x0b, 0xf8, 0x5e, 0xb0, 0x30, 0x81, 0x1e, 0xa7,
- 0xff, 0x47, 0xf5, 0x77, 0x81, 0x76, 0xf4, 0x9f, 0xdb, 0xe7, 0xce, 0x55,
- 0x32, 0xa0, 0xc7, 0x21, 0x9e, 0xa7, 0x8a, 0x4b, 0xb4, 0x03, 0xc0, 0xf7,
- 0x3f, 0x94, 0xc8, 0xa9, 0x84, 0x1c, 0x2a, 0x70, 0x0f, 0xe8, 0x24, 0xf0,
- 0xa1, 0xcf, 0xa4, 0xa0, 0xce, 0x15, 0xb8, 0xa0, 0xec, 0x67, 0xb7, 0xe3,
- 0xea, 0xc5, 0xf5, 0x56, 0x5c, 0x20, 0x87, 0xd9, 0x13, 0xb8, 0xfa, 0xd0,
- 0xb7, 0x8a, 0x37, 0x09, 0x73, 0xa9, 0xbe, 0x8d, 0x36, 0xda, 0xb6, 0xcc,
- 0xa9, 0xa1, 0x01, 0xe0, 0x6f, 0x00, 0xb0, 0x25, 0x70, 0x31, 0xff, 0xf8,
- 0x87, 0x8e, 0x9c, 0x7a, 0x19, 0x17, 0x18, 0xec, 0x14, 0x08, 0xf3, 0xd4,
- 0x20, 0x2e, 0x28, 0xb1, 0x53, 0x69, 0x5c, 0x23, 0xb8, 0xfe, 0xd2, 0x31,
- 0x3c, 0xd7, 0x09, 0x7c, 0x85, 0x3c, 0x02, 0x9c, 0xaf, 0xe0, 0xb9, 0xaf,
- 0x3b, 0x6f, 0x9c, 0xe7, 0x7e, 0xe2, 0x18, 0x9e, 0x7b, 0xc5, 0xa9, 0xf2,
- 0xdc, 0x59, 0x47, 0x3d, 0xfc, 0x8c, 0x13, 0x79, 0x98, 0xbe, 0xc4, 0x59,
- 0xc7, 0xf0, 0x7f, 0x44, 0x86, 0xf7, 0x82, 0x96, 0x1e, 0x5e, 0xc0, 0x45,
- 0xba, 0x7a, 0x16, 0xe5, 0x2f, 0xac, 0x1a, 0xf7, 0xf9, 0x37, 0x31, 0xee,
- 0xab, 0x76, 0x5c, 0x51, 0xd5, 0x71, 0x2f, 0xa0, 0xef, 0x97, 0xec, 0xb8,
- 0x17, 0x6a, 0xc6, 0x05, 0xad, 0x3c, 0xbc, 0x84, 0x8b, 0x74, 0xf1, 0x22,
- 0xca, 0x43, 0x99, 0x80, 0x85, 0x6e, 0x6e, 0xd0, 0x67, 0x9d, 0xe2, 0x5e,
- 0xc3, 0xb2, 0x6e, 0x4c, 0xd7, 0xe8, 0x87, 0x37, 0xa2, 0x1f, 0x27, 0x8b,
- 0xb4, 0x11, 0x17, 0x6a, 0xe4, 0x02, 0x7d, 0xa3, 0x40, 0x8e, 0x69, 0x3f,
- 0x88, 0x3e, 0x11, 0xfd, 0xa3, 0xd5, 0xb6, 0xd5, 0x27, 0x75, 0xee, 0xd8,
- 0xaf, 0x15, 0x3a, 0xe5, 0xd3, 0x05, 0xda, 0x84, 0xa4, 0x97, 0x20, 0x98,
- 0xd8, 0x41, 0xfb, 0x34, 0x17, 0x5c, 0xe2, 0x91, 0x4e, 0x3c, 0xf7, 0x33,
- 0x6b, 0x75, 0x46, 0x69, 0x18, 0xbe, 0x7b, 0xe6, 0xe8, 0xaf, 0x40, 0x67,
- 0x34, 0x00, 0x6e, 0xd2, 0x5b, 0x87, 0xdc, 0x58, 0x52, 0x53, 0x9b, 0x25,
- 0x21, 0x37, 0x15, 0x1a, 0x61, 0xf7, 0x30, 0xaf, 0xaa, 0x59, 0xba, 0x77,
- 0xc4, 0x4c, 0xde, 0xb7, 0x1b, 0xc7, 0x6f, 0xd7, 0xe4, 0xa1, 0xc7, 0x13,
- 0x78, 0xff, 0x7b, 0x2e, 0xe5, 0x60, 0xdc, 0xbb, 0x56, 0xe7, 0xf4, 0x74,
- 0xed, 0xa0, 0xdd, 0x72, 0xbd, 0xd6, 0xe1, 0xd1, 0x35, 0x76, 0x92, 0xea,
- 0x70, 0xa5, 0x6a, 0xa3, 0x8d, 0x17, 0x52, 0x49, 0xc2, 0xf5, 0x90, 0x70,
- 0xff, 0xeb, 0x1e, 0xc9, 0xfb, 0xad, 0xf0, 0x0b, 0x18, 0x3b, 0x4f, 0xf5,
- 0xd2, 0x36, 0x9a, 0x9d, 0x76, 0x6d, 0x5e, 0xf4, 0x46, 0x79, 0x4e, 0x8f,
- 0xd3, 0xa8, 0x61, 0x34, 0x67, 0x25, 0xb8, 0x8f, 0x10, 0xd3, 0xe7, 0x73,
- 0x66, 0xcb, 0x2d, 0x5a, 0xef, 0xcc, 0x96, 0x99, 0x87, 0x0f, 0x7f, 0xaa,
- 0xcc, 0xbc, 0x7b, 0x5f, 0xdc, 0x77, 0xc2, 0xcf, 0x2d, 0x6f, 0x91, 0xf1,
- 0xe9, 0x75, 0xd2, 0xe8, 0xa9, 0xf8, 0x66, 0xc8, 0x47, 0xb6, 0xe9, 0xda,
- 0x01, 0xff, 0x70, 0x66, 0xab, 0x3c, 0x39, 0xc3, 0xbe, 0x3b, 0x64, 0x6e,
- 0x5e, 0x1c, 0xf7, 0x9d, 0xeb, 0x51, 0x07, 0x72, 0x7d, 0x07, 0xcb, 0x92,
- 0xb8, 0x8b, 0x72, 0xdf, 0x19, 0x95, 0x73, 0x03, 0x7c, 0x66, 0xee, 0xbf,
- 0x44, 0xd9, 0xdf, 0xb9, 0x81, 0x4e, 0x79, 0x7c, 0x1e, 0x34, 0x01, 0xb9,
- 0x3f, 0x72, 0x82, 0x30, 0x89, 0xec, 0x9a, 0x65, 0x2c, 0xbd, 0xdb, 0x65,
- 0xdc, 0x94, 0xfb, 0x34, 0xb7, 0x0c, 0x70, 0x2c, 0xe8, 0x25, 0xe8, 0xb8,
- 0xae, 0x1d, 0x46, 0x16, 0xa4, 0x67, 0x1b, 0x50, 0xce, 0x7e, 0xe1, 0x3f,
- 0xee, 0x65, 0x3f, 0x61, 0x5b, 0x85, 0x39, 0x35, 0x6a, 0x7a, 0x59, 0x5a,
- 0xa5, 0x3f, 0xce, 0xfc, 0x4c, 0xf6, 0x37, 0xfb, 0xe8, 0xd5, 0x7b, 0x21,
- 0xdc, 0x53, 0x36, 0xb6, 0x15, 0xd7, 0x44, 0xef, 0x29, 0xc0, 0xae, 0xba,
- 0x42, 0xdb, 0x17, 0x73, 0x15, 0xae, 0x20, 0x63, 0x51, 0xe1, 0x1a, 0x25,
- 0xe4, 0xd1, 0xe2, 0xf2, 0x3a, 0x6d, 0x69, 0x58, 0xb9, 0x4e, 0xa4, 0x15,
- 0x7f, 0xcc, 0xda, 0x1e, 0x8b, 0x92, 0x83, 0x5d, 0xd6, 0xab, 0xd7, 0x6c,
- 0x11, 0xb6, 0xac, 0x5d, 0x33, 0x6d, 0xcf, 0xe6, 0xc3, 0x35, 0x1b, 0x85,
- 0xc6, 0x29, 0xab, 0x4d, 0x5c, 0x33, 0x97, 0xf1, 0x6e, 0xe0, 0x3d, 0x87,
- 0x75, 0xca, 0x61, 0x8d, 0x72, 0xe5, 0x0e, 0x99, 0x3d, 0xa6, 0x3a, 0x1b,
- 0x44, 0x92, 0xe3, 0x5e, 0x87, 0x4c, 0xce, 0x33, 0x96, 0xb0, 0x05, 0x36,
- 0xd8, 0x56, 0x5c, 0x9d, 0x78, 0x66, 0x3b, 0xf0, 0x54, 0x59, 0xa1, 0x6d,
- 0xd3, 0x1a, 0x3b, 0xeb, 0x71, 0x8c, 0xcd, 0x1c, 0xe1, 0x27, 0x80, 0x87,
- 0x2a, 0xef, 0x4c, 0xd5, 0xc4, 0x9f, 0x38, 0x57, 0xad, 0x43, 0x31, 0xdf,
- 0xb8, 0x5e, 0x4f, 0x1d, 0x87, 0x2a, 0x36, 0xbe, 0x19, 0x7b, 0x2a, 0x41,
- 0x7b, 0x2a, 0x5b, 0x72, 0xcd, 0xf9, 0x80, 0x51, 0xf8, 0x4e, 0x5e, 0xef,
- 0x26, 0xd2, 0xfa, 0xd8, 0x0c, 0xe1, 0x8a, 0x85, 0x70, 0xad, 0x58, 0x33,
- 0x9e, 0xe7, 0x5a, 0x1b, 0xe7, 0x98, 0x5a, 0xce, 0x5f, 0x34, 0xb1, 0x7d,
- 0xc6, 0x51, 0x3a, 0xeb, 0xc0, 0x74, 0xa7, 0xb6, 0x61, 0x45, 0x8d, 0xc9,
- 0x81, 0x22, 0xcf, 0x82, 0x31, 0x9e, 0x78, 0x23, 0xe3, 0x49, 0xbd, 0xb3,
- 0xf2, 0x5e, 0x8c, 0xcd, 0x5c, 0x1d, 0x65, 0xe3, 0x37, 0x1b, 0x6c, 0x8e,
- 0x48, 0x6d, 0x0c, 0xc7, 0xe4, 0xf2, 0xac, 0xcc, 0x8b, 0x4e, 0x8d, 0x2e,
- 0x61, 0x9d, 0x7f, 0x5d, 0xef, 0x0d, 0x4a, 0x29, 0x02, 0xed, 0x37, 0x3e,
- 0x90, 0x1a, 0x34, 0xe7, 0x60, 0x92, 0xb2, 0xb3, 0x68, 0xe6, 0x7f, 0x5e,
- 0xe7, 0xf4, 0x98, 0xdc, 0x45, 0x93, 0xef, 0x73, 0x8f, 0x9c, 0x87, 0x0e,
- 0xaf, 0xae, 0x6d, 0x93, 0x4c, 0x02, 0x17, 0x59, 0xbd, 0x2f, 0x91, 0x94,
- 0xec, 0xc0, 0xc7, 0x37, 0xf1, 0x9c, 0x44, 0x0c, 0xeb, 0x93, 0x9f, 0xe1,
- 0xd9, 0x49, 0xf6, 0x7b, 0xb1, 0xbe, 0x28, 0x66, 0x99, 0x87, 0x0f, 0x59,
- 0xf9, 0xb6, 0xbe, 0x44, 0xb3, 0x7e, 0xbf, 0xce, 0xe6, 0x5b, 0x3b, 0x22,
- 0x37, 0x06, 0xf2, 0x87, 0x10, 0x9f, 0x8f, 0xd9, 0x39, 0x25, 0x75, 0xcc,
- 0x4a, 0x82, 0x73, 0x7e, 0xc2, 0xc6, 0x2c, 0x39, 0x97, 0x1b, 0x2c, 0x7d,
- 0x1b, 0xfb, 0xa7, 0x6a, 0x43, 0x9b, 0x7d, 0xbf, 0x27, 0xb5, 0x2c, 0xec,
- 0xb7, 0xb6, 0xb3, 0x8e, 0xf3, 0x1c, 0x17, 0x9d, 0x13, 0x10, 0xfa, 0x46,
- 0x3d, 0x35, 0x7e, 0x81, 0xf1, 0xe5, 0xf2, 0xd3, 0xf5, 0x64, 0x54, 0xd5,
- 0x27, 0xa4, 0x2f, 0x37, 0xb1, 0x8d, 0xdf, 0x2d, 0x08, 0x7d, 0xb9, 0x7e,
- 0xeb, 0xcb, 0xb5, 0x6a, 0x5f, 0xce, 0xc4, 0x1e, 0x5a, 0x97, 0x7d, 0xb9,
- 0xfc, 0x74, 0x0e, 0xb4, 0x12, 0x7e, 0x67, 0xc1, 0xd8, 0x42, 0x93, 0x05,
- 0x9e, 0x79, 0x69, 0x94, 0xec, 0xa8, 0x82, 0xdf, 0x60, 0x7c, 0x2c, 0xc6,
- 0x2a, 0x94, 0xfa, 0x96, 0xf5, 0x2f, 0x3a, 0x25, 0xdd, 0xbe, 0x0e, 0xf3,
- 0xbe, 0x53, 0xaf, 0xf9, 0x5c, 0xc1, 0xec, 0x7d, 0x66, 0xf7, 0x32, 0x26,
- 0xc4, 0x73, 0x4d, 0x9a, 0xbf, 0x92, 0xc3, 0x91, 0x5e, 0x63, 0xcf, 0x7a,
- 0xdf, 0x04, 0xde, 0x4f, 0x02, 0xe7, 0x31, 0x3b, 0x6e, 0x12, 0x30, 0x1d,
- 0xc0, 0xda, 0x5c, 0x6b, 0x65, 0x32, 0xc7, 0xde, 0xd3, 0xc4, 0xd8, 0xc0,
- 0x7c, 0x21, 0x8c, 0x11, 0x46, 0xec, 0x99, 0x4a, 0x2f, 0xd2, 0xe8, 0xad,
- 0xab, 0x6b, 0xab, 0x9e, 0x7e, 0x5d, 0xdd, 0x44, 0x5a, 0xba, 0x53, 0xe7,
- 0xb9, 0xac, 0x1f, 0x48, 0xed, 0xd1, 0x39, 0xf2, 0x3a, 0xc6, 0x98, 0x13,
- 0xe6, 0x94, 0x7d, 0x57, 0xde, 0xa1, 0x65, 0xfe, 0x01, 0x9f, 0xfa, 0x6b,
- 0x87, 0xfe, 0xdd, 0x38, 0x14, 0x04, 0xe7, 0x06, 0xee, 0x86, 0xad, 0xe2,
- 0xb9, 0xdf, 0x97, 0xee, 0xc4, 0xb0, 0xb6, 0x9d, 0xb0, 0x46, 0x7b, 0x9b,
- 0x65, 0x9d, 0x77, 0xb3, 0xcd, 0x99, 0xc9, 0x41, 0x6e, 0xa6, 0x60, 0x33,
- 0xf1, 0x4c, 0x70, 0x8f, 0x7d, 0x97, 0x0b, 0x9a, 0x41, 0x47, 0x1f, 0x13,
- 0x23, 0x63, 0xb2, 0x55, 0x19, 0xc3, 0x5c, 0x83, 0x34, 0x09, 0x39, 0x7a,
- 0x44, 0x52, 0xfc, 0xee, 0x07, 0xc7, 0xce, 0xcb, 0xa5, 0xd0, 0xcb, 0x6c,
- 0xa7, 0xbf, 0xd9, 0x83, 0x67, 0xee, 0xe1, 0x78, 0xee, 0x41, 0xe8, 0x96,
- 0xeb, 0xd7, 0xea, 0x96, 0x04, 0xfd, 0xfa, 0x6c, 0x89, 0xbe, 0xe1, 0x7a,
- 0xb4, 0xe9, 0x90, 0x8f, 0x4f, 0x77, 0xb7, 0x91, 0xb7, 0xc6, 0x20, 0xd7,
- 0xd5, 0xfd, 0xe1, 0x59, 0x20, 0x96, 0xf1, 0x3d, 0xfb, 0x6d, 0x92, 0xe4,
- 0xfb, 0x5d, 0xf9, 0x7c, 0x25, 0x95, 0x5c, 0x82, 0x6e, 0x1a, 0x73, 0x7e,
- 0xf1, 0x72, 0x13, 0x53, 0x7d, 0x7b, 0x9b, 0x39, 0x3b, 0xd0, 0x4c, 0x9b,
- 0xdd, 0xc6, 0x59, 0x6b, 0x69, 0x76, 0xc9, 0xca, 0xe3, 0x20, 0x68, 0x1e,
- 0xd0, 0x32, 0x78, 0x0f, 0x65, 0xf0, 0x01, 0xbf, 0xc7, 0xd0, 0xbe, 0xf6,
- 0x99, 0x02, 0xac, 0x23, 0xf0, 0x30, 0x10, 0x65, 0x7e, 0x9e, 0xe5, 0x4f,
- 0x2f, 0xbd, 0x68, 0xe5, 0x92, 0x72, 0xd6, 0xf2, 0xa5, 0xba, 0x2a, 0xb6,
- 0x42, 0xe6, 0x1e, 0x9a, 0xa6, 0x3e, 0xf6, 0x17, 0xbe, 0x0b, 0x39, 0x95,
- 0xd5, 0x78, 0xe8, 0x90, 0xfb, 0xa6, 0x25, 0x7d, 0x1e, 0xba, 0x2a, 0x3f,
- 0xbf, 0x92, 0x37, 0xd7, 0xf6, 0xc7, 0xb9, 0x7e, 0xb8, 0xcd, 0xf8, 0xb6,
- 0x2b, 0xe7, 0xba, 0x80, 0xb9, 0xa6, 0xf5, 0x5c, 0xb9, 0x6f, 0xf3, 0x31,
- 0x3b, 0xd7, 0xf5, 0xe1, 0x5c, 0x07, 0x57, 0xce, 0x35, 0xf4, 0xed, 0x43,
- 0xb9, 0x9b, 0xd4, 0xf9, 0xf2, 0x3a, 0x4f, 0x7b, 0x7a, 0xbd, 0x0c, 0x97,
- 0x5a, 0xad, 0xbc, 0x74, 0xa1, 0x7b, 0x98, 0xc3, 0xbe, 0x70, 0xaf, 0x2b,
- 0x16, 0x67, 0x8a, 0x78, 0xa0, 0xac, 0x6d, 0xd3, 0x67, 0x6c, 0x66, 0xe1,
- 0x5f, 0xdd, 0x5a, 0x60, 0xdd, 0xf0, 0xfd, 0xc5, 0x62, 0xc7, 0xa1, 0x4f,
- 0x4d, 0xbf, 0xa9, 0x77, 0x4d, 0x4c, 0xc1, 0xc4, 0x87, 0x19, 0x17, 0x36,
- 0x67, 0x7f, 0x99, 0x8b, 0x78, 0x07, 0x78, 0xea, 0x53, 0x85, 0xd4, 0x60,
- 0x26, 0x42, 0x39, 0x7a, 0x5c, 0x0e, 0x55, 0x46, 0xa4, 0x4b, 0x9f, 0xff,
- 0x7c, 0xdd, 0xd8, 0x71, 0xba, 0x36, 0x76, 0xcc, 0x74, 0x02, 0xc6, 0x8e,
- 0xf7, 0xfc, 0x0c, 0xb1, 0x63, 0x71, 0x4c, 0xec, 0xb8, 0x9e, 0x7f, 0x35,
- 0x55, 0x3c, 0x8e, 0x79, 0x35, 0x43, 0x96, 0x2c, 0x3a, 0xd9, 0xf9, 0x16,
- 0xdc, 0xcf, 0xe2, 0x1e, 0xc3, 0xfd, 0x3c, 0xee, 0x2e, 0xee, 0x17, 0x70,
- 0x8f, 0xcb, 0xd4, 0xb2, 0xce, 0x38, 0x0e, 0xb9, 0x41, 0x5d, 0xc6, 0xb6,
- 0xc6, 0x1f, 0x98, 0x2b, 0xb7, 0xf3, 0x7b, 0x2d, 0xce, 0xec, 0x3c, 0xe7,
- 0xd0, 0x2a, 0x93, 0xd3, 0x94, 0xd9, 0x6d, 0x52, 0x9a, 0x0e, 0x6d, 0xdb,
- 0x9f, 0xef, 0xe0, 0x9e, 0xc1, 0x98, 0x84, 0xb6, 0xeb, 0x3d, 0x1d, 0x66,
- 0xaf, 0xf1, 0x3b, 0x58, 0xe3, 0x8d, 0x58, 0x83, 0x93, 0x72, 0x7e, 0x66,
- 0xe3, 0x0a, 0x1b, 0x36, 0x69, 0x63, 0x82, 0x33, 0x56, 0xf7, 0xd6, 0x97,
- 0x11, 0xb5, 0xeb, 0x9f, 0xb0, 0x67, 0xcb, 0xc2, 0x1c, 0xa1, 0xa4, 0x5e,
- 0x9f, 0xd1, 0xca, 0x71, 0x8c, 0x37, 0x28, 0xe9, 0x19, 0xce, 0x73, 0xf9,
- 0x9b, 0x11, 0x90, 0x87, 0x27, 0xa0, 0x57, 0x57, 0xd0, 0x25, 0xe8, 0x96,
- 0x73, 0x73, 0x40, 0xbb, 0x8f, 0xca, 0x6c, 0x89, 0xf0, 0xf5, 0x24, 0x22,
- 0xfa, 0xac, 0x19, 0x9e, 0x67, 0x4c, 0x8e, 0xfb, 0x70, 0x25, 0x3c, 0x67,
- 0xb6, 0x89, 0x67, 0x07, 0x57, 0x9d, 0x35, 0xb3, 0xfa, 0x59, 0xdb, 0x0e,
- 0x3c, 0x73, 0x16, 0xce, 0xa1, 0x1e, 0x3d, 0x05, 0x32, 0xa9, 0xf3, 0xce,
- 0x36, 0xcb, 0x63, 0x0f, 0x2e, 0xe7, 0xbc, 0xb6, 0xc1, 0x46, 0xe9, 0x84,
- 0x89, 0x3c, 0x1a, 0x1d, 0xea, 0x81, 0x8f, 0xc7, 0x3c, 0x99, 0x9e, 0xc4,
- 0x6d, 0x3a, 0x17, 0xb9, 0x7a, 0xee, 0xaf, 0x9a, 0x8f, 0x1c, 0x9e, 0xb3,
- 0x4a, 0xe8, 0xef, 0x5a, 0xec, 0xd4, 0xe5, 0x71, 0xcc, 0x87, 0xfb, 0x7e,
- 0x1a, 0x0f, 0x09, 0x7e, 0xa7, 0xeb, 0x29, 0xe0, 0x60, 0xb2, 0xf2, 0x6d,
- 0xd0, 0xbb, 0x63, 0xcf, 0x9c, 0x91, 0xc6, 0x06, 0x64, 0xa2, 0x9c, 0x70,
- 0x26, 0xca, 0x03, 0xce, 0xbe, 0xb2, 0x7d, 0x37, 0xb0, 0x67, 0xb3, 0x34,
- 0xe3, 0xf7, 0x4c, 0x97, 0x33, 0x06, 0x7c, 0xe5, 0x8b, 0xdd, 0x4e, 0x5a,
- 0xdf, 0x3d, 0x7b, 0x87, 0x1c, 0xc0, 0x5a, 0x0d, 0xcf, 0xc4, 0xb5, 0x9c,
- 0xaf, 0x7e, 0x5b, 0x2a, 0x5c, 0x57, 0x7e, 0x13, 0x89, 0x7c, 0x7c, 0x5c,
- 0x7f, 0xe7, 0xc8, 0xd8, 0x0e, 0x27, 0xd1, 0xdf, 0x71, 0x1b, 0x13, 0xef,
- 0x73, 0xb2, 0xba, 0x1f, 0xb3, 0x1e, 0xf9, 0xe2, 0x09, 0xdc, 0x57, 0x9f,
- 0x79, 0x0e, 0xf5, 0x8c, 0x85, 0xbb, 0x10, 0xdc, 0x63, 0xe4, 0xd5, 0x71,
- 0x99, 0xaa, 0x30, 0x7f, 0xc4, 0xd1, 0x7c, 0x34, 0x59, 0x3e, 0x00, 0x9d,
- 0xb4, 0xf2, 0xcc, 0xdf, 0xce, 0xea, 0x3a, 0x24, 0x67, 0x84, 0xb0, 0x70,
- 0x0d, 0x56, 0x9e, 0x87, 0xbf, 0xf8, 0xbf, 0x70, 0x5f, 0xd1, 0xc8, 0x50,
- 0x0b, 0x47, 0x9a, 0xf2, 0xce, 0xc8, 0x95, 0x69, 0x39, 0x08, 0x78, 0x0e,
- 0xe3, 0x52, 0xf7, 0xf3, 0x3b, 0x2c, 0xf3, 0x92, 0x9f, 0xbb, 0x4f, 0xd4,
- 0x43, 0xe7, 0x9d, 0xe8, 0x43, 0x07, 0x25, 0xf2, 0xd0, 0xa2, 0xd3, 0xf0,
- 0x50, 0xb7, 0xf6, 0xcb, 0x77, 0xfb, 0xdd, 0x89, 0x7d, 0x72, 0x52, 0xa2,
- 0xf7, 0x2b, 0x7d, 0xfe, 0x2b, 0xef, 0x32, 0xc6, 0x77, 0x52, 0x22, 0xf7,
- 0xc7, 0xec, 0xd9, 0x51, 0x13, 0xd7, 0x5b, 0xd2, 0x7c, 0xff, 0x9b, 0x71,
- 0xe2, 0x6c, 0x49, 0x8e, 0x6b, 0xde, 0x19, 0x86, 0x9e, 0xc8, 0x94, 0x92,
- 0xcb, 0x75, 0x4c, 0xbe, 0xe7, 0xf3, 0x9b, 0x0d, 0xbf, 0xb0, 0x4e, 0x8f,
- 0xc3, 0xef, 0x38, 0x18, 0x9d, 0x91, 0xb9, 0x2c, 0xcc, 0xfd, 0x34, 0x6b,
- 0xca, 0xf7, 0x67, 0xb1, 0x86, 0x3d, 0x58, 0x2f, 0x8e, 0xe7, 0xe8, 0xfd,
- 0x5c, 0x9e, 0x9d, 0x75, 0xa5, 0x2f, 0xd1, 0xb4, 0x6c, 0x07, 0xb1, 0xee,
- 0x7d, 0xd2, 0x04, 0xb8, 0xd5, 0x43, 0x79, 0x63, 0xd7, 0x09, 0xe9, 0x54,
- 0x20, 0xb9, 0x49, 0xb3, 0x3d, 0x83, 0xbb, 0xf5, 0x1a, 0xde, 0x6b, 0x69,
- 0x66, 0x9d, 0xb1, 0x1f, 0xf1, 0x6c, 0xe8, 0x22, 0x2f, 0xbb, 0xa6, 0x7f,
- 0x08, 0x3d, 0xcf, 0x7d, 0x17, 0x6d, 0x2f, 0xd6, 0xb1, 0x05, 0xc9, 0x4b,
- 0xcf, 0x58, 0xbf, 0x32, 0x08, 0xa6, 0x7d, 0x1f, 0x78, 0xac, 0xe7, 0x4b,
- 0x6e, 0x71, 0xe6, 0x4a, 0x5b, 0x9d, 0xd9, 0x52, 0x20, 0x13, 0x3e, 0xbf,
- 0xe3, 0xc1, 0x1c, 0x00, 0xda, 0x5b, 0x2c, 0xeb, 0x86, 0x6e, 0xfd, 0xeb,
- 0xcd, 0x3c, 0x8f, 0x74, 0x93, 0xf7, 0xa2, 0x98, 0x7a, 0xc4, 0x31, 0x7d,
- 0xe4, 0xee, 0xe3, 0x59, 0xe1, 0xf7, 0x34, 0xfa, 0x12, 0x71, 0xfd, 0x5d,
- 0x8f, 0xcf, 0xa1, 0x1d, 0xc6, 0x28, 0x72, 0xdc, 0x67, 0x9d, 0x59, 0xc8,
- 0xb3, 0xb9, 0x69, 0x9e, 0xe1, 0x67, 0x3e, 0x6d, 0xa4, 0x53, 0xc9, 0x15,
- 0xee, 0xa4, 0xfd, 0x06, 0x5c, 0x0e, 0x2e, 0x50, 0x44, 0x97, 0xf5, 0xb9,
- 0xe3, 0xcb, 0xdf, 0x85, 0x0b, 0xcb, 0xc2, 0xef, 0xc3, 0x29, 0x9d, 0x3b,
- 0x0d, 0x5f, 0xf6, 0xb1, 0x31, 0xf9, 0x89, 0x33, 0x5f, 0x78, 0xc5, 0x79,
- 0xb4, 0x90, 0xbe, 0xea, 0x12, 0xd0, 0xc7, 0x39, 0xbf, 0x97, 0xf2, 0x0b,
- 0x36, 0x5f, 0x41, 0x72, 0x95, 0x09, 0x99, 0xe9, 0xe8, 0x76, 0xef, 0xd7,
- 0x6b, 0x33, 0x03, 0x9c, 0x7d, 0x1b, 0xeb, 0xf7, 0xc9, 0x38, 0xf5, 0xdb,
- 0x78, 0x41, 0x81, 0x97, 0xd5, 0xcf, 0xe3, 0x82, 0x6d, 0xdb, 0xa8, 0x6d,
- 0x94, 0x7d, 0x3e, 0xeb, 0x6d, 0x75, 0x86, 0x4b, 0x5b, 0xb0, 0x8e, 0x7b,
- 0xa1, 0x3f, 0x1d, 0xd8, 0x69, 0xa0, 0x6d, 0x94, 0x4d, 0x02, 0x07, 0xe3,
- 0xbe, 0x91, 0xe7, 0xc3, 0x92, 0xd3, 0x3e, 0x9e, 0xb9, 0xa7, 0x95, 0x89,
- 0x99, 0x05, 0xc1, 0x1c, 0xec, 0x83, 0x6c, 0x7f, 0x09, 0xbc, 0xf0, 0x08,
- 0xae, 0xb7, 0xdb, 0x3d, 0xed, 0x17, 0x2e, 0xb2, 0xa7, 0xed, 0xca, 0xc9,
- 0x8a, 0x3e, 0xd7, 0xae, 0xf3, 0xab, 0x92, 0xea, 0xbf, 0x5f, 0xa2, 0xd7,
- 0x4a, 0xf5, 0xe8, 0x9c, 0xb4, 0xb4, 0x7c, 0x38, 0x6e, 0xf4, 0x30, 0x61,
- 0x4a, 0x02, 0x9e, 0xad, 0xc0, 0x05, 0xe1, 0x31, 0x6d, 0x44, 0x6d, 0xba,
- 0x94, 0xfa, 0x70, 0x49, 0x3e, 0x12, 0x0f, 0xcf, 0x14, 0xa0, 0x1f, 0xc8,
- 0xb8, 0x8f, 0x5d, 0x6a, 0xf4, 0xe4, 0xe6, 0x3a, 0xfd, 0x84, 0x73, 0x73,
- 0xec, 0xdc, 0x48, 0xb7, 0x7f, 0x96, 0xa0, 0x4f, 0xb1, 0x24, 0x4d, 0xab,
- 0xea, 0x33, 0xa6, 0xbf, 0xe1, 0x72, 0x73, 0x46, 0x81, 0x75, 0x5d, 0xd8,
- 0xa6, 0xb4, 0x73, 0x89, 0x47, 0xbd, 0x6e, 0x05, 0x25, 0x3c, 0x67, 0x00,
- 0x6e, 0xae, 0x5c, 0xe1, 0xbe, 0x43, 0x91, 0x0e, 0x43, 0x5c, 0x7f, 0x5b,
- 0xf3, 0xc9, 0x78, 0x81, 0xb1, 0x95, 0x47, 0x83, 0xf4, 0x28, 0x79, 0x8c,
- 0x7d, 0xf0, 0x7d, 0x41, 0xc7, 0x73, 0xf7, 0xfa, 0x8c, 0x15, 0x75, 0x1f,
- 0xbf, 0x43, 0x85, 0x72, 0x0a, 0xfa, 0xb7, 0xb8, 0xe8, 0xf0, 0x1b, 0x78,
- 0x37, 0x0a, 0xee, 0xf3, 0x8b, 0xce, 0x77, 0xa7, 0x9f, 0xc5, 0x73, 0x83,
- 0xfd, 0xee, 0x9d, 0xd1, 0x53, 0x22, 0xc5, 0x70, 0xbe, 0x89, 0x1c, 0xd6,
- 0xfe, 0x02, 0xd6, 0xbe, 0xfe, 0x77, 0xee, 0xf0, 0xae, 0x8c, 0x77, 0xe5,
- 0x0f, 0x07, 0xe9, 0x36, 0xd2, 0x22, 0xe9, 0xef, 0xb5, 0xfc, 0xe6, 0x41,
- 0xcd, 0x17, 0x93, 0xc5, 0xc7, 0xc1, 0x17, 0x69, 0xee, 0x37, 0x07, 0x0f,
- 0xfb, 0x37, 0x80, 0x2f, 0xf6, 0xc8, 0xef, 0xc3, 0x2e, 0xf8, 0xdd, 0xca,
- 0x10, 0xf8, 0x63, 0x10, 0xfc, 0x32, 0x00, 0x1e, 0xf1, 0xb5, 0x8d, 0xfc,
- 0x04, 0xf4, 0x1f, 0xf4, 0x9a, 0xb3, 0xaf, 0xd4, 0xe5, 0x64, 0x4b, 0x9e,
- 0x33, 0x51, 0xe2, 0xf7, 0x5a, 0xd4, 0x5b, 0x1b, 0x24, 0x9a, 0x98, 0x13,
- 0xf2, 0x42, 0x37, 0x73, 0x1c, 0xdb, 0x81, 0xab, 0x53, 0xc4, 0xd5, 0x5c,
- 0xa5, 0xcf, 0xbd, 0x04, 0x3c, 0xd1, 0xae, 0x79, 0xa2, 0xd5, 0x49, 0xbb,
- 0x37, 0x58, 0x9e, 0x78, 0x11, 0x3c, 0x71, 0x7e, 0x0d, 0x4f, 0x3c, 0x6d,
- 0xe9, 0x7f, 0xa1, 0x86, 0x27, 0xe6, 0x6c, 0xd9, 0xcc, 0x45, 0x78, 0xe2,
- 0x52, 0x2f, 0xf5, 0xa5, 0x31, 0x79, 0x15, 0x3c, 0x21, 0x8a, 0x3c, 0x71,
- 0xa9, 0xe6, 0x09, 0xc6, 0x8e, 0xc8, 0x17, 0x9d, 0x90, 0x23, 0xe4, 0x8b,
- 0xb3, 0xb2, 0x04, 0xbe, 0x78, 0x5e, 0x71, 0xec, 0x19, 0xda, 0x0a, 0x25,
- 0xfa, 0x64, 0x27, 0x8a, 0x5d, 0xe0, 0x77, 0x25, 0xff, 0x65, 0x3a, 0x08,
- 0x16, 0xe1, 0xa7, 0x3f, 0x08, 0x7b, 0x3e, 0xaa, 0xbf, 0xa9, 0xb8, 0x00,
- 0xba, 0x0f, 0xe9, 0x7d, 0xc2, 0x01, 0xbd, 0x1f, 0x9e, 0xc5, 0x1c, 0x26,
- 0xd4, 0x7f, 0x86, 0x2f, 0xec, 0x62, 0x5d, 0x69, 0xe7, 0x1f, 0xd3, 0x3c,
- 0xd4, 0x00, 0x7d, 0xf0, 0xe8, 0x00, 0x63, 0x4d, 0x9e, 0xbb, 0x4f, 0x75,
- 0xe7, 0x46, 0x00, 0x73, 0x44, 0xdd, 0x2f, 0x8c, 0x73, 0xb4, 0xad, 0xb2,
- 0xf3, 0x29, 0x23, 0x46, 0x21, 0xeb, 0xcc, 0xbb, 0x5c, 0xd0, 0x04, 0x9b,
- 0xb4, 0x49, 0x19, 0x1b, 0x5d, 0xed, 0x48, 0xb9, 0x1f, 0x84, 0x00, 0x6d,
- 0x84, 0xbd, 0xb0, 0x0b, 0xab, 0x3d, 0x52, 0xa8, 0xb5, 0xf1, 0xff, 0x03,
- 0x6c, 0x7c, 0xb6, 0x91, 0xa8, 0xb1, 0xf1, 0x7f, 0xcd, 0xf2, 0x1a, 0x7f,
- 0xbb, 0xda, 0xde, 0x3f, 0x00, 0xf8, 0x76, 0x2f, 0xdb, 0xfb, 0xec, 0x83,
- 0x76, 0x87, 0xc8, 0xf5, 0xb0, 0xf9, 0xde, 0x0d, 0x1e, 0xbc, 0x01, 0xbe,
- 0xd4, 0x7b, 0x0a, 0xae, 0xec, 0x29, 0xb4, 0xc3, 0xe7, 0xee, 0x94, 0xf7,
- 0x4e, 0x6f, 0x95, 0x9d, 0x25, 0xff, 0x12, 0x69, 0xee, 0x80, 0x8d, 0x5a,
- 0x00, 0x9c, 0x11, 0x2b, 0xb7, 0xcf, 0x02, 0x6f, 0xdd, 0xc9, 0x9f, 0xa8,
- 0x17, 0xad, 0x5d, 0xc4, 0xb3, 0x8e, 0xf5, 0xfa, 0x89, 0xa3, 0x3d, 0x63,
- 0x29, 0x1d, 0x72, 0xea, 0x18, 0xbd, 0xaf, 0x24, 0xec, 0x72, 0x1f, 0x36,
- 0xc9, 0x16, 0xf4, 0xc7, 0x78, 0xf2, 0x46, 0x79, 0xfa, 0xaa, 0xe8, 0x5d,
- 0x59, 0xcd, 0x87, 0x9d, 0x4e, 0x66, 0x1a, 0x3e, 0xc0, 0xde, 0x18, 0xe6,
- 0xa0, 0xda, 0x37, 0xcb, 0x75, 0xb2, 0x53, 0xcf, 0x67, 0x46, 0x0e, 0x42,
- 0x37, 0xff, 0x41, 0x61, 0xa7, 0x2c, 0x8d, 0xb6, 0xe1, 0x39, 0x26, 0x4f,
- 0x17, 0xfa, 0xe0, 0xfb, 0xbc, 0x0b, 0x38, 0x6a, 0xc4, 0x73, 0xa3, 0x0c,
- 0x5f, 0x42, 0x5e, 0x6d, 0x91, 0x45, 0x94, 0xbf, 0x5b, 0x7e, 0xc1, 0x96,
- 0xb3, 0x8c, 0xbc, 0xd1, 0x82, 0xb6, 0x31, 0x39, 0x57, 0xa0, 0x5d, 0xa9,
- 0x79, 0x62, 0xf0, 0x7b, 0xd2, 0x97, 0xfe, 0x1e, 0xec, 0xd4, 0xb3, 0xb8,
- 0x9e, 0x91, 0xd4, 0x9e, 0x71, 0xa7, 0x2f, 0xd9, 0xed, 0x40, 0x77, 0xe2,
- 0x8a, 0x3a, 0x7d, 0x6e, 0xa3, 0x73, 0x85, 0xed, 0xa3, 0x41, 0x9e, 0xd9,
- 0xab, 0x12, 0x2d, 0x58, 0x93, 0xed, 0x4e, 0x8f, 0x2d, 0xe3, 0x73, 0xca,
- 0x78, 0x40, 0xa7, 0xd4, 0x96, 0x0d, 0x22, 0x5d, 0x2d, 0xb0, 0x79, 0x26,
- 0x44, 0xb5, 0xb7, 0x48, 0x54, 0xba, 0x67, 0x55, 0x27, 0xca, 0x3c, 0x5b,
- 0x16, 0x6f, 0x81, 0x7e, 0x40, 0x59, 0x07, 0xca, 0xb6, 0xd9, 0xb2, 0xb6,
- 0x16, 0x69, 0x44, 0xd9, 0x8c, 0xe6, 0xf9, 0xf3, 0x3d, 0x9e, 0x9b, 0x75,
- 0x9a, 0xa5, 0xeb, 0x44, 0x0b, 0x64, 0xc3, 0x46, 0x59, 0xbc, 0xaa, 0x49,
- 0xba, 0xf0, 0x8e, 0x71, 0x6e, 0xff, 0x44, 0x4c, 0xae, 0x3d, 0xd1, 0x9d,
- 0xf8, 0x38, 0xe6, 0xd0, 0x7d, 0x8a, 0x71, 0xef, 0xfc, 0x25, 0x8c, 0xfb,
- 0x74, 0x9d, 0xe2, 0xbd, 0x49, 0xcb, 0x1f, 0xe2, 0xc3, 0x7c, 0x93, 0x88,
- 0x32, 0xf9, 0x24, 0xfc, 0x5c, 0xea, 0xf0, 0x6e, 0xfb, 0xfd, 0x8c, 0xe3,
- 0x97, 0xd0, 0x6f, 0x9b, 0xa5, 0x5d, 0x52, 0x24, 0x3f, 0x52, 0x0f, 0xe1,
- 0x3e, 0xe3, 0x48, 0xbe, 0x2a, 0xb3, 0xe6, 0xc9, 0x57, 0xc7, 0x14, 0x73,
- 0x59, 0x50, 0x56, 0xf9, 0xc5, 0xc0, 0xac, 0x31, 0x79, 0xc1, 0xc8, 0xa5,
- 0x0f, 0x18, 0xb9, 0xf4, 0xd8, 0x99, 0x15, 0x72, 0xe9, 0xbc, 0x96, 0x4b,
- 0x7b, 0x05, 0xf7, 0xf9, 0xf3, 0x90, 0x4b, 0x2f, 0xe2, 0xd9, 0xd5, 0x72,
- 0x29, 0x2e, 0xd6, 0x5e, 0x96, 0xaf, 0xea, 0xf1, 0xe7, 0x8a, 0x51, 0x6d,
- 0x57, 0xe5, 0x67, 0x60, 0x93, 0x14, 0xa7, 0xac, 0xfe, 0x96, 0xa1, 0x36,
- 0xe9, 0x19, 0xfc, 0xa9, 0x84, 0x36, 0xe7, 0x7f, 0xba, 0x84, 0xdf, 0xee,
- 0x7c, 0x5e, 0x51, 0x86, 0xbd, 0x0a, 0x19, 0x26, 0xaa, 0xbe, 0x0c, 0xc3,
- 0xbb, 0x32, 0xde, 0x95, 0xd9, 0xef, 0x8f, 0x7e, 0x3a, 0xe6, 0x52, 0x7e,
- 0x50, 0x66, 0x40, 0x26, 0x15, 0x21, 0x93, 0x8a, 0x90, 0x53, 0x45, 0xc8,
- 0x25, 0xd8, 0x6c, 0x67, 0x8a, 0x90, 0x4b, 0x45, 0xc8, 0x25, 0xc8, 0xb8,
- 0x27, 0x20, 0xe3, 0x8c, 0x4c, 0x1b, 0x85, 0x4c, 0x9b, 0x91, 0xfb, 0xac,
- 0xae, 0x37, 0xb1, 0x92, 0x7e, 0xeb, 0x23, 0x0d, 0xe8, 0x18, 0xf2, 0x99,
- 0x9a, 0xd8, 0xe0, 0x8d, 0x47, 0x34, 0xbf, 0xbb, 0x9e, 0xba, 0xc2, 0x61,
- 0x0e, 0xcd, 0x4f, 0xb4, 0xff, 0xbe, 0x9d, 0xbf, 0xa5, 0x09, 0x7c, 0xfd,
- 0x03, 0xcb, 0xd7, 0xdb, 0x97, 0xf9, 0x3a, 0xe5, 0x30, 0x56, 0x5c, 0x9f,
- 0xaf, 0x3b, 0xec, 0xbb, 0x5c, 0xb0, 0x0e, 0x7c, 0xbd, 0x6e, 0x15, 0x5f,
- 0xc7, 0xc0, 0xd7, 0x7b, 0xd6, 0xf0, 0xf5, 0x06, 0x67, 0x58, 0xb7, 0xe1,
- 0x19, 0x09, 0x3e, 0x37, 0x3a, 0x55, 0xbe, 0xbe, 0x47, 0xf3, 0xf5, 0x21,
- 0xf0, 0xf5, 0x75, 0x35, 0x7c, 0xbd, 0x47, 0x52, 0x37, 0x67, 0x22, 0x5b,
- 0x65, 0xfc, 0x7e, 0xd5, 0xbe, 0x49, 0xfe, 0x49, 0x4c, 0x7b, 0xc3, 0x63,
- 0xc3, 0xd3, 0xed, 0x92, 0x7d, 0xe8, 0x15, 0x94, 0x91, 0xcf, 0x52, 0x63,
- 0x69, 0xc7, 0x95, 0x83, 0x47, 0x7e, 0x22, 0x0b, 0x9a, 0xb7, 0x44, 0x26,
- 0x8e, 0xc4, 0x64, 0xf2, 0x08, 0xe3, 0x10, 0x7f, 0x63, 0xe9, 0xbd, 0x49,
- 0x26, 0xf7, 0x32, 0x6f, 0x2e, 0x2a, 0xe3, 0x47, 0xe0, 0x6f, 0x1d, 0x61,
- 0x1c, 0xe2, 0xa5, 0x65, 0x1e, 0x5b, 0x80, 0x6c, 0x19, 0x3f, 0xc2, 0xb5,
- 0x8e, 0xa1, 0x9f, 0x16, 0x39, 0x74, 0x44, 0xe4, 0xb6, 0x23, 0x51, 0xf9,
- 0xe8, 0x91, 0x65, 0x5e, 0x1b, 0x0d, 0x79, 0xed, 0x59, 0xf0, 0x5a, 0xb7,
- 0xe5, 0x35, 0xb5, 0xcc, 0x6b, 0x7f, 0x5a, 0xc3, 0x6b, 0x6c, 0x4f, 0x5e,
- 0x7b, 0xce, 0x96, 0xf1, 0x39, 0x2a, 0xfb, 0x8e, 0x74, 0xca, 0xf8, 0x43,
- 0x6f, 0x91, 0x89, 0xfb, 0x09, 0xab, 0xf9, 0x8e, 0x13, 0x6d, 0xb1, 0x99,
- 0x4a, 0x37, 0xfa, 0x0f, 0x73, 0x88, 0xf4, 0xf7, 0x10, 0x7a, 0x67, 0x25,
- 0x95, 0xe3, 0x78, 0x8d, 0xf0, 0xa3, 0x4f, 0xc0, 0xbf, 0xd8, 0x07, 0x98,
- 0x6e, 0x39, 0x22, 0xa9, 0xa8, 0xbc, 0x2c, 0x53, 0xfe, 0x27, 0x2e, 0x37,
- 0xf6, 0x04, 0x6c, 0x11, 0x6d, 0xfb, 0xa4, 0x25, 0xfb, 0xce, 0x40, 0xfb,
- 0x18, 0xa5, 0xb2, 0x30, 0x16, 0xc0, 0xb8, 0xb9, 0x63, 0xbe, 0xc7, 0xc4,
- 0xfc, 0xc7, 0x06, 0x7d, 0xe6, 0x45, 0xc7, 0x6c, 0x07, 0xf8, 0x9e, 0xcf,
- 0xb0, 0x67, 0xf4, 0x59, 0x43, 0xb6, 0x7f, 0x44, 0x7f, 0x1b, 0x91, 0x31,
- 0xf5, 0x7c, 0x99, 0xdf, 0xb0, 0x81, 0xff, 0x59, 0xe6, 0xb7, 0xb0, 0xf6,
- 0xb7, 0x9b, 0xf8, 0x2c, 0xf9, 0xee, 0x87, 0x0e, 0xbf, 0x5d, 0x35, 0xa5,
- 0x73, 0xbd, 0xf0, 0xbb, 0xcc, 0x67, 0xd6, 0x7f, 0x84, 0xf1, 0x8e, 0x64,
- 0x52, 0xbd, 0xf7, 0x72, 0xe6, 0x1e, 0xec, 0x9d, 0x67, 0xdd, 0xad, 0x96,
- 0x47, 0xb7, 0x6a, 0xbf, 0x83, 0x36, 0xd6, 0x78, 0xe9, 0x45, 0xc9, 0xd3,
- 0x36, 0x19, 0xdd, 0xea, 0xe4, 0x66, 0x92, 0x97, 0x1b, 0xfb, 0x79, 0xdd,
- 0xa5, 0xcc, 0x3b, 0x4c, 0xab, 0xb5, 0x32, 0xf9, 0x84, 0x84, 0x32, 0x39,
- 0x75, 0x33, 0xbf, 0xb7, 0x9b, 0x3d, 0xa2, 0xbf, 0x2f, 0x95, 0xec, 0x56,
- 0x9c, 0xd3, 0xa7, 0x21, 0x5f, 0x43, 0x5a, 0x48, 0xc8, 0x27, 0x8f, 0x90,
- 0x1e, 0x54, 0xbc, 0x55, 0x3e, 0x61, 0xe9, 0x61, 0x46, 0x0a, 0x90, 0x3b,
- 0x47, 0x8e, 0x7c, 0x54, 0x66, 0x6e, 0x5c, 0x4d, 0x0f, 0x13, 0x55, 0x7a,
- 0x88, 0xc3, 0x3e, 0x73, 0x6a, 0xe9, 0xe1, 0x97, 0x97, 0xe9, 0x61, 0xc6,
- 0xf9, 0xe7, 0xd2, 0xc3, 0xf5, 0x2b, 0xe8, 0x61, 0x4a, 0xd3, 0xc3, 0xce,
- 0x65, 0x7a, 0x98, 0x3a, 0xc2, 0x71, 0xf5, 0xde, 0xa8, 0xbb, 0xe8, 0x70,
- 0xcd, 0x97, 0x69, 0x21, 0x39, 0xa9, 0xf3, 0xf5, 0x53, 0x39, 0x9e, 0x6f,
- 0xda, 0xa0, 0x18, 0x27, 0xa9, 0xae, 0x7f, 0xeb, 0xbf, 0xe8, 0xfa, 0xbf,
- 0xfc, 0xff, 0x79, 0xfd, 0xd5, 0xa5, 0xcc, 0xdd, 0xe7, 0x99, 0x55, 0x23,
- 0x8f, 0x43, 0x7a, 0x88, 0x5d, 0x6a, 0xf4, 0x02, 0xd7, 0x98, 0xcf, 0x90,
- 0x67, 0x90, 0x7f, 0x67, 0x20, 0xff, 0x9e, 0x84, 0xfc, 0x3b, 0xbd, 0x62,
- 0x4f, 0x60, 0xd0, 0xc6, 0x23, 0x02, 0x39, 0xe8, 0x57, 0xf1, 0xb1, 0x38,
- 0x40, 0x7c, 0x98, 0xfc, 0x13, 0xe6, 0xfe, 0xae, 0xc4, 0x49, 0x54, 0xe7,
- 0x1c, 0x3d, 0xea, 0xd7, 0xe2, 0x84, 0x70, 0xbf, 0x5c, 0x33, 0x47, 0xfc,
- 0x2e, 0xf3, 0x79, 0x46, 0xe7, 0x91, 0xe4, 0xf5, 0x1e, 0x14, 0xf1, 0xc2,
- 0x3d, 0x28, 0xe2, 0x24, 0xaa, 0xed, 0xfd, 0x7c, 0xb9, 0x49, 0xe7, 0xd0,
- 0x1f, 0x98, 0x8f, 0xcb, 0x62, 0x9c, 0x31, 0x3e, 0x7e, 0x97, 0x90, 0x7e,
- 0xb3, 0x97, 0xc8, 0x4b, 0x8e, 0xb9, 0x72, 0xe0, 0xe9, 0x0d, 0x96, 0xb6,
- 0x19, 0x1b, 0xe4, 0x99, 0xdd, 0x70, 0x2f, 0xa2, 0xd7, 0xca, 0xba, 0x96,
- 0x9a, 0x98, 0x25, 0xf0, 0x3e, 0x2d, 0xc9, 0xcc, 0x00, 0xee, 0xf3, 0x1c,
- 0x7b, 0xbf, 0x4c, 0x3d, 0x38, 0x01, 0x5b, 0x6e, 0x2f, 0x74, 0x0e, 0xcf,
- 0x9f, 0x99, 0xef, 0x70, 0x13, 0x86, 0x59, 0xfd, 0xdd, 0x29, 0xfa, 0x80,
- 0xa4, 0x87, 0x04, 0x9e, 0x67, 0x6c, 0x5c, 0x29, 0x21, 0xf9, 0xc2, 0x05,
- 0xf3, 0x6d, 0xcb, 0xc2, 0x4b, 0xb8, 0xbf, 0xde, 0x7a, 0x18, 0x3f, 0x64,
- 0xd4, 0xdc, 0xd1, 0xd7, 0x92, 0xa4, 0xcb, 0x26, 0xc7, 0xa5, 0x1a, 0x37,
- 0x99, 0x91, 0xc3, 0xda, 0x7e, 0x1e, 0xb2, 0xb9, 0x2d, 0xa9, 0xd1, 0x9c,
- 0x18, 0x1b, 0xfa, 0x77, 0x60, 0x43, 0x7f, 0xb1, 0x92, 0xd6, 0xfb, 0x58,
- 0xa7, 0x61, 0x43, 0x3f, 0x01, 0xdd, 0x43, 0x9d, 0x13, 0xb7, 0x3a, 0x67,
- 0x4a, 0xdd, 0xa8, 0x75, 0xce, 0x37, 0xb5, 0xce, 0x79, 0xef, 0x1a, 0x9d,
- 0x73, 0x48, 0x75, 0x97, 0xa8, 0x73, 0x86, 0xd5, 0x1e, 0x87, 0xf6, 0xe2,
- 0xe6, 0x3a, 0x3a, 0xe7, 0x7d, 0xf2, 0x2e, 0xfb, 0xee, 0x1e, 0x79, 0xff,
- 0x0e, 0xbd, 0x77, 0xe3, 0xce, 0x2a, 0x7e, 0x6b, 0xc9, 0xe8, 0xa0, 0xeb,
- 0x54, 0xaf, 0xde, 0xf3, 0xfd, 0x46, 0x8d, 0xce, 0xe9, 0x52, 0x03, 0xce,
- 0xb0, 0x6e, 0xc3, 0xd8, 0x04, 0x9f, 0x7d, 0x27, 0x3d, 0xda, 0x84, 0xe7,
- 0x84, 0x44, 0x8e, 0x60, 0xee, 0xe6, 0x7b, 0x50, 0xca, 0xbc, 0x7b, 0xab,
- 0x7d, 0xa7, 0xc2, 0xf2, 0xa8, 0x29, 0xef, 0xb6, 0xe5, 0x46, 0x57, 0x75,
- 0xa9, 0x4e, 0xad, 0xab, 0xb6, 0x83, 0xa1, 0x66, 0xa1, 0x5f, 0x67, 0x8b,
- 0xa1, 0xce, 0xe2, 0x6f, 0xc6, 0x9e, 0x19, 0xa3, 0x08, 0x63, 0xd8, 0x49,
- 0xd4, 0xc1, 0x55, 0x0c, 0x6d, 0x4a, 0xfe, 0x86, 0xaf, 0x80, 0x6b, 0x1e,
- 0x78, 0xbd, 0x19, 0xfc, 0xf3, 0x6f, 0x0a, 0x8c, 0x81, 0xb6, 0xcb, 0xd1,
- 0xe9, 0xda, 0x77, 0x9d, 0xf2, 0x9e, 0xe9, 0x2d, 0xb2, 0xbf, 0xf4, 0x2d,
- 0xf0, 0xc1, 0x56, 0x99, 0x2a, 0x15, 0xf4, 0x79, 0xf5, 0x4d, 0xfa, 0x3b,
- 0x1e, 0xfc, 0xbe, 0x8d, 0x91, 0x91, 0x3b, 0x1d, 0x23, 0x23, 0xd3, 0xaa,
- 0x6a, 0xb3, 0x86, 0x7d, 0xf2, 0xdb, 0x21, 0x23, 0xa5, 0x84, 0xfe, 0xc6,
- 0xe9, 0x6c, 0xe5, 0x0a, 0xf9, 0xc2, 0x31, 0x75, 0xa7, 0xaa, 0x9e, 0xef,
- 0xd5, 0x36, 0xeb, 0xdc, 0x0a, 0x9b, 0xf5, 0xaf, 0x64, 0xf1, 0xfd, 0x31,
- 0xcc, 0x13, 0x34, 0x7c, 0xe5, 0xf7, 0xb8, 0x17, 0xda, 0x1e, 0x97, 0x0b,
- 0x32, 0xa2, 0xf1, 0x47, 0x79, 0xda, 0x02, 0x39, 0xb8, 0xa4, 0xf5, 0xeb,
- 0x66, 0xd0, 0x20, 0x65, 0xe9, 0xc7, 0xe4, 0x45, 0x2d, 0xcf, 0x36, 0x5b,
- 0xdb, 0x75, 0x81, 0xb1, 0xd4, 0x23, 0xb4, 0x5d, 0xbf, 0x69, 0xcb, 0x59,
- 0x96, 0x4a, 0x2c, 0x09, 0xf5, 0x5d, 0x1c, 0x32, 0x94, 0xf2, 0xf4, 0x8d,
- 0xda, 0xae, 0x5f, 0xb3, 0x7d, 0x50, 0x7e, 0x1a, 0xd9, 0xbd, 0xdd, 0x59,
- 0xb0, 0x65, 0x7c, 0x0e, 0xe3, 0xe9, 0x5e, 0x3a, 0x6b, 0xf9, 0x4c, 0x39,
- 0x5f, 0xc2, 0xfb, 0x4d, 0x78, 0x4f, 0x3e, 0x3b, 0xad, 0xf9, 0x4c, 0xdb,
- 0x27, 0x4e, 0xbf, 0xdd, 0x5f, 0x58, 0xde, 0x1b, 0xc8, 0x91, 0xcf, 0xd4,
- 0x51, 0x77, 0xc1, 0xc8, 0x03, 0xe6, 0xa9, 0x7e, 0x1e, 0xba, 0x83, 0x6d,
- 0x51, 0xfe, 0x70, 0x9a, 0xbe, 0x2d, 0xfc, 0x9f, 0x56, 0x3c, 0xb7, 0xe3,
- 0x79, 0x56, 0xde, 0xbb, 0x37, 0xa6, 0xe7, 0x3d, 0x85, 0x79, 0x1c, 0x38,
- 0x82, 0x39, 0x39, 0xc6, 0x76, 0x8e, 0x9e, 0x8a, 0x4a, 0xc3, 0x29, 0xf2,
- 0x1d, 0xcf, 0xda, 0x04, 0xc1, 0xbe, 0x7e, 0xd2, 0x6d, 0xca, 0xdd, 0xa9,
- 0xcf, 0x96, 0x6e, 0x4f, 0x44, 0x80, 0x93, 0x03, 0x58, 0x8f, 0xa9, 0x82,
- 0xe7, 0x66, 0x1c, 0x2f, 0x81, 0x79, 0xc2, 0x06, 0xec, 0x86, 0x2d, 0xd8,
- 0x0d, 0x3b, 0xb0, 0x1b, 0x76, 0xe0, 0x46, 0x39, 0x71, 0x15, 0x73, 0x4c,
- 0x72, 0xd7, 0xc2, 0x2b, 0x97, 0xef, 0xe8, 0x38, 0x7d, 0xe3, 0xcd, 0x23,
- 0xf0, 0xd9, 0xc5, 0x4d, 0x8d, 0x32, 0x0f, 0x7f, 0xc9, 0x6d, 0xbc, 0x79,
- 0xa7, 0x74, 0x0f, 0xe2, 0xfd, 0xe0, 0x05, 0xe9, 0xb9, 0xf9, 0x56, 0xa7,
- 0x71, 0x74, 0x04, 0x78, 0x4c, 0x3b, 0xa9, 0xc4, 0x98, 0xb3, 0x80, 0x71,
- 0x32, 0xdb, 0x23, 0xc2, 0xb8, 0xe5, 0x02, 0x63, 0x11, 0x37, 0x77, 0x47,
- 0xfa, 0x92, 0xe3, 0x4e, 0x6a, 0x54, 0x45, 0x52, 0xa3, 0x23, 0x4e, 0x58,
- 0x8f, 0xdf, 0x48, 0x85, 0x9c, 0x01, 0xac, 0x07, 0x8a, 0xd3, 0xa0, 0xa7,
- 0xff, 0x28, 0xf9, 0x63, 0x2d, 0x32, 0x5f, 0xe8, 0x76, 0x33, 0x2a, 0xae,
- 0x73, 0x4b, 0xd4, 0x09, 0x10, 0xfd, 0xa9, 0x98, 0xcc, 0x96, 0xb6, 0x8a,
- 0xd2, 0xb6, 0x7b, 0x87, 0x64, 0xa6, 0x4b, 0x72, 0x6e, 0x40, 0xda, 0x14,
- 0xfa, 0xe7, 0xb7, 0x67, 0xd5, 0x09, 0xee, 0x25, 0x86, 0xbc, 0x70, 0x39,
- 0xf9, 0xa4, 0x04, 0x1c, 0x82, 0x6e, 0x19, 0xe3, 0x6d, 0x12, 0xca, 0xbd,
- 0x8f, 0xea, 0xf8, 0x29, 0x63, 0xb6, 0xb5, 0x7b, 0x0f, 0xe4, 0x8f, 0x58,
- 0x5d, 0xfe, 0x98, 0x2b, 0x72, 0x9f, 0x46, 0x72, 0x51, 0xc6, 0x88, 0x3d,
- 0xfc, 0x9e, 0x61, 0xdd, 0x26, 0x99, 0x1a, 0xc8, 0xd9, 0x3c, 0x8f, 0x47,
- 0x12, 0xcc, 0x21, 0x26, 0x4e, 0xc6, 0x07, 0xc8, 0xeb, 0xab, 0xf7, 0x36,
- 0x62, 0x35, 0xf2, 0xc0, 0x91, 0xc5, 0x52, 0xb8, 0x17, 0xc2, 0xfe, 0xf0,
- 0x3c, 0x63, 0xe4, 0x6d, 0x66, 0x4d, 0x3b, 0xc2, 0xc5, 0xfd, 0xca, 0x95,
- 0x32, 0x56, 0x79, 0x94, 0xa9, 0xae, 0x96, 0xaf, 0x8f, 0x55, 0x8c, 0x6c,
- 0x9d, 0xa9, 0x84, 0xba, 0x25, 0x66, 0x74, 0xe9, 0x1a, 0x7d, 0x62, 0xa2,
- 0x99, 0x55, 0x7d, 0x42, 0xbd, 0xa8, 0xe4, 0x03, 0xf3, 0x1d, 0x12, 0x7d,
- 0x58, 0x96, 0xa6, 0xbc, 0xec, 0xe5, 0xcc, 0xd5, 0x98, 0xf2, 0xdf, 0x8c,
- 0x7e, 0xfc, 0x6f, 0x09, 0xea, 0xc3, 0x31, 0xf5, 0x75, 0xdc, 0x37, 0x69,
- 0xfa, 0x03, 0x4f, 0xe1, 0xd9, 0xf8, 0x09, 0xbf, 0x03, 0x3f, 0xe1, 0x8b,
- 0xd0, 0x75, 0x67, 0xe0, 0x27, 0x3c, 0x09, 0x3f, 0xe1, 0x34, 0xfc, 0x84,
- 0x27, 0xa0, 0x27, 0x6b, 0xfd, 0x83, 0xc9, 0x15, 0xfe, 0x41, 0xa0, 0xf9,
- 0x9f, 0xf1, 0xc0, 0x27, 0x6b, 0x7c, 0x83, 0x7d, 0x46, 0x5f, 0xc1, 0xef,
- 0x37, 0x7c, 0xd4, 0xa5, 0x6e, 0xd2, 0xfa, 0xd1, 0xe4, 0xed, 0x8e, 0x2e,
- 0xeb, 0xab, 0x2e, 0x65, 0xf4, 0xd5, 0x6c, 0x55, 0x5f, 0x19, 0x3e, 0x7a,
- 0xb8, 0x24, 0x11, 0xaf, 0xb4, 0x90, 0xf1, 0x77, 0x69, 0x1e, 0x6a, 0xf3,
- 0xb6, 0x4a, 0xe4, 0x01, 0xd5, 0xde, 0x20, 0x19, 0xfb, 0x0c, 0xfa, 0x3a,
- 0x3a, 0x8d, 0xbe, 0xae, 0x95, 0xac, 0xb6, 0xcf, 0x2e, 0x8e, 0xef, 0x27,
- 0x56, 0xe1, 0x3b, 0x5f, 0xbc, 0x5b, 0xe3, 0xfc, 0xfe, 0x32, 0xf7, 0x59,
- 0x5a, 0x64, 0xb2, 0x1c, 0xe2, 0x9c, 0xe7, 0x59, 0x99, 0x8b, 0xd1, 0x29,
- 0x91, 0x87, 0x3b, 0x78, 0xce, 0x4a, 0x65, 0xfd, 0xf5, 0x3a, 0x87, 0xe5,
- 0xc4, 0x80, 0x24, 0xb2, 0x03, 0xa4, 0xd5, 0xfb, 0x64, 0x56, 0xaf, 0x45,
- 0x87, 0x34, 0x3c, 0x4c, 0x1b, 0x25, 0xdc, 0xcf, 0xeb, 0xba, 0xcc, 0x7e,
- 0x23, 0x35, 0x66, 0xea, 0x89, 0x1c, 0xd4, 0xeb, 0x75, 0x5c, 0xe7, 0x19,
- 0xde, 0x34, 0xcf, 0xb8, 0x3c, 0xbf, 0x47, 0xc5, 0x98, 0xfc, 0x3f, 0x67,
- 0xfd, 0x7e, 0xe1, 0x32, 0x63, 0xcf, 0x6c, 0xb2, 0x76, 0x8c, 0x89, 0x53,
- 0xd5, 0xb7, 0x61, 0xd8, 0x4f, 0xed, 0x37, 0x14, 0xb7, 0x38, 0x93, 0xa5,
- 0xad, 0x4e, 0xbe, 0xc4, 0xbd, 0x6c, 0xfb, 0xf7, 0x2e, 0xdc, 0x3d, 0xce,
- 0x01, 0x6f, 0x0b, 0xca, 0x18, 0xb3, 0x64, 0xcc, 0xe6, 0x97, 0x2e, 0x63,
- 0x8c, 0x36, 0xe3, 0x71, 0x6c, 0x96, 0x6d, 0x71, 0xa6, 0x4a, 0xdd, 0xf0,
- 0xcd, 0x79, 0xae, 0x8a, 0xef, 0x77, 0x72, 0xed, 0xa0, 0x83, 0x5d, 0x7d,
- 0x66, 0x77, 0x42, 0xae, 0xb0, 0x31, 0x68, 0xea, 0xe1, 0x9f, 0x5f, 0xb1,
- 0x77, 0x7b, 0x08, 0x7a, 0xec, 0x16, 0xc8, 0x23, 0xea, 0xe1, 0x43, 0x72,
- 0xb5, 0xa5, 0xe7, 0x95, 0x7a, 0xf8, 0xbc, 0x30, 0x4e, 0xdc, 0x8f, 0x77,
- 0xb9, 0x20, 0x06, 0x7a, 0x38, 0x5c, 0xe3, 0xab, 0xd1, 0xef, 0x6b, 0x1a,
- 0x32, 0xfb, 0x61, 0x2b, 0xfd, 0x3e, 0xc8, 0x81, 0x78, 0xe8, 0xe7, 0x35,
- 0x2e, 0xef, 0xd7, 0xee, 0xb1, 0x6d, 0xa7, 0xfc, 0xfb, 0x89, 0xa3, 0xe4,
- 0x21, 0xe9, 0x81, 0x2e, 0x63, 0x0e, 0xc8, 0x6f, 0x69, 0x9c, 0x89, 0x22,
- 0xed, 0x6d, 0xd2, 0x30, 0x5a, 0x39, 0x9f, 0x0c, 0x73, 0x38, 0xf2, 0xb6,
- 0xed, 0x84, 0xdd, 0x93, 0xcf, 0xcb, 0xdc, 0x65, 0xd4, 0x83, 0x23, 0x91,
- 0xf5, 0xfc, 0x7e, 0x22, 0xda, 0xf6, 0x18, 0xbd, 0x28, 0x61, 0x5f, 0x7c,
- 0x6e, 0xa8, 0xe9, 0x9b, 0x76, 0x14, 0xef, 0xab, 0xcf, 0x91, 0x3d, 0xa3,
- 0xf7, 0x19, 0xcd, 0xf7, 0x12, 0x42, 0x3e, 0x21, 0xef, 0x24, 0xf5, 0x59,
- 0x27, 0xef, 0x61, 0xda, 0x3d, 0xdc, 0x83, 0x75, 0x17, 0x26, 0xfd, 0x4f,
- 0xe8, 0x6f, 0xfc, 0xcd, 0x88, 0x38, 0x79, 0xff, 0x36, 0x9d, 0x7b, 0x92,
- 0xd7, 0xb1, 0xe6, 0x1c, 0xee, 0x55, 0x1f, 0xb5, 0xeb, 0x61, 0xfe, 0x4d,
- 0x0b, 0x96, 0x65, 0x01, 0x1b, 0x75, 0x08, 0x65, 0x6f, 0x5c, 0xba, 0x8e,
- 0x7e, 0x58, 0xf3, 0xc2, 0x66, 0xf8, 0x02, 0xc3, 0x47, 0xa1, 0xab, 0x8f,
- 0x26, 0x64, 0xe7, 0x51, 0xad, 0x1b, 0xd3, 0x6b, 0x63, 0x05, 0x7d, 0x6e,
- 0xd4, 0x79, 0x8f, 0x3e, 0xc7, 0xf6, 0xd6, 0xa3, 0x11, 0x39, 0x1c, 0xef,
- 0x73, 0x7b, 0x9c, 0xf7, 0x5a, 0x5d, 0x18, 0xc6, 0xb0, 0x5b, 0xd0, 0xfe,
- 0xf5, 0xe2, 0xd8, 0x61, 0xfc, 0x3a, 0x22, 0x33, 0x7b, 0x3b, 0x01, 0xdb,
- 0x5f, 0x5d, 0x66, 0xce, 0x20, 0x63, 0xad, 0xf4, 0xb7, 0xe7, 0xa3, 0x09,
- 0xca, 0xb2, 0x2e, 0xc0, 0x32, 0x72, 0x94, 0xfa, 0xcc, 0xd3, 0x3c, 0x0e,
- 0x18, 0xdc, 0x06, 0xed, 0x87, 0x90, 0x2f, 0xdf, 0x22, 0xde, 0x03, 0x90,
- 0x71, 0x47, 0x63, 0xd2, 0x73, 0xb4, 0x45, 0xb6, 0x1d, 0xa5, 0x1f, 0x52,
- 0xeb, 0x97, 0xd2, 0x2e, 0x7d, 0x04, 0x73, 0x7c, 0xb7, 0x96, 0x93, 0xdc,
- 0xd3, 0xdc, 0x4f, 0xde, 0x45, 0xdd, 0x2c, 0x6c, 0xe6, 0xcc, 0x51, 0x57,
- 0xef, 0x91, 0x66, 0x30, 0xe7, 0x6c, 0xd9, 0xc5, 0x38, 0x46, 0xe6, 0xe4,
- 0xe9, 0xa7, 0x8c, 0x76, 0x00, 0xc7, 0xef, 0xb5, 0xbc, 0xb3, 0xbe, 0xc3,
- 0xf2, 0xe8, 0xcf, 0xc8, 0x7b, 0x5b, 0x3a, 0x8c, 0xec, 0x7c, 0x4b, 0x07,
- 0x73, 0x93, 0x36, 0x7b, 0xbc, 0x37, 0x69, 0x7b, 0xc2, 0xc8, 0xd0, 0xd7,
- 0xe2, 0x45, 0x01, 0x8e, 0xc2, 0x7d, 0x29, 0x7d, 0x96, 0x2f, 0x38, 0xe7,
- 0xeb, 0xf3, 0x2b, 0xfe, 0xa2, 0xfe, 0x3b, 0x21, 0xdc, 0x23, 0xab, 0x7e,
- 0x6f, 0x65, 0x57, 0x85, 0x71, 0xf2, 0xcf, 0x86, 0x7f, 0x97, 0xa4, 0x26,
- 0xef, 0xb0, 0x76, 0x0f, 0x8c, 0xb1, 0xa6, 0xe5, 0xdc, 0xa0, 0xa0, 0xa4,
- 0xbf, 0x5f, 0xf4, 0x9c, 0x73, 0xbe, 0x70, 0xd6, 0xf9, 0xee, 0xb4, 0x04,
- 0x51, 0xef, 0x27, 0xce, 0xf7, 0x3d, 0xee, 0x99, 0x7f, 0xdd, 0xf9, 0x5e,
- 0xc1, 0x03, 0x1f, 0xde, 0x87, 0x79, 0xbc, 0xe2, 0xfc, 0x00, 0xeb, 0x7b,
- 0xb0, 0x98, 0x4e, 0xb9, 0x36, 0x26, 0x7e, 0xb6, 0xf0, 0x8a, 0xf3, 0xb5,
- 0x6a, 0x3c, 0x69, 0x30, 0xa4, 0x91, 0x43, 0x7c, 0x57, 0xc6, 0xbb, 0xb2,
- 0xde, 0xff, 0x71, 0xe6, 0xa6, 0x6d, 0x7e, 0x89, 0xe6, 0xe3, 0x85, 0xe5,
- 0x7d, 0x99, 0x51, 0xbd, 0x57, 0xf1, 0xac, 0x33, 0x37, 0x7f, 0x77, 0x87,
- 0xc9, 0x33, 0x3a, 0x8b, 0x77, 0x26, 0xe7, 0x72, 0x76, 0xfe, 0x2c, 0xea,
- 0x3c, 0xe3, 0xcc, 0xea, 0xf8, 0x97, 0xf6, 0xc5, 0x9d, 0x99, 0xf9, 0x67,
- 0x9c, 0x79, 0xbd, 0x07, 0x7d, 0xce, 0x79, 0x74, 0x9a, 0x7d, 0x9f, 0x43,
- 0x9d, 0x05, 0xe7, 0x04, 0xfa, 0x9b, 0x9f, 0xe6, 0x79, 0xdc, 0x6e, 0xd8,
- 0x05, 0xfc, 0x7b, 0x3f, 0xfc, 0x1e, 0xc7, 0xb3, 0xce, 0xfc, 0x72, 0xbf,
- 0x8b, 0xe8, 0x87, 0x75, 0x49, 0x8b, 0x1c, 0xf7, 0x59, 0xf4, 0xbf, 0x76,
- 0xaf, 0x6a, 0x2d, 0x4e, 0x5e, 0x00, 0x4e, 0x2e, 0x58, 0x9c, 0xbc, 0x6a,
- 0x71, 0xf2, 0x7c, 0x0d, 0x4e, 0x44, 0xad, 0xc4, 0xc9, 0xab, 0xc0, 0x89,
- 0xa8, 0xfa, 0x38, 0xc1, 0xbb, 0x32, 0xde, 0x69, 0x9c, 0xbc, 0xb4, 0x0a,
- 0x27, 0x4b, 0xcb, 0x71, 0x79, 0x83, 0x93, 0x17, 0x81, 0x93, 0xaf, 0x5a,
- 0xd8, 0x2f, 0x58, 0x9c, 0xe0, 0x3e, 0x7f, 0x01, 0x75, 0x5e, 0xaa, 0xc1,
- 0xc9, 0x05, 0xe0, 0xe4, 0x25, 0x8b, 0x93, 0xef, 0x5b, 0x9c, 0x7c, 0x1f,
- 0x75, 0x96, 0x80, 0x93, 0xf3, 0x75, 0x70, 0xf2, 0x22, 0x70, 0x12, 0xf6,
- 0x7b, 0x1e, 0xfd, 0x7c, 0xbf, 0x06, 0x27, 0x2f, 0xd6, 0xc1, 0x09, 0xf7,
- 0x62, 0xc3, 0x9c, 0xee, 0x99, 0xd7, 0xc9, 0xe9, 0x96, 0x3b, 0x5f, 0x3f,
- 0xa7, 0x9b, 0x75, 0x66, 0xa4, 0xfa, 0x37, 0x25, 0xee, 0xb6, 0x39, 0x6a,
- 0x26, 0x17, 0xb0, 0xfa, 0xcd, 0xa6, 0x6e, 0xf0, 0x79, 0x3e, 0xe7, 0x8a,
- 0xc9, 0x29, 0x8d, 0xee, 0xf8, 0x10, 0x78, 0x6d, 0x97, 0x1c, 0x38, 0xd6,
- 0x78, 0x38, 0x6b, 0xcb, 0xbc, 0x1d, 0xdd, 0x39, 0xa5, 0xf8, 0x2e, 0xcc,
- 0x49, 0xa0, 0x5f, 0xd2, 0xc0, 0x6f, 0x0b, 0xf6, 0xa6, 0xa5, 0x76, 0x4f,
- 0xba, 0xc0, 0x6f, 0x34, 0x61, 0xec, 0x25, 0xfe, 0xfd, 0x8b, 0x24, 0xf3,
- 0xac, 0xf2, 0x1a, 0xde, 0x14, 0xf4, 0xc7, 0xa0, 0xce, 0xad, 0xca, 0x14,
- 0x68, 0x73, 0x27, 0x99, 0xa3, 0x06, 0x5b, 0x79, 0xc8, 0x9e, 0x09, 0xf3,
- 0xf5, 0x39, 0x95, 0x2a, 0xff, 0xd4, 0x9e, 0x87, 0x26, 0xdf, 0x55, 0xe9,
- 0xe6, 0xe0, 0xf2, 0x77, 0x02, 0x4f, 0xca, 0xd3, 0x3a, 0x56, 0xdc, 0x8c,
- 0xf5, 0x09, 0x82, 0xc7, 0x7c, 0x13, 0xa3, 0x5d, 0xd4, 0x31, 0x5a, 0x81,
- 0x37, 0x3e, 0x69, 0xe3, 0xb4, 0x3d, 0x83, 0x2f, 0x2d, 0xc7, 0x68, 0x6b,
- 0xf3, 0x59, 0xcc, 0xfe, 0x7a, 0xa6, 0xf4, 0x88, 0xce, 0xd1, 0x19, 0xe1,
- 0xf7, 0x37, 0x20, 0x23, 0x26, 0x66, 0xe6, 0x65, 0xf2, 0x41, 0x3e, 0x53,
- 0xbf, 0x45, 0xa0, 0xc3, 0x28, 0xc3, 0x73, 0x92, 0x19, 0x64, 0x99, 0x69,
- 0x33, 0xa2, 0xfd, 0xe5, 0x93, 0x32, 0xbc, 0x3c, 0x3e, 0xf1, 0x7b, 0x57,
- 0xcd, 0x77, 0xab, 0x69, 0xf3, 0xa4, 0x9d, 0x4c, 0x85, 0xef, 0xc3, 0x3d,
- 0xf2, 0xbb, 0xec, 0xb7, 0xb3, 0xf8, 0xbe, 0xf6, 0x5b, 0xad, 0x5a, 0x74,
- 0xe0, 0x37, 0xbf, 0x87, 0x36, 0xe5, 0x8c, 0xa0, 0xcd, 0x82, 0xdb, 0x32,
- 0xaa, 0x86, 0x6e, 0x18, 0xe5, 0xb9, 0xb9, 0xd9, 0x35, 0xdf, 0xba, 0xae,
- 0xea, 0xc5, 0xbc, 0x5e, 0x53, 0xe6, 0x67, 0xdd, 0x05, 0x5a, 0xd4, 0xb4,
- 0xa5, 0xe9, 0xff, 0xc0, 0xb2, 0xbe, 0xa4, 0x9e, 0x35, 0xdf, 0x9e, 0x31,
- 0xfa, 0x32, 0x95, 0x18, 0xc1, 0xf8, 0xfa, 0x6f, 0x2a, 0xd8, 0x73, 0xbd,
- 0xd9, 0xf9, 0xdb, 0xb5, 0xae, 0x9f, 0xf2, 0xd3, 0xc9, 0xa8, 0xd4, 0xa9,
- 0x5b, 0xaa, 0xa9, 0xab, 0xe7, 0xed, 0xca, 0x7f, 0xc5, 0xda, 0x7c, 0xbe,
- 0x58, 0x96, 0xe1, 0xe9, 0xbf, 0x84, 0xff, 0x98, 0x90, 0xdf, 0x2e, 0x96,
- 0x40, 0xaf, 0xb9, 0xcd, 0xf6, 0x5b, 0x4d, 0x19, 0xc0, 0xcd, 0x6f, 0xaf,
- 0xe8, 0x7c, 0xe2, 0xc8, 0x17, 0x40, 0x17, 0x9f, 0x2b, 0x71, 0x0c, 0xc0,
- 0x12, 0x81, 0x6d, 0x0f, 0x3b, 0x61, 0xa6, 0xa4, 0x73, 0xe7, 0xae, 0x2b,
- 0x97, 0x74, 0xcc, 0x62, 0x67, 0xb9, 0x53, 0x76, 0x95, 0x5b, 0x64, 0x37,
- 0xf4, 0xc2, 0xee, 0xb2, 0x87, 0x2b, 0x26, 0xef, 0x2e, 0x9b, 0x75, 0xfa,
- 0x58, 0x99, 0xeb, 0xbd, 0x43, 0x66, 0x8f, 0xad, 0xfe, 0x3e, 0xe7, 0x42,
- 0x2e, 0xfc, 0x3b, 0x4b, 0x4a, 0x31, 0xbf, 0x8c, 0xb4, 0x84, 0xab, 0x98,
- 0x3a, 0xbc, 0xa0, 0xf1, 0xc0, 0x0c, 0xd7, 0x54, 0x69, 0x49, 0x98, 0xa7,
- 0xcf, 0xbf, 0xad, 0x34, 0x73, 0x39, 0xcf, 0x4d, 0xf3, 0x5b, 0x5e, 0x3b,
- 0x2b, 0x61, 0xde, 0x78, 0xbd, 0x9c, 0x71, 0xd8, 0xf9, 0x3b, 0xc2, 0x1c,
- 0xbf, 0x18, 0x73, 0xc6, 0xa5, 0xeb, 0x54, 0x0b, 0xee, 0xa7, 0x2f, 0xd7,
- 0x67, 0x9b, 0x4f, 0x89, 0x2d, 0xd3, 0xf9, 0xe4, 0x78, 0x5e, 0xfd, 0x7d,
- 0xb5, 0x90, 0x1f, 0xaa, 0x7f, 0xa7, 0x40, 0xe4, 0xff, 0x02, 0xfb, 0x2e,
- 0x88, 0x71, 0xec, 0x6e, 0x00, 0x00, 0x00 };
+ 0xbd, 0x7d, 0x0d, 0x74, 0x5c, 0xd7, 0x5d, 0xe7, 0xff, 0xdd, 0x79, 0x92,
+ 0xc6, 0xb2, 0x6c, 0x3f, 0xcb, 0x13, 0x79, 0x62, 0xab, 0xf6, 0x8c, 0xf4,
+ 0x64, 0xab, 0x91, 0x08, 0x2f, 0xae, 0x28, 0x82, 0x9d, 0x84, 0xe9, 0x48,
+ 0xb2, 0x9d, 0x34, 0xed, 0xca, 0x8d, 0x5b, 0xb2, 0x9c, 0x02, 0x62, 0x24,
+ 0x27, 0xe9, 0x77, 0xd2, 0x04, 0xb6, 0xec, 0xc9, 0x6e, 0x26, 0x23, 0xf9,
+ 0x83, 0x74, 0xec, 0x51, 0x12, 0x25, 0xce, 0xa1, 0x3d, 0xbb, 0xaa, 0xa4,
+ 0xd8, 0x06, 0x06, 0x8f, 0x93, 0xb8, 0xa5, 0xec, 0xa6, 0x54, 0x28, 0xae,
+ 0x09, 0xa1, 0x07, 0x52, 0x48, 0xd9, 0x40, 0x53, 0x2a, 0xdc, 0xb4, 0xcd,
+ 0x9e, 0x53, 0xb6, 0x01, 0xca, 0x12, 0x68, 0xe8, 0xdb, 0xdf, 0xef, 0xde,
+ 0xfb, 0x34, 0xa3, 0x0f, 0xe7, 0xa3, 0xec, 0xe2, 0x73, 0x9e, 0xdf, 0xbc,
+ 0xfb, 0xee, 0xc7, 0xff, 0xfe, 0xef, 0xff, 0xfb, 0xfe, 0xef, 0xd3, 0x76,
+ 0x91, 0x66, 0xb1, 0xff, 0x36, 0xe0, 0x7a, 0x5b, 0xea, 0xf6, 0xd1, 0x6b,
+ 0xae, 0xfe, 0xc9, 0xab, 0xf9, 0xec, 0x3a, 0x4d, 0x31, 0x79, 0x13, 0xff,
+ 0x52, 0x6f, 0xa0, 0x0e, 0x3a, 0xf4, 0xa2, 0xb1, 0x78, 0x49, 0x5c, 0x65,
+ 0xdc, 0x3b, 0x72, 0xbe, 0xc4, 0x63, 0x99, 0x91, 0x5f, 0x1e, 0xf5, 0x45,
+ 0xb2, 0x95, 0x9e, 0xd4, 0x80, 0xfc, 0x4b, 0x58, 0x48, 0xb8, 0xc2, 0xf2,
+ 0xb7, 0x64, 0x5e, 0xfd, 0x6f, 0x5f, 0xf8, 0xc9, 0xf4, 0xcb, 0xd3, 0x31,
+ 0x89, 0x7b, 0x99, 0x0f, 0x8b, 0xb7, 0x4b, 0xe2, 0xed, 0x19, 0xb9, 0xe3,
+ 0xd3, 0xbb, 0xff, 0x46, 0x64, 0x63, 0xd4, 0xd7, 0x4b, 0xe1, 0x17, 0x76,
+ 0x4b, 0x61, 0x5b, 0x26, 0x39, 0xd2, 0x90, 0x49, 0xc8, 0x17, 0xab, 0x9e,
+ 0x9c, 0xab, 0xca, 0xf0, 0xa9, 0xd2, 0xcb, 0xa1, 0x9b, 0x09, 0x63, 0x13,
+ 0x7d, 0x8e, 0xc4, 0x32, 0x72, 0x61, 0xb4, 0xef, 0x9e, 0x50, 0xf9, 0x32,
+ 0xe2, 0x65, 0xfc, 0x60, 0x41, 0x5a, 0xfa, 0x2f, 0xf6, 0xa1, 0x4e, 0xe5,
+ 0xe0, 0xb5, 0x8d, 0x27, 0xe2, 0xa2, 0x32, 0x5d, 0xcf, 0xe7, 0x62, 0xd7,
+ 0x88, 0xf2, 0xfd, 0xe0, 0x82, 0x74, 0x05, 0x4f, 0x09, 0xca, 0xcf, 0xc6,
+ 0x25, 0x57, 0x95, 0x16, 0x94, 0xe1, 0xde, 0x8c, 0x3a, 0x69, 0x2f, 0x17,
+ 0x4b, 0x48, 0xb1, 0xfa, 0x63, 0xcd, 0x66, 0xec, 0xaf, 0xaf, 0x33, 0xf7,
+ 0xdd, 0xf6, 0xbe, 0xee, 0x67, 0xdd, 0x4c, 0x3c, 0xae, 0x4e, 0xc8, 0xcb,
+ 0x13, 0x7d, 0x2f, 0x87, 0x31, 0xdf, 0xf7, 0x06, 0xa4, 0x41, 0x06, 0x13,
+ 0x80, 0xa9, 0xec, 0xa0, 0xef, 0x14, 0xda, 0xfe, 0x12, 0x70, 0x0e, 0xf8,
+ 0xca, 0x29, 0x29, 0x10, 0xce, 0x72, 0x5c, 0x16, 0x63, 0x49, 0x01, 0xfc,
+ 0xc0, 0x45, 0xbb, 0x8c, 0xa3, 0x3c, 0x57, 0xe2, 0x7c, 0x5c, 0xc9, 0x7b,
+ 0x1e, 0xe6, 0xd2, 0x8e, 0x36, 0x3b, 0x1d, 0xd3, 0x3f, 0x9e, 0x97, 0xd5,
+ 0x67, 0xdd, 0xe7, 0x51, 0x37, 0xa5, 0xeb, 0x3d, 0x51, 0x4d, 0xca, 0xe3,
+ 0xd5, 0x84, 0x3c, 0x56, 0xfd, 0x98, 0x64, 0x3d, 0xe2, 0x00, 0xb0, 0x96,
+ 0x1b, 0x65, 0x60, 0xaa, 0x59, 0x72, 0x53, 0x9d, 0xc9, 0xbc, 0x84, 0xe1,
+ 0x9d, 0xc1, 0x07, 0x64, 0xa4, 0x15, 0xf5, 0xcb, 0x7c, 0x97, 0x5c, 0xf6,
+ 0x2e, 0x1f, 0xf4, 0x78, 0x79, 0xe5, 0x48, 0xf6, 0x60, 0x3a, 0x39, 0xa2,
+ 0xf8, 0xdc, 0x20, 0xb9, 0x5e, 0x3c, 0x0f, 0xbb, 0x12, 0xf3, 0xc3, 0xf0,
+ 0x8e, 0x60, 0x17, 0xe0, 0x48, 0xa7, 0x52, 0x8a, 0x6d, 0xd9, 0x2e, 0x5d,
+ 0x48, 0xa9, 0x24, 0xe6, 0x71, 0xb5, 0xa4, 0x5a, 0xc3, 0xf0, 0x3d, 0x81,
+ 0x8f, 0x72, 0x91, 0x81, 0x92, 0xdc, 0xae, 0x32, 0x3e, 0xfa, 0x94, 0x40,
+ 0x65, 0xb6, 0x60, 0x1e, 0x3d, 0xc0, 0x43, 0xa3, 0x64, 0x13, 0x92, 0x55,
+ 0x19, 0x49, 0xa9, 0xcc, 0x3a, 0x94, 0x39, 0xd2, 0xe0, 0xff, 0x77, 0x4b,
+ 0x7f, 0x9b, 0xf0, 0x2c, 0xc3, 0x2a, 0xd3, 0xba, 0xa2, 0x3c, 0x9d, 0x12,
+ 0xf5, 0xe3, 0x71, 0x8c, 0xd9, 0x9d, 0x55, 0x2c, 0xc3, 0x5d, 0x97, 0x15,
+ 0x9a, 0x56, 0x97, 0x4d, 0x3a, 0xcb, 0xcb, 0x4e, 0xb5, 0x10, 0x56, 0x51,
+ 0xfc, 0x9d, 0xd4, 0x73, 0xcd, 0x26, 0x3a, 0xbd, 0x06, 0xcc, 0x6b, 0x38,
+ 0x48, 0x7b, 0x43, 0xea, 0xb9, 0x50, 0xda, 0x08, 0x33, 0xdf, 0x29, 0xbc,
+ 0x43, 0xd5, 0x4c, 0x80, 0x75, 0x4e, 0xc8, 0x51, 0xcc, 0xed, 0xd2, 0x54,
+ 0xda, 0xeb, 0x50, 0xb8, 0xcf, 0xf1, 0x77, 0x18, 0xe6, 0x82, 0x82, 0xa6,
+ 0x81, 0x6f, 0x4e, 0x25, 0xf1, 0x0c, 0xf8, 0x13, 0xd9, 0xf4, 0x66, 0xb9,
+ 0xc9, 0xae, 0xcb, 0x37, 0x31, 0x66, 0xa7, 0x77, 0x87, 0xea, 0xf4, 0x02,
+ 0x95, 0xf6, 0x66, 0xe4, 0xf7, 0xf1, 0x1c, 0x86, 0x07, 0x82, 0x74, 0xb2,
+ 0x80, 0x35, 0x7b, 0xb1, 0x94, 0x90, 0x6f, 0x95, 0xd2, 0xa0, 0xfc, 0x74,
+ 0xf7, 0xac, 0xf4, 0x04, 0xb3, 0x80, 0xb7, 0x88, 0xeb, 0x08, 0xdf, 0x55,
+ 0xf0, 0xae, 0xc2, 0xb6, 0x61, 0x78, 0x53, 0xf0, 0xeb, 0xe1, 0x48, 0x9b,
+ 0xe1, 0xa5, 0x2f, 0x96, 0xb1, 0x9e, 0x80, 0xf9, 0x71, 0xac, 0xd3, 0x63,
+ 0xe5, 0x88, 0x4e, 0xba, 0xb1, 0xee, 0xa4, 0x0d, 0xd2, 0xc5, 0x1e, 0x4b,
+ 0xff, 0xa3, 0xf6, 0x2e, 0x92, 0x03, 0x8d, 0xe5, 0x82, 0x1f, 0x84, 0x59,
+ 0xcd, 0x63, 0xe2, 0x0c, 0x94, 0x49, 0xbb, 0x0d, 0x80, 0x95, 0x8f, 0x1f,
+ 0xb3, 0xf5, 0xda, 0x1d, 0xe0, 0x96, 0xeb, 0xc0, 0xf7, 0x71, 0xe5, 0x37,
+ 0xd9, 0xf7, 0x11, 0x2f, 0xf1, 0x1f, 0xe8, 0xcd, 0xaf, 0xd5, 0xcb, 0x91,
+ 0x26, 0xab, 0x05, 0xc9, 0x3f, 0x18, 0xca, 0x40, 0x00, 0x3c, 0xb1, 0x4f,
+ 0x2f, 0x10, 0xdd, 0xd6, 0x63, 0x1d, 0x5d, 0x17, 0xff, 0xae, 0x69, 0xc4,
+ 0x18, 0xce, 0x60, 0xb9, 0xd6, 0x76, 0xb0, 0xfc, 0xe4, 0x16, 0x0b, 0x1f,
+ 0x9e, 0xfb, 0x9d, 0x5c, 0xf5, 0x6f, 0xed, 0xda, 0x46, 0xf3, 0xb8, 0x69,
+ 0x0d, 0xda, 0x0e, 0xc3, 0x89, 0x40, 0x46, 0x54, 0x66, 0x31, 0x9e, 0x2b,
+ 0x89, 0xd3, 0x90, 0xf1, 0xbd, 0x21, 0x59, 0x27, 0x76, 0x5e, 0xb6, 0xdc,
+ 0x03, 0xaf, 0x74, 0xa1, 0xdc, 0x11, 0xc8, 0x8d, 0x11, 0x07, 0x65, 0x1d,
+ 0x15, 0x94, 0x61, 0xfd, 0xc6, 0x81, 0xaf, 0x7c, 0xa9, 0x5f, 0xaf, 0x65,
+ 0xbe, 0x34, 0x0c, 0xde, 0xcf, 0xe0, 0x77, 0x76, 0xb3, 0x2b, 0x5d, 0xa0,
+ 0x43, 0xae, 0xb1, 0xb8, 0xb9, 0xdd, 0xa0, 0xd5, 0xea, 0xeb, 0x4b, 0x2c,
+ 0x3d, 0xf7, 0xe0, 0x5f, 0x88, 0xd3, 0x25, 0x78, 0x62, 0x19, 0xf2, 0xf5,
+ 0xf3, 0x21, 0xe8, 0x19, 0x65, 0x84, 0x99, 0x35, 0x13, 0x32, 0x51, 0xde,
+ 0x26, 0xc5, 0x29, 0x5f, 0xc6, 0x4b, 0xf3, 0xdd, 0x4a, 0x5e, 0x86, 0xac,
+ 0xf1, 0x41, 0x0b, 0x69, 0xf0, 0x41, 0x46, 0x06, 0xaa, 0x18, 0xaf, 0x84,
+ 0x7b, 0xb9, 0x13, 0x6d, 0x5d, 0xc9, 0x26, 0xcd, 0x3a, 0x17, 0x4b, 0x63,
+ 0xc0, 0x15, 0xd6, 0x8d, 0xb2, 0x41, 0xc3, 0x3c, 0x0c, 0x3a, 0xf4, 0x24,
+ 0xd7, 0xa7, 0xe1, 0x7c, 0x13, 0xf0, 0xc5, 0x65, 0x26, 0x68, 0xb4, 0x38,
+ 0x22, 0x7f, 0xc6, 0xdd, 0x01, 0xe0, 0x61, 0xa0, 0x72, 0x0f, 0xfa, 0x6f,
+ 0xc1, 0x6f, 0x96, 0x89, 0x2d, 0x73, 0xf5, 0xf3, 0x40, 0x85, 0x30, 0x47,
+ 0x74, 0x0f, 0x3e, 0x98, 0x82, 0xfc, 0x01, 0xdd, 0x0f, 0x90, 0x5f, 0xe6,
+ 0x38, 0x17, 0xc2, 0xb5, 0x4d, 0xff, 0x1e, 0x9f, 0xda, 0xa1, 0x9f, 0xf3,
+ 0xc3, 0xdb, 0xa4, 0x30, 0x17, 0xcd, 0x99, 0xb2, 0x87, 0xf2, 0x26, 0x7d,
+ 0x0c, 0x74, 0x05, 0xf9, 0x13, 0x86, 0x0f, 0x06, 0x94, 0x41, 0x61, 0xf8,
+ 0x78, 0x40, 0x99, 0x74, 0x1e, 0xb2, 0x86, 0x72, 0x88, 0x72, 0x61, 0x50,
+ 0x71, 0xdd, 0x73, 0xa5, 0x00, 0xeb, 0xd3, 0x28, 0xf9, 0xde, 0x47, 0x08,
+ 0x2b, 0x64, 0xd8, 0xb3, 0x1f, 0xcb, 0xf9, 0x85, 0x64, 0x4c, 0xe3, 0x49,
+ 0xb0, 0x5e, 0x71, 0xc9, 0xea, 0x99, 0x75, 0x48, 0xb1, 0x77, 0xd2, 0xd6,
+ 0x79, 0x49, 0xd7, 0x71, 0x57, 0xd5, 0xf9, 0x75, 0x65, 0x78, 0x3c, 0xc0,
+ 0x5a, 0xfe, 0xb4, 0x22, 0x1e, 0x3b, 0x76, 0xf1, 0x59, 0xe2, 0x0d, 0x99,
+ 0xaf, 0xe1, 0xdd, 0xb9, 0x3b, 0x1f, 0xf5, 0xd7, 0x7a, 0xb7, 0xb5, 0x61,
+ 0xf5, 0xbb, 0x09, 0x71, 0xfd, 0x74, 0xf7, 0x01, 0xf5, 0x4f, 0x78, 0x17,
+ 0x86, 0x8f, 0x06, 0x51, 0x79, 0x6f, 0xc3, 0xea, 0x31, 0x7e, 0x76, 0x8d,
+ 0xb2, 0xf3, 0x6b, 0x94, 0xfd, 0xc9, 0x1a, 0x65, 0xef, 0x6d, 0x5c, 0x5d,
+ 0xf6, 0xc0, 0x1a, 0x65, 0x4f, 0xaf, 0x51, 0xe6, 0x37, 0xad, 0x2e, 0xdb,
+ 0xb5, 0x46, 0xd9, 0x5b, 0xd7, 0x28, 0x3b, 0xb0, 0x46, 0x99, 0x0b, 0x1e,
+ 0xde, 0x25, 0xc5, 0xc4, 0xbd, 0x9c, 0xbb, 0xc5, 0xcd, 0xe7, 0x62, 0xab,
+ 0x71, 0xd3, 0x80, 0x7a, 0xed, 0x2b, 0xea, 0x7d, 0x6d, 0x8d, 0x7a, 0x8d,
+ 0xa8, 0xd7, 0xba, 0xa2, 0xde, 0xcd, 0xee, 0xea, 0x7a, 0x4d, 0xa8, 0x17,
+ 0x5f, 0x51, 0xef, 0x77, 0xd7, 0xa8, 0xc7, 0xf2, 0x4f, 0xd9, 0x71, 0x7a,
+ 0xa0, 0xd1, 0x5e, 0x6b, 0xbd, 0x1a, 0x45, 0xda, 0x58, 0x1e, 0x40, 0x1f,
+ 0xfd, 0xb4, 0x32, 0x32, 0x86, 0xf2, 0x4c, 0xe3, 0x0d, 0x74, 0x9e, 0x04,
+ 0xdd, 0x51, 0x26, 0x83, 0xcf, 0x7c, 0xf2, 0xfe, 0x06, 0x19, 0x49, 0xf4,
+ 0x78, 0x6f, 0x53, 0x2d, 0xa0, 0xb1, 0xb4, 0x97, 0x52, 0xe4, 0x3f, 0x29,
+ 0x80, 0xb7, 0x0b, 0x03, 0xa2, 0x12, 0x4a, 0x42, 0x19, 0x0c, 0x54, 0xab,
+ 0x92, 0x7b, 0xc0, 0x5f, 0x59, 0xe8, 0xbf, 0x03, 0xe1, 0x80, 0xe6, 0x2d,
+ 0x53, 0xf7, 0xf2, 0xf2, 0xb9, 0x5f, 0x8e, 0x50, 0xae, 0x66, 0x82, 0x3b,
+ 0x73, 0xfe, 0x7c, 0x7f, 0x23, 0x68, 0xf6, 0x12, 0xda, 0xec, 0x43, 0xcb,
+ 0x43, 0x15, 0x57, 0x06, 0x2b, 0x19, 0xf0, 0x82, 0x23, 0x17, 0xfd, 0x4d,
+ 0x72, 0x31, 0x40, 0xdd, 0x6a, 0x4c, 0x16, 0x12, 0x8e, 0x2c, 0xe0, 0x39,
+ 0x17, 0xe0, 0x5d, 0x35, 0xe2, 0xad, 0x8c, 0x1c, 0x2e, 0xf7, 0xcb, 0xb1,
+ 0xf2, 0x87, 0x55, 0xa4, 0x23, 0x87, 0x82, 0xf5, 0x72, 0xc6, 0x33, 0x7d,
+ 0xef, 0xf3, 0xe7, 0xa1, 0x9d, 0x5d, 0xb9, 0xe4, 0xa7, 0x93, 0x0b, 0x9a,
+ 0x27, 0xfe, 0x31, 0x1c, 0x44, 0x3f, 0x33, 0x7e, 0xda, 0xfb, 0x03, 0x0a,
+ 0xc9, 0x0a, 0x6d, 0xa9, 0x5a, 0x5f, 0xe3, 0xe8, 0xeb, 0x68, 0x79, 0x83,
+ 0xdc, 0x6a, 0xdb, 0xef, 0xf5, 0xe7, 0xbb, 0xc1, 0x73, 0xde, 0x29, 0xca,
+ 0x90, 0x12, 0xe0, 0x3a, 0x08, 0xde, 0x46, 0xdb, 0x2f, 0x09, 0xdb, 0xc0,
+ 0xf6, 0x2a, 0x6d, 0x82, 0xac, 0xff, 0x87, 0xf0, 0xd6, 0x04, 0xeb, 0xb3,
+ 0x8c, 0xfa, 0x4b, 0x26, 0x55, 0x06, 0x32, 0xa1, 0xaf, 0x0b, 0xfa, 0x2b,
+ 0x25, 0x83, 0x55, 0xc8, 0x9e, 0xf2, 0x0f, 0xc3, 0xac, 0xcb, 0x31, 0xa2,
+ 0xb1, 0xa4, 0x50, 0xab, 0xc3, 0x32, 0xd6, 0x23, 0xff, 0x2f, 0x2e, 0xc9,
+ 0x8a, 0x02, 0xe4, 0x8b, 0xb1, 0xd1, 0xfe, 0x13, 0x78, 0xb4, 0x5d, 0x06,
+ 0x4b, 0xe9, 0x42, 0x56, 0x76, 0x61, 0xfd, 0x7e, 0x0d, 0x6b, 0xea, 0xe2,
+ 0xfa, 0x93, 0xf5, 0xb2, 0x31, 0x80, 0x1d, 0xc0, 0x72, 0x74, 0xda, 0x46,
+ 0xfb, 0xec, 0x19, 0xe0, 0x61, 0x9c, 0x6b, 0x9e, 0xcc, 0xc5, 0x9c, 0x61,
+ 0xda, 0x3e, 0xc3, 0x90, 0x8f, 0xf9, 0x0a, 0xfb, 0x26, 0xbc, 0x49, 0xfb,
+ 0x1b, 0x36, 0x5b, 0xa9, 0xdd, 0xfe, 0x6e, 0xc1, 0xef, 0x94, 0xfd, 0x0d,
+ 0x99, 0x5a, 0xf2, 0xed, 0xef, 0x04, 0x7e, 0x77, 0xdb, 0xdf, 0x49, 0xfc,
+ 0xee, 0xd5, 0xbf, 0x27, 0xca, 0x7b, 0xf7, 0x2a, 0xff, 0x6a, 0xc9, 0xcf,
+ 0xb5, 0xcb, 0xe1, 0xd2, 0x7b, 0xad, 0x6c, 0xc1, 0x25, 0x9f, 0x77, 0xcc,
+ 0x3c, 0x01, 0x77, 0x99, 0x6d, 0x0a, 0xce, 0xb0, 0xb6, 0xdd, 0xda, 0x61,
+ 0xeb, 0xf4, 0x78, 0x9b, 0x85, 0x34, 0x30, 0xe1, 0x0c, 0x54, 0x9d, 0x6c,
+ 0x2c, 0xd3, 0x95, 0x1c, 0x97, 0x63, 0xf8, 0x2d, 0x5e, 0x2c, 0xf3, 0x79,
+ 0xdc, 0x0d, 0x0e, 0xbe, 0x00, 0x7d, 0x33, 0x5e, 0xa6, 0xbc, 0xf4, 0x31,
+ 0xf7, 0x94, 0x9c, 0x5f, 0x66, 0xaf, 0x11, 0x17, 0x4a, 0xf2, 0x53, 0xe9,
+ 0x47, 0x0a, 0x92, 0x2e, 0x4c, 0x83, 0x21, 0x0e, 0x04, 0xae, 0xbc, 0x27,
+ 0x00, 0xed, 0x5e, 0xed, 0xc8, 0xde, 0xab, 0x5d, 0xd8, 0x57, 0xfe, 0xf4,
+ 0x5e, 0xc8, 0xd8, 0x7c, 0xe9, 0xea, 0x18, 0xe9, 0x41, 0x9d, 0x95, 0x11,
+ 0x37, 0x03, 0x6c, 0x9f, 0xed, 0x1d, 0x1c, 0x2f, 0xe5, 0x3f, 0xac, 0x32,
+ 0xb7, 0xff, 0x6a, 0xae, 0x6f, 0x17, 0x74, 0x79, 0x18, 0xc6, 0x32, 0x6d,
+ 0xd0, 0x4b, 0x5c, 0x57, 0xea, 0xa9, 0x9b, 0x6e, 0x8a, 0x65, 0x1a, 0x64,
+ 0xe0, 0x60, 0x1b, 0xea, 0xb3, 0x9c, 0xb8, 0x72, 0xd0, 0x47, 0x3a, 0x35,
+ 0x28, 0x72, 0xf7, 0x44, 0xdf, 0xa2, 0x33, 0x3e, 0xf9, 0x73, 0xe0, 0xc7,
+ 0x7e, 0xc9, 0x1f, 0x7c, 0x00, 0xf8, 0x7d, 0xd9, 0x29, 0x4e, 0xbd, 0xe2,
+ 0x8c, 0x4f, 0xfd, 0x9d, 0x33, 0x31, 0xb5, 0x63, 0xc7, 0x50, 0xff, 0x8e,
+ 0x1d, 0xa3, 0xfd, 0xae, 0xd5, 0x2d, 0x3b, 0x76, 0x4c, 0xf4, 0x67, 0x31,
+ 0xff, 0x1e, 0x6f, 0x50, 0x7c, 0x6f, 0x2f, 0x95, 0x7c, 0xc2, 0xac, 0xfd,
+ 0x4c, 0xd0, 0x8d, 0xf7, 0x6c, 0xdf, 0xab, 0xdf, 0x0f, 0x48, 0x4f, 0xb2,
+ 0x55, 0x38, 0x7e, 0x87, 0xd5, 0x49, 0x6c, 0x07, 0x7a, 0xe9, 0xa5, 0x1d,
+ 0xa8, 0x50, 0x2f, 0x05, 0x7c, 0xd0, 0x26, 0xde, 0x06, 0x1b, 0x82, 0xed,
+ 0x94, 0x5d, 0xf7, 0x92, 0x6a, 0xf0, 0x63, 0xba, 0x5f, 0x75, 0x36, 0x13,
+ 0x33, 0x6b, 0xde, 0x63, 0xed, 0xeb, 0x4d, 0x28, 0xe7, 0x33, 0x71, 0x49,
+ 0x7c, 0xd1, 0xde, 0x69, 0xd0, 0xf6, 0x69, 0xbe, 0x44, 0x5a, 0x72, 0x65,
+ 0xac, 0xd4, 0x8f, 0x36, 0xa0, 0x97, 0xb3, 0xf6, 0x3a, 0x81, 0xf1, 0x0e,
+ 0xa2, 0xaf, 0x13, 0x47, 0xd1, 0x8e, 0xb2, 0x24, 0xdd, 0x2d, 0xea, 0x41,
+ 0xd4, 0xe9, 0xf1, 0xb6, 0x08, 0xed, 0x9a, 0x47, 0x24, 0x5f, 0x26, 0xdf,
+ 0xd3, 0x36, 0x88, 0x4b, 0xaa, 0x0d, 0xcf, 0xd5, 0xc3, 0xb0, 0x75, 0x1a,
+ 0x22, 0x7b, 0x43, 0x6a, 0x76, 0xd1, 0xaf, 0x2a, 0xf1, 0x0f, 0xcb, 0xc8,
+ 0xec, 0x76, 0xd4, 0x33, 0xf6, 0xbc, 0xf2, 0x61, 0x17, 0xcd, 0x66, 0x25,
+ 0xb7, 0xeb, 0x5e, 0xdc, 0x3d, 0x3c, 0x17, 0x71, 0x7f, 0x0b, 0xee, 0xe3,
+ 0xb8, 0x47, 0x70, 0x02, 0xe7, 0x41, 0xcc, 0xea, 0xb2, 0x51, 0x8c, 0xfd,
+ 0xef, 0x25, 0x37, 0x09, 0x7a, 0x2d, 0x85, 0x9b, 0x72, 0x7e, 0xd6, 0x53,
+ 0xa2, 0xb6, 0x28, 0x99, 0x40, 0x7d, 0xf8, 0x29, 0xfe, 0x11, 0x19, 0x3d,
+ 0x8d, 0xdf, 0x0f, 0xd2, 0xee, 0x9e, 0x90, 0xd1, 0x59, 0x8e, 0x53, 0x02,
+ 0x4c, 0x93, 0x92, 0x3f, 0xfd, 0x00, 0xae, 0x29, 0x5c, 0x0f, 0xe3, 0xe2,
+ 0xdc, 0xd8, 0xff, 0xc2, 0x66, 0x25, 0x2d, 0xfa, 0x39, 0x4f, 0xfa, 0xae,
+ 0xe2, 0x37, 0x69, 0xbb, 0x4a, 0x1b, 0x08, 0x74, 0x5d, 0x8d, 0xe8, 0x3d,
+ 0xb0, 0xbf, 0x93, 0x9a, 0xdf, 0x0b, 0xad, 0xa0, 0xa5, 0x6a, 0x56, 0xcb,
+ 0x22, 0xc0, 0x00, 0xb9, 0x03, 0x9b, 0xa4, 0x95, 0x73, 0xec, 0xb5, 0x65,
+ 0xbd, 0xba, 0x2c, 0xa5, 0xcb, 0xfa, 0x6c, 0x19, 0xee, 0xd5, 0x06, 0x19,
+ 0x69, 0x03, 0xc4, 0x94, 0xdb, 0x12, 0xe1, 0x93, 0xb2, 0x01, 0x74, 0x8d,
+ 0xf5, 0x3d, 0x7f, 0x59, 0xb9, 0xb8, 0xa8, 0xed, 0xbd, 0x73, 0x55, 0xd2,
+ 0x37, 0x69, 0x3e, 0x0c, 0xef, 0x0f, 0x9a, 0xd0, 0x3f, 0x65, 0x81, 0x48,
+ 0xc3, 0x09, 0x57, 0xa6, 0x3d, 0xd2, 0xc0, 0xc7, 0x5a, 0x48, 0x03, 0x8d,
+ 0x3e, 0x69, 0xbb, 0x9e, 0xef, 0xb8, 0x86, 0xec, 0xaf, 0x00, 0x1b, 0x92,
+ 0xb6, 0x64, 0x17, 0xec, 0x73, 0x8e, 0x71, 0x8c, 0xcf, 0x9e, 0x02, 0xaf,
+ 0xe5, 0x96, 0x78, 0x4d, 0x64, 0xa6, 0x44, 0xdc, 0x44, 0x36, 0x26, 0xd7,
+ 0x99, 0xf8, 0x39, 0x87, 0x39, 0xf3, 0x7e, 0xde, 0xe2, 0xe9, 0xf3, 0x16,
+ 0x4f, 0x4f, 0xda, 0xbb, 0xe7, 0xe4, 0xb5, 0xcd, 0x38, 0x8f, 0x67, 0xae,
+ 0x0f, 0xe8, 0xaa, 0x4a, 0x9e, 0x9b, 0xc6, 0x1d, 0x75, 0xcb, 0xe7, 0x64,
+ 0x54, 0xdb, 0x6f, 0x31, 0x79, 0x87, 0x96, 0x79, 0x5f, 0xc5, 0x5a, 0x96,
+ 0x00, 0x73, 0x83, 0x14, 0x12, 0x31, 0xbd, 0xf6, 0xae, 0xff, 0x5b, 0xae,
+ 0xa1, 0x55, 0xe2, 0x64, 0x99, 0xbf, 0x56, 0x07, 0x53, 0xe4, 0xa3, 0x12,
+ 0x2e, 0xd2, 0xee, 0xa7, 0x35, 0x5c, 0xb7, 0x40, 0x0e, 0x16, 0x44, 0xb5,
+ 0x35, 0xca, 0x95, 0xa0, 0x05, 0x95, 0x80, 0x46, 0x0b, 0x9f, 0x82, 0x3d,
+ 0x95, 0x9f, 0xa5, 0x9d, 0xde, 0x41, 0xdf, 0x28, 0x9e, 0xef, 0xdd, 0x48,
+ 0x3a, 0x52, 0x86, 0x6f, 0x1c, 0x95, 0xef, 0xd5, 0x74, 0xea, 0x28, 0x3f,
+ 0xa1, 0x6d, 0x71, 0xd7, 0xdf, 0xea, 0x5a, 0x9f, 0xde, 0x55, 0xfe, 0x96,
+ 0x95, 0x65, 0x29, 0xea, 0x67, 0xb4, 0x4b, 0xe5, 0x7b, 0xdb, 0xc8, 0x63,
+ 0x1e, 0xfc, 0xe1, 0xac, 0xf2, 0xb5, 0xff, 0x55, 0x50, 0x7d, 0x9b, 0x56,
+ 0xd4, 0xd7, 0x77, 0xc7, 0x3e, 0xbb, 0xf6, 0xee, 0xd9, 0x7b, 0xca, 0xde,
+ 0x0b, 0x6e, 0x1f, 0xef, 0x8e, 0xb8, 0x19, 0xde, 0xb1, 0x86, 0x19, 0xf6,
+ 0xa1, 0xf9, 0x2a, 0x34, 0xb6, 0x72, 0x97, 0x57, 0x14, 0xf2, 0xd5, 0x57,
+ 0xe5, 0x96, 0x59, 0x23, 0x97, 0xf7, 0x96, 0xc2, 0x10, 0x3e, 0xa2, 0xb7,
+ 0x00, 0xff, 0x38, 0x7b, 0xb0, 0x22, 0xb7, 0x54, 0x89, 0xb7, 0x4f, 0x02,
+ 0x7f, 0x43, 0x2e, 0x79, 0xd3, 0x13, 0xca, 0xe3, 0xbb, 0x84, 0xf6, 0x6a,
+ 0xb1, 0x44, 0x9c, 0x5f, 0x10, 0xae, 0x4d, 0xb1, 0xf4, 0xb4, 0x5e, 0x9b,
+ 0x23, 0xa5, 0x05, 0xe0, 0xe7, 0xcb, 0xa0, 0xfb, 0x30, 0x5c, 0x08, 0x8a,
+ 0xa0, 0x9c, 0x3f, 0xc6, 0x6f, 0xd8, 0x28, 0xa5, 0x67, 0xf1, 0x7e, 0xa3,
+ 0x14, 0x27, 0xc9, 0x73, 0xae, 0xe5, 0xe1, 0xb3, 0xe0, 0xa7, 0x9f, 0x41,
+ 0xbf, 0x28, 0xeb, 0xe3, 0xef, 0x1f, 0xe0, 0x1d, 0xee, 0xb3, 0x58, 0xc4,
+ 0x36, 0xda, 0x40, 0x1c, 0x9b, 0x6b, 0xc7, 0x35, 0xa3, 0xaf, 0x5e, 0xef,
+ 0x97, 0x73, 0xbd, 0xd2, 0xdd, 0x05, 0x59, 0x8a, 0x2b, 0xc8, 0xb9, 0x12,
+ 0xeb, 0x93, 0xfe, 0xfb, 0xd6, 0x19, 0x1d, 0xb1, 0xa1, 0xd9, 0xdc, 0x57,
+ 0xb6, 0xe5, 0x9a, 0xd7, 0xd3, 0x20, 0x7d, 0xa8, 0x74, 0x7f, 0x01, 0x72,
+ 0xc7, 0xf5, 0x37, 0xca, 0xa0, 0x96, 0x9d, 0xa4, 0x09, 0xd2, 0xc0, 0xcd,
+ 0xca, 0xd0, 0xe6, 0xfb, 0x95, 0xa1, 0xcd, 0xa7, 0x41, 0x8b, 0xb8, 0xca,
+ 0x8b, 0x8e, 0xa1, 0xcd, 0x2f, 0xe3, 0x8e, 0xab, 0xfc, 0xa2, 0x13, 0xf1,
+ 0xf1, 0x00, 0xfc, 0xca, 0xbd, 0x25, 0xd7, 0x19, 0xad, 0x82, 0x7e, 0xcb,
+ 0x71, 0x94, 0xcf, 0x13, 0xe7, 0x98, 0x3f, 0xc7, 0xd9, 0x69, 0xfb, 0x3f,
+ 0x27, 0x63, 0xe5, 0x50, 0xdb, 0x5b, 0xf9, 0xd9, 0x7b, 0x71, 0x5f, 0xaf,
+ 0xe5, 0x8c, 0xf2, 0xb3, 0xca, 0xc8, 0xab, 0x77, 0xe0, 0xde, 0x99, 0x3c,
+ 0x22, 0x9d, 0x5e, 0x4c, 0x9e, 0x45, 0x5f, 0xdf, 0x75, 0xc6, 0xaa, 0x2f,
+ 0xe3, 0xfa, 0x3e, 0xae, 0x57, 0x71, 0xbd, 0x82, 0x7e, 0x5f, 0x40, 0xf9,
+ 0x7a, 0x99, 0xf7, 0x9a, 0x51, 0x5f, 0xd4, 0x68, 0xf5, 0x79, 0x67, 0xe4,
+ 0xf4, 0x4b, 0xb8, 0x5c, 0x35, 0x56, 0x7d, 0xce, 0xc9, 0xcf, 0x86, 0x9b,
+ 0x16, 0x7c, 0xca, 0xb0, 0xaf, 0x3a, 0xa6, 0xef, 0x0c, 0xe6, 0x00, 0x9a,
+ 0x2e, 0xcf, 0x63, 0xec, 0xa7, 0x35, 0xcf, 0x0c, 0x42, 0x1f, 0xe4, 0x61,
+ 0xaf, 0x8c, 0x68, 0x98, 0xb6, 0x03, 0x3e, 0xf8, 0xd3, 0x7d, 0xb8, 0xcf,
+ 0x36, 0xca, 0x62, 0x82, 0xf6, 0xe5, 0x93, 0xba, 0x7e, 0xbe, 0x7c, 0xbd,
+ 0xc6, 0xed, 0xf4, 0x2a, 0xfe, 0xa1, 0x4f, 0x18, 0xc9, 0x03, 0x23, 0x8d,
+ 0x67, 0x4a, 0x94, 0x05, 0xd0, 0x4d, 0xa5, 0x09, 0xdc, 0x1b, 0xb5, 0x4c,
+ 0x28, 0x4a, 0x24, 0x0f, 0xd8, 0x8e, 0x32, 0xa1, 0x5e, 0xee, 0x50, 0xd6,
+ 0x50, 0xf6, 0x50, 0x96, 0x98, 0xf5, 0x18, 0x7d, 0x90, 0x32, 0xfc, 0x3a,
+ 0xe8, 0x4d, 0xda, 0x25, 0xbe, 0xf1, 0x4d, 0xa6, 0x72, 0xca, 0xc8, 0xd3,
+ 0xfd, 0x7a, 0x2d, 0xc6, 0x4a, 0x2a, 0x01, 0xc8, 0x51, 0x86, 0xeb, 0xe4,
+ 0x41, 0xdc, 0xf3, 0x6a, 0x0c, 0x57, 0xfe, 0xe4, 0xfb, 0xf0, 0x9b, 0x6b,
+ 0x33, 0x86, 0x7a, 0xb8, 0xca, 0xc3, 0xb8, 0xe3, 0x2a, 0xdf, 0xa8, 0x8c,
+ 0x1c, 0xe1, 0x9a, 0x26, 0xed, 0x9a, 0x3e, 0x09, 0x3c, 0x70, 0x7e, 0x4a,
+ 0xc7, 0x38, 0x94, 0xbf, 0x07, 0x78, 0xaf, 0x5a, 0x9f, 0x7a, 0xa3, 0x18,
+ 0x1e, 0xc4, 0xd5, 0x4d, 0x7e, 0x6e, 0x31, 0xeb, 0xa5, 0x69, 0x77, 0x5d,
+ 0x83, 0xe1, 0xc5, 0x04, 0xca, 0x62, 0x28, 0x6b, 0x33, 0x3a, 0x73, 0x09,
+ 0x8f, 0x59, 0x8b, 0x47, 0xfe, 0x56, 0xf6, 0x37, 0xe8, 0x09, 0xb6, 0x2e,
+ 0xe4, 0x35, 0xc6, 0xc5, 0x5c, 0x4e, 0xee, 0x57, 0xa3, 0x65, 0xfa, 0xc9,
+ 0x94, 0xe1, 0x8c, 0x65, 0x70, 0x7e, 0xec, 0x17, 0xe5, 0x1a, 0x07, 0x81,
+ 0xd4, 0xe2, 0x04, 0x4f, 0x62, 0xcd, 0xce, 0xc9, 0xa1, 0xf2, 0x47, 0xb4,
+ 0xdf, 0xde, 0x78, 0xc2, 0xac, 0x87, 0xa8, 0xa8, 0x1e, 0xfa, 0x4e, 0xd0,
+ 0xe6, 0xf9, 0x75, 0xfd, 0xde, 0x3d, 0xc1, 0xdf, 0x49, 0x1d, 0x4f, 0xaa,
+ 0xc9, 0x7b, 0x63, 0xef, 0x14, 0x97, 0xc9, 0x3a, 0xda, 0x1d, 0x58, 0xb3,
+ 0x4a, 0x3d, 0xde, 0x19, 0x47, 0xa0, 0xcc, 0x23, 0x3f, 0x1d, 0x01, 0x4f,
+ 0x60, 0xf2, 0x9a, 0xf7, 0xe9, 0x83, 0xac, 0xc5, 0x4f, 0x3e, 0x6c, 0x62,
+ 0x57, 0x4e, 0xc1, 0xa6, 0xdb, 0xbb, 0xd4, 0x07, 0x64, 0x65, 0x22, 0x2e,
+ 0xa7, 0x4b, 0x2d, 0x32, 0x5b, 0x52, 0x6d, 0x31, 0x2b, 0x3b, 0x63, 0x92,
+ 0xd4, 0xfa, 0x97, 0x76, 0xdf, 0xc0, 0x54, 0xcc, 0xd2, 0xdd, 0x8d, 0xe8,
+ 0xff, 0x93, 0xd0, 0xb1, 0x15, 0xe8, 0xd8, 0x8d, 0xd0, 0xc1, 0x2b, 0x65,
+ 0xc4, 0xfe, 0x86, 0xd5, 0x32, 0x82, 0x6d, 0xd2, 0xf0, 0xd6, 0x8f, 0xa0,
+ 0x5d, 0x44, 0x7f, 0x71, 0x4d, 0x6b, 0x79, 0x29, 0x38, 0x7b, 0xab, 0x13,
+ 0xce, 0xbe, 0xea, 0x4a, 0x1d, 0xd4, 0xe3, 0xb9, 0x62, 0x60, 0x3d, 0x5d,
+ 0xa2, 0xed, 0x9a, 0x0e, 0x72, 0xc0, 0xc9, 0x3e, 0xd0, 0xdd, 0x53, 0x93,
+ 0xf0, 0xef, 0x29, 0x97, 0x01, 0xf3, 0x19, 0xc0, 0x3c, 0x33, 0xe9, 0x44,
+ 0xb6, 0x81, 0x30, 0x40, 0x33, 0x33, 0xd5, 0x2b, 0x0b, 0x73, 0xa4, 0x43,
+ 0xc8, 0x80, 0x49, 0xac, 0x67, 0xb0, 0x0e, 0x76, 0x00, 0xc7, 0x87, 0xdc,
+ 0x9e, 0xda, 0xa6, 0xdf, 0x19, 0x7d, 0xde, 0x2e, 0x0b, 0x95, 0x3b, 0x2d,
+ 0x6c, 0xc7, 0xea, 0x60, 0x5b, 0xb7, 0x04, 0xdb, 0x3e, 0xc0, 0xb6, 0x7f,
+ 0x4d, 0xd8, 0xd6, 0xd2, 0xc5, 0x1d, 0xb0, 0x69, 0xc8, 0x1f, 0x11, 0x5e,
+ 0xdb, 0x2c, 0x3d, 0x94, 0xac, 0x1d, 0x4c, 0x9b, 0xe8, 0x87, 0x80, 0x87,
+ 0x34, 0x86, 0xdf, 0xb3, 0x8f, 0x52, 0x96, 0xa1, 0x9c, 0xcf, 0x0f, 0xa1,
+ 0x0e, 0x9e, 0x67, 0x13, 0x56, 0x0e, 0x7e, 0xc2, 0xc2, 0x42, 0x3b, 0x21,
+ 0x0b, 0x5b, 0x79, 0xd0, 0xc9, 0xcd, 0x12, 0x86, 0x53, 0x80, 0x17, 0xef,
+ 0xaa, 0xf5, 0x7d, 0xf2, 0xce, 0x7e, 0xaf, 0xb2, 0xfd, 0xb0, 0xef, 0x68,
+ 0x2e, 0xeb, 0xad, 0x9e, 0x8f, 0xe8, 0x2b, 0xb2, 0xbb, 0x27, 0x9c, 0xec,
+ 0xaa, 0x79, 0xd5, 0xd3, 0x1c, 0xe5, 0xad, 0x2b, 0x43, 0xa0, 0x93, 0xa1,
+ 0x65, 0xb4, 0xa6, 0xdd, 0x13, 0x4b, 0xc7, 0xeb, 0xec, 0xfc, 0x0e, 0x1b,
+ 0xbe, 0x09, 0xe2, 0xd0, 0x87, 0x94, 0x37, 0xff, 0xc5, 0xf8, 0xec, 0xf2,
+ 0xe5, 0x06, 0xc6, 0x69, 0xcd, 0x33, 0x69, 0x93, 0xbf, 0x29, 0x93, 0x6a,
+ 0xb4, 0x68, 0x7c, 0x9a, 0x76, 0x8c, 0x55, 0x6f, 0xc7, 0xbb, 0x32, 0x6c,
+ 0xd6, 0xfc, 0x18, 0xd7, 0x9c, 0x3e, 0x4a, 0xe7, 0x03, 0xc3, 0x96, 0xbf,
+ 0xd2, 0x93, 0x05, 0xb9, 0xd5, 0xce, 0xfd, 0xd2, 0x1a, 0x6b, 0xb7, 0x71,
+ 0x69, 0xed, 0x86, 0xab, 0x2b, 0xe7, 0x28, 0xd2, 0xf1, 0x80, 0xab, 0x7d,
+ 0x5e, 0xfa, 0xf0, 0x8d, 0x3e, 0xe5, 0x27, 0x6d, 0x25, 0x94, 0xcf, 0xf4,
+ 0x78, 0xad, 0xf0, 0x0d, 0xbe, 0xb8, 0xca, 0xee, 0x4a, 0x59, 0xb9, 0x49,
+ 0xff, 0x38, 0x1a, 0xa3, 0x60, 0xe5, 0x64, 0x01, 0xfd, 0x4f, 0x38, 0x43,
+ 0xd5, 0xb5, 0xe4, 0x65, 0x24, 0x27, 0x39, 0x9f, 0x7b, 0xe5, 0x8e, 0x07,
+ 0xc9, 0xa3, 0x25, 0x6d, 0x5f, 0x5f, 0xb3, 0xe7, 0x30, 0xf0, 0x47, 0xf8,
+ 0x17, 0x36, 0xc3, 0x64, 0x80, 0xce, 0xcd, 0xca, 0xa8, 0x5d, 0xb7, 0xd1,
+ 0xa5, 0xf5, 0xe7, 0x35, 0x0c, 0xdd, 0xc8, 0x58, 0xae, 0xb2, 0x30, 0x6b,
+ 0x3b, 0x16, 0x76, 0xdd, 0x4a, 0x5b, 0x96, 0x73, 0xa0, 0x3d, 0xdb, 0x68,
+ 0x6c, 0xc1, 0x32, 0xed, 0x4f, 0xca, 0x2e, 0xda, 0x9f, 0x57, 0x37, 0x4a,
+ 0x33, 0xe7, 0x93, 0xb5, 0x65, 0xb4, 0x53, 0x57, 0xce, 0x6f, 0xa5, 0x5f,
+ 0x49, 0x38, 0x09, 0xb7, 0xa1, 0xad, 0x94, 0x22, 0x6c, 0xa1, 0x0c, 0x07,
+ 0xd7, 0xe9, 0x35, 0x50, 0xb4, 0x5d, 0xf7, 0x34, 0x34, 0x9a, 0x38, 0xf6,
+ 0x5e, 0xf4, 0xcf, 0x31, 0xc9, 0x7f, 0xbc, 0xd3, 0xce, 0x5f, 0x4b, 0x96,
+ 0xd5, 0xeb, 0x9e, 0x2b, 0x97, 0xf0, 0x37, 0xb4, 0x6c, 0x8d, 0x22, 0xfc,
+ 0x45, 0x74, 0x51, 0x8f, 0x43, 0xd2, 0x04, 0x69, 0x21, 0xa2, 0xc5, 0x9d,
+ 0x56, 0xdf, 0x44, 0xb4, 0xb7, 0x15, 0xb4, 0x77, 0x1f, 0xf0, 0x44, 0x19,
+ 0xce, 0x78, 0xde, 0x16, 0x3c, 0x1f, 0xc7, 0x73, 0xc4, 0x27, 0x91, 0x0c,
+ 0xa7, 0x4d, 0xb4, 0x52, 0x8e, 0x53, 0x86, 0xc7, 0x61, 0xf7, 0x50, 0xd6,
+ 0x6f, 0xb7, 0xfc, 0x94, 0xb3, 0xbc, 0x44, 0x5d, 0xf0, 0xfb, 0xe8, 0xe7,
+ 0x86, 0x46, 0x63, 0xa7, 0x17, 0x1b, 0x29, 0x5f, 0x37, 0xcb, 0x91, 0xba,
+ 0xb2, 0xcb, 0xc9, 0xef, 0xfa, 0x39, 0x6f, 0xff, 0x7f, 0x30, 0xe7, 0xe4,
+ 0x8a, 0x39, 0x7b, 0x76, 0xce, 0x55, 0xbc, 0x6f, 0xc5, 0xfb, 0x16, 0xea,
+ 0x82, 0x54, 0x4d, 0xde, 0x58, 0x5c, 0x68, 0x7d, 0x56, 0x2f, 0x27, 0x22,
+ 0x19, 0xc1, 0x79, 0x1d, 0xb5, 0x73, 0xf8, 0x7c, 0xdd, 0xbc, 0x8e, 0xbe,
+ 0x89, 0x79, 0xb5, 0x2f, 0x9b, 0xd7, 0xde, 0xcb, 0xce, 0x6b, 0x2d, 0x1e,
+ 0x27, 0x2f, 0x47, 0xf3, 0x8b, 0xcb, 0x81, 0x12, 0xe7, 0x38, 0x84, 0x39,
+ 0x12, 0x86, 0x68, 0x8e, 0x19, 0x3b, 0x47, 0x51, 0x1d, 0x7b, 0x7e, 0x0a,
+ 0xbf, 0xeb, 0xe7, 0x47, 0xdd, 0xff, 0xf7, 0xa0, 0xe9, 0x26, 0xf8, 0xc4,
+ 0x4d, 0x56, 0xfe, 0x3f, 0x29, 0xb7, 0x96, 0xb9, 0xd6, 0xe9, 0xac, 0xc8,
+ 0x7e, 0x75, 0xa8, 0xfc, 0x72, 0x23, 0xf7, 0x11, 0xf6, 0x06, 0x56, 0x8f,
+ 0x41, 0x5f, 0xec, 0x83, 0xcd, 0x37, 0x54, 0x52, 0x7d, 0x31, 0x09, 0xc3,
+ 0xdb, 0x82, 0x66, 0x8c, 0xbd, 0x49, 0xfb, 0xaa, 0xab, 0x63, 0xf8, 0xcf,
+ 0x36, 0x8a, 0x4f, 0x7b, 0x83, 0xfa, 0x1c, 0xfa, 0xee, 0x24, 0x6d, 0xb0,
+ 0x1c, 0xec, 0xe4, 0x6c, 0x32, 0xa6, 0x6d, 0x31, 0xea, 0xc4, 0x74, 0x32,
+ 0x2b, 0x15, 0xc9, 0x9f, 0xcc, 0x26, 0xe1, 0xd8, 0x62, 0x0c, 0xd8, 0x6a,
+ 0xb0, 0x21, 0x6f, 0x85, 0xac, 0xb9, 0xb5, 0x7a, 0x50, 0xdd, 0x02, 0x7b,
+ 0xe7, 0x96, 0xd3, 0xef, 0x53, 0xb7, 0xc1, 0xd6, 0xb9, 0xed, 0xf4, 0x8d,
+ 0xea, 0x10, 0x6c, 0x9b, 0x43, 0xb0, 0x73, 0x0e, 0x55, 0x69, 0x7b, 0xde,
+ 0x0c, 0xba, 0x6b, 0x87, 0x1e, 0xe2, 0x5c, 0xb8, 0x26, 0xb4, 0x71, 0x38,
+ 0x3f, 0xe2, 0xfe, 0x0b, 0x5c, 0x83, 0x20, 0xa5, 0x76, 0x34, 0x71, 0x5d,
+ 0x5a, 0x97, 0x95, 0xbd, 0x96, 0xac, 0x8a, 0xf4, 0xd3, 0x06, 0x1b, 0x4f,
+ 0x32, 0x7e, 0xe5, 0xe5, 0x69, 0x8b, 0x34, 0xe2, 0x01, 0xcf, 0xc4, 0x1f,
+ 0x69, 0xab, 0x7e, 0xfe, 0x57, 0x36, 0x89, 0x9f, 0xc3, 0xf8, 0xf7, 0x42,
+ 0xbe, 0xd6, 0xd3, 0x14, 0xef, 0x5e, 0x1d, 0x7f, 0x50, 0x06, 0x47, 0xf4,
+ 0xb0, 0xf3, 0x35, 0xe4, 0xef, 0x65, 0xe9, 0xe9, 0x9e, 0x58, 0x26, 0x0c,
+ 0x47, 0xfb, 0x64, 0x13, 0xe3, 0x01, 0xb9, 0x6a, 0x2d, 0x26, 0xa0, 0xfc,
+ 0xfa, 0x98, 0x00, 0xfd, 0xac, 0x4f, 0x03, 0xbf, 0xd3, 0xb8, 0x44, 0x46,
+ 0x18, 0x77, 0xa8, 0x46, 0x76, 0xf9, 0x57, 0xac, 0x5d, 0x1e, 0xc1, 0x91,
+ 0x02, 0x1c, 0x46, 0x3e, 0xaf, 0xd6, 0x73, 0xcb, 0xf5, 0x77, 0x61, 0xc9,
+ 0xa6, 0x4d, 0xc9, 0x81, 0xb2, 0xb6, 0x13, 0x21, 0x83, 0x89, 0x9b, 0x7a,
+ 0x19, 0x9c, 0xb4, 0x76, 0x14, 0xea, 0x68, 0xf9, 0xb9, 0x5a, 0x76, 0x52,
+ 0xee, 0x31, 0x6e, 0xff, 0x40, 0x40, 0x5a, 0x7f, 0x97, 0x64, 0x97, 0xe2,
+ 0xf6, 0x02, 0x7a, 0x93, 0x20, 0x96, 0xd1, 0x7b, 0x7a, 0xde, 0x8c, 0xec,
+ 0x93, 0x81, 0x04, 0x63, 0xa0, 0x8c, 0xf3, 0xf9, 0x85, 0x19, 0xe9, 0x66,
+ 0x8c, 0x03, 0x16, 0x7c, 0xa3, 0x8c, 0x78, 0xa1, 0xec, 0x0d, 0x1c, 0x1d,
+ 0x53, 0x36, 0xba, 0xf6, 0x62, 0x93, 0xb1, 0x5d, 0x1d, 0x1d, 0x17, 0x5e,
+ 0x00, 0xf5, 0x2d, 0x68, 0xfb, 0x56, 0x69, 0xfd, 0x3b, 0xaf, 0xeb, 0xfc,
+ 0x41, 0x53, 0x14, 0xdf, 0x5c, 0xf0, 0x62, 0xb6, 0x5e, 0x7d, 0xf9, 0xd7,
+ 0x6c, 0xdc, 0xba, 0x1b, 0xb2, 0x3f, 0x2a, 0xfb, 0xde, 0x1a, 0x65, 0xb1,
+ 0xf8, 0xea, 0xb2, 0xcd, 0x6b, 0x94, 0x99, 0x78, 0xe1, 0x50, 0x69, 0x27,
+ 0xde, 0x4d, 0x68, 0xdf, 0x5d, 0xf4, 0x9e, 0x5b, 0xb7, 0x14, 0x96, 0xea,
+ 0x6c, 0xb0, 0x7e, 0x19, 0x63, 0xc7, 0x26, 0x66, 0x9c, 0xd7, 0x31, 0xe3,
+ 0x1e, 0x6f, 0x8f, 0xd2, 0x7b, 0x2c, 0xb7, 0x33, 0xfe, 0x78, 0x48, 0xe3,
+ 0x85, 0x38, 0xf9, 0x02, 0x63, 0xc3, 0x05, 0xee, 0x0f, 0xa7, 0xd4, 0xe5,
+ 0x68, 0xbb, 0x66, 0x9b, 0x98, 0x75, 0xa3, 0x5d, 0xdc, 0x22, 0x83, 0xb0,
+ 0x15, 0x86, 0x4a, 0xad, 0xb2, 0x77, 0xea, 0xa3, 0xeb, 0xa8, 0xb7, 0xf6,
+ 0x4d, 0x19, 0x7f, 0xf0, 0x10, 0xf8, 0x2a, 0x2b, 0x84, 0x31, 0x1d, 0x88,
+ 0xd0, 0x26, 0x5e, 0x6d, 0x0b, 0xbf, 0x76, 0x7f, 0xf7, 0x5f, 0xa6, 0x3f,
+ 0x07, 0xb6, 0xc3, 0x1b, 0xed, 0xaf, 0x59, 0x06, 0xa7, 0x22, 0x5c, 0xa9,
+ 0x1f, 0xb1, 0x5d, 0xec, 0x32, 0xed, 0xb4, 0x5d, 0x22, 0x4f, 0x2d, 0xc9,
+ 0xe2, 0x9d, 0xb0, 0x99, 0x24, 0xcc, 0xf5, 0x49, 0x7b, 0x4c, 0x74, 0x8c,
+ 0x27, 0x30, 0xb2, 0xb9, 0x8b, 0x7b, 0x3e, 0xa0, 0x7f, 0x63, 0xab, 0x98,
+ 0x78, 0x6a, 0x64, 0xa7, 0xac, 0x45, 0xbb, 0xd7, 0x5b, 0xda, 0xe5, 0xbe,
+ 0xee, 0x3e, 0xca, 0x5c, 0xac, 0x89, 0xa1, 0xe3, 0xbd, 0x25, 0x49, 0x45,
+ 0x74, 0xbc, 0x20, 0xd9, 0x65, 0x74, 0xbc, 0x20, 0x83, 0x9a, 0x8e, 0x1b,
+ 0x97, 0xd1, 0x71, 0xbb, 0xa5, 0xe3, 0x8f, 0xc6, 0x0d, 0x5d, 0x28, 0xad,
+ 0xa7, 0x48, 0xa7, 0x86, 0x8e, 0x1d, 0x4d, 0xc7, 0x0b, 0xb8, 0xbb, 0xfe,
+ 0xc7, 0x6c, 0x9d, 0x98, 0x2d, 0xe3, 0xef, 0xa8, 0x8c, 0x72, 0x71, 0x2a,
+ 0x6e, 0xf4, 0xd2, 0x20, 0xe8, 0x28, 0x2a, 0xff, 0x4d, 0x4b, 0x9f, 0xf5,
+ 0x65, 0x26, 0x3e, 0x32, 0x54, 0x3a, 0xb2, 0x82, 0x3e, 0x07, 0x41, 0x9f,
+ 0x51, 0x9d, 0xd7, 0xa2, 0xcf, 0x66, 0xbb, 0x9f, 0x91, 0xd4, 0x7b, 0xff,
+ 0xd9, 0x84, 0xa1, 0xd5, 0x5b, 0xf4, 0xdc, 0x39, 0xef, 0x0b, 0x6f, 0x80,
+ 0x56, 0xcd, 0xda, 0x5c, 0xac, 0xf9, 0xdb, 0x8c, 0x45, 0xa5, 0x4c, 0x6c,
+ 0x9b, 0x71, 0xd2, 0xcb, 0xd9, 0x8e, 0x2f, 0xd5, 0xf9, 0x15, 0x1b, 0xa4,
+ 0xc0, 0xbc, 0x87, 0xea, 0x46, 0xc6, 0xa2, 0x47, 0xdc, 0x4c, 0x9f, 0x64,
+ 0x2b, 0xed, 0xa9, 0x62, 0x89, 0x7e, 0xd1, 0xab, 0x36, 0x37, 0x02, 0xcf,
+ 0x95, 0x16, 0x79, 0xb4, 0x44, 0xda, 0x3a, 0x62, 0x70, 0xb1, 0x26, 0xad,
+ 0x73, 0xad, 0xd9, 0x4f, 0xbd, 0x0e, 0xe8, 0x83, 0xee, 0xa1, 0xcd, 0xae,
+ 0xe5, 0x3e, 0xde, 0xb5, 0xa7, 0x72, 0xa5, 0xa8, 0x5f, 0xee, 0x3f, 0x70,
+ 0x4f, 0xb8, 0x3d, 0xd5, 0x51, 0xf1, 0x6d, 0x9c, 0x79, 0x23, 0x9e, 0xfb,
+ 0xa4, 0xa3, 0xa2, 0xe4, 0x03, 0x53, 0x2d, 0x72, 0x7b, 0xc9, 0x95, 0x0f,
+ 0xa1, 0xfd, 0x07, 0x4b, 0x1e, 0xfc, 0xfb, 0xff, 0x1d, 0xa7, 0x9d, 0x79,
+ 0xa8, 0xc4, 0x7d, 0x50, 0x47, 0xdb, 0x2a, 0xcb, 0xf7, 0x86, 0x63, 0xd2,
+ 0xd1, 0x55, 0x84, 0xe7, 0x23, 0xee, 0x7e, 0xc0, 0xd1, 0x94, 0xc9, 0xc8,
+ 0x77, 0xfa, 0x36, 0xa1, 0x2c, 0xca, 0xf1, 0x18, 0x76, 0x4c, 0xfc, 0xb8,
+ 0x5f, 0xde, 0x59, 0xcd, 0xc8, 0x0d, 0x55, 0xb3, 0x77, 0x5b, 0xdb, 0x9b,
+ 0x4d, 0x7b, 0xf3, 0xd0, 0x67, 0x59, 0x2f, 0x0c, 0x2f, 0xfa, 0xa0, 0xa2,
+ 0xe3, 0xae, 0xc4, 0xbb, 0xd2, 0xc9, 0x79, 0x31, 0xcf, 0x97, 0x2a, 0xff,
+ 0x1c, 0x8e, 0x24, 0x5c, 0xf9, 0x8e, 0xcf, 0x39, 0xf6, 0xcb, 0xf5, 0x95,
+ 0xfa, 0xb1, 0xb9, 0x3f, 0x1b, 0x5b, 0xc7, 0xfd, 0x90, 0x5c, 0xf5, 0x9f,
+ 0xe3, 0x8c, 0xdb, 0xd3, 0x87, 0xe9, 0xf8, 0x31, 0xee, 0x87, 0xbb, 0xb8,
+ 0x83, 0x0e, 0x13, 0xb0, 0x21, 0xae, 0x01, 0x8c, 0xd7, 0x30, 0x96, 0xc6,
+ 0x18, 0x1a, 0x9f, 0xbf, 0x8c, 0x71, 0xd9, 0xf6, 0x93, 0xd6, 0xfe, 0x3e,
+ 0xb2, 0xc4, 0x8b, 0x6b, 0xeb, 0xb1, 0x8d, 0x23, 0xf1, 0x8c, 0x38, 0xf1,
+ 0x9f, 0x48, 0xca, 0x3a, 0xbf, 0x7e, 0x7c, 0xee, 0x47, 0xc3, 0xa2, 0xec,
+ 0x13, 0x77, 0xdf, 0xee, 0x7e, 0x19, 0xc4, 0xfc, 0x86, 0x56, 0xcd, 0xef,
+ 0x1e, 0x61, 0xbc, 0xf6, 0x52, 0x89, 0x73, 0xa8, 0xcd, 0x4b, 0xfd, 0xb6,
+ 0x99, 0x57, 0xbc, 0x6b, 0xe5, 0x7c, 0x74, 0x7b, 0x75, 0x0a, 0xb0, 0x7c,
+ 0x49, 0xe7, 0x42, 0x84, 0xe1, 0x5b, 0xbb, 0x2e, 0x85, 0xa9, 0x2b, 0xd2,
+ 0xdd, 0xf3, 0xb5, 0x7d, 0xa4, 0x91, 0x58, 0x26, 0xab, 0xf5, 0x23, 0x9e,
+ 0x53, 0xf9, 0xca, 0x7e, 0xac, 0xa3, 0xb8, 0xf9, 0x5e, 0x57, 0xf3, 0x5d,
+ 0xde, 0xdf, 0x6f, 0xf7, 0xca, 0x22, 0x9f, 0x2c, 0x0c, 0x95, 0xbf, 0x52,
+ 0x0e, 0x51, 0xff, 0x61, 0xee, 0xf2, 0x98, 0xdd, 0x3f, 0xe8, 0x66, 0x7c,
+ 0x0c, 0xb4, 0x18, 0x07, 0xdd, 0xf9, 0xf8, 0xdd, 0x82, 0xfb, 0x1e, 0xd8,
+ 0x3f, 0x01, 0xec, 0x23, 0x49, 0x28, 0x23, 0x6b, 0xc0, 0x1b, 0x5d, 0x05,
+ 0xa5, 0xc8, 0xeb, 0x5e, 0x6a, 0xbc, 0x92, 0x48, 0x4d, 0x56, 0x9e, 0x60,
+ 0x7b, 0xd4, 0x5d, 0x2b, 0x36, 0x68, 0xf2, 0x6c, 0xbe, 0x58, 0xe5, 0x18,
+ 0xa4, 0xfb, 0x37, 0x32, 0x86, 0x6b, 0xfb, 0x66, 0x9f, 0x11, 0x5e, 0x5c,
+ 0xba, 0xf8, 0xf8, 0xb7, 0xdf, 0xfa, 0x3a, 0x9c, 0xdf, 0x13, 0x16, 0xee,
+ 0x95, 0xe3, 0x3e, 0xaf, 0xed, 0xa1, 0xc7, 0xab, 0xb4, 0x41, 0xb9, 0x8f,
+ 0x94, 0x7e, 0x64, 0x5a, 0x08, 0x47, 0x18, 0x3e, 0x1b, 0x18, 0x5b, 0xe0,
+ 0x8b, 0x55, 0xee, 0x99, 0x84, 0xe1, 0xdf, 0xd2, 0xce, 0x3e, 0x58, 0xc6,
+ 0x78, 0x11, 0x0e, 0x76, 0x16, 0x5c, 0xc8, 0xd9, 0x89, 0x3e, 0xe2, 0x57,
+ 0xe0, 0xf1, 0x76, 0x79, 0x07, 0x24, 0x9e, 0xfa, 0x78, 0xa5, 0x25, 0x75,
+ 0x67, 0xc5, 0x03, 0x9e, 0x39, 0xef, 0x44, 0x6a, 0xcc, 0xce, 0x39, 0x5f,
+ 0x21, 0x7e, 0x5f, 0x6b, 0xbf, 0xf3, 0xf9, 0x65, 0xfe, 0x17, 0x61, 0xaa,
+ 0xc1, 0x42, 0xd8, 0x52, 0x16, 0x37, 0x61, 0xf8, 0xf7, 0x01, 0xc7, 0xdc,
+ 0x0f, 0x1f, 0x46, 0x26, 0x30, 0x6e, 0x61, 0x8b, 0x22, 0x1e, 0xe2, 0xa9,
+ 0x3b, 0x30, 0xf6, 0xc7, 0x31, 0xf6, 0xed, 0x15, 0x8e, 0x07, 0xd9, 0x83,
+ 0xb9, 0x4f, 0x54, 0x23, 0x78, 0xd7, 0x1a, 0x3b, 0x5a, 0xf3, 0x6e, 0x6b,
+ 0x33, 0x46, 0xcf, 0x1a, 0x91, 0x6d, 0x0a, 0xbe, 0x63, 0xae, 0xba, 0xb0,
+ 0xd9, 0x95, 0x9f, 0x81, 0x1c, 0x0f, 0xe5, 0x51, 0xc8, 0xc7, 0x05, 0x4d,
+ 0x37, 0xb9, 0xed, 0xfc, 0x3f, 0x26, 0x4f, 0xad, 0x63, 0xbc, 0x7a, 0xc0,
+ 0xa7, 0x2d, 0xbc, 0x18, 0x2e, 0xf8, 0x94, 0xf7, 0x1b, 0x64, 0xda, 0x2b,
+ 0x74, 0x43, 0xf7, 0xa0, 0x6c, 0x23, 0xfd, 0xf7, 0x54, 0x2e, 0x96, 0x4e,
+ 0x8d, 0x0b, 0x73, 0xbe, 0x98, 0x13, 0xc1, 0xbc, 0x26, 0xca, 0x06, 0x17,
+ 0x32, 0x94, 0x6b, 0x68, 0xc6, 0x1b, 0xaf, 0xd4, 0xea, 0x1e, 0x16, 0xee,
+ 0x4d, 0xa6, 0x93, 0x87, 0xb4, 0xbd, 0x23, 0x32, 0x5a, 0x62, 0xdd, 0xdd,
+ 0xb0, 0x76, 0xfc, 0xba, 0xfa, 0x3a, 0x57, 0x0d, 0x7c, 0x1e, 0xc5, 0xc5,
+ 0xe2, 0xcc, 0x29, 0x79, 0x39, 0xd6, 0x27, 0x2f, 0xd3, 0x8e, 0x1d, 0x00,
+ 0x6d, 0x7b, 0xbe, 0xce, 0x2b, 0xd1, 0xe5, 0xb9, 0x40, 0x16, 0x73, 0xfd,
+ 0x3d, 0xb4, 0xdb, 0x0b, 0x4a, 0xf3, 0x84, 0x28, 0xb4, 0x8d, 0xe7, 0x2b,
+ 0x32, 0x98, 0x2f, 0xd9, 0xd8, 0xd1, 0x30, 0xe7, 0xbc, 0xa1, 0x6e, 0xee,
+ 0x1b, 0xc5, 0x05, 0x4c, 0x83, 0xb1, 0x94, 0xd3, 0xe0, 0x7f, 0xaa, 0xc5,
+ 0xd8, 0x10, 0xd0, 0x23, 0xad, 0xf7, 0xb7, 0x71, 0x6f, 0x56, 0xc1, 0x27,
+ 0x57, 0x6d, 0x1f, 0xbe, 0x56, 0x65, 0xfe, 0x32, 0x09, 0xbd, 0x6a, 0x65,
+ 0x65, 0x7c, 0xb0, 0x63, 0x89, 0xbe, 0x39, 0xbe, 0xb4, 0xc5, 0xfc, 0xd4,
+ 0xe0, 0x40, 0x45, 0x54, 0x2c, 0xe3, 0xc5, 0x07, 0x2a, 0xcb, 0x69, 0xfe,
+ 0x8b, 0xd5, 0xcf, 0x5a, 0xdb, 0xb2, 0x3e, 0x46, 0x5b, 0xff, 0x8e, 0x7c,
+ 0xb7, 0x6c, 0xff, 0x23, 0x05, 0xbe, 0xb2, 0xfb, 0xc6, 0x5c, 0x93, 0xec,
+ 0x5b, 0x19, 0xd8, 0x9c, 0xd6, 0x3e, 0x1f, 0x73, 0x3b, 0xe2, 0x36, 0xbf,
+ 0xce, 0xe0, 0x3a, 0x5b, 0x71, 0x64, 0x02, 0xf2, 0xe1, 0xb0, 0xfc, 0x53,
+ 0x98, 0x4d, 0x98, 0xf7, 0x66, 0x7d, 0x59, 0x9f, 0x7b, 0x1b, 0xcd, 0x52,
+ 0x3c, 0xed, 0x4a, 0xe1, 0x34, 0xf7, 0xd4, 0xce, 0xdd, 0x51, 0xcb, 0x0f,
+ 0xa1, 0x1c, 0xe0, 0xbe, 0xb0, 0x23, 0x45, 0xf8, 0xc8, 0x83, 0xdc, 0xef,
+ 0xef, 0xfd, 0x47, 0xe6, 0xea, 0xc4, 0xb9, 0x4e, 0xa6, 0x6d, 0x0b, 0xda,
+ 0x36, 0xda, 0xb6, 0xc1, 0xc7, 0xdf, 0x5c, 0xdb, 0x8d, 0x68, 0x1b, 0x8f,
+ 0xc6, 0x7d, 0x83, 0x6d, 0x35, 0x3e, 0xaf, 0x1d, 0x28, 0x95, 0x17, 0x5d,
+ 0xdf, 0x4f, 0x8e, 0x49, 0xd6, 0x19, 0xed, 0xd3, 0xf3, 0xb9, 0x76, 0xa0,
+ 0x02, 0x38, 0x12, 0x61, 0x58, 0x0c, 0x22, 0xbd, 0xce, 0x7f, 0x27, 0xa1,
+ 0xde, 0x59, 0xc6, 0x7d, 0x50, 0xfa, 0x27, 0x8c, 0xba, 0x7a, 0xcc, 0xc1,
+ 0x93, 0x22, 0xf7, 0x3b, 0x13, 0x9b, 0x70, 0x57, 0x1d, 0xc4, 0x49, 0xde,
+ 0x67, 0xfc, 0x78, 0x93, 0x2d, 0x8f, 0xb1, 0x3c, 0xed, 0x42, 0x96, 0x98,
+ 0xf2, 0x98, 0x2d, 0x07, 0x4c, 0x41, 0x31, 0x05, 0x6e, 0xb3, 0xe5, 0x7c,
+ 0x56, 0xba, 0xdc, 0x3c, 0x1b, 0x1e, 0x1a, 0x11, 0xc6, 0x89, 0x72, 0xd7,
+ 0x37, 0xc8, 0x4e, 0xac, 0x0f, 0x7d, 0x50, 0x47, 0x9a, 0x01, 0xc7, 0xc5,
+ 0xe0, 0xc7, 0x61, 0xab, 0x87, 0xf2, 0x9d, 0xc0, 0xd0, 0xff, 0x8c, 0x74,
+ 0x65, 0x95, 0xc3, 0x5c, 0x83, 0x50, 0x86, 0x82, 0x5d, 0xc9, 0xbd, 0xf8,
+ 0x3d, 0xda, 0x9b, 0x92, 0x99, 0x7e, 0xd0, 0x63, 0x2f, 0x79, 0x63, 0x27,
+ 0x6c, 0x28, 0xfc, 0xee, 0x6a, 0x91, 0x45, 0xaf, 0xe0, 0xad, 0x83, 0xff,
+ 0x37, 0x88, 0x59, 0xcd, 0x96, 0x7c, 0xef, 0x36, 0x08, 0xb9, 0xac, 0xd7,
+ 0x85, 0x7b, 0xfd, 0x7c, 0xbf, 0x8e, 0xf9, 0x9e, 0x6b, 0x96, 0x66, 0x96,
+ 0xd7, 0xd7, 0x6d, 0x94, 0xfd, 0xde, 0x6e, 0x2f, 0xbe, 0xac, 0xee, 0x25,
+ 0xd4, 0x65, 0x99, 0xef, 0x31, 0x17, 0x68, 0xa6, 0x42, 0x3a, 0x33, 0xb0,
+ 0x76, 0x74, 0x85, 0xe1, 0xf5, 0x01, 0xc7, 0x0d, 0xc3, 0x1b, 0x82, 0x1e,
+ 0xef, 0x19, 0x79, 0x2e, 0x34, 0x36, 0x5a, 0x44, 0x3b, 0xcf, 0x5a, 0x79,
+ 0x1d, 0x86, 0x2f, 0x07, 0xdd, 0xf2, 0xb9, 0x6a, 0xfa, 0x1c, 0x7d, 0xf8,
+ 0xf3, 0x78, 0x3e, 0x1f, 0x98, 0xfc, 0xa5, 0x3f, 0x43, 0xbb, 0x84, 0xea,
+ 0x05, 0x0d, 0xfb, 0xf2, 0x59, 0xed, 0xf3, 0x13, 0x7f, 0x66, 0xcf, 0xa0,
+ 0x06, 0x03, 0x26, 0xec, 0xe7, 0x36, 0x7b, 0xcc, 0x69, 0xd4, 0xf4, 0x5b,
+ 0xff, 0x4e, 0xe1, 0x1d, 0xcb, 0xc2, 0xf0, 0x8a, 0xbe, 0x96, 0xf5, 0xd0,
+ 0xd7, 0x93, 0xdc, 0x0b, 0x7c, 0x9f, 0xe6, 0x3f, 0x91, 0x03, 0xdc, 0xf7,
+ 0x02, 0x0e, 0x95, 0xf2, 0x8f, 0x75, 0xa8, 0x74, 0x41, 0xe4, 0x2d, 0x58,
+ 0x7f, 0xae, 0x31, 0x18, 0xa4, 0x15, 0xb0, 0xef, 0xfa, 0xa5, 0x66, 0x13,
+ 0x9b, 0xa2, 0x6f, 0x9e, 0xdd, 0x0c, 0xdf, 0x59, 0xdb, 0x33, 0xdc, 0x57,
+ 0x1f, 0x6b, 0x0d, 0xc3, 0xf7, 0x06, 0xd1, 0x9a, 0xd9, 0xd8, 0x37, 0x74,
+ 0x7c, 0xbe, 0x57, 0xd6, 0x1b, 0xbb, 0x90, 0xb9, 0x8d, 0x29, 0xbd, 0x4f,
+ 0xa0, 0xda, 0xa0, 0x43, 0x76, 0xfd, 0x00, 0x38, 0xe5, 0x18, 0xcc, 0x73,
+ 0x8c, 0x60, 0xaa, 0xb5, 0xcf, 0xf7, 0xae, 0xb3, 0x36, 0xac, 0x0b, 0x5c,
+ 0xfa, 0x5e, 0x87, 0xfa, 0x5e, 0x68, 0x74, 0x6b, 0x44, 0xc3, 0xff, 0x10,
+ 0x3e, 0x98, 0x30, 0xcf, 0xb9, 0x5d, 0xec, 0x63, 0xa7, 0x8c, 0xef, 0xc2,
+ 0xb3, 0x7b, 0x1d, 0xee, 0x03, 0x57, 0xc6, 0xe4, 0xaa, 0xe4, 0x80, 0xda,
+ 0xe5, 0x3d, 0x28, 0x3d, 0x56, 0xc6, 0x7d, 0x09, 0xfa, 0xbe, 0x00, 0xff,
+ 0xbe, 0x49, 0x1e, 0x04, 0x4d, 0xab, 0xbe, 0x74, 0x6a, 0x5e, 0xa5, 0xbb,
+ 0xa7, 0x55, 0x3a, 0x18, 0x51, 0x13, 0x9c, 0x57, 0x3f, 0x71, 0x31, 0x4d,
+ 0xfc, 0x96, 0x81, 0xff, 0x32, 0x70, 0x7c, 0xd9, 0x3d, 0xe3, 0xc0, 0xea,
+ 0x16, 0xa3, 0xdf, 0x0a, 0x9a, 0x36, 0x8d, 0x9d, 0xff, 0xa7, 0x41, 0xb4,
+ 0x86, 0x3d, 0x5e, 0x03, 0x73, 0x71, 0xd6, 0x5c, 0xa3, 0x3c, 0xd7, 0x08,
+ 0x8a, 0xa1, 0x00, 0xba, 0x4f, 0xa7, 0xc6, 0xd4, 0x62, 0xb8, 0x79, 0x4f,
+ 0x67, 0xf7, 0x63, 0xba, 0x9f, 0x74, 0x90, 0x55, 0x4f, 0x02, 0x9e, 0x9d,
+ 0xd2, 0xb4, 0x87, 0x78, 0x26, 0xac, 0x71, 0xc6, 0xa7, 0xbc, 0x3b, 0x50,
+ 0x77, 0x44, 0xe9, 0x3d, 0x6d, 0x5b, 0x87, 0x30, 0xbf, 0x1b, 0xf8, 0xa5,
+ 0x1e, 0x62, 0xcc, 0xed, 0xb5, 0x74, 0x21, 0x64, 0xd2, 0x49, 0xca, 0xc0,
+ 0x98, 0x89, 0x25, 0x57, 0xef, 0xe4, 0xfa, 0xd3, 0x13, 0x88, 0xbb, 0x90,
+ 0x51, 0x13, 0xe0, 0xe2, 0xa3, 0x27, 0xc5, 0x6d, 0xf0, 0xbb, 0xd7, 0x1b,
+ 0x3f, 0x8c, 0x3e, 0x19, 0xc7, 0x6e, 0x90, 0xe2, 0xaa, 0xf8, 0xcd, 0x24,
+ 0xe0, 0x6f, 0x96, 0xf1, 0x93, 0x5c, 0x0b, 0x17, 0x32, 0x87, 0x63, 0x8b,
+ 0x9b, 0xeb, 0x0d, 0xc3, 0x51, 0x96, 0x9f, 0x26, 0xff, 0x4a, 0x9a, 0xef,
+ 0x0a, 0xa7, 0xe7, 0x37, 0xab, 0x65, 0xb2, 0xb6, 0xc5, 0xc2, 0xa1, 0xf1,
+ 0x24, 0x93, 0x5a, 0x8e, 0x50, 0xdf, 0xcc, 0xd4, 0xc1, 0x13, 0x7c, 0x7c,
+ 0xc2, 0x6f, 0x7c, 0x13, 0xf0, 0xfc, 0x0f, 0xc0, 0xd3, 0x62, 0xe1, 0x69,
+ 0x5c, 0x01, 0x4f, 0x4b, 0x04, 0x0f, 0xe4, 0x1c, 0xe5, 0x6a, 0xfc, 0xda,
+ 0x6c, 0x45, 0x9c, 0xa2, 0x2f, 0xed, 0x4a, 0xfb, 0x43, 0xd4, 0x37, 0x8d,
+ 0xde, 0x68, 0x9f, 0x27, 0xa3, 0x5a, 0xd7, 0xb8, 0xd7, 0x76, 0x56, 0xe6,
+ 0x61, 0xbd, 0x8a, 0x93, 0xf3, 0x09, 0xfb, 0x5a, 0x76, 0xd5, 0x3d, 0x90,
+ 0xff, 0x0b, 0x69, 0xd7, 0xda, 0x12, 0x93, 0x01, 0xfd, 0xa0, 0x84, 0xce,
+ 0x15, 0xa8, 0xc1, 0xf4, 0x12, 0x60, 0x82, 0x3c, 0x3e, 0xd9, 0xe3, 0x0d,
+ 0xcb, 0x56, 0xed, 0xeb, 0x59, 0x5c, 0x63, 0x6e, 0xf1, 0xba, 0xb9, 0x41,
+ 0xff, 0xa9, 0x68, 0x6e, 0x90, 0x89, 0xa8, 0x37, 0x29, 0x7f, 0x64, 0x71,
+ 0xb1, 0x11, 0x73, 0x8a, 0xd7, 0xcd, 0xa7, 0x33, 0x79, 0x3b, 0xcb, 0xcc,
+ 0x7c, 0xba, 0x8a, 0x7e, 0xdc, 0xe2, 0x77, 0x2d, 0x9f, 0xc4, 0xd8, 0x3d,
+ 0xd3, 0x12, 0xca, 0x44, 0x80, 0x35, 0xea, 0xa6, 0x7f, 0x12, 0xb7, 0xb9,
+ 0xd7, 0x0a, 0xcf, 0x1b, 0x2c, 0x7f, 0x79, 0x52, 0xd4, 0xfe, 0xe0, 0xdf,
+ 0x59, 0x3e, 0x75, 0x6d, 0x9e, 0x1c, 0x7f, 0x1f, 0x5c, 0x6f, 0xf3, 0x05,
+ 0x0a, 0x59, 0x79, 0x65, 0x3d, 0xed, 0x92, 0x06, 0xff, 0x57, 0x56, 0x94,
+ 0xc5, 0x51, 0x76, 0x6a, 0xbd, 0x95, 0x0b, 0x28, 0xbb, 0x07, 0x7e, 0x1f,
+ 0xf3, 0x3e, 0xf8, 0x8e, 0x32, 0xb8, 0x1e, 0x27, 0x3d, 0x60, 0x45, 0xf2,
+ 0x3c, 0xe5, 0x22, 0x6d, 0x4a, 0xcc, 0x51, 0x6d, 0x8f, 0xe2, 0xf2, 0xf8,
+ 0xbd, 0x96, 0xed, 0x4f, 0x7c, 0x13, 0xd7, 0xf2, 0x8d, 0x09, 0xf0, 0xfd,
+ 0xe1, 0xc0, 0x71, 0x67, 0x98, 0x57, 0xa0, 0x69, 0xb8, 0xbe, 0xef, 0x1b,
+ 0x18, 0x26, 0xb4, 0xb4, 0x4c, 0x7a, 0x21, 0x4f, 0x3b, 0xd2, 0x44, 0x5d,
+ 0x7c, 0xd2, 0xd3, 0x39, 0xee, 0x39, 0xad, 0x97, 0xeb, 0xd7, 0xb1, 0x09,
+ 0xba, 0x26, 0x61, 0x78, 0xd4, 0x33, 0xfb, 0xe7, 0xb5, 0xfe, 0x46, 0xd0,
+ 0x1f, 0xed, 0x34, 0xf8, 0xfd, 0x3e, 0xa3, 0x43, 0x94, 0x5f, 0x8e, 0xab,
+ 0xae, 0xd6, 0x7e, 0x6b, 0x5c, 0xe7, 0x37, 0x2d, 0xd5, 0x1d, 0xb3, 0x63,
+ 0x93, 0x6e, 0xcd, 0x7e, 0x42, 0x6d, 0x7c, 0x71, 0xd4, 0x2e, 0x01, 0x95,
+ 0x35, 0xca, 0x44, 0x1f, 0x69, 0x94, 0x73, 0xd7, 0x36, 0xd4, 0xb5, 0xb4,
+ 0x23, 0x0c, 0x7d, 0xd2, 0x76, 0x72, 0xaf, 0xcd, 0x97, 0x1a, 0x8d, 0xcf,
+ 0x92, 0x90, 0x2d, 0x0d, 0x3a, 0x2f, 0x01, 0x65, 0x95, 0x48, 0x97, 0xb9,
+ 0x32, 0xd3, 0xfb, 0x7f, 0xc2, 0xec, 0x41, 0xd6, 0x5d, 0x33, 0x0f, 0x20,
+ 0x39, 0x2d, 0x1a, 0x4f, 0x5f, 0xab, 0xe1, 0xc9, 0xce, 0x2d, 0xb1, 0x72,
+ 0x6e, 0x70, 0x6a, 0xfd, 0x7b, 0x20, 0x3b, 0xb9, 0x4e, 0x26, 0xe7, 0xfc,
+ 0x9c, 0x38, 0x6e, 0xae, 0x7b, 0xad, 0xb9, 0x4d, 0x46, 0x78, 0xe5, 0xdc,
+ 0x40, 0xab, 0xd1, 0xbc, 0x48, 0xdb, 0x09, 0xbd, 0xef, 0xa4, 0x14, 0x61,
+ 0xd9, 0xb8, 0x02, 0xb7, 0x11, 0xdd, 0x19, 0x9a, 0xfb, 0xa2, 0xa6, 0xb9,
+ 0x16, 0x4b, 0x73, 0xa8, 0xeb, 0x71, 0x1f, 0xfd, 0xbe, 0x96, 0x1a, 0xcd,
+ 0x6d, 0xb0, 0x34, 0xa7, 0x5a, 0xcc, 0x1e, 0x7b, 0xb9, 0xc5, 0xec, 0x71,
+ 0x25, 0x57, 0x3c, 0xbf, 0x93, 0xcf, 0xf0, 0xc5, 0xa2, 0xe7, 0x7a, 0x58,
+ 0xcf, 0x03, 0xd6, 0x7a, 0x59, 0xd3, 0x64, 0xe3, 0x78, 0xdc, 0x8f, 0xa7,
+ 0xdf, 0xe7, 0xca, 0xa3, 0xb0, 0x83, 0x8a, 0x95, 0x1f, 0x84, 0xf3, 0xf0,
+ 0xfd, 0x26, 0x96, 0x74, 0xef, 0x4c, 0x0b, 0xf9, 0x6d, 0x1a, 0xbf, 0x8e,
+ 0xd4, 0xf9, 0x3c, 0x98, 0x2f, 0xca, 0xfe, 0x19, 0xeb, 0x01, 0xb9, 0xbc,
+ 0x54, 0x97, 0x31, 0x10, 0xe3, 0xe3, 0x9c, 0xab, 0xb6, 0xdb, 0xfd, 0x49,
+ 0xca, 0xf9, 0xbb, 0xe1, 0x13, 0xdd, 0x03, 0x3d, 0x49, 0xfa, 0xee, 0xd8,
+ 0x60, 0xf2, 0x89, 0x13, 0xd0, 0x63, 0x3f, 0x6f, 0x73, 0xab, 0x6e, 0xbf,
+ 0x7d, 0xed, 0x5c, 0x62, 0xd0, 0xbe, 0x43, 0x9a, 0x79, 0xdb, 0x06, 0x13,
+ 0x83, 0xde, 0xba, 0x81, 0x7c, 0xa6, 0x76, 0xed, 0xda, 0xa8, 0xf9, 0xc2,
+ 0x89, 0x9e, 0xab, 0x2b, 0x9e, 0xa3, 0x76, 0x7f, 0xb3, 0x71, 0x79, 0xbb,
+ 0xa8, 0xfc, 0xce, 0x4d, 0xcb, 0xcb, 0xff, 0xa3, 0xb7, 0xbc, 0x7d, 0xe3,
+ 0xe6, 0xe5, 0xcf, 0x7b, 0x57, 0x3c, 0x7f, 0x64, 0xc5, 0xf3, 0xef, 0xad,
+ 0x78, 0xde, 0xd1, 0xba, 0xfc, 0xf9, 0x43, 0x2b, 0x9e, 0x4f, 0xb5, 0xae,
+ 0x0d, 0xef, 0x42, 0xeb, 0x72, 0xb8, 0xee, 0xd6, 0xfb, 0x07, 0xd3, 0x55,
+ 0x57, 0xf6, 0x96, 0xf0, 0xde, 0x79, 0xdf, 0x16, 0xa3, 0xd7, 0xea, 0xdf,
+ 0x33, 0x5e, 0xb7, 0x7b, 0xcb, 0xf2, 0xfe, 0x6a, 0xed, 0xf6, 0xd5, 0xda,
+ 0x05, 0xb5, 0x76, 0x46, 0xb6, 0xcd, 0x54, 0xf9, 0x8e, 0xe5, 0x51, 0xbf,
+ 0xa6, 0xed, 0x44, 0xd9, 0xd7, 0x39, 0xb7, 0xc3, 0x3a, 0xe7, 0x36, 0x05,
+ 0x3e, 0xbc, 0x5b, 0xc7, 0xa8, 0x36, 0xc3, 0x50, 0x1e, 0xaf, 0x6e, 0xd4,
+ 0x71, 0x2a, 0xd1, 0x79, 0xb7, 0xc3, 0xb0, 0x6d, 0x99, 0x6b, 0x1b, 0xca,
+ 0xfe, 0xc0, 0xdc, 0x4d, 0xee, 0xed, 0xb1, 0x70, 0xc0, 0x0b, 0xc3, 0x71,
+ 0xff, 0x76, 0x9b, 0x7f, 0x86, 0x7b, 0xd5, 0xb4, 0xa1, 0x0e, 0x7e, 0x0c,
+ 0x3a, 0xb8, 0xa6, 0x7b, 0xef, 0xc6, 0x58, 0xf3, 0xa0, 0x99, 0x3e, 0xf9,
+ 0x9d, 0x6a, 0xfa, 0xf3, 0xa2, 0xcf, 0x16, 0xf5, 0xc2, 0x86, 0x9b, 0xbf,
+ 0xf3, 0xbd, 0x7e, 0x00, 0x5b, 0x2f, 0x94, 0x87, 0x83, 0x7e, 0xd0, 0x50,
+ 0x37, 0xec, 0x3d, 0x5f, 0xfb, 0xa5, 0x8f, 0x6b, 0xda, 0x22, 0x8d, 0x31,
+ 0xdf, 0x86, 0x76, 0x81, 0x13, 0xcf, 0xf5, 0xfe, 0xb1, 0x89, 0xd3, 0x04,
+ 0x9d, 0xde, 0x97, 0xc0, 0xb7, 0x43, 0xfe, 0x0e, 0xf8, 0x28, 0xa4, 0x21,
+ 0xc6, 0xd3, 0xb6, 0xdb, 0x7c, 0xc7, 0x36, 0x99, 0x76, 0x19, 0x77, 0x4c,
+ 0xf7, 0x8f, 0x08, 0xe7, 0x9d, 0x4e, 0xa6, 0x94, 0xb6, 0xab, 0xc2, 0x03,
+ 0x01, 0x73, 0x79, 0xb9, 0x67, 0x43, 0x7e, 0x1e, 0xbe, 0x6b, 0xc2, 0x2f,
+ 0x78, 0x31, 0x9b, 0xff, 0x9b, 0x2b, 0x19, 0xda, 0x1c, 0x23, 0x6d, 0xc2,
+ 0x9f, 0x5a, 0xe8, 0xfd, 0xbb, 0x90, 0xf6, 0x7d, 0x4a, 0x91, 0xf6, 0xbf,
+ 0x17, 0xce, 0xba, 0xec, 0x8b, 0x70, 0x0f, 0xdf, 0x95, 0xd3, 0xb8, 0xba,
+ 0x5b, 0x0e, 0x97, 0x69, 0x0b, 0xc7, 0x75, 0x7e, 0xc8, 0x68, 0x40, 0x3b,
+ 0x2d, 0x0e, 0x3c, 0x8e, 0x01, 0x7f, 0x2d, 0xb0, 0xb9, 0x6f, 0x44, 0x9d,
+ 0x98, 0x8c, 0x0c, 0xb7, 0x80, 0xf7, 0xc8, 0x9f, 0xbc, 0xbb, 0xa8, 0xef,
+ 0xc9, 0x5c, 0x69, 0x44, 0xe7, 0xef, 0x3d, 0x8e, 0xb6, 0x4f, 0xe0, 0x9a,
+ 0x29, 0x7d, 0x18, 0x6d, 0xde, 0xaf, 0xeb, 0xcf, 0x4c, 0x32, 0x17, 0x5a,
+ 0x20, 0x97, 0x3e, 0x21, 0xc5, 0xd9, 0x0e, 0x19, 0x49, 0xcc, 0x4f, 0xbb,
+ 0x4b, 0x71, 0x99, 0x47, 0x37, 0x70, 0xcf, 0xa4, 0x78, 0x35, 0xf7, 0x97,
+ 0xc5, 0x1d, 0xde, 0xad, 0xba, 0x5b, 0xb5, 0xcf, 0xd5, 0x2f, 0x43, 0xd5,
+ 0x8c, 0xdc, 0x54, 0x7d, 0x62, 0x8b, 0x89, 0x45, 0x2d, 0x8b, 0x6f, 0x1d,
+ 0xd3, 0x52, 0xe5, 0x84, 0xcb, 0xf3, 0x59, 0x32, 0x73, 0x56, 0x24, 0x76,
+ 0x22, 0x8a, 0x4d, 0xb2, 0xcc, 0x93, 0x8e, 0xab, 0x01, 0xd7, 0x59, 0xc8,
+ 0xd6, 0x44, 0x5c, 0x3e, 0xbb, 0x2b, 0x1a, 0xab, 0x10, 0x4e, 0xed, 0x2a,
+ 0xc8, 0x9d, 0xb8, 0xf2, 0x57, 0xa7, 0x27, 0x73, 0x8a, 0xe3, 0xfe, 0x75,
+ 0x48, 0x59, 0xa6, 0x32, 0xbe, 0x14, 0x5a, 0xa3, 0xb1, 0xe1, 0xdf, 0xec,
+ 0x89, 0xc6, 0xa7, 0xcd, 0x6d, 0xce, 0x56, 0x14, 0xb9, 0x8f, 0x03, 0xfa,
+ 0x8b, 0x65, 0x3e, 0xb7, 0x81, 0xbe, 0xc3, 0x80, 0xb0, 0x1d, 0x64, 0xba,
+ 0x62, 0xdf, 0x84, 0x93, 0xf0, 0xd7, 0xc3, 0xb9, 0x90, 0x4a, 0x00, 0x47,
+ 0x85, 0xd7, 0x85, 0xb7, 0xc7, 0xf3, 0xd5, 0x5a, 0xf0, 0xde, 0x6c, 0x63,
+ 0x89, 0x8c, 0x0f, 0xae, 0x03, 0xde, 0x5a, 0x50, 0x9e, 0x97, 0x89, 0x93,
+ 0xb7, 0x6e, 0xe1, 0xde, 0x78, 0x83, 0xef, 0xd8, 0x1c, 0x56, 0x9e, 0x39,
+ 0x9a, 0x40, 0x1d, 0xbe, 0x1f, 0x41, 0x9b, 0x74, 0x21, 0x17, 0xdb, 0x02,
+ 0x9f, 0x88, 0xe3, 0x86, 0xb1, 0x8e, 0x3d, 0xcd, 0x3a, 0x27, 0x55, 0xce,
+ 0x52, 0x9f, 0x47, 0x6d, 0x27, 0x74, 0xce, 0x07, 0xfc, 0xf6, 0xc2, 0x60,
+ 0x8c, 0xf2, 0xab, 0x5b, 0x06, 0xa8, 0x4f, 0xce, 0x8e, 0x68, 0xda, 0xef,
+ 0xdc, 0xc5, 0xf3, 0x57, 0x3d, 0xc6, 0x46, 0x4f, 0x10, 0xc6, 0x9b, 0x51,
+ 0x0e, 0xfb, 0xfd, 0x35, 0x61, 0x28, 0xbc, 0x49, 0x18, 0x0a, 0x6f, 0x12,
+ 0x06, 0xe2, 0x02, 0x70, 0x54, 0xaf, 0xd8, 0x18, 0xc5, 0xbe, 0xb7, 0x62,
+ 0x1e, 0x47, 0xca, 0x05, 0x39, 0x5a, 0x76, 0x74, 0xdc, 0x71, 0x5e, 0x51,
+ 0x26, 0x78, 0xe0, 0x49, 0xf0, 0x5e, 0x19, 0xbc, 0x59, 0x06, 0x2f, 0x96,
+ 0xc1, 0x97, 0xb0, 0xff, 0xcf, 0x43, 0x3e, 0x3c, 0x81, 0xb5, 0x79, 0x7c,
+ 0x19, 0x2f, 0x67, 0x35, 0x2f, 0x17, 0xcb, 0xf4, 0xd5, 0x7a, 0x2f, 0xc3,
+ 0xaf, 0xae, 0x0c, 0x94, 0xd2, 0x50, 0x25, 0x8e, 0x9b, 0xef, 0xfd, 0x28,
+ 0xf9, 0x55, 0x1e, 0x0c, 0x0e, 0xa2, 0xcd, 0x24, 0x68, 0x3c, 0x4d, 0x3b,
+ 0x90, 0xf6, 0x4f, 0x01, 0xbc, 0x79, 0x8c, 0xbe, 0x9a, 0xba, 0x7a, 0xb3,
+ 0x50, 0xbf, 0xb8, 0x7b, 0x98, 0xcb, 0xc8, 0xb9, 0xa6, 0x56, 0xe0, 0xc9,
+ 0xf0, 0xef, 0x98, 0x4f, 0x3d, 0x43, 0xbe, 0x7d, 0x96, 0x7c, 0x5b, 0xc7,
+ 0xab, 0x3f, 0xc5, 0xf9, 0x85, 0xde, 0xae, 0xb5, 0xda, 0xd6, 0xea, 0x6f,
+ 0x5e, 0xaa, 0xaf, 0xc7, 0x9f, 0x24, 0x3f, 0xaa, 0xcc, 0x24, 0x71, 0x9f,
+ 0xca, 0xc5, 0x76, 0x58, 0xdc, 0xc3, 0x76, 0xdb, 0x73, 0x05, 0x70, 0xdf,
+ 0x2e, 0x85, 0xb9, 0x50, 0xfc, 0x3d, 0x51, 0x9f, 0xb5, 0x7e, 0x3c, 0xdb,
+ 0xcf, 0x68, 0xc9, 0x91, 0xc1, 0x5d, 0xdc, 0xd7, 0x70, 0xa0, 0xe7, 0xa3,
+ 0xf5, 0x80, 0xbd, 0xaf, 0xd7, 0x9c, 0x32, 0x96, 0xb2, 0xb5, 0xc5, 0xc6,
+ 0x9f, 0xd8, 0xdf, 0xe4, 0x8a, 0x75, 0x7a, 0x31, 0xe4, 0xb9, 0xb6, 0x09,
+ 0xff, 0x60, 0x1d, 0xad, 0x3c, 0x60, 0x69, 0x45, 0xad, 0x98, 0xc7, 0x5d,
+ 0x96, 0x56, 0x22, 0x78, 0x13, 0x11, 0xad, 0x34, 0x45, 0xb4, 0x52, 0x98,
+ 0x8e, 0x68, 0x85, 0x6d, 0xef, 0x8a, 0x68, 0x25, 0x55, 0x4f, 0x2b, 0x85,
+ 0x69, 0x07, 0xd7, 0x4a, 0x38, 0x48, 0x2f, 0xec, 0x87, 0xf4, 0x02, 0x58,
+ 0xaa, 0x9f, 0x59, 0xa2, 0x97, 0x04, 0xfa, 0x39, 0x5a, 0x36, 0x39, 0x22,
+ 0xf0, 0xbb, 0xac, 0x0e, 0xf1, 0xb0, 0xe6, 0xc6, 0x47, 0x5c, 0x9b, 0x46,
+ 0x02, 0x4b, 0x23, 0xb5, 0x7c, 0xfa, 0x15, 0xb4, 0x01, 0xdc, 0x33, 0x37,
+ 0x76, 0xb7, 0xa6, 0x8d, 0xfb, 0x83, 0x12, 0xea, 0x0e, 0x83, 0x36, 0x22,
+ 0x1c, 0xbc, 0xc7, 0xe2, 0x60, 0xe5, 0x5a, 0xde, 0x66, 0x71, 0x30, 0x6c,
+ 0x71, 0xa0, 0xf9, 0xa5, 0xc0, 0x35, 0x53, 0x1a, 0x07, 0x4d, 0x1a, 0x07,
+ 0xa2, 0xa2, 0xb6, 0xb7, 0xad, 0x81, 0x03, 0xd6, 0x19, 0xd6, 0xf3, 0x8f,
+ 0x61, 0xfe, 0xb7, 0x63, 0xfe, 0x4a, 0xcf, 0x9f, 0xeb, 0x60, 0x72, 0xb9,
+ 0x8b, 0xd5, 0xbf, 0x5e, 0x9a, 0x7f, 0x2b, 0xfa, 0x38, 0x52, 0x8e, 0xe9,
+ 0xf9, 0xc3, 0xb6, 0xef, 0x8f, 0xe6, 0xff, 0x78, 0xd5, 0xe4, 0x53, 0x3f,
+ 0xbe, 0x4a, 0xcf, 0x95, 0x2c, 0x6f, 0xf8, 0xda, 0x2f, 0x66, 0x4c, 0xfb,
+ 0x3c, 0x74, 0xdb, 0x54, 0x90, 0xb2, 0xe7, 0xae, 0x8c, 0xbd, 0xf4, 0x95,
+ 0x80, 0xbc, 0xf3, 0x21, 0x9d, 0xd7, 0x72, 0x8e, 0x76, 0x53, 0xb9, 0x55,
+ 0x06, 0xa7, 0xea, 0xe1, 0x26, 0xbc, 0x05, 0x2d, 0x47, 0xf3, 0x98, 0xdf,
+ 0x68, 0xd0, 0x0d, 0xf9, 0xa6, 0x69, 0x09, 0xe5, 0xe9, 0xc2, 0x40, 0xac,
+ 0x49, 0xd4, 0x03, 0xef, 0xc7, 0x9c, 0x5d, 0xd9, 0xe2, 0x77, 0x7a, 0x7b,
+ 0x14, 0x75, 0xe1, 0x95, 0x75, 0xba, 0xb0, 0xcd, 0xea, 0xc2, 0xcd, 0xd4,
+ 0x85, 0x80, 0xfb, 0x6e, 0x39, 0x56, 0xe6, 0xfa, 0x15, 0x52, 0x4d, 0xd0,
+ 0xff, 0xdf, 0xf1, 0x79, 0xc6, 0x45, 0xc7, 0xcd, 0x92, 0xc7, 0x34, 0x2d,
+ 0x53, 0xa7, 0xa5, 0xf5, 0x99, 0x90, 0x05, 0xda, 0xd8, 0x09, 0xc6, 0x42,
+ 0xa9, 0xf7, 0xfe, 0x3e, 0xfc, 0xcc, 0x1a, 0x7a, 0x6f, 0xbc, 0x6c, 0xec,
+ 0xb7, 0x06, 0xd8, 0x84, 0x72, 0xaa, 0x0d, 0xd7, 0x26, 0x9e, 0x89, 0xe8,
+ 0xee, 0x52, 0xcd, 0xd2, 0x70, 0x6a, 0xa3, 0x8c, 0x4d, 0x19, 0x1b, 0x57,
+ 0x9d, 0x02, 0xfe, 0x4f, 0x31, 0x7f, 0x56, 0x74, 0xbe, 0x7f, 0x7e, 0x12,
+ 0x76, 0xee, 0xcc, 0xdd, 0xe6, 0x1c, 0xc8, 0x54, 0x83, 0xfe, 0x4d, 0x1b,
+ 0xa4, 0x18, 0x64, 0xa1, 0xef, 0xe2, 0x32, 0x86, 0x3e, 0x3b, 0x77, 0x35,
+ 0x62, 0xce, 0x09, 0xb4, 0xa5, 0xcf, 0xc7, 0x38, 0x5a, 0xa3, 0xb8, 0x33,
+ 0x49, 0x9d, 0xab, 0xcf, 0xf3, 0xae, 0xb9, 0xfe, 0x56, 0xbc, 0x63, 0x7e,
+ 0x84, 0x87, 0xb1, 0x22, 0xd9, 0x8f, 0x7e, 0x4f, 0x88, 0xdd, 0xef, 0xc9,
+ 0x68, 0xfd, 0x17, 0x3b, 0xe1, 0xd9, 0xb3, 0x7a, 0xfd, 0x58, 0xf7, 0xb5,
+ 0xf4, 0xa2, 0x31, 0x72, 0x73, 0x58, 0x3f, 0x75, 0xd6, 0xc5, 0xbd, 0x1d,
+ 0xf7, 0xa8, 0xbf, 0x48, 0x8f, 0x40, 0x37, 0xbe, 0xfd, 0xd0, 0x26, 0x69,
+ 0x06, 0xbe, 0x67, 0x14, 0x70, 0x6d, 0x72, 0xbc, 0x0a, 0x9a, 0x17, 0x6a,
+ 0xf4, 0xf0, 0xc4, 0xeb, 0xf2, 0x03, 0x69, 0x82, 0xb4, 0x40, 0xb9, 0x48,
+ 0xda, 0xa0, 0x4c, 0x24, 0x6d, 0x1b, 0x7a, 0x78, 0x2c, 0xf0, 0x63, 0xcc,
+ 0x03, 0x30, 0x71, 0x79, 0xd2, 0x06, 0x69, 0x3e, 0xa5, 0xe3, 0xf5, 0x59,
+ 0xf9, 0x96, 0x64, 0x5b, 0x3b, 0x61, 0x97, 0xfd, 0xdb, 0xae, 0xb1, 0x39,
+ 0x2b, 0xac, 0x69, 0x0e, 0xba, 0x89, 0x39, 0x79, 0xdd, 0xf2, 0x9e, 0x6a,
+ 0x01, 0x78, 0xb8, 0x17, 0x4a, 0xf9, 0x6e, 0x9d, 0xe7, 0xb8, 0xaf, 0xb4,
+ 0x49, 0x6e, 0x09, 0xe2, 0x36, 0xee, 0x7e, 0x04, 0x74, 0xb0, 0xe0, 0xc8,
+ 0xa9, 0x0b, 0xb8, 0x2e, 0x3a, 0x5c, 0xbf, 0x4b, 0x41, 0x36, 0xad, 0xc8,
+ 0xec, 0xbe, 0x9b, 0x5c, 0x90, 0x1e, 0x6f, 0x4c, 0x18, 0xeb, 0x98, 0x77,
+ 0x9a, 0x4e, 0xfd, 0xfe, 0x26, 0xe3, 0x4b, 0x03, 0x16, 0xbf, 0xd1, 0x1b,
+ 0xa4, 0x2d, 0x17, 0x84, 0x61, 0x9e, 0x76, 0x83, 0x28, 0xed, 0x23, 0xc1,
+ 0xe7, 0x43, 0x19, 0xe3, 0x13, 0x3b, 0x9d, 0xc6, 0xb3, 0x2f, 0x58, 0x5a,
+ 0x91, 0x98, 0xca, 0x3c, 0xed, 0x34, 0x9c, 0x7a, 0x84, 0x6b, 0xa6, 0xf3,
+ 0xae, 0x0d, 0x5d, 0x3d, 0xeb, 0xd4, 0xe8, 0xea, 0x2b, 0xf6, 0xb7, 0xca,
+ 0x34, 0x49, 0x36, 0xdd, 0x84, 0xf9, 0x0e, 0x94, 0x22, 0x18, 0xbf, 0x0d,
+ 0xb8, 0x08, 0x0f, 0xe8, 0x76, 0xe6, 0x7f, 0xe2, 0x5a, 0x04, 0x2c, 0xf7,
+ 0x01, 0xee, 0x4b, 0x80, 0xf9, 0x45, 0x5c, 0x6a, 0x5b, 0x4c, 0xfe, 0xd4,
+ 0x89, 0xcd, 0xd4, 0xc3, 0x4b, 0x18, 0xbf, 0x6b, 0xe1, 0x7d, 0x2d, 0x58,
+ 0x3d, 0x59, 0xe8, 0xeb, 0x00, 0x3c, 0x84, 0xf3, 0x25, 0xc0, 0x48, 0xbb,
+ 0xf5, 0x39, 0x3c, 0x7b, 0x80, 0xef, 0x79, 0x0b, 0x13, 0xe8, 0x71, 0xea,
+ 0x2f, 0x6a, 0xbf, 0x4b, 0xb4, 0xa3, 0xff, 0xd2, 0x3e, 0xb7, 0xaf, 0x90,
+ 0x01, 0x5d, 0x0e, 0xf1, 0x3c, 0x51, 0x5e, 0xa4, 0x1d, 0x00, 0xbe, 0xff,
+ 0xae, 0xc4, 0xce, 0x26, 0xe5, 0x68, 0x89, 0x7b, 0x40, 0xa7, 0x81, 0x0f,
+ 0x7d, 0xc6, 0x05, 0x75, 0xae, 0xc2, 0x05, 0x65, 0x3f, 0xb3, 0x1b, 0x57,
+ 0x37, 0xae, 0xb7, 0xe2, 0x02, 0x39, 0xcc, 0x9c, 0xc2, 0xd5, 0x83, 0xbe,
+ 0x55, 0xa2, 0x49, 0x98, 0x9b, 0xf5, 0x0d, 0xb4, 0xd1, 0xb6, 0x65, 0x41,
+ 0x65, 0xfa, 0x80, 0xbf, 0x3e, 0xc0, 0x96, 0xc4, 0xc5, 0x7c, 0xe6, 0xef,
+ 0x3a, 0x72, 0xf6, 0x65, 0x5c, 0x60, 0xb0, 0xb3, 0x20, 0xcc, 0xb3, 0xfd,
+ 0xb8, 0xa0, 0xc4, 0xce, 0x66, 0x71, 0x0d, 0xe2, 0xfa, 0x2b, 0xc7, 0xf0,
+ 0x5c, 0x3b, 0xf0, 0x15, 0xf1, 0x08, 0x70, 0xbe, 0x8c, 0xe7, 0xbe, 0xec,
+ 0xbc, 0x71, 0x9e, 0xfb, 0xbe, 0x63, 0x78, 0xee, 0x15, 0xa7, 0xc6, 0x73,
+ 0x17, 0x1c, 0xf5, 0xf0, 0xd3, 0x4e, 0xec, 0x61, 0xfa, 0x12, 0x17, 0x1c,
+ 0xc3, 0xff, 0x31, 0x19, 0x38, 0x08, 0x5a, 0x7a, 0x78, 0x1e, 0x17, 0xe9,
+ 0xea, 0x19, 0x94, 0x3f, 0xbf, 0x62, 0xdc, 0xe7, 0xde, 0xc4, 0xb8, 0xaf,
+ 0xda, 0x71, 0x45, 0xd5, 0xc6, 0x7d, 0x11, 0x7d, 0xbf, 0x64, 0xc7, 0x7d,
+ 0xb1, 0x6e, 0x5c, 0xd0, 0xca, 0xc3, 0x8b, 0xb8, 0x48, 0x17, 0x2f, 0xa0,
+ 0x3c, 0x92, 0x09, 0x1f, 0xf4, 0xa4, 0xb9, 0x01, 0xbc, 0x1b, 0x87, 0x7e,
+ 0x6c, 0x58, 0xd2, 0x8d, 0xd9, 0x3a, 0xfd, 0xf0, 0x46, 0xf4, 0xe3, 0x78,
+ 0x99, 0x36, 0xe2, 0x7c, 0x9d, 0x5c, 0xa0, 0x6f, 0x14, 0xca, 0x49, 0xed,
+ 0x07, 0xd1, 0x27, 0xa2, 0x7f, 0xb4, 0xd2, 0xb6, 0xfa, 0xa8, 0xce, 0x45,
+ 0xfb, 0x95, 0x52, 0xbb, 0xdc, 0x59, 0xa2, 0x4d, 0x48, 0x7a, 0x09, 0xc3,
+ 0xb1, 0x3d, 0xb4, 0x4f, 0x0b, 0xe1, 0x15, 0x3e, 0xe9, 0xc4, 0xf7, 0x7e,
+ 0x79, 0xb5, 0xce, 0x98, 0x1c, 0x80, 0xef, 0x9e, 0x3b, 0xf1, 0x8b, 0xd0,
+ 0x19, 0x0d, 0x80, 0x9b, 0xf4, 0xb6, 0x4d, 0x0e, 0x4c, 0xaa, 0x89, 0x2d,
+ 0x90, 0x25, 0x37, 0x95, 0x1a, 0x61, 0xf7, 0x30, 0x4f, 0xab, 0x59, 0x3a,
+ 0xf7, 0xc4, 0x4d, 0x1e, 0xb9, 0x97, 0xc0, 0x6f, 0xcf, 0xe4, 0xb5, 0x27,
+ 0x92, 0x78, 0xff, 0x0f, 0x1e, 0xe5, 0x60, 0xc2, 0xbf, 0x4e, 0xe7, 0x08,
+ 0x75, 0xec, 0xa1, 0xdd, 0x72, 0x83, 0xd6, 0xe1, 0xee, 0x2a, 0x3b, 0x49,
+ 0x6d, 0xf3, 0xa4, 0x66, 0xa3, 0x8d, 0x96, 0xd2, 0x29, 0xc2, 0xf5, 0x90,
+ 0x70, 0xff, 0xeb, 0x1e, 0x29, 0x06, 0x1b, 0xe1, 0x17, 0x30, 0x76, 0x9e,
+ 0xee, 0xa6, 0x6d, 0x34, 0x33, 0xe5, 0xd9, 0x3c, 0xeb, 0x4d, 0xf2, 0xac,
+ 0x1e, 0xa7, 0x51, 0xc3, 0x68, 0xce, 0x5e, 0x70, 0x1f, 0x21, 0xae, 0xcf,
+ 0xfb, 0xcc, 0x54, 0x5a, 0xb4, 0xde, 0x99, 0xa9, 0x30, 0xaf, 0x1f, 0xfe,
+ 0x54, 0x85, 0x79, 0xfc, 0x81, 0x78, 0x6f, 0x87, 0x9f, 0x5b, 0xd9, 0x21,
+ 0xa3, 0x53, 0xeb, 0xa4, 0xd1, 0x57, 0x89, 0x2d, 0xd0, 0x1f, 0x6c, 0xd3,
+ 0xb1, 0x07, 0xfe, 0xe1, 0xf4, 0x4e, 0x79, 0x62, 0x9a, 0x7d, 0x6f, 0x93,
+ 0xd9, 0x39, 0x71, 0xbc, 0xb7, 0xaf, 0x47, 0x1d, 0xc8, 0xf5, 0x3d, 0x2c,
+ 0x4b, 0xe1, 0x2e, 0xca, 0x7b, 0xbb, 0x2b, 0x17, 0xfb, 0xf8, 0xcc, 0xb3,
+ 0x04, 0xe2, 0xb2, 0xbf, 0x8b, 0x7d, 0xed, 0x72, 0x6e, 0x0e, 0x34, 0x01,
+ 0xb9, 0x3f, 0x78, 0x8a, 0x30, 0x89, 0xec, 0x9d, 0x61, 0x2c, 0xbd, 0xd3,
+ 0x63, 0xdc, 0x94, 0xfb, 0x34, 0xb7, 0xf4, 0x71, 0x2c, 0xe8, 0x25, 0xe8,
+ 0xb8, 0x8e, 0x3d, 0x46, 0x16, 0x64, 0x67, 0x1a, 0x50, 0xce, 0x7e, 0xe1,
+ 0x3f, 0x1e, 0x64, 0x3f, 0x51, 0x5b, 0x85, 0x39, 0x35, 0x6a, 0x7a, 0x59,
+ 0x5c, 0xa1, 0x3f, 0xce, 0xff, 0x48, 0xf6, 0x37, 0xfb, 0xe8, 0xd6, 0x7b,
+ 0x21, 0xdc, 0x53, 0x36, 0xb6, 0x15, 0xd7, 0x44, 0xef, 0x29, 0xc0, 0xae,
+ 0xba, 0x4a, 0xdb, 0x17, 0xb3, 0x55, 0xae, 0x20, 0x63, 0x51, 0xd1, 0x1a,
+ 0x25, 0xe5, 0xd1, 0xf2, 0xd2, 0x3a, 0xed, 0x68, 0x58, 0xbe, 0x4e, 0xa4,
+ 0x95, 0x60, 0xc4, 0xda, 0x1e, 0x0b, 0x72, 0x0c, 0x76, 0x59, 0xb7, 0x5e,
+ 0xb3, 0x05, 0xd8, 0xb2, 0x76, 0xcd, 0xb4, 0x3d, 0x5b, 0x8c, 0xd6, 0x6c,
+ 0x18, 0x1a, 0xa7, 0x92, 0xd9, 0xcc, 0x35, 0xf3, 0x18, 0xef, 0x06, 0xde,
+ 0x0b, 0x58, 0xa7, 0x02, 0xd6, 0xa8, 0x50, 0xd9, 0x26, 0x33, 0x27, 0x55,
+ 0x7b, 0x83, 0x48, 0x6a, 0xd4, 0xdf, 0x26, 0xe3, 0x73, 0x8c, 0x25, 0xec,
+ 0x80, 0x0d, 0xb6, 0x13, 0x57, 0x3b, 0x9e, 0xd9, 0x2e, 0x21, 0xc5, 0x8a,
+ 0x42, 0xdb, 0xa6, 0x55, 0x76, 0xd6, 0x39, 0x8c, 0xcd, 0x33, 0x9d, 0x8f,
+ 0x01, 0x0f, 0x35, 0xde, 0x29, 0xd5, 0xc5, 0x9f, 0x38, 0x57, 0xad, 0x43,
+ 0x31, 0xdf, 0x84, 0x5e, 0x4f, 0x1d, 0x87, 0x2a, 0x37, 0xbe, 0x19, 0x7b,
+ 0x2a, 0x49, 0x7b, 0x2a, 0x3f, 0xe9, 0x99, 0xf3, 0x06, 0xc3, 0xf0, 0x9d,
+ 0xfc, 0xfc, 0x66, 0xd2, 0xfa, 0xc8, 0x34, 0xe1, 0x8a, 0x47, 0x70, 0x2d,
+ 0x5b, 0x33, 0x9e, 0x0f, 0x5b, 0x1d, 0xe7, 0x28, 0x2d, 0xe5, 0x43, 0x9a,
+ 0xd8, 0x3e, 0xe3, 0x28, 0xed, 0x6b, 0xc0, 0x74, 0xb7, 0xb6, 0x61, 0x45,
+ 0xdd, 0x26, 0x87, 0xcb, 0x3c, 0x5b, 0xc6, 0x78, 0xe2, 0x27, 0x19, 0x5f,
+ 0xea, 0x9e, 0x91, 0x63, 0x18, 0x9b, 0xb9, 0x3f, 0xca, 0xc6, 0x6f, 0x36,
+ 0xd8, 0x1c, 0x91, 0xfa, 0x18, 0x8e, 0xc9, 0x0d, 0x5a, 0x9e, 0x67, 0x9d,
+ 0x1e, 0x5e, 0xc4, 0x3a, 0xff, 0x9a, 0xde, 0x1b, 0x94, 0xc9, 0x18, 0xb4,
+ 0xdf, 0x68, 0x5f, 0xba, 0xdf, 0x9c, 0xab, 0x49, 0xc9, 0x50, 0xd9, 0xcc,
+ 0xff, 0x92, 0xce, 0x11, 0x32, 0xb9, 0x90, 0x26, 0x7f, 0xe8, 0x1e, 0xb9,
+ 0x04, 0x1d, 0x5e, 0x5b, 0xdb, 0x26, 0x19, 0x07, 0x2e, 0xf2, 0x7a, 0x5f,
+ 0x22, 0x25, 0xf9, 0xbe, 0x47, 0x37, 0xf3, 0xdc, 0x45, 0x1c, 0xeb, 0x53,
+ 0x9c, 0xe6, 0x59, 0x4c, 0xf6, 0x7b, 0xb9, 0xbe, 0x28, 0x66, 0x99, 0xd7,
+ 0x0f, 0x59, 0xf9, 0x63, 0x3d, 0xc9, 0x66, 0xfd, 0x7e, 0x9d, 0xcd, 0xdf,
+ 0x76, 0x44, 0x0e, 0x84, 0xf2, 0x87, 0xd0, 0x93, 0x67, 0xec, 0x9c, 0x52,
+ 0x3a, 0x66, 0x25, 0xe1, 0xc5, 0x20, 0x69, 0x63, 0x96, 0x9c, 0xcb, 0x41,
+ 0x4b, 0xdf, 0xc6, 0xfe, 0xa9, 0xd9, 0xd0, 0x66, 0xdf, 0xef, 0x09, 0x2d,
+ 0x0b, 0x7b, 0xad, 0xed, 0xac, 0xe3, 0x3c, 0x8f, 0x88, 0xce, 0x09, 0x88,
+ 0x7c, 0xa3, 0xae, 0x3a, 0xbf, 0xc0, 0xf8, 0x72, 0xc5, 0xa9, 0xb5, 0x64,
+ 0x54, 0xcd, 0x27, 0xa4, 0x2f, 0x37, 0xb6, 0x8b, 0xdf, 0x47, 0x88, 0x7c,
+ 0xb9, 0x5e, 0xeb, 0xcb, 0x6d, 0xd4, 0xbe, 0x9c, 0x89, 0x3d, 0x6c, 0x5c,
+ 0xf2, 0xe5, 0x8a, 0x53, 0x05, 0xd0, 0x4a, 0xf4, 0x3d, 0x07, 0x63, 0x0b,
+ 0x8d, 0x97, 0x78, 0x86, 0xa6, 0x51, 0xf2, 0xc3, 0x0a, 0x7e, 0x83, 0xf1,
+ 0xb1, 0x18, 0xab, 0x50, 0xea, 0xeb, 0xd6, 0xbf, 0x68, 0x97, 0x6c, 0xdb,
+ 0x3a, 0xcc, 0xfb, 0x6e, 0xbd, 0xe6, 0xb3, 0x25, 0xb3, 0xf7, 0x99, 0x3f,
+ 0xc8, 0x98, 0x10, 0xcf, 0x49, 0x69, 0xfe, 0x4a, 0x0d, 0xc4, 0xba, 0x8d,
+ 0x3d, 0xeb, 0x7b, 0xad, 0xd2, 0x7c, 0x1a, 0x38, 0x8f, 0xdb, 0x71, 0x53,
+ 0x80, 0xe9, 0x30, 0xd6, 0xe6, 0x3a, 0x2b, 0x93, 0x39, 0xf6, 0x47, 0x9b,
+ 0x18, 0x1b, 0x98, 0x2b, 0x45, 0x31, 0xc2, 0x98, 0x3d, 0xa3, 0xe9, 0xc7,
+ 0x1a, 0xfd, 0x75, 0x6b, 0xda, 0xaa, 0x8f, 0xbf, 0xae, 0x6e, 0x22, 0x2d,
+ 0xdd, 0xad, 0xf3, 0x5c, 0xd6, 0xf7, 0xa5, 0xf7, 0xeb, 0x9c, 0x7b, 0x1d,
+ 0x63, 0x2c, 0x08, 0x73, 0xd4, 0xbe, 0x29, 0x3f, 0xa1, 0x65, 0xfe, 0xe1,
+ 0x80, 0xfa, 0x6b, 0x8f, 0xfe, 0xdd, 0x98, 0x09, 0xc3, 0x8b, 0x7d, 0x13,
+ 0x8c, 0x29, 0x7a, 0xdf, 0x96, 0xce, 0xe4, 0x80, 0xb6, 0x9d, 0xb0, 0x46,
+ 0x07, 0x9b, 0x65, 0x9d, 0x3f, 0x62, 0x73, 0x66, 0x0a, 0x90, 0x9b, 0x69,
+ 0xd8, 0x4c, 0x3c, 0x7f, 0xdc, 0x65, 0xdf, 0x15, 0xc2, 0x66, 0xd0, 0xd1,
+ 0x07, 0xc5, 0xc8, 0x98, 0x7c, 0x4d, 0xc6, 0x30, 0xd7, 0x20, 0x4b, 0x42,
+ 0x76, 0x8f, 0x4b, 0x9a, 0xdf, 0x2a, 0xe1, 0xd8, 0x45, 0xd9, 0x0a, 0xbd,
+ 0xcc, 0x76, 0xb4, 0x55, 0xf9, 0xcc, 0x3d, 0x1c, 0xdf, 0x3b, 0x02, 0xdd,
+ 0x72, 0xc3, 0x6a, 0xdd, 0x92, 0xa4, 0x5f, 0x9f, 0x9f, 0xa4, 0x6f, 0xb8,
+ 0x1e, 0x6d, 0xb6, 0xc9, 0x87, 0xa6, 0x7e, 0xbe, 0x95, 0xbc, 0x35, 0x02,
+ 0xb9, 0xae, 0xee, 0x8f, 0xce, 0x16, 0xb1, 0x8c, 0xef, 0xd9, 0x6f, 0x93,
+ 0xa4, 0xde, 0xeb, 0xc9, 0x6f, 0x54, 0xd3, 0xa9, 0x45, 0xe8, 0xa6, 0x11,
+ 0xe7, 0x57, 0xb7, 0x9b, 0x98, 0xea, 0x07, 0x5a, 0xcd, 0x59, 0x84, 0x66,
+ 0xe0, 0x34, 0x8a, 0xb3, 0xd6, 0xd3, 0xec, 0xa2, 0x95, 0xc7, 0x61, 0xd8,
+ 0xdc, 0xa7, 0x65, 0xf0, 0x7e, 0xca, 0xe0, 0xc3, 0x41, 0x97, 0xa1, 0x7d,
+ 0xed, 0x33, 0x85, 0x58, 0x47, 0xe0, 0xa1, 0xcf, 0x65, 0xbe, 0x9f, 0xe5,
+ 0x4f, 0x3f, 0xbb, 0x60, 0xe5, 0x92, 0x72, 0x56, 0xf3, 0xa5, 0xba, 0x26,
+ 0xbe, 0x4c, 0xe6, 0x1e, 0x9d, 0xa2, 0x3e, 0x0e, 0xe6, 0xbf, 0x09, 0x39,
+ 0x95, 0xd7, 0x78, 0xd8, 0x26, 0xf7, 0x4d, 0x49, 0xf6, 0x12, 0x74, 0x55,
+ 0x71, 0x6e, 0x39, 0x6f, 0xae, 0xee, 0x8f, 0x73, 0x7d, 0xa4, 0xd5, 0xf8,
+ 0xb6, 0xcb, 0xe7, 0x3a, 0x8f, 0xb9, 0x66, 0xf5, 0x5c, 0xb9, 0x6f, 0x33,
+ 0x67, 0xe7, 0xba, 0x3e, 0x9a, 0x6b, 0xff, 0xf2, 0xb9, 0x46, 0xbe, 0x7d,
+ 0x24, 0x77, 0x53, 0x3a, 0xff, 0x5e, 0xe7, 0x7d, 0x4f, 0xad, 0x97, 0x81,
+ 0xc9, 0x8d, 0x56, 0x5e, 0x7a, 0xd0, 0x3d, 0xcc, 0x89, 0x9f, 0xbf, 0xd7,
+ 0x13, 0x8b, 0x33, 0x45, 0x3c, 0x50, 0xd6, 0xb6, 0xea, 0x33, 0x3b, 0x33,
+ 0xf0, 0xaf, 0x6e, 0x2d, 0xb1, 0x6e, 0xf4, 0xfe, 0x72, 0xb1, 0xe3, 0xc8,
+ 0xa7, 0xa6, 0xdf, 0xd4, 0xbd, 0x2a, 0xa6, 0x60, 0xe2, 0xc3, 0x8c, 0x0b,
+ 0x9b, 0xb3, 0xc4, 0xcc, 0x45, 0xbc, 0x03, 0x3c, 0xf5, 0xf1, 0x52, 0xba,
+ 0x3f, 0x17, 0xa3, 0x1c, 0x9d, 0x96, 0xa3, 0xd5, 0x41, 0xe9, 0xd0, 0xe7,
+ 0x49, 0x5f, 0x37, 0x76, 0x9c, 0xad, 0x8f, 0x1d, 0x33, 0x9d, 0x80, 0xb1,
+ 0xe3, 0xfd, 0x3f, 0x42, 0xec, 0x58, 0x1c, 0x13, 0x3b, 0x5e, 0xcb, 0xbf,
+ 0x9a, 0x28, 0x4f, 0x63, 0x5e, 0xcd, 0x90, 0x25, 0x0b, 0x4e, 0x7e, 0xae,
+ 0x05, 0xf7, 0x0b, 0xb8, 0xc7, 0x71, 0xbf, 0x84, 0xbb, 0x87, 0xfb, 0x8b,
+ 0xb8, 0x27, 0x64, 0x62, 0x49, 0x67, 0x4c, 0x43, 0x6e, 0x50, 0x97, 0xb1,
+ 0xad, 0xf1, 0x07, 0x66, 0x2b, 0x6d, 0xfc, 0x2e, 0x8c, 0x33, 0x33, 0xc7,
+ 0x39, 0x6c, 0x94, 0xf1, 0x29, 0xca, 0xec, 0x56, 0x99, 0x9c, 0x8a, 0x6c,
+ 0xdb, 0xbb, 0xb6, 0x71, 0xcf, 0x60, 0x44, 0x22, 0xdb, 0xf5, 0x77, 0xb7,
+ 0xd9, 0x5c, 0xfb, 0x2d, 0xd2, 0xbc, 0x09, 0x6b, 0x70, 0x5a, 0x2e, 0x4d,
+ 0x6f, 0x5a, 0x66, 0xc3, 0xa6, 0x6c, 0x4c, 0x70, 0xda, 0xea, 0xde, 0xb5,
+ 0x65, 0x44, 0xfd, 0xfa, 0x27, 0x6d, 0x4e, 0x69, 0x94, 0x23, 0x94, 0xd2,
+ 0xeb, 0x33, 0x5c, 0x9d, 0xc6, 0x78, 0xfd, 0x92, 0x9d, 0xe6, 0x3c, 0x97,
+ 0xbe, 0x4d, 0x01, 0x79, 0x78, 0x0a, 0x7a, 0x75, 0x19, 0x5d, 0x82, 0x6e,
+ 0x39, 0x37, 0x07, 0xb4, 0xfb, 0xa8, 0xcc, 0x4c, 0x12, 0xbe, 0xae, 0x64,
+ 0x4c, 0x9f, 0x5d, 0xc3, 0xf3, 0xb4, 0xc9, 0x99, 0x1f, 0xa8, 0x46, 0xe7,
+ 0xd6, 0x36, 0xeb, 0xef, 0x11, 0x2c, 0x3f, 0xbb, 0x66, 0xf5, 0xb3, 0xb6,
+ 0x1d, 0x78, 0x86, 0x2d, 0x9a, 0xc3, 0x5a, 0xf4, 0x14, 0xca, 0xb8, 0xce,
+ 0x3b, 0xdb, 0x22, 0x67, 0x1e, 0x5c, 0xca, 0xa1, 0x6d, 0x85, 0x8d, 0xd2,
+ 0x0e, 0x13, 0x79, 0xd8, 0xcd, 0x74, 0xc1, 0xc7, 0x63, 0x9e, 0x4c, 0x57,
+ 0xf2, 0x36, 0x9d, 0xdb, 0x5c, 0x3b, 0x47, 0x58, 0xcb, 0x6f, 0x8e, 0xce,
+ 0x6d, 0x25, 0x65, 0x10, 0x74, 0x38, 0xa4, 0xcb, 0x13, 0x98, 0x0f, 0xf7,
+ 0xfd, 0x34, 0x1e, 0x20, 0x7b, 0xb8, 0xe7, 0x87, 0xb9, 0x57, 0xbf, 0x01,
+ 0x7a, 0x77, 0xec, 0x19, 0x36, 0xd2, 0x58, 0x9f, 0x8c, 0x55, 0x92, 0xce,
+ 0x58, 0xa5, 0xcf, 0x39, 0x54, 0xb1, 0xef, 0xfa, 0x8a, 0x58, 0x0f, 0xfc,
+ 0x9e, 0xee, 0x70, 0x46, 0x80, 0xaf, 0x62, 0xb9, 0xd3, 0xc9, 0xea, 0xbb,
+ 0x6f, 0xef, 0x90, 0x03, 0x58, 0xab, 0x81, 0xe9, 0xa4, 0x96, 0xf3, 0xb5,
+ 0xef, 0x61, 0x45, 0xeb, 0xfa, 0xa4, 0xde, 0x1b, 0x9a, 0x97, 0x69, 0xfd,
+ 0x7d, 0x25, 0x63, 0x3b, 0x9c, 0x46, 0x7f, 0xd3, 0x36, 0x26, 0xde, 0xe3,
+ 0xe4, 0x75, 0x3f, 0x66, 0x3d, 0x8a, 0xe5, 0x53, 0xb8, 0xaf, 0x3c, 0x43,
+ 0x1d, 0xe9, 0x19, 0xc2, 0xfd, 0x08, 0xf4, 0x59, 0x78, 0x8f, 0x91, 0x57,
+ 0xd3, 0x32, 0x51, 0x65, 0xfe, 0x08, 0xfb, 0x41, 0x79, 0xe5, 0x30, 0x74,
+ 0xd2, 0xf2, 0x33, 0x84, 0x43, 0xb5, 0x75, 0x48, 0x4d, 0x0b, 0x61, 0xe1,
+ 0x1a, 0x2c, 0x3f, 0x5f, 0x7f, 0xf9, 0x7f, 0xd1, 0xbe, 0xa2, 0x91, 0xa1,
+ 0x16, 0x8e, 0x2c, 0xe5, 0x9d, 0x91, 0x2b, 0x9f, 0x96, 0x23, 0xc0, 0xe3,
+ 0x31, 0xc0, 0xa4, 0xee, 0xe7, 0xf7, 0x5e, 0x2a, 0x52, 0x9c, 0xbd, 0x4f,
+ 0xd4, 0x43, 0x97, 0x1c, 0xf7, 0xa1, 0x23, 0x12, 0x7b, 0x68, 0xc1, 0x69,
+ 0x78, 0xa8, 0x53, 0xfb, 0xe5, 0xfb, 0x82, 0xce, 0xe4, 0x21, 0x39, 0x2d,
+ 0xee, 0xfd, 0x4a, 0x9f, 0x27, 0x2b, 0x7a, 0x8c, 0xf1, 0x9d, 0x96, 0xd8,
+ 0xfd, 0x71, 0x7b, 0x16, 0xd5, 0xc4, 0xf5, 0x16, 0x35, 0xdf, 0x3f, 0x97,
+ 0x20, 0xce, 0x16, 0x65, 0x5a, 0xf3, 0xce, 0x00, 0xf4, 0x44, 0x6e, 0x32,
+ 0xb5, 0x54, 0xc7, 0xe4, 0x7b, 0x6e, 0x4c, 0x18, 0x7e, 0x61, 0x9d, 0x2e,
+ 0x87, 0xdf, 0x85, 0xb0, 0x3a, 0xff, 0xca, 0x28, 0xf7, 0xd3, 0xac, 0x29,
+ 0xdf, 0xff, 0x10, 0x6b, 0xd8, 0x85, 0xf5, 0xe2, 0x78, 0x8e, 0xde, 0xcf,
+ 0xe5, 0x59, 0x5c, 0x4f, 0x7a, 0x92, 0x4d, 0x4b, 0x76, 0x10, 0xeb, 0xde,
+ 0x27, 0x4d, 0x80, 0x5b, 0x3d, 0x54, 0x34, 0x76, 0x9d, 0x90, 0x4e, 0x05,
+ 0x92, 0x9b, 0x34, 0xdb, 0xd5, 0xbf, 0x4f, 0xaf, 0xe1, 0xbd, 0x96, 0x66,
+ 0xd6, 0x19, 0xfb, 0x11, 0xcf, 0x86, 0x2e, 0x8a, 0xb2, 0x77, 0xea, 0xbb,
+ 0xd0, 0xf3, 0xdc, 0x77, 0xd1, 0xf6, 0xe2, 0x1a, 0xb6, 0x20, 0x79, 0xe9,
+ 0x69, 0xeb, 0x57, 0x86, 0xe1, 0x54, 0x10, 0x00, 0x8f, 0x6b, 0xf9, 0x92,
+ 0x3b, 0x9c, 0xd9, 0xc9, 0x9d, 0xce, 0xcc, 0x64, 0x28, 0x63, 0x01, 0xbf,
+ 0x19, 0xc2, 0x1c, 0x00, 0xda, 0x5b, 0x2c, 0xeb, 0x84, 0x6e, 0xdd, 0x9d,
+ 0xe0, 0xf9, 0xa6, 0x9b, 0xfc, 0x17, 0xc4, 0xd4, 0x23, 0x8e, 0xe9, 0x23,
+ 0x77, 0x3e, 0x92, 0x17, 0x7e, 0x9f, 0xa3, 0x27, 0x99, 0xd0, 0xdf, 0x10,
+ 0xf9, 0x0c, 0xda, 0x61, 0x8c, 0x32, 0xc7, 0x7d, 0xc6, 0x99, 0x81, 0x3c,
+ 0x9b, 0x9d, 0xe2, 0x37, 0x01, 0x98, 0x4f, 0x1b, 0x6b, 0x57, 0x72, 0x95,
+ 0x37, 0x6e, 0xbf, 0x5b, 0x57, 0x80, 0x0b, 0x14, 0xd3, 0x65, 0x3d, 0xde,
+ 0xe8, 0xd2, 0xb7, 0xec, 0xa2, 0xb2, 0xe8, 0x9b, 0x76, 0x4a, 0xe7, 0x4e,
+ 0xc3, 0x97, 0x3d, 0x33, 0x22, 0xdf, 0x77, 0xe6, 0x4a, 0xaf, 0x38, 0x8f,
+ 0x96, 0xb2, 0xd7, 0x5c, 0x01, 0xfa, 0xb8, 0x18, 0xe4, 0x29, 0xbf, 0x60,
+ 0xf3, 0x4d, 0x49, 0xa1, 0x3a, 0x26, 0xd3, 0xdb, 0x3a, 0xbd, 0xfb, 0xf5,
+ 0xda, 0x9c, 0x01, 0xce, 0xbe, 0x81, 0xf5, 0x3b, 0x93, 0xa0, 0x7e, 0x1b,
+ 0x2d, 0x29, 0xf0, 0xb2, 0xfa, 0x69, 0x5c, 0xb0, 0x6d, 0x1b, 0xb5, 0x8d,
+ 0x72, 0x28, 0x60, 0xbd, 0x9d, 0xce, 0xc0, 0xe4, 0x0e, 0xac, 0xe3, 0x41,
+ 0xe8, 0x4f, 0x07, 0x76, 0x1a, 0x68, 0x1b, 0x65, 0xe3, 0xc0, 0xc1, 0x68,
+ 0x60, 0xe4, 0xf9, 0x80, 0x14, 0xb4, 0x8f, 0x67, 0xee, 0x59, 0x65, 0x62,
+ 0x66, 0x61, 0x38, 0x0b, 0xfb, 0x80, 0xdf, 0xc5, 0x9a, 0xa8, 0xce, 0xe1,
+ 0xfa, 0x71, 0xbb, 0xa7, 0x3d, 0x7f, 0x99, 0x3d, 0x6d, 0x4f, 0x4e, 0x57,
+ 0xf5, 0x39, 0x79, 0x9d, 0x5f, 0x95, 0x52, 0xeb, 0xda, 0xf4, 0x5a, 0xa9,
+ 0x2e, 0x9d, 0x93, 0x96, 0x95, 0x47, 0x12, 0x46, 0x0f, 0x13, 0xa6, 0x14,
+ 0xe0, 0xd9, 0x09, 0x5c, 0x10, 0x1e, 0xd3, 0x46, 0xd4, 0x3b, 0xb7, 0x52,
+ 0x1f, 0x2e, 0xca, 0xa7, 0x12, 0xd1, 0x19, 0x05, 0xf4, 0x03, 0x19, 0x37,
+ 0xb7, 0xd5, 0xe8, 0xc9, 0x2d, 0x6b, 0xf4, 0x13, 0xcd, 0xcd, 0xb1, 0x73,
+ 0x23, 0xdd, 0x6e, 0xbe, 0x92, 0x3e, 0xc5, 0xa2, 0x34, 0xad, 0xa8, 0xcf,
+ 0x98, 0xfe, 0xbe, 0xed, 0xe6, 0xcc, 0x03, 0xeb, 0x7a, 0xb0, 0x4d, 0x69,
+ 0xe7, 0x12, 0x8f, 0x7a, 0xdd, 0x4a, 0x4a, 0x78, 0x6e, 0xe1, 0x0c, 0x64,
+ 0xcb, 0x55, 0xde, 0x4f, 0x28, 0xd2, 0x61, 0x84, 0xeb, 0x6f, 0x68, 0x3e,
+ 0x19, 0x2d, 0x31, 0xb6, 0xf2, 0x68, 0x98, 0x1d, 0x26, 0x8f, 0xb1, 0x0f,
+ 0xbe, 0x9f, 0xd2, 0xf1, 0xdc, 0x83, 0x01, 0x63, 0x45, 0x9d, 0x8f, 0xdc,
+ 0xa1, 0x22, 0x39, 0x05, 0xfd, 0x5b, 0x5e, 0x70, 0xf8, 0xdd, 0xbe, 0x03,
+ 0x82, 0xfb, 0xdc, 0x82, 0xf3, 0xcd, 0xa9, 0x67, 0xf0, 0xdc, 0x60, 0xbf,
+ 0xd5, 0x67, 0xf4, 0x94, 0xc8, 0x1f, 0x46, 0xf3, 0x4d, 0x16, 0xb0, 0xf6,
+ 0x2f, 0x62, 0xed, 0xd7, 0xfe, 0x36, 0x1f, 0xde, 0x55, 0xf0, 0xae, 0xf2,
+ 0x0b, 0x61, 0xb6, 0x95, 0xb4, 0x18, 0xe8, 0xb3, 0xa9, 0x97, 0xf7, 0x9b,
+ 0xfb, 0x35, 0x5f, 0x8c, 0x97, 0xcf, 0x81, 0x2f, 0xb2, 0xdc, 0x6f, 0x0e,
+ 0x1f, 0x0e, 0x6e, 0x04, 0x5f, 0xec, 0x97, 0xdf, 0x83, 0x5d, 0xf0, 0x3b,
+ 0xd5, 0x0c, 0xf8, 0xa3, 0x1f, 0xfc, 0xd2, 0x07, 0x1e, 0x09, 0xb4, 0x8d,
+ 0xfc, 0x18, 0xf4, 0x1f, 0xf4, 0x9a, 0x73, 0x68, 0xb2, 0xc3, 0xc9, 0x4f,
+ 0xfa, 0xce, 0xd8, 0x24, 0xbf, 0xff, 0xa2, 0xde, 0xda, 0x20, 0x6e, 0x72,
+ 0x56, 0xc8, 0x0b, 0x9d, 0xcc, 0x71, 0x6c, 0x03, 0xae, 0xce, 0x12, 0x57,
+ 0xb3, 0xd5, 0x1e, 0xef, 0x0a, 0xf0, 0x44, 0x9b, 0xe6, 0x89, 0x8d, 0x4e,
+ 0xd6, 0xbb, 0xd1, 0xf2, 0xc4, 0x0b, 0xe0, 0x89, 0x4b, 0xab, 0x78, 0xe2,
+ 0x29, 0x4b, 0xff, 0xf3, 0x75, 0x3c, 0x31, 0x6b, 0xcb, 0xa6, 0x2f, 0xc3,
+ 0x13, 0x5b, 0xfd, 0xf4, 0xe7, 0x47, 0xe4, 0x55, 0xf0, 0x84, 0x28, 0xf2,
+ 0xc4, 0x56, 0xcd, 0x13, 0x8c, 0x1d, 0x91, 0x2f, 0xda, 0x21, 0x47, 0xc8,
+ 0x17, 0x17, 0x64, 0x11, 0x7c, 0xf1, 0x9c, 0xe2, 0xd8, 0x67, 0x68, 0x2b,
+ 0x4c, 0xd2, 0x27, 0x3b, 0x55, 0xee, 0x00, 0xbf, 0x2b, 0xf9, 0xaf, 0x53,
+ 0x61, 0xb8, 0x00, 0x3f, 0xfd, 0x41, 0xd8, 0xf3, 0xae, 0xfe, 0x0e, 0xe4,
+ 0x3c, 0xe8, 0x3e, 0xa2, 0xf7, 0x31, 0x07, 0xf4, 0x7e, 0x6c, 0x06, 0x73,
+ 0x18, 0x53, 0x9f, 0x82, 0x2f, 0xec, 0x61, 0x5d, 0x69, 0xe7, 0x9f, 0xd4,
+ 0x3c, 0xd4, 0x00, 0x7d, 0xf0, 0x68, 0x1f, 0x63, 0x4d, 0xbe, 0x77, 0x48,
+ 0x75, 0x16, 0x06, 0x01, 0x73, 0x4c, 0xdd, 0x2f, 0x8c, 0x73, 0xb4, 0xae,
+ 0xb0, 0xf3, 0x29, 0x23, 0x86, 0x21, 0xeb, 0xcc, 0xbb, 0x42, 0xd8, 0x04,
+ 0x9b, 0xb4, 0x49, 0x19, 0x1b, 0x5d, 0xed, 0x49, 0x7b, 0x3f, 0x07, 0x01,
+ 0xda, 0x08, 0x7b, 0x61, 0x2f, 0x56, 0x7b, 0xb0, 0x54, 0x6f, 0xe3, 0xff,
+ 0x67, 0xd8, 0xf8, 0x6c, 0x23, 0xae, 0xb1, 0xf1, 0x7f, 0xc5, 0xf2, 0x1a,
+ 0x7f, 0x7b, 0xda, 0xde, 0x3f, 0x0c, 0xf8, 0xf6, 0x2d, 0xd9, 0xfb, 0xec,
+ 0x83, 0x76, 0x87, 0xc8, 0x0d, 0xb0, 0xf9, 0xde, 0x09, 0x1e, 0xbc, 0x11,
+ 0xbe, 0xd4, 0xbb, 0x4a, 0x9e, 0xec, 0x2f, 0xb5, 0xc1, 0xe7, 0x6e, 0x97,
+ 0x77, 0x4f, 0xed, 0x94, 0xa1, 0xc9, 0x0f, 0x5e, 0x21, 0xcd, 0xdb, 0x60,
+ 0xa3, 0x4e, 0x01, 0xce, 0x98, 0x95, 0xdb, 0x3f, 0x04, 0xde, 0x3a, 0x53,
+ 0xdf, 0x57, 0x6d, 0xdb, 0x8d, 0x9c, 0xe7, 0xd9, 0xc9, 0xb5, 0xfa, 0x49,
+ 0xa0, 0x3d, 0x63, 0x29, 0xdb, 0xe4, 0xec, 0x49, 0x7a, 0x5f, 0x29, 0xd8,
+ 0xe5, 0x01, 0x6c, 0x92, 0x1d, 0xe8, 0x8f, 0xf1, 0xe4, 0x4d, 0xf2, 0xd4,
+ 0x35, 0xee, 0x27, 0xf2, 0x9a, 0x0f, 0xdb, 0x9d, 0xdc, 0xd4, 0x8d, 0x52,
+ 0x3c, 0x18, 0xc7, 0x1c, 0x54, 0xdb, 0x16, 0xb9, 0x5e, 0x86, 0xf4, 0x7c,
+ 0xce, 0xc8, 0x11, 0xe8, 0xe6, 0x3f, 0x28, 0x0d, 0xc9, 0xe2, 0x70, 0x2b,
+ 0x9e, 0xe3, 0xf2, 0x54, 0xa9, 0x07, 0xbe, 0xcf, 0x3b, 0x80, 0xa3, 0x46,
+ 0x3c, 0x37, 0xca, 0xc0, 0x15, 0xe4, 0xd5, 0x16, 0x59, 0x40, 0xf9, 0x3b,
+ 0xe5, 0xdf, 0xd9, 0x72, 0x96, 0x91, 0x37, 0x5a, 0xd0, 0x36, 0x2e, 0x17,
+ 0x4b, 0xb4, 0x2b, 0x35, 0x4f, 0xf4, 0x7f, 0x4b, 0x7a, 0xb2, 0xdf, 0x82,
+ 0x9d, 0x7a, 0x01, 0xd7, 0xd3, 0x92, 0xde, 0x3f, 0xea, 0xf4, 0xa4, 0x3a,
+ 0x1d, 0xe8, 0x4e, 0x5c, 0xae, 0xd3, 0xe3, 0x35, 0x3a, 0x57, 0xd9, 0x3e,
+ 0x1a, 0xe4, 0xe9, 0x83, 0x2a, 0xd9, 0x82, 0x35, 0xd9, 0xed, 0x74, 0xd9,
+ 0x32, 0x3e, 0xeb, 0x9c, 0x3c, 0xe9, 0x3c, 0xab, 0x76, 0x6c, 0x10, 0xe9,
+ 0x68, 0x81, 0xcd, 0x33, 0x26, 0xaa, 0xad, 0x45, 0x5c, 0xe9, 0x9c, 0x51,
+ 0xed, 0x28, 0xf3, 0x6d, 0x59, 0xa2, 0x05, 0xfa, 0x01, 0x65, 0xdb, 0x50,
+ 0xb6, 0xcb, 0x96, 0xb5, 0xb6, 0x48, 0x23, 0xca, 0xce, 0x68, 0x9e, 0xbf,
+ 0xd4, 0xe5, 0x7b, 0x79, 0xa7, 0x59, 0x3a, 0x4e, 0xb5, 0x40, 0x36, 0x6c,
+ 0x92, 0x85, 0x6b, 0x9a, 0xa4, 0x03, 0xef, 0x18, 0xe7, 0x0e, 0x4e, 0xc5,
+ 0xe5, 0xba, 0x53, 0x9d, 0xc9, 0x0f, 0x61, 0x0e, 0x9d, 0x67, 0x19, 0xf7,
+ 0x7e, 0xf2, 0x0a, 0xc6, 0x7d, 0x3a, 0xce, 0xf2, 0xde, 0xa4, 0xe5, 0x0f,
+ 0xf1, 0x61, 0xbe, 0x71, 0x44, 0x99, 0x7c, 0x1a, 0x7e, 0x2e, 0x75, 0x78,
+ 0xa7, 0xfd, 0x1e, 0xc7, 0x9f, 0x5e, 0x41, 0xbf, 0x6d, 0x86, 0xf6, 0x54,
+ 0x99, 0xfc, 0x48, 0x3d, 0x84, 0xfb, 0xb4, 0x23, 0xc5, 0x9a, 0xcc, 0x9a,
+ 0x23, 0x5f, 0x9d, 0x54, 0xcc, 0x65, 0x41, 0x59, 0xf5, 0x67, 0x42, 0xb3,
+ 0xc6, 0xe4, 0x05, 0x23, 0x97, 0xde, 0x67, 0xe4, 0xd2, 0x99, 0xf3, 0xcb,
+ 0xe4, 0xd2, 0x25, 0x2d, 0x97, 0x0e, 0x0a, 0xee, 0x73, 0x97, 0x20, 0x97,
+ 0x5e, 0xc0, 0xb3, 0xa7, 0xe5, 0x52, 0x42, 0xac, 0xbd, 0x2c, 0x3f, 0xd0,
+ 0xe3, 0xcf, 0x96, 0x5d, 0x6d, 0x57, 0x15, 0xa7, 0x61, 0x93, 0x94, 0x27,
+ 0xac, 0xfe, 0x96, 0x4c, 0xab, 0x74, 0xf5, 0xff, 0x50, 0x22, 0x9b, 0xf3,
+ 0xcf, 0xae, 0xe0, 0xf7, 0x46, 0x9f, 0x53, 0x94, 0x61, 0xaf, 0x42, 0x86,
+ 0x89, 0x5a, 0x5b, 0x86, 0xe1, 0x5d, 0x05, 0xef, 0x2a, 0xec, 0xf7, 0x6f,
+ 0x7f, 0x38, 0xe2, 0x51, 0x7e, 0x50, 0x66, 0x40, 0x26, 0x95, 0x21, 0x93,
+ 0xca, 0x90, 0x53, 0x65, 0xc8, 0x25, 0xd8, 0x6c, 0xe7, 0xcb, 0x90, 0x4b,
+ 0x65, 0xc8, 0x25, 0xc8, 0xb8, 0xc7, 0x20, 0xe3, 0x8c, 0x4c, 0x1b, 0x86,
+ 0x4c, 0x3b, 0x23, 0xf7, 0x59, 0x5d, 0x6f, 0x62, 0x25, 0xbd, 0xd6, 0x47,
+ 0xea, 0xd3, 0x31, 0xe4, 0xf3, 0x75, 0xb1, 0xc1, 0x03, 0xc7, 0x35, 0xbf,
+ 0x7b, 0xbe, 0xba, 0xca, 0x61, 0x0e, 0xcd, 0xf7, 0xb5, 0xff, 0xbe, 0x9b,
+ 0xbf, 0xa5, 0x09, 0x7c, 0xfd, 0x1d, 0xcb, 0xd7, 0xbb, 0x97, 0xf8, 0x3a,
+ 0xed, 0x30, 0x56, 0xbc, 0x36, 0x5f, 0x6f, 0xb3, 0xef, 0x0a, 0xe1, 0x3a,
+ 0xf0, 0xf5, 0xba, 0x15, 0x7c, 0x1d, 0x07, 0x5f, 0xef, 0x5f, 0xc5, 0xd7,
+ 0x1b, 0x9c, 0x01, 0xdd, 0x86, 0x67, 0x24, 0xf8, 0xdc, 0xe8, 0xd4, 0xf8,
+ 0xfa, 0x1e, 0xcd, 0xd7, 0x47, 0xc1, 0xd7, 0xd7, 0xd7, 0xf1, 0xf5, 0x7e,
+ 0x49, 0xdf, 0x9c, 0x8b, 0xed, 0x94, 0xd1, 0xfb, 0x55, 0xdb, 0x66, 0xf9,
+ 0x17, 0x31, 0xed, 0x0d, 0x8f, 0x0d, 0x4c, 0xb5, 0x49, 0xfe, 0xa1, 0x57,
+ 0x50, 0x46, 0x3e, 0x4b, 0x8f, 0x64, 0x1d, 0x4f, 0x8e, 0x1c, 0xff, 0xbe,
+ 0xcc, 0x6b, 0xde, 0x12, 0x19, 0x3b, 0x1e, 0x97, 0xf1, 0xe3, 0x8c, 0x43,
+ 0x7c, 0xcf, 0xd2, 0x7b, 0x93, 0x8c, 0x1f, 0x64, 0xde, 0x9c, 0x2b, 0xa3,
+ 0xc7, 0xe1, 0x6f, 0x1d, 0x67, 0x1c, 0xe2, 0xa5, 0x25, 0x1e, 0x9b, 0x87,
+ 0x6c, 0x19, 0x3d, 0xce, 0xb5, 0x8e, 0xa3, 0x9f, 0x16, 0x39, 0x7a, 0x5c,
+ 0xe4, 0xb6, 0xe3, 0xae, 0x7c, 0xe0, 0xf8, 0x12, 0xaf, 0x0d, 0x47, 0xbc,
+ 0xf6, 0x0c, 0x78, 0xad, 0xd3, 0xf2, 0x9a, 0x5a, 0xe2, 0xb5, 0xaf, 0xd6,
+ 0xf1, 0x1a, 0xdb, 0x93, 0xd7, 0x9e, 0xb5, 0x65, 0x7c, 0x76, 0xe5, 0xd0,
+ 0xf1, 0x76, 0x19, 0x7d, 0xe8, 0x2d, 0x32, 0x76, 0x3f, 0x61, 0x35, 0xdf,
+ 0x85, 0xa2, 0x2d, 0x36, 0x5d, 0xed, 0x44, 0xff, 0x51, 0x0e, 0x11, 0x71,
+ 0xed, 0x77, 0xcf, 0x48, 0xba, 0xc0, 0xf1, 0x1a, 0xe1, 0x47, 0x9f, 0x82,
+ 0x7f, 0x71, 0x08, 0x30, 0xdd, 0x72, 0x5c, 0xd2, 0xae, 0xbc, 0x2c, 0x13,
+ 0xc1, 0xe9, 0xed, 0xc6, 0x9e, 0x80, 0x2d, 0xa2, 0x6d, 0x9f, 0xac, 0xe4,
+ 0xdf, 0x1e, 0x6a, 0x1f, 0x63, 0xb2, 0x22, 0x8c, 0x05, 0x30, 0x6e, 0x6e,
+ 0xbf, 0x85, 0xca, 0xfc, 0xc7, 0x06, 0x7d, 0xe6, 0x45, 0xc7, 0x6c, 0xfb,
+ 0xf8, 0x9e, 0xcf, 0xb0, 0x67, 0xf4, 0xd9, 0x45, 0xb6, 0x67, 0x3f, 0x09,
+ 0x1d, 0x53, 0x2f, 0x56, 0xf8, 0x4d, 0x1c, 0xf8, 0x9f, 0x15, 0x7e, 0x5b,
+ 0xeb, 0x37, 0xdb, 0x4c, 0x7c, 0x96, 0x7c, 0xf7, 0x5d, 0x27, 0x5f, 0x9a,
+ 0xd3, 0xdf, 0x38, 0xc8, 0xf9, 0xf8, 0x5d, 0xe1, 0x33, 0xeb, 0xcf, 0x31,
+ 0xde, 0x91, 0x4a, 0xa9, 0x63, 0xdb, 0x99, 0x7b, 0x70, 0x70, 0x8e, 0x75,
+ 0x77, 0x5a, 0x1e, 0xdd, 0xa9, 0xfd, 0x0e, 0xda, 0x58, 0xa3, 0x93, 0x2f,
+ 0x48, 0x91, 0xb6, 0xc9, 0xf0, 0x4e, 0xa7, 0x30, 0xfd, 0x73, 0xdb, 0x8d,
+ 0xfd, 0x3c, 0xb0, 0x95, 0x79, 0x87, 0x59, 0xb5, 0x5a, 0x26, 0x9f, 0x92,
+ 0x48, 0x26, 0xa7, 0x6f, 0xce, 0xc2, 0xce, 0xce, 0x1f, 0xd7, 0xdf, 0xab,
+ 0x4a, 0x75, 0x2a, 0xce, 0xe9, 0x4e, 0xc8, 0xd7, 0x88, 0x16, 0x92, 0xf2,
+ 0xd1, 0xe3, 0xa4, 0x07, 0x95, 0xd8, 0x28, 0x1f, 0xb1, 0xf4, 0x70, 0x46,
+ 0x4a, 0x90, 0x3b, 0xc7, 0x8f, 0x7f, 0x40, 0xa6, 0x0f, 0xac, 0xa4, 0x87,
+ 0xb1, 0x1a, 0x3d, 0x24, 0x60, 0x9f, 0x39, 0xf5, 0xf4, 0xf0, 0xf3, 0x4b,
+ 0xf4, 0x30, 0xed, 0xfc, 0x6b, 0xe9, 0xe1, 0x86, 0x65, 0xf4, 0x30, 0xa1,
+ 0xe9, 0x61, 0x68, 0x89, 0x1e, 0x26, 0x8e, 0x73, 0x5c, 0xbd, 0x37, 0xea,
+ 0x2d, 0x38, 0x5c, 0xf3, 0x25, 0x5a, 0x48, 0x8d, 0xeb, 0x7c, 0xfd, 0x74,
+ 0x81, 0xe7, 0x9b, 0x36, 0x28, 0xc6, 0x49, 0x6a, 0xeb, 0xbf, 0xf1, 0xdf,
+ 0x74, 0xfd, 0xaf, 0xda, 0xfa, 0xff, 0x77, 0xfd, 0x33, 0x5b, 0x99, 0xbb,
+ 0xcf, 0x33, 0xb0, 0x46, 0x1e, 0x47, 0xf4, 0x90, 0xdb, 0x6a, 0xf4, 0x02,
+ 0xd7, 0x98, 0xcf, 0x90, 0x67, 0x90, 0x7f, 0xe7, 0x21, 0xff, 0x9e, 0x80,
+ 0xfc, 0x7b, 0x7c, 0xd9, 0x9e, 0x40, 0xbf, 0x8d, 0x47, 0x84, 0x72, 0x24,
+ 0xa8, 0xe1, 0x63, 0xa1, 0x8f, 0xf8, 0x30, 0xf9, 0x27, 0xcc, 0xfd, 0x5d,
+ 0x8e, 0x13, 0x57, 0xe7, 0x1c, 0x3d, 0x1a, 0xd4, 0xe3, 0x84, 0x70, 0xbf,
+ 0x5c, 0x37, 0x47, 0xfc, 0xae, 0xf0, 0xf9, 0x8c, 0xce, 0x23, 0x29, 0xea,
+ 0x3d, 0x28, 0xe2, 0x85, 0x7b, 0x50, 0xc4, 0x89, 0xab, 0xed, 0xfd, 0x62,
+ 0xa5, 0x49, 0xe7, 0xd0, 0x1f, 0x9e, 0x4b, 0xc8, 0x42, 0x82, 0x31, 0x3e,
+ 0x7e, 0xe7, 0x90, 0x7e, 0xb3, 0x9f, 0x2c, 0x4a, 0x81, 0xb9, 0x72, 0xe0,
+ 0xe9, 0x0d, 0x96, 0xb6, 0x19, 0x1b, 0xe4, 0x19, 0xe0, 0x68, 0x2f, 0xa2,
+ 0xdb, 0xca, 0xba, 0x96, 0xba, 0x98, 0x25, 0xf0, 0x3e, 0x25, 0xa9, 0x5c,
+ 0x1f, 0xee, 0x73, 0x1c, 0xfb, 0x13, 0x32, 0xf1, 0xe0, 0x87, 0x61, 0xcb,
+ 0xbd, 0x1f, 0x3a, 0x87, 0xe7, 0xcf, 0xb8, 0xf7, 0xe0, 0x69, 0x18, 0x66,
+ 0xf4, 0x77, 0xac, 0xe8, 0x03, 0x92, 0x1e, 0x92, 0x78, 0x3e, 0x63, 0xe3,
+ 0x4a, 0x49, 0x29, 0x96, 0x5e, 0x94, 0x7c, 0x85, 0xdf, 0x5c, 0x7b, 0x09,
+ 0xf7, 0xd7, 0x5b, 0x0f, 0xe3, 0x87, 0x0c, 0xeb, 0x3b, 0xd7, 0x66, 0x51,
+ 0xb2, 0x15, 0x93, 0xe3, 0x52, 0x8b, 0x9b, 0x9c, 0x91, 0x63, 0xda, 0x7e,
+ 0xce, 0xd8, 0xdc, 0x96, 0xf4, 0x70, 0x41, 0x8c, 0x0d, 0xfd, 0x39, 0xd8,
+ 0xd0, 0x9f, 0xad, 0x66, 0xf5, 0x3e, 0xd6, 0xe3, 0xb0, 0xa1, 0x1f, 0x83,
+ 0xee, 0xa1, 0xce, 0x49, 0x58, 0x9d, 0x33, 0xa1, 0x0e, 0x68, 0x9d, 0xf3,
+ 0xe7, 0x5a, 0xe7, 0xbc, 0x7b, 0x95, 0xce, 0x39, 0xaa, 0x3a, 0x27, 0xa9,
+ 0x73, 0x06, 0xd4, 0x7e, 0x87, 0xf6, 0xe2, 0x96, 0x35, 0x74, 0xce, 0x7b,
+ 0xe4, 0x1d, 0xf6, 0xdd, 0x3d, 0xf2, 0xde, 0x3d, 0x7a, 0xef, 0xc6, 0x9b,
+ 0x51, 0xfc, 0x76, 0x93, 0xd1, 0x41, 0xd7, 0xab, 0x6e, 0xbd, 0xe7, 0xfb,
+ 0x95, 0x3a, 0x9d, 0xd3, 0xa1, 0xfa, 0x9c, 0x01, 0xdd, 0x86, 0xb1, 0x09,
+ 0x3e, 0x07, 0x4e, 0x76, 0xb8, 0x09, 0xcf, 0x49, 0x89, 0x1d, 0xc7, 0xdc,
+ 0xcd, 0xf7, 0xa5, 0x94, 0x79, 0xf7, 0x56, 0xfb, 0x4e, 0x45, 0xe5, 0xae,
+ 0x29, 0xef, 0xb4, 0xe5, 0x46, 0x57, 0x75, 0xa8, 0x76, 0xad, 0xab, 0x76,
+ 0x83, 0xa1, 0x66, 0xa0, 0x5f, 0x67, 0xca, 0x91, 0xce, 0xe2, 0x6f, 0xc6,
+ 0x9e, 0x19, 0xa3, 0x88, 0x62, 0xd8, 0x29, 0xd4, 0xc1, 0x55, 0x8e, 0x6c,
+ 0x4a, 0xfe, 0x86, 0xaf, 0x80, 0x6b, 0x0e, 0x78, 0xbd, 0x19, 0xfc, 0xf3,
+ 0x1f, 0x4a, 0x8c, 0x81, 0xb6, 0xc9, 0x89, 0xa9, 0xfa, 0x77, 0xed, 0xf2,
+ 0xae, 0xa9, 0x1d, 0x72, 0xfb, 0xe4, 0xd6, 0xa4, 0x34, 0xef, 0x94, 0x89,
+ 0xc9, 0x29, 0x7d, 0xfe, 0x7d, 0xb3, 0xfe, 0x2e, 0x08, 0xbf, 0x97, 0x63,
+ 0x64, 0xe4, 0x90, 0x63, 0x64, 0x64, 0x56, 0xd5, 0x6c, 0xd6, 0xa8, 0x4f,
+ 0x7e, 0x8b, 0x64, 0x70, 0x32, 0xa9, 0xbf, 0xa5, 0x3a, 0x53, 0xbd, 0x4a,
+ 0x7e, 0xfb, 0xa4, 0xba, 0x4b, 0xd5, 0xce, 0xf7, 0x6a, 0x9b, 0x75, 0x76,
+ 0x99, 0xcd, 0xfa, 0xbf, 0x64, 0xe1, 0xbd, 0x71, 0xcc, 0x13, 0x34, 0x7c,
+ 0xf5, 0xb7, 0xb8, 0x17, 0xda, 0x96, 0x90, 0x17, 0x65, 0x50, 0xe3, 0x8f,
+ 0xf2, 0xb4, 0x05, 0x72, 0x70, 0x51, 0xeb, 0xd7, 0x2d, 0xa0, 0x41, 0xca,
+ 0xd2, 0x0f, 0xca, 0x0b, 0x5a, 0x9e, 0x6d, 0xb1, 0xb6, 0xeb, 0x3c, 0xbf,
+ 0x6d, 0x7d, 0x9c, 0xb6, 0xeb, 0x9f, 0xdb, 0x72, 0x96, 0xa5, 0x93, 0x8b,
+ 0x42, 0x7d, 0x97, 0x80, 0x0c, 0xa5, 0x3c, 0x7d, 0xa3, 0xb6, 0xeb, 0x97,
+ 0x6c, 0x1f, 0x94, 0x9f, 0x46, 0x76, 0xef, 0x76, 0xe6, 0x6d, 0x19, 0x9f,
+ 0xa3, 0x78, 0xba, 0x9f, 0xcd, 0x5b, 0x3e, 0x53, 0xce, 0xe7, 0xf1, 0x7e,
+ 0x33, 0xde, 0x93, 0xcf, 0x1e, 0xd7, 0x7c, 0xa6, 0xed, 0x13, 0xa7, 0xd7,
+ 0xee, 0x2f, 0x2c, 0xed, 0x0d, 0x14, 0xc8, 0x67, 0xea, 0x84, 0x37, 0x6f,
+ 0xe4, 0x01, 0xf3, 0x54, 0x7f, 0x03, 0xba, 0x83, 0x6d, 0x51, 0xfe, 0x70,
+ 0x96, 0xbe, 0x2d, 0xfc, 0x9f, 0x8d, 0x78, 0x6e, 0xc3, 0xf3, 0x8c, 0xbc,
+ 0xfb, 0x60, 0x5c, 0xcf, 0x7b, 0x02, 0xf3, 0x38, 0x7c, 0x1c, 0x73, 0x72,
+ 0x8c, 0xed, 0xec, 0x9e, 0x75, 0xa5, 0xe1, 0x2c, 0xf9, 0x8e, 0x67, 0x6d,
+ 0xc2, 0xf0, 0x50, 0x2f, 0xe9, 0x36, 0xed, 0x0d, 0xe9, 0xb3, 0xa5, 0xbb,
+ 0x93, 0x31, 0xe0, 0xe4, 0x30, 0xd6, 0x63, 0xa2, 0xe4, 0x7b, 0x39, 0xc7,
+ 0x4f, 0x62, 0x9e, 0xb0, 0x01, 0x3b, 0x61, 0x0b, 0x76, 0xc2, 0x0e, 0xec,
+ 0x84, 0x1d, 0xb8, 0x49, 0x4e, 0x5d, 0xc3, 0x1c, 0x93, 0xc2, 0x75, 0xf0,
+ 0xca, 0xe5, 0xaf, 0x75, 0x9c, 0xbe, 0xf1, 0xe6, 0x41, 0xf8, 0xec, 0xe2,
+ 0xa5, 0x87, 0x99, 0x87, 0xbf, 0xe8, 0x35, 0xde, 0x3c, 0x24, 0x9d, 0xfd,
+ 0x78, 0xdf, 0xff, 0xa2, 0x74, 0xdd, 0x7c, 0xab, 0xd3, 0x38, 0x3c, 0x08,
+ 0x3c, 0x66, 0x9d, 0x74, 0x72, 0xc4, 0x99, 0xc7, 0x38, 0xb9, 0xdd, 0x31,
+ 0x61, 0xdc, 0x72, 0x9e, 0xb1, 0x88, 0x9b, 0x3b, 0x63, 0x3d, 0xa9, 0x51,
+ 0x27, 0x3d, 0xac, 0x62, 0xe9, 0xe1, 0x41, 0x27, 0xaa, 0xc7, 0x6f, 0xae,
+ 0x42, 0xce, 0x00, 0xd6, 0xc3, 0xe5, 0x4f, 0x83, 0x9e, 0x8e, 0x48, 0xf1,
+ 0x64, 0x8b, 0xcc, 0x95, 0x3a, 0xbd, 0x9c, 0x4a, 0xe8, 0xdc, 0x12, 0x75,
+ 0x0a, 0x44, 0x7f, 0x36, 0x2e, 0x33, 0x93, 0x3b, 0x45, 0x69, 0xdb, 0x7d,
+ 0x9b, 0xe4, 0xa6, 0x26, 0xe5, 0x62, 0x9f, 0xb4, 0x2a, 0xf4, 0xcf, 0x6f,
+ 0xdc, 0xaa, 0x53, 0xdc, 0x4b, 0x8c, 0x78, 0x61, 0x3b, 0xf9, 0x64, 0x12,
+ 0x38, 0x04, 0xdd, 0x32, 0xc6, 0xdb, 0x24, 0x94, 0x7b, 0x1f, 0xd0, 0xf1,
+ 0x53, 0xc6, 0x6c, 0xeb, 0xf7, 0x1e, 0xc8, 0x1f, 0xf1, 0x35, 0xf9, 0x63,
+ 0xb6, 0xcc, 0x7d, 0x1a, 0x29, 0xb8, 0x8c, 0x11, 0xfb, 0xf8, 0x3d, 0xcd,
+ 0xba, 0x4d, 0x32, 0xd1, 0x57, 0xb0, 0x79, 0x1e, 0x7f, 0x9e, 0x64, 0x0e,
+ 0x31, 0x71, 0x32, 0xda, 0x47, 0x5e, 0x5f, 0xb9, 0xb7, 0x11, 0xaf, 0x93,
+ 0x07, 0x8e, 0x2c, 0x4c, 0x46, 0x7b, 0x21, 0xec, 0x0f, 0xcf, 0xd3, 0x46,
+ 0xde, 0xe6, 0x56, 0xb5, 0x23, 0x5c, 0xdc, 0xaf, 0x5c, 0x2e, 0x63, 0x95,
+ 0x4f, 0x99, 0xea, 0x69, 0xf9, 0x7a, 0xa6, 0x6a, 0x64, 0xeb, 0x74, 0x35,
+ 0xd2, 0x2d, 0x71, 0xa3, 0x4b, 0x57, 0xe9, 0x13, 0x13, 0xcd, 0xac, 0xe9,
+ 0x13, 0xea, 0x45, 0x25, 0xef, 0x9b, 0xdb, 0x26, 0xee, 0xc3, 0xb2, 0x38,
+ 0xe1, 0x7f, 0x7a, 0x3b, 0x73, 0x35, 0x26, 0x82, 0x37, 0xa3, 0x1f, 0x9b,
+ 0xae, 0xa4, 0x3e, 0x1c, 0x51, 0x8d, 0xb8, 0x6f, 0xd6, 0xf4, 0x07, 0x9e,
+ 0xc2, 0xb3, 0xf1, 0x13, 0x3e, 0x07, 0x3f, 0xe1, 0xb3, 0xd0, 0x75, 0xe7,
+ 0xe1, 0x27, 0x3c, 0x01, 0x3f, 0xe1, 0x71, 0xf8, 0x09, 0x8f, 0x41, 0x4f,
+ 0xd6, 0xfb, 0x07, 0xe3, 0xcb, 0xfc, 0x83, 0x50, 0xf3, 0x3f, 0xe3, 0x81,
+ 0x4f, 0xd4, 0xf9, 0x06, 0x87, 0x8c, 0xbe, 0x82, 0xdf, 0x6f, 0xf8, 0xa8,
+ 0x43, 0xdd, 0xa4, 0xf5, 0xa3, 0xc9, 0xdb, 0x1d, 0x5e, 0xd2, 0x57, 0x1d,
+ 0xca, 0xe8, 0xab, 0x99, 0x9a, 0xbe, 0x32, 0x7c, 0xf4, 0xf0, 0xa4, 0xc4,
+ 0xfc, 0xc9, 0xf9, 0x5c, 0xb0, 0x57, 0xf3, 0x50, 0xab, 0xbf, 0x53, 0x62,
+ 0x0f, 0xa8, 0xb6, 0x06, 0xc9, 0xd9, 0x67, 0xd0, 0xd7, 0x89, 0x4f, 0xa3,
+ 0xaf, 0xeb, 0x24, 0xaf, 0xed, 0xb3, 0xcb, 0xe3, 0xfb, 0xb1, 0x15, 0xf8,
+ 0x2e, 0x96, 0x27, 0x34, 0xce, 0xef, 0xaf, 0x70, 0x9f, 0xa5, 0x45, 0xc6,
+ 0x2b, 0x11, 0xce, 0x79, 0x9e, 0x95, 0xb9, 0x18, 0xed, 0x12, 0x7b, 0x78,
+ 0x1b, 0xcf, 0x59, 0xa9, 0x7c, 0xb0, 0x5e, 0xe7, 0xb0, 0x9c, 0xea, 0x93,
+ 0x64, 0xbe, 0x8f, 0xb4, 0x7a, 0x9f, 0xcc, 0xe8, 0xb5, 0xd8, 0x26, 0x0d,
+ 0x0f, 0xd3, 0x46, 0x89, 0xf6, 0xf3, 0xde, 0x7f, 0xa5, 0xfd, 0xe6, 0x6a,
+ 0xdc, 0xd4, 0x13, 0x39, 0xa2, 0xd7, 0x6b, 0x5a, 0xe7, 0x19, 0xde, 0x34,
+ 0xc7, 0xb8, 0x3c, 0xbf, 0x6f, 0xc5, 0x98, 0xfc, 0xbf, 0x66, 0xfd, 0x7e,
+ 0xf9, 0x4a, 0x63, 0xcf, 0x6c, 0xb6, 0x76, 0x8c, 0x89, 0x53, 0xad, 0x6d,
+ 0xc3, 0xb0, 0x9f, 0xfa, 0x6f, 0x32, 0xee, 0x70, 0xc6, 0x27, 0x77, 0x3a,
+ 0xc5, 0x49, 0xee, 0x65, 0xdb, 0xbf, 0xd1, 0xe1, 0xed, 0x77, 0x0e, 0xfb,
+ 0x3b, 0x50, 0xc6, 0x98, 0x25, 0x63, 0x36, 0xf7, 0x5f, 0xc9, 0x18, 0x6d,
+ 0xce, 0xe7, 0xd8, 0x2c, 0xdb, 0xe1, 0x4c, 0x4c, 0x76, 0xc2, 0x37, 0xe7,
+ 0xb9, 0x2a, 0xbe, 0x1f, 0xe2, 0xda, 0x41, 0x07, 0x7b, 0xfa, 0xcc, 0xee,
+ 0x98, 0x5c, 0x65, 0x63, 0xd0, 0xd4, 0xc3, 0x3f, 0xbd, 0x6c, 0xef, 0xf6,
+ 0x28, 0xf4, 0xd8, 0x2d, 0x90, 0x47, 0xd4, 0xc3, 0x47, 0xe5, 0x6d, 0x96,
+ 0x9e, 0x97, 0xeb, 0xe1, 0x4b, 0xc2, 0x38, 0x71, 0x2f, 0xde, 0x15, 0xc2,
+ 0x38, 0xe8, 0xe1, 0x58, 0x9d, 0xaf, 0x46, 0xbf, 0xaf, 0x29, 0x63, 0xf6,
+ 0xc3, 0x96, 0xfb, 0x7d, 0x90, 0x03, 0x89, 0xc8, 0xcf, 0x6b, 0x5c, 0xda,
+ 0xaf, 0xdd, 0x6f, 0xdb, 0x4e, 0x04, 0x7f, 0x44, 0x1c, 0xa5, 0x8e, 0xca,
+ 0x2f, 0x42, 0xa7, 0x31, 0x07, 0xe4, 0x2f, 0x34, 0xce, 0x44, 0x91, 0xf6,
+ 0x36, 0x6b, 0x18, 0xad, 0x9c, 0x4f, 0x45, 0x39, 0x1c, 0x45, 0xdb, 0x76,
+ 0xcc, 0xee, 0xc9, 0x17, 0xe5, 0xeb, 0x8c, 0x73, 0xa6, 0x06, 0x63, 0xeb,
+ 0xf9, 0x3d, 0x46, 0xb4, 0xfd, 0x45, 0xed, 0xb7, 0x67, 0x25, 0xea, 0x8b,
+ 0xcf, 0x0d, 0x75, 0x7d, 0xd3, 0x8e, 0xe2, 0x7d, 0xe5, 0x39, 0xb2, 0xa7,
+ 0xf5, 0x3e, 0xa3, 0xf9, 0x5e, 0x42, 0xc4, 0x27, 0xe4, 0x9d, 0x94, 0x3e,
+ 0xeb, 0xe4, 0x3f, 0x4c, 0xbb, 0x87, 0x7b, 0xb0, 0xde, 0xfc, 0x78, 0xf0,
+ 0x11, 0xfd, 0xcd, 0xc0, 0x69, 0x11, 0xa7, 0x18, 0xdc, 0xa6, 0x73, 0x4f,
+ 0x8a, 0x3a, 0xd6, 0x5c, 0xc0, 0xbd, 0xe6, 0xa3, 0x76, 0x3c, 0xcc, 0xbf,
+ 0xc3, 0xc1, 0xb2, 0x3c, 0x60, 0xa3, 0x0e, 0xa1, 0xec, 0x4d, 0x48, 0xc7,
+ 0x89, 0x5f, 0xd0, 0xbc, 0xb0, 0x05, 0xbe, 0xc0, 0xc0, 0x09, 0xe8, 0xea,
+ 0x13, 0x49, 0x19, 0x3a, 0xa1, 0x75, 0x63, 0x76, 0x75, 0xac, 0xa0, 0xc7,
+ 0x73, 0x9d, 0x77, 0xe9, 0x73, 0x6c, 0x6f, 0x3d, 0x11, 0x93, 0x63, 0x89,
+ 0x1e, 0xaf, 0xcb, 0x79, 0xb7, 0xd5, 0x85, 0x51, 0x0c, 0xbb, 0x05, 0xed,
+ 0x5f, 0x2f, 0x8e, 0x1d, 0xc5, 0xaf, 0x63, 0x32, 0x7d, 0xb0, 0x1d, 0xb0,
+ 0x75, 0x6e, 0x33, 0x67, 0x90, 0xb1, 0x56, 0xfa, 0x1b, 0xf7, 0x6e, 0x92,
+ 0xb2, 0xac, 0x03, 0xb0, 0x0c, 0x9e, 0xa0, 0x3e, 0xf3, 0x35, 0x8f, 0x03,
+ 0x06, 0xaf, 0x41, 0xfb, 0x21, 0xe4, 0xcb, 0xb7, 0x88, 0xff, 0x00, 0x64,
+ 0xdc, 0x89, 0xb8, 0x74, 0x9d, 0x68, 0x91, 0x5d, 0x27, 0xe8, 0x87, 0xd4,
+ 0xfb, 0xa5, 0xb4, 0x4b, 0xe7, 0x30, 0xc7, 0x77, 0x6a, 0x39, 0xc9, 0x3d,
+ 0xcd, 0xdb, 0xc9, 0xbb, 0xa8, 0x9b, 0x87, 0xcd, 0x9c, 0x3b, 0xe1, 0xe9,
+ 0x3d, 0xd2, 0x1c, 0xe6, 0x9c, 0xaf, 0x78, 0x18, 0xc7, 0xc8, 0x9c, 0x22,
+ 0xfd, 0x94, 0xe1, 0x6d, 0xc0, 0xf1, 0x31, 0xcb, 0x3b, 0x43, 0xdb, 0x2c,
+ 0x8f, 0xfe, 0x88, 0xbc, 0x77, 0xf3, 0x36, 0x23, 0x3b, 0x7f, 0x76, 0x1b,
+ 0x73, 0x93, 0xb6, 0xf8, 0xbc, 0x37, 0x69, 0x7b, 0xc2, 0xc8, 0xd0, 0xd7,
+ 0xe2, 0x45, 0x01, 0x8e, 0xa2, 0x7d, 0x29, 0x7d, 0x96, 0x2f, 0xbc, 0x18,
+ 0xe8, 0xf3, 0x2b, 0xc1, 0x02, 0xf3, 0x08, 0xf5, 0x77, 0x14, 0x6a, 0xdf,
+ 0x5b, 0xd9, 0x5b, 0x65, 0x9c, 0xfc, 0x89, 0xe8, 0x6f, 0xa9, 0xd4, 0xe5,
+ 0x1d, 0xd6, 0xef, 0x81, 0x31, 0xd6, 0xb4, 0x94, 0x1b, 0x14, 0x4e, 0xea,
+ 0xef, 0x21, 0x3d, 0xeb, 0x5c, 0x2a, 0x5d, 0x70, 0xbe, 0x39, 0x25, 0xa1,
+ 0xeb, 0x7f, 0xdf, 0xf9, 0xb6, 0xcf, 0x3d, 0xf3, 0x2f, 0x3b, 0xdf, 0x2a,
+ 0xf9, 0xe0, 0xc3, 0x0b, 0x98, 0xc7, 0x2b, 0xce, 0x77, 0xb0, 0xbe, 0x47,
+ 0xca, 0xd9, 0xb4, 0x67, 0x63, 0xe2, 0x17, 0x4a, 0xaf, 0x38, 0x5f, 0xaa,
+ 0xc5, 0x93, 0xfa, 0x23, 0x1a, 0x39, 0xca, 0x77, 0x15, 0xbc, 0xab, 0xe8,
+ 0xfd, 0x1f, 0x67, 0x76, 0xca, 0xe6, 0x97, 0x68, 0x3e, 0x9e, 0x5f, 0xda,
+ 0x97, 0x19, 0xd6, 0x7b, 0x15, 0xcf, 0x38, 0xb3, 0x73, 0x9f, 0xdb, 0x66,
+ 0xf2, 0x8c, 0x2e, 0xe0, 0x9d, 0xc9, 0xb9, 0x9c, 0x99, 0xbb, 0x80, 0x3a,
+ 0x4f, 0x3b, 0x33, 0x3a, 0xfe, 0xc5, 0x76, 0x17, 0x9c, 0xe9, 0xb9, 0xa7,
+ 0x9d, 0x39, 0xbd, 0x07, 0x7d, 0xd1, 0x79, 0x74, 0x8a, 0x7d, 0x5f, 0x44,
+ 0x9d, 0x79, 0xe7, 0x14, 0xfa, 0x9b, 0x9b, 0xe2, 0x79, 0xdc, 0x4e, 0xd8,
+ 0x05, 0xfc, 0x1b, 0x45, 0xfc, 0x1e, 0xc7, 0x33, 0xce, 0xdc, 0x52, 0xbf,
+ 0x0b, 0xe8, 0x87, 0x75, 0x49, 0x8b, 0x1c, 0xf7, 0x19, 0xf4, 0xbf, 0x7a,
+ 0xaf, 0x6a, 0x35, 0x4e, 0x9e, 0x07, 0x4e, 0x5e, 0xb4, 0x38, 0x79, 0xd5,
+ 0xe2, 0xe4, 0xb9, 0x3a, 0x9c, 0x88, 0x5a, 0x8e, 0x93, 0x57, 0x81, 0x13,
+ 0x51, 0x6b, 0xe3, 0x04, 0xef, 0x2a, 0x78, 0xa7, 0x71, 0xf2, 0xd2, 0x0a,
+ 0x9c, 0x2c, 0x2e, 0xc5, 0xe5, 0x0d, 0x4e, 0x5e, 0x00, 0x4e, 0x7e, 0x60,
+ 0x61, 0x7f, 0xd1, 0xe2, 0x04, 0xf7, 0xb9, 0x17, 0x51, 0xe7, 0xa5, 0x3a,
+ 0x9c, 0xbc, 0x08, 0x9c, 0xbc, 0x64, 0x71, 0xf2, 0x6d, 0x8b, 0x93, 0x6f,
+ 0xa3, 0xce, 0x22, 0x70, 0x72, 0x69, 0x0d, 0x9c, 0xbc, 0x00, 0x9c, 0x44,
+ 0xfd, 0x5e, 0x42, 0x3f, 0xdf, 0xae, 0xc3, 0xc9, 0x0b, 0x6b, 0xe0, 0x84,
+ 0x7b, 0xb1, 0x51, 0x4e, 0xf7, 0x99, 0xd7, 0xc9, 0xe9, 0x5e, 0x7c, 0x03,
+ 0x39, 0xdd, 0xac, 0x73, 0x46, 0x6a, 0x7f, 0xbb, 0x62, 0xc2, 0xe6, 0xa8,
+ 0x99, 0x5c, 0xc0, 0xda, 0x37, 0x9b, 0x3a, 0xc1, 0xe7, 0xc5, 0x02, 0xbc,
+ 0x11, 0x9d, 0x53, 0xea, 0xee, 0x19, 0x03, 0xaf, 0xbd, 0x5b, 0x0e, 0x9f,
+ 0x6c, 0x3c, 0x96, 0xb7, 0x65, 0xfe, 0x9e, 0xce, 0x82, 0x52, 0x7c, 0x17,
+ 0xe5, 0x24, 0xd0, 0x2f, 0x69, 0xe0, 0xb7, 0x0a, 0xbb, 0xb3, 0x52, 0xbf,
+ 0x27, 0x3d, 0xc5, 0x6f, 0x34, 0x71, 0x7f, 0x8c, 0x7f, 0x67, 0x23, 0xc5,
+ 0x3c, 0xab, 0xa2, 0x86, 0x37, 0x0d, 0xfd, 0xd1, 0xaf, 0x73, 0xab, 0xf8,
+ 0x37, 0x82, 0x62, 0xf0, 0xfb, 0x47, 0xfb, 0x68, 0x2b, 0x67, 0xec, 0x99,
+ 0xb0, 0x40, 0x9f, 0x53, 0xa9, 0xf1, 0x4f, 0xfd, 0x79, 0x68, 0xf2, 0x5d,
+ 0x8d, 0x6e, 0x8e, 0x2c, 0x7d, 0x77, 0xf0, 0xb4, 0x3c, 0xa5, 0x63, 0xc5,
+ 0xcd, 0xfa, 0xef, 0x2b, 0x9c, 0x09, 0x4c, 0x8c, 0x76, 0x41, 0xc7, 0x68,
+ 0x05, 0xde, 0xf8, 0xb8, 0x8d, 0xd3, 0x76, 0xf5, 0xbf, 0xb4, 0x14, 0xa3,
+ 0xad, 0xcf, 0x67, 0x31, 0xfb, 0xeb, 0xb9, 0xc9, 0x39, 0x9d, 0xa3, 0x33,
+ 0xc8, 0xef, 0x6f, 0x40, 0x46, 0x8c, 0x4d, 0x57, 0x64, 0xfc, 0x41, 0x3e,
+ 0x53, 0xbf, 0xc5, 0xa0, 0xc3, 0x28, 0xc3, 0x0b, 0x92, 0xeb, 0x67, 0x99,
+ 0x69, 0x33, 0xa8, 0xfd, 0xe5, 0xd3, 0x32, 0xb0, 0x34, 0x3e, 0xf1, 0xfb,
+ 0x89, 0xba, 0xef, 0x60, 0xd3, 0xe6, 0xc9, 0x3a, 0xb9, 0x2a, 0xdf, 0x47,
+ 0x7b, 0xe4, 0x9f, 0xb0, 0xdf, 0x0a, 0xe4, 0xfb, 0xfa, 0x6f, 0xbf, 0x6a,
+ 0xd1, 0x81, 0xdf, 0xfc, 0xbe, 0xda, 0x84, 0x33, 0x88, 0x36, 0xf3, 0x5e,
+ 0xcb, 0xb0, 0xca, 0xdc, 0x38, 0xcc, 0x73, 0x73, 0x33, 0xab, 0xbe, 0x9d,
+ 0x5d, 0xd3, 0x8b, 0x45, 0xbd, 0xa6, 0xcc, 0xcf, 0x2a, 0x80, 0x16, 0x35,
+ 0x6d, 0x69, 0xfa, 0x3f, 0xbc, 0xa4, 0x2f, 0xa9, 0x67, 0xcd, 0xb7, 0x67,
+ 0x8c, 0xbe, 0x4c, 0x27, 0x07, 0x31, 0xbe, 0xfe, 0x1b, 0x0d, 0xf6, 0x5c,
+ 0x6f, 0x7e, 0xee, 0x2e, 0xad, 0xeb, 0x27, 0x82, 0x6c, 0xca, 0x95, 0x35,
+ 0xea, 0x4e, 0xd6, 0xd5, 0xd5, 0xf3, 0xf6, 0xe4, 0xb7, 0xb0, 0x36, 0xbf,
+ 0x51, 0xae, 0xc8, 0xc0, 0xd4, 0x5f, 0xc1, 0x7f, 0x4c, 0xca, 0x6f, 0x96,
+ 0x1f, 0x01, 0xbd, 0x16, 0xb6, 0xd8, 0x6f, 0x35, 0xe5, 0x00, 0x37, 0xbf,
+ 0xbd, 0xa2, 0xf3, 0x89, 0x63, 0xbf, 0x0d, 0xba, 0xf8, 0xcc, 0x23, 0x1c,
+ 0x03, 0xb0, 0xc4, 0x60, 0xdb, 0xc3, 0x4e, 0x98, 0x7e, 0x44, 0xe7, 0xce,
+ 0x5d, 0x5f, 0x79, 0x44, 0xc7, 0x2c, 0x86, 0x2a, 0xed, 0xb2, 0xb7, 0xd2,
+ 0x22, 0xfb, 0xa0, 0x17, 0xf6, 0x55, 0x7c, 0x5c, 0x71, 0x79, 0x67, 0xc5,
+ 0xac, 0xd3, 0x07, 0x2b, 0x5c, 0xef, 0x3d, 0x32, 0x73, 0x72, 0xe5, 0xf7,
+ 0x3e, 0xe7, 0x0b, 0xd1, 0xdf, 0x73, 0x52, 0x8a, 0xf9, 0x65, 0xa4, 0x25,
+ 0x5c, 0xe5, 0xf4, 0xb1, 0x79, 0x8d, 0x07, 0x66, 0xb8, 0xa6, 0x27, 0x17,
+ 0x85, 0x79, 0xfa, 0xfc, 0x1b, 0x4e, 0x7f, 0xb9, 0x9d, 0xe7, 0xa6, 0xf9,
+ 0x2d, 0xaf, 0xa1, 0x6a, 0x94, 0x37, 0xbe, 0x56, 0xce, 0x38, 0xec, 0xfc,
+ 0x3d, 0x51, 0x8e, 0x5f, 0x9c, 0x39, 0xe3, 0xd2, 0x71, 0xb6, 0x05, 0xf7,
+ 0xef, 0x6e, 0xd7, 0x67, 0x9b, 0xcf, 0x8a, 0x2d, 0xd3, 0xf9, 0xe4, 0x78,
+ 0x5e, 0xf9, 0xbd, 0xb6, 0x88, 0x1f, 0x6a, 0x7f, 0xf7, 0x40, 0xe4, 0xff,
+ 0x02, 0x06, 0x86, 0xe5, 0x0a, 0xd4, 0x6f, 0x00, 0x00, 0x00 };
static const u32 bnx2_CP_b09FwData[(0x0/4) + 1] = { 0x0 };
static const u32 bnx2_CP_b09FwRodata[(0x118/4) + 1] = {
- 0x0800061c, 0x0800083c, 0x08000780, 0x080007a8, 0x080007d0, 0x080007f8,
- 0x08000654, 0x08000640, 0x08000864, 0x08000864, 0x08000670, 0x0800068c,
- 0x0800068c, 0x08000864, 0x080006a4, 0x080006b8, 0x08000864, 0x080006cc,
- 0x08000864, 0x08000864, 0x080006e0, 0x08000864, 0x08000864, 0x08000864,
- 0x08000864, 0x08000864, 0x08000864, 0x08000864, 0x08000864, 0x08000864,
- 0x08000864, 0x080006f4, 0x08000864, 0x08000708, 0x0800071c, 0x08000730,
- 0x08000864, 0x08000744, 0x08000758, 0x0800076c, 0x08003200, 0x08003218,
- 0x08003228, 0x08003238, 0x08003250, 0x08003268, 0x08003278, 0x08003288,
- 0x080032a8, 0x080032b8, 0x080032c8, 0x08003358, 0x08003298, 0x080032d8,
- 0x080032e8, 0x08003300, 0x08003320, 0x08003358, 0x08003338, 0x08003338,
- 0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050fc,
- 0x080050fc, 0x08005124, 0x08005174, 0x08005144, 0x00000000 };
-static const u32 bnx2_CP_b09FwBss[(0x3b0/4) + 1] = { 0x0 };
-static const u32 bnx2_CP_b09FwSbss[(0xa1/4) + 1] = { 0x0 };
+ 0x0800069c, 0x080008bc, 0x08000800, 0x08000828, 0x08000850, 0x08000878,
+ 0x080006d4, 0x080006c0, 0x080008e4, 0x080008e4, 0x080006f0, 0x0800070c,
+ 0x0800070c, 0x080008e4, 0x08000724, 0x08000738, 0x080008e4, 0x0800074c,
+ 0x080008e4, 0x080008e4, 0x08000760, 0x080008e4, 0x080008e4, 0x080008e4,
+ 0x080008e4, 0x080008e4, 0x080008e4, 0x080008e4, 0x080008e4, 0x080008e4,
+ 0x080008e4, 0x08000774, 0x080008e4, 0x08000788, 0x0800079c, 0x080007b0,
+ 0x080008e4, 0x080007c4, 0x080007d8, 0x080007ec, 0x080032e8, 0x08003300,
+ 0x08003310, 0x08003320, 0x08003338, 0x08003350, 0x08003360, 0x08003370,
+ 0x08003390, 0x080033a0, 0x080033b0, 0x08003440, 0x08003380, 0x080033c0,
+ 0x080033d0, 0x080033e8, 0x08003408, 0x08003440, 0x08003420, 0x08003420,
+ 0x080051bc, 0x080051bc, 0x080051bc, 0x080051bc, 0x080051bc, 0x080051e4,
+ 0x080051e4, 0x0800520c, 0x0800525c, 0x0800522c, 0x00000000 };
static struct fw_info bnx2_cp_fw_09 = {
+ /* Firmware version: 3.7.1 */
.ver_major = 0x3,
- .ver_minor = 0x4,
- .ver_fix = 0x3,
+ .ver_minor = 0x7,
+ .ver_fix = 0x1,
.start_addr = 0x0800006c,
.text_addr = 0x08000000,
- .text_len = 0x6ee8,
+ .text_len = 0x6fd0,
.text_index = 0x0,
.gz_text = bnx2_CP_b09FwText,
.gz_text_len = sizeof(bnx2_CP_b09FwText),
- .data_addr = 0x08007020,
+ .data_addr = 0x08007100,
.data_len = 0x0,
.data_index = 0x0,
.data = bnx2_CP_b09FwData,
- .sbss_addr = 0x08007024,
- .sbss_len = 0xa1,
+ .sbss_addr = 0x08007104,
+ .sbss_len = 0xa9,
.sbss_index = 0x0,
- .sbss = bnx2_CP_b09FwSbss,
- .bss_addr = 0x080070d0,
+ .bss_addr = 0x080071b0,
.bss_len = 0x3b0,
.bss_index = 0x0,
- .bss = bnx2_CP_b09FwBss,
- .rodata_addr = 0x08006ee8,
+ .rodata_addr = 0x08006fd0,
.rodata_len = 0x118,
.rodata_index = 0x0,
.rodata = bnx2_CP_b09FwRodata,
};
static u8 bnx2_RXP_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xec, 0x5c,
- 0x5d, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0xf3, 0x43, 0x6a, 0x49, 0xf1, 0x67,
- 0xb8, 0x5c, 0xb1, 0x2b, 0x99, 0x96, 0x77, 0xc9, 0x91, 0xc8, 0x58, 0x8a,
- 0x31, 0xa2, 0x09, 0x5b, 0x48, 0x17, 0xf6, 0x76, 0x76, 0x25, 0xb1, 0xb1,
- 0x03, 0x53, 0xb6, 0x62, 0x07, 0x45, 0x6a, 0xb0, 0x4b, 0xb9, 0x0e, 0x8c,
- 0x06, 0x90, 0xff, 0x52, 0xbf, 0xb0, 0xde, 0x2c, 0xa9, 0x58, 0x4d, 0x17,
- 0x9c, 0xb5, 0x4d, 0x9b, 0x0e, 0x60, 0xb7, 0x0b, 0x92, 0x12, 0xf5, 0xb0,
- 0xd0, 0xb2, 0xa9, 0xdb, 0xea, 0xc1, 0x8e, 0x09, 0x56, 0xb1, 0x53, 0xa0,
- 0x2d, 0x5c, 0x27, 0x69, 0xfc, 0x10, 0x14, 0xaa, 0xec, 0xc4, 0x42, 0xd1,
- 0xa2, 0x02, 0x12, 0xd8, 0x29, 0x22, 0x7b, 0xfa, 0x7d, 0x77, 0x66, 0xc8,
- 0x25, 0x2d, 0xdb, 0x41, 0x1f, 0xfa, 0xd2, 0xbd, 0xc0, 0x62, 0xee, 0xbd,
- 0x73, 0xee, 0xb9, 0xe7, 0x9e, 0xff, 0x73, 0x87, 0xd2, 0x1f, 0x74, 0x48,
- 0xbb, 0x84, 0xad, 0x13, 0xbf, 0xd4, 0x89, 0x27, 0x1e, 0xb9, 0x69, 0xf4,
- 0xa6, 0x9b, 0xd1, 0xbd, 0xd9, 0x30, 0x4c, 0x23, 0x9a, 0x6f, 0xb6, 0x66,
- 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
- 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
- 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
- 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
- 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
- 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0xfb, 0xff, 0xde,
- 0x0c, 0x11, 0x8b, 0xcf, 0xce, 0xf0, 0x27, 0x31, 0x3d, 0x23, 0x0f, 0xb9,
- 0xb6, 0xc4, 0x8c, 0xcc, 0xd5, 0xa9, 0x49, 0x5b, 0x24, 0x5b, 0xdb, 0x97,
- 0xca, 0xc9, 0x87, 0x7e, 0x31, 0x61, 0x0a, 0xe7, 0xaf, 0xcf, 0x5c, 0xfd,
- 0x8b, 0x57, 0x6f, 0x4d, 0x5f, 0xa9, 0x1a, 0x12, 0xb3, 0x32, 0x33, 0x07,
- 0xac, 0xbd, 0x12, 0xeb, 0xc7, 0x9a, 0x17, 0x87, 0xfe, 0xa9, 0x4b, 0xba,
- 0x22, 0x5c, 0x22, 0x0b, 0xe5, 0xb4, 0x73, 0x18, 0xcf, 0x33, 0xb5, 0x7d,
- 0xce, 0x9a, 0x98, 0xb2, 0x6a, 0x05, 0x3b, 0x96, 0xca, 0x1a, 0xf1, 0x48,
- 0xa9, 0x16, 0x93, 0x8b, 0xea, 0xdf, 0x79, 0x60, 0x4f, 0x9b, 0xfd, 0xf3,
- 0x9a, 0x5b, 0xf7, 0xfd, 0xd3, 0x8e, 0xef, 0xbf, 0x8e, 0xdf, 0x7b, 0x0e,
- 0xc6, 0xde, 0x47, 0x7e, 0xd6, 0x34, 0x44, 0xb7, 0xff, 0x4c, 0x73, 0x17,
- 0x5b, 0xa5, 0x34, 0x2f, 0x32, 0xed, 0xc5, 0xe4, 0x94, 0x57, 0xd4, 0xf2,
- 0xf5, 0xb2, 0x76, 0x68, 0x79, 0x56, 0x3b, 0xbc, 0x7c, 0x4a, 0x3b, 0xb2,
- 0x5c, 0xd1, 0xdc, 0x65, 0x29, 0xea, 0x07, 0x3a, 0x24, 0x6b, 0x9d, 0xd5,
- 0x72, 0xf5, 0x3e, 0xcd, 0x9d, 0xbf, 0xea, 0xbb, 0x4e, 0xda, 0xfa, 0x3d,
- 0x31, 0xb3, 0xdc, 0xcf, 0x2d, 0xfb, 0x18, 0x9b, 0x92, 0x4d, 0xf8, 0xbe,
- 0x9e, 0xf1, 0x9f, 0x74, 0x47, 0x6d, 0x4b, 0xd7, 0x62, 0x52, 0xaa, 0xb7,
- 0x03, 0x6f, 0x87, 0x96, 0x9b, 0x37, 0xb5, 0xbc, 0xe7, 0xbf, 0xe6, 0x3a,
- 0xd2, 0x6f, 0x88, 0xef, 0xcf, 0x38, 0x7b, 0x92, 0xc7, 0xe5, 0x0c, 0xf0,
- 0xd6, 0x80, 0x4f, 0x2c, 0x3d, 0x43, 0xfa, 0x22, 0x9a, 0x8b, 0x5a, 0x6e,
- 0x28, 0xa2, 0x4f, 0x52, 0xa4, 0xbf, 0xb0, 0xa4, 0x83, 0xce, 0xed, 0x52,
- 0xa8, 0x5a, 0x32, 0xb1, 0xb4, 0x15, 0xfe, 0xa2, 0xff, 0xea, 0x50, 0x42,
- 0xfe, 0xb2, 0x9e, 0x3e, 0x55, 0x04, 0x2f, 0x66, 0xbc, 0x94, 0x80, 0xcf,
- 0x59, 0x77, 0xb4, 0x5f, 0x5e, 0xab, 0x27, 0xe5, 0xbb, 0x75, 0x3b, 0x59,
- 0x92, 0x6d, 0x52, 0x48, 0x58, 0xb2, 0x82, 0x35, 0xd3, 0xa0, 0x43, 0xb7,
- 0x6d, 0xab, 0x04, 0xd8, 0x52, 0xfd, 0x27, 0xfc, 0xb7, 0x32, 0xd6, 0xe4,
- 0xa8, 0x5a, 0x53, 0x04, 0xdd, 0x21, 0x2c, 0xcf, 0xa1, 0x60, 0xd5, 0x59,
- 0x02, 0x58, 0x29, 0x4e, 0x8e, 0x62, 0xae, 0xfe, 0x85, 0x50, 0x16, 0xad,
- 0x38, 0x2f, 0x9f, 0xbb, 0x71, 0xbe, 0xdd, 0xe0, 0x89, 0x24, 0x74, 0xd9,
- 0x93, 0x2c, 0x60, 0x66, 0xba, 0xde, 0x81, 0x31, 0x69, 0xf1, 0xfd, 0x23,
- 0x8e, 0x58, 0x25, 0xa7, 0x1b, 0xbc, 0x4b, 0x49, 0xc9, 0xe9, 0xc2, 0x9a,
- 0x16, 0xb1, 0x6c, 0x9e, 0x81, 0x78, 0xdb, 0x30, 0xef, 0x77, 0x1a, 0x19,
- 0xdf, 0x9f, 0x1c, 0x95, 0xae, 0x60, 0x6e, 0x1f, 0x70, 0x98, 0x32, 0x31,
- 0xae, 0x01, 0xee, 0x03, 0xd2, 0x17, 0x8b, 0x67, 0xd8, 0xe7, 0x73, 0x54,
- 0xdc, 0xd9, 0x54, 0xb8, 0x6f, 0x87, 0x94, 0xbc, 0xeb, 0xc3, 0x3e, 0x78,
- 0xed, 0xe1, 0xcc, 0xce, 0x4e, 0x8c, 0xb5, 0x1b, 0x80, 0xc7, 0x29, 0x09,
- 0xf7, 0xd8, 0x21, 0x6b, 0x09, 0xd1, 0x2f, 0x39, 0xbd, 0x21, 0x5c, 0x17,
- 0x68, 0x8d, 0x64, 0xde, 0x2e, 0x33, 0xf3, 0xad, 0x72, 0x72, 0x9e, 0xbc,
- 0x2d, 0x43, 0x16, 0x78, 0xde, 0x52, 0xd4, 0xb2, 0xf5, 0x53, 0xe8, 0x9b,
- 0x32, 0x69, 0xfb, 0xaf, 0xcd, 0x38, 0xb3, 0x5a, 0x6e, 0xf9, 0x8c, 0x96,
- 0x87, 0x0e, 0x1c, 0x5a, 0x3e, 0xaf, 0x1d, 0xae, 0xaf, 0x76, 0x4a, 0x7b,
- 0x1a, 0xda, 0x66, 0xca, 0x49, 0x4f, 0x13, 0xd2, 0xbb, 0x00, 0x7e, 0x65,
- 0x2d, 0x70, 0xde, 0xee, 0xd2, 0x0e, 0x03, 0x57, 0x8b, 0xfd, 0xad, 0x0e,
- 0xe9, 0x32, 0x64, 0x9b, 0x1d, 0xc1, 0xc6, 0xe4, 0x5b, 0xa0, 0x6d, 0xcd,
- 0x49, 0x00, 0x4e, 0xba, 0x83, 0x35, 0x3d, 0x21, 0x3d, 0xd4, 0x25, 0xea,
- 0x91, 0x9e, 0xcd, 0xcf, 0xfd, 0x69, 0x6f, 0x69, 0xff, 0x76, 0xc2, 0xc0,
- 0x3e, 0x52, 0x0f, 0x4d, 0xda, 0x6e, 0x8f, 0x29, 0x45, 0x4b, 0x97, 0xb4,
- 0x95, 0x93, 0x1b, 0x64, 0xc6, 0x11, 0xc9, 0x41, 0xbf, 0x75, 0xdb, 0x04,
- 0x8f, 0x6c, 0xf0, 0x68, 0xcf, 0xa9, 0x41, 0xfd, 0x0e, 0x49, 0xf5, 0x15,
- 0x35, 0x33, 0xe4, 0xe7, 0x82, 0xdc, 0xa6, 0xd6, 0xeb, 0x19, 0x07, 0x3a,
- 0xd9, 0xce, 0x3e, 0xf6, 0x8d, 0xa9, 0x7d, 0x8d, 0x8c, 0x9d, 0x5c, 0x14,
- 0xd1, 0xf4, 0xcc, 0x3e, 0xe0, 0xa3, 0xae, 0x12, 0xee, 0x29, 0xd0, 0x48,
- 0xda, 0xd9, 0xb7, 0xb1, 0x26, 0x26, 0xae, 0xd3, 0xd9, 0x40, 0x27, 0xe8,
- 0x49, 0x90, 0xe7, 0xe4, 0xa1, 0x3a, 0xa7, 0xb6, 0x71, 0xce, 0x5f, 0xfb,
- 0xdb, 0x46, 0x4c, 0x79, 0x5d, 0x9d, 0x97, 0x76, 0x45, 0x38, 0x75, 0x46,
- 0x21, 0x7f, 0xa6, 0x3d, 0xd1, 0x0a, 0x8e, 0xb5, 0x8e, 0x0b, 0x7a, 0xa1,
- 0x1b, 0x99, 0x0e, 0xc9, 0x29, 0xfa, 0x0e, 0x62, 0x2f, 0xda, 0x1b, 0xec,
- 0xc6, 0xe6, 0x59, 0x38, 0x97, 0x81, 0xed, 0xa6, 0x95, 0xfe, 0x14, 0x2a,
- 0xf4, 0x07, 0xa4, 0x6d, 0x35, 0xad, 0x4b, 0x80, 0xaf, 0xf4, 0x6c, 0x37,
- 0x68, 0xe3, 0x18, 0xb6, 0x67, 0xe3, 0xfd, 0x7e, 0xd8, 0xfa, 0xc1, 0x41,
- 0xf0, 0x87, 0x70, 0x76, 0x0a, 0xf2, 0xce, 0xba, 0xd8, 0xd3, 0x75, 0x6e,
- 0x56, 0x3c, 0xe8, 0xc1, 0x79, 0x06, 0x67, 0xc9, 0xaf, 0x76, 0xe8, 0xb3,
- 0x26, 0x05, 0x27, 0x9d, 0xa2, 0xfc, 0x03, 0xda, 0x75, 0xd9, 0x76, 0x4b,
- 0x23, 0xed, 0x91, 0xac, 0xa8, 0x8f, 0xa6, 0xc4, 0x47, 0x08, 0x4b, 0x38,
- 0xc2, 0xa7, 0x0f, 0x8a, 0xfe, 0x6b, 0xdf, 0xda, 0x74, 0x56, 0x5b, 0x06,
- 0x66, 0x41, 0x43, 0xc0, 0x5b, 0xf0, 0xe4, 0xb3, 0x60, 0xc9, 0xd7, 0xad,
- 0xfc, 0x23, 0x6c, 0x23, 0x1c, 0x74, 0xa2, 0x8f, 0x34, 0xac, 0x74, 0x04,
- 0xf6, 0x15, 0xd1, 0x14, 0xc9, 0x46, 0x0b, 0x71, 0x7c, 0xda, 0x39, 0x08,
- 0x0f, 0xbb, 0xf7, 0x60, 0xf7, 0x1e, 0x7c, 0x82, 0x07, 0x9b, 0xf7, 0xe8,
- 0x27, 0x52, 0xf2, 0xea, 0x10, 0xfc, 0xda, 0x86, 0x5f, 0x41, 0x1b, 0x43,
- 0x5f, 0x17, 0x03, 0x7e, 0x65, 0xba, 0xaa, 0xc3, 0x76, 0x61, 0x43, 0x4b,
- 0x9c, 0xb3, 0xf0, 0xcc, 0xe3, 0x69, 0xc3, 0x8f, 0x52, 0xaf, 0x22, 0xff,
- 0x49, 0x3f, 0x93, 0x84, 0x4f, 0xa1, 0xaf, 0xa1, 0x2f, 0x21, 0xac, 0xef,
- 0xe7, 0x1d, 0xae, 0xf5, 0x65, 0xdc, 0xa1, 0x1d, 0x75, 0x88, 0x1e, 0x2f,
- 0x6a, 0x47, 0x87, 0x60, 0x63, 0x37, 0xb6, 0x80, 0x56, 0xda, 0xda, 0x75,
- 0x74, 0x15, 0x68, 0xbf, 0xe8, 0x0c, 0xfe, 0x5d, 0xde, 0x36, 0xc0, 0x28,
- 0xa1, 0x76, 0x05, 0xe3, 0xb6, 0xd0, 0x9f, 0xf0, 0x7d, 0x3a, 0x95, 0x95,
- 0xdd, 0xe1, 0x98, 0xfd, 0x75, 0x7a, 0x1d, 0xfd, 0x96, 0x98, 0x0c, 0x9c,
- 0x09, 0xfc, 0xe0, 0xc0, 0x82, 0x25, 0xf6, 0x99, 0x80, 0xc6, 0x81, 0x73,
- 0x91, 0x3f, 0x6c, 0x01, 0x3e, 0xd0, 0xe7, 0x6d, 0xc4, 0x09, 0x91, 0xf7,
- 0x34, 0x98, 0x0a, 0xe6, 0xb6, 0xf2, 0x82, 0x3e, 0x98, 0xf6, 0x66, 0x35,
- 0xda, 0xdb, 0x01, 0xd8, 0x9b, 0xd3, 0x2a, 0x69, 0xe7, 0xef, 0x60, 0x6f,
- 0x4f, 0x39, 0x1a, 0x78, 0x23, 0x72, 0xa1, 0xdc, 0x01, 0x5b, 0x37, 0x93,
- 0xef, 0xc8, 0x9e, 0xd4, 0xb4, 0x68, 0x72, 0x9a, 0x73, 0x35, 0xcc, 0x29,
- 0xff, 0x1b, 0xd8, 0xf7, 0x45, 0xe3, 0x69, 0xd0, 0xe5, 0xfb, 0xd3, 0xc0,
- 0x59, 0xd8, 0x6f, 0x84, 0xb6, 0x15, 0xcd, 0xa7, 0x10, 0xf3, 0xdc, 0xcf,
- 0x19, 0x52, 0x1c, 0x6e, 0x91, 0xf4, 0xf0, 0x02, 0x70, 0x4f, 0x3a, 0x81,
- 0x1d, 0x53, 0xd7, 0x17, 0x81, 0x7f, 0xc6, 0x1b, 0x82, 0x1e, 0xd3, 0x0e,
- 0x40, 0x17, 0xf0, 0x2f, 0x02, 0xff, 0x4c, 0xbd, 0x45, 0xbe, 0x69, 0x46,
- 0xb1, 0x34, 0x3a, 0x4f, 0x1b, 0xc0, 0xa2, 0x7d, 0x4f, 0xc8, 0x17, 0xbd,
- 0xb8, 0xe6, 0x3e, 0x4b, 0x3f, 0x5b, 0x1a, 0x86, 0x9d, 0x68, 0x25, 0x87,
- 0x7b, 0x1b, 0xb2, 0xb8, 0x0e, 0x23, 0xd9, 0x52, 0x60, 0x83, 0x59, 0x77,
- 0xa8, 0x98, 0x34, 0x94, 0x2f, 0x11, 0x39, 0x5c, 0x36, 0x01, 0xc3, 0x31,
- 0xe7, 0x83, 0xb9, 0xb1, 0x72, 0x1f, 0x7c, 0x23, 0xc7, 0x57, 0xfd, 0x49,
- 0x27, 0x98, 0xfb, 0xdd, 0x72, 0x81, 0x32, 0x62, 0xdc, 0x4e, 0x95, 0x9c,
- 0x7f, 0xf7, 0xa1, 0xbf, 0x9b, 0xd6, 0x5c, 0x1b, 0x4f, 0x7a, 0x2c, 0x8c,
- 0xf5, 0xda, 0x11, 0x5b, 0xef, 0x6b, 0x0d, 0x7d, 0xd8, 0x11, 0x4c, 0x1e,
- 0x2a, 0x97, 0x7a, 0x5b, 0xe5, 0xaa, 0xc1, 0xd8, 0x79, 0x09, 0x46, 0xed,
- 0x96, 0xf7, 0x82, 0x1f, 0xa5, 0x9e, 0x86, 0xb9, 0x58, 0xbe, 0xec, 0xcb,
- 0x9a, 0x13, 0xac, 0xc1, 0xb8, 0x23, 0x57, 0xd6, 0xfb, 0x62, 0xb2, 0x3e,
- 0xb6, 0xb8, 0x66, 0x49, 0xf6, 0x0e, 0x2f, 0x8a, 0x5a, 0xdb, 0x1b, 0xdb,
- 0x58, 0x9b, 0xc8, 0x97, 0x4b, 0x3d, 0x0d, 0xe3, 0x64, 0x0e, 0xb8, 0xf4,
- 0x03, 0xeb, 0x6b, 0xfb, 0x37, 0xd6, 0xee, 0x90, 0x54, 0x0f, 0xd7, 0xeb,
- 0x7d, 0x6d, 0x1b, 0xb8, 0x53, 0x21, 0x3d, 0xbd, 0x6d, 0x1b, 0x38, 0x6c,
- 0xe2, 0x6c, 0x18, 0x0f, 0x13, 0xe7, 0xc0, 0x06, 0xce, 0xfd, 0x9b, 0xe9,
- 0x39, 0x21, 0xf0, 0x41, 0xb1, 0xd6, 0x8c, 0x1c, 0xb8, 0x50, 0x1e, 0x1c,
- 0xff, 0xa2, 0x20, 0xe6, 0xed, 0xdf, 0x16, 0xfa, 0x64, 0xf3, 0x80, 0x0b,
- 0x5e, 0x99, 0x42, 0x1f, 0xa7, 0x49, 0x09, 0x72, 0x7e, 0xa8, 0x26, 0x07,
- 0xd6, 0x6a, 0x12, 0xea, 0x12, 0x75, 0xe2, 0x32, 0x6c, 0x4c, 0x8a, 0xbb,
- 0x32, 0x1d, 0x13, 0x66, 0xc6, 0x82, 0xad, 0xc9, 0x78, 0x09, 0x3e, 0xd9,
- 0xc8, 0xec, 0x79, 0x3b, 0x67, 0x3c, 0xe9, 0x1b, 0x88, 0xdb, 0x39, 0xe9,
- 0x38, 0xe8, 0x8e, 0x62, 0xbe, 0x46, 0xdb, 0x82, 0x5f, 0xa9, 0x13, 0xf7,
- 0x7c, 0xb7, 0x74, 0x21, 0x2e, 0xd6, 0x5e, 0xda, 0x11, 0xd8, 0x8e, 0x98,
- 0x26, 0x7c, 0xed, 0xcc, 0x28, 0xe3, 0x78, 0x6b, 0x0c, 0xf0, 0x13, 0x46,
- 0x66, 0x6c, 0xe7, 0xf1, 0xda, 0x9d, 0x3b, 0x0b, 0xb5, 0xe2, 0xce, 0x42,
- 0xd9, 0xa2, 0x9d, 0xe8, 0xee, 0x28, 0xfa, 0x2a, 0x57, 0x4a, 0xc2, 0x26,
- 0x2e, 0xab, 0x3c, 0xe2, 0xb5, 0x7a, 0x1d, 0xf6, 0x47, 0xfb, 0x16, 0x19,
- 0xf7, 0xb0, 0xc7, 0xc8, 0x87, 0x90, 0x3b, 0x68, 0x83, 0x4f, 0xcb, 0xe2,
- 0xd4, 0xfa, 0xc8, 0xbf, 0x85, 0xf6, 0xc9, 0xfe, 0xfb, 0x7e, 0xe0, 0xef,
- 0xef, 0xe8, 0x0e, 0xe6, 0xde, 0x0a, 0x6d, 0x3a, 0xc2, 0x45, 0x3c, 0xc3,
- 0xda, 0x38, 0x72, 0x92, 0xf1, 0xba, 0xa9, 0xd1, 0x3f, 0xe7, 0x3c, 0xe6,
- 0x12, 0xcc, 0x23, 0xa6, 0x43, 0x3f, 0x27, 0xd9, 0x1c, 0xfc, 0x88, 0x8e,
- 0xdc, 0xa2, 0x00, 0xbb, 0x31, 0x33, 0x57, 0x64, 0x46, 0xf9, 0x48, 0x89,
- 0xb5, 0x64, 0x9e, 0x00, 0xcc, 0x7f, 0xc0, 0xe6, 0xda, 0xba, 0x43, 0x3d,
- 0x0c, 0x7d, 0xbc, 0xf2, 0xbb, 0x80, 0xbd, 0xbc, 0x05, 0xf6, 0xdd, 0x46,
- 0x58, 0xbc, 0xbf, 0xb8, 0xe5, 0xfd, 0x4f, 0x69, 0xbf, 0x78, 0xb7, 0x0a,
- 0x7f, 0xda, 0x1a, 0xda, 0xfe, 0x05, 0x29, 0xc0, 0xb7, 0x9a, 0x36, 0x73,
- 0xc7, 0xdb, 0xb0, 0x16, 0xe3, 0x1a, 0x68, 0x84, 0xbf, 0x40, 0xcc, 0x04,
- 0xbf, 0x11, 0x13, 0x12, 0x37, 0x30, 0x3f, 0xa2, 0x9f, 0x00, 0x2c, 0xfd,
- 0x2f, 0x61, 0x5f, 0xe9, 0x20, 0xcf, 0x0b, 0x35, 0xae, 0xa1, 0xaf, 0x12,
- 0xdf, 0x1d, 0x6d, 0x83, 0x46, 0xf9, 0xaf, 0x19, 0x76, 0x04, 0x1b, 0xe1,
- 0xdd, 0x0a, 0xcb, 0x7c, 0x85, 0xb8, 0xbb, 0xc3, 0x3c, 0x60, 0x4c, 0xb2,
- 0xf5, 0x2c, 0x7e, 0x45, 0x99, 0x7c, 0x16, 0xb9, 0x98, 0xdd, 0x42, 0x5e,
- 0x90, 0x35, 0x56, 0xc0, 0xa3, 0x68, 0xdd, 0x13, 0xbd, 0x9b, 0xc7, 0xf7,
- 0xc5, 0x37, 0x7c, 0x25, 0x2d, 0x4d, 0xb2, 0x88, 0x15, 0xe0, 0x71, 0x6a,
- 0x42, 0xcf, 0x24, 0x24, 0x57, 0x0b, 0xf8, 0x8b, 0x78, 0x0b, 0xff, 0xc8,
- 0x2e, 0x64, 0xb2, 0xee, 0x07, 0x23, 0x99, 0x53, 0xcf, 0xb2, 0x90, 0x4d,
- 0x0a, 0xba, 0x34, 0x86, 0xb5, 0x72, 0x02, 0x38, 0x18, 0x87, 0x1d, 0x3d,
- 0x13, 0x97, 0x82, 0xc5, 0x7c, 0x41, 0xe5, 0x7a, 0x59, 0xfa, 0x01, 0x3d,
- 0xd3, 0x86, 0x39, 0xf6, 0x1f, 0xee, 0x0e, 0x64, 0xdd, 0xc9, 0xf1, 0xb8,
- 0x9e, 0xe9, 0xde, 0x32, 0xff, 0x7a, 0x67, 0x40, 0x9b, 0x1a, 0x63, 0xfe,
- 0x5f, 0xb6, 0x8c, 0xbf, 0x1e, 0xdf, 0x3c, 0x7e, 0x60, 0x67, 0xa4, 0x0f,
- 0x7a, 0xe6, 0x89, 0x90, 0x5e, 0xea, 0xe9, 0x56, 0x5a, 0x7f, 0x13, 0x7d,
- 0x79, 0x0e, 0x38, 0x95, 0x8e, 0xff, 0x06, 0xfa, 0xb2, 0x0e, 0xfb, 0x09,
- 0xfa, 0xd2, 0x48, 0xc3, 0x7a, 0x5d, 0x51, 0xd1, 0x91, 0x93, 0xba, 0xa3,
- 0x7b, 0x90, 0x77, 0xa4, 0x24, 0x5f, 0x07, 0xef, 0xd6, 0xe3, 0xea, 0x3a,
- 0x4c, 0x71, 0x03, 0x26, 0x88, 0x3b, 0xf9, 0xba, 0x8f, 0x3c, 0xae, 0x31,
- 0x06, 0x0f, 0xa3, 0x5f, 0xc4, 0x59, 0x57, 0x64, 0xd2, 0x5b, 0xcb, 0xea,
- 0xf6, 0xa9, 0x20, 0x0f, 0xb5, 0xbf, 0xad, 0xe5, 0x17, 0x99, 0xa3, 0xc6,
- 0xd0, 0x57, 0xf5, 0x07, 0x62, 0xdc, 0x33, 0x5a, 0x76, 0x79, 0x0e, 0xf9,
- 0xe9, 0x12, 0x7e, 0x67, 0xf1, 0xab, 0xe1, 0x17, 0xd5, 0x01, 0x2f, 0xa0,
- 0x8e, 0x50, 0xfe, 0x1e, 0xb1, 0x29, 0xd8, 0xff, 0x67, 0x4b, 0xc8, 0x8f,
- 0xe7, 0x12, 0xf2, 0x94, 0xad, 0xf7, 0xea, 0x81, 0x8f, 0xcb, 0x22, 0xb7,
- 0xb6, 0x2e, 0xcb, 0x97, 0xc2, 0x1c, 0x4d, 0xe4, 0x9d, 0x0a, 0x64, 0xb9,
- 0xff, 0x48, 0xe8, 0x9f, 0xbe, 0xf6, 0xa0, 0xab, 0x7c, 0x79, 0x98, 0x83,
- 0xc1, 0xef, 0x64, 0x15, 0xd4, 0x1b, 0xe0, 0x8f, 0x26, 0xef, 0x41, 0x8f,
- 0xdf, 0xa9, 0xb4, 0x83, 0x1e, 0x5b, 0x0a, 0xc7, 0x90, 0xbb, 0x68, 0x83,
- 0xd6, 0x36, 0xad, 0x1d, 0x79, 0x18, 0xfc, 0x8e, 0x1a, 0x93, 0x67, 0x17,
- 0xa7, 0x16, 0xca, 0x3a, 0x60, 0xc1, 0xf3, 0x51, 0xf4, 0xa1, 0x7f, 0x97,
- 0x2a, 0x5c, 0xa7, 0xcb, 0xbb, 0x15, 0x43, 0x7e, 0x8e, 0xbc, 0xee, 0x3d,
- 0xfb, 0xe2, 0x14, 0x6c, 0xb0, 0x0f, 0xf1, 0x0a, 0xb5, 0xd0, 0x1e, 0xc6,
- 0x8c, 0x01, 0x13, 0xcf, 0x3c, 0x7e, 0x87, 0x91, 0xe7, 0x5d, 0x7b, 0xcd,
- 0x27, 0xc1, 0x93, 0xb6, 0x18, 0xd6, 0x10, 0xde, 0x04, 0x6d, 0x5d, 0xd0,
- 0xc1, 0xb4, 0x35, 0x21, 0xdd, 0x96, 0xca, 0x9d, 0x34, 0xce, 0x07, 0x7e,
- 0xf2, 0xe3, 0xf3, 0xe4, 0xb3, 0x01, 0x1d, 0xe2, 0x98, 0xef, 0xe8, 0xcf,
- 0x89, 0x2f, 0x7d, 0x30, 0x8b, 0xc3, 0x5c, 0xaa, 0x04, 0xfd, 0x68, 0x4e,
- 0xb4, 0x28, 0xa6, 0xd2, 0x4f, 0xe7, 0x61, 0xab, 0x1c, 0x8f, 0x8b, 0x92,
- 0xc1, 0x26, 0x79, 0x52, 0x8f, 0x56, 0xa7, 0x66, 0x6c, 0xca, 0xd5, 0x92,
- 0xe9, 0x72, 0x24, 0x57, 0xca, 0x08, 0x75, 0x66, 0xe5, 0xdb, 0x90, 0xab,
- 0x1e, 0xd6, 0x20, 0xf0, 0x03, 0x73, 0x94, 0x2f, 0xea, 0xc4, 0x0a, 0xf2,
- 0xb0, 0x8a, 0xc4, 0x83, 0x1a, 0xea, 0x19, 0xd4, 0x1d, 0x90, 0x5f, 0x79,
- 0x0e, 0x38, 0x12, 0x78, 0x2e, 0xe1, 0x99, 0xc4, 0xf3, 0x2c, 0x9e, 0xfd,
- 0x78, 0xd6, 0x68, 0x1f, 0x61, 0xde, 0xf3, 0x31, 0x7a, 0x60, 0x27, 0x79,
- 0xda, 0xb4, 0x7c, 0xaf, 0x9e, 0x91, 0xbf, 0xad, 0x1f, 0x94, 0xbf, 0xa9,
- 0x8f, 0xca, 0x5f, 0xd7, 0x1d, 0x79, 0xb9, 0xbe, 0x5f, 0xfe, 0xaa, 0x3e,
- 0xcc, 0x9a, 0x10, 0x39, 0x5c, 0x0a, 0xbe, 0xf9, 0xbc, 0x3c, 0xe8, 0xd5,
- 0xe1, 0x73, 0x28, 0xff, 0x8b, 0x53, 0xd9, 0xda, 0x75, 0x52, 0x78, 0xd6,
- 0x42, 0x9e, 0x69, 0xb0, 0x2e, 0x93, 0xc7, 0x9c, 0x3b, 0xe2, 0x94, 0xbd,
- 0x6e, 0xb3, 0x4e, 0x39, 0x49, 0x38, 0xd4, 0xbb, 0x1a, 0xf2, 0x97, 0x16,
- 0x99, 0x48, 0xa4, 0x57, 0x5c, 0x23, 0x19, 0xfa, 0xa3, 0x3b, 0x01, 0x87,
- 0x3d, 0xbd, 0x0e, 0x59, 0x7b, 0x1e, 0xb6, 0xe0, 0xa0, 0x56, 0x4e, 0xc4,
- 0xe0, 0xfb, 0x54, 0x7e, 0xa2, 0x7c, 0x4b, 0xe0, 0x4b, 0xa3, 0x9a, 0x91,
- 0x73, 0xd9, 0x70, 0x8e, 0xf1, 0xd1, 0x02, 0xec, 0x72, 0x18, 0x43, 0xb6,
- 0xe2, 0xa4, 0x6f, 0x3c, 0x16, 0xfa, 0xc7, 0x15, 0x39, 0xe1, 0x0d, 0x66,
- 0xaf, 0x20, 0xf6, 0x68, 0x2d, 0x51, 0x5e, 0xb4, 0x0b, 0xb4, 0xf9, 0xfe,
- 0xdd, 0xac, 0xbf, 0xe3, 0xa6, 0xfc, 0x70, 0x36, 0x6d, 0x3d, 0xa2, 0xcf,
- 0x40, 0xce, 0xbe, 0x7f, 0xd4, 0x4e, 0x9f, 0x9a, 0xd0, 0x3b, 0xe5, 0x27,
- 0xcf, 0x30, 0x26, 0xaf, 0x4e, 0x7d, 0x1f, 0x7a, 0x50, 0x5d, 0x6a, 0x95,
- 0x6a, 0xd5, 0x94, 0x4b, 0x23, 0x83, 0x6a, 0xdf, 0x6a, 0x2d, 0x8e, 0x3c,
- 0xaf, 0x4d, 0xa6, 0xfb, 0x94, 0xb2, 0xc3, 0x6f, 0x0f, 0x2b, 0xbf, 0xed,
- 0xda, 0x78, 0xd6, 0x92, 0xd6, 0x66, 0x5a, 0x5e, 0x96, 0x82, 0x07, 0x1d,
- 0x8b, 0xef, 0x02, 0x4f, 0xd8, 0x1f, 0xb4, 0x0a, 0x3a, 0x62, 0xa0, 0x39,
- 0x68, 0x3d, 0xa8, 0xff, 0xd2, 0xff, 0x1d, 0x93, 0x7c, 0x7c, 0x1b, 0xb1,
- 0x85, 0xb1, 0x52, 0x53, 0x7a, 0xb7, 0xb0, 0xf4, 0x53, 0x8b, 0xfe, 0x65,
- 0xa5, 0xb6, 0x2b, 0x1c, 0xd3, 0xbf, 0x73, 0xdc, 0x2e, 0x2f, 0x57, 0xb7,
- 0xcb, 0x62, 0x95, 0xef, 0x5b, 0x65, 0xa1, 0x3a, 0x78, 0xa5, 0x57, 0xef,
- 0x93, 0xd5, 0xeb, 0x6e, 0xb4, 0xee, 0xd7, 0xc1, 0x93, 0x63, 0x1f, 0xc9,
- 0x07, 0x23, 0xdd, 0xf2, 0xd6, 0x7d, 0xe9, 0x17, 0xfe, 0x44, 0x87, 0x3e,
- 0x8e, 0x74, 0xd0, 0xce, 0xd0, 0xe7, 0x7c, 0xfa, 0x4a, 0x56, 0xa7, 0x9e,
- 0xfd, 0x00, 0xfa, 0x95, 0xae, 0x04, 0x3a, 0x49, 0xdc, 0xc4, 0x0b, 0xf9,
- 0xd8, 0x6f, 0x00, 0x27, 0xde, 0xd5, 0x06, 0x81, 0xeb, 0x0d, 0xc5, 0x8b,
- 0xbb, 0x9d, 0xf4, 0x15, 0x84, 0x28, 0xff, 0x92, 0x3d, 0x38, 0x3c, 0xa0,
- 0xef, 0x92, 0x6a, 0xf2, 0x46, 0xeb, 0xbb, 0x88, 0x07, 0xd9, 0x44, 0xfa,
- 0xd4, 0x45, 0x59, 0x9d, 0xba, 0x60, 0x53, 0x17, 0x69, 0xc3, 0xff, 0x80,
- 0x9c, 0xd4, 0x92, 0x4a, 0x8d, 0xbe, 0x8b, 0xb8, 0x58, 0x17, 0xec, 0xb5,
- 0x4e, 0x80, 0x06, 0x77, 0x3f, 0xde, 0x61, 0xde, 0xf8, 0x3c, 0xe5, 0xd6,
- 0xc2, 0xb5, 0xc3, 0x59, 0xbd, 0x7f, 0x0b, 0x8f, 0x06, 0xad, 0x43, 0x3a,
- 0xf7, 0xfb, 0x2f, 0xec, 0xfb, 0x3e, 0x68, 0x1d, 0xc4, 0x5a, 0xc4, 0xd0,
- 0x64, 0xe3, 0x1e, 0x3f, 0x52, 0x7b, 0x3c, 0x5b, 0x43, 0x0e, 0xb8, 0xbe,
- 0x07, 0xe6, 0x6a, 0x3a, 0xce, 0x69, 0x2a, 0xb9, 0x5c, 0x1a, 0x21, 0x7f,
- 0x6f, 0xef, 0x61, 0x2c, 0x37, 0x32, 0x2f, 0x85, 0x79, 0x46, 0x4c, 0x7e,
- 0x8c, 0xba, 0x6b, 0x12, 0xfe, 0x7f, 0x61, 0xef, 0x20, 0x68, 0x40, 0x7d,
- 0x9a, 0x54, 0xf1, 0x7c, 0xca, 0x05, 0x8e, 0x9c, 0xc2, 0xfd, 0xa6, 0x2c,
- 0x01, 0xf7, 0x38, 0xf9, 0x00, 0xdc, 0x33, 0x9c, 0x57, 0x32, 0xc0, 0x7c,
- 0x2d, 0x05, 0xbc, 0xbd, 0xa1, 0xff, 0x8b, 0x43, 0x57, 0xf7, 0x59, 0x77,
- 0x4b, 0x2c, 0xf4, 0x7f, 0x71, 0x79, 0xeb, 0x79, 0xe8, 0x7d, 0x9c, 0xfa,
- 0x93, 0xe8, 0xd9, 0xd0, 0x9f, 0x46, 0xfc, 0xad, 0x92, 0xaf, 0xc4, 0x80,
- 0x17, 0x39, 0xf7, 0x28, 0xf1, 0x62, 0x5c, 0xa5, 0x2e, 0x17, 0x43, 0x5d,
- 0xee, 0x08, 0x71, 0xaf, 0x41, 0x97, 0xd3, 0xa9, 0x55, 0x9d, 0xf5, 0xd5,
- 0x4e, 0x55, 0xf3, 0x1a, 0xb0, 0xaf, 0x42, 0x99, 0xb1, 0x88, 0xb6, 0x75,
- 0x71, 0x6a, 0x12, 0x35, 0x6c, 0xa1, 0x7c, 0x50, 0x2f, 0xd4, 0x47, 0xf5,
- 0x82, 0x47, 0x7d, 0xdb, 0x6b, 0x2d, 0x28, 0x1e, 0x27, 0x65, 0xa1, 0xfe,
- 0x81, 0x5f, 0xda, 0xbb, 0x0d, 0x7d, 0xe8, 0xfe, 0x38, 0xe5, 0x7b, 0x3d,
- 0xe9, 0x42, 0x50, 0x27, 0xbf, 0x13, 0x72, 0x66, 0xe8, 0x7b, 0xdd, 0xcc,
- 0xd1, 0x96, 0x87, 0x88, 0x1f, 0x74, 0x24, 0x12, 0xb2, 0xe8, 0x71, 0x8f,
- 0xd5, 0x29, 0xf2, 0xb2, 0x30, 0x67, 0xc9, 0x09, 0x25, 0x3f, 0x9e, 0x9b,
- 0xf7, 0x47, 0x86, 0x4c, 0xc6, 0x07, 0xad, 0x47, 0x25, 0x7d, 0x65, 0xcd,
- 0x48, 0xbf, 0x30, 0x81, 0xb8, 0xba, 0x30, 0x6f, 0x88, 0xab, 0xea, 0x30,
- 0xca, 0x28, 0x5d, 0x81, 0x35, 0x86, 0x67, 0xbf, 0xa7, 0xe1, 0xec, 0x5d,
- 0x72, 0xe1, 0xf9, 0xcf, 0xc3, 0xee, 0x5f, 0x81, 0x2c, 0xcc, 0xd4, 0x71,
- 0xe4, 0x19, 0xcf, 0xc9, 0xa0, 0x55, 0x42, 0xfe, 0x0c, 0xbe, 0xa3, 0xbd,
- 0xa2, 0x6c, 0x60, 0x41, 0xc7, 0xb8, 0x9f, 0x7c, 0xe2, 0x78, 0xb7, 0x2c,
- 0xf4, 0x05, 0x36, 0xce, 0x77, 0x03, 0xc0, 0x11, 0xbc, 0xe3, 0xf8, 0xb7,
- 0x64, 0x40, 0xbd, 0xab, 0xaa, 0x75, 0x25, 0xe9, 0x0d, 0xe5, 0xf7, 0x18,
- 0xf6, 0x24, 0x8f, 0xa3, 0xf9, 0x4e, 0x09, 0x6c, 0x29, 0xe2, 0xbb, 0x25,
- 0x47, 0x6b, 0x09, 0xb9, 0xa7, 0x96, 0x94, 0x2f, 0xd7, 0xfa, 0x25, 0x0f,
- 0x39, 0x4e, 0x8e, 0x3e, 0xd9, 0xc3, 0xb3, 0xe5, 0x96, 0xd2, 0x2f, 0x88,
- 0x4e, 0x5a, 0xab, 0x72, 0xdc, 0x8b, 0xe8, 0xe9, 0x08, 0xe9, 0x33, 0xc3,
- 0x71, 0x2c, 0xa4, 0xa1, 0x11, 0x5f, 0x07, 0x70, 0x65, 0x81, 0xe7, 0xa5,
- 0x10, 0x0f, 0xfd, 0x08, 0x68, 0x3d, 0x96, 0x94, 0x25, 0x8f, 0x74, 0x6c,
- 0x97, 0x52, 0x82, 0xfd, 0x57, 0xa0, 0x6f, 0xc4, 0xb3, 0x8d, 0xf9, 0xcd,
- 0x26, 0x1e, 0x3f, 0x5c, 0x2b, 0x82, 0xc7, 0xe4, 0x2f, 0xe1, 0xe0, 0xaf,
- 0xbf, 0x40, 0xf9, 0xed, 0x43, 0x8e, 0x6f, 0x07, 0xba, 0x69, 0x6d, 0xec,
- 0x99, 0x9f, 0xeb, 0x82, 0xac, 0xb8, 0x6f, 0xbb, 0x1c, 0x83, 0xdd, 0xe7,
- 0xaa, 0xdc, 0xff, 0x18, 0xf4, 0xe8, 0x2d, 0xb5, 0x7f, 0x7e, 0xa9, 0x2f,
- 0x5c, 0xcf, 0xb5, 0x5d, 0x5b, 0xd6, 0xb6, 0xca, 0xa1, 0x8a, 0x75, 0x8d,
- 0xf5, 0xbf, 0x8f, 0xf5, 0xba, 0x9c, 0x1e, 0xe5, 0x7a, 0xe2, 0x01, 0x5c,
- 0x35, 0xf1, 0x29, 0x78, 0xe2, 0xaa, 0xde, 0xcf, 0x55, 0x5b, 0x25, 0x57,
- 0x89, 0x70, 0x11, 0xcf, 0x47, 0xa8, 0x87, 0xbf, 0xaa, 0x70, 0x4d, 0x2a,
- 0x5c, 0x78, 0x5f, 0xa5, 0xcf, 0xb9, 0x15, 0xeb, 0x3b, 0xe8, 0xff, 0xa5,
- 0x14, 0xef, 0x94, 0x92, 0xaa, 0xe9, 0xdb, 0x95, 0xaf, 0x29, 0xc5, 0xdb,
- 0xf0, 0xbe, 0x13, 0x36, 0xbf, 0x0f, 0xb9, 0x45, 0x17, 0xeb, 0xdc, 0x2d,
- 0x73, 0x5b, 0xe9, 0x8f, 0x6d, 0xa1, 0x3f, 0x06, 0xb8, 0x5e, 0xec, 0x19,
- 0xc0, 0xe5, 0x01, 0x37, 0x3d, 0x07, 0x3e, 0x3b, 0xf4, 0x2b, 0x8c, 0x93,
- 0xd7, 0x29, 0x5a, 0xa6, 0x97, 0xfe, 0x1b, 0xe7, 0xea, 0xc3, 0xda, 0x68,
- 0x1c, 0xf0, 0xe1, 0x69, 0xe0, 0x99, 0xab, 0xaa, 0xbb, 0x0b, 0xc8, 0x60,
- 0x7b, 0x9c, 0x67, 0x2f, 0x55, 0x3f, 0x8b, 0x67, 0xd7, 0x35, 0xf0, 0x8b,
- 0xbc, 0x22, 0xbd, 0xa4, 0x95, 0xf7, 0x48, 0xb0, 0x37, 0x07, 0x7a, 0x1c,
- 0x37, 0x24, 0x3f, 0x6a, 0x21, 0x3f, 0xe7, 0x3d, 0x2c, 0xed, 0xd2, 0xe2,
- 0xdd, 0x67, 0x4c, 0xb7, 0x19, 0x6b, 0x4d, 0x75, 0xf6, 0xe3, 0x4b, 0xbc,
- 0x8b, 0x4d, 0xf1, 0xee, 0x6e, 0x98, 0xd7, 0x18, 0x8f, 0x2c, 0xd9, 0xf2,
- 0x78, 0x6d, 0x58, 0x1e, 0xad, 0xa5, 0xad, 0xfb, 0xe1, 0x03, 0x0a, 0xeb,
- 0x77, 0xb4, 0x43, 0x71, 0xfa, 0x2f, 0x13, 0x79, 0x60, 0x8b, 0x1d, 0xe4,
- 0x05, 0x25, 0xd6, 0x6c, 0x73, 0x69, 0xde, 0xe3, 0x58, 0x55, 0xd9, 0x9a,
- 0x3b, 0xfc, 0x5f, 0xe6, 0x0d, 0xdc, 0x9f, 0xfe, 0x1a, 0x79, 0x82, 0x87,
- 0x3c, 0xc1, 0x43, 0x9e, 0xe0, 0x21, 0x4f, 0xf0, 0x90, 0x27, 0x78, 0xc8,
- 0x13, 0x3c, 0xe4, 0x09, 0x1e, 0xf2, 0x04, 0xc4, 0xee, 0xa0, 0x5e, 0x18,
- 0x43, 0xfe, 0x0b, 0xff, 0xe5, 0xdd, 0x06, 0x3e, 0xf1, 0xfe, 0x92, 0x31,
- 0x87, 0xb1, 0x99, 0x73, 0xab, 0xdb, 0x5c, 0xca, 0x4d, 0xf9, 0xbe, 0x3b,
- 0x31, 0x37, 0x1e, 0xe6, 0x23, 0x84, 0x89, 0x62, 0x37, 0xe1, 0xe4, 0xa0,
- 0xeb, 0x68, 0xb0, 0x31, 0xe6, 0x2b, 0x41, 0xcc, 0x0a, 0x72, 0xe5, 0xb7,
- 0x91, 0xb3, 0xa4, 0x90, 0xb3, 0xf4, 0x23, 0x3f, 0xe1, 0x9d, 0x75, 0x74,
- 0xc7, 0x94, 0xd5, 0x8e, 0x7a, 0x63, 0xda, 0x3d, 0x1e, 0x73, 0x69, 0x3b,
- 0x55, 0xd0, 0xf5, 0xb9, 0x5e, 0xf1, 0x25, 0x37, 0xf2, 0x4d, 0xe4, 0xad,
- 0xcf, 0xa9, 0xfb, 0xb4, 0xf1, 0x21, 0xca, 0xbc, 0xf2, 0x09, 0xb9, 0x6b,
- 0xc4, 0xdf, 0xe0, 0x1e, 0x50, 0x5f, 0x20, 0xff, 0x44, 0x7a, 0xce, 0x81,
- 0xe1, 0xe7, 0x62, 0x12, 0x3f, 0xb3, 0x1d, 0x73, 0x96, 0xf4, 0xaa, 0xbb,
- 0x24, 0x88, 0xf2, 0xdc, 0x55, 0xc8, 0xcb, 0x16, 0xfd, 0x1c, 0x6f, 0x1c,
- 0x88, 0x97, 0xfe, 0x75, 0x65, 0x2a, 0x57, 0x5d, 0x51, 0x3a, 0x75, 0xb4,
- 0x96, 0x47, 0x7d, 0xd4, 0xd3, 0x2b, 0xed, 0x26, 0x6a, 0xab, 0x08, 0x37,
- 0x71, 0xfe, 0x32, 0xae, 0x6a, 0x9e, 0x73, 0xeb, 0xf2, 0x84, 0xac, 0xb9,
- 0xcf, 0xca, 0x54, 0xa9, 0x92, 0x4e, 0xb2, 0x56, 0xce, 0x5a, 0x2b, 0x53,
- 0x27, 0x81, 0x63, 0x11, 0xb9, 0x81, 0xa1, 0xf6, 0x5e, 0x99, 0x9a, 0xae,
- 0x04, 0xf7, 0x59, 0x01, 0x0d, 0x8c, 0x57, 0xed, 0x62, 0x2c, 0x04, 0xf7,
- 0x5a, 0xba, 0x5a, 0xcb, 0x75, 0x5c, 0x6f, 0x62, 0x1d, 0xe5, 0x36, 0x8c,
- 0xb5, 0x94, 0x1d, 0x69, 0x58, 0x99, 0x2a, 0x56, 0x1b, 0x69, 0x20, 0x1e,
- 0xe2, 0x8d, 0xce, 0xc3, 0xb3, 0xc4, 0x45, 0x3f, 0xe3, 0xfb, 0x85, 0x91,
- 0xfe, 0x30, 0xef, 0x3a, 0x89, 0xfc, 0xce, 0x0c, 0xf4, 0x5c, 0x8d, 0xbf,
- 0xa3, 0xe2, 0x54, 0x4a, 0xe7, 0x3c, 0x9f, 0x78, 0x37, 0xba, 0x80, 0x39,
- 0x8c, 0x17, 0x23, 0x58, 0x3d, 0x84, 0xed, 0x6c, 0xe0, 0x67, 0x4b, 0xb8,
- 0x1f, 0x69, 0xe2, 0x39, 0x2f, 0x61, 0x2f, 0xd2, 0x45, 0x98, 0x38, 0x68,
- 0x83, 0x2c, 0xbd, 0xff, 0x2d, 0xef, 0x1b, 0xcf, 0x44, 0x9e, 0x9a, 0x58,
- 0x43, 0x78, 0xe2, 0x88, 0xd6, 0xe0, 0xc5, 0xb9, 0x60, 0x9d, 0xbe, 0x7e,
- 0xff, 0xf7, 0x69, 0xfb, 0x36, 0xd2, 0x1a, 0xed, 0x1f, 0xe1, 0x19, 0x0e,
- 0xe4, 0xb6, 0xbe, 0x5e, 0xfd, 0x9f, 0x61, 0x78, 0x42, 0x17, 0x3f, 0x76,
- 0x8f, 0x3a, 0xdc, 0x50, 0x87, 0x46, 0xf7, 0x17, 0xbc, 0x0f, 0x60, 0x7d,
- 0xcf, 0x6f, 0x07, 0x8d, 0xb5, 0xe2, 0xcb, 0x61, 0x2c, 0xdb, 0x29, 0x59,
- 0x93, 0x75, 0xc3, 0xf9, 0x70, 0xbc, 0x03, 0xb1, 0x8d, 0xe3, 0x3a, 0xf8,
- 0x0b, 0x5d, 0x76, 0xda, 0xc3, 0xba, 0x25, 0x1e, 0x7c, 0xe3, 0x19, 0xa6,
- 0x1d, 0xb1, 0xee, 0x6b, 0x0b, 0xe7, 0x22, 0x3b, 0xa2, 0x1f, 0x36, 0xc3,
- 0x39, 0xfa, 0x5b, 0x1d, 0xb5, 0x0b, 0xfb, 0xc0, 0xb3, 0xd8, 0x68, 0x4b,
- 0xd1, 0x33, 0x2e, 0x67, 0xe7, 0x23, 0xbf, 0x05, 0x9f, 0x32, 0x64, 0x86,
- 0xbe, 0xbf, 0x03, 0xbe, 0xaf, 0x4b, 0x0e, 0xc1, 0x67, 0x1d, 0x86, 0xcf,
- 0x3a, 0x82, 0x7a, 0x71, 0x6c, 0xa9, 0xf1, 0x9e, 0x97, 0x35, 0x6a, 0x97,
- 0x76, 0x5c, 0xc9, 0xbf, 0xe8, 0x1b, 0xf6, 0x47, 0xd0, 0x01, 0xd6, 0x5d,
- 0x91, 0x4e, 0xc0, 0xdf, 0x3a, 0x71, 0xe8, 0xc4, 0xd6, 0xfb, 0xe4, 0x61,
- 0xd8, 0x46, 0x7b, 0x56, 0xc5, 0x86, 0xa5, 0x80, 0xf7, 0xa5, 0x6a, 0xc0,
- 0x7b, 0xf8, 0x65, 0xe0, 0x37, 0xa5, 0x58, 0xb3, 0xa4, 0x88, 0x7d, 0x8b,
- 0xd8, 0xb7, 0x88, 0x3a, 0x6f, 0xba, 0xd6, 0xf8, 0x1d, 0xab, 0x33, 0xa4,
- 0x9d, 0x6b, 0xa3, 0xbe, 0xd5, 0x70, 0xfe, 0xe8, 0x79, 0x0a, 0xfc, 0x7f,
- 0x0c, 0xfc, 0x3f, 0x81, 0xfa, 0xe6, 0x8f, 0x50, 0xdf, 0x7c, 0x0d, 0xf5,
- 0xcd, 0x71, 0xd4, 0x37, 0x13, 0xa8, 0x6f, 0xbe, 0x0a, 0xff, 0xf1, 0x15,
- 0xf8, 0x8f, 0x63, 0xf0, 0x1f, 0xe3, 0xea, 0xee, 0xe9, 0xa8, 0xb7, 0xf5,
- 0x4e, 0x25, 0xda, 0x8b, 0xed, 0x67, 0x22, 0x76, 0x11, 0x67, 0x1a, 0x93,
- 0x6a, 0x9d, 0xf5, 0x8d, 0x23, 0xee, 0x41, 0xd6, 0x37, 0xc7, 0xb4, 0x09,
- 0xe4, 0xef, 0xf7, 0xef, 0x67, 0xdd, 0x13, 0xd7, 0x72, 0xaa, 0xee, 0x49,
- 0x9f, 0x77, 0x91, 0x22, 0x21, 0xf7, 0xc3, 0x99, 0xd3, 0x67, 0x73, 0xa0,
- 0x25, 0xc8, 0xf9, 0x7a, 0x42, 0xbf, 0xd7, 0x21, 0x8b, 0xb3, 0xa8, 0x19,
- 0xbc, 0x1f, 0x6b, 0x05, 0xe5, 0x1b, 0x2d, 0x8c, 0x51, 0x2b, 0x7b, 0xff,
- 0x1c, 0x8e, 0x47, 0x64, 0x72, 0x1e, 0xb5, 0xed, 0xf3, 0xff, 0xa8, 0xe5,
- 0xd4, 0xd8, 0xc1, 0x18, 0xf9, 0xee, 0xf3, 0x7f, 0x1f, 0x8e, 0x8b, 0xa1,
- 0x3e, 0x84, 0xb4, 0x5a, 0x0e, 0x9e, 0xdd, 0x61, 0xce, 0xf1, 0x6a, 0xef,
- 0xe6, 0xff, 0xd3, 0x8e, 0xad, 0x45, 0x13, 0xfb, 0x1b, 0x3b, 0x82, 0xfa,
- 0xac, 0x71, 0xbe, 0xab, 0x61, 0xfe, 0x8a, 0xfa, 0xce, 0x5a, 0x28, 0xb7,
- 0xfd, 0x0a, 0x1e, 0x58, 0x96, 0x86, 0x98, 0xe7, 0x7d, 0xe4, 0xf3, 0xfb,
- 0x9f, 0xab, 0xb7, 0xab, 0x6f, 0x72, 0xae, 0xca, 0xb7, 0x61, 0xe7, 0x23,
- 0xa5, 0x1d, 0x81, 0x2f, 0x60, 0x3f, 0xa1, 0x05, 0xfe, 0xfd, 0x8f, 0x81,
- 0x07, 0xbc, 0xf6, 0x1a, 0x6b, 0x38, 0x2b, 0xbc, 0x4b, 0xb9, 0x32, 0xc5,
- 0xdc, 0xba, 0xa4, 0x70, 0xb3, 0xd6, 0x63, 0xdd, 0x17, 0xc5, 0x80, 0x08,
- 0xd7, 0xcf, 0x13, 0x01, 0xdd, 0xe3, 0xa8, 0xe9, 0x08, 0x13, 0x8d, 0x1b,
- 0xeb, 0xbf, 0x8e, 0xf0, 0x1e, 0xee, 0x4a, 0x90, 0x57, 0x29, 0x7c, 0x66,
- 0x88, 0xef, 0x3f, 0xfd, 0xc0, 0xf7, 0x70, 0xbd, 0xd5, 0xb0, 0xfe, 0x3c,
- 0x72, 0x3d, 0xde, 0x99, 0xec, 0x52, 0xdf, 0x19, 0xdf, 0x9f, 0xed, 0x94,
- 0x5f, 0x3c, 0xe3, 0xfb, 0xe3, 0x4e, 0x7a, 0xf8, 0x4d, 0xd4, 0x1e, 0x67,
- 0x68, 0x27, 0x23, 0xa4, 0x73, 0x30, 0x35, 0x2d, 0x03, 0xbd, 0x41, 0x2e,
- 0xfe, 0x75, 0xed, 0xe3, 0x74, 0xeb, 0xe1, 0x3e, 0x3f, 0x6c, 0xd8, 0x27,
- 0xd5, 0xb0, 0xcf, 0x0a, 0x6d, 0xb6, 0x7a, 0x2f, 0xce, 0x5c, 0xdc, 0x75,
- 0xa3, 0x95, 0x08, 0xeb, 0xb2, 0x47, 0x47, 0xda, 0xa4, 0xd2, 0x97, 0x5e,
- 0xf9, 0x11, 0xf2, 0xf5, 0xc2, 0x08, 0xe6, 0x12, 0x83, 0x78, 0xc7, 0xf9,
- 0x74, 0x15, 0xb9, 0xe8, 0x4a, 0x55, 0x86, 0xb0, 0x3e, 0x5d, 0x14, 0xe1,
- 0x3c, 0xfb, 0x8a, 0xb6, 0x6a, 0xe8, 0x03, 0x92, 0x6b, 0x38, 0xf3, 0x04,
- 0xea, 0xaf, 0x13, 0xeb, 0xf5, 0x30, 0xf7, 0xb9, 0x59, 0x5b, 0x53, 0xb9,
- 0xf1, 0x01, 0xad, 0x98, 0x08, 0xce, 0xf8, 0x87, 0xf0, 0x17, 0x86, 0xce,
- 0xb5, 0xef, 0x03, 0xb7, 0x26, 0x0b, 0xcf, 0x18, 0xea, 0x0e, 0xb6, 0x30,
- 0x42, 0x59, 0xf3, 0x79, 0x2d, 0xde, 0x45, 0x67, 0xfa, 0xf3, 0xf0, 0x4c,
- 0xd9, 0xb0, 0x9e, 0x8e, 0xce, 0x14, 0x93, 0x77, 0x67, 0x2d, 0xac, 0xfd,
- 0x1c, 0xf8, 0x91, 0x97, 0xa5, 0x7a, 0xea, 0x33, 0xf0, 0x94, 0x1b, 0x78,
- 0x63, 0x6e, 0x91, 0x61, 0x71, 0xa3, 0x86, 0x1f, 0x4f, 0xc2, 0x0e, 0xbf,
- 0xd1, 0x1b, 0xdd, 0x0d, 0x1b, 0xb6, 0xcf, 0xba, 0x07, 0x8d, 0xf3, 0xfd,
- 0xb0, 0xc5, 0x14, 0xec, 0x93, 0x39, 0x53, 0x9e, 0xb5, 0x0a, 0xed, 0xc9,
- 0x72, 0x8d, 0xb4, 0x75, 0x4c, 0x86, 0x51, 0xef, 0xf0, 0xfc, 0x19, 0x59,
- 0xac, 0x47, 0x34, 0x8c, 0xc2, 0x1e, 0x0f, 0xe2, 0xb7, 0x1f, 0xef, 0x1c,
- 0xfc, 0x58, 0x2b, 0xad, 0xc8, 0xe3, 0x2a, 0x17, 0x47, 0xae, 0x3d, 0x44,
- 0xfa, 0xee, 0x04, 0x3c, 0xf5, 0x99, 0x7a, 0x7a, 0xa7, 0xb8, 0x7d, 0xf4,
- 0x15, 0x49, 0xe0, 0xc6, 0x1a, 0xef, 0x22, 0x6c, 0xbd, 0x1f, 0xcf, 0xb4,
- 0x55, 0x20, 0x6f, 0x15, 0x7e, 0xdf, 0x37, 0x46, 0xf9, 0x8d, 0xe2, 0x7c,
- 0x38, 0x1e, 0xb4, 0xbe, 0x4c, 0xdd, 0x4b, 0xee, 0x96, 0x95, 0xf9, 0x28,
- 0x0e, 0x9e, 0x86, 0x0d, 0xf2, 0xce, 0x76, 0x0c, 0x7c, 0xe1, 0x58, 0x0b,
- 0xe3, 0x21, 0xe6, 0x17, 0x97, 0x71, 0xee, 0x8c, 0x9c, 0x41, 0xfd, 0x2f,
- 0x7d, 0x7c, 0xa6, 0x80, 0x7f, 0x7b, 0xa8, 0xef, 0x9b, 0xd7, 0x1b, 0x36,
- 0xfb, 0x63, 0xa0, 0xcf, 0x6c, 0x58, 0xcf, 0x35, 0x41, 0x7d, 0xb2, 0x26,
- 0x88, 0xc7, 0x49, 0xff, 0x76, 0x3d, 0xf3, 0xa2, 0x3c, 0xa0, 0xce, 0x54,
- 0x93, 0xe3, 0xf3, 0xbe, 0xef, 0x8e, 0x0e, 0x0e, 0x2f, 0x4a, 0x7a, 0xf8,
- 0xa4, 0xec, 0xb3, 0x0e, 0xb1, 0x1e, 0xb3, 0x88, 0xc7, 0xbf, 0xbd, 0x25,
- 0xe3, 0xfb, 0xa7, 0x41, 0xfb, 0xf7, 0xd5, 0x3e, 0x2f, 0x82, 0x7e, 0xf0,
- 0x4a, 0xd5, 0x24, 0xa4, 0x15, 0xcf, 0x04, 0xe9, 0x2d, 0xcb, 0xf1, 0xfa,
- 0x85, 0x50, 0x36, 0x8f, 0x89, 0xeb, 0x5d, 0x36, 0x5c, 0xbb, 0x0c, 0xd8,
- 0x85, 0x90, 0xb6, 0x0c, 0xe8, 0xc5, 0xfe, 0xf5, 0xb7, 0x13, 0xf4, 0x0d,
- 0x94, 0xb9, 0x8b, 0xac, 0xd1, 0x1d, 0x41, 0x1e, 0x95, 0xf8, 0x24, 0x3f,
- 0x10, 0x97, 0xcd, 0x7e, 0x80, 0xeb, 0xe2, 0xd7, 0xd0, 0x15, 0xd2, 0x51,
- 0x54, 0xfe, 0x53, 0xc5, 0x2d, 0x85, 0xcf, 0xd8, 0xe2, 0x0b, 0x2a, 0xea,
- 0xb9, 0x6a, 0xd0, 0x37, 0x31, 0xfe, 0x51, 0x87, 0xbb, 0xe0, 0xff, 0xa0,
- 0x83, 0xb0, 0xe3, 0xdc, 0x3c, 0xef, 0x27, 0x86, 0x78, 0xaf, 0x74, 0x36,
- 0x0f, 0xd9, 0x2e, 0xf0, 0xfb, 0x63, 0x22, 0xa8, 0x31, 0x83, 0xfa, 0x2b,
- 0x45, 0x5f, 0x88, 0xb6, 0xa4, 0xfc, 0x64, 0x5e, 0x7d, 0x6f, 0x8c, 0x03,
- 0xc6, 0xa7, 0xef, 0x6c, 0xf8, 0x9b, 0x89, 0x1f, 0x64, 0x83, 0xbf, 0x99,
- 0x08, 0xbf, 0xfd, 0x56, 0x83, 0x3c, 0xe2, 0xe1, 0x9a, 0x29, 0x13, 0xb5,
- 0xe8, 0x6f, 0x28, 0x28, 0x07, 0xf8, 0xe6, 0x5a, 0x94, 0x3b, 0xf8, 0x41,
- 0x4d, 0xb3, 0x49, 0x96, 0x4b, 0x61, 0x4e, 0xc4, 0x1a, 0x80, 0x3c, 0xc4,
- 0x78, 0x31, 0xaa, 0x2f, 0x07, 0x20, 0x3f, 0xf0, 0x1c, 0x74, 0xbd, 0x3b,
- 0x1b, 0xd4, 0xb9, 0x25, 0xfa, 0xc5, 0xfe, 0xa8, 0xee, 0xdd, 0x25, 0xa5,
- 0x63, 0x7c, 0x1f, 0x93, 0x77, 0x66, 0x63, 0xea, 0x7d, 0x41, 0x62, 0xe1,
- 0x7b, 0x8e, 0xe3, 0x52, 0x50, 0xef, 0xab, 0x21, 0x3e, 0xd4, 0x69, 0x5f,
- 0x89, 0xc6, 0xa6, 0x76, 0xbc, 0x1e, 0xac, 0x9b, 0xac, 0x57, 0xe5, 0xf1,
- 0xfa, 0x2a, 0xce, 0xaf, 0x49, 0x6e, 0xbc, 0x28, 0xbb, 0x6d, 0x4b, 0xc5,
- 0x7d, 0x37, 0x4e, 0x1d, 0xa3, 0x7e, 0x8d, 0xa9, 0xba, 0xb3, 0x88, 0x7c,
- 0xa1, 0x30, 0xc2, 0x6f, 0x3c, 0xbf, 0xba, 0xab, 0x50, 0x4e, 0x5b, 0x59,
- 0xf9, 0xd0, 0x77, 0x4d, 0x8e, 0x45, 0x47, 0x3d, 0x74, 0xd7, 0xc3, 0xb5,
- 0x0b, 0x77, 0x05, 0x67, 0xc5, 0xfb, 0x1a, 0x61, 0x0d, 0xf5, 0x6d, 0xf6,
- 0x5f, 0x6f, 0x35, 0x65, 0xed, 0x56, 0xdf, 0xbf, 0xdf, 0xb1, 0xc4, 0x0d,
- 0x6b, 0x57, 0x4b, 0xd5, 0xae, 0xed, 0x2a, 0x07, 0x71, 0x47, 0x52, 0x5a,
- 0x1e, 0xf6, 0x7a, 0xc6, 0x43, 0x9d, 0xa3, 0xa7, 0x0f, 0xae, 0xea, 0x16,
- 0x62, 0x6e, 0x3a, 0x35, 0x27, 0x6e, 0x2f, 0xbf, 0x37, 0xcf, 0x38, 0x84,
- 0xd9, 0x19, 0xdc, 0x75, 0xdd, 0x34, 0xae, 0xfc, 0xac, 0x48, 0x18, 0x7b,
- 0x6e, 0x6a, 0xb4, 0x89, 0xc6, 0xdc, 0x92, 0xb6, 0x20, 0x13, 0x26, 0x68,
- 0x29, 0x95, 0xa3, 0x3c, 0x8d, 0x7f, 0x1b, 0xb0, 0x7a, 0xd7, 0xd3, 0xa0,
- 0x73, 0x1a, 0x74, 0xf2, 0x1c, 0xd3, 0xb5, 0x48, 0xe7, 0xa2, 0x5a, 0x81,
- 0x7d, 0xc4, 0x7c, 0x0f, 0x31, 0xdf, 0x43, 0xcc, 0xf7, 0x10, 0xf3, 0x3d,
- 0xc4, 0x7c, 0x0f, 0x31, 0xdf, 0x43, 0xcc, 0xf7, 0x10, 0xf3, 0xbd, 0xf1,
- 0x30, 0x4f, 0x7b, 0x62, 0x3d, 0x4f, 0x5b, 0xa9, 0xf3, 0x3b, 0x94, 0xa2,
- 0xa5, 0x58, 0x94, 0x20, 0xcf, 0x15, 0x9d, 0x39, 0x4d, 0x94, 0xe7, 0x5e,
- 0xfb, 0x9b, 0x48, 0xb0, 0x8e, 0x39, 0x1e, 0xd7, 0x15, 0x35, 0xdd, 0xe6,
- 0xba, 0x20, 0xcf, 0x63, 0x6d, 0xb5, 0x79, 0x0d, 0xf2, 0xb5, 0x0c, 0xfd,
- 0x19, 0xed, 0x22, 0x11, 0xd4, 0x8b, 0x99, 0xf3, 0xf7, 0xba, 0x88, 0xbf,
- 0x85, 0x9a, 0x8a, 0xc1, 0xbc, 0x17, 0xbc, 0x97, 0x7f, 0xb7, 0x00, 0x39,
- 0xf0, 0xdd, 0x7d, 0xac, 0x27, 0x0a, 0xb5, 0xa4, 0x14, 0x17, 0xa3, 0xfc,
- 0x07, 0xeb, 0xbc, 0x7d, 0x5a, 0xbe, 0x42, 0xd9, 0xea, 0x32, 0x9d, 0x00,
- 0x53, 0xec, 0xc6, 0xbc, 0xee, 0x4d, 0x55, 0x23, 0xad, 0xd4, 0x49, 0xcf,
- 0x7e, 0xd0, 0x16, 0xdd, 0xe3, 0x8a, 0x18, 0xb3, 0x09, 0xd1, 0x67, 0x91,
- 0xd3, 0xda, 0x43, 0xea, 0x6f, 0x1d, 0x7a, 0xb0, 0x8f, 0x3e, 0x3b, 0x10,
- 0xfd, 0x2d, 0x06, 0xeb, 0xae, 0xec, 0xc6, 0xfd, 0x2b, 0xcf, 0x91, 0x80,
- 0xbd, 0x7e, 0x69, 0x27, 0xce, 0x06, 0xb9, 0x5e, 0xde, 0xa1, 0xf2, 0x6e,
- 0xf8, 0xce, 0xd3, 0x43, 0xe9, 0x3e, 0xe9, 0xda, 0x25, 0x67, 0x86, 0x58,
- 0xa3, 0xb5, 0x01, 0x1f, 0x61, 0x79, 0xe7, 0xb4, 0x4b, 0x96, 0xe7, 0xe1,
- 0x5b, 0xe7, 0xd3, 0x0e, 0xff, 0xbe, 0x60, 0x01, 0x21, 0x6d, 0xa1, 0x3e,
- 0xd6, 0xc7, 0x98, 0xbc, 0x58, 0xa7, 0xae, 0xf4, 0x60, 0x7d, 0x3f, 0x74,
- 0x71, 0x1b, 0x6c, 0x48, 0xc7, 0xfe, 0x11, 0xee, 0xf7, 0x14, 0xee, 0x1e,
- 0xfb, 0xb7, 0x77, 0x2a, 0xdd, 0xd0, 0xd3, 0x56, 0x4a, 0x07, 0xed, 0x1f,
- 0xab, 0x2d, 0x1d, 0xe1, 0xf7, 0xc2, 0x69, 0xaf, 0xf1, 0xbb, 0xe1, 0x3e,
- 0xad, 0x50, 0xe1, 0xdf, 0x38, 0x0c, 0xc9, 0x21, 0x8b, 0x7f, 0xff, 0xb3,
- 0x4f, 0x7b, 0xa0, 0x4a, 0x18, 0x1b, 0x7d, 0xd6, 0xe1, 0xcb, 0xb0, 0xe5,
- 0xff, 0x29, 0xdc, 0xea, 0x62, 0xdb, 0x3a, 0xcb, 0xf0, 0xfb, 0x1d, 0xe7,
- 0xc7, 0x4d, 0xdd, 0xe4, 0x34, 0x71, 0x12, 0x27, 0xca, 0xc0, 0xc7, 0x39,
- 0x49, 0x3d, 0x39, 0xd5, 0x4e, 0xa2, 0x14, 0x22, 0x88, 0x84, 0xe5, 0xfc,
- 0xcc, 0x63, 0x14, 0x3c, 0xc8, 0xa6, 0x4e, 0x42, 0x55, 0x94, 0x74, 0x5b,
- 0x27, 0xee, 0xb8, 0x40, 0x5c, 0x80, 0x6a, 0x39, 0x69, 0xe9, 0x86, 0x3d,
- 0xa7, 0x5b, 0xba, 0x00, 0x57, 0x9e, 0xe3, 0xa4, 0x4d, 0xe7, 0xcc, 0x1a,
- 0x03, 0x69, 0x70, 0x41, 0x23, 0x33, 0x6d, 0xe3, 0x66, 0x37, 0x48, 0x5c,
- 0x57, 0x29, 0x83, 0x02, 0x6b, 0x2b, 0xb8, 0xe1, 0xef, 0xe2, 0xf0, 0x3c,
- 0xdf, 0x39, 0x76, 0xd3, 0xc0, 0x44, 0x24, 0xeb, 0x7c, 0xe7, 0x3b, 0xdf,
- 0xff, 0xf7, 0xbe, 0xcf, 0xfb, 0x9b, 0x6e, 0xb9, 0x08, 0x3a, 0xce, 0x8d,
- 0xb5, 0xfa, 0xfe, 0xd6, 0x0e, 0x9f, 0x87, 0x07, 0xfb, 0x7c, 0x19, 0xa5,
- 0x75, 0xc9, 0x9c, 0xd6, 0xa7, 0xbb, 0x0e, 0x7d, 0x7b, 0x16, 0x6b, 0x8a,
- 0xe0, 0x1c, 0x1e, 0xe9, 0xd3, 0x78, 0x64, 0xf0, 0xbd, 0xff, 0xd0, 0x7b,
- 0xdf, 0xa1, 0xf7, 0xde, 0xff, 0xd1, 0x9e, 0xe5, 0xc3, 0xf4, 0xc0, 0x75,
- 0x5a, 0x53, 0x1a, 0xfd, 0xf2, 0x93, 0x6a, 0x39, 0x6f, 0x25, 0xa9, 0x0b,
- 0xcc, 0x88, 0xab, 0x66, 0x9c, 0x36, 0x60, 0x5c, 0x9b, 0xac, 0xae, 0x83,
- 0xe6, 0xb1, 0x8f, 0x76, 0x9b, 0xf1, 0xf2, 0x89, 0x3e, 0xf2, 0x4c, 0x10,
- 0xd7, 0x60, 0xd8, 0xc3, 0x11, 0xb4, 0x73, 0x5f, 0x74, 0x12, 0xe6, 0x39,
- 0xed, 0xbf, 0xa1, 0x0e, 0xe3, 0xaa, 0x9c, 0xce, 0xfd, 0x60, 0x9b, 0x16,
- 0xb9, 0x6d, 0xa7, 0xba, 0xfd, 0xdc, 0x20, 0xd8, 0xbb, 0xa9, 0x3e, 0xea,
- 0x17, 0x2f, 0x38, 0xcd, 0x3a, 0x73, 0x5f, 0x98, 0x77, 0x05, 0xa2, 0x79,
- 0x4a, 0xa4, 0x54, 0x11, 0xb9, 0x86, 0xdf, 0x6f, 0x2a, 0x7e, 0xfc, 0x42,
- 0xd1, 0xd6, 0x9e, 0x96, 0x1b, 0xc5, 0x2f, 0x48, 0x15, 0x32, 0x67, 0xc7,
- 0x71, 0xdd, 0x3b, 0x4e, 0x54, 0x9f, 0xf9, 0x0f, 0xf2, 0x4a, 0x62, 0xe3,
- 0x94, 0x69, 0x6d, 0xf2, 0xc3, 0x75, 0xe6, 0xd5, 0x59, 0xe6, 0x1d, 0x61,
- 0x7e, 0x5b, 0x44, 0xd2, 0xe1, 0x80, 0xd6, 0x4b, 0xe5, 0x69, 0x68, 0x12,
- 0xf8, 0xf6, 0x87, 0xf5, 0xb3, 0x7d, 0xf4, 0xb9, 0x7c, 0xbc, 0xce, 0x77,
- 0x03, 0x4f, 0x43, 0xea, 0x76, 0x00, 0xfa, 0x2b, 0x80, 0xc7, 0xe4, 0xb9,
- 0x73, 0xbf, 0xcf, 0x73, 0x6d, 0xa8, 0xa3, 0x0d, 0xdb, 0x26, 0xb9, 0x11,
- 0xe0, 0xa0, 0x1a, 0xd6, 0xf9, 0x47, 0xf5, 0xb0, 0xc6, 0xe5, 0x40, 0x99,
- 0x7e, 0x7b, 0xf3, 0xa8, 0xc6, 0xe8, 0xd4, 0xee, 0xf7, 0xf4, 0x5e, 0x50,
- 0xce, 0x96, 0x1d, 0xd2, 0xaa, 0x29, 0x3b, 0xe0, 0xb5, 0xeb, 0xb5, 0x37,
- 0xfa, 0x79, 0x57, 0x37, 0x6a, 0xdf, 0xef, 0xf3, 0x6c, 0x34, 0xd6, 0x5d,
- 0xe8, 0xf3, 0xea, 0xa2, 0xbe, 0xcd, 0x45, 0xdb, 0xac, 0x84, 0xbd, 0x7d,
- 0x5b, 0x6a, 0x1b, 0xdf, 0x95, 0x77, 0x8b, 0xdf, 0x91, 0x5f, 0x6c, 0x9c,
- 0x81, 0xce, 0x61, 0x95, 0xb2, 0x90, 0x27, 0x6f, 0xd7, 0x5c, 0xf7, 0x6d,
- 0x67, 0x01, 0xf6, 0x81, 0xeb, 0xfe, 0xd6, 0xd9, 0x93, 0xd8, 0xc4, 0x37,
- 0xb1, 0xe7, 0x0c, 0x78, 0x88, 0x58, 0x98, 0x06, 0xbd, 0x7d, 0xb1, 0x5f,
- 0x3a, 0x42, 0x9a, 0x4e, 0x86, 0x27, 0x5a, 0xb1, 0x07, 0xc3, 0xd7, 0xc3,
- 0xb9, 0x97, 0xe9, 0x7e, 0xd2, 0x8c, 0x51, 0xfb, 0x09, 0xe6, 0x6f, 0x05,
- 0x5f, 0x1c, 0xc5, 0x4f, 0xc9, 0x9d, 0x71, 0xac, 0x75, 0x9c, 0xb4, 0xd7,
- 0x2a, 0xb1, 0xc7, 0xb0, 0x8f, 0x4c, 0x8b, 0xdc, 0xcb, 0x6f, 0xf6, 0xd1,
- 0x9f, 0x77, 0x2f, 0xcf, 0xb2, 0xf1, 0xb9, 0x4e, 0x71, 0xa5, 0x05, 0xf2,
- 0x7b, 0x75, 0xd2, 0xd3, 0x95, 0x7e, 0xad, 0x4e, 0xa0, 0xbd, 0x9d, 0x7d,
- 0x4f, 0x51, 0xb7, 0xcb, 0xba, 0xad, 0xd0, 0xc5, 0xe7, 0xa0, 0x03, 0xa5,
- 0x6a, 0x17, 0xa4, 0x3e, 0x1e, 0x42, 0x1b, 0xea, 0x28, 0x1a, 0x4b, 0x64,
- 0x26, 0xcf, 0x7c, 0x2d, 0xe6, 0x4e, 0x61, 0x8d, 0x0b, 0xc4, 0x0d, 0xae,
- 0xb1, 0x8d, 0x31, 0x38, 0xbf, 0xce, 0x06, 0x8d, 0xb0, 0x8e, 0xf4, 0x9d,
- 0x04, 0x4f, 0x26, 0x29, 0x37, 0x31, 0xde, 0x18, 0xc6, 0x63, 0xb9, 0x13,
- 0xe3, 0x5d, 0x90, 0x94, 0xd3, 0x18, 0x73, 0x0a, 0x6d, 0x88, 0x33, 0x53,
- 0xd0, 0x1f, 0x86, 0xd4, 0xec, 0x7a, 0x18, 0xf2, 0xbb, 0x4f, 0x66, 0xcd,
- 0x23, 0x07, 0xf6, 0x98, 0xd5, 0xf6, 0x81, 0x61, 0x8c, 0xf9, 0x6b, 0xea,
- 0x3c, 0xb0, 0x26, 0xf6, 0xc7, 0x0f, 0xb6, 0x71, 0x6a, 0x7d, 0x0d, 0x38,
- 0xb5, 0xf6, 0x61, 0xca, 0x39, 0x2b, 0x33, 0x61, 0xae, 0x89, 0xf5, 0x61,
- 0xac, 0x99, 0x7e, 0xac, 0x67, 0x81, 0x43, 0x47, 0xfc, 0x3a, 0xb6, 0x15,
- 0x23, 0x85, 0xb3, 0xf7, 0xec, 0x5a, 0xd6, 0x7d, 0x56, 0x52, 0x6b, 0x19,
- 0x99, 0xd7, 0xfd, 0x78, 0x86, 0x83, 0x5a, 0xf7, 0x20, 0xaf, 0xc6, 0x7a,
- 0x70, 0x96, 0x89, 0x07, 0x36, 0x70, 0xb4, 0x47, 0xcb, 0xcc, 0x7e, 0x8f,
- 0x67, 0xf1, 0xad, 0x87, 0x77, 0xd4, 0x26, 0xb1, 0x6f, 0x40, 0x46, 0xe6,
- 0x1b, 0xf5, 0x21, 0xf9, 0x24, 0xdf, 0xd1, 0xcf, 0x38, 0xcb, 0xdd, 0xbc,
- 0x29, 0x1f, 0xe7, 0x75, 0x2c, 0x74, 0x31, 0x20, 0xd6, 0x79, 0xcf, 0x3e,
- 0x1f, 0x59, 0x5c, 0x55, 0xfc, 0x3e, 0x72, 0x7e, 0x4b, 0x05, 0xd1, 0x36,
- 0x84, 0x76, 0x5c, 0x87, 0x29, 0x73, 0xf9, 0xbf, 0xb9, 0x4b, 0xa3, 0xae,
- 0x3b, 0xaf, 0xf3, 0xc3, 0x12, 0xe6, 0xaa, 0x6a, 0xe8, 0xe4, 0x71, 0xc9,
- 0x87, 0xdb, 0x31, 0x57, 0xc2, 0xdc, 0x52, 0x23, 0x58, 0x0f, 0xcb, 0x3d,
- 0xe4, 0x89, 0xc8, 0x9e, 0x70, 0x7c, 0x2b, 0xbd, 0xa9, 0x12, 0xd1, 0x61,
- 0x65, 0x25, 0x73, 0xf8, 0xb5, 0x28, 0x1d, 0x47, 0x8c, 0x44, 0x15, 0x78,
- 0x17, 0x7b, 0xb2, 0x4f, 0xba, 0x6e, 0xda, 0x66, 0x7d, 0xc2, 0x0c, 0x29,
- 0xfa, 0x5b, 0x3a, 0x74, 0xbc, 0xf1, 0x72, 0x6f, 0xc2, 0x3c, 0xa9, 0x8e,
- 0xfb, 0xef, 0x53, 0xc0, 0xcc, 0xe6, 0x78, 0x67, 0x36, 0x95, 0x29, 0x2f,
- 0xe5, 0x13, 0xd1, 0x65, 0x65, 0x65, 0x30, 0x66, 0x66, 0x56, 0x11, 0x37,
- 0x12, 0x66, 0x87, 0xa2, 0x4f, 0xb4, 0x5d, 0xef, 0x3b, 0x8d, 0xfe, 0x09,
- 0xd5, 0xe2, 0xaf, 0x87, 0xf7, 0xf5, 0xe3, 0x7e, 0x8f, 0x67, 0x88, 0x39,
- 0xa3, 0xc0, 0x4c, 0xe6, 0x9a, 0xe9, 0xdc, 0x86, 0x64, 0x6c, 0x62, 0x54,
- 0x63, 0xe8, 0xfd, 0x53, 0x7f, 0x47, 0x1d, 0xca, 0x25, 0xd6, 0xc5, 0x7d,
- 0x7e, 0x1b, 0xd5, 0x3a, 0xf3, 0xfd, 0x53, 0x59, 0x9d, 0xc7, 0x58, 0x57,
- 0x31, 0x7f, 0xdf, 0xcd, 0x3b, 0x8b, 0xa6, 0x9c, 0x47, 0x38, 0xce, 0x5a,
- 0x60, 0xba, 0x5d, 0x98, 0x23, 0x3a, 0x57, 0x6c, 0xd0, 0x06, 0xfd, 0x01,
- 0xcc, 0x17, 0x68, 0xc4, 0xbd, 0x2f, 0x88, 0x31, 0x11, 0x3c, 0x40, 0x27,
- 0xd0, 0x35, 0xa1, 0xa3, 0x56, 0x30, 0x4e, 0x6e, 0x5d, 0xb2, 0x5e, 0x7f,
- 0x09, 0x32, 0x27, 0x35, 0x57, 0xf9, 0xb4, 0x31, 0x38, 0x37, 0xe6, 0xc0,
- 0xfb, 0xfd, 0x53, 0xa4, 0x4f, 0x9e, 0x4d, 0x54, 0xcd, 0x6d, 0x70, 0x3d,
- 0x83, 0x32, 0xbf, 0x3e, 0x24, 0xcb, 0xf8, 0xad, 0xae, 0x7b, 0xf7, 0xb6,
- 0x0d, 0xdd, 0x7a, 0x3e, 0x6f, 0x6a, 0x7e, 0x5d, 0x76, 0x18, 0x33, 0x01,
- 0xaf, 0xe8, 0x9c, 0x2a, 0xf6, 0x65, 0x5e, 0xe1, 0x10, 0xe5, 0xa3, 0x53,
- 0x87, 0x5c, 0xdd, 0xae, 0x51, 0x4f, 0x65, 0xbd, 0x35, 0x15, 0x0d, 0x74,
- 0xc9, 0x2a, 0xf0, 0xae, 0x0c, 0xd9, 0x99, 0x7b, 0x25, 0x24, 0xcb, 0x79,
- 0x1d, 0x4f, 0x8e, 0xfe, 0x5e, 0x39, 0x52, 0xad, 0x4d, 0xca, 0x6e, 0x2d,
- 0xae, 0xbf, 0x51, 0xae, 0xe5, 0x5e, 0x37, 0xe4, 0xf9, 0x51, 0x9d, 0x57,
- 0x17, 0x2f, 0x4b, 0xef, 0x00, 0x75, 0x9e, 0x2d, 0x9d, 0x63, 0x07, 0xec,
- 0x80, 0xce, 0xf1, 0x33, 0xe8, 0x1c, 0xef, 0x40, 0xe7, 0xf8, 0x69, 0x11,
- 0xf8, 0x52, 0x4c, 0xfb, 0xf8, 0xbf, 0x08, 0x1c, 0xa2, 0xac, 0xb6, 0xce,
- 0xe0, 0x4e, 0x17, 0xb3, 0xa0, 0xc1, 0x5b, 0x92, 0x06, 0xde, 0xa6, 0xe4,
- 0xfa, 0xc6, 0xbc, 0xec, 0x6c, 0x78, 0x79, 0xc8, 0x1f, 0x30, 0x07, 0x6c,
- 0x9c, 0xf7, 0x14, 0x07, 0x0e, 0x1d, 0x91, 0xd8, 0x49, 0xe2, 0x47, 0x50,
- 0x36, 0x0b, 0xef, 0x68, 0x1c, 0xda, 0x2c, 0xb0, 0x1c, 0x10, 0x9d, 0x4f,
- 0xb6, 0xb0, 0x27, 0x65, 0xe7, 0x97, 0xa8, 0x3f, 0xa6, 0x7d, 0x40, 0x9e,
- 0x4f, 0x9e, 0x78, 0xf9, 0x67, 0xff, 0xee, 0x95, 0xce, 0xb3, 0x5b, 0x32,
- 0xbb, 0xd0, 0xae, 0x81, 0x5d, 0xc3, 0x5e, 0xcc, 0x5b, 0xfd, 0x05, 0x6d,
- 0x30, 0x47, 0xb1, 0x4b, 0xb6, 0x21, 0x43, 0xea, 0xf1, 0x2e, 0xad, 0xfb,
- 0xd5, 0xe3, 0x43, 0x3a, 0x17, 0x97, 0xe3, 0xe4, 0x0a, 0xb6, 0xac, 0x14,
- 0xac, 0x68, 0x16, 0xf4, 0xb7, 0x0b, 0x5b, 0xed, 0x3a, 0xee, 0x60, 0x07,
- 0x67, 0x70, 0xa3, 0x46, 0x39, 0x7f, 0x57, 0x63, 0xef, 0x66, 0xed, 0x4f,
- 0x18, 0xc7, 0x3a, 0x93, 0x94, 0x3f, 0xf6, 0x13, 0x03, 0xe9, 0x8f, 0x9a,
- 0xd1, 0xfd, 0xbd, 0x7e, 0xd7, 0xd1, 0x76, 0xa7, 0x46, 0x3c, 0x16, 0xb9,
- 0x94, 0xb7, 0x21, 0x4b, 0x5e, 0x8f, 0x50, 0x07, 0x28, 0xa9, 0x46, 0x3f,
- 0xd7, 0x5f, 0xb3, 0xeb, 0x1e, 0xb5, 0xb9, 0xae, 0xb8, 0x8f, 0xdb, 0x94,
- 0xfd, 0x7b, 0x5a, 0xee, 0xe7, 0x8b, 0x67, 0xe5, 0x2d, 0xdc, 0xb7, 0xa7,
- 0xe3, 0x64, 0xe4, 0x4d, 0xe8, 0x78, 0xb5, 0x62, 0x23, 0x6f, 0x7b, 0x1a,
- 0xe7, 0x64, 0xa9, 0x95, 0x2b, 0x2f, 0xcb, 0xe5, 0xab, 0xfb, 0xea, 0xa5,
- 0xab, 0x31, 0xf5, 0xf2, 0x95, 0x61, 0x95, 0xbb, 0xe2, 0xba, 0xff, 0x74,
- 0x96, 0xe4, 0xdd, 0x0d, 0x57, 0x4e, 0x3b, 0xc6, 0x40, 0x40, 0x1a, 0xb9,
- 0x75, 0xae, 0x1b, 0x04, 0x36, 0xdf, 0xe8, 0x75, 0xdd, 0x47, 0xc7, 0xc7,
- 0x25, 0xde, 0x4b, 0x1d, 0xe5, 0xf3, 0x11, 0xe6, 0xbb, 0x12, 0x73, 0x52,
- 0xb6, 0x7d, 0xbe, 0xac, 0x14, 0xf0, 0xad, 0xcb, 0xd3, 0x5f, 0x1e, 0x3b,
- 0xe6, 0xc7, 0x4a, 0x7e, 0xf4, 0x22, 0x7d, 0xc9, 0x91, 0xff, 0xf2, 0x25,
- 0x9b, 0x72, 0xae, 0xf0, 0x19, 0xf4, 0x0f, 0xcb, 0xb7, 0x0a, 0xa1, 0x43,
- 0x65, 0x13, 0xcf, 0x31, 0x95, 0x2b, 0xdc, 0x73, 0x87, 0x75, 0xcc, 0x00,
- 0x3a, 0x89, 0xe9, 0xba, 0xcb, 0x0e, 0xe7, 0xeb, 0xc2, 0x7c, 0x7b, 0xe6,
- 0x31, 0xc8, 0xff, 0xd3, 0x5a, 0x3e, 0x9f, 0x53, 0xb0, 0x7d, 0xc1, 0xdf,
- 0x61, 0x99, 0x2d, 0x40, 0xc6, 0x2b, 0xe6, 0x9c, 0x52, 0x57, 0xb0, 0x22,
- 0xcb, 0xc0, 0x8e, 0x25, 0xe0, 0xcd, 0x93, 0x3a, 0xb6, 0xda, 0xa3, 0xb1,
- 0x67, 0x85, 0xe5, 0x8c, 0x24, 0xcb, 0x4e, 0xb7, 0x3e, 0xbf, 0xfd, 0xdd,
- 0x57, 0x23, 0xde, 0x9d, 0x83, 0x8f, 0x33, 0x4a, 0xda, 0x60, 0x03, 0xcd,
- 0x6c, 0x2d, 0x80, 0x27, 0x22, 0x38, 0xdb, 0x56, 0xcd, 0x0f, 0x75, 0xc8,
- 0xef, 0xba, 0xf6, 0x23, 0x7a, 0xf1, 0x8a, 0xba, 0xc9, 0x76, 0xcf, 0xa0,
- 0x5f, 0xbb, 0xa4, 0xae, 0xb4, 0x69, 0x5c, 0x7d, 0xb8, 0x2e, 0x09, 0x3d,
- 0xe4, 0x69, 0x94, 0x03, 0xa8, 0x8b, 0xfa, 0x65, 0x03, 0xe5, 0x45, 0x94,
- 0x5b, 0xf0, 0x64, 0x9b, 0x11, 0xe8, 0x15, 0x78, 0xbe, 0x81, 0xf1, 0xc6,
- 0xb1, 0xe6, 0x8c, 0x29, 0x1f, 0x9d, 0xa2, 0x2c, 0x19, 0x53, 0xcc, 0x4b,
- 0x5e, 0xb6, 0xf1, 0xac, 0x0e, 0xab, 0x99, 0x35, 0x96, 0xf1, 0x2c, 0x79,
- 0xdf, 0x1f, 0xc2, 0x24, 0xf4, 0x49, 0x5d, 0xf5, 0x30, 0xe9, 0xa3, 0x26,
- 0x26, 0xb1, 0xae, 0x5d, 0x66, 0xaf, 0x90, 0xd7, 0x4d, 0xd0, 0x5b, 0x87,
- 0xcc, 0x5c, 0x0d, 0x6b, 0x7d, 0xb4, 0x0c, 0x5a, 0xdc, 0x06, 0x5d, 0x6d,
- 0x82, 0xa6, 0x52, 0x05, 0x6b, 0x6a, 0x51, 0x45, 0xb5, 0x2f, 0xe0, 0x09,
- 0xd0, 0x6b, 0xf0, 0x15, 0xea, 0xa2, 0xe4, 0xe5, 0x38, 0x68, 0x4f, 0xdc,
- 0xa0, 0x6d, 0xa7, 0xe3, 0xca, 0x06, 0x0d, 0x82, 0x2e, 0x0b, 0x1e, 0x4f,
- 0xbf, 0xa7, 0x34, 0xae, 0x4e, 0xdd, 0x96, 0x44, 0xf2, 0xb6, 0x58, 0xc0,
- 0x02, 0xcb, 0xf9, 0x50, 0x1c, 0x8c, 0x39, 0x29, 0xd7, 0x30, 0x8f, 0x01,
- 0xfe, 0x1e, 0x3d, 0xa1, 0xf9, 0x7b, 0x4a, 0x02, 0x87, 0x79, 0x1c, 0xf4,
- 0x06, 0x0c, 0xf2, 0x78, 0x3a, 0xe9, 0xd3, 0xe8, 0xd7, 0xc1, 0xbf, 0x16,
- 0x2c, 0xb1, 0xb0, 0xac, 0x82, 0xff, 0xb7, 0xf1, 0xfd, 0x66, 0x6d, 0x44,
- 0xad, 0xac, 0x29, 0x3f, 0x97, 0xe4, 0x19, 0xe8, 0xc9, 0xb7, 0x70, 0x76,
- 0x9d, 0x5a, 0x77, 0x8f, 0x8d, 0x33, 0x7e, 0x96, 0x56, 0x97, 0xed, 0x93,
- 0xb2, 0x3f, 0x36, 0x89, 0xf2, 0x31, 0x3c, 0x0d, 0x9c, 0x43, 0x48, 0xc7,
- 0xbf, 0x37, 0xf3, 0x8e, 0xf2, 0xfe, 0x67, 0x61, 0x42, 0xe7, 0xe7, 0x1b,
- 0x76, 0x2f, 0xbe, 0xd3, 0x17, 0xc3, 0xbd, 0x41, 0x67, 0x52, 0x11, 0x9d,
- 0x6f, 0x5a, 0x86, 0x2e, 0xb1, 0x85, 0xf1, 0xde, 0xa7, 0x2f, 0xaf, 0x0a,
- 0x1e, 0x1e, 0xfb, 0x97, 0x9b, 0x0c, 0x33, 0x47, 0xfd, 0x6e, 0xc4, 0x93,
- 0x7f, 0x9f, 0xb8, 0xfb, 0xf6, 0xca, 0x94, 0x81, 0x97, 0x5b, 0x66, 0x18,
- 0x6d, 0x21, 0xcb, 0x20, 0x8b, 0x4a, 0x9a, 0x7e, 0xd9, 0xce, 0xeb, 0x9b,
- 0xab, 0x26, 0xcc, 0x0f, 0xc4, 0xeb, 0xbb, 0x6a, 0x53, 0xee, 0xb4, 0x03,
- 0x5f, 0xa2, 0x5a, 0xaf, 0x7c, 0xdf, 0xce, 0x02, 0x15, 0xac, 0x68, 0x1a,
- 0x34, 0xda, 0x26, 0x56, 0x7c, 0x4e, 0x1e, 0xcc, 0xbb, 0xac, 0xfb, 0xb2,
- 0x6d, 0xa3, 0x6f, 0x63, 0x5e, 0xae, 0x9f, 0x7b, 0xe1, 0x1e, 0xe8, 0x9b,
- 0x36, 0x35, 0x8d, 0xd6, 0xab, 0xdd, 0x03, 0x1e, 0x8d, 0x36, 0xf6, 0x11,
- 0xfe, 0x3f, 0xfb, 0x20, 0x9d, 0x38, 0xca, 0xcb, 0xbb, 0xc0, 0xb3, 0xca,
- 0xf3, 0x1c, 0x01, 0x6d, 0x1c, 0xa4, 0x9f, 0x86, 0x6f, 0xd1, 0xa3, 0x9f,
- 0x47, 0x9b, 0xf4, 0x43, 0xba, 0xe9, 0x90, 0xd9, 0xab, 0xb6, 0xcc, 0x17,
- 0xf4, 0x7d, 0x43, 0xd7, 0xa4, 0xcf, 0x68, 0x12, 0x74, 0x43, 0x5a, 0x27,
- 0x6f, 0x99, 0x52, 0x02, 0x1d, 0x95, 0x80, 0x4f, 0x25, 0xd0, 0x54, 0x19,
- 0xf8, 0x56, 0x02, 0xbe, 0x95, 0x6a, 0x56, 0xbc, 0x82, 0x3d, 0x53, 0x66,
- 0x6f, 0x81, 0x8e, 0xb6, 0x6b, 0xbc, 0x7f, 0xbd, 0x66, 0x93, 0x72, 0xf0,
- 0x66, 0xf3, 0xee, 0xff, 0x81, 0xbb, 0x1f, 0x92, 0x5d, 0xd8, 0x2d, 0x6f,
- 0x15, 0xc7, 0x80, 0x49, 0x02, 0x8c, 0x72, 0x40, 0x1b, 0x53, 0x72, 0xbd,
- 0x38, 0x2d, 0x3b, 0x90, 0x4f, 0x37, 0x36, 0x62, 0xd0, 0xa7, 0x23, 0xb2,
- 0xf2, 0xda, 0xa8, 0xbc, 0xb9, 0xa1, 0x64, 0x09, 0xf4, 0x9b, 0xdb, 0xa4,
- 0xdf, 0x1d, 0xf4, 0x5c, 0xea, 0xd0, 0x71, 0xfa, 0xd9, 0x8a, 0xe7, 0x7f,
- 0x9f, 0xab, 0x74, 0xca, 0x7c, 0xc5, 0x94, 0xc7, 0x2b, 0xdd, 0xf2, 0xe5,
- 0x4a, 0x58, 0x4e, 0xc3, 0x0e, 0xfc, 0x4a, 0x65, 0x50, 0x9e, 0xac, 0x0c,
- 0xc9, 0x57, 0xab, 0x51, 0xf9, 0x5a, 0xd5, 0x96, 0x4c, 0x35, 0x2e, 0xe9,
- 0xea, 0x98, 0x3c, 0x51, 0xa5, 0x5f, 0x1d, 0xf3, 0xe1, 0x37, 0xd3, 0xf4,
- 0x57, 0x70, 0x5d, 0x41, 0xac, 0x2b, 0xae, 0xe6, 0x74, 0x9c, 0x52, 0x32,
- 0x9e, 0xcf, 0x43, 0xe4, 0x39, 0x8c, 0x75, 0xf1, 0x35, 0x25, 0x65, 0x3d,
- 0x7f, 0xe3, 0xff, 0x46, 0x42, 0xda, 0x36, 0x7a, 0xae, 0x34, 0x88, 0x36,
- 0x90, 0x7b, 0xf9, 0x86, 0xef, 0xa3, 0xe1, 0xf3, 0x6f, 0xd8, 0x5e, 0x86,
- 0xf6, 0x5b, 0xdf, 0xa4, 0xed, 0xa5, 0xcf, 0x9e, 0xf8, 0x41, 0x3b, 0xe7,
- 0x9a, 0xf6, 0x9b, 0x3c, 0x88, 0x6d, 0x34, 0xe6, 0xbd, 0x98, 0x79, 0xf8,
- 0xff, 0x53, 0xbc, 0x18, 0xd5, 0xb9, 0xea, 0x20, 0xff, 0x4f, 0x05, 0x6b,
- 0xf9, 0xf4, 0xdc, 0xf1, 0xf9, 0xe2, 0xac, 0x7a, 0xbc, 0x48, 0x8d, 0xc6,
- 0x95, 0x8b, 0xcd, 0x9c, 0xb8, 0x2f, 0xc9, 0xa6, 0x13, 0xd2, 0x6b, 0xf0,
- 0xf3, 0x1f, 0x75, 0x7e, 0xdc, 0xec, 0x09, 0xd2, 0x1f, 0x63, 0x6f, 0x9d,
- 0x7e, 0x3c, 0x01, 0xba, 0xad, 0x63, 0xca, 0xa5, 0x8a, 0xe7, 0xb3, 0x5a,
- 0xd1, 0xf4, 0xf2, 0x2b, 0xd0, 0x1c, 0x63, 0x0e, 0xde, 0x33, 0x5b, 0xf2,
- 0xfa, 0xce, 0xe0, 0xde, 0x60, 0x8f, 0x63, 0xbf, 0x46, 0x37, 0xe7, 0xe2,
- 0xff, 0xe9, 0xa0, 0xec, 0xaf, 0x97, 0xb9, 0xc6, 0xb6, 0xa6, 0x45, 0x2f,
- 0xae, 0x1b, 0x97, 0x17, 0x70, 0x7e, 0x65, 0x93, 0xeb, 0x0f, 0x4a, 0x39,
- 0x4e, 0xdb, 0x96, 0xf8, 0x7d, 0x42, 0x4a, 0x98, 0xa7, 0x1c, 0x6f, 0xf8,
- 0xc3, 0x3c, 0x9c, 0x2d, 0x9b, 0x0f, 0xe6, 0x5d, 0x2c, 0x1d, 0xc7, 0x3b,
- 0xea, 0xe2, 0xd0, 0x99, 0x16, 0xf8, 0x7e, 0x11, 0x65, 0xfa, 0x46, 0x56,
- 0xf0, 0x8c, 0xf8, 0x75, 0xd5, 0x01, 0xad, 0xab, 0x4f, 0x3f, 0xe8, 0xb7,
- 0x54, 0xb2, 0xb2, 0xa9, 0x40, 0x42, 0x19, 0xaf, 0xfe, 0x7c, 0x80, 0x98,
- 0x7b, 0xdc, 0xe6, 0x2f, 0x24, 0x7f, 0x35, 0xb5, 0x4f, 0xc1, 0xff, 0x76,
- 0x44, 0x9e, 0x32, 0x99, 0xc7, 0x9e, 0x54, 0xb3, 0xc5, 0x9c, 0x9f, 0xe3,
- 0x9b, 0x50, 0xc7, 0xcb, 0x37, 0x07, 0xbc, 0x9c, 0x77, 0x8e, 0x7d, 0x30,
- 0xcf, 0xfd, 0x20, 0x9d, 0x30, 0xdf, 0xbd, 0xbd, 0xf9, 0x3f, 0x52, 0xe5,
- 0x3c, 0xf0, 0xce, 0x6e, 0xd1, 0xfc, 0x98, 0xab, 0xfe, 0xdb, 0xdd, 0xd3,
- 0xfc, 0xdc, 0xf0, 0x31, 0xfc, 0x6e, 0x80, 0xb6, 0x2d, 0x71, 0xe3, 0x92,
- 0x97, 0x3b, 0xaa, 0x6d, 0x68, 0x60, 0x05, 0xea, 0xc8, 0xab, 0xe0, 0x93,
- 0x66, 0x5b, 0xfe, 0xfd, 0x07, 0x69, 0x3f, 0x51, 0x42, 0x6c, 0x67, 0x00,
- 0x00, 0x00 };
+ 0xec, 0x5c, 0x7d, 0x6c, 0x1c, 0xc7, 0x75, 0x7f, 0x3b, 0xbb, 0xa4, 0x8e,
+ 0xd4, 0x91, 0x5c, 0x1e, 0x4f, 0xcc, 0x51, 0xa6, 0xed, 0x5b, 0x71, 0x25,
+ 0x9e, 0x4d, 0xc6, 0x59, 0xd1, 0x07, 0x9b, 0x28, 0x0e, 0xc9, 0x66, 0xef,
+ 0x24, 0xb1, 0x86, 0x5b, 0x53, 0x35, 0x1d, 0x1b, 0x6d, 0xea, 0xb2, 0x47,
+ 0xb5, 0x29, 0x8c, 0x06, 0x90, 0xbf, 0x00, 0x17, 0xa8, 0xe4, 0xcb, 0x91,
+ 0x8a, 0x55, 0xf7, 0xc0, 0xbd, 0xc8, 0x8c, 0x18, 0x20, 0x6e, 0x7d, 0x25,
+ 0x29, 0x4a, 0x08, 0x0e, 0x3a, 0xa6, 0x71, 0x1a, 0xfd, 0x61, 0xd7, 0x04,
+ 0x2b, 0x1b, 0x6e, 0x91, 0xd6, 0x72, 0xe3, 0xb6, 0x46, 0x50, 0x04, 0x84,
+ 0xec, 0x34, 0x6e, 0xd0, 0x0f, 0xa1, 0x2e, 0x6c, 0x03, 0x96, 0xbd, 0xfd,
+ 0xbd, 0xd9, 0x5d, 0xf2, 0x48, 0x5b, 0x76, 0xd0, 0x3f, 0xfa, 0x4f, 0x77,
+ 0x80, 0xc3, 0xce, 0xcc, 0xbe, 0xf7, 0xe6, 0xcd, 0x9b, 0xf7, 0x39, 0x4b,
+ 0xe9, 0xb7, 0xe3, 0xd4, 0x4e, 0x41, 0xeb, 0xc0, 0x2f, 0x7d, 0xf4, 0xb1,
+ 0x87, 0x6e, 0xb9, 0xfd, 0x96, 0x5b, 0xd1, 0xdd, 0xaf, 0x2a, 0x3b, 0xd4,
+ 0x70, 0x3e, 0x6a, 0x51, 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45,
+ 0x2d, 0x6a, 0x51, 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0x2d,
+ 0x6a, 0x51, 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0x2d, 0x6a,
+ 0x51, 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0x2d, 0x6a, 0x51,
+ 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0x2d, 0x6a, 0x51, 0x8b,
+ 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0xed, 0xff, 0x7b, 0x53, 0x89,
+ 0x74, 0x7e, 0x76, 0x04, 0x3f, 0x8a, 0x89, 0x5c, 0xfa, 0x01, 0xc7, 0xa4,
+ 0x98, 0x9a, 0xeb, 0x3f, 0x3e, 0x65, 0x12, 0xd9, 0xf5, 0xa1, 0x74, 0x9e,
+ 0x3e, 0xf0, 0x4a, 0x49, 0x8d, 0x78, 0xfe, 0xfa, 0xdc, 0xd5, 0x67, 0x9e,
+ 0xbf, 0xdd, 0xb8, 0x52, 0x53, 0x29, 0xa6, 0xe7, 0x66, 0xf6, 0xeb, 0xfb,
+ 0x28, 0xd6, 0x0f, 0x9c, 0xa7, 0x07, 0xff, 0xb1, 0x93, 0x3a, 0x43, 0x5a,
+ 0x44, 0x0b, 0x15, 0xc3, 0x3a, 0x88, 0xe7, 0x72, 0x7d, 0xc8, 0x5a, 0x23,
+ 0x8d, 0x56, 0x75, 0x7f, 0xc5, 0x72, 0x45, 0x61, 0x3a, 0x54, 0xae, 0xc7,
+ 0x68, 0x5d, 0xfe, 0x3b, 0x0f, 0xac, 0x69, 0x72, 0xff, 0x82, 0xe2, 0x34,
+ 0x3c, 0xef, 0x8c, 0xe5, 0x79, 0x2f, 0xe1, 0xf7, 0x33, 0x0b, 0x63, 0xf7,
+ 0x43, 0xcf, 0xd6, 0x54, 0x12, 0xe6, 0x1f, 0x2b, 0xce, 0x62, 0x2b, 0x95,
+ 0xe7, 0x89, 0xa6, 0xdd, 0x18, 0x9d, 0x74, 0x4b, 0x4a, 0xa1, 0x51, 0x51,
+ 0x0e, 0x9c, 0x9d, 0x55, 0x0e, 0x9e, 0x3d, 0xa9, 0x1c, 0x3a, 0x5b, 0x55,
+ 0x9c, 0xb3, 0x54, 0x12, 0xfb, 0xe3, 0x64, 0xeb, 0xe7, 0x94, 0x7c, 0xa3,
+ 0x57, 0x71, 0xe6, 0xaf, 0x7a, 0x8e, 0x65, 0xe8, 0xbf, 0x4e, 0x9a, 0xcd,
+ 0xeb, 0x39, 0x15, 0x0f, 0x63, 0x8d, 0xec, 0xa4, 0xe7, 0x89, 0x9c, 0xf7,
+ 0xb8, 0x93, 0x35, 0x75, 0xa1, 0xc4, 0xa8, 0xdc, 0x68, 0x07, 0x5d, 0x4d,
+ 0xc9, 0xbb, 0xde, 0x0b, 0x8e, 0xb5, 0x0c, 0x3a, 0x75, 0xe0, 0x93, 0x2e,
+ 0x72, 0xcc, 0x4f, 0xc8, 0x63, 0x49, 0xc9, 0x0f, 0x86, 0xfc, 0x50, 0x9a,
+ 0xf9, 0x2d, 0x2e, 0x09, 0xf0, 0xb5, 0x93, 0x8a, 0x35, 0x9d, 0x26, 0x97,
+ 0xb6, 0xc3, 0xaf, 0x7b, 0xcf, 0x0f, 0xea, 0xb4, 0xd2, 0x30, 0x4a, 0x25,
+ 0xec, 0x7d, 0xc6, 0x4d, 0x93, 0xc8, 0x91, 0xed, 0x64, 0xfb, 0xe9, 0x85,
+ 0x46, 0x8a, 0xfe, 0xbc, 0x61, 0xa6, 0xca, 0xb4, 0x83, 0x8a, 0xc9, 0x24,
+ 0x7d, 0x17, 0x38, 0xd3, 0x58, 0x5b, 0x98, 0xa6, 0x5e, 0x06, 0x6c, 0xb9,
+ 0xf1, 0x23, 0xfe, 0xb7, 0x31, 0xfa, 0x54, 0x56, 0xe2, 0x94, 0xc0, 0x67,
+ 0x00, 0xcb, 0x7c, 0x4b, 0x58, 0xc9, 0xbb, 0x0f, 0x4b, 0xa5, 0xa9, 0x2c,
+ 0xe6, 0x1a, 0x4e, 0x20, 0xfb, 0x56, 0xec, 0x8f, 0x9f, 0x37, 0x28, 0xf9,
+ 0xf9, 0x1b, 0x20, 0x03, 0x4a, 0x0a, 0xda, 0x9b, 0x2a, 0x62, 0x66, 0xba,
+ 0x11, 0xc7, 0x98, 0x79, 0xf1, 0xbc, 0x43, 0x16, 0xe9, 0x65, 0xab, 0x0b,
+ 0xb2, 0x4a, 0x53, 0xd9, 0xea, 0x04, 0x4e, 0x0b, 0x75, 0x9b, 0xbc, 0x07,
+ 0xa6, 0xdb, 0x86, 0x79, 0xaf, 0x43, 0xcd, 0x79, 0xde, 0x54, 0x96, 0x3a,
+ 0xfd, 0xb9, 0x21, 0xd0, 0xd0, 0x68, 0x72, 0x5c, 0x01, 0xdc, 0xdb, 0xcc,
+ 0x5f, 0x2c, 0x91, 0xe3, 0x3e, 0x3f, 0xb3, 0xe4, 0xcc, 0xa6, 0x83, 0x75,
+ 0xe3, 0x54, 0x76, 0xaf, 0x0f, 0xfa, 0x90, 0xad, 0x8b, 0x3d, 0x5b, 0x7d,
+ 0x18, 0x2b, 0x37, 0x82, 0x8e, 0x55, 0x26, 0x5e, 0x63, 0x17, 0xad, 0x25,
+ 0x49, 0x5c, 0xb6, 0x7a, 0x02, 0xb8, 0x4e, 0xf0, 0x1a, 0x9e, 0x71, 0x3b,
+ 0xcd, 0xcc, 0xb7, 0xd2, 0x89, 0x79, 0x96, 0x6d, 0x05, 0x67, 0x21, 0x68,
+ 0xcf, 0x6d, 0x25, 0xc5, 0x6e, 0x9c, 0x44, 0x5f, 0xa3, 0x29, 0xd3, 0x7b,
+ 0x61, 0xc6, 0x9a, 0x55, 0xf2, 0x67, 0x97, 0x95, 0x02, 0xce, 0xfc, 0xc0,
+ 0xd9, 0x0b, 0xca, 0xc1, 0xc6, 0xcb, 0x1d, 0xd4, 0x6e, 0x40, 0xbb, 0x34,
+ 0x3a, 0xe1, 0x2a, 0xc4, 0xfc, 0x2e, 0x40, 0x5e, 0xb6, 0x0e, 0xc9, 0x9b,
+ 0x9d, 0xca, 0x41, 0xd0, 0x6a, 0x31, 0xbf, 0x1e, 0xa7, 0x4e, 0x95, 0x76,
+ 0x98, 0x21, 0x6c, 0x8c, 0xbe, 0x0e, 0xde, 0xd6, 0xac, 0x24, 0xe0, 0xa8,
+ 0xcb, 0xc7, 0xe9, 0x0e, 0xf8, 0x61, 0xdd, 0x61, 0xbd, 0x11, 0x76, 0x61,
+ 0xee, 0x8f, 0x7a, 0xca, 0xc3, 0x3b, 0x19, 0x06, 0xf6, 0x60, 0x3f, 0x30,
+ 0x65, 0x3a, 0xdd, 0x1a, 0x95, 0x74, 0x41, 0x86, 0x9e, 0xa7, 0x1b, 0x69,
+ 0xc6, 0x22, 0xca, 0x43, 0x9f, 0x85, 0xa9, 0x41, 0x46, 0x26, 0x64, 0xb4,
+ 0xb7, 0xa4, 0x8a, 0x7b, 0x41, 0xa2, 0xa4, 0x68, 0x81, 0x3c, 0x17, 0xe8,
+ 0x0e, 0x89, 0x2f, 0x72, 0x16, 0x74, 0xb0, 0x9d, 0xfb, 0x58, 0x37, 0x26,
+ 0xd7, 0x55, 0x73, 0x66, 0x6a, 0x91, 0x48, 0x11, 0xb9, 0x21, 0xd0, 0x63,
+ 0xdd, 0x64, 0x38, 0x17, 0x3c, 0x32, 0xef, 0xdc, 0x37, 0x81, 0x13, 0x23,
+ 0xc7, 0xea, 0x68, 0xe2, 0x13, 0xfc, 0x24, 0x59, 0xe6, 0x2c, 0x43, 0xb9,
+ 0x4f, 0x65, 0x73, 0x9f, 0xef, 0x7b, 0x83, 0x23, 0x1a, 0xbd, 0x24, 0xf7,
+ 0xcb, 0x76, 0xc4, 0x70, 0x72, 0x8f, 0xc4, 0xf2, 0x99, 0x76, 0x49, 0x29,
+ 0x5a, 0xfa, 0x06, 0x2d, 0xe8, 0x85, 0x50, 0x73, 0x71, 0xca, 0x4b, 0xfe,
+ 0x46, 0xb1, 0x16, 0xdb, 0x17, 0xec, 0xc4, 0xe4, 0xbd, 0xf0, 0x5c, 0x0e,
+ 0xb6, 0x6a, 0x48, 0xfd, 0x29, 0x56, 0xd9, 0xfe, 0x99, 0xb7, 0x55, 0x43,
+ 0x50, 0x48, 0x4f, 0xf4, 0xaa, 0xd4, 0x45, 0xe3, 0xd6, 0x55, 0x4f, 0xec,
+ 0xc3, 0xfb, 0xe1, 0x14, 0x78, 0x33, 0xd2, 0xb0, 0xb6, 0x84, 0x4a, 0xb0,
+ 0x73, 0x6b, 0x28, 0xa5, 0x93, 0x89, 0xbd, 0x25, 0xc8, 0x1e, 0x5f, 0x85,
+ 0xe0, 0xaf, 0xc5, 0xa7, 0x4f, 0x17, 0x6c, 0xda, 0x0e, 0x78, 0x74, 0xac,
+ 0x5b, 0xa5, 0xcc, 0x74, 0xec, 0x5f, 0x9d, 0x65, 0xf9, 0xb6, 0x43, 0xff,
+ 0x15, 0x2a, 0x5a, 0x4c, 0x3b, 0xa4, 0x21, 0x68, 0xf0, 0xb6, 0x66, 0x1a,
+ 0xe1, 0xd9, 0xb2, 0xfe, 0x6a, 0x34, 0x32, 0xc2, 0xb0, 0x0c, 0xc7, 0xf0,
+ 0xc6, 0x68, 0x5a, 0xbc, 0xef, 0xed, 0xdf, 0xb2, 0xa6, 0x49, 0x62, 0x16,
+ 0x3c, 0xfb, 0x67, 0x01, 0x19, 0x7e, 0x1a, 0x2c, 0x9f, 0xc3, 0x76, 0x79,
+ 0x33, 0x6c, 0x33, 0x1c, 0x74, 0xa8, 0x97, 0x79, 0xa8, 0xc7, 0x7d, 0x7b,
+ 0x0c, 0x79, 0x0a, 0xcf, 0x52, 0x09, 0x68, 0x7c, 0xd2, 0x3e, 0x18, 0x1e,
+ 0x7e, 0xc2, 0x85, 0x9f, 0x70, 0xe1, 0x1f, 0x5c, 0xf8, 0x11, 0x97, 0xfd,
+ 0x4a, 0x9a, 0x9e, 0x1f, 0x84, 0xdf, 0xdb, 0xf4, 0x43, 0x68, 0x63, 0xe8,
+ 0x0b, 0x52, 0xe1, 0x87, 0xa6, 0x6b, 0x02, 0xb6, 0x0e, 0x9b, 0x5b, 0xe2,
+ 0x39, 0x1d, 0xcf, 0x02, 0x9e, 0x26, 0xfc, 0x2c, 0xeb, 0x61, 0xe8, 0x5f,
+ 0xd9, 0x2f, 0xa5, 0xe0, 0x83, 0xd8, 0xef, 0xb0, 0x7f, 0x62, 0x58, 0xcf,
+ 0x2b, 0x58, 0x8c, 0xeb, 0xe1, 0x1c, 0xd9, 0xee, 0xe2, 0x24, 0x12, 0x25,
+ 0xe5, 0xf0, 0x20, 0x6c, 0xf2, 0xe6, 0x16, 0xf0, 0xca, 0xb6, 0x79, 0x1d,
+ 0xbb, 0x16, 0xb4, 0xf7, 0x3b, 0xfc, 0x7f, 0xb7, 0xb7, 0x03, 0x30, 0xd2,
+ 0xc6, 0x3b, 0xfd, 0x71, 0x77, 0xe0, 0x7f, 0xf8, 0xbd, 0x91, 0xb6, 0x69,
+ 0x5f, 0x30, 0xe6, 0xfe, 0x06, 0xbf, 0x96, 0xb8, 0x2d, 0x46, 0x7b, 0x96,
+ 0x7d, 0xbf, 0xb9, 0x67, 0x01, 0x9a, 0xb1, 0xec, 0xf3, 0xb8, 0xe7, 0x7c,
+ 0xe8, 0x3f, 0x3b, 0x40, 0x0f, 0xfc, 0xb9, 0x9b, 0x71, 0x84, 0xe8, 0xbf,
+ 0x14, 0x98, 0x16, 0xe6, 0xb6, 0xcb, 0xc2, 0xf3, 0x66, 0x2c, 0xb6, 0x4f,
+ 0xbd, 0xd9, 0x3e, 0xf7, 0xc3, 0x3e, 0xad, 0x56, 0x32, 0xac, 0xbf, 0x82,
+ 0x7d, 0x3e, 0x61, 0x29, 0x90, 0x0d, 0xd1, 0xc5, 0x4a, 0x1c, 0xbe, 0x41,
+ 0x4b, 0xbd, 0x41, 0x7b, 0xd3, 0xd3, 0xd0, 0xcb, 0x33, 0x3c, 0x87, 0x23,
+ 0x3a, 0x21, 0xfd, 0xb5, 0xef, 0x0f, 0xd6, 0xd5, 0x6f, 0x80, 0x2f, 0xcf,
+ 0x9b, 0x06, 0xcd, 0xe2, 0xb0, 0x1a, 0xd8, 0x62, 0x38, 0x6f, 0x23, 0x26,
+ 0x3a, 0x37, 0xa9, 0x54, 0xca, 0xb4, 0x90, 0x91, 0x59, 0x00, 0xed, 0x29,
+ 0xcb, 0xb7, 0x7b, 0xb6, 0x8d, 0x45, 0xd0, 0x9f, 0x71, 0x07, 0xe1, 0x17,
+ 0xd8, 0x6e, 0xc0, 0x17, 0xe8, 0x2f, 0x82, 0xfe, 0x4c, 0xa3, 0x85, 0xbe,
+ 0xa6, 0x85, 0xb1, 0x36, 0xdc, 0x0f, 0x44, 0x6d, 0x86, 0xeb, 0x1e, 0xa5,
+ 0x3b, 0xdc, 0x84, 0xe2, 0x3c, 0xc5, 0x7e, 0xb9, 0x9c, 0x81, 0x5d, 0x29,
+ 0x65, 0x8b, 0xd7, 0x56, 0x69, 0x71, 0x03, 0x86, 0xec, 0xb2, 0x6f, 0xb3,
+ 0xb6, 0x33, 0x58, 0x4a, 0xa9, 0xd2, 0xf7, 0x10, 0x1d, 0xac, 0x68, 0x80,
+ 0xe1, 0x31, 0xcf, 0xfb, 0x73, 0x63, 0x95, 0x5e, 0xf8, 0x52, 0x1e, 0x5f,
+ 0xf5, 0xa6, 0x2c, 0x7f, 0xee, 0x97, 0x2b, 0x0f, 0xf0, 0x19, 0x61, 0x2f,
+ 0x94, 0x2e, 0x5b, 0x3f, 0xf7, 0xa0, 0xbf, 0x5b, 0x70, 0x3e, 0x9e, 0x8e,
+ 0x31, 0xe6, 0xeb, 0x2c, 0x29, 0x87, 0x4c, 0xd1, 0xdb, 0x1a, 0xf8, 0xbc,
+ 0x43, 0x98, 0x3c, 0x50, 0x29, 0xf7, 0xb4, 0xd2, 0x55, 0x95, 0x63, 0xeb,
+ 0x65, 0x38, 0x01, 0xa7, 0xb2, 0x0f, 0xf2, 0x28, 0x77, 0x37, 0xcd, 0xc5,
+ 0x0a, 0x15, 0x8f, 0xd6, 0x2c, 0x1f, 0x07, 0xe3, 0x78, 0xbe, 0x22, 0x7a,
+ 0x63, 0xb4, 0x31, 0xd6, 0x19, 0x67, 0x89, 0xf6, 0x65, 0x16, 0x49, 0xe2,
+ 0xf6, 0xc4, 0x36, 0x71, 0x93, 0x85, 0x4a, 0xb9, 0xbb, 0x69, 0x9c, 0xca,
+ 0x83, 0x96, 0xd8, 0xbf, 0x81, 0xdb, 0xbf, 0x89, 0xbb, 0x8b, 0xd2, 0xdd,
+ 0x8c, 0x2f, 0x7a, 0xdb, 0x36, 0x69, 0xa7, 0x03, 0x7e, 0x7a, 0xda, 0x36,
+ 0x69, 0x98, 0x4c, 0xb3, 0x69, 0x9c, 0x61, 0x9a, 0x7b, 0x36, 0x69, 0x0e,
+ 0x6f, 0xe5, 0xe7, 0x28, 0xc1, 0x07, 0xc5, 0x5a, 0x73, 0xb4, 0xff, 0x62,
+ 0x65, 0x60, 0xfc, 0x0e, 0x42, 0x8c, 0x1c, 0xde, 0x11, 0xf8, 0x70, 0x6d,
+ 0xbf, 0x03, 0x59, 0x69, 0xc4, 0x3e, 0x51, 0xa1, 0x32, 0xce, 0xf9, 0x81,
+ 0x3a, 0xed, 0x5f, 0xab, 0x53, 0xa0, 0x4b, 0xac, 0x13, 0x6f, 0xc1, 0xc6,
+ 0xa8, 0xb4, 0x3b, 0x17, 0x9f, 0xd4, 0x72, 0x3a, 0x6c, 0x8d, 0xc6, 0xcb,
+ 0xf0, 0xe1, 0x6a, 0x6e, 0xef, 0xeb, 0x79, 0xf5, 0x71, 0x4f, 0x35, 0xd9,
+ 0x1f, 0xc6, 0x47, 0x9d, 0x2c, 0xe6, 0xeb, 0x6c, 0x5b, 0xf0, 0x2b, 0x0d,
+ 0xa6, 0xfd, 0x4c, 0x17, 0x75, 0x22, 0x8e, 0xd6, 0xcf, 0xec, 0xf2, 0x6d,
+ 0x87, 0x34, 0x0d, 0xbe, 0x79, 0x26, 0xcb, 0x71, 0xbf, 0x35, 0x06, 0xf8,
+ 0x49, 0x35, 0x37, 0xd6, 0x77, 0xa4, 0x7e, 0x67, 0x5f, 0xb1, 0x5e, 0xea,
+ 0x2b, 0x56, 0x74, 0xb6, 0x13, 0xe1, 0x64, 0xd1, 0x97, 0xb9, 0x54, 0x0a,
+ 0x36, 0xc1, 0x6b, 0x27, 0xb1, 0xe6, 0x0f, 0x60, 0x7f, 0x6c, 0xdf, 0x44,
+ 0xe3, 0x2e, 0xd6, 0x18, 0xf9, 0x00, 0xe7, 0x0e, 0xde, 0xe0, 0xd3, 0x6c,
+ 0xec, 0x5a, 0x8c, 0xfc, 0x6b, 0x60, 0x9f, 0xdc, 0x7f, 0xc7, 0xf3, 0xe3,
+ 0xc3, 0xdd, 0x5d, 0xfe, 0xdc, 0x8f, 0x03, 0x9b, 0x0e, 0x69, 0x31, 0x9d,
+ 0x8c, 0x32, 0x8e, 0x1c, 0x66, 0xbc, 0xa1, 0x29, 0xec, 0x9f, 0xf3, 0x2e,
+ 0xe7, 0x1e, 0x9c, 0x77, 0x4c, 0x07, 0x7e, 0x8e, 0x6c, 0xe4, 0x4f, 0x9e,
+ 0x40, 0x2e, 0x52, 0x84, 0xdd, 0x68, 0xb9, 0x2b, 0x34, 0x23, 0x7d, 0x24,
+ 0xc5, 0x5a, 0x72, 0x8f, 0x01, 0xe6, 0xdf, 0x60, 0x73, 0xdd, 0x5d, 0x81,
+ 0x1e, 0x06, 0x3e, 0x5e, 0xfa, 0x5d, 0xc0, 0xbe, 0xb5, 0x0d, 0xf6, 0xcd,
+ 0x66, 0x58, 0xbc, 0x5f, 0xdf, 0xf6, 0xfe, 0x9f, 0xd9, 0x7e, 0xf1, 0x6e,
+ 0x15, 0xfe, 0xb4, 0x35, 0xb0, 0xfd, 0x8b, 0x54, 0x84, 0x6f, 0xd5, 0x4c,
+ 0xce, 0x2d, 0x0f, 0x02, 0x17, 0xe3, 0x3a, 0x78, 0x84, 0xbf, 0x40, 0x8c,
+ 0x85, 0xbc, 0x11, 0x13, 0x92, 0x37, 0x72, 0x3e, 0x05, 0xd8, 0x34, 0x60,
+ 0xd9, 0xff, 0x32, 0xec, 0x85, 0x38, 0xcb, 0xbc, 0x58, 0x67, 0x1c, 0xf6,
+ 0x55, 0xe4, 0x39, 0xd9, 0x36, 0x68, 0x94, 0xf7, 0x82, 0x6a, 0x86, 0xb0,
+ 0x21, 0xdd, 0xed, 0xb0, 0x9c, 0xdf, 0x30, 0xed, 0xae, 0x20, 0x6f, 0x18,
+ 0x23, 0xbb, 0x61, 0xe3, 0x57, 0xa2, 0xa9, 0xa7, 0x90, 0xbb, 0x99, 0x2d,
+ 0x2c, 0x0b, 0x9e, 0xd7, 0x7d, 0x19, 0x85, 0x78, 0xa5, 0x9e, 0xad, 0xe3,
+ 0xdf, 0x4a, 0x6c, 0xfa, 0x4a, 0xb6, 0x34, 0xb2, 0x11, 0x2b, 0x20, 0xe3,
+ 0xf4, 0xa4, 0xc8, 0x25, 0x29, 0x5f, 0xf7, 0xe5, 0x8b, 0xf8, 0x0c, 0xff,
+ 0x28, 0xfd, 0x07, 0xce, 0x3d, 0xf4, 0x83, 0xe1, 0x99, 0xb3, 0x9e, 0xd9,
+ 0x38, 0x9b, 0x34, 0x74, 0x69, 0x0c, 0xb8, 0x74, 0x14, 0x34, 0x38, 0x6e,
+ 0x5b, 0x22, 0x97, 0xa0, 0xa2, 0xce, 0xf9, 0x85, 0xcc, 0x0d, 0x6d, 0xf6,
+ 0x03, 0x22, 0xd7, 0x86, 0x39, 0xee, 0xff, 0x41, 0x97, 0x7f, 0xd6, 0x1d,
+ 0x3c, 0x1e, 0x17, 0xb9, 0xae, 0x6d, 0xf3, 0x7f, 0xd7, 0xe1, 0xf3, 0x26,
+ 0xc7, 0x98, 0xff, 0xc9, 0xb6, 0xf1, 0xa3, 0x89, 0xad, 0xe3, 0xaf, 0xf6,
+ 0x85, 0xfa, 0x20, 0x72, 0x8f, 0x05, 0xfc, 0xb2, 0x9e, 0x6e, 0xe7, 0xf5,
+ 0x17, 0xd1, 0x97, 0x3f, 0x01, 0x4d, 0xa9, 0xe3, 0xbf, 0x80, 0xbe, 0x6c,
+ 0xc0, 0x5e, 0x43, 0x5f, 0x9a, 0x79, 0xd8, 0xa8, 0x3b, 0xaa, 0x02, 0x39,
+ 0xac, 0x93, 0xdd, 0x9b, 0x2e, 0xc3, 0xc6, 0x0b, 0x0d, 0xc8, 0x6e, 0x23,
+ 0xae, 0x6e, 0xc0, 0x94, 0x36, 0x61, 0xfc, 0xb8, 0x53, 0x68, 0x78, 0xc8,
+ 0xfb, 0x9a, 0x63, 0x70, 0x06, 0xfd, 0x12, 0xf6, 0xba, 0x42, 0x53, 0xee,
+ 0x9a, 0x2d, 0xcc, 0x93, 0x32, 0x6f, 0x15, 0xe6, 0x93, 0x4a, 0x61, 0x91,
+ 0x73, 0xda, 0x18, 0xfa, 0xb2, 0x3e, 0x41, 0x8c, 0x3b, 0xa5, 0xd8, 0x67,
+ 0xe7, 0x90, 0xcf, 0x2e, 0xe1, 0x77, 0x0e, 0xbf, 0x3a, 0x7e, 0x61, 0xdd,
+ 0xf0, 0x2d, 0xd4, 0x1d, 0xd2, 0xdf, 0x23, 0x36, 0xf9, 0xeb, 0xff, 0x74,
+ 0x09, 0xf9, 0xf4, 0x5c, 0x92, 0x9e, 0x30, 0x45, 0x8f, 0xf0, 0x7d, 0x9c,
+ 0x8d, 0x5c, 0x5c, 0x7f, 0x8b, 0x7e, 0x25, 0xc8, 0xe9, 0x88, 0xde, 0xa8,
+ 0xe2, 0x2c, 0x87, 0x0f, 0x05, 0xfe, 0xe9, 0xe4, 0x57, 0x1c, 0xe9, 0xcb,
+ 0x83, 0x9c, 0x0d, 0x7e, 0xc7, 0x96, 0x50, 0xaf, 0x40, 0x3e, 0x0a, 0xfd,
+ 0x0c, 0x7a, 0xfc, 0x46, 0xb5, 0x1d, 0xfc, 0x98, 0x54, 0x9c, 0x30, 0x46,
+ 0x49, 0x19, 0xd0, 0x77, 0x28, 0xed, 0xc8, 0xdb, 0xe0, 0x77, 0xe4, 0x98,
+ 0x65, 0x46, 0xc7, 0x17, 0x2a, 0x02, 0xb0, 0x90, 0x79, 0x16, 0x7d, 0xe8,
+ 0xdf, 0xe5, 0x2a, 0xe3, 0x09, 0x7a, 0xb3, 0xaa, 0xd2, 0xbf, 0x20, 0x0f,
+ 0xc4, 0xbb, 0xe3, 0xb0, 0xc1, 0x5e, 0xc4, 0xab, 0x7e, 0x95, 0xf6, 0x72,
+ 0xcc, 0xd8, 0xa3, 0xe1, 0x59, 0xc0, 0xef, 0x20, 0xf2, 0xc2, 0x6b, 0xe0,
+ 0x5c, 0x03, 0x9e, 0x79, 0x8b, 0x01, 0x87, 0xe1, 0x35, 0xf0, 0xd6, 0x09,
+ 0x1d, 0x34, 0xf4, 0x49, 0xfa, 0x8c, 0x2e, 0x73, 0x27, 0x85, 0xe7, 0x7d,
+ 0x3f, 0xf9, 0xd1, 0x79, 0x96, 0xb3, 0x0a, 0x1d, 0xe2, 0x31, 0xbf, 0x63,
+ 0x7f, 0xce, 0xf4, 0x8c, 0x51, 0x1b, 0x9b, 0xb9, 0x5c, 0xf5, 0xfb, 0xe1,
+ 0x1c, 0x29, 0x61, 0x4c, 0x65, 0x3f, 0x5d, 0x80, 0xad, 0xf2, 0x78, 0x9c,
+ 0xe4, 0x19, 0x6c, 0x39, 0x4f, 0xa9, 0x47, 0xc7, 0x66, 0x4c, 0x3e, 0x57,
+ 0x9d, 0xa6, 0x2b, 0xe1, 0xb9, 0xf2, 0x19, 0xa1, 0x0e, 0xad, 0x3e, 0x89,
+ 0x73, 0x15, 0x41, 0xcd, 0x02, 0x3f, 0x30, 0xc7, 0xe7, 0x8b, 0x3a, 0xb2,
+ 0x8a, 0x3c, 0xac, 0x4a, 0x09, 0xbf, 0xe6, 0x3a, 0x85, 0x3a, 0x05, 0xe7,
+ 0x57, 0x99, 0x03, 0x8d, 0x24, 0x9e, 0x4b, 0x78, 0xa6, 0xf0, 0x3c, 0x87,
+ 0x67, 0x3f, 0x9e, 0x75, 0xb6, 0x8f, 0x20, 0xef, 0xf9, 0x08, 0x3f, 0xb0,
+ 0x93, 0x02, 0xdb, 0x34, 0xfd, 0x65, 0x23, 0x47, 0x3f, 0x68, 0x8c, 0xd2,
+ 0x5f, 0x34, 0xb2, 0xf4, 0xfd, 0x86, 0x45, 0xcf, 0x36, 0x86, 0xe9, 0x7b,
+ 0x8d, 0x0c, 0xd7, 0x90, 0xc8, 0xe1, 0xd2, 0xf0, 0xcd, 0x17, 0xe8, 0x2b,
+ 0x6e, 0x03, 0x3e, 0x47, 0xfa, 0xcb, 0xe3, 0x76, 0xfd, 0x3a, 0x2a, 0x3e,
+ 0xa5, 0x23, 0xcf, 0x54, 0xb9, 0x8e, 0xa3, 0x47, 0xad, 0xbb, 0x13, 0x7c,
+ 0xf6, 0xc2, 0xe4, 0xba, 0xe6, 0x04, 0xc3, 0xa1, 0x1e, 0x56, 0x90, 0xbf,
+ 0xb4, 0xd0, 0x64, 0xd2, 0x58, 0x71, 0xd4, 0x74, 0xe0, 0x8f, 0x26, 0x00,
+ 0x87, 0x35, 0xdd, 0x38, 0xad, 0x9d, 0x86, 0x2d, 0x58, 0xa8, 0xa5, 0x93,
+ 0x31, 0xf8, 0x3e, 0x99, 0x9f, 0x48, 0xdf, 0xe2, 0xfb, 0xd2, 0xb0, 0xc6,
+ 0xe4, 0x39, 0x3b, 0x98, 0xe3, 0xf8, 0xa8, 0x03, 0xb6, 0x11, 0xc4, 0x90,
+ 0xed, 0x34, 0xd9, 0x37, 0x4e, 0x04, 0xfe, 0x71, 0x85, 0x1e, 0x76, 0x07,
+ 0xec, 0xb7, 0x11, 0x7b, 0x94, 0x96, 0x30, 0x2f, 0xda, 0x0d, 0xde, 0x3c,
+ 0xef, 0x30, 0xea, 0xf3, 0x74, 0x42, 0xa3, 0xbf, 0x9f, 0x35, 0xf4, 0xc3,
+ 0x02, 0x01, 0xae, 0xdd, 0xf3, 0xc6, 0x4d, 0xa3, 0x64, 0x8b, 0x0e, 0xfa,
+ 0xa7, 0x53, 0x1c, 0x93, 0xd7, 0x8f, 0xbd, 0x08, 0x3d, 0xa8, 0x2d, 0xb5,
+ 0x52, 0xad, 0xa6, 0xd1, 0xe5, 0x91, 0x01, 0xb9, 0x6e, 0xad, 0x9e, 0x40,
+ 0x9e, 0xd7, 0x46, 0x8b, 0xbd, 0x52, 0xd9, 0xe1, 0xb7, 0x33, 0xd2, 0x6f,
+ 0x3b, 0x26, 0x9e, 0xf5, 0xb4, 0xbe, 0x95, 0x97, 0x67, 0xa9, 0xe8, 0x76,
+ 0xa2, 0x42, 0xd9, 0x0d, 0x99, 0x70, 0x7f, 0x40, 0x77, 0x04, 0x62, 0xa0,
+ 0x36, 0xa0, 0x1f, 0x12, 0xff, 0xed, 0x7d, 0x51, 0x63, 0x39, 0xbe, 0x8e,
+ 0xd8, 0xc2, 0xb1, 0x52, 0x91, 0x7a, 0xb7, 0xb0, 0xf4, 0xa6, 0xce, 0xfe,
+ 0xe5, 0x7b, 0xf5, 0xdd, 0xc1, 0x98, 0xfd, 0x3b, 0x8f, 0xdb, 0xe9, 0xfb,
+ 0xb5, 0x9d, 0xb4, 0x58, 0xe3, 0xf7, 0xad, 0xb4, 0x50, 0x1b, 0xb8, 0xf2,
+ 0x90, 0xe8, 0xa5, 0xd5, 0xeb, 0x6e, 0xd6, 0x3f, 0x2f, 0x20, 0x93, 0x89,
+ 0x0f, 0xe9, 0xdd, 0x91, 0x2e, 0x7a, 0xf5, 0x5e, 0xa3, 0x7a, 0xbf, 0x80,
+ 0x3e, 0x8e, 0xc4, 0xd9, 0xce, 0xd0, 0xe7, 0x79, 0xe3, 0x4a, 0x5a, 0xb0,
+ 0x9e, 0xbd, 0x0c, 0xfd, 0x32, 0x4e, 0xfa, 0x3a, 0xc9, 0xb4, 0x99, 0x2e,
+ 0xce, 0xc7, 0x7c, 0x05, 0x34, 0xf1, 0xae, 0x3e, 0x00, 0x5a, 0xaf, 0x48,
+ 0x59, 0x1c, 0xb6, 0x8c, 0x2b, 0x08, 0x51, 0xde, 0x65, 0x73, 0x20, 0x23,
+ 0xc4, 0x6e, 0xaa, 0xa5, 0x6e, 0xd6, 0xbf, 0x8b, 0x78, 0x80, 0x9a, 0xab,
+ 0xb4, 0x4e, 0xeb, 0xc7, 0x2e, 0x9a, 0xac, 0x8b, 0x6c, 0xc3, 0x3f, 0x44,
+ 0x4e, 0xaa, 0xd3, 0x53, 0x75, 0xf6, 0x5d, 0x4c, 0x8b, 0xeb, 0x82, 0x7d,
+ 0xfa, 0xdd, 0xe0, 0xc1, 0x19, 0xc6, 0x3b, 0xcc, 0xab, 0x9f, 0xe5, 0x73,
+ 0x6b, 0x61, 0xdc, 0x4c, 0x9a, 0x37, 0xb3, 0x45, 0x46, 0x03, 0xfa, 0x5e,
+ 0xc1, 0xeb, 0xbd, 0x8b, 0x75, 0xdf, 0x01, 0xaf, 0x03, 0xc0, 0x45, 0x0c,
+ 0x4d, 0x35, 0xaf, 0xf1, 0x9a, 0x5c, 0xe3, 0x54, 0x1d, 0x39, 0xe0, 0xc6,
+ 0x1a, 0x98, 0xab, 0x0b, 0xec, 0xf3, 0x57, 0x65, 0xfe, 0xac, 0x22, 0xff,
+ 0xb9, 0x3c, 0xf2, 0x4c, 0x90, 0x5f, 0x3c, 0x07, 0x59, 0xc7, 0xe8, 0xb5,
+ 0x59, 0xae, 0x2f, 0x0f, 0x51, 0x39, 0xb1, 0x7e, 0x6c, 0xca, 0x44, 0x4d,
+ 0x8f, 0x38, 0x50, 0xde, 0x37, 0xe0, 0xeb, 0x55, 0x3f, 0xe3, 0x3c, 0x27,
+ 0xcf, 0xa4, 0x2c, 0x5a, 0xe9, 0x8b, 0x5a, 0x1a, 0xf8, 0x3c, 0x77, 0x29,
+ 0x38, 0xcf, 0x6f, 0x83, 0x1f, 0xf4, 0xeb, 0x3d, 0x81, 0xff, 0x4b, 0x40,
+ 0x57, 0x87, 0xf4, 0xc3, 0x14, 0x0b, 0xfc, 0x5f, 0x82, 0x5e, 0x3d, 0xad,
+ 0x42, 0x87, 0x58, 0x7f, 0xfa, 0xbb, 0x37, 0xf5, 0x87, 0xdf, 0xad, 0x1f,
+ 0x73, 0xc0, 0x63, 0x7e, 0xae, 0x95, 0x0a, 0xd5, 0x18, 0x4d, 0x65, 0x91,
+ 0x73, 0x23, 0xfe, 0xe4, 0xa1, 0x4b, 0x85, 0x1a, 0xeb, 0x72, 0x29, 0xd0,
+ 0xe5, 0x78, 0x40, 0xfb, 0x6f, 0xa0, 0xcb, 0x46, 0x7a, 0x55, 0x70, 0x7d,
+ 0xd5, 0x27, 0x6b, 0x64, 0x15, 0xf6, 0x55, 0xac, 0x70, 0x2c, 0x62, 0xdb,
+ 0xa2, 0xe3, 0xcc, 0x7f, 0xb1, 0x32, 0x2a, 0x8a, 0x8d, 0xac, 0x28, 0xba,
+ 0xcc, 0xdf, 0x3e, 0xf0, 0xad, 0xc8, 0x3a, 0x78, 0xa1, 0xf1, 0xae, 0xb7,
+ 0xb0, 0x6f, 0x07, 0xfa, 0xd0, 0xfd, 0x71, 0x3e, 0xdf, 0xeb, 0x99, 0xaf,
+ 0xb4, 0x2d, 0x58, 0xde, 0x49, 0x5a, 0x1e, 0x7c, 0xa9, 0x8b, 0x73, 0xb4,
+ 0xb3, 0x83, 0x4c, 0x1f, 0x7c, 0x24, 0x93, 0xb4, 0xe8, 0xf2, 0x1a, 0x2c,
+ 0x17, 0xf8, 0xba, 0x39, 0x9d, 0x1e, 0x96, 0xe7, 0xc7, 0xba, 0xc5, 0xf7,
+ 0x4d, 0x2a, 0xe5, 0x13, 0x03, 0xfa, 0x43, 0x64, 0x5c, 0x59, 0x53, 0x8d,
+ 0xea, 0x24, 0xe2, 0xea, 0xc2, 0xbc, 0x4a, 0x7b, 0x64, 0x1d, 0xc6, 0x67,
+ 0x64, 0x9c, 0x84, 0x35, 0x06, 0x7b, 0xff, 0x8d, 0xa6, 0xbd, 0x77, 0xd2,
+ 0xc5, 0xd3, 0x9f, 0x85, 0xdd, 0xb3, 0x5c, 0xb5, 0xf4, 0x11, 0xe4, 0x19,
+ 0x73, 0x04, 0xf9, 0x22, 0x7f, 0xb6, 0x53, 0xe1, 0xb9, 0xb0, 0xbc, 0x77,
+ 0x49, 0xf9, 0x0b, 0x29, 0xff, 0x1b, 0xa8, 0xdc, 0xeb, 0xdb, 0x38, 0xbf,
+ 0x13, 0xa0, 0xe1, 0xbf, 0xe3, 0xf1, 0x67, 0x90, 0x1f, 0xf1, 0xbb, 0x9a,
+ 0x8f, 0x47, 0x3d, 0x4c, 0x07, 0xef, 0xfe, 0x10, 0x6b, 0xb2, 0x8c, 0xc3,
+ 0xf9, 0x0e, 0xf2, 0x6d, 0x29, 0x94, 0x3b, 0x12, 0x8c, 0x7a, 0x92, 0x7e,
+ 0xad, 0x9e, 0xa2, 0x89, 0x7a, 0x3f, 0x15, 0xea, 0x69, 0x9c, 0xc1, 0x13,
+ 0xdd, 0xbc, 0xb7, 0xfc, 0x12, 0xf6, 0x23, 0x98, 0xd7, 0x1a, 0x1d, 0x71,
+ 0x43, 0x7e, 0xe2, 0x01, 0x7f, 0x5a, 0x30, 0x8e, 0x05, 0x3c, 0x34, 0xd3,
+ 0x8b, 0x83, 0x96, 0x0d, 0x3a, 0x67, 0x02, 0x3a, 0xec, 0x47, 0xc0, 0xeb,
+ 0x44, 0x8a, 0x96, 0x5c, 0xe6, 0x63, 0x27, 0x95, 0x93, 0xdc, 0x7f, 0x0e,
+ 0x7a, 0xc6, 0x74, 0x76, 0x70, 0x7e, 0xb3, 0x45, 0xc6, 0x47, 0xeb, 0x25,
+ 0xc8, 0x98, 0xe5, 0xcb, 0x70, 0x71, 0x5a, 0xf8, 0x25, 0x3e, 0xbf, 0x21,
+ 0xe4, 0xf8, 0xac, 0x0b, 0x3b, 0x03, 0xbd, 0xf2, 0xd7, 0x2c, 0xcc, 0x75,
+ 0xe2, 0xac, 0x78, 0xdd, 0x76, 0xba, 0x07, 0x76, 0x9f, 0xaf, 0xf1, 0xfa,
+ 0x13, 0xd0, 0xa3, 0x1f, 0xcb, 0xf5, 0x0b, 0x4b, 0xbd, 0x01, 0x3e, 0xe3,
+ 0x76, 0x6e, 0xc3, 0x6d, 0xa5, 0x03, 0x55, 0xfd, 0x63, 0xf0, 0x7f, 0x13,
+ 0xf8, 0x82, 0xce, 0x64, 0x19, 0x9f, 0xe9, 0x00, 0xae, 0x96, 0xfc, 0x04,
+ 0x3a, 0x09, 0x59, 0xef, 0xe7, 0x6b, 0xad, 0x94, 0xaf, 0x86, 0xb4, 0x98,
+ 0xce, 0x87, 0xa8, 0x87, 0xbf, 0x2c, 0x69, 0x4d, 0x49, 0x5a, 0x78, 0x5f,
+ 0x63, 0x9f, 0x73, 0x3b, 0xf0, 0xe3, 0xec, 0xff, 0x69, 0x21, 0xd1, 0x41,
+ 0x0b, 0xb2, 0xa6, 0x6f, 0xf7, 0x7d, 0x4d, 0xa2, 0x0d, 0xef, 0x77, 0xc1,
+ 0xe6, 0x87, 0x90, 0x5b, 0x74, 0x62, 0x2e, 0xbd, 0x6d, 0x6e, 0x3b, 0xff,
+ 0xb1, 0x6d, 0xfc, 0xeb, 0x80, 0xeb, 0xc1, 0x9a, 0x3e, 0x5c, 0x01, 0x70,
+ 0xd3, 0x73, 0x90, 0xb3, 0xc5, 0x7e, 0x85, 0xe3, 0xe4, 0x75, 0x92, 0x97,
+ 0xe9, 0x25, 0x05, 0x70, 0xbd, 0xc0, 0x0d, 0xc7, 0xbe, 0x1c, 0xaa, 0xa0,
+ 0xf3, 0xcd, 0x9a, 0xbc, 0xbb, 0xc0, 0x19, 0xf4, 0x24, 0x78, 0xef, 0xe5,
+ 0xda, 0xa7, 0xc9, 0xec, 0xba, 0x26, 0x79, 0xb1, 0xac, 0x98, 0x5f, 0xe6,
+ 0x15, 0x7a, 0x8a, 0x38, 0xe4, 0x58, 0xa8, 0x0b, 0x13, 0x2a, 0x15, 0xb2,
+ 0x3a, 0xf2, 0x73, 0xbe, 0xb7, 0x65, 0xbb, 0xd4, 0xf9, 0xae, 0x34, 0x26,
+ 0x4c, 0x8e, 0xb5, 0x9a, 0xdc, 0xfb, 0x91, 0x25, 0xbe, 0xbb, 0x4d, 0xf3,
+ 0x5d, 0x5f, 0x86, 0xb0, 0xf7, 0x07, 0x97, 0x4c, 0x7a, 0xa4, 0x9e, 0xa1,
+ 0x87, 0xea, 0x86, 0x7e, 0x3f, 0x7c, 0x40, 0x71, 0xe3, 0x4e, 0xf7, 0x73,
+ 0x09, 0xae, 0x45, 0x34, 0xe4, 0x81, 0x2d, 0xa6, 0x9f, 0x17, 0x94, 0xb9,
+ 0x66, 0x9b, 0x33, 0xf8, 0x1e, 0x47, 0xaf, 0xd1, 0xf6, 0xdc, 0xe1, 0xff,
+ 0x32, 0x6f, 0xe0, 0xf5, 0xd9, 0x5f, 0x23, 0x4f, 0x70, 0x91, 0x27, 0xb8,
+ 0xc8, 0x13, 0x5c, 0xe4, 0x09, 0x2e, 0xf2, 0x04, 0x17, 0x79, 0x82, 0x8b,
+ 0x3c, 0xc1, 0x45, 0x9e, 0x80, 0xd8, 0xed, 0xd7, 0x0b, 0x63, 0xc8, 0x7f,
+ 0xe1, 0xbf, 0xdc, 0xcf, 0x43, 0x4e, 0x7c, 0xdf, 0xc9, 0x31, 0x87, 0x63,
+ 0x33, 0xcf, 0xad, 0xee, 0x70, 0xf8, 0xdc, 0xa4, 0xef, 0xbb, 0x13, 0x73,
+ 0xe3, 0x41, 0x3e, 0xc2, 0x30, 0x61, 0xec, 0x66, 0x38, 0x1a, 0x75, 0x2c,
+ 0x05, 0x36, 0xc6, 0xf9, 0x8a, 0x1f, 0xb3, 0xfc, 0x5c, 0xf9, 0x75, 0xe4,
+ 0x2c, 0x69, 0xe4, 0x2c, 0xfd, 0xc8, 0x4f, 0xf8, 0x8e, 0x3b, 0xbc, 0x63,
+ 0xb2, 0x95, 0xc3, 0xee, 0x98, 0x72, 0xb7, 0xcb, 0xb9, 0xb4, 0x99, 0x2e,
+ 0x0a, 0x31, 0xd7, 0x43, 0x1e, 0xe5, 0x47, 0xbe, 0x86, 0xbc, 0xf5, 0x9b,
+ 0xf2, 0x3e, 0x6d, 0x7c, 0x90, 0xcf, 0x7c, 0xe5, 0x1a, 0xb9, 0x6b, 0x28,
+ 0x5f, 0xff, 0x1e, 0x50, 0x2c, 0xb0, 0xfc, 0x88, 0xba, 0xcf, 0x43, 0xe0,
+ 0xe7, 0x63, 0x94, 0x58, 0xde, 0x89, 0x39, 0x9d, 0x7a, 0xe4, 0x5d, 0x12,
+ 0x8e, 0xf2, 0xbc, 0xd6, 0x43, 0xed, 0x26, 0x89, 0xf3, 0x7c, 0xe3, 0xc0,
+ 0x74, 0xd9, 0xbf, 0x5e, 0x3a, 0x96, 0xaf, 0x5d, 0x92, 0x3a, 0x75, 0xb8,
+ 0x5e, 0x40, 0x7d, 0xd4, 0x07, 0x18, 0x0d, 0xb5, 0x55, 0x48, 0x9b, 0x69,
+ 0x5e, 0x4d, 0xc8, 0x9a, 0xe7, 0xfc, 0xc6, 0x79, 0xe2, 0xac, 0x79, 0x9d,
+ 0x4b, 0xc7, 0xca, 0x55, 0x23, 0xc5, 0xb5, 0xb2, 0xad, 0x5f, 0x3a, 0x76,
+ 0x02, 0x34, 0x16, 0x91, 0x1b, 0xa8, 0x72, 0xed, 0x4b, 0xc7, 0xa6, 0xab,
+ 0xfe, 0x7d, 0x96, 0xcf, 0x03, 0xe2, 0x60, 0xb6, 0x9d, 0xd4, 0x05, 0xff,
+ 0x5e, 0x4b, 0x48, 0x5c, 0xc6, 0x63, 0x7c, 0x0d, 0x78, 0x7c, 0x6e, 0x19,
+ 0xe0, 0xf2, 0xd9, 0x31, 0x0f, 0x97, 0x8e, 0x95, 0x6a, 0xcd, 0x3c, 0x30,
+ 0x1d, 0xa6, 0x1b, 0xee, 0x87, 0xf7, 0x92, 0x20, 0xb1, 0xec, 0x79, 0xc5,
+ 0x91, 0xfe, 0x20, 0xef, 0x3a, 0x81, 0xfc, 0x4e, 0x93, 0x7a, 0xee, 0x8f,
+ 0xff, 0x4c, 0xc6, 0xa9, 0xb4, 0xe0, 0x79, 0x7e, 0xe2, 0x5d, 0xf6, 0x3b,
+ 0x98, 0xc3, 0x78, 0x31, 0x84, 0x15, 0x01, 0x6c, 0x47, 0x93, 0x3c, 0x5b,
+ 0x82, 0xf5, 0x98, 0x27, 0xde, 0xe7, 0xcf, 0xb1, 0x7f, 0x79, 0x07, 0xc7,
+ 0xf9, 0x18, 0xd6, 0xc5, 0x59, 0xba, 0xff, 0x5b, 0xd9, 0x37, 0xef, 0x89,
+ 0x65, 0xaa, 0x01, 0x87, 0xe1, 0x99, 0x46, 0x88, 0x83, 0x17, 0xe7, 0x7d,
+ 0x3c, 0xb1, 0x71, 0xff, 0xf7, 0x49, 0xeb, 0x36, 0xf3, 0x1a, 0xae, 0x1f,
+ 0xd2, 0xc9, 0xf8, 0xe7, 0xb6, 0x81, 0x2f, 0xff, 0x4f, 0x31, 0x3c, 0xa1,
+ 0x8b, 0x1f, 0xb9, 0x47, 0xcd, 0x34, 0xd5, 0xa1, 0xe1, 0xfd, 0x05, 0xdf,
+ 0x07, 0x70, 0x7d, 0xcf, 0xdf, 0x1a, 0x9a, 0x6b, 0xc5, 0x67, 0x83, 0x58,
+ 0xd6, 0x47, 0xb6, 0xc6, 0x75, 0xc3, 0x85, 0x60, 0xbc, 0x0b, 0xb1, 0x8d,
+ 0xc7, 0x0d, 0xc8, 0x17, 0xba, 0x6c, 0xb5, 0x07, 0x75, 0x4b, 0xc2, 0xff,
+ 0x26, 0x94, 0x61, 0x3b, 0xe2, 0xba, 0xaf, 0x2d, 0x98, 0x0b, 0xed, 0x88,
+ 0xfd, 0xb0, 0x16, 0xcc, 0xb1, 0xbf, 0x15, 0xa8, 0x5d, 0xb8, 0x0f, 0x3a,
+ 0x8b, 0xcd, 0xb6, 0x14, 0x3e, 0x13, 0x74, 0x6e, 0x3e, 0xf4, 0x5b, 0xf0,
+ 0x29, 0x83, 0x5a, 0xe0, 0xfb, 0xe3, 0xf0, 0x7d, 0x9d, 0x74, 0x00, 0x3e,
+ 0xeb, 0x20, 0x7c, 0xd6, 0x21, 0xd4, 0x8b, 0x63, 0x4b, 0xcd, 0xf7, 0xbc,
+ 0x5c, 0xa3, 0x76, 0x2a, 0x47, 0xe4, 0xf9, 0x97, 0x3c, 0xd5, 0xfc, 0x10,
+ 0x3a, 0xc0, 0x75, 0x57, 0xa8, 0x13, 0xf0, 0xb7, 0x56, 0x02, 0x3a, 0xb1,
+ 0xfd, 0x3e, 0x39, 0x03, 0xdb, 0x68, 0xb7, 0x85, 0xcc, 0xe5, 0x7c, 0xd9,
+ 0x97, 0x6b, 0xbe, 0xec, 0xe1, 0x97, 0x41, 0x5f, 0xa3, 0x52, 0x5d, 0xa7,
+ 0x12, 0xd6, 0x2d, 0x61, 0xdd, 0x12, 0xea, 0xbc, 0xe9, 0x7a, 0xf3, 0x77,
+ 0xaf, 0x8e, 0x80, 0x77, 0xc6, 0x0d, 0xfb, 0x7a, 0xd3, 0xfe, 0xc3, 0xe7,
+ 0x49, 0xc8, 0xff, 0x11, 0xc8, 0xff, 0x28, 0xea, 0x9b, 0xdf, 0x47, 0x7d,
+ 0xf3, 0x7b, 0xa8, 0x6f, 0x8e, 0xa0, 0xbe, 0x99, 0x44, 0x7d, 0xf3, 0x65,
+ 0xf8, 0x8f, 0xfb, 0xe0, 0x3f, 0x26, 0xe0, 0x3f, 0xc6, 0xe5, 0xdd, 0xd3,
+ 0x61, 0x77, 0xfb, 0x9d, 0x4a, 0xb8, 0x16, 0xb7, 0x9f, 0x12, 0x99, 0x25,
+ 0xec, 0x69, 0x8c, 0x6a, 0x0d, 0xae, 0x6f, 0x2c, 0x72, 0x46, 0xb9, 0xbe,
+ 0x99, 0x50, 0x26, 0x91, 0xbf, 0xdf, 0x3f, 0xcc, 0x75, 0x4f, 0x42, 0xc9,
+ 0xcb, 0xba, 0xc7, 0xb8, 0xe0, 0x20, 0x75, 0x43, 0xee, 0x87, 0x3d, 0x1b,
+ 0xe7, 0xf2, 0xe0, 0xc5, 0xcf, 0xf9, 0xba, 0x03, 0xbf, 0x17, 0xa7, 0xc5,
+ 0x59, 0xd4, 0x0c, 0xee, 0x3f, 0x28, 0x45, 0xe9, 0x1b, 0x75, 0x8c, 0x51,
+ 0x2b, 0xbb, 0xaf, 0x06, 0xe3, 0x11, 0x9a, 0x9a, 0x47, 0x6d, 0x7b, 0xfa,
+ 0x6f, 0x95, 0xbc, 0x1c, 0x5b, 0x18, 0x23, 0xdf, 0x3d, 0xfd, 0xd7, 0xc1,
+ 0xb8, 0x14, 0xe8, 0x43, 0xc0, 0xab, 0x6e, 0xe1, 0xd9, 0x15, 0xe4, 0x1c,
+ 0x2f, 0xf6, 0x6c, 0xfd, 0x3f, 0xef, 0xb8, 0xb5, 0x28, 0x64, 0x1e, 0xdf,
+ 0xe5, 0xd7, 0x67, 0xcd, 0xf3, 0x9d, 0x4d, 0xf3, 0xba, 0xfc, 0x0e, 0x5b,
+ 0xac, 0xb4, 0xbd, 0x07, 0x0f, 0x4c, 0x4b, 0x83, 0x46, 0xd5, 0xa6, 0x0f,
+ 0x3d, 0xfe, 0x5e, 0xe8, 0x88, 0x76, 0xf9, 0x0d, 0xcf, 0x91, 0xf7, 0x7a,
+ 0xb0, 0xf3, 0x91, 0x27, 0x77, 0xf9, 0xbe, 0x80, 0xfb, 0x49, 0xc5, 0xf7,
+ 0xef, 0x8f, 0x83, 0x0e, 0x64, 0xed, 0x36, 0xd7, 0x70, 0x7a, 0x70, 0x97,
+ 0xa2, 0x1f, 0x9f, 0xe1, 0xb3, 0x96, 0xb4, 0xb9, 0xd6, 0xe3, 0xba, 0x2f,
+ 0x8c, 0x01, 0x21, 0xad, 0xff, 0x48, 0xfa, 0x7c, 0xdf, 0x87, 0x9a, 0x8e,
+ 0x61, 0xc2, 0x71, 0x73, 0xfd, 0x17, 0x0f, 0xee, 0xe1, 0x98, 0xd7, 0x58,
+ 0xc0, 0xab, 0x16, 0xd0, 0xfb, 0x77, 0xcf, 0xf7, 0x3d, 0x8c, 0xaf, 0x37,
+ 0xe1, 0x5f, 0x40, 0xae, 0xc7, 0x77, 0x26, 0xbb, 0xe5, 0x77, 0xc9, 0x77,
+ 0x66, 0x3b, 0xe8, 0xed, 0x53, 0xc8, 0x59, 0x2d, 0x23, 0x73, 0x09, 0xb5,
+ 0xc7, 0x32, 0xdb, 0xc9, 0x08, 0xf3, 0x39, 0x90, 0x9e, 0xa6, 0x9b, 0x7b,
+ 0xfc, 0x5c, 0xfc, 0xab, 0xca, 0x47, 0xf9, 0x16, 0xc1, 0x3a, 0x3f, 0x6a,
+ 0x5a, 0x27, 0xdd, 0xb4, 0xce, 0x0a, 0xdb, 0x6c, 0xed, 0x4b, 0xd8, 0x73,
+ 0x69, 0xf7, 0xcd, 0x7a, 0x32, 0xa8, 0xcb, 0x1e, 0x1e, 0x69, 0xa3, 0x6a,
+ 0xaf, 0xb1, 0xf2, 0x1a, 0xf2, 0xf5, 0xe2, 0x08, 0xe6, 0x92, 0x03, 0x78,
+ 0xc7, 0xf3, 0x46, 0x8d, 0x84, 0xb1, 0x52, 0xa3, 0xcf, 0x01, 0xdf, 0x28,
+ 0x11, 0xf1, 0x3c, 0xf7, 0x25, 0x6f, 0xb5, 0xc0, 0x07, 0xa4, 0xd6, 0xb0,
+ 0xe7, 0x49, 0xd4, 0x5f, 0x47, 0x37, 0xea, 0x61, 0x5e, 0xe7, 0x56, 0x65,
+ 0x4d, 0xe6, 0xc6, 0xfb, 0x95, 0x52, 0xd2, 0xdf, 0xe3, 0xef, 0xc2, 0x5f,
+ 0xa8, 0x82, 0x71, 0xdf, 0x01, 0x6d, 0x85, 0x16, 0x4e, 0xa9, 0xf2, 0x0e,
+ 0xb6, 0x38, 0xc2, 0x67, 0xcd, 0xcf, 0x8f, 0x93, 0x5d, 0xb8, 0xa7, 0x3f,
+ 0x0d, 0xf6, 0x34, 0x16, 0xd4, 0xd3, 0xe1, 0x9e, 0x62, 0xf4, 0xe6, 0xac,
+ 0x0e, 0xdc, 0x9b, 0x20, 0x8f, 0x02, 0x2d, 0x35, 0xd2, 0x9f, 0x42, 0xa7,
+ 0xd2, 0x24, 0x1b, 0x6d, 0xdb, 0x19, 0x96, 0x36, 0x6b, 0xf8, 0xf1, 0x14,
+ 0xec, 0xf0, 0x78, 0x4f, 0x78, 0x37, 0xac, 0x9a, 0x1e, 0xd7, 0x3d, 0x68,
+ 0x3c, 0xdf, 0x0f, 0x5b, 0x4c, 0xc3, 0x3e, 0x39, 0x67, 0x2a, 0x70, 0xad,
+ 0xc2, 0xf6, 0xa4, 0x3b, 0xaa, 0xa1, 0x4f, 0x50, 0x06, 0xf5, 0x0e, 0xef,
+ 0x3f, 0x47, 0x8b, 0x8d, 0x90, 0x87, 0x2c, 0xec, 0x71, 0x14, 0xbf, 0x61,
+ 0xbc, 0xb3, 0xf0, 0xe3, 0x5a, 0x69, 0x85, 0x1e, 0x95, 0xb9, 0x38, 0x72,
+ 0xed, 0x41, 0xe6, 0xef, 0x4e, 0xc0, 0xb3, 0x3e, 0xb3, 0x9e, 0xde, 0x49,
+ 0x4e, 0x2f, 0xfb, 0x8a, 0x14, 0x68, 0x03, 0xc7, 0x5d, 0x87, 0xad, 0xf7,
+ 0xe3, 0x69, 0xe8, 0x45, 0x96, 0xad, 0xa4, 0xef, 0x79, 0x6a, 0x96, 0xbf,
+ 0x51, 0x5c, 0x08, 0xc6, 0x03, 0xfa, 0x3d, 0xac, 0x7b, 0xa9, 0x1b, 0x68,
+ 0x65, 0x3e, 0x8c, 0x83, 0x67, 0x60, 0x83, 0x7c, 0x67, 0x3b, 0x06, 0xb9,
+ 0xf0, 0x58, 0x09, 0xe2, 0x21, 0xe6, 0x17, 0x91, 0x94, 0xb4, 0xe7, 0x68,
+ 0x19, 0xf5, 0x3f, 0xf5, 0xf2, 0x13, 0xf9, 0xae, 0xbb, 0x33, 0xd0, 0xf7,
+ 0xad, 0xf8, 0xaa, 0xc9, 0xfd, 0x31, 0xf0, 0xa7, 0x35, 0xe1, 0x33, 0x8e,
+ 0x5f, 0x9f, 0xac, 0x11, 0xe2, 0x71, 0xca, 0xfb, 0x82, 0xc8, 0x3d, 0x4d,
+ 0xbf, 0x23, 0xf7, 0x54, 0xa7, 0x23, 0xf3, 0xa8, 0x6d, 0xb3, 0x03, 0x99,
+ 0x45, 0x32, 0x32, 0x27, 0x68, 0x48, 0x3f, 0x40, 0xaa, 0xfc, 0xd6, 0x97,
+ 0x16, 0xde, 0x17, 0x5a, 0x72, 0x9e, 0x77, 0x06, 0xbc, 0xbf, 0x28, 0xd7,
+ 0x79, 0x1a, 0xfc, 0x43, 0x56, 0xb2, 0x26, 0x61, 0x5e, 0xf1, 0x4c, 0x32,
+ 0xbf, 0x15, 0x3a, 0xd2, 0xf8, 0x61, 0x70, 0x36, 0x8f, 0x90, 0xe3, 0xbe,
+ 0xa5, 0x3a, 0x66, 0x05, 0xb0, 0xdf, 0x09, 0x78, 0xcb, 0x81, 0x5f, 0xac,
+ 0xdf, 0x58, 0x4f, 0xb2, 0x6f, 0xe0, 0x33, 0x77, 0x90, 0x35, 0x3a, 0x23,
+ 0xc8, 0xa3, 0x92, 0xd7, 0xf2, 0x03, 0x09, 0xda, 0xea, 0x07, 0x18, 0x2f,
+ 0xf1, 0x31, 0xba, 0xc2, 0x7c, 0x94, 0xa4, 0xff, 0x94, 0x71, 0x4b, 0xd2,
+ 0x53, 0xb7, 0xf9, 0x82, 0x6f, 0xc9, 0xe7, 0xaa, 0xca, 0xbe, 0x89, 0xe3,
+ 0x1f, 0xeb, 0x70, 0x27, 0xfc, 0x1f, 0x74, 0x10, 0x76, 0x9c, 0x9f, 0xe7,
+ 0xfb, 0x89, 0x41, 0xbe, 0x57, 0x3a, 0x57, 0xc0, 0xd9, 0x2e, 0xf0, 0xf7,
+ 0xc7, 0xa4, 0x5f, 0x63, 0xfa, 0xf5, 0x57, 0x9a, 0x7d, 0x21, 0xda, 0x92,
+ 0xf4, 0x93, 0x05, 0xf9, 0xbd, 0x31, 0x01, 0x18, 0x8f, 0x7d, 0x67, 0xd3,
+ 0xdf, 0x58, 0xbc, 0x6c, 0xfb, 0x7f, 0x63, 0x11, 0x7c, 0xfb, 0xad, 0xf9,
+ 0x79, 0xc4, 0x83, 0x75, 0x8d, 0x26, 0xeb, 0xe1, 0xdf, 0x5c, 0xf0, 0x39,
+ 0xc0, 0x37, 0xd7, 0xc3, 0xdc, 0xc1, 0x93, 0xf1, 0xa5, 0xbc, 0xe5, 0x2c,
+ 0x97, 0x82, 0x9c, 0x88, 0x6b, 0x00, 0x96, 0x21, 0xc6, 0x8b, 0xfe, 0xf9,
+ 0x2d, 0x88, 0x3d, 0x38, 0x3f, 0xc8, 0x1c, 0x7c, 0xbd, 0x39, 0xeb, 0xd7,
+ 0xb9, 0x65, 0xf6, 0x8b, 0xfd, 0x61, 0xdd, 0xbb, 0x9b, 0xca, 0x13, 0xfc,
+ 0x3e, 0x46, 0x6f, 0xcc, 0xc6, 0xe4, 0xfb, 0x22, 0xc5, 0x82, 0xf7, 0x3c,
+ 0x4e, 0x50, 0x51, 0xbe, 0xaf, 0x05, 0xf4, 0x50, 0xa7, 0xdd, 0x17, 0x8e,
+ 0x35, 0xe5, 0x48, 0xc3, 0xc7, 0x9b, 0x6a, 0xd4, 0xe8, 0xd1, 0xc6, 0x2a,
+ 0xf6, 0xaf, 0x50, 0x7e, 0xbc, 0x44, 0x37, 0x98, 0xba, 0x8c, 0xfb, 0x4e,
+ 0x82, 0x75, 0x8c, 0xf5, 0x6b, 0x4c, 0xd6, 0x9d, 0x25, 0xe4, 0x0b, 0xc5,
+ 0x11, 0xfe, 0xc6, 0xf3, 0xde, 0x5d, 0xc5, 0x8a, 0xa1, 0xdb, 0xf4, 0x81,
+ 0xe7, 0x68, 0x3c, 0x26, 0x21, 0x72, 0xab, 0x77, 0x3d, 0x58, 0xbf, 0x78,
+ 0x97, 0xbf, 0x57, 0xbc, 0xaf, 0x33, 0xac, 0x2a, 0xbf, 0xcd, 0xfe, 0xe4,
+ 0x76, 0x8d, 0xd6, 0x6e, 0xf7, 0xbc, 0xfb, 0x2d, 0x9d, 0x9c, 0xa0, 0x76,
+ 0xf5, 0xbf, 0xb9, 0xb7, 0xcb, 0x1c, 0xc4, 0x19, 0x49, 0x2b, 0x05, 0xd8,
+ 0xeb, 0xb2, 0x8b, 0x3a, 0x47, 0x18, 0xa3, 0xab, 0x42, 0x47, 0xcc, 0xe5,
+ 0x3b, 0x80, 0x3b, 0x7a, 0xf8, 0x7b, 0xf3, 0x8c, 0xc5, 0x30, 0x7d, 0xfe,
+ 0x5d, 0xd7, 0x2d, 0xf7, 0x49, 0x3f, 0x4b, 0x14, 0xc4, 0x9e, 0x5b, 0x9a,
+ 0x6d, 0xa2, 0x39, 0xb7, 0x64, 0x5b, 0xa0, 0x49, 0x0d, 0xbc, 0x94, 0x2b,
+ 0x61, 0x9e, 0xc6, 0x7f, 0x4b, 0xb0, 0x7a, 0xd7, 0x37, 0xc0, 0xe7, 0x34,
+ 0xf8, 0xe4, 0x7d, 0x4c, 0xd7, 0x43, 0x9d, 0x0b, 0x6b, 0x05, 0xee, 0x23,
+ 0xe6, 0xbb, 0x88, 0xf9, 0x2e, 0x62, 0xbe, 0x8b, 0x98, 0xef, 0x22, 0xe6,
+ 0xbb, 0x88, 0xf9, 0x2e, 0x62, 0xbe, 0x8b, 0x98, 0xef, 0x8e, 0x07, 0x79,
+ 0xda, 0x63, 0x1b, 0x79, 0xda, 0x4a, 0x83, 0xbf, 0x43, 0x49, 0x5e, 0x4a,
+ 0x25, 0xf2, 0xf3, 0x5c, 0x12, 0x9c, 0xd3, 0x84, 0x79, 0xee, 0xc7, 0x7f,
+ 0x13, 0xf1, 0xf1, 0x38, 0xc7, 0x63, 0xbc, 0x92, 0x22, 0x4c, 0xc6, 0xf3,
+ 0xf3, 0x3c, 0xae, 0xad, 0xb6, 0xe2, 0x20, 0x5f, 0xcb, 0xb1, 0x3f, 0x63,
+ 0xbb, 0x48, 0xfa, 0xf5, 0x62, 0xee, 0xf5, 0x2f, 0xa1, 0x76, 0x3c, 0x5e,
+ 0xac, 0xcb, 0x18, 0x8c, 0xf1, 0x7b, 0x18, 0x6b, 0xac, 0x73, 0xfc, 0xee,
+ 0x5e, 0xae, 0x27, 0x8a, 0xf5, 0x14, 0x95, 0x16, 0xc3, 0xfc, 0x07, 0x78,
+ 0xee, 0x90, 0x52, 0xa8, 0xf2, 0xd9, 0x0a, 0x9a, 0x4e, 0x42, 0x28, 0x66,
+ 0x73, 0x5e, 0x77, 0x49, 0xd6, 0x48, 0xfe, 0xdf, 0x05, 0x0d, 0x83, 0xb7,
+ 0xf0, 0x1e, 0x97, 0x48, 0x9d, 0x4d, 0xca, 0xbf, 0x31, 0x48, 0x98, 0x83,
+ 0xf2, 0x6f, 0x1d, 0xba, 0xb1, 0x8e, 0x98, 0xdd, 0x13, 0xfe, 0xed, 0x06,
+ 0xd7, 0x5d, 0xf6, 0xe6, 0xfd, 0x2b, 0xef, 0x23, 0x09, 0x7b, 0xbd, 0xa7,
+ 0x0f, 0x7b, 0xc3, 0xb9, 0x5e, 0xd9, 0x25, 0xf3, 0x6e, 0xf8, 0xce, 0x33,
+ 0x83, 0x37, 0xf5, 0x52, 0xe7, 0x6e, 0x5a, 0x1e, 0xe4, 0x1a, 0xad, 0x0d,
+ 0xf4, 0x18, 0xd6, 0xc8, 0xd8, 0x62, 0x37, 0x9d, 0x9d, 0x87, 0x6f, 0x9d,
+ 0x37, 0x2c, 0xfe, 0xfb, 0x82, 0x85, 0xc1, 0x24, 0x7c, 0xf2, 0x78, 0x2f,
+ 0xc7, 0xe4, 0xc5, 0x06, 0xeb, 0x4a, 0x37, 0xf0, 0xfb, 0xa1, 0x8b, 0x3b,
+ 0x60, 0x43, 0x02, 0xeb, 0x87, 0xb4, 0xff, 0x53, 0xd2, 0xee, 0x36, 0xf3,
+ 0x7d, 0x52, 0x37, 0x84, 0xa1, 0xa7, 0x05, 0x78, 0xff, 0x48, 0x6d, 0x69,
+ 0x11, 0x7f, 0x2f, 0x9c, 0x76, 0x9b, 0xbf, 0x1b, 0x0e, 0x29, 0xc5, 0x2a,
+ 0xff, 0x8d, 0xc3, 0x20, 0xfd, 0x4f, 0xe1, 0x56, 0x17, 0xd3, 0xd6, 0x79,
+ 0x86, 0xdf, 0xcf, 0xe6, 0x2f, 0xc4, 0x81, 0x13, 0xe2, 0x80, 0x41, 0x54,
+ 0xf3, 0x31, 0x07, 0xe2, 0xca, 0x44, 0x3d, 0x20, 0x32, 0x59, 0x15, 0x52,
+ 0x2d, 0xdb, 0x50, 0xb7, 0x5d, 0x36, 0x77, 0xcb, 0xa6, 0x4c, 0xda, 0x22,
+ 0x06, 0x49, 0x9b, 0x6a, 0xd2, 0x2e, 0x76, 0x31, 0xed, 0x2e, 0x96, 0x81,
+ 0x34, 0xcd, 0xec, 0x1a, 0x56, 0x32, 0xa4, 0x5d, 0x4c, 0xae, 0x31, 0x04,
+ 0x88, 0x53, 0xab, 0x5b, 0x2f, 0x32, 0x4d, 0x53, 0x90, 0x57, 0x25, 0xdd,
+ 0x4d, 0x6f, 0x76, 0x3f, 0x55, 0x64, 0xad, 0x72, 0xd1, 0x25, 0x6a, 0xa7,
+ 0x6a, 0x7f, 0x17, 0x67, 0xcf, 0xf3, 0x9d, 0x63, 0x20, 0x6c, 0xd5, 0x90,
+ 0xac, 0xf3, 0x9d, 0xef, 0x7c, 0xff, 0xdf, 0xfb, 0x3e, 0xef, 0x2f, 0x53,
+ 0xa0, 0x2f, 0xc3, 0x8a, 0xa9, 0x4b, 0x65, 0xb6, 0xb1, 0x50, 0xa6, 0x1d,
+ 0x7e, 0x13, 0xbc, 0xdc, 0x23, 0x8b, 0xa0, 0xe3, 0xfc, 0x68, 0xab, 0xe7,
+ 0x6f, 0xed, 0xf4, 0x78, 0x38, 0xd2, 0xeb, 0xc9, 0x28, 0xad, 0x4b, 0xe6,
+ 0xb5, 0x3e, 0xdd, 0x7d, 0xe8, 0xdb, 0x0f, 0xb0, 0xa6, 0x10, 0xce, 0x61,
+ 0xb8, 0x57, 0xe3, 0x91, 0x8f, 0xef, 0x7d, 0x87, 0xde, 0x7b, 0x0f, 0xbd,
+ 0x9f, 0xfc, 0x1f, 0xed, 0x59, 0x3e, 0x4c, 0x0f, 0x5c, 0xa7, 0x19, 0xe7,
+ 0x2c, 0xf9, 0xc2, 0x84, 0x9a, 0x2b, 0x98, 0x09, 0xea, 0x02, 0x29, 0x71,
+ 0x54, 0xca, 0x6e, 0x03, 0xc6, 0xb5, 0xc9, 0xc2, 0x0a, 0x68, 0x1e, 0xfb,
+ 0x68, 0xb7, 0x18, 0x2f, 0x7f, 0xb6, 0x97, 0x3c, 0xd3, 0x81, 0x6b, 0xf0,
+ 0x59, 0x43, 0x21, 0xb4, 0x73, 0x5e, 0xb3, 0x63, 0xc6, 0x45, 0xed, 0xbf,
+ 0xa1, 0x0e, 0xe3, 0xa8, 0xbc, 0xce, 0xfd, 0x60, 0x9b, 0x16, 0x79, 0x60,
+ 0x25, 0x7b, 0xbc, 0x5c, 0x22, 0xd8, 0xbb, 0x2f, 0xf6, 0x52, 0xbf, 0x78,
+ 0xd5, 0xde, 0xab, 0x33, 0x76, 0x85, 0x79, 0x5a, 0x20, 0x9a, 0x97, 0x45,
+ 0xca, 0x55, 0x91, 0x9b, 0xf8, 0xfd, 0xb1, 0xea, 0xc5, 0x2f, 0x14, 0x6d,
+ 0xed, 0x49, 0xd9, 0x2e, 0x3d, 0x2b, 0x35, 0xc8, 0x9c, 0x2d, 0xdb, 0x71,
+ 0x1e, 0xda, 0x61, 0x7d, 0xe6, 0xaf, 0x17, 0x94, 0x44, 0xc6, 0x28, 0xd3,
+ 0xda, 0xe4, 0x67, 0x2b, 0xcc, 0xbb, 0x33, 0x8d, 0x87, 0xc2, 0xfc, 0xb7,
+ 0x90, 0x64, 0x82, 0x7e, 0xad, 0x97, 0xca, 0xb7, 0x45, 0x3e, 0xc1, 0xb7,
+ 0x4f, 0x56, 0x5e, 0xe9, 0xa5, 0xcf, 0xe5, 0xe3, 0x15, 0xbe, 0xfb, 0xf0,
+ 0xf4, 0x49, 0xc3, 0xf2, 0x43, 0x7f, 0x05, 0xf0, 0x18, 0x3c, 0x77, 0xee,
+ 0xf7, 0x47, 0x5c, 0x1b, 0xea, 0x68, 0xc3, 0xb6, 0x49, 0x7e, 0x18, 0x38,
+ 0xa8, 0x86, 0x74, 0xbe, 0x52, 0x23, 0xa8, 0x71, 0xd9, 0x5f, 0x61, 0x5e,
+ 0x9d, 0x71, 0x54, 0x63, 0x74, 0xf2, 0xf6, 0x82, 0xde, 0x0b, 0xca, 0xb9,
+ 0x8a, 0x4d, 0x5a, 0x35, 0x64, 0x0b, 0xbc, 0xb6, 0x59, 0xdf, 0xea, 0xe3,
+ 0x5d, 0x6d, 0xd7, 0x17, 0x7b, 0x5d, 0x1b, 0x8d, 0x75, 0xaf, 0xf7, 0xba,
+ 0x75, 0x61, 0xcf, 0xe6, 0xa2, 0x6d, 0x56, 0xc6, 0xde, 0x7e, 0x2c, 0xf5,
+ 0xd5, 0x9f, 0xca, 0x9d, 0xd2, 0x4f, 0xe4, 0xb7, 0xab, 0xe7, 0xa1, 0x73,
+ 0x98, 0xe5, 0x1c, 0xe4, 0xc9, 0xbb, 0x75, 0xc7, 0x79, 0xd7, 0x3e, 0x07,
+ 0xfb, 0xc0, 0x71, 0xfe, 0x64, 0xef, 0x48, 0x64, 0xfc, 0x7b, 0xd8, 0x73,
+ 0x16, 0x3c, 0x44, 0x2c, 0xcc, 0x80, 0xde, 0x52, 0x7d, 0xd2, 0x19, 0xd0,
+ 0x74, 0x32, 0x34, 0xde, 0x8a, 0x3d, 0xf8, 0x3c, 0x3d, 0x9c, 0x7b, 0x49,
+ 0xf7, 0x91, 0x66, 0x7c, 0xf5, 0x0a, 0xe6, 0x6f, 0x05, 0x5f, 0x1c, 0xc5,
+ 0x4f, 0xc9, 0xc3, 0x31, 0xac, 0x75, 0x8c, 0xb4, 0xd7, 0x2a, 0x91, 0x67,
+ 0xb0, 0x8f, 0x6c, 0x8b, 0x3c, 0x2a, 0xdc, 0xea, 0xa5, 0x3f, 0xef, 0x51,
+ 0x81, 0x65, 0xdf, 0x57, 0xbb, 0xc4, 0x91, 0x16, 0xc8, 0xef, 0x85, 0x09,
+ 0x57, 0x57, 0xfa, 0x83, 0x3a, 0x85, 0xf6, 0x56, 0xee, 0x7d, 0x45, 0xdd,
+ 0x2e, 0xe7, 0xb4, 0x42, 0x17, 0x9f, 0x82, 0x0e, 0x94, 0xac, 0x5f, 0x91,
+ 0xc6, 0x58, 0x00, 0x6d, 0xa8, 0xa3, 0x68, 0x2c, 0x91, 0x54, 0x81, 0xf9,
+ 0x5d, 0xcc, 0xb5, 0xc2, 0x1a, 0xcf, 0x11, 0x37, 0xb8, 0xc6, 0x36, 0xc6,
+ 0xe0, 0xbc, 0x3a, 0x0b, 0x34, 0xc2, 0x3a, 0xd2, 0x77, 0x02, 0x3c, 0x99,
+ 0xa0, 0xdc, 0xc4, 0x78, 0xa3, 0x18, 0x8f, 0xe5, 0x2e, 0x8c, 0x77, 0x45,
+ 0x92, 0x76, 0x73, 0xcc, 0x38, 0xda, 0x10, 0x67, 0xe2, 0xd0, 0x1f, 0x06,
+ 0x55, 0x7a, 0x25, 0x08, 0xf9, 0xdd, 0x2b, 0x69, 0xe3, 0xc8, 0x81, 0x3d,
+ 0xe6, 0xb4, 0x7d, 0xe0, 0xf3, 0x8d, 0x7a, 0x6b, 0xea, 0x3a, 0xb0, 0x26,
+ 0xf6, 0xc7, 0x0f, 0xb6, 0x71, 0x72, 0x65, 0x09, 0x38, 0xb5, 0xf4, 0x41,
+ 0xd2, 0xbe, 0x20, 0xa9, 0x20, 0xd7, 0xc4, 0xfa, 0x20, 0xd6, 0x4c, 0x3f,
+ 0xd6, 0x77, 0x81, 0x43, 0x47, 0xbc, 0x3a, 0xb6, 0x15, 0x5f, 0x12, 0x67,
+ 0xef, 0xda, 0xb5, 0xac, 0xfb, 0x8a, 0x24, 0x97, 0xb2, 0x32, 0xad, 0xfb,
+ 0xf1, 0x0c, 0x07, 0xb4, 0xee, 0x41, 0x5e, 0x8d, 0x9c, 0xc0, 0x59, 0xc6,
+ 0xf6, 0x6d, 0xe0, 0xf0, 0x09, 0x72, 0x91, 0xd1, 0xe7, 0xf2, 0x2c, 0xbe,
+ 0x9d, 0xe0, 0x1d, 0xb5, 0x49, 0xe4, 0x5b, 0x90, 0x91, 0x85, 0x66, 0x7d,
+ 0x40, 0x3e, 0x2d, 0xf4, 0xf4, 0x31, 0xce, 0xf2, 0xd7, 0x82, 0x21, 0x1f,
+ 0x17, 0x74, 0x2c, 0x74, 0xc6, 0x2f, 0xe6, 0x65, 0xd7, 0x3e, 0x1f, 0x9e,
+ 0x59, 0x50, 0xfc, 0x3e, 0x7c, 0x79, 0x5d, 0x75, 0xa0, 0x6d, 0x00, 0xed,
+ 0xb8, 0x0e, 0x43, 0xa6, 0x0a, 0x9f, 0x3b, 0xb3, 0x23, 0x8e, 0x33, 0xad,
+ 0xf3, 0xc3, 0x62, 0xc6, 0x82, 0x6a, 0xea, 0xe4, 0x51, 0x29, 0x04, 0xdb,
+ 0x31, 0x57, 0xcc, 0x58, 0x57, 0xc3, 0x58, 0x0f, 0xcb, 0x27, 0xc8, 0x13,
+ 0xa1, 0x1d, 0xe1, 0xf8, 0x66, 0x66, 0x4d, 0xc5, 0xc2, 0x43, 0xca, 0x4c,
+ 0xe4, 0xf1, 0x6b, 0x51, 0x3a, 0x8e, 0x18, 0x0a, 0x2b, 0xf0, 0x2e, 0xf6,
+ 0x64, 0x9d, 0x76, 0x9c, 0x8c, 0xc5, 0xfa, 0x98, 0x11, 0x50, 0xf4, 0xb7,
+ 0x74, 0xea, 0x78, 0xe3, 0xb5, 0x93, 0x31, 0xe3, 0xb4, 0x3a, 0xee, 0xbd,
+ 0xc7, 0x81, 0x99, 0x7b, 0xe3, 0x9d, 0x5f, 0x53, 0x86, 0xbc, 0x51, 0x88,
+ 0x85, 0xe7, 0x94, 0x99, 0xc5, 0x98, 0xd9, 0xb4, 0x22, 0x6e, 0xc4, 0x8c,
+ 0x4e, 0x45, 0x9f, 0x68, 0xbb, 0xde, 0x77, 0x06, 0xfd, 0x63, 0xaa, 0xc5,
+ 0x5b, 0x0f, 0xef, 0xeb, 0xed, 0x3e, 0x97, 0x67, 0x88, 0x39, 0x23, 0xc0,
+ 0x4c, 0xe6, 0x9a, 0xe9, 0xdc, 0x86, 0x44, 0x64, 0x7c, 0x44, 0x63, 0xe8,
+ 0xe3, 0x33, 0x7f, 0x47, 0x1d, 0xca, 0x65, 0xd6, 0x45, 0x3d, 0x7e, 0x1b,
+ 0xd1, 0x3a, 0xf3, 0xe3, 0x33, 0x39, 0x9d, 0xf7, 0xd8, 0x50, 0x11, 0x6f,
+ 0xdf, 0x7b, 0x77, 0x16, 0x4e, 0xda, 0x4f, 0x71, 0x9c, 0x25, 0xff, 0x64,
+ 0xbb, 0x30, 0xa7, 0x74, 0xaa, 0xd4, 0xa4, 0x0d, 0xfa, 0x03, 0x98, 0x2f,
+ 0xd0, 0x8c, 0x7b, 0x5f, 0x11, 0xdf, 0x78, 0xc7, 0x01, 0x3a, 0x81, 0xae,
+ 0x09, 0x1d, 0xb5, 0x8a, 0x71, 0xf2, 0x2b, 0x92, 0x73, 0xfb, 0x4b, 0x07,
+ 0x73, 0x58, 0xf3, 0xd5, 0x2f, 0x1b, 0x83, 0x73, 0x63, 0x0e, 0xbc, 0x3f,
+ 0x3e, 0x43, 0xfa, 0xe4, 0xd9, 0x84, 0xd5, 0xd4, 0x2a, 0xd7, 0x33, 0x20,
+ 0xd3, 0x2b, 0x83, 0x32, 0x87, 0xdf, 0xc2, 0x8a, 0x7b, 0x6f, 0x1b, 0xd0,
+ 0xad, 0xa7, 0x0b, 0x86, 0xe6, 0xd7, 0x39, 0x9b, 0x31, 0x13, 0xf0, 0x8a,
+ 0xce, 0xa9, 0x62, 0x5f, 0xc6, 0x89, 0x06, 0x29, 0x1f, 0xed, 0x06, 0xe4,
+ 0xea, 0x46, 0x9d, 0x7a, 0x2a, 0xeb, 0xcd, 0x78, 0xd8, 0xdf, 0x2d, 0x0b,
+ 0xc0, 0xbb, 0x0a, 0x64, 0x67, 0xfe, 0xcd, 0x80, 0xcc, 0x15, 0x74, 0x3c,
+ 0x39, 0xfc, 0x17, 0x65, 0x4b, 0xad, 0x3e, 0x21, 0xb7, 0xeb, 0x51, 0xfd,
+ 0x8d, 0x72, 0x2d, 0xff, 0x0b, 0x9f, 0xbc, 0x32, 0xa2, 0xf3, 0xea, 0xa2,
+ 0x15, 0x79, 0xaa, 0x9f, 0x3a, 0xcf, 0xba, 0xce, 0xb1, 0x03, 0x76, 0x40,
+ 0xe7, 0x78, 0x0f, 0x3a, 0xc7, 0x6f, 0xa0, 0x73, 0xfc, 0xba, 0x04, 0x7c,
+ 0x29, 0x65, 0x3c, 0xfc, 0x9f, 0x01, 0x0e, 0x51, 0x56, 0x9b, 0xe7, 0x71,
+ 0xa7, 0x33, 0x39, 0xd0, 0xe0, 0x47, 0x92, 0x01, 0xde, 0x26, 0x65, 0x73,
+ 0x75, 0x5a, 0xb6, 0x56, 0xdd, 0x3c, 0xe5, 0xfb, 0xcc, 0x01, 0x1b, 0xe3,
+ 0x3d, 0x45, 0x81, 0x43, 0x47, 0x24, 0x72, 0x9a, 0xf8, 0xd1, 0x21, 0x6b,
+ 0xc5, 0xdf, 0x69, 0x1c, 0x5a, 0x2b, 0xb2, 0xec, 0x17, 0x9d, 0x4f, 0x76,
+ 0x6e, 0x47, 0x2a, 0x76, 0x03, 0xf5, 0xc7, 0xb4, 0x0f, 0xc8, 0xf5, 0xc9,
+ 0x13, 0x2f, 0x3f, 0xf7, 0xee, 0x5e, 0xe9, 0x3c, 0xbb, 0x59, 0xa3, 0x1b,
+ 0xed, 0x9a, 0xd8, 0x35, 0xe4, 0xc6, 0xbc, 0xd5, 0xdf, 0xd0, 0x06, 0x73,
+ 0x94, 0xba, 0x65, 0x03, 0x32, 0xa4, 0x11, 0xed, 0xd6, 0xba, 0x5f, 0x23,
+ 0x3a, 0xa8, 0x73, 0x77, 0x39, 0x4e, 0xbe, 0x68, 0xc9, 0x7c, 0xd1, 0x0c,
+ 0xe7, 0x40, 0x7f, 0xb7, 0x61, 0xab, 0x6d, 0xe2, 0x0e, 0xb6, 0x70, 0x06,
+ 0xdb, 0x75, 0xca, 0xf9, 0x2f, 0x34, 0xf6, 0xae, 0xd5, 0x3f, 0xc3, 0x38,
+ 0xe6, 0xf9, 0x84, 0x3c, 0xee, 0x23, 0x06, 0xd2, 0x1f, 0x95, 0xd2, 0xfd,
+ 0xdd, 0x7e, 0x9b, 0x68, 0xbb, 0x55, 0x27, 0x1e, 0x8b, 0x5c, 0x2d, 0x58,
+ 0x90, 0x25, 0xbf, 0x0a, 0x51, 0x07, 0x28, 0xab, 0x66, 0x3f, 0xc7, 0x5b,
+ 0xb3, 0xe3, 0x1c, 0xb5, 0xb8, 0xae, 0xa8, 0x87, 0xdb, 0x94, 0xfd, 0x3b,
+ 0x5a, 0xee, 0x17, 0x4a, 0x17, 0xe4, 0x1d, 0xdc, 0xb7, 0xab, 0xe3, 0x64,
+ 0xe5, 0x16, 0x74, 0xbc, 0x7a, 0xa9, 0x99, 0xd7, 0x3d, 0x89, 0x73, 0x32,
+ 0xd5, 0xfc, 0xf2, 0x75, 0xb9, 0x76, 0x63, 0x57, 0xbd, 0x71, 0x23, 0xa2,
+ 0xae, 0x2f, 0x0f, 0xa9, 0xfc, 0xb2, 0xe3, 0xfc, 0xd3, 0x9e, 0x95, 0x3b,
+ 0xab, 0x8e, 0x9c, 0xb5, 0x7d, 0xfd, 0x7e, 0x69, 0xe6, 0xd6, 0x39, 0x4e,
+ 0x07, 0xb0, 0x79, 0xfb, 0xa4, 0xe3, 0x3c, 0x3d, 0x36, 0x26, 0xd1, 0x93,
+ 0xd4, 0x51, 0x9e, 0x0b, 0x31, 0x3f, 0x96, 0x98, 0x93, 0xb4, 0xac, 0xcb,
+ 0x15, 0xa5, 0x80, 0x6f, 0xdd, 0xae, 0xfe, 0xf2, 0xcc, 0x31, 0x2f, 0x56,
+ 0x72, 0xe7, 0x35, 0xfa, 0x92, 0x43, 0xff, 0xe5, 0x4b, 0x36, 0xe4, 0x62,
+ 0x71, 0x04, 0xfd, 0x83, 0xf2, 0xc3, 0x62, 0xe0, 0x50, 0xd9, 0xc0, 0x73,
+ 0x54, 0xe5, 0x8b, 0x8f, 0x9c, 0x21, 0x1d, 0x33, 0x80, 0x4e, 0x62, 0x38,
+ 0xce, 0x9c, 0xcd, 0xf9, 0xba, 0x31, 0xdf, 0x8e, 0x71, 0x0c, 0xf2, 0xff,
+ 0xac, 0x96, 0xcf, 0x17, 0x15, 0x6c, 0x5f, 0xf0, 0x77, 0x50, 0xd2, 0x45,
+ 0xc8, 0x78, 0xc5, 0x9c, 0x53, 0xea, 0x0a, 0x66, 0x68, 0x0e, 0xd8, 0x31,
+ 0x0b, 0xbc, 0x79, 0x49, 0xc7, 0x56, 0x4f, 0x68, 0xec, 0x99, 0x67, 0x39,
+ 0x2b, 0x89, 0x8a, 0xdd, 0xa3, 0xcf, 0x6f, 0xf7, 0xf6, 0x2f, 0x43, 0xee,
+ 0x9d, 0x83, 0x8f, 0xb3, 0x4a, 0xda, 0x60, 0x03, 0xa5, 0xd6, 0xcf, 0x81,
+ 0x27, 0x42, 0x38, 0xdb, 0x56, 0xcd, 0x0f, 0x0d, 0xc8, 0xef, 0x86, 0xf6,
+ 0x23, 0xba, 0xf1, 0x8a, 0x86, 0xc1, 0x76, 0x17, 0xd0, 0xaf, 0x5d, 0x92,
+ 0xcb, 0x6d, 0x1a, 0x57, 0x9f, 0xac, 0x4b, 0x40, 0x0f, 0xf9, 0x3e, 0xca,
+ 0x7e, 0xd4, 0x85, 0xbd, 0xb2, 0x0f, 0xe5, 0x19, 0x94, 0x5b, 0xf0, 0x64,
+ 0x9b, 0x61, 0xe8, 0x15, 0x78, 0xbe, 0x8d, 0xf1, 0xc6, 0xb0, 0xe6, 0xac,
+ 0x21, 0x1f, 0x9e, 0xa1, 0x2c, 0x19, 0x55, 0xcc, 0x63, 0x9e, 0xb3, 0xf0,
+ 0xac, 0x0d, 0xa9, 0xd4, 0x12, 0xcb, 0x78, 0x96, 0xdd, 0xef, 0x4f, 0x60,
+ 0x12, 0xfa, 0x24, 0x6f, 0xb8, 0x98, 0xf4, 0xe1, 0x1e, 0x26, 0xb1, 0xae,
+ 0x5d, 0xd2, 0xcb, 0xe4, 0x75, 0x03, 0xf4, 0xd6, 0x29, 0xa9, 0x1b, 0x41,
+ 0xad, 0x8f, 0x56, 0x40, 0x8b, 0x1b, 0xa0, 0xab, 0x35, 0xd0, 0x54, 0xb2,
+ 0x68, 0xc6, 0x67, 0x54, 0x58, 0xfb, 0x02, 0x5e, 0x00, 0xbd, 0x76, 0xbc,
+ 0x49, 0x5d, 0x94, 0xbc, 0x1c, 0x05, 0xed, 0x89, 0xd3, 0x61, 0x59, 0x99,
+ 0xa8, 0xb2, 0x40, 0x83, 0xa0, 0xcb, 0xa2, 0xcb, 0xd3, 0xef, 0x2b, 0x8d,
+ 0xab, 0xf1, 0x07, 0x12, 0x4b, 0x3c, 0x10, 0x13, 0x58, 0x60, 0xda, 0x1f,
+ 0x88, 0x8d, 0x31, 0x27, 0xe4, 0x26, 0xe6, 0xf1, 0x81, 0xbf, 0x47, 0x4e,
+ 0x69, 0xfe, 0x8e, 0x8b, 0xff, 0x30, 0x8f, 0x83, 0xde, 0x80, 0x41, 0x2e,
+ 0x4f, 0x27, 0x3c, 0x1a, 0xfd, 0x26, 0xf8, 0xd7, 0x84, 0x25, 0x16, 0x94,
+ 0x05, 0xf0, 0xff, 0x06, 0xbe, 0xdf, 0xad, 0x0f, 0xab, 0xf9, 0x25, 0xe5,
+ 0xe5, 0x92, 0x7c, 0x07, 0x7a, 0xf2, 0x43, 0x9c, 0x5d, 0x97, 0xd6, 0xdd,
+ 0x23, 0x63, 0x8c, 0x9f, 0x65, 0xd4, 0x35, 0xeb, 0xb4, 0xec, 0x8e, 0x4e,
+ 0xa0, 0x7c, 0x0c, 0x4f, 0x1f, 0xce, 0x21, 0xa0, 0xe3, 0xdf, 0x6b, 0x05,
+ 0x5b, 0xb9, 0xff, 0xd3, 0x30, 0x8e, 0xbe, 0xc4, 0xb2, 0x93, 0xf8, 0x4e,
+ 0x5f, 0x0c, 0xf7, 0x06, 0x9d, 0x49, 0x85, 0x74, 0xbe, 0x69, 0x05, 0xba,
+ 0xc4, 0x3a, 0xc6, 0xbb, 0x47, 0x5f, 0x5e, 0x0d, 0x3c, 0x3c, 0xfa, 0x2f,
+ 0x27, 0x11, 0x64, 0x4e, 0xfb, 0x17, 0x21, 0x57, 0xfe, 0x7d, 0xea, 0xec,
+ 0x5a, 0xf3, 0x71, 0x1f, 0x5e, 0x3e, 0x32, 0x82, 0x68, 0x0b, 0x59, 0x06,
+ 0x59, 0x54, 0xd6, 0xf4, 0xcb, 0x76, 0x6e, 0xdf, 0x7c, 0x2d, 0x66, 0xdc,
+ 0x17, 0xb7, 0xef, 0x82, 0x45, 0xb9, 0xd3, 0x0e, 0x7c, 0x09, 0x6b, 0xbd,
+ 0xf2, 0x9e, 0x95, 0x03, 0x2a, 0x98, 0xe1, 0x0c, 0x68, 0xb4, 0x4d, 0xcc,
+ 0xe8, 0x94, 0xec, 0xcf, 0x3b, 0xa7, 0xfb, 0xb2, 0x6d, 0xb3, 0x6f, 0x73,
+ 0x5e, 0xae, 0x9f, 0x7b, 0xe1, 0x1e, 0xe8, 0x9b, 0x36, 0x34, 0x8d, 0x36,
+ 0x6a, 0x03, 0xfd, 0x2e, 0x8d, 0x36, 0xf7, 0x11, 0xfc, 0x3f, 0xfb, 0x20,
+ 0x9d, 0xd8, 0xca, 0x8d, 0xd3, 0xe3, 0x59, 0xe3, 0x79, 0x0e, 0x83, 0x36,
+ 0x0e, 0xd2, 0x4f, 0xd3, 0xb7, 0xe8, 0xd2, 0xcf, 0xd3, 0x7b, 0xf4, 0x43,
+ 0xba, 0xe9, 0x94, 0xf4, 0x0d, 0x4b, 0xa6, 0x8b, 0xfa, 0xbe, 0xa1, 0x6b,
+ 0xd2, 0x67, 0x34, 0x01, 0xba, 0x21, 0xad, 0x93, 0xb7, 0x0c, 0x29, 0x83,
+ 0x8e, 0xca, 0xc0, 0xa7, 0x32, 0x68, 0xaa, 0x02, 0x7c, 0x2b, 0x03, 0xdf,
+ 0xca, 0x75, 0x33, 0x5a, 0xc5, 0x9e, 0x29, 0xb3, 0xd7, 0x41, 0x47, 0x1b,
+ 0x75, 0xde, 0xbf, 0x5e, 0xb3, 0x41, 0x39, 0x78, 0x77, 0xef, 0xee, 0xff,
+ 0x81, 0xbb, 0x1f, 0x94, 0xdb, 0xb0, 0x5b, 0xde, 0x29, 0x8d, 0x02, 0x93,
+ 0x04, 0x18, 0x65, 0x83, 0x36, 0xe2, 0xb2, 0x59, 0x9a, 0x94, 0x2d, 0xc8,
+ 0xa7, 0xed, 0xd5, 0x08, 0xf4, 0xe9, 0x90, 0xcc, 0xbf, 0x35, 0x22, 0xb7,
+ 0x56, 0x95, 0xcc, 0x82, 0x7e, 0xf3, 0x6b, 0xf4, 0xbb, 0x83, 0x9e, 0xcb,
+ 0x9d, 0x3a, 0x4e, 0x9f, 0xae, 0xba, 0xfe, 0xf7, 0xa9, 0x6a, 0x97, 0x4c,
+ 0x57, 0x0d, 0x79, 0xbe, 0xda, 0x23, 0x2f, 0x56, 0x83, 0x72, 0x16, 0x76,
+ 0xe0, 0xd7, 0xaa, 0x03, 0xf2, 0x52, 0x75, 0x50, 0xbe, 0x5e, 0x0b, 0xcb,
+ 0x37, 0x6a, 0x96, 0x64, 0x6b, 0x51, 0xc9, 0xd4, 0x46, 0xe5, 0x85, 0x1a,
+ 0xfd, 0xea, 0x98, 0x0f, 0xbf, 0xd4, 0x9e, 0xbf, 0x82, 0xeb, 0xea, 0xc0,
+ 0xba, 0xa2, 0x6a, 0x4a, 0xc7, 0x29, 0x25, 0xeb, 0xfa, 0x3c, 0x44, 0x2e,
+ 0x61, 0xac, 0xc5, 0xb7, 0x94, 0x54, 0xf4, 0xfc, 0xcd, 0xff, 0x33, 0x09,
+ 0x68, 0xdb, 0xe8, 0x52, 0x79, 0x00, 0x6d, 0x20, 0xf7, 0x0a, 0x4d, 0xdf,
+ 0x47, 0xd3, 0xe7, 0xdf, 0xb4, 0xbd, 0x7c, 0xda, 0x6f, 0x7d, 0x97, 0xb6,
+ 0x97, 0x3e, 0x7b, 0xe2, 0x07, 0xed, 0x9c, 0x9b, 0xda, 0x6f, 0xb2, 0x1f,
+ 0xdb, 0x68, 0xce, 0xbb, 0x98, 0x7d, 0xf2, 0xff, 0x59, 0xdc, 0x18, 0xd5,
+ 0xc5, 0xda, 0x00, 0xff, 0xaf, 0x05, 0x6b, 0xf9, 0xf2, 0xdc, 0xf1, 0xe9,
+ 0x52, 0x5a, 0x3d, 0x5f, 0xa2, 0x46, 0xe3, 0xc8, 0xe2, 0x5e, 0x4e, 0xdc,
+ 0x73, 0xb2, 0x66, 0x07, 0xf4, 0x1a, 0x5c, 0x5f, 0x7d, 0x42, 0xe7, 0xc7,
+ 0xa5, 0x4f, 0x91, 0xfe, 0x18, 0x7b, 0xeb, 0xf2, 0xe2, 0x09, 0xd0, 0x6d,
+ 0x6d, 0x43, 0xae, 0x56, 0x5d, 0x9f, 0xd5, 0xbc, 0xa6, 0x97, 0x7b, 0xa0,
+ 0x39, 0xc6, 0x1c, 0xdc, 0x67, 0xae, 0xec, 0xf6, 0x4d, 0xe1, 0xde, 0x60,
+ 0x8f, 0x63, 0xbf, 0xbe, 0x1e, 0xce, 0xc5, 0xff, 0xe3, 0x41, 0xd9, 0x5b,
+ 0x2f, 0x73, 0x8d, 0x2d, 0x4d, 0x8b, 0x6e, 0x5c, 0x37, 0x2a, 0xaf, 0xe2,
+ 0xfc, 0x2a, 0x06, 0xd7, 0xdf, 0x21, 0x95, 0x28, 0x6d, 0x5b, 0xe2, 0xf7,
+ 0x29, 0x29, 0x63, 0x9e, 0x4a, 0xb4, 0xe9, 0x0f, 0x73, 0x71, 0xb6, 0x62,
+ 0xec, 0xcf, 0x3b, 0x53, 0x3e, 0x8e, 0x77, 0xd4, 0x45, 0xa1, 0x33, 0x9d,
+ 0xe3, 0xfb, 0x22, 0xca, 0xf4, 0x8d, 0xcc, 0xe3, 0x19, 0xf2, 0xea, 0xde,
+ 0xeb, 0xd7, 0xba, 0xfa, 0xe4, 0x7e, 0xbf, 0xd9, 0xb2, 0x99, 0x4b, 0xfa,
+ 0x63, 0xca, 0xf7, 0xf3, 0xdf, 0xf7, 0x13, 0x73, 0x8f, 0x5b, 0xfc, 0x05,
+ 0xe4, 0x33, 0x43, 0xfb, 0x14, 0xbc, 0x6f, 0x47, 0xe4, 0x65, 0x83, 0x79,
+ 0xec, 0x09, 0x95, 0x2e, 0x5d, 0xf7, 0x72, 0x7c, 0x63, 0xea, 0x78, 0xe5,
+ 0x7e, 0xbf, 0x9b, 0xf3, 0xce, 0xb1, 0x0f, 0xe6, 0xb9, 0x1f, 0xa4, 0x13,
+ 0xe6, 0xbb, 0xb7, 0xef, 0xfd, 0x0f, 0x55, 0xa5, 0x00, 0xbc, 0xb3, 0x5a,
+ 0x34, 0x3f, 0xe6, 0x6b, 0xff, 0x76, 0x76, 0x34, 0x3f, 0x37, 0x7d, 0x0c,
+ 0x7f, 0xee, 0xa7, 0x6d, 0x4b, 0xdc, 0xb8, 0xea, 0xe6, 0x8e, 0x6a, 0x1b,
+ 0x1a, 0x58, 0x81, 0x3a, 0xf2, 0x2a, 0xf8, 0x64, 0xaf, 0x2d, 0xff, 0xfe,
+ 0x03, 0x9a, 0xb8, 0x8a, 0x6c, 0x8c, 0x67, 0x00, 0x00, 0x00 };
static const u32 bnx2_RXP_b09FwData[(0x0/4) + 1] = { 0x0 };
static const u32 bnx2_RXP_b09FwRodata[(0x278/4) + 1] = {
- 0x08004050, 0x08003f50, 0x08003ff4, 0x0800400c, 0x08004024, 0x08004044,
- 0x08004050, 0x08004050, 0x08003f58, 0x00000000, 0x08004a0c, 0x08004a44,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004a7c, 0x08004c40,
- 0x08004b88, 0x08004bc0, 0x08004c40, 0x08004b10, 0x08004c40, 0x08004c40,
- 0x08004bc0, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c00,
- 0x08004c40, 0x08004c00, 0x08004b88, 0x08004c40, 0x08004c40, 0x08004c00,
- 0x08004c00, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
- 0x08004aec, 0x00000000, 0x08006058, 0x08006070, 0x08006070, 0x08006070,
- 0x08006058, 0x08006070, 0x08006070, 0x08006070, 0x08006058, 0x08006070,
- 0x08006070, 0x08006070, 0x08006058, 0x08006070, 0x08006070, 0x08006070,
- 0x08006064, 0x00000000, 0x00000000 };
-static const u32 bnx2_RXP_b09FwBss[(0x13dc/4) + 1] = { 0x0 };
-static const u32 bnx2_RXP_b09FwSbss[(0x20/4) + 1] = { 0x0 };
+ 0x08004070, 0x08003f70, 0x08004014, 0x0800402c, 0x08004044, 0x08004064,
+ 0x08004070, 0x08004070, 0x08003f78, 0x00000000, 0x08004a2c, 0x08004a64,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004a9c, 0x08004c60,
+ 0x08004ba8, 0x08004be0, 0x08004c60, 0x08004b30, 0x08004c60, 0x08004c60,
+ 0x08004be0, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c20,
+ 0x08004c60, 0x08004c20, 0x08004ba8, 0x08004c60, 0x08004c60, 0x08004c20,
+ 0x08004c20, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60,
+ 0x08004b0c, 0x00000000, 0x08006078, 0x08006090, 0x08006090, 0x08006090,
+ 0x08006078, 0x08006090, 0x08006090, 0x08006090, 0x08006078, 0x08006090,
+ 0x08006090, 0x08006090, 0x08006078, 0x08006090, 0x08006090, 0x08006090,
+ 0x08006084, 0x00000000, 0x00000000 };
static struct fw_info bnx2_rxp_fw_09 = {
+ /* Firmware version: 3.7.1 */
.ver_major = 0x3,
- .ver_minor = 0x4,
- .ver_fix = 0x3,
+ .ver_minor = 0x7,
+ .ver_fix = 0x1,
.start_addr = 0x08003184,
.text_addr = 0x08000000,
- .text_len = 0x6768,
+ .text_len = 0x6788,
.text_index = 0x0,
.gz_text = bnx2_RXP_b09FwText,
.gz_text_len = sizeof(bnx2_RXP_b09FwText),
- .data_addr = 0x08006a00,
+ .data_addr = 0x08006a20,
.data_len = 0x0,
.data_index = 0x0,
.data = bnx2_RXP_b09FwData,
- .sbss_addr = 0x08006a00,
+ .sbss_addr = 0x08006a20,
.sbss_len = 0x20,
.sbss_index = 0x0,
- .sbss = bnx2_RXP_b09FwSbss,
- .bss_addr = 0x08006a20,
+ .bss_addr = 0x08006a40,
.bss_len = 0x13dc,
.bss_index = 0x0,
- .bss = bnx2_RXP_b09FwBss,
- .rodata_addr = 0x08006768,
+ .rodata_addr = 0x08006788,
.rodata_len = 0x278,
.rodata_index = 0x0,
.rodata = bnx2_RXP_b09FwRodata,
};
static u8 bnx2_TPAT_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x58,
- 0x5d, 0x68, 0x1c, 0xd7, 0x15, 0x3e, 0xf3, 0xb7, 0x3b, 0x52, 0x24, 0xeb,
- 0x5a, 0xd9, 0xa6, 0xeb, 0xa0, 0x34, 0x33, 0xda, 0x91, 0xac, 0x22, 0x13,
- 0x4f, 0x9d, 0x25, 0x16, 0x65, 0x21, 0x93, 0xd9, 0x91, 0xac, 0x98, 0x3c,
- 0x28, 0xc5, 0x90, 0x87, 0x52, 0x50, 0x57, 0x32, 0x09, 0x79, 0x69, 0xda,
- 0xc6, 0x90, 0x3e, 0x79, 0x3b, 0x2b, 0xc7, 0x0e, 0x6c, 0xbc, 0x8d, 0x52,
- 0xe4, 0x52, 0xfa, 0x60, 0xd6, 0xb1, 0x05, 0xcd, 0x46, 0x93, 0xd4, 0x7e,
- 0x35, 0x36, 0x4e, 0x93, 0xa7, 0x42, 0x9f, 0x52, 0xf4, 0x18, 0xd2, 0x12,
- 0xda, 0x52, 0x8a, 0x69, 0xa1, 0x09, 0x8d, 0xeb, 0xdb, 0xef, 0xdc, 0x99,
- 0x91, 0x57, 0xb6, 0xec, 0xa4, 0x25, 0x85, 0x0a, 0x56, 0x77, 0xe6, 0xce,
- 0x3d, 0xe7, 0x9e, 0x7b, 0xee, 0x77, 0xbe, 0x73, 0xee, 0x2d, 0xeb, 0x34,
- 0x48, 0xd9, 0xdf, 0x30, 0x7e, 0x2f, 0x7e, 0xf7, 0x85, 0x17, 0xab, 0x8f,
- 0x3c, 0xea, 0x10, 0x3d, 0xfa, 0x88, 0x66, 0x98, 0x06, 0x7d, 0x09, 0x7f,
- 0x50, 0x22, 0x72, 0xfd, 0xfc, 0x23, 0x5b, 0xaf, 0x9d, 0x72, 0x42, 0x8f,
- 0x6c, 0xa3, 0x26, 0xbe, 0xbe, 0xe4, 0x11, 0x05, 0xbd, 0x69, 0xa7, 0x4e,
- 0xff, 0x92, 0xcd, 0x92, 0x49, 0xdc, 0xff, 0x50, 0xed, 0xc6, 0xfe, 0xcb,
- 0x07, 0xdd, 0xeb, 0x67, 0x0d, 0xb2, 0x45, 0x6d, 0xd1, 0x16, 0x93, 0x64,
- 0x8f, 0xd5, 0x9a, 0xce, 0x2f, 0xf6, 0x1e, 0x28, 0xd0, 0xae, 0x5c, 0x97,
- 0xa0, 0xb8, 0x43, 0x4d, 0xab, 0x66, 0x53, 0xd4, 0x7e, 0x49, 0x0b, 0x3b,
- 0x9e, 0x98, 0x85, 0x8e, 0xa0, 0x04, 0xfd, 0x1e, 0xde, 0x13, 0x53, 0x8b,
- 0xce, 0xd8, 0xa4, 0xd7, 0x02, 0x3c, 0x4f, 0x51, 0xab, 0x23, 0xe5, 0x2b,
- 0xbe, 0x46, 0x4b, 0xbe, 0x4d, 0x8b, 0xc2, 0x0d, 0x1c, 0xed, 0xa6, 0xac,
- 0x4c, 0x48, 0xf9, 0x9c, 0xaf, 0x93, 0xee, 0xcd, 0x69, 0xe1, 0xfa, 0xbc,
- 0x56, 0x5f, 0x9f, 0x67, 0x7f, 0xc0, 0xbe, 0x39, 0x2d, 0x58, 0xe7, 0xb6,
- 0x66, 0xd7, 0xdb, 0xbb, 0x68, 0xb1, 0x44, 0x23, 0xba, 0x37, 0x85, 0xf9,
- 0x4a, 0xd0, 0xe3, 0x50, 0xe8, 0x4f, 0x0b, 0x9d, 0x2a, 0xf8, 0x0d, 0xd0,
- 0xac, 0x4f, 0x03, 0xba, 0xa7, 0x53, 0xa3, 0xa4, 0xd1, 0x1b, 0x55, 0x0b,
- 0xbf, 0xc3, 0x5a, 0xb4, 0xfe, 0x7c, 0xa6, 0x87, 0xc7, 0xdb, 0xf8, 0xc6,
- 0x36, 0xb3, 0x7c, 0xbf, 0xec, 0x30, 0x9e, 0x9f, 0xc3, 0x38, 0x8b, 0xc2,
- 0xea, 0xed, 0xdf, 0x06, 0xf0, 0xac, 0xa1, 0xff, 0x30, 0xec, 0x62, 0x3d,
- 0x0e, 0xec, 0x28, 0xd3, 0x4a, 0x67, 0x1e, 0xeb, 0x29, 0x50, 0x53, 0x4c,
- 0x4c, 0x35, 0xc8, 0x84, 0x8c, 0x41, 0x41, 0xe9, 0x8a, 0xd4, 0x6b, 0x52,
- 0x86, 0x55, 0x6f, 0xaa, 0xab, 0xe6, 0xd0, 0xc9, 0xf0, 0x0a, 0x14, 0xf9,
- 0xc3, 0xd4, 0x12, 0x06, 0xc5, 0xfb, 0x2c, 0x0a, 0x16, 0x4c, 0xac, 0x71,
- 0x14, 0x72, 0x1a, 0xe4, 0x5f, 0xcb, 0xf6, 0xbc, 0x48, 0xb1, 0x28, 0xa0,
- 0x7f, 0x84, 0xe2, 0xd2, 0x6e, 0x4d, 0xaf, 0xbd, 0x82, 0xfe, 0x09, 0xd1,
- 0xa5, 0x53, 0x68, 0x35, 0xbc, 0xef, 0xc6, 0x58, 0x7e, 0xd7, 0xa0, 0x8f,
- 0x44, 0x98, 0x78, 0xd4, 0x4a, 0x72, 0x59, 0xee, 0x4f, 0xfb, 0x9a, 0xc9,
- 0xed, 0xfb, 0xed, 0xc1, 0x4e, 0x41, 0x27, 0x3a, 0xb3, 0x98, 0x8f, 0x9a,
- 0x46, 0x0d, 0xe3, 0xb0, 0x37, 0xbc, 0xbf, 0x81, 0xc2, 0xc1, 0xe3, 0xdc,
- 0xcf, 0x7f, 0xe8, 0x77, 0xc8, 0xa8, 0xf1, 0xb7, 0x6f, 0x52, 0xfa, 0x2d,
- 0xb5, 0x3f, 0xf4, 0x1f, 0xcb, 0xde, 0x4b, 0x22, 0x3c, 0xf3, 0x28, 0xd6,
- 0xa8, 0x60, 0x83, 0xe7, 0x02, 0xf0, 0x11, 0xcf, 0xe8, 0xd4, 0x2c, 0x17,
- 0xc9, 0xf5, 0x8f, 0xa2, 0xf7, 0xd7, 0x6d, 0x83, 0xea, 0xec, 0x2b, 0xdf,
- 0xcc, 0x64, 0x18, 0x1b, 0x1f, 0x64, 0x76, 0x0a, 0x5a, 0x3c, 0x22, 0xe5,
- 0x8a, 0x2f, 0xa5, 0x55, 0xf3, 0x9c, 0x13, 0x34, 0x5d, 0x36, 0x69, 0x52,
- 0xa0, 0x85, 0x8f, 0xbd, 0x72, 0x83, 0x2c, 0x60, 0xa1, 0x1f, 0xff, 0xfc,
- 0xf7, 0xa6, 0x86, 0x25, 0xd0, 0xb5, 0x36, 0xeb, 0x98, 0x70, 0x66, 0x95,
- 0x8c, 0x94, 0xf1, 0xcc, 0xbd, 0x64, 0x2e, 0x65, 0x32, 0x52, 0x46, 0x55,
- 0x81, 0x3d, 0x6f, 0x0a, 0xd8, 0x87, 0x75, 0x31, 0xc6, 0x89, 0xa2, 0x9e,
- 0x6f, 0x37, 0xda, 0xb0, 0xd1, 0x43, 0xdb, 0x13, 0xf0, 0x0f, 0x51, 0x0b,
- 0x63, 0xf5, 0xea, 0x7d, 0x8c, 0x0d, 0xec, 0xef, 0x82, 0x1d, 0xb5, 0xdd,
- 0xf2, 0x29, 0x5a, 0xb0, 0xeb, 0xbd, 0xe9, 0xf2, 0x32, 0x3d, 0xc4, 0x73,
- 0xd8, 0x56, 0xed, 0x88, 0xdd, 0x55, 0x72, 0x88, 0xc4, 0x41, 0x3c, 0xf7,
- 0x88, 0xe2, 0x36, 0x69, 0xa1, 0x7f, 0x1f, 0xaf, 0x15, 0x72, 0xf3, 0x99,
- 0xdc, 0x7c, 0x26, 0x37, 0x92, 0xc9, 0x3d, 0xd5, 0x27, 0xf7, 0x14, 0xcb,
- 0x61, 0x6c, 0x90, 0x8d, 0x0d, 0xb2, 0xb1, 0x66, 0x36, 0x36, 0xca, 0xc6,
- 0xa2, 0xed, 0x8d, 0xc1, 0x36, 0x77, 0xca, 0xd1, 0x6c, 0x8a, 0x3d, 0xf9,
- 0x70, 0xe8, 0x53, 0x50, 0xf7, 0xdc, 0xcd, 0xba, 0x31, 0x42, 0xe7, 0xfc,
- 0x21, 0x5a, 0x49, 0xc6, 0x28, 0x4e, 0x56, 0x28, 0x4c, 0x74, 0xc8, 0x8e,
- 0x50, 0xd7, 0xbb, 0x2e, 0x67, 0x7d, 0x1f, 0x7b, 0x66, 0xb3, 0x5c, 0x79,
- 0x96, 0x1c, 0x7c, 0x9f, 0x16, 0xcb, 0xe4, 0x03, 0x2b, 0x3a, 0xf6, 0xad,
- 0xa2, 0x9e, 0xe3, 0xc4, 0xe7, 0x35, 0x37, 0xf5, 0xaa, 0x2b, 0x62, 0x72,
- 0xcb, 0xa1, 0x41, 0x42, 0xaf, 0xc1, 0x4f, 0x49, 0x93, 0xa2, 0xc4, 0xa6,
- 0x0f, 0x8d, 0x97, 0x54, 0x8c, 0xc6, 0x9d, 0x4d, 0x79, 0x79, 0xaf, 0x43,
- 0x57, 0x30, 0xcf, 0xc5, 0xa4, 0x4c, 0xbf, 0x4a, 0x4a, 0xf4, 0x4e, 0x42,
- 0x7a, 0xe8, 0x03, 0xc3, 0x25, 0x41, 0x6f, 0x27, 0xfd, 0x3e, 0xff, 0x88,
- 0x7d, 0x6e, 0xdf, 0x5f, 0x23, 0x7b, 0xb4, 0xc6, 0x38, 0x4b, 0x39, 0xa0,
- 0x9e, 0x72, 0x80, 0xc2, 0x52, 0xab, 0x13, 0x3f, 0x68, 0x80, 0x7f, 0x96,
- 0xfc, 0x60, 0xb7, 0xa1, 0xf6, 0xa3, 0x89, 0x3d, 0xcc, 0x5b, 0xde, 0x9b,
- 0xab, 0xce, 0x92, 0xe7, 0x9e, 0xaa, 0x33, 0x6a, 0x4f, 0x5b, 0x39, 0x2e,
- 0xfb, 0xe6, 0xf8, 0x33, 0xe6, 0x18, 0xa2, 0x06, 0xe2, 0xec, 0x09, 0x13,
- 0xb1, 0xe3, 0xfd, 0xdd, 0x60, 0x5c, 0x39, 0x1b, 0x8c, 0x6f, 0xa2, 0xf1,
- 0x0d, 0x9b, 0xd6, 0xdb, 0x45, 0x72, 0xba, 0x43, 0xb4, 0xd4, 0x19, 0xa4,
- 0xca, 0x05, 0x13, 0x63, 0xef, 0xa3, 0xca, 0xaa, 0x5e, 0xe2, 0x38, 0xae,
- 0xc3, 0xc7, 0xe3, 0x5d, 0x09, 0x7c, 0x0e, 0xd2, 0xf8, 0x9a, 0xab, 0xb0,
- 0xb3, 0xe4, 0xb5, 0x7c, 0x83, 0x7e, 0x4c, 0xd7, 0xf6, 0x15, 0xb0, 0xa6,
- 0x12, 0xf9, 0x93, 0xfd, 0xf3, 0xe9, 0x80, 0x18, 0xf7, 0xc5, 0x45, 0xda,
- 0xe5, 0x3a, 0xa4, 0xb3, 0x3e, 0x9b, 0xc6, 0x2f, 0xd8, 0x5a, 0xbd, 0xc3,
- 0x3e, 0x63, 0xfc, 0xd9, 0x19, 0xfe, 0x4c, 0x2d, 0x3c, 0x53, 0xc4, 0x5c,
- 0x7f, 0x91, 0xa1, 0x27, 0xb1, 0x0f, 0x3a, 0x2d, 0x55, 0x7f, 0x04, 0xfb,
- 0xd0, 0xd7, 0xe5, 0x6f, 0xd7, 0xb3, 0x7e, 0xd6, 0x01, 0x7e, 0xf0, 0xef,
- 0xa7, 0x90, 0xb9, 0xe0, 0x08, 0xcb, 0x14, 0x69, 0x7c, 0x95, 0xf9, 0x05,
- 0x6d, 0x97, 0xdf, 0x79, 0x6d, 0x03, 0xd4, 0x80, 0x57, 0x1a, 0x53, 0x25,
- 0xd8, 0xa5, 0x2b, 0xbe, 0x68, 0x80, 0x3f, 0x74, 0x6f, 0x10, 0x2d, 0xcf,
- 0xf7, 0x73, 0x23, 0x8f, 0xa9, 0xb8, 0x33, 0x44, 0x75, 0xe0, 0xd7, 0x84,
- 0x3d, 0xcb, 0x34, 0x51, 0x3e, 0xaa, 0xbe, 0xa1, 0xaf, 0xc7, 0xdf, 0xc4,
- 0x6d, 0xdf, 0xf0, 0xde, 0xcb, 0x6d, 0x40, 0x6c, 0x7b, 0x2d, 0xcc, 0x62,
- 0x65, 0x7e, 0xe1, 0xf1, 0xcd, 0x32, 0xf6, 0x06, 0x7c, 0x46, 0xf0, 0x25,
- 0x51, 0xb7, 0x6d, 0x82, 0x6f, 0xf4, 0xaf, 0xea, 0x2c, 0x57, 0x62, 0x3d,
- 0x58, 0xff, 0x9a, 0xa9, 0xd5, 0xcf, 0x78, 0xce, 0x1f, 0x88, 0xe5, 0x2b,
- 0xf0, 0xc1, 0xc4, 0x4c, 0x8b, 0xc7, 0xf7, 0x2c, 0xf2, 0x56, 0x9b, 0xc2,
- 0xc4, 0x9e, 0xc2, 0x73, 0x54, 0xff, 0xc9, 0x08, 0xf6, 0xda, 0x75, 0x5a,
- 0xf4, 0x5b, 0xd8, 0x53, 0x20, 0xaf, 0x6b, 0xd2, 0x1b, 0x6d, 0xf6, 0x85,
- 0x4d, 0x95, 0x35, 0x29, 0x4f, 0xfa, 0xbc, 0x27, 0xbf, 0x83, 0x5f, 0x08,
- 0x2b, 0x9c, 0x98, 0xf9, 0x08, 0xfb, 0xb3, 0xde, 0xe3, 0xbd, 0xb1, 0x94,
- 0x4f, 0xbc, 0xd5, 0x29, 0xec, 0xeb, 0x54, 0x66, 0x23, 0xef, 0x97, 0x49,
- 0x2b, 0x55, 0x9d, 0xce, 0x57, 0x3f, 0x93, 0xba, 0xc7, 0xfc, 0x5a, 0x80,
- 0x6f, 0x31, 0xae, 0x8b, 0x71, 0x49, 0x01, 0x3e, 0xfc, 0x07, 0x78, 0x45,
- 0xca, 0xf3, 0x55, 0xf4, 0xaf, 0x1e, 0x87, 0xad, 0x06, 0x64, 0x53, 0x8c,
- 0xb1, 0x3d, 0x73, 0xed, 0x7c, 0x7d, 0xde, 0xcc, 0x7b, 0x4a, 0xdf, 0x10,
- 0x4d, 0x6e, 0x0c, 0xd1, 0xb3, 0xbd, 0x21, 0x1a, 0x3f, 0xcd, 0x32, 0xe0,
- 0xa6, 0xaa, 0x27, 0x22, 0xc6, 0xa8, 0xa7, 0xfc, 0x50, 0x36, 0x74, 0x5e,
- 0x27, 0xbe, 0x6f, 0x10, 0x2d, 0xf7, 0x78, 0x0e, 0xb3, 0x4f, 0xa7, 0x4e,
- 0x87, 0x7e, 0x4a, 0x74, 0xa8, 0xc7, 0xb2, 0x5b, 0xbe, 0x83, 0x5e, 0x01,
- 0x9d, 0x82, 0x38, 0x0f, 0x19, 0x1e, 0xf2, 0xdd, 0x7a, 0x88, 0xfc, 0x15,
- 0xe1, 0x37, 0x87, 0x9c, 0xc6, 0xeb, 0x9f, 0x42, 0xfc, 0x31, 0x8f, 0xdf,
- 0xc4, 0xda, 0x0b, 0xb4, 0xe2, 0xcf, 0x63, 0x0c, 0xef, 0xf1, 0x61, 0x7c,
- 0x1f, 0x46, 0x1e, 0xc8, 0xf2, 0x84, 0xe0, 0x3c, 0xb1, 0x1b, 0x71, 0x30,
- 0x00, 0xee, 0xdf, 0x63, 0x6e, 0xcf, 0x13, 0x18, 0x57, 0xda, 0x83, 0xbc,
- 0x70, 0x3f, 0xfa, 0x59, 0xd7, 0x28, 0xda, 0x01, 0xbc, 0xef, 0xc1, 0xd8,
- 0xfe, 0x1c, 0x91, 0xcb, 0xdd, 0x2d, 0x3f, 0x20, 0x26, 0x56, 0x11, 0x2b,
- 0x6b, 0x9c, 0x27, 0x38, 0x16, 0x79, 0x4f, 0x8b, 0xe0, 0x6f, 0x1b, 0x3a,
- 0x78, 0x6f, 0x8b, 0xd8, 0x43, 0xce, 0x71, 0x82, 0x2a, 0x1b, 0x3b, 0xe5,
- 0x0f, 0x5e, 0x0f, 0x38, 0xec, 0x34, 0xaf, 0xc5, 0x15, 0x0d, 0xf0, 0x59,
- 0xb8, 0x31, 0x8d, 0xef, 0xc8, 0x85, 0x22, 0xb2, 0x1b, 0xa7, 0x53, 0x2e,
- 0x6b, 0x6c, 0x8c, 0x29, 0x9c, 0xc6, 0x89, 0xc0, 0x3b, 0x73, 0x59, 0xce,
- 0x5d, 0x8c, 0x25, 0x0a, 0x20, 0xbb, 0x19, 0x1a, 0x52, 0x2e, 0xf9, 0x23,
- 0xd4, 0x00, 0x2e, 0x03, 0xf0, 0x59, 0x03, 0x7c, 0x56, 0xef, 0xe3, 0xb3,
- 0xfa, 0xe7, 0xf2, 0x19, 0xb8, 0xaa, 0x03, 0xae, 0xea, 0x80, 0xab, 0x50,
- 0x1b, 0xbc, 0x03, 0xec, 0xbf, 0xdd, 0xd9, 0x89, 0xe3, 0x98, 0xdf, 0x98,
- 0xe7, 0xa6, 0xe8, 0xf2, 0xde, 0xff, 0x94, 0xe7, 0x8e, 0x83, 0x13, 0x6c,
- 0xfa, 0xfe, 0xde, 0x7b, 0x73, 0xdd, 0x09, 0x70, 0x9d, 0xf5, 0xf9, 0x5c,
- 0xd7, 0x64, 0xae, 0x33, 0x81, 0xbd, 0x26, 0x78, 0x40, 0x5f, 0xed, 0x9f,
- 0xe7, 0x24, 0xe6, 0xe1, 0x3e, 0x33, 0xcb, 0xa5, 0x3a, 0x75, 0x81, 0x7b,
- 0xc3, 0xe3, 0x79, 0x60, 0x73, 0x92, 0x72, 0xd1, 0x13, 0x66, 0x89, 0xac,
- 0x49, 0xe0, 0x61, 0x75, 0x88, 0x8c, 0xd3, 0xb7, 0xf0, 0x8e, 0x7a, 0x00,
- 0x71, 0x8e, 0x7f, 0x1b, 0xb9, 0x8e, 0x41, 0x70, 0x8d, 0x49, 0x85, 0x55,
- 0x0b, 0xef, 0xda, 0xb6, 0x71, 0x87, 0x90, 0x6f, 0x8c, 0x9a, 0x3b, 0xf3,
- 0x7b, 0x7e, 0xee, 0xf1, 0x98, 0x41, 0xd2, 0xd7, 0x5c, 0xc7, 0xd1, 0x5d,
- 0xff, 0x1a, 0xb8, 0xe1, 0x7d, 0x8f, 0xf9, 0x2f, 0x06, 0x0a, 0x0a, 0x64,
- 0xae, 0xca, 0xe3, 0x56, 0x8d, 0xe7, 0x6e, 0x3a, 0x88, 0x73, 0xe7, 0x35,
- 0xe0, 0x87, 0x73, 0xe7, 0xf9, 0x2a, 0xd7, 0x7b, 0x69, 0x8c, 0xb6, 0x7a,
- 0xf9, 0x9c, 0xa3, 0xb0, 0xdb, 0x82, 0x4c, 0xff, 0x58, 0xc6, 0x8b, 0x94,
- 0xcf, 0x62, 0x4d, 0x06, 0xe6, 0xb1, 0xd6, 0x6c, 0x2a, 0xac, 0xb1, 0x5f,
- 0x5c, 0xc8, 0x57, 0xc4, 0x1c, 0x6d, 0x6e, 0xe3, 0x83, 0x93, 0xbd, 0x0f,
- 0x4c, 0xe6, 0x50, 0x03, 0xb1, 0x59, 0xc4, 0xbc, 0xd6, 0x96, 0x2e, 0xca,
- 0x74, 0xb1, 0xbc, 0x57, 0x7e, 0x76, 0x4b, 0x9e, 0x79, 0x6d, 0xa2, 0xcc,
- 0xfc, 0xc5, 0x76, 0x18, 0x8a, 0x4b, 0x07, 0x33, 0x2e, 0xad, 0x60, 0x3f,
- 0x07, 0x55, 0x5c, 0xea, 0xde, 0xc3, 0x19, 0x9f, 0xee, 0x46, 0xcb, 0x7d,
- 0x37, 0xb2, 0x38, 0x31, 0x61, 0x2f, 0xeb, 0x1d, 0x24, 0x03, 0x76, 0x45,
- 0x6a, 0x4d, 0x7f, 0x93, 0x4b, 0x1e, 0x73, 0x04, 0xe3, 0x53, 0x71, 0x29,
- 0xfa, 0x27, 0x60, 0x33, 0xf3, 0x02, 0xcb, 0xb1, 0xfc, 0x4e, 0x72, 0x7f,
- 0x85, 0x9c, 0xd8, 0x41, 0x0e, 0x7d, 0x1b, 0x2c, 0xc3, 0xdc, 0x30, 0x8a,
- 0xf1, 0x21, 0xf3, 0x02, 0x7c, 0xc6, 0xb2, 0xe5, 0x2c, 0x0e, 0x23, 0x7c,
- 0xe3, 0xba, 0x97, 0xe3, 0x23, 0x20, 0xab, 0xc6, 0xeb, 0xe0, 0x9a, 0x98,
- 0xf3, 0x22, 0xd7, 0xa1, 0x5c, 0x6f, 0xe6, 0xf5, 0xa9, 0x37, 0x35, 0x7b,
- 0xb7, 0x5a, 0x53, 0xf4, 0xd7, 0x9a, 0xe8, 0xd8, 0xb1, 0xd6, 0xf4, 0xac,
- 0xb4, 0xd6, 0xac, 0x58, 0x77, 0xaf, 0x35, 0x73, 0xd9, 0x7b, 0xd7, 0x9a,
- 0x71, 0x87, 0xf7, 0x08, 0xb9, 0x54, 0xf0, 0x5a, 0xa8, 0x69, 0x66, 0x7c,
- 0x11, 0xdd, 0xc6, 0x17, 0xd1, 0x69, 0xb7, 0x7c, 0x8e, 0x38, 0xa6, 0xdd,
- 0x72, 0x8b, 0x6b, 0xa0, 0x0d, 0xae, 0x81, 0x0c, 0xe4, 0xd2, 0x7e, 0xce,
- 0xc8, 0x7d, 0xc2, 0xbe, 0x1c, 0x04, 0x27, 0xb3, 0x1f, 0x8b, 0x19, 0x3f,
- 0xa0, 0xf5, 0x3e, 0x05, 0x3f, 0xe4, 0xbc, 0xc2, 0x3e, 0xfb, 0x7f, 0xe2,
- 0x15, 0xb2, 0x07, 0xc0, 0x0f, 0x36, 0xea, 0xcd, 0x46, 0x47, 0xd9, 0x02,
- 0x5f, 0x48, 0x39, 0xe7, 0x33, 0xf6, 0x53, 0xbe, 0x50, 0x3e, 0x51, 0x78,
- 0x2c, 0xd2, 0xbb, 0x3e, 0x63, 0x01, 0xe7, 0x23, 0x8f, 0x73, 0x22, 0xf3,
- 0xef, 0x4d, 0xf9, 0xae, 0x17, 0xa2, 0x2f, 0xc2, 0x9e, 0x33, 0x0e, 0xe6,
- 0xb5, 0x43, 0xeb, 0x36, 0xe4, 0x18, 0x0b, 0xe5, 0x3b, 0xce, 0x3d, 0xe9,
- 0xf9, 0x84, 0x6b, 0xe1, 0xff, 0x16, 0x1b, 0x17, 0xef, 0x82, 0x8d, 0x37,
- 0x33, 0x6c, 0xfc, 0xf2, 0x1e, 0xd8, 0xb8, 0xf8, 0x05, 0xb1, 0xe1, 0x3a,
- 0x1f, 0xa3, 0x5e, 0x7a, 0xcf, 0x63, 0x7c, 0x48, 0xf9, 0xb1, 0xbf, 0x53,
- 0x3e, 0x09, 0x6c, 0xe3, 0xd5, 0x9b, 0x32, 0xce, 0x72, 0x89, 0xfe, 0xd6,
- 0xad, 0x5c, 0x32, 0xfe, 0x6a, 0x8a, 0x8b, 0xf1, 0xb7, 0xa4, 0x3c, 0xb7,
- 0x03, 0x0e, 0xb8, 0x56, 0xbe, 0x0a, 0x1e, 0x68, 0xd1, 0xff, 0xa2, 0x56,
- 0x66, 0xce, 0xae, 0xda, 0x47, 0xdb, 0xf9, 0xbe, 0xe7, 0x7b, 0x5e, 0xa0,
- 0xb3, 0x62, 0x17, 0xfc, 0xb5, 0x9f, 0x5a, 0xaf, 0x9b, 0x7c, 0x7e, 0x00,
- 0x1e, 0x1e, 0x37, 0x39, 0x56, 0x71, 0x56, 0xc4, 0x73, 0x7f, 0x3d, 0x0d,
- 0x3c, 0xfa, 0xbc, 0x76, 0xb5, 0xee, 0x3e, 0xae, 0xff, 0x1e, 0x4a, 0x92,
- 0x3b, 0xf2, 0xc8, 0xb6, 0x73, 0xb3, 0x81, 0x73, 0x73, 0x5d, 0xe9, 0xe0,
- 0xb3, 0x55, 0xea, 0xbf, 0x13, 0xea, 0xac, 0x7c, 0x53, 0x9e, 0x53, 0xe7,
- 0xe5, 0xd1, 0x02, 0x0d, 0xce, 0x67, 0x58, 0x61, 0x5f, 0x0c, 0xab, 0x7a,
- 0x82, 0x31, 0xd5, 0x42, 0xbe, 0x5d, 0x82, 0x3f, 0x1a, 0x2a, 0x16, 0xb0,
- 0xf6, 0xcc, 0x1f, 0x2d, 0xf8, 0xa3, 0x9e, 0xa4, 0x31, 0xf1, 0xe5, 0x9e,
- 0x1d, 0xfe, 0x88, 0x7c, 0x6a, 0x2f, 0x9a, 0x38, 0x6f, 0x5f, 0x49, 0x54,
- 0xfe, 0x5c, 0x68, 0xb5, 0xa9, 0xf9, 0x60, 0xed, 0x38, 0xd7, 0x6d, 0x5c,
- 0x77, 0xcd, 0x2c, 0x55, 0xd1, 0xd7, 0xb3, 0x29, 0x84, 0x4f, 0xbe, 0x7d,
- 0x90, 0x16, 0x8d, 0x1a, 0xe3, 0x17, 0xef, 0x09, 0x35, 0xc3, 0x83, 0xa8,
- 0xa5, 0x92, 0xb1, 0x45, 0xbd, 0x36, 0x06, 0x1c, 0x35, 0x29, 0x80, 0x9d,
- 0x01, 0x74, 0xcf, 0xb5, 0x6d, 0x7b, 0xb9, 0xcd, 0x67, 0xa4, 0x26, 0xf1,
- 0x19, 0xbc, 0xdb, 0xbb, 0x0e, 0x7d, 0x03, 0xcf, 0xe0, 0xcc, 0xea, 0xc4,
- 0xc0, 0xd5, 0xcb, 0x89, 0x45, 0xad, 0x12, 0xdf, 0x51, 0x30, 0x57, 0x96,
- 0xa1, 0xe3, 0x99, 0x42, 0x8a, 0xcb, 0x32, 0xf4, 0x70, 0xcc, 0x10, 0xe6,
- 0x63, 0xff, 0xe5, 0x58, 0x2b, 0xf7, 0xd5, 0xee, 0x85, 0xec, 0xbc, 0x4a,
- 0xca, 0x07, 0xec, 0xdf, 0xd0, 0x7b, 0xbe, 0x90, 0xdf, 0xc7, 0xb4, 0x10,
- 0xf3, 0x8d, 0x7d, 0x8c, 0x43, 0x0d, 0x78, 0xc3, 0x98, 0x84, 0xfb, 0x90,
- 0x57, 0xf6, 0x21, 0x37, 0x97, 0x8a, 0xaa, 0x6d, 0x26, 0xc7, 0xb2, 0xf1,
- 0xba, 0x1a, 0xc7, 0x39, 0x21, 0x4e, 0xd4, 0x59, 0x41, 0x8b, 0x3a, 0xe4,
- 0x34, 0x7c, 0x9c, 0x81, 0x50, 0x5b, 0xac, 0x24, 0x9c, 0xcf, 0xf7, 0xd9,
- 0xba, 0xe2, 0xb9, 0x4d, 0xc8, 0xe0, 0x79, 0x83, 0xf4, 0x86, 0xcf, 0xf7,
- 0x07, 0xd9, 0xdd, 0x46, 0x89, 0x86, 0x21, 0x0f, 0xbb, 0xc6, 0xd8, 0xae,
- 0xa0, 0xa1, 0x6a, 0x11, 0xd6, 0xbd, 0x5f, 0x4f, 0xef, 0x5c, 0x7e, 0x93,
- 0xcd, 0x65, 0x83, 0x5f, 0x08, 0xe7, 0x1d, 0x9f, 0xf3, 0xda, 0xd7, 0x0c,
- 0xba, 0x4e, 0x8a, 0x23, 0xc5, 0x37, 0x90, 0xef, 0x0e, 0x42, 0x26, 0x50,
- 0xfc, 0x92, 0x9e, 0x19, 0x72, 0x99, 0x8a, 0xb1, 0x5d, 0xc7, 0x77, 0xcc,
- 0xed, 0xef, 0x01, 0x62, 0xab, 0x9a, 0xcd, 0xd7, 0x8f, 0xd3, 0x4d, 0xe0,
- 0x74, 0xb3, 0xb0, 0x75, 0xee, 0x28, 0x15, 0x30, 0x8e, 0x6d, 0x64, 0x2e,
- 0x61, 0x99, 0x4f, 0xac, 0xed, 0x7a, 0x2a, 0x3b, 0xe8, 0xf8, 0x53, 0x9f,
- 0x8e, 0x12, 0xaf, 0x4d, 0x34, 0xd2, 0xf3, 0xb3, 0xfa, 0x6b, 0xc0, 0xcf,
- 0x38, 0x6f, 0x3c, 0xa0, 0x63, 0x1d, 0x5c, 0x7f, 0xd5, 0x55, 0x3f, 0x0e,
- 0x56, 0xdb, 0xf4, 0xfe, 0x30, 0x9b, 0x67, 0x5f, 0x1a, 0x0f, 0x1e, 0xda,
- 0x64, 0xb3, 0xcf, 0x76, 0x6b, 0x87, 0x79, 0x91, 0xd8, 0xbd, 0x19, 0x8d,
- 0xf1, 0x66, 0xd4, 0x38, 0x07, 0xe3, 0x79, 0x0b, 0x1f, 0x8c, 0xd5, 0xcf,
- 0xc7, 0xa8, 0xf5, 0x05, 0x31, 0xfa, 0x46, 0x9b, 0xb9, 0x22, 0xc5, 0x68,
- 0xe3, 0x0e, 0x8c, 0xa2, 0x06, 0x2a, 0xe5, 0xf8, 0xe4, 0x78, 0xc9, 0xf1,
- 0x99, 0x3f, 0xf3, 0xfd, 0x08, 0x38, 0x38, 0xe3, 0xb6, 0x18, 0xdc, 0x16,
- 0xa9, 0x1c, 0xe7, 0x96, 0x23, 0x4a, 0xe3, 0x78, 0x19, 0x71, 0x1c, 0x19,
- 0x9c, 0xf3, 0x38, 0x86, 0x59, 0x8e, 0xe3, 0x98, 0xe5, 0x46, 0x32, 0x39,
- 0xb4, 0x88, 0xe7, 0x28, 0x8b, 0xe7, 0x16, 0x78, 0x37, 0xca, 0xe2, 0xb9,
- 0x85, 0x18, 0x5e, 0xc9, 0xe2, 0xb9, 0x95, 0xc5, 0x33, 0xdf, 0xdb, 0x19,
- 0x55, 0x95, 0x8b, 0x9d, 0x3a, 0x78, 0x6d, 0x45, 0xe9, 0x6c, 0x62, 0x9d,
- 0xb0, 0xb1, 0x93, 0xc7, 0xc5, 0x1d, 0xf7, 0x5b, 0x58, 0xcf, 0xad, 0xbc,
- 0x32, 0x8b, 0xbc, 0x72, 0x0e, 0x79, 0xa5, 0xdb, 0x77, 0xbf, 0x75, 0x56,
- 0xe5, 0x95, 0x27, 0x8b, 0x79, 0x5e, 0xe9, 0x66, 0x79, 0xa5, 0xab, 0xf2,
- 0xca, 0x13, 0x45, 0xce, 0x2b, 0x31, 0x05, 0xc5, 0xfe, 0xbc, 0x12, 0x6f,
- 0xcb, 0x2b, 0xb9, 0x2c, 0xf7, 0xef, 0x94, 0x57, 0x72, 0x9f, 0x71, 0x6e,
- 0xb1, 0x72, 0x5e, 0xbd, 0x2d, 0x9f, 0xe4, 0x63, 0xd8, 0x56, 0xe6, 0x25,
- 0xe6, 0xe0, 0xb4, 0xae, 0xbf, 0x92, 0xe4, 0xb1, 0x74, 0x0c, 0xf3, 0xe0,
- 0xbd, 0xb3, 0x53, 0x2c, 0xd9, 0x59, 0x2c, 0x0d, 0xa7, 0x32, 0x9d, 0xfe,
- 0x78, 0x3a, 0x56, 0xdc, 0x1e, 0x4f, 0xb9, 0x9e, 0x3c, 0x9e, 0x52, 0x9d,
- 0x1f, 0x1a, 0x65, 0xae, 0x07, 0x70, 0x96, 0x76, 0xfd, 0x39, 0xf4, 0x5e,
- 0xe8, 0x4d, 0xa3, 0xae, 0x36, 0xe9, 0x6a, 0xce, 0x37, 0xea, 0xbe, 0x07,
- 0x6d, 0x2f, 0xb7, 0xb5, 0xb8, 0xf5, 0xad, 0x8b, 0xda, 0xfa, 0x7d, 0xf0,
- 0xc8, 0x79, 0xf5, 0xfd, 0x33, 0x79, 0xb5, 0x84, 0x33, 0xb0, 0x97, 0x8f,
- 0x7b, 0x1d, 0xf3, 0xb9, 0xe2, 0x2c, 0x9e, 0x5e, 0xee, 0xdd, 0x82, 0xf9,
- 0x8a, 0xc7, 0x7d, 0xff, 0x44, 0x0e, 0x41, 0x5d, 0xbe, 0x35, 0x96, 0xcf,
- 0x38, 0x1e, 0xd6, 0xec, 0xd0, 0xa5, 0x6d, 0xe7, 0x9c, 0xf4, 0x7c, 0x83,
- 0x75, 0xa3, 0x3e, 0xe1, 0x3a, 0x25, 0xfc, 0x8a, 0x4e, 0x2f, 0xd1, 0xb7,
- 0x7c, 0xee, 0xd3, 0x69, 0xf6, 0x31, 0x29, 0x5f, 0x40, 0xcd, 0xf2, 0xf4,
- 0xb6, 0x9a, 0xa5, 0x48, 0xe3, 0x07, 0xfa, 0xcf, 0x87, 0x37, 0xe5, 0xf8,
- 0xa4, 0x7b, 0x36, 0xa0, 0x40, 0x9b, 0x5d, 0xe7, 0x5a, 0x76, 0xab, 0x76,
- 0x25, 0x1a, 0xbd, 0x21, 0xf5, 0x49, 0xce, 0x85, 0x57, 0x33, 0x5f, 0xe1,
- 0xdb, 0x99, 0x1b, 0xe0, 0xd6, 0x48, 0xdd, 0xf1, 0x06, 0xeb, 0x3c, 0x0f,
- 0xbf, 0xa3, 0x4d, 0xb8, 0xbe, 0xb9, 0xdb, 0xbd, 0xab, 0x89, 0x7d, 0x71,
- 0x9d, 0xa3, 0x06, 0xa9, 0xbb, 0x8b, 0x25, 0xdf, 0xfd, 0x59, 0x8b, 0x52,
- 0x9e, 0x88, 0xfc, 0x05, 0xd8, 0x02, 0x9c, 0x8b, 0x45, 0xec, 0xcd, 0x24,
- 0x78, 0xc9, 0x75, 0x0e, 0xe8, 0x42, 0x61, 0x7f, 0x19, 0xba, 0x8d, 0x03,
- 0x5c, 0x3f, 0x7e, 0x2a, 0x97, 0x7b, 0x2a, 0x07, 0xfb, 0x8c, 0x91, 0x7a,
- 0xb2, 0x5b, 0xe7, 0x36, 0x48, 0xf8, 0xb9, 0x80, 0x79, 0x9c, 0xbb, 0xe0,
- 0xa7, 0x24, 0xa2, 0x33, 0x8e, 0x98, 0xed, 0x38, 0x62, 0xae, 0xa3, 0x03,
- 0xdd, 0xb6, 0x4d, 0xbb, 0xb0, 0x27, 0xc8, 0xc1, 0xf4, 0x00, 0x6c, 0xb9,
- 0xe0, 0x88, 0x3a, 0x6a, 0xc1, 0x1f, 0x18, 0xae, 0x78, 0x9a, 0x3e, 0xc1,
- 0x1a, 0x6f, 0xc8, 0xf4, 0xde, 0xc5, 0x11, 0xd1, 0xd6, 0xdc, 0x37, 0x30,
- 0x37, 0xdb, 0xc4, 0x31, 0xca, 0xf9, 0x72, 0x5e, 0x5b, 0x80, 0x8f, 0x8e,
- 0xac, 0x6b, 0xe0, 0x35, 0xce, 0x97, 0x23, 0xd9, 0xfd, 0x12, 0xf6, 0x07,
- 0xeb, 0xbf, 0x74, 0x47, 0xad, 0x99, 0xd7, 0x94, 0xe9, 0xdd, 0x69, 0x3c,
- 0xc3, 0xf3, 0x13, 0x6c, 0x99, 0x98, 0xba, 0xa0, 0xce, 0x3d, 0xd3, 0xa8,
- 0xf1, 0xb8, 0x95, 0xa8, 0x83, 0xf8, 0xae, 0x8b, 0x6b, 0x27, 0x89, 0xf8,
- 0x4f, 0x9f, 0x63, 0x3e, 0x13, 0xcd, 0xb0, 0x0e, 0x3e, 0x1b, 0x71, 0xfc,
- 0xfc, 0x1b, 0x2f, 0xf3, 0x0a, 0xbd, 0x68, 0x18, 0x00, 0x00, 0x00 };
+ 0xcd, 0x58, 0x5d, 0x6c, 0x1c, 0x57, 0x15, 0x3e, 0xf3, 0xb7, 0x3b, 0xde,
+ 0x38, 0xf1, 0x24, 0x19, 0xca, 0xa6, 0x72, 0xe9, 0x8c, 0x3d, 0x76, 0x8c,
+ 0x6c, 0x35, 0xd3, 0x76, 0xd5, 0x58, 0x68, 0xa4, 0x4e, 0x67, 0x76, 0x1d,
+ 0x2b, 0xf4, 0xc1, 0x85, 0x48, 0x3c, 0xf0, 0xe2, 0xae, 0x1d, 0x05, 0x78,
+ 0x2a, 0x28, 0x0f, 0x11, 0x2f, 0x59, 0x76, 0x37, 0xfd, 0x41, 0xdb, 0x2c,
+ 0x35, 0xc8, 0x41, 0x02, 0xa4, 0xb0, 0x69, 0xe2, 0x97, 0xad, 0x27, 0x2d,
+ 0x45, 0xea, 0x4b, 0x95, 0x28, 0x55, 0x2b, 0xc4, 0x13, 0x2f, 0x54, 0x79,
+ 0xac, 0x52, 0x5a, 0xf1, 0x00, 0x28, 0x42, 0x15, 0xaa, 0x68, 0xf0, 0xe5,
+ 0x3b, 0x77, 0x66, 0xdc, 0xdd, 0xc4, 0x49, 0xcb, 0x9f, 0x84, 0xa5, 0xf5,
+ 0x9d, 0xb9, 0xf7, 0x9e, 0x73, 0xcf, 0x3d, 0x3f, 0xdf, 0x39, 0x67, 0xca,
+ 0x2a, 0x95, 0x28, 0xfb, 0xdb, 0x8d, 0xdf, 0xc9, 0xa7, 0x9f, 0x39, 0x79,
+ 0xf8, 0xa1, 0x47, 0x1d, 0xa2, 0x87, 0x1f, 0x52, 0x94, 0xa2, 0x46, 0xff,
+ 0x85, 0x3f, 0x30, 0xb1, 0x72, 0xfe, 0xfc, 0x23, 0x53, 0x0d, 0x7e, 0xe3,
+ 0x44, 0x1e, 0x99, 0x5a, 0xb0, 0xf4, 0xe5, 0x15, 0x8f, 0x28, 0xec, 0xcf,
+ 0x3a, 0x31, 0xfd, 0x43, 0x34, 0x6c, 0x9d, 0x78, 0xfe, 0x81, 0xe0, 0xd6,
+ 0xa1, 0x37, 0x0f, 0xbb, 0x37, 0xcf, 0x6b, 0x64, 0x5a, 0xc1, 0xb2, 0x69,
+ 0x4d, 0x93, 0x39, 0x1e, 0x5c, 0x75, 0x7e, 0x7e, 0x30, 0x28, 0xd0, 0x9e,
+ 0x9c, 0x97, 0x4d, 0xcd, 0x2e, 0x35, 0xf4, 0xc0, 0xa4, 0x5a, 0xe7, 0x94,
+ 0x12, 0x75, 0x3d, 0xab, 0x0a, 0x1e, 0xa1, 0x0d, 0xfe, 0x1e, 0xde, 0x13,
+ 0x5d, 0xa9, 0x9e, 0x33, 0x49, 0x0d, 0x42, 0x3c, 0xcf, 0x51, 0xab, 0x2b,
+ 0xc4, 0x0f, 0x7d, 0x85, 0x56, 0x7c, 0x93, 0x96, 0x2d, 0x77, 0x31, 0x54,
+ 0xb6, 0x44, 0x3c, 0x25, 0xc4, 0xb7, 0x7d, 0x95, 0x54, 0x6f, 0x41, 0x89,
+ 0x36, 0x16, 0x95, 0x78, 0x63, 0x91, 0xf5, 0x01, 0xf9, 0x16, 0x94, 0x70,
+ 0x83, 0xc7, 0xc0, 0x8c, 0x3b, 0x7b, 0x68, 0xd9, 0xa6, 0x31, 0xd5, 0x9b,
+ 0xc3, 0x79, 0x65, 0xf0, 0x71, 0x28, 0xf2, 0x67, 0x2d, 0x95, 0x26, 0xf1,
+ 0x1b, 0xa1, 0x9a, 0x4f, 0x23, 0xaa, 0xa7, 0x52, 0xdd, 0x56, 0xe8, 0xe5,
+ 0x8a, 0x81, 0xdf, 0x51, 0xa5, 0xba, 0xf1, 0x9d, 0x8c, 0x0f, 0xef, 0x37,
+ 0xb1, 0xc6, 0x32, 0x33, 0xfd, 0x20, 0xed, 0x6e, 0x3c, 0x7f, 0x0b, 0xfb,
+ 0x0c, 0x8a, 0x2a, 0xb7, 0xaf, 0x8d, 0xe0, 0x59, 0xc1, 0xfc, 0x51, 0xc8,
+ 0xc5, 0x7c, 0x1c, 0xc8, 0x31, 0x4e, 0xed, 0xee, 0x22, 0xee, 0x53, 0xa0,
+ 0x86, 0x35, 0x35, 0x53, 0x27, 0x1d, 0x34, 0x1a, 0x85, 0xf6, 0x15, 0xa1,
+ 0x06, 0x42, 0x44, 0x15, 0x6f, 0xa6, 0x27, 0xcf, 0x50, 0x49, 0xf3, 0x0a,
+ 0x54, 0xf5, 0x77, 0x53, 0xcb, 0xd2, 0xa8, 0x39, 0x67, 0x50, 0xb8, 0xa4,
+ 0xe3, 0x8e, 0xfb, 0x40, 0xa7, 0x80, 0xfe, 0xa5, 0xcc, 0xe6, 0x45, 0x6a,
+ 0x5a, 0x05, 0xcc, 0x8f, 0x51, 0xd3, 0xde, 0xab, 0xa8, 0xc1, 0x0b, 0x98,
+ 0x9f, 0xb2, 0x7a, 0xf4, 0x3c, 0x46, 0x05, 0xef, 0x7b, 0xb1, 0x97, 0xdf,
+ 0x15, 0xf0, 0x23, 0x2b, 0x4a, 0x66, 0xa8, 0x95, 0xe4, 0xb4, 0x3c, 0x9f,
+ 0xce, 0x35, 0x92, 0xdb, 0xed, 0x8d, 0x7d, 0xdd, 0x1a, 0x74, 0xcc, 0xb6,
+ 0xc1, 0x9e, 0xdc, 0x2e, 0xd2, 0x07, 0x1e, 0xe7, 0x79, 0xfe, 0xc3, 0xbc,
+ 0x43, 0x5a, 0xe0, 0x59, 0x31, 0x7d, 0x85, 0xd2, 0xb5, 0x54, 0xf6, 0xc8,
+ 0x7f, 0x2c, 0x7b, 0xb7, 0xad, 0xe8, 0xdc, 0xa3, 0xb8, 0x9f, 0x74, 0x19,
+ 0x3c, 0xdb, 0xb8, 0x7f, 0x01, 0xfe, 0xd1, 0x0c, 0x55, 0x6a, 0x94, 0x4d,
+ 0x72, 0xe7, 0x57, 0xb1, 0xf2, 0x41, 0x47, 0xa3, 0x98, 0x75, 0xe5, 0xeb,
+ 0x19, 0x1d, 0xfb, 0xc6, 0xbb, 0x90, 0xb3, 0x61, 0x99, 0x70, 0xbc, 0xe5,
+ 0x63, 0x42, 0x5c, 0xf4, 0x85, 0x28, 0x04, 0xde, 0xcc, 0x25, 0x9a, 0x2d,
+ 0x1b, 0x34, 0x6d, 0x61, 0x84, 0x8e, 0xbd, 0x72, 0x9d, 0x8c, 0x5c, 0x9e,
+ 0xdc, 0x37, 0xf1, 0xd7, 0x57, 0x08, 0x3e, 0x79, 0xa3, 0xf3, 0x7b, 0xd6,
+ 0xc7, 0xcc, 0x82, 0xa4, 0x11, 0xa2, 0x37, 0x7f, 0x2f, 0x9a, 0x5f, 0x67,
+ 0x34, 0x42, 0xd4, 0x2a, 0x7c, 0xae, 0x8b, 0x3b, 0xb3, 0x7f, 0x13, 0xd5,
+ 0xfa, 0xbe, 0x59, 0xef, 0x40, 0x3e, 0x0f, 0x63, 0x9f, 0xa8, 0xde, 0xe5,
+ 0x7b, 0x98, 0xd4, 0x84, 0xde, 0x5a, 0xd8, 0xaf, 0x56, 0x76, 0xb1, 0x7f,
+ 0xc0, 0xc6, 0x4b, 0x66, 0xb5, 0xe3, 0x96, 0x5f, 0xa0, 0x25, 0x33, 0xee,
+ 0xcf, 0x96, 0x57, 0xe9, 0x01, 0x3e, 0xc7, 0x34, 0x82, 0x63, 0x66, 0x4f,
+ 0xd2, 0x1b, 0x1a, 0x95, 0xf0, 0x0c, 0x1e, 0xcd, 0x0e, 0x29, 0x91, 0xbf,
+ 0x8b, 0xef, 0x0b, 0xba, 0xc5, 0x8c, 0x6e, 0x31, 0xa3, 0x1b, 0xcb, 0xe8,
+ 0x9e, 0x1c, 0xa0, 0x7b, 0x92, 0xe9, 0xb0, 0x37, 0xcc, 0xf6, 0x86, 0xd9,
+ 0x5e, 0x3d, 0xdb, 0x5b, 0xcd, 0xf6, 0x62, 0xec, 0x3b, 0x90, 0xcf, 0x9d,
+ 0x09, 0x15, 0xc8, 0xe8, 0x89, 0x07, 0x23, 0x9f, 0xc2, 0xd8, 0x73, 0xaf,
+ 0xc7, 0xda, 0x18, 0x5d, 0xf0, 0x2d, 0x6a, 0x27, 0x0e, 0x64, 0x6f, 0x53,
+ 0x94, 0xa8, 0xa0, 0x1d, 0xa3, 0x9e, 0x77, 0x53, 0xd4, 0xfc, 0x0a, 0x6c,
+ 0x37, 0xca, 0x74, 0xe5, 0x1a, 0x14, 0xd1, 0x4c, 0x66, 0xad, 0x55, 0xaa,
+ 0xc0, 0x5f, 0x54, 0xd8, 0x6f, 0x52, 0x3e, 0x37, 0x93, 0x0a, 0xd6, 0xa9,
+ 0xa1, 0x56, 0x5c, 0xab, 0x49, 0x6e, 0x39, 0xd2, 0xc8, 0x52, 0x03, 0x1b,
+ 0x7b, 0x1a, 0x54, 0x4d, 0x4c, 0x7a, 0x4f, 0x3b, 0x25, 0xe3, 0xb4, 0xd9,
+ 0xbd, 0x2e, 0xde, 0x3c, 0xe8, 0xd0, 0x95, 0x64, 0x9c, 0x7e, 0x95, 0x94,
+ 0xe9, 0xb5, 0xc4, 0xa6, 0x57, 0x13, 0x52, 0x23, 0x1f, 0x7e, 0x6c, 0x5b,
+ 0x74, 0x39, 0x19, 0xd4, 0xfb, 0x07, 0xac, 0x77, 0x73, 0x7f, 0x40, 0xe6,
+ 0xbe, 0x80, 0x1a, 0x5a, 0x90, 0xe2, 0x40, 0x9c, 0xe2, 0x80, 0xf4, 0xa9,
+ 0x56, 0xb7, 0x79, 0xbf, 0x06, 0x0c, 0x5a, 0xf1, 0xc3, 0xbd, 0x1a, 0xec,
+ 0x12, 0x23, 0x0a, 0xd4, 0xed, 0x51, 0xda, 0xc8, 0x5d, 0xf1, 0xdc, 0xe7,
+ 0x63, 0xec, 0xf6, 0xce, 0x1a, 0x98, 0xbd, 0xdd, 0xb6, 0x7f, 0xc6, 0x19,
+ 0xa3, 0xb0, 0x9b, 0x46, 0x4f, 0xe8, 0x88, 0x1f, 0xef, 0x23, 0x8d, 0x63,
+ 0xc0, 0xd9, 0xb4, 0xe9, 0x4c, 0x97, 0x68, 0x62, 0xd3, 0xa4, 0x8d, 0x4e,
+ 0x91, 0x9c, 0xde, 0x28, 0xad, 0x74, 0x4b, 0x34, 0x79, 0x49, 0xc7, 0xde,
+ 0x5d, 0x34, 0xb9, 0xa6, 0xda, 0x1c, 0xcb, 0x31, 0x74, 0x3c, 0xd1, 0x13,
+ 0xf0, 0xd1, 0x12, 0x4d, 0xac, 0xbb, 0xd2, 0x7f, 0x56, 0xbc, 0x96, 0xaf,
+ 0xd1, 0x0f, 0xe8, 0xda, 0x5c, 0x01, 0x77, 0xb2, 0xc9, 0x9f, 0x1e, 0x3c,
+ 0xcf, 0x80, 0x9b, 0xf1, 0x1c, 0x98, 0xee, 0x71, 0x1d, 0x52, 0x99, 0x9f,
+ 0x49, 0x13, 0x97, 0x4c, 0x25, 0xee, 0xb2, 0xce, 0xd8, 0x07, 0xcd, 0xcc,
+ 0x07, 0x75, 0x25, 0x3a, 0x57, 0xc4, 0x59, 0x7f, 0x12, 0x91, 0x07, 0xdf,
+ 0x03, 0x96, 0xad, 0x54, 0xbe, 0x0f, 0xf9, 0x30, 0xd7, 0xe3, 0xb5, 0x9b,
+ 0xd9, 0x3c, 0xf3, 0x00, 0x46, 0xf8, 0xfb, 0x29, 0x62, 0x3c, 0x38, 0xc6,
+ 0x34, 0x45, 0x9a, 0x58, 0x63, 0x8c, 0xc1, 0xd8, 0xe3, 0x77, 0xbe, 0xdb,
+ 0x08, 0xd5, 0xa1, 0x95, 0xfa, 0x8c, 0x0d, 0xb9, 0x54, 0x89, 0x19, 0x75,
+ 0x60, 0x88, 0xea, 0x95, 0x30, 0xf2, 0x79, 0x3f, 0xd3, 0xd2, 0xf8, 0xb7,
+ 0xa5, 0xbd, 0x63, 0xf8, 0xaf, 0x0e, 0x79, 0x56, 0x69, 0xaa, 0x7c, 0x5c,
+ 0xae, 0x61, 0xae, 0xcf, 0x6b, 0xd6, 0x6d, 0x6b, 0x78, 0xef, 0xe7, 0x32,
+ 0x20, 0xc6, 0xbd, 0x16, 0x4e, 0x31, 0x32, 0xbd, 0xf0, 0xfe, 0x46, 0x19,
+ 0xb6, 0x01, 0xa6, 0x11, 0x74, 0x49, 0xd4, 0xeb, 0xe8, 0xc0, 0x1c, 0xf5,
+ 0x8b, 0x2a, 0xd3, 0xd9, 0xcc, 0x07, 0xf7, 0x5f, 0xd7, 0x95, 0xf8, 0x9c,
+ 0xe7, 0xfc, 0x81, 0x98, 0x7e, 0x12, 0x3a, 0x98, 0x9a, 0x6f, 0xf1, 0xfe,
+ 0xbe, 0x41, 0xde, 0x5a, 0xc3, 0xd2, 0x61, 0x53, 0x15, 0x06, 0x8d, 0x7f,
+ 0x34, 0x06, 0x5b, 0xbb, 0x4e, 0x8b, 0x7e, 0x07, 0x79, 0x0a, 0xe4, 0xf5,
+ 0x74, 0x7a, 0xb9, 0xc3, 0xba, 0x30, 0x69, 0x72, 0x5d, 0x88, 0xe7, 0x7c,
+ 0xb6, 0xc9, 0xbb, 0xd0, 0x0b, 0xe1, 0x86, 0x53, 0xf3, 0x37, 0x60, 0x9f,
+ 0x8d, 0x3e, 0xdb, 0xc6, 0x90, 0x3a, 0xf1, 0xd6, 0xe6, 0x60, 0xd7, 0x99,
+ 0x4c, 0x46, 0xb6, 0x97, 0x4e, 0xed, 0x8a, 0x4a, 0x17, 0x2b, 0x9f, 0x08,
+ 0xd5, 0x63, 0x8c, 0x2d, 0x40, 0xb7, 0xd8, 0xd7, 0xc3, 0xbe, 0xa4, 0x00,
+ 0x1d, 0xfe, 0x4d, 0x18, 0xc0, 0xdf, 0x8b, 0x15, 0xcc, 0xaf, 0x9d, 0x86,
+ 0xac, 0x1a, 0x68, 0x53, 0x1f, 0x63, 0x79, 0x16, 0x3a, 0xf9, 0xfd, 0xbc,
+ 0xf9, 0xb7, 0x25, 0xbf, 0x51, 0x9a, 0xde, 0x1c, 0xa5, 0x13, 0xfd, 0x51,
+ 0x9a, 0x38, 0xcb, 0x34, 0x42, 0xb4, 0x2b, 0x8c, 0x91, 0xf0, 0x51, 0x4f,
+ 0xea, 0xa1, 0xac, 0xa9, 0x7c, 0x4f, 0xac, 0x6f, 0x12, 0xad, 0xf6, 0xf9,
+ 0x0c, 0x7d, 0x80, 0xa7, 0x4a, 0x47, 0x7e, 0x42, 0x74, 0xa4, 0xcf, 0xb4,
+ 0xdb, 0xba, 0x03, 0x5f, 0x0b, 0x3c, 0x2d, 0xe2, 0x5c, 0xa4, 0x79, 0xc8,
+ 0x79, 0x1b, 0x11, 0x72, 0x58, 0x15, 0xbf, 0x05, 0xe4, 0x35, 0xbe, 0xff,
+ 0x1c, 0xe2, 0x8f, 0xb1, 0x7c, 0x0b, 0x77, 0x2f, 0x50, 0xdb, 0x5f, 0xc4,
+ 0x1e, 0xb6, 0xf1, 0x51, 0xac, 0xef, 0x46, 0x2e, 0xc8, 0x72, 0x85, 0xc5,
+ 0xb9, 0x62, 0x2f, 0xe2, 0x60, 0x04, 0xf8, 0x7f, 0xbf, 0x3e, 0x9c, 0x2b,
+ 0xb0, 0xcf, 0x3e, 0x80, 0xdc, 0x80, 0x44, 0x5d, 0x62, 0x5e, 0xfb, 0x31,
+ 0x8e, 0xe0, 0xfd, 0x00, 0xf6, 0x0e, 0xe6, 0x89, 0x9c, 0xee, 0x6e, 0x39,
+ 0x02, 0x31, 0xb1, 0x86, 0x58, 0x59, 0x9f, 0x61, 0xcc, 0x80, 0x3d, 0xd8,
+ 0xa6, 0x45, 0x60, 0xb8, 0x09, 0x1e, 0x6c, 0xdb, 0x22, 0x6c, 0xc8, 0x79,
+ 0xce, 0xa2, 0xc9, 0x4d, 0x8e, 0xeb, 0x34, 0x8f, 0xc4, 0xdb, 0x79, 0x84,
+ 0x64, 0x4c, 0x34, 0x13, 0xf6, 0x89, 0xd0, 0x8c, 0xce, 0x6e, 0x09, 0xc4,
+ 0x70, 0x39, 0x66, 0x5c, 0xdb, 0x9c, 0x05, 0xbd, 0x86, 0xf8, 0xa8, 0x9a,
+ 0xf5, 0xb3, 0x29, 0xa6, 0xd5, 0x37, 0x1d, 0xe9, 0x93, 0xcd, 0xc4, 0xc2,
+ 0x3b, 0x63, 0x5a, 0x8e, 0x61, 0x4c, 0x4f, 0x61, 0x04, 0x7c, 0x8b, 0x34,
+ 0x21, 0x56, 0xfc, 0x31, 0xaa, 0xc3, 0x3f, 0x43, 0xe0, 0x5a, 0x1d, 0xb8,
+ 0x16, 0x0f, 0xe0, 0x5a, 0xfc, 0x99, 0xb8, 0x06, 0xcc, 0xea, 0x02, 0xb3,
+ 0x50, 0x23, 0xbc, 0x06, 0x8c, 0x7f, 0x15, 0xe7, 0x5d, 0xee, 0xee, 0x84,
+ 0x75, 0x8c, 0x73, 0x8c, 0x77, 0x33, 0xf4, 0xe6, 0xc1, 0x7f, 0x15, 0xef,
+ 0xda, 0xc0, 0x06, 0x93, 0xbe, 0x7b, 0xf0, 0xde, 0x98, 0x77, 0x06, 0x98,
+ 0x67, 0x7c, 0x36, 0xe6, 0x35, 0x18, 0xf3, 0x74, 0xf8, 0x60, 0x03, 0x78,
+ 0xa0, 0xae, 0x0d, 0x9e, 0xd3, 0xc1, 0x39, 0x3c, 0xa7, 0x67, 0x79, 0x55,
+ 0xa5, 0x1e, 0xfc, 0x5f, 0xf3, 0xf8, 0x9c, 0x39, 0xd6, 0xbb, 0xd4, 0xff,
+ 0x13, 0xba, 0x4d, 0xc6, 0x34, 0xfc, 0x62, 0x6d, 0x94, 0xb4, 0xb3, 0x9f,
+ 0xfa, 0x3d, 0x6a, 0x03, 0xc4, 0x3b, 0xfe, 0x6d, 0xe6, 0x3c, 0x4a, 0xc0,
+ 0x1c, 0x9d, 0x0a, 0x6b, 0x06, 0xde, 0x95, 0xa1, 0x7d, 0x47, 0x90, 0x77,
+ 0xb4, 0xc0, 0x9d, 0x7f, 0x9f, 0x9f, 0xfb, 0xbc, 0xa7, 0x44, 0xea, 0xba,
+ 0xeb, 0x38, 0xaa, 0xeb, 0x5f, 0x03, 0x46, 0xbc, 0xe3, 0x31, 0x0e, 0x36,
+ 0xe1, 0x0d, 0x05, 0xd2, 0xd7, 0xc4, 0x69, 0x23, 0xe0, 0xb3, 0x1b, 0x0e,
+ 0xe2, 0xdd, 0x79, 0x09, 0x7e, 0xc4, 0x39, 0xf4, 0x22, 0xe2, 0xa7, 0x96,
+ 0xc5, 0x6a, 0xab, 0x9f, 0x9f, 0xb9, 0x0f, 0x72, 0x1b, 0xa0, 0x19, 0xdc,
+ 0xcb, 0x71, 0x20, 0xc4, 0x09, 0xdc, 0x49, 0xc3, 0x39, 0xc6, 0xba, 0x49,
+ 0x85, 0x75, 0xd6, 0x8b, 0x0b, 0xfa, 0x49, 0x6b, 0x81, 0xae, 0x0f, 0xe1,
+ 0xc2, 0x73, 0xfd, 0xeb, 0x3a, 0x63, 0xa9, 0x86, 0x18, 0x2d, 0xe2, 0x5c,
+ 0x63, 0x9b, 0x17, 0x65, 0xbc, 0x98, 0xde, 0x2b, 0x9f, 0xd8, 0xa6, 0x67,
+ 0x7c, 0x9b, 0x2a, 0x33, 0x8e, 0xb1, 0x1c, 0x9a, 0xc4, 0xd4, 0x52, 0x86,
+ 0xa9, 0x93, 0xb0, 0x67, 0x49, 0xc6, 0xa7, 0xea, 0x3d, 0x98, 0xe1, 0xea,
+ 0x5e, 0x8c, 0x3c, 0x27, 0xb2, 0x78, 0xd1, 0x21, 0x2f, 0xf3, 0x2d, 0x91,
+ 0xb6, 0xce, 0x35, 0x04, 0xdf, 0xe9, 0xaf, 0xf0, 0x6d, 0xc6, 0x0a, 0xf6,
+ 0x4f, 0x89, 0xa9, 0x98, 0x9f, 0x82, 0xcc, 0x8c, 0x0f, 0x4c, 0xc7, 0xf4,
+ 0x3b, 0xd1, 0xfd, 0x05, 0x74, 0xd6, 0x0e, 0x74, 0x98, 0xdb, 0x64, 0x1a,
+ 0xc6, 0x88, 0x7d, 0xd8, 0x1f, 0x31, 0x3e, 0x40, 0x67, 0x4c, 0x3b, 0x9e,
+ 0xc5, 0x63, 0x15, 0x6b, 0x5c, 0x03, 0xcb, 0xf8, 0x22, 0x23, 0xe0, 0x7b,
+ 0x70, 0x7d, 0xcc, 0xf9, 0x91, 0x6b, 0x52, 0xae, 0x3d, 0xf3, 0x5a, 0xd5,
+ 0x9b, 0xa9, 0xdd, 0xad, 0xee, 0xb4, 0x06, 0xeb, 0xce, 0x43, 0xc6, 0xce,
+ 0x75, 0xe7, 0x41, 0x23, 0xad, 0x3b, 0xa7, 0x8d, 0xbb, 0xd7, 0x9d, 0x39,
+ 0xed, 0xbd, 0xeb, 0xce, 0x66, 0x97, 0xcf, 0xdc, 0x19, 0x2f, 0x56, 0xe0,
+ 0xaf, 0xad, 0x24, 0xbf, 0x27, 0xf7, 0x06, 0xa1, 0x59, 0x3b, 0x9b, 0xda,
+ 0xbe, 0x29, 0x7d, 0x11, 0x38, 0xb2, 0x39, 0x0b, 0x3b, 0xa2, 0xa6, 0x1e,
+ 0xc2, 0x8e, 0x9c, 0x86, 0x75, 0x5a, 0x02, 0x46, 0xb3, 0x3e, 0x8b, 0x19,
+ 0x4e, 0x60, 0xf4, 0x3e, 0x06, 0x4e, 0xe4, 0xf8, 0xc2, 0xfc, 0xfe, 0x9f,
+ 0xf0, 0x85, 0xcc, 0x11, 0xe0, 0x84, 0x19, 0x30, 0x5e, 0x4a, 0x59, 0x50,
+ 0x93, 0x0b, 0xb1, 0xe0, 0x73, 0x0c, 0x0c, 0xf6, 0x4c, 0xec, 0x0f, 0x45,
+ 0x7a, 0xcb, 0x67, 0x9f, 0x40, 0xcf, 0xe4, 0x71, 0x8e, 0x64, 0x3c, 0xde,
+ 0x12, 0x6f, 0x79, 0x11, 0xe6, 0xaa, 0xb0, 0x3d, 0xfb, 0xc3, 0xa2, 0x72,
+ 0x64, 0xc3, 0x04, 0x1d, 0xfb, 0xc4, 0xf8, 0x1d, 0xbd, 0x50, 0xda, 0xb3,
+ 0x70, 0x7d, 0xfc, 0xef, 0xfa, 0xc8, 0x1b, 0x77, 0xf1, 0x91, 0xcb, 0x99,
+ 0x8f, 0x24, 0xf7, 0xf0, 0x91, 0x37, 0x3e, 0xa7, 0x8f, 0xb8, 0xe5, 0x0f,
+ 0x51, 0x3f, 0xbd, 0x0d, 0x39, 0x42, 0x4b, 0x88, 0x0f, 0xfd, 0x9d, 0xfa,
+ 0x94, 0xd0, 0xd4, 0x5f, 0x64, 0x9d, 0xa5, 0x79, 0xa5, 0x85, 0x77, 0xed,
+ 0x15, 0xae, 0x97, 0x39, 0xe7, 0xa4, 0xb9, 0x65, 0xe2, 0xc5, 0xd4, 0x3f,
+ 0x26, 0x5e, 0x11, 0xe2, 0xc2, 0x0e, 0xfe, 0xc0, 0x35, 0xf4, 0x55, 0xf8,
+ 0x55, 0x8b, 0xfe, 0x17, 0x35, 0x34, 0x63, 0x78, 0xc5, 0x3c, 0xde, 0xc9,
+ 0xed, 0x9f, 0xdb, 0xbe, 0x40, 0xe7, 0xad, 0x3d, 0xd0, 0xdb, 0xa3, 0xd4,
+ 0xfa, 0xb1, 0xce, 0x7d, 0x05, 0xfc, 0xe2, 0x71, 0x9d, 0x63, 0x17, 0x7d,
+ 0x24, 0x9e, 0x07, 0xeb, 0x6c, 0xf8, 0xa5, 0x5f, 0xc8, 0xe3, 0x65, 0x00,
+ 0xfb, 0x4f, 0xa1, 0x54, 0xb9, 0x23, 0xaf, 0x0c, 0xf5, 0xd4, 0x1a, 0x7a,
+ 0xea, 0x58, 0xf2, 0xe0, 0xbe, 0x2b, 0xd5, 0x63, 0x5b, 0xf6, 0xd1, 0x5b,
+ 0xa2, 0x25, 0x7b, 0xe9, 0x03, 0x05, 0x2a, 0x2d, 0x66, 0x3e, 0xe3, 0x20,
+ 0x1f, 0xb9, 0x7e, 0x03, 0xfc, 0xb9, 0xd6, 0x80, 0x1c, 0xb4, 0x8a, 0x58,
+ 0xbc, 0x80, 0x3c, 0xbc, 0x02, 0xbd, 0xd4, 0x65, 0x6c, 0x8c, 0xd1, 0x35,
+ 0xe4, 0xfe, 0x36, 0xf2, 0xf3, 0x19, 0xe8, 0xa6, 0x05, 0xdd, 0xc4, 0x49,
+ 0x1a, 0x27, 0xd7, 0xa0, 0x9b, 0x85, 0x01, 0xdd, 0x2c, 0xfc, 0x47, 0xfd,
+ 0xc5, 0x1f, 0x91, 0x6b, 0xcd, 0x65, 0x1d, 0xf3, 0x57, 0x12, 0x99, 0x5b,
+ 0x97, 0x5a, 0x1d, 0x6a, 0xdc, 0x1f, 0x9c, 0xe6, 0xda, 0x8e, 0x6b, 0xb3,
+ 0xf9, 0x95, 0x0a, 0xe6, 0xfa, 0x26, 0x45, 0xd0, 0xcf, 0x37, 0x0f, 0xd3,
+ 0xb2, 0x16, 0xb0, 0x4f, 0xe3, 0x3d, 0xa1, 0x46, 0x74, 0x18, 0xf5, 0x56,
+ 0x32, 0xbe, 0x8c, 0x7e, 0x1c, 0xbe, 0xd5, 0xa0, 0x10, 0x72, 0x86, 0xe0,
+ 0xbd, 0xd0, 0x31, 0xcd, 0xd5, 0x0e, 0xf7, 0x51, 0x0d, 0xe2, 0x5e, 0xbd,
+ 0xd7, 0xbf, 0x09, 0x7e, 0x23, 0xdf, 0x40, 0x7f, 0xeb, 0x34, 0x81, 0xd3,
+ 0xcf, 0xc2, 0x6d, 0x5b, 0x36, 0x7f, 0xcb, 0x60, 0x1c, 0x1d, 0x07, 0x8f,
+ 0xa7, 0x0b, 0xa9, 0xaf, 0x8e, 0x83, 0x0f, 0xc7, 0x11, 0xe1, 0x3c, 0xd6,
+ 0x65, 0xee, 0x7f, 0xe5, 0x81, 0xfa, 0xbe, 0x40, 0x39, 0x86, 0x35, 0xa1,
+ 0x37, 0xd6, 0x75, 0xe4, 0x9d, 0x2c, 0xe4, 0xdf, 0x6d, 0x5a, 0xc0, 0x81,
+ 0xfa, 0x1c, 0x63, 0x96, 0x02, 0xdf, 0xa3, 0xb4, 0xaf, 0x44, 0x1f, 0x52,
+ 0x9f, 0x43, 0xde, 0xb6, 0x8b, 0x72, 0x6c, 0x24, 0xa7, 0xb3, 0xfd, 0xaa,
+ 0xdc, 0xc7, 0xf9, 0xa2, 0x99, 0xc8, 0x7e, 0x42, 0xa9, 0x76, 0xc9, 0xa9,
+ 0xfb, 0xe8, 0x93, 0x50, 0x7b, 0xb4, 0x13, 0xce, 0xf5, 0x73, 0xa6, 0x2a,
+ 0xb1, 0xef, 0x06, 0x68, 0xf0, 0xbc, 0x49, 0x6a, 0xdd, 0xe7, 0xef, 0x0c,
+ 0xfc, 0x0d, 0x04, 0xf1, 0x63, 0xd3, 0x6e, 0xd0, 0x43, 0xae, 0x71, 0x96,
+ 0x2b, 0xac, 0xcb, 0x3a, 0x85, 0x79, 0x1f, 0x52, 0xd3, 0x6f, 0x33, 0xef,
+ 0x66, 0x67, 0x99, 0x88, 0x1f, 0xc6, 0x5d, 0x9f, 0x73, 0xde, 0x97, 0x34,
+ 0xba, 0x49, 0x12, 0x37, 0xad, 0x87, 0x91, 0x0b, 0x0f, 0x83, 0x26, 0x94,
+ 0x98, 0x93, 0xf6, 0x15, 0x39, 0x8d, 0xa7, 0x0d, 0xf3, 0x58, 0xd6, 0x87,
+ 0xdf, 0x43, 0xc4, 0x59, 0x25, 0x3b, 0x6f, 0xd0, 0x67, 0xdf, 0x87, 0xcf,
+ 0xde, 0xc8, 0xf6, 0x00, 0x87, 0xed, 0x02, 0xf6, 0xb1, 0x8c, 0x8c, 0x2f,
+ 0x4c, 0xb3, 0x65, 0x0c, 0xf3, 0x99, 0xdc, 0x81, 0xc7, 0x47, 0x03, 0x3c,
+ 0x6c, 0xbe, 0x9b, 0x55, 0x4f, 0x7b, 0x6c, 0xf9, 0x57, 0x87, 0x9e, 0xd1,
+ 0x93, 0xdc, 0xa7, 0xe2, 0x1e, 0x5c, 0x9b, 0xc5, 0x72, 0xfe, 0x97, 0xc5,
+ 0x61, 0xbe, 0xa7, 0xb2, 0x73, 0xfc, 0x34, 0x36, 0x3c, 0x8c, 0xc9, 0x8d,
+ 0x01, 0xd9, 0x8d, 0x1d, 0xce, 0xdd, 0xa5, 0xa3, 0x35, 0x50, 0xd8, 0xdf,
+ 0xb4, 0x80, 0xf3, 0x33, 0x9e, 0xb7, 0xfd, 0x83, 0x7d, 0xf5, 0xb3, 0x7d,
+ 0xd4, 0xf8, 0x9c, 0x3e, 0xfa, 0x72, 0x87, 0x71, 0x23, 0xf5, 0xd1, 0xfa,
+ 0x1d, 0x3e, 0x8a, 0xfa, 0xc8, 0xce, 0xfd, 0x93, 0xe3, 0x25, 0xf7, 0xcf,
+ 0xfc, 0x99, 0x63, 0x1c, 0xb8, 0x9c, 0xe1, 0x5c, 0x13, 0x38, 0x57, 0x95,
+ 0x79, 0xcf, 0x2d, 0x57, 0x29, 0x8d, 0xe5, 0x55, 0xc4, 0x72, 0x55, 0xe3,
+ 0x3c, 0xc8, 0x31, 0xcc, 0x74, 0x1c, 0xc7, 0x4c, 0x37, 0x96, 0xd1, 0x61,
+ 0x44, 0x3c, 0x57, 0xb3, 0x78, 0x6e, 0x75, 0x5d, 0xa7, 0x9a, 0xc5, 0x73,
+ 0x0b, 0x31, 0xdc, 0xce, 0xe2, 0xb9, 0x95, 0xc5, 0x33, 0x7f, 0xdf, 0xd3,
+ 0x2a, 0x9c, 0x1b, 0x5d, 0x27, 0x06, 0xc6, 0xb5, 0x25, 0xcf, 0x06, 0xee,
+ 0x09, 0x19, 0xbb, 0x79, 0x5c, 0xdc, 0xf1, 0x1d, 0x0c, 0xf7, 0xf9, 0x34,
+ 0xd7, 0xd4, 0x90, 0x6b, 0x2e, 0x20, 0xd7, 0xf4, 0x06, 0xbe, 0x83, 0x9d,
+ 0x97, 0xb9, 0xe6, 0xeb, 0xc5, 0x3c, 0xd7, 0xf4, 0xb2, 0x5c, 0xd3, 0x93,
+ 0xb9, 0xe6, 0xab, 0x45, 0xce, 0x35, 0x4d, 0x3a, 0x5a, 0x1c, 0xcc, 0x35,
+ 0xcd, 0xa1, 0x5c, 0x93, 0xd3, 0xf2, 0xfc, 0x4e, 0xb9, 0x26, 0xd7, 0xd9,
+ 0xbd, 0x6a, 0x92, 0x7c, 0x0f, 0xcb, 0xca, 0xb8, 0xc4, 0x78, 0x9c, 0xd6,
+ 0xfc, 0x57, 0x92, 0x3c, 0x96, 0x4e, 0xe3, 0x1c, 0xbc, 0x77, 0x77, 0x8a,
+ 0x25, 0x33, 0x8b, 0xa5, 0xdd, 0x29, 0x4d, 0x77, 0x30, 0x9e, 0x4e, 0x17,
+ 0x87, 0xe3, 0x29, 0xe7, 0x93, 0xc7, 0x53, 0xca, 0xf3, 0x3d, 0xad, 0xcc,
+ 0x35, 0x02, 0xfa, 0x6d, 0xd7, 0x5f, 0xc0, 0xec, 0xa5, 0xfe, 0x2c, 0x6a,
+ 0x6e, 0x9d, 0xae, 0xe6, 0x78, 0x23, 0xbf, 0x09, 0x61, 0xec, 0xe7, 0xb2,
+ 0x16, 0xb7, 0xd7, 0x7a, 0xa8, 0xbb, 0xdf, 0x01, 0x8e, 0x5c, 0x94, 0xeb,
+ 0x9f, 0x88, 0xab, 0x68, 0x09, 0xdb, 0x5e, 0xbe, 0xef, 0x17, 0x38, 0xcf,
+ 0xb5, 0xce, 0xe3, 0xe9, 0xd9, 0x7e, 0xae, 0x13, 0x5e, 0xe7, 0xb9, 0xbf,
+ 0x23, 0x9f, 0xa0, 0x66, 0xdf, 0xde, 0xcb, 0xfd, 0x8f, 0x87, 0x3b, 0x3b,
+ 0xf4, 0xfa, 0x50, 0x0f, 0x94, 0xf6, 0x3e, 0x75, 0xf9, 0x8d, 0x97, 0x6b,
+ 0x97, 0xe8, 0x0b, 0x2a, 0x9d, 0xa2, 0xaf, 0xf9, 0x3c, 0xa7, 0x52, 0xed,
+ 0x31, 0x21, 0x9e, 0x41, 0x1d, 0xf3, 0xd4, 0x50, 0x1d, 0x53, 0xa4, 0x89,
+ 0x47, 0x06, 0x7b, 0xc8, 0x2d, 0x31, 0x31, 0xed, 0x9e, 0x0f, 0x29, 0x54,
+ 0x6a, 0x1b, 0x5c, 0xe7, 0x6e, 0xd7, 0xb5, 0x44, 0xfb, 0x6e, 0x09, 0x75,
+ 0x9a, 0xf3, 0xe2, 0x6f, 0x33, 0x5d, 0x61, 0xed, 0xdc, 0x2d, 0x60, 0x6b,
+ 0x55, 0x7e, 0x0b, 0x0e, 0x37, 0xf8, 0x1c, 0x7e, 0xc7, 0x98, 0x70, 0xcd,
+ 0x73, 0xb7, 0xef, 0xb3, 0x3a, 0xec, 0xe2, 0x3a, 0xc7, 0x35, 0x92, 0xdf,
+ 0x37, 0x56, 0x7c, 0xf7, 0xa7, 0x2d, 0x4a, 0x71, 0xa2, 0xea, 0x2f, 0x41,
+ 0x16, 0xd4, 0x9d, 0xd6, 0x32, 0x6c, 0x33, 0x0d, 0x5c, 0x72, 0x9d, 0x47,
+ 0x54, 0x5b, 0xe2, 0xf8, 0x2a, 0x78, 0x6b, 0x8f, 0x70, 0x4d, 0xf9, 0xb1,
+ 0x58, 0xed, 0xcb, 0x7c, 0xec, 0xb3, 0x8f, 0xc4, 0xc9, 0x5e, 0x95, 0xc7,
+ 0x30, 0xe1, 0xe7, 0x02, 0x71, 0x2d, 0xb9, 0xb3, 0xff, 0xd8, 0x56, 0xf5,
+ 0x9c, 0x63, 0xd5, 0xba, 0x8e, 0xb5, 0xd0, 0x55, 0xe1, 0xdd, 0xfb, 0x4c,
+ 0xda, 0x03, 0x9b, 0x20, 0x1f, 0xd3, 0x7d, 0x90, 0xe5, 0x92, 0x63, 0xc5,
+ 0xa8, 0x0f, 0xbf, 0xa7, 0xb9, 0xd6, 0x53, 0xa4, 0x98, 0x54, 0xba, 0x25,
+ 0xd2, 0x6f, 0x33, 0x8e, 0x55, 0xdd, 0x3e, 0xfb, 0x16, 0xce, 0x66, 0x99,
+ 0x38, 0x46, 0x39, 0x5f, 0x2e, 0x2a, 0x4b, 0xd0, 0xd1, 0xb1, 0x8d, 0x5d,
+ 0xc0, 0x35, 0xce, 0x97, 0x07, 0xb2, 0x6f, 0x50, 0xb0, 0x0f, 0xee, 0xff,
+ 0xfa, 0x1d, 0xf5, 0x67, 0x5e, 0x67, 0x32, 0xbd, 0x10, 0xcd, 0x79, 0x3e,
+ 0x9f, 0x20, 0xcb, 0xd4, 0xcc, 0x25, 0xd9, 0x13, 0xcd, 0xa2, 0xee, 0xe3,
+ 0x51, 0xa0, 0x26, 0xe2, 0xef, 0x61, 0xae, 0x55, 0xc7, 0x73, 0x35, 0x7b,
+ 0x6e, 0x72, 0xbf, 0x34, 0xcf, 0x3c, 0xb8, 0x6f, 0xe2, 0xf8, 0xf9, 0x27,
+ 0x6e, 0xb7, 0x92, 0x82, 0x90, 0x18, 0x00, 0x00, 0x00 };
static const u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 };
static const u32 bnx2_TPAT_b09FwRodata[(0x0/4) + 1] = { 0x0 };
-static const u32 bnx2_TPAT_b09FwBss[(0x850/4) + 1] = { 0x0 };
-static const u32 bnx2_TPAT_b09FwSbss[(0x2c/4) + 1] = { 0x0 };
static struct fw_info bnx2_tpat_fw_09 = {
+ /* Firmware version: 3.7.1 */
.ver_major = 0x3,
- .ver_minor = 0x4,
- .ver_fix = 0x3,
+ .ver_minor = 0x7,
+ .ver_fix = 0x1,
.start_addr = 0x08000860,
.text_addr = 0x08000800,
- .text_len = 0x1864,
+ .text_len = 0x188c,
.text_index = 0x0,
.gz_text = bnx2_TPAT_b09FwText,
.gz_text_len = sizeof(bnx2_TPAT_b09FwText),
- .data_addr = 0x08002080,
+ .data_addr = 0x080020c0,
.data_len = 0x0,
.data_index = 0x0,
.data = bnx2_TPAT_b09FwData,
- .sbss_addr = 0x08002088,
- .sbss_len = 0x2c,
+ .sbss_addr = 0x080020c8,
+ .sbss_len = 0x30,
.sbss_index = 0x0,
- .sbss = bnx2_TPAT_b09FwSbss,
- .bss_addr = 0x080020c0,
+ .bss_addr = 0x08002100,
.bss_len = 0x850,
.bss_index = 0x0,
- .bss = bnx2_TPAT_b09FwBss,
.rodata_addr = 0x00000000,
.rodata_len = 0x0,
@@ -3279,767 +3289,770 @@ static struct fw_info bnx2_tpat_fw_09 = {
};
static u8 bnx2_TXP_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x7c,
- 0x6f, 0x70, 0x5b, 0xd7, 0x95, 0xdf, 0x79, 0xef, 0x81, 0x24, 0x48, 0xd1,
- 0xd4, 0x13, 0x17, 0x56, 0x60, 0x87, 0x71, 0x00, 0xf1, 0x81, 0x66, 0x42,
- 0xae, 0x04, 0x2b, 0x4c, 0xc2, 0x6d, 0xd1, 0xf8, 0x05, 0x00, 0x29, 0x48,
- 0xd1, 0x6c, 0x68, 0x95, 0x49, 0x94, 0x54, 0xe3, 0x62, 0x41, 0x52, 0xf1,
- 0xb6, 0xce, 0x54, 0x9b, 0x78, 0x5a, 0x4d, 0xeb, 0xad, 0x11, 0x90, 0xfa,
- 0xe7, 0x85, 0x04, 0xda, 0x62, 0x44, 0x7f, 0xc8, 0x07, 0x18, 0x80, 0x24,
- 0x6f, 0xf2, 0x44, 0x28, 0x9b, 0x7f, 0xfd, 0xd0, 0xac, 0x50, 0x4a, 0xd6,
- 0xba, 0x9b, 0xb4, 0xa3, 0xed, 0x66, 0x67, 0x3b, 0xd3, 0x2f, 0x1c, 0x49,
- 0xf6, 0x7a, 0x77, 0x67, 0x36, 0xda, 0x6e, 0xb6, 0xab, 0xb6, 0xb2, 0xd1,
- 0xdf, 0xef, 0xbe, 0xf7, 0x28, 0x90, 0xa6, 0x6c, 0xcb, 0xb3, 0xed, 0x94,
- 0x33, 0x18, 0xe0, 0xdd, 0x77, 0xdf, 0xb9, 0xe7, 0x9e, 0x73, 0xee, 0x39,
- 0xe7, 0x77, 0xee, 0x7d, 0x0c, 0x8b, 0x74, 0x89, 0xf7, 0xf7, 0x00, 0x3e,
- 0x91, 0x43, 0x87, 0x9f, 0xd9, 0x3e, 0xb2, 0xfd, 0x13, 0xf8, 0xf9, 0x09,
- 0x31, 0x02, 0x06, 0x6f, 0xbe, 0x69, 0x88, 0x64, 0xff, 0x42, 0x3e, 0xf0,
- 0x1f, 0x1e, 0x37, 0x7d, 0xfa, 0xfc, 0x48, 0x50, 0x4f, 0x4c, 0xec, 0x4a,
- 0x5a, 0x12, 0x34, 0x12, 0xb2, 0x6f, 0xca, 0x12, 0xb1, 0x9d, 0xa1, 0x48,
- 0x4a, 0xde, 0x6a, 0xe6, 0x43, 0x01, 0x61, 0xfb, 0x47, 0x12, 0x77, 0x9e,
- 0xfb, 0xc9, 0xa7, 0xa3, 0xb7, 0xca, 0x86, 0x04, 0xcd, 0x44, 0x56, 0xcc,
- 0x01, 0x09, 0xf6, 0xe1, 0x99, 0x6f, 0x3f, 0x6a, 0x18, 0xd2, 0xb3, 0xca,
- 0xab, 0xcc, 0x95, 0x56, 0x9a, 0x3f, 0x79, 0x34, 0x2c, 0xbf, 0x57, 0x0f,
- 0xc9, 0xf7, 0xea, 0xa6, 0x5c, 0xac, 0x07, 0xb4, 0xf1, 0x92, 0x29, 0xb3,
- 0xa5, 0x69, 0xfd, 0x48, 0x31, 0x2f, 0xa9, 0x7a, 0x56, 0x2f, 0x2c, 0x98,
- 0x3d, 0xc9, 0xf3, 0x39, 0x7d, 0x76, 0xa1, 0xb7, 0x27, 0x75, 0x7e, 0x5a,
- 0x2f, 0x14, 0xc3, 0x3d, 0xc9, 0xba, 0xd9, 0x93, 0x5a, 0x0c, 0xe1, 0xba,
- 0xb7, 0x27, 0xb9, 0x18, 0x9d, 0x17, 0xd9, 0x8a, 0x3e, 0xe1, 0x9e, 0x54,
- 0x29, 0x9a, 0x15, 0xe9, 0x8f, 0xbf, 0x2a, 0x7d, 0x3d, 0xa9, 0xfa, 0x3f,
- 0xd1, 0x1b, 0xa6, 0x26, 0x85, 0x5f, 0x15, 0x33, 0x9c, 0xb8, 0xd5, 0x7c,
- 0xc8, 0xd2, 0xc4, 0xb4, 0x6e, 0x37, 0xb7, 0x58, 0x41, 0xc9, 0x9d, 0xee,
- 0x14, 0x5b, 0xcd, 0xc9, 0x94, 0xdc, 0xe2, 0x90, 0xb9, 0x2c, 0x6d, 0x62,
- 0x87, 0xfc, 0xeb, 0x66, 0x33, 0x19, 0xff, 0x32, 0xe5, 0x8a, 0x71, 0xa4,
- 0x67, 0xbc, 0x2e, 0x92, 0x2c, 0x05, 0x25, 0x19, 0x7f, 0xab, 0xe9, 0x3e,
- 0x13, 0xc4, 0x98, 0x81, 0x9e, 0xb1, 0x52, 0xb3, 0x99, 0x8e, 0x83, 0x7e,
- 0xdc, 0x7f, 0xb6, 0x4d, 0xca, 0x21, 0xbb, 0x3c, 0x1b, 0xff, 0x6f, 0xba,
- 0xab, 0x13, 0xce, 0x91, 0xd7, 0xb6, 0xe8, 0x56, 0x5e, 0x72, 0x21, 0x29,
- 0x17, 0xe2, 0x9f, 0x92, 0x13, 0xf1, 0x30, 0xe6, 0x17, 0x94, 0x63, 0x71,
- 0xc8, 0xd1, 0x3a, 0xac, 0x25, 0xeb, 0xd1, 0x48, 0x56, 0x9e, 0x97, 0xe4,
- 0x62, 0xbf, 0x99, 0x16, 0x8c, 0x6d, 0x35, 0x3f, 0x9a, 0x8c, 0x63, 0xbc,
- 0xe1, 0xff, 0xd5, 0xb4, 0x43, 0xd1, 0x6c, 0x59, 0x06, 0xa5, 0x50, 0xea,
- 0x8f, 0xff, 0x4c, 0x34, 0x09, 0x5a, 0x62, 0x4f, 0x59, 0x26, 0xe4, 0x16,
- 0x1d, 0x4c, 0x19, 0x4d, 0xd9, 0x83, 0xf1, 0x93, 0x16, 0xee, 0xd7, 0x65,
- 0xb3, 0x6e, 0xb5, 0x4b, 0xc1, 0x94, 0x50, 0x97, 0x3c, 0x22, 0x85, 0xd3,
- 0x68, 0x8f, 0xdb, 0xbd, 0x3a, 0x9e, 0xc9, 0x8c, 0xb0, 0x4d, 0x34, 0x23,
- 0x11, 0x33, 0x53, 0xe0, 0xa8, 0xe2, 0x0c, 0x62, 0xfc, 0x98, 0xdd, 0xa9,
- 0x99, 0xb2, 0x62, 0x06, 0xa4, 0xea, 0xc4, 0xec, 0xb0, 0xd6, 0x2e, 0xc7,
- 0x62, 0x5d, 0x90, 0x69, 0x18, 0xb4, 0xe5, 0x9b, 0x7a, 0x22, 0x16, 0xce,
- 0x41, 0x51, 0x3a, 0x64, 0x35, 0x07, 0x7e, 0xe6, 0xe2, 0x59, 0x2d, 0x55,
- 0xff, 0x8a, 0x96, 0x3c, 0xbf, 0x5f, 0xdb, 0x75, 0x1e, 0x7d, 0xea, 0xe7,
- 0x3c, 0xbb, 0x0b, 0x83, 0x37, 0x1d, 0xcf, 0xb2, 0x1d, 0x3c, 0x2b, 0xde,
- 0xd1, 0x06, 0x5d, 0x36, 0x26, 0x43, 0x3d, 0x49, 0xa5, 0x4b, 0xf2, 0xa6,
- 0x4b, 0x6e, 0x42, 0x93, 0x5e, 0xcb, 0x96, 0xe0, 0x27, 0xa1, 0xcf, 0x45,
- 0xe8, 0x72, 0x31, 0x22, 0x47, 0x4a, 0x12, 0xd2, 0x85, 0x63, 0x65, 0xf5,
- 0xaa, 0x43, 0x7b, 0x80, 0x6e, 0xa1, 0xfb, 0x82, 0xc3, 0x67, 0xa1, 0xc3,
- 0x52, 0x1a, 0xf2, 0xc9, 0x60, 0xec, 0x7d, 0xda, 0x9e, 0xea, 0xa4, 0x96,
- 0x81, 0x9d, 0x14, 0x4e, 0x0f, 0x41, 0x77, 0xd1, 0xc8, 0x8a, 0x6c, 0x96,
- 0x82, 0x65, 0x45, 0xbe, 0x2c, 0xdd, 0x72, 0x6c, 0xd1, 0x92, 0x23, 0x8b,
- 0x21, 0xc9, 0x9b, 0x51, 0xb3, 0x26, 0x7d, 0xd9, 0x4d, 0x89, 0x1e, 0x79,
- 0xfe, 0x74, 0x34, 0x53, 0x96, 0x7e, 0xfb, 0x75, 0xdc, 0xcf, 0x9d, 0xa4,
- 0x4e, 0x25, 0x9f, 0x8a, 0x1b, 0x92, 0x85, 0x4d, 0x18, 0xd6, 0x1f, 0x81,
- 0xff, 0xe6, 0x73, 0xc9, 0x78, 0x34, 0x2c, 0xa2, 0x4b, 0xea, 0x0b, 0xfd,
- 0xe6, 0x6e, 0x89, 0x9a, 0x19, 0xca, 0x3f, 0x3e, 0x04, 0x3d, 0xfc, 0x77,
- 0xca, 0x1e, 0xb4, 0xa8, 0xe3, 0xa1, 0xf0, 0x31, 0xe8, 0x32, 0xab, 0x74,
- 0xdc, 0x83, 0xf1, 0x03, 0x9e, 0xed, 0xf4, 0x48, 0xbe, 0x7a, 0xc3, 0x93,
- 0x43, 0x8f, 0xcc, 0x57, 0xbb, 0xa5, 0x00, 0x1d, 0x16, 0xc4, 0x92, 0xc2,
- 0xf9, 0x3f, 0xf7, 0xda, 0x2d, 0x99, 0x3b, 0xff, 0x32, 0xec, 0xe1, 0xb0,
- 0xb6, 0xbf, 0xfe, 0x0b, 0xcd, 0xb3, 0x1f, 0xd8, 0x5f, 0x50, 0xec, 0x89,
- 0xa0, 0x9c, 0xab, 0xbb, 0xf6, 0x57, 0xc1, 0x1a, 0xb3, 0x4d, 0x1b, 0xb6,
- 0xf4, 0xc6, 0x6a, 0x9f, 0x73, 0xf5, 0x3e, 0x3c, 0x1b, 0x94, 0x23, 0x75,
- 0xf6, 0xcf, 0xc3, 0xc6, 0x82, 0xb2, 0xf4, 0x68, 0xb7, 0x64, 0xd1, 0x5e,
- 0x58, 0x14, 0x3b, 0x19, 0xd7, 0xf1, 0x4c, 0x0f, 0xe6, 0xb2, 0x15, 0x9f,
- 0x2e, 0x99, 0xaa, 0x76, 0xd8, 0x86, 0x15, 0x92, 0xa9, 0x3a, 0xf5, 0x8f,
- 0xef, 0x92, 0x6f, 0x03, 0x94, 0x2f, 0xdb, 0xf9, 0x1c, 0xdb, 0x4d, 0xb4,
- 0xb7, 0xb6, 0xd1, 0xb6, 0x37, 0x53, 0xa6, 0x83, 0x82, 0xb6, 0x5c, 0x29,
- 0x66, 0xee, 0xe7, 0x77, 0x9d, 0xf6, 0xd0, 0x6a, 0x0b, 0x01, 0xf4, 0x87,
- 0x1e, 0xab, 0x18, 0xeb, 0xf4, 0x9d, 0x66, 0xdb, 0x08, 0xae, 0x2d, 0x2c,
- 0xaa, 0x2e, 0x8e, 0x1d, 0x00, 0x5f, 0xba, 0x64, 0xab, 0x8a, 0xb7, 0x08,
- 0x6d, 0xc0, 0x9d, 0x47, 0x9f, 0xcc, 0x2e, 0x76, 0xf7, 0xa4, 0x17, 0xd9,
- 0x9e, 0x0c, 0x1b, 0x98, 0xe7, 0x54, 0x5c, 0x1a, 0x73, 0x71, 0xbd, 0x3f,
- 0x00, 0xbe, 0xa6, 0xb1, 0xe0, 0x30, 0x0f, 0x8f, 0xc7, 0x06, 0xee, 0xf7,
- 0xca, 0xd4, 0x79, 0xf6, 0xe5, 0x18, 0x85, 0x2d, 0xba, 0x24, 0xc0, 0x1b,
- 0x3e, 0x56, 0x14, 0xf7, 0x3b, 0x31, 0x4e, 0x37, 0x6c, 0x27, 0x83, 0x31,
- 0x9b, 0x8f, 0x27, 0xe3, 0xbd, 0x92, 0x5d, 0xed, 0x2b, 0xb0, 0x3b, 0xf6,
- 0x1f, 0x5c, 0xd7, 0x17, 0xf2, 0x3d, 0x0f, 0x9a, 0x8b, 0x9d, 0x90, 0x21,
- 0xdb, 0x75, 0xf0, 0xdc, 0x01, 0x1e, 0x82, 0x98, 0x4f, 0x3f, 0xd6, 0x43,
- 0x07, 0xe8, 0x6f, 0xc2, 0x9c, 0x3a, 0x65, 0xfa, 0x74, 0x2f, 0x74, 0x61,
- 0xa2, 0x6f, 0x50, 0x9e, 0x2f, 0x45, 0x61, 0x03, 0xec, 0x0f, 0x1d, 0x2c,
- 0x46, 0xc3, 0x55, 0xb1, 0x65, 0x2e, 0xde, 0x01, 0xfb, 0x6a, 0x36, 0x67,
- 0x60, 0x1f, 0xdf, 0x51, 0xfe, 0x62, 0xc8, 0x1c, 0xd3, 0x24, 0xdf, 0x91,
- 0x38, 0x0c, 0x7e, 0xa2, 0x4f, 0x89, 0xf0, 0x7a, 0x87, 0xc6, 0x35, 0x0b,
- 0x39, 0x72, 0x6c, 0xf8, 0xa4, 0xad, 0x90, 0x21, 0xfd, 0x56, 0x1f, 0xec,
- 0x39, 0xac, 0xfc, 0xc9, 0xd8, 0x86, 0xfe, 0x24, 0x3a, 0x51, 0xc6, 0x58,
- 0x85, 0xf3, 0x01, 0xfa, 0xb0, 0x51, 0x2c, 0x57, 0x79, 0x00, 0x6b, 0x6f,
- 0x56, 0xd9, 0xc7, 0x09, 0xce, 0xb7, 0xf9, 0xf9, 0x38, 0xf9, 0xe2, 0x7c,
- 0x6d, 0x3c, 0x4b, 0x1b, 0x8c, 0x1e, 0xb6, 0xd5, 0xf8, 0x27, 0xbc, 0xf1,
- 0x5d, 0xde, 0x0b, 0xa5, 0x1e, 0x2d, 0xa5, 0x78, 0xf0, 0xe9, 0x88, 0x2c,
- 0x9f, 0xec, 0x37, 0xf7, 0xc0, 0x86, 0xe9, 0xa7, 0x96, 0x2f, 0x50, 0xc7,
- 0xa0, 0x31, 0x42, 0x1d, 0x9b, 0x8a, 0xbf, 0xe4, 0x22, 0xd7, 0x9e, 0xf4,
- 0x19, 0x42, 0x1f, 0x01, 0x9f, 0x8b, 0xb5, 0x38, 0xeb, 0xad, 0xc5, 0x9c,
- 0x43, 0xfb, 0x7b, 0x06, 0xcf, 0xea, 0x32, 0x16, 0xa3, 0x7f, 0x78, 0x5e,
- 0x52, 0xf0, 0x91, 0xd0, 0xa3, 0x54, 0x31, 0x97, 0x4a, 0xa9, 0xd5, 0x6f,
- 0xc1, 0xb6, 0x86, 0xff, 0xae, 0xe9, 0xfa, 0x43, 0xfa, 0x06, 0xfa, 0x9a,
- 0x82, 0xa9, 0x43, 0x72, 0x3a, 0x9c, 0x21, 0x74, 0x13, 0x4f, 0x1a, 0xd1,
- 0x4c, 0x16, 0x7c, 0x4d, 0x59, 0x4d, 0xb1, 0x1e, 0x13, 0x44, 0x0c, 0xf4,
- 0xa9, 0xcb, 0x4e, 0xdf, 0x3f, 0x2d, 0x3b, 0xbe, 0x2e, 0xa8, 0x57, 0xea,
- 0xc1, 0xf7, 0x11, 0x01, 0xb9, 0x0c, 0xdf, 0x35, 0x57, 0xea, 0x96, 0x06,
- 0x78, 0xba, 0xe2, 0xf8, 0xb6, 0x66, 0x78, 0xb6, 0xc6, 0x67, 0xba, 0xf1,
- 0x7c, 0x00, 0x7e, 0x4d, 0xf2, 0x46, 0x02, 0xbf, 0x8b, 0xa4, 0xc9, 0x36,
- 0xdf, 0xce, 0xb9, 0x66, 0xa2, 0x76, 0x59, 0xda, 0x25, 0x13, 0x43, 0xfc,
- 0x58, 0xd4, 0x31, 0x56, 0x1f, 0x7c, 0x79, 0x40, 0x0e, 0x96, 0x42, 0xf2,
- 0xd5, 0x12, 0xe7, 0x95, 0xd6, 0x52, 0xd0, 0x5b, 0x72, 0xb1, 0x09, 0x9d,
- 0x8f, 0xc3, 0xe7, 0x65, 0xb4, 0x31, 0xf8, 0x9f, 0xdd, 0xd5, 0xaf, 0x68,
- 0xe9, 0xf3, 0x59, 0x6d, 0xbc, 0xbe, 0x5f, 0xcb, 0x9c, 0x9f, 0xd4, 0x76,
- 0xb5, 0xf8, 0x22, 0xd1, 0xde, 0xdd, 0x17, 0x9d, 0x38, 0xcd, 0x31, 0xfb,
- 0xe3, 0x1b, 0xfb, 0xa2, 0x5f, 0x6a, 0xad, 0xbe, 0xa8, 0x1f, 0xbe, 0x28,
- 0x03, 0x5f, 0x34, 0x7e, 0xdf, 0xbe, 0xa8, 0x5d, 0xdf, 0xd8, 0x17, 0x75,
- 0xeb, 0x77, 0x7d, 0x11, 0x63, 0xcf, 0xbf, 0xc6, 0xb5, 0x29, 0xdb, 0x76,
- 0xfa, 0x72, 0x0e, 0xc3, 0x0f, 0x6f, 0x82, 0xac, 0xbb, 0xb8, 0x76, 0x22,
- 0x05, 0xd8, 0xfd, 0x34, 0xc6, 0xfa, 0x4d, 0xd8, 0xfb, 0xb6, 0x98, 0x65,
- 0x3e, 0xa1, 0xc6, 0x7d, 0xa7, 0xce, 0xc7, 0x56, 0x75, 0x4e, 0x1e, 0xdf,
- 0x53, 0xe7, 0xb6, 0xab, 0x73, 0xea, 0xba, 0x53, 0x66, 0xd4, 0xb8, 0x4d,
- 0x09, 0x3c, 0x26, 0xf0, 0x2a, 0xf2, 0x59, 0x23, 0x11, 0x05, 0x3d, 0x1d,
- 0xe3, 0x53, 0x5f, 0x31, 0xf0, 0x20, 0xd0, 0x6f, 0xb7, 0xf2, 0x45, 0xbb,
- 0xa0, 0xf7, 0x65, 0xe7, 0xfe, 0x74, 0x95, 0x69, 0xd1, 0xd5, 0x9e, 0x35,
- 0xba, 0xea, 0x90, 0xe1, 0x98, 0xaf, 0xa3, 0xcd, 0x92, 0x8c, 0x51, 0x67,
- 0xf7, 0xa3, 0xab, 0x7f, 0xaa, 0xff, 0xfd, 0xe8, 0xea, 0xb7, 0xee, 0xa1,
- 0xab, 0x7f, 0xb5, 0x4e, 0x57, 0x96, 0xf9, 0x82, 0x46, 0xda, 0x8c, 0x1f,
- 0xf4, 0x47, 0xcd, 0x8f, 0x4e, 0x31, 0x7f, 0xa8, 0x73, 0x4d, 0xfb, 0x79,
- 0x07, 0xd7, 0xf3, 0xa5, 0xa6, 0x61, 0x59, 0x90, 0x1d, 0xd7, 0x34, 0xe5,
- 0x16, 0x35, 0x3f, 0x4f, 0xfe, 0x11, 0x3b, 0xa6, 0x10, 0x6b, 0x5c, 0x1e,
- 0xda, 0xa5, 0xbc, 0xc5, 0xed, 0x3f, 0x55, 0x6a, 0xfe, 0x42, 0x4f, 0xbc,
- 0xdd, 0x4c, 0x8e, 0x58, 0x5e, 0x1c, 0x08, 0xca, 0xd7, 0xaa, 0xd1, 0xac,
- 0xad, 0x75, 0x4b, 0xfe, 0x41, 0xc4, 0x9e, 0x12, 0xfd, 0xd7, 0xd6, 0x7b,
- 0xc4, 0xe8, 0x3e, 0x2f, 0x46, 0x57, 0xc1, 0x2b, 0xf3, 0xab, 0xef, 0xbe,
- 0xd5, 0x08, 0xf1, 0x3b, 0x66, 0xee, 0x93, 0x2f, 0x73, 0x8e, 0x88, 0xf7,
- 0x8c, 0xfb, 0x16, 0x73, 0x9e, 0x7c, 0x20, 0xd1, 0x25, 0xf9, 0x2d, 0x5c,
- 0x8f, 0xf4, 0x73, 0xf4, 0x5d, 0xed, 0x1e, 0xdf, 0x7e, 0x8e, 0xa4, 0x78,
- 0x33, 0x30, 0x65, 0xf4, 0x41, 0x3e, 0x54, 0xe2, 0x3c, 0xde, 0xf2, 0xec,
- 0x89, 0xb9, 0x82, 0xb4, 0xb9, 0xbe, 0x61, 0x2f, 0x72, 0x01, 0xda, 0x81,
- 0xaf, 0x73, 0xea, 0x9b, 0x39, 0x82, 0x44, 0x74, 0x8b, 0x39, 0x82, 0x98,
- 0x46, 0x62, 0x9f, 0x66, 0x43, 0xf7, 0x36, 0x74, 0x6f, 0x43, 0xf7, 0x36,
- 0x74, 0x9f, 0xac, 0x1f, 0xc6, 0x3d, 0x95, 0x87, 0x80, 0x17, 0x97, 0x7e,
- 0xda, 0xa5, 0x0f, 0x3e, 0xb7, 0x4a, 0x4e, 0xe9, 0x84, 0xf3, 0x45, 0xae,
- 0xa1, 0xfc, 0xf5, 0xb8, 0xe6, 0xfa, 0x6b, 0xd2, 0xcb, 0xe0, 0xf9, 0xdb,
- 0x98, 0xa7, 0xad, 0xeb, 0xd6, 0x5d, 0x99, 0xcc, 0xb5, 0xc8, 0x64, 0xd6,
- 0xa1, 0x8c, 0xd8, 0x9f, 0x3e, 0x77, 0x5a, 0xaf, 0xac, 0xca, 0x65, 0x2f,
- 0x78, 0xe8, 0xe0, 0xdc, 0xbd, 0x79, 0x90, 0x7e, 0xaf, 0x47, 0xff, 0x6f,
- 0xd1, 0x87, 0xfe, 0x75, 0xa3, 0x71, 0x39, 0x26, 0x73, 0xc6, 0x77, 0x9b,
- 0x0f, 0x72, 0x66, 0xac, 0x81, 0xef, 0x21, 0x96, 0x5f, 0x44, 0x2c, 0x59,
- 0x31, 0x22, 0xf2, 0x93, 0x47, 0xaf, 0x21, 0x97, 0x96, 0xfc, 0xc3, 0x89,
- 0x66, 0x24, 0x90, 0x78, 0xab, 0x39, 0x37, 0x82, 0x18, 0x97, 0x88, 0x86,
- 0x93, 0xc6, 0xb0, 0x5c, 0xaa, 0x0f, 0xca, 0x8f, 0xea, 0x96, 0xfc, 0xb0,
- 0x1e, 0x91, 0x1f, 0x20, 0xe6, 0x7f, 0xbf, 0xde, 0x9a, 0x73, 0x47, 0x68,
- 0x4f, 0x3d, 0xe9, 0xfa, 0x46, 0xb9, 0x7f, 0x13, 0x34, 0xde, 0x82, 0x9d,
- 0x04, 0xb2, 0xc8, 0xf5, 0x19, 0xbf, 0x26, 0x0e, 0x15, 0x9f, 0x6b, 0x82,
- 0xb7, 0x6c, 0x5b, 0xc2, 0xca, 0xeb, 0x7a, 0xf7, 0xa8, 0xf9, 0x29, 0xb4,
- 0x39, 0xa3, 0x81, 0x6a, 0xb1, 0x53, 0xe5, 0x8b, 0xd0, 0x91, 0xd8, 0xf5,
- 0x60, 0xb0, 0x56, 0xbc, 0x85, 0x7e, 0xcd, 0xe6, 0xa1, 0xf8, 0x6f, 0xed,
- 0x30, 0xff, 0x81, 0x85, 0x35, 0xdd, 0xf9, 0x25, 0x23, 0xb1, 0x49, 0x66,
- 0x43, 0xdf, 0x6f, 0x98, 0x03, 0x7d, 0x59, 0x3d, 0x11, 0x94, 0x74, 0x91,
- 0x6b, 0x2a, 0x24, 0xb3, 0x55, 0x28, 0xff, 0x3c, 0xd7, 0x85, 0x3c, 0x3b,
- 0x17, 0xef, 0x86, 0xed, 0xff, 0x9a, 0xe1, 0xae, 0x03, 0x18, 0x50, 0x75,
- 0x50, 0xf2, 0xe0, 0x37, 0x5f, 0x7f, 0xcb, 0xc3, 0x0e, 0xf0, 0x2a, 0x5b,
- 0x21, 0xf8, 0xc4, 0x70, 0xda, 0x76, 0xfe, 0x30, 0x88, 0xb6, 0xe0, 0x56,
- 0xeb, 0xce, 0x26, 0x7c, 0x3f, 0x10, 0xb2, 0x88, 0x4d, 0x24, 0xf3, 0x05,
- 0x7c, 0xff, 0x4a, 0x42, 0x36, 0xf7, 0xe2, 0x7b, 0x4b, 0x02, 0x26, 0x99,
- 0x60, 0xcc, 0xd5, 0x5a, 0x62, 0xae, 0x68, 0x69, 0xc8, 0x6e, 0x0e, 0x73,
- 0x4f, 0x43, 0x9e, 0x5f, 0xac, 0x07, 0xb5, 0xd4, 0xe9, 0x47, 0xc0, 0x87,
- 0x9f, 0x3b, 0x23, 0x3f, 0x33, 0x97, 0xb7, 0x04, 0xe4, 0x16, 0x7c, 0x5c,
- 0x12, 0x7e, 0xcc, 0x46, 0x6e, 0xb1, 0x03, 0xcb, 0x35, 0xfa, 0x5f, 0xbf,
- 0x20, 0x5f, 0xf3, 0x78, 0x6b, 0x93, 0x05, 0x65, 0xa3, 0x6c, 0xcf, 0x67,
- 0xfe, 0xcd, 0xc0, 0xdd, 0xf6, 0x17, 0x57, 0xdb, 0xcb, 0x99, 0x7f, 0xb8,
- 0xda, 0xde, 0xdb, 0xe6, 0xf2, 0x3f, 0xaa, 0x4d, 0xd4, 0xf7, 0x78, 0x6d,
- 0xb7, 0xa1, 0xb3, 0x66, 0x93, 0xb9, 0x45, 0x01, 0xd8, 0x24, 0x1d, 0xa7,
- 0x2f, 0xbe, 0x1f, 0x5f, 0xbb, 0xc6, 0xcf, 0x9a, 0x49, 0x83, 0xb6, 0x10,
- 0x14, 0x97, 0x26, 0xef, 0x77, 0x20, 0x7f, 0xbf, 0x8d, 0xdf, 0x8c, 0xa3,
- 0x7e, 0x6e, 0xce, 0x3e, 0x7c, 0xfe, 0xcd, 0x7b, 0xd8, 0x4b, 0x08, 0xf6,
- 0xf2, 0xff, 0xab, 0x5d, 0x5c, 0xba, 0x1f, 0xbb, 0xc0, 0x9f, 0xb2, 0x0b,
- 0xd5, 0xff, 0xd2, 0xea, 0x5a, 0x09, 0x43, 0x3e, 0x8c, 0x07, 0x83, 0xd0,
- 0xf1, 0x66, 0x99, 0xb5, 0xc8, 0x8f, 0x15, 0xc9, 0xc1, 0x5f, 0x9e, 0x58,
- 0x17, 0xbb, 0xbb, 0x10, 0x0f, 0x8e, 0x9f, 0x8e, 0x8e, 0x32, 0x1e, 0xc4,
- 0xe0, 0x1b, 0x93, 0xef, 0x88, 0x07, 0x37, 0x8c, 0xd6, 0x78, 0x60, 0x20,
- 0x1e, 0xec, 0x7a, 0x97, 0x78, 0x70, 0xe2, 0x1d, 0xf1, 0x40, 0x83, 0x6c,
- 0x38, 0xbf, 0xbf, 0x35, 0xfc, 0x78, 0x50, 0x58, 0x13, 0x0f, 0x7c, 0x5d,
- 0x59, 0x0a, 0x0b, 0xdc, 0xd5, 0x5b, 0x97, 0xa7, 0x2b, 0x09, 0x06, 0x12,
- 0x8d, 0xcc, 0x9c, 0xf5, 0xb0, 0xb4, 0xc1, 0xe7, 0x5e, 0xaa, 0x8f, 0x40,
- 0x67, 0x97, 0x30, 0xf7, 0x68, 0x9c, 0x89, 0x65, 0x5b, 0x82, 0xeb, 0xe1,
- 0xcd, 0x08, 0x30, 0xe2, 0x6e, 0xe0, 0xbe, 0xdd, 0x67, 0xd5, 0xfa, 0x78,
- 0x33, 0xea, 0x61, 0xf7, 0x6d, 0xc0, 0xee, 0x78, 0x3e, 0x00, 0x4c, 0xc8,
- 0xf6, 0x2b, 0x66, 0x12, 0x7a, 0xaa, 0x3a, 0xf6, 0xee, 0x02, 0x3e, 0x73,
- 0xaa, 0xef, 0xad, 0x08, 0xfb, 0x76, 0x24, 0x12, 0xd1, 0x3f, 0xc3, 0x77,
- 0x7b, 0x22, 0xbc, 0xed, 0xaa, 0x45, 0xba, 0x87, 0xa2, 0x67, 0x15, 0x8d,
- 0x80, 0x14, 0xd4, 0xb3, 0x91, 0x6d, 0x7c, 0xf6, 0x18, 0x62, 0xf6, 0x51,
- 0xc7, 0x94, 0x23, 0x4e, 0x76, 0x77, 0x0e, 0x1f, 0x62, 0xd5, 0x4b, 0x25,
- 0xde, 0x1f, 0xc5, 0xfd, 0x80, 0x30, 0x97, 0xfc, 0x2a, 0xfa, 0x1c, 0x44,
- 0x9f, 0x19, 0xc7, 0xd7, 0x05, 0xef, 0x37, 0x32, 0x29, 0xdc, 0x9f, 0x29,
- 0x36, 0x32, 0xe9, 0x22, 0xf3, 0xd6, 0xa1, 0xf0, 0x11, 0xc8, 0x33, 0x8b,
- 0x5c, 0xcd, 0x96, 0xe8, 0x60, 0x5e, 0x9e, 0xee, 0x1c, 0x07, 0x4e, 0x3a,
- 0x87, 0x1c, 0xc2, 0x9e, 0x8c, 0xc6, 0xcb, 0xf2, 0xe1, 0xce, 0xe4, 0x69,
- 0xe4, 0x0b, 0xf1, 0xed, 0x90, 0x61, 0x23, 0xa3, 0xc7, 0x04, 0xb6, 0x1e,
- 0x87, 0x5f, 0x1e, 0xd1, 0x53, 0xc5, 0x7e, 0x73, 0x56, 0x1e, 0x95, 0x86,
- 0x19, 0x0d, 0x8f, 0xcb, 0x26, 0x49, 0x05, 0xd0, 0x6f, 0xf0, 0x43, 0x92,
- 0x0d, 0x53, 0xd6, 0x0f, 0xc2, 0xdf, 0x6b, 0xd2, 0x61, 0xb5, 0xc6, 0x9e,
- 0x5b, 0x10, 0x6f, 0x2e, 0x40, 0x9f, 0xdd, 0x61, 0x75, 0x7a, 0x3a, 0xd9,
- 0x24, 0xcb, 0xef, 0xe8, 0x77, 0xbb, 0xa5, 0x5f, 0x6b, 0xfb, 0xdb, 0x68,
- 0xdf, 0x84, 0x9c, 0xb3, 0x91, 0x09, 0xc4, 0x20, 0x7f, 0xcc, 0xa1, 0x0d,
- 0x76, 0x72, 0x15, 0xf3, 0x61, 0x1c, 0x2c, 0x94, 0x99, 0xf7, 0x18, 0x52,
- 0x36, 0x71, 0xcf, 0x69, 0x36, 0x2b, 0x16, 0xf8, 0xbd, 0x40, 0x9e, 0x83,
- 0x32, 0xee, 0x0c, 0x88, 0x5d, 0xa3, 0x1c, 0xa2, 0xf0, 0x4a, 0x0f, 0x77,
- 0xa5, 0x16, 0xa3, 0x76, 0x1e, 0x14, 0x8d, 0x0b, 0x7d, 0x5d, 0x49, 0xe4,
- 0x39, 0xfa, 0x85, 0x48, 0x57, 0x0a, 0x36, 0x6b, 0x5c, 0x78, 0xa8, 0x2b,
- 0x7d, 0x9a, 0x7c, 0x19, 0xc8, 0x73, 0x3e, 0x0a, 0x9c, 0xdf, 0x94, 0xdf,
- 0x45, 0x2e, 0x5b, 0x18, 0x44, 0x0e, 0x80, 0xd5, 0xaf, 0x83, 0xef, 0xbc,
- 0x29, 0xc1, 0xae, 0xc4, 0xab, 0xe0, 0x6f, 0x18, 0xb2, 0xd9, 0x84, 0x3e,
- 0x06, 0xda, 0x07, 0x58, 0x13, 0x68, 0x69, 0xb7, 0xba, 0x10, 0x4f, 0x11,
- 0xbb, 0x24, 0x98, 0x1c, 0xe9, 0x06, 0xfd, 0x2b, 0x01, 0xe6, 0x82, 0xc1,
- 0xd8, 0x6a, 0xfb, 0x37, 0xdd, 0xf6, 0x41, 0xf0, 0xc2, 0xe7, 0x88, 0x09,
- 0x24, 0x38, 0x35, 0x62, 0x82, 0x07, 0xf6, 0x0d, 0xa9, 0xbe, 0xe9, 0x45,
- 0xda, 0x40, 0x23, 0x53, 0xb1, 0x1e, 0x91, 0xd4, 0xc2, 0x56, 0x19, 0x5f,
- 0xe8, 0x95, 0x5d, 0x0b, 0xc4, 0x30, 0xac, 0x69, 0x60, 0x2a, 0xc0, 0x18,
- 0xfa, 0x05, 0xe6, 0x76, 0xd1, 0xf0, 0x41, 0xe9, 0x0f, 0x7f, 0x15, 0xeb,
- 0x60, 0xca, 0x8a, 0x45, 0x66, 0xb1, 0xc6, 0x02, 0x8a, 0x4e, 0xd8, 0x1f,
- 0x93, 0x36, 0xba, 0x66, 0xdc, 0xf4, 0xe2, 0xbd, 0xe8, 0x62, 0xe1, 0x5c,
- 0x08, 0xaf, 0xa3, 0xfb, 0x57, 0x1e, 0x5d, 0x13, 0x74, 0xfb, 0x40, 0x93,
- 0x73, 0x7c, 0xa8, 0x73, 0xec, 0xb4, 0xd8, 0x1d, 0xe0, 0x2f, 0x1d, 0x7b,
- 0x58, 0x66, 0x41, 0xe7, 0xe8, 0x02, 0xfd, 0xa4, 0x6c, 0xc5, 0x67, 0xb8,
- 0x4d, 0x62, 0x83, 0xe7, 0x81, 0x73, 0xc6, 0x14, 0x0d, 0x17, 0x73, 0xe8,
- 0x17, 0x12, 0xc0, 0xa9, 0x1f, 0x07, 0x3f, 0xcc, 0xb1, 0x38, 0xe7, 0x00,
- 0xe6, 0x9b, 0xc0, 0x3a, 0x64, 0x7d, 0x85, 0xeb, 0x1b, 0xbf, 0xcf, 0x87,
- 0x3b, 0x53, 0xa7, 0xdb, 0xb1, 0xee, 0xe4, 0x11, 0x43, 0xc5, 0x7e, 0xea,
- 0xc5, 0xea, 0x4c, 0x96, 0x14, 0xdf, 0x9d, 0xa9, 0x12, 0x65, 0x14, 0xef,
- 0x4c, 0x97, 0x28, 0x23, 0x01, 0x3f, 0x71, 0xd8, 0x64, 0x40, 0x22, 0x5b,
- 0xa8, 0xc7, 0x43, 0xe8, 0xf7, 0x57, 0x01, 0xe2, 0xb8, 0xa4, 0xc5, 0xdf,
- 0xf0, 0xb5, 0x17, 0x0e, 0xa3, 0x2f, 0x7f, 0x6f, 0x07, 0xdd, 0xfe, 0xc1,
- 0x82, 0xb4, 0x0f, 0xce, 0xc0, 0x4f, 0xe8, 0x23, 0xc0, 0x91, 0xca, 0xce,
- 0x9b, 0xc0, 0xd8, 0x3b, 0x30, 0x1f, 0xac, 0x8d, 0x98, 0x25, 0xd3, 0xf3,
- 0x94, 0xab, 0x7c, 0x08, 0x73, 0xc0, 0xfc, 0x63, 0xf0, 0x2d, 0x9c, 0x03,
- 0xc7, 0x16, 0xe4, 0x36, 0x4b, 0x92, 0x9b, 0x0f, 0x2a, 0x2c, 0x6b, 0x9b,
- 0x1c, 0x5f, 0xd3, 0xf4, 0x44, 0x17, 0x74, 0xcc, 0xb9, 0xcd, 0x81, 0xb7,
- 0x67, 0x10, 0xff, 0xa2, 0x0a, 0x43, 0x19, 0x17, 0xb8, 0x56, 0x46, 0xb1,
- 0x4e, 0xc8, 0xbf, 0x67, 0x7b, 0x5a, 0x03, 0x3e, 0x45, 0xf9, 0x7f, 0xe4,
- 0xea, 0x09, 0xf8, 0x91, 0x51, 0xf9, 0x7d, 0xf8, 0x92, 0x1f, 0xd7, 0xe3,
- 0xc8, 0x1b, 0x86, 0x91, 0x37, 0x0c, 0x22, 0x6f, 0xb0, 0x90, 0x37, 0x44,
- 0x90, 0x37, 0xf4, 0x21, 0x6f, 0x08, 0x23, 0x3e, 0x88, 0x1c, 0xad, 0xe7,
- 0x61, 0x63, 0x0d, 0xf8, 0x41, 0x33, 0x68, 0xd7, 0x43, 0xc1, 0x64, 0x3d,
- 0x1c, 0x4c, 0xd5, 0x03, 0x98, 0xd3, 0x01, 0x8e, 0x89, 0xf9, 0xe5, 0x3b,
- 0xc7, 0x4a, 0xc3, 0x88, 0x39, 0x36, 0xfc, 0x52, 0x1a, 0xf1, 0x36, 0x2e,
- 0x47, 0xf0, 0xcc, 0xf2, 0x7c, 0x04, 0xcf, 0x34, 0x25, 0x1d, 0x6f, 0x93,
- 0x59, 0x33, 0x0e, 0x1a, 0x5b, 0x94, 0x9d, 0x22, 0xdf, 0x6a, 0x83, 0x9d,
- 0x4a, 0xae, 0xc8, 0x7c, 0xab, 0x0f, 0xf4, 0x3a, 0x11, 0x97, 0xe9, 0x1f,
- 0xe8, 0x0b, 0xec, 0xdd, 0x5f, 0xb2, 0xb8, 0xe6, 0xba, 0xb4, 0xe4, 0xe9,
- 0xbc, 0x10, 0x6b, 0x22, 0x0e, 0xc2, 0x2e, 0xd8, 0x36, 0x81, 0xe7, 0xf8,
- 0xfb, 0x6d, 0xcf, 0xef, 0x7f, 0x24, 0x28, 0x30, 0xde, 0x4b, 0x8c, 0xf9,
- 0x16, 0xe8, 0x39, 0xad, 0xeb, 0xb5, 0xa6, 0x8b, 0xe5, 0xdf, 0x67, 0xfd,
- 0x8d, 0x35, 0xc7, 0xd7, 0xc0, 0x73, 0xbf, 0xb9, 0x8c, 0x1c, 0xd9, 0xde,
- 0xbf, 0x82, 0xdf, 0xad, 0xfd, 0xeb, 0xe8, 0xaf, 0xda, 0x82, 0x66, 0x22,
- 0xce, 0x7c, 0x18, 0x3e, 0x73, 0x10, 0xfe, 0xf1, 0x56, 0x46, 0x5f, 0xba,
- 0x89, 0x79, 0x42, 0x9e, 0xc5, 0x5b, 0x99, 0xc0, 0xc0, 0xb5, 0xe6, 0x8b,
- 0xc0, 0x37, 0x63, 0x4b, 0x23, 0x92, 0x5a, 0xea, 0x0f, 0x5f, 0x96, 0xce,
- 0xdb, 0xb6, 0x5c, 0x6b, 0xce, 0x3a, 0xd1, 0xe3, 0xb6, 0x10, 0x6f, 0x99,
- 0x52, 0x01, 0xa9, 0x6d, 0x3b, 0x3b, 0x88, 0x19, 0x2f, 0x8a, 0x1e, 0x91,
- 0xe4, 0x29, 0x5b, 0x46, 0x76, 0xfa, 0xb9, 0xfb, 0x9d, 0x0e, 0xe9, 0x42,
- 0xdb, 0x52, 0x04, 0x7d, 0x88, 0x53, 0x39, 0xef, 0x2c, 0xe6, 0xac, 0xb9,
- 0xcf, 0x78, 0xf5, 0xc9, 0x42, 0x09, 0x73, 0xaf, 0xdf, 0xca, 0x5c, 0x3e,
- 0x05, 0xec, 0x0e, 0x1d, 0x25, 0x4f, 0xb1, 0xae, 0xb0, 0x09, 0x72, 0x1a,
- 0x83, 0xad, 0xd0, 0x06, 0xfa, 0xf1, 0x6c, 0x53, 0xbe, 0x11, 0xa7, 0x5d,
- 0xbc, 0x04, 0x59, 0x82, 0x56, 0xc0, 0x9f, 0x0f, 0x70, 0xde, 0x3c, 0xe5,
- 0x17, 0x46, 0x6e, 0xce, 0xb1, 0x25, 0xd8, 0x99, 0x58, 0x9f, 0x77, 0xdf,
- 0xca, 0x2c, 0x9f, 0x02, 0xfd, 0x01, 0xd6, 0xde, 0xe0, 0xb3, 0x8b, 0xac,
- 0x1d, 0x32, 0x27, 0xdd, 0x05, 0x3d, 0xed, 0x55, 0xb5, 0xb8, 0x64, 0x35,
- 0x2e, 0xd6, 0x49, 0xfa, 0x2c, 0x89, 0x18, 0xd6, 0x7e, 0xe4, 0xaf, 0x62,
- 0xea, 0x89, 0x49, 0xdc, 0xa3, 0x3c, 0x35, 0xe4, 0x1c, 0xb8, 0x7f, 0x61,
- 0x45, 0xe9, 0xc4, 0x80, 0xee, 0x72, 0x3b, 0x99, 0x84, 0xc9, 0xbc, 0x91,
- 0x80, 0x2f, 0x1c, 0xe1, 0x1c, 0xd4, 0xd8, 0xc8, 0xc7, 0xb9, 0xfe, 0x30,
- 0x67, 0xd8, 0x55, 0x4b, 0x5e, 0xae, 0xfe, 0x66, 0x4b, 0x47, 0x60, 0xd3,
- 0x92, 0x6f, 0x43, 0x3e, 0x90, 0x1c, 0xc1, 0x6f, 0x38, 0x81, 0xa3, 0xd0,
- 0xe7, 0xd9, 0x11, 0xd6, 0x3f, 0x5f, 0x02, 0xb6, 0x27, 0xdf, 0xb1, 0xc8,
- 0x11, 0xb5, 0x86, 0x71, 0xed, 0x30, 0x97, 0xdb, 0x24, 0x97, 0xd5, 0xfc,
- 0x1e, 0x22, 0xf6, 0x80, 0x9e, 0xee, 0x67, 0x7e, 0xe3, 0xf7, 0x39, 0x3f,
- 0x97, 0x3e, 0x63, 0x57, 0xd2, 0x8a, 0x48, 0xaa, 0x78, 0xa9, 0x19, 0xb0,
- 0x2c, 0x60, 0x67, 0x57, 0x8f, 0x29, 0x27, 0x08, 0x3e, 0x58, 0x6b, 0xdb,
- 0xa9, 0x74, 0x09, 0x3e, 0x68, 0x3b, 0xf9, 0x60, 0x62, 0xb3, 0x9c, 0x9b,
- 0xef, 0x91, 0xca, 0xfc, 0xcf, 0xa5, 0x3a, 0xdf, 0x25, 0xe7, 0xe7, 0x9b,
- 0x72, 0x35, 0xae, 0x7c, 0x93, 0xd5, 0xae, 0xd6, 0xb5, 0x3c, 0xec, 0xd6,
- 0x61, 0x62, 0xa3, 0xd7, 0xe5, 0x79, 0x39, 0x57, 0x76, 0x79, 0xcf, 0xb4,
- 0xf0, 0x7e, 0x15, 0xb6, 0xf6, 0xaa, 0x45, 0xfe, 0x47, 0xa4, 0x52, 0x24,
- 0xef, 0xfb, 0x14, 0xef, 0xbb, 0x56, 0x79, 0x97, 0xac, 0x61, 0x91, 0xff,
- 0x8d, 0x78, 0xef, 0x90, 0xec, 0x56, 0xf2, 0x1f, 0xc1, 0xb3, 0xef, 0xb4,
- 0xbf, 0x8a, 0x73, 0xad, 0xb9, 0x5c, 0x6c, 0x53, 0x3c, 0x1b, 0x89, 0x11,
- 0xc8, 0xe7, 0x5a, 0xb3, 0xe1, 0x70, 0x1d, 0xe1, 0xb7, 0xf3, 0x2f, 0xe0,
- 0xab, 0x7a, 0x55, 0xce, 0x92, 0x9b, 0xec, 0xee, 0x4c, 0x2e, 0x8e, 0x42,
- 0xb7, 0x9d, 0x6a, 0x1d, 0xc2, 0x6d, 0x40, 0x67, 0xff, 0x1e, 0xfd, 0xbf,
- 0xcd, 0xf5, 0xa6, 0xe4, 0x92, 0x86, 0x5c, 0x0a, 0xc5, 0xf1, 0x76, 0xe0,
- 0x27, 0x8c, 0xd3, 0xc8, 0x64, 0x1d, 0x3e, 0xd3, 0x07, 0xdf, 0xc6, 0xef,
- 0xf7, 0x6d, 0x0f, 0x79, 0xf8, 0x5c, 0xe8, 0x1c, 0x79, 0x05, 0xd7, 0xf3,
- 0x48, 0x03, 0x31, 0x36, 0x36, 0x58, 0x51, 0xfb, 0x10, 0x71, 0x85, 0x85,
- 0x67, 0x9d, 0x6f, 0xe3, 0xe3, 0x8e, 0x37, 0x56, 0xe7, 0x98, 0x6b, 0xe7,
- 0x54, 0x70, 0x1a, 0xc8, 0xdf, 0x2d, 0xd0, 0xe5, 0xb8, 0x79, 0x31, 0x12,
- 0x06, 0xc6, 0x65, 0x5b, 0x37, 0x7c, 0x4c, 0x04, 0x3e, 0x6b, 0x18, 0xbe,
- 0x9f, 0x6b, 0x99, 0x7e, 0xde, 0xe7, 0x7d, 0x18, 0x34, 0xe9, 0x7f, 0x87,
- 0x31, 0x67, 0xe6, 0xd8, 0xf4, 0x9f, 0x88, 0x27, 0xb5, 0x70, 0x57, 0xf2,
- 0xb4, 0x5b, 0x1b, 0x74, 0x7f, 0xf3, 0xbe, 0x04, 0x1f, 0x49, 0x44, 0xcb,
- 0x79, 0xe4, 0x7e, 0x29, 0xac, 0xd1, 0xa4, 0x85, 0x3c, 0xbb, 0x16, 0x7d,
- 0x85, 0x98, 0x5b, 0xa7, 0x0c, 0x96, 0x28, 0x27, 0xd6, 0xa9, 0x4c, 0xc9,
- 0x57, 0xbe, 0x0b, 0x79, 0x04, 0x65, 0x8b, 0x95, 0x85, 0x4f, 0x01, 0xff,
- 0x98, 0xfb, 0x5c, 0x89, 0xb5, 0xc8, 0x7e, 0xc4, 0x31, 0x03, 0x42, 0x40,
- 0x4e, 0xb5, 0x64, 0xc8, 0x67, 0x03, 0x43, 0xc8, 0x01, 0x9f, 0x45, 0xdf,
- 0x80, 0xe4, 0x97, 0x18, 0x0f, 0x02, 0x32, 0xb7, 0x24, 0x72, 0xfd, 0x14,
- 0xfd, 0x8a, 0xfa, 0x83, 0xcc, 0x1b, 0x99, 0x69, 0x62, 0xed, 0x79, 0xfa,
- 0x18, 0xfa, 0x89, 0x07, 0xa1, 0x8b, 0xd8, 0x4b, 0xdf, 0x40, 0x6c, 0x9a,
- 0x2d, 0xf6, 0xc3, 0x67, 0x4a, 0x43, 0x87, 0x4c, 0x11, 0xd3, 0x98, 0xa3,
- 0x6f, 0x50, 0x77, 0xf4, 0x6b, 0x8e, 0x41, 0x29, 0x9c, 0x62, 0xbd, 0x31,
- 0x08, 0x5e, 0x98, 0xb7, 0x1a, 0x2a, 0x0f, 0x7a, 0x50, 0xf9, 0x56, 0x7e,
- 0x07, 0x5a, 0xc6, 0x8d, 0x1d, 0xdf, 0xa6, 0xd3, 0x8f, 0x3d, 0x22, 0xf6,
- 0xc4, 0xa1, 0xce, 0x5d, 0xa5, 0x76, 0x29, 0xf7, 0xd2, 0x2e, 0xa9, 0xff,
- 0xac, 0x4e, 0x5f, 0x8b, 0x3c, 0x0c, 0xf4, 0x58, 0x23, 0x08, 0xa0, 0x5f,
- 0xc8, 0xeb, 0x47, 0xb9, 0xfe, 0xb6, 0x4c, 0xed, 0xfc, 0x3b, 0xf0, 0xe5,
- 0xfa, 0xb5, 0xdc, 0x4e, 0xf8, 0xdb, 0x09, 0x5d, 0x1e, 0xfb, 0x54, 0x1a,
- 0xcf, 0x32, 0x16, 0xde, 0xf2, 0xf0, 0x38, 0xdb, 0x58, 0xa3, 0x45, 0x9e,
- 0x7e, 0xce, 0xc4, 0x77, 0xaf, 0xe4, 0xcf, 0x05, 0x21, 0x07, 0xe4, 0xc4,
- 0x15, 0x97, 0x16, 0xf3, 0xde, 0xe3, 0xd0, 0x91, 0x7e, 0x32, 0x28, 0x6d,
- 0x27, 0x7b, 0x25, 0xf0, 0xad, 0x2e, 0x69, 0xff, 0xd6, 0x80, 0x18, 0xdf,
- 0x62, 0x2d, 0x29, 0x1a, 0x39, 0xaa, 0xea, 0x58, 0x69, 0x39, 0x86, 0xf8,
- 0xa5, 0x23, 0x16, 0x2b, 0x3b, 0x35, 0xb7, 0x8a, 0x81, 0xc4, 0x55, 0x7f,
- 0xc1, 0x96, 0xaf, 0xef, 0xfc, 0x85, 0xaa, 0xa3, 0x26, 0x47, 0x70, 0xfd,
- 0x72, 0x06, 0xd8, 0x44, 0x83, 0xad, 0x34, 0x32, 0xd7, 0x1e, 0xf5, 0x73,
- 0xcb, 0x41, 0x55, 0x93, 0xff, 0xfa, 0x4e, 0x37, 0xb7, 0x9c, 0x45, 0x6e,
- 0x99, 0x56, 0xb9, 0x25, 0xfc, 0x6b, 0x80, 0xfd, 0xb6, 0x8a, 0x8e, 0xb1,
- 0x72, 0xc2, 0x5c, 0xfd, 0xa3, 0x62, 0x1f, 0xc0, 0xba, 0x38, 0x23, 0xf3,
- 0x7a, 0x42, 0x53, 0x34, 0x8d, 0x17, 0xe8, 0xa7, 0xe8, 0xbf, 0x68, 0xe3,
- 0xac, 0x69, 0xa1, 0xed, 0x65, 0xfa, 0x28, 0xd7, 0xb6, 0xc7, 0x5a, 0x7c,
- 0xdd, 0x5c, 0xa9, 0x0e, 0x1d, 0x22, 0xa7, 0xb7, 0xda, 0x30, 0x7f, 0xc4,
- 0x74, 0x8b, 0xd7, 0x9c, 0x3f, 0x7c, 0x67, 0x28, 0xa4, 0xae, 0x0b, 0x65,
- 0xb7, 0x86, 0xe1, 0xd2, 0x67, 0xfe, 0x01, 0x1f, 0x53, 0x27, 0x1f, 0x1c,
- 0xb7, 0x4f, 0x8c, 0x33, 0x21, 0x09, 0x9c, 0xa1, 0xfd, 0x45, 0x23, 0x69,
- 0xc8, 0x6f, 0xce, 0x22, 0x06, 0x3c, 0x04, 0x6c, 0xf4, 0x88, 0xe8, 0xe7,
- 0x06, 0xb1, 0x76, 0xa2, 0xe1, 0xb2, 0xc4, 0xc4, 0xa8, 0x04, 0xe5, 0x8d,
- 0x53, 0xd1, 0x08, 0xed, 0xe5, 0x2c, 0xe2, 0xd5, 0x91, 0x7a, 0xe7, 0xed,
- 0x86, 0xe2, 0x82, 0x6d, 0xdf, 0x08, 0x00, 0x3b, 0x0c, 0xda, 0x7a, 0xb7,
- 0xdc, 0x80, 0xbe, 0xb3, 0xaa, 0xed, 0x11, 0xd0, 0x05, 0x0f, 0x67, 0x58,
- 0x1b, 0x24, 0xdd, 0xa3, 0xa0, 0x49, 0xda, 0x8d, 0xcc, 0x32, 0x73, 0xd3,
- 0x53, 0xb4, 0xdd, 0x5e, 0xd8, 0x1d, 0xae, 0xeb, 0xed, 0x92, 0x9d, 0x8c,
- 0x88, 0x7e, 0x6a, 0x8f, 0xf4, 0xef, 0xd4, 0xdd, 0xf9, 0xa8, 0x39, 0xb2,
- 0x8d, 0x35, 0xe7, 0x11, 0xb5, 0x1e, 0xf5, 0x25, 0xd8, 0xcc, 0x3e, 0xea,
- 0x18, 0xb1, 0x1f, 0x71, 0x8c, 0x7e, 0xcc, 0x40, 0x1c, 0x4b, 0xd5, 0x5d,
- 0xbd, 0x97, 0xf7, 0x6d, 0x95, 0x63, 0x67, 0x68, 0x4f, 0xb8, 0xb7, 0x6a,
- 0x53, 0xfe, 0xde, 0x10, 0xef, 0x59, 0x72, 0xfc, 0x45, 0xe6, 0x1e, 0xcc,
- 0x39, 0x98, 0x67, 0x45, 0xc3, 0xbb, 0x30, 0x1f, 0xfd, 0x31, 0xfa, 0x03,
- 0x5d, 0xd9, 0x6e, 0x0e, 0x3e, 0xba, 0x50, 0xa7, 0xde, 0x86, 0xb9, 0x7f,
- 0x66, 0x32, 0x5f, 0xb3, 0xc3, 0xae, 0xbc, 0x0b, 0x68, 0x9b, 0x85, 0xef,
- 0x4f, 0x39, 0x6d, 0xb2, 0x32, 0x69, 0x43, 0xf7, 0x5f, 0x02, 0x5f, 0x07,
- 0x3a, 0x59, 0x23, 0x58, 0x99, 0x4c, 0xe3, 0xfa, 0x80, 0xca, 0xd1, 0x8c,
- 0xc7, 0x6c, 0xd0, 0xd8, 0xca, 0x75, 0xe4, 0xe9, 0x29, 0xae, 0x17, 0xe6,
- 0x1f, 0xd3, 0x67, 0xe1, 0xb3, 0xc7, 0xe3, 0x8c, 0xf1, 0xdc, 0x4b, 0xe8,
- 0x00, 0x1f, 0xdd, 0x0a, 0x57, 0xe8, 0xd6, 0x4e, 0xbd, 0x50, 0xa6, 0x9f,
- 0xcf, 0x87, 0xdb, 0x85, 0x78, 0xc4, 0xd4, 0x2b, 0x16, 0x75, 0xa2, 0xc9,
- 0x65, 0xb5, 0xef, 0x20, 0x92, 0x76, 0x0e, 0x61, 0xac, 0xb8, 0x5e, 0x2d,
- 0xef, 0xd4, 0xf3, 0x65, 0x43, 0x56, 0x42, 0xe4, 0x3b, 0xa2, 0xf2, 0xf8,
- 0x9d, 0xca, 0xd6, 0x8a, 0x88, 0x25, 0xb0, 0x99, 0xf8, 0x87, 0x31, 0xae,
- 0x6a, 0x83, 0x4d, 0x51, 0xf7, 0xd4, 0xbb, 0xf2, 0x91, 0x9e, 0xee, 0x37,
- 0x8a, 0x99, 0x45, 0xf8, 0x5f, 0xd6, 0x2f, 0x3a, 0xbc, 0x5a, 0xe3, 0x4b,
- 0x5e, 0x3e, 0xf4, 0x8c, 0x30, 0x4f, 0x99, 0x2b, 0x91, 0x97, 0x22, 0xfc,
- 0xe1, 0x46, 0xb6, 0x44, 0x39, 0xba, 0x3e, 0xe5, 0x10, 0xec, 0x42, 0x5f,
- 0x32, 0x3d, 0x1b, 0xe0, 0xdf, 0x28, 0xee, 0x31, 0x06, 0xe0, 0xbb, 0xde,
- 0x86, 0xf5, 0xbe, 0x17, 0x32, 0xa2, 0x6e, 0xa0, 0xbf, 0x25, 0xee, 0xbb,
- 0x42, 0x7f, 0x4b, 0x57, 0xde, 0xb6, 0x7b, 0xe9, 0xf3, 0x46, 0xe4, 0x18,
- 0xfc, 0xe8, 0xd1, 0x45, 0xf2, 0x93, 0xf6, 0x70, 0xd9, 0x30, 0x64, 0x42,
- 0x1f, 0x3f, 0x2c, 0x6f, 0xd4, 0x7e, 0xa0, 0x70, 0xe0, 0xb6, 0x9d, 0x0d,
- 0x99, 0x86, 0x7f, 0x98, 0x71, 0x20, 0x7f, 0x33, 0x82, 0xf5, 0x19, 0x56,
- 0xfe, 0x71, 0xe6, 0xfd, 0xe5, 0x24, 0x01, 0x37, 0x66, 0x7f, 0xf6, 0x3e,
- 0x63, 0xf6, 0x03, 0xc0, 0x61, 0xef, 0x8b, 0xbe, 0xe1, 0xd2, 0xff, 0x33,
- 0xe8, 0xea, 0xd7, 0x55, 0xfd, 0x22, 0xb7, 0x73, 0x2b, 0x65, 0xfa, 0x5e,
- 0xcf, 0xe9, 0xee, 0x73, 0x9f, 0xbb, 0x4f, 0xbe, 0x4c, 0xa9, 0x01, 0x2b,
- 0xe4, 0x55, 0x1c, 0x65, 0xae, 0xd8, 0xe6, 0xe9, 0x6f, 0x10, 0x18, 0x9a,
- 0x74, 0x7d, 0xdf, 0xdb, 0x21, 0xf9, 0x5e, 0x3f, 0xff, 0x84, 0xcf, 0x5e,
- 0x6d, 0xf7, 0xf3, 0x59, 0x3e, 0xbf, 0x92, 0x41, 0xfe, 0x0c, 0x1b, 0x60,
- 0x2c, 0x60, 0x5b, 0x5c, 0xf9, 0xa1, 0x77, 0xe7, 0x9b, 0xf5, 0x0b, 0xf2,
- 0xbd, 0x5b, 0xf1, 0x9d, 0x56, 0x7c, 0xb3, 0x06, 0xb9, 0x5f, 0x4b, 0x9d,
- 0x67, 0x1d, 0xd2, 0xaf, 0x3b, 0x92, 0x1e, 0xb0, 0x01, 0xf4, 0xfd, 0x63,
- 0xd0, 0xfd, 0x11, 0xf4, 0xfa, 0xc3, 0x12, 0xb0, 0x41, 0x09, 0xd8, 0xa0,
- 0x04, 0x6c, 0x50, 0x02, 0x36, 0x28, 0x85, 0xbd, 0x3a, 0x8b, 0x4d, 0x6c,
- 0xff, 0x3e, 0x6d, 0xd7, 0xaf, 0x6d, 0xac, 0xb7, 0x4b, 0xb7, 0xb6, 0x99,
- 0xaa, 0xfb, 0x18, 0x39, 0xc8, 0x5a, 0x2b, 0xb0, 0x9a, 0x5f, 0xf7, 0xf0,
- 0x62, 0x44, 0x8d, 0xfb, 0x5e, 0x88, 0x11, 0x35, 0x1b, 0xeb, 0x66, 0x28,
- 0x6c, 0x00, 0x1b, 0x1a, 0x12, 0xc6, 0x6f, 0x13, 0xbe, 0x17, 0xb4, 0x86,
- 0xfb, 0xb1, 0x92, 0xda, 0x55, 0x5d, 0xef, 0x88, 0xaa, 0x3b, 0x58, 0x32,
- 0x5b, 0xf6, 0x73, 0xb7, 0x98, 0x8c, 0xcd, 0x13, 0x6f, 0xca, 0x16, 0x3d,
- 0x01, 0x1d, 0x38, 0xc4, 0x88, 0xdc, 0x27, 0xe4, 0xf8, 0xb1, 0xc1, 0x2a,
- 0xc6, 0x2c, 0x58, 0x2e, 0x7f, 0x47, 0x9c, 0xbb, 0xcf, 0xec, 0x82, 0x7f,
- 0xce, 0x14, 0x23, 0x32, 0x5e, 0x74, 0x31, 0x01, 0xf2, 0x9f, 0x75, 0xf5,
- 0xe5, 0x5b, 0xd0, 0xc3, 0xad, 0xcc, 0x94, 0xb5, 0x6a, 0x1b, 0x91, 0xcb,
- 0x71, 0xca, 0x98, 0xfa, 0xdf, 0xab, 0xf6, 0x29, 0x76, 0x55, 0xdd, 0xbd,
- 0xa4, 0x71, 0x65, 0x0b, 0x01, 0xfa, 0x19, 0xd0, 0x89, 0xbb, 0x6b, 0x18,
- 0x76, 0x91, 0x73, 0x7c, 0xb9, 0xb4, 0xe2, 0x91, 0x2f, 0x6a, 0x62, 0x6d,
- 0xd4, 0xfe, 0x1b, 0x2d, 0xed, 0xab, 0xf7, 0x3d, 0x7e, 0xe1, 0xfb, 0x56,
- 0x6b, 0x0d, 0xf4, 0x53, 0x77, 0xdb, 0x81, 0xdd, 0x24, 0xa0, 0xee, 0xc3,
- 0x87, 0xd7, 0x42, 0x92, 0xaa, 0x59, 0x92, 0x2e, 0xb3, 0x1f, 0xeb, 0x17,
- 0xf4, 0x47, 0x7f, 0x22, 0x29, 0xe4, 0xab, 0xd9, 0x50, 0x34, 0x6e, 0xcb,
- 0x7f, 0x96, 0xe5, 0x85, 0x7c, 0x84, 0xe7, 0x0a, 0xf2, 0x13, 0x1a, 0x9e,
- 0xfb, 0x19, 0xae, 0xc9, 0xb3, 0x25, 0x33, 0x45, 0xc6, 0x9d, 0xa1, 0x70,
- 0x0d, 0xf7, 0xb2, 0x93, 0xac, 0xd9, 0x7c, 0x07, 0x36, 0x19, 0x8d, 0x94,
- 0xa1, 0xef, 0x2b, 0x45, 0x8e, 0x07, 0x6c, 0x54, 0x64, 0x5d, 0xc7, 0xbf,
- 0xff, 0x27, 0xc0, 0x81, 0xf0, 0xd5, 0x21, 0xaf, 0x8f, 0x9a, 0xab, 0x6d,
- 0x06, 0x60, 0xe3, 0x0d, 0xcf, 0xdf, 0x56, 0x8a, 0x6e, 0x1d, 0xe5, 0x2c,
- 0xf9, 0x70, 0xfe, 0x77, 0xb3, 0x11, 0x42, 0x0e, 0xb4, 0x3a, 0xc7, 0xab,
- 0xa4, 0x6f, 0xc2, 0xdd, 0xca, 0x51, 0xc7, 0x97, 0x05, 0xef, 0xb3, 0x8d,
- 0x67, 0x27, 0x9a, 0xcd, 0xb3, 0xd6, 0x07, 0xad, 0x99, 0xf5, 0x6d, 0x4f,
- 0x5a, 0xf9, 0xdd, 0x15, 0x27, 0xef, 0xd5, 0xcc, 0xbe, 0xbd, 0xc3, 0xad,
- 0x99, 0xd5, 0x76, 0xac, 0xad, 0x99, 0x59, 0xdb, 0xdd, 0x9a, 0xd9, 0xfc,
- 0xee, 0x02, 0x3e, 0x6e, 0xcd, 0x2c, 0xbb, 0xdd, 0xad, 0x99, 0x95, 0xb7,
- 0xbb, 0x35, 0x33, 0x67, 0x87, 0x5b, 0x33, 0xfb, 0xf9, 0xf6, 0xb5, 0x35,
- 0xb3, 0x1f, 0xec, 0x58, 0x5b, 0x33, 0xbb, 0xb8, 0x3b, 0x87, 0xcf, 0xdd,
- 0x9a, 0xd9, 0xcf, 0x76, 0xdc, 0xbb, 0x66, 0xf6, 0x9a, 0x8f, 0xd7, 0x31,
- 0x9f, 0x11, 0xcc, 0x21, 0x0e, 0xbc, 0x3e, 0x0c, 0xbc, 0xfe, 0x6e, 0x75,
- 0xfe, 0x00, 0xe6, 0x39, 0xe8, 0xc5, 0x83, 0x0f, 0x82, 0xdb, 0x47, 0xbc,
- 0x67, 0x6d, 0xe4, 0xbb, 0x11, 0x2f, 0x57, 0x21, 0x76, 0xdf, 0xec, 0xe5,
- 0x6c, 0xff, 0xa8, 0xf3, 0xee, 0xb9, 0x97, 0xd6, 0xef, 0x0f, 0x21, 0xf5,
- 0xf6, 0xf1, 0x3c, 0xe7, 0x95, 0x47, 0xee, 0x47, 0x39, 0xd8, 0xe8, 0x3f,
- 0xbf, 0xfb, 0x1b, 0x16, 0x31, 0xfe, 0x73, 0x58, 0xab, 0xf6, 0x16, 0x43,
- 0x9d, 0x01, 0x60, 0x8c, 0x3a, 0x2e, 0x29, 0xf4, 0x4f, 0xa9, 0xfe, 0xd7,
- 0x5a, 0xfa, 0xaf, 0xa0, 0x3f, 0xe9, 0x46, 0xff, 0x1d, 0x3e, 0x2f, 0x29,
- 0xfb, 0xb6, 0x5c, 0x0c, 0x9f, 0x2e, 0xf9, 0x78, 0x2b, 0xe0, 0x61, 0xe7,
- 0x46, 0xc6, 0x76, 0x3e, 0x8f, 0x67, 0xa2, 0x17, 0x6d, 0xb9, 0xa9, 0xf0,
- 0xbb, 0x91, 0x88, 0x5e, 0xcc, 0xaa, 0x7c, 0xad, 0x91, 0xc9, 0x39, 0x7e,
- 0xfe, 0x8d, 0x1c, 0x6a, 0x80, 0x39, 0x0c, 0xec, 0x7d, 0x69, 0x10, 0x71,
- 0xac, 0x35, 0xc7, 0x66, 0x5e, 0xad, 0x7b, 0x79, 0xb5, 0x29, 0x9f, 0xd9,
- 0xd9, 0x8a, 0xcd, 0x2f, 0xee, 0xfe, 0xc7, 0x0a, 0x9b, 0x6f, 0x42, 0x6e,
- 0x4e, 0xec, 0x4d, 0x1c, 0x43, 0x0c, 0x41, 0x7c, 0xce, 0x7a, 0x01, 0xf3,
- 0x19, 0xc6, 0x46, 0xe6, 0x37, 0x21, 0x7c, 0x78, 0x26, 0xc9, 0xc7, 0xe8,
- 0xed, 0x9e, 0x7f, 0x67, 0x5e, 0xe4, 0x63, 0x95, 0xe4, 0x26, 0x37, 0x37,
- 0xda, 0xa4, 0xb9, 0xf9, 0x67, 0xc4, 0xeb, 0x13, 0x58, 0xc5, 0xc2, 0x81,
- 0x55, 0x2c, 0xbc, 0x66, 0x1f, 0x4b, 0xd4, 0xf9, 0x27, 0xb5, 0x1f, 0xc6,
- 0xfd, 0xb1, 0x46, 0xe6, 0xca, 0x80, 0x68, 0x7a, 0x82, 0xfb, 0x64, 0xc0,
- 0x3a, 0x16, 0xf7, 0xcd, 0xe8, 0x3b, 0xf7, 0x69, 0xa9, 0x2a, 0xe3, 0x0f,
- 0xf1, 0x91, 0xbf, 0x17, 0xee, 0xeb, 0x89, 0xb2, 0x63, 0xdb, 0x1f, 0x6b,
- 0xc8, 0x79, 0xe3, 0xed, 0xd6, 0x53, 0xe0, 0x25, 0x83, 0x6f, 0x5f, 0xa6,
- 0x9f, 0x55, 0xb1, 0xaf, 0x03, 0xb6, 0x7b, 0xa4, 0x44, 0xec, 0xba, 0x59,
- 0x6a, 0x1e, 0x7e, 0x3d, 0x37, 0xef, 0x62, 0xd7, 0xc0, 0x5a, 0xec, 0x1a,
- 0x5f, 0x16, 0x97, 0xc7, 0x5d, 0x1b, 0xf2, 0x48, 0xbc, 0x4a, 0xfe, 0x18,
- 0x77, 0xf6, 0xc2, 0xff, 0x35, 0x80, 0x69, 0x19, 0x73, 0x18, 0x6f, 0x22,
- 0xc0, 0xf6, 0xf7, 0xe2, 0x4f, 0xb5, 0x1d, 0xea, 0xb0, 0x82, 0xf8, 0x4c,
- 0xc3, 0x7f, 0x4c, 0xe0, 0x99, 0x8c, 0xcc, 0x9e, 0xfe, 0x1a, 0xe6, 0x36,
- 0x2d, 0x57, 0xe6, 0x27, 0xc1, 0xdf, 0x73, 0x32, 0x17, 0xcf, 0xc3, 0x8f,
- 0x70, 0xcf, 0x83, 0xb8, 0xad, 0xdf, 0xfb, 0x9e, 0xd6, 0xcf, 0x5a, 0x51,
- 0xe2, 0x46, 0xa9, 0x16, 0xe9, 0x83, 0xb9, 0x67, 0xc8, 0xbd, 0x61, 0xda,
- 0x0f, 0xeb, 0x27, 0xc8, 0x5d, 0x99, 0xc3, 0x9e, 0xe2, 0xf8, 0x6b, 0x75,
- 0xb2, 0xec, 0x10, 0x7f, 0x35, 0x32, 0x8d, 0x25, 0xe2, 0xc7, 0xf7, 0x8b,
- 0x25, 0xa9, 0x07, 0xe2, 0xc9, 0xfb, 0xc1, 0x91, 0xd1, 0x79, 0x60, 0xc8,
- 0x57, 0x1a, 0x7a, 0x2b, 0x8e, 0x74, 0x31, 0x64, 0x72, 0x29, 0x0b, 0x9a,
- 0x71, 0x85, 0x95, 0x91, 0xc7, 0xc1, 0xed, 0xf5, 0xe3, 0xd9, 0x7e, 0xe4,
- 0xe4, 0x2e, 0x66, 0x4c, 0x01, 0x33, 0xfe, 0x06, 0x30, 0xe3, 0xac, 0x74,
- 0x76, 0x11, 0x33, 0xda, 0x1e, 0x66, 0x4c, 0xc3, 0x9e, 0x73, 0x6b, 0xec,
- 0x59, 0x53, 0xb5, 0x28, 0xde, 0xcb, 0x01, 0xf3, 0xa5, 0x4e, 0x45, 0xef,
- 0x03, 0x27, 0x6a, 0x12, 0x52, 0xe7, 0x52, 0x02, 0x2d, 0x34, 0x7d, 0x3c,
- 0xb8, 0x4d, 0xe1, 0xbc, 0xdd, 0xa5, 0x4d, 0xc8, 0x51, 0x14, 0xee, 0xf3,
- 0xf6, 0x4b, 0x03, 0xeb, 0xf6, 0x90, 0x03, 0x2d, 0x7b, 0xc8, 0x77, 0xf1,
- 0x21, 0x9e, 0xf3, 0x6a, 0x7d, 0x6d, 0xf0, 0x05, 0xff, 0x13, 0x3c, 0x71,
- 0x7d, 0x71, 0x2d, 0x68, 0xee, 0x7a, 0x59, 0x83, 0x13, 0xff, 0x7a, 0x1d,
- 0x4e, 0x44, 0xec, 0x3a, 0x17, 0x92, 0x24, 0x30, 0xa2, 0xbd, 0x44, 0x5a,
- 0x5c, 0xd3, 0xc3, 0xd2, 0x8e, 0xf9, 0x75, 0x9c, 0xea, 0x05, 0x36, 0xea,
- 0x92, 0x20, 0x30, 0x52, 0x9b, 0xc2, 0x48, 0x03, 0xc4, 0x32, 0x83, 0x33,
- 0xc0, 0x36, 0xb5, 0x55, 0x9c, 0x14, 0x8d, 0xff, 0x01, 0xf4, 0xf2, 0x94,
- 0xf2, 0x3d, 0x69, 0x39, 0x01, 0x5f, 0xda, 0xbe, 0x04, 0x7c, 0x77, 0xce,
- 0xc5, 0x4f, 0x6d, 0xeb, 0xf0, 0xd3, 0xc1, 0x0d, 0xf1, 0x93, 0xaa, 0xdf,
- 0x8f, 0x52, 0x26, 0x37, 0x1c, 0xb7, 0x7e, 0x7f, 0xdd, 0x71, 0xeb, 0xf7,
- 0x37, 0x9c, 0xd6, 0xfa, 0xfd, 0x47, 0xa4, 0x60, 0x46, 0xed, 0x15, 0x59,
- 0x57, 0xbf, 0x9f, 0x60, 0x3d, 0xdc, 0xe9, 0x72, 0xeb, 0xf4, 0x5d, 0x5e,
- 0xfd, 0x3e, 0x2a, 0x85, 0x35, 0xed, 0xa6, 0xbc, 0x69, 0xf9, 0xf5, 0xfb,
- 0xef, 0xa2, 0xad, 0x1b, 0x63, 0xac, 0xad, 0xdd, 0x5f, 0x77, 0x58, 0xbb,
- 0x0f, 0xb1, 0x9f, 0x57, 0xbb, 0x67, 0x3f, 0xe4, 0xf2, 0x0e, 0xeb, 0xf6,
- 0x8f, 0x40, 0x16, 0x5b, 0x21, 0x87, 0x5e, 0x69, 0x3f, 0x13, 0x66, 0x1f,
- 0x55, 0xaf, 0x5f, 0x71, 0x42, 0x78, 0xce, 0xad, 0xab, 0xcf, 0xc0, 0xae,
- 0x0e, 0xae, 0xd6, 0xeb, 0xdd, 0x31, 0x6e, 0x3a, 0x6b, 0xe9, 0xaf, 0xa5,
- 0xd3, 0xe7, 0xd1, 0x09, 0x81, 0x4e, 0x78, 0x1d, 0x9d, 0xbb, 0xf5, 0xf9,
- 0x9b, 0x8e, 0x5b, 0x9b, 0x4f, 0x9f, 0x16, 0xbb, 0x1d, 0xbe, 0xf9, 0xe2,
- 0xc0, 0xc3, 0x1e, 0x8d, 0xd5, 0xda, 0x3c, 0x7d, 0x08, 0x70, 0x7b, 0x4c,
- 0x9d, 0xbd, 0x9a, 0xf9, 0x7f, 0x50, 0x9b, 0x67, 0x5d, 0xde, 0xdd, 0x5f,
- 0xe1, 0xfa, 0x04, 0x3e, 0x7f, 0xd1, 0xad, 0xc9, 0x8f, 0x95, 0xfc, 0x5a,
- 0x3b, 0xf3, 0x47, 0xff, 0x5c, 0x54, 0x7f, 0xe4, 0x88, 0xd0, 0x56, 0xc8,
- 0x1f, 0xe9, 0x76, 0xcb, 0x94, 0xc2, 0x47, 0xb0, 0xa9, 0xd8, 0xbd, 0x31,
- 0x72, 0xe5, 0x94, 0x8f, 0x91, 0x43, 0x0a, 0x23, 0x57, 0x96, 0x7c, 0x8c,
- 0x9c, 0xbc, 0x07, 0x46, 0x6e, 0x76, 0xb9, 0x71, 0x20, 0x28, 0x79, 0x85,
- 0x91, 0xef, 0x75, 0x96, 0x8c, 0xf7, 0xba, 0x88, 0x07, 0xc4, 0x3d, 0x5f,
- 0xd0, 0x7b, 0x8f, 0xb5, 0xe6, 0xe3, 0x66, 0xc6, 0xfe, 0xad, 0x32, 0x71,
- 0xe6, 0x2e, 0x6e, 0x76, 0xb1, 0x71, 0x34, 0x72, 0x48, 0xc5, 0x44, 0xe0,
- 0x84, 0x3a, 0xeb, 0xdf, 0xc4, 0xbe, 0x8c, 0x39, 0x01, 0x85, 0xcf, 0x72,
- 0x45, 0xe6, 0x01, 0x6c, 0x23, 0x16, 0xee, 0xe4, 0x31, 0x2b, 0x2f, 0x26,
- 0xf9, 0x58, 0xd3, 0x3f, 0xd7, 0xc2, 0x3d, 0x86, 0x37, 0x8d, 0xa4, 0x85,
- 0x76, 0xc7, 0xcf, 0x15, 0xe2, 0xea, 0x3c, 0x50, 0x12, 0x58, 0x72, 0x6a,
- 0x15, 0x4b, 0xd2, 0x57, 0xfc, 0xf4, 0x6d, 0xdb, 0xa4, 0x5f, 0xf3, 0xb1,
- 0x22, 0x72, 0xa2, 0x12, 0xd7, 0xb6, 0x8f, 0x15, 0x5d, 0x9c, 0x98, 0x72,
- 0x1a, 0xc0, 0xcb, 0x01, 0x19, 0x03, 0x4e, 0x6f, 0x7c, 0x89, 0x35, 0x28,
- 0x1f, 0x1b, 0xd9, 0xf8, 0x6e, 0xad, 0x49, 0xf1, 0xba, 0x5d, 0xed, 0x05,
- 0x5e, 0x1e, 0x08, 0xb6, 0xb4, 0x3f, 0x0b, 0xff, 0x8d, 0xfc, 0x08, 0xd8,
- 0xc4, 0xc5, 0x44, 0x3b, 0xa0, 0x83, 0x91, 0x7b, 0x60, 0xa2, 0xf5, 0x31,
- 0x8a, 0x31, 0xf3, 0x6e, 0x8c, 0x4a, 0xd7, 0xe9, 0xcf, 0xef, 0xc6, 0xa8,
- 0x7b, 0xc7, 0x50, 0xb6, 0x61, 0x76, 0x56, 0x06, 0x9f, 0x69, 0x29, 0xac,
- 0x8b, 0x51, 0x73, 0x1f, 0x20, 0x46, 0xb9, 0xf8, 0xc0, 0xe5, 0xfb, 0xf7,
- 0x21, 0x9b, 0x1f, 0x43, 0xa6, 0x3f, 0x02, 0xe6, 0xfa, 0x21, 0xe6, 0xf5,
- 0x03, 0xe0, 0xa1, 0xef, 0x97, 0xd6, 0x9f, 0x07, 0x19, 0x15, 0xe6, 0x87,
- 0x2e, 0x66, 0x72, 0x31, 0xfd, 0x0c, 0x56, 0x57, 0xad, 0xd8, 0xc8, 0x4c,
- 0x15, 0x87, 0xcc, 0x69, 0x77, 0x1f, 0x35, 0x92, 0x95, 0xa7, 0x3b, 0x53,
- 0x8b, 0x8c, 0x19, 0xea, 0x3a, 0xcc, 0xfa, 0x25, 0xb1, 0x43, 0x55, 0xe5,
- 0x99, 0x03, 0x52, 0xae, 0xb9, 0x78, 0x6b, 0x6e, 0xd1, 0xa5, 0x31, 0xe5,
- 0xe1, 0xad, 0x9c, 0x87, 0xb7, 0xb2, 0xb5, 0xe5, 0x48, 0x00, 0xfd, 0xe7,
- 0xe2, 0x6b, 0x31, 0xd6, 0x8c, 0x87, 0xb1, 0xa6, 0x3f, 0x20, 0xc6, 0xe2,
- 0x58, 0x39, 0x3c, 0x33, 0x3e, 0x1f, 0x91, 0x5d, 0x90, 0xf3, 0x58, 0x91,
- 0xfa, 0xe2, 0x19, 0xb2, 0xf7, 0xd2, 0x19, 0xf5, 0xe5, 0xea, 0x2a, 0x10,
- 0xdb, 0xa7, 0x8d, 0x43, 0x57, 0x63, 0xef, 0xa9, 0x2b, 0x31, 0xdf, 0x18,
- 0x09, 0xe2, 0xf3, 0xf7, 0xa5, 0x2b, 0xce, 0x83, 0xfa, 0x5a, 0x8f, 0xc5,
- 0xee, 0x07, 0x93, 0xad, 0xc5, 0x63, 0xb6, 0xc2, 0x63, 0xed, 0x5e, 0x1f,
- 0xd9, 0x33, 0x0e, 0x5d, 0xfe, 0x27, 0xf4, 0xf9, 0x99, 0xd5, 0x2d, 0x3f,
- 0x85, 0xff, 0xfe, 0x43, 0xe8, 0xe4, 0x3f, 0x22, 0x57, 0x78, 0xcd, 0xea,
- 0x93, 0x3f, 0x40, 0xdb, 0x5d, 0x9c, 0xc3, 0xfe, 0xc1, 0xc7, 0x92, 0xd6,
- 0x35, 0xe0, 0x93, 0x6b, 0x1e, 0x3e, 0x79, 0x3a, 0x99, 0xb4, 0x26, 0x59,
- 0x37, 0x87, 0x9c, 0x0f, 0xa4, 0xa6, 0x14, 0x36, 0xf1, 0x31, 0xc9, 0xed,
- 0x34, 0xc7, 0x9f, 0x75, 0x56, 0x80, 0x7d, 0x56, 0x3c, 0xec, 0x73, 0x60,
- 0xcc, 0xc5, 0x3e, 0xc1, 0xcf, 0x50, 0xff, 0x2e, 0xee, 0x59, 0xb1, 0x93,
- 0x18, 0xa7, 0x0a, 0x4c, 0x52, 0x71, 0x0e, 0x48, 0xbe, 0xbe, 0x57, 0x7d,
- 0x8e, 0x94, 0xec, 0x68, 0x1b, 0xe4, 0xc4, 0xda, 0xeb, 0x49, 0xae, 0x4a,
- 0x27, 0x6a, 0x16, 0xf1, 0x9d, 0x75, 0xa2, 0xe1, 0xdf, 0xf1, 0xae, 0x9f,
- 0xf7, 0xae, 0x4f, 0x78, 0xd7, 0xc7, 0x11, 0x87, 0x8f, 0xa9, 0x58, 0xca,
- 0x76, 0xb6, 0x41, 0xc9, 0x0e, 0x68, 0x01, 0x7b, 0x9c, 0x1d, 0xfe, 0x8b,
- 0x66, 0x59, 0xe9, 0x98, 0xf4, 0x27, 0xf0, 0x39, 0x8e, 0xcf, 0x34, 0x3e,
- 0xfb, 0xf1, 0xc9, 0xe3, 0xb3, 0x2a, 0x53, 0x2d, 0x55, 0x9a, 0x84, 0x8d,
- 0x0c, 0x4a, 0xaa, 0xfe, 0x12, 0xf4, 0xf8, 0x1c, 0x74, 0x7b, 0x58, 0x0a,
- 0xd5, 0x3f, 0x95, 0xd9, 0x79, 0x4d, 0xba, 0x2c, 0xe8, 0xb4, 0x0a, 0x5b,
- 0x9e, 0x77, 0xf7, 0x13, 0x3b, 0x13, 0x7b, 0xd1, 0xb7, 0x29, 0x4f, 0xc5,
- 0x9f, 0x13, 0xfd, 0xb1, 0x39, 0xf4, 0x13, 0xbd, 0x30, 0xfc, 0x31, 0xb5,
- 0x6f, 0x56, 0x8d, 0xbb, 0x32, 0xde, 0x65, 0xd9, 0x51, 0xe8, 0x7c, 0xf0,
- 0x18, 0x68, 0x27, 0xd5, 0xd9, 0xd8, 0x8c, 0x1c, 0x3d, 0xbd, 0xbc, 0xc5,
- 0xf5, 0xad, 0x51, 0xf3, 0x26, 0xf5, 0x8e, 0x79, 0xd8, 0xf0, 0x85, 0x19,
- 0xd8, 0xfb, 0x41, 0x27, 0xa0, 0x8d, 0x21, 0xde, 0x8c, 0x39, 0x37, 0x55,
- 0xbc, 0x81, 0xef, 0xca, 0xc4, 0x4e, 0x86, 0x70, 0xcd, 0xb3, 0x45, 0x88,
- 0x8b, 0xea, 0x6c, 0xe5, 0x32, 0xf0, 0x8d, 0xa6, 0xea, 0x80, 0xb3, 0xab,
- 0xfb, 0x43, 0x86, 0xf2, 0x5b, 0xb1, 0x98, 0x2e, 0xb9, 0x11, 0xe2, 0xdc,
- 0xbd, 0x2a, 0x36, 0xd5, 0x8a, 0xf6, 0x43, 0xcc, 0x15, 0x6f, 0x08, 0xe3,
- 0xdc, 0xe3, 0xe8, 0xd7, 0x07, 0x7f, 0x8c, 0x7b, 0x75, 0xda, 0x27, 0xe7,
- 0xca, 0x67, 0xa6, 0xa5, 0x5a, 0x1e, 0xc5, 0x7c, 0xbd, 0x1c, 0x49, 0xe5,
- 0x12, 0x11, 0xd8, 0xa3, 0xbf, 0x17, 0xe5, 0xd6, 0x4f, 0xaa, 0x8e, 0x8f,
- 0x29, 0xba, 0xd1, 0x87, 0x79, 0x05, 0x64, 0xe4, 0xee, 0x9f, 0xa9, 0xbd,
- 0xb3, 0x82, 0x33, 0x0a, 0x39, 0x25, 0xd1, 0xce, 0x5a, 0x35, 0x7e, 0x97,
- 0x75, 0x55, 0x13, 0x58, 0x31, 0x66, 0xa4, 0x56, 0x6e, 0x82, 0x5f, 0xc4,
- 0xdc, 0x2d, 0x33, 0x52, 0x29, 0x4f, 0xcb, 0x2b, 0xe5, 0x9f, 0x77, 0x03,
- 0x53, 0x41, 0xa6, 0xe4, 0xbf, 0x5b, 0xee, 0x9e, 0xbf, 0xf5, 0xdb, 0x21,
- 0xcf, 0xd3, 0xf9, 0xb0, 0x9b, 0xe7, 0xe6, 0x55, 0x2d, 0xc6, 0xfd, 0xb6,
- 0xf5, 0x29, 0x2b, 0x1a, 0x9e, 0x45, 0xcf, 0x83, 0x0b, 0xb4, 0xcd, 0xfc,
- 0xf8, 0x9c, 0xb5, 0x43, 0xae, 0xc6, 0x37, 0xcb, 0x72, 0x5c, 0xe5, 0xc5,
- 0xc4, 0x0f, 0x58, 0xeb, 0x51, 0xb3, 0x21, 0x7b, 0xe4, 0x28, 0xd6, 0xed,
- 0xd5, 0xf8, 0xd3, 0xb0, 0xd3, 0x67, 0x61, 0x0b, 0xac, 0x01, 0x1c, 0x62,
- 0xae, 0x25, 0x0d, 0x55, 0x23, 0x6b, 0x36, 0xc7, 0xd5, 0x19, 0xee, 0x76,
- 0x59, 0x56, 0x58, 0xcc, 0xad, 0x9d, 0x2f, 0x4f, 0xba, 0x6b, 0xc4, 0x50,
- 0x76, 0xff, 0xc7, 0xe0, 0xc7, 0x84, 0xed, 0xb6, 0xa9, 0x3e, 0x46, 0xa2,
- 0xc3, 0xeb, 0xa3, 0xf4, 0xdb, 0xd2, 0xe7, 0x95, 0x44, 0xd2, 0xda, 0xff,
- 0x89, 0xa4, 0x75, 0x73, 0xb7, 0x5b, 0x6f, 0x89, 0x9a, 0xb6, 0xc6, 0xf7,
- 0x52, 0xdc, 0xf5, 0x98, 0xc1, 0xba, 0xba, 0xb4, 0x8a, 0xa1, 0x61, 0xa4,
- 0x2f, 0x5f, 0x81, 0x7e, 0x03, 0xd2, 0x7e, 0xb2, 0xf9, 0xf8, 0x54, 0x7c,
- 0x28, 0x72, 0x50, 0x78, 0x02, 0x8b, 0x79, 0x75, 0x34, 0x9e, 0x95, 0x2b,
- 0x88, 0x93, 0x77, 0x88, 0x1d, 0x06, 0x2f, 0xcb, 0x9d, 0xc7, 0x93, 0xf1,
- 0x51, 0xad, 0x32, 0x89, 0xac, 0xe5, 0xe5, 0x49, 0xc6, 0xd9, 0x43, 0x22,
- 0xc0, 0x97, 0x27, 0x47, 0x24, 0x5d, 0x54, 0xef, 0xa9, 0xf0, 0x9c, 0xad,
- 0x36, 0x0d, 0xf9, 0xe1, 0xf9, 0x09, 0x06, 0x46, 0xdd, 0xea, 0x8f, 0xa4,
- 0xe5, 0x69, 0xd6, 0xc0, 0x24, 0xb7, 0x20, 0xdb, 0x92, 0xf0, 0xab, 0xf6,
- 0x44, 0xbb, 0x4c, 0xd7, 0x1a, 0x99, 0xfe, 0x53, 0xcf, 0x82, 0xc6, 0x14,
- 0x68, 0xed, 0x45, 0x6e, 0x92, 0x45, 0xac, 0xa6, 0x7c, 0xe9, 0xbb, 0x9f,
- 0x81, 0x8c, 0x3e, 0xc2, 0x3d, 0xe5, 0xd1, 0xac, 0x44, 0x27, 0xf2, 0x8a,
- 0xee, 0x5b, 0x5a, 0x6e, 0xf8, 0x57, 0x10, 0xeb, 0x02, 0xb2, 0x2b, 0x26,
- 0xfa, 0xde, 0x58, 0xe0, 0xed, 0x29, 0x8b, 0x6d, 0x41, 0xb6, 0xe9, 0x68,
- 0x0b, 0xfc, 0x7a, 0x2c, 0xa8, 0x27, 0x63, 0xd1, 0x51, 0x9e, 0x8f, 0x36,
- 0xac, 0x29, 0xee, 0x4d, 0x3c, 0x20, 0x5d, 0x7b, 0xa5, 0xe7, 0x42, 0x74,
- 0xf4, 0x06, 0x78, 0x09, 0x28, 0x5f, 0x3f, 0x25, 0xba, 0xd7, 0xde, 0xbd,
- 0xda, 0x1e, 0xf0, 0xda, 0xf7, 0x4a, 0xd7, 0x85, 0x21, 0xf3, 0x75, 0x99,
- 0x01, 0x4d, 0x43, 0xae, 0x23, 0xd7, 0xb1, 0x06, 0xa6, 0x60, 0x8b, 0x4f,
- 0x92, 0x97, 0xfd, 0xc0, 0x1a, 0x58, 0x1b, 0xc8, 0xbf, 0xad, 0x0f, 0xcb,
- 0x57, 0xcd, 0x4e, 0xc9, 0xa9, 0x5c, 0x37, 0xe0, 0xd6, 0x52, 0x61, 0xef,
- 0x8f, 0x0e, 0x1c, 0xec, 0x71, 0xeb, 0x05, 0xdc, 0xef, 0x18, 0x46, 0xdb,
- 0x9d, 0xe6, 0x39, 0x8b, 0x6d, 0xbc, 0x77, 0xa7, 0x59, 0xb5, 0x86, 0xcc,
- 0x94, 0x16, 0xf4, 0xf6, 0xbd, 0x0f, 0xa9, 0xb9, 0xe7, 0xcb, 0xfd, 0x66,
- 0x45, 0x1e, 0xd5, 0x52, 0x0f, 0x22, 0x5e, 0x38, 0xd3, 0xe8, 0x7b, 0x87,
- 0xe7, 0x29, 0x54, 0x7d, 0xbf, 0x22, 0xfe, 0x35, 0xe9, 0x0c, 0x99, 0xe3,
- 0xea, 0xd9, 0x21, 0xf3, 0xa8, 0xd6, 0xfa, 0x6c, 0x58, 0x1b, 0x5f, 0xf3,
- 0x6c, 0x97, 0x92, 0x91, 0x61, 0xb9, 0x7d, 0x66, 0xcb, 0x7b, 0xe5, 0x79,
- 0x87, 0xfd, 0xee, 0x34, 0x53, 0xd6, 0x03, 0xda, 0xd1, 0x07, 0xe9, 0x0b,
- 0xd9, 0xf7, 0xf6, 0xba, 0x71, 0x78, 0x7d, 0xaf, 0x31, 0x9a, 0xb2, 0x76,
- 0x8c, 0x4d, 0xaa, 0xcf, 0x55, 0xd5, 0x27, 0xa0, 0x64, 0xbd, 0x76, 0x9c,
- 0xbf, 0x91, 0xb5, 0xe3, 0x74, 0xad, 0xce, 0x79, 0x16, 0x34, 0x8f, 0xa1,
- 0x6f, 0xd1, 0xe9, 0x0f, 0x57, 0xe5, 0x76, 0x33, 0x67, 0xbd, 0x29, 0x57,
- 0x57, 0x69, 0xff, 0x12, 0xd7, 0xad, 0x3c, 0xfd, 0xd2, 0xe3, 0x91, 0xbf,
- 0xd9, 0xf6, 0x2f, 0x95, 0xbc, 0x1f, 0xb0, 0xfa, 0xf7, 0x57, 0xb4, 0xe8,
- 0xe8, 0x5f, 0x0a, 0x75, 0xf5, 0xcf, 0x94, 0xaf, 0xf9, 0x18, 0xf4, 0xb4,
- 0xed, 0x05, 0xac, 0xdd, 0xe1, 0xa4, 0xea, 0x73, 0xdd, 0xda, 0x2b, 0xdb,
- 0x4e, 0xf6, 0x9b, 0xd7, 0xe5, 0x33, 0x92, 0x0e, 0xf1, 0x1a, 0x39, 0x94,
- 0xc5, 0xf7, 0x52, 0x3e, 0xc1, 0xbc, 0x00, 0xba, 0xec, 0x1f, 0xfc, 0x4b,
- 0x79, 0x56, 0x8e, 0x96, 0xe6, 0xe0, 0x7b, 0xa6, 0x64, 0xf0, 0x05, 0xfa,
- 0x9f, 0xbc, 0xe9, 0xd6, 0x6a, 0xdc, 0x98, 0x98, 0xf2, 0x62, 0xe2, 0x9c,
- 0xf2, 0x73, 0xaf, 0x79, 0xe7, 0x22, 0xfa, 0x07, 0xcf, 0xe1, 0xd9, 0x57,
- 0x94, 0x0f, 0xf8, 0x3d, 0xa9, 0x62, 0x2d, 0x44, 0x5e, 0xde, 0x2c, 0x0f,
- 0x3c, 0x41, 0x9b, 0x44, 0x06, 0xf0, 0xb1, 0x36, 0xf5, 0x1e, 0x8c, 0x6e,
- 0x75, 0x88, 0x6c, 0xa1, 0xfd, 0x5c, 0x86, 0xad, 0x4d, 0xb9, 0x7b, 0x5f,
- 0x6b, 0xae, 0xa3, 0x13, 0x2b, 0xf2, 0x1f, 0x94, 0x1d, 0x7e, 0xfc, 0x82,
- 0xfb, 0x3d, 0x7c, 0x01, 0xe9, 0x72, 0x6c, 0xaf, 0x6c, 0xbf, 0xe0, 0xda,
- 0xdd, 0xec, 0xfc, 0xb3, 0x4a, 0xbe, 0x53, 0x4a, 0xbe, 0x4d, 0x99, 0x89,
- 0x53, 0xf6, 0x9c, 0x13, 0xcf, 0x4f, 0xba, 0x32, 0xf9, 0x9c, 0x67, 0x47,
- 0xfd, 0x2f, 0xf0, 0x3d, 0x35, 0xca, 0x88, 0x7c, 0xcf, 0xf4, 0x70, 0x3f,
- 0x76, 0xdb, 0x05, 0xce, 0xb7, 0x6f, 0xcd, 0x7c, 0x4f, 0xc0, 0xc7, 0x0e,
- 0x0c, 0xb8, 0x73, 0x7e, 0x6d, 0xfe, 0xfd, 0xcf, 0xf9, 0x77, 0x57, 0xe7,
- 0x6c, 0x48, 0x55, 0xe5, 0xb9, 0xb1, 0xcd, 0xd2, 0x95, 0x93, 0x06, 0xec,
- 0xe3, 0xcf, 0x85, 0x67, 0xc6, 0xc9, 0x8b, 0x3b, 0xee, 0xb2, 0x43, 0x9e,
- 0xfc, 0x39, 0x90, 0xaf, 0x29, 0x4f, 0x7f, 0xe4, 0xe3, 0xd9, 0x0d, 0xef,
- 0x5d, 0x97, 0x46, 0x66, 0x10, 0x6d, 0xba, 0xd2, 0xe1, 0x98, 0xb7, 0xde,
- 0xf6, 0x8a, 0xae, 0x74, 0x98, 0x5c, 0xd5, 0xe1, 0x0d, 0xe8, 0xb0, 0x2a,
- 0x9f, 0xc6, 0x9c, 0xb0, 0xbe, 0x5f, 0x18, 0x32, 0x67, 0x64, 0xab, 0xd2,
- 0xbf, 0x35, 0x00, 0x9f, 0xea, 0xe9, 0xb2, 0xfd, 0x3e, 0x74, 0xf9, 0xba,
- 0x28, 0x7d, 0xaa, 0x73, 0x44, 0x55, 0x45, 0x87, 0xbe, 0x8d, 0x73, 0x6b,
- 0x57, 0x3e, 0x81, 0x3c, 0xaa, 0xb3, 0x01, 0x13, 0xae, 0x7e, 0xd5, 0x9a,
- 0xf7, 0xf4, 0x9b, 0x9d, 0xa0, 0x0e, 0x7f, 0xad, 0xc7, 0xd5, 0x67, 0x87,
- 0xea, 0x73, 0x2a, 0x36, 0xaa, 0xd6, 0xbb, 0x35, 0xf0, 0xe9, 0x1e, 0xea,
- 0xf4, 0x79, 0xc7, 0xfd, 0x2e, 0x22, 0xce, 0x9d, 0x72, 0xde, 0x4b, 0xaf,
- 0xae, 0x4e, 0xc7, 0xc4, 0x5d, 0x57, 0xeb, 0xf5, 0xa9, 0x5f, 0x08, 0x28,
- 0x1b, 0x1e, 0x83, 0x0c, 0x8f, 0x97, 0x1e, 0xf4, 0xec, 0xde, 0x9d, 0xf3,
- 0xc0, 0xfb, 0x9c, 0xf3, 0x91, 0x62, 0xbf, 0xf9, 0x26, 0xee, 0x8d, 0x63,
- 0xce, 0x33, 0xd2, 0x26, 0x29, 0x6f, 0xce, 0x91, 0xd5, 0x39, 0xfb, 0x3c,
- 0xba, 0xfd, 0x52, 0xcc, 0x63, 0x1d, 0xfa, 0xaf, 0x7f, 0xab, 0xde, 0x37,
- 0xb9, 0x59, 0xa4, 0xdf, 0x06, 0x56, 0x0a, 0xf5, 0xca, 0xf5, 0x5a, 0x44,
- 0xae, 0x13, 0x83, 0x8c, 0xe0, 0xdb, 0x99, 0xf3, 0x62, 0x78, 0x50, 0x5e,
- 0x2f, 0x6e, 0xc4, 0xc7, 0xb0, 0xdc, 0x28, 0xfa, 0xbc, 0x10, 0x0b, 0x33,
- 0x5f, 0x98, 0x92, 0x37, 0xe6, 0xfb, 0xa5, 0x31, 0x81, 0xb8, 0x3f, 0x40,
- 0x99, 0x0c, 0x99, 0x7b, 0xd4, 0x7b, 0x48, 0x77, 0x9a, 0x97, 0x2d, 0xd0,
- 0x5f, 0x68, 0xca, 0x41, 0xee, 0x67, 0xf3, 0x77, 0xed, 0x21, 0x69, 0x30,
- 0xa7, 0x18, 0xe8, 0x95, 0xca, 0x02, 0xf2, 0xf9, 0x22, 0xe9, 0x53, 0x6e,
- 0x7b, 0xd5, 0xef, 0x71, 0x8c, 0xf7, 0x39, 0xbe, 0x1f, 0x10, 0xa2, 0x6e,
- 0xee, 0x34, 0x97, 0x2d, 0xee, 0x67, 0x4e, 0x49, 0x0d, 0xfa, 0xfb, 0xe7,
- 0x31, 0xee, 0xb7, 0xe7, 0xd4, 0xf9, 0xdb, 0x4a, 0x6d, 0x02, 0xb9, 0xc3,
- 0x9d, 0xe6, 0x9c, 0x75, 0x56, 0xe9, 0xad, 0x56, 0x7e, 0xc2, 0x6b, 0xe7,
- 0x35, 0xef, 0x35, 0x32, 0xdb, 0x06, 0x98, 0xaf, 0x3e, 0x81, 0x7c, 0x81,
- 0xb9, 0xea, 0x04, 0xf0, 0x1a, 0x65, 0x12, 0x91, 0xd9, 0x22, 0x69, 0x49,
- 0x68, 0x13, 0xf2, 0xfb, 0x9c, 0x8c, 0x83, 0x9f, 0x08, 0x72, 0x7b, 0xc6,
- 0x87, 0x47, 0x65, 0x39, 0xe4, 0xc6, 0x01, 0x9e, 0xfb, 0x5a, 0x46, 0x6c,
- 0x58, 0x5e, 0x8d, 0x0d, 0x5b, 0x71, 0xdd, 0xc8, 0xc4, 0x07, 0xfe, 0x06,
- 0xf4, 0x59, 0xb7, 0x61, 0x6c, 0x18, 0x45, 0x7f, 0xb6, 0xf5, 0xca, 0xec,
- 0x02, 0x92, 0x08, 0xe4, 0x2c, 0x15, 0xe1, 0x99, 0x8e, 0xac, 0x9c, 0xaa,
- 0xf5, 0x87, 0x2f, 0x6b, 0x69, 0x75, 0xf6, 0x23, 0x36, 0xc0, 0xf3, 0x2c,
- 0xbd, 0x52, 0x5b, 0x90, 0x88, 0x91, 0x78, 0x52, 0x9c, 0x9a, 0x8b, 0xd9,
- 0xe7, 0x34, 0x9e, 0x69, 0xb1, 0xa5, 0xb6, 0xb6, 0x8f, 0x89, 0xdc, 0x57,
- 0xbe, 0xe3, 0xf5, 0x49, 0xab, 0x3e, 0x7f, 0xdd, 0xc3, 0x3d, 0xb4, 0x9a,
- 0xd3, 0x03, 0x1e, 0xc8, 0xdb, 0xc3, 0xad, 0xe3, 0x46, 0xee, 0x8e, 0xcb,
- 0x31, 0x91, 0xcd, 0x6c, 0xb1, 0x31, 0xee, 0x4d, 0x3c, 0xf3, 0x24, 0xf8,
- 0xb8, 0x63, 0xe8, 0xd6, 0x93, 0x52, 0xa8, 0xad, 0x1f, 0xa3, 0x95, 0x07,
- 0x3e, 0x43, 0xfa, 0x1c, 0xe7, 0x00, 0xf8, 0xbb, 0xa3, 0xe9, 0xd6, 0x01,
- 0xc8, 0xd2, 0x1d, 0xc3, 0x38, 0x13, 0x35, 0x7f, 0x2a, 0x03, 0xa2, 0x9f,
- 0xd3, 0x94, 0xfc, 0xf5, 0xca, 0x30, 0x16, 0x48, 0x46, 0xba, 0x96, 0x26,
- 0xc5, 0x58, 0x62, 0x0d, 0xe1, 0xb5, 0xce, 0xb4, 0xda, 0xbf, 0xdd, 0x84,
- 0xf5, 0x2d, 0x76, 0xc0, 0x62, 0xbd, 0x80, 0xf5, 0xe0, 0x9f, 0x6e, 0x96,
- 0x1e, 0xd6, 0x0b, 0x98, 0x37, 0xec, 0xc7, 0x37, 0x73, 0x87, 0x4b, 0x4d,
- 0xe4, 0x7a, 0x9b, 0x19, 0x5f, 0x73, 0x35, 0xde, 0x8f, 0x46, 0x44, 0x78,
- 0x8f, 0x7e, 0xa3, 0x57, 0xda, 0xbe, 0x35, 0x08, 0x5f, 0xf1, 0x34, 0xb0,
- 0x37, 0xe8, 0x9e, 0x1c, 0x90, 0x80, 0x7b, 0x66, 0x42, 0xd5, 0x5b, 0xde,
- 0x58, 0x88, 0x7a, 0xef, 0x73, 0xc9, 0xb6, 0xcb, 0x71, 0xd6, 0x44, 0xfb,
- 0x58, 0xf3, 0x41, 0x3f, 0xd1, 0x97, 0x91, 0x9f, 0x5e, 0xaf, 0x59, 0x9b,
- 0x79, 0x7e, 0xf3, 0x86, 0x83, 0x6b, 0x62, 0xff, 0x90, 0xc2, 0x98, 0xde,
- 0x3d, 0xfe, 0x46, 0xbe, 0xf4, 0x8e, 0x77, 0x13, 0x98, 0x4f, 0x4d, 0x7a,
- 0x67, 0xe7, 0x1a, 0x99, 0xa3, 0x6b, 0x72, 0xaa, 0x41, 0x55, 0xef, 0x6d,
- 0x38, 0x16, 0xfc, 0xe3, 0x08, 0xec, 0x93, 0x6b, 0xa0, 0xa9, 0x3d, 0x01,
- 0x6c, 0x16, 0xe9, 0x55, 0x39, 0xd1, 0xf1, 0x27, 0xc4, 0xb5, 0x77, 0x58,
- 0x99, 0xf2, 0x65, 0x8d, 0xb2, 0x9b, 0x83, 0x2c, 0x97, 0x33, 0xf2, 0x47,
- 0xce, 0x15, 0x55, 0x6b, 0x9d, 0x47, 0x5e, 0x12, 0x38, 0xa5, 0x72, 0xb2,
- 0x16, 0x7c, 0x0b, 0xbf, 0xf7, 0xe2, 0xd7, 0xb1, 0x16, 0xa3, 0xea, 0x8c,
- 0x82, 0x7e, 0xae, 0xd9, 0x4c, 0xc1, 0x7f, 0xe8, 0x96, 0x65, 0x16, 0x10,
- 0x0f, 0x53, 0xea, 0x9c, 0x0b, 0xd7, 0xf1, 0x6f, 0x2b, 0xff, 0x2c, 0x15,
- 0xc8, 0xe6, 0x4c, 0x04, 0x74, 0x34, 0x65, 0x9f, 0x86, 0xd2, 0xc3, 0x13,
- 0x0a, 0xf3, 0x1a, 0xe7, 0xe0, 0xb0, 0x96, 0x06, 0x44, 0xce, 0x65, 0x64,
- 0x0e, 0x6b, 0x38, 0xb0, 0x44, 0x1d, 0x50, 0xb6, 0x93, 0xd2, 0x06, 0xd9,
- 0x1f, 0x01, 0xf6, 0x30, 0x4e, 0x51, 0xc6, 0x61, 0xac, 0x8b, 0x5e, 0x09,
- 0x9c, 0x81, 0x8c, 0x4f, 0x01, 0x23, 0x2c, 0xb4, 0xcb, 0xf7, 0x6a, 0xbe,
- 0x4c, 0x2f, 0xf1, 0x5c, 0xbf, 0x3e, 0x35, 0xd2, 0x47, 0x1c, 0x25, 0xd5,
- 0xda, 0x9c, 0xcc, 0x9d, 0x66, 0xce, 0x3e, 0xa9, 0xce, 0x0c, 0x04, 0xd4,
- 0x99, 0x15, 0x37, 0x67, 0x76, 0xbf, 0x5d, 0x8c, 0x59, 0x15, 0xee, 0xb5,
- 0x09, 0x6c, 0x67, 0x18, 0xe3, 0x6e, 0x24, 0x5f, 0x37, 0x57, 0x1d, 0x07,
- 0xbf, 0x97, 0xe7, 0xa3, 0x99, 0xbc, 0xc4, 0x79, 0x76, 0x7a, 0xc2, 0xc6,
- 0xfc, 0x97, 0xe1, 0x3f, 0xe7, 0x4a, 0x3c, 0x27, 0x5d, 0xc0, 0x0a, 0xcb,
- 0xc8, 0xe5, 0x22, 0x73, 0xc6, 0x8f, 0x43, 0x6f, 0xbc, 0x2e, 0x8c, 0x1a,
- 0xf0, 0x03, 0x2b, 0xea, 0xdd, 0xcf, 0xa8, 0xdd, 0x40, 0x0e, 0x1b, 0xd1,
- 0xf6, 0x43, 0xd7, 0x79, 0xb3, 0xcd, 0xb3, 0x07, 0x9e, 0xc5, 0x3f, 0x0b,
- 0x3f, 0x7a, 0x5e, 0xf8, 0x4e, 0xd6, 0xed, 0x26, 0xf3, 0xa5, 0xab, 0xf0,
- 0x7b, 0x99, 0x58, 0x06, 0x36, 0x94, 0x0f, 0x77, 0x80, 0xe7, 0xdf, 0xc4,
- 0xbd, 0x9c, 0xc3, 0x71, 0xa2, 0xf1, 0x15, 0x29, 0x44, 0x02, 0x32, 0x14,
- 0xb9, 0x22, 0x9b, 0xe1, 0xc9, 0x34, 0x79, 0xdd, 0x8a, 0x8e, 0x8a, 0xa6,
- 0xe8, 0x0d, 0xee, 0x86, 0x0d, 0xde, 0x84, 0xbf, 0x6b, 0xf7, 0x72, 0xfd,
- 0x54, 0x91, 0x18, 0xea, 0x59, 0x75, 0xb6, 0xe0, 0xaa, 0xc5, 0x3a, 0x20,
- 0xdf, 0xc5, 0xfe, 0x1f, 0x6a, 0x8c, 0xbb, 0x7b, 0x77, 0xac, 0x43, 0x93,
- 0x3f, 0x77, 0x8e, 0xbb, 0x2c, 0x97, 0x47, 0xd2, 0x69, 0x6b, 0xa1, 0x73,
- 0xd9, 0xa3, 0x73, 0xd6, 0xa3, 0x53, 0xf1, 0xe8, 0x5c, 0x5d, 0xa5, 0xb3,
- 0x07, 0x76, 0xd0, 0x6c, 0x9e, 0x00, 0xde, 0x48, 0xc6, 0x9b, 0xcd, 0x34,
- 0xf2, 0xb2, 0xd9, 0xe1, 0x69, 0xb5, 0xe7, 0xaa, 0x27, 0x46, 0xc7, 0x93,
- 0x96, 0x2b, 0x7f, 0x58, 0x81, 0x4c, 0xc3, 0x1e, 0xf3, 0xe2, 0x62, 0x75,
- 0xee, 0x07, 0xba, 0xfb, 0x85, 0x5d, 0xf0, 0x03, 0x4f, 0x23, 0x96, 0x5c,
- 0x1c, 0x3f, 0x6f, 0x49, 0x7e, 0xdb, 0x27, 0x75, 0xd8, 0x7b, 0x0f, 0xdf,
- 0x27, 0x35, 0xa5, 0xeb, 0xe2, 0x78, 0xb5, 0xf6, 0x34, 0xf2, 0x23, 0xf6,
- 0xdf, 0x4e, 0x0c, 0xb6, 0xab, 0x52, 0x8b, 0xec, 0x3a, 0xcb, 0xfd, 0x21,
- 0xf4, 0xab, 0xd4, 0xba, 0x21, 0xf7, 0x6e, 0x55, 0x57, 0xb9, 0x52, 0x0c,
- 0x41, 0x8f, 0x26, 0x6c, 0x3e, 0x84, 0xb6, 0x30, 0xec, 0xa0, 0x0f, 0xed,
- 0x3f, 0xc7, 0xda, 0x8e, 0xa0, 0x7d, 0xa5, 0x73, 0x5c, 0xe1, 0x58, 0x4b,
- 0xce, 0x39, 0x37, 0x11, 0x73, 0xdf, 0x84, 0x1f, 0x1d, 0x44, 0x9f, 0x61,
- 0xf4, 0xf9, 0x14, 0xc6, 0xe1, 0x3b, 0xcd, 0x1b, 0xf1, 0xd4, 0x00, 0x4f,
- 0x7a, 0x0b, 0x4f, 0x0d, 0xf0, 0x03, 0xdf, 0x79, 0x92, 0x35, 0xe8, 0x61,
- 0x39, 0x5a, 0xe4, 0x19, 0x29, 0xbe, 0x17, 0x6f, 0x4a, 0x00, 0x98, 0xb4,
- 0xed, 0x64, 0x34, 0xdc, 0x50, 0xb5, 0x1e, 0xda, 0xd6, 0x50, 0xbc, 0x2a,
- 0x2a, 0xce, 0x44, 0x8e, 0x22, 0x7e, 0xdd, 0x74, 0xba, 0xe5, 0x75, 0x6f,
- 0xac, 0x15, 0xe1, 0xfe, 0xe5, 0xda, 0xb1, 0x8e, 0x95, 0xae, 0x8d, 0xbf,
- 0x6a, 0x19, 0xde, 0xbc, 0x7a, 0x31, 0xd6, 0xaf, 0xa2, 0xef, 0xb5, 0xf1,
- 0xcb, 0xb5, 0x8d, 0xfa, 0xde, 0x44, 0xdf, 0xb6, 0x96, 0xbe, 0x37, 0xd1,
- 0xaf, 0x1b, 0x71, 0xb0, 0x5b, 0xcd, 0x69, 0x16, 0x7c, 0x5d, 0x2f, 0xaa,
- 0xf7, 0xb4, 0x21, 0x77, 0x8e, 0x69, 0x12, 0x53, 0x67, 0xdc, 0x5a, 0x49,
- 0xd4, 0x8c, 0x68, 0xef, 0xa8, 0xf7, 0x28, 0x1b, 0x18, 0xb3, 0x80, 0x7b,
- 0xe7, 0x27, 0xb4, 0x54, 0x35, 0x87, 0x98, 0xf5, 0x30, 0xf1, 0x53, 0xdc,
- 0x46, 0xcc, 0xac, 0x80, 0x5e, 0xad, 0xd8, 0xe0, 0x79, 0x6a, 0xd8, 0xc5,
- 0x2d, 0xe2, 0xec, 0x87, 0x0d, 0x75, 0xae, 0x21, 0xad, 0x6a, 0x76, 0x95,
- 0xa2, 0x98, 0xc9, 0x11, 0x9e, 0x65, 0xf8, 0x0c, 0xd6, 0xe5, 0x57, 0xd0,
- 0x96, 0x44, 0x7c, 0x3c, 0xa0, 0x25, 0xcf, 0x8f, 0xe3, 0xfa, 0x49, 0x5c,
- 0xc3, 0x1f, 0x2f, 0x64, 0x71, 0xff, 0x49, 0x5c, 0x4f, 0x6b, 0xa9, 0x7a,
- 0x16, 0xd7, 0x4f, 0xe1, 0x7a, 0xca, 0x64, 0x9e, 0xf2, 0xaa, 0x95, 0xd1,
- 0x6c, 0xd0, 0xb2, 0xcf, 0x8f, 0xe3, 0xd3, 0x4a, 0x8f, 0xf7, 0xa0, 0xa7,
- 0x22, 0xf7, 0xda, 0x62, 0xe0, 0x69, 0x9f, 0x96, 0xae, 0x76, 0x81, 0xc6,
- 0x00, 0x9e, 0xa7, 0x4d, 0xed, 0xf7, 0xc6, 0x67, 0xcd, 0xe9, 0x63, 0xaa,
- 0xe6, 0x64, 0x24, 0x32, 0xc0, 0xc9, 0x87, 0x91, 0x07, 0x68, 0x92, 0xb6,
- 0x9e, 0x93, 0x42, 0x1c, 0x7e, 0xa5, 0x6a, 0x48, 0x2a, 0x94, 0xc7, 0xef,
- 0xbc, 0x24, 0x47, 0x71, 0xbf, 0x4a, 0x5b, 0x60, 0xbf, 0x3f, 0x95, 0x42,
- 0x99, 0xb8, 0x9f, 0x75, 0x26, 0xd6, 0xa6, 0x58, 0x5f, 0xca, 0x41, 0x06,
- 0x21, 0xda, 0xef, 0x06, 0x35, 0x31, 0xf7, 0x8c, 0x34, 0xe2, 0xb2, 0x96,
- 0xac, 0x72, 0xdf, 0xaf, 0x91, 0xb9, 0x6c, 0xf1, 0xfd, 0xb1, 0x69, 0xee,
- 0x23, 0x16, 0x8c, 0x04, 0xeb, 0x23, 0xaa, 0xbe, 0x1e, 0x77, 0xf7, 0x07,
- 0x5b, 0xcf, 0xa4, 0xf8, 0xeb, 0x85, 0xe3, 0x7e, 0x0d, 0xcf, 0xbb, 0xf5,
- 0xac, 0x54, 0xfd, 0x9d, 0xba, 0xe0, 0x3b, 0x00, 0xe7, 0xa0, 0x8b, 0xcb,
- 0x2a, 0x37, 0xe6, 0x1e, 0xee, 0xbb, 0xe5, 0x54, 0xc8, 0x61, 0x8a, 0xac,
- 0x91, 0xf9, 0xfb, 0x76, 0xbe, 0x1c, 0xd7, 0xf3, 0x4a, 0x3e, 0x67, 0x40,
- 0x53, 0xe2, 0xf4, 0xbb, 0xd9, 0x10, 0xf7, 0xdf, 0xf8, 0x8c, 0x7c, 0xf3,
- 0x2e, 0xdf, 0xe4, 0x99, 0xf2, 0x38, 0x0c, 0xff, 0xc9, 0xf7, 0x2b, 0x9e,
- 0x93, 0x5c, 0x9c, 0x35, 0x1e, 0x03, 0xb1, 0x31, 0x8f, 0xdf, 0x77, 0xe5,
- 0x37, 0xeb, 0xc9, 0x2f, 0x57, 0xfe, 0x2f, 0x4a, 0x87, 0x15, 0x8b, 0xe3,
- 0xf9, 0xb5, 0x8f, 0xbd, 0x4a, 0x77, 0x15, 0x75, 0x7e, 0xd7, 0x97, 0x81,
- 0x5f, 0xbf, 0xdb, 0xd8, 0xf6, 0xc6, 0x2d, 0xf2, 0xf6, 0x10, 0xcf, 0x43,
- 0x0c, 0xda, 0x42, 0xfe, 0x39, 0x0f, 0xc6, 0x30, 0x7f, 0xaf, 0xd5, 0x9f,
- 0x83, 0x3f, 0xcf, 0xfb, 0x95, 0x0f, 0xf9, 0xfd, 0xe4, 0x16, 0xe9, 0xca,
- 0x98, 0x86, 0xc5, 0xd8, 0xf0, 0xb8, 0xb7, 0x3f, 0xf0, 0x7f, 0x43, 0xce,
- 0xae, 0x2c, 0x02, 0x09, 0x99, 0xf5, 0xde, 0xbf, 0xde, 0xc0, 0x1e, 0xd6,
- 0xef, 0x35, 0x37, 0x32, 0x67, 0xad, 0xbb, 0xf3, 0xae, 0x6c, 0x30, 0xef,
- 0x8a, 0x37, 0xef, 0xea, 0x7d, 0xf2, 0x5b, 0x99, 0xb7, 0x31, 0x67, 0xda,
- 0xdc, 0x46, 0xf6, 0x28, 0xea, 0xdd, 0xb0, 0x15, 0x23, 0x18, 0xb4, 0x9d,
- 0x7b, 0xd5, 0x50, 0x99, 0x57, 0xbb, 0x76, 0x79, 0x16, 0xb1, 0xb0, 0x5c,
- 0x76, 0x73, 0xec, 0xb2, 0xc3, 0x5a, 0xf6, 0xbb, 0xf1, 0xc0, 0x77, 0xb9,
- 0xbe, 0xa8, 0xce, 0xbb, 0xcc, 0x3a, 0x6e, 0xdd, 0xab, 0x5c, 0x6e, 0x8d,
- 0xa9, 0x0f, 0x32, 0x9e, 0x0e, 0xe6, 0x65, 0x82, 0xef, 0x94, 0xe3, 0xfa,
- 0x11, 0xb9, 0xb2, 0xa0, 0xf6, 0xac, 0xbc, 0xbd, 0x21, 0xee, 0xf9, 0xa8,
- 0xfd, 0x6f, 0xf8, 0xb5, 0x49, 0xe5, 0xd7, 0x97, 0x17, 0xd4, 0x3d, 0x17,
- 0x2b, 0x39, 0x13, 0xf0, 0xfb, 0xc8, 0x25, 0xac, 0x07, 0xa4, 0x80, 0x9c,
- 0xfb, 0xac, 0x75, 0x78, 0x0b, 0x71, 0x0e, 0x69, 0x2d, 0x83, 0xd6, 0xe5,
- 0x05, 0xd9, 0xc2, 0x33, 0x25, 0x65, 0xb5, 0xcf, 0xe6, 0xd6, 0xc5, 0xa7,
- 0xc5, 0xff, 0x7f, 0x1d, 0x41, 0x2f, 0x16, 0xf2, 0x5c, 0x0b, 0xdf, 0x73,
- 0xa6, 0xaf, 0x40, 0x1e, 0x34, 0xc1, 0x7d, 0x9c, 0x66, 0xd3, 0xad, 0x9b,
- 0x37, 0xb1, 0x2e, 0xda, 0xf8, 0x0e, 0x05, 0xfe, 0x0e, 0xc3, 0x7e, 0xb0,
- 0x4e, 0x56, 0xdb, 0x79, 0xcd, 0xdc, 0xc3, 0xbf, 0x66, 0x60, 0xfb, 0x3f,
- 0xe8, 0xf3, 0x49, 0x14, 0x38, 0x46, 0x00, 0x00, 0x00 };
+ 0xbd, 0x7c, 0x7d, 0x70, 0x1c, 0xe7, 0x79, 0xdf, 0xb3, 0xbb, 0x07, 0xe0,
+ 0x00, 0x82, 0xe0, 0x12, 0x39, 0x52, 0x27, 0x0a, 0xa6, 0x6e, 0x89, 0x3d,
+ 0x08, 0x32, 0x20, 0x71, 0xc5, 0x20, 0x36, 0x26, 0xb9, 0xca, 0xab, 0xbb,
+ 0x03, 0x78, 0x94, 0x31, 0x31, 0xc4, 0xc2, 0x16, 0xed, 0x70, 0xd4, 0xeb,
+ 0x01, 0xa4, 0x95, 0x54, 0x9e, 0xb2, 0xb6, 0xda, 0x72, 0x5a, 0x35, 0x3a,
+ 0x1f, 0xc0, 0x0f, 0x29, 0x47, 0x1c, 0x24, 0xc0, 0x84, 0xfe, 0x70, 0x93,
+ 0x13, 0x0e, 0x24, 0x64, 0xf7, 0x88, 0x93, 0xfc, 0xd9, 0x3f, 0x62, 0x0b,
+ 0x03, 0xd2, 0xb4, 0x5a, 0xbb, 0xb5, 0xda, 0x28, 0x13, 0xcf, 0xf4, 0x63,
+ 0x30, 0x14, 0xa5, 0x28, 0x71, 0xa7, 0x56, 0x9b, 0x4c, 0xa2, 0x36, 0x94,
+ 0xaf, 0xbf, 0xdf, 0xbb, 0xbb, 0xe0, 0x01, 0x22, 0x65, 0x51, 0x93, 0x14,
+ 0x33, 0x37, 0x77, 0xfb, 0xee, 0xbb, 0xef, 0xfb, 0x7c, 0xbd, 0xcf, 0xf3,
+ 0xfc, 0x9e, 0xf7, 0x5d, 0x44, 0x45, 0xda, 0xc4, 0xff, 0xdb, 0x8a, 0x4f,
+ 0xec, 0xd8, 0xf1, 0xc7, 0xef, 0xfd, 0xf8, 0xbd, 0xbf, 0x8a, 0x9f, 0xf7,
+ 0x89, 0xd6, 0x62, 0xf0, 0xe6, 0x5b, 0x86, 0x48, 0xf6, 0xcf, 0xe5, 0x43,
+ 0xff, 0xe1, 0x71, 0x33, 0x18, 0x9f, 0x1f, 0x09, 0xeb, 0x89, 0x57, 0x87,
+ 0x93, 0xb6, 0x84, 0x8d, 0x44, 0xfe, 0xa1, 0x71, 0x5b, 0xc4, 0xad, 0xf6,
+ 0xc5, 0x52, 0xf2, 0x6e, 0x3d, 0x1f, 0x09, 0x09, 0xdb, 0x3f, 0x92, 0xb8,
+ 0xf6, 0xe4, 0xf7, 0x3e, 0x6e, 0xbd, 0x5d, 0x36, 0x24, 0x6c, 0x26, 0xb2,
+ 0x62, 0xf6, 0x48, 0xb8, 0x0b, 0xcf, 0x7c, 0xf5, 0xae, 0x47, 0x0d, 0xe9,
+ 0x08, 0xc6, 0x7a, 0xab, 0xfe, 0xbd, 0xbb, 0x24, 0xbf, 0x2b, 0x51, 0x8f,
+ 0x85, 0x12, 0xef, 0xd6, 0xa7, 0x06, 0xc2, 0xa2, 0x27, 0xac, 0x68, 0xd2,
+ 0x88, 0xc8, 0xcb, 0x35, 0x53, 0x5e, 0xac, 0xc5, 0x64, 0xb2, 0x26, 0x1d,
+ 0xe9, 0xda, 0x8d, 0x68, 0xaa, 0xa3, 0xef, 0xbb, 0xf5, 0xe4, 0x40, 0x28,
+ 0x6b, 0x24, 0xa4, 0x23, 0x59, 0x93, 0xd1, 0x63, 0xc5, 0xd6, 0x87, 0x9b,
+ 0x12, 0x4f, 0xd6, 0x75, 0x5b, 0xb2, 0xa1, 0x84, 0x9d, 0xd7, 0xf5, 0xf6,
+ 0x41, 0xf3, 0x63, 0x68, 0xaf, 0x0e, 0x86, 0x26, 0x8b, 0xa6, 0x9c, 0x1b,
+ 0x68, 0x15, 0xdd, 0x0e, 0x4b, 0xb2, 0xd6, 0xfa, 0xb0, 0x9e, 0x88, 0x88,
+ 0x5b, 0xab, 0xd7, 0x8f, 0x39, 0xff, 0x64, 0xaf, 0xf9, 0xeb, 0xe1, 0xf0,
+ 0x64, 0x51, 0xde, 0x0e, 0xd9, 0x76, 0x74, 0x42, 0x7a, 0xcc, 0x9c, 0x68,
+ 0x92, 0xec, 0xef, 0x89, 0x1e, 0xc1, 0xf7, 0x78, 0x7f, 0xdc, 0x4c, 0xc9,
+ 0x16, 0x71, 0xcd, 0x6f, 0xae, 0x98, 0x3d, 0x5d, 0x59, 0x3d, 0x11, 0x96,
+ 0x74, 0x51, 0x13, 0xc3, 0x8e, 0xc8, 0x64, 0xc5, 0x96, 0xfc, 0x52, 0x87,
+ 0xe4, 0x2b, 0xf2, 0xc4, 0x94, 0xd3, 0x2e, 0x53, 0x4b, 0x47, 0x7d, 0x5d,
+ 0x44, 0xd0, 0xd6, 0x2b, 0xf9, 0x5a, 0x14, 0x9f, 0x9f, 0xf8, 0xfc, 0xea,
+ 0x22, 0x3b, 0x05, 0xcf, 0xf7, 0xa7, 0xdd, 0xea, 0xd7, 0xc2, 0x5e, 0xdb,
+ 0x7f, 0xd9, 0xe2, 0x7d, 0x83, 0xdf, 0x12, 0xf8, 0x2d, 0x85, 0x65, 0xcd,
+ 0x88, 0xca, 0xf7, 0xee, 0x8a, 0xc9, 0x54, 0x69, 0x0d, 0xb2, 0x89, 0xca,
+ 0x37, 0x6a, 0x11, 0x79, 0x49, 0xc9, 0x22, 0xa4, 0x0d, 0xa3, 0xcf, 0x64,
+ 0x69, 0x42, 0x3f, 0x51, 0xcc, 0x4b, 0xaa, 0x96, 0xd5, 0x0b, 0x73, 0x66,
+ 0x47, 0x72, 0x29, 0xa7, 0x4f, 0xce, 0x75, 0x76, 0xa4, 0x96, 0x26, 0xf4,
+ 0x42, 0x31, 0x0a, 0x39, 0x98, 0x1d, 0xa9, 0xf9, 0x08, 0xae, 0x3b, 0x3b,
+ 0x92, 0xf3, 0xd6, 0x0c, 0x26, 0x45, 0x9f, 0x68, 0x47, 0xaa, 0x64, 0x65,
+ 0x45, 0xba, 0x9d, 0x1f, 0x48, 0x57, 0x47, 0xaa, 0xf6, 0x5b, 0xfa, 0x8a,
+ 0xa9, 0x49, 0xe1, 0x1e, 0x31, 0xa3, 0x89, 0xb7, 0xeb, 0xb7, 0xdb, 0x9a,
+ 0x98, 0xf6, 0x3b, 0xf5, 0xed, 0x90, 0x4d, 0x6e, 0xb6, 0x15, 0xbc, 0x92,
+ 0x26, 0x53, 0x72, 0xf3, 0x7d, 0xe6, 0xaa, 0x34, 0x89, 0x1b, 0x09, 0xae,
+ 0xeb, 0xf5, 0xa4, 0xf3, 0x07, 0xe4, 0x91, 0xf2, 0xee, 0x18, 0x86, 0x5e,
+ 0x92, 0xa0, 0x39, 0xe9, 0xbc, 0x5b, 0xf7, 0x9e, 0x09, 0x63, 0xce, 0x50,
+ 0xc7, 0x50, 0xa9, 0x5e, 0x4f, 0x3b, 0x18, 0xdf, 0x09, 0x9e, 0x6d, 0x92,
+ 0x72, 0xc4, 0x2d, 0x4f, 0x3a, 0x96, 0xe1, 0xc9, 0x87, 0xba, 0xe7, 0xb5,
+ 0x0b, 0x7d, 0xe4, 0x25, 0x17, 0x91, 0x72, 0xc1, 0xf9, 0x98, 0x3c, 0xe5,
+ 0x44, 0xc1, 0x5f, 0x58, 0x4e, 0x39, 0xb0, 0x2f, 0xfb, 0xb8, 0x96, 0xac,
+ 0x59, 0xb1, 0xac, 0x3c, 0x2d, 0xc9, 0xf9, 0x6e, 0x33, 0x2d, 0x98, 0xdb,
+ 0xae, 0xdf, 0x99, 0x74, 0x30, 0x5f, 0xff, 0xff, 0xad, 0xbb, 0x11, 0x2b,
+ 0x5b, 0x96, 0x5e, 0x29, 0x94, 0xba, 0x9d, 0x1f, 0x43, 0x4f, 0x61, 0x5b,
+ 0xdc, 0x71, 0xdb, 0x84, 0xdc, 0xac, 0xde, 0x94, 0x51, 0x97, 0x07, 0x31,
+ 0x7f, 0xd2, 0xc6, 0xfd, 0x9a, 0x6c, 0xd3, 0xed, 0x66, 0x29, 0x98, 0x12,
+ 0x69, 0x93, 0xdd, 0x52, 0x98, 0x45, 0xbb, 0xe3, 0x76, 0xea, 0x78, 0x26,
+ 0x33, 0xc0, 0x36, 0xd1, 0x8c, 0x04, 0x75, 0x2c, 0xb2, 0x50, 0xed, 0xc5,
+ 0xfc, 0x71, 0xb7, 0x55, 0x33, 0x65, 0xcd, 0x0c, 0x49, 0xa5, 0x1a, 0x77,
+ 0xa3, 0x5a, 0xb3, 0x9c, 0x8a, 0xb7, 0x41, 0xa6, 0x51, 0x8c, 0x2d, 0x5f,
+ 0xd6, 0x13, 0xf1, 0x68, 0x0e, 0x4a, 0xa3, 0x1d, 0x4d, 0x81, 0x9e, 0x29,
+ 0x27, 0xab, 0xa5, 0x6a, 0x9f, 0xd3, 0x92, 0x4b, 0x87, 0xb4, 0xfd, 0x4b,
+ 0xe8, 0x53, 0xfb, 0x1f, 0xbe, 0x0d, 0x44, 0x41, 0x9b, 0x8e, 0x67, 0xd9,
+ 0x0e, 0x9a, 0x15, 0xed, 0x68, 0x83, 0x2e, 0x57, 0xc6, 0x22, 0x1d, 0x49,
+ 0xa5, 0x4b, 0xd2, 0xa6, 0x4b, 0x6e, 0x54, 0x93, 0x4e, 0xdb, 0x95, 0xf0,
+ 0xaf, 0x41, 0x9f, 0xf3, 0xd0, 0xe5, 0x7c, 0x4c, 0x4e, 0x94, 0x24, 0xa2,
+ 0x0b, 0xe7, 0xca, 0xea, 0x95, 0x2a, 0xed, 0x01, 0xba, 0x85, 0xee, 0x0b,
+ 0x55, 0x3e, 0x0b, 0x1d, 0x96, 0xd2, 0x90, 0x4f, 0x06, 0x73, 0x1f, 0xd4,
+ 0x1e, 0xac, 0x8c, 0x69, 0x19, 0xd8, 0x49, 0x61, 0xb6, 0x0f, 0xba, 0xb3,
+ 0x62, 0x6b, 0xb2, 0x4d, 0x0a, 0xb6, 0x1d, 0xfb, 0xac, 0xb4, 0xcb, 0xa9,
+ 0x79, 0x5b, 0x4e, 0xcc, 0xc3, 0x1e, 0x4d, 0xcb, 0x5c, 0x94, 0xae, 0xec,
+ 0x96, 0x44, 0x87, 0x3c, 0x3d, 0x6b, 0x65, 0xca, 0xd2, 0xed, 0xbe, 0x81,
+ 0xfb, 0xb9, 0x33, 0xd4, 0xa9, 0xe4, 0x53, 0x8e, 0x21, 0x59, 0x93, 0x76,
+ 0x7d, 0x9b, 0x26, 0x6d, 0xf5, 0x27, 0x93, 0x8e, 0x15, 0xa5, 0xcd, 0xa6,
+ 0x3e, 0xdd, 0x6d, 0x1e, 0x10, 0xcb, 0xcc, 0x50, 0xfe, 0x4e, 0x1f, 0xf4,
+ 0xf0, 0xbf, 0x29, 0x7b, 0x8c, 0x45, 0x1d, 0xf7, 0x45, 0x4f, 0x41, 0x97,
+ 0x59, 0xa5, 0xe3, 0x0e, 0xcc, 0x1f, 0xf2, 0x6d, 0x87, 0x6b, 0xe2, 0x6e,
+ 0xcd, 0x93, 0x43, 0x87, 0xcc, 0x54, 0xda, 0xa5, 0x00, 0x1d, 0x16, 0xc4,
+ 0x96, 0xc2, 0xd2, 0x5e, 0xbf, 0xdd, 0xc6, 0x7a, 0xf9, 0x53, 0x5d, 0xda,
+ 0x8e, 0x6b, 0x87, 0x6a, 0x3f, 0xd7, 0x7c, 0xfb, 0x81, 0xfd, 0x85, 0xc5,
+ 0x1d, 0x0d, 0xcb, 0xf9, 0x9a, 0x67, 0x7f, 0x0b, 0xf0, 0x3d, 0xae, 0xe9,
+ 0xc2, 0x96, 0xde, 0x5c, 0xef, 0x73, 0xbe, 0xd6, 0x85, 0x67, 0xc3, 0x72,
+ 0xa2, 0xc6, 0xfe, 0x79, 0xd8, 0x58, 0x58, 0x96, 0xef, 0x6a, 0x97, 0x2c,
+ 0xda, 0x0b, 0xf3, 0xe2, 0x26, 0x1d, 0x1d, 0xcf, 0x74, 0x80, 0x97, 0x9d,
+ 0xf8, 0xb4, 0xc9, 0x78, 0xa5, 0xc5, 0xe5, 0x7a, 0x1d, 0xaf, 0x51, 0xff,
+ 0xf8, 0x2e, 0x05, 0x36, 0x40, 0xf9, 0xb2, 0x9d, 0xcf, 0xb1, 0xdd, 0x44,
+ 0x7b, 0x63, 0x1b, 0x6d, 0x7b, 0x1b, 0x65, 0xda, 0xcb, 0x35, 0x9a, 0x2b,
+ 0xc5, 0xcd, 0x43, 0xfc, 0xae, 0xd1, 0x1e, 0x1a, 0x6d, 0x21, 0x84, 0xfe,
+ 0xd0, 0x63, 0x05, 0x73, 0xcd, 0x5e, 0xab, 0x37, 0x0d, 0xe0, 0xda, 0xfe,
+ 0x1d, 0xf0, 0xc9, 0xb9, 0x43, 0xa0, 0x4b, 0x97, 0x6c, 0x45, 0xd1, 0x16,
+ 0xa3, 0x0d, 0x78, 0x7c, 0x74, 0xc9, 0xe4, 0x7c, 0x7b, 0x47, 0x7a, 0x9e,
+ 0xed, 0xc9, 0xa8, 0x01, 0x3e, 0xc7, 0x1d, 0x59, 0x99, 0x72, 0xf4, 0xee,
+ 0x10, 0xe8, 0x9a, 0xc0, 0x82, 0x03, 0x1f, 0x3e, 0x8d, 0x2b, 0xb8, 0xdf,
+ 0x29, 0xe3, 0x4b, 0xec, 0xcb, 0x39, 0x0a, 0xdb, 0x75, 0x49, 0x80, 0x36,
+ 0x7c, 0x6c, 0x0b, 0xf7, 0x5b, 0x31, 0x4f, 0x3b, 0x6c, 0x67, 0x9a, 0xba,
+ 0xfb, 0x44, 0xd2, 0xe9, 0x94, 0xec, 0x7a, 0x5f, 0x81, 0xdd, 0xb1, 0x7f,
+ 0xef, 0xa6, 0xbe, 0x90, 0xef, 0x12, 0xc6, 0x9c, 0x6f, 0x85, 0x0c, 0xd9,
+ 0xae, 0x83, 0xe6, 0x16, 0xd0, 0x00, 0x1f, 0x6c, 0x77, 0x63, 0x3d, 0xb4,
+ 0x60, 0xfc, 0x2d, 0xe0, 0xa9, 0x55, 0x26, 0x66, 0x3b, 0xa1, 0x0b, 0x13,
+ 0x7d, 0xc3, 0xf2, 0x74, 0xc9, 0x82, 0x0d, 0xb0, 0x3f, 0x74, 0x30, 0x6f,
+ 0x45, 0x2b, 0xe2, 0xca, 0x94, 0xd3, 0x02, 0xfb, 0xaa, 0xd7, 0x8f, 0xc0,
+ 0x3e, 0xbe, 0xae, 0xfc, 0x45, 0x9f, 0x39, 0xa4, 0x49, 0xbe, 0x25, 0xf1,
+ 0x7d, 0xd0, 0x63, 0x3d, 0x2a, 0xc2, 0xeb, 0xbd, 0x1a, 0xd7, 0x2c, 0xe4,
+ 0xc8, 0xb9, 0xe1, 0x93, 0x76, 0x42, 0x86, 0xf4, 0x5b, 0x5d, 0xb0, 0xe7,
+ 0xa8, 0xf2, 0x27, 0x43, 0x37, 0xf4, 0x27, 0xd6, 0x68, 0x19, 0x73, 0x15,
+ 0x96, 0x42, 0xf4, 0x61, 0x83, 0x58, 0xae, 0xb2, 0x15, 0x6b, 0x6f, 0x52,
+ 0xd9, 0xc7, 0x4f, 0xc8, 0x6f, 0xfd, 0x53, 0x0e, 0xe9, 0x22, 0xbf, 0x2e,
+ 0x9e, 0xa5, 0x0d, 0x5a, 0xc7, 0x5d, 0x35, 0xff, 0x4f, 0xfc, 0xf9, 0x3d,
+ 0xda, 0x0b, 0xa5, 0x0e, 0x2d, 0xa5, 0x68, 0x08, 0xc6, 0x11, 0x59, 0x3d,
+ 0xd3, 0x6d, 0x3e, 0x08, 0x1b, 0xa6, 0x9f, 0x5a, 0xbd, 0x40, 0x1d, 0x63,
+ 0x8c, 0x01, 0xea, 0xd8, 0x54, 0xf4, 0x25, 0xe7, 0xb9, 0xf6, 0xa4, 0xcb,
+ 0x10, 0xfa, 0x08, 0xf8, 0x5c, 0xac, 0xc5, 0x49, 0x7f, 0x2d, 0xe6, 0xaa,
+ 0xb4, 0xbf, 0xc7, 0xf1, 0xac, 0x2e, 0x43, 0x71, 0xfa, 0x87, 0xa7, 0x25,
+ 0x05, 0x1f, 0x09, 0x3d, 0x4a, 0x05, 0xbc, 0x2c, 0x94, 0x1a, 0xfd, 0x16,
+ 0x6c, 0xab, 0xff, 0xaf, 0xeb, 0x9e, 0x3f, 0xa4, 0x6f, 0xa0, 0xaf, 0x29,
+ 0x98, 0x3a, 0x24, 0x87, 0xc8, 0xe0, 0x42, 0x37, 0x4e, 0xd2, 0xb0, 0x32,
+ 0x59, 0xc6, 0x1c, 0xbb, 0x2e, 0xf6, 0x7d, 0x82, 0x48, 0xda, 0xcb, 0xf8,
+ 0xb7, 0x2f, 0xf0, 0x4f, 0xab, 0xd5, 0x40, 0x17, 0xd4, 0x2b, 0xf5, 0x10,
+ 0xf8, 0x88, 0x90, 0x5c, 0x84, 0xef, 0x9a, 0x2a, 0xb5, 0xcb, 0x0a, 0x68,
+ 0xba, 0x54, 0x0d, 0x6c, 0xcd, 0xf0, 0x6d, 0x8d, 0xcf, 0xb4, 0xe3, 0xf9,
+ 0x10, 0xfc, 0x9a, 0xe4, 0x8d, 0x04, 0x7e, 0x17, 0x39, 0x26, 0xdb, 0x02,
+ 0x3b, 0xe7, 0x9a, 0xb1, 0xdc, 0xb2, 0x34, 0x4b, 0x26, 0x8e, 0xf8, 0x31,
+ 0xaf, 0x63, 0xae, 0x2e, 0xf8, 0xf2, 0x90, 0x1c, 0x2d, 0x45, 0xe4, 0xf3,
+ 0x25, 0xf2, 0x95, 0xd6, 0x52, 0xd0, 0x5b, 0x72, 0xbe, 0x0e, 0x9d, 0x0f,
+ 0xc3, 0xe7, 0x65, 0xb4, 0x21, 0xf8, 0x9f, 0x03, 0x95, 0xcf, 0x69, 0xe9,
+ 0xa5, 0xac, 0x36, 0x5c, 0x3b, 0xa4, 0x65, 0x96, 0xc6, 0xb4, 0xfd, 0x0d,
+ 0xbe, 0x48, 0xb4, 0xf7, 0xf7, 0x45, 0x4f, 0xcd, 0x72, 0xce, 0x6e, 0xe7,
+ 0xc6, 0xbe, 0xe8, 0xd7, 0xf5, 0x46, 0x5f, 0xd4, 0x0d, 0x5f, 0x94, 0x81,
+ 0x2f, 0x1a, 0xbe, 0x65, 0x5f, 0x34, 0xa2, 0xdf, 0xd8, 0x17, 0x1d, 0xd4,
+ 0xaf, 0xfb, 0x22, 0xc6, 0x9e, 0x15, 0x5c, 0x9b, 0xb2, 0x67, 0x5f, 0x20,
+ 0xe7, 0x28, 0xfc, 0xf0, 0x16, 0xc8, 0xba, 0x8d, 0x6b, 0x27, 0x56, 0x80,
+ 0xdd, 0x4f, 0x60, 0xae, 0xdf, 0x86, 0xbd, 0xef, 0x89, 0xdb, 0xe6, 0x43,
+ 0x6a, 0xde, 0xf7, 0xea, 0x7c, 0x68, 0x5d, 0xe7, 0xa4, 0xf1, 0x97, 0xea,
+ 0xdc, 0xf5, 0x74, 0x4e, 0x5d, 0xb7, 0xca, 0x11, 0x35, 0x6f, 0x5d, 0x42,
+ 0xf7, 0x09, 0xbc, 0x8a, 0x3c, 0x60, 0x24, 0x2c, 0x8c, 0xa7, 0x63, 0x7e,
+ 0xea, 0x2b, 0x0e, 0x1a, 0x04, 0xfa, 0x6d, 0x57, 0xbe, 0x68, 0x3f, 0xf4,
+ 0xbe, 0x5a, 0xbd, 0x35, 0x5d, 0x65, 0x1a, 0x74, 0xf5, 0xe0, 0x06, 0x5d,
+ 0xb5, 0x48, 0x7f, 0x3c, 0xd0, 0xd1, 0x36, 0x49, 0xc6, 0xa9, 0xb3, 0x5b,
+ 0xd1, 0xd5, 0xb9, 0xbf, 0x25, 0x5d, 0x7d, 0xf7, 0x26, 0xba, 0xfa, 0xde,
+ 0x26, 0x5d, 0xd9, 0xe6, 0x33, 0x1a, 0xc7, 0x66, 0xfc, 0xa0, 0x3f, 0xaa,
+ 0xdf, 0x39, 0xce, 0xfc, 0xa1, 0xc6, 0x35, 0x1d, 0xe4, 0x1d, 0x5c, 0xcf,
+ 0x2f, 0xd7, 0x0d, 0xdb, 0x86, 0xec, 0xb8, 0xa6, 0x29, 0x37, 0xcb, 0xfc,
+ 0x14, 0xe9, 0x47, 0xec, 0x18, 0x47, 0xac, 0xf1, 0x68, 0x68, 0x96, 0xf2,
+ 0x76, 0xaf, 0xff, 0x78, 0xa9, 0xfe, 0x73, 0x3d, 0xf1, 0x0b, 0xe4, 0x95,
+ 0xb6, 0x1f, 0x07, 0xc2, 0xf2, 0x85, 0x8a, 0x95, 0x75, 0xb5, 0x76, 0xc9,
+ 0xef, 0x40, 0xec, 0x29, 0xd1, 0x7f, 0xed, 0xbc, 0x49, 0x8c, 0xee, 0xf2,
+ 0x63, 0xf4, 0x9f, 0x81, 0x56, 0xe6, 0x57, 0xff, 0xe6, 0xdd, 0x95, 0x08,
+ 0xbf, 0xe3, 0xe6, 0x41, 0xf9, 0x2c, 0x79, 0x44, 0xbc, 0x67, 0xdc, 0xb7,
+ 0x99, 0xf3, 0xe4, 0x43, 0x89, 0x36, 0xc9, 0x6f, 0xe7, 0x7a, 0xa4, 0x9f,
+ 0xa3, 0xef, 0x6a, 0xf6, 0xe9, 0x0e, 0x72, 0x24, 0xfe, 0xb5, 0x18, 0x60,
+ 0x19, 0x7d, 0x90, 0x0f, 0x95, 0xc8, 0xc7, 0xbb, 0xbe, 0x3d, 0x31, 0x57,
+ 0x90, 0x26, 0xcf, 0x37, 0x8c, 0x20, 0x17, 0xa0, 0x1d, 0x04, 0x3a, 0xa7,
+ 0xbe, 0x99, 0x23, 0x48, 0x4c, 0xb7, 0x99, 0x23, 0x88, 0x69, 0x24, 0x0e,
+ 0x6a, 0x2e, 0x74, 0xef, 0x42, 0xf7, 0x2e, 0x74, 0xef, 0x42, 0xf7, 0xc9,
+ 0xda, 0x71, 0xdc, 0x53, 0x79, 0x08, 0x68, 0xf1, 0xc6, 0x4f, 0x7b, 0xe3,
+ 0x83, 0xce, 0x9d, 0x92, 0x53, 0x3a, 0x21, 0xbf, 0xc8, 0x35, 0x94, 0xbf,
+ 0x1e, 0xd6, 0x3c, 0x7f, 0xcd, 0xf1, 0x32, 0x78, 0xfe, 0x7e, 0xe4, 0x73,
+ 0xae, 0xae, 0xdb, 0xd7, 0x65, 0x32, 0xd5, 0x20, 0x93, 0xc9, 0x2a, 0x65,
+ 0xc4, 0xfe, 0xf4, 0xb9, 0x13, 0xfa, 0xc2, 0xba, 0x5c, 0x46, 0x40, 0x43,
+ 0x0b, 0x79, 0xf7, 0xf9, 0xe0, 0xf8, 0x9d, 0xfe, 0xf8, 0xbf, 0x81, 0x31,
+ 0xe9, 0x5f, 0x6f, 0x34, 0x2f, 0xe7, 0x64, 0xce, 0xf8, 0x7e, 0xfc, 0x20,
+ 0x67, 0xc6, 0x1a, 0x78, 0x69, 0x3d, 0x9f, 0x8e, 0x21, 0x9f, 0x7e, 0x07,
+ 0xb9, 0x74, 0xbd, 0xce, 0x38, 0x55, 0x40, 0x9e, 0x9b, 0x76, 0xb8, 0xae,
+ 0x6f, 0x65, 0xdd, 0x6e, 0x58, 0xb3, 0x66, 0xd2, 0xe0, 0xb8, 0x61, 0xf1,
+ 0xc6, 0xe4, 0xfd, 0x16, 0xe4, 0x82, 0xef, 0xe0, 0x37, 0x7d, 0x72, 0x90,
+ 0xe7, 0xb1, 0x0f, 0x9f, 0x7f, 0x15, 0x73, 0xf7, 0x03, 0xcf, 0xf4, 0xca,
+ 0x77, 0x6a, 0xb6, 0x7c, 0x1b, 0x98, 0xe6, 0x5b, 0xc8, 0x2d, 0xbe, 0x59,
+ 0x0b, 0x72, 0xfb, 0xbd, 0x30, 0x75, 0xe6, 0xf7, 0x12, 0xde, 0x69, 0x13,
+ 0x57, 0xe5, 0xf7, 0x7f, 0xda, 0x96, 0xad, 0x11, 0xfc, 0xfe, 0x95, 0x84,
+ 0x6c, 0xeb, 0xc4, 0xf7, 0xf6, 0x04, 0x4c, 0x27, 0xc1, 0xd8, 0xa8, 0x35,
+ 0xc4, 0x46, 0xd1, 0xd2, 0xe0, 0x71, 0x0a, 0xe3, 0xa5, 0xc1, 0xf7, 0x67,
+ 0x6a, 0x61, 0x2d, 0x35, 0xbb, 0x1b, 0x98, 0x24, 0xc8, 0x71, 0x91, 0x47,
+ 0x99, 0xab, 0xdb, 0x43, 0xf2, 0x36, 0x78, 0x4a, 0x82, 0x76, 0x17, 0x39,
+ 0xc0, 0x3f, 0xc5, 0x5c, 0xd6, 0x4f, 0x3f, 0x2d, 0xff, 0xda, 0xcf, 0xc3,
+ 0x9b, 0x64, 0x4e, 0xf1, 0xc8, 0x76, 0xc9, 0xfc, 0xcb, 0x9e, 0xeb, 0xed,
+ 0xcf, 0xae, 0xb7, 0xc7, 0x32, 0xbf, 0xb1, 0xde, 0x7e, 0x35, 0xe4, 0xe1,
+ 0x95, 0x41, 0x6d, 0xb4, 0xf6, 0x2f, 0x8c, 0x00, 0xeb, 0x14, 0x66, 0x7b,
+ 0x31, 0xd7, 0x36, 0x99, 0xb4, 0xdf, 0x06, 0xf6, 0xb2, 0x63, 0x39, 0xac,
+ 0xaf, 0xa7, 0x36, 0xf9, 0xfa, 0x36, 0xf8, 0x8f, 0xd3, 0xb3, 0xd6, 0x20,
+ 0xfd, 0x47, 0x1c, 0x6b, 0x29, 0xf9, 0x1e, 0xff, 0xf1, 0x6d, 0xa3, 0xd1,
+ 0x7f, 0x18, 0xf0, 0x1f, 0xfb, 0xdf, 0xc7, 0x7f, 0x3c, 0xf5, 0x1e, 0xff,
+ 0xa1, 0xc1, 0x2e, 0xe8, 0x3f, 0x7e, 0x68, 0x04, 0xfe, 0xa3, 0xb0, 0xc1,
+ 0x7f, 0x04, 0xfa, 0xb0, 0x55, 0xee, 0xe8, 0xfd, 0x26, 0xfe, 0x6c, 0xf3,
+ 0x31, 0xa7, 0x84, 0x43, 0x09, 0x37, 0x33, 0x65, 0xef, 0x92, 0x26, 0xac,
+ 0xd1, 0x97, 0x6b, 0x03, 0xf0, 0x25, 0xbf, 0x0f, 0x9c, 0x66, 0x39, 0x4c,
+ 0x44, 0x9a, 0x12, 0xd4, 0xcd, 0x48, 0x2c, 0x69, 0xbf, 0x90, 0x59, 0xa8,
+ 0xbe, 0x90, 0x39, 0xa7, 0x74, 0x35, 0x61, 0x79, 0x18, 0xf8, 0x09, 0x0b,
+ 0x18, 0x18, 0xcf, 0x87, 0x80, 0x21, 0xd8, 0xde, 0x6e, 0x26, 0x91, 0xa3,
+ 0x54, 0xaa, 0x2b, 0x99, 0x02, 0x3e, 0x53, 0xaa, 0xef, 0x58, 0x8c, 0x7d,
+ 0x5b, 0x12, 0xe5, 0xd8, 0x9f, 0xe2, 0xbb, 0x39, 0x31, 0x67, 0x5d, 0xb6,
+ 0x39, 0xee, 0x6b, 0xb1, 0x73, 0x6a, 0x8c, 0x90, 0x14, 0xd4, 0xb3, 0x5f,
+ 0xb5, 0xf8, 0xec, 0x29, 0xf8, 0xf8, 0x93, 0x55, 0x53, 0x4e, 0x54, 0xd7,
+ 0x32, 0x39, 0x7c, 0x88, 0x6d, 0x5e, 0x2e, 0xf1, 0xfe, 0xb7, 0x70, 0x3f,
+ 0x24, 0xcc, 0x3d, 0x3e, 0x8f, 0x3e, 0x47, 0xd1, 0xe7, 0x48, 0x35, 0xc0,
+ 0x8d, 0xbc, 0xef, 0x66, 0x52, 0xb8, 0x7f, 0xa4, 0xe8, 0x66, 0xd2, 0x45,
+ 0xe6, 0x39, 0x7d, 0xd1, 0x13, 0x90, 0x67, 0x16, 0xb1, 0xdd, 0x15, 0xab,
+ 0x37, 0x2f, 0x8f, 0xb5, 0x0e, 0x23, 0xaf, 0x3e, 0x8f, 0x98, 0xe3, 0x8e,
+ 0x59, 0x4e, 0x19, 0xcc, 0x4d, 0x95, 0xee, 0x90, 0xc2, 0x0c, 0x62, 0x8c,
+ 0x73, 0x0f, 0x73, 0xed, 0x8c, 0x1e, 0x77, 0xe0, 0x13, 0x06, 0x80, 0x27,
+ 0xbb, 0x81, 0x85, 0xef, 0x92, 0x15, 0xd3, 0x8a, 0x0e, 0x03, 0x03, 0xa7,
+ 0x42, 0xe8, 0xd3, 0x7b, 0x9b, 0x64, 0xa3, 0x94, 0xf5, 0x0e, 0xf8, 0x07,
+ 0x4d, 0x5a, 0xec, 0x46, 0x5f, 0xf5, 0x17, 0x10, 0x2f, 0x92, 0xdf, 0x36,
+ 0xb6, 0xb7, 0xfa, 0x3a, 0xd9, 0x22, 0xab, 0xef, 0xe9, 0xf7, 0x37, 0x0d,
+ 0xfd, 0x1a, 0xdb, 0x35, 0x4d, 0xd0, 0x7f, 0x0d, 0x34, 0x84, 0xe2, 0x90,
+ 0x3f, 0x78, 0x68, 0x82, 0x9d, 0x5c, 0x06, 0x3f, 0xf4, 0x9b, 0x85, 0x32,
+ 0xe3, 0xa4, 0x21, 0x65, 0x13, 0xf7, 0xaa, 0xf5, 0xfa, 0x82, 0x0d, 0x5a,
+ 0x2f, 0x90, 0xde, 0xb0, 0x0c, 0x57, 0x7b, 0xc4, 0x5d, 0xa4, 0x1c, 0x2c,
+ 0xac, 0x8e, 0x5d, 0x6d, 0xa9, 0x79, 0xcb, 0xcd, 0x63, 0x44, 0xe3, 0x42,
+ 0x57, 0x5b, 0x12, 0x71, 0x51, 0xbf, 0x10, 0x6b, 0x4b, 0xc1, 0x1f, 0x18,
+ 0x17, 0x6e, 0x6f, 0x4b, 0xcf, 0x92, 0x2e, 0x03, 0x71, 0xf1, 0x4e, 0xe0,
+ 0xc2, 0xba, 0x7c, 0x0d, 0xb9, 0x4f, 0xa1, 0x17, 0x31, 0x03, 0xab, 0x44,
+ 0x07, 0xdd, 0x79, 0x53, 0xc2, 0x6d, 0x89, 0x79, 0xd0, 0xd7, 0xdf, 0x9a,
+ 0x9c, 0xdd, 0x82, 0x3e, 0x06, 0xda, 0x7b, 0x88, 0x21, 0x1b, 0xda, 0xed,
+ 0x36, 0xf8, 0x5f, 0xf8, 0x3a, 0x09, 0x27, 0x07, 0xda, 0x31, 0xfe, 0xd9,
+ 0x10, 0x73, 0x87, 0x70, 0x7c, 0xbd, 0xfd, 0xcb, 0x5e, 0x7b, 0x2f, 0x68,
+ 0xe1, 0x73, 0xcc, 0x21, 0x25, 0x3c, 0x3e, 0x60, 0x82, 0x06, 0xf6, 0x8d,
+ 0xa8, 0xbe, 0xe9, 0x79, 0xda, 0x80, 0x9b, 0x59, 0xb0, 0x77, 0x4b, 0x6a,
+ 0x6e, 0xa7, 0x0c, 0xcf, 0x75, 0xca, 0xfe, 0x39, 0xe6, 0xbc, 0xc4, 0xc0,
+ 0x60, 0x05, 0x39, 0xa9, 0x7e, 0x81, 0xb9, 0x80, 0x15, 0x3d, 0x2a, 0xdd,
+ 0xd1, 0xcf, 0x63, 0x1d, 0x8c, 0xdb, 0xf1, 0xd8, 0x24, 0xd6, 0x58, 0x48,
+ 0x8d, 0x13, 0x0d, 0xe6, 0xa4, 0x8d, 0x6e, 0x98, 0x37, 0x3d, 0x7f, 0xb3,
+ 0x71, 0xb1, 0x70, 0x2e, 0x44, 0x37, 0x8d, 0xfb, 0x3f, 0xfd, 0x71, 0x4d,
+ 0x8c, 0xdb, 0x85, 0x31, 0xc9, 0xe3, 0xed, 0xad, 0x43, 0xb3, 0xe2, 0xb6,
+ 0x80, 0xbe, 0x74, 0x7c, 0x97, 0x4c, 0x62, 0x9c, 0x93, 0x73, 0xf4, 0x85,
+ 0xb2, 0x13, 0x9f, 0xfe, 0x26, 0x89, 0xf7, 0x2e, 0x21, 0x2f, 0x1e, 0x52,
+ 0x63, 0x78, 0x39, 0xaa, 0x7e, 0x21, 0x01, 0x5c, 0xf3, 0x51, 0xd0, 0xc3,
+ 0x98, 0x4c, 0x9e, 0x43, 0xe0, 0x37, 0x81, 0x75, 0x48, 0x3c, 0xce, 0xf5,
+ 0x8d, 0xdf, 0x4b, 0xd1, 0xd6, 0xd4, 0x6c, 0x33, 0xd6, 0x9d, 0xec, 0x36,
+ 0x54, 0xac, 0xa0, 0x5e, 0xec, 0xd6, 0x64, 0x49, 0xd1, 0xdd, 0x9a, 0x2a,
+ 0x51, 0x46, 0x4e, 0x6b, 0xba, 0x44, 0x19, 0x09, 0xe8, 0x71, 0xe0, 0x63,
+ 0x43, 0x12, 0xdb, 0x4e, 0x3d, 0x1e, 0x43, 0xbf, 0x95, 0x10, 0xf3, 0xfe,
+ 0xa4, 0xcd, 0xdf, 0xc0, 0x2b, 0x17, 0x8e, 0xa3, 0x2f, 0x7f, 0xdf, 0x8b,
+ 0x71, 0xbb, 0x7b, 0x0b, 0xd2, 0xdc, 0x7b, 0x04, 0x7e, 0x42, 0x1f, 0x00,
+ 0xee, 0x50, 0x76, 0x5e, 0x07, 0x26, 0xdb, 0x0b, 0x7e, 0xb0, 0x36, 0xe2,
+ 0xb6, 0x4c, 0xcc, 0x50, 0xae, 0x72, 0x1b, 0x78, 0x00, 0xff, 0x71, 0xf8,
+ 0x16, 0xf2, 0xc0, 0xb9, 0x05, 0x76, 0xbf, 0x2c, 0xb9, 0x99, 0xb0, 0xc2,
+ 0x3e, 0xae, 0xc9, 0xf9, 0x35, 0x4d, 0x4f, 0xb4, 0x41, 0xc7, 0xe4, 0x6d,
+ 0x0a, 0xb4, 0x3d, 0x0e, 0x3f, 0x6c, 0xa9, 0x9c, 0xdb, 0x40, 0xff, 0x42,
+ 0x69, 0x50, 0x4f, 0x15, 0x49, 0xbf, 0x6f, 0x7b, 0xda, 0x0a, 0x7c, 0x8a,
+ 0xaa, 0x63, 0x21, 0xb7, 0x4b, 0xc0, 0x8f, 0x0c, 0xca, 0xf7, 0xe1, 0x4b,
+ 0xbe, 0x5b, 0x73, 0xe0, 0xff, 0xfb, 0xe1, 0xff, 0x7b, 0xe1, 0xff, 0x6d,
+ 0xf8, 0xff, 0x18, 0xfc, 0x7f, 0x17, 0xfc, 0x7f, 0x94, 0xbe, 0x5f, 0x4e,
+ 0xd6, 0xf2, 0xb0, 0xb1, 0x15, 0xf8, 0x41, 0x33, 0xec, 0xd6, 0x22, 0xe1,
+ 0x64, 0x2d, 0x1a, 0x4e, 0xd5, 0x42, 0xe0, 0xe9, 0x30, 0xe7, 0x04, 0x7f,
+ 0xf9, 0xd6, 0xa1, 0x52, 0x3f, 0xe2, 0x8a, 0x0b, 0xbf, 0x94, 0x86, 0xdf,
+ 0x77, 0x80, 0x7f, 0xf3, 0xb2, 0x3a, 0x13, 0xc3, 0x33, 0x75, 0x49, 0x3b,
+ 0x4d, 0x32, 0x69, 0x3a, 0x18, 0x63, 0xbb, 0xb2, 0x53, 0x23, 0xb1, 0xab,
+ 0x09, 0x76, 0x2a, 0xb9, 0x22, 0xe3, 0x73, 0x17, 0xc6, 0x6b, 0x45, 0x7c,
+ 0xa0, 0x7f, 0xa0, 0x2f, 0x58, 0xc9, 0x3c, 0x6c, 0x73, 0xcd, 0xb5, 0x69,
+ 0x49, 0xe0, 0x67, 0x62, 0x13, 0xc4, 0x3a, 0xd8, 0x05, 0xdb, 0xf6, 0xe0,
+ 0x39, 0xfe, 0xfe, 0x6f, 0x7e, 0x8d, 0xea, 0xaf, 0x5a, 0x04, 0xc6, 0xfb,
+ 0x32, 0x63, 0x8f, 0x8d, 0xf1, 0xaa, 0x8d, 0xeb, 0x75, 0x49, 0x17, 0x3b,
+ 0xb8, 0xcf, 0x7a, 0x0d, 0x6b, 0x54, 0xaf, 0x80, 0xde, 0x7a, 0x7d, 0x55,
+ 0x61, 0x48, 0xe4, 0x33, 0x87, 0xd6, 0xc0, 0x43, 0xe3, 0x33, 0xdf, 0xc0,
+ 0x33, 0xaa, 0x2d, 0x6c, 0x26, 0x1c, 0xe6, 0x50, 0xf0, 0x9b, 0x2f, 0xc0,
+ 0x47, 0x1e, 0xcb, 0xe8, 0xcb, 0x57, 0xf1, 0x2c, 0x64, 0x5a, 0x3c, 0x96,
+ 0x09, 0xf5, 0xbc, 0x5a, 0x7f, 0x16, 0x39, 0xf1, 0xd0, 0xf2, 0x80, 0xa4,
+ 0x96, 0xbb, 0xa3, 0x17, 0xa5, 0xf5, 0x1d, 0x17, 0xb1, 0x74, 0xb2, 0x6a,
+ 0x9d, 0x76, 0x85, 0x39, 0xba, 0x29, 0x0b, 0xc0, 0xd5, 0x7b, 0xf6, 0x3d,
+ 0x0f, 0xda, 0xad, 0x17, 0x45, 0x8f, 0xe1, 0x37, 0x31, 0x0c, 0x79, 0x5c,
+ 0x03, 0x7f, 0x1a, 0xae, 0x5b, 0xd6, 0x6b, 0x57, 0x85, 0x12, 0xf8, 0xac,
+ 0x1d, 0xcb, 0x5c, 0x9c, 0x06, 0xae, 0x83, 0x3e, 0x92, 0xd3, 0xc4, 0x9c,
+ 0x5b, 0x20, 0x93, 0x21, 0xd8, 0x05, 0xf5, 0x1d, 0xc7, 0xb3, 0x75, 0xf9,
+ 0x92, 0x43, 0x1b, 0x78, 0x0e, 0x72, 0xc3, 0x58, 0xa1, 0x80, 0x6e, 0x60,
+ 0x80, 0x19, 0xca, 0x6a, 0x17, 0xf2, 0x36, 0x57, 0x06, 0xf6, 0x49, 0x78,
+ 0x47, 0x62, 0x73, 0x4e, 0x76, 0x2c, 0xb3, 0x3a, 0x8d, 0xf1, 0x7b, 0x80,
+ 0x79, 0x84, 0xb5, 0x19, 0xfa, 0x60, 0x81, 0xed, 0xec, 0x87, 0x7e, 0x98,
+ 0x7b, 0x33, 0x47, 0xa3, 0x6f, 0x3a, 0xa8, 0xa5, 0x2a, 0x65, 0x43, 0x3a,
+ 0x0e, 0x21, 0xb7, 0x71, 0x64, 0x71, 0x9a, 0x39, 0x1a, 0xf3, 0x99, 0x20,
+ 0x7f, 0xd1, 0x90, 0x4b, 0xa0, 0x7d, 0xf9, 0x25, 0xa5, 0x07, 0x03, 0xfa,
+ 0xca, 0xed, 0xbb, 0x9f, 0x7c, 0xcd, 0x18, 0x09, 0xf8, 0xbf, 0x01, 0xf2,
+ 0xa2, 0x68, 0x40, 0xce, 0xc6, 0x35, 0x17, 0x03, 0x5f, 0xf8, 0x5c, 0xcf,
+ 0xdd, 0xd4, 0xdf, 0x64, 0xe9, 0x04, 0xec, 0x58, 0xf2, 0x4d, 0x09, 0xf0,
+ 0x36, 0x80, 0xdf, 0x58, 0xf8, 0x27, 0xa1, 0xc3, 0x73, 0x03, 0xac, 0x91,
+ 0x3d, 0x07, 0xfc, 0x47, 0xfa, 0xe3, 0xb1, 0x13, 0x6a, 0xdd, 0xe2, 0xba,
+ 0xca, 0x3c, 0x62, 0x8b, 0x5c, 0x54, 0x7c, 0xde, 0xc1, 0xfc, 0x14, 0x7a,
+ 0xb9, 0x15, 0x3e, 0x87, 0x3f, 0x24, 0x9f, 0xde, 0x3c, 0x8c, 0x5b, 0x49,
+ 0x3b, 0x26, 0xa9, 0xe2, 0xcb, 0x75, 0xaf, 0x0e, 0xfb, 0x47, 0xb0, 0x2b,
+ 0x5c, 0x57, 0xc3, 0xa0, 0x87, 0x75, 0x99, 0x01, 0xa5, 0x5b, 0xd0, 0x43,
+ 0x9b, 0xc9, 0x87, 0x13, 0xdb, 0xe4, 0xfc, 0x4c, 0x87, 0x2c, 0xcc, 0xbc,
+ 0x26, 0x95, 0x99, 0x36, 0x59, 0x9a, 0xa9, 0xcb, 0x65, 0x47, 0xf9, 0x25,
+ 0xbb, 0x59, 0xad, 0x69, 0xd9, 0xe5, 0x61, 0xf6, 0xf8, 0xe0, 0x15, 0x79,
+ 0x5a, 0xce, 0x97, 0x3d, 0x1e, 0x32, 0x0d, 0x3c, 0xbc, 0x0a, 0x1b, 0xeb,
+ 0xec, 0x21, 0x0f, 0xb4, 0x07, 0xf2, 0xc3, 0xdc, 0x83, 0x39, 0xe6, 0x41,
+ 0xac, 0xa3, 0x11, 0x60, 0xa3, 0x83, 0x5a, 0xd2, 0xe7, 0x21, 0xe5, 0xf1,
+ 0x90, 0x7d, 0x2f, 0x0f, 0x2d, 0x92, 0xdd, 0x49, 0x3e, 0xa0, 0x83, 0x69,
+ 0xea, 0x25, 0xc0, 0x1b, 0x1e, 0xfd, 0xc9, 0xe5, 0x57, 0xeb, 0xfa, 0x74,
+ 0x93, 0xa2, 0xdd, 0x48, 0x0c, 0xc0, 0xae, 0x5e, 0xad, 0xcb, 0x32, 0xd7,
+ 0x12, 0x7e, 0x57, 0xff, 0x31, 0xfc, 0x55, 0xa7, 0xca, 0x5b, 0x72, 0x63,
+ 0xed, 0xad, 0xc9, 0xf9, 0x41, 0xe8, 0xba, 0x55, 0xad, 0x45, 0xb8, 0x0e,
+ 0xe8, 0xf0, 0x0f, 0xd1, 0xff, 0xab, 0x5c, 0x73, 0x4a, 0x3e, 0x69, 0xc8,
+ 0xa7, 0x50, 0xbc, 0xbd, 0x19, 0x39, 0x37, 0xe6, 0x71, 0x33, 0xd9, 0x2a,
+ 0x9f, 0xe9, 0x82, 0x7f, 0xe3, 0xf7, 0x07, 0xb6, 0x8f, 0x3c, 0xfc, 0x2e,
+ 0x6c, 0x00, 0xb9, 0x05, 0xd7, 0xf4, 0xc0, 0x0a, 0xe2, 0x6c, 0xbc, 0x77,
+ 0x41, 0xd5, 0xf4, 0x1d, 0x85, 0x9f, 0x26, 0xab, 0x5f, 0xc5, 0xc7, 0x9b,
+ 0x6f, 0xa8, 0xc6, 0x39, 0x37, 0xf2, 0x84, 0x9c, 0x06, 0xb9, 0xa4, 0x8d,
+ 0x71, 0x39, 0x6f, 0x5e, 0x8c, 0x84, 0x81, 0x79, 0xd9, 0xd6, 0x0e, 0x3f,
+ 0x13, 0x83, 0xdf, 0xea, 0x87, 0xff, 0xe7, 0x5a, 0xa6, 0xaf, 0x0f, 0x68,
+ 0xef, 0xc7, 0x98, 0xf4, 0xc1, 0xfd, 0xe0, 0x99, 0xb9, 0x34, 0x7d, 0x28,
+ 0x62, 0xca, 0x62, 0xb4, 0x2d, 0x39, 0xeb, 0xd5, 0x93, 0xbc, 0xdf, 0xbc,
+ 0x2f, 0xe1, 0xdd, 0x09, 0xab, 0x9c, 0x47, 0xfe, 0x97, 0xc2, 0xda, 0x4d,
+ 0xda, 0xc8, 0xa7, 0x17, 0xad, 0x17, 0x88, 0xd3, 0x74, 0xca, 0x60, 0x99,
+ 0x72, 0x62, 0x6d, 0xc3, 0x94, 0xfc, 0xc2, 0xef, 0x42, 0x1e, 0x61, 0xd9,
+ 0x6e, 0x67, 0xe1, 0x53, 0x98, 0xb7, 0xb8, 0xe0, 0x8d, 0xbe, 0xa7, 0x1b,
+ 0xb1, 0xcc, 0x80, 0x10, 0x90, 0x57, 0x2d, 0x1b, 0xf2, 0x40, 0xa8, 0x0f,
+ 0x79, 0xe0, 0xa7, 0xd0, 0x37, 0x24, 0xf9, 0x65, 0xc6, 0x84, 0x90, 0x4c,
+ 0x2d, 0x8b, 0x5c, 0x99, 0xa6, 0x5f, 0x51, 0x7f, 0x90, 0xb9, 0x9b, 0x99,
+ 0x20, 0x3e, 0x9b, 0xa1, 0x8f, 0xa1, 0xff, 0xd8, 0x01, 0x5d, 0xc4, 0x9f,
+ 0xfb, 0x12, 0xe2, 0xd3, 0x64, 0xb1, 0x1b, 0x7e, 0x53, 0x56, 0x74, 0xc8,
+ 0x14, 0x71, 0x8d, 0xf5, 0xaa, 0x1b, 0xd4, 0xaa, 0x82, 0x3a, 0x55, 0x58,
+ 0x0a, 0xd3, 0xac, 0x51, 0x85, 0x41, 0x0b, 0x73, 0x57, 0x43, 0xe5, 0x42,
+ 0x3b, 0x94, 0x7f, 0xe5, 0x77, 0xa8, 0x61, 0xde, 0xf8, 0xe9, 0x3d, 0x3a,
+ 0xfd, 0xd8, 0x6e, 0x71, 0x47, 0x8f, 0xb5, 0xee, 0x2f, 0x01, 0x8b, 0x76,
+ 0xd2, 0x3e, 0xa9, 0xff, 0xac, 0x4e, 0x7f, 0x3b, 0x55, 0x1a, 0xc0, 0x78,
+ 0xc4, 0x95, 0x21, 0xf4, 0x8b, 0xf8, 0xfd, 0x28, 0xd7, 0x7f, 0x25, 0xe3,
+ 0xfb, 0xfe, 0x1a, 0x74, 0x79, 0xfe, 0x8e, 0x75, 0xee, 0xdc, 0x67, 0x74,
+ 0xb9, 0xef, 0x63, 0x69, 0x3c, 0xcb, 0x78, 0xf8, 0xb6, 0x8f, 0xe1, 0xd8,
+ 0xc6, 0xba, 0x1e, 0x72, 0xf5, 0xf3, 0x26, 0xbe, 0x3b, 0x25, 0x7f, 0x3e,
+ 0x0c, 0x39, 0x20, 0x2f, 0x5e, 0xf0, 0xc6, 0x62, 0xee, 0x7b, 0x1a, 0x3a,
+ 0xd2, 0xcf, 0x84, 0xa5, 0xe9, 0x4c, 0xa7, 0x84, 0xbe, 0xd2, 0x26, 0xcd,
+ 0x5f, 0xe9, 0x11, 0xe3, 0x2b, 0xac, 0x3f, 0x58, 0xb1, 0x93, 0xaa, 0xf6,
+ 0x91, 0x96, 0x53, 0x88, 0x61, 0x3a, 0xe2, 0xb1, 0xb2, 0x53, 0x73, 0xa7,
+ 0x18, 0x48, 0x5e, 0xf5, 0x67, 0x5c, 0xf9, 0xe2, 0xbe, 0x9f, 0xab, 0xda,
+ 0x1b, 0x70, 0xb3, 0xe8, 0xcf, 0x67, 0xc4, 0xad, 0xbd, 0x46, 0x3b, 0xcd,
+ 0xbc, 0x7a, 0xd7, 0x1d, 0xd0, 0x39, 0x73, 0xcb, 0x5e, 0x55, 0xc7, 0xfd,
+ 0xe2, 0x3e, 0xc6, 0x4c, 0x2f, 0xbf, 0x4c, 0x23, 0xbf, 0x9c, 0x94, 0x6e,
+ 0xf8, 0x59, 0xf6, 0xdb, 0x29, 0x3a, 0xe6, 0xca, 0x09, 0xf3, 0xf5, 0x3b,
+ 0xc5, 0x3d, 0x8c, 0x75, 0x71, 0x56, 0x66, 0xf4, 0x84, 0xa6, 0xc6, 0x34,
+ 0x9e, 0xa1, 0xdf, 0xa2, 0x3f, 0xa3, 0x8d, 0xb3, 0x0e, 0x82, 0xb6, 0xe7,
+ 0xe9, 0xb3, 0x3c, 0xdb, 0x1e, 0x6a, 0xf0, 0x7d, 0x53, 0xa5, 0x1a, 0x74,
+ 0x88, 0xbc, 0xde, 0x6e, 0x02, 0xff, 0x88, 0xeb, 0x36, 0xaf, 0xc9, 0x3f,
+ 0x7c, 0x69, 0x24, 0xa2, 0xae, 0x0b, 0x65, 0x0f, 0xf7, 0x7a, 0xe3, 0x33,
+ 0x07, 0x81, 0xaf, 0xa9, 0x91, 0x0e, 0xce, 0xdb, 0x25, 0xc6, 0xd9, 0x88,
+ 0x84, 0xce, 0xd2, 0xfe, 0xac, 0x58, 0x1a, 0xf2, 0x9b, 0xb2, 0x89, 0xf5,
+ 0x0e, 0xc0, 0x17, 0xec, 0x16, 0xfd, 0x7c, 0x2f, 0xd6, 0x8e, 0x15, 0x2d,
+ 0x4b, 0x5c, 0x8c, 0x85, 0xb0, 0xbc, 0x09, 0xdf, 0x41, 0x7b, 0x39, 0x87,
+ 0x78, 0x75, 0xa2, 0xd6, 0xfa, 0xce, 0x8a, 0xa2, 0x82, 0x6d, 0x43, 0xc0,
+ 0x4b, 0x56, 0xaf, 0xab, 0xb7, 0xcb, 0xeb, 0xd0, 0x77, 0x56, 0xb5, 0xed,
+ 0xc6, 0xb8, 0xa0, 0xe1, 0x2c, 0xeb, 0x49, 0x1c, 0xf7, 0x1f, 0x60, 0x4c,
+ 0x8e, 0xed, 0x66, 0x56, 0x99, 0x9f, 0x4e, 0xd3, 0x76, 0x3b, 0x61, 0x77,
+ 0xb8, 0xae, 0x35, 0x4b, 0x76, 0x2c, 0x26, 0xfa, 0xf4, 0x83, 0xd2, 0xbd,
+ 0x4f, 0xf7, 0xf8, 0x51, 0x3c, 0xb2, 0x8d, 0x75, 0xca, 0x16, 0xb5, 0x1e,
+ 0xf5, 0x65, 0xd8, 0xcc, 0x41, 0xea, 0x18, 0xf1, 0x1f, 0xf1, 0x8d, 0xfe,
+ 0xcc, 0x40, 0x7c, 0x4b, 0xd5, 0x3c, 0xbd, 0x97, 0x0f, 0xee, 0x94, 0x53,
+ 0x67, 0x69, 0x4f, 0xb8, 0xb7, 0x6e, 0x53, 0xc1, 0x7e, 0x02, 0xef, 0xd9,
+ 0x72, 0xfa, 0x59, 0xe6, 0x1f, 0xcc, 0x3b, 0x98, 0x6b, 0x59, 0xd1, 0xfd,
+ 0xe0, 0x47, 0xbf, 0x8f, 0xfe, 0x40, 0x57, 0xb6, 0x9b, 0x83, 0xaf, 0x2e,
+ 0xd4, 0xa8, 0xb7, 0x7e, 0xee, 0xb9, 0x98, 0xcc, 0xd9, 0xdc, 0xa8, 0x27,
+ 0xef, 0x02, 0xda, 0x26, 0x11, 0x07, 0x52, 0xd5, 0x26, 0x59, 0x1b, 0x73,
+ 0xa1, 0xfb, 0x8f, 0x82, 0xae, 0xc3, 0xad, 0xc4, 0xab, 0x6b, 0x63, 0x69,
+ 0x5c, 0x1f, 0x56, 0x79, 0x9a, 0x71, 0x9f, 0x8b, 0x31, 0x76, 0x72, 0x1d,
+ 0xf9, 0x7a, 0x72, 0xf4, 0xc2, 0xcc, 0x7d, 0xfa, 0x24, 0x7c, 0xf7, 0xb0,
+ 0xc3, 0x18, 0xcf, 0xfa, 0x73, 0x0b, 0xe8, 0x68, 0x57, 0xd8, 0x42, 0xb7,
+ 0xf7, 0xe9, 0x85, 0x32, 0xfd, 0x7d, 0x3e, 0xda, 0x2c, 0x0e, 0x7d, 0x96,
+ 0xbe, 0x60, 0x53, 0x27, 0x9a, 0x5c, 0x54, 0xb5, 0x6a, 0x44, 0xa0, 0x6a,
+ 0x0a, 0x73, 0x39, 0x7a, 0xa5, 0xbc, 0x4f, 0xcf, 0xc3, 0x55, 0xaf, 0x45,
+ 0x48, 0x77, 0x4c, 0xe5, 0xf2, 0xfb, 0x94, 0xad, 0x15, 0x11, 0x53, 0x60,
+ 0x33, 0xce, 0x1d, 0x98, 0x57, 0xb5, 0xc1, 0xa6, 0xa8, 0x7b, 0xea, 0x5d,
+ 0xf9, 0x48, 0x5f, 0xf7, 0x37, 0x8a, 0xa1, 0x45, 0xf8, 0x5f, 0x62, 0xe9,
+ 0x16, 0xbf, 0x3e, 0xf5, 0xcf, 0xfd, 0x9c, 0xe8, 0x71, 0x61, 0x9e, 0x32,
+ 0x55, 0x22, 0x2d, 0x45, 0xf8, 0xc3, 0x1b, 0xd9, 0x12, 0xe5, 0xe8, 0xf9,
+ 0x94, 0x63, 0xb0, 0x0b, 0x7d, 0xd9, 0xf4, 0x6d, 0x40, 0xe1, 0x67, 0xdc,
+ 0x63, 0x0c, 0xc0, 0x77, 0xad, 0x09, 0xeb, 0x7d, 0x04, 0x32, 0xa2, 0x6e,
+ 0xa0, 0xbf, 0x65, 0xee, 0xd5, 0x41, 0x7f, 0xcb, 0x97, 0x7e, 0xe1, 0x76,
+ 0xd2, 0xe7, 0x0d, 0xc8, 0x29, 0xf8, 0xd1, 0x93, 0xf3, 0xa4, 0x27, 0xad,
+ 0xd6, 0xce, 0x14, 0xe4, 0x7d, 0x42, 0xf9, 0xf8, 0x7e, 0x79, 0x73, 0xf1,
+ 0x5b, 0x0a, 0x0b, 0xee, 0xd9, 0xb7, 0x22, 0x13, 0xf0, 0x0f, 0x47, 0xaa,
+ 0x90, 0xb7, 0x19, 0xc3, 0xfa, 0xdc, 0xa5, 0xfc, 0xe3, 0x17, 0x3f, 0x78,
+ 0xae, 0x12, 0xd2, 0x13, 0x0f, 0x7c, 0xc8, 0x18, 0xbe, 0x55, 0xdc, 0xce,
+ 0x0f, 0x3c, 0x8f, 0xa1, 0x27, 0xfe, 0x10, 0x3a, 0xfb, 0x4d, 0xcc, 0x15,
+ 0x06, 0x9d, 0x6a, 0x3f, 0xe4, 0x83, 0x3c, 0xa7, 0xeb, 0x89, 0x4f, 0x7e,
+ 0x48, 0xfa, 0x4c, 0x59, 0x04, 0x7e, 0xc8, 0xab, 0xb8, 0xca, 0xdc, 0xb1,
+ 0xc9, 0xd7, 0xe7, 0x0b, 0xc0, 0xd5, 0xc0, 0xd2, 0xc5, 0xc0, 0x17, 0xb7,
+ 0x48, 0xbe, 0x33, 0xc8, 0x47, 0xe1, 0xc3, 0xd7, 0xdb, 0x83, 0x1c, 0x97,
+ 0xcf, 0x67, 0x33, 0xc8, 0xa9, 0x61, 0x13, 0xb7, 0x61, 0x8d, 0xb2, 0x4d,
+ 0xe5, 0xb0, 0x37, 0xa1, 0xdf, 0xa3, 0x3d, 0x57, 0x6c, 0xcc, 0x2d, 0x0e,
+ 0xa8, 0xdc, 0x62, 0x68, 0x43, 0x6e, 0x11, 0xd4, 0xb4, 0x02, 0xba, 0x39,
+ 0x2e, 0x70, 0x03, 0xec, 0xe0, 0xbb, 0x18, 0xff, 0x3b, 0xd0, 0xf7, 0xb7,
+ 0x4b, 0xc0, 0x0d, 0x25, 0xe0, 0x86, 0x12, 0x70, 0x43, 0x09, 0xb8, 0xa1,
+ 0x14, 0xf5, 0xeb, 0x5b, 0x2e, 0x71, 0xff, 0x07, 0xb4, 0xe9, 0xa0, 0xee,
+ 0xb1, 0xd9, 0x5e, 0xbd, 0x3a, 0x59, 0xaa, 0x16, 0xe0, 0xe7, 0x30, 0xeb,
+ 0x76, 0xc0, 0x71, 0x41, 0x4d, 0xc4, 0x8f, 0x1d, 0x8b, 0xdc, 0x43, 0x41,
+ 0xec, 0x58, 0x74, 0xb1, 0x9e, 0xfa, 0xa2, 0x06, 0x70, 0xa3, 0x21, 0x51,
+ 0xfc, 0x36, 0xe1, 0x93, 0xb9, 0x67, 0xde, 0x8d, 0x15, 0xd6, 0xac, 0x6a,
+ 0x4f, 0x27, 0x54, 0x4d, 0xc2, 0x96, 0xc9, 0x72, 0x90, 0xdb, 0xc5, 0x65,
+ 0x68, 0x86, 0x58, 0x54, 0xb6, 0xeb, 0x09, 0xe8, 0xa2, 0x4a, 0xfc, 0xc8,
+ 0x3d, 0x27, 0xce, 0x1f, 0xef, 0xad, 0x60, 0xce, 0x82, 0xed, 0xd1, 0x77,
+ 0xa2, 0xaa, 0xce, 0x05, 0xf8, 0xcf, 0x05, 0x67, 0x01, 0xe2, 0xb2, 0x7f,
+ 0x86, 0x7b, 0xef, 0x31, 0x19, 0x2d, 0x3a, 0xc8, 0x65, 0x55, 0x8e, 0x84,
+ 0x78, 0xe0, 0xc9, 0x7d, 0xc8, 0x97, 0x7b, 0x0e, 0xd8, 0x61, 0xdc, 0x0e,
+ 0xe4, 0x4e, 0x79, 0x8f, 0x68, 0xc3, 0x90, 0xf5, 0x7e, 0x5f, 0xd6, 0xe9,
+ 0x25, 0x31, 0x91, 0xff, 0xc4, 0x8c, 0x7d, 0x63, 0xda, 0x68, 0x4d, 0x61,
+ 0x16, 0xfa, 0x23, 0x8c, 0xe5, 0x78, 0x6b, 0x1d, 0xf6, 0x92, 0xab, 0x6e,
+ 0xde, 0x8f, 0x6f, 0xc4, 0x2f, 0x9f, 0xd5, 0xc4, 0x0e, 0xe4, 0xd8, 0xd8,
+ 0x3e, 0xd1, 0xd0, 0xbe, 0x7e, 0xdf, 0xe7, 0x01, 0xbe, 0x72, 0xbd, 0x3e,
+ 0x41, 0xbf, 0x76, 0xbd, 0x1d, 0x78, 0x4f, 0x42, 0xea, 0x3e, 0x7c, 0xfe,
+ 0x62, 0x44, 0x52, 0x8b, 0xb6, 0xa4, 0xcb, 0xec, 0xc7, 0x9a, 0x07, 0xfd,
+ 0xd7, 0x1f, 0x4b, 0x0a, 0x79, 0x6e, 0x36, 0x62, 0x39, 0xae, 0xfc, 0x47,
+ 0x59, 0x9d, 0xcb, 0xc7, 0xb8, 0x77, 0x9d, 0x1f, 0xd5, 0xf0, 0xdc, 0x8f,
+ 0x71, 0x4d, 0xda, 0x6d, 0xac, 0x0f, 0xc6, 0xa9, 0xbe, 0xe8, 0x22, 0xee,
+ 0x65, 0xc7, 0x58, 0xe7, 0x79, 0x2a, 0x2c, 0x6d, 0x56, 0xac, 0x0c, 0x3b,
+ 0xb8, 0x54, 0xe4, 0x7c, 0xc0, 0x52, 0x45, 0xd6, 0x82, 0x82, 0xfb, 0x7f,
+ 0x0c, 0xec, 0xa8, 0x13, 0x3b, 0x79, 0x7d, 0x94, 0xbe, 0x5c, 0x33, 0x84,
+ 0x35, 0xb0, 0xe2, 0xfb, 0xe7, 0x85, 0xa2, 0x57, 0x7b, 0x39, 0x47, 0x3a,
+ 0xaa, 0x7f, 0x53, 0x5f, 0x89, 0x20, 0x67, 0x5a, 0xe7, 0xf1, 0x1c, 0xc7,
+ 0x37, 0xe1, 0x9e, 0xe5, 0x64, 0x35, 0x90, 0x05, 0xef, 0xb3, 0x8d, 0xfb,
+ 0xf3, 0xf5, 0xfa, 0x39, 0xfb, 0xc3, 0xd6, 0xd9, 0x9e, 0xbb, 0x27, 0x69,
+ 0xcb, 0x81, 0x85, 0xaa, 0x1c, 0xf0, 0xea, 0x6c, 0xd1, 0xbd, 0x5e, 0x9d,
+ 0x2d, 0xb6, 0x77, 0x63, 0x9d, 0xad, 0x7c, 0x8f, 0x57, 0x67, 0x33, 0x0f,
+ 0xc0, 0x07, 0x1f, 0xf0, 0xea, 0x6c, 0xff, 0xf5, 0x1e, 0xaf, 0xce, 0xd6,
+ 0x75, 0xaf, 0x57, 0x67, 0xeb, 0xdd, 0xeb, 0xd5, 0xd9, 0x46, 0xef, 0xdd,
+ 0x58, 0x67, 0x73, 0xf6, 0x6e, 0xac, 0xb3, 0x39, 0x07, 0x72, 0xf8, 0x5c,
+ 0xaf, 0xb3, 0x65, 0xf6, 0xde, 0xbc, 0xce, 0xf6, 0x4a, 0x80, 0xf1, 0xc1,
+ 0xcf, 0x00, 0x78, 0x70, 0x80, 0xf1, 0xfb, 0x81, 0xf1, 0x6f, 0x56, 0xe3,
+ 0x55, 0xe7, 0x37, 0xc0, 0xa7, 0xe6, 0xc7, 0x8f, 0x0f, 0x83, 0xf5, 0xb7,
+ 0xfa, 0xcf, 0xba, 0xc8, 0x8f, 0x63, 0x7e, 0x6e, 0x43, 0xbc, 0xbf, 0xcd,
+ 0xcf, 0xf1, 0xba, 0x5a, 0xaf, 0x9f, 0xad, 0x68, 0xfc, 0xbe, 0x0d, 0xa9,
+ 0x7a, 0x50, 0x03, 0x20, 0x5f, 0x72, 0xe0, 0x61, 0x25, 0x87, 0x3b, 0xd1,
+ 0xdf, 0x3c, 0xf0, 0x25, 0x9b, 0x75, 0x81, 0x27, 0xb1, 0x86, 0xdd, 0xed,
+ 0x86, 0xda, 0x67, 0x66, 0x4c, 0x3b, 0x2d, 0x29, 0xf4, 0x4f, 0xa9, 0xfe,
+ 0xa3, 0x0d, 0xfd, 0xb3, 0xe8, 0xcf, 0x71, 0xad, 0x7f, 0x8b, 0xcf, 0x73,
+ 0xca, 0xbe, 0x6d, 0x0f, 0xf7, 0xa7, 0x4b, 0x01, 0x4e, 0x0b, 0xf9, 0x18,
+ 0xdc, 0xcd, 0xb8, 0xd5, 0x7b, 0xf1, 0x8c, 0xf5, 0xa2, 0x2b, 0x57, 0x15,
+ 0xde, 0x37, 0x12, 0xd6, 0x8b, 0x59, 0x95, 0xdf, 0xb9, 0x99, 0x5c, 0x75,
+ 0x3d, 0x5f, 0x07, 0x0e, 0x63, 0xce, 0x03, 0x7b, 0x5f, 0xee, 0x45, 0xdc,
+ 0x6b, 0xcc, 0xc9, 0x99, 0x87, 0xeb, 0x7e, 0x1e, 0x6e, 0xca, 0xfd, 0xfb,
+ 0x1a, 0x31, 0xbe, 0x73, 0xe0, 0xef, 0x2b, 0x8c, 0xbf, 0x05, 0xb9, 0x3c,
+ 0x31, 0x3c, 0x71, 0x0f, 0x31, 0x07, 0x71, 0x3e, 0xeb, 0x0b, 0xcc, 0x7f,
+ 0x18, 0x4b, 0x99, 0x0f, 0x45, 0xf0, 0xe1, 0xb9, 0x97, 0x00, 0xeb, 0x37,
+ 0xfb, 0xfe, 0x9f, 0x79, 0x54, 0x80, 0x6d, 0xac, 0x2d, 0x5e, 0x2e, 0xb5,
+ 0x45, 0xf3, 0xf2, 0xd5, 0x98, 0xdf, 0x27, 0xb4, 0x8e, 0xa5, 0x43, 0xeb,
+ 0x58, 0x7a, 0xc3, 0x5e, 0x89, 0xa8, 0x33, 0x36, 0x6a, 0xcf, 0x85, 0x7b,
+ 0x30, 0x6e, 0xe6, 0x52, 0x0f, 0xf1, 0x30, 0xf7, 0x62, 0x80, 0x8d, 0xec,
+ 0xc6, 0x58, 0xc5, 0x38, 0x45, 0x3c, 0x15, 0xec, 0xb7, 0x06, 0x7a, 0xa2,
+ 0xec, 0xd8, 0xf6, 0x47, 0x1a, 0x72, 0x64, 0xa7, 0xd9, 0xde, 0x0f, 0x5a,
+ 0x32, 0xf8, 0x0e, 0x64, 0xfa, 0x80, 0x8a, 0x91, 0x2d, 0xb0, 0xdd, 0x13,
+ 0x25, 0x62, 0xde, 0x6d, 0xb2, 0xe8, 0xe3, 0xde, 0xf3, 0x33, 0x1e, 0xe6,
+ 0x0d, 0x6d, 0xc4, 0xbc, 0xce, 0xaa, 0x78, 0x34, 0xee, 0xbf, 0x21, 0x8d,
+ 0xc4, 0xb7, 0xa4, 0x8f, 0x31, 0x89, 0xfe, 0xd1, 0xcd, 0x5c, 0xee, 0x61,
+ 0x3c, 0x62, 0x2c, 0x8a, 0xc9, 0xea, 0x4d, 0xe9, 0x53, 0x6d, 0xc7, 0x5a,
+ 0xec, 0x30, 0x3e, 0x13, 0xf0, 0x1f, 0xa3, 0x78, 0x26, 0x23, 0x93, 0xb3,
+ 0x5f, 0x00, 0x6f, 0x13, 0x72, 0x69, 0x66, 0x0c, 0xf4, 0x3d, 0x29, 0x53,
+ 0x4e, 0x1e, 0x7e, 0x84, 0x7b, 0x21, 0xc4, 0x79, 0xdd, 0xfe, 0xf7, 0x84,
+ 0x7e, 0xce, 0xb6, 0x88, 0x33, 0xa5, 0x52, 0xa4, 0x0f, 0xe6, 0xbe, 0x14,
+ 0xf7, 0x1f, 0x69, 0x3f, 0xac, 0xc3, 0x20, 0xd7, 0x65, 0xce, 0x3b, 0xcd,
+ 0xf9, 0x37, 0xea, 0x64, 0xb5, 0x4a, 0xbc, 0xe6, 0x66, 0x56, 0x96, 0x89,
+ 0x37, 0x3f, 0x28, 0xf6, 0xa4, 0x1e, 0x88, 0x3f, 0x6f, 0x05, 0x77, 0x5a,
+ 0x33, 0xc0, 0x9c, 0x2f, 0xac, 0xe8, 0x8d, 0xb8, 0xd3, 0xc3, 0x9c, 0xc9,
+ 0xe5, 0x2c, 0xc6, 0x74, 0x14, 0xb6, 0x46, 0xde, 0x07, 0xb7, 0xd7, 0x8d,
+ 0x67, 0xbb, 0x91, 0xc3, 0x7b, 0x18, 0x33, 0x05, 0x8c, 0xf9, 0x0f, 0x81,
+ 0x31, 0x27, 0xe5, 0xad, 0x56, 0x62, 0x4c, 0xd7, 0xc7, 0x98, 0x69, 0xd8,
+ 0x73, 0x6e, 0x83, 0x3d, 0x6b, 0xaa, 0x76, 0xc5, 0x7b, 0x39, 0x60, 0xc4,
+ 0xd4, 0xb4, 0x75, 0x0b, 0xb8, 0x52, 0x93, 0x88, 0x3a, 0xfb, 0x10, 0x6a,
+ 0x18, 0x33, 0xc0, 0x8f, 0x7b, 0x14, 0x2e, 0x3c, 0x50, 0xda, 0x82, 0x1c,
+ 0x46, 0xe1, 0x44, 0x7f, 0x4f, 0x2e, 0xb4, 0x69, 0x9f, 0x32, 0xd4, 0xb0,
+ 0x4f, 0x79, 0x1d, 0x4f, 0xe2, 0x39, 0xbf, 0x3e, 0xd8, 0x04, 0x5f, 0xf0,
+ 0x7f, 0x40, 0x13, 0xd7, 0x17, 0xd7, 0x82, 0xe6, 0xad, 0x97, 0xd1, 0x46,
+ 0x5c, 0xf9, 0xbf, 0x36, 0xe1, 0x4a, 0xc4, 0xae, 0xf3, 0x11, 0x49, 0x02,
+ 0x53, 0xba, 0xcb, 0x1c, 0x8b, 0x6b, 0xba, 0x5f, 0x9a, 0xc1, 0x5f, 0xcb,
+ 0x74, 0x27, 0xb0, 0x54, 0x9b, 0x84, 0x81, 0xa9, 0x9a, 0x14, 0xa6, 0xea,
+ 0x21, 0xf6, 0xe9, 0x3d, 0x02, 0x2c, 0xb4, 0xb8, 0x8e, 0xab, 0x2c, 0xe7,
+ 0x87, 0xd0, 0xcb, 0xa3, 0xca, 0xf7, 0xa4, 0xe5, 0x29, 0xf8, 0xd2, 0xe6,
+ 0x65, 0xe0, 0xc1, 0xf3, 0x1e, 0xde, 0x6a, 0xda, 0x84, 0xb7, 0x8e, 0xde,
+ 0x10, 0x6f, 0xa9, 0x9a, 0xff, 0x20, 0x65, 0xf2, 0x7a, 0xd5, 0xab, 0xf9,
+ 0x5f, 0xa9, 0x7a, 0x35, 0xff, 0xd7, 0xab, 0x8d, 0x35, 0xff, 0x8f, 0x48,
+ 0xc1, 0xb4, 0xdc, 0x35, 0xd9, 0x54, 0xf3, 0x1f, 0x65, 0x0d, 0xfd, 0xf7,
+ 0xda, 0xbc, 0xda, 0x7e, 0x9b, 0x5f, 0xf3, 0xb7, 0xa4, 0xb0, 0xa1, 0xdd,
+ 0x94, 0xb7, 0xec, 0xa0, 0xe6, 0xff, 0x34, 0xda, 0xda, 0x31, 0xc7, 0xc6,
+ 0x7a, 0xff, 0x95, 0x2a, 0xeb, 0xfd, 0x11, 0xf6, 0xf3, 0xeb, 0xfd, 0xec,
+ 0x87, 0xdc, 0xbf, 0xca, 0x5a, 0xff, 0x6e, 0xc8, 0x62, 0x27, 0xe4, 0xd0,
+ 0x29, 0xcd, 0x67, 0xa3, 0xec, 0xa3, 0x6a, 0xfc, 0x6b, 0xc8, 0x37, 0xae,
+ 0x54, 0xbd, 0x5a, 0xfc, 0x11, 0xd8, 0xd5, 0xd1, 0xf5, 0x1a, 0xbf, 0x37,
+ 0xc7, 0xd5, 0xea, 0xc6, 0xf1, 0x37, 0x8e, 0xd3, 0xe5, 0x8f, 0x13, 0xc1,
+ 0x38, 0xd1, 0x4d, 0xe3, 0x5c, 0xaf, 0xe9, 0x5f, 0xad, 0x7a, 0xf5, 0xfc,
+ 0xf4, 0xac, 0xb8, 0xcd, 0xf0, 0xcd, 0x2f, 0xf6, 0xec, 0xf2, 0xc7, 0x58,
+ 0xaf, 0xe7, 0xd3, 0x87, 0x00, 0xe7, 0xc7, 0xd5, 0xf9, 0x9e, 0x23, 0xff,
+ 0x1f, 0xea, 0xf9, 0xac, 0xe5, 0x7b, 0x7b, 0x32, 0x5c, 0x9f, 0xc0, 0xf3,
+ 0xcf, 0x7a, 0x75, 0xfc, 0xa1, 0x52, 0x50, 0x9f, 0x67, 0x5e, 0x19, 0x9c,
+ 0xbd, 0xe9, 0x8e, 0x9d, 0x10, 0xda, 0x0a, 0xe9, 0xe3, 0xb8, 0xed, 0x32,
+ 0xae, 0xf0, 0x14, 0x6c, 0x2a, 0x7e, 0x73, 0x4c, 0xbd, 0x30, 0x1d, 0x60,
+ 0xea, 0x88, 0xc2, 0xd4, 0x0b, 0xcb, 0x01, 0xa6, 0x4e, 0xde, 0x04, 0x53,
+ 0xff, 0xf7, 0x36, 0x2f, 0x0e, 0x84, 0x25, 0xaf, 0x30, 0xf5, 0xcd, 0xce,
+ 0x2b, 0xf1, 0x5e, 0x1b, 0xf1, 0x82, 0x78, 0x7b, 0xd8, 0x9d, 0x37, 0x59,
+ 0x6b, 0x01, 0xce, 0x66, 0xec, 0xdf, 0x29, 0xa3, 0x67, 0xaf, 0xe3, 0x6c,
+ 0x0f, 0x4b, 0x5b, 0xb1, 0x63, 0x2a, 0x26, 0x02, 0xd7, 0xd5, 0x58, 0x2f,
+ 0x27, 0x56, 0x66, 0xcc, 0x09, 0x29, 0x3c, 0x97, 0x2b, 0x32, 0x0f, 0x60,
+ 0x1b, 0xb1, 0x73, 0x2b, 0x8f, 0xf2, 0xf8, 0x31, 0x29, 0xc0, 0xa6, 0xc1,
+ 0xd9, 0x09, 0xee, 0x4b, 0xbc, 0x65, 0x24, 0x6d, 0xb4, 0x57, 0x83, 0x5c,
+ 0xc1, 0x51, 0x67, 0x4e, 0x92, 0xc0, 0x3f, 0xe3, 0xeb, 0xd8, 0x93, 0xbe,
+ 0xe2, 0x47, 0xbf, 0x70, 0x4d, 0xfa, 0xb5, 0x00, 0x5b, 0x22, 0x27, 0x2a,
+ 0x71, 0x6d, 0x07, 0xd8, 0xd2, 0xc3, 0x95, 0xa9, 0xea, 0x0a, 0xf0, 0x75,
+ 0x48, 0x86, 0x80, 0xeb, 0x57, 0x1e, 0x66, 0xcd, 0x2a, 0xc0, 0x4e, 0x2e,
+ 0xbe, 0x1b, 0x6b, 0x58, 0xbc, 0x6e, 0x56, 0x7b, 0x87, 0x17, 0x7b, 0xc2,
+ 0x0d, 0xed, 0xbf, 0x05, 0xff, 0x8d, 0xfc, 0x08, 0x98, 0xc5, 0xc3, 0x4c,
+ 0x7b, 0xa1, 0x83, 0x01, 0x85, 0x99, 0xa6, 0xde, 0x83, 0x99, 0x36, 0xc7,
+ 0x28, 0xc6, 0xcc, 0xeb, 0x31, 0x2a, 0x5d, 0xa3, 0x3f, 0xbf, 0x1e, 0xa3,
+ 0x6e, 0x1e, 0x43, 0xd9, 0x06, 0xee, 0xec, 0x0c, 0x3e, 0x13, 0x52, 0xd8,
+ 0x14, 0xa3, 0xa6, 0x3e, 0x44, 0x8c, 0x1a, 0x56, 0x31, 0xca, 0xa3, 0xfb,
+ 0xfb, 0x90, 0xcd, 0x77, 0x21, 0xd3, 0xef, 0x00, 0x8b, 0x7d, 0x1b, 0x7c,
+ 0x7d, 0x0b, 0x38, 0xe9, 0x9b, 0xa5, 0xcd, 0x67, 0x0e, 0x06, 0x85, 0xf9,
+ 0xa1, 0x87, 0xa5, 0xbc, 0x1a, 0xc0, 0x11, 0xac, 0xae, 0xc5, 0xa2, 0x9b,
+ 0x19, 0x2f, 0xf6, 0x99, 0x13, 0xde, 0xde, 0x6b, 0x2c, 0x2b, 0x8f, 0xb5,
+ 0xa6, 0xe6, 0x19, 0x33, 0xd4, 0x75, 0x94, 0xf5, 0x4e, 0x62, 0x87, 0x8a,
+ 0xca, 0x33, 0x7b, 0xa4, 0xbc, 0xe8, 0xe1, 0xb0, 0xa9, 0x79, 0x6f, 0x8c,
+ 0x71, 0x1f, 0x87, 0xe5, 0x7c, 0x1c, 0x96, 0x5d, 0x5c, 0x8d, 0x85, 0xd0,
+ 0x7f, 0xca, 0xd9, 0x88, 0xbd, 0x8e, 0xf8, 0xd8, 0x6b, 0xe2, 0x43, 0x61,
+ 0x2f, 0x6f, 0xae, 0x1c, 0x9e, 0x19, 0x9e, 0x89, 0xc9, 0x7e, 0xc8, 0x79,
+ 0xa8, 0x48, 0x7d, 0xf1, 0x9c, 0xd2, 0x2f, 0xd3, 0x19, 0xf5, 0xe5, 0xe9,
+ 0x2a, 0x14, 0x3f, 0xa8, 0x0d, 0x43, 0x57, 0x43, 0xbf, 0x54, 0x57, 0x62,
+ 0xbe, 0x39, 0x10, 0xc6, 0xe7, 0x6f, 0x4b, 0x57, 0xe4, 0x83, 0xfa, 0xda,
+ 0x8c, 0xc5, 0x6e, 0x05, 0x93, 0x6d, 0xc4, 0x63, 0xae, 0xc2, 0x63, 0xcd,
+ 0x7e, 0x9f, 0xfc, 0x81, 0x61, 0xe8, 0xf2, 0x3f, 0xa0, 0xcf, 0x8f, 0xed,
+ 0x76, 0xf9, 0x11, 0xfc, 0xf7, 0xbf, 0x87, 0x4e, 0xfe, 0x1d, 0x72, 0x85,
+ 0x57, 0xec, 0x2e, 0xf9, 0x21, 0xda, 0xae, 0xe3, 0x1c, 0xf6, 0x9f, 0x72,
+ 0x92, 0xf6, 0x28, 0xf0, 0xc9, 0xa8, 0x8f, 0x4f, 0xde, 0x7a, 0x20, 0x69,
+ 0x8f, 0xb1, 0xce, 0x0e, 0x39, 0xff, 0x34, 0x39, 0xae, 0xb0, 0x49, 0x80,
+ 0x49, 0x1e, 0x4f, 0x73, 0xfe, 0xc9, 0x6a, 0x16, 0xd8, 0x27, 0xeb, 0x63,
+ 0x9f, 0x9f, 0xa6, 0x3d, 0xec, 0x33, 0xf5, 0xf7, 0xa8, 0x7f, 0x0f, 0xf7,
+ 0x1c, 0x76, 0x93, 0x98, 0x07, 0xb8, 0x07, 0xd7, 0x87, 0x25, 0x5f, 0x1b,
+ 0x51, 0x9f, 0x13, 0x25, 0xd7, 0x6a, 0x82, 0x9c, 0x58, 0xab, 0x3d, 0xc3,
+ 0x55, 0x59, 0xb5, 0xcc, 0x22, 0xbe, 0xb3, 0x55, 0x2b, 0xfa, 0x7b, 0xfe,
+ 0xf5, 0xd3, 0xfe, 0xf5, 0x53, 0xfe, 0xf5, 0x69, 0xc4, 0xe1, 0x53, 0x2a,
+ 0x96, 0xb2, 0x9d, 0x6d, 0x50, 0x72, 0x15, 0x63, 0x01, 0x7b, 0x9c, 0xeb,
+ 0xff, 0xf3, 0x7a, 0x59, 0xe9, 0x98, 0xe3, 0x8f, 0xe2, 0x73, 0x1a, 0x9f,
+ 0x09, 0x7c, 0x0e, 0xe1, 0x93, 0xc7, 0x67, 0x5d, 0xa6, 0x5a, 0xaa, 0x34,
+ 0x06, 0x1b, 0xe9, 0x95, 0x54, 0xed, 0x39, 0xe8, 0xf1, 0x49, 0xe8, 0xf6,
+ 0xb8, 0x14, 0x2a, 0x7f, 0x22, 0x93, 0x33, 0x9a, 0xb4, 0xd9, 0xd0, 0x69,
+ 0x05, 0xb6, 0x3c, 0xe3, 0xed, 0x41, 0xb6, 0x26, 0x46, 0xd0, 0xb7, 0x2e,
+ 0x8f, 0x3a, 0x4f, 0x8a, 0x7e, 0xdf, 0x14, 0xfa, 0x89, 0x5e, 0xe8, 0xbf,
+ 0x5b, 0xed, 0xbf, 0x55, 0x1c, 0x4f, 0xc6, 0xfb, 0x6d, 0xd7, 0x82, 0xce,
+ 0x7b, 0x4f, 0x61, 0xec, 0xa4, 0x3a, 0x7f, 0x99, 0x91, 0x93, 0xb3, 0xab,
+ 0xdb, 0x3d, 0xdf, 0x6a, 0x99, 0x57, 0xa9, 0x77, 0xf0, 0xe1, 0xc2, 0x17,
+ 0x66, 0x60, 0xef, 0x47, 0xab, 0x21, 0x6d, 0x08, 0xf1, 0x66, 0xa8, 0x7a,
+ 0x55, 0xc5, 0x9b, 0x54, 0xd5, 0xcd, 0xc4, 0xcf, 0x44, 0x70, 0xcd, 0x73,
+ 0x31, 0x88, 0x8b, 0xea, 0xfc, 0xde, 0x2a, 0xf0, 0x8d, 0xa6, 0xea, 0x86,
+ 0x93, 0xeb, 0xfb, 0x4a, 0xea, 0x7c, 0x71, 0x26, 0x1e, 0xd7, 0x25, 0x37,
+ 0x40, 0x9c, 0x3b, 0xa2, 0x62, 0x13, 0xd6, 0xea, 0xed, 0xcc, 0x15, 0x5f,
+ 0xe7, 0xbb, 0x00, 0xf6, 0x27, 0xd0, 0xaf, 0x0b, 0xfe, 0x18, 0xf7, 0x6a,
+ 0xb4, 0x4f, 0xf2, 0xca, 0x67, 0x26, 0xa4, 0x52, 0x1e, 0x04, 0xbf, 0x7e,
+ 0x8e, 0xa4, 0x72, 0x89, 0x18, 0xec, 0x31, 0xd8, 0xc3, 0xf2, 0xea, 0x2a,
+ 0x95, 0x6a, 0x80, 0x29, 0xda, 0xd1, 0x87, 0x79, 0x05, 0x64, 0xe4, 0xed,
+ 0xbf, 0xa9, 0xbd, 0xb7, 0x42, 0x75, 0x10, 0x72, 0x4a, 0xa2, 0x9d, 0xb5,
+ 0x6d, 0xfc, 0x2e, 0xeb, 0xaa, 0x26, 0xb0, 0x66, 0x1c, 0x91, 0xc5, 0x72,
+ 0x1d, 0xf4, 0x22, 0xe6, 0x6e, 0x3f, 0x22, 0x0b, 0xe5, 0x09, 0x79, 0xa1,
+ 0xfc, 0xcd, 0x76, 0x60, 0x2a, 0xc8, 0x94, 0xf4, 0xb7, 0xcb, 0xf5, 0x33,
+ 0x9e, 0x41, 0x3b, 0xe4, 0x39, 0x9b, 0x8f, 0x7a, 0x79, 0x6e, 0x5e, 0xd5,
+ 0x68, 0xbc, 0x6f, 0x57, 0x1f, 0xb7, 0xad, 0xe8, 0x24, 0x7a, 0x1e, 0x9d,
+ 0x53, 0xb6, 0x39, 0x3c, 0x65, 0xef, 0x95, 0xcb, 0xce, 0x36, 0x59, 0x75,
+ 0x54, 0x5e, 0x4c, 0xfc, 0x80, 0xb5, 0x6e, 0x99, 0x2b, 0xf2, 0xa0, 0x9c,
+ 0xc4, 0xba, 0xbd, 0xec, 0x3c, 0x06, 0x3b, 0x7d, 0x02, 0xb6, 0xc0, 0x1a,
+ 0xc0, 0x31, 0xe6, 0x5a, 0xb2, 0xa2, 0x6a, 0x68, 0xf5, 0xfa, 0xb0, 0x3a,
+ 0x27, 0xdc, 0x2c, 0xab, 0x0a, 0x8b, 0x79, 0xb5, 0xf6, 0xd5, 0x31, 0x6f,
+ 0x8d, 0x18, 0xca, 0xee, 0xbf, 0x01, 0x7a, 0x8a, 0xb0, 0xdd, 0x26, 0xd5,
+ 0xc7, 0x48, 0xb4, 0xf8, 0x7d, 0x14, 0x06, 0x6d, 0xe8, 0x63, 0x27, 0x92,
+ 0xf6, 0x6b, 0xfb, 0x92, 0xf6, 0xc4, 0x81, 0x5c, 0xd5, 0xf3, 0x99, 0xae,
+ 0xb6, 0xb6, 0x5e, 0xff, 0xc9, 0x60, 0x5d, 0xbd, 0xbc, 0x8e, 0xa1, 0x61,
+ 0xa4, 0xcf, 0x5f, 0x82, 0x7e, 0x43, 0xd2, 0x7c, 0xa6, 0xfe, 0x89, 0x71,
+ 0xa7, 0x2f, 0x76, 0x54, 0x78, 0x32, 0x8b, 0x79, 0xb5, 0xe5, 0x64, 0xe5,
+ 0x12, 0xe2, 0xe4, 0x35, 0x62, 0x87, 0xde, 0x8b, 0x72, 0xed, 0x13, 0x49,
+ 0x67, 0x50, 0x5b, 0x18, 0x43, 0xd6, 0xf2, 0xfc, 0x18, 0xe3, 0xec, 0x31,
+ 0x11, 0xe0, 0xcb, 0x33, 0x03, 0x92, 0x2e, 0xaa, 0x77, 0x21, 0x78, 0x96,
+ 0x53, 0x9b, 0x80, 0xfc, 0xf0, 0xfc, 0x28, 0x03, 0xa3, 0x6e, 0x77, 0xc7,
+ 0xd2, 0xf2, 0x18, 0x6b, 0x63, 0x92, 0x9b, 0x93, 0x3d, 0x49, 0xf8, 0x55,
+ 0x77, 0xb4, 0x59, 0x26, 0x16, 0xdd, 0x4c, 0xf7, 0xf4, 0x13, 0x18, 0x63,
+ 0x1c, 0x63, 0x8d, 0x20, 0x37, 0xc9, 0x22, 0x56, 0x53, 0xbe, 0xf4, 0xdd,
+ 0x8f, 0x43, 0x46, 0x1f, 0xe1, 0x59, 0xd7, 0xc1, 0xac, 0x58, 0xa3, 0x79,
+ 0x35, 0xee, 0xbb, 0x5a, 0xae, 0xff, 0x57, 0x10, 0xeb, 0x42, 0xb2, 0x3f,
+ 0x2e, 0xfa, 0x48, 0x3c, 0xf4, 0x8b, 0x71, 0x9b, 0x6d, 0x61, 0xb6, 0xe9,
+ 0x68, 0x0b, 0xfd, 0x66, 0x3c, 0xac, 0x27, 0xe3, 0xd6, 0x20, 0xcf, 0xe0,
+ 0x1a, 0xf6, 0xb8, 0x18, 0xcf, 0xd7, 0x21, 0x8b, 0x11, 0xe9, 0xb8, 0x60,
+ 0x0d, 0xbe, 0x0e, 0x5a, 0x42, 0xca, 0xd7, 0x8f, 0x8b, 0xee, 0xb7, 0xb7,
+ 0xaf, 0xb7, 0x87, 0xfc, 0xf6, 0x11, 0x69, 0xbb, 0xd0, 0x67, 0xbe, 0x21,
+ 0x47, 0x30, 0xa6, 0x21, 0x57, 0x90, 0xeb, 0xd8, 0x3d, 0xe3, 0xb0, 0xc5,
+ 0x47, 0x48, 0xcb, 0x21, 0xd6, 0x1b, 0x5d, 0xd8, 0x5f, 0x8b, 0x7d, 0x87,
+ 0x7c, 0xde, 0x6c, 0x95, 0x9c, 0xca, 0x75, 0x43, 0xea, 0xbd, 0x85, 0x1c,
+ 0xec, 0xfd, 0xae, 0x9e, 0xa1, 0x0e, 0xaf, 0x5e, 0xc0, 0xfd, 0x91, 0x7e,
+ 0xb4, 0x5d, 0xab, 0x9f, 0xb7, 0xd9, 0xc6, 0x7b, 0xd7, 0xea, 0x15, 0xbb,
+ 0xcf, 0x4c, 0x69, 0x61, 0x7f, 0xff, 0xfc, 0x98, 0xe2, 0x3d, 0x5f, 0xee,
+ 0x36, 0x17, 0xe4, 0x2e, 0x2d, 0xb5, 0x03, 0xf1, 0xa2, 0x9a, 0x42, 0xdf,
+ 0x6b, 0x3c, 0x83, 0xa1, 0xf6, 0x03, 0x16, 0x24, 0xb8, 0xe6, 0x38, 0x7d,
+ 0xe6, 0xb0, 0x7a, 0xb6, 0xcf, 0x3c, 0xa9, 0x35, 0x3e, 0x1b, 0xd5, 0x86,
+ 0x37, 0x3c, 0xdb, 0xa6, 0x64, 0x64, 0xd8, 0x5e, 0x9f, 0xc9, 0xf2, 0x88,
+ 0x3c, 0x5d, 0x65, 0xbf, 0x6b, 0xf5, 0x94, 0xbd, 0x55, 0x3b, 0xb9, 0x83,
+ 0xbe, 0x90, 0x7d, 0xdf, 0xd9, 0x34, 0x0f, 0xaf, 0x6f, 0x36, 0x47, 0x5d,
+ 0x36, 0xce, 0xb1, 0x45, 0xf5, 0xb9, 0xac, 0xfa, 0x84, 0x94, 0xac, 0x37,
+ 0xce, 0xf3, 0x17, 0xb2, 0x71, 0x9e, 0xb6, 0x75, 0x9e, 0x27, 0x31, 0xe6,
+ 0x29, 0xf4, 0x2d, 0x56, 0xbb, 0xa3, 0x15, 0x79, 0xa7, 0x9e, 0xb3, 0xdf,
+ 0x92, 0xcb, 0xeb, 0x63, 0xff, 0x25, 0xae, 0x1b, 0x69, 0xfa, 0x4b, 0x9f,
+ 0x46, 0xfe, 0x66, 0xdb, 0x3f, 0x53, 0xf2, 0xde, 0x6a, 0x77, 0x1f, 0x5a,
+ 0xd0, 0xac, 0xc1, 0x9f, 0x09, 0x75, 0xf5, 0x3b, 0xca, 0xd7, 0xdc, 0x0d,
+ 0x3d, 0xed, 0x79, 0x06, 0x6b, 0xb7, 0x3f, 0xa9, 0xfa, 0x5c, 0xb1, 0x47,
+ 0x64, 0xcf, 0x99, 0x6e, 0xf3, 0x8a, 0xdc, 0x2f, 0xe9, 0x08, 0xaf, 0x91,
+ 0x43, 0xd9, 0x7c, 0xf7, 0xe1, 0x57, 0x99, 0x17, 0x40, 0x97, 0xdd, 0xbd,
+ 0x3f, 0x93, 0x27, 0xe4, 0x64, 0x69, 0x0a, 0xbe, 0x67, 0x5c, 0x7a, 0x9f,
+ 0xa1, 0xff, 0xc9, 0x9b, 0x5e, 0xad, 0xc6, 0x8b, 0x89, 0x29, 0x3f, 0x26,
+ 0x4e, 0x29, 0x3f, 0xf7, 0x8a, 0x7f, 0x8e, 0xa2, 0xbb, 0xf7, 0x3c, 0x9e,
+ 0x7d, 0x41, 0xf9, 0x80, 0x6f, 0x48, 0x05, 0x6b, 0x21, 0xf6, 0xfc, 0x36,
+ 0xd9, 0xfa, 0x10, 0x6d, 0x12, 0x19, 0xc0, 0xdd, 0x4d, 0xea, 0x5d, 0x0b,
+ 0xdd, 0x6e, 0x11, 0xd9, 0x4e, 0xfb, 0x59, 0xd8, 0x2a, 0x6d, 0xe3, 0xde,
+ 0x5e, 0xd9, 0x86, 0x6b, 0x6b, 0x74, 0x4d, 0xca, 0x5b, 0x69, 0x87, 0x1f,
+ 0xbd, 0xe0, 0x7d, 0xf7, 0x5f, 0x40, 0xba, 0x1c, 0x1f, 0x91, 0x7b, 0x2f,
+ 0x78, 0x76, 0x37, 0x39, 0xf3, 0x84, 0x92, 0xef, 0xb8, 0x92, 0x6f, 0x5d,
+ 0x8e, 0x38, 0x94, 0x3d, 0x79, 0xe2, 0xb9, 0x4a, 0x4f, 0x26, 0x9f, 0xf4,
+ 0xed, 0xa8, 0xfb, 0x19, 0xbe, 0x23, 0x46, 0x19, 0x91, 0xee, 0x74, 0x07,
+ 0xf7, 0x6f, 0xf7, 0x5c, 0x20, 0xbf, 0x5d, 0x1b, 0xf8, 0x7d, 0x0a, 0x3e,
+ 0xb6, 0xa7, 0xc7, 0xe3, 0xf9, 0x95, 0x99, 0x0f, 0xce, 0xf3, 0xd7, 0xd6,
+ 0x79, 0x36, 0xa4, 0xa2, 0xf2, 0xdc, 0xd0, 0x36, 0x69, 0xcb, 0xc9, 0x0a,
+ 0xec, 0xe3, 0xcf, 0x84, 0xe7, 0x92, 0x49, 0x8b, 0x37, 0xef, 0x6a, 0x95,
+ 0x34, 0x05, 0x3c, 0x90, 0xae, 0xa4, 0xaf, 0x3f, 0xd2, 0xf1, 0xc4, 0x0d,
+ 0xef, 0x5d, 0x11, 0x37, 0xd3, 0x8b, 0x36, 0x5d, 0xe9, 0x70, 0xc8, 0x5f,
+ 0x6f, 0x23, 0xa2, 0x2b, 0x1d, 0x26, 0xd7, 0x75, 0xf8, 0x3a, 0x74, 0x58,
+ 0x91, 0x8f, 0x83, 0x27, 0xac, 0xef, 0x67, 0xfa, 0xcc, 0x23, 0xb2, 0x53,
+ 0xe9, 0xdf, 0xee, 0x81, 0x4f, 0xf5, 0x75, 0xd9, 0x7c, 0x0b, 0xba, 0x7c,
+ 0x43, 0x94, 0x3e, 0xd5, 0xd9, 0xa3, 0x8a, 0x1a, 0x87, 0xbe, 0x8d, 0xbc,
+ 0x35, 0x2b, 0x9f, 0x40, 0x1a, 0xd5, 0x59, 0x82, 0x51, 0x4f, 0xbf, 0x6a,
+ 0xcd, 0xfb, 0xfa, 0xcd, 0x8e, 0x52, 0x87, 0xd1, 0x0e, 0x4f, 0x9f, 0x2d,
+ 0xaa, 0xcf, 0x74, 0xfc, 0x36, 0xb5, 0xde, 0xed, 0x9e, 0x9d, 0x1d, 0xd4,
+ 0xe9, 0xd3, 0x55, 0xef, 0xbb, 0x88, 0x38, 0x37, 0x5d, 0xfd, 0x65, 0x7a,
+ 0xf5, 0x74, 0x3a, 0x24, 0xde, 0xba, 0xda, 0xac, 0x4f, 0xfd, 0x42, 0x48,
+ 0xd9, 0xf0, 0x10, 0x64, 0x78, 0xba, 0xb4, 0xc3, 0xb7, 0x7b, 0x8f, 0xe7,
+ 0x9e, 0x0f, 0xc8, 0xf3, 0x89, 0x62, 0xb7, 0xf9, 0x16, 0xee, 0x0d, 0x83,
+ 0xe7, 0x23, 0xd2, 0x24, 0x29, 0x9f, 0xe7, 0xd8, 0x3a, 0xcf, 0x01, 0x8d,
+ 0x5e, 0xbf, 0x14, 0xf3, 0xd8, 0x2a, 0xfd, 0xd7, 0xef, 0xaa, 0x77, 0x1a,
+ 0xae, 0x16, 0xe9, 0xb7, 0x81, 0x95, 0x22, 0x9d, 0x72, 0x65, 0x31, 0x26,
+ 0x57, 0x88, 0x41, 0x06, 0xf0, 0x5d, 0x9d, 0xf2, 0x63, 0x78, 0x58, 0xde,
+ 0x28, 0xde, 0x88, 0x8e, 0x7e, 0x79, 0xbd, 0x18, 0xd0, 0x42, 0x2c, 0xcc,
+ 0x7c, 0x61, 0x5c, 0xde, 0x9c, 0xe9, 0x96, 0x95, 0x51, 0xc4, 0xfd, 0x1e,
+ 0xca, 0xa4, 0xcf, 0x7c, 0x50, 0xbd, 0xeb, 0x72, 0xad, 0x7e, 0xd1, 0xc6,
+ 0xf8, 0x73, 0x75, 0x39, 0xca, 0xfd, 0x6f, 0xfe, 0x5e, 0xbc, 0x5d, 0x56,
+ 0x98, 0x53, 0xf4, 0x74, 0xca, 0xc2, 0x1c, 0xf2, 0xf9, 0x22, 0xc7, 0xa7,
+ 0xdc, 0x46, 0xd4, 0xef, 0x61, 0xcc, 0xf7, 0x49, 0x9e, 0x41, 0x8f, 0x50,
+ 0x37, 0xd7, 0xea, 0xab, 0x36, 0xf7, 0x3f, 0xc7, 0x65, 0x11, 0xfa, 0xfb,
+ 0x47, 0x71, 0xee, 0xcf, 0xe7, 0xd4, 0xfb, 0x85, 0x0b, 0x8b, 0xa3, 0xc8,
+ 0x1d, 0xae, 0xd5, 0xa7, 0xec, 0x29, 0xa5, 0xb7, 0xc5, 0xf2, 0x43, 0x7e,
+ 0x3b, 0xaf, 0x79, 0xcf, 0xcd, 0xec, 0xe9, 0x61, 0xbe, 0xfa, 0x10, 0xf2,
+ 0x05, 0xe6, 0xaa, 0xa3, 0xc0, 0x6b, 0x94, 0x49, 0x4c, 0x26, 0x8b, 0x1c,
+ 0x4b, 0x22, 0x5b, 0x90, 0xdf, 0xe7, 0x64, 0x18, 0xf4, 0xc4, 0x90, 0xdb,
+ 0x33, 0x3e, 0xdc, 0x25, 0xab, 0x11, 0x2f, 0x0e, 0xf0, 0xac, 0xd8, 0x2a,
+ 0x62, 0xc3, 0xea, 0x7a, 0x6c, 0xd8, 0x89, 0x6b, 0x37, 0xe3, 0xf4, 0xfc,
+ 0x67, 0x8c, 0xcf, 0xba, 0x0d, 0x63, 0xc3, 0x20, 0xfa, 0xb3, 0xad, 0x53,
+ 0x26, 0xe7, 0x90, 0x44, 0x20, 0x67, 0x59, 0x10, 0x9e, 0x01, 0xc9, 0xca,
+ 0xf4, 0x62, 0x77, 0xf4, 0xa2, 0x96, 0x56, 0x67, 0x45, 0xe2, 0x98, 0x73,
+ 0xa1, 0xd8, 0x29, 0x8b, 0x73, 0x12, 0x33, 0x12, 0x8f, 0x48, 0x75, 0xd1,
+ 0xc3, 0xec, 0x53, 0x1a, 0xda, 0xab, 0xae, 0x2c, 0x6e, 0xec, 0x63, 0x1a,
+ 0x89, 0xc3, 0xf2, 0x75, 0xbf, 0x4f, 0x5a, 0xf5, 0x79, 0xb5, 0x83, 0x7b,
+ 0x6c, 0x8b, 0xd5, 0x0e, 0xd0, 0x40, 0xda, 0x76, 0x35, 0xce, 0x1b, 0xbb,
+ 0x3e, 0x2f, 0xe7, 0x44, 0x36, 0xb3, 0xdd, 0xc5, 0xbc, 0x17, 0xf1, 0xcc,
+ 0x23, 0xa0, 0xe3, 0x9a, 0xa1, 0xdb, 0x8f, 0x48, 0x61, 0x71, 0xf3, 0x1c,
+ 0x8d, 0x34, 0xf0, 0x19, 0x8e, 0xcf, 0x79, 0x0e, 0x83, 0xbe, 0x6b, 0x9a,
+ 0x6e, 0x1f, 0x86, 0x2c, 0xbd, 0x39, 0x8c, 0xb3, 0x96, 0xf9, 0x23, 0xe9,
+ 0x11, 0xfd, 0xbc, 0xa6, 0xe4, 0xaf, 0x2f, 0xf4, 0x63, 0x81, 0x64, 0xa4,
+ 0x6d, 0x79, 0x4c, 0x8c, 0x65, 0xd6, 0x10, 0x5e, 0x69, 0x4d, 0xab, 0xfd,
+ 0xde, 0x2d, 0x58, 0xdf, 0xe2, 0x86, 0x6c, 0xd6, 0x0b, 0x58, 0x0f, 0xfe,
+ 0xfa, 0x36, 0xe9, 0x60, 0xbd, 0x80, 0x79, 0xc3, 0x21, 0x7c, 0x33, 0x77,
+ 0x78, 0xb9, 0x9e, 0x74, 0x7e, 0xa6, 0xe2, 0x6b, 0x6e, 0x91, 0xf7, 0xad,
+ 0x98, 0x08, 0xef, 0xd1, 0x6f, 0x74, 0x4a, 0xd3, 0x57, 0x7a, 0xe1, 0x2b,
+ 0x1e, 0x03, 0xf6, 0xc6, 0xb8, 0x67, 0x7a, 0x24, 0xe4, 0x9d, 0xb1, 0x50,
+ 0xf5, 0x96, 0x37, 0xe7, 0x2c, 0xff, 0x9d, 0x21, 0xd9, 0x73, 0xd1, 0x61,
+ 0x4d, 0xb4, 0x8b, 0x35, 0x1f, 0xf4, 0x13, 0x7d, 0x15, 0xf9, 0xe9, 0x95,
+ 0x45, 0x63, 0x1b, 0xcf, 0x7c, 0xbe, 0x5e, 0xc5, 0x35, 0xb1, 0x7f, 0x44,
+ 0x61, 0x4c, 0xff, 0x1e, 0x7f, 0x23, 0x5f, 0x7a, 0xcf, 0xf9, 0x77, 0xe6,
+ 0x53, 0x63, 0xfe, 0x59, 0x3b, 0x37, 0x73, 0x72, 0x43, 0x4e, 0xd5, 0xab,
+ 0xea, 0xbd, 0x2b, 0x55, 0x1b, 0xfe, 0x71, 0x00, 0xf6, 0xc9, 0x35, 0x50,
+ 0xd7, 0x1e, 0x02, 0x36, 0x8b, 0x75, 0xaa, 0x9c, 0xe8, 0xf4, 0x43, 0xe2,
+ 0xd9, 0x3b, 0xac, 0x4c, 0xf9, 0xb2, 0x95, 0xb2, 0x97, 0x83, 0xac, 0x96,
+ 0x33, 0xf2, 0x9f, 0xaa, 0x97, 0x54, 0xad, 0x75, 0x06, 0x79, 0x49, 0x68,
+ 0x5a, 0xe5, 0x64, 0x0d, 0xf8, 0x16, 0x7e, 0xef, 0xd9, 0x2f, 0x62, 0x2d,
+ 0x5a, 0xea, 0x4c, 0x83, 0x7e, 0xbe, 0x5e, 0x4f, 0xc1, 0x7f, 0xe8, 0xb6,
+ 0x6d, 0x16, 0x10, 0x0f, 0x53, 0xea, 0x5c, 0x0c, 0xd7, 0xf1, 0x61, 0xe5,
+ 0x9f, 0x65, 0x01, 0xb2, 0x39, 0x1b, 0xc3, 0x38, 0x9a, 0xb2, 0x4f, 0x43,
+ 0xe9, 0xe1, 0x21, 0x85, 0x79, 0x8d, 0xf3, 0x70, 0x58, 0xcb, 0x3d, 0x22,
+ 0xe7, 0x33, 0x32, 0x85, 0x35, 0x1c, 0x5a, 0xa6, 0x0e, 0x28, 0xdb, 0x31,
+ 0x69, 0x82, 0xec, 0x4f, 0x00, 0x7b, 0x18, 0xd3, 0x94, 0x71, 0x14, 0xeb,
+ 0xa2, 0x53, 0x42, 0x67, 0x21, 0xe3, 0x69, 0x60, 0x84, 0xb9, 0x66, 0x79,
+ 0x69, 0x31, 0x90, 0xe9, 0xcb, 0x3c, 0xef, 0xaf, 0x8f, 0x0f, 0x74, 0x11,
+ 0x47, 0x49, 0x65, 0x71, 0x4a, 0xa6, 0x66, 0x99, 0xb3, 0x8f, 0xa9, 0x33,
+ 0x06, 0x21, 0x75, 0xc6, 0xc5, 0xcb, 0x99, 0xbd, 0x6f, 0x0f, 0x63, 0x56,
+ 0x84, 0x7b, 0x6d, 0x02, 0xdb, 0xe9, 0xc7, 0xbc, 0x37, 0x92, 0xaf, 0x97,
+ 0xab, 0x0e, 0x83, 0xde, 0x8b, 0x33, 0x56, 0x26, 0x2f, 0x0e, 0xcf, 0x5b,
+ 0x8f, 0xba, 0xe0, 0x7f, 0x15, 0xfe, 0x73, 0xaa, 0x74, 0x2f, 0xf8, 0x2c,
+ 0x60, 0x85, 0x65, 0xe4, 0x62, 0x91, 0x39, 0xe3, 0x47, 0xa1, 0x37, 0x5e,
+ 0x17, 0x06, 0x0d, 0xf8, 0x81, 0x35, 0xf5, 0x7e, 0xa1, 0xe5, 0xae, 0x20,
+ 0x87, 0x8d, 0x69, 0x87, 0xa0, 0xeb, 0xbc, 0xd9, 0xe4, 0xdb, 0x03, 0xdf,
+ 0x35, 0x3e, 0x07, 0x3f, 0xba, 0x24, 0x7c, 0xef, 0xe7, 0x9d, 0x3a, 0xf3,
+ 0xa5, 0xcb, 0xf0, 0x7b, 0x99, 0x78, 0x06, 0x36, 0x94, 0x8f, 0xb6, 0x80,
+ 0xe6, 0xdf, 0xc6, 0xbd, 0x5c, 0x95, 0xf3, 0x58, 0xce, 0x9a, 0x14, 0x62,
+ 0x21, 0xe9, 0x8b, 0x5d, 0x92, 0x6d, 0xf0, 0x64, 0x9a, 0xbc, 0x61, 0x5b,
+ 0x83, 0xa2, 0xa9, 0xf1, 0x7a, 0x0f, 0xc0, 0x06, 0xaf, 0xc2, 0xdf, 0x35,
+ 0xfb, 0xb9, 0x7e, 0xaa, 0x48, 0x0c, 0xf5, 0x84, 0x3a, 0x8b, 0x70, 0xd9,
+ 0x66, 0x1d, 0x90, 0xef, 0xfb, 0xfe, 0x95, 0x9a, 0xe3, 0xfa, 0xde, 0x1d,
+ 0xeb, 0xd0, 0xa4, 0xcf, 0xe3, 0x71, 0xbf, 0xed, 0xd1, 0xc8, 0x71, 0x9a,
+ 0x1a, 0xc6, 0xb9, 0xe8, 0x8f, 0x73, 0xce, 0x1f, 0x67, 0xc1, 0x1f, 0xe7,
+ 0xf2, 0xfa, 0x38, 0x0f, 0xc2, 0x0e, 0xea, 0xf5, 0xa7, 0x80, 0x37, 0x92,
+ 0x4e, 0xbd, 0x9e, 0x46, 0x5e, 0x36, 0xd9, 0x3f, 0xa1, 0xf6, 0x5e, 0xf5,
+ 0xc4, 0x8b, 0x43, 0x49, 0xdb, 0x93, 0x3f, 0xac, 0x40, 0x26, 0x60, 0x8f,
+ 0x79, 0xf1, 0xb0, 0x3a, 0xf7, 0x03, 0xbd, 0xfd, 0xc2, 0x36, 0xf8, 0x81,
+ 0xc7, 0x10, 0x4b, 0x9c, 0xe1, 0x25, 0x5b, 0xf2, 0x7b, 0x7e, 0x4d, 0x87,
+ 0xbd, 0x77, 0x20, 0x2e, 0xbd, 0x09, 0xdb, 0x71, 0x86, 0x2b, 0x8b, 0x8f,
+ 0xa9, 0x3d, 0xe1, 0xa6, 0xc4, 0xbd, 0xd0, 0x67, 0x79, 0x78, 0x61, 0xb1,
+ 0x3c, 0x7c, 0x8e, 0xfb, 0x43, 0xe8, 0xb7, 0xb0, 0xd8, 0x0e, 0xb9, 0xb7,
+ 0xab, 0xba, 0xca, 0xa5, 0x62, 0x04, 0x7a, 0x34, 0x61, 0xf3, 0x11, 0xb4,
+ 0x45, 0x61, 0x07, 0x5d, 0x68, 0x7f, 0x0d, 0x6b, 0x3b, 0x86, 0xf6, 0xb5,
+ 0xd6, 0x61, 0x85, 0x63, 0x6d, 0x39, 0x5f, 0xbd, 0x8a, 0x98, 0xfb, 0x16,
+ 0xfc, 0x68, 0x2f, 0xfa, 0xf4, 0xa3, 0xcf, 0x0e, 0x13, 0xf8, 0x2a, 0x53,
+ 0xbe, 0x21, 0x4d, 0x2e, 0x68, 0xd2, 0x1b, 0x68, 0x72, 0x41, 0x0f, 0x7c,
+ 0xe7, 0x19, 0xd6, 0xa0, 0xfb, 0xe5, 0x64, 0x91, 0x67, 0xaa, 0xf8, 0xee,
+ 0xb5, 0x29, 0x21, 0x60, 0xd2, 0xa6, 0x33, 0x56, 0x74, 0x45, 0xd5, 0x7a,
+ 0x68, 0x5b, 0x7d, 0x4e, 0x45, 0x54, 0x9c, 0x89, 0x9d, 0x44, 0xfc, 0xba,
+ 0x5a, 0x6d, 0x97, 0x37, 0xfc, 0xb9, 0xd6, 0x84, 0xfb, 0x97, 0x1b, 0xe7,
+ 0x3a, 0x55, 0x1a, 0x1d, 0xfe, 0x81, 0x6d, 0xf8, 0x7c, 0x75, 0x62, 0xae,
+ 0x76, 0xf4, 0x1d, 0x1d, 0xbe, 0xb8, 0x78, 0xa3, 0xbe, 0x13, 0xe8, 0xdb,
+ 0xd4, 0xd0, 0x77, 0x02, 0xfd, 0xda, 0x11, 0x07, 0xdb, 0x15, 0x4f, 0x93,
+ 0xa0, 0xeb, 0x4a, 0x51, 0xbd, 0x0b, 0x0c, 0xb9, 0x73, 0x4e, 0x93, 0x98,
+ 0x3a, 0xe3, 0xd5, 0x4a, 0x2c, 0x33, 0xa6, 0xbd, 0xa7, 0xde, 0xa3, 0x6c,
+ 0x60, 0xc8, 0x06, 0xee, 0x9d, 0x19, 0xd5, 0x52, 0x95, 0x1c, 0x62, 0xd6,
+ 0x2e, 0xe2, 0x27, 0xc7, 0x45, 0xcc, 0x5c, 0xc0, 0x78, 0x8b, 0xc5, 0x15,
+ 0x9e, 0xc1, 0x86, 0x5d, 0xbc, 0x4d, 0x9c, 0xbd, 0xcb, 0x50, 0x67, 0x1e,
+ 0xd2, 0xaa, 0x66, 0xb7, 0x50, 0x14, 0x33, 0x39, 0xc0, 0x33, 0x0e, 0xf7,
+ 0x63, 0x5d, 0x7e, 0x0e, 0x6d, 0x49, 0xc4, 0xc7, 0xc3, 0x5a, 0x72, 0x69,
+ 0x18, 0xd7, 0x8f, 0xe0, 0x1a, 0xfe, 0x78, 0x2e, 0x8b, 0xfb, 0x8f, 0xe0,
+ 0x7a, 0x42, 0x4b, 0xd5, 0xb2, 0xb8, 0x7e, 0x14, 0xd7, 0x49, 0x93, 0x79,
+ 0xca, 0x0f, 0xec, 0x8c, 0xe6, 0x62, 0x2c, 0x77, 0x69, 0x18, 0x9f, 0xc6,
+ 0xf1, 0x78, 0x0f, 0x7a, 0x2a, 0x72, 0xaf, 0x2d, 0x0e, 0x9a, 0x0e, 0x6a,
+ 0xe9, 0x4a, 0x1b, 0xc6, 0xe8, 0xc1, 0xf3, 0xb4, 0xa9, 0x43, 0xfe, 0xfc,
+ 0xac, 0x39, 0xdd, 0xad, 0x6a, 0x4e, 0x46, 0x22, 0x03, 0x9c, 0x7c, 0x1c,
+ 0x79, 0x80, 0x26, 0x69, 0xfb, 0x49, 0x29, 0x38, 0xf0, 0x2b, 0x15, 0x43,
+ 0x52, 0x91, 0x3c, 0x7e, 0xe7, 0x25, 0x39, 0x88, 0xfb, 0x15, 0xda, 0x02,
+ 0xfb, 0xfd, 0x89, 0x14, 0xca, 0xc4, 0xfd, 0xac, 0x33, 0xb1, 0x36, 0xc5,
+ 0xfa, 0x52, 0x0e, 0x32, 0x88, 0xd0, 0x7e, 0x6f, 0x50, 0x13, 0xf3, 0xce,
+ 0x55, 0x23, 0x2e, 0x6b, 0xc9, 0x0a, 0xf7, 0xfd, 0xdc, 0xcc, 0x45, 0x9b,
+ 0xef, 0x28, 0x4d, 0x70, 0x1f, 0xb1, 0x60, 0x24, 0x58, 0x1f, 0x51, 0xf5,
+ 0x75, 0xc7, 0xdb, 0x1f, 0xe4, 0xb8, 0x63, 0xe0, 0xb7, 0xb1, 0x6e, 0xc5,
+ 0x79, 0xbf, 0x80, 0xe7, 0xbd, 0x7a, 0x56, 0xaa, 0xf6, 0x5e, 0x5d, 0xf0,
+ 0xbd, 0x81, 0xf3, 0xd0, 0xc5, 0x45, 0x95, 0x1b, 0x73, 0x0f, 0xf7, 0xfd,
+ 0x72, 0x2a, 0xe4, 0x30, 0x45, 0xd6, 0xc8, 0x82, 0x7d, 0xbb, 0x40, 0x8e,
+ 0x9b, 0x69, 0x25, 0x9d, 0x47, 0x30, 0xa6, 0x38, 0xf4, 0xbb, 0xd9, 0x08,
+ 0xf7, 0xdf, 0xf8, 0x8c, 0x7c, 0xf9, 0x3a, 0xdd, 0xa4, 0x99, 0xf2, 0x38,
+ 0x0e, 0xff, 0xc9, 0x77, 0x32, 0x9e, 0x94, 0x9c, 0xc3, 0x1a, 0x8f, 0x81,
+ 0xd8, 0x98, 0xc7, 0xef, 0xeb, 0xf2, 0x9b, 0xf4, 0xe5, 0x97, 0x2b, 0xbf,
+ 0xa4, 0x74, 0xb8, 0x60, 0x73, 0xbe, 0xa0, 0xf6, 0x31, 0xa2, 0x74, 0xb7,
+ 0xa0, 0xce, 0xfd, 0x06, 0x32, 0x08, 0xea, 0x77, 0x37, 0xb6, 0xbd, 0x61,
+ 0x9b, 0xb4, 0xdd, 0xce, 0xf3, 0x10, 0xbd, 0xae, 0x90, 0x7e, 0xf2, 0xc1,
+ 0x18, 0x16, 0xec, 0xb5, 0x06, 0x3c, 0x04, 0x7c, 0xde, 0xaa, 0x7c, 0x48,
+ 0x6f, 0x64, 0xbb, 0xb4, 0x65, 0x4c, 0xc3, 0x66, 0x6c, 0xf8, 0x84, 0xbf,
+ 0x3f, 0xf0, 0x77, 0x21, 0x67, 0x4f, 0x16, 0xa1, 0x84, 0x4c, 0xfa, 0xef,
+ 0xf8, 0xde, 0xc0, 0x1e, 0x36, 0xef, 0x35, 0xbb, 0x99, 0x73, 0xf6, 0x75,
+ 0xbe, 0x17, 0x6e, 0xc0, 0xf7, 0x82, 0xcf, 0x77, 0xe5, 0x16, 0xe9, 0x5d,
+ 0x98, 0x71, 0xc1, 0x33, 0x6d, 0xee, 0x46, 0xf6, 0x28, 0xea, 0x7f, 0x5f,
+ 0xac, 0x19, 0xe1, 0xb0, 0x5b, 0xbd, 0x59, 0x0d, 0x95, 0x79, 0xb5, 0x67,
+ 0x97, 0xe7, 0x10, 0x0b, 0xcb, 0x65, 0x2f, 0xc7, 0x2e, 0x57, 0x59, 0xcb,
+ 0x7e, 0x3f, 0x1a, 0xf8, 0xfe, 0xd7, 0x67, 0xd4, 0x79, 0x97, 0xc9, 0xaa,
+ 0x57, 0xf7, 0x2a, 0x97, 0x1b, 0x63, 0xea, 0x0e, 0xc6, 0xd3, 0xde, 0xbc,
+ 0x8c, 0xf2, 0xbd, 0x65, 0x5c, 0xef, 0x96, 0x4b, 0x73, 0x6a, 0xcf, 0xca,
+ 0xdf, 0x1b, 0xe2, 0x9e, 0x8f, 0xda, 0xff, 0x86, 0x5f, 0x1b, 0x53, 0x7e,
+ 0x7d, 0x75, 0x4e, 0xdd, 0xf3, 0xb0, 0x52, 0x75, 0x14, 0x7e, 0x1f, 0xb9,
+ 0x84, 0xbd, 0x55, 0x0a, 0xc8, 0xb9, 0xcf, 0xd9, 0x0f, 0x6f, 0x27, 0xce,
+ 0xe1, 0x58, 0xab, 0x18, 0xeb, 0xe2, 0x9c, 0x6c, 0xe7, 0x99, 0x92, 0xb2,
+ 0xda, 0x67, 0xf3, 0xea, 0xe2, 0x13, 0x12, 0xfc, 0x4f, 0x88, 0xb0, 0x1f,
+ 0x0b, 0x79, 0xae, 0x85, 0xef, 0xd2, 0xd2, 0x57, 0x20, 0x0f, 0x1a, 0xe5,
+ 0x3e, 0x4e, 0xbd, 0xee, 0xd5, 0xcd, 0xeb, 0x58, 0x17, 0x4d, 0x7c, 0xef,
+ 0x02, 0x7f, 0xc7, 0x61, 0x3f, 0x58, 0x27, 0xeb, 0xed, 0xbc, 0x66, 0xee,
+ 0x11, 0x5c, 0x33, 0xb0, 0xfd, 0x3f, 0xd4, 0x46, 0x90, 0x7c, 0xb4, 0x45,
+ 0x00, 0x00, 0x00 };
static const u32 bnx2_TXP_b09FwData[(0xd0/4) + 1] = {
0x00000000, 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000010,
@@ -4052,41 +4065,38 @@ static const u32 bnx2_TXP_b09FwData[(0xd0/4) + 1] = {
0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
static const u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = {
- 0x08004060, 0x0800408c, 0x080040d4, 0x080040d4, 0x08003f60, 0x08003f8c,
- 0x08003f8c, 0x080040d4, 0x080040d4, 0x080040d4, 0x08003ff4, 0x00000000,
+ 0x08003fdc, 0x08004008, 0x08004050, 0x08004050, 0x08003edc, 0x08003f08,
+ 0x08003f08, 0x08004050, 0x08004050, 0x08004050, 0x08003f70, 0x00000000,
0x00000000 };
-static const u32 bnx2_TXP_b09FwBss[(0xa20/4) + 1] = { 0x0 };
-static const u32 bnx2_TXP_b09FwSbss[(0x8c/4) + 1] = { 0x0 };
static struct fw_info bnx2_txp_fw_09 = {
+ /* Firmware version: 3.7.1 */
.ver_major = 0x3,
- .ver_minor = 0x4,
- .ver_fix = 0x3,
+ .ver_minor = 0x7,
+ .ver_fix = 0x1,
.start_addr = 0x08000060,
.text_addr = 0x08000000,
- .text_len = 0x4634,
+ .text_len = 0x45b0,
.text_index = 0x0,
.gz_text = bnx2_TXP_b09FwText,
.gz_text_len = sizeof(bnx2_TXP_b09FwText),
- .data_addr = 0x08004680,
+ .data_addr = 0x08004600,
.data_len = 0xd0,
.data_index = 0x0,
.data = bnx2_TXP_b09FwData,
- .sbss_addr = 0x08004750,
+ .sbss_addr = 0x080046d0,
.sbss_len = 0x8c,
.sbss_index = 0x0,
- .sbss = bnx2_TXP_b09FwSbss,
- .bss_addr = 0x080047e0,
+ .bss_addr = 0x08004760,
.bss_len = 0xa20,
.bss_index = 0x0,
- .bss = bnx2_TXP_b09FwBss,
- .rodata_addr = 0x08004638,
+ .rodata_addr = 0x080045b0,
.rodata_len = 0x30,
.rodata_index = 0x0,
.rodata = bnx2_TXP_b09FwRodata,
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index f829e4ad8b4..cb3c6faa788 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -29,6 +29,7 @@
#include <linux/ethtool.h>
#include <linux/if_bonding.h>
#include <linux/pkt_sched.h>
+#include <net/net_namespace.h>
#include "bonding.h"
#include "bond_3ad.h"
@@ -100,7 +101,6 @@ static u16 __get_link_speed(struct port *port);
static u8 __get_duplex(struct port *port);
static inline void __initialize_port_locks(struct port *port);
//conversions
-static void __htons_lacpdu(struct lacpdu *lacpdu);
static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par);
@@ -126,7 +126,7 @@ static struct aggregator *__get_active_agg(struct aggregator *aggregator);
// ================= main 802.3ad protocol functions ==================
static int ad_lacpdu_send(struct port *port);
-static int ad_marker_send(struct port *port, struct marker *marker);
+static int ad_marker_send(struct port *port, struct bond_marker *marker);
static void ad_mux_machine(struct port *port);
static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port);
static void ad_tx_machine(struct port *port);
@@ -139,8 +139,8 @@ static void ad_initialize_port(struct port *port, int lacp_fast);
static void ad_initialize_lacpdu(struct lacpdu *Lacpdu);
static void ad_enable_collecting_distributing(struct port *port);
static void ad_disable_collecting_distributing(struct port *port);
-static void ad_marker_info_received(struct marker *marker_info, struct port *port);
-static void ad_marker_response_received(struct marker *marker, struct port *port);
+static void ad_marker_info_received(struct bond_marker *marker_info, struct port *port);
+static void ad_marker_response_received(struct bond_marker *marker, struct port *port);
/////////////////////////////////////////////////////////////////////////////////
@@ -419,26 +419,6 @@ static inline void __initialize_port_locks(struct port *port)
}
//conversions
-/**
- * __htons_lacpdu - convert the contents of a LACPDU to network byte order
- * @lacpdu: the speicifed lacpdu
- *
- * For each multi-byte field in the lacpdu, convert its content
- */
-static void __htons_lacpdu(struct lacpdu *lacpdu)
-{
- if (lacpdu) {
- lacpdu->actor_system_priority = htons(lacpdu->actor_system_priority);
- lacpdu->actor_key = htons(lacpdu->actor_key);
- lacpdu->actor_port_priority = htons(lacpdu->actor_port_priority);
- lacpdu->actor_port = htons(lacpdu->actor_port);
- lacpdu->partner_system_priority = htons(lacpdu->partner_system_priority);
- lacpdu->partner_key = htons(lacpdu->partner_key);
- lacpdu->partner_port_priority = htons(lacpdu->partner_port_priority);
- lacpdu->partner_port = htons(lacpdu->partner_port);
- lacpdu->collector_max_delay = htons(lacpdu->collector_max_delay);
- }
-}
/**
* __ad_timer_to_ticks - convert a given timer type to AD module ticks
@@ -826,11 +806,11 @@ static inline void __update_lacpdu_from_port(struct port *port)
* lacpdu->actor_information_length initialized
*/
- lacpdu->actor_system_priority = port->actor_system_priority;
+ lacpdu->actor_system_priority = htons(port->actor_system_priority);
lacpdu->actor_system = port->actor_system;
- lacpdu->actor_key = port->actor_oper_port_key;
- lacpdu->actor_port_priority = port->actor_port_priority;
- lacpdu->actor_port = port->actor_port_number;
+ lacpdu->actor_key = htons(port->actor_oper_port_key);
+ lacpdu->actor_port_priority = htons(port->actor_port_priority);
+ lacpdu->actor_port = htons(port->actor_port_number);
lacpdu->actor_state = port->actor_oper_port_state;
/* lacpdu->reserved_3_1 initialized
@@ -838,11 +818,11 @@ static inline void __update_lacpdu_from_port(struct port *port)
* lacpdu->partner_information_length initialized
*/
- lacpdu->partner_system_priority = port->partner_oper_system_priority;
+ lacpdu->partner_system_priority = htons(port->partner_oper_system_priority);
lacpdu->partner_system = port->partner_oper_system;
- lacpdu->partner_key = port->partner_oper_key;
- lacpdu->partner_port_priority = port->partner_oper_port_priority;
- lacpdu->partner_port = port->partner_oper_port_number;
+ lacpdu->partner_key = htons(port->partner_oper_key);
+ lacpdu->partner_port_priority = htons(port->partner_oper_port_priority);
+ lacpdu->partner_port = htons(port->partner_oper_port_number);
lacpdu->partner_state = port->partner_oper_port_state;
/* lacpdu->reserved_3_2 initialized
@@ -854,9 +834,6 @@ static inline void __update_lacpdu_from_port(struct port *port)
* terminator_length initialized
* reserved_50[50] initialized
*/
-
- /* Convert all non u8 parameters to Big Endian for transmit */
- __htons_lacpdu(lacpdu);
}
//////////////////////////////////////////////////////////////////////////////////////
@@ -912,12 +889,12 @@ static int ad_lacpdu_send(struct port *port)
* Returns: 0 on success
* < 0 on error
*/
-static int ad_marker_send(struct port *port, struct marker *marker)
+static int ad_marker_send(struct port *port, struct bond_marker *marker)
{
struct slave *slave = port->slave;
struct sk_buff *skb;
- struct marker_header *marker_header;
- int length = sizeof(struct marker_header);
+ struct bond_marker_header *marker_header;
+ int length = sizeof(struct bond_marker_header);
struct mac_addr lacpdu_multicast_address = AD_MULTICAST_LACPDU_ADDR;
skb = dev_alloc_skb(length + 16);
@@ -932,7 +909,7 @@ static int ad_marker_send(struct port *port, struct marker *marker)
skb->network_header = skb->mac_header + ETH_HLEN;
skb->protocol = PKT_TYPE_LACPDU;
- marker_header = (struct marker_header *)skb_put(skb, length);
+ marker_header = (struct bond_marker_header *)skb_put(skb, length);
marker_header->ad_header.destination_address = lacpdu_multicast_address;
/* Note: source addres is set to be the member's PERMANENT address, because we use it
@@ -1732,7 +1709,7 @@ static void ad_disable_collecting_distributing(struct port *port)
*/
static void ad_marker_info_send(struct port *port)
{
- struct marker marker;
+ struct bond_marker marker;
u16 index;
// fill the marker PDU with the appropriate values
@@ -1765,13 +1742,14 @@ static void ad_marker_info_send(struct port *port)
* @port: the port we're looking at
*
*/
-static void ad_marker_info_received(struct marker *marker_info,struct port *port)
+static void ad_marker_info_received(struct bond_marker *marker_info,
+ struct port *port)
{
- struct marker marker;
+ struct bond_marker marker;
// copy the received marker data to the response marker
//marker = *marker_info;
- memcpy(&marker, marker_info, sizeof(struct marker));
+ memcpy(&marker, marker_info, sizeof(struct bond_marker));
// change the marker subtype to marker response
marker.tlv_type=AD_MARKER_RESPONSE_SUBTYPE;
// send the marker response
@@ -1790,7 +1768,8 @@ static void ad_marker_info_received(struct marker *marker_info,struct port *port
* response for marker PDU's, in this stage, but only to respond to marker
* information.
*/
-static void ad_marker_response_received(struct marker *marker, struct port *port)
+static void ad_marker_response_received(struct bond_marker *marker,
+ struct port *port)
{
marker=NULL; // just to satisfy the compiler
port=NULL; // just to satisfy the compiler
@@ -1833,7 +1812,7 @@ static void ad_initialize_lacpdu(struct lacpdu *lacpdu)
}
lacpdu->tlv_type_collector_info = 0x03;
lacpdu->collector_information_length= 0x10;
- lacpdu->collector_max_delay = AD_COLLECTOR_MAX_DELAY;
+ lacpdu->collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY);
for (index=0; index<=11; index++) {
lacpdu->reserved_12[index]=0;
}
@@ -2097,8 +2076,10 @@ void bond_3ad_unbind_slave(struct slave *slave)
* times out, and it selects an aggregator for the ports that are yet not
* related to any aggregator, and selects the active aggregator for a bond.
*/
-void bond_3ad_state_machine_handler(struct bonding *bond)
+void bond_3ad_state_machine_handler(struct work_struct *work)
{
+ struct bonding *bond = container_of(work, struct bonding,
+ ad_work.work);
struct port *port;
struct aggregator *aggregator;
@@ -2149,7 +2130,7 @@ void bond_3ad_state_machine_handler(struct bonding *bond)
}
re_arm:
- mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + ad_delta_in_ticks);
+ queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
out:
read_unlock(&bond->lock);
}
@@ -2187,15 +2168,15 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u
case AD_TYPE_MARKER:
// No need to convert fields to Little Endian since we don't use the marker's fields.
- switch (((struct marker *)lacpdu)->tlv_type) {
+ switch (((struct bond_marker *)lacpdu)->tlv_type) {
case AD_MARKER_INFORMATION_SUBTYPE:
dprintk("Received Marker Information on port %d\n", port->actor_port_number);
- ad_marker_info_received((struct marker *)lacpdu, port);
+ ad_marker_info_received((struct bond_marker *)lacpdu, port);
break;
case AD_MARKER_RESPONSE_SUBTYPE:
dprintk("Received Marker Response on port %d\n", port->actor_port_number);
- ad_marker_response_received((struct marker *)lacpdu, port);
+ ad_marker_response_received((struct bond_marker *)lacpdu, port);
break;
default:
@@ -2448,6 +2429,9 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac
struct slave *slave = NULL;
int ret = NET_RX_DROP;
+ if (dev->nd_net != &init_net)
+ goto out;
+
if (!(dev->flags & IFF_MASTER))
goto out;
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index 6ad5ad6e65d..b5ee45f6d55 100644
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -92,7 +92,7 @@ typedef enum {
typedef enum {
AD_MARKER_INFORMATION_SUBTYPE = 1, // marker imformation subtype
AD_MARKER_RESPONSE_SUBTYPE // marker response subtype
-} marker_subtype_t;
+} bond_marker_subtype_t;
// timers types(43.4.9 in the 802.3ad standard)
typedef enum {
@@ -108,7 +108,7 @@ typedef enum {
typedef struct ad_header {
struct mac_addr destination_address;
struct mac_addr source_address;
- u16 length_type;
+ __be16 length_type;
} ad_header_t;
// Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard)
@@ -117,25 +117,25 @@ typedef struct lacpdu {
u8 version_number;
u8 tlv_type_actor_info; // = actor information(type/length/value)
u8 actor_information_length; // = 20
- u16 actor_system_priority;
+ __be16 actor_system_priority;
struct mac_addr actor_system;
- u16 actor_key;
- u16 actor_port_priority;
- u16 actor_port;
+ __be16 actor_key;
+ __be16 actor_port_priority;
+ __be16 actor_port;
u8 actor_state;
u8 reserved_3_1[3]; // = 0
u8 tlv_type_partner_info; // = partner information
u8 partner_information_length; // = 20
- u16 partner_system_priority;
+ __be16 partner_system_priority;
struct mac_addr partner_system;
- u16 partner_key;
- u16 partner_port_priority;
- u16 partner_port;
+ __be16 partner_key;
+ __be16 partner_port_priority;
+ __be16 partner_port;
u8 partner_state;
u8 reserved_3_2[3]; // = 0
u8 tlv_type_collector_info; // = collector information
u8 collector_information_length; // = 16
- u16 collector_max_delay;
+ __be16 collector_max_delay;
u8 reserved_12[12];
u8 tlv_type_terminator; // = terminator
u8 terminator_length; // = 0
@@ -148,7 +148,7 @@ typedef struct lacpdu_header {
} lacpdu_header_t;
// Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard)
-typedef struct marker {
+typedef struct bond_marker {
u8 subtype; // = 0x02 (marker PDU)
u8 version_number; // = 0x01
u8 tlv_type; // = 0x01 (marker information)
@@ -161,12 +161,12 @@ typedef struct marker {
u8 tlv_type_terminator; // = 0x00
u8 terminator_length; // = 0x00
u8 reserved_90[90]; // = 0
-} marker_t;
+} bond_marker_t;
-typedef struct marker_header {
+typedef struct bond_marker_header {
struct ad_header ad_header;
- struct marker marker;
-} marker_header_t;
+ struct bond_marker marker;
+} bond_marker_header_t;
#pragma pack()
@@ -276,7 +276,7 @@ struct ad_slave_info {
void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fast);
int bond_3ad_bind_slave(struct slave *slave);
void bond_3ad_unbind_slave(struct slave *slave);
-void bond_3ad_state_machine_handler(struct bonding *bond);
+void bond_3ad_state_machine_handler(struct work_struct *);
void bond_3ad_adapter_speed_changed(struct slave *slave);
void bond_3ad_adapter_duplex_changed(struct slave *slave);
void bond_3ad_handle_link_change(struct slave *slave, char link);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 92c3b6f6a8e..25b8dbf6cfd 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -87,20 +87,20 @@ static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC;
struct learning_pkt {
u8 mac_dst[ETH_ALEN];
u8 mac_src[ETH_ALEN];
- u16 type;
+ __be16 type;
u8 padding[ETH_ZLEN - ETH_HLEN];
};
struct arp_pkt {
- u16 hw_addr_space;
- u16 prot_addr_space;
+ __be16 hw_addr_space;
+ __be16 prot_addr_space;
u8 hw_addr_len;
u8 prot_addr_len;
- u16 op_code;
+ __be16 op_code;
u8 mac_src[ETH_ALEN]; /* sender hardware address */
- u32 ip_src; /* sender IP address */
+ __be32 ip_src; /* sender IP address */
u8 mac_dst[ETH_ALEN]; /* target hardware address */
- u32 ip_dst; /* target IP address */
+ __be32 ip_dst; /* target IP address */
};
#pragma pack()
@@ -128,12 +128,12 @@ static inline u8 _simple_hash(const u8 *hash_start, int hash_size)
static inline void _lock_tx_hashtbl(struct bonding *bond)
{
- spin_lock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
+ spin_lock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
}
static inline void _unlock_tx_hashtbl(struct bonding *bond)
{
- spin_unlock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
+ spin_unlock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
}
/* Caller must hold tx_hashtbl lock */
@@ -305,12 +305,12 @@ static struct slave *tlb_choose_channel(struct bonding *bond, u32 hash_index, u3
/*********************** rlb specific functions ***************************/
static inline void _lock_rx_hashtbl(struct bonding *bond)
{
- spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
+ spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
}
static inline void _unlock_rx_hashtbl(struct bonding *bond)
{
- spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
+ spin_unlock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
}
/* when an ARP REPLY is received from a client update its info
@@ -345,6 +345,9 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct
struct arp_pkt *arp = (struct arp_pkt *)skb->data;
int res = NET_RX_DROP;
+ if (bond_dev->nd_net != &init_net)
+ goto out;
+
if (!(bond_dev->flags & IFF_MASTER))
goto out;
@@ -469,13 +472,13 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave)
_unlock_rx_hashtbl(bond);
- write_lock(&bond->curr_slave_lock);
+ write_lock_bh(&bond->curr_slave_lock);
if (slave != bond->curr_active_slave) {
rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr);
}
- write_unlock(&bond->curr_slave_lock);
+ write_unlock_bh(&bond->curr_slave_lock);
}
static void rlb_update_client(struct rlb_client_info *client_info)
@@ -579,7 +582,7 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla
}
/* mark all clients using src_ip to be updated */
-static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip)
+static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct rlb_client_info *client_info;
@@ -956,19 +959,34 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw)
return 0;
}
-/* Caller must hold bond lock for write or curr_slave_lock for write*/
+/*
+ * Swap MAC addresses between two slaves.
+ *
+ * Called with RTNL held, and no other locks.
+ *
+ */
+
static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2)
{
- struct slave *disabled_slave = NULL;
u8 tmp_mac_addr[ETH_ALEN];
- int slaves_state_differ;
-
- slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2));
memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN);
alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled);
alb_set_slave_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled);
+}
+
+/*
+ * Send learning packets after MAC address swap.
+ *
+ * Called with RTNL and bond->lock held for read.
+ */
+static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
+ struct slave *slave2)
+{
+ int slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2));
+ struct slave *disabled_slave = NULL;
+
/* fasten the change in the switch */
if (SLAVE_IS_OK(slave1)) {
alb_send_learning_packets(slave1, slave1->dev->dev_addr);
@@ -1041,7 +1059,9 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla
}
if (found) {
+ /* locking: needs RTNL and nothing else */
alb_swap_mac_addr(bond, slave, tmp_slave);
+ alb_fasten_mac_swap(bond, slave, tmp_slave);
}
}
}
@@ -1264,7 +1284,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
struct ethhdr *eth_data;
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct slave *tx_slave = NULL;
- static const u32 ip_bcast = 0xffffffff;
+ static const __be32 ip_bcast = htonl(0xffffffff);
int hash_size = 0;
int do_tx_balance = 1;
u32 hash_index = 0;
@@ -1308,8 +1328,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
hash_size = sizeof(ipv6_hdr(skb)->daddr);
break;
case ETH_P_IPX:
- if (ipx_hdr(skb)->ipx_checksum !=
- __constant_htons(IPX_NO_CHECKSUM)) {
+ if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) {
/* something is wrong with this packet */
do_tx_balance = 0;
break;
@@ -1373,8 +1392,10 @@ out:
return 0;
}
-void bond_alb_monitor(struct bonding *bond)
+void bond_alb_monitor(struct work_struct *work)
{
+ struct bonding *bond = container_of(work, struct bonding,
+ alb_work.work);
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct slave *slave;
int i;
@@ -1434,16 +1455,16 @@ void bond_alb_monitor(struct bonding *bond)
/* handle rlb stuff */
if (bond_info->rlb_enabled) {
- /* the following code changes the promiscuity of the
- * the curr_active_slave. It needs to be locked with a
- * write lock to protect from other code that also
- * sets the promiscuity.
- */
- write_lock_bh(&bond->curr_slave_lock);
-
if (bond_info->primary_is_promisc &&
(++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) {
+ /*
+ * dev_set_promiscuity requires rtnl and
+ * nothing else.
+ */
+ read_unlock(&bond->lock);
+ rtnl_lock();
+
bond_info->rlb_promisc_timeout_counter = 0;
/* If the primary was set to promiscuous mode
@@ -1452,9 +1473,10 @@ void bond_alb_monitor(struct bonding *bond)
*/
dev_set_promiscuity(bond->curr_active_slave->dev, -1);
bond_info->primary_is_promisc = 0;
- }
- write_unlock_bh(&bond->curr_slave_lock);
+ rtnl_unlock();
+ read_lock(&bond->lock);
+ }
if (bond_info->rlb_rebalance) {
bond_info->rlb_rebalance = 0;
@@ -1477,7 +1499,7 @@ void bond_alb_monitor(struct bonding *bond)
}
re_arm:
- mod_timer(&(bond_info->alb_timer), jiffies + alb_delta_in_ticks);
+ queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks);
out:
read_unlock(&bond->lock);
}
@@ -1498,11 +1520,11 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
/* caller must hold the bond lock for write since the mac addresses
* are compared and may be swapped.
*/
- write_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
res = alb_handle_addr_collision_on_attach(bond, slave);
- write_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
if (res) {
return res;
@@ -1567,13 +1589,21 @@ void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char
* Set the bond->curr_active_slave to @new_slave and handle
* mac address swapping and promiscuity changes as needed.
*
- * Caller must hold bond curr_slave_lock for write (or bond lock for write)
+ * If new_slave is NULL, caller must hold curr_slave_lock or
+ * bond->lock for write.
+ *
+ * If new_slave is not NULL, caller must hold RTNL, bond->lock for
+ * read and curr_slave_lock for write. Processing here may sleep, so
+ * no other locks may be held.
*/
void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave)
{
struct slave *swap_slave;
int i;
+ if (new_slave)
+ ASSERT_RTNL();
+
if (bond->curr_active_slave == new_slave) {
return;
}
@@ -1606,6 +1636,19 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
}
}
+ /*
+ * Arrange for swap_slave and new_slave to temporarily be
+ * ignored so we can mess with their MAC addresses without
+ * fear of interference from transmit activity.
+ */
+ if (swap_slave) {
+ tlb_clear_slave(bond, swap_slave, 1);
+ }
+ tlb_clear_slave(bond, new_slave, 1);
+
+ write_unlock_bh(&bond->curr_slave_lock);
+ read_unlock(&bond->lock);
+
/* curr_active_slave must be set before calling alb_swap_mac_addr */
if (swap_slave) {
/* swap mac address */
@@ -1614,11 +1657,23 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
/* set the new_slave to the bond mac address */
alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr,
bond->alb_info.rlb_enabled);
+ }
+
+ read_lock(&bond->lock);
+
+ if (swap_slave) {
+ alb_fasten_mac_swap(bond, swap_slave, new_slave);
+ } else {
/* fasten bond mac on new current slave */
alb_send_learning_packets(new_slave, bond->dev->dev_addr);
}
+
+ write_lock_bh(&bond->curr_slave_lock);
}
+/*
+ * Called with RTNL
+ */
int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
{
struct bonding *bond = bond_dev->priv;
@@ -1655,8 +1710,12 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
}
}
+ write_unlock_bh(&bond->curr_slave_lock);
+ read_unlock(&bond->lock);
+
if (swap_slave) {
alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave);
+ alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave);
} else {
alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr,
bond->alb_info.rlb_enabled);
@@ -1668,6 +1727,9 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
}
}
+ read_lock(&bond->lock);
+ write_lock_bh(&bond->curr_slave_lock);
+
return 0;
}
diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
index 28f2a2fd1b5..50968f8196c 100644
--- a/drivers/net/bonding/bond_alb.h
+++ b/drivers/net/bonding/bond_alb.h
@@ -60,8 +60,8 @@ struct tlb_client_info {
* -------------------------------------------------------------------------
*/
struct rlb_client_info {
- u32 ip_src; /* the server IP address */
- u32 ip_dst; /* the client IP address */
+ __be32 ip_src; /* the server IP address */
+ __be32 ip_dst; /* the client IP address */
u8 mac_dst[ETH_ALEN]; /* the client MAC address */
u32 next; /* The next Hash table entry index */
u32 prev; /* The previous Hash table entry index */
@@ -125,7 +125,7 @@ void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave);
void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link);
void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave);
int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
-void bond_alb_monitor(struct bonding *bond);
+void bond_alb_monitor(struct work_struct *);
int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr);
void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id);
#endif /* __BOND_ALB_H__ */
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 1afda3230de..423298c84a1 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -75,6 +75,7 @@
#include <linux/if_vlan.h>
#include <linux/if_bonding.h>
#include <net/route.h>
+#include <net/net_namespace.h>
#include "bonding.h"
#include "bond_3ad.h"
#include "bond_alb.h"
@@ -97,6 +98,7 @@ static char *xmit_hash_policy = NULL;
static int arp_interval = BOND_LINK_ARP_INTERV;
static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
static char *arp_validate = NULL;
+static int fail_over_mac = 0;
struct bond_params bonding_defaults;
module_param(max_bonds, int, 0);
@@ -130,6 +132,8 @@ module_param_array(arp_ip_target, charp, NULL, 0);
MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
module_param(arp_validate, charp, 0);
MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
+module_param(fail_over_mac, int, 0);
+MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. 0 of off (default), 1 for on.");
/*----------------------------- Global variables ----------------------------*/
@@ -143,7 +147,7 @@ static struct proc_dir_entry *bond_proc_dir = NULL;
#endif
extern struct rw_semaphore bonding_rwsem;
-static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
+static __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
static int arp_ip_count = 0;
static int bond_mode = BOND_MODE_ROUNDROBIN;
static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2;
@@ -184,6 +188,7 @@ struct bond_parm_tbl arp_validate_tbl[] = {
/*-------------------------- Forward declarations ---------------------------*/
static void bond_send_gratuitous_arp(struct bonding *bond);
+static void bond_deinit(struct net_device *bond_dev);
/*---------------------------- General routines -----------------------------*/
@@ -1095,7 +1100,21 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
if (new_active) {
bond_set_slave_active_flags(new_active);
}
- bond_send_gratuitous_arp(bond);
+
+ /* when bonding does not set the slave MAC address, the bond MAC
+ * address is the one of the active slave.
+ */
+ if (new_active && bond->params.fail_over_mac)
+ memcpy(bond->dev->dev_addr, new_active->dev->dev_addr,
+ new_active->dev->addr_len);
+ if (bond->curr_active_slave &&
+ test_bit(__LINK_STATE_LINKWATCH_PENDING,
+ &bond->curr_active_slave->dev->state)) {
+ dprintk("delaying gratuitous arp on %s\n",
+ bond->curr_active_slave->dev->name);
+ bond->send_grat_arp = 1;
+ } else
+ bond_send_gratuitous_arp(bond);
}
}
@@ -1216,7 +1235,8 @@ static int bond_compute_features(struct bonding *bond)
struct slave *slave;
struct net_device *bond_dev = bond->dev;
unsigned long features = bond_dev->features;
- unsigned short max_hard_header_len = ETH_HLEN;
+ unsigned short max_hard_header_len = max((u16)ETH_HLEN,
+ bond_dev->hard_header_len);
int i;
features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
@@ -1237,6 +1257,24 @@ static int bond_compute_features(struct bonding *bond)
return 0;
}
+
+static void bond_setup_by_slave(struct net_device *bond_dev,
+ struct net_device *slave_dev)
+{
+ struct bonding *bond = bond_dev->priv;
+
+ bond_dev->neigh_setup = slave_dev->neigh_setup;
+ bond_dev->header_ops = slave_dev->header_ops;
+
+ bond_dev->type = slave_dev->type;
+ bond_dev->hard_header_len = slave_dev->hard_header_len;
+ bond_dev->addr_len = slave_dev->addr_len;
+
+ memcpy(bond_dev->broadcast, slave_dev->broadcast,
+ slave_dev->addr_len);
+ bond->setup_by_slave = 1;
+}
+
/* enslave device <slave> to bond device <master> */
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
{
@@ -1257,8 +1295,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
/* bond must be initialized by bond_open() before enslaving */
if (!(bond_dev->flags & IFF_UP)) {
- dprintk("Error, master_dev is not up\n");
- return -EPERM;
+ printk(KERN_WARNING DRV_NAME
+ " %s: master_dev is not up in bond_enslave\n",
+ bond_dev->name);
}
/* already enslaved */
@@ -1311,14 +1350,42 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
goto err_undo_flags;
}
+ /* set bonding device ether type by slave - bonding netdevices are
+ * created with ether_setup, so when the slave type is not ARPHRD_ETHER
+ * there is a need to override some of the type dependent attribs/funcs.
+ *
+ * bond ether type mutual exclusion - don't allow slaves of dissimilar
+ * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond
+ */
+ if (bond->slave_cnt == 0) {
+ if (slave_dev->type != ARPHRD_ETHER)
+ bond_setup_by_slave(bond_dev, slave_dev);
+ } else if (bond_dev->type != slave_dev->type) {
+ printk(KERN_ERR DRV_NAME ": %s ether type (%d) is different "
+ "from other slaves (%d), can not enslave it.\n",
+ slave_dev->name,
+ slave_dev->type, bond_dev->type);
+ res = -EINVAL;
+ goto err_undo_flags;
+ }
+
if (slave_dev->set_mac_address == NULL) {
- printk(KERN_ERR DRV_NAME
- ": %s: Error: The slave device you specified does "
- "not support setting the MAC address. "
- "Your kernel likely does not support slave "
- "devices.\n", bond_dev->name);
- res = -EOPNOTSUPP;
- goto err_undo_flags;
+ if (bond->slave_cnt == 0) {
+ printk(KERN_WARNING DRV_NAME
+ ": %s: Warning: The first slave device "
+ "specified does not support setting the MAC "
+ "address. Enabling the fail_over_mac option.",
+ bond_dev->name);
+ bond->params.fail_over_mac = 1;
+ } else if (!bond->params.fail_over_mac) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: Error: The slave device specified "
+ "does not support setting the MAC address, "
+ "but fail_over_mac is not enabled.\n"
+ , bond_dev->name);
+ res = -EOPNOTSUPP;
+ goto err_undo_flags;
+ }
}
new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
@@ -1339,16 +1406,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
*/
memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN);
- /*
- * Set slave to master's mac address. The application already
- * set the master's mac address to that of the first slave
- */
- memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len);
- addr.sa_family = slave_dev->type;
- res = dev_set_mac_address(slave_dev, &addr);
- if (res) {
- dprintk("Error %d calling set_mac_address\n", res);
- goto err_free;
+ if (!bond->params.fail_over_mac) {
+ /*
+ * Set slave to master's mac address. The application already
+ * set the master's mac address to that of the first slave
+ */
+ memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len);
+ addr.sa_family = slave_dev->type;
+ res = dev_set_mac_address(slave_dev, &addr);
+ if (res) {
+ dprintk("Error %d calling set_mac_address\n", res);
+ goto err_free;
+ }
}
res = netdev_set_master(slave_dev, bond_dev);
@@ -1522,15 +1591,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
case BOND_MODE_TLB:
case BOND_MODE_ALB:
new_slave->state = BOND_STATE_ACTIVE;
- if ((!bond->curr_active_slave) &&
- (new_slave->link != BOND_LINK_DOWN)) {
- /* first slave or no active slave yet, and this link
- * is OK, so make this interface the active one
- */
- bond_change_active_slave(bond, new_slave);
- } else {
- bond_set_slave_inactive_flags(new_slave);
- }
+ bond_set_slave_inactive_flags(new_slave);
break;
default:
dprintk("This slave is always active in trunk mode\n");
@@ -1573,9 +1634,11 @@ err_close:
dev_close(slave_dev);
err_restore_mac:
- memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
- addr.sa_family = slave_dev->type;
- dev_set_mac_address(slave_dev, &addr);
+ if (!bond->params.fail_over_mac) {
+ memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
+ addr.sa_family = slave_dev->type;
+ dev_set_mac_address(slave_dev, &addr);
+ }
err_free:
kfree(new_slave);
@@ -1603,6 +1666,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
struct slave *slave, *oldcurrent;
struct sockaddr addr;
int mac_addr_differ;
+ DECLARE_MAC_BUF(mac);
/* slave is not a slave or master is not master of this slave */
if (!(slave_dev->flags & IFF_SLAVE) ||
@@ -1630,19 +1694,13 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
ETH_ALEN);
if (!mac_addr_differ && (bond->slave_cnt > 1)) {
printk(KERN_WARNING DRV_NAME
- ": %s: Warning: the permanent HWaddr of %s "
- "- %02X:%02X:%02X:%02X:%02X:%02X - is "
- "still in use by %s. Set the HWaddr of "
- "%s to a different address to avoid "
- "conflicts.\n",
+ ": %s: Warning: the permanent HWaddr of %s - "
+ "%s - is still in use by %s. "
+ "Set the HWaddr of %s to a different address "
+ "to avoid conflicts.\n",
bond_dev->name,
slave_dev->name,
- slave->perm_hwaddr[0],
- slave->perm_hwaddr[1],
- slave->perm_hwaddr[2],
- slave->perm_hwaddr[3],
- slave->perm_hwaddr[4],
- slave->perm_hwaddr[5],
+ print_mac(mac, slave->perm_hwaddr),
bond_dev->name,
slave_dev->name);
}
@@ -1689,9 +1747,23 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
bond_alb_deinit_slave(bond, slave);
}
- if (oldcurrent == slave)
+ if (oldcurrent == slave) {
+ /*
+ * Note that we hold RTNL over this sequence, so there
+ * is no concern that another slave add/remove event
+ * will interfere.
+ */
+ write_unlock_bh(&bond->lock);
+ read_lock(&bond->lock);
+ write_lock_bh(&bond->curr_slave_lock);
+
bond_select_active_slave(bond);
+ write_unlock_bh(&bond->curr_slave_lock);
+ read_unlock(&bond->lock);
+ write_lock_bh(&bond->lock);
+ }
+
if (bond->slave_cnt == 0) {
bond_set_carrier(bond);
@@ -1753,10 +1825,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
/* close slave before restoring its mac address */
dev_close(slave_dev);
- /* restore original ("permanent") mac address */
- memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
- addr.sa_family = slave_dev->type;
- dev_set_mac_address(slave_dev, &addr);
+ if (!bond->params.fail_over_mac) {
+ /* restore original ("permanent") mac address */
+ memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+ addr.sa_family = slave_dev->type;
+ dev_set_mac_address(slave_dev, &addr);
+ }
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
IFF_SLAVE_INACTIVE | IFF_BONDING |
@@ -1768,6 +1842,35 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
}
/*
+* Destroy a bonding device.
+* Must be under rtnl_lock when this function is called.
+*/
+void bond_destroy(struct bonding *bond)
+{
+ bond_deinit(bond->dev);
+ bond_destroy_sysfs_entry(bond);
+ unregister_netdevice(bond->dev);
+}
+
+/*
+* First release a slave and than destroy the bond if no more slaves iare left.
+* Must be under rtnl_lock when this function is called.
+*/
+int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev)
+{
+ struct bonding *bond = bond_dev->priv;
+ int ret;
+
+ ret = bond_release(bond_dev, slave_dev);
+ if ((ret == 0) && (bond->slave_cnt == 0)) {
+ printk(KERN_INFO DRV_NAME ": %s: destroying bond %s.\n",
+ bond_dev->name, bond_dev->name);
+ bond_destroy(bond);
+ }
+ return ret;
+}
+
+/*
* This function releases all slaves.
*/
static int bond_release_all(struct net_device *bond_dev)
@@ -1843,10 +1946,12 @@ static int bond_release_all(struct net_device *bond_dev)
/* close slave before restoring its mac address */
dev_close(slave_dev);
- /* restore original ("permanent") mac address*/
- memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
- addr.sa_family = slave_dev->type;
- dev_set_mac_address(slave_dev, &addr);
+ if (!bond->params.fail_over_mac) {
+ /* restore original ("permanent") mac address*/
+ memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+ addr.sa_family = slave_dev->type;
+ dev_set_mac_address(slave_dev, &addr);
+ }
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
IFF_SLAVE_INACTIVE);
@@ -1914,16 +2019,19 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi
return -EINVAL;
}
- write_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
+ read_lock(&bond->curr_slave_lock);
old_active = bond->curr_active_slave;
+ read_unlock(&bond->curr_slave_lock);
+
new_active = bond_get_slave_by_dev(bond, slave_dev);
/*
* Changing to the current active: do nothing; return success.
*/
if (new_active && (new_active == old_active)) {
- write_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
return 0;
}
@@ -1931,12 +2039,14 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi
(old_active) &&
(new_active->link == BOND_LINK_UP) &&
IS_UP(new_active->dev)) {
+ write_lock_bh(&bond->curr_slave_lock);
bond_change_active_slave(bond, new_active);
+ write_unlock_bh(&bond->curr_slave_lock);
} else {
res = -EINVAL;
}
- write_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
return res;
}
@@ -1948,9 +2058,9 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info)
info->bond_mode = bond->params.mode;
info->miimon = bond->params.miimon;
- read_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
info->num_slaves = bond->slave_cnt;
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
return 0;
}
@@ -1965,7 +2075,7 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
return -ENODEV;
}
- read_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
bond_for_each_slave(bond, slave, i) {
if (i == (int)info->slave_id) {
@@ -1974,7 +2084,7 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
}
}
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
if (found) {
strcpy(info->slave_name, slave->dev->name);
@@ -1990,26 +2100,25 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
/*-------------------------------- Monitoring -------------------------------*/
-/* this function is called regularly to monitor each slave's link. */
-void bond_mii_monitor(struct net_device *bond_dev)
+/*
+ * if !have_locks, return nonzero if a failover is necessary. if
+ * have_locks, do whatever failover activities are needed.
+ *
+ * This is to separate the inspection and failover steps for locking
+ * purposes; failover requires rtnl, but acquiring it for every
+ * inspection is undesirable, so a wrapper first does inspection, and
+ * the acquires the necessary locks and calls again to perform
+ * failover if needed. Since all locks are dropped, a complete
+ * restart is needed between calls.
+ */
+static int __bond_mii_monitor(struct bonding *bond, int have_locks)
{
- struct bonding *bond = bond_dev->priv;
struct slave *slave, *oldcurrent;
int do_failover = 0;
- int delta_in_ticks;
int i;
- read_lock(&bond->lock);
-
- delta_in_ticks = (bond->params.miimon * HZ) / 1000;
-
- if (bond->kill_timers) {
+ if (bond->slave_cnt == 0)
goto out;
- }
-
- if (bond->slave_cnt == 0) {
- goto re_arm;
- }
/* we will try to read the link status of each of our slaves, and
* set their IFF_RUNNING flag appropriately. For each slave not
@@ -2017,6 +2126,17 @@ void bond_mii_monitor(struct net_device *bond_dev)
* program could monitor the link itself if needed.
*/
+ if (bond->send_grat_arp) {
+ if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING,
+ &bond->curr_active_slave->dev->state))
+ dprintk("Needs to send gratuitous arp but not yet\n");
+ else {
+ dprintk("sending delayed gratuitous arp on on %s\n",
+ bond->curr_active_slave->dev->name);
+ bond_send_gratuitous_arp(bond);
+ bond->send_grat_arp = 0;
+ }
+ }
read_lock(&bond->curr_slave_lock);
oldcurrent = bond->curr_active_slave;
read_unlock(&bond->curr_slave_lock);
@@ -2032,7 +2152,11 @@ void bond_mii_monitor(struct net_device *bond_dev)
switch (slave->link) {
case BOND_LINK_UP: /* the link was up */
if (link_state == BMSR_LSTATUS) {
- /* link stays up, nothing more to do */
+ if (!oldcurrent) {
+ if (!have_locks)
+ return 1;
+ do_failover = 1;
+ }
break;
} else { /* link going down */
slave->link = BOND_LINK_FAIL;
@@ -2047,7 +2171,7 @@ void bond_mii_monitor(struct net_device *bond_dev)
": %s: link status down for %s "
"interface %s, disabling it in "
"%d ms.\n",
- bond_dev->name,
+ bond->dev->name,
IS_UP(slave_dev)
? ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
? ((slave == oldcurrent)
@@ -2065,6 +2189,9 @@ void bond_mii_monitor(struct net_device *bond_dev)
if (link_state != BMSR_LSTATUS) {
/* link stays down */
if (slave->delay <= 0) {
+ if (!have_locks)
+ return 1;
+
/* link down for too long time */
slave->link = BOND_LINK_DOWN;
@@ -2080,7 +2207,7 @@ void bond_mii_monitor(struct net_device *bond_dev)
": %s: link status definitely "
"down for interface %s, "
"disabling it\n",
- bond_dev->name,
+ bond->dev->name,
slave_dev->name);
/* notify ad that the link status has changed */
@@ -2106,7 +2233,7 @@ void bond_mii_monitor(struct net_device *bond_dev)
printk(KERN_INFO DRV_NAME
": %s: link status up again after %d "
"ms for interface %s.\n",
- bond_dev->name,
+ bond->dev->name,
(bond->params.downdelay - slave->delay) * bond->params.miimon,
slave_dev->name);
}
@@ -2126,7 +2253,7 @@ void bond_mii_monitor(struct net_device *bond_dev)
": %s: link status up for "
"interface %s, enabling it "
"in %d ms.\n",
- bond_dev->name,
+ bond->dev->name,
slave_dev->name,
bond->params.updelay * bond->params.miimon);
}
@@ -2142,12 +2269,15 @@ void bond_mii_monitor(struct net_device *bond_dev)
printk(KERN_INFO DRV_NAME
": %s: link status down again after %d "
"ms for interface %s.\n",
- bond_dev->name,
+ bond->dev->name,
(bond->params.updelay - slave->delay) * bond->params.miimon,
slave_dev->name);
} else {
/* link stays up */
if (slave->delay == 0) {
+ if (!have_locks)
+ return 1;
+
/* now the link has been up for long time enough */
slave->link = BOND_LINK_UP;
slave->jiffies = jiffies;
@@ -2166,7 +2296,7 @@ void bond_mii_monitor(struct net_device *bond_dev)
printk(KERN_INFO DRV_NAME
": %s: link status definitely "
"up for interface %s.\n",
- bond_dev->name,
+ bond->dev->name,
slave_dev->name);
/* notify ad that the link status has changed */
@@ -2192,7 +2322,7 @@ void bond_mii_monitor(struct net_device *bond_dev)
/* Should not happen */
printk(KERN_ERR DRV_NAME
": %s: Error: %s Illegal value (link=%d)\n",
- bond_dev->name,
+ bond->dev->name,
slave->dev->name,
slave->link);
goto out;
@@ -2213,24 +2343,54 @@ void bond_mii_monitor(struct net_device *bond_dev)
} /* end of for */
if (do_failover) {
- write_lock(&bond->curr_slave_lock);
+ ASSERT_RTNL();
+
+ write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
- write_unlock(&bond->curr_slave_lock);
+ write_unlock_bh(&bond->curr_slave_lock);
+
} else
bond_set_carrier(bond);
-re_arm:
- if (bond->params.miimon) {
- mod_timer(&bond->mii_timer, jiffies + delta_in_ticks);
- }
out:
- read_unlock(&bond->lock);
+ return 0;
}
+/*
+ * bond_mii_monitor
+ *
+ * Really a wrapper that splits the mii monitor into two phases: an
+ * inspection, then (if inspection indicates something needs to be
+ * done) an acquisition of appropriate locks followed by another pass
+ * to implement whatever link state changes are indicated.
+ */
+void bond_mii_monitor(struct work_struct *work)
+{
+ struct bonding *bond = container_of(work, struct bonding,
+ mii_work.work);
+ unsigned long delay;
-static u32 bond_glean_dev_ip(struct net_device *dev)
+ read_lock(&bond->lock);
+ if (bond->kill_timers) {
+ read_unlock(&bond->lock);
+ return;
+ }
+ if (__bond_mii_monitor(bond, 0)) {
+ read_unlock(&bond->lock);
+ rtnl_lock();
+ read_lock(&bond->lock);
+ __bond_mii_monitor(bond, 1);
+ rtnl_unlock();
+ }
+
+ delay = ((bond->params.miimon * HZ) / 1000) ? : 1;
+ read_unlock(&bond->lock);
+ queue_delayed_work(bond->wq, &bond->mii_work, delay);
+}
+
+static __be32 bond_glean_dev_ip(struct net_device *dev)
{
struct in_device *idev;
struct in_ifaddr *ifa;
@@ -2273,7 +2433,7 @@ static int bond_has_ip(struct bonding *bond)
return 0;
}
-static int bond_has_this_ip(struct bonding *bond, u32 ip)
+static int bond_has_this_ip(struct bonding *bond, __be32 ip)
{
struct vlan_entry *vlan, *vlan_next;
@@ -2297,7 +2457,7 @@ static int bond_has_this_ip(struct bonding *bond, u32 ip)
* switches in VLAN mode (especially if ports are configured as
* "native" to a VLAN) might not pass non-tagged frames.
*/
-static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip, u32 src_ip, unsigned short vlan_id)
+static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ip, __be32 src_ip, unsigned short vlan_id)
{
struct sk_buff *skb;
@@ -2325,7 +2485,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip,
static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
{
int i, vlan_id, rv;
- u32 *targets = bond->params.arp_targets;
+ __be32 *targets = bond->params.arp_targets;
struct vlan_entry *vlan, *vlan_next;
struct net_device *vlan_dev;
struct flowi fl;
@@ -2418,7 +2578,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
if (bond->master_ip) {
bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip,
- bond->master_ip, 0);
+ bond->master_ip, 0);
}
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
@@ -2430,10 +2590,10 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
}
}
-static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip)
+static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip)
{
int i;
- u32 *targets = bond->params.arp_targets;
+ __be32 *targets = bond->params.arp_targets;
targets = bond->params.arp_targets;
for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
@@ -2455,7 +2615,10 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
struct slave *slave;
struct bonding *bond;
unsigned char *arp_ptr;
- u32 sip, tip;
+ __be32 sip, tip;
+
+ if (dev->nd_net != &init_net)
+ goto out;
if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
goto out;
@@ -2524,9 +2687,10 @@ out:
* arp is transmitted to generate traffic. see activebackup_arp_monitor for
* arp monitoring in active backup mode.
*/
-void bond_loadbalance_arp_mon(struct net_device *bond_dev)
+void bond_loadbalance_arp_mon(struct work_struct *work)
{
- struct bonding *bond = bond_dev->priv;
+ struct bonding *bond = container_of(work, struct bonding,
+ arp_work.work);
struct slave *slave, *oldcurrent;
int do_failover = 0;
int delta_in_ticks;
@@ -2573,13 +2737,13 @@ void bond_loadbalance_arp_mon(struct net_device *bond_dev)
printk(KERN_INFO DRV_NAME
": %s: link status definitely "
"up for interface %s, ",
- bond_dev->name,
+ bond->dev->name,
slave->dev->name);
do_failover = 1;
} else {
printk(KERN_INFO DRV_NAME
": %s: interface %s is now up\n",
- bond_dev->name,
+ bond->dev->name,
slave->dev->name);
}
}
@@ -2603,7 +2767,7 @@ void bond_loadbalance_arp_mon(struct net_device *bond_dev)
printk(KERN_INFO DRV_NAME
": %s: interface %s is now down.\n",
- bond_dev->name,
+ bond->dev->name,
slave->dev->name);
if (slave == oldcurrent) {
@@ -2625,17 +2789,19 @@ void bond_loadbalance_arp_mon(struct net_device *bond_dev)
}
if (do_failover) {
- write_lock(&bond->curr_slave_lock);
+ rtnl_lock();
+ write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
- write_unlock(&bond->curr_slave_lock);
+ write_unlock_bh(&bond->curr_slave_lock);
+ rtnl_unlock();
+
}
re_arm:
- if (bond->params.arp_interval) {
- mod_timer(&bond->arp_timer, jiffies + delta_in_ticks);
- }
+ if (bond->params.arp_interval)
+ queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
out:
read_unlock(&bond->lock);
}
@@ -2655,9 +2821,10 @@ out:
* may have received.
* see loadbalance_arp_monitor for arp monitoring in load balancing mode
*/
-void bond_activebackup_arp_mon(struct net_device *bond_dev)
+void bond_activebackup_arp_mon(struct work_struct *work)
{
- struct bonding *bond = bond_dev->priv;
+ struct bonding *bond = container_of(work, struct bonding,
+ arp_work.work);
struct slave *slave;
int delta_in_ticks;
int i;
@@ -2686,7 +2853,9 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
slave->link = BOND_LINK_UP;
- write_lock(&bond->curr_slave_lock);
+ rtnl_lock();
+
+ write_lock_bh(&bond->curr_slave_lock);
if ((!bond->curr_active_slave) &&
((jiffies - slave->dev->trans_start) <= delta_in_ticks)) {
@@ -2709,18 +2878,19 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
printk(KERN_INFO DRV_NAME
": %s: %s is up and now the "
"active interface\n",
- bond_dev->name,
+ bond->dev->name,
slave->dev->name);
netif_carrier_on(bond->dev);
} else {
printk(KERN_INFO DRV_NAME
": %s: backup interface %s is "
"now up\n",
- bond_dev->name,
+ bond->dev->name,
slave->dev->name);
}
- write_unlock(&bond->curr_slave_lock);
+ write_unlock_bh(&bond->curr_slave_lock);
+ rtnl_unlock();
}
} else {
read_lock(&bond->curr_slave_lock);
@@ -2752,7 +2922,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
printk(KERN_INFO DRV_NAME
": %s: backup interface %s is now down\n",
- bond_dev->name,
+ bond->dev->name,
slave->dev->name);
} else {
read_unlock(&bond->curr_slave_lock);
@@ -2787,15 +2957,18 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
printk(KERN_INFO DRV_NAME
": %s: link status down for active interface "
"%s, disabling it\n",
- bond_dev->name,
+ bond->dev->name,
slave->dev->name);
- write_lock(&bond->curr_slave_lock);
+ rtnl_lock();
+ write_lock_bh(&bond->curr_slave_lock);
bond_select_active_slave(bond);
slave = bond->curr_active_slave;
- write_unlock(&bond->curr_slave_lock);
+ write_unlock_bh(&bond->curr_slave_lock);
+
+ rtnl_unlock();
bond->current_arp_slave = slave;
@@ -2809,14 +2982,17 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
printk(KERN_INFO DRV_NAME
": %s: changing from interface %s to primary "
"interface %s\n",
- bond_dev->name,
+ bond->dev->name,
slave->dev->name,
bond->primary_slave->dev->name);
/* primary is up so switch to it */
- write_lock(&bond->curr_slave_lock);
+ rtnl_lock();
+ write_lock_bh(&bond->curr_slave_lock);
bond_change_active_slave(bond, bond->primary_slave);
- write_unlock(&bond->curr_slave_lock);
+ write_unlock_bh(&bond->curr_slave_lock);
+
+ rtnl_unlock();
slave = bond->primary_slave;
slave->jiffies = jiffies;
@@ -2873,7 +3049,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
printk(KERN_INFO DRV_NAME
": %s: backup interface %s is "
"now down.\n",
- bond_dev->name,
+ bond->dev->name,
slave->dev->name);
}
}
@@ -2882,7 +3058,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
re_arm:
if (bond->params.arp_interval) {
- mod_timer(&bond->arp_timer, jiffies + delta_in_ticks);
+ queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
}
out:
read_unlock(&bond->lock);
@@ -2903,7 +3079,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
/* make sure the bond won't be taken away */
read_lock(&dev_base_lock);
- read_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
if (*pos == 0) {
return SEQ_START_TOKEN;
@@ -2937,7 +3113,7 @@ static void bond_info_seq_stop(struct seq_file *seq, void *v)
{
struct bonding *bond = seq->private;
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
read_unlock(&dev_base_lock);
}
@@ -2952,9 +3128,15 @@ static void bond_info_show_master(struct seq_file *seq)
curr = bond->curr_active_slave;
read_unlock(&bond->curr_slave_lock);
- seq_printf(seq, "Bonding Mode: %s\n",
+ seq_printf(seq, "Bonding Mode: %s",
bond_mode_name(bond->params.mode));
+ if (bond->params.mode == BOND_MODE_ACTIVEBACKUP &&
+ bond->params.fail_over_mac)
+ seq_printf(seq, " (fail_over_mac)");
+
+ seq_printf(seq, "\n");
+
if (bond->params.mode == BOND_MODE_XOR ||
bond->params.mode == BOND_MODE_8023AD) {
seq_printf(seq, "Transmit Hash Policy: %s (%d)\n",
@@ -3002,6 +3184,7 @@ static void bond_info_show_master(struct seq_file *seq)
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
+ DECLARE_MAC_BUF(mac);
seq_puts(seq, "\n802.3ad info\n");
seq_printf(seq, "LACP rate: %s\n",
@@ -3021,13 +3204,8 @@ static void bond_info_show_master(struct seq_file *seq)
ad_info.actor_key);
seq_printf(seq, "\tPartner Key: %d\n",
ad_info.partner_key);
- seq_printf(seq, "\tPartner Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
- ad_info.partner_system[0],
- ad_info.partner_system[1],
- ad_info.partner_system[2],
- ad_info.partner_system[3],
- ad_info.partner_system[4],
- ad_info.partner_system[5]);
+ seq_printf(seq, "\tPartner Mac Address: %s\n",
+ print_mac(mac, ad_info.partner_system));
}
}
}
@@ -3035,6 +3213,7 @@ static void bond_info_show_master(struct seq_file *seq)
static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave)
{
struct bonding *bond = seq->private;
+ DECLARE_MAC_BUF(mac);
seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name);
seq_printf(seq, "MII Status: %s\n",
@@ -3043,10 +3222,8 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave
slave->link_failure_count);
seq_printf(seq,
- "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
- slave->perm_hwaddr[0], slave->perm_hwaddr[1],
- slave->perm_hwaddr[2], slave->perm_hwaddr[3],
- slave->perm_hwaddr[4], slave->perm_hwaddr[5]);
+ "Permanent HW addr: %s\n",
+ print_mac(mac, slave->perm_hwaddr));
if (bond->params.mode == BOND_MODE_8023AD) {
const struct aggregator *agg
@@ -3144,7 +3321,7 @@ static void bond_create_proc_dir(void)
{
int len = strlen(DRV_NAME);
- for (bond_proc_dir = proc_net->subdir; bond_proc_dir;
+ for (bond_proc_dir = init_net.proc_net->subdir; bond_proc_dir;
bond_proc_dir = bond_proc_dir->next) {
if ((bond_proc_dir->namelen == len) &&
!memcmp(bond_proc_dir->name, DRV_NAME, len)) {
@@ -3153,7 +3330,7 @@ static void bond_create_proc_dir(void)
}
if (!bond_proc_dir) {
- bond_proc_dir = proc_mkdir(DRV_NAME, proc_net);
+ bond_proc_dir = proc_mkdir(DRV_NAME, init_net.proc_net);
if (bond_proc_dir) {
bond_proc_dir->owner = THIS_MODULE;
} else {
@@ -3188,7 +3365,7 @@ static void bond_destroy_proc_dir(void)
bond_proc_dir->owner = NULL;
}
} else {
- remove_proc_entry(DRV_NAME, proc_net);
+ remove_proc_entry(DRV_NAME, init_net.proc_net);
bond_proc_dir = NULL;
}
}
@@ -3239,7 +3416,10 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave
switch (event) {
case NETDEV_UNREGISTER:
if (bond_dev) {
- bond_release(bond_dev, slave_dev);
+ if (bond->setup_by_slave)
+ bond_release_and_destroy(bond_dev, slave_dev);
+ else
+ bond_release(bond_dev, slave_dev);
}
break;
case NETDEV_CHANGE:
@@ -3295,6 +3475,9 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v
{
struct net_device *event_dev = (struct net_device *)ptr;
+ if (event_dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
dprintk("event_dev: %s, event: %lx\n",
(event_dev ? event_dev->name : "None"),
event);
@@ -3430,14 +3613,14 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb,
{
struct ethhdr *data = (struct ethhdr *)skb->data;
struct iphdr *iph = ip_hdr(skb);
- u16 *layer4hdr = (u16 *)((u32 *)iph + iph->ihl);
+ __be16 *layer4hdr = (__be16 *)((u32 *)iph + iph->ihl);
int layer4_xor = 0;
if (skb->protocol == __constant_htons(ETH_P_IP)) {
if (!(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) &&
(iph->protocol == IPPROTO_TCP ||
iph->protocol == IPPROTO_UDP)) {
- layer4_xor = htons((*layer4hdr ^ *(layer4hdr + 1)));
+ layer4_xor = ntohs((*layer4hdr ^ *(layer4hdr + 1)));
}
return (layer4_xor ^
((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count;
@@ -3463,15 +3646,11 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb,
static int bond_open(struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;
- struct timer_list *mii_timer = &bond->mii_timer;
- struct timer_list *arp_timer = &bond->arp_timer;
bond->kill_timers = 0;
if ((bond->params.mode == BOND_MODE_TLB) ||
(bond->params.mode == BOND_MODE_ALB)) {
- struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer);
-
/* bond_alb_initialize must be called before the timer
* is started.
*/
@@ -3480,44 +3659,31 @@ static int bond_open(struct net_device *bond_dev)
return -1;
}
- init_timer(alb_timer);
- alb_timer->expires = jiffies + 1;
- alb_timer->data = (unsigned long)bond;
- alb_timer->function = (void *)&bond_alb_monitor;
- add_timer(alb_timer);
+ INIT_DELAYED_WORK(&bond->alb_work, bond_alb_monitor);
+ queue_delayed_work(bond->wq, &bond->alb_work, 0);
}
if (bond->params.miimon) { /* link check interval, in milliseconds. */
- init_timer(mii_timer);
- mii_timer->expires = jiffies + 1;
- mii_timer->data = (unsigned long)bond_dev;
- mii_timer->function = (void *)&bond_mii_monitor;
- add_timer(mii_timer);
+ INIT_DELAYED_WORK(&bond->mii_work, bond_mii_monitor);
+ queue_delayed_work(bond->wq, &bond->mii_work, 0);
}
if (bond->params.arp_interval) { /* arp interval, in milliseconds. */
- init_timer(arp_timer);
- arp_timer->expires = jiffies + 1;
- arp_timer->data = (unsigned long)bond_dev;
- if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
- arp_timer->function = (void *)&bond_activebackup_arp_mon;
- } else {
- arp_timer->function = (void *)&bond_loadbalance_arp_mon;
- }
+ if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
+ INIT_DELAYED_WORK(&bond->arp_work,
+ bond_activebackup_arp_mon);
+ else
+ INIT_DELAYED_WORK(&bond->arp_work,
+ bond_loadbalance_arp_mon);
+
+ queue_delayed_work(bond->wq, &bond->arp_work, 0);
if (bond->params.arp_validate)
bond_register_arp(bond);
-
- add_timer(arp_timer);
}
if (bond->params.mode == BOND_MODE_8023AD) {
- struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer);
- init_timer(ad_timer);
- ad_timer->expires = jiffies + 1;
- ad_timer->data = (unsigned long)bond;
- ad_timer->function = (void *)&bond_3ad_state_machine_handler;
- add_timer(ad_timer);
-
+ INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler);
+ queue_delayed_work(bond->wq, &bond->ad_work, 0);
/* register to receive LACPDUs */
bond_register_lacpdu(bond);
}
@@ -3545,25 +3711,21 @@ static int bond_close(struct net_device *bond_dev)
write_unlock_bh(&bond->lock);
- /* del_timer_sync must run without holding the bond->lock
- * because a running timer might be trying to hold it too
- */
-
if (bond->params.miimon) { /* link check interval, in milliseconds. */
- del_timer_sync(&bond->mii_timer);
+ cancel_delayed_work(&bond->mii_work);
}
if (bond->params.arp_interval) { /* arp interval, in milliseconds. */
- del_timer_sync(&bond->arp_timer);
+ cancel_delayed_work(&bond->arp_work);
}
switch (bond->params.mode) {
case BOND_MODE_8023AD:
- del_timer_sync(&(BOND_AD_INFO(bond).ad_timer));
+ cancel_delayed_work(&bond->ad_work);
break;
case BOND_MODE_TLB:
case BOND_MODE_ALB:
- del_timer_sync(&(BOND_ALB_INFO(bond).alb_timer));
+ cancel_delayed_work(&bond->alb_work);
break;
default:
break;
@@ -3660,13 +3822,13 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
if (mii->reg_num == 1) {
struct bonding *bond = bond_dev->priv;
mii->val_out = 0;
- read_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
read_lock(&bond->curr_slave_lock);
if (netif_carrier_ok(bond->dev)) {
mii->val_out = BMSR_LSTATUS;
}
read_unlock(&bond->curr_slave_lock);
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
}
return 0;
@@ -3712,7 +3874,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
}
down_write(&(bonding_rwsem));
- slave_dev = dev_get_by_name(ifr->ifr_slave);
+ slave_dev = dev_get_by_name(&init_net, ifr->ifr_slave);
dprintk("slave_dev=%p: \n", slave_dev);
@@ -3883,6 +4045,13 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None"));
+ /*
+ * If fail_over_mac is enabled, do nothing and return success.
+ * Returning an error causes ifenslave to fail.
+ */
+ if (bond->params.fail_over_mac)
+ return 0;
+
if (!is_valid_ether_addr(sa->sa_data)) {
return -EADDRNOTAVAIL;
}
@@ -3951,8 +4120,7 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
{
struct bonding *bond = bond_dev->priv;
struct slave *slave, *start_at;
- int i;
- int res = 1;
+ int i, slave_no, res = 1;
read_lock(&bond->lock);
@@ -3960,29 +4128,29 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
goto out;
}
- read_lock(&bond->curr_slave_lock);
- slave = start_at = bond->curr_active_slave;
- read_unlock(&bond->curr_slave_lock);
+ /*
+ * Concurrent TX may collide on rr_tx_counter; we accept that
+ * as being rare enough not to justify using an atomic op here
+ */
+ slave_no = bond->rr_tx_counter++ % bond->slave_cnt;
- if (!slave) {
- goto out;
+ bond_for_each_slave(bond, slave, i) {
+ slave_no--;
+ if (slave_no < 0) {
+ break;
+ }
}
+ start_at = slave;
bond_for_each_slave_from(bond, slave, i, start_at) {
if (IS_UP(slave->dev) &&
(slave->link == BOND_LINK_UP) &&
(slave->state == BOND_STATE_ACTIVE)) {
res = bond_dev_queue_xmit(bond, skb, slave->dev);
-
- write_lock(&bond->curr_slave_lock);
- bond->curr_active_slave = slave->next;
- write_unlock(&bond->curr_slave_lock);
-
break;
}
}
-
out:
if (res) {
/* no suitable interface, frame not sent */
@@ -4195,10 +4363,6 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
}
static const struct ethtool_ops bond_ethtool_ops = {
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_tso = ethtool_op_get_tso,
- .get_ufo = ethtool_op_get_ufo,
- .get_sg = ethtool_op_get_sg,
.get_drvinfo = bond_ethtool_get_drvinfo,
};
@@ -4218,12 +4382,18 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
bond->params = *params; /* copy params struct */
+ bond->wq = create_singlethread_workqueue(bond_dev->name);
+ if (!bond->wq)
+ return -ENOMEM;
+
/* Initialize pointers */
bond->first_slave = NULL;
bond->curr_active_slave = NULL;
bond->current_arp_slave = NULL;
bond->primary_slave = NULL;
bond->dev = bond_dev;
+ bond->send_grat_arp = 0;
+ bond->setup_by_slave = 0;
INIT_LIST_HEAD(&bond->vlan_list);
/* Initialize the device entry points */
@@ -4235,6 +4405,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
bond_dev->set_multicast_list = bond_set_multicast_list;
bond_dev->change_mtu = bond_change_mtu;
bond_dev->set_mac_address = bond_set_mac_address;
+ bond_dev->validate_addr = NULL;
bond_set_mode_ops(bond, bond->params.mode);
@@ -4272,7 +4443,6 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
#ifdef CONFIG_PROC_FS
bond_create_proc_entry(bond);
#endif
-
list_add_tail(&bond->bond_list, &bond_dev_list);
return 0;
@@ -4281,7 +4451,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
/* De-initialize device specific data.
* Caller must hold rtnl_lock.
*/
-void bond_deinit(struct net_device *bond_dev)
+static void bond_deinit(struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;
@@ -4528,7 +4698,7 @@ static int bond_check_params(struct bond_params *params)
arp_ip_target[arp_ip_count]);
arp_interval = 0;
} else {
- u32 ip = in_aton(arp_ip_target[arp_ip_count]);
+ __be32 ip = in_aton(arp_ip_target[arp_ip_count]);
arp_target[arp_ip_count] = ip;
}
}
@@ -4606,6 +4776,11 @@ static int bond_check_params(struct bond_params *params)
primary = NULL;
}
+ if (fail_over_mac && (bond_mode != BOND_MODE_ACTIVEBACKUP))
+ printk(KERN_WARNING DRV_NAME
+ ": Warning: fail_over_mac only affects "
+ "active-backup mode.\n");
+
/* fill params struct with the proper values */
params->mode = bond_mode;
params->xmit_policy = xmit_hashtype;
@@ -4617,6 +4792,7 @@ static int bond_check_params(struct bond_params *params)
params->use_carrier = use_carrier;
params->lacp_fast = lacp_fast;
params->primary[0] = 0;
+ params->fail_over_mac = fail_over_mac;
if (primary) {
strncpy(params->primary, primary, IFNAMSIZ);
@@ -4667,8 +4843,6 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
goto out_netdev;
}
- SET_MODULE_OWNER(bond_dev);
-
res = register_netdevice(bond_dev);
if (res < 0) {
goto out_bond;
@@ -4699,10 +4873,32 @@ out_rtnl:
return res;
}
+static void bond_work_cancel_all(struct bonding *bond)
+{
+ write_lock_bh(&bond->lock);
+ bond->kill_timers = 1;
+ write_unlock_bh(&bond->lock);
+
+ if (bond->params.miimon && delayed_work_pending(&bond->mii_work))
+ cancel_delayed_work(&bond->mii_work);
+
+ if (bond->params.arp_interval && delayed_work_pending(&bond->arp_work))
+ cancel_delayed_work(&bond->arp_work);
+
+ if (bond->params.mode == BOND_MODE_ALB &&
+ delayed_work_pending(&bond->alb_work))
+ cancel_delayed_work(&bond->alb_work);
+
+ if (bond->params.mode == BOND_MODE_8023AD &&
+ delayed_work_pending(&bond->ad_work))
+ cancel_delayed_work(&bond->ad_work);
+}
+
static int __init bonding_init(void)
{
int i;
int res;
+ struct bonding *bond, *nxt;
printk(KERN_INFO "%s", version);
@@ -4729,6 +4925,11 @@ static int __init bonding_init(void)
goto out;
err:
+ list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
+ bond_work_cancel_all(bond);
+ destroy_workqueue(bond->wq);
+ }
+
rtnl_lock();
bond_free_all();
bond_destroy_sysfs();
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 60cccf2aa95..b29330d8e30 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -31,10 +31,10 @@
#include <linux/inetdevice.h>
#include <linux/in.h>
#include <linux/sysfs.h>
-#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/inet.h>
#include <linux/rtnetlink.h>
+#include <net/net_namespace.h>
/* #define BONDING_DEBUG 1 */
#include "bonding.h"
@@ -55,7 +55,7 @@ static int expected_refcount = -1;
static struct class *netdev_class;
/*--------------------------- Data Structures -----------------------------*/
-/* Bonding sysfs lock. Why can't we just use the subsytem lock?
+/* Bonding sysfs lock. Why can't we just use the subsystem lock?
* Because kobject_register tries to acquire the subsystem lock. If
* we already hold the lock (which we would if the user was creating
* a new bond through the sysfs interface), we deadlock.
@@ -164,9 +164,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
printk(KERN_INFO DRV_NAME
": %s is being deleted...\n",
bond->dev->name);
- bond_deinit(bond->dev);
- bond_destroy_sysfs_entry(bond);
- unregister_netdevice(bond->dev);
+ bond_destroy(bond);
rtnl_unlock();
goto out;
}
@@ -231,7 +229,7 @@ static ssize_t bonding_show_slaves(struct device *d,
int i, res = 0;
struct bonding *bond = to_bond(d);
- read_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
bond_for_each_slave(bond, slave, i) {
if (res > (PAGE_SIZE - IFNAMSIZ)) {
/* not enough space for another interface name */
@@ -242,7 +240,7 @@ static ssize_t bonding_show_slaves(struct device *d,
}
res += sprintf(buf + res, "%s ", slave->dev->name);
}
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
res += sprintf(buf + res, "\n");
res++;
return res;
@@ -260,17 +258,16 @@ static ssize_t bonding_store_slaves(struct device *d,
char command[IFNAMSIZ + 1] = { 0, };
char *ifname;
int i, res, found, ret = count;
+ u32 original_mtu;
struct slave *slave;
struct net_device *dev = NULL;
struct bonding *bond = to_bond(d);
/* Quick sanity check -- is the bond interface up? */
if (!(bond->dev->flags & IFF_UP)) {
- printk(KERN_ERR DRV_NAME
- ": %s: Unable to update slaves because interface is down.\n",
+ printk(KERN_WARNING DRV_NAME
+ ": %s: doing slave updates when interface is down.\n",
bond->dev->name);
- ret = -EPERM;
- goto out;
}
/* Note: We can't hold bond->lock here, as bond_create grabs it. */
@@ -285,21 +282,21 @@ static ssize_t bonding_store_slaves(struct device *d,
/* Got a slave name in ifname. Is it already in the list? */
found = 0;
- read_lock_bh(&bond->lock);
+ read_lock(&bond->lock);
bond_for_each_slave(bond, slave, i)
if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
printk(KERN_ERR DRV_NAME
": %s: Interface %s is already enslaved!\n",
bond->dev->name, ifname);
ret = -EPERM;
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
goto out;
}
- read_unlock_bh(&bond->lock);
+ read_unlock(&bond->lock);
printk(KERN_INFO DRV_NAME ": %s: Adding slave %s.\n",
bond->dev->name, ifname);
- dev = dev_get_by_name(ifname);
+ dev = dev_get_by_name(&init_net, ifname);
if (!dev) {
printk(KERN_INFO DRV_NAME
": %s: Interface %s does not exist!\n",
@@ -327,6 +324,7 @@ static ssize_t bonding_store_slaves(struct device *d,
}
/* Set the slave's MTU to match the bond */
+ original_mtu = dev->mtu;
if (dev->mtu != bond->dev->mtu) {
if (dev->change_mtu) {
res = dev->change_mtu(dev,
@@ -341,6 +339,9 @@ static ssize_t bonding_store_slaves(struct device *d,
}
rtnl_lock();
res = bond_enslave(bond->dev, dev);
+ bond_for_each_slave(bond, slave, i)
+ if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0)
+ slave->original_mtu = original_mtu;
rtnl_unlock();
if (res) {
ret = res;
@@ -353,13 +354,17 @@ static ssize_t bonding_store_slaves(struct device *d,
bond_for_each_slave(bond, slave, i)
if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
dev = slave->dev;
+ original_mtu = slave->original_mtu;
break;
}
if (dev) {
printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n",
bond->dev->name, dev->name);
rtnl_lock();
- res = bond_release(bond->dev, dev);
+ if (bond->setup_by_slave)
+ res = bond_release_and_destroy(bond->dev, dev);
+ else
+ res = bond_release(bond->dev, dev);
rtnl_unlock();
if (res) {
ret = res;
@@ -367,9 +372,9 @@ static ssize_t bonding_store_slaves(struct device *d,
}
/* set the slave MTU to the default */
if (dev->change_mtu) {
- dev->change_mtu(dev, 1500);
+ dev->change_mtu(dev, original_mtu);
} else {
- dev->mtu = 1500;
+ dev->mtu = original_mtu;
}
}
else {
@@ -563,6 +568,54 @@ static ssize_t bonding_store_arp_validate(struct device *d,
static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
/*
+ * Show and store fail_over_mac. User only allowed to change the
+ * value when there are no slaves.
+ */
+static ssize_t bonding_show_fail_over_mac(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ return sprintf(buf, "%d\n", bond->params.fail_over_mac) + 1;
+}
+
+static ssize_t bonding_store_fail_over_mac(struct device *d, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int new_value;
+ int ret = count;
+ struct bonding *bond = to_bond(d);
+
+ if (bond->slave_cnt != 0) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: Can't alter fail_over_mac with slaves in bond.\n",
+ bond->dev->name);
+ ret = -EPERM;
+ goto out;
+ }
+
+ if (sscanf(buf, "%d", &new_value) != 1) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: no fail_over_mac value specified.\n",
+ bond->dev->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if ((new_value == 0) || (new_value == 1)) {
+ bond->params.fail_over_mac = new_value;
+ printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %d.\n",
+ bond->dev->name, new_value);
+ } else {
+ printk(KERN_INFO DRV_NAME
+ ": %s: Ignoring invalid fail_over_mac value %d.\n",
+ bond->dev->name, new_value);
+ }
+out:
+ return ret;
+}
+
+static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, bonding_show_fail_over_mac, bonding_store_fail_over_mac);
+
+/*
* Show and set the arp timer interval. There are two tricky bits
* here. First, if ARP monitoring is activated, then we must disable
* MII monitoring. Second, if the ARP timer isn't running, we must
@@ -609,12 +662,9 @@ static ssize_t bonding_store_arp_interval(struct device *d,
"%s Disabling MII monitoring.\n",
bond->dev->name, bond->dev->name);
bond->params.miimon = 0;
- /* Kill MII timer, else it brings bond's link down */
- if (bond->arp_timer.function) {
- printk(KERN_INFO DRV_NAME
- ": %s: Kill MII timer, else it brings bond's link down...\n",
- bond->dev->name);
- del_timer_sync(&bond->mii_timer);
+ if (delayed_work_pending(&bond->mii_work)) {
+ cancel_delayed_work(&bond->mii_work);
+ flush_workqueue(bond->wq);
}
}
if (!bond->params.arp_targets[0]) {
@@ -629,25 +679,15 @@ static ssize_t bonding_store_arp_interval(struct device *d,
* timer will get fired off when the open function
* is called.
*/
- if (bond->arp_timer.function) {
- /* The timer's already set up, so fire it off */
- mod_timer(&bond->arp_timer, jiffies + 1);
- } else {
- /* Set up the timer. */
- init_timer(&bond->arp_timer);
- bond->arp_timer.expires = jiffies + 1;
- bond->arp_timer.data =
- (unsigned long) bond->dev;
- if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
- bond->arp_timer.function =
- (void *)
- &bond_activebackup_arp_mon;
- } else {
- bond->arp_timer.function =
- (void *)
- &bond_loadbalance_arp_mon;
- }
- add_timer(&bond->arp_timer);
+ if (!delayed_work_pending(&bond->arp_work)) {
+ if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
+ INIT_DELAYED_WORK(&bond->arp_work,
+ bond_activebackup_arp_mon);
+ else
+ INIT_DELAYED_WORK(&bond->arp_work,
+ bond_loadbalance_arp_mon);
+
+ queue_delayed_work(bond->wq, &bond->arp_work, 0);
}
}
@@ -682,16 +722,16 @@ static ssize_t bonding_store_arp_targets(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
- u32 newtarget;
+ __be32 newtarget;
int i = 0, done = 0, ret = count;
struct bonding *bond = to_bond(d);
- u32 *targets;
+ __be32 *targets;
targets = bond->params.arp_targets;
newtarget = in_aton(buf + 1);
/* look for adds */
if (buf[0] == '+') {
- if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) {
+ if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) {
printk(KERN_ERR DRV_NAME
": %s: invalid ARP target %u.%u.%u.%u specified for addition\n",
bond->dev->name, NIPQUAD(newtarget));
@@ -727,7 +767,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
}
else if (buf[0] == '-') {
- if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) {
+ if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) {
printk(KERN_ERR DRV_NAME
": %s: invalid ARP target %d.%d.%d.%d specified for removal\n",
bond->dev->name, NIPQUAD(newtarget));
@@ -1003,12 +1043,9 @@ static ssize_t bonding_store_miimon(struct device *d,
bond->params.arp_validate =
BOND_ARP_VALIDATE_NONE;
}
- /* Kill ARP timer, else it brings bond's link down */
- if (bond->mii_timer.function) {
- printk(KERN_INFO DRV_NAME
- ": %s: Kill ARP timer, else it brings bond's link down...\n",
- bond->dev->name);
- del_timer_sync(&bond->arp_timer);
+ if (delayed_work_pending(&bond->arp_work)) {
+ cancel_delayed_work(&bond->arp_work);
+ flush_workqueue(bond->wq);
}
}
@@ -1018,18 +1055,11 @@ static ssize_t bonding_store_miimon(struct device *d,
* timer will get fired off when the open function
* is called.
*/
- if (bond->mii_timer.function) {
- /* The timer's already set up, so fire it off */
- mod_timer(&bond->mii_timer, jiffies + 1);
- } else {
- /* Set up the timer. */
- init_timer(&bond->mii_timer);
- bond->mii_timer.expires = jiffies + 1;
- bond->mii_timer.data =
- (unsigned long) bond->dev;
- bond->mii_timer.function =
- (void *) &bond_mii_monitor;
- add_timer(&bond->mii_timer);
+ if (!delayed_work_pending(&bond->mii_work)) {
+ INIT_DELAYED_WORK(&bond->mii_work,
+ bond_mii_monitor);
+ queue_delayed_work(bond->wq,
+ &bond->mii_work, 0);
}
}
}
@@ -1103,6 +1133,9 @@ static ssize_t bonding_store_primary(struct device *d,
}
out:
write_unlock_bh(&bond->lock);
+
+ rtnl_unlock();
+
return count;
}
static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary);
@@ -1160,7 +1193,6 @@ static ssize_t bonding_show_active_slave(struct device *d,
struct bonding *bond = to_bond(d);
int count;
-
read_lock(&bond->curr_slave_lock);
curr = bond->curr_active_slave;
read_unlock(&bond->curr_slave_lock);
@@ -1182,7 +1214,9 @@ static ssize_t bonding_store_active_slave(struct device *d,
struct slave *new_active = NULL;
struct bonding *bond = to_bond(d);
+ rtnl_lock();
write_lock_bh(&bond->lock);
+
if (!USES_PRIMARY(bond->params.mode)) {
printk(KERN_INFO DRV_NAME
": %s: Unable to change active slave; %s is in mode %d\n",
@@ -1239,6 +1273,8 @@ static ssize_t bonding_store_active_slave(struct device *d,
}
out:
write_unlock_bh(&bond->lock);
+ rtnl_unlock();
+
return count;
}
@@ -1361,17 +1397,14 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d,
{
int count = 0;
struct bonding *bond = to_bond(d);
+ DECLARE_MAC_BUF(mac);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
if (!bond_3ad_get_active_agg_info(bond, &ad_info)) {
- count = sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x\n",
- ad_info.partner_system[0],
- ad_info.partner_system[1],
- ad_info.partner_system[2],
- ad_info.partner_system[3],
- ad_info.partner_system[4],
- ad_info.partner_system[5]) + 1;
+ count = sprintf(buf,"%s\n",
+ print_mac(mac, ad_info.partner_system))
+ + 1;
}
}
else
@@ -1386,6 +1419,7 @@ static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
static struct attribute *per_bond_attrs[] = {
&dev_attr_slaves.attr,
&dev_attr_mode.attr,
+ &dev_attr_fail_over_mac.attr,
&dev_attr_arp_validate.attr,
&dev_attr_arp_interval.attr,
&dev_attr_arp_ip_target.attr,
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 6dcbd25e3ef..61c1b4536d3 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -22,8 +22,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "3.1.3"
-#define DRV_RELDATE "June 13, 2007"
+#define DRV_VERSION "3.2.1"
+#define DRV_RELDATE "October 15, 2007"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -128,11 +128,12 @@ struct bond_params {
int arp_interval;
int arp_validate;
int use_carrier;
+ int fail_over_mac;
int updelay;
int downdelay;
int lacp_fast;
char primary[IFNAMSIZ];
- u32 arp_targets[BOND_MAX_ARP_TARGETS];
+ __be32 arp_targets[BOND_MAX_ARP_TARGETS];
};
struct bond_parm_tbl {
@@ -142,7 +143,7 @@ struct bond_parm_tbl {
struct vlan_entry {
struct list_head vlan_list;
- u32 vlan_ip;
+ __be32 vlan_ip;
unsigned short vlan_id;
};
@@ -156,6 +157,7 @@ struct slave {
s8 link; /* one of BOND_LINK_XXXX */
s8 state; /* one of BOND_STATE_XXXX */
u32 original_flags;
+ u32 original_mtu;
u32 link_failure_count;
u16 speed;
u8 duplex;
@@ -182,9 +184,9 @@ struct bonding {
s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
rwlock_t lock;
rwlock_t curr_slave_lock;
- struct timer_list mii_timer;
- struct timer_list arp_timer;
s8 kill_timers;
+ s8 send_grat_arp;
+ s8 setup_by_slave;
struct net_device_stats stats;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_entry;
@@ -193,14 +195,20 @@ struct bonding {
struct list_head bond_list;
struct dev_mc_list *mc_list;
int (*xmit_hash_policy)(struct sk_buff *, struct net_device *, int);
- u32 master_ip;
+ __be32 master_ip;
u16 flags;
+ u16 rr_tx_counter;
struct ad_bond_info ad_info;
struct alb_bond_info alb_info;
struct bond_params params;
struct list_head vlan_list;
struct vlan_group *vlgrp;
struct packet_type arp_mon_pt;
+ struct workqueue_struct *wq;
+ struct delayed_work mii_work;
+ struct delayed_work arp_work;
+ struct delayed_work alb_work;
+ struct delayed_work ad_work;
};
/**
@@ -292,7 +300,8 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond)
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
int bond_create(char *name, struct bond_params *params, struct bonding **newbond);
-void bond_deinit(struct net_device *bond_dev);
+void bond_destroy(struct bonding *bond);
+int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_create_sysfs(void);
void bond_destroy_sysfs(void);
void bond_destroy_sysfs_entry(struct bonding *bond);
@@ -301,9 +310,9 @@ int bond_create_slave_symlinks(struct net_device *master, struct net_device *sla
void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave);
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
-void bond_mii_monitor(struct net_device *bond_dev);
-void bond_loadbalance_arp_mon(struct net_device *bond_dev);
-void bond_activebackup_arp_mon(struct net_device *bond_dev);
+void bond_mii_monitor(struct work_struct *);
+void bond_loadbalance_arp_mon(struct work_struct *);
+void bond_activebackup_arp_mon(struct work_struct *);
void bond_set_mode_ops(struct bonding *bond, int mode);
int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl);
void bond_select_active_slave(struct bonding *bond);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index f6e4030c73d..7df31b5561c 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -2485,7 +2485,7 @@ static irqreturn_t cas_interruptN(int irq, void *dev_id)
if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
#ifdef USE_NAPI
cas_mask_intr(cp);
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &cp->napi);
#else
cas_rx_ringN(cp, ring, 0);
#endif
@@ -2536,7 +2536,7 @@ static irqreturn_t cas_interrupt1(int irq, void *dev_id)
if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
#ifdef USE_NAPI
cas_mask_intr(cp);
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &cp->napi);
#else
cas_rx_ringN(cp, 1, 0);
#endif
@@ -2592,7 +2592,7 @@ static irqreturn_t cas_interrupt(int irq, void *dev_id)
if (status & INTR_RX_DONE) {
#ifdef USE_NAPI
cas_mask_intr(cp);
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &cp->napi);
#else
cas_rx_ringN(cp, 0, 0);
#endif
@@ -2607,9 +2607,10 @@ static irqreturn_t cas_interrupt(int irq, void *dev_id)
#ifdef USE_NAPI
-static int cas_poll(struct net_device *dev, int *budget)
+static int cas_poll(struct napi_struct *napi, int budget)
{
- struct cas *cp = netdev_priv(dev);
+ struct cas *cp = container_of(napi, struct cas, napi);
+ struct net_device *dev = cp->dev;
int i, enable_intr, todo, credits;
u32 status = readl(cp->regs + REG_INTR_STATUS);
unsigned long flags;
@@ -2620,20 +2621,18 @@ static int cas_poll(struct net_device *dev, int *budget)
/* NAPI rx packets. we spread the credits across all of the
* rxc rings
- */
- todo = min(*budget, dev->quota);
-
- /* to make sure we're fair with the work we loop through each
+ *
+ * to make sure we're fair with the work we loop through each
* ring N_RX_COMP_RING times with a request of
- * todo / N_RX_COMP_RINGS
+ * budget / N_RX_COMP_RINGS
*/
enable_intr = 1;
credits = 0;
for (i = 0; i < N_RX_COMP_RINGS; i++) {
int j;
for (j = 0; j < N_RX_COMP_RINGS; j++) {
- credits += cas_rx_ringN(cp, j, todo / N_RX_COMP_RINGS);
- if (credits >= todo) {
+ credits += cas_rx_ringN(cp, j, budget / N_RX_COMP_RINGS);
+ if (credits >= budget) {
enable_intr = 0;
goto rx_comp;
}
@@ -2641,9 +2640,6 @@ static int cas_poll(struct net_device *dev, int *budget)
}
rx_comp:
- *budget -= credits;
- dev->quota -= credits;
-
/* final rx completion */
spin_lock_irqsave(&cp->lock, flags);
if (status)
@@ -2674,11 +2670,10 @@ rx_comp:
#endif
spin_unlock_irqrestore(&cp->lock, flags);
if (enable_intr) {
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
cas_unmask_intr(cp);
- return 0;
}
- return 1;
+ return credits;
}
#endif
@@ -4351,6 +4346,9 @@ static int cas_open(struct net_device *dev)
goto err_spare;
}
+#ifdef USE_NAPI
+ napi_enable(&cp->napi);
+#endif
/* init hw */
cas_lock_all_save(cp, flags);
cas_clean_rings(cp);
@@ -4376,6 +4374,9 @@ static int cas_close(struct net_device *dev)
unsigned long flags;
struct cas *cp = netdev_priv(dev);
+#ifdef USE_NAPI
+ napi_enable(&cp->napi);
+#endif
/* Make sure we don't get distracted by suspend/resume */
mutex_lock(&cp->pm_mutex);
@@ -4442,7 +4443,7 @@ static struct {
{REG_MAC_COLL_EXCESS},
{REG_MAC_COLL_LATE}
};
-#define CAS_REG_LEN (sizeof(ethtool_register_table)/sizeof(int))
+#define CAS_REG_LEN ARRAY_SIZE(ethtool_register_table)
#define CAS_MAX_REGS (sizeof (u32)*CAS_REG_LEN)
static void cas_read_regs(struct cas *cp, u8 *ptr, int len)
@@ -4771,9 +4772,14 @@ static void cas_get_regs(struct net_device *dev, struct ethtool_regs *regs,
cas_read_regs(cp, p, regs->len / sizeof(u32));
}
-static int cas_get_stats_count(struct net_device *dev)
+static int cas_get_sset_count(struct net_device *dev, int sset)
{
- return CAS_NUM_STAT_KEYS;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return CAS_NUM_STAT_KEYS;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void cas_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -4817,7 +4823,7 @@ static const struct ethtool_ops cas_ethtool_ops = {
.set_msglevel = cas_set_msglevel,
.get_regs_len = cas_get_regs_len,
.get_regs = cas_get_regs,
- .get_stats_count = cas_get_stats_count,
+ .get_sset_count = cas_get_sset_count,
.get_strings = cas_get_strings,
.get_ethtool_stats = cas_get_ethtool_stats,
};
@@ -4876,6 +4882,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
int i, err, pci_using_dac;
u16 pci_cmd;
u8 orig_cacheline_size = 0, cas_cacheline_size = 0;
+ DECLARE_MAC_BUF(mac);
if (cas_version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -4899,7 +4906,6 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
err = -ENOMEM;
goto err_out_disable_pdev;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = pci_request_regions(pdev, dev->name);
@@ -5062,8 +5068,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
dev->watchdog_timeo = CAS_TX_TIMEOUT;
dev->change_mtu = cas_change_mtu;
#ifdef USE_NAPI
- dev->poll = cas_poll;
- dev->weight = 64;
+ netif_napi_add(dev, &cp->napi, cas_poll, 64);
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = cas_netpoll;
@@ -5085,16 +5090,12 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
i = readl(cp->regs + REG_BIM_CFG);
printk(KERN_INFO "%s: Sun Cassini%s (%sbit/%sMHz PCI/%s) "
- "Ethernet[%d] ", dev->name,
+ "Ethernet[%d] %s\n", dev->name,
(cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "",
(i & BIM_CFG_32BIT) ? "32" : "64",
(i & BIM_CFG_66MHZ) ? "66" : "33",
- (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq);
-
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- i == 5 ? ' ' : ':');
- printk("\n");
+ (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq,
+ print_mac(mac, dev->dev_addr));
pci_set_drvdata(pdev, dev);
cp->hw_running = 1;
diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h
index a970804487c..2f93f83342d 100644
--- a/drivers/net/cassini.h
+++ b/drivers/net/cassini.h
@@ -4280,6 +4280,8 @@ struct cas {
int rx_cur[N_RX_COMP_RINGS], rx_new[N_RX_COMP_RINGS];
int rx_last[N_RX_DESC_RINGS];
+ struct napi_struct napi;
+
/* Set when chip is actually in operational state
* (ie. not power managed) */
int hw_running;
diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile
index 743ad8b41b5..57a4b262fd3 100644
--- a/drivers/net/chelsio/Makefile
+++ b/drivers/net/chelsio/Makefile
@@ -4,6 +4,6 @@
obj-$(CONFIG_CHELSIO_T1) += cxgb.o
-cxgb-$(CONFIG_CHELSIO_T1_1G) += mac.o mv88e1xxx.o vsc7326.o
+cxgb-$(CONFIG_CHELSIO_T1_1G) += mv88e1xxx.o vsc7326.o
cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \
mv88x201x.o my3126.o $(cxgb-y)
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 8ba702c8b56..846ca5383d3 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -278,6 +278,7 @@ struct adapter {
struct peespi *espi;
struct petp *tp;
+ struct napi_struct napi;
struct port_info port[MAX_NPORTS];
struct delayed_work stats_update_task;
struct timer_list stats_update_timer;
@@ -371,6 +372,7 @@ extern void t1_interrupts_enable(adapter_t *adapter);
extern void t1_interrupts_disable(adapter_t *adapter);
extern void t1_interrupts_clear(adapter_t *adapter);
extern int t1_elmer0_ext_intr_handler(adapter_t *adapter);
+extern void t1_elmer0_ext_intr(adapter_t *adapter);
extern int t1_slow_intr_handler(adapter_t *adapter);
extern int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index 231ce43b97c..2dbf8dc116c 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -255,8 +255,11 @@ static int cxgb_open(struct net_device *dev)
struct adapter *adapter = dev->priv;
int other_ports = adapter->open_device_map & PORT_MASK;
- if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
+ napi_enable(&adapter->napi);
+ if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) {
+ napi_disable(&adapter->napi);
return err;
+ }
__set_bit(dev->if_port, &adapter->open_device_map);
link_start(&adapter->port[dev->if_port]);
@@ -274,6 +277,7 @@ static int cxgb_close(struct net_device *dev)
struct cmac *mac = p->mac;
netif_stop_queue(dev);
+ napi_disable(&adapter->napi);
mac->ops->disable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
netif_carrier_off(dev);
@@ -435,9 +439,14 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
strcpy(info->bus_info, pci_name(adapter->pdev));
}
-static int get_stats_count(struct net_device *dev)
+static int get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(stats_strings);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(stats_strings);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -790,17 +799,14 @@ static const struct ethtool_ops t1_ethtool_ops = {
.set_pauseparam = set_pauseparam,
.get_rx_csum = get_rx_csum,
.set_rx_csum = set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_link = ethtool_op_get_link,
.get_strings = get_strings,
- .get_stats_count = get_stats_count,
+ .get_sset_count = get_sset_count,
.get_ethtool_stats = get_stats,
.get_regs_len = get_regs_len,
.get_regs = get_regs,
- .get_tso = ethtool_op_get_tso,
.set_tso = set_tso,
};
@@ -1032,7 +1038,6 @@ static int __devinit init_one(struct pci_dev *pdev,
goto out_free_dev;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
if (!adapter) {
@@ -1113,8 +1118,7 @@ static int __devinit init_one(struct pci_dev *pdev,
netdev->poll_controller = t1_netpoll;
#endif
#ifdef CONFIG_CHELSIO_T1_NAPI
- netdev->weight = 64;
- netdev->poll = t1_poll;
+ netif_napi_add(netdev, &adapter->napi, t1_poll, 64);
#endif
SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops);
diff --git a/drivers/net/chelsio/mac.c b/drivers/net/chelsio/mac.c
deleted file mode 100644
index 1d972825eac..00000000000
--- a/drivers/net/chelsio/mac.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/* $Date: 2005/10/22 00:42:59 $ $RCSfile: mac.c,v $ $Revision: 1.32 $ */
-#include "gmac.h"
-#include "regs.h"
-#include "fpga_defs.h"
-
-#define MAC_CSR_INTERFACE_GMII 0x0
-#define MAC_CSR_INTERFACE_TBI 0x1
-#define MAC_CSR_INTERFACE_MII 0x2
-#define MAC_CSR_INTERFACE_RMII 0x3
-
-/* Chelsio's MAC statistics. */
-struct mac_statistics {
-
- /* Transmit */
- u32 TxFramesTransmittedOK;
- u32 TxReserved1;
- u32 TxReserved2;
- u32 TxOctetsTransmittedOK;
- u32 TxFramesWithDeferredXmissions;
- u32 TxLateCollisions;
- u32 TxFramesAbortedDueToXSCollisions;
- u32 TxFramesLostDueToIntMACXmitError;
- u32 TxReserved3;
- u32 TxMulticastFrameXmittedOK;
- u32 TxBroadcastFramesXmittedOK;
- u32 TxFramesWithExcessiveDeferral;
- u32 TxPAUSEMACCtrlFramesTransmitted;
-
- /* Receive */
- u32 RxFramesReceivedOK;
- u32 RxFrameCheckSequenceErrors;
- u32 RxAlignmentErrors;
- u32 RxOctetsReceivedOK;
- u32 RxFramesLostDueToIntMACRcvError;
- u32 RxMulticastFramesReceivedOK;
- u32 RxBroadcastFramesReceivedOK;
- u32 RxInRangeLengthErrors;
- u32 RxTxOutOfRangeLengthField;
- u32 RxFrameTooLongErrors;
- u32 RxPAUSEMACCtrlFramesReceived;
-};
-
-static int static_aPorts[] = {
- FPGA_GMAC_INTERRUPT_PORT0,
- FPGA_GMAC_INTERRUPT_PORT1,
- FPGA_GMAC_INTERRUPT_PORT2,
- FPGA_GMAC_INTERRUPT_PORT3
-};
-
-struct _cmac_instance {
- u32 index;
-};
-
-static int mac_intr_enable(struct cmac *mac)
-{
- u32 mac_intr;
-
- if (t1_is_asic(mac->adapter)) {
- /* ASIC */
-
- /* We don't use the on chip MAC for ASIC products. */
- } else {
- /* FPGA */
-
- /* Set parent gmac interrupt. */
- mac_intr = readl(mac->adapter->regs + A_PL_ENABLE);
- mac_intr |= FPGA_PCIX_INTERRUPT_GMAC;
- writel(mac_intr, mac->adapter->regs + A_PL_ENABLE);
-
- mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
- mac_intr |= static_aPorts[mac->instance->index];
- writel(mac_intr,
- mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
- }
-
- return 0;
-}
-
-static int mac_intr_disable(struct cmac *mac)
-{
- u32 mac_intr;
-
- if (t1_is_asic(mac->adapter)) {
- /* ASIC */
-
- /* We don't use the on chip MAC for ASIC products. */
- } else {
- /* FPGA */
-
- /* Set parent gmac interrupt. */
- mac_intr = readl(mac->adapter->regs + A_PL_ENABLE);
- mac_intr &= ~FPGA_PCIX_INTERRUPT_GMAC;
- writel(mac_intr, mac->adapter->regs + A_PL_ENABLE);
-
- mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
- mac_intr &= ~(static_aPorts[mac->instance->index]);
- writel(mac_intr,
- mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
- }
-
- return 0;
-}
-
-static int mac_intr_clear(struct cmac *mac)
-{
- u32 mac_intr;
-
- if (t1_is_asic(mac->adapter)) {
- /* ASIC */
-
- /* We don't use the on chip MAC for ASIC products. */
- } else {
- /* FPGA */
-
- /* Set parent gmac interrupt. */
- writel(FPGA_PCIX_INTERRUPT_GMAC,
- mac->adapter->regs + A_PL_CAUSE);
- mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
- mac_intr |= (static_aPorts[mac->instance->index]);
- writel(mac_intr,
- mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
- }
-
- return 0;
-}
-
-static int mac_get_address(struct cmac *mac, u8 addr[6])
-{
- u32 data32_lo, data32_hi;
-
- data32_lo = readl(mac->adapter->regs
- + MAC_REG_IDLO(mac->instance->index));
- data32_hi = readl(mac->adapter->regs
- + MAC_REG_IDHI(mac->instance->index));
-
- addr[0] = (u8) ((data32_hi >> 8) & 0xFF);
- addr[1] = (u8) ((data32_hi) & 0xFF);
- addr[2] = (u8) ((data32_lo >> 24) & 0xFF);
- addr[3] = (u8) ((data32_lo >> 16) & 0xFF);
- addr[4] = (u8) ((data32_lo >> 8) & 0xFF);
- addr[5] = (u8) ((data32_lo) & 0xFF);
- return 0;
-}
-
-static int mac_reset(struct cmac *mac)
-{
- u32 data32;
- int mac_in_reset, time_out = 100;
- int idx = mac->instance->index;
-
- data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx));
- writel(data32 | F_MAC_RESET,
- mac->adapter->regs + MAC_REG_CSR(idx));
-
- do {
- data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx));
-
- mac_in_reset = data32 & F_MAC_RESET;
- if (mac_in_reset)
- udelay(1);
- } while (mac_in_reset && --time_out);
-
- if (mac_in_reset) {
- CH_ERR("%s: MAC %d reset timed out\n",
- mac->adapter->name, idx);
- return 2;
- }
-
- return 0;
-}
-
-static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
-{
- u32 val;
-
- val = readl(mac->adapter->regs
- + MAC_REG_CSR(mac->instance->index));
- val &= ~(F_MAC_PROMISC | F_MAC_MC_ENABLE);
- val |= V_MAC_PROMISC(t1_rx_mode_promisc(rm) != 0);
- val |= V_MAC_MC_ENABLE(t1_rx_mode_allmulti(rm) != 0);
- writel(val,
- mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
-
- return 0;
-}
-
-static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
- int fc)
-{
- u32 data32;
-
- data32 = readl(mac->adapter->regs
- + MAC_REG_CSR(mac->instance->index));
- data32 &= ~(F_MAC_HALF_DUPLEX | V_MAC_SPEED(M_MAC_SPEED) |
- V_INTERFACE(M_INTERFACE) | F_MAC_TX_PAUSE_ENABLE |
- F_MAC_RX_PAUSE_ENABLE);
-
- switch (speed) {
- case SPEED_10:
- case SPEED_100:
- data32 |= V_INTERFACE(MAC_CSR_INTERFACE_MII);
- data32 |= V_MAC_SPEED(speed == SPEED_10 ? 0 : 1);
- break;
- case SPEED_1000:
- data32 |= V_INTERFACE(MAC_CSR_INTERFACE_GMII);
- data32 |= V_MAC_SPEED(2);
- break;
- }
-
- if (duplex >= 0)
- data32 |= V_MAC_HALF_DUPLEX(duplex == DUPLEX_HALF);
-
- if (fc >= 0) {
- data32 |= V_MAC_RX_PAUSE_ENABLE((fc & PAUSE_RX) != 0);
- data32 |= V_MAC_TX_PAUSE_ENABLE((fc & PAUSE_TX) != 0);
- }
-
- writel(data32,
- mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
- return 0;
-}
-
-static int mac_enable(struct cmac *mac, int which)
-{
- u32 val;
-
- val = readl(mac->adapter->regs
- + MAC_REG_CSR(mac->instance->index));
- if (which & MAC_DIRECTION_RX)
- val |= F_MAC_RX_ENABLE;
- if (which & MAC_DIRECTION_TX)
- val |= F_MAC_TX_ENABLE;
- writel(val,
- mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
- return 0;
-}
-
-static int mac_disable(struct cmac *mac, int which)
-{
- u32 val;
-
- val = readl(mac->adapter->regs
- + MAC_REG_CSR(mac->instance->index));
- if (which & MAC_DIRECTION_RX)
- val &= ~F_MAC_RX_ENABLE;
- if (which & MAC_DIRECTION_TX)
- val &= ~F_MAC_TX_ENABLE;
- writel(val,
- mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
- return 0;
-}
-
-#if 0
-static int mac_set_ifs(struct cmac *mac, u32 mode)
-{
- t1_write_reg_4(mac->adapter,
- MAC_REG_IFS(mac->instance->index),
- mode);
- return 0;
-}
-
-static int mac_enable_isl(struct cmac *mac)
-{
- u32 data32 = readl(mac->adapter->regs
- + MAC_REG_CSR(mac->instance->index));
- data32 |= F_MAC_RX_ENABLE | F_MAC_TX_ENABLE;
- t1_write_reg_4(mac->adapter,
- MAC_REG_CSR(mac->instance->index),
- data32);
- return 0;
-}
-#endif
-
-static int mac_set_mtu(struct cmac *mac, int mtu)
-{
- if (mtu > 9600)
- return -EINVAL;
- writel(mtu + ETH_HLEN + VLAN_HLEN,
- mac->adapter->regs + MAC_REG_LARGEFRAMELENGTH(mac->instance->index));
-
- return 0;
-}
-
-static const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
- int flag)
-{
- struct mac_statistics st;
- u32 *p = (u32 *) & st, i;
-
- writel(0,
- mac->adapter->regs + MAC_REG_RMCNT(mac->instance->index));
-
- for (i = 0; i < sizeof(st) / sizeof(u32); i++)
- *p++ = readl(mac->adapter->regs
- + MAC_REG_RMDATA(mac->instance->index));
-
- /* XXX convert stats */
- return &mac->stats;
-}
-
-static void mac_destroy(struct cmac *mac)
-{
- kfree(mac);
-}
-
-static struct cmac_ops chelsio_mac_ops = {
- .destroy = mac_destroy,
- .reset = mac_reset,
- .interrupt_enable = mac_intr_enable,
- .interrupt_disable = mac_intr_disable,
- .interrupt_clear = mac_intr_clear,
- .enable = mac_enable,
- .disable = mac_disable,
- .set_mtu = mac_set_mtu,
- .set_rx_mode = mac_set_rx_mode,
- .set_speed_duplex_fc = mac_set_speed_duplex_fc,
- .macaddress_get = mac_get_address,
- .statistics_update = mac_update_statistics,
-};
-
-static struct cmac *mac_create(adapter_t *adapter, int index)
-{
- struct cmac *mac;
- u32 data32;
-
- if (index >= 4)
- return NULL;
-
- mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
- if (!mac)
- return NULL;
-
- mac->ops = &chelsio_mac_ops;
- mac->instance = (cmac_instance *) (mac + 1);
-
- mac->instance->index = index;
- mac->adapter = adapter;
-
- data32 = readl(adapter->regs + MAC_REG_CSR(mac->instance->index));
- data32 &= ~(F_MAC_RESET | F_MAC_PROMISC | F_MAC_PROMISC |
- F_MAC_LB_ENABLE | F_MAC_RX_ENABLE | F_MAC_TX_ENABLE);
- data32 |= F_MAC_JUMBO_ENABLE;
- writel(data32, adapter->regs + MAC_REG_CSR(mac->instance->index));
-
- /* Initialize the random backoff seed. */
- data32 = 0x55aa + (3 * index);
- writel(data32,
- adapter->regs + MAC_REG_GMRANDBACKOFFSEED(mac->instance->index));
-
- /* Check to see if the mac address needs to be set manually. */
- data32 = readl(adapter->regs + MAC_REG_IDLO(mac->instance->index));
- if (data32 == 0 || data32 == 0xffffffff) {
- /*
- * Add a default MAC address if we can't read one.
- */
- writel(0x43FFFFFF - index,
- adapter->regs + MAC_REG_IDLO(mac->instance->index));
- writel(0x0007,
- adapter->regs + MAC_REG_IDHI(mac->instance->index));
- }
-
- (void) mac_set_mtu(mac, 1500);
- return mac;
-}
-
-const struct gmac t1_chelsio_mac_ops = {
- .create = mac_create
-};
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index e4f874a70fe..443666292a5 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -1379,11 +1379,11 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
}
__skb_pull(skb, sizeof(*p));
- skb->dev->last_rx = jiffies;
st = per_cpu_ptr(sge->port_stats[p->iff], smp_processor_id());
st->rx_packets++;
skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev);
+ skb->dev->last_rx = jiffies;
if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff &&
skb->protocol == htons(ETH_P_IP) &&
(skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) {
@@ -1620,23 +1620,20 @@ static int process_pure_responses(struct adapter *adapter)
* or protection from interrupts as data interrupts are off at this point and
* other adapter interrupts do not interfere.
*/
-int t1_poll(struct net_device *dev, int *budget)
+int t1_poll(struct napi_struct *napi, int budget)
{
- struct adapter *adapter = dev->priv;
+ struct adapter *adapter = container_of(napi, struct adapter, napi);
+ struct net_device *dev = adapter->port[0].dev;
int work_done;
- work_done = process_responses(adapter, min(*budget, dev->quota));
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (unlikely(responses_pending(adapter)))
- return 1;
-
- netif_rx_complete(dev);
- writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
-
- return 0;
+ work_done = process_responses(adapter, budget);
+ if (likely(!responses_pending(adapter))) {
+ netif_rx_complete(dev, napi);
+ writel(adapter->sge->respQ.cidx,
+ adapter->regs + A_SG_SLEEPING);
+ }
+ return work_done;
}
/*
@@ -1653,13 +1650,13 @@ irqreturn_t t1_interrupt(int irq, void *data)
writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
- if (__netif_rx_schedule_prep(dev)) {
+ if (napi_schedule_prep(&adapter->napi)) {
if (process_pure_responses(adapter))
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &adapter->napi);
else {
/* no data, no NAPI needed */
writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
- netif_poll_enable(dev); /* undo schedule_prep */
+ napi_enable(&adapter->napi); /* undo schedule_prep */
}
}
return IRQ_HANDLED;
diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h
index d132a0ef2a2..713d9c55f24 100644
--- a/drivers/net/chelsio/sge.h
+++ b/drivers/net/chelsio/sge.h
@@ -77,7 +77,7 @@ int t1_sge_configure(struct sge *, struct sge_params *);
int t1_sge_set_coalesce_params(struct sge *, struct sge_params *);
void t1_sge_destroy(struct sge *);
irqreturn_t t1_interrupt(int irq, void *cookie);
-int t1_poll(struct net_device *, int *);
+int t1_poll(struct napi_struct *, int);
int t1_start_xmit(struct sk_buff *skb, struct net_device *dev);
void t1_set_vlan_accel(struct adapter *adapter, int on_off);
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index 7de9a611e1f..dc50151bed8 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -884,7 +884,7 @@ static int asic_slow_intr(adapter_t *adapter)
if (cause & F_PL_INTR_PCIX)
t1_pci_intr_handler(adapter);
if (cause & F_PL_INTR_EXT)
- t1_elmer0_ext_intr_handler(adapter);
+ t1_elmer0_ext_intr(adapter);
/* Clear the interrupts just processed. */
writel(cause, adapter->regs + A_PL_CAUSE);
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c
new file mode 100644
index 00000000000..6fd95a2c8ce
--- /dev/null
+++ b/drivers/net/cpmac.c
@@ -0,0 +1,1196 @@
+/*
+ * Copyright (C) 2006, 2007 Eugene Konev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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/moduleparam.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <asm/gpio.h>
+
+MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>");
+MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)");
+MODULE_LICENSE("GPL");
+
+static int debug_level = 8;
+static int dumb_switch;
+
+/* Next 2 are only used in cpmac_probe, so it's pointless to change them */
+module_param(debug_level, int, 0444);
+module_param(dumb_switch, int, 0444);
+
+MODULE_PARM_DESC(debug_level, "Number of NETIF_MSG bits to enable");
+MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus");
+
+#define CPMAC_VERSION "0.5.0"
+/* frame size + 802.1q tag */
+#define CPMAC_SKB_SIZE (ETH_FRAME_LEN + 4)
+#define CPMAC_QUEUES 8
+
+/* Ethernet registers */
+#define CPMAC_TX_CONTROL 0x0004
+#define CPMAC_TX_TEARDOWN 0x0008
+#define CPMAC_RX_CONTROL 0x0014
+#define CPMAC_RX_TEARDOWN 0x0018
+#define CPMAC_MBP 0x0100
+# define MBP_RXPASSCRC 0x40000000
+# define MBP_RXQOS 0x20000000
+# define MBP_RXNOCHAIN 0x10000000
+# define MBP_RXCMF 0x01000000
+# define MBP_RXSHORT 0x00800000
+# define MBP_RXCEF 0x00400000
+# define MBP_RXPROMISC 0x00200000
+# define MBP_PROMISCCHAN(channel) (((channel) & 0x7) << 16)
+# define MBP_RXBCAST 0x00002000
+# define MBP_BCASTCHAN(channel) (((channel) & 0x7) << 8)
+# define MBP_RXMCAST 0x00000020
+# define MBP_MCASTCHAN(channel) ((channel) & 0x7)
+#define CPMAC_UNICAST_ENABLE 0x0104
+#define CPMAC_UNICAST_CLEAR 0x0108
+#define CPMAC_MAX_LENGTH 0x010c
+#define CPMAC_BUFFER_OFFSET 0x0110
+#define CPMAC_MAC_CONTROL 0x0160
+# define MAC_TXPTYPE 0x00000200
+# define MAC_TXPACE 0x00000040
+# define MAC_MII 0x00000020
+# define MAC_TXFLOW 0x00000010
+# define MAC_RXFLOW 0x00000008
+# define MAC_MTEST 0x00000004
+# define MAC_LOOPBACK 0x00000002
+# define MAC_FDX 0x00000001
+#define CPMAC_MAC_STATUS 0x0164
+# define MAC_STATUS_QOS 0x00000004
+# define MAC_STATUS_RXFLOW 0x00000002
+# define MAC_STATUS_TXFLOW 0x00000001
+#define CPMAC_TX_INT_ENABLE 0x0178
+#define CPMAC_TX_INT_CLEAR 0x017c
+#define CPMAC_MAC_INT_VECTOR 0x0180
+# define MAC_INT_STATUS 0x00080000
+# define MAC_INT_HOST 0x00040000
+# define MAC_INT_RX 0x00020000
+# define MAC_INT_TX 0x00010000
+#define CPMAC_MAC_EOI_VECTOR 0x0184
+#define CPMAC_RX_INT_ENABLE 0x0198
+#define CPMAC_RX_INT_CLEAR 0x019c
+#define CPMAC_MAC_INT_ENABLE 0x01a8
+#define CPMAC_MAC_INT_CLEAR 0x01ac
+#define CPMAC_MAC_ADDR_LO(channel) (0x01b0 + (channel) * 4)
+#define CPMAC_MAC_ADDR_MID 0x01d0
+#define CPMAC_MAC_ADDR_HI 0x01d4
+#define CPMAC_MAC_HASH_LO 0x01d8
+#define CPMAC_MAC_HASH_HI 0x01dc
+#define CPMAC_TX_PTR(channel) (0x0600 + (channel) * 4)
+#define CPMAC_RX_PTR(channel) (0x0620 + (channel) * 4)
+#define CPMAC_TX_ACK(channel) (0x0640 + (channel) * 4)
+#define CPMAC_RX_ACK(channel) (0x0660 + (channel) * 4)
+#define CPMAC_REG_END 0x0680
+/*
+ * Rx/Tx statistics
+ * TODO: use some of them to fill stats in cpmac_stats()
+ */
+#define CPMAC_STATS_RX_GOOD 0x0200
+#define CPMAC_STATS_RX_BCAST 0x0204
+#define CPMAC_STATS_RX_MCAST 0x0208
+#define CPMAC_STATS_RX_PAUSE 0x020c
+#define CPMAC_STATS_RX_CRC 0x0210
+#define CPMAC_STATS_RX_ALIGN 0x0214
+#define CPMAC_STATS_RX_OVER 0x0218
+#define CPMAC_STATS_RX_JABBER 0x021c
+#define CPMAC_STATS_RX_UNDER 0x0220
+#define CPMAC_STATS_RX_FRAG 0x0224
+#define CPMAC_STATS_RX_FILTER 0x0228
+#define CPMAC_STATS_RX_QOSFILTER 0x022c
+#define CPMAC_STATS_RX_OCTETS 0x0230
+
+#define CPMAC_STATS_TX_GOOD 0x0234
+#define CPMAC_STATS_TX_BCAST 0x0238
+#define CPMAC_STATS_TX_MCAST 0x023c
+#define CPMAC_STATS_TX_PAUSE 0x0240
+#define CPMAC_STATS_TX_DEFER 0x0244
+#define CPMAC_STATS_TX_COLLISION 0x0248
+#define CPMAC_STATS_TX_SINGLECOLL 0x024c
+#define CPMAC_STATS_TX_MULTICOLL 0x0250
+#define CPMAC_STATS_TX_EXCESSCOLL 0x0254
+#define CPMAC_STATS_TX_LATECOLL 0x0258
+#define CPMAC_STATS_TX_UNDERRUN 0x025c
+#define CPMAC_STATS_TX_CARRIERSENSE 0x0260
+#define CPMAC_STATS_TX_OCTETS 0x0264
+
+#define cpmac_read(base, reg) (readl((void __iomem *)(base) + (reg)))
+#define cpmac_write(base, reg, val) (writel(val, (void __iomem *)(base) + \
+ (reg)))
+
+/* MDIO bus */
+#define CPMAC_MDIO_VERSION 0x0000
+#define CPMAC_MDIO_CONTROL 0x0004
+# define MDIOC_IDLE 0x80000000
+# define MDIOC_ENABLE 0x40000000
+# define MDIOC_PREAMBLE 0x00100000
+# define MDIOC_FAULT 0x00080000
+# define MDIOC_FAULTDETECT 0x00040000
+# define MDIOC_INTTEST 0x00020000
+# define MDIOC_CLKDIV(div) ((div) & 0xff)
+#define CPMAC_MDIO_ALIVE 0x0008
+#define CPMAC_MDIO_LINK 0x000c
+#define CPMAC_MDIO_ACCESS(channel) (0x0080 + (channel) * 8)
+# define MDIO_BUSY 0x80000000
+# define MDIO_WRITE 0x40000000
+# define MDIO_REG(reg) (((reg) & 0x1f) << 21)
+# define MDIO_PHY(phy) (((phy) & 0x1f) << 16)
+# define MDIO_DATA(data) ((data) & 0xffff)
+#define CPMAC_MDIO_PHYSEL(channel) (0x0084 + (channel) * 8)
+# define PHYSEL_LINKSEL 0x00000040
+# define PHYSEL_LINKINT 0x00000020
+
+struct cpmac_desc {
+ u32 hw_next;
+ u32 hw_data;
+ u16 buflen;
+ u16 bufflags;
+ u16 datalen;
+ u16 dataflags;
+#define CPMAC_SOP 0x8000
+#define CPMAC_EOP 0x4000
+#define CPMAC_OWN 0x2000
+#define CPMAC_EOQ 0x1000
+ struct sk_buff *skb;
+ struct cpmac_desc *next;
+ dma_addr_t mapping;
+ dma_addr_t data_mapping;
+};
+
+struct cpmac_priv {
+ spinlock_t lock;
+ spinlock_t rx_lock;
+ struct cpmac_desc *rx_head;
+ int ring_size;
+ struct cpmac_desc *desc_ring;
+ dma_addr_t dma_ring;
+ void __iomem *regs;
+ struct mii_bus *mii_bus;
+ struct phy_device *phy;
+ char phy_name[BUS_ID_SIZE];
+ int oldlink, oldspeed, oldduplex;
+ u32 msg_enable;
+ struct net_device *dev;
+ struct work_struct reset_work;
+ struct platform_device *pdev;
+ struct napi_struct napi;
+};
+
+static irqreturn_t cpmac_irq(int, void *);
+static void cpmac_hw_start(struct net_device *dev);
+static void cpmac_hw_stop(struct net_device *dev);
+static int cpmac_stop(struct net_device *dev);
+static int cpmac_open(struct net_device *dev);
+
+static void cpmac_dump_regs(struct net_device *dev)
+{
+ int i;
+ struct cpmac_priv *priv = netdev_priv(dev);
+ for (i = 0; i < CPMAC_REG_END; i += 4) {
+ if (i % 16 == 0) {
+ if (i)
+ printk("\n");
+ printk(KERN_DEBUG "%s: reg[%p]:", dev->name,
+ priv->regs + i);
+ }
+ printk(" %08x", cpmac_read(priv->regs, i));
+ }
+ printk("\n");
+}
+
+static void cpmac_dump_desc(struct net_device *dev, struct cpmac_desc *desc)
+{
+ int i;
+ printk(KERN_DEBUG "%s: desc[%p]:", dev->name, desc);
+ for (i = 0; i < sizeof(*desc) / 4; i++)
+ printk(" %08x", ((u32 *)desc)[i]);
+ printk("\n");
+}
+
+static void cpmac_dump_skb(struct net_device *dev, struct sk_buff *skb)
+{
+ int i;
+ printk(KERN_DEBUG "%s: skb 0x%p, len=%d\n", dev->name, skb, skb->len);
+ for (i = 0; i < skb->len; i++) {
+ if (i % 16 == 0) {
+ if (i)
+ printk("\n");
+ printk(KERN_DEBUG "%s: data[%p]:", dev->name,
+ skb->data + i);
+ }
+ printk(" %02x", ((u8 *)skb->data)[i]);
+ }
+ printk("\n");
+}
+
+static int cpmac_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+ u32 val;
+
+ while (cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0)) & MDIO_BUSY)
+ cpu_relax();
+ cpmac_write(bus->priv, CPMAC_MDIO_ACCESS(0), MDIO_BUSY | MDIO_REG(reg) |
+ MDIO_PHY(phy_id));
+ while ((val = cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0))) & MDIO_BUSY)
+ cpu_relax();
+ return MDIO_DATA(val);
+}
+
+static int cpmac_mdio_write(struct mii_bus *bus, int phy_id,
+ int reg, u16 val)
+{
+ while (cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0)) & MDIO_BUSY)
+ cpu_relax();
+ cpmac_write(bus->priv, CPMAC_MDIO_ACCESS(0), MDIO_BUSY | MDIO_WRITE |
+ MDIO_REG(reg) | MDIO_PHY(phy_id) | MDIO_DATA(val));
+ return 0;
+}
+
+static int cpmac_mdio_reset(struct mii_bus *bus)
+{
+ ar7_device_reset(AR7_RESET_BIT_MDIO);
+ cpmac_write(bus->priv, CPMAC_MDIO_CONTROL, MDIOC_ENABLE |
+ MDIOC_CLKDIV(ar7_cpmac_freq() / 2200000 - 1));
+ return 0;
+}
+
+static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, };
+
+static struct mii_bus cpmac_mii = {
+ .name = "cpmac-mii",
+ .read = cpmac_mdio_read,
+ .write = cpmac_mdio_write,
+ .reset = cpmac_mdio_reset,
+ .irq = mii_irqs,
+};
+
+static int cpmac_config(struct net_device *dev, struct ifmap *map)
+{
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+
+ /* Don't allow changing the I/O address */
+ if (map->base_addr != dev->base_addr)
+ return -EOPNOTSUPP;
+
+ /* ignore other fields */
+ return 0;
+}
+
+static void cpmac_set_multicast_list(struct net_device *dev)
+{
+ struct dev_mc_list *iter;
+ int i;
+ u8 tmp;
+ u32 mbp, bit, hash[2] = { 0, };
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ mbp = cpmac_read(priv->regs, CPMAC_MBP);
+ if (dev->flags & IFF_PROMISC) {
+ cpmac_write(priv->regs, CPMAC_MBP, (mbp & ~MBP_PROMISCCHAN(0)) |
+ MBP_RXPROMISC);
+ } else {
+ cpmac_write(priv->regs, CPMAC_MBP, mbp & ~MBP_RXPROMISC);
+ if (dev->flags & IFF_ALLMULTI) {
+ /* enable all multicast mode */
+ cpmac_write(priv->regs, CPMAC_MAC_HASH_LO, 0xffffffff);
+ cpmac_write(priv->regs, CPMAC_MAC_HASH_HI, 0xffffffff);
+ } else {
+ /*
+ * cpmac uses some strange mac address hashing
+ * (not crc32)
+ */
+ for (i = 0, iter = dev->mc_list; i < dev->mc_count;
+ i++, iter = iter->next) {
+ bit = 0;
+ tmp = iter->dmi_addr[0];
+ bit ^= (tmp >> 2) ^ (tmp << 4);
+ tmp = iter->dmi_addr[1];
+ bit ^= (tmp >> 4) ^ (tmp << 2);
+ tmp = iter->dmi_addr[2];
+ bit ^= (tmp >> 6) ^ tmp;
+ tmp = iter->dmi_addr[3];
+ bit ^= (tmp >> 2) ^ (tmp << 4);
+ tmp = iter->dmi_addr[4];
+ bit ^= (tmp >> 4) ^ (tmp << 2);
+ tmp = iter->dmi_addr[5];
+ bit ^= (tmp >> 6) ^ tmp;
+ bit &= 0x3f;
+ hash[bit / 32] |= 1 << (bit % 32);
+ }
+
+ cpmac_write(priv->regs, CPMAC_MAC_HASH_LO, hash[0]);
+ cpmac_write(priv->regs, CPMAC_MAC_HASH_HI, hash[1]);
+ }
+ }
+}
+
+static struct sk_buff *cpmac_rx_one(struct cpmac_priv *priv,
+ struct cpmac_desc *desc)
+{
+ struct sk_buff *skb, *result = NULL;
+
+ if (unlikely(netif_msg_hw(priv)))
+ cpmac_dump_desc(priv->dev, desc);
+ cpmac_write(priv->regs, CPMAC_RX_ACK(0), (u32)desc->mapping);
+ if (unlikely(!desc->datalen)) {
+ if (netif_msg_rx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING "%s: rx: spurious interrupt\n",
+ priv->dev->name);
+ return NULL;
+ }
+
+ skb = netdev_alloc_skb(priv->dev, CPMAC_SKB_SIZE);
+ if (likely(skb)) {
+ skb_reserve(skb, 2);
+ skb_put(desc->skb, desc->datalen);
+ desc->skb->protocol = eth_type_trans(desc->skb, priv->dev);
+ desc->skb->ip_summed = CHECKSUM_NONE;
+ priv->dev->stats.rx_packets++;
+ priv->dev->stats.rx_bytes += desc->datalen;
+ result = desc->skb;
+ dma_unmap_single(&priv->dev->dev, desc->data_mapping,
+ CPMAC_SKB_SIZE, DMA_FROM_DEVICE);
+ desc->skb = skb;
+ desc->data_mapping = dma_map_single(&priv->dev->dev, skb->data,
+ CPMAC_SKB_SIZE,
+ DMA_FROM_DEVICE);
+ desc->hw_data = (u32)desc->data_mapping;
+ if (unlikely(netif_msg_pktdata(priv))) {
+ printk(KERN_DEBUG "%s: received packet:\n",
+ priv->dev->name);
+ cpmac_dump_skb(priv->dev, result);
+ }
+ } else {
+ if (netif_msg_rx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING
+ "%s: low on skbs, dropping packet\n",
+ priv->dev->name);
+ priv->dev->stats.rx_dropped++;
+ }
+
+ desc->buflen = CPMAC_SKB_SIZE;
+ desc->dataflags = CPMAC_OWN;
+
+ return result;
+}
+
+static int cpmac_poll(struct napi_struct *napi, int budget)
+{
+ struct sk_buff *skb;
+ struct cpmac_desc *desc;
+ int received = 0;
+ struct cpmac_priv *priv = container_of(napi, struct cpmac_priv, napi);
+
+ spin_lock(&priv->rx_lock);
+ if (unlikely(!priv->rx_head)) {
+ if (netif_msg_rx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING "%s: rx: polling, but no queue\n",
+ priv->dev->name);
+ netif_rx_complete(priv->dev, napi);
+ return 0;
+ }
+
+ desc = priv->rx_head;
+ while (((desc->dataflags & CPMAC_OWN) == 0) && (received < budget)) {
+ skb = cpmac_rx_one(priv, desc);
+ if (likely(skb)) {
+ netif_receive_skb(skb);
+ received++;
+ }
+ desc = desc->next;
+ }
+
+ priv->rx_head = desc;
+ spin_unlock(&priv->rx_lock);
+ if (unlikely(netif_msg_rx_status(priv)))
+ printk(KERN_DEBUG "%s: poll processed %d packets\n",
+ priv->dev->name, received);
+ if (desc->dataflags & CPMAC_OWN) {
+ netif_rx_complete(priv->dev, napi);
+ cpmac_write(priv->regs, CPMAC_RX_PTR(0), (u32)desc->mapping);
+ cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ int queue, len;
+ struct cpmac_desc *desc;
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ if (unlikely(skb_padto(skb, ETH_ZLEN)))
+ return NETDEV_TX_OK;
+
+ len = max(skb->len, ETH_ZLEN);
+ queue = skb->queue_mapping;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ netif_stop_subqueue(dev, queue);
+#else
+ netif_stop_queue(dev);
+#endif
+
+ desc = &priv->desc_ring[queue];
+ if (unlikely(desc->dataflags & CPMAC_OWN)) {
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING "%s: tx dma ring full\n",
+ dev->name);
+ return NETDEV_TX_BUSY;
+ }
+
+ spin_lock(&priv->lock);
+ dev->trans_start = jiffies;
+ spin_unlock(&priv->lock);
+ desc->dataflags = CPMAC_SOP | CPMAC_EOP | CPMAC_OWN;
+ desc->skb = skb;
+ desc->data_mapping = dma_map_single(&dev->dev, skb->data, len,
+ DMA_TO_DEVICE);
+ desc->hw_data = (u32)desc->data_mapping;
+ desc->datalen = len;
+ desc->buflen = len;
+ if (unlikely(netif_msg_tx_queued(priv)))
+ printk(KERN_DEBUG "%s: sending 0x%p, len=%d\n", dev->name, skb,
+ skb->len);
+ if (unlikely(netif_msg_hw(priv)))
+ cpmac_dump_desc(dev, desc);
+ if (unlikely(netif_msg_pktdata(priv)))
+ cpmac_dump_skb(dev, skb);
+ cpmac_write(priv->regs, CPMAC_TX_PTR(queue), (u32)desc->mapping);
+
+ return NETDEV_TX_OK;
+}
+
+static void cpmac_end_xmit(struct net_device *dev, int queue)
+{
+ struct cpmac_desc *desc;
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ desc = &priv->desc_ring[queue];
+ cpmac_write(priv->regs, CPMAC_TX_ACK(queue), (u32)desc->mapping);
+ if (likely(desc->skb)) {
+ spin_lock(&priv->lock);
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += desc->skb->len;
+ spin_unlock(&priv->lock);
+ dma_unmap_single(&dev->dev, desc->data_mapping, desc->skb->len,
+ DMA_TO_DEVICE);
+
+ if (unlikely(netif_msg_tx_done(priv)))
+ printk(KERN_DEBUG "%s: sent 0x%p, len=%d\n", dev->name,
+ desc->skb, desc->skb->len);
+
+ dev_kfree_skb_irq(desc->skb);
+ desc->skb = NULL;
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (netif_subqueue_stopped(dev, queue))
+ netif_wake_subqueue(dev, queue);
+#else
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+#endif
+ } else {
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING
+ "%s: end_xmit: spurious interrupt\n", dev->name);
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ if (netif_subqueue_stopped(dev, queue))
+ netif_wake_subqueue(dev, queue);
+#else
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+#endif
+ }
+}
+
+static void cpmac_hw_stop(struct net_device *dev)
+{
+ int i;
+ struct cpmac_priv *priv = netdev_priv(dev);
+ struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data;
+
+ ar7_device_reset(pdata->reset_bit);
+ cpmac_write(priv->regs, CPMAC_RX_CONTROL,
+ cpmac_read(priv->regs, CPMAC_RX_CONTROL) & ~1);
+ cpmac_write(priv->regs, CPMAC_TX_CONTROL,
+ cpmac_read(priv->regs, CPMAC_TX_CONTROL) & ~1);
+ for (i = 0; i < 8; i++) {
+ cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0);
+ cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0);
+ }
+ cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_MAC_CONTROL,
+ cpmac_read(priv->regs, CPMAC_MAC_CONTROL) & ~MAC_MII);
+}
+
+static void cpmac_hw_start(struct net_device *dev)
+{
+ int i;
+ struct cpmac_priv *priv = netdev_priv(dev);
+ struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data;
+
+ ar7_device_reset(pdata->reset_bit);
+ for (i = 0; i < 8; i++) {
+ cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0);
+ cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0);
+ }
+ cpmac_write(priv->regs, CPMAC_RX_PTR(0), priv->rx_head->mapping);
+
+ cpmac_write(priv->regs, CPMAC_MBP, MBP_RXSHORT | MBP_RXBCAST |
+ MBP_RXMCAST);
+ cpmac_write(priv->regs, CPMAC_BUFFER_OFFSET, 0);
+ for (i = 0; i < 8; i++)
+ cpmac_write(priv->regs, CPMAC_MAC_ADDR_LO(i), dev->dev_addr[5]);
+ cpmac_write(priv->regs, CPMAC_MAC_ADDR_MID, dev->dev_addr[4]);
+ cpmac_write(priv->regs, CPMAC_MAC_ADDR_HI, dev->dev_addr[0] |
+ (dev->dev_addr[1] << 8) | (dev->dev_addr[2] << 16) |
+ (dev->dev_addr[3] << 24));
+ cpmac_write(priv->regs, CPMAC_MAX_LENGTH, CPMAC_SKB_SIZE);
+ cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff);
+ cpmac_write(priv->regs, CPMAC_UNICAST_ENABLE, 1);
+ cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1);
+ cpmac_write(priv->regs, CPMAC_TX_INT_ENABLE, 0xff);
+ cpmac_write(priv->regs, CPMAC_MAC_INT_ENABLE, 3);
+
+ cpmac_write(priv->regs, CPMAC_RX_CONTROL,
+ cpmac_read(priv->regs, CPMAC_RX_CONTROL) | 1);
+ cpmac_write(priv->regs, CPMAC_TX_CONTROL,
+ cpmac_read(priv->regs, CPMAC_TX_CONTROL) | 1);
+ cpmac_write(priv->regs, CPMAC_MAC_CONTROL,
+ cpmac_read(priv->regs, CPMAC_MAC_CONTROL) | MAC_MII |
+ MAC_FDX);
+}
+
+static void cpmac_clear_rx(struct net_device *dev)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+ struct cpmac_desc *desc;
+ int i;
+ if (unlikely(!priv->rx_head))
+ return;
+ desc = priv->rx_head;
+ for (i = 0; i < priv->ring_size; i++) {
+ if ((desc->dataflags & CPMAC_OWN) == 0) {
+ if (netif_msg_rx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING "%s: packet dropped\n",
+ dev->name);
+ if (unlikely(netif_msg_hw(priv)))
+ cpmac_dump_desc(dev, desc);
+ desc->dataflags = CPMAC_OWN;
+ dev->stats.rx_dropped++;
+ }
+ desc = desc->next;
+ }
+}
+
+static void cpmac_clear_tx(struct net_device *dev)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+ int i;
+ if (unlikely(!priv->desc_ring))
+ return;
+ for (i = 0; i < CPMAC_QUEUES; i++) {
+ priv->desc_ring[i].dataflags = 0;
+ if (priv->desc_ring[i].skb) {
+ dev_kfree_skb_any(priv->desc_ring[i].skb);
+ if (netif_subqueue_stopped(dev, i))
+ netif_wake_subqueue(dev, i);
+ }
+ }
+}
+
+static void cpmac_hw_error(struct work_struct *work)
+{
+ struct cpmac_priv *priv =
+ container_of(work, struct cpmac_priv, reset_work);
+
+ spin_lock(&priv->rx_lock);
+ cpmac_clear_rx(priv->dev);
+ spin_unlock(&priv->rx_lock);
+ cpmac_clear_tx(priv->dev);
+ cpmac_hw_start(priv->dev);
+ napi_enable(&priv->napi);
+ netif_start_queue(priv->dev);
+}
+
+static irqreturn_t cpmac_irq(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct cpmac_priv *priv;
+ int queue;
+ u32 status;
+
+ if (!dev)
+ return IRQ_NONE;
+
+ priv = netdev_priv(dev);
+
+ status = cpmac_read(priv->regs, CPMAC_MAC_INT_VECTOR);
+
+ if (unlikely(netif_msg_intr(priv)))
+ printk(KERN_DEBUG "%s: interrupt status: 0x%08x\n", dev->name,
+ status);
+
+ if (status & MAC_INT_TX)
+ cpmac_end_xmit(dev, (status & 7));
+
+ if (status & MAC_INT_RX) {
+ queue = (status >> 8) & 7;
+ if (netif_rx_schedule_prep(dev, &priv->napi)) {
+ cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 1 << queue);
+ __netif_rx_schedule(dev, &priv->napi);
+ }
+ }
+
+ cpmac_write(priv->regs, CPMAC_MAC_EOI_VECTOR, 0);
+
+ if (unlikely(status & (MAC_INT_HOST | MAC_INT_STATUS))) {
+ if (netif_msg_drv(priv) && net_ratelimit())
+ printk(KERN_ERR "%s: hw error, resetting...\n",
+ dev->name);
+ netif_stop_queue(dev);
+ napi_disable(&priv->napi);
+ cpmac_hw_stop(dev);
+ schedule_work(&priv->reset_work);
+ if (unlikely(netif_msg_hw(priv)))
+ cpmac_dump_regs(dev);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void cpmac_tx_timeout(struct net_device *dev)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+ int i;
+
+ spin_lock(&priv->lock);
+ dev->stats.tx_errors++;
+ spin_unlock(&priv->lock);
+ if (netif_msg_tx_err(priv) && net_ratelimit())
+ printk(KERN_WARNING "%s: transmit timeout\n", dev->name);
+ /*
+ * FIXME: waking up random queue is not the best thing to
+ * do... on the other hand why we got here at all?
+ */
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ for (i = 0; i < CPMAC_QUEUES; i++)
+ if (priv->desc_ring[i].skb) {
+ priv->desc_ring[i].dataflags = 0;
+ dev_kfree_skb_any(priv->desc_ring[i].skb);
+ netif_wake_subqueue(dev, i);
+ break;
+ }
+#else
+ priv->desc_ring[0].dataflags = 0;
+ if (priv->desc_ring[0].skb)
+ dev_kfree_skb_any(priv->desc_ring[0].skb);
+ netif_wake_queue(dev);
+#endif
+}
+
+static int cpmac_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+ if (!(netif_running(dev)))
+ return -EINVAL;
+ if (!priv->phy)
+ return -EINVAL;
+ if ((cmd == SIOCGMIIPHY) || (cmd == SIOCGMIIREG) ||
+ (cmd == SIOCSMIIREG))
+ return phy_mii_ioctl(priv->phy, if_mii(ifr), cmd);
+
+ return -EOPNOTSUPP;
+}
+
+static int cpmac_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ if (priv->phy)
+ return phy_ethtool_gset(priv->phy, cmd);
+
+ return -EINVAL;
+}
+
+static int cpmac_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (priv->phy)
+ return phy_ethtool_sset(priv->phy, cmd);
+
+ return -EINVAL;
+}
+
+static void cpmac_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ ring->rx_max_pending = 1024;
+ ring->rx_mini_max_pending = 1;
+ ring->rx_jumbo_max_pending = 1;
+ ring->tx_max_pending = 1;
+
+ ring->rx_pending = priv->ring_size;
+ ring->rx_mini_pending = 1;
+ ring->rx_jumbo_pending = 1;
+ ring->tx_pending = 1;
+}
+
+static int cpmac_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+
+ if (netif_running(dev))
+ return -EBUSY;
+ priv->ring_size = ring->rx_pending;
+ return 0;
+}
+
+static void cpmac_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, "cpmac");
+ strcpy(info->version, CPMAC_VERSION);
+ info->fw_version[0] = '\0';
+ sprintf(info->bus_info, "%s", "cpmac");
+ info->regdump_len = 0;
+}
+
+static const struct ethtool_ops cpmac_ethtool_ops = {
+ .get_settings = cpmac_get_settings,
+ .set_settings = cpmac_set_settings,
+ .get_drvinfo = cpmac_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_ringparam = cpmac_get_ringparam,
+ .set_ringparam = cpmac_set_ringparam,
+};
+
+static void cpmac_adjust_link(struct net_device *dev)
+{
+ struct cpmac_priv *priv = netdev_priv(dev);
+ int new_state = 0;
+
+ spin_lock(&priv->lock);
+ if (priv->phy->link) {
+ netif_start_queue(dev);
+ if (priv->phy->duplex != priv->oldduplex) {
+ new_state = 1;
+ priv->oldduplex = priv->phy->duplex;
+ }
+
+ if (priv->phy->speed != priv->oldspeed) {
+ new_state = 1;
+ priv->oldspeed = priv->phy->speed;
+ }
+
+ if (!priv->oldlink) {
+ new_state = 1;
+ priv->oldlink = 1;
+ netif_schedule(dev);
+ }
+ } else if (priv->oldlink) {
+ netif_stop_queue(dev);
+ new_state = 1;
+ priv->oldlink = 0;
+ priv->oldspeed = 0;
+ priv->oldduplex = -1;
+ }
+
+ if (new_state && netif_msg_link(priv) && net_ratelimit())
+ phy_print_status(priv->phy);
+
+ spin_unlock(&priv->lock);
+}
+
+static int cpmac_link_update(struct net_device *dev,
+ struct fixed_phy_status *status)
+{
+ status->link = 1;
+ status->speed = 100;
+ status->duplex = 1;
+ return 0;
+}
+
+static int cpmac_open(struct net_device *dev)
+{
+ int i, size, res;
+ struct cpmac_priv *priv = netdev_priv(dev);
+ struct resource *mem;
+ struct cpmac_desc *desc;
+ struct sk_buff *skb;
+
+ mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs");
+ if (!request_mem_region(mem->start, mem->end - mem->start, dev->name)) {
+ if (netif_msg_drv(priv))
+ printk(KERN_ERR "%s: failed to request registers\n",
+ dev->name);
+ res = -ENXIO;
+ goto fail_reserve;
+ }
+
+ priv->regs = ioremap(mem->start, mem->end - mem->start);
+ if (!priv->regs) {
+ if (netif_msg_drv(priv))
+ printk(KERN_ERR "%s: failed to remap registers\n",
+ dev->name);
+ res = -ENXIO;
+ goto fail_remap;
+ }
+
+ size = priv->ring_size + CPMAC_QUEUES;
+ priv->desc_ring = dma_alloc_coherent(&dev->dev,
+ sizeof(struct cpmac_desc) * size,
+ &priv->dma_ring,
+ GFP_KERNEL);
+ if (!priv->desc_ring) {
+ res = -ENOMEM;
+ goto fail_alloc;
+ }
+
+ for (i = 0; i < size; i++)
+ priv->desc_ring[i].mapping = priv->dma_ring + sizeof(*desc) * i;
+
+ priv->rx_head = &priv->desc_ring[CPMAC_QUEUES];
+ for (i = 0, desc = priv->rx_head; i < priv->ring_size; i++, desc++) {
+ skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE);
+ if (unlikely(!skb)) {
+ res = -ENOMEM;
+ goto fail_desc;
+ }
+ skb_reserve(skb, 2);
+ desc->skb = skb;
+ desc->data_mapping = dma_map_single(&dev->dev, skb->data,
+ CPMAC_SKB_SIZE,
+ DMA_FROM_DEVICE);
+ desc->hw_data = (u32)desc->data_mapping;
+ desc->buflen = CPMAC_SKB_SIZE;
+ desc->dataflags = CPMAC_OWN;
+ desc->next = &priv->rx_head[(i + 1) % priv->ring_size];
+ desc->hw_next = (u32)desc->next->mapping;
+ }
+
+ if ((res = request_irq(dev->irq, cpmac_irq, IRQF_SHARED,
+ dev->name, dev))) {
+ if (netif_msg_drv(priv))
+ printk(KERN_ERR "%s: failed to obtain irq\n",
+ dev->name);
+ goto fail_irq;
+ }
+
+ INIT_WORK(&priv->reset_work, cpmac_hw_error);
+ cpmac_hw_start(dev);
+
+ napi_enable(&priv->napi);
+ priv->phy->state = PHY_CHANGELINK;
+ phy_start(priv->phy);
+
+ return 0;
+
+fail_irq:
+fail_desc:
+ for (i = 0; i < priv->ring_size; i++) {
+ if (priv->rx_head[i].skb) {
+ dma_unmap_single(&dev->dev,
+ priv->rx_head[i].data_mapping,
+ CPMAC_SKB_SIZE,
+ DMA_FROM_DEVICE);
+ kfree_skb(priv->rx_head[i].skb);
+ }
+ }
+fail_alloc:
+ kfree(priv->desc_ring);
+ iounmap(priv->regs);
+
+fail_remap:
+ release_mem_region(mem->start, mem->end - mem->start);
+
+fail_reserve:
+ return res;
+}
+
+static int cpmac_stop(struct net_device *dev)
+{
+ int i;
+ struct cpmac_priv *priv = netdev_priv(dev);
+ struct resource *mem;
+
+ netif_stop_queue(dev);
+
+ cancel_work_sync(&priv->reset_work);
+ napi_disable(&priv->napi);
+ phy_stop(priv->phy);
+
+ cpmac_hw_stop(dev);
+
+ for (i = 0; i < 8; i++)
+ cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0);
+ cpmac_write(priv->regs, CPMAC_RX_PTR(0), 0);
+ cpmac_write(priv->regs, CPMAC_MBP, 0);
+
+ free_irq(dev->irq, dev);
+ iounmap(priv->regs);
+ mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs");
+ release_mem_region(mem->start, mem->end - mem->start);
+ priv->rx_head = &priv->desc_ring[CPMAC_QUEUES];
+ for (i = 0; i < priv->ring_size; i++) {
+ if (priv->rx_head[i].skb) {
+ dma_unmap_single(&dev->dev,
+ priv->rx_head[i].data_mapping,
+ CPMAC_SKB_SIZE,
+ DMA_FROM_DEVICE);
+ kfree_skb(priv->rx_head[i].skb);
+ }
+ }
+
+ dma_free_coherent(&dev->dev, sizeof(struct cpmac_desc) *
+ (CPMAC_QUEUES + priv->ring_size),
+ priv->desc_ring, priv->dma_ring);
+ return 0;
+}
+
+static int external_switch;
+
+static int __devinit cpmac_probe(struct platform_device *pdev)
+{
+ int rc, phy_id, i;
+ struct resource *mem;
+ struct cpmac_priv *priv;
+ struct net_device *dev;
+ struct plat_cpmac_data *pdata;
+ struct fixed_info *fixed_phy;
+ DECLARE_MAC_BUF(mac);
+
+ pdata = pdev->dev.platform_data;
+
+ for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) {
+ if (!(pdata->phy_mask & (1 << phy_id)))
+ continue;
+ if (!cpmac_mii.phy_map[phy_id])
+ continue;
+ break;
+ }
+
+ if (phy_id == PHY_MAX_ADDR) {
+ if (external_switch || dumb_switch)
+ phy_id = 0;
+ else {
+ printk(KERN_ERR "cpmac: no PHY present\n");
+ return -ENODEV;
+ }
+ }
+
+ dev = alloc_etherdev_mq(sizeof(*priv), CPMAC_QUEUES);
+
+ if (!dev) {
+ printk(KERN_ERR "cpmac: Unable to allocate net_device\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, dev);
+ priv = netdev_priv(dev);
+
+ priv->pdev = pdev;
+ mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+ if (!mem) {
+ rc = -ENODEV;
+ goto fail;
+ }
+
+ dev->irq = platform_get_irq_byname(pdev, "irq");
+
+ dev->open = cpmac_open;
+ dev->stop = cpmac_stop;
+ dev->set_config = cpmac_config;
+ dev->hard_start_xmit = cpmac_start_xmit;
+ dev->do_ioctl = cpmac_ioctl;
+ dev->set_multicast_list = cpmac_set_multicast_list;
+ dev->tx_timeout = cpmac_tx_timeout;
+ dev->ethtool_ops = &cpmac_ethtool_ops;
+ dev->features |= NETIF_F_MULTI_QUEUE;
+
+ netif_napi_add(dev, &priv->napi, cpmac_poll, 64);
+
+ spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->rx_lock);
+ priv->dev = dev;
+ priv->ring_size = 64;
+ priv->msg_enable = netif_msg_init(debug_level, 0xff);
+ memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr));
+
+ if (phy_id == 31) {
+ snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, cpmac_mii.id,
+ phy_id);
+ } else {
+ /* Let's try to get a free fixed phy... */
+ for (i = 0; i < MAX_PHY_AMNT; i++) {
+ fixed_phy = fixed_mdio_get_phydev(i);
+ if (!fixed_phy)
+ continue;
+ if (!fixed_phy->phydev->attached_dev) {
+ strncpy(priv->phy_name,
+ fixed_phy->phydev->dev.bus_id,
+ BUS_ID_SIZE);
+ fixed_mdio_set_link_update(fixed_phy->phydev,
+ &cpmac_link_update);
+ goto phy_found;
+ }
+ }
+ if (netif_msg_drv(priv))
+ printk(KERN_ERR "%s: Could not find fixed PHY\n",
+ dev->name);
+ rc = -ENODEV;
+ goto fail;
+ }
+
+phy_found:
+ priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0,
+ PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(priv->phy)) {
+ if (netif_msg_drv(priv))
+ printk(KERN_ERR "%s: Could not attach to PHY\n",
+ dev->name);
+ return PTR_ERR(priv->phy);
+ }
+
+ if ((rc = register_netdev(dev))) {
+ printk(KERN_ERR "cpmac: error %i registering device %s\n", rc,
+ dev->name);
+ goto fail;
+ }
+
+ if (netif_msg_probe(priv)) {
+ printk(KERN_INFO
+ "cpmac: device %s (regs: %p, irq: %d, phy: %s, "
+ "mac: %s)\n", dev->name, (void *)mem->start, dev->irq,
+ priv->phy_name, print_mac(mac, dev->dev_addr));
+ }
+ return 0;
+
+fail:
+ free_netdev(dev);
+ return rc;
+}
+
+static int __devexit cpmac_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ unregister_netdev(dev);
+ free_netdev(dev);
+ return 0;
+}
+
+static struct platform_driver cpmac_driver = {
+ .driver.name = "cpmac",
+ .probe = cpmac_probe,
+ .remove = __devexit_p(cpmac_remove),
+};
+
+int __devinit cpmac_init(void)
+{
+ u32 mask;
+ int i, res;
+
+ cpmac_mii.priv = ioremap(AR7_REGS_MDIO, 256);
+
+ if (!cpmac_mii.priv) {
+ printk(KERN_ERR "Can't ioremap mdio registers\n");
+ return -ENXIO;
+ }
+
+#warning FIXME: unhardcode gpio&reset bits
+ ar7_gpio_disable(26);
+ ar7_gpio_disable(27);
+ ar7_device_reset(AR7_RESET_BIT_CPMAC_LO);
+ ar7_device_reset(AR7_RESET_BIT_CPMAC_HI);
+ ar7_device_reset(AR7_RESET_BIT_EPHY);
+
+ cpmac_mii.reset(&cpmac_mii);
+
+ for (i = 0; i < 300000; i++)
+ if ((mask = cpmac_read(cpmac_mii.priv, CPMAC_MDIO_ALIVE)))
+ break;
+ else
+ cpu_relax();
+
+ mask &= 0x7fffffff;
+ if (mask & (mask - 1)) {
+ external_switch = 1;
+ mask = 0;
+ }
+
+ cpmac_mii.phy_mask = ~(mask | 0x80000000);
+
+ res = mdiobus_register(&cpmac_mii);
+ if (res)
+ goto fail_mii;
+
+ res = platform_driver_register(&cpmac_driver);
+ if (res)
+ goto fail_cpmac;
+
+ return 0;
+
+fail_cpmac:
+ mdiobus_unregister(&cpmac_mii);
+
+fail_mii:
+ iounmap(cpmac_mii.priv);
+
+ return res;
+}
+
+void __devexit cpmac_exit(void)
+{
+ platform_driver_unregister(&cpmac_driver);
+ mdiobus_unregister(&cpmac_mii);
+ iounmap(cpmac_mii.priv);
+}
+
+module_init(cpmac_init);
+module_exit(cpmac_exit);
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 5bdf5ca85a6..917b7b46f1a 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -234,6 +234,7 @@
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/bitops.h>
#include <linux/if.h>
#include <linux/mii.h>
@@ -247,9 +248,9 @@
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/system.h>
-#include <asm/bitops.h>
#include <asm/ethernet.h>
#include <asm/cache.h>
+#include <asm/arch/io_interface_mux.h>
//#define ETHDEBUG
#define D(x)
@@ -279,6 +280,9 @@ struct net_local {
* by this lock as well.
*/
spinlock_t lock;
+
+ spinlock_t led_lock; /* Protect LED state */
+ spinlock_t transceiver_lock; /* Protect transceiver state. */
};
typedef struct etrax_eth_descr
@@ -295,8 +299,6 @@ struct transceiver_ops
void (*check_duplex)(struct net_device* dev);
};
-struct transceiver_ops* transceiver;
-
/* Duplex settings */
enum duplex
{
@@ -307,7 +309,7 @@ enum duplex
/* Dma descriptors etc. */
-#define MAX_MEDIA_DATA_SIZE 1518
+#define MAX_MEDIA_DATA_SIZE 1522
#define MIN_PACKET_LEN 46
#define ETHER_HEAD_LEN 14
@@ -332,8 +334,8 @@ enum duplex
/*Intel LXT972A specific*/
#define MDIO_INT_STATUS_REG_2 0x0011
-#define MDIO_INT_FULL_DUPLEX_IND ( 1 << 9 )
-#define MDIO_INT_SPEED ( 1 << 14 )
+#define MDIO_INT_FULL_DUPLEX_IND (1 << 9)
+#define MDIO_INT_SPEED (1 << 14)
/* Network flash constants */
#define NET_FLASH_TIME (HZ/50) /* 20 ms */
@@ -344,8 +346,8 @@ enum duplex
#define NO_NETWORK_ACTIVITY 0
#define NETWORK_ACTIVITY 1
-#define NBR_OF_RX_DESC 64
-#define NBR_OF_TX_DESC 256
+#define NBR_OF_RX_DESC 32
+#define NBR_OF_TX_DESC 16
/* Large packets are sent directly to upper layers while small packets are */
/* copied (to reduce memory waste). The following constant decides the breakpoint */
@@ -367,7 +369,6 @@ enum duplex
static etrax_eth_descr *myNextRxDesc; /* Points to the next descriptor to
to be processed */
static etrax_eth_descr *myLastRxDesc; /* The last processed descriptor */
-static etrax_eth_descr *myPrevRxDesc; /* The descriptor right before myNextRxDesc */
static etrax_eth_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(32)));
@@ -377,7 +378,6 @@ static etrax_eth_descr* myNextTxDesc; /* Next descriptor to use */
static etrax_eth_descr TxDescList[NBR_OF_TX_DESC] __attribute__ ((aligned(32)));
static unsigned int network_rec_config_shadow = 0;
-static unsigned int mdio_phy_addr; /* Transciever address */
static unsigned int network_tr_ctrl_shadow = 0;
@@ -411,7 +411,7 @@ static int e100_set_config(struct net_device* dev, struct ifmap* map);
static void e100_tx_timeout(struct net_device *dev);
static struct net_device_stats *e100_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
-static void e100_hardware_send_packet(char *buf, int length);
+static void e100_hardware_send_packet(struct net_local* np, char *buf, int length);
static void update_rx_stats(struct net_device_stats *);
static void update_tx_stats(struct net_device_stats *);
static int e100_probe_transceiver(struct net_device* dev);
@@ -434,7 +434,10 @@ static void e100_clear_network_leds(unsigned long dummy);
static void e100_set_network_leds(int active);
static const struct ethtool_ops e100_ethtool_ops;
-
+#if defined(CONFIG_ETRAX_NO_PHY)
+static void dummy_check_speed(struct net_device* dev);
+static void dummy_check_duplex(struct net_device* dev);
+#else
static void broadcom_check_speed(struct net_device* dev);
static void broadcom_check_duplex(struct net_device* dev);
static void tdk_check_speed(struct net_device* dev);
@@ -443,16 +446,28 @@ static void intel_check_speed(struct net_device* dev);
static void intel_check_duplex(struct net_device* dev);
static void generic_check_speed(struct net_device* dev);
static void generic_check_duplex(struct net_device* dev);
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void e100_netpoll(struct net_device* dev);
+#endif
+
+static int autoneg_normal = 1;
struct transceiver_ops transceivers[] =
{
+#if defined(CONFIG_ETRAX_NO_PHY)
+ {0x0000, dummy_check_speed, dummy_check_duplex} /* Dummy */
+#else
{0x1018, broadcom_check_speed, broadcom_check_duplex}, /* Broadcom */
{0xC039, tdk_check_speed, tdk_check_duplex}, /* TDK 2120 */
{0x039C, tdk_check_speed, tdk_check_duplex}, /* TDK 2120C */
{0x04de, intel_check_speed, intel_check_duplex}, /* Intel LXT972A*/
{0x0000, generic_check_speed, generic_check_duplex} /* Generic, must be last */
+#endif
};
+struct transceiver_ops* transceiver = &transceivers[0];
+
#define tx_done(dev) (*R_DMA_CH0_CMD == 0)
/*
@@ -471,14 +486,22 @@ etrax_ethernet_init(void)
int i, err;
printk(KERN_INFO
- "ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2003 Axis Communications AB\n");
+ "ETRAX 100LX 10/100MBit ethernet v2.0 (c) 1998-2007 Axis Communications AB\n");
- dev = alloc_etherdev(sizeof(struct net_local));
- np = dev->priv;
+ if (cris_request_io_interface(if_eth, cardname)) {
+ printk(KERN_CRIT "etrax_ethernet_init failed to get IO interface\n");
+ return -EBUSY;
+ }
+ dev = alloc_etherdev(sizeof(struct net_local));
if (!dev)
return -ENOMEM;
+ np = netdev_priv(dev);
+
+ /* we do our own locking */
+ dev->features |= NETIF_F_LLTX;
+
dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */
/* now setup our etrax specific stuff */
@@ -498,14 +521,22 @@ etrax_ethernet_init(void)
dev->do_ioctl = e100_ioctl;
dev->set_config = e100_set_config;
dev->tx_timeout = e100_tx_timeout;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = e100_netpoll;
+#endif
+
+ spin_lock_init(&np->lock);
+ spin_lock_init(&np->led_lock);
+ spin_lock_init(&np->transceiver_lock);
/* Initialise the list of Etrax DMA-descriptors */
/* Initialise receive descriptors */
for (i = 0; i < NBR_OF_RX_DESC; i++) {
- /* Allocate two extra cachelines to make sure that buffer used by DMA
- * does not share cacheline with any other data (to avoid cache bug)
+ /* Allocate two extra cachelines to make sure that buffer used
+ * by DMA does not share cacheline with any other data (to
+ * avoid cache bug)
*/
RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
if (!RxDescList[i].skb)
@@ -541,7 +572,6 @@ etrax_ethernet_init(void)
myNextRxDesc = &RxDescList[0];
myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
- myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1];
myFirstTxDesc = &TxDescList[0];
myNextTxDesc = &TxDescList[0];
myLastTxDesc = &TxDescList[NBR_OF_TX_DESC - 1];
@@ -562,10 +592,11 @@ etrax_ethernet_init(void)
current_speed = 10;
current_speed_selection = 0; /* Auto */
speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
- duplex_timer.data = (unsigned long)dev;
+ speed_timer.data = (unsigned long)dev;
speed_timer.function = e100_check_speed;
clear_led_timer.function = e100_clear_network_leds;
+ clear_led_timer.data = (unsigned long)dev;
full_duplex = 0;
current_duplex = autoneg;
@@ -574,7 +605,6 @@ etrax_ethernet_init(void)
duplex_timer.function = e100_check_duplex;
/* Initialize mii interface */
- np->mii_if.phy_id = mdio_phy_addr;
np->mii_if.phy_id_mask = 0x1f;
np->mii_if.reg_num_mask = 0x1f;
np->mii_if.dev = dev;
@@ -585,6 +615,9 @@ etrax_ethernet_init(void)
/* unwanted addresses are matched */
*R_NETWORK_GA_0 = 0x00000000;
*R_NETWORK_GA_1 = 0x00000000;
+
+ /* Initialize next time the led can flash */
+ led_next_time = jiffies;
return 0;
}
@@ -595,9 +628,9 @@ etrax_ethernet_init(void)
static int
e100_set_mac_address(struct net_device *dev, void *p)
{
- struct net_local *np = (struct net_local *)dev->priv;
+ struct net_local *np = netdev_priv(dev);
struct sockaddr *addr = p;
- int i;
+ DECLARE_MAC_BUF(mac);
spin_lock(&np->lock); /* preemption protection */
@@ -618,12 +651,8 @@ e100_set_mac_address(struct net_device *dev, void *p)
/* show it in the log as well */
- printk(KERN_INFO "%s: changed MAC to ", dev->name);
-
- for (i = 0; i < 5; i++)
- printk("%02X:", dev->dev_addr[i]);
-
- printk("%02X\n", dev->dev_addr[i]);
+ printk(KERN_INFO "%s: changed MAC to %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
spin_unlock(&np->lock);
@@ -690,6 +719,25 @@ e100_open(struct net_device *dev)
goto grace_exit2;
}
+ /*
+ * Always allocate the DMA channels after the IRQ,
+ * and clean up on failure.
+ */
+
+ if (cris_request_dma(NETWORK_TX_DMA_NBR,
+ cardname,
+ DMA_VERBOSE_ON_ERROR,
+ dma_eth)) {
+ goto grace_exit3;
+ }
+
+ if (cris_request_dma(NETWORK_RX_DMA_NBR,
+ cardname,
+ DMA_VERBOSE_ON_ERROR,
+ dma_eth)) {
+ goto grace_exit4;
+ }
+
/* give the HW an idea of what MAC address we want */
*R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) |
@@ -704,6 +752,7 @@ e100_open(struct net_device *dev)
*R_NETWORK_REC_CONFIG = 0xd; /* broadcast rec, individ. rec, ma0 enabled */
#else
+ SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, max_size, size1522);
SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, broadcast, receive);
SETS(network_rec_config_shadow, R_NETWORK_REC_CONFIG, ma0, enable);
SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
@@ -723,8 +772,7 @@ e100_open(struct net_device *dev)
SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, crc, enable);
*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* enable the irq's for ethernet DMA */
@@ -756,12 +804,13 @@ e100_open(struct net_device *dev)
*R_DMA_CH0_FIRST = 0;
*R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc);
+ netif_start_queue(dev);
- restore_flags(flags);
+ local_irq_restore(flags);
/* Probe for transceiver */
if (e100_probe_transceiver(dev))
- goto grace_exit3;
+ goto grace_exit5;
/* Start duplex/speed timers */
add_timer(&speed_timer);
@@ -770,10 +819,14 @@ e100_open(struct net_device *dev)
/* We are now ready to accept transmit requeusts from
* the queueing layer of the networking.
*/
- netif_start_queue(dev);
+ netif_carrier_on(dev);
return 0;
+grace_exit5:
+ cris_free_dma(NETWORK_RX_DMA_NBR, cardname);
+grace_exit4:
+ cris_free_dma(NETWORK_TX_DMA_NBR, cardname);
grace_exit3:
free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
grace_exit2:
@@ -784,12 +837,20 @@ grace_exit0:
return -EAGAIN;
}
-
+#if defined(CONFIG_ETRAX_NO_PHY)
+static void
+dummy_check_speed(struct net_device* dev)
+{
+ current_speed = 100;
+}
+#else
static void
generic_check_speed(struct net_device* dev)
{
unsigned long data;
- data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
+ struct net_local *np = netdev_priv(dev);
+
+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE);
if ((data & ADVERTISE_100FULL) ||
(data & ADVERTISE_100HALF))
current_speed = 100;
@@ -801,7 +862,10 @@ static void
tdk_check_speed(struct net_device* dev)
{
unsigned long data;
- data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_TDK_DIAGNOSTIC_REG);
+ struct net_local *np = netdev_priv(dev);
+
+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+ MDIO_TDK_DIAGNOSTIC_REG);
current_speed = (data & MDIO_TDK_DIAGNOSTIC_RATE ? 100 : 10);
}
@@ -809,7 +873,10 @@ static void
broadcom_check_speed(struct net_device* dev)
{
unsigned long data;
- data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_AUX_CTRL_STATUS_REG);
+ struct net_local *np = netdev_priv(dev);
+
+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+ MDIO_AUX_CTRL_STATUS_REG);
current_speed = (data & MDIO_BC_SPEED ? 100 : 10);
}
@@ -817,46 +884,62 @@ static void
intel_check_speed(struct net_device* dev)
{
unsigned long data;
- data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2);
+ struct net_local *np = netdev_priv(dev);
+
+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+ MDIO_INT_STATUS_REG_2);
current_speed = (data & MDIO_INT_SPEED ? 100 : 10);
}
-
+#endif
static void
e100_check_speed(unsigned long priv)
{
struct net_device* dev = (struct net_device*)priv;
+ struct net_local *np = netdev_priv(dev);
static int led_initiated = 0;
unsigned long data;
int old_speed = current_speed;
- data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR);
+ spin_lock(&np->transceiver_lock);
+
+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMSR);
if (!(data & BMSR_LSTATUS)) {
current_speed = 0;
} else {
transceiver->check_speed(dev);
}
+ spin_lock(&np->led_lock);
if ((old_speed != current_speed) || !led_initiated) {
led_initiated = 1;
e100_set_network_leds(NO_NETWORK_ACTIVITY);
+ if (current_speed)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
}
+ spin_unlock(&np->led_lock);
/* Reinitialize the timer. */
speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
add_timer(&speed_timer);
+
+ spin_unlock(&np->transceiver_lock);
}
static void
e100_negotiate(struct net_device* dev)
{
- unsigned short data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
+ struct net_local *np = netdev_priv(dev);
+ unsigned short data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+ MII_ADVERTISE);
/* Discard old speed and duplex settings */
data &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL |
ADVERTISE_10HALF | ADVERTISE_10FULL);
switch (current_speed_selection) {
- case 10 :
+ case 10:
if (current_duplex == full)
data |= ADVERTISE_10FULL;
else if (current_duplex == half)
@@ -865,7 +948,7 @@ e100_negotiate(struct net_device* dev)
data |= ADVERTISE_10HALF | ADVERTISE_10FULL;
break;
- case 100 :
+ case 100:
if (current_duplex == full)
data |= ADVERTISE_100FULL;
else if (current_duplex == half)
@@ -874,7 +957,7 @@ e100_negotiate(struct net_device* dev)
data |= ADVERTISE_100HALF | ADVERTISE_100FULL;
break;
- case 0 : /* Auto */
+ case 0: /* Auto */
if (current_duplex == full)
data |= ADVERTISE_100FULL | ADVERTISE_10FULL;
else if (current_duplex == half)
@@ -884,35 +967,44 @@ e100_negotiate(struct net_device* dev)
ADVERTISE_100HALF | ADVERTISE_100FULL;
break;
- default : /* assume autoneg speed and duplex */
+ default: /* assume autoneg speed and duplex */
data |= ADVERTISE_10HALF | ADVERTISE_10FULL |
ADVERTISE_100HALF | ADVERTISE_100FULL;
+ break;
}
- e100_set_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE, data);
+ e100_set_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE, data);
/* Renegotiate with link partner */
- data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMCR);
+ if (autoneg_normal) {
+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR);
data |= BMCR_ANENABLE | BMCR_ANRESTART;
-
- e100_set_mdio_reg(dev, mdio_phy_addr, MII_BMCR, data);
+ }
+ e100_set_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR, data);
}
static void
e100_set_speed(struct net_device* dev, unsigned long speed)
{
+ struct net_local *np = netdev_priv(dev);
+
+ spin_lock(&np->transceiver_lock);
if (speed != current_speed_selection) {
current_speed_selection = speed;
e100_negotiate(dev);
}
+ spin_unlock(&np->transceiver_lock);
}
static void
e100_check_duplex(unsigned long priv)
{
struct net_device *dev = (struct net_device *)priv;
- struct net_local *np = (struct net_local *)dev->priv;
- int old_duplex = full_duplex;
+ struct net_local *np = netdev_priv(dev);
+ int old_duplex;
+
+ spin_lock(&np->transceiver_lock);
+ old_duplex = full_duplex;
transceiver->check_duplex(dev);
if (old_duplex != full_duplex) {
/* Duplex changed */
@@ -924,13 +1016,22 @@ e100_check_duplex(unsigned long priv)
duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
add_timer(&duplex_timer);
np->mii_if.full_duplex = full_duplex;
+ spin_unlock(&np->transceiver_lock);
}
-
+#if defined(CONFIG_ETRAX_NO_PHY)
+static void
+dummy_check_duplex(struct net_device* dev)
+{
+ full_duplex = 1;
+}
+#else
static void
generic_check_duplex(struct net_device* dev)
{
unsigned long data;
- data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_ADVERTISE);
+ struct net_local *np = netdev_priv(dev);
+
+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_ADVERTISE);
if ((data & ADVERTISE_10FULL) ||
(data & ADVERTISE_100FULL))
full_duplex = 1;
@@ -942,7 +1043,10 @@ static void
tdk_check_duplex(struct net_device* dev)
{
unsigned long data;
- data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_TDK_DIAGNOSTIC_REG);
+ struct net_local *np = netdev_priv(dev);
+
+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+ MDIO_TDK_DIAGNOSTIC_REG);
full_duplex = (data & MDIO_TDK_DIAGNOSTIC_DPLX) ? 1 : 0;
}
@@ -950,7 +1054,10 @@ static void
broadcom_check_duplex(struct net_device* dev)
{
unsigned long data;
- data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_AUX_CTRL_STATUS_REG);
+ struct net_local *np = netdev_priv(dev);
+
+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+ MDIO_AUX_CTRL_STATUS_REG);
full_duplex = (data & MDIO_BC_FULL_DUPLEX_IND) ? 1 : 0;
}
@@ -958,38 +1065,55 @@ static void
intel_check_duplex(struct net_device* dev)
{
unsigned long data;
- data = e100_get_mdio_reg(dev, mdio_phy_addr, MDIO_INT_STATUS_REG_2);
+ struct net_local *np = netdev_priv(dev);
+
+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id,
+ MDIO_INT_STATUS_REG_2);
full_duplex = (data & MDIO_INT_FULL_DUPLEX_IND) ? 1 : 0;
}
-
+#endif
static void
e100_set_duplex(struct net_device* dev, enum duplex new_duplex)
{
+ struct net_local *np = netdev_priv(dev);
+
+ spin_lock(&np->transceiver_lock);
if (new_duplex != current_duplex) {
current_duplex = new_duplex;
e100_negotiate(dev);
}
+ spin_unlock(&np->transceiver_lock);
}
static int
e100_probe_transceiver(struct net_device* dev)
{
+ int ret = 0;
+
+#if !defined(CONFIG_ETRAX_NO_PHY)
unsigned int phyid_high;
unsigned int phyid_low;
unsigned int oui;
struct transceiver_ops* ops = NULL;
+ struct net_local *np = netdev_priv(dev);
+
+ spin_lock(&np->transceiver_lock);
/* Probe MDIO physical address */
- for (mdio_phy_addr = 0; mdio_phy_addr <= 31; mdio_phy_addr++) {
- if (e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMSR) != 0xffff)
+ for (np->mii_if.phy_id = 0; np->mii_if.phy_id <= 31;
+ np->mii_if.phy_id++) {
+ if (e100_get_mdio_reg(dev,
+ np->mii_if.phy_id, MII_BMSR) != 0xffff)
break;
}
- if (mdio_phy_addr == 32)
- return -ENODEV;
+ if (np->mii_if.phy_id == 32) {
+ ret = -ENODEV;
+ goto out;
+ }
/* Get manufacturer */
- phyid_high = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID1);
- phyid_low = e100_get_mdio_reg(dev, mdio_phy_addr, MII_PHYSID2);
+ phyid_high = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_PHYSID1);
+ phyid_low = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_PHYSID2);
oui = (phyid_high << 6) | (phyid_low >> 10);
for (ops = &transceivers[0]; ops->oui; ops++) {
@@ -997,8 +1121,10 @@ e100_probe_transceiver(struct net_device* dev)
break;
}
transceiver = ops;
-
- return 0;
+out:
+ spin_unlock(&np->transceiver_lock);
+#endif
+ return ret;
}
static int
@@ -1092,13 +1218,14 @@ e100_receive_mdio_bit()
static void
e100_reset_transceiver(struct net_device* dev)
{
+ struct net_local *np = netdev_priv(dev);
unsigned short cmd;
unsigned short data;
int bitCounter;
- data = e100_get_mdio_reg(dev, mdio_phy_addr, MII_BMCR);
+ data = e100_get_mdio_reg(dev, np->mii_if.phy_id, MII_BMCR);
- cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (mdio_phy_addr << 7) | (MII_BMCR << 2);
+ cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (np->mii_if.phy_id << 7) | (MII_BMCR << 2);
e100_send_mdio_cmd(cmd, 1);
@@ -1116,7 +1243,7 @@ e100_reset_transceiver(struct net_device* dev)
static void
e100_tx_timeout(struct net_device *dev)
{
- struct net_local *np = (struct net_local *)dev->priv;
+ struct net_local *np = netdev_priv(dev);
unsigned long flags;
spin_lock_irqsave(&np->lock, flags);
@@ -1138,8 +1265,7 @@ e100_tx_timeout(struct net_device *dev)
e100_reset_transceiver(dev);
/* and get rid of the packets that never got an interrupt */
- while (myFirstTxDesc != myNextTxDesc)
- {
+ while (myFirstTxDesc != myNextTxDesc) {
dev_kfree_skb(myFirstTxDesc->skb);
myFirstTxDesc->skb = 0;
myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
@@ -1165,7 +1291,7 @@ e100_tx_timeout(struct net_device *dev)
static int
e100_send_packet(struct sk_buff *skb, struct net_device *dev)
{
- struct net_local *np = (struct net_local *)dev->priv;
+ struct net_local *np = netdev_priv(dev);
unsigned char *buf = skb->data;
unsigned long flags;
@@ -1178,7 +1304,7 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- e100_hardware_send_packet(buf, skb->len);
+ e100_hardware_send_packet(np, buf, skb->len);
myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next);
@@ -1201,13 +1327,15 @@ static irqreturn_t
e100rxtx_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
- struct net_local *np = (struct net_local *)dev->priv;
- unsigned long irqbits = *R_IRQ_MASK2_RD;
+ struct net_local *np = netdev_priv(dev);
+ unsigned long irqbits;
- /* Disable RX/TX IRQs to avoid reentrancy */
- *R_IRQ_MASK2_CLR =
- IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
- IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
+ /*
+ * Note that both rx and tx interrupts are blocked at this point,
+ * regardless of which got us here.
+ */
+
+ irqbits = *R_IRQ_MASK2_RD;
/* Handle received packets */
if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
@@ -1223,7 +1351,7 @@ e100rxtx_interrupt(int irq, void *dev_id)
* allocate a new buffer to put a packet in.
*/
e100_rx(dev);
- ((struct net_local *)dev->priv)->stats.rx_packets++;
+ np->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 */
@@ -1237,9 +1365,8 @@ e100rxtx_interrupt(int irq, void *dev_id)
}
/* Report any packets that have been sent */
- while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) &&
- myFirstTxDesc != myNextTxDesc)
- {
+ 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++;
@@ -1248,19 +1375,15 @@ e100rxtx_interrupt(int irq, void *dev_id)
dev_kfree_skb_irq(myFirstTxDesc->skb);
myFirstTxDesc->skb = 0;
myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next);
+ /* Wake up queue. */
+ netif_wake_queue(dev);
}
if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
- /* acknowledge the eop interrupt and wake up queue */
+ /* acknowledge the eop interrupt. */
*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
- netif_wake_queue(dev);
}
- /* Enable RX/TX IRQs again */
- *R_IRQ_MASK2_SET =
- IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |
- IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set);
-
return IRQ_HANDLED;
}
@@ -1268,7 +1391,7 @@ static irqreturn_t
e100nw_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
- struct net_local *np = (struct net_local *)dev->priv;
+ struct net_local *np = netdev_priv(dev);
unsigned long irqbits = *R_IRQ_MASK0_RD;
/* check for underrun irq */
@@ -1290,7 +1413,6 @@ 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);
- *R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr);
np->stats.tx_errors++;
D(printk("ethernet excessive collisions!\n"));
}
@@ -1303,12 +1425,13 @@ e100_rx(struct net_device *dev)
{
struct sk_buff *skb;
int length = 0;
- struct net_local *np = (struct net_local *)dev->priv;
+ struct net_local *np = netdev_priv(dev);
unsigned char *skb_data_ptr;
#ifdef ETHDEBUG
int i;
#endif
-
+ etrax_eth_descr *prevRxDesc; /* The descriptor right before myNextRxDesc */
+ spin_lock(&np->led_lock);
if (!led_active && time_after(jiffies, led_next_time)) {
/* light the network leds depending on the current speed. */
e100_set_network_leds(NETWORK_ACTIVITY);
@@ -1318,9 +1441,10 @@ e100_rx(struct net_device *dev)
led_active = 1;
mod_timer(&clear_led_timer, jiffies + HZ/10);
}
+ spin_unlock(&np->led_lock);
length = myNextRxDesc->descr.hw_len - 4;
- ((struct net_local *)dev->priv)->stats.rx_bytes += length;
+ np->stats.rx_bytes += length;
#ifdef ETHDEBUG
printk("Got a packet of length %d:\n", length);
@@ -1340,7 +1464,7 @@ e100_rx(struct net_device *dev)
if (!skb) {
np->stats.rx_errors++;
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
- return;
+ goto update_nextrxdesc;
}
skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */
@@ -1358,15 +1482,15 @@ e100_rx(struct net_device *dev)
else {
/* Large packet, send directly to upper layers and allocate new
* memory (aligned to cache line boundary to avoid bug).
- * Before sending the skb to upper layers we must make sure that
- * skb->data points to the aligned start of the packet.
+ * Before sending the skb to upper layers we must make sure
+ * that skb->data points to the aligned start of the packet.
*/
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++;
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
- return;
+ goto update_nextrxdesc;
}
skb = myNextRxDesc->skb;
align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data;
@@ -1381,9 +1505,10 @@ e100_rx(struct net_device *dev)
/* Send the packet to the upper layers */
netif_rx(skb);
+ update_nextrxdesc:
/* Prepare for next packet */
myNextRxDesc->descr.status = 0;
- myPrevRxDesc = myNextRxDesc;
+ prevRxDesc = myNextRxDesc;
myNextRxDesc = phys_to_virt(myNextRxDesc->descr.next);
rx_queue_len++;
@@ -1391,9 +1516,9 @@ e100_rx(struct net_device *dev)
/* Check if descriptors should be returned */
if (rx_queue_len == RX_QUEUE_THRESHOLD) {
flush_etrax_cache();
- myPrevRxDesc->descr.ctrl |= d_eol;
+ prevRxDesc->descr.ctrl |= d_eol;
myLastRxDesc->descr.ctrl &= ~d_eol;
- myLastRxDesc = myPrevRxDesc;
+ myLastRxDesc = prevRxDesc;
rx_queue_len = 0;
}
}
@@ -1402,7 +1527,7 @@ e100_rx(struct net_device *dev)
static int
e100_close(struct net_device *dev)
{
- struct net_local *np = (struct net_local *)dev->priv;
+ struct net_local *np = netdev_priv(dev);
printk(KERN_INFO "Closing %s.\n", dev->name);
@@ -1430,6 +1555,9 @@ e100_close(struct net_device *dev)
free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
+ cris_free_dma(NETWORK_TX_DMA_NBR, cardname);
+ cris_free_dma(NETWORK_RX_DMA_NBR, cardname);
+
/* Update the statistics here. */
update_rx_stats(&np->stats);
@@ -1447,18 +1575,11 @@ e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct mii_ioctl_data *data = if_mii(ifr);
struct net_local *np = netdev_priv(dev);
+ int rc = 0;
+ int old_autoneg;
spin_lock(&np->lock); /* Preempt protection */
switch (cmd) {
- case SIOCGMIIPHY: /* Get PHY address */
- data->phy_id = mdio_phy_addr;
- break;
- case SIOCGMIIREG: /* Read MII register */
- data->val_out = e100_get_mdio_reg(dev, mdio_phy_addr, data->reg_num);
- break;
- case SIOCSMIIREG: /* Write MII register */
- e100_set_mdio_reg(dev, mdio_phy_addr, data->reg_num, data->val_in);
- break;
/* The ioctls below should be considered obsolete but are */
/* still present for compatability with old scripts/apps */
case SET_ETH_SPEED_10: /* 10 Mbps */
@@ -1467,60 +1588,47 @@ e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SET_ETH_SPEED_100: /* 100 Mbps */
e100_set_speed(dev, 100);
break;
- case SET_ETH_SPEED_AUTO: /* Auto negotiate speed */
+ case SET_ETH_SPEED_AUTO: /* Auto-negotiate speed */
e100_set_speed(dev, 0);
break;
- case SET_ETH_DUPLEX_HALF: /* Half duplex. */
+ case SET_ETH_DUPLEX_HALF: /* Half duplex */
e100_set_duplex(dev, half);
break;
- case SET_ETH_DUPLEX_FULL: /* Full duplex. */
+ case SET_ETH_DUPLEX_FULL: /* Full duplex */
e100_set_duplex(dev, full);
break;
- case SET_ETH_DUPLEX_AUTO: /* Autonegotiate duplex*/
+ case SET_ETH_DUPLEX_AUTO: /* Auto-negotiate duplex */
e100_set_duplex(dev, autoneg);
break;
+ case SET_ETH_AUTONEG:
+ old_autoneg = autoneg_normal;
+ autoneg_normal = *(int*)data;
+ if (autoneg_normal != old_autoneg)
+ e100_negotiate(dev);
+ break;
default:
- return -EINVAL;
+ rc = generic_mii_ioctl(&np->mii_if, if_mii(ifr),
+ cmd, NULL);
+ break;
}
spin_unlock(&np->lock);
- return 0;
+ return rc;
}
-static int e100_set_settings(struct net_device *dev,
- struct ethtool_cmd *ecmd)
+static int e100_get_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
{
- ecmd->supported = SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
- SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
- ecmd->port = PORT_TP;
- ecmd->transceiver = XCVR_EXTERNAL;
- ecmd->phy_address = mdio_phy_addr;
- ecmd->speed = current_speed;
- ecmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
- ecmd->advertising = ADVERTISED_TP;
+ struct net_local *np = netdev_priv(dev);
+ int err;
- if (current_duplex == autoneg && current_speed_selection == 0)
- ecmd->advertising |= ADVERTISED_Autoneg;
- else {
- ecmd->advertising |=
- ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
- if (current_speed_selection == 10)
- ecmd->advertising &= ~(ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full);
- else if (current_speed_selection == 100)
- ecmd->advertising &= ~(ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full);
- if (current_duplex == half)
- ecmd->advertising &= ~(ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Full);
- else if (current_duplex == full)
- ecmd->advertising &= ~(ADVERTISED_10baseT_Half |
- ADVERTISED_100baseT_Half);
- }
+ spin_lock_irq(&np->lock);
+ err = mii_ethtool_gset(&np->mii_if, cmd);
+ spin_unlock_irq(&np->lock);
- ecmd->autoneg = AUTONEG_ENABLE;
- return 0;
+ /* The PHY may support 1000baseT, but the Etrax100 does not. */
+ cmd->supported &= ~(SUPPORTED_1000baseT_Half
+ | SUPPORTED_1000baseT_Full);
+ return err;
}
static int e100_set_settings(struct net_device *dev,
@@ -1564,7 +1672,8 @@ static const struct ethtool_ops e100_ethtool_ops = {
static int
e100_set_config(struct net_device *dev, struct ifmap *map)
{
- struct net_local *np = (struct net_local *)dev->priv;
+ struct net_local *np = netdev_priv(dev);
+
spin_lock(&np->lock); /* Preempt protection */
switch(map->port) {
@@ -1616,7 +1725,6 @@ update_tx_stats(struct net_device_stats *es)
es->collisions +=
IO_EXTRACT(R_TR_COUNTERS, single_col, r) +
IO_EXTRACT(R_TR_COUNTERS, multiple_col, r);
- es->tx_errors += IO_EXTRACT(R_TR_COUNTERS, deferred, r);
}
/*
@@ -1626,8 +1734,9 @@ update_tx_stats(struct net_device_stats *es)
static struct net_device_stats *
e100_get_stats(struct net_device *dev)
{
- struct net_local *lp = (struct net_local *)dev->priv;
+ struct net_local *lp = netdev_priv(dev);
unsigned long flags;
+
spin_lock_irqsave(&lp->lock, flags);
update_rx_stats(&lp->stats);
@@ -1647,13 +1756,13 @@ e100_get_stats(struct net_device *dev)
static void
set_multicast_list(struct net_device *dev)
{
- struct net_local *lp = (struct net_local *)dev->priv;
+ struct net_local *lp = netdev_priv(dev);
int num_addr = dev->mc_count;
unsigned long int lo_bits;
unsigned long int hi_bits;
+
spin_lock(&lp->lock);
- if (dev->flags & IFF_PROMISC)
- {
+ if (dev->flags & IFF_PROMISC) {
/* promiscuous mode */
lo_bits = 0xfffffffful;
hi_bits = 0xfffffffful;
@@ -1683,9 +1792,10 @@ set_multicast_list(struct net_device *dev)
struct dev_mc_list *dmi = dev->mc_list;
int i;
char *baddr;
+
lo_bits = 0x00000000ul;
hi_bits = 0x00000000ul;
- for (i=0; i<num_addr; i++) {
+ for (i = 0; i < num_addr; i++) {
/* Calculate the hash index for the GA registers */
hash_ix = 0;
@@ -1712,8 +1822,7 @@ set_multicast_list(struct net_device *dev)
if (hash_ix >= 32) {
hi_bits |= (1 << (hash_ix-32));
- }
- else {
+ } else {
lo_bits |= (1 << hash_ix);
}
dmi = dmi->next;
@@ -1728,10 +1837,11 @@ set_multicast_list(struct net_device *dev)
}
void
-e100_hardware_send_packet(char *buf, int length)
+e100_hardware_send_packet(struct net_local *np, char *buf, int length)
{
D(printk("e100 send pack, buf 0x%x len %d\n", buf, length));
+ spin_lock(&np->led_lock);
if (!led_active && time_after(jiffies, led_next_time)) {
/* light the network leds depending on the current speed. */
e100_set_network_leds(NETWORK_ACTIVITY);
@@ -1741,6 +1851,7 @@ e100_hardware_send_packet(char *buf, int length)
led_active = 1;
mod_timer(&clear_led_timer, jiffies + HZ/10);
}
+ spin_unlock(&np->led_lock);
/* configure the tx dma descriptor */
myNextTxDesc->descr.sw_len = length;
@@ -1758,6 +1869,11 @@ e100_hardware_send_packet(char *buf, int length)
static void
e100_clear_network_leds(unsigned long dummy)
{
+ struct net_device *dev = (struct net_device *)dummy;
+ struct net_local *np = netdev_priv(dev);
+
+ spin_lock(&np->led_lock);
+
if (led_active && time_after(jiffies, led_next_time)) {
e100_set_network_leds(NO_NETWORK_ACTIVITY);
@@ -1765,6 +1881,8 @@ e100_clear_network_leds(unsigned long dummy)
led_next_time = jiffies + NET_FLASH_PAUSE;
led_active = 0;
}
+
+ spin_unlock(&np->led_lock);
}
static void
@@ -1785,19 +1903,25 @@ e100_set_network_leds(int active)
#else
LED_NETWORK_SET(LED_OFF);
#endif
- }
- else if (light_leds) {
+ } else if (light_leds) {
if (current_speed == 10) {
LED_NETWORK_SET(LED_ORANGE);
} else {
LED_NETWORK_SET(LED_GREEN);
}
- }
- else {
+ } else {
LED_NETWORK_SET(LED_OFF);
}
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void
+e100_netpoll(struct net_device* netdev)
+{
+ e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev, NULL);
+}
+#endif
+
static int
etrax_init_module(void)
{
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 9774bb1b3e8..57175097513 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -516,8 +516,8 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
unsigned rev_type = 0;
int eeprom_buff[CHKSUM_LEN];
int retval;
+ DECLARE_MAC_BUF(mac);
- SET_MODULE_OWNER(dev);
/* Initialize the device structure. */
if (!modular) {
memset(lp, 0, sizeof(*lp));
@@ -806,7 +806,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
i = cs8900_irq_map[0];
#else
/* Translate the IRQ using the IRQ mapping table. */
- if (i >= sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))
+ if (i >= ARRAY_SIZE(cs8900_irq_map))
printk("\ncs89x0: invalid ISA interrupt number %d\n", i);
else
i = cs8900_irq_map[i];
@@ -841,11 +841,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
}
/* print the ethernet address. */
- printk(", MAC");
- for (i = 0; i < ETH_ALEN; i++)
- {
- printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
- }
+ printk(", MAC %s", print_mac(mac, dev->dev_addr));
dev->open = net_open;
dev->stop = net_close;
@@ -1247,11 +1243,11 @@ write_irq(struct net_device *dev, int chip_type, int irq)
if (chip_type == CS8900) {
/* Search the mapping table for the corresponding IRQ pin. */
- for (i = 0; i != sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]); i++)
+ for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++)
if (cs8900_irq_map[i] == irq)
break;
/* Not found */
- if (i == sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))
+ if (i == ARRAY_SIZE(cs8900_irq_map))
i = 3;
writereg(dev, PP_CS8900_ISAINT, i);
} else {
@@ -1807,17 +1803,15 @@ static int set_mac_address(struct net_device *dev, void *p)
int i;
struct sockaddr *addr = p;
-
if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
if (net_debug) {
- printk("%s: Setting MAC address to ", dev->name);
- for (i = 0; i < dev->addr_len; i++)
- printk(" %2.2x", dev->dev_addr[i]);
- printk(".\n");
+ DECLARE_MAC_BUF(mac);
+ printk("%s: Setting MAC address to %s.\n",
+ dev->name, print_mac(mac, dev->dev_addr));
}
/* set the Ethernet address */
for (i=0; i < ETH_ALEN/2; i++)
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 20e887de254..60a62f510db 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -41,19 +41,19 @@
#include <linux/timer.h>
#include <linux/cache.h>
#include <linux/mutex.h>
+#include <linux/bitops.h>
#include "t3cdev.h"
#include <asm/semaphore.h>
-#include <asm/bitops.h>
#include <asm/io.h>
-typedef irqreturn_t(*intr_handler_t) (int, void *);
-
struct vlan_group;
-
struct adapter;
+struct sge_qset;
+
struct port_info {
struct adapter *adapter;
struct vlan_group *vlan_grp;
+ struct sge_qset *qs;
const struct port_type_info *port_type;
u8 port_id;
u8 rx_csum_offload;
@@ -173,10 +173,12 @@ enum { /* per port SGE statistics */
};
struct sge_qset { /* an SGE queue set */
+ struct adapter *adap;
+ struct napi_struct napi;
struct sge_rspq rspq;
struct sge_fl fl[SGE_RXQ_PER_SET];
struct sge_txq txq[SGE_TXQ_PER_SET];
- struct net_device *netdev; /* associated net device */
+ struct net_device *netdev;
unsigned long txq_stopped; /* which Tx queues are stopped */
struct timer_list tx_reclaim_timer; /* reclaims TX buffers */
unsigned long port_stats[SGE_PSTAT_MAX];
@@ -221,12 +223,6 @@ struct adapter {
struct delayed_work adap_check_task;
struct work_struct ext_intr_handler_task;
- /*
- * Dummy netdevices are needed when using multiple receive queues with
- * NAPI as each netdevice can service only one queue.
- */
- struct net_device *dummy_netdev[SGE_QSETS - 1];
-
struct dentry *debugfs_root;
struct mutex mdio_lock;
@@ -253,12 +249,6 @@ static inline struct port_info *adap2pinfo(struct adapter *adap, int idx)
return netdev_priv(adap->port[idx]);
}
-/*
- * We use the spare atalk_ptr to map a net device to its SGE queue set.
- * This is a macro so it can be used as l-value.
- */
-#define dev2qset(netdev) ((netdev)->atalk_ptr)
-
#define OFFLOAD_DEVMAP_BIT 15
#define tdev2adap(d) container_of(d, struct adapter, tdev)
@@ -278,13 +268,13 @@ void t3_sge_start(struct adapter *adap);
void t3_sge_stop(struct adapter *adap);
void t3_free_sge_resources(struct adapter *adap);
void t3_sge_err_intr_handler(struct adapter *adapter);
-intr_handler_t t3_intr_handler(struct adapter *adap, int polling);
+irq_handler_t t3_intr_handler(struct adapter *adap, int polling);
int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev);
int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb);
void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p);
int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
int irq_vec_idx, const struct qset_params *p,
- int ntxq, struct net_device *netdev);
+ int ntxq, struct net_device *dev);
int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
unsigned char *data);
irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 2129210a67c..99c75d30f67 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -97,6 +97,7 @@ enum {
MAX_NPORTS = 2, /* max # of ports */
MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */
EEPROMSIZE = 8192, /* Serial EEPROM size */
+ SERNUM_LEN = 16, /* Serial # length */
RSS_TABLE_SIZE = 64, /* size of RSS lookup and mapping tables */
TCB_SIZE = 128, /* TCB size */
NMTUS = 16, /* size of MTU table */
@@ -104,7 +105,7 @@ enum {
PROTO_SRAM_LINES = 128, /* size of TP sram */
};
-#define MAX_RX_COALESCING_LEN 16224U
+#define MAX_RX_COALESCING_LEN 12288U
enum {
PAUSE_RX = 1 << 0,
@@ -126,8 +127,8 @@ enum { /* adapter interrupt-maintained statistics */
enum {
TP_VERSION_MAJOR = 1,
- TP_VERSION_MINOR = 0,
- TP_VERSION_MICRO = 44
+ TP_VERSION_MINOR = 1,
+ TP_VERSION_MICRO = 0
};
#define S_TP_VERSION_MAJOR 16
@@ -167,8 +168,8 @@ enum {
};
struct sg_ent { /* SGE scatter/gather entry */
- u32 len[2];
- u64 addr[2];
+ __be32 len[2];
+ __be64 addr[2];
};
#ifndef SGE_NUM_GENBITS
@@ -391,6 +392,7 @@ struct vpd_params {
unsigned int uclk;
unsigned int mdc;
unsigned int mem_timing;
+ u8 sn[SERNUM_LEN + 1];
u8 eth_base[6];
u8 port_type[MAX_NPORTS];
unsigned short xauicfg[2];
@@ -436,6 +438,7 @@ enum { /* chip revisions */
T3_REV_A = 0,
T3_REV_B = 2,
T3_REV_B2 = 3,
+ T3_REV_C = 4,
};
struct trace_params {
@@ -507,9 +510,11 @@ struct cmac {
unsigned int tx_xcnt;
u64 tx_mcnt;
unsigned int rx_xcnt;
+ unsigned int rx_ocnt;
u64 rx_mcnt;
unsigned int toggle_cnt;
unsigned int txen;
+ u64 rx_pause;
struct mac_stats stats;
};
@@ -687,7 +692,7 @@ int t3_read_flash(struct adapter *adapter, unsigned int addr,
unsigned int nwords, u32 *data, int byte_oriented);
int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size);
int t3_get_fw_version(struct adapter *adapter, u32 *vers);
-int t3_check_fw_version(struct adapter *adapter);
+int t3_check_fw_version(struct adapter *adapter, int *must_load);
int t3_init_hw(struct adapter *adapter, u32 fw_params);
void mac_prep(struct cmac *mac, struct adapter *adapter, int index);
void early_hw_init(struct adapter *adapter, const struct adapter_info *ai);
diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h
index 2095ddacff7..6c4f3206691 100644
--- a/drivers/net/cxgb3/cxgb3_ctl_defs.h
+++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h
@@ -33,27 +33,29 @@
#define _CXGB3_OFFLOAD_CTL_DEFS_H
enum {
- GET_MAX_OUTSTANDING_WR,
- GET_TX_MAX_CHUNK,
- GET_TID_RANGE,
- GET_STID_RANGE,
- GET_RTBL_RANGE,
- GET_L2T_CAPACITY,
- GET_MTUS,
- GET_WR_LEN,
- GET_IFF_FROM_MAC,
- GET_DDP_PARAMS,
- GET_PORTS,
-
- ULP_ISCSI_GET_PARAMS,
- ULP_ISCSI_SET_PARAMS,
-
- RDMA_GET_PARAMS,
- RDMA_CQ_OP,
- RDMA_CQ_SETUP,
- RDMA_CQ_DISABLE,
- RDMA_CTRL_QP_SETUP,
- RDMA_GET_MEM,
+ GET_MAX_OUTSTANDING_WR = 0,
+ GET_TX_MAX_CHUNK = 1,
+ GET_TID_RANGE = 2,
+ GET_STID_RANGE = 3,
+ GET_RTBL_RANGE = 4,
+ GET_L2T_CAPACITY = 5,
+ GET_MTUS = 6,
+ GET_WR_LEN = 7,
+ GET_IFF_FROM_MAC = 8,
+ GET_DDP_PARAMS = 9,
+ GET_PORTS = 10,
+
+ ULP_ISCSI_GET_PARAMS = 11,
+ ULP_ISCSI_SET_PARAMS = 12,
+
+ RDMA_GET_PARAMS = 13,
+ RDMA_CQ_OP = 14,
+ RDMA_CQ_SETUP = 15,
+ RDMA_CQ_DISABLE = 16,
+ RDMA_CTRL_QP_SETUP = 17,
+ RDMA_GET_MEM = 18,
+
+ GET_RX_PAGE_INFO = 50,
};
/*
@@ -161,4 +163,12 @@ struct rdma_ctrlqp_setup {
unsigned long long base_addr;
unsigned int size;
};
+
+/*
+ * Offload TX/RX page information.
+ */
+struct ofld_page_info {
+ unsigned int page_size; /* Page size, should be a power of 2 */
+ unsigned int num; /* Number of pages */
+};
#endif /* _CXGB3_OFFLOAD_CTL_DEFS_H */
diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h
index 483a594210a..45e92164c26 100644
--- a/drivers/net/cxgb3/cxgb3_defs.h
+++ b/drivers/net/cxgb3/cxgb3_defs.h
@@ -79,9 +79,17 @@ static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t,
static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t,
unsigned int tid)
{
+ union listen_entry *e;
+
if (tid < t->stid_base || tid >= t->stid_base + t->nstids)
return NULL;
- return &(stid2entry(t, tid)->t3c_tid);
+
+ e = stid2entry(t, tid);
+ if ((void *)e->next >= (void *)t->tid_tab &&
+ (void *)e->next < (void *)&t->atid_tab[t->natids])
+ return NULL;
+
+ return &e->t3c_tid;
}
/*
@@ -90,9 +98,17 @@ static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t,
static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t,
unsigned int tid)
{
+ union active_open_entry *e;
+
if (tid < t->atid_base || tid >= t->atid_base + t->natids)
return NULL;
- return &(atid2entry(t, tid)->t3c_tid);
+
+ e = atid2entry(t, tid);
+ if ((void *)e->next >= (void *)t->tid_tab &&
+ (void *)e->next < (void *)&t->atid_tab[t->natids])
+ return NULL;
+
+ return &e->t3c_tid;
}
int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n);
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 5ab319cfe5d..61ffc925eae 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -339,49 +339,17 @@ static void setup_rss(struct adapter *adap)
V_RRCPLCPUSIZE(6), cpus, rspq_map);
}
-/*
- * If we have multiple receive queues per port serviced by NAPI we need one
- * netdevice per queue as NAPI operates on netdevices. We already have one
- * netdevice, namely the one associated with the interface, so we use dummy
- * ones for any additional queues. Note that these netdevices exist purely
- * so that NAPI has something to work with, they do not represent network
- * ports and are not registered.
- */
-static int init_dummy_netdevs(struct adapter *adap)
+static void init_napi(struct adapter *adap)
{
- int i, j, dummy_idx = 0;
- struct net_device *nd;
-
- for_each_port(adap, i) {
- struct net_device *dev = adap->port[i];
- const struct port_info *pi = netdev_priv(dev);
-
- for (j = 0; j < pi->nqsets - 1; j++) {
- if (!adap->dummy_netdev[dummy_idx]) {
- struct port_info *p;
-
- nd = alloc_netdev(sizeof(*p), "", ether_setup);
- if (!nd)
- goto free_all;
+ int i;
- p = netdev_priv(nd);
- p->adapter = adap;
- nd->weight = 64;
- set_bit(__LINK_STATE_START, &nd->state);
- adap->dummy_netdev[dummy_idx] = nd;
- }
- strcpy(adap->dummy_netdev[dummy_idx]->name, dev->name);
- dummy_idx++;
- }
- }
- return 0;
+ for (i = 0; i < SGE_QSETS; i++) {
+ struct sge_qset *qs = &adap->sge.qs[i];
-free_all:
- while (--dummy_idx >= 0) {
- free_netdev(adap->dummy_netdev[dummy_idx]);
- adap->dummy_netdev[dummy_idx] = NULL;
+ if (qs->adap)
+ netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll,
+ 64);
}
- return -ENOMEM;
}
/*
@@ -392,20 +360,18 @@ free_all:
static void quiesce_rx(struct adapter *adap)
{
int i;
- struct net_device *dev;
- for_each_port(adap, i) {
- dev = adap->port[i];
- while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
- msleep(1);
- }
+ for (i = 0; i < SGE_QSETS; i++)
+ if (adap->sge.qs[i].adap)
+ napi_disable(&adap->sge.qs[i].napi);
+}
- for (i = 0; i < ARRAY_SIZE(adap->dummy_netdev); i++) {
- dev = adap->dummy_netdev[i];
- if (dev)
- while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
- msleep(1);
- }
+static void enable_all_napi(struct adapter *adap)
+{
+ int i;
+ for (i = 0; i < SGE_QSETS; i++)
+ if (adap->sge.qs[i].adap)
+ napi_enable(&adap->sge.qs[i].napi);
}
/**
@@ -418,7 +384,7 @@ static void quiesce_rx(struct adapter *adap)
*/
static int setup_sge_qsets(struct adapter *adap)
{
- int i, j, err, irq_idx = 0, qset_idx = 0, dummy_dev_idx = 0;
+ int i, j, err, irq_idx = 0, qset_idx = 0;
unsigned int ntxq = SGE_TXQ_PER_SET;
if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
@@ -426,15 +392,14 @@ static int setup_sge_qsets(struct adapter *adap)
for_each_port(adap, i) {
struct net_device *dev = adap->port[i];
- const struct port_info *pi = netdev_priv(dev);
+ struct port_info *pi = netdev_priv(dev);
+ pi->qs = &adap->sge.qs[pi->first_qset];
for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
err = t3_sge_alloc_qset(adap, qset_idx, 1,
(adap->flags & USING_MSIX) ? qset_idx + 1 :
irq_idx,
- &adap->params.sge.qset[qset_idx], ntxq,
- j == 0 ? dev :
- adap-> dummy_netdev[dummy_dev_idx++]);
+ &adap->params.sge.qset[qset_idx], ntxq, dev);
if (err) {
t3_free_sge_resources(adap);
return err;
@@ -768,11 +733,14 @@ static inline char t3rev2char(struct adapter *adapter)
case T3_REV_B2:
rev = 'b';
break;
+ case T3_REV_C:
+ rev = 'c';
+ break;
}
return rev;
}
-int update_tpsram(struct adapter *adap)
+static int update_tpsram(struct adapter *adap)
{
const struct firmware *tpsram;
char buf[64];
@@ -828,15 +796,16 @@ release_tpsram:
*/
static int cxgb_up(struct adapter *adap)
{
- int err = 0;
+ int err;
int must_load;
if (!(adap->flags & FULL_INIT_DONE)) {
- err = t3_check_fw_version(adap);
- if (err == -EINVAL)
+ err = t3_check_fw_version(adap, &must_load);
+ if (err == -EINVAL) {
err = upgrade_fw(adap);
- if (err)
- goto out;
+ if (err && must_load)
+ goto out;
+ }
err = t3_check_tpsram_version(adap, &must_load);
if (err == -EINVAL) {
@@ -845,21 +814,18 @@ static int cxgb_up(struct adapter *adap)
goto out;
}
- err = init_dummy_netdevs(adap);
- if (err)
- goto out;
-
err = t3_init_hw(adap, 0);
if (err)
goto out;
t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
-
+
err = setup_sge_qsets(adap);
if (err)
goto out;
setup_rss(adap);
+ init_napi(adap);
adap->flags |= FULL_INIT_DONE;
}
@@ -886,6 +852,7 @@ static int cxgb_up(struct adapter *adap)
adap->name, adap)))
goto irq_err;
+ enable_all_napi(adap);
t3_sge_start(adap);
t3_intr_enable(adap);
@@ -944,7 +911,7 @@ static int offload_open(struct net_device *dev)
struct adapter *adapter = pi->adapter;
struct t3cdev *tdev = dev2t3cdev(dev);
int adap_up = adapter->open_device_map & PORT_MASK;
- int err = 0;
+ int err;
if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
return 0;
@@ -1012,8 +979,10 @@ static int cxgb_open(struct net_device *dev)
int other_ports = adapter->open_device_map & PORT_MASK;
int err;
- if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
+ if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) {
+ quiesce_rx(adapter);
return err;
+ }
set_bit(pi->port_id, &adapter->open_device_map);
if (is_offload(adapter) && !ofld_disable) {
@@ -1162,9 +1131,14 @@ static char stats_strings[][ETH_GSTRING_LEN] = {
};
-static int get_stats_count(struct net_device *dev)
+static int get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(stats_strings);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(stats_strings);
+ default:
+ return -EOPNOTSUPP;
+ }
}
#define T3_REGMAP_SIZE (3 * 1024)
@@ -1601,7 +1575,7 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
struct adapter *adapter = pi->adapter;
u32 aligned_offset, aligned_len, *p;
u8 *buf;
- int err = 0;
+ int err;
if (eeprom->magic != EEPROM_MAGIC)
return -EINVAL;
@@ -1665,20 +1639,17 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
.set_pauseparam = set_pauseparam,
.get_rx_csum = get_rx_csum,
.set_rx_csum = set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_link = ethtool_op_get_link,
.get_strings = get_strings,
.phys_id = cxgb3_phys_id,
.nway_reset = restart_autoneg,
- .get_stats_count = get_stats_count,
+ .get_sset_count = get_sset_count,
.get_ethtool_stats = get_stats,
.get_regs_len = get_regs_len,
.get_regs = get_regs,
.get_wol = get_wol,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
};
@@ -1798,7 +1769,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
}
case CHELSIO_SET_QSET_NUM:{
struct ch_reg edata;
- struct port_info *pi = netdev_priv(dev);
unsigned int i, first_qset = 0, other_qsets = 0;
if (!capable(CAP_NET_ADMIN))
@@ -1830,7 +1800,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
}
case CHELSIO_GET_QSET_NUM:{
struct ch_reg edata;
- struct port_info *pi = netdev_priv(dev);
edata.cmd = CHELSIO_GET_QSET_NUM;
edata.val = pi->nqsets;
@@ -2332,6 +2301,10 @@ void t3_fatal_err(struct adapter *adapter)
if (adapter->flags & FULL_INIT_DONE) {
t3_sge_stop(adapter);
+ t3_write_reg(adapter, A_XGM_TX_CTRL, 0);
+ t3_write_reg(adapter, A_XGM_RX_CTRL, 0);
+ t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0);
+ t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0);
t3_intr_disable(adapter);
}
CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
@@ -2391,10 +2364,12 @@ static void __devinit print_port_info(struct adapter *adap,
(adap->flags & USING_MSIX) ? " MSI-X" :
(adap->flags & USING_MSI) ? " MSI" : "");
if (adap->name == dev->name && adap->params.vpd.mclk)
- printk(KERN_INFO "%s: %uMB CM, %uMB PMTX, %uMB PMRX\n",
+ printk(KERN_INFO
+ "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
adap->name, t3_mc7_size(&adap->cm) >> 20,
t3_mc7_size(&adap->pmtx) >> 20,
- t3_mc7_size(&adap->pmrx) >> 20);
+ t3_mc7_size(&adap->pmrx) >> 20,
+ adap->params.vpd.sn);
}
}
@@ -2490,7 +2465,6 @@ static int __devinit init_one(struct pci_dev *pdev,
goto out_free_dev;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
adapter->port[i] = netdev;
@@ -2524,7 +2498,6 @@ static int __devinit init_one(struct pci_dev *pdev,
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = cxgb_netpoll;
#endif
- netdev->weight = 64;
SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
}
@@ -2625,12 +2598,6 @@ static void __devexit remove_one(struct pci_dev *pdev)
t3_free_sge_resources(adapter);
cxgb_disable_msi(adapter);
- for (i = 0; i < ARRAY_SIZE(adapter->dummy_netdev); i++)
- if (adapter->dummy_netdev[i]) {
- free_netdev(adapter->dummy_netdev[i]);
- adapter->dummy_netdev[i] = NULL;
- }
-
for_each_port(adapter, i)
if (adapter->port[i])
free_netdev(adapter->port[i]);
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index bdff7baeb59..bd25421bc12 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -57,7 +57,7 @@ static DEFINE_RWLOCK(adapter_list_lock);
static LIST_HEAD(adapter_list);
static const unsigned int MAX_ATIDS = 64 * 1024;
-static const unsigned int ATID_BASE = 0x100000;
+static const unsigned int ATID_BASE = 0x10000;
static inline int offload_activated(struct t3cdev *tdev)
{
@@ -222,32 +222,32 @@ static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data)
int ret = 0;
switch (req) {
- case RDMA_GET_PARAMS:{
- struct rdma_info *req = data;
+ case RDMA_GET_PARAMS: {
+ struct rdma_info *rdma = data;
struct pci_dev *pdev = adapter->pdev;
- req->udbell_physbase = pci_resource_start(pdev, 2);
- req->udbell_len = pci_resource_len(pdev, 2);
- req->tpt_base =
+ rdma->udbell_physbase = pci_resource_start(pdev, 2);
+ rdma->udbell_len = pci_resource_len(pdev, 2);
+ rdma->tpt_base =
t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT);
- req->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT);
- req->pbl_base =
+ rdma->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT);
+ rdma->pbl_base =
t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT);
- req->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT);
- req->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT);
- req->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT);
- req->kdb_addr = adapter->regs + A_SG_KDOORBELL;
- req->pdev = pdev;
+ rdma->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT);
+ rdma->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT);
+ rdma->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT);
+ rdma->kdb_addr = adapter->regs + A_SG_KDOORBELL;
+ rdma->pdev = pdev;
break;
}
case RDMA_CQ_OP:{
unsigned long flags;
- struct rdma_cq_op *req = data;
+ struct rdma_cq_op *rdma = data;
/* may be called in any context */
spin_lock_irqsave(&adapter->sge.reg_lock, flags);
- ret = t3_sge_cqcntxt_op(adapter, req->id, req->op,
- req->credits);
+ ret = t3_sge_cqcntxt_op(adapter, rdma->id, rdma->op,
+ rdma->credits);
spin_unlock_irqrestore(&adapter->sge.reg_lock, flags);
break;
}
@@ -274,15 +274,15 @@ static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data)
break;
}
case RDMA_CQ_SETUP:{
- struct rdma_cq_setup *req = data;
+ struct rdma_cq_setup *rdma = data;
spin_lock_irq(&adapter->sge.reg_lock);
ret =
- t3_sge_init_cqcntxt(adapter, req->id,
- req->base_addr, req->size,
+ t3_sge_init_cqcntxt(adapter, rdma->id,
+ rdma->base_addr, rdma->size,
ASYNC_NOTIF_RSPQ,
- req->ovfl_mode, req->credits,
- req->credit_thres);
+ rdma->ovfl_mode, rdma->credits,
+ rdma->credit_thres);
spin_unlock_irq(&adapter->sge.reg_lock);
break;
}
@@ -292,13 +292,13 @@ static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data)
spin_unlock_irq(&adapter->sge.reg_lock);
break;
case RDMA_CTRL_QP_SETUP:{
- struct rdma_ctrlqp_setup *req = data;
+ struct rdma_ctrlqp_setup *rdma = data;
spin_lock_irq(&adapter->sge.reg_lock);
ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0,
SGE_CNTXT_RDMA,
ASYNC_NOTIF_RSPQ,
- req->base_addr, req->size,
+ rdma->base_addr, rdma->size,
FW_RI_TID_START, 1, 0);
spin_unlock_irq(&adapter->sge.reg_lock);
break;
@@ -317,6 +317,8 @@ static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data)
struct iff_mac *iffmacp;
struct ddp_params *ddpp;
struct adap_ports *ports;
+ struct ofld_page_info *rx_page_info;
+ struct tp_params *tp = &adapter->params.tp;
int i;
switch (req) {
@@ -382,6 +384,11 @@ static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data)
if (!offload_running(adapter))
return -EAGAIN;
return cxgb_rdma_ctl(adapter, req, data);
+ case GET_RX_PAGE_INFO:
+ rx_page_info = data;
+ rx_page_info->page_size = tp->rx_pg_size;
+ rx_page_info->num = tp->rx_num_pgs;
+ break;
default:
return -EOPNOTSUPP;
}
@@ -687,10 +694,19 @@ static int do_cr(struct t3cdev *dev, struct sk_buff *skb)
{
struct cpl_pass_accept_req *req = cplhdr(skb);
unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+ struct tid_info *t = &(T3C_DATA(dev))->tid_maps;
struct t3c_tid_entry *t3c_tid;
+ unsigned int tid = GET_TID(req);
- t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
- if (t3c_tid->ctx && t3c_tid->client->handlers &&
+ if (unlikely(tid >= t->ntids)) {
+ printk("%s: passive open TID %u too large\n",
+ dev->name, tid);
+ t3_fatal_err(tdev2adap(dev));
+ return CPL_RET_BUF_DONE;
+ }
+
+ t3c_tid = lookup_stid(t, stid);
+ if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) {
return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
(dev, skb, t3c_tid->ctx);
@@ -772,16 +788,25 @@ static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb)
{
struct cpl_act_establish *req = cplhdr(skb);
unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+ struct tid_info *t = &(T3C_DATA(dev))->tid_maps;
struct t3c_tid_entry *t3c_tid;
+ unsigned int tid = GET_TID(req);
- t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+ if (unlikely(tid >= t->ntids)) {
+ printk("%s: active establish TID %u too large\n",
+ dev->name, tid);
+ t3_fatal_err(tdev2adap(dev));
+ return CPL_RET_BUF_DONE;
+ }
+
+ t3c_tid = lookup_atid(t, atid);
if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) {
return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
(dev, skb, t3c_tid->ctx);
} else {
printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
- dev->name, CPL_PASS_ACCEPT_REQ);
+ dev->name, CPL_ACT_ESTABLISH);
return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
}
}
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
index aa80313c922..5e1bc0dec5f 100644
--- a/drivers/net/cxgb3/regs.h
+++ b/drivers/net/cxgb3/regs.h
@@ -172,6 +172,14 @@
#define A_SG_INT_CAUSE 0x5c
+#define S_HIPIODRBDROPERR 11
+#define V_HIPIODRBDROPERR(x) ((x) << S_HIPIODRBDROPERR)
+#define F_HIPIODRBDROPERR V_HIPIODRBDROPERR(1U)
+
+#define S_LOPIODRBDROPERR 10
+#define V_LOPIODRBDROPERR(x) ((x) << S_LOPIODRBDROPERR)
+#define F_LOPIODRBDROPERR V_LOPIODRBDROPERR(1U)
+
#define S_RSPQDISABLED 3
#define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED)
#define F_RSPQDISABLED V_RSPQDISABLED(1U)
@@ -1318,6 +1326,7 @@
#define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT)
#define A_PM1_RX_CFG 0x5c0
+#define A_PM1_RX_MODE 0x5c4
#define A_PM1_RX_INT_ENABLE 0x5d8
@@ -1386,6 +1395,7 @@
#define A_PM1_RX_INT_CAUSE 0x5dc
#define A_PM1_TX_CFG 0x5e0
+#define A_PM1_TX_MODE 0x5e4
#define A_PM1_TX_INT_ENABLE 0x5f8
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 58a5f60521e..c15e43a8543 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -79,7 +79,7 @@ enum {
};
struct tx_desc {
- u64 flit[TX_DESC_FLITS];
+ __be64 flit[TX_DESC_FLITS];
};
struct rx_desc {
@@ -544,7 +544,7 @@ static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size,
* as HW contexts, packet buffers, and descriptor rings. Traffic to the
* queue set must be quiesced prior to calling this.
*/
-void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
+static void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
{
int i;
struct pci_dev *pdev = adapter->pdev;
@@ -591,9 +591,6 @@ void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
q->rspq.desc, q->rspq.phys_addr);
}
- if (q->netdev)
- q->netdev->atalk_ptr = NULL;
-
memset(q, 0, sizeof(*q));
}
@@ -907,8 +904,8 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb,
const struct sge_txq *q,
const struct sg_ent *sgl,
unsigned int flits, unsigned int sgl_flits,
- unsigned int gen, unsigned int wr_hi,
- unsigned int wr_lo)
+ unsigned int gen, __be32 wr_hi,
+ __be32 wr_lo)
{
struct work_request_hdr *wrp = (struct work_request_hdr *)d;
struct tx_sw_desc *sd = &q->sdesc[pidx];
@@ -1074,7 +1071,7 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned int ndesc, pidx, credits, gen, compl;
const struct port_info *pi = netdev_priv(dev);
struct adapter *adap = pi->adapter;
- struct sge_qset *qs = dev2qset(dev);
+ struct sge_qset *qs = pi->qs;
struct sge_txq *q = &qs->txq[TXQ_ETH];
/*
@@ -1182,8 +1179,8 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
*
* Writes a packet as immediate data into a Tx descriptor. The packet
* contains a work request at its beginning. We must write the packet
- * carefully so the SGE doesn't read accidentally before it's written in
- * its entirety.
+ * carefully so the SGE doesn't read it accidentally before it's written
+ * in its entirety.
*/
static inline void write_imm(struct tx_desc *d, struct sk_buff *skb,
unsigned int len, unsigned int gen)
@@ -1191,7 +1188,11 @@ static inline void write_imm(struct tx_desc *d, struct sk_buff *skb,
struct work_request_hdr *from = (struct work_request_hdr *)skb->data;
struct work_request_hdr *to = (struct work_request_hdr *)d;
- memcpy(&to[1], &from[1], len - sizeof(*from));
+ if (likely(!skb->data_len))
+ memcpy(&to[1], &from[1], len - sizeof(*from));
+ else
+ skb_copy_bits(skb, sizeof(*from), &to[1], len - sizeof(*from));
+
to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP |
V_WR_BCNTLFLT(len & 7));
wmb();
@@ -1261,7 +1262,7 @@ static inline void reclaim_completed_tx_imm(struct sge_txq *q)
static inline int immediate(const struct sk_buff *skb)
{
- return skb->len <= WR_LEN && !skb->data_len;
+ return skb->len <= WR_LEN;
}
/**
@@ -1326,13 +1327,12 @@ static void restart_ctrlq(unsigned long data)
struct sk_buff *skb;
struct sge_qset *qs = (struct sge_qset *)data;
struct sge_txq *q = &qs->txq[TXQ_CTRL];
- const struct port_info *pi = netdev_priv(qs->netdev);
- struct adapter *adap = pi->adapter;
spin_lock(&q->lock);
again:reclaim_completed_tx_imm(q);
- while (q->in_use < q->size && (skb = __skb_dequeue(&q->sendq)) != NULL) {
+ while (q->in_use < q->size &&
+ (skb = __skb_dequeue(&q->sendq)) != NULL) {
write_imm(&q->desc[q->pidx], skb, skb->len, q->gen);
@@ -1354,7 +1354,7 @@ static void restart_ctrlq(unsigned long data)
}
spin_unlock(&q->lock);
- t3_write_reg(adap, A_SG_KDOORBELL,
+ t3_write_reg(qs->adap, A_SG_KDOORBELL,
F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
}
@@ -1468,12 +1468,13 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
*/
static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb)
{
- unsigned int flits, cnt = skb_shinfo(skb)->nr_frags;
+ unsigned int flits, cnt;
- if (skb->len <= WR_LEN && cnt == 0)
+ if (skb->len <= WR_LEN)
return 1; /* packet fits as immediate data */
flits = skb_transport_offset(skb) / 8; /* headers */
+ cnt = skb_shinfo(skb)->nr_frags;
if (skb->tail != skb->transport_header)
cnt++;
return flits_to_desc(flits + sgl_len(cnt));
@@ -1638,8 +1639,7 @@ static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb)
else {
struct sge_qset *qs = rspq_to_qset(q);
- if (__netif_rx_schedule_prep(qs->netdev))
- __netif_rx_schedule(qs->netdev);
+ napi_schedule(&qs->napi);
q->rx_head = skb;
}
q->rx_tail = skb;
@@ -1675,34 +1675,30 @@ static inline void deliver_partial_bundle(struct t3cdev *tdev,
* receive handler. Batches need to be of modest size as we do prefetches
* on the packets in each.
*/
-static int ofld_poll(struct net_device *dev, int *budget)
+static int ofld_poll(struct napi_struct *napi, int budget)
{
- const struct port_info *pi = netdev_priv(dev);
- struct adapter *adapter = pi->adapter;
- struct sge_qset *qs = dev2qset(dev);
+ struct sge_qset *qs = container_of(napi, struct sge_qset, napi);
struct sge_rspq *q = &qs->rspq;
- int work_done, limit = min(*budget, dev->quota), avail = limit;
+ struct adapter *adapter = qs->adap;
+ int work_done = 0;
- while (avail) {
+ while (work_done < budget) {
struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE];
int ngathered;
spin_lock_irq(&q->lock);
head = q->rx_head;
if (!head) {
- work_done = limit - avail;
- *budget -= work_done;
- dev->quota -= work_done;
- __netif_rx_complete(dev);
+ napi_complete(napi);
spin_unlock_irq(&q->lock);
- return 0;
+ return work_done;
}
tail = q->rx_tail;
q->rx_head = q->rx_tail = NULL;
spin_unlock_irq(&q->lock);
- for (ngathered = 0; avail && head; avail--) {
+ for (ngathered = 0; work_done < budget && head; work_done++) {
prefetch(head->data);
skbs[ngathered] = head;
head = head->next;
@@ -1724,10 +1720,8 @@ static int ofld_poll(struct net_device *dev, int *budget)
}
deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered);
}
- work_done = limit - avail;
- *budget -= work_done;
- dev->quota -= work_done;
- return 1;
+
+ return work_done;
}
/**
@@ -2071,50 +2065,47 @@ static inline int is_pure_response(const struct rsp_desc *r)
/**
* napi_rx_handler - the NAPI handler for Rx processing
- * @dev: the net device
+ * @napi: the napi instance
* @budget: how many packets we can process in this round
*
* Handler for new data events when using NAPI.
*/
-static int napi_rx_handler(struct net_device *dev, int *budget)
+static int napi_rx_handler(struct napi_struct *napi, int budget)
{
- const struct port_info *pi = netdev_priv(dev);
- struct adapter *adap = pi->adapter;
- struct sge_qset *qs = dev2qset(dev);
- int effective_budget = min(*budget, dev->quota);
+ struct sge_qset *qs = container_of(napi, struct sge_qset, napi);
+ struct adapter *adap = qs->adap;
+ int work_done = process_responses(adap, qs, budget);
- int work_done = process_responses(adap, qs, effective_budget);
- *budget -= work_done;
- dev->quota -= work_done;
+ if (likely(work_done < budget)) {
+ napi_complete(napi);
- if (work_done >= effective_budget)
- return 1;
-
- netif_rx_complete(dev);
-
- /*
- * Because we don't atomically flush the following write it is
- * possible that in very rare cases it can reach the device in a way
- * that races with a new response being written plus an error interrupt
- * causing the NAPI interrupt handler below to return unhandled status
- * to the OS. To protect against this would require flushing the write
- * and doing both the write and the flush with interrupts off. Way too
- * expensive and unjustifiable given the rarity of the race.
- *
- * The race cannot happen at all with MSI-X.
- */
- t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) |
- V_NEWTIMER(qs->rspq.next_holdoff) |
- V_NEWINDEX(qs->rspq.cidx));
- return 0;
+ /*
+ * Because we don't atomically flush the following
+ * write it is possible that in very rare cases it can
+ * reach the device in a way that races with a new
+ * response being written plus an error interrupt
+ * causing the NAPI interrupt handler below to return
+ * unhandled status to the OS. To protect against
+ * this would require flushing the write and doing
+ * both the write and the flush with interrupts off.
+ * Way too expensive and unjustifiable given the
+ * rarity of the race.
+ *
+ * The race cannot happen at all with MSI-X.
+ */
+ t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) |
+ V_NEWTIMER(qs->rspq.next_holdoff) |
+ V_NEWINDEX(qs->rspq.cidx));
+ }
+ return work_done;
}
/*
* Returns true if the device is already scheduled for polling.
*/
-static inline int napi_is_scheduled(struct net_device *dev)
+static inline int napi_is_scheduled(struct napi_struct *napi)
{
- return test_bit(__LINK_STATE_RX_SCHED, &dev->state);
+ return test_bit(NAPI_STATE_SCHED, &napi->state);
}
/**
@@ -2197,8 +2188,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q)
V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx));
return 0;
}
- if (likely(__netif_rx_schedule_prep(qs->netdev)))
- __netif_rx_schedule(qs->netdev);
+ napi_schedule(&qs->napi);
return 1;
}
@@ -2209,8 +2199,7 @@ static inline int handle_responses(struct adapter *adap, struct sge_rspq *q)
irqreturn_t t3_sge_intr_msix(int irq, void *cookie)
{
struct sge_qset *qs = cookie;
- const struct port_info *pi = netdev_priv(qs->netdev);
- struct adapter *adap = pi->adapter;
+ struct adapter *adap = qs->adap;
struct sge_rspq *q = &qs->rspq;
spin_lock(&q->lock);
@@ -2226,16 +2215,14 @@ irqreturn_t t3_sge_intr_msix(int irq, void *cookie)
* The MSI-X interrupt handler for an SGE response queue for the NAPI case
* (i.e., response queue serviced by NAPI polling).
*/
-irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie)
+static irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie)
{
struct sge_qset *qs = cookie;
- const struct port_info *pi = netdev_priv(qs->netdev);
- struct adapter *adap = pi->adapter;
struct sge_rspq *q = &qs->rspq;
spin_lock(&q->lock);
- if (handle_responses(adap, q) < 0)
+ if (handle_responses(qs->adap, q) < 0)
q->unhandled_irqs++;
spin_unlock(&q->lock);
return IRQ_HANDLED;
@@ -2278,11 +2265,13 @@ static irqreturn_t t3_intr_msi(int irq, void *cookie)
return IRQ_HANDLED;
}
-static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q)
+static int rspq_check_napi(struct sge_qset *qs)
{
- if (!napi_is_scheduled(dev) && is_new_response(&q->desc[q->cidx], q)) {
- if (likely(__netif_rx_schedule_prep(dev)))
- __netif_rx_schedule(dev);
+ struct sge_rspq *q = &qs->rspq;
+
+ if (!napi_is_scheduled(&qs->napi) &&
+ is_new_response(&q->desc[q->cidx], q)) {
+ napi_schedule(&qs->napi);
return 1;
}
return 0;
@@ -2295,7 +2284,7 @@ static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q)
* one SGE response queue per port in this mode and protect all response
* queues with queue 0's lock.
*/
-irqreturn_t t3_intr_msi_napi(int irq, void *cookie)
+static irqreturn_t t3_intr_msi_napi(int irq, void *cookie)
{
int new_packets;
struct adapter *adap = cookie;
@@ -2303,10 +2292,9 @@ irqreturn_t t3_intr_msi_napi(int irq, void *cookie)
spin_lock(&q->lock);
- new_packets = rspq_check_napi(adap->sge.qs[0].netdev, q);
+ new_packets = rspq_check_napi(&adap->sge.qs[0]);
if (adap->params.nports == 2)
- new_packets += rspq_check_napi(adap->sge.qs[1].netdev,
- &adap->sge.qs[1].rspq);
+ new_packets += rspq_check_napi(&adap->sge.qs[1]);
if (!new_packets && t3_slow_intr_handler(adap) == 0)
q->unhandled_irqs++;
@@ -2409,9 +2397,9 @@ static irqreturn_t t3b_intr(int irq, void *cookie)
static irqreturn_t t3b_intr_napi(int irq, void *cookie)
{
u32 map;
- struct net_device *dev;
struct adapter *adap = cookie;
- struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+ struct sge_qset *qs0 = &adap->sge.qs[0];
+ struct sge_rspq *q0 = &qs0->rspq;
t3_write_reg(adap, A_PL_CLI, 0);
map = t3_read_reg(adap, A_SG_DATA_INTR);
@@ -2424,18 +2412,11 @@ static irqreturn_t t3b_intr_napi(int irq, void *cookie)
if (unlikely(map & F_ERRINTR))
t3_slow_intr_handler(adap);
- if (likely(map & 1)) {
- dev = adap->sge.qs[0].netdev;
-
- if (likely(__netif_rx_schedule_prep(dev)))
- __netif_rx_schedule(dev);
- }
- if (map & 2) {
- dev = adap->sge.qs[1].netdev;
+ if (likely(map & 1))
+ napi_schedule(&qs0->napi);
- if (likely(__netif_rx_schedule_prep(dev)))
- __netif_rx_schedule(dev);
- }
+ if (map & 2)
+ napi_schedule(&adap->sge.qs[1].napi);
spin_unlock(&q0->lock);
return IRQ_HANDLED;
@@ -2450,7 +2431,7 @@ static irqreturn_t t3b_intr_napi(int irq, void *cookie)
* (MSI-X, MSI, or legacy) and whether NAPI will be used to service the
* response queues.
*/
-intr_handler_t t3_intr_handler(struct adapter *adap, int polling)
+irq_handler_t t3_intr_handler(struct adapter *adap, int polling)
{
if (adap->flags & USING_MSIX)
return polling ? t3_sge_intr_msix_napi : t3_sge_intr_msix;
@@ -2482,6 +2463,10 @@ void t3_sge_err_intr_handler(struct adapter *adapter)
"(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff);
}
+ if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR))
+ CH_ALERT(adapter, "SGE dropped %s priority doorbell\n",
+ status & F_HIPIODRBDROPERR ? "high" : "lo");
+
t3_write_reg(adapter, A_SG_INT_CAUSE, status);
if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED))
t3_fatal_err(adapter);
@@ -2514,8 +2499,7 @@ static void sge_timer_cb(unsigned long data)
{
spinlock_t *lock;
struct sge_qset *qs = (struct sge_qset *)data;
- const struct port_info *pi = netdev_priv(qs->netdev);
- struct adapter *adap = pi->adapter;
+ struct adapter *adap = qs->adap;
if (spin_trylock(&qs->txq[TXQ_ETH].lock)) {
reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]);
@@ -2526,9 +2510,9 @@ static void sge_timer_cb(unsigned long data)
spin_unlock(&qs->txq[TXQ_OFLD].lock);
}
lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock :
- &adap->sge.qs[0].rspq.lock;
+ &adap->sge.qs[0].rspq.lock;
if (spin_trylock_irq(lock)) {
- if (!napi_is_scheduled(qs->netdev)) {
+ if (!napi_is_scheduled(&qs->napi)) {
u32 status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS);
if (qs->fl[0].credits < qs->fl[0].size)
@@ -2562,12 +2546,9 @@ static void sge_timer_cb(unsigned long data)
*/
void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p)
{
- if (!qs->netdev)
- return;
-
qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */
qs->rspq.polling = p->polling;
- qs->netdev->poll = p->polling ? napi_rx_handler : ofld_poll;
+ qs->napi.poll = p->polling ? napi_rx_handler : ofld_poll;
}
/**
@@ -2587,7 +2568,7 @@ void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p)
*/
int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
int irq_vec_idx, const struct qset_params *p,
- int ntxq, struct net_device *netdev)
+ int ntxq, struct net_device *dev)
{
int i, ret = -ENOMEM;
struct sge_qset *q = &adapter->sge.qs[id];
@@ -2708,16 +2689,10 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
}
spin_unlock(&adapter->sge.reg_lock);
- q->netdev = netdev;
- t3_update_qset_coalesce(q, p);
- /*
- * We use atalk_ptr as a backpointer to a qset. In case a device is
- * associated with multiple queue sets only the first one sets
- * atalk_ptr.
- */
- if (netdev->atalk_ptr == NULL)
- netdev->atalk_ptr = q;
+ q->adap = adapter;
+ q->netdev = dev;
+ t3_update_qset_coalesce(q, p);
refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL);
refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL);
diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/cxgb3/sge_defs.h
index 514869e26a7..29b6c800b23 100644
--- a/drivers/net/cxgb3/sge_defs.h
+++ b/drivers/net/cxgb3/sge_defs.h
@@ -106,6 +106,10 @@
#define V_CQ_GEN(x) ((x) << S_CQ_GEN)
#define F_CQ_GEN V_CQ_GEN(1U)
+#define S_CQ_ERR 30
+#define V_CQ_ERR(x) ((x) << S_CQ_ERR)
+#define F_CQ_ERR V_CQ_ERR(1U)
+
#define S_CQ_OVERFLOW_MODE 31
#define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE)
#define F_CQ_OVERFLOW_MODE V_CQ_OVERFLOW_MODE(1U)
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index b02d15daf5d..d4ee00d3221 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -119,9 +119,9 @@ void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
* Reads registers that are accessed indirectly through an address/data
* register pair.
*/
-void t3_read_indirect(struct adapter *adap, unsigned int addr_reg,
- unsigned int data_reg, u32 *vals, unsigned int nregs,
- unsigned int start_idx)
+static void t3_read_indirect(struct adapter *adap, unsigned int addr_reg,
+ unsigned int data_reg, u32 *vals,
+ unsigned int nregs, unsigned int start_idx)
{
while (nregs--) {
t3_write_reg(adap, addr_reg, start_idx);
@@ -505,7 +505,7 @@ struct t3_vpd {
u8 vpdr_len[2];
VPD_ENTRY(pn, 16); /* part number */
VPD_ENTRY(ec, 16); /* EC level */
- VPD_ENTRY(sn, 16); /* serial number */
+ VPD_ENTRY(sn, SERNUM_LEN); /* serial number */
VPD_ENTRY(na, 12); /* MAC address base */
VPD_ENTRY(cclk, 6); /* core clock */
VPD_ENTRY(mclk, 6); /* mem clock */
@@ -648,6 +648,7 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10);
p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10);
p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10);
+ memcpy(p->sn, vpd.sn_data, SERNUM_LEN);
/* Old eeproms didn't have port information */
if (adapter->params.rev == 0 && !vpd.port0_data[0]) {
@@ -959,16 +960,18 @@ int t3_get_fw_version(struct adapter *adapter, u32 *vers)
/**
* t3_check_fw_version - check if the FW is compatible with this driver
* @adapter: the adapter
- *
+ * @must_load: set to 1 if loading a new FW image is required
+
* Checks if an adapter's FW is compatible with the driver. Returns 0
* if the versions are compatible, a negative error otherwise.
*/
-int t3_check_fw_version(struct adapter *adapter)
+int t3_check_fw_version(struct adapter *adapter, int *must_load)
{
int ret;
u32 vers;
unsigned int type, major, minor;
+ *must_load = 1;
ret = t3_get_fw_version(adapter, &vers);
if (ret)
return ret;
@@ -981,9 +984,17 @@ int t3_check_fw_version(struct adapter *adapter)
minor == FW_VERSION_MINOR)
return 0;
- CH_ERR(adapter, "found wrong FW version(%u.%u), "
- "driver needs version %u.%u\n", major, minor,
- FW_VERSION_MAJOR, FW_VERSION_MINOR);
+ if (major != FW_VERSION_MAJOR)
+ CH_ERR(adapter, "found wrong FW version(%u.%u), "
+ "driver needs version %u.%u\n", major, minor,
+ FW_VERSION_MAJOR, FW_VERSION_MINOR);
+ else {
+ *must_load = 0;
+ CH_WARN(adapter, "found wrong FW minor version(%u.%u), "
+ "driver compiled for version %u.%u\n", major, minor,
+ FW_VERSION_MAJOR, FW_VERSION_MINOR);
+ }
+
return -EINVAL;
}
@@ -1347,6 +1358,10 @@ static void pcie_intr_handler(struct adapter *adapter)
{0}
};
+ if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR)
+ CH_ALERT(adapter, "PEX error code 0x%x\n",
+ t3_read_reg(adapter, A_PCIE_PEX_ERR));
+
if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
pcie_intr_info, adapter->irq_stats))
t3_fatal_err(adapter);
@@ -1798,6 +1813,8 @@ void t3_intr_clear(struct adapter *adapter)
for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
+ if (is_pcie(adapter))
+ t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff);
t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
}
@@ -1853,6 +1870,8 @@ void t3_port_intr_clear(struct adapter *adapter, int idx)
phy->ops->intr_clear(phy);
}
+#define SG_CONTEXT_CMD_ATTEMPTS 100
+
/**
* t3_sge_write_context - write an SGE context
* @adapter: the adapter
@@ -1872,7 +1891,7 @@ static int t3_sge_write_context(struct adapter *adapter, unsigned int id,
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
- 0, 5, 1);
+ 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
}
/**
@@ -2029,7 +2048,8 @@ int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
base_addr >>= 32;
t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) |
- V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode));
+ V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) |
+ V_CQ_ERR(ovfl_mode));
t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
V_CQ_CREDIT_THRES(credit_thres));
return t3_sge_write_context(adapter, id, F_CQ);
@@ -2057,7 +2077,7 @@ int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable)
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
- 0, 5, 1);
+ 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
}
/**
@@ -2081,7 +2101,7 @@ int t3_sge_disable_fl(struct adapter *adapter, unsigned int id)
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
- 0, 5, 1);
+ 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
}
/**
@@ -2105,7 +2125,7 @@ int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id)
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
- 0, 5, 1);
+ 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
}
/**
@@ -2129,7 +2149,7 @@ int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id)
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
- 0, 5, 1);
+ 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
}
/**
@@ -2154,7 +2174,7 @@ int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
V_CONTEXT(id) | F_CQ);
if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
- 0, 5, 1, &val))
+ 0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val))
return -EIO;
if (op >= 2 && op < 7) {
@@ -2164,7 +2184,8 @@ int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
- F_CONTEXT_CMD_BUSY, 0, 5, 1))
+ F_CONTEXT_CMD_BUSY, 0,
+ SG_CONTEXT_CMD_ATTEMPTS, 1))
return -EIO;
return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
}
@@ -2190,7 +2211,7 @@ static int t3_sge_read_context(unsigned int type, struct adapter *adapter,
t3_write_reg(adapter, A_SG_CONTEXT_CMD,
V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id));
if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0,
- 5, 1))
+ SG_CONTEXT_CMD_ATTEMPTS, 1))
return -EIO;
data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0);
data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1);
@@ -3222,6 +3243,8 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params)
t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN);
t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff);
+ t3_write_reg(adapter, A_PM1_RX_MODE, 0);
+ t3_write_reg(adapter, A_PM1_TX_MODE, 0);
init_hw_for_avail_ports(adapter, adapter->params.nports);
t3_sge_init(adapter, &adapter->params.sge);
@@ -3384,7 +3407,7 @@ void early_hw_init(struct adapter *adapter, const struct adapter_info *ai)
* Older PCIe cards lose their config space during reset, PCI-X
* ones don't.
*/
-int t3_reset_adapter(struct adapter *adapter)
+static int t3_reset_adapter(struct adapter *adapter)
{
int i, save_and_restore_pcie =
adapter->params.rev < T3_REV_B2 && is_pcie(adapter);
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index eb508bf8022..ef1c6339c80 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -39,6 +39,6 @@
/* Firmware version */
#define FW_VERSION_MAJOR 4
-#define FW_VERSION_MINOR 3
+#define FW_VERSION_MINOR 6
#define FW_VERSION_MICRO 0
#endif /* __CHELSIO_VERSION_H */
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index c302b1a30cb..eeb766aeced 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -142,7 +142,7 @@ int t3_mac_reset(struct cmac *mac)
return 0;
}
-int t3b2_mac_reset(struct cmac *mac)
+static int t3b2_mac_reset(struct cmac *mac)
{
struct adapter *adap = mac->adapter;
unsigned int oft = mac->offset;
@@ -437,12 +437,13 @@ int t3_mac_enable(struct cmac *mac, int which)
struct mac_stats *s = &mac->stats;
if (which & MAC_DIRECTION_TX) {
- t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401);
t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
+ t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
+
t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
mac->tx_mcnt = s->tx_frames;
mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
@@ -451,9 +452,11 @@ int t3_mac_enable(struct cmac *mac, int which)
A_XGM_TX_SPI4_SOP_EOP_CNT +
oft)));
mac->rx_mcnt = s->rx_frames;
+ mac->rx_pause = s->rx_pause;
mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
A_XGM_RX_SPI4_SOP_EOP_CNT +
oft)));
+ mac->rx_ocnt = s->rx_fifo_ovfl;
mac->txen = F_TXEN;
mac->toggle_cnt = 0;
}
@@ -464,24 +467,19 @@ int t3_mac_enable(struct cmac *mac, int which)
int t3_mac_disable(struct cmac *mac, int which)
{
- int idx = macidx(mac);
struct adapter *adap = mac->adapter;
- int val;
if (which & MAC_DIRECTION_TX) {
t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
- t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
- t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f);
- t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
- t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
mac->txen = 0;
}
if (which & MAC_DIRECTION_RX) {
+ int val = F_MAC_RESET_;
+
t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
F_PCS_RESET_, 0);
msleep(100);
t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
- val = F_MAC_RESET_;
if (is_10G(adap))
val |= F_PCS_RESET_;
else if (uses_xaui(adap))
@@ -507,7 +505,7 @@ int t3b2_mac_watchdog_task(struct cmac *mac)
tx_xcnt = 1; /* By default tx_xcnt is making progress */
tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt */
rx_xcnt = 1; /* By default rx_xcnt is making progress */
- if (tx_mcnt == mac->tx_mcnt) {
+ if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
A_XGM_TX_SPI4_SOP_EOP_CNT +
mac->offset)));
@@ -524,10 +522,7 @@ int t3b2_mac_watchdog_task(struct cmac *mac)
goto rxcheck;
}
- if (((tx_tcnt != mac->tx_tcnt) &&
- (tx_xcnt == 0) && (mac->tx_xcnt == 0)) ||
- ((mac->tx_mcnt == tx_mcnt) &&
- (tx_xcnt != 0) && (mac->tx_xcnt != 0))) {
+ if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
if (mac->toggle_cnt > 4) {
status = 2;
goto out;
@@ -541,11 +536,14 @@ int t3b2_mac_watchdog_task(struct cmac *mac)
}
rxcheck:
- if (rx_mcnt != mac->rx_mcnt)
+ if (rx_mcnt != mac->rx_mcnt) {
rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
A_XGM_RX_SPI4_SOP_EOP_CNT +
- mac->offset)));
- else
+ mac->offset))) +
+ (s->rx_fifo_ovfl -
+ mac->rx_ocnt);
+ mac->rx_ocnt = s->rx_fifo_ovfl;
+ } else
goto out;
if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 &&
@@ -560,6 +558,7 @@ out:
mac->tx_mcnt = s->tx_frames;
mac->rx_xcnt = rx_xcnt;
mac->rx_mcnt = s->rx_frames;
+ mac->rx_pause = s->rx_pause;
if (status == 1) {
t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset); /* flush */
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index dae97b860da..cb849b091f9 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -154,11 +154,6 @@ static int de600_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *get_stats(struct net_device *dev)
-{
- return (struct net_device_stats *)(dev->priv);
-}
-
static inline void trigger_interrupt(struct net_device *dev)
{
de600_put_command(FLIP_IRQ);
@@ -308,7 +303,7 @@ static int de600_tx_intr(struct net_device *dev, int irq_status)
if (!(irq_status & TX_FAILED16)) {
tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES;
++free_tx_pages;
- ((struct net_device_stats *)(dev->priv))->tx_packets++;
+ dev->stats.tx_packets++;
netif_wake_queue(dev);
}
@@ -375,8 +370,8 @@ static void de600_rx_intr(struct net_device *dev)
/* update stats */
dev->last_rx = jiffies;
- ((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */
- ((struct net_device_stats *)(dev->priv))->rx_bytes += size; /* count all received bytes */
+ dev->stats.rx_packets++; /* count all receives */
+ dev->stats.rx_bytes += size; /* count all received bytes */
/*
* If any worth-while packets have been received, netif_rx()
@@ -389,12 +384,12 @@ static struct net_device * __init de600_probe(void)
int i;
struct net_device *dev;
int err;
+ DECLARE_MAC_BUF(mac);
- dev = alloc_etherdev(sizeof(struct net_device_stats));
+ dev = alloc_etherdev(0);
if (!dev)
return ERR_PTR(-ENOMEM);
- SET_MODULE_OWNER(dev);
if (!request_region(DE600_IO, 3, "de600")) {
printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO);
@@ -444,12 +439,7 @@ static struct net_device * __init de600_probe(void)
goto out1;
}
- printk(", Ethernet Address: %02X", dev->dev_addr[0]);
- for (i = 1; i < ETH_ALEN; i++)
- printk(":%02X",dev->dev_addr[i]);
- printk("\n");
-
- dev->get_stats = get_stats;
+ printk(", Ethernet Address: %s\n", print_mac(mac, dev->dev_addr));
dev->open = de600_open;
dev->stop = de600_close;
diff --git a/drivers/net/de600.h b/drivers/net/de600.h
index 1288e48ba70..e80ecbabcf4 100644
--- a/drivers/net/de600.h
+++ b/drivers/net/de600.h
@@ -121,7 +121,6 @@ static u8 de600_read_byte(unsigned char type, struct net_device *dev);
/* Put in the device structure. */
static int de600_open(struct net_device *dev);
static int de600_close(struct net_device *dev);
-static struct net_device_stats *get_stats(struct net_device *dev);
static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev);
/* Dispatch from interrupts. */
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index dc489242617..3f5190c654c 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -216,7 +216,6 @@ MODULE_PARM_DESC(de620_debug, "DE-620 debug level (0-2)");
/* Put in the device structure. */
static int de620_open(struct net_device *);
static int de620_close(struct net_device *);
-static struct net_device_stats *get_stats(struct net_device *);
static void de620_set_multicast_list(struct net_device *);
static int de620_start_xmit(struct sk_buff *, struct net_device *);
@@ -480,16 +479,6 @@ static int de620_close(struct net_device *dev)
/*********************************************
*
- * Return current statistics
- *
- */
-static struct net_device_stats *get_stats(struct net_device *dev)
-{
- return (struct net_device_stats *)(dev->priv);
-}
-
-/*********************************************
- *
* Set or clear the multicast filter for this adaptor.
* (no real multicast implemented for the DE-620, but she can be promiscuous...)
*
@@ -579,7 +568,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
if(!(using_txbuf == (TXBF0 | TXBF1)))
netif_wake_queue(dev);
- ((struct net_device_stats *)(dev->priv))->tx_packets++;
+ dev->stats.tx_packets++;
spin_unlock_irqrestore(&de620_lock, flags);
dev_kfree_skb (skb);
return 0;
@@ -660,7 +649,7 @@ static int de620_rx_intr(struct net_device *dev)
/* You win some, you lose some. And sometimes plenty... */
adapter_init(dev);
netif_wake_queue(dev);
- ((struct net_device_stats *)(dev->priv))->rx_over_errors++;
+ dev->stats.rx_over_errors++;
return 0;
}
@@ -680,7 +669,7 @@ static int de620_rx_intr(struct net_device *dev)
next_rx_page = header_buf.Rx_NextPage; /* at least a try... */
de620_send_command(dev, W_DUMMY);
de620_set_register(dev, W_NPRF, next_rx_page);
- ((struct net_device_stats *)(dev->priv))->rx_over_errors++;
+ dev->stats.rx_over_errors++;
return 0;
}
next_rx_page = pagelink;
@@ -693,7 +682,7 @@ static int de620_rx_intr(struct net_device *dev)
skb = dev_alloc_skb(size+2);
if (skb == NULL) { /* Yeah, but no place to put it... */
printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
- ((struct net_device_stats *)(dev->priv))->rx_dropped++;
+ dev->stats.rx_dropped++;
}
else { /* Yep! Go get it! */
skb_reserve(skb,2); /* Align */
@@ -706,8 +695,8 @@ static int de620_rx_intr(struct net_device *dev)
netif_rx(skb); /* deliver it "upstairs" */
dev->last_rx = jiffies;
/* count all receives */
- ((struct net_device_stats *)(dev->priv))->rx_packets++;
- ((struct net_device_stats *)(dev->priv))->rx_bytes += size;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += size;
}
}
@@ -818,13 +807,12 @@ struct net_device * __init de620_probe(int unit)
struct net_device *dev;
int err = -ENOMEM;
int i;
+ DECLARE_MAC_BUF(mac);
- dev = alloc_etherdev(sizeof(struct net_device_stats));
+ dev = alloc_etherdev(0);
if (!dev)
goto out;
- SET_MODULE_OWNER(dev);
-
spin_lock_init(&de620_lock);
/*
@@ -866,13 +854,14 @@ struct net_device * __init de620_probe(int unit)
}
/* else, got it! */
- printk(", Ethernet Address: %2.2X",
- dev->dev_addr[0] = nic_data.NodeID[0]);
+ dev->dev_addr[0] = nic_data.NodeID[0];
for (i = 1; i < ETH_ALEN; i++) {
- printk(":%2.2X", dev->dev_addr[i] = nic_data.NodeID[i]);
+ dev->dev_addr[i] = nic_data.NodeID[i];
dev->broadcast[i] = 0xff;
}
+ printk(", Ethernet Address: %s", print_mac(mac, dev->dev_addr));
+
printk(" (%dk RAM,",
(nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64);
@@ -881,7 +870,6 @@ struct net_device * __init de620_probe(int unit)
else
printk(" UTP)\n");
- dev->get_stats = get_stats;
dev->open = de620_open;
dev->stop = de620_close;
dev->hard_start_xmit = de620_start_xmit;
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index b2577f40124..00e0194bfef 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -258,8 +258,6 @@ struct lance_private {
int rx_new, tx_new;
int rx_old, tx_old;
- struct net_device_stats stats;
-
unsigned short busmaster_regval;
struct timer_list multicast_timer;
@@ -583,22 +581,22 @@ static int lance_rx(struct net_device *dev)
/* We got an incomplete frame? */
if ((bits & LE_R1_POK) != LE_R1_POK) {
- lp->stats.rx_over_errors++;
- lp->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
} else if (bits & LE_R1_ERR) {
/* Count only the end frame as a rx error,
* not the beginning
*/
if (bits & LE_R1_BUF)
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (bits & LE_R1_CRC)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (bits & LE_R1_OFL)
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (bits & LE_R1_FRA)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (bits & LE_R1_EOP)
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
} else {
len = (*rds_ptr(rd, mblength, lp->type) & 0xfff) - 4;
skb = dev_alloc_skb(len + 2);
@@ -606,7 +604,7 @@ static int lance_rx(struct net_device *dev)
if (skb == 0) {
printk("%s: Memory squeeze, deferring packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
*rds_ptr(rd, mblength, lp->type) = 0;
*rds_ptr(rd, rmd1, lp->type) =
((lp->rx_buf_ptr_lnc[entry] >> 16) &
@@ -614,7 +612,7 @@ static int lance_rx(struct net_device *dev)
lp->rx_new = (entry + 1) & RX_RING_MOD_MASK;
return 0;
}
- lp->stats.rx_bytes += len;
+ dev->stats.rx_bytes += len;
skb_reserve(skb, 2); /* 16 byte align */
skb_put(skb, len); /* make room */
@@ -625,7 +623,7 @@ static int lance_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
+ dev->stats.rx_packets++;
}
/* Return the packet to the pool */
@@ -660,14 +658,14 @@ static void lance_tx(struct net_device *dev)
if (*tds_ptr(td, tmd1, lp->type) & LE_T1_ERR) {
status = *tds_ptr(td, misc, lp->type);
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (status & LE_T3_RTY)
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (status & LE_T3_LCOL)
- lp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (status & LE_T3_CLOS) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
printk("%s: Carrier Lost\n", dev->name);
/* Stop the lance */
writereg(&ll->rap, LE_CSR0);
@@ -681,7 +679,7 @@ static void lance_tx(struct net_device *dev)
* transmitter, restart the adapter.
*/
if (status & (LE_T3_BUF | LE_T3_UFL)) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
dev->name);
@@ -702,13 +700,13 @@ static void lance_tx(struct net_device *dev)
/* One collision before packet was sent. */
if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EONE)
- lp->stats.collisions++;
+ dev->stats.collisions++;
/* More than one collision, be optimistic. */
if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EMORE)
- lp->stats.collisions += 2;
+ dev->stats.collisions += 2;
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
j = (j + 1) & TX_RING_MOD_MASK;
}
@@ -754,10 +752,10 @@ static irqreturn_t lance_interrupt(const int irq, void *dev_id)
lance_tx(dev);
if (csr0 & LE_C0_BABL)
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (csr0 & LE_C0_MISS)
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (csr0 & LE_C0_MERR) {
printk("%s: Memory error, status %04x\n", dev->name, csr0);
@@ -912,7 +910,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = ETH_ZLEN;
}
- lp->stats.tx_bytes += len;
+ dev->stats.tx_bytes += len;
entry = lp->tx_new;
*lib_ptr(ib, btx_ring[entry].length, lp->type) = (-len);
@@ -938,13 +936,6 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static struct net_device_stats *lance_get_stats(struct net_device *dev)
-{
- struct lance_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
static void lance_load_multicast(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
@@ -1036,6 +1027,7 @@ static int __init dec_lance_probe(struct device *bdev, const int type)
int i, ret;
unsigned long esar_base;
unsigned char *esar;
+ DECLARE_MAC_BUF(mac);
if (dec_lance_debug && version_printed++ == 0)
printk(version);
@@ -1223,28 +1215,26 @@ static int __init dec_lance_probe(struct device *bdev, const int type)
*/
switch (type) {
case ASIC_LANCE:
- printk("%s: IOASIC onboard LANCE, addr = ", name);
+ printk("%s: IOASIC onboard LANCE", name);
break;
case PMAD_LANCE:
- printk("%s: PMAD-AA, addr = ", name);
+ printk("%s: PMAD-AA", name);
break;
case PMAX_LANCE:
- printk("%s: PMAX onboard LANCE, addr = ", name);
+ printk("%s: PMAX onboard LANCE", name);
break;
}
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
dev->dev_addr[i] = esar[i * 4];
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ',' : ':');
- }
- printk(" irq = %d\n", dev->irq);
+ printk(", addr = %s, irq = %d\n",
+ print_mac(mac, dev->dev_addr), dev->irq);
dev->open = &lance_open;
dev->stop = &lance_close;
dev->hard_start_xmit = &lance_start_xmit;
dev->tx_timeout = &lance_tx_timeout;
dev->watchdog_timeo = 5*HZ;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
/* lp->ll is the location of the registers for lance card */
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 9c8e3f9f5e5..ddc30c4bf34 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -539,7 +539,6 @@ static int __devinit dfx_register(struct device *bdev)
goto err_out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, bdev);
bp = netdev_priv(dev);
@@ -806,7 +805,7 @@ static void __devinit dfx_bus_init(struct net_device *dev)
* Interrupts are disabled at the adapter bus-specific logic.
*/
-static void __devinit dfx_bus_uninit(struct net_device *dev)
+static void __devexit dfx_bus_uninit(struct net_device *dev)
{
DFX_board_t *bp = netdev_priv(dev);
struct device *bdev = bp->bus_dev;
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 183497020bf..ace39ec0a36 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -485,7 +485,6 @@ struct depca_private {
/* Kernel-only (not device) fields */
int rx_new, tx_new; /* The next free ring entry */
int rx_old, tx_old; /* The ring entries to be free()ed. */
- struct net_device_stats stats;
spinlock_t lock;
struct { /* Private stats counters */
u32 bins[DEPCA_PKT_STAT_SZ];
@@ -522,7 +521,6 @@ static irqreturn_t depca_interrupt(int irq, void *dev_id);
static int depca_close(struct net_device *dev);
static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void depca_tx_timeout(struct net_device *dev);
-static struct net_device_stats *depca_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
/*
@@ -575,6 +573,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
s16 nicsr;
u_long ioaddr;
u_long mem_start;
+ DECLARE_MAC_BUF(mac);
/*
* We are now supposed to enter this function with the
@@ -634,14 +633,11 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
printk(", h/w address ");
status = get_hw_addr(dev);
+ printk("%s", print_mac(mac, dev->dev_addr));
if (status != 0) {
printk(" which has an Ethernet PROM CRC error.\n");
return -ENXIO;
}
- for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */
- printk("%2.2x:", dev->dev_addr[i]);
- }
- printk("%2.2x", dev->dev_addr[i]);
/* Set up the maximum amount of network RAM(kB) */
netRAM = ((lp->adapter != DEPCA) ? 64 : 48);
@@ -801,7 +797,6 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
dev->open = &depca_open;
dev->hard_start_xmit = &depca_start_xmit;
dev->stop = &depca_close;
- dev->get_stats = &depca_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->do_ioctl = &depca_ioctl;
dev->tx_timeout = depca_tx_timeout;
@@ -1026,15 +1021,15 @@ static int depca_rx(struct net_device *dev)
}
if (status & R_ENP) { /* Valid frame status */
if (status & R_ERR) { /* There was an error. */
- lp->stats.rx_errors++; /* Update the error stats. */
+ dev->stats.rx_errors++; /* Update the error stats. */
if (status & R_FRAM)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & R_OFLO)
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (status & R_CRC)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (status & R_BUFF)
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
} else {
short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
struct sk_buff *skb;
@@ -1063,8 +1058,8 @@ static int depca_rx(struct net_device *dev)
** Update stats
*/
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) {
if (pkt_len < (i * DEPCA_PKT_BIN_SZ)) {
lp->pktStats.bins[i]++;
@@ -1087,7 +1082,7 @@ static int depca_rx(struct net_device *dev)
}
} else {
printk("%s: Memory squeeze, deferring packet.\n", dev->name);
- lp->stats.rx_dropped++; /* Really, deferred. */
+ dev->stats.rx_dropped++; /* Really, deferred. */
break;
}
}
@@ -1125,24 +1120,24 @@ static int depca_tx(struct net_device *dev)
break;
} else if (status & T_ERR) { /* An error occurred. */
status = readl(&lp->tx_ring[entry].misc);
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (status & TMD3_RTRY)
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (status & TMD3_LCAR)
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (status & TMD3_LCOL)
- lp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (status & TMD3_UFLO)
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (status & (TMD3_BUFF | TMD3_UFLO)) {
/* Trigger an immediate send demand. */
outw(CSR0, DEPCA_ADDR);
outw(INEA | TDMD, DEPCA_DATA);
}
} else if (status & (T_MORE | T_ONE)) {
- lp->stats.collisions++;
+ dev->stats.collisions++;
} else {
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
/* Update all the pointers */
@@ -1234,15 +1229,6 @@ static int InitRestartDepca(struct net_device *dev)
return status;
}
-static struct net_device_stats *depca_get_stats(struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *) dev->priv;
-
- /* Null body since there is no framing error counter */
-
- return &lp->stats;
-}
-
/*
** Set or clear the multicast filter for this adaptor.
*/
@@ -1855,6 +1841,7 @@ static void depca_dbg_open(struct net_device *dev)
u_long ioaddr = dev->base_addr;
struct depca_init *p = &lp->init_block;
int i;
+ DECLARE_MAC_BUF(mac);
if (depca_debug > 1) {
/* Do not copy the shadow init block into shared memory */
@@ -1893,11 +1880,7 @@ static void depca_dbg_open(struct net_device *dev)
printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start);
printk(" mode: 0x%4.4x\n", p->mode);
- printk(" physical address: ");
- for (i = 0; i < ETH_ALEN - 1; i++) {
- printk("%2.2x:", p->phys_addr[i]);
- }
- printk("%2.2x\n", p->phys_addr[i]);
+ printk(" physical address: %s\n", print_mac(mac, p->phys_addr));
printk(" multicast hash table: ");
for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) {
printk("%2.2x:", p->mcast_table[i]);
diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c
deleted file mode 100644
index df62c0232f3..00000000000
--- a/drivers/net/dgrs.c
+++ /dev/null
@@ -1,1615 +0,0 @@
-/*
- * Digi RightSwitch SE-X loadable device driver for Linux
- *
- * The RightSwitch is a 4 (EISA) or 6 (PCI) port etherswitch and
- * a NIC on an internal board.
- *
- * Author: Rick Richardson, rick@remotepoint.com
- * Derived from the SVR4.2 (UnixWare) driver for the same card.
- *
- * Copyright 1995-1996 Digi International Inc.
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For information on purchasing a RightSwitch SE-4 or SE-6
- * board, please contact Digi's sales department at 1-612-912-3444
- * or 1-800-DIGIBRD. Outside the U.S., please check our Web page
- * at http://www.dgii.com for sales offices worldwide.
- *
- * OPERATION:
- * When compiled as a loadable module, this driver can operate
- * the board as either a 4/6 port switch with a 5th or 7th port
- * that is a conventional NIC interface as far as the host is
- * concerned, OR as 4/6 independent NICs. To select multi-NIC
- * mode, add "nicmode=1" on the insmod load line for the driver.
- *
- * This driver uses the "dev" common ethernet device structure
- * and a private "priv" (dev->priv) structure that contains
- * mostly DGRS-specific information and statistics. To keep
- * the code for both the switch mode and the multi-NIC mode
- * as similar as possible, I have introduced the concept of
- * "dev0"/"priv0" and "devN"/"privN" pointer pairs in subroutines
- * where needed. The first pair of pointers points to the
- * "dev" and "priv" structures of the zeroth (0th) device
- * interface associated with a board. The second pair of
- * pointers points to the current (Nth) device interface
- * for the board: the one for which we are processing data.
- *
- * In switch mode, the pairs of pointers are always the same,
- * that is, dev0 == devN and priv0 == privN. This is just
- * like previous releases of this driver which did not support
- * NIC mode.
- *
- * In multi-NIC mode, the pairs of pointers may be different.
- * We use the devN and privN pointers to reference just the
- * name, port number, and statistics for the current interface.
- * We use the dev0 and priv0 pointers to access the variables
- * that control access to the board, such as board address
- * and simulated 82596 variables. This is because there is
- * only one "fake" 82596 that serves as the interface to
- * the board. We do not want to try to keep the variables
- * associated with this 82596 in sync across all devices.
- *
- * This scheme works well. As you will see, except for
- * initialization, there is very little difference between
- * the two modes as far as this driver is concerned. On the
- * receive side in NIC mode, the interrupt *always* comes in on
- * the 0th interface (dev0/priv0). We then figure out which
- * real 82596 port it came in on from looking at the "chan"
- * member that the board firmware adds at the end of each
- * RBD (a.k.a. TBD). We get the channel number like this:
- * int chan = ((I596_RBD *) S2H(cbp->xmit.tbdp))->chan;
- *
- * On the transmit side in multi-NIC mode, we specify the
- * output 82596 port by setting the new "dstchan" structure
- * member that is at the end of the RFD, like this:
- * priv0->rfdp->dstchan = privN->chan;
- *
- * TODO:
- * - Multi-NIC mode is not yet supported when the driver is linked
- * into the kernel.
- * - Better handling of multicast addresses.
- *
- * Fixes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
- * - fix dgrs_found_device wrt checking kmalloc return and
- * rollbacking the partial steps of the whole process when
- * one of the devices can't be allocated. Fix SET_MODULE_OWNER
- * on the loop to use devN instead of repeated calls to dev.
- *
- * davej <davej@suse.de> - 9/2/2001
- * - Enable PCI device before reading ioaddr/irq
- *
- */
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <asm/uaccess.h>
-
-static char version[] __initdata =
- "$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $";
-
-/*
- * DGRS include files
- */
-typedef unsigned char uchar;
-#define vol volatile
-
-#include "dgrs.h"
-#include "dgrs_es4h.h"
-#include "dgrs_plx9060.h"
-#include "dgrs_i82596.h"
-#include "dgrs_ether.h"
-#include "dgrs_asstruct.h"
-#include "dgrs_bcomm.h"
-
-#ifdef CONFIG_PCI
-static struct pci_device_id dgrs_pci_tbl[] = {
- { SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
- { } /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl);
-#endif
-
-#ifdef CONFIG_EISA
-static struct eisa_device_id dgrs_eisa_tbl[] = {
- { "DBI0A01" },
- { }
-};
-MODULE_DEVICE_TABLE(eisa, dgrs_eisa_tbl);
-#endif
-
-MODULE_LICENSE("GPL");
-
-
-/*
- * Firmware. Compiled separately for local compilation,
- * but #included for Linux distribution.
- */
-#ifndef NOFW
- #include "dgrs_firmware.c"
-#else
- extern int dgrs_firmnum;
- extern char dgrs_firmver[];
- extern char dgrs_firmdate[];
- extern uchar dgrs_code[];
- extern int dgrs_ncode;
-#endif
-
-/*
- * Linux out*() is backwards from all other operating systems
- */
-#define OUTB(ADDR, VAL) outb(VAL, ADDR)
-#define OUTW(ADDR, VAL) outw(VAL, ADDR)
-#define OUTL(ADDR, VAL) outl(VAL, ADDR)
-
-/*
- * Macros to convert switch to host and host to switch addresses
- * (assumes a local variable priv points to board dependent struct)
- */
-#define S2H(A) ( ((unsigned long)(A)&0x00ffffff) + priv0->vmem )
-#define S2HN(A) ( ((unsigned long)(A)&0x00ffffff) + privN->vmem )
-#define H2S(A) ( ((char *) (A) - priv0->vmem) + 0xA3000000 )
-
-/*
- * Convert a switch address to a "safe" address for use with the
- * PLX 9060 DMA registers and the associated HW kludge that allows
- * for host access of the DMA registers.
- */
-#define S2DMA(A) ( (unsigned long)(A) & 0x00ffffff)
-
-/*
- * "Space.c" variables, now settable from module interface
- * Use the name below, minus the "dgrs_" prefix. See init_module().
- */
-static int dgrs_debug = 1;
-static int dgrs_dma = 1;
-static int dgrs_spantree = -1;
-static int dgrs_hashexpire = -1;
-static uchar dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff};
-static uchar dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff};
-static __u32 dgrs_ipxnet = -1;
-static int dgrs_nicmode;
-
-/*
- * Private per-board data structure (dev->priv)
- */
-typedef struct
-{
- /*
- * Stuff for generic ethercard I/F
- */
- struct net_device_stats stats;
-
- /*
- * DGRS specific data
- */
- char *vmem;
-
- struct bios_comm *bcomm; /* Firmware BIOS comm structure */
- PORT *port; /* Ptr to PORT[0] struct in VM */
- I596_SCB *scbp; /* Ptr to SCB struct in VM */
- I596_RFD *rfdp; /* Current RFD list */
- I596_RBD *rbdp; /* Current RBD list */
-
- volatile int intrcnt; /* Count of interrupts */
-
- /*
- * SE-4 (EISA) board variables
- */
- uchar is_reg; /* EISA: Value for ES4H_IS reg */
-
- /*
- * SE-6 (PCI) board variables
- *
- * The PLX "expansion rom" space is used for DMA register
- * access from the host on the SE-6. These are the physical
- * and virtual addresses of that space.
- */
- ulong plxreg; /* Phys address of PLX chip */
- char *vplxreg; /* Virtual address of PLX chip */
- ulong plxdma; /* Phys addr of PLX "expansion rom" */
- ulong volatile *vplxdma; /* Virtual addr of "expansion rom" */
- int use_dma; /* Flag: use DMA */
- DMACHAIN *dmadesc_s; /* area for DMA chains (SW addr.) */
- DMACHAIN *dmadesc_h; /* area for DMA chains (Host Virtual) */
-
- /*
- * Multi-NIC mode variables
- *
- * All entries of the devtbl[] array are valid for the 0th
- * device (i.e. eth0, but not eth1...eth5). devtbl[0] is
- * valid for all devices (i.e. eth0, eth1, ..., eth5).
- */
- int nports; /* Number of physical ports (4 or 6) */
- int chan; /* Channel # (1-6) for this device */
- struct net_device *devtbl[6]; /* Ptrs to N device structs */
-
-} DGRS_PRIV;
-
-
-/*
- * reset or un-reset the IDT processor
- */
-static void
-proc_reset(struct net_device *dev0, int reset)
-{
- DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv;
-
- if (priv0->plxreg)
- {
- ulong val;
- val = inl(dev0->base_addr + PLX_MISC_CSR);
- if (reset)
- val |= SE6_RESET;
- else
- val &= ~SE6_RESET;
- OUTL(dev0->base_addr + PLX_MISC_CSR, val);
- }
- else
- {
- OUTB(dev0->base_addr + ES4H_PC, reset ? ES4H_PC_RESET : 0);
- }
-}
-
-/*
- * See if the board supports bus master DMA
- */
-static int
-check_board_dma(struct net_device *dev0)
-{
- DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv;
- ulong x;
-
- /*
- * If Space.c says not to use DMA, or if it's not a PLX based
- * PCI board, or if the expansion ROM space is not PCI
- * configured, then return false.
- */
- if (!dgrs_dma || !priv0->plxreg || !priv0->plxdma)
- return (0);
-
- /*
- * Set the local address remap register of the "expansion rom"
- * area to 0x80000000 so that we can use it to access the DMA
- * registers from the host side.
- */
- OUTL(dev0->base_addr + PLX_ROM_BASE_ADDR, 0x80000000);
-
- /*
- * Set the PCI region descriptor to:
- * Space 0:
- * disable read-prefetch
- * enable READY
- * enable BURST
- * 0 internal wait states
- * Expansion ROM: (used for host DMA register access)
- * disable read-prefetch
- * enable READY
- * disable BURST
- * 0 internal wait states
- */
- OUTL(dev0->base_addr + PLX_BUS_REGION, 0x49430343);
-
- /*
- * Now map the DMA registers into our virtual space
- */
- priv0->vplxdma = (ulong *) ioremap (priv0->plxdma, 256);
- if (!priv0->vplxdma)
- {
- printk("%s: can't *remap() the DMA regs\n", dev0->name);
- return (0);
- }
-
- /*
- * Now test to see if we can access the DMA registers
- * If we write -1 and get back 1FFF, then we accessed the
- * DMA register. Otherwise, we probably have an old board
- * and wrote into regular RAM.
- */
- priv0->vplxdma[PLX_DMA0_MODE/4] = 0xFFFFFFFF;
- x = priv0->vplxdma[PLX_DMA0_MODE/4];
- if (x != 0x00001FFF) {
- iounmap((void *)priv0->vplxdma);
- return (0);
- }
-
- return (1);
-}
-
-/*
- * Initiate DMA using PLX part on PCI board. Spin the
- * processor until completed. All addresses are physical!
- *
- * If pciaddr is NULL, then it's a chaining DMA, and lcladdr is
- * the address of the first DMA descriptor in the chain.
- *
- * If pciaddr is not NULL, then it's a single DMA.
- *
- * In either case, "lcladdr" must have been fixed up to make
- * sure the MSB isn't set using the S2DMA macro before passing
- * the address to this routine.
- */
-static int
-do_plx_dma(
- struct net_device *dev,
- ulong pciaddr,
- ulong lcladdr,
- int len,
- int to_host
-)
-{
- int i;
- ulong csr = 0;
- DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
-
- if (pciaddr)
- {
- /*
- * Do a single, non-chain DMA
- */
- priv->vplxdma[PLX_DMA0_PCI_ADDR/4] = pciaddr;
- priv->vplxdma[PLX_DMA0_LCL_ADDR/4] = lcladdr;
- priv->vplxdma[PLX_DMA0_SIZE/4] = len;
- priv->vplxdma[PLX_DMA0_DESCRIPTOR/4] = to_host
- ? PLX_DMA_DESC_TO_HOST
- : PLX_DMA_DESC_TO_BOARD;
- priv->vplxdma[PLX_DMA0_MODE/4] =
- PLX_DMA_MODE_WIDTH32
- | PLX_DMA_MODE_WAITSTATES(0)
- | PLX_DMA_MODE_READY
- | PLX_DMA_MODE_NOBTERM
- | PLX_DMA_MODE_BURST
- | PLX_DMA_MODE_NOCHAIN;
- }
- else
- {
- /*
- * Do a chaining DMA
- */
- priv->vplxdma[PLX_DMA0_MODE/4] =
- PLX_DMA_MODE_WIDTH32
- | PLX_DMA_MODE_WAITSTATES(0)
- | PLX_DMA_MODE_READY
- | PLX_DMA_MODE_NOBTERM
- | PLX_DMA_MODE_BURST
- | PLX_DMA_MODE_CHAIN;
- priv->vplxdma[PLX_DMA0_DESCRIPTOR/4] = lcladdr;
- }
-
- priv->vplxdma[PLX_DMA_CSR/4] =
- PLX_DMA_CSR_0_ENABLE | PLX_DMA_CSR_0_START;
-
- /*
- * Wait for DMA to complete
- */
- for (i = 0; i < 1000000; ++i)
- {
- /*
- * Spin the host CPU for 1 usec, so we don't thrash
- * the PCI bus while the PLX 9060 is doing DMA.
- */
- udelay(1);
-
- csr = (volatile unsigned long) priv->vplxdma[PLX_DMA_CSR/4];
-
- if (csr & PLX_DMA_CSR_0_DONE)
- break;
- }
-
- if ( ! (csr & PLX_DMA_CSR_0_DONE) )
- {
- printk("%s: DMA done never occurred. DMA disabled.\n",
- dev->name);
- priv->use_dma = 0;
- return 1;
- }
- return 0;
-}
-
-/*
- * dgrs_rcv_frame()
- *
- * Process a received frame. This is called from the interrupt
- * routine, and works for both switch mode and multi-NIC mode.
- *
- * Note that when in multi-NIC mode, we want to always access the
- * hardware using the dev and priv structures of the first port,
- * so that we are using only one set of variables to maintain
- * the board interface status, but we want to use the Nth port
- * dev and priv structures to maintain statistics and to pass
- * the packet up.
- *
- * Only the first device structure is attached to the interrupt.
- * We use the special "chan" variable at the end of the first RBD
- * to select the Nth device in multi-NIC mode.
- *
- * We currently do chained DMA on a per-packet basis when the
- * packet is "long", and we spin the CPU a short time polling
- * for DMA completion. This avoids a second interrupt overhead,
- * and gives the best performance for light traffic to the host.
- *
- * However, a better scheme that could be implemented would be
- * to see how many packets are outstanding for the host, and if
- * the number is "large", create a long chain to DMA several
- * packets into the host in one go. In this case, we would set
- * up some state variables to let the host CPU continue doing
- * other things until a DMA completion interrupt comes along.
- */
-static void
-dgrs_rcv_frame(
- struct net_device *dev0,
- DGRS_PRIV *priv0,
- I596_CB *cbp
-)
-{
- int len;
- I596_TBD *tbdp;
- struct sk_buff *skb;
- uchar *putp;
- uchar *p;
- struct net_device *devN;
- DGRS_PRIV *privN;
-
- /*
- * Determine Nth priv and dev structure pointers
- */
- if (dgrs_nicmode)
- { /* Multi-NIC mode */
- int chan = ((I596_RBD *) S2H(cbp->xmit.tbdp))->chan;
-
- devN = priv0->devtbl[chan-1];
- /*
- * If devN is null, we got an interrupt before the I/F
- * has been initialized. Pitch the packet.
- */
- if (devN == NULL)
- goto out;
- privN = (DGRS_PRIV *) devN->priv;
- }
- else
- { /* Switch mode */
- devN = dev0;
- privN = priv0;
- }
-
- if (0) printk("%s: rcv len=%ld\n", devN->name, cbp->xmit.count);
-
- /*
- * Allocate a message block big enough to hold the whole frame
- */
- len = cbp->xmit.count;
- if ((skb = dev_alloc_skb(len+5)) == NULL)
- {
- printk("%s: dev_alloc_skb failed for rcv buffer\n", devN->name);
- ++privN->stats.rx_dropped;
- /* discarding the frame */
- goto out;
- }
- skb_reserve(skb, 2); /* Align IP header */
-
-again:
- putp = p = skb_put(skb, len);
-
- /*
- * There are three modes here for doing the packet copy.
- * If we have DMA, and the packet is "long", we use the
- * chaining mode of DMA. If it's shorter, we use single
- * DMA's. Otherwise, we use memcpy().
- */
- if (priv0->use_dma && priv0->dmadesc_h && len > 64)
- {
- /*
- * If we can use DMA and it's a long frame, copy it using
- * DMA chaining.
- */
- DMACHAIN *ddp_h; /* Host virtual DMA desc. pointer */
- DMACHAIN *ddp_s; /* Switch physical DMA desc. pointer */
- uchar *phys_p;
-
- /*
- * Get the physical address of the STREAMS buffer.
- * NOTE: allocb() guarantees that the whole buffer
- * is in a single page if the length < 4096.
- */
- phys_p = (uchar *) virt_to_phys(putp);
-
- ddp_h = priv0->dmadesc_h;
- ddp_s = priv0->dmadesc_s;
- tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);
- for (;;)
- {
- int count;
- int amt;
-
- count = tbdp->count;
- amt = count & 0x3fff;
- if (amt == 0)
- break; /* For safety */
- if ( (p-putp) >= len)
- {
- printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp));
- proc_reset(dev0, 1); /* Freeze IDT */
- break; /* For Safety */
- }
-
- ddp_h->pciaddr = (ulong) phys_p;
- ddp_h->lcladdr = S2DMA(tbdp->buf);
- ddp_h->len = amt;
-
- phys_p += amt;
- p += amt;
-
- if (count & I596_TBD_EOF)
- {
- ddp_h->next = PLX_DMA_DESC_TO_HOST
- | PLX_DMA_DESC_EOC;
- ++ddp_h;
- break;
- }
- else
- {
- ++ddp_s;
- ddp_h->next = PLX_DMA_DESC_TO_HOST
- | (ulong) ddp_s;
- tbdp = (I596_TBD *) S2H(tbdp->next);
- ++ddp_h;
- }
- }
- if (ddp_h - priv0->dmadesc_h)
- {
- int rc;
-
- rc = do_plx_dma(dev0,
- 0, (ulong) priv0->dmadesc_s, len, 0);
- if (rc)
- {
- printk("%s: Chained DMA failure\n", devN->name);
- goto again;
- }
- }
- }
- else if (priv0->use_dma)
- {
- /*
- * If we can use DMA and it's a shorter frame, copy it
- * using single DMA transfers.
- */
- uchar *phys_p;
-
- /*
- * Get the physical address of the STREAMS buffer.
- * NOTE: allocb() guarantees that the whole buffer
- * is in a single page if the length < 4096.
- */
- phys_p = (uchar *) virt_to_phys(putp);
-
- tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);
- for (;;)
- {
- int count;
- int amt;
- int rc;
-
- count = tbdp->count;
- amt = count & 0x3fff;
- if (amt == 0)
- break; /* For safety */
- if ( (p-putp) >= len)
- {
- printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp));
- proc_reset(dev0, 1); /* Freeze IDT */
- break; /* For Safety */
- }
- rc = do_plx_dma(dev0, (ulong) phys_p,
- S2DMA(tbdp->buf), amt, 1);
- if (rc)
- {
- memcpy(p, S2H(tbdp->buf), amt);
- printk("%s: Single DMA failed\n", devN->name);
- }
- phys_p += amt;
- p += amt;
- if (count & I596_TBD_EOF)
- break;
- tbdp = (I596_TBD *) S2H(tbdp->next);
- }
- }
- else
- {
- /*
- * Otherwise, copy it piece by piece using memcpy()
- */
- tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);
- for (;;)
- {
- int count;
- int amt;
-
- count = tbdp->count;
- amt = count & 0x3fff;
- if (amt == 0)
- break; /* For safety */
- if ( (p-putp) >= len)
- {
- printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp));
- proc_reset(dev0, 1); /* Freeze IDT */
- break; /* For Safety */
- }
- memcpy(p, S2H(tbdp->buf), amt);
- p += amt;
- if (count & I596_TBD_EOF)
- break;
- tbdp = (I596_TBD *) S2H(tbdp->next);
- }
- }
-
- /*
- * Pass the frame to upper half
- */
- skb->protocol = eth_type_trans(skb, devN);
- netif_rx(skb);
- devN->last_rx = jiffies;
- ++privN->stats.rx_packets;
- privN->stats.rx_bytes += len;
-
-out:
- cbp->xmit.status = I596_CB_STATUS_C | I596_CB_STATUS_OK;
-}
-
-/*
- * Start transmission of a frame
- *
- * The interface to the board is simple: we pretend that we are
- * a fifth 82596 ethernet controller 'receiving' data, and copy the
- * data into the same structures that a real 82596 would. This way,
- * the board firmware handles the host 'port' the same as any other.
- *
- * NOTE: we do not use Bus master DMA for this routine. Turns out
- * that it is not needed. Slave writes over the PCI bus are about
- * as fast as DMA, due to the fact that the PLX part can do burst
- * writes. The same is not true for data being read from the board.
- *
- * For multi-NIC mode, we tell the firmware the desired 82596
- * output port by setting the special "dstchan" member at the
- * end of the traditional 82596 RFD structure.
- */
-
-static int dgrs_start_xmit(struct sk_buff *skb, struct net_device *devN)
-{
- DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv;
- struct net_device *dev0;
- DGRS_PRIV *priv0;
- I596_RBD *rbdp;
- int count;
- int i, len, amt;
-
- /*
- * Determine 0th priv and dev structure pointers
- */
- if (dgrs_nicmode)
- {
- dev0 = privN->devtbl[0];
- priv0 = (DGRS_PRIV *) dev0->priv;
- }
- else
- {
- dev0 = devN;
- priv0 = privN;
- }
-
- if (dgrs_debug > 1)
- printk("%s: xmit len=%d\n", devN->name, (int) skb->len);
-
- devN->trans_start = jiffies;
- netif_start_queue(devN);
-
- if (priv0->rfdp->cmd & I596_RFD_EL)
- { /* Out of RFD's */
- if (0) printk("%s: NO RFD's\n", devN->name);
- goto no_resources;
- }
-
- rbdp = priv0->rbdp;
- count = 0;
- priv0->rfdp->rbdp = (I596_RBD *) H2S(rbdp);
-
- i = 0; len = skb->len;
- for (;;)
- {
- if (rbdp->size & I596_RBD_EL)
- { /* Out of RBD's */
- if (0) printk("%s: NO RBD's\n", devN->name);
- goto no_resources;
- }
-
- amt = min_t(unsigned int, len, rbdp->size - count);
- skb_copy_from_linear_data_offset(skb, i, S2H(rbdp->buf) + count, amt);
- i += amt;
- count += amt;
- len -= amt;
- if (len == 0)
- {
- if (skb->len < 60)
- rbdp->count = 60 | I596_RBD_EOF;
- else
- rbdp->count = count | I596_RBD_EOF;
- rbdp = (I596_RBD *) S2H(rbdp->next);
- goto frame_done;
- }
- else if (count < 32)
- {
- /* More data to come, but we used less than 32
- * bytes of this RBD. Keep filling this RBD.
- */
- {} /* Yes, we do nothing here */
- }
- else
- {
- rbdp->count = count;
- rbdp = (I596_RBD *) S2H(rbdp->next);
- count = 0;
- }
- }
-
-frame_done:
- priv0->rbdp = rbdp;
- if (dgrs_nicmode)
- priv0->rfdp->dstchan = privN->chan;
- priv0->rfdp->status = I596_RFD_C | I596_RFD_OK;
- priv0->rfdp = (I596_RFD *) S2H(priv0->rfdp->next);
-
- ++privN->stats.tx_packets;
-
- dev_kfree_skb (skb);
- return (0);
-
-no_resources:
- priv0->scbp->status |= I596_SCB_RNR; /* simulate I82596 */
- return (-EAGAIN);
-}
-
-/*
- * Open the interface
- */
-static int
-dgrs_open( struct net_device *dev )
-{
- netif_start_queue(dev);
- return (0);
-}
-
-/*
- * Close the interface
- */
-static int dgrs_close( struct net_device *dev )
-{
- netif_stop_queue(dev);
- return (0);
-}
-
-/*
- * Get statistics
- */
-static struct net_device_stats *dgrs_get_stats( struct net_device *dev )
-{
- DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
-
- return (&priv->stats);
-}
-
-/*
- * Set multicast list and/or promiscuous mode
- */
-
-static void dgrs_set_multicast_list( struct net_device *dev)
-{
- DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
-
- priv->port->is_promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
-}
-
-/*
- * Unique ioctl's
- */
-static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd)
-{
- DGRS_PRIV *privN = (DGRS_PRIV *) devN->priv;
- DGRS_IOCTL ioc;
- int i;
-
- if (cmd != DGRSIOCTL)
- return -EINVAL;
-
- if(copy_from_user(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL)))
- return -EFAULT;
-
- switch (ioc.cmd)
- {
- case DGRS_GETMEM:
- if (ioc.len != sizeof(ulong))
- return -EINVAL;
- if(copy_to_user(ioc.data, &devN->mem_start, ioc.len))
- return -EFAULT;
- return (0);
- case DGRS_SETFILTER:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (ioc.port > privN->bcomm->bc_nports)
- return -EINVAL;
- if (ioc.filter >= NFILTERS)
- return -EINVAL;
- if (ioc.len > privN->bcomm->bc_filter_area_len)
- return -EINVAL;
-
- /* Wait for old command to finish */
- for (i = 0; i < 1000; ++i)
- {
- if ( (volatile long) privN->bcomm->bc_filter_cmd <= 0 )
- break;
- udelay(1);
- }
- if (i >= 1000)
- return -EIO;
-
- privN->bcomm->bc_filter_port = ioc.port;
- privN->bcomm->bc_filter_num = ioc.filter;
- privN->bcomm->bc_filter_len = ioc.len;
-
- if (ioc.len)
- {
- if(copy_from_user(S2HN(privN->bcomm->bc_filter_area),
- ioc.data, ioc.len))
- return -EFAULT;
- privN->bcomm->bc_filter_cmd = BC_FILTER_SET;
- }
- else
- privN->bcomm->bc_filter_cmd = BC_FILTER_CLR;
- return(0);
- default:
- return -EOPNOTSUPP;
- }
-}
-
-/*
- * Process interrupts
- *
- * dev, priv will always refer to the 0th device in Multi-NIC mode.
- */
-
-static irqreturn_t dgrs_intr(int irq, void *dev_id)
-{
- struct net_device *dev0 = dev_id;
- DGRS_PRIV *priv0 = dev0->priv;
- I596_CB *cbp;
- int cmd;
- int i;
-
- ++priv0->intrcnt;
- if (1) ++priv0->bcomm->bc_cnt[4];
- if (0)
- {
- static int cnt = 100;
- if (--cnt > 0)
- printk("%s: interrupt: irq %d\n", dev0->name, irq);
- }
-
- /*
- * Get 596 command
- */
- cmd = priv0->scbp->cmd;
-
- /*
- * See if RU has been restarted
- */
- if ( (cmd & I596_SCB_RUC) == I596_SCB_RUC_START)
- {
- if (0) printk("%s: RUC start\n", dev0->name);
- priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp);
- priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp);
- priv0->scbp->status &= ~(I596_SCB_RNR|I596_SCB_RUS);
- /*
- * Tell upper half (halves)
- */
- if (dgrs_nicmode)
- {
- for (i = 0; i < priv0->nports; ++i)
- netif_wake_queue (priv0->devtbl[i]);
- }
- else
- netif_wake_queue (dev0);
- /* if (bd->flags & TX_QUEUED)
- DL_sched(bd, bdd); */
- }
-
- /*
- * See if any CU commands to process
- */
- if ( (cmd & I596_SCB_CUC) != I596_SCB_CUC_START)
- {
- priv0->scbp->cmd = 0; /* Ignore all other commands */
- goto ack_intr;
- }
- priv0->scbp->status &= ~(I596_SCB_CNA|I596_SCB_CUS);
-
- /*
- * Process a command
- */
- cbp = (I596_CB *) S2H(priv0->scbp->cbp);
- priv0->scbp->cmd = 0; /* Safe to clear the command */
- for (;;)
- {
- switch (cbp->nop.cmd & I596_CB_CMD)
- {
- case I596_CB_CMD_XMIT:
- dgrs_rcv_frame(dev0, priv0, cbp);
- break;
- default:
- cbp->nop.status = I596_CB_STATUS_C | I596_CB_STATUS_OK;
- break;
- }
- if (cbp->nop.cmd & I596_CB_CMD_EL)
- break;
- cbp = (I596_CB *) S2H(cbp->nop.next);
- }
- priv0->scbp->status |= I596_SCB_CNA;
-
- /*
- * Ack the interrupt
- */
-ack_intr:
- if (priv0->plxreg)
- OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1);
-
- return IRQ_HANDLED;
-}
-
-/*
- * Download the board firmware
- */
-static int __init
-dgrs_download(struct net_device *dev0)
-{
- DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv;
- int is;
- unsigned long i;
-
- static const int iv2is[16] = {
- 0, 0, 0, ES4H_IS_INT3,
- 0, ES4H_IS_INT5, 0, ES4H_IS_INT7,
- 0, 0, ES4H_IS_INT10, ES4H_IS_INT11,
- ES4H_IS_INT12, 0, 0, ES4H_IS_INT15 };
-
- /*
- * Map in the dual port memory
- */
- priv0->vmem = ioremap(dev0->mem_start, 2048*1024);
- if (!priv0->vmem)
- {
- printk("%s: cannot map in board memory\n", dev0->name);
- return -ENXIO;
- }
-
- /*
- * Hold the processor and configure the board addresses
- */
- if (priv0->plxreg)
- { /* PCI bus */
- proc_reset(dev0, 1);
- }
- else
- { /* EISA bus */
- is = iv2is[dev0->irq & 0x0f];
- if (!is)
- {
- printk("%s: Illegal IRQ %d\n", dev0->name, dev0->irq);
- iounmap(priv0->vmem);
- priv0->vmem = NULL;
- return -ENXIO;
- }
- OUTB(dev0->base_addr + ES4H_AS_31_24,
- (uchar) (dev0->mem_start >> 24) );
- OUTB(dev0->base_addr + ES4H_AS_23_16,
- (uchar) (dev0->mem_start >> 16) );
- priv0->is_reg = ES4H_IS_LINEAR | is |
- ((uchar) (dev0->mem_start >> 8) & ES4H_IS_AS15);
- OUTB(dev0->base_addr + ES4H_IS, priv0->is_reg);
- OUTB(dev0->base_addr + ES4H_EC, ES4H_EC_ENABLE);
- OUTB(dev0->base_addr + ES4H_PC, ES4H_PC_RESET);
- OUTB(dev0->base_addr + ES4H_MW, ES4H_MW_ENABLE | 0x00);
- }
-
- /*
- * See if we can do DMA on the SE-6
- */
- priv0->use_dma = check_board_dma(dev0);
- if (priv0->use_dma)
- printk("%s: Bus Master DMA is enabled.\n", dev0->name);
-
- /*
- * Load and verify the code at the desired address
- */
- memcpy(priv0->vmem, dgrs_code, dgrs_ncode); /* Load code */
- if (memcmp(priv0->vmem, dgrs_code, dgrs_ncode))
- {
- iounmap(priv0->vmem);
- priv0->vmem = NULL;
- printk("%s: download compare failed\n", dev0->name);
- return -ENXIO;
- }
-
- /*
- * Configurables
- */
- priv0->bcomm = (struct bios_comm *) (priv0->vmem + 0x0100);
- priv0->bcomm->bc_nowait = 1; /* Tell board to make printf not wait */
- priv0->bcomm->bc_squelch = 0; /* Flag from Space.c */
- priv0->bcomm->bc_150ohm = 0; /* Flag from Space.c */
-
- priv0->bcomm->bc_spew = 0; /* Debug flag from Space.c */
- priv0->bcomm->bc_maxrfd = 0; /* Debug flag from Space.c */
- priv0->bcomm->bc_maxrbd = 0; /* Debug flag from Space.c */
-
- /*
- * Tell board we are operating in switch mode (1) or in
- * multi-NIC mode (2).
- */
- priv0->bcomm->bc_host = dgrs_nicmode ? BC_MULTINIC : BC_SWITCH;
-
- /*
- * Request memory space on board for DMA chains
- */
- if (priv0->use_dma)
- priv0->bcomm->bc_hostarea_len = (2048/64) * 16;
-
- /*
- * NVRAM configurables from Space.c
- */
- priv0->bcomm->bc_spantree = dgrs_spantree;
- priv0->bcomm->bc_hashexpire = dgrs_hashexpire;
- memcpy(priv0->bcomm->bc_ipaddr, dgrs_ipaddr, 4);
- memcpy(priv0->bcomm->bc_iptrap, dgrs_iptrap, 4);
- memcpy(priv0->bcomm->bc_ipxnet, &dgrs_ipxnet, 4);
-
- /*
- * Release processor, wait 8 seconds for board to initialize
- */
- proc_reset(dev0, 0);
-
- for (i = jiffies + 8 * HZ; time_after(i, jiffies); )
- {
- barrier(); /* Gcc 2.95 needs this */
- if (priv0->bcomm->bc_status >= BC_RUN)
- break;
- }
-
- if (priv0->bcomm->bc_status < BC_RUN)
- {
- printk("%s: board not operating\n", dev0->name);
- iounmap(priv0->vmem);
- priv0->vmem = NULL;
- return -ENXIO;
- }
-
- priv0->port = (PORT *) S2H(priv0->bcomm->bc_port);
- priv0->scbp = (I596_SCB *) S2H(priv0->port->scbp);
- priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp);
- priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp);
-
- priv0->scbp->status = I596_SCB_CNA; /* CU is idle */
-
- /*
- * Get switch physical and host virtual pointers to DMA
- * chaining area. NOTE: the MSB of the switch physical
- * address *must* be turned off. Otherwise, the HW kludge
- * that allows host access of the PLX DMA registers will
- * erroneously select the PLX registers.
- */
- priv0->dmadesc_s = (DMACHAIN *) S2DMA(priv0->bcomm->bc_hostarea);
- if (priv0->dmadesc_s)
- priv0->dmadesc_h = (DMACHAIN *) S2H(priv0->dmadesc_s);
- else
- priv0->dmadesc_h = NULL;
-
- /*
- * Enable board interrupts
- */
- if (priv0->plxreg)
- { /* PCI bus */
- OUTL(dev0->base_addr + PLX_INT_CSR,
- inl(dev0->base_addr + PLX_INT_CSR)
- | PLX_PCI_DOORBELL_IE); /* Enable intr to host */
- OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1);
- }
- else
- { /* EISA bus */
- }
-
- return (0);
-}
-
-/*
- * Probe (init) a board
- */
-static int __init
-dgrs_probe1(struct net_device *dev)
-{
- DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
- unsigned long i;
- int rc;
-
- printk("%s: Digi RightSwitch io=%lx mem=%lx irq=%d plx=%lx dma=%lx\n",
- dev->name, dev->base_addr, dev->mem_start, dev->irq,
- priv->plxreg, priv->plxdma);
-
- /*
- * Download the firmware and light the processor
- */
- rc = dgrs_download(dev);
- if (rc)
- goto err_out;
-
- /*
- * Get ether address of board
- */
- printk("%s: Ethernet address", dev->name);
- memcpy(dev->dev_addr, priv->port->ethaddr, 6);
- for (i = 0; i < 6; ++i)
- printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
- printk("\n");
-
- if (dev->dev_addr[0] & 1)
- {
- printk("%s: Illegal Ethernet Address\n", dev->name);
- rc = -ENXIO;
- goto err_out;
- }
-
- /*
- * ACK outstanding interrupts, hook the interrupt,
- * and verify that we are getting interrupts from the board.
- */
- if (priv->plxreg)
- OUTL(dev->base_addr + PLX_LCL2PCI_DOORBELL, 1);
-
- rc = request_irq(dev->irq, &dgrs_intr, IRQF_SHARED, "RightSwitch", dev);
- if (rc)
- goto err_out;
-
- priv->intrcnt = 0;
- for (i = jiffies + 2*HZ + HZ/2; time_after(i, jiffies); )
- {
- cpu_relax();
- if (priv->intrcnt >= 2)
- break;
- }
- if (priv->intrcnt < 2)
- {
- printk(KERN_ERR "%s: Not interrupting on IRQ %d (%d)\n",
- dev->name, dev->irq, priv->intrcnt);
- rc = -ENXIO;
- goto err_free_irq;
- }
-
- /*
- * Entry points...
- */
- dev->open = &dgrs_open;
- dev->stop = &dgrs_close;
- dev->get_stats = &dgrs_get_stats;
- dev->hard_start_xmit = &dgrs_start_xmit;
- dev->set_multicast_list = &dgrs_set_multicast_list;
- dev->do_ioctl = &dgrs_ioctl;
-
- return rc;
-
-err_free_irq:
- free_irq(dev->irq, dev);
-err_out:
- return rc;
-}
-
-static int __init
-dgrs_initclone(struct net_device *dev)
-{
- DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
- int i;
-
- printk("%s: Digi RightSwitch port %d ",
- dev->name, priv->chan);
- for (i = 0; i < 6; ++i)
- printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
- printk("\n");
-
- return (0);
-}
-
-static struct net_device * __init
-dgrs_found_device(
- int io,
- ulong mem,
- int irq,
- ulong plxreg,
- ulong plxdma,
- struct device *pdev
-)
-{
- DGRS_PRIV *priv;
- struct net_device *dev;
- int i, ret = -ENOMEM;
-
- dev = alloc_etherdev(sizeof(DGRS_PRIV));
- if (!dev)
- goto err0;
-
- priv = (DGRS_PRIV *)dev->priv;
-
- dev->base_addr = io;
- dev->mem_start = mem;
- dev->mem_end = mem + 2048 * 1024 - 1;
- dev->irq = irq;
- priv->plxreg = plxreg;
- priv->plxdma = plxdma;
- priv->vplxdma = NULL;
-
- priv->chan = 1;
- priv->devtbl[0] = dev;
-
- SET_MODULE_OWNER(dev);
- SET_NETDEV_DEV(dev, pdev);
-
- ret = dgrs_probe1(dev);
- if (ret)
- goto err1;
-
- ret = register_netdev(dev);
- if (ret)
- goto err2;
-
- if ( !dgrs_nicmode )
- return dev; /* Switch mode, we are done */
-
- /*
- * Operating card as N separate NICs
- */
-
- priv->nports = priv->bcomm->bc_nports;
-
- for (i = 1; i < priv->nports; ++i)
- {
- struct net_device *devN;
- DGRS_PRIV *privN;
- /* Allocate new dev and priv structures */
- devN = alloc_etherdev(sizeof(DGRS_PRIV));
- ret = -ENOMEM;
- if (!devN)
- goto fail;
-
- /* Don't copy the network device structure! */
-
- /* copy the priv structure of dev[0] */
- privN = (DGRS_PRIV *)devN->priv;
- *privN = *priv;
-
- /* ... and zero out VM areas */
- privN->vmem = NULL;
- privN->vplxdma = NULL;
- /* ... and zero out IRQ */
- devN->irq = 0;
- /* ... and base MAC address off address of 1st port */
- devN->dev_addr[5] += i;
-
- ret = dgrs_initclone(devN);
- if (ret)
- goto fail;
-
- SET_MODULE_OWNER(devN);
- SET_NETDEV_DEV(dev, pdev);
-
- ret = register_netdev(devN);
- if (ret) {
- free_netdev(devN);
- goto fail;
- }
- privN->chan = i+1;
- priv->devtbl[i] = devN;
- }
- return dev;
-
- fail:
- while (i >= 0) {
- struct net_device *d = priv->devtbl[i--];
- unregister_netdev(d);
- free_netdev(d);
- }
-
- err2:
- free_irq(dev->irq, dev);
- err1:
- free_netdev(dev);
- err0:
- return ERR_PTR(ret);
-}
-
-static void __devexit dgrs_remove(struct net_device *dev)
-{
- DGRS_PRIV *priv = dev->priv;
- int i;
-
- unregister_netdev(dev);
-
- for (i = 1; i < priv->nports; ++i) {
- struct net_device *d = priv->devtbl[i];
- if (d) {
- unregister_netdev(d);
- free_netdev(d);
- }
- }
-
- proc_reset(priv->devtbl[0], 1);
-
- if (priv->vmem)
- iounmap(priv->vmem);
- if (priv->vplxdma)
- iounmap((uchar *) priv->vplxdma);
-
- if (dev->irq)
- free_irq(dev->irq, dev);
-
- for (i = 1; i < priv->nports; ++i) {
- if (priv->devtbl[i])
- unregister_netdev(priv->devtbl[i]);
- }
-}
-
-#ifdef CONFIG_PCI
-static int __init dgrs_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct net_device *dev;
- int err;
- uint io;
- uint mem;
- uint irq;
- uint plxreg;
- uint plxdma;
-
- /*
- * Get and check the bus-master and latency values.
- * Some PCI BIOSes fail to set the master-enable bit,
- * and the latency timer must be set to the maximum
- * value to avoid data corruption that occurs when the
- * timer expires during a transfer. Yes, it's a bug.
- */
- err = pci_enable_device(pdev);
- if (err)
- return err;
- err = pci_request_regions(pdev, "RightSwitch");
- if (err)
- return err;
-
- pci_set_master(pdev);
-
- plxreg = pci_resource_start (pdev, 0);
- io = pci_resource_start (pdev, 1);
- mem = pci_resource_start (pdev, 2);
- pci_read_config_dword(pdev, 0x30, &plxdma);
- irq = pdev->irq;
- plxdma &= ~15;
-
- /*
- * On some BIOSES, the PLX "expansion rom" (used for DMA)
- * address comes up as "0". This is probably because
- * the BIOS doesn't see a valid 55 AA ROM signature at
- * the "ROM" start and zeroes the address. To get
- * around this problem the SE-6 is configured to ask
- * for 4 MB of space for the dual port memory. We then
- * must set its range back to 2 MB, and use the upper
- * half for DMA register access
- */
- OUTL(io + PLX_SPACE0_RANGE, 0xFFE00000L);
- if (plxdma == 0)
- plxdma = mem + (2048L * 1024L);
- pci_write_config_dword(pdev, 0x30, plxdma + 1);
- pci_read_config_dword(pdev, 0x30, &plxdma);
- plxdma &= ~15;
-
- dev = dgrs_found_device(io, mem, irq, plxreg, plxdma, &pdev->dev);
- if (IS_ERR(dev)) {
- pci_release_regions(pdev);
- return PTR_ERR(dev);
- }
-
- pci_set_drvdata(pdev, dev);
- return 0;
-}
-
-static void __devexit dgrs_pci_remove(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
-
- dgrs_remove(dev);
- pci_release_regions(pdev);
- free_netdev(dev);
-}
-
-static struct pci_driver dgrs_pci_driver = {
- .name = "dgrs",
- .id_table = dgrs_pci_tbl,
- .probe = dgrs_pci_probe,
- .remove = __devexit_p(dgrs_pci_remove),
-};
-#else
-static struct pci_driver dgrs_pci_driver = {};
-#endif
-
-
-#ifdef CONFIG_EISA
-static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 };
-
-static int __init dgrs_eisa_probe (struct device *gendev)
-{
- struct net_device *dev;
- struct eisa_device *edev = to_eisa_device(gendev);
- uint io = edev->base_addr;
- uint mem;
- uint irq;
- int rc = -ENODEV; /* Not EISA configured */
-
- if (!request_region(io, 256, "RightSwitch")) {
- printk(KERN_ERR "dgrs: eisa io 0x%x, which is busy.\n", io);
- return -EBUSY;
- }
-
- if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) )
- goto err_out;
-
- mem = (inb(io+ES4H_AS_31_24) << 24)
- + (inb(io+ES4H_AS_23_16) << 16);
-
- irq = is2iv[ inb(io+ES4H_IS) & ES4H_IS_INTMASK ];
-
- dev = dgrs_found_device(io, mem, irq, 0L, 0L, gendev);
- if (IS_ERR(dev)) {
- rc = PTR_ERR(dev);
- goto err_out;
- }
-
- gendev->driver_data = dev;
- return 0;
- err_out:
- release_region(io, 256);
- return rc;
-}
-
-static int __devexit dgrs_eisa_remove(struct device *gendev)
-{
- struct net_device *dev = gendev->driver_data;
-
- dgrs_remove(dev);
-
- release_region(dev->base_addr, 256);
-
- free_netdev(dev);
- return 0;
-}
-
-
-static struct eisa_driver dgrs_eisa_driver = {
- .id_table = dgrs_eisa_tbl,
- .driver = {
- .name = "dgrs",
- .probe = dgrs_eisa_probe,
- .remove = __devexit_p(dgrs_eisa_remove),
- }
-};
-#endif
-
-/*
- * Variables that can be overriden from module command line
- */
-static int debug = -1;
-static int dma = -1;
-static int hashexpire = -1;
-static int spantree = -1;
-static int ipaddr[4] = { -1 };
-static int iptrap[4] = { -1 };
-static __u32 ipxnet = -1;
-static int nicmode = -1;
-
-module_param(debug, int, 0);
-module_param(dma, int, 0);
-module_param(hashexpire, int, 0);
-module_param(spantree, int, 0);
-module_param_array(ipaddr, int, NULL, 0);
-module_param_array(iptrap, int, NULL, 0);
-module_param(ipxnet, int, 0);
-module_param(nicmode, int, 0);
-MODULE_PARM_DESC(debug, "Digi RightSwitch enable debugging (0-1)");
-MODULE_PARM_DESC(dma, "Digi RightSwitch enable BM DMA (0-1)");
-MODULE_PARM_DESC(nicmode, "Digi RightSwitch operating mode (1: switch, 2: multi-NIC)");
-
-static int __init dgrs_init_module (void)
-{
- int i;
- int err;
-
- /*
- * Command line variable overrides
- * debug=NNN
- * dma=0/1
- * spantree=0/1
- * hashexpire=NNN
- * ipaddr=A,B,C,D
- * iptrap=A,B,C,D
- * ipxnet=NNN
- * nicmode=NNN
- */
- if (debug >= 0)
- dgrs_debug = debug;
- if (dma >= 0)
- dgrs_dma = dma;
- if (nicmode >= 0)
- dgrs_nicmode = nicmode;
- if (hashexpire >= 0)
- dgrs_hashexpire = hashexpire;
- if (spantree >= 0)
- dgrs_spantree = spantree;
- if (ipaddr[0] != -1)
- for (i = 0; i < 4; ++i)
- dgrs_ipaddr[i] = ipaddr[i];
- if (iptrap[0] != -1)
- for (i = 0; i < 4; ++i)
- dgrs_iptrap[i] = iptrap[i];
- if (ipxnet != -1)
- dgrs_ipxnet = htonl( ipxnet );
-
- if (dgrs_debug)
- {
- printk(KERN_INFO "dgrs: SW=%s FW=Build %d %s\nFW Version=%s\n",
- version, dgrs_firmnum, dgrs_firmdate, dgrs_firmver);
- }
-
- /*
- * Find and configure all the cards
- */
-#ifdef CONFIG_EISA
- err = eisa_driver_register(&dgrs_eisa_driver);
- if (err)
- return err;
-#endif
- err = pci_register_driver(&dgrs_pci_driver);
- if (err)
- return err;
- return 0;
-}
-
-static void __exit dgrs_cleanup_module (void)
-{
-#ifdef CONFIG_EISA
- eisa_driver_unregister (&dgrs_eisa_driver);
-#endif
-#ifdef CONFIG_PCI
- pci_unregister_driver (&dgrs_pci_driver);
-#endif
-}
-
-module_init(dgrs_init_module);
-module_exit(dgrs_cleanup_module);
diff --git a/drivers/net/dgrs.h b/drivers/net/dgrs.h
deleted file mode 100644
index 6058d5301cb..00000000000
--- a/drivers/net/dgrs.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * ioctl's for the Digi Intl. RightSwitch
- *
- * These network driver ioctl's are a bit obtuse compared to the usual
- * ioctl's for a "normal" device driver. Hey, I didn't invent it.
- *
- * Typical use:
- *
- * struct ifreq ifr;
- * DGRS_IOCTL ioc;
- * int x;
- *
- * strcpy(ifr.ifr_name, "eth1");
- * ifr.ifr_data = (caddr_t) &ioc;
- * ioc.cmd = DGRS_GETMEM;
- * ioc.len = sizeof(x);
- * ioc.data = (caddr_t) &x;
- * rc = ioctl(fd, DGRSIOCTL, &ifr);
- * printf("rc=%d mem=%x\n", rc, x);
- *
- */
-#include <linux/sockios.h>
-
-#define DGRSIOCTL SIOCDEVPRIVATE
-
-typedef struct dgrs_ioctl {
- unsigned short cmd; /* Command to run */
- unsigned short len; /* Length of the data buffer */
- unsigned char __user *data; /* Pointer to the data buffer */
- unsigned short port; /* port number for command, if needed */
- unsigned short filter; /* filter number for command, if needed */
-} DGRS_IOCTL;
-
-/*
- * Commands for the driver
- */
-#define DGRS_GETMEM 0x01 /* Get the dual port memory address */
-#define DGRS_SETFILTER 0x02 /* Set a filter */
diff --git a/drivers/net/dgrs_asstruct.h b/drivers/net/dgrs_asstruct.h
deleted file mode 100644
index f0e2121770f..00000000000
--- a/drivers/net/dgrs_asstruct.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * For declaring structures shared with assembly routines
- *
- * $Id: asstruct.h,v 1.1.1.1 1994/10/23 05:08:32 rick Exp $
- */
-
-#ifdef ASSEMBLER
-
-# define MO(t,a) (a)
-# define VMO(t,a) (a)
-
-# define BEGIN_STRUCT(x) _Off=0
-# define S1A(t,x,n) _Off=(_Off+0)&~0; x=_Off; _Off=_Off+(1*n)
-# define S2A(t,x,n) _Off=(_Off+1)&~1; x=_Off; _Off=_Off+(2*n)
-# define S4A(t,x,n) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+(4*n)
-# define WORD(x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
-# define WORDA(x,n) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+(4*n)
-# define VWORD(x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
-# define S1(t,x) _Off=(_Off+0)&~0; x=_Off; _Off=_Off+1
-# define S2(t,x) _Off=(_Off+1)&~1; x=_Off; _Off=_Off+2
-# define S4(t,x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
-# define END_STRUCT(x) _Off=(_Off+3)&~3; x=_Off
-
-#else /* C */
-
-#define VMO(t,a) (*(volatile t *)(a))
-
-# define BEGIN_STRUCT(x) struct x {
-# define S1(t,x) t x ;
-# define S1A(t,x,n) t x[n] ;
-# define S2(t,x) t x ;
-# define S2A(t,x,n) t x[n] ;
-# define S4(t,x) t x ;
-# define S4A(t,x,n) t x[n] ;
-# define END_STRUCT(x) } ;
-
-#endif
diff --git a/drivers/net/dgrs_bcomm.h b/drivers/net/dgrs_bcomm.h
deleted file mode 100644
index 5e9c2527398..00000000000
--- a/drivers/net/dgrs_bcomm.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * The bios low-memory structure
- *
- * Some of the variables in here can be used to set parameters that
- * are stored in NVRAM and will retain their old values the next time
- * the card is brought up. To use the values stored in NVRAM, the
- * parameter should be set to "all ones". This tells the firmware to
- * use the NVRAM value or a suitable default. The value that is used
- * will be stored back into this structure by the firmware. If the
- * value of the variable is not "all ones", then that value will be
- * used and will be stored into NVRAM if it isn't already there.
- * The variables this applies to are the following:
- * Variable Set to: Gets default of:
- * bc_hashexpire -1 300 (5 minutes)
- * bc_spantree -1 1 (spanning tree on)
- * bc_ipaddr FF:FF:FF:FF 0 (no SNMP IP address)
- * bc_ipxnet FF:FF:FF:FF 0 (no SNMP IPX net)
- * bc_iptrap FF:FF:FF:FF 0 (no SNMP IP trap address)
- *
- * Some variables MUST have their value set after the firmware
- * is loaded onto the board, but before the processor is released.
- * These are:
- * bc_host 0 means no host "port", run as standalone switch.
- * 1 means run as a switch, with a host port. (normal)
- * 2 means run as multiple NICs, not as a switch.
- * -1 means run in diagnostics mode.
- * bc_nowait
- * bc_hostarea_len
- * bc_filter_len
- *
- */
-BEGIN_STRUCT(bios_comm)
- S4(ulong, bc_intflag) /* Count of all interrupts */
- S4(ulong, bc_lbolt) /* Count of timer interrupts */
- S4(ulong, bc_maincnt) /* Count of main loops */
- S4(ulong, bc_hashcnt) /* Count of entries in hash table */
- S4A(ulong, bc_cnt, 8) /* Misc counters, for debugging */
- S4A(ulong, bc_flag, 8) /* Misc flags, for debugging */
- S4(ulong, bc_memsize) /* Size of memory */
- S4(ulong, bc_dcache) /* Size of working dcache */
- S4(ulong, bc_icache) /* Size of working icache */
- S4(long, bc_status) /* Firmware status */
- S1A(char, bc_file, 8) /* File name of assertion failure */
- S4(ulong, bc_line) /* Line # of assertion failure */
- S4(uchar *, bc_ramstart)
- S4(uchar *, bc_ramend)
- S4(uchar *, bc_heapstart) /* Start of heap (end of loaded memory) */
- S4(uchar *, bc_heapend) /* End of heap */
-
- /* Configurable Parameters */
- S4(long, bc_host) /* 1=Host Port, 0=No Host Port, -1=Test Mode */
- S4(long, bc_nowait) /* Don't wait for 2host circ buffer to empty*/
- S4(long, bc_150ohm) /* 0 == 100 ohm UTP, 1 == 150 ohm STP */
- S4(long, bc_squelch) /* 0 == normal squelch, 1 == reduced squelch */
- S4(ulong, bc_hashexpire) /* Expiry time in seconds for hash table */
- S4(long, bc_spantree) /* 1 == enable IEEE spanning tree */
-
- S2A(ushort, bc_eaddr, 3) /* New ether address */
- S2(ushort, bc_dummy1) /* padding for DOS compilers */
-
- /* Various debugging aids */
- S4(long, bc_debug) /* Debugging is turned on */
- S4(long, bc_spew) /* Spew data on port 4 for bs_spew seconds */
- S4(long, bc_spewlen) /* Length of spewed data packets */
- S4(long, bc_maxrfd) /* If != 0, max number of RFD's to allocate */
- S4(long, bc_maxrbd) /* If != 0, max number of RBD's to allocate */
-
- /* Circular buffers for messages to/from host */
- S4(ulong, bc_2host_head)
- S4(ulong, bc_2host_tail)
- S4(ulong, bc_2host_mask)
- S1A(char, bc_2host, 0x200) /* Circ buff to host */
-
- S4(ulong, bc_2idt_head)
- S4(ulong, bc_2idt_tail)
- S4(ulong, bc_2idt_mask)
- S1A(char, bc_2idt, 0x200) /* Circ buff to idt */
-
- /* Pointers to structures for driver access */
- S4(uchar *, bc_port) /* pointer to Port[] structures */
- S4(long, bc_nports) /* Number of ports */
- S4(long, bc_portlen) /* sizeof(PORT) */
- S4(uchar *, bc_hash) /* Pointer to hash table */
- S4(long, bc_hashlen) /* sizeof(Table) */
-
- /* SNMP agent addresses */
- S1A(uchar, bc_ipaddr, 4) /* IP address for SNMP */
- S1A(uchar, bc_ipxnet, 4) /* IPX net address for SNMP */
-
- S4(long, bc_nohostintr) /* Do not cause periodic host interrupts */
-
- S4(uchar *, bc_dmaaddr) /* Physical addr of host DMA buf for diags */
- S4(ulong, bc_dmalen) /* Length of DMA buffer 0..2048 */
-
- /*
- * Board memory allocated on startup for use by host, usually
- * for the purposes of creating DMA chain descriptors. The
- * "len" must be set before the processor is released. The
- * address of the area is returned in bc_hostarea. The area
- * is guaranteed to be aligned on a 16 byte boundary.
- */
- S4(ulong, bc_hostarea_len) /* RW: Number of bytes to allocate */
- S4(uchar *, bc_hostarea) /* RO: Address of allocated memory */
-
- /*
- * Variables for communicating filters into the board
- */
- S4(ulong *, bc_filter_area) /* RO: Space to put filter into */
- S4(ulong, bc_filter_area_len) /* RO: Length of area, in bytes */
- S4(long, bc_filter_cmd) /* RW: Filter command, see below */
- S4(ulong, bc_filter_len) /* RW: Actual length of filter */
- S4(ulong, bc_filter_port) /* RW: Port # for filter 0..6 */
- S4(ulong, bc_filter_num) /* RW: Filter #, 0=input, 1=output */
-
- /* more SNMP agent addresses */
- S1A(uchar, bc_iptrap, 4) /* IP address for SNMP */
-
- S4A(long, bc_spare, 2) /* spares */
-END_STRUCT(bios_comm)
-
-#define bc VMO(struct bios_comm, 0xa3000100)
-
-/*
- * bc_status values
- */
-#define BC_INIT 0
-#define BC_RUN 100
-
-/*
- * bc_host values
- */
-#define BC_DIAGS -1
-#define BC_SASWITCH 0
-#define BC_SWITCH 1
-#define BC_MULTINIC 2
-
-/*
- * Values for spew (debugging)
- */
-#define BC_SPEW_ENABLE 0x80000000
-
-/*
- * filter commands
- */
-#define BC_FILTER_ERR -1
-#define BC_FILTER_OK 0
-#define BC_FILTER_SET 1
-#define BC_FILTER_CLR 2
diff --git a/drivers/net/dgrs_es4h.h b/drivers/net/dgrs_es4h.h
deleted file mode 100644
index 5518fba46b2..00000000000
--- a/drivers/net/dgrs_es4h.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/************************************************************************/
-/* */
-/* es4h.h: Hardware definition of the ES/4h Ethernet Switch, from */
-/* both the host and the 3051's point of view. */
-/* NOTE: this name is a misnomer now that there is a PCI */
-/* board. Everything that says "es4h" should really be */
-/* "se4". But we'll keep the old name for now. */
-/* */
-/* $Id: es4h.h,v 1.10 1996/08/22 17:16:53 rick Exp $ */
-/* */
-/************************************************************************/
-
-/************************************************************************/
-/* */
-/* EISA I/O Registers. These are located at 0x1000 * slot-number */
-/* plus the indicated address. I.E. 0x4000-0x4009 for slot 4. */
-/* */
-/************************************************************************/
-
-#define ES4H_MANUFmsb 0x00 /* Read-only */
-#define ES4H_MANUFlsb 0x01 /* Read-only */
-# define ES4H_MANUF_CODE 0x1049 /* = "DBI" */
-
-#define ES4H_PRODUCT 0x02 /* Read-only */
-# define ES4H_PRODUCT_CODE 0x0A
-# define EPC_PRODUCT_CODE 0x03
-
-#define ES4H_REVISION 0x03 /* Read-only */
-# define ES4H_REVISION_CODE 0x01
-
-#define ES4H_EC 0x04 /* EISA Control */
-# define ES4H_EC_RESET 0x04 /* WO, EISA reset */
-# define ES4H_EC_ENABLE 0x01 /* RW, EISA enable - set to */
- /* 1 before memory enable */
-#define ES4H_PC 0x05 /* Processor Control */
-# define ES4H_PC_RESET 0x04 /* RW, 3051 reset */
-# define ES4H_PC_INT 0x08 /* WO, assert 3051 intr. 3 */
-
-#define ES4H_MW 0x06 /* Memory Window select and enable */
-# define ES4H_MW_ENABLE 0x80 /* WO, enable memory */
-# define ES4H_MW_SELECT_MASK 0x1f /* WO, 32k window selected */
-
-#define ES4H_IS 0x07 /* Interrupt, addr select */
-# define ES4H_IS_INTMASK 0x07 /* WO, interrupt select */
-# define ES4H_IS_INTOFF 0x00 /* No IRQ */
-# define ES4H_IS_INT3 0x03 /* IRQ 3 */
-# define ES4H_IS_INT5 0x02 /* IRQ 5 */
-# define ES4H_IS_INT7 0x01 /* IRQ 7 */
-# define ES4H_IS_INT10 0x04 /* IRQ 10 */
-# define ES4H_IS_INT11 0x05 /* IRQ 11 */
-# define ES4H_IS_INT12 0x06 /* IRQ 12 */
-# define ES4H_IS_INT15 0x07 /* IRQ 15 */
-# define ES4H_IS_INTACK 0x10 /* WO, interrupt ack */
-# define ES4H_IS_INTPEND 0x10 /* RO, interrupt pending */
-# define ES4H_IS_LINEAR 0x40 /* WO, no memory windowing */
-# define ES4H_IS_AS15 0x80 /* RW, address select bit 15 */
-
-#define ES4H_AS_23_16 0x08 /* Address select bits 23-16 */
-#define ES4H_AS_31_24 0x09 /* Address select bits 31-24 */
-
-#define ES4H_IO_MAX 0x09 /* Size of I/O space */
-
-/*
- * PCI
- */
-#define SE6_RESET PLX_USEROUT
-
-/************************************************************************/
-/* */
-/* 3051 Memory Map */
-/* */
-/* Note: 3051 has 4K I-cache, 2K D-cache. 1 cycle is 50 nsec. */
-/* */
-/************************************************************************/
-#define SE4_NPORTS 4 /* # of ethernet ports */
-#define SE6_NPORTS 6 /* # of ethernet ports */
-#define SE_NPORTS 6 /* Max # of ethernet ports */
-
-#define ES4H_RAM_BASE 0x83000000 /* Base address of RAM */
-#define ES4H_RAM_SIZE 0x00200000 /* Size of RAM (2MB) */
-#define ES4H_RAM_INTBASE 0x83800000 /* Base of int-on-write RAM */
- /* a.k.a. PKT RAM */
-
- /* Ethernet controllers */
- /* See: i82596.h */
-#define ES4H_ETHER0_PORT 0xA2000000
-#define ES4H_ETHER0_CMD 0xA2000100
-#define ES4H_ETHER1_PORT 0xA2000200
-#define ES4H_ETHER1_CMD 0xA2000300
-#define ES4H_ETHER2_PORT 0xA2000400
-#define ES4H_ETHER2_CMD 0xA2000500
-#define ES4H_ETHER3_PORT 0xA2000600
-#define ES4H_ETHER3_CMD 0xA2000700
-#define ES4H_ETHER4_PORT 0xA2000800 /* RS SE-6 only */
-#define ES4H_ETHER4_CMD 0xA2000900 /* RS SE-6 only */
-#define ES4H_ETHER5_PORT 0xA2000A00 /* RS SE-6 only */
-#define ES4H_ETHER5_CMD 0xA2000B00 /* RS SE-6 only */
-
-#define ES4H_I8254 0xA2040000 /* 82C54 timers */
- /* See: i8254.h */
-
-#define SE4_I8254_HZ (23000000/4) /* EISA clock input freq. */
-#define SE4_IDT_HZ (46000000) /* EISA CPU freq. */
-#define SE6_I8254_HZ (20000000/4) /* PCI clock input freq. */
-#define SE6_IDT_HZ (50000000) /* PCI CPU freq. */
-#define ES4H_I8254_HZ (23000000/4) /* EISA clock input freq. */
-
-#define ES4H_GPP 0xA2050000 /* General purpose port */
- /*
- * SE-4 (EISA) GPP bits
- */
-# define ES4H_GPP_C0_100 0x0001 /* WO, Chan 0: 100 ohm TP */
-# define ES4H_GPP_C0_SQE 0x0002 /* WO, Chan 0: normal squelch */
-# define ES4H_GPP_C1_100 0x0004 /* WO, Chan 1: 100 ohm TP */
-# define ES4H_GPP_C1_SQE 0x0008 /* WO, Chan 1: normal squelch */
-# define ES4H_GPP_C2_100 0x0010 /* WO, Chan 2: 100 ohm TP */
-# define ES4H_GPP_C2_SQE 0x0020 /* WO, Chan 2: normal squelch */
-# define ES4H_GPP_C3_100 0x0040 /* WO, Chan 3: 100 ohm TP */
-# define ES4H_GPP_C3_SQE 0x0080 /* WO, Chan 3: normal squelch */
-# define ES4H_GPP_SQE 0x00AA /* WO, All: normal squelch */
-# define ES4H_GPP_100 0x0055 /* WO, All: 100 ohm TP */
-# define ES4H_GPP_HOSTINT 0x0100 /* RO, cause intr. to host */
- /* Hold high > 250 nsec */
-# define SE4_GPP_EED 0x0200 /* RW, EEPROM data bit */
-# define SE4_GPP_EECS 0x0400 /* RW, EEPROM chip select */
-# define SE4_GPP_EECK 0x0800 /* RW, EEPROM clock */
-
- /*
- * SE-6 (PCI) GPP bits
- */
-# define SE6_GPP_EED 0x0001 /* RW, EEPROM data bit */
-# define SE6_GPP_EECS 0x0002 /* RW, EEPROM chip select */
-# define SE6_GPP_EECK 0x0004 /* RW, EEPROM clock */
-# define SE6_GPP_LINK 0x00fc /* R, Link status LEDs */
-
-#define ES4H_INTVEC 0xA2060000 /* RO: Interrupt Vector */
-# define ES4H_IV_DMA0 0x01 /* Chan 0 DMA interrupt */
-# define ES4H_IV_PKT0 0x02 /* Chan 0 PKT interrupt */
-# define ES4H_IV_DMA1 0x04 /* Chan 1 DMA interrupt */
-# define ES4H_IV_PKT1 0x08 /* Chan 1 PKT interrupt */
-# define ES4H_IV_DMA2 0x10 /* Chan 2 DMA interrupt */
-# define ES4H_IV_PKT2 0x20 /* Chan 2 PKT interrupt */
-# define ES4H_IV_DMA3 0x40 /* Chan 3 DMA interrupt */
-# define ES4H_IV_PKT3 0x80 /* Chan 3 PKT interrupt */
-
-#define ES4H_INTACK 0xA2060000 /* WO: Interrupt Ack */
-# define ES4H_INTACK_8254 0x01 /* Real Time Clock (int 0) */
-# define ES4H_INTACK_HOST 0x02 /* Host (int 1) */
-# define ES4H_INTACK_PKT0 0x04 /* Chan 0 Pkt (int 2) */
-# define ES4H_INTACK_PKT1 0x08 /* Chan 1 Pkt (int 3) */
-# define ES4H_INTACK_PKT2 0x10 /* Chan 2 Pkt (int 4) */
-# define ES4H_INTACK_PKT3 0x20 /* Chan 3 Pkt (int 5) */
-
-#define SE6_PLX 0xA2070000 /* PLX 9060, SE-6 (PCI) only */
- /* see plx9060.h */
-
-#define SE6_PCI_VENDOR_ID 0x114F /* Digi PCI vendor ID */
-#define SE6_PCI_DEVICE_ID 0x0003 /* RS SE-6 device ID */
-#define SE6_PCI_ID ((SE6_PCI_DEVICE_ID<<16) | SE6_PCI_VENDOR_ID)
-
-/*
- * IDT Interrupts
- */
-#define ES4H_INT_8254 IDT_INT0
-#define ES4H_INT_HOST IDT_INT1
-#define ES4H_INT_ETHER0 IDT_INT2
-#define ES4H_INT_ETHER1 IDT_INT3
-#define ES4H_INT_ETHER2 IDT_INT4
-#define ES4H_INT_ETHER3 IDT_INT5
-
-/*
- * Because there are differences between the SE-4 and the SE-6,
- * we assume that the following globals will be set up at init
- * time in main.c to containt the appropriate constants from above
- */
-extern ushort Gpp; /* Softcopy of GPP register */
-extern ushort EEck; /* Clock bit */
-extern ushort EEcs; /* CS bit */
-extern ushort EEd; /* Data bit */
-extern ulong I8254_Hz; /* i8254 input frequency */
-extern ulong IDT_Hz; /* IDT CPU frequency */
-extern int Nports; /* Number of ethernet controllers */
-extern int Nchan; /* Nports+1 */
diff --git a/drivers/net/dgrs_ether.h b/drivers/net/dgrs_ether.h
deleted file mode 100644
index 7539b596bff..00000000000
--- a/drivers/net/dgrs_ether.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * A filtering function. There are two filters/port. Filter "0"
- * is the input filter, and filter "1" is the output filter.
- */
-typedef int (FILTER_FUNC)(uchar *pktp, int pktlen, ulong *scratch, int port);
-#define NFILTERS 2
-
-/*
- * The per port structure
- */
-typedef struct
-{
- int chan; /* Channel number (0-3) */
- ulong portaddr; /* address of 596 port register */
- volatile ulong *ca; /* address of 596 chan attention */
- ulong intmask; /* Interrupt mask for this port */
- ulong intack; /* Ack bit for this port */
-
- uchar ethaddr[6]; /* Ethernet address of this port */
- int is_promisc; /* Port is promiscuous */
-
- int debug; /* Debugging turned on */
-
- I596_ISCP *iscpp; /* Uncached ISCP pointer */
- I596_SCP *scpp; /* Uncached SCP pointer */
- I596_SCB *scbp; /* Uncached SCB pointer */
-
- I596_ISCP iscp;
- I596_SCB scb;
-
- /* Command Queue */
- I596_CB *cb0;
- I596_CB *cbN;
- I596_CB *cb_head;
- I596_CB *cb_tail;
-
- /* Receive Queue */
- I596_RFD *rfd0;
- I596_RFD *rfdN;
- I596_RFD *rfd_head;
- I596_RFD *rfd_tail;
-
- /* Receive Buffers */
- I596_RBD *rbd0;
- I596_RBD *rbdN;
- I596_RBD *rbd_head;
- I596_RBD *rbd_tail;
- int buf_size; /* Size of an RBD buffer */
- int buf_cnt; /* Total RBD's allocated */
-
- /* Rx Statistics */
- ulong cnt_rx_cnt; /* Total packets rcvd, good and bad */
- ulong cnt_rx_good; /* Total good packets rcvd */
- ulong cnt_rx_bad; /* Total of all bad packets rcvd */
- /* Subtotals can be gotten from SCB */
- ulong cnt_rx_nores; /* No resources */
- ulong cnt_rx_bytes; /* Total bytes rcvd */
-
- /* Tx Statistics */
- ulong cnt_tx_queued;
- ulong cnt_tx_done;
- ulong cnt_tx_freed;
- ulong cnt_tx_nores; /* No resources */
-
- ulong cnt_tx_bad;
- ulong cnt_tx_err_late;
- ulong cnt_tx_err_nocrs;
- ulong cnt_tx_err_nocts;
- ulong cnt_tx_err_under;
- ulong cnt_tx_err_maxcol;
- ulong cnt_tx_collisions;
-
- /* Special stuff for host */
-# define rfd_freed cnt_rx_cnt
- ulong rbd_freed;
- int host_timer;
-
- /* Added after first beta */
- ulong cnt_tx_races; /* Counts race conditions */
- int spanstate;
- ulong cnt_st_tx; /* send span tree pkts */
- ulong cnt_st_fail_tx; /* Failures to send span tree pkts */
- ulong cnt_st_fail_rbd;/* Failures to send span tree pkts */
- ulong cnt_st_rx; /* rcv span tree pkts */
- ulong cnt_st_rx_bad; /* bogus st packets rcvd */
- ulong cnt_rx_fwd; /* Rcvd packets that were forwarded */
-
- ulong cnt_rx_mcast; /* Multicast pkts received */
- ulong cnt_tx_mcast; /* Multicast pkts transmitted */
- ulong cnt_tx_bytes; /* Bytes transmitted */
-
- /*
- * Packet filtering
- * Filter 0: input filter
- * Filter 1: output filter
- */
-
- ulong *filter_space[NFILTERS];
- FILTER_FUNC *filter_func[NFILTERS];
- ulong filter_cnt[NFILTERS];
- ulong filter_len[NFILTERS];
-
- ulong pad[ (512-300) / 4];
-} PORT;
-
-/*
- * Port[0] is host interface
- * Port[1..SE_NPORTS] are external 10 Base T ports. Fewer may be in
- * use, depending on whether this is an SE-4 or
- * an SE-6.
- * Port[SE_NPORTS] Pseudo-port for Spanning tree and SNMP
- */
-extern PORT Port[1+SE_NPORTS+1];
-
-extern int Nports; /* Number of genuine ethernet controllers */
-extern int Nchan; /* ... plus one for host interface */
-
-extern int FirstChan; /* 0 or 1, depedning on whether host is used */
-extern int NumChan; /* 4 or 5 */
-
-/*
- * A few globals
- */
-extern int IsPromisc;
-extern int MultiNicMode;
-
-/*
- * Functions
- */
-extern void eth_xmit_spew_on(PORT *p, int cnt);
-extern void eth_xmit_spew_off(PORT *p);
-
-extern I596_RBD *alloc_rbds(PORT *p, int num);
-
-extern I596_CB * eth_cb_alloc(PORT *p);
diff --git a/drivers/net/dgrs_firmware.c b/drivers/net/dgrs_firmware.c
deleted file mode 100644
index 8c20d4c9993..00000000000
--- a/drivers/net/dgrs_firmware.c
+++ /dev/null
@@ -1,9966 +0,0 @@
-static const int dgrs_firmnum = 550;
-static char dgrs_firmver[] = "$Version$";
-static char dgrs_firmdate[] = "11/16/96 03:45:15";
-static unsigned char dgrs_code[] __initdata = {
- 213,5,192,8,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,64,40,35,41,
- 101,115,52,104,46,98,105,110,32,32,32,32,
- 32,32,49,46,48,32,48,48,47,48,48,47,
- 57,52,0,64,40,35,41,67,111,112,121,114,
- 105,103,104,116,32,49,57,57,53,44,32,68,
- 105,103,105,32,73,110,116,101,114,110,97,116,
- 105,111,110,97,108,46,32,32,65,108,108,32,
- 82,105,103,104,116,115,32,82,101,115,101,114,
- 118,101,100,46,0,0,0,0,97,5,192,8,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,255,255,0,16,0,0,0,0,
- 0,0,0,0,8,0,224,3,0,0,0,0,
- 148,255,189,39,16,0,161,175,20,0,162,175,
- 24,0,163,175,28,0,164,175,32,0,165,175,
- 36,0,166,175,40,0,167,175,44,0,168,175,
- 48,0,169,175,52,0,170,175,56,0,171,175,
- 60,0,172,175,64,0,173,175,68,0,174,175,
- 72,0,175,175,76,0,184,175,80,0,185,175,
- 88,0,190,175,92,0,191,175,0,112,8,64,
- 18,72,0,0,16,80,0,0,0,96,11,64,
- 84,0,168,175,96,0,169,175,100,0,170,175,
- 104,0,171,175,33,56,0,1,0,131,24,60,
- 0,1,24,39,0,0,8,143,0,0,0,0,
- 1,0,8,33,0,0,8,175,0,104,5,64,
- 0,96,6,64,124,0,168,48,212,255,0,21,
- 0,0,0,0,36,64,166,0,0,255,8,49,
- 27,0,0,17,0,0,0,0,130,65,8,0,
- 2,131,9,60,33,72,40,1,0,220,41,141,
- 66,64,8,0,2,131,10,60,33,80,72,1,
- 0,224,74,141,0,0,0,0,38,80,70,1,
- 1,255,74,49,33,40,192,0,38,48,202,0,
- 0,96,134,64,66,64,8,0,2,131,4,60,
- 33,32,136,0,0,226,132,144,9,248,32,1,
- 0,0,0,0,104,0,166,143,0,0,0,0,
- 0,96,134,64,0,104,5,64,227,255,0,16,
- 0,0,0,0,104,0,168,143,96,0,169,143,
- 100,0,170,143,0,0,0,0,0,96,136,64,
- 19,0,32,1,17,0,64,1,20,0,162,143,
- 24,0,163,143,28,0,164,143,32,0,165,143,
- 36,0,166,143,40,0,167,143,44,0,168,143,
- 48,0,169,143,52,0,170,143,56,0,171,143,
- 60,0,172,143,64,0,173,143,68,0,174,143,
- 72,0,175,143,76,0,184,143,80,0,185,143,
- 88,0,190,143,92,0,191,143,0,0,0,0,
- 84,0,186,143,16,0,161,143,108,0,189,39,
- 8,0,64,3,16,0,0,66,0,96,26,64,
- 0,0,0,0,255,255,27,60,254,0,123,55,
- 0,0,0,0,36,208,91,3,0,0,0,0,
- 0,96,154,64,0,0,0,0,0,112,26,64,
- 0,0,0,0,16,0,0,66,0,0,0,0,
- 8,0,64,3,0,0,0,0,255,255,8,36,
- 133,255,0,17,0,0,0,0,1,0,8,37,
- 130,255,0,21,0,0,0,0,255,255,8,36,
- 33,8,0,1,126,255,40,20,0,0,0,0,
- 1,0,33,36,123,255,32,20,0,0,0,0,
- 255,255,2,36,120,255,72,20,0,0,0,0,
- 1,0,66,36,117,255,64,20,0,0,0,0,
- 255,255,3,36,114,255,104,20,0,0,0,0,
- 1,0,99,36,111,255,96,20,0,0,0,0,
- 255,255,4,36,108,255,136,20,0,0,0,0,
- 1,0,132,36,105,255,128,20,0,0,0,0,
- 255,255,5,36,102,255,168,20,0,0,0,0,
- 1,0,165,36,99,255,160,20,0,0,0,0,
- 255,255,6,36,96,255,200,20,0,0,0,0,
- 1,0,198,36,93,255,192,20,0,0,0,0,
- 255,255,7,36,90,255,232,20,0,0,0,0,
- 1,0,231,36,87,255,224,20,0,0,0,0,
- 255,255,9,36,84,255,40,21,0,0,0,0,
- 1,0,41,37,81,255,32,21,0,0,0,0,
- 255,255,10,36,78,255,72,21,0,0,0,0,
- 1,0,74,37,75,255,64,21,0,0,0,0,
- 255,255,11,36,72,255,104,21,0,0,0,0,
- 1,0,107,37,69,255,96,21,0,0,0,0,
- 255,255,12,36,66,255,136,21,0,0,0,0,
- 1,0,140,37,63,255,128,21,0,0,0,0,
- 255,255,13,36,60,255,168,21,0,0,0,0,
- 1,0,173,37,57,255,160,21,0,0,0,0,
- 255,255,14,36,54,255,200,21,0,0,0,0,
- 1,0,206,37,51,255,192,21,0,0,0,0,
- 255,255,15,36,48,255,232,21,0,0,0,0,
- 1,0,239,37,45,255,224,21,0,0,0,0,
- 255,255,24,36,42,255,8,23,0,0,0,0,
- 1,0,24,39,39,255,0,23,0,0,0,0,
- 255,255,16,36,36,255,8,22,0,0,0,0,
- 1,0,16,38,33,255,0,22,0,0,0,0,
- 255,255,17,36,30,255,40,22,0,0,0,0,
- 1,0,49,38,27,255,32,22,0,0,0,0,
- 255,255,18,36,24,255,72,22,0,0,0,0,
- 1,0,82,38,21,255,64,22,0,0,0,0,
- 255,255,19,36,18,255,104,22,0,0,0,0,
- 1,0,115,38,15,255,96,22,0,0,0,0,
- 255,255,20,36,12,255,136,22,0,0,0,0,
- 1,0,148,38,9,255,128,22,0,0,0,0,
- 255,255,21,36,6,255,168,22,0,0,0,0,
- 1,0,181,38,3,255,160,22,0,0,0,0,
- 255,255,22,36,0,255,200,22,0,0,0,0,
- 1,0,214,38,253,254,192,22,0,0,0,0,
- 255,255,23,36,250,254,232,22,0,0,0,0,
- 1,0,247,38,247,254,224,22,0,0,0,0,
- 255,255,26,36,244,254,72,23,0,0,0,0,
- 1,0,90,39,241,254,64,23,0,0,0,0,
- 255,255,27,36,238,254,104,23,0,0,0,0,
- 1,0,123,39,235,254,96,23,0,0,0,0,
- 255,255,28,36,232,254,136,23,0,0,0,0,
- 1,0,156,39,229,254,128,23,0,0,0,0,
- 255,255,29,36,226,254,168,23,0,0,0,0,
- 1,0,189,39,223,254,160,23,0,0,0,0,
- 255,255,30,36,220,254,200,23,0,0,0,0,
- 1,0,222,39,217,254,192,23,0,0,0,0,
- 255,255,31,36,214,254,232,23,0,0,0,0,
- 1,0,255,39,211,254,224,23,0,0,0,0,
- 0,131,24,60,0,1,24,39,0,32,1,60,
- 37,192,1,3,0,96,8,64,0,0,0,0,
- 1,0,1,60,37,64,1,1,0,96,136,64,
- 33,16,0,0,165,165,3,60,165,165,99,52,
- 0,128,1,60,0,0,35,172,0,128,9,60,
- 0,0,41,141,0,0,0,0,0,96,10,64,
- 0,0,0,0,8,0,1,60,36,80,65,1,
- 29,0,64,21,0,0,0,0,27,0,105,20,
- 0,0,0,0,0,1,2,36,0,128,1,60,
- 33,8,34,0,0,0,32,172,64,16,2,0,
- 1,0,1,60,1,0,33,52,43,8,65,0,
- 248,255,32,20,0,0,0,0,255,255,3,36,
- 0,128,1,60,0,0,35,172,0,1,2,36,
- 0,128,3,60,33,24,98,0,0,0,99,140,
- 0,0,0,0,7,0,96,20,0,0,0,0,
- 64,16,2,0,1,0,1,60,1,0,33,52,
- 43,8,65,0,245,255,32,20,0,0,0,0,
- 0,96,128,64,0,0,0,0,84,0,2,175,
- 0,96,8,64,0,0,0,0,3,0,1,60,
- 37,64,1,1,0,96,136,64,33,16,0,0,
- 165,165,3,60,165,165,99,52,0,128,1,60,
- 0,0,35,172,0,128,9,60,0,0,41,141,
- 0,0,0,0,0,96,10,64,0,0,0,0,
- 8,0,1,60,36,80,65,1,29,0,64,21,
- 0,0,0,0,27,0,105,20,0,0,0,0,
- 0,1,2,36,0,128,1,60,33,8,34,0,
- 0,0,32,172,64,16,2,0,1,0,1,60,
- 1,0,33,52,43,8,65,0,248,255,32,20,
- 0,0,0,0,255,255,3,36,0,128,1,60,
- 0,0,35,172,0,1,2,36,0,128,3,60,
- 33,24,98,0,0,0,99,140,0,0,0,0,
- 7,0,96,20,0,0,0,0,64,16,2,0,
- 1,0,1,60,1,0,33,52,43,8,65,0,
- 245,255,32,20,0,0,0,0,0,96,128,64,
- 0,0,0,0,88,0,2,175,88,0,9,143,
- 0,0,0,0,17,0,32,17,0,0,0,0,
- 0,0,0,0,3,0,2,60,0,0,0,0,
- 0,96,130,64,0,128,8,60,37,72,40,1,
- 0,0,0,161,4,0,0,161,8,0,0,161,
- 12,0,0,161,16,0,0,161,20,0,0,161,
- 24,0,0,161,32,0,8,37,247,255,9,21,
- 252,255,0,161,84,0,9,143,0,0,0,0,
- 17,0,32,17,0,0,0,0,0,0,0,0,
- 1,0,2,60,0,0,0,0,0,96,130,64,
- 0,128,8,60,37,72,40,1,0,0,0,161,
- 4,0,0,161,8,0,0,161,12,0,0,161,
- 16,0,0,161,20,0,0,161,24,0,0,161,
- 32,0,8,37,247,255,9,21,252,255,0,161,
- 32,0,8,60,0,96,136,64,0,104,128,64,
- 0,131,2,60,152,28,66,36,255,31,9,60,
- 255,255,41,53,36,16,73,0,0,128,9,60,
- 37,16,73,0,8,0,64,0,0,0,0,0,
- 2,131,8,60,224,210,8,37,252,255,1,36,
- 36,64,1,1,3,131,9,60,124,18,41,37,
- 252,255,1,36,36,72,33,1,0,0,10,36,
- 0,0,10,173,254,255,9,21,4,0,8,37,
- 3,131,8,60,128,18,8,37,252,255,1,36,
- 36,64,1,1,31,131,9,60,252,255,41,53,
- 252,255,1,36,36,72,33,1,237,254,10,60,
- 175,222,74,53,0,0,10,173,254,255,9,21,
- 4,0,8,37,2,131,8,60,0,212,8,37,
- 252,255,1,36,36,64,1,1,2,131,9,60,
- 252,219,41,37,252,255,1,36,36,72,33,1,
- 173,222,10,60,239,190,74,53,0,0,10,173,
- 254,255,9,21,4,0,8,37,0,4,8,60,
- 0,0,0,0,0,24,136,64,0,0,0,0,
- 2,131,29,60,0,220,189,39,0,0,30,36,
- 2,131,28,60,51,8,192,12,16,78,156,39,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 232,255,189,39,16,0,191,175,8,128,132,39,
- 15,63,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,16,0,191,175,12,128,132,39,
- 15,63,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,16,0,191,175,16,128,132,39,
- 15,63,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,16,0,191,175,20,128,132,39,
- 15,63,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,24,133,131,143,6,0,2,36,
- 20,0,191,175,6,0,98,20,16,0,176,175,
- 7,162,3,60,228,0,99,52,1,0,2,36,
- 184,7,192,8,0,0,98,172,0,128,130,151,
- 5,162,16,60,0,1,66,52,120,63,192,12,
- 0,0,2,166,0,128,130,151,0,0,0,0,
- 255,254,66,48,0,0,2,166,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 232,255,189,39,33,16,128,0,3,0,64,4,
- 16,0,191,175,254,255,2,60,192,29,66,52,
- 0,163,4,60,96,1,132,52,0,163,1,60,
- 92,1,34,172,0,163,1,60,104,1,38,172,
- 204,63,192,12,8,0,6,36,228,63,192,12,
- 255,255,4,36,204,7,192,8,0,0,0,0,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,216,255,189,39,1,0,6,36,
- 3,131,2,60,143,18,66,36,240,255,3,36,
- 36,16,67,0,0,163,1,60,120,1,34,172,
- 0,163,2,60,120,1,66,140,33,56,0,0,
- 32,0,191,175,28,0,177,175,24,0,176,175,
- 16,0,160,175,0,163,1,60,116,1,34,172,
- 0,163,3,60,112,1,99,140,0,163,2,60,
- 116,1,66,140,0,163,4,60,116,1,132,140,
- 35,136,98,0,84,64,192,12,33,40,32,2,
- 13,0,64,16,0,0,0,0,1,131,4,60,
- 96,127,132,36,24,128,144,39,33,40,0,2,
- 1,131,7,60,128,127,231,36,15,63,192,12,
- 148,0,6,36,1,0,4,36,33,40,0,2,
- 188,7,192,12,148,0,6,36,2,0,33,6,
- 33,16,32,2,3,0,34,38,131,136,2,0,
- 0,163,2,60,116,1,66,140,0,0,0,0,
- 6,0,32,18,237,254,3,60,175,222,99,52,
- 0,0,67,172,255,255,49,38,253,255,32,22,
- 4,0,66,36,32,0,191,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,40,0,189,39,
- 224,255,189,39,15,0,132,36,240,255,3,36,
- 20,0,177,175,0,163,17,60,120,1,49,142,
- 0,163,2,60,120,1,66,140,36,32,131,0,
- 33,16,68,0,0,163,1,60,120,1,34,172,
- 0,163,3,60,120,1,99,140,0,163,2,60,
- 112,1,66,140,24,0,191,175,43,16,67,0,
- 13,0,64,16,16,0,176,175,1,131,4,60,
- 96,127,132,36,24,128,144,39,33,40,0,2,
- 1,131,7,60,176,127,231,36,15,63,192,12,
- 171,0,6,36,1,0,4,36,33,40,0,2,
- 188,7,192,12,171,0,6,36,33,16,32,2,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,216,255,189,39,
- 3,0,2,60,7,162,3,60,36,0,191,175,
- 32,0,176,175,0,163,1,60,92,1,32,172,
- 0,0,99,140,79,17,66,52,32,0,98,20,
- 87,0,4,60,76,0,8,60,64,75,8,53,
- 250,2,7,60,128,240,231,52,7,162,6,60,
- 152,0,198,52,67,73,3,60,67,3,99,52,
- 7,162,4,60,48,1,132,52,7,162,5,60,
- 0,1,165,52,6,0,2,36,24,133,130,175,
- 0,163,1,60,204,5,34,172,4,0,2,36,
- 50,133,130,167,2,0,2,36,48,133,130,167,
- 1,0,2,36,20,133,130,167,119,119,2,36,
- 28,133,136,175,16,133,135,175,0,0,195,172,
- 0,0,130,172,67,1,2,36,0,0,162,172,
- 109,8,192,8,31,131,4,60,240,188,132,52,
- 189,2,3,60,128,231,99,52,4,0,2,36,
- 24,133,130,175,0,163,1,60,204,5,34,172,
- 0,8,2,36,50,133,130,167,0,4,2,36,
- 48,133,130,167,0,2,2,36,20,133,130,167,
- 28,133,132,175,16,133,131,175,31,131,4,60,
- 0,240,132,52,24,133,131,143,0,131,2,60,
- 0,163,1,60,108,1,34,172,0,163,1,60,
- 112,1,36,172,1,0,99,36,32,133,131,175,
- 210,7,192,12,0,0,0,0,0,163,2,60,
- 132,1,66,140,0,128,128,167,2,0,64,20,
- 85,0,2,36,0,128,130,167,0,163,2,60,
- 136,1,66,140,0,0,0,0,5,0,64,20,
- 0,0,0,0,0,128,130,151,0,0,0,0,
- 170,0,66,52,0,128,130,167,0,128,131,151,
- 5,162,2,60,0,0,67,164,188,64,192,12,
- 1,0,16,36,2,131,4,60,0,220,132,36,
- 2,131,5,60,0,224,165,36,2,131,6,60,
- 0,226,198,36,8,0,7,36,2,131,2,60,
- 112,154,66,36,16,0,162,175,2,131,2,60,
- 144,154,66,36,20,0,162,175,2,131,2,60,
- 176,154,66,36,24,0,162,175,0,131,2,60,
- 36,30,66,36,0,163,1,60,92,1,48,172,
- 240,64,192,12,28,0,162,175,0,163,3,60,
- 124,1,99,140,40,133,128,175,2,0,98,40,
- 7,0,64,16,2,0,2,36,18,0,97,4,
- 255,255,2,36,7,0,98,16,0,0,0,0,
- 196,8,192,8,0,0,0,0,16,0,98,16,
- 0,0,0,0,196,8,192,8,0,0,0,0,
- 24,133,133,143,1,131,4,60,15,63,192,12,
- 208,127,132,36,0,163,1,60,112,25,192,12,
- 124,1,32,172,207,8,192,8,0,0,0,0,
- 211,8,192,12,0,0,0,0,207,8,192,8,
- 0,0,0,0,40,133,144,175,31,10,192,12,
- 0,0,0,0,207,8,192,8,0,0,0,0,
- 1,131,4,60,96,127,132,36,24,128,144,39,
- 33,40,0,2,32,128,135,39,15,63,192,12,
- 58,1,6,36,1,0,4,36,33,40,0,2,
- 188,7,192,12,58,1,6,36,36,0,191,143,
- 32,0,176,143,8,0,224,3,40,0,189,39,
- 192,255,189,39,56,0,191,175,52,0,181,175,
- 48,0,180,175,44,0,179,175,40,0,178,175,
- 36,0,177,175,180,10,192,12,32,0,176,175,
- 33,32,0,0,2,0,2,36,0,163,1,60,
- 244,57,192,12,92,1,34,172,3,0,2,36,
- 0,163,1,60,0,12,192,12,92,1,34,172,
- 1,0,4,36,4,0,2,36,0,163,1,60,
- 34,11,192,12,92,1,34,172,5,0,2,36,
- 0,163,1,60,92,1,34,172,0,163,19,60,
- 124,1,115,142,0,163,3,60,160,1,99,140,
- 1,0,98,46,80,133,130,175,0,128,2,60,
- 5,0,98,20,0,0,0,0,32,133,130,143,
- 0,0,0,0,252,8,192,8,255,255,66,36,
- 32,133,130,143,0,0,0,0,84,133,130,175,
- 130,11,192,12,0,0,0,0,33,32,64,0,
- 2,0,5,36,232,3,6,36,0,131,7,60,
- 196,37,231,36,156,11,192,12,16,0,160,175,
- 35,35,192,12,0,0,0,0,6,0,2,36,
- 0,163,1,60,84,35,192,12,92,1,34,172,
- 7,0,2,36,0,163,1,60,141,47,192,12,
- 92,1,34,172,8,0,2,36,0,163,1,60,
- 120,50,192,12,92,1,34,172,9,0,2,36,
- 0,163,1,60,92,1,34,172,0,163,2,60,
- 240,5,66,140,0,0,0,0,8,0,64,16,
- 10,0,2,36,0,163,4,60,240,5,132,140,
- 13,8,192,12,0,0,0,0,0,163,1,60,
- 244,5,34,172,10,0,2,36,0,163,1,60,
- 92,1,34,172,157,15,192,12,1,0,21,36,
- 2,131,2,60,192,246,66,36,33,160,64,0,
- 80,133,131,143,11,0,2,36,0,163,1,60,
- 92,1,34,172,100,0,2,36,0,163,1,60,
- 92,1,34,172,84,133,130,143,64,26,3,0,
- 33,136,116,0,64,18,2,0,33,144,84,0,
- 0,163,2,60,8,1,66,140,0,0,0,0,
- 1,0,66,36,0,163,1,60,8,1,34,172,
- 0,163,2,60,8,1,66,140,0,163,2,60,
- 124,1,66,140,0,0,0,0,14,0,83,16,
- 0,0,0,0,4,0,64,16,33,152,64,0,
- 80,133,128,175,76,9,192,8,0,0,0,0,
- 80,133,149,175,2,131,4,60,163,23,192,12,
- 192,246,132,36,80,133,130,143,0,0,0,0,
- 64,18,2,0,33,136,84,0,0,163,2,60,
- 0,6,66,140,0,0,0,0,3,0,64,24,
- 33,128,32,2,239,15,192,12,0,0,0,0,
- 43,16,18,2,11,0,64,16,33,32,0,2,
- 151,18,192,12,10,0,5,36,27,22,192,12,
- 33,32,0,2,142,22,192,12,33,32,0,2,
- 0,2,16,38,43,16,18,2,247,255,64,20,
- 33,32,0,2,184,11,192,12,0,0,0,0,
- 54,9,192,8,0,0,0,0,56,0,191,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,64,0,189,39,4,128,130,143,
- 232,255,189,39,20,0,191,175,16,0,176,175,
- 1,0,67,36,4,128,131,175,255,255,3,36,
- 4,0,67,20,255,31,4,60,0,163,1,60,
- 8,1,32,172,255,31,4,60,255,255,132,52,
- 0,163,16,60,0,163,2,60,8,1,66,140,
- 208,132,131,143,220,5,16,54,35,16,67,0,
- 0,163,1,60,16,1,34,172,2,131,2,60,
- 192,246,66,36,36,16,68,0,0,160,3,60,
- 37,16,67,0,0,163,3,60,8,1,99,140,
- 28,0,68,140,0,0,5,142,3,131,2,60,
- 20,18,66,140,208,132,131,175,36,133,132,175,
- 18,0,162,16,0,163,4,60,99,59,192,12,
- 220,5,132,52,255,0,5,60,255,0,165,52,
- 0,255,6,60,0,0,4,142,0,255,198,52,
- 0,20,4,0,2,28,4,0,37,16,67,0,
- 2,26,2,0,36,24,101,0,0,18,2,0,
- 36,16,70,0,37,24,98,0,176,133,132,175,
- 184,133,131,175,0,163,16,60,16,6,16,54,
- 0,0,3,142,3,131,2,60,68,18,66,140,
- 0,0,0,0,18,0,98,16,0,163,4,60,
- 119,59,192,12,16,6,132,52,255,0,5,60,
- 255,0,165,52,0,255,6,60,0,0,4,142,
- 0,255,198,52,0,20,4,0,2,28,4,0,
- 37,16,67,0,2,26,2,0,36,24,101,0,
- 0,18,2,0,36,16,70,0,37,24,98,0,
- 196,133,132,175,192,133,131,175,0,163,16,60,
- 224,5,16,54,0,0,3,142,3,131,2,60,
- 24,18,66,140,0,0,0,0,18,0,98,16,
- 0,163,4,60,139,59,192,12,224,5,132,52,
- 255,0,5,60,255,0,165,52,0,255,6,60,
- 0,0,4,142,0,255,198,52,0,20,4,0,
- 2,28,4,0,37,16,67,0,2,26,2,0,
- 36,24,101,0,0,18,2,0,36,16,70,0,
- 37,24,98,0,188,133,132,175,180,133,131,175,
- 44,133,131,143,0,163,2,60,144,1,66,140,
- 0,0,0,0,5,0,98,16,0,0,0,0,
- 0,163,4,60,144,1,132,140,159,59,192,12,
- 0,0,0,0,0,163,3,60,140,1,99,140,
- 3,131,2,60,64,18,66,140,0,0,0,0,
- 5,0,98,16,0,0,0,0,0,163,4,60,
- 140,1,132,140,51,60,192,12,0,0,0,0,
- 44,133,130,143,0,0,0,0,3,0,64,16,
- 0,0,0,0,116,38,192,12,0,0,0,0,
- 164,7,192,12,0,0,0,0,36,128,130,143,
- 0,0,0,0,1,0,66,36,36,128,130,175,
- 60,0,66,40,8,0,64,20,0,0,0,0,
- 3,131,2,60,24,18,66,140,36,128,128,175,
- 3,0,64,16,0,0,0,0,222,48,192,12,
- 0,0,0,0,0,163,2,60,48,1,66,140,
- 0,0,0,0,20,0,64,16,0,0,0,0,
- 0,163,1,60,48,1,32,172,0,163,1,60,
- 16,1,32,172,0,163,1,60,20,1,32,172,
- 0,163,1,60,24,1,32,172,0,163,1,60,
- 28,1,32,172,0,163,1,60,32,1,32,172,
- 0,163,1,60,36,1,32,172,0,163,1,60,
- 40,1,32,172,0,163,1,60,201,13,192,12,
- 44,1,32,172,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,216,255,189,39,
- 36,0,191,175,32,0,178,175,28,0,177,175,
- 180,10,192,12,24,0,176,175,33,32,0,0,
- 2,0,2,36,0,163,1,60,244,57,192,12,
- 92,1,34,172,3,0,2,36,0,163,1,60,
- 0,12,192,12,92,1,34,172,1,0,4,36,
- 4,0,2,36,0,163,1,60,34,11,192,12,
- 92,1,34,172,32,133,131,143,5,0,2,36,
- 0,163,1,60,92,1,34,172,80,133,128,175,
- 84,133,131,175,130,11,192,12,0,0,0,0,
- 33,32,64,0,2,0,5,36,232,3,6,36,
- 0,131,7,60,196,37,231,36,156,11,192,12,
- 16,0,160,175,0,163,2,60,240,5,66,140,
- 0,0,0,0,8,0,64,16,10,0,2,36,
- 0,163,4,60,240,5,132,140,13,8,192,12,
- 0,0,0,0,0,163,1,60,244,5,34,172,
- 10,0,2,36,0,163,1,60,92,1,34,172,
- 100,0,2,36,80,133,131,143,2,131,4,60,
- 192,246,132,36,0,163,1,60,92,1,34,172,
- 84,133,130,143,64,26,3,0,33,144,100,0,
- 64,18,2,0,33,136,68,0,0,163,2,60,
- 8,1,66,140,33,128,64,2,1,0,66,36,
- 0,163,1,60,8,1,34,172,0,163,2,60,
- 8,1,66,140,43,16,17,2,11,0,64,16,
- 33,32,0,2,151,18,192,12,10,0,5,36,
- 27,22,192,12,33,32,0,2,142,22,192,12,
- 33,32,0,2,0,2,16,38,43,16,17,2,
- 247,255,64,20,33,32,0,2,184,11,192,12,
- 0,0,0,0,91,10,192,8,0,0,0,0,
- 36,0,191,143,32,0,178,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,40,0,189,39,
- 4,128,130,143,232,255,189,39,16,0,191,175,
- 1,0,67,36,4,128,131,175,255,255,3,36,
- 4,0,67,20,255,31,4,60,0,163,1,60,
- 8,1,32,172,255,31,4,60,0,163,2,60,
- 8,1,66,140,212,132,131,143,255,255,132,52,
- 35,16,67,0,0,163,1,60,16,1,34,172,
- 2,131,2,60,192,246,66,36,36,16,68,0,
- 0,160,3,60,37,16,67,0,0,163,3,60,
- 8,1,99,140,28,0,66,140,212,132,131,175,
- 36,133,130,175,164,7,192,12,0,0,0,0,
- 0,163,2,60,48,1,66,140,0,0,0,0,
- 20,0,64,16,0,0,0,0,0,163,1,60,
- 48,1,32,172,0,163,1,60,16,1,32,172,
- 0,163,1,60,20,1,32,172,0,163,1,60,
- 24,1,32,172,0,163,1,60,28,1,32,172,
- 0,163,1,60,32,1,32,172,0,163,1,60,
- 36,1,32,172,0,163,1,60,40,1,32,172,
- 0,163,1,60,201,13,192,12,44,1,32,172,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,224,255,189,39,24,0,191,175,
- 20,0,177,175,120,63,192,12,16,0,176,175,
- 52,0,2,36,4,162,1,60,12,0,34,160,
- 120,63,192,12,232,3,16,36,28,133,130,143,
- 0,0,0,0,27,0,80,0,2,0,0,22,
- 0,0,0,0,13,0,7,0,18,16,0,0,
- 4,162,17,60,120,63,192,12,0,0,34,162,
- 28,133,130,143,0,0,0,0,27,0,80,0,
- 2,0,0,22,0,0,0,0,13,0,7,0,
- 18,16,0,0,33,40,0,0,33,32,0,0,
- 6,162,3,60,2,18,2,0,0,0,34,162,
- 1,0,2,36,0,163,1,60,4,1,32,172,
- 0,0,98,172,2,131,1,60,33,8,36,0,
- 8,245,32,172,1,0,165,36,22,0,162,44,
- 250,255,64,20,20,0,132,36,31,131,4,60,
- 0,240,132,52,52,128,131,143,1,0,2,36,
- 68,133,128,175,48,128,130,175,64,133,128,175,
- 32,131,1,60,252,239,36,172,8,0,96,16,
- 31,131,5,60,252,239,165,52,31,131,6,60,
- 1,131,4,60,224,127,132,36,15,63,192,12,
- 0,240,198,52,52,128,128,175,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,16,0,176,175,
- 116,0,2,36,20,0,191,175,4,162,1,60,
- 12,0,34,160,130,63,192,12,33,128,128,0,
- 4,162,1,60,4,0,48,160,130,63,192,12,
- 3,130,16,0,4,162,1,60,130,63,192,12,
- 4,0,48,160,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,224,255,189,39,
- 64,0,2,36,24,0,191,175,20,0,177,175,
- 16,0,176,175,4,162,1,60,130,63,192,12,
- 12,0,34,160,4,162,17,60,4,0,49,146,
- 0,0,0,0,130,63,192,12,255,0,49,50,
- 4,162,16,60,4,0,16,146,0,0,0,0,
- 130,63,192,12,255,0,16,50,0,130,16,0,
- 37,16,17,2,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 48,128,130,143,232,255,189,39,16,0,176,175,
- 33,128,128,0,3,0,64,20,20,0,191,175,
- 180,10,192,12,0,0,0,0,5,0,0,18,
- 0,0,0,0,236,63,192,12,1,4,4,36,
- 50,11,192,8,0,0,0,0,228,63,192,12,
- 0,4,4,36,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,216,255,189,39,
- 6,162,3,60,1,0,2,36,32,0,191,175,
- 28,0,177,175,24,0,176,175,0,0,98,172,
- 0,163,2,60,4,1,66,140,33,136,224,0,
- 1,0,66,36,0,163,1,60,4,1,34,172,
- 56,128,130,143,0,163,3,60,4,1,99,140,
- 1,0,66,36,56,128,130,175,232,3,66,40,
- 21,0,64,20,255,127,3,60,68,133,130,143,
- 254,255,99,52,56,128,128,175,1,0,66,36,
- 43,24,98,0,68,133,130,175,13,0,96,16,
- 0,0,0,0,2,131,4,60,28,128,132,36,
- 60,128,144,39,33,40,0,2,2,131,7,60,
- 60,128,231,36,15,63,192,12,144,0,6,36,
- 1,0,4,36,33,40,0,2,188,7,192,12,
- 144,0,6,36,64,133,134,143,0,0,0,0,
- 14,0,192,24,33,24,0,0,2,131,5,60,
- 0,245,165,36,33,32,0,0,2,131,2,60,
- 33,16,68,0,0,245,66,140,20,0,132,36,
- 1,0,99,36,255,255,66,36,0,0,162,172,
- 42,16,102,0,247,255,64,20,20,0,165,36,
- 31,131,4,60,252,239,132,52,31,131,2,60,
- 0,0,131,140,255,255,66,52,0,0,113,172,
- 4,0,99,36,43,16,67,0,3,0,64,16,
- 0,0,0,0,31,131,3,60,0,240,99,52,
- 0,0,131,172,32,0,191,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,40,0,189,39,
- 64,133,130,143,232,255,189,39,20,0,191,175,
- 22,0,66,40,13,0,64,20,16,0,176,175,
- 2,131,4,60,28,128,132,36,60,128,144,39,
- 33,40,0,2,2,131,7,60,84,128,231,36,
- 15,63,192,12,173,0,6,36,1,0,4,36,
- 33,40,0,2,188,7,192,12,173,0,6,36,
- 64,133,130,143,0,0,0,0,1,0,67,36,
- 64,133,131,175,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,128,16,4,0,
- 33,16,68,0,16,0,163,143,128,16,2,0,
- 2,131,1,60,33,8,34,0,4,245,38,172,
- 2,131,1,60,33,8,34,0,12,245,39,172,
- 2,131,1,60,33,8,34,0,0,245,38,172,
- 2,131,1,60,33,8,34,0,8,245,37,172,
- 2,131,1,60,33,8,34,0,16,245,35,172,
- 8,0,224,3,33,16,0,1,128,16,4,0,
- 33,16,68,0,128,16,2,0,2,131,1,60,
- 33,8,34,0,8,0,224,3,8,245,32,172,
- 64,133,130,143,192,255,189,39,40,0,180,175,
- 33,160,0,0,56,0,191,175,52,0,183,175,
- 48,0,182,175,44,0,181,175,36,0,179,175,
- 32,0,178,175,28,0,177,175,48,0,64,24,
- 24,0,176,175,1,0,23,36,2,0,22,36,
- 2,131,16,60,12,245,16,38,4,0,19,38,
- 244,255,17,38,252,255,18,38,33,168,0,0,
- 0,0,67,142,0,0,0,0,7,0,119,16,
- 2,0,98,40,25,0,64,20,0,0,0,0,
- 9,0,118,16,0,0,0,0,236,11,192,8,
- 20,0,16,38,0,0,34,142,0,0,0,0,
- 17,0,64,28,0,0,0,0,230,11,192,8,
- 0,0,64,174,0,0,34,142,0,0,0,0,
- 11,0,64,28,0,0,0,0,2,131,2,60,
- 33,16,85,0,4,245,66,140,0,0,0,0,
- 0,0,34,174,0,0,100,142,0,0,2,142,
- 0,0,0,0,9,248,64,0,0,0,0,0,
- 20,0,16,38,20,0,115,38,20,0,49,38,
- 20,0,82,38,64,133,130,143,1,0,148,38,
- 42,16,130,2,218,255,64,20,20,0,181,38,
- 56,0,191,143,52,0,183,143,48,0,182,143,
- 44,0,181,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,64,0,189,39,0,0,0,0,
- 2,131,3,60,192,246,99,36,0,2,2,36,
- 0,163,1,60,200,5,35,172,0,163,1,60,
- 208,5,34,172,0,163,2,60,124,1,66,140,
- 216,255,189,39,16,0,176,175,33,128,0,0,
- 28,0,179,175,255,255,19,36,24,0,178,175,
- 21,0,114,36,20,0,177,175,32,0,191,175,
- 1,0,66,44,80,133,130,175,139,14,192,12,
- 20,0,113,36,184,24,192,12,0,0,0,0,
- 27,67,192,12,33,32,0,2,6,0,83,20,
- 1,0,16,38,2,131,4,60,15,63,192,12,
- 112,128,132,36,126,12,192,8,1,0,2,36,
- 0,0,34,162,3,18,2,0,0,0,66,162,
- 2,0,82,38,3,0,2,42,241,255,64,20,
- 2,0,49,38,2,131,17,60,212,246,49,38,
- 33,32,32,2,33,40,0,0,255,127,6,60,
- 247,24,192,12,255,255,198,52,255,31,3,60,
- 255,255,99,52,236,255,48,38,36,0,34,38,
- 36,16,67,0,0,160,3,60,37,16,67,0,
- 0,32,3,36,236,255,32,174,2,131,1,60,
- 220,246,32,172,2,131,1,60,204,246,32,172,
- 2,131,1,60,236,246,34,172,0,0,67,164,
- 222,21,192,12,33,32,0,2,122,15,192,12,
- 33,32,0,2,242,21,192,12,33,32,0,2,
- 32,133,130,143,1,0,16,36,42,16,2,2,
- 12,0,64,16,255,31,3,60,236,1,49,38,
- 133,12,192,12,33,32,0,2,242,21,192,12,
- 33,32,32,2,32,133,130,143,1,0,16,38,
- 42,16,2,2,248,255,64,20,0,2,49,38,
- 255,31,3,60,255,255,99,52,2,131,16,60,
- 192,4,16,38,7,0,2,36,0,0,2,174,
- 56,0,2,38,36,16,67,0,0,160,3,60,
- 37,16,67,0,0,32,3,36,2,131,1,60,
- 220,4,32,172,2,131,1,60,204,4,32,172,
- 2,131,1,60,236,4,34,172,0,0,67,164,
- 2,131,2,60,212,246,66,140,2,131,3,60,
- 216,246,99,132,20,0,2,174,24,0,3,166,
- 2,131,2,60,217,4,66,144,0,0,0,0,
- 7,0,66,36,2,131,1,60,217,4,34,160,
- 112,15,192,12,33,32,0,2,33,32,0,2,
- 19,15,192,12,32,0,5,36,20,0,16,38,
- 33,32,0,2,7,0,5,36,255,127,6,60,
- 247,24,192,12,255,255,198,52,33,16,0,0,
- 32,0,191,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,200,255,189,39,48,0,180,175,
- 33,160,128,0,255,31,6,60,255,255,198,52,
- 64,26,20,0,2,131,2,60,192,246,66,36,
- 40,0,178,175,33,144,98,0,255,255,132,38,
- 64,18,4,0,0,162,3,60,33,16,67,0,
- 52,0,191,175,44,0,179,175,36,0,177,175,
- 32,0,176,175,4,0,66,174,0,1,66,36,
- 8,0,66,174,0,16,2,36,4,16,130,0,
- 12,0,66,174,4,0,2,36,4,16,130,0,
- 0,160,5,60,16,0,66,174,48,0,66,38,
- 36,16,70,0,37,16,69,0,36,0,66,174,
- 64,16,4,0,33,16,68,0,128,16,2,0,
- 2,131,3,60,240,231,99,36,33,16,67,0,
- 36,16,70,0,37,16,69,0,40,0,66,174,
- 56,0,66,38,36,16,70,0,37,16,69,0,
- 0,0,84,174,44,0,66,174,32,0,64,174,
- 2,131,2,60,212,246,66,140,2,131,3,60,
- 216,246,99,132,20,0,66,174,24,0,67,166,
- 25,0,66,146,0,0,0,0,33,32,84,0,
- 2,131,2,60,0,227,66,36,36,16,70,0,
- 37,128,69,0,2,131,2,60,32,227,66,36,
- 36,16,70,0,25,0,68,162,40,133,131,143,
- 0,0,0,0,3,0,96,16,37,136,69,0,
- 255,255,130,36,25,0,66,162,12,0,68,142,
- 28,0,64,174,228,63,192,12,1,0,132,52,
- 4,0,68,142,0,0,0,0,76,67,192,12,
- 33,40,0,0,76,63,192,12,0,0,0,0,
- 76,63,192,12,0,0,0,0,255,255,2,36,
- 4,0,2,174,4,0,2,142,0,0,0,0,
- 0,0,2,174,4,0,68,142,0,0,0,0,
- 76,67,192,12,1,0,5,54,4,0,4,38,
- 33,40,0,0,255,255,6,36,211,67,192,12,
- 208,7,7,36,8,0,64,20,255,255,2,52,
- 2,131,4,60,184,128,132,36,4,0,6,142,
- 0,0,0,0,15,63,192,12,33,40,128,2,
- 255,255,2,52,48,1,34,174,4,0,68,142,
- 0,0,0,0,76,67,192,12,3,0,37,54,
- 48,1,36,38,33,40,0,0,255,255,6,52,
- 211,67,192,12,208,7,7,36,7,0,64,20,
- 0,0,0,0,2,131,4,60,8,129,132,36,
- 48,1,38,142,0,0,0,0,15,63,192,12,
- 33,40,128,2,143,63,192,12,0,0,0,0,
- 40,0,69,142,4,0,68,142,0,0,0,0,
- 76,67,192,12,2,0,165,52,44,0,81,142,
- 84,128,131,143,80,128,132,143,100,0,2,36,
- 0,0,32,166,2,0,32,166,4,0,32,174,
- 8,0,32,174,12,0,32,174,16,0,32,174,
- 24,0,32,174,20,0,32,174,28,0,32,174,
- 32,0,32,174,36,0,34,166,38,0,34,166,
- 36,0,35,166,38,0,36,166,36,0,83,142,
- 1,0,2,36,0,0,98,174,44,0,66,142,
- 0,0,0,0,4,0,98,174,40,0,67,142,
- 116,0,2,60,0,0,98,172,40,0,67,142,
- 36,0,66,142,0,0,0,0,8,0,98,172,
- 8,0,66,142,0,0,0,0,0,0,64,172,
- 0,0,98,142,0,0,0,0,10,0,64,16,
- 33,128,0,0,208,7,2,42,7,0,64,16,
- 0,0,0,0,143,63,192,12,0,0,0,0,
- 0,0,98,142,0,0,0,0,248,255,64,20,
- 1,0,16,38,0,0,98,142,0,0,0,0,
- 6,0,64,16,33,32,32,2,2,131,4,60,
- 76,129,132,36,15,63,192,12,33,40,128,2,
- 33,32,32,2,8,0,5,36,0,0,34,150,
- 8,0,6,36,0,240,66,48,0,6,66,52,
- 2,0,34,166,8,0,66,142,208,7,7,36,
- 129,67,192,12,0,0,64,172,6,0,64,20,
- 2,0,36,38,2,131,4,60,160,129,132,36,
- 15,63,192,12,33,40,128,2,2,0,36,38,
- 33,40,0,0,0,0,34,150,33,48,0,0,
- 0,240,66,48,2,0,34,166,8,0,66,142,
- 208,7,7,36,129,67,192,12,0,0,64,172,
- 4,0,64,20,0,0,0,0,2,131,4,60,
- 15,63,192,12,248,129,132,36,143,63,192,12,
- 0,0,0,0,108,0,80,142,0,128,2,52,
- 0,0,0,166,2,0,2,166,44,0,66,142,
- 0,32,5,36,4,0,80,172,44,0,67,142,
- 0,241,2,52,2,0,98,164,8,0,66,142,
- 0,32,6,36,0,0,64,172,44,0,68,142,
- 0,0,0,0,129,67,192,12,208,7,7,36,
- 12,0,64,20,0,0,0,0,44,0,66,142,
- 0,0,0,0,0,0,69,148,2,131,4,60,
- 15,63,192,12,16,130,132,36,254,255,4,36,
- 2,131,5,60,44,130,165,36,188,7,192,12,
- 1,1,6,36,108,0,80,142,2,128,2,52,
- 0,0,0,166,2,0,2,166,14,0,2,36,
- 8,0,2,162,200,0,2,36,9,0,2,162,
- 65,0,2,36,10,0,2,162,46,0,2,36,
- 11,0,2,162,87,0,2,36,12,0,0,162,
- 13,0,2,162,242,0,2,36,14,0,0,162,
- 15,0,2,162,1,0,2,36,16,0,2,162,
- 8,0,2,36,17,0,2,162,88,128,130,143,
- 0,0,0,0,6,0,64,16,64,0,2,36,
- 2,131,4,60,15,63,192,12,56,130,132,36,
- 88,128,128,175,64,0,2,36,18,0,2,162,
- 255,0,2,36,19,0,2,162,63,0,2,36,
- 20,0,0,162,21,0,2,162,44,0,66,142,
- 0,32,5,36,4,0,80,172,44,0,67,142,
- 0,33,2,36,2,0,98,164,8,0,66,142,
- 0,32,6,36,0,0,64,172,44,0,68,142,
- 0,0,0,0,129,67,192,12,208,7,7,36,
- 12,0,64,20,0,0,0,0,44,0,66,142,
- 0,0,0,0,0,0,69,148,2,131,4,60,
- 15,63,192,12,16,130,132,36,253,255,4,36,
- 2,131,5,60,44,130,165,36,188,7,192,12,
- 85,1,6,36,222,21,192,12,33,32,64,2,
- 122,15,192,12,33,32,64,2,52,0,191,143,
- 48,0,180,143,44,0,179,143,40,0,178,143,
- 36,0,177,143,32,0,176,143,8,0,224,3,
- 56,0,189,39,248,255,189,39,32,133,133,143,
- 0,0,0,0,50,0,160,24,33,32,0,0,
- 2,131,3,60,192,246,99,36,44,0,98,140,
- 152,0,96,172,156,0,96,172,160,0,96,172,
- 164,0,96,172,168,0,96,172,172,0,96,172,
- 176,0,96,172,180,0,96,172,184,0,96,172,
- 188,0,96,172,192,0,96,172,196,0,96,172,
- 200,0,96,172,204,0,96,172,208,0,96,172,
- 212,0,96,172,216,0,96,172,224,0,96,172,
- 232,0,96,172,236,0,96,172,240,0,96,172,
- 244,0,96,172,248,0,96,172,252,0,96,172,
- 0,1,96,172,4,1,96,172,8,1,96,172,
- 12,0,64,172,44,0,98,140,0,0,0,0,
- 16,0,64,172,44,0,98,140,0,0,0,0,
- 24,0,64,172,44,0,98,140,0,0,0,0,
- 20,0,64,172,44,0,98,140,1,0,132,36,
- 28,0,64,172,44,0,98,140,0,2,99,36,
- 32,0,64,172,42,16,133,0,210,255,64,20,
- 0,0,0,0,33,32,0,0,0,163,3,60,
- 0,1,99,52,32,0,5,36,33,16,131,0,
- 188,0,69,160,1,0,132,36,0,2,130,44,
- 251,255,64,20,0,0,0,0,8,0,224,3,
- 8,0,189,39,0,0,0,0,124,133,130,143,
- 232,255,189,39,20,0,191,175,17,0,64,20,
- 16,0,176,175,208,7,16,36,7,0,0,26,
- 0,0,0,0,143,63,192,12,255,255,16,38,
- 124,133,130,143,0,0,0,0,249,255,64,16,
- 0,0,0,0,6,0,0,22,0,0,0,0,
- 2,131,4,60,15,63,192,12,80,130,132,36,
- 45,14,192,8,33,16,0,0,220,63,192,12,
- 33,32,0,0,33,32,64,0,124,133,144,143,
- 128,133,130,143,4,0,3,142,255,255,66,36,
- 128,133,130,175,124,133,131,175,220,63,192,12,
- 0,0,0,0,33,16,0,2,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 232,255,189,39,96,133,130,143,33,40,128,0,
- 43,16,162,0,6,0,64,20,16,0,191,175,
- 100,133,130,143,0,0,0,0,43,16,162,0,
- 6,0,64,20,0,0,0,0,2,131,4,60,
- 15,63,192,12,116,130,132,36,71,14,192,8,
- 0,0,0,0,124,133,131,143,128,133,130,143,
- 124,133,133,175,1,0,66,36,4,0,163,172,
- 128,133,130,175,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,108,133,130,143,
- 232,255,189,39,20,0,191,175,17,0,64,20,
- 16,0,176,175,208,7,16,36,7,0,0,26,
- 0,0,0,0,143,63,192,12,255,255,16,38,
- 108,133,130,143,0,0,0,0,249,255,64,16,
- 0,0,0,0,6,0,0,22,0,0,0,0,
- 2,131,4,60,15,63,192,12,148,130,132,36,
- 108,14,192,8,33,16,0,0,220,63,192,12,
- 33,32,0,0,33,32,64,0,108,133,144,143,
- 120,133,130,143,0,0,3,142,255,255,66,36,
- 120,133,130,175,108,133,131,175,220,63,192,12,
- 0,0,0,0,33,16,0,2,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 232,255,189,39,104,133,130,143,33,40,128,0,
- 43,16,162,0,6,0,64,20,16,0,191,175,
- 112,133,130,143,0,0,0,0,43,16,162,0,
- 6,0,64,20,0,0,0,0,2,131,4,60,
- 15,63,192,12,184,130,132,36,135,14,192,8,
- 0,0,0,0,108,133,130,143,0,0,0,0,
- 0,0,162,172,120,133,130,143,108,133,133,175,
- 1,0,66,36,120,133,130,175,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,20,0,191,175,16,0,176,175,
- 124,133,128,175,13,8,192,12,0,32,4,36,
- 255,31,3,60,255,255,99,52,255,1,16,36,
- 36,16,67,0,0,160,3,60,37,16,67,0,
- 96,133,130,175,0,32,66,36,100,133,130,175,
- 0,17,16,0,96,133,132,143,255,255,16,38,
- 49,14,192,12,33,32,130,0,251,255,1,6,
- 0,17,16,0,0,2,2,36,132,133,130,175,
- 108,133,128,175,13,8,192,12,18,0,4,60,
- 255,31,3,60,255,255,99,52,255,17,16,36,
- 36,16,67,0,0,160,3,60,37,16,67,0,
- 18,0,3,60,104,133,130,175,33,16,67,0,
- 112,133,130,175,0,18,16,0,104,133,132,143,
- 255,255,16,38,112,14,192,12,33,32,130,0,
- 251,255,1,6,0,18,16,0,0,18,2,36,
- 116,133,130,175,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,163,2,60,
- 168,1,66,140,216,255,189,39,28,0,177,175,
- 33,136,128,0,32,0,178,175,33,144,160,0,
- 36,0,191,175,17,0,64,16,24,0,176,175,
- 0,163,2,60,168,1,66,140,0,0,0,0,
- 42,16,82,0,12,0,64,16,128,128,18,0,
- 0,0,34,142,0,163,18,60,168,1,82,142,
- 0,0,0,0,6,0,64,20,128,128,18,0,
- 2,131,4,60,224,130,132,36,15,63,192,12,
- 33,40,64,2,128,128,18,0,33,128,18,2,
- 128,128,16,0,13,8,192,12,33,32,0,2,
- 255,31,3,60,255,255,99,52,33,32,0,0,
- 36,16,67,0,0,160,3,60,37,16,67,0,
- 112,0,34,174,112,0,35,142,33,16,80,0,
- 15,0,64,26,116,0,34,174,8,0,5,36,
- 1,0,132,36,20,0,98,36,4,0,98,172,
- 2,0,101,164,0,0,96,164,8,0,96,172,
- 14,0,96,164,12,0,96,164,33,24,64,0,
- 42,16,146,0,246,255,64,20,1,0,132,36,
- 255,255,132,36,116,0,35,142,112,0,34,142,
- 0,0,0,0,240,255,98,172,116,0,35,142,
- 0,0,0,0,218,255,98,148,0,0,0,0,
- 0,128,66,52,218,255,98,164,116,0,35,142,
- 0,0,0,0,238,255,98,148,0,0,0,0,
- 0,128,66,52,238,255,98,164,116,0,34,142,
- 112,0,35,142,216,255,66,36,120,0,35,174,
- 124,0,34,174,36,0,191,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 40,0,189,39,200,255,189,39,32,0,178,175,
- 33,144,128,0,0,1,2,36,48,0,191,175,
- 44,0,181,175,40,0,180,175,36,0,179,175,
- 28,0,177,175,24,0,176,175,144,0,66,174,
- 0,163,2,60,172,1,66,140,0,0,0,0,
- 17,0,64,16,33,160,160,0,0,163,2,60,
- 172,1,66,140,0,0,0,0,42,16,84,0,
- 12,0,64,16,128,128,20,0,0,0,66,142,
- 0,163,20,60,172,1,148,142,0,0,0,0,
- 6,0,64,20,128,128,20,0,2,131,4,60,
- 236,130,132,36,15,63,192,12,33,40,128,2,
- 128,128,20,0,33,128,20,2,128,128,16,0,
- 33,32,0,2,13,8,192,12,148,0,84,174,
- 255,31,3,60,255,255,99,52,33,152,0,0,
- 36,16,67,0,0,160,3,60,37,16,67,0,
- 128,0,66,174,128,0,81,142,33,16,80,0,
- 15,0,128,26,132,0,66,174,0,1,21,36,
- 20,0,48,38,4,0,48,174,75,14,192,12,
- 0,0,32,174,8,0,34,174,12,0,53,174,
- 0,0,66,142,1,0,115,38,16,0,34,162,
- 17,0,32,162,42,16,116,2,244,255,64,20,
- 33,136,0,2,132,0,67,142,128,0,66,142,
- 0,0,0,0,240,255,98,172,132,0,67,142,
- 0,0,0,0,228,255,98,140,0,0,0,0,
- 0,128,66,52,228,255,98,172,132,0,67,142,
- 0,0,0,0,248,255,98,140,0,0,0,0,
- 0,128,66,52,248,255,98,172,132,0,66,142,
- 128,0,67,142,216,255,66,36,136,0,67,174,
- 140,0,66,174,48,0,191,143,44,0,181,143,
- 40,0,180,143,36,0,179,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 56,0,189,39,152,0,128,172,156,0,128,172,
- 160,0,128,172,164,0,128,172,168,0,128,172,
- 252,0,128,172,0,1,128,172,152,0,128,172,
- 8,0,224,3,216,0,128,172,232,255,189,39,
- 16,0,176,175,20,0,191,175,112,15,192,12,
- 33,128,128,0,33,32,0,2,192,14,192,12,
- 0,4,5,36,33,32,0,2,19,15,192,12,
- 128,2,5,36,120,0,3,142,136,0,2,142,
- 0,0,0,0,8,0,98,172,44,0,3,142,
- 120,0,2,142,0,0,0,0,8,0,98,172,
- 0,0,2,142,0,0,0,0,255,255,66,36,
- 6,0,66,44,7,0,64,16,16,0,3,36,
- 44,0,2,142,0,0,0,0,2,0,67,164,
- 8,0,2,142,0,0,0,0,0,0,64,172,
- 20,0,191,143,16,0,176,143,8,0,224,3,
- 24,0,189,39,184,255,189,39,0,32,6,36,
- 68,0,191,175,64,0,190,175,60,0,183,175,
- 56,0,182,175,52,0,181,175,48,0,180,175,
- 44,0,179,175,40,0,178,175,36,0,177,175,
- 32,0,176,175,0,163,1,60,252,5,38,172,
- 13,8,192,12,0,32,4,36,255,31,4,60,
- 255,255,132,52,33,168,0,0,255,31,6,60,
- 255,255,198,52,2,131,3,60,212,247,99,36,
- 16,0,101,36,8,0,126,36,248,255,119,36,
- 33,176,96,0,36,16,68,0,0,160,3,60,
- 37,16,67,0,16,0,166,175,0,163,1,60,
- 248,5,34,172,0,163,1,60,0,6,32,172,
- 33,160,0,0,33,128,224,2,33,152,160,0,
- 33,144,192,3,33,136,192,2,32,133,130,143,
- 0,0,32,174,0,0,0,174,0,0,64,174,
- 42,16,162,2,10,0,64,16,0,0,96,174,
- 0,32,4,36,13,8,192,12,24,0,165,175,
- 16,0,166,143,0,128,3,60,36,16,70,0,
- 37,16,67,0,0,0,2,174,24,0,165,143,
- 4,0,16,38,4,0,115,38,4,0,82,38,
- 1,0,148,38,2,0,130,42,234,255,64,20,
- 4,0,49,38,0,2,165,36,0,2,222,39,
- 0,2,247,38,1,0,181,38,7,0,162,42,
- 222,255,64,20,0,2,214,38,68,0,191,143,
- 64,0,190,143,60,0,183,143,56,0,182,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,72,0,189,39,0,163,4,60,
- 0,6,132,140,0,163,3,60,8,6,99,140,
- 32,133,130,143,224,255,189,39,16,0,176,175,
- 0,163,16,60,12,6,16,142,20,0,177,175,
- 0,163,17,60,4,6,49,142,43,16,98,0,
- 42,0,64,16,24,0,191,175,2,0,2,46,
- 40,0,64,16,255,255,2,36,0,163,2,60,
- 252,5,66,140,0,0,0,0,43,16,81,0,
- 34,0,64,20,255,255,2,36,64,18,3,0,
- 2,131,3,60,192,246,99,36,33,24,67,0,
- 1,0,2,36,5,0,130,16,2,0,2,36,
- 18,0,130,16,128,16,16,0,36,16,192,8,
- 0,0,0,0,128,128,16,0,33,128,3,2,
- 12,1,4,142,0,163,5,60,248,5,165,140,
- 33,48,32,2,80,68,192,12,36,1,17,174,
- 12,1,4,142,12,1,2,142,33,40,32,2,
- 114,68,192,12,20,1,2,174,36,16,192,8,
- 0,0,0,0,33,16,67,0,20,1,64,172,
- 36,1,64,172,0,163,1,60,42,16,192,8,
- 0,6,32,172,255,255,2,36,0,163,1,60,
- 0,6,34,172,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 176,133,136,143,188,133,137,143,232,255,189,39,
- 3,0,0,21,16,0,191,175,124,0,32,17,
- 0,0,0,0,12,0,194,148,0,0,0,0,
- 0,26,2,0,2,18,2,0,37,56,98,0,
- 255,255,227,48,221,5,98,44,36,0,64,20,
- 170,170,2,52,0,8,2,36,23,0,98,20,
- 6,8,2,36,21,0,0,17,0,0,0,0,
- 32,0,194,148,30,0,195,148,0,20,2,0,
- 37,56,67,0,36,0,195,148,0,161,2,52,
- 5,0,98,16,8,0,2,36,34,0,195,148,
- 0,0,0,0,98,0,98,20,0,0,0,0,
- 3,0,232,16,255,255,2,36,94,0,226,20,
- 0,0,0,0,226,46,192,12,14,0,6,36,
- 177,16,192,8,0,0,0,0,7,0,98,20,
- 255,255,227,48,71,0,0,17,55,129,2,52,
- 108,43,192,12,14,0,6,36,177,16,192,8,
- 0,0,0,0,162,16,192,8,55,129,2,52,
- 14,0,195,148,0,0,0,0,61,0,98,20,
- 255,255,2,52,16,0,195,144,3,0,2,36,
- 55,0,98,20,255,255,2,52,20,0,194,148,
- 0,0,0,0,0,26,2,0,2,18,2,0,
- 37,56,98,0,255,255,227,48,0,8,2,36,
- 23,0,98,20,6,8,2,36,21,0,0,17,
- 0,0,0,0,40,0,194,148,38,0,195,148,
- 0,20,2,0,37,56,67,0,44,0,195,148,
- 0,161,2,52,5,0,98,16,8,0,2,36,
- 42,0,195,148,0,0,0,0,49,0,98,20,
- 0,0,0,0,3,0,232,16,255,255,2,36,
- 45,0,226,20,0,0,0,0,226,46,192,12,
- 22,0,6,36,177,16,192,8,0,0,0,0,
- 7,0,98,20,255,255,227,48,6,0,0,17,
- 55,129,2,52,108,43,192,12,22,0,6,36,
- 177,16,192,8,0,0,0,0,55,129,2,52,
- 30,0,98,20,0,0,0,0,28,0,32,17,
- 144,15,3,36,38,0,194,148,28,0,198,140,
- 24,0,67,20,0,0,0,0,3,0,201,16,
- 0,0,0,0,20,0,192,20,0,0,0,0,
- 175,16,192,8,22,0,6,36,14,0,195,148,
- 0,0,0,0,14,0,98,20,0,0,0,0,
- 12,0,32,17,144,15,3,36,30,0,194,148,
- 20,0,198,140,8,0,67,20,0,0,0,0,
- 3,0,201,16,0,0,0,0,4,0,192,20,
- 0,0,0,0,14,0,6,36,126,49,192,12,
- 0,0,0,0,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,128,255,189,39,
- 116,0,183,175,33,184,128,0,3,0,3,36,
- 124,0,191,175,120,0,190,175,112,0,182,175,
- 108,0,181,175,104,0,180,175,100,0,179,175,
- 96,0,178,175,92,0,177,175,88,0,176,175,
- 0,0,245,142,8,0,178,140,192,17,21,0,
- 3,131,4,60,33,32,130,0,20,13,132,140,
- 8,0,84,142,0,0,0,0,59,0,131,16,
- 5,0,130,44,57,0,64,16,128,16,4,0,
- 2,131,1,60,33,8,34,0,104,131,34,140,
- 0,0,0,0,8,0,64,0,0,0,0,0,
- 44,133,130,143,0,0,0,0,48,0,64,16,
- 6,0,132,38,4,0,131,150,2,131,2,60,
- 68,207,66,148,0,0,0,0,6,0,98,20,
- 33,32,0,0,0,0,130,142,48,129,131,143,
- 0,0,0,0,38,16,67,0,1,0,68,44,
- 72,1,128,16,33,32,160,2,114,42,192,12,
- 33,40,128,2,45,18,192,8,33,32,64,2,
- 44,133,130,143,0,0,0,0,27,0,64,16,
- 6,0,132,38,4,0,131,150,2,131,2,60,
- 68,207,66,148,0,0,0,0,6,0,98,20,
- 33,32,0,0,0,0,130,142,48,129,131,143,
- 0,0,0,0,38,16,67,0,1,0,68,44,
- 5,0,128,16,33,32,160,2,114,42,192,12,
- 33,40,128,2,45,18,192,8,33,32,64,2,
- 6,0,132,38,0,163,6,60,140,1,198,140,
- 0,0,0,0,247,24,192,12,33,40,160,2,
- 45,18,192,8,33,32,64,2,6,0,132,38,
- 0,163,6,60,140,1,198,140,0,0,0,0,
- 247,24,192,12,33,40,160,2,203,24,192,12,
- 33,32,128,2,20,1,227,142,0,0,0,0,
- 14,0,96,16,33,240,64,0,33,32,128,2,
- 16,0,166,39,18,0,69,150,0,0,0,0,
- 9,248,96,0,33,56,192,3,6,0,64,16,
- 33,32,64,2,28,1,226,142,0,0,0,0,
- 1,0,66,36,45,18,192,8,28,1,226,174,
- 132,0,193,7,7,0,2,36,4,0,131,150,
- 2,131,2,60,68,207,66,148,0,0,0,0,
- 6,0,98,20,33,32,0,0,0,0,130,142,
- 48,129,131,143,0,0,0,0,38,16,67,0,
- 1,0,68,44,9,0,128,16,255,255,2,36,
- 44,133,130,143,0,0,0,0,251,0,64,16,
- 33,32,160,2,114,42,192,12,33,40,128,2,
- 45,18,192,8,33,32,64,2,10,0,194,23,
- 0,0,0,0,8,0,160,18,0,0,0,0,
- 36,133,130,143,0,0,0,0,8,0,64,16,
- 1,0,19,36,80,133,147,143,69,17,192,8,
- 0,0,0,0,0,1,226,142,80,133,147,143,
- 1,0,66,36,0,1,226,174,84,133,130,143,
- 0,0,0,0,35,16,83,0,255,255,66,36,
- 17,0,66,162,84,133,130,143,33,128,96,2,
- 42,16,2,2,15,0,64,16,64,18,16,0,
- 2,131,3,60,192,246,99,36,33,136,67,0,
- 5,0,21,18,0,0,0,0,247,22,192,12,
- 33,32,32,2,217,0,64,16,33,16,0,0,
- 84,133,130,143,1,0,16,38,42,16,2,2,
- 246,255,64,20,0,2,49,38,84,133,130,143,
- 33,128,96,2,42,16,2,2,55,0,64,16,
- 64,18,16,0,2,131,3,60,192,246,99,36,
- 33,152,67,0,33,136,64,0,192,177,16,0,
- 41,0,21,18,0,0,0,0,2,131,2,60,
- 33,16,81,0,216,247,66,140,0,0,0,0,
- 15,0,64,16,33,32,128,2,16,0,166,39,
- 18,0,69,150,0,0,0,0,9,248,64,0,
- 33,56,160,2,8,0,64,16,0,0,0,0,
- 2,131,2,60,33,16,81,0,224,247,66,140,
- 0,0,0,0,1,0,66,36,140,17,192,8,
- 32,1,98,174,44,133,130,143,0,0,0,0,
- 7,0,64,16,3,0,8,36,3,131,2,60,
- 33,16,86,0,20,13,66,140,0,0,0,0,
- 6,0,72,20,0,0,0,0,33,32,96,2,
- 6,23,192,12,33,40,64,2,146,17,192,8,
- 0,2,115,38,17,0,66,146,0,0,0,0,
- 255,255,66,36,17,0,66,162,17,0,66,146,
- 0,2,115,38,0,2,49,38,84,133,130,143,
- 1,0,16,38,42,16,2,2,208,255,64,20,
- 128,0,214,38,254,255,2,36,4,0,194,23,
- 33,32,224,2,33,40,64,2,47,16,192,12,
- 33,48,128,2,17,0,66,146,0,0,0,0,
- 140,0,64,16,33,32,64,2,36,18,192,8,
- 0,0,0,0,26,0,194,23,0,0,0,0,
- 36,133,130,143,0,0,0,0,11,0,64,16,
- 33,32,224,2,9,0,160,18,1,0,2,36,
- 17,0,66,162,2,131,4,60,192,246,132,36,
- 6,23,192,12,33,40,64,2,126,0,64,16,
- 33,16,0,0,33,32,224,2,33,40,64,2,
- 47,16,192,12,33,48,128,2,36,133,130,143,
- 0,0,0,0,115,0,64,16,33,32,64,2,
- 116,0,160,22,1,0,2,36,45,18,192,8,
- 0,0,0,0,87,0,213,19,64,130,30,0,
- 2,131,2,60,33,16,80,0,216,247,66,140,
- 0,0,0,0,18,0,64,16,33,32,128,2,
- 16,0,166,39,18,0,69,150,0,0,0,0,
- 9,248,64,0,33,56,160,2,11,0,64,16,
- 33,32,64,2,2,131,2,60,33,16,80,0,
- 224,247,66,140,0,0,0,0,1,0,66,36,
- 2,131,1,60,33,8,48,0,224,247,34,172,
- 45,18,192,8,17,0,128,160,36,133,130,143,
- 0,0,0,0,43,0,64,16,0,0,0,0,
- 41,0,192,19,0,0,0,0,39,0,160,18,
- 64,18,30,0,2,131,16,60,192,246,16,38,
- 33,136,80,0,247,22,192,12,33,32,32,2,
- 74,0,64,16,33,16,0,0,247,22,192,12,
- 33,32,0,2,63,0,64,16,2,0,2,36,
- 17,0,66,162,44,133,130,143,0,0,0,0,
- 7,0,64,16,192,17,30,0,3,131,3,60,
- 33,24,98,0,20,13,99,140,3,0,2,36,
- 6,0,98,20,0,0,0,0,33,32,32,2,
- 6,23,192,12,33,40,64,2,0,18,192,8,
- 0,0,0,0,17,0,66,146,0,0,0,0,
- 255,255,66,36,17,0,66,162,17,0,66,146,
- 2,131,4,60,192,246,132,36,6,23,192,12,
- 33,40,64,2,36,18,192,8,0,0,0,0,
- 44,133,130,143,0,0,0,0,7,0,64,16,
- 192,17,30,0,3,131,3,60,33,24,98,0,
- 20,13,99,140,3,0,2,36,28,0,98,20,
- 0,0,0,0,1,0,2,36,17,0,66,162,
- 64,18,30,0,2,131,4,60,192,246,132,36,
- 32,18,192,8,33,32,68,0,36,133,130,143,
- 0,0,0,0,17,0,64,16,0,0,0,0,
- 15,0,192,19,1,0,2,36,17,0,66,162,
- 2,131,4,60,192,246,132,36,6,23,192,12,
- 33,40,64,2,13,0,64,16,33,16,0,0,
- 252,0,226,142,0,0,0,0,1,0,66,36,
- 47,18,192,8,252,0,226,174,48,18,192,8,
- 33,16,0,0,17,0,64,162,33,32,64,2,
- 152,21,192,12,0,0,0,0,1,0,2,36,
- 124,0,191,143,120,0,190,143,116,0,183,143,
- 112,0,182,143,108,0,181,143,104,0,180,143,
- 100,0,179,143,96,0,178,143,92,0,177,143,
- 88,0,176,143,8,0,224,3,128,0,189,39,
- 216,255,189,39,24,0,178,175,33,144,128,0,
- 32,0,191,175,28,0,179,175,20,0,177,175,
- 16,0,176,175,8,0,177,140,0,0,66,142,
- 8,0,38,142,36,0,64,16,0,0,0,0,
- 28,0,66,142,0,0,0,0,18,0,64,20,
- 1,0,2,36,0,0,194,144,0,0,0,0,
- 1,0,66,48,13,0,64,20,1,0,2,36,
- 4,0,195,148,24,0,66,150,0,0,0,0,
- 6,0,98,20,33,32,0,0,0,0,194,140,
- 20,0,67,142,0,0,0,0,38,16,67,0,
- 1,0,68,44,10,0,128,16,1,0,2,36,
- 17,0,34,162,2,131,4,60,192,246,132,36,
- 6,23,192,12,33,40,32,2,45,0,64,16,
- 33,16,0,0,139,18,192,8,0,0,0,0,
- 17,0,32,162,152,21,192,12,33,32,32,2,
- 144,18,192,8,1,0,2,36,16,0,179,140,
- 0,0,0,0,6,0,96,26,0,0,0,0,
- 32,133,130,143,0,0,0,0,42,16,98,2,
- 15,0,64,20,1,0,2,36,2,131,4,60,
- 248,130,132,36,2,131,16,60,24,131,16,38,
- 33,40,0,2,2,131,7,60,36,131,231,36,
- 15,63,192,12,188,2,6,36,1,0,4,36,
- 33,40,0,2,188,7,192,12,188,2,6,36,
- 1,0,2,36,17,0,34,162,64,18,19,0,
- 2,131,4,60,192,246,132,36,33,32,68,0,
- 6,23,192,12,33,40,32,2,6,0,64,16,
- 33,16,0,0,252,0,66,142,0,0,0,0,
- 1,0,66,36,252,0,66,174,1,0,2,36,
- 32,0,191,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,72,255,189,39,164,0,181,175,
- 33,168,128,0,180,0,191,175,176,0,190,175,
- 172,0,183,175,168,0,182,175,160,0,180,175,
- 156,0,179,175,152,0,178,175,148,0,177,175,
- 144,0,176,175,88,0,165,175,120,0,160,175,
- 120,0,168,142,0,0,0,0,96,0,168,175,
- 124,0,169,142,0,0,0,0,15,2,160,24,
- 104,0,169,175,96,0,168,143,0,0,0,0,
- 0,0,4,149,0,0,0,0,0,128,130,48,
- 9,2,64,16,0,0,0,0,128,0,160,175,
- 8,0,2,141,136,0,169,142,255,255,8,36,
- 18,0,72,16,112,0,169,175,112,0,169,143,
- 0,0,0,0,0,0,35,141,4,0,40,141,
- 128,0,169,143,255,63,98,48,33,72,34,1,
- 0,128,99,48,112,0,168,175,246,255,96,16,
- 128,0,169,175,96,0,168,143,0,0,0,0,
- 8,0,2,141,128,0,169,151,0,0,0,0,
- 18,0,73,164,0,32,130,48,200,1,64,16,
- 0,0,0,0,40,133,130,143,0,0,0,0,
- 75,0,64,16,3,0,8,36,96,0,168,143,
- 0,0,0,0,8,0,16,141,0,0,162,142,
- 8,0,5,142,30,0,64,16,0,0,0,0,
- 28,0,162,142,0,0,0,0,18,0,64,20,
- 1,0,9,36,0,0,162,144,0,0,0,0,
- 1,0,66,48,13,0,64,20,0,0,0,0,
- 4,0,163,148,24,0,162,150,0,0,0,0,
- 6,0,98,20,33,32,0,0,0,0,162,140,
- 20,0,163,142,0,0,0,0,38,16,67,0,
- 1,0,68,44,6,0,128,16,1,0,9,36,
- 17,0,9,162,2,131,4,60,192,246,132,36,
- 18,19,192,8,33,40,0,2,17,0,0,162,
- 130,20,192,8,33,32,0,2,16,0,17,141,
- 0,0,0,0,6,0,32,26,0,0,0,0,
- 32,133,130,143,0,0,0,0,42,16,34,2,
- 15,0,64,20,1,0,9,36,2,131,4,60,
- 248,130,132,36,2,131,5,60,24,131,165,36,
- 2,131,7,60,36,131,231,36,15,63,192,12,
- 188,2,6,36,1,0,4,36,2,131,5,60,
- 24,131,165,36,188,7,192,12,188,2,6,36,
- 1,0,9,36,17,0,9,162,64,34,17,0,
- 2,131,8,60,192,246,8,37,33,32,136,0,
- 33,40,0,2,6,23,192,12,0,0,0,0,
- 112,1,64,16,33,16,0,0,252,0,162,142,
- 0,0,0,0,1,0,66,36,132,20,192,8,
- 252,0,162,174,0,0,182,142,96,0,169,143,
- 192,17,22,0,8,0,50,141,3,131,3,60,
- 33,24,98,0,20,13,99,140,8,0,84,142,
- 0,0,0,0,59,0,104,16,5,0,98,44,
- 57,0,64,16,128,16,3,0,2,131,1,60,
- 33,8,34,0,128,131,34,140,0,0,0,0,
- 8,0,64,0,0,0,0,0,44,133,130,143,
- 0,0,0,0,48,0,64,16,6,0,132,38,
- 4,0,131,150,2,131,2,60,68,207,66,148,
- 0,0,0,0,6,0,98,20,33,32,0,0,
- 0,0,130,142,48,129,131,143,0,0,0,0,
- 38,16,67,0,1,0,68,44,67,1,128,16,
- 33,32,192,2,114,42,192,12,33,40,128,2,
- 130,20,192,8,33,32,64,2,44,133,130,143,
- 0,0,0,0,27,0,64,16,6,0,132,38,
- 4,0,131,150,2,131,2,60,68,207,66,148,
- 0,0,0,0,6,0,98,20,33,32,0,0,
- 0,0,130,142,48,129,131,143,0,0,0,0,
- 38,16,67,0,1,0,68,44,5,0,128,16,
- 33,32,192,2,114,42,192,12,33,40,128,2,
- 130,20,192,8,33,32,64,2,6,0,132,38,
- 0,163,6,60,140,1,198,140,0,0,0,0,
- 247,24,192,12,33,40,192,2,130,20,192,8,
- 33,32,64,2,6,0,132,38,0,163,6,60,
- 140,1,198,140,0,0,0,0,247,24,192,12,
- 33,40,192,2,203,24,192,12,33,32,128,2,
- 20,1,163,142,0,0,0,0,14,0,96,16,
- 33,240,64,0,33,32,128,2,16,0,166,39,
- 18,0,69,150,0,0,0,0,9,248,96,0,
- 33,56,192,3,6,0,64,16,33,32,64,2,
- 28,1,162,142,0,0,0,0,1,0,66,36,
- 130,20,192,8,28,1,162,174,132,0,193,7,
- 7,0,2,36,4,0,131,150,2,131,2,60,
- 68,207,66,148,0,0,0,0,6,0,98,20,
- 33,32,0,0,0,0,130,142,48,129,131,143,
- 0,0,0,0,38,16,67,0,1,0,68,44,
- 9,0,128,16,255,255,9,36,44,133,130,143,
- 0,0,0,0,246,0,64,16,33,32,192,2,
- 114,42,192,12,33,40,128,2,130,20,192,8,
- 33,32,64,2,10,0,201,23,0,0,0,0,
- 8,0,192,18,0,0,0,0,36,133,130,143,
- 0,0,0,0,8,0,64,16,1,0,19,36,
- 80,133,147,143,159,19,192,8,0,0,0,0,
- 0,1,162,142,80,133,147,143,1,0,66,36,
- 0,1,162,174,84,133,130,143,0,0,0,0,
- 35,16,83,0,255,255,66,36,17,0,66,162,
- 84,133,130,143,33,136,96,2,42,16,34,2,
- 15,0,64,16,64,18,17,0,2,131,8,60,
- 192,246,8,37,33,128,72,0,5,0,54,18,
- 0,0,0,0,247,22,192,12,33,32,0,2,
- 212,0,64,16,33,16,0,0,84,133,130,143,
- 1,0,49,38,42,16,34,2,246,255,64,20,
- 0,2,16,38,84,133,130,143,33,136,96,2,
- 42,16,34,2,55,0,64,16,64,18,17,0,
- 2,131,9,60,192,246,41,37,33,152,73,0,
- 33,128,64,0,192,185,17,0,41,0,54,18,
- 0,0,0,0,2,131,2,60,33,16,80,0,
- 216,247,66,140,0,0,0,0,15,0,64,16,
- 33,32,128,2,16,0,166,39,18,0,69,150,
- 0,0,0,0,9,248,64,0,33,56,192,2,
- 8,0,64,16,0,0,0,0,2,131,2,60,
- 33,16,80,0,224,247,66,140,0,0,0,0,
- 1,0,66,36,230,19,192,8,32,1,98,174,
- 44,133,130,143,0,0,0,0,7,0,64,16,
- 3,0,8,36,3,131,2,60,33,16,87,0,
- 20,13,66,140,0,0,0,0,6,0,72,20,
- 0,0,0,0,33,32,96,2,6,23,192,12,
- 33,40,64,2,236,19,192,8,0,2,115,38,
- 17,0,66,146,0,0,0,0,255,255,66,36,
- 17,0,66,162,17,0,66,146,0,2,115,38,
- 0,2,16,38,84,133,130,143,1,0,49,38,
- 42,16,34,2,208,255,64,20,128,0,247,38,
- 254,255,2,36,4,0,194,23,33,32,160,2,
- 33,40,64,2,47,16,192,12,33,48,128,2,
- 17,0,66,146,0,0,0,0,135,0,64,16,
- 33,32,64,2,22,19,192,8,0,0,0,0,
- 26,0,194,23,0,0,0,0,36,133,130,143,
- 0,0,0,0,11,0,64,16,33,32,160,2,
- 9,0,192,18,1,0,9,36,17,0,73,162,
- 2,131,4,60,192,246,132,36,6,23,192,12,
- 33,40,64,2,121,0,64,16,33,16,0,0,
- 33,32,160,2,33,40,64,2,47,16,192,12,
- 33,48,128,2,36,133,130,143,0,0,0,0,
- 110,0,64,16,33,32,64,2,111,0,192,22,
- 1,0,2,36,130,20,192,8,0,0,0,0,
- 89,0,214,19,64,130,30,0,2,131,2,60,
- 33,16,80,0,216,247,66,140,0,0,0,0,
- 18,0,64,16,33,32,128,2,16,0,166,39,
- 18,0,69,150,0,0,0,0,9,248,64,0,
- 33,56,192,2,11,0,64,16,33,32,64,2,
- 2,131,8,60,192,246,8,37,2,131,2,60,
- 33,16,80,0,224,247,66,140,33,24,8,2,
- 1,0,66,36,32,1,98,172,130,20,192,8,
- 17,0,128,160,36,133,130,143,0,0,0,0,
- 44,0,64,16,0,0,0,0,42,0,192,19,
- 0,0,0,0,40,0,192,18,64,18,30,0,
- 2,131,9,60,192,246,41,37,33,128,73,0,
- 247,22,192,12,33,32,0,2,69,0,64,16,
- 33,16,0,0,2,131,4,60,247,22,192,12,
- 192,246,132,36,57,0,64,16,2,0,2,36,
- 17,0,66,162,44,133,130,143,0,0,0,0,
- 7,0,64,16,192,17,30,0,3,131,1,60,
- 33,8,34,0,20,13,34,140,3,0,8,36,
- 6,0,72,20,0,0,0,0,33,32,0,2,
- 6,23,192,12,33,40,64,2,91,20,192,8,
- 0,0,0,0,17,0,66,146,0,0,0,0,
- 255,255,66,36,17,0,66,162,17,0,66,146,
- 2,131,4,60,192,246,132,36,6,23,192,12,
- 33,40,64,2,22,19,192,8,0,0,0,0,
- 44,133,130,143,0,0,0,0,7,0,64,16,
- 192,17,30,0,3,131,1,60,33,8,34,0,
- 20,13,34,140,3,0,9,36,22,0,73,20,
- 0,0,0,0,1,0,8,36,17,0,72,162,
- 64,34,30,0,2,131,9,60,192,246,41,37,
- 33,32,137,0,18,19,192,8,33,40,64,2,
- 36,133,130,143,0,0,0,0,10,0,64,16,
- 0,0,0,0,8,0,192,19,1,0,8,36,
- 17,0,72,162,2,131,4,60,192,246,132,36,
- 18,19,192,8,33,40,64,2,133,20,192,8,
- 33,16,0,0,17,0,64,162,33,32,64,2,
- 152,21,192,12,0,0,0,0,1,0,2,36,
- 52,0,64,16,0,0,0,0,152,0,162,142,
- 0,0,0,0,1,0,66,36,152,0,162,174,
- 156,0,162,142,168,0,163,142,1,0,66,36,
- 156,0,162,174,128,0,169,143,0,0,0,0,
- 33,24,105,0,163,20,192,8,168,0,163,174,
- 152,0,162,142,160,0,163,142,1,0,66,36,
- 1,0,99,36,152,0,162,174,160,0,163,174,
- 96,0,168,143,0,0,0,0,8,0,2,141,
- 255,255,9,36,4,0,73,16,0,0,0,0,
- 8,0,4,141,152,21,192,12,0,0,0,0,
- 120,0,168,143,112,0,169,143,1,0,8,37,
- 120,0,168,175,136,0,169,174,96,0,168,143,
- 8,128,2,52,0,0,0,165,2,0,2,165,
- 104,0,169,143,8,0,2,36,2,0,34,165,
- 4,0,40,141,96,0,169,143,104,0,168,175,
- 4,0,41,141,120,0,168,143,96,0,169,175,
- 88,0,169,143,0,0,0,0,42,16,9,1,
- 243,253,64,20,0,0,0,0,96,0,168,143,
- 44,0,163,142,120,0,168,174,104,0,169,143,
- 0,0,0,0,124,0,169,174,0,0,98,148,
- 0,0,0,0,0,16,66,48,43,0,64,16,
- 0,0,0,0,2,0,98,148,0,0,0,0,
- 39,0,64,20,0,0,0,0,0,0,2,149,
- 0,0,0,0,35,0,64,20,0,0,0,0,
- 2,0,2,149,8,0,3,36,255,255,66,48,
- 30,0,67,20,0,0,0,0,136,0,162,142,
- 0,0,0,0,12,0,66,140,0,0,0,0,
- 0,128,66,48,23,0,64,20,0,0,0,0,
- 164,0,162,142,44,0,163,142,1,0,66,36,
- 164,0,162,174,8,0,104,172,136,0,162,142,
- 0,0,0,0,8,0,2,173,44,0,163,142,
- 16,16,2,36,2,0,98,164,0,0,162,142,
- 0,0,0,0,5,0,64,20,0,0,0,0,
- 164,7,192,12,0,0,0,0,239,20,192,8,
- 0,0,0,0,8,0,162,142,0,0,0,0,
- 0,0,64,172,180,0,191,143,176,0,190,143,
- 172,0,183,143,168,0,182,143,164,0,181,143,
- 160,0,180,143,156,0,179,143,152,0,178,143,
- 148,0,177,143,144,0,176,143,8,0,224,3,
- 184,0,189,39,216,255,189,39,28,0,177,175,
- 33,136,128,0,32,0,178,175,33,144,160,0,
- 96,128,132,39,6,0,37,38,24,0,176,175,
- 104,128,144,39,36,0,191,175,31,21,192,12,
- 33,48,0,2,108,128,132,39,33,40,32,2,
- 31,21,192,12,33,48,0,2,10,0,64,26,
- 33,128,0,0,116,128,132,39,33,16,17,2,
- 12,0,69,144,0,0,0,0,15,63,192,12,
- 1,0,16,38,42,16,18,2,248,255,64,20,
- 0,0,0,0,124,128,132,39,15,63,192,12,
- 0,0,0,0,36,0,191,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 40,0,189,39,208,255,189,39,40,0,191,175,
- 2,0,162,144,0,0,163,144,1,0,167,144,
- 16,0,162,175,3,0,162,144,33,64,128,0,
- 20,0,162,175,4,0,162,144,2,131,4,60,
- 68,131,132,36,24,0,162,175,5,0,162,144,
- 33,40,0,1,32,0,166,175,33,48,96,0,
- 15,63,192,12,28,0,162,175,40,0,191,143,
- 48,0,189,39,8,0,224,3,0,0,0,0,
- 248,255,189,39,136,0,135,140,255,255,163,36,
- 12,0,160,16,33,48,224,0,255,255,5,36,
- 12,0,194,140,0,0,0,0,0,128,66,48,
- 8,0,64,20,33,16,0,0,255,255,99,36,
- 0,0,192,172,4,0,198,140,247,255,101,20,
- 0,0,0,0,136,0,134,172,33,16,224,0,
- 8,0,224,3,8,0,189,39,224,255,189,39,
- 16,0,176,175,33,128,160,0,28,0,191,175,
- 24,0,178,175,33,0,128,20,20,0,177,175,
- 84,133,130,143,80,133,131,143,0,0,0,0,
- 35,16,67,0,17,0,2,162,80,133,145,143,
- 84,133,130,143,0,0,0,0,42,16,34,2,
- 19,0,64,16,64,18,17,0,2,131,3,60,
- 192,246,99,36,33,144,67,0,33,32,64,2,
- 6,23,192,12,33,40,0,2,6,0,64,20,
- 0,0,0,0,17,0,2,146,0,0,0,0,
- 255,255,66,36,17,0,2,162,17,0,2,146,
- 84,133,130,143,1,0,49,38,42,16,34,2,
- 242,255,64,20,0,2,82,38,17,0,2,146,
- 144,21,192,8,0,0,0,0,36,133,130,143,
- 0,0,0,0,25,0,64,16,1,0,2,36,
- 0,0,130,140,0,0,0,0,20,0,64,16,
- 2,0,2,36,17,0,2,162,6,23,192,12,
- 33,40,0,2,19,0,64,16,33,16,0,0,
- 2,131,4,60,192,246,132,36,6,23,192,12,
- 33,40,0,2,7,0,64,20,0,0,0,0,
- 17,0,2,146,0,0,0,0,255,255,66,36,
- 17,0,2,162,17,0,2,146,0,0,0,0,
- 144,21,192,8,1,0,2,36,1,0,2,36,
- 17,0,2,162,6,23,192,12,33,40,0,2,
- 28,0,191,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 0,0,0,0,0,0,0,0,0,129,9,52,
- 16,0,130,144,2,131,3,60,192,246,99,36,
- 64,18,2,0,33,56,67,0,140,0,230,140,
- 0,1,8,36,4,0,197,140,0,0,131,140,
- 0,0,128,172,12,0,137,172,4,0,164,172,
- 12,0,200,172,33,48,160,0,216,0,226,140,
- 33,40,128,0,1,0,66,36,0,128,99,48,
- 4,0,96,20,216,0,226,172,4,0,132,140,
- 161,21,192,8,0,0,0,0,8,0,224,3,
- 140,0,230,172,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,8,0,224,3,0,0,0,0,
- 172,0,128,172,176,0,128,172,180,0,128,172,
- 184,0,128,172,188,0,128,172,192,0,128,172,
- 196,0,128,172,200,0,128,172,204,0,128,172,
- 208,0,128,172,212,0,128,172,224,0,128,172,
- 8,1,128,172,4,1,128,172,236,0,128,172,
- 240,0,128,172,232,0,128,172,244,0,128,172,
- 8,0,224,3,248,0,128,172,224,255,189,39,
- 16,0,176,175,33,128,128,0,20,0,177,175,
- 0,2,17,36,24,0,191,175,13,8,192,12,
- 0,48,4,36,255,31,3,60,255,255,99,52,
- 33,32,0,0,36,16,67,0,0,128,3,60,
- 37,40,67,0,33,24,160,0,0,128,6,52,
- 1,0,132,36,24,0,98,36,0,0,96,164,
- 2,0,102,164,4,0,98,172,33,24,64,0,
- 42,16,145,0,249,255,64,20,1,0,132,36,
- 255,255,132,36,64,16,17,0,33,16,81,0,
- 192,16,2,0,33,16,69,0,48,0,163,36,
- 236,255,69,172,108,0,3,174,104,0,3,174,
- 96,0,5,174,100,0,2,174,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,248,255,189,39,0,32,14,60,
- 4,0,177,175,7,0,17,60,0,0,176,175,
- 4,0,16,60,2,131,25,60,192,246,57,39,
- 0,1,15,36,108,0,152,140,104,0,137,140,
- 176,0,140,140,180,0,141,140,94,0,56,17,
- 0,0,0,0,4,0,43,141,0,0,0,0,
- 37,16,110,1,0,0,66,148,0,0,0,0,
- 0,128,66,48,86,0,64,16,37,16,46,1,
- 0,0,67,140,0,0,0,0,36,16,113,0,
- 76,0,80,20,0,32,98,48,41,0,64,20,
- 15,0,98,48,188,0,130,140,0,0,0,0,
- 1,0,66,36,188,0,130,172,0,8,98,48,
- 6,0,64,16,0,4,98,48,192,0,130,140,
- 0,0,0,0,1,0,66,36,192,0,130,172,
- 0,4,98,48,6,0,64,16,0,2,98,48,
- 196,0,130,140,0,0,0,0,1,0,66,36,
- 196,0,130,172,0,2,98,48,6,0,64,16,
- 0,1,98,48,200,0,130,140,0,0,0,0,
- 1,0,66,36,200,0,130,172,0,1,98,48,
- 6,0,64,16,32,0,98,48,204,0,130,140,
- 0,0,0,0,1,0,66,36,204,0,130,172,
- 32,0,98,48,6,0,64,16,15,0,98,48,
- 208,0,130,140,0,0,0,0,1,0,66,36,
- 208,0,130,172,15,0,98,48,212,0,131,140,
- 8,0,37,141,33,24,98,0,212,0,131,172,
- 17,0,162,144,1,0,140,37,255,255,66,36,
- 17,0,162,160,25,0,64,20,37,24,46,1,
- 16,0,162,144,1,0,173,37,64,18,2,0,
- 33,64,89,0,140,0,7,141,0,129,10,52,
- 4,0,230,140,0,0,163,140,0,0,160,172,
- 12,0,170,172,4,0,197,172,12,0,239,172,
- 33,56,192,0,216,0,2,141,33,48,160,0,
- 1,0,66,36,0,128,99,48,4,0,96,20,
- 216,0,2,173,4,0,165,140,114,22,192,8,
- 0,0,0,0,140,0,7,173,37,24,46,1,
- 0,128,2,60,0,0,98,172,40,22,192,8,
- 33,72,96,1,104,0,137,172,176,0,140,172,
- 180,0,141,172,4,0,177,143,0,0,176,143,
- 8,0,224,3,8,0,189,39,224,255,189,39,
- 16,0,176,175,33,128,128,0,24,0,191,175,
- 20,0,177,175,44,0,17,142,0,0,0,0,
- 0,0,34,150,0,0,0,0,0,32,66,48,
- 89,0,64,16,0,0,0,0,2,0,34,150,
- 0,0,0,0,0,1,66,48,84,0,64,20,
- 0,0,0,0,27,22,192,12,0,0,0,0,
- 104,0,4,142,0,0,0,0,2,0,130,148,
- 0,128,3,52,255,255,66,48,75,0,67,16,
- 0,0,0,0,224,0,2,142,0,0,0,0,
- 1,0,66,36,224,0,2,174,4,0,36,174,
- 0,0,128,164,4,0,130,140,0,0,0,0,
- 0,0,64,164,0,0,2,142,0,0,0,0,
- 51,0,64,16,0,33,2,36,2,0,34,150,
- 0,0,0,0,47,0,64,16,0,33,2,36,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 2,0,34,150,0,0,0,0,211,255,64,20,
- 0,33,2,36,2,0,34,166,0,0,2,142,
- 0,0,0,0,5,0,64,16,0,0,0,0,
- 8,0,2,142,0,0,0,0,242,22,192,8,
- 0,0,64,172,164,7,192,12,0,0,0,0,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,108,0,133,140,
- 0,0,0,0,4,0,162,140,0,0,0,0,
- 4,0,67,140,104,0,130,140,0,0,0,0,
- 5,0,98,20,33,16,160,0,184,0,131,140,
- 33,16,0,0,1,0,99,36,184,0,131,172,
- 8,0,224,3,0,0,0,0,224,255,189,39,
- 16,0,176,175,33,128,128,0,28,0,191,175,
- 24,0,178,175,20,0,177,175,108,0,18,142,
- 8,1,6,142,44,0,17,142,4,0,66,142,
- 104,0,7,142,4,0,66,140,18,0,163,148,
- 172,0,4,142,0,0,0,0,6,0,71,20,
- 255,255,99,48,184,0,3,142,33,16,0,0,
- 1,0,99,36,157,23,192,8,184,0,3,174,
- 33,48,195,0,1,0,130,36,172,0,2,174,
- 8,1,6,174,8,0,162,140,4,1,3,142,
- 0,0,70,144,33,32,64,2,8,0,69,174,
- 12,0,64,174,1,0,194,48,2,0,64,16,
- 1,0,98,36,4,1,2,174,0,0,2,142,
- 0,0,0,0,35,0,64,20,0,0,0,0,
- 18,0,162,148,0,0,0,0,255,255,66,48,
- 12,0,66,174,0,0,34,150,0,0,0,0,
- 0,32,66,48,24,0,64,16,12,0,2,36,
- 2,0,34,150,0,0,0,0,0,1,66,48,
- 19,0,64,20,12,0,2,36,4,0,242,16,
- 0,0,0,0,27,22,192,12,33,32,0,2,
- 12,0,2,36,2,0,66,166,104,0,4,142,
- 0,0,0,0,0,0,128,164,4,0,130,140,
- 0,0,0,0,0,0,64,164,0,33,2,36,
- 4,0,36,174,164,7,192,12,2,0,34,166,
- 154,23,192,8,0,0,0,0,154,23,192,8,
- 2,0,130,164,0,0,34,150,0,0,0,0,
- 0,32,66,48,69,0,64,16,12,0,2,36,
- 4,0,242,16,0,0,0,0,27,22,192,12,
- 33,32,0,2,12,0,2,36,2,0,66,166,
- 104,0,4,142,0,0,0,0,0,0,128,164,
- 4,0,130,140,0,0,0,0,0,0,64,164,
- 4,0,36,174,2,0,34,150,0,0,0,0,
- 47,0,64,16,0,33,2,36,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,2,0,34,150,
- 0,0,0,0,211,255,64,20,0,33,2,36,
- 2,0,34,166,8,0,2,142,0,0,0,0,
- 154,23,192,8,0,0,64,172,2,0,66,166,
- 4,0,67,142,1,0,2,36,108,0,3,174,
- 28,0,191,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 216,255,189,39,20,0,177,175,33,136,128,0,
- 24,0,178,175,2,131,18,60,192,131,82,38,
- 28,0,179,175,0,1,19,36,32,0,191,175,
- 16,0,176,175,104,0,48,142,108,0,34,142,
- 0,0,0,0,4,0,2,22,0,0,0,0,
- 2,0,2,150,245,23,192,8,0,0,0,0,
- 2,0,2,150,0,0,0,0,7,0,66,48,
- 11,0,64,20,33,40,64,2,2,131,4,60,
- 160,131,132,36,2,131,7,60,252,131,231,36,
- 15,63,192,12,0,2,6,36,1,0,4,36,
- 33,40,64,2,188,7,192,12,0,2,6,36,
- 2,0,2,150,4,0,3,36,7,0,66,48,
- 40,0,67,20,0,128,2,52,8,0,3,142,
- 0,0,0,0,17,0,98,144,0,0,0,0,
- 255,255,66,36,17,0,98,160,17,0,98,144,
- 0,0,0,0,30,0,64,20,0,128,2,52,
- 180,0,34,142,33,32,96,0,1,0,66,36,
- 180,0,34,174,16,0,130,144,2,131,3,60,
- 192,246,99,36,64,18,2,0,33,56,67,0,
- 140,0,230,140,0,129,8,52,4,0,197,140,
- 0,0,131,140,0,0,128,172,12,0,136,172,
- 4,0,164,172,12,0,211,172,33,48,160,0,
- 216,0,226,140,33,40,128,0,1,0,66,36,
- 0,128,99,48,4,0,96,20,216,0,226,172,
- 4,0,132,140,223,23,192,8,0,0,0,0,
- 140,0,230,172,0,128,2,52,2,0,2,166,
- 0,0,0,166,4,0,16,142,174,23,192,8,
- 0,0,0,0,44,0,35,142,104,0,48,174,
- 0,0,98,148,0,0,0,0,0,32,66,52,
- 0,0,98,164,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,0,163,2,60,
- 0,1,66,52,0,0,66,140,2,131,3,60,
- 192,6,99,36,255,3,66,48,60,0,66,36,
- 0,128,66,52,8,0,224,3,0,0,98,172,
- 208,255,189,39,28,0,177,175,33,136,128,0,
- 32,0,178,175,33,144,160,0,24,0,176,175,
- 0,163,16,60,0,163,2,60,164,1,66,140,
- 0,1,16,54,44,0,191,175,40,0,180,175,
- 4,0,64,20,36,0,179,175,60,0,2,36,
- 0,163,1,60,164,1,34,172,0,163,2,60,
- 164,1,66,140,0,0,0,0,221,5,66,40,
- 3,0,64,20,220,5,2,36,0,163,1,60,
- 164,1,34,172,0,163,3,60,164,1,99,140,
- 255,255,2,36,21,0,98,20,0,0,0,0,
- 128,128,130,143,0,0,0,0,5,0,67,20,
- 2,0,5,36,130,11,192,12,0,0,0,0,
- 128,128,130,175,2,0,5,36,10,0,6,36,
- 128,128,132,143,0,131,7,60,8,96,231,36,
- 156,11,192,12,16,0,160,175,0,0,2,142,
- 2,131,3,60,192,6,99,36,255,3,66,48,
- 66,24,192,8,64,0,66,36,0,163,2,60,
- 164,1,66,140,2,131,3,60,192,6,99,36,
- 0,128,66,52,0,0,98,172,255,31,4,60,
- 255,255,132,52,2,131,2,60,208,6,66,36,
- 36,16,68,0,0,160,5,60,37,16,69,0,
- 2,131,3,60,176,12,99,36,2,131,1,60,
- 196,6,32,172,2,131,1,60,200,6,34,172,
- 12,0,2,36,0,0,96,164,2,131,1,60,
- 178,12,34,164,6,0,65,6,36,16,100,0,
- 37,16,69,0,2,131,1,60,180,12,34,172,
- 99,24,192,8,255,31,18,60,2,131,2,60,
- 178,12,66,148,0,0,0,0,0,128,66,52,
- 2,131,1,60,178,12,34,164,255,31,18,60,
- 255,255,82,54,2,131,2,60,192,6,66,36,
- 36,16,82,0,0,160,20,60,37,16,84,0,
- 2,131,1,60,184,12,34,172,2,131,1,60,
- 188,12,32,172,44,0,34,142,0,0,0,0,
- 0,0,66,148,2,131,19,60,176,12,115,38,
- 0,32,66,48,15,0,64,20,33,40,0,0,
- 2,131,4,60,160,131,132,36,2,131,16,60,
- 192,131,16,38,33,40,0,2,2,131,7,60,
- 24,132,231,36,15,63,192,12,71,2,6,36,
- 1,0,4,36,33,40,0,2,188,7,192,12,
- 71,2,6,36,33,40,0,0,33,48,0,0,
- 36,16,114,2,44,0,35,142,37,16,84,0,
- 4,0,98,172,44,0,36,142,208,7,7,36,
- 129,67,192,12,2,0,132,36,12,0,64,20,
- 0,0,0,0,44,0,34,142,0,0,0,0,
- 2,0,69,148,2,131,4,60,15,63,192,12,
- 56,132,132,36,255,255,4,36,2,131,5,60,
- 192,131,165,36,188,7,192,12,79,2,6,36,
- 44,0,34,142,0,33,3,36,2,0,67,164,
- 8,0,34,142,0,0,0,0,0,0,64,172,
- 44,0,191,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,48,0,189,39,232,255,189,39,
- 128,128,132,143,0,128,2,52,16,0,191,175,
- 2,131,1,60,3,0,128,4,178,12,34,164,
- 177,11,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 8,0,224,3,0,0,0,0,0,0,0,0,
- 0,0,0,0,240,255,2,52,2,131,1,60,
- 33,8,34,0,208,12,32,172,240,255,66,36,
- 251,255,65,4,0,0,0,0,2,131,2,60,
- 208,12,66,36,0,163,1,60,12,1,32,172,
- 0,163,1,60,212,5,34,172,1,0,2,60,
- 148,133,128,175,144,133,128,175,0,163,1,60,
- 8,0,224,3,216,5,34,172,0,0,136,148,
- 4,0,138,148,1,0,2,49,34,0,64,20,
- 2,0,137,148,0,25,10,0,38,24,106,0,
- 38,24,105,0,240,255,99,48,2,131,15,60,
- 208,12,239,37,33,40,111,0,68,133,142,143,
- 128,0,3,36,0,0,162,140,4,0,171,148,
- 23,0,64,16,43,16,194,1,9,0,64,16,
- 6,0,172,148,7,0,11,21,8,0,173,148,
- 5,0,44,21,0,0,0,0,3,0,77,21,
- 10,0,162,148,8,0,224,3,0,0,0,0,
- 255,255,99,36,10,0,96,16,240,255,165,36,
- 43,16,175,0,238,255,64,16,0,0,162,140,
- 248,127,229,37,248,127,165,36,218,24,192,8,
- 0,0,162,140,8,0,224,3,254,255,2,36,
- 8,0,224,3,255,255,2,36,8,0,224,3,
- 0,0,0,0,0,0,136,148,68,133,142,143,
- 1,0,2,49,53,0,64,20,2,0,137,148,
- 0,131,2,60,4,0,138,148,12,1,89,140,
- 0,25,10,0,38,24,106,0,38,24,105,0,
- 240,255,99,48,2,131,15,60,208,12,239,37,
- 33,56,111,0,128,0,3,36,0,0,248,140,
- 4,0,235,148,43,16,216,1,14,0,64,16,
- 6,0,236,148,24,0,11,21,8,0,237,148,
- 22,0,44,21,255,127,2,60,20,0,77,21,
- 255,255,66,52,43,16,2,3,2,0,64,16,
- 33,16,198,1,0,0,226,172,10,0,229,164,
- 8,0,224,3,0,0,2,36,3,0,0,23,
- 1,0,57,35,0,131,2,60,12,1,89,172,
- 33,16,198,1,0,0,226,172,10,0,229,164,
- 4,0,232,164,6,0,233,164,8,0,234,164,
- 8,0,224,3,1,0,2,36,255,255,99,36,
- 11,0,96,16,0,0,0,0,240,255,231,36,
- 43,16,239,0,221,255,64,16,0,0,248,140,
- 248,127,231,37,248,127,231,36,8,25,192,8,
- 0,0,248,140,8,0,224,3,0,0,2,36,
- 144,133,130,143,0,0,0,0,1,0,66,32,
- 144,133,130,175,8,0,224,3,255,255,2,36,
- 8,0,224,3,0,0,0,0,164,128,130,143,
- 0,0,0,0,7,0,130,20,232,255,189,39,
- 160,128,130,143,2,131,3,60,208,12,99,36,
- 0,17,2,0,108,25,192,8,33,16,67,0,
- 42,16,130,0,3,0,64,16,255,255,2,36,
- 164,128,128,175,160,128,130,175,164,128,130,143,
- 160,128,131,143,35,48,130,0,1,0,101,36,
- 0,16,162,40,25,0,64,16,0,25,5,0,
- 68,133,135,143,2,131,2,60,33,16,67,0,
- 208,12,66,140,0,0,0,0,43,16,226,0,
- 4,0,64,16,0,0,0,0,255,255,198,36,
- 6,0,192,16,0,16,162,40,1,0,165,36,
- 0,16,162,40,243,255,64,20,16,0,99,36,
- 0,16,162,40,7,0,64,16,0,25,5,0,
- 2,131,2,60,208,12,66,36,160,128,133,175,
- 164,128,132,175,108,25,192,8,33,16,98,0,
- 33,16,0,0,255,255,3,36,164,128,128,175,
- 160,128,131,175,8,0,224,3,24,0,189,39,
- 0,0,0,0,0,0,0,0,24,255,189,39,
- 228,0,191,175,224,0,190,175,220,0,183,175,
- 216,0,182,175,212,0,181,175,208,0,180,175,
- 204,0,179,175,200,0,178,175,196,0,177,175,
- 192,0,176,175,44,28,192,12,0,0,0,0,
- 176,128,132,39,15,63,192,12,1,0,17,36,
- 24,0,176,39,164,68,192,12,33,32,0,2,
- 24,0,162,131,0,0,0,0,137,25,192,8,
- 32,0,8,36,0,0,2,130,32,0,8,36,
- 253,255,72,16,1,0,16,38,255,255,16,38,
- 9,0,8,36,249,255,72,16,1,0,16,38,
- 255,255,16,38,0,0,2,146,0,0,0,0,
- 208,255,66,36,10,0,66,44,27,0,64,16,
- 33,32,0,2,33,40,0,0,212,68,192,12,
- 33,48,0,0,0,0,3,146,0,0,0,0,
- 208,255,99,36,10,0,99,44,9,0,96,16,
- 33,136,64,0,1,0,16,38,0,0,2,146,
- 0,0,0,0,208,255,66,36,10,0,66,44,
- 251,255,64,20,1,0,16,38,255,255,16,38,
- 0,0,2,130,32,0,8,36,253,255,72,16,
- 1,0,16,38,255,255,16,38,9,0,8,36,
- 249,255,72,16,1,0,16,38,255,255,16,38,
- 0,0,2,130,0,0,3,146,0,0,0,0,
- 22,0,64,16,104,0,180,39,32,0,8,36,
- 19,0,72,16,9,0,8,36,17,0,72,16,
- 32,0,5,36,9,0,4,36,208,255,98,36,
- 10,0,66,44,12,0,64,20,0,0,0,0,
- 1,0,16,38,0,0,131,162,0,0,2,130,
- 0,0,3,146,0,0,0,0,5,0,64,16,
- 1,0,148,38,3,0,69,16,0,0,0,0,
- 243,255,68,20,208,255,98,36,0,0,128,162,
- 104,0,180,39,0,0,2,130,32,0,8,36,
- 253,255,72,16,1,0,16,38,255,255,16,38,
- 9,0,8,36,249,255,72,16,1,0,16,38,
- 255,255,16,38,33,240,0,2,0,0,196,131,
- 0,0,0,0,32,69,192,12,144,0,190,175,
- 11,0,64,16,33,32,192,3,33,40,0,0,
- 212,68,192,12,33,48,0,0,33,152,64,0,
- 33,32,192,3,33,40,0,0,44,69,192,12,
- 16,0,6,36,232,25,192,8,33,144,64,0,
- 255,255,18,36,255,255,19,36,0,0,3,130,
- 0,0,2,146,0,0,0,0,17,0,96,16,
- 32,0,8,36,15,0,104,16,1,0,16,38,
- 255,255,16,38,32,0,4,36,0,22,2,0,
- 3,22,2,0,9,0,8,36,8,0,72,16,
- 0,0,0,0,1,0,16,38,0,0,3,130,
- 0,0,2,146,3,0,96,16,0,0,0,0,
- 246,255,100,20,0,22,2,0,0,0,2,130,
- 32,0,8,36,253,255,72,16,1,0,16,38,
- 255,255,16,38,9,0,8,36,249,255,72,16,
- 1,0,16,38,255,255,16,38,33,184,0,2,
- 33,32,224,2,33,40,0,0,212,68,192,12,
- 33,48,0,0,33,32,224,2,33,40,0,0,
- 16,0,6,36,44,69,192,12,33,176,64,0,
- 0,0,227,130,0,0,0,0,15,0,96,16,
- 33,168,64,0,32,0,8,36,12,0,104,16,
- 32,0,3,36,0,0,2,130,9,0,8,36,
- 8,0,72,16,0,0,0,0,1,0,16,38,
- 0,0,2,130,0,0,0,0,3,0,64,16,
- 0,0,0,0,248,255,67,20,0,0,0,0,
- 0,0,131,130,0,0,0,0,121,0,98,44,
- 244,1,64,16,128,16,3,0,2,131,1,60,
- 33,8,34,0,160,138,34,140,0,0,0,0,
- 8,0,64,0,0,0,0,0,1,0,131,130,
- 104,0,2,36,26,0,98,16,105,0,98,40,
- 7,0,64,16,116,0,2,36,34,0,96,16,
- 98,0,2,36,11,0,98,16,0,0,0,0,
- 26,28,192,8,0,0,0,0,5,0,98,16,
- 119,0,8,36,27,0,104,16,33,16,32,2,
- 26,28,192,8,0,0,0,0,4,162,2,60,
- 33,144,66,2,2,0,130,130,0,0,0,0,
- 214,1,64,20,0,0,0,0,2,131,4,60,
- 108,132,132,36,0,0,70,146,82,26,192,8,
- 0,0,0,0,2,0,130,130,0,0,0,0,
- 205,1,64,20,0,0,0,0,2,131,4,60,
- 120,132,132,36,0,0,70,150,0,0,0,0,
- 15,63,192,12,33,40,64,2,125,25,192,8,
- 0,0,0,0,33,16,32,2,37,255,64,16,
- 255,255,49,38,0,0,80,142,2,131,4,60,
- 132,132,132,36,33,40,64,2,4,0,82,38,
- 15,63,192,12,33,48,0,2,33,16,32,2,
- 247,255,64,20,255,255,49,38,125,25,192,8,
- 0,0,0,0,1,0,131,130,104,0,2,36,
- 23,0,98,16,105,0,98,40,7,0,64,16,
- 116,0,2,36,25,0,96,16,98,0,2,36,
- 11,0,98,16,0,0,0,0,26,28,192,8,
- 0,0,0,0,5,0,98,16,119,0,8,36,
- 17,0,104,16,0,0,0,0,26,28,192,8,
- 0,0,0,0,4,162,2,60,33,144,66,2,
- 2,0,130,130,0,0,0,0,158,1,64,20,
- 0,0,0,0,125,25,192,8,0,0,85,162,
- 2,0,130,130,0,0,0,0,152,1,64,20,
- 0,0,0,0,125,25,192,8,0,0,85,166,
- 125,25,192,8,0,0,85,174,0,163,16,60,
- 31,163,17,60,255,255,49,54,0,0,2,142,
- 0,0,0,0,4,0,82,20,0,0,0,0,
- 180,128,132,39,15,63,192,12,33,40,0,2,
- 4,0,16,38,43,16,48,2,246,255,64,16,
- 0,0,0,0,125,25,192,8,0,0,0,0,
- 33,16,32,2,228,254,64,16,255,255,49,38,
- 33,32,96,2,164,32,192,12,33,40,192,2,
- 33,16,32,2,251,255,64,20,255,255,49,38,
- 125,25,192,8,0,0,0,0,1,0,130,130,
- 0,0,0,0,117,1,64,20,33,32,32,2,
- 133,29,192,12,33,40,96,2,125,25,192,8,
- 0,0,0,0,33,32,96,2,33,40,32,2,
- 234,31,192,12,33,48,192,2,125,25,192,8,
- 0,0,0,0,1,0,130,130,0,0,0,0,
- 103,1,64,20,33,16,32,2,200,254,64,16,
- 255,255,49,38,33,32,96,2,33,40,192,2,
- 182,29,192,12,33,48,0,2,33,16,32,2,
- 250,255,64,20,255,255,49,38,125,25,192,8,
- 0,0,0,0,33,32,32,2,33,40,96,2,
- 33,48,192,2,38,30,192,12,33,56,0,2,
- 125,25,192,8,0,0,0,0,5,162,2,60,
- 0,0,69,144,2,131,4,60,15,63,192,12,
- 144,132,132,36,125,25,192,8,0,0,0,0,
- 0,163,1,60,20,1,32,172,14,0,32,18,
- 33,128,0,0,164,7,192,12,1,0,16,38,
- 143,63,192,12,0,0,0,0,143,63,192,12,
- 0,0,0,0,143,63,192,12,0,0,0,0,
- 143,63,192,12,0,0,0,0,43,16,17,2,
- 244,255,64,20,0,0,0,0,184,63,192,12,
- 0,0,0,0,0,163,16,60,20,1,16,142,
- 0,0,0,0,7,0,17,22,33,40,32,2,
- 2,131,4,60,164,132,132,36,15,63,192,12,
- 33,40,32,2,125,25,192,8,0,0,0,0,
- 2,131,4,60,188,132,132,36,15,63,192,12,
- 33,48,0,2,125,25,192,8,0,0,0,0,
- 0,0,226,130,7,162,8,60,16,0,64,16,
- 33,144,72,2,33,16,32,2,134,254,64,16,
- 255,255,49,38,0,0,85,174,2,131,4,60,
- 132,132,132,36,33,40,64,2,15,63,192,12,
- 33,48,160,2,4,0,82,38,33,16,32,2,
- 247,255,64,20,255,255,49,38,125,25,192,8,
- 0,0,0,0,33,16,32,2,119,254,64,16,
- 255,255,49,38,0,0,80,142,2,131,4,60,
- 132,132,132,36,33,40,64,2,4,0,82,38,
- 15,63,192,12,33,48,0,2,33,16,32,2,
- 247,255,64,20,255,255,49,38,125,25,192,8,
- 0,0,0,0,7,162,16,60,64,0,17,38,
- 2,131,4,60,228,132,132,36,33,40,0,2,
- 0,0,6,142,0,0,0,0,15,63,192,12,
- 4,0,16,38,42,16,17,2,247,255,64,20,
- 7,162,8,60,128,0,16,37,176,0,17,37,
- 2,131,4,60,228,132,132,36,33,40,0,2,
- 0,0,6,142,0,0,0,0,15,63,192,12,
- 4,0,16,38,42,16,17,2,247,255,64,20,
- 7,162,8,60,192,0,16,37,240,0,17,37,
- 2,131,4,60,228,132,132,36,33,40,0,2,
- 0,0,6,142,0,0,0,0,15,63,192,12,
- 4,0,16,38,42,16,17,2,247,255,64,20,
- 0,0,0,0,125,25,192,8,0,0,0,0,
- 1,0,130,130,0,0,0,0,222,0,64,20,
- 33,16,32,2,63,254,64,16,255,255,49,38,
- 33,32,96,2,213,29,192,12,33,40,160,2,
- 33,16,32,2,251,255,64,20,255,255,49,38,
- 125,25,192,8,0,0,0,0,1,0,130,130,
- 0,0,0,0,208,0,64,20,33,16,32,2,
- 49,254,64,16,255,255,49,38,33,32,96,2,
- 161,31,192,12,33,40,192,2,33,16,32,2,
- 251,255,64,20,255,255,49,38,125,25,192,8,
- 0,0,0,0,33,16,32,2,38,254,64,16,
- 255,255,49,38,208,32,192,12,33,32,0,0,
- 33,32,0,0,164,32,192,12,33,40,0,0,
- 40,29,192,12,0,0,0,0,133,29,192,12,
- 255,255,4,36,33,16,32,2,245,255,64,20,
- 255,255,49,38,125,25,192,8,0,0,0,0,
- 1,0,131,130,87,0,2,36,27,0,98,16,
- 88,0,98,40,7,0,64,16,114,0,2,36,
- 37,0,96,16,82,0,2,36,9,0,98,16,
- 0,0,0,0,125,25,192,8,0,0,0,0,
- 5,0,98,16,119,0,8,36,15,0,104,16,
- 0,0,0,0,125,25,192,8,0,0,0,0,
- 2,0,130,130,0,0,0,0,159,0,64,20,
- 0,0,0,0,60,65,192,12,33,32,96,2,
- 184,128,132,39,33,40,96,2,15,63,192,12,
- 33,48,64,0,125,25,192,8,0,0,0,0,
- 2,0,130,130,0,0,0,0,147,0,64,20,
- 33,32,96,2,162,65,192,12,33,40,160,2,
- 242,253,64,20,33,40,160,2,2,131,4,60,
- 8,133,132,36,15,63,192,12,33,48,96,2,
- 125,25,192,8,0,0,0,0,33,16,32,2,
- 233,253,64,16,255,255,49,38,40,29,192,12,
- 0,0,0,0,33,16,32,2,252,255,64,20,
- 255,255,49,38,125,25,192,8,0,0,0,0,
- 1,0,133,130,87,0,2,36,29,0,162,16,
- 88,0,162,40,5,0,64,16,82,0,2,36,
- 11,0,162,16,33,16,32,2,125,25,192,8,
- 0,0,0,0,114,0,2,36,5,0,162,16,
- 119,0,8,36,19,0,168,16,33,32,64,2,
- 125,25,192,8,0,0,0,0,33,16,32,2,
- 206,253,64,16,255,255,49,38,168,69,192,12,
- 33,32,64,2,184,128,132,39,33,40,64,2,
- 15,63,192,12,33,48,64,0,1,0,82,38,
- 33,16,32,2,247,255,64,20,255,255,49,38,
- 125,25,192,8,0,0,0,0,33,32,64,2,
- 29,70,192,12,33,40,160,2,189,253,64,20,
- 33,40,160,2,2,131,4,60,40,133,132,36,
- 15,63,192,12,33,48,64,2,125,25,192,8,
- 0,0,0,0,144,0,164,143,122,28,192,12,
- 0,0,0,0,125,25,192,8,0,0,0,0,
- 33,16,96,2,175,253,64,16,255,255,115,38,
- 143,63,192,12,0,0,0,0,33,16,96,2,
- 252,255,64,20,255,255,115,38,125,25,192,8,
- 0,0,0,0,33,16,32,2,165,253,64,16,
- 255,255,49,38,33,32,96,2,208,32,192,12,
- 33,40,192,2,33,16,32,2,251,255,64,20,
- 255,255,49,38,125,25,192,8,0,0,0,0,
- 1,0,130,146,0,0,0,0,159,255,66,36,
- 0,22,2,0,3,30,2,0,24,0,98,44,
- 27,0,64,16,128,16,3,0,2,131,1,60,
- 33,8,34,0,136,140,34,140,0,0,0,0,
- 8,0,64,0,0,0,0,0,12,33,192,12,
- 33,32,64,2,125,25,192,8,0,0,0,0,
- 15,33,192,12,33,32,96,2,125,25,192,8,
- 0,0,0,0,18,33,192,12,33,32,96,2,
- 125,25,192,8,0,0,0,0,22,33,192,12,
- 33,32,96,2,125,25,192,8,0,0,0,0,
- 25,33,192,12,33,32,64,2,125,25,192,8,
- 0,0,0,0,33,32,64,2,7,33,192,12,
- 33,40,192,2,125,25,192,8,0,0,0,0,
- 16,0,182,175,33,32,32,2,33,40,192,3,
- 33,48,224,2,161,33,192,12,33,56,160,2,
- 125,25,192,8,0,0,0,0,33,136,0,0,
- 2,131,4,60,72,133,132,36,15,63,192,12,
- 1,0,49,38,32,0,34,46,250,255,64,20,
- 0,0,0,0,125,25,192,8,0,0,0,0,
- 2,131,4,60,92,133,132,36,15,63,192,12,
- 33,40,128,2,123,25,192,8,0,0,0,0,
- 228,0,191,143,224,0,190,143,220,0,183,143,
- 216,0,182,143,212,0,181,143,208,0,180,143,
- 204,0,179,143,200,0,178,143,196,0,177,143,
- 192,0,176,143,8,0,224,3,232,0,189,39,
- 232,255,189,39,2,131,5,60,192,154,165,36,
- 20,0,191,175,16,0,176,175,0,0,162,140,
- 0,0,0,0,9,0,64,16,33,128,160,0,
- 0,0,5,142,192,128,132,39,15,63,192,12,
- 4,0,16,38,0,0,2,142,0,0,0,0,
- 249,255,64,20,0,0,0,0,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 0,0,132,144,0,0,0,0,208,255,130,36,
- 10,0,66,44,4,0,64,16,0,22,4,0,
- 3,22,2,0,89,28,192,8,208,255,66,36,
- 159,255,130,36,6,0,66,44,4,0,64,16,
- 0,22,4,0,3,22,2,0,89,28,192,8,
- 169,255,66,36,191,255,130,36,6,0,66,44,
- 3,0,64,20,0,22,4,0,89,28,192,8,
- 255,255,2,36,3,22,2,0,201,255,66,36,
- 8,0,224,3,0,0,0,0,216,255,189,39,
- 24,0,178,175,33,144,128,0,32,0,191,175,
- 28,0,179,175,20,0,177,175,16,0,176,175,
- 0,0,81,142,0,0,0,0,65,28,192,12,
- 33,32,32,2,33,24,64,0,255,255,19,36,
- 9,0,115,16,0,129,3,0,65,28,192,12,
- 1,0,36,38,33,24,64,0,4,0,115,16,
- 2,0,34,38,0,0,66,174,115,28,192,8,
- 37,16,3,2,255,255,2,36,32,0,191,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,40,0,189,39,
- 176,255,189,39,64,0,180,175,33,160,128,0,
- 72,0,191,175,68,0,181,175,60,0,179,175,
- 56,0,178,175,52,0,177,175,48,0,176,175,
- 0,0,130,130,0,0,0,0,53,0,64,20,
- 33,128,0,0,27,67,192,12,33,32,0,0,
- 1,0,4,36,27,67,192,12,33,128,64,0,
- 2,0,4,36,27,67,192,12,33,136,64,0,
- 33,24,64,0,255,255,2,36,5,0,2,18,
- 0,0,0,0,3,0,34,18,0,0,0,0,
- 6,0,98,20,255,255,2,52,2,131,4,60,
- 15,63,192,12,60,137,132,36,29,29,192,8,
- 0,0,0,0,5,0,2,18,0,0,0,0,
- 3,0,34,18,0,0,0,0,6,0,98,20,
- 1,0,2,50,2,131,4,60,15,63,192,12,
- 104,137,132,36,29,29,192,8,0,0,0,0,
- 6,0,64,16,255,0,5,50,2,131,4,60,
- 15,63,192,12,132,137,132,36,29,29,192,8,
- 0,0,0,0,2,131,4,60,176,137,132,36,
- 3,50,16,0,3,18,17,0,16,0,162,175,
- 255,0,98,48,20,0,162,175,3,18,3,0,
- 255,0,39,50,15,63,192,12,24,0,162,175,
- 29,29,192,8,0,0,0,0,40,0,180,175,
- 58,0,21,36,32,0,19,36,255,255,18,36,
- 32,0,177,39,40,0,162,143,0,0,0,0,
- 0,0,67,128,0,0,0,0,3,0,117,16,
- 0,0,0,0,3,0,115,20,0,0,0,0,
- 1,0,66,36,40,0,162,175,91,28,192,12,
- 40,0,164,39,33,24,64,0,75,0,114,16,
- 0,0,0,0,40,0,162,143,0,0,35,166,
- 0,0,67,128,0,0,0,0,3,0,117,16,
- 0,0,0,0,3,0,115,20,0,0,0,0,
- 1,0,66,36,40,0,162,175,91,28,192,12,
- 40,0,164,39,33,24,64,0,60,0,114,16,
- 1,0,16,38,0,0,34,150,0,26,3,0,
- 37,16,67,0,0,0,34,166,3,0,2,42,
- 220,255,64,20,2,0,49,38,32,0,165,151,
- 0,0,0,0,1,0,162,48,7,0,64,16,
- 0,0,0,0,2,131,4,60,208,137,132,36,
- 15,63,192,12,255,0,165,48,25,29,192,8,
- 0,0,0,0,36,0,162,151,0,0,0,0,
- 0,7,66,48,6,0,64,16,0,0,0,0,
- 2,131,4,60,15,63,192,12,0,138,132,36,
- 25,29,192,8,0,0,0,0,255,66,192,12,
- 33,32,0,0,1,0,4,36,34,0,165,151,
- 0,0,0,0,255,66,192,12,33,128,0,0,
- 36,0,165,151,0,0,0,0,255,66,192,12,
- 2,0,4,36,2,131,4,60,15,63,192,12,
- 32,138,132,36,2,131,4,60,80,138,132,36,
- 15,63,192,12,33,40,0,2,196,128,132,39,
- 200,128,134,39,31,21,192,12,32,0,165,39,
- 36,0,162,151,1,0,16,38,0,1,66,36,
- 36,0,162,167,8,0,2,42,7,0,64,16,
- 0,0,0,0,8,29,192,8,0,0,0,0,
- 2,131,4,60,116,138,132,36,15,63,192,12,
- 33,40,128,2,72,0,191,143,68,0,181,143,
- 64,0,180,143,60,0,179,143,56,0,178,143,
- 52,0,177,143,48,0,176,143,8,0,224,3,
- 80,0,189,39,0,0,0,0,0,0,0,0,
- 224,255,189,39,16,0,176,175,33,128,0,0,
- 20,0,177,175,33,136,0,0,24,0,191,175,
- 33,32,0,2,162,65,192,12,33,40,0,0,
- 43,0,64,16,0,0,0,0,1,0,16,38,
- 64,0,2,42,249,255,64,20,33,32,0,2,
- 33,128,0,0,85,85,17,36,33,32,0,2,
- 162,65,192,12,85,85,5,36,32,0,64,16,
- 0,0,0,0,1,0,16,38,64,0,2,42,
- 249,255,64,20,33,32,0,2,33,128,0,0,
- 170,170,17,52,33,32,0,2,162,65,192,12,
- 170,170,5,52,21,0,64,16,0,0,0,0,
- 1,0,16,38,64,0,2,42,249,255,64,20,
- 33,32,0,2,33,128,0,0,255,255,17,52,
- 33,32,0,2,162,65,192,12,255,255,5,52,
- 10,0,64,16,0,0,0,0,1,0,16,38,
- 64,0,2,42,249,255,64,20,33,32,0,2,
- 2,131,4,60,15,63,192,12,240,140,132,36,
- 101,29,192,8,0,0,0,0,60,65,192,12,
- 33,32,0,2,2,131,4,60,4,141,132,36,
- 33,40,32,2,33,48,0,2,15,63,192,12,
- 33,56,64,0,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 0,0,0,0,0,0,0,0,232,255,189,39,
- 16,0,191,175,210,7,192,12,0,0,0,0,
- 139,14,192,12,0,0,0,0,180,10,192,12,
- 0,0,0,0,32,133,132,143,1,0,2,36,
- 42,16,68,0,9,0,64,16,0,2,3,36,
- 64,34,4,0,2,131,1,60,33,8,35,0,
- 196,246,32,172,0,2,99,36,42,16,100,0,
- 250,255,64,20,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 208,255,189,39,24,0,178,175,33,144,128,0,
- 32,0,180,175,33,160,160,0,44,0,191,175,
- 40,0,182,175,36,0,181,175,28,0,179,175,
- 20,0,177,175,3,0,128,26,16,0,176,175,
- 149,29,192,8,1,0,147,38,1,0,20,36,
- 32,133,147,143,255,255,82,38,255,255,2,36,
- 20,0,66,18,255,255,21,36,2,131,22,60,
- 192,246,214,38,108,29,192,12,33,128,128,2,
- 42,16,19,2,10,0,64,16,64,18,16,0,
- 33,136,86,0,242,21,192,12,33,32,32,2,
- 133,12,192,12,33,32,0,2,1,0,16,38,
- 42,16,19,2,249,255,64,20,0,2,49,38,
- 255,255,82,38,240,255,85,22,0,0,0,0,
- 44,0,191,143,40,0,182,143,36,0,181,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 48,0,189,39,216,255,189,39,24,0,178,175,
- 33,144,160,0,28,0,179,175,33,152,192,0,
- 32,0,191,175,20,0,177,175,3,0,128,24,
- 16,0,176,175,195,29,192,8,1,0,145,36,
- 1,0,4,36,32,133,145,143,33,128,128,0,
- 42,16,17,2,8,0,64,16,33,32,0,2,
- 33,40,64,2,250,29,192,12,33,48,96,2,
- 1,0,16,38,42,16,17,2,250,255,64,20,
- 33,32,0,2,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,224,255,189,39,
- 24,0,191,175,20,0,177,175,3,0,128,24,
- 16,0,176,175,222,29,192,8,1,0,145,36,
- 1,0,4,36,32,133,145,143,33,128,128,0,
- 42,16,17,2,7,0,64,16,0,0,0,0,
- 237,29,192,12,33,32,0,2,1,0,16,38,
- 42,16,17,2,251,255,64,20,0,0,0,0,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,64,34,4,0,
- 2,131,2,60,192,246,66,36,33,32,130,0,
- 44,0,131,140,1,0,2,36,32,0,130,172,
- 16,0,2,36,2,0,98,164,8,0,130,140,
- 0,0,0,0,8,0,224,3,0,0,64,172,
- 208,255,189,39,33,48,128,0,64,18,6,0,
- 2,131,3,60,192,246,99,36,36,0,177,175,
- 33,136,67,0,40,0,191,175,32,0,176,175,
- 4,0,34,142,0,0,0,0,4,0,64,20,
- 33,128,160,0,1,0,4,36,133,29,192,12,
- 33,40,192,0,3,0,0,30,221,5,2,42,
- 17,30,192,8,1,0,16,36,3,0,64,20,
- 33,32,32,2,220,5,16,36,33,32,32,2,
- 208,7,5,36,108,0,131,140,12,0,2,36,
- 2,0,98,164,16,0,162,39,8,0,98,172,
- 0,128,2,54,12,0,96,172,16,0,162,175,
- 255,255,2,36,20,0,162,175,2,131,2,60,
- 0,155,66,36,98,31,192,12,24,0,162,175,
- 40,0,191,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,48,0,189,39,56,254,189,39,
- 160,1,176,175,33,128,192,0,48,1,164,175,
- 33,32,224,0,64,18,5,0,2,131,3,60,
- 192,246,99,36,33,16,67,0,56,1,162,175,
- 64,18,16,0,33,16,67,0,40,0,168,39,
- 196,1,191,175,192,1,190,175,188,1,183,175,
- 184,1,182,175,180,1,181,175,176,1,180,175,
- 172,1,179,175,168,1,178,175,164,1,177,175,
- 64,1,162,175,12,0,160,24,96,1,168,175,
- 32,133,131,143,0,0,0,0,42,16,163,0,
- 19,1,64,16,1,0,2,36,5,0,0,26,
- 42,16,3,2,15,1,64,16,1,0,2,36,
- 3,0,176,20,33,40,0,0,86,31,192,8,
- 1,0,2,36,212,68,192,12,33,48,0,0,
- 6,0,65,4,104,1,162,175,33,72,64,0,
- 35,72,9,0,104,1,169,175,87,30,192,8,
- 112,1,160,175,1,0,8,36,112,1,168,175,
- 1,0,4,36,133,29,192,12,33,40,0,0,
- 237,29,192,12,33,32,0,2,24,0,169,39,
- 56,1,168,143,255,0,2,36,80,1,169,175,
- 108,0,8,141,43,1,163,39,72,1,168,175,
- 0,0,98,160,255,255,66,36,253,255,65,4,
- 255,255,99,36,64,1,169,143,0,0,0,0,
- 120,0,41,141,64,1,168,143,128,1,169,175,
- 124,0,8,141,64,1,169,143,136,1,168,175,
- 44,0,34,141,0,0,0,0,12,0,64,172,
- 44,0,34,141,0,0,0,0,16,0,64,172,
- 44,0,34,141,120,1,160,175,32,0,64,172,
- 44,0,34,141,88,1,160,175,24,0,64,172,
- 48,1,168,143,0,0,0,0,168,0,0,25,
- 40,0,169,39,144,1,169,175,88,1,168,143,
- 0,0,0,0,255,0,2,49,4,0,86,36,
- 60,0,194,42,2,0,64,16,0,0,0,0,
- 60,0,22,36,104,1,169,143,0,0,0,0,
- 2,0,32,17,0,0,0,0,104,1,182,143,
- 56,1,164,143,72,1,168,143,12,0,2,36,
- 2,0,2,165,80,1,169,143,0,128,194,54,
- 8,0,9,173,12,0,0,173,0,0,34,173,
- 255,255,8,36,4,0,40,173,144,1,168,143,
- 0,0,0,0,8,0,40,173,88,1,168,143,
- 96,1,169,143,208,7,5,36,98,31,192,12,
- 0,0,40,173,0,128,5,52,0,128,6,52,
- 128,1,164,143,0,0,0,0,129,67,192,12,
- 2,0,7,36,13,0,64,20,0,0,0,0,
- 88,1,165,143,2,131,4,60,15,63,192,12,
- 64,141,132,36,120,1,169,143,0,0,0,0,
- 1,0,41,37,20,0,34,41,117,0,64,16,
- 120,1,169,175,32,31,192,8,0,0,0,0,
- 128,1,168,143,64,1,169,143,8,0,2,141,
- 255,255,8,36,136,0,53,141,0,0,0,0,
- 50,0,72,16,33,184,0,0,1,0,4,36,
- 4,0,18,36,4,0,3,36,0,0,190,142,
- 8,0,166,142,112,1,169,143,255,63,212,51,
- 30,0,32,17,33,184,244,2,42,16,116,0,
- 27,0,64,16,33,152,96,0,144,1,168,143,
- 0,0,0,0,33,136,72,2,33,128,102,0,
- 15,0,128,16,0,0,0,0,0,0,2,146,
- 0,0,35,146,0,0,0,0,10,0,67,16,
- 33,48,192,2,2,131,4,60,92,141,132,36,
- 88,1,165,143,16,0,163,175,0,0,2,146,
- 33,56,64,2,15,63,192,12,20,0,162,175,
- 33,32,0,0,1,0,115,38,1,0,16,38,
- 1,0,49,38,42,16,116,2,235,255,64,20,
- 1,0,82,38,33,24,0,0,4,0,181,142,
- 0,128,194,51,217,255,64,16,0,0,0,0,
- 128,1,169,143,0,0,0,0,8,0,34,141,
- 0,0,0,0,25,0,128,16,18,0,87,164,
- 9,0,246,18,33,48,192,2,2,131,4,60,
- 140,141,132,36,88,1,165,143,0,0,0,0,
- 15,63,192,12,33,56,224,2,5,31,192,8,
- 0,0,0,0,64,1,168,143,0,0,0,0,
- 136,0,2,141,96,1,169,143,8,0,70,140,
- 0,0,34,141,0,0,198,140,0,0,0,0,
- 7,0,194,16,0,0,0,0,88,1,165,143,
- 2,131,4,60,15,63,192,12,184,141,132,36,
- 64,1,168,143,0,0,0,0,136,0,4,141,
- 152,21,192,12,0,0,0,0,64,1,169,143,
- 0,0,0,0,136,0,53,173,128,1,168,143,
- 8,128,2,52,0,0,0,165,2,0,2,165,
- 8,0,0,173,12,0,0,165,136,1,169,143,
- 8,0,2,36,2,0,34,165,4,0,40,141,
- 128,1,169,143,136,1,168,175,4,0,41,141,
- 64,1,168,143,128,1,169,175,120,0,9,173,
- 136,1,169,143,0,0,0,0,124,0,9,173,
- 88,1,168,143,48,1,169,143,1,0,8,37,
- 42,16,9,1,91,255,64,20,88,1,168,175,
- 64,1,168,143,0,0,0,0,44,0,3,141,
- 0,0,0,0,12,0,98,140,0,0,0,0,
- 5,0,64,16,0,0,0,0,12,0,101,140,
- 2,131,4,60,15,63,192,12,212,141,132,36,
- 64,1,169,143,0,0,0,0,44,0,35,141,
- 0,0,0,0,16,0,98,140,0,0,0,0,
- 5,0,64,16,0,0,0,0,16,0,101,140,
- 2,131,4,60,15,63,192,12,240,141,132,36,
- 64,1,168,143,0,0,0,0,44,0,3,141,
- 0,0,0,0,32,0,98,140,0,0,0,0,
- 5,0,64,16,0,0,0,0,32,0,101,140,
- 2,131,4,60,15,63,192,12,16,142,132,36,
- 64,1,169,143,0,0,0,0,44,0,35,141,
- 0,0,0,0,24,0,98,140,0,0,0,0,
- 5,0,64,16,0,0,0,0,24,0,101,140,
- 2,131,4,60,15,63,192,12,48,142,132,36,
- 196,1,191,143,192,1,190,143,188,1,183,143,
- 184,1,182,143,180,1,181,143,176,1,180,143,
- 172,1,179,143,168,1,178,143,164,1,177,143,
- 160,1,176,143,8,0,224,3,200,1,189,39,
- 224,255,189,39,16,0,176,175,33,128,128,0,
- 24,0,191,175,20,0,177,175,44,0,4,142,
- 0,0,0,0,0,0,130,148,0,0,0,0,
- 0,32,66,48,7,0,64,20,33,136,160,0,
- 0,0,133,148,2,131,4,60,15,63,192,12,
- 80,142,132,36,156,31,192,8,3,0,2,36,
- 2,0,132,36,33,40,0,0,33,48,0,0,
- 129,67,192,12,33,56,32,2,13,0,64,16,
- 33,40,0,0,44,0,3,142,0,33,2,36,
- 2,0,98,164,8,0,2,142,33,48,0,0,
- 0,0,64,172,44,0,4,142,33,56,32,2,
- 129,67,192,12,2,0,132,36,9,0,64,20,
- 0,32,5,36,44,0,2,142,0,0,0,0,
- 2,0,69,148,2,131,4,60,15,63,192,12,
- 108,142,132,36,156,31,192,8,1,0,2,36,
- 44,0,4,142,0,32,6,36,129,67,192,12,
- 33,56,32,2,8,0,64,20,33,16,0,0,
- 44,0,2,142,0,0,0,0,0,0,69,148,
- 2,131,4,60,15,63,192,12,132,142,132,36,
- 2,0,2,36,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 224,255,189,39,24,0,178,175,33,144,160,0,
- 28,0,191,175,20,0,177,175,7,0,128,4,
- 16,0,176,175,24,133,130,143,0,0,0,0,
- 255,255,66,36,42,16,68,0,4,0,64,16,
- 33,136,128,0,24,133,130,143,33,32,0,0,
- 255,255,81,36,33,128,128,0,42,16,48,2,
- 7,0,64,20,33,32,0,2,193,31,192,12,
- 33,40,64,2,1,0,16,38,42,16,48,2,
- 251,255,64,16,33,32,0,2,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,8,0,224,3,
- 0,0,0,0,232,255,189,39,16,0,191,175,
- 236,63,192,12,1,16,4,36,85,0,2,36,
- 131,131,1,60,128,18,34,160,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 216,255,189,39,28,0,177,175,33,136,128,0,
- 32,0,178,175,33,144,160,0,212,128,132,39,
- 36,0,191,175,15,63,192,12,24,0,176,175,
- 9,0,64,26,33,128,0,0,0,0,37,146,
- 1,0,49,38,220,128,132,39,15,63,192,12,
- 1,0,16,38,42,16,18,2,249,255,64,20,
- 0,0,0,0,228,128,132,39,15,63,192,12,
- 0,0,0,0,36,0,191,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 40,0,189,39,48,255,189,39,33,56,128,0,
- 192,0,178,175,33,144,160,0,200,0,180,175,
- 33,160,192,0,255,255,226,36,6,0,66,44,
- 204,0,191,175,196,0,179,175,188,0,177,175,
- 2,0,64,20,184,0,176,175,1,0,7,36,
- 2,0,64,30,0,0,0,0,1,0,18,36,
- 2,0,128,30,64,18,7,0,60,0,20,36,
- 2,131,3,60,192,246,99,36,33,136,67,0,
- 4,0,34,142,0,0,0,0,4,0,64,20,
- 33,152,64,2,1,0,4,36,133,29,192,12,
- 33,40,224,0,255,31,4,60,255,255,132,52,
- 0,128,133,54,120,0,162,39,36,16,68,0,
- 0,160,3,60,37,16,67,0,104,0,165,175,
- 108,0,160,175,112,0,162,175,12,0,2,36,
- 80,0,160,167,82,0,162,167,80,0,162,39,
- 36,16,68,0,37,128,67,0,104,0,162,39,
- 36,16,68,0,232,128,132,143,37,16,67,0,
- 84,0,176,175,88,0,162,175,92,0,160,175,
- 5,0,128,16,4,0,2,36,82,0,162,167,
- 255,255,2,36,92,0,165,175,88,0,162,175,
- 44,0,34,142,0,0,0,0,0,0,66,148,
- 0,0,0,0,0,32,66,48,7,0,64,20,
- 33,40,0,0,255,255,4,36,2,131,5,60,
- 184,142,165,36,188,7,192,12,208,1,6,36,
- 33,40,0,0,44,0,34,142,33,48,0,0,
- 4,0,80,172,44,0,36,142,208,7,7,36,
- 129,67,192,12,2,0,132,36,12,0,64,20,
- 0,0,0,0,44,0,34,142,0,0,0,0,
- 2,0,69,148,2,131,4,60,15,63,192,12,
- 108,142,132,36,255,255,4,36,2,131,5,60,
- 184,142,165,36,188,7,192,12,216,1,6,36,
- 34,11,192,12,1,0,4,36,0,163,16,60,
- 4,1,16,142,0,163,2,60,4,1,66,140,
- 0,0,0,0,252,255,2,18,0,33,3,36,
- 44,0,34,142,0,0,0,0,2,0,67,164,
- 8,0,34,142,0,0,0,0,0,0,64,172,
- 0,163,16,60,4,1,16,142,44,0,36,142,
- 0,0,0,0,4,0,130,140,0,0,0,0,
- 0,0,66,148,0,0,0,0,0,128,66,48,
- 10,0,64,20,0,0,0,0,44,0,35,142,
- 0,0,0,0,4,0,98,140,0,0,0,0,
- 0,0,66,148,0,0,0,0,0,128,66,48,
- 250,255,64,16,0,0,0,0,255,255,115,38,
- 19,0,96,18,33,40,64,2,44,0,35,142,
- 0,0,0,0,4,0,98,140,0,0,0,0,
- 0,0,66,148,0,0,0,0,0,128,66,48,
- 229,255,64,16,0,0,0,0,4,0,98,140,
- 0,0,0,0,0,0,66,148,0,0,0,0,
- 0,128,66,48,250,255,64,20,0,0,0,0,
- 89,32,192,8,0,0,0,0,2,131,4,60,
- 200,142,132,36,33,48,128,2,0,163,3,60,
- 4,1,99,140,0,128,2,52,82,0,162,167,
- 35,128,112,0,15,63,192,12,33,56,0,2,
- 19,0,0,18,64,41,18,0,35,40,178,0,
- 128,40,5,0,33,40,178,0,192,40,5,0,
- 26,0,176,0,2,0,0,22,0,0,0,0,
- 13,0,7,0,255,255,1,36,4,0,1,22,
- 0,128,1,60,2,0,161,20,0,0,0,0,
- 13,0,6,0,18,40,0,0,236,128,132,39,
- 15,63,192,12,0,0,0,0,204,0,191,143,
- 200,0,180,143,196,0,179,143,192,0,178,143,
- 188,0,177,143,184,0,176,143,8,0,224,3,
- 208,0,189,39,224,255,189,39,20,0,177,175,
- 33,136,128,0,24,0,191,175,180,10,192,12,
- 16,0,176,175,34,11,192,12,1,0,4,36,
- 16,133,132,143,0,163,16,60,4,1,16,142,
- 193,63,192,12,0,0,0,0,0,163,2,60,
- 4,1,66,140,0,0,0,0,35,40,80,0,
- 73,252,162,36,99,0,66,44,4,0,64,16,
- 0,0,0,0,2,131,4,60,196,32,192,8,
- 0,143,132,36,5,0,160,20,0,0,0,0,
- 2,131,4,60,36,143,132,36,196,32,192,8,
- 33,40,0,0,2,131,4,60,76,143,132,36,
- 15,63,192,12,1,0,16,36,3,0,48,18,
- 0,0,0,0,34,11,192,12,33,32,0,0,
- 0,129,144,175,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 200,255,189,39,32,0,178,175,33,144,128,0,
- 33,48,64,2,44,0,181,175,1,131,21,60,
- 60,252,181,38,33,56,160,2,40,0,180,175,
- 2,131,20,60,144,143,148,38,36,0,179,175,
- 0,163,19,60,120,1,115,142,0,163,3,60,
- 120,1,99,140,32,131,2,60,48,0,191,175,
- 28,0,177,175,24,0,176,175,16,0,180,175,
- 33,32,96,2,35,136,67,0,84,64,192,12,
- 33,40,32,2,3,0,64,18,33,128,64,0,
- 10,0,0,22,0,0,0,0,16,0,180,175,
- 33,32,96,2,33,40,32,2,33,48,64,2,
- 244,63,192,12,33,56,160,2,33,128,2,2,
- 5,0,0,18,33,40,96,2,2,131,4,60,
- 168,143,132,36,252,32,192,8,33,40,96,2,
- 2,131,4,60,204,143,132,36,15,63,192,12,
- 33,48,177,0,48,0,191,143,44,0,181,143,
- 40,0,180,143,36,0,179,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 56,0,189,39,0,163,1,60,232,5,36,172,
- 0,163,1,60,8,0,224,3,236,5,37,172,
- 28,129,132,175,8,0,224,3,0,0,0,0,
- 16,129,132,175,8,0,224,3,0,0,0,0,
- 15,0,132,48,20,129,132,175,8,0,224,3,
- 0,0,0,0,24,129,132,175,8,0,224,3,
- 0,0,0,0,32,129,132,175,8,0,224,3,
- 0,0,0,0,33,72,128,0,33,80,160,0,
- 33,88,192,0,7,162,4,60,48,1,132,52,
- 7,162,8,60,0,1,8,53,20,129,130,143,
- 24,129,131,143,128,48,2,0,28,129,130,143,
- 3,0,197,52,2,0,96,16,0,0,130,172,
- 67,0,197,52,16,129,130,143,0,0,0,0,
- 2,0,64,16,33,24,160,0,0,1,99,52,
- 36,129,130,143,0,0,0,0,2,0,64,16,
- 0,0,0,0,0,4,99,52,32,129,130,143,
- 0,0,3,173,3,0,64,16,7,162,5,60,
- 0,0,2,173,7,162,5,60,4,1,165,52,
- 7,162,6,60,8,1,198,52,255,0,2,60,
- 255,255,66,52,7,162,3,60,12,1,99,52,
- 7,162,4,60,16,1,132,52,36,16,66,1,
- 0,0,169,172,0,0,194,172,43,16,7,0,
- 192,16,2,0,0,0,107,172,8,0,224,3,
- 0,0,130,172,7,162,3,60,40,1,99,52,
- 3,0,2,36,0,163,1,60,20,1,32,172,
- 8,0,224,3,0,0,98,172,232,255,189,39,
- 16,0,191,175,33,24,0,0,7,162,6,60,
- 40,1,198,52,15,0,4,60,63,66,132,52,
- 0,0,197,140,0,0,0,0,16,0,162,48,
- 7,0,64,20,1,0,99,36,42,16,131,0,
- 249,255,64,16,0,0,0,0,2,131,4,60,
- 122,33,192,8,240,143,132,36,36,129,130,143,
- 0,0,0,0,3,0,64,20,33,24,0,0,
- 125,33,192,8,33,16,0,0,1,0,5,36,
- 15,0,4,60,63,66,132,52,0,163,2,60,
- 20,1,66,140,0,0,0,0,247,255,69,16,
- 1,0,99,36,42,16,131,0,249,255,64,16,
- 0,0,0,0,0,163,5,60,20,1,165,140,
- 2,131,4,60,24,144,132,36,15,63,192,12,
- 0,0,0,0,1,0,2,36,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 224,255,189,39,24,0,191,175,33,72,192,0,
- 255,31,3,60,255,255,99,52,33,64,0,0,
- 36,32,131,0,0,160,2,60,37,32,130,0,
- 36,40,163,0,16,0,32,25,37,40,162,0,
- 0,0,134,144,0,0,167,144,0,0,0,0,
- 7,0,199,16,1,0,165,36,2,131,4,60,
- 72,144,132,36,15,63,192,12,33,40,0,1,
- 157,33,192,8,1,0,2,36,1,0,8,37,
- 42,16,9,1,242,255,64,20,1,0,132,36,
- 33,16,0,0,24,0,191,143,32,0,189,39,
- 8,0,224,3,0,0,0,0,0,163,2,60,
- 232,5,66,140,152,255,189,39,80,0,180,175,
- 120,0,180,143,64,0,176,175,33,128,160,0,
- 68,0,177,175,33,136,192,0,72,0,178,175,
- 33,144,224,0,100,0,191,175,96,0,190,175,
- 92,0,183,175,88,0,182,175,84,0,181,175,
- 76,0,179,175,12,0,64,16,16,0,164,175,
- 0,163,2,60,236,5,66,140,0,0,0,0,
- 7,0,64,16,0,0,0,0,0,163,2,60,
- 236,5,66,140,0,0,0,0,1,8,66,44,
- 10,0,64,20,16,0,2,60,0,163,5,60,
- 232,5,165,140,0,163,6,60,236,5,198,140,
- 2,131,4,60,15,63,192,12,124,144,132,36,
- 7,35,192,8,0,0,0,0,16,0,168,143,
- 0,0,0,0,43,16,72,0,6,0,64,16,
- 0,0,0,0,2,131,4,60,15,63,192,12,
- 172,144,132,36,7,35,192,8,0,0,0,0,
- 224,132,130,143,0,0,0,0,11,0,64,20,
- 0,0,0,0,0,163,4,60,236,5,132,140,
- 13,8,192,12,0,0,0,0,255,31,3,60,
- 255,255,99,52,36,16,67,0,0,160,3,60,
- 37,16,67,0,224,132,130,175,228,132,130,143,
- 0,0,0,0,11,0,64,20,0,0,0,0,
- 0,163,4,60,236,5,132,140,13,8,192,12,
- 0,0,0,0,255,31,3,60,255,255,99,52,
- 36,16,67,0,0,160,3,60,37,16,67,0,
- 228,132,130,175,224,132,133,143,0,163,6,60,
- 232,5,198,140,228,132,135,143,2,131,4,60,
- 15,63,192,12,208,144,132,36,16,129,133,143,
- 20,129,134,143,2,131,4,60,15,63,192,12,
- 8,145,132,36,7,162,2,60,232,0,66,52,
- 0,0,83,140,1,0,3,130,105,0,2,36,
- 7,0,98,20,251,255,2,60,1,0,2,36,
- 36,129,130,175,4,0,2,60,0,8,66,52,
- 10,34,192,8,37,152,98,2,36,129,128,175,
- 255,247,66,52,36,152,98,2,7,162,2,60,
- 232,0,66,52,0,0,83,172,0,0,5,130,
- 114,0,2,36,3,0,162,16,82,0,2,36,
- 3,0,162,20,119,0,2,36,42,34,192,8,
- 33,176,0,0,3,0,162,16,87,0,2,36,
- 3,0,162,20,108,0,2,36,42,34,192,8,
- 1,0,22,36,3,0,162,16,76,0,2,36,
- 3,0,162,20,116,0,2,36,42,34,192,8,
- 2,0,22,36,118,0,162,16,84,0,2,36,
- 116,0,162,16,0,0,0,0,2,131,4,60,
- 15,63,192,12,52,145,132,36,7,35,192,8,
- 0,0,0,0,0,0,38,130,0,0,0,0,
- 12,0,192,16,99,0,2,36,3,0,194,16,
- 67,0,2,36,4,0,194,20,33,152,0,0,
- 5,0,19,36,61,34,192,8,5,0,21,36,
- 2,131,1,60,80,155,50,160,61,34,192,8,
- 33,168,0,0,33,168,0,0,5,0,19,36,
- 2,131,1,60,80,155,32,160,16,0,168,143,
- 0,163,18,60,236,5,82,142,0,0,0,0,
- 197,0,0,17,255,255,20,37,255,255,194,38,
- 2,0,87,44,2,0,30,36,33,128,160,2,
- 42,16,112,2,73,0,64,20,0,0,0,0,
- 42,0,224,18,5,0,2,36,13,0,2,22,
- 0,0,0,0,25,0,64,26,33,136,0,0,
- 224,132,130,143,0,0,0,0,33,16,81,0,
- 0,0,81,160,1,0,49,38,42,16,50,2,
- 249,255,64,20,33,48,64,2,105,34,192,8,
- 0,0,0,0,2,131,3,60,33,24,112,0,
- 80,155,99,144,0,0,0,0,9,0,64,26,
- 33,136,0,0,224,132,130,143,0,0,0,0,
- 33,16,81,0,1,0,49,38,0,0,67,160,
- 42,16,50,2,249,255,64,20,0,0,0,0,
- 33,48,64,2,0,163,4,60,232,5,132,140,
- 224,132,133,143,0,0,0,0,28,33,192,12,
- 1,0,7,36,76,33,192,12,0,0,0,0,
- 83,33,192,12,0,0,0,0,147,0,64,20,
- 0,0,0,0,3,0,192,18,33,48,64,2,
- 22,0,222,22,0,0,0,0,0,163,4,60,
- 232,5,132,140,228,132,133,143,0,0,0,0,
- 28,33,192,12,33,56,0,0,76,33,192,12,
- 0,0,0,0,83,33,192,12,0,0,0,0,
- 131,0,64,20,0,0,0,0,8,0,222,22,
- 0,0,0,0,224,132,132,143,228,132,133,143,
- 0,0,0,0,129,33,192,12,33,48,64,2,
- 122,0,64,20,0,0,0,0,1,0,16,38,
- 42,16,112,2,185,255,64,16,0,0,0,0,
- 255,255,148,38,255,255,2,36,178,255,130,22,
- 33,128,160,2,7,35,192,8,0,0,0,0,
- 180,10,192,12,0,0,0,0,34,11,192,12,
- 1,0,4,36,0,0,34,130,0,0,0,0,
- 6,0,64,16,33,184,0,0,24,0,160,175,
- 2,131,1,60,88,155,52,164,171,34,192,8,
- 33,176,0,0,6,0,23,36,4,0,2,36,
- 24,0,160,175,2,131,1,60,88,155,34,164,
- 33,176,0,0,0,8,30,36,24,0,177,143,
- 0,0,0,0,42,16,241,2,83,0,64,20,
- 64,16,17,0,2,131,8,60,88,155,8,37,
- 33,168,72,0,0,0,178,150,0,0,0,0,
- 26,0,210,3,2,0,64,22,0,0,0,0,
- 13,0,7,0,255,255,1,36,4,0,65,22,
- 0,128,1,60,2,0,193,23,0,0,0,0,
- 13,0,6,0,18,16,0,0,16,0,168,143,
- 0,0,0,0,24,0,72,0,33,56,192,2,
- 33,128,0,0,0,163,19,60,4,1,115,142,
- 0,163,4,60,232,5,132,140,224,132,133,143,
- 18,160,0,0,0,0,0,0,0,0,0,0,
- 28,33,192,12,33,48,64,2,10,0,128,26,
- 0,0,0,0,76,33,192,12,0,0,0,0,
- 83,33,192,12,0,0,0,0,48,0,64,20,
- 1,0,16,38,42,16,20,2,248,255,64,20,
- 0,0,0,0,2,131,5,60,140,145,165,36,
- 0,163,16,60,4,1,16,142,3,0,192,18,
- 0,0,0,0,2,131,5,60,128,145,165,36,
- 2,131,4,60,96,145,132,36,15,63,192,12,
- 33,48,64,2,19,0,19,18,24,0,146,2,
- 18,24,0,0,35,16,19,2,0,0,0,0,
- 27,0,98,0,2,0,64,20,0,0,0,0,
- 13,0,7,0,18,16,0,0,2,131,4,60,
- 152,145,132,36,64,41,2,0,35,40,162,0,
- 128,40,5,0,33,40,162,0,15,63,192,12,
- 192,40,5,0,255,34,192,8,2,0,181,38,
- 2,131,4,60,168,145,132,36,15,63,192,12,
- 2,0,181,38,1,0,49,38,42,16,241,2,
- 178,255,64,16,0,0,0,0,1,0,214,38,
- 2,0,194,42,166,255,64,20,0,0,0,0,
- 100,0,191,143,96,0,190,143,92,0,183,143,
- 88,0,182,143,84,0,181,143,80,0,180,143,
- 76,0,179,143,72,0,178,143,68,0,177,143,
- 64,0,176,143,8,0,224,3,104,0,189,39,
- 0,0,0,0,43,16,134,0,0,0,164,175,
- 4,0,165,175,8,0,166,175,7,0,64,20,
- 12,0,167,175,43,16,196,0,5,0,64,20,
- 1,0,2,36,43,16,167,0,2,0,64,16,
- 43,16,229,0,255,255,2,36,8,0,224,3,
- 0,0,0,0,232,255,189,39,3,131,4,60,
- 208,12,132,36,170,0,5,36,16,0,191,175,
- 144,71,192,12,60,0,6,36,2,131,6,60,
- 112,155,198,36,2,131,2,60,212,246,66,140,
- 2,131,3,60,216,246,99,132,0,0,194,172,
- 4,0,195,164,2,131,2,60,138,155,66,148,
- 2,131,3,60,132,155,99,148,2,131,4,60,
- 134,155,132,148,2,131,5,60,136,155,165,148,
- 3,131,1,60,216,12,34,164,2,131,2,60,
- 130,155,66,148,3,131,10,60,218,12,74,37,
- 3,0,199,136,0,0,199,152,4,0,200,128,
- 5,0,201,128,3,0,71,169,0,0,71,185,
- 4,0,72,161,5,0,73,161,3,131,1,60,
- 238,12,35,164,3,131,1,60,242,12,36,164,
- 3,131,1,60,246,12,37,164,3,131,1,60,
- 240,12,34,164,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,3,131,2,60,
- 216,12,66,140,3,131,3,60,220,12,99,140,
- 3,131,1,60,208,12,34,172,3,131,1,60,
- 212,12,35,172,3,131,2,60,238,12,66,148,
- 3,131,3,60,240,12,99,148,3,131,4,60,
- 242,12,132,148,232,255,189,39,16,0,176,175,
- 3,131,1,60,234,12,35,164,24,133,131,143,
- 20,0,191,175,3,131,1,60,224,12,32,172,
- 3,131,1,60,228,12,32,172,3,131,1,60,
- 248,12,32,172,3,131,1,60,252,12,32,172,
- 3,131,1,60,8,13,32,164,3,131,1,60,
- 4,13,32,164,3,131,1,60,232,12,34,164,
- 33,16,68,0,3,131,1,60,236,12,36,164,
- 3,131,1,60,244,12,34,164,8,0,96,24,
- 1,0,16,36,150,35,192,12,33,32,0,2,
- 24,133,130,143,1,0,16,38,42,16,80,0,
- 250,255,64,16,0,0,0,0,206,35,192,12,
- 0,0,0,0,52,36,192,12,0,0,0,0,
- 1,0,2,36,3,131,1,60,0,13,34,164,
- 3,0,2,36,3,131,1,60,2,13,32,164,
- 3,131,1,60,20,13,34,172,2,131,1,60,
- 164,247,34,172,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,224,255,189,39,
- 20,0,177,175,33,136,128,0,16,0,176,175,
- 192,129,17,0,3,131,4,60,16,13,132,36,
- 33,32,4,2,187,0,5,36,24,0,191,175,
- 144,71,192,12,128,0,6,36,2,131,2,60,
- 140,155,66,148,100,0,3,36,3,131,1,60,
- 33,8,48,0,24,13,35,172,0,18,2,0,
- 37,16,34,2,3,131,1,60,33,8,48,0,
- 16,13,34,164,22,36,192,12,33,32,32,2,
- 4,0,2,36,64,138,17,0,3,131,1,60,
- 33,8,48,0,20,13,34,172,2,131,1,60,
- 33,8,49,0,164,247,34,172,3,131,1,60,
- 33,8,48,0,52,13,32,172,3,131,1,60,
- 33,8,48,0,56,13,32,172,3,131,1,60,
- 33,8,48,0,106,13,32,164,3,131,1,60,
- 33,8,48,0,110,13,32,164,3,131,1,60,
- 33,8,48,0,114,13,32,164,3,131,1,60,
- 33,8,48,0,120,13,32,172,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,24,133,130,143,216,255,189,39,
- 20,0,177,175,1,0,17,36,36,0,191,175,
- 32,0,180,175,28,0,179,175,24,0,178,175,
- 55,0,64,24,16,0,176,175,3,131,20,60,
- 228,12,148,38,3,131,2,60,56,13,66,36,
- 128,0,83,36,124,0,82,36,128,0,16,36,
- 0,0,130,142,0,0,0,0,6,0,34,22,
- 33,32,32,2,0,0,64,174,101,36,192,12,
- 0,0,96,174,8,36,192,8,128,0,115,38,
- 3,131,4,60,33,32,144,0,40,13,132,140,
- 3,131,5,60,33,40,176,0,44,13,165,140,
- 244,255,134,142,248,255,135,142,20,35,192,12,
- 0,0,0,0,17,0,64,20,33,32,32,2,
- 3,131,3,60,33,24,112,0,48,13,99,148,
- 3,131,2,60,33,16,80,0,16,13,66,148,
- 0,0,0,0,8,0,98,20,0,0,0,0,
- 3,131,1,60,33,8,48,0,106,13,32,164,
- 101,36,192,12,33,32,32,2,8,36,192,8,
- 128,0,115,38,0,0,64,174,125,36,192,12,
- 0,0,96,174,128,0,115,38,128,0,82,38,
- 24,133,130,143,1,0,49,38,42,16,81,0,
- 210,255,64,16,128,0,16,38,36,0,191,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,192,33,4,0,3,131,2,60,
- 28,13,66,36,33,24,130,0,3,131,5,60,
- 208,12,165,140,3,131,6,60,212,12,198,140,
- 0,0,101,172,4,0,102,172,12,0,66,36,
- 3,131,3,60,224,12,99,140,33,16,130,0,
- 3,131,1,60,33,8,36,0,36,13,35,172,
- 3,131,3,60,216,12,99,140,3,131,5,60,
- 220,12,165,140,0,0,67,172,4,0,69,172,
- 3,131,2,60,33,16,68,0,16,13,66,148,
- 3,131,1,60,33,8,36,0,8,0,224,3,
- 48,13,34,164,24,133,130,143,224,255,189,39,
- 20,0,177,175,1,0,17,36,24,0,191,175,
- 38,0,64,24,16,0,176,175,128,0,16,36,
- 3,131,4,60,33,32,144,0,40,13,132,140,
- 3,131,5,60,33,40,176,0,44,13,165,140,
- 3,131,6,60,216,12,198,140,3,131,7,60,
- 220,12,231,140,20,35,192,12,0,0,0,0,
- 18,0,64,20,0,0,0,0,3,131,3,60,
- 33,24,112,0,48,13,99,148,3,131,2,60,
- 33,16,80,0,16,13,66,148,0,0,0,0,
- 9,0,98,20,0,0,0,0,3,131,2,60,
- 33,16,80,0,20,13,66,140,0,0,0,0,
- 3,0,64,16,0,0,0,0,203,36,192,12,
- 33,32,32,2,24,133,130,143,1,0,49,38,
- 42,16,81,0,221,255,64,16,128,0,16,38,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,192,41,4,0,
- 3,131,3,60,33,24,101,0,20,13,99,140,
- 4,0,2,36,16,0,98,20,240,255,189,39,
- 1,0,2,36,64,26,4,0,3,131,1,60,
- 33,8,37,0,20,13,34,172,2,131,1,60,
- 33,8,35,0,164,247,34,172,1,0,2,36,
- 3,131,1,60,33,8,37,0,110,13,34,164,
- 3,131,1,60,33,8,37,0,112,13,32,164,
- 8,0,224,3,16,0,189,39,224,255,189,39,
- 24,0,178,175,33,144,128,0,16,0,176,175,
- 192,129,18,0,28,0,191,175,20,0,177,175,
- 3,131,2,60,33,16,80,0,20,13,66,140,
- 0,0,0,0,18,0,64,16,4,0,17,36,
- 16,0,81,16,254,255,66,36,2,0,66,44,
- 4,0,64,16,64,18,18,0,161,36,192,12,
- 0,0,0,0,64,18,18,0,3,131,1,60,
- 33,8,48,0,20,13,49,172,2,131,1,60,
- 33,8,34,0,164,247,49,172,3,131,1,60,
- 33,8,48,0,110,13,32,164,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,3,131,4,60,
- 208,12,132,140,3,131,5,60,212,12,165,140,
- 3,131,6,60,216,12,198,140,3,131,7,60,
- 220,12,231,140,232,255,189,39,16,0,191,175,
- 20,35,192,12,0,0,0,0,10,0,64,20,
- 1,0,2,36,3,131,1,60,252,12,34,172,
- 1,0,2,36,3,131,1,60,4,13,34,164,
- 3,131,1,60,6,13,32,164,197,36,192,8,
- 1,0,2,36,3,131,2,60,248,12,66,140,
- 0,0,0,0,9,0,64,20,1,0,2,36,
- 72,37,192,12,0,0,0,0,1,0,2,36,
- 3,131,1,60,8,13,34,164,3,131,1,60,
- 10,13,32,164,1,0,2,36,3,131,1,60,
- 248,12,34,172,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,224,255,189,39,
- 20,0,177,175,33,136,128,0,16,0,176,175,
- 192,129,17,0,24,0,191,175,3,131,2,60,
- 33,16,80,0,114,13,66,132,0,0,0,0,
- 5,0,64,16,1,0,2,36,3,131,1,60,
- 33,8,48,0,67,37,192,8,56,13,34,172,
- 3,131,4,60,208,12,132,36,3,131,2,60,
- 64,13,66,36,33,24,2,2,3,131,1,60,
- 33,8,48,0,60,13,32,164,0,0,133,140,
- 4,0,134,140,0,0,101,172,4,0,102,172,
- 12,0,66,36,3,131,3,60,224,12,99,140,
- 33,16,2,2,3,131,1,60,33,8,48,0,
- 72,13,35,172,3,131,3,60,216,12,99,140,
- 3,131,5,60,220,12,165,140,0,0,67,172,
- 4,0,69,172,3,131,2,60,33,16,80,0,
- 16,13,66,148,3,131,1,60,33,8,48,0,
- 84,13,34,164,0,0,132,140,3,131,5,60,
- 212,12,165,140,3,131,6,60,216,12,198,140,
- 3,131,7,60,220,12,231,140,20,35,192,12,
- 0,0,0,0,5,0,64,20,0,0,0,0,
- 3,131,1,60,33,8,48,0,22,37,192,8,
- 86,13,32,164,3,131,2,60,228,12,66,140,
- 2,131,3,60,128,155,99,148,192,17,2,0,
- 3,131,1,60,33,8,34,0,108,13,34,148,
- 0,0,0,0,33,16,67,0,3,131,1,60,
- 33,8,48,0,86,13,34,164,3,131,2,60,
- 232,12,66,148,192,129,17,0,3,131,1,60,
- 33,8,48,0,88,13,34,164,3,131,2,60,
- 234,12,66,148,33,32,32,2,3,131,1,60,
- 33,8,48,0,90,13,34,164,3,131,3,60,
- 236,12,99,148,3,131,2,60,33,16,80,0,
- 52,13,66,140,3,131,5,60,60,13,165,36,
- 3,131,1,60,33,8,48,0,52,13,32,172,
- 3,131,1,60,33,8,48,0,96,13,34,172,
- 3,131,1,60,33,8,48,0,92,13,35,164,
- 3,131,2,60,252,12,66,140,3,131,1,60,
- 33,8,48,0,100,13,34,172,80,40,192,12,
- 33,40,5,2,1,0,2,36,3,131,1,60,
- 33,8,48,0,56,13,32,172,3,131,1,60,
- 33,8,48,0,114,13,34,164,3,131,1,60,
- 33,8,48,0,116,13,32,164,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,128,0,2,36,
- 3,131,4,60,228,12,132,140,3,131,5,60,
- 104,13,165,36,16,0,191,175,192,25,4,0,
- 3,131,1,60,33,8,35,0,104,13,34,164,
- 151,40,192,12,33,40,101,0,2,131,4,60,
- 15,63,192,12,12,146,132,36,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,16,0,191,175,102,37,192,12,
- 0,0,0,0,13,38,192,12,0,0,0,0,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,24,133,130,143,208,255,189,39,
- 24,0,178,175,33,144,0,0,28,0,179,175,
- 1,0,19,36,44,0,191,175,40,0,182,175,
- 36,0,181,175,32,0,180,175,20,0,177,175,
- 110,0,64,24,16,0,176,175,3,131,21,60,
- 216,12,181,38,3,131,22,60,16,13,214,38,
- 128,0,208,38,128,0,20,36,192,17,18,0,
- 3,131,4,60,33,32,148,0,40,13,132,140,
- 3,131,5,60,33,40,180,0,44,13,165,140,
- 0,0,166,142,3,131,7,60,220,12,231,140,
- 0,0,0,0,20,35,192,12,33,136,86,0,
- 10,0,64,20,0,0,0,0,3,131,3,60,
- 33,24,116,0,48,13,99,148,3,131,2,60,
- 33,16,84,0,16,13,66,148,0,0,0,0,
- 74,0,98,16,0,0,0,0,4,0,2,142,
- 0,0,0,0,70,0,64,16,0,0,0,0,
- 12,0,4,142,16,0,5,142,0,0,166,142,
- 3,131,7,60,220,12,231,140,20,35,192,12,
- 0,0,0,0,61,0,65,4,0,0,0,0,
- 58,0,64,18,0,0,0,0,12,0,4,142,
- 16,0,5,142,12,0,38,142,16,0,39,142,
- 20,35,192,12,0,0,0,0,50,0,64,4,
- 0,0,0,0,12,0,4,142,16,0,5,142,
- 12,0,38,142,16,0,39,142,20,35,192,12,
- 0,0,0,0,43,0,64,20,0,0,0,0,
- 20,0,5,142,8,0,3,142,20,0,36,142,
- 8,0,34,142,33,40,163,0,33,32,130,0,
- 43,16,164,0,33,0,64,20,0,0,0,0,
- 32,0,164,20,0,0,0,0,24,0,4,142,
- 28,0,5,142,24,0,38,142,28,0,39,142,
- 20,35,192,12,0,0,0,0,23,0,64,4,
- 0,0,0,0,24,0,4,142,28,0,5,142,
- 24,0,38,142,28,0,39,142,20,35,192,12,
- 0,0,0,0,16,0,64,20,0,0,0,0,
- 32,0,4,150,32,0,35,150,0,0,0,0,
- 43,16,131,0,9,0,64,20,0,0,0,0,
- 8,0,131,20,0,0,0,0,0,0,2,150,
- 0,0,35,150,0,0,0,0,43,16,67,0,
- 2,0,64,16,0,0,0,0,33,144,96,2,
- 128,0,16,38,24,133,130,143,1,0,115,38,
- 42,16,83,0,154,255,64,16,128,0,148,38,
- 3,131,1,60,228,12,50,172,12,0,64,22,
- 192,17,18,0,3,131,2,60,216,12,66,140,
- 3,131,3,60,220,12,99,140,3,131,1,60,
- 208,12,34,172,3,131,1,60,212,12,35,172,
- 3,131,1,60,3,38,192,8,224,12,32,172,
- 3,131,3,60,33,24,98,0,28,13,99,140,
- 3,131,4,60,33,32,130,0,32,13,132,140,
- 3,131,1,60,208,12,35,172,3,131,1,60,
- 212,12,36,172,3,131,3,60,33,24,98,0,
- 36,13,99,140,3,131,1,60,33,8,34,0,
- 24,13,34,140,0,0,0,0,33,24,98,0,
- 3,131,1,60,224,12,35,172,44,0,191,143,
- 40,0,182,143,36,0,181,143,32,0,180,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,48,0,189,39,
- 24,133,130,143,208,255,189,39,36,0,181,175,
- 1,0,21,36,44,0,191,175,40,0,182,175,
- 32,0,180,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,82,0,64,24,16,0,176,175,
- 3,131,22,60,216,12,214,38,3,131,2,60,
- 48,13,66,36,128,0,84,36,96,0,83,36,
- 124,0,82,36,120,0,81,36,128,0,16,36,
- 0,0,36,142,0,0,69,142,0,0,198,142,
- 3,131,7,60,220,12,231,140,20,35,192,12,
- 0,0,0,0,55,0,64,20,0,0,0,0,
- 0,0,131,150,0,0,98,150,0,0,0,0,
- 50,0,98,20,0,0,0,0,3,131,4,60,
- 33,32,144,0,28,13,132,140,3,131,5,60,
- 33,40,176,0,32,13,165,140,248,255,198,142,
- 3,131,7,60,212,12,231,140,20,35,192,12,
- 0,0,0,0,37,0,64,16,0,0,0,0,
- 8,0,196,142,3,131,3,60,33,24,112,0,
- 36,13,99,140,0,0,0,0,43,16,131,0,
- 29,0,64,20,0,0,0,0,27,0,131,20,
- 0,0,0,0,0,0,196,142,3,131,5,60,
- 220,12,165,140,0,0,38,142,0,0,71,142,
- 20,35,192,12,0,0,0,0,16,0,64,4,
- 0,0,0,0,0,0,196,142,3,131,5,60,
- 220,12,165,140,0,0,38,142,0,0,71,142,
- 20,35,192,12,0,0,0,0,9,0,64,20,
- 0,0,0,0,0,0,99,150,0,0,130,150,
- 0,0,0,0,43,16,67,0,3,0,64,20,
- 0,0,0,0,22,36,192,12,33,32,160,2,
- 128,0,148,38,128,0,115,38,128,0,82,38,
- 128,0,49,38,24,133,130,143,1,0,181,38,
- 42,16,85,0,185,255,64,16,128,0,16,38,
- 44,0,191,143,40,0,182,143,36,0,181,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 48,0,189,39,216,255,189,39,3,131,4,60,
- 0,13,132,36,32,0,191,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 0,0,130,132,0,0,0,0,14,0,64,16,
- 0,0,0,0,3,131,2,60,2,13,66,148,
- 3,131,3,60,234,12,99,148,1,0,66,36,
- 3,131,1,60,2,13,34,164,255,255,66,48,
- 43,16,67,0,3,0,64,20,0,0,0,0,
- 11,39,192,12,0,0,128,164,3,131,4,60,
- 8,13,132,36,0,0,130,132,0,0,0,0,
- 14,0,64,16,0,0,0,0,3,131,2,60,
- 10,13,66,148,3,131,3,60,234,12,99,148,
- 1,0,66,36,3,131,1,60,10,13,34,164,
- 255,255,66,48,43,16,67,0,3,0,64,20,
- 0,0,0,0,24,39,192,12,0,0,128,164,
- 3,131,4,60,4,13,132,36,0,0,130,132,
- 0,0,0,0,14,0,64,16,0,0,0,0,
- 3,131,2,60,6,13,66,148,3,131,3,60,
- 244,12,99,148,1,0,66,36,3,131,1,60,
- 6,13,34,164,255,255,66,48,43,16,67,0,
- 3,0,64,20,0,0,0,0,37,39,192,12,
- 0,0,128,164,24,133,130,143,0,0,0,0,
- 78,0,64,24,1,0,17,36,3,131,2,60,
- 16,13,66,36,226,0,83,36,128,0,82,36,
- 128,0,16,36,3,131,2,60,33,16,80,0,
- 110,13,66,132,0,0,0,0,18,0,64,16,
- 0,0,0,0,3,131,2,60,33,16,80,0,
- 112,13,66,148,0,0,0,0,1,0,66,36,
- 96,0,66,166,3,131,3,60,236,12,99,148,
- 255,255,66,48,43,16,67,0,6,0,64,20,
- 0,0,0,0,3,131,1,60,33,8,48,0,
- 110,13,32,164,79,39,192,12,33,32,32,2,
- 3,131,2,60,33,16,80,0,106,13,66,132,
- 0,0,0,0,18,0,64,16,0,0,0,0,
- 3,131,2,60,33,16,80,0,108,13,66,148,
- 0,0,0,0,1,0,66,36,92,0,66,166,
- 3,131,3,60,232,12,99,148,255,255,66,48,
- 43,16,67,0,6,0,64,20,0,0,0,0,
- 3,131,1,60,33,8,48,0,106,13,32,164,
- 129,39,192,12,33,32,32,2,0,0,98,134,
- 0,0,0,0,16,0,64,16,0,0,0,0,
- 3,131,2,60,33,16,80,0,116,13,66,148,
- 0,0,0,0,1,0,66,36,100,0,66,166,
- 3,131,3,60,246,12,99,148,255,255,66,48,
- 43,16,67,0,4,0,64,20,0,0,0,0,
- 0,0,96,166,191,39,192,12,33,32,32,2,
- 128,0,115,38,128,0,82,38,24,133,130,143,
- 1,0,49,38,42,16,81,0,185,255,64,16,
- 128,0,16,38,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,232,255,189,39,
- 16,0,191,175,52,36,192,12,0,0,0,0,
- 1,0,2,36,3,131,1,60,0,13,34,164,
- 3,131,1,60,2,13,32,164,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,16,0,191,175,72,37,192,12,
- 0,0,0,0,1,0,2,36,3,131,1,60,
- 8,13,34,164,3,131,1,60,10,13,32,164,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,240,255,189,39,3,131,1,60,
- 248,12,32,172,3,131,1,60,252,12,32,172,
- 8,0,224,3,16,0,189,39,24,133,130,143,
- 224,255,189,39,20,0,177,175,1,0,17,36,
- 24,0,191,175,23,0,64,24,16,0,176,175,
- 128,0,16,36,3,131,4,60,33,32,144,0,
- 40,13,132,140,3,131,5,60,33,40,176,0,
- 44,13,165,140,3,131,6,60,216,12,198,140,
- 3,131,7,60,220,12,231,140,20,35,192,12,
- 0,0,0,0,3,0,64,20,1,0,49,38,
- 74,39,192,8,1,0,2,36,24,133,130,143,
- 0,0,0,0,42,16,81,0,236,255,64,16,
- 128,0,16,38,33,16,0,0,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,192,41,4,0,
- 16,0,191,175,3,131,3,60,33,24,101,0,
- 20,13,99,140,1,0,2,36,16,0,98,20,
- 2,0,2,36,64,26,4,0,3,131,1,60,
- 33,8,37,0,20,13,34,172,2,131,1,60,
- 33,8,35,0,164,247,34,172,1,0,2,36,
- 3,131,1,60,33,8,37,0,110,13,34,164,
- 3,131,1,60,33,8,37,0,125,39,192,8,
- 112,13,32,164,21,0,98,20,3,0,3,36,
- 64,18,4,0,3,131,1,60,33,8,37,0,
- 20,13,35,172,2,131,1,60,33,8,34,0,
- 164,247,35,172,3,131,2,60,33,16,69,0,
- 120,13,66,140,0,0,0,0,1,0,66,36,
- 3,131,1,60,33,8,37,0,44,39,192,12,
- 120,13,34,172,3,0,64,16,0,0,0,0,
- 161,36,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 224,255,189,39,16,0,176,175,33,128,128,0,
- 20,0,177,175,3,131,17,60,208,12,49,38,
- 24,0,191,175,0,0,36,142,3,131,5,60,
- 212,12,165,140,3,131,6,60,216,12,198,140,
- 3,131,7,60,220,12,231,140,20,35,192,12,
- 0,0,0,0,33,32,0,2,22,36,192,12,
- 1,0,80,44,92,37,192,12,0,0,0,0,
- 206,35,192,12,0,0,0,0,33,0,0,22,
- 0,0,0,0,0,0,36,142,3,131,5,60,
- 212,12,165,140,3,131,6,60,216,12,198,140,
- 3,131,7,60,220,12,231,140,20,35,192,12,
- 0,0,0,0,22,0,64,20,0,0,0,0,
- 3,131,2,60,238,12,66,148,3,131,3,60,
- 240,12,99,148,3,131,4,60,242,12,132,148,
- 3,131,1,60,232,12,34,164,3,131,1,60,
- 234,12,35,164,3,131,1,60,161,36,192,12,
- 236,12,36,164,3,131,1,60,52,36,192,12,
- 8,13,32,164,1,0,2,36,3,131,1,60,
- 0,13,34,164,3,131,1,60,2,13,32,164,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,232,255,189,39,
- 192,17,4,0,16,0,191,175,3,131,1,60,
- 33,8,34,0,56,13,34,140,0,0,0,0,
- 3,0,64,16,0,0,0,0,203,36,192,12,
- 0,0,0,0,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,3,131,1,60,
- 248,12,32,172,3,131,1,60,8,0,224,3,
- 8,13,32,164,232,255,189,39,192,25,4,0,
- 1,0,2,36,16,0,191,175,3,131,1,60,
- 33,8,35,0,203,36,192,12,52,13,34,172,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,192,33,4,0,3,131,2,60,
- 28,13,66,36,33,24,130,0,4,0,166,140,
- 8,0,167,140,0,0,102,172,4,0,103,172,
- 12,0,66,36,12,0,163,140,33,16,130,0,
- 3,131,1,60,33,8,36,0,36,13,35,172,
- 16,0,163,140,20,0,166,140,0,0,67,172,
- 4,0,70,172,24,0,163,148,1,0,2,36,
- 3,131,1,60,33,8,36,0,106,13,34,164,
- 3,131,1,60,33,8,36,0,48,13,35,164,
- 26,0,162,148,3,131,1,60,33,8,36,0,
- 8,0,224,3,108,13,34,164,28,0,130,148,
- 3,131,1,60,232,12,34,164,30,0,130,148,
- 3,131,1,60,234,12,34,164,32,0,130,148,
- 3,131,1,60,236,12,34,164,40,0,130,140,
- 3,131,1,60,8,0,224,3,252,12,34,172,
- 224,255,189,39,16,0,176,175,33,128,160,0,
- 192,25,4,0,3,131,2,60,16,13,66,36,
- 20,0,177,175,33,136,98,0,24,0,191,175,
- 4,0,4,142,8,0,5,142,12,0,38,142,
- 16,0,39,142,20,35,192,12,0,0,0,0,
- 48,0,64,4,1,0,2,36,4,0,4,142,
- 8,0,5,142,12,0,38,142,16,0,39,142,
- 20,35,192,12,0,0,0,0,40,0,64,20,
- 33,16,0,0,12,0,4,142,20,0,35,142,
- 0,0,0,0,43,16,131,0,34,0,64,20,
- 1,0,2,36,32,0,131,20,33,16,0,0,
- 16,0,4,142,20,0,5,142,24,0,38,142,
- 28,0,39,142,20,35,192,12,0,0,0,0,
- 24,0,64,4,1,0,2,36,16,0,4,142,
- 20,0,5,142,24,0,38,142,28,0,39,142,
- 20,35,192,12,0,0,0,0,16,0,64,20,
- 33,16,0,0,16,0,4,142,20,0,5,142,
- 3,131,6,60,216,12,198,140,3,131,7,60,
- 220,12,231,140,20,35,192,12,0,0,0,0,
- 6,0,64,20,1,0,2,36,24,0,3,150,
- 32,0,34,150,0,0,0,0,43,16,67,0,
- 1,0,66,56,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 44,133,130,143,216,255,189,39,20,0,177,175,
- 33,136,128,0,32,0,180,175,33,160,160,0,
- 36,0,191,175,28,0,179,175,24,0,178,175,
- 53,0,64,16,16,0,176,175,2,131,19,60,
- 192,4,115,38,33,32,96,2,54,21,192,12,
- 1,0,5,36,33,128,64,0,8,0,0,22,
- 64,26,17,0,2,131,2,60,33,16,67,0,
- 176,247,66,140,33,24,99,2,1,0,66,36,
- 143,40,192,8,240,242,98,172,8,0,4,142,
- 64,146,17,0,20,242,101,38,33,40,69,2,
- 172,41,192,12,33,48,128,2,33,24,64,0,
- 60,0,98,40,2,0,64,16,0,242,98,38,
- 60,0,3,36,33,136,66,2,33,32,32,2,
- 33,40,0,2,1,0,2,36,17,0,2,162,
- 0,128,98,52,0,0,2,174,6,23,192,12,
- 18,0,3,166,10,0,64,20,33,32,0,2,
- 2,131,2,60,33,16,82,0,172,247,66,140,
- 0,0,0,0,1,0,66,36,152,21,192,12,
- 236,0,34,174,143,40,192,8,0,0,0,0,
- 2,131,2,60,33,16,82,0,168,247,66,140,
- 0,0,0,0,1,0,66,36,232,0,34,174,
- 36,0,191,143,32,0,180,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,44,133,130,143,
- 216,255,189,39,20,0,177,175,33,136,128,0,
- 32,0,180,175,33,160,160,0,36,0,191,175,
- 28,0,179,175,24,0,178,175,53,0,64,16,
- 16,0,176,175,2,131,19,60,192,4,115,38,
- 33,32,96,2,54,21,192,12,1,0,5,36,
- 33,128,64,0,8,0,0,22,64,26,17,0,
- 2,131,2,60,33,16,67,0,176,247,66,140,
- 33,24,99,2,1,0,66,36,214,40,192,8,
- 240,242,98,172,8,0,4,142,64,146,17,0,
- 20,242,101,38,33,40,69,2,74,42,192,12,
- 33,48,128,2,33,24,64,0,60,0,98,40,
- 2,0,64,16,0,242,98,38,60,0,3,36,
- 33,136,66,2,33,32,32,2,33,40,0,2,
- 1,0,2,36,17,0,2,162,0,128,98,52,
- 0,0,2,174,6,23,192,12,18,0,3,166,
- 10,0,64,20,33,32,0,2,2,131,2,60,
- 33,16,82,0,172,247,66,140,0,0,0,0,
- 1,0,66,36,152,21,192,12,236,0,34,174,
- 214,40,192,8,0,0,0,0,2,131,2,60,
- 33,16,82,0,168,247,66,140,0,0,0,0,
- 1,0,66,36,232,0,34,174,36,0,191,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,216,255,189,39,24,0,178,175,
- 33,144,128,0,20,0,177,175,33,136,160,0,
- 16,0,176,175,33,128,192,0,36,0,191,175,
- 32,0,180,175,28,0,179,175,4,0,36,142,
- 8,0,37,142,160,133,134,143,2,131,7,60,
- 180,211,231,140,20,35,192,12,0,0,0,0,
- 11,0,64,20,0,0,0,0,2,131,4,60,
- 144,146,132,36,15,63,192,12,33,40,0,2,
- 100,129,132,39,108,129,134,39,31,21,192,12,
- 6,0,5,38,92,41,192,8,0,0,0,0,
- 3,131,20,60,208,12,148,38,0,0,132,142,
- 3,131,5,60,212,12,165,140,3,131,6,60,
- 216,12,198,140,3,131,7,60,220,12,231,140,
- 0,0,0,0,20,35,192,12,192,129,18,0,
- 3,131,3,60,33,24,112,0,20,13,99,140,
- 0,0,0,0,80,0,96,16,1,0,83,44,
- 33,32,64,2,11,40,192,12,33,40,32,2,
- 50,0,64,16,33,32,64,2,223,39,192,12,
- 33,40,32,2,92,37,192,12,0,0,0,0,
- 206,35,192,12,0,0,0,0,0,0,132,142,
- 3,131,5,60,212,12,165,140,3,131,6,60,
- 216,12,198,140,3,131,7,60,220,12,231,140,
- 20,35,192,12,0,0,0,0,16,0,64,16,
- 0,0,0,0,14,0,96,18,0,0,0,0,
- 3,131,2,60,248,12,66,140,3,131,1,60,
- 9,0,64,16,0,13,32,164,3,131,1,60,
- 72,37,192,12,4,13,32,164,1,0,2,36,
- 3,131,1,60,8,13,34,164,3,131,1,60,
- 10,13,32,164,3,131,2,60,228,12,66,140,
- 0,0,0,0,38,0,66,22,0,0,0,0,
- 254,39,192,12,33,32,32,2,52,36,192,12,
- 0,0,0,0,36,0,34,142,0,0,0,0,
- 30,0,64,16,0,0,0,0,206,39,192,12,
- 0,0,0,0,92,41,192,8,0,0,0,0,
- 3,131,4,60,33,32,144,0,40,13,132,140,
- 3,131,5,60,33,40,176,0,44,13,165,140,
- 3,131,6,60,216,12,198,140,3,131,7,60,
- 220,12,231,140,20,35,192,12,0,0,0,0,
- 12,0,64,20,0,0,0,0,3,131,3,60,
- 33,24,112,0,48,13,99,148,3,131,2,60,
- 33,16,80,0,16,13,66,148,0,0,0,0,
- 3,0,98,20,0,0,0,0,203,36,192,12,
- 33,32,64,2,36,0,191,143,32,0,180,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,40,0,189,39,
- 224,255,189,39,20,0,177,175,33,136,128,0,
- 16,0,176,175,192,129,17,0,24,0,191,175,
- 3,131,2,60,33,16,80,0,20,13,66,140,
- 0,0,0,0,28,0,64,16,0,0,0,0,
- 3,131,4,60,33,32,144,0,40,13,132,140,
- 3,131,5,60,33,40,176,0,44,13,165,140,
- 3,131,6,60,216,12,198,140,3,131,7,60,
- 220,12,231,140,20,35,192,12,0,0,0,0,
- 14,0,64,20,0,0,0,0,3,131,3,60,
- 33,24,112,0,48,13,99,148,3,131,2,60,
- 33,16,80,0,16,13,66,148,0,0,0,0,
- 5,0,98,20,0,0,0,0,161,36,192,12,
- 0,0,0,0,211,39,192,12,33,32,32,2,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,2,18,5,0,
- 0,0,130,160,8,0,224,3,1,0,133,160,
- 2,22,5,0,0,0,130,160,2,20,5,0,
- 1,0,130,160,2,18,5,0,2,0,130,160,
- 8,0,224,3,3,0,133,160,0,0,130,144,
- 1,0,131,144,0,18,2,0,8,0,224,3,
- 37,16,98,0,0,0,130,144,1,0,131,144,
- 2,0,133,144,0,22,2,0,0,28,3,0,
- 33,16,67,0,0,42,5,0,3,0,131,144,
- 33,16,69,0,8,0,224,3,37,16,67,0,
- 224,255,189,39,16,0,176,175,33,128,128,0,
- 24,0,191,175,20,0,177,175,48,129,135,39,
- 3,0,226,136,0,0,226,152,4,0,227,128,
- 5,0,228,128,3,0,2,170,0,0,2,186,
- 4,0,3,162,5,0,4,162,3,0,162,136,
- 0,0,162,152,4,0,163,128,5,0,164,128,
- 9,0,2,170,6,0,2,186,10,0,3,162,
- 11,0,4,162,12,0,4,38,38,0,5,36,
- 144,41,192,12,33,136,192,0,14,0,4,38,
- 144,41,192,12,66,66,5,36,17,0,4,38,
- 33,40,0,0,3,0,2,36,144,41,192,12,
- 16,0,2,162,19,0,0,162,20,0,0,162,
- 40,0,34,142,0,0,0,0,43,32,2,0,
- 36,0,34,142,0,0,0,0,3,0,64,16,
- 33,24,128,0,218,41,192,8,128,0,130,52,
- 33,16,96,0,21,0,2,162,4,0,37,150,
- 0,0,0,0,144,41,192,12,22,0,4,38,
- 9,0,34,138,6,0,34,154,10,0,35,130,
- 11,0,36,130,27,0,2,170,24,0,2,186,
- 28,0,3,162,29,0,4,162,12,0,37,142,
- 0,0,0,0,148,41,192,12,30,0,4,38,
- 16,0,37,150,0,0,0,0,144,41,192,12,
- 34,0,4,38,21,0,34,138,18,0,34,154,
- 22,0,35,130,23,0,36,130,39,0,2,170,
- 36,0,2,186,40,0,3,162,41,0,4,162,
- 24,0,37,150,0,0,0,0,144,41,192,12,
- 42,0,4,38,26,0,37,150,0,0,0,0,
- 144,41,192,12,44,0,4,38,28,0,37,150,
- 0,0,0,0,144,41,192,12,46,0,4,38,
- 30,0,37,150,0,0,0,0,144,41,192,12,
- 48,0,4,38,32,0,37,150,0,0,0,0,
- 144,41,192,12,50,0,4,38,52,0,2,36,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,224,255,189,39,
- 16,0,176,175,33,128,160,0,24,0,191,175,
- 20,0,177,175,21,0,2,146,33,136,128,0,
- 1,0,66,48,40,0,34,174,22,0,2,146,
- 22,0,4,38,128,0,66,48,156,41,192,12,
- 36,0,34,174,4,0,34,166,27,0,2,138,
- 24,0,2,154,28,0,3,130,29,0,4,130,
- 9,0,34,170,6,0,34,186,10,0,35,162,
- 11,0,36,162,161,41,192,12,30,0,4,38,
- 34,0,4,38,156,41,192,12,12,0,34,174,
- 16,0,34,166,39,0,2,138,36,0,2,154,
- 40,0,3,130,41,0,4,130,21,0,34,170,
- 18,0,34,186,22,0,35,162,23,0,36,162,
- 156,41,192,12,42,0,4,38,44,0,4,38,
- 156,41,192,12,24,0,34,166,46,0,4,38,
- 156,41,192,12,26,0,34,166,48,0,4,38,
- 156,41,192,12,28,0,34,166,50,0,4,38,
- 156,41,192,12,30,0,34,166,32,0,34,166,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,232,255,189,39,
- 16,0,176,175,33,128,128,0,20,0,191,175,
- 48,129,134,39,3,0,194,136,0,0,194,152,
- 4,0,195,128,5,0,196,128,3,0,2,170,
- 0,0,2,186,4,0,3,162,5,0,4,162,
- 3,0,162,136,0,0,162,152,4,0,163,128,
- 5,0,164,128,9,0,2,170,6,0,2,186,
- 10,0,3,162,11,0,4,162,12,0,4,38,
- 144,41,192,12,7,0,5,36,14,0,4,38,
- 144,41,192,12,66,66,5,36,17,0,4,38,
- 33,40,0,0,3,0,2,36,144,41,192,12,
- 16,0,2,162,21,0,2,36,128,0,3,36,
- 19,0,0,162,20,0,3,162,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 176,255,189,39,68,0,177,175,64,0,176,175,
- 33,128,160,0,72,0,191,175,14,0,3,146,
- 66,0,2,36,9,0,98,20,33,136,128,0,
- 15,0,2,146,0,0,0,0,6,0,67,20,
- 64,26,17,0,16,0,3,146,3,0,2,36,
- 11,0,98,16,0,0,0,0,64,26,17,0,
- 2,131,2,60,33,16,67,0,184,247,66,140,
- 0,0,0,0,1,0,66,36,2,131,1,60,
- 33,8,35,0,182,42,192,8,184,247,34,172,
- 20,0,3,146,0,0,0,0,5,0,96,16,
- 128,0,2,36,21,0,98,16,64,26,17,0,
- 179,42,192,8,0,0,0,0,16,0,164,39,
- 64,26,17,0,2,131,2,60,33,16,67,0,
- 180,247,66,140,0,0,0,0,1,0,66,36,
- 2,131,1,60,33,8,35,0,180,247,34,172,
- 17,42,192,12,33,40,0,2,33,32,32,2,
- 16,0,165,39,222,40,192,12,33,48,0,2,
- 182,42,192,8,0,0,0,0,2,131,2,60,
- 33,16,67,0,180,247,66,140,0,0,0,0,
- 1,0,66,36,2,131,1,60,33,8,35,0,
- 180,247,34,172,100,41,192,12,33,32,32,2,
- 182,42,192,8,0,0,0,0,112,129,132,39,
- 15,63,192,12,0,0,0,0,72,0,191,143,
- 68,0,177,143,64,0,176,143,8,0,224,3,
- 80,0,189,39,8,0,224,3,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,162,48,8,0,64,16,255,255,198,48,
- 67,40,5,0,64,16,5,0,33,16,68,0,
- 0,0,66,144,0,0,0,0,203,42,192,8,
- 33,48,194,0,67,40,5,0,255,255,165,36,
- 255,255,2,36,6,0,162,16,255,255,3,36,
- 0,0,130,148,2,0,132,36,255,255,165,36,
- 252,255,163,20,33,48,194,0,255,255,195,48,
- 2,20,6,0,33,48,98,0,255,255,195,48,
- 2,20,6,0,33,48,98,0,8,0,224,3,
- 255,255,194,48,208,255,189,39,16,0,176,175,
- 33,128,128,0,28,0,179,175,33,152,160,0,
- 24,0,178,175,33,144,192,0,36,0,181,175,
- 33,168,0,2,32,0,180,175,33,160,0,0,
- 40,0,191,175,20,0,177,175,12,0,3,142,
- 0,0,2,142,0,0,0,0,35,24,98,0,
- 42,16,114,0,2,0,64,16,33,136,64,2,
- 33,136,96,0,13,0,32,18,33,40,96,2,
- 35,144,81,2,8,0,2,142,0,0,4,142,
- 33,48,32,2,80,68,192,12,33,32,68,0,
- 8,0,2,142,0,0,2,142,0,0,2,142,
- 33,152,113,2,33,16,81,0,0,0,2,174,
- 0,0,2,142,0,0,0,0,4,0,64,18,
- 33,160,130,2,4,0,16,142,233,42,192,8,
- 0,0,0,0,18,0,180,166,33,16,0,2,
- 40,0,191,143,36,0,181,143,32,0,180,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,48,0,189,39,
- 224,255,189,39,24,0,178,175,33,144,128,0,
- 2,131,4,60,192,4,132,36,36,0,165,175,
- 1,0,5,36,28,0,191,175,20,0,177,175,
- 54,21,192,12,16,0,176,175,33,136,64,0,
- 8,0,32,22,33,40,0,0,2,131,2,60,
- 176,5,66,140,0,0,0,0,1,0,66,36,
- 2,131,1,60,102,43,192,8,176,5,34,172,
- 0,1,3,36,8,0,48,142,8,0,2,36,
- 16,0,2,166,6,0,2,36,18,0,2,162,
- 4,0,2,36,14,0,3,166,19,0,2,162,
- 20,0,3,166,2,131,6,60,212,4,198,36,
- 3,0,194,136,0,0,194,152,4,0,195,132,
- 25,0,2,170,22,0,2,186,26,0,3,166,
- 2,131,1,60,195,211,34,136,176,133,130,155,
- 0,0,0,0,31,0,2,170,28,0,2,186,
- 32,0,4,38,144,71,192,12,6,0,6,36,
- 39,0,162,139,36,0,162,155,0,0,0,0,
- 41,0,2,170,38,0,2,186,132,129,133,39,
- 3,0,162,136,0,0,162,152,4,0,163,128,
- 5,0,164,128,3,0,2,170,0,0,2,186,
- 4,0,3,162,5,0,4,162,2,131,5,60,
- 212,4,165,36,3,0,162,136,0,0,162,152,
- 4,0,163,128,5,0,164,128,9,0,2,170,
- 6,0,2,186,10,0,3,162,11,0,4,162,
- 33,32,64,2,8,6,2,36,12,0,2,166,
- 60,128,2,52,0,0,34,174,60,0,2,36,
- 18,0,34,166,74,21,192,12,33,40,32,2,
- 3,0,64,20,0,0,0,0,152,21,192,12,
- 33,32,32,2,28,0,191,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,216,255,189,39,32,0,180,175,
- 33,160,128,0,16,0,176,175,33,128,160,0,
- 36,0,191,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,8,0,2,142,33,152,192,0,
- 33,136,83,0,6,0,35,150,0,1,4,36,
- 5,0,100,16,0,2,2,36,113,0,98,16,
- 0,0,0,0,15,44,192,8,0,0,0,0,
- 24,0,35,150,176,133,130,151,0,0,0,0,
- 139,0,98,20,0,0,0,0,26,0,35,150,
- 2,131,2,60,194,211,66,148,0,0,0,0,
- 133,0,98,20,0,0,0,0,0,0,34,150,
- 0,0,0,0,129,0,68,20,8,0,2,36,
- 2,0,35,150,0,0,0,0,125,0,98,20,
- 6,4,2,36,4,0,35,150,0,0,0,0,
- 121,0,98,20,0,0,0,0,2,131,4,60,
- 192,4,132,36,54,21,192,12,1,0,5,36,
- 33,144,64,0,8,0,64,22,0,0,0,0,
- 2,131,2,60,176,5,66,140,0,0,0,0,
- 1,0,66,36,2,131,1,60,15,44,192,8,
- 176,5,34,172,8,0,5,142,8,0,80,142,
- 9,0,162,136,6,0,162,152,10,0,163,128,
- 11,0,164,128,3,0,2,170,0,0,2,186,
- 4,0,3,162,5,0,4,162,2,131,6,60,
- 212,4,198,36,3,0,194,136,0,0,194,152,
- 4,0,195,128,5,0,196,128,9,0,2,170,
- 6,0,2,186,10,0,3,162,11,0,4,162,
- 12,0,4,38,12,0,165,36,33,128,19,2,
- 80,68,192,12,244,255,102,38,0,1,2,36,
- 0,0,2,166,8,0,2,36,2,0,2,166,
- 6,0,2,36,4,0,2,162,4,0,2,36,
- 5,0,2,162,0,2,2,36,6,0,2,166,
- 2,131,5,60,212,4,165,36,3,0,162,136,
- 0,0,162,152,4,0,163,132,11,0,2,170,
- 8,0,2,186,12,0,3,166,2,131,1,60,
- 195,211,34,136,176,133,130,155,0,0,0,0,
- 17,0,2,170,14,0,2,186,11,0,34,138,
- 8,0,34,154,12,0,35,134,21,0,2,170,
- 18,0,2,186,22,0,3,166,17,0,34,138,
- 14,0,34,154,0,0,0,0,27,0,2,170,
- 24,0,2,186,33,32,128,2,33,40,64,2,
- 60,128,2,52,0,0,66,174,60,0,2,36,
- 74,21,192,12,18,0,66,166,38,0,64,20,
- 0,0,0,0,152,21,192,12,33,32,64,2,
- 15,44,192,8,0,0,0,0,14,0,35,150,
- 196,133,130,151,0,0,0,0,29,0,98,20,
- 0,0,0,0,16,0,35,150,2,131,2,60,
- 214,211,66,148,0,0,0,0,23,0,98,20,
- 0,0,0,0,0,0,34,150,0,0,0,0,
- 19,0,68,20,8,0,2,36,2,0,35,150,
- 0,0,0,0,15,0,98,20,6,4,2,36,
- 4,0,35,150,0,0,0,0,11,0,98,20,
- 0,0,0,0,68,133,130,143,140,129,134,39,
- 11,0,35,138,8,0,35,154,12,0,36,134,
- 3,0,195,168,0,0,195,184,4,0,196,164,
- 20,0,66,36,152,129,130,175,36,0,191,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,192,255,189,39,80,0,169,143,
- 84,0,168,143,56,0,180,175,33,160,128,0,
- 44,0,177,175,88,0,177,143,16,0,164,39,
- 52,0,179,175,92,0,179,143,3,131,3,60,
- 32,17,99,36,40,0,176,175,33,128,192,0,
- 60,0,191,175,48,0,178,175,0,0,98,140,
- 8,0,50,142,1,0,66,36,0,0,98,172,
- 3,0,162,136,0,0,162,152,4,0,163,128,
- 5,0,170,128,3,0,66,170,0,0,66,186,
- 4,0,67,162,5,0,74,162,2,131,10,60,
- 212,4,74,37,3,0,66,137,0,0,66,153,
- 4,0,67,129,5,0,69,129,9,0,66,170,
- 6,0,66,186,10,0,67,162,11,0,69,162,
- 69,0,2,36,16,0,162,163,17,0,168,163,
- 18,0,34,150,240,132,131,143,33,48,0,0,
- 25,0,169,163,20,0,66,36,0,66,2,0,
- 255,255,66,48,2,18,2,0,37,64,2,1,
- 0,74,3,0,255,255,98,48,2,18,2,0,
- 37,72,34,1,3,131,2,60,0,17,66,140,
- 22,0,160,167,26,0,160,167,18,0,168,167,
- 176,133,136,143,1,0,99,36,240,132,131,175,
- 20,0,169,167,24,0,162,163,28,0,168,175,
- 3,0,226,136,0,0,226,152,0,0,0,0,
- 35,0,162,171,32,0,162,187,192,42,192,12,
- 20,0,5,36,39,16,2,0,26,0,162,167,
- 14,0,2,36,44,0,2,22,8,0,2,36,
- 12,0,66,166,19,0,162,139,16,0,162,155,
- 23,0,163,139,20,0,163,155,27,0,164,139,
- 24,0,164,155,31,0,165,139,28,0,165,155,
- 17,0,66,170,14,0,66,186,21,0,67,170,
- 18,0,67,186,25,0,68,170,22,0,68,186,
- 29,0,69,170,26,0,69,186,35,0,162,139,
- 32,0,162,155,0,0,0,0,33,0,66,170,
- 30,0,66,186,34,0,2,36,0,0,34,174,
- 0,0,35,142,18,0,34,150,0,0,0,0,
- 33,16,67,0,18,0,34,166,18,0,34,150,
- 0,0,0,0,60,0,66,44,68,0,64,16,
- 33,32,128,2,0,0,98,142,18,0,35,150,
- 60,0,66,36,35,16,67,0,0,0,98,174,
- 60,0,2,36,18,0,34,166,201,44,192,8,
- 33,32,128,2,164,129,133,39,3,0,162,136,
- 0,0,162,152,4,0,163,128,5,0,164,128,
- 17,0,66,170,14,0,66,186,18,0,67,162,
- 19,0,68,162,8,0,2,36,20,0,66,166,
- 19,0,162,139,16,0,162,155,23,0,163,139,
- 20,0,163,155,27,0,164,139,24,0,164,155,
- 31,0,165,139,28,0,165,155,25,0,66,170,
- 22,0,66,186,29,0,67,170,26,0,67,186,
- 33,0,68,170,30,0,68,186,37,0,69,170,
- 34,0,69,186,35,0,162,139,32,0,162,155,
- 0,0,0,0,41,0,66,170,38,0,66,186,
- 42,0,2,36,0,0,34,174,0,0,35,142,
- 18,0,34,150,0,0,0,0,33,16,67,0,
- 18,0,34,166,18,0,34,150,0,0,0,0,
- 60,0,66,44,8,0,64,16,0,0,0,0,
- 0,0,98,142,18,0,35,150,60,0,66,36,
- 35,16,67,0,0,0,98,174,60,0,2,36,
- 18,0,34,166,18,0,34,150,0,0,0,0,
- 0,26,2,0,2,18,2,0,37,24,98,0,
- 12,0,67,166,33,32,128,2,74,21,192,12,
- 33,40,32,2,8,0,64,20,33,32,32,2,
- 3,131,3,60,36,17,99,36,0,0,98,140,
- 0,0,0,0,1,0,66,36,152,21,192,12,
- 0,0,98,172,60,0,191,143,56,0,180,143,
- 52,0,179,143,48,0,178,143,44,0,177,143,
- 40,0,176,143,8,0,224,3,64,0,189,39,
- 176,255,189,39,56,0,180,175,112,0,180,143,
- 48,0,178,175,100,0,178,143,52,0,179,175,
- 104,0,179,143,64,0,182,175,33,176,128,0,
- 72,0,190,175,33,240,160,0,60,0,181,175,
- 33,168,224,0,68,0,183,175,108,0,183,143,
- 2,131,4,60,192,4,132,36,76,0,191,175,
- 44,0,177,175,40,0,176,175,32,0,166,175,
- 7,2,130,38,2,130,2,0,54,21,192,12,
- 33,40,0,2,33,136,64,0,8,0,32,22,
- 0,74,18,0,2,131,4,60,232,146,132,36,
- 33,40,128,2,15,63,192,12,33,48,0,2,
- 74,45,192,8,0,0,0,0,255,255,66,50,
- 2,18,2,0,37,72,34,1,0,66,19,0,
- 255,255,98,50,2,18,2,0,37,64,2,1,
- 8,0,130,38,0,58,2,0,255,255,66,48,
- 2,18,2,0,37,56,226,0,0,163,4,60,
- 220,5,132,52,4,0,5,36,4,0,34,142,
- 0,17,6,36,8,0,80,140,4,0,35,142,
- 8,0,2,36,0,0,98,172,0,0,9,166,
- 2,0,8,166,6,0,0,166,192,42,192,12,
- 4,0,7,166,33,32,160,2,4,0,5,36,
- 192,42,192,12,255,255,70,48,4,0,4,38,
- 2,0,5,36,192,42,192,12,255,255,70,48,
- 33,32,0,2,8,0,5,36,192,42,192,12,
- 255,255,70,48,33,32,224,2,33,40,128,2,
- 192,42,192,12,255,255,70,48,39,24,2,0,
- 255,255,98,48,2,0,64,20,33,40,224,2,
- 255,255,3,52,6,0,3,166,4,0,36,142,
- 0,0,0,0,220,42,192,12,33,48,128,2,
- 33,32,192,2,0,0,67,140,33,40,192,3,
- 0,128,99,52,0,0,67,172,4,0,35,142,
- 32,0,166,143,18,0,99,148,33,56,160,2,
- 18,0,35,166,96,0,170,143,17,0,3,36,
- 16,0,163,175,24,0,177,175,28,0,162,175,
- 23,44,192,12,20,0,170,175,3,131,3,60,
- 124,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,76,0,191,143,
- 72,0,190,143,68,0,183,143,64,0,182,143,
- 60,0,181,143,56,0,180,143,52,0,179,143,
- 48,0,178,143,44,0,177,143,40,0,176,143,
- 8,0,224,3,80,0,189,39,128,255,189,39,
- 116,0,183,175,33,184,128,0,112,0,182,175,
- 33,176,160,0,104,0,180,175,33,160,192,0,
- 108,0,181,175,33,168,224,0,40,0,164,39,
- 96,0,178,175,144,0,178,143,33,40,0,0,
- 100,0,179,175,148,0,179,143,16,0,6,36,
- 120,0,191,175,92,0,177,175,144,71,192,12,
- 88,0,176,175,56,0,177,39,33,32,32,2,
- 33,40,0,0,2,0,16,36,40,0,176,167,
- 2,0,162,150,0,0,0,0,42,0,162,167,
- 19,0,130,138,16,0,130,154,0,0,0,0,
- 47,0,162,171,44,0,162,187,144,71,192,12,
- 16,0,6,36,33,32,64,2,33,40,96,2,
- 40,0,166,39,33,56,32,2,56,0,176,167,
- 0,0,162,150,2,131,16,60,8,239,16,38,
- 58,0,162,167,15,0,130,138,12,0,130,154,
- 0,0,0,0,63,0,162,171,60,0,162,187,
- 242,5,2,36,84,0,162,167,72,0,162,39,
- 72,0,160,167,76,0,176,175,80,0,176,175,
- 247,71,192,12,16,0,162,175,255,255,3,36,
- 22,0,67,16,12,0,145,38,33,32,224,2,
- 6,0,197,38,35,48,150,2,0,0,163,150,
- 4,0,2,36,16,0,162,175,161,0,2,36,
- 20,0,162,175,28,0,176,175,0,18,3,0,
- 2,26,3,0,37,16,67,0,255,255,66,48,
- 24,0,162,175,80,0,162,143,76,0,163,143,
- 33,56,32,2,35,16,67,0,255,255,66,48,
- 220,44,192,12,32,0,162,175,120,0,191,143,
- 116,0,183,143,112,0,182,143,108,0,181,143,
- 104,0,180,143,100,0,179,143,96,0,178,143,
- 92,0,177,143,88,0,176,143,8,0,224,3,
- 128,0,189,39,196,133,130,143,184,255,189,39,
- 64,0,191,175,60,0,177,175,109,0,64,16,
- 56,0,176,175,255,255,3,36,106,0,67,16,
- 0,0,0,0,176,133,130,143,176,133,145,39,
- 102,0,64,16,0,0,0,0,100,0,67,16,
- 0,0,0,0,2,131,2,60,8,239,66,36,
- 44,0,162,175,48,0,162,175,242,5,2,36,
- 40,0,160,167,6,0,128,16,52,0,162,167,
- 1,0,2,36,23,0,130,16,0,0,0,0,
- 36,46,192,8,0,0,0,0,2,131,16,60,
- 160,204,16,38,156,71,192,12,33,32,0,2,
- 0,163,4,60,4,1,132,140,204,204,3,60,
- 205,204,99,52,25,0,131,0,33,40,32,2,
- 33,48,0,2,33,56,64,0,40,0,164,39,
- 16,64,0,0,194,16,8,0,0,0,0,0,
- 104,56,192,12,16,0,162,175,251,45,192,8,
- 33,24,64,0,3,131,2,60,28,18,66,148,
- 0,0,0,0,2,0,66,48,61,0,64,16,
- 0,0,0,0,2,131,16,60,160,204,16,38,
- 156,71,192,12,33,32,0,2,0,163,4,60,
- 4,1,132,140,204,204,3,60,205,204,99,52,
- 25,0,131,0,33,40,32,2,33,48,0,2,
- 33,56,64,0,40,0,164,39,16,64,0,0,
- 194,16,8,0,0,0,0,0,105,57,192,12,
- 16,0,162,175,33,24,64,0,255,255,2,36,
- 39,0,98,16,0,0,0,0,140,129,130,147,
- 0,0,0,0,1,0,66,48,7,0,64,20,
- 0,0,0,0,68,133,131,143,152,129,130,143,
- 0,0,0,0,43,16,67,0,11,0,64,16,
- 33,32,0,0,68,133,131,143,148,129,130,143,
- 0,0,0,0,6,0,98,16,33,32,0,0,
- 196,133,133,143,148,129,131,175,17,43,192,12,
- 33,32,0,0,33,32,0,0,140,129,133,39,
- 14,0,6,36,4,0,2,36,16,0,162,175,
- 162,0,2,36,20,0,162,175,24,0,162,175,
- 2,131,2,60,8,239,66,36,28,0,162,175,
- 48,0,162,143,44,0,163,143,196,133,135,39,
- 35,16,67,0,255,255,66,48,220,44,192,12,
- 32,0,162,175,64,0,191,143,60,0,177,143,
- 56,0,176,143,8,0,224,3,72,0,189,39,
- 208,255,189,39,36,0,179,175,33,152,128,0,
- 40,0,180,175,33,160,160,0,32,0,178,175,
- 24,0,176,175,33,128,224,0,44,0,191,175,
- 28,0,177,175,6,0,2,150,64,0,177,143,
- 0,0,0,0,20,0,64,16,33,144,192,0,
- 12,0,68,38,8,0,5,36,192,42,192,12,
- 0,17,6,36,4,0,4,38,2,0,5,36,
- 192,42,192,12,255,255,70,48,33,32,0,2,
- 33,40,32,2,192,42,192,12,255,255,70,48,
- 255,255,66,48,255,255,3,52,4,0,67,16,
- 0,0,0,0,3,131,3,60,111,46,192,8,
- 120,17,99,36,4,0,2,150,0,0,0,0,
- 0,26,2,0,2,18,2,0,37,24,98,0,
- 255,255,99,48,4,0,113,16,8,0,7,38,
- 3,131,3,60,111,46,192,8,120,17,99,36,
- 2,0,2,150,0,0,0,0,0,26,2,0,
- 2,18,2,0,37,24,98,0,255,255,99,48,
- 161,0,2,36,15,0,98,20,248,255,40,38,
- 33,32,96,2,33,40,128,2,3,131,3,60,
- 112,17,99,36,0,0,98,140,33,48,64,2,
- 16,0,167,175,33,56,0,2,20,0,168,175,
- 1,0,66,36,86,45,192,12,0,0,98,172,
- 115,46,192,8,0,0,0,0,3,131,3,60,
- 116,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,44,0,191,143,
- 40,0,180,143,36,0,179,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 48,0,189,39,192,255,189,39,52,0,181,175,
- 33,168,128,0,44,0,179,175,33,152,160,0,
- 48,0,180,175,33,160,192,0,32,0,176,175,
- 33,128,224,0,33,32,0,2,33,48,0,0,
- 40,0,178,175,80,0,178,143,3,131,3,60,
- 144,16,99,36,56,0,191,175,36,0,177,175,
- 0,0,98,140,33,40,64,2,1,0,66,36,
- 192,42,192,12,0,0,98,172,255,255,66,48,
- 255,255,3,52,8,0,67,16,8,0,2,36,
- 3,131,2,60,148,16,66,140,0,0,0,0,
- 1,0,66,36,3,131,1,60,217,46,192,8,
- 148,16,34,172,0,0,3,150,0,0,0,0,
- 58,0,98,20,255,1,69,38,2,131,4,60,
- 192,4,132,36,3,131,2,60,172,16,66,140,
- 3,131,3,60,196,16,99,140,1,0,66,36,
- 1,0,99,36,3,131,1,60,172,16,34,172,
- 3,131,1,60,196,16,35,172,54,21,192,12,
- 2,42,5,0,33,136,64,0,8,0,32,22,
- 33,32,0,2,3,131,2,60,200,16,66,140,
- 0,0,0,0,1,0,66,36,3,131,1,60,
- 217,46,192,8,200,16,34,172,33,40,64,2,
- 33,48,0,0,0,0,0,162,192,42,192,12,
- 2,0,0,166,33,40,0,2,39,16,2,0,
- 2,0,162,164,4,0,36,142,0,0,0,0,
- 220,42,192,12,33,48,64,2,33,32,160,2,
- 6,0,101,38,35,48,147,2,0,0,67,140,
- 12,0,135,38,0,128,99,52,0,0,67,172,
- 1,0,3,36,18,0,50,166,16,0,163,175,
- 4,0,3,36,20,0,163,175,24,0,177,175,
- 23,44,192,12,28,0,162,175,3,131,2,60,
- 228,16,66,140,0,0,0,0,1,0,66,36,
- 3,131,1,60,228,16,34,172,56,0,191,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,64,0,189,39,200,255,189,39,
- 44,0,181,175,33,168,128,0,3,131,3,60,
- 4,17,99,36,48,0,191,175,40,0,180,175,
- 36,0,179,175,32,0,178,175,28,0,177,175,
- 24,0,176,175,0,0,98,140,33,136,160,0,
- 1,0,66,36,0,0,98,172,18,0,34,150,
- 0,0,0,0,255,255,84,48,243,5,130,46,
- 8,0,64,20,33,152,192,0,3,131,2,60,
- 8,17,66,140,0,0,0,0,1,0,66,36,
- 3,131,1,60,132,47,192,8,8,17,34,172,
- 2,131,18,60,18,233,82,38,33,32,64,2,
- 0,0,48,142,8,0,37,142,255,63,16,50,
- 80,68,192,12,33,48,0,2,0,0,34,142,
- 0,0,0,0,0,128,66,48,5,0,64,20,
- 33,144,80,2,4,0,49,142,0,0,0,0,
- 1,47,192,8,33,32,64,2,2,131,18,60,
- 18,233,82,38,33,128,114,2,16,0,17,38,
- 33,32,32,2,176,133,133,39,168,71,192,12,
- 4,0,6,36,9,0,64,16,33,32,32,2,
- 128,129,133,39,168,71,192,12,4,0,6,36,
- 4,0,64,16,0,0,0,0,3,131,3,60,
- 128,47,192,8,12,17,99,36,0,0,4,146,
- 64,0,2,36,240,0,131,48,4,0,98,16,
- 15,0,130,48,3,131,3,60,128,47,192,8,
- 8,17,99,36,128,136,2,0,20,0,34,42,
- 4,0,64,16,33,32,0,2,3,131,3,60,
- 128,47,192,8,8,17,99,36,33,40,32,2,
- 192,42,192,12,33,48,0,0,255,255,66,48,
- 255,255,3,52,4,0,67,16,0,0,0,0,
- 3,131,3,60,128,47,192,8,8,17,99,36,
- 6,0,2,150,0,0,0,0,63,255,66,48,
- 18,0,64,16,33,56,17,2,3,131,3,60,
- 48,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,3,131,2,60,
- 56,17,66,140,3,131,3,60,24,17,99,140,
- 1,0,66,36,1,0,99,36,3,131,1,60,
- 56,17,34,172,3,131,1,60,132,47,192,8,
- 24,17,35,172,2,0,2,150,0,0,0,0,
- 0,26,2,0,2,18,2,0,37,24,98,0,
- 255,255,99,48,35,64,113,0,35,16,242,0,
- 35,16,130,2,42,16,72,0,4,0,64,16,
- 1,0,2,36,3,131,3,60,128,47,192,8,
- 24,17,99,36,9,0,3,146,0,0,0,0,
- 5,0,98,16,17,0,2,36,15,0,98,16,
- 33,32,160,2,126,47,192,8,0,0,0,0,
- 33,32,160,2,33,40,64,2,3,131,3,60,
- 28,17,99,36,0,0,98,140,33,48,0,2,
- 16,0,168,175,1,0,66,36,123,46,192,12,
- 0,0,98,172,132,47,192,8,0,0,0,0,
- 33,40,64,2,3,131,3,60,28,17,99,36,
- 0,0,98,140,33,48,0,2,16,0,168,175,
- 1,0,66,36,41,46,192,12,0,0,98,172,
- 132,47,192,8,0,0,0,0,3,131,3,60,
- 20,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,48,0,191,143,
- 44,0,181,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,56,0,189,39,232,255,189,39,
- 255,0,12,60,255,0,140,53,0,255,13,60,
- 0,255,173,53,16,0,176,175,3,131,16,60,
- 0,17,16,38,33,32,0,2,33,40,0,0,
- 0,163,9,60,220,5,41,141,0,163,10,60,
- 16,6,74,141,0,163,11,60,224,5,107,141,
- 20,0,191,175,0,28,9,0,2,20,9,0,
- 37,24,98,0,0,60,10,0,2,20,10,0,
- 37,56,226,0,0,68,11,0,2,20,11,0,
- 37,64,2,1,2,18,3,0,36,16,76,0,
- 0,26,3,0,36,24,109,0,37,16,67,0,
- 184,133,130,175,2,18,7,0,36,16,76,0,
- 0,58,7,0,36,56,237,0,37,16,71,0,
- 192,133,130,175,2,18,8,0,36,16,76,0,
- 0,66,8,0,36,64,13,1,37,16,72,0,
- 176,133,137,175,196,133,138,175,188,133,139,175,
- 180,133,130,175,144,71,192,12,76,0,6,36,
- 3,131,4,60,144,16,132,36,33,40,0,0,
- 32,0,2,36,0,0,2,174,10,0,2,36,
- 3,131,1,60,44,17,34,172,144,71,192,12,
- 104,0,6,36,3,131,4,60,112,17,132,36,
- 33,40,0,0,144,71,192,12,16,0,6,36,
- 3,131,4,60,80,17,132,36,33,40,0,0,
- 144,71,192,12,32,0,6,36,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 176,255,189,39,100,0,162,143,96,0,169,143,
- 72,0,182,175,33,176,128,0,48,0,176,175,
- 104,0,176,143,34,0,164,39,60,0,179,175,
- 108,0,179,143,3,131,3,60,104,17,99,36,
- 56,0,178,175,2,131,18,60,212,4,82,38,
- 52,0,177,175,33,136,192,0,68,0,181,175,
- 112,0,181,143,4,0,6,36,76,0,191,175,
- 64,0,180,175,0,66,2,0,255,255,66,48,
- 2,18,2,0,37,64,2,1,0,0,98,140,
- 8,0,116,142,1,0,66,36,0,0,98,172,
- 3,0,162,136,0,0,162,152,4,0,163,128,
- 5,0,170,128,3,0,130,170,0,0,130,186,
- 4,0,131,162,5,0,138,162,3,0,66,138,
- 0,0,66,154,4,0,67,130,5,0,69,130,
- 9,0,130,170,6,0,130,186,10,0,131,162,
- 11,0,133,162,255,255,2,52,16,0,162,167,
- 18,0,98,150,33,40,0,0,20,0,160,163,
- 21,0,160,163,30,0,66,36,0,26,2,0,
- 255,255,66,48,2,18,2,0,37,24,98,0,
- 18,0,163,167,3,0,226,136,0,0,226,152,
- 0,0,0,0,25,0,162,171,22,0,162,187,
- 3,0,34,137,0,0,34,153,4,0,35,129,
- 5,0,39,129,29,0,162,171,26,0,162,187,
- 30,0,163,163,31,0,167,163,144,71,192,12,
- 32,0,168,167,3,0,66,138,0,0,66,154,
- 4,0,67,134,41,0,162,171,38,0,162,187,
- 42,0,163,167,33,16,0,2,0,130,16,0,
- 255,255,66,48,2,18,2,0,37,128,2,2,
- 14,0,2,36,58,0,34,22,44,0,176,167,
- 18,0,162,151,0,0,0,0,12,0,130,166,
- 19,0,162,139,16,0,162,155,23,0,163,139,
- 20,0,163,155,27,0,164,139,24,0,164,155,
- 31,0,165,139,28,0,165,155,17,0,130,170,
- 14,0,130,186,21,0,131,170,18,0,131,186,
- 25,0,132,170,22,0,132,186,29,0,133,170,
- 26,0,133,186,35,0,162,139,32,0,162,155,
- 39,0,163,139,36,0,163,155,43,0,164,139,
- 40,0,164,155,44,0,165,131,33,0,130,170,
- 30,0,130,186,37,0,131,170,34,0,131,186,
- 41,0,132,170,38,0,132,186,42,0,133,162,
- 45,0,162,131,0,0,0,0,43,0,130,162,
- 44,0,2,36,0,0,98,174,0,0,99,142,
- 18,0,98,150,0,0,0,0,33,16,67,0,
- 18,0,98,166,18,0,98,150,0,0,0,0,
- 60,0,66,44,80,0,64,16,33,32,192,2,
- 0,0,162,142,18,0,99,150,60,0,66,36,
- 35,16,67,0,0,0,162,174,60,0,2,36,
- 18,0,98,166,172,48,192,8,33,32,192,2,
- 208,129,133,39,3,0,162,136,0,0,162,152,
- 4,0,163,128,5,0,164,128,17,0,130,170,
- 14,0,130,186,18,0,131,162,19,0,132,162,
- 129,55,2,36,20,0,130,166,19,0,162,139,
- 16,0,162,155,23,0,163,139,20,0,163,155,
- 27,0,164,139,24,0,164,155,31,0,165,139,
- 28,0,165,155,25,0,130,170,22,0,130,186,
- 29,0,131,170,26,0,131,186,33,0,132,170,
- 30,0,132,186,37,0,133,170,34,0,133,186,
- 35,0,162,139,32,0,162,155,39,0,163,139,
- 36,0,163,155,43,0,164,139,40,0,164,155,
- 44,0,165,131,41,0,130,170,38,0,130,186,
- 45,0,131,170,42,0,131,186,49,0,132,170,
- 46,0,132,186,50,0,133,162,45,0,162,131,
- 0,0,0,0,51,0,130,162,52,0,2,36,
- 0,0,98,174,0,0,99,142,18,0,98,150,
- 0,0,0,0,33,16,67,0,18,0,98,166,
- 18,0,98,150,0,0,0,0,60,0,66,44,
- 8,0,64,16,0,0,0,0,0,0,162,142,
- 18,0,99,150,60,0,66,36,35,16,67,0,
- 0,0,162,174,60,0,2,36,18,0,98,166,
- 18,0,98,150,0,0,0,0,0,26,2,0,
- 2,18,2,0,37,24,98,0,12,0,131,166,
- 33,32,192,2,74,21,192,12,33,40,96,2,
- 8,0,64,20,33,32,96,2,3,131,3,60,
- 108,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,152,21,192,12,0,0,98,172,
- 76,0,191,143,72,0,182,143,68,0,181,143,
- 64,0,180,143,60,0,179,143,56,0,178,143,
- 52,0,177,143,48,0,176,143,8,0,224,3,
- 80,0,189,39,33,24,0,0,5,0,7,36,
- 58,0,6,36,0,0,162,144,0,0,0,0,
- 2,17,2,0,2,131,1,60,33,8,34,0,
- 176,155,34,144,0,0,0,0,0,0,130,160,
- 0,0,162,144,1,0,132,36,15,0,66,48,
- 2,131,1,60,33,8,34,0,176,155,34,144,
- 1,0,165,36,0,0,130,160,3,0,103,16,
- 1,0,132,36,0,0,134,160,1,0,132,36,
- 1,0,99,36,6,0,98,40,233,255,64,20,
- 0,0,0,0,8,0,224,3,0,0,0,0,
- 128,255,189,39,2,101,2,36,0,2,3,36,
- 112,0,176,175,44,0,176,39,33,32,0,2,
- 33,40,0,0,48,0,6,36,120,0,191,175,
- 116,0,177,175,40,0,162,167,144,71,192,12,
- 42,0,163,167,3,131,17,60,96,18,49,38,
- 2,131,5,60,224,147,165,36,188,71,192,12,
- 33,32,32,2,18,0,64,20,33,32,0,2,
- 2,131,5,60,236,147,165,36,0,0,162,140,
- 4,0,163,140,8,0,164,140,44,0,162,175,
- 48,0,163,175,52,0,164,175,12,0,162,128,
- 0,0,0,0,56,0,162,163,2,131,5,60,
- 212,4,165,36,193,48,192,12,56,0,164,39,
- 8,49,192,8,92,0,177,39,33,40,32,2,
- 204,63,192,12,48,0,6,36,92,0,177,39,
- 33,32,32,2,33,40,0,0,144,71,192,12,
- 4,0,6,36,2,131,4,60,212,4,132,36,
- 0,0,130,140,4,0,131,132,96,0,162,175,
- 100,0,163,167,4,82,2,36,0,1,3,36,
- 236,255,132,36,2,0,5,36,102,0,162,167,
- 54,21,192,12,104,0,163,167,33,128,64,0,
- 22,0,0,18,40,0,165,39,4,0,4,142,
- 0,0,0,0,220,42,192,12,66,0,6,36,
- 33,32,0,0,0,0,67,140,132,129,133,39,
- 0,128,99,52,0,0,67,172,4,0,3,142,
- 14,0,6,36,18,0,99,148,33,56,32,2,
- 18,0,3,166,82,4,3,36,16,0,165,175,
- 20,0,163,175,24,0,163,175,28,0,176,175,
- 214,47,192,12,32,0,162,175,120,0,191,143,
- 116,0,177,143,112,0,176,143,8,0,224,3,
- 128,0,189,39,144,255,189,39,104,0,180,175,
- 33,160,128,0,100,0,179,175,33,152,160,0,
- 92,0,177,175,33,136,192,0,33,32,224,0,
- 40,0,166,39,56,0,167,39,96,0,178,175,
- 2,131,18,60,8,239,82,38,88,0,176,175,
- 128,0,176,143,242,5,2,36,84,0,162,167,
- 72,0,162,39,108,0,191,175,72,0,160,167,
- 76,0,178,175,80,0,178,175,16,0,162,175,
- 247,71,192,12,33,40,0,2,255,255,3,36,
- 37,0,67,16,255,1,5,38,2,131,4,60,
- 192,4,132,36,54,21,192,12,2,42,5,0,
- 33,128,64,0,30,0,0,18,33,40,64,2,
- 80,0,166,143,76,0,162,143,4,0,4,142,
- 35,48,194,0,220,42,192,12,255,255,198,48,
- 33,32,128,2,0,0,67,140,6,0,101,38,
- 0,128,99,52,0,0,67,172,4,0,3,142,
- 35,48,51,2,18,0,99,148,18,0,39,38,
- 18,0,3,166,28,0,40,150,22,0,35,38,
- 16,0,163,175,15,144,3,52,24,0,163,175,
- 28,0,176,175,32,0,162,175,0,18,8,0,
- 2,66,8,0,37,16,72,0,255,255,66,48,
- 214,47,192,12,20,0,162,175,108,0,191,143,
- 104,0,180,143,100,0,179,143,96,0,178,143,
- 92,0,177,143,88,0,176,143,8,0,224,3,
- 112,0,189,39,200,255,189,39,44,0,181,175,
- 33,168,128,0,28,0,177,175,33,136,160,0,
- 48,0,191,175,40,0,180,175,36,0,179,175,
- 32,0,178,175,24,0,176,175,18,0,34,150,
- 0,0,0,0,255,255,84,48,243,5,130,46,
- 4,0,64,20,33,152,192,0,3,131,3,60,
- 241,49,192,8,84,17,99,36,2,131,18,60,
- 16,233,82,38,33,32,64,2,0,0,48,142,
- 8,0,37,142,255,63,16,50,80,68,192,12,
- 33,48,0,2,0,0,34,142,0,0,0,0,
- 0,128,66,48,5,0,64,20,33,144,80,2,
- 4,0,49,142,0,0,0,0,148,49,192,8,
- 33,32,64,2,2,131,2,60,16,233,66,36,
- 33,128,98,2,6,0,17,38,33,32,32,2,
- 0,163,5,60,224,5,165,52,168,71,192,12,
- 4,0,6,36,9,0,64,16,33,32,32,2,
- 224,129,133,39,168,71,192,12,4,0,6,36,
- 5,0,64,16,10,0,17,38,3,131,3,60,
- 241,49,192,8,88,17,99,36,10,0,17,38,
- 33,32,32,2,2,131,5,60,212,4,165,36,
- 168,71,192,12,6,0,6,36,9,0,64,16,
- 33,32,32,2,228,129,133,39,168,71,192,12,
- 6,0,6,36,4,0,64,16,0,0,0,0,
- 3,131,3,60,241,49,192,8,88,17,99,36,
- 0,0,3,150,255,255,2,52,4,0,98,16,
- 30,0,7,38,3,131,3,60,241,49,192,8,
- 88,17,99,36,2,0,2,150,2,131,5,60,
- 16,233,165,36,0,26,2,0,2,18,2,0,
- 37,24,98,0,255,255,99,48,226,255,104,36,
- 35,16,229,0,35,16,130,2,42,16,72,0,
- 4,0,64,16,0,0,0,0,3,131,3,60,
- 241,49,192,8,96,17,99,36,16,0,2,150,
- 0,0,0,0,0,26,2,0,2,18,2,0,
- 37,24,98,0,255,255,99,48,15,144,2,52,
- 11,0,98,20,33,32,160,2,3,131,3,60,
- 100,17,99,36,0,0,98,140,33,48,0,2,
- 16,0,168,175,1,0,66,36,54,49,192,12,
- 0,0,98,172,245,49,192,8,0,0,0,0,
- 3,131,3,60,92,17,99,36,0,0,98,140,
- 0,0,0,0,1,0,66,36,0,0,98,172,
- 48,0,191,143,44,0,181,143,40,0,180,143,
- 36,0,179,143,32,0,178,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,56,0,189,39,
- 0,0,0,0,0,0,0,0,232,255,189,39,
- 16,0,191,175,13,8,192,12,0,8,4,36,
- 8,133,130,175,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,232,255,189,39,
- 45,0,128,16,16,0,191,175,240,129,133,143,
- 7,0,130,36,194,16,2,0,10,0,160,20,
- 1,0,70,36,8,133,133,143,0,133,130,39,
- 0,133,133,175,0,0,162,172,0,8,2,36,
- 240,129,133,175,2,131,1,60,20,211,32,172,
- 4,0,162,172,0,0,164,140,0,0,0,0,
- 4,0,131,140,0,0,0,0,43,16,102,0,
- 14,0,64,20,0,0,0,0,5,0,102,20,
- 35,16,102,0,0,0,130,140,0,0,0,0,
- 43,50,192,8,0,0,162,172,4,0,130,172,
- 192,16,2,0,33,32,130,0,4,0,134,172,
- 240,129,133,175,57,50,192,8,8,0,130,36,
- 240,129,130,143,0,0,0,0,4,0,130,16,
- 33,40,128,0,0,0,132,140,28,50,192,8,
- 0,0,0,0,2,131,4,60,15,63,192,12,
- 64,148,132,36,33,16,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 56,0,128,16,248,255,132,36,240,129,133,143,
- 0,0,0,0,78,50,192,8,43,16,164,0,
- 0,0,163,140,0,0,0,0,43,16,163,0,
- 5,0,64,20,43,16,164,0,12,0,64,20,
- 43,16,131,0,10,0,64,20,0,0,0,0,
- 33,40,96,0,43,16,164,0,244,255,64,16,
- 0,0,0,0,0,0,162,140,0,0,0,0,
- 43,16,130,0,239,255,64,16,0,0,0,0,
- 4,0,134,140,0,0,163,140,192,16,6,0,
- 33,16,130,0,11,0,67,20,0,0,0,0,
- 4,0,98,140,0,0,0,0,33,16,194,0,
- 4,0,130,172,0,0,162,140,0,0,0,0,
- 0,0,66,140,0,0,0,0,102,50,192,8,
- 0,0,130,172,0,0,131,172,4,0,163,140,
- 0,0,0,0,192,16,3,0,33,16,162,0,
- 9,0,68,20,0,0,0,0,4,0,130,140,
- 0,0,0,0,33,16,98,0,4,0,162,172,
- 0,0,130,140,0,0,0,0,117,50,192,8,
- 0,0,162,172,0,0,164,172,240,129,133,175,
- 8,0,224,3,0,0,0,0,232,255,189,39,
- 16,0,191,175,0,50,192,12,0,0,0,0,
- 178,45,192,12,33,32,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 1,0,3,36,5,0,195,20,255,255,2,36,
- 0,0,226,140,0,0,0,0,43,16,2,0,
- 35,16,2,0,8,0,224,3,0,0,0,0,
- 224,255,189,39,16,0,176,175,33,128,224,0,
- 20,0,177,175,48,0,177,143,1,0,2,36,
- 5,0,162,20,24,0,191,175,0,0,194,140,
- 0,0,0,0,8,0,64,16,0,0,0,0,
- 11,0,2,36,33,32,0,2,33,40,32,2,
- 48,72,192,12,96,0,2,174,1,0,66,36,
- 100,0,2,174,17,0,34,146,0,0,0,0,
- 1,0,66,52,17,0,34,162,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,8,0,224,3,0,0,0,0,
- 16,0,163,143,0,0,0,0,17,0,98,144,
- 0,0,0,0,2,0,66,52,8,0,224,3,
- 17,0,98,160,8,0,224,3,0,0,0,0,
- 224,255,189,39,16,0,176,175,33,128,128,0,
- 244,129,131,151,255,0,2,36,28,0,191,175,
- 24,0,178,175,20,0,177,175,4,0,2,174,
- 60,0,0,174,1,0,98,36,244,129,130,167,
- 10,0,3,166,3,0,162,136,0,0,162,152,
- 7,0,163,136,4,0,163,152,11,0,164,136,
- 8,0,164,152,15,0,167,136,12,0,167,152,
- 15,0,2,170,12,0,2,186,19,0,3,170,
- 16,0,3,186,23,0,4,170,20,0,4,186,
- 27,0,7,170,24,0,7,186,3,0,194,136,
- 0,0,194,152,7,0,195,136,4,0,195,152,
- 11,0,196,136,8,0,196,152,15,0,197,136,
- 12,0,197,152,31,0,2,170,28,0,2,186,
- 35,0,3,170,32,0,3,186,39,0,4,170,
- 36,0,4,186,43,0,5,170,40,0,5,186,
- 80,0,2,142,76,0,3,142,0,0,0,0,
- 35,16,67,0,255,255,81,48,88,0,3,150,
- 3,0,2,36,13,0,98,16,0,0,0,0,
- 2,131,18,60,160,204,82,38,156,71,192,12,
- 33,32,64,2,7,0,81,20,33,32,64,2,
- 76,0,5,142,0,0,0,0,168,71,192,12,
- 33,48,32,2,21,0,64,16,33,16,0,0,
- 2,131,18,60,192,204,82,38,156,71,192,12,
- 33,32,64,2,7,0,81,20,33,32,64,2,
- 76,0,5,142,0,0,0,0,168,71,192,12,
- 33,48,32,2,9,0,64,16,33,16,0,0,
- 3,131,3,60,132,17,99,36,0,0,98,140,
- 1,0,4,36,1,0,66,36,178,45,192,12,
- 0,0,98,172,1,0,2,36,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,0,0,0,0,
- 0,0,0,0,224,255,189,39,20,0,177,175,
- 33,136,224,0,16,0,176,175,48,0,176,143,
- 24,0,191,175,156,71,192,12,33,32,32,2,
- 0,0,2,174,33,16,32,2,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,8,0,224,3,33,16,224,0,
- 0,0,227,140,204,204,2,60,205,204,66,52,
- 25,0,98,0,16,32,0,0,0,0,0,0,
- 0,0,0,0,8,0,224,3,194,16,4,0,
- 224,255,189,39,16,0,176,175,33,128,224,0,
- 33,32,0,2,33,40,0,0,20,0,177,175,
- 48,0,177,143,24,0,191,175,208,71,192,12,
- 16,0,6,36,2,0,64,20,35,16,80,0,
- 16,0,2,36,0,0,34,174,33,16,0,2,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,232,255,189,39,
- 40,0,164,143,44,0,165,143,16,0,191,175,
- 205,59,192,12,0,0,0,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,40,0,164,143,44,0,165,143,
- 16,0,191,175,239,59,192,12,0,0,0,0,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,232,255,189,39,40,0,164,143,
- 44,0,165,143,16,0,191,175,17,60,192,12,
- 0,0,0,0,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,8,0,224,3,
- 33,16,224,0,0,0,226,140,8,0,224,3,
- 0,0,0,0,216,255,189,39,24,0,176,175,
- 56,0,176,143,32,0,191,175,28,0,177,175,
- 36,0,2,142,1,0,3,36,20,0,81,140,
- 187,0,163,20,0,0,0,0,0,0,195,140,
- 0,0,0,0,183,0,96,16,0,0,0,0,
- 32,133,130,143,0,0,0,0,43,16,67,0,
- 178,0,64,20,255,255,104,36,64,18,8,0,
- 2,131,3,60,192,246,99,36,33,40,67,0,
- 255,255,132,36,22,0,130,44,170,0,64,16,
- 128,16,4,0,2,131,1,60,33,8,34,0,
- 144,148,34,140,0,0,0,0,8,0,64,0,
- 0,0,0,0,2,0,2,36,16,0,2,162,
- 17,0,2,146,0,0,195,140,0,0,0,0,
- 15,52,192,8,2,0,66,52,33,32,32,2,
- 17,0,3,146,4,0,2,36,16,0,2,162,
- 40,0,0,166,44,0,17,174,2,0,99,52,
- 156,71,192,12,17,0,3,162,255,255,66,48,
- 33,16,34,2,48,0,2,174,40,52,192,8,
- 52,0,0,166,17,0,3,146,2,0,2,36,
- 16,0,2,162,243,51,192,8,40,0,17,174,
- 17,0,3,146,2,0,2,36,16,0,2,162,
- 243,51,192,8,40,0,17,174,66,0,2,36,
- 13,0,0,21,16,0,2,162,24,133,132,143,
- 0,0,0,0,64,25,4,0,35,24,100,0,
- 128,17,3,0,35,16,67,0,192,16,2,0,
- 33,16,68,0,128,24,2,0,33,16,67,0,
- 178,51,192,8,192,17,2,0,152,0,2,60,
- 128,150,66,52,40,0,2,174,17,0,2,146,
- 0,0,0,0,199,51,192,8,2,0,66,52,
- 17,0,3,146,4,0,2,36,16,0,2,162,
- 20,0,162,36,44,0,2,174,26,0,162,36,
- 40,0,0,166,48,0,2,174,243,51,192,8,
- 52,0,0,166,2,0,2,36,16,0,2,162,
- 17,0,2,146,1,0,3,36,40,0,3,174,
- 2,0,66,52,40,52,192,8,17,0,2,162,
- 17,0,3,146,0,0,0,0,241,51,192,8,
- 67,0,2,36,65,0,2,36,16,0,2,162,
- 17,0,2,146,168,0,163,140,0,0,0,0,
- 15,52,192,8,2,0,66,52,65,0,2,36,
- 16,0,2,162,156,0,162,140,0,1,164,140,
- 22,52,192,8,0,0,0,0,65,0,2,36,
- 16,0,2,162,17,0,2,146,0,1,163,140,
- 0,0,0,0,15,52,192,8,2,0,66,52,
- 65,0,2,36,16,0,2,162,17,0,2,146,
- 164,0,163,140,0,0,0,0,15,52,192,8,
- 2,0,66,52,65,0,2,36,16,0,2,162,
- 17,0,2,146,160,0,163,140,0,0,0,0,
- 15,52,192,8,2,0,66,52,17,0,3,146,
- 65,0,2,36,16,0,2,162,40,0,0,174,
- 2,0,99,52,40,52,192,8,17,0,3,162,
- 65,0,2,36,16,0,2,162,172,0,162,140,
- 4,1,164,140,22,52,192,8,0,0,0,0,
- 65,0,2,36,16,0,2,162,17,0,2,146,
- 4,1,163,140,0,0,0,0,15,52,192,8,
- 2,0,66,52,65,0,2,36,16,0,2,162,
- 17,0,2,146,184,0,163,140,0,0,0,0,
- 15,52,192,8,2,0,66,52,65,0,2,36,
- 16,0,2,162,17,0,2,146,188,0,163,140,
- 2,0,66,52,40,0,3,174,40,52,192,8,
- 17,0,2,162,66,0,2,36,16,0,2,162,
- 172,0,162,140,176,0,164,140,17,0,3,146,
- 35,16,68,0,2,0,99,52,40,0,2,174,
- 40,52,192,8,17,0,3,162,16,0,160,175,
- 33,32,224,0,33,40,0,2,2,131,7,60,
- 96,204,231,36,226,76,192,12,2,0,6,36,
- 40,52,192,8,0,0,0,0,33,32,224,0,
- 200,76,192,12,33,40,0,2,32,0,191,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 40,0,189,39,224,255,189,39,16,0,176,175,
- 33,128,224,0,20,0,177,175,48,0,177,143,
- 1,0,2,36,10,0,162,20,24,0,191,175,
- 0,0,198,140,0,0,0,0,6,0,192,16,
- 0,0,0,0,32,133,130,143,0,0,0,0,
- 43,16,70,0,5,0,64,16,7,0,2,36,
- 33,32,0,2,33,40,32,2,70,52,192,8,
- 11,0,2,36,7,0,130,16,33,32,0,2,
- 33,40,32,2,17,0,2,36,48,72,192,12,
- 96,0,2,174,1,0,66,36,100,0,2,174,
- 17,0,34,146,0,0,0,0,1,0,66,52,
- 17,0,34,162,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 208,255,189,39,32,0,176,175,64,0,176,143,
- 36,0,177,175,33,136,224,0,4,0,160,20,
- 40,0,191,175,1,0,2,36,106,52,192,8,
- 24,0,162,175,0,0,198,140,32,133,130,143,
- 0,0,0,0,43,16,194,0,3,0,64,16,
- 1,0,194,36,106,52,192,8,24,0,162,175,
- 17,0,2,146,0,0,0,0,18,0,66,52,
- 116,52,192,8,17,0,2,162,16,0,176,175,
- 1,0,5,36,24,0,166,39,97,51,192,12,
- 33,56,32,2,33,32,32,2,33,40,0,2,
- 1,0,6,36,253,76,192,12,24,0,167,39,
- 40,0,191,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,48,0,189,39,16,0,163,143,
- 1,0,2,36,13,0,162,20,14,0,2,36,
- 0,0,198,140,0,0,0,0,9,0,192,16,
- 0,0,0,0,32,133,130,143,0,0,0,0,
- 43,16,70,0,4,0,64,20,14,0,2,36,
- 7,0,2,36,2,0,130,16,14,0,2,36,
- 96,0,226,172,17,0,98,144,0,0,0,0,
- 2,0,66,52,8,0,224,3,17,0,98,160,
- 16,0,162,143,0,0,0,0,8,0,224,3,
- 0,0,226,172,0,0,226,140,8,0,224,3,
- 0,0,0,0,232,255,189,39,40,0,168,143,
- 1,0,2,36,61,0,162,20,16,0,191,175,
- 0,0,197,140,0,0,0,0,57,0,160,16,
- 0,0,0,0,32,133,130,143,0,0,0,0,
- 43,16,69,0,52,0,64,20,255,255,132,36,
- 5,0,130,44,49,0,64,16,128,16,4,0,
- 2,131,1,60,33,8,34,0,232,148,34,140,
- 0,0,0,0,8,0,64,0,0,0,0,0,
- 64,0,2,36,16,0,2,161,0,163,5,60,
- 220,5,165,52,3,0,162,136,0,0,162,152,
- 0,0,0,0,43,0,2,169,40,0,2,185,
- 17,0,2,145,0,0,0,0,213,52,192,8,
- 2,0,66,52,2,0,2,36,16,0,2,161,
- 17,0,2,145,0,0,195,140,0,0,0,0,
- 198,52,192,8,2,0,66,52,64,0,2,36,
- 16,0,2,161,17,0,2,145,128,132,131,143,
- 2,0,66,52,40,0,3,173,218,52,192,8,
- 17,0,2,161,2,0,2,36,16,0,2,161,
- 17,0,2,145,0,0,0,0,211,52,192,8,
- 1,0,3,36,2,0,2,36,16,0,2,161,
- 17,0,2,145,220,5,3,36,40,0,3,173,
- 2,0,66,52,218,52,192,8,17,0,2,161,
- 33,32,224,0,200,76,192,12,33,40,0,1,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,208,255,189,39,32,0,176,175,
- 64,0,176,143,36,0,177,175,33,136,224,0,
- 4,0,160,20,40,0,191,175,1,0,2,36,
- 245,52,192,8,24,0,162,175,0,0,198,140,
- 32,133,130,143,0,0,0,0,43,16,194,0,
- 3,0,64,16,1,0,194,36,245,52,192,8,
- 24,0,162,175,17,0,2,146,0,0,0,0,
- 18,0,66,52,255,52,192,8,17,0,2,162,
- 16,0,176,175,1,0,5,36,24,0,166,39,
- 150,52,192,12,33,56,32,2,33,32,32,2,
- 33,40,0,2,1,0,6,36,253,76,192,12,
- 24,0,167,39,40,0,191,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,48,0,189,39,
- 232,255,189,39,40,0,165,143,16,0,191,175,
- 200,76,192,12,33,32,224,0,16,0,191,143,
- 24,0,189,39,8,0,224,3,0,0,0,0,
- 16,0,163,143,14,0,2,36,96,0,226,172,
- 17,0,98,144,0,0,0,0,2,0,66,52,
- 8,0,224,3,17,0,98,160,224,255,189,39,
- 16,0,176,175,33,128,224,0,17,0,2,36,
- 24,0,191,175,20,0,177,175,96,0,2,174,
- 48,0,177,143,33,32,0,2,48,72,192,12,
- 33,40,32,2,1,0,66,36,100,0,2,174,
- 17,0,34,146,0,0,0,0,1,0,66,52,
- 17,0,34,162,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 16,0,163,143,0,0,0,0,17,0,98,144,
- 0,0,0,0,18,0,66,52,8,0,224,3,
- 17,0,98,160,8,0,224,3,33,16,224,0,
- 224,255,189,39,48,0,168,143,1,0,2,36,
- 114,0,162,20,24,0,191,175,0,0,195,140,
- 0,0,0,0,110,0,96,16,0,0,0,0,
- 32,133,130,143,0,0,0,0,43,16,67,0,
- 105,0,64,20,255,255,98,36,64,18,2,0,
- 2,131,3,60,192,246,99,36,33,24,67,0,
- 255,255,132,36,17,0,130,44,97,0,64,16,
- 128,16,4,0,2,131,1,60,33,8,34,0,
- 0,149,34,140,0,0,0,0,8,0,64,0,
- 0,0,0,0,2,0,2,36,16,0,2,161,
- 17,0,2,145,0,0,195,140,0,0,0,0,
- 140,53,192,8,2,0,66,52,2,0,2,36,
- 16,0,2,161,44,0,99,140,17,0,2,145,
- 16,0,99,140,0,0,0,0,101,53,192,8,
- 2,0,66,52,2,0,2,36,16,0,2,161,
- 44,0,99,140,17,0,2,145,12,0,99,140,
- 2,0,66,52,17,0,2,161,173,53,192,8,
- 40,0,3,173,2,0,2,36,16,0,2,161,
- 17,0,2,145,212,0,99,140,0,0,0,0,
- 140,53,192,8,2,0,66,52,2,0,2,36,
- 16,0,2,161,17,0,2,145,192,0,99,140,
- 0,0,0,0,140,53,192,8,2,0,66,52,
- 2,0,2,36,16,0,2,161,17,0,2,145,
- 208,0,99,140,0,0,0,0,140,53,192,8,
- 2,0,66,52,2,0,2,36,16,0,2,161,
- 204,0,98,140,184,0,100,140,17,0,3,145,
- 33,16,68,0,2,0,99,52,40,0,2,173,
- 173,53,192,8,17,0,3,161,2,0,2,36,
- 16,0,2,161,17,0,2,145,196,0,99,140,
- 2,0,66,52,40,0,3,173,173,53,192,8,
- 17,0,2,161,17,0,3,145,2,0,2,36,
- 16,0,2,161,40,0,0,173,2,0,99,52,
- 173,53,192,8,17,0,3,161,2,0,2,36,
- 16,0,2,161,44,0,100,140,17,0,2,145,
- 20,0,131,140,24,0,132,140,2,0,66,52,
- 17,0,2,161,33,24,100,0,173,53,192,8,
- 40,0,3,173,16,0,160,175,33,32,224,0,
- 33,40,0,1,2,131,7,60,104,204,231,36,
- 226,76,192,12,11,0,6,36,173,53,192,8,
- 0,0,0,0,33,32,224,0,200,76,192,12,
- 33,40,0,1,24,0,191,143,32,0,189,39,
- 8,0,224,3,0,0,0,0,208,255,189,39,
- 32,0,176,175,64,0,176,143,36,0,177,175,
- 33,136,224,0,4,0,160,20,40,0,191,175,
- 1,0,2,36,200,53,192,8,24,0,162,175,
- 0,0,198,140,32,133,130,143,0,0,0,0,
- 43,16,194,0,3,0,64,16,1,0,194,36,
- 200,53,192,8,24,0,162,175,17,0,2,146,
- 0,0,0,0,18,0,66,52,210,53,192,8,
- 17,0,2,162,16,0,176,175,1,0,5,36,
- 24,0,166,39,52,53,192,12,33,56,32,2,
- 33,32,32,2,33,40,0,2,1,0,6,36,
- 253,76,192,12,24,0,167,39,40,0,191,143,
- 36,0,177,143,32,0,176,143,8,0,224,3,
- 48,0,189,39,0,0,226,140,8,0,224,3,
- 0,0,0,0,3,131,2,60,28,18,66,148,
- 0,0,0,0,2,0,66,48,2,0,64,16,
- 2,0,3,36,1,0,3,36,8,0,224,3,
- 33,16,96,0,232,255,189,39,40,0,164,143,
- 16,0,191,175,1,0,132,56,186,59,192,12,
- 1,0,132,44,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,16,0,163,143,
- 6,0,2,36,0,0,98,172,8,0,224,3,
- 33,16,224,0,224,255,189,39,48,0,168,143,
- 1,0,2,36,52,0,162,20,24,0,191,175,
- 0,0,197,140,0,0,0,0,48,0,160,16,
- 0,0,0,0,24,133,130,143,0,0,0,0,
- 43,16,69,0,43,0,64,20,255,255,132,36,
- 5,0,130,44,40,0,64,16,128,16,4,0,
- 2,131,1,60,33,8,34,0,72,149,34,140,
- 0,0,0,0,8,0,64,0,0,0,0,0,
- 2,0,2,36,16,0,2,161,17,0,2,145,
- 0,0,195,140,2,0,66,52,40,0,3,173,
- 45,54,192,8,17,0,2,161,2,0,2,36,
- 16,0,2,161,0,0,194,140,17,0,3,145,
- 1,0,66,36,2,0,99,52,40,0,2,173,
- 45,54,192,8,17,0,3,161,16,0,160,175,
- 33,32,224,0,33,40,0,1,2,131,7,60,
- 148,204,231,36,226,76,192,12,2,0,6,36,
- 45,54,192,8,0,0,0,0,17,0,3,145,
- 2,0,2,36,16,0,2,161,40,0,0,173,
- 2,0,99,52,45,54,192,8,17,0,3,161,
- 33,32,224,0,200,76,192,12,33,40,0,1,
- 24,0,191,143,32,0,189,39,8,0,224,3,
- 0,0,0,0,208,255,189,39,32,0,176,175,
- 64,0,176,143,36,0,177,175,33,136,224,0,
- 4,0,160,20,40,0,191,175,1,0,2,36,
- 72,54,192,8,24,0,162,175,0,0,198,140,
- 24,133,130,143,0,0,0,0,43,16,194,0,
- 3,0,64,16,1,0,194,36,72,54,192,8,
- 24,0,162,175,17,0,2,146,0,0,0,0,
- 18,0,66,52,82,54,192,8,17,0,2,162,
- 16,0,176,175,1,0,5,36,24,0,166,39,
- 242,53,192,12,33,56,32,2,33,32,32,2,
- 33,40,0,2,1,0,6,36,253,76,192,12,
- 24,0,167,39,40,0,191,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,48,0,189,39,
- 0,0,226,148,8,0,224,3,0,0,0,0,
- 8,0,224,3,33,16,224,0,16,0,163,143,
- 8,0,2,36,0,0,98,172,8,0,224,3,
- 33,16,224,0,224,255,189,39,16,0,176,175,
- 48,0,176,143,1,0,2,36,24,0,191,175,
- 126,0,162,20,20,0,177,175,0,0,198,140,
- 0,0,0,0,122,0,192,16,0,0,0,0,
- 24,133,130,143,0,0,0,0,43,16,70,0,
- 117,0,64,20,192,17,6,0,3,131,3,60,
- 16,13,99,36,33,136,67,0,255,255,132,36,
- 10,0,130,44,110,0,64,16,128,16,4,0,
- 2,131,1,60,33,8,34,0,96,149,34,140,
- 0,0,0,0,8,0,64,0,0,0,0,0,
- 17,0,3,146,2,0,2,36,16,0,2,162,
- 211,54,192,8,40,0,6,174,2,0,2,36,
- 16,0,2,162,0,0,34,150,17,0,3,146,
- 0,0,0,0,143,54,192,8,2,18,2,0,
- 2,0,2,36,16,0,2,162,4,0,34,142,
- 17,0,3,146,1,0,66,36,2,0,99,52,
- 40,0,2,174,232,54,192,8,17,0,3,162,
- 2,0,2,36,16,0,2,162,4,0,34,142,
- 0,0,0,0,2,0,64,16,2,0,3,36,
- 1,0,3,36,17,0,2,146,40,0,3,174,
- 2,0,66,52,232,54,192,8,17,0,2,162,
- 2,0,2,36,16,0,2,162,17,0,2,146,
- 8,0,35,142,0,0,0,0,226,54,192,8,
- 2,0,66,52,9,50,192,12,8,0,4,36,
- 33,48,64,0,15,0,34,138,12,0,34,154,
- 19,0,35,138,16,0,35,154,3,0,194,168,
- 0,0,194,184,7,0,195,168,196,54,192,8,
- 4,0,195,184,2,0,2,36,16,0,2,162,
- 17,0,2,146,20,0,35,142,0,0,0,0,
- 226,54,192,8,2,0,66,52,9,50,192,12,
- 8,0,4,36,33,48,64,0,27,0,34,138,
- 24,0,34,154,31,0,35,138,28,0,35,154,
- 3,0,194,168,0,0,194,184,7,0,195,168,
- 4,0,195,184,0,0,194,148,0,0,0,0,
- 0,26,2,0,2,18,2,0,37,24,98,0,
- 0,0,195,164,17,0,3,146,4,0,2,36,
- 16,0,2,162,1,0,2,36,40,0,2,166,
- 8,0,194,36,44,0,6,174,48,0,2,174,
- 52,0,0,166,2,0,99,52,232,54,192,8,
- 17,0,3,162,2,0,2,36,16,0,2,162,
- 17,0,2,146,32,0,35,150,0,0,0,0,
- 226,54,192,8,2,0,66,52,2,0,2,36,
- 16,0,2,162,17,0,2,146,104,0,35,142,
- 2,0,66,52,40,0,3,174,232,54,192,8,
- 17,0,2,162,33,32,224,0,200,76,192,12,
- 33,40,0,2,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 224,255,189,39,16,0,176,175,33,128,224,0,
- 20,0,177,175,48,0,177,143,1,0,2,36,
- 10,0,162,20,24,0,191,175,0,0,198,140,
- 0,0,0,0,6,0,192,16,0,0,0,0,
- 24,133,130,143,0,0,0,0,43,16,70,0,
- 5,0,64,16,2,0,2,36,33,32,0,2,
- 33,40,32,2,13,55,192,8,11,0,2,36,
- 14,0,130,16,2,0,130,44,5,0,64,20,
- 6,0,130,44,3,0,64,16,4,0,130,44,
- 8,0,64,16,0,0,0,0,33,32,0,2,
- 33,40,32,2,17,0,2,36,48,72,192,12,
- 96,0,2,174,1,0,66,36,100,0,2,174,
- 17,0,34,146,0,0,0,0,1,0,66,52,
- 17,0,34,162,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 208,255,189,39,32,0,176,175,64,0,176,143,
- 36,0,177,175,33,136,224,0,4,0,160,20,
- 40,0,191,175,1,0,2,36,49,55,192,8,
- 24,0,162,175,0,0,198,140,24,133,130,143,
- 0,0,0,0,43,16,194,0,3,0,64,16,
- 1,0,194,36,49,55,192,8,24,0,162,175,
- 17,0,2,146,0,0,0,0,18,0,66,52,
- 59,55,192,8,17,0,2,162,16,0,176,175,
- 1,0,5,36,24,0,166,39,97,54,192,12,
- 33,56,32,2,33,32,32,2,33,40,0,2,
- 1,0,6,36,253,76,192,12,24,0,167,39,
- 40,0,191,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,48,0,189,39,232,255,189,39,
- 33,64,128,0,16,0,176,175,40,0,176,143,
- 1,0,2,36,57,0,162,20,20,0,191,175,
- 0,0,196,140,0,0,0,0,54,0,128,16,
- 14,0,2,36,24,133,130,143,0,0,0,0,
- 43,16,68,0,49,0,64,20,14,0,2,36,
- 192,17,4,0,3,131,3,60,16,13,99,36,
- 33,48,67,0,4,0,2,36,21,0,2,17,
- 5,0,2,45,5,0,64,16,2,0,2,36,
- 8,0,2,17,14,0,2,36,129,55,192,8,
- 96,0,226,172,5,0,2,36,28,0,2,17,
- 14,0,2,36,129,55,192,8,96,0,226,172,
- 0,0,195,144,0,0,0,0,0,0,195,164,
- 40,0,2,142,0,0,0,0,0,18,2,0,
- 37,24,98,0,129,55,192,8,0,0,195,164,
- 40,0,3,142,0,0,0,0,5,0,101,16,
- 2,0,2,36,7,0,98,16,14,0,2,36,
- 129,55,192,8,96,0,226,172,187,42,192,12,
- 1,0,5,36,129,55,192,8,0,0,0,0,
- 187,42,192,12,33,40,0,0,129,55,192,8,
- 0,0,0,0,40,0,2,142,0,0,0,0,
- 129,55,192,8,8,0,194,172,14,0,2,36,
- 96,0,226,172,17,0,2,146,0,0,0,0,
- 2,0,66,52,17,0,2,162,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 216,255,189,39,20,0,177,175,33,136,128,0,
- 28,0,179,175,33,152,160,0,24,0,178,175,
- 33,144,224,0,16,0,176,175,56,0,176,143,
- 1,0,2,36,46,0,98,22,32,0,191,175,
- 0,0,196,140,0,0,0,0,42,0,128,16,
- 0,0,0,0,58,25,192,12,0,0,0,0,
- 33,32,64,0,37,0,128,16,2,0,2,36,
- 11,0,34,18,3,0,34,46,5,0,64,16,
- 3,0,2,36,15,0,51,18,4,0,2,36,
- 195,55,192,8,33,32,64,2,20,0,34,18,
- 33,32,64,2,195,55,192,8,0,0,0,0,
- 2,0,2,36,16,0,2,162,17,0,2,146,
- 10,0,131,132,2,0,66,52,40,0,3,174,
- 197,55,192,8,17,0,2,162,17,0,3,146,
- 16,0,2,162,4,0,130,36,44,0,2,174,
- 10,0,130,36,40,0,0,166,48,0,2,174,
- 191,55,192,8,52,0,0,166,17,0,3,146,
- 2,0,2,36,16,0,2,162,40,0,17,174,
- 2,0,99,52,197,55,192,8,17,0,3,162,
- 33,32,64,2,200,76,192,12,33,40,0,2,
- 32,0,191,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,208,255,189,39,32,0,176,175,
- 64,0,176,143,40,0,178,175,33,144,128,0,
- 36,0,177,175,33,136,224,0,3,0,160,20,
- 44,0,191,175,218,55,192,8,1,0,2,36,
- 0,0,194,140,0,0,0,0,1,0,66,36,
- 24,0,162,175,24,0,164,143,58,25,192,12,
- 0,0,0,0,6,0,64,20,33,32,64,2,
- 17,0,2,146,0,0,0,0,18,0,66,52,
- 239,55,192,8,17,0,2,162,16,0,176,175,
- 1,0,5,36,24,0,166,39,137,55,192,12,
- 33,56,32,2,33,32,32,2,33,40,0,2,
- 1,0,6,36,253,76,192,12,24,0,167,39,
- 44,0,191,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,48,0,189,39,
- 232,255,189,39,40,0,168,143,1,0,2,36,
- 63,0,162,20,16,0,191,175,0,0,195,140,
- 0,0,0,0,59,0,96,16,0,0,0,0,
- 24,133,130,143,0,0,0,0,43,16,67,0,
- 54,0,64,20,64,18,3,0,2,131,3,60,
- 192,246,99,36,33,24,67,0,255,255,132,36,
- 5,0,130,44,47,0,64,16,128,16,4,0,
- 2,131,1,60,33,8,34,0,136,149,34,140,
- 0,0,0,0,8,0,64,0,0,0,0,0,
- 2,0,2,36,16,0,2,161,17,0,2,145,
- 0,0,195,140,0,0,0,0,43,56,192,8,
- 2,0,66,52,2,0,2,36,16,0,2,161,
- 17,0,2,145,220,5,3,36,40,0,3,173,
- 2,0,66,52,59,56,192,8,17,0,2,161,
- 65,0,2,36,16,0,2,161,17,0,2,145,
- 156,0,99,140,0,0,0,0,43,56,192,8,
- 2,0,66,52,65,0,2,36,16,0,2,161,
- 17,0,2,145,172,0,99,140,2,0,66,52,
- 40,0,3,173,59,56,192,8,17,0,2,161,
- 65,0,2,36,16,0,2,161,156,0,98,140,
- 252,0,100,140,17,0,3,145,35,16,68,0,
- 2,0,99,52,40,0,2,173,59,56,192,8,
- 17,0,3,161,33,32,224,0,200,76,192,12,
- 33,40,0,1,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,208,255,189,39,
- 32,0,176,175,64,0,176,143,36,0,177,175,
- 33,136,224,0,4,0,160,20,40,0,191,175,
- 1,0,2,36,86,56,192,8,24,0,162,175,
- 0,0,198,140,24,133,130,143,0,0,0,0,
- 43,16,194,0,3,0,64,16,1,0,194,36,
- 86,56,192,8,24,0,162,175,17,0,2,146,
- 0,0,0,0,18,0,66,52,96,56,192,8,
- 17,0,2,162,16,0,176,175,1,0,5,36,
- 24,0,166,39,245,55,192,12,33,56,32,2,
- 33,32,32,2,33,40,0,2,1,0,6,36,
- 253,76,192,12,24,0,167,39,40,0,191,143,
- 36,0,177,143,32,0,176,143,8,0,224,3,
- 48,0,189,39,0,0,0,0,0,0,0,0,
- 0,0,0,0,200,255,189,39,72,0,163,143,
- 44,0,177,175,33,136,128,0,20,0,165,175,
- 33,40,224,0,2,131,2,60,172,210,66,140,
- 152,132,135,143,33,32,0,0,48,0,191,175,
- 40,0,176,175,24,0,160,175,28,0,160,175,
- 36,0,160,175,16,0,162,175,104,77,192,12,
- 32,0,163,175,33,128,64,0,3,0,0,22,
- 33,32,0,2,143,56,192,8,33,16,0,0,
- 197,80,192,12,33,40,32,2,255,255,3,36,
- 5,0,67,20,0,0,0,0,167,83,192,12,
- 33,32,0,2,143,56,192,8,33,16,0,0,
- 167,83,192,12,33,32,0,2,8,0,34,142,
- 4,0,35,142,0,0,0,0,35,16,67,0,
- 255,255,66,48,48,0,191,143,44,0,177,143,
- 40,0,176,143,8,0,224,3,56,0,189,39,
- 200,255,189,39,44,0,177,175,33,136,128,0,
- 72,0,168,143,33,32,0,0,20,0,165,175,
- 33,40,224,0,2,131,3,60,172,210,99,140,
- 152,132,135,143,1,0,2,36,48,0,191,175,
- 40,0,176,175,24,0,162,175,28,0,160,175,
- 36,0,160,175,16,0,163,175,104,77,192,12,
- 32,0,168,175,33,128,64,0,3,0,0,22,
- 33,32,0,2,188,56,192,8,33,16,0,0,
- 197,80,192,12,33,40,32,2,255,255,3,36,
- 5,0,67,20,0,0,0,0,167,83,192,12,
- 33,32,0,2,188,56,192,8,33,16,0,0,
- 167,83,192,12,33,32,0,2,8,0,34,142,
- 4,0,35,142,0,0,0,0,35,16,67,0,
- 255,255,66,48,48,0,191,143,44,0,177,143,
- 40,0,176,143,8,0,224,3,56,0,189,39,
- 176,255,189,39,44,0,177,175,108,0,177,143,
- 68,0,183,175,96,0,183,143,72,0,190,175,
- 100,0,190,143,48,0,178,175,33,144,128,0,
- 56,0,180,175,33,160,160,0,52,0,179,175,
- 33,152,192,0,40,0,176,175,33,128,224,0,
- 60,0,181,175,1,0,21,36,76,0,191,175,
- 3,0,53,18,64,0,182,175,9,57,192,8,
- 255,255,2,36,4,0,6,36,2,131,22,60,
- 48,205,214,38,160,132,132,143,104,0,165,143,
- 128,32,4,0,80,68,192,12,33,32,150,0,
- 33,32,0,0,33,40,0,2,152,132,135,143,
- 2,0,2,36,24,0,162,175,160,132,130,143,
- 2,131,3,60,172,210,99,140,33,48,96,2,
- 20,0,180,175,28,0,160,175,32,0,183,175,
- 36,0,181,175,1,0,81,36,104,77,192,12,
- 16,0,163,175,33,128,64,0,23,0,0,18,
- 33,40,0,0,16,0,190,175,33,32,0,2,
- 33,48,32,2,108,84,192,12,33,56,192,2,
- 255,255,17,36,13,0,81,16,33,32,0,2,
- 197,80,192,12,33,40,64,2,9,0,81,16,
- 0,0,0,0,167,83,192,12,33,32,0,2,
- 8,0,66,142,4,0,67,142,0,0,0,0,
- 35,16,67,0,9,57,192,8,255,255,66,48,
- 167,83,192,12,33,32,0,2,33,16,0,0,
- 76,0,191,143,72,0,190,143,68,0,183,143,
- 64,0,182,143,60,0,181,143,56,0,180,143,
- 52,0,179,143,48,0,178,143,44,0,177,143,
- 40,0,176,143,8,0,224,3,80,0,189,39,
- 176,255,189,39,44,0,177,175,108,0,177,143,
- 68,0,183,175,96,0,183,143,72,0,190,175,
- 100,0,190,143,48,0,178,175,33,144,128,0,
- 56,0,180,175,33,160,160,0,52,0,179,175,
- 33,152,192,0,40,0,176,175,33,128,224,0,
- 60,0,181,175,1,0,21,36,76,0,191,175,
- 3,0,53,18,64,0,182,175,93,57,192,8,
- 255,255,2,36,4,0,6,36,2,131,22,60,
- 48,205,214,38,160,132,132,143,104,0,165,143,
- 128,32,4,0,80,68,192,12,33,32,150,0,
- 33,32,0,0,33,40,0,2,152,132,135,143,
- 3,0,2,36,24,0,162,175,160,132,130,143,
- 2,131,3,60,172,210,99,140,33,48,96,2,
- 20,0,180,175,28,0,160,175,32,0,183,175,
- 36,0,181,175,1,0,81,36,104,77,192,12,
- 16,0,163,175,33,128,64,0,23,0,0,18,
- 33,40,0,0,16,0,190,175,33,32,0,2,
- 33,48,32,2,108,84,192,12,33,56,192,2,
- 255,255,17,36,13,0,81,16,33,32,0,2,
- 197,80,192,12,33,40,64,2,9,0,81,16,
- 0,0,0,0,167,83,192,12,33,32,0,2,
- 8,0,66,142,4,0,67,142,0,0,0,0,
- 35,16,67,0,93,57,192,8,255,255,66,48,
- 167,83,192,12,33,32,0,2,33,16,0,0,
- 76,0,191,143,72,0,190,143,68,0,183,143,
- 64,0,182,143,60,0,181,143,56,0,180,143,
- 52,0,179,143,48,0,178,143,44,0,177,143,
- 40,0,176,143,8,0,224,3,80,0,189,39,
- 200,255,189,39,44,0,177,175,33,136,128,0,
- 72,0,168,143,33,32,0,0,20,0,165,175,
- 33,40,224,0,2,131,3,60,172,210,99,140,
- 152,132,135,143,4,0,2,36,48,0,191,175,
- 40,0,176,175,24,0,162,175,28,0,160,175,
- 36,0,160,175,16,0,163,175,104,77,192,12,
- 32,0,168,175,33,128,64,0,3,0,0,22,
- 33,32,0,2,145,57,192,8,33,16,0,0,
- 197,80,192,12,33,40,32,2,255,255,3,36,
- 5,0,67,20,0,0,0,0,167,83,192,12,
- 33,32,0,2,145,57,192,8,33,16,0,0,
- 167,83,192,12,33,32,0,2,8,0,34,142,
- 4,0,35,142,0,0,0,0,35,16,67,0,
- 255,255,66,48,48,0,191,143,44,0,177,143,
- 40,0,176,143,8,0,224,3,56,0,189,39,
- 200,255,189,39,44,0,177,175,33,136,128,0,
- 72,0,163,143,33,32,0,0,20,0,165,175,
- 33,40,224,0,164,132,135,143,2,131,2,60,
- 92,205,66,36,16,0,162,175,6,0,2,36,
- 24,0,162,175,1,0,2,36,48,0,191,175,
- 40,0,176,175,28,0,162,175,36,0,160,175,
- 104,77,192,12,32,0,163,175,33,128,64,0,
- 3,0,0,22,33,32,0,2,191,57,192,8,
- 33,16,0,0,197,80,192,12,33,40,32,2,
- 255,255,3,36,5,0,67,20,0,0,0,0,
- 167,83,192,12,33,32,0,2,191,57,192,8,
- 33,16,0,0,167,83,192,12,33,32,0,2,
- 8,0,34,142,4,0,35,142,0,0,0,0,
- 35,16,67,0,255,255,66,48,48,0,191,143,
- 44,0,177,143,40,0,176,143,8,0,224,3,
- 56,0,189,39,200,255,189,39,44,0,177,175,
- 33,136,128,0,72,0,163,143,33,32,0,0,
- 20,0,165,175,33,40,224,0,164,132,135,143,
- 2,131,2,60,92,205,66,36,16,0,162,175,
- 6,0,2,36,24,0,162,175,2,0,2,36,
- 48,0,191,175,40,0,176,175,28,0,162,175,
- 36,0,160,175,104,77,192,12,32,0,163,175,
- 33,128,64,0,3,0,0,22,33,32,0,2,
- 237,57,192,8,33,16,0,0,197,80,192,12,
- 33,40,32,2,255,255,3,36,5,0,67,20,
- 0,0,0,0,167,83,192,12,33,32,0,2,
- 237,57,192,8,33,16,0,0,167,83,192,12,
- 33,32,0,2,8,0,34,142,4,0,35,142,
- 0,0,0,0,35,16,67,0,255,255,66,48,
- 48,0,191,143,44,0,177,143,40,0,176,143,
- 8,0,224,3,56,0,189,39,0,0,0,0,
- 0,0,0,0,224,255,189,39,24,0,178,175,
- 33,144,128,0,20,0,177,175,3,131,17,60,
- 0,18,49,38,16,0,176,175,33,128,0,0,
- 28,0,191,175,208,133,128,175,60,65,192,12,
- 33,32,0,2,0,0,34,166,1,0,16,38,
- 64,0,2,42,250,255,64,20,2,0,49,38,
- 3,131,3,60,18,18,99,144,255,0,2,36,
- 3,0,98,16,0,0,0,0,6,0,64,18,
- 0,163,4,60,75,59,192,12,32,0,4,36,
- 87,59,192,12,255,0,4,36,0,163,4,60,
- 220,5,132,52,176,132,133,39,168,71,192,12,
- 4,0,6,36,25,0,64,20,0,163,4,60,
- 3,131,16,60,20,18,16,38,33,32,0,2,
- 176,132,133,39,168,71,192,12,4,0,6,36,
- 3,0,64,16,0,163,4,60,7,0,64,18,
- 0,0,0,0,220,5,132,52,33,40,0,0,
- 144,71,192,12,4,0,6,36,47,58,192,8,
- 0,163,4,60,0,163,5,60,220,5,165,52,
- 3,0,2,138,0,0,2,154,0,0,0,0,
- 3,0,162,168,0,0,162,184,0,163,4,60,
- 99,59,192,12,220,5,132,52,0,163,4,60,
- 16,6,132,52,176,132,133,39,168,71,192,12,
- 4,0,6,36,25,0,64,20,0,163,4,60,
- 3,131,16,60,68,18,16,38,33,32,0,2,
- 176,132,133,39,168,71,192,12,4,0,6,36,
- 3,0,64,16,0,163,4,60,7,0,64,18,
- 0,0,0,0,16,6,132,52,33,40,0,0,
- 144,71,192,12,4,0,6,36,80,58,192,8,
- 0,163,4,60,0,163,5,60,16,6,165,52,
- 3,0,2,138,0,0,2,154,0,0,0,0,
- 3,0,162,168,0,0,162,184,0,163,4,60,
- 119,59,192,12,16,6,132,52,0,163,4,60,
- 224,5,132,52,176,132,133,39,168,71,192,12,
- 4,0,6,36,25,0,64,20,0,163,4,60,
- 3,131,16,60,24,18,16,38,33,32,0,2,
- 176,132,133,39,168,71,192,12,4,0,6,36,
- 3,0,64,16,0,163,4,60,7,0,64,18,
- 0,0,0,0,224,5,132,52,33,40,0,0,
- 144,71,192,12,4,0,6,36,113,58,192,8,
- 0,163,4,60,0,163,5,60,224,5,165,52,
- 3,0,2,138,0,0,2,154,0,0,0,0,
- 3,0,162,168,0,0,162,184,0,163,4,60,
- 139,59,192,12,224,5,132,52,3,131,3,60,
- 28,18,99,36,0,0,98,148,0,0,0,0,
- 0,128,66,48,3,0,64,20,1,0,2,36,
- 2,0,64,18,0,0,0,0,0,0,98,164,
- 0,163,2,60,144,1,66,140,0,0,0,0,
- 7,0,64,20,0,0,0,0,3,131,3,60,
- 28,18,99,36,0,0,98,148,0,0,0,0,
- 146,58,192,8,254,255,66,48,0,163,2,60,
- 144,1,66,140,0,0,0,0,7,0,64,24,
- 0,0,0,0,3,131,3,60,28,18,99,36,
- 0,0,98,148,0,0,0,0,1,0,66,52,
- 0,0,98,164,3,131,4,60,28,18,132,148,
- 0,0,0,0,159,59,192,12,1,0,132,48,
- 3,131,3,60,80,18,99,144,255,0,2,36,
- 3,0,98,16,0,0,0,0,5,0,64,18,
- 0,0,0,0,2,131,4,60,160,149,132,36,
- 205,59,192,12,14,0,5,36,3,131,3,60,
- 96,18,99,144,255,0,2,36,3,0,98,16,
- 0,0,0,0,5,0,64,18,0,0,0,0,
- 2,131,4,60,176,149,132,36,239,59,192,12,
- 11,0,5,36,3,131,3,60,112,18,99,144,
- 255,0,2,36,3,0,98,16,0,0,0,0,
- 5,0,64,18,0,0,0,0,2,131,4,60,
- 188,149,132,36,17,60,192,12,15,0,5,36,
- 0,163,2,60,140,1,66,140,0,0,0,0,
- 7,0,64,16,15,0,2,60,0,163,3,60,
- 140,1,99,140,64,66,66,52,43,16,67,0,
- 26,0,64,16,0,0,0,0,3,131,3,60,
- 64,18,99,140,255,255,2,36,3,0,98,16,
- 44,1,2,36,4,0,64,18,0,0,0,0,
- 0,163,1,60,221,58,192,8,140,1,34,172,
- 5,0,96,20,15,0,4,60,1,0,2,36,
- 0,163,1,60,221,58,192,8,140,1,34,172,
- 64,66,132,52,43,16,131,0,4,0,64,16,
- 0,0,0,0,0,163,1,60,221,58,192,8,
- 140,1,36,172,0,163,1,60,140,1,35,172,
- 0,163,4,60,140,1,132,140,51,60,192,12,
- 0,0,0,0,28,0,191,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,208,255,189,39,20,0,177,175,
- 33,136,128,0,36,0,181,175,33,168,160,0,
- 28,0,179,175,33,152,192,0,44,0,191,175,
- 40,0,182,175,32,0,180,175,24,0,178,175,
- 168,71,192,12,16,0,176,175,76,0,64,16,
- 0,0,0,0,3,131,22,60,0,18,214,38,
- 35,16,54,2,194,31,2,0,33,16,67,0,
- 67,144,2,0,1,0,98,38,194,31,2,0,
- 33,16,67,0,67,128,2,0,255,255,20,38,
- 64,0,130,46,14,0,64,20,64,0,66,46,
- 2,131,4,60,204,149,132,36,180,132,144,39,
- 33,40,0,2,2,131,7,60,236,149,231,36,
- 15,63,192,12,143,0,6,36,1,0,4,36,
- 33,40,0,2,188,7,192,12,143,0,6,36,
- 64,0,66,46,14,0,64,20,33,32,32,2,
- 2,131,4,60,204,149,132,36,180,132,144,39,
- 33,40,0,2,2,131,7,60,20,150,231,36,
- 15,63,192,12,144,0,6,36,1,0,4,36,
- 33,40,0,2,188,7,192,12,144,0,6,36,
- 33,32,32,2,33,40,160,2,80,68,192,12,
- 33,48,96,2,64,16,18,0,33,136,86,0,
- 33,128,128,2,255,255,2,36,25,0,2,18,
- 255,255,20,36,180,132,147,39,33,32,64,2,
- 208,133,130,143,1,0,82,38,1,0,66,36,
- 208,133,130,175,0,0,37,150,0,0,0,0,
- 162,65,192,12,2,0,49,38,10,0,64,20,
- 33,40,96,2,2,131,4,60,204,149,132,36,
- 188,132,135,39,15,63,192,12,159,0,6,36,
- 1,0,4,36,33,40,96,2,188,7,192,12,
- 159,0,6,36,255,255,16,38,235,255,20,22,
- 33,32,64,2,44,0,191,143,40,0,182,143,
- 36,0,181,143,32,0,180,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,48,0,189,39,224,255,189,39,
- 16,0,164,163,3,131,4,60,18,18,132,36,
- 16,0,165,39,24,0,191,175,231,58,192,12,
- 1,0,6,36,24,0,191,143,32,0,189,39,
- 8,0,224,3,0,0,0,0,224,255,189,39,
- 16,0,164,163,3,131,4,60,19,18,132,36,
- 16,0,165,39,24,0,191,175,231,58,192,12,
- 1,0,6,36,24,0,191,143,32,0,189,39,
- 8,0,224,3,0,0,0,0,232,255,189,39,
- 33,40,128,0,16,0,176,175,3,131,16,60,
- 20,18,16,38,33,32,0,2,20,0,191,175,
- 231,58,192,12,4,0,6,36,0,163,5,60,
- 220,5,165,52,3,0,2,138,0,0,2,154,
- 0,0,0,0,3,0,162,168,0,0,162,184,
- 20,0,191,143,16,0,176,143,8,0,224,3,
- 24,0,189,39,232,255,189,39,33,40,128,0,
- 16,0,176,175,3,131,16,60,68,18,16,38,
- 33,32,0,2,20,0,191,175,231,58,192,12,
- 4,0,6,36,0,163,5,60,16,6,165,52,
- 3,0,2,138,0,0,2,154,0,0,0,0,
- 3,0,162,168,0,0,162,184,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 232,255,189,39,33,40,128,0,16,0,176,175,
- 3,131,16,60,24,18,16,38,33,32,0,2,
- 20,0,191,175,231,58,192,12,4,0,6,36,
- 0,163,5,60,224,5,165,52,3,0,2,138,
- 0,0,2,154,0,0,0,0,3,0,162,168,
- 0,0,162,184,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,3,131,2,60,
- 28,18,66,148,224,255,189,39,24,0,191,175,
- 8,0,128,16,16,0,162,167,1,0,66,52,
- 16,0,162,167,1,0,2,36,44,133,130,175,
- 0,163,1,60,177,59,192,8,144,1,34,172,
- 254,255,66,48,16,0,162,167,44,133,128,175,
- 0,163,1,60,144,1,32,172,3,131,4,60,
- 28,18,132,36,16,0,165,39,231,58,192,12,
- 2,0,6,36,24,0,191,143,32,0,189,39,
- 8,0,224,3,0,0,0,0,3,131,2,60,
- 28,18,66,148,224,255,189,39,24,0,191,175,
- 3,0,128,16,16,0,162,167,195,59,192,8,
- 2,0,66,52,253,255,66,48,16,0,162,167,
- 3,131,4,60,28,18,132,36,16,0,165,39,
- 231,58,192,12,2,0,6,36,24,0,191,143,
- 32,0,189,39,8,0,224,3,0,0,0,0,
- 216,255,189,39,32,0,191,175,33,56,128,0,
- 33,48,160,0,3,0,226,136,0,0,226,152,
- 7,0,227,136,4,0,227,152,11,0,228,136,
- 8,0,228,152,15,0,229,136,12,0,229,152,
- 19,0,162,171,16,0,162,187,23,0,163,171,
- 20,0,163,187,27,0,164,171,24,0,164,187,
- 31,0,165,171,28,0,165,187,16,0,194,44,
- 3,0,64,16,16,0,163,39,33,16,102,0,
- 0,0,64,160,3,131,4,60,80,18,132,36,
- 33,40,224,0,231,58,192,12,16,0,6,36,
- 32,0,191,143,40,0,189,39,8,0,224,3,
- 0,0,0,0,216,255,189,39,32,0,191,175,
- 33,56,128,0,33,48,160,0,3,0,226,136,
- 0,0,226,152,7,0,227,136,4,0,227,152,
- 11,0,228,136,8,0,228,152,15,0,229,136,
- 12,0,229,152,19,0,162,171,16,0,162,187,
- 23,0,163,171,20,0,163,187,27,0,164,171,
- 24,0,164,187,31,0,165,171,28,0,165,187,
- 16,0,194,44,3,0,64,16,16,0,163,39,
- 33,16,102,0,0,0,64,160,3,131,4,60,
- 96,18,132,36,33,40,224,0,231,58,192,12,
- 16,0,6,36,32,0,191,143,40,0,189,39,
- 8,0,224,3,0,0,0,0,216,255,189,39,
- 32,0,191,175,33,56,128,0,33,48,160,0,
- 3,0,226,136,0,0,226,152,7,0,227,136,
- 4,0,227,152,11,0,228,136,8,0,228,152,
- 15,0,229,136,12,0,229,152,19,0,162,171,
- 16,0,162,187,23,0,163,171,20,0,163,187,
- 27,0,164,171,24,0,164,187,31,0,165,171,
- 28,0,165,187,16,0,194,44,3,0,64,16,
- 16,0,163,39,33,16,102,0,0,0,64,160,
- 3,131,4,60,112,18,132,36,33,40,224,0,
- 231,58,192,12,16,0,6,36,32,0,191,143,
- 40,0,189,39,8,0,224,3,0,0,0,0,
- 232,255,189,39,15,0,2,60,54,66,66,52,
- 24,0,164,175,246,255,132,36,43,16,68,0,
- 3,0,64,16,16,0,191,175,44,1,2,36,
- 24,0,162,175,3,131,4,60,64,18,132,36,
- 24,0,165,39,231,58,192,12,4,0,6,36,
- 24,0,162,143,0,163,1,60,140,1,34,172,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,232,255,189,39,16,0,191,175,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,232,255,189,39,16,0,191,175,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,160,255,189,39,112,0,162,143,
- 72,0,176,175,33,128,224,0,88,0,180,175,
- 33,160,0,0,84,0,179,175,33,152,192,0,
- 92,0,191,175,80,0,178,175,7,0,160,16,
- 76,0,177,175,6,0,65,4,51,0,177,39,
- 45,0,20,36,3,0,0,18,35,16,2,0,
- 255,255,16,38,51,0,177,39,51,0,160,163,
- 27,0,68,0,2,0,128,20,0,0,0,0,
- 13,0,7,0,18,24,0,0,16,16,0,0,
- 2,131,1,60,33,8,34,0,128,205,34,144,
- 255,255,49,38,2,0,0,18,0,0,34,162,
- 255,255,16,38,33,16,96,0,241,255,64,20,
- 1,0,3,36,0,22,19,0,3,22,2,0,
- 11,0,67,20,33,32,128,2,255,255,16,38,
- 255,255,2,36,7,0,2,18,0,0,0,0,
- 255,255,18,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,18,22,33,32,128,2,
- 4,0,128,16,0,22,19,0,196,64,192,12,
- 0,0,0,0,0,22,19,0,3,22,2,0,
- 2,0,3,36,14,0,67,20,255,255,2,36,
- 255,255,16,38,11,0,2,18,255,255,18,36,
- 196,64,192,12,48,0,4,36,255,255,16,38,
- 6,0,18,18,0,0,0,0,156,60,192,8,
- 0,0,0,0,0,38,4,0,196,64,192,12,
- 3,38,4,0,0,0,34,130,0,0,36,146,
- 0,0,0,0,249,255,64,20,1,0,49,38,
- 255,255,49,38,0,22,19,0,3,22,2,0,
- 3,0,3,36,9,0,67,20,255,255,16,38,
- 255,255,2,36,6,0,2,18,255,255,17,36,
- 196,64,192,12,32,0,4,36,255,255,16,38,
- 252,255,17,22,0,0,0,0,92,0,191,143,
- 88,0,180,143,84,0,179,143,80,0,178,143,
- 76,0,177,143,72,0,176,143,8,0,224,3,
- 96,0,189,39,200,255,189,39,40,0,178,175,
- 33,144,128,0,32,0,176,175,33,128,160,0,
- 36,0,177,175,33,136,192,0,33,32,32,2,
- 48,0,191,175,156,71,192,12,44,0,179,175,
- 33,32,0,0,33,24,64,0,42,16,112,0,
- 2,0,64,16,33,152,64,2,35,32,3,2,
- 0,22,18,0,3,22,2,0,1,0,3,36,
- 11,0,67,20,33,128,128,0,255,255,16,38,
- 255,255,2,36,8,0,2,18,0,22,19,0,
- 255,255,18,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,18,22,0,0,0,0,
- 0,22,19,0,3,22,2,0,2,0,3,36,
- 14,0,67,20,255,255,2,36,255,255,16,38,
- 11,0,2,18,255,255,18,36,196,64,192,12,
- 48,0,4,36,255,255,16,38,6,0,18,18,
- 0,0,0,0,233,60,192,8,0,0,0,0,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 0,0,34,130,0,0,36,146,0,0,0,0,
- 249,255,64,20,1,0,49,38,255,255,49,38,
- 0,22,19,0,3,22,2,0,3,0,3,36,
- 9,0,67,20,255,255,16,38,255,255,2,36,
- 6,0,2,18,255,255,17,36,196,64,192,12,
- 32,0,4,36,255,255,16,38,252,255,17,22,
- 0,0,0,0,48,0,191,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,56,0,189,39,32,255,189,39,
- 192,0,178,175,33,144,160,0,196,0,179,175,
- 33,152,0,0,220,0,191,175,216,0,190,175,
- 212,0,183,175,208,0,182,175,204,0,181,175,
- 200,0,180,175,188,0,177,175,184,0,176,175,
- 1,0,130,128,0,0,0,0,229,1,64,16,
- 33,136,0,0,255,255,22,36,1,0,23,36,
- 2,0,30,36,1,0,149,36,0,0,162,146,
- 0,0,0,0,219,255,66,36,0,22,2,0,
- 3,30,2,0,84,0,98,44,217,1,64,16,
- 128,16,3,0,2,131,1,60,33,8,34,0,
- 80,150,34,140,0,0,0,0,8,0,64,0,
- 0,0,0,0,209,61,192,8,37,0,4,36,
- 2,131,16,60,64,150,16,38,156,71,192,12,
- 33,32,0,2,59,61,192,8,0,0,0,0,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 0,0,2,130,0,0,4,146,0,0,0,0,
- 249,255,64,20,1,0,16,38,3,63,192,8,
- 1,0,162,38,0,38,18,0,209,61,192,8,
- 3,38,4,0,2,0,3,36,33,128,32,2,
- 33,40,64,2,33,160,0,0,51,0,177,39,
- 51,0,160,163,27,0,163,0,2,0,96,20,
- 0,0,0,0,13,0,7,0,18,40,0,0,
- 16,16,0,0,2,131,1,60,33,8,34,0,
- 128,205,34,144,255,255,49,38,2,0,0,18,
- 0,0,34,162,255,255,16,38,242,255,160,20,
- 0,0,0,0,10,0,119,22,0,22,20,0,
- 255,255,16,38,8,0,22,18,3,38,2,0,
- 255,255,18,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,18,22,0,22,20,0,
- 3,38,2,0,3,0,128,16,0,0,0,0,
- 196,64,192,12,0,0,0,0,14,0,126,22,
- 0,0,0,0,255,255,16,38,11,0,22,18,
- 255,255,18,36,196,64,192,12,48,0,4,36,
- 255,255,16,38,6,0,18,18,0,0,0,0,
- 111,61,192,8,0,0,0,0,0,38,4,0,
- 196,64,192,12,3,38,4,0,0,0,34,130,
- 0,0,36,146,0,0,0,0,249,255,64,20,
- 1,0,49,38,255,255,49,38,3,0,6,36,
- 80,0,102,22,66,0,4,36,255,255,16,38,
- 77,0,22,18,255,255,17,36,196,64,192,12,
- 32,0,4,36,255,255,16,38,252,255,17,22,
- 66,0,4,36,209,61,192,8,0,0,0,0,
- 8,0,3,36,33,128,32,2,33,40,64,2,
- 33,160,0,0,51,0,177,39,51,0,160,163,
- 27,0,163,0,2,0,96,20,0,0,0,0,
- 13,0,7,0,18,40,0,0,16,16,0,0,
- 2,131,1,60,33,8,34,0,128,205,34,144,
- 255,255,49,38,2,0,0,18,0,0,34,162,
- 255,255,16,38,242,255,160,20,0,0,0,0,
- 10,0,119,22,0,22,20,0,255,255,16,38,
- 8,0,22,18,3,38,2,0,255,255,18,36,
- 196,64,192,12,32,0,4,36,255,255,16,38,
- 252,255,18,22,0,22,20,0,3,38,2,0,
- 3,0,128,16,0,0,0,0,196,64,192,12,
- 0,0,0,0,14,0,126,22,0,0,0,0,
- 255,255,16,38,11,0,22,18,255,255,18,36,
- 196,64,192,12,48,0,4,36,255,255,16,38,
- 6,0,18,18,0,0,0,0,182,61,192,8,
- 0,0,0,0,0,38,4,0,196,64,192,12,
- 3,38,4,0,0,0,34,130,0,0,36,146,
- 0,0,0,0,249,255,64,20,1,0,49,38,
- 255,255,49,38,3,0,6,36,9,0,102,22,
- 81,0,4,36,255,255,16,38,6,0,22,18,
- 255,255,17,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,17,22,81,0,4,36,
- 196,64,192,12,0,0,0,0,3,63,192,8,
- 1,0,162,38,33,128,32,2,33,16,64,2,
- 33,160,0,0,5,0,65,6,10,0,4,36,
- 45,0,20,36,2,0,32,18,35,16,18,0,
- 255,255,48,38,51,0,177,39,51,0,160,163,
- 27,0,68,0,2,0,128,20,0,0,0,0,
- 13,0,7,0,18,24,0,0,16,16,0,0,
- 2,131,1,60,33,8,34,0,128,205,34,144,
- 255,255,49,38,2,0,0,18,0,0,34,162,
- 255,255,16,38,33,16,96,0,241,255,64,20,
- 0,0,0,0,10,0,119,22,33,32,128,2,
- 255,255,16,38,7,0,22,18,0,0,0,0,
- 255,255,18,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,18,22,33,32,128,2,
- 3,0,128,16,0,0,0,0,196,64,192,12,
- 0,0,0,0,14,0,126,22,0,0,0,0,
- 255,255,16,38,11,0,22,18,255,255,18,36,
- 196,64,192,12,48,0,4,36,255,255,16,38,
- 6,0,18,18,0,0,0,0,4,62,192,8,
- 0,0,0,0,0,38,4,0,196,64,192,12,
- 3,38,4,0,0,0,34,130,0,0,36,146,
- 0,0,0,0,249,255,64,20,1,0,49,38,
- 255,255,49,38,3,0,6,36,237,0,102,22,
- 1,0,162,38,255,255,16,38,234,0,22,18,
- 255,255,17,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,17,22,1,0,162,38,
- 3,63,192,8,0,0,0,0,10,0,3,36,
- 33,128,32,2,33,40,64,2,33,160,0,0,
- 51,0,177,39,51,0,160,163,27,0,163,0,
- 2,0,96,20,0,0,0,0,13,0,7,0,
- 18,40,0,0,16,16,0,0,2,131,1,60,
- 33,8,34,0,128,205,34,144,255,255,49,38,
- 2,0,0,18,0,0,34,162,255,255,16,38,
- 242,255,160,20,0,0,0,0,10,0,119,22,
- 0,22,20,0,255,255,16,38,8,0,22,18,
- 3,38,2,0,255,255,18,36,196,64,192,12,
- 32,0,4,36,255,255,16,38,252,255,18,22,
- 0,22,20,0,3,38,2,0,3,0,128,16,
- 0,0,0,0,196,64,192,12,0,0,0,0,
- 14,0,126,22,0,0,0,0,255,255,16,38,
- 11,0,22,18,255,255,18,36,196,64,192,12,
- 48,0,4,36,255,255,16,38,6,0,18,18,
- 0,0,0,0,75,62,192,8,0,0,0,0,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 0,0,34,130,0,0,36,146,0,0,0,0,
- 249,255,64,20,1,0,49,38,255,255,49,38,
- 3,0,6,36,166,0,102,22,1,0,162,38,
- 255,255,16,38,163,0,22,18,255,255,17,36,
- 196,64,192,12,32,0,4,36,255,255,16,38,
- 252,255,17,22,1,0,162,38,3,63,192,8,
- 0,0,0,0,192,132,144,39,156,71,192,12,
- 33,32,0,2,112,62,192,8,0,0,0,0,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 0,0,2,130,0,0,4,146,0,0,0,0,
- 249,255,64,20,1,0,16,38,16,0,3,36,
- 33,128,32,2,33,40,64,2,33,160,0,0,
- 51,0,177,39,51,0,160,163,27,0,163,0,
- 2,0,96,20,0,0,0,0,13,0,7,0,
- 18,40,0,0,16,16,0,0,2,131,1,60,
- 33,8,34,0,128,205,34,144,255,255,49,38,
- 2,0,0,18,0,0,34,162,255,255,16,38,
- 242,255,160,20,0,0,0,0,10,0,119,22,
- 0,22,20,0,255,255,16,38,8,0,22,18,
- 3,38,2,0,255,255,18,36,196,64,192,12,
- 32,0,4,36,255,255,16,38,252,255,18,22,
- 0,22,20,0,3,38,2,0,3,0,128,16,
- 0,0,0,0,196,64,192,12,0,0,0,0,
- 14,0,126,22,0,0,0,0,255,255,16,38,
- 11,0,22,18,255,255,18,36,196,64,192,12,
- 48,0,4,36,255,255,16,38,6,0,18,18,
- 0,0,0,0,159,62,192,8,0,0,0,0,
- 0,38,4,0,196,64,192,12,3,38,4,0,
- 0,0,34,130,0,0,36,146,0,0,0,0,
- 249,255,64,20,1,0,49,38,255,255,49,38,
- 3,0,6,36,82,0,102,22,1,0,162,38,
- 255,255,16,38,79,0,22,18,255,255,17,36,
- 196,64,192,12,32,0,4,36,255,255,16,38,
- 252,255,17,22,1,0,162,38,3,63,192,8,
- 0,0,0,0,156,71,192,12,33,32,64,2,
- 33,24,64,0,42,16,113,0,2,0,64,16,
- 33,32,0,0,35,32,35,2,10,0,119,22,
- 33,128,128,0,255,255,16,38,7,0,22,18,
- 0,0,0,0,255,255,17,36,196,64,192,12,
- 32,0,4,36,255,255,16,38,252,255,17,22,
- 0,0,0,0,14,0,126,22,0,0,0,0,
- 255,255,16,38,11,0,22,18,255,255,17,36,
- 196,64,192,12,48,0,4,36,255,255,16,38,
- 6,0,17,18,0,0,0,0,211,62,192,8,
- 0,0,0,0,0,38,4,0,196,64,192,12,
- 3,38,4,0,0,0,66,130,0,0,68,146,
- 0,0,0,0,249,255,64,20,1,0,82,38,
- 255,255,82,38,3,0,6,36,30,0,102,22,
- 1,0,162,38,255,255,16,38,27,0,22,18,
- 255,255,17,36,196,64,192,12,32,0,4,36,
- 255,255,16,38,252,255,17,22,1,0,162,38,
- 3,63,192,8,0,0,0,0,253,62,192,8,
- 3,0,19,36,3,0,96,22,128,16,17,0,
- 2,0,19,36,128,16,17,0,33,16,81,0,
- 64,16,2,0,0,0,163,130,208,255,66,36,
- 2,0,96,22,33,136,67,0,1,0,19,36,
- 1,0,181,38,0,0,162,130,0,0,0,0,
- 33,254,64,20,0,0,0,0,1,0,130,36,
- 220,0,191,143,216,0,190,143,212,0,183,143,
- 208,0,182,143,204,0,181,143,200,0,180,143,
- 196,0,179,143,192,0,178,143,188,0,177,143,
- 184,0,176,143,8,0,224,3,224,0,189,39,
- 0,0,164,175,4,0,165,175,8,0,166,175,
- 12,0,167,175,200,255,189,39,59,0,162,39,
- 252,255,3,36,36,16,67,0,52,0,191,175,
- 48,0,180,175,44,0,179,175,40,0,178,175,
- 36,0,177,175,32,0,176,175,56,0,164,175,
- 0,0,80,140,4,0,81,36,0,0,2,130,
- 0,0,3,146,0,0,0,0,31,0,64,16,
- 37,0,20,36,69,0,19,36,252,255,18,36,
- 0,22,3,0,3,38,2,0,18,0,148,20,
- 0,0,0,0,1,0,3,130,0,0,0,0,
- 4,0,100,16,33,32,0,2,4,0,115,20,
- 3,0,34,38,33,32,0,2,56,63,192,8,
- 33,40,0,0,36,16,82,0,4,0,81,36,
- 0,0,69,140,33,32,0,2,13,61,192,12,
- 0,0,0,0,62,63,192,8,33,128,64,0,
- 196,64,192,12,1,0,16,38,0,0,2,130,
- 0,0,3,146,0,0,0,0,230,255,64,20,
- 0,22,3,0,52,0,191,143,48,0,180,143,
- 44,0,179,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,56,0,189,39,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,8,0,224,3,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,8,0,224,3,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 8,0,224,3,0,0,0,0,33,72,224,3,
- 170,3,8,36,76,63,192,12,0,0,0,0,
- 255,255,8,33,252,255,0,21,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,8,0,32,1,
- 0,0,0,0,33,88,224,3,232,3,10,36,
- 143,63,192,12,0,0,0,0,255,255,74,33,
- 252,255,64,21,0,0,0,0,8,0,96,1,
- 0,0,0,0,250,255,132,32,130,32,4,0,
- 255,255,132,32,0,0,0,0,253,255,128,20,
- 0,0,0,0,8,0,224,3,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 248,255,189,39,255,255,195,36,10,0,192,16,
- 33,56,160,0,255,255,6,36,0,0,162,144,
- 1,0,165,36,0,0,130,160,4,0,64,16,
- 1,0,132,36,255,255,99,36,249,255,102,20,
- 0,0,0,0,33,16,224,0,8,0,224,3,
- 8,0,189,39,0,96,2,64,0,0,0,0,
- 38,64,68,0,1,255,8,49,38,64,2,1,
- 0,96,136,64,8,0,224,3,1,255,66,48,
- 0,96,2,64,0,0,0,0,1,255,132,48,
- 39,32,128,0,36,64,68,0,0,96,136,64,
- 8,0,224,3,1,255,66,48,0,96,2,64,
- 0,0,0,0,0,255,132,48,37,64,68,0,
- 1,0,8,53,0,96,136,64,8,0,224,3,
- 1,255,66,48,176,255,189,39,64,0,182,175,
- 33,176,128,0,52,0,179,175,33,152,160,0,
- 72,0,190,175,33,240,192,0,68,0,183,175,
- 33,184,224,0,60,0,181,175,33,168,0,0,
- 56,0,180,175,33,160,0,0,76,0,191,175,
- 48,0,178,175,44,0,177,175,40,0,176,175,
- 2,131,6,60,33,48,212,0,160,205,198,144,
- 0,0,0,0,28,0,96,26,33,128,0,0,
- 33,24,192,2,33,32,118,2,0,0,102,160,
- 1,0,99,36,42,16,100,0,252,255,64,20,
- 0,0,0,0,19,0,96,26,33,128,0,0,
- 255,0,210,48,33,136,192,2,0,0,39,146,
- 0,0,0,0,9,0,242,16,0,0,0,0,
- 5,0,224,18,33,40,0,2,96,0,164,143,
- 0,0,0,0,9,248,224,2,33,48,64,2,
- 32,0,192,23,1,0,181,38,1,0,16,38,
- 42,16,19,2,241,255,64,20,1,0,49,38,
- 1,0,148,38,4,0,130,46,220,255,64,20,
- 0,0,0,0,7,0,96,26,33,128,0,0,
- 33,24,192,2,0,0,112,160,1,0,16,38,
- 42,16,19,2,252,255,64,20,1,0,99,36,
- 20,0,96,26,33,128,0,0,33,136,192,2,
- 0,0,39,146,255,0,6,50,11,0,230,16,
- 0,0,0,0,5,0,224,18,0,0,0,0,
- 96,0,164,143,0,0,0,0,9,248,224,2,
- 33,40,0,2,3,0,192,19,1,0,181,38,
- 72,64,192,8,1,0,2,36,1,0,16,38,
- 42,16,19,2,239,255,64,20,1,0,49,38,
- 33,16,160,2,76,0,191,143,72,0,190,143,
- 68,0,183,143,64,0,182,143,60,0,181,143,
- 56,0,180,143,52,0,179,143,48,0,178,143,
- 44,0,177,143,40,0,176,143,8,0,224,3,
- 80,0,189,39,160,255,189,39,88,0,190,175,
- 33,240,128,0,68,0,179,175,33,152,160,0,
- 76,0,181,175,33,168,224,0,72,0,180,175,
- 33,160,0,0,33,16,96,2,92,0,191,175,
- 84,0,183,175,80,0,182,175,64,0,178,175,
- 60,0,177,175,56,0,176,175,2,0,97,6,
- 16,0,166,175,3,0,98,38,131,152,2,0,
- 33,184,0,0,2,131,22,60,164,205,214,38,
- 0,0,210,142,0,0,0,0,7,0,96,18,
- 33,128,0,0,33,24,192,3,0,0,114,172,
- 1,0,16,38,43,16,19,2,252,255,64,20,
- 4,0,99,36,20,0,96,18,33,128,0,0,
- 33,136,192,3,0,0,39,142,0,0,0,0,
- 11,0,242,16,128,40,16,0,5,0,160,18,
- 0,0,0,0,112,0,164,143,0,0,0,0,
- 9,248,160,2,33,48,64,2,16,0,168,143,
- 0,0,0,0,34,0,0,21,1,0,148,38,
- 1,0,16,38,43,16,19,2,239,255,64,20,
- 4,0,49,38,1,0,247,38,4,0,226,46,
- 222,255,64,20,4,0,214,38,7,0,96,18,
- 33,128,0,0,33,24,192,3,0,0,112,172,
- 1,0,16,38,43,16,19,2,252,255,64,20,
- 4,0,99,36,22,0,96,18,33,128,0,0,
- 33,136,192,3,0,0,39,142,0,0,0,0,
- 13,0,240,16,128,40,16,0,5,0,160,18,
- 0,0,0,0,112,0,164,143,0,0,0,0,
- 9,248,160,2,33,48,0,2,16,0,168,143,
- 0,0,0,0,3,0,0,17,1,0,148,38,
- 174,64,192,8,1,0,2,36,1,0,16,38,
- 43,16,19,2,237,255,64,20,4,0,49,38,
- 33,16,128,2,92,0,191,143,88,0,190,143,
- 84,0,183,143,80,0,182,143,76,0,181,143,
- 72,0,180,143,68,0,179,143,64,0,178,143,
- 60,0,177,143,56,0,176,143,8,0,224,3,
- 96,0,189,39,0,0,0,0,0,0,0,0,
- 255,1,2,36,0,163,1,60,176,1,32,172,
- 0,163,1,60,180,1,32,172,0,163,1,60,
- 8,0,224,3,184,1,34,172,232,255,189,39,
- 16,0,176,175,33,128,128,0,20,0,191,175,
- 220,63,192,12,33,32,0,0,33,40,64,0,
- 0,163,3,60,180,1,99,140,0,163,2,60,
- 184,1,66,140,0,163,4,60,128,1,132,140,
- 1,0,99,36,11,0,128,20,36,24,98,0,
- 0,163,2,60,176,1,66,140,0,0,0,0,
- 6,0,98,20,0,0,0,0,0,163,2,60,
- 128,1,66,140,0,0,0,0,247,255,64,16,
- 0,0,0,0,0,163,2,60,180,1,66,140,
- 33,32,160,0,0,163,1,60,33,8,34,0,
- 188,1,48,160,0,163,1,60,220,63,192,12,
- 180,1,35,172,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,8,0,224,3,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,192,255,189,39,33,80,0,0,
- 80,0,185,143,84,0,184,143,88,0,175,143,
- 1,0,2,36,60,0,177,175,92,0,177,143,
- 4,112,226,0,12,0,224,24,56,0,176,175,
- 1,0,9,36,33,64,160,3,33,24,32,3,
- 0,0,98,140,4,0,99,36,1,0,74,37,
- 4,16,73,0,0,0,2,173,42,16,71,1,
- 249,255,64,20,4,0,8,37,46,0,192,25,
- 33,80,0,0,255,0,16,36,33,72,0,0,
- 0,0,145,172,0,0,160,164,34,0,224,24,
- 0,0,208,160,33,88,128,0,33,96,160,0,
- 33,104,192,0,33,64,32,3,33,24,160,3,
- 0,0,98,140,0,0,0,0,36,16,66,1,
- 19,0,64,16,0,0,0,0,0,0,2,141,
- 0,0,0,0,128,16,2,0,33,16,88,0,
- 0,0,66,140,0,0,0,0,0,0,98,173,
- 0,0,2,141,0,0,0,0,64,16,2,0,
- 33,16,79,0,0,0,66,148,0,0,0,0,
- 0,0,130,165,0,0,2,141,0,0,0,0,
- 47,65,192,8,0,0,162,161,4,0,8,37,
- 1,0,41,37,42,16,39,1,229,255,64,20,
- 4,0,99,36,1,0,198,36,2,0,165,36,
- 1,0,74,37,42,16,78,1,213,255,64,20,
- 4,0,132,36,60,0,177,143,56,0,176,143,
- 8,0,224,3,64,0,189,39,0,0,0,0,
- 0,0,0,0,0,0,0,0,216,255,189,39,
- 63,0,132,48,28,0,179,175,128,1,147,52,
- 50,133,130,151,48,133,132,151,0,128,131,151,
- 20,0,177,175,16,0,176,175,5,162,16,60,
- 32,0,191,175,24,0,178,175,39,16,68,0,
- 36,24,98,0,0,128,131,167,0,0,3,166,
- 76,63,192,12,0,1,17,36,0,128,130,151,
- 48,133,131,151,5,162,18,60,37,16,67,0,
- 0,128,130,167,0,0,2,166,36,16,51,2,
- 6,0,64,16,0,0,0,0,0,128,131,151,
- 20,133,130,151,0,0,0,0,96,65,192,8,
- 37,24,98,0,20,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,0,128,131,167,
- 0,0,67,166,76,63,192,12,66,136,17,0,
- 0,128,130,151,50,133,131,151,0,0,0,0,
- 37,16,67,0,0,128,130,167,76,63,192,12,
- 0,0,66,166,50,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,255,255,34,50,
- 0,128,131,167,0,0,67,166,226,255,64,20,
- 36,16,51,2,33,136,0,0,16,0,16,36,
- 5,162,18,60,255,255,19,36,76,63,192,12,
- 0,0,0,0,0,128,131,151,50,133,130,151,
- 0,0,0,0,37,24,98,0,0,128,131,167,
- 76,63,192,12,0,0,67,166,8,0,0,18,
- 0,0,0,0,0,0,67,150,20,133,130,151,
- 0,0,0,0,36,16,67,0,2,0,64,16,
- 64,136,17,0,1,0,49,54,76,63,192,12,
- 255,255,16,38,50,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,0,128,131,167,
- 230,255,19,22,0,0,67,166,48,133,130,151,
- 0,128,131,151,39,16,2,0,36,24,98,0,
- 5,162,2,60,0,128,131,167,0,0,67,164,
- 255,255,34,50,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,208,255,189,39,
- 36,0,181,175,33,168,160,0,32,0,180,175,
- 63,0,148,48,33,32,128,2,44,0,191,175,
- 40,0,182,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,60,65,192,12,16,0,176,175,
- 33,152,64,0,255,255,163,50,255,255,98,50,
- 3,0,98,20,48,1,22,36,245,66,192,8,
- 1,0,2,36,5,162,16,60,50,133,130,151,
- 48,133,132,151,0,128,131,151,39,16,68,0,
- 36,24,98,0,0,128,131,167,0,0,3,166,
- 76,63,192,12,0,1,17,36,0,128,130,151,
- 48,133,131,151,5,162,18,60,37,16,67,0,
- 0,128,130,167,0,0,2,166,36,16,54,2,
- 6,0,64,16,0,0,0,0,0,128,131,151,
- 20,133,130,151,0,0,0,0,210,65,192,8,
- 37,24,98,0,20,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,0,128,131,167,
- 0,0,67,166,76,63,192,12,66,136,17,0,
- 0,128,130,151,50,133,131,151,0,0,0,0,
- 37,16,67,0,0,128,130,167,76,63,192,12,
- 0,0,66,166,50,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,255,255,34,50,
- 0,128,131,167,0,0,67,166,226,255,64,20,
- 36,16,54,2,255,255,163,50,255,255,98,50,
- 39,16,2,0,36,24,98,0,84,0,96,16,
- 192,1,147,54,5,162,16,60,50,133,130,151,
- 48,133,132,151,0,128,131,151,39,16,68,0,
- 36,24,98,0,0,128,131,167,0,0,3,166,
- 76,63,192,12,0,1,17,36,0,128,130,151,
- 48,133,131,151,5,162,18,60,37,16,67,0,
- 0,128,130,167,0,0,2,166,36,16,51,2,
- 6,0,64,16,0,0,0,0,0,128,131,151,
- 20,133,130,151,0,0,0,0,8,66,192,8,
- 37,24,98,0,20,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,0,128,131,167,
- 0,0,67,166,76,63,192,12,66,136,17,0,
- 0,128,130,151,50,133,131,151,0,0,0,0,
- 37,16,67,0,0,128,130,167,76,63,192,12,
- 0,0,66,166,50,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,255,255,34,50,
- 0,128,131,167,0,0,67,166,226,255,64,20,
- 36,16,51,2,5,162,16,60,50,133,130,151,
- 48,133,132,151,0,128,131,151,39,16,68,0,
- 36,24,98,0,0,128,131,167,76,63,192,12,
- 0,0,3,166,0,128,131,151,48,133,130,151,
- 0,0,0,0,37,24,98,0,0,0,3,166,
- 0,0,4,150,20,133,130,151,0,128,131,167,
- 36,16,68,0,9,0,64,20,0,0,0,0,
- 76,63,192,12,0,0,0,0,0,0,3,150,
- 20,133,130,151,0,0,0,0,36,16,67,0,
- 249,255,64,16,0,0,0,0,48,133,130,151,
- 0,128,131,151,39,16,2,0,36,24,98,0,
- 5,162,2,60,0,128,131,167,0,0,67,164,
- 255,255,163,50,255,255,2,52,125,0,98,16,
- 64,1,147,54,5,162,16,60,50,133,130,151,
- 48,133,132,151,0,128,131,151,39,16,68,0,
- 36,24,98,0,0,128,131,167,0,0,3,166,
- 76,63,192,12,0,1,17,36,0,128,130,151,
- 48,133,131,151,5,162,18,60,37,16,67,0,
- 0,128,130,167,0,0,2,166,36,16,51,2,
- 6,0,64,16,0,0,0,0,0,128,131,151,
- 20,133,130,151,0,0,0,0,95,66,192,8,
- 37,24,98,0,20,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,0,128,131,167,
- 0,0,67,166,76,63,192,12,66,136,17,0,
- 0,128,130,151,50,133,131,151,0,0,0,0,
- 37,16,67,0,0,128,130,167,76,63,192,12,
- 0,0,66,166,50,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,255,255,34,50,
- 0,128,131,167,0,0,67,166,226,255,64,20,
- 36,16,51,2,33,144,160,2,0,128,16,52,
- 0,128,130,151,48,133,131,151,5,162,17,60,
- 37,16,67,0,5,162,3,60,0,128,130,167,
- 0,0,98,164,36,16,18,2,6,0,64,16,
- 0,0,0,0,0,128,131,151,20,133,130,151,
- 0,0,0,0,136,66,192,8,37,24,98,0,
- 20,133,130,151,0,128,131,151,39,16,2,0,
- 36,24,98,0,0,128,131,167,0,0,35,166,
- 76,63,192,12,66,128,16,0,0,128,130,151,
- 50,133,131,151,0,0,0,0,37,16,67,0,
- 0,128,130,167,76,63,192,12,0,0,34,166,
- 50,133,130,151,0,128,131,151,39,16,2,0,
- 36,24,98,0,255,255,2,50,0,128,131,167,
- 0,0,35,166,226,255,64,20,36,16,18,2,
- 5,162,16,60,50,133,130,151,48,133,132,151,
- 0,128,131,151,39,16,68,0,36,24,98,0,
- 0,128,131,167,76,63,192,12,0,0,3,166,
- 0,128,131,151,48,133,130,151,0,0,0,0,
- 37,24,98,0,0,0,3,166,0,0,4,150,
- 20,133,130,151,0,128,131,167,36,16,68,0,
- 9,0,64,20,0,0,0,0,76,63,192,12,
- 0,0,0,0,0,0,3,150,20,133,130,151,
- 0,0,0,0,36,16,67,0,249,255,64,16,
- 0,0,0,0,48,133,130,151,0,128,131,151,
- 39,16,2,0,36,24,98,0,5,162,2,60,
- 0,128,131,167,0,0,67,164,0,1,19,36,
- 5,162,16,60,50,133,130,151,48,133,132,151,
- 0,128,131,151,39,16,68,0,36,24,98,0,
- 0,128,131,167,0,0,3,166,76,63,192,12,
- 0,1,17,36,0,128,130,151,48,133,131,151,
- 5,162,18,60,37,16,67,0,0,128,130,167,
- 0,0,2,166,36,16,113,2,6,0,64,16,
- 0,0,0,0,0,128,131,151,20,133,130,151,
- 0,0,0,0,220,66,192,8,37,24,98,0,
- 20,133,130,151,0,128,131,151,39,16,2,0,
- 36,24,98,0,0,128,131,167,0,0,67,166,
- 76,63,192,12,66,136,17,0,0,128,130,151,
- 50,133,131,151,0,0,0,0,37,16,67,0,
- 0,128,130,167,76,63,192,12,0,0,66,166,
- 50,133,130,151,0,128,131,151,39,16,2,0,
- 36,24,98,0,255,255,34,50,0,128,131,167,
- 0,0,67,166,226,255,64,20,36,16,113,2,
- 60,65,192,12,33,32,128,2,38,16,162,2,
- 255,255,66,48,1,0,66,44,44,0,191,143,
- 40,0,182,143,36,0,181,143,32,0,180,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,48,0,189,39,
- 224,255,189,39,24,0,178,175,33,144,0,0,
- 64,16,4,0,16,0,176,175,33,128,68,0,
- 33,32,0,2,20,0,177,175,255,255,177,48,
- 28,0,191,175,162,65,192,12,33,40,32,2,
- 8,0,64,16,1,0,4,38,162,65,192,12,
- 33,40,32,2,4,0,64,16,2,0,4,38,
- 162,65,192,12,33,40,32,2,43,144,2,0,
- 33,16,64,2,28,0,191,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,216,255,189,39,64,16,4,0,
- 24,0,178,175,33,144,68,0,33,32,64,2,
- 36,0,191,175,32,0,180,175,28,0,179,175,
- 20,0,177,175,60,65,192,12,16,0,176,175,
- 1,0,84,38,33,32,128,2,60,65,192,12,
- 33,136,64,0,2,0,83,38,33,32,96,2,
- 60,65,192,12,33,128,64,0,255,255,35,50,
- 255,255,17,50,8,0,113,20,0,0,0,0,
- 255,255,66,48,3,0,34,18,33,32,96,2,
- 162,65,192,12,33,40,32,2,66,67,192,8,
- 33,16,32,2,255,255,80,48,4,0,112,16,
- 33,32,128,2,5,0,48,22,255,255,2,36,
- 33,32,64,2,162,65,192,12,33,40,0,2,
- 33,16,0,2,36,0,191,143,32,0,180,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,40,0,189,39,
- 0,0,0,0,0,0,0,0,0,96,8,64,
- 0,0,0,0,254,255,1,36,36,72,1,1,
- 0,96,137,64,0,0,133,164,2,0,132,32,
- 2,44,5,0,0,0,133,164,0,96,136,64,
- 8,0,224,3,0,0,0,0,208,255,189,39,
- 32,0,178,175,33,144,128,0,28,0,177,175,
- 33,136,160,0,36,0,179,175,33,152,192,0,
- 40,0,180,175,33,160,224,0,44,0,191,175,
- 2,0,32,22,24,0,176,175,255,255,17,36,
- 0,0,66,142,0,0,0,0,36,16,81,0,
- 3,0,83,20,0,0,0,0,121,67,192,8,
- 1,0,2,36,11,0,128,26,33,128,0,0,
- 143,63,192,12,0,0,0,0,0,0,66,142,
- 0,0,0,0,36,16,81,0,246,255,83,16,
- 1,0,16,38,42,16,20,2,247,255,64,20,
- 0,0,0,0,33,16,0,0,44,0,191,143,
- 40,0,180,143,36,0,179,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 48,0,189,39,208,255,189,39,32,0,178,175,
- 33,144,128,0,28,0,177,175,33,136,160,0,
- 36,0,179,175,33,152,192,0,40,0,180,175,
- 33,160,224,0,44,0,191,175,2,0,32,22,
- 24,0,176,175,255,255,17,52,0,0,66,150,
- 0,0,0,0,36,16,81,0,3,0,83,20,
- 0,0,0,0,162,67,192,8,1,0,2,36,
- 11,0,128,26,33,128,0,0,143,63,192,12,
- 0,0,0,0,0,0,66,150,0,0,0,0,
- 36,16,81,0,246,255,83,16,1,0,16,38,
- 42,16,20,2,247,255,64,20,0,0,0,0,
- 33,16,0,0,44,0,191,143,40,0,180,143,
- 36,0,179,143,32,0,178,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,48,0,189,39,
- 208,255,189,39,32,0,178,175,33,144,128,0,
- 28,0,177,175,33,136,160,0,36,0,179,175,
- 33,152,192,0,40,0,180,175,33,160,224,0,
- 44,0,191,175,2,0,32,22,24,0,176,175,
- 255,0,17,36,0,0,66,146,0,0,0,0,
- 36,16,81,0,3,0,83,20,0,0,0,0,
- 203,67,192,8,1,0,2,36,11,0,128,26,
- 33,128,0,0,143,63,192,12,0,0,0,0,
- 0,0,66,146,0,0,0,0,36,16,81,0,
- 246,255,83,16,1,0,16,38,42,16,20,2,
- 247,255,64,20,0,0,0,0,33,16,0,0,
- 44,0,191,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,48,0,189,39,208,255,189,39,
- 32,0,178,175,33,144,128,0,28,0,177,175,
- 33,136,160,0,36,0,179,175,33,152,192,0,
- 40,0,180,175,33,160,224,0,44,0,191,175,
- 2,0,32,22,24,0,176,175,255,255,17,36,
- 0,0,66,142,0,0,0,0,36,16,81,0,
- 3,0,83,20,0,0,0,0,244,67,192,8,
- 1,0,2,36,11,0,128,26,33,128,0,0,
- 143,63,192,12,0,0,0,0,0,0,66,142,
- 0,0,0,0,36,16,81,0,246,255,83,20,
- 1,0,16,38,42,16,20,2,247,255,64,20,
- 0,0,0,0,33,16,0,0,44,0,191,143,
- 40,0,180,143,36,0,179,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 48,0,189,39,208,255,189,39,32,0,178,175,
- 33,144,128,0,28,0,177,175,33,136,160,0,
- 36,0,179,175,33,152,192,0,40,0,180,175,
- 33,160,224,0,44,0,191,175,2,0,32,22,
- 24,0,176,175,255,255,17,52,0,0,66,150,
- 0,0,0,0,36,16,81,0,3,0,83,20,
- 0,0,0,0,29,68,192,8,1,0,2,36,
- 11,0,128,26,33,128,0,0,143,63,192,12,
- 0,0,0,0,0,0,66,150,0,0,0,0,
- 36,16,81,0,246,255,83,20,1,0,16,38,
- 42,16,20,2,247,255,64,20,0,0,0,0,
- 33,16,0,0,44,0,191,143,40,0,180,143,
- 36,0,179,143,32,0,178,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,48,0,189,39,
- 208,255,189,39,32,0,178,175,33,144,128,0,
- 28,0,177,175,33,136,160,0,36,0,179,175,
- 33,152,192,0,40,0,180,175,33,160,224,0,
- 44,0,191,175,2,0,32,22,24,0,176,175,
- 255,0,17,36,0,0,66,146,0,0,0,0,
- 36,16,81,0,3,0,83,20,0,0,0,0,
- 70,68,192,8,1,0,2,36,11,0,128,26,
- 33,128,0,0,143,63,192,12,0,0,0,0,
- 0,0,66,146,0,0,0,0,36,16,81,0,
- 246,255,83,20,1,0,16,38,42,16,20,2,
- 247,255,64,20,0,0,0,0,33,16,0,0,
- 44,0,191,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,48,0,189,39,0,0,0,0,
- 0,0,0,0,248,255,189,39,255,255,195,36,
- 8,0,192,16,33,56,128,0,255,255,6,36,
- 0,0,162,144,1,0,165,36,255,255,99,36,
- 0,0,130,160,251,255,102,20,1,0,132,36,
- 33,16,224,0,8,0,224,3,8,0,189,39,
- 0,0,0,0,0,0,0,0,0,96,8,64,
- 1,0,9,60,0,96,137,64,15,0,138,48,
- 33,40,170,0,192,255,165,36,0,0,128,160,
- 16,0,128,160,32,0,128,160,251,255,160,28,
- 48,0,128,160,64,0,132,36,0,96,136,64,
- 0,0,0,0,0,0,0,0,8,0,224,3,
- 0,0,0,0,0,0,0,0,1,131,2,60,
- 224,17,66,36,0,32,9,60,37,16,73,0,
- 8,0,64,0,0,0,0,0,0,96,8,64,
- 3,0,9,60,0,96,137,64,15,0,138,48,
- 33,40,170,0,192,255,165,36,0,0,128,160,
- 16,0,128,160,32,0,128,160,251,255,160,28,
- 48,0,128,160,64,0,132,36,0,96,136,64,
- 0,0,0,0,0,0,0,0,8,0,224,3,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,163,3,60,192,3,99,140,
- 0,163,2,60,188,3,66,140,0,0,0,0,
- 16,0,98,16,255,255,2,36,0,163,2,60,
- 188,3,66,140,0,163,1,60,33,8,34,0,
- 200,3,34,144,0,163,3,60,188,3,99,140,
- 0,163,4,60,196,3,132,140,0,22,2,0,
- 3,22,2,0,1,0,99,36,36,24,100,0,
- 0,163,1,60,188,3,35,172,8,0,224,3,
- 0,0,0,0,0,163,6,60,0,1,198,52,
- 10,0,9,36,255,255,8,36,13,0,7,36,
- 0,163,3,60,192,3,99,140,0,163,2,60,
- 188,3,66,140,0,0,0,0,17,0,98,16,
- 255,255,5,36,0,163,2,60,188,3,66,140,
- 0,0,0,0,33,16,70,0,200,2,66,144,
- 0,0,0,0,0,22,2,0,3,46,2,0,
- 0,163,2,60,188,3,66,140,0,163,3,60,
- 196,3,99,140,1,0,66,36,36,16,67,0,
- 0,163,1,60,188,3,34,172,11,0,169,16,
- 11,0,162,40,5,0,64,16,0,0,0,0,
- 228,255,168,16,0,0,0,0,206,68,192,8,
- 0,0,133,160,224,255,167,16,0,0,0,0,
- 206,68,192,8,0,0,133,160,208,68,192,8,
- 0,0,128,160,169,68,192,8,1,0,132,36,
- 8,0,224,3,0,0,0,0,0,0,0,0,
- 0,0,0,0,208,255,189,39,24,0,176,175,
- 33,128,128,0,36,0,179,175,33,152,160,0,
- 28,0,177,175,33,136,0,0,32,0,178,175,
- 33,144,0,2,5,0,64,22,40,0,191,175,
- 54,0,96,22,33,16,0,0,22,69,192,8,
- 0,0,32,174,0,0,67,130,0,0,0,0,
- 233,68,192,8,32,0,2,36,0,0,3,130,
- 32,0,2,36,253,255,98,16,1,0,16,38,
- 255,255,16,38,9,0,2,36,249,255,98,16,
- 1,0,16,38,255,255,16,38,0,0,3,130,
- 45,0,2,36,4,0,98,20,43,0,2,36,
- 1,0,16,38,250,68,192,8,1,0,17,36,
- 3,0,98,20,33,32,0,2,1,0,16,38,
- 33,32,0,2,44,69,192,12,16,0,165,39,
- 7,0,96,18,33,24,64,0,16,0,162,143,
- 0,0,0,0,2,0,80,20,0,0,0,0,
- 33,16,64,2,0,0,98,174,6,0,32,18,
- 0,128,2,60,43,16,67,0,5,0,64,20,
- 255,127,2,60,19,69,192,8,33,16,96,0,
- 5,0,97,4,255,127,2,60,7,0,32,18,
- 255,255,66,52,22,69,192,8,0,128,2,60,
- 33,16,96,0,2,0,32,18,0,0,0,0,
- 35,16,2,0,40,0,191,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,48,0,189,39,0,0,0,0,
- 0,0,0,0,0,0,0,0,208,255,130,36,
- 10,0,66,44,7,0,64,20,1,0,2,36,
- 191,255,130,36,6,0,66,44,3,0,64,20,
- 1,0,2,36,159,255,130,36,6,0,66,44,
- 8,0,224,3,0,0,0,0,248,255,189,39,
- 0,0,176,175,33,56,0,0,33,72,0,0,
- 33,80,0,0,33,112,0,0,5,0,128,20,
- 33,200,128,0,110,0,160,20,33,16,0,0,
- 163,69,192,8,0,0,192,173,0,0,131,128,
- 32,0,2,36,253,255,98,16,1,0,132,36,
- 255,255,132,36,9,0,2,36,249,255,98,16,
- 1,0,132,36,255,255,132,36,0,0,131,128,
- 43,0,2,36,3,0,98,20,45,0,2,36,
- 75,69,192,8,1,0,132,36,3,0,98,20,
- 0,0,0,0,1,0,132,36,1,0,14,36,
- 3,0,192,16,16,0,2,36,16,0,194,20,
- 0,0,0,0,0,0,131,128,48,0,2,36,
- 9,0,98,20,10,0,2,36,1,0,131,128,
- 88,0,2,36,3,0,98,16,120,0,2,36,
- 3,0,98,20,8,0,2,36,16,0,2,36,
- 2,0,132,36,2,0,192,20,0,0,0,0,
- 33,48,64,0,0,0,131,128,255,255,2,36,
- 27,0,70,0,2,0,192,20,0,0,0,0,
- 13,0,7,0,18,64,0,0,16,192,0,0,
- 0,0,0,0,0,0,0,0,42,0,96,16,
- 48,0,98,44,48,0,207,36,11,0,205,40,
- 87,0,204,36,55,0,203,36,5,0,64,20,
- 43,16,111,0,3,0,64,16,0,0,0,0,
- 130,69,192,8,208,255,99,36,30,0,160,21,
- 97,0,98,44,6,0,64,20,65,0,98,44,
- 43,16,108,0,3,0,64,16,65,0,98,44,
- 130,69,192,8,169,255,99,36,21,0,64,20,
- 43,16,107,0,19,0,64,16,0,0,0,0,
- 201,255,99,36,43,16,7,1,6,0,64,20,
- 1,0,9,36,6,0,232,20,24,0,230,0,
- 43,16,3,3,3,0,64,16,0,0,0,0,
- 1,0,10,36,24,0,230,0,1,0,132,36,
- 18,128,0,0,33,56,3,2,0,0,131,128,
- 0,0,0,0,220,255,96,20,48,0,98,44,
- 5,0,64,17,0,0,0,0,13,0,160,16,
- 255,255,2,36,163,69,192,8,0,0,164,172,
- 6,0,160,16,0,0,0,0,3,0,32,21,
- 0,0,0,0,160,69,192,8,0,0,185,172,
- 0,0,164,172,2,0,192,17,33,16,224,0,
- 35,16,2,0,0,0,176,143,8,0,224,3,
- 8,0,189,39,0,0,0,0,0,0,0,0,
- 200,255,189,39,16,0,176,175,7,162,16,60,
- 236,0,16,54,255,240,3,60,255,255,99,52,
- 63,0,132,48,36,0,181,175,128,1,149,52,
- 24,0,178,175,0,1,18,36,20,0,177,175,
- 7,162,17,60,236,0,49,54,44,0,183,175,
- 0,4,23,60,32,0,180,175,255,251,20,60,
- 255,255,148,54,40,0,182,175,0,1,22,60,
- 28,0,179,175,255,254,19,60,48,0,191,175,
- 0,0,2,142,0,0,0,0,36,16,67,0,
- 224,133,130,175,0,0,2,174,76,63,192,12,
- 255,255,115,54,224,133,130,143,0,2,3,60,
- 37,16,67,0,224,133,130,175,0,0,2,174,
- 36,16,85,2,5,0,64,16,0,0,0,0,
- 224,133,130,143,0,0,0,0,214,69,192,8,
- 37,16,87,0,224,133,130,143,0,0,0,0,
- 36,16,84,0,224,133,130,175,76,63,192,12,
- 0,0,34,174,224,133,130,143,0,0,0,0,
- 37,16,86,0,224,133,130,175,0,0,34,174,
- 76,63,192,12,66,144,18,0,224,133,130,143,
- 0,0,0,0,36,16,83,0,224,133,130,175,
- 0,0,34,174,255,255,66,50,230,255,64,20,
- 36,16,85,2,33,136,0,0,16,0,16,36,
- 7,162,18,60,236,0,82,54,0,1,22,60,
- 0,8,21,60,255,254,19,60,255,255,115,54,
- 255,255,20,36,76,63,192,12,0,0,0,0,
- 224,133,130,143,0,0,0,0,37,16,86,0,
- 224,133,130,175,76,63,192,12,0,0,66,174,
- 7,0,0,18,0,0,0,0,0,0,66,142,
- 0,0,0,0,36,16,85,0,2,0,64,16,
- 64,136,17,0,1,0,49,54,76,63,192,12,
- 255,255,16,38,224,133,130,143,0,0,0,0,
- 36,16,83,0,224,133,130,175,0,0,66,174,
- 232,255,20,22,7,162,4,60,236,0,132,52,
- 255,253,3,60,224,133,130,143,255,255,99,52,
- 36,16,67,0,224,133,130,175,0,0,130,172,
- 255,255,34,50,48,0,191,143,44,0,183,143,
- 40,0,182,143,36,0,181,143,32,0,180,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,56,0,189,39,
- 200,255,189,39,48,0,190,175,33,240,160,0,
- 40,0,182,175,63,0,150,48,33,32,192,2,
- 52,0,191,175,44,0,183,175,36,0,181,175,
- 32,0,180,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,168,69,192,12,16,0,176,175,
- 33,152,64,0,255,255,195,51,255,255,98,50,
- 3,0,98,20,7,162,16,60,131,71,192,8,
- 1,0,2,36,236,0,16,54,255,252,3,60,
- 255,255,99,52,0,1,18,36,7,162,17,60,
- 236,0,49,54,255,251,21,60,255,255,181,54,
- 0,1,23,60,255,254,20,60,224,133,130,143,
- 0,0,0,0,36,16,67,0,224,133,130,175,
- 0,0,2,174,76,63,192,12,255,255,148,54,
- 224,133,130,143,0,2,3,60,37,16,67,0,
- 224,133,130,175,0,0,2,174,48,1,66,50,
- 5,0,64,16,0,4,6,60,224,133,130,143,
- 0,0,0,0,83,70,192,8,37,16,70,0,
- 224,133,130,143,0,0,0,0,36,16,85,0,
- 224,133,130,175,76,63,192,12,0,0,34,174,
- 224,133,130,143,0,0,0,0,37,16,87,0,
- 224,133,130,175,0,0,34,174,76,63,192,12,
- 66,144,18,0,224,133,130,143,0,0,0,0,
- 36,16,84,0,224,133,130,175,0,0,34,174,
- 255,255,66,50,230,255,64,20,48,1,66,50,
- 255,255,195,51,255,255,98,50,39,16,2,0,
- 36,24,98,0,88,0,96,16,192,1,213,54,
- 7,162,16,60,236,0,16,54,255,252,3,60,
- 255,255,99,52,0,1,18,36,7,162,17,60,
- 236,0,49,54,255,251,20,60,255,255,148,54,
- 0,1,23,60,255,254,19,60,224,133,130,143,
- 0,0,0,0,36,16,67,0,224,133,130,175,
- 0,0,2,174,76,63,192,12,255,255,115,54,
- 224,133,130,143,0,2,3,60,37,16,67,0,
- 224,133,130,175,0,0,2,174,36,16,85,2,
- 5,0,64,16,0,4,6,60,224,133,130,143,
- 0,0,0,0,140,70,192,8,37,16,70,0,
- 224,133,130,143,0,0,0,0,36,16,84,0,
- 224,133,130,175,76,63,192,12,0,0,34,174,
- 224,133,130,143,0,0,0,0,37,16,87,0,
- 224,133,130,175,0,0,34,174,76,63,192,12,
- 66,144,18,0,224,133,130,143,0,0,0,0,
- 36,16,83,0,224,133,130,175,0,0,34,174,
- 255,255,66,50,230,255,64,20,36,16,85,2,
- 7,162,16,60,236,0,16,54,255,252,3,60,
- 224,133,130,143,255,255,99,52,36,16,67,0,
- 224,133,130,175,76,63,192,12,0,0,2,174,
- 224,133,130,143,0,2,3,60,37,16,67,0,
- 224,133,130,175,0,0,2,174,0,0,2,142,
- 0,8,3,60,36,16,67,0,11,0,64,20,
- 7,162,4,60,7,162,16,60,236,0,16,54,
- 0,8,17,60,76,63,192,12,0,0,0,0,
- 0,0,2,142,0,0,0,0,36,16,81,0,
- 250,255,64,16,7,162,4,60,236,0,132,52,
- 255,253,3,60,224,133,130,143,255,255,99,52,
- 36,16,67,0,224,133,130,175,0,0,130,172,
- 255,255,195,51,255,255,2,52,133,0,98,16,
- 64,1,213,54,7,162,16,60,236,0,16,54,
- 255,252,3,60,255,255,99,52,0,1,18,36,
- 7,162,17,60,236,0,49,54,255,251,20,60,
- 255,255,148,54,0,1,23,60,255,254,19,60,
- 224,133,130,143,0,0,0,0,36,16,67,0,
- 224,133,130,175,0,0,2,174,76,63,192,12,
- 255,255,115,54,224,133,130,143,0,2,3,60,
- 37,16,67,0,224,133,130,175,0,0,2,174,
- 36,16,85,2,5,0,64,16,0,4,6,60,
- 224,133,130,143,0,0,0,0,231,70,192,8,
- 37,16,70,0,224,133,130,143,0,0,0,0,
- 36,16,84,0,224,133,130,175,76,63,192,12,
- 0,0,34,174,224,133,130,143,0,0,0,0,
- 37,16,87,0,224,133,130,175,0,0,34,174,
- 76,63,192,12,66,144,18,0,224,133,130,143,
- 0,0,0,0,36,16,83,0,224,133,130,175,
- 0,0,34,174,255,255,66,50,230,255,64,20,
- 36,16,85,2,33,160,192,3,7,162,2,60,
- 236,0,66,52,0,128,17,52,7,162,16,60,
- 236,0,16,54,0,4,23,60,255,251,19,60,
- 255,255,115,54,0,1,21,60,255,254,18,60,
- 255,255,82,54,224,133,131,143,0,2,4,60,
- 37,24,100,0,224,133,131,175,0,0,67,172,
- 36,16,52,2,5,0,64,16,0,0,0,0,
- 224,133,130,143,0,0,0,0,20,71,192,8,
- 37,16,87,0,224,133,130,143,0,0,0,0,
- 36,16,83,0,224,133,130,175,76,63,192,12,
- 0,0,2,174,224,133,130,143,0,0,0,0,
- 37,16,85,0,224,133,130,175,0,0,2,174,
- 76,63,192,12,66,136,17,0,224,133,130,143,
- 0,0,0,0,36,16,82,0,224,133,130,175,
- 0,0,2,174,255,255,34,50,230,255,64,20,
- 36,16,52,2,7,162,16,60,236,0,16,54,
- 255,252,3,60,224,133,130,143,255,255,99,52,
- 36,16,67,0,224,133,130,175,76,63,192,12,
- 0,0,2,174,224,133,130,143,0,2,3,60,
- 37,16,67,0,224,133,130,175,0,0,2,174,
- 0,0,2,142,0,8,3,60,36,16,67,0,
- 11,0,64,20,7,162,4,60,7,162,16,60,
- 236,0,16,54,0,8,17,60,76,63,192,12,
- 0,0,0,0,0,0,2,142,0,0,0,0,
- 36,16,81,0,250,255,64,16,7,162,4,60,
- 236,0,132,52,255,253,3,60,224,133,130,143,
- 255,255,99,52,36,16,67,0,224,133,130,175,
- 0,0,130,172,7,162,16,60,236,0,16,54,
- 255,252,3,60,255,255,99,52,0,1,18,36,
- 7,162,17,60,236,0,49,54,0,4,23,60,
- 255,251,20,60,255,255,148,54,0,1,21,60,
- 255,254,19,60,224,133,130,143,0,0,0,0,
- 36,16,67,0,224,133,130,175,0,0,2,174,
- 76,63,192,12,255,255,115,54,224,133,130,143,
- 0,2,3,60,37,16,67,0,224,133,130,175,
- 0,0,2,174,0,1,66,50,5,0,64,16,
- 0,0,0,0,224,133,130,143,0,0,0,0,
- 108,71,192,8,37,16,87,0,224,133,130,143,
- 0,0,0,0,36,16,84,0,224,133,130,175,
- 76,63,192,12,0,0,34,174,224,133,130,143,
- 0,0,0,0,37,16,85,0,224,133,130,175,
- 0,0,34,174,76,63,192,12,66,144,18,0,
- 224,133,130,143,0,0,0,0,36,16,83,0,
- 224,133,130,175,0,0,34,174,255,255,66,50,
- 230,255,64,20,0,1,66,50,168,69,192,12,
- 33,32,192,2,38,16,194,3,255,255,66,48,
- 1,0,66,44,52,0,191,143,48,0,190,143,
- 44,0,183,143,40,0,182,143,36,0,181,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 56,0,189,39,0,0,0,0,248,255,189,39,
- 255,255,195,36,6,0,192,16,33,16,128,0,
- 255,255,6,36,0,0,133,160,255,255,99,36,
- 253,255,102,20,1,0,132,36,8,0,189,39,
- 8,0,224,3,0,0,0,0,159,71,192,8,
- 33,24,0,0,1,0,99,36,0,0,130,128,
- 0,0,0,0,252,255,64,20,1,0,132,36,
- 8,0,224,3,33,16,96,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,255,255,198,36,
- 10,0,192,16,0,0,0,0,0,0,131,128,
- 0,0,162,128,0,0,0,0,5,0,98,20,
- 0,0,0,0,1,0,132,36,255,255,198,36,
- 248,255,192,20,1,0,165,36,0,0,131,144,
- 0,0,162,144,0,0,0,0,8,0,224,3,
- 35,16,98,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,196,71,192,8,240,255,189,39,
- 0,0,163,128,3,22,2,0,8,0,67,20,
- 0,0,0,0,1,0,132,36,1,0,165,36,
- 0,0,130,128,0,0,131,144,0,0,0,0,
- 246,255,64,20,0,22,3,0,0,0,131,144,
- 0,0,162,144,0,0,0,0,35,16,98,0,
- 8,0,224,3,16,0,189,39,0,0,0,0,
- 255,255,198,36,9,0,192,4,33,16,0,0,
- 0,0,130,144,0,0,0,0,5,0,69,16,
- 33,16,128,0,255,255,198,36,250,255,193,4,
- 1,0,132,36,33,16,0,0,8,0,224,3,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,2,0,192,20,255,255,2,36,
- 1,0,2,36,8,0,224,3,0,0,226,172,
- 232,255,189,39,20,0,191,175,16,0,176,175,
- 40,0,176,143,33,32,192,0,4,0,5,142,
- 0,0,0,0,15,86,192,12,255,255,230,48,
- 3,0,64,16,255,255,2,36,243,71,192,8,
- 0,0,2,174,0,0,0,174,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 208,255,189,39,40,0,191,175,33,24,128,0,
- 64,0,162,143,32,0,160,175,36,0,162,175,
- 12,0,66,148,0,0,0,0,2,0,64,20,
- 33,32,160,0,120,5,2,36,255,255,66,48,
- 16,0,162,175,1,131,2,60,148,31,66,36,
- 20,0,162,175,1,131,2,60,128,31,66,36,
- 24,0,162,175,32,0,162,39,28,0,162,175,
- 166,85,192,12,33,40,96,0,32,0,162,143,
- 40,0,191,143,48,0,189,39,8,0,224,3,
- 0,0,0,0,0,0,0,0,88,0,131,148,
- 4,0,2,36,9,0,98,20,0,0,0,0,
- 33,72,192,8,116,0,132,36,33,16,69,0,
- 128,16,2,0,8,0,131,140,0,0,0,0,
- 46,72,192,8,33,16,67,0,104,0,132,36,
- 12,0,128,16,33,16,0,0,4,0,130,140,
- 0,0,0,0,42,16,162,0,243,255,64,20,
- 0,17,5,0,4,0,130,140,12,0,132,140,
- 0,0,0,0,247,255,128,20,35,40,162,0,
- 33,16,0,0,8,0,224,3,0,0,0,0,
- 88,0,131,148,4,0,2,36,3,0,98,20,
- 33,48,0,0,55,72,192,8,116,0,132,36,
- 104,0,132,36,8,0,130,140,0,0,0,0,
- 43,16,162,0,14,0,64,16,255,255,2,36,
- 92,72,192,8,0,0,0,0,35,24,163,0,
- 0,17,3,0,35,16,67,0,0,26,2,0,
- 33,16,67,0,0,28,2,0,33,16,67,0,
- 35,16,2,0,131,16,2,0,92,72,192,8,
- 33,16,194,0,18,0,128,16,0,0,0,0,
- 4,0,131,140,0,0,0,0,0,17,3,0,
- 33,16,67,0,128,16,2,0,8,0,131,140,
- 0,0,0,0,33,16,67,0,43,16,162,0,
- 233,255,64,20,0,0,0,0,4,0,130,140,
- 12,0,132,140,0,0,0,0,241,255,128,20,
- 33,48,194,0,255,255,2,36,8,0,224,3,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 8,0,130,36,144,0,163,140,120,132,135,39,
- 2,0,96,16,20,0,137,36,33,56,96,0,
- 0,0,72,140,4,0,68,140,132,72,192,8,
- 0,0,0,0,30,0,0,25,0,0,0,0,
- 4,0,227,140,0,0,0,0,4,0,98,140,
- 0,0,0,0,55,0,64,16,255,255,2,36,
- 0,0,135,140,0,0,98,140,0,0,0,0,
- 8,0,71,16,0,0,0,0,8,0,99,36,
- 4,0,98,140,0,0,0,0,248,255,64,20,
- 255,255,2,36,168,72,192,8,0,0,0,0,
- 0,0,130,140,0,0,0,0,4,0,34,173,
- 4,0,103,140,255,255,8,37,4,0,132,36,
- 0,0,226,148,0,0,0,0,1,0,66,48,
- 226,255,64,16,0,0,0,0,0,0,226,148,
- 0,0,0,0,64,0,66,48,27,0,64,20,
- 255,255,2,36,0,0,226,148,0,0,0,0,
- 1,0,66,48,17,0,64,16,0,0,0,0,
- 13,0,192,16,1,0,2,36,64,0,162,140,
- 0,0,0,0,9,0,64,20,1,0,2,36,
- 28,0,226,140,4,0,163,140,0,0,0,0,
- 36,16,67,0,3,0,64,20,1,0,2,36,
- 168,72,192,8,255,255,2,36,164,72,192,8,
- 0,0,34,165,0,0,32,165,8,0,40,173,
- 12,0,36,173,16,0,39,173,33,16,0,0,
- 8,0,224,3,0,0,0,0,200,255,189,39,
- 48,0,191,175,44,0,179,175,40,0,178,175,
- 36,0,177,175,32,0,176,175,33,152,128,0,
- 33,128,160,0,33,144,192,0,0,0,4,142,
- 0,0,0,0,48,0,130,40,2,0,64,16,
- 8,0,113,38,48,0,4,36,0,0,36,174,
- 9,50,192,12,128,32,4,0,3,0,64,20,
- 4,0,34,174,214,72,192,8,255,255,2,36,
- 144,0,66,142,120,132,132,39,2,0,64,16,
- 0,0,0,0,33,32,64,0,16,0,160,175,
- 20,0,179,175,24,0,178,175,0,0,5,142,
- 4,0,6,142,0,0,0,0,221,72,192,12,
- 33,56,32,2,33,128,64,0,4,0,0,26,
- 0,0,0,0,0,0,34,142,214,72,192,8,
- 0,0,0,0,110,86,192,12,33,32,32,2,
- 33,16,0,2,48,0,191,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,56,0,189,39,184,255,189,39,
- 68,0,191,175,64,0,190,175,60,0,183,175,
- 56,0,182,175,52,0,181,175,48,0,180,175,
- 44,0,179,175,40,0,178,175,36,0,177,175,
- 32,0,176,175,33,144,128,0,33,176,160,0,
- 33,136,224,0,88,0,183,143,92,0,179,143,
- 96,0,190,143,32,0,226,38,0,0,36,142,
- 0,0,0,0,42,16,130,0,22,0,64,16,
- 33,160,192,0,4,0,132,36,9,50,192,12,
- 128,32,4,0,33,128,64,0,3,0,0,22,
- 33,32,0,2,153,73,192,8,255,255,2,36,
- 0,0,38,142,4,0,37,142,0,0,0,0,
- 80,68,192,12,128,48,6,0,4,0,36,142,
- 61,50,192,12,0,0,0,0,4,0,48,174,
- 0,0,34,142,0,0,0,0,4,0,66,36,
- 0,0,34,174,0,0,66,150,0,0,0,0,
- 1,0,66,48,96,0,64,20,0,0,0,0,
- 33,0,192,30,0,0,0,0,4,0,80,142,
- 0,0,0,0,4,0,2,142,0,0,0,0,
- 108,0,64,16,128,160,23,0,1,0,242,38,
- 4,0,34,142,0,0,0,0,33,16,130,2,
- 0,0,3,142,0,0,0,0,0,0,67,172,
- 0,0,2,142,0,0,0,0,24,0,98,174,
- 16,0,178,175,20,0,179,175,24,0,190,175,
- 4,0,4,142,33,40,0,0,33,48,0,0,
- 221,72,192,12,33,56,32,2,112,0,64,20,
- 8,0,16,38,4,0,2,142,0,0,0,0,
- 234,255,64,20,33,16,0,0,153,73,192,8,
- 0,0,0,0,4,0,80,142,0,0,0,0,
- 4,0,2,142,0,0,0,0,76,0,64,16,
- 128,168,23,0,1,0,242,38,0,0,3,142,
- 0,0,132,142,0,0,0,0,43,16,100,0,
- 42,0,64,20,0,0,0,0,19,0,100,20,
- 255,255,197,38,4,0,34,142,0,0,0,0,
- 33,16,162,2,0,0,67,172,0,0,2,142,
- 0,0,0,0,24,0,98,174,16,0,178,175,
- 20,0,179,175,24,0,190,175,4,0,4,142,
- 4,0,134,38,221,72,192,12,33,56,32,2,
- 25,0,64,16,8,0,16,38,153,73,192,8,
- 0,0,0,0,0,0,130,142,0,0,0,0,
- 43,16,67,0,17,0,64,16,33,40,0,0,
- 4,0,34,142,0,0,0,0,33,16,162,2,
- 0,0,67,172,0,0,2,142,0,0,0,0,
- 24,0,98,174,16,0,178,175,20,0,179,175,
- 24,0,190,175,4,0,4,142,33,48,0,0,
- 221,72,192,12,33,56,32,2,52,0,64,20,
- 0,0,0,0,8,0,16,38,4,0,2,142,
- 0,0,0,0,205,255,64,20,33,16,0,0,
- 153,73,192,8,0,0,0,0,0,0,66,150,
- 0,0,0,0,64,0,66,48,40,0,64,20,
- 33,16,0,0,3,0,66,146,0,0,0,0,
- 1,0,66,48,11,0,64,16,33,24,64,2,
- 64,0,194,143,0,0,0,0,9,0,64,20,
- 0,0,0,0,28,0,98,140,4,0,195,143,
- 0,0,0,0,36,16,67,0,3,0,64,20,
- 0,0,0,0,153,73,192,8,33,16,0,0,
- 14,0,192,26,33,16,246,2,0,0,34,174,
- 4,0,36,142,128,128,23,0,33,32,4,2,
- 33,40,128,2,80,68,192,12,128,48,22,0,
- 28,0,118,174,4,0,34,142,0,0,0,0,
- 33,128,2,2,149,73,192,8,32,0,112,174,
- 0,0,55,174,28,0,96,174,32,0,96,174,
- 36,0,114,174,1,0,2,36,20,0,98,166,
- 1,0,2,36,68,0,191,143,64,0,190,143,
- 60,0,183,143,56,0,182,143,52,0,181,143,
- 48,0,180,143,44,0,179,143,40,0,178,143,
- 36,0,177,143,32,0,176,143,8,0,224,3,
- 72,0,189,39,3,0,160,28,33,16,0,0,
- 0,0,224,172,1,0,2,36,8,0,224,3,
- 0,0,0,0,208,255,189,39,44,0,191,175,
- 40,0,178,175,36,0,177,175,32,0,176,175,
- 33,144,128,0,33,136,224,0,64,0,176,143,
- 0,0,0,0,6,0,160,24,24,0,160,175,
- 17,0,2,146,0,0,0,0,18,0,66,52,
- 200,73,192,8,17,0,2,162,33,32,32,2,
- 33,40,0,2,1,0,6,36,253,76,192,12,
- 24,0,167,39,36,0,2,142,16,0,176,175,
- 8,0,66,140,33,32,64,2,1,0,5,36,
- 24,0,166,39,9,248,64,0,33,56,32,2,
- 44,0,191,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,48,0,189,39,
- 224,255,189,39,28,0,191,175,24,0,178,175,
- 20,0,177,175,33,144,128,0,33,136,160,0,
- 31,0,81,18,16,0,176,175,4,0,80,142,
- 0,0,0,0,4,0,2,142,0,0,0,0,
- 10,0,64,16,0,0,0,0,4,0,4,142,
- 0,0,0,0,206,73,192,12,33,40,32,2,
- 8,0,16,38,4,0,2,142,0,0,0,0,
- 248,255,64,20,0,0,0,0,0,0,66,150,
- 0,0,0,0,32,0,66,48,4,0,64,16,
- 0,0,0,0,4,0,68,142,61,50,192,12,
- 0,0,0,0,0,0,66,150,0,0,0,0,
- 16,0,66,48,3,0,64,16,0,0,0,0,
- 61,50,192,12,33,32,64,2,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,120,132,131,39,
- 2,0,128,16,0,0,0,0,33,24,128,0,
- 0,0,167,140,4,0,165,140,26,74,192,8,
- 0,0,0,0,28,0,224,24,0,0,0,0,
- 4,0,99,140,0,0,0,0,4,0,98,140,
- 0,0,0,0,11,0,64,16,0,0,0,0,
- 0,0,164,140,0,0,98,140,0,0,0,0,
- 9,0,68,16,0,0,0,0,8,0,99,36,
- 4,0,98,140,0,0,0,0,248,255,64,20,
- 0,0,0,0,0,0,192,172,33,74,192,8,
- 2,0,2,36,4,0,99,140,255,255,231,36,
- 4,0,165,36,0,0,98,148,0,0,0,0,
- 1,0,66,48,228,255,64,16,0,0,0,0,
- 0,0,195,172,42,16,7,0,8,0,224,3,
- 0,0,0,0,208,255,189,39,44,0,191,175,
- 40,0,182,175,36,0,181,175,32,0,180,175,
- 28,0,179,175,24,0,178,175,20,0,177,175,
- 16,0,176,175,33,168,192,0,0,0,162,140,
- 0,0,0,0,3,0,64,28,33,48,0,0,
- 220,74,192,8,5,0,2,36,120,132,147,39,
- 2,0,128,16,0,0,224,172,33,152,128,0,
- 0,0,177,140,4,0,180,140,84,74,192,8,
- 0,0,0,0,29,0,32,26,0,0,0,0,
- 4,0,102,142,0,0,0,0,4,0,194,140,
- 0,0,0,0,23,0,64,16,0,0,0,0,
- 0,0,131,142,0,0,194,140,0,0,0,0,
- 6,0,67,16,0,0,0,0,8,0,198,36,
- 4,0,194,140,0,0,0,0,248,255,64,20,
- 0,0,0,0,4,0,194,140,0,0,0,0,
- 9,0,64,16,0,0,0,0,255,255,49,38,
- 4,0,148,38,33,152,64,0,0,0,98,150,
- 0,0,0,0,1,0,66,48,227,255,64,16,
- 0,0,0,0,29,0,32,22,0,0,0,0,
- 0,0,99,150,0,0,0,0,1,0,98,48,
- 11,0,64,16,4,0,98,48,123,0,64,16,
- 3,0,2,36,0,0,162,150,0,0,0,0,
- 1,0,66,48,118,0,64,16,4,0,2,36,
- 0,0,243,172,219,74,192,8,4,0,213,172,
- 0,0,98,150,0,0,0,0,4,0,66,48,
- 110,0,64,16,3,0,2,36,0,0,162,150,
- 0,0,0,0,1,0,66,48,105,0,64,20,
- 4,0,2,36,0,0,243,172,219,74,192,8,
- 4,0,213,172,0,0,98,150,0,0,0,0,
- 1,0,66,48,97,0,64,20,2,0,2,36,
- 2,0,34,42,23,0,64,20,33,144,160,2,
- 56,0,22,36,9,50,192,12,16,0,4,36,
- 33,128,64,0,40,0,0,18,128,16,17,0,
- 33,16,84,0,252,255,66,140,0,0,0,0,
- 0,0,2,174,4,0,18,174,8,0,0,174,
- 12,0,0,174,9,50,192,12,8,0,4,36,
- 33,144,64,0,24,0,64,18,255,255,49,38,
- 0,0,86,166,2,0,34,42,236,255,64,16,
- 4,0,80,174,4,0,102,142,0,0,0,0,
- 4,0,194,140,0,0,0,0,6,0,64,16,
- 1,0,17,36,8,0,198,36,4,0,194,140,
- 0,0,0,0,252,255,64,20,1,0,49,38,
- 1,0,36,38,9,50,192,12,192,32,4,0,
- 33,128,64,0,12,0,0,22,33,32,64,2,
- 173,74,192,8,0,0,0,0,0,0,18,142,
- 0,0,0,0,61,50,192,12,33,32,0,2,
- 33,32,64,2,206,73,192,12,33,40,160,2,
- 220,74,192,8,1,0,2,36,4,0,102,142,
- 0,0,0,0,192,74,192,8,33,168,0,2,
- 4,0,194,140,0,0,0,0,14,0,64,16,
- 0,0,0,0,0,0,194,140,4,0,195,140,
- 0,0,2,174,4,0,3,174,8,0,198,36,
- 8,0,16,38,255,255,49,38,0,0,194,140,
- 0,0,131,142,0,0,0,0,43,16,67,0,
- 240,255,64,20,0,0,0,0,0,0,130,142,
- 0,0,0,0,0,0,2,174,4,0,18,174,
- 8,0,4,38,33,40,192,0,80,68,192,12,
- 192,48,17,0,4,0,102,142,4,0,117,174,
- 0,0,98,150,0,0,0,0,32,0,66,48,
- 3,0,64,16,0,0,0,0,61,50,192,12,
- 33,32,192,0,0,0,98,150,0,0,0,0,
- 32,0,66,52,0,0,98,166,33,16,0,0,
- 44,0,191,143,40,0,182,143,36,0,181,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 48,0,189,39,232,255,189,39,20,0,191,175,
- 16,0,176,175,0,0,162,140,0,0,0,0,
- 85,0,64,24,33,16,0,0,120,132,144,39,
- 2,0,128,16,0,0,0,0,33,128,128,0,
- 0,0,164,140,4,0,165,140,0,0,0,0,
- 0,0,168,140,0,0,2,150,0,0,0,0,
- 33,24,64,0,1,0,66,48,34,0,64,20,
- 33,56,0,2,32,0,128,24,8,0,98,48,
- 4,0,6,142,5,0,64,16,0,0,0,0,
- 12,0,194,140,0,0,0,0,3,0,64,16,
- 0,0,0,0,33,56,0,2,0,0,168,140,
- 0,0,195,140,0,0,162,140,0,0,0,0,
- 10,0,98,16,0,0,0,0,0,0,163,140,
- 4,0,194,140,0,0,0,0,20,0,64,16,
- 8,0,198,36,0,0,194,140,0,0,0,0,
- 249,255,67,20,0,0,0,0,255,255,132,36,
- 4,0,208,140,0,0,0,0,0,0,3,150,
- 0,0,0,0,1,0,98,48,224,255,64,16,
- 4,0,165,36,36,0,128,20,33,16,0,0,
- 0,0,2,150,0,0,0,0,2,0,66,48,
- 3,0,64,20,0,0,0,0,65,75,192,8,
- 33,16,0,0,4,0,230,140,0,0,0,0,
- 0,0,194,140,0,0,0,0,7,0,72,16,
- 0,0,0,0,8,0,198,36,0,0,194,140,
- 0,0,0,0,253,255,72,20,8,0,198,36,
- 248,255,198,36,4,0,199,140,0,0,0,0,
- 10,0,224,16,33,32,224,0,8,0,194,140,
- 12,0,195,140,0,0,194,172,4,0,195,172,
- 8,0,198,36,4,0,194,140,0,0,0,0,
- 248,255,64,20,33,32,224,0,206,73,192,12,
- 33,40,0,2,33,16,0,2,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 192,255,189,39,56,0,191,175,52,0,181,175,
- 48,0,180,175,44,0,179,175,40,0,178,175,
- 36,0,177,175,32,0,176,175,33,136,128,0,
- 33,144,160,0,33,152,192,0,33,160,224,0,
- 80,0,181,143,0,0,0,0,36,0,162,142,
- 0,0,0,0,20,0,80,140,33,32,128,2,
- 48,72,192,12,33,40,160,2,16,0,3,142,
- 0,0,0,0,16,0,163,175,20,0,180,175,
- 24,0,162,175,0,0,2,142,1,0,4,36,
- 33,40,32,2,33,48,64,2,9,248,64,0,
- 33,56,96,2,6,0,64,20,33,32,128,2,
- 17,0,162,146,0,0,0,0,1,0,66,52,
- 113,75,192,8,17,0,162,162,33,40,160,2,
- 59,77,192,12,33,48,64,0,56,0,191,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,64,0,189,39,192,255,189,39,
- 60,0,191,175,56,0,178,175,52,0,177,175,
- 48,0,176,175,33,136,224,0,80,0,178,143,
- 36,0,160,175,36,0,66,142,0,0,0,0,
- 20,0,67,140,2,0,80,144,0,0,0,0,
- 255,0,2,50,254,255,71,36,70,0,226,44,
- 110,0,64,16,128,16,7,0,2,131,1,60,
- 33,8,34,0,160,151,34,140,0,0,0,0,
- 8,0,64,0,0,0,0,0,16,0,177,175,
- 8,0,98,140,16,0,103,140,9,248,64,0,
- 0,0,0,0,2,0,3,36,16,0,67,162,
- 251,75,192,8,40,0,66,174,16,0,177,175,
- 8,0,98,140,16,0,103,140,9,248,64,0,
- 0,0,0,0,40,0,162,175,16,0,80,162,
- 40,0,162,143,0,0,0,0,251,75,192,8,
- 40,0,66,174,32,0,162,39,16,0,162,175,
- 20,0,177,175,36,0,162,39,24,0,162,175,
- 8,0,98,140,16,0,103,140,9,248,64,0,
- 0,0,0,0,33,48,64,0,16,0,80,162,
- 17,0,66,146,0,0,0,0,2,0,66,52,
- 17,0,66,162,36,0,162,143,0,0,0,0,
- 43,16,2,0,40,0,66,166,44,0,70,174,
- 32,0,162,151,0,0,0,0,33,16,194,0,
- 48,0,66,174,255,75,192,8,52,0,64,166,
- 16,0,177,175,36,0,162,39,20,0,162,175,
- 8,0,98,140,16,0,103,140,9,248,64,0,
- 0,0,0,0,33,128,64,0,8,0,0,22,
- 33,32,32,2,16,0,160,175,33,40,64,2,
- 33,48,0,0,226,76,192,12,33,56,0,0,
- 255,75,192,8,0,0,0,0,36,0,162,143,
- 0,0,0,0,16,0,162,175,0,0,6,142,
- 4,0,7,142,0,0,0,0,226,76,192,12,
- 33,40,64,2,36,0,162,143,0,0,0,0,
- 35,0,64,16,0,0,0,0,61,50,192,12,
- 33,32,0,2,255,75,192,8,0,0,0,0,
- 5,0,2,36,251,75,192,8,16,0,66,162,
- 16,0,177,175,40,0,162,39,20,0,162,175,
- 8,0,98,140,16,0,103,140,9,248,64,0,
- 0,0,0,0,33,48,64,0,7,0,192,16,
- 64,0,2,36,3,0,194,136,0,0,194,152,
- 0,0,0,0,43,0,162,171,40,0,162,187,
- 64,0,2,36,16,0,66,162,40,0,162,143,
- 0,0,0,0,251,75,192,8,40,0,66,174,
- 5,0,2,36,96,0,34,174,17,0,66,146,
- 0,0,0,0,2,0,66,52,17,0,66,162,
- 60,0,191,143,56,0,178,143,52,0,177,143,
- 48,0,176,143,8,0,224,3,64,0,189,39,
- 80,255,189,39,168,0,191,175,164,0,179,175,
- 160,0,178,175,156,0,177,175,152,0,176,175,
- 33,152,128,0,33,136,224,0,192,0,178,143,
- 0,0,0,0,36,0,66,142,0,0,0,0,
- 20,0,67,140,0,0,0,0,16,0,98,140,
- 0,0,0,0,16,0,162,175,20,0,177,175,
- 4,0,98,140,0,0,0,0,9,248,64,0,
- 24,0,167,39,33,128,64,0,6,0,0,22,
- 33,32,32,2,17,0,66,146,0,0,0,0,
- 18,0,66,52,45,76,192,8,17,0,66,162,
- 33,40,64,2,33,48,0,2,253,76,192,12,
- 24,0,167,39,16,0,178,175,33,32,96,2,
- 33,40,0,2,24,0,166,39,122,75,192,12,
- 33,56,32,2,168,0,191,143,164,0,179,143,
- 160,0,178,143,156,0,177,143,152,0,176,143,
- 8,0,224,3,176,0,189,39,192,255,189,39,
- 56,0,191,175,52,0,181,175,48,0,180,175,
- 44,0,179,175,40,0,178,175,36,0,177,175,
- 32,0,176,175,33,152,128,0,33,160,160,0,
- 33,168,192,0,33,136,224,0,80,0,178,143,
- 0,0,0,0,36,0,66,142,0,0,0,0,
- 20,0,80,140,33,32,32,2,48,72,192,12,
- 33,40,64,2,16,0,3,142,0,0,0,0,
- 16,0,163,175,20,0,177,175,24,0,162,175,
- 0,0,2,142,33,32,0,0,33,40,96,2,
- 33,48,128,2,9,248,64,0,33,56,160,2,
- 5,0,64,16,33,32,32,2,200,76,192,12,
- 33,40,64,2,95,76,192,8,0,0,0,0,
- 16,0,178,175,33,32,96,2,33,40,128,2,
- 33,48,160,2,122,75,192,12,33,56,32,2,
- 56,0,191,143,52,0,181,143,48,0,180,143,
- 44,0,179,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,64,0,189,39,
- 192,255,189,39,56,0,191,175,52,0,181,175,
- 48,0,180,175,44,0,179,175,40,0,178,175,
- 36,0,177,175,32,0,176,175,33,152,128,0,
- 33,160,160,0,33,168,192,0,80,0,177,143,
- 0,0,0,0,36,0,34,142,0,0,0,0,
- 20,0,82,140,2,0,66,144,0,0,0,0,
- 254,255,67,36,70,0,98,44,57,0,64,16,
- 33,128,224,0,128,16,3,0,2,131,1,60,
- 33,8,34,0,184,152,34,140,0,0,0,0,
- 8,0,64,0,0,0,0,0,33,32,0,2,
- 48,72,192,12,33,40,32,2,40,0,35,142,
- 0,0,0,0,16,0,163,175,20,0,176,175,
- 173,76,192,8,24,0,162,175,33,32,0,2,
- 48,72,192,12,33,40,32,2,44,0,35,142,
- 0,0,0,0,16,0,163,175,48,0,35,142,
- 44,0,36,142,0,0,0,0,35,24,100,0,
- 170,76,192,8,255,255,99,48,33,32,0,2,
- 48,72,192,12,33,40,32,2,40,0,35,142,
- 0,0,0,0,16,0,163,175,44,0,35,142,
- 0,0,0,0,171,76,192,8,20,0,163,175,
- 33,32,0,2,48,72,192,12,33,40,32,2,
- 40,0,35,38,16,0,163,175,4,0,3,36,
- 20,0,163,175,24,0,176,175,28,0,162,175,
- 12,0,66,142,33,32,96,2,33,40,128,2,
- 16,0,71,142,0,0,0,0,9,248,64,0,
- 33,48,160,2,184,76,192,8,0,0,0,0,
- 5,0,2,36,96,0,2,174,17,0,34,146,
- 0,0,0,0,2,0,66,52,17,0,34,162,
- 56,0,191,143,52,0,181,143,48,0,180,143,
- 44,0,179,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,64,0,189,39,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 224,255,189,39,24,0,191,175,20,0,177,175,
- 16,0,176,175,33,128,128,0,64,0,2,142,
- 0,0,0,0,7,0,64,20,33,136,160,0,
- 2,0,2,36,48,72,192,12,96,0,2,174,
- 1,0,66,36,217,76,192,8,100,0,2,174,
- 129,0,2,36,16,0,34,162,17,0,34,146,
- 0,0,0,0,2,0,66,52,17,0,34,162,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,232,255,189,39,
- 20,0,191,175,16,0,176,175,33,128,128,0,
- 33,64,160,0,33,32,192,0,33,40,224,0,
- 40,0,162,143,17,0,3,145,0,0,0,0,
- 2,0,99,52,17,0,3,161,6,0,3,36,
- 4,0,64,16,16,0,3,161,40,0,4,173,
- 249,76,192,8,44,0,5,173,80,86,192,12,
- 40,0,6,37,2,0,64,16,5,0,2,36,
- 96,0,2,174,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,200,255,189,39,
- 48,0,191,175,44,0,183,175,40,0,182,175,
- 36,0,181,175,32,0,180,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,176,128,0,33,144,160,0,33,152,192,0,
- 37,0,96,18,33,184,224,0,28,0,84,38,
- 8,0,67,142,28,0,66,142,0,0,0,0,
- 35,128,98,0,42,16,83,0,23,0,64,16,
- 33,168,19,2,9,50,192,12,128,32,21,0,
- 33,136,64,0,8,0,32,22,128,128,16,0,
- 5,0,2,36,96,0,194,174,17,0,66,146,
- 0,0,0,0,2,0,66,52,48,77,192,8,
- 17,0,66,162,33,32,32,2,12,0,69,142,
- 0,0,0,0,80,68,192,12,33,48,0,2,
- 110,86,192,12,8,0,68,38,12,0,81,174,
- 33,128,48,2,4,0,144,174,4,0,132,142,
- 33,40,224,2,80,68,192,12,128,48,19,0,
- 0,0,147,174,8,0,85,174,48,0,191,143,
- 44,0,183,143,40,0,182,143,36,0,181,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 56,0,189,39,224,255,189,39,24,0,191,175,
- 20,0,177,175,16,0,176,175,33,136,128,0,
- 5,0,192,24,33,128,160,0,3,0,2,36,
- 96,0,34,174,95,77,192,8,100,0,38,174,
- 19,0,195,36,19,0,98,44,9,0,64,16,
- 128,16,3,0,2,131,1,60,33,8,34,0,
- 208,153,34,140,0,0,0,0,8,0,64,0,
- 0,0,0,0,89,77,192,8,2,0,6,36,
- 89,77,192,8,5,0,6,36,89,77,192,8,
- 3,0,6,36,89,77,192,8,1,0,6,36,
- 35,48,6,0,96,0,38,174,33,32,32,2,
- 48,72,192,12,33,40,0,2,1,0,66,36,
- 100,0,34,174,17,0,2,146,0,0,0,0,
- 1,0,66,52,17,0,2,162,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,200,255,189,39,52,0,191,175,
- 48,0,190,175,44,0,183,175,40,0,182,175,
- 36,0,181,175,32,0,180,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,152,128,0,33,168,160,0,33,160,192,0,
- 76,0,182,143,80,0,183,143,84,0,190,143,
- 92,0,177,143,0,0,0,0,209,83,192,12,
- 33,144,224,0,33,128,64,0,3,0,0,22,
- 4,0,2,36,168,77,192,8,33,16,0,0,
- 88,0,2,166,64,0,19,174,33,32,64,2,
- 72,0,165,143,0,0,0,0,80,86,192,12,
- 92,0,6,38,255,255,3,36,23,0,67,16,
- 0,0,0,0,3,0,194,138,0,0,194,154,
- 0,0,0,0,103,0,2,170,100,0,2,186,
- 104,0,23,174,108,0,30,174,88,0,168,143,
- 0,0,0,0,112,0,8,174,72,0,0,166,
- 76,0,20,174,255,255,162,50,33,16,130,2,
- 80,0,2,174,84,0,0,166,9,0,32,18,
- 120,0,17,174,224,83,192,12,33,32,32,2,
- 6,0,64,20,124,0,2,174,167,83,192,12,
- 33,32,0,2,168,77,192,8,33,16,0,0,
- 124,0,0,174,33,16,0,2,52,0,191,143,
- 48,0,190,143,44,0,183,143,40,0,182,143,
- 36,0,181,143,32,0,180,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,56,0,189,39,224,255,189,39,
- 28,0,191,175,24,0,178,175,20,0,177,175,
- 16,0,176,175,33,144,128,0,92,0,68,142,
- 128,86,192,12,0,0,0,0,96,0,68,142,
- 0,0,0,0,128,86,192,12,33,128,64,0,
- 100,0,68,142,0,0,0,0,128,86,192,12,
- 33,136,64,0,33,128,17,2,6,0,16,38,
- 33,16,80,0,90,0,66,166,191,79,192,12,
- 104,0,68,38,255,255,67,48,90,0,68,150,
- 128,0,98,44,5,0,64,20,2,0,130,36,
- 0,1,98,44,2,0,64,20,3,0,130,36,
- 4,0,130,36,33,16,67,0,90,0,66,166,
- 80,0,66,142,76,0,67,142,90,0,80,150,
- 64,0,68,142,0,0,0,0,128,86,192,12,
- 35,136,67,0,255,255,67,48,90,0,68,150,
- 0,0,0,0,128,0,130,44,9,0,64,20,
- 0,1,130,44,4,0,64,16,0,0,0,0,
- 33,24,112,0,237,77,192,8,6,0,99,36,
- 33,24,112,0,237,77,192,8,7,0,99,36,
- 33,24,112,0,5,0,99,36,255,255,36,50,
- 128,0,130,44,5,0,64,20,1,0,130,36,
- 0,1,130,44,2,0,64,20,2,0,130,36,
- 3,0,130,36,33,16,98,0,2,0,66,166,
- 2,0,67,150,2,0,68,150,0,0,0,0,
- 128,0,130,44,6,0,64,20,1,0,99,36,
- 0,1,130,44,4,0,64,20,2,0,98,36,
- 3,78,192,8,3,0,98,36,1,0,98,36,
- 0,0,66,166,0,0,66,150,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,216,255,189,39,
- 32,0,191,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,16,0,176,175,33,152,128,0,
- 171,86,192,12,92,0,100,38,104,0,100,142,
- 0,0,0,0,128,86,192,12,33,144,64,0,
- 108,0,100,142,0,0,0,0,128,86,192,12,
- 33,136,64,0,112,0,100,142,0,0,0,0,
- 153,86,192,12,33,128,64,0,10,0,82,38,
- 33,136,50,2,33,128,17,2,4,0,16,38,
- 33,16,80,0,90,0,98,166,191,79,192,12,
- 116,0,100,38,255,255,67,48,90,0,100,150,
- 128,0,98,44,5,0,64,20,2,0,130,36,
- 0,1,98,44,2,0,64,20,3,0,130,36,
- 4,0,130,36,33,16,67,0,90,0,98,166,
- 80,0,98,142,76,0,99,142,90,0,113,150,
- 64,0,100,142,0,0,0,0,128,86,192,12,
- 35,128,67,0,255,255,67,48,90,0,100,150,
- 0,0,0,0,128,0,130,44,9,0,64,20,
- 0,1,130,44,4,0,64,16,0,0,0,0,
- 33,24,113,0,74,78,192,8,6,0,99,36,
- 33,24,113,0,74,78,192,8,7,0,99,36,
- 33,24,113,0,5,0,99,36,255,255,4,50,
- 128,0,130,44,5,0,64,20,1,0,130,36,
- 0,1,130,44,2,0,64,20,2,0,130,36,
- 3,0,130,36,33,16,98,0,2,0,98,166,
- 2,0,99,150,2,0,100,150,0,0,0,0,
- 128,0,130,44,6,0,64,20,1,0,99,36,
- 0,1,130,44,4,0,64,20,2,0,112,36,
- 96,78,192,8,3,0,112,36,1,0,112,36,
- 255,255,2,50,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,208,255,189,39,
- 40,0,191,175,36,0,179,175,32,0,178,175,
- 28,0,177,175,24,0,176,175,33,128,128,0,
- 33,152,192,0,33,144,224,0,33,136,160,0,
- 16,0,4,36,32,0,5,36,1,131,6,60,
- 56,97,198,36,242,86,192,12,33,56,0,2,
- 255,255,36,50,1,131,5,60,56,97,165,36,
- 44,87,192,12,33,48,0,2,16,0,176,175,
- 2,0,4,36,33,40,0,0,1,131,7,60,
- 56,97,231,36,94,87,192,12,33,48,96,2,
- 8,0,71,142,4,0,66,142,0,0,0,0,
- 35,56,226,0,1,131,2,60,56,97,66,36,
- 16,0,162,175,20,0,176,175,4,0,4,36,
- 33,40,0,0,4,0,70,142,0,0,0,0,
- 194,87,192,12,255,255,231,48,40,0,191,143,
- 36,0,179,143,32,0,178,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,48,0,189,39,
- 216,255,189,39,36,0,191,175,32,0,178,175,
- 28,0,177,175,24,0,176,175,33,128,128,0,
- 33,136,160,0,88,0,4,150,160,0,5,36,
- 1,131,6,60,56,97,198,36,242,86,192,12,
- 33,56,32,2,90,0,4,150,1,131,5,60,
- 56,97,165,36,44,87,192,12,33,48,32,2,
- 16,0,177,175,6,0,4,36,33,40,0,0,
- 1,131,7,60,56,97,231,36,15,88,192,12,
- 92,0,6,38,1,131,18,60,56,97,82,38,
- 16,0,178,175,20,0,177,175,33,32,0,0,
- 64,0,5,36,100,0,6,38,194,87,192,12,
- 4,0,7,36,16,0,177,175,2,0,4,36,
- 33,40,0,0,104,0,6,142,0,0,0,0,
- 94,87,192,12,33,56,64,2,16,0,177,175,
- 2,0,4,36,33,40,0,0,108,0,6,142,
- 0,0,0,0,94,87,192,12,33,56,64,2,
- 16,0,177,175,3,0,4,36,64,0,5,36,
- 112,0,6,142,0,0,0,0,143,87,192,12,
- 33,56,64,2,116,0,4,38,7,79,192,12,
- 33,40,32,2,36,0,191,143,32,0,178,143,
- 28,0,177,143,24,0,176,143,8,0,224,3,
- 40,0,189,39,216,255,189,39,32,0,191,175,
- 28,0,177,175,24,0,176,175,33,128,128,0,
- 33,136,160,0,88,0,4,150,160,0,5,36,
- 1,131,6,60,56,97,198,36,242,86,192,12,
- 33,56,32,2,90,0,4,150,1,131,5,60,
- 56,97,165,36,44,87,192,12,33,48,32,2,
- 16,0,177,175,2,0,4,36,92,0,6,142,
- 1,131,7,60,56,97,231,36,94,87,192,12,
- 33,40,0,0,16,0,177,175,2,0,4,36,
- 96,0,6,142,1,131,7,60,56,97,231,36,
- 94,87,192,12,33,40,0,0,16,0,177,175,
- 2,0,4,36,100,0,6,142,1,131,7,60,
- 56,97,231,36,94,87,192,12,33,40,0,0,
- 104,0,4,38,7,79,192,12,33,40,32,2,
- 32,0,191,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,40,0,189,39,200,255,189,39,
- 52,0,191,175,48,0,180,175,44,0,179,175,
- 40,0,178,175,36,0,177,175,32,0,176,175,
- 33,144,128,0,33,136,160,0,16,0,4,36,
- 32,0,5,36,1,131,6,60,56,97,198,36,
- 242,86,192,12,33,56,32,2,0,0,68,150,
- 1,131,5,60,56,97,165,36,44,87,192,12,
- 33,48,32,2,155,0,64,18,0,0,0,0,
- 1,131,20,60,56,97,148,38,8,0,80,142,
- 0,0,0,0,145,0,0,18,0,0,0,0,
- 4,0,66,142,0,0,0,0,141,0,64,24,
- 33,152,0,0,16,0,4,36,32,0,5,36,
- 33,48,128,2,242,86,192,12,33,56,32,2,
- 4,0,4,150,33,40,128,2,44,87,192,12,
- 33,48,32,2,16,0,177,175,6,0,4,36,
- 33,40,0,0,8,0,6,38,15,88,192,12,
- 33,56,128,2,16,0,3,146,65,0,2,36,
- 47,0,98,16,66,0,98,40,18,0,64,16,
- 5,0,2,36,88,0,98,16,6,0,98,40,
- 7,0,64,16,2,0,2,36,30,0,98,16,
- 4,0,2,36,51,0,98,16,4,0,4,36,
- 174,79,192,8,1,0,115,38,6,0,2,36,
- 68,0,98,16,64,0,2,36,78,0,98,16,
- 33,32,0,0,174,79,192,8,1,0,115,38,
- 68,0,2,36,47,0,98,16,69,0,98,40,
- 7,0,64,16,66,0,2,36,24,0,98,16,
- 67,0,2,36,25,0,98,16,3,0,4,36,
- 174,79,192,8,1,0,115,38,131,0,98,40,
- 83,0,64,16,128,0,98,40,68,0,64,16,
- 0,0,0,0,174,79,192,8,1,0,115,38,
- 16,0,177,175,2,0,4,36,40,0,6,142,
- 1,131,7,60,56,97,231,36,94,87,192,12,
- 33,40,0,0,174,79,192,8,1,0,115,38,
- 16,0,177,175,111,79,192,8,1,0,4,36,
- 16,0,177,175,111,79,192,8,2,0,4,36,
- 16,0,177,175,40,0,6,142,1,131,7,60,
- 56,97,231,36,143,87,192,12,64,0,5,36,
- 174,79,192,8,1,0,115,38,48,0,7,142,
- 44,0,2,142,0,0,0,0,35,56,226,0,
- 16,0,180,175,20,0,177,175,134,79,192,8,
- 33,40,0,0,48,0,7,142,44,0,2,142,
- 0,0,0,0,35,56,226,0,16,0,180,175,
- 20,0,177,175,4,0,4,36,64,0,5,36,
- 44,0,6,142,0,0,0,0,194,87,192,12,
- 255,255,231,48,174,79,192,8,1,0,115,38,
- 16,0,177,175,6,0,4,36,33,40,0,0,
- 1,131,7,60,56,97,231,36,15,88,192,12,
- 40,0,6,38,174,79,192,8,1,0,115,38,
- 5,0,4,36,164,79,192,8,33,40,0,0,
- 16,0,180,175,20,0,177,175,64,0,5,36,
- 40,0,6,38,194,87,192,12,4,0,7,36,
- 174,79,192,8,1,0,115,38,16,0,4,146,
- 16,0,5,146,31,0,132,48,224,0,165,48,
- 1,131,6,60,56,97,198,36,242,86,192,12,
- 33,56,32,2,33,32,0,0,1,131,5,60,
- 56,97,165,36,44,87,192,12,33,48,32,2,
- 1,0,115,38,4,0,66,142,0,0,0,0,
- 42,16,98,2,117,255,64,20,68,0,16,38,
- 12,0,82,142,0,0,0,0,105,255,64,22,
- 0,0,0,0,52,0,191,143,48,0,180,143,
- 44,0,179,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,56,0,189,39,
- 200,255,189,39,52,0,191,175,48,0,182,175,
- 44,0,181,175,40,0,180,175,36,0,179,175,
- 32,0,178,175,28,0,177,175,24,0,176,175,
- 33,168,128,0,33,152,160,2,113,0,160,18,
- 33,144,0,0,4,0,22,36,8,0,112,142,
- 0,0,0,0,104,0,0,18,0,0,0,0,
- 4,0,98,142,0,0,0,0,100,0,64,24,
- 33,160,0,0,171,86,192,12,8,0,4,38,
- 255,255,67,48,128,0,98,44,5,0,64,20,
- 2,0,113,36,0,1,98,44,2,0,64,20,
- 3,0,113,36,4,0,113,36,16,0,3,146,
- 64,0,2,36,50,0,98,16,65,0,98,40,
- 16,0,64,16,68,0,2,36,34,0,118,16,
- 5,0,98,40,5,0,64,16,2,0,2,36,
- 20,0,98,16,255,255,36,50,22,80,192,8,
- 0,0,0,0,5,0,2,36,35,0,98,16,
- 6,0,2,36,29,0,98,16,255,255,36,50,
- 22,80,192,8,0,0,0,0,19,0,98,16,
- 68,0,98,40,12,0,64,20,131,0,98,40,
- 28,0,64,16,128,0,98,40,27,0,64,20,
- 255,255,36,50,22,80,192,8,18,0,0,166,
- 40,0,4,142,128,86,192,12,0,0,0,0,
- 21,80,192,8,18,0,2,166,40,0,4,142,
- 153,86,192,12,0,0,0,0,21,80,192,8,
- 18,0,2,166,48,0,2,142,44,0,3,142,
- 0,0,0,0,35,16,67,0,21,80,192,8,
- 18,0,2,166,171,86,192,12,40,0,4,38,
- 21,80,192,8,18,0,2,166,21,80,192,8,
- 18,0,0,166,18,0,22,166,255,255,36,50,
- 18,0,3,150,0,0,0,0,128,0,98,44,
- 6,0,64,20,1,0,132,36,0,1,98,44,
- 4,0,64,20,2,0,98,36,33,80,192,8,
- 3,0,98,36,1,0,98,36,33,16,130,0,
- 4,0,2,166,4,0,4,150,0,0,0,0,
- 1,0,132,36,4,0,3,150,0,0,0,0,
- 128,0,98,44,6,0,64,20,255,255,69,50,
- 0,1,98,44,4,0,64,20,2,0,162,36,
- 49,80,192,8,3,0,162,36,1,0,162,36,
- 33,144,68,0,1,0,148,38,4,0,98,142,
- 0,0,0,0,42,16,130,2,158,255,64,20,
- 68,0,16,38,12,0,115,142,0,0,0,0,
- 146,255,96,22,0,0,0,0,0,0,178,166,
- 255,255,66,50,52,0,191,143,48,0,182,143,
- 44,0,181,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,56,0,189,39,224,255,189,39,
- 24,0,191,175,20,0,177,175,16,0,176,175,
- 33,128,128,0,171,86,192,12,8,0,4,38,
- 255,255,67,48,128,0,98,44,5,0,64,20,
- 2,0,113,36,0,1,98,44,2,0,64,20,
- 3,0,113,36,4,0,113,36,16,0,3,146,
- 64,0,2,36,52,0,98,16,65,0,98,40,
- 17,0,64,16,4,0,2,36,37,0,98,16,
- 0,0,0,0,5,0,98,40,5,0,64,16,
- 2,0,2,36,22,0,98,16,255,255,36,50,
- 145,80,192,8,0,0,0,0,5,0,2,36,
- 36,0,98,16,6,0,2,36,30,0,98,16,
- 255,255,36,50,145,80,192,8,0,0,0,0,
- 68,0,2,36,20,0,98,16,0,0,0,0,
- 68,0,98,40,12,0,64,20,131,0,98,40,
- 28,0,64,16,128,0,98,40,27,0,64,20,
- 255,255,36,50,145,80,192,8,18,0,0,166,
- 40,0,4,142,128,86,192,12,0,0,0,0,
- 144,80,192,8,18,0,2,166,40,0,4,142,
- 153,86,192,12,0,0,0,0,144,80,192,8,
- 18,0,2,166,48,0,2,142,44,0,3,142,
- 0,0,0,0,143,80,192,8,35,16,67,0,
- 171,86,192,12,40,0,4,38,144,80,192,8,
- 18,0,2,166,144,80,192,8,18,0,0,166,
- 4,0,2,36,18,0,2,166,255,255,36,50,
- 18,0,3,150,0,0,0,0,128,0,98,44,
- 6,0,64,20,1,0,132,36,0,1,98,44,
- 4,0,64,20,2,0,98,36,156,80,192,8,
- 3,0,98,36,1,0,98,36,33,16,130,0,
- 4,0,2,166,4,0,3,150,4,0,4,150,
- 0,0,0,0,128,0,130,44,6,0,64,20,
- 1,0,99,36,0,1,130,44,4,0,64,20,
- 2,0,98,36,170,80,192,8,3,0,98,36,
- 1,0,98,36,255,255,66,48,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,16,0,191,175,
- 64,0,130,140,0,0,0,0,12,0,64,20,
- 33,16,0,0,88,0,131,148,4,0,2,36,
- 5,0,98,16,0,0,0,0,180,77,192,12,
- 0,0,0,0,193,80,192,8,255,255,66,48,
- 11,78,192,12,0,0,0,0,255,255,66,48,
- 16,0,191,143,24,0,189,39,8,0,224,3,
- 0,0,0,0,224,255,189,39,24,0,191,175,
- 20,0,177,175,16,0,176,175,33,128,128,0,
- 176,80,192,12,33,136,160,0,33,32,0,2,
- 33,40,32,2,213,80,192,12,255,255,70,48,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,224,255,189,39,
- 28,0,191,175,24,0,178,175,20,0,177,175,
- 16,0,176,175,33,144,128,0,33,136,192,0,
- 255,255,34,50,41,0,64,16,33,128,160,0,
- 4,0,2,142,0,0,0,0,11,0,64,20,
- 255,255,35,50,9,50,192,12,255,255,36,50,
- 33,24,64,0,32,0,96,16,1,0,2,36,
- 0,0,2,166,4,0,3,174,8,0,3,174,
- 242,80,192,8,12,0,17,166,12,0,2,150,
- 0,0,0,0,43,16,67,0,23,0,64,20,
- 255,255,2,36,64,0,66,142,0,0,0,0,
- 19,0,64,20,255,255,2,36,33,32,0,2,
- 2,0,69,150,33,48,0,0,104,78,192,12,
- 72,0,71,38,88,0,67,150,4,0,2,36,
- 5,0,98,16,33,32,64,2,217,78,192,12,
- 33,40,0,2,8,81,192,8,33,16,0,0,
- 153,78,192,12,33,40,0,2,8,81,192,8,
- 33,16,0,0,255,255,2,36,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,0,0,0,0,
- 0,0,0,0,168,255,189,39,80,0,191,175,
- 76,0,183,175,72,0,182,175,68,0,181,175,
- 64,0,180,175,60,0,179,175,56,0,178,175,
- 52,0,177,175,48,0,176,175,33,24,128,0,
- 33,152,160,0,33,176,192,0,33,184,224,0,
- 104,0,162,143,0,0,0,0,2,0,64,20,
- 44,0,160,175,40,0,162,39,0,0,64,172,
- 24,0,164,39,33,40,96,0,156,88,192,12,
- 33,48,96,2,33,136,64,0,82,0,32,18,
- 33,16,0,0,209,83,192,12,0,0,0,0,
- 33,144,64,0,5,0,64,22,1,0,2,36,
- 183,88,192,12,33,32,32,2,124,81,192,8,
- 33,16,0,0,148,0,66,162,196,88,192,12,
- 33,32,32,2,224,0,85,48,44,0,176,39,
- 33,32,32,2,124,89,192,12,33,40,0,2,
- 33,160,64,0,33,32,32,2,198,89,192,12,
- 33,40,0,2,2,0,66,166,44,0,162,143,
- 0,0,0,0,14,0,64,20,0,0,0,0,
- 8,0,35,142,4,0,34,142,0,0,0,0,
- 35,128,98,0,2,0,66,150,0,0,0,0,
- 33,128,2,2,42,16,19,2,16,0,64,20,
- 33,32,32,2,42,16,112,2,16,0,64,16,
- 0,0,0,0,167,83,192,12,33,32,64,2,
- 183,88,192,12,33,32,32,2,3,131,3,60,
- 140,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,124,81,192,8,
- 33,16,0,0,33,40,0,2,42,89,192,12,
- 33,48,0,0,255,0,162,50,255,255,131,50,
- 37,16,67,0,48,0,3,36,8,0,67,20,
- 33,32,64,2,16,0,176,175,33,40,32,2,
- 33,48,192,2,135,81,192,12,33,56,224,2,
- 117,81,192,8,33,128,64,0,3,131,3,60,
- 140,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,33,128,0,0,
- 3,0,0,22,0,0,0,0,167,83,192,12,
- 33,32,64,2,183,88,192,12,33,32,32,2,
- 33,16,0,2,80,0,191,143,76,0,183,143,
- 72,0,182,143,68,0,181,143,64,0,180,143,
- 60,0,179,143,56,0,178,143,52,0,177,143,
- 48,0,176,143,8,0,224,3,88,0,189,39,
- 176,255,189,39,76,0,191,175,72,0,182,175,
- 68,0,181,175,64,0,180,175,60,0,179,175,
- 56,0,178,175,52,0,177,175,48,0,176,175,
- 33,128,128,0,33,136,160,0,33,160,192,0,
- 33,168,224,0,96,0,182,143,24,0,160,175,
- 33,32,32,2,24,0,165,39,2,0,6,36,
- 239,90,192,12,33,56,0,0,64,0,2,174,
- 24,0,162,143,0,0,0,0,155,0,64,20,
- 0,0,0,0,64,0,2,142,0,0,0,0,
- 4,0,64,16,33,32,32,2,3,131,3,60,
- 60,82,192,8,148,17,99,36,16,0,160,175,
- 72,0,5,38,24,0,166,39,110,90,192,12,
- 4,0,7,36,24,0,162,143,0,0,0,0,
- 139,0,64,20,0,0,0,0,196,88,192,12,
- 33,32,32,2,224,0,66,48,160,0,3,36,
- 133,0,67,20,33,32,32,2,124,89,192,12,
- 24,0,165,39,33,144,64,0,33,32,32,2,
- 198,89,192,12,24,0,165,39,33,152,64,0,
- 24,0,162,143,0,0,0,0,122,0,64,20,
- 0,0,0,0,255,255,66,50,5,0,66,44,
- 118,0,64,16,0,0,0,0,8,0,34,142,
- 4,0,35,142,0,0,0,0,35,16,67,0,
- 255,255,99,50,33,16,67,0,110,0,194,22,
- 33,32,0,2,88,0,18,166,90,0,19,166,
- 33,40,128,2,178,50,192,12,33,48,160,2,
- 118,0,64,20,33,16,0,0,255,255,67,50,
- 4,0,2,36,24,0,98,16,33,32,32,2,
- 24,0,165,39,2,0,6,36,239,90,192,12,
- 33,56,0,0,92,0,2,174,33,32,32,2,
- 24,0,165,39,2,0,6,36,239,90,192,12,
- 33,56,0,0,96,0,2,174,33,32,32,2,
- 24,0,165,39,2,0,6,36,239,90,192,12,
- 33,56,0,0,100,0,2,174,24,0,162,143,
- 0,0,0,0,78,0,64,20,33,32,32,2,
- 67,82,192,8,104,0,5,38,4,0,2,36,
- 88,0,2,166,90,0,19,166,124,0,0,174,
- 16,0,160,175,92,0,5,38,24,0,166,39,
- 186,91,192,12,6,0,7,36,24,0,162,143,
- 0,0,0,0,63,0,64,20,100,0,4,38,
- 33,40,0,0,144,71,192,12,4,0,6,36,
- 32,0,160,167,40,0,160,175,36,0,160,175,
- 44,0,160,167,32,0,178,39,64,0,2,36,
- 16,0,162,175,33,32,32,2,33,40,64,2,
- 24,0,166,39,110,90,192,12,33,56,0,0,
- 24,0,162,143,0,0,0,0,5,0,64,16,
- 0,0,0,0,24,92,192,12,33,32,64,2,
- 58,82,192,8,0,0,0,0,40,0,162,143,
- 36,0,163,143,0,0,0,0,35,16,67,0,
- 255,255,70,48,5,0,194,44,2,0,64,20,
- 0,0,0,0,4,0,6,36,8,0,192,16,
- 33,32,32,2,36,0,165,143,0,0,0,0,
- 80,68,192,12,100,0,4,38,24,92,192,12,
- 32,0,164,39,33,32,32,2,24,0,165,39,
- 2,0,6,36,239,90,192,12,33,56,0,0,
- 104,0,2,174,33,32,32,2,24,0,165,39,
- 2,0,6,36,239,90,192,12,33,56,0,0,
- 108,0,2,174,33,32,32,2,24,0,165,39,
- 3,0,6,36,239,90,192,12,64,0,7,36,
- 112,0,2,174,24,0,162,143,0,0,0,0,
- 9,0,64,16,33,32,32,2,3,131,3,60,
- 140,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,73,82,192,8,
- 33,16,0,0,116,0,5,38,33,48,192,2,
- 163,82,192,12,33,56,0,2,255,255,3,36,
- 248,255,67,16,33,16,0,2,76,0,191,143,
- 72,0,182,143,68,0,181,143,64,0,180,143,
- 60,0,179,143,56,0,178,143,52,0,177,143,
- 48,0,176,143,8,0,224,3,80,0,189,39,
- 184,255,189,39,64,0,191,175,60,0,183,175,
- 56,0,182,175,52,0,181,175,48,0,180,175,
- 44,0,179,175,40,0,178,175,36,0,177,175,
- 32,0,176,175,33,128,128,0,16,0,160,175,
- 8,0,2,142,4,0,3,142,0,0,0,0,
- 35,184,67,0,33,144,0,0,255,255,162,48,
- 45,0,64,16,33,136,0,0,3,131,19,60,
- 140,17,115,38,255,255,22,36,255,255,181,48,
- 8,0,3,142,4,0,2,142,0,0,0,0,
- 35,160,98,0,0,0,2,146,0,0,0,0,
- 128,0,66,48,32,0,64,20,33,32,0,2,
- 124,89,192,12,16,0,165,39,33,32,0,2,
- 198,89,192,12,16,0,165,39,33,40,64,0,
- 16,0,162,143,0,0,0,0,6,0,64,20,
- 33,32,0,2,255,255,165,48,251,88,192,12,
- 1,0,6,36,7,0,86,20,0,0,0,0,
- 0,0,98,142,0,0,0,0,1,0,66,36,
- 0,0,98,174,147,82,192,8,255,255,17,36,
- 8,0,2,142,4,0,3,142,0,0,0,0,
- 35,16,67,0,33,16,66,2,35,144,84,0,
- 255,255,66,50,43,16,85,0,217,255,64,20,
- 1,0,49,38,33,32,0,2,33,40,224,2,
- 251,88,192,12,33,48,0,0,33,16,32,2,
- 64,0,191,143,60,0,183,143,56,0,182,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,72,0,189,39,192,255,189,39,
- 56,0,191,175,52,0,181,175,48,0,180,175,
- 44,0,179,175,40,0,178,175,36,0,177,175,
- 32,0,176,175,33,144,128,0,33,152,160,0,
- 33,168,224,0,16,0,160,175,124,89,192,12,
- 16,0,165,39,33,32,64,2,198,89,192,12,
- 16,0,165,39,0,0,98,166,16,0,162,143,
- 0,0,0,0,28,0,64,20,0,0,0,0,
- 12,0,66,142,8,0,67,142,0,0,0,0,
- 35,16,67,0,0,0,99,150,255,255,66,48,
- 20,0,98,20,0,0,0,0,4,0,96,174,
- 0,0,101,150,0,0,0,0,83,82,192,12,
- 33,32,64,2,33,32,64,0,255,255,2,36,
- 46,0,130,16,0,0,0,0,3,0,128,20,
- 0,0,0,0,246,82,192,8,8,0,96,174,
- 224,83,192,12,4,0,100,174,10,0,64,20,
- 8,0,98,174,247,82,192,8,255,255,2,36,
- 3,131,3,60,140,17,99,36,0,0,98,140,
- 0,0,0,0,1,0,66,36,210,82,192,8,
- 0,0,98,172,8,0,112,142,4,0,98,142,
- 0,0,0,0,23,0,64,24,33,136,0,0,
- 255,255,20,36,33,32,64,2,124,89,192,12,
- 16,0,165,39,33,32,64,2,198,89,192,12,
- 16,0,165,39,4,0,2,166,16,0,162,143,
- 0,0,0,0,233,255,64,20,33,32,64,2,
- 33,40,0,2,0,83,192,12,33,48,160,2,
- 226,255,84,16,1,0,49,38,4,0,98,142,
- 0,0,0,0,42,16,34,2,236,255,64,20,
- 68,0,16,38,33,16,0,0,56,0,191,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,64,0,189,39,184,255,189,39,
- 68,0,191,175,64,0,180,175,60,0,179,175,
- 56,0,178,175,52,0,177,175,48,0,176,175,
- 33,128,128,0,33,144,160,0,24,0,160,175,
- 16,0,160,175,8,0,69,38,24,0,166,39,
- 186,91,192,12,6,0,7,36,24,0,162,143,
- 0,0,0,0,103,0,64,20,0,0,0,0,
- 196,88,192,12,33,32,0,2,224,0,84,48,
- 33,32,0,2,124,89,192,12,24,0,165,39,
- 33,152,64,0,33,32,0,2,198,89,192,12,
- 24,0,165,39,33,136,64,0,24,0,162,143,
- 0,0,0,0,88,0,64,20,37,16,116,2,
- 18,0,81,166,16,0,66,162,16,0,67,146,
- 64,0,2,36,48,0,98,16,65,0,98,40,
- 16,0,64,16,4,0,2,36,31,0,98,16,
- 5,0,98,40,5,0,64,16,2,0,2,36,
- 22,0,98,16,33,32,0,2,121,83,192,8,
- 0,0,0,0,5,0,2,36,65,0,98,16,
- 6,0,2,36,27,0,98,16,33,32,0,2,
- 121,83,192,8,0,0,0,0,68,0,2,36,
- 15,0,98,16,68,0,98,40,8,0,64,20,
- 33,32,0,2,131,0,98,40,57,0,64,16,
- 128,0,98,40,51,0,64,16,0,0,0,0,
- 121,83,192,8,0,0,0,0,255,255,37,50,
- 164,90,192,12,24,0,166,39,117,83,192,8,
- 40,0,66,174,33,32,0,2,255,255,37,50,
- 40,0,70,38,19,90,192,12,24,0,167,39,
- 117,83,192,8,0,0,0,0,255,255,37,50,
- 40,0,70,38,24,91,192,12,24,0,167,39,
- 117,83,192,8,0,0,0,0,40,0,68,38,
- 33,40,0,0,144,71,192,12,4,0,6,36,
- 32,0,160,167,40,0,160,175,36,0,160,175,
- 44,0,160,167,33,32,0,2,255,255,37,50,
- 32,0,166,39,19,90,192,12,24,0,167,39,
- 40,0,162,143,36,0,163,143,0,0,0,0,
- 35,16,67,0,255,255,70,48,5,0,194,44,
- 2,0,64,20,0,0,0,0,4,0,6,36,
- 7,0,192,16,0,0,0,0,36,0,165,143,
- 0,0,0,0,80,68,192,12,40,0,68,38,
- 24,92,192,12,32,0,164,39,24,0,162,143,
- 0,0,0,0,8,0,64,16,33,16,0,0,
- 3,131,3,60,140,17,99,36,0,0,98,140,
- 0,0,0,0,1,0,66,36,0,0,98,172,
- 255,255,2,36,68,0,191,143,64,0,180,143,
- 60,0,179,143,56,0,178,143,52,0,177,143,
- 48,0,176,143,8,0,224,3,72,0,189,39,
- 232,255,189,39,20,0,191,175,16,0,176,175,
- 33,128,128,0,76,0,2,142,0,0,0,0,
- 3,0,64,16,0,0,0,0,24,92,192,12,
- 72,0,4,38,88,0,3,150,4,0,2,36,
- 5,0,98,20,0,0,0,0,110,86,192,12,
- 92,0,4,38,157,83,192,8,116,0,4,38,
- 13,84,192,12,104,0,4,38,120,0,4,38,
- 13,84,192,12,0,0,0,0,148,0,3,146,
- 0,0,0,0,248,83,192,12,33,32,0,2,
- 20,0,191,143,16,0,176,143,8,0,224,3,
- 24,0,189,39,232,255,189,39,20,0,191,175,
- 16,0,176,175,33,128,128,0,5,0,0,18,
- 0,0,0,0,136,83,192,12,0,0,0,0,
- 61,50,192,12,33,32,0,2,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 224,255,189,39,24,0,191,175,20,0,177,175,
- 16,0,176,175,33,136,128,0,9,50,192,12,
- 16,0,4,36,33,128,64,0,11,0,0,18,
- 33,32,0,2,33,40,0,0,144,71,192,12,
- 16,0,6,36,224,83,192,12,33,32,32,2,
- 4,0,64,16,8,0,2,174,4,0,17,174,
- 204,83,192,8,33,16,0,2,61,50,192,12,
- 33,32,0,2,33,16,0,0,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,20,0,191,175,
- 16,0,176,175,9,50,192,12,152,0,4,36,
- 33,128,64,0,4,0,0,18,33,16,0,0,
- 248,83,192,12,33,32,0,2,33,16,0,2,
- 20,0,191,143,16,0,176,143,8,0,224,3,
- 24,0,189,39,224,255,189,39,24,0,191,175,
- 20,0,177,175,0,17,4,0,33,16,68,0,
- 128,136,2,0,11,0,32,18,16,0,176,175,
- 9,50,192,12,33,32,32,2,33,128,64,0,
- 4,0,0,18,33,32,0,2,33,40,0,0,
- 144,71,192,12,33,48,32,2,243,83,192,8,
- 33,16,0,2,33,16,0,0,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,20,0,191,175,
- 16,0,176,175,33,128,128,0,33,40,0,0,
- 144,71,192,12,152,0,6,36,255,0,2,36,
- 88,0,2,166,120,5,2,36,58,0,2,166,
- 72,0,0,166,80,0,0,174,76,0,0,174,
- 84,0,0,166,148,0,0,162,149,0,0,162,
- 20,0,191,143,16,0,176,143,8,0,224,3,
- 24,0,189,39,208,255,189,39,40,0,191,175,
- 36,0,179,175,32,0,178,175,28,0,177,175,
- 24,0,176,175,33,128,128,0,31,0,0,18,
- 1,0,19,36,8,0,18,142,0,0,0,0,
- 16,0,64,18,0,0,0,0,4,0,2,142,
- 0,0,0,0,9,0,64,24,33,136,0,0,
- 59,84,192,12,33,32,64,2,1,0,49,38,
- 4,0,2,142,0,0,0,0,42,16,34,2,
- 249,255,64,20,68,0,82,38,8,0,4,142,
- 61,50,192,12,0,0,0,0,12,0,17,142,
- 4,0,96,18,0,0,0,0,33,152,0,0,
- 49,84,192,8,4,0,0,174,61,50,192,12,
- 33,32,0,2,33,128,32,2,227,255,0,22,
- 0,0,0,0,40,0,191,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,48,0,189,39,232,255,189,39,
- 20,0,191,175,16,0,176,175,33,128,128,0,
- 60,0,2,142,0,0,0,0,4,0,64,16,
- 0,0,0,0,9,248,64,0,0,0,0,0,
- 60,0,0,174,110,86,192,12,8,0,4,38,
- 78,84,192,12,33,32,0,2,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 232,255,189,39,16,0,191,175,16,0,131,144,
- 6,0,2,36,18,0,98,16,7,0,98,40,
- 5,0,64,16,4,0,2,36,6,0,98,16,
- 0,0,0,0,103,84,192,8,0,0,0,0,
- 68,0,2,36,11,0,98,20,0,0,0,0,
- 44,0,130,140,0,0,0,0,7,0,64,16,
- 0,0,0,0,24,92,192,12,40,0,132,36,
- 103,84,192,8,0,0,0,0,110,86,192,12,
- 40,0,132,36,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,0,0,0,0,
- 216,255,189,39,32,0,191,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,136,192,0,56,0,179,143,0,0,0,0,
- 20,72,192,12,33,144,224,0,33,128,64,0,
- 11,0,0,18,33,32,32,2,33,40,64,2,
- 80,86,192,12,8,0,6,38,255,255,3,36,
- 5,0,67,16,2,0,2,36,16,0,2,162,
- 40,0,19,174,133,84,192,8,33,16,0,0,
- 255,255,2,36,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,216,255,189,39,
- 32,0,191,175,28,0,177,175,24,0,176,175,
- 33,128,128,0,96,0,5,174,100,0,6,174,
- 128,0,2,142,0,0,0,0,11,0,64,16,
- 0,0,0,0,13,84,192,12,104,0,4,38,
- 124,0,2,142,0,0,0,0,108,0,2,174,
- 128,0,2,142,0,0,0,0,112,0,2,174,
- 128,0,0,174,124,0,0,174,88,0,17,150,
- 2,0,2,36,88,0,2,166,176,80,192,12,
- 33,32,0,2,33,56,64,0,64,0,2,142,
- 0,0,0,0,35,0,64,20,255,255,35,50,
- 3,0,2,36,14,0,98,16,255,255,227,48,
- 58,0,2,150,0,0,0,0,43,16,67,0,
- 9,0,64,16,12,0,4,38,48,0,2,142,
- 28,0,5,38,52,0,7,142,0,0,0,0,
- 9,248,64,0,1,0,6,36,214,84,192,8,
- 0,0,0,0,96,0,2,142,0,0,0,0,
- 250,255,67,36,13,0,98,44,13,0,64,16,
- 128,16,3,0,2,131,1,60,33,8,34,0,
- 32,154,34,140,0,0,0,0,8,0,64,0,
- 0,0,0,0,204,84,192,8,2,0,2,36,
- 204,84,192,8,3,0,2,36,5,0,2,36,
- 96,0,2,174,52,0,2,142,0,0,0,0,
- 16,0,162,175,44,0,2,142,12,0,4,38,
- 28,0,5,38,33,48,0,2,9,248,64,0,
- 255,255,231,48,32,0,191,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,40,0,189,39,
- 224,255,189,39,28,0,191,175,24,0,176,175,
- 33,128,128,0,96,0,5,142,0,0,0,0,
- 6,0,160,16,0,0,0,0,100,0,6,142,
- 140,84,192,12,0,0,0,0,56,85,192,8,
- 0,0,0,0,176,80,192,12,33,32,0,2,
- 33,56,64,0,88,0,2,150,0,0,0,0,
- 2,0,66,44,11,0,64,16,255,255,227,48,
- 58,0,2,150,0,0,0,0,43,16,67,0,
- 6,0,64,16,33,32,0,2,1,0,5,36,
- 140,84,192,12,33,48,0,0,56,85,192,8,
- 0,0,0,0,96,0,2,142,0,0,0,0,
- 49,0,64,20,2,0,2,36,88,0,3,150,
- 3,0,2,36,33,0,98,16,4,0,98,40,
- 7,0,64,16,2,0,98,40,41,0,64,16,
- 2,0,2,36,39,0,96,4,0,0,0,0,
- 13,85,192,8,0,0,0,0,5,0,2,36,
- 34,0,98,20,2,0,2,36,3,131,3,60,
- 236,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,104,0,4,38,25,0,128,16,
- 0,0,98,172,3,131,5,60,176,17,165,36,
- 0,0,162,140,108,0,3,142,0,0,0,0,
- 33,16,67,0,0,0,162,172,12,0,132,140,
- 0,0,0,0,248,255,128,20,2,0,2,36,
- 47,85,192,8,88,0,2,166,3,131,4,60,
- 236,17,132,36,0,0,130,140,0,0,0,0,
- 1,0,66,36,0,0,130,172,200,255,130,140,
- 108,0,3,142,0,0,0,0,33,16,67,0,
- 200,255,130,172,2,0,2,36,88,0,2,166,
- 52,0,2,142,0,0,0,0,16,0,162,175,
- 44,0,2,142,12,0,4,38,28,0,5,38,
- 33,48,0,2,9,248,64,0,255,255,231,48,
- 28,0,191,143,24,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,20,0,191,175,
- 16,0,176,175,33,128,128,0,88,0,3,150,
- 1,0,2,36,25,0,98,16,2,0,98,40,
- 5,0,64,16,3,0,2,36,7,0,96,16,
- 0,0,0,0,116,85,192,8,0,0,0,0,
- 37,0,98,16,0,0,0,0,116,85,192,8,
- 0,0,0,0,112,0,4,142,108,0,3,142,
- 0,0,0,0,34,0,96,16,0,0,0,0,
- 17,0,130,144,0,0,0,0,2,0,66,48,
- 33,0,64,16,255,255,99,36,250,255,96,20,
- 68,0,132,36,116,85,192,8,0,0,0,0,
- 112,0,4,142,108,0,3,142,0,0,0,0,
- 8,0,96,16,0,0,0,0,17,0,130,144,
- 0,0,0,0,2,0,66,48,19,0,64,16,
- 255,255,99,36,250,255,96,20,68,0,132,36,
- 118,93,192,12,33,32,0,2,241,255,64,28,
- 255,255,66,40,7,0,64,16,0,0,0,0,
- 92,85,192,8,0,0,0,0,120,94,192,12,
- 33,32,0,2,5,0,64,20,0,0,0,0,
- 219,84,192,12,33,32,0,2,167,83,192,12,
- 33,32,0,2,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,232,255,189,39,
- 20,0,191,175,16,0,176,175,33,128,128,0,
- 88,0,3,150,1,0,2,36,17,0,98,16,
- 2,0,98,40,5,0,64,16,3,0,2,36,
- 9,0,96,16,0,0,0,0,156,85,192,8,
- 0,0,0,0,13,0,98,16,5,0,2,36,
- 7,0,98,16,0,0,0,0,156,85,192,8,
- 0,0,0,0,60,95,192,12,33,32,0,2,
- 154,85,192,8,0,0,0,0,0,93,192,12,
- 33,32,0,2,154,85,192,8,0,0,0,0,
- 252,93,192,12,33,32,0,2,5,0,64,20,
- 0,0,0,0,60,85,192,12,33,32,0,2,
- 162,85,192,8,0,0,0,0,167,83,192,12,
- 33,32,0,2,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,192,255,189,39,
- 60,0,191,175,56,0,182,175,52,0,181,175,
- 48,0,180,175,44,0,179,175,40,0,178,175,
- 36,0,177,175,32,0,176,175,33,64,128,0,
- 33,136,192,0,33,152,224,0,84,0,182,143,
- 88,0,181,143,92,0,180,143,80,0,178,151,
- 3,131,3,60,128,17,99,36,0,0,98,140,
- 0,0,0,0,1,0,66,36,0,0,98,172,
- 24,0,162,39,16,0,162,175,33,32,160,0,
- 16,81,192,12,33,40,0,1,33,128,64,0,
- 57,0,0,18,255,255,66,50,58,0,3,150,
- 0,0,0,0,43,16,67,0,2,0,64,16,
- 0,0,0,0,58,0,18,166,44,0,22,174,
- 48,0,21,174,52,0,20,174,24,0,162,143,
- 0,0,0,0,7,0,64,16,1,0,2,36,
- 219,84,192,12,33,32,0,2,167,83,192,12,
- 33,32,0,2,5,86,192,8,0,0,0,0,
- 88,0,3,150,0,0,0,0,16,0,98,16,
- 2,0,98,40,5,0,64,16,3,0,2,36,
- 9,0,96,16,0,0,0,0,244,85,192,8,
- 0,0,0,0,11,0,98,16,5,0,2,36,
- 31,0,98,16,0,0,0,0,244,85,192,8,
- 0,0,0,0,3,131,3,60,239,85,192,8,
- 184,17,99,36,3,131,3,60,239,85,192,8,
- 188,17,99,36,3,131,3,60,192,17,99,36,
- 0,0,98,140,0,0,0,0,1,0,66,36,
- 3,86,192,8,0,0,98,172,3,131,3,60,
- 140,17,99,36,0,0,98,140,0,0,0,0,
- 1,0,66,36,0,0,98,172,167,83,192,12,
- 33,32,0,2,33,32,32,2,33,40,96,2,
- 1,0,6,36,9,248,160,2,33,56,128,2,
- 5,86,192,8,0,0,0,0,124,85,192,12,
- 33,32,0,2,60,0,191,143,56,0,182,143,
- 52,0,181,143,48,0,180,143,44,0,179,143,
- 40,0,178,143,36,0,177,143,32,0,176,143,
- 8,0,224,3,64,0,189,39,232,255,189,39,
- 20,0,191,175,16,0,176,175,33,128,128,0,
- 213,80,192,12,255,255,198,48,53,0,64,20,
- 255,255,2,36,3,131,3,60,144,17,99,36,
- 0,0,98,140,0,0,0,0,1,0,66,36,
- 0,0,98,172,96,0,2,142,0,0,0,0,
- 32,0,64,16,4,0,2,36,92,0,98,140,
- 0,0,0,0,1,0,66,36,92,0,98,172,
- 96,0,2,142,0,0,0,0,255,255,67,36,
- 5,0,98,44,32,0,64,16,128,16,3,0,
- 2,131,1,60,33,8,34,0,88,154,34,140,
- 0,0,0,0,8,0,64,0,0,0,0,0,
- 3,131,3,60,70,86,192,8,204,17,99,36,
- 3,131,3,60,70,86,192,8,212,17,99,36,
- 3,131,3,60,70,86,192,8,216,17,99,36,
- 3,131,3,60,70,86,192,8,208,17,99,36,
- 3,131,3,60,70,86,192,8,220,17,99,36,
- 88,0,3,150,0,0,0,0,8,0,98,20,
- 33,16,0,0,3,131,3,60,240,17,99,36,
- 0,0,98,140,0,0,0,0,1,0,66,36,
- 0,0,98,172,33,16,0,0,20,0,191,143,
- 16,0,176,143,8,0,224,3,24,0,189,39,
- 0,0,0,0,224,255,189,39,28,0,191,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,144,160,0,33,128,192,0,4,0,0,174,
- 14,0,128,16,0,0,4,174,128,136,4,0,
- 9,50,192,12,33,32,32,2,3,0,64,20,
- 4,0,2,174,104,86,192,8,255,255,2,36,
- 5,0,32,18,33,40,64,2,4,0,4,142,
- 0,0,0,0,80,68,192,12,33,48,32,2,
- 33,16,0,0,28,0,191,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,20,0,191,175,
- 16,0,176,175,33,128,128,0,4,0,4,142,
- 0,0,0,0,4,0,128,16,0,0,0,0,
- 61,50,192,12,0,0,0,0,4,0,0,174,
- 0,0,0,174,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,0,0,0,0,
- 0,0,0,0,11,0,128,4,128,0,130,40,
- 20,0,64,20,1,0,3,36,255,127,2,36,
- 42,16,68,0,16,0,64,16,2,0,3,36,
- 127,0,2,60,255,255,66,52,148,86,192,8,
- 42,16,68,0,128,255,130,40,9,0,64,16,
- 1,0,3,36,0,128,130,40,6,0,64,16,
- 2,0,3,36,128,255,2,60,42,16,130,0,
- 2,0,64,20,4,0,3,36,3,0,3,36,
- 8,0,224,3,33,16,96,0,128,0,130,44,
- 14,0,64,20,1,0,2,36,255,127,2,36,
- 43,16,68,0,9,0,64,16,127,0,2,60,
- 255,255,66,52,43,16,68,0,6,0,64,16,
- 3,0,2,36,4,0,128,4,5,0,2,36,
- 169,86,192,8,4,0,2,36,2,0,2,36,
- 8,0,224,3,0,0,0,0,4,0,135,140,
- 0,0,130,140,0,0,0,0,65,0,64,16,
- 33,16,0,0,0,0,227,140,4,0,231,36,
- 128,16,3,0,33,16,67,0,192,16,2,0,
- 0,0,227,140,0,0,0,0,33,24,67,0,
- 128,0,98,44,17,0,64,20,4,0,231,36,
- 0,64,98,44,15,0,64,20,2,0,5,36,
- 31,0,2,60,255,255,66,52,43,16,67,0,
- 7,0,64,16,255,15,2,60,255,255,66,52,
- 43,16,67,0,6,0,64,20,5,0,5,36,
- 204,86,192,8,4,0,5,36,204,86,192,8,
- 3,0,5,36,1,0,5,36,2,0,6,36,
- 0,0,130,140,0,0,0,0,42,16,194,0,
- 31,0,64,16,255,255,162,48,31,0,9,60,
- 255,255,41,53,255,15,8,60,255,255,8,53,
- 0,0,132,140,0,0,227,140,4,0,231,36,
- 128,0,98,44,16,0,64,20,255,255,165,48,
- 0,64,98,44,11,0,64,20,43,16,35,1,
- 7,0,64,16,43,16,3,1,3,0,64,20,
- 0,0,0,0,236,86,192,8,4,0,165,36,
- 236,86,192,8,5,0,165,36,236,86,192,8,
- 3,0,165,36,236,86,192,8,2,0,165,36,
- 1,0,165,36,1,0,198,36,42,16,196,0,
- 232,255,64,20,255,255,162,48,8,0,224,3,
- 0,0,0,0,208,255,189,39,40,0,191,175,
- 33,72,192,0,224,0,165,48,255,255,130,48,
- 31,0,66,44,7,0,64,16,33,48,160,0,
- 37,16,133,0,16,0,162,163,33,32,224,0,
- 16,0,165,39,38,87,192,8,1,0,6,36,
- 32,0,163,39,33,40,0,0,31,0,194,52,
- 24,0,162,163,255,255,130,48,8,0,64,16,
- 25,0,168,39,127,0,130,48,0,0,98,160,
- 1,0,99,36,255,255,130,48,194,33,2,0,
- 250,255,128,20,1,0,165,36,1,0,166,36,
- 33,16,160,0,255,255,66,48,2,0,66,44,
- 13,0,64,20,255,255,165,36,255,255,4,52,
- 255,255,99,36,0,0,98,144,0,0,0,0,
- 128,0,66,52,0,0,2,161,1,0,8,37,
- 33,16,160,0,255,255,66,48,2,0,66,44,
- 246,255,64,16,33,40,164,0,255,255,98,144,
- 0,0,0,0,0,0,2,161,33,32,224,0,
- 24,0,165,39,255,255,198,48,9,248,32,1,
- 0,0,0,0,40,0,191,143,48,0,189,39,
- 8,0,224,3,0,0,0,0,208,255,189,39,
- 40,0,191,175,33,72,160,0,255,255,130,48,
- 128,0,66,44,6,0,64,16,33,64,192,0,
- 16,0,164,163,33,32,0,1,16,0,165,39,
- 88,87,192,8,1,0,6,36,24,0,167,39,
- 32,0,165,39,255,255,130,48,7,0,64,16,
- 33,24,0,0,0,0,164,160,1,0,165,36,
- 255,255,130,48,2,34,2,0,251,255,128,20,
- 1,0,99,36,128,0,98,52,0,0,226,160,
- 1,0,231,36,1,0,102,36,33,16,96,0,
- 255,255,66,48,11,0,64,16,255,255,99,36,
- 255,255,4,52,255,255,165,36,0,0,162,144,
- 0,0,0,0,0,0,226,160,1,0,231,36,
- 33,16,96,0,255,255,66,48,248,255,64,20,
- 33,24,100,0,33,32,0,1,24,0,165,39,
- 255,255,198,48,9,248,32,1,0,0,0,0,
- 40,0,191,143,48,0,189,39,8,0,224,3,
- 0,0,0,0,200,255,189,39,48,0,191,175,
- 44,0,181,175,40,0,180,175,36,0,179,175,
- 32,0,178,175,28,0,177,175,24,0,176,175,
- 33,136,160,0,33,144,192,0,33,152,224,0,
- 72,0,180,143,33,128,128,0,128,86,192,12,
- 33,32,64,2,33,168,64,0,255,255,4,50,
- 192,0,37,50,33,48,96,2,242,86,192,12,
- 33,56,128,2,255,255,176,50,33,32,0,2,
- 33,40,96,2,44,87,192,12,33,48,128,2,
- 16,0,162,39,33,24,80,0,255,255,99,36,
- 6,0,98,16,0,0,114,160,16,0,162,39,
- 3,146,18,0,255,255,99,36,253,255,98,20,
- 0,0,114,160,33,32,128,2,16,0,165,39,
- 9,248,96,2,255,255,166,50,48,0,191,143,
- 44,0,181,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,56,0,189,39,200,255,189,39,
- 48,0,191,175,44,0,181,175,40,0,180,175,
- 36,0,179,175,32,0,178,175,28,0,177,175,
- 24,0,176,175,33,136,160,0,33,144,192,0,
- 33,160,224,0,72,0,181,143,33,128,128,0,
- 153,86,192,12,33,32,64,2,33,152,64,0,
- 255,255,4,50,192,0,37,50,33,48,128,2,
- 242,86,192,12,33,56,160,2,255,255,112,50,
- 33,32,0,2,33,40,128,2,44,87,192,12,
- 33,48,160,2,16,0,162,39,33,32,80,0,
- 9,0,0,18,255,255,99,38,255,255,5,52,
- 255,255,132,36,0,0,146,160,2,146,18,0,
- 33,16,96,0,255,255,66,48,250,255,64,20,
- 33,24,101,0,33,32,160,2,16,0,165,39,
- 9,248,128,2,255,255,102,50,48,0,191,143,
- 44,0,181,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,56,0,189,39,216,255,189,39,
- 32,0,191,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,16,0,176,175,33,152,192,0,
- 56,0,178,143,60,0,177,143,33,128,224,0,
- 255,255,132,48,192,0,165,48,33,48,64,2,
- 242,86,192,12,33,56,32,2,255,255,16,50,
- 33,32,0,2,33,40,64,2,44,87,192,12,
- 33,48,32,2,4,0,0,18,33,32,32,2,
- 33,40,96,2,9,248,64,2,33,48,0,2,
- 32,0,191,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,224,255,189,39,24,0,191,175,
- 33,72,160,0,128,0,130,44,18,0,64,20,
- 33,64,192,0,0,64,130,44,13,0,64,20,
- 31,0,2,60,255,255,66,52,43,16,68,0,
- 7,0,64,16,255,15,2,60,255,255,66,52,
- 43,16,68,0,8,0,64,20,5,0,6,36,
- 250,87,192,8,4,0,6,36,250,87,192,8,
- 3,0,6,36,250,87,192,8,2,0,6,36,
- 1,0,6,36,255,255,194,48,16,0,163,39,
- 33,40,98,0,9,0,163,16,33,56,0,0,
- 16,0,163,39,255,255,165,36,127,0,130,48,
- 37,16,226,0,0,0,162,160,194,33,4,0,
- 250,255,163,20,128,0,7,36,33,32,0,1,
- 16,0,165,39,9,248,32,1,255,255,198,48,
- 24,0,191,143,32,0,189,39,8,0,224,3,
- 0,0,0,0,208,255,189,39,44,0,191,175,
- 40,0,182,175,36,0,181,175,32,0,180,175,
- 28,0,179,175,24,0,178,175,20,0,177,175,
- 16,0,176,175,33,144,160,0,33,168,192,0,
- 33,160,224,0,64,0,182,143,33,136,128,0,
- 4,0,179,142,0,0,0,0,171,86,192,12,
- 33,32,160,2,33,128,64,0,255,255,36,50,
- 192,0,69,50,33,48,128,2,242,86,192,12,
- 33,56,192,2,255,255,16,50,33,32,0,2,
- 33,40,128,2,44,87,192,12,33,48,192,2,
- 23,0,0,18,33,40,128,2,0,0,98,142,
- 4,0,115,38,128,32,2,0,33,32,130,0,
- 192,32,4,0,0,0,98,142,4,0,115,38,
- 33,32,130,0,226,87,192,12,33,48,192,2,
- 63,88,192,8,2,0,16,36,0,0,100,142,
- 4,0,115,38,226,87,192,12,33,48,192,2,
- 1,0,16,38,0,0,162,142,0,0,0,0,
- 42,16,2,2,247,255,64,20,33,40,128,2,
- 44,0,191,143,40,0,182,143,36,0,181,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 48,0,189,39,224,255,189,39,28,0,191,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,136,128,0,33,144,192,0,255,255,67,50,
- 12,0,34,150,0,0,0,0,43,16,67,0,
- 4,0,64,16,1,0,2,36,12,0,50,150,
- 0,0,0,0,255,255,67,50,11,0,98,16,
- 2,0,98,40,5,0,64,16,2,0,2,36,
- 50,0,96,16,255,255,80,50,137,88,192,8,
- 0,0,0,0,15,0,98,16,255,255,80,50,
- 137,88,192,8,0,0,0,0,8,0,35,142,
- 0,0,0,0,1,0,98,36,8,0,34,174,
- 0,0,162,144,0,0,0,0,0,0,98,160,
- 12,0,34,150,0,0,0,0,255,255,66,36,
- 149,88,192,8,12,0,34,166,8,0,35,142,
- 0,0,0,0,1,0,98,36,8,0,34,174,
- 0,0,162,144,0,0,0,0,0,0,98,160,
- 8,0,35,142,0,0,0,0,1,0,98,36,
- 8,0,34,174,1,0,162,144,0,0,0,0,
- 0,0,98,160,12,0,34,150,0,0,0,0,
- 254,255,66,36,149,88,192,8,12,0,34,166,
- 8,0,36,142,0,0,0,0,80,68,192,12,
- 33,48,0,2,12,0,34,150,0,0,0,0,
- 35,16,82,0,12,0,34,166,8,0,34,142,
- 0,0,0,0,33,128,2,2,8,0,48,174,
- 255,255,66,50,28,0,191,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,224,255,189,39,24,0,191,175,
- 20,0,177,175,16,0,176,175,33,128,160,0,
- 10,0,128,20,33,136,192,0,9,50,192,12,
- 16,0,4,36,33,32,64,0,3,0,128,20,
- 1,0,2,36,178,88,192,8,33,16,0,0,
- 173,88,192,8,0,0,130,160,0,0,128,160,
- 4,0,144,172,8,0,144,172,33,16,17,2,
- 12,0,130,172,33,16,128,0,24,0,191,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,232,255,189,39,16,0,191,175,
- 0,0,130,144,0,0,0,0,1,0,66,48,
- 3,0,64,16,0,0,0,0,61,50,192,12,
- 0,0,0,0,16,0,191,143,24,0,189,39,
- 8,0,224,3,0,0,0,0,0,0,130,144,
- 0,0,0,0,128,0,66,48,16,0,64,20,
- 255,255,2,36,8,0,130,140,12,0,131,140,
- 0,0,0,0,43,16,67,0,7,0,64,20,
- 0,0,0,0,0,0,130,144,0,0,0,0,
- 128,0,66,52,0,0,130,160,216,88,192,8,
- 255,255,2,36,8,0,130,140,0,0,0,0,
- 0,0,66,144,8,0,224,3,0,0,0,0,
- 30,0,192,24,33,56,192,0,0,0,130,144,
- 0,0,0,0,128,0,66,48,16,0,64,20,
- 255,0,3,36,8,0,131,140,12,0,130,140,
- 0,0,0,0,43,16,98,0,5,0,64,16,
- 1,0,98,36,8,0,130,172,0,0,99,144,
- 240,88,192,8,0,0,0,0,0,0,130,144,
- 0,0,0,0,128,0,66,52,0,0,130,160,
- 255,0,3,36,0,0,130,144,0,0,0,0,
- 128,0,66,48,5,0,64,20,0,0,0,0,
- 0,0,163,160,255,255,198,36,228,255,192,28,
- 1,0,165,36,8,0,224,3,35,16,230,0,
- 1,0,2,36,15,0,194,16,2,0,194,40,
- 5,0,64,16,2,0,2,36,7,0,192,16,
- 255,255,2,36,40,89,192,8,0,0,0,0,
- 11,0,194,16,255,255,2,36,40,89,192,8,
- 0,0,0,0,4,0,130,140,0,0,0,0,
- 21,89,192,8,33,40,162,0,8,0,130,140,
- 0,0,0,0,19,89,192,8,33,40,162,0,
- 12,0,130,140,0,0,0,0,35,40,69,0,
- 4,0,130,140,0,0,0,0,43,16,162,0,
- 17,0,64,20,255,255,2,36,12,0,130,140,
- 0,0,0,0,43,16,69,0,12,0,64,20,
- 255,255,2,36,12,0,130,140,0,0,0,0,
- 43,16,162,0,5,0,64,16,0,0,0,0,
- 0,0,130,144,0,0,0,0,127,0,66,48,
- 0,0,130,160,8,0,133,172,33,16,0,0,
- 8,0,224,3,0,0,0,0,12,0,130,140,
- 4,0,131,140,0,0,0,0,35,56,67,0,
- 1,0,2,36,15,0,194,16,2,0,194,40,
- 5,0,64,16,2,0,2,36,7,0,192,16,
- 255,255,2,36,87,89,192,8,0,0,0,0,
- 12,0,194,16,255,255,2,36,87,89,192,8,
- 0,0,0,0,4,0,130,140,0,0,0,0,
- 66,89,192,8,33,16,162,0,8,0,130,140,
- 0,0,0,0,33,16,162,0,72,89,192,8,
- 12,0,130,172,12,0,130,140,0,0,0,0,
- 35,16,69,0,12,0,130,172,8,0,130,140,
- 12,0,131,140,0,0,0,0,43,16,67,0,
- 5,0,64,16,0,0,0,0,0,0,130,144,
- 0,0,0,0,85,89,192,8,127,0,66,48,
- 0,0,130,144,0,0,0,0,128,0,66,52,
- 0,0,130,160,33,16,224,0,8,0,224,3,
- 0,0,0,0,232,255,189,39,20,0,191,175,
- 16,0,176,175,12,0,128,20,33,128,160,0,
- 9,50,192,12,16,0,4,36,33,32,64,0,
- 3,0,128,20,0,0,0,0,119,89,192,8,
- 33,16,0,0,0,0,2,146,0,0,0,0,
- 108,89,192,8,1,0,66,52,0,0,2,146,
- 0,0,0,0,254,0,66,48,0,0,130,160,
- 4,0,2,142,0,0,0,0,4,0,130,172,
- 8,0,2,142,0,0,0,0,8,0,130,172,
- 12,0,2,142,0,0,0,0,12,0,130,172,
- 33,16,128,0,20,0,191,143,16,0,176,143,
- 8,0,224,3,24,0,189,39,0,0,0,0,
- 0,0,130,144,0,0,0,0,128,0,66,48,
- 17,0,64,20,31,0,3,36,8,0,131,140,
- 12,0,130,140,0,0,0,0,43,16,98,0,
- 6,0,64,16,1,0,98,36,8,0,130,172,
- 0,0,98,144,0,0,0,0,145,89,192,8,
- 31,0,67,48,0,0,130,144,0,0,0,0,
- 128,0,66,52,0,0,130,160,31,0,3,36,
- 0,0,130,144,0,0,0,0,128,0,66,48,
- 4,0,64,16,1,0,2,36,0,0,162,172,
- 196,89,192,8,33,16,0,0,255,0,99,48,
- 31,0,2,36,6,0,98,16,33,16,96,0,
- 196,89,192,8,0,0,0,0,1,0,2,36,
- 195,89,192,8,0,0,162,172,33,48,0,0,
- 0,0,130,144,0,0,0,0,128,0,66,48,
- 16,0,64,20,255,0,3,36,8,0,131,140,
- 12,0,130,140,0,0,0,0,43,16,98,0,
- 5,0,64,16,1,0,98,36,8,0,130,172,
- 0,0,99,144,183,89,192,8,0,0,0,0,
- 0,0,130,144,0,0,0,0,128,0,66,52,
- 0,0,130,160,255,0,3,36,0,0,130,144,
- 0,0,0,0,128,0,66,48,228,255,64,20,
- 128,0,98,48,4,0,64,16,127,0,98,48,
- 37,16,194,0,163,89,192,8,192,49,2,0,
- 255,0,98,48,37,48,70,0,255,255,194,48,
- 8,0,224,3,0,0,0,0,0,0,130,144,
- 0,0,0,0,128,0,66,48,16,0,64,20,
- 255,0,6,36,8,0,131,140,12,0,130,140,
- 0,0,0,0,43,16,98,0,5,0,64,16,
- 1,0,98,36,8,0,130,172,0,0,102,144,
- 218,89,192,8,0,0,0,0,0,0,130,144,
- 0,0,0,0,128,0,66,52,0,0,130,160,
- 255,0,6,36,0,0,130,144,0,0,0,0,
- 128,0,66,48,13,0,64,20,1,0,2,36,
- 255,0,195,48,128,0,2,36,4,0,98,20,
- 2,0,2,36,0,0,162,172,17,90,192,8,
- 255,255,2,52,128,0,194,48,6,0,64,20,
- 33,24,0,0,17,90,192,8,255,0,194,48,
- 0,0,162,172,17,90,192,8,33,16,0,0,
- 127,0,194,48,32,0,64,16,255,255,71,36,
- 0,26,3,0,0,0,130,144,0,0,0,0,
- 128,0,66,48,16,0,64,20,255,255,102,48,
- 8,0,131,140,12,0,130,140,0,0,0,0,
- 43,16,98,0,6,0,64,16,1,0,98,36,
- 8,0,130,172,0,0,98,144,0,0,0,0,
- 7,90,192,8,37,24,194,0,0,0,130,144,
- 0,0,0,0,128,0,66,52,0,0,130,160,
- 255,0,195,52,0,0,130,144,0,0,0,0,
- 128,0,66,48,224,255,64,20,1,0,2,36,
- 33,16,224,0,255,0,66,48,226,255,64,20,
- 255,255,231,36,255,255,98,48,8,0,224,3,
- 0,0,0,0,216,255,189,39,36,0,191,175,
- 32,0,180,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,16,0,176,175,33,152,128,0,
- 33,128,192,0,33,144,160,0,255,255,81,50,
- 33,0,32,18,33,160,224,0,255,255,2,52,
- 30,0,34,18,0,0,0,0,9,50,192,12,
- 33,32,32,2,33,24,64,0,29,0,96,16,
- 1,0,2,36,0,0,2,166,4,0,3,174,
- 8,0,3,174,12,0,18,166,33,32,96,2,
- 8,0,5,142,0,0,0,0,218,88,192,12,
- 33,48,32,2,33,24,64,0,255,255,100,48,
- 10,0,145,20,1,0,2,36,12,0,2,150,
- 0,0,0,0,35,16,67,0,12,0,2,166,
- 8,0,2,142,0,0,0,0,33,16,130,0,
- 68,90,192,8,8,0,2,174,68,90,192,8,
- 0,0,130,174,0,0,0,166,4,0,0,174,
- 8,0,0,174,12,0,0,166,36,0,191,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,224,255,189,39,28,0,191,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,144,128,0,33,136,160,0,33,128,192,0,
- 124,89,192,12,33,40,0,2,33,32,64,2,
- 198,89,192,12,33,40,0,2,33,40,64,0,
- 0,0,2,142,0,0,0,0,7,0,64,20,
- 33,32,64,2,255,255,165,48,33,48,32,2,
- 19,90,192,12,33,56,0,2,104,90,192,8,
- 0,0,0,0,0,0,32,166,4,0,32,174,
- 8,0,32,174,12,0,32,166,28,0,191,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,216,255,189,39,
- 36,0,191,175,32,0,180,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,152,128,0,33,136,160,0,33,144,192,0,
- 56,0,176,147,0,0,0,0,196,88,192,12,
- 33,160,224,0,224,0,66,48,7,0,80,20,
- 33,32,96,2,124,89,192,12,33,40,64,2,
- 255,255,66,48,255,255,131,50,7,0,67,16,
- 33,32,96,2,0,0,66,142,0,0,0,0,
- 16,0,64,20,4,0,2,36,152,90,192,8,
- 0,0,66,174,198,89,192,12,33,40,64,2,
- 33,40,64,0,0,0,66,142,0,0,0,0,
- 7,0,64,20,33,32,96,2,255,255,165,48,
- 33,48,32,2,19,90,192,12,33,56,64,2,
- 156,90,192,8,0,0,0,0,0,0,32,166,
- 4,0,32,174,8,0,32,174,12,0,32,166,
- 36,0,191,143,32,0,180,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,33,56,0,0,
- 255,255,168,36,255,255,165,48,50,0,160,16,
- 1,0,9,36,1,0,12,36,4,0,10,36,
- 3,0,11,36,255,255,5,52,0,0,130,144,
- 0,0,0,0,128,0,66,48,16,0,64,20,
- 255,0,3,36,8,0,131,140,12,0,130,140,
- 0,0,0,0,43,16,98,0,5,0,64,16,
- 1,0,98,36,8,0,130,172,0,0,99,144,
- 193,90,192,8,0,0,0,0,0,0,130,144,
- 0,0,0,0,128,0,66,52,0,0,130,160,
- 255,0,3,36,0,0,130,144,0,0,0,0,
- 128,0,66,48,3,0,64,16,0,0,0,0,
- 218,90,192,8,0,0,204,172,11,0,32,17,
- 255,255,2,49,5,0,74,20,33,72,0,0,
- 3,0,96,16,0,0,0,0,218,90,192,8,
- 0,0,203,172,128,0,98,48,3,0,64,16,
- 0,18,7,0,255,255,7,36,0,18,7,0,
- 37,56,67,0,33,16,0,1,255,255,66,48,
- 212,255,64,20,33,64,5,1,8,0,224,3,
- 33,16,224,0,224,255,189,39,24,0,191,175,
- 20,0,177,175,16,0,176,175,33,128,128,0,
- 124,89,192,12,33,136,160,0,33,32,0,2,
- 198,89,192,12,33,40,32,2,33,32,0,2,
- 255,255,69,48,164,90,192,12,33,48,32,2,
- 24,0,191,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,32,0,189,39,216,255,189,39,
- 32,0,191,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,16,0,176,175,33,144,128,0,
- 33,136,160,0,33,152,192,0,196,88,192,12,
- 33,128,224,0,224,0,66,48,255,0,16,50,
- 7,0,80,20,33,32,64,2,124,89,192,12,
- 33,40,32,2,255,255,66,48,255,255,99,50,
- 8,0,67,16,33,32,64,2,0,0,34,142,
- 0,0,0,0,2,0,64,20,4,0,2,36,
- 0,0,34,174,17,91,192,8,33,16,0,0,
- 198,89,192,12,33,40,32,2,33,32,64,2,
- 255,255,69,48,164,90,192,12,33,48,32,2,
- 32,0,191,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,208,255,189,39,44,0,191,175,
- 40,0,180,175,36,0,179,175,32,0,178,175,
- 28,0,177,175,24,0,176,175,33,128,128,0,
- 33,152,192,0,33,160,224,0,0,0,96,174,
- 4,0,96,174,8,0,3,142,4,0,2,142,
- 0,0,0,0,35,24,98,0,255,255,165,48,
- 35,0,160,24,33,144,0,0,1,0,6,36,
- 0,0,2,146,0,0,0,0,128,0,66,48,
- 16,0,64,20,255,0,4,36,8,0,4,142,
- 12,0,2,142,0,0,0,0,43,16,130,0,
- 5,0,64,16,1,0,130,36,8,0,2,174,
- 0,0,132,144,64,91,192,8,0,0,0,0,
- 0,0,2,146,0,0,0,0,128,0,66,52,
- 0,0,2,162,255,0,4,36,0,0,2,146,
- 0,0,0,0,128,0,66,48,3,0,64,16,
- 128,0,130,48,150,91,192,8,0,0,134,174,
- 2,0,64,20,0,0,0,0,1,0,82,38,
- 255,255,165,36,224,255,160,28,0,0,0,0,
- 33,32,0,2,33,40,96,0,251,88,192,12,
- 33,48,0,0,68,0,64,18,1,0,81,38,
- 9,50,192,12,128,32,17,0,33,40,64,0,
- 63,0,160,16,0,0,0,0,0,0,113,174,
- 4,0,101,174,59,0,64,26,33,56,0,0,
- 1,0,8,36,33,48,0,0,0,0,2,146,
- 0,0,0,0,128,0,66,48,16,0,64,20,
- 255,0,4,36,8,0,3,142,12,0,2,142,
- 0,0,0,0,43,16,98,0,5,0,64,16,
- 1,0,98,36,8,0,2,174,0,0,100,144,
- 114,91,192,8,0,0,0,0,0,0,2,146,
- 0,0,0,0,128,0,66,52,0,0,2,162,
- 255,0,4,36,0,0,2,146,0,0,0,0,
- 128,0,66,48,3,0,64,16,192,49,6,0,
- 150,91,192,8,0,0,136,174,127,0,130,48,
- 37,48,194,0,128,0,130,48,225,255,64,20,
- 0,0,0,0,18,0,224,20,40,0,194,44,
- 4,0,64,16,80,0,194,44,0,0,160,172,
- 145,91,192,8,4,0,165,36,5,0,64,16,
- 216,255,194,36,0,0,168,172,4,0,165,36,
- 146,91,192,8,0,0,162,172,2,0,2,36,
- 0,0,162,172,4,0,165,36,176,255,194,36,
- 146,91,192,8,0,0,162,172,0,0,166,172,
- 1,0,231,36,42,16,242,0,200,255,64,20,
- 4,0,165,36,44,0,191,143,40,0,180,143,
- 36,0,179,143,32,0,178,143,28,0,177,143,
- 24,0,176,143,8,0,224,3,48,0,189,39,
- 224,255,189,39,28,0,191,175,24,0,178,175,
- 20,0,177,175,16,0,176,175,33,136,128,0,
- 33,144,160,0,33,128,192,0,124,89,192,12,
- 33,40,0,2,33,32,32,2,198,89,192,12,
- 33,40,0,2,33,40,64,0,0,0,2,142,
- 0,0,0,0,5,0,64,20,33,32,32,2,
- 255,255,165,48,33,48,64,2,24,91,192,12,
- 33,56,0,2,28,0,191,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 32,0,189,39,216,255,189,39,36,0,191,175,
- 32,0,180,175,28,0,179,175,24,0,178,175,
- 20,0,177,175,16,0,176,175,33,144,128,0,
- 33,160,160,0,33,136,192,0,56,0,176,147,
- 0,0,0,0,196,88,192,12,33,152,224,0,
- 224,0,66,48,7,0,80,20,33,32,64,2,
- 124,89,192,12,33,40,32,2,255,255,66,48,
- 255,255,99,50,7,0,67,16,33,32,64,2,
- 0,0,34,142,0,0,0,0,14,0,64,20,
- 4,0,2,36,226,91,192,8,0,0,34,174,
- 198,89,192,12,33,40,32,2,33,40,64,0,
- 0,0,34,142,0,0,0,0,5,0,64,20,
- 33,32,64,2,255,255,165,48,33,48,128,2,
- 24,91,192,12,33,56,32,2,36,0,191,143,
- 32,0,180,143,28,0,179,143,24,0,178,143,
- 20,0,177,143,16,0,176,143,8,0,224,3,
- 40,0,189,39,0,0,0,0,0,0,0,0,
- 216,255,189,39,32,0,191,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,152,128,0,8,0,99,142,4,0,98,142,
- 0,0,0,0,35,128,98,0,255,255,4,50,
- 19,0,128,16,33,136,160,0,9,50,192,12,
- 0,0,0,0,33,144,64,0,3,0,64,22,
- 255,255,16,50,17,92,192,8,255,255,2,36,
- 33,32,64,2,4,0,101,142,0,0,0,0,
- 80,68,192,12,33,48,0,2,1,0,2,36,
- 0,0,34,166,4,0,50,174,33,128,80,2,
- 15,92,192,8,8,0,48,174,0,0,32,166,
- 4,0,32,174,8,0,32,174,12,0,32,166,
- 33,16,0,0,32,0,191,143,28,0,179,143,
- 24,0,178,143,20,0,177,143,16,0,176,143,
- 8,0,224,3,40,0,189,39,232,255,189,39,
- 20,0,191,175,16,0,176,175,33,128,128,0,
- 0,0,2,150,0,0,0,0,1,0,66,48,
- 7,0,64,16,0,0,0,0,4,0,4,142,
- 0,0,0,0,3,0,128,16,0,0,0,0,
- 61,50,192,12,0,0,0,0,0,0,0,166,
- 8,0,0,174,4,0,0,174,12,0,0,166,
- 20,0,191,143,16,0,176,143,8,0,224,3,
- 24,0,189,39,224,255,189,39,24,0,191,175,
- 20,0,177,175,16,0,176,175,33,128,128,0,
- 8,0,163,140,4,0,162,140,0,0,0,0,
- 35,136,98,0,255,255,35,50,12,0,2,150,
- 0,0,0,0,43,16,67,0,4,0,64,16,
- 255,255,38,50,12,0,17,150,0,0,0,0,
- 255,255,38,50,6,0,192,16,255,255,34,50,
- 8,0,4,142,4,0,165,140,80,68,192,12,
- 0,0,0,0,255,255,34,50,8,0,3,142,
- 0,0,0,0,33,16,67,0,8,0,2,174,
- 12,0,2,150,0,0,0,0,35,16,81,0,
- 12,0,2,166,24,0,191,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,32,0,189,39,
- 1,0,2,36,23,0,194,16,2,0,194,40,
- 5,0,64,16,2,0,2,36,7,0,192,16,
- 255,255,2,36,132,92,192,8,0,0,0,0,
- 23,0,194,16,255,255,2,36,132,92,192,8,
- 0,0,0,0,255,255,162,48,4,0,131,140,
- 0,0,0,0,33,48,67,0,8,0,130,140,
- 0,0,0,0,35,16,67,0,12,0,131,148,
- 0,0,0,0,33,16,67,0,124,92,192,8,
- 35,40,69,0,255,255,162,48,8,0,131,140,
- 0,0,0,0,33,48,67,0,12,0,130,148,
- 0,0,0,0,124,92,192,8,35,40,69,0,
- 12,0,130,148,8,0,131,140,0,0,0,0,
- 33,48,67,0,255,255,162,48,35,48,194,0,
- 4,0,130,140,0,0,0,0,43,16,194,0,
- 4,0,64,20,255,255,2,36,8,0,134,172,
- 12,0,133,164,33,16,0,0,8,0,224,3,
- 0,0,0,0,216,255,189,39,32,0,191,175,
- 28,0,179,175,24,0,178,175,20,0,177,175,
- 16,0,176,175,33,128,128,0,33,152,160,0,
- 8,0,3,142,4,0,2,142,0,0,0,0,
- 35,144,98,0,255,255,66,50,12,0,3,150,
- 0,0,0,0,33,16,67,0,255,255,99,50,
- 42,16,67,0,35,0,64,16,1,0,2,36,
- 0,0,3,150,0,0,0,0,32,0,98,20,
- 255,255,2,36,9,50,192,12,255,255,100,50,
- 33,136,64,0,3,0,32,22,255,255,70,50,
- 189,92,192,8,255,255,2,36,5,0,192,16,
- 0,0,0,0,4,0,5,142,0,0,0,0,
- 80,68,192,12,33,32,32,2,0,0,2,150,
- 0,0,0,0,1,0,66,48,7,0,64,16,
- 0,0,0,0,4,0,4,142,0,0,0,0,
- 3,0,128,16,0,0,0,0,61,50,192,12,
- 0,0,0,0,4,0,17,174,255,255,66,50,
- 33,16,34,2,8,0,2,174,35,16,114,2,
- 12,0,2,166,33,16,0,0,32,0,191,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,40,0,189,39,
- 216,255,189,39,32,0,191,175,28,0,179,175,
- 24,0,178,175,20,0,177,175,16,0,176,175,
- 33,128,128,0,33,136,192,0,255,255,36,50,
- 35,0,128,16,33,152,160,0,8,0,2,142,
- 4,0,3,142,0,0,0,0,35,16,67,0,
- 255,255,66,48,12,0,3,150,0,0,0,0,
- 33,16,67,0,42,16,68,0,20,0,64,16,
- 0,0,0,0,9,50,192,12,0,0,0,0,
- 33,144,64,0,24,0,64,18,255,255,2,36,
- 0,0,2,150,0,0,0,0,1,0,66,48,
- 8,0,64,16,1,0,2,36,4,0,4,142,
- 0,0,0,0,4,0,128,16,0,0,0,0,
- 61,50,192,12,0,0,0,0,1,0,2,36,
- 0,0,2,166,4,0,18,174,4,0,4,142,
- 33,40,96,2,80,68,192,12,255,255,38,50,
- 33,32,0,2,255,255,37,50,85,92,192,12,
- 33,48,0,0,33,16,0,0,32,0,191,143,
- 28,0,179,143,24,0,178,143,20,0,177,143,
- 16,0,176,143,8,0,224,3,40,0,189,39,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 184,255,189,39,64,0,191,175,60,0,183,175,
- 56,0,182,175,52,0,181,175,48,0,180,175,
- 44,0,179,175,40,0,178,175,36,0,177,175,
- 32,0,176,175,33,144,128,0,112,0,84,142,
- 0,0,0,0,92,0,128,18,1,0,2,36,
- 108,0,81,142,0,0,0,0,88,0,32,18,
- 0,0,0,0,96,0,87,38,136,0,66,174,
- 140,0,64,174,96,0,64,174,100,0,64,174,
- 224,83,192,12,33,32,32,2,33,168,64,0,
- 25,0,160,18,33,128,160,2,108,0,66,142,
- 0,0,0,0,124,0,66,174,128,0,84,174,
- 108,0,81,174,112,0,85,174,29,0,32,26,
- 33,152,0,0,255,255,22,36,33,32,0,2,
- 8,0,133,38,33,48,64,2,170,72,192,12,
- 1,0,7,36,10,0,86,16,33,32,64,2,
- 14,0,64,20,0,0,0,0,64,0,66,142,
- 0,0,0,0,10,0,64,20,2,0,5,36,
- 56,93,192,8,1,0,102,38,33,32,64,2,
- 5,0,5,36,33,48,0,0,140,84,192,12,
- 0,0,0,0,107,93,192,8,1,0,2,36,
- 1,0,115,38,68,0,16,38,42,16,113,2,
- 230,255,64,20,68,0,148,38,40,0,32,18,
- 33,128,160,2,17,0,2,146,0,0,0,0,
- 34,0,66,48,32,0,64,20,0,0,0,0,
- 36,0,2,142,16,0,176,175,16,0,66,140,
- 24,0,4,142,28,0,5,142,32,0,6,142,
- 0,0,0,0,9,248,64,0,33,56,64,2,
- 17,0,2,146,0,0,0,0,32,0,66,52,
- 17,0,2,162,0,0,226,142,0,0,0,0,
- 15,0,64,16,0,0,0,0,255,255,49,38,
- 15,0,32,18,68,0,16,38,17,0,3,146,
- 0,0,0,0,32,0,98,48,2,0,64,20,
- 34,0,98,52,17,0,2,162,255,255,49,38,
- 248,255,32,22,68,0,16,38,107,93,192,8,
- 33,16,0,0,255,255,49,38,218,255,32,22,
- 68,0,16,38,33,16,0,0,64,0,191,143,
- 60,0,183,143,56,0,182,143,52,0,181,143,
- 48,0,180,143,44,0,179,143,40,0,178,143,
- 36,0,177,143,32,0,176,143,8,0,224,3,
- 72,0,189,39,168,255,189,39,80,0,191,175,
- 76,0,183,175,72,0,182,175,68,0,181,175,
- 64,0,180,175,60,0,179,175,56,0,178,175,
- 52,0,177,175,48,0,176,175,33,144,128,0,
- 96,0,66,142,0,0,0,0,3,0,64,16,
- 33,32,0,0,240,93,192,8,255,255,2,36,
- 116,0,66,142,0,0,0,0,7,0,64,16,
- 104,0,67,38,12,0,99,140,0,0,0,0,
- 12,0,98,140,0,0,0,0,251,255,64,20,
- 0,0,0,0,8,0,116,140,0,0,0,0,
- 92,0,128,18,33,16,0,0,4,0,115,140,
- 0,0,0,0,88,0,96,18,0,0,0,0,
- 64,0,66,142,0,0,0,0,55,0,64,20,
- 0,0,0,0,33,128,128,2,52,0,96,26,
- 33,136,0,0,255,255,23,36,2,0,22,36,
- 5,0,21,36,17,0,2,146,0,0,0,0,
- 16,0,66,48,40,0,64,16,24,0,165,39,
- 8,0,3,142,28,0,2,142,0,0,0,0,
- 35,24,98,0,24,0,163,175,12,0,2,142,
- 0,0,0,0,28,0,162,175,128,24,3,0,
- 33,24,98,0,252,255,98,140,0,0,0,0,
- 1,0,66,36,252,255,98,172,12,0,0,174,
- 8,0,0,174,33,32,0,2,33,48,64,2,
- 170,72,192,12,1,0,7,36,6,0,87,16,
- 0,0,0,0,9,0,64,20,1,0,34,38,
- 96,0,86,174,196,93,192,8,100,0,66,174,
- 96,0,85,174,110,86,192,12,24,0,164,39,
- 240,93,192,8,255,255,2,36,110,86,192,12,
- 24,0,164,39,17,0,2,146,0,0,0,0,
- 12,0,66,48,17,0,2,162,1,0,4,36,
- 1,0,49,38,42,16,51,2,209,255,64,20,
- 68,0,16,38,27,0,128,16,33,128,128,2,
- 23,0,96,26,33,136,0,0,17,0,2,146,
- 0,0,0,0,34,0,66,48,14,0,64,20,
- 0,0,0,0,36,0,2,142,16,0,176,175,
- 16,0,66,140,24,0,4,142,28,0,5,142,
- 32,0,6,142,0,0,0,0,9,248,64,0,
- 33,56,64,2,17,0,2,146,0,0,0,0,
- 32,0,66,52,17,0,2,162,1,0,49,38,
- 42,16,51,2,235,255,64,20,68,0,16,38,
- 240,93,192,8,1,0,2,36,33,16,0,0,
- 80,0,191,143,76,0,183,143,72,0,182,143,
- 68,0,181,143,64,0,180,143,60,0,179,143,
- 56,0,178,143,52,0,177,143,48,0,176,143,
- 8,0,224,3,88,0,189,39,0,0,0,0,
- 200,255,189,39,48,0,191,175,44,0,179,175,
- 40,0,178,175,36,0,177,175,32,0,176,175,
- 33,144,128,0,96,0,64,174,100,0,64,174,
- 112,0,80,142,0,0,0,0,105,0,0,18,
- 33,16,0,0,108,0,81,142,0,0,0,0,
- 101,0,32,18,0,0,0,0,64,0,66,142,
- 0,0,0,0,43,0,64,20,33,32,64,2,
- 50,0,32,26,33,152,0,0,33,32,0,2,
- 33,40,64,2,96,72,192,12,1,0,6,36,
- 13,0,64,20,33,32,64,2,20,0,2,150,
- 0,0,0,0,1,0,66,48,34,0,64,16,
- 2,0,5,36,36,0,2,142,0,0,0,0,
- 3,0,66,144,0,0,0,0,2,0,66,48,
- 3,0,64,20,0,0,0,0,63,94,192,8,
- 2,0,5,36,36,0,2,142,0,0,0,0,
- 32,0,66,140,4,0,67,142,0,0,0,0,
- 36,16,67,0,16,0,64,16,33,32,64,2,
- 36,0,2,142,16,0,3,146,2,0,66,144,
- 0,0,0,0,11,0,98,20,3,0,5,36,
- 1,0,115,38,42,16,113,2,219,255,64,20,
- 68,0,16,38,69,94,192,8,96,0,83,38,
- 5,0,5,36,64,94,192,8,33,48,0,0,
- 2,0,5,36,1,0,102,38,140,84,192,12,
- 0,0,0,0,113,94,192,8,1,0,2,36,
- 96,0,83,38,112,0,80,142,0,0,0,0,
- 41,0,32,18,33,16,0,0,17,0,2,146,
- 0,0,0,0,17,0,66,48,32,0,64,20,
- 0,0,0,0,36,0,2,142,16,0,176,175,
- 4,0,66,140,24,0,4,142,28,0,5,142,
- 32,0,6,142,0,0,0,0,9,248,64,0,
- 33,56,64,2,17,0,2,146,0,0,0,0,
- 16,0,66,52,17,0,2,162,0,0,98,142,
- 0,0,0,0,15,0,64,16,0,0,0,0,
- 255,255,49,38,15,0,32,18,68,0,16,38,
- 17,0,3,146,0,0,0,0,16,0,98,48,
- 2,0,64,20,17,0,98,52,17,0,2,162,
- 255,255,49,38,248,255,32,22,68,0,16,38,
- 113,94,192,8,33,16,0,0,255,255,49,38,
- 218,255,32,22,68,0,16,38,33,16,0,0,
- 48,0,191,143,44,0,179,143,40,0,178,143,
- 36,0,177,143,32,0,176,143,8,0,224,3,
- 56,0,189,39,192,255,189,39,56,0,191,175,
- 52,0,183,175,48,0,182,175,44,0,181,175,
- 40,0,180,175,36,0,179,175,32,0,178,175,
- 28,0,177,175,24,0,176,175,33,144,128,0,
- 112,0,84,142,0,0,0,0,171,0,128,18,
- 33,16,0,0,108,0,85,142,0,0,0,0,
- 166,0,160,18,32,0,2,36,56,0,67,146,
- 0,0,0,0,75,0,98,16,96,0,83,38,
- 33,0,98,40,5,0,64,16,64,0,2,36,
- 9,0,96,16,33,16,0,0,49,95,192,8,
- 0,0,0,0,85,0,98,16,128,0,2,36,
- 137,0,98,16,33,16,0,0,49,95,192,8,
- 0,0,0,0,33,136,160,2,8,0,32,18,
- 33,128,128,2,17,0,2,146,0,0,0,0,
- 1,0,66,48,139,0,64,16,255,255,49,38,
- 250,255,32,22,68,0,16,38,0,0,98,142,
- 0,0,0,0,136,0,64,20,33,16,0,0,
- 33,136,160,2,43,0,32,18,33,128,128,2,
- 14,0,22,36,64,0,23,36,17,0,2,146,
- 0,0,0,0,34,0,66,48,33,0,64,20,
- 0,0,0,0,36,0,2,142,16,0,176,175,
- 12,0,66,140,24,0,4,142,28,0,5,142,
- 32,0,6,142,0,0,0,0,9,248,64,0,
- 33,56,64,2,17,0,2,146,0,0,0,0,
- 32,0,66,52,17,0,2,162,0,0,98,142,
- 0,0,0,0,16,0,64,16,0,0,0,0,
- 255,255,49,38,10,0,32,18,68,0,16,38,
- 17,0,3,146,0,0,0,0,32,0,98,48,
- 2,0,64,20,192,0,98,52,17,0,2,162,
- 255,255,49,38,248,255,32,22,68,0,16,38,
- 0,0,118,174,236,94,192,8,56,0,87,162,
- 255,255,49,38,217,255,32,22,68,0,16,38,
- 32,0,2,36,56,0,66,162,0,0,98,142,
- 0,0,0,0,13,0,64,20,64,0,2,36,
- 33,136,160,2,81,0,32,18,33,128,128,2,
- 17,0,2,146,0,0,0,0,2,0,66,48,
- 74,0,64,16,255,255,49,38,250,255,32,22,
- 68,0,16,38,49,95,192,8,33,16,0,0,
- 56,0,66,162,14,0,2,36,0,0,98,174,
- 33,136,160,2,53,0,32,18,33,128,128,2,
- 2,0,23,36,15,0,22,36,17,0,2,146,
- 0,0,0,0,194,0,66,48,5,0,64,16,
- 0,0,0,0,19,0,87,16,0,0,0,0,
- 32,95,192,8,255,255,49,38,64,0,2,142,
- 0,0,0,0,34,0,64,16,0,0,0,0,
- 16,0,176,175,64,0,2,142,24,0,4,142,
- 28,0,5,142,32,0,6,142,0,0,0,0,
- 9,248,64,0,33,56,64,2,17,0,2,146,
- 0,0,0,0,30,95,192,8,64,0,66,52,
- 64,0,2,142,0,0,0,0,13,0,64,16,
- 0,0,0,0,16,0,176,175,64,0,2,142,
- 24,0,4,142,28,0,5,142,32,0,6,142,
- 0,0,0,0,9,248,64,0,33,56,64,2,
- 17,0,2,146,0,0,0,0,30,95,192,8,
- 64,0,66,52,0,0,118,174,17,0,2,146,
- 0,0,0,0,128,0,66,52,17,0,2,162,
- 255,255,49,38,208,255,32,22,68,0,16,38,
- 33,136,160,2,12,0,32,18,33,128,128,2,
- 17,0,2,146,0,0,0,0,128,0,66,48,
- 5,0,64,16,255,255,49,38,250,255,32,22,
- 68,0,16,38,49,95,192,8,33,16,0,0,
- 49,95,192,8,1,0,2,36,33,16,0,0,
- 56,0,191,143,52,0,183,143,48,0,182,143,
- 44,0,181,143,40,0,180,143,36,0,179,143,
- 32,0,178,143,28,0,177,143,24,0,176,143,
- 8,0,224,3,64,0,189,39,184,255,189,39,
- 64,0,191,175,60,0,183,175,56,0,182,175,
- 52,0,181,175,48,0,180,175,44,0,179,175,
- 40,0,178,175,36,0,177,175,32,0,176,175,
- 33,160,128,0,112,0,147,142,0,0,0,0,
- 129,0,96,18,33,16,0,0,108,0,146,142,
- 0,0,0,0,125,0,64,18,96,0,151,38,
- 96,0,128,174,100,0,128,174,224,83,192,12,
- 33,32,64,2,33,168,64,0,5,0,160,22,
- 33,136,64,2,33,32,128,2,5,0,5,36,
- 123,95,192,8,33,48,0,0,36,0,64,18,
- 33,128,160,2,5,0,22,36,16,0,22,162,
- 8,0,100,142,12,0,101,142,0,0,0,0,
- 80,86,192,12,8,0,6,38,5,0,64,20,
- 0,0,0,0,255,255,49,38,68,0,115,38,
- 245,255,32,22,68,0,16,38,21,0,32,18,
- 42,16,50,2,7,0,64,16,33,128,160,2,
- 59,84,192,12,33,32,0,2,1,0,49,38,
- 42,16,50,2,251,255,64,20,68,0,16,38,
- 61,50,192,12,33,32,160,2,33,32,128,2,
- 5,0,5,36,123,95,192,8,33,48,0,0,
- 2,0,5,36,1,0,38,38,140,84,192,12,
- 0,0,0,0,203,95,192,8,1,0,2,36,
- 124,0,146,174,112,0,130,142,0,0,0,0,
- 128,0,130,174,112,0,149,174,33,128,160,2,
- 27,0,64,26,33,136,0,0,33,32,0,2,
- 33,40,128,2,96,72,192,12,1,0,6,36,
- 13,0,64,20,0,0,0,0,20,0,2,150,
- 0,0,0,0,1,0,66,48,8,0,64,16,
- 0,0,0,0,36,0,2,142,0,0,0,0,
- 3,0,66,144,0,0,0,0,1,0,66,48,
- 5,0,64,20,0,0,0,0,64,0,130,142,
- 0,0,0,0,221,255,64,16,33,32,128,2,
- 1,0,49,38,42,16,50,2,231,255,64,20,
- 68,0,16,38,40,0,64,18,33,128,160,2,
- 17,0,2,146,0,0,0,0,34,0,66,48,
- 32,0,64,20,0,0,0,0,36,0,2,142,
- 16,0,176,175,8,0,66,140,24,0,4,142,
- 28,0,5,142,32,0,6,142,0,0,0,0,
- 9,248,64,0,33,56,128,2,17,0,2,146,
- 0,0,0,0,32,0,66,52,17,0,2,162,
- 0,0,226,142,0,0,0,0,15,0,64,16,
- 0,0,0,0,255,255,82,38,15,0,64,18,
- 68,0,16,38,17,0,3,146,0,0,0,0,
- 32,0,98,48,2,0,64,20,34,0,98,52,
- 17,0,2,162,255,255,82,38,248,255,64,22,
- 68,0,16,38,203,95,192,8,33,16,0,0,
- 255,255,82,38,218,255,64,22,68,0,16,38,
- 33,16,0,0,64,0,191,143,60,0,183,143,
- 56,0,182,143,52,0,181,143,48,0,180,143,
- 44,0,179,143,40,0,178,143,36,0,177,143,
- 32,0,176,143,8,0,224,3,72,0,189,39,
- 0,0,0,0,0,0,0,0,37,115,58,37,
- 100,58,32,102,97,105,108,101,100,32,97,115,
- 115,101,114,116,105,111,110,32,96,37,115,39,
- 10,0,0,0,114,97,109,116,101,115,116,100,
- 119,40,98,99,46,98,99,95,104,101,97,112,
- 115,116,97,114,116,44,32,108,101,110,44,32,
- 49,44,32,48,44,32,48,41,32,61,61,32,
- 48,0,0,0,98,99,46,98,99,95,104,101,
- 97,112,101,110,100,32,60,61,32,98,99,46,
- 98,99,95,114,97,109,101,110,100,0,0,0,
- 35,32,112,111,114,116,115,58,32,37,100,10,
- 0,0,0,0,42,42,42,80,114,111,102,105,
- 108,105,110,103,32,64,32,37,120,44,32,37,
- 120,10,0,0,103,111,116,32,104,101,114,101,
- 32,99,97,117,115,101,61,37,120,32,115,116,
- 97,116,117,115,61,37,120,32,118,101,99,61,
- 37,120,10,0,37,115,58,37,100,58,32,102,
- 97,105,108,101,100,32,97,115,115,101,114,116,
- 105,111,110,32,96,37,115,39,10,0,0,0,
- 83,101,99,111,110,100,115,32,60,32,48,120,
- 55,70,70,70,102,102,102,102,0,0,0,0,
- 84,105,109,101,114,115,85,115,101,100,32,60,
- 32,78,84,73,77,69,82,83,0,0,0,0,
- 0,0,0,0,69,69,80,82,79,77,32,105,
- 115,32,98,97,100,10,0,0,80,111,114,116,
- 32,37,100,32,101,116,104,101,114,32,97,100,
- 100,114,101,115,115,58,32,37,48,50,88,58,
- 37,48,50,88,58,37,48,50,88,58,37,48,
- 50,88,58,37,48,50,88,58,37,48,50,88,
- 10,0,0,0,35,35,35,32,56,50,53,57,
- 54,32,67,104,97,110,32,37,100,58,32,115,
- 101,108,102,116,101,115,116,32,102,97,105,108,
- 101,100,32,40,37,120,41,10,0,0,0,0,
- 42,42,42,32,56,50,53,57,54,32,80,111,
- 114,116,32,37,100,58,32,115,101,108,102,116,
- 101,115,116,32,112,97,115,115,101,100,10,0,
- 56,50,53,57,54,32,80,111,114,116,32,37,
- 100,58,32,100,117,109,112,32,102,97,105,108,
- 101,100,32,40,37,120,41,10,0,0,0,0,
- 42,42,42,32,56,50,53,57,54,32,80,111,
- 114,116,32,37,100,58,32,100,117,109,112,32,
- 112,97,115,115,101,100,10,0,35,35,35,32,
- 56,50,53,57,54,32,80,111,114,116,32,37,
- 100,58,32,83,67,80,32,102,101,116,99,104,
- 32,102,97,105,108,101,100,10,0,0,0,0,
- 42,42,42,32,56,50,53,57,54,32,80,111,
- 114,116,32,37,100,58,32,83,67,80,32,102,
- 101,116,99,104,32,112,97,115,115,101,100,32,
- 37,120,32,10,0,0,0,0,35,35,35,32,
- 56,50,53,57,54,32,80,111,114,116,32,37,
- 100,58,32,66,85,83,84,73,77,69,82,83,
- 32,108,111,97,100,32,102,97,105,108,101,100,
- 10,0,0,0,42,42,42,32,56,50,53,57,
- 54,32,80,111,114,116,32,37,100,58,32,66,
- 85,83,84,73,77,69,82,83,32,108,111,97,
- 100,32,112,97,115,115,101,100,10,0,0,0,
- 35,35,35,32,65,67,75,32,100,105,100,32,
- 110,111,116,32,111,99,99,117,114,10,0,0,
- 35,35,35,32,115,116,97,116,117,115,32,115,
- 116,105,108,108,32,98,117,115,121,58,32,37,
- 120,10,0,0,101,116,104,95,105,110,105,116,
- 46,99,0,0,42,42,42,76,49,87,65,10,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,35,35,35,32,84,66,68,32,
- 98,108,111,99,107,115,32,97,114,101,110,39,
- 116,32,98,101,105,110,103,32,102,114,101,101,
- 100,10,0,0,65,116,116,101,109,112,116,32,
- 116,111,32,102,114,101,101,32,98,111,103,117,
- 115,32,84,66,68,32,37,120,10,0,0,0,
- 35,35,35,32,66,85,70,32,98,108,111,99,
- 107,115,32,97,114,101,110,39,116,32,98,101,
- 105,110,103,32,102,114,101,101,100,10,0,0,
- 65,116,116,101,109,112,116,32,116,111,32,102,
- 114,101,101,32,98,111,103,117,115,32,66,85,
- 70,32,37,120,10,0,0,0,0,0,0,0,
- 0,0,0,0,82,70,68,115,32,37,100,32,
- 10,0,0,0,82,66,68,115,32,37,100,32,
- 10,0,0,0,37,115,58,37,100,58,32,102,
- 97,105,108,101,100,32,97,115,115,101,114,116,
- 105,111,110,32,96,37,115,39,10,0,0,0,
- 101,116,104,95,114,99,118,46,99,0,0,0,
- 100,115,116,99,104,97,110,32,62,61,32,49,
- 32,38,38,32,100,115,116,99,104,97,110,32,
- 60,32,78,99,104,97,110,0,37,115,37,48,
- 50,88,58,37,48,50,88,58,37,48,50,88,
- 58,37,48,50,88,58,37,48,50,88,58,37,
- 48,50,88,37,115,0,0,0,176,72,0,131,
- 80,67,0,131,164,67,0,131,24,68,0,131,
- 80,67,0,131,0,0,0,0,4,82,0,131,
- 184,76,0,131,12,77,0,131,128,77,0,131,
- 184,76,0,131,0,0,0,0,0,0,0,0,
- 0,0,0,0,37,115,58,37,100,58,32,102,
- 97,105,108,101,100,32,97,115,115,101,114,116,
- 105,111,110,32,96,37,115,39,10,0,0,0,
- 101,116,104,95,120,109,105,116,46,99,0,0,
- 99,98,112,45,62,110,111,112,46,99,109,100,
- 32,61,61,32,73,53,57,54,95,67,66,95,
- 67,77,68,95,78,79,80,124,73,53,57,54,
- 95,67,66,95,67,77,68,95,69,76,0,0,
- 99,98,112,45,62,110,111,112,46,99,109,100,
- 32,38,32,73,53,57,54,95,67,66,95,67,
- 77,68,0,0,112,45,62,115,99,98,112,45,
- 62,115,116,97,116,117,115,32,38,32,73,53,
- 57,54,95,83,67,66,95,67,78,65,0,0,
- 35,35,35,32,99,109,100,32,115,116,105,108,
- 108,32,98,117,115,121,58,32,37,120,10,0,
- 37,100,61,37,100,44,37,120,44,37,100,10,
- 0,0,0,0,39,37,115,39,32,37,120,32,
- 37,120,10,0,37,48,56,120,58,32,37,48,
- 50,120,10,0,37,48,56,120,58,32,37,48,
- 52,120,10,0,37,48,56,120,58,32,37,48,
- 56,120,10,0,108,105,110,107,32,115,116,97,
- 116,101,32,37,48,50,120,10,0,0,0,0,
- 42,42,42,32,103,111,116,32,37,100,32,105,
- 110,116,101,114,114,117,112,116,115,10,0,0,
- 35,35,35,32,69,120,112,101,99,116,101,100,
- 32,37,100,32,98,117,116,32,103,111,116,32,
- 37,100,32,105,110,116,101,114,114,117,112,116,
- 115,10,0,0,80,76,88,57,48,54,48,32,
- 65,100,100,114,101,115,115,32,61,32,37,88,
- 32,68,65,84,65,32,61,32,37,88,32,10,
- 0,0,0,0,42,42,42,32,87,114,105,116,
- 101,32,111,102,32,37,120,32,116,111,32,37,
- 100,32,102,97,105,108,101,100,10,0,0,0,
- 42,42,42,32,87,114,105,116,101,32,111,102,
- 32,37,120,32,116,111,32,37,120,32,102,97,
- 105,108,101,100,10,0,0,0,42,42,42,42,
- 42,42,42,42,42,42,42,42,42,42,42,42,
- 0,0,0,0,42,42,42,32,73,108,108,101,
- 103,97,108,32,99,111,109,109,97,110,100,32,
- 39,37,115,39,10,0,0,0,45,45,45,32,
- 99,111,109,109,97,110,100,115,32,109,44,116,
- 44,101,44,69,44,97,44,120,44,108,44,115,
- 44,112,32,99,97,110,32,98,101,32,112,114,
- 101,102,105,120,101,100,32,119,105,116,104,32,
- 97,32,114,101,112,101,97,116,32,99,111,117,
- 110,116,0,0,108,32,120,112,111,114,116,32,
- 114,112,111,114,116,32,91,108,101,110,93,32,
- 32,32,32,32,32,32,32,32,32,76,111,111,
- 112,98,97,99,107,32,116,101,115,116,32,102,
- 114,111,109,32,120,112,111,114,116,32,40,49,
- 45,54,41,32,116,111,32,114,112,111,114,116,
- 32,40,49,45,54,41,0,0,105,32,32,32,
- 32,32,32,32,32,32,73,110,116,101,114,114,
- 117,112,116,32,72,111,115,116,32,32,124,32,
- 32,115,32,91,112,111,114,116,93,32,91,108,
- 101,110,93,32,66,97,99,107,50,98,97,99,
- 107,32,120,109,105,116,32,99,110,116,32,112,
- 97,99,107,101,116,115,0,0,80,32,32,32,
- 32,32,32,32,32,32,84,101,115,116,32,80,
- 76,88,32,57,48,54,48,32,32,32,124,32,
- 32,100,32,91,114,124,119,124,108,124,116,93,
- 32,91,118,97,108,124,39,99,39,93,32,32,
- 82,101,97,100,47,87,114,105,116,101,47,76,
- 111,111,112,47,84,105,109,101,32,68,77,65,
- 0,0,0,0,76,32,32,32,32,32,32,32,
- 32,32,82,101,97,100,32,76,105,110,107,32,
- 76,69,68,115,32,32,124,32,32,112,32,114,
- 101,103,110,111,32,91,118,97,108,93,32,32,
- 82,101,97,100,47,91,119,114,105,116,101,93,
- 32,80,76,88,32,114,101,103,105,115,116,101,
- 114,0,0,0,65,32,97,100,100,114,32,32,
- 32,32,83,101,116,32,101,116,104,101,114,32,
- 97,100,100,114,32,32,124,32,32,36,32,115,
- 99,114,105,112,116,32,32,32,32,32,32,32,
- 82,101,97,100,32,99,109,100,115,32,102,114,
- 111,109,32,102,105,108,101,32,39,115,99,114,
- 105,112,116,39,0,0,0,0,120,32,91,112,
- 111,114,116,93,32,32,84,120,32,101,116,104,
- 101,114,32,32,32,32,32,32,32,32,124,32,
- 32,82,32,91,112,111,114,116,93,32,32,32,
- 32,32,32,32,82,120,32,101,116,104,101,114,
- 32,91,111,110,32,112,111,114,116,32,49,45,
- 54,93,0,0,72,32,32,32,32,32,32,32,
- 32,32,84,111,103,103,108,101,32,70,67,67,
- 32,116,101,115,116,32,124,32,32,113,44,94,
- 68,44,94,90,32,32,32,32,32,32,32,32,
- 81,117,105,116,0,0,0,0,97,32,32,32,
- 32,32,32,32,32,32,84,101,115,116,32,97,
- 108,108,32,32,32,32,32,32,32,32,124,32,
- 32,90,32,109,115,101,99,115,32,32,32,32,
- 32,32,32,32,80,97,117,115,101,32,102,111,
- 114,32,97,32,119,104,105,108,101,0,0,0,
- 69,32,32,32,32,32,32,32,32,32,84,101,
- 115,116,32,69,69,80,82,79,77,32,32,32,
- 32,32,124,32,32,83,114,32,97,100,100,114,
- 59,32,83,119,32,97,100,100,114,32,118,97,
- 108,59,32,32,82,101,97,100,47,87,114,105,
- 116,101,32,80,76,88,32,69,50,32,114,101,
- 103,0,0,0,101,32,91,112,111,114,116,93,
- 32,32,84,101,115,116,32,101,116,104,101,114,
- 110,101,116,32,32,32,124,32,32,69,114,32,
- 97,100,100,114,59,32,69,119,32,97,100,100,
- 114,32,118,97,108,59,32,32,82,101,97,100,
- 47,87,114,105,116,101,32,69,69,80,82,79,
- 77,32,114,101,103,0,0,0,116,32,32,32,
- 32,32,32,32,32,32,84,101,115,116,32,116,
- 105,109,101,114,115,32,32,32,32,32,124,32,
- 32,119,91,42,93,32,97,100,100,114,32,118,
- 97,108,32,32,87,114,105,116,101,32,109,101,
- 109,111,114,121,58,32,119,98,32,119,104,44,
- 32,119,119,44,32,119,116,0,109,32,32,32,
- 32,32,32,32,32,32,84,101,115,116,32,109,
- 101,109,111,114,121,32,32,32,32,32,124,32,
- 32,114,91,42,93,32,97,100,100,114,32,32,
- 32,32,32,32,82,101,97,100,32,109,101,109,
- 111,114,121,58,32,114,98,32,114,104,44,32,
- 114,119,44,32,114,116,0,0,42,42,42,32,
- 82,105,103,104,116,83,119,105,116,99,104,32,
- 68,105,97,103,110,111,115,116,105,99,115,32,
- 109,101,110,117,32,42,42,42,0,0,0,0,
- 45,45,45,32,84,104,114,101,101,32,99,111,
- 112,105,101,115,32,111,102,32,97,100,100,114,
- 101,115,115,32,100,111,32,110,111,116,32,97,
- 103,114,101,101,33,10,0,0,45,45,45,32,
- 69,116,104,101,114,32,65,100,100,114,101,115,
- 115,32,78,111,116,32,83,101,116,33,10,0,
- 45,45,45,32,69,116,104,101,114,32,65,100,
- 100,114,101,115,115,32,105,115,32,97,32,109,
- 117,108,116,105,99,97,115,116,32,97,100,100,
- 114,101,115,115,33,10,0,0,42,42,42,32,
- 37,48,50,88,37,48,50,88,37,48,50,88,
- 58,37,48,50,88,58,37,48,50,88,37,48,
- 50,88,10,0,45,45,45,32,70,105,114,115,
- 116,32,98,121,116,101,32,40,37,48,50,88,
- 41,32,105,115,32,97,32,98,114,111,97,100,
- 99,97,115,116,32,97,100,100,114,101,115,115,
- 10,0,0,0,45,45,45,32,76,97,115,116,
- 32,100,105,103,105,116,32,109,117,115,116,32,
- 98,101,32,48,32,111,114,32,56,10,0,0,
- 42,42,42,32,69,105,103,104,116,32,101,116,
- 104,101,114,110,101,116,32,97,100,100,114,101,
- 115,115,101,115,32,104,97,118,101,32,98,101,
- 101,110,32,117,115,101,100,58,10,0,0,0,
- 42,42,42,32,80,111,114,116,32,37,100,32,
- 101,116,104,101,114,110,101,116,32,97,100,100,
- 114,101,115,115,32,105,115,32,0,0,0,0,
- 45,45,45,32,66,97,100,32,101,116,104,101,
- 114,32,97,100,100,114,101,115,115,32,39,37,
- 115,39,32,115,112,101,99,105,102,105,101,100,
- 10,0,0,0,0,0,0,0,244,101,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,244,101,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,64,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,28,111,0,131,104,112,0,131,
- 104,112,0,131,132,111,0,131,152,109,0,131,
- 104,112,0,131,104,112,0,131,244,101,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 24,107,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,76,108,0,131,104,112,0,131,
- 228,108,0,131,112,110,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 28,109,0,131,104,112,0,131,48,111,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 104,112,0,131,104,112,0,131,104,112,0,131,
- 84,109,0,131,104,112,0,131,104,112,0,131,
- 32,112,0,131,136,106,0,131,28,106,0,131,
- 104,112,0,131,104,112,0,131,52,107,0,131,
- 104,112,0,131,104,112,0,131,252,106,0,131,
- 88,111,0,131,104,112,0,131,104,112,0,131,
- 196,107,0,131,104,112,0,131,180,104,0,131,
- 168,106,0,131,92,106,0,131,104,112,0,131,
- 104,112,0,131,148,105,0,131,192,106,0,131,
- 0,0,0,0,188,111,0,131,204,111,0,131,
- 12,112,0,131,12,112,0,131,12,112,0,131,
- 12,112,0,131,12,112,0,131,12,112,0,131,
- 12,112,0,131,12,112,0,131,12,112,0,131,
- 12,112,0,131,252,111,0,131,12,112,0,131,
- 12,112,0,131,12,112,0,131,12,112,0,131,
- 236,111,0,131,12,112,0,131,12,112,0,131,
- 12,112,0,131,12,112,0,131,220,111,0,131,
- 252,111,0,131,0,0,0,0,0,0,0,0,
- 42,42,42,32,69,69,80,82,79,77,32,80,
- 97,115,115,101,100,10,0,0,33,33,33,32,
- 69,69,80,82,79,77,32,70,97,105,108,117,
- 114,101,58,32,87,114,111,116,101,32,37,48,
- 52,120,32,97,116,32,37,100,44,32,103,111,
- 116,32,37,48,52,120,10,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,35,35,35,70,
- 114,97,109,101,32,37,100,32,100,105,100,32,
- 110,111,116,32,97,114,114,105,118,101,10,0,
- 35,35,35,32,70,114,97,109,101,32,37,100,
- 44,32,108,101,110,32,37,100,44,32,98,121,
- 116,101,32,37,100,44,32,119,97,110,116,32,
- 37,120,32,103,111,116,32,37,120,10,0,0,
- 35,35,35,70,114,97,109,101,32,37,100,32,
- 119,114,111,110,103,32,108,101,110,103,116,104,
- 32,40,119,97,110,116,32,37,100,32,103,111,
- 116,32,37,100,41,10,0,0,35,35,35,70,
- 114,97,109,101,32,37,100,58,32,103,111,116,
- 32,115,101,113,32,37,100,10,0,0,0,0,
- 35,35,35,32,37,100,32,67,82,67,32,101,
- 114,114,111,114,115,32,111,99,99,117,114,101,
- 100,10,0,0,35,35,35,32,37,100,32,65,
- 108,105,103,110,32,101,114,114,111,114,115,32,
- 111,99,99,117,114,101,100,10,0,0,0,0,
- 35,35,35,32,37,100,32,83,104,111,114,116,
- 32,101,114,114,111,114,115,32,111,99,99,117,
- 114,101,100,10,0,0,0,0,35,35,35,32,
- 37,100,32,79,118,101,114,114,117,110,32,101,
- 114,114,111,114,115,32,111,99,99,117,114,101,
- 100,10,0,0,35,35,35,32,67,85,32,115,
- 116,105,108,108,32,114,117,110,110,105,110,103,
- 58,32,37,120,10,0,0,0,35,35,35,32,
- 99,109,100,32,115,116,105,108,108,32,98,117,
- 115,121,58,32,37,120,10,0,35,35,35,32,
- 115,116,97,116,117,115,32,115,116,105,108,108,
- 32,98,117,115,121,58,32,37,120,10,0,0,
- 67,66,61,37,120,44,32,84,66,68,61,37,
- 120,44,32,66,85,70,61,37,120,10,0,0,
- 116,101,115,116,95,101,116,104,101,114,46,99,
- 0,0,0,0,37,100,32,102,114,97,109,101,
- 115,32,111,102,32,108,101,110,103,116,104,32,
- 37,100,32,115,101,110,116,32,105,110,32,37,
- 100,32,109,115,101,99,115,10,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 42,42,42,32,56,50,53,52,32,84,105,109,
- 101,114,32,48,32,79,75,44,32,99,111,117,
- 110,116,32,119,97,115,32,37,100,10,0,0,
- 42,42,42,32,56,50,53,52,32,84,105,109,
- 101,114,32,48,32,110,111,116,32,105,110,116,
- 101,114,114,117,112,116,105,110,103,32,37,100,
- 10,0,0,0,42,42,42,32,56,50,53,52,
- 32,84,105,109,101,114,32,48,32,115,112,101,
- 101,100,32,119,114,111,110,103,44,32,103,111,
- 116,32,37,100,32,115,104,111,117,108,100,32,
- 98,101,32,49,48,48,48,10,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 9,37,120,58,32,119,97,110,116,32,37,120,
- 32,103,111,116,32,37,120,10,0,0,0,0,
- 45,45,45,32,82,65,77,32,84,101,115,116,
- 32,111,102,32,37,120,32,116,111,32,37,120,
- 32,102,97,105,108,101,100,10,0,0,0,0,
- 42,42,42,32,82,65,77,32,84,101,115,116,
- 32,111,102,32,37,120,32,116,111,32,37,120,
- 32,112,97,115,115,101,100,10,0,0,0,0,
- 35,35,35,32,68,77,65,32,68,79,78,69,
- 32,110,101,118,101,114,32,111,99,99,117,114,
- 114,101,100,46,32,32,99,115,114,32,61,32,
- 37,120,10,0,35,35,35,32,72,111,115,116,
- 32,110,101,118,101,114,32,103,111,116,32,68,
- 77,65,32,105,110,116,101,114,114,117,112,116,
- 46,32,98,99,95,99,110,116,32,61,32,37,
- 100,10,0,0,35,35,35,32,68,77,65,32,
- 101,114,114,111,114,32,97,116,32,105,110,100,
- 101,120,32,37,100,58,32,119,97,110,116,101,
- 100,32,37,48,50,120,32,103,111,116,32,37,
- 48,50,120,10,0,0,0,0,35,35,35,32,
- 73,108,108,101,103,97,108,32,72,111,115,116,
- 32,97,100,100,114,32,40,61,37,120,41,32,
- 111,114,32,108,101,110,103,116,104,32,40,61,
- 37,100,41,10,0,0,0,0,35,35,35,32,
- 67,111,117,110,116,32,99,97,110,110,111,116,
- 32,98,101,32,62,32,49,48,50,52,42,49,
- 48,50,52,10,0,0,0,0,42,42,42,32,
- 108,99,108,46,66,117,102,49,32,61,32,37,
- 120,32,45,45,62,32,104,111,115,116,46,66,
- 117,102,32,61,32,37,120,32,45,45,62,32,
- 108,99,108,46,66,117,102,50,32,61,32,37,
- 120,10,0,0,42,42,42,32,62,32,68,98,
- 32,37,100,32,40,98,117,114,115,116,41,59,
- 32,62,32,68,119,32,37,100,32,40,119,97,
- 105,116,115,116,97,116,101,115,41,10,0,0,
- 35,35,35,32,83,101,99,111,110,100,32,97,
- 114,103,32,109,117,115,116,32,98,101,32,39,
- 114,39,32,111,114,32,39,119,39,32,111,114,
- 32,39,108,39,10,0,0,0,42,42,42,32,
- 68,77,65,32,37,115,32,105,110,32,37,52,
- 100,32,98,121,116,101,32,99,104,117,110,107,
- 115,58,32,0,32,32,116,111,32,104,111,115,
- 116,0,0,0,102,114,111,109,32,104,111,115,
- 116,0,0,0,37,56,100,32,98,121,116,101,
- 115,47,115,101,99,46,10,0,116,105,109,101,
- 32,116,111,111,32,115,104,111,114,116,32,116,
- 111,32,109,101,97,115,117,114,101,10,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 80,37,100,45,62,37,115,32,10,0,0,0,
- 116,114,97,110,115,109,105,116,32,112,101,110,
- 100,105,110,103,32,111,110,32,37,100,10,0,
- 116,114,97,110,115,109,105,116,32,99,111,110,
- 102,105,103,32,111,110,32,37,100,10,0,0,
- 116,114,97,110,115,109,105,116,32,116,99,110,
- 10,0,0,0,116,99,110,32,101,120,112,10,
- 0,0,0,0,102,111,114,119,97,114,100,95,
- 100,101,108,97,121,32,101,120,112,32,37,100,
- 10,0,0,0,109,101,115,115,97,103,101,95,
- 97,103,101,32,101,120,112,32,37,100,10,0,
- 104,111,108,100,32,101,120,112,32,37,100,10,
- 0,0,0,0,84,120,67,79,78,70,73,71,
- 37,100,10,0,84,120,84,67,78,37,100,10,
- 0,0,0,0,114,99,118,32,99,111,110,102,
- 105,103,32,111,110,32,37,100,10,0,0,0,
- 90,69,82,79,32,114,111,111,116,33,32,97,
- 116,32,37,120,32,0,0,0,115,117,112,101,
- 114,99,101,100,101,115,32,37,100,10,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 65,82,80,82,69,81,32,37,120,33,10,0,
- 65,82,80,82,69,80,32,37,120,33,10,0,
- 83,101,110,100,32,85,68,80,32,37,100,10,
- 0,0,0,0,78,111,32,82,66,68,39,115,
- 32,105,110,32,85,68,80,32,40,37,100,32,
- 37,100,41,10,0,0,0,0,83,101,110,116,
- 32,85,68,80,32,37,100,10,0,0,0,0,
- 83,78,77,80,32,39,37,99,39,32,108,101,
- 110,32,37,100,10,0,0,0,69,110,118,111,
- 121,32,114,99,61,37,100,10,0,0,0,0,
- 71,101,110,32,116,114,97,112,32,37,100,32,
- 114,99,61,37,100,10,0,0,66,97,100,32,
- 85,68,80,32,99,104,101,99,107,115,117,109,
- 32,37,120,32,108,101,110,32,37,100,10,0,
- 66,97,100,32,85,68,80,32,108,101,110,103,
- 116,104,32,119,97,110,116,32,37,100,32,103,
- 111,116,32,37,100,10,0,0,66,97,100,32,
- 73,67,77,80,32,99,104,101,99,107,115,117,
- 109,10,0,0,78,111,32,82,66,68,39,115,
- 32,105,110,32,73,67,77,80,10,0,0,0,
- 66,97,100,32,73,80,32,99,104,101,99,107,
- 115,117,109,10,0,0,0,0,84,114,117,110,
- 99,97,116,101,100,32,73,80,10,0,0,0,
- 83,69,78,84,32,73,80,88,33,10,0,0,
- 110,111,32,115,121,115,78,97,109,101,0,0,
- 114,105,103,104,116,115,119,105,116,99,104,45,
- 0,0,0,0,78,111,32,82,66,68,39,115,
- 32,105,110,32,115,101,110,100,95,115,97,112,
- 10,0,0,0,78,111,32,82,66,68,39,115,
- 32,105,110,32,73,80,88,10,0,0,0,0,
- 84,114,117,110,99,97,116,101,100,32,73,80,
- 88,10,0,0,0,0,0,0,0,0,0,0,
- 77,97,108,108,111,99,32,114,101,116,117,114,
- 110,115,32,78,85,76,76,33,0,0,0,0,
- 0,0,0,0,0,0,0,0,68,105,103,105,
- 32,73,110,116,108,46,32,82,105,103,104,116,
- 83,119,105,116,99,104,32,83,69,45,88,0,
- 73,110,116,101,108,32,56,50,53,57,54,0,
- 0,0,0,0,0,0,0,0,8,206,0,131,
- 36,206,0,131,92,206,0,131,112,206,0,131,
- 132,206,0,131,220,206,0,131,4,207,0,131,
- 4,207,0,131,36,207,0,131,52,207,0,131,
- 80,207,0,131,104,207,0,131,132,207,0,131,
- 160,207,0,131,188,207,0,131,188,207,0,131,
- 216,207,0,131,240,207,0,131,12,208,0,131,
- 40,208,0,131,72,208,0,131,112,208,0,131,
- 180,210,0,131,232,210,0,131,4,211,0,131,
- 36,211,0,131,60,211,0,131,0,0,0,0,
- 64,213,0,131,92,213,0,131,124,213,0,131,
- 160,213,0,131,60,214,0,131,60,214,0,131,
- 60,214,0,131,188,213,0,131,216,213,0,131,
- 244,213,0,131,28,214,0,131,168,214,0,131,
- 60,214,0,131,168,214,0,131,168,214,0,131,
- 88,214,0,131,132,214,0,131,0,0,0,0,
- 36,216,0,131,68,216,0,131,104,216,0,131,
- 140,216,0,131,140,216,0,131,0,0,0,0,
- 248,217,0,131,12,218,0,131,40,218,0,131,
- 76,218,0,131,124,218,0,131,152,218,0,131,
- 200,218,0,131,228,218,0,131,88,219,0,131,
- 116,219,0,131,64,224,0,131,92,224,0,131,
- 124,224,0,131,152,224,0,131,184,224,0,131,
- 0,0,0,0,110,111,32,115,121,115,67,111,
- 110,116,97,99,116,0,0,0,110,111,32,115,
- 121,115,78,97,109,101,0,0,110,111,32,115,
- 121,115,76,111,99,97,116,105,111,110,0,0,
- 37,115,58,37,100,58,32,102,97,105,108,101,
- 100,32,97,115,115,101,114,116,105,111,110,32,
- 96,37,115,39,10,0,0,0,110,117,109,114,
- 101,103,115,32,60,61,32,78,86,82,65,77,
- 95,78,82,69,71,83,32,38,38,32,110,117,
- 109,114,101,103,115,32,62,32,48,0,0,0,
- 102,105,114,115,116,114,101,103,32,60,32,78,
- 86,82,65,77,95,78,82,69,71,83,32,38,
- 38,32,102,105,114,115,116,114,101,103,32,62,
- 61,32,48,0,0,0,0,0,10,13,69,82,
- 82,79,82,32,45,0,0,0,0,0,0,0,
- 192,244,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,192,251,0,131,
- 8,252,0,131,8,252,0,131,200,251,0,131,
- 212,251,0,131,212,251,0,131,212,251,0,131,
- 212,251,0,131,212,251,0,131,212,251,0,131,
- 212,251,0,131,212,251,0,131,212,251,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,200,244,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 212,249,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,20,245,0,131,8,245,0,131,
- 84,247,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 8,252,0,131,8,252,0,131,244,251,0,131,
- 8,252,0,131,8,252,0,131,48,246,0,131,
- 8,252,0,131,8,252,0,131,8,252,0,131,
- 240,250,0,131,8,252,0,131,132,248,0,131,
- 8,252,0,131,8,252,0,131,160,249,0,131,
- 72,46,1,131,228,47,1,131,152,46,1,131,
- 132,47,1,131,0,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,228,47,1,131,
- 228,47,1,131,228,47,1,131,144,47,1,131,
- 108,46,1,131,108,46,1,131,108,46,1,131,
- 152,46,1,131,152,46,1,131,228,47,1,131,
- 108,46,1,131,20,50,1,131,216,50,1,131,
- 56,50,1,131,224,50,1,131,104,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 216,50,1,131,216,50,1,131,216,50,1,131,
- 144,50,1,131,20,50,1,131,20,50,1,131,
- 20,50,1,131,56,50,1,131,56,50,1,131,
- 216,50,1,131,20,50,1,131,124,53,1,131,
- 96,53,1,131,96,53,1,131,96,53,1,131,
- 96,53,1,131,96,53,1,131,96,53,1,131,
- 96,53,1,131,96,53,1,131,96,53,1,131,
- 96,53,1,131,96,53,1,131,96,53,1,131,
- 96,53,1,131,88,53,1,131,64,53,1,131,
- 80,53,1,131,72,53,1,131,64,53,1,131,
- 0,0,0,0,28,83,1,131,36,83,1,131,
- 36,83,1,131,36,83,1,131,36,83,1,131,
- 28,83,1,131,44,83,1,131,44,83,1,131,
- 44,83,1,131,44,83,1,131,44,83,1,131,
- 28,83,1,131,44,83,1,131,0,0,0,0,
- 196,88,1,131,232,88,1,131,208,88,1,131,
- 220,88,1,131,244,88,1,131,0,0,0,0,
- 4,0,0,0,5,0,0,0,6,0,0,0,
- 7,0,0,0,2,0,0,0,3,0,0,0,
- 0,0,0,0,1,0,0,0,72,30,0,131,
- 72,30,0,131,216,44,0,131,0,30,0,131,
- 108,30,0,131,108,30,0,131,108,30,0,131,
- 108,30,0,131,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,20,137,1,131,
- 204,136,1,131,132,136,1,131,56,136,1,131,
- 236,135,1,131,172,135,1,131,120,135,1,131,
- 52,135,1,131,232,134,1,131,160,134,1,131,
- 80,134,1,131,8,134,1,131,188,133,1,131,
- 120,133,1,131,0,0,0,0,0,0,0,0,
- 72,72,72,72,72,72,72,72,72,72,72,72,
- 72,72,72,72,72,72,72,72,72,72,72,72,
- 72,72,72,72,72,72,72,72,72,72,72,72,
- 72,72,72,72,72,72,72,72,72,72,72,72,
- 72,72,72,72,72,72,72,72,72,72,72,72,
- 72,72,72,72,72,72,72,72,72,72,72,72,
- 72,72,72,72,72,0,0,0,0,255,85,170,
- 0,0,0,0,4,0,8,0,16,0,32,0,
- 64,0,0,1,0,8,0,0,0,0,0,0,
- 0,0,0,0,0,4,3,2,1,0,0,0,
- 7,0,0,0,1,0,1,0,1,0,2,0,
- 20,0,15,0,1,0,0,128,128,0,0,0,
- 100,0,0,0,96,207,1,131,92,207,1,131,
- 88,207,1,131,84,207,1,131,80,207,1,131,
- 0,0,0,0,0,0,0,0,48,49,50,51,
- 52,53,54,55,56,57,65,66,67,68,69,70,
- 0,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,64,204,0,131,156,202,0,131,
- 96,148,1,131,1,0,4,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 200,155,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,124,204,0,131,156,202,0,131,
- 168,210,1,131,1,0,6,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 4,156,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,132,204,0,131,156,202,0,131,
- 4,1,0,163,1,0,67,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 64,156,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,168,204,0,131,248,204,0,131,
- 80,18,3,131,1,0,4,3,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 124,156,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,168,204,0,131,32,205,0,131,
- 96,18,3,131,1,0,4,3,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 184,156,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,168,204,0,131,72,205,0,131,
- 112,18,3,131,1,0,4,3,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 244,156,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,112,205,0,131,156,202,0,131,
- 2,0,0,0,1,0,2,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 48,157,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,0,0,
- 220,155,1,131,2,0,0,0,24,156,1,131,
- 3,0,0,0,84,156,1,131,4,0,0,0,
- 144,156,1,131,5,0,0,0,204,156,1,131,
- 6,0,0,0,8,157,1,131,7,0,0,0,
- 68,157,1,131,0,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,120,205,0,131,
- 156,202,0,131,48,211,1,131,1,0,2,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,172,157,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,4,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 124,148,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,6,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,220,5,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,66,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,4,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,3,180,208,0,131,132,205,0,131,
- 228,209,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,67,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,180,208,0,131,
- 132,205,0,131,164,202,0,131,76,209,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,66,1,
- 180,208,0,131,132,205,0,131,164,202,0,131,
- 76,209,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,6,1,180,208,0,131,132,205,0,131,
- 164,202,0,131,76,209,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,0,0,232,157,1,131,
- 2,0,0,0,16,158,1,131,3,0,0,0,
- 56,158,1,131,4,0,0,0,96,158,1,131,
- 5,0,0,0,136,158,1,131,6,0,0,0,
- 176,158,1,131,7,0,0,0,216,158,1,131,
- 8,0,0,0,0,159,1,131,9,0,0,0,
- 40,159,1,131,10,0,0,0,80,159,1,131,
- 11,0,0,0,120,159,1,131,12,0,0,0,
- 160,159,1,131,13,0,0,0,200,159,1,131,
- 14,0,0,0,240,159,1,131,15,0,0,0,
- 24,160,1,131,16,0,0,0,64,160,1,131,
- 17,0,0,0,104,160,1,131,18,0,0,0,
- 144,160,1,131,19,0,0,0,184,160,1,131,
- 20,0,0,0,224,160,1,131,21,0,0,0,
- 8,161,1,131,22,0,0,0,48,161,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 32,208,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,192,157,1,131,2,0,0,0,
- 40,208,1,131,0,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,112,205,0,131,
- 60,210,0,131,2,0,0,0,1,0,2,3,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,56,162,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,120,205,0,131,
- 60,210,0,131,0,17,3,131,1,0,2,3,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,116,162,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,4,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,176,162,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,8,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,236,162,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,12,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,40,163,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,16,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,100,163,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,20,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,160,163,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,24,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,220,163,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,28,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,24,164,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,32,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,84,164,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,36,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,144,164,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,40,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,204,164,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,120,205,0,131,
- 156,202,0,131,44,17,3,131,1,0,2,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,8,165,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,48,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,68,165,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,52,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,128,165,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,56,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,188,165,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,60,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,248,165,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,64,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,52,166,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,68,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,112,166,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,64,1,44,202,0,131,88,210,0,131,
- 164,202,0,131,120,211,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,44,202,0,131,
- 88,210,0,131,164,202,0,131,120,211,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,64,1,
- 44,202,0,131,88,210,0,131,164,202,0,131,
- 120,211,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,44,202,0,131,88,210,0,131,
- 164,202,0,131,120,211,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,44,202,0,131,
- 88,210,0,131,164,202,0,131,120,211,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,0,0,
- 172,166,1,131,2,0,0,0,212,166,1,131,
- 3,0,0,0,252,166,1,131,4,0,0,0,
- 36,167,1,131,5,0,0,0,76,167,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 56,208,1,131,0,0,0,0,0,0,0,0,
- 1,0,64,3,84,212,0,131,16,212,0,131,
- 52,212,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,3,84,212,0,131,
- 16,212,0,131,52,212,0,131,172,212,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,3,
- 84,212,0,131,16,212,0,131,52,212,0,131,
- 172,212,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,3,84,212,0,131,16,212,0,131,
- 52,212,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,3,84,212,0,131,
- 16,212,0,131,52,212,0,131,172,212,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,3,
- 84,212,0,131,16,212,0,131,52,212,0,131,
- 172,212,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,64,3,84,212,0,131,16,212,0,131,
- 52,212,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,3,84,212,0,131,
- 16,212,0,131,52,212,0,131,172,212,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,1,
- 84,212,0,131,16,212,0,131,164,202,0,131,
- 172,212,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,3,84,212,0,131,16,212,0,131,
- 52,212,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,64,3,84,212,0,131,
- 16,212,0,131,52,212,0,131,172,212,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,3,
- 84,212,0,131,16,212,0,131,52,212,0,131,
- 172,212,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,6,1,84,212,0,131,16,212,0,131,
- 164,202,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,0,0,180,167,1,131,
- 2,0,0,0,220,167,1,131,3,0,0,0,
- 4,168,1,131,4,0,0,0,44,168,1,131,
- 5,0,0,0,84,168,1,131,6,0,0,0,
- 124,168,1,131,7,0,0,0,164,168,1,131,
- 8,0,0,0,204,168,1,131,9,0,0,0,
- 244,168,1,131,10,0,0,0,28,169,1,131,
- 11,0,0,0,68,169,1,131,12,0,0,0,
- 108,169,1,131,13,0,0,0,148,169,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 72,208,1,131,0,0,0,0,0,0,0,0,
- 1,0,2,3,84,212,0,131,16,212,0,131,
- 52,212,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,4,3,84,212,0,131,
- 16,212,0,131,52,212,0,131,172,212,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,64,3,
- 84,212,0,131,16,212,0,131,52,212,0,131,
- 172,212,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,3,84,212,0,131,16,212,0,131,
- 52,212,0,131,172,212,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,0,0,60,170,1,131,
- 2,0,0,0,100,170,1,131,3,0,0,0,
- 140,170,1,131,4,0,0,0,180,170,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 88,208,1,131,0,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,72,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,20,171,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,0,0,76,162,1,131,2,0,0,0,
- 136,162,1,131,3,0,0,0,196,162,1,131,
- 4,0,0,0,0,163,1,131,5,0,0,0,
- 60,163,1,131,6,0,0,0,120,163,1,131,
- 7,0,0,0,180,163,1,131,8,0,0,0,
- 240,163,1,131,9,0,0,0,44,164,1,131,
- 10,0,0,0,104,164,1,131,11,0,0,0,
- 164,164,1,131,12,0,0,0,224,164,1,131,
- 13,0,0,0,28,165,1,131,14,0,0,0,
- 88,165,1,131,15,0,0,0,148,165,1,131,
- 16,0,0,0,208,165,1,131,17,0,0,0,
- 12,166,1,131,18,0,0,0,72,166,1,131,
- 19,0,0,0,132,166,1,131,20,0,0,0,
- 64,208,1,131,21,0,0,0,80,208,1,131,
- 22,0,0,0,96,208,1,131,23,0,0,0,
- 40,171,1,131,0,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,144,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,16,172,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,148,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,76,172,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,152,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,136,172,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,156,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,196,172,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,160,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,0,173,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,164,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,60,173,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,168,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,120,173,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,172,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,180,173,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,176,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,240,173,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,180,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,44,174,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,184,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,104,174,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,188,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,164,174,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,192,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,224,174,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,196,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,28,175,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,200,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,88,175,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,204,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,148,175,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,208,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,208,175,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,212,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,12,176,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,216,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,72,176,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,220,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,132,176,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,224,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,192,176,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,228,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,252,176,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,232,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,56,177,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,236,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,116,177,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,240,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,176,177,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,244,16,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,236,177,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,0,0,36,172,1,131,2,0,0,0,
- 96,172,1,131,3,0,0,0,156,172,1,131,
- 4,0,0,0,216,172,1,131,5,0,0,0,
- 20,173,1,131,6,0,0,0,80,173,1,131,
- 7,0,0,0,140,173,1,131,8,0,0,0,
- 200,173,1,131,9,0,0,0,4,174,1,131,
- 10,0,0,0,64,174,1,131,11,0,0,0,
- 124,174,1,131,12,0,0,0,184,174,1,131,
- 13,0,0,0,244,174,1,131,14,0,0,0,
- 48,175,1,131,15,0,0,0,108,175,1,131,
- 16,0,0,0,168,175,1,131,17,0,0,0,
- 228,175,1,131,18,0,0,0,32,176,1,131,
- 19,0,0,0,92,176,1,131,20,0,0,0,
- 152,176,1,131,21,0,0,0,212,176,1,131,
- 22,0,0,0,16,177,1,131,23,0,0,0,
- 76,177,1,131,24,0,0,0,136,177,1,131,
- 25,0,0,0,196,177,1,131,26,0,0,0,
- 0,178,1,131,0,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,112,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,0,179,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,116,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,60,179,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,120,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,120,179,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,76,210,0,131,
- 156,202,0,131,124,17,3,131,1,0,65,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,180,179,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,200,212,0,131,
- 156,202,0,131,220,5,0,163,1,0,64,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,240,179,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,112,205,0,131,
- 156,202,0,131,161,0,0,0,1,0,2,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,44,180,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,0,0,4,180,1,131,2,0,0,0,
- 64,180,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,120,208,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,20,179,1,131,
- 2,0,0,0,80,179,1,131,3,0,0,0,
- 140,179,1,131,4,0,0,0,200,179,1,131,
- 5,0,0,0,128,208,1,131,0,0,0,0,
- 0,0,0,0,1,0,2,1,44,202,0,131,
- 208,212,0,131,164,202,0,131,196,214,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 44,202,0,131,208,212,0,131,164,202,0,131,
- 196,214,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,44,202,0,131,208,212,0,131,
- 164,202,0,131,196,214,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,44,202,0,131,
- 208,212,0,131,164,202,0,131,196,214,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 44,202,0,131,208,212,0,131,164,202,0,131,
- 196,214,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,44,202,0,131,208,212,0,131,
- 164,202,0,131,196,214,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,44,202,0,131,
- 208,212,0,131,164,202,0,131,196,214,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 44,202,0,131,208,212,0,131,164,202,0,131,
- 196,214,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,44,202,0,131,208,212,0,131,
- 164,202,0,131,196,214,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,44,202,0,131,
- 208,212,0,131,164,202,0,131,196,214,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 44,202,0,131,208,212,0,131,164,202,0,131,
- 196,214,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,44,202,0,131,208,212,0,131,
- 164,202,0,131,196,214,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,44,202,0,131,
- 208,212,0,131,164,202,0,131,196,214,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,6,1,
- 44,202,0,131,208,212,0,131,164,202,0,131,
- 196,214,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,0,0,192,180,1,131,2,0,0,0,
- 232,180,1,131,3,0,0,0,16,181,1,131,
- 4,0,0,0,56,181,1,131,5,0,0,0,
- 96,181,1,131,6,0,0,0,136,181,1,131,
- 7,0,0,0,176,181,1,131,8,0,0,0,
- 216,181,1,131,9,0,0,0,0,182,1,131,
- 10,0,0,0,40,182,1,131,11,0,0,0,
- 80,182,1,131,13,0,0,0,120,182,1,131,
- 16,0,0,0,160,182,1,131,17,0,0,0,
- 200,182,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,144,208,1,131,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 160,208,1,131,2,0,0,0,168,208,1,131,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,184,208,1,131,2,0,0,0,
- 192,208,1,131,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,208,208,1,131,2,0,0,0,
- 216,208,1,131,3,0,0,0,224,208,1,131,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,240,208,1,131,2,0,0,0,
- 248,208,1,131,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 8,209,1,131,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,0,0,0,24,209,1,131,
- 2,0,0,0,32,209,1,131,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,48,209,1,131,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,64,209,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,232,208,1,131,
- 2,0,0,0,0,209,1,131,3,0,0,0,
- 16,209,1,131,4,0,0,0,40,209,1,131,
- 5,0,0,0,56,209,1,131,6,0,0,0,
- 72,209,1,131,0,0,0,0,0,0,0,0,
- 2,0,0,0,152,208,1,131,6,0,0,0,
- 176,208,1,131,7,0,0,0,200,208,1,131,
- 8,0,0,0,80,209,1,131,0,0,0,0,
- 0,0,0,0,7,0,0,0,88,209,1,131,
- 0,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 128,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 8,185,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 144,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 68,185,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 148,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 128,185,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 132,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 188,185,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 136,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 248,185,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 140,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 52,186,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 156,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 112,186,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 160,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 172,186,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 164,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 232,186,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 168,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 36,187,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 172,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 96,187,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 176,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 156,187,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 180,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 216,187,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 184,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 20,188,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 188,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 80,188,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 192,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 140,188,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 196,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 200,188,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 200,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 4,189,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 204,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 64,189,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 208,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 124,189,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 212,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 184,189,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 220,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 244,189,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 224,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 48,190,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 228,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 108,190,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 232,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 168,190,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 236,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 228,190,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,92,215,0,131,156,202,0,131,
- 240,17,3,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 32,191,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,104,215,0,131,140,215,0,131,
- 0,0,0,0,1,0,2,3,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 92,191,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,0,0,
- 28,185,1,131,2,0,0,0,88,185,1,131,
- 3,0,0,0,148,185,1,131,4,0,0,0,
- 208,185,1,131,5,0,0,0,12,186,1,131,
- 6,0,0,0,72,186,1,131,8,0,0,0,
- 132,186,1,131,9,0,0,0,192,186,1,131,
- 10,0,0,0,252,186,1,131,11,0,0,0,
- 56,187,1,131,12,0,0,0,116,187,1,131,
- 13,0,0,0,176,187,1,131,14,0,0,0,
- 236,187,1,131,15,0,0,0,40,188,1,131,
- 16,0,0,0,100,188,1,131,17,0,0,0,
- 160,188,1,131,18,0,0,0,220,188,1,131,
- 19,0,0,0,24,189,1,131,20,0,0,0,
- 84,189,1,131,21,0,0,0,144,189,1,131,
- 22,0,0,0,204,189,1,131,24,0,0,0,
- 8,190,1,131,25,0,0,0,68,190,1,131,
- 26,0,0,0,128,190,1,131,27,0,0,0,
- 188,190,1,131,28,0,0,0,248,190,1,131,
- 29,0,0,0,52,191,1,131,30,0,0,0,
- 112,191,1,131,0,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,180,215,0,131,
- 156,202,0,131,218,12,3,131,1,0,4,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,128,192,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,120,205,0,131,
- 156,202,0,131,40,211,1,131,1,0,2,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,188,192,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 8,202,0,131,148,38,1,131,112,205,0,131,
- 156,202,0,131,2,0,0,0,1,0,2,1,
- 32,45,1,131,208,48,1,131,160,49,1,131,
- 20,48,1,131,248,192,1,131,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,44,202,0,131,200,215,0,131,
- 164,202,0,131,196,216,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,44,202,0,131,
- 200,215,0,131,164,202,0,131,196,216,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,6,1,
- 44,202,0,131,200,215,0,131,164,202,0,131,
- 196,216,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,44,202,0,131,200,215,0,131,
- 164,202,0,131,196,216,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,44,202,0,131,
- 200,215,0,131,164,202,0,131,196,216,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,0,0,
- 52,193,1,131,2,0,0,0,92,193,1,131,
- 3,0,0,0,132,193,1,131,4,0,0,0,
- 172,193,1,131,5,0,0,0,212,193,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 112,209,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,148,192,1,131,2,0,0,0,
- 208,192,1,131,3,0,0,0,12,193,1,131,
- 4,0,0,0,120,209,1,131,0,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 112,205,0,131,156,202,0,131,3,0,0,0,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,100,194,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,60,210,0,131,216,12,3,131,
- 1,0,2,3,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,160,194,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 104,217,0,131,156,202,0,131,0,0,0,0,
- 1,0,67,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,220,194,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 104,217,0,131,156,202,0,131,0,0,0,0,
- 1,0,65,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,24,195,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 112,217,0,131,156,202,0,131,216,12,3,131,
- 1,0,4,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,84,195,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 120,205,0,131,156,202,0,131,224,12,3,131,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,144,195,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 120,205,0,131,156,202,0,131,228,12,3,131,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,204,195,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,156,202,0,131,232,12,3,131,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,8,196,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,156,202,0,131,234,12,3,131,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,68,196,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,156,202,0,131,246,12,3,131,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,128,196,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,156,202,0,131,236,12,3,131,
- 1,0,2,1,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,188,196,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,60,210,0,131,238,12,3,131,
- 1,0,2,3,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,248,196,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,60,210,0,131,240,12,3,131,
- 1,0,2,3,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,52,197,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,8,202,0,131,148,38,1,131,
- 92,217,0,131,60,210,0,131,242,12,3,131,
- 1,0,2,3,32,45,1,131,208,48,1,131,
- 160,49,1,131,20,48,1,131,112,197,1,131,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,180,219,0,131,
- 132,217,0,131,164,202,0,131,104,220,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,3,
- 180,219,0,131,132,217,0,131,0,221,0,131,
- 104,220,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,180,219,0,131,132,217,0,131,
- 164,202,0,131,104,220,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,3,180,219,0,131,
- 132,217,0,131,0,221,0,131,104,220,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,2,3,
- 180,219,0,131,132,217,0,131,0,221,0,131,
- 104,220,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,4,1,180,219,0,131,132,217,0,131,
- 164,202,0,131,104,220,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,180,219,0,131,
- 132,217,0,131,164,202,0,131,104,220,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,4,1,
- 180,219,0,131,132,217,0,131,164,202,0,131,
- 104,220,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,4,1,180,219,0,131,132,217,0,131,
- 164,202,0,131,104,220,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,180,219,0,131,
- 132,217,0,131,164,202,0,131,104,220,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,0,0,
- 172,197,1,131,2,0,0,0,212,197,1,131,
- 3,0,0,0,252,197,1,131,4,0,0,0,
- 36,198,1,131,5,0,0,0,76,198,1,131,
- 6,0,0,0,116,198,1,131,7,0,0,0,
- 156,198,1,131,8,0,0,0,196,198,1,131,
- 9,0,0,0,236,198,1,131,10,0,0,0,
- 20,199,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,136,209,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,120,194,1,131,
- 2,0,0,0,180,194,1,131,3,0,0,0,
- 240,194,1,131,4,0,0,0,44,195,1,131,
- 5,0,0,0,104,195,1,131,6,0,0,0,
- 164,195,1,131,7,0,0,0,224,195,1,131,
- 8,0,0,0,28,196,1,131,9,0,0,0,
- 88,196,1,131,10,0,0,0,148,196,1,131,
- 11,0,0,0,208,196,1,131,12,0,0,0,
- 12,197,1,131,13,0,0,0,72,197,1,131,
- 14,0,0,0,132,197,1,131,15,0,0,0,
- 144,209,1,131,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,76,210,0,131,156,202,0,131,
- 160,211,1,131,1,0,65,1,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 44,200,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,8,202,0,131,
- 148,38,1,131,120,205,0,131,60,210,0,131,
- 140,1,0,163,1,0,2,3,32,45,1,131,
- 208,48,1,131,160,49,1,131,20,48,1,131,
- 104,200,1,131,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,4,1,
- 44,202,0,131,36,222,0,131,164,202,0,131,
- 48,223,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,44,202,0,131,36,222,0,131,
- 164,202,0,131,48,223,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,2,1,44,202,0,131,
- 36,222,0,131,164,202,0,131,48,223,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,0,0,
- 164,200,1,131,2,0,0,0,204,200,1,131,
- 3,0,0,0,244,200,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,168,209,1,131,
- 0,0,0,0,0,0,0,0,1,0,2,1,
- 44,202,0,131,212,223,0,131,164,202,0,131,
- 252,224,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,2,1,44,202,0,131,212,223,0,131,
- 164,202,0,131,252,224,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,65,1,44,202,0,131,
- 212,223,0,131,164,202,0,131,252,224,0,131,
- 0,0,0,0,0,0,0,0,255,0,0,0,
- 255,0,0,0,0,0,0,0,1,0,65,1,
- 44,202,0,131,212,223,0,131,164,202,0,131,
- 252,224,0,131,0,0,0,0,0,0,0,0,
- 255,0,0,0,255,0,0,0,0,0,0,0,
- 1,0,65,1,44,202,0,131,212,223,0,131,
- 164,202,0,131,252,224,0,131,0,0,0,0,
- 0,0,0,0,255,0,0,0,255,0,0,0,
- 0,0,0,0,1,0,0,0,76,201,1,131,
- 2,0,0,0,116,201,1,131,3,0,0,0,
- 156,201,1,131,4,0,0,0,196,201,1,131,
- 5,0,0,0,236,201,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,184,209,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 64,200,1,131,2,0,0,0,124,200,1,131,
- 3,0,0,0,176,209,1,131,4,0,0,0,
- 192,209,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,128,209,1,131,2,0,0,0,
- 152,209,1,131,3,0,0,0,160,209,1,131,
- 4,0,0,0,200,209,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,24,208,1,131,
- 2,0,0,0,48,208,1,131,4,0,0,0,
- 104,208,1,131,5,0,0,0,112,208,1,131,
- 7,0,0,0,136,208,1,131,10,0,0,0,
- 96,209,1,131,11,0,0,0,104,209,1,131,
- 17,0,0,0,208,209,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,216,209,1,131,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,240,209,1,131,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,1,0,0,0,8,210,1,131,
- 2,0,0,0,16,210,1,131,3,0,0,0,
- 24,210,1,131,4,0,0,0,32,210,1,131,
- 5,0,0,0,40,210,1,131,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 56,210,1,131,2,0,0,0,64,210,1,131,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 72,210,1,131,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 48,210,1,131,2,0,0,0,80,210,1,131,
- 3,0,0,0,88,210,1,131,0,0,0,0,
- 0,0,0,0,1,0,0,0,16,208,1,131,
- 2,0,0,0,224,209,1,131,3,0,0,0,
- 232,209,1,131,4,0,0,0,248,209,1,131,
- 5,0,0,0,0,210,1,131,6,0,0,0,
- 96,210,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,104,210,1,131,0,0,0,0,
- 0,0,0,0,6,0,0,0,112,210,1,131,
- 0,0,0,0,0,0,0,0,3,0,0,0,
- 120,210,1,131,0,0,0,0,0,0,0,0,
- 1,0,0,0,128,210,1,131,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,3,0,0,0,6,0,0,0,
- 1,0,0,0,2,0,0,0,1,0,0,0,
- 10,0,0,0,7,0,0,0,8,0,0,0,
- 2,0,0,0,2,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,112,117,98,108,
- 105,99,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,112,114,105,118,97,116,101,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 83,78,77,80,95,116,114,97,112,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 3,0,0,0,6,0,0,0,1,0,0,0,
- 4,0,0,0,1,0,0,0,76,1,0,0,
- 5,0,0,0,1,0,0,0,1,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 3,0,0,0,6,0,0,0,1,0,0,0,
- 2,0,0,0,1,0,0,0,2,0,0,0,
- 2,0,0,0,1,0,0,0,1,0,0,0,
- 0,0,0,0,1,0,0,0,3,0,0,0,
- 6,0,0,0,1,0,0,0,2,0,0,0,
- 1,0,0,0,17,0,0,0,0,0,0,0,
- 0,0,0,0,48,49,50,51,52,53,54,55,
- 56,57,65,66,67,68,69,70,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 255,85,170,0,255,255,255,255,85,85,85,85,
- 170,170,170,170,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,64,40,35,41,
- 32,67,111,112,121,114,105,103,104,116,32,40,
- 99,41,32,49,57,56,54,32,45,32,49,57,
- 57,53,32,32,69,112,105,108,111,103,117,101,
- 32,84,101,99,104,110,111,108,111,103,121,32,
- 67,111,114,112,111,114,97,116,105,111,110,10,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,255,255,255,255,
- 72,10,0,0,78,10,0,0,83,10,0,0,
- 69,10,0,0,109,97,105,110,46,99,0,0,
- 48,0,0,0,55,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 0,0,0,0,116,105,109,101,114,46,99,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 100,0,0,0,100,0,0,0,1,0,0,0,
- 0,0,0,0,115,114,99,32,0,0,0,0,
- 32,0,0,0,100,115,116,32,0,0,0,0,
- 32,37,48,50,88,0,0,0,10,0,0,0,
- 255,255,255,255,48,48,48,48,48,48,0,0,
- 48,48,48,48,48,49,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,255,255,255,255,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 62,32,0,0,37,120,10,0,37,120,58,9,
- 37,120,10,0,37,115,10,0,0,0,0,0,
- 10,0,0,0,0,0,0,0,0,0,0,0,
- 68,85,77,80,10,0,0,0,37,48,50,120,
- 32,0,0,0,10,0,0,0,0,0,0,0,
- 37,100,32,112,112,115,10,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 1,0,0,0,0,0,0,0,1,0,0,0,
- 119,119,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,128,194,0,
- 0,0,0,0,1,128,194,0,0,16,0,0,
- 66,76,75,0,70,87,68,0,76,82,78,0,
- 76,73,83,0,68,73,83,0,72,69,76,76,
- 79,10,0,0,116,99,32,101,120,112,10,0,
- 102,114,111,109,32,0,0,0,10,0,0,0,
- 87,101,105,114,100,0,0,0,0,0,0,0,
- 0,0,0,0,255,255,255,255,255,255,255,255,
- 255,255,0,0,255,255,255,255,255,255,0,0,
- 0,0,0,0,0,0,0,0,80,65,68,37,
- 100,10,0,0,170,170,3,0,0,0,0,0,
- 83,69,78,84,33,10,0,0,85,68,80,10,
- 0,0,0,0,73,67,77,80,10,0,0,0,
- 69,67,72,79,10,0,0,0,73,80,10,0,
- 170,170,3,0,0,0,0,0,73,80,88,33,
- 10,0,0,0,0,0,0,0,255,255,255,255,
- 255,255,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,192,155,1,131,0,0,0,0,
- 108,157,1,131,0,0,0,0,88,161,1,131,
- 0,0,0,0,16,162,1,131,0,0,0,0,
- 32,162,1,131,0,0,0,0,116,167,1,131,
- 0,0,0,0,164,167,1,131,0,0,0,0,
- 188,169,1,131,0,0,0,0,44,170,1,131,
- 0,0,0,0,220,170,1,131,0,0,0,0,
- 4,171,1,131,0,0,0,0,80,171,1,131,
- 0,0,0,0,40,178,1,131,0,0,0,0,
- 104,180,1,131,0,0,0,0,128,180,1,131,
- 0,0,0,0,144,180,1,131,0,0,0,0,
- 240,182,1,131,0,0,0,0,104,183,1,131,
- 0,0,0,0,120,183,1,131,0,0,0,0,
- 128,183,1,131,0,0,0,0,136,183,1,131,
- 0,0,0,0,160,183,1,131,0,0,0,0,
- 168,183,1,131,0,0,0,0,176,183,1,131,
- 0,0,0,0,200,183,1,131,0,0,0,0,
- 208,183,1,131,0,0,0,0,216,183,1,131,
- 0,0,0,0,224,183,1,131,0,0,0,0,
- 0,184,1,131,0,0,0,0,8,184,1,131,
- 0,0,0,0,16,184,1,131,0,0,0,0,
- 40,184,1,131,0,0,0,0,48,184,1,131,
- 0,0,0,0,64,184,1,131,0,0,0,0,
- 72,184,1,131,0,0,0,0,80,184,1,131,
- 0,0,0,0,104,184,1,131,0,0,0,0,
- 112,184,1,131,0,0,0,0,128,184,1,131,
- 0,0,0,0,136,184,1,131,0,0,0,0,
- 152,184,1,131,0,0,0,0,208,184,1,131,
- 0,0,0,0,248,184,1,131,0,0,0,0,
- 152,191,1,131,0,0,0,0,252,193,1,131,
- 0,0,0,0,44,194,1,131,0,0,0,0,
- 60,194,1,131,0,0,0,0,60,199,1,131,
- 0,0,0,0,148,199,1,131,0,0,0,0,
- 164,199,1,131,0,0,0,0,36,200,1,131,
- 0,0,0,0,28,201,1,131,0,0,0,0,
- 60,201,1,131,0,0,0,0,20,202,1,131,
- 0,0,0,0,68,202,1,131,0,0,0,0,
- 84,202,1,131,0,0,0,0,124,202,1,131,
- 0,0,0,0,164,202,1,131,0,0,0,0,
- 236,202,1,131,0,0,0,0,252,202,1,131,
- 0,0,0,0,4,203,1,131,0,0,0,0,
- 12,203,1,131,0,0,0,0,28,203,1,131,
- 0,0,0,0,36,203,1,131,0,0,0,0,
- 44,203,1,131,0,0,0,0,52,203,1,131,
- 0,0,0,0,60,203,1,131,0,0,0,0,
- 68,203,1,131,0,0,0,0,76,203,1,131,
- 0,0,0,0,124,203,1,131,0,0,0,0,
- 132,203,1,131,0,0,0,0,140,203,1,131,
- 0,0,0,0,164,203,1,131,0,0,0,0,
- 180,203,1,131,0,0,0,0,188,203,1,131,
- 0,0,0,0,220,203,1,131,0,0,0,0,
- 20,204,1,131,0,0,0,0,36,204,1,131,
- 0,0,0,0,52,204,1,131,0,0,0,0,
- 68,204,1,131,255,255,255,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,
- 10,0,0,0,10,0,0,0,0,205,1,131,
- 10,0,0,0,7,0,0,0,0,0,0,0,
- 0,0,0,0,255,255,255,255,110,118,114,97,
- 109,46,99,0,114,99,0,0,48,120,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0
- } ;
-static const int dgrs_ncode = 119520 ;
diff --git a/drivers/net/dgrs_i82596.h b/drivers/net/dgrs_i82596.h
deleted file mode 100644
index ac9217ad213..00000000000
--- a/drivers/net/dgrs_i82596.h
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * i82596 ethernet controller bits and structures (little endian)
- *
- * $Id: i82596.h,v 1.8 1996/09/03 11:19:03 rick Exp $
- */
-
-/************************************************************************/
-/* */
-/* PORT commands (p. 4-20). The least significant nibble is one */
-/* of these commands, the rest of the command is a memory address */
-/* aligned on a 16 byte boundary. Note that port commands must */
-/* be written to the PORT address and the PORT address+2 with two */
-/* halfword writes. Write the LSH first to PORT, then the MSH to */
-/* PORT+2. Blame Intel. */
-/* */
-/************************************************************************/
-#define I596_PORT_RESET 0x0 /* Reset. Wait 5 SysClks & 10 TxClks */
-#define I596_PORT_SELFTEST 0x1 /* Do a selftest */
-#define I596_PORT_SCP_ADDR 0x2 /* Set new SCP address */
-#define I596_PORT_DUMP 0x3 /* Dump internal data structures */
-
-/*
- * I596_ST: Selftest results (p. 4-21)
- */
-typedef volatile struct
-{
- ulong signature; /* ROM checksum */
- ulong result; /* Selftest results: non-zero is a failure */
-} I596_ST;
-
-#define I596_ST_SELFTEST_FAIL 0x1000 /* Selftest Failed */
-#define I596_ST_DIAGNOSE_FAIL 0x0020 /* Diagnose Failed */
-#define I596_ST_BUSTIMER_FAIL 0x0010 /* Bus Timer Failed */
-#define I596_ST_REGISTER_FAIL 0x0008 /* Register Failed */
-#define I596_ST_ROM_FAIL 0x0004 /* ROM Failed */
-
-/*
- * I596_DUMP: Dump results
- */
-typedef volatile struct
-{
- ulong dump[77];
-} I596_DUMP;
-
-/************************************************************************/
-/* */
-/* I596_TBD: Transmit Buffer Descriptor (p. 4-59) */
-/* */
-/************************************************************************/
-typedef volatile struct _I596_TBD
-{
- ulong count;
- vol struct _I596_TBD *next;
- uchar *buf;
- ushort unused1;
- ushort unused2;
-} I596_TBD;
-
-#define I596_TBD_NOLINK ((I596_TBD *) 0xffffffff)
-#define I596_TBD_EOF 0x8000
-#define I596_TBD_COUNT_MASK 0x3fff
-
-/************************************************************************/
-/* */
-/* I596_TFD: Transmit Frame Descriptor (p. 4-56) */
-/* a.k.a. I596_CB_XMIT */
-/* */
-/************************************************************************/
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
- I596_TBD *tbdp;
- ulong count; /* for speed */
-
- /* Application defined data follows structure... */
-
-#if 0 /* We don't use these intel defined ones */
- uchar addr[6];
- ushort len;
- uchar data[1];
-#else
- ulong dstchan;/* Used by multi-NIC mode */
-#endif
-} I596_TFD;
-
-#define I596_TFD_NOCRC 0x0010 /* cmd: No CRC insertion */
-#define I596_TFD_FLEX 0x0008 /* cmd: Flexible mode */
-
-/************************************************************************/
-/* */
-/* I596_RBD: Receive Buffer Descriptor (p. 4-84) */
-/* */
-/************************************************************************/
-typedef volatile struct _I596_RBD
-{
-#ifdef INTEL_RETENTIVE
- ushort count; /* Length of data in buf */
- ushort offset;
-#else
- ulong count; /* Length of data in buf */
-#endif
- vol struct _I596_RBD *next; /* Next buffer descriptor in list */
- uchar *buf; /* Data buffer */
-#ifdef INTEL_RETENTIVE
- ushort size; /* Size of buf (constant) */
- ushort zero;
-#else
- ulong size; /* Size of buf (constant) */
-#endif
-
- /* Application defined data follows structure... */
-
- uchar chan;
- uchar refcnt;
- ushort len;
-} I596_RBD;
-
-#define I596_RBD_NOLINK ((I596_RBD *) 0xffffffff)
-#define I596_RBD_EOF 0x8000 /* This is last buffer in a frame */
-#define I596_RBD_F 0x4000 /* The actual count is valid */
-
-#define I596_RBD_EL 0x8000 /* Last buffer in list */
-
-/************************************************************************/
-/* */
-/* I596_RFD: Receive Frame Descriptor (p. 4-79) */
-/* */
-/************************************************************************/
-typedef volatile struct _I596_RFD
-{
- ushort status;
- ushort cmd;
- vol struct _I596_RFD *next;
- vol struct _I596_RBD *rbdp;
- ushort count; /* Len of data in RFD: always 0 */
- ushort size; /* Size of RFD buffer: always 0 */
-
- /* Application defined data follows structure... */
-
-# if 0 /* We don't use these intel defined ones */
- uchar addr[6];
- ushort len;
- uchar data[1];
-# else
- ulong dstchan;/* Used by multi-nic mode */
-# endif
-} I596_RFD;
-
-#define I596_RFD_C 0x8000 /* status: frame complete */
-#define I596_RFD_B 0x4000 /* status: frame busy or waiting */
-#define I596_RFD_OK 0x2000 /* status: frame OK */
-#define I596_RFD_ERR_LENGTH 0x1000 /* status: length error */
-#define I596_RFD_ERR_CRC 0x0800 /* status: CRC error */
-#define I596_RFD_ERR_ALIGN 0x0400 /* status: alignment error */
-#define I596_RFD_ERR_NOBUFS 0x0200 /* status: resource error */
-#define I596_RFD_ERR_DMA 0x0100 /* status: DMA error */
-#define I596_RFD_ERR_SHORT 0x0080 /* status: too short error */
-#define I596_RFD_NOMATCH 0x0002 /* status: IA was not matched */
-#define I596_RFD_COLLISION 0x0001 /* status: collision during receive */
-
-#define I596_RFD_EL 0x8000 /* cmd: end of RFD list */
-#define I596_RFD_FLEX 0x0008 /* cmd: Flexible mode */
-#define I596_RFD_EOF 0x8000 /* count: last buffer in the frame */
-#define I596_RFD_F 0x4000 /* count: The actual count is valid */
-
-/************************************************************************/
-/* */
-/* Commands */
-/* */
-/************************************************************************/
-
- /* values for cmd halfword in all the structs below */
-#define I596_CB_CMD 0x07 /* CB COMMANDS */
-#define I596_CB_CMD_NOP 0
-#define I596_CB_CMD_IA 1
-#define I596_CB_CMD_CONF 2
-#define I596_CB_CMD_MCAST 3
-#define I596_CB_CMD_XMIT 4
-#define I596_CB_CMD_TDR 5
-#define I596_CB_CMD_DUMP 6
-#define I596_CB_CMD_DIAG 7
-
-#define I596_CB_CMD_EL 0x8000 /* CB is last in linked list */
-#define I596_CB_CMD_S 0x4000 /* Suspend after execution */
-#define I596_CB_CMD_I 0x2000 /* cause interrupt */
-
- /* values for the status halfword in all the struct below */
-#define I596_CB_STATUS 0xF000 /* All four status bits */
-#define I596_CB_STATUS_C 0x8000 /* Command complete */
-#define I596_CB_STATUS_B 0x4000 /* Command busy executing */
-#define I596_CB_STATUS_C_OR_B 0xC000 /* Command complete or busy */
-#define I596_CB_STATUS_OK 0x2000 /* Command complete, no errors */
-#define I596_CB_STATUS_A 0x1000 /* Command busy executing */
-
-#define I596_CB_NOLINK ((I596_CB *) 0xffffffff)
-
-/*
- * I596_CB_NOP: NOP Command (p. 4-34)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
-} I596_CB_NOP;
-
-/*
- * Same as above, but command and status in one ulong for speed
- */
-typedef volatile struct
-{
- ulong csr;
- union _I596_CB *next;
-} I596_CB_FAST;
-#define FASTs(X) (X)
-#define FASTc(X) ((X)<<16)
-
-/*
- * I596_CB_IA: Individual (MAC) Address Command (p. 4-35)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
- uchar addr[6];
-} I596_CB_IA;
-
-/*
- * I596_CB_CONF: Configure Command (p. 4-37)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
- uchar conf[14];
-} I596_CB_CONF;
-
-#define I596_CONF0_P 0x80 /* Enable RBD Prefetch Bit */
-#define I596_CONF0_COUNT 14 /* Count of configuration bytes */
-
-#define I596_CONF1_MON_OFF 0xC0 /* Monitor mode: Monitor off */
-#define I596_CONF1_MON_ON 0x80 /* Monitor mode: Monitor on */
-#define I596_CONF1_TxFIFO(W) (W) /* TxFIFO trigger, in words */
-
-#define I596_CONF2_SAVEBF 0x80 /* Save bad frames */
-
-#define I596_CONF3_ADDRLEN(B) (B) /* Address length */
-#define I596_CONF3_NOSRCINSERT 0x08 /* Do not insert source address */
-#define I596_CONF3_PREAMBLE8 0x20 /* 8 byte preamble */
-#define I596_CONF3_LOOPOFF 0x00 /* Loopback: Off */
-#define I596_CONF3_LOOPINT 0x40 /* Loopback: internal */
-#define I596_CONF3_LOOPEXT 0xC0 /* Loopback: external */
-
-#define I596_CONF4_LINPRI(ST) (ST) /* Linear priority: slot times */
-#define I596_CONF4_EXPPRI(ST) (ST) /* Exponential priority: slot times */
-#define I596_CONF4_IEEE_BOM 0 /* IEEE 802.3 backoff method */
-
-#define I596_CONF5_IFS(X) (X) /* Interframe spacing in clocks */
-
-#define I596_CONF6_ST_LOW(X) (X&255) /* Slot time, low byte */
-
-#define I596_CONF7_ST_HI(X) (X>>8) /* Slot time, high bits */
-#define I596_CONF7_RETRY(X) (X<<4) /* Max retry number */
-
-#define I596_CONF8_PROMISC 0x01 /* Rcv all frames */
-#define I596_CONF8_NOBROAD 0x02
-#define I596_CONF8_MANCHESTER 0x04
-#define I596_CONF8_TxNOCRS 0x08
-#define I596_CONF8_NOCRC 0x10
-#define I596_CONF8_CRC_CCITT 0x20
-#define I596_CONF8_BITSTUFFING 0x40
-#define I596_CONF8_PADDING 0x80
-
-#define I596_CONF9_CSFILTER(X) (X)
-#define I596_CONF9_CSINT(X) 0x08
-#define I596_CONF9_CDFILTER(X) (X<<4)
-#define I596_CONF9_CDINT(X) 0x80
-
-#define I596_CONF10_MINLEN(X) (X) /* Minimum frame length */
-
-#define I596_CONF11_PRECRS_ 0x01 /* Preamble before carrier sense */
-#define I596_CONF11_LNGFLD_ 0x02 /* Padding in End of Carrier */
-#define I596_CONF11_CRCINM_ 0x04 /* CRC in memory */
-#define I596_CONF11_AUTOTX 0x08 /* Auto retransmit */
-#define I596_CONF11_CSBSAC_ 0x10 /* Collision detect by src addr cmp. */
-#define I596_CONF11_MCALL_ 0x20 /* Multicast all */
-
-#define I596_CONF13_RESERVED 0x3f /* Reserved: must be ones */
-#define I596_CONF13_MULTIA 0x40 /* Enable multiple addr. reception */
-#define I596_CONF13_DISBOF 0x80 /* Disable backoff algorithm */
-/*
- * I596_CB_MCAST: Multicast-Setup Command (p. 4-54)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
- ushort count; /* Number of 6-byte addrs that follow */
- uchar addr[6][1];
-} I596_CB_MCAST;
-
-/*
- * I596_CB_XMIT: Transmit Command (p. 4-56)
- */
-typedef I596_TFD I596_CB_XMIT;
-
-#define I596_CB_XMIT_NOCRC 0x0010 /* cmd: No CRC insertion */
-#define I596_CB_XMIT_FLEX 0x0008 /* cmd: Flexible memory mode */
-
-#define I596_CB_XMIT_ERR_LATE 0x0800 /* status: error: late collision */
-#define I596_CB_XMIT_ERR_NOCRS 0x0400 /* status: error: no carriers sense */
-#define I596_CB_XMIT_ERR_NOCTS 0x0200 /* status: error: loss of CTS */
-#define I596_CB_XMIT_ERR_UNDER 0x0100 /* status: error: DMA underrun */
-#define I596_CB_XMIT_ERR_MAXCOL 0x0020 /* status: error: maximum collisions */
-#define I596_CB_XMIT_COLLISIONS 0x000f /* status: number of collisions */
-
-/*
- * I596_CB_TDR: Time Domain Reflectometry Command (p. 4-63)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
- ushort time;
-} I596_CB_TDR;
-
-/*
- * I596_CB_DUMP: Dump Command (p. 4-65)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
- uchar *buf;
-} I596_CB_DUMP;
-
-/*
- * I596_CB_DIAG: Diagnose Command (p. 4-77)
- */
-typedef volatile struct
-{
- ushort status;
- ushort cmd;
- union _I596_CB *next;
-} I596_CB_DIAG;
-
-/*
- * I596_CB: Command Block
- */
-typedef union _I596_CB
-{
- I596_CB_NOP nop;
- I596_CB_IA ia;
- I596_CB_CONF conf;
- I596_CB_MCAST mcast;
- I596_CB_XMIT xmit;
- I596_CB_TDR tdr;
- I596_CB_DUMP dump;
- I596_CB_DIAG diag;
-
- /* command and status in one ulong for speed... */
- I596_CB_FAST fast;
-} I596_CB;
-
-/************************************************************************/
-/* */
-/* I596_SCB: System Configuration Block (p. 4-26) */
-/* */
-/************************************************************************/
-typedef volatile struct
-{
- volatile ushort status; /* Status word */
- volatile ushort cmd; /* Command word */
- I596_CB *cbp;
- I596_RFD *rfdp;
- ulong crc_errs;
- ulong align_errs;
- ulong resource_errs;
- ulong overrun_errs;
- ulong rcvcdt_errs;
- ulong short_errs;
- ushort toff;
- ushort ton;
-} I596_SCB;
-
- /* cmd halfword values */
-#define I596_SCB_ACK 0xF000 /* ACKNOWLEDGMENTS */
-#define I596_SCB_ACK_CX 0x8000 /* Ack command completion */
-#define I596_SCB_ACK_FR 0x4000 /* Ack received frame */
-#define I596_SCB_ACK_CNA 0x2000 /* Ack command unit not active */
-#define I596_SCB_ACK_RNR 0x1000 /* Ack rcv unit not ready */
-#define I596_SCB_ACK_ALL 0xF000 /* Ack everything */
-
-#define I596_SCB_CUC 0x0700 /* COMMAND UNIT COMMANDS */
-#define I596_SCB_CUC_NOP 0x0000 /* No operation */
-#define I596_SCB_CUC_START 0x0100 /* Start execution of first CB */
-#define I596_SCB_CUC_RESUME 0x0200 /* Resume execution */
-#define I596_SCB_CUC_SUSPEND 0x0300 /* Suspend after current CB */
-#define I596_SCB_CUC_ABORT 0x0400 /* Abort current CB immediately */
-#define I596_SCB_CUC_LOAD 0x0500 /* Load Bus throttle timers */
-#define I596_SCB_CUC_LOADIMM 0x0600 /* Load Bus throttle timers, now */
-
-#define I596_SCB_RUC 0x0070 /* RECEIVE UNIT COMMANDS */
-#define I596_SCB_RUC_NOP 0x0000 /* No operation */
-#define I596_SCB_RUC_START 0x0010 /* Start reception */
-#define I596_SCB_RUC_RESUME 0x0020 /* Resume reception */
-#define I596_SCB_RUC_SUSPEND 0x0030 /* Suspend reception */
-#define I596_SCB_RUC_ABORT 0x0040 /* Abort reception */
-
-#define I596_SCB_RESET 0x0080 /* Hard reset chip */
-
- /* status halfword values */
-#define I596_SCB_STAT 0xF000 /* STATUS */
-#define I596_SCB_CX 0x8000 /* command completion */
-#define I596_SCB_FR 0x4000 /* received frame */
-#define I596_SCB_CNA 0x2000 /* command unit not active */
-#define I596_SCB_RNR 0x1000 /* rcv unit not ready */
-
-#define I596_SCB_CUS 0x0700 /* COMMAND UNIT STATUS */
-#define I596_SCB_CUS_IDLE 0x0000 /* Idle */
-#define I596_SCB_CUS_SUSPENDED 0x0100 /* Suspended */
-#define I596_SCB_CUS_ACTIVE 0x0200 /* Active */
-
-#define I596_SCB_RUS 0x00F0 /* RECEIVE UNIT STATUS */
-#define I596_SCB_RUS_IDLE 0x0000 /* Idle */
-#define I596_SCB_RUS_SUSPENDED 0x0010 /* Suspended */
-#define I596_SCB_RUS_NORES 0x0020 /* No Resources */
-#define I596_SCB_RUS_READY 0x0040 /* Ready */
-#define I596_SCB_RUS_NORBDS 0x0080 /* No more RBDs modifier */
-
-#define I596_SCB_LOADED 0x0008 /* Bus timers loaded */
-
-/************************************************************************/
-/* */
-/* I596_ISCP: Intermediate System Configuration Ptr (p 4-26) */
-/* */
-/************************************************************************/
-typedef volatile struct
-{
- ulong busy; /* Set to 1; I596 clears it when scbp is read */
- I596_SCB *scbp;
-} I596_ISCP;
-
-/************************************************************************/
-/* */
-/* I596_SCP: System Configuration Pointer (p. 4-23) */
-/* */
-/************************************************************************/
-typedef volatile struct
-{
- ulong sysbus;
- ulong dummy;
- I596_ISCP *iscpp;
-} I596_SCP;
-
- /* .sysbus values */
-#define I596_SCP_RESERVED 0x400000 /* Reserved bits must be set */
-#define I596_SCP_INTLOW 0x200000 /* Intr. Polarity active low */
-#define I596_SCP_INTHIGH 0 /* Intr. Polarity active high */
-#define I596_SCP_LOCKDIS 0x100000 /* Lock Function disabled */
-#define I596_SCP_LOCKEN 0 /* Lock Function enabled */
-#define I596_SCP_ETHROTTLE 0x080000 /* External Bus Throttle */
-#define I596_SCP_ITHROTTLE 0 /* Internal Bus Throttle */
-#define I596_SCP_LINEAR 0x040000 /* Linear Mode */
-#define I596_SCP_SEGMENTED 0x020000 /* Segmented Mode */
-#define I596_SCP_82586 0x000000 /* 82586 Mode */
diff --git a/drivers/net/dgrs_plx9060.h b/drivers/net/dgrs_plx9060.h
deleted file mode 100644
index 6888ae0d0ce..00000000000
--- a/drivers/net/dgrs_plx9060.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * PLX 9060 PCI Interface chip
- */
-
-/*
- * PCI configuration registers, same offset on local and PCI sides,
- * but on PCI side, must use PCI BIOS calls to read/write.
- */
-#define PCI_PLXREGS_BASE_ADDR 0x10
-
-#define PCI_PLXREGS_IO_ADDR 0x14
-
-#define PCI_SPACE0_BASE_ADDR 0x18
-
-#define PCI_ROM_BASE_ADDR 0x30
-# define PCI_ROM_ENABLED 0x00000001
-
-#define PCI_INT_LINE 0x3C
-
-/*
- * Registers accessible directly from PCI and local side.
- * Offset is from PCI side. Add PLX_LCL_OFFSET for local address.
- */
-#define PLX_LCL_OFFSET 0x80 /* Offset of regs from local side */
-
-/*
- * Local Configuration Registers
- */
-#define PLX_SPACE0_RANGE 0x00 /* Range for PCI to Lcl Addr Space 0 */
-#define PLX_SPACE0_BASE_ADDR 0x04 /* Lcl Base address remap */
-
-#define PLX_ROM_RANGE 0x10 /* Range for expansion ROM (DMA) */
-#define PLX_ROM_BASE_ADDR 0x14 /* Lcl base address remap for ROM */
-
-#define PLX_BUS_REGION 0x18 /* Bus Region Descriptors */
-
-/*
- * Shared Run Time Registers
- */
-#define PLX_MBOX0 0x40
-#define PLX_MBOX1 0x44
-#define PLX_MBOX2 0x48
-#define PLX_MBOX3 0x4C
-#define PLX_MBOX4 0x50
-#define PLX_MBOX5 0x54
-#define PLX_MBOX6 0x58
-#define PLX_MBOX7 0x5C
-
-#define PLX_PCI2LCL_DOORBELL 0x60
-
-#define PLX_LCL2PCI_DOORBELL 0x64
-
-#define PLX_INT_CSR 0x68 /* Interrupt Control/Status */
-# define PLX_LSERR_ENABLE 0x00000001
-# define PLX_LSERR_PE 0x00000002
-# define PLX_SERR 0x00000004
-# undef PLX_UNUSED /* 0x00000008 */
-# undef PLX_UNUSED /* 0x00000010 */
-# undef PLX_UNUSED /* 0x00000020 */
-# undef PLX_UNUSED /* 0x00000040 */
-# undef PLX_UNUSED /* 0x00000080 */
-# define PLX_PCI_IE 0x00000100
-# define PLX_PCI_DOORBELL_IE 0x00000200
-# define PLX_PCI_ABORT_IE 0x00000400
-# define PLX_PCI_LOCAL_IE 0x00000800
-# define PLX_RETRY_ABORT_ENABLE 0x00001000
-# define PLX_PCI_DOORBELL_INT 0x00002000
-# define PLX_PCI_ABORT_INT 0x00004000
-# define PLX_PCI_LOCAL_INT 0x00008000
-# define PLX_LCL_IE 0x00010000
-# define PLX_LCL_DOORBELL_IE 0x00020000
-# define PLX_LCL_DMA0_IE 0x00040000
-# define PLX_LCL_DMA1_IE 0x00080000
-# define PLX_LCL_DOORBELL_INT 0x00100000
-# define PLX_LCL_DMA0_INT 0x00200000
-# define PLX_LCL_DMA1_INT 0x00400000
-# define PLX_LCL_BIST_INT 0x00800000
-# define PLX_BM_DIRECT_ 0x01000000
-# define PLX_BM_DMA0_ 0x02000000
-# define PLX_BM_DMA1_ 0x04000000
-# define PLX_BM_ABORT_ 0x08000000
-# undef PLX_UNUSED /* 0x10000000 */
-# undef PLX_UNUSED /* 0x20000000 */
-# undef PLX_UNUSED /* 0x40000000 */
-# undef PLX_UNUSED /* 0x80000000 */
-
-#define PLX_MISC_CSR 0x6c /* EEPROM,PCI,User,Init Control/Status*/
-# define PLX_USEROUT 0x00010000
-# define PLX_USERIN 0x00020000
-# define PLX_EECK 0x01000000
-# define PLX_EECS 0x02000000
-# define PLX_EEWD 0x04000000
-# define PLX_EERD 0x08000000
-
-/*
- * DMA registers. Offset is from local side
- */
-#define PLX_DMA0_MODE 0x100
-# define PLX_DMA_MODE_WIDTH32 0x00000003
-# define PLX_DMA_MODE_WAITSTATES(X) ((X)<<2)
-# define PLX_DMA_MODE_NOREADY 0x00000000
-# define PLX_DMA_MODE_READY 0x00000040
-# define PLX_DMA_MODE_NOBTERM 0x00000000
-# define PLX_DMA_MODE_BTERM 0x00000080
-# define PLX_DMA_MODE_NOBURST 0x00000000
-# define PLX_DMA_MODE_BURST 0x00000100
-# define PLX_DMA_MODE_NOCHAIN 0x00000000
-# define PLX_DMA_MODE_CHAIN 0x00000200
-# define PLX_DMA_MODE_DONE_IE 0x00000400
-# define PLX_DMA_MODE_ADDR_HOLD 0x00000800
-
-#define PLX_DMA0_PCI_ADDR 0x104
- /* non-chaining mode PCI address */
-
-#define PLX_DMA0_LCL_ADDR 0x108
- /* non-chaining mode local address */
-
-#define PLX_DMA0_SIZE 0x10C
- /* non-chaining mode length */
-
-#define PLX_DMA0_DESCRIPTOR 0x110
-# define PLX_DMA_DESC_EOC 0x00000002
-# define PLX_DMA_DESC_TC_IE 0x00000004
-# define PLX_DMA_DESC_TO_HOST 0x00000008
-# define PLX_DMA_DESC_TO_BOARD 0x00000000
-# define PLX_DMA_DESC_NEXTADDR 0xFFFFfff0
-
-#define PLX_DMA1_MODE 0x114
-#define PLX_DMA1_PCI_ADDR 0x118
-#define PLX_DMA1_LCL_ADDR 0x11C
-#define PLX_DMA1_SIZE 0x110
-#define PLX_DMA1_DESCRIPTOR 0x124
-
-#define PLX_DMA_CSR 0x128
-# define PLX_DMA_CSR_0_ENABLE 0x00000001
-# define PLX_DMA_CSR_0_START 0x00000002
-# define PLX_DMA_CSR_0_ABORT 0x00000004
-# define PLX_DMA_CSR_0_CLR_INTR 0x00000008
-# define PLX_DMA_CSR_0_DONE 0x00000010
-# define PLX_DMA_CSR_1_ENABLE 0x00000100
-# define PLX_DMA_CSR_1_START 0x00000200
-# define PLX_DMA_CSR_1_ABORT 0x00000400
-# define PLX_DMA_CSR_1_CLR_INTR 0x00000800
-# define PLX_DMA_CSR_1_DONE 0x00001000
-
-#define PLX_DMA_ARB0 0x12C
-# define PLX_DMA_ARB0_LATENCY_T 0x000000FF
-# define PLX_DMA_ARB0_PAUSE_T 0x0000FF00
-# define PLX_DMA_ARB0_LATENCY_EN 0x00010000
-# define PLX_DMA_ARB0_PAUSE_EN 0x00020000
-# define PLX_DMA_ARB0_BREQ_EN 0x00040000
-# define PLX_DMA_ARB0_PRI 0x00180000
-# define PLX_DMA_ARB0_PRI_ROUND 0x00000000
-# define PLX_DMA_ARB0_PRI_0 0x00080000
-# define PLX_DMA_ARB0_PRI_1 0x00100000
-
-#define PLX_DMA_ARB1 0x130
- /* Chan 0: FIFO DEPTH=16 */
-# define PLX_DMA_ARB1_0_P2L_LW_TRIG(X) ( ((X)&15) << 0 )
-# define PLX_DMA_ARB1_0_L2P_LR_TRIG(X) ( ((X)&15) << 4 )
-# define PLX_DMA_ARB1_0_L2P_PW_TRIG(X) ( ((X)&15) << 8 )
-# define PLX_DMA_ARB1_0_P2L_PR_TRIG(X) ( ((X)&15) << 12 )
- /* Chan 1: FIFO DEPTH=8 */
-# define PLX_DMA_ARB1_1_P2L_LW_TRIG(X) ( ((X)& 7) << 16 )
-# define PLX_DMA_ARB1_1_L2P_LR_TRIG(X) ( ((X)& 7) << 20 )
-# define PLX_DMA_ARB1_1_L2P_PW_TRIG(X) ( ((X)& 7) << 24 )
-# define PLX_DMA_ARB1_1_P2L_PR_TRIG(X) ( ((X)& 7) << 28 )
-
-typedef struct _dmachain
-{
- ulong pciaddr;
- ulong lcladdr;
- ulong len;
- ulong next;
-} DMACHAIN;
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 04e3710c908..5066beb2e7b 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -10,9 +10,9 @@
(at your option) any later version.
*/
-#define DRV_NAME "D-Link DL2000-based linux driver"
-#define DRV_VERSION "v1.18"
-#define DRV_RELDATE "2006/06/27"
+#define DRV_NAME "DL2000/TC902x-based linux driver"
+#define DRV_VERSION "v1.19"
+#define DRV_RELDATE "2007/08/12"
#include "dl2k.h"
#include <linux/dma-mapping.h>
@@ -97,6 +97,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
static int version_printed;
void *ring_space;
dma_addr_t ring_dma;
+ DECLARE_MAC_BUF(mac);
if (!version_printed++)
printk ("%s", version);
@@ -116,7 +117,6 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
err = -ENOMEM;
goto err_out_res;
}
- SET_MODULE_OWNER (dev);
SET_NETDEV_DEV(dev, &pdev->dev);
#ifdef MEM_MAPPING
@@ -257,10 +257,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
card_idx++;
- printk (KERN_INFO "%s: %s, %02x:%02x:%02x:%02x:%02x:%02x, IRQ %d\n",
- dev->name, np->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], irq);
+ printk (KERN_INFO "%s: %s, %s, IRQ %d\n",
+ dev->name, np->name, print_mac(mac, dev->dev_addr), irq);
if (tx_coalesce > 1)
printk(KERN_INFO "tx_coalesce:\t%d packets\n",
tx_coalesce);
@@ -292,7 +290,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
return err;
}
-int
+static int
find_miiphy (struct net_device *dev)
{
int i, phy_found = 0;
@@ -316,7 +314,7 @@ find_miiphy (struct net_device *dev)
return 0;
}
-int
+static int
parse_eeprom (struct net_device *dev)
{
int i, j;
@@ -339,17 +337,24 @@ parse_eeprom (struct net_device *dev)
#ifdef MEM_MAPPING
ioaddr = dev->base_addr;
#endif
- /* Check CRC */
- crc = ~ether_crc_le (256 - 4, sromdata);
- if (psrom->crc != crc) {
- printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
- return -1;
+ if (np->pdev->vendor == PCI_VENDOR_ID_DLINK) { /* D-Link Only */
+ /* Check CRC */
+ crc = ~ether_crc_le (256 - 4, sromdata);
+ if (psrom->crc != crc) {
+ printk (KERN_ERR "%s: EEPROM data CRC error.\n",
+ dev->name);
+ return -1;
+ }
}
/* Set MAC address */
for (i = 0; i < 6; i++)
dev->dev_addr[i] = psrom->mac_addr[i];
+ if (np->pdev->vendor != PCI_VENDOR_ID_DLINK) {
+ return 0;
+ }
+
/* Parse Software Information Block */
i = 0x30;
psib = (u8 *) sromdata;
@@ -1091,7 +1096,7 @@ clear_stats (struct net_device *dev)
}
-int
+static int
change_mtu (struct net_device *dev, int new_mtu)
{
struct netdev_private *np = netdev_priv(dev);
@@ -1326,7 +1331,7 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
#define EEP_BUSY 0x8000
/* Read the EEPROM word */
/* We use I/O instruction to read/write eeprom to avoid fail on some machines */
-int
+static int
read_eeprom (long ioaddr, int eep_addr)
{
int i = 1000;
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
index e443065a452..5b801775f42 100644
--- a/drivers/net/dl2k.h
+++ b/drivers/net/dl2k.h
@@ -692,6 +692,7 @@ struct netdev_private {
static const struct pci_device_id rio_pci_tbl[] = {
{0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, },
+ {0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, },
{ }
};
MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 738aa590651..3286d2a0a87 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -148,7 +148,6 @@ typedef struct board_info {
struct resource *irq_res;
struct timer_list timer;
- struct net_device_stats stats;
unsigned char srom[128];
spinlock_t lock;
@@ -166,8 +165,6 @@ static int dm9000_stop(struct net_device *);
static void dm9000_timer(unsigned long);
static void dm9000_init_dm9000(struct net_device *);
-static struct net_device_stats *dm9000_get_stats(struct net_device *);
-
static irqreturn_t dm9000_interrupt(int, void *);
static int dm9000_phy_read(struct net_device *dev, int phyaddr_unsused, int reg);
@@ -416,7 +413,6 @@ dm9000_probe(struct platform_device *pdev)
return -ENOMEM;
}
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
PRINTK2("dm9000_probe()");
@@ -546,7 +542,8 @@ dm9000_probe(struct platform_device *pdev)
if (id_val != DM9000_ID) {
printk("%s: wrong id: 0x%08x\n", CARDNAME, id_val);
- goto release;
+ ret = -ENODEV;
+ goto out;
}
/* from this point we assume that we have found a DM9000 */
@@ -559,7 +556,6 @@ dm9000_probe(struct platform_device *pdev)
ndev->tx_timeout = &dm9000_timeout;
ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
ndev->stop = &dm9000_stop;
- ndev->get_stats = &dm9000_get_stats;
ndev->set_multicast_list = &dm9000_hash_table;
#ifdef CONFIG_NET_POLL_CONTROLLER
ndev->poll_controller = &dm9000_poll_controller;
@@ -600,16 +596,14 @@ dm9000_probe(struct platform_device *pdev)
ret = register_netdev(ndev);
if (ret == 0) {
- printk("%s: dm9000 at %p,%p IRQ %d MAC: ",
- ndev->name, db->io_addr, db->io_data, ndev->irq);
- for (i = 0; i < 5; i++)
- printk("%02x:", ndev->dev_addr[i]);
- printk("%02x\n", ndev->dev_addr[5]);
+ DECLARE_MAC_BUF(mac);
+ printk("%s: dm9000 at %p,%p IRQ %d MAC: %s\n",
+ ndev->name, db->io_addr, db->io_data, ndev->irq,
+ print_mac(mac, ndev->dev_addr));
}
return 0;
- release:
- out:
+out:
printk("%s: not found (%d).\n", CARDNAME, ret);
dm9000_release_board(pdev, db);
@@ -714,7 +708,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
writeb(DM9000_MWCMD, db->io_addr);
(db->outblk)(db->io_data, skb->data, skb->len);
- db->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
db->tx_pkt_cnt++;
/* TX control: First packet immediately send, second packet queue */
@@ -791,7 +785,7 @@ dm9000_tx_done(struct net_device *dev, board_info_t * db)
if (tx_status & (NSR_TX2END | NSR_TX1END)) {
/* One packet sent complete */
db->tx_pkt_cnt--;
- db->stats.tx_packets++;
+ dev->stats.tx_packets++;
/* Queue packet check & send */
if (db->tx_pkt_cnt > 0) {
@@ -853,17 +847,6 @@ dm9000_interrupt(int irq, void *dev_id)
}
/*
- * Get statistics from driver.
- */
-static struct net_device_stats *
-dm9000_get_stats(struct net_device *dev)
-{
- board_info_t *db = (board_info_t *) dev->priv;
- return &db->stats;
-}
-
-
-/*
* A periodic timer routine
* Dynamic media sense, allocated Rx buffer...
*/
@@ -940,15 +923,15 @@ dm9000_rx(struct net_device *dev)
GoodPacket = false;
if (rxhdr.RxStatus & 0x100) {
PRINTK1("fifo error\n");
- db->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
}
if (rxhdr.RxStatus & 0x200) {
PRINTK1("crc error\n");
- db->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
}
if (rxhdr.RxStatus & 0x8000) {
PRINTK1("length error\n");
- db->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
}
@@ -961,12 +944,12 @@ dm9000_rx(struct net_device *dev)
/* Read received packet from RX SRAM */
(db->inblk)(db->io_data, rdptr, RxLen);
- db->stats.rx_bytes += RxLen;
+ dev->stats.rx_bytes += RxLen;
/* Pass to upper layer */
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- db->stats.rx_packets++;
+ dev->stats.rx_packets++;
} else {
/* need to dump the packet's data */
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 756a6bcb038..84e14f397d9 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -71,7 +71,6 @@ static void dummy_setup(struct net_device *dev)
dev->change_mtu = NULL;
dev->flags |= IFF_NOARP;
dev->flags &= ~IFF_MULTICAST;
- SET_MODULE_OWNER(dev);
random_ether_addr(dev->dev_addr);
}
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 280313b9b06..3dbaec680b4 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -539,6 +539,7 @@ struct nic {
struct csr __iomem *csr;
enum scb_cmd_lo cuc_cmd;
unsigned int cbs_avail;
+ struct napi_struct napi;
struct cb *cbs;
struct cb *cb_to_use;
struct cb *cb_to_send;
@@ -557,7 +558,6 @@ struct nic {
enum mac mac;
enum phy phy;
struct params params;
- struct net_device_stats net_stats;
struct timer_list watchdog;
struct timer_list blink_timer;
struct mii_if_info mii;
@@ -1324,7 +1324,7 @@ static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb,
if (!--counter) break;
}
- /* ack any interupts, something could have been set */
+ /* ack any interrupts, something could have been set */
iowrite8(~0, &nic->csr->scb.stat_ack);
/* if the command failed, or is not OK, notify and return */
@@ -1482,7 +1482,8 @@ static void e100_set_multicast_list(struct net_device *netdev)
static void e100_update_stats(struct nic *nic)
{
- struct net_device_stats *ns = &nic->net_stats;
+ struct net_device *dev = nic->netdev;
+ struct net_device_stats *ns = &dev->stats;
struct stats *s = &nic->mem->stats;
u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause :
(nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames :
@@ -1604,7 +1605,8 @@ static void e100_watchdog(unsigned long data)
else
nic->flags &= ~ich_10h_workaround;
- mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD);
+ mod_timer(&nic->watchdog,
+ round_jiffies(jiffies + E100_WATCHDOG_PERIOD));
}
static void e100_xmit_prepare(struct nic *nic, struct cb *cb,
@@ -1659,6 +1661,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
static int e100_tx_clean(struct nic *nic)
{
+ struct net_device *dev = nic->netdev;
struct cb *cb;
int tx_cleaned = 0;
@@ -1673,8 +1676,8 @@ static int e100_tx_clean(struct nic *nic)
cb->status);
if(likely(cb->skb != NULL)) {
- nic->net_stats.tx_packets++;
- nic->net_stats.tx_bytes += cb->skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += cb->skb->len;
pci_unmap_single(nic->pdev,
le32_to_cpu(cb->u.tcb.tbd.buf_addr),
@@ -1805,6 +1808,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
static int e100_rx_indicate(struct nic *nic, struct rx *rx,
unsigned int *work_done, unsigned int work_to_do)
{
+ struct net_device *dev = nic->netdev;
struct sk_buff *skb = rx->skb;
struct rfd *rfd = (struct rfd *)skb->data;
u16 rfd_status, actual_size;
@@ -1849,8 +1853,8 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
nic->rx_over_length_errors++;
dev_kfree_skb_any(skb);
} else {
- nic->net_stats.rx_packets++;
- nic->net_stats.rx_bytes += actual_size;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += actual_size;
nic->netdev->last_rx = jiffies;
netif_receive_skb(skb);
if(work_done)
@@ -1974,35 +1978,31 @@ static irqreturn_t e100_intr(int irq, void *dev_id)
if(stat_ack & stat_ack_rnr)
nic->ru_running = RU_SUSPENDED;
- if(likely(netif_rx_schedule_prep(netdev))) {
+ if(likely(netif_rx_schedule_prep(netdev, &nic->napi))) {
e100_disable_irq(nic);
- __netif_rx_schedule(netdev);
+ __netif_rx_schedule(netdev, &nic->napi);
}
return IRQ_HANDLED;
}
-static int e100_poll(struct net_device *netdev, int *budget)
+static int e100_poll(struct napi_struct *napi, int budget)
{
- struct nic *nic = netdev_priv(netdev);
- unsigned int work_to_do = min(netdev->quota, *budget);
+ struct nic *nic = container_of(napi, struct nic, napi);
+ struct net_device *netdev = nic->netdev;
unsigned int work_done = 0;
int tx_cleaned;
- e100_rx_clean(nic, &work_done, work_to_do);
+ e100_rx_clean(nic, &work_done, budget);
tx_cleaned = e100_tx_clean(nic);
/* If no Rx and Tx cleanup work was done, exit polling mode. */
if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
- netif_rx_complete(netdev);
+ netif_rx_complete(netdev, napi);
e100_enable_irq(nic);
- return 0;
}
- *budget -= work_done;
- netdev->quota -= work_done;
-
- return 1;
+ return work_done;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2017,12 +2017,6 @@ static void e100_netpoll(struct net_device *netdev)
}
#endif
-static struct net_device_stats *e100_get_stats(struct net_device *netdev)
-{
- struct nic *nic = netdev_priv(netdev);
- return &nic->net_stats;
-}
-
static int e100_set_mac_address(struct net_device *netdev, void *p)
{
struct nic *nic = netdev_priv(netdev);
@@ -2071,7 +2065,7 @@ static int e100_up(struct nic *nic)
nic->netdev->name, nic->netdev)))
goto err_no_irq;
netif_wake_queue(nic->netdev);
- netif_poll_enable(nic->netdev);
+ napi_enable(&nic->napi);
/* enable ints _after_ enabling poll, preventing a race between
* disable ints+schedule */
e100_enable_irq(nic);
@@ -2089,7 +2083,7 @@ err_rx_clean_list:
static void e100_down(struct nic *nic)
{
/* wait here for poll to complete */
- netif_poll_disable(nic->netdev);
+ napi_disable(&nic->napi);
netif_stop_queue(nic->netdev);
e100_hw_reset(nic);
free_irq(nic->pdev->irq, nic->netdev);
@@ -2380,11 +2374,6 @@ static const char e100_gstrings_test[][ETH_GSTRING_LEN] = {
};
#define E100_TEST_LEN sizeof(e100_gstrings_test) / ETH_GSTRING_LEN
-static int e100_diag_test_count(struct net_device *netdev)
-{
- return E100_TEST_LEN;
-}
-
static void e100_diag_test(struct net_device *netdev,
struct ethtool_test *test, u64 *data)
{
@@ -2447,9 +2436,16 @@ static const char e100_gstrings_stats[][ETH_GSTRING_LEN] = {
#define E100_NET_STATS_LEN 21
#define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN
-static int e100_get_stats_count(struct net_device *netdev)
+static int e100_get_sset_count(struct net_device *netdev, int sset)
{
- return E100_STATS_LEN;
+ switch (sset) {
+ case ETH_SS_TEST:
+ return E100_TEST_LEN;
+ case ETH_SS_STATS:
+ return E100_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void e100_get_ethtool_stats(struct net_device *netdev,
@@ -2459,7 +2455,7 @@ static void e100_get_ethtool_stats(struct net_device *netdev,
int i;
for(i = 0; i < E100_NET_STATS_LEN; i++)
- data[i] = ((unsigned long *)&nic->net_stats)[i];
+ data[i] = ((unsigned long *)&netdev->stats)[i];
data[i++] = nic->tx_deferred;
data[i++] = nic->tx_single_collisions;
@@ -2500,12 +2496,11 @@ static const struct ethtool_ops e100_ethtool_ops = {
.set_eeprom = e100_set_eeprom,
.get_ringparam = e100_get_ringparam,
.set_ringparam = e100_set_ringparam,
- .self_test_count = e100_diag_test_count,
.self_test = e100_diag_test,
.get_strings = e100_get_strings,
.phys_id = e100_phys_id,
- .get_stats_count = e100_get_stats_count,
.get_ethtool_stats = e100_get_ethtool_stats,
+ .get_sset_count = e100_get_sset_count,
};
static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
@@ -2554,6 +2549,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
struct net_device *netdev;
struct nic *nic;
int err;
+ DECLARE_MAC_BUF(mac);
if(!(netdev = alloc_etherdev(sizeof(struct nic)))) {
if(((1 << debug) - 1) & NETIF_MSG_PROBE)
@@ -2564,7 +2560,6 @@ static int __devinit e100_probe(struct pci_dev *pdev,
netdev->open = e100_open;
netdev->stop = e100_close;
netdev->hard_start_xmit = e100_xmit_frame;
- netdev->get_stats = e100_get_stats;
netdev->set_multicast_list = e100_set_multicast_list;
netdev->set_mac_address = e100_set_mac_address;
netdev->change_mtu = e100_change_mtu;
@@ -2572,14 +2567,13 @@ static int __devinit e100_probe(struct pci_dev *pdev,
SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops);
netdev->tx_timeout = e100_tx_timeout;
netdev->watchdog_timeo = E100_WATCHDOG_PERIOD;
- netdev->poll = e100_poll;
- netdev->weight = E100_NAPI_WEIGHT;
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = e100_netpoll;
#endif
strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
nic = netdev_priv(netdev);
+ netif_napi_add(netdev, &nic->napi, e100_poll, E100_NAPI_WEIGHT);
nic->netdev = netdev;
nic->pdev = pdev;
nic->msg_enable = (1 << debug) - 1;
@@ -2607,7 +2601,6 @@ static int __devinit e100_probe(struct pci_dev *pdev,
goto err_out_free_res;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
if (use_io)
@@ -2688,11 +2681,9 @@ static int __devinit e100_probe(struct pci_dev *pdev,
goto err_out_free;
}
- DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, "
- "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
- (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), pdev->irq,
- netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
- netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+ DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %s\n",
+ (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0),
+ pdev->irq, print_mac(mac, netdev->dev_addr));
return 0;
@@ -2733,7 +2724,7 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
struct nic *nic = netdev_priv(netdev);
if (netif_running(netdev))
- netif_poll_disable(nic->netdev);
+ napi_disable(&nic->napi);
del_timer_sync(&nic->watchdog);
netif_carrier_off(nic->netdev);
netif_device_detach(netdev);
@@ -2779,7 +2770,7 @@ static void e100_shutdown(struct pci_dev *pdev)
struct nic *nic = netdev_priv(netdev);
if (netif_running(netdev))
- netif_poll_disable(nic->netdev);
+ napi_disable(&nic->napi);
del_timer_sync(&nic->watchdog);
netif_carrier_off(nic->netdev);
@@ -2804,12 +2795,13 @@ static void e100_shutdown(struct pci_dev *pdev)
static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
+ struct nic *nic = netdev_priv(netdev);
/* Similar to calling e100_down(), but avoids adpater I/O. */
netdev->stop(netdev);
/* Detach; put netif into state similar to hotplug unplug. */
- netif_poll_enable(netdev);
+ napi_enable(&nic->napi);
netif_device_detach(netdev);
pci_disable_device(pdev);
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 16a6edfeba4..3b840283a9c 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -300,6 +300,7 @@ struct e1000_adapter {
int cleaned_count);
struct e1000_rx_ring *rx_ring; /* One per active queue */
#ifdef CONFIG_E1000_NAPI
+ struct napi_struct napi;
struct net_device *polling_netdev; /* One per active queue */
#endif
int num_tx_queues;
@@ -350,4 +351,12 @@ enum e1000_state_t {
__E1000_DOWN
};
+extern char e1000_driver_name[];
+extern const char e1000_driver_version[];
+
+extern void e1000_power_up_phy(struct e1000_adapter *);
+extern void e1000_set_ethtool_ops(struct net_device *netdev);
+extern void e1000_check_options(struct e1000_adapter *adapter);
+
+
#endif /* _E1000_H_ */
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 9ecc3adcf6c..667f18bcc17 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -32,9 +32,6 @@
#include <asm/uaccess.h>
-extern char e1000_driver_name[];
-extern char e1000_driver_version[];
-
extern int e1000_up(struct e1000_adapter *adapter);
extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_reinit_locked(struct e1000_adapter *adapter);
@@ -106,8 +103,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
};
#define E1000_QUEUE_STATS_LEN 0
-#define E1000_GLOBAL_STATS_LEN \
- sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
+#define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats)
#define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN + E1000_QUEUE_STATS_LEN)
static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
"Register test (offline)", "Eeprom test (offline)",
@@ -619,8 +615,6 @@ e1000_get_drvinfo(struct net_device *netdev,
strncpy(drvinfo->fw_version, firmware_version, 32);
strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
- drvinfo->n_stats = E1000_STATS_LEN;
- drvinfo->testinfo_len = E1000_TEST_LEN;
drvinfo->regdump_len = e1000_get_regs_len(netdev);
drvinfo->eedump_len = e1000_get_eeprom_len(netdev);
}
@@ -736,16 +730,16 @@ err_setup:
#define REG_PATTERN_TEST(R, M, W) \
{ \
- uint32_t pat, value; \
- uint32_t test[] = \
+ uint32_t pat, val; \
+ const uint32_t test[] = \
{0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \
- for (pat = 0; pat < ARRAY_SIZE(test); pat++) { \
+ for (pat = 0; pat < ARRAY_SIZE(test); pat++) { \
E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \
- value = E1000_READ_REG(&adapter->hw, R); \
- if (value != (test[pat] & W & M)) { \
+ val = E1000_READ_REG(&adapter->hw, R); \
+ if (val != (test[pat] & W & M)) { \
DPRINTK(DRV, ERR, "pattern test reg %04X failed: got " \
"0x%08X expected 0x%08X\n", \
- E1000_##R, value, (test[pat] & W & M)); \
+ E1000_##R, val, (test[pat] & W & M)); \
*data = (adapter->hw.mac_type < e1000_82543) ? \
E1000_82542_##R : E1000_##R; \
return 1; \
@@ -755,12 +749,12 @@ err_setup:
#define REG_SET_AND_CHECK(R, M, W) \
{ \
- uint32_t value; \
+ uint32_t val; \
E1000_WRITE_REG(&adapter->hw, R, W & M); \
- value = E1000_READ_REG(&adapter->hw, R); \
- if ((W & M) != (value & M)) { \
+ val = E1000_READ_REG(&adapter->hw, R); \
+ if ((W & M) != (val & M)) { \
DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\
- "expected 0x%08X\n", E1000_##R, (value & M), (W & M)); \
+ "expected 0x%08X\n", E1000_##R, (val & M), (W & M)); \
*data = (adapter->hw.mac_type < e1000_82543) ? \
E1000_82542_##R : E1000_##R; \
return 1; \
@@ -1612,13 +1606,18 @@ e1000_link_test(struct e1000_adapter *adapter, uint64_t *data)
}
static int
-e1000_diag_test_count(struct net_device *netdev)
+e1000_get_sset_count(struct net_device *netdev, int sset)
{
- return E1000_TEST_LEN;
+ switch (sset) {
+ case ETH_SS_TEST:
+ return E1000_TEST_LEN;
+ case ETH_SS_STATS:
+ return E1000_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
-extern void e1000_power_up_phy(struct e1000_adapter *);
-
static void
e1000_diag_test(struct net_device *netdev,
struct ethtool_test *eth_test, uint64_t *data)
@@ -1855,8 +1854,8 @@ e1000_phys_id(struct net_device *netdev, uint32_t data)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
- if (!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ))
- data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ);
+ if (!data)
+ data = INT_MAX;
if (adapter->hw.mac_type < e1000_82571) {
if (!adapter->blink_timer.function) {
@@ -1899,12 +1898,6 @@ e1000_nway_reset(struct net_device *netdev)
return 0;
}
-static int
-e1000_get_stats_count(struct net_device *netdev)
-{
- return E1000_STATS_LEN;
-}
-
static void
e1000_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, uint64_t *data)
@@ -1966,16 +1959,13 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.set_rx_csum = e1000_set_rx_csum,
.get_tx_csum = e1000_get_tx_csum,
.set_tx_csum = e1000_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = e1000_set_tso,
- .self_test_count = e1000_diag_test_count,
.self_test = e1000_diag_test,
.get_strings = e1000_get_strings,
.phys_id = e1000_phys_id,
- .get_stats_count = e1000_get_stats_count,
.get_ethtool_stats = e1000_get_ethtool_stats,
+ .get_sset_count = e1000_get_sset_count,
};
void e1000_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 8604adbe351..7c6888c58c2 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -871,10 +871,6 @@ e1000_init_hw(struct e1000_hw *hw)
uint32_t ctrl;
uint32_t i;
int32_t ret_val;
- uint16_t pcix_cmd_word;
- uint16_t pcix_stat_hi_word;
- uint16_t cmd_mmrbc;
- uint16_t stat_mmrbc;
uint32_t mta_size;
uint32_t reg_data;
uint32_t ctrl_ext;
@@ -964,24 +960,9 @@ e1000_init_hw(struct e1000_hw *hw)
break;
default:
/* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
- if (hw->bus_type == e1000_bus_type_pcix) {
- e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
- e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI,
- &pcix_stat_hi_word);
- cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >>
- PCIX_COMMAND_MMRBC_SHIFT;
- stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
- PCIX_STATUS_HI_MMRBC_SHIFT;
- if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
- stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
- if (cmd_mmrbc > stat_mmrbc) {
- pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
- pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
- e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER,
- &pcix_cmd_word);
- }
- }
- break;
+ if (hw->bus_type == e1000_bus_type_pcix && e1000_pcix_get_mmrbc(hw) > 2048)
+ e1000_pcix_set_mmrbc(hw, 2048);
+ break;
}
/* More time needed for PHY to initialize */
@@ -8626,7 +8607,7 @@ e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index,
DEBUGFUNC("e1000_read_ich8_data");
- if (size < 1 || size > 2 || data == 0x0 ||
+ if (size < 1 || size > 2 || data == NULL ||
index > ICH_FLASH_LINEAR_ADDR_MASK)
return error;
@@ -8860,7 +8841,7 @@ e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t *data)
* amount of NVM used in each bank is a *minimum* of 4 KBytes, but in fact the
* bank size may be 4, 8 or 64 KBytes
*****************************************************************************/
-int32_t
+static int32_t
e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t bank)
{
union ich8_hws_flash_status hsfsts;
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 07f0ea73676..a2a86c54a75 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -424,6 +424,8 @@ void e1000_pci_clear_mwi(struct e1000_hw *hw);
void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value);
+void e1000_pcix_set_mmrbc(struct e1000_hw *hw, int mmrbc);
+int e1000_pcix_get_mmrbc(struct e1000_hw *hw);
/* Port I/O is only supported on 82544 and newer */
void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value);
int32_t e1000_disable_pciex_master(struct e1000_hw *hw);
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index e7c8951f47f..cf39473ef90 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -37,8 +37,8 @@ static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
#define DRIVERNAPI "-NAPI"
#endif
#define DRV_VERSION "7.3.20-k2"DRIVERNAPI
-char e1000_driver_version[] = DRV_VERSION;
-static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
+const char e1000_driver_version[] = DRV_VERSION;
+static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
*
@@ -166,7 +166,7 @@ static irqreturn_t e1000_intr_msi(int irq, void *data);
static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter,
struct e1000_tx_ring *tx_ring);
#ifdef CONFIG_E1000_NAPI
-static int e1000_clean(struct net_device *poll_dev, int *budget);
+static int e1000_clean(struct napi_struct *napi, int budget);
static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
@@ -188,7 +188,6 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
int cmd);
-void e1000_set_ethtool_ops(struct net_device *netdev);
static void e1000_enter_82542_rst(struct e1000_adapter *adapter);
static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
static void e1000_tx_timeout(struct net_device *dev);
@@ -213,8 +212,6 @@ static void e1000_shutdown(struct pci_dev *pdev);
static void e1000_netpoll (struct net_device *netdev);
#endif
-extern void e1000_check_options(struct e1000_adapter *adapter);
-
#define COPYBREAK_DEFAULT 256
static unsigned int copybreak __read_mostly = COPYBREAK_DEFAULT;
module_param(copybreak, uint, 0644);
@@ -545,7 +542,7 @@ int e1000_up(struct e1000_adapter *adapter)
clear_bit(__E1000_DOWN, &adapter->flags);
#ifdef CONFIG_E1000_NAPI
- netif_poll_enable(adapter->netdev);
+ napi_enable(&adapter->napi);
#endif
e1000_irq_enable(adapter);
@@ -634,7 +631,7 @@ e1000_down(struct e1000_adapter *adapter)
set_bit(__E1000_DOWN, &adapter->flags);
#ifdef CONFIG_E1000_NAPI
- netif_poll_disable(netdev);
+ napi_disable(&adapter->napi);
#endif
e1000_irq_disable(adapter);
@@ -872,6 +869,8 @@ e1000_probe(struct pci_dev *pdev,
int i, err, pci_using_dac;
uint16_t eeprom_data = 0;
uint16_t eeprom_apme_mask = E1000_EEPROM_APME;
+ DECLARE_MAC_BUF(mac);
+
if ((err = pci_enable_device(pdev)))
return err;
@@ -897,7 +896,6 @@ e1000_probe(struct pci_dev *pdev,
if (!netdev)
goto err_alloc_etherdev;
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
pci_set_drvdata(pdev, netdev);
@@ -936,8 +934,7 @@ e1000_probe(struct pci_dev *pdev,
netdev->tx_timeout = &e1000_tx_timeout;
netdev->watchdog_timeo = 5 * HZ;
#ifdef CONFIG_E1000_NAPI
- netdev->poll = &e1000_clean;
- netdev->weight = 64;
+ netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);
#endif
netdev->vlan_rx_register = e1000_vlan_rx_register;
netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
@@ -1134,8 +1131,7 @@ e1000_probe(struct pci_dev *pdev,
"32-bit"));
}
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", netdev->dev_addr[i], i == 5 ? '\n' : ':');
+ printk("%s\n", print_mac(mac, netdev->dev_addr));
/* reset the hardware with the new settings */
e1000_reset(adapter);
@@ -1151,9 +1147,6 @@ e1000_probe(struct pci_dev *pdev,
/* tell the stack to leave us alone until e1000_open() is called */
netif_carrier_off(netdev);
netif_stop_queue(netdev);
-#ifdef CONFIG_E1000_NAPI
- netif_poll_disable(netdev);
-#endif
strcpy(netdev->name, "eth%d");
if ((err = register_netdev(netdev)))
@@ -1222,12 +1215,13 @@ e1000_remove(struct pci_dev *pdev)
* would have already happened in close and is redundant. */
e1000_release_hw_control(adapter);
- unregister_netdev(netdev);
#ifdef CONFIG_E1000_NAPI
for (i = 0; i < adapter->num_rx_queues; i++)
dev_put(&adapter->polling_netdev[i]);
#endif
+ unregister_netdev(netdev);
+
if (!e1000_check_phy_reset_block(&adapter->hw))
e1000_phy_hw_reset(&adapter->hw);
@@ -1325,8 +1319,6 @@ e1000_sw_init(struct e1000_adapter *adapter)
#ifdef CONFIG_E1000_NAPI
for (i = 0; i < adapter->num_rx_queues; i++) {
adapter->polling_netdev[i].priv = adapter;
- adapter->polling_netdev[i].poll = &e1000_clean;
- adapter->polling_netdev[i].weight = 64;
dev_hold(&adapter->polling_netdev[i]);
set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state);
}
@@ -1443,7 +1435,7 @@ e1000_open(struct net_device *netdev)
clear_bit(__E1000_DOWN, &adapter->flags);
#ifdef CONFIG_E1000_NAPI
- netif_poll_enable(netdev);
+ napi_enable(&adapter->napi);
#endif
e1000_irq_enable(adapter);
@@ -3266,14 +3258,13 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD;
unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
unsigned int tx_flags = 0;
- unsigned int len = skb->len;
+ unsigned int len = skb->len - skb->data_len;
unsigned long flags;
- unsigned int nr_frags = 0;
- unsigned int mss = 0;
+ unsigned int nr_frags;
+ unsigned int mss;
int count = 0;
int tso;
unsigned int f;
- len -= skb->data_len;
/* This goes back to the question of how to logically map a tx queue
* to a flow. Right now, performance is impacted slightly negatively
@@ -3307,7 +3298,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
* points to just header, pull a few bytes of payload from
* frags into skb->data */
hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
- if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) {
+ if (skb->data_len && hdr_len == len) {
switch (adapter->hw.mac_type) {
unsigned int pull_size;
case e1000_82544:
@@ -3596,7 +3587,7 @@ e1000_update_stats(struct e1000_adapter *adapter)
spin_lock_irqsave(&adapter->stats_lock, flags);
- /* these counters are modified from e1000_adjust_tbi_stats,
+ /* these counters are modified from e1000_tbi_adjust_stats,
* called from the interrupt context, so they must only
* be written while holding adapter->stats_lock
*/
@@ -3786,12 +3777,12 @@ e1000_intr_msi(int irq, void *data)
}
#ifdef CONFIG_E1000_NAPI
- if (likely(netif_rx_schedule_prep(netdev))) {
+ if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) {
adapter->total_tx_bytes = 0;
adapter->total_tx_packets = 0;
adapter->total_rx_bytes = 0;
adapter->total_rx_packets = 0;
- __netif_rx_schedule(netdev);
+ __netif_rx_schedule(netdev, &adapter->napi);
} else
e1000_irq_enable(adapter);
#else
@@ -3871,12 +3862,12 @@ e1000_intr(int irq, void *data)
E1000_WRITE_REG(hw, IMC, ~0);
E1000_WRITE_FLUSH(hw);
}
- if (likely(netif_rx_schedule_prep(netdev))) {
+ if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) {
adapter->total_tx_bytes = 0;
adapter->total_tx_packets = 0;
adapter->total_rx_bytes = 0;
adapter->total_rx_packets = 0;
- __netif_rx_schedule(netdev);
+ __netif_rx_schedule(netdev, &adapter->napi);
} else
/* this really should not happen! if it does it is basically a
* bug, but not a hard error, so enable ints and continue */
@@ -3924,10 +3915,10 @@ e1000_intr(int irq, void *data)
**/
static int
-e1000_clean(struct net_device *poll_dev, int *budget)
+e1000_clean(struct napi_struct *napi, int budget)
{
- struct e1000_adapter *adapter;
- int work_to_do = min(*budget, poll_dev->quota);
+ struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
+ struct net_device *poll_dev = adapter->netdev;
int tx_cleaned = 0, work_done = 0;
/* Must NOT use netdev_priv macro here. */
@@ -3948,23 +3939,19 @@ e1000_clean(struct net_device *poll_dev, int *budget)
}
adapter->clean_rx(adapter, &adapter->rx_ring[0],
- &work_done, work_to_do);
-
- *budget -= work_done;
- poll_dev->quota -= work_done;
+ &work_done, budget);
/* If no Tx and not enough Rx work done, exit the polling mode */
- if ((!tx_cleaned && (work_done == 0)) ||
+ if ((!tx_cleaned && (work_done < budget)) ||
!netif_running(poll_dev)) {
quit_polling:
if (likely(adapter->itr_setting & 3))
e1000_set_itr(adapter);
- netif_rx_complete(poll_dev);
+ netif_rx_complete(poll_dev, napi);
e1000_irq_enable(adapter);
- return 0;
}
- return 1;
+ return work_done;
}
#endif
@@ -4817,6 +4804,7 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
spin_unlock_irqrestore(&adapter->stats_lock, flags);
return -EIO;
}
+ spin_unlock_irqrestore(&adapter->stats_lock, flags);
if (adapter->hw.media_type == e1000_media_type_copper) {
switch (data->reg_num) {
case PHY_CTRL:
@@ -4837,12 +4825,8 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
DUPLEX_HALF;
retval = e1000_set_spd_dplx(adapter,
spddplx);
- if (retval) {
- spin_unlock_irqrestore(
- &adapter->stats_lock,
- flags);
+ if (retval)
return retval;
- }
}
if (netif_running(adapter->netdev))
e1000_reinit_locked(adapter);
@@ -4851,11 +4835,8 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
break;
case M88E1000_PHY_SPEC_CTRL:
case M88E1000_EXT_PHY_SPEC_CTRL:
- if (e1000_phy_reset(&adapter->hw)) {
- spin_unlock_irqrestore(
- &adapter->stats_lock, flags);
+ if (e1000_phy_reset(&adapter->hw))
return -EIO;
- }
break;
}
} else {
@@ -4870,7 +4851,6 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
break;
}
}
- spin_unlock_irqrestore(&adapter->stats_lock, flags);
break;
default:
return -EOPNOTSUPP;
@@ -4912,6 +4892,20 @@ e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
pci_write_config_word(adapter->pdev, reg, *value);
}
+int
+e1000_pcix_get_mmrbc(struct e1000_hw *hw)
+{
+ struct e1000_adapter *adapter = hw->back;
+ return pcix_get_mmrbc(adapter->pdev);
+}
+
+void
+e1000_pcix_set_mmrbc(struct e1000_hw *hw, int mmrbc)
+{
+ struct e1000_adapter *adapter = hw->back;
+ pcix_set_mmrbc(adapter->pdev, mmrbc);
+}
+
int32_t
e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
{
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index f485874a63f..e6565ce686b 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -46,7 +46,7 @@
#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
#define E1000_PARAM(X, desc) \
static int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
- static int num_##X = 0; \
+ static unsigned int num_##X; \
module_param_array_named(X, X, int, &num_##X, 0); \
MODULE_PARM_DESC(X, desc);
@@ -198,9 +198,9 @@ E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
struct e1000_option {
enum { enable_option, range_option, list_option } type;
- char *name;
- char *err;
- int def;
+ const char *name;
+ const char *err;
+ int def;
union {
struct { /* range_option info */
int min;
@@ -214,8 +214,9 @@ struct e1000_option {
};
static int __devinit
-e1000_validate_option(int *value, struct e1000_option *opt,
- struct e1000_adapter *adapter)
+e1000_validate_option(unsigned int *value,
+ const struct e1000_option *opt,
+ struct e1000_adapter *adapter)
{
if (*value == OPTION_UNSET) {
*value = opt->def;
@@ -348,7 +349,7 @@ e1000_check_options(struct e1000_adapter *adapter)
};
if (num_XsumRX > bd) {
- int rx_csum = XsumRX[bd];
+ unsigned int rx_csum = XsumRX[bd];
e1000_validate_option(&rx_csum, &opt, adapter);
adapter->rx_csum = rx_csum;
} else {
@@ -374,7 +375,7 @@ e1000_check_options(struct e1000_adapter *adapter)
};
if (num_FlowControl > bd) {
- int fc = FlowControl[bd];
+ unsigned int fc = FlowControl[bd];
e1000_validate_option(&fc, &opt, adapter);
adapter->hw.fc = adapter->hw.original_fc = fc;
} else {
@@ -506,7 +507,7 @@ e1000_check_options(struct e1000_adapter *adapter)
};
if (num_SmartPowerDownEnable > bd) {
- int spd = SmartPowerDownEnable[bd];
+ unsigned int spd = SmartPowerDownEnable[bd];
e1000_validate_option(&spd, &opt, adapter);
adapter->smart_power_down = spd;
} else {
@@ -522,7 +523,7 @@ e1000_check_options(struct e1000_adapter *adapter)
};
if (num_KumeranLockLoss > bd) {
- int kmrn_lock_loss = KumeranLockLoss[bd];
+ unsigned int kmrn_lock_loss = KumeranLockLoss[bd];
e1000_validate_option(&kmrn_lock_loss, &opt, adapter);
adapter->hw.kmrn_lock_loss_workaround_disabled = !kmrn_lock_loss;
} else {
@@ -581,7 +582,7 @@ e1000_check_fiber_options(struct e1000_adapter *adapter)
static void __devinit
e1000_check_copper_options(struct e1000_adapter *adapter)
{
- int speed, dplx, an;
+ unsigned int speed, dplx, an;
int bd = adapter->bd_number;
{ /* Speed */
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
new file mode 100644
index 00000000000..14141a55eaa
--- /dev/null
+++ b/drivers/net/e1000e/82571.c
@@ -0,0 +1,1351 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/*
+ * 82571EB Gigabit Ethernet Controller
+ * 82571EB Gigabit Ethernet Controller (Fiber)
+ * 82572EI Gigabit Ethernet Controller (Copper)
+ * 82572EI Gigabit Ethernet Controller (Fiber)
+ * 82572EI Gigabit Ethernet Controller
+ * 82573V Gigabit Ethernet Controller (Copper)
+ * 82573E Gigabit Ethernet Controller (Copper)
+ * 82573L Gigabit Ethernet Controller
+ */
+
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "e1000.h"
+
+#define ID_LED_RESERVED_F746 0xF746
+#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_OFF1_ON2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+
+static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
+static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
+static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
+static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
+ u16 words, u16 *data);
+static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
+static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
+static s32 e1000_setup_link_82571(struct e1000_hw *hw);
+static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
+
+/**
+ * e1000_init_phy_params_82571 - Init PHY func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+
+ if (hw->media_type != e1000_media_type_copper) {
+ phy->type = e1000_phy_none;
+ return 0;
+ }
+
+ phy->addr = 1;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->reset_delay_us = 100;
+
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ phy->type = e1000_phy_igp_2;
+ break;
+ case e1000_82573:
+ phy->type = e1000_phy_m88;
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
+
+ /* This can only be done after all function pointers are setup. */
+ ret_val = e1000_get_phy_id_82571(hw);
+
+ /* Verify phy id */
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ if (phy->id != IGP01E1000_I_PHY_ID)
+ return -E1000_ERR_PHY;
+ break;
+ case e1000_82573:
+ if (phy->id != M88E1111_I_PHY_ID)
+ return -E1000_ERR_PHY;
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_init_nvm_params_82571 - Init NVM func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 eecd = er32(EECD);
+ u16 size;
+
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+ switch (nvm->override) {
+ case e1000_nvm_override_spi_large:
+ nvm->page_size = 32;
+ nvm->address_bits = 16;
+ break;
+ case e1000_nvm_override_spi_small:
+ nvm->page_size = 8;
+ nvm->address_bits = 8;
+ break;
+ default:
+ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+ break;
+ }
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+ if (((eecd >> 15) & 0x3) == 0x3) {
+ nvm->type = e1000_nvm_flash_hw;
+ nvm->word_size = 2048;
+ /* Autonomous Flash update bit must be cleared due
+ * to Flash update issue.
+ */
+ eecd &= ~E1000_EECD_AUPDEN;
+ ew32(EECD, eecd);
+ break;
+ }
+ /* Fall Through */
+ default:
+ nvm->type = e1000_nvm_eeprom_spi;
+ size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+ /* Added to a constant, "size" becomes the left-shift value
+ * for setting word_size.
+ */
+ size += NVM_WORD_SIZE_BASE_SHIFT;
+ nvm->word_size = 1 << size;
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_init_mac_params_82571 - Init MAC func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_mac_info *mac = &hw->mac;
+ struct e1000_mac_operations *func = &mac->ops;
+
+ /* Set media type */
+ switch (adapter->pdev->device) {
+ case E1000_DEV_ID_82571EB_FIBER:
+ case E1000_DEV_ID_82572EI_FIBER:
+ case E1000_DEV_ID_82571EB_QUAD_FIBER:
+ hw->media_type = e1000_media_type_fiber;
+ break;
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82572EI_SERDES:
+ hw->media_type = e1000_media_type_internal_serdes;
+ break;
+ default:
+ hw->media_type = e1000_media_type_copper;
+ break;
+ }
+
+ /* Set mta register count */
+ mac->mta_reg_count = 128;
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_RAR_ENTRIES;
+ /* Set if manageability features are enabled. */
+ mac->arc_subsystem_valid =
+ (er32(FWSM) & E1000_FWSM_MODE_MASK) ? 1 : 0;
+
+ /* check for link */
+ switch (hw->media_type) {
+ case e1000_media_type_copper:
+ func->setup_physical_interface = e1000_setup_copper_link_82571;
+ func->check_for_link = e1000e_check_for_copper_link;
+ func->get_link_up_info = e1000e_get_speed_and_duplex_copper;
+ break;
+ case e1000_media_type_fiber:
+ func->setup_physical_interface = e1000_setup_fiber_serdes_link_82571;
+ func->check_for_link = e1000e_check_for_fiber_link;
+ func->get_link_up_info = e1000e_get_speed_and_duplex_fiber_serdes;
+ break;
+ case e1000_media_type_internal_serdes:
+ func->setup_physical_interface = e1000_setup_fiber_serdes_link_82571;
+ func->check_for_link = e1000e_check_for_serdes_link;
+ func->get_link_up_info = e1000e_get_speed_and_duplex_fiber_serdes;
+ break;
+ default:
+ return -E1000_ERR_CONFIG;
+ break;
+ }
+
+ return 0;
+}
+
+static s32 e1000_get_invariants_82571(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ static int global_quad_port_a; /* global port a indication */
+ struct pci_dev *pdev = adapter->pdev;
+ u16 eeprom_data = 0;
+ int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1;
+ s32 rc;
+
+ rc = e1000_init_mac_params_82571(adapter);
+ if (rc)
+ return rc;
+
+ rc = e1000_init_nvm_params_82571(hw);
+ if (rc)
+ return rc;
+
+ rc = e1000_init_phy_params_82571(hw);
+ if (rc)
+ return rc;
+
+ /* tag quad port adapters first, it's used below */
+ switch (pdev->device) {
+ case E1000_DEV_ID_82571EB_QUAD_COPPER:
+ case E1000_DEV_ID_82571EB_QUAD_FIBER:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
+ adapter->flags |= FLAG_IS_QUAD_PORT;
+ /* mark the first port */
+ if (global_quad_port_a == 0)
+ adapter->flags |= FLAG_IS_QUAD_PORT_A;
+ /* Reset for multiple quad port adapters */
+ global_quad_port_a++;
+ if (global_quad_port_a == 4)
+ global_quad_port_a = 0;
+ break;
+ default:
+ break;
+ }
+
+ switch (adapter->hw.mac.type) {
+ case e1000_82571:
+ /* these dual ports don't have WoL on port B at all */
+ if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) ||
+ (pdev->device == E1000_DEV_ID_82571EB_SERDES) ||
+ (pdev->device == E1000_DEV_ID_82571EB_COPPER)) &&
+ (is_port_b))
+ adapter->flags &= ~FLAG_HAS_WOL;
+ /* quad ports only support WoL on port A */
+ if (adapter->flags & FLAG_IS_QUAD_PORT &&
+ (!(adapter->flags & FLAG_IS_QUAD_PORT_A)))
+ adapter->flags &= ~FLAG_HAS_WOL;
+ break;
+
+ case e1000_82573:
+ if (pdev->device == E1000_DEV_ID_82573L) {
+ e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,
+ &eeprom_data);
+ if (eeprom_data & NVM_WORD1A_ASPM_MASK)
+ adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_get_phy_id_82571 - Retrieve the PHY ID and revision
+ * @hw: pointer to the HW structure
+ *
+ * Reads the PHY registers and stores the PHY ID and possibly the PHY
+ * revision in the hardware structure.
+ **/
+static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ /* The 82571 firmware may still be configuring the PHY.
+ * In this case, we cannot access the PHY until the
+ * configuration is done. So we explicitly set the
+ * PHY ID. */
+ phy->id = IGP01E1000_I_PHY_ID;
+ break;
+ case e1000_82573:
+ return e1000e_get_phy_id(hw);
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_get_hw_semaphore_82571 - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM
+ **/
+static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
+{
+ u32 swsm;
+ s32 timeout = hw->nvm.word_size + 1;
+ s32 i = 0;
+
+ /* Get the FW semaphore. */
+ for (i = 0; i < timeout; i++) {
+ swsm = er32(SWSM);
+ ew32(SWSM, swsm | E1000_SWSM_SWESMBI);
+
+ /* Semaphore acquired if bit latched */
+ if (er32(SWSM) & E1000_SWSM_SWESMBI)
+ break;
+
+ udelay(50);
+ }
+
+ if (i == timeout) {
+ /* Release semaphores */
+ e1000e_put_hw_semaphore(hw);
+ hw_dbg(hw, "Driver can't access the NVM\n");
+ return -E1000_ERR_NVM;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_put_hw_semaphore_82571 - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ **/
+static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
+{
+ u32 swsm;
+
+ swsm = er32(SWSM);
+
+ swsm &= ~E1000_SWSM_SWESMBI;
+
+ ew32(SWSM, swsm);
+}
+
+/**
+ * e1000_acquire_nvm_82571 - Request for access to the EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * To gain access to the EEPROM, first we must obtain a hardware semaphore.
+ * Then for non-82573 hardware, set the EEPROM access request bit and wait
+ * for EEPROM access grant bit. If the access grant bit is not set, release
+ * hardware semaphore.
+ **/
+static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
+{
+ s32 ret_val;
+
+ ret_val = e1000_get_hw_semaphore_82571(hw);
+ if (ret_val)
+ return ret_val;
+
+ if (hw->mac.type != e1000_82573)
+ ret_val = e1000e_acquire_nvm(hw);
+
+ if (ret_val)
+ e1000_put_hw_semaphore_82571(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_release_nvm_82571 - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+static void e1000_release_nvm_82571(struct e1000_hw *hw)
+{
+ e1000e_release_nvm(hw);
+ e1000_put_hw_semaphore_82571(hw);
+}
+
+/**
+ * e1000_write_nvm_82571 - Write to EEPROM using appropriate interface
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * For non-82573 silicon, write data to EEPROM at offset using SPI interface.
+ *
+ * If e1000e_update_nvm_checksum is not called after this function, the
+ * EEPROM will most likley contain an invalid checksum.
+ **/
+static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ s32 ret_val;
+
+ switch (hw->mac.type) {
+ case e1000_82573:
+ ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ ret_val = e1000e_write_nvm_spi(hw, offset, words, data);
+ break;
+ default:
+ ret_val = -E1000_ERR_NVM;
+ break;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_update_nvm_checksum_82571 - Update EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ * up to the checksum. Then calculates the EEPROM checksum and writes the
+ * value to the EEPROM.
+ **/
+static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw)
+{
+ u32 eecd;
+ s32 ret_val;
+ u16 i;
+
+ ret_val = e1000e_update_nvm_checksum_generic(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* If our nvm is an EEPROM, then we're done
+ * otherwise, commit the checksum to the flash NVM. */
+ if (hw->nvm.type != e1000_nvm_flash_hw)
+ return ret_val;
+
+ /* Check for pending operations. */
+ for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+ msleep(1);
+ if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
+ break;
+ }
+
+ if (i == E1000_FLASH_UPDATES)
+ return -E1000_ERR_NVM;
+
+ /* Reset the firmware if using STM opcode. */
+ if ((er32(FLOP) & 0xFF00) == E1000_STM_OPCODE) {
+ /* The enabling of and the actual reset must be done
+ * in two write cycles.
+ */
+ ew32(HICR, E1000_HICR_FW_RESET_ENABLE);
+ e1e_flush();
+ ew32(HICR, E1000_HICR_FW_RESET);
+ }
+
+ /* Commit the write to flash */
+ eecd = er32(EECD) | E1000_EECD_FLUPD;
+ ew32(EECD, eecd);
+
+ for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+ msleep(1);
+ if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
+ break;
+ }
+
+ if (i == E1000_FLASH_UPDATES)
+ return -E1000_ERR_NVM;
+
+ return 0;
+}
+
+/**
+ * e1000_validate_nvm_checksum_82571 - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+static s32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw)
+{
+ if (hw->nvm.type == e1000_nvm_flash_hw)
+ e1000_fix_nvm_checksum_82571(hw);
+
+ return e1000e_validate_nvm_checksum_generic(hw);
+}
+
+/**
+ * e1000_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * After checking for invalid values, poll the EEPROM to ensure the previous
+ * command has completed before trying to write the next word. After write
+ * poll for completion.
+ *
+ * If e1000e_update_nvm_checksum is not called after this function, the
+ * EEPROM will most likley contain an invalid checksum.
+ **/
+static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
+ u16 words, u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 i;
+ u32 eewr = 0;
+ s32 ret_val = 0;
+
+ /* A check for invalid values: offset too large, too many words,
+ * and not enough words. */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+ return -E1000_ERR_NVM;
+ }
+
+ for (i = 0; i < words; i++) {
+ eewr = (data[i] << E1000_NVM_RW_REG_DATA) |
+ ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
+ E1000_NVM_RW_REG_START;
+
+ ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+ if (ret_val)
+ break;
+
+ ew32(EEWR, eewr);
+
+ ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+ if (ret_val)
+ break;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_get_cfg_done_82571 - Poll for configuration done
+ * @hw: pointer to the HW structure
+ *
+ * Reads the management control register for the config done bit to be set.
+ **/
+static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw)
+{
+ s32 timeout = PHY_CFG_TIMEOUT;
+
+ while (timeout) {
+ if (er32(EEMNGCTL) &
+ E1000_NVM_CFG_DONE_PORT_0)
+ break;
+ msleep(1);
+ timeout--;
+ }
+ if (!timeout) {
+ hw_dbg(hw, "MNG configuration cycle has not completed.\n");
+ return -E1000_ERR_RESET;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D0 state according to the active flag. When activating LPLU
+ * this function also disables smart speed and vice versa. LPLU will not be
+ * activated unless the device autonegotiation advertisement meets standards
+ * of either 10 or 10/100 or 10/100/1000 at all duplexes. This is a function
+ * pointer entry point only called by PHY setup routines.
+ **/
+static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+
+ ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+ if (ret_val)
+ return ret_val;
+
+ if (active) {
+ data |= IGP02E1000_PM_D0_LPLU;
+ ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
+ if (ret_val)
+ return ret_val;
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
+ if (ret_val)
+ return ret_val;
+ } else {
+ data &= ~IGP02E1000_PM_D0_LPLU;
+ ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained. */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_reset_hw_82571 - Reset hardware
+ * @hw: pointer to the HW structure
+ *
+ * This resets the hardware into a known state. This is a
+ * function pointer entry point called by the api module.
+ **/
+static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ u32 extcnf_ctrl;
+ u32 ctrl_ext;
+ u32 icr;
+ s32 ret_val;
+ u16 i = 0;
+
+ /* Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000e_disable_pcie_master(hw);
+ if (ret_val)
+ hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+
+ hw_dbg(hw, "Masking off all interrupts\n");
+ ew32(IMC, 0xffffffff);
+
+ ew32(RCTL, 0);
+ ew32(TCTL, E1000_TCTL_PSP);
+ e1e_flush();
+
+ msleep(10);
+
+ /* Must acquire the MDIO ownership before MAC reset.
+ * Ownership defaults to firmware after a reset. */
+ if (hw->mac.type == e1000_82573) {
+ extcnf_ctrl = er32(EXTCNF_CTRL);
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+ do {
+ ew32(EXTCNF_CTRL, extcnf_ctrl);
+ extcnf_ctrl = er32(EXTCNF_CTRL);
+
+ if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+ break;
+
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+ msleep(2);
+ i++;
+ } while (i < MDIO_OWNERSHIP_TIMEOUT);
+ }
+
+ ctrl = er32(CTRL);
+
+ hw_dbg(hw, "Issuing a global reset to MAC\n");
+ ew32(CTRL, ctrl | E1000_CTRL_RST);
+
+ if (hw->nvm.type == e1000_nvm_flash_hw) {
+ udelay(10);
+ ctrl_ext = er32(CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ ew32(CTRL_EXT, ctrl_ext);
+ e1e_flush();
+ }
+
+ ret_val = e1000e_get_auto_rd_done(hw);
+ if (ret_val)
+ /* We don't want to continue accessing MAC registers. */
+ return ret_val;
+
+ /* Phy configuration from NVM just starts after EECD_AUTO_RD is set.
+ * Need to wait for Phy configuration completion before accessing
+ * NVM and Phy.
+ */
+ if (hw->mac.type == e1000_82573)
+ msleep(25);
+
+ /* Clear any pending interrupt events. */
+ ew32(IMC, 0xffffffff);
+ icr = er32(ICR);
+
+ return 0;
+}
+
+/**
+ * e1000_init_hw_82571 - Initialize hardware
+ * @hw: pointer to the HW structure
+ *
+ * This inits the hardware readying it for operation.
+ **/
+static s32 e1000_init_hw_82571(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 reg_data;
+ s32 ret_val;
+ u16 i;
+ u16 rar_count = mac->rar_entry_count;
+
+ e1000_initialize_hw_bits_82571(hw);
+
+ /* Initialize identification LED */
+ ret_val = e1000e_id_led_init(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error initializing identification LED\n");
+ return ret_val;
+ }
+
+ /* Disabling VLAN filtering */
+ hw_dbg(hw, "Initializing the IEEE VLAN\n");
+ e1000e_clear_vfta(hw);
+
+ /* Setup the receive address. */
+ /* If, however, a locally administered address was assigned to the
+ * 82571, we must reserve a RAR for it to work around an issue where
+ * resetting one port will reload the MAC on the other port.
+ */
+ if (e1000e_get_laa_state_82571(hw))
+ rar_count--;
+ e1000e_init_rx_addrs(hw, rar_count);
+
+ /* Zero out the Multicast HASH table */
+ hw_dbg(hw, "Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+ /* Setup link and flow control */
+ ret_val = e1000_setup_link_82571(hw);
+
+ /* Set the transmit descriptor write-back policy */
+ reg_data = er32(TXDCTL);
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB |
+ E1000_TXDCTL_COUNT_DESC;
+ ew32(TXDCTL, reg_data);
+
+ /* ...for both queues. */
+ if (mac->type != e1000_82573) {
+ reg_data = er32(TXDCTL1);
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB |
+ E1000_TXDCTL_COUNT_DESC;
+ ew32(TXDCTL1, reg_data);
+ } else {
+ e1000e_enable_tx_pkt_filtering(hw);
+ reg_data = er32(GCR);
+ reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+ ew32(GCR, reg_data);
+ }
+
+ /* Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_82571(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_initialize_hw_bits_82571 - Initialize hardware-dependent bits
+ * @hw: pointer to the HW structure
+ *
+ * Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
+{
+ u32 reg;
+
+ /* Transmit Descriptor Control 0 */
+ reg = er32(TXDCTL);
+ reg |= (1 << 22);
+ ew32(TXDCTL, reg);
+
+ /* Transmit Descriptor Control 1 */
+ reg = er32(TXDCTL1);
+ reg |= (1 << 22);
+ ew32(TXDCTL1, reg);
+
+ /* Transmit Arbitration Control 0 */
+ reg = er32(TARC0);
+ reg &= ~(0xF << 27); /* 30:27 */
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26);
+ break;
+ default:
+ break;
+ }
+ ew32(TARC0, reg);
+
+ /* Transmit Arbitration Control 1 */
+ reg = er32(TARC1);
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ reg &= ~((1 << 29) | (1 << 30));
+ reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26);
+ if (er32(TCTL) & E1000_TCTL_MULR)
+ reg &= ~(1 << 28);
+ else
+ reg |= (1 << 28);
+ ew32(TARC1, reg);
+ break;
+ default:
+ break;
+ }
+
+ /* Device Control */
+ if (hw->mac.type == e1000_82573) {
+ reg = er32(CTRL);
+ reg &= ~(1 << 29);
+ ew32(CTRL, reg);
+ }
+
+ /* Extended Device Control */
+ if (hw->mac.type == e1000_82573) {
+ reg = er32(CTRL_EXT);
+ reg &= ~(1 << 23);
+ reg |= (1 << 22);
+ ew32(CTRL_EXT, reg);
+ }
+}
+
+/**
+ * e1000e_clear_vfta - Clear VLAN filter table
+ * @hw: pointer to the HW structure
+ *
+ * Clears the register array which contains the VLAN filter table by
+ * setting all the values to 0.
+ **/
+void e1000e_clear_vfta(struct e1000_hw *hw)
+{
+ u32 offset;
+ u32 vfta_value = 0;
+ u32 vfta_offset = 0;
+ u32 vfta_bit_in_reg = 0;
+
+ if (hw->mac.type == e1000_82573) {
+ if (hw->mng_cookie.vlan_id != 0) {
+ /* The VFTA is a 4096b bit-field, each identifying
+ * a single VLAN ID. The following operations
+ * determine which 32b entry (i.e. offset) into the
+ * array we want to set the VLAN ID (i.e. bit) of
+ * the manageability unit.
+ */
+ vfta_offset = (hw->mng_cookie.vlan_id >>
+ E1000_VFTA_ENTRY_SHIFT) &
+ E1000_VFTA_ENTRY_MASK;
+ vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
+ E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+ }
+ }
+ for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+ /* If the offset we want to clear is the same offset of the
+ * manageability VLAN ID, then clear all bits except that of
+ * the manageability unit.
+ */
+ vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
+ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value);
+ e1e_flush();
+ }
+}
+
+/**
+ * e1000_mc_addr_list_update_82571 - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ * @rar_used_count: the first RAR register free to program
+ * @rar_count: total number of supported Receive Address Registers
+ *
+ * Updates the Receive Address Registers and Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ * The parameter rar_count will usually be hw->mac.rar_entry_count
+ * unless there are workarounds that change this.
+ **/
+static void e1000_mc_addr_list_update_82571(struct e1000_hw *hw,
+ u8 *mc_addr_list,
+ u32 mc_addr_count,
+ u32 rar_used_count,
+ u32 rar_count)
+{
+ if (e1000e_get_laa_state_82571(hw))
+ rar_count--;
+
+ e1000e_mc_addr_list_update_generic(hw, mc_addr_list, mc_addr_count,
+ rar_used_count, rar_count);
+}
+
+/**
+ * e1000_setup_link_82571 - Setup flow control and link settings
+ * @hw: pointer to the HW structure
+ *
+ * Determines which flow control settings to use, then configures flow
+ * control. Calls the appropriate media-specific link configuration
+ * function. Assuming the adapter has a valid link partner, a valid link
+ * should be established. Assumes the hardware has previously been reset
+ * and the transmitter and receiver are not enabled.
+ **/
+static s32 e1000_setup_link_82571(struct e1000_hw *hw)
+{
+ /* 82573 does not have a word in the NVM to determine
+ * the default flow control setting, so we explicitly
+ * set it to full.
+ */
+ if (hw->mac.type == e1000_82573)
+ hw->mac.fc = e1000_fc_full;
+
+ return e1000e_setup_link(hw);
+}
+
+/**
+ * e1000_setup_copper_link_82571 - Configure copper link settings
+ * @hw: pointer to the HW structure
+ *
+ * Configures the link for auto-neg or forced speed and duplex. Then we check
+ * for link, once link is established calls to configure collision distance
+ * and flow control are called.
+ **/
+static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ u32 led_ctrl;
+ s32 ret_val;
+
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ew32(CTRL, ctrl);
+
+ switch (hw->phy.type) {
+ case e1000_phy_m88:
+ ret_val = e1000e_copper_link_setup_m88(hw);
+ break;
+ case e1000_phy_igp_2:
+ ret_val = e1000e_copper_link_setup_igp(hw);
+ /* Setup activity LED */
+ led_ctrl = er32(LEDCTL);
+ led_ctrl &= IGP_ACTIVITY_LED_MASK;
+ led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+ ew32(LEDCTL, led_ctrl);
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
+
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000e_setup_copper_link(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes
+ * @hw: pointer to the HW structure
+ *
+ * Configures collision distance and flow control for fiber and serdes links.
+ * Upon successful setup, poll for link.
+ **/
+static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw)
+{
+ switch (hw->mac.type) {
+ case e1000_82571:
+ case e1000_82572:
+ /* If SerDes loopback mode is entered, there is no form
+ * of reset to take the adapter out of that mode. So we
+ * have to explicitly take the adapter out of loopback
+ * mode. This prevents drivers from twidling their thumbs
+ * if another tool failed to take it out of loopback mode.
+ */
+ ew32(SCTL,
+ E1000_SCTL_DISABLE_SERDES_LOOPBACK);
+ break;
+ default:
+ break;
+ }
+
+ return e1000e_setup_fiber_serdes_link(hw);
+}
+
+/**
+ * e1000_valid_led_default_82571 - Verify a valid default LED config
+ * @hw: pointer to the HW structure
+ * @data: pointer to the NVM (EEPROM)
+ *
+ * Read the EEPROM for the current default LED configuration. If the
+ * LED configuration is not valid, set to a valid LED configuration.
+ **/
+static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data)
+{
+ s32 ret_val;
+
+ ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+
+ if (hw->mac.type == e1000_82573 &&
+ *data == ID_LED_RESERVED_F746)
+ *data = ID_LED_DEFAULT_82573;
+ else if (*data == ID_LED_RESERVED_0000 ||
+ *data == ID_LED_RESERVED_FFFF)
+ *data = ID_LED_DEFAULT;
+
+ return 0;
+}
+
+/**
+ * e1000e_get_laa_state_82571 - Get locally administered address state
+ * @hw: pointer to the HW structure
+ *
+ * Retrieve and return the current locally administed address state.
+ **/
+bool e1000e_get_laa_state_82571(struct e1000_hw *hw)
+{
+ if (hw->mac.type != e1000_82571)
+ return 0;
+
+ return hw->dev_spec.e82571.laa_is_present;
+}
+
+/**
+ * e1000e_set_laa_state_82571 - Set locally administered address state
+ * @hw: pointer to the HW structure
+ * @state: enable/disable locally administered address
+ *
+ * Enable/Disable the current locally administed address state.
+ **/
+void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state)
+{
+ if (hw->mac.type != e1000_82571)
+ return;
+
+ hw->dev_spec.e82571.laa_is_present = state;
+
+ /* If workaround is activated... */
+ if (state)
+ /* Hold a copy of the LAA in RAR[14] This is done so that
+ * between the time RAR[0] gets clobbered and the time it
+ * gets fixed, the actual LAA is in one of the RARs and no
+ * incoming packets directed to this port are dropped.
+ * Eventually the LAA will be in RAR[0] and RAR[14].
+ */
+ e1000e_rar_set(hw, hw->mac.addr, hw->mac.rar_entry_count - 1);
+}
+
+/**
+ * e1000_fix_nvm_checksum_82571 - Fix EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Verifies that the EEPROM has completed the update. After updating the
+ * EEPROM, we need to check bit 15 in work 0x23 for the checksum fix. If
+ * the checksum fix is not implemented, we need to set the bit and update
+ * the checksum. Otherwise, if bit 15 is set and the checksum is incorrect,
+ * we need to return bad checksum.
+ **/
+static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ s32 ret_val;
+ u16 data;
+
+ if (nvm->type != e1000_nvm_flash_hw)
+ return 0;
+
+ /* Check bit 4 of word 10h. If it is 0, firmware is done updating
+ * 10h-12h. Checksum may need to be fixed.
+ */
+ ret_val = e1000_read_nvm(hw, 0x10, 1, &data);
+ if (ret_val)
+ return ret_val;
+
+ if (!(data & 0x10)) {
+ /* Read 0x23 and check bit 15. This bit is a 1
+ * when the checksum has already been fixed. If
+ * the checksum is still wrong and this bit is a
+ * 1, we need to return bad checksum. Otherwise,
+ * we need to set this bit to a 1 and update the
+ * checksum.
+ */
+ ret_val = e1000_read_nvm(hw, 0x23, 1, &data);
+ if (ret_val)
+ return ret_val;
+
+ if (!(data & 0x8000)) {
+ data |= 0x8000;
+ ret_val = e1000_write_nvm(hw, 0x23, 1, &data);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000e_update_nvm_checksum(hw);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_clear_hw_cntrs_82571 - Clear device specific hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw)
+{
+ u32 temp;
+
+ e1000e_clear_hw_cntrs_base(hw);
+
+ temp = er32(PRC64);
+ temp = er32(PRC127);
+ temp = er32(PRC255);
+ temp = er32(PRC511);
+ temp = er32(PRC1023);
+ temp = er32(PRC1522);
+ temp = er32(PTC64);
+ temp = er32(PTC127);
+ temp = er32(PTC255);
+ temp = er32(PTC511);
+ temp = er32(PTC1023);
+ temp = er32(PTC1522);
+
+ temp = er32(ALGNERRC);
+ temp = er32(RXERRC);
+ temp = er32(TNCRS);
+ temp = er32(CEXTERR);
+ temp = er32(TSCTC);
+ temp = er32(TSCTFC);
+
+ temp = er32(MGTPRC);
+ temp = er32(MGTPDC);
+ temp = er32(MGTPTC);
+
+ temp = er32(IAC);
+ temp = er32(ICRXOC);
+
+ temp = er32(ICRXPTC);
+ temp = er32(ICRXATC);
+ temp = er32(ICTXPTC);
+ temp = er32(ICTXATC);
+ temp = er32(ICTXQEC);
+ temp = er32(ICTXQMTC);
+ temp = er32(ICRXDMTC);
+}
+
+static struct e1000_mac_operations e82571_mac_ops = {
+ .mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+ /* .check_for_link: media type dependent */
+ .cleanup_led = e1000e_cleanup_led_generic,
+ .clear_hw_cntrs = e1000_clear_hw_cntrs_82571,
+ .get_bus_info = e1000e_get_bus_info_pcie,
+ /* .get_link_up_info: media type dependent */
+ .led_on = e1000e_led_on_generic,
+ .led_off = e1000e_led_off_generic,
+ .mc_addr_list_update = e1000_mc_addr_list_update_82571,
+ .reset_hw = e1000_reset_hw_82571,
+ .init_hw = e1000_init_hw_82571,
+ .setup_link = e1000_setup_link_82571,
+ /* .setup_physical_interface: media type dependent */
+};
+
+static struct e1000_phy_operations e82_phy_ops_igp = {
+ .acquire_phy = e1000_get_hw_semaphore_82571,
+ .check_reset_block = e1000e_check_reset_block_generic,
+ .commit_phy = NULL,
+ .force_speed_duplex = e1000e_phy_force_speed_duplex_igp,
+ .get_cfg_done = e1000_get_cfg_done_82571,
+ .get_cable_length = e1000e_get_cable_length_igp_2,
+ .get_phy_info = e1000e_get_phy_info_igp,
+ .read_phy_reg = e1000e_read_phy_reg_igp,
+ .release_phy = e1000_put_hw_semaphore_82571,
+ .reset_phy = e1000e_phy_hw_reset_generic,
+ .set_d0_lplu_state = e1000_set_d0_lplu_state_82571,
+ .set_d3_lplu_state = e1000e_set_d3_lplu_state,
+ .write_phy_reg = e1000e_write_phy_reg_igp,
+};
+
+static struct e1000_phy_operations e82_phy_ops_m88 = {
+ .acquire_phy = e1000_get_hw_semaphore_82571,
+ .check_reset_block = e1000e_check_reset_block_generic,
+ .commit_phy = e1000e_phy_sw_reset,
+ .force_speed_duplex = e1000e_phy_force_speed_duplex_m88,
+ .get_cfg_done = e1000e_get_cfg_done,
+ .get_cable_length = e1000e_get_cable_length_m88,
+ .get_phy_info = e1000e_get_phy_info_m88,
+ .read_phy_reg = e1000e_read_phy_reg_m88,
+ .release_phy = e1000_put_hw_semaphore_82571,
+ .reset_phy = e1000e_phy_hw_reset_generic,
+ .set_d0_lplu_state = e1000_set_d0_lplu_state_82571,
+ .set_d3_lplu_state = e1000e_set_d3_lplu_state,
+ .write_phy_reg = e1000e_write_phy_reg_m88,
+};
+
+static struct e1000_nvm_operations e82571_nvm_ops = {
+ .acquire_nvm = e1000_acquire_nvm_82571,
+ .read_nvm = e1000e_read_nvm_spi,
+ .release_nvm = e1000_release_nvm_82571,
+ .update_nvm = e1000_update_nvm_checksum_82571,
+ .valid_led_default = e1000_valid_led_default_82571,
+ .validate_nvm = e1000_validate_nvm_checksum_82571,
+ .write_nvm = e1000_write_nvm_82571,
+};
+
+static struct e1000_nvm_operations e82573_nvm_ops = {
+ .acquire_nvm = e1000_acquire_nvm_82571,
+ .read_nvm = e1000e_read_nvm_eerd,
+ .release_nvm = e1000_release_nvm_82571,
+ .update_nvm = e1000_update_nvm_checksum_82571,
+ .valid_led_default = e1000_valid_led_default_82571,
+ .validate_nvm = e1000_validate_nvm_checksum_82571,
+ .write_nvm = e1000_write_nvm_82571,
+};
+
+struct e1000_info e1000_82571_info = {
+ .mac = e1000_82571,
+ .flags = FLAG_HAS_HW_VLAN_FILTER
+ | FLAG_HAS_JUMBO_FRAMES
+ | FLAG_HAS_STATS_PTC_PRC
+ | FLAG_HAS_WOL
+ | FLAG_APME_IN_CTRL3
+ | FLAG_RX_CSUM_ENABLED
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_STATS_ICR_ICT
+ | FLAG_HAS_SMART_POWER_DOWN
+ | FLAG_RESET_OVERWRITES_LAA /* errata */
+ | FLAG_TARC_SPEED_MODE_BIT /* errata */
+ | FLAG_APME_CHECK_PORT_B,
+ .pba = 38,
+ .get_invariants = e1000_get_invariants_82571,
+ .mac_ops = &e82571_mac_ops,
+ .phy_ops = &e82_phy_ops_igp,
+ .nvm_ops = &e82571_nvm_ops,
+};
+
+struct e1000_info e1000_82572_info = {
+ .mac = e1000_82572,
+ .flags = FLAG_HAS_HW_VLAN_FILTER
+ | FLAG_HAS_JUMBO_FRAMES
+ | FLAG_HAS_STATS_PTC_PRC
+ | FLAG_HAS_WOL
+ | FLAG_APME_IN_CTRL3
+ | FLAG_RX_CSUM_ENABLED
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_STATS_ICR_ICT
+ | FLAG_TARC_SPEED_MODE_BIT, /* errata */
+ .pba = 38,
+ .get_invariants = e1000_get_invariants_82571,
+ .mac_ops = &e82571_mac_ops,
+ .phy_ops = &e82_phy_ops_igp,
+ .nvm_ops = &e82571_nvm_ops,
+};
+
+struct e1000_info e1000_82573_info = {
+ .mac = e1000_82573,
+ .flags = FLAG_HAS_HW_VLAN_FILTER
+ | FLAG_HAS_JUMBO_FRAMES
+ | FLAG_HAS_STATS_PTC_PRC
+ | FLAG_HAS_WOL
+ | FLAG_APME_IN_CTRL3
+ | FLAG_RX_CSUM_ENABLED
+ | FLAG_HAS_STATS_ICR_ICT
+ | FLAG_HAS_SMART_POWER_DOWN
+ | FLAG_HAS_AMT
+ | FLAG_HAS_ASPM
+ | FLAG_HAS_ERT
+ | FLAG_HAS_SWSM_ON_LOAD,
+ .pba = 20,
+ .get_invariants = e1000_get_invariants_82571,
+ .mac_ops = &e82571_mac_ops,
+ .phy_ops = &e82_phy_ops_m88,
+ .nvm_ops = &e82573_nvm_ops,
+};
+
diff --git a/drivers/net/e1000e/Makefile b/drivers/net/e1000e/Makefile
new file mode 100644
index 00000000000..650f866e7ac
--- /dev/null
+++ b/drivers/net/e1000e/Makefile
@@ -0,0 +1,37 @@
+################################################################################
+#
+# Intel PRO/1000 Linux driver
+# Copyright(c) 1999 - 2007 Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# Linux NICS <linux.nics@intel.com>
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) PRO/1000 ethernet driver
+#
+
+obj-$(CONFIG_E1000E) += e1000e.o
+
+e1000e-objs := 82571.o ich8lan.o es2lan.o \
+ lib.o phy.o param.o ethtool.o netdev.o
+
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
new file mode 100644
index 00000000000..b32ed45b4b3
--- /dev/null
+++ b/drivers/net/e1000e/defines.h
@@ -0,0 +1,739 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_DEFINES_H_
+#define _E1000_DEFINES_H_
+
+#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE 8
+#define REQ_RX_DESCRIPTOR_MULTIPLE 8
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME 0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000
+#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
+#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
+#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
+
+/* Receive Decriptor bit definitions */
+#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
+#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */
+#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */
+#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */
+#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */
+#define E1000_RXD_ERR_CE 0x01 /* CRC Error */
+#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */
+#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */
+#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */
+
+#define E1000_RXDEXT_STATERR_CE 0x01000000
+#define E1000_RXDEXT_STATERR_SE 0x02000000
+#define E1000_RXDEXT_STATERR_SEQ 0x04000000
+#define E1000_RXDEXT_STATERR_CXE 0x10000000
+#define E1000_RXDEXT_STATERR_RXE 0x80000000
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+ E1000_RXD_ERR_CE | \
+ E1000_RXD_ERR_SE | \
+ E1000_RXD_ERR_SEQ | \
+ E1000_RXD_ERR_CXE | \
+ E1000_RXD_ERR_RXE)
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+ E1000_RXDEXT_STATERR_CE | \
+ E1000_RXDEXT_STATERR_SE | \
+ E1000_RXDEXT_STATERR_SEQ | \
+ E1000_RXDEXT_STATERR_CXE | \
+ E1000_RXDEXT_STATERR_RXE)
+
+#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */
+#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */
+#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 /* Enable MAC address
+ * filtering */
+#define E1000_MANC_EN_MNG2HOST 0x00200000 /* Enable MNG packets to host
+ * memory */
+
+/* Receive Control */
+#define E1000_RCTL_EN 0x00000002 /* enable */
+#define E1000_RCTL_SBP 0x00000004 /* store bad packet */
+#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */
+#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */
+#define E1000_RCTL_LPE 0x00000020 /* long packet enable */
+#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */
+#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */
+#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */
+#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */
+#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */
+#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */
+#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */
+#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */
+#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */
+
+/* Use byte values for the following shift parameters
+ * Usage:
+ * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ * E1000_PSRCTL_BSIZE0_MASK) |
+ * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ * E1000_PSRCTL_BSIZE1_MASK) |
+ * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ * E1000_PSRCTL_BSIZE2_MASK) |
+ * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ * E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256], default=256
+ * value1 = [1024..64512], default=4096
+ * value2 = [0..64512], default=4096
+ * value3 = [0..64512], default=0
+ */
+
+#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */
+
+/* SWFW_SYNC Definitions */
+#define E1000_SWFW_EEP_SM 0x1
+#define E1000_SWFW_PHY0_SM 0x2
+#define E1000_SWFW_PHY1_SM 0x4
+
+/* Device Control */
+#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
+#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */
+#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */
+#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */
+#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */
+#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */
+#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */
+#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */
+#define E1000_CTRL_RST 0x04000000 /* Global reset */
+#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
+#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+
+/* Device Status */
+#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */
+#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */
+#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+
+#define ADVERTISE_10_HALF 0x0001
+#define ADVERTISE_10_FULL 0x0002
+#define ADVERTISE_100_HALF 0x0004
+#define ADVERTISE_100_FULL 0x0008
+#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL 0x0020
+
+/* 1000/H is not supported, nor spec-compliant. */
+#define E1000_ALL_SPEED_DUPLEX ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
+ ADVERTISE_100_HALF | ADVERTISE_100_FULL | \
+ ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG ( ADVERTISE_10_HALF | ADVERTISE_10_FULL | \
+ ADVERTISE_100_HALF | ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL)
+#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF)
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT 0
+#define E1000_LEDCTL_LED0_IVRT 0x00000040
+#define E1000_LEDCTL_LED0_BLINK 0x00000080
+
+#define E1000_LEDCTL_MODE_LED_ON 0xE
+#define E1000_LEDCTL_MODE_LED_OFF 0xF
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */
+#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */
+
+/* Transmit Control */
+#define E1000_TCTL_EN 0x00000002 /* enable tx */
+#define E1000_TCTL_PSP 0x00000008 /* pad short packets */
+#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */
+#define E1000_TCTL_COLD 0x003ff000 /* collision distance */
+#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */
+#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */
+
+/* Transmit Arbitration Count */
+
+/* SerDes Control */
+#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */
+
+/* Header split receive */
+#define E1000_RFCTL_EXTEN 0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS 0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD 15
+#define E1000_CT_SHIFT 4
+#define E1000_COLLISION_DISTANCE 63
+#define E1000_COLD_SHIFT 12
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK 0x000003FF
+
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT 10
+
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
+#define E1000_TIPG_IPGR2_SHIFT 20
+
+#define MAX_JUMBO_FRAME_SIZE 0x3F00
+
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001
+#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16
+
+#define E1000_PHY_CTRL_D0A_LPLU 0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040
+
+#define E1000_KABGTXD_BGSQLBIAS 0x00050000
+
+/* PBA constants */
+#define E1000_PBA_8K 0x0008 /* 8KB, default Rx allocation */
+#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */
+
+#define E1000_PBS_16K E1000_PBA_16K
+
+#define IFS_MAX 80
+#define IFS_MIN 40
+#define IFS_RATIO 4
+#define IFS_STEP 10
+#define MIN_NUM_XMITS 1000
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */
+#define E1000_ICR_LSC 0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register. Each bit is documented below:
+ * o RXT0 = Receiver Timer Interrupt (ring 0)
+ * o TXDW = Transmit Descriptor Written Back
+ * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ * o RXSEQ = Receive Sequence Error
+ * o LSC = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+ E1000_IMS_RXT0 | \
+ E1000_IMS_TXDW | \
+ E1000_IMS_RXDMT0 | \
+ E1000_IMS_RXSEQ | \
+ E1000_IMS_LSC)
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
+#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */
+#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */
+
+/* Interrupt Cause Set */
+#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */
+#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc.
+ still to be processed. */
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE 0x8808
+
+/* 802.1q VLAN Packet Size */
+#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
+
+/* Receive Address */
+/* Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * Technically, we have 16 spots. However, we reserve one of these spots
+ * (RAR[15]) for our directed address used by controllers with
+ * manageability enabled, allowing us room for 15 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES 15
+#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */
+
+/* Error Codes */
+#define E1000_ERR_NVM 1
+#define E1000_ERR_PHY 2
+#define E1000_ERR_CONFIG 3
+#define E1000_ERR_PARAM 4
+#define E1000_ERR_MAC_INIT 5
+#define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET 9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET 12
+#define E1000_ERR_SWFW_SYNC 13
+#define E1000_NOT_IMPLEMENTED 14
+
+/* Loop limit on how long we wait for auto-negotiation to complete */
+#define FIBER_LINK_UP_LIMIT 50
+#define COPPER_LINK_UP_LIMIT 10
+#define PHY_AUTO_NEG_LIMIT 45
+#define PHY_FORCE_LIMIT 20
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT 800
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT 100
+/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
+#define MDIO_OWNERSHIP_TIMEOUT 10
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT 10
+
+/* Flow Control */
+#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */
+#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */
+#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */
+#define E1000_RXCW_C 0x20000000 /* Receive config */
+#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */
+
+/* PCI Express Control */
+#define E1000_GCR_RXD_NO_SNOOP 0x00000001
+#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002
+#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004
+#define E1000_GCR_TXD_NO_SNOOP 0x00000008
+#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010
+#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020
+
+#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \
+ E1000_GCR_RXDSCW_NO_SNOOP | \
+ E1000_GCR_RXDSCR_NO_SNOOP | \
+ E1000_GCR_TXD_NO_SNOOP | \
+ E1000_GCR_TXDSCW_NO_SNOOP | \
+ E1000_GCR_TXDSCR_NO_SNOOP)
+
+/* PHY Control Register */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000 0x0040
+#define MII_CR_SPEED_100 0x2000
+#define MII_CR_SPEED_10 0x0000
+
+/* PHY Status Register */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */
+#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */
+#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
+
+/* Autoneg Expansion Register */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */
+ /* 0=DTE device */
+#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */
+ /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */
+ /* 0=Automatic Master/Slave config */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */
+
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL 0x00 /* Control Register */
+#define PHY_STATUS 0x01 /* Status Regiser */
+#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */
+#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+
+/* NVM Control */
+#define E1000_EECD_SK 0x00000001 /* NVM Clock */
+#define E1000_EECD_CS 0x00000002 /* NVM Chip Select */
+#define E1000_EECD_DI 0x00000004 /* NVM Data In */
+#define E1000_EECD_DO 0x00000008 /* NVM Data Out */
+#define E1000_EECD_REQ 0x00000040 /* NVM Access Request */
+#define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */
+#define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */
+#define E1000_EECD_ADDR_BITS 0x00000400 /* NVM Addressing bits based on type
+ * (0-small, 1-large) */
+#define E1000_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */
+#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */
+#define E1000_EECD_SIZE_EX_SHIFT 11
+#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
+
+#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write registers */
+#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */
+#define E1000_NVM_RW_REG_START 1 /* Start operation */
+#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */
+#define E1000_NVM_POLL_WRITE 1 /* Flag for polling for write complete */
+#define E1000_NVM_POLL_READ 0 /* Flag for polling for read complete */
+#define E1000_FLASH_UPDATES 2000
+
+/* NVM Word Offsets */
+#define NVM_ID_LED_SETTINGS 0x0004
+#define NVM_INIT_CONTROL2_REG 0x000F
+#define NVM_INIT_CONTROL3_PORT_B 0x0014
+#define NVM_INIT_3GIO_3 0x001A
+#define NVM_INIT_CONTROL3_PORT_A 0x0024
+#define NVM_CFG 0x0012
+#define NVM_CHECKSUM_REG 0x003F
+
+#define E1000_NVM_CFG_DONE_PORT_0 0x40000 /* MNG config cycle done */
+#define E1000_NVM_CFG_DONE_PORT_1 0x80000 /* ...for second port */
+
+/* Mask bits for fields in Word 0x0f of the NVM */
+#define NVM_WORD0F_PAUSE_MASK 0x3000
+#define NVM_WORD0F_PAUSE 0x1000
+#define NVM_WORD0F_ASM_DIR 0x2000
+
+/* Mask bits for fields in Word 0x1a of the NVM */
+#define NVM_WORD1A_ASPM_MASK 0x000C
+
+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
+#define NVM_SUM 0xBABA
+
+/* PBA (printed board assembly) number words */
+#define NVM_PBA_OFFSET_0 8
+#define NVM_PBA_OFFSET_1 9
+
+#define NVM_WORD_SIZE_BASE_SHIFT 6
+
+/* NVM Commands - SPI */
+#define NVM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */
+#define NVM_READ_OPCODE_SPI 0x03 /* NVM read opcode */
+#define NVM_WRITE_OPCODE_SPI 0x02 /* NVM write opcode */
+#define NVM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */
+#define NVM_WREN_OPCODE_SPI 0x06 /* NVM set Write Enable latch */
+#define NVM_RDSR_OPCODE_SPI 0x05 /* NVM read Status register */
+
+/* SPI NVM Status Register */
+#define NVM_STATUS_RDY_SPI 0x01
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \
+ (ID_LED_OFF1_OFF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2 0x1
+#define ID_LED_DEF1_ON2 0x2
+#define ID_LED_DEF1_OFF2 0x3
+#define ID_LED_ON1_DEF2 0x4
+#define ID_LED_ON1_ON2 0x5
+#define ID_LED_ON1_OFF2 0x6
+#define ID_LED_OFF1_DEF2 0x7
+#define ID_LED_OFF1_ON2 0x8
+#define ID_LED_OFF1_OFF2 0x9
+
+#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE 0x07000000
+
+/* PCI/PCI-X/PCI-EX Config space */
+#define PCI_HEADER_TYPE_REGISTER 0x0E
+#define PCIE_LINK_STATUS 0x12
+
+#define PCI_HEADER_TYPE_MULTIFUNC 0x80
+#define PCIE_LINK_WIDTH_MASK 0x3F0
+#define PCIE_LINK_WIDTH_SHIFT 4
+
+#define PHY_REVISION_MASK 0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF
+
+/* Bit definitions for valid PHY IDs. */
+/* I = Integrated
+ * E = External
+ */
+#define M88E1000_E_PHY_ID 0x01410C50
+#define M88E1000_I_PHY_ID 0x01410C30
+#define M88E1011_I_PHY_ID 0x01410C20
+#define IGP01E1000_I_PHY_ID 0x02A80380
+#define M88E1111_I_PHY_ID 0x01410CC0
+#define GG82563_E_PHY_ID 0x01410CA0
+#define IGP03E1000_E_PHY_ID 0x02A80390
+#define IFE_E_PHY_ID 0x02A80330
+#define IFE_PLUS_E_PHY_ID 0x02A80320
+#define IFE_C_E_PHY_ID 0x02A80310
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
+
+#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */
+ /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */
+#define M88E1000_PSCR_AUTO_X_1000T 0x0040 /* 1000BASE-T: Auto crossover,
+ * 100BASE-TX/10BASE-T:
+ * MDI Mode
+ */
+#define M88E1000_PSCR_AUTO_X_MODE 0x0060 /* Auto crossover enabled
+ * all speeds.
+ */
+ /* 1=Enable Extended 10BASE-T distance
+ * (Lower 10BASE-T RX Threshold)
+ * 0=Normal 10BASE-T RX Threshold */
+ /* 1=5-Bit interface in 100BASE-TX
+ * 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */
+#define M88E1000_PSSR_CABLE_LENGTH 0x0380 /* 0=<50M;1=50-80M;2=80-110M;
+ * 3=110-140M;4=>140M */
+#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100
+#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
+
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800
+
+/* Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define GG82563_PAGE_SHIFT 5
+#define GG82563_REG(page, reg) \
+ (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+#define GG82563_MIN_ALT_REG 30
+
+/* GG82563 Specific Registers */
+#define GG82563_PHY_SPEC_CTRL \
+ GG82563_REG(0, 16) /* PHY Specific Control */
+#define GG82563_PHY_PAGE_SELECT \
+ GG82563_REG(0, 22) /* Page Select */
+#define GG82563_PHY_SPEC_CTRL_2 \
+ GG82563_REG(0, 26) /* PHY Specific Control 2 */
+#define GG82563_PHY_PAGE_SELECT_ALT \
+ GG82563_REG(0, 29) /* Alternate Page Select */
+
+#define GG82563_PHY_MAC_SPEC_CTRL \
+ GG82563_REG(2, 21) /* MAC Specific Control Register */
+
+#define GG82563_PHY_DSP_DISTANCE \
+ GG82563_REG(5, 26) /* DSP Distance */
+
+/* Page 193 - Port Control Registers */
+#define GG82563_PHY_KMRN_MODE_CTRL \
+ GG82563_REG(193, 16) /* Kumeran Mode Control */
+#define GG82563_PHY_PWR_MGMT_CTRL \
+ GG82563_REG(193, 20) /* Power Management Control */
+
+/* Page 194 - KMRN Registers */
+#define GG82563_PHY_INBAND_CTRL \
+ GG82563_REG(194, 18) /* Inband Control */
+
+/* MDI Control */
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE 0x04000000
+#define E1000_MDIC_OP_READ 0x08000000
+#define E1000_MDIC_READY 0x10000000
+#define E1000_MDIC_ERROR 0x40000000
+
+/* SerDes Control */
+#define E1000_GEN_POLL_TIMEOUT 640
+
+#endif /* _E1000_DEFINES_H_ */
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
new file mode 100644
index 00000000000..473f78de4be
--- /dev/null
+++ b/drivers/net/e1000e/e1000.h
@@ -0,0 +1,513 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* Linux PRO/1000 Ethernet Driver main header file */
+
+#ifndef _E1000_H_
+#define _E1000_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+
+#include "hw.h"
+
+struct e1000_info;
+
+#define ndev_printk(level, netdev, format, arg...) \
+ printk(level "%s: %s: " format, (netdev)->dev.parent->bus_id, \
+ (netdev)->name, ## arg)
+
+#ifdef DEBUG
+#define ndev_dbg(netdev, format, arg...) \
+ ndev_printk(KERN_DEBUG , netdev, format, ## arg)
+#else
+#define ndev_dbg(netdev, format, arg...) do { (void)(netdev); } while (0)
+#endif
+
+#define ndev_err(netdev, format, arg...) \
+ ndev_printk(KERN_ERR , netdev, format, ## arg)
+#define ndev_info(netdev, format, arg...) \
+ ndev_printk(KERN_INFO , netdev, format, ## arg)
+#define ndev_warn(netdev, format, arg...) \
+ ndev_printk(KERN_WARNING , netdev, format, ## arg)
+#define ndev_notice(netdev, format, arg...) \
+ ndev_printk(KERN_NOTICE , netdev, format, ## arg)
+
+
+/* TX/RX descriptor defines */
+#define E1000_DEFAULT_TXD 256
+#define E1000_MAX_TXD 4096
+#define E1000_MIN_TXD 80
+
+#define E1000_DEFAULT_RXD 256
+#define E1000_MAX_RXD 4096
+#define E1000_MIN_RXD 80
+
+/* Early Receive defines */
+#define E1000_ERT_2048 0x100
+
+#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */
+
+/* How many Tx Descriptors do we need to call netif_wake_queue ? */
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */
+
+#define AUTO_ALL_MODES 0
+#define E1000_EEPROM_APME 0x0400
+
+#define E1000_MNG_VLAN_NONE (-1)
+
+/* Number of packet split data buffers (not including the header buffer) */
+#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1)
+
+enum e1000_boards {
+ board_82571,
+ board_82572,
+ board_82573,
+ board_80003es2lan,
+ board_ich8lan,
+ board_ich9lan,
+};
+
+struct e1000_queue_stats {
+ u64 packets;
+ u64 bytes;
+};
+
+struct e1000_ps_page {
+ struct page *page;
+ u64 dma; /* must be u64 - written to hw */
+};
+
+/*
+ * wrappers around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct e1000_buffer {
+ dma_addr_t dma;
+ struct sk_buff *skb;
+ union {
+ /* TX */
+ struct {
+ unsigned long time_stamp;
+ u16 length;
+ u16 next_to_watch;
+ };
+ /* RX */
+ /* arrays of page information for packet split */
+ struct e1000_ps_page *ps_pages;
+ };
+
+};
+
+struct e1000_ring {
+ void *desc; /* pointer to ring memory */
+ dma_addr_t dma; /* phys address of ring */
+ unsigned int size; /* length of ring in bytes */
+ unsigned int count; /* number of desc. in ring */
+
+ u16 next_to_use;
+ u16 next_to_clean;
+
+ u16 head;
+ u16 tail;
+
+ /* array of buffer information structs */
+ struct e1000_buffer *buffer_info;
+
+ struct sk_buff *rx_skb_top;
+
+ struct e1000_queue_stats stats;
+};
+
+/* board specific private data structure */
+struct e1000_adapter {
+ struct timer_list watchdog_timer;
+ struct timer_list phy_info_timer;
+ struct timer_list blink_timer;
+
+ struct work_struct reset_task;
+ struct work_struct watchdog_task;
+
+ const struct e1000_info *ei;
+
+ struct vlan_group *vlgrp;
+ u32 bd_number;
+ u32 rx_buffer_len;
+ u16 mng_vlan_id;
+ u16 link_speed;
+ u16 link_duplex;
+
+ spinlock_t tx_queue_lock; /* prevent concurrent tail updates */
+
+ /* this is still needed for 82571 and above */
+ atomic_t irq_sem;
+
+ /* track device up/down/testing state */
+ unsigned long state;
+
+ /* Interrupt Throttle Rate */
+ u32 itr;
+ u32 itr_setting;
+ u16 tx_itr;
+ u16 rx_itr;
+
+ /*
+ * TX
+ */
+ struct e1000_ring *tx_ring /* One per active queue */
+ ____cacheline_aligned_in_smp;
+
+ struct napi_struct napi;
+
+ unsigned long tx_queue_len;
+ unsigned int restart_queue;
+ u32 txd_cmd;
+
+ bool detect_tx_hung;
+ u8 tx_timeout_factor;
+
+ u32 tx_int_delay;
+ u32 tx_abs_int_delay;
+
+ unsigned int total_tx_bytes;
+ unsigned int total_tx_packets;
+ unsigned int total_rx_bytes;
+ unsigned int total_rx_packets;
+
+ /* TX stats */
+ u64 tpt_old;
+ u64 colc_old;
+ u64 gotcl_old;
+ u32 gotcl;
+ u32 tx_timeout_count;
+ u32 tx_fifo_head;
+ u32 tx_head_addr;
+ u32 tx_fifo_size;
+ u32 tx_dma_failed;
+
+ /*
+ * RX
+ */
+ bool (*clean_rx) (struct e1000_adapter *adapter,
+ int *work_done, int work_to_do)
+ ____cacheline_aligned_in_smp;
+ void (*alloc_rx_buf) (struct e1000_adapter *adapter,
+ int cleaned_count);
+ struct e1000_ring *rx_ring;
+
+ u32 rx_int_delay;
+ u32 rx_abs_int_delay;
+
+ /* RX stats */
+ u64 hw_csum_err;
+ u64 hw_csum_good;
+ u64 rx_hdr_split;
+ u64 gorcl_old;
+ u32 gorcl;
+ u32 alloc_rx_buff_failed;
+ u32 rx_dma_failed;
+
+ unsigned int rx_ps_pages;
+ u16 rx_ps_bsize0;
+
+ /* OS defined structs */
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct net_device_stats net_stats;
+ spinlock_t stats_lock; /* prevent concurrent stats updates */
+
+ /* structs defined in e1000_hw.h */
+ struct e1000_hw hw;
+
+ struct e1000_hw_stats stats;
+ struct e1000_phy_info phy_info;
+ struct e1000_phy_stats phy_stats;
+
+ struct e1000_ring test_tx_ring;
+ struct e1000_ring test_rx_ring;
+ u32 test_icr;
+
+ u32 msg_enable;
+
+ u32 eeprom_wol;
+ u32 wol;
+ u32 pba;
+
+ u8 fc_autoneg;
+
+ unsigned long led_status;
+
+ unsigned int flags;
+};
+
+struct e1000_info {
+ enum e1000_mac_type mac;
+ unsigned int flags;
+ u32 pba;
+ s32 (*get_invariants)(struct e1000_adapter *);
+ struct e1000_mac_operations *mac_ops;
+ struct e1000_phy_operations *phy_ops;
+ struct e1000_nvm_operations *nvm_ops;
+};
+
+/* hardware capability, feature, and workaround flags */
+#define FLAG_HAS_AMT (1 << 0)
+#define FLAG_HAS_FLASH (1 << 1)
+#define FLAG_HAS_HW_VLAN_FILTER (1 << 2)
+#define FLAG_HAS_WOL (1 << 3)
+#define FLAG_HAS_ERT (1 << 4)
+#define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5)
+#define FLAG_HAS_SWSM_ON_LOAD (1 << 6)
+#define FLAG_HAS_JUMBO_FRAMES (1 << 7)
+#define FLAG_HAS_ASPM (1 << 8)
+#define FLAG_HAS_STATS_ICR_ICT (1 << 9)
+#define FLAG_HAS_STATS_PTC_PRC (1 << 10)
+#define FLAG_HAS_SMART_POWER_DOWN (1 << 11)
+#define FLAG_IS_QUAD_PORT_A (1 << 12)
+#define FLAG_IS_QUAD_PORT (1 << 13)
+#define FLAG_TIPG_MEDIUM_FOR_80003ESLAN (1 << 14)
+#define FLAG_APME_IN_WUC (1 << 15)
+#define FLAG_APME_IN_CTRL3 (1 << 16)
+#define FLAG_APME_CHECK_PORT_B (1 << 17)
+#define FLAG_DISABLE_FC_PAUSE_TIME (1 << 18)
+#define FLAG_NO_WAKE_UCAST (1 << 19)
+#define FLAG_MNG_PT_ENABLED (1 << 20)
+#define FLAG_RESET_OVERWRITES_LAA (1 << 21)
+#define FLAG_TARC_SPEED_MODE_BIT (1 << 22)
+#define FLAG_TARC_SET_BIT_ZERO (1 << 23)
+#define FLAG_RX_NEEDS_RESTART (1 << 24)
+#define FLAG_LSC_GIG_SPEED_DROP (1 << 25)
+#define FLAG_SMART_POWER_DOWN (1 << 26)
+#define FLAG_MSI_ENABLED (1 << 27)
+#define FLAG_RX_CSUM_ENABLED (1 << 28)
+#define FLAG_TSO_FORCE (1 << 29)
+
+#define E1000_RX_DESC_PS(R, i) \
+ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
+#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
+#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc)
+#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc)
+#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc)
+
+enum e1000_state_t {
+ __E1000_TESTING,
+ __E1000_RESETTING,
+ __E1000_DOWN
+};
+
+enum latency_range {
+ lowest_latency = 0,
+ low_latency = 1,
+ bulk_latency = 2,
+ latency_invalid = 255
+};
+
+extern char e1000e_driver_name[];
+extern const char e1000e_driver_version[];
+
+extern void e1000e_check_options(struct e1000_adapter *adapter);
+extern void e1000e_set_ethtool_ops(struct net_device *netdev);
+
+extern int e1000e_up(struct e1000_adapter *adapter);
+extern void e1000e_down(struct e1000_adapter *adapter);
+extern void e1000e_reinit_locked(struct e1000_adapter *adapter);
+extern void e1000e_reset(struct e1000_adapter *adapter);
+extern void e1000e_power_up_phy(struct e1000_adapter *adapter);
+extern int e1000e_setup_rx_resources(struct e1000_adapter *adapter);
+extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter);
+extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
+extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
+extern void e1000e_update_stats(struct e1000_adapter *adapter);
+
+extern unsigned int copybreak;
+
+extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw);
+
+extern struct e1000_info e1000_82571_info;
+extern struct e1000_info e1000_82572_info;
+extern struct e1000_info e1000_82573_info;
+extern struct e1000_info e1000_ich8_info;
+extern struct e1000_info e1000_ich9_info;
+extern struct e1000_info e1000_es2_info;
+
+extern s32 e1000e_read_part_num(struct e1000_hw *hw, u32 *part_num);
+
+extern s32 e1000e_commit_phy(struct e1000_hw *hw);
+
+extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
+
+extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
+extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
+
+extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+ bool state);
+extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
+extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
+
+extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
+extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
+extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw);
+extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
+extern s32 e1000e_led_on_generic(struct e1000_hw *hw);
+extern s32 e1000e_led_off_generic(struct e1000_hw *hw);
+extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw);
+extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex);
+extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex);
+extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw);
+extern s32 e1000e_get_auto_rd_done(struct e1000_hw *hw);
+extern s32 e1000e_id_led_init(struct e1000_hw *hw);
+extern void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw);
+extern s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw);
+extern s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw);
+extern s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw);
+extern s32 e1000e_setup_link(struct e1000_hw *hw);
+extern void e1000e_clear_vfta(struct e1000_hw *hw);
+extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
+extern void e1000e_mc_addr_list_update_generic(struct e1000_hw *hw,
+ u8 *mc_addr_list, u32 mc_addr_count,
+ u32 rar_used_count, u32 rar_count);
+extern void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
+extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
+extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
+extern s32 e1000e_get_hw_semaphore(struct e1000_hw *hw);
+extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data);
+extern void e1000e_config_collision_dist(struct e1000_hw *hw);
+extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw);
+extern s32 e1000e_force_mac_fc(struct e1000_hw *hw);
+extern s32 e1000e_blink_led(struct e1000_hw *hw);
+extern void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
+extern void e1000e_reset_adaptive(struct e1000_hw *hw);
+extern void e1000e_update_adaptive(struct e1000_hw *hw);
+
+extern s32 e1000e_setup_copper_link(struct e1000_hw *hw);
+extern s32 e1000e_get_phy_id(struct e1000_hw *hw);
+extern void e1000e_put_hw_semaphore(struct e1000_hw *hw);
+extern s32 e1000e_check_reset_block_generic(struct e1000_hw *hw);
+extern s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+extern s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw);
+extern s32 e1000e_get_phy_info_igp(struct e1000_hw *hw);
+extern s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw);
+extern s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active);
+extern s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000e_phy_sw_reset(struct e1000_hw *hw);
+extern s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+extern s32 e1000e_get_cfg_done(struct e1000_hw *hw);
+extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw);
+extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw);
+extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
+extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
+extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
+extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+ u32 usec_interval, bool *success);
+extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
+extern s32 e1000e_check_downshift(struct e1000_hw *hw);
+
+static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw)
+{
+ return hw->phy.ops.reset_phy(hw);
+}
+
+static inline s32 e1000_check_reset_block(struct e1000_hw *hw)
+{
+ return hw->phy.ops.check_reset_block(hw);
+}
+
+static inline s32 e1e_rphy(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ return hw->phy.ops.read_phy_reg(hw, offset, data);
+}
+
+static inline s32 e1e_wphy(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ return hw->phy.ops.write_phy_reg(hw, offset, data);
+}
+
+static inline s32 e1000_get_cable_length(struct e1000_hw *hw)
+{
+ return hw->phy.ops.get_cable_length(hw);
+}
+
+extern s32 e1000e_acquire_nvm(struct e1000_hw *hw);
+extern s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+extern s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw);
+extern s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
+extern s32 e1000e_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
+extern void e1000e_release_nvm(struct e1000_hw *hw);
+extern void e1000e_reload_nvm(struct e1000_hw *hw);
+extern s32 e1000e_read_mac_addr(struct e1000_hw *hw);
+
+static inline s32 e1000_validate_nvm_checksum(struct e1000_hw *hw)
+{
+ return hw->nvm.ops.validate_nvm(hw);
+}
+
+static inline s32 e1000e_update_nvm_checksum(struct e1000_hw *hw)
+{
+ return hw->nvm.ops.update_nvm(hw);
+}
+
+static inline s32 e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+ return hw->nvm.ops.read_nvm(hw, offset, words, data);
+}
+
+static inline s32 e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+ return hw->nvm.ops.write_nvm(hw, offset, words, data);
+}
+
+static inline s32 e1000_get_phy_info(struct e1000_hw *hw)
+{
+ return hw->phy.ops.get_phy_info(hw);
+}
+
+extern bool e1000e_check_mng_mode(struct e1000_hw *hw);
+extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
+extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
+
+static inline u32 __er32(struct e1000_hw *hw, unsigned long reg)
+{
+ return readl(hw->hw_addr + reg);
+}
+
+static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val)
+{
+ writel(val, hw->hw_addr + reg);
+}
+
+#endif /* _E1000_H_ */
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
new file mode 100644
index 00000000000..88657adf965
--- /dev/null
+++ b/drivers/net/e1000e/es2lan.c
@@ -0,0 +1,1232 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/*
+ * 80003ES2LAN Gigabit Ethernet Controller (Copper)
+ * 80003ES2LAN Gigabit Ethernet Controller (Serdes)
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "e1000.h"
+
+#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00
+#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02
+#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10
+
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800
+#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING 0x0010
+
+#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
+#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000
+
+#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
+#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000
+
+#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN 0x8
+#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN 0x9
+
+/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
+#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Reversal Disab. */
+#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060
+#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI */
+#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX */
+#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Auto crossover */
+
+/* PHY Specific Control Register 2 (Page 0, Register 26) */
+#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000
+ /* 1=Reverse Auto-Negotiation */
+
+/* MAC Specific Control Register (Page 2, Register 21) */
+/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
+#define GG82563_MSCR_TX_CLK_MASK 0x0007
+#define GG82563_MSCR_TX_CLK_10MBPS_2_5 0x0004
+#define GG82563_MSCR_TX_CLK_100MBPS_25 0x0005
+#define GG82563_MSCR_TX_CLK_1000MBPS_25 0x0007
+
+#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */
+
+/* DSP Distance Register (Page 5, Register 26) */
+#define GG82563_DSPD_CABLE_LENGTH 0x0007 /* 0 = <50M
+ 1 = 50-80M
+ 2 = 80-110M
+ 3 = 110-140M
+ 4 = >140M */
+
+/* Kumeran Mode Control Register (Page 193, Register 16) */
+#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800
+
+/* Power Management Control Register (Page 193, Register 20) */
+#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001
+ /* 1=Enable SERDES Electrical Idle */
+
+/* In-Band Control Register (Page 194, Register 18) */
+#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding */
+
+/* A table for the GG82563 cable length where the range is defined
+ * with a lower bound at "index" and the upper bound at
+ * "index + 5".
+ */
+static const u16 e1000_gg82563_cable_length_table[] =
+ { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF };
+
+static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw);
+static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
+static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
+static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw);
+static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw);
+static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw);
+static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex);
+
+/**
+ * e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+
+ if (hw->media_type != e1000_media_type_copper) {
+ phy->type = e1000_phy_none;
+ return 0;
+ }
+
+ phy->addr = 1;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->reset_delay_us = 100;
+ phy->type = e1000_phy_gg82563;
+
+ /* This can only be done after all function pointers are setup. */
+ ret_val = e1000e_get_phy_id(hw);
+
+ /* Verify phy id */
+ if (phy->id != GG82563_E_PHY_ID)
+ return -E1000_ERR_PHY;
+
+ return ret_val;
+}
+
+/**
+ * e1000_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 eecd = er32(EECD);
+ u16 size;
+
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
+ switch (nvm->override) {
+ case e1000_nvm_override_spi_large:
+ nvm->page_size = 32;
+ nvm->address_bits = 16;
+ break;
+ case e1000_nvm_override_spi_small:
+ nvm->page_size = 8;
+ nvm->address_bits = 8;
+ break;
+ default:
+ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+ break;
+ }
+
+ nvm->type = e1000_nvm_eeprom_spi;
+
+ size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+ E1000_EECD_SIZE_EX_SHIFT);
+
+ /* Added to a constant, "size" becomes the left-shift value
+ * for setting word_size.
+ */
+ size += NVM_WORD_SIZE_BASE_SHIFT;
+ nvm->word_size = 1 << size;
+
+ return 0;
+}
+
+/**
+ * e1000_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs.
+ * @hw: pointer to the HW structure
+ *
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_mac_params_80003es2lan(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_mac_info *mac = &hw->mac;
+ struct e1000_mac_operations *func = &mac->ops;
+
+ /* Set media type */
+ switch (adapter->pdev->device) {
+ case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+ hw->media_type = e1000_media_type_internal_serdes;
+ break;
+ default:
+ hw->media_type = e1000_media_type_copper;
+ break;
+ }
+
+ /* Set mta register count */
+ mac->mta_reg_count = 128;
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_RAR_ENTRIES;
+ /* Set if manageability features are enabled. */
+ mac->arc_subsystem_valid =
+ (er32(FWSM) & E1000_FWSM_MODE_MASK) ? 1 : 0;
+
+ /* check for link */
+ switch (hw->media_type) {
+ case e1000_media_type_copper:
+ func->setup_physical_interface = e1000_setup_copper_link_80003es2lan;
+ func->check_for_link = e1000e_check_for_copper_link;
+ break;
+ case e1000_media_type_fiber:
+ func->setup_physical_interface = e1000e_setup_fiber_serdes_link;
+ func->check_for_link = e1000e_check_for_fiber_link;
+ break;
+ case e1000_media_type_internal_serdes:
+ func->setup_physical_interface = e1000e_setup_fiber_serdes_link;
+ func->check_for_link = e1000e_check_for_serdes_link;
+ break;
+ default:
+ return -E1000_ERR_CONFIG;
+ break;
+ }
+
+ return 0;
+}
+
+static s32 e1000_get_invariants_80003es2lan(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ s32 rc;
+
+ rc = e1000_init_mac_params_80003es2lan(adapter);
+ if (rc)
+ return rc;
+
+ rc = e1000_init_nvm_params_80003es2lan(hw);
+ if (rc)
+ return rc;
+
+ rc = e1000_init_phy_params_80003es2lan(hw);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+/**
+ * e1000_acquire_phy_80003es2lan - Acquire rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * A wrapper to acquire access rights to the correct PHY. This is a
+ * function pointer entry point called by the api module.
+ **/
+static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw)
+{
+ u16 mask;
+
+ mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+
+ return e1000_acquire_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ * e1000_release_phy_80003es2lan - Release rights to access PHY
+ * @hw: pointer to the HW structure
+ *
+ * A wrapper to release access rights to the correct PHY. This is a
+ * function pointer entry point called by the api module.
+ **/
+static void e1000_release_phy_80003es2lan(struct e1000_hw *hw)
+{
+ u16 mask;
+
+ mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+ e1000_release_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ * e1000_acquire_nvm_80003es2lan - Acquire rights to access NVM
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the semaphore to access the EEPROM. This is a function
+ * pointer entry point called by the api module.
+ **/
+static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw)
+{
+ s32 ret_val;
+
+ ret_val = e1000_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000e_acquire_nvm(hw);
+
+ if (ret_val)
+ e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+
+ return ret_val;
+}
+
+/**
+ * e1000_release_nvm_80003es2lan - Relinquish rights to access NVM
+ * @hw: pointer to the HW structure
+ *
+ * Release the semaphore used to access the EEPROM. This is a
+ * function pointer entry point called by the api module.
+ **/
+static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw)
+{
+ e1000e_release_nvm(hw);
+ e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ * e1000_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Acquire the SW/FW semaphore to access the PHY or NVM. The mask
+ * will also specify which port we're acquiring the lock for.
+ **/
+static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
+{
+ u32 swfw_sync;
+ u32 swmask = mask;
+ u32 fwmask = mask << 16;
+ s32 i = 0;
+ s32 timeout = 200;
+
+ while (i < timeout) {
+ if (e1000e_get_hw_semaphore(hw))
+ return -E1000_ERR_SWFW_SYNC;
+
+ swfw_sync = er32(SW_FW_SYNC);
+ if (!(swfw_sync & (fwmask | swmask)))
+ break;
+
+ /* Firmware currently using resource (fwmask)
+ * or other software thread using resource (swmask) */
+ e1000e_put_hw_semaphore(hw);
+ mdelay(5);
+ i++;
+ }
+
+ if (i == timeout) {
+ hw_dbg(hw,
+ "Driver can't access resource, SW_FW_SYNC timeout.\n");
+ return -E1000_ERR_SWFW_SYNC;
+ }
+
+ swfw_sync |= swmask;
+ ew32(SW_FW_SYNC, swfw_sync);
+
+ e1000e_put_hw_semaphore(hw);
+
+ return 0;
+}
+
+/**
+ * e1000_release_swfw_sync_80003es2lan - Release SW/FW semaphore
+ * @hw: pointer to the HW structure
+ * @mask: specifies which semaphore to acquire
+ *
+ * Release the SW/FW semaphore used to access the PHY or NVM. The mask
+ * will also specify which port we're releasing the lock for.
+ **/
+static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
+{
+ u32 swfw_sync;
+
+ while (e1000e_get_hw_semaphore(hw) != 0);
+ /* Empty */
+
+ swfw_sync = er32(SW_FW_SYNC);
+ swfw_sync &= ~mask;
+ ew32(SW_FW_SYNC, swfw_sync);
+
+ e1000e_put_hw_semaphore(hw);
+}
+
+/**
+ * e1000_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: offset of the register to read
+ * @data: pointer to the data returned from the operation
+ *
+ * Read the GG82563 PHY register. This is a function pointer entry
+ * point called by the api module.
+ **/
+static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+ u32 offset, u16 *data)
+{
+ s32 ret_val;
+ u32 page_select;
+ u16 temp;
+
+ /* Select Configuration Page */
+ if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG)
+ page_select = GG82563_PHY_PAGE_SELECT;
+ else
+ /* Use Alternative Page Select register to access
+ * registers 30 and 31
+ */
+ page_select = GG82563_PHY_PAGE_SELECT_ALT;
+
+ temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
+ ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp);
+ if (ret_val)
+ return ret_val;
+
+ /* The "ready" bit in the MDIC register may be incorrectly set
+ * before the device has completed the "Page Select" MDI
+ * transaction. So we wait 200us after each MDI command...
+ */
+ udelay(200);
+
+ /* ...and verify the command was successful. */
+ ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp);
+
+ if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
+ ret_val = -E1000_ERR_PHY;
+ return ret_val;
+ }
+
+ udelay(200);
+
+ ret_val = e1000e_read_phy_reg_m88(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ udelay(200);
+
+ return ret_val;
+}
+
+/**
+ * e1000_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: offset of the register to read
+ * @data: value to write to the register
+ *
+ * Write to the GG82563 PHY register. This is a function pointer entry
+ * point called by the api module.
+ **/
+static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+ u32 offset, u16 data)
+{
+ s32 ret_val;
+ u32 page_select;
+ u16 temp;
+
+ /* Select Configuration Page */
+ if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG)
+ page_select = GG82563_PHY_PAGE_SELECT;
+ else
+ /* Use Alternative Page Select register to access
+ * registers 30 and 31
+ */
+ page_select = GG82563_PHY_PAGE_SELECT_ALT;
+
+ temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
+ ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp);
+ if (ret_val)
+ return ret_val;
+
+
+ /* The "ready" bit in the MDIC register may be incorrectly set
+ * before the device has completed the "Page Select" MDI
+ * transaction. So we wait 200us after each MDI command...
+ */
+ udelay(200);
+
+ /* ...and verify the command was successful. */
+ ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp);
+
+ if (((u16)offset >> GG82563_PAGE_SHIFT) != temp)
+ return -E1000_ERR_PHY;
+
+ udelay(200);
+
+ ret_val = e1000e_write_phy_reg_m88(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ udelay(200);
+
+ return ret_val;
+}
+
+/**
+ * e1000_write_nvm_80003es2lan - Write to ESB2 NVM
+ * @hw: pointer to the HW structure
+ * @offset: offset of the register to read
+ * @words: number of words to write
+ * @data: buffer of data to write to the NVM
+ *
+ * Write "words" of data to the ESB2 NVM. This is a function
+ * pointer entry point called by the api module.
+ **/
+static s32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset,
+ u16 words, u16 *data)
+{
+ return e1000e_write_nvm_spi(hw, offset, words, data);
+}
+
+/**
+ * e1000_get_cfg_done_80003es2lan - Wait for configuration to complete
+ * @hw: pointer to the HW structure
+ *
+ * Wait a specific amount of time for manageability processes to complete.
+ * This is a function pointer entry point called by the phy module.
+ **/
+static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw)
+{
+ s32 timeout = PHY_CFG_TIMEOUT;
+ u32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+ if (hw->bus.func == 1)
+ mask = E1000_NVM_CFG_DONE_PORT_1;
+
+ while (timeout) {
+ if (er32(EEMNGCTL) & mask)
+ break;
+ msleep(1);
+ timeout--;
+ }
+ if (!timeout) {
+ hw_dbg(hw, "MNG configuration cycle has not completed.\n");
+ return -E1000_ERR_RESET;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex
+ * @hw: pointer to the HW structure
+ *
+ * Force the speed and duplex settings onto the PHY. This is a
+ * function pointer entry point called by the phy module.
+ **/
+static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 phy_data;
+ bool link;
+
+ /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+ * forced whenever speed and duplex are forced.
+ */
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO;
+ ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ hw_dbg(hw, "GG82563 PSCR: %X\n", phy_data);
+
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ /* Reset the phy to commit changes. */
+ phy_data |= MII_CR_RESET;
+
+ ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ udelay(1);
+
+ if (hw->phy.wait_for_link) {
+ hw_dbg(hw, "Waiting for forced speed/duplex link "
+ "on GG82563 phy.\n");
+
+ ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link) {
+ /* We didn't get link.
+ * Reset the DSP and cross our fingers.
+ */
+ ret_val = e1000e_phy_reset_dsp(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Try once more */
+ ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ return ret_val;
+ }
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Resetting the phy means we need to verify the TX_CLK corresponds
+ * to the link speed. 10Mbps -> 2.5MHz, else 25MHz.
+ */
+ phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
+ if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED)
+ phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5;
+ else
+ phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25;
+
+ /* In addition, we must re-enable CRS on Tx for both half and full
+ * duplex.
+ */
+ phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+ ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
+
+ return ret_val;
+}
+
+/**
+ * e1000_get_cable_length_80003es2lan - Set approximate cable length
+ * @hw: pointer to the HW structure
+ *
+ * Find the approximate cable length as measured by the GG82563 PHY.
+ * This is a function pointer entry point called by the phy module.
+ **/
+static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data;
+ u16 index;
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ index = phy_data & GG82563_DSPD_CABLE_LENGTH;
+ phy->min_cable_length = e1000_gg82563_cable_length_table[index];
+ phy->max_cable_length = e1000_gg82563_cable_length_table[index+5];
+
+ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+ return 0;
+}
+
+/**
+ * e1000_get_link_up_info_80003es2lan - Report speed and duplex
+ * @hw: pointer to the HW structure
+ * @speed: pointer to speed buffer
+ * @duplex: pointer to duplex buffer
+ *
+ * Retrieve the current speed and duplex configuration.
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
+ u16 *duplex)
+{
+ s32 ret_val;
+
+ if (hw->media_type == e1000_media_type_copper) {
+ ret_val = e1000e_get_speed_and_duplex_copper(hw,
+ speed,
+ duplex);
+ if (ret_val)
+ return ret_val;
+ if (*speed == SPEED_1000)
+ ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw);
+ else
+ ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw,
+ *duplex);
+ } else {
+ ret_val = e1000e_get_speed_and_duplex_fiber_serdes(hw,
+ speed,
+ duplex);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_reset_hw_80003es2lan - Reset the ESB2 controller
+ * @hw: pointer to the HW structure
+ *
+ * Perform a global reset to the ESB2 controller.
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ u32 icr;
+ s32 ret_val;
+
+ /* Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000e_disable_pcie_master(hw);
+ if (ret_val)
+ hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+
+ hw_dbg(hw, "Masking off all interrupts\n");
+ ew32(IMC, 0xffffffff);
+
+ ew32(RCTL, 0);
+ ew32(TCTL, E1000_TCTL_PSP);
+ e1e_flush();
+
+ msleep(10);
+
+ ctrl = er32(CTRL);
+
+ hw_dbg(hw, "Issuing a global reset to MAC\n");
+ ew32(CTRL, ctrl | E1000_CTRL_RST);
+
+ ret_val = e1000e_get_auto_rd_done(hw);
+ if (ret_val)
+ /* We don't want to continue accessing MAC registers. */
+ return ret_val;
+
+ /* Clear any pending interrupt events. */
+ ew32(IMC, 0xffffffff);
+ icr = er32(ICR);
+
+ return 0;
+}
+
+/**
+ * e1000_init_hw_80003es2lan - Initialize the ESB2 controller
+ * @hw: pointer to the HW structure
+ *
+ * Initialize the hw bits, LED, VFTA, MTA, link and hw counters.
+ * This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 reg_data;
+ s32 ret_val;
+ u16 i;
+
+ e1000_initialize_hw_bits_80003es2lan(hw);
+
+ /* Initialize identification LED */
+ ret_val = e1000e_id_led_init(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error initializing identification LED\n");
+ return ret_val;
+ }
+
+ /* Disabling VLAN filtering */
+ hw_dbg(hw, "Initializing the IEEE VLAN\n");
+ e1000e_clear_vfta(hw);
+
+ /* Setup the receive address. */
+ e1000e_init_rx_addrs(hw, mac->rar_entry_count);
+
+ /* Zero out the Multicast HASH table */
+ hw_dbg(hw, "Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+ /* Setup link and flow control */
+ ret_val = e1000e_setup_link(hw);
+
+ /* Set the transmit descriptor write-back policy */
+ reg_data = er32(TXDCTL);
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+ ew32(TXDCTL, reg_data);
+
+ /* ...for both queues. */
+ reg_data = er32(TXDCTL1);
+ reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+ ew32(TXDCTL1, reg_data);
+
+ /* Enable retransmit on late collisions */
+ reg_data = er32(TCTL);
+ reg_data |= E1000_TCTL_RTLC;
+ ew32(TCTL, reg_data);
+
+ /* Configure Gigabit Carry Extend Padding */
+ reg_data = er32(TCTL_EXT);
+ reg_data &= ~E1000_TCTL_EXT_GCEX_MASK;
+ reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN;
+ ew32(TCTL_EXT, reg_data);
+
+ /* Configure Transmit Inter-Packet Gap */
+ reg_data = er32(TIPG);
+ reg_data &= ~E1000_TIPG_IPGT_MASK;
+ reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+ ew32(TIPG, reg_data);
+
+ reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001);
+ reg_data &= ~0x00100000;
+ E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data);
+
+ /* Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_80003es2lan(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_initialize_hw_bits_80003es2lan - Init hw bits of ESB2
+ * @hw: pointer to the HW structure
+ *
+ * Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw)
+{
+ u32 reg;
+
+ /* Transmit Descriptor Control 0 */
+ reg = er32(TXDCTL);
+ reg |= (1 << 22);
+ ew32(TXDCTL, reg);
+
+ /* Transmit Descriptor Control 1 */
+ reg = er32(TXDCTL1);
+ reg |= (1 << 22);
+ ew32(TXDCTL1, reg);
+
+ /* Transmit Arbitration Control 0 */
+ reg = er32(TARC0);
+ reg &= ~(0xF << 27); /* 30:27 */
+ if (hw->media_type != e1000_media_type_copper)
+ reg &= ~(1 << 20);
+ ew32(TARC0, reg);
+
+ /* Transmit Arbitration Control 1 */
+ reg = er32(TARC1);
+ if (er32(TCTL) & E1000_TCTL_MULR)
+ reg &= ~(1 << 28);
+ else
+ reg |= (1 << 28);
+ ew32(TARC1, reg);
+}
+
+/**
+ * e1000_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link
+ * @hw: pointer to the HW structure
+ *
+ * Setup some GG82563 PHY registers for obtaining link
+ **/
+static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u32 ctrl_ext;
+ u16 data;
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+ /* Use 25MHz for both link down and 1000Base-T for Tx clock. */
+ data |= GG82563_MSCR_TX_CLK_1000MBPS_25;
+
+ ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
+ data);
+ if (ret_val)
+ return ret_val;
+
+ /* Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
+
+ switch (phy->mdix) {
+ case 1:
+ data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
+ break;
+ case 2:
+ data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
+ break;
+ case 0:
+ default:
+ data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
+ break;
+ }
+
+ /* Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+ if (phy->disable_polarity_correction)
+ data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+
+ ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, data);
+ if (ret_val)
+ return ret_val;
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = e1000e_commit_phy(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error Resetting the PHY\n");
+ return ret_val;
+ }
+
+ /* Bypass RX and TX FIFO's */
+ ret_val = e1000e_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL,
+ E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
+ E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL_2, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
+ ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL_2, data);
+ if (ret_val)
+ return ret_val;
+
+ ctrl_ext = er32(CTRL_EXT);
+ ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
+ ew32(CTRL_EXT, ctrl_ext);
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_PWR_MGMT_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ /* Do not init these registers when the HW is in IAMT mode, since the
+ * firmware will have already initialized them. We only initialize
+ * them if the HW is not in IAMT mode.
+ */
+ if (!e1000e_check_mng_mode(hw)) {
+ /* Enable Electrical Idle on the PHY */
+ data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
+ ret_val = e1e_wphy(hw, GG82563_PHY_PWR_MGMT_CTRL, data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Workaround: Disable padding in Kumeran interface in the MAC
+ * and in the PHY to avoid CRC errors.
+ */
+ ret_val = e1e_rphy(hw, GG82563_PHY_INBAND_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= GG82563_ICR_DIS_PADDING;
+ ret_val = e1e_wphy(hw, GG82563_PHY_INBAND_CTRL, data);
+ if (ret_val)
+ return ret_val;
+
+ return 0;
+}
+
+/**
+ * e1000_setup_copper_link_80003es2lan - Setup Copper Link for ESB2
+ * @hw: pointer to the HW structure
+ *
+ * Essentially a wrapper for setting up all things "copper" related.
+ * This is a function pointer entry point called by the mac module.
+ **/
+static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ s32 ret_val;
+ u16 reg_data;
+
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ew32(CTRL, ctrl);
+
+ /* Set the mac to wait the maximum time between each
+ * iteration and increase the max iterations when
+ * polling the phy; this fixes erroneous timeouts at 10Mbps. */
+ ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), &reg_data);
+ if (ret_val)
+ return ret_val;
+ reg_data |= 0x3F;
+ ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000e_read_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+ &reg_data);
+ if (ret_val)
+ return ret_val;
+ reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING;
+ ret_val = e1000e_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+ reg_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_copper_link_setup_gg82563_80003es2lan(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000e_setup_copper_link(hw);
+
+ return 0;
+}
+
+/**
+ * e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation
+ * @hw: pointer to the HW structure
+ * @duplex: current duplex setting
+ *
+ * Configure the KMRN interface by applying last minute quirks for
+ * 10/100 operation.
+ **/
+static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
+{
+ s32 ret_val;
+ u32 tipg;
+ u16 reg_data;
+
+ reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
+ ret_val = e1000e_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = er32(TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN;
+ ew32(TIPG, tipg);
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+ if (ret_val)
+ return ret_val;
+
+ if (duplex == HALF_DUPLEX)
+ reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+ else
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+
+ ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+ return 0;
+}
+
+/**
+ * e1000_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation
+ * @hw: pointer to the HW structure
+ *
+ * Configure the KMRN interface by applying last minute quirks for
+ * gigabit operation.
+ **/
+static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 reg_data;
+ u32 tipg;
+
+ reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
+ ret_val = e1000e_write_kmrn_reg(hw,
+ E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+ reg_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Configure Transmit Inter-Packet Gap */
+ tipg = er32(TIPG);
+ tipg &= ~E1000_TIPG_IPGT_MASK;
+ tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+ ew32(TIPG, tipg);
+
+ ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+ if (ret_val)
+ return ret_val;
+
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+ return ret_val;
+}
+
+/**
+ * e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
+{
+ u32 temp;
+
+ e1000e_clear_hw_cntrs_base(hw);
+
+ temp = er32(PRC64);
+ temp = er32(PRC127);
+ temp = er32(PRC255);
+ temp = er32(PRC511);
+ temp = er32(PRC1023);
+ temp = er32(PRC1522);
+ temp = er32(PTC64);
+ temp = er32(PTC127);
+ temp = er32(PTC255);
+ temp = er32(PTC511);
+ temp = er32(PTC1023);
+ temp = er32(PTC1522);
+
+ temp = er32(ALGNERRC);
+ temp = er32(RXERRC);
+ temp = er32(TNCRS);
+ temp = er32(CEXTERR);
+ temp = er32(TSCTC);
+ temp = er32(TSCTFC);
+
+ temp = er32(MGTPRC);
+ temp = er32(MGTPDC);
+ temp = er32(MGTPTC);
+
+ temp = er32(IAC);
+ temp = er32(ICRXOC);
+
+ temp = er32(ICRXPTC);
+ temp = er32(ICRXATC);
+ temp = er32(ICTXPTC);
+ temp = er32(ICTXATC);
+ temp = er32(ICTXQEC);
+ temp = er32(ICTXQMTC);
+ temp = er32(ICRXDMTC);
+}
+
+static struct e1000_mac_operations es2_mac_ops = {
+ .mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+ /* check_for_link dependent on media type */
+ .cleanup_led = e1000e_cleanup_led_generic,
+ .clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan,
+ .get_bus_info = e1000e_get_bus_info_pcie,
+ .get_link_up_info = e1000_get_link_up_info_80003es2lan,
+ .led_on = e1000e_led_on_generic,
+ .led_off = e1000e_led_off_generic,
+ .mc_addr_list_update = e1000e_mc_addr_list_update_generic,
+ .reset_hw = e1000_reset_hw_80003es2lan,
+ .init_hw = e1000_init_hw_80003es2lan,
+ .setup_link = e1000e_setup_link,
+ /* setup_physical_interface dependent on media type */
+};
+
+static struct e1000_phy_operations es2_phy_ops = {
+ .acquire_phy = e1000_acquire_phy_80003es2lan,
+ .check_reset_block = e1000e_check_reset_block_generic,
+ .commit_phy = e1000e_phy_sw_reset,
+ .force_speed_duplex = e1000_phy_force_speed_duplex_80003es2lan,
+ .get_cfg_done = e1000_get_cfg_done_80003es2lan,
+ .get_cable_length = e1000_get_cable_length_80003es2lan,
+ .get_phy_info = e1000e_get_phy_info_m88,
+ .read_phy_reg = e1000_read_phy_reg_gg82563_80003es2lan,
+ .release_phy = e1000_release_phy_80003es2lan,
+ .reset_phy = e1000e_phy_hw_reset_generic,
+ .set_d0_lplu_state = NULL,
+ .set_d3_lplu_state = e1000e_set_d3_lplu_state,
+ .write_phy_reg = e1000_write_phy_reg_gg82563_80003es2lan,
+};
+
+static struct e1000_nvm_operations es2_nvm_ops = {
+ .acquire_nvm = e1000_acquire_nvm_80003es2lan,
+ .read_nvm = e1000e_read_nvm_eerd,
+ .release_nvm = e1000_release_nvm_80003es2lan,
+ .update_nvm = e1000e_update_nvm_checksum_generic,
+ .valid_led_default = e1000e_valid_led_default,
+ .validate_nvm = e1000e_validate_nvm_checksum_generic,
+ .write_nvm = e1000_write_nvm_80003es2lan,
+};
+
+struct e1000_info e1000_es2_info = {
+ .mac = e1000_80003es2lan,
+ .flags = FLAG_HAS_HW_VLAN_FILTER
+ | FLAG_HAS_JUMBO_FRAMES
+ | FLAG_HAS_STATS_PTC_PRC
+ | FLAG_HAS_WOL
+ | FLAG_APME_IN_CTRL3
+ | FLAG_RX_CSUM_ENABLED
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_STATS_ICR_ICT
+ | FLAG_RX_NEEDS_RESTART /* errata */
+ | FLAG_TARC_SET_BIT_ZERO /* errata */
+ | FLAG_APME_CHECK_PORT_B
+ | FLAG_DISABLE_FC_PAUSE_TIME /* errata */
+ | FLAG_TIPG_MEDIUM_FOR_80003ESLAN,
+ .pba = 38,
+ .get_invariants = e1000_get_invariants_80003es2lan,
+ .mac_ops = &es2_mac_ops,
+ .phy_ops = &es2_phy_ops,
+ .nvm_ops = &es2_nvm_ops,
+};
+
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
new file mode 100644
index 00000000000..6a39784e7ee
--- /dev/null
+++ b/drivers/net/e1000e/ethtool.c
@@ -0,0 +1,1791 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for e1000 */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "e1000.h"
+
+struct e1000_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+};
+
+#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \
+ offsetof(struct e1000_adapter, m)
+static const struct e1000_stats e1000_gstrings_stats[] = {
+ { "rx_packets", E1000_STAT(stats.gprc) },
+ { "tx_packets", E1000_STAT(stats.gptc) },
+ { "rx_bytes", E1000_STAT(stats.gorcl) },
+ { "tx_bytes", E1000_STAT(stats.gotcl) },
+ { "rx_broadcast", E1000_STAT(stats.bprc) },
+ { "tx_broadcast", E1000_STAT(stats.bptc) },
+ { "rx_multicast", E1000_STAT(stats.mprc) },
+ { "tx_multicast", E1000_STAT(stats.mptc) },
+ { "rx_errors", E1000_STAT(net_stats.rx_errors) },
+ { "tx_errors", E1000_STAT(net_stats.tx_errors) },
+ { "tx_dropped", E1000_STAT(net_stats.tx_dropped) },
+ { "multicast", E1000_STAT(stats.mprc) },
+ { "collisions", E1000_STAT(stats.colc) },
+ { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) },
+ { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) },
+ { "rx_crc_errors", E1000_STAT(stats.crcerrs) },
+ { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) },
+ { "rx_no_buffer_count", E1000_STAT(stats.rnbc) },
+ { "rx_missed_errors", E1000_STAT(stats.mpc) },
+ { "tx_aborted_errors", E1000_STAT(stats.ecol) },
+ { "tx_carrier_errors", E1000_STAT(stats.tncrs) },
+ { "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) },
+ { "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) },
+ { "tx_window_errors", E1000_STAT(stats.latecol) },
+ { "tx_abort_late_coll", E1000_STAT(stats.latecol) },
+ { "tx_deferred_ok", E1000_STAT(stats.dc) },
+ { "tx_single_coll_ok", E1000_STAT(stats.scc) },
+ { "tx_multi_coll_ok", E1000_STAT(stats.mcc) },
+ { "tx_timeout_count", E1000_STAT(tx_timeout_count) },
+ { "tx_restart_queue", E1000_STAT(restart_queue) },
+ { "rx_long_length_errors", E1000_STAT(stats.roc) },
+ { "rx_short_length_errors", E1000_STAT(stats.ruc) },
+ { "rx_align_errors", E1000_STAT(stats.algnerrc) },
+ { "tx_tcp_seg_good", E1000_STAT(stats.tsctc) },
+ { "tx_tcp_seg_failed", E1000_STAT(stats.tsctfc) },
+ { "rx_flow_control_xon", E1000_STAT(stats.xonrxc) },
+ { "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) },
+ { "tx_flow_control_xon", E1000_STAT(stats.xontxc) },
+ { "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) },
+ { "rx_long_byte_count", E1000_STAT(stats.gorcl) },
+ { "rx_csum_offload_good", E1000_STAT(hw_csum_good) },
+ { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) },
+ { "rx_header_split", E1000_STAT(rx_hdr_split) },
+ { "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) },
+ { "tx_smbus", E1000_STAT(stats.mgptc) },
+ { "rx_smbus", E1000_STAT(stats.mgprc) },
+ { "dropped_smbus", E1000_STAT(stats.mgpdc) },
+ { "rx_dma_failed", E1000_STAT(rx_dma_failed) },
+ { "tx_dma_failed", E1000_STAT(tx_dma_failed) },
+};
+
+#define E1000_GLOBAL_STATS_LEN \
+ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
+#define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN)
+static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
+ "Register test (offline)", "Eeprom test (offline)",
+ "Interrupt test (offline)", "Loopback test (offline)",
+ "Link test (on/offline)"
+};
+#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN
+
+static int e1000_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 status;
+
+ if (hw->media_type == e1000_media_type_copper) {
+
+ ecmd->supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_TP);
+ if (hw->phy.type == e1000_phy_ife)
+ ecmd->supported &= ~SUPPORTED_1000baseT_Full;
+ ecmd->advertising = ADVERTISED_TP;
+
+ if (hw->mac.autoneg == 1) {
+ ecmd->advertising |= ADVERTISED_Autoneg;
+ /* the e1000 autoneg seems to match ethtool nicely */
+ ecmd->advertising |= hw->phy.autoneg_advertised;
+ }
+
+ ecmd->port = PORT_TP;
+ ecmd->phy_address = hw->phy.addr;
+ ecmd->transceiver = XCVR_INTERNAL;
+
+ } else {
+ ecmd->supported = (SUPPORTED_1000baseT_Full |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Autoneg);
+
+ ecmd->advertising = (ADVERTISED_1000baseT_Full |
+ ADVERTISED_FIBRE |
+ ADVERTISED_Autoneg);
+
+ ecmd->port = PORT_FIBRE;
+ ecmd->transceiver = XCVR_EXTERNAL;
+ }
+
+ status = er32(STATUS);
+ if (status & E1000_STATUS_LU) {
+ if (status & E1000_STATUS_SPEED_1000)
+ ecmd->speed = 1000;
+ else if (status & E1000_STATUS_SPEED_100)
+ ecmd->speed = 100;
+ else
+ ecmd->speed = 10;
+
+ if (status & E1000_STATUS_FD)
+ ecmd->duplex = DUPLEX_FULL;
+ else
+ ecmd->duplex = DUPLEX_HALF;
+ } else {
+ ecmd->speed = -1;
+ ecmd->duplex = -1;
+ }
+
+ ecmd->autoneg = ((hw->media_type == e1000_media_type_fiber) ||
+ hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+ return 0;
+}
+
+static u32 e1000_get_link(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 status;
+
+ status = er32(STATUS);
+ return (status & E1000_STATUS_LU);
+}
+
+static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
+{
+ struct e1000_mac_info *mac = &adapter->hw.mac;
+
+ mac->autoneg = 0;
+
+ /* Fiber NICs only allow 1000 gbps Full duplex */
+ if ((adapter->hw.media_type == e1000_media_type_fiber) &&
+ spddplx != (SPEED_1000 + DUPLEX_FULL)) {
+ ndev_err(adapter->netdev, "Unsupported Speed/Duplex "
+ "configuration\n");
+ return -EINVAL;
+ }
+
+ switch (spddplx) {
+ case SPEED_10 + DUPLEX_HALF:
+ mac->forced_speed_duplex = ADVERTISE_10_HALF;
+ break;
+ case SPEED_10 + DUPLEX_FULL:
+ mac->forced_speed_duplex = ADVERTISE_10_FULL;
+ break;
+ case SPEED_100 + DUPLEX_HALF:
+ mac->forced_speed_duplex = ADVERTISE_100_HALF;
+ break;
+ case SPEED_100 + DUPLEX_FULL:
+ mac->forced_speed_duplex = ADVERTISE_100_FULL;
+ break;
+ case SPEED_1000 + DUPLEX_FULL:
+ mac->autoneg = 1;
+ adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL;
+ break;
+ case SPEED_1000 + DUPLEX_HALF: /* not supported */
+ default:
+ ndev_err(adapter->netdev, "Unsupported Speed/Duplex "
+ "configuration\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int e1000_set_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ /* When SoL/IDER sessions are active, autoneg/speed/duplex
+ * cannot be changed */
+ if (e1000_check_reset_block(hw)) {
+ ndev_err(netdev, "Cannot change link "
+ "characteristics when SoL/IDER is active.\n");
+ return -EINVAL;
+ }
+
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+ msleep(1);
+
+ if (ecmd->autoneg == AUTONEG_ENABLE) {
+ hw->mac.autoneg = 1;
+ if (hw->media_type == e1000_media_type_fiber)
+ hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full |
+ ADVERTISED_FIBRE |
+ ADVERTISED_Autoneg;
+ else
+ hw->phy.autoneg_advertised = ecmd->advertising |
+ ADVERTISED_TP |
+ ADVERTISED_Autoneg;
+ ecmd->advertising = hw->phy.autoneg_advertised;
+ } else {
+ if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
+ clear_bit(__E1000_RESETTING, &adapter->state);
+ return -EINVAL;
+ }
+ }
+
+ /* reset the link */
+
+ if (netif_running(adapter->netdev)) {
+ e1000e_down(adapter);
+ e1000e_up(adapter);
+ } else {
+ e1000e_reset(adapter);
+ }
+
+ clear_bit(__E1000_RESETTING, &adapter->state);
+ return 0;
+}
+
+static void e1000_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ pause->autoneg =
+ (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
+
+ if (hw->mac.fc == e1000_fc_rx_pause) {
+ pause->rx_pause = 1;
+ } else if (hw->mac.fc == e1000_fc_tx_pause) {
+ pause->tx_pause = 1;
+ } else if (hw->mac.fc == e1000_fc_full) {
+ pause->rx_pause = 1;
+ pause->tx_pause = 1;
+ }
+}
+
+static int e1000_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ int retval = 0;
+
+ adapter->fc_autoneg = pause->autoneg;
+
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+ msleep(1);
+
+ if (pause->rx_pause && pause->tx_pause)
+ hw->mac.fc = e1000_fc_full;
+ else if (pause->rx_pause && !pause->tx_pause)
+ hw->mac.fc = e1000_fc_rx_pause;
+ else if (!pause->rx_pause && pause->tx_pause)
+ hw->mac.fc = e1000_fc_tx_pause;
+ else if (!pause->rx_pause && !pause->tx_pause)
+ hw->mac.fc = e1000_fc_none;
+
+ hw->mac.original_fc = hw->mac.fc;
+
+ if (adapter->fc_autoneg == AUTONEG_ENABLE) {
+ hw->mac.fc = e1000_fc_default;
+ if (netif_running(adapter->netdev)) {
+ e1000e_down(adapter);
+ e1000e_up(adapter);
+ } else {
+ e1000e_reset(adapter);
+ }
+ } else {
+ retval = ((hw->media_type == e1000_media_type_fiber) ?
+ hw->mac.ops.setup_link(hw) : e1000e_force_mac_fc(hw));
+ }
+
+ clear_bit(__E1000_RESETTING, &adapter->state);
+ return retval;
+}
+
+static u32 e1000_get_rx_csum(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ return (adapter->flags & FLAG_RX_CSUM_ENABLED);
+}
+
+static int e1000_set_rx_csum(struct net_device *netdev, u32 data)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (data)
+ adapter->flags |= FLAG_RX_CSUM_ENABLED;
+ else
+ adapter->flags &= ~FLAG_RX_CSUM_ENABLED;
+
+ if (netif_running(netdev))
+ e1000e_reinit_locked(adapter);
+ else
+ e1000e_reset(adapter);
+ return 0;
+}
+
+static u32 e1000_get_tx_csum(struct net_device *netdev)
+{
+ return ((netdev->features & NETIF_F_HW_CSUM) != 0);
+}
+
+static int e1000_set_tx_csum(struct net_device *netdev, u32 data)
+{
+ if (data)
+ netdev->features |= NETIF_F_HW_CSUM;
+ else
+ netdev->features &= ~NETIF_F_HW_CSUM;
+
+ return 0;
+}
+
+static int e1000_set_tso(struct net_device *netdev, u32 data)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (data) {
+ netdev->features |= NETIF_F_TSO;
+ netdev->features |= NETIF_F_TSO6;
+ } else {
+ netdev->features &= ~NETIF_F_TSO;
+ netdev->features &= ~NETIF_F_TSO6;
+ }
+
+ ndev_info(netdev, "TSO is %s\n",
+ data ? "Enabled" : "Disabled");
+ adapter->flags |= FLAG_TSO_FORCE;
+ return 0;
+}
+
+static u32 e1000_get_msglevel(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ return adapter->msg_enable;
+}
+
+static void e1000_set_msglevel(struct net_device *netdev, u32 data)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ adapter->msg_enable = data;
+}
+
+static int e1000_get_regs_len(struct net_device *netdev)
+{
+#define E1000_REGS_LEN 32 /* overestimate */
+ return E1000_REGS_LEN * sizeof(u32);
+}
+
+static void e1000_get_regs(struct net_device *netdev,
+ struct ethtool_regs *regs, void *p)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 *regs_buff = p;
+ u16 phy_data;
+ u8 revision_id;
+
+ memset(p, 0, E1000_REGS_LEN * sizeof(u32));
+
+ pci_read_config_byte(adapter->pdev, PCI_REVISION_ID, &revision_id);
+
+ regs->version = (1 << 24) | (revision_id << 16) | adapter->pdev->device;
+
+ regs_buff[0] = er32(CTRL);
+ regs_buff[1] = er32(STATUS);
+
+ regs_buff[2] = er32(RCTL);
+ regs_buff[3] = er32(RDLEN);
+ regs_buff[4] = er32(RDH);
+ regs_buff[5] = er32(RDT);
+ regs_buff[6] = er32(RDTR);
+
+ regs_buff[7] = er32(TCTL);
+ regs_buff[8] = er32(TDLEN);
+ regs_buff[9] = er32(TDH);
+ regs_buff[10] = er32(TDT);
+ regs_buff[11] = er32(TIDV);
+
+ regs_buff[12] = adapter->hw.phy.type; /* PHY type (IGP=1, M88=0) */
+ if (hw->phy.type == e1000_phy_m88) {
+ e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ regs_buff[13] = (u32)phy_data; /* cable length */
+ regs_buff[14] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[15] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[16] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ regs_buff[17] = (u32)phy_data; /* extended 10bt distance */
+ regs_buff[18] = regs_buff[13]; /* cable polarity */
+ regs_buff[19] = 0; /* Dummy (to align w/ IGP phy reg dump) */
+ regs_buff[20] = regs_buff[17]; /* polarity correction */
+ /* phy receive errors */
+ regs_buff[22] = adapter->phy_stats.receive_errors;
+ regs_buff[23] = regs_buff[13]; /* mdix mode */
+ }
+ regs_buff[21] = adapter->phy_stats.idle_errors; /* phy idle errors */
+ e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
+ regs_buff[24] = (u32)phy_data; /* phy local receiver status */
+ regs_buff[25] = regs_buff[24]; /* phy remote receiver status */
+}
+
+static int e1000_get_eeprom_len(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ return adapter->hw.nvm.word_size * 2;
+}
+
+static int e1000_get_eeprom(struct net_device *netdev,
+ struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u16 *eeprom_buff;
+ int first_word;
+ int last_word;
+ int ret_val = 0;
+ u16 i;
+
+ if (eeprom->len == 0)
+ return -EINVAL;
+
+ eeprom->magic = adapter->pdev->vendor | (adapter->pdev->device << 16);
+
+ first_word = eeprom->offset >> 1;
+ last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+
+ eeprom_buff = kmalloc(sizeof(u16) *
+ (last_word - first_word + 1), GFP_KERNEL);
+ if (!eeprom_buff)
+ return -ENOMEM;
+
+ if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+ ret_val = e1000_read_nvm(hw, first_word,
+ last_word - first_word + 1,
+ eeprom_buff);
+ } else {
+ for (i = 0; i < last_word - first_word + 1; i++) {
+ ret_val = e1000_read_nvm(hw, first_word + i, 1,
+ &eeprom_buff[i]);
+ if (ret_val)
+ break;
+ }
+ }
+
+ /* Device's eeprom is always little-endian, word addressable */
+ for (i = 0; i < last_word - first_word + 1; i++)
+ le16_to_cpus(&eeprom_buff[i]);
+
+ memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
+ kfree(eeprom_buff);
+
+ return ret_val;
+}
+
+static int e1000_set_eeprom(struct net_device *netdev,
+ struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u16 *eeprom_buff;
+ void *ptr;
+ int max_len;
+ int first_word;
+ int last_word;
+ int ret_val = 0;
+ u16 i;
+
+ if (eeprom->len == 0)
+ return -EOPNOTSUPP;
+
+ if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16)))
+ return -EFAULT;
+
+ max_len = hw->nvm.word_size * 2;
+
+ first_word = eeprom->offset >> 1;
+ last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+ eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+ if (!eeprom_buff)
+ return -ENOMEM;
+
+ ptr = (void *)eeprom_buff;
+
+ if (eeprom->offset & 1) {
+ /* need read/modify/write of first changed EEPROM word */
+ /* only the second byte of the word is being modified */
+ ret_val = e1000_read_nvm(hw, first_word, 1, &eeprom_buff[0]);
+ ptr++;
+ }
+ if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0))
+ /* need read/modify/write of last changed EEPROM word */
+ /* only the first byte of the word is being modified */
+ ret_val = e1000_read_nvm(hw, last_word, 1,
+ &eeprom_buff[last_word - first_word]);
+
+ /* Device's eeprom is always little-endian, word addressable */
+ for (i = 0; i < last_word - first_word + 1; i++)
+ le16_to_cpus(&eeprom_buff[i]);
+
+ memcpy(ptr, bytes, eeprom->len);
+
+ for (i = 0; i < last_word - first_word + 1; i++)
+ eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
+
+ ret_val = e1000_write_nvm(hw, first_word,
+ last_word - first_word + 1, eeprom_buff);
+
+ /* Update the checksum over the first part of the EEPROM if needed
+ * and flush shadow RAM for 82573 controllers */
+ if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) ||
+ (hw->mac.type == e1000_82573)))
+ e1000e_update_nvm_checksum(hw);
+
+ kfree(eeprom_buff);
+ return ret_val;
+}
+
+static void e1000_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ char firmware_version[32];
+ u16 eeprom_data;
+
+ strncpy(drvinfo->driver, e1000e_driver_name, 32);
+ strncpy(drvinfo->version, e1000e_driver_version, 32);
+
+ /* EEPROM image version # is reported as firmware version # for
+ * PCI-E controllers */
+ e1000_read_nvm(&adapter->hw, 5, 1, &eeprom_data);
+ sprintf(firmware_version, "%d.%d-%d",
+ (eeprom_data & 0xF000) >> 12,
+ (eeprom_data & 0x0FF0) >> 4,
+ eeprom_data & 0x000F);
+
+ strncpy(drvinfo->fw_version, firmware_version, 32);
+ strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+ drvinfo->regdump_len = e1000_get_regs_len(netdev);
+ drvinfo->eedump_len = e1000_get_eeprom_len(netdev);
+}
+
+static void e1000_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+
+ ring->rx_max_pending = E1000_MAX_RXD;
+ ring->tx_max_pending = E1000_MAX_TXD;
+ ring->rx_mini_max_pending = 0;
+ ring->rx_jumbo_max_pending = 0;
+ ring->rx_pending = rx_ring->count;
+ ring->tx_pending = tx_ring->count;
+ ring->rx_mini_pending = 0;
+ ring->rx_jumbo_pending = 0;
+}
+
+static int e1000_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_ring *tx_ring, *tx_old;
+ struct e1000_ring *rx_ring, *rx_old;
+ int err;
+
+ if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+ return -EINVAL;
+
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+ msleep(1);
+
+ if (netif_running(adapter->netdev))
+ e1000e_down(adapter);
+
+ tx_old = adapter->tx_ring;
+ rx_old = adapter->rx_ring;
+
+ err = -ENOMEM;
+ tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+ if (!tx_ring)
+ goto err_alloc_tx;
+
+ rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+ if (!rx_ring)
+ goto err_alloc_rx;
+
+ adapter->tx_ring = tx_ring;
+ adapter->rx_ring = rx_ring;
+
+ rx_ring->count = max(ring->rx_pending, (u32)E1000_MIN_RXD);
+ rx_ring->count = min(rx_ring->count, (u32)(E1000_MAX_RXD));
+ rx_ring->count = ALIGN(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE);
+
+ tx_ring->count = max(ring->tx_pending, (u32)E1000_MIN_TXD);
+ tx_ring->count = min(tx_ring->count, (u32)(E1000_MAX_TXD));
+ tx_ring->count = ALIGN(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE);
+
+ if (netif_running(adapter->netdev)) {
+ /* Try to get new resources before deleting old */
+ err = e1000e_setup_rx_resources(adapter);
+ if (err)
+ goto err_setup_rx;
+ err = e1000e_setup_tx_resources(adapter);
+ if (err)
+ goto err_setup_tx;
+
+ /* save the new, restore the old in order to free it,
+ * then restore the new back again */
+ adapter->rx_ring = rx_old;
+ adapter->tx_ring = tx_old;
+ e1000e_free_rx_resources(adapter);
+ e1000e_free_tx_resources(adapter);
+ kfree(tx_old);
+ kfree(rx_old);
+ adapter->rx_ring = rx_ring;
+ adapter->tx_ring = tx_ring;
+ err = e1000e_up(adapter);
+ if (err)
+ goto err_setup;
+ }
+
+ clear_bit(__E1000_RESETTING, &adapter->state);
+ return 0;
+err_setup_tx:
+ e1000e_free_rx_resources(adapter);
+err_setup_rx:
+ adapter->rx_ring = rx_old;
+ adapter->tx_ring = tx_old;
+ kfree(rx_ring);
+err_alloc_rx:
+ kfree(tx_ring);
+err_alloc_tx:
+ e1000e_up(adapter);
+err_setup:
+ clear_bit(__E1000_RESETTING, &adapter->state);
+ return err;
+}
+
+#define REG_PATTERN_TEST(R, M, W) REG_PATTERN_TEST_ARRAY(R, 0, M, W)
+#define REG_PATTERN_TEST_ARRAY(reg, offset, mask, writeable) \
+{ \
+ u32 _pat; \
+ u32 _value; \
+ u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \
+ for (_pat = 0; _pat < ARRAY_SIZE(_test); _pat++) { \
+ E1000_WRITE_REG_ARRAY(hw, reg, offset, \
+ (_test[_pat] & writeable)); \
+ _value = E1000_READ_REG_ARRAY(hw, reg, offset); \
+ if (_value != (_test[_pat] & writeable & mask)) { \
+ ndev_err(netdev, "pattern test reg %04X " \
+ "failed: got 0x%08X expected 0x%08X\n", \
+ reg + offset, \
+ value, (_test[_pat] & writeable & mask)); \
+ *data = reg; \
+ return 1; \
+ } \
+ } \
+}
+
+#define REG_SET_AND_CHECK(R, M, W) \
+{ \
+ u32 _value; \
+ __ew32(hw, R, W & M); \
+ _value = __er32(hw, R); \
+ if ((W & M) != (_value & M)) { \
+ ndev_err(netdev, "set/check reg %04X test failed: " \
+ "got 0x%08X expected 0x%08X\n", R, (_value & M), \
+ (W & M)); \
+ *data = R; \
+ return 1; \
+ } \
+}
+
+static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_mac_info *mac = &adapter->hw.mac;
+ struct net_device *netdev = adapter->netdev;
+ u32 value;
+ u32 before;
+ u32 after;
+ u32 i;
+ u32 toggle;
+
+ /* The status register is Read Only, so a write should fail.
+ * Some bits that get toggled are ignored.
+ */
+ switch (mac->type) {
+ /* there are several bits on newer hardware that are r/w */
+ case e1000_82571:
+ case e1000_82572:
+ case e1000_80003es2lan:
+ toggle = 0x7FFFF3FF;
+ break;
+ case e1000_82573:
+ case e1000_ich8lan:
+ case e1000_ich9lan:
+ toggle = 0x7FFFF033;
+ break;
+ default:
+ toggle = 0xFFFFF833;
+ break;
+ }
+
+ before = er32(STATUS);
+ value = (er32(STATUS) & toggle);
+ ew32(STATUS, toggle);
+ after = er32(STATUS) & toggle;
+ if (value != after) {
+ ndev_err(netdev, "failed STATUS register test got: "
+ "0x%08X expected: 0x%08X\n", after, value);
+ *data = 1;
+ return 1;
+ }
+ /* restore previous status */
+ ew32(STATUS, before);
+
+ if ((mac->type != e1000_ich8lan) &&
+ (mac->type != e1000_ich9lan)) {
+ REG_PATTERN_TEST(E1000_FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_FCAH, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_FCT, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_VET, 0x0000FFFF, 0xFFFFFFFF);
+ }
+
+ REG_PATTERN_TEST(E1000_RDTR, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_RDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_RDLEN, 0x000FFF80, 0x000FFFFF);
+ REG_PATTERN_TEST(E1000_RDH, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(E1000_RDT, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(E1000_FCRTH, 0x0000FFF8, 0x0000FFF8);
+ REG_PATTERN_TEST(E1000_FCTTV, 0x0000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(E1000_TIPG, 0x3FFFFFFF, 0x3FFFFFFF);
+ REG_PATTERN_TEST(E1000_TDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_TDLEN, 0x000FFF80, 0x000FFFFF);
+
+ REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x00000000);
+
+ before = (((mac->type == e1000_ich8lan) ||
+ (mac->type == e1000_ich9lan)) ? 0x06C3B33E : 0x06DFB3FE);
+ REG_SET_AND_CHECK(E1000_RCTL, before, 0x003FFFFB);
+ REG_SET_AND_CHECK(E1000_TCTL, 0xFFFFFFFF, 0x00000000);
+
+ REG_SET_AND_CHECK(E1000_RCTL, before, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_RDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
+ if ((mac->type != e1000_ich8lan) &&
+ (mac->type != e1000_ich9lan))
+ REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF);
+ REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
+ REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF);
+ for (i = 0; i < mac->rar_entry_count; i++)
+ REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
+ 0x8003FFFF, 0xFFFFFFFF);
+
+ for (i = 0; i < mac->mta_reg_count; i++)
+ REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF);
+
+ *data = 0;
+ return 0;
+}
+
+static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data)
+{
+ u16 temp;
+ u16 checksum = 0;
+ u16 i;
+
+ *data = 0;
+ /* Read and add up the contents of the EEPROM */
+ for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+ if ((e1000_read_nvm(&adapter->hw, i, 1, &temp)) < 0) {
+ *data = 1;
+ break;
+ }
+ checksum += temp;
+ }
+
+ /* If Checksum is not Correct return error else test passed */
+ if ((checksum != (u16) NVM_SUM) && !(*data))
+ *data = 2;
+
+ return *data;
+}
+
+static irqreturn_t e1000_test_intr(int irq, void *data)
+{
+ struct net_device *netdev = (struct net_device *) data;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ adapter->test_icr |= er32(ICR);
+
+ return IRQ_HANDLED;
+}
+
+static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 mask;
+ u32 shared_int = 1;
+ u32 irq = adapter->pdev->irq;
+ int i;
+
+ *data = 0;
+
+ /* NOTE: we don't test MSI interrupts here, yet */
+ /* Hook up test interrupt handler just for this test */
+ if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name,
+ netdev)) {
+ shared_int = 0;
+ } else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED,
+ netdev->name, netdev)) {
+ *data = 1;
+ return -1;
+ }
+ ndev_info(netdev, "testing %s interrupt\n",
+ (shared_int ? "shared" : "unshared"));
+
+ /* Disable all the interrupts */
+ ew32(IMC, 0xFFFFFFFF);
+ msleep(10);
+
+ /* Test each interrupt */
+ for (i = 0; i < 10; i++) {
+
+ if (((adapter->hw.mac.type == e1000_ich8lan) ||
+ (adapter->hw.mac.type == e1000_ich9lan)) && i == 8)
+ continue;
+
+ /* Interrupt to test */
+ mask = 1 << i;
+
+ if (!shared_int) {
+ /* Disable the interrupt to be reported in
+ * the cause register and then force the same
+ * interrupt and see if one gets posted. If
+ * an interrupt was posted to the bus, the
+ * test failed.
+ */
+ adapter->test_icr = 0;
+ ew32(IMC, mask);
+ ew32(ICS, mask);
+ msleep(10);
+
+ if (adapter->test_icr & mask) {
+ *data = 3;
+ break;
+ }
+ }
+
+ /* Enable the interrupt to be reported in
+ * the cause register and then force the same
+ * interrupt and see if one gets posted. If
+ * an interrupt was not posted to the bus, the
+ * test failed.
+ */
+ adapter->test_icr = 0;
+ ew32(IMS, mask);
+ ew32(ICS, mask);
+ msleep(10);
+
+ if (!(adapter->test_icr & mask)) {
+ *data = 4;
+ break;
+ }
+
+ if (!shared_int) {
+ /* Disable the other interrupts to be reported in
+ * the cause register and then force the other
+ * interrupts and see if any get posted. If
+ * an interrupt was posted to the bus, the
+ * test failed.
+ */
+ adapter->test_icr = 0;
+ ew32(IMC, ~mask & 0x00007FFF);
+ ew32(ICS, ~mask & 0x00007FFF);
+ msleep(10);
+
+ if (adapter->test_icr) {
+ *data = 5;
+ break;
+ }
+ }
+ }
+
+ /* Disable all the interrupts */
+ ew32(IMC, 0xFFFFFFFF);
+ msleep(10);
+
+ /* Unhook test interrupt handler */
+ free_irq(irq, netdev);
+
+ return *data;
+}
+
+static void e1000_free_desc_rings(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *tx_ring = &adapter->test_tx_ring;
+ struct e1000_ring *rx_ring = &adapter->test_rx_ring;
+ struct pci_dev *pdev = adapter->pdev;
+ int i;
+
+ if (tx_ring->desc && tx_ring->buffer_info) {
+ for (i = 0; i < tx_ring->count; i++) {
+ if (tx_ring->buffer_info[i].dma)
+ pci_unmap_single(pdev,
+ tx_ring->buffer_info[i].dma,
+ tx_ring->buffer_info[i].length,
+ PCI_DMA_TODEVICE);
+ if (tx_ring->buffer_info[i].skb)
+ dev_kfree_skb(tx_ring->buffer_info[i].skb);
+ }
+ }
+
+ if (rx_ring->desc && rx_ring->buffer_info) {
+ for (i = 0; i < rx_ring->count; i++) {
+ if (rx_ring->buffer_info[i].dma)
+ pci_unmap_single(pdev,
+ rx_ring->buffer_info[i].dma,
+ 2048, PCI_DMA_FROMDEVICE);
+ if (rx_ring->buffer_info[i].skb)
+ dev_kfree_skb(rx_ring->buffer_info[i].skb);
+ }
+ }
+
+ if (tx_ring->desc) {
+ dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
+ tx_ring->dma);
+ tx_ring->desc = NULL;
+ }
+ if (rx_ring->desc) {
+ dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
+ rx_ring->dma);
+ rx_ring->desc = NULL;
+ }
+
+ kfree(tx_ring->buffer_info);
+ tx_ring->buffer_info = NULL;
+ kfree(rx_ring->buffer_info);
+ rx_ring->buffer_info = NULL;
+}
+
+static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *tx_ring = &adapter->test_tx_ring;
+ struct e1000_ring *rx_ring = &adapter->test_rx_ring;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 rctl;
+ int size;
+ int i;
+ int ret_val;
+
+ /* Setup Tx descriptor ring and Tx buffers */
+
+ if (!tx_ring->count)
+ tx_ring->count = E1000_DEFAULT_TXD;
+
+ size = tx_ring->count * sizeof(struct e1000_buffer);
+ tx_ring->buffer_info = kmalloc(size, GFP_KERNEL);
+ if (!tx_ring->buffer_info) {
+ ret_val = 1;
+ goto err_nomem;
+ }
+ memset(tx_ring->buffer_info, 0, size);
+
+ tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
+ tx_ring->size = ALIGN(tx_ring->size, 4096);
+ tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
+ &tx_ring->dma, GFP_KERNEL);
+ if (!tx_ring->desc) {
+ ret_val = 2;
+ goto err_nomem;
+ }
+ memset(tx_ring->desc, 0, tx_ring->size);
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+
+ ew32(TDBAL,
+ ((u64) tx_ring->dma & 0x00000000FFFFFFFF));
+ ew32(TDBAH, ((u64) tx_ring->dma >> 32));
+ ew32(TDLEN,
+ tx_ring->count * sizeof(struct e1000_tx_desc));
+ ew32(TDH, 0);
+ ew32(TDT, 0);
+ ew32(TCTL,
+ E1000_TCTL_PSP | E1000_TCTL_EN |
+ E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT |
+ E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT);
+
+ for (i = 0; i < tx_ring->count; i++) {
+ struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i);
+ struct sk_buff *skb;
+ unsigned int skb_size = 1024;
+
+ skb = alloc_skb(skb_size, GFP_KERNEL);
+ if (!skb) {
+ ret_val = 3;
+ goto err_nomem;
+ }
+ skb_put(skb, skb_size);
+ tx_ring->buffer_info[i].skb = skb;
+ tx_ring->buffer_info[i].length = skb->len;
+ tx_ring->buffer_info[i].dma =
+ pci_map_single(pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(tx_ring->buffer_info[i].dma)) {
+ ret_val = 4;
+ goto err_nomem;
+ }
+ tx_desc->buffer_addr = cpu_to_le64(
+ tx_ring->buffer_info[i].dma);
+ tx_desc->lower.data = cpu_to_le32(skb->len);
+ tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP |
+ E1000_TXD_CMD_IFCS |
+ E1000_TXD_CMD_RPS);
+ tx_desc->upper.data = 0;
+ }
+
+ /* Setup Rx descriptor ring and Rx buffers */
+
+ if (!rx_ring->count)
+ rx_ring->count = E1000_DEFAULT_RXD;
+
+ size = rx_ring->count * sizeof(struct e1000_buffer);
+ rx_ring->buffer_info = kmalloc(size, GFP_KERNEL);
+ if (!rx_ring->buffer_info) {
+ ret_val = 5;
+ goto err_nomem;
+ }
+ memset(rx_ring->buffer_info, 0, size);
+
+ rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc);
+ rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
+ &rx_ring->dma, GFP_KERNEL);
+ if (!rx_ring->desc) {
+ ret_val = 6;
+ goto err_nomem;
+ }
+ memset(rx_ring->desc, 0, rx_ring->size);
+ rx_ring->next_to_use = 0;
+ rx_ring->next_to_clean = 0;
+
+ rctl = er32(RCTL);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+ ew32(RDBAL, ((u64) rx_ring->dma & 0xFFFFFFFF));
+ ew32(RDBAH, ((u64) rx_ring->dma >> 32));
+ ew32(RDLEN, rx_ring->size);
+ ew32(RDH, 0);
+ ew32(RDT, 0);
+ rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
+ E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+ (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
+ ew32(RCTL, rctl);
+
+ for (i = 0; i < rx_ring->count; i++) {
+ struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i);
+ struct sk_buff *skb;
+
+ skb = alloc_skb(2048 + NET_IP_ALIGN, GFP_KERNEL);
+ if (!skb) {
+ ret_val = 7;
+ goto err_nomem;
+ }
+ skb_reserve(skb, NET_IP_ALIGN);
+ rx_ring->buffer_info[i].skb = skb;
+ rx_ring->buffer_info[i].dma =
+ pci_map_single(pdev, skb->data, 2048,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(rx_ring->buffer_info[i].dma)) {
+ ret_val = 8;
+ goto err_nomem;
+ }
+ rx_desc->buffer_addr =
+ cpu_to_le64(rx_ring->buffer_info[i].dma);
+ memset(skb->data, 0x00, skb->len);
+ }
+
+ return 0;
+
+err_nomem:
+ e1000_free_desc_rings(adapter);
+ return ret_val;
+}
+
+static void e1000_phy_disable_receiver(struct e1000_adapter *adapter)
+{
+ /* Write out to PHY registers 29 and 30 to disable the Receiver. */
+ e1e_wphy(&adapter->hw, 29, 0x001F);
+ e1e_wphy(&adapter->hw, 30, 0x8FFC);
+ e1e_wphy(&adapter->hw, 29, 0x001A);
+ e1e_wphy(&adapter->hw, 30, 0x8FF0);
+}
+
+static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl_reg = 0;
+ u32 stat_reg = 0;
+
+ adapter->hw.mac.autoneg = 0;
+
+ if (adapter->hw.phy.type == e1000_phy_m88) {
+ /* Auto-MDI/MDIX Off */
+ e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
+ /* reset to update Auto-MDI/MDIX */
+ e1e_wphy(hw, PHY_CONTROL, 0x9140);
+ /* autoneg off */
+ e1e_wphy(hw, PHY_CONTROL, 0x8140);
+ } else if (adapter->hw.phy.type == e1000_phy_gg82563)
+ e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC);
+
+ ctrl_reg = er32(CTRL);
+
+ if (adapter->hw.phy.type == e1000_phy_ife) {
+ /* force 100, set loopback */
+ e1e_wphy(hw, PHY_CONTROL, 0x6100);
+
+ /* Now set up the MAC to the same speed/duplex as the PHY. */
+ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_100 |/* Force Speed to 100 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+ } else {
+ /* force 1000, set loopback */
+ e1e_wphy(hw, PHY_CONTROL, 0x4140);
+
+ /* Now set up the MAC to the same speed/duplex as the PHY. */
+ ctrl_reg = er32(CTRL);
+ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+ }
+
+ if (adapter->hw.media_type == e1000_media_type_copper &&
+ adapter->hw.phy.type == e1000_phy_m88) {
+ ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
+ } else {
+ /* Set the ILOS bit on the fiber Nic if half duplex link is
+ * detected. */
+ stat_reg = er32(STATUS);
+ if ((stat_reg & E1000_STATUS_FD) == 0)
+ ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
+ }
+
+ ew32(CTRL, ctrl_reg);
+
+ /* Disable the receiver on the PHY so when a cable is plugged in, the
+ * PHY does not begin to autoneg when a cable is reconnected to the NIC.
+ */
+ if (adapter->hw.phy.type == e1000_phy_m88)
+ e1000_phy_disable_receiver(adapter);
+
+ udelay(500);
+
+ return 0;
+}
+
+static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl = er32(CTRL);
+ int link = 0;
+
+ /* special requirements for 82571/82572 fiber adapters */
+
+ /* jump through hoops to make sure link is up because serdes
+ * link is hardwired up */
+ ctrl |= E1000_CTRL_SLU;
+ ew32(CTRL, ctrl);
+
+ /* disable autoneg */
+ ctrl = er32(TXCW);
+ ctrl &= ~(1 << 31);
+ ew32(TXCW, ctrl);
+
+ link = (er32(STATUS) & E1000_STATUS_LU);
+
+ if (!link) {
+ /* set invert loss of signal */
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_ILOS;
+ ew32(CTRL, ctrl);
+ }
+
+ /* special write to serdes control register to enable SerDes analog
+ * loopback */
+#define E1000_SERDES_LB_ON 0x410
+ ew32(SCTL, E1000_SERDES_LB_ON);
+ msleep(10);
+
+ return 0;
+}
+
+/* only call this for fiber/serdes connections to es2lan */
+static int e1000_set_es2lan_mac_loopback(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrlext = er32(CTRL_EXT);
+ u32 ctrl = er32(CTRL);
+
+ /* save CTRL_EXT to restore later, reuse an empty variable (unused
+ on mac_type 80003es2lan) */
+ adapter->tx_fifo_head = ctrlext;
+
+ /* clear the serdes mode bits, putting the device into mac loopback */
+ ctrlext &= ~E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES;
+ ew32(CTRL_EXT, ctrlext);
+
+ /* force speed to 1000/FD, link up */
+ ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX |
+ E1000_CTRL_SPD_1000 | E1000_CTRL_FD);
+ ew32(CTRL, ctrl);
+
+ /* set mac loopback */
+ ctrl = er32(RCTL);
+ ctrl |= E1000_RCTL_LBM_MAC;
+ ew32(RCTL, ctrl);
+
+ /* set testing mode parameters (no need to reset later) */
+#define KMRNCTRLSTA_OPMODE (0x1F << 16)
+#define KMRNCTRLSTA_OPMODE_1GB_FD_GMII 0x0582
+ ew32(KMRNCTRLSTA,
+ (KMRNCTRLSTA_OPMODE | KMRNCTRLSTA_OPMODE_1GB_FD_GMII));
+
+ return 0;
+}
+
+static int e1000_setup_loopback_test(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 rctl;
+
+ if (hw->media_type == e1000_media_type_fiber ||
+ hw->media_type == e1000_media_type_internal_serdes) {
+ switch (hw->mac.type) {
+ case e1000_80003es2lan:
+ return e1000_set_es2lan_mac_loopback(adapter);
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ return e1000_set_82571_fiber_loopback(adapter);
+ break;
+ default:
+ rctl = er32(RCTL);
+ rctl |= E1000_RCTL_LBM_TCVR;
+ ew32(RCTL, rctl);
+ return 0;
+ }
+ } else if (hw->media_type == e1000_media_type_copper) {
+ return e1000_integrated_phy_loopback(adapter);
+ }
+
+ return 7;
+}
+
+static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 rctl;
+ u16 phy_reg;
+
+ rctl = er32(RCTL);
+ rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
+ ew32(RCTL, rctl);
+
+ switch (hw->mac.type) {
+ case e1000_80003es2lan:
+ if (hw->media_type == e1000_media_type_fiber ||
+ hw->media_type == e1000_media_type_internal_serdes) {
+ /* restore CTRL_EXT, stealing space from tx_fifo_head */
+ ew32(CTRL_EXT,
+ adapter->tx_fifo_head);
+ adapter->tx_fifo_head = 0;
+ }
+ /* fall through */
+ case e1000_82571:
+ case e1000_82572:
+ if (hw->media_type == e1000_media_type_fiber ||
+ hw->media_type == e1000_media_type_internal_serdes) {
+#define E1000_SERDES_LB_OFF 0x400
+ ew32(SCTL, E1000_SERDES_LB_OFF);
+ msleep(10);
+ break;
+ }
+ /* Fall Through */
+ default:
+ hw->mac.autoneg = 1;
+ if (hw->phy.type == e1000_phy_gg82563)
+ e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x180);
+ e1e_rphy(hw, PHY_CONTROL, &phy_reg);
+ if (phy_reg & MII_CR_LOOPBACK) {
+ phy_reg &= ~MII_CR_LOOPBACK;
+ e1e_wphy(hw, PHY_CONTROL, phy_reg);
+ e1000e_commit_phy(hw);
+ }
+ break;
+ }
+}
+
+static void e1000_create_lbtest_frame(struct sk_buff *skb,
+ unsigned int frame_size)
+{
+ memset(skb->data, 0xFF, frame_size);
+ frame_size &= ~1;
+ memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
+ memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);
+ memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);
+}
+
+static int e1000_check_lbtest_frame(struct sk_buff *skb,
+ unsigned int frame_size)
+{
+ frame_size &= ~1;
+ if (*(skb->data + 3) == 0xFF)
+ if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
+ (*(skb->data + frame_size / 2 + 12) == 0xAF))
+ return 0;
+ return 13;
+}
+
+static int e1000_run_loopback_test(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *tx_ring = &adapter->test_tx_ring;
+ struct e1000_ring *rx_ring = &adapter->test_rx_ring;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_hw *hw = &adapter->hw;
+ int i, j, k, l;
+ int lc;
+ int good_cnt;
+ int ret_val = 0;
+ unsigned long time;
+
+ ew32(RDT, rx_ring->count - 1);
+
+ /* Calculate the loop count based on the largest descriptor ring
+ * The idea is to wrap the largest ring a number of times using 64
+ * send/receive pairs during each loop
+ */
+
+ if (rx_ring->count <= tx_ring->count)
+ lc = ((tx_ring->count / 64) * 2) + 1;
+ else
+ lc = ((rx_ring->count / 64) * 2) + 1;
+
+ k = 0;
+ l = 0;
+ for (j = 0; j <= lc; j++) { /* loop count loop */
+ for (i = 0; i < 64; i++) { /* send the packets */
+ e1000_create_lbtest_frame(
+ tx_ring->buffer_info[i].skb, 1024);
+ pci_dma_sync_single_for_device(pdev,
+ tx_ring->buffer_info[k].dma,
+ tx_ring->buffer_info[k].length,
+ PCI_DMA_TODEVICE);
+ k++;
+ if (k == tx_ring->count)
+ k = 0;
+ }
+ ew32(TDT, k);
+ msleep(200);
+ time = jiffies; /* set the start time for the receive */
+ good_cnt = 0;
+ do { /* receive the sent packets */
+ pci_dma_sync_single_for_cpu(pdev,
+ rx_ring->buffer_info[l].dma, 2048,
+ PCI_DMA_FROMDEVICE);
+
+ ret_val = e1000_check_lbtest_frame(
+ rx_ring->buffer_info[l].skb, 1024);
+ if (!ret_val)
+ good_cnt++;
+ l++;
+ if (l == rx_ring->count)
+ l = 0;
+ /* time + 20 msecs (200 msecs on 2.4) is more than
+ * enough time to complete the receives, if it's
+ * exceeded, break and error off
+ */
+ } while ((good_cnt < 64) && !time_after(jiffies, time + 20));
+ if (good_cnt != 64) {
+ ret_val = 13; /* ret_val is the same as mis-compare */
+ break;
+ }
+ if (jiffies >= (time + 2)) {
+ ret_val = 14; /* error code for time out error */
+ break;
+ }
+ } /* end loop count loop */
+ return ret_val;
+}
+
+static int e1000_loopback_test(struct e1000_adapter *adapter, u64 *data)
+{
+ /* PHY loopback cannot be performed if SoL/IDER
+ * sessions are active */
+ if (e1000_check_reset_block(&adapter->hw)) {
+ ndev_err(adapter->netdev, "Cannot do PHY loopback test "
+ "when SoL/IDER is active.\n");
+ *data = 0;
+ goto out;
+ }
+
+ *data = e1000_setup_desc_rings(adapter);
+ if (*data)
+ goto out;
+
+ *data = e1000_setup_loopback_test(adapter);
+ if (*data)
+ goto err_loopback;
+
+ *data = e1000_run_loopback_test(adapter);
+ e1000_loopback_cleanup(adapter);
+
+err_loopback:
+ e1000_free_desc_rings(adapter);
+out:
+ return *data;
+}
+
+static int e1000_link_test(struct e1000_adapter *adapter, u64 *data)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ *data = 0;
+ if (hw->media_type == e1000_media_type_internal_serdes) {
+ int i = 0;
+ hw->mac.serdes_has_link = 0;
+
+ /* On some blade server designs, link establishment
+ * could take as long as 2-3 minutes */
+ do {
+ hw->mac.ops.check_for_link(hw);
+ if (hw->mac.serdes_has_link)
+ return *data;
+ msleep(20);
+ } while (i++ < 3750);
+
+ *data = 1;
+ } else {
+ hw->mac.ops.check_for_link(hw);
+ if (hw->mac.autoneg)
+ msleep(4000);
+
+ if (!(er32(STATUS) &
+ E1000_STATUS_LU))
+ *data = 1;
+ }
+ return *data;
+}
+
+static int e1000e_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_TEST:
+ return E1000_TEST_LEN;
+ case ETH_SS_STATS:
+ return E1000_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void e1000_diag_test(struct net_device *netdev,
+ struct ethtool_test *eth_test, u64 *data)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ u16 autoneg_advertised;
+ u8 forced_speed_duplex;
+ u8 autoneg;
+ bool if_running = netif_running(netdev);
+
+ set_bit(__E1000_TESTING, &adapter->state);
+ if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+ /* Offline tests */
+
+ /* save speed, duplex, autoneg settings */
+ autoneg_advertised = adapter->hw.phy.autoneg_advertised;
+ forced_speed_duplex = adapter->hw.mac.forced_speed_duplex;
+ autoneg = adapter->hw.mac.autoneg;
+
+ ndev_info(netdev, "offline testing starting\n");
+
+ /* Link test performed before hardware reset so autoneg doesn't
+ * interfere with test result */
+ if (e1000_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ if (if_running)
+ /* indicate we're in test mode */
+ dev_close(netdev);
+ else
+ e1000e_reset(adapter);
+
+ if (e1000_reg_test(adapter, &data[0]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000e_reset(adapter);
+ if (e1000_eeprom_test(adapter, &data[1]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000e_reset(adapter);
+ if (e1000_intr_test(adapter, &data[2]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ e1000e_reset(adapter);
+ /* make sure the phy is powered up */
+ e1000e_power_up_phy(adapter);
+ if (e1000_loopback_test(adapter, &data[3]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ /* restore speed, duplex, autoneg settings */
+ adapter->hw.phy.autoneg_advertised = autoneg_advertised;
+ adapter->hw.mac.forced_speed_duplex = forced_speed_duplex;
+ adapter->hw.mac.autoneg = autoneg;
+
+ /* force this routine to wait until autoneg complete/timeout */
+ adapter->hw.phy.wait_for_link = 1;
+ e1000e_reset(adapter);
+ adapter->hw.phy.wait_for_link = 0;
+
+ clear_bit(__E1000_TESTING, &adapter->state);
+ if (if_running)
+ dev_open(netdev);
+ } else {
+ ndev_info(netdev, "online testing starting\n");
+ /* Online tests */
+ if (e1000_link_test(adapter, &data[4]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+
+ /* Online tests aren't run; pass by default */
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 0;
+
+ clear_bit(__E1000_TESTING, &adapter->state);
+ }
+ msleep_interruptible(4 * 1000);
+}
+
+static void e1000_get_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ wol->supported = 0;
+ wol->wolopts = 0;
+
+ if (!(adapter->flags & FLAG_HAS_WOL))
+ return;
+
+ wol->supported = WAKE_UCAST | WAKE_MCAST |
+ WAKE_BCAST | WAKE_MAGIC;
+
+ /* apply any specific unsupported masks here */
+ if (adapter->flags & FLAG_NO_WAKE_UCAST) {
+ wol->supported &= ~WAKE_UCAST;
+
+ if (adapter->wol & E1000_WUFC_EX)
+ ndev_err(netdev, "Interface does not support "
+ "directed (unicast) frame wake-up packets\n");
+ }
+
+ if (adapter->wol & E1000_WUFC_EX)
+ wol->wolopts |= WAKE_UCAST;
+ if (adapter->wol & E1000_WUFC_MC)
+ wol->wolopts |= WAKE_MCAST;
+ if (adapter->wol & E1000_WUFC_BC)
+ wol->wolopts |= WAKE_BCAST;
+ if (adapter->wol & E1000_WUFC_MAG)
+ wol->wolopts |= WAKE_MAGIC;
+}
+
+static int e1000_set_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+ return -EOPNOTSUPP;
+
+ if (!(adapter->flags & FLAG_HAS_WOL))
+ return wol->wolopts ? -EOPNOTSUPP : 0;
+
+ /* these settings will always override what we currently have */
+ adapter->wol = 0;
+
+ if (wol->wolopts & WAKE_UCAST)
+ adapter->wol |= E1000_WUFC_EX;
+ if (wol->wolopts & WAKE_MCAST)
+ adapter->wol |= E1000_WUFC_MC;
+ if (wol->wolopts & WAKE_BCAST)
+ adapter->wol |= E1000_WUFC_BC;
+ if (wol->wolopts & WAKE_MAGIC)
+ adapter->wol |= E1000_WUFC_MAG;
+
+ return 0;
+}
+
+/* toggle LED 4 times per second = 2 "blinks" per second */
+#define E1000_ID_INTERVAL (HZ/4)
+
+/* bit defines for adapter->led_status */
+#define E1000_LED_ON 0
+
+static void e1000_led_blink_callback(unsigned long data)
+{
+ struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+
+ if (test_and_change_bit(E1000_LED_ON, &adapter->led_status))
+ adapter->hw.mac.ops.led_off(&adapter->hw);
+ else
+ adapter->hw.mac.ops.led_on(&adapter->hw);
+
+ mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL);
+}
+
+static int e1000_phys_id(struct net_device *netdev, u32 data)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (!data)
+ data = INT_MAX;
+
+ if (adapter->hw.phy.type == e1000_phy_ife) {
+ if (!adapter->blink_timer.function) {
+ init_timer(&adapter->blink_timer);
+ adapter->blink_timer.function =
+ e1000_led_blink_callback;
+ adapter->blink_timer.data = (unsigned long) adapter;
+ }
+ mod_timer(&adapter->blink_timer, jiffies);
+ msleep_interruptible(data * 1000);
+ del_timer_sync(&adapter->blink_timer);
+ e1e_wphy(&adapter->hw,
+ IFE_PHY_SPECIAL_CONTROL_LED, 0);
+ } else {
+ e1000e_blink_led(&adapter->hw);
+ msleep_interruptible(data * 1000);
+ }
+
+ adapter->hw.mac.ops.led_off(&adapter->hw);
+ clear_bit(E1000_LED_ON, &adapter->led_status);
+ adapter->hw.mac.ops.cleanup_led(&adapter->hw);
+
+ return 0;
+}
+
+static int e1000_nway_reset(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ if (netif_running(netdev))
+ e1000e_reinit_locked(adapter);
+ return 0;
+}
+
+static void e1000_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ int i;
+
+ e1000e_update_stats(adapter);
+ for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
+ char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset;
+ data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+}
+
+static void e1000_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *data)
+{
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_TEST:
+ memcpy(data, *e1000_gstrings_test,
+ E1000_TEST_LEN*ETH_GSTRING_LEN);
+ break;
+ case ETH_SS_STATS:
+ for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
+ memcpy(p, e1000_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ }
+}
+
+static const struct ethtool_ops e1000_ethtool_ops = {
+ .get_settings = e1000_get_settings,
+ .set_settings = e1000_set_settings,
+ .get_drvinfo = e1000_get_drvinfo,
+ .get_regs_len = e1000_get_regs_len,
+ .get_regs = e1000_get_regs,
+ .get_wol = e1000_get_wol,
+ .set_wol = e1000_set_wol,
+ .get_msglevel = e1000_get_msglevel,
+ .set_msglevel = e1000_set_msglevel,
+ .nway_reset = e1000_nway_reset,
+ .get_link = e1000_get_link,
+ .get_eeprom_len = e1000_get_eeprom_len,
+ .get_eeprom = e1000_get_eeprom,
+ .set_eeprom = e1000_set_eeprom,
+ .get_ringparam = e1000_get_ringparam,
+ .set_ringparam = e1000_set_ringparam,
+ .get_pauseparam = e1000_get_pauseparam,
+ .set_pauseparam = e1000_set_pauseparam,
+ .get_rx_csum = e1000_get_rx_csum,
+ .set_rx_csum = e1000_set_rx_csum,
+ .get_tx_csum = e1000_get_tx_csum,
+ .set_tx_csum = e1000_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = e1000_set_tso,
+ .self_test = e1000_diag_test,
+ .get_strings = e1000_get_strings,
+ .phys_id = e1000_phys_id,
+ .get_ethtool_stats = e1000_get_ethtool_stats,
+ .get_sset_count = e1000e_get_sset_count,
+};
+
+void e1000e_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops);
+}
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
new file mode 100644
index 00000000000..64515789fd4
--- /dev/null
+++ b/drivers/net/e1000e/hw.h
@@ -0,0 +1,864 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include <linux/types.h>
+
+struct e1000_hw;
+struct e1000_adapter;
+
+#include "defines.h"
+
+#define er32(reg) __er32(hw, E1000_##reg)
+#define ew32(reg,val) __ew32(hw, E1000_##reg, (val))
+#define e1e_flush() er32(STATUS)
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
+ (writel((value), ((a)->hw_addr + reg + ((offset) << 2))))
+
+#define E1000_READ_REG_ARRAY(a, reg, offset) \
+ (readl((a)->hw_addr + reg + ((offset) << 2)))
+
+enum e1e_registers {
+ E1000_CTRL = 0x00000, /* Device Control - RW */
+ E1000_STATUS = 0x00008, /* Device Status - RO */
+ E1000_EECD = 0x00010, /* EEPROM/Flash Control - RW */
+ E1000_EERD = 0x00014, /* EEPROM Read - RW */
+ E1000_CTRL_EXT = 0x00018, /* Extended Device Control - RW */
+ E1000_FLA = 0x0001C, /* Flash Access - RW */
+ E1000_MDIC = 0x00020, /* MDI Control - RW */
+ E1000_SCTL = 0x00024, /* SerDes Control - RW */
+ E1000_FCAL = 0x00028, /* Flow Control Address Low - RW */
+ E1000_FCAH = 0x0002C, /* Flow Control Address High -RW */
+ E1000_FEXTNVM = 0x00028, /* Future Extended NVM - RW */
+ E1000_FCT = 0x00030, /* Flow Control Type - RW */
+ E1000_VET = 0x00038, /* VLAN Ether Type - RW */
+ E1000_ICR = 0x000C0, /* Interrupt Cause Read - R/clr */
+ E1000_ITR = 0x000C4, /* Interrupt Throttling Rate - RW */
+ E1000_ICS = 0x000C8, /* Interrupt Cause Set - WO */
+ E1000_IMS = 0x000D0, /* Interrupt Mask Set - RW */
+ E1000_IMC = 0x000D8, /* Interrupt Mask Clear - WO */
+ E1000_IAM = 0x000E0, /* Interrupt Acknowledge Auto Mask */
+ E1000_RCTL = 0x00100, /* RX Control - RW */
+ E1000_FCTTV = 0x00170, /* Flow Control Transmit Timer Value - RW */
+ E1000_TXCW = 0x00178, /* TX Configuration Word - RW */
+ E1000_RXCW = 0x00180, /* RX Configuration Word - RO */
+ E1000_TCTL = 0x00400, /* TX Control - RW */
+ E1000_TCTL_EXT = 0x00404, /* Extended TX Control - RW */
+ E1000_TIPG = 0x00410, /* TX Inter-packet gap -RW */
+ E1000_AIT = 0x00458, /* Adaptive Interframe Spacing Throttle - RW */
+ E1000_LEDCTL = 0x00E00, /* LED Control - RW */
+ E1000_EXTCNF_CTRL = 0x00F00, /* Extended Configuration Control */
+ E1000_EXTCNF_SIZE = 0x00F08, /* Extended Configuration Size */
+ E1000_PHY_CTRL = 0x00F10, /* PHY Control Register in CSR */
+ E1000_PBA = 0x01000, /* Packet Buffer Allocation - RW */
+ E1000_PBS = 0x01008, /* Packet Buffer Size */
+ E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */
+ E1000_EEWR = 0x0102C, /* EEPROM Write Register - RW */
+ E1000_FLOP = 0x0103C, /* FLASH Opcode Register */
+ E1000_ERT = 0x02008, /* Early Rx Threshold - RW */
+ E1000_FCRTL = 0x02160, /* Flow Control Receive Threshold Low - RW */
+ E1000_FCRTH = 0x02168, /* Flow Control Receive Threshold High - RW */
+ E1000_PSRCTL = 0x02170, /* Packet Split Receive Control - RW */
+ E1000_RDBAL = 0x02800, /* RX Descriptor Base Address Low - RW */
+ E1000_RDBAH = 0x02804, /* RX Descriptor Base Address High - RW */
+ E1000_RDLEN = 0x02808, /* RX Descriptor Length - RW */
+ E1000_RDH = 0x02810, /* RX Descriptor Head - RW */
+ E1000_RDT = 0x02818, /* RX Descriptor Tail - RW */
+ E1000_RDTR = 0x02820, /* RX Delay Timer - RW */
+ E1000_RADV = 0x0282C, /* RX Interrupt Absolute Delay Timer - RW */
+
+/* Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ *
+ */
+#define E1000_RDBAL_REG(_n) (E1000_RDBAL + (_n << 8))
+ E1000_KABGTXD = 0x03004, /* AFE Band Gap Transmit Ref Data */
+ E1000_TDBAL = 0x03800, /* TX Descriptor Base Address Low - RW */
+ E1000_TDBAH = 0x03804, /* TX Descriptor Base Address High - RW */
+ E1000_TDLEN = 0x03808, /* TX Descriptor Length - RW */
+ E1000_TDH = 0x03810, /* TX Descriptor Head - RW */
+ E1000_TDT = 0x03818, /* TX Descriptor Tail - RW */
+ E1000_TIDV = 0x03820, /* TX Interrupt Delay Value - RW */
+ E1000_TXDCTL = 0x03828, /* TX Descriptor Control - RW */
+ E1000_TADV = 0x0382C, /* TX Interrupt Absolute Delay Val - RW */
+ E1000_TARC0 = 0x03840, /* TX Arbitration Count (0) */
+ E1000_TXDCTL1 = 0x03928, /* TX Descriptor Control (1) - RW */
+ E1000_TARC1 = 0x03940, /* TX Arbitration Count (1) */
+ E1000_CRCERRS = 0x04000, /* CRC Error Count - R/clr */
+ E1000_ALGNERRC = 0x04004, /* Alignment Error Count - R/clr */
+ E1000_SYMERRS = 0x04008, /* Symbol Error Count - R/clr */
+ E1000_RXERRC = 0x0400C, /* Receive Error Count - R/clr */
+ E1000_MPC = 0x04010, /* Missed Packet Count - R/clr */
+ E1000_SCC = 0x04014, /* Single Collision Count - R/clr */
+ E1000_ECOL = 0x04018, /* Excessive Collision Count - R/clr */
+ E1000_MCC = 0x0401C, /* Multiple Collision Count - R/clr */
+ E1000_LATECOL = 0x04020, /* Late Collision Count - R/clr */
+ E1000_COLC = 0x04028, /* Collision Count - R/clr */
+ E1000_DC = 0x04030, /* Defer Count - R/clr */
+ E1000_TNCRS = 0x04034, /* TX-No CRS - R/clr */
+ E1000_SEC = 0x04038, /* Sequence Error Count - R/clr */
+ E1000_CEXTERR = 0x0403C, /* Carrier Extension Error Count - R/clr */
+ E1000_RLEC = 0x04040, /* Receive Length Error Count - R/clr */
+ E1000_XONRXC = 0x04048, /* XON RX Count - R/clr */
+ E1000_XONTXC = 0x0404C, /* XON TX Count - R/clr */
+ E1000_XOFFRXC = 0x04050, /* XOFF RX Count - R/clr */
+ E1000_XOFFTXC = 0x04054, /* XOFF TX Count - R/clr */
+ E1000_FCRUC = 0x04058, /* Flow Control RX Unsupported Count- R/clr */
+ E1000_PRC64 = 0x0405C, /* Packets RX (64 bytes) - R/clr */
+ E1000_PRC127 = 0x04060, /* Packets RX (65-127 bytes) - R/clr */
+ E1000_PRC255 = 0x04064, /* Packets RX (128-255 bytes) - R/clr */
+ E1000_PRC511 = 0x04068, /* Packets RX (255-511 bytes) - R/clr */
+ E1000_PRC1023 = 0x0406C, /* Packets RX (512-1023 bytes) - R/clr */
+ E1000_PRC1522 = 0x04070, /* Packets RX (1024-1522 bytes) - R/clr */
+ E1000_GPRC = 0x04074, /* Good Packets RX Count - R/clr */
+ E1000_BPRC = 0x04078, /* Broadcast Packets RX Count - R/clr */
+ E1000_MPRC = 0x0407C, /* Multicast Packets RX Count - R/clr */
+ E1000_GPTC = 0x04080, /* Good Packets TX Count - R/clr */
+ E1000_GORCL = 0x04088, /* Good Octets RX Count Low - R/clr */
+ E1000_GORCH = 0x0408C, /* Good Octets RX Count High - R/clr */
+ E1000_GOTCL = 0x04090, /* Good Octets TX Count Low - R/clr */
+ E1000_GOTCH = 0x04094, /* Good Octets TX Count High - R/clr */
+ E1000_RNBC = 0x040A0, /* RX No Buffers Count - R/clr */
+ E1000_RUC = 0x040A4, /* RX Undersize Count - R/clr */
+ E1000_RFC = 0x040A8, /* RX Fragment Count - R/clr */
+ E1000_ROC = 0x040AC, /* RX Oversize Count - R/clr */
+ E1000_RJC = 0x040B0, /* RX Jabber Count - R/clr */
+ E1000_MGTPRC = 0x040B4, /* Management Packets RX Count - R/clr */
+ E1000_MGTPDC = 0x040B8, /* Management Packets Dropped Count - R/clr */
+ E1000_MGTPTC = 0x040BC, /* Management Packets TX Count - R/clr */
+ E1000_TORL = 0x040C0, /* Total Octets RX Low - R/clr */
+ E1000_TORH = 0x040C4, /* Total Octets RX High - R/clr */
+ E1000_TOTL = 0x040C8, /* Total Octets TX Low - R/clr */
+ E1000_TOTH = 0x040CC, /* Total Octets TX High - R/clr */
+ E1000_TPR = 0x040D0, /* Total Packets RX - R/clr */
+ E1000_TPT = 0x040D4, /* Total Packets TX - R/clr */
+ E1000_PTC64 = 0x040D8, /* Packets TX (64 bytes) - R/clr */
+ E1000_PTC127 = 0x040DC, /* Packets TX (65-127 bytes) - R/clr */
+ E1000_PTC255 = 0x040E0, /* Packets TX (128-255 bytes) - R/clr */
+ E1000_PTC511 = 0x040E4, /* Packets TX (256-511 bytes) - R/clr */
+ E1000_PTC1023 = 0x040E8, /* Packets TX (512-1023 bytes) - R/clr */
+ E1000_PTC1522 = 0x040EC, /* Packets TX (1024-1522 Bytes) - R/clr */
+ E1000_MPTC = 0x040F0, /* Multicast Packets TX Count - R/clr */
+ E1000_BPTC = 0x040F4, /* Broadcast Packets TX Count - R/clr */
+ E1000_TSCTC = 0x040F8, /* TCP Segmentation Context TX - R/clr */
+ E1000_TSCTFC = 0x040FC, /* TCP Segmentation Context TX Fail - R/clr */
+ E1000_IAC = 0x04100, /* Interrupt Assertion Count */
+ E1000_ICRXPTC = 0x04104, /* Irq Cause Rx Packet Timer Expire Count */
+ E1000_ICRXATC = 0x04108, /* Irq Cause Rx Abs Timer Expire Count */
+ E1000_ICTXPTC = 0x0410C, /* Irq Cause Tx Packet Timer Expire Count */
+ E1000_ICTXATC = 0x04110, /* Irq Cause Tx Abs Timer Expire Count */
+ E1000_ICTXQEC = 0x04118, /* Irq Cause Tx Queue Empty Count */
+ E1000_ICTXQMTC = 0x0411C, /* Irq Cause Tx Queue MinThreshold Count */
+ E1000_ICRXDMTC = 0x04120, /* Irq Cause Rx Desc MinThreshold Count */
+ E1000_ICRXOC = 0x04124, /* Irq Cause Receiver Overrun Count */
+ E1000_RXCSUM = 0x05000, /* RX Checksum Control - RW */
+ E1000_RFCTL = 0x05008, /* Receive Filter Control*/
+ E1000_MTA = 0x05200, /* Multicast Table Array - RW Array */
+ E1000_RA = 0x05400, /* Receive Address - RW Array */
+ E1000_VFTA = 0x05600, /* VLAN Filter Table Array - RW Array */
+ E1000_WUC = 0x05800, /* Wakeup Control - RW */
+ E1000_WUFC = 0x05808, /* Wakeup Filter Control - RW */
+ E1000_WUS = 0x05810, /* Wakeup Status - RO */
+ E1000_MANC = 0x05820, /* Management Control - RW */
+ E1000_FFLT = 0x05F00, /* Flexible Filter Length Table - RW Array */
+ E1000_HOST_IF = 0x08800, /* Host Interface */
+
+ E1000_KMRNCTRLSTA = 0x00034, /* MAC-PHY interface - RW */
+ E1000_MANC2H = 0x05860, /* Management Control To Host - RW */
+ E1000_SW_FW_SYNC = 0x05B5C, /* Software-Firmware Synchronization - RW */
+ E1000_GCR = 0x05B00, /* PCI-Ex Control */
+ E1000_FACTPS = 0x05B30, /* Function Active and Power State to MNG */
+ E1000_SWSM = 0x05B50, /* SW Semaphore */
+ E1000_FWSM = 0x05B54, /* FW Semaphore */
+ E1000_HICR = 0x08F00, /* Host Inteface Control */
+};
+
+/* RSS registers */
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */
+#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */
+#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */
+#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */
+#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */
+
+#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK 0x0078
+
+#define IGP01E1000_PSCR_AUTO_MDIX 0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */
+
+#define IGP01E1000_PSCFR_SMART_SPEED 0x0080
+
+#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */
+#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */
+#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */
+
+#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000
+
+#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002
+#define IGP01E1000_PSSR_MDIX 0x0008
+#define IGP01E1000_PSSR_SPEED_MASK 0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000
+
+#define IGP02E1000_PHY_CHANNEL_NUM 4
+#define IGP02E1000_PHY_AGC_A 0x11B1
+#define IGP02E1000_PHY_AGC_B 0x12B1
+#define IGP02E1000_PHY_AGC_C 0x14B1
+#define IGP02E1000_PHY_AGC_D 0x18B1
+
+#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK 0x7F
+#define IGP02E1000_AGC_RANGE 15
+
+/* manage.c */
+#define E1000_VFTA_ENTRY_SHIFT 5
+#define E1000_VFTA_ENTRY_MASK 0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F
+
+#define E1000_HICR_EN 0x01 /* Enable bit - RO */
+#define E1000_HICR_C 0x02 /* Driver sets this bit when done
+ * to put command in RAM */
+#define E1000_HICR_FW_RESET_ENABLE 0x40
+#define E1000_HICR_FW_RESET 0x80
+
+#define E1000_FWSM_MODE_MASK 0xE
+#define E1000_FWSM_MODE_SHIFT 1
+
+#define E1000_MNG_IAMT_MODE 0x3
+#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10
+#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2
+
+/* nvm.c */
+#define E1000_STM_OPCODE 0xDB00
+
+#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000
+#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16
+#define E1000_KMRNCTRLSTA_REN 0x00200000
+#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */
+#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
+#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */
+#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */
+
+/* IFE PHY Extended Status Control */
+#define IFE_PESC_POLARITY_REVERSED 0x0100
+
+/* IFE PHY Special Control */
+#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010
+#define IFE_PSC_FORCE_POLARITY 0x0020
+
+/* IFE PHY Special Control and LED Control */
+#define IFE_PSCL_PROBE_MODE 0x0020
+#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */
+
+/* IFE PHY MDIX Control */
+#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */
+#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
+
+#define E1000_CABLE_LENGTH_UNDEFINED 0xFF
+
+#define E1000_DEV_ID_82571EB_COPPER 0x105E
+#define E1000_DEV_ID_82571EB_FIBER 0x105F
+#define E1000_DEV_ID_82571EB_SERDES 0x1060
+#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
+#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP 0x10BC
+#define E1000_DEV_ID_82572EI_COPPER 0x107D
+#define E1000_DEV_ID_82572EI_FIBER 0x107E
+#define E1000_DEV_ID_82572EI_SERDES 0x107F
+#define E1000_DEV_ID_82572EI 0x10B9
+#define E1000_DEV_ID_82573E 0x108B
+#define E1000_DEV_ID_82573E_IAMT 0x108C
+#define E1000_DEV_ID_82573L 0x109A
+
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB
+
+#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A
+#define E1000_DEV_ID_ICH8_IGP_C 0x104B
+#define E1000_DEV_ID_ICH8_IFE 0x104C
+#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4
+#define E1000_DEV_ID_ICH8_IFE_G 0x10C5
+#define E1000_DEV_ID_ICH8_IGP_M 0x104D
+#define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD
+#define E1000_DEV_ID_ICH9_IGP_C 0x294C
+#define E1000_DEV_ID_ICH9_IFE 0x10C0
+#define E1000_DEV_ID_ICH9_IFE_GT 0x10C3
+#define E1000_DEV_ID_ICH9_IFE_G 0x10C2
+
+#define E1000_FUNC_1 1
+
+enum e1000_mac_type {
+ e1000_82571,
+ e1000_82572,
+ e1000_82573,
+ e1000_80003es2lan,
+ e1000_ich8lan,
+ e1000_ich9lan,
+};
+
+enum e1000_media_type {
+ e1000_media_type_unknown = 0,
+ e1000_media_type_copper = 1,
+ e1000_media_type_fiber = 2,
+ e1000_media_type_internal_serdes = 3,
+ e1000_num_media_types
+};
+
+enum e1000_nvm_type {
+ e1000_nvm_unknown = 0,
+ e1000_nvm_none,
+ e1000_nvm_eeprom_spi,
+ e1000_nvm_flash_hw,
+ e1000_nvm_flash_sw
+};
+
+enum e1000_nvm_override {
+ e1000_nvm_override_none = 0,
+ e1000_nvm_override_spi_small,
+ e1000_nvm_override_spi_large
+};
+
+enum e1000_phy_type {
+ e1000_phy_unknown = 0,
+ e1000_phy_none,
+ e1000_phy_m88,
+ e1000_phy_igp,
+ e1000_phy_igp_2,
+ e1000_phy_gg82563,
+ e1000_phy_igp_3,
+ e1000_phy_ife,
+};
+
+enum e1000_bus_width {
+ e1000_bus_width_unknown = 0,
+ e1000_bus_width_pcie_x1,
+ e1000_bus_width_pcie_x2,
+ e1000_bus_width_pcie_x4 = 4,
+ e1000_bus_width_32,
+ e1000_bus_width_64,
+ e1000_bus_width_reserved
+};
+
+enum e1000_1000t_rx_status {
+ e1000_1000t_rx_status_not_ok = 0,
+ e1000_1000t_rx_status_ok,
+ e1000_1000t_rx_status_undefined = 0xFF
+};
+
+enum e1000_rev_polarity{
+ e1000_rev_polarity_normal = 0,
+ e1000_rev_polarity_reversed,
+ e1000_rev_polarity_undefined = 0xFF
+};
+
+enum e1000_fc_mode {
+ e1000_fc_none = 0,
+ e1000_fc_rx_pause,
+ e1000_fc_tx_pause,
+ e1000_fc_full,
+ e1000_fc_default = 0xFF
+};
+
+enum e1000_ms_type {
+ e1000_ms_hw_default = 0,
+ e1000_ms_force_master,
+ e1000_ms_force_slave,
+ e1000_ms_auto
+};
+
+enum e1000_smart_speed {
+ e1000_smart_speed_default = 0,
+ e1000_smart_speed_on,
+ e1000_smart_speed_off
+};
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+ u64 buffer_addr; /* Address of the descriptor's data buffer */
+ u16 length; /* Length of data DMAed into data buffer */
+ u16 csum; /* Packet checksum */
+ u8 status; /* Descriptor status */
+ u8 errors; /* Descriptor Errors */
+ u16 special;
+};
+
+/* Receive Descriptor - Extended */
+union e1000_rx_desc_extended {
+ struct {
+ u64 buffer_addr;
+ u64 reserved;
+ } read;
+ struct {
+ struct {
+ u32 mrq; /* Multiple Rx Queues */
+ union {
+ u32 rss; /* RSS Hash */
+ struct {
+ u16 ip_id; /* IP id */
+ u16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ u32 status_error; /* ext status/error */
+ u16 length;
+ u16 vlan; /* VLAN tag */
+ } upper;
+ } wb; /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union e1000_rx_desc_packet_split {
+ struct {
+ /* one buffer for protocol header(s), three data buffers */
+ u64 buffer_addr[MAX_PS_BUFFERS];
+ } read;
+ struct {
+ struct {
+ u32 mrq; /* Multiple Rx Queues */
+ union {
+ u32 rss; /* RSS Hash */
+ struct {
+ u16 ip_id; /* IP id */
+ u16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ u32 status_error; /* ext status/error */
+ u16 length0; /* length of buffer 0 */
+ u16 vlan; /* VLAN tag */
+ } middle;
+ struct {
+ u16 header_status;
+ u16 length[3]; /* length of buffers 1-3 */
+ } upper;
+ u64 reserved;
+ } wb; /* writeback */
+};
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+ u64 buffer_addr; /* Address of the descriptor's data buffer */
+ union {
+ u32 data;
+ struct {
+ u16 length; /* Data buffer length */
+ u8 cso; /* Checksum offset */
+ u8 cmd; /* Descriptor control */
+ } flags;
+ } lower;
+ union {
+ u32 data;
+ struct {
+ u8 status; /* Descriptor status */
+ u8 css; /* Checksum start */
+ u16 special;
+ } fields;
+ } upper;
+};
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+ union {
+ u32 ip_config;
+ struct {
+ u8 ipcss; /* IP checksum start */
+ u8 ipcso; /* IP checksum offset */
+ u16 ipcse; /* IP checksum end */
+ } ip_fields;
+ } lower_setup;
+ union {
+ u32 tcp_config;
+ struct {
+ u8 tucss; /* TCP checksum start */
+ u8 tucso; /* TCP checksum offset */
+ u16 tucse; /* TCP checksum end */
+ } tcp_fields;
+ } upper_setup;
+ u32 cmd_and_length;
+ union {
+ u32 data;
+ struct {
+ u8 status; /* Descriptor status */
+ u8 hdr_len; /* Header length */
+ u16 mss; /* Maximum segment size */
+ } fields;
+ } tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+ u64 buffer_addr; /* Address of the descriptor's buffer address */
+ union {
+ u32 data;
+ struct {
+ u16 length; /* Data buffer length */
+ u8 typ_len_ext;
+ u8 cmd;
+ } flags;
+ } lower;
+ union {
+ u32 data;
+ struct {
+ u8 status; /* Descriptor status */
+ u8 popts; /* Packet Options */
+ u16 special; /* */
+ } fields;
+ } upper;
+};
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+ u64 crcerrs;
+ u64 algnerrc;
+ u64 symerrs;
+ u64 rxerrc;
+ u64 mpc;
+ u64 scc;
+ u64 ecol;
+ u64 mcc;
+ u64 latecol;
+ u64 colc;
+ u64 dc;
+ u64 tncrs;
+ u64 sec;
+ u64 cexterr;
+ u64 rlec;
+ u64 xonrxc;
+ u64 xontxc;
+ u64 xoffrxc;
+ u64 xofftxc;
+ u64 fcruc;
+ u64 prc64;
+ u64 prc127;
+ u64 prc255;
+ u64 prc511;
+ u64 prc1023;
+ u64 prc1522;
+ u64 gprc;
+ u64 bprc;
+ u64 mprc;
+ u64 gptc;
+ u64 gorcl;
+ u64 gorch;
+ u64 gotcl;
+ u64 gotch;
+ u64 rnbc;
+ u64 ruc;
+ u64 rfc;
+ u64 roc;
+ u64 rjc;
+ u64 mgprc;
+ u64 mgpdc;
+ u64 mgptc;
+ u64 torl;
+ u64 torh;
+ u64 totl;
+ u64 toth;
+ u64 tpr;
+ u64 tpt;
+ u64 ptc64;
+ u64 ptc127;
+ u64 ptc255;
+ u64 ptc511;
+ u64 ptc1023;
+ u64 ptc1522;
+ u64 mptc;
+ u64 bptc;
+ u64 tsctc;
+ u64 tsctfc;
+ u64 iac;
+ u64 icrxptc;
+ u64 icrxatc;
+ u64 ictxptc;
+ u64 ictxatc;
+ u64 ictxqec;
+ u64 ictxqmtc;
+ u64 icrxdmtc;
+ u64 icrxoc;
+};
+
+struct e1000_phy_stats {
+ u32 idle_errors;
+ u32 receive_errors;
+};
+
+struct e1000_host_mng_dhcp_cookie {
+ u32 signature;
+ u8 status;
+ u8 reserved0;
+ u16 vlan_id;
+ u32 reserved1;
+ u16 reserved2;
+ u8 reserved3;
+ u8 checksum;
+};
+
+/* Host Interface "Rev 1" */
+struct e1000_host_command_header {
+ u8 command_id;
+ u8 command_length;
+ u8 command_options;
+ u8 checksum;
+};
+
+#define E1000_HI_MAX_DATA_LENGTH 252
+struct e1000_host_command_info {
+ struct e1000_host_command_header command_header;
+ u8 command_data[E1000_HI_MAX_DATA_LENGTH];
+};
+
+/* Host Interface "Rev 2" */
+struct e1000_host_mng_command_header {
+ u8 command_id;
+ u8 checksum;
+ u16 reserved1;
+ u16 reserved2;
+ u16 command_length;
+};
+
+#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+struct e1000_host_mng_command_info {
+ struct e1000_host_mng_command_header command_header;
+ u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
+};
+
+/* Function pointers and static data for the MAC. */
+struct e1000_mac_operations {
+ u32 mng_mode_enab;
+
+ s32 (*check_for_link)(struct e1000_hw *);
+ s32 (*cleanup_led)(struct e1000_hw *);
+ void (*clear_hw_cntrs)(struct e1000_hw *);
+ s32 (*get_bus_info)(struct e1000_hw *);
+ s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
+ s32 (*led_on)(struct e1000_hw *);
+ s32 (*led_off)(struct e1000_hw *);
+ void (*mc_addr_list_update)(struct e1000_hw *, u8 *, u32, u32,
+ u32);
+ s32 (*reset_hw)(struct e1000_hw *);
+ s32 (*init_hw)(struct e1000_hw *);
+ s32 (*setup_link)(struct e1000_hw *);
+ s32 (*setup_physical_interface)(struct e1000_hw *);
+};
+
+/* Function pointers for the PHY. */
+struct e1000_phy_operations {
+ s32 (*acquire_phy)(struct e1000_hw *);
+ s32 (*check_reset_block)(struct e1000_hw *);
+ s32 (*commit_phy)(struct e1000_hw *);
+ s32 (*force_speed_duplex)(struct e1000_hw *);
+ s32 (*get_cfg_done)(struct e1000_hw *hw);
+ s32 (*get_cable_length)(struct e1000_hw *);
+ s32 (*get_phy_info)(struct e1000_hw *);
+ s32 (*read_phy_reg)(struct e1000_hw *, u32, u16 *);
+ void (*release_phy)(struct e1000_hw *);
+ s32 (*reset_phy)(struct e1000_hw *);
+ s32 (*set_d0_lplu_state)(struct e1000_hw *, bool);
+ s32 (*set_d3_lplu_state)(struct e1000_hw *, bool);
+ s32 (*write_phy_reg)(struct e1000_hw *, u32, u16);
+};
+
+/* Function pointers for the NVM. */
+struct e1000_nvm_operations {
+ s32 (*acquire_nvm)(struct e1000_hw *);
+ s32 (*read_nvm)(struct e1000_hw *, u16, u16, u16 *);
+ void (*release_nvm)(struct e1000_hw *);
+ s32 (*update_nvm)(struct e1000_hw *);
+ s32 (*valid_led_default)(struct e1000_hw *, u16 *);
+ s32 (*validate_nvm)(struct e1000_hw *);
+ s32 (*write_nvm)(struct e1000_hw *, u16, u16, u16 *);
+};
+
+struct e1000_mac_info {
+ struct e1000_mac_operations ops;
+
+ u8 addr[6];
+ u8 perm_addr[6];
+
+ enum e1000_mac_type type;
+ enum e1000_fc_mode fc;
+ enum e1000_fc_mode original_fc;
+
+ u32 collision_delta;
+ u32 ledctl_default;
+ u32 ledctl_mode1;
+ u32 ledctl_mode2;
+ u32 max_frame_size;
+ u32 mc_filter_type;
+ u32 min_frame_size;
+ u32 tx_packet_delta;
+ u32 txcw;
+
+ u16 current_ifs_val;
+ u16 ifs_max_val;
+ u16 ifs_min_val;
+ u16 ifs_ratio;
+ u16 ifs_step_size;
+ u16 mta_reg_count;
+ u16 rar_entry_count;
+ u16 fc_high_water;
+ u16 fc_low_water;
+ u16 fc_pause_time;
+
+ u8 forced_speed_duplex;
+
+ bool arc_subsystem_valid;
+ bool autoneg;
+ bool autoneg_failed;
+ bool get_link_status;
+ bool in_ifs_mode;
+ bool serdes_has_link;
+ bool tx_pkt_filtering;
+};
+
+struct e1000_phy_info {
+ struct e1000_phy_operations ops;
+
+ enum e1000_phy_type type;
+
+ enum e1000_1000t_rx_status local_rx;
+ enum e1000_1000t_rx_status remote_rx;
+ enum e1000_ms_type ms_type;
+ enum e1000_ms_type original_ms_type;
+ enum e1000_rev_polarity cable_polarity;
+ enum e1000_smart_speed smart_speed;
+
+ u32 addr;
+ u32 id;
+ u32 reset_delay_us; /* in usec */
+ u32 revision;
+
+ u16 autoneg_advertised;
+ u16 autoneg_mask;
+ u16 cable_length;
+ u16 max_cable_length;
+ u16 min_cable_length;
+
+ u8 mdix;
+
+ bool disable_polarity_correction;
+ bool is_mdix;
+ bool polarity_correction;
+ bool speed_downgraded;
+ bool wait_for_link;
+};
+
+struct e1000_nvm_info {
+ struct e1000_nvm_operations ops;
+
+ enum e1000_nvm_type type;
+ enum e1000_nvm_override override;
+
+ u32 flash_bank_size;
+ u32 flash_base_addr;
+
+ u16 word_size;
+ u16 delay_usec;
+ u16 address_bits;
+ u16 opcode_bits;
+ u16 page_size;
+};
+
+struct e1000_bus_info {
+ enum e1000_bus_width width;
+
+ u16 func;
+};
+
+struct e1000_dev_spec_82571 {
+ bool laa_is_present;
+};
+
+struct e1000_shadow_ram {
+ u16 value;
+ bool modified;
+};
+
+#define E1000_ICH8_SHADOW_RAM_WORDS 2048
+
+struct e1000_dev_spec_ich8lan {
+ bool kmrn_lock_loss_workaround_enabled;
+ struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
+};
+
+struct e1000_hw {
+ struct e1000_adapter *adapter;
+
+ u8 __iomem *hw_addr;
+ u8 __iomem *flash_address;
+
+ struct e1000_mac_info mac;
+ struct e1000_phy_info phy;
+ struct e1000_nvm_info nvm;
+ struct e1000_bus_info bus;
+ struct e1000_host_mng_dhcp_cookie mng_cookie;
+
+ union {
+ struct e1000_dev_spec_82571 e82571;
+ struct e1000_dev_spec_ich8lan ich8lan;
+ } dev_spec;
+
+ enum e1000_media_type media_type;
+};
+
+#ifdef DEBUG
+#define hw_dbg(hw, format, arg...) \
+ printk(KERN_DEBUG "%s: " format, e1000e_get_hw_dev_name(hw), ##arg)
+#else
+static inline int __attribute__ ((format (printf, 2, 3)))
+hw_dbg(struct e1000_hw *hw, const char *format, ...)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
new file mode 100644
index 00000000000..8f8139de1f4
--- /dev/null
+++ b/drivers/net/e1000e/ich8lan.c
@@ -0,0 +1,2225 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/*
+ * 82562G-2 10/100 Network Connection
+ * 82562GT 10/100 Network Connection
+ * 82562GT-2 10/100 Network Connection
+ * 82562V 10/100 Network Connection
+ * 82562V-2 10/100 Network Connection
+ * 82566DC-2 Gigabit Network Connection
+ * 82566DC Gigabit Network Connection
+ * 82566DM-2 Gigabit Network Connection
+ * 82566DM Gigabit Network Connection
+ * 82566MC Gigabit Network Connection
+ * 82566MM Gigabit Network Connection
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "e1000.h"
+
+#define ICH_FLASH_GFPREG 0x0000
+#define ICH_FLASH_HSFSTS 0x0004
+#define ICH_FLASH_HSFCTL 0x0006
+#define ICH_FLASH_FADDR 0x0008
+#define ICH_FLASH_FDATA0 0x0010
+
+#define ICH_FLASH_READ_COMMAND_TIMEOUT 500
+#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500
+#define ICH_FLASH_ERASE_COMMAND_TIMEOUT 3000000
+#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
+#define ICH_FLASH_CYCLE_REPEAT_COUNT 10
+
+#define ICH_CYCLE_READ 0
+#define ICH_CYCLE_WRITE 2
+#define ICH_CYCLE_ERASE 3
+
+#define FLASH_GFPREG_BASE_MASK 0x1FFF
+#define FLASH_SECTOR_ADDR_SHIFT 12
+
+#define ICH_FLASH_SEG_SIZE_256 256
+#define ICH_FLASH_SEG_SIZE_4K 4096
+#define ICH_FLASH_SEG_SIZE_8K 8192
+#define ICH_FLASH_SEG_SIZE_64K 65536
+
+
+#define E1000_ICH_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI Reset */
+
+#define E1000_ICH_MNG_IAMT_MODE 0x2
+
+#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_DEF1_OFF2 << 8) | \
+ (ID_LED_DEF1_ON2 << 4) | \
+ (ID_LED_DEF1_DEF2))
+
+#define E1000_ICH_NVM_SIG_WORD 0x13
+#define E1000_ICH_NVM_SIG_MASK 0xC000
+
+#define E1000_ICH8_LAN_INIT_TIMEOUT 1500
+
+#define E1000_FEXTNVM_SW_CONFIG 1
+#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M :/ */
+
+#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL
+
+#define E1000_ICH_RAR_ENTRIES 7
+
+#define PHY_PAGE_SHIFT 5
+#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
+ ((reg) & MAX_PHY_REG_ADDRESS))
+#define IGP3_KMRN_DIAG PHY_REG(770, 19) /* KMRN Diagnostic */
+#define IGP3_VR_CTRL PHY_REG(776, 18) /* Voltage Regulator Control */
+
+#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002
+#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
+#define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200
+
+/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
+/* Offset 04h HSFSTS */
+union ich8_hws_flash_status {
+ struct ich8_hsfsts {
+ u16 flcdone :1; /* bit 0 Flash Cycle Done */
+ u16 flcerr :1; /* bit 1 Flash Cycle Error */
+ u16 dael :1; /* bit 2 Direct Access error Log */
+ u16 berasesz :2; /* bit 4:3 Sector Erase Size */
+ u16 flcinprog :1; /* bit 5 flash cycle in Progress */
+ u16 reserved1 :2; /* bit 13:6 Reserved */
+ u16 reserved2 :6; /* bit 13:6 Reserved */
+ u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */
+ u16 flockdn :1; /* bit 15 Flash Config Lock-Down */
+ } hsf_status;
+ u16 regval;
+};
+
+/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
+/* Offset 06h FLCTL */
+union ich8_hws_flash_ctrl {
+ struct ich8_hsflctl {
+ u16 flcgo :1; /* 0 Flash Cycle Go */
+ u16 flcycle :2; /* 2:1 Flash Cycle */
+ u16 reserved :5; /* 7:3 Reserved */
+ u16 fldbcount :2; /* 9:8 Flash Data Byte Count */
+ u16 flockdn :6; /* 15:10 Reserved */
+ } hsf_ctrl;
+ u16 regval;
+};
+
+/* ICH Flash Region Access Permissions */
+union ich8_hws_flash_regacc {
+ struct ich8_flracc {
+ u32 grra :8; /* 0:7 GbE region Read Access */
+ u32 grwa :8; /* 8:15 GbE region Write Access */
+ u32 gmrag :8; /* 23:16 GbE Master Read Access Grant */
+ u32 gmwag :8; /* 31:24 GbE Master Write Access Grant */
+ } hsf_flregacc;
+ u16 regval;
+};
+
+static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
+static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
+static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
+static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw);
+static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
+static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+ u32 offset, u8 byte);
+static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
+ u16 *data);
+static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+ u8 size, u16 *data);
+static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
+static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
+
+static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
+{
+ return readw(hw->flash_address + reg);
+}
+
+static inline u32 __er32flash(struct e1000_hw *hw, unsigned long reg)
+{
+ return readl(hw->flash_address + reg);
+}
+
+static inline void __ew16flash(struct e1000_hw *hw, unsigned long reg, u16 val)
+{
+ writew(val, hw->flash_address + reg);
+}
+
+static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val)
+{
+ writel(val, hw->flash_address + reg);
+}
+
+#define er16flash(reg) __er16flash(hw, (reg))
+#define er32flash(reg) __er32flash(hw, (reg))
+#define ew16flash(reg,val) __ew16flash(hw, (reg), (val))
+#define ew32flash(reg,val) __ew32flash(hw, (reg), (val))
+
+/**
+ * e1000_init_phy_params_ich8lan - Initialize PHY function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific PHY parameters and function pointers.
+ **/
+static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 i = 0;
+
+ phy->addr = 1;
+ phy->reset_delay_us = 100;
+
+ phy->id = 0;
+ while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) &&
+ (i++ < 100)) {
+ msleep(1);
+ ret_val = e1000e_get_phy_id(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Verify phy id */
+ switch (phy->id) {
+ case IGP03E1000_E_PHY_ID:
+ phy->type = e1000_phy_igp_3;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ break;
+ case IFE_E_PHY_ID:
+ case IFE_PLUS_E_PHY_ID:
+ case IFE_C_E_PHY_ID:
+ phy->type = e1000_phy_ife;
+ phy->autoneg_mask = E1000_ALL_NOT_GIG;
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific NVM parameters and function
+ * pointers.
+ **/
+static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ u32 gfpreg;
+ u32 sector_base_addr;
+ u32 sector_end_addr;
+ u16 i;
+
+ /* Can't read flash registers if the register set isn't mapped.
+ */
+ if (!hw->flash_address) {
+ hw_dbg(hw, "ERROR: Flash registers not mapped\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ nvm->type = e1000_nvm_flash_sw;
+
+ gfpreg = er32flash(ICH_FLASH_GFPREG);
+
+ /* sector_X_addr is a "sector"-aligned address (4096 bytes)
+ * Add 1 to sector_end_addr since this sector is included in
+ * the overall size. */
+ sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
+ sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
+
+ /* flash_base_addr is byte-aligned */
+ nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
+
+ /* find total size of the NVM, then cut in half since the total
+ * size represents two separate NVM banks. */
+ nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
+ << FLASH_SECTOR_ADDR_SHIFT;
+ nvm->flash_bank_size /= 2;
+ /* Adjust to word count */
+ nvm->flash_bank_size /= sizeof(u16);
+
+ nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS;
+
+ /* Clear shadow ram */
+ for (i = 0; i < nvm->word_size; i++) {
+ dev_spec->shadow_ram[i].modified = 0;
+ dev_spec->shadow_ram[i].value = 0xFFFF;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_init_mac_params_ich8lan - Initialize MAC function pointers
+ * @hw: pointer to the HW structure
+ *
+ * Initialize family-specific MAC parameters and function
+ * pointers.
+ **/
+static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_mac_info *mac = &hw->mac;
+
+ /* Set media type function pointer */
+ hw->media_type = e1000_media_type_copper;
+
+ /* Set mta register count */
+ mac->mta_reg_count = 32;
+ /* Set rar entry count */
+ mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
+ if (mac->type == e1000_ich8lan)
+ mac->rar_entry_count--;
+ /* Set if manageability features are enabled. */
+ mac->arc_subsystem_valid = 1;
+
+ /* Enable PCS Lock-loss workaround for ICH8 */
+ if (mac->type == e1000_ich8lan)
+ e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, 1);
+
+ return 0;
+}
+
+static s32 e1000_get_invariants_ich8lan(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ s32 rc;
+
+ rc = e1000_init_mac_params_ich8lan(adapter);
+ if (rc)
+ return rc;
+
+ rc = e1000_init_nvm_params_ich8lan(hw);
+ if (rc)
+ return rc;
+
+ rc = e1000_init_phy_params_ich8lan(hw);
+ if (rc)
+ return rc;
+
+ if ((adapter->hw.mac.type == e1000_ich8lan) &&
+ (adapter->hw.phy.type == e1000_phy_igp_3))
+ adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
+
+ return 0;
+}
+
+/**
+ * e1000_acquire_swflag_ich8lan - Acquire software control flag
+ * @hw: pointer to the HW structure
+ *
+ * Acquires the software control flag for performing NVM and PHY
+ * operations. This is a function pointer entry point only called by
+ * read/write routines for the PHY and NVM parts.
+ **/
+static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
+{
+ u32 extcnf_ctrl;
+ u32 timeout = PHY_CFG_TIMEOUT;
+
+ while (timeout) {
+ extcnf_ctrl = er32(EXTCNF_CTRL);
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+ ew32(EXTCNF_CTRL, extcnf_ctrl);
+
+ extcnf_ctrl = er32(EXTCNF_CTRL);
+ if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+ break;
+ mdelay(1);
+ timeout--;
+ }
+
+ if (!timeout) {
+ hw_dbg(hw, "FW or HW has locked the resource for too long.\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_release_swflag_ich8lan - Release software control flag
+ * @hw: pointer to the HW structure
+ *
+ * Releases the software control flag for performing NVM and PHY operations.
+ * This is a function pointer entry point only called by read/write
+ * routines for the PHY and NVM parts.
+ **/
+static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
+{
+ u32 extcnf_ctrl;
+
+ extcnf_ctrl = er32(EXTCNF_CTRL);
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+ ew32(EXTCNF_CTRL, extcnf_ctrl);
+}
+
+/**
+ * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
+ * @hw: pointer to the HW structure
+ *
+ * Checks if firmware is blocking the reset of the PHY.
+ * This is a function pointer entry point only called by
+ * reset routines.
+ **/
+static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
+{
+ u32 fwsm;
+
+ fwsm = er32(FWSM);
+
+ return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? 0 : E1000_BLK_PHY_RESET;
+}
+
+/**
+ * e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex
+ * @hw: pointer to the HW structure
+ *
+ * Forces the speed and duplex settings of the PHY.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+ bool link;
+
+ if (phy->type != e1000_phy_ife) {
+ ret_val = e1000e_phy_force_speed_duplex_igp(hw);
+ return ret_val;
+ }
+
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &data);
+ if (ret_val)
+ return ret_val;
+
+ e1000e_phy_force_speed_duplex_setup(hw, &data);
+
+ ret_val = e1e_wphy(hw, PHY_CONTROL, data);
+ if (ret_val)
+ return ret_val;
+
+ /* Disable MDI-X support for 10/100 */
+ ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IFE_PMC_AUTO_MDIX;
+ data &= ~IFE_PMC_FORCE_MDIX;
+
+ ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data);
+ if (ret_val)
+ return ret_val;
+
+ hw_dbg(hw, "IFE PMC: %X\n", data);
+
+ udelay(1);
+
+ if (phy->wait_for_link) {
+ hw_dbg(hw, "Waiting for forced speed/duplex link on IFE phy.\n");
+
+ ret_val = e1000e_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link)
+ hw_dbg(hw, "Link taking longer than expected.\n");
+
+ /* Try once more */
+ ret_val = e1000e_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ return ret_val;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_phy_hw_reset_ich8lan - Performs a PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Resets the PHY
+ * This is a function pointer entry point called by drivers
+ * or other shared routines.
+ **/
+static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ u32 i;
+ u32 data, cnf_size, cnf_base_addr, sw_cfg_mask;
+ s32 ret_val;
+ u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT;
+ u16 word_addr, reg_data, reg_addr, phy_page = 0;
+
+ ret_val = e1000e_phy_hw_reset_generic(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Initialize the PHY from the NVM on ICH platforms. This
+ * is needed due to an issue where the NVM configuration is
+ * not properly autoloaded after power transitions.
+ * Therefore, after each PHY reset, we will load the
+ * configuration data out of the NVM manually.
+ */
+ if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) {
+ struct e1000_adapter *adapter = hw->adapter;
+
+ /* Check if SW needs configure the PHY */
+ if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
+ (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M))
+ sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
+ else
+ sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+
+ data = er32(FEXTNVM);
+ if (!(data & sw_cfg_mask))
+ return 0;
+
+ /* Wait for basic configuration completes before proceeding*/
+ do {
+ data = er32(STATUS);
+ data &= E1000_STATUS_LAN_INIT_DONE;
+ udelay(100);
+ } while ((!data) && --loop);
+
+ /* If basic configuration is incomplete before the above loop
+ * count reaches 0, loading the configuration from NVM will
+ * leave the PHY in a bad state possibly resulting in no link.
+ */
+ if (loop == 0) {
+ hw_dbg(hw, "LAN_INIT_DONE not set, increase timeout\n");
+ }
+
+ /* Clear the Init Done bit for the next init event */
+ data = er32(STATUS);
+ data &= ~E1000_STATUS_LAN_INIT_DONE;
+ ew32(STATUS, data);
+
+ /* Make sure HW does not configure LCD from PHY
+ * extended configuration before SW configuration */
+ data = er32(EXTCNF_CTRL);
+ if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+ return 0;
+
+ cnf_size = er32(EXTCNF_SIZE);
+ cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
+ cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
+ if (!cnf_size)
+ return 0;
+
+ cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
+ cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
+
+ /* Configure LCD from extended configuration
+ * region. */
+
+ /* cnf_base_addr is in DWORD */
+ word_addr = (u16)(cnf_base_addr << 1);
+
+ for (i = 0; i < cnf_size; i++) {
+ ret_val = e1000_read_nvm(hw,
+ (word_addr + i * 2),
+ 1,
+ &reg_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_nvm(hw,
+ (word_addr + i * 2 + 1),
+ 1,
+ &reg_addr);
+ if (ret_val)
+ return ret_val;
+
+ /* Save off the PHY page for future writes. */
+ if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
+ phy_page = reg_data;
+ continue;
+ }
+
+ reg_addr |= phy_page;
+
+ ret_val = e1e_wphy(hw, (u32)reg_addr, reg_data);
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states
+ * @hw: pointer to the HW structure
+ *
+ * Populates "phy" structure with various feature states.
+ * This function is only called by other family-specific
+ * routines.
+ **/
+static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+ bool link;
+
+ ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link) {
+ hw_dbg(hw, "Phy info is only valid if link is up\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data);
+ if (ret_val)
+ return ret_val;
+ phy->polarity_correction = (!(data & IFE_PSC_AUTO_POLARITY_DISABLE));
+
+ if (phy->polarity_correction) {
+ ret_val = e1000_check_polarity_ife_ich8lan(hw);
+ if (ret_val)
+ return ret_val;
+ } else {
+ /* Polarity is forced */
+ phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+ }
+
+ ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
+ if (ret_val)
+ return ret_val;
+
+ phy->is_mdix = (data & IFE_PMC_MDIX_STATUS);
+
+ /* The following parameters are undefined for 10/100 operation. */
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+
+ return 0;
+}
+
+/**
+ * e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info
+ * @hw: pointer to the HW structure
+ *
+ * Wrapper for calling the get_phy_info routines for the appropriate phy type.
+ * This is a function pointer entry point called by drivers
+ * or other shared routines.
+ **/
+static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
+{
+ switch (hw->phy.type) {
+ case e1000_phy_ife:
+ return e1000_get_phy_info_ife_ich8lan(hw);
+ break;
+ case e1000_phy_igp_3:
+ return e1000e_get_phy_info_igp(hw);
+ break;
+ default:
+ break;
+ }
+
+ return -E1000_ERR_PHY_TYPE;
+}
+
+/**
+ * e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY
+ * @hw: pointer to the HW structure
+ *
+ * Polarity is determined on the polarity reveral feature being enabled.
+ * This function is only called by other family-specific
+ * routines.
+ **/
+static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data, offset, mask;
+
+ /* Polarity is determined based on the reversal feature
+ * being enabled.
+ */
+ if (phy->polarity_correction) {
+ offset = IFE_PHY_EXTENDED_STATUS_CONTROL;
+ mask = IFE_PESC_POLARITY_REVERSED;
+ } else {
+ offset = IFE_PHY_SPECIAL_CONTROL;
+ mask = IFE_PSC_FORCE_POLARITY;
+ }
+
+ ret_val = e1e_rphy(hw, offset, &phy_data);
+
+ if (!ret_val)
+ phy->cable_polarity = (phy_data & mask)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+ return ret_val;
+}
+
+/**
+ * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D0 state according to the active flag. When
+ * activating LPLU this function also disables smart speed
+ * and vice versa. LPLU will not be activated unless the
+ * device autonegotiation advertisement meets standards of
+ * either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ u32 phy_ctrl;
+ s32 ret_val = 0;
+ u16 data;
+
+ if (phy->type != e1000_phy_igp_3)
+ return ret_val;
+
+ phy_ctrl = er32(PHY_CTRL);
+
+ if (active) {
+ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
+ ew32(PHY_CTRL, phy_ctrl);
+
+ /* Call gig speed drop workaround on LPLU before accessing
+ * any PHY registers */
+ if ((hw->mac.type == e1000_ich8lan) &&
+ (hw->phy.type == e1000_phy_igp_3))
+ e1000e_gig_downshift_workaround_ich8lan(hw);
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
+ if (ret_val)
+ return ret_val;
+ } else {
+ phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
+ ew32(PHY_CTRL, phy_ctrl);
+
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained. */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
+ * @hw: pointer to the HW structure
+ * @active: TRUE to enable LPLU, FALSE to disable
+ *
+ * Sets the LPLU D3 state according to the active flag. When
+ * activating LPLU this function also disables smart speed
+ * and vice versa. LPLU will not be activated unless the
+ * device autonegotiation advertisement meets standards of
+ * either 10 or 10/100 or 10/100/1000 at all duplexes.
+ * This is a function pointer entry point only called by
+ * PHY setup routines.
+ **/
+static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ u32 phy_ctrl;
+ s32 ret_val;
+ u16 data;
+
+ phy_ctrl = er32(PHY_CTRL);
+
+ if (!active) {
+ phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+ ew32(PHY_CTRL, phy_ctrl);
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained. */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1e_rphy(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1e_rphy(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ }
+ } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+ (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+ (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+ phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
+ ew32(PHY_CTRL, phy_ctrl);
+
+ /* Call gig speed drop workaround on LPLU before accessing
+ * any PHY registers */
+ if ((hw->mac.type == e1000_ich8lan) &&
+ (hw->phy.type == e1000_phy_igp_3))
+ e1000e_gig_downshift_workaround_ich8lan(hw);
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = e1e_rphy(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw,
+ IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_read_nvm_ich8lan - Read word(s) from the NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the word(s) to read.
+ * @words: Size of data to read in words
+ * @data: Pointer to the word(s) to read at offset.
+ *
+ * Reads a word(s) from the NVM using the flash access registers.
+ **/
+static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ u32 act_offset;
+ s32 ret_val;
+ u16 i, word;
+
+ if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+ (words == 0)) {
+ hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+ return -E1000_ERR_NVM;
+ }
+
+ ret_val = e1000_acquire_swflag_ich8lan(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Start with the bank offset, then add the relative offset. */
+ act_offset = (er32(EECD) & E1000_EECD_SEC1VAL)
+ ? nvm->flash_bank_size
+ : 0;
+ act_offset += offset;
+
+ for (i = 0; i < words; i++) {
+ if ((dev_spec->shadow_ram) &&
+ (dev_spec->shadow_ram[offset+i].modified)) {
+ data[i] = dev_spec->shadow_ram[offset+i].value;
+ } else {
+ ret_val = e1000_read_flash_word_ich8lan(hw,
+ act_offset + i,
+ &word);
+ if (ret_val)
+ break;
+ data[i] = word;
+ }
+ }
+
+ e1000_release_swflag_ich8lan(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000_flash_cycle_init_ich8lan - Initialize flash
+ * @hw: pointer to the HW structure
+ *
+ * This function does initial flash setup so that a new read/write/erase cycle
+ * can be started.
+ **/
+static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
+{
+ union ich8_hws_flash_status hsfsts;
+ s32 ret_val = -E1000_ERR_NVM;
+ s32 i = 0;
+
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+
+ /* Check if the flash descriptor is valid */
+ if (hsfsts.hsf_status.fldesvalid == 0) {
+ hw_dbg(hw, "Flash descriptor invalid. "
+ "SW Sequencing must be used.");
+ return -E1000_ERR_NVM;
+ }
+
+ /* Clear FCERR and DAEL in hw status by writing 1 */
+ hsfsts.hsf_status.flcerr = 1;
+ hsfsts.hsf_status.dael = 1;
+
+ ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+
+ /* Either we should have a hardware SPI cycle in progress
+ * bit to check against, in order to start a new cycle or
+ * FDONE bit should be changed in the hardware so that it
+ * is 1 after harware reset, which can then be used as an
+ * indication whether a cycle is in progress or has been
+ * completed.
+ */
+
+ if (hsfsts.hsf_status.flcinprog == 0) {
+ /* There is no cycle running at present,
+ * so we can start a cycle */
+ /* Begin by setting Flash Cycle Done. */
+ hsfsts.hsf_status.flcdone = 1;
+ ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+ ret_val = 0;
+ } else {
+ /* otherwise poll for sometime so the current
+ * cycle has a chance to end before giving up. */
+ for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
+ hsfsts.regval = __er16flash(hw, ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcinprog == 0) {
+ ret_val = 0;
+ break;
+ }
+ udelay(1);
+ }
+ if (ret_val == 0) {
+ /* Successful in waiting for previous cycle to timeout,
+ * now set the Flash Cycle Done. */
+ hsfsts.hsf_status.flcdone = 1;
+ ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+ } else {
+ hw_dbg(hw, "Flash controller busy, cannot get access");
+ }
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
+ * @hw: pointer to the HW structure
+ * @timeout: maximum time to wait for completion
+ *
+ * This function starts a flash cycle and waits for its completion.
+ **/
+static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
+{
+ union ich8_hws_flash_ctrl hsflctl;
+ union ich8_hws_flash_status hsfsts;
+ s32 ret_val = -E1000_ERR_NVM;
+ u32 i = 0;
+
+ /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
+ hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+ hsflctl.hsf_ctrl.flcgo = 1;
+ ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ /* wait till FDONE bit is set to 1 */
+ do {
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcdone == 1)
+ break;
+ udelay(1);
+ } while (i++ < timeout);
+
+ if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
+ return 0;
+
+ return ret_val;
+}
+
+/**
+ * e1000_read_flash_word_ich8lan - Read word from flash
+ * @hw: pointer to the HW structure
+ * @offset: offset to data location
+ * @data: pointer to the location for storing the data
+ *
+ * Reads the flash word at offset into data. Offset is converted
+ * to bytes before read.
+ **/
+static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
+ u16 *data)
+{
+ /* Must convert offset into bytes. */
+ offset <<= 1;
+
+ return e1000_read_flash_data_ich8lan(hw, offset, 2, data);
+}
+
+/**
+ * e1000_read_flash_data_ich8lan - Read byte or word from NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the byte or word to read.
+ * @size: Size of data to read, 1=byte 2=word
+ * @data: Pointer to the word to store the value read.
+ *
+ * Reads a byte or word from the NVM using the flash access registers.
+ **/
+static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+ u8 size, u16 *data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ u32 flash_linear_addr;
+ u32 flash_data = 0;
+ s32 ret_val = -E1000_ERR_NVM;
+ u8 count = 0;
+
+ if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
+ return -E1000_ERR_NVM;
+
+ flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr;
+
+ do {
+ udelay(1);
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val != 0)
+ break;
+
+ hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+ hsflctl.hsf_ctrl.fldbcount = size - 1;
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
+ ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
+
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_READ_COMMAND_TIMEOUT);
+
+ /* Check if FCERR is set to 1, if set to 1, clear it
+ * and try the whole sequence a few more times, else
+ * read in (shift in) the Flash Data0, the order is
+ * least significant byte first msb to lsb */
+ if (ret_val == 0) {
+ flash_data = er32flash(ICH_FLASH_FDATA0);
+ if (size == 1) {
+ *data = (u8)(flash_data & 0x000000FF);
+ } else if (size == 2) {
+ *data = (u16)(flash_data & 0x0000FFFF);
+ }
+ break;
+ } else {
+ /* If we've gotten here, then things are probably
+ * completely hosed, but if the error condition is
+ * detected, it won't hurt to give it another try...
+ * ICH_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1) {
+ /* Repeat for some time before giving up. */
+ continue;
+ } else if (hsfsts.hsf_status.flcdone == 0) {
+ hw_dbg(hw, "Timeout error - flash cycle "
+ "did not complete.");
+ break;
+ }
+ }
+ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+ return ret_val;
+}
+
+/**
+ * e1000_write_nvm_ich8lan - Write word(s) to the NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the word(s) to write.
+ * @words: Size of data to write in words
+ * @data: Pointer to the word(s) to write at offset.
+ *
+ * Writes a byte or word to the NVM using the flash access registers.
+ **/
+static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
+ u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ s32 ret_val;
+ u16 i;
+
+ if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+ (words == 0)) {
+ hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+ return -E1000_ERR_NVM;
+ }
+
+ ret_val = e1000_acquire_swflag_ich8lan(hw);
+ if (ret_val)
+ return ret_val;
+
+ for (i = 0; i < words; i++) {
+ dev_spec->shadow_ram[offset+i].modified = 1;
+ dev_spec->shadow_ram[offset+i].value = data[i];
+ }
+
+ e1000_release_swflag_ich8lan(hw);
+
+ return 0;
+}
+
+/**
+ * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
+ * @hw: pointer to the HW structure
+ *
+ * The NVM checksum is updated by calling the generic update_nvm_checksum,
+ * which writes the checksum to the shadow ram. The changes in the shadow
+ * ram are then committed to the EEPROM by processing each bank at a time
+ * checking for the modified bit and writing only the pending changes.
+ * After a succesful commit, the shadow ram is cleared and is ready for
+ * future writes.
+ **/
+static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ u32 i, act_offset, new_bank_offset, old_bank_offset;
+ s32 ret_val;
+ u16 data;
+
+ ret_val = e1000e_update_nvm_checksum_generic(hw);
+ if (ret_val)
+ return ret_val;;
+
+ if (nvm->type != e1000_nvm_flash_sw)
+ return ret_val;;
+
+ ret_val = e1000_acquire_swflag_ich8lan(hw);
+ if (ret_val)
+ return ret_val;;
+
+ /* We're writing to the opposite bank so if we're on bank 1,
+ * write to bank 0 etc. We also need to erase the segment that
+ * is going to be written */
+ if (!(er32(EECD) & E1000_EECD_SEC1VAL)) {
+ new_bank_offset = nvm->flash_bank_size;
+ old_bank_offset = 0;
+ e1000_erase_flash_bank_ich8lan(hw, 1);
+ } else {
+ old_bank_offset = nvm->flash_bank_size;
+ new_bank_offset = 0;
+ e1000_erase_flash_bank_ich8lan(hw, 0);
+ }
+
+ for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
+ /* Determine whether to write the value stored
+ * in the other NVM bank or a modified value stored
+ * in the shadow RAM */
+ if (dev_spec->shadow_ram[i].modified) {
+ data = dev_spec->shadow_ram[i].value;
+ } else {
+ e1000_read_flash_word_ich8lan(hw,
+ i + old_bank_offset,
+ &data);
+ }
+
+ /* If the word is 0x13, then make sure the signature bits
+ * (15:14) are 11b until the commit has completed.
+ * This will allow us to write 10b which indicates the
+ * signature is valid. We want to do this after the write
+ * has completed so that we don't mark the segment valid
+ * while the write is still in progress */
+ if (i == E1000_ICH_NVM_SIG_WORD)
+ data |= E1000_ICH_NVM_SIG_MASK;
+
+ /* Convert offset to bytes. */
+ act_offset = (i + new_bank_offset) << 1;
+
+ udelay(100);
+ /* Write the bytes to the new bank. */
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+ act_offset,
+ (u8)data);
+ if (ret_val)
+ break;
+
+ udelay(100);
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+ act_offset + 1,
+ (u8)(data >> 8));
+ if (ret_val)
+ break;
+ }
+
+ /* Don't bother writing the segment valid bits if sector
+ * programming failed. */
+ if (ret_val) {
+ hw_dbg(hw, "Flash commit failed.\n");
+ e1000_release_swflag_ich8lan(hw);
+ return ret_val;
+ }
+
+ /* Finally validate the new segment by setting bit 15:14
+ * to 10b in word 0x13 , this can be done without an
+ * erase as well since these bits are 11 to start with
+ * and we need to change bit 14 to 0b */
+ act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
+ e1000_read_flash_word_ich8lan(hw, act_offset, &data);
+ data &= 0xBFFF;
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+ act_offset * 2 + 1,
+ (u8)(data >> 8));
+ if (ret_val) {
+ e1000_release_swflag_ich8lan(hw);
+ return ret_val;
+ }
+
+ /* And invalidate the previously valid segment by setting
+ * its signature word (0x13) high_byte to 0b. This can be
+ * done without an erase because flash erase sets all bits
+ * to 1's. We can write 1's to 0's without an erase */
+ act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
+ ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
+ if (ret_val) {
+ e1000_release_swflag_ich8lan(hw);
+ return ret_val;
+ }
+
+ /* Great! Everything worked, we can now clear the cached entries. */
+ for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
+ dev_spec->shadow_ram[i].modified = 0;
+ dev_spec->shadow_ram[i].value = 0xFFFF;
+ }
+
+ e1000_release_swflag_ich8lan(hw);
+
+ /* Reload the EEPROM, or else modifications will not appear
+ * until after the next adapter reset.
+ */
+ e1000e_reload_nvm(hw);
+ msleep(10);
+
+ return ret_val;
+}
+
+/**
+ * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
+ * If the bit is 0, that the EEPROM had been modified, but the checksum was not
+ * calculated, in which case we need to calculate the checksum and set bit 6.
+ **/
+static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 data;
+
+ /* Read 0x19 and check bit 6. If this bit is 0, the checksum
+ * needs to be fixed. This bit is an indication that the NVM
+ * was prepared by OEM software and did not calculate the
+ * checksum...a likely scenario.
+ */
+ ret_val = e1000_read_nvm(hw, 0x19, 1, &data);
+ if (ret_val)
+ return ret_val;
+
+ if ((data & 0x40) == 0) {
+ data |= 0x40;
+ ret_val = e1000_write_nvm(hw, 0x19, 1, &data);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000e_update_nvm_checksum(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ return e1000e_validate_nvm_checksum_generic(hw);
+}
+
+/**
+ * e1000_write_flash_data_ich8lan - Writes bytes to the NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset (in bytes) of the byte/word to read.
+ * @size: Size of data to read, 1=byte 2=word
+ * @data: The byte(s) to write to the NVM.
+ *
+ * Writes one/two bytes to the NVM using the flash access registers.
+ **/
+static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+ u8 size, u16 data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ u32 flash_linear_addr;
+ u32 flash_data = 0;
+ s32 ret_val;
+ u8 count = 0;
+
+ if (size < 1 || size > 2 || data > size * 0xff ||
+ offset > ICH_FLASH_LINEAR_ADDR_MASK)
+ return -E1000_ERR_NVM;
+
+ flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+ hw->nvm.flash_base_addr;
+
+ do {
+ udelay(1);
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val)
+ break;
+
+ hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+ hsflctl.hsf_ctrl.fldbcount = size -1;
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
+ ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
+
+ if (size == 1)
+ flash_data = (u32)data & 0x00FF;
+ else
+ flash_data = (u32)data;
+
+ ew32flash(ICH_FLASH_FDATA0, flash_data);
+
+ /* check if FCERR is set to 1 , if set to 1, clear it
+ * and try the whole sequence a few more times else done */
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_WRITE_COMMAND_TIMEOUT);
+ if (!ret_val)
+ break;
+
+ /* If we're here, then things are most likely
+ * completely hosed, but if the error condition
+ * is detected, it won't hurt to give it another
+ * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1)
+ /* Repeat for some time before giving up. */
+ continue;
+ if (hsfsts.hsf_status.flcdone == 0) {
+ hw_dbg(hw, "Timeout error - flash cycle "
+ "did not complete.");
+ break;
+ }
+ } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+ return ret_val;
+}
+
+/**
+ * e1000_write_flash_byte_ich8lan - Write a single byte to NVM
+ * @hw: pointer to the HW structure
+ * @offset: The index of the byte to read.
+ * @data: The byte to write to the NVM.
+ *
+ * Writes a single byte to the NVM using the flash access registers.
+ **/
+static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
+ u8 data)
+{
+ u16 word = (u16)data;
+
+ return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
+}
+
+/**
+ * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
+ * @hw: pointer to the HW structure
+ * @offset: The offset of the byte to write.
+ * @byte: The byte to write to the NVM.
+ *
+ * Writes a single byte to the NVM using the flash access registers.
+ * Goes through a retry algorithm before giving up.
+ **/
+static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+ u32 offset, u8 byte)
+{
+ s32 ret_val;
+ u16 program_retries;
+
+ ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
+ if (!ret_val)
+ return ret_val;
+
+ for (program_retries = 0; program_retries < 100; program_retries++) {
+ hw_dbg(hw, "Retrying Byte %2.2X at offset %u\n", byte, offset);
+ udelay(100);
+ ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
+ if (!ret_val)
+ break;
+ }
+ if (program_retries == 100)
+ return -E1000_ERR_NVM;
+
+ return 0;
+}
+
+/**
+ * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
+ * @hw: pointer to the HW structure
+ * @bank: 0 for first bank, 1 for second bank, etc.
+ *
+ * Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
+ * bank N is 4096 * N + flash_reg_addr.
+ **/
+static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ u32 flash_linear_addr;
+ /* bank size is in 16bit words - adjust to bytes */
+ u32 flash_bank_size = nvm->flash_bank_size * 2;
+ s32 ret_val;
+ s32 count = 0;
+ s32 iteration;
+ s32 sector_size;
+ s32 j;
+
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+
+ /* Determine HW Sector size: Read BERASE bits of hw flash status
+ * register */
+ /* 00: The Hw sector is 256 bytes, hence we need to erase 16
+ * consecutive sectors. The start index for the nth Hw sector
+ * can be calculated as = bank * 4096 + n * 256
+ * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
+ * The start index for the nth Hw sector can be calculated
+ * as = bank * 4096
+ * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
+ * (ich9 only, otherwise error condition)
+ * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
+ */
+ switch (hsfsts.hsf_status.berasesz) {
+ case 0:
+ /* Hw sector size 256 */
+ sector_size = ICH_FLASH_SEG_SIZE_256;
+ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
+ break;
+ case 1:
+ sector_size = ICH_FLASH_SEG_SIZE_4K;
+ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K;
+ break;
+ case 2:
+ if (hw->mac.type == e1000_ich9lan) {
+ sector_size = ICH_FLASH_SEG_SIZE_8K;
+ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K;
+ } else {
+ return -E1000_ERR_NVM;
+ }
+ break;
+ case 3:
+ sector_size = ICH_FLASH_SEG_SIZE_64K;
+ iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K;
+ break;
+ default:
+ return -E1000_ERR_NVM;
+ }
+
+ /* Start with the base address, then add the sector offset. */
+ flash_linear_addr = hw->nvm.flash_base_addr;
+ flash_linear_addr += (bank) ? (sector_size * iteration) : 0;
+
+ for (j = 0; j < iteration ; j++) {
+ do {
+ /* Steps */
+ ret_val = e1000_flash_cycle_init_ich8lan(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Write a value 11 (block Erase) in Flash
+ * Cycle field in hw flash control */
+ hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+ hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
+ ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+ /* Write the last 24 bits of an index within the
+ * block into Flash Linear address field in Flash
+ * Address.
+ */
+ flash_linear_addr += (j * sector_size);
+ ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
+
+ ret_val = e1000_flash_cycle_ich8lan(hw,
+ ICH_FLASH_ERASE_COMMAND_TIMEOUT);
+ if (ret_val == 0)
+ break;
+
+ /* Check if FCERR is set to 1. If 1,
+ * clear it and try the whole sequence
+ * a few more times else Done */
+ hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1)
+ /* repeat for some time before
+ * giving up */
+ continue;
+ else if (hsfsts.hsf_status.flcdone == 0)
+ return ret_val;
+ } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_valid_led_default_ich8lan - Set the default LED settings
+ * @hw: pointer to the HW structure
+ * @data: Pointer to the LED settings
+ *
+ * Reads the LED default settings from the NVM to data. If the NVM LED
+ * settings is all 0's or F's, set the LED default to a valid LED default
+ * setting.
+ **/
+static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
+{
+ s32 ret_val;
+
+ ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+
+ if (*data == ID_LED_RESERVED_0000 ||
+ *data == ID_LED_RESERVED_FFFF)
+ *data = ID_LED_DEFAULT_ICH8LAN;
+
+ return 0;
+}
+
+/**
+ * e1000_get_bus_info_ich8lan - Get/Set the bus type and width
+ * @hw: pointer to the HW structure
+ *
+ * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
+ * register, so the the bus width is hard coded.
+ **/
+static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+ s32 ret_val;
+
+ ret_val = e1000e_get_bus_info_pcie(hw);
+
+ /* ICH devices are "PCI Express"-ish. They have
+ * a configuration space, but do not contain
+ * PCI Express Capability registers, so bus width
+ * must be hardcoded.
+ */
+ if (bus->width == e1000_bus_width_unknown)
+ bus->width = e1000_bus_width_pcie_x1;
+
+ return ret_val;
+}
+
+/**
+ * e1000_reset_hw_ich8lan - Reset the hardware
+ * @hw: pointer to the HW structure
+ *
+ * Does a full reset of the hardware which includes a reset of the PHY and
+ * MAC.
+ **/
+static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
+{
+ u32 ctrl, icr, kab;
+ s32 ret_val;
+
+ /* Prevent the PCI-E bus from sticking if there is no TLP connection
+ * on the last TLP read/write transaction when MAC is reset.
+ */
+ ret_val = e1000e_disable_pcie_master(hw);
+ if (ret_val) {
+ hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+ }
+
+ hw_dbg(hw, "Masking off all interrupts\n");
+ ew32(IMC, 0xffffffff);
+
+ /* Disable the Transmit and Receive units. Then delay to allow
+ * any pending transactions to complete before we hit the MAC
+ * with the global reset.
+ */
+ ew32(RCTL, 0);
+ ew32(TCTL, E1000_TCTL_PSP);
+ e1e_flush();
+
+ msleep(10);
+
+ /* Workaround for ICH8 bit corruption issue in FIFO memory */
+ if (hw->mac.type == e1000_ich8lan) {
+ /* Set Tx and Rx buffer allocation to 8k apiece. */
+ ew32(PBA, E1000_PBA_8K);
+ /* Set Packet Buffer Size to 16k. */
+ ew32(PBS, E1000_PBS_16K);
+ }
+
+ ctrl = er32(CTRL);
+
+ if (!e1000_check_reset_block(hw)) {
+ /* PHY HW reset requires MAC CORE reset at the same
+ * time to make sure the interface between MAC and the
+ * external PHY is reset.
+ */
+ ctrl |= E1000_CTRL_PHY_RST;
+ }
+ ret_val = e1000_acquire_swflag_ich8lan(hw);
+ hw_dbg(hw, "Issuing a global reset to ich8lan");
+ ew32(CTRL, (ctrl | E1000_CTRL_RST));
+ msleep(20);
+
+ ret_val = e1000e_get_auto_rd_done(hw);
+ if (ret_val) {
+ /*
+ * When auto config read does not complete, do not
+ * return with an error. This can happen in situations
+ * where there is no eeprom and prevents getting link.
+ */
+ hw_dbg(hw, "Auto Read Done did not complete\n");
+ }
+
+ ew32(IMC, 0xffffffff);
+ icr = er32(ICR);
+
+ kab = er32(KABGTXD);
+ kab |= E1000_KABGTXD_BGSQLBIAS;
+ ew32(KABGTXD, kab);
+
+ return ret_val;
+}
+
+/**
+ * e1000_init_hw_ich8lan - Initialize the hardware
+ * @hw: pointer to the HW structure
+ *
+ * Prepares the hardware for transmit and receive by doing the following:
+ * - initialize hardware bits
+ * - initialize LED identification
+ * - setup receive address registers
+ * - setup flow control
+ * - setup transmit discriptors
+ * - clear statistics
+ **/
+static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 ctrl_ext, txdctl, snoop;
+ s32 ret_val;
+ u16 i;
+
+ e1000_initialize_hw_bits_ich8lan(hw);
+
+ /* Initialize identification LED */
+ ret_val = e1000e_id_led_init(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error initializing identification LED\n");
+ return ret_val;
+ }
+
+ /* Setup the receive address. */
+ e1000e_init_rx_addrs(hw, mac->rar_entry_count);
+
+ /* Zero out the Multicast HASH table */
+ hw_dbg(hw, "Zeroing the MTA\n");
+ for (i = 0; i < mac->mta_reg_count; i++)
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+ /* Setup link and flow control */
+ ret_val = e1000_setup_link_ich8lan(hw);
+
+ /* Set the transmit descriptor write-back policy for both queues */
+ txdctl = er32(TXDCTL);
+ txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB;
+ txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+ E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+ ew32(TXDCTL, txdctl);
+ txdctl = er32(TXDCTL1);
+ txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+ E1000_TXDCTL_FULL_TX_DESC_WB;
+ txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+ E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+ ew32(TXDCTL1, txdctl);
+
+ /* ICH8 has opposite polarity of no_snoop bits.
+ * By default, we should use snoop behavior. */
+ if (mac->type == e1000_ich8lan)
+ snoop = PCIE_ICH8_SNOOP_ALL;
+ else
+ snoop = (u32) ~(PCIE_NO_SNOOP_ALL);
+ e1000e_set_pcie_no_snoop(hw, snoop);
+
+ ctrl_ext = er32(CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+ ew32(CTRL_EXT, ctrl_ext);
+
+ /* Clear all of the statistics registers (clear on read). It is
+ * important that we do this after we have tried to establish link
+ * because the symbol error count will increment wildly if there
+ * is no link.
+ */
+ e1000_clear_hw_cntrs_ich8lan(hw);
+
+ return 0;
+}
+/**
+ * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
+ * @hw: pointer to the HW structure
+ *
+ * Sets/Clears required hardware bits necessary for correctly setting up the
+ * hardware for transmit and receive.
+ **/
+static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
+{
+ u32 reg;
+
+ /* Extended Device Control */
+ reg = er32(CTRL_EXT);
+ reg |= (1 << 22);
+ ew32(CTRL_EXT, reg);
+
+ /* Transmit Descriptor Control 0 */
+ reg = er32(TXDCTL);
+ reg |= (1 << 22);
+ ew32(TXDCTL, reg);
+
+ /* Transmit Descriptor Control 1 */
+ reg = er32(TXDCTL1);
+ reg |= (1 << 22);
+ ew32(TXDCTL1, reg);
+
+ /* Transmit Arbitration Control 0 */
+ reg = er32(TARC0);
+ if (hw->mac.type == e1000_ich8lan)
+ reg |= (1 << 28) | (1 << 29);
+ reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
+ ew32(TARC0, reg);
+
+ /* Transmit Arbitration Control 1 */
+ reg = er32(TARC1);
+ if (er32(TCTL) & E1000_TCTL_MULR)
+ reg &= ~(1 << 28);
+ else
+ reg |= (1 << 28);
+ reg |= (1 << 24) | (1 << 26) | (1 << 30);
+ ew32(TARC1, reg);
+
+ /* Device Status */
+ if (hw->mac.type == e1000_ich8lan) {
+ reg = er32(STATUS);
+ reg &= ~(1 << 31);
+ ew32(STATUS, reg);
+ }
+}
+
+/**
+ * e1000_setup_link_ich8lan - Setup flow control and link settings
+ * @hw: pointer to the HW structure
+ *
+ * Determines which flow control settings to use, then configures flow
+ * control. Calls the appropriate media-specific link configuration
+ * function. Assuming the adapter has a valid link partner, a valid link
+ * should be established. Assumes the hardware has previously been reset
+ * and the transmitter and receiver are not enabled.
+ **/
+static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ s32 ret_val;
+
+ if (e1000_check_reset_block(hw))
+ return 0;
+
+ /* ICH parts do not have a word in the NVM to determine
+ * the default flow control setting, so we explicitly
+ * set it to full.
+ */
+ if (mac->fc == e1000_fc_default)
+ mac->fc = e1000_fc_full;
+
+ mac->original_fc = mac->fc;
+
+ hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", mac->fc);
+
+ /* Continue to configure the copper link. */
+ ret_val = e1000_setup_copper_link_ich8lan(hw);
+ if (ret_val)
+ return ret_val;
+
+ ew32(FCTTV, mac->fc_pause_time);
+
+ return e1000e_set_fc_watermarks(hw);
+}
+
+/**
+ * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
+ * @hw: pointer to the HW structure
+ *
+ * Configures the kumeran interface to the PHY to wait the appropriate time
+ * when polling the PHY, then call the generic setup_copper_link to finish
+ * configuring the copper link.
+ **/
+static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ s32 ret_val;
+ u16 reg_data;
+
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ew32(CTRL, ctrl);
+
+ /* Set the mac to wait the maximum time between each iteration
+ * and increase the max iterations when polling the phy;
+ * this fixes erroneous timeouts at 10Mbps. */
+ ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), &reg_data);
+ if (ret_val)
+ return ret_val;
+ reg_data |= 0x3F;
+ ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data);
+ if (ret_val)
+ return ret_val;
+
+ if (hw->phy.type == e1000_phy_igp_3) {
+ ret_val = e1000e_copper_link_setup_igp(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ return e1000e_setup_copper_link(hw);
+}
+
+/**
+ * e1000_get_link_up_info_ich8lan - Get current link speed and duplex
+ * @hw: pointer to the HW structure
+ * @speed: pointer to store current link speed
+ * @duplex: pointer to store the current link duplex
+ *
+ * Calls the generic get_speed_and_duplex to retreive the current link
+ * information and then calls the Kumeran lock loss workaround for links at
+ * gigabit speeds.
+ **/
+static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
+ u16 *duplex)
+{
+ s32 ret_val;
+
+ ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex);
+ if (ret_val)
+ return ret_val;
+
+ if ((hw->mac.type == e1000_ich8lan) &&
+ (hw->phy.type == e1000_phy_igp_3) &&
+ (*speed == SPEED_1000)) {
+ ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
+ * @hw: pointer to the HW structure
+ *
+ * Work-around for 82566 Kumeran PCS lock loss:
+ * On link status change (i.e. PCI reset, speed change) and link is up and
+ * speed is gigabit-
+ * 0) if workaround is optionally disabled do nothing
+ * 1) wait 1ms for Kumeran link to come up
+ * 2) check Kumeran Diagnostic register PCS lock loss bit
+ * 3) if not set the link is locked (all is good), otherwise...
+ * 4) reset the PHY
+ * 5) repeat up to 10 times
+ * Note: this is only called for IGP3 copper when speed is 1gb.
+ **/
+static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
+{
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+ u32 phy_ctrl;
+ s32 ret_val;
+ u16 i, data;
+ bool link;
+
+ if (!dev_spec->kmrn_lock_loss_workaround_enabled)
+ return 0;
+
+ /* Make sure link is up before proceeding. If not just return.
+ * Attempting this while link is negotiating fouled up link
+ * stability */
+ ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+ if (!link)
+ return 0;
+
+ for (i = 0; i < 10; i++) {
+ /* read once to clear */
+ ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data);
+ if (ret_val)
+ return ret_val;
+ /* and again to get new status */
+ ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data);
+ if (ret_val)
+ return ret_val;
+
+ /* check for PCS lock */
+ if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS))
+ return 0;
+
+ /* Issue PHY reset */
+ e1000_phy_hw_reset(hw);
+ mdelay(5);
+ }
+ /* Disable GigE link negotiation */
+ phy_ctrl = er32(PHY_CTRL);
+ phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
+ E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+ ew32(PHY_CTRL, phy_ctrl);
+
+ /* Call gig speed drop workaround on Giga disable before accessing
+ * any PHY registers */
+ e1000e_gig_downshift_workaround_ich8lan(hw);
+
+ /* unable to acquire PCS lock */
+ return -E1000_ERR_PHY;
+}
+
+/**
+ * e1000_set_kmrn_lock_loss_workaound_ich8lan - Set Kumeran workaround state
+ * @hw: pointer to the HW structure
+ * @state: boolean value used to set the current Kumaran workaround state
+ *
+ * If ICH8, set the current Kumeran workaround state (enabled - TRUE
+ * /disabled - FALSE).
+ **/
+void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+ bool state)
+{
+ struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+
+ if (hw->mac.type != e1000_ich8lan) {
+ hw_dbg(hw, "Workaround applies to ICH8 only.\n");
+ return;
+ }
+
+ dev_spec->kmrn_lock_loss_workaround_enabled = state;
+}
+
+/**
+ * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
+ * @hw: pointer to the HW structure
+ *
+ * Workaround for 82566 power-down on D3 entry:
+ * 1) disable gigabit link
+ * 2) write VR power-down enable
+ * 3) read it back
+ * Continue if successful, else issue LCD reset and repeat
+ **/
+void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
+{
+ u32 reg;
+ u16 data;
+ u8 retry = 0;
+
+ if (hw->phy.type != e1000_phy_igp_3)
+ return;
+
+ /* Try the workaround twice (if needed) */
+ do {
+ /* Disable link */
+ reg = er32(PHY_CTRL);
+ reg |= (E1000_PHY_CTRL_GBE_DISABLE |
+ E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+ ew32(PHY_CTRL, reg);
+
+ /* Call gig speed drop workaround on Giga disable before
+ * accessing any PHY registers */
+ if (hw->mac.type == e1000_ich8lan)
+ e1000e_gig_downshift_workaround_ich8lan(hw);
+
+ /* Write VR power-down enable */
+ e1e_rphy(hw, IGP3_VR_CTRL, &data);
+ data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+ e1e_wphy(hw, IGP3_VR_CTRL, data | IGP3_VR_CTRL_MODE_SHUTDOWN);
+
+ /* Read it back and test */
+ e1e_rphy(hw, IGP3_VR_CTRL, &data);
+ data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+ if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
+ break;
+
+ /* Issue PHY reset and repeat at most one more time */
+ reg = er32(CTRL);
+ ew32(CTRL, reg | E1000_CTRL_PHY_RST);
+ retry++;
+ } while (retry);
+}
+
+/**
+ * e1000e_gig_downshift_workaround_ich8lan - WoL from S5 stops working
+ * @hw: pointer to the HW structure
+ *
+ * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
+ * LPLU, Giga disable, MDIC PHY reset):
+ * 1) Set Kumeran Near-end loopback
+ * 2) Clear Kumeran Near-end loopback
+ * Should only be called for ICH8[m] devices with IGP_3 Phy.
+ **/
+void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 reg_data;
+
+ if ((hw->mac.type != e1000_ich8lan) ||
+ (hw->phy.type != e1000_phy_igp_3))
+ return;
+
+ ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
+ &reg_data);
+ if (ret_val)
+ return;
+ reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
+ ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
+ reg_data);
+ if (ret_val)
+ return;
+ reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
+ ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
+ reg_data);
+}
+
+/**
+ * e1000_cleanup_led_ich8lan - Restore the default LED operation
+ * @hw: pointer to the HW structure
+ *
+ * Return the LED back to the default configuration.
+ **/
+static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
+{
+ if (hw->phy.type == e1000_phy_ife)
+ return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0);
+
+ ew32(LEDCTL, hw->mac.ledctl_default);
+ return 0;
+}
+
+/**
+ * e1000_led_on_ich8lan - Turn LED's on
+ * @hw: pointer to the HW structure
+ *
+ * Turn on the LED's.
+ **/
+static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
+{
+ if (hw->phy.type == e1000_phy_ife)
+ return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
+
+ ew32(LEDCTL, hw->mac.ledctl_mode2);
+ return 0;
+}
+
+/**
+ * e1000_led_off_ich8lan - Turn LED's off
+ * @hw: pointer to the HW structure
+ *
+ * Turn off the LED's.
+ **/
+static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
+{
+ if (hw->phy.type == e1000_phy_ife)
+ return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
+
+ ew32(LEDCTL, hw->mac.ledctl_mode1);
+ return 0;
+}
+
+/**
+ * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears hardware counters specific to the silicon family and calls
+ * clear_hw_cntrs_generic to clear all general purpose counters.
+ **/
+static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
+{
+ u32 temp;
+
+ e1000e_clear_hw_cntrs_base(hw);
+
+ temp = er32(ALGNERRC);
+ temp = er32(RXERRC);
+ temp = er32(TNCRS);
+ temp = er32(CEXTERR);
+ temp = er32(TSCTC);
+ temp = er32(TSCTFC);
+
+ temp = er32(MGTPRC);
+ temp = er32(MGTPDC);
+ temp = er32(MGTPTC);
+
+ temp = er32(IAC);
+ temp = er32(ICRXOC);
+
+}
+
+static struct e1000_mac_operations ich8_mac_ops = {
+ .mng_mode_enab = E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+ .check_for_link = e1000e_check_for_copper_link,
+ .cleanup_led = e1000_cleanup_led_ich8lan,
+ .clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan,
+ .get_bus_info = e1000_get_bus_info_ich8lan,
+ .get_link_up_info = e1000_get_link_up_info_ich8lan,
+ .led_on = e1000_led_on_ich8lan,
+ .led_off = e1000_led_off_ich8lan,
+ .mc_addr_list_update = e1000e_mc_addr_list_update_generic,
+ .reset_hw = e1000_reset_hw_ich8lan,
+ .init_hw = e1000_init_hw_ich8lan,
+ .setup_link = e1000_setup_link_ich8lan,
+ .setup_physical_interface= e1000_setup_copper_link_ich8lan,
+};
+
+static struct e1000_phy_operations ich8_phy_ops = {
+ .acquire_phy = e1000_acquire_swflag_ich8lan,
+ .check_reset_block = e1000_check_reset_block_ich8lan,
+ .commit_phy = NULL,
+ .force_speed_duplex = e1000_phy_force_speed_duplex_ich8lan,
+ .get_cfg_done = e1000e_get_cfg_done,
+ .get_cable_length = e1000e_get_cable_length_igp_2,
+ .get_phy_info = e1000_get_phy_info_ich8lan,
+ .read_phy_reg = e1000e_read_phy_reg_igp,
+ .release_phy = e1000_release_swflag_ich8lan,
+ .reset_phy = e1000_phy_hw_reset_ich8lan,
+ .set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan,
+ .set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan,
+ .write_phy_reg = e1000e_write_phy_reg_igp,
+};
+
+static struct e1000_nvm_operations ich8_nvm_ops = {
+ .acquire_nvm = e1000_acquire_swflag_ich8lan,
+ .read_nvm = e1000_read_nvm_ich8lan,
+ .release_nvm = e1000_release_swflag_ich8lan,
+ .update_nvm = e1000_update_nvm_checksum_ich8lan,
+ .valid_led_default = e1000_valid_led_default_ich8lan,
+ .validate_nvm = e1000_validate_nvm_checksum_ich8lan,
+ .write_nvm = e1000_write_nvm_ich8lan,
+};
+
+struct e1000_info e1000_ich8_info = {
+ .mac = e1000_ich8lan,
+ .flags = FLAG_HAS_WOL
+ | FLAG_RX_CSUM_ENABLED
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_AMT
+ | FLAG_HAS_FLASH
+ | FLAG_APME_IN_WUC,
+ .pba = 8,
+ .get_invariants = e1000_get_invariants_ich8lan,
+ .mac_ops = &ich8_mac_ops,
+ .phy_ops = &ich8_phy_ops,
+ .nvm_ops = &ich8_nvm_ops,
+};
+
+struct e1000_info e1000_ich9_info = {
+ .mac = e1000_ich9lan,
+ .flags = FLAG_HAS_JUMBO_FRAMES
+ | FLAG_HAS_WOL
+ | FLAG_RX_CSUM_ENABLED
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_AMT
+ | FLAG_HAS_ERT
+ | FLAG_HAS_FLASH
+ | FLAG_APME_IN_WUC,
+ .pba = 10,
+ .get_invariants = e1000_get_invariants_ich8lan,
+ .mac_ops = &ich8_mac_ops,
+ .phy_ops = &ich8_phy_ops,
+ .nvm_ops = &ich8_nvm_ops,
+};
+
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
new file mode 100644
index 00000000000..0bdeca30c75
--- /dev/null
+++ b/drivers/net/e1000e/lib.c
@@ -0,0 +1,2493 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "e1000.h"
+
+enum e1000_mng_mode {
+ e1000_mng_mode_none = 0,
+ e1000_mng_mode_asf,
+ e1000_mng_mode_pt,
+ e1000_mng_mode_ipmi,
+ e1000_mng_mode_host_if_only
+};
+
+#define E1000_FACTPS_MNGCG 0x20000000
+
+#define E1000_IAMT_SIGNATURE 0x544D4149 /* Intel(R) Active Management
+ * Technology signature */
+
+/**
+ * e1000e_get_bus_info_pcie - Get PCIe bus information
+ * @hw: pointer to the HW structure
+ *
+ * Determines and stores the system bus information for a particular
+ * network interface. The following bus information is determined and stored:
+ * bus speed, bus width, type (PCIe), and PCIe function.
+ **/
+s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw)
+{
+ struct e1000_bus_info *bus = &hw->bus;
+ struct e1000_adapter *adapter = hw->adapter;
+ u32 status;
+ u16 pcie_link_status, pci_header_type, cap_offset;
+
+ cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (!cap_offset) {
+ bus->width = e1000_bus_width_unknown;
+ } else {
+ pci_read_config_word(adapter->pdev,
+ cap_offset + PCIE_LINK_STATUS,
+ &pcie_link_status);
+ bus->width = (enum e1000_bus_width)((pcie_link_status &
+ PCIE_LINK_WIDTH_MASK) >>
+ PCIE_LINK_WIDTH_SHIFT);
+ }
+
+ pci_read_config_word(adapter->pdev, PCI_HEADER_TYPE_REGISTER,
+ &pci_header_type);
+ if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
+ status = er32(STATUS);
+ bus->func = (status & E1000_STATUS_FUNC_MASK)
+ >> E1000_STATUS_FUNC_SHIFT;
+ } else {
+ bus->func = 0;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_write_vfta - Write value to VLAN filter table
+ * @hw: pointer to the HW structure
+ * @offset: register offset in VLAN filter table
+ * @value: register value written to VLAN filter table
+ *
+ * Writes value at the given offset in the register array which stores
+ * the VLAN filter table.
+ **/
+void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
+{
+ E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
+ e1e_flush();
+}
+
+/**
+ * e1000e_init_rx_addrs - Initialize receive address's
+ * @hw: pointer to the HW structure
+ * @rar_count: receive address registers
+ *
+ * Setups the receive address registers by setting the base receive address
+ * register to the devices MAC address and clearing all the other receive
+ * address registers to 0.
+ **/
+void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
+{
+ u32 i;
+
+ /* Setup the receive address */
+ hw_dbg(hw, "Programming MAC Address into RAR[0]\n");
+
+ e1000e_rar_set(hw, hw->mac.addr, 0);
+
+ /* Zero out the other (rar_entry_count - 1) receive addresses */
+ hw_dbg(hw, "Clearing RAR[1-%u]\n", rar_count-1);
+ for (i = 1; i < rar_count; i++) {
+ E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1), 0);
+ e1e_flush();
+ E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((i << 1) + 1), 0);
+ e1e_flush();
+ }
+}
+
+/**
+ * e1000e_rar_set - Set receive address register
+ * @hw: pointer to the HW structure
+ * @addr: pointer to the receive address
+ * @index: receive address array register
+ *
+ * Sets the receive address array register at index to the address passed
+ * in by addr.
+ **/
+void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+ u32 rar_low, rar_high;
+
+ /* HW expects these in little endian so we reverse the byte order
+ * from network order (big endian) to little endian
+ */
+ rar_low = ((u32) addr[0] |
+ ((u32) addr[1] << 8) |
+ ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+
+ rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+
+ rar_high |= E1000_RAH_AV;
+
+ E1000_WRITE_REG_ARRAY(hw, E1000_RA, (index << 1), rar_low);
+ E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((index << 1) + 1), rar_high);
+}
+
+/**
+ * e1000_mta_set - Set multicast filter table address
+ * @hw: pointer to the HW structure
+ * @hash_value: determines the MTA register and bit to set
+ *
+ * The multicast table address is a register array of 32-bit registers.
+ * The hash_value is used to determine what register the bit is in, the
+ * current value is read, the new bit is OR'd in and the new value is
+ * written back into the register.
+ **/
+static void e1000_mta_set(struct e1000_hw *hw, u32 hash_value)
+{
+ u32 hash_bit, hash_reg, mta;
+
+ /* The MTA is a register array of 32-bit registers. It is
+ * treated like an array of (32*mta_reg_count) bits. We want to
+ * set bit BitArray[hash_value]. So we figure out what register
+ * the bit is in, read it, OR in the new bit, then write
+ * back the new value. The (hw->mac.mta_reg_count - 1) serves as a
+ * mask to bits 31:5 of the hash value which gives us the
+ * register we're modifying. The hash bit within that register
+ * is determined by the lower 5 bits of the hash value.
+ */
+ hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+ hash_bit = hash_value & 0x1F;
+
+ mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
+
+ mta |= (1 << hash_bit);
+
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
+ e1e_flush();
+}
+
+/**
+ * e1000_hash_mc_addr - Generate a multicast hash value
+ * @hw: pointer to the HW structure
+ * @mc_addr: pointer to a multicast address
+ *
+ * Generates a multicast address hash value which is used to determine
+ * the multicast filter table array address and new table value. See
+ * e1000_mta_set_generic()
+ **/
+static u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
+{
+ u32 hash_value, hash_mask;
+ u8 bit_shift = 0;
+
+ /* Register count multiplied by bits per register */
+ hash_mask = (hw->mac.mta_reg_count * 32) - 1;
+
+ /* For a mc_filter_type of 0, bit_shift is the number of left-shifts
+ * where 0xFF would still fall within the hash mask. */
+ while (hash_mask >> bit_shift != 0xFF)
+ bit_shift++;
+
+ /* The portion of the address that is used for the hash table
+ * is determined by the mc_filter_type setting.
+ * The algorithm is such that there is a total of 8 bits of shifting.
+ * The bit_shift for a mc_filter_type of 0 represents the number of
+ * left-shifts where the MSB of mc_addr[5] would still fall within
+ * the hash_mask. Case 0 does this exactly. Since there are a total
+ * of 8 bits of shifting, then mc_addr[4] will shift right the
+ * remaining number of bits. Thus 8 - bit_shift. The rest of the
+ * cases are a variation of this algorithm...essentially raising the
+ * number of bits to shift mc_addr[5] left, while still keeping the
+ * 8-bit shifting total.
+ */
+ /* For example, given the following Destination MAC Address and an
+ * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
+ * we can see that the bit_shift for case 0 is 4. These are the hash
+ * values resulting from each mc_filter_type...
+ * [0] [1] [2] [3] [4] [5]
+ * 01 AA 00 12 34 56
+ * LSB MSB
+ *
+ * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
+ * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
+ * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
+ * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
+ */
+ switch (hw->mac.mc_filter_type) {
+ default:
+ case 0:
+ break;
+ case 1:
+ bit_shift += 1;
+ break;
+ case 2:
+ bit_shift += 2;
+ break;
+ case 3:
+ bit_shift += 4;
+ break;
+ }
+
+ hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
+ (((u16) mc_addr[5]) << bit_shift)));
+
+ return hash_value;
+}
+
+/**
+ * e1000e_mc_addr_list_update_generic - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ * @rar_used_count: the first RAR register free to program
+ * @rar_count: total number of supported Receive Address Registers
+ *
+ * Updates the Receive Address Registers and Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ * The parameter rar_count will usually be hw->mac.rar_entry_count
+ * unless there are workarounds that change this.
+ **/
+void e1000e_mc_addr_list_update_generic(struct e1000_hw *hw,
+ u8 *mc_addr_list, u32 mc_addr_count,
+ u32 rar_used_count, u32 rar_count)
+{
+ u32 hash_value;
+ u32 i;
+
+ /* Load the first set of multicast addresses into the exact
+ * filters (RAR). If there are not enough to fill the RAR
+ * array, clear the filters.
+ */
+ for (i = rar_used_count; i < rar_count; i++) {
+ if (mc_addr_count) {
+ e1000e_rar_set(hw, mc_addr_list, i);
+ mc_addr_count--;
+ mc_addr_list += ETH_ALEN;
+ } else {
+ E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0);
+ e1e_flush();
+ E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0);
+ e1e_flush();
+ }
+ }
+
+ /* Clear the old settings from the MTA */
+ hw_dbg(hw, "Clearing MTA\n");
+ for (i = 0; i < hw->mac.mta_reg_count; i++) {
+ E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+ e1e_flush();
+ }
+
+ /* Load any remaining multicast addresses into the hash table. */
+ for (; mc_addr_count > 0; mc_addr_count--) {
+ hash_value = e1000_hash_mc_addr(hw, mc_addr_list);
+ hw_dbg(hw, "Hash value = 0x%03X\n", hash_value);
+ e1000_mta_set(hw, hash_value);
+ mc_addr_list += ETH_ALEN;
+ }
+}
+
+/**
+ * e1000e_clear_hw_cntrs_base - Clear base hardware counters
+ * @hw: pointer to the HW structure
+ *
+ * Clears the base hardware counters by reading the counter registers.
+ **/
+void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw)
+{
+ u32 temp;
+
+ temp = er32(CRCERRS);
+ temp = er32(SYMERRS);
+ temp = er32(MPC);
+ temp = er32(SCC);
+ temp = er32(ECOL);
+ temp = er32(MCC);
+ temp = er32(LATECOL);
+ temp = er32(COLC);
+ temp = er32(DC);
+ temp = er32(SEC);
+ temp = er32(RLEC);
+ temp = er32(XONRXC);
+ temp = er32(XONTXC);
+ temp = er32(XOFFRXC);
+ temp = er32(XOFFTXC);
+ temp = er32(FCRUC);
+ temp = er32(GPRC);
+ temp = er32(BPRC);
+ temp = er32(MPRC);
+ temp = er32(GPTC);
+ temp = er32(GORCL);
+ temp = er32(GORCH);
+ temp = er32(GOTCL);
+ temp = er32(GOTCH);
+ temp = er32(RNBC);
+ temp = er32(RUC);
+ temp = er32(RFC);
+ temp = er32(ROC);
+ temp = er32(RJC);
+ temp = er32(TORL);
+ temp = er32(TORH);
+ temp = er32(TOTL);
+ temp = er32(TOTH);
+ temp = er32(TPR);
+ temp = er32(TPT);
+ temp = er32(MPTC);
+ temp = er32(BPTC);
+}
+
+/**
+ * e1000e_check_for_copper_link - Check for link (Copper)
+ * @hw: pointer to the HW structure
+ *
+ * Checks to see of the link status of the hardware has changed. If a
+ * change in link status has been detected, then we read the PHY registers
+ * to get the current speed/duplex if link exists.
+ **/
+s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ s32 ret_val;
+ bool link;
+
+ /* We only want to go out to the PHY registers to see if Auto-Neg
+ * has completed and/or if our link status has changed. The
+ * get_link_status flag is set upon receiving a Link Status
+ * Change or Rx Sequence Error interrupt.
+ */
+ if (!mac->get_link_status)
+ return 0;
+
+ /* First we want to see if the MII Status Register reports
+ * link. If so, then we want to get the current speed/duplex
+ * of the PHY.
+ */
+ ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link)
+ return ret_val; /* No link detected */
+
+ mac->get_link_status = 0;
+
+ /* Check if there was DownShift, must be checked
+ * immediately after link-up */
+ e1000e_check_downshift(hw);
+
+ /* If we are forcing speed/duplex, then we simply return since
+ * we have already determined whether we have link or not.
+ */
+ if (!mac->autoneg) {
+ ret_val = -E1000_ERR_CONFIG;
+ return ret_val;
+ }
+
+ /* Auto-Neg is enabled. Auto Speed Detection takes care
+ * of MAC speed/duplex configuration. So we only need to
+ * configure Collision Distance in the MAC.
+ */
+ e1000e_config_collision_dist(hw);
+
+ /* Configure Flow Control now that Auto-Neg has completed.
+ * First, we need to restore the desired flow control
+ * settings because we may have had to re-autoneg with a
+ * different link partner.
+ */
+ ret_val = e1000e_config_fc_after_link_up(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error configuring flow control\n");
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_check_for_fiber_link - Check for link (Fiber)
+ * @hw: pointer to the HW structure
+ *
+ * Checks for link up on the hardware. If link is not up and we have
+ * a signal, then we need to force link up.
+ **/
+s32 e1000e_check_for_fiber_link(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 rxcw;
+ u32 ctrl;
+ u32 status;
+ s32 ret_val;
+
+ ctrl = er32(CTRL);
+ status = er32(STATUS);
+ rxcw = er32(RXCW);
+
+ /* If we don't have link (auto-negotiation failed or link partner
+ * cannot auto-negotiate), the cable is plugged in (we have signal),
+ * and our link partner is not trying to auto-negotiate with us (we
+ * are receiving idles or data), we need to force link up. We also
+ * need to give auto-negotiation time to complete, in case the cable
+ * was just plugged in. The autoneg_failed flag does this.
+ */
+ /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+ if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
+ (!(rxcw & E1000_RXCW_C))) {
+ if (mac->autoneg_failed == 0) {
+ mac->autoneg_failed = 1;
+ return 0;
+ }
+ hw_dbg(hw, "NOT RXing /C/, disable AutoNeg and force link.\n");
+
+ /* Disable auto-negotiation in the TXCW register */
+ ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+ /* Force link-up and also force full-duplex. */
+ ctrl = er32(CTRL);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ ew32(CTRL, ctrl);
+
+ /* Configure Flow Control after forcing link up. */
+ ret_val = e1000e_config_fc_after_link_up(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error configuring flow control\n");
+ return ret_val;
+ }
+ } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+ /* If we are forcing link and we are receiving /C/ ordered
+ * sets, re-enable auto-negotiation in the TXCW register
+ * and disable forced link in the Device Control register
+ * in an attempt to auto-negotiate with our link partner.
+ */
+ hw_dbg(hw, "RXing /C/, enable AutoNeg and stop forcing link.\n");
+ ew32(TXCW, mac->txcw);
+ ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+ mac->serdes_has_link = 1;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_check_for_serdes_link - Check for link (Serdes)
+ * @hw: pointer to the HW structure
+ *
+ * Checks for link up on the hardware. If link is not up and we have
+ * a signal, then we need to force link up.
+ **/
+s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 rxcw;
+ u32 ctrl;
+ u32 status;
+ s32 ret_val;
+
+ ctrl = er32(CTRL);
+ status = er32(STATUS);
+ rxcw = er32(RXCW);
+
+ /* If we don't have link (auto-negotiation failed or link partner
+ * cannot auto-negotiate), and our link partner is not trying to
+ * auto-negotiate with us (we are receiving idles or data),
+ * we need to force link up. We also need to give auto-negotiation
+ * time to complete.
+ */
+ /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+ if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
+ if (mac->autoneg_failed == 0) {
+ mac->autoneg_failed = 1;
+ return 0;
+ }
+ hw_dbg(hw, "NOT RXing /C/, disable AutoNeg and force link.\n");
+
+ /* Disable auto-negotiation in the TXCW register */
+ ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+ /* Force link-up and also force full-duplex. */
+ ctrl = er32(CTRL);
+ ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+ ew32(CTRL, ctrl);
+
+ /* Configure Flow Control after forcing link up. */
+ ret_val = e1000e_config_fc_after_link_up(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error configuring flow control\n");
+ return ret_val;
+ }
+ } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+ /* If we are forcing link and we are receiving /C/ ordered
+ * sets, re-enable auto-negotiation in the TXCW register
+ * and disable forced link in the Device Control register
+ * in an attempt to auto-negotiate with our link partner.
+ */
+ hw_dbg(hw, "RXing /C/, enable AutoNeg and stop forcing link.\n");
+ ew32(TXCW, mac->txcw);
+ ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+ mac->serdes_has_link = 1;
+ } else if (!(E1000_TXCW_ANE & er32(TXCW))) {
+ /* If we force link for non-auto-negotiation switch, check
+ * link status based on MAC synchronization for internal
+ * serdes media type.
+ */
+ /* SYNCH bit and IV bit are sticky. */
+ udelay(10);
+ if (E1000_RXCW_SYNCH & er32(RXCW)) {
+ if (!(rxcw & E1000_RXCW_IV)) {
+ mac->serdes_has_link = 1;
+ hw_dbg(hw, "SERDES: Link is up.\n");
+ }
+ } else {
+ mac->serdes_has_link = 0;
+ hw_dbg(hw, "SERDES: Link is down.\n");
+ }
+ }
+
+ if (E1000_TXCW_ANE & er32(TXCW)) {
+ status = er32(STATUS);
+ mac->serdes_has_link = (status & E1000_STATUS_LU);
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_set_default_fc_generic - Set flow control default values
+ * @hw: pointer to the HW structure
+ *
+ * Read the EEPROM for the default values for flow control and store the
+ * values.
+ **/
+static s32 e1000_set_default_fc_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ s32 ret_val;
+ u16 nvm_data;
+
+ if (mac->fc != e1000_fc_default)
+ return 0;
+
+ /* Read and store word 0x0F of the EEPROM. This word contains bits
+ * that determine the hardware's default PAUSE (flow control) mode,
+ * a bit that determines whether the HW defaults to enabling or
+ * disabling auto-negotiation, and the direction of the
+ * SW defined pins. If there is no SW over-ride of the flow
+ * control setting, then the variable hw->fc will
+ * be initialized based on a value in the EEPROM.
+ */
+ ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
+
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+
+ if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
+ mac->fc = e1000_fc_none;
+ else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
+ NVM_WORD0F_ASM_DIR)
+ mac->fc = e1000_fc_tx_pause;
+ else
+ mac->fc = e1000_fc_full;
+
+ return 0;
+}
+
+/**
+ * e1000e_setup_link - Setup flow control and link settings
+ * @hw: pointer to the HW structure
+ *
+ * Determines which flow control settings to use, then configures flow
+ * control. Calls the appropriate media-specific link configuration
+ * function. Assuming the adapter has a valid link partner, a valid link
+ * should be established. Assumes the hardware has previously been reset
+ * and the transmitter and receiver are not enabled.
+ **/
+s32 e1000e_setup_link(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ s32 ret_val;
+
+ /* In the case of the phy reset being blocked, we already have a link.
+ * We do not need to set it up again.
+ */
+ if (e1000_check_reset_block(hw))
+ return 0;
+
+ /*
+ * If flow control is set to default, set flow control based on
+ * the EEPROM flow control settings.
+ */
+ if (mac->fc == e1000_fc_default) {
+ ret_val = e1000_set_default_fc_generic(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* We want to save off the original Flow Control configuration just
+ * in case we get disconnected and then reconnected into a different
+ * hub or switch with different Flow Control capabilities.
+ */
+ mac->original_fc = mac->fc;
+
+ hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", mac->fc);
+
+ /* Call the necessary media_type subroutine to configure the link. */
+ ret_val = mac->ops.setup_physical_interface(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Initialize the flow control address, type, and PAUSE timer
+ * registers to their default values. This is done even if flow
+ * control is disabled, because it does not hurt anything to
+ * initialize these registers.
+ */
+ hw_dbg(hw, "Initializing the Flow Control address, type and timer regs\n");
+ ew32(FCT, FLOW_CONTROL_TYPE);
+ ew32(FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+ ew32(FCAL, FLOW_CONTROL_ADDRESS_LOW);
+
+ ew32(FCTTV, mac->fc_pause_time);
+
+ return e1000e_set_fc_watermarks(hw);
+}
+
+/**
+ * e1000_commit_fc_settings_generic - Configure flow control
+ * @hw: pointer to the HW structure
+ *
+ * Write the flow control settings to the Transmit Config Word Register (TXCW)
+ * base on the flow control settings in e1000_mac_info.
+ **/
+static s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 txcw;
+
+ /* Check for a software override of the flow control settings, and
+ * setup the device accordingly. If auto-negotiation is enabled, then
+ * software will have to set the "PAUSE" bits to the correct value in
+ * the Transmit Config Word Register (TXCW) and re-start auto-
+ * negotiation. However, if auto-negotiation is disabled, then
+ * software will have to manually configure the two flow control enable
+ * bits in the CTRL register.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames,
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames but we
+ * do not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ */
+ switch (mac->fc) {
+ case e1000_fc_none:
+ /* Flow control completely disabled by a software over-ride. */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+ break;
+ case e1000_fc_rx_pause:
+ /* RX Flow control is enabled and TX Flow control is disabled
+ * by a software over-ride. Since there really isn't a way to
+ * advertise that we are capable of RX Pause ONLY, we will
+ * advertise that we support both symmetric and asymmetric RX
+ * PAUSE. Later, we will disable the adapter's ability to send
+ * PAUSE frames.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ case e1000_fc_tx_pause:
+ /* TX Flow control is enabled, and RX Flow control is disabled,
+ * by a software over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+ break;
+ case e1000_fc_full:
+ /* Flow control (both RX and TX) is enabled by a software
+ * over-ride.
+ */
+ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+ break;
+ default:
+ hw_dbg(hw, "Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ break;
+ }
+
+ ew32(TXCW, txcw);
+ mac->txcw = txcw;
+
+ return 0;
+}
+
+/**
+ * e1000_poll_fiber_serdes_link_generic - Poll for link up
+ * @hw: pointer to the HW structure
+ *
+ * Polls for link up by reading the status register, if link fails to come
+ * up with auto-negotiation, then the link is forced if a signal is detected.
+ **/
+static s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 i, status;
+ s32 ret_val;
+
+ /* If we have a signal (the cable is plugged in, or assumed true for
+ * serdes media) then poll for a "Link-Up" indication in the Device
+ * Status Register. Time-out if a link isn't seen in 500 milliseconds
+ * seconds (Auto-negotiation should complete in less than 500
+ * milliseconds even if the other end is doing it in SW).
+ */
+ for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
+ msleep(10);
+ status = er32(STATUS);
+ if (status & E1000_STATUS_LU)
+ break;
+ }
+ if (i == FIBER_LINK_UP_LIMIT) {
+ hw_dbg(hw, "Never got a valid link from auto-neg!!!\n");
+ mac->autoneg_failed = 1;
+ /* AutoNeg failed to achieve a link, so we'll call
+ * mac->check_for_link. This routine will force the
+ * link up if we detect a signal. This will allow us to
+ * communicate with non-autonegotiating link partners.
+ */
+ ret_val = mac->ops.check_for_link(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error while checking for link\n");
+ return ret_val;
+ }
+ mac->autoneg_failed = 0;
+ } else {
+ mac->autoneg_failed = 0;
+ hw_dbg(hw, "Valid Link Found\n");
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_setup_fiber_serdes_link - Setup link for fiber/serdes
+ * @hw: pointer to the HW structure
+ *
+ * Configures collision distance and flow control for fiber and serdes
+ * links. Upon successful setup, poll for link.
+ **/
+s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ s32 ret_val;
+
+ ctrl = er32(CTRL);
+
+ /* Take the link out of reset */
+ ctrl &= ~E1000_CTRL_LRST;
+
+ e1000e_config_collision_dist(hw);
+
+ ret_val = e1000_commit_fc_settings_generic(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Since auto-negotiation is enabled, take the link out of reset (the
+ * link will be in reset, because we previously reset the chip). This
+ * will restart auto-negotiation. If auto-negotiation is successful
+ * then the link-up status bit will be set and the flow control enable
+ * bits (RFCE and TFCE) will be set according to their negotiated value.
+ */
+ hw_dbg(hw, "Auto-negotiation enabled\n");
+
+ ew32(CTRL, ctrl);
+ e1e_flush();
+ msleep(1);
+
+ /* For these adapters, the SW defineable pin 1 is set when the optics
+ * detect a signal. If we have a signal, then poll for a "Link-Up"
+ * indication.
+ */
+ if (hw->media_type == e1000_media_type_internal_serdes ||
+ (er32(CTRL) & E1000_CTRL_SWDPIN1)) {
+ ret_val = e1000_poll_fiber_serdes_link_generic(hw);
+ } else {
+ hw_dbg(hw, "No signal detected\n");
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_config_collision_dist - Configure collision distance
+ * @hw: pointer to the HW structure
+ *
+ * Configures the collision distance to the default value and is used
+ * during link setup. Currently no func pointer exists and all
+ * implementations are handled in the generic version of this function.
+ **/
+void e1000e_config_collision_dist(struct e1000_hw *hw)
+{
+ u32 tctl;
+
+ tctl = er32(TCTL);
+
+ tctl &= ~E1000_TCTL_COLD;
+ tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+ ew32(TCTL, tctl);
+ e1e_flush();
+}
+
+/**
+ * e1000e_set_fc_watermarks - Set flow control high/low watermarks
+ * @hw: pointer to the HW structure
+ *
+ * Sets the flow control high/low threshold (watermark) registers. If
+ * flow control XON frame transmission is enabled, then set XON frame
+ * tansmission as well.
+ **/
+s32 e1000e_set_fc_watermarks(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 fcrtl = 0, fcrth = 0;
+
+ /* Set the flow control receive threshold registers. Normally,
+ * these registers will be set to a default threshold that may be
+ * adjusted later by the driver's runtime code. However, if the
+ * ability to transmit pause frames is not enabled, then these
+ * registers will be set to 0.
+ */
+ if (mac->fc & e1000_fc_tx_pause) {
+ /* We need to set up the Receive Threshold high and low water
+ * marks as well as (optionally) enabling the transmission of
+ * XON frames.
+ */
+ fcrtl = mac->fc_low_water;
+ fcrtl |= E1000_FCRTL_XONE;
+ fcrth = mac->fc_high_water;
+ }
+ ew32(FCRTL, fcrtl);
+ ew32(FCRTH, fcrth);
+
+ return 0;
+}
+
+/**
+ * e1000e_force_mac_fc - Force the MAC's flow control settings
+ * @hw: pointer to the HW structure
+ *
+ * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the
+ * device control register to reflect the adapter settings. TFCE and RFCE
+ * need to be explicitly set by software when a copper PHY is used because
+ * autonegotiation is managed by the PHY rather than the MAC. Software must
+ * also configure these bits when link is forced on a fiber connection.
+ **/
+s32 e1000e_force_mac_fc(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 ctrl;
+
+ ctrl = er32(CTRL);
+
+ /* Because we didn't get link via the internal auto-negotiation
+ * mechanism (we either forced link or we got link via PHY
+ * auto-neg), we have to manually enable/disable transmit an
+ * receive flow control.
+ *
+ * The "Case" statement below enables/disable flow control
+ * according to the "mac->fc" parameter.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause
+ * frames but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * frames but we do not receive pause frames).
+ * 3: Both Rx and TX flow control (symmetric) is enabled.
+ * other: No other values should be possible at this point.
+ */
+ hw_dbg(hw, "mac->fc = %u\n", mac->fc);
+
+ switch (mac->fc) {
+ case e1000_fc_none:
+ ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+ break;
+ case e1000_fc_rx_pause:
+ ctrl &= (~E1000_CTRL_TFCE);
+ ctrl |= E1000_CTRL_RFCE;
+ break;
+ case e1000_fc_tx_pause:
+ ctrl &= (~E1000_CTRL_RFCE);
+ ctrl |= E1000_CTRL_TFCE;
+ break;
+ case e1000_fc_full:
+ ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+ break;
+ default:
+ hw_dbg(hw, "Flow control param set incorrectly\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ ew32(CTRL, ctrl);
+
+ return 0;
+}
+
+/**
+ * e1000e_config_fc_after_link_up - Configures flow control after link
+ * @hw: pointer to the HW structure
+ *
+ * Checks the status of auto-negotiation after link up to ensure that the
+ * speed and duplex were not forced. If the link needed to be forced, then
+ * flow control needs to be forced also. If auto-negotiation is enabled
+ * and did not fail, then we configure flow control based on our link
+ * partner.
+ **/
+s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ s32 ret_val = 0;
+ u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
+ u16 speed, duplex;
+
+ /* Check for the case where we have fiber media and auto-neg failed
+ * so we had to force link. In this case, we need to force the
+ * configuration of the MAC to match the "fc" parameter.
+ */
+ if (mac->autoneg_failed) {
+ if (hw->media_type == e1000_media_type_fiber ||
+ hw->media_type == e1000_media_type_internal_serdes)
+ ret_val = e1000e_force_mac_fc(hw);
+ } else {
+ if (hw->media_type == e1000_media_type_copper)
+ ret_val = e1000e_force_mac_fc(hw);
+ }
+
+ if (ret_val) {
+ hw_dbg(hw, "Error forcing flow control settings\n");
+ return ret_val;
+ }
+
+ /* Check for the case where we have copper media and auto-neg is
+ * enabled. In this case, we need to check and see if Auto-Neg
+ * has completed, and if so, how the PHY and link partner has
+ * flow control configured.
+ */
+ if ((hw->media_type == e1000_media_type_copper) && mac->autoneg) {
+ /* Read the MII Status Register and check to see if AutoNeg
+ * has completed. We read this twice because this reg has
+ * some "sticky" (latched) bits.
+ */
+ ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
+ if (ret_val)
+ return ret_val;
+
+ if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+ hw_dbg(hw, "Copper PHY and Auto Neg "
+ "has not completed.\n");
+ return ret_val;
+ }
+
+ /* The AutoNeg process has completed, so we now need to
+ * read both the Auto Negotiation Advertisement
+ * Register (Address 4) and the Auto_Negotiation Base
+ * Page Ability Register (Address 5) to determine how
+ * flow control was negotiated.
+ */
+ ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1e_rphy(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg);
+ if (ret_val)
+ return ret_val;
+
+ /* Two bits in the Auto Negotiation Advertisement Register
+ * (Address 4) and two bits in the Auto Negotiation Base
+ * Page Ability Register (Address 5) determine flow control
+ * for both the PHY and the link partner. The following
+ * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+ * 1999, describes these PAUSE resolution bits and how flow
+ * control is determined based upon these settings.
+ * NOTE: DC = Don't Care
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+ *-------|---------|-------|---------|--------------------
+ * 0 | 0 | DC | DC | e1000_fc_none
+ * 0 | 1 | 0 | DC | e1000_fc_none
+ * 0 | 1 | 1 | 0 | e1000_fc_none
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ * 1 | 0 | 0 | DC | e1000_fc_none
+ * 1 | DC | 1 | DC | e1000_fc_full
+ * 1 | 1 | 0 | 0 | e1000_fc_none
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ *
+ */
+ /* Are both PAUSE bits set to 1? If so, this implies
+ * Symmetric Flow Control is enabled at both ends. The
+ * ASM_DIR bits are irrelevant per the spec.
+ *
+ * For Symmetric Flow Control:
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | DC | 1 | DC | E1000_fc_full
+ *
+ */
+ if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+ /* Now we need to check if the user selected RX ONLY
+ * of pause frames. In this case, we had to advertise
+ * FULL flow control because we could not advertise RX
+ * ONLY. Hence, we must now check to see if we need to
+ * turn OFF the TRANSMISSION of PAUSE frames.
+ */
+ if (mac->original_fc == e1000_fc_full) {
+ mac->fc = e1000_fc_full;
+ hw_dbg(hw, "Flow Control = FULL.\r\n");
+ } else {
+ mac->fc = e1000_fc_rx_pause;
+ hw_dbg(hw, "Flow Control = "
+ "RX PAUSE frames only.\r\n");
+ }
+ }
+ /* For receiving PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ *
+ */
+ else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ mac->fc = e1000_fc_tx_pause;
+ hw_dbg(hw, "Flow Control = TX PAUSE frames only.\r\n");
+ }
+ /* For transmitting PAUSE frames ONLY.
+ *
+ * LOCAL DEVICE | LINK PARTNER
+ * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+ *-------|---------|-------|---------|--------------------
+ * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ *
+ */
+ else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ mac->fc = e1000_fc_rx_pause;
+ hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
+ }
+ /* Per the IEEE spec, at this point flow control should be
+ * disabled. However, we want to consider that we could
+ * be connected to a legacy switch that doesn't advertise
+ * desired flow control, but can be forced on the link
+ * partner. So if we advertised no flow control, that is
+ * what we will resolve to. If we advertised some kind of
+ * receive capability (Rx Pause Only or Full Flow Control)
+ * and the link partner advertised none, we will configure
+ * ourselves to enable Rx Flow Control only. We can do
+ * this safely for two reasons: If the link partner really
+ * didn't want flow control enabled, and we enable Rx, no
+ * harm done since we won't be receiving any PAUSE frames
+ * anyway. If the intent on the link partner was to have
+ * flow control enabled, then by us enabling RX only, we
+ * can at least receive pause frames and process them.
+ * This is a good idea because in most cases, since we are
+ * predominantly a server NIC, more times than not we will
+ * be asked to delay transmission of packets than asking
+ * our link partner to pause transmission of frames.
+ */
+ else if ((mac->original_fc == e1000_fc_none) ||
+ (mac->original_fc == e1000_fc_tx_pause)) {
+ mac->fc = e1000_fc_none;
+ hw_dbg(hw, "Flow Control = NONE.\r\n");
+ } else {
+ mac->fc = e1000_fc_rx_pause;
+ hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
+ }
+
+ /* Now we need to do one last check... If we auto-
+ * negotiated to HALF DUPLEX, flow control should not be
+ * enabled per IEEE 802.3 spec.
+ */
+ ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
+ if (ret_val) {
+ hw_dbg(hw, "Error getting link speed and duplex\n");
+ return ret_val;
+ }
+
+ if (duplex == HALF_DUPLEX)
+ mac->fc = e1000_fc_none;
+
+ /* Now we call a subroutine to actually force the MAC
+ * controller to use the correct flow control settings.
+ */
+ ret_val = e1000e_force_mac_fc(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error forcing flow control settings\n");
+ return ret_val;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_get_speed_and_duplex_copper - Retreive current speed/duplex
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * Read the status register for the current speed/duplex and store the current
+ * speed and duplex for copper connections.
+ **/
+s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex)
+{
+ u32 status;
+
+ status = er32(STATUS);
+ if (status & E1000_STATUS_SPEED_1000) {
+ *speed = SPEED_1000;
+ hw_dbg(hw, "1000 Mbs, ");
+ } else if (status & E1000_STATUS_SPEED_100) {
+ *speed = SPEED_100;
+ hw_dbg(hw, "100 Mbs, ");
+ } else {
+ *speed = SPEED_10;
+ hw_dbg(hw, "10 Mbs, ");
+ }
+
+ if (status & E1000_STATUS_FD) {
+ *duplex = FULL_DUPLEX;
+ hw_dbg(hw, "Full Duplex\n");
+ } else {
+ *duplex = HALF_DUPLEX;
+ hw_dbg(hw, "Half Duplex\n");
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_get_speed_and_duplex_fiber_serdes - Retreive current speed/duplex
+ * @hw: pointer to the HW structure
+ * @speed: stores the current speed
+ * @duplex: stores the current duplex
+ *
+ * Sets the speed and duplex to gigabit full duplex (the only possible option)
+ * for fiber/serdes links.
+ **/
+s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex)
+{
+ *speed = SPEED_1000;
+ *duplex = FULL_DUPLEX;
+
+ return 0;
+}
+
+/**
+ * e1000e_get_hw_semaphore - Acquire hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Acquire the HW semaphore to access the PHY or NVM
+ **/
+s32 e1000e_get_hw_semaphore(struct e1000_hw *hw)
+{
+ u32 swsm;
+ s32 timeout = hw->nvm.word_size + 1;
+ s32 i = 0;
+
+ /* Get the SW semaphore */
+ while (i < timeout) {
+ swsm = er32(SWSM);
+ if (!(swsm & E1000_SWSM_SMBI))
+ break;
+
+ udelay(50);
+ i++;
+ }
+
+ if (i == timeout) {
+ hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n");
+ return -E1000_ERR_NVM;
+ }
+
+ /* Get the FW semaphore. */
+ for (i = 0; i < timeout; i++) {
+ swsm = er32(SWSM);
+ ew32(SWSM, swsm | E1000_SWSM_SWESMBI);
+
+ /* Semaphore acquired if bit latched */
+ if (er32(SWSM) & E1000_SWSM_SWESMBI)
+ break;
+
+ udelay(50);
+ }
+
+ if (i == timeout) {
+ /* Release semaphores */
+ e1000e_put_hw_semaphore(hw);
+ hw_dbg(hw, "Driver can't access the NVM\n");
+ return -E1000_ERR_NVM;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_put_hw_semaphore - Release hardware semaphore
+ * @hw: pointer to the HW structure
+ *
+ * Release hardware semaphore used to access the PHY or NVM
+ **/
+void e1000e_put_hw_semaphore(struct e1000_hw *hw)
+{
+ u32 swsm;
+
+ swsm = er32(SWSM);
+ swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+ ew32(SWSM, swsm);
+}
+
+/**
+ * e1000e_get_auto_rd_done - Check for auto read completion
+ * @hw: pointer to the HW structure
+ *
+ * Check EEPROM for Auto Read done bit.
+ **/
+s32 e1000e_get_auto_rd_done(struct e1000_hw *hw)
+{
+ s32 i = 0;
+
+ while (i < AUTO_READ_DONE_TIMEOUT) {
+ if (er32(EECD) & E1000_EECD_AUTO_RD)
+ break;
+ msleep(1);
+ i++;
+ }
+
+ if (i == AUTO_READ_DONE_TIMEOUT) {
+ hw_dbg(hw, "Auto read by HW from NVM has not completed.\n");
+ return -E1000_ERR_RESET;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_valid_led_default - Verify a valid default LED config
+ * @hw: pointer to the HW structure
+ * @data: pointer to the NVM (EEPROM)
+ *
+ * Read the EEPROM for the current default LED configuration. If the
+ * LED configuration is not valid, set to a valid LED configuration.
+ **/
+s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data)
+{
+ s32 ret_val;
+
+ ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+
+ if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
+ *data = ID_LED_DEFAULT;
+
+ return 0;
+}
+
+/**
+ * e1000e_id_led_init -
+ * @hw: pointer to the HW structure
+ *
+ **/
+s32 e1000e_id_led_init(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ s32 ret_val;
+ const u32 ledctl_mask = 0x000000FF;
+ const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+ const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+ u16 data, i, temp;
+ const u16 led_mask = 0x0F;
+
+ ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+ if (ret_val)
+ return ret_val;
+
+ mac->ledctl_default = er32(LEDCTL);
+ mac->ledctl_mode1 = mac->ledctl_default;
+ mac->ledctl_mode2 = mac->ledctl_default;
+
+ for (i = 0; i < 4; i++) {
+ temp = (data >> (i << 2)) & led_mask;
+ switch (temp) {
+ case ID_LED_ON1_DEF2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_ON1_OFF2:
+ mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode1 |= ledctl_on << (i << 3);
+ break;
+ case ID_LED_OFF1_DEF2:
+ case ID_LED_OFF1_ON2:
+ case ID_LED_OFF1_OFF2:
+ mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode1 |= ledctl_off << (i << 3);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ switch (temp) {
+ case ID_LED_DEF1_ON2:
+ case ID_LED_ON1_ON2:
+ case ID_LED_OFF1_ON2:
+ mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode2 |= ledctl_on << (i << 3);
+ break;
+ case ID_LED_DEF1_OFF2:
+ case ID_LED_ON1_OFF2:
+ case ID_LED_OFF1_OFF2:
+ mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+ mac->ledctl_mode2 |= ledctl_off << (i << 3);
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_cleanup_led_generic - Set LED config to default operation
+ * @hw: pointer to the HW structure
+ *
+ * Remove the current LED configuration and set the LED configuration
+ * to the default value, saved from the EEPROM.
+ **/
+s32 e1000e_cleanup_led_generic(struct e1000_hw *hw)
+{
+ ew32(LEDCTL, hw->mac.ledctl_default);
+ return 0;
+}
+
+/**
+ * e1000e_blink_led - Blink LED
+ * @hw: pointer to the HW structure
+ *
+ * Blink the led's which are set to be on.
+ **/
+s32 e1000e_blink_led(struct e1000_hw *hw)
+{
+ u32 ledctl_blink = 0;
+ u32 i;
+
+ if (hw->media_type == e1000_media_type_fiber) {
+ /* always blink LED0 for PCI-E fiber */
+ ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+ (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+ } else {
+ /* set the blink bit for each LED that's "on" (0x0E)
+ * in ledctl_mode2 */
+ ledctl_blink = hw->mac.ledctl_mode2;
+ for (i = 0; i < 4; i++)
+ if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+ E1000_LEDCTL_MODE_LED_ON)
+ ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
+ (i * 8));
+ }
+
+ ew32(LEDCTL, ledctl_blink);
+
+ return 0;
+}
+
+/**
+ * e1000e_led_on_generic - Turn LED on
+ * @hw: pointer to the HW structure
+ *
+ * Turn LED on.
+ **/
+s32 e1000e_led_on_generic(struct e1000_hw *hw)
+{
+ u32 ctrl;
+
+ switch (hw->media_type) {
+ case e1000_media_type_fiber:
+ ctrl = er32(CTRL);
+ ctrl &= ~E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ ew32(CTRL, ctrl);
+ break;
+ case e1000_media_type_copper:
+ ew32(LEDCTL, hw->mac.ledctl_mode2);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_led_off_generic - Turn LED off
+ * @hw: pointer to the HW structure
+ *
+ * Turn LED off.
+ **/
+s32 e1000e_led_off_generic(struct e1000_hw *hw)
+{
+ u32 ctrl;
+
+ switch (hw->media_type) {
+ case e1000_media_type_fiber:
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_SWDPIN0;
+ ctrl |= E1000_CTRL_SWDPIO0;
+ ew32(CTRL, ctrl);
+ break;
+ case e1000_media_type_copper:
+ ew32(LEDCTL, hw->mac.ledctl_mode1);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_set_pcie_no_snoop - Set PCI-express capabilities
+ * @hw: pointer to the HW structure
+ * @no_snoop: bitmap of snoop events
+ *
+ * Set the PCI-express register to snoop for events enabled in 'no_snoop'.
+ **/
+void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop)
+{
+ u32 gcr;
+
+ if (no_snoop) {
+ gcr = er32(GCR);
+ gcr &= ~(PCIE_NO_SNOOP_ALL);
+ gcr |= no_snoop;
+ ew32(GCR, gcr);
+ }
+}
+
+/**
+ * e1000e_disable_pcie_master - Disables PCI-express master access
+ * @hw: pointer to the HW structure
+ *
+ * Returns 0 if successful, else returns -10
+ * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not casued
+ * the master requests to be disabled.
+ *
+ * Disables PCI-Express master access and verifies there are no pending
+ * requests.
+ **/
+s32 e1000e_disable_pcie_master(struct e1000_hw *hw)
+{
+ u32 ctrl;
+ s32 timeout = MASTER_DISABLE_TIMEOUT;
+
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+ ew32(CTRL, ctrl);
+
+ while (timeout) {
+ if (!(er32(STATUS) &
+ E1000_STATUS_GIO_MASTER_ENABLE))
+ break;
+ udelay(100);
+ timeout--;
+ }
+
+ if (!timeout) {
+ hw_dbg(hw, "Master requests are pending.\n");
+ return -E1000_ERR_MASTER_REQUESTS_PENDING;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_reset_adaptive - Reset Adaptive Interframe Spacing
+ * @hw: pointer to the HW structure
+ *
+ * Reset the Adaptive Interframe Spacing throttle to default values.
+ **/
+void e1000e_reset_adaptive(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+
+ mac->current_ifs_val = 0;
+ mac->ifs_min_val = IFS_MIN;
+ mac->ifs_max_val = IFS_MAX;
+ mac->ifs_step_size = IFS_STEP;
+ mac->ifs_ratio = IFS_RATIO;
+
+ mac->in_ifs_mode = 0;
+ ew32(AIT, 0);
+}
+
+/**
+ * e1000e_update_adaptive - Update Adaptive Interframe Spacing
+ * @hw: pointer to the HW structure
+ *
+ * Update the Adaptive Interframe Spacing Throttle value based on the
+ * time between transmitted packets and time between collisions.
+ **/
+void e1000e_update_adaptive(struct e1000_hw *hw)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+
+ if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
+ if (mac->tx_packet_delta > MIN_NUM_XMITS) {
+ mac->in_ifs_mode = 1;
+ if (mac->current_ifs_val < mac->ifs_max_val) {
+ if (!mac->current_ifs_val)
+ mac->current_ifs_val = mac->ifs_min_val;
+ else
+ mac->current_ifs_val +=
+ mac->ifs_step_size;
+ ew32(AIT,
+ mac->current_ifs_val);
+ }
+ }
+ } else {
+ if (mac->in_ifs_mode &&
+ (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
+ mac->current_ifs_val = 0;
+ mac->in_ifs_mode = 0;
+ ew32(AIT, 0);
+ }
+ }
+}
+
+/**
+ * e1000_raise_eec_clk - Raise EEPROM clock
+ * @hw: pointer to the HW structure
+ * @eecd: pointer to the EEPROM
+ *
+ * Enable/Raise the EEPROM clock bit.
+ **/
+static void e1000_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+ *eecd = *eecd | E1000_EECD_SK;
+ ew32(EECD, *eecd);
+ e1e_flush();
+ udelay(hw->nvm.delay_usec);
+}
+
+/**
+ * e1000_lower_eec_clk - Lower EEPROM clock
+ * @hw: pointer to the HW structure
+ * @eecd: pointer to the EEPROM
+ *
+ * Clear/Lower the EEPROM clock bit.
+ **/
+static void e1000_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+ *eecd = *eecd & ~E1000_EECD_SK;
+ ew32(EECD, *eecd);
+ e1e_flush();
+ udelay(hw->nvm.delay_usec);
+}
+
+/**
+ * e1000_shift_out_eec_bits - Shift data bits our to the EEPROM
+ * @hw: pointer to the HW structure
+ * @data: data to send to the EEPROM
+ * @count: number of bits to shift out
+ *
+ * We need to shift 'count' bits out to the EEPROM. So, the value in the
+ * "data" parameter will be shifted out to the EEPROM one bit at a time.
+ * In order to do this, "data" must be broken down into bits.
+ **/
+static void e1000_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 eecd = er32(EECD);
+ u32 mask;
+
+ mask = 0x01 << (count - 1);
+ if (nvm->type == e1000_nvm_eeprom_spi)
+ eecd |= E1000_EECD_DO;
+
+ do {
+ eecd &= ~E1000_EECD_DI;
+
+ if (data & mask)
+ eecd |= E1000_EECD_DI;
+
+ ew32(EECD, eecd);
+ e1e_flush();
+
+ udelay(nvm->delay_usec);
+
+ e1000_raise_eec_clk(hw, &eecd);
+ e1000_lower_eec_clk(hw, &eecd);
+
+ mask >>= 1;
+ } while (mask);
+
+ eecd &= ~E1000_EECD_DI;
+ ew32(EECD, eecd);
+}
+
+/**
+ * e1000_shift_in_eec_bits - Shift data bits in from the EEPROM
+ * @hw: pointer to the HW structure
+ * @count: number of bits to shift in
+ *
+ * In order to read a register from the EEPROM, we need to shift 'count' bits
+ * in from the EEPROM. Bits are "shifted in" by raising the clock input to
+ * the EEPROM (setting the SK bit), and then reading the value of the data out
+ * "DO" bit. During this "shifting in" process the data in "DI" bit should
+ * always be clear.
+ **/
+static u16 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
+{
+ u32 eecd;
+ u32 i;
+ u16 data;
+
+ eecd = er32(EECD);
+
+ eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+ data = 0;
+
+ for (i = 0; i < count; i++) {
+ data <<= 1;
+ e1000_raise_eec_clk(hw, &eecd);
+
+ eecd = er32(EECD);
+
+ eecd &= ~E1000_EECD_DI;
+ if (eecd & E1000_EECD_DO)
+ data |= 1;
+
+ e1000_lower_eec_clk(hw, &eecd);
+ }
+
+ return data;
+}
+
+/**
+ * e1000e_poll_eerd_eewr_done - Poll for EEPROM read/write completion
+ * @hw: pointer to the HW structure
+ * @ee_reg: EEPROM flag for polling
+ *
+ * Polls the EEPROM status bit for either read or write completion based
+ * upon the value of 'ee_reg'.
+ **/
+s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
+{
+ u32 attempts = 100000;
+ u32 i, reg = 0;
+
+ for (i = 0; i < attempts; i++) {
+ if (ee_reg == E1000_NVM_POLL_READ)
+ reg = er32(EERD);
+ else
+ reg = er32(EEWR);
+
+ if (reg & E1000_NVM_RW_REG_DONE)
+ return 0;
+
+ udelay(5);
+ }
+
+ return -E1000_ERR_NVM;
+}
+
+/**
+ * e1000e_acquire_nvm - Generic request for access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ * Return successful if access grant bit set, else clear the request for
+ * EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+s32 e1000e_acquire_nvm(struct e1000_hw *hw)
+{
+ u32 eecd = er32(EECD);
+ s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
+
+ ew32(EECD, eecd | E1000_EECD_REQ);
+ eecd = er32(EECD);
+
+ while (timeout) {
+ if (eecd & E1000_EECD_GNT)
+ break;
+ udelay(5);
+ eecd = er32(EECD);
+ timeout--;
+ }
+
+ if (!timeout) {
+ eecd &= ~E1000_EECD_REQ;
+ ew32(EECD, eecd);
+ hw_dbg(hw, "Could not acquire NVM grant\n");
+ return -E1000_ERR_NVM;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_standby_nvm - Return EEPROM to standby state
+ * @hw: pointer to the HW structure
+ *
+ * Return the EEPROM to a standby state.
+ **/
+static void e1000_standby_nvm(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 eecd = er32(EECD);
+
+ if (nvm->type == e1000_nvm_eeprom_spi) {
+ /* Toggle CS to flush commands */
+ eecd |= E1000_EECD_CS;
+ ew32(EECD, eecd);
+ e1e_flush();
+ udelay(nvm->delay_usec);
+ eecd &= ~E1000_EECD_CS;
+ ew32(EECD, eecd);
+ e1e_flush();
+ udelay(nvm->delay_usec);
+ }
+}
+
+/**
+ * e1000_stop_nvm - Terminate EEPROM command
+ * @hw: pointer to the HW structure
+ *
+ * Terminates the current command by inverting the EEPROM's chip select pin.
+ **/
+static void e1000_stop_nvm(struct e1000_hw *hw)
+{
+ u32 eecd;
+
+ eecd = er32(EECD);
+ if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+ /* Pull CS high */
+ eecd |= E1000_EECD_CS;
+ e1000_lower_eec_clk(hw, &eecd);
+ }
+}
+
+/**
+ * e1000e_release_nvm - Release exclusive access to EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+void e1000e_release_nvm(struct e1000_hw *hw)
+{
+ u32 eecd;
+
+ e1000_stop_nvm(hw);
+
+ eecd = er32(EECD);
+ eecd &= ~E1000_EECD_REQ;
+ ew32(EECD, eecd);
+}
+
+/**
+ * e1000_ready_nvm_eeprom - Prepares EEPROM for read/write
+ * @hw: pointer to the HW structure
+ *
+ * Setups the EEPROM for reading and writing.
+ **/
+static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 eecd = er32(EECD);
+ u16 timeout = 0;
+ u8 spi_stat_reg;
+
+ if (nvm->type == e1000_nvm_eeprom_spi) {
+ /* Clear SK and CS */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ ew32(EECD, eecd);
+ udelay(1);
+ timeout = NVM_MAX_RETRY_SPI;
+
+ /* Read "Status Register" repeatedly until the LSB is cleared.
+ * The EEPROM will signal that the command has been completed
+ * by clearing bit 0 of the internal status register. If it's
+ * not cleared within 'timeout', then error out. */
+ while (timeout) {
+ e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
+ hw->nvm.opcode_bits);
+ spi_stat_reg = (u8)e1000_shift_in_eec_bits(hw, 8);
+ if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
+ break;
+
+ udelay(5);
+ e1000_standby_nvm(hw);
+ timeout--;
+ }
+
+ if (!timeout) {
+ hw_dbg(hw, "SPI NVM Status error\n");
+ return -E1000_ERR_NVM;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_read_nvm_spi - Read EEPROM's using SPI
+ * @hw: pointer to the HW structure
+ * @offset: offset of word in the EEPROM to read
+ * @words: number of words to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM.
+ **/
+s32 e1000e_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 i = 0;
+ s32 ret_val;
+ u16 word_in;
+ u8 read_opcode = NVM_READ_OPCODE_SPI;
+
+ /* A check for invalid values: offset too large, too many words,
+ * and not enough words. */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+ return -E1000_ERR_NVM;
+ }
+
+ ret_val = nvm->ops.acquire_nvm(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_ready_nvm_eeprom(hw);
+ if (ret_val) {
+ nvm->ops.release_nvm(hw);
+ return ret_val;
+ }
+
+ e1000_standby_nvm(hw);
+
+ if ((nvm->address_bits == 8) && (offset >= 128))
+ read_opcode |= NVM_A8_OPCODE_SPI;
+
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
+ e1000_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits);
+
+ /* Read the data. SPI NVMs increment the address with each byte
+ * read and will roll over if reading beyond the end. This allows
+ * us to read the whole NVM from any offset */
+ for (i = 0; i < words; i++) {
+ word_in = e1000_shift_in_eec_bits(hw, 16);
+ data[i] = (word_in >> 8) | (word_in << 8);
+ }
+
+ nvm->ops.release_nvm(hw);
+ return 0;
+}
+
+/**
+ * e1000e_read_nvm_eerd - Reads EEPROM using EERD register
+ * @hw: pointer to the HW structure
+ * @offset: offset of word in the EEPROM to read
+ * @words: number of words to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ u32 i, eerd = 0;
+ s32 ret_val = 0;
+
+ /* A check for invalid values: offset too large, too many words,
+ * and not enough words. */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+ return -E1000_ERR_NVM;
+ }
+
+ for (i = 0; i < words; i++) {
+ eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
+ E1000_NVM_RW_REG_START;
+
+ ew32(EERD, eerd);
+ ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
+ if (ret_val)
+ break;
+
+ data[i] = (er32(EERD) >>
+ E1000_NVM_RW_REG_DATA);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_write_nvm_spi - Write to EEPROM using SPI
+ * @hw: pointer to the HW structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of words to write
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * Writes data to EEPROM at offset using SPI interface.
+ *
+ * If e1000e_update_nvm_checksum is not called after this function , the
+ * EEPROM will most likley contain an invalid checksum.
+ **/
+s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+ struct e1000_nvm_info *nvm = &hw->nvm;
+ s32 ret_val;
+ u16 widx = 0;
+
+ /* A check for invalid values: offset too large, too many words,
+ * and not enough words. */
+ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+ (words == 0)) {
+ hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+ return -E1000_ERR_NVM;
+ }
+
+ ret_val = nvm->ops.acquire_nvm(hw);
+ if (ret_val)
+ return ret_val;
+
+ msleep(10);
+
+ while (widx < words) {
+ u8 write_opcode = NVM_WRITE_OPCODE_SPI;
+
+ ret_val = e1000_ready_nvm_eeprom(hw);
+ if (ret_val) {
+ nvm->ops.release_nvm(hw);
+ return ret_val;
+ }
+
+ e1000_standby_nvm(hw);
+
+ /* Send the WRITE ENABLE command (8 bit opcode) */
+ e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
+ nvm->opcode_bits);
+
+ e1000_standby_nvm(hw);
+
+ /* Some SPI eeproms use the 8th address bit embedded in the
+ * opcode */
+ if ((nvm->address_bits == 8) && (offset >= 128))
+ write_opcode |= NVM_A8_OPCODE_SPI;
+
+ /* Send the Write command (8-bit opcode + addr) */
+ e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
+ e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
+ nvm->address_bits);
+
+ /* Loop to allow for up to whole page write of eeprom */
+ while (widx < words) {
+ u16 word_out = data[widx];
+ word_out = (word_out >> 8) | (word_out << 8);
+ e1000_shift_out_eec_bits(hw, word_out, 16);
+ widx++;
+
+ if ((((offset + widx) * 2) % nvm->page_size) == 0) {
+ e1000_standby_nvm(hw);
+ break;
+ }
+ }
+ }
+
+ msleep(10);
+ return 0;
+}
+
+/**
+ * e1000e_read_mac_addr - Read device MAC address
+ * @hw: pointer to the HW structure
+ *
+ * Reads the device MAC address from the EEPROM and stores the value.
+ * Since devices with two ports use the same EEPROM, we increment the
+ * last bit in the MAC address for the second port.
+ **/
+s32 e1000e_read_mac_addr(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 offset, nvm_data, i;
+
+ for (i = 0; i < ETH_ALEN; i += 2) {
+ offset = i >> 1;
+ ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+ hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
+ hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
+ }
+
+ /* Flip last bit of mac address if we're on second port */
+ if (hw->bus.func == E1000_FUNC_1)
+ hw->mac.perm_addr[5] ^= 1;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+ return 0;
+}
+
+/**
+ * e1000e_validate_nvm_checksum_generic - Validate EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ * and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 checksum = 0;
+ u16 i, nvm_data;
+
+ for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+ ret_val = e1000_read_nvm(hw, i, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+ checksum += nvm_data;
+ }
+
+ if (checksum != (u16) NVM_SUM) {
+ hw_dbg(hw, "NVM Checksum Invalid\n");
+ return -E1000_ERR_NVM;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_update_nvm_checksum_generic - Update EEPROM checksum
+ * @hw: pointer to the HW structure
+ *
+ * Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ * up to the checksum. Then calculates the EEPROM checksum and writes the
+ * value to the EEPROM.
+ **/
+s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 checksum = 0;
+ u16 i, nvm_data;
+
+ for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+ ret_val = e1000_read_nvm(hw, i, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error while updating checksum.\n");
+ return ret_val;
+ }
+ checksum += nvm_data;
+ }
+ checksum = (u16) NVM_SUM - checksum;
+ ret_val = e1000_write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum);
+ if (ret_val)
+ hw_dbg(hw, "NVM Write Error while updating checksum.\n");
+
+ return ret_val;
+}
+
+/**
+ * e1000e_reload_nvm - Reloads EEPROM
+ * @hw: pointer to the HW structure
+ *
+ * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
+ * extended control register.
+ **/
+void e1000e_reload_nvm(struct e1000_hw *hw)
+{
+ u32 ctrl_ext;
+
+ udelay(10);
+ ctrl_ext = er32(CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ ew32(CTRL_EXT, ctrl_ext);
+ e1e_flush();
+}
+
+/**
+ * e1000_calculate_checksum - Calculate checksum for buffer
+ * @buffer: pointer to EEPROM
+ * @length: size of EEPROM to calculate a checksum for
+ *
+ * Calculates the checksum for some buffer on a specified length. The
+ * checksum calculated is returned.
+ **/
+static u8 e1000_calculate_checksum(u8 *buffer, u32 length)
+{
+ u32 i;
+ u8 sum = 0;
+
+ if (!buffer)
+ return 0;
+
+ for (i = 0; i < length; i++)
+ sum += buffer[i];
+
+ return (u8) (0 - sum);
+}
+
+/**
+ * e1000_mng_enable_host_if - Checks host interface is enabled
+ * @hw: pointer to the HW structure
+ *
+ * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
+ *
+ * This function checks whether the HOST IF is enabled for command operaton
+ * and also checks whether the previous command is completed. It busy waits
+ * in case of previous command is not completed.
+ **/
+static s32 e1000_mng_enable_host_if(struct e1000_hw *hw)
+{
+ u32 hicr;
+ u8 i;
+
+ /* Check that the host interface is enabled. */
+ hicr = er32(HICR);
+ if ((hicr & E1000_HICR_EN) == 0) {
+ hw_dbg(hw, "E1000_HOST_EN bit disabled.\n");
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
+ }
+ /* check the previous command is completed */
+ for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+ hicr = er32(HICR);
+ if (!(hicr & E1000_HICR_C))
+ break;
+ mdelay(1);
+ }
+
+ if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
+ hw_dbg(hw, "Previous command timeout failed .\n");
+ return -E1000_ERR_HOST_INTERFACE_COMMAND;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_check_mng_mode - check managament mode
+ * @hw: pointer to the HW structure
+ *
+ * Reads the firmware semaphore register and returns true (>0) if
+ * manageability is enabled, else false (0).
+ **/
+bool e1000e_check_mng_mode(struct e1000_hw *hw)
+{
+ u32 fwsm = er32(FWSM);
+
+ return (fwsm & E1000_FWSM_MODE_MASK) == hw->mac.ops.mng_mode_enab;
+}
+
+/**
+ * e1000e_enable_tx_pkt_filtering - Enable packet filtering on TX
+ * @hw: pointer to the HW structure
+ *
+ * Enables packet filtering on transmit packets if manageability is enabled
+ * and host interface is enabled.
+ **/
+bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw)
+{
+ struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
+ u32 *buffer = (u32 *)&hw->mng_cookie;
+ u32 offset;
+ s32 ret_val, hdr_csum, csum;
+ u8 i, len;
+
+ /* No manageability, no filtering */
+ if (!e1000e_check_mng_mode(hw)) {
+ hw->mac.tx_pkt_filtering = 0;
+ return 0;
+ }
+
+ /* If we can't read from the host interface for whatever
+ * reason, disable filtering.
+ */
+ ret_val = e1000_mng_enable_host_if(hw);
+ if (ret_val != 0) {
+ hw->mac.tx_pkt_filtering = 0;
+ return ret_val;
+ }
+
+ /* Read in the header. Length and offset are in dwords. */
+ len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
+ offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
+ for (i = 0; i < len; i++)
+ *(buffer + i) = E1000_READ_REG_ARRAY(hw, E1000_HOST_IF, offset + i);
+ hdr_csum = hdr->checksum;
+ hdr->checksum = 0;
+ csum = e1000_calculate_checksum((u8 *)hdr,
+ E1000_MNG_DHCP_COOKIE_LENGTH);
+ /* If either the checksums or signature don't match, then
+ * the cookie area isn't considered valid, in which case we
+ * take the safe route of assuming Tx filtering is enabled.
+ */
+ if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) {
+ hw->mac.tx_pkt_filtering = 1;
+ return 1;
+ }
+
+ /* Cookie area is valid, make the final check for filtering. */
+ if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) {
+ hw->mac.tx_pkt_filtering = 0;
+ return 0;
+ }
+
+ hw->mac.tx_pkt_filtering = 1;
+ return 1;
+}
+
+/**
+ * e1000_mng_write_cmd_header - Writes manageability command header
+ * @hw: pointer to the HW structure
+ * @hdr: pointer to the host interface command header
+ *
+ * Writes the command header after does the checksum calculation.
+ **/
+static s32 e1000_mng_write_cmd_header(struct e1000_hw *hw,
+ struct e1000_host_mng_command_header *hdr)
+{
+ u16 i, length = sizeof(struct e1000_host_mng_command_header);
+
+ /* Write the whole command header structure with new checksum. */
+
+ hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
+
+ length >>= 2;
+ /* Write the relevant command block into the ram area. */
+ for (i = 0; i < length; i++) {
+ E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, i,
+ *((u32 *) hdr + i));
+ e1e_flush();
+ }
+
+ return 0;
+}
+
+/**
+ * e1000_mng_host_if_write - Writes to the manageability host interface
+ * @hw: pointer to the HW structure
+ * @buffer: pointer to the host interface buffer
+ * @length: size of the buffer
+ * @offset: location in the buffer to write to
+ * @sum: sum of the data (not checksum)
+ *
+ * This function writes the buffer content at the offset given on the host if.
+ * It also does alignment considerations to do the writes in most efficient
+ * way. Also fills up the sum of the buffer in *buffer parameter.
+ **/
+static s32 e1000_mng_host_if_write(struct e1000_hw *hw, u8 *buffer,
+ u16 length, u16 offset, u8 *sum)
+{
+ u8 *tmp;
+ u8 *bufptr = buffer;
+ u32 data = 0;
+ u16 remaining, i, j, prev_bytes;
+
+ /* sum = only sum of the data and it is not checksum */
+
+ if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH)
+ return -E1000_ERR_PARAM;
+
+ tmp = (u8 *)&data;
+ prev_bytes = offset & 0x3;
+ offset >>= 2;
+
+ if (prev_bytes) {
+ data = E1000_READ_REG_ARRAY(hw, E1000_HOST_IF, offset);
+ for (j = prev_bytes; j < sizeof(u32); j++) {
+ *(tmp + j) = *bufptr++;
+ *sum += *(tmp + j);
+ }
+ E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset, data);
+ length -= j - prev_bytes;
+ offset++;
+ }
+
+ remaining = length & 0x3;
+ length -= remaining;
+
+ /* Calculate length in DWORDs */
+ length >>= 2;
+
+ /* The device driver writes the relevant command block into the
+ * ram area. */
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < sizeof(u32); j++) {
+ *(tmp + j) = *bufptr++;
+ *sum += *(tmp + j);
+ }
+
+ E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset + i, data);
+ }
+ if (remaining) {
+ for (j = 0; j < sizeof(u32); j++) {
+ if (j < remaining)
+ *(tmp + j) = *bufptr++;
+ else
+ *(tmp + j) = 0;
+
+ *sum += *(tmp + j);
+ }
+ E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset + i, data);
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_mng_write_dhcp_info - Writes DHCP info to host interface
+ * @hw: pointer to the HW structure
+ * @buffer: pointer to the host interface
+ * @length: size of the buffer
+ *
+ * Writes the DHCP information to the host interface.
+ **/
+s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length)
+{
+ struct e1000_host_mng_command_header hdr;
+ s32 ret_val;
+ u32 hicr;
+
+ hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+ hdr.command_length = length;
+ hdr.reserved1 = 0;
+ hdr.reserved2 = 0;
+ hdr.checksum = 0;
+
+ /* Enable the host interface */
+ ret_val = e1000_mng_enable_host_if(hw);
+ if (ret_val)
+ return ret_val;
+
+ /* Populate the host interface with the contents of "buffer". */
+ ret_val = e1000_mng_host_if_write(hw, buffer, length,
+ sizeof(hdr), &(hdr.checksum));
+ if (ret_val)
+ return ret_val;
+
+ /* Write the manageability command header */
+ ret_val = e1000_mng_write_cmd_header(hw, &hdr);
+ if (ret_val)
+ return ret_val;
+
+ /* Tell the ARC a new command is pending. */
+ hicr = er32(HICR);
+ ew32(HICR, hicr | E1000_HICR_C);
+
+ return 0;
+}
+
+/**
+ * e1000e_enable_mng_pass_thru - Enable processing of ARP's
+ * @hw: pointer to the HW structure
+ *
+ * Verifies the hardware needs to allow ARPs to be processed by the host.
+ **/
+bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw)
+{
+ u32 manc;
+ u32 fwsm, factps;
+ bool ret_val = 0;
+
+ manc = er32(MANC);
+
+ if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+ !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+ return ret_val;
+
+ if (hw->mac.arc_subsystem_valid) {
+ fwsm = er32(FWSM);
+ factps = er32(FACTPS);
+
+ if (!(factps & E1000_FACTPS_MNGCG) &&
+ ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
+ ret_val = 1;
+ return ret_val;
+ }
+ } else {
+ if ((manc & E1000_MANC_SMBUS_EN) &&
+ !(manc & E1000_MANC_ASF_EN)) {
+ ret_val = 1;
+ return ret_val;
+ }
+ }
+
+ return ret_val;
+}
+
+s32 e1000e_read_part_num(struct e1000_hw *hw, u32 *part_num)
+{
+ s32 ret_val;
+ u16 nvm_data;
+
+ ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+ *part_num = (u32)(nvm_data << 16);
+
+ ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+ *part_num |= nvm_data;
+
+ return 0;
+}
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
new file mode 100644
index 00000000000..4fd2e23720b
--- /dev/null
+++ b/drivers/net/e1000e/netdev.c
@@ -0,0 +1,4157 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+
+#include "e1000.h"
+
+#define DRV_VERSION "0.2.0"
+char e1000e_driver_name[] = "e1000e";
+const char e1000e_driver_version[] = DRV_VERSION;
+
+static const struct e1000_info *e1000_info_tbl[] = {
+ [board_82571] = &e1000_82571_info,
+ [board_82572] = &e1000_82572_info,
+ [board_82573] = &e1000_82573_info,
+ [board_80003es2lan] = &e1000_es2_info,
+ [board_ich8lan] = &e1000_ich8_info,
+ [board_ich9lan] = &e1000_ich9_info,
+};
+
+#ifdef DEBUG
+/**
+ * e1000_get_hw_dev_name - return device name string
+ * used by hardware layer to print debugging information
+ **/
+char *e1000e_get_hw_dev_name(struct e1000_hw *hw)
+{
+ return hw->adapter->netdev->name;
+}
+#endif
+
+/**
+ * e1000_desc_unused - calculate if we have unused descriptors
+ **/
+static int e1000_desc_unused(struct e1000_ring *ring)
+{
+ if (ring->next_to_clean > ring->next_to_use)
+ return ring->next_to_clean - ring->next_to_use - 1;
+
+ return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+}
+
+/**
+ * e1000_receive_skb - helper function to handle rx indications
+ * @adapter: board private structure
+ * @status: descriptor status field as written by hardware
+ * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
+ * @skb: pointer to sk_buff to be indicated to stack
+ **/
+static void e1000_receive_skb(struct e1000_adapter *adapter,
+ struct net_device *netdev,
+ struct sk_buff *skb,
+ u8 status, u16 vlan)
+{
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ if (adapter->vlgrp && (status & E1000_RXD_STAT_VP))
+ vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
+ le16_to_cpu(vlan) &
+ E1000_RXD_SPC_VLAN_MASK);
+ else
+ netif_receive_skb(skb);
+
+ netdev->last_rx = jiffies;
+}
+
+/**
+ * e1000_rx_checksum - Receive Checksum Offload for 82543
+ * @adapter: board private structure
+ * @status_err: receive descriptor status and error fields
+ * @csum: receive descriptor csum field
+ * @sk_buff: socket buffer with received data
+ **/
+static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
+ u32 csum, struct sk_buff *skb)
+{
+ u16 status = (u16)status_err;
+ u8 errors = (u8)(status_err >> 24);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* Ignore Checksum bit is set */
+ if (status & E1000_RXD_STAT_IXSM)
+ return;
+ /* TCP/UDP checksum error bit is set */
+ if (errors & E1000_RXD_ERR_TCPE) {
+ /* let the stack verify checksum errors */
+ adapter->hw_csum_err++;
+ return;
+ }
+
+ /* TCP/UDP Checksum has not been calculated */
+ if (!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS)))
+ return;
+
+ /* It must be a TCP or UDP packet with a valid checksum */
+ if (status & E1000_RXD_STAT_TCPCS) {
+ /* TCP checksum is good */
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ /* IP fragment with UDP payload */
+ /* Hardware complements the payload checksum, so we undo it
+ * and then put the value in host order for further stack use.
+ */
+ csum = ntohl(csum ^ 0xFFFF);
+ skb->csum = csum;
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ }
+ adapter->hw_csum_good++;
+}
+
+/**
+ * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
+ * @adapter: address of board private structure
+ **/
+static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
+ int cleaned_count)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ struct e1000_rx_desc *rx_desc;
+ struct e1000_buffer *buffer_info;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN;
+
+ i = rx_ring->next_to_use;
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (cleaned_count--) {
+ skb = buffer_info->skb;
+ if (skb) {
+ skb_trim(skb, 0);
+ goto map_skb;
+ }
+
+ skb = netdev_alloc_skb(netdev, bufsz);
+ if (!skb) {
+ /* Better luck next round */
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
+
+ /* Make buffer alignment 2 beyond a 16 byte boundary
+ * this will result in a 16 byte aligned IP header after
+ * the 14 byte MAC header is removed
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ buffer_info->skb = skb;
+map_skb:
+ buffer_info->dma = pci_map_single(pdev, skb->data,
+ adapter->rx_buffer_len,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(buffer_info->dma)) {
+ dev_err(&pdev->dev, "RX DMA map failed\n");
+ adapter->rx_dma_failed++;
+ break;
+ }
+
+ rx_desc = E1000_RX_DESC(*rx_ring, i);
+ rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ buffer_info = &rx_ring->buffer_info[i];
+ }
+
+ if (rx_ring->next_to_use != i) {
+ rx_ring->next_to_use = i;
+ if (i-- == 0)
+ i = (rx_ring->count - 1);
+
+ /* Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64). */
+ wmb();
+ writel(i, adapter->hw.hw_addr + rx_ring->tail);
+ }
+}
+
+/**
+ * e1000_alloc_rx_buffers_ps - Replace used receive buffers; packet split
+ * @adapter: address of board private structure
+ **/
+static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
+ int cleaned_count)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ union e1000_rx_desc_packet_split *rx_desc;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ struct e1000_buffer *buffer_info;
+ struct e1000_ps_page *ps_page;
+ struct sk_buff *skb;
+ unsigned int i, j;
+
+ i = rx_ring->next_to_use;
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (cleaned_count--) {
+ rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
+
+ for (j = 0; j < PS_PAGE_BUFFERS; j++) {
+ ps_page = &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] = ~0;
+ continue;
+ }
+ if (!ps_page->page) {
+ ps_page->page = alloc_page(GFP_ATOMIC);
+ if (!ps_page->page) {
+ adapter->alloc_rx_buff_failed++;
+ goto no_buffers;
+ }
+ ps_page->dma = pci_map_page(pdev,
+ ps_page->page,
+ 0, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(ps_page->dma)) {
+ dev_err(&adapter->pdev->dev,
+ "RX DMA page map failed\n");
+ adapter->rx_dma_failed++;
+ goto no_buffers;
+ }
+ }
+ /*
+ * Refresh the desc even if buffer_addrs
+ * didn't change because each write-back
+ * erases this info.
+ */
+ rx_desc->read.buffer_addr[j+1] =
+ cpu_to_le64(ps_page->dma);
+ }
+
+ skb = netdev_alloc_skb(netdev,
+ adapter->rx_ps_bsize0 + NET_IP_ALIGN);
+
+ if (!skb) {
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
+
+ /* Make buffer alignment 2 beyond a 16 byte boundary
+ * this will result in a 16 byte aligned IP header after
+ * the 14 byte MAC header is removed
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ buffer_info->skb = skb;
+ buffer_info->dma = pci_map_single(pdev, skb->data,
+ adapter->rx_ps_bsize0,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(buffer_info->dma)) {
+ dev_err(&pdev->dev, "RX DMA map failed\n");
+ adapter->rx_dma_failed++;
+ /* cleanup skb */
+ dev_kfree_skb_any(skb);
+ buffer_info->skb = NULL;
+ break;
+ }
+
+ rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma);
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ buffer_info = &rx_ring->buffer_info[i];
+ }
+
+no_buffers:
+ if (rx_ring->next_to_use != i) {
+ rx_ring->next_to_use = i;
+
+ if (!(i--))
+ i = (rx_ring->count - 1);
+
+ /* Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64). */
+ wmb();
+ /* Hardware increments by 16 bytes, but packet split
+ * descriptors are 32 bytes...so we increment tail
+ * twice as much.
+ */
+ writel(i<<1, adapter->hw.hw_addr + rx_ring->tail);
+ }
+}
+
+/**
+ * e1000_clean_rx_irq - Send received data up the network stack; legacy
+ * @adapter: board private structure
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ **/
+static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
+ int *work_done, int work_to_do)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ struct e1000_rx_desc *rx_desc, *next_rxd;
+ struct e1000_buffer *buffer_info, *next_buffer;
+ u32 length;
+ unsigned int i;
+ int cleaned_count = 0;
+ bool cleaned = 0;
+ unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+
+ i = rx_ring->next_to_clean;
+ rx_desc = E1000_RX_DESC(*rx_ring, i);
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (rx_desc->status & E1000_RXD_STAT_DD) {
+ struct sk_buff *skb;
+ u8 status;
+
+ if (*work_done >= work_to_do)
+ break;
+ (*work_done)++;
+
+ status = rx_desc->status;
+ skb = buffer_info->skb;
+ buffer_info->skb = NULL;
+
+ prefetch(skb->data - NET_IP_ALIGN);
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ next_rxd = E1000_RX_DESC(*rx_ring, i);
+ prefetch(next_rxd);
+
+ next_buffer = &rx_ring->buffer_info[i];
+
+ cleaned = 1;
+ cleaned_count++;
+ pci_unmap_single(pdev,
+ buffer_info->dma,
+ adapter->rx_buffer_len,
+ PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
+
+ length = le16_to_cpu(rx_desc->length);
+
+ /* !EOP means multiple descriptors were used to store a single
+ * packet, also make sure the frame isn't just CRC only */
+ if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) {
+ /* All receives must fit into a single buffer */
+ ndev_dbg(netdev, "%s: Receive packet consumed "
+ "multiple buffers\n", netdev->name);
+ /* recycle */
+ buffer_info->skb = skb;
+ goto next_desc;
+ }
+
+ if (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
+ /* recycle */
+ buffer_info->skb = skb;
+ goto next_desc;
+ }
+
+ total_rx_bytes += length;
+ total_rx_packets++;
+
+ /* code added for copybreak, this should improve
+ * performance for small packets with large amounts
+ * of reassembly being done in the stack */
+ if (length < copybreak) {
+ struct sk_buff *new_skb =
+ netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
+ if (new_skb) {
+ skb_reserve(new_skb, NET_IP_ALIGN);
+ memcpy(new_skb->data - NET_IP_ALIGN,
+ skb->data - NET_IP_ALIGN,
+ length + NET_IP_ALIGN);
+ /* save the skb in buffer_info as good */
+ buffer_info->skb = skb;
+ skb = new_skb;
+ }
+ /* else just continue with the old one */
+ }
+ /* end copybreak code */
+ skb_put(skb, length);
+
+ /* Receive Checksum Offload */
+ e1000_rx_checksum(adapter,
+ (u32)(status) |
+ ((u32)(rx_desc->errors) << 24),
+ le16_to_cpu(rx_desc->csum), skb);
+
+ e1000_receive_skb(adapter, netdev, skb,status,rx_desc->special);
+
+next_desc:
+ rx_desc->status = 0;
+
+ /* return some buffers to hardware, one at a time is too slow */
+ if (cleaned_count >= E1000_RX_BUFFER_WRITE) {
+ adapter->alloc_rx_buf(adapter, cleaned_count);
+ cleaned_count = 0;
+ }
+
+ /* use prefetched values */
+ rx_desc = next_rxd;
+ buffer_info = next_buffer;
+ }
+ rx_ring->next_to_clean = i;
+
+ cleaned_count = e1000_desc_unused(rx_ring);
+ if (cleaned_count)
+ adapter->alloc_rx_buf(adapter, cleaned_count);
+
+ adapter->total_rx_packets += total_rx_packets;
+ adapter->total_rx_bytes += total_rx_bytes;
+ return cleaned;
+}
+
+static void e1000_put_txbuf(struct e1000_adapter *adapter,
+ struct e1000_buffer *buffer_info)
+{
+ if (buffer_info->dma) {
+ pci_unmap_page(adapter->pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_TODEVICE);
+ buffer_info->dma = 0;
+ }
+ if (buffer_info->skb) {
+ dev_kfree_skb_any(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+}
+
+static void e1000_print_tx_hang(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ unsigned int i = tx_ring->next_to_clean;
+ unsigned int eop = tx_ring->buffer_info[i].next_to_watch;
+ struct e1000_tx_desc *eop_desc = E1000_TX_DESC(*tx_ring, eop);
+ struct net_device *netdev = adapter->netdev;
+
+ /* detected Tx unit hang */
+ ndev_err(netdev,
+ "Detected Tx Unit Hang:\n"
+ " TDH <%x>\n"
+ " TDT <%x>\n"
+ " next_to_use <%x>\n"
+ " next_to_clean <%x>\n"
+ "buffer_info[next_to_clean]:\n"
+ " time_stamp <%lx>\n"
+ " next_to_watch <%x>\n"
+ " jiffies <%lx>\n"
+ " next_to_watch.status <%x>\n",
+ readl(adapter->hw.hw_addr + tx_ring->head),
+ readl(adapter->hw.hw_addr + tx_ring->tail),
+ tx_ring->next_to_use,
+ tx_ring->next_to_clean,
+ tx_ring->buffer_info[eop].time_stamp,
+ eop,
+ jiffies,
+ eop_desc->upper.fields.status);
+}
+
+/**
+ * e1000_clean_tx_irq - Reclaim resources after transmit completes
+ * @adapter: board private structure
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ **/
+static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_tx_desc *tx_desc, *eop_desc;
+ struct e1000_buffer *buffer_info;
+ unsigned int i, eop;
+ unsigned int count = 0;
+ bool cleaned = 0;
+ unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+
+ i = tx_ring->next_to_clean;
+ eop = tx_ring->buffer_info[i].next_to_watch;
+ eop_desc = E1000_TX_DESC(*tx_ring, eop);
+
+ while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
+ for (cleaned = 0; !cleaned; ) {
+ tx_desc = E1000_TX_DESC(*tx_ring, i);
+ buffer_info = &tx_ring->buffer_info[i];
+ cleaned = (i == eop);
+
+ if (cleaned) {
+ struct sk_buff *skb = buffer_info->skb;
+ unsigned int segs, bytecount;
+ segs = skb_shinfo(skb)->gso_segs ?: 1;
+ /* multiply data chunks by size of headers */
+ bytecount = ((segs - 1) * skb_headlen(skb)) +
+ skb->len;
+ total_tx_packets += segs;
+ total_tx_bytes += bytecount;
+ }
+
+ e1000_put_txbuf(adapter, buffer_info);
+ tx_desc->upper.data = 0;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ eop = tx_ring->buffer_info[i].next_to_watch;
+ eop_desc = E1000_TX_DESC(*tx_ring, eop);
+#define E1000_TX_WEIGHT 64
+ /* weight of a sort for tx, to avoid endless transmit cleanup */
+ if (count++ == E1000_TX_WEIGHT)
+ break;
+ }
+
+ tx_ring->next_to_clean = i;
+
+#define TX_WAKE_THRESHOLD 32
+ if (cleaned && netif_carrier_ok(netdev) &&
+ e1000_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD) {
+ /* Make sure that anybody stopping the queue after this
+ * sees the new next_to_clean.
+ */
+ smp_mb();
+
+ if (netif_queue_stopped(netdev) &&
+ !(test_bit(__E1000_DOWN, &adapter->state))) {
+ netif_wake_queue(netdev);
+ ++adapter->restart_queue;
+ }
+ }
+
+ if (adapter->detect_tx_hung) {
+ /* Detect a transmit hang in hardware, this serializes the
+ * check with the clearing of time_stamp and movement of i */
+ adapter->detect_tx_hung = 0;
+ if (tx_ring->buffer_info[eop].dma &&
+ time_after(jiffies, tx_ring->buffer_info[eop].time_stamp
+ + (adapter->tx_timeout_factor * HZ))
+ && !(er32(STATUS) &
+ E1000_STATUS_TXOFF)) {
+ e1000_print_tx_hang(adapter);
+ netif_stop_queue(netdev);
+ }
+ }
+ adapter->total_tx_bytes += total_tx_bytes;
+ adapter->total_tx_packets += total_tx_packets;
+ return cleaned;
+}
+
+/**
+ * e1000_clean_rx_irq_ps - Send received data up the network stack; packet split
+ * @adapter: board private structure
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ **/
+static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
+ int *work_done, int work_to_do)
+{
+ union e1000_rx_desc_packet_split *rx_desc, *next_rxd;
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ struct e1000_buffer *buffer_info, *next_buffer;
+ struct e1000_ps_page *ps_page;
+ struct sk_buff *skb;
+ unsigned int i, j;
+ u32 length, staterr;
+ int cleaned_count = 0;
+ bool cleaned = 0;
+ unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+
+ i = rx_ring->next_to_clean;
+ rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
+ staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (staterr & E1000_RXD_STAT_DD) {
+ if (*work_done >= work_to_do)
+ break;
+ (*work_done)++;
+ skb = buffer_info->skb;
+
+ /* in the packet split case this is header only */
+ prefetch(skb->data - NET_IP_ALIGN);
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ next_rxd = E1000_RX_DESC_PS(*rx_ring, i);
+ prefetch(next_rxd);
+
+ next_buffer = &rx_ring->buffer_info[i];
+
+ cleaned = 1;
+ cleaned_count++;
+ pci_unmap_single(pdev, buffer_info->dma,
+ adapter->rx_ps_bsize0,
+ PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
+
+ if (!(staterr & E1000_RXD_STAT_EOP)) {
+ ndev_dbg(netdev, "%s: Packet Split buffers didn't pick "
+ "up the full packet\n", netdev->name);
+ dev_kfree_skb_irq(skb);
+ goto next_desc;
+ }
+
+ if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) {
+ dev_kfree_skb_irq(skb);
+ goto next_desc;
+ }
+
+ length = le16_to_cpu(rx_desc->wb.middle.length0);
+
+ if (!length) {
+ ndev_dbg(netdev, "%s: Last part of the packet spanning"
+ " multiple descriptors\n", netdev->name);
+ dev_kfree_skb_irq(skb);
+ goto next_desc;
+ }
+
+ /* Good Receive */
+ skb_put(skb, length);
+
+ {
+ /* this looks ugly, but it seems compiler issues make it
+ more efficient than reusing j */
+ int l1 = le16_to_cpu(rx_desc->wb.upper.length[0]);
+
+ /* page alloc/put takes too long and effects small packet
+ * throughput, so unsplit small packets and save the alloc/put*/
+ if (l1 && (l1 <= copybreak) &&
+ ((length + l1) <= adapter->rx_ps_bsize0)) {
+ u8 *vaddr;
+
+ ps_page = &buffer_info->ps_pages[0];
+
+ /* there is no documentation about how to call
+ * kmap_atomic, so we can't hold the mapping
+ * very long */
+ pci_dma_sync_single_for_cpu(pdev, ps_page->dma,
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ vaddr = kmap_atomic(ps_page->page, KM_SKB_DATA_SOFTIRQ);
+ memcpy(skb_tail_pointer(skb), vaddr, l1);
+ kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ);
+ pci_dma_sync_single_for_device(pdev, ps_page->dma,
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
+
+ skb_put(skb, l1);
+ goto copydone;
+ } /* if */
+ }
+
+ for (j = 0; j < PS_PAGE_BUFFERS; j++) {
+ length = le16_to_cpu(rx_desc->wb.upper.length[j]);
+ if (!length)
+ break;
+
+ ps_page = &buffer_info->ps_pages[j];
+ pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ ps_page->dma = 0;
+ skb_fill_page_desc(skb, j, ps_page->page, 0, length);
+ ps_page->page = NULL;
+ skb->len += length;
+ skb->data_len += length;
+ skb->truesize += length;
+ }
+
+copydone:
+ total_rx_bytes += skb->len;
+ total_rx_packets++;
+
+ e1000_rx_checksum(adapter, staterr, le16_to_cpu(
+ rx_desc->wb.lower.hi_dword.csum_ip.csum), skb);
+
+ if (rx_desc->wb.upper.header_status &
+ cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP))
+ adapter->rx_hdr_split++;
+
+ e1000_receive_skb(adapter, netdev, skb,
+ staterr, rx_desc->wb.middle.vlan);
+
+next_desc:
+ rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF);
+ buffer_info->skb = NULL;
+
+ /* return some buffers to hardware, one at a time is too slow */
+ if (cleaned_count >= E1000_RX_BUFFER_WRITE) {
+ adapter->alloc_rx_buf(adapter, cleaned_count);
+ cleaned_count = 0;
+ }
+
+ /* use prefetched values */
+ rx_desc = next_rxd;
+ buffer_info = next_buffer;
+
+ staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
+ }
+ rx_ring->next_to_clean = i;
+
+ cleaned_count = e1000_desc_unused(rx_ring);
+ if (cleaned_count)
+ adapter->alloc_rx_buf(adapter, cleaned_count);
+
+ adapter->total_rx_packets += total_rx_packets;
+ adapter->total_rx_bytes += total_rx_bytes;
+ return cleaned;
+}
+
+/**
+ * e1000_clean_rx_ring - Free Rx Buffers per Queue
+ * @adapter: board private structure
+ **/
+static void e1000_clean_rx_ring(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ struct e1000_buffer *buffer_info;
+ struct e1000_ps_page *ps_page;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned int i, j;
+
+ /* Free all the Rx ring sk_buffs */
+ for (i = 0; i < rx_ring->count; i++) {
+ buffer_info = &rx_ring->buffer_info[i];
+ if (buffer_info->dma) {
+ if (adapter->clean_rx == e1000_clean_rx_irq)
+ pci_unmap_single(pdev, buffer_info->dma,
+ adapter->rx_buffer_len,
+ PCI_DMA_FROMDEVICE);
+ else if (adapter->clean_rx == e1000_clean_rx_irq_ps)
+ pci_unmap_single(pdev, buffer_info->dma,
+ adapter->rx_ps_bsize0,
+ PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
+ }
+
+ if (buffer_info->skb) {
+ dev_kfree_skb(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+
+ for (j = 0; j < PS_PAGE_BUFFERS; j++) {
+ ps_page = &buffer_info->ps_pages[j];
+ if (!ps_page->page)
+ break;
+ pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ ps_page->dma = 0;
+ put_page(ps_page->page);
+ ps_page->page = NULL;
+ }
+ }
+
+ /* there also may be some cached data from a chained receive */
+ if (rx_ring->rx_skb_top) {
+ dev_kfree_skb(rx_ring->rx_skb_top);
+ rx_ring->rx_skb_top = NULL;
+ }
+
+ /* Zero out the descriptor ring */
+ memset(rx_ring->desc, 0, rx_ring->size);
+
+ rx_ring->next_to_clean = 0;
+ rx_ring->next_to_use = 0;
+
+ writel(0, adapter->hw.hw_addr + rx_ring->head);
+ writel(0, adapter->hw.hw_addr + rx_ring->tail);
+}
+
+/**
+ * e1000_intr_msi - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ **/
+static irqreturn_t e1000_intr_msi(int irq, void *data)
+{
+ struct net_device *netdev = data;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 icr = er32(ICR);
+
+ /* read ICR disables interrupts using IAM, so keep up with our
+ * enable/disable accounting */
+ atomic_inc(&adapter->irq_sem);
+
+ if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+ hw->mac.get_link_status = 1;
+ /* ICH8 workaround-- Call gig speed drop workaround on cable
+ * disconnect (LSC) before accessing any PHY registers */
+ if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
+ (!(er32(STATUS) & E1000_STATUS_LU)))
+ e1000e_gig_downshift_workaround_ich8lan(hw);
+
+ /* 80003ES2LAN workaround-- For packet buffer work-around on
+ * link down event; disable receives here in the ISR and reset
+ * adapter in watchdog */
+ if (netif_carrier_ok(netdev) &&
+ adapter->flags & FLAG_RX_NEEDS_RESTART) {
+ /* disable receives */
+ u32 rctl = er32(RCTL);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+ }
+ /* guard against interrupt when we're going down */
+ if (!test_bit(__E1000_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer, jiffies + 1);
+ }
+
+ if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+ adapter->total_tx_bytes = 0;
+ adapter->total_tx_packets = 0;
+ adapter->total_rx_bytes = 0;
+ adapter->total_rx_packets = 0;
+ __netif_rx_schedule(netdev, &adapter->napi);
+ } else {
+ atomic_dec(&adapter->irq_sem);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * e1000_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ **/
+static irqreturn_t e1000_intr(int irq, void *data)
+{
+ struct net_device *netdev = data;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ u32 rctl, icr = er32(ICR);
+ if (!icr)
+ return IRQ_NONE; /* Not our interrupt */
+
+ /* IMS will not auto-mask if INT_ASSERTED is not set, and if it is
+ * not set, then the adapter didn't send an interrupt */
+ if (!(icr & E1000_ICR_INT_ASSERTED))
+ return IRQ_NONE;
+
+ /* Interrupt Auto-Mask...upon reading ICR,
+ * interrupts are masked. No need for the
+ * IMC write, but it does mean we should
+ * account for it ASAP. */
+ atomic_inc(&adapter->irq_sem);
+
+ if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+ hw->mac.get_link_status = 1;
+ /* ICH8 workaround-- Call gig speed drop workaround on cable
+ * disconnect (LSC) before accessing any PHY registers */
+ if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
+ (!(er32(STATUS) & E1000_STATUS_LU)))
+ e1000e_gig_downshift_workaround_ich8lan(hw);
+
+ /* 80003ES2LAN workaround--
+ * For packet buffer work-around on link down event;
+ * disable receives here in the ISR and
+ * reset adapter in watchdog
+ */
+ if (netif_carrier_ok(netdev) &&
+ (adapter->flags & FLAG_RX_NEEDS_RESTART)) {
+ /* disable receives */
+ rctl = er32(RCTL);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+ }
+ /* guard against interrupt when we're going down */
+ if (!test_bit(__E1000_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer, jiffies + 1);
+ }
+
+ if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+ adapter->total_tx_bytes = 0;
+ adapter->total_tx_packets = 0;
+ adapter->total_rx_bytes = 0;
+ adapter->total_rx_packets = 0;
+ __netif_rx_schedule(netdev, &adapter->napi);
+ } else {
+ atomic_dec(&adapter->irq_sem);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int e1000_request_irq(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ void (*handler) = &e1000_intr;
+ int irq_flags = IRQF_SHARED;
+ int err;
+
+ err = pci_enable_msi(adapter->pdev);
+ if (err) {
+ ndev_warn(netdev,
+ "Unable to allocate MSI interrupt Error: %d\n", err);
+ } else {
+ adapter->flags |= FLAG_MSI_ENABLED;
+ handler = &e1000_intr_msi;
+ irq_flags = 0;
+ }
+
+ err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,
+ netdev);
+ if (err) {
+ if (adapter->flags & FLAG_MSI_ENABLED)
+ pci_disable_msi(adapter->pdev);
+ ndev_err(netdev,
+ "Unable to allocate interrupt Error: %d\n", err);
+ }
+
+ return err;
+}
+
+static void e1000_free_irq(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ free_irq(adapter->pdev->irq, netdev);
+ if (adapter->flags & FLAG_MSI_ENABLED) {
+ pci_disable_msi(adapter->pdev);
+ adapter->flags &= ~FLAG_MSI_ENABLED;
+ }
+}
+
+/**
+ * e1000_irq_disable - Mask off interrupt generation on the NIC
+ **/
+static void e1000_irq_disable(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ atomic_inc(&adapter->irq_sem);
+ ew32(IMC, ~0);
+ e1e_flush();
+ synchronize_irq(adapter->pdev->irq);
+}
+
+/**
+ * e1000_irq_enable - Enable default interrupt generation settings
+ **/
+static void e1000_irq_enable(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (atomic_dec_and_test(&adapter->irq_sem)) {
+ ew32(IMS, IMS_ENABLE_MASK);
+ e1e_flush();
+ }
+}
+
+/**
+ * e1000_get_hw_control - get control of the h/w from f/w
+ * @adapter: address of board private structure
+ *
+ * e1000_get_hw_control sets {CTRL_EXT|FWSM}:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded. For AMT version (only with 82573)
+ * of the f/w this means that the network i/f is open.
+ **/
+static void e1000_get_hw_control(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl_ext;
+ u32 swsm;
+
+ /* Let firmware know the driver has taken over */
+ if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) {
+ swsm = er32(SWSM);
+ ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD);
+ } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) {
+ ctrl_ext = er32(CTRL_EXT);
+ ew32(CTRL_EXT,
+ ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+ }
+}
+
+/**
+ * e1000_release_hw_control - release control of the h/w to f/w
+ * @adapter: address of board private structure
+ *
+ * e1000_release_hw_control resets {CTRL_EXT|FWSM}:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that the
+ * driver is no longer loaded. For AMT version (only with 82573) i
+ * of the f/w this means that the network i/f is closed.
+ *
+ **/
+static void e1000_release_hw_control(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl_ext;
+ u32 swsm;
+
+ /* Let firmware taken over control of h/w */
+ if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) {
+ swsm = er32(SWSM);
+ ew32(SWSM, swsm & ~E1000_SWSM_DRV_LOAD);
+ } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) {
+ ctrl_ext = er32(CTRL_EXT);
+ ew32(CTRL_EXT,
+ ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
+ }
+}
+
+static void e1000_release_manageability(struct e1000_adapter *adapter)
+{
+ if (adapter->flags & FLAG_MNG_PT_ENABLED) {
+ struct e1000_hw *hw = &adapter->hw;
+
+ u32 manc = er32(MANC);
+
+ /* re-enable hardware interception of ARP */
+ manc |= E1000_MANC_ARP_EN;
+ manc &= ~E1000_MANC_EN_MNG2HOST;
+
+ /* don't explicitly have to mess with MANC2H since
+ * MANC has an enable disable that gates MANC2H */
+ ew32(MANC, manc);
+ }
+}
+
+/**
+ * @e1000_alloc_ring - allocate memory for a ring structure
+ **/
+static int e1000_alloc_ring_dma(struct e1000_adapter *adapter,
+ struct e1000_ring *ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma,
+ GFP_KERNEL);
+ if (!ring->desc)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * e1000e_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ **/
+int e1000e_setup_tx_resources(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ int err = -ENOMEM, size;
+
+ size = sizeof(struct e1000_buffer) * tx_ring->count;
+ tx_ring->buffer_info = vmalloc(size);
+ if (!tx_ring->buffer_info)
+ goto err;
+ memset(tx_ring->buffer_info, 0, size);
+
+ /* round up to nearest 4K */
+ tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
+ tx_ring->size = ALIGN(tx_ring->size, 4096);
+
+ err = e1000_alloc_ring_dma(adapter, tx_ring);
+ if (err)
+ goto err;
+
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+ spin_lock_init(&adapter->tx_queue_lock);
+
+ return 0;
+err:
+ vfree(tx_ring->buffer_info);
+ ndev_err(adapter->netdev,
+ "Unable to allocate memory for the transmit descriptor ring\n");
+ return err;
+}
+
+/**
+ * e1000e_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int e1000e_setup_rx_resources(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ struct e1000_buffer *buffer_info;
+ int i, size, desc_len, err = -ENOMEM;
+
+ size = sizeof(struct e1000_buffer) * rx_ring->count;
+ rx_ring->buffer_info = vmalloc(size);
+ if (!rx_ring->buffer_info)
+ goto err;
+ memset(rx_ring->buffer_info, 0, size);
+
+ for (i = 0; i < rx_ring->count; i++) {
+ buffer_info = &rx_ring->buffer_info[i];
+ buffer_info->ps_pages = kcalloc(PS_PAGE_BUFFERS,
+ sizeof(struct e1000_ps_page),
+ GFP_KERNEL);
+ if (!buffer_info->ps_pages)
+ goto err_pages;
+ }
+
+ desc_len = sizeof(union e1000_rx_desc_packet_split);
+
+ /* Round up to nearest 4K */
+ rx_ring->size = rx_ring->count * desc_len;
+ rx_ring->size = ALIGN(rx_ring->size, 4096);
+
+ err = e1000_alloc_ring_dma(adapter, rx_ring);
+ if (err)
+ goto err_pages;
+
+ rx_ring->next_to_clean = 0;
+ rx_ring->next_to_use = 0;
+ rx_ring->rx_skb_top = NULL;
+
+ return 0;
+
+err_pages:
+ for (i = 0; i < rx_ring->count; i++) {
+ buffer_info = &rx_ring->buffer_info[i];
+ kfree(buffer_info->ps_pages);
+ }
+err:
+ vfree(rx_ring->buffer_info);
+ ndev_err(adapter->netdev,
+ "Unable to allocate memory for the transmit descriptor ring\n");
+ return err;
+}
+
+/**
+ * e1000_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ **/
+static void e1000_clean_tx_ring(struct e1000_adapter *adapter)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_buffer *buffer_info;
+ unsigned long size;
+ unsigned int i;
+
+ for (i = 0; i < tx_ring->count; i++) {
+ buffer_info = &tx_ring->buffer_info[i];
+ e1000_put_txbuf(adapter, buffer_info);
+ }
+
+ size = sizeof(struct e1000_buffer) * tx_ring->count;
+ memset(tx_ring->buffer_info, 0, size);
+
+ memset(tx_ring->desc, 0, tx_ring->size);
+
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+
+ writel(0, adapter->hw.hw_addr + tx_ring->head);
+ writel(0, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+/**
+ * e1000e_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+void e1000e_free_tx_resources(struct e1000_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+
+ e1000_clean_tx_ring(adapter);
+
+ vfree(tx_ring->buffer_info);
+ tx_ring->buffer_info = NULL;
+
+ dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
+ tx_ring->dma);
+ tx_ring->desc = NULL;
+}
+
+/**
+ * e1000e_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+
+void e1000e_free_rx_resources(struct e1000_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ int i;
+
+ e1000_clean_rx_ring(adapter);
+
+ 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;
+
+ dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
+ rx_ring->dma);
+ rx_ring->desc = NULL;
+}
+
+/**
+ * e1000_update_itr - update the dynamic ITR value based on statistics
+ * Stores a new ITR value based on packets and byte
+ * counts during the last interrupt. The advantage of per interrupt
+ * computation is faster updates and more accurate ITR for the current
+ * traffic pattern. Constants in this function were computed
+ * based on theoretical maximum wire speed and thresholds were set based
+ * on testing data as well as attempting to minimize response time
+ * while increasing bulk throughput.
+ * this functionality is controlled by the InterruptThrottleRate module
+ * parameter (see e1000_param.c)
+ * @adapter: pointer to adapter
+ * @itr_setting: current adapter->itr
+ * @packets: the number of packets during this measurement interval
+ * @bytes: the number of bytes during this measurement interval
+ **/
+static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
+ u16 itr_setting, int packets,
+ int bytes)
+{
+ unsigned int retval = itr_setting;
+
+ if (packets == 0)
+ goto update_itr_done;
+
+ switch (itr_setting) {
+ case lowest_latency:
+ /* handle TSO and jumbo frames */
+ if (bytes/packets > 8000)
+ retval = bulk_latency;
+ else if ((packets < 5) && (bytes > 512)) {
+ retval = low_latency;
+ }
+ break;
+ case low_latency: /* 50 usec aka 20000 ints/s */
+ if (bytes > 10000) {
+ /* this if handles the TSO accounting */
+ if (bytes/packets > 8000) {
+ retval = bulk_latency;
+ } else if ((packets < 10) || ((bytes/packets) > 1200)) {
+ retval = bulk_latency;
+ } else if ((packets > 35)) {
+ retval = lowest_latency;
+ }
+ } else if (bytes/packets > 2000) {
+ retval = bulk_latency;
+ } else if (packets <= 2 && bytes < 512) {
+ retval = lowest_latency;
+ }
+ break;
+ case bulk_latency: /* 250 usec aka 4000 ints/s */
+ if (bytes > 25000) {
+ if (packets > 35) {
+ retval = low_latency;
+ }
+ } else if (bytes < 6000) {
+ retval = low_latency;
+ }
+ break;
+ }
+
+update_itr_done:
+ return retval;
+}
+
+static void e1000_set_itr(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u16 current_itr;
+ u32 new_itr = adapter->itr;
+
+ /* for non-gigabit speeds, just fix the interrupt rate at 4000 */
+ if (adapter->link_speed != SPEED_1000) {
+ current_itr = 0;
+ new_itr = 4000;
+ goto set_itr_now;
+ }
+
+ adapter->tx_itr = e1000_update_itr(adapter,
+ adapter->tx_itr,
+ adapter->total_tx_packets,
+ adapter->total_tx_bytes);
+ /* conservative mode (itr 3) eliminates the lowest_latency setting */
+ if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency)
+ adapter->tx_itr = low_latency;
+
+ adapter->rx_itr = e1000_update_itr(adapter,
+ adapter->rx_itr,
+ adapter->total_rx_packets,
+ adapter->total_rx_bytes);
+ /* conservative mode (itr 3) eliminates the lowest_latency setting */
+ if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency)
+ adapter->rx_itr = low_latency;
+
+ current_itr = max(adapter->rx_itr, adapter->tx_itr);
+
+ switch (current_itr) {
+ /* counts and packets in update_itr are dependent on these numbers */
+ case lowest_latency:
+ new_itr = 70000;
+ break;
+ case low_latency:
+ new_itr = 20000; /* aka hwitr = ~200 */
+ break;
+ case bulk_latency:
+ new_itr = 4000;
+ break;
+ default:
+ break;
+ }
+
+set_itr_now:
+ if (new_itr != adapter->itr) {
+ /* this attempts to bias the interrupt rate towards Bulk
+ * by adding intermediate steps when interrupt rate is
+ * increasing */
+ new_itr = new_itr > adapter->itr ?
+ min(adapter->itr + (new_itr >> 2), new_itr) :
+ new_itr;
+ adapter->itr = new_itr;
+ ew32(ITR, 1000000000 / (new_itr * 256));
+ }
+}
+
+/**
+ * e1000_clean - NAPI Rx polling callback
+ * @adapter: board private structure
+ **/
+static int e1000_clean(struct napi_struct *napi, int budget)
+{
+ struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
+ struct net_device *poll_dev = adapter->netdev;
+ int tx_cleaned = 0, work_done = 0;
+
+ /* Must NOT use netdev_priv macro here. */
+ adapter = poll_dev->priv;
+
+ /* Keep link state information with original netdev */
+ if (!netif_carrier_ok(poll_dev))
+ goto quit_polling;
+
+ /* e1000_clean is called per-cpu. This lock protects
+ * tx_ring from being cleaned by multiple cpus
+ * simultaneously. A failure obtaining the lock means
+ * tx_ring is currently being cleaned anyway. */
+ if (spin_trylock(&adapter->tx_queue_lock)) {
+ tx_cleaned = e1000_clean_tx_irq(adapter);
+ spin_unlock(&adapter->tx_queue_lock);
+ }
+
+ adapter->clean_rx(adapter, &work_done, budget);
+
+ /* If no Tx and not enough Rx work done, exit the polling mode */
+ if ((!tx_cleaned && (work_done < budget)) ||
+ !netif_running(poll_dev)) {
+quit_polling:
+ if (adapter->itr_setting & 3)
+ e1000_set_itr(adapter);
+ netif_rx_complete(poll_dev, napi);
+ e1000_irq_enable(adapter);
+ }
+
+ return work_done;
+}
+
+static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 vfta, index;
+
+ /* don't update vlan cookie if already programmed */
+ if ((adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+ (vid == adapter->mng_vlan_id))
+ return;
+ /* add VID to filter table */
+ index = (vid >> 5) & 0x7F;
+ vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index);
+ vfta |= (1 << (vid & 0x1F));
+ e1000e_write_vfta(hw, index, vfta);
+}
+
+static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 vfta, index;
+
+ e1000_irq_disable(adapter);
+ vlan_group_set_device(adapter->vlgrp, vid, NULL);
+ e1000_irq_enable(adapter);
+
+ if ((adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+ (vid == adapter->mng_vlan_id)) {
+ /* release control to f/w */
+ e1000_release_hw_control(adapter);
+ return;
+ }
+
+ /* remove VID from filter table */
+ index = (vid >> 5) & 0x7F;
+ vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index);
+ vfta &= ~(1 << (vid & 0x1F));
+ e1000e_write_vfta(hw, index, vfta);
+}
+
+static void e1000_update_mng_vlan(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ u16 vid = adapter->hw.mng_cookie.vlan_id;
+ u16 old_vid = adapter->mng_vlan_id;
+
+ if (!adapter->vlgrp)
+ return;
+
+ if (!vlan_group_get_device(adapter->vlgrp, vid)) {
+ adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
+ if (adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN) {
+ e1000_vlan_rx_add_vid(netdev, vid);
+ adapter->mng_vlan_id = vid;
+ }
+
+ if ((old_vid != (u16)E1000_MNG_VLAN_NONE) &&
+ (vid != old_vid) &&
+ !vlan_group_get_device(adapter->vlgrp, old_vid))
+ e1000_vlan_rx_kill_vid(netdev, old_vid);
+ } else {
+ adapter->mng_vlan_id = vid;
+ }
+}
+
+
+static void e1000_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *grp)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl, rctl;
+
+ e1000_irq_disable(adapter);
+ adapter->vlgrp = grp;
+
+ if (grp) {
+ /* enable VLAN tag insert/strip */
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_VME;
+ ew32(CTRL, ctrl);
+
+ if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) {
+ /* enable VLAN receive filtering */
+ rctl = er32(RCTL);
+ rctl |= E1000_RCTL_VFE;
+ rctl &= ~E1000_RCTL_CFIEN;
+ ew32(RCTL, rctl);
+ e1000_update_mng_vlan(adapter);
+ }
+ } else {
+ /* disable VLAN tag insert/strip */
+ ctrl = er32(CTRL);
+ ctrl &= ~E1000_CTRL_VME;
+ ew32(CTRL, ctrl);
+
+ if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) {
+ /* disable VLAN filtering */
+ rctl = er32(RCTL);
+ rctl &= ~E1000_RCTL_VFE;
+ ew32(RCTL, rctl);
+ if (adapter->mng_vlan_id !=
+ (u16)E1000_MNG_VLAN_NONE) {
+ e1000_vlan_rx_kill_vid(netdev,
+ adapter->mng_vlan_id);
+ adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
+ }
+ }
+ }
+
+ e1000_irq_enable(adapter);
+}
+
+static void e1000_restore_vlan(struct e1000_adapter *adapter)
+{
+ u16 vid;
+
+ e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+
+ if (!adapter->vlgrp)
+ return;
+
+ for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ if (!vlan_group_get_device(adapter->vlgrp, vid))
+ continue;
+ e1000_vlan_rx_add_vid(adapter->netdev, vid);
+ }
+}
+
+static void e1000_init_manageability(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 manc, manc2h;
+
+ if (!(adapter->flags & FLAG_MNG_PT_ENABLED))
+ return;
+
+ manc = er32(MANC);
+
+ /* disable hardware interception of ARP */
+ manc &= ~(E1000_MANC_ARP_EN);
+
+ /* enable receiving management packets to the host. this will probably
+ * generate destination unreachable messages from the host OS, but
+ * the packets will be handled on SMBUS */
+ manc |= E1000_MANC_EN_MNG2HOST;
+ manc2h = er32(MANC2H);
+#define E1000_MNG2HOST_PORT_623 (1 << 5)
+#define E1000_MNG2HOST_PORT_664 (1 << 6)
+ manc2h |= E1000_MNG2HOST_PORT_623;
+ manc2h |= E1000_MNG2HOST_PORT_664;
+ ew32(MANC2H, manc2h);
+ ew32(MANC, manc);
+}
+
+/**
+ * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void e1000_configure_tx(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ u64 tdba;
+ u32 tdlen, tctl, tipg, tarc;
+ u32 ipgr1, ipgr2;
+
+ /* Setup the HW Tx Head and Tail descriptor pointers */
+ tdba = tx_ring->dma;
+ tdlen = tx_ring->count * sizeof(struct e1000_tx_desc);
+ ew32(TDBAL, (tdba & DMA_32BIT_MASK));
+ ew32(TDBAH, (tdba >> 32));
+ ew32(TDLEN, tdlen);
+ ew32(TDH, 0);
+ ew32(TDT, 0);
+ tx_ring->head = E1000_TDH;
+ tx_ring->tail = E1000_TDT;
+
+ /* Set the default values for the Tx Inter Packet Gap timer */
+ tipg = DEFAULT_82543_TIPG_IPGT_COPPER; /* 8 */
+ ipgr1 = DEFAULT_82543_TIPG_IPGR1; /* 8 */
+ ipgr2 = DEFAULT_82543_TIPG_IPGR2; /* 6 */
+
+ if (adapter->flags & FLAG_TIPG_MEDIUM_FOR_80003ESLAN)
+ ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2; /* 7 */
+
+ tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT;
+ tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT;
+ ew32(TIPG, tipg);
+
+ /* Set the Tx Interrupt Delay register */
+ ew32(TIDV, adapter->tx_int_delay);
+ /* tx irq moderation */
+ ew32(TADV, adapter->tx_abs_int_delay);
+
+ /* Program the Transmit Control Register */
+ tctl = er32(TCTL);
+ tctl &= ~E1000_TCTL_CT;
+ tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
+ (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+ if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) {
+ tarc = er32(TARC0);
+ /* set the speed mode bit, we'll clear it if we're not at
+ * gigabit link later */
+#define SPEED_MODE_BIT (1 << 21)
+ tarc |= SPEED_MODE_BIT;
+ ew32(TARC0, tarc);
+ }
+
+ /* errata: program both queues to unweighted RR */
+ if (adapter->flags & FLAG_TARC_SET_BIT_ZERO) {
+ tarc = er32(TARC0);
+ tarc |= 1;
+ ew32(TARC0, tarc);
+ tarc = er32(TARC1);
+ tarc |= 1;
+ ew32(TARC1, tarc);
+ }
+
+ e1000e_config_collision_dist(hw);
+
+ /* Setup Transmit Descriptor Settings for eop descriptor */
+ adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;
+
+ /* only set IDE if we are delaying interrupts using the timers */
+ if (adapter->tx_int_delay)
+ adapter->txd_cmd |= E1000_TXD_CMD_IDE;
+
+ /* enable Report Status bit */
+ adapter->txd_cmd |= E1000_TXD_CMD_RS;
+
+ ew32(TCTL, tctl);
+
+ adapter->tx_queue_len = adapter->netdev->tx_queue_len;
+}
+
+/**
+ * e1000_setup_rctl - configure the receive control registers
+ * @adapter: Board private structure
+ **/
+#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
+ (((S) & (PAGE_SIZE - 1)) ? 1 : 0))
+static void e1000_setup_rctl(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 rctl, rfctl;
+ u32 psrctl = 0;
+ u32 pages = 0;
+
+ /* Program MC offset vector base */
+ rctl = er32(RCTL);
+ rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
+ rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
+ E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+ (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
+
+ /* Do not Store bad packets */
+ rctl &= ~E1000_RCTL_SBP;
+
+ /* Enable Long Packet receive */
+ if (adapter->netdev->mtu <= ETH_DATA_LEN)
+ rctl &= ~E1000_RCTL_LPE;
+ else
+ rctl |= E1000_RCTL_LPE;
+
+ /* Setup buffer sizes */
+ rctl &= ~E1000_RCTL_SZ_4096;
+ rctl |= E1000_RCTL_BSEX;
+ switch (adapter->rx_buffer_len) {
+ case 256:
+ rctl |= E1000_RCTL_SZ_256;
+ rctl &= ~E1000_RCTL_BSEX;
+ break;
+ case 512:
+ rctl |= E1000_RCTL_SZ_512;
+ rctl &= ~E1000_RCTL_BSEX;
+ break;
+ case 1024:
+ rctl |= E1000_RCTL_SZ_1024;
+ rctl &= ~E1000_RCTL_BSEX;
+ break;
+ case 2048:
+ default:
+ rctl |= E1000_RCTL_SZ_2048;
+ rctl &= ~E1000_RCTL_BSEX;
+ break;
+ case 4096:
+ rctl |= E1000_RCTL_SZ_4096;
+ break;
+ case 8192:
+ rctl |= E1000_RCTL_SZ_8192;
+ break;
+ case 16384:
+ rctl |= E1000_RCTL_SZ_16384;
+ break;
+ }
+
+ /*
+ * 82571 and greater support packet-split where the protocol
+ * header is placed in skb->data and the packet data is
+ * placed in pages hanging off of skb_shinfo(skb)->nr_frags.
+ * In the case of a non-split, skb->data is linearly filled,
+ * followed by the page buffers. Therefore, skb->data is
+ * sized to hold the largest protocol header.
+ *
+ * allocations using alloc_page take too long for regular MTU
+ * so only enable packet split for jumbo frames
+ *
+ * Using pages when the page size is greater than 16k wastes
+ * a lot of memory, since we allocate 3 pages at all times
+ * per packet.
+ */
+ adapter->rx_ps_pages = 0;
+ pages = PAGE_USE_COUNT(adapter->netdev->mtu);
+ if ((pages <= 3) && (PAGE_SIZE <= 16384) && (rctl & E1000_RCTL_LPE))
+ adapter->rx_ps_pages = pages;
+
+ if (adapter->rx_ps_pages) {
+ /* Configure extra packet-split registers */
+ rfctl = er32(RFCTL);
+ rfctl |= E1000_RFCTL_EXTEN;
+ /* disable packet split support for IPv6 extension headers,
+ * because some malformed IPv6 headers can hang the RX */
+ rfctl |= (E1000_RFCTL_IPV6_EX_DIS |
+ E1000_RFCTL_NEW_IPV6_EXT_DIS);
+
+ ew32(RFCTL, rfctl);
+
+ /* Enable Packet split descriptors */
+ rctl |= E1000_RCTL_DTYP_PS;
+
+ /* Enable hardware CRC frame stripping */
+ rctl |= E1000_RCTL_SECRC;
+
+ psrctl |= adapter->rx_ps_bsize0 >>
+ E1000_PSRCTL_BSIZE0_SHIFT;
+
+ switch (adapter->rx_ps_pages) {
+ case 3:
+ psrctl |= PAGE_SIZE <<
+ E1000_PSRCTL_BSIZE3_SHIFT;
+ case 2:
+ psrctl |= PAGE_SIZE <<
+ E1000_PSRCTL_BSIZE2_SHIFT;
+ case 1:
+ psrctl |= PAGE_SIZE >>
+ E1000_PSRCTL_BSIZE1_SHIFT;
+ break;
+ }
+
+ ew32(PSRCTL, psrctl);
+ }
+
+ ew32(RCTL, rctl);
+}
+
+/**
+ * e1000_configure_rx - Configure Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void e1000_configure_rx(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_ring *rx_ring = adapter->rx_ring;
+ u64 rdba;
+ u32 rdlen, rctl, rxcsum, ctrl_ext;
+
+ if (adapter->rx_ps_pages) {
+ /* this is a 32 byte descriptor */
+ rdlen = rx_ring->count *
+ sizeof(union e1000_rx_desc_packet_split);
+ adapter->clean_rx = e1000_clean_rx_irq_ps;
+ adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps;
+ } else {
+ rdlen = rx_ring->count *
+ sizeof(struct e1000_rx_desc);
+ adapter->clean_rx = e1000_clean_rx_irq;
+ adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
+ }
+
+ /* disable receives while setting up the descriptors */
+ rctl = er32(RCTL);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+ e1e_flush();
+ msleep(10);
+
+ /* set the Receive Delay Timer Register */
+ ew32(RDTR, adapter->rx_int_delay);
+
+ /* irq moderation */
+ ew32(RADV, adapter->rx_abs_int_delay);
+ if (adapter->itr_setting != 0)
+ ew32(ITR,
+ 1000000000 / (adapter->itr * 256));
+
+ ctrl_ext = er32(CTRL_EXT);
+ /* Reset delay timers after every interrupt */
+ ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR;
+ /* Auto-Mask interrupts upon ICR access */
+ ctrl_ext |= E1000_CTRL_EXT_IAME;
+ ew32(IAM, 0xffffffff);
+ ew32(CTRL_EXT, ctrl_ext);
+ e1e_flush();
+
+ /* Setup the HW Rx Head and Tail Descriptor Pointers and
+ * the Base and Length of the Rx Descriptor Ring */
+ rdba = rx_ring->dma;
+ ew32(RDBAL, (rdba & DMA_32BIT_MASK));
+ ew32(RDBAH, (rdba >> 32));
+ ew32(RDLEN, rdlen);
+ ew32(RDH, 0);
+ ew32(RDT, 0);
+ rx_ring->head = E1000_RDH;
+ rx_ring->tail = E1000_RDT;
+
+ /* Enable Receive Checksum Offload for TCP and UDP */
+ rxcsum = er32(RXCSUM);
+ if (adapter->flags & FLAG_RX_CSUM_ENABLED) {
+ rxcsum |= E1000_RXCSUM_TUOFL;
+
+ /* IPv4 payload checksum for UDP fragments must be
+ * used in conjunction with packet-split. */
+ if (adapter->rx_ps_pages)
+ rxcsum |= E1000_RXCSUM_IPPCSE;
+ } else {
+ rxcsum &= ~E1000_RXCSUM_TUOFL;
+ /* no need to clear IPPCSE as it defaults to 0 */
+ }
+ ew32(RXCSUM, rxcsum);
+
+ /* Enable early receives on supported devices, only takes effect when
+ * packet size is equal or larger than the specified value (in 8 byte
+ * units), e.g. using jumbo frames when setting to E1000_ERT_2048 */
+ if ((adapter->flags & FLAG_HAS_ERT) &&
+ (adapter->netdev->mtu > ETH_DATA_LEN))
+ ew32(ERT, E1000_ERT_2048);
+
+ /* Enable Receives */
+ ew32(RCTL, rctl);
+}
+
+/**
+ * e1000_mc_addr_list_update - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ * @rar_used_count: the first RAR register free to program
+ * @rar_count: total number of supported Receive Address Registers
+ *
+ * Updates the Receive Address Registers and Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ * The parameter rar_count will usually be hw->mac.rar_entry_count
+ * unless there are workarounds that change this. Currently no func pointer
+ * exists and all implementations are handled in the generic version of this
+ * function.
+ **/
+static void e1000_mc_addr_list_update(struct e1000_hw *hw, u8 *mc_addr_list,
+ u32 mc_addr_count, u32 rar_used_count,
+ u32 rar_count)
+{
+ hw->mac.ops.mc_addr_list_update(hw, mc_addr_list, mc_addr_count,
+ rar_used_count, rar_count);
+}
+
+/**
+ * e1000_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated. This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ **/
+static void e1000_set_multi(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ struct e1000_mac_info *mac = &hw->mac;
+ struct dev_mc_list *mc_ptr;
+ u8 *mta_list;
+ u32 rctl;
+ int i;
+
+ /* Check for Promiscuous and All Multicast modes */
+
+ rctl = er32(RCTL);
+
+ if (netdev->flags & IFF_PROMISC) {
+ rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+ } else if (netdev->flags & IFF_ALLMULTI) {
+ rctl |= E1000_RCTL_MPE;
+ rctl &= ~E1000_RCTL_UPE;
+ } else {
+ rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+ }
+
+ ew32(RCTL, rctl);
+
+ if (netdev->mc_count) {
+ mta_list = kmalloc(netdev->mc_count * 6, GFP_ATOMIC);
+ if (!mta_list)
+ return;
+
+ /* prepare a packed array of only addresses. */
+ mc_ptr = netdev->mc_list;
+
+ for (i = 0; i < netdev->mc_count; i++) {
+ if (!mc_ptr)
+ break;
+ memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr,
+ ETH_ALEN);
+ mc_ptr = mc_ptr->next;
+ }
+
+ e1000_mc_addr_list_update(hw, mta_list, i, 1,
+ mac->rar_entry_count);
+ kfree(mta_list);
+ } else {
+ /*
+ * if we're called from probe, we might not have
+ * anything to do here, so clear out the list
+ */
+ e1000_mc_addr_list_update(hw, NULL, 0, 1,
+ mac->rar_entry_count);
+ }
+}
+
+/**
+ * e1000_configure - configure the hardware for RX and TX
+ * @adapter: private board structure
+ **/
+static void e1000_configure(struct e1000_adapter *adapter)
+{
+ e1000_set_multi(adapter->netdev);
+
+ e1000_restore_vlan(adapter);
+ e1000_init_manageability(adapter);
+
+ e1000_configure_tx(adapter);
+ e1000_setup_rctl(adapter);
+ e1000_configure_rx(adapter);
+ adapter->alloc_rx_buf(adapter,
+ e1000_desc_unused(adapter->rx_ring));
+}
+
+/**
+ * e1000e_power_up_phy - restore link in case the phy was powered down
+ * @adapter: address of board private structure
+ *
+ * The phy may be powered down to save power and turn off link when the
+ * driver is unloaded and wake on lan is not enabled (among others)
+ * *** this routine MUST be followed by a call to e1000e_reset ***
+ **/
+void e1000e_power_up_phy(struct e1000_adapter *adapter)
+{
+ u16 mii_reg = 0;
+
+ /* Just clear the power down bit to wake the phy back up */
+ if (adapter->hw.media_type == e1000_media_type_copper) {
+ /* according to the manual, the phy will retain its
+ * settings across a power-down/up cycle */
+ e1e_rphy(&adapter->hw, PHY_CONTROL, &mii_reg);
+ mii_reg &= ~MII_CR_POWER_DOWN;
+ e1e_wphy(&adapter->hw, PHY_CONTROL, mii_reg);
+ }
+
+ adapter->hw.mac.ops.setup_link(&adapter->hw);
+}
+
+/**
+ * e1000_power_down_phy - Power down the PHY
+ *
+ * Power down the PHY so no link is implied when interface is down
+ * The PHY cannot be powered down is management or WoL is active
+ */
+static void e1000_power_down_phy(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u16 mii_reg;
+
+ /* WoL is enabled */
+ if (!adapter->wol)
+ return;
+
+ /* non-copper PHY? */
+ if (adapter->hw.media_type != e1000_media_type_copper)
+ return;
+
+ /* reset is blocked because of a SoL/IDER session */
+ if (e1000e_check_mng_mode(hw) ||
+ e1000_check_reset_block(hw))
+ return;
+
+ /* managebility (AMT) is enabled */
+ if (er32(MANC) & E1000_MANC_SMBUS_EN)
+ return;
+
+ /* power down the PHY */
+ e1e_rphy(hw, PHY_CONTROL, &mii_reg);
+ mii_reg |= MII_CR_POWER_DOWN;
+ e1e_wphy(hw, PHY_CONTROL, mii_reg);
+ mdelay(1);
+}
+
+/**
+ * e1000e_reset - bring the hardware into a known good state
+ *
+ * This function boots the hardware and enables some settings that
+ * require a configuration cycle of the hardware - those cannot be
+ * set/changed during runtime. After reset the device needs to be
+ * properly configured for rx, tx etc.
+ */
+void e1000e_reset(struct e1000_adapter *adapter)
+{
+ struct e1000_mac_info *mac = &adapter->hw.mac;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 tx_space, min_tx_space, min_rx_space;
+ u32 pba;
+ u16 hwm;
+
+ ew32(PBA, adapter->pba);
+
+ if (mac->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN ) {
+ /* To maintain wire speed transmits, the Tx FIFO should be
+ * large enough to accommodate two full transmit packets,
+ * rounded up to the next 1KB and expressed in KB. Likewise,
+ * the Rx FIFO should be large enough to accommodate at least
+ * one full receive packet and is similarly rounded up and
+ * expressed in KB. */
+ pba = er32(PBA);
+ /* upper 16 bits has Tx packet buffer allocation size in KB */
+ tx_space = pba >> 16;
+ /* 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
+ * but don't include ethernet FCS because hardware appends it */
+ min_tx_space = (mac->max_frame_size +
+ sizeof(struct e1000_tx_desc) -
+ ETH_FCS_LEN) * 2;
+ min_tx_space = ALIGN(min_tx_space, 1024);
+ min_tx_space >>= 10;
+ /* software strips receive CRC, so leave room for it */
+ min_rx_space = mac->max_frame_size;
+ min_rx_space = ALIGN(min_rx_space, 1024);
+ min_rx_space >>= 10;
+
+ /* If current Tx allocation is less than the min Tx FIFO size,
+ * and the min Tx FIFO size is less than the current Rx FIFO
+ * allocation, take space away from current Rx allocation */
+ if ((tx_space < min_tx_space) &&
+ ((min_tx_space - tx_space) < pba)) {
+ pba -= min_tx_space - tx_space;
+
+ /* if short on rx space, rx wins and must trump tx
+ * adjustment or use Early Receive if available */
+ if ((pba < min_rx_space) &&
+ (!(adapter->flags & FLAG_HAS_ERT)))
+ /* ERT enabled in e1000_configure_rx */
+ pba = min_rx_space;
+ }
+
+ ew32(PBA, pba);
+ }
+
+
+ /* flow control settings */
+ /* The high water mark must be low enough to fit one full frame
+ * (or the size used for early receive) above it in the Rx FIFO.
+ * Set it to the lower of:
+ * - 90% of the Rx FIFO size, and
+ * - the full Rx FIFO size minus the early receive size (for parts
+ * with ERT support assuming ERT set to E1000_ERT_2048), or
+ * - the full Rx FIFO size minus one full frame */
+ if (adapter->flags & FLAG_HAS_ERT)
+ hwm = min(((adapter->pba << 10) * 9 / 10),
+ ((adapter->pba << 10) - (E1000_ERT_2048 << 3)));
+ else
+ hwm = min(((adapter->pba << 10) * 9 / 10),
+ ((adapter->pba << 10) - mac->max_frame_size));
+
+ mac->fc_high_water = hwm & 0xFFF8; /* 8-byte granularity */
+ mac->fc_low_water = mac->fc_high_water - 8;
+
+ if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME)
+ mac->fc_pause_time = 0xFFFF;
+ else
+ mac->fc_pause_time = E1000_FC_PAUSE_TIME;
+ mac->fc = mac->original_fc;
+
+ /* Allow time for pending master requests to run */
+ mac->ops.reset_hw(hw);
+ ew32(WUC, 0);
+
+ if (mac->ops.init_hw(hw))
+ ndev_err(adapter->netdev, "Hardware Error\n");
+
+ e1000_update_mng_vlan(adapter);
+
+ /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
+ ew32(VET, ETH_P_8021Q);
+
+ e1000e_reset_adaptive(hw);
+ e1000_get_phy_info(hw);
+
+ if (!(adapter->flags & FLAG_SMART_POWER_DOWN)) {
+ u16 phy_data = 0;
+ /* speed up time to link by disabling smart power down, ignore
+ * the return value of this function because there is nothing
+ * different we would do if it failed */
+ e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
+ phy_data &= ~IGP02E1000_PM_SPD;
+ e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
+ }
+
+ e1000_release_manageability(adapter);
+}
+
+int e1000e_up(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ /* hardware has been reset, we need to reload some things */
+ e1000_configure(adapter);
+
+ clear_bit(__E1000_DOWN, &adapter->state);
+
+ napi_enable(&adapter->napi);
+ e1000_irq_enable(adapter);
+
+ /* fire a link change interrupt to start the watchdog */
+ ew32(ICS, E1000_ICS_LSC);
+ return 0;
+}
+
+void e1000e_down(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 tctl, rctl;
+
+ /* signal that we're down so the interrupt handler does not
+ * reschedule our watchdog timer */
+ set_bit(__E1000_DOWN, &adapter->state);
+
+ /* disable receives in the hardware */
+ rctl = er32(RCTL);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+ /* flush and sleep below */
+
+ netif_stop_queue(netdev);
+
+ /* disable transmits in the hardware */
+ tctl = er32(TCTL);
+ tctl &= ~E1000_TCTL_EN;
+ ew32(TCTL, tctl);
+ /* flush both disables and wait for them to finish */
+ e1e_flush();
+ msleep(10);
+
+ napi_disable(&adapter->napi);
+ e1000_irq_disable(adapter);
+
+ del_timer_sync(&adapter->watchdog_timer);
+ del_timer_sync(&adapter->phy_info_timer);
+
+ netdev->tx_queue_len = adapter->tx_queue_len;
+ netif_carrier_off(netdev);
+ adapter->link_speed = 0;
+ adapter->link_duplex = 0;
+
+ e1000e_reset(adapter);
+ e1000_clean_tx_ring(adapter);
+ e1000_clean_rx_ring(adapter);
+
+ /*
+ * TODO: for power management, we could drop the link and
+ * pci_disable_device here.
+ */
+}
+
+void e1000e_reinit_locked(struct e1000_adapter *adapter)
+{
+ might_sleep();
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+ msleep(1);
+ e1000e_down(adapter);
+ e1000e_up(adapter);
+ clear_bit(__E1000_RESETTING, &adapter->state);
+}
+
+/**
+ * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * e1000_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+
+ adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN;
+ adapter->rx_ps_bsize0 = 128;
+ hw->mac.max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+ hw->mac.min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+ adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+ if (!adapter->tx_ring)
+ goto err;
+
+ adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+ if (!adapter->rx_ring)
+ goto err;
+
+ spin_lock_init(&adapter->tx_queue_lock);
+
+ /* Explicitly disable IRQ since the NIC can be in any state. */
+ atomic_set(&adapter->irq_sem, 0);
+ e1000_irq_disable(adapter);
+
+ spin_lock_init(&adapter->stats_lock);
+
+ set_bit(__E1000_DOWN, &adapter->state);
+ return 0;
+
+err:
+ ndev_err(netdev, "Unable to allocate memory for queues\n");
+ kfree(adapter->rx_ring);
+ kfree(adapter->tx_ring);
+ return -ENOMEM;
+}
+
+/**
+ * e1000_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP). At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int e1000_open(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ int err;
+
+ /* disallow open during test */
+ if (test_bit(__E1000_TESTING, &adapter->state))
+ return -EBUSY;
+
+ /* allocate transmit descriptors */
+ err = e1000e_setup_tx_resources(adapter);
+ if (err)
+ goto err_setup_tx;
+
+ /* allocate receive descriptors */
+ err = e1000e_setup_rx_resources(adapter);
+ if (err)
+ goto err_setup_rx;
+
+ e1000e_power_up_phy(adapter);
+
+ adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
+ if ((adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN))
+ e1000_update_mng_vlan(adapter);
+
+ /* If AMT is enabled, let the firmware know that the network
+ * interface is now open */
+ if ((adapter->flags & FLAG_HAS_AMT) &&
+ e1000e_check_mng_mode(&adapter->hw))
+ e1000_get_hw_control(adapter);
+
+ /* before we allocate an interrupt, we must be ready to handle it.
+ * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
+ * as soon as we call pci_request_irq, so we have to setup our
+ * clean_rx handler before we do so. */
+ e1000_configure(adapter);
+
+ err = e1000_request_irq(adapter);
+ if (err)
+ goto err_req_irq;
+
+ /* From here on the code is the same as e1000e_up() */
+ clear_bit(__E1000_DOWN, &adapter->state);
+
+ napi_enable(&adapter->napi);
+
+ e1000_irq_enable(adapter);
+
+ /* fire a link status change interrupt to start the watchdog */
+ ew32(ICS, E1000_ICS_LSC);
+
+ return 0;
+
+err_req_irq:
+ e1000_release_hw_control(adapter);
+ e1000_power_down_phy(adapter);
+ e1000e_free_rx_resources(adapter);
+err_setup_rx:
+ e1000e_free_tx_resources(adapter);
+err_setup_tx:
+ e1000e_reset(adapter);
+
+ return err;
+}
+
+/**
+ * e1000_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS. The hardware is still under the drivers control, but
+ * needs to be disabled. A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static int e1000_close(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
+ e1000e_down(adapter);
+ e1000_power_down_phy(adapter);
+ e1000_free_irq(adapter);
+
+ e1000e_free_tx_resources(adapter);
+ e1000e_free_rx_resources(adapter);
+
+ /* kill manageability vlan ID if supported, but not if a vlan with
+ * the same ID is registered on the host OS (let 8021q kill it) */
+ if ((adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+ !(adapter->vlgrp &&
+ vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id)))
+ e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+
+ /* If AMT is enabled, let the firmware know that the network
+ * interface is now closed */
+ if ((adapter->flags & FLAG_HAS_AMT) &&
+ e1000e_check_mng_mode(&adapter->hw))
+ e1000_release_hw_control(adapter);
+
+ return 0;
+}
+/**
+ * e1000_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int e1000_set_mac(struct net_device *netdev, void *p)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len);
+
+ e1000e_rar_set(&adapter->hw, adapter->hw.mac.addr, 0);
+
+ if (adapter->flags & FLAG_RESET_OVERWRITES_LAA) {
+ /* activate the work around */
+ e1000e_set_laa_state_82571(&adapter->hw, 1);
+
+ /* Hold a copy of the LAA in RAR[14] This is done so that
+ * between the time RAR[0] gets clobbered and the time it
+ * gets fixed (in e1000_watchdog), the actual LAA is in one
+ * of the RARs and no incoming packets directed to this port
+ * are dropped. Eventually the LAA will be in RAR[0] and
+ * RAR[14] */
+ e1000e_rar_set(&adapter->hw,
+ adapter->hw.mac.addr,
+ adapter->hw.mac.rar_entry_count - 1);
+ }
+
+ return 0;
+}
+
+/* Need to wait a few seconds after link up to get diagnostic information from
+ * the phy */
+static void e1000_update_phy_info(unsigned long data)
+{
+ struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+ e1000_get_phy_info(&adapter->hw);
+}
+
+/**
+ * e1000e_update_stats - Update the board statistics counters
+ * @adapter: board private structure
+ **/
+void e1000e_update_stats(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long irq_flags;
+ u16 phy_tmp;
+
+#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
+
+ /*
+ * Prevent stats update while adapter is being reset, or if the pci
+ * connection is down.
+ */
+ if (adapter->link_speed == 0)
+ return;
+ if (pci_channel_offline(pdev))
+ return;
+
+ spin_lock_irqsave(&adapter->stats_lock, irq_flags);
+
+ /* these counters are modified from e1000_adjust_tbi_stats,
+ * called from the interrupt context, so they must only
+ * be written while holding adapter->stats_lock
+ */
+
+ adapter->stats.crcerrs += er32(CRCERRS);
+ adapter->stats.gprc += er32(GPRC);
+ adapter->stats.gorcl += er32(GORCL);
+ adapter->stats.gorch += er32(GORCH);
+ adapter->stats.bprc += er32(BPRC);
+ adapter->stats.mprc += er32(MPRC);
+ adapter->stats.roc += er32(ROC);
+
+ if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) {
+ adapter->stats.prc64 += er32(PRC64);
+ adapter->stats.prc127 += er32(PRC127);
+ adapter->stats.prc255 += er32(PRC255);
+ adapter->stats.prc511 += er32(PRC511);
+ adapter->stats.prc1023 += er32(PRC1023);
+ adapter->stats.prc1522 += er32(PRC1522);
+ adapter->stats.symerrs += er32(SYMERRS);
+ adapter->stats.sec += er32(SEC);
+ }
+
+ adapter->stats.mpc += er32(MPC);
+ adapter->stats.scc += er32(SCC);
+ adapter->stats.ecol += er32(ECOL);
+ adapter->stats.mcc += er32(MCC);
+ adapter->stats.latecol += er32(LATECOL);
+ adapter->stats.dc += er32(DC);
+ adapter->stats.rlec += er32(RLEC);
+ adapter->stats.xonrxc += er32(XONRXC);
+ adapter->stats.xontxc += er32(XONTXC);
+ adapter->stats.xoffrxc += er32(XOFFRXC);
+ adapter->stats.xofftxc += er32(XOFFTXC);
+ adapter->stats.fcruc += er32(FCRUC);
+ adapter->stats.gptc += er32(GPTC);
+ adapter->stats.gotcl += er32(GOTCL);
+ adapter->stats.gotch += er32(GOTCH);
+ adapter->stats.rnbc += er32(RNBC);
+ adapter->stats.ruc += er32(RUC);
+ adapter->stats.rfc += er32(RFC);
+ adapter->stats.rjc += er32(RJC);
+ adapter->stats.torl += er32(TORL);
+ adapter->stats.torh += er32(TORH);
+ adapter->stats.totl += er32(TOTL);
+ adapter->stats.toth += er32(TOTH);
+ adapter->stats.tpr += er32(TPR);
+
+ if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) {
+ adapter->stats.ptc64 += er32(PTC64);
+ adapter->stats.ptc127 += er32(PTC127);
+ adapter->stats.ptc255 += er32(PTC255);
+ adapter->stats.ptc511 += er32(PTC511);
+ adapter->stats.ptc1023 += er32(PTC1023);
+ adapter->stats.ptc1522 += er32(PTC1522);
+ }
+
+ adapter->stats.mptc += er32(MPTC);
+ adapter->stats.bptc += er32(BPTC);
+
+ /* used for adaptive IFS */
+
+ hw->mac.tx_packet_delta = er32(TPT);
+ adapter->stats.tpt += hw->mac.tx_packet_delta;
+ hw->mac.collision_delta = er32(COLC);
+ adapter->stats.colc += hw->mac.collision_delta;
+
+ adapter->stats.algnerrc += er32(ALGNERRC);
+ adapter->stats.rxerrc += er32(RXERRC);
+ adapter->stats.tncrs += er32(TNCRS);
+ adapter->stats.cexterr += er32(CEXTERR);
+ adapter->stats.tsctc += er32(TSCTC);
+ adapter->stats.tsctfc += er32(TSCTFC);
+
+ adapter->stats.iac += er32(IAC);
+
+ if (adapter->flags & FLAG_HAS_STATS_ICR_ICT) {
+ adapter->stats.icrxoc += er32(ICRXOC);
+ adapter->stats.icrxptc += er32(ICRXPTC);
+ adapter->stats.icrxatc += er32(ICRXATC);
+ adapter->stats.ictxptc += er32(ICTXPTC);
+ adapter->stats.ictxatc += er32(ICTXATC);
+ adapter->stats.ictxqec += er32(ICTXQEC);
+ adapter->stats.ictxqmtc += er32(ICTXQMTC);
+ adapter->stats.icrxdmtc += er32(ICRXDMTC);
+ }
+
+ /* Fill out the OS statistics structure */
+ adapter->net_stats.rx_packets = adapter->stats.gprc;
+ adapter->net_stats.tx_packets = adapter->stats.gptc;
+ adapter->net_stats.rx_bytes = adapter->stats.gorcl;
+ adapter->net_stats.tx_bytes = adapter->stats.gotcl;
+ adapter->net_stats.multicast = adapter->stats.mprc;
+ adapter->net_stats.collisions = adapter->stats.colc;
+
+ /* Rx Errors */
+
+ /* RLEC on some newer hardware can be incorrect so build
+ * our own version based on RUC and ROC */
+ adapter->net_stats.rx_errors = adapter->stats.rxerrc +
+ adapter->stats.crcerrs + adapter->stats.algnerrc +
+ adapter->stats.ruc + adapter->stats.roc +
+ adapter->stats.cexterr;
+ adapter->net_stats.rx_length_errors = adapter->stats.ruc +
+ adapter->stats.roc;
+ adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
+ adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc;
+ adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
+
+ /* Tx Errors */
+ adapter->net_stats.tx_errors = adapter->stats.ecol +
+ adapter->stats.latecol;
+ adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
+ adapter->net_stats.tx_window_errors = adapter->stats.latecol;
+ adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs;
+
+ /* Tx Dropped needs to be maintained elsewhere */
+
+ /* Phy Stats */
+ if (hw->media_type == e1000_media_type_copper) {
+ if ((adapter->link_speed == SPEED_1000) &&
+ (!e1e_rphy(hw, PHY_1000T_STATUS, &phy_tmp))) {
+ phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
+ adapter->phy_stats.idle_errors += phy_tmp;
+ }
+ }
+
+ /* Management Stats */
+ adapter->stats.mgptc += er32(MGTPTC);
+ adapter->stats.mgprc += er32(MGTPRC);
+ adapter->stats.mgpdc += er32(MGTPDC);
+
+ spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
+}
+
+static void e1000_print_link_info(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl = er32(CTRL);
+
+ ndev_info(netdev,
+ "Link is Up %d Mbps %s, Flow Control: %s\n",
+ adapter->link_speed,
+ (adapter->link_duplex == FULL_DUPLEX) ?
+ "Full Duplex" : "Half Duplex",
+ ((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ?
+ "RX/TX" :
+ ((ctrl & E1000_CTRL_RFCE) ? "RX" :
+ ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" )));
+}
+
+/**
+ * e1000_watchdog - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void e1000_watchdog(unsigned long data)
+{
+ struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+
+ /* Do the rest outside of interrupt context */
+ schedule_work(&adapter->watchdog_task);
+
+ /* TODO: make this use queue_delayed_work() */
+}
+
+static void e1000_watchdog_task(struct work_struct *work)
+{
+ struct e1000_adapter *adapter = container_of(work,
+ struct e1000_adapter, watchdog_task);
+
+ struct net_device *netdev = adapter->netdev;
+ struct e1000_mac_info *mac = &adapter->hw.mac;
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 link, tctl;
+ s32 ret_val;
+ int tx_pending = 0;
+
+ if ((netif_carrier_ok(netdev)) &&
+ (er32(STATUS) & E1000_STATUS_LU))
+ goto link_up;
+
+ ret_val = mac->ops.check_for_link(hw);
+ if ((ret_val == E1000_ERR_PHY) &&
+ (adapter->hw.phy.type == e1000_phy_igp_3) &&
+ (er32(CTRL) &
+ E1000_PHY_CTRL_GBE_DISABLE)) {
+ /* See e1000_kmrn_lock_loss_workaround_ich8lan() */
+ ndev_info(netdev,
+ "Gigabit has been disabled, downgrading speed\n");
+ }
+
+ if ((e1000e_enable_tx_pkt_filtering(hw)) &&
+ (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id))
+ e1000_update_mng_vlan(adapter);
+
+ if ((adapter->hw.media_type == e1000_media_type_internal_serdes) &&
+ !(er32(TXCW) & E1000_TXCW_ANE))
+ link = adapter->hw.mac.serdes_has_link;
+ else
+ link = er32(STATUS) & E1000_STATUS_LU;
+
+ if (link) {
+ if (!netif_carrier_ok(netdev)) {
+ bool txb2b = 1;
+ mac->ops.get_link_up_info(&adapter->hw,
+ &adapter->link_speed,
+ &adapter->link_duplex);
+ e1000_print_link_info(adapter);
+ /* tweak tx_queue_len according to speed/duplex
+ * and adjust the timeout factor */
+ netdev->tx_queue_len = adapter->tx_queue_len;
+ adapter->tx_timeout_factor = 1;
+ switch (adapter->link_speed) {
+ case SPEED_10:
+ txb2b = 0;
+ netdev->tx_queue_len = 10;
+ adapter->tx_timeout_factor = 14;
+ break;
+ case SPEED_100:
+ txb2b = 0;
+ netdev->tx_queue_len = 100;
+ /* maybe add some timeout factor ? */
+ break;
+ }
+
+ /* workaround: re-program speed mode bit after
+ * link-up event */
+ if ((adapter->flags & FLAG_TARC_SPEED_MODE_BIT) &&
+ !txb2b) {
+ u32 tarc0;
+ tarc0 = er32(TARC0);
+ tarc0 &= ~SPEED_MODE_BIT;
+ ew32(TARC0, tarc0);
+ }
+
+ /* disable TSO for pcie and 10/100 speeds, to avoid
+ * some hardware issues */
+ if (!(adapter->flags & FLAG_TSO_FORCE)) {
+ switch (adapter->link_speed) {
+ case SPEED_10:
+ case SPEED_100:
+ ndev_info(netdev,
+ "10/100 speed: disabling TSO\n");
+ netdev->features &= ~NETIF_F_TSO;
+ netdev->features &= ~NETIF_F_TSO6;
+ break;
+ case SPEED_1000:
+ netdev->features |= NETIF_F_TSO;
+ netdev->features |= NETIF_F_TSO6;
+ break;
+ default:
+ /* oops */
+ break;
+ }
+ }
+
+ /* enable transmits in the hardware, need to do this
+ * after setting TARC0 */
+ tctl = er32(TCTL);
+ tctl |= E1000_TCTL_EN;
+ ew32(TCTL, tctl);
+
+ netif_carrier_on(netdev);
+ netif_wake_queue(netdev);
+
+ if (!test_bit(__E1000_DOWN, &adapter->state))
+ mod_timer(&adapter->phy_info_timer,
+ round_jiffies(jiffies + 2 * HZ));
+ } else {
+ /* make sure the receive unit is started */
+ if (adapter->flags & FLAG_RX_NEEDS_RESTART) {
+ u32 rctl = er32(RCTL);
+ ew32(RCTL, rctl |
+ E1000_RCTL_EN);
+ }
+ }
+ } else {
+ if (netif_carrier_ok(netdev)) {
+ adapter->link_speed = 0;
+ adapter->link_duplex = 0;
+ ndev_info(netdev, "Link is Down\n");
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ if (!test_bit(__E1000_DOWN, &adapter->state))
+ mod_timer(&adapter->phy_info_timer,
+ round_jiffies(jiffies + 2 * HZ));
+
+ if (adapter->flags & FLAG_RX_NEEDS_RESTART)
+ schedule_work(&adapter->reset_task);
+ }
+ }
+
+link_up:
+ e1000e_update_stats(adapter);
+
+ mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;
+ adapter->tpt_old = adapter->stats.tpt;
+ mac->collision_delta = adapter->stats.colc - adapter->colc_old;
+ adapter->colc_old = adapter->stats.colc;
+
+ adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old;
+ adapter->gorcl_old = adapter->stats.gorcl;
+ adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old;
+ adapter->gotcl_old = adapter->stats.gotcl;
+
+ e1000e_update_adaptive(&adapter->hw);
+
+ if (!netif_carrier_ok(netdev)) {
+ tx_pending = (e1000_desc_unused(tx_ring) + 1 <
+ tx_ring->count);
+ if (tx_pending) {
+ /* We've lost link, so the controller stops DMA,
+ * but we've got queued Tx work that's never going
+ * to get done, so reset controller to flush Tx.
+ * (Do the reset outside of interrupt context). */
+ adapter->tx_timeout_count++;
+ schedule_work(&adapter->reset_task);
+ }
+ }
+
+ /* Cause software interrupt to ensure rx ring is cleaned */
+ ew32(ICS, E1000_ICS_RXDMT0);
+
+ /* Force detection of hung controller every watchdog period */
+ adapter->detect_tx_hung = 1;
+
+ /* With 82571 controllers, LAA may be overwritten due to controller
+ * reset from the other port. Set the appropriate LAA in RAR[0] */
+ if (e1000e_get_laa_state_82571(hw))
+ e1000e_rar_set(hw, adapter->hw.mac.addr, 0);
+
+ /* Reset the timer */
+ if (!test_bit(__E1000_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer,
+ round_jiffies(jiffies + 2 * HZ));
+}
+
+#define E1000_TX_FLAGS_CSUM 0x00000001
+#define E1000_TX_FLAGS_VLAN 0x00000002
+#define E1000_TX_FLAGS_TSO 0x00000004
+#define E1000_TX_FLAGS_IPV4 0x00000008
+#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000
+#define E1000_TX_FLAGS_VLAN_SHIFT 16
+
+static int e1000_tso(struct e1000_adapter *adapter,
+ struct sk_buff *skb)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_context_desc *context_desc;
+ struct e1000_buffer *buffer_info;
+ unsigned int i;
+ u32 cmd_length = 0;
+ u16 ipcse = 0, tucse, mss;
+ u8 ipcss, ipcso, tucss, tucso, hdr_len;
+ int err;
+
+ if (skb_is_gso(skb)) {
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (err)
+ return err;
+ }
+
+ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ mss = skb_shinfo(skb)->gso_size;
+ if (skb->protocol == htons(ETH_P_IP)) {
+ struct iphdr *iph = ip_hdr(skb);
+ iph->tot_len = 0;
+ iph->check = 0;
+ tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+ iph->daddr, 0,
+ IPPROTO_TCP,
+ 0);
+ cmd_length = E1000_TXD_CMD_IP;
+ ipcse = skb_transport_offset(skb) - 1;
+ } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+ ipv6_hdr(skb)->payload_len = 0;
+ tcp_hdr(skb)->check =
+ ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0);
+ ipcse = 0;
+ }
+ ipcss = skb_network_offset(skb);
+ ipcso = (void *)&(ip_hdr(skb)->check) - (void *)skb->data;
+ tucss = skb_transport_offset(skb);
+ tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data;
+ tucse = 0;
+
+ cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
+ E1000_TXD_CMD_TCP | (skb->len - (hdr_len)));
+
+ i = tx_ring->next_to_use;
+ context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+ buffer_info = &tx_ring->buffer_info[i];
+
+ context_desc->lower_setup.ip_fields.ipcss = ipcss;
+ context_desc->lower_setup.ip_fields.ipcso = ipcso;
+ context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse);
+ context_desc->upper_setup.tcp_fields.tucss = tucss;
+ context_desc->upper_setup.tcp_fields.tucso = tucso;
+ context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse);
+ context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss);
+ context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
+ context_desc->cmd_and_length = cpu_to_le32(cmd_length);
+
+ buffer_info->time_stamp = jiffies;
+ buffer_info->next_to_watch = i;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ tx_ring->next_to_use = i;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_context_desc *context_desc;
+ struct e1000_buffer *buffer_info;
+ unsigned int i;
+ u8 css;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ css = skb_transport_offset(skb);
+
+ i = tx_ring->next_to_use;
+ buffer_info = &tx_ring->buffer_info[i];
+ context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+
+ context_desc->lower_setup.ip_config = 0;
+ context_desc->upper_setup.tcp_fields.tucss = css;
+ context_desc->upper_setup.tcp_fields.tucso =
+ css + skb->csum_offset;
+ context_desc->upper_setup.tcp_fields.tucse = 0;
+ context_desc->tcp_seg_setup.data = 0;
+ context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
+
+ buffer_info->time_stamp = jiffies;
+ buffer_info->next_to_watch = i;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ tx_ring->next_to_use = i;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+#define E1000_MAX_PER_TXD 8192
+#define E1000_MAX_TXD_PWR 12
+
+static int e1000_tx_map(struct e1000_adapter *adapter,
+ struct sk_buff *skb, unsigned int first,
+ unsigned int max_per_txd, unsigned int nr_frags,
+ unsigned int mss)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_buffer *buffer_info;
+ unsigned int len = skb->len - skb->data_len;
+ unsigned int offset = 0, size, count = 0, i;
+ unsigned int f;
+
+ i = tx_ring->next_to_use;
+
+ while (len) {
+ buffer_info = &tx_ring->buffer_info[i];
+ size = min(len, max_per_txd);
+
+ /* Workaround for premature desc write-backs
+ * in TSO mode. Append 4-byte sentinel desc */
+ if (mss && !nr_frags && size == len && size > 8)
+ size -= 4;
+
+ buffer_info->length = size;
+ /* set time_stamp *before* dma to help avoid a possible race */
+ buffer_info->time_stamp = jiffies;
+ buffer_info->dma =
+ pci_map_single(adapter->pdev,
+ skb->data + offset,
+ size,
+ PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(buffer_info->dma)) {
+ dev_err(&adapter->pdev->dev, "TX DMA map failed\n");
+ adapter->tx_dma_failed++;
+ return -1;
+ }
+ buffer_info->next_to_watch = i;
+
+ len -= size;
+ offset += size;
+ count++;
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ for (f = 0; f < nr_frags; f++) {
+ struct skb_frag_struct *frag;
+
+ frag = &skb_shinfo(skb)->frags[f];
+ len = frag->size;
+ offset = frag->page_offset;
+
+ while (len) {
+ buffer_info = &tx_ring->buffer_info[i];
+ size = min(len, max_per_txd);
+ /* Workaround for premature desc write-backs
+ * in TSO mode. Append 4-byte sentinel desc */
+ if (mss && f == (nr_frags-1) && size == len && size > 8)
+ size -= 4;
+
+ buffer_info->length = size;
+ buffer_info->time_stamp = jiffies;
+ buffer_info->dma =
+ pci_map_page(adapter->pdev,
+ frag->page,
+ offset,
+ size,
+ PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(buffer_info->dma)) {
+ dev_err(&adapter->pdev->dev,
+ "TX DMA page map failed\n");
+ adapter->tx_dma_failed++;
+ return -1;
+ }
+
+ buffer_info->next_to_watch = i;
+
+ len -= size;
+ offset += size;
+ count++;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+ }
+
+ if (i == 0)
+ i = tx_ring->count - 1;
+ else
+ i--;
+
+ tx_ring->buffer_info[i].skb = skb;
+ tx_ring->buffer_info[first].next_to_watch = i;
+
+ return count;
+}
+
+static void e1000_tx_queue(struct e1000_adapter *adapter,
+ int tx_flags, int count)
+{
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ struct e1000_tx_desc *tx_desc = NULL;
+ struct e1000_buffer *buffer_info;
+ u32 txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS;
+ unsigned int i;
+
+ if (tx_flags & E1000_TX_FLAGS_TSO) {
+ txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D |
+ E1000_TXD_CMD_TSE;
+ txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+
+ if (tx_flags & E1000_TX_FLAGS_IPV4)
+ txd_upper |= E1000_TXD_POPTS_IXSM << 8;
+ }
+
+ if (tx_flags & E1000_TX_FLAGS_CSUM) {
+ txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+ txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+ }
+
+ if (tx_flags & E1000_TX_FLAGS_VLAN) {
+ txd_lower |= E1000_TXD_CMD_VLE;
+ txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK);
+ }
+
+ i = tx_ring->next_to_use;
+
+ while (count--) {
+ buffer_info = &tx_ring->buffer_info[i];
+ tx_desc = E1000_TX_DESC(*tx_ring, i);
+ tx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+ tx_desc->lower.data =
+ cpu_to_le32(txd_lower | buffer_info->length);
+ tx_desc->upper.data = cpu_to_le32(txd_upper);
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd);
+
+ /* Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64). */
+ wmb();
+
+ tx_ring->next_to_use = i;
+ writel(i, adapter->hw.hw_addr + tx_ring->tail);
+ /* we need this if more than one processor can write to our tail
+ * at a time, it synchronizes IO on IA64/Altix systems */
+ mmiowb();
+}
+
+#define MINIMUM_DHCP_PACKET_SIZE 282
+static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter,
+ struct sk_buff *skb)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u16 length, offset;
+
+ if (vlan_tx_tag_present(skb)) {
+ if (!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id)
+ && (adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN)))
+ return 0;
+ }
+
+ if (skb->len <= MINIMUM_DHCP_PACKET_SIZE)
+ return 0;
+
+ if (((struct ethhdr *) skb->data)->h_proto != htons(ETH_P_IP))
+ return 0;
+
+ {
+ const struct iphdr *ip = (struct iphdr *)((u8 *)skb->data+14);
+ struct udphdr *udp;
+
+ if (ip->protocol != IPPROTO_UDP)
+ return 0;
+
+ udp = (struct udphdr *)((u8 *)ip + (ip->ihl << 2));
+ if (ntohs(udp->dest) != 67)
+ return 0;
+
+ offset = (u8 *)udp + 8 - skb->data;
+ length = skb->len - offset;
+ return e1000e_mng_write_dhcp_info(hw, (u8 *)udp + 8, length);
+ }
+
+ return 0;
+}
+
+static int __e1000_maybe_stop_tx(struct net_device *netdev, int size)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ netif_stop_queue(netdev);
+ /* Herbert's original patch had:
+ * smp_mb__after_netif_stop_queue();
+ * but since that doesn't exist yet, just open code it. */
+ smp_mb();
+
+ /* We need to check again in a case another CPU has just
+ * made room available. */
+ if (e1000_desc_unused(adapter->tx_ring) < size)
+ return -EBUSY;
+
+ /* A reprieve! */
+ netif_start_queue(netdev);
+ ++adapter->restart_queue;
+ return 0;
+}
+
+static int e1000_maybe_stop_tx(struct net_device *netdev, int size)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (e1000_desc_unused(adapter->tx_ring) >= size)
+ return 0;
+ return __e1000_maybe_stop_tx(netdev, size);
+}
+
+#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 )
+static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_ring *tx_ring = adapter->tx_ring;
+ unsigned int first;
+ unsigned int max_per_txd = E1000_MAX_PER_TXD;
+ unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
+ unsigned int tx_flags = 0;
+ unsigned int len = skb->len - skb->data_len;
+ unsigned long irq_flags;
+ unsigned int nr_frags;
+ unsigned int mss;
+ int count = 0;
+ int tso;
+ unsigned int f;
+
+ if (test_bit(__E1000_DOWN, &adapter->state)) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ if (skb->len <= 0) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ mss = skb_shinfo(skb)->gso_size;
+ /* The controller does a simple calculation to
+ * make sure there is enough room in the FIFO before
+ * initiating the DMA for each buffer. The calc is:
+ * 4 = ceil(buffer len/mss). To make sure we don't
+ * overrun the FIFO, adjust the max buffer len if mss
+ * drops. */
+ if (mss) {
+ u8 hdr_len;
+ max_per_txd = min(mss << 2, max_per_txd);
+ max_txd_pwr = fls(max_per_txd) - 1;
+
+ /* TSO Workaround for 82571/2/3 Controllers -- if skb->data
+ * points to just header, pull a few bytes of payload from
+ * frags into skb->data */
+ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+ if (skb->data_len && (hdr_len == len)) {
+ unsigned int pull_size;
+
+ pull_size = min((unsigned int)4, skb->data_len);
+ if (!__pskb_pull_tail(skb, pull_size)) {
+ ndev_err(netdev,
+ "__pskb_pull_tail failed.\n");
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+ len = skb->len - skb->data_len;
+ }
+ }
+
+ /* reserve a descriptor for the offload context */
+ if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL))
+ count++;
+ count++;
+
+ count += TXD_USE_COUNT(len, max_txd_pwr);
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ for (f = 0; f < nr_frags; f++)
+ count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
+ max_txd_pwr);
+
+ if (adapter->hw.mac.tx_pkt_filtering)
+ e1000_transfer_dhcp_info(adapter, skb);
+
+ if (!spin_trylock_irqsave(&adapter->tx_queue_lock, irq_flags))
+ /* Collision - tell upper layer to requeue */
+ return NETDEV_TX_LOCKED;
+
+ /* need: count + 2 desc gap to keep tail from touching
+ * head, otherwise try next time */
+ if (e1000_maybe_stop_tx(netdev, count + 2)) {
+ spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+ return NETDEV_TX_BUSY;
+ }
+
+ if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ tx_flags |= E1000_TX_FLAGS_VLAN;
+ tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
+ }
+
+ first = tx_ring->next_to_use;
+
+ tso = e1000_tso(adapter, skb);
+ if (tso < 0) {
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+ return NETDEV_TX_OK;
+ }
+
+ if (tso)
+ tx_flags |= E1000_TX_FLAGS_TSO;
+ else if (e1000_tx_csum(adapter, skb))
+ tx_flags |= E1000_TX_FLAGS_CSUM;
+
+ /* Old method was to assume IPv4 packet by default if TSO was enabled.
+ * 82571 hardware supports TSO capabilities for IPv6 as well...
+ * no longer assume, we must. */
+ if (skb->protocol == htons(ETH_P_IP))
+ tx_flags |= E1000_TX_FLAGS_IPV4;
+
+ count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss);
+ if (count < 0) {
+ /* handle pci_map_single() error in e1000_tx_map */
+ dev_kfree_skb_any(skb);
+ spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+ return NETDEV_TX_OK;
+ }
+
+ e1000_tx_queue(adapter, tx_flags, count);
+
+ netdev->trans_start = jiffies;
+
+ /* Make sure there is space in the ring for the next send. */
+ e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2);
+
+ spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+ return NETDEV_TX_OK;
+}
+
+/**
+ * e1000_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+static void e1000_tx_timeout(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ /* Do the reset outside of interrupt context */
+ adapter->tx_timeout_count++;
+ schedule_work(&adapter->reset_task);
+}
+
+static void e1000_reset_task(struct work_struct *work)
+{
+ struct e1000_adapter *adapter;
+ adapter = container_of(work, struct e1000_adapter, reset_task);
+
+ e1000e_reinit_locked(adapter);
+}
+
+/**
+ * e1000_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ **/
+static struct net_device_stats *e1000_get_stats(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ /* only return the current stats */
+ return &adapter->net_stats;
+}
+
+/**
+ * e1000_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+
+ if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
+ (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+ ndev_err(netdev, "Invalid MTU setting\n");
+ return -EINVAL;
+ }
+
+ /* Jumbo frame size limits */
+ if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) {
+ if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
+ ndev_err(netdev, "Jumbo Frames not supported.\n");
+ return -EINVAL;
+ }
+ if (adapter->hw.phy.type == e1000_phy_ife) {
+ ndev_err(netdev, "Jumbo Frames not supported.\n");
+ return -EINVAL;
+ }
+ }
+
+#define MAX_STD_JUMBO_FRAME_SIZE 9234
+ if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) {
+ ndev_err(netdev, "MTU > 9216 not supported.\n");
+ return -EINVAL;
+ }
+
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+ msleep(1);
+ /* e1000e_down has a dependency on max_frame_size */
+ adapter->hw.mac.max_frame_size = max_frame;
+ if (netif_running(netdev))
+ e1000e_down(adapter);
+
+ /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
+ * means we reserve 2 more, this pushes us to allocate from the next
+ * larger slab size.
+ * i.e. RXBUFFER_2048 --> size-4096 slab */
+
+ if (max_frame <= 256)
+ adapter->rx_buffer_len = 256;
+ else if (max_frame <= 512)
+ adapter->rx_buffer_len = 512;
+ else if (max_frame <= 1024)
+ adapter->rx_buffer_len = 1024;
+ else if (max_frame <= 2048)
+ adapter->rx_buffer_len = 2048;
+ else
+ adapter->rx_buffer_len = 4096;
+
+ /* adjust allocation if LPE protects us, and we aren't using SBP */
+ if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) ||
+ (max_frame == ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN))
+ adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN
+ + ETH_FCS_LEN ;
+
+ ndev_info(netdev, "changing MTU from %d to %d\n",
+ netdev->mtu, new_mtu);
+ netdev->mtu = new_mtu;
+
+ if (netif_running(netdev))
+ e1000e_up(adapter);
+ else
+ e1000e_reset(adapter);
+
+ clear_bit(__E1000_RESETTING, &adapter->state);
+
+ return 0;
+}
+
+static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
+ int cmd)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct mii_ioctl_data *data = if_mii(ifr);
+ unsigned long irq_flags;
+
+ if (adapter->hw.media_type != e1000_media_type_copper)
+ return -EOPNOTSUPP;
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ data->phy_id = adapter->hw.phy.addr;
+ break;
+ case SIOCGMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ spin_lock_irqsave(&adapter->stats_lock, irq_flags);
+ if (e1e_rphy(&adapter->hw, data->reg_num & 0x1F,
+ &data->val_out)) {
+ spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
+ return -EIO;
+ }
+ spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
+ break;
+ case SIOCSMIIREG:
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ return e1000_mii_ioctl(netdev, ifr, cmd);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl, ctrl_ext, rctl, status;
+ u32 wufc = adapter->wol;
+ int retval = 0;
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev)) {
+ WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
+ e1000e_down(adapter);
+ e1000_free_irq(adapter);
+ }
+
+ retval = pci_save_state(pdev);
+ if (retval)
+ return retval;
+
+ status = er32(STATUS);
+ if (status & E1000_STATUS_LU)
+ wufc &= ~E1000_WUFC_LNKC;
+
+ if (wufc) {
+ e1000_setup_rctl(adapter);
+ e1000_set_multi(netdev);
+
+ /* turn on all-multi mode if wake on multicast is enabled */
+ if (wufc & E1000_WUFC_MC) {
+ rctl = er32(RCTL);
+ rctl |= E1000_RCTL_MPE;
+ ew32(RCTL, rctl);
+ }
+
+ ctrl = er32(CTRL);
+ /* advertise wake from D3Cold */
+ #define E1000_CTRL_ADVD3WUC 0x00100000
+ /* phy power management enable */
+ #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000
+ ctrl |= E1000_CTRL_ADVD3WUC |
+ E1000_CTRL_EN_PHY_PWR_MGMT;
+ ew32(CTRL, ctrl);
+
+ if (adapter->hw.media_type == e1000_media_type_fiber ||
+ adapter->hw.media_type == e1000_media_type_internal_serdes) {
+ /* keep the laser running in D3 */
+ ctrl_ext = er32(CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA;
+ ew32(CTRL_EXT, ctrl_ext);
+ }
+
+ /* Allow time for pending master requests to run */
+ e1000e_disable_pcie_master(&adapter->hw);
+
+ ew32(WUC, E1000_WUC_PME_EN);
+ ew32(WUFC, wufc);
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_enable_wake(pdev, PCI_D3cold, 1);
+ } else {
+ ew32(WUC, 0);
+ ew32(WUFC, 0);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+ }
+
+ e1000_release_manageability(adapter);
+
+ /* make sure adapter isn't asleep if manageability is enabled */
+ if (adapter->flags & FLAG_MNG_PT_ENABLED) {
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_enable_wake(pdev, PCI_D3cold, 1);
+ }
+
+ if (adapter->hw.phy.type == e1000_phy_igp_3)
+ e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw);
+
+ /* Release control of h/w to f/w. If f/w is AMT enabled, this
+ * would have already happened in close and is redundant. */
+ e1000_release_hw_control(adapter);
+
+ pci_disable_device(pdev);
+
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int e1000_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ u32 err;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Cannot enable PCI device from suspend\n");
+ return err;
+ }
+
+ pci_set_master(pdev);
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ if (netif_running(netdev)) {
+ err = e1000_request_irq(adapter);
+ if (err)
+ return err;
+ }
+
+ e1000e_power_up_phy(adapter);
+ e1000e_reset(adapter);
+ ew32(WUS, ~0);
+
+ e1000_init_manageability(adapter);
+
+ if (netif_running(netdev))
+ e1000e_up(adapter);
+
+ netif_device_attach(netdev);
+
+ /* If the controller has AMT, do not set DRV_LOAD until the interface
+ * is up. For all other cases, let the f/w know that the h/w is now
+ * under the control of the driver. */
+ if (!(adapter->flags & FLAG_HAS_AMT) || !e1000e_check_mng_mode(&adapter->hw))
+ e1000_get_hw_control(adapter);
+
+ return 0;
+}
+#endif
+
+static void e1000_shutdown(struct pci_dev *pdev)
+{
+ e1000_suspend(pdev, PMSG_SUSPEND);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void e1000_netpoll(struct net_device *netdev)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ disable_irq(adapter->pdev->irq);
+ e1000_intr(adapter->pdev->irq, netdev);
+
+ e1000_clean_tx_irq(adapter);
+
+ enable_irq(adapter->pdev->irq);
+}
+#endif
+
+/**
+ * e1000_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev))
+ e1000e_down(adapter);
+ pci_disable_device(pdev);
+
+ /* Request a slot slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * e1000_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot. Implementation
+ * resembles the first-half of the e1000_resume routine.
+ */
+static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (pci_enable_device(pdev)) {
+ dev_err(&pdev->dev,
+ "Cannot re-enable PCI device after reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ pci_set_master(pdev);
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ e1000e_reset(adapter);
+ ew32(WUS, ~0);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * e1000_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation. Implementation resembles the
+ * second-half of the e1000_resume routine.
+ */
+static void e1000_io_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ e1000_init_manageability(adapter);
+
+ if (netif_running(netdev)) {
+ if (e1000e_up(adapter)) {
+ dev_err(&pdev->dev,
+ "can't bring device back up after reset\n");
+ return;
+ }
+ }
+
+ netif_device_attach(netdev);
+
+ /* If the controller has AMT, do not set DRV_LOAD until the interface
+ * is up. For all other cases, let the f/w know that the h/w is now
+ * under the control of the driver. */
+ if (!(adapter->flags & FLAG_HAS_AMT) ||
+ !e1000e_check_mng_mode(&adapter->hw))
+ e1000_get_hw_control(adapter);
+
+}
+
+static void e1000_print_device_info(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ u32 part_num;
+
+ /* print bus type/speed/width info */
+ ndev_info(netdev, "(PCI Express:2.5GB/s:%s) "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ /* bus width */
+ ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" :
+ "Width x1"),
+ /* MAC address */
+ netdev->dev_addr[0], netdev->dev_addr[1],
+ netdev->dev_addr[2], netdev->dev_addr[3],
+ netdev->dev_addr[4], netdev->dev_addr[5]);
+ ndev_info(netdev, "Intel(R) PRO/%s Network Connection\n",
+ (hw->phy.type == e1000_phy_ife)
+ ? "10/100" : "1000");
+ e1000e_read_part_num(hw, &part_num);
+ ndev_info(netdev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
+ hw->mac.type, hw->phy.type,
+ (part_num >> 8), (part_num & 0xff));
+}
+
+/**
+ * e1000_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in e1000_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * e1000_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int __devinit e1000_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *netdev;
+ struct e1000_adapter *adapter;
+ struct e1000_hw *hw;
+ const struct e1000_info *ei = e1000_info_tbl[ent->driver_data];
+ unsigned long mmio_start, mmio_len;
+ unsigned long flash_start, flash_len;
+
+ static int cards_found;
+ int i, err, pci_using_dac;
+ u16 eeprom_data = 0;
+ u16 eeprom_apme_mask = E1000_EEPROM_APME;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ pci_using_dac = 0;
+ err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ if (!err) {
+ err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (!err)
+ pci_using_dac = 1;
+ } else {
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ err = pci_set_consistent_dma_mask(pdev,
+ DMA_32BIT_MASK);
+ if (err) {
+ dev_err(&pdev->dev, "No usable DMA "
+ "configuration, aborting\n");
+ goto err_dma;
+ }
+ }
+ }
+
+ err = pci_request_regions(pdev, e1000e_driver_name);
+ if (err)
+ goto err_pci_reg;
+
+ pci_set_master(pdev);
+
+ err = -ENOMEM;
+ netdev = alloc_etherdev(sizeof(struct e1000_adapter));
+ if (!netdev)
+ goto err_alloc_etherdev;
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ pci_set_drvdata(pdev, netdev);
+ adapter = netdev_priv(netdev);
+ hw = &adapter->hw;
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ adapter->ei = ei;
+ adapter->pba = ei->pba;
+ adapter->flags = ei->flags;
+ adapter->hw.adapter = adapter;
+ adapter->hw.mac.type = ei->mac;
+ adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1;
+
+ mmio_start = pci_resource_start(pdev, 0);
+ mmio_len = pci_resource_len(pdev, 0);
+
+ err = -EIO;
+ adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
+ if (!adapter->hw.hw_addr)
+ goto err_ioremap;
+
+ if ((adapter->flags & FLAG_HAS_FLASH) &&
+ (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
+ flash_start = pci_resource_start(pdev, 1);
+ flash_len = pci_resource_len(pdev, 1);
+ adapter->hw.flash_address = ioremap(flash_start, flash_len);
+ if (!adapter->hw.flash_address)
+ goto err_flashmap;
+ }
+
+ /* construct the net_device struct */
+ netdev->open = &e1000_open;
+ netdev->stop = &e1000_close;
+ netdev->hard_start_xmit = &e1000_xmit_frame;
+ netdev->get_stats = &e1000_get_stats;
+ netdev->set_multicast_list = &e1000_set_multi;
+ netdev->set_mac_address = &e1000_set_mac;
+ netdev->change_mtu = &e1000_change_mtu;
+ netdev->do_ioctl = &e1000_ioctl;
+ e1000e_set_ethtool_ops(netdev);
+ netdev->tx_timeout = &e1000_tx_timeout;
+ netdev->watchdog_timeo = 5 * HZ;
+ netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);
+ netdev->vlan_rx_register = e1000_vlan_rx_register;
+ netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
+ netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = e1000_netpoll;
+#endif
+ strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
+
+ netdev->mem_start = mmio_start;
+ netdev->mem_end = mmio_start + mmio_len;
+
+ adapter->bd_number = cards_found++;
+
+ /* setup adapter struct */
+ err = e1000_sw_init(adapter);
+ if (err)
+ goto err_sw_init;
+
+ err = -EIO;
+
+ memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops));
+ memcpy(&hw->nvm.ops, ei->nvm_ops, sizeof(hw->nvm.ops));
+ memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops));
+
+ err = ei->get_invariants(adapter);
+ if (err)
+ goto err_hw_init;
+
+ hw->mac.ops.get_bus_info(&adapter->hw);
+
+ adapter->hw.phy.wait_for_link = 0;
+
+ /* Copper options */
+ if (adapter->hw.media_type == e1000_media_type_copper) {
+ adapter->hw.phy.mdix = AUTO_ALL_MODES;
+ adapter->hw.phy.disable_polarity_correction = 0;
+ adapter->hw.phy.ms_type = e1000_ms_hw_default;
+ }
+
+ if (e1000_check_reset_block(&adapter->hw))
+ ndev_info(netdev,
+ "PHY reset is blocked due to SOL/IDER session.\n");
+
+ netdev->features = NETIF_F_SG |
+ NETIF_F_HW_CSUM |
+ NETIF_F_HW_VLAN_TX |
+ NETIF_F_HW_VLAN_RX;
+
+ if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER)
+ netdev->features |= NETIF_F_HW_VLAN_FILTER;
+
+ netdev->features |= NETIF_F_TSO;
+ netdev->features |= NETIF_F_TSO6;
+
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ /* We should not be using LLTX anymore, but we are still TX faster with
+ * it. */
+ netdev->features |= NETIF_F_LLTX;
+
+ if (e1000e_enable_mng_pass_thru(&adapter->hw))
+ adapter->flags |= FLAG_MNG_PT_ENABLED;
+
+ /* before reading the NVM, reset the controller to
+ * put the device in a known good starting state */
+ adapter->hw.mac.ops.reset_hw(&adapter->hw);
+
+ /*
+ * systems with ASPM and others may see the checksum fail on the first
+ * attempt. Let's give it a few tries
+ */
+ for (i = 0;; i++) {
+ if (e1000_validate_nvm_checksum(&adapter->hw) >= 0)
+ break;
+ if (i == 2) {
+ ndev_err(netdev, "The NVM Checksum Is Not Valid\n");
+ err = -EIO;
+ goto err_eeprom;
+ }
+ }
+
+ /* copy the MAC address out of the NVM */
+ if (e1000e_read_mac_addr(&adapter->hw))
+ ndev_err(netdev, "NVM Read Error while reading MAC address\n");
+
+ memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
+ memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
+
+ if (!is_valid_ether_addr(netdev->perm_addr)) {
+ ndev_err(netdev, "Invalid MAC Address: "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ netdev->perm_addr[0], netdev->perm_addr[1],
+ netdev->perm_addr[2], netdev->perm_addr[3],
+ netdev->perm_addr[4], netdev->perm_addr[5]);
+ err = -EIO;
+ goto err_eeprom;
+ }
+
+ init_timer(&adapter->watchdog_timer);
+ adapter->watchdog_timer.function = &e1000_watchdog;
+ adapter->watchdog_timer.data = (unsigned long) adapter;
+
+ init_timer(&adapter->phy_info_timer);
+ adapter->phy_info_timer.function = &e1000_update_phy_info;
+ adapter->phy_info_timer.data = (unsigned long) adapter;
+
+ INIT_WORK(&adapter->reset_task, e1000_reset_task);
+ INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
+
+ e1000e_check_options(adapter);
+
+ /* Initialize link parameters. User can change them with ethtool */
+ adapter->hw.mac.autoneg = 1;
+ adapter->fc_autoneg = 1;
+ adapter->hw.mac.original_fc = e1000_fc_default;
+ adapter->hw.mac.fc = e1000_fc_default;
+ adapter->hw.phy.autoneg_advertised = 0x2f;
+
+ /* ring size defaults */
+ adapter->rx_ring->count = 256;
+ adapter->tx_ring->count = 256;
+
+ /*
+ * Initial Wake on LAN setting - If APM wake is enabled in
+ * the EEPROM, enable the ACPI Magic Packet filter
+ */
+ if (adapter->flags & FLAG_APME_IN_WUC) {
+ /* APME bit in EEPROM is mapped to WUC.APME */
+ eeprom_data = er32(WUC);
+ eeprom_apme_mask = E1000_WUC_APME;
+ } else if (adapter->flags & FLAG_APME_IN_CTRL3) {
+ if (adapter->flags & FLAG_APME_CHECK_PORT_B &&
+ (adapter->hw.bus.func == 1))
+ e1000_read_nvm(&adapter->hw,
+ NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
+ else
+ e1000_read_nvm(&adapter->hw,
+ NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
+ }
+
+ /* fetch WoL from EEPROM */
+ if (eeprom_data & eeprom_apme_mask)
+ adapter->eeprom_wol |= E1000_WUFC_MAG;
+
+ /*
+ * now that we have the eeprom settings, apply the special cases
+ * where the eeprom may be wrong or the board simply won't support
+ * wake on lan on a particular port
+ */
+ if (!(adapter->flags & FLAG_HAS_WOL))
+ adapter->eeprom_wol = 0;
+
+ /* initialize the wol settings based on the eeprom settings */
+ adapter->wol = adapter->eeprom_wol;
+
+ /* reset the hardware with the new settings */
+ e1000e_reset(adapter);
+
+ /* If the controller has AMT, do not set DRV_LOAD until the interface
+ * is up. For all other cases, let the f/w know that the h/w is now
+ * under the control of the driver. */
+ if (!(adapter->flags & FLAG_HAS_AMT) ||
+ !e1000e_check_mng_mode(&adapter->hw))
+ e1000_get_hw_control(adapter);
+
+ /* tell the stack to leave us alone until e1000_open() is called */
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ strcpy(netdev->name, "eth%d");
+ err = register_netdev(netdev);
+ if (err)
+ goto err_register;
+
+ e1000_print_device_info(adapter);
+
+ return 0;
+
+err_register:
+err_hw_init:
+ e1000_release_hw_control(adapter);
+err_eeprom:
+ if (!e1000_check_reset_block(&adapter->hw))
+ e1000_phy_hw_reset(&adapter->hw);
+
+ if (adapter->hw.flash_address)
+ iounmap(adapter->hw.flash_address);
+
+err_flashmap:
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+err_sw_init:
+ iounmap(adapter->hw.hw_addr);
+err_ioremap:
+ free_netdev(netdev);
+err_alloc_etherdev:
+ pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+ pci_disable_device(pdev);
+ return err;
+}
+
+/**
+ * e1000_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * e1000_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit e1000_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ /* flush_scheduled work may reschedule our watchdog task, so
+ * explicitly disable watchdog tasks from being rescheduled */
+ set_bit(__E1000_DOWN, &adapter->state);
+ del_timer_sync(&adapter->watchdog_timer);
+ del_timer_sync(&adapter->phy_info_timer);
+
+ flush_scheduled_work();
+
+ e1000_release_manageability(adapter);
+
+ /* Release control of h/w to f/w. If f/w is AMT enabled, this
+ * would have already happened in close and is redundant. */
+ e1000_release_hw_control(adapter);
+
+ unregister_netdev(netdev);
+
+ if (!e1000_check_reset_block(&adapter->hw))
+ e1000_phy_hw_reset(&adapter->hw);
+
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+
+ iounmap(adapter->hw.hw_addr);
+ if (adapter->hw.flash_address)
+ iounmap(adapter->hw.flash_address);
+ pci_release_regions(pdev);
+
+ free_netdev(netdev);
+
+ pci_disable_device(pdev);
+}
+
+/* PCI Error Recovery (ERS) */
+static struct pci_error_handlers e1000_err_handler = {
+ .error_detected = e1000_io_error_detected,
+ .slot_reset = e1000_io_slot_reset,
+ .resume = e1000_io_resume,
+};
+
+static struct pci_device_id e1000_pci_tbl[] = {
+ /*
+ * Support for 82571/2/3, es2lan and ich8 will be phased in
+ * stepwise.
+
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP), board_82571 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER), board_82571 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES), board_82571 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI), board_82572 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_COPPER), board_82572 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_FIBER), board_82572 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_SERDES), board_82572 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E), board_82573 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT),
+ board_80003es2lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT),
+ board_80003es2lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_DPT),
+ board_80003es2lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_SPT),
+ board_80003es2lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE), board_ich8lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_G), board_ich8lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_GT), board_ich8lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_AMT), board_ich8lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_C), board_ich8lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M), board_ich8lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M_AMT), board_ich8lan },
+ */
+
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE), board_ich9lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_G), board_ich9lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT), board_ich9lan },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C), board_ich9lan },
+
+ { } /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
+
+/* PCI Device API Driver */
+static struct pci_driver e1000_driver = {
+ .name = e1000e_driver_name,
+ .id_table = e1000_pci_tbl,
+ .probe = e1000_probe,
+ .remove = __devexit_p(e1000_remove),
+#ifdef CONFIG_PM
+ /* Power Managment Hooks */
+ .suspend = e1000_suspend,
+ .resume = e1000_resume,
+#endif
+ .shutdown = e1000_shutdown,
+ .err_handler = &e1000_err_handler
+};
+
+/**
+ * e1000_init_module - Driver Registration Routine
+ *
+ * e1000_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+static int __init e1000_init_module(void)
+{
+ int ret;
+ printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Driver - %s\n",
+ e1000e_driver_name, e1000e_driver_version);
+ printk(KERN_INFO "%s: Copyright (c) 1999-2007 Intel Corporation.\n",
+ e1000e_driver_name);
+ ret = pci_register_driver(&e1000_driver);
+
+ return ret;
+}
+module_init(e1000_init_module);
+
+/**
+ * e1000_exit_module - Driver Exit Cleanup Routine
+ *
+ * e1000_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+static void __exit e1000_exit_module(void)
+{
+ pci_unregister_driver(&e1000_driver);
+}
+module_exit(e1000_exit_module);
+
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+/* e1000_main.c */
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c
new file mode 100644
index 00000000000..332789238b9
--- /dev/null
+++ b/drivers/net/e1000e/param.c
@@ -0,0 +1,383 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/netdevice.h>
+
+#include "e1000.h"
+
+/* This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+
+#define E1000_MAX_NIC 32
+
+#define OPTION_UNSET -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED 1
+
+#define COPYBREAK_DEFAULT 256
+unsigned int copybreak = COPYBREAK_DEFAULT;
+module_param(copybreak, uint, 0644);
+MODULE_PARM_DESC(copybreak,
+ "Maximum size of packet that is copied to a new buffer on receive");
+
+/* All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+
+#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
+#define E1000_PARAM(X, desc) \
+ static int __devinitdata X[E1000_MAX_NIC+1] \
+ = E1000_PARAM_INIT; \
+ static unsigned int num_##X; \
+ module_param_array_named(X, X, int, &num_##X, 0); \
+ MODULE_PARM_DESC(X, desc);
+
+
+/* Transmit Interrupt Delay in units of 1.024 microseconds
+ * Tx interrupt delay needs to typically be set to something non zero
+ *
+ * Valid Range: 0-65535
+ */
+E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
+#define DEFAULT_TIDV 8
+#define MAX_TXDELAY 0xFFFF
+#define MIN_TXDELAY 0
+
+/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ */
+E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay");
+#define DEFAULT_TADV 32
+#define MAX_TXABSDELAY 0xFFFF
+#define MIN_TXABSDELAY 0
+
+/* Receive Interrupt Delay in units of 1.024 microseconds
+ * hardware will likely hang if you set this to anything but zero.
+ *
+ * Valid Range: 0-65535
+ */
+E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
+#define DEFAULT_RDTR 0
+#define MAX_RXDELAY 0xFFFF
+#define MIN_RXDELAY 0
+
+/* Receive Absolute Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ */
+E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
+#define DEFAULT_RADV 8
+#define MAX_RXABSDELAY 0xFFFF
+#define MIN_RXABSDELAY 0
+
+/* Interrupt Throttle Rate (interrupts/sec)
+ *
+ * Valid Range: 100-100000 (0=off, 1=dynamic, 3=dynamic conservative)
+ */
+E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
+#define DEFAULT_ITR 3
+#define MAX_ITR 100000
+#define MIN_ITR 100
+
+/* Enable Smart Power Down of the PHY
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 0 (disabled)
+ */
+E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
+
+/* Enable Kumeran Lock Loss workaround
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 1 (enabled)
+ */
+E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
+
+struct e1000_option {
+ enum { enable_option, range_option, list_option } type;
+ const char *name;
+ const char *err;
+ int def;
+ union {
+ struct { /* range_option info */
+ int min;
+ int max;
+ } r;
+ struct { /* list_option info */
+ int nr;
+ struct e1000_opt_list { int i; char *str; } *p;
+ } l;
+ } arg;
+};
+
+static int __devinit e1000_validate_option(unsigned int *value,
+ const struct e1000_option *opt,
+ struct e1000_adapter *adapter)
+{
+ if (*value == OPTION_UNSET) {
+ *value = opt->def;
+ return 0;
+ }
+
+ switch (opt->type) {
+ case enable_option:
+ switch (*value) {
+ case OPTION_ENABLED:
+ ndev_info(adapter->netdev, "%s Enabled\n", opt->name);
+ return 0;
+ case OPTION_DISABLED:
+ ndev_info(adapter->netdev, "%s Disabled\n", opt->name);
+ return 0;
+ }
+ break;
+ case range_option:
+ if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+ ndev_info(adapter->netdev,
+ "%s set to %i\n", opt->name, *value);
+ return 0;
+ }
+ break;
+ case list_option: {
+ int i;
+ struct e1000_opt_list *ent;
+
+ for (i = 0; i < opt->arg.l.nr; i++) {
+ ent = &opt->arg.l.p[i];
+ if (*value == ent->i) {
+ if (ent->str[0] != '\0')
+ ndev_info(adapter->netdev, "%s\n",
+ ent->str);
+ return 0;
+ }
+ }
+ }
+ break;
+ default:
+ BUG();
+ }
+
+ ndev_info(adapter->netdev, "Invalid %s value specified (%i) %s\n",
+ opt->name, *value, opt->err);
+ *value = opt->def;
+ return -1;
+}
+
+/**
+ * e1000e_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line parameters for valid user
+ * input. If an invalid value is given, or if no user specified
+ * value exists, a default value is used. The final value is stored
+ * in a variable in the adapter structure.
+ **/
+void __devinit e1000e_check_options(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ int bd = adapter->bd_number;
+
+ if (bd >= E1000_MAX_NIC) {
+ ndev_notice(netdev,
+ "Warning: no configuration for board #%i\n", bd);
+ ndev_notice(netdev, "Using defaults for all values\n");
+ }
+
+ { /* Transmit Interrupt Delay */
+ const struct e1000_option opt = {
+ .type = range_option,
+ .name = "Transmit Interrupt Delay",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_TIDV),
+ .def = DEFAULT_TIDV,
+ .arg = { .r = { .min = MIN_TXDELAY,
+ .max = MAX_TXDELAY } }
+ };
+
+ if (num_TxIntDelay > bd) {
+ adapter->tx_int_delay = TxIntDelay[bd];
+ e1000_validate_option(&adapter->tx_int_delay, &opt,
+ adapter);
+ } else {
+ adapter->tx_int_delay = opt.def;
+ }
+ }
+ { /* Transmit Absolute Interrupt Delay */
+ const struct e1000_option opt = {
+ .type = range_option,
+ .name = "Transmit Absolute Interrupt Delay",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_TADV),
+ .def = DEFAULT_TADV,
+ .arg = { .r = { .min = MIN_TXABSDELAY,
+ .max = MAX_TXABSDELAY } }
+ };
+
+ if (num_TxAbsIntDelay > bd) {
+ adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
+ e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
+ adapter);
+ } else {
+ adapter->tx_abs_int_delay = opt.def;
+ }
+ }
+ { /* Receive Interrupt Delay */
+ struct e1000_option opt = {
+ .type = range_option,
+ .name = "Receive Interrupt Delay",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_RDTR),
+ .def = DEFAULT_RDTR,
+ .arg = { .r = { .min = MIN_RXDELAY,
+ .max = MAX_RXDELAY } }
+ };
+
+ /* modify min and default if 82573 for slow ping w/a,
+ * a value greater than 8 needs to be set for RDTR */
+ if (adapter->flags & FLAG_HAS_ASPM) {
+ opt.def = 32;
+ opt.arg.r.min = 8;
+ }
+
+ if (num_RxIntDelay > bd) {
+ adapter->rx_int_delay = RxIntDelay[bd];
+ e1000_validate_option(&adapter->rx_int_delay, &opt,
+ adapter);
+ } else {
+ adapter->rx_int_delay = opt.def;
+ }
+ }
+ { /* Receive Absolute Interrupt Delay */
+ const struct e1000_option opt = {
+ .type = range_option,
+ .name = "Receive Absolute Interrupt Delay",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_RADV),
+ .def = DEFAULT_RADV,
+ .arg = { .r = { .min = MIN_RXABSDELAY,
+ .max = MAX_RXABSDELAY } }
+ };
+
+ if (num_RxAbsIntDelay > bd) {
+ adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
+ e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
+ adapter);
+ } else {
+ adapter->rx_abs_int_delay = opt.def;
+ }
+ }
+ { /* Interrupt Throttling Rate */
+ const struct e1000_option opt = {
+ .type = range_option,
+ .name = "Interrupt Throttling Rate (ints/sec)",
+ .err = "using default of "
+ __MODULE_STRING(DEFAULT_ITR),
+ .def = DEFAULT_ITR,
+ .arg = { .r = { .min = MIN_ITR,
+ .max = MAX_ITR } }
+ };
+
+ if (num_InterruptThrottleRate > bd) {
+ adapter->itr = InterruptThrottleRate[bd];
+ switch (adapter->itr) {
+ case 0:
+ ndev_info(netdev, "%s turned off\n",
+ opt.name);
+ break;
+ case 1:
+ ndev_info(netdev,
+ "%s set to dynamic mode\n",
+ opt.name);
+ adapter->itr_setting = adapter->itr;
+ adapter->itr = 20000;
+ break;
+ case 3:
+ ndev_info(netdev,
+ "%s set to dynamic conservative mode\n",
+ opt.name);
+ adapter->itr_setting = adapter->itr;
+ adapter->itr = 20000;
+ break;
+ default:
+ e1000_validate_option(&adapter->itr, &opt,
+ adapter);
+ /*
+ * save the setting, because the dynamic bits
+ * change itr. clear the lower two bits
+ * because they are used as control
+ */
+ adapter->itr_setting = adapter->itr & ~3;
+ break;
+ }
+ } else {
+ adapter->itr_setting = opt.def;
+ adapter->itr = 20000;
+ }
+ }
+ { /* Smart Power Down */
+ const struct e1000_option opt = {
+ .type = enable_option,
+ .name = "PHY Smart Power Down",
+ .err = "defaulting to Disabled",
+ .def = OPTION_DISABLED
+ };
+
+ if (num_SmartPowerDownEnable > bd) {
+ unsigned int spd = SmartPowerDownEnable[bd];
+ e1000_validate_option(&spd, &opt, adapter);
+ if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN)
+ && spd)
+ adapter->flags |= FLAG_SMART_POWER_DOWN;
+ }
+ }
+ { /* Kumeran Lock Loss Workaround */
+ const struct e1000_option opt = {
+ .type = enable_option,
+ .name = "Kumeran Lock Loss Workaround",
+ .err = "defaulting to Enabled",
+ .def = OPTION_ENABLED
+ };
+
+ if (num_KumeranLockLoss > bd) {
+ unsigned int kmrn_lock_loss = KumeranLockLoss[bd];
+ e1000_validate_option(&kmrn_lock_loss, &opt, adapter);
+ if (hw->mac.type == e1000_ich8lan)
+ e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw,
+ kmrn_lock_loss);
+ } else {
+ if (hw->mac.type == e1000_ich8lan)
+ e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw,
+ opt.def);
+ }
+ }
+}
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
new file mode 100644
index 00000000000..793231810ae
--- /dev/null
+++ b/drivers/net/e1000e/phy.c
@@ -0,0 +1,1773 @@
+/*******************************************************************************
+
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/delay.h>
+
+#include "e1000.h"
+
+static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw);
+static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw);
+static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active);
+static s32 e1000_wait_autoneg(struct e1000_hw *hw);
+
+/* Cable length tables */
+static const u16 e1000_m88_cable_length_table[] =
+ { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+
+static const u16 e1000_igp_2_cable_length_table[] =
+ { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, 0, 0, 0, 3,
+ 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, 6, 10, 14, 18, 22,
+ 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, 21, 26, 31, 35, 40,
+ 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, 40, 45, 51, 56, 61,
+ 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, 60, 66, 72, 77, 82,
+ 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, 83, 89, 95,
+ 100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121,
+ 124};
+#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
+ (sizeof(e1000_igp_2_cable_length_table) / \
+ sizeof(e1000_igp_2_cable_length_table[0]))
+
+/**
+ * e1000e_check_reset_block_generic - Check if PHY reset is blocked
+ * @hw: pointer to the HW structure
+ *
+ * Read the PHY management control register and check whether a PHY reset
+ * is blocked. If a reset is not blocked return 0, otherwise
+ * return E1000_BLK_PHY_RESET (12).
+ **/
+s32 e1000e_check_reset_block_generic(struct e1000_hw *hw)
+{
+ u32 manc;
+
+ manc = er32(MANC);
+
+ return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+ E1000_BLK_PHY_RESET : 0;
+}
+
+/**
+ * e1000e_get_phy_id - Retrieve the PHY ID and revision
+ * @hw: pointer to the HW structure
+ *
+ * Reads the PHY registers and stores the PHY ID and possibly the PHY
+ * revision in the hardware structure.
+ **/
+s32 e1000e_get_phy_id(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_id;
+
+ ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
+ if (ret_val)
+ return ret_val;
+
+ phy->id = (u32)(phy_id << 16);
+ udelay(20);
+ ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
+ if (ret_val)
+ return ret_val;
+
+ phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
+ phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+
+ return 0;
+}
+
+/**
+ * e1000e_phy_reset_dsp - Reset PHY DSP
+ * @hw: pointer to the HW structure
+ *
+ * Reset the digital signal processor.
+ **/
+s32 e1000e_phy_reset_dsp(struct e1000_hw *hw)
+{
+ s32 ret_val;
+
+ ret_val = e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
+ if (ret_val)
+ return ret_val;
+
+ return e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0);
+}
+
+/**
+ * e1000_read_phy_reg_mdic - Read MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Reads the MDI control regsiter in the PHY at offset and stores the
+ * information read to data.
+ **/
+static s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ u32 i, mdic = 0;
+
+ if (offset > MAX_PHY_REG_ADDRESS) {
+ hw_dbg(hw, "PHY Address %d is out of range\n", offset);
+ return -E1000_ERR_PARAM;
+ }
+
+ /* Set up Op-code, Phy Address, and register offset in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+ (phy->addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_READ));
+
+ ew32(MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for (i = 0; i < 64; i++) {
+ udelay(50);
+ mdic = er32(MDIC);
+ if (mdic & E1000_MDIC_READY)
+ break;
+ }
+ if (!(mdic & E1000_MDIC_READY)) {
+ hw_dbg(hw, "MDI Read did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if (mdic & E1000_MDIC_ERROR) {
+ hw_dbg(hw, "MDI Error\n");
+ return -E1000_ERR_PHY;
+ }
+ *data = (u16) mdic;
+
+ return 0;
+}
+
+/**
+ * e1000_write_phy_reg_mdic - Write MDI control register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write to register at offset
+ *
+ * Writes data to MDI control register in the PHY at offset.
+ **/
+static s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ u32 i, mdic = 0;
+
+ if (offset > MAX_PHY_REG_ADDRESS) {
+ hw_dbg(hw, "PHY Address %d is out of range\n", offset);
+ return -E1000_ERR_PARAM;
+ }
+
+ /* Set up Op-code, Phy Address, and register offset in the MDI
+ * Control register. The MAC will take care of interfacing with the
+ * PHY to retrieve the desired data.
+ */
+ mdic = (((u32)data) |
+ (offset << E1000_MDIC_REG_SHIFT) |
+ (phy->addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_WRITE));
+
+ ew32(MDIC, mdic);
+
+ /* Poll the ready bit to see if the MDI read completed */
+ for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) {
+ udelay(5);
+ mdic = er32(MDIC);
+ if (mdic & E1000_MDIC_READY)
+ break;
+ }
+ if (!(mdic & E1000_MDIC_READY)) {
+ hw_dbg(hw, "MDI Write did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+
+ return 0;
+}
+
+/**
+ * e1000e_read_phy_reg_m88 - Read m88 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data. Release any acquired
+ * semaphores before exiting.
+ **/
+s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ s32 ret_val;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release_phy(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_write_phy_reg_m88 - Write m88 PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ s32 ret_val;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release_phy(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_read_phy_reg_igp - Read igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore, if necessary, then reads the PHY register at offset
+ * and storing the retrieved information in data. Release any acquired
+ * semaphores before exiting.
+ **/
+s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ s32 ret_val;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (u16)offset);
+ if (ret_val) {
+ hw->phy.ops.release_phy(hw);
+ return ret_val;
+ }
+ }
+
+ ret_val = e1000_read_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release_phy(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_write_phy_reg_igp - Write igp PHY register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ s32 ret_val;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ if (offset > MAX_PHY_MULTI_PAGE_REG) {
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ IGP01E1000_PHY_PAGE_SELECT,
+ (u16)offset);
+ if (ret_val) {
+ hw->phy.ops.release_phy(hw);
+ return ret_val;
+ }
+ }
+
+ ret_val = e1000_write_phy_reg_mdic(hw,
+ MAX_PHY_REG_ADDRESS & offset,
+ data);
+
+ hw->phy.ops.release_phy(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_read_kmrn_reg - Read kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to be read
+ * @data: pointer to the read data
+ *
+ * Acquires semaphore, if necessary. Then reads the PHY register at offset
+ * using the kumeran interface. The information retrieved is stored in data.
+ * Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ u32 kmrnctrlsta;
+ s32 ret_val;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+ E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+ ew32(KMRNCTRLSTA, kmrnctrlsta);
+
+ udelay(2);
+
+ kmrnctrlsta = er32(KMRNCTRLSTA);
+ *data = (u16)kmrnctrlsta;
+
+ hw->phy.ops.release_phy(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_write_kmrn_reg - Write kumeran register
+ * @hw: pointer to the HW structure
+ * @offset: register offset to write to
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary. Then write the data to PHY register
+ * at the offset using the kumeran interface. Release any acquired semaphores
+ * before exiting.
+ **/
+s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ u32 kmrnctrlsta;
+ s32 ret_val;
+
+ ret_val = hw->phy.ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+ E1000_KMRNCTRLSTA_OFFSET) | data;
+ ew32(KMRNCTRLSTA, kmrnctrlsta);
+
+ udelay(2);
+ hw->phy.ops.release_phy(hw);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_copper_link_setup_m88 - Setup m88 PHY's for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock
+ * and downshift values are set also.
+ **/
+s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data;
+
+ /* Enable CRS on TX. This must be set for half-duplex operation. */
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+ /* Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+ switch (phy->mdix) {
+ case 1:
+ phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+ break;
+ case 2:
+ phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+ break;
+ case 3:
+ phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+ break;
+ case 0:
+ default:
+ phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+ break;
+ }
+
+ /* Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+ if (phy->disable_polarity_correction == 1)
+ phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+
+ ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ if (phy->revision < 4) {
+ /* Force TX_CLK in the Extended PHY Specific Control Register
+ * to 25MHz clock.
+ */
+ ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+ if ((phy->revision == 2) &&
+ (phy->id == M88E1111_I_PHY_ID)) {
+ /* 82573L PHY - set the downshift counter to 5x. */
+ phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
+ phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+ } else {
+ /* Configure Master and Slave downshift values */
+ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+ }
+ ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Commit the changes. */
+ ret_val = e1000e_commit_phy(hw);
+ if (ret_val)
+ hw_dbg(hw, "Error committing the PHY changes\n");
+
+ return ret_val;
+}
+
+/**
+ * e1000e_copper_link_setup_igp - Setup igp PHY's for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
+ * igp PHY's.
+ **/
+s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+
+ ret_val = e1000_phy_hw_reset(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error resetting the PHY.\n");
+ return ret_val;
+ }
+
+ /* Wait 15ms for MAC to configure PHY from NVM settings. */
+ msleep(15);
+
+ /* disable lplu d0 during driver init */
+ ret_val = e1000_set_d0_lplu_state(hw, 0);
+ if (ret_val) {
+ hw_dbg(hw, "Error Disabling LPLU D0\n");
+ return ret_val;
+ }
+ /* Configure mdi-mdix settings */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+ switch (phy->mdix) {
+ case 1:
+ data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 2:
+ data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+ break;
+ case 0:
+ default:
+ data |= IGP01E1000_PSCR_AUTO_MDIX;
+ break;
+ }
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, data);
+ if (ret_val)
+ return ret_val;
+
+ /* set auto-master slave resolution settings */
+ if (hw->mac.autoneg) {
+ /* when autonegotiation advertisement is only 1000Mbps then we
+ * should disable SmartSpeed and enable Auto MasterSlave
+ * resolution as hardware default. */
+ if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
+ /* Disable SmartSpeed */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+
+ /* Set auto Master/Slave resolution process */
+ ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~CR_1000T_MS_ENABLE;
+ ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
+ if (ret_val)
+ return ret_val;
+ }
+
+ ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
+ if (ret_val)
+ return ret_val;
+
+ /* load defaults for future use */
+ phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
+ ((data & CR_1000T_MS_VALUE) ?
+ e1000_ms_force_master :
+ e1000_ms_force_slave) :
+ e1000_ms_auto;
+
+ switch (phy->ms_type) {
+ case e1000_ms_force_master:
+ data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_force_slave:
+ data |= CR_1000T_MS_ENABLE;
+ data &= ~(CR_1000T_MS_VALUE);
+ break;
+ case e1000_ms_auto:
+ data &= ~CR_1000T_MS_ENABLE;
+ default:
+ break;
+ }
+ ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
+ * @hw: pointer to the HW structure
+ *
+ * Reads the MII auto-neg advertisement register and/or the 1000T control
+ * register and if the PHY is already setup for auto-negotiation, then
+ * return successful. Otherwise, setup advertisement and flow control to
+ * the appropriate values for the wanted auto-negotiation.
+ **/
+static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 mii_autoneg_adv_reg;
+ u16 mii_1000t_ctrl_reg = 0;
+
+ phy->autoneg_advertised &= phy->autoneg_mask;
+
+ /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+ ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+ if (ret_val)
+ return ret_val;
+
+ if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Need to parse both autoneg_advertised and fc and set up
+ * the appropriate PHY registers. First we will parse for
+ * autoneg_advertised software override. Since we can advertise
+ * a plethora of combinations, we need to check each bit
+ * individually.
+ */
+
+ /* First we clear all the 10/100 mb speed bits in the Auto-Neg
+ * Advertisement Register (Address 4) and the 1000 mb speed bits in
+ * the 1000Base-T Control Register (Address 9).
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
+ NWAY_AR_100TX_HD_CAPS |
+ NWAY_AR_10T_FD_CAPS |
+ NWAY_AR_10T_HD_CAPS);
+ mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+
+ hw_dbg(hw, "autoneg_advertised %x\n", phy->autoneg_advertised);
+
+ /* Do we want to advertise 10 Mb Half Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
+ hw_dbg(hw, "Advertise 10mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+ }
+
+ /* Do we want to advertise 10 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
+ hw_dbg(hw, "Advertise 10mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Half Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
+ hw_dbg(hw, "Advertise 100mb Half duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+ }
+
+ /* Do we want to advertise 100 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
+ hw_dbg(hw, "Advertise 100mb Full duplex\n");
+ mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+ }
+
+ /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+ if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
+ hw_dbg(hw, "Advertise 1000mb Half duplex request denied!\n");
+
+ /* Do we want to advertise 1000 Mb Full Duplex? */
+ if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
+ hw_dbg(hw, "Advertise 1000mb Full duplex\n");
+ mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+ }
+
+ /* Check for a software override of the flow control settings, and
+ * setup the PHY advertisement registers accordingly. If
+ * auto-negotiation is enabled, then software will have to set the
+ * "PAUSE" bits to the correct value in the Auto-Negotiation
+ * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+ * negotiation.
+ *
+ * The possible values of the "fc" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames
+ * but not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames
+ * but we do not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ * other: No software override. The flow control configuration
+ * in the EEPROM is used.
+ */
+ switch (hw->mac.fc) {
+ case e1000_fc_none:
+ /* Flow control (RX & TX) is completely disabled by a
+ * software over-ride.
+ */
+ mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_rx_pause:
+ /* RX Flow control is enabled, and TX Flow control is
+ * disabled, by a software over-ride.
+ */
+ /* Since there really isn't a way to advertise that we are
+ * capable of RX Pause ONLY, we will advertise that we
+ * support both symmetric and asymmetric RX PAUSE. Later
+ * (in e1000e_config_fc_after_link_up) we will disable the
+ * hw's ability to send PAUSE frames.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ case e1000_fc_tx_pause:
+ /* TX Flow control is enabled, and RX Flow control is
+ * disabled, by a software over-ride.
+ */
+ mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+ mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+ break;
+ case e1000_fc_full:
+ /* Flow control (both RX and TX) is enabled by a software
+ * over-ride.
+ */
+ mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+ break;
+ default:
+ hw_dbg(hw, "Flow control param set incorrectly\n");
+ ret_val = -E1000_ERR_CONFIG;
+ return ret_val;
+ }
+
+ ret_val = e1e_wphy(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+ if (ret_val)
+ return ret_val;
+
+ hw_dbg(hw, "Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+ if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+ ret_val = e1e_wphy(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
+ * @hw: pointer to the HW structure
+ *
+ * Performs initial bounds checking on autoneg advertisement parameter, then
+ * configure to advertise the full capability. Setup the PHY to autoneg
+ * and restart the negotiation process between the link partner. If
+ * wait_for_link, then wait for autoneg to complete before exiting.
+ **/
+static s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_ctrl;
+
+ /* Perform some bounds checking on the autoneg advertisement
+ * parameter.
+ */
+ phy->autoneg_advertised &= phy->autoneg_mask;
+
+ /* If autoneg_advertised is zero, we assume it was not defaulted
+ * by the calling code so we set to advertise full capability.
+ */
+ if (phy->autoneg_advertised == 0)
+ phy->autoneg_advertised = phy->autoneg_mask;
+
+ hw_dbg(hw, "Reconfiguring auto-neg advertisement params\n");
+ ret_val = e1000_phy_setup_autoneg(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error Setting up Auto-Negotiation\n");
+ return ret_val;
+ }
+ hw_dbg(hw, "Restarting Auto-Neg\n");
+
+ /* Restart auto-negotiation by setting the Auto Neg Enable bit and
+ * the Auto Neg Restart bit in the PHY control register.
+ */
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+ ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ /* Does the user want to wait for Auto-Neg to complete here, or
+ * check at a later time (for example, callback routine).
+ */
+ if (phy->wait_for_link) {
+ ret_val = e1000_wait_autoneg(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error while waiting for "
+ "autoneg to complete\n");
+ return ret_val;
+ }
+ }
+
+ hw->mac.get_link_status = 1;
+
+ return ret_val;
+}
+
+/**
+ * e1000e_setup_copper_link - Configure copper link settings
+ * @hw: pointer to the HW structure
+ *
+ * Calls the appropriate function to configure the link for auto-neg or forced
+ * speed and duplex. Then we check for link, once link is established calls
+ * to configure collision distance and flow control are called. If link is
+ * not established, we return -E1000_ERR_PHY (-2).
+ **/
+s32 e1000e_setup_copper_link(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ bool link;
+
+ if (hw->mac.autoneg) {
+ /* Setup autoneg and flow control advertisement and perform
+ * autonegotiation. */
+ ret_val = e1000_copper_link_autoneg(hw);
+ if (ret_val)
+ return ret_val;
+ } else {
+ /* PHY will be set to 10H, 10F, 100H or 100F
+ * depending on user settings. */
+ hw_dbg(hw, "Forcing Speed and Duplex\n");
+ ret_val = e1000_phy_force_speed_duplex(hw);
+ if (ret_val) {
+ hw_dbg(hw, "Error Forcing Speed and Duplex\n");
+ return ret_val;
+ }
+ }
+
+ /* Check link status. Wait up to 100 microseconds for link to become
+ * valid.
+ */
+ ret_val = e1000e_phy_has_link_generic(hw,
+ COPPER_LINK_UP_LIMIT,
+ 10,
+ &link);
+ if (ret_val)
+ return ret_val;
+
+ if (link) {
+ hw_dbg(hw, "Valid link established!!!\n");
+ e1000e_config_collision_dist(hw);
+ ret_val = e1000e_config_fc_after_link_up(hw);
+ } else {
+ hw_dbg(hw, "Unable to establish link!!!\n");
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
+ * @hw: pointer to the HW structure
+ *
+ * Calls the PHY setup function to force speed and duplex. Clears the
+ * auto-crossover to force MDI manually. Waits for link and returns
+ * successful if link up is successful, else -E1000_ERR_PHY (-2).
+ **/
+s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data;
+ bool link;
+
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Clear Auto-Crossover to force MDI manually. IGP requires MDI
+ * forced whenever speed and duplex are forced.
+ */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+ phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ hw_dbg(hw, "IGP PSCR: %X\n", phy_data);
+
+ udelay(1);
+
+ if (phy->wait_for_link) {
+ hw_dbg(hw, "Waiting for forced speed/duplex link on IGP phy.\n");
+
+ ret_val = e1000e_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link)
+ hw_dbg(hw, "Link taking longer than expected.\n");
+
+ /* Try once more */
+ ret_val = e1000e_phy_has_link_generic(hw,
+ PHY_FORCE_LIMIT,
+ 100000,
+ &link);
+ if (ret_val)
+ return ret_val;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Calls the PHY setup function to force speed and duplex. Clears the
+ * auto-crossover to force MDI manually. Resets the PHY to commit the
+ * changes. If time expires while waiting for link up, we reset the DSP.
+ * After reset, TX_CLK and CRS on TX must be set. Return successful upon
+ * successful completion, else return corresponding error code.
+ **/
+s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data;
+ bool link;
+
+ /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+ * forced whenever speed and duplex are forced.
+ */
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+ ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ hw_dbg(hw, "M88E1000 PSCR: %X\n", phy_data);
+
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+ /* Reset the phy to commit changes. */
+ phy_data |= MII_CR_RESET;
+
+ ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ udelay(1);
+
+ if (phy->wait_for_link) {
+ hw_dbg(hw, "Waiting for forced speed/duplex link on M88 phy.\n");
+
+ ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link) {
+ /* We didn't get link.
+ * Reset the DSP and cross our fingers.
+ */
+ ret_val = e1e_wphy(hw, M88E1000_PHY_PAGE_SELECT, 0x001d);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000e_phy_reset_dsp(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
+ /* Try once more */
+ ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+ 100000, &link);
+ if (ret_val)
+ return ret_val;
+ }
+
+ ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Resetting the phy means we need to re-force TX_CLK in the
+ * Extended PHY Specific Control Register to 25MHz clock from
+ * the reset value of 2.5MHz.
+ */
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+ ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* In addition, we must re-enable CRS on Tx for both half and full
+ * duplex.
+ */
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
+ * @hw: pointer to the HW structure
+ * @phy_ctrl: pointer to current value of PHY_CONTROL
+ *
+ * Forces speed and duplex on the PHY by doing the following: disable flow
+ * control, force speed/duplex on the MAC, disable auto speed detection,
+ * disable auto-negotiation, configure duplex, configure speed, configure
+ * the collision distance, write configuration to CTRL register. The
+ * caller must write to the PHY_CONTROL register for these settings to
+ * take affect.
+ **/
+void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
+{
+ struct e1000_mac_info *mac = &hw->mac;
+ u32 ctrl;
+
+ /* Turn off flow control when forcing speed/duplex */
+ mac->fc = e1000_fc_none;
+
+ /* Force speed/duplex on the mac */
+ ctrl = er32(CTRL);
+ ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ ctrl &= ~E1000_CTRL_SPD_SEL;
+
+ /* Disable Auto Speed Detection */
+ ctrl &= ~E1000_CTRL_ASDE;
+
+ /* Disable autoneg on the phy */
+ *phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+
+ /* Forcing Full or Half Duplex? */
+ if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
+ ctrl &= ~E1000_CTRL_FD;
+ *phy_ctrl &= ~MII_CR_FULL_DUPLEX;
+ hw_dbg(hw, "Half Duplex\n");
+ } else {
+ ctrl |= E1000_CTRL_FD;
+ *phy_ctrl |= MII_CR_FULL_DUPLEX;
+ hw_dbg(hw, "Full Duplex\n");
+ }
+
+ /* Forcing 10mb or 100mb? */
+ if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
+ ctrl |= E1000_CTRL_SPD_100;
+ *phy_ctrl |= MII_CR_SPEED_100;
+ *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+ hw_dbg(hw, "Forcing 100mb\n");
+ } else {
+ ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+ *phy_ctrl |= MII_CR_SPEED_10;
+ *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+ hw_dbg(hw, "Forcing 10mb\n");
+ }
+
+ e1000e_config_collision_dist(hw);
+
+ ew32(CTRL, ctrl);
+}
+
+/**
+ * e1000e_set_d3_lplu_state - Sets low power link up state for D3
+ * @hw: pointer to the HW structure
+ * @active: boolean used to enable/disable lplu
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * The low power link up (lplu) state is set to the power management level D3
+ * and SmartSpeed is disabled when active is true, else clear lplu for D3
+ * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
+ * is used during Dx states where the power conservation is most important.
+ * During driver activity, SmartSpeed should be enabled so performance is
+ * maintained.
+ **/
+s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+
+ ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+ if (ret_val)
+ return ret_val;
+
+ if (!active) {
+ data &= ~IGP02E1000_PM_D3_LPLU;
+ ret_val = e1e_wphy(hw,
+ IGP02E1000_PHY_POWER_MGMT,
+ data);
+ if (ret_val)
+ return ret_val;
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained. */
+ if (phy->smart_speed == e1000_smart_speed_on) {
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data |= IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ } else if (phy->smart_speed == e1000_smart_speed_off) {
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+ data);
+ if (ret_val)
+ return ret_val;
+ }
+ } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+ (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+ (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+ data |= IGP02E1000_PM_D3_LPLU;
+ ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
+ if (ret_val)
+ return ret_val;
+
+ /* When LPLU is enabled, we should disable SmartSpeed */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+ if (ret_val)
+ return ret_val;
+
+ data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+ ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_check_downshift - Checks whether a downshift in speed occured
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * A downshift is detected by querying the PHY link health.
+ **/
+s32 e1000e_check_downshift(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data, offset, mask;
+
+ switch (phy->type) {
+ case e1000_phy_m88:
+ case e1000_phy_gg82563:
+ offset = M88E1000_PHY_SPEC_STATUS;
+ mask = M88E1000_PSSR_DOWNSHIFT;
+ break;
+ case e1000_phy_igp_2:
+ case e1000_phy_igp_3:
+ offset = IGP01E1000_PHY_LINK_HEALTH;
+ mask = IGP01E1000_PLHR_SS_DOWNGRADE;
+ break;
+ default:
+ /* speed downshift not supported */
+ phy->speed_downgraded = 0;
+ return 0;
+ }
+
+ ret_val = e1e_rphy(hw, offset, &phy_data);
+
+ if (!ret_val)
+ phy->speed_downgraded = (phy_data & mask);
+
+ return ret_val;
+}
+
+/**
+ * e1000_check_polarity_m88 - Checks the polarity.
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ * Polarity is determined based on the PHY specific status register.
+ **/
+static s32 e1000_check_polarity_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &data);
+
+ if (!ret_val)
+ phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+ return ret_val;
+}
+
+/**
+ * e1000_check_polarity_igp - Checks the polarity.
+ * @hw: pointer to the HW structure
+ *
+ * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ * Polarity is determined based on the PHY port status register, and the
+ * current speed (since there is no polarity at 100Mbps).
+ **/
+static s32 e1000_check_polarity_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data, offset, mask;
+
+ /* Polarity is determined based on the speed of
+ * our connection. */
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+ if (ret_val)
+ return ret_val;
+
+ if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+ offset = IGP01E1000_PHY_PCS_INIT_REG;
+ mask = IGP01E1000_PHY_POLARITY_MASK;
+ } else {
+ /* This really only applies to 10Mbps since
+ * there is no polarity for 100Mbps (always 0).
+ */
+ offset = IGP01E1000_PHY_PORT_STATUS;
+ mask = IGP01E1000_PSSR_POLARITY_REVERSED;
+ }
+
+ ret_val = e1e_rphy(hw, offset, &data);
+
+ if (!ret_val)
+ phy->cable_polarity = (data & mask)
+ ? e1000_rev_polarity_reversed
+ : e1000_rev_polarity_normal;
+
+ return ret_val;
+}
+
+/**
+ * e1000_wait_autoneg - Wait for auto-neg compeletion
+ * @hw: pointer to the HW structure
+ *
+ * Waits for auto-negotiation to complete or for the auto-negotiation time
+ * limit to expire, which ever happens first.
+ **/
+static s32 e1000_wait_autoneg(struct e1000_hw *hw)
+{
+ s32 ret_val = 0;
+ u16 i, phy_status;
+
+ /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
+ for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
+ ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ if (phy_status & MII_SR_AUTONEG_COMPLETE)
+ break;
+ msleep(100);
+ }
+
+ /* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
+ * has completed.
+ */
+ return ret_val;
+}
+
+/**
+ * e1000e_phy_has_link_generic - Polls PHY for link
+ * @hw: pointer to the HW structure
+ * @iterations: number of times to poll for link
+ * @usec_interval: delay between polling attempts
+ * @success: pointer to whether polling was successful or not
+ *
+ * Polls the PHY status register for link, 'iterations' number of times.
+ **/
+s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+ u32 usec_interval, bool *success)
+{
+ s32 ret_val = 0;
+ u16 i, phy_status;
+
+ for (i = 0; i < iterations; i++) {
+ /* Some PHYs require the PHY_STATUS register to be read
+ * twice due to the link bit being sticky. No harm doing
+ * it across the board.
+ */
+ ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+ if (ret_val)
+ break;
+ if (phy_status & MII_SR_LINK_STATUS)
+ break;
+ if (usec_interval >= 1000)
+ mdelay(usec_interval/1000);
+ else
+ udelay(usec_interval);
+ }
+
+ *success = (i < iterations);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_get_cable_length_m88 - Determine cable length for m88 PHY
+ * @hw: pointer to the HW structure
+ *
+ * Reads the PHY specific status register to retrieve the cable length
+ * information. The cable length is determined by averaging the minimum and
+ * maximum values to get the "average" cable length. The m88 PHY has four
+ * possible cable length values, which are:
+ * Register Value Cable Length
+ * 0 < 50 meters
+ * 1 50 - 80 meters
+ * 2 80 - 110 meters
+ * 3 110 - 140 meters
+ * 4 > 140 meters
+ **/
+s32 e1000e_get_cable_length_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data, index;
+
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+ phy->min_cable_length = e1000_m88_cable_length_table[index];
+ phy->max_cable_length = e1000_m88_cable_length_table[index+1];
+
+ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+ return ret_val;
+}
+
+/**
+ * e1000e_get_cable_length_igp_2 - Determine cable length for igp2 PHY
+ * @hw: pointer to the HW structure
+ *
+ * The automatic gain control (agc) normalizes the amplitude of the
+ * received signal, adjusting for the attenuation produced by the
+ * cable. By reading the AGC registers, which reperesent the
+ * cobination of course and fine gain value, the value can be put
+ * into a lookup table to obtain the approximate cable length
+ * for each channel.
+ **/
+s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data, i, agc_value = 0;
+ u16 cur_agc_index, max_agc_index = 0;
+ u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
+ u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+ {IGP02E1000_PHY_AGC_A,
+ IGP02E1000_PHY_AGC_B,
+ IGP02E1000_PHY_AGC_C,
+ IGP02E1000_PHY_AGC_D};
+
+ /* Read the AGC registers for all channels */
+ for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+ ret_val = e1e_rphy(hw, agc_reg_array[i], &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Getting bits 15:9, which represent the combination of
+ * course and fine gain values. The result is a number
+ * that can be put into the lookup table to obtain the
+ * approximate cable length. */
+ cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+ IGP02E1000_AGC_LENGTH_MASK;
+
+ /* Array index bound check. */
+ if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
+ (cur_agc_index == 0))
+ return -E1000_ERR_PHY;
+
+ /* Remove min & max AGC values from calculation. */
+ if (e1000_igp_2_cable_length_table[min_agc_index] >
+ e1000_igp_2_cable_length_table[cur_agc_index])
+ min_agc_index = cur_agc_index;
+ if (e1000_igp_2_cable_length_table[max_agc_index] <
+ e1000_igp_2_cable_length_table[cur_agc_index])
+ max_agc_index = cur_agc_index;
+
+ agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
+ }
+
+ agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+ e1000_igp_2_cable_length_table[max_agc_index]);
+ agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+ /* Calculate cable length with the error range of +/- 10 meters. */
+ phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+ (agc_value - IGP02E1000_AGC_RANGE) : 0;
+ phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
+
+ phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+ return ret_val;
+}
+
+/**
+ * e1000e_get_phy_info_m88 - Retrieve PHY information
+ * @hw: pointer to the HW structure
+ *
+ * Valid for only copper links. Read the PHY status register (sticky read)
+ * to verify that link is up. Read the PHY special control register to
+ * determine the polarity and 10base-T extended distance. Read the PHY
+ * special status register to determine MDI/MDIx and current speed. If
+ * speed is 1000, then determine cable length, local and remote receiver.
+ **/
+s32 e1000e_get_phy_info_m88(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 phy_data;
+ bool link;
+
+ if (hw->media_type != e1000_media_type_copper) {
+ hw_dbg(hw, "Phy info is only valid for copper media\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link) {
+ hw_dbg(hw, "Phy info is only valid if link is up\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy->polarity_correction = (phy_data &
+ M88E1000_PSCR_POLARITY_REVERSAL);
+
+ ret_val = e1000_check_polarity_m88(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX);
+
+ if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+ ret_val = e1000_get_cable_length(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+
+ phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+ } else {
+ /* Set values to "undefined" */
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_get_phy_info_igp - Retrieve igp PHY information
+ * @hw: pointer to the HW structure
+ *
+ * Read PHY status to determine if link is up. If link is up, then
+ * set/determine 10base-T extended distance and polarity correction. Read
+ * PHY port status to determine MDI/MDIx and speed. Based on the speed,
+ * determine on the cable length, local and remote receiver.
+ **/
+s32 e1000e_get_phy_info_igp(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u16 data;
+ bool link;
+
+ ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+ if (ret_val)
+ return ret_val;
+
+ if (!link) {
+ hw_dbg(hw, "Phy info is only valid if link is up\n");
+ return -E1000_ERR_CONFIG;
+ }
+
+ phy->polarity_correction = 1;
+
+ ret_val = e1000_check_polarity_igp(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+ if (ret_val)
+ return ret_val;
+
+ phy->is_mdix = (data & IGP01E1000_PSSR_MDIX);
+
+ if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+ IGP01E1000_PSSR_SPEED_1000MBPS) {
+ ret_val = e1000_get_cable_length(hw);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);
+ if (ret_val)
+ return ret_val;
+
+ phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+
+ phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+ ? e1000_1000t_rx_status_ok
+ : e1000_1000t_rx_status_not_ok;
+ } else {
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+ phy->local_rx = e1000_1000t_rx_status_undefined;
+ phy->remote_rx = e1000_1000t_rx_status_undefined;
+ }
+
+ return ret_val;
+}
+
+/**
+ * e1000e_phy_sw_reset - PHY software reset
+ * @hw: pointer to the HW structure
+ *
+ * Does a software reset of the PHY by reading the PHY control register and
+ * setting/write the control register reset bit to the PHY.
+ **/
+s32 e1000e_phy_sw_reset(struct e1000_hw *hw)
+{
+ s32 ret_val;
+ u16 phy_ctrl;
+
+ ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ phy_ctrl |= MII_CR_RESET;
+ ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
+ if (ret_val)
+ return ret_val;
+
+ udelay(1);
+
+ return ret_val;
+}
+
+/**
+ * e1000e_phy_hw_reset_generic - PHY hardware reset
+ * @hw: pointer to the HW structure
+ *
+ * Verify the reset block is not blocking us from resetting. Acquire
+ * semaphore (if necessary) and read/set/write the device control reset
+ * bit in the PHY. Wait the appropriate delay time for the device to
+ * reset and relase the semaphore (if necessary).
+ **/
+s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw)
+{
+ struct e1000_phy_info *phy = &hw->phy;
+ s32 ret_val;
+ u32 ctrl;
+
+ ret_val = e1000_check_reset_block(hw);
+ if (ret_val)
+ return 0;
+
+ ret_val = phy->ops.acquire_phy(hw);
+ if (ret_val)
+ return ret_val;
+
+ ctrl = er32(CTRL);
+ ew32(CTRL, ctrl | E1000_CTRL_PHY_RST);
+ e1e_flush();
+
+ udelay(phy->reset_delay_us);
+
+ ew32(CTRL, ctrl);
+ e1e_flush();
+
+ udelay(150);
+
+ phy->ops.release_phy(hw);
+
+ return e1000_get_phy_cfg_done(hw);
+}
+
+/**
+ * e1000e_get_cfg_done - Generic configuration done
+ * @hw: pointer to the HW structure
+ *
+ * Generic function to wait 10 milli-seconds for configuration to complete
+ * and return success.
+ **/
+s32 e1000e_get_cfg_done(struct e1000_hw *hw)
+{
+ mdelay(10);
+ return 0;
+}
+
+/* Internal function pointers */
+
+/**
+ * e1000_get_phy_cfg_done - Generic PHY configuration done
+ * @hw: pointer to the HW structure
+ *
+ * Return success if silicon family did not implement a family specific
+ * get_cfg_done function.
+ **/
+static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.get_cfg_done)
+ return hw->phy.ops.get_cfg_done(hw);
+
+ return 0;
+}
+
+/**
+ * e1000_phy_force_speed_duplex - Generic force PHY speed/duplex
+ * @hw: pointer to the HW structure
+ *
+ * When the silicon family has not implemented a forced speed/duplex
+ * function for the PHY, simply return 0.
+ **/
+static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.force_speed_duplex)
+ return hw->phy.ops.force_speed_duplex(hw);
+
+ return 0;
+}
+
+/**
+ * e1000e_get_phy_type_from_id - Get PHY type from id
+ * @phy_id: phy_id read from the phy
+ *
+ * Returns the phy type from the id.
+ **/
+enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
+{
+ enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+ switch (phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1000_E_PHY_ID:
+ case M88E1111_I_PHY_ID:
+ case M88E1011_I_PHY_ID:
+ phy_type = e1000_phy_m88;
+ break;
+ case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
+ phy_type = e1000_phy_igp_2;
+ break;
+ case GG82563_E_PHY_ID:
+ phy_type = e1000_phy_gg82563;
+ break;
+ case IGP03E1000_E_PHY_ID:
+ phy_type = e1000_phy_igp_3;
+ break;
+ case IFE_E_PHY_ID:
+ case IFE_PLUS_E_PHY_ID:
+ case IFE_C_E_PHY_ID:
+ phy_type = e1000_phy_ife;
+ break;
+ default:
+ phy_type = e1000_phy_unknown;
+ break;
+ }
+ return phy_type;
+}
+
+/**
+ * e1000e_commit_phy - Soft PHY reset
+ * @hw: pointer to the HW structure
+ *
+ * Performs a soft PHY reset on those that apply. This is a function pointer
+ * entry point called by drivers.
+ **/
+s32 e1000e_commit_phy(struct e1000_hw *hw)
+{
+ if (hw->phy.ops.commit_phy)
+ return hw->phy.ops.commit_phy(hw);
+
+ return 0;
+}
+
+/**
+ * e1000_set_d0_lplu_state - Sets low power link up state for D0
+ * @hw: pointer to the HW structure
+ * @active: boolean used to enable/disable lplu
+ *
+ * Success returns 0, Failure returns 1
+ *
+ * The low power link up (lplu) state is set to the power management level D0
+ * and SmartSpeed is disabled when active is true, else clear lplu for D0
+ * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU
+ * is used during Dx states where the power conservation is most important.
+ * During driver activity, SmartSpeed should be enabled so performance is
+ * maintained. This is a function pointer entry point called by drivers.
+ **/
+static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
+{
+ if (hw->phy.ops.set_d0_lplu_state)
+ return hw->phy.ops.set_d0_lplu_state(hw, active);
+
+ return 0;
+}
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index b2b0a96218c..6390f51ea6f 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -124,8 +124,6 @@ static int __init do_e2100_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) /* Check a single specified location. */
return e21_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 47680237f78..83bda6ccde9 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -192,7 +192,6 @@ static unsigned int net_debug = NET_DEBUG;
/* Information that need to be kept for each board. */
struct eepro_local {
- struct net_device_stats stats;
unsigned rx_start;
unsigned tx_start; /* start of the transmit chain */
int tx_last; /* pointer to last packet in the transmit chain */
@@ -315,7 +314,6 @@ static irqreturn_t eepro_interrupt(int irq, void *dev_id);
static void eepro_rx(struct net_device *dev);
static void eepro_transmit_interrupt(struct net_device *dev);
static int eepro_close(struct net_device *dev);
-static struct net_device_stats *eepro_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static void eepro_tx_timeout (struct net_device *dev);
@@ -514,7 +512,7 @@ buffer (transmit-buffer = 32K - receive-buffer).
/* a complete sel reset */
#define eepro_complete_selreset(ioaddr) { \
- lp->stats.tx_errors++;\
+ dev->stats.tx_errors++;\
eepro_sel_reset(ioaddr);\
lp->tx_end = \
lp->xmt_lower_limit;\
@@ -537,8 +535,6 @@ static int __init do_eepro_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
#ifdef PnPWakeup
/* XXXX for multiple cards should this only be run once? */
@@ -594,8 +590,6 @@ struct net_device * __init eepro_probe(int unit)
if (!dev)
return ERR_PTR(-ENODEV);
- SET_MODULE_OWNER(dev);
-
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
@@ -696,6 +690,7 @@ static void __init eepro_print_info (struct net_device *dev)
struct eepro_local * lp = netdev_priv(dev);
int i;
const char * ifmap[] = {"AUI", "10Base2", "10BaseT"};
+ DECLARE_MAC_BUF(mac);
i = inb(dev->base_addr + ID_REG);
printk(KERN_DEBUG " id: %#x ",i);
@@ -717,10 +712,10 @@ static void __init eepro_print_info (struct net_device *dev)
case LAN595:
printk("%s: Intel 82595-based lan card at %#x,",
dev->name, (unsigned)dev->base_addr);
+ break;
}
- for (i=0; i < 6; i++)
- printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
+ printk(" %s", print_mac(mac, dev->dev_addr));
if (net_debug > 3)
printk(KERN_DEBUG ", %dK RCV buffer",
@@ -860,7 +855,6 @@ static int __init eepro_probe1(struct net_device *dev, int autoprobe)
dev->open = eepro_open;
dev->stop = eepro_close;
dev->hard_start_xmit = eepro_send_packet;
- dev->get_stats = eepro_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->tx_timeout = eepro_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -1158,9 +1152,9 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
if (hardware_send_packet(dev, buf, length))
/* we won't wake queue here because we're out of space */
- lp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
else {
- lp->stats.tx_bytes+=skb->len;
+ dev->stats.tx_bytes+=skb->len;
dev->trans_start = jiffies;
netif_wake_queue(dev);
}
@@ -1170,7 +1164,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
/* You might need to clean up and record Tx statistics here. */
- /* lp->stats.tx_aborted_errors++; */
+ /* dev->stats.tx_aborted_errors++; */
if (net_debug > 5)
printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name);
@@ -1277,16 +1271,6 @@ static int eepro_close(struct net_device *dev)
return 0;
}
-/* Get the current statistics. This may be called with the card open or
- closed. */
-static struct net_device_stats *
-eepro_get_stats(struct net_device *dev)
-{
- struct eepro_local *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/* Set or clear the multicast filter for this adaptor.
*/
static void
@@ -1579,12 +1563,12 @@ eepro_rx(struct net_device *dev)
/* Malloc up new buffer. */
struct sk_buff *skb;
- lp->stats.rx_bytes+=rcv_size;
+ dev->stats.rx_bytes+=rcv_size;
rcv_size &= 0x3fff;
skb = dev_alloc_skb(rcv_size+5);
if (skb == NULL) {
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
lp->rx_start = rcv_next_frame;
outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
@@ -1606,28 +1590,28 @@ eepro_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
+ dev->stats.rx_packets++;
}
else { /* Not sure will ever reach here,
I set the 595 to discard bad received frames */
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rcv_status & 0x0100)
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
else if (rcv_status & 0x0400)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
else if (rcv_status & 0x0800)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n",
dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
}
if (rcv_status & 0x1000)
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
lp->rx_start = rcv_next_frame;
@@ -1670,11 +1654,11 @@ eepro_transmit_interrupt(struct net_device *dev)
netif_wake_queue (dev);
if (xmt_status & TX_OK)
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
else {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (xmt_status & 0x0400) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
printk(KERN_DEBUG "%s: carrier error\n",
dev->name);
printk(KERN_DEBUG "%s: XMT status = %#x\n",
@@ -1688,11 +1672,11 @@ eepro_transmit_interrupt(struct net_device *dev)
}
}
if (xmt_status & 0x000f) {
- lp->stats.collisions += (xmt_status & 0x000f);
+ dev->stats.collisions += (xmt_status & 0x000f);
}
if ((xmt_status & 0x0040) == 0x0) {
- lp->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
}
}
}
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 3c54014acec..1548a80f917 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -622,6 +622,7 @@ static int __devinit speedo_found1(struct pci_dev *pdev,
int size;
void *tx_ring_space;
dma_addr_t tx_ring_dma;
+ DECLARE_MAC_BUF(mac);
size = TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats);
tx_ring_space = pci_alloc_consistent(pdev, size, &tx_ring_dma);
@@ -635,7 +636,6 @@ static int __devinit speedo_found1(struct pci_dev *pdev,
return -1;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (dev->mem_start > 0)
@@ -706,12 +706,8 @@ static int __devinit speedo_found1(struct pci_dev *pdev,
else
product = pci_name(pdev);
- printk(KERN_INFO "%s: %s, ", dev->name, product);
-
- for (i = 0; i < 5; i++)
- printk("%2.2X:", dev->dev_addr[i]);
- printk("%2.2X, ", dev->dev_addr[i]);
- printk("IRQ %d.\n", pdev->irq);
+ printk(KERN_INFO "%s: %s, %s, IRQ %d.\n", dev->name, product,
+ print_mac(mac, dev->dev_addr), pdev->irq);
sp = netdev_priv(dev);
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 7934ea37f94..70509ed6c11 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -135,7 +135,6 @@
struct net_local
{
- struct net_device_stats stats;
unsigned long last_tx; /* jiffies when last transmit started */
unsigned long init_time; /* jiffies when eexp_hw_init586 called */
unsigned short rx_first; /* first rx buf, same as RX_BUF_START */
@@ -247,7 +246,6 @@ static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 };
static int eexp_open(struct net_device *dev);
static int eexp_close(struct net_device *dev);
static void eexp_timeout(struct net_device *dev);
-static struct net_device_stats *eexp_stats(struct net_device *dev);
static int eexp_xmit(struct sk_buff *buf, struct net_device *dev);
static irqreturn_t eexp_irq(int irq, void *dev_addr);
@@ -341,8 +339,6 @@ static int __init do_express_probe(struct net_device *dev)
int dev_irq = dev->irq;
int err;
- SET_MODULE_OWNER(dev);
-
dev->if_port = 0xff; /* not set */
#ifdef CONFIG_MCA_LEGACY
@@ -535,17 +531,6 @@ static int eexp_close(struct net_device *dev)
}
/*
- * Return interface stats
- */
-
-static struct net_device_stats *eexp_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
-/*
* This gets called when a higher level thinks we are broken. Check that
* nothing has become jammed in the CU.
*/
@@ -648,7 +633,7 @@ static void eexp_timeout(struct net_device *dev)
printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name,
(SCB_complete(status)?"lost interrupt":
"board on fire"));
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
lp->last_tx = jiffies;
if (!SCB_complete(status)) {
scb_command(dev, SCB_CUabort);
@@ -666,9 +651,9 @@ static void eexp_timeout(struct net_device *dev)
*/
static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
{
- struct net_local *lp = netdev_priv(dev);
short length = buf->len;
#ifdef CONFIG_SMP
+ struct net_local *lp = netdev_priv(dev);
unsigned long flags;
#endif
@@ -696,7 +681,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
{
unsigned short *data = (unsigned short *)buf->data;
- lp->stats.tx_bytes += length;
+ dev->stats.tx_bytes += length;
eexp_hw_tx_pio(dev,data,length);
}
@@ -845,7 +830,7 @@ static irqreturn_t eexp_irq(int irq, void *dev_info)
outw(rbd+8, ioaddr+READ_PTR);
printk("[%04x]\n", inw(ioaddr+DATAPORT));
#endif
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
#if 1
eexp_hw_rxinit(dev);
#else
@@ -954,17 +939,17 @@ static void eexp_hw_rx_pio(struct net_device *dev)
}
else if (!FD_OK(status))
{
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (FD_CRC(status))
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (FD_Align(status))
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (FD_Resrc(status))
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (FD_DMA(status))
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (FD_Short(status))
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
else
{
@@ -974,7 +959,7 @@ static void eexp_hw_rx_pio(struct net_device *dev)
if (skb == NULL)
{
printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
skb_reserve(skb, 2);
@@ -983,8 +968,8 @@ static void eexp_hw_rx_pio(struct net_device *dev)
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
outw(rx_block, ioaddr+WRITE_PTR);
outw(0, ioaddr+DATAPORT);
@@ -1055,7 +1040,7 @@ static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
outw(0xFFFF, ioaddr+SIGNAL_CA);
}
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
lp->last_tx = jiffies;
}
@@ -1182,7 +1167,6 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
dev->open = eexp_open;
dev->stop = eexp_close;
dev->hard_start_xmit = eexp_xmit;
- dev->get_stats = eexp_stats;
dev->set_multicast_list = &eexp_set_multicast;
dev->tx_timeout = eexp_timeout;
dev->watchdog_timeo = 2*HZ;
@@ -1265,35 +1249,35 @@ static unsigned short eexp_hw_lasttxstat(struct net_device *dev)
else
{
lp->last_tx_restart = 0;
- lp->stats.collisions += Stat_NoColl(status);
+ dev->stats.collisions += Stat_NoColl(status);
if (!Stat_OK(status))
{
char *whatsup = NULL;
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (Stat_Abort(status))
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (Stat_TNoCar(status)) {
whatsup = "aborted, no carrier";
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
}
if (Stat_TNoCTS(status)) {
whatsup = "aborted, lost CTS";
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
}
if (Stat_TNoDMA(status)) {
whatsup = "FIFO underran";
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
}
if (Stat_TXColl(status)) {
whatsup = "aborted, too many collisions";
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
}
if (whatsup)
printk(KERN_INFO "%s: transmit %s\n",
dev->name, whatsup);
}
else
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
lp->tx_reap = tx_block = TX_BUF_START;
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 8d58be56f4e..f78e5bf7cb3 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -33,19 +33,20 @@
#include <linux/ethtool.h>
#include <linux/vmalloc.h>
#include <linux/if_vlan.h>
+#include <linux/inet_lro.h>
#include <asm/ibmebus.h>
#include <asm/abs_addr.h>
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0074"
+#define DRV_VERSION "EHEA_0080"
/* eHEA capability flags */
#define DLPAR_PORT_ADD_REM 1
#define DLPAR_MEM_ADD 2
#define DLPAR_MEM_REM 4
-#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM)
+#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD)
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@@ -58,6 +59,7 @@
#define EHEA_SMALL_QUEUES
#define EHEA_NUM_TX_QP 1
+#define EHEA_LRO_MAX_AGGR 64
#ifdef EHEA_SMALL_QUEUES
#define EHEA_MAX_CQE_COUNT 1023
@@ -84,6 +86,8 @@
#define EHEA_RQ2_PKT_SIZE 1522
#define EHEA_L_PKT_SIZE 256 /* low latency */
+#define MAX_LRO_DESCRIPTORS 8
+
/* Send completion signaling */
/* Protection Domain Identifier */
@@ -351,6 +355,7 @@ struct ehea_q_skb_arr {
* Port resources
*/
struct ehea_port_res {
+ struct napi_struct napi;
struct port_stats p_stats;
struct ehea_mr send_mr; /* send memory region */
struct ehea_mr recv_mr; /* receive memory region */
@@ -362,7 +367,6 @@ struct ehea_port_res {
struct ehea_cq *send_cq;
struct ehea_cq *recv_cq;
struct ehea_eq *eq;
- struct net_device *d_netdev;
struct ehea_q_skb_arr rq1_skba;
struct ehea_q_skb_arr rq2_skba;
struct ehea_q_skb_arr rq3_skba;
@@ -376,16 +380,17 @@ struct ehea_port_res {
u64 tx_packets;
u64 rx_packets;
u32 poll_counter;
+ struct net_lro_mgr lro_mgr;
+ struct net_lro_desc lro_desc[MAX_LRO_DESCRIPTORS];
};
#define EHEA_MAX_PORTS 16
struct ehea_adapter {
u64 handle;
- struct ibmebus_dev *ebus_dev;
+ struct of_device *ofdev;
struct ehea_port *port[EHEA_MAX_PORTS];
struct ehea_eq *neq; /* notification event queue */
- struct workqueue_struct *ehea_wq;
struct tasklet_struct neq_tasklet;
struct ehea_mr mr;
u32 pd; /* protection domain */
@@ -429,6 +434,7 @@ struct ehea_port {
u32 msg_enable;
u32 sig_comp_iv;
u32 state;
+ u32 lro_max_aggr;
u8 phy_link;
u8 full_duplex;
u8 autoneg;
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
index decec8cfe96..679f40ee957 100644
--- a/drivers/net/ehea/ehea_ethtool.c
+++ b/drivers/net/ehea/ehea_ethtool.c
@@ -183,6 +183,9 @@ static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"PR5 free_swqes"},
{"PR6 free_swqes"},
{"PR7 free_swqes"},
+ {"LRO aggregated"},
+ {"LRO flushed"},
+ {"LRO no_desc"},
};
static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -193,9 +196,14 @@ static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
}
}
-static int ehea_get_stats_count(struct net_device *dev)
+static int ehea_get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(ehea_ethtool_stats_keys);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(ehea_ethtool_stats_keys);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void ehea_get_ethtool_stats(struct net_device *dev,
@@ -204,7 +212,7 @@ static void ehea_get_ethtool_stats(struct net_device *dev,
int i, k, tmp;
struct ehea_port *port = netdev_priv(dev);
- for (i = 0; i < ehea_get_stats_count(dev); i++)
+ for (i = 0; i < ehea_get_sset_count(dev, ETH_SS_STATS); i++)
data[i] = 0;
i = 0;
@@ -239,6 +247,18 @@ static void ehea_get_ethtool_stats(struct net_device *dev,
for (k = 0; k < 8; k++)
data[i++] = atomic_read(&port->port_res[k].swqe_avail);
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp |= port->port_res[k].lro_mgr.stats.aggregated;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp |= port->port_res[k].lro_mgr.stats.flushed;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp |= port->port_res[k].lro_mgr.stats.no_desc;
+ data[i++] = tmp;
+
}
const struct ethtool_ops ehea_ethtool_ops = {
@@ -247,12 +267,9 @@ const struct ethtool_ops ehea_ethtool_ops = {
.get_msglevel = ehea_get_msglevel,
.set_msglevel = ehea_set_msglevel,
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_strings = ehea_get_strings,
- .get_stats_count = ehea_get_stats_count,
+ .get_sset_count = ehea_get_sset_count,
.get_ethtool_stats = ehea_get_ethtool_stats,
.get_rx_csum = ehea_get_rx_csum,
.set_settings = ehea_set_settings,
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 717b12984d1..f0319f1e8e0 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -33,6 +33,9 @@
#include <linux/if.h>
#include <linux/list.h>
#include <linux/if_ether.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
#include <net/ip.h>
#include "ehea.h"
@@ -52,6 +55,8 @@ static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
static int sq_entries = EHEA_DEF_ENTRIES_SQ;
static int use_mcs = 0;
+static int use_lro = 0;
+static int lro_max_aggr = EHEA_LRO_MAX_AGGR;
static int num_tx_qps = EHEA_NUM_TX_QP;
static int prop_carrier_state = 0;
@@ -62,6 +67,8 @@ module_param(rq3_entries, int, 0);
module_param(sq_entries, int, 0);
module_param(prop_carrier_state, int, 0);
module_param(use_mcs, int, 0);
+module_param(use_lro, int, 0);
+module_param(lro_max_aggr, int, 0);
module_param(num_tx_qps, int, 0);
MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS");
@@ -82,17 +89,22 @@ MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue "
__MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 0 ");
+MODULE_PARM_DESC(lro_max_aggr, " LRO: Max packets to be aggregated. Default = "
+ __MODULE_STRING(EHEA_LRO_MAX_AGGR));
+MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, "
+ "Default = 0");
+
static int port_name_cnt = 0;
static LIST_HEAD(adapter_list);
u64 ehea_driver_flags = 0;
-struct workqueue_struct *ehea_driver_wq;
struct work_struct ehea_rereg_mr_task;
+struct semaphore dlpar_mem_lock;
-static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
+static int __devinit ehea_probe_adapter(struct of_device *dev,
const struct of_device_id *id);
-static int __devexit ehea_remove(struct ibmebus_dev *dev);
+static int __devexit ehea_remove(struct of_device *dev);
static struct of_device_id ehea_device_table[] = {
{
@@ -102,9 +114,9 @@ static struct of_device_id ehea_device_table[] = {
{},
};
-static struct ibmebus_driver ehea_driver = {
+static struct of_platform_driver ehea_driver = {
.name = "ehea",
- .id_table = ehea_device_table,
+ .match_table = ehea_device_table,
.probe = ehea_probe_adapter,
.remove = ehea_remove,
};
@@ -168,16 +180,24 @@ static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr;
struct net_device *dev = pr->port->netdev;
int max_index_mask = pr->rq1_skba.len - 1;
+ int fill_wqes = pr->rq1_skba.os_skbs + nr_of_wqes;
+ int adder = 0;
int i;
- if (!nr_of_wqes)
+ pr->rq1_skba.os_skbs = 0;
+
+ if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
+ pr->rq1_skba.index = index;
+ pr->rq1_skba.os_skbs = fill_wqes;
return;
+ }
- for (i = 0; i < nr_of_wqes; i++) {
+ for (i = 0; i < fill_wqes; i++) {
if (!skb_arr_rq1[index]) {
skb_arr_rq1[index] = netdev_alloc_skb(dev,
EHEA_L_PKT_SIZE);
if (!skb_arr_rq1[index]) {
+ pr->rq1_skba.os_skbs = fill_wqes - i;
ehea_error("%s: no mem for skb/%d wqes filled",
dev->name, i);
break;
@@ -185,9 +205,14 @@ static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
}
index--;
index &= max_index_mask;
+ adder++;
}
+
+ if (adder == 0)
+ return;
+
/* Ring doorbell */
- ehea_update_rq1a(pr->qp, i);
+ ehea_update_rq1a(pr->qp, adder);
}
static int ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
@@ -221,16 +246,21 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
struct sk_buff **skb_arr = q_skba->arr;
struct ehea_rwqe *rwqe;
int i, index, max_index_mask, fill_wqes;
+ int adder = 0;
int ret = 0;
fill_wqes = q_skba->os_skbs + num_wqes;
+ q_skba->os_skbs = 0;
- if (!fill_wqes)
+ if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
+ q_skba->os_skbs = fill_wqes;
return ret;
+ }
index = q_skba->index;
max_index_mask = q_skba->len - 1;
for (i = 0; i < fill_wqes; i++) {
+ u64 tmp_addr;
struct sk_buff *skb = netdev_alloc_skb(dev, packet_size);
if (!skb) {
ehea_error("%s: no mem for skb/%d wqes filled",
@@ -242,30 +272,37 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
skb_reserve(skb, NET_IP_ALIGN);
skb_arr[index] = skb;
+ tmp_addr = ehea_map_vaddr(skb->data);
+ if (tmp_addr == -1) {
+ dev_kfree_skb(skb);
+ q_skba->os_skbs = fill_wqes - i;
+ ret = 0;
+ break;
+ }
rwqe = ehea_get_next_rwqe(qp, rq_nr);
rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type)
| EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
- rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data);
+ rwqe->sg_list[0].vaddr = tmp_addr;
rwqe->sg_list[0].len = packet_size;
rwqe->data_segments = 1;
index++;
index &= max_index_mask;
-
- if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)))
- goto out;
+ adder++;
}
q_skba->index = index;
+ if (adder == 0)
+ goto out;
/* Ring doorbell */
iosync();
if (rq_nr == 2)
- ehea_update_rq2a(pr->qp, i);
+ ehea_update_rq2a(pr->qp, adder);
else
- ehea_update_rq3a(pr->qp, i);
+ ehea_update_rq3a(pr->qp, adder);
out:
return ret;
}
@@ -386,16 +423,70 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
if (cqe->status & EHEA_CQE_STAT_FAT_ERR_MASK) {
ehea_error("Critical receive error. Resetting port.");
- queue_work(pr->port->adapter->ehea_wq, &pr->port->reset_task);
+ schedule_work(&pr->port->reset_task);
return 1;
}
return 0;
}
-static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
- struct ehea_port_res *pr,
- int *budget)
+static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
+ void **tcph, u64 *hdr_flags, void *priv)
+{
+ struct ehea_cqe *cqe = priv;
+ unsigned int ip_len;
+ struct iphdr *iph;
+
+ /* non tcp/udp packets */
+ if (!cqe->header_length)
+ return -1;
+
+ /* non tcp packet */
+ skb_reset_network_header(skb);
+ iph = ip_hdr(skb);
+ if (iph->protocol != IPPROTO_TCP)
+ return -1;
+
+ ip_len = ip_hdrlen(skb);
+ skb_set_transport_header(skb, ip_len);
+ *tcph = tcp_hdr(skb);
+
+ /* check if ip header and tcp header are complete */
+ if (iph->tot_len < ip_len + tcp_hdrlen(skb))
+ return -1;
+
+ *hdr_flags = LRO_IPV4 | LRO_TCP;
+ *iphdr = iph;
+
+ return 0;
+}
+
+static void ehea_proc_skb(struct ehea_port_res *pr, struct ehea_cqe *cqe,
+ struct sk_buff *skb)
+{
+ int vlan_extracted = (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
+ && pr->port->vgrp;
+
+ if (use_lro) {
+ if (vlan_extracted)
+ lro_vlan_hwaccel_receive_skb(&pr->lro_mgr, skb,
+ pr->port->vgrp,
+ cqe->vlan_tag,
+ cqe);
+ else
+ lro_receive_skb(&pr->lro_mgr, skb, cqe);
+ } else {
+ if (vlan_extracted)
+ vlan_hwaccel_receive_skb(skb, pr->port->vgrp,
+ cqe->vlan_tag);
+ else
+ netif_receive_skb(skb);
+ }
+}
+
+static int ehea_proc_rwqes(struct net_device *dev,
+ struct ehea_port_res *pr,
+ int budget)
{
struct ehea_port *port = pr->port;
struct ehea_qp *qp = pr->qp;
@@ -408,18 +499,16 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
int skb_arr_rq2_len = pr->rq2_skba.len;
int skb_arr_rq3_len = pr->rq3_skba.len;
int processed, processed_rq1, processed_rq2, processed_rq3;
- int wqe_index, last_wqe_index, rq, my_quota, port_reset;
+ int wqe_index, last_wqe_index, rq, port_reset;
processed = processed_rq1 = processed_rq2 = processed_rq3 = 0;
last_wqe_index = 0;
- my_quota = min(*budget, dev->quota);
cqe = ehea_poll_rq1(qp, &wqe_index);
- while ((my_quota > 0) && cqe) {
+ while ((processed < budget) && cqe) {
ehea_inc_rq1(qp);
processed_rq1++;
processed++;
- my_quota--;
if (netif_msg_rx_status(port))
ehea_dump(cqe, sizeof(*cqe), "CQE");
@@ -434,14 +523,14 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
if (netif_msg_rx_err(port))
ehea_error("LL rq1: skb=NULL");
- skb = netdev_alloc_skb(port->netdev,
+ skb = netdev_alloc_skb(dev,
EHEA_L_PKT_SIZE);
if (!skb)
break;
}
skb_copy_to_linear_data(skb, ((char*)cqe) + 64,
cqe->num_bytes_transfered - 4);
- ehea_fill_skb(port->netdev, skb, cqe);
+ ehea_fill_skb(dev, skb, cqe);
} else if (rq == 2) { /* RQ2 */
skb = get_skb_by_index(skb_arr_rq2,
skb_arr_rq2_len, cqe);
@@ -450,7 +539,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
ehea_error("rq2: skb=NULL");
break;
}
- ehea_fill_skb(port->netdev, skb, cqe);
+ ehea_fill_skb(dev, skb, cqe);
processed_rq2++;
} else { /* RQ3 */
skb = get_skb_by_index(skb_arr_rq3,
@@ -460,18 +549,12 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
ehea_error("rq3: skb=NULL");
break;
}
- ehea_fill_skb(port->netdev, skb, cqe);
+ ehea_fill_skb(dev, skb, cqe);
processed_rq3++;
}
- if ((cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
- && port->vgrp)
- vlan_hwaccel_receive_skb(skb, port->vgrp,
- cqe->vlan_tag);
- else
- netif_receive_skb(skb);
-
- port->netdev->last_rx = jiffies;
+ ehea_proc_skb(pr, cqe, skb);
+ dev->last_rx = jiffies;
} else {
pr->p_stats.poll_receive_errors++;
port_reset = ehea_treat_poll_error(pr, rq, cqe,
@@ -482,16 +565,16 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
}
cqe = ehea_poll_rq1(qp, &wqe_index);
}
+ if (use_lro)
+ lro_flush_all(&pr->lro_mgr);
pr->rx_packets += processed;
- *budget -= processed;
ehea_refill_rq1(pr, last_wqe_index, processed_rq1);
ehea_refill_rq2(pr, processed_rq2);
ehea_refill_rq3(pr, processed_rq3);
- cqe = ehea_poll_rq1(qp, &wqe_index);
- return cqe;
+ return processed;
}
static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
@@ -515,8 +598,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
ehea_error("Send Completion Error: Resetting port");
if (netif_msg_tx_err(pr->port))
ehea_dump(cqe, sizeof(*cqe), "Send CQE");
- queue_work(pr->port->adapter->ehea_wq,
- &pr->port->reset_task);
+ schedule_work(&pr->port->reset_task);
break;
}
@@ -554,22 +636,27 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
}
#define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16
+#define EHEA_POLL_MAX_CQES 65535
-static int ehea_poll(struct net_device *dev, int *budget)
+static int ehea_poll(struct napi_struct *napi, int budget)
{
- struct ehea_port_res *pr = dev->priv;
+ struct ehea_port_res *pr = container_of(napi, struct ehea_port_res, napi);
+ struct net_device *dev = pr->port->netdev;
struct ehea_cqe *cqe;
struct ehea_cqe *cqe_skb = NULL;
int force_irq, wqe_index;
-
- cqe = ehea_poll_rq1(pr->qp, &wqe_index);
- cqe_skb = ehea_poll_cq(pr->send_cq);
+ int rx = 0;
force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ);
+ cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES);
+
+ if (!force_irq)
+ rx += ehea_proc_rwqes(dev, pr, budget - rx);
- if ((!cqe && !cqe_skb) || force_irq) {
+ while ((rx != budget) || force_irq) {
pr->poll_counter = 0;
- netif_rx_complete(dev);
+ force_irq = 0;
+ netif_rx_complete(dev, napi);
ehea_reset_cq_ep(pr->recv_cq);
ehea_reset_cq_ep(pr->send_cq);
ehea_reset_cq_n1(pr->recv_cq);
@@ -578,43 +665,35 @@ static int ehea_poll(struct net_device *dev, int *budget)
cqe_skb = ehea_poll_cq(pr->send_cq);
if (!cqe && !cqe_skb)
- return 0;
+ return rx;
- if (!netif_rx_reschedule(dev, dev->quota))
- return 0;
- }
-
- cqe = ehea_proc_rwqes(dev, pr, budget);
- cqe_skb = ehea_proc_cqes(pr, 300);
+ if (!netif_rx_reschedule(dev, napi))
+ return rx;
- if (cqe || cqe_skb)
- pr->poll_counter++;
+ cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES);
+ rx += ehea_proc_rwqes(dev, pr, budget - rx);
+ }
- return 1;
+ pr->poll_counter++;
+ return rx;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
static void ehea_netpoll(struct net_device *dev)
{
struct ehea_port *port = netdev_priv(dev);
+ int i;
- netif_rx_schedule(port->port_res[0].d_netdev);
+ for (i = 0; i < port->num_def_qps; i++)
+ netif_rx_schedule(dev, &port->port_res[i].napi);
}
#endif
-static int ehea_poll_firstqueue(struct net_device *dev, int *budget)
-{
- struct ehea_port *port = netdev_priv(dev);
- struct net_device *d_dev = port->port_res[0].d_netdev;
-
- return ehea_poll(d_dev, budget);
-}
-
static irqreturn_t ehea_recv_irq_handler(int irq, void *param)
{
struct ehea_port_res *pr = param;
- netif_rx_schedule(pr->d_netdev);
+ netif_rx_schedule(pr->port->netdev, &pr->napi);
return IRQ_HANDLED;
}
@@ -638,7 +717,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
eqe = ehea_poll_eq(port->qp_eq);
}
- queue_work(port->adapter->ehea_wq, &port->reset_task);
+ schedule_work(&port->reset_task);
return IRQ_HANDLED;
}
@@ -968,7 +1047,7 @@ static int ehea_reg_interrupts(struct net_device *dev)
snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff",
dev->name);
- ret = ibmebus_request_irq(NULL, port->qp_eq->attr.ist1,
+ ret = ibmebus_request_irq(port->qp_eq->attr.ist1,
ehea_qp_aff_irq_handler,
IRQF_DISABLED, port->int_aff_name, port);
if (ret) {
@@ -986,7 +1065,7 @@ static int ehea_reg_interrupts(struct net_device *dev)
pr = &port->port_res[i];
snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1,
"%s-queue%d", dev->name, i);
- ret = ibmebus_request_irq(NULL, pr->eq->attr.ist1,
+ ret = ibmebus_request_irq(pr->eq->attr.ist1,
ehea_recv_irq_handler,
IRQF_DISABLED, pr->int_send_name,
pr);
@@ -1007,11 +1086,11 @@ out:
out_free_req:
while (--i >= 0) {
u32 ist = port->port_res[i].eq->attr.ist1;
- ibmebus_free_irq(NULL, ist, &port->port_res[i]);
+ ibmebus_free_irq(ist, &port->port_res[i]);
}
out_free_qpeq:
- ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port);
+ ibmebus_free_irq(port->qp_eq->attr.ist1, port);
i = port->num_def_qps;
goto out;
@@ -1028,14 +1107,14 @@ 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(NULL, pr->eq->attr.ist1, pr);
+ 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);
}
/* associated events */
- ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port);
+ 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);
@@ -1236,14 +1315,16 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
kfree(init_attr);
- pr->d_netdev = alloc_netdev(0, "", ether_setup);
- if (!pr->d_netdev)
- goto out_free;
- pr->d_netdev->priv = pr;
- pr->d_netdev->weight = 64;
- pr->d_netdev->poll = ehea_poll;
- set_bit(__LINK_STATE_START, &pr->d_netdev->state);
- strcpy(pr->d_netdev->name, port->netdev->name);
+ netif_napi_add(pr->port->netdev, &pr->napi, ehea_poll, 64);
+
+ pr->lro_mgr.max_aggr = pr->port->lro_max_aggr;
+ pr->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS;
+ pr->lro_mgr.lro_arr = pr->lro_desc;
+ pr->lro_mgr.get_skb_header = get_skb_hdr;
+ pr->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
+ pr->lro_mgr.dev = port->netdev;
+ pr->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
+ pr->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
ret = 0;
goto out;
@@ -1266,8 +1347,6 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr)
{
int ret, i;
- free_netdev(pr->d_netdev);
-
ret = ehea_destroy_qp(pr->qp);
if (!ret) {
@@ -1915,11 +1994,12 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
ehea_dump(swqe, 512, "swqe");
}
- if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)))
- goto out;
+ if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
+ netif_stop_queue(dev);
+ swqe->tx_control |= EHEA_SWQE_PURGE;
+ }
ehea_post_swqe(pr->qp, swqe);
- pr->tx_packets++;
if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
spin_lock_irqsave(&pr->netif_queue, flags);
@@ -1932,7 +2012,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
dev->trans_start = jiffies;
spin_unlock(&pr->xmit_lock);
-out:
+
return NETDEV_TX_OK;
}
@@ -2248,6 +2328,22 @@ out:
return ret;
}
+static void port_napi_disable(struct ehea_port *port)
+{
+ int i;
+
+ for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
+ napi_disable(&port->port_res[i].napi);
+}
+
+static void port_napi_enable(struct ehea_port *port)
+{
+ int i;
+
+ for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
+ napi_enable(&port->port_res[i].napi);
+}
+
static int ehea_open(struct net_device *dev)
{
int ret;
@@ -2259,8 +2355,10 @@ static int ehea_open(struct net_device *dev)
ehea_info("enabling port %s", dev->name);
ret = ehea_up(dev);
- if (!ret)
+ if (!ret) {
+ port_napi_enable(port);
netif_start_queue(dev);
+ }
up(&port->port_lock);
@@ -2269,7 +2367,7 @@ static int ehea_open(struct net_device *dev)
static int ehea_down(struct net_device *dev)
{
- int ret, i;
+ int ret;
struct ehea_port *port = netdev_priv(dev);
if (port->state == EHEA_PORT_DOWN)
@@ -2278,11 +2376,6 @@ static int ehea_down(struct net_device *dev)
ehea_drop_multicast_list(dev);
ehea_free_interrupts(dev);
- for (i = 0; i < port->num_def_qps; i++)
- while (test_bit(__LINK_STATE_RX_SCHED,
- &port->port_res[i].d_netdev->state))
- msleep(1);
-
port->state = EHEA_PORT_DOWN;
ret = ehea_clean_all_portres(port);
@@ -2301,14 +2394,201 @@ static int ehea_stop(struct net_device *dev)
if (netif_msg_ifdown(port))
ehea_info("disabling port %s", dev->name);
- flush_workqueue(port->adapter->ehea_wq);
+ flush_scheduled_work();
down(&port->port_lock);
netif_stop_queue(dev);
+ port_napi_disable(port);
ret = ehea_down(dev);
up(&port->port_lock);
return ret;
}
+void ehea_purge_sq(struct ehea_qp *orig_qp)
+{
+ struct ehea_qp qp = *orig_qp;
+ struct ehea_qp_init_attr *init_attr = &qp.init_attr;
+ struct ehea_swqe *swqe;
+ int wqe_index;
+ int i;
+
+ for (i = 0; i < init_attr->act_nr_send_wqes; i++) {
+ swqe = ehea_get_swqe(&qp, &wqe_index);
+ swqe->tx_control |= EHEA_SWQE_PURGE;
+ }
+}
+
+int ehea_stop_qps(struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct ehea_adapter *adapter = port->adapter;
+ struct hcp_modify_qp_cb0* cb0;
+ int ret = -EIO;
+ int dret;
+ int i;
+ u64 hret;
+ u64 dummy64 = 0;
+ u16 dummy16 = 0;
+
+ cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!cb0) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) {
+ struct ehea_port_res *pr = &port->port_res[i];
+ struct ehea_qp *qp = pr->qp;
+
+ /* Purge send queue */
+ ehea_purge_sq(qp);
+
+ /* Disable queue pair */
+ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
+ cb0);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_qp failed (1)");
+ goto out;
+ }
+
+ cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8;
+ cb0->qp_ctl_reg &= ~H_QP_CR_ENABLED;
+
+ hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG,
+ 1), cb0, &dummy64,
+ &dummy64, &dummy16, &dummy16);
+ if (hret != H_SUCCESS) {
+ ehea_error("modify_ehea_qp failed (1)");
+ goto out;
+ }
+
+ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
+ cb0);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_qp failed (2)");
+ goto out;
+ }
+
+ /* deregister shared memory regions */
+ dret = ehea_rem_smrs(pr);
+ if (dret) {
+ ehea_error("unreg shared memory region failed");
+ goto out;
+ }
+ }
+
+ ret = 0;
+out:
+ kfree(cb0);
+
+ return ret;
+}
+
+void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res * pr)
+{
+ struct ehea_qp qp = *orig_qp;
+ struct ehea_qp_init_attr *init_attr = &qp.init_attr;
+ struct ehea_rwqe *rwqe;
+ struct sk_buff **skba_rq2 = pr->rq2_skba.arr;
+ struct sk_buff **skba_rq3 = pr->rq3_skba.arr;
+ struct sk_buff *skb;
+ u32 lkey = pr->recv_mr.lkey;
+
+
+ int i;
+ int index;
+
+ for (i = 0; i < init_attr->act_nr_rwqes_rq2 + 1; i++) {
+ rwqe = ehea_get_next_rwqe(&qp, 2);
+ rwqe->sg_list[0].l_key = lkey;
+ index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id);
+ skb = skba_rq2[index];
+ if (skb)
+ rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data);
+ }
+
+ for (i = 0; i < init_attr->act_nr_rwqes_rq3 + 1; i++) {
+ rwqe = ehea_get_next_rwqe(&qp, 3);
+ rwqe->sg_list[0].l_key = lkey;
+ index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id);
+ skb = skba_rq3[index];
+ if (skb)
+ rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data);
+ }
+}
+
+int ehea_restart_qps(struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct ehea_adapter *adapter = port->adapter;
+ int ret = 0;
+ int i;
+
+ struct hcp_modify_qp_cb0* cb0;
+ u64 hret;
+ u64 dummy64 = 0;
+ u16 dummy16 = 0;
+
+ cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!cb0) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) {
+ struct ehea_port_res *pr = &port->port_res[i];
+ struct ehea_qp *qp = pr->qp;
+
+ ret = ehea_gen_smrs(pr);
+ if (ret) {
+ ehea_error("creation of shared memory regions failed");
+ goto out;
+ }
+
+ ehea_update_rqs(qp, pr);
+
+ /* Enable queue pair */
+ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
+ cb0);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_qp failed (1)");
+ goto out;
+ }
+
+ cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8;
+ cb0->qp_ctl_reg |= H_QP_CR_ENABLED;
+
+ hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG,
+ 1), cb0, &dummy64,
+ &dummy64, &dummy16, &dummy16);
+ if (hret != H_SUCCESS) {
+ ehea_error("modify_ehea_qp failed (1)");
+ goto out;
+ }
+
+ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
+ cb0);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_qp failed (2)");
+ goto out;
+ }
+
+ /* refill entire queue */
+ ehea_refill_rq1(pr, pr->rq1_skba.index, 0);
+ ehea_refill_rq2(pr, 0);
+ ehea_refill_rq3(pr, 0);
+ }
+out:
+ kfree(cb0);
+
+ return ret;
+}
+
static void ehea_reset_port(struct work_struct *work)
{
int ret;
@@ -2319,7 +2599,8 @@ static void ehea_reset_port(struct work_struct *work)
port->resets++;
down(&port->port_lock);
netif_stop_queue(dev);
- netif_poll_disable(dev);
+
+ port_napi_disable(port);
ehea_down(dev);
@@ -2327,10 +2608,13 @@ static void ehea_reset_port(struct work_struct *work)
if (ret)
goto out;
+ ehea_set_multicast_list(dev);
+
if (netif_msg_timer(port))
ehea_info("Device %s resetted successfully", dev->name);
- netif_poll_enable(dev);
+ port_napi_enable(port);
+
netif_wake_queue(dev);
out:
up(&port->port_lock);
@@ -2342,6 +2626,7 @@ static void ehea_rereg_mrs(struct work_struct *work)
int ret, i;
struct ehea_adapter *adapter;
+ down(&dlpar_mem_lock);
ehea_info("LPAR memory enlarged - re-initializing driver");
list_for_each_entry(adapter, &adapter_list, list)
@@ -2354,12 +2639,14 @@ static void ehea_rereg_mrs(struct work_struct *work)
struct net_device *dev = port->netdev;
if (dev->flags & IFF_UP) {
- ehea_info("stopping %s",
- dev->name);
down(&port->port_lock);
netif_stop_queue(dev);
- netif_poll_disable(dev);
- ehea_down(dev);
+ ret = ehea_stop_qps(dev);
+ if (ret) {
+ up(&port->port_lock);
+ goto out;
+ }
+ port_napi_disable(port);
up(&port->port_lock);
}
}
@@ -2375,10 +2662,11 @@ static void ehea_rereg_mrs(struct work_struct *work)
}
ehea_destroy_busmap();
-
ret = ehea_create_busmap();
- if (ret)
+ if (ret) {
+ ehea_error("creating ehea busmap failed");
goto out;
+ }
clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
@@ -2400,21 +2688,18 @@ static void ehea_rereg_mrs(struct work_struct *work)
struct net_device *dev = port->netdev;
if (dev->flags & IFF_UP) {
- ehea_info("restarting %s",
- dev->name);
down(&port->port_lock);
-
- ret = ehea_up(dev);
- if (!ret) {
- netif_poll_enable(dev);
+ port_napi_enable(port);
+ ret = ehea_restart_qps(dev);
+ if (!ret)
netif_wake_queue(dev);
- }
-
up(&port->port_lock);
}
}
}
}
+ up(&dlpar_mem_lock);
+ ehea_info("re-initializing driver complete");
out:
return;
}
@@ -2423,8 +2708,9 @@ static void ehea_tx_watchdog(struct net_device *dev)
{
struct ehea_port *port = netdev_priv(dev);
- if (netif_carrier_ok(dev))
- queue_work(port->adapter->ehea_wq, &port->reset_task);
+ if (netif_carrier_ok(dev) &&
+ !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
+ schedule_work(&port->reset_task);
}
int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
@@ -2548,7 +2834,7 @@ static struct device *ehea_register_port(struct ehea_port *port,
int ret;
port->ofdev.node = of_node_get(dn);
- port->ofdev.dev.parent = &port->adapter->ebus_dev->ofdev.dev;
+ port->ofdev.dev.parent = &port->adapter->ofdev->dev;
port->ofdev.dev.bus = &ibmebus_bus_type;
sprintf(port->ofdev.dev.bus_id, "port%d", port_name_cnt++);
@@ -2639,16 +2925,12 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
SET_NETDEV_DEV(dev, port_dev);
/* initialize net_device structure */
- SET_MODULE_OWNER(dev);
-
memcpy(dev->dev_addr, &port->mac_addr, ETH_ALEN);
dev->open = ehea_open;
- dev->poll = ehea_poll_firstqueue;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = ehea_netpoll;
#endif
- dev->weight = 64;
dev->stop = ehea_stop;
dev->hard_start_xmit = ehea_start_xmit;
dev->get_stats = ehea_get_stats;
@@ -2681,6 +2963,8 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
goto out_dereg_bc;
}
+ port->lro_max_aggr = lro_max_aggr;
+
ret = ehea_get_jumboframe_status(port, &jumbo);
if (ret)
ehea_error("failed determining jumbo frame status for %s",
@@ -2729,7 +3013,7 @@ static int ehea_setup_ports(struct ehea_adapter *adapter)
const u32 *dn_log_port_id;
int i = 0;
- lhea_dn = adapter->ebus_dev->ofdev.node;
+ lhea_dn = adapter->ofdev->node;
while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
@@ -2769,7 +3053,7 @@ static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter,
struct device_node *eth_dn = NULL;
const u32 *dn_log_port_id;
- lhea_dn = adapter->ebus_dev->ofdev.node;
+ lhea_dn = adapter->ofdev->node;
while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
@@ -2875,31 +3159,31 @@ static ssize_t ehea_remove_port(struct device *dev,
static DEVICE_ATTR(probe_port, S_IWUSR, NULL, ehea_probe_port);
static DEVICE_ATTR(remove_port, S_IWUSR, NULL, ehea_remove_port);
-int ehea_create_device_sysfs(struct ibmebus_dev *dev)
+int ehea_create_device_sysfs(struct of_device *dev)
{
- int ret = device_create_file(&dev->ofdev.dev, &dev_attr_probe_port);
+ int ret = device_create_file(&dev->dev, &dev_attr_probe_port);
if (ret)
goto out;
- ret = device_create_file(&dev->ofdev.dev, &dev_attr_remove_port);
+ ret = device_create_file(&dev->dev, &dev_attr_remove_port);
out:
return ret;
}
-void ehea_remove_device_sysfs(struct ibmebus_dev *dev)
+void ehea_remove_device_sysfs(struct of_device *dev)
{
- device_remove_file(&dev->ofdev.dev, &dev_attr_probe_port);
- device_remove_file(&dev->ofdev.dev, &dev_attr_remove_port);
+ device_remove_file(&dev->dev, &dev_attr_probe_port);
+ device_remove_file(&dev->dev, &dev_attr_remove_port);
}
-static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
+static int __devinit ehea_probe_adapter(struct of_device *dev,
const struct of_device_id *id)
{
struct ehea_adapter *adapter;
const u64 *adapter_handle;
int ret;
- if (!dev || !dev->ofdev.node) {
+ if (!dev || !dev->node) {
ehea_error("Invalid ibmebus device probed");
return -EINVAL;
}
@@ -2907,36 +3191,36 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
if (!adapter) {
ret = -ENOMEM;
- dev_err(&dev->ofdev.dev, "no mem for ehea_adapter\n");
+ dev_err(&dev->dev, "no mem for ehea_adapter\n");
goto out;
}
list_add(&adapter->list, &adapter_list);
- adapter->ebus_dev = dev;
+ adapter->ofdev = dev;
- adapter_handle = of_get_property(dev->ofdev.node, "ibm,hea-handle",
+ adapter_handle = of_get_property(dev->node, "ibm,hea-handle",
NULL);
if (adapter_handle)
adapter->handle = *adapter_handle;
if (!adapter->handle) {
- dev_err(&dev->ofdev.dev, "failed getting handle for adapter"
- " '%s'\n", dev->ofdev.node->full_name);
+ dev_err(&dev->dev, "failed getting handle for adapter"
+ " '%s'\n", dev->node->full_name);
ret = -ENODEV;
goto out_free_ad;
}
adapter->pd = EHEA_PD_ID;
- dev->ofdev.dev.driver_data = adapter;
+ dev->dev.driver_data = adapter;
/* initialize adapter and ports */
/* get adapter properties */
ret = ehea_sense_adapter_attr(adapter);
if (ret) {
- dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret);
+ dev_err(&dev->dev, "sense_adapter_attr failed: %d\n", ret);
goto out_free_ad;
}
@@ -2944,34 +3228,28 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1);
if (!adapter->neq) {
ret = -EIO;
- dev_err(&dev->ofdev.dev, "NEQ creation failed");
+ dev_err(&dev->dev, "NEQ creation failed\n");
goto out_free_ad;
}
tasklet_init(&adapter->neq_tasklet, ehea_neq_tasklet,
(unsigned long)adapter);
- ret = ibmebus_request_irq(NULL, adapter->neq->attr.ist1,
+ ret = ibmebus_request_irq(adapter->neq->attr.ist1,
ehea_interrupt_neq, IRQF_DISABLED,
"ehea_neq", adapter);
if (ret) {
- dev_err(&dev->ofdev.dev, "requesting NEQ IRQ failed");
+ dev_err(&dev->dev, "requesting NEQ IRQ failed\n");
goto out_kill_eq;
}
- adapter->ehea_wq = create_workqueue("ehea_wq");
- if (!adapter->ehea_wq) {
- ret = -EIO;
- goto out_free_irq;
- }
-
ret = ehea_create_device_sysfs(dev);
if (ret)
- goto out_kill_wq;
+ goto out_free_irq;
ret = ehea_setup_ports(adapter);
if (ret) {
- dev_err(&dev->ofdev.dev, "setup_ports failed");
+ dev_err(&dev->dev, "setup_ports failed\n");
goto out_rem_dev_sysfs;
}
@@ -2981,11 +3259,8 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
out_rem_dev_sysfs:
ehea_remove_device_sysfs(dev);
-out_kill_wq:
- destroy_workqueue(adapter->ehea_wq);
-
out_free_irq:
- ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
+ ibmebus_free_irq(adapter->neq->attr.ist1, adapter);
out_kill_eq:
ehea_destroy_eq(adapter->neq);
@@ -2996,9 +3271,9 @@ out:
return ret;
}
-static int __devexit ehea_remove(struct ibmebus_dev *dev)
+static int __devexit ehea_remove(struct of_device *dev)
{
- struct ehea_adapter *adapter = dev->ofdev.dev.driver_data;
+ struct ehea_adapter *adapter = dev->dev.driver_data;
int i;
for (i = 0; i < EHEA_MAX_PORTS; i++)
@@ -3009,9 +3284,9 @@ static int __devexit ehea_remove(struct ibmebus_dev *dev)
ehea_remove_device_sysfs(dev);
- destroy_workqueue(adapter->ehea_wq);
+ flush_scheduled_work();
- ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
+ ibmebus_free_irq(adapter->neq->attr.ist1, adapter);
tasklet_kill(&adapter->neq_tasklet);
ehea_destroy_eq(adapter->neq);
@@ -3023,6 +3298,20 @@ static int __devexit ehea_remove(struct ibmebus_dev *dev)
return 0;
}
+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");
+ ibmebus_unregister_driver(&ehea_driver);
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block ehea_reboot_nb = {
+ .notifier_call = ehea_reboot_notifier,
+};
+
static int check_module_parm(void)
{
int ret = 0;
@@ -3067,9 +3356,9 @@ int __init ehea_module_init(void)
printk(KERN_INFO "IBM eHEA ethernet device driver (Release %s)\n",
DRV_VERSION);
- ehea_driver_wq = create_workqueue("ehea_driver_wq");
INIT_WORK(&ehea_rereg_mr_task, ehea_rereg_mrs);
+ sema_init(&dlpar_mem_lock, 1);
ret = check_module_parm();
if (ret)
@@ -3079,6 +3368,8 @@ int __init ehea_module_init(void)
if (ret)
goto out;
+ register_reboot_notifier(&ehea_reboot_nb);
+
ret = ibmebus_register_driver(&ehea_driver);
if (ret) {
ehea_error("failed registering eHEA device driver on ebus");
@@ -3090,6 +3381,7 @@ int __init ehea_module_init(void)
if (ret) {
ehea_error("failed to register capabilities attribute, ret=%d",
ret);
+ unregister_reboot_notifier(&ehea_reboot_nb);
ibmebus_unregister_driver(&ehea_driver);
goto out;
}
@@ -3100,9 +3392,10 @@ out:
static void __exit ehea_module_exit(void)
{
- destroy_workqueue(ehea_driver_wq);
+ flush_scheduled_work();
driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
ibmebus_unregister_driver(&ehea_driver);
+ unregister_reboot_notifier(&ehea_reboot_nb);
ehea_destroy_busmap();
}
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h
index 89b63531ff2..faa191d23b8 100644
--- a/drivers/net/ehea/ehea_phyp.h
+++ b/drivers/net/ehea/ehea_phyp.h
@@ -126,6 +126,7 @@ struct hcp_modify_qp_cb0 {
#define H_QP_CR_STATE_RDY2RCV 0x0000030000000000ULL /* Ready to recv */
#define H_QP_CR_STATE_RDY2SND 0x0000050000000000ULL /* Ready to send */
#define H_QP_CR_STATE_ERROR 0x0000800000000000ULL /* Error */
+#define H_QP_CR_RES_STATE 0x0000007F00000000ULL /* Resultant state */
struct hcp_modify_qp_cb1 {
u32 qpn; /* 00 */
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index c82e2459607..83b76432b41 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -34,7 +34,6 @@
struct ehea_busmap ehea_bmap = { 0, 0, NULL };
extern u64 ehea_driver_flags;
-extern struct workqueue_struct *ehea_driver_wq;
extern struct work_struct ehea_rereg_mr_task;
@@ -563,8 +562,7 @@ int ehea_destroy_qp(struct ehea_qp *qp)
int ehea_create_busmap( void )
{
u64 vaddr = EHEA_BUSMAP_START;
- unsigned long abs_max_pfn = 0;
- unsigned long sec_max_pfn;
+ unsigned long high_section_index = 0;
int i;
/*
@@ -574,14 +572,10 @@ int ehea_create_busmap( void )
ehea_bmap.valid_sections = 0;
for (i = 0; i < NR_MEM_SECTIONS; i++)
- if (valid_section_nr(i)) {
- sec_max_pfn = section_nr_to_pfn(i);
- if (sec_max_pfn > abs_max_pfn)
- abs_max_pfn = sec_max_pfn;
- ehea_bmap.valid_sections++;
- }
+ if (valid_section_nr(i))
+ high_section_index = i;
- ehea_bmap.entries = abs_max_pfn / EHEA_PAGES_PER_SECTION + 1;
+ ehea_bmap.entries = high_section_index + 1;
ehea_bmap.vaddr = vmalloc(ehea_bmap.entries * sizeof(*ehea_bmap.vaddr));
if (!ehea_bmap.vaddr)
@@ -593,6 +587,7 @@ int ehea_create_busmap( void )
if (pfn_valid(pfn)) {
ehea_bmap.vaddr[i] = vaddr;
vaddr += EHEA_SECTSIZE;
+ ehea_bmap.valid_sections++;
} else
ehea_bmap.vaddr[i] = 0;
}
@@ -622,7 +617,7 @@ u64 ehea_map_vaddr(void *caddr)
if (unlikely(mapped_addr == -1))
if (!test_and_set_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
- queue_work(ehea_driver_wq, &ehea_rereg_mr_task);
+ schedule_work(&ehea_rereg_mr_task);
return mapped_addr;
}
@@ -637,7 +632,7 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
mr_len = ehea_bmap.valid_sections * EHEA_SECTSIZE;
- pt = kzalloc(EHEA_MAX_RPAGE * sizeof(u64), GFP_KERNEL);
+ pt = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!pt) {
ehea_error("no mem");
ret = -ENOMEM;
@@ -660,8 +655,8 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
void *sectbase = __va(i << SECTION_SIZE_BITS);
unsigned long k = 0;
- for (j = 0; j < (PAGES_PER_SECTION / EHEA_MAX_RPAGE);
- j++) {
+ for (j = 0; j < (EHEA_PAGES_PER_SECTION /
+ EHEA_MAX_RPAGE); j++) {
for (m = 0; m < EHEA_MAX_RPAGE; m++) {
pg = sectbase + ((k++) * EHEA_PAGESIZE);
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index b71f8452a5e..562de0ebdd8 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -39,7 +39,7 @@
#define EHEA_PAGESHIFT 12
#define EHEA_PAGESIZE (1UL << EHEA_PAGESHIFT)
#define EHEA_SECTSIZE (1UL << 24)
-#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> PAGE_SHIFT)
+#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> EHEA_PAGESHIFT)
#if (1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE
#error eHEA module can't work if kernel sectionsize < ehea sectionsize
@@ -145,7 +145,7 @@ struct ehea_rwqe {
#define EHEA_CQE_VLAN_TAG_XTRACT 0x0400
#define EHEA_CQE_TYPE_RQ 0x60
-#define EHEA_CQE_STAT_ERR_MASK 0x721F
+#define EHEA_CQE_STAT_ERR_MASK 0x720F
#define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F
#define EHEA_CQE_STAT_ERR_TCP 0x4000
#define EHEA_CQE_STAT_ERR_IP 0x2000
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 119778401e4..ecdd3fc8d70 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -262,6 +262,7 @@ struct epic_private {
/* Ring pointers. */
spinlock_t lock; /* Group with Tx control cache line. */
spinlock_t napi_lock;
+ struct napi_struct napi;
unsigned int reschedule_in_poll;
unsigned int cur_tx, dirty_tx;
@@ -294,7 +295,7 @@ static void epic_tx_timeout(struct net_device *dev);
static void epic_init_ring(struct net_device *dev);
static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int epic_rx(struct net_device *dev, int budget);
-static int epic_poll(struct net_device *dev, int *budget);
+static int epic_poll(struct napi_struct *napi, int budget);
static irqreturn_t epic_interrupt(int irq, void *dev_instance);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static const struct ethtool_ops netdev_ethtool_ops;
@@ -316,6 +317,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
int i, ret, option = 0, duplex = 0;
void *ring_space;
dma_addr_t ring_dma;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -351,7 +353,6 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
dev_err(&pdev->dev, "no memory for eth device\n");
goto err_out_free_res;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
#ifdef USE_IO_OPS
@@ -487,18 +488,15 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
dev->ethtool_ops = &netdev_ethtool_ops;
dev->watchdog_timeo = TX_TIMEOUT;
dev->tx_timeout = &epic_tx_timeout;
- dev->poll = epic_poll;
- dev->weight = 64;
+ netif_napi_add(dev, &ep->napi, epic_poll, 64);
ret = register_netdev(dev);
if (ret < 0)
goto err_out_unmap_rx;
- printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
- dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x.\n", dev->dev_addr[i]);
+ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n",
+ dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq,
+ print_mac(mac, dev->dev_addr));
out:
return ret;
@@ -660,8 +658,11 @@ static int epic_open(struct net_device *dev)
/* Soft reset the chip. */
outl(0x4001, ioaddr + GENCTL);
- if ((retval = request_irq(dev->irq, &epic_interrupt, IRQF_SHARED, dev->name, dev)))
+ napi_enable(&ep->napi);
+ if ((retval = request_irq(dev->irq, &epic_interrupt, IRQF_SHARED, dev->name, dev))) {
+ napi_disable(&ep->napi);
return retval;
+ }
epic_init_ring(dev);
@@ -1103,9 +1104,9 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance)
if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) {
spin_lock(&ep->napi_lock);
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &ep->napi)) {
epic_napi_irq_off(dev, ep);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &ep->napi);
} else
ep->reschedule_in_poll++;
spin_unlock(&ep->napi_lock);
@@ -1257,26 +1258,22 @@ static void epic_rx_err(struct net_device *dev, struct epic_private *ep)
outw(RxQueued, ioaddr + COMMAND);
}
-static int epic_poll(struct net_device *dev, int *budget)
+static int epic_poll(struct napi_struct *napi, int budget)
{
- struct epic_private *ep = dev->priv;
- int work_done = 0, orig_budget;
+ struct epic_private *ep = container_of(napi, struct epic_private, napi);
+ struct net_device *dev = ep->mii.dev;
+ int work_done = 0;
long ioaddr = dev->base_addr;
- orig_budget = (*budget > dev->quota) ? dev->quota : *budget;
-
rx_action:
epic_tx(dev, ep);
- work_done += epic_rx(dev, *budget);
+ work_done += epic_rx(dev, budget);
epic_rx_err(dev, ep);
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (netif_running(dev) && (work_done < orig_budget)) {
+ if (netif_running(dev) && (work_done < budget)) {
unsigned long flags;
int more;
@@ -1286,7 +1283,7 @@ rx_action:
more = ep->reschedule_in_poll;
if (!more) {
- __netif_rx_complete(dev);
+ __netif_rx_complete(dev, napi);
outl(EpicNapiEvent, ioaddr + INTSTAT);
epic_napi_irq_on(dev, ep);
} else
@@ -1298,7 +1295,7 @@ rx_action:
goto rx_action;
}
- return (work_done >= orig_budget);
+ return work_done;
}
static int epic_close(struct net_device *dev)
@@ -1309,6 +1306,7 @@ static int epic_close(struct net_device *dev)
int i;
netif_stop_queue(dev);
+ napi_disable(&ep->napi);
if (debug > 1)
printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
@@ -1495,8 +1493,6 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.get_link = netdev_get_link,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
- .get_sg = ethtool_op_get_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
.begin = ethtool_begin,
.complete = ethtool_complete
};
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
index 102218c4a90..18f1364d3d5 100644
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -116,6 +116,7 @@
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/netdevice.h>
+#include <net/net_namespace.h>
#include <linux/if.h>
#include <linux/if_arp.h>
@@ -127,7 +128,6 @@ static int eql_open(struct net_device *dev);
static int eql_close(struct net_device *dev);
static int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *eql_get_stats(struct net_device *dev);
#define eql_is_slave(dev) ((dev->flags & IFF_SLAVE) == IFF_SLAVE)
#define eql_is_master(dev) ((dev->flags & IFF_MASTER) == IFF_MASTER)
@@ -166,8 +166,6 @@ static void __init eql_setup(struct net_device *dev)
{
equalizer_t *eql = netdev_priv(dev);
- SET_MODULE_OWNER(dev);
-
init_timer(&eql->timer);
eql->timer.data = (unsigned long) eql;
eql->timer.expires = jiffies + EQL_DEFAULT_RESCHED_IVAL;
@@ -181,7 +179,6 @@ static void __init eql_setup(struct net_device *dev)
dev->stop = eql_close;
dev->do_ioctl = eql_ioctl;
dev->hard_start_xmit = eql_slave_xmit;
- dev->get_stats = eql_get_stats;
/*
* Now we undo some of the things that eth_setup does
@@ -338,9 +335,9 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev)
skb->priority = 1;
slave->bytes_queued += skb->len;
dev_queue_xmit(skb);
- eql->stats.tx_packets++;
+ dev->stats.tx_packets++;
} else {
- eql->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
}
@@ -349,12 +346,6 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static struct net_device_stats * eql_get_stats(struct net_device *dev)
-{
- equalizer_t *eql = netdev_priv(dev);
- return &eql->stats;
-}
-
/*
* Private ioctl functions
*/
@@ -412,7 +403,7 @@ static int eql_enslave(struct net_device *master_dev, slaving_request_t __user *
if (copy_from_user(&srq, srqp, sizeof (slaving_request_t)))
return -EFAULT;
- slave_dev = dev_get_by_name(srq.slave_name);
+ slave_dev = dev_get_by_name(&init_net, srq.slave_name);
if (slave_dev) {
if ((master_dev->flags & IFF_UP) == IFF_UP) {
/* slave is not a master & not already a slave: */
@@ -460,7 +451,7 @@ static int eql_emancipate(struct net_device *master_dev, slaving_request_t __use
if (copy_from_user(&srq, srqp, sizeof (slaving_request_t)))
return -EFAULT;
- slave_dev = dev_get_by_name(srq.slave_name);
+ slave_dev = dev_get_by_name(&init_net, srq.slave_name);
ret = -EINVAL;
if (slave_dev) {
spin_lock_bh(&eql->queue.lock);
@@ -493,7 +484,7 @@ static int eql_g_slave_cfg(struct net_device *dev, slave_config_t __user *scp)
if (copy_from_user(&sc, scp, sizeof (slave_config_t)))
return -EFAULT;
- slave_dev = dev_get_by_name(sc.slave_name);
+ slave_dev = dev_get_by_name(&init_net, sc.slave_name);
if (!slave_dev)
return -ENODEV;
@@ -528,7 +519,7 @@ static int eql_s_slave_cfg(struct net_device *dev, slave_config_t __user *scp)
if (copy_from_user(&sc, scp, sizeof (slave_config_t)))
return -EFAULT;
- slave_dev = dev_get_by_name(sc.slave_name);
+ slave_dev = dev_get_by_name(&init_net, sc.slave_name);
if (!slave_dev)
return -ENODEV;
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index 822e5bfd1a7..deefa51b8c3 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -130,8 +130,6 @@ static int __init do_es_probe(struct net_device *dev)
int irq = dev->irq;
int mem_start = dev->mem_start;
- SET_MODULE_OWNER(dev);
-
if (ioaddr > 0x1ff) /* Check a single specified location. */
return es_probe1(dev, ioaddr);
else if (ioaddr > 0) /* Don't probe at all. */
@@ -181,6 +179,7 @@ static int __init es_probe1(struct net_device *dev, int ioaddr)
{
int i, retval;
unsigned long eisa_id;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT, "es3210"))
return -ENODEV;
@@ -192,7 +191,6 @@ static int __init es_probe1(struct net_device *dev, int ioaddr)
inb(ioaddr + ES_CFG4), inb(ioaddr + ES_CFG5), inb(ioaddr + ES_CFG6));
#endif
-
/* Check the EISA ID of the card. */
eisa_id = inl(ioaddr + ES_ID_PORT);
if ((eisa_id != ES_EISA_ID1) && (eisa_id != ES_EISA_ID2)) {
@@ -200,21 +198,21 @@ static int __init es_probe1(struct net_device *dev, int ioaddr)
goto out;
}
+ for (i = 0; i < ETHER_ADDR_LEN ; i++)
+ dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i);
+
/* Check the Racal vendor ID as well. */
- if (inb(ioaddr + ES_SA_PROM + 0) != ES_ADDR0
- || inb(ioaddr + ES_SA_PROM + 1) != ES_ADDR1
- || inb(ioaddr + ES_SA_PROM + 2) != ES_ADDR2 ) {
- printk("es3210.c: card not found");
- for(i = 0; i < ETHER_ADDR_LEN; i++)
- printk(" %02x", inb(ioaddr + ES_SA_PROM + i));
- printk(" (invalid prefix).\n");
+ if (dev->dev_addr[0] != ES_ADDR0 ||
+ dev->dev_addr[1] != ES_ADDR1 ||
+ dev->dev_addr[2] != ES_ADDR2) {
+ printk("es3210.c: card not found %s (invalid_prefix).\n",
+ print_mac(mac, dev->dev_addr));
retval = -ENODEV;
goto out;
}
- printk("es3210.c: ES3210 rev. %ld at %#x, node", eisa_id>>24, ioaddr);
- for(i = 0; i < ETHER_ADDR_LEN; i++)
- printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i)));
+ printk("es3210.c: ES3210 rev. %ld at %#x, node %s",
+ eisa_id>>24, ioaddr, print_mac(mac, dev->dev_addr));
/* Snarf the interrupt now. */
if (dev->irq == 0) {
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 04abf59e500..e3dd8b13690 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -170,7 +170,6 @@ static char *version =
/* Few macros */
-#define BIT(a) ( (1 << (a)) )
#define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr)))
#define BITCLR(ioaddr, bnum) ((outb(((inb(ioaddr)) & (~(bnum))), ioaddr)))
@@ -380,7 +379,6 @@ static unsigned int eth16i_debug = ETH16I_DEBUG;
/* Information for each board */
struct eth16i_local {
- struct net_device_stats stats;
unsigned char tx_started;
unsigned char tx_buf_busy;
unsigned short tx_queue; /* Number of packets in transmit buffer */
@@ -426,8 +424,6 @@ static int eth16i_set_irq(struct net_device *dev);
static ushort eth16i_parse_mediatype(const char* s);
#endif
-static struct net_device_stats *eth16i_get_stats(struct net_device *dev);
-
static char cardname[] __initdata = "ICL EtherTeam 16i/32";
static int __init do_eth16i_probe(struct net_device *dev)
@@ -436,8 +432,6 @@ static int __init do_eth16i_probe(struct net_device *dev)
int ioaddr;
int base_addr = dev->base_addr;
- SET_MODULE_OWNER(dev);
-
if(eth16i_debug > 4)
printk(KERN_DEBUG "Probing started for %s\n", cardname);
@@ -559,7 +553,6 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
dev->open = eth16i_open;
dev->stop = eth16i_close;
dev->hard_start_xmit = eth16i_tx;
- dev->get_stats = eth16i_get_stats;
dev->set_multicast_list = eth16i_multicast;
dev->tx_timeout = eth16i_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -1047,7 +1040,7 @@ static void eth16i_timeout(struct net_device *dev)
printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
}
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
eth16i_reset(dev);
dev->trans_start = jiffies;
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
@@ -1132,7 +1125,6 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
static void eth16i_rx(struct net_device *dev)
{
- struct eth16i_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int boguscount = MAX_RX_LOOP;
@@ -1151,16 +1143,16 @@ static void eth16i_rx(struct net_device *dev)
inb(ioaddr + RECEIVE_MODE_REG), status);
if( !(status & PKT_GOOD) ) {
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) {
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
eth16i_reset(dev);
return;
}
else {
eth16i_skip_packet(dev);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
}
else { /* Ok so now we should have a good packet */
@@ -1171,7 +1163,7 @@ static void eth16i_rx(struct net_device *dev)
printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n",
dev->name, pkt_len);
eth16i_skip_packet(dev);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
@@ -1214,8 +1206,8 @@ static void eth16i_rx(struct net_device *dev)
}
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
} /* else */
@@ -1252,32 +1244,32 @@ static irqreturn_t eth16i_interrupt(int irq, void *dev_id)
if( status & 0x7f00 ) {
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if(status & (BUS_RD_ERR << 8) )
printk(KERN_WARNING "%s: Bus read error.\n",dev->name);
- if(status & (SHORT_PKT_ERR << 8) ) lp->stats.rx_length_errors++;
- if(status & (ALIGN_ERR << 8) ) lp->stats.rx_frame_errors++;
- if(status & (CRC_ERR << 8) ) lp->stats.rx_crc_errors++;
- if(status & (RX_BUF_OVERFLOW << 8) ) lp->stats.rx_over_errors++;
+ if(status & (SHORT_PKT_ERR << 8) ) dev->stats.rx_length_errors++;
+ if(status & (ALIGN_ERR << 8) ) dev->stats.rx_frame_errors++;
+ if(status & (CRC_ERR << 8) ) dev->stats.rx_crc_errors++;
+ if(status & (RX_BUF_OVERFLOW << 8) ) dev->stats.rx_over_errors++;
}
if( status & 0x001a) {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
- if(status & CR_LOST) lp->stats.tx_carrier_errors++;
- if(status & TX_JABBER_ERR) lp->stats.tx_window_errors++;
+ if(status & CR_LOST) dev->stats.tx_carrier_errors++;
+ if(status & TX_JABBER_ERR) dev->stats.tx_window_errors++;
#if 0
if(status & COLLISION) {
- lp->stats.collisions +=
+ dev->stats.collisions +=
((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4);
}
#endif
if(status & COLLISIONS_16) {
if(lp->col_16 < MAX_COL_16) {
lp->col_16++;
- lp->stats.collisions++;
+ dev->stats.collisions++;
/* Resume transmitting, skip failed packet */
outb(0x02, ioaddr + COL_16_REG);
}
@@ -1290,8 +1282,8 @@ static irqreturn_t eth16i_interrupt(int irq, void *dev_id)
if( status & 0x00ff ) { /* Let's check the transmit status reg */
if(status & TX_DONE) { /* The transmit has been done */
- lp->stats.tx_packets = lp->tx_buffered_packets;
- lp->stats.tx_bytes += lp->tx_buffered_bytes;
+ dev->stats.tx_packets = lp->tx_buffered_packets;
+ dev->stats.tx_bytes += lp->tx_buffered_bytes;
lp->col_16 = 0;
if(lp->tx_queue) { /* Is there still packets ? */
@@ -1371,12 +1363,6 @@ static void eth16i_multicast(struct net_device *dev)
}
}
-static struct net_device_stats *eth16i_get_stats(struct net_device *dev)
-{
- struct eth16i_local *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
static void eth16i_select_regbank(unsigned char banknbr, int ioaddr)
{
unsigned char data;
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index cb0792c187b..593a120e31b 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -275,7 +275,6 @@ struct ewrk3_private {
u_long shmem_base; /* Shared memory start address */
void __iomem *shmem;
u_long shmem_length; /* Shared memory window length */
- struct net_device_stats stats; /* Public stats */
struct ewrk3_stats pktStats; /* Private stats counters */
u_char irq_mask; /* Adapter IRQ mask bits */
u_char mPage; /* Maximum 2kB Page number */
@@ -302,7 +301,6 @@ static int ewrk3_open(struct net_device *dev);
static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t ewrk3_interrupt(int irq, void *dev_id);
static int ewrk3_close(struct net_device *dev);
-static struct net_device_stats *ewrk3_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static const struct ethtool_ops ethtool_ops_203;
@@ -356,7 +354,6 @@ struct net_device * __init ewrk3_probe(int unit)
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
err = ewrk3_probe1(dev, dev->base_addr, dev->irq);
if (err)
@@ -399,6 +396,7 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
u_long mem_start, shmem_length;
u_char cr, cmr, icr, nicsr, lemac, hard_strapped = 0;
u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0;
+ DECLARE_MAC_BUF(mac);
/*
** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot.
@@ -463,10 +461,7 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
if (lemac != LeMAC2)
DevicePresent(iobase); /* need after EWRK3_INIT */
status = get_hw_addr(dev, eeprom_image, lemac);
- for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */
- printk("%2.2x:", dev->dev_addr[i]);
- }
- printk("%2.2x,\n", dev->dev_addr[i]);
+ printk("%s\n", print_mac(mac, dev->dev_addr));
if (status) {
printk(" which has an EEPROM CRC error.\n");
@@ -612,7 +607,6 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
dev->open = ewrk3_open;
dev->hard_start_xmit = ewrk3_queue_pkt;
dev->stop = ewrk3_close;
- dev->get_stats = ewrk3_get_stats;
dev->set_multicast_list = set_multicast_list;
dev->do_ioctl = ewrk3_ioctl;
if (lp->adapter_name[4] == '3')
@@ -632,7 +626,7 @@ static int ewrk3_open(struct net_device *dev)
{
struct ewrk3_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
- int i, status = 0;
+ int status = 0;
u_char icr, csr;
/*
@@ -652,12 +646,10 @@ static int ewrk3_open(struct net_device *dev)
ewrk3_init(dev);
if (ewrk3_debug > 1) {
+ DECLARE_MAC_BUF(mac);
printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq);
- printk(" physical address: ");
- for (i = 0; i < 5; i++) {
- printk("%2.2x:", (u_char) dev->dev_addr[i]);
- }
- printk("%2.2x\n", (u_char) dev->dev_addr[i]);
+ printk(" physical address: %s\n",
+ print_mac(mac, dev->dev_addr));
if (lp->shmem_length == 0) {
printk(" no shared memory, I/O only mode\n");
} else {
@@ -864,7 +856,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev)
ENABLE_IRQs;
spin_unlock_irq (&lp->hw_lock);
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
dev->trans_start = jiffies;
dev_kfree_skb (skb);
@@ -981,13 +973,13 @@ static int ewrk3_rx(struct net_device *dev)
}
if (!(rx_status & R_ROK)) { /* There was an error. */
- lp->stats.rx_errors++; /* Update the error stats. */
+ dev->stats.rx_errors++; /* Update the error stats. */
if (rx_status & R_DBE)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rx_status & R_CRC)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rx_status & R_PLL)
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
} else {
struct sk_buff *skb;
@@ -1038,11 +1030,11 @@ static int ewrk3_rx(struct net_device *dev)
** Update stats
*/
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
} else {
printk("%s: Insufficient memory; nuking packet.\n", dev->name);
- lp->stats.rx_dropped++; /* Really, deferred. */
+ dev->stats.rx_dropped++; /* Really, deferred. */
break;
}
}
@@ -1072,11 +1064,11 @@ static int ewrk3_tx(struct net_device *dev)
while ((tx_status = inb(EWRK3_TDQ)) > 0) { /* Whilst there's old buffers */
if (tx_status & T_VSTS) { /* The status is valid */
if (tx_status & T_TXE) {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (tx_status & T_NCL)
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (tx_status & T_LCL)
- lp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (tx_status & T_CTU) {
if ((tx_status & T_COLL) ^ T_XUR) {
lp->pktStats.tx_underruns++;
@@ -1085,13 +1077,13 @@ static int ewrk3_tx(struct net_device *dev)
}
} else if (tx_status & T_COLL) {
if ((tx_status & T_COLL) ^ T_XCOLL) {
- lp->stats.collisions++;
+ dev->stats.collisions++;
} else {
lp->pktStats.excessive_collisions++;
}
}
} else {
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
}
}
@@ -1134,14 +1126,6 @@ static int ewrk3_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *ewrk3_get_stats(struct net_device *dev)
-{
- struct ewrk3_private *lp = netdev_priv(dev);
-
- /* Null body since there is no framing error counter */
- return &lp->stats;
-}
-
/*
** Set or clear the multicast filter for this adapter.
*/
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index ff9f177d715..7bb9c728a1d 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -111,7 +111,6 @@ MODULE_AUTHOR("Myson or whoever");
MODULE_DESCRIPTION("Myson MTD-8xx 100/10M Ethernet PCI Adapter Driver");
MODULE_LICENSE("GPL");
module_param(max_interrupt_work, int, 0);
-//MODULE_PARM(min_pci_latency, "i");
module_param(debug, int, 0);
module_param(rx_copybreak, int, 0);
module_param(multicast_filter_limit, int, 0);
@@ -486,6 +485,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
#else
int bar = 1;
#endif
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -527,7 +527,6 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
err = -ENOMEM;
goto err_out_unmap;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/* read ethernet id */
@@ -665,11 +664,9 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
if (err)
goto err_out_free_tx;
- printk(KERN_INFO "%s: %s at %p, ",
- dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+ printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+ dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr,
+ print_mac(mac, dev->dev_addr), irq);
return 0;
@@ -1892,8 +1889,6 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.get_link = netdev_get_link,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
- .get_sg = ethtool_op_get_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
};
static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 4e8df910c00..0fbf1bbbaee 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -204,7 +204,6 @@ struct fec_enet_private {
cbd_t *tx_bd_base;
cbd_t *cur_rx, *cur_tx; /* The next free ring entry */
cbd_t *dirty_tx; /* The ring entries to be free()ed. */
- struct net_device_stats stats;
uint tx_full;
spinlock_t lock;
@@ -234,7 +233,6 @@ static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
static void fec_enet_tx(struct net_device *dev);
static void fec_enet_rx(struct net_device *dev);
static int fec_enet_close(struct net_device *dev);
-static struct net_device_stats *fec_enet_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static void fec_restart(struct net_device *dev, int duplex);
static void fec_stop(struct net_device *dev);
@@ -359,7 +357,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
fep->tx_skbuff[fep->skb_cur] = skb;
- fep->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK;
/* Push the data cache so the CPM does not get stale memory
@@ -409,7 +407,7 @@ fec_timeout(struct net_device *dev)
struct fec_enet_private *fep = netdev_priv(dev);
printk("%s: transmit timed out.\n", dev->name);
- fep->stats.tx_errors++;
+ dev->stats.tx_errors++;
#ifndef final_version
{
int i;
@@ -511,19 +509,19 @@ fec_enet_tx(struct net_device *dev)
if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
BD_ENET_TX_RL | BD_ENET_TX_UN |
BD_ENET_TX_CSL)) {
- fep->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (status & BD_ENET_TX_HB) /* No heartbeat */
- fep->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
if (status & BD_ENET_TX_LC) /* Late collision */
- fep->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (status & BD_ENET_TX_RL) /* Retrans limit */
- fep->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (status & BD_ENET_TX_UN) /* Underrun */
- fep->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (status & BD_ENET_TX_CSL) /* Carrier lost */
- fep->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
} else {
- fep->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
#ifndef final_version
@@ -534,7 +532,7 @@ fec_enet_tx(struct net_device *dev)
* but we eventually sent the packet OK.
*/
if (status & BD_ENET_TX_DEF)
- fep->stats.collisions++;
+ dev->stats.collisions++;
/* Free the sk buffer associated with this last transmit.
*/
@@ -607,17 +605,17 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
/* Check for errors. */
if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
BD_ENET_RX_CR | BD_ENET_RX_OV)) {
- fep->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
/* Frame too long or too short. */
- fep->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
if (status & BD_ENET_RX_NO) /* Frame alignment */
- fep->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & BD_ENET_RX_CR) /* CRC Error */
- fep->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (status & BD_ENET_RX_OV) /* FIFO overrun */
- fep->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
}
/* Report late collisions as a frame error.
@@ -625,16 +623,16 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
* have in the buffer. So, just drop this frame on the floor.
*/
if (status & BD_ENET_RX_CL) {
- fep->stats.rx_errors++;
- fep->stats.rx_frame_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_frame_errors++;
goto rx_processing_done;
}
/* Process the incoming frame.
*/
- fep->stats.rx_packets++;
+ dev->stats.rx_packets++;
pkt_len = bdp->cbd_datlen;
- fep->stats.rx_bytes += pkt_len;
+ dev->stats.rx_bytes += pkt_len;
data = (__u8*)__va(bdp->cbd_bufaddr);
/* This does 16 byte alignment, exactly what we need.
@@ -646,7 +644,7 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
if (skb == NULL) {
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
- fep->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
} else {
skb_put(skb,pkt_len-4); /* Make room */
skb_copy_to_linear_data(skb, data, pkt_len-4);
@@ -753,13 +751,11 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
if (mii_head) {
mii_tail->mii_next = mip;
mii_tail = mip;
- }
- else {
+ } else {
mii_head = mii_tail = mip;
fep->hwp->fec_mii_data = regval;
}
- }
- else {
+ } else {
retval = 1;
}
@@ -770,14 +766,11 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
{
- int k;
-
if(!c)
return;
- for(k = 0; (c+k)->mii_data != mk_mii_end; k++) {
- mii_queue(dev, (c+k)->mii_data, (c+k)->funct);
- }
+ for (; c->mii_data != mk_mii_end; c++)
+ mii_queue(dev, c->mii_data, c->funct);
}
static void mii_parse_sr(uint mii_reg, struct net_device *dev)
@@ -794,7 +787,6 @@ static void mii_parse_sr(uint mii_reg, struct net_device *dev)
status |= PHY_STAT_FAULT;
if (mii_reg & 0x0020)
status |= PHY_STAT_ANC;
-
*s = status;
}
@@ -1241,7 +1233,6 @@ mii_link_interrupt(int irq, void * dev_id);
#endif
#if defined(CONFIG_M5272)
-
/*
* Code specific to Coldfire 5272 setup.
*/
@@ -2022,8 +2013,7 @@ static void mii_relink(struct work_struct *work)
& (PHY_STAT_100FDX | PHY_STAT_10FDX))
duplex = 1;
fec_restart(dev, duplex);
- }
- else
+ } else
fec_stop(dev);
#if 0
@@ -2121,8 +2111,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
fep->phy_id = phytype << 16;
mii_queue(dev, mk_mii_read(MII_REG_PHYIR2),
mii_discover_phy3);
- }
- else {
+ } else {
fep->phy_addr++;
mii_queue(dev, mk_mii_read(MII_REG_PHYIR1),
mii_discover_phy);
@@ -2220,13 +2209,6 @@ fec_enet_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *fec_enet_get_stats(struct net_device *dev)
-{
- struct fec_enet_private *fep = netdev_priv(dev);
-
- return &fep->stats;
-}
-
/* Set or clear the multicast filter for this adaptor.
* Skeleton taken from sunlance driver.
* The CPM Ethernet implementation allows Multicast as well as individual
@@ -2462,7 +2444,6 @@ int __init fec_enet_init(struct net_device *dev)
dev->tx_timeout = fec_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
dev->stop = fec_enet_close;
- dev->get_stats = fec_enet_get_stats;
dev->set_multicast_list = set_multicast_list;
for (i=0; i<NMII-1; i++)
@@ -2584,8 +2565,7 @@ fec_restart(struct net_device *dev, int duplex)
if (duplex) {
fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;/* MII enable */
fecp->fec_x_cntrl = 0x04; /* FD enable */
- }
- else {
+ } else {
/* MII enable|No Rcv on Xmit */
fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x06;
fecp->fec_x_cntrl = 0x00;
@@ -2645,6 +2625,7 @@ static int __init fec_enet_module_init(void)
{
struct net_device *dev;
int i, j, err;
+ DECLARE_MAC_BUF(mac);
printk("FEC ENET Version 0.2\n");
@@ -2663,10 +2644,8 @@ static int __init fec_enet_module_init(void)
return -EIO;
}
- printk("%s: ethernet ", dev->name);
- for (j = 0; (j < 5); j++)
- printk("%02x:", dev->dev_addr[j]);
- printk("%02x\n", dev->dev_addr[5]);
+ printk("%s: ethernet %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
}
return 0;
}
diff --git a/drivers/net/fec_8xx/fec_8xx.h b/drivers/net/fec_8xx/fec_8xx.h
index 5af60b0f920..f3b1c6fbba8 100644
--- a/drivers/net/fec_8xx/fec_8xx.h
+++ b/drivers/net/fec_8xx/fec_8xx.h
@@ -105,6 +105,8 @@ struct fec;
struct fec_enet_private {
spinlock_t lock; /* during all ops except TX pckt processing */
spinlock_t tx_lock; /* during fec_start_xmit and fec_tx */
+ struct net_device *dev;
+ struct napi_struct napi;
int fecno;
struct fec *fecp;
const struct fec_platform_info *fpi;
diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c
index e5502af5b8e..8d2904fa578 100644
--- a/drivers/net/fec_8xx/fec_main.c
+++ b/drivers/net/fec_8xx/fec_main.c
@@ -465,9 +465,9 @@ void fec_stop(struct net_device *dev)
}
/* common receive function */
-static int fec_enet_rx_common(struct net_device *dev, int *budget)
+static int fec_enet_rx_common(struct fec_enet_private *ep,
+ struct net_device *dev, int budget)
{
- struct fec_enet_private *fep = netdev_priv(dev);
fec_t *fecp = fep->fecp;
const struct fec_platform_info *fpi = fep->fpi;
cbd_t *bdp;
@@ -475,11 +475,8 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget)
int received = 0;
__u16 pkt_len, sc;
int curidx;
- int rx_work_limit;
if (fpi->use_napi) {
- rx_work_limit = min(dev->quota, *budget);
-
if (!netif_running(dev))
return 0;
}
@@ -530,11 +527,6 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget)
BUG_ON(skbn == NULL);
} else {
-
- /* napi, got packet but no quota */
- if (fpi->use_napi && --rx_work_limit < 0)
- break;
-
skb = fep->rx_skbuff[curidx];
BUG_ON(skb == NULL);
@@ -599,25 +591,24 @@ static int fec_enet_rx_common(struct net_device *dev, int *budget)
* able to keep up at the expense of system resources.
*/
FW(fecp, r_des_active, 0x01000000);
+
+ if (received >= budget)
+ break;
+
}
fep->cur_rx = bdp;
if (fpi->use_napi) {
- dev->quota -= received;
- *budget -= received;
-
- if (rx_work_limit < 0)
- return 1; /* not done */
+ if (received < budget) {
+ netif_rx_complete(dev, &fep->napi);
- /* done */
- netif_rx_complete(dev);
-
- /* enable RX interrupt bits */
- FS(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB);
+ /* enable RX interrupt bits */
+ FS(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB);
+ }
}
- return 0;
+ return received;
}
static void fec_enet_tx(struct net_device *dev)
@@ -743,12 +734,12 @@ fec_enet_interrupt(int irq, void *dev_id)
if ((int_events & FEC_ENET_RXF) != 0) {
if (!fpi->use_napi)
- fec_enet_rx_common(dev, NULL);
+ fec_enet_rx_common(fep, dev, ~0);
else {
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &fep->napi)) {
/* disable rx interrupts */
FC(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &fep->napi);
} else {
printk(KERN_ERR DRV_MODULE_NAME
": %s driver bug! interrupt while in poll!\n",
@@ -893,10 +884,13 @@ static int fec_enet_open(struct net_device *dev)
const struct fec_platform_info *fpi = fep->fpi;
unsigned long flags;
+ napi_enable(&fep->napi);
+
/* Install our interrupt handler. */
if (request_irq(fpi->fec_irq, fec_enet_interrupt, 0, "fec", dev) != 0) {
printk(KERN_ERR DRV_MODULE_NAME
": %s Could not allocate FEC IRQ!", dev->name);
+ napi_disable(&fep->napi);
return -EINVAL;
}
@@ -907,6 +901,7 @@ static int fec_enet_open(struct net_device *dev)
printk(KERN_ERR DRV_MODULE_NAME
": %s Could not allocate PHY IRQ!", dev->name);
free_irq(fpi->fec_irq, dev);
+ napi_disable(&fep->napi);
return -EINVAL;
}
@@ -932,6 +927,7 @@ static int fec_enet_close(struct net_device *dev)
unsigned long flags;
netif_stop_queue(dev);
+ napi_disable(&fep->napi);
netif_carrier_off(dev);
if (fpi->use_mdio)
@@ -955,9 +951,12 @@ static struct net_device_stats *fec_enet_get_stats(struct net_device *dev)
return &fep->stats;
}
-static int fec_enet_poll(struct net_device *dev, int *budget)
+static int fec_enet_poll(struct napi_struct *napi, int budget)
{
- return fec_enet_rx_common(dev, budget);
+ struct fec_enet_private *fep = container_of(napi, struct fec_enet_private, napi);
+ struct net_device *dev = fep->dev;
+
+ return fec_enet_rx_common(fep, dev, budget);
}
/*************************************************************************/
@@ -1042,9 +1041,7 @@ static const struct ethtool_ops fec_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_msglevel = fec_get_msglevel,
.set_msglevel = fec_set_msglevel,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum, /* local! */
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_regs = fec_get_regs,
};
@@ -1104,9 +1101,9 @@ int fec_8xx_init_one(const struct fec_platform_info *fpi,
err = -ENOMEM;
goto err;
}
- SET_MODULE_OWNER(dev);
fep = netdev_priv(dev);
+ fep->dev = dev;
/* partial reset of FEC */
fec_whack_reset(fecp);
@@ -1172,10 +1169,9 @@ int fec_8xx_init_one(const struct fec_platform_info *fpi,
dev->get_stats = fec_enet_get_stats;
dev->set_multicast_list = fec_set_multicast_list;
dev->set_mac_address = fec_set_mac_address;
- if (fpi->use_napi) {
- dev->poll = fec_enet_poll;
- dev->weight = fpi->napi_weight;
- }
+ netif_napi_add(dev, &fec->napi,
+ fec_enet_poll, fpi->napi_weight);
+
dev->ethtool_ops = &fec_ethtool_ops;
dev->do_ioctl = fec_ioctl;
diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c
index b3fa0d6a159..e8e10a02d20 100644
--- a/drivers/net/fec_8xx/fec_mii.c
+++ b/drivers/net/fec_8xx/fec_mii.c
@@ -308,12 +308,11 @@ int fec_mii_phy_id_detect(struct net_device *dev)
return -1;
}
- for (i = 0, phy = phy_info; i < sizeof(phy_info) / sizeof(phy_info[0]);
- i++, phy++)
+ for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++)
if (phy->id == (phy_hwid >> 4) || phy->id == 0)
break;
- if (i >= sizeof(phy_info) / sizeof(phy_info[0])) {
+ if (i >= ARRAY_SIZE(phy_info)) {
printk(KERN_ERR DRV_MODULE_NAME
": %s PHY id 0x%08x is not supported!\n",
dev->name, phy_hwid);
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
new file mode 100644
index 00000000000..a8a0ee220da
--- /dev/null
+++ b/drivers/net/fec_mpc52xx.c
@@ -0,0 +1,1112 @@
+/*
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> and
+ * now maintained by Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Copyright (C) 2007 Domen Puncer, Telargo, Inc.
+ * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>
+ * Copyright (C) 2003-2004 MontaVista, Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+#include <linux/hardirq.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/mpc52xx.h>
+
+#include <sysdev/bestcomm/bestcomm.h>
+#include <sysdev/bestcomm/fec.h>
+
+#include "fec_mpc52xx.h"
+
+#define DRIVER_NAME "mpc52xx-fec"
+
+static irqreturn_t mpc52xx_fec_interrupt(int, void *);
+static irqreturn_t mpc52xx_fec_rx_interrupt(int, void *);
+static irqreturn_t mpc52xx_fec_tx_interrupt(int, void *);
+static void mpc52xx_fec_stop(struct net_device *dev);
+static void mpc52xx_fec_start(struct net_device *dev);
+static void mpc52xx_fec_reset(struct net_device *dev);
+
+static u8 mpc52xx_fec_mac_addr[6];
+module_param_array_named(mac, mpc52xx_fec_mac_addr, byte, NULL, 0);
+MODULE_PARM_DESC(mac, "six hex digits, ie. 0x1,0x2,0xc0,0x01,0xba,0xbe");
+
+#define MPC52xx_MESSAGES_DEFAULT ( NETIF_MSG_DRV | NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFDOWN )
+static int debug = -1; /* the above default */
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "debugging messages level");
+
+static void mpc52xx_fec_tx_timeout(struct net_device *dev)
+{
+ dev_warn(&dev->dev, "transmit timed out\n");
+
+ mpc52xx_fec_reset(dev);
+
+ dev->stats.tx_errors++;
+
+ netif_wake_queue(dev);
+}
+
+static void mpc52xx_fec_set_paddr(struct net_device *dev, u8 *mac)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ out_be32(&fec->paddr1, *(u32 *)(&mac[0]));
+ out_be32(&fec->paddr2, (*(u16 *)(&mac[4]) << 16) | FEC_PADDR2_TYPE);
+}
+
+static void mpc52xx_fec_get_paddr(struct net_device *dev, u8 *mac)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ *(u32 *)(&mac[0]) = in_be32(&fec->paddr1);
+ *(u16 *)(&mac[4]) = in_be32(&fec->paddr2) >> 16;
+}
+
+static int mpc52xx_fec_set_mac_address(struct net_device *dev, void *addr)
+{
+ struct sockaddr *sock = addr;
+
+ memcpy(dev->dev_addr, sock->sa_data, dev->addr_len);
+
+ mpc52xx_fec_set_paddr(dev, sock->sa_data);
+ return 0;
+}
+
+static void mpc52xx_fec_free_rx_buffers(struct net_device *dev, struct bcom_task *s)
+{
+ while (!bcom_queue_empty(s)) {
+ struct bcom_fec_bd *bd;
+ struct sk_buff *skb;
+
+ skb = bcom_retrieve_buffer(s, NULL, (struct bcom_bd **)&bd);
+ dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_FROM_DEVICE);
+ kfree_skb(skb);
+ }
+}
+
+static int mpc52xx_fec_alloc_rx_buffers(struct net_device *dev, struct bcom_task *rxtsk)
+{
+ while (!bcom_queue_full(rxtsk)) {
+ struct sk_buff *skb;
+ struct bcom_fec_bd *bd;
+
+ skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
+ if (skb == NULL)
+ return -EAGAIN;
+
+ /* zero out the initial receive buffers to aid debugging */
+ memset(skb->data, 0, FEC_RX_BUFFER_SIZE);
+
+ bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk);
+
+ bd->status = FEC_RX_BUFFER_SIZE;
+ bd->skb_pa = dma_map_single(&dev->dev, skb->data,
+ FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ bcom_submit_next_buffer(rxtsk, skb);
+ }
+
+ return 0;
+}
+
+/* based on generic_adjust_link from fs_enet-main.c */
+static void mpc52xx_fec_adjust_link(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+ int new_state = 0;
+
+ if (phydev->link != PHY_DOWN) {
+ if (phydev->duplex != priv->duplex) {
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ u32 rcntrl;
+ u32 tcntrl;
+
+ new_state = 1;
+ priv->duplex = phydev->duplex;
+
+ rcntrl = in_be32(&fec->r_cntrl);
+ tcntrl = in_be32(&fec->x_cntrl);
+
+ rcntrl &= ~FEC_RCNTRL_DRT;
+ tcntrl &= ~FEC_TCNTRL_FDEN;
+ if (phydev->duplex == DUPLEX_FULL)
+ tcntrl |= FEC_TCNTRL_FDEN; /* FD enable */
+ else
+ rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */
+
+ out_be32(&fec->r_cntrl, rcntrl);
+ out_be32(&fec->x_cntrl, tcntrl);
+ }
+
+ if (phydev->speed != priv->speed) {
+ new_state = 1;
+ priv->speed = phydev->speed;
+ }
+
+ if (priv->link == PHY_DOWN) {
+ new_state = 1;
+ priv->link = phydev->link;
+ netif_schedule(dev);
+ netif_carrier_on(dev);
+ netif_start_queue(dev);
+ }
+
+ } else if (priv->link) {
+ new_state = 1;
+ priv->link = PHY_DOWN;
+ priv->speed = 0;
+ priv->duplex = -1;
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+ }
+
+ if (new_state && netif_msg_link(priv))
+ phy_print_status(phydev);
+}
+
+static int mpc52xx_fec_init_phy(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev;
+ char phy_id[BUS_ID_SIZE];
+
+ snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT,
+ (unsigned int)dev->base_addr, priv->phy_addr);
+
+ priv->link = PHY_DOWN;
+ priv->speed = 0;
+ priv->duplex = -1;
+
+ phydev = phy_connect(dev, phy_id, &mpc52xx_fec_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(phydev)) {
+ dev_err(&dev->dev, "phy_connect failed\n");
+ return PTR_ERR(phydev);
+ }
+ dev_info(&dev->dev, "attached phy %i to driver %s\n",
+ phydev->addr, phydev->drv->name);
+
+ priv->phydev = phydev;
+
+ return 0;
+}
+
+static int mpc52xx_fec_phy_start(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ int err;
+
+ if (!priv->has_phy)
+ return 0;
+
+ err = mpc52xx_fec_init_phy(dev);
+ if (err) {
+ dev_err(&dev->dev, "mpc52xx_fec_init_phy failed\n");
+ return err;
+ }
+
+ /* reset phy - this also wakes it from PDOWN */
+ phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
+ phy_start(priv->phydev);
+
+ return 0;
+}
+
+static void mpc52xx_fec_phy_stop(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+
+ if (!priv->has_phy)
+ return;
+
+ phy_disconnect(priv->phydev);
+ /* power down phy */
+ phy_stop(priv->phydev);
+ phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN);
+}
+
+static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv,
+ struct mii_ioctl_data *mii_data, int cmd)
+{
+ if (!priv->has_phy)
+ return -ENOTSUPP;
+
+ return phy_mii_ioctl(priv->phydev, mii_data, cmd);
+}
+
+static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv)
+{
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ if (!priv->has_phy)
+ return;
+
+ out_be32(&fec->mii_speed, priv->phy_speed);
+}
+
+static int mpc52xx_fec_open(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ int err = -EBUSY;
+
+ if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_SHARED,
+ DRIVER_NAME "_ctrl", dev)) {
+ dev_err(&dev->dev, "ctrl interrupt request failed\n");
+ goto out;
+ }
+ if (request_irq(priv->r_irq, &mpc52xx_fec_rx_interrupt, 0,
+ DRIVER_NAME "_rx", dev)) {
+ dev_err(&dev->dev, "rx interrupt request failed\n");
+ goto free_ctrl_irq;
+ }
+ if (request_irq(priv->t_irq, &mpc52xx_fec_tx_interrupt, 0,
+ DRIVER_NAME "_tx", dev)) {
+ dev_err(&dev->dev, "tx interrupt request failed\n");
+ goto free_2irqs;
+ }
+
+ bcom_fec_rx_reset(priv->rx_dmatsk);
+ bcom_fec_tx_reset(priv->tx_dmatsk);
+
+ err = mpc52xx_fec_alloc_rx_buffers(dev, priv->rx_dmatsk);
+ if (err) {
+ dev_err(&dev->dev, "mpc52xx_fec_alloc_rx_buffers failed\n");
+ goto free_irqs;
+ }
+
+ err = mpc52xx_fec_phy_start(dev);
+ if (err)
+ goto free_skbs;
+
+ bcom_enable(priv->rx_dmatsk);
+ bcom_enable(priv->tx_dmatsk);
+
+ mpc52xx_fec_start(dev);
+
+ netif_start_queue(dev);
+
+ return 0;
+
+ free_skbs:
+ mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk);
+
+ free_irqs:
+ free_irq(priv->t_irq, dev);
+ free_2irqs:
+ free_irq(priv->r_irq, dev);
+ free_ctrl_irq:
+ free_irq(dev->irq, dev);
+ out:
+
+ return err;
+}
+
+static int mpc52xx_fec_close(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+
+ mpc52xx_fec_stop(dev);
+
+ mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk);
+
+ free_irq(dev->irq, dev);
+ free_irq(priv->r_irq, dev);
+ free_irq(priv->t_irq, dev);
+
+ mpc52xx_fec_phy_stop(dev);
+
+ return 0;
+}
+
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
+static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct bcom_fec_bd *bd;
+
+ if (bcom_queue_full(priv->tx_dmatsk)) {
+ if (net_ratelimit())
+ dev_err(&dev->dev, "transmit queue overrun\n");
+ return 1;
+ }
+
+ spin_lock_irq(&priv->lock);
+ dev->trans_start = jiffies;
+
+ bd = (struct bcom_fec_bd *)
+ bcom_prepare_next_buffer(priv->tx_dmatsk);
+
+ bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_TC;
+ bd->skb_pa = dma_map_single(&dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
+
+ bcom_submit_next_buffer(priv->tx_dmatsk, skb);
+
+ if (bcom_queue_full(priv->tx_dmatsk)) {
+ netif_stop_queue(dev);
+ }
+
+ spin_unlock_irq(&priv->lock);
+
+ return 0;
+}
+
+/* This handles BestComm transmit task interrupts
+ */
+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);
+
+ spin_lock(&priv->lock);
+
+ while (bcom_buffer_done(priv->tx_dmatsk)) {
+ struct sk_buff *skb;
+ struct bcom_fec_bd *bd;
+ skb = bcom_retrieve_buffer(priv->tx_dmatsk, NULL,
+ (struct bcom_bd **)&bd);
+ dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_TO_DEVICE);
+
+ dev_kfree_skb_irq(skb);
+ }
+
+ netif_wake_queue(dev);
+
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+
+ while (bcom_buffer_done(priv->rx_dmatsk)) {
+ struct sk_buff *skb;
+ struct sk_buff *rskb;
+ struct bcom_fec_bd *bd;
+ u32 status;
+
+ rskb = bcom_retrieve_buffer(priv->rx_dmatsk, &status,
+ (struct bcom_bd **)&bd);
+ dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_FROM_DEVICE);
+
+ /* Test for errors in received frame */
+ if (status & BCOM_FEC_RX_BD_ERRORS) {
+ /* Drop packet and reuse the buffer */
+ bd = (struct bcom_fec_bd *)
+ bcom_prepare_next_buffer(priv->rx_dmatsk);
+
+ bd->status = FEC_RX_BUFFER_SIZE;
+ bd->skb_pa = dma_map_single(&dev->dev, rskb->data,
+ FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ bcom_submit_next_buffer(priv->rx_dmatsk, rskb);
+
+ dev->stats.rx_dropped++;
+
+ continue;
+ }
+
+ /* skbs are allocated on open, so now we allocate a new one,
+ * and remove the old (with the packet) */
+ skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE);
+ if (skb) {
+ /* Process the received skb */
+ int length = status & BCOM_FEC_RX_BD_LEN_MASK;
+
+ skb_put(rskb, length - 4); /* length without CRC32 */
+
+ rskb->dev = dev;
+ rskb->protocol = eth_type_trans(rskb, dev);
+
+ netif_rx(rskb);
+ dev->last_rx = jiffies;
+ } else {
+ /* Can't get a new one : reuse the same & drop pkt */
+ dev_notice(&dev->dev, "Memory squeeze, dropping packet.\n");
+ dev->stats.rx_dropped++;
+
+ skb = rskb;
+ }
+
+ bd = (struct bcom_fec_bd *)
+ bcom_prepare_next_buffer(priv->rx_dmatsk);
+
+ bd->status = FEC_RX_BUFFER_SIZE;
+ bd->skb_pa = dma_map_single(&dev->dev, rskb->data,
+ FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ bcom_submit_next_buffer(priv->rx_dmatsk, skb);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ u32 ievent;
+
+ ievent = in_be32(&fec->ievent);
+
+ ievent &= ~FEC_IEVENT_MII; /* mii is handled separately */
+ if (!ievent)
+ return IRQ_NONE;
+
+ out_be32(&fec->ievent, ievent); /* clear pending events */
+
+ if (ievent & ~(FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
+ if (ievent & ~FEC_IEVENT_TFINT)
+ dev_dbg(&dev->dev, "ievent: %08x\n", ievent);
+ return IRQ_HANDLED;
+ }
+
+ if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR))
+ dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n");
+ if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
+ dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
+
+ mpc52xx_fec_reset(dev);
+
+ netif_wake_queue(dev);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *mpc52xx_fec_get_stats(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ stats->rx_bytes = in_be32(&fec->rmon_r_octets);
+ stats->rx_packets = in_be32(&fec->rmon_r_packets);
+ stats->rx_errors = in_be32(&fec->rmon_r_crc_align) +
+ in_be32(&fec->rmon_r_undersize) +
+ in_be32(&fec->rmon_r_oversize) +
+ in_be32(&fec->rmon_r_frag) +
+ in_be32(&fec->rmon_r_jab);
+
+ stats->tx_bytes = in_be32(&fec->rmon_t_octets);
+ stats->tx_packets = in_be32(&fec->rmon_t_packets);
+ stats->tx_errors = in_be32(&fec->rmon_t_crc_align) +
+ in_be32(&fec->rmon_t_undersize) +
+ in_be32(&fec->rmon_t_oversize) +
+ in_be32(&fec->rmon_t_frag) +
+ in_be32(&fec->rmon_t_jab);
+
+ stats->multicast = in_be32(&fec->rmon_r_mc_pkt);
+ stats->collisions = in_be32(&fec->rmon_t_col);
+
+ /* detailed rx_errors: */
+ stats->rx_length_errors = in_be32(&fec->rmon_r_undersize)
+ + in_be32(&fec->rmon_r_oversize)
+ + in_be32(&fec->rmon_r_frag)
+ + in_be32(&fec->rmon_r_jab);
+ stats->rx_over_errors = in_be32(&fec->r_macerr);
+ stats->rx_crc_errors = in_be32(&fec->ieee_r_crc);
+ stats->rx_frame_errors = in_be32(&fec->ieee_r_align);
+ stats->rx_fifo_errors = in_be32(&fec->rmon_r_drop);
+ stats->rx_missed_errors = in_be32(&fec->rmon_r_drop);
+
+ /* detailed tx_errors: */
+ stats->tx_aborted_errors = 0;
+ stats->tx_carrier_errors = in_be32(&fec->ieee_t_cserr);
+ stats->tx_fifo_errors = in_be32(&fec->rmon_t_drop);
+ stats->tx_heartbeat_errors = in_be32(&fec->ieee_t_sqe);
+ stats->tx_window_errors = in_be32(&fec->ieee_t_lcol);
+
+ return stats;
+}
+
+/*
+ * Read MIB counters in order to reset them,
+ * then zero all the stats fields in memory
+ */
+static void mpc52xx_fec_reset_stats(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ out_be32(&fec->mib_control, FEC_MIB_DISABLE);
+ memset_io(&fec->rmon_t_drop, 0, (__force u32)&fec->reserved10 -
+ (__force u32)&fec->rmon_t_drop);
+ out_be32(&fec->mib_control, 0);
+
+ memset(&dev->stats, 0, sizeof(dev->stats));
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+static void mpc52xx_fec_set_multicast_list(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ u32 rx_control;
+
+ rx_control = in_be32(&fec->r_cntrl);
+
+ if (dev->flags & IFF_PROMISC) {
+ rx_control |= FEC_RCNTRL_PROM;
+ out_be32(&fec->r_cntrl, rx_control);
+ } else {
+ rx_control &= ~FEC_RCNTRL_PROM;
+ out_be32(&fec->r_cntrl, rx_control);
+
+ if (dev->flags & IFF_ALLMULTI) {
+ out_be32(&fec->gaddr1, 0xffffffff);
+ out_be32(&fec->gaddr2, 0xffffffff);
+ } else {
+ u32 crc;
+ int i;
+ struct dev_mc_list *dmi;
+ u32 gaddr1 = 0x00000000;
+ u32 gaddr2 = 0x00000000;
+
+ dmi = dev->mc_list;
+ for (i=0; i<dev->mc_count; i++) {
+ crc = ether_crc_le(6, dmi->dmi_addr) >> 26;
+ if (crc >= 32)
+ gaddr1 |= 1 << (crc-32);
+ else
+ gaddr2 |= 1 << crc;
+ dmi = dmi->next;
+ }
+ out_be32(&fec->gaddr1, gaddr1);
+ out_be32(&fec->gaddr2, gaddr2);
+ }
+ }
+}
+
+/**
+ * mpc52xx_fec_hw_init
+ * @dev: network device
+ *
+ * Setup various hardware setting, only needed once on start
+ */
+static void mpc52xx_fec_hw_init(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ int i;
+
+ /* Whack a reset. We should wait for this. */
+ out_be32(&fec->ecntrl, FEC_ECNTRL_RESET);
+ for (i = 0; i < FEC_RESET_DELAY; ++i) {
+ if ((in_be32(&fec->ecntrl) & FEC_ECNTRL_RESET) == 0)
+ break;
+ udelay(1);
+ }
+ if (i == FEC_RESET_DELAY)
+ dev_err(&dev->dev, "FEC Reset timeout!\n");
+
+ /* set pause to 0x20 frames */
+ out_be32(&fec->op_pause, FEC_OP_PAUSE_OPCODE | 0x20);
+
+ /* high service request will be deasserted when there's < 7 bytes in fifo
+ * low service request will be deasserted when there's < 4*7 bytes in fifo
+ */
+ out_be32(&fec->rfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7);
+ out_be32(&fec->tfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7);
+
+ /* alarm when <= x bytes in FIFO */
+ out_be32(&fec->rfifo_alarm, 0x0000030c);
+ out_be32(&fec->tfifo_alarm, 0x00000100);
+
+ /* begin transmittion when 256 bytes are in FIFO (or EOF or FIFO full) */
+ out_be32(&fec->x_wmrk, FEC_FIFO_WMRK_256B);
+
+ /* enable crc generation */
+ out_be32(&fec->xmit_fsm, FEC_XMIT_FSM_APPEND_CRC | FEC_XMIT_FSM_ENABLE_CRC);
+ out_be32(&fec->iaddr1, 0x00000000); /* No individual filter */
+ out_be32(&fec->iaddr2, 0x00000000); /* No individual filter */
+
+ /* set phy speed.
+ * this can't be done in phy driver, since it needs to be called
+ * before fec stuff (even on resume) */
+ mpc52xx_fec_phy_hw_init(priv);
+}
+
+/**
+ * mpc52xx_fec_start
+ * @dev: network device
+ *
+ * This function is called to start or restart the FEC during a link
+ * change. This happens on fifo errors or when switching between half
+ * and full duplex.
+ */
+static void mpc52xx_fec_start(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ u32 rcntrl;
+ u32 tcntrl;
+ u32 tmp;
+
+ /* clear sticky error bits */
+ tmp = FEC_FIFO_STATUS_ERR | FEC_FIFO_STATUS_UF | FEC_FIFO_STATUS_OF;
+ out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & tmp);
+ out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & tmp);
+
+ /* FIFOs will reset on mpc52xx_fec_enable */
+ out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET);
+
+ /* Set station address. */
+ mpc52xx_fec_set_paddr(dev, dev->dev_addr);
+
+ mpc52xx_fec_set_multicast_list(dev);
+
+ /* set max frame len, enable flow control, select mii mode */
+ rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */
+ rcntrl |= FEC_RCNTRL_FCE;
+
+ if (priv->has_phy)
+ rcntrl |= FEC_RCNTRL_MII_MODE;
+
+ if (priv->duplex == DUPLEX_FULL)
+ tcntrl = FEC_TCNTRL_FDEN; /* FD enable */
+ else {
+ rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */
+ tcntrl = 0;
+ }
+ out_be32(&fec->r_cntrl, rcntrl);
+ out_be32(&fec->x_cntrl, tcntrl);
+
+ /* Clear any outstanding interrupt. */
+ out_be32(&fec->ievent, 0xffffffff);
+
+ /* Enable interrupts we wish to service. */
+ out_be32(&fec->imask, FEC_IMASK_ENABLE);
+
+ /* And last, enable the transmit and receive processing. */
+ out_be32(&fec->ecntrl, FEC_ECNTRL_ETHER_EN);
+ out_be32(&fec->r_des_active, 0x01000000);
+}
+
+/**
+ * mpc52xx_fec_stop
+ * @dev: network device
+ *
+ * stop all activity on fec and empty dma buffers
+ */
+static void mpc52xx_fec_stop(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+ unsigned long timeout;
+
+ /* disable all interrupts */
+ out_be32(&fec->imask, 0);
+
+ /* Disable the rx task. */
+ bcom_disable(priv->rx_dmatsk);
+
+ /* Wait for tx queue to drain, but only if we're in process context */
+ if (!in_interrupt()) {
+ timeout = jiffies + msecs_to_jiffies(2000);
+ while (time_before(jiffies, timeout) &&
+ !bcom_queue_empty(priv->tx_dmatsk))
+ msleep(100);
+
+ if (time_after_eq(jiffies, timeout))
+ dev_err(&dev->dev, "queues didn't drain\n");
+#if 1
+ if (time_after_eq(jiffies, timeout)) {
+ dev_err(&dev->dev, " tx: index: %i, outdex: %i\n",
+ priv->tx_dmatsk->index,
+ priv->tx_dmatsk->outdex);
+ dev_err(&dev->dev, " rx: index: %i, outdex: %i\n",
+ priv->rx_dmatsk->index,
+ priv->rx_dmatsk->outdex);
+ }
+#endif
+ }
+
+ bcom_disable(priv->tx_dmatsk);
+
+ /* Stop FEC */
+ out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN);
+
+ return;
+}
+
+/* reset fec and bestcomm tasks */
+static void mpc52xx_fec_reset(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ struct mpc52xx_fec __iomem *fec = priv->fec;
+
+ mpc52xx_fec_stop(dev);
+
+ out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status));
+ out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_RESET_FIFO);
+
+ mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk);
+
+ mpc52xx_fec_hw_init(dev);
+
+ phy_stop(priv->phydev);
+ phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
+ phy_start(priv->phydev);
+
+ bcom_fec_rx_reset(priv->rx_dmatsk);
+ bcom_fec_tx_reset(priv->tx_dmatsk);
+
+ mpc52xx_fec_alloc_rx_buffers(dev, priv->rx_dmatsk);
+
+ bcom_enable(priv->rx_dmatsk);
+ bcom_enable(priv->tx_dmatsk);
+
+ mpc52xx_fec_start(dev);
+}
+
+
+/* ethtool interface */
+static void mpc52xx_fec_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRIVER_NAME);
+}
+
+static int mpc52xx_fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int mpc52xx_fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+static u32 mpc52xx_fec_get_msglevel(struct net_device *dev)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ return priv->msg_enable;
+}
+
+static void mpc52xx_fec_set_msglevel(struct net_device *dev, u32 level)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+ priv->msg_enable = level;
+}
+
+static const struct ethtool_ops mpc52xx_fec_ethtool_ops = {
+ .get_drvinfo = mpc52xx_fec_get_drvinfo,
+ .get_settings = mpc52xx_fec_get_settings,
+ .set_settings = mpc52xx_fec_set_settings,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = mpc52xx_fec_get_msglevel,
+ .set_msglevel = mpc52xx_fec_set_msglevel,
+};
+
+
+static int mpc52xx_fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct mpc52xx_fec_priv *priv = netdev_priv(dev);
+
+ return mpc52xx_fec_phy_mii_ioctl(priv, if_mii(rq), cmd);
+}
+
+/* ======================================================================== */
+/* OF Driver */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
+{
+ int rv;
+ struct net_device *ndev;
+ struct mpc52xx_fec_priv *priv = NULL;
+ struct resource mem;
+ const phandle *ph;
+
+ phys_addr_t rx_fifo;
+ phys_addr_t tx_fifo;
+
+ /* Get the ether ndev & it's private zone */
+ ndev = alloc_etherdev(sizeof(struct mpc52xx_fec_priv));
+ if (!ndev)
+ return -ENOMEM;
+
+ priv = netdev_priv(ndev);
+
+ /* Reserve FEC control zone */
+ rv = of_address_to_resource(op->node, 0, &mem);
+ if (rv) {
+ printk(KERN_ERR DRIVER_NAME ": "
+ "Error while parsing device node resource\n" );
+ return rv;
+ }
+ if ((mem.end - mem.start + 1) < sizeof(struct mpc52xx_fec)) {
+ printk(KERN_ERR DRIVER_NAME
+ " - invalid resource size (%lx < %x), check mpc52xx_devices.c\n",
+ (unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec));
+ return -EINVAL;
+ }
+
+ if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec), DRIVER_NAME))
+ return -EBUSY;
+
+ /* Init ether ndev with what we have */
+ ndev->open = mpc52xx_fec_open;
+ ndev->stop = mpc52xx_fec_close;
+ ndev->hard_start_xmit = mpc52xx_fec_hard_start_xmit;
+ ndev->do_ioctl = mpc52xx_fec_ioctl;
+ ndev->ethtool_ops = &mpc52xx_fec_ethtool_ops;
+ ndev->get_stats = mpc52xx_fec_get_stats;
+ ndev->set_mac_address = mpc52xx_fec_set_mac_address;
+ ndev->set_multicast_list = mpc52xx_fec_set_multicast_list;
+ ndev->tx_timeout = mpc52xx_fec_tx_timeout;
+ ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT;
+ ndev->base_addr = mem.start;
+
+ priv->t_irq = priv->r_irq = ndev->irq = NO_IRQ; /* IRQ are free for now */
+
+ spin_lock_init(&priv->lock);
+
+ /* ioremap the zones */
+ priv->fec = ioremap(mem.start, sizeof(struct mpc52xx_fec));
+
+ if (!priv->fec) {
+ rv = -ENOMEM;
+ goto probe_error;
+ }
+
+ /* Bestcomm init */
+ rx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, rfifo_data);
+ tx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, tfifo_data);
+
+ priv->rx_dmatsk = bcom_fec_rx_init(FEC_RX_NUM_BD, rx_fifo, FEC_RX_BUFFER_SIZE);
+ priv->tx_dmatsk = bcom_fec_tx_init(FEC_TX_NUM_BD, tx_fifo);
+
+ if (!priv->rx_dmatsk || !priv->tx_dmatsk) {
+ printk(KERN_ERR DRIVER_NAME ": Can not init SDMA tasks\n" );
+ rv = -ENOMEM;
+ goto probe_error;
+ }
+
+ /* Get the IRQ we need one by one */
+ /* Control */
+ ndev->irq = irq_of_parse_and_map(op->node, 0);
+
+ /* RX */
+ priv->r_irq = bcom_get_task_irq(priv->rx_dmatsk);
+
+ /* TX */
+ priv->t_irq = bcom_get_task_irq(priv->tx_dmatsk);
+
+ /* MAC address init */
+ if (!is_zero_ether_addr(mpc52xx_fec_mac_addr))
+ memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6);
+ else
+ mpc52xx_fec_get_paddr(ndev, ndev->dev_addr);
+
+ priv->msg_enable = netif_msg_init(debug, MPC52xx_MESSAGES_DEFAULT);
+ priv->duplex = DUPLEX_FULL;
+
+ /* is the phy present in device tree? */
+ ph = of_get_property(op->node, "phy-handle", NULL);
+ if (ph) {
+ const unsigned int *prop;
+ struct device_node *phy_dn;
+ priv->has_phy = 1;
+
+ phy_dn = of_find_node_by_phandle(*ph);
+ prop = of_get_property(phy_dn, "reg", NULL);
+ priv->phy_addr = *prop;
+
+ of_node_put(phy_dn);
+
+ /* Phy speed */
+ priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
+ } else {
+ dev_info(&ndev->dev, "can't find \"phy-handle\" in device"
+ " tree, using 7-wire mode\n");
+ }
+
+ /* Hardware init */
+ mpc52xx_fec_hw_init(ndev);
+
+ mpc52xx_fec_reset_stats(ndev);
+
+ /* Register the new network device */
+ rv = register_netdev(ndev);
+ if (rv < 0)
+ goto probe_error;
+
+ /* We're done ! */
+ dev_set_drvdata(&op->dev, ndev);
+
+ return 0;
+
+
+ /* Error handling - free everything that might be allocated */
+probe_error:
+
+ irq_dispose_mapping(ndev->irq);
+
+ if (priv->rx_dmatsk)
+ bcom_fec_rx_release(priv->rx_dmatsk);
+ if (priv->tx_dmatsk)
+ bcom_fec_tx_release(priv->tx_dmatsk);
+
+ if (priv->fec)
+ iounmap(priv->fec);
+
+ release_mem_region(mem.start, sizeof(struct mpc52xx_fec));
+
+ free_netdev(ndev);
+
+ return rv;
+}
+
+static int
+mpc52xx_fec_remove(struct of_device *op)
+{
+ struct net_device *ndev;
+ struct mpc52xx_fec_priv *priv;
+
+ ndev = dev_get_drvdata(&op->dev);
+ priv = netdev_priv(ndev);
+
+ unregister_netdev(ndev);
+
+ irq_dispose_mapping(ndev->irq);
+
+ bcom_fec_rx_release(priv->rx_dmatsk);
+ bcom_fec_tx_release(priv->tx_dmatsk);
+
+ iounmap(priv->fec);
+
+ release_mem_region(ndev->base_addr, sizeof(struct mpc52xx_fec));
+
+ free_netdev(ndev);
+
+ dev_set_drvdata(&op->dev, NULL);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mpc52xx_fec_of_suspend(struct of_device *op, pm_message_t state)
+{
+ struct net_device *dev = dev_get_drvdata(&op->dev);
+
+ if (netif_running(dev))
+ mpc52xx_fec_close(dev);
+
+ return 0;
+}
+
+static int mpc52xx_fec_of_resume(struct of_device *op)
+{
+ struct net_device *dev = dev_get_drvdata(&op->dev);
+
+ mpc52xx_fec_hw_init(dev);
+ mpc52xx_fec_reset_stats(dev);
+
+ if (netif_running(dev))
+ mpc52xx_fec_open(dev);
+
+ return 0;
+}
+#endif
+
+static struct of_device_id mpc52xx_fec_match[] = {
+ {
+ .type = "network",
+ .compatible = "mpc5200-fec",
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, mpc52xx_fec_match);
+
+static struct of_platform_driver mpc52xx_fec_driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .match_table = mpc52xx_fec_match,
+ .probe = mpc52xx_fec_probe,
+ .remove = mpc52xx_fec_remove,
+#ifdef CONFIG_PM
+ .suspend = mpc52xx_fec_of_suspend,
+ .resume = mpc52xx_fec_of_resume,
+#endif
+};
+
+
+/* ======================================================================== */
+/* Module */
+/* ======================================================================== */
+
+static int __init
+mpc52xx_fec_init(void)
+{
+#ifdef CONFIG_FEC_MPC52xx_MDIO
+ int ret;
+ ret = of_register_platform_driver(&mpc52xx_fec_mdio_driver);
+ if (ret) {
+ printk(KERN_ERR DRIVER_NAME ": failed to register mdio driver\n");
+ return ret;
+ }
+#endif
+ return of_register_platform_driver(&mpc52xx_fec_driver);
+}
+
+static void __exit
+mpc52xx_fec_exit(void)
+{
+ of_unregister_platform_driver(&mpc52xx_fec_driver);
+#ifdef CONFIG_FEC_MPC52xx_MDIO
+ of_unregister_platform_driver(&mpc52xx_fec_mdio_driver);
+#endif
+}
+
+
+module_init(mpc52xx_fec_init);
+module_exit(mpc52xx_fec_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dale Farnsworth");
+MODULE_DESCRIPTION("Ethernet driver for the Freescale MPC52xx FEC");
diff --git a/drivers/net/fec_mpc52xx.h b/drivers/net/fec_mpc52xx.h
new file mode 100644
index 00000000000..8b1f75397b9
--- /dev/null
+++ b/drivers/net/fec_mpc52xx.h
@@ -0,0 +1,313 @@
+/*
+ * drivers/drivers/net/fec_mpc52xx/fec.h
+ *
+ * Driver for the MPC5200 Fast Ethernet Controller
+ *
+ * Author: Dale Farnsworth <dfarnsworth@mvista.com>
+ *
+ * 2003-2004 (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.
+ */
+
+#ifndef __DRIVERS_NET_MPC52XX_FEC_H__
+#define __DRIVERS_NET_MPC52XX_FEC_H__
+
+#include <linux/phy.h>
+
+/* Tunable constant */
+/* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */
+#define FEC_RX_BUFFER_SIZE 1522 /* max receive packet size */
+#define FEC_RX_NUM_BD 256
+#define FEC_TX_NUM_BD 64
+
+#define FEC_RESET_DELAY 50 /* uS */
+
+#define FEC_WATCHDOG_TIMEOUT ((400*HZ)/1000)
+
+struct mpc52xx_fec_priv {
+ int duplex;
+ int r_irq;
+ int t_irq;
+ struct mpc52xx_fec __iomem *fec;
+ struct bcom_task *rx_dmatsk;
+ struct bcom_task *tx_dmatsk;
+ spinlock_t lock;
+ int msg_enable;
+
+ int has_phy;
+ unsigned int phy_speed;
+ unsigned int phy_addr;
+ struct phy_device *phydev;
+ enum phy_state link;
+ int speed;
+};
+
+
+/* ======================================================================== */
+/* Hardware register sets & bits */
+/* ======================================================================== */
+
+struct mpc52xx_fec {
+ u32 fec_id; /* FEC + 0x000 */
+ u32 ievent; /* FEC + 0x004 */
+ u32 imask; /* FEC + 0x008 */
+
+ u32 reserved0[1]; /* FEC + 0x00C */
+ u32 r_des_active; /* FEC + 0x010 */
+ u32 x_des_active; /* FEC + 0x014 */
+ u32 r_des_active_cl; /* FEC + 0x018 */
+ u32 x_des_active_cl; /* FEC + 0x01C */
+ u32 ivent_set; /* FEC + 0x020 */
+ u32 ecntrl; /* FEC + 0x024 */
+
+ u32 reserved1[6]; /* FEC + 0x028-03C */
+ u32 mii_data; /* FEC + 0x040 */
+ u32 mii_speed; /* FEC + 0x044 */
+ u32 mii_status; /* FEC + 0x048 */
+
+ u32 reserved2[5]; /* FEC + 0x04C-05C */
+ u32 mib_data; /* FEC + 0x060 */
+ u32 mib_control; /* FEC + 0x064 */
+
+ u32 reserved3[6]; /* FEC + 0x068-7C */
+ u32 r_activate; /* FEC + 0x080 */
+ u32 r_cntrl; /* FEC + 0x084 */
+ u32 r_hash; /* FEC + 0x088 */
+ u32 r_data; /* FEC + 0x08C */
+ u32 ar_done; /* FEC + 0x090 */
+ u32 r_test; /* FEC + 0x094 */
+ u32 r_mib; /* FEC + 0x098 */
+ u32 r_da_low; /* FEC + 0x09C */
+ u32 r_da_high; /* FEC + 0x0A0 */
+
+ u32 reserved4[7]; /* FEC + 0x0A4-0BC */
+ u32 x_activate; /* FEC + 0x0C0 */
+ u32 x_cntrl; /* FEC + 0x0C4 */
+ u32 backoff; /* FEC + 0x0C8 */
+ u32 x_data; /* FEC + 0x0CC */
+ u32 x_status; /* FEC + 0x0D0 */
+ u32 x_mib; /* FEC + 0x0D4 */
+ u32 x_test; /* FEC + 0x0D8 */
+ u32 fdxfc_da1; /* FEC + 0x0DC */
+ u32 fdxfc_da2; /* FEC + 0x0E0 */
+ u32 paddr1; /* FEC + 0x0E4 */
+ u32 paddr2; /* FEC + 0x0E8 */
+ u32 op_pause; /* FEC + 0x0EC */
+
+ u32 reserved5[4]; /* FEC + 0x0F0-0FC */
+ u32 instr_reg; /* FEC + 0x100 */
+ u32 context_reg; /* FEC + 0x104 */
+ u32 test_cntrl; /* FEC + 0x108 */
+ u32 acc_reg; /* FEC + 0x10C */
+ u32 ones; /* FEC + 0x110 */
+ u32 zeros; /* FEC + 0x114 */
+ u32 iaddr1; /* FEC + 0x118 */
+ u32 iaddr2; /* FEC + 0x11C */
+ u32 gaddr1; /* FEC + 0x120 */
+ u32 gaddr2; /* FEC + 0x124 */
+ u32 random; /* FEC + 0x128 */
+ u32 rand1; /* FEC + 0x12C */
+ u32 tmp; /* FEC + 0x130 */
+
+ u32 reserved6[3]; /* FEC + 0x134-13C */
+ u32 fifo_id; /* FEC + 0x140 */
+ u32 x_wmrk; /* FEC + 0x144 */
+ u32 fcntrl; /* FEC + 0x148 */
+ u32 r_bound; /* FEC + 0x14C */
+ u32 r_fstart; /* FEC + 0x150 */
+ u32 r_count; /* FEC + 0x154 */
+ u32 r_lag; /* FEC + 0x158 */
+ u32 r_read; /* FEC + 0x15C */
+ u32 r_write; /* FEC + 0x160 */
+ u32 x_count; /* FEC + 0x164 */
+ u32 x_lag; /* FEC + 0x168 */
+ u32 x_retry; /* FEC + 0x16C */
+ u32 x_write; /* FEC + 0x170 */
+ u32 x_read; /* FEC + 0x174 */
+
+ u32 reserved7[2]; /* FEC + 0x178-17C */
+ u32 fm_cntrl; /* FEC + 0x180 */
+ u32 rfifo_data; /* FEC + 0x184 */
+ u32 rfifo_status; /* FEC + 0x188 */
+ u32 rfifo_cntrl; /* FEC + 0x18C */
+ u32 rfifo_lrf_ptr; /* FEC + 0x190 */
+ u32 rfifo_lwf_ptr; /* FEC + 0x194 */
+ u32 rfifo_alarm; /* FEC + 0x198 */
+ u32 rfifo_rdptr; /* FEC + 0x19C */
+ u32 rfifo_wrptr; /* FEC + 0x1A0 */
+ u32 tfifo_data; /* FEC + 0x1A4 */
+ u32 tfifo_status; /* FEC + 0x1A8 */
+ u32 tfifo_cntrl; /* FEC + 0x1AC */
+ u32 tfifo_lrf_ptr; /* FEC + 0x1B0 */
+ u32 tfifo_lwf_ptr; /* FEC + 0x1B4 */
+ u32 tfifo_alarm; /* FEC + 0x1B8 */
+ u32 tfifo_rdptr; /* FEC + 0x1BC */
+ u32 tfifo_wrptr; /* FEC + 0x1C0 */
+
+ u32 reset_cntrl; /* FEC + 0x1C4 */
+ u32 xmit_fsm; /* FEC + 0x1C8 */
+
+ u32 reserved8[3]; /* FEC + 0x1CC-1D4 */
+ u32 rdes_data0; /* FEC + 0x1D8 */
+ u32 rdes_data1; /* FEC + 0x1DC */
+ u32 r_length; /* FEC + 0x1E0 */
+ u32 x_length; /* FEC + 0x1E4 */
+ u32 x_addr; /* FEC + 0x1E8 */
+ u32 cdes_data; /* FEC + 0x1EC */
+ u32 status; /* FEC + 0x1F0 */
+ u32 dma_control; /* FEC + 0x1F4 */
+ u32 des_cmnd; /* FEC + 0x1F8 */
+ u32 data; /* FEC + 0x1FC */
+
+ u32 rmon_t_drop; /* FEC + 0x200 */
+ u32 rmon_t_packets; /* FEC + 0x204 */
+ u32 rmon_t_bc_pkt; /* FEC + 0x208 */
+ u32 rmon_t_mc_pkt; /* FEC + 0x20C */
+ u32 rmon_t_crc_align; /* FEC + 0x210 */
+ u32 rmon_t_undersize; /* FEC + 0x214 */
+ u32 rmon_t_oversize; /* FEC + 0x218 */
+ u32 rmon_t_frag; /* FEC + 0x21C */
+ u32 rmon_t_jab; /* FEC + 0x220 */
+ u32 rmon_t_col; /* FEC + 0x224 */
+ u32 rmon_t_p64; /* FEC + 0x228 */
+ u32 rmon_t_p65to127; /* FEC + 0x22C */
+ u32 rmon_t_p128to255; /* FEC + 0x230 */
+ u32 rmon_t_p256to511; /* FEC + 0x234 */
+ u32 rmon_t_p512to1023; /* FEC + 0x238 */
+ u32 rmon_t_p1024to2047; /* FEC + 0x23C */
+ u32 rmon_t_p_gte2048; /* FEC + 0x240 */
+ u32 rmon_t_octets; /* FEC + 0x244 */
+ u32 ieee_t_drop; /* FEC + 0x248 */
+ u32 ieee_t_frame_ok; /* FEC + 0x24C */
+ u32 ieee_t_1col; /* FEC + 0x250 */
+ u32 ieee_t_mcol; /* FEC + 0x254 */
+ u32 ieee_t_def; /* FEC + 0x258 */
+ u32 ieee_t_lcol; /* FEC + 0x25C */
+ u32 ieee_t_excol; /* FEC + 0x260 */
+ u32 ieee_t_macerr; /* FEC + 0x264 */
+ u32 ieee_t_cserr; /* FEC + 0x268 */
+ u32 ieee_t_sqe; /* FEC + 0x26C */
+ u32 t_fdxfc; /* FEC + 0x270 */
+ u32 ieee_t_octets_ok; /* FEC + 0x274 */
+
+ u32 reserved9[2]; /* FEC + 0x278-27C */
+ u32 rmon_r_drop; /* FEC + 0x280 */
+ u32 rmon_r_packets; /* FEC + 0x284 */
+ u32 rmon_r_bc_pkt; /* FEC + 0x288 */
+ u32 rmon_r_mc_pkt; /* FEC + 0x28C */
+ u32 rmon_r_crc_align; /* FEC + 0x290 */
+ u32 rmon_r_undersize; /* FEC + 0x294 */
+ u32 rmon_r_oversize; /* FEC + 0x298 */
+ u32 rmon_r_frag; /* FEC + 0x29C */
+ u32 rmon_r_jab; /* FEC + 0x2A0 */
+
+ u32 rmon_r_resvd_0; /* FEC + 0x2A4 */
+
+ u32 rmon_r_p64; /* FEC + 0x2A8 */
+ u32 rmon_r_p65to127; /* FEC + 0x2AC */
+ u32 rmon_r_p128to255; /* FEC + 0x2B0 */
+ u32 rmon_r_p256to511; /* FEC + 0x2B4 */
+ u32 rmon_r_p512to1023; /* FEC + 0x2B8 */
+ u32 rmon_r_p1024to2047; /* FEC + 0x2BC */
+ u32 rmon_r_p_gte2048; /* FEC + 0x2C0 */
+ u32 rmon_r_octets; /* FEC + 0x2C4 */
+ u32 ieee_r_drop; /* FEC + 0x2C8 */
+ u32 ieee_r_frame_ok; /* FEC + 0x2CC */
+ u32 ieee_r_crc; /* FEC + 0x2D0 */
+ u32 ieee_r_align; /* FEC + 0x2D4 */
+ u32 r_macerr; /* FEC + 0x2D8 */
+ u32 r_fdxfc; /* FEC + 0x2DC */
+ u32 ieee_r_octets_ok; /* FEC + 0x2E0 */
+
+ u32 reserved10[7]; /* FEC + 0x2E4-2FC */
+
+ u32 reserved11[64]; /* FEC + 0x300-3FF */
+};
+
+#define FEC_MIB_DISABLE 0x80000000
+
+#define FEC_IEVENT_HBERR 0x80000000
+#define FEC_IEVENT_BABR 0x40000000
+#define FEC_IEVENT_BABT 0x20000000
+#define FEC_IEVENT_GRA 0x10000000
+#define FEC_IEVENT_TFINT 0x08000000
+#define FEC_IEVENT_MII 0x00800000
+#define FEC_IEVENT_LATE_COL 0x00200000
+#define FEC_IEVENT_COL_RETRY_LIM 0x00100000
+#define FEC_IEVENT_XFIFO_UN 0x00080000
+#define FEC_IEVENT_XFIFO_ERROR 0x00040000
+#define FEC_IEVENT_RFIFO_ERROR 0x00020000
+
+#define FEC_IMASK_HBERR 0x80000000
+#define FEC_IMASK_BABR 0x40000000
+#define FEC_IMASK_BABT 0x20000000
+#define FEC_IMASK_GRA 0x10000000
+#define FEC_IMASK_MII 0x00800000
+#define FEC_IMASK_LATE_COL 0x00200000
+#define FEC_IMASK_COL_RETRY_LIM 0x00100000
+#define FEC_IMASK_XFIFO_UN 0x00080000
+#define FEC_IMASK_XFIFO_ERROR 0x00040000
+#define FEC_IMASK_RFIFO_ERROR 0x00020000
+
+/* all but MII, which is enabled separately */
+#define FEC_IMASK_ENABLE (FEC_IMASK_HBERR | FEC_IMASK_BABR | \
+ FEC_IMASK_BABT | FEC_IMASK_GRA | FEC_IMASK_LATE_COL | \
+ FEC_IMASK_COL_RETRY_LIM | FEC_IMASK_XFIFO_UN | \
+ FEC_IMASK_XFIFO_ERROR | FEC_IMASK_RFIFO_ERROR)
+
+#define FEC_RCNTRL_MAX_FL_SHIFT 16
+#define FEC_RCNTRL_LOOP 0x01
+#define FEC_RCNTRL_DRT 0x02
+#define FEC_RCNTRL_MII_MODE 0x04
+#define FEC_RCNTRL_PROM 0x08
+#define FEC_RCNTRL_BC_REJ 0x10
+#define FEC_RCNTRL_FCE 0x20
+
+#define FEC_TCNTRL_GTS 0x00000001
+#define FEC_TCNTRL_HBC 0x00000002
+#define FEC_TCNTRL_FDEN 0x00000004
+#define FEC_TCNTRL_TFC_PAUSE 0x00000008
+#define FEC_TCNTRL_RFC_PAUSE 0x00000010
+
+#define FEC_ECNTRL_RESET 0x00000001
+#define FEC_ECNTRL_ETHER_EN 0x00000002
+
+#define FEC_MII_DATA_ST 0x40000000 /* Start frame */
+#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform read */
+#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform write */
+#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address mask */
+#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register mask */
+#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */
+#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data mask */
+
+#define FEC_MII_READ_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA)
+#define FEC_MII_WRITE_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | FEC_MII_DATA_TA)
+
+#define FEC_MII_DATA_RA_SHIFT 0x12 /* MII reg addr bits */
+#define FEC_MII_DATA_PA_SHIFT 0x17 /* MII PHY addr bits */
+
+#define FEC_PADDR2_TYPE 0x8808
+
+#define FEC_OP_PAUSE_OPCODE 0x00010000
+
+#define FEC_FIFO_WMRK_256B 0x3
+
+#define FEC_FIFO_STATUS_ERR 0x00400000
+#define FEC_FIFO_STATUS_UF 0x00200000
+#define FEC_FIFO_STATUS_OF 0x00100000
+
+#define FEC_FIFO_CNTRL_FRAME 0x08000000
+#define FEC_FIFO_CNTRL_LTG_7 0x07000000
+
+#define FEC_RESET_CNTRL_RESET_FIFO 0x02000000
+#define FEC_RESET_CNTRL_ENABLE_IS_RESET 0x01000000
+
+#define FEC_XMIT_FSM_APPEND_CRC 0x02000000
+#define FEC_XMIT_FSM_ENABLE_CRC 0x01000000
+
+
+extern struct of_platform_driver mpc52xx_fec_mdio_driver;
+
+#endif /* __DRIVERS_NET_MPC52XX_FEC_H__ */
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c
new file mode 100644
index 00000000000..ba6e8b218e0
--- /dev/null
+++ b/drivers/net/fec_mpc52xx_phy.c
@@ -0,0 +1,198 @@
+/*
+ * Driver for the MPC5200 Fast Ethernet Controller - MDIO bus driver
+ *
+ * Copyright (C) 2007 Domen Puncer, Telargo, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/of_platform.h>
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+#include "fec_mpc52xx.h"
+
+struct mpc52xx_fec_mdio_priv {
+ struct mpc52xx_fec __iomem *regs;
+};
+
+static int mpc52xx_fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+ struct mpc52xx_fec_mdio_priv *priv = bus->priv;
+ struct mpc52xx_fec __iomem *fec;
+ int tries = 100;
+ u32 request = FEC_MII_READ_FRAME;
+
+ fec = priv->regs;
+ out_be32(&fec->ievent, FEC_IEVENT_MII);
+
+ request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
+ request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
+
+ out_be32(&priv->regs->mii_data, request);
+
+ /* wait for it to finish, this takes about 23 us on lite5200b */
+ while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
+ udelay(5);
+
+ if (tries == 0)
+ return -ETIMEDOUT;
+
+ return in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK;
+}
+
+static int mpc52xx_fec_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
+{
+ struct mpc52xx_fec_mdio_priv *priv = bus->priv;
+ struct mpc52xx_fec __iomem *fec;
+ u32 value = data;
+ int tries = 100;
+
+ fec = priv->regs;
+ out_be32(&fec->ievent, FEC_IEVENT_MII);
+
+ value |= FEC_MII_WRITE_FRAME;
+ value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
+ value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
+
+ out_be32(&priv->regs->mii_data, value);
+
+ /* wait for request to finish */
+ while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
+ udelay(5);
+
+ if (tries == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_id *match)
+{
+ struct device *dev = &of->dev;
+ struct device_node *np = of->node;
+ struct device_node *child = NULL;
+ struct mii_bus *bus;
+ struct mpc52xx_fec_mdio_priv *priv;
+ struct resource res = {};
+ int err;
+ int i;
+
+ bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+ if (bus == NULL)
+ return -ENOMEM;
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (priv == NULL) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ bus->name = "mpc52xx MII bus";
+ bus->read = mpc52xx_fec_mdio_read;
+ bus->write = mpc52xx_fec_mdio_write;
+
+ /* setup irqs */
+ bus->irq = kmalloc(sizeof(bus->irq[0]) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (bus->irq == NULL) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+ for (i=0; i<PHY_MAX_ADDR; i++)
+ bus->irq[i] = PHY_POLL;
+
+ while ((child = of_get_next_child(np, child)) != NULL) {
+ int irq = irq_of_parse_and_map(child, 0);
+ if (irq != NO_IRQ) {
+ const u32 *id = of_get_property(child, "reg", NULL);
+ bus->irq[*id] = irq;
+ }
+ }
+
+ /* setup registers */
+ err = of_address_to_resource(np, 0, &res);
+ if (err)
+ goto out_free;
+ priv->regs = ioremap(res.start, res.end - res.start + 1);
+ if (priv->regs == NULL) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+
+ bus->id = res.start;
+ bus->priv = priv;
+
+ bus->dev = dev;
+ dev_set_drvdata(dev, bus);
+
+ /* set MII speed */
+ out_be32(&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1);
+
+ /* enable MII interrupt */
+ out_be32(&priv->regs->imask, in_be32(&priv->regs->imask) | FEC_IMASK_MII);
+
+ err = mdiobus_register(bus);
+ if (err)
+ goto out_unmap;
+
+ return 0;
+
+ out_unmap:
+ iounmap(priv->regs);
+ out_free:
+ for (i=0; i<PHY_MAX_ADDR; i++)
+ if (bus->irq[i] != PHY_POLL)
+ irq_dispose_mapping(bus->irq[i]);
+ kfree(bus->irq);
+ kfree(priv);
+ kfree(bus);
+
+ return err;
+}
+
+static int mpc52xx_fec_mdio_remove(struct of_device *of)
+{
+ struct device *dev = &of->dev;
+ struct mii_bus *bus = dev_get_drvdata(dev);
+ struct mpc52xx_fec_mdio_priv *priv = bus->priv;
+ int i;
+
+ mdiobus_unregister(bus);
+ dev_set_drvdata(dev, NULL);
+
+ iounmap(priv->regs);
+ for (i=0; i<PHY_MAX_ADDR; i++)
+ if (bus->irq[i])
+ irq_dispose_mapping(bus->irq[i]);
+ kfree(priv);
+ kfree(bus->irq);
+ kfree(bus);
+
+ return 0;
+}
+
+
+static struct of_device_id mpc52xx_fec_mdio_match[] = {
+ {
+ .type = "mdio",
+ .compatible = "mpc5200b-fec-phy",
+ },
+ {},
+};
+
+struct of_platform_driver mpc52xx_fec_mdio_driver = {
+ .name = "mpc5200b-fec-phy",
+ .probe = mpc52xx_fec_mdio_probe,
+ .remove = mpc52xx_fec_mdio_remove,
+ .match_table = mpc52xx_fec_mdio_match,
+};
+
+/* let fec driver call it, since this has to be registered before it */
+EXPORT_SYMBOL_GPL(mpc52xx_fec_mdio_driver);
+
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 1938d6dfc86..92ce2e38f0d 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -128,7 +128,7 @@
#else
#define DRIVERNAPI
#endif
-#define FORCEDETH_VERSION "0.60"
+#define FORCEDETH_VERSION "0.61"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -159,6 +159,8 @@
#define dprintk(x...) do { } while (0)
#endif
+#define TX_WORK_PER_LOOP 64
+#define RX_WORK_PER_LOOP 64
/*
* Hardware access:
@@ -745,9 +747,11 @@ struct nv_skb_map {
struct fe_priv {
spinlock_t lock;
+ struct net_device *dev;
+ struct napi_struct napi;
+
/* General data:
* Locking: spin_lock(&np->lock); */
- struct net_device_stats stats;
struct nv_ethtool_stats estats;
int in_shutdown;
u32 linkspeed;
@@ -988,7 +992,7 @@ static void nv_enable_irq(struct net_device *dev)
if (np->msi_flags & NV_MSI_X_ENABLED)
enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
else
- enable_irq(dev->irq);
+ enable_irq(np->pci_dev->irq);
} else {
enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
@@ -1004,7 +1008,7 @@ static void nv_disable_irq(struct net_device *dev)
if (np->msi_flags & NV_MSI_X_ENABLED)
disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
else
- disable_irq(dev->irq);
+ disable_irq(np->pci_dev->irq);
} else {
disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
@@ -1500,15 +1504,16 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)
nv_get_hw_stats(dev);
/* copy to net_device stats */
- np->stats.tx_bytes = np->estats.tx_bytes;
- np->stats.tx_fifo_errors = np->estats.tx_fifo_errors;
- np->stats.tx_carrier_errors = np->estats.tx_carrier_errors;
- np->stats.rx_crc_errors = np->estats.rx_crc_errors;
- np->stats.rx_over_errors = np->estats.rx_over_errors;
- np->stats.rx_errors = np->estats.rx_errors_total;
- np->stats.tx_errors = np->estats.tx_errors_total;
- }
- return &np->stats;
+ dev->stats.tx_bytes = np->estats.tx_bytes;
+ dev->stats.tx_fifo_errors = np->estats.tx_fifo_errors;
+ dev->stats.tx_carrier_errors = np->estats.tx_carrier_errors;
+ dev->stats.rx_crc_errors = np->estats.rx_crc_errors;
+ dev->stats.rx_over_errors = np->estats.rx_over_errors;
+ dev->stats.rx_errors = np->estats.rx_errors_total;
+ dev->stats.tx_errors = np->estats.tx_errors_total;
+ }
+
+ return &dev->stats;
}
/*
@@ -1586,9 +1591,10 @@ static int nv_alloc_rx_optimized(struct net_device *dev)
static void nv_do_rx_refill(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
+ struct fe_priv *np = netdev_priv(dev);
/* Just reschedule NAPI rx processing */
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &np->napi);
}
#else
static void nv_do_rx_refill(unsigned long data)
@@ -1601,7 +1607,7 @@ static void nv_do_rx_refill(unsigned long data)
if (np->msi_flags & NV_MSI_X_ENABLED)
disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
else
- disable_irq(dev->irq);
+ disable_irq(np->pci_dev->irq);
} else {
disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
}
@@ -1619,7 +1625,7 @@ static void nv_do_rx_refill(unsigned long data)
if (np->msi_flags & NV_MSI_X_ENABLED)
enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
else
- enable_irq(dev->irq);
+ enable_irq(np->pci_dev->irq);
} else {
enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
}
@@ -1727,7 +1733,7 @@ static void nv_drain_tx(struct net_device *dev)
np->tx_ring.ex[i].buflow = 0;
}
if (nv_release_txskb(dev, &np->tx_skb[i]))
- np->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
}
}
@@ -2043,13 +2049,13 @@ static void nv_tx_done(struct net_device *dev)
if (flags & NV_TX_LASTPACKET) {
if (flags & NV_TX_ERROR) {
if (flags & NV_TX_UNDERFLOW)
- np->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (flags & NV_TX_CARRIERLOST)
- np->stats.tx_carrier_errors++;
- np->stats.tx_errors++;
+ dev->stats.tx_carrier_errors++;
+ dev->stats.tx_errors++;
} else {
- np->stats.tx_packets++;
- np->stats.tx_bytes += np->get_tx_ctx->skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += np->get_tx_ctx->skb->len;
}
dev_kfree_skb_any(np->get_tx_ctx->skb);
np->get_tx_ctx->skb = NULL;
@@ -2058,13 +2064,13 @@ static void nv_tx_done(struct net_device *dev)
if (flags & NV_TX2_LASTPACKET) {
if (flags & NV_TX2_ERROR) {
if (flags & NV_TX2_UNDERFLOW)
- np->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (flags & NV_TX2_CARRIERLOST)
- np->stats.tx_carrier_errors++;
- np->stats.tx_errors++;
+ dev->stats.tx_carrier_errors++;
+ dev->stats.tx_errors++;
} else {
- np->stats.tx_packets++;
- np->stats.tx_bytes += np->get_tx_ctx->skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += np->get_tx_ctx->skb->len;
}
dev_kfree_skb_any(np->get_tx_ctx->skb);
np->get_tx_ctx->skb = NULL;
@@ -2101,7 +2107,7 @@ static void nv_tx_done_optimized(struct net_device *dev, int limit)
if (flags & NV_TX2_LASTPACKET) {
if (!(flags & NV_TX2_ERROR))
- np->stats.tx_packets++;
+ dev->stats.tx_packets++;
dev_kfree_skb_any(np->get_tx_ctx->skb);
np->get_tx_ctx->skb = NULL;
}
@@ -2262,13 +2268,13 @@ static int nv_rx_process(struct net_device *dev, int limit)
{
struct fe_priv *np = netdev_priv(dev);
u32 flags;
- u32 rx_processed_cnt = 0;
+ int rx_work = 0;
struct sk_buff *skb;
int len;
while((np->get_rx.orig != np->put_rx.orig) &&
!((flags = le32_to_cpu(np->get_rx.orig->flaglen)) & NV_RX_AVAIL) &&
- (rx_processed_cnt++ < limit)) {
+ (rx_work < limit)) {
dprintk(KERN_DEBUG "%s: nv_rx_process: flags 0x%x.\n",
dev->name, flags);
@@ -2302,7 +2308,7 @@ static int nv_rx_process(struct net_device *dev, int limit)
if (flags & NV_RX_ERROR4) {
len = nv_getlen(dev, skb->data, len);
if (len < 0) {
- np->stats.rx_errors++;
+ dev->stats.rx_errors++;
dev_kfree_skb(skb);
goto next_pkt;
}
@@ -2316,12 +2322,12 @@ static int nv_rx_process(struct net_device *dev, int limit)
/* the rest are hard errors */
else {
if (flags & NV_RX_MISSEDFRAME)
- np->stats.rx_missed_errors++;
+ dev->stats.rx_missed_errors++;
if (flags & NV_RX_CRCERR)
- np->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (flags & NV_RX_OVERFLOW)
- np->stats.rx_over_errors++;
- np->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
dev_kfree_skb(skb);
goto next_pkt;
}
@@ -2337,7 +2343,7 @@ static int nv_rx_process(struct net_device *dev, int limit)
if (flags & NV_RX2_ERROR4) {
len = nv_getlen(dev, skb->data, len);
if (len < 0) {
- np->stats.rx_errors++;
+ dev->stats.rx_errors++;
dev_kfree_skb(skb);
goto next_pkt;
}
@@ -2351,10 +2357,10 @@ static int nv_rx_process(struct net_device *dev, int limit)
/* the rest are hard errors */
else {
if (flags & NV_RX2_CRCERR)
- np->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (flags & NV_RX2_OVERFLOW)
- np->stats.rx_over_errors++;
- np->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
dev_kfree_skb(skb);
goto next_pkt;
}
@@ -2383,16 +2389,18 @@ static int nv_rx_process(struct net_device *dev, int limit)
netif_rx(skb);
#endif
dev->last_rx = jiffies;
- np->stats.rx_packets++;
- np->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
next_pkt:
if (unlikely(np->get_rx.orig++ == np->last_rx.orig))
np->get_rx.orig = np->first_rx.orig;
if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx))
np->get_rx_ctx = np->first_rx_ctx;
+
+ rx_work++;
}
- return rx_processed_cnt;
+ return rx_work;
}
static int nv_rx_process_optimized(struct net_device *dev, int limit)
@@ -2400,13 +2408,13 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
struct fe_priv *np = netdev_priv(dev);
u32 flags;
u32 vlanflags = 0;
- u32 rx_processed_cnt = 0;
+ int rx_work = 0;
struct sk_buff *skb;
int len;
while((np->get_rx.ex != np->put_rx.ex) &&
!((flags = le32_to_cpu(np->get_rx.ex->flaglen)) & NV_RX2_AVAIL) &&
- (rx_processed_cnt++ < limit)) {
+ (rx_work < limit)) {
dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: flags 0x%x.\n",
dev->name, flags);
@@ -2499,8 +2507,8 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
}
dev->last_rx = jiffies;
- np->stats.rx_packets++;
- np->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
} else {
dev_kfree_skb(skb);
}
@@ -2509,9 +2517,11 @@ next_pkt:
np->get_rx.ex = np->first_rx.ex;
if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx))
np->get_rx_ctx = np->first_rx_ctx;
+
+ rx_work++;
}
- return rx_processed_cnt;
+ return rx_work;
}
static void set_bufsize(struct net_device *dev)
@@ -2997,7 +3007,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
#ifdef CONFIG_FORCEDETH_NAPI
if (events & NVREG_IRQ_RX_ALL) {
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &np->napi);
/* Disable furthur receive irq's */
spin_lock(&np->lock);
@@ -3010,7 +3020,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
spin_unlock(&np->lock);
}
#else
- if (nv_rx_process(dev, dev->weight)) {
+ if (nv_rx_process(dev, RX_WORK_PER_LOOP)) {
if (unlikely(nv_alloc_rx(dev))) {
spin_lock(&np->lock);
if (!np->in_shutdown)
@@ -3079,8 +3089,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
return IRQ_RETVAL(i);
}
-#define TX_WORK_PER_LOOP 64
-#define RX_WORK_PER_LOOP 64
/**
* All _optimized functions are used to help increase performance
* (reduce CPU and increase throughput). They use descripter version 3,
@@ -3114,7 +3122,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
#ifdef CONFIG_FORCEDETH_NAPI
if (events & NVREG_IRQ_RX_ALL) {
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &np->napi);
/* Disable furthur receive irq's */
spin_lock(&np->lock);
@@ -3127,7 +3135,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
spin_unlock(&np->lock);
}
#else
- if (nv_rx_process_optimized(dev, dev->weight)) {
+ if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) {
if (unlikely(nv_alloc_rx_optimized(dev))) {
spin_lock(&np->lock);
if (!np->in_shutdown)
@@ -3245,19 +3253,19 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
}
#ifdef CONFIG_FORCEDETH_NAPI
-static int nv_napi_poll(struct net_device *dev, int *budget)
+static int nv_napi_poll(struct napi_struct *napi, int budget)
{
- int pkts, limit = min(*budget, dev->quota);
- struct fe_priv *np = netdev_priv(dev);
+ struct fe_priv *np = container_of(napi, struct fe_priv, napi);
+ struct net_device *dev = np->dev;
u8 __iomem *base = get_hwbase(dev);
unsigned long flags;
- int retcode;
+ int pkts, retcode;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- pkts = nv_rx_process(dev, limit);
+ pkts = nv_rx_process(dev, budget);
retcode = nv_alloc_rx(dev);
} else {
- pkts = nv_rx_process_optimized(dev, limit);
+ pkts = nv_rx_process_optimized(dev, budget);
retcode = nv_alloc_rx_optimized(dev);
}
@@ -3268,13 +3276,12 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
spin_unlock_irqrestore(&np->lock, flags);
}
- if (pkts < limit) {
- /* all done, no more packets present */
- netif_rx_complete(dev);
-
+ if (pkts < budget) {
/* re-enable receive interrupts */
spin_lock_irqsave(&np->lock, flags);
+ __netif_rx_complete(dev, napi);
+
np->irqmask |= NVREG_IRQ_RX_ALL;
if (np->msi_flags & NV_MSI_X_ENABLED)
writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
@@ -3282,13 +3289,8 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
writel(np->irqmask, base + NvRegIrqMask);
spin_unlock_irqrestore(&np->lock, flags);
- return 0;
- } else {
- /* used up our quantum, so reschedule */
- dev->quota -= pkts;
- *budget -= pkts;
- return 1;
}
+ return pkts;
}
#endif
@@ -3296,6 +3298,7 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
static irqreturn_t nv_nic_irq_rx(int foo, void *data)
{
struct net_device *dev = (struct net_device *) data;
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 events;
@@ -3303,7 +3306,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
if (events) {
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &np->napi);
/* disable receive interrupts on the nic */
writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
pci_push(base);
@@ -3329,7 +3332,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
if (!(events & np->irqmask))
break;
- if (nv_rx_process_optimized(dev, dev->weight)) {
+ if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) {
if (unlikely(nv_alloc_rx_optimized(dev))) {
spin_lock_irqsave(&np->lock, flags);
if (!np->in_shutdown)
@@ -3557,10 +3560,12 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
np->msi_flags |= NV_MSI_ENABLED;
+ 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);
pci_disable_msi(np->pci_dev);
np->msi_flags &= ~NV_MSI_ENABLED;
+ dev->irq = np->pci_dev->irq;
goto out_err;
}
@@ -3623,7 +3628,7 @@ static void nv_do_nic_poll(unsigned long data)
if (np->msi_flags & NV_MSI_X_ENABLED)
disable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
else
- disable_irq_lockdep(dev->irq);
+ disable_irq_lockdep(np->pci_dev->irq);
mask = np->irqmask;
} else {
if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {
@@ -3641,6 +3646,8 @@ static void nv_do_nic_poll(unsigned long data)
}
np->nic_poll_irq = 0;
+ /* disable_irq() contains synchronize_irq, thus no irq handler can run now */
+
if (np->recover_error) {
np->recover_error = 0;
printk(KERN_INFO "forcedeth: MAC in recoverable error state\n");
@@ -3677,7 +3684,6 @@ static void nv_do_nic_poll(unsigned long data)
}
}
- /* FIXME: Do we need synchronize_irq(dev->irq) here? */
writel(mask, base + NvRegIrqMask);
pci_push(base);
@@ -3690,7 +3696,7 @@ static void nv_do_nic_poll(unsigned long data)
if (np->msi_flags & NV_MSI_X_ENABLED)
enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
else
- enable_irq_lockdep(dev->irq);
+ enable_irq_lockdep(np->pci_dev->irq);
} else {
if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {
nv_nic_irq_rx(0, dev);
@@ -3728,7 +3734,7 @@ static void nv_do_stats_poll(unsigned long data)
static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct fe_priv *np = netdev_priv(dev);
- strcpy(info->driver, "forcedeth");
+ strcpy(info->driver, DRV_NAME);
strcpy(info->version, FORCEDETH_VERSION);
strcpy(info->bus_info, pci_name(np->pci_dev));
}
@@ -4334,16 +4340,26 @@ static int nv_set_sg(struct net_device *dev, u32 data)
return -EOPNOTSUPP;
}
-static int nv_get_stats_count(struct net_device *dev)
+static int nv_get_sset_count(struct net_device *dev, int sset)
{
struct fe_priv *np = netdev_priv(dev);
- if (np->driver_data & DEV_HAS_STATISTICS_V1)
- return NV_DEV_STATISTICS_V1_COUNT;
- else if (np->driver_data & DEV_HAS_STATISTICS_V2)
- return NV_DEV_STATISTICS_V2_COUNT;
- else
- return 0;
+ switch (sset) {
+ case ETH_SS_TEST:
+ if (np->driver_data & DEV_HAS_TEST_EXTENDED)
+ return NV_TEST_COUNT_EXTENDED;
+ else
+ return NV_TEST_COUNT_BASE;
+ case ETH_SS_STATS:
+ if (np->driver_data & DEV_HAS_STATISTICS_V1)
+ return NV_DEV_STATISTICS_V1_COUNT;
+ else if (np->driver_data & DEV_HAS_STATISTICS_V2)
+ return NV_DEV_STATISTICS_V2_COUNT;
+ else
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, u64 *buffer)
@@ -4353,17 +4369,7 @@ static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *e
/* update stats */
nv_do_stats_poll((unsigned long)dev);
- memcpy(buffer, &np->estats, nv_get_stats_count(dev)*sizeof(u64));
-}
-
-static int nv_self_test_count(struct net_device *dev)
-{
- struct fe_priv *np = netdev_priv(dev);
-
- if (np->driver_data & DEV_HAS_TEST_EXTENDED)
- return NV_TEST_COUNT_EXTENDED;
- else
- return NV_TEST_COUNT_BASE;
+ memcpy(buffer, &np->estats, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(u64));
}
static int nv_link_test(struct net_device *dev)
@@ -4610,7 +4616,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
int result;
- memset(buffer, 0, nv_self_test_count(dev)*sizeof(u64));
+ memset(buffer, 0, nv_get_sset_count(dev, ETH_SS_TEST)*sizeof(u64));
if (!nv_link_test(dev)) {
test->flags |= ETH_TEST_FL_FAILED;
@@ -4620,7 +4626,9 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
if (test->flags & ETH_TEST_FL_OFFLINE) {
if (netif_running(dev)) {
netif_stop_queue(dev);
- netif_poll_disable(dev);
+#ifdef CONFIG_FORCEDETH_NAPI
+ napi_disable(&np->napi);
+#endif
netif_tx_lock_bh(dev);
spin_lock_irq(&np->lock);
nv_disable_hw_interrupts(dev, np->irqmask);
@@ -4679,7 +4687,9 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
nv_start_rx(dev);
nv_start_tx(dev);
netif_start_queue(dev);
- netif_poll_enable(dev);
+#ifdef CONFIG_FORCEDETH_NAPI
+ napi_enable(&np->napi);
+#endif
nv_enable_hw_interrupts(dev, np->irqmask);
}
}
@@ -4689,10 +4699,10 @@ static void nv_get_strings(struct net_device *dev, u32 stringset, u8 *buffer)
{
switch (stringset) {
case ETH_SS_STATS:
- memcpy(buffer, &nv_estats_str, nv_get_stats_count(dev)*sizeof(struct nv_ethtool_str));
+ memcpy(buffer, &nv_estats_str, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(struct nv_ethtool_str));
break;
case ETH_SS_TEST:
- memcpy(buffer, &nv_etests_str, nv_self_test_count(dev)*sizeof(struct nv_ethtool_str));
+ memcpy(buffer, &nv_etests_str, nv_get_sset_count(dev, ETH_SS_TEST)*sizeof(struct nv_ethtool_str));
break;
}
}
@@ -4707,7 +4717,6 @@ static const struct ethtool_ops ops = {
.get_regs_len = nv_get_regs_len,
.get_regs = nv_get_regs,
.nway_reset = nv_nway_reset,
- .get_tso = ethtool_op_get_tso,
.set_tso = nv_set_tso,
.get_ringparam = nv_get_ringparam,
.set_ringparam = nv_set_ringparam,
@@ -4715,14 +4724,11 @@ static const struct ethtool_ops ops = {
.set_pauseparam = nv_set_pauseparam,
.get_rx_csum = nv_get_rx_csum,
.set_rx_csum = nv_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = nv_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = nv_set_sg,
.get_strings = nv_get_strings,
- .get_stats_count = nv_get_stats_count,
.get_ethtool_stats = nv_get_ethtool_stats,
- .self_test_count = nv_self_test_count,
+ .get_sset_count = nv_get_sset_count,
.self_test = nv_self_test,
};
@@ -4911,12 +4917,14 @@ static int nv_open(struct net_device *dev)
nv_start_rx(dev);
nv_start_tx(dev);
netif_start_queue(dev);
- netif_poll_enable(dev);
+#ifdef CONFIG_FORCEDETH_NAPI
+ napi_enable(&np->napi);
+#endif
if (ret) {
netif_carrier_on(dev);
} else {
- printk("%s: no link during initialization.\n", dev->name);
+ printk(KERN_INFO "%s: no link during initialization.\n", dev->name);
netif_carrier_off(dev);
}
if (oom)
@@ -4942,8 +4950,10 @@ static int nv_close(struct net_device *dev)
spin_lock_irq(&np->lock);
np->in_shutdown = 1;
spin_unlock_irq(&np->lock);
- netif_poll_disable(dev);
- synchronize_irq(dev->irq);
+#ifdef CONFIG_FORCEDETH_NAPI
+ napi_disable(&np->napi);
+#endif
+ synchronize_irq(np->pci_dev->irq);
del_timer_sync(&np->oom_kick);
del_timer_sync(&np->nic_poll);
@@ -4987,6 +4997,12 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
u32 powerstate, txreg;
u32 phystate_orig = 0, phystate;
int phyinitialized = 0;
+ DECLARE_MAC_BUF(mac);
+ static int printed_version;
+
+ if (!printed_version++)
+ printk(KERN_INFO "%s: Reverse Engineered nForce ethernet"
+ " driver. Version %s.\n", DRV_NAME, FORCEDETH_VERSION);
dev = alloc_etherdev(sizeof(struct fe_priv));
err = -ENOMEM;
@@ -4994,9 +5010,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
goto out;
np = netdev_priv(dev);
+ np->dev = dev;
np->pci_dev = pci_dev;
spin_lock_init(&np->lock);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pci_dev->dev);
init_timer(&np->oom_kick);
@@ -5010,11 +5026,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->stats_poll.function = &nv_do_stats_poll; /* timer handler */
err = pci_enable_device(pci_dev);
- if (err) {
- printk(KERN_INFO "forcedeth: pci_enable_dev failed (%d) for device %s\n",
- err, pci_name(pci_dev));
+ if (err)
goto out_free;
- }
pci_set_master(pci_dev);
@@ -5043,8 +5056,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
}
}
if (i == DEVICE_COUNT_RESOURCE) {
- printk(KERN_INFO "forcedeth: Couldn't find register window for device %s.\n",
- pci_name(pci_dev));
+ dev_printk(KERN_INFO, &pci_dev->dev,
+ "Couldn't find register window\n");
goto out_relreg;
}
@@ -5057,16 +5070,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->desc_ver = DESC_VER_3;
np->txrxctl_bits = NVREG_TXRXCTL_DESC_3;
if (dma_64bit) {
- if (pci_set_dma_mask(pci_dev, DMA_39BIT_MASK)) {
- printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n",
- pci_name(pci_dev));
- } else {
+ if (pci_set_dma_mask(pci_dev, DMA_39BIT_MASK))
+ dev_printk(KERN_INFO, &pci_dev->dev,
+ "64-bit DMA failed, using 32-bit addressing\n");
+ else
dev->features |= NETIF_F_HIGHDMA;
- printk(KERN_INFO "forcedeth: using HIGHDMA\n");
- }
if (pci_set_consistent_dma_mask(pci_dev, DMA_39BIT_MASK)) {
- printk(KERN_INFO "forcedeth: 64-bit DMA (consistent) failed, using 32-bit ring buffers for device %s.\n",
- pci_name(pci_dev));
+ dev_printk(KERN_INFO, &pci_dev->dev,
+ "64-bit DMA (consistent) failed, using 32-bit ring buffers\n");
}
}
} else if (id->driver_data & DEV_HAS_LARGEDESC) {
@@ -5155,9 +5166,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = nv_poll_controller;
#endif
- dev->weight = RX_WORK_PER_LOOP;
#ifdef CONFIG_FORCEDETH_NAPI
- dev->poll = nv_napi_poll;
+ netif_napi_add(dev, &np->napi, nv_napi_poll, RX_WORK_PER_LOOP);
#endif
SET_ETHTOOL_OPS(dev, &ops);
dev->tx_timeout = nv_tx_timeout;
@@ -5202,20 +5212,19 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
* Bad mac address. At least one bios sets the mac address
* to 01:23:45:67:89:ab
*/
- printk(KERN_ERR "%s: Invalid Mac address detected: %02x:%02x:%02x:%02x:%02x:%02x\n",
- pci_name(pci_dev),
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
- printk(KERN_ERR "Please complain to your hardware vendor. Switching to a random MAC.\n");
+ dev_printk(KERN_ERR, &pci_dev->dev,
+ "Invalid Mac address detected: %s\n",
+ print_mac(mac, dev->dev_addr));
+ dev_printk(KERN_ERR, &pci_dev->dev,
+ "Please complain to your hardware vendor. Switching to a random MAC.\n");
dev->dev_addr[0] = 0x00;
dev->dev_addr[1] = 0x00;
dev->dev_addr[2] = 0x6c;
get_random_bytes(&dev->dev_addr[3], 3);
}
- dprintk(KERN_DEBUG "%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", pci_name(pci_dev),
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ dprintk(KERN_DEBUG "%s: MAC Address %s\n",
+ pci_name(pci_dev), print_mac(mac, dev->dev_addr));
/* set mac address */
nv_copy_mac_to_hw(dev);
@@ -5321,8 +5330,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
break;
}
if (i == 33) {
- printk(KERN_INFO "%s: open: Could not find a valid PHY.\n",
- pci_name(pci_dev));
+ dev_printk(KERN_INFO, &pci_dev->dev,
+ "open: Could not find a valid PHY.\n");
goto out_error;
}
@@ -5344,12 +5353,37 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
err = register_netdev(dev);
if (err) {
- printk(KERN_INFO "forcedeth: unable to register netdev: %d\n", err);
+ dev_printk(KERN_INFO, &pci_dev->dev,
+ "unable to register netdev: %d\n", err);
goto out_error;
}
- printk(KERN_INFO "%s: forcedeth.c: subsystem: %05x:%04x bound to %s\n",
- dev->name, pci_dev->subsystem_vendor, pci_dev->subsystem_device,
- pci_name(pci_dev));
+
+ 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_HW_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;
@@ -5563,21 +5597,36 @@ static struct pci_device_id pci_tbl[] = {
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31),
.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
},
+ { /* MCP77 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ },
+ { /* MCP77 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ },
+ { /* MCP77 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ },
+ { /* MCP77 Ethernet Controller */
+ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35),
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+ },
{0,},
};
static struct pci_driver driver = {
- .name = "forcedeth",
- .id_table = pci_tbl,
- .probe = nv_probe,
- .remove = __devexit_p(nv_remove),
- .suspend = nv_suspend,
- .resume = nv_resume,
+ .name = DRV_NAME,
+ .id_table = pci_tbl,
+ .probe = nv_probe,
+ .remove = __devexit_p(nv_remove),
+ .suspend = nv_suspend,
+ .resume = nv_resume,
};
static int __init init_nic(void)
{
- printk(KERN_INFO "forcedeth.c: Reverse Engineered nForce ethernet driver. Version %s.\n", FORCEDETH_VERSION);
return pci_register_driver(&driver);
}
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig
index e27ee210b60..562ea68ed99 100644
--- a/drivers/net/fs_enet/Kconfig
+++ b/drivers/net/fs_enet/Kconfig
@@ -2,6 +2,7 @@ config FS_ENET
tristate "Freescale Ethernet Driver"
depends on CPM1 || CPM2
select MII
+ select PHYLIB
config FS_ENET_HAS_SCC
bool "Chip has an SCC usable for ethernet"
@@ -16,5 +17,14 @@ config FS_ENET_HAS_FCC
config FS_ENET_HAS_FEC
bool "Chip has an FEC usable for ethernet"
depends on FS_ENET && CPM1
+ select FS_ENET_MDIO_FEC
default y
+config FS_ENET_MDIO_FEC
+ tristate "MDIO driver for FEC"
+ depends on FS_ENET && CPM1
+
+config FS_ENET_MDIO_FCC
+ tristate "MDIO driver for FCC"
+ depends on FS_ENET && CPM2
+ select MDIO_BITBANG
diff --git a/drivers/net/fs_enet/Makefile b/drivers/net/fs_enet/Makefile
index 02d4dc18ba6..1ffbe0756a0 100644
--- a/drivers/net/fs_enet/Makefile
+++ b/drivers/net/fs_enet/Makefile
@@ -4,7 +4,16 @@
obj-$(CONFIG_FS_ENET) += fs_enet.o
-obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o mii-fec.o
-obj-$(CONFIG_CPM2) += mac-fcc.o mii-bitbang.o
+fs_enet-$(CONFIG_FS_ENET_HAS_SCC) += mac-scc.o
+fs_enet-$(CONFIG_FS_ENET_HAS_FEC) += mac-fec.o
+fs_enet-$(CONFIG_FS_ENET_HAS_FCC) += mac-fcc.o
-fs_enet-objs := fs_enet-main.o
+ifeq ($(CONFIG_PPC_CPM_NEW_BINDING),y)
+obj-$(CONFIG_FS_ENET_MDIO_FEC) += mii-fec.o
+obj-$(CONFIG_FS_ENET_MDIO_FCC) += mii-bitbang.o
+else
+fs_enet-$(CONFIG_FS_ENET_MDIO_FEC) += mii-fec.o
+fs_enet-$(CONFIG_FS_ENET_MDIO_FCC) += mii-bitbang.o
+endif
+
+fs_enet-objs := fs_enet-main.o $(fs_enet-m)
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index a4a2a0ea43d..f2a4d399a6e 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -1,17 +1,17 @@
/*
* Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
*
- * Copyright (c) 2003 Intracom S.A.
+ * Copyright (c) 2003 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
- *
- * 2005 (c) MontaVista Software, Inc.
+ *
+ * 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
* Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>
* and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
*
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
@@ -39,28 +39,35 @@
#include <linux/vmalloc.h>
#include <asm/pgtable.h>
-
-#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_platform.h>
+#endif
+
#include "fs_enet.h"
/*************************************************/
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n";
+#endif
MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>");
MODULE_DESCRIPTION("Freescale Ethernet Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
-int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */
+static int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */
module_param(fs_enet_debug, int, 0);
MODULE_PARM_DESC(fs_enet_debug,
"Freescale bitmapped debugging message enable value");
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void fs_enet_netpoll(struct net_device *dev);
+#endif
static void fs_set_multicast_list(struct net_device *dev)
{
@@ -69,19 +76,25 @@ static void fs_set_multicast_list(struct net_device *dev)
(*fep->ops->set_multicast_list)(dev);
}
+static void skb_align(struct sk_buff *skb, int align)
+{
+ int off = ((unsigned long)skb->data) & (align - 1);
+
+ if (off)
+ skb_reserve(skb, align - off);
+}
+
/* NAPI receive function */
-static int fs_enet_rx_napi(struct net_device *dev, int *budget)
+static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
{
- struct fs_enet_private *fep = netdev_priv(dev);
+ struct fs_enet_private *fep = container_of(napi, struct fs_enet_private, napi);
+ struct net_device *dev = fep->ndev;
const struct fs_platform_info *fpi = fep->fpi;
- cbd_t *bdp;
+ cbd_t __iomem *bdp;
struct sk_buff *skb, *skbn, *skbt;
int received = 0;
u16 pkt_len, sc;
int curidx;
- int rx_work_limit = 0; /* pacify gcc */
-
- rx_work_limit = min(dev->quota, *budget);
if (!netif_running(dev))
return 0;
@@ -96,7 +109,6 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
(*fep->ops->napi_clear_rx_event)(dev);
while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) {
-
curidx = bdp - fep->rx_bd_base;
/*
@@ -109,7 +121,7 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
dev->name);
/*
- * Check for errors.
+ * Check for errors.
*/
if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL |
BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) {
@@ -136,11 +148,6 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
skbn = skb;
} else {
-
- /* napi, got packet but no quota */
- if (--rx_work_limit < 0)
- break;
-
skb = fep->rx_skbuff[curidx];
dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp),
@@ -166,9 +173,13 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
skb = skbn;
skbn = skbt;
}
- } else
+ } else {
skbn = dev_alloc_skb(ENET_RX_FRSIZE);
+ if (skbn)
+ skb_align(skbn, ENET_RX_ALIGN);
+ }
+
if (skbn != NULL) {
skb_put(skb, pkt_len); /* Make room */
skb->protocol = eth_type_trans(skb, dev);
@@ -191,7 +202,7 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY);
/*
- * Update BD pointer to next entry.
+ * Update BD pointer to next entry.
*/
if ((sc & BD_ENET_RX_WRAP) == 0)
bdp++;
@@ -199,22 +210,19 @@ static int fs_enet_rx_napi(struct net_device *dev, int *budget)
bdp = fep->rx_bd_base;
(*fep->ops->rx_bd_done)(dev);
+
+ if (received >= budget)
+ break;
}
fep->cur_rx = bdp;
- dev->quota -= received;
- *budget -= received;
-
- if (rx_work_limit < 0)
- return 1; /* not done */
-
- /* done */
- netif_rx_complete(dev);
-
- (*fep->ops->napi_enable_rx)(dev);
-
- return 0;
+ if (received < budget) {
+ /* done */
+ netif_rx_complete(dev, napi);
+ (*fep->ops->napi_enable_rx)(dev);
+ }
+ return received;
}
/* non NAPI receive function */
@@ -222,7 +230,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
- cbd_t *bdp;
+ cbd_t __iomem *bdp;
struct sk_buff *skb, *skbn, *skbt;
int received = 0;
u16 pkt_len, sc;
@@ -247,7 +255,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
dev->name);
/*
- * Check for errors.
+ * Check for errors.
*/
if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL |
BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) {
@@ -300,9 +308,13 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
skb = skbn;
skbn = skbt;
}
- } else
+ } else {
skbn = dev_alloc_skb(ENET_RX_FRSIZE);
+ if (skbn)
+ skb_align(skbn, ENET_RX_ALIGN);
+ }
+
if (skbn != NULL) {
skb_put(skb, pkt_len); /* Make room */
skb->protocol = eth_type_trans(skb, dev);
@@ -325,7 +337,7 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY);
/*
- * Update BD pointer to next entry.
+ * Update BD pointer to next entry.
*/
if ((sc & BD_ENET_RX_WRAP) == 0)
bdp++;
@@ -343,17 +355,16 @@ static int fs_enet_rx_non_napi(struct net_device *dev)
static void fs_enet_tx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- cbd_t *bdp;
+ cbd_t __iomem *bdp;
struct sk_buff *skb;
int dirtyidx, do_wake, do_restart;
u16 sc;
- spin_lock(&fep->lock);
+ spin_lock(&fep->tx_lock);
bdp = fep->dirty_tx;
do_wake = do_restart = 0;
while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) {
-
dirtyidx = bdp - fep->tx_bd_base;
if (fep->tx_free == fep->tx_ring)
@@ -362,7 +373,7 @@ static void fs_enet_tx(struct net_device *dev)
skb = fep->tx_skbuff[dirtyidx];
/*
- * Check for errors.
+ * Check for errors.
*/
if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC |
BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) {
@@ -402,13 +413,13 @@ static void fs_enet_tx(struct net_device *dev)
skb->len, DMA_TO_DEVICE);
/*
- * Free the sk buffer associated with this last transmit.
+ * Free the sk buffer associated with this last transmit.
*/
dev_kfree_skb_irq(skb);
fep->tx_skbuff[dirtyidx] = NULL;
/*
- * Update pointer to next buffer descriptor to be transmitted.
+ * Update pointer to next buffer descriptor to be transmitted.
*/
if ((sc & BD_ENET_TX_WRAP) == 0)
bdp++;
@@ -428,7 +439,7 @@ static void fs_enet_tx(struct net_device *dev)
if (do_restart)
(*fep->ops->tx_restart)(dev);
- spin_unlock(&fep->lock);
+ spin_unlock(&fep->tx_lock);
if (do_wake)
netif_wake_queue(dev);
@@ -454,7 +465,6 @@ fs_enet_interrupt(int irq, void *dev_id)
nr = 0;
while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) {
-
nr++;
int_clr_events = int_events;
@@ -470,7 +480,7 @@ fs_enet_interrupt(int irq, void *dev_id)
if (!fpi->use_napi)
fs_enet_rx_non_napi(dev);
else {
- napi_ok = netif_rx_schedule_prep(dev);
+ napi_ok = napi_schedule_prep(&fep->napi);
(*fep->ops->napi_disable_rx)(dev);
(*fep->ops->clear_int_events)(dev, fep->ev_napi_rx);
@@ -478,7 +488,7 @@ fs_enet_interrupt(int irq, void *dev_id)
/* NOTE: it is possible for FCCs in NAPI mode */
/* to submit a spurious interrupt while in poll */
if (napi_ok)
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &fep->napi);
}
}
@@ -493,7 +503,7 @@ fs_enet_interrupt(int irq, void *dev_id)
void fs_init_bds(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- cbd_t *bdp;
+ cbd_t __iomem *bdp;
struct sk_buff *skb;
int i;
@@ -504,7 +514,7 @@ void fs_init_bds(struct net_device *dev)
fep->cur_rx = fep->rx_bd_base;
/*
- * Initialize the receive buffer descriptors.
+ * Initialize the receive buffer descriptors.
*/
for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) {
skb = dev_alloc_skb(ENET_RX_FRSIZE);
@@ -514,6 +524,7 @@ void fs_init_bds(struct net_device *dev)
dev->name);
break;
}
+ skb_align(skb, ENET_RX_ALIGN);
fep->rx_skbuff[i] = skb;
CBDW_BUFADDR(bdp,
dma_map_single(fep->dev, skb->data,
@@ -524,7 +535,7 @@ void fs_init_bds(struct net_device *dev)
((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP));
}
/*
- * if we failed, fillup remainder
+ * if we failed, fillup remainder
*/
for (; i < fep->rx_ring; i++, bdp++) {
fep->rx_skbuff[i] = NULL;
@@ -532,7 +543,7 @@ void fs_init_bds(struct net_device *dev)
}
/*
- * ...and the same for transmit.
+ * ...and the same for transmit.
*/
for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) {
fep->tx_skbuff[i] = NULL;
@@ -546,11 +557,11 @@ void fs_cleanup_bds(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
struct sk_buff *skb;
- cbd_t *bdp;
+ cbd_t __iomem *bdp;
int i;
/*
- * Reset SKB transmit buffers.
+ * Reset SKB transmit buffers.
*/
for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) {
if ((skb = fep->tx_skbuff[i]) == NULL)
@@ -565,7 +576,7 @@ void fs_cleanup_bds(struct net_device *dev)
}
/*
- * Reset SKB receive buffers
+ * Reset SKB receive buffers
*/
for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) {
if ((skb = fep->rx_skbuff[i]) == NULL)
@@ -587,7 +598,7 @@ void fs_cleanup_bds(struct net_device *dev)
static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- cbd_t *bdp;
+ cbd_t __iomem *bdp;
int curidx;
u16 sc;
unsigned long flags;
@@ -595,7 +606,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave(&fep->tx_lock, flags);
/*
- * Fill in a Tx ring entry
+ * Fill in a Tx ring entry
*/
bdp = fep->cur_tx;
@@ -614,19 +625,19 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
curidx = bdp - fep->tx_bd_base;
/*
- * Clear all of the status flags.
+ * Clear all of the status flags.
*/
CBDC_SC(bdp, BD_ENET_TX_STATS);
/*
- * Save skb pointer.
+ * Save skb pointer.
*/
fep->tx_skbuff[curidx] = skb;
fep->stats.tx_bytes += skb->len;
/*
- * Push the data cache so the CPM does not get stale memory data.
+ * Push the data cache so the CPM does not get stale memory data.
*/
CBDW_BUFADDR(bdp, dma_map_single(fep->dev,
skb->data, skb->len, DMA_TO_DEVICE));
@@ -635,7 +646,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
/*
- * If this was the last BD in the ring, start at the beginning again.
+ * If this was the last BD in the ring, start at the beginning again.
*/
if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0)
fep->cur_tx++;
@@ -710,45 +721,43 @@ static void fs_timeout(struct net_device *dev)
*-----------------------------------------------------------------------------*/
static void generic_adjust_link(struct net_device *dev)
{
- struct fs_enet_private *fep = netdev_priv(dev);
- struct phy_device *phydev = fep->phydev;
- int new_state = 0;
-
- if (phydev->link) {
-
- /* adjust to duplex mode */
- if (phydev->duplex != fep->oldduplex){
- new_state = 1;
- fep->oldduplex = phydev->duplex;
- }
-
- if (phydev->speed != fep->oldspeed) {
- new_state = 1;
- fep->oldspeed = phydev->speed;
- }
-
- if (!fep->oldlink) {
- new_state = 1;
- fep->oldlink = 1;
- netif_schedule(dev);
- netif_carrier_on(dev);
- netif_start_queue(dev);
- }
-
- if (new_state)
- fep->ops->restart(dev);
-
- } else if (fep->oldlink) {
- new_state = 1;
- fep->oldlink = 0;
- fep->oldspeed = 0;
- fep->oldduplex = -1;
- netif_carrier_off(dev);
- netif_stop_queue(dev);
- }
-
- if (new_state && netif_msg_link(fep))
- phy_print_status(phydev);
+ struct fs_enet_private *fep = netdev_priv(dev);
+ struct phy_device *phydev = fep->phydev;
+ int new_state = 0;
+
+ if (phydev->link) {
+ /* adjust to duplex mode */
+ if (phydev->duplex != fep->oldduplex) {
+ new_state = 1;
+ fep->oldduplex = phydev->duplex;
+ }
+
+ if (phydev->speed != fep->oldspeed) {
+ new_state = 1;
+ fep->oldspeed = phydev->speed;
+ }
+
+ if (!fep->oldlink) {
+ new_state = 1;
+ fep->oldlink = 1;
+ netif_schedule(dev);
+ netif_carrier_on(dev);
+ netif_start_queue(dev);
+ }
+
+ if (new_state)
+ fep->ops->restart(dev);
+ } else if (fep->oldlink) {
+ new_state = 1;
+ fep->oldlink = 0;
+ fep->oldspeed = 0;
+ fep->oldduplex = -1;
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
+ }
+
+ if (new_state && netif_msg_link(fep))
+ phy_print_status(phydev);
}
@@ -792,25 +801,31 @@ static int fs_init_phy(struct net_device *dev)
return 0;
}
-
static int fs_enet_open(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
int r;
int err;
+ if (fep->fpi->use_napi)
+ napi_enable(&fep->napi);
+
/* Install our interrupt handler. */
r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt);
if (r != 0) {
printk(KERN_ERR DRV_MODULE_NAME
": %s Could not allocate FS_ENET IRQ!", dev->name);
+ if (fep->fpi->use_napi)
+ napi_disable(&fep->napi);
return -EINVAL;
}
err = fs_init_phy(dev);
- if(err)
+ if (err) {
+ if (fep->fpi->use_napi)
+ napi_disable(&fep->napi);
return err;
-
+ }
phy_start(fep->phydev);
return 0;
@@ -823,10 +838,13 @@ static int fs_enet_close(struct net_device *dev)
netif_stop_queue(dev);
netif_carrier_off(dev);
+ napi_disable(&fep->napi);
phy_stop(fep->phydev);
spin_lock_irqsave(&fep->lock, flags);
+ spin_lock(&fep->tx_lock);
(*fep->ops->stop)(dev);
+ spin_unlock(&fep->tx_lock);
spin_unlock_irqrestore(&fep->lock, flags);
/* release any irqs */
@@ -915,9 +933,7 @@ static const struct ethtool_ops fs_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_msglevel = fs_get_msglevel,
.set_msglevel = fs_set_msglevel,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum, /* local! */
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_regs = fs_get_regs,
};
@@ -941,6 +957,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
extern int fs_mii_connect(struct net_device *dev);
extern void fs_mii_disconnect(struct net_device *dev);
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
static struct net_device *fs_init_instance(struct device *dev,
struct fs_platform_info *fpi)
{
@@ -961,10 +978,8 @@ static struct net_device *fs_init_instance(struct device *dev,
err = -ENOMEM;
goto err;
}
- SET_MODULE_OWNER(ndev);
fep = netdev_priv(ndev);
- memset(fep, 0, privsize); /* clear everything */
fep->dev = dev;
dev_set_drvdata(dev, ndev);
@@ -978,7 +993,7 @@ static struct net_device *fs_init_instance(struct device *dev,
#endif
#ifdef CONFIG_FS_ENET_HAS_SCC
- if (fs_get_scc_index(fpi->fs_no) >=0 )
+ if (fs_get_scc_index(fpi->fs_no) >=0)
fep->ops = &fs_scc_ops;
#endif
@@ -1013,13 +1028,13 @@ static struct net_device *fs_init_instance(struct device *dev,
spin_lock_init(&fep->tx_lock);
/*
- * Set the Ethernet address.
+ * Set the Ethernet address.
*/
for (i = 0; i < 6; i++)
ndev->dev_addr[i] = fpi->macaddr[i];
-
+
r = (*fep->ops->allocate_bd)(ndev);
-
+
if (fep->ring_base == NULL) {
printk(KERN_ERR DRV_MODULE_NAME
": %s buffer descriptor alloc failed (%d).\n", ndev->name, r);
@@ -1038,7 +1053,7 @@ static struct net_device *fs_init_instance(struct device *dev,
fep->rx_ring = fpi->rx_ring;
/*
- * The FEC Ethernet specific entries in the device structure.
+ * The FEC Ethernet specific entries in the device structure.
*/
ndev->open = fs_enet_open;
ndev->hard_start_xmit = fs_enet_start_xmit;
@@ -1047,10 +1062,14 @@ static struct net_device *fs_init_instance(struct device *dev,
ndev->stop = fs_enet_close;
ndev->get_stats = fs_enet_get_stats;
ndev->set_multicast_list = fs_set_multicast_list;
- if (fpi->use_napi) {
- ndev->poll = fs_enet_rx_napi;
- ndev->weight = fpi->napi_weight;
- }
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ ndev->poll_controller = fs_enet_netpoll;
+#endif
+
+ netif_napi_add(ndev, &fep->napi,
+ fs_enet_rx_napi, fpi->napi_weight);
+
ndev->ethtool_ops = &fs_ethtool_ops;
ndev->do_ioctl = fs_ioctl;
@@ -1069,9 +1088,8 @@ static struct net_device *fs_init_instance(struct device *dev,
return ndev;
- err:
+err:
if (ndev != NULL) {
-
if (registered)
unregister_netdev(ndev);
@@ -1106,7 +1124,7 @@ static int fs_cleanup_instance(struct net_device *ndev)
unregister_netdev(ndev);
dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t),
- fep->ring_base, fep->ring_mem_addr);
+ (void __force *)fep->ring_base, fep->ring_mem_addr);
/* reset it */
(*fep->ops->cleanup_data)(ndev);
@@ -1121,43 +1139,260 @@ static int fs_cleanup_instance(struct net_device *ndev)
return 0;
}
+#endif
/**************************************************************************************/
/* handy pointer to the immap */
-void *fs_enet_immap = NULL;
+void __iomem *fs_enet_immap = NULL;
static int setup_immap(void)
{
- phys_addr_t paddr = 0;
- unsigned long size = 0;
-
#ifdef CONFIG_CPM1
- paddr = IMAP_ADDR;
- size = 0x10000; /* map 64K */
-#endif
-
-#ifdef CONFIG_CPM2
- paddr = CPM_MAP_ADDR;
- size = 0x40000; /* map 256 K */
+ fs_enet_immap = ioremap(IMAP_ADDR, 0x4000);
+ WARN_ON(!fs_enet_immap);
+#elif defined(CONFIG_CPM2)
+ fs_enet_immap = cpm2_immr;
#endif
- fs_enet_immap = ioremap(paddr, size);
- if (fs_enet_immap == NULL)
- return -EBADF; /* XXX ahem; maybe just BUG_ON? */
return 0;
}
static void cleanup_immap(void)
{
- if (fs_enet_immap != NULL) {
- iounmap(fs_enet_immap);
- fs_enet_immap = NULL;
- }
+#if defined(CONFIG_CPM1)
+ iounmap(fs_enet_immap);
+#endif
}
/**************************************************************************************/
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static int __devinit find_phy(struct device_node *np,
+ struct fs_platform_info *fpi)
+{
+ struct device_node *phynode, *mdionode;
+ struct resource res;
+ int ret = 0, len;
+
+ const u32 *data = of_get_property(np, "phy-handle", &len);
+ if (!data || len != 4)
+ return -EINVAL;
+
+ phynode = of_find_node_by_phandle(*data);
+ if (!phynode)
+ return -EINVAL;
+
+ mdionode = of_get_parent(phynode);
+ if (!mdionode)
+ goto out_put_phy;
+
+ ret = of_address_to_resource(mdionode, 0, &res);
+ if (ret)
+ goto out_put_mdio;
+
+ data = of_get_property(phynode, "reg", &len);
+ if (!data || len != 4)
+ goto out_put_mdio;
+
+ snprintf(fpi->bus_id, 16, PHY_ID_FMT, res.start, *data);
+
+out_put_mdio:
+ of_node_put(mdionode);
+out_put_phy:
+ of_node_put(phynode);
+ return ret;
+}
+
+#ifdef CONFIG_FS_ENET_HAS_FEC
+#define IS_FEC(match) ((match)->data == &fs_fec_ops)
+#else
+#define IS_FEC(match) 0
+#endif
+
+static int __devinit fs_enet_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct net_device *ndev;
+ struct fs_enet_private *fep;
+ struct fs_platform_info *fpi;
+ const u32 *data;
+ const u8 *mac_addr;
+ int privsize, len, ret = -ENODEV;
+
+ fpi = kzalloc(sizeof(*fpi), GFP_KERNEL);
+ if (!fpi)
+ return -ENOMEM;
+
+ if (!IS_FEC(match)) {
+ data = of_get_property(ofdev->node, "fsl,cpm-command", &len);
+ if (!data || len != 4)
+ goto out_free_fpi;
+
+ fpi->cp_command = *data;
+ }
+
+ fpi->rx_ring = 32;
+ fpi->tx_ring = 32;
+ fpi->rx_copybreak = 240;
+ fpi->use_napi = 1;
+ fpi->napi_weight = 17;
+
+ ret = find_phy(ofdev->node, fpi);
+ if (ret)
+ goto out_free_fpi;
+
+ privsize = sizeof(*fep) +
+ sizeof(struct sk_buff **) *
+ (fpi->rx_ring + fpi->tx_ring);
+
+ ndev = alloc_etherdev(privsize);
+ if (!ndev) {
+ ret = -ENOMEM;
+ goto out_free_fpi;
+ }
+
+ dev_set_drvdata(&ofdev->dev, ndev);
+
+ fep = netdev_priv(ndev);
+ fep->dev = &ofdev->dev;
+ fep->ndev = ndev;
+ fep->fpi = fpi;
+ fep->ops = match->data;
+
+ ret = fep->ops->setup_data(ndev);
+ if (ret)
+ goto out_free_dev;
+
+ fep->rx_skbuff = (struct sk_buff **)&fep[1];
+ fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring;
+
+ spin_lock_init(&fep->lock);
+ spin_lock_init(&fep->tx_lock);
+
+ mac_addr = of_get_mac_address(ofdev->node);
+ if (mac_addr)
+ memcpy(ndev->dev_addr, mac_addr, 6);
+
+ ret = fep->ops->allocate_bd(ndev);
+ if (ret)
+ goto out_cleanup_data;
+
+ fep->rx_bd_base = fep->ring_base;
+ fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring;
+
+ fep->tx_ring = fpi->tx_ring;
+ fep->rx_ring = fpi->rx_ring;
+
+ ndev->open = fs_enet_open;
+ ndev->hard_start_xmit = fs_enet_start_xmit;
+ ndev->tx_timeout = fs_timeout;
+ ndev->watchdog_timeo = 2 * HZ;
+ ndev->stop = fs_enet_close;
+ ndev->get_stats = fs_enet_get_stats;
+ ndev->set_multicast_list = fs_set_multicast_list;
+
+ if (fpi->use_napi)
+ netif_napi_add(ndev, &fep->napi, fs_enet_rx_napi,
+ fpi->napi_weight);
+
+ ndev->ethtool_ops = &fs_ethtool_ops;
+ ndev->do_ioctl = fs_ioctl;
+
+ init_timer(&fep->phy_timer_list);
+
+ netif_carrier_off(ndev);
+
+ ret = register_netdev(ndev);
+ if (ret)
+ goto out_free_bd;
+
+ printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ndev->name,
+ ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
+ ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+
+ return 0;
+
+out_free_bd:
+ fep->ops->free_bd(ndev);
+out_cleanup_data:
+ fep->ops->cleanup_data(ndev);
+out_free_dev:
+ free_netdev(ndev);
+ dev_set_drvdata(&ofdev->dev, NULL);
+out_free_fpi:
+ kfree(fpi);
+ return ret;
+}
+
+static int fs_enet_remove(struct of_device *ofdev)
+{
+ struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
+ struct fs_enet_private *fep = netdev_priv(ndev);
+
+ unregister_netdev(ndev);
+
+ fep->ops->free_bd(ndev);
+ fep->ops->cleanup_data(ndev);
+ dev_set_drvdata(fep->dev, NULL);
+
+ free_netdev(ndev);
+ return 0;
+}
+
+static struct of_device_id fs_enet_match[] = {
+#ifdef CONFIG_FS_ENET_HAS_SCC
+ {
+ .compatible = "fsl,cpm1-scc-enet",
+ .data = (void *)&fs_scc_ops,
+ },
+#endif
+#ifdef CONFIG_FS_ENET_HAS_FCC
+ {
+ .compatible = "fsl,cpm2-fcc-enet",
+ .data = (void *)&fs_fcc_ops,
+ },
+#endif
+#ifdef CONFIG_FS_ENET_HAS_FEC
+ {
+ .compatible = "fsl,pq1-fec-enet",
+ .data = (void *)&fs_fec_ops,
+ },
+#endif
+ {}
+};
+
+static struct of_platform_driver fs_enet_driver = {
+ .name = "fs_enet",
+ .match_table = fs_enet_match,
+ .probe = fs_enet_probe,
+ .remove = fs_enet_remove,
+};
+
+static int __init fs_init(void)
+{
+ int r = setup_immap();
+ if (r != 0)
+ return r;
+
+ r = of_register_platform_driver(&fs_enet_driver);
+ if (r != 0)
+ goto out;
+
+ return 0;
+
+out:
+ cleanup_immap();
+ return r;
+}
+
+static void __exit fs_cleanup(void)
+{
+ of_unregister_platform_driver(&fs_enet_driver);
+ cleanup_immap();
+}
+#else
static int __devinit fs_enet_probe(struct device *dev)
{
struct net_device *ndev;
@@ -1262,7 +1497,6 @@ static int __init fs_init(void)
err:
cleanup_immap();
return r;
-
}
static void __exit fs_cleanup(void)
@@ -1272,6 +1506,16 @@ static void __exit fs_cleanup(void)
driver_unregister(&fs_enet_scc_driver);
cleanup_immap();
}
+#endif
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void fs_enet_netpoll(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ fs_enet_interrupt(dev->irq, dev, NULL);
+ enable_irq(dev->irq);
+}
+#endif
/**************************************************************************************/
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index 569be225cd0..c675e29aadc 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -15,8 +15,8 @@
#include <asm/commproc.h>
struct fec_info {
- fec_t* fecp;
- u32 mii_speed;
+ fec_t __iomem *fecp;
+ u32 mii_speed;
};
#endif
@@ -24,19 +24,6 @@ struct fec_info {
#include <asm/cpm2.h>
#endif
-/* This is used to operate with pins.
- Note that the actual port size may
- be different; cpm(s) handle it OK */
-struct bb_info {
- u8 mdio_dat_msk;
- u8 mdio_dir_msk;
- u8 *mdio_dir;
- u8 *mdio_dat;
- u8 mdc_msk;
- u8 *mdc_dat;
- int delay;
-};
-
/* hw driver ops */
struct fs_ops {
int (*setup_data)(struct net_device *dev);
@@ -82,60 +69,27 @@ struct phy_info {
/* Must be a multiple of 32 (to cover both FEC & FCC) */
#define PKT_MAXBLR_SIZE ((PKT_MAXBUF_SIZE + 31) & ~31)
/* This is needed so that invalidate_xxx wont invalidate too much */
-#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE)
-
-struct fs_enet_mii_bus {
- struct list_head list;
- spinlock_t mii_lock;
- const struct fs_mii_bus_info *bus_info;
- int refs;
- u32 usage_map;
-
- int (*mii_read)(struct fs_enet_mii_bus *bus,
- int phy_id, int location);
-
- void (*mii_write)(struct fs_enet_mii_bus *bus,
- int phy_id, int location, int value);
-
- union {
- struct {
- unsigned int mii_speed;
- void *fecp;
- } fec;
-
- struct {
- /* note that the actual port size may */
- /* be different; cpm(s) handle it OK */
- u8 mdio_msk;
- u8 *mdio_dir;
- u8 *mdio_dat;
- u8 mdc_msk;
- u8 *mdc_dir;
- u8 *mdc_dat;
- } bitbang;
-
- struct {
- u16 lpa;
- } fixed;
- };
-};
+#define ENET_RX_ALIGN 16
+#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE + ENET_RX_ALIGN - 1)
struct fs_enet_private {
+ struct napi_struct napi;
struct device *dev; /* pointer back to the device (must be initialized first) */
+ struct net_device *ndev;
spinlock_t lock; /* during all ops except TX pckt processing */
spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */
- const struct fs_platform_info *fpi;
+ struct fs_platform_info *fpi;
const struct fs_ops *ops;
int rx_ring, tx_ring;
dma_addr_t ring_mem_addr;
- void *ring_base;
+ void __iomem *ring_base;
struct sk_buff **rx_skbuff;
struct sk_buff **tx_skbuff;
- cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */
- cbd_t *tx_bd_base;
- cbd_t *dirty_tx; /* ring entries to be free()ed. */
- cbd_t *cur_rx;
- cbd_t *cur_tx;
+ cbd_t __iomem *rx_bd_base; /* Address of Rx and Tx buffers. */
+ cbd_t __iomem *tx_bd_base;
+ cbd_t __iomem *dirty_tx; /* ring entries to be free()ed. */
+ cbd_t __iomem *cur_rx;
+ cbd_t __iomem *cur_tx;
int tx_free;
struct net_device_stats stats;
struct timer_list phy_timer_list;
@@ -143,7 +97,6 @@ struct fs_enet_private {
u32 msg_enable;
struct mii_if_info mii_if;
unsigned int last_mii_status;
- struct fs_enet_mii_bus *mii_bus;
int interrupt;
struct phy_device *phydev;
@@ -161,23 +114,23 @@ struct fs_enet_private {
union {
struct {
int idx; /* FEC1 = 0, FEC2 = 1 */
- void *fecp; /* hw registers */
+ void __iomem *fecp; /* hw registers */
u32 hthi, htlo; /* state for multicast */
} fec;
struct {
int idx; /* FCC1-3 = 0-2 */
- void *fccp; /* hw registers */
- void *ep; /* parameter ram */
- void *fcccp; /* hw registers cont. */
- void *mem; /* FCC DPRAM */
+ void __iomem *fccp; /* hw registers */
+ void __iomem *ep; /* parameter ram */
+ void __iomem *fcccp; /* hw registers cont. */
+ void __iomem *mem; /* FCC DPRAM */
u32 gaddrh, gaddrl; /* group address */
} fcc;
struct {
int idx; /* FEC1 = 0, FEC2 = 1 */
- void *sccp; /* hw registers */
- void *ep; /* parameter ram */
+ void __iomem *sccp; /* hw registers */
+ void __iomem *ep; /* parameter ram */
u32 hthi, htlo; /* state for multicast */
} scc;
@@ -185,9 +138,10 @@ struct fs_enet_private {
};
/***************************************************************************/
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
int fs_enet_mdio_bb_init(void);
-int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);
int fs_enet_mdio_fec_init(void);
+#endif
void fs_init_bds(struct net_device *dev);
void fs_cleanup_bds(struct net_device *dev);
@@ -247,7 +201,7 @@ extern const struct fs_ops fs_scc_ops;
/*******************************************************************/
/* handy pointer to the immap */
-extern void *fs_enet_immap;
+extern void __iomem *fs_enet_immap;
/*******************************************************************/
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 5603121132c..da4efbca646 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -1,14 +1,14 @@
/*
* FCC driver for Motorola MPC82xx (PQ2).
*
- * Copyright (c) 2003 Intracom S.A.
+ * Copyright (c) 2003 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
*
- * 2005 (c) MontaVista Software, Inc.
+ * 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
@@ -42,34 +42,29 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_device.h>
+#endif
+
#include "fs_enet.h"
/*************************************************/
/* FCC access macros */
-#define __fcc_out32(addr, x) out_be32((unsigned *)addr, x)
-#define __fcc_out16(addr, x) out_be16((unsigned short *)addr, x)
-#define __fcc_out8(addr, x) out_8((unsigned char *)addr, x)
-#define __fcc_in32(addr) in_be32((unsigned *)addr)
-#define __fcc_in16(addr) in_be16((unsigned short *)addr)
-#define __fcc_in8(addr) in_8((unsigned char *)addr)
-
-/* parameter space */
-
/* write, read, set bits, clear bits */
-#define W32(_p, _m, _v) __fcc_out32(&(_p)->_m, (_v))
-#define R32(_p, _m) __fcc_in32(&(_p)->_m)
+#define W32(_p, _m, _v) out_be32(&(_p)->_m, (_v))
+#define R32(_p, _m) in_be32(&(_p)->_m)
#define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v))
#define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v))
-#define W16(_p, _m, _v) __fcc_out16(&(_p)->_m, (_v))
-#define R16(_p, _m) __fcc_in16(&(_p)->_m)
+#define W16(_p, _m, _v) out_be16(&(_p)->_m, (_v))
+#define R16(_p, _m) in_be16(&(_p)->_m)
#define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v))
#define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v))
-#define W8(_p, _m, _v) __fcc_out8(&(_p)->_m, (_v))
-#define R8(_p, _m) __fcc_in8(&(_p)->_m)
+#define W8(_p, _m, _v) out_8(&(_p)->_m, (_v))
+#define R8(_p, _m) in_8(&(_p)->_m)
#define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v))
#define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v))
@@ -83,34 +78,62 @@
#define MAX_CR_CMD_LOOPS 10000
-static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op)
+static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op)
{
const struct fs_platform_info *fpi = fep->fpi;
-
- cpm2_map_t *immap = fs_enet_immap;
- cpm_cpm2_t *cpmp = &immap->im_cpm;
- u32 v;
int i;
- /* Currently I don't know what feature call will look like. But
- I guess there'd be something like do_cpm_cmd() which will require page & sblock */
- v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op);
- W32(cpmp, cp_cpcr, v | CPM_CR_FLG);
+ W32(cpmp, cp_cpcr, fpi->cp_command | op | CPM_CR_FLG);
for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
- break;
+ return 0;
- if (i >= MAX_CR_CMD_LOOPS) {
- printk(KERN_ERR "%s(): Not able to issue CPM command\n",
- __FUNCTION__);
- return 1;
- }
-
- return 0;
+ printk(KERN_ERR "%s(): Not able to issue CPM command\n",
+ __FUNCTION__);
+ return 1;
}
static int do_pd_setup(struct fs_enet_private *fep)
{
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct of_device *ofdev = to_of_device(fep->dev);
+ struct fs_platform_info *fpi = fep->fpi;
+ int ret = -EINVAL;
+
+ fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (fep->interrupt == NO_IRQ)
+ goto out;
+
+ fep->fcc.fccp = of_iomap(ofdev->node, 0);
+ if (!fep->fcc.fccp)
+ goto out;
+
+ fep->fcc.ep = of_iomap(ofdev->node, 1);
+ if (!fep->fcc.ep)
+ goto out_fccp;
+
+ fep->fcc.fcccp = of_iomap(ofdev->node, 2);
+ if (!fep->fcc.fcccp)
+ goto out_ep;
+
+ fep->fcc.mem = (void __iomem *)cpm2_immr;
+ fpi->dpram_offset = cpm_dpalloc(128, 8);
+ if (IS_ERR_VALUE(fpi->dpram_offset)) {
+ ret = fpi->dpram_offset;
+ goto out_fcccp;
+ }
+
+ return 0;
+
+out_fcccp:
+ iounmap(fep->fcc.fcccp);
+out_ep:
+ iounmap(fep->fcc.ep);
+out_fccp:
+ iounmap(fep->fcc.fccp);
+out:
+ return ret;
+#else
struct platform_device *pdev = to_platform_device(fep->dev);
struct resource *r;
@@ -121,33 +144,33 @@ static int do_pd_setup(struct fs_enet_private *fep)
/* Attach the memory for the FCC Parameter RAM */
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram");
- fep->fcc.ep = (void *)ioremap(r->start, r->end - r->start + 1);
+ fep->fcc.ep = ioremap(r->start, r->end - r->start + 1);
if (fep->fcc.ep == NULL)
return -EINVAL;
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs");
- fep->fcc.fccp = (void *)ioremap(r->start, r->end - r->start + 1);
+ fep->fcc.fccp = ioremap(r->start, r->end - r->start + 1);
if (fep->fcc.fccp == NULL)
return -EINVAL;
if (fep->fpi->fcc_regs_c) {
-
- fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c;
+ fep->fcc.fcccp = (void __iomem *)fep->fpi->fcc_regs_c;
} else {
r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"fcc_regs_c");
- fep->fcc.fcccp = (void *)ioremap(r->start,
+ fep->fcc.fcccp = ioremap(r->start,
r->end - r->start + 1);
}
if (fep->fcc.fcccp == NULL)
return -EINVAL;
- fep->fcc.mem = (void *)fep->fpi->mem_offset;
+ fep->fcc.mem = (void __iomem *)fep->fpi->mem_offset;
if (fep->fcc.mem == NULL)
return -EINVAL;
return 0;
+#endif
}
#define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB)
@@ -158,11 +181,17 @@ static int do_pd_setup(struct fs_enet_private *fep)
static int setup_data(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- const struct fs_platform_info *fpi = fep->fpi;
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
+ struct fs_platform_info *fpi = fep->fpi;
+
+ fpi->cp_command = (fpi->cp_page << 26) |
+ (fpi->cp_block << 21) |
+ (12 << 6);
fep->fcc.idx = fs_get_fcc_index(fpi->fs_no);
if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */
return -EINVAL;
+#endif
if (do_pd_setup(fep) != 0)
return -EINVAL;
@@ -180,7 +209,7 @@ static int allocate_bd(struct net_device *dev)
struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
- fep->ring_base = dma_alloc_coherent(fep->dev,
+ fep->ring_base = (void __iomem __force *)dma_alloc_coherent(fep->dev,
(fpi->tx_ring + fpi->rx_ring) *
sizeof(cbd_t), &fep->ring_mem_addr,
GFP_KERNEL);
@@ -198,7 +227,7 @@ static void free_bd(struct net_device *dev)
if (fep->ring_base)
dma_free_coherent(fep->dev,
(fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t),
- fep->ring_base, fep->ring_mem_addr);
+ (void __force *)fep->ring_base, fep->ring_mem_addr);
}
static void cleanup_data(struct net_device *dev)
@@ -209,7 +238,7 @@ static void cleanup_data(struct net_device *dev)
static void set_promiscuous_mode(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
S32(fccp, fcc_fpsmr, FCC_PSMR_PRO);
}
@@ -217,7 +246,7 @@ static void set_promiscuous_mode(struct net_device *dev)
static void set_multicast_start(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_enet_t *ep = fep->fcc.ep;
+ fcc_enet_t __iomem *ep = fep->fcc.ep;
W32(ep, fen_gaddrh, 0);
W32(ep, fen_gaddrl, 0);
@@ -226,7 +255,7 @@ static void set_multicast_start(struct net_device *dev)
static void set_multicast_one(struct net_device *dev, const u8 *mac)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_enet_t *ep = fep->fcc.ep;
+ fcc_enet_t __iomem *ep = fep->fcc.ep;
u16 taddrh, taddrm, taddrl;
taddrh = ((u16)mac[5] << 8) | mac[4];
@@ -236,14 +265,14 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac)
W16(ep, fen_taddrh, taddrh);
W16(ep, fen_taddrm, taddrm);
W16(ep, fen_taddrl, taddrl);
- fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR);
+ fcc_cr_cmd(fep, CPM_CR_SET_GADDR);
}
static void set_multicast_finish(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
- fcc_enet_t *ep = fep->fcc.ep;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
+ fcc_enet_t __iomem *ep = fep->fcc.ep;
/* clear promiscuous always */
C32(fccp, fcc_fpsmr, FCC_PSMR_PRO);
@@ -278,12 +307,14 @@ static void restart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
- fcc_t *fccp = fep->fcc.fccp;
- fcc_c_t *fcccp = fep->fcc.fcccp;
- fcc_enet_t *ep = fep->fcc.ep;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
+ fcc_c_t __iomem *fcccp = fep->fcc.fcccp;
+ fcc_enet_t __iomem *ep = fep->fcc.ep;
dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
u16 paddrh, paddrm, paddrl;
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
u16 mem_addr;
+#endif
const unsigned char *mac;
int i;
@@ -291,7 +322,7 @@ static void restart(struct net_device *dev)
/* clear everything (slow & steady does it) */
for (i = 0; i < sizeof(*ep); i++)
- __fcc_out8((char *)ep + i, 0);
+ out_8((u8 __iomem *)ep + i, 0);
/* get physical address */
rx_bd_base_phys = fep->ring_mem_addr;
@@ -315,14 +346,22 @@ static void restart(struct net_device *dev)
* this area.
*/
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ W16(ep, fen_genfcc.fcc_riptr, fpi->dpram_offset);
+ W16(ep, fen_genfcc.fcc_tiptr, fpi->dpram_offset + 32);
+
+ W16(ep, fen_padptr, fpi->dpram_offset + 64);
+#else
mem_addr = (u32) fep->fcc.mem; /* de-fixup dpram offset */
W16(ep, fen_genfcc.fcc_riptr, (mem_addr & 0xffff));
W16(ep, fen_genfcc.fcc_tiptr, ((mem_addr + 32) & 0xffff));
+
W16(ep, fen_padptr, mem_addr + 64);
+#endif
/* fill with special symbol... */
- memset(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32);
+ memset_io(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32);
W32(ep, fen_genfcc.fcc_rbptr, 0);
W32(ep, fen_genfcc.fcc_tbptr, 0);
@@ -407,7 +446,7 @@ static void restart(struct net_device *dev)
S8(fcccp, fcc_gfemr, 0x20);
}
- fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX);
+ fcc_cr_cmd(fep, CPM_CR_INIT_TRX);
/* clear events */
W16(fccp, fcc_fcce, 0xffff);
@@ -438,7 +477,7 @@ static void restart(struct net_device *dev)
static void stop(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
/* stop ethernet */
C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);
@@ -465,7 +504,7 @@ static void post_free_irq(struct net_device *dev, int irq)
static void napi_clear_rx_event(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK);
}
@@ -473,7 +512,7 @@ static void napi_clear_rx_event(struct net_device *dev)
static void napi_enable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK);
}
@@ -481,7 +520,7 @@ static void napi_enable_rx(struct net_device *dev)
static void napi_disable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK);
}
@@ -494,15 +533,15 @@ static void rx_bd_done(struct net_device *dev)
static void tx_kickstart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
- S32(fccp, fcc_ftodr, 0x80);
+ S16(fccp, fcc_ftodr, 0x8000);
}
static u32 get_int_events(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
return (u32)R16(fccp, fcc_fcce);
}
@@ -510,7 +549,7 @@ static u32 get_int_events(struct net_device *dev)
static void clear_int_events(struct net_device *dev, u32 int_events)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
W16(fccp, fcc_fcce, int_events & 0xffff);
}
@@ -521,47 +560,46 @@ static void ev_error(struct net_device *dev, u32 int_events)
": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events);
}
-int get_regs(struct net_device *dev, void *p, int *sizep)
+static int get_regs(struct net_device *dev, void *p, int *sizep)
{
struct fs_enet_private *fep = netdev_priv(dev);
- if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t))
+ if (*sizep < sizeof(fcc_t) + sizeof(fcc_enet_t) + 1)
return -EINVAL;
memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t));
p = (char *)p + sizeof(fcc_t);
- memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t));
- p = (char *)p + sizeof(fcc_c_t);
-
memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t));
+ p = (char *)p + sizeof(fcc_enet_t);
+ memcpy_fromio(p, fep->fcc.fcccp, 1);
return 0;
}
-int get_regs_len(struct net_device *dev)
+static int get_regs_len(struct net_device *dev)
{
- return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t);
+ return sizeof(fcc_t) + sizeof(fcc_enet_t) + 1;
}
/* Some transmit errors cause the transmitter to shut
* down. We now issue a restart transmit. Since the
* errors close the BD and update the pointers, the restart
* _should_ pick up without having to reset any of our
- * pointers either. Also, To workaround 8260 device erratum
+ * pointers either. Also, To workaround 8260 device erratum
* CPM37, we must disable and then re-enable the transmitter
* following a Late Collision, Underrun, or Retry Limit error.
*/
-void tx_restart(struct net_device *dev)
+static void tx_restart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fcc_t *fccp = fep->fcc.fccp;
+ fcc_t __iomem *fccp = fep->fcc.fccp;
C32(fccp, fcc_gfmr, FCC_GFMR_ENT);
udelay(10);
S32(fccp, fcc_gfmr, FCC_GFMR_ENT);
- fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX);
+ fcc_cr_cmd(fep, CPM_CR_RESTART_TX);
}
/*************************************************************************/
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 04b4f80a1cd..c1fee48517e 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -1,14 +1,14 @@
/*
* Freescale Ethernet controllers
*
- * Copyright (c) 2005 Intracom S.A.
+ * Copyright (c) 2005 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
*
- * 2005 (c) MontaVista Software, Inc.
+ * 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
@@ -43,6 +43,10 @@
#include <asm/commproc.h>
#endif
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_device.h>
+#endif
+
#include "fs_enet.h"
#include "fec.h"
@@ -79,7 +83,7 @@
*/
#define FEC_RESET_DELAY 50
-static int whack_reset(fec_t * fecp)
+static int whack_reset(fec_t __iomem *fecp)
{
int i;
@@ -95,9 +99,22 @@ static int whack_reset(fec_t * fecp)
static int do_pd_setup(struct fs_enet_private *fep)
{
- struct platform_device *pdev = to_platform_device(fep->dev);
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct of_device *ofdev = to_of_device(fep->dev);
+
+ fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (fep->interrupt == NO_IRQ)
+ return -EINVAL;
+
+ fep->fec.fecp = of_iomap(ofdev->node, 0);
+ if (!fep->fcc.fccp)
+ return -EINVAL;
+
+ return 0;
+#else
+ struct platform_device *pdev = to_platform_device(fep->dev);
struct resource *r;
-
+
/* Fill out IRQ field */
fep->interrupt = platform_get_irq_byname(pdev,"interrupt");
if (fep->interrupt < 0)
@@ -110,7 +127,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
return -EINVAL;
return 0;
-
+#endif
}
#define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB)
@@ -141,8 +158,8 @@ static int allocate_bd(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
-
- fep->ring_base = dma_alloc_coherent(fep->dev,
+
+ fep->ring_base = (void __force __iomem *)dma_alloc_coherent(fep->dev,
(fpi->tx_ring + fpi->rx_ring) *
sizeof(cbd_t), &fep->ring_mem_addr,
GFP_KERNEL);
@@ -160,7 +177,7 @@ static void free_bd(struct net_device *dev)
if(fep->ring_base)
dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring)
* sizeof(cbd_t),
- fep->ring_base,
+ (void __force *)fep->ring_base,
fep->ring_mem_addr);
}
@@ -172,7 +189,7 @@ static void cleanup_data(struct net_device *dev)
static void set_promiscuous_mode(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FS(fecp, r_cntrl, FEC_RCNTRL_PROM);
}
@@ -220,7 +237,7 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac)
static void set_multicast_finish(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
/* if all multi or too many multicasts; just enable all */
if ((dev->flags & IFF_ALLMULTI) != 0 ||
@@ -254,7 +271,7 @@ static void restart(struct net_device *dev)
u32 cptr;
#endif
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
const struct fs_platform_info *fpi = fep->fpi;
dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
int r;
@@ -280,13 +297,13 @@ static void restart(struct net_device *dev)
FW(fecp, addr_high, addrlo);
/*
- * Reset all multicast.
+ * Reset all multicast.
*/
FW(fecp, hash_table_high, fep->fec.hthi);
FW(fecp, hash_table_low, fep->fec.htlo);
/*
- * Set maximum receive buffer size.
+ * Set maximum receive buffer size.
*/
FW(fecp, r_buff_size, PKT_MAXBLR_SIZE);
FW(fecp, r_hash, PKT_MAXBUF_SIZE);
@@ -296,7 +313,7 @@ static void restart(struct net_device *dev)
tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring;
/*
- * Set receive and transmit descriptor base.
+ * Set receive and transmit descriptor base.
*/
FW(fecp, r_des_start, rx_bd_base_phys);
FW(fecp, x_des_start, tx_bd_base_phys);
@@ -304,7 +321,7 @@ static void restart(struct net_device *dev)
fs_init_bds(dev);
/*
- * Enable big endian and don't care about SDMA FC.
+ * Enable big endian and don't care about SDMA FC.
*/
FW(fecp, fun_code, 0x78000000);
@@ -366,13 +383,13 @@ static void restart(struct net_device *dev)
}
/*
- * Enable interrupts we wish to service.
+ * Enable interrupts we wish to service.
*/
FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB |
FEC_ENET_RXF | FEC_ENET_RXB);
/*
- * And last, enable the transmit and receive processing.
+ * And last, enable the transmit and receive processing.
*/
FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
FW(fecp, r_des_active, 0x01000000);
@@ -382,7 +399,7 @@ static void stop(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
const struct fs_platform_info *fpi = fep->fpi;
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
struct fec_info* feci= fep->phydev->bus->priv;
@@ -401,7 +418,7 @@ static void stop(struct net_device *dev)
": %s FEC timeout on graceful transmit stop\n",
dev->name);
/*
- * Disable FEC. Let only MII interrupts.
+ * Disable FEC. Let only MII interrupts.
*/
FW(fecp, imask, 0);
FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN);
@@ -444,7 +461,7 @@ static void post_free_irq(struct net_device *dev, int irq)
static void napi_clear_rx_event(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK);
}
@@ -452,7 +469,7 @@ static void napi_clear_rx_event(struct net_device *dev)
static void napi_enable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
}
@@ -460,7 +477,7 @@ static void napi_enable_rx(struct net_device *dev)
static void napi_disable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
}
@@ -468,7 +485,7 @@ static void napi_disable_rx(struct net_device *dev)
static void rx_bd_done(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FW(fecp, r_des_active, 0x01000000);
}
@@ -476,7 +493,7 @@ static void rx_bd_done(struct net_device *dev)
static void tx_kickstart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FW(fecp, x_des_active, 0x01000000);
}
@@ -484,7 +501,7 @@ static void tx_kickstart(struct net_device *dev)
static u32 get_int_events(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
return FR(fecp, ievent) & FR(fecp, imask);
}
@@ -492,7 +509,7 @@ static u32 get_int_events(struct net_device *dev)
static void clear_int_events(struct net_device *dev, u32 int_events)
{
struct fs_enet_private *fep = netdev_priv(dev);
- fec_t *fecp = fep->fec.fecp;
+ fec_t __iomem *fecp = fep->fec.fecp;
FW(fecp, ievent, int_events);
}
@@ -503,7 +520,7 @@ static void ev_error(struct net_device *dev, u32 int_events)
": %s FEC ERROR(s) 0x%x\n", dev->name, int_events);
}
-int get_regs(struct net_device *dev, void *p, int *sizep)
+static int get_regs(struct net_device *dev, void *p, int *sizep)
{
struct fs_enet_private *fep = netdev_priv(dev);
@@ -515,12 +532,12 @@ int get_regs(struct net_device *dev, void *p, int *sizep)
return 0;
}
-int get_regs_len(struct net_device *dev)
+static int get_regs_len(struct net_device *dev)
{
return sizeof(fec_t);
}
-void tx_restart(struct net_device *dev)
+static void tx_restart(struct net_device *dev)
{
/* nothing */
}
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index 7540966687e..03134f47a4e 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -1,14 +1,14 @@
/*
* Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx.
*
- * Copyright (c) 2003 Intracom S.A.
+ * Copyright (c) 2003 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
- *
- * 2005 (c) MontaVista Software, Inc.
+ *
+ * 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
@@ -43,6 +43,10 @@
#include <asm/commproc.h>
#endif
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_platform.h>
+#endif
+
#include "fs_enet.h"
/*************************************************/
@@ -82,34 +86,45 @@
#define SCC_MAX_MULTICAST_ADDRS 64
/*
- * Delay to wait for SCC reset command to complete (in us)
+ * Delay to wait for SCC reset command to complete (in us)
*/
#define SCC_RESET_DELAY 50
#define MAX_CR_CMD_LOOPS 10000
static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op)
{
- cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm;
- u32 v, ch;
- int i = 0;
+ const struct fs_platform_info *fpi = fep->fpi;
+ int i;
- ch = fep->scc.idx << 2;
- v = mk_cr_cmd(ch, op);
- W16(cpmp, cp_cpcr, v | CPM_CR_FLG);
+ W16(cpmp, cp_cpcr, fpi->cp_command | CPM_CR_FLG | (op << 8));
for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
- break;
+ return 0;
- if (i >= MAX_CR_CMD_LOOPS) {
- printk(KERN_ERR "%s(): Not able to issue CPM command\n",
- __FUNCTION__);
- return 1;
- }
- return 0;
+ printk(KERN_ERR "%s(): Not able to issue CPM command\n",
+ __FUNCTION__);
+ return 1;
}
static int do_pd_setup(struct fs_enet_private *fep)
{
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct of_device *ofdev = to_of_device(fep->dev);
+
+ fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (fep->interrupt == NO_IRQ)
+ return -EINVAL;
+
+ fep->scc.sccp = of_iomap(ofdev->node, 0);
+ if (!fep->scc.sccp)
+ return -EINVAL;
+
+ fep->scc.ep = of_iomap(ofdev->node, 1);
+ if (!fep->scc.ep) {
+ iounmap(fep->scc.sccp);
+ return -EINVAL;
+ }
+#else
struct platform_device *pdev = to_platform_device(fep->dev);
struct resource *r;
@@ -129,6 +144,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
if (fep->scc.ep == NULL)
return -EINVAL;
+#endif
return 0;
}
@@ -141,12 +157,17 @@ static int do_pd_setup(struct fs_enet_private *fep)
static int setup_data(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- const struct fs_platform_info *fpi = fep->fpi;
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct fs_platform_info *fpi = fep->fpi;
fep->scc.idx = fs_get_scc_index(fpi->fs_no);
- if ((unsigned int)fep->fcc.idx > 4) /* max 4 SCCs */
+ if ((unsigned int)fep->fcc.idx >= 4) /* max 4 SCCs */
return -EINVAL;
+ fpi->cp_command = fep->fcc.idx << 6;
+#endif
+
do_pd_setup(fep);
fep->scc.hthi = 0;
@@ -154,7 +175,7 @@ static int setup_data(struct net_device *dev)
fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK;
fep->ev_rx = SCC_RX_EVENT;
- fep->ev_tx = SCC_TX_EVENT;
+ fep->ev_tx = SCC_TX_EVENT | SCCE_ENET_TXE;
fep->ev_err = SCC_ERR_EVENT_MSK;
return 0;
@@ -170,7 +191,8 @@ static int allocate_bd(struct net_device *dev)
if (IS_ERR_VALUE(fep->ring_mem_addr))
return -ENOMEM;
- fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr);
+ fep->ring_base = (void __iomem __force*)
+ cpm_dpram_addr(fep->ring_mem_addr);
return 0;
}
@@ -189,9 +211,9 @@ static void cleanup_data(struct net_device *dev)
}
static void set_promiscuous_mode(struct net_device *dev)
-{
+{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
S16(sccp, scc_psmr, SCC_PSMR_PRO);
}
@@ -199,7 +221,7 @@ static void set_promiscuous_mode(struct net_device *dev)
static void set_multicast_start(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_enet_t *ep = fep->scc.ep;
+ scc_enet_t __iomem *ep = fep->scc.ep;
W16(ep, sen_gaddr1, 0);
W16(ep, sen_gaddr2, 0);
@@ -210,7 +232,7 @@ static void set_multicast_start(struct net_device *dev)
static void set_multicast_one(struct net_device *dev, const u8 * mac)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_enet_t *ep = fep->scc.ep;
+ scc_enet_t __iomem *ep = fep->scc.ep;
u16 taddrh, taddrm, taddrl;
taddrh = ((u16) mac[5] << 8) | mac[4];
@@ -226,8 +248,8 @@ static void set_multicast_one(struct net_device *dev, const u8 * mac)
static void set_multicast_finish(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
- scc_enet_t *ep = fep->scc.ep;
+ scc_t __iomem *sccp = fep->scc.sccp;
+ scc_enet_t __iomem *ep = fep->scc.ep;
/* clear promiscuous always */
C16(sccp, scc_psmr, SCC_PSMR_PRO);
@@ -264,8 +286,8 @@ static void set_multicast_list(struct net_device *dev)
static void restart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
- scc_enet_t *ep = fep->scc.ep;
+ scc_t __iomem *sccp = fep->scc.sccp;
+ scc_enet_t __iomem *ep = fep->scc.ep;
const struct fs_platform_info *fpi = fep->fpi;
u16 paddrh, paddrm, paddrl;
const unsigned char *mac;
@@ -275,7 +297,7 @@ static void restart(struct net_device *dev)
/* clear everything (slow & steady does it) */
for (i = 0; i < sizeof(*ep); i++)
- __fs_out8((char *)ep + i, 0);
+ __fs_out8((u8 __iomem *)ep + i, 0);
/* point to bds */
W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr);
@@ -323,7 +345,7 @@ static void restart(struct net_device *dev)
W16(ep, sen_iaddr3, 0);
W16(ep, sen_iaddr4, 0);
- /* set address
+ /* set address
*/
mac = dev->dev_addr;
paddrh = ((u16) mac[5] << 8) | mac[4];
@@ -345,7 +367,7 @@ static void restart(struct net_device *dev)
W16(sccp, scc_scce, 0xffff);
- /* Enable interrupts we wish to service.
+ /* Enable interrupts we wish to service.
*/
W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB);
@@ -373,10 +395,10 @@ static void restart(struct net_device *dev)
S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
-static void stop(struct net_device *dev)
+static void stop(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
int i;
for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++)
@@ -420,7 +442,7 @@ static void post_free_irq(struct net_device *dev, int irq)
static void napi_clear_rx_event(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK);
}
@@ -428,7 +450,7 @@ static void napi_clear_rx_event(struct net_device *dev)
static void napi_enable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK);
}
@@ -436,7 +458,7 @@ static void napi_enable_rx(struct net_device *dev)
static void napi_disable_rx(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK);
}
@@ -454,7 +476,7 @@ static void tx_kickstart(struct net_device *dev)
static u32 get_int_events(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
return (u32) R16(sccp, scc_scce);
}
@@ -462,7 +484,7 @@ static u32 get_int_events(struct net_device *dev)
static void clear_int_events(struct net_device *dev, u32 int_events)
{
struct fs_enet_private *fep = netdev_priv(dev);
- scc_t *sccp = fep->scc.sccp;
+ scc_t __iomem *sccp = fep->scc.sccp;
W16(sccp, scc_scce, int_events & 0xffff);
}
@@ -477,20 +499,20 @@ static int get_regs(struct net_device *dev, void *p, int *sizep)
{
struct fs_enet_private *fep = netdev_priv(dev);
- if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t))
+ if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t __iomem *))
return -EINVAL;
memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t));
p = (char *)p + sizeof(scc_t);
- memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t));
+ memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t __iomem *));
return 0;
}
static int get_regs_len(struct net_device *dev)
{
- return sizeof(scc_t) + sizeof(scc_enet_t);
+ return sizeof(scc_t) + sizeof(scc_enet_t __iomem *);
}
static void tx_restart(struct net_device *dev)
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index d3840108ffb..b8e4a736a13 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -1,314 +1,288 @@
/*
* Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
*
- * Copyright (c) 2003 Intracom S.A.
+ * Copyright (c) 2003 Intracom S.A.
* by Pantelis Antoniou <panto@intracom.gr>
- *
- * 2005 (c) MontaVista Software, Inc.
+ *
+ * 2005 (c) MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
*
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
-
#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
-#include <linux/interrupt.h>
#include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
#include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/bitops.h>
#include <linux/platform_device.h>
+#include <linux/mdio-bitbang.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
#include "fs_enet.h"
-static int bitbang_prep_bit(u8 **datp, u8 *mskp,
- struct fs_mii_bit *mii_bit)
-{
- void *dat;
- int adv;
- u8 msk;
-
- dat = (void*) mii_bit->offset;
-
- adv = mii_bit->bit >> 3;
- dat = (char *)dat + adv;
-
- msk = 1 << (7 - (mii_bit->bit & 7));
-
- *datp = dat;
- *mskp = msk;
-
- return 0;
-}
+struct bb_info {
+ struct mdiobb_ctrl ctrl;
+ __be32 __iomem *dir;
+ __be32 __iomem *dat;
+ u32 mdio_msk;
+ u32 mdc_msk;
+};
-static inline void bb_set(u8 *p, u8 m)
+/* FIXME: If any other users of GPIO crop up, then these will have to
+ * have some sort of global synchronization to avoid races with other
+ * pins on the same port. The ideal solution would probably be to
+ * bind the ports to a GPIO driver, and have this be a client of it.
+ */
+static inline void bb_set(u32 __iomem *p, u32 m)
{
- out_8(p, in_8(p) | m);
+ out_be32(p, in_be32(p) | m);
}
-static inline void bb_clr(u8 *p, u8 m)
+static inline void bb_clr(u32 __iomem *p, u32 m)
{
- out_8(p, in_8(p) & ~m);
+ out_be32(p, in_be32(p) & ~m);
}
-static inline int bb_read(u8 *p, u8 m)
+static inline int bb_read(u32 __iomem *p, u32 m)
{
- return (in_8(p) & m) != 0;
+ return (in_be32(p) & m) != 0;
}
-static inline void mdio_active(struct bb_info *bitbang)
+static inline void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
{
- bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk);
-}
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
-static inline void mdio_tristate(struct bb_info *bitbang )
-{
- bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk);
+ if (dir)
+ bb_set(bitbang->dir, bitbang->mdio_msk);
+ else
+ bb_clr(bitbang->dir, bitbang->mdio_msk);
+
+ /* Read back to flush the write. */
+ in_be32(bitbang->dir);
}
-static inline int mdio_read(struct bb_info *bitbang )
+static inline int mdio_read(struct mdiobb_ctrl *ctrl)
{
- return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk);
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+ return bb_read(bitbang->dat, bitbang->mdio_msk);
}
-static inline void mdio(struct bb_info *bitbang , int what)
+static inline void mdio(struct mdiobb_ctrl *ctrl, int what)
{
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+
if (what)
- bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk);
+ bb_set(bitbang->dat, bitbang->mdio_msk);
else
- bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk);
+ bb_clr(bitbang->dat, bitbang->mdio_msk);
+
+ /* Read back to flush the write. */
+ in_be32(bitbang->dat);
}
-static inline void mdc(struct bb_info *bitbang , int what)
+static inline void mdc(struct mdiobb_ctrl *ctrl, int what)
{
+ struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+
if (what)
- bb_set(bitbang->mdc_dat, bitbang->mdc_msk);
+ bb_set(bitbang->dat, bitbang->mdc_msk);
else
- bb_clr(bitbang->mdc_dat, bitbang->mdc_msk);
+ bb_clr(bitbang->dat, bitbang->mdc_msk);
+
+ /* Read back to flush the write. */
+ in_be32(bitbang->dat);
}
-static inline void mii_delay(struct bb_info *bitbang )
+static struct mdiobb_ops bb_ops = {
+ .owner = THIS_MODULE,
+ .set_mdc = mdc,
+ .set_mdio_dir = mdio_dir,
+ .set_mdio_data = mdio,
+ .get_mdio_data = mdio_read,
+};
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static int __devinit fs_mii_bitbang_init(struct mii_bus *bus,
+ struct device_node *np)
{
- udelay(bitbang->delay);
+ struct resource res;
+ const u32 *data;
+ int mdio_pin, mdc_pin, len;
+ struct bb_info *bitbang = bus->priv;
+
+ int ret = of_address_to_resource(np, 0, &res);
+ if (ret)
+ return ret;
+
+ if (res.end - res.start < 13)
+ return -ENODEV;
+
+ /* This should really encode the pin number as well, but all
+ * we get is an int, and the odds of multiple bitbang mdio buses
+ * is low enough that it's not worth going too crazy.
+ */
+ bus->id = res.start;
+
+ data = of_get_property(np, "fsl,mdio-pin", &len);
+ if (!data || len != 4)
+ return -ENODEV;
+ mdio_pin = *data;
+
+ data = of_get_property(np, "fsl,mdc-pin", &len);
+ if (!data || len != 4)
+ return -ENODEV;
+ mdc_pin = *data;
+
+ bitbang->dir = ioremap(res.start, res.end - res.start + 1);
+ if (!bitbang->dir)
+ return -ENOMEM;
+
+ bitbang->dat = bitbang->dir + 4;
+ bitbang->mdio_msk = 1 << (31 - mdio_pin);
+ bitbang->mdc_msk = 1 << (31 - mdc_pin);
+
+ return 0;
}
-/* Utility to send the preamble, address, and register (common to read and write). */
-static void bitbang_pre(struct bb_info *bitbang , int read, u8 addr, u8 reg)
+static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
{
- int j;
-
- /*
- * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
- * The IEEE spec says this is a PHY optional requirement. The AMD
- * 79C874 requires one after power up and one after a MII communications
- * error. This means that we are doing more preambles than we need,
- * but it is safer and will be much more robust.
- */
+ const u32 *data;
+ int len, id, irq;
- mdio_active(bitbang);
- mdio(bitbang, 1);
- for (j = 0; j < 32; j++) {
- mdc(bitbang, 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- }
+ data = of_get_property(np, "reg", &len);
+ if (!data || len != 4)
+ return;
- /* send the start bit (01) and the read opcode (10) or write (10) */
- mdc(bitbang, 0);
- mdio(bitbang, 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 0);
- mdio(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 0);
- mdio(bitbang, read);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 0);
- mdio(bitbang, !read);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
-
- /* send the PHY address */
- for (j = 0; j < 5; j++) {
- mdc(bitbang, 0);
- mdio(bitbang, (addr & 0x10) != 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- addr <<= 1;
- }
+ id = *data;
+ bus->phy_mask &= ~(1 << id);
- /* send the register address */
- for (j = 0; j < 5; j++) {
- mdc(bitbang, 0);
- mdio(bitbang, (reg & 0x10) != 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- reg <<= 1;
- }
+ irq = of_irq_to_resource(np, 0, NULL);
+ if (irq != NO_IRQ)
+ bus->irq[id] = irq;
}
-static int fs_enet_mii_bb_read(struct mii_bus *bus , int phy_id, int location)
+static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
{
- u16 rdreg;
- int ret, j;
- u8 addr = phy_id & 0xff;
- u8 reg = location & 0xff;
- struct bb_info* bitbang = bus->priv;
-
- bitbang_pre(bitbang, 1, addr, reg);
-
- /* tri-state our MDIO I/O pin so we can read */
- mdc(bitbang, 0);
- mdio_tristate(bitbang);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
-
- /* check the turnaround bit: the PHY should be driving it to zero */
- if (mdio_read(bitbang) != 0) {
- /* PHY didn't drive TA low */
- for (j = 0; j < 32; j++) {
- mdc(bitbang, 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- }
- ret = -1;
+ struct device_node *np = NULL;
+ struct mii_bus *new_bus;
+ struct bb_info *bitbang;
+ int ret = -ENOMEM;
+ int i;
+
+ bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
+ if (!bitbang)
goto out;
- }
- mdc(bitbang, 0);
- mii_delay(bitbang);
-
- /* read 16 bits of register data, MSB first */
- rdreg = 0;
- for (j = 0; j < 16; j++) {
- mdc(bitbang, 1);
- mii_delay(bitbang);
- rdreg <<= 1;
- rdreg |= mdio_read(bitbang);
- mdc(bitbang, 0);
- mii_delay(bitbang);
- }
+ bitbang->ctrl.ops = &bb_ops;
+
+ new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
+ if (!new_bus)
+ goto out_free_priv;
+
+ new_bus->name = "CPM2 Bitbanged MII",
+
+ ret = fs_mii_bitbang_init(new_bus, ofdev->node);
+ if (ret)
+ goto out_free_bus;
+
+ new_bus->phy_mask = ~0;
+ new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!new_bus->irq)
+ goto out_unmap_regs;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ new_bus->irq[i] = -1;
+
+ while ((np = of_get_next_child(ofdev->node, np)))
+ if (!strcmp(np->type, "ethernet-phy"))
+ add_phy(new_bus, np);
+
+ new_bus->dev = &ofdev->dev;
+ dev_set_drvdata(&ofdev->dev, new_bus);
+
+ ret = mdiobus_register(new_bus);
+ if (ret)
+ goto out_free_irqs;
- mdc(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
+ return 0;
- ret = rdreg;
+out_free_irqs:
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(new_bus->irq);
+out_unmap_regs:
+ iounmap(bitbang->dir);
+out_free_bus:
+ kfree(new_bus);
+out_free_priv:
+ free_mdio_bitbang(new_bus);
out:
return ret;
}
-static int fs_enet_mii_bb_write(struct mii_bus *bus, int phy_id, int location, u16 val)
+static int fs_enet_mdio_remove(struct of_device *ofdev)
{
- int j;
- struct bb_info* bitbang = bus->priv;
-
- u8 addr = phy_id & 0xff;
- u8 reg = location & 0xff;
- u16 value = val & 0xffff;
-
- bitbang_pre(bitbang, 0, addr, reg);
-
- /* send the turnaround (10) */
- mdc(bitbang, 0);
- mdio(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- mdc(bitbang, 0);
- mdio(bitbang, 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
-
- /* write 16 bits of register data, MSB first */
- for (j = 0; j < 16; j++) {
- mdc(bitbang, 0);
- mdio(bitbang, (value & 0x8000) != 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- value <<= 1;
- }
+ struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct bb_info *bitbang = bus->priv;
- /*
- * Tri-state the MDIO line.
- */
- mdio_tristate(bitbang);
- mdc(bitbang, 0);
- mii_delay(bitbang);
- mdc(bitbang, 1);
- mii_delay(bitbang);
- return 0;
-}
+ mdiobus_unregister(bus);
+ free_mdio_bitbang(bus);
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(bus->irq);
+ iounmap(bitbang->dir);
+ kfree(bitbang);
+ kfree(bus);
-static int fs_enet_mii_bb_reset(struct mii_bus *bus)
-{
- /*nothing here - dunno how to reset it*/
return 0;
}
-static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi)
-{
- int r;
+static struct of_device_id fs_enet_mdio_bb_match[] = {
+ {
+ .compatible = "fsl,cpm2-mdio-bitbang",
+ },
+ {},
+};
- bitbang->delay = fmpi->delay;
+static struct of_platform_driver fs_enet_bb_mdio_driver = {
+ .name = "fsl-bb-mdio",
+ .match_table = fs_enet_mdio_bb_match,
+ .probe = fs_enet_mdio_probe,
+ .remove = fs_enet_mdio_remove,
+};
- r = bitbang_prep_bit(&bitbang->mdio_dir,
- &bitbang->mdio_dir_msk,
- &fmpi->mdio_dir);
- if (r != 0)
- return r;
+static int fs_enet_mdio_bb_init(void)
+{
+ return of_register_platform_driver(&fs_enet_bb_mdio_driver);
+}
- r = bitbang_prep_bit(&bitbang->mdio_dat,
- &bitbang->mdio_dat_msk,
- &fmpi->mdio_dat);
- if (r != 0)
- return r;
+static void fs_enet_mdio_bb_exit(void)
+{
+ of_unregister_platform_driver(&fs_enet_bb_mdio_driver);
+}
- r = bitbang_prep_bit(&bitbang->mdc_dat,
- &bitbang->mdc_msk,
- &fmpi->mdc_dat);
- if (r != 0)
- return r;
+module_init(fs_enet_mdio_bb_init);
+module_exit(fs_enet_mdio_bb_exit);
+#else
+static int __devinit fs_mii_bitbang_init(struct bb_info *bitbang,
+ struct fs_mii_bb_platform_info *fmpi)
+{
+ bitbang->dir = (u32 __iomem *)fmpi->mdio_dir.offset;
+ bitbang->dat = (u32 __iomem *)fmpi->mdio_dat.offset;
+ bitbang->mdio_msk = 1U << (31 - fmpi->mdio_dat.bit);
+ bitbang->mdc_msk = 1U << (31 - fmpi->mdc_dat.bit);
return 0;
}
-
static int __devinit fs_enet_mdio_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -320,20 +294,19 @@ static int __devinit fs_enet_mdio_probe(struct device *dev)
if (NULL == dev)
return -EINVAL;
- new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+ bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
- if (NULL == new_bus)
+ if (NULL == bitbang)
return -ENOMEM;
- bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
+ bitbang->ctrl.ops = &bb_ops;
- if (NULL == bitbang)
+ new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
+
+ if (NULL == new_bus)
return -ENOMEM;
new_bus->name = "BB MII Bus",
- new_bus->read = &fs_enet_mii_bb_read,
- new_bus->write = &fs_enet_mii_bb_write,
- new_bus->reset = &fs_enet_mii_bb_reset,
new_bus->id = pdev->id;
new_bus->phy_mask = ~0x9;
@@ -365,13 +338,12 @@ static int __devinit fs_enet_mdio_probe(struct device *dev)
return 0;
bus_register_fail:
+ free_mdio_bitbang(new_bus);
kfree(bitbang);
- kfree(new_bus);
return err;
}
-
static int fs_enet_mdio_remove(struct device *dev)
{
struct mii_bus *bus = dev_get_drvdata(dev);
@@ -380,9 +352,7 @@ static int fs_enet_mdio_remove(struct device *dev)
dev_set_drvdata(dev, NULL);
- iounmap((void *) (&bus->priv));
- bus->priv = NULL;
- kfree(bus);
+ free_mdio_bitbang(bus);
return 0;
}
@@ -403,4 +373,4 @@ void fs_enet_mdio_bb_exit(void)
{
driver_unregister(&fs_enet_bb_mdio_driver);
}
-
+#endif
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 0a563a83016..a89cf15090b 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -36,6 +36,10 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_platform.h>
+#endif
+
#include "fs_enet.h"
#include "fec.h"
@@ -47,6 +51,7 @@
#define FEC_MII_LOOPS 10000
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
static int match_has_phy (struct device *dev, void* data)
{
struct platform_device* pdev = container_of(dev, struct platform_device, dev);
@@ -65,7 +70,7 @@ static int match_has_phy (struct device *dev, void* data)
static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info *fmpi)
{
struct resource *r;
- fec_t *fecp;
+ fec_t __iomem *fecp;
char* name = "fsl-cpm-fec";
/* we need fec in order to be useful */
@@ -80,7 +85,7 @@ static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info
r = platform_get_resource_byname(fec_pdev, IORESOURCE_MEM, "regs");
- fec->fecp = fecp = (fec_t*)ioremap(r->start,sizeof(fec_t));
+ fec->fecp = fecp = ioremap(r->start,sizeof(fec_t));
fec->mii_speed = fmpi->mii_speed;
setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
@@ -90,11 +95,12 @@ static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info
return 0;
}
+#endif
static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
{
struct fec_info* fec = bus->priv;
- fec_t *fecp = fec->fecp;
+ fec_t __iomem *fecp = fec->fecp;
int i, ret = -1;
if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
@@ -113,13 +119,12 @@ static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
}
return ret;
-
}
static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val)
{
struct fec_info* fec = bus->priv;
- fec_t *fecp = fec->fecp;
+ fec_t __iomem *fecp = fec->fecp;
int i;
/* this must never happen */
@@ -146,6 +151,141 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus)
return 0;
}
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
+{
+ const u32 *data;
+ int len, id, irq;
+
+ data = of_get_property(np, "reg", &len);
+ if (!data || len != 4)
+ return;
+
+ id = *data;
+ bus->phy_mask &= ~(1 << id);
+
+ irq = of_irq_to_resource(np, 0, NULL);
+ if (irq != NO_IRQ)
+ bus->irq[id] = irq;
+}
+
+static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = NULL;
+ struct resource res;
+ struct mii_bus *new_bus;
+ struct fec_info *fec;
+ int ret = -ENOMEM, i;
+
+ new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+ if (!new_bus)
+ goto out;
+
+ fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL);
+ if (!fec)
+ goto out_mii;
+
+ new_bus->priv = fec;
+ new_bus->name = "FEC MII Bus";
+ new_bus->read = &fs_enet_fec_mii_read;
+ new_bus->write = &fs_enet_fec_mii_write;
+ new_bus->reset = &fs_enet_fec_mii_reset;
+
+ ret = of_address_to_resource(ofdev->node, 0, &res);
+ if (ret)
+ return ret;
+
+ new_bus->id = res.start;
+
+ fec->fecp = ioremap(res.start, res.end - res.start + 1);
+ if (!fec->fecp)
+ goto out_fec;
+
+ fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1;
+
+ setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
+ setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX |
+ FEC_ECNTRL_ETHER_EN);
+ out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII);
+ out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed);
+
+ new_bus->phy_mask = ~0;
+ new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!new_bus->irq)
+ goto out_unmap_regs;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ new_bus->irq[i] = -1;
+
+ while ((np = of_get_next_child(ofdev->node, np)))
+ if (!strcmp(np->type, "ethernet-phy"))
+ add_phy(new_bus, np);
+
+ new_bus->dev = &ofdev->dev;
+ dev_set_drvdata(&ofdev->dev, new_bus);
+
+ ret = mdiobus_register(new_bus);
+ if (ret)
+ goto out_free_irqs;
+
+ return 0;
+
+out_free_irqs:
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(new_bus->irq);
+out_unmap_regs:
+ iounmap(fec->fecp);
+out_fec:
+ kfree(fec);
+out_mii:
+ kfree(new_bus);
+out:
+ return ret;
+}
+
+static int fs_enet_mdio_remove(struct of_device *ofdev)
+{
+ struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct fec_info *fec = bus->priv;
+
+ mdiobus_unregister(bus);
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(bus->irq);
+ iounmap(fec->fecp);
+ kfree(fec);
+ kfree(bus);
+
+ return 0;
+}
+
+static struct of_device_id fs_enet_mdio_fec_match[] = {
+ {
+ .compatible = "fsl,pq1-fec-mdio",
+ },
+ {},
+};
+
+static struct of_platform_driver fs_enet_fec_mdio_driver = {
+ .name = "fsl-fec-mdio",
+ .match_table = fs_enet_mdio_fec_match,
+ .probe = fs_enet_mdio_probe,
+ .remove = fs_enet_mdio_remove,
+};
+
+static int fs_enet_mdio_fec_init(void)
+{
+ return of_register_platform_driver(&fs_enet_fec_mdio_driver);
+}
+
+static void fs_enet_mdio_fec_exit(void)
+{
+ of_unregister_platform_driver(&fs_enet_fec_mdio_driver);
+}
+
+module_init(fs_enet_mdio_fec_init);
+module_exit(fs_enet_mdio_fec_exit);
+#else
static int __devinit fs_enet_fec_mdio_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -236,4 +376,4 @@ void fs_enet_mdio_fec_exit(void)
{
driver_unregister(&fs_enet_fec_mdio_driver);
}
-
+#endif
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index f92690555dd..38268d7335a 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -116,7 +116,6 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void gfar_timeout(struct net_device *dev);
static int gfar_close(struct net_device *dev);
struct sk_buff *gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp);
-static struct net_device_stats *gfar_get_stats(struct net_device *dev);
static int gfar_set_mac_address(struct net_device *dev);
static int gfar_change_mtu(struct net_device *dev, int new_mtu);
static irqreturn_t gfar_error(int irq, void *dev_id);
@@ -134,7 +133,7 @@ static void gfar_configure_serdes(struct net_device *dev);
extern int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, int regnum, u16 value);
extern int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum);
#ifdef CONFIG_GFAR_NAPI
-static int gfar_poll(struct net_device *dev, int *budget);
+static int gfar_poll(struct napi_struct *napi, int budget);
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
static void gfar_netpoll(struct net_device *dev);
@@ -169,8 +168,8 @@ static int gfar_probe(struct platform_device *pdev)
struct gfar_private *priv = NULL;
struct gianfar_platform_data *einfo;
struct resource *r;
- int idx;
int err = 0;
+ DECLARE_MAC_BUF(mac);
einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
@@ -188,6 +187,7 @@ static int gfar_probe(struct platform_device *pdev)
return -ENOMEM;
priv = netdev_priv(dev);
+ priv->dev = dev;
/* Set the info in the priv to the current info */
priv->einfo = einfo;
@@ -253,7 +253,6 @@ static int gfar_probe(struct platform_device *pdev)
/* Set the dev->base_addr to the gfar reg region */
dev->base_addr = (unsigned long) (priv->regs);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/* Fill in the dev structure */
@@ -262,14 +261,12 @@ static int gfar_probe(struct platform_device *pdev)
dev->tx_timeout = gfar_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
#ifdef CONFIG_GFAR_NAPI
- dev->poll = gfar_poll;
- dev->weight = GFAR_DEV_WEIGHT;
+ netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT);
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = gfar_netpoll;
#endif
dev->stop = gfar_close;
- dev->get_stats = gfar_get_stats;
dev->change_mtu = gfar_change_mtu;
dev->mtu = 1500;
dev->set_multicast_list = gfar_set_multi;
@@ -361,10 +358,8 @@ static int gfar_probe(struct platform_device *pdev)
gfar_init_sysfs(dev);
/* Print out the device info */
- printk(KERN_INFO DEVICE_NAME, dev->name);
- for (idx = 0; idx < 6; idx++)
- printk("%2.2x%c", dev->dev_addr[idx], idx == 5 ? ' ' : ':');
- printk("\n");
+ printk(KERN_INFO DEVICE_NAME "%s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
/* Even more device info helps when determining which kernel */
/* provided which set of benchmarks. */
@@ -937,8 +932,15 @@ tx_skb_fail:
/* Returns 0 for success. */
static int gfar_enet_open(struct net_device *dev)
{
+#ifdef CONFIG_GFAR_NAPI
+ struct gfar_private *priv = netdev_priv(dev);
+#endif
int err;
+#ifdef CONFIG_GFAR_NAPI
+ napi_enable(&priv->napi);
+#endif
+
/* Initialize a bunch of registers */
init_registers(dev);
@@ -946,10 +948,20 @@ static int gfar_enet_open(struct net_device *dev)
err = init_phy(dev);
- if(err)
+ if(err) {
+#ifdef CONFIG_GFAR_NAPI
+ napi_disable(&priv->napi);
+#endif
return err;
+ }
err = startup_gfar(dev);
+ if (err) {
+#ifdef CONFIG_GFAR_NAPI
+ napi_disable(&priv->napi);
+#endif
+ return err;
+ }
netif_start_queue(dev);
@@ -1010,7 +1022,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
/* Update transmit stats */
- priv->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
/* Lock priv now */
spin_lock_irqsave(&priv->txlock, flags);
@@ -1083,7 +1095,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (txbdp == priv->dirty_tx) {
netif_stop_queue(dev);
- priv->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
}
/* Update the current txbd to the next one */
@@ -1102,6 +1114,11 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
static int gfar_close(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
+
+#ifdef CONFIG_GFAR_NAPI
+ napi_disable(&priv->napi);
+#endif
+
stop_gfar(dev);
/* Disconnect from the PHY */
@@ -1113,14 +1130,6 @@ static int gfar_close(struct net_device *dev)
return 0;
}
-/* returns a net_device_stats structure pointer */
-static struct net_device_stats * gfar_get_stats(struct net_device *dev)
-{
- struct gfar_private *priv = netdev_priv(dev);
-
- return &(priv->stats);
-}
-
/* Changes the mac address if the controller is not running. */
int gfar_set_mac_address(struct net_device *dev)
{
@@ -1230,9 +1239,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
* starting over will fix the problem. */
static void gfar_timeout(struct net_device *dev)
{
- struct gfar_private *priv = netdev_priv(dev);
-
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (dev->flags & IFF_UP) {
stop_gfar(dev);
@@ -1262,12 +1269,12 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id)
if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0))
break;
- priv->stats.tx_packets++;
+ dev->stats.tx_packets++;
/* Deferred means some collisions occurred during transmit, */
/* but we eventually sent the packet. */
if (bdp->status & TXBD_DEF)
- priv->stats.collisions++;
+ dev->stats.collisions++;
/* Free the sk buffer associated with this TxBD */
dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]);
@@ -1318,7 +1325,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
return NULL;
alignamount = RXBUF_ALIGNMENT -
- (((unsigned) skb->data) & (RXBUF_ALIGNMENT - 1));
+ (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1));
/* We need the data buffer to be aligned properly. We will reserve
* as many bytes as needed to align the data properly
@@ -1337,9 +1344,10 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
return skb;
}
-static inline void count_errors(unsigned short status, struct gfar_private *priv)
+static inline void count_errors(unsigned short status, struct net_device *dev)
{
- struct net_device_stats *stats = &priv->stats;
+ struct gfar_private *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
struct gfar_extra_stats *estats = &priv->extra_stats;
/* If the packet was truncated, none of the other errors
@@ -1390,12 +1398,12 @@ irqreturn_t gfar_receive(int irq, void *dev_id)
/* support NAPI */
#ifdef CONFIG_GFAR_NAPI
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &priv->napi)) {
tempval = gfar_read(&priv->regs->imask);
tempval &= IMASK_RX_DISABLED;
gfar_write(&priv->regs->imask, tempval);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &priv->napi);
} else {
if (netif_msg_rx_err(priv))
printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
@@ -1464,7 +1472,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
if (NULL == skb) {
if (netif_msg_rx_err(priv))
printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
priv->extra_stats.rx_skbmissing++;
} else {
int ret;
@@ -1522,7 +1530,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
(RXBD_LARGE | RXBD_SHORT | RXBD_NONOCTET
| RXBD_CRCERR | RXBD_OVERRUN | RXBD_TRUNCATED))) {
/* Increment the number of packets */
- priv->stats.rx_packets++;
+ dev->stats.rx_packets++;
howmany++;
/* Remove the FCS from the packet length */
@@ -1530,9 +1538,9 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
gfar_process_frame(dev, skb, pkt_len);
- priv->stats.rx_bytes += pkt_len;
+ dev->stats.rx_bytes += pkt_len;
} else {
- count_errors(bdp->status, priv);
+ count_errors(bdp->status, dev);
if (skb)
dev_kfree_skb_any(skb);
@@ -1569,23 +1577,16 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
}
#ifdef CONFIG_GFAR_NAPI
-static int gfar_poll(struct net_device *dev, int *budget)
+static int gfar_poll(struct napi_struct *napi, int budget)
{
+ struct gfar_private *priv = container_of(napi, struct gfar_private, napi);
+ struct net_device *dev = priv->dev;
int howmany;
- struct gfar_private *priv = netdev_priv(dev);
- int rx_work_limit = *budget;
- if (rx_work_limit > dev->quota)
- rx_work_limit = dev->quota;
+ howmany = gfar_clean_rx_ring(dev, budget);
- howmany = gfar_clean_rx_ring(dev, rx_work_limit);
-
- dev->quota -= howmany;
- rx_work_limit -= howmany;
- *budget -= howmany;
-
- if (rx_work_limit > 0) {
- netif_rx_complete(dev);
+ if (howmany < budget) {
+ netif_rx_complete(dev, napi);
/* Clear the halt bit in RSTAT */
gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
@@ -1601,8 +1602,7 @@ static int gfar_poll(struct net_device *dev, int *budget)
gfar_write(&priv->regs->rxic, 0);
}
- /* Return 1 if there's more work to do */
- return (rx_work_limit > 0) ? 0 : 1;
+ return howmany;
}
#endif
@@ -1918,17 +1918,17 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
/* Update the error counters */
if (events & IEVENT_TXE) {
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (events & IEVENT_LC)
- priv->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (events & IEVENT_CRL)
- priv->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (events & IEVENT_XFUN) {
if (netif_msg_tx_err(priv))
printk(KERN_DEBUG "%s: TX FIFO underrun, "
"packet dropped.\n", dev->name);
- priv->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
priv->extra_stats.tx_underrun++;
/* Reactivate the Tx Queues */
@@ -1938,7 +1938,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
}
if (events & IEVENT_BSY) {
- priv->stats.rx_errors++;
+ dev->stats.rx_errors++;
priv->extra_stats.rx_bsy++;
gfar_receive(irq, dev_id);
@@ -1953,7 +1953,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
dev->name, gfar_read(&priv->regs->rstat));
}
if (events & IEVENT_BABR) {
- priv->stats.rx_errors++;
+ dev->stats.rx_errors++;
priv->extra_stats.rx_babr++;
if (netif_msg_rx_err(priv))
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index d8e779c102f..46cd7735e6f 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -45,7 +45,6 @@
#include <linux/crc32.h>
#include <linux/workqueue.h>
#include <linux/ethtool.h>
-#include <linux/netdevice.h>
#include <linux/fsl_devices.h>
#include "gianfar_mii.h"
@@ -691,6 +690,9 @@ struct gfar_private {
/* RX Locked fields */
spinlock_t rxlock;
+ struct net_device *dev;
+ struct napi_struct napi;
+
/* skb array and index */
struct sk_buff ** rx_skbuff;
u16 skb_currx;
@@ -747,7 +749,6 @@ struct gfar_private {
uint32_t msg_enable;
/* Network Statistics */
- struct net_device_stats stats;
struct gfar_extra_stats extra_stats;
};
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 7b411c1514d..6007147cc1e 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/crc32.h>
#include <asm/types.h>
-#include <asm/uaccess.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/phy.h>
@@ -153,15 +152,19 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
buf[i] = extra[i];
}
-/* Returns the number of stats (and their corresponding strings) */
-static int gfar_stats_count(struct net_device *dev)
+static int gfar_sset_count(struct net_device *dev, int sset)
{
struct gfar_private *priv = netdev_priv(dev);
- if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
- return GFAR_STATS_LEN;
- else
- return GFAR_EXTRA_STATS_LEN;
+ switch (sset) {
+ case ETH_SS_STATS:
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+ return GFAR_STATS_LEN;
+ else
+ return GFAR_EXTRA_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
/* Fills in the drvinfo structure with some basic info */
@@ -172,8 +175,6 @@ static void gfar_gdrvinfo(struct net_device *dev, struct
strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN);
strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN);
strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN);
- drvinfo->n_stats = GFAR_STATS_LEN;
- drvinfo->testinfo_len = 0;
drvinfo->regdump_len = 0;
drvinfo->eedump_len = 0;
}
@@ -576,7 +577,7 @@ const struct ethtool_ops gfar_ethtool_ops = {
.get_ringparam = gfar_gringparam,
.set_ringparam = gfar_sringparam,
.get_strings = gfar_gstrings,
- .get_stats_count = gfar_stats_count,
+ .get_sset_count = gfar_sset_count,
.get_ethtool_stats = gfar_fill_stats,
.get_rx_csum = gfar_get_rx_csum,
.get_tx_csum = gfar_get_tx_csum,
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 15254dc7876..ed407c85708 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -580,6 +580,7 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
void *ring_space;
dma_addr_t ring_dma;
int ret = -ENOMEM;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -613,7 +614,6 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
if (!dev)
goto err_out_iounmap;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
#ifdef TX_CHECKSUM
@@ -742,12 +742,9 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
goto err_out_unmap_rx;
}
- printk(KERN_INFO "%s: %s type %x at %p, ",
+ printk(KERN_INFO "%s: %s type %x at %p, %s, IRQ %d.\n",
dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev),
- ioaddr);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+ ioaddr, print_mac(mac, dev->dev_addr), irq);
i = readb(ioaddr + PCIClkMeas);
printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers "
"%2.2x, LPA %4.4x.\n",
@@ -1020,7 +1017,7 @@ static inline int hamachi_tx(struct net_device *dev)
break;
/* Free the original skb. */
skb = hmp->tx_skbuff[entry];
- if (skb != 0) {
+ if (skb) {
pci_unmap_single(hmp->pci_dev,
hmp->tx_ring[entry].addr, skb->len,
PCI_DMA_TODEVICE);
@@ -1072,7 +1069,6 @@ static void hamachi_tx_timeout(struct net_device *dev)
" resetting...\n", dev->name, (int)readw(ioaddr + TxStatus));
{
- int i;
printk(KERN_DEBUG " Rx ring %p: ", hmp->rx_ring);
for (i = 0; i < RX_RING_SIZE; i++)
printk(" %8.8x", (unsigned int)hmp->rx_ring[i].status_n_length);
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 760d04a671f..580cb4ab2af 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -3,7 +3,7 @@
* devices like TTY. It interfaces between a raw TTY and the
* kernel's AX.25 protocol layers.
*
- * Authors: Andreas Könsgen <ajk@iehk.rwth-aachen.de>
+ * Authors: Andreas Könsgen <ajk@iehk.rwth-aachen.de>
* Ralf Baechle DL5RB <ralf@linux-mips.org>
*
* Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by
@@ -288,10 +288,11 @@ static int sp_close(struct net_device *dev)
/* Return the frame type ID */
static int sp_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
#ifdef CONFIG_INET
- if (type != htons(ETH_P_AX25))
+ if (type != ETH_P_AX25)
return ax25_hard_header(skb, dev, type, daddr, saddr, len);
#endif
return 0;
@@ -323,6 +324,11 @@ static int sp_rebuild_header(struct sk_buff *skb)
#endif
}
+static const struct header_ops sp_header_ops = {
+ .create = sp_header,
+ .rebuild = sp_rebuild_header,
+};
+
static void sp_setup(struct net_device *dev)
{
/* Finish setting up the DEVICE info. */
@@ -331,22 +337,21 @@ static void sp_setup(struct net_device *dev)
dev->open = sp_open_dev;
dev->destructor = free_netdev;
dev->stop = sp_close;
- dev->hard_header = sp_header;
+
dev->get_stats = sp_get_stats;
dev->set_mac_address = sp_set_mac_address;
dev->hard_header_len = AX25_MAX_HEADER_LEN;
+ dev->header_ops = &sp_header_ops;
+
dev->addr_len = AX25_ADDR_LEN;
dev->type = ARPHRD_AX25;
dev->tx_queue_len = 10;
- dev->rebuild_header = sp_rebuild_header;
dev->tx_timeout = NULL;
/* Only activated in AX.25 mode */
memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
- SET_MODULE_OWNER(dev);
-
dev->flags = 0;
}
@@ -757,26 +762,20 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file,
if (copy_from_user(&addr,
(void __user *) arg, AX25_ADDR_LEN)) {
- err = -EFAULT;
- break;
- }
-
- netif_tx_lock_bh(dev);
- memcpy(dev->dev_addr, &addr, AX25_ADDR_LEN);
- netif_tx_unlock_bh(dev);
+ err = -EFAULT;
+ break;
+ }
- err = 0;
- break;
- }
+ netif_tx_lock_bh(dev);
+ memcpy(dev->dev_addr, &addr, AX25_ADDR_LEN);
+ netif_tx_unlock_bh(dev);
- /* Allow stty to read, but not set, the serial port */
- case TCGETS:
- case TCGETA:
- err = n_tty_ioctl(tty, (struct file *) file, cmd, arg);
- break;
+ err = 0;
+ break;
+ }
default:
- err = -ENOIOCTLCMD;
+ err = tty_mode_ioctl(tty, file, cmd, arg);
}
sp_put(sp);
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig
index 36d2c7d4f4d..62d5d5cfd6a 100644
--- a/drivers/net/hamradio/Kconfig
+++ b/drivers/net/hamradio/Kconfig
@@ -64,7 +64,7 @@ config DMASCC
dmascc. If you don't pass any parameter to the driver, all
possible I/O addresses are probed. This could irritate other devices
that are currently not in use. You may specify the list of addresses
- to be probed by "dmascc=addr1,addr2,..." (when compiled into the
+ to be probed by "dmascc.io=addr1,addr2,..." (when compiled into the
kernel image) or "io=addr1,addr2,..." (when loaded as a module). The
network interfaces will be called dmascc0 and dmascc1 for the board
detected first, dmascc2 and dmascc3 for the second one, and so on.
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 355c6cf3d11..dde9c7e6408 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -325,12 +325,6 @@ static int eppconfig(struct baycom_state *bc)
/* ---------------------------------------------------------------------- */
-static void epp_interrupt(int irq, void *dev_id)
-{
-}
-
-/* ---------------------------------------------------------------------- */
-
static inline void do_kiss_params(struct baycom_state *bc,
unsigned char *data, unsigned long len)
{
@@ -871,7 +865,7 @@ static int epp_open(struct net_device *dev)
}
memset(&bc->modem, 0, sizeof(bc->modem));
bc->pdev = parport_register_device(pp, dev->name, NULL, epp_wakeup,
- epp_interrupt, PARPORT_DEV_EXCL, dev);
+ NULL, PARPORT_DEV_EXCL, dev);
parport_put_port(pp);
if (!bc->pdev) {
printk(KERN_ERR "%s: cannot register parport at 0x%lx\n", bc_drvname, pp->base);
@@ -1159,8 +1153,7 @@ static void baycom_probe(struct net_device *dev)
/* Fill in the fields of the device structure */
bc->skb = NULL;
- dev->hard_header = ax25_hard_header;
- dev->rebuild_header = ax25_rebuild_header;
+ dev->header_ops = &ax25_header_ops;
dev->set_mac_address = baycom_set_mac_address;
dev->type = ARPHRD_AX25; /* AF_AX25 device */
diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c
index 5930aeb3501..2e6fc4dc74b 100644
--- a/drivers/net/hamradio/baycom_par.c
+++ b/drivers/net/hamradio/baycom_par.c
@@ -270,9 +270,9 @@ static __inline__ void par96_rx(struct net_device *dev, struct baycom_state *bc)
/* --------------------------------------------------------------------- */
-static void par96_interrupt(int irq, void *dev_id)
+static void par96_interrupt(void *dev_id)
{
- struct net_device *dev = (struct net_device *)dev_id;
+ struct net_device *dev = dev_id;
struct baycom_state *bc = netdev_priv(dev);
baycom_int_freq(bc);
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index cc0ee93669e..5ddf8b0c34f 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -64,7 +64,7 @@
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
-#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <net/sock.h>
@@ -83,6 +83,7 @@
#include <net/ip.h>
#include <net/arp.h>
+#include <net/net_namespace.h>
#include <linux/bpqether.h>
@@ -94,7 +95,6 @@ static char bpq_eth_addr[6];
static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
static int bpq_device_event(struct notifier_block *, unsigned long, void *);
-static const char *bpq_print_ethaddr(const unsigned char *);
static struct packet_type bpq_packet_type = {
.type = __constant_htons(ETH_P_BPQ),
@@ -172,6 +172,9 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty
struct ethhdr *eth;
struct bpqdev *bpq;
+ if (dev->nd_net != &init_net)
+ goto drop;
+
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
return NET_RX_DROP;
@@ -283,7 +286,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev)
skb->protocol = ax25_type_trans(skb, dev);
skb_reset_network_header(skb);
- dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
+ dev_hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
bpq->stats.tx_packets++;
bpq->stats.tx_bytes+=skb->len;
@@ -379,16 +382,6 @@ static int bpq_close(struct net_device *dev)
/*
* Proc filesystem
*/
-static const char * bpq_print_ethaddr(const unsigned char *e)
-{
- static char buf[18];
-
- sprintf(buf, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
- e[0], e[1], e[2], e[3], e[4], e[5]);
-
- return buf;
-}
-
static void *bpq_seq_start(struct seq_file *seq, loff_t *pos)
{
int i = 1;
@@ -434,14 +427,16 @@ static int bpq_seq_show(struct seq_file *seq, void *v)
"dev ether destination accept from\n");
else {
const struct bpqdev *bpqdev = v;
+ DECLARE_MAC_BUF(mac);
seq_printf(seq, "%-5s %-10s %s ",
bpqdev->axdev->name, bpqdev->ethdev->name,
- bpq_print_ethaddr(bpqdev->dest_addr));
+ print_mac(mac, bpqdev->dest_addr));
- seq_printf(seq, "%s\n",
- (bpqdev->acpt_addr[0] & 0x01) ? "*"
- : bpq_print_ethaddr(bpqdev->acpt_addr));
+ if (is_multicast_ether_addr(bpqdev->acpt_addr))
+ seq_printf(seq, "*\n");
+ else
+ seq_printf(seq, "%s\n", print_mac(mac, bpqdev->acpt_addr));
}
return 0;
@@ -488,8 +483,7 @@ static void bpq_setup(struct net_device *dev)
dev->flags = 0;
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
- dev->hard_header = ax25_hard_header;
- dev->rebuild_header = ax25_rebuild_header;
+ dev->header_ops = &ax25_header_ops;
#endif
dev->type = ARPHRD_AX25;
@@ -559,6 +553,9 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi
{
struct net_device *dev = (struct net_device *)ptr;
+ if (dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
if (!dev_is_ethdev(dev))
return NOTIFY_DONE;
@@ -594,7 +591,7 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi
static int __init bpq_init_driver(void)
{
#ifdef CONFIG_PROC_FS
- if (!proc_net_fops_create("bpqether", S_IRUGO, &bpq_info_fops)) {
+ if (!proc_net_fops_create(&init_net, "bpqether", S_IRUGO, &bpq_info_fops)) {
printk(KERN_ERR
"bpq: cannot create /proc/net/bpqether entry.\n");
return -ENOENT;
@@ -618,7 +615,7 @@ static void __exit bpq_cleanup_driver(void)
unregister_netdevice_notifier(&bpq_dev_notifier);
- proc_net_remove("bpqether");
+ proc_net_remove(&init_net, "bpqether");
rtnl_lock();
while (!list_empty(&bpq_devices)) {
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 205f0967249..11b83dae00a 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
+#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/if_arp.h>
@@ -35,7 +36,6 @@
#include <linux/sockios.h>
#include <linux/workqueue.h>
#include <asm/atomic.h>
-#include <asm/bitops.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -581,8 +581,7 @@ static int __init setup_adapter(int card_base, int type, int n)
dev->do_ioctl = scc_ioctl;
dev->hard_start_xmit = scc_send_packet;
dev->get_stats = scc_get_stats;
- dev->hard_header = ax25_hard_header;
- dev->rebuild_header = ax25_rebuild_header;
+ dev->header_ops = &ax25_header_ops;
dev->set_mac_address = scc_set_mac_address;
}
if (register_netdev(info->dev[0])) {
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index b33adc6a340..ae9629fa688 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -682,8 +682,7 @@ static void hdlcdrv_setup(struct net_device *dev)
s->skb = NULL;
- dev->hard_header = ax25_hard_header;
- dev->rebuild_header = ax25_rebuild_header;
+ dev->header_ops = &ax25_header_ops;
dev->set_mac_address = hdlcdrv_set_mac_address;
dev->type = ARPHRD_AX25; /* AF_AX25 device */
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index d08fbc39664..803a3bdea0a 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -578,11 +578,12 @@ static int ax_open_dev(struct net_device *dev)
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
/* Return the frame type ID */
-static int ax_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len)
+static int ax_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
#ifdef CONFIG_INET
- if (type != htons(ETH_P_AX25))
+ if (type != ETH_P_AX25)
return ax25_hard_header(skb, dev, type, daddr, saddr, len);
#endif
return 0;
@@ -670,6 +671,11 @@ static struct net_device_stats *ax_get_stats(struct net_device *dev)
return &ax->stats;
}
+static const struct header_ops ax_header_ops = {
+ .create = ax_header,
+ .rebuild = ax_rebuild_header,
+};
+
static void ax_setup(struct net_device *dev)
{
/* Finish setting up the DEVICE info. */
@@ -683,8 +689,8 @@ static void ax_setup(struct net_device *dev)
dev->addr_len = 0;
dev->type = ARPHRD_AX25;
dev->tx_queue_len = 10;
- dev->hard_header = ax_header;
- dev->rebuild_header = ax_rebuild_header;
+ dev->header_ops = &ax_header_ops;
+
memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 6fdaad5a457..353d13e543c 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -174,6 +174,7 @@
#include <linux/seq_file.h>
#include <linux/bitops.h>
+#include <net/net_namespace.h>
#include <net/ax25.h>
#include <asm/irq.h>
@@ -1550,8 +1551,8 @@ static void scc_net_setup(struct net_device *dev)
dev->stop = scc_net_close;
dev->hard_start_xmit = scc_net_tx;
- dev->hard_header = ax25_hard_header;
- dev->rebuild_header = ax25_rebuild_header;
+ dev->header_ops = &ax25_header_ops;
+
dev->set_mac_address = scc_net_set_mac_address;
dev->get_stats = scc_net_get_stats;
dev->do_ioctl = scc_net_ioctl;
@@ -2114,7 +2115,7 @@ static int __init scc_init_driver (void)
}
rtnl_unlock();
- proc_net_fops_create("z8530drv", 0, &scc_net_seq_fops);
+ proc_net_fops_create(&init_net, "z8530drv", 0, &scc_net_seq_fops);
return 0;
}
@@ -2169,7 +2170,7 @@ static void __exit scc_cleanup_driver(void)
if (Vector_Latch)
release_region(Vector_Latch, 1);
- proc_net_remove("z8530drv");
+ proc_net_remove(&init_net, "z8530drv");
}
MODULE_AUTHOR("Joerg Reuter <jreuter@yaina.de>");
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 467559debfd..1c942862a3f 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -65,6 +65,7 @@
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <net/net_namespace.h>
#include <asm/uaccess.h>
#include <linux/init.h>
@@ -1096,8 +1097,7 @@ static void yam_setup(struct net_device *dev)
skb_queue_head_init(&yp->send_queue);
- dev->hard_header = ax25_hard_header;
- dev->rebuild_header = ax25_rebuild_header;
+ dev->header_ops = &ax25_header_ops;
dev->set_mac_address = yam_set_mac_address;
@@ -1142,7 +1142,7 @@ static int __init yam_init_driver(void)
yam_timer.expires = jiffies + HZ / 100;
add_timer(&yam_timer);
- proc_net_fops_create("yam", S_IRUGO, &yam_info_fops);
+ proc_net_fops_create(&init_net, "yam", S_IRUGO, &yam_info_fops);
return 0;
error:
while (--i >= 0) {
@@ -1174,7 +1174,7 @@ static void __exit yam_cleanup_driver(void)
kfree(p);
}
- proc_net_remove("yam");
+ proc_net_remove(&init_net, "yam");
}
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 99a36cc3f8d..c2c4f49d757 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -122,8 +122,6 @@ static int __init do_hpp_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) /* Check a single specified location. */
return hpp_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
@@ -168,6 +166,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr)
const char name[] = "HP-PC-LAN+";
int mem_start;
static unsigned version_printed;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -182,7 +181,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr)
if (ei_debug && version_printed++ == 0)
printk(version);
- printk("%s: %s at %#3x,", dev->name, name, ioaddr);
+ printk("%s: %s at %#3x, ", dev->name, name, ioaddr);
/* Retrieve and checksum the station address. */
outw(MAC_Page, ioaddr + HP_PAGING);
@@ -191,10 +190,11 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr)
unsigned char inval = inb(ioaddr + 8 + i);
dev->dev_addr[i] = inval;
checksum += inval;
- printk(" %2.2x", inval);
}
checksum += inb(ioaddr + 14);
+ printk("%s", print_mac(mac, dev->dev_addr));
+
if (checksum != 0xff) {
printk(" bad checksum %2.2x.\n", checksum);
retval = -ENODEV;
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index 635b13c2e2a..c649a8019be 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -86,8 +86,6 @@ static int __init do_hp_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) /* Check a single specified location. */
return hp_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
@@ -129,6 +127,7 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr)
int i, retval, board_id, wordmode;
const char *name;
static unsigned version_printed;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -160,7 +159,9 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr)
printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
for(i = 0; i < ETHER_ADDR_LEN; i++)
- printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+ dev->dev_addr[i] = inb(ioaddr + i);
+
+ printk(" %s", print_mac(mac, dev->dev_addr));
/* Snarf the interrupt now. Someday this could be moved to open(). */
if (dev->irq < 2) {
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 8caa591c564..49421d1cd3a 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -8,7 +8,7 @@
** Extended for new busmaster capable chipsets by
** Siegfried "Frieder" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de>
**
-** Maintained by: Jaroslav Kysela <perex@suse.cz>
+** Maintained by: Jaroslav Kysela <perex@perex.cz>
**
** This driver has only been tested with
** -- HP J2585B 10/100 Mbit/s PCI Busmaster
@@ -404,8 +404,6 @@ struct net_device * __init hp100_probe(int unit)
if (!dev)
return ERR_PTR(-ENODEV);
- SET_MODULE_OWNER(dev);
-
#ifdef HP100_DEBUG_B
hp100_outw(0x4200, TRACE);
printk("hp100: %s: probe\n", dev->name);
@@ -2095,9 +2093,9 @@ static void hp100_set_multicast_list(struct net_device *dev)
addrs = dmi->dmi_addr;
if ((*addrs & 0x01) == 0x01) { /* multicast address? */
#ifdef HP100_DEBUG
- printk("hp100: %s: multicast = %02x:%02x:%02x:%02x:%02x:%02x, ",
- dev->name, addrs[0], addrs[1], addrs[2],
- addrs[3], addrs[4], addrs[5]);
+ DECLARE_MAC_BUF(mac);
+ printk("hp100: %s: multicast = %s, ",
+ dev->name, print_mac(mac, addrs));
#endif
for (j = idx = 0; j < 6; j++) {
idx ^= *addrs++ & 0x3f;
@@ -2843,7 +2841,6 @@ static int __init hp100_eisa_probe (struct device *gendev)
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &edev->dev);
err = hp100_probe1(dev, edev->base_addr + 0xC38, HP100_BUS_EISA, NULL);
@@ -2896,7 +2893,6 @@ static int __devinit hp100_pci_probe (struct pci_dev *pdev,
goto out0;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
@@ -2955,7 +2951,7 @@ static struct pci_driver hp100_pci_driver = {
*/
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, "
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, "
"Siegfried \"Frieder\" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de>");
MODULE_DESCRIPTION("HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters");
@@ -2993,7 +2989,6 @@ static int __init hp100_isa_init(void)
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
err = hp100_isa_probe(dev, hp100_port[i]);
if (!err)
diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c
index c991cb82ff2..be6e5bc7c88 100644
--- a/drivers/net/hplance.c
+++ b/drivers/net/hplance.c
@@ -141,7 +141,6 @@ static void __init hplance_init(struct net_device *dev, struct dio_dev *d)
dev->poll_controller = lance_poll;
#endif
dev->hard_start_xmit = &lance_start_xmit;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
dev->dma = 0;
diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c
index f970bfbb9db..b96cf2dcb10 100644
--- a/drivers/net/hydra.c
+++ b/drivers/net/hydra.c
@@ -103,6 +103,7 @@ static int __devinit hydra_init(struct zorro_dev *z)
int start_page, stop_page;
int j;
int err;
+ DECLARE_MAC_BUF(mac);
static u32 hydra_offsets[16] = {
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
@@ -112,7 +113,6 @@ static int __devinit hydra_init(struct zorro_dev *z)
dev = ____alloc_ei_netdev(0);
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
for(j = 0; j < ETHER_ADDR_LEN; j++)
dev->dev_addr[j] = *((u8 *)(board + HYDRA_ADDRPROM + 2*j));
@@ -163,10 +163,8 @@ static int __devinit hydra_init(struct zorro_dev *z)
zorro_set_drvdata(z, dev);
printk(KERN_INFO "%s: Hydra at 0x%08lx, address "
- "%02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n",
- dev->name, z->resource.start, dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4],
- dev->dev_addr[5]);
+ "%s (hydra.c " HYDRA_VERSION ")\n",
+ dev->name, z->resource.start, print_mac(mac, dev->dev_addr));
return 0;
}
diff --git a/drivers/net/ibm_emac/Kconfig b/drivers/net/ibm_emac/Kconfig
new file mode 100644
index 00000000000..f61c48047dc
--- /dev/null
+++ b/drivers/net/ibm_emac/Kconfig
@@ -0,0 +1,70 @@
+config IBM_EMAC
+ tristate "PowerPC 4xx on-chip Ethernet support"
+ depends on 4xx && !PPC_MERGE
+ help
+ This driver supports the PowerPC 4xx EMAC family of on-chip
+ Ethernet controllers.
+
+config IBM_EMAC_RXB
+ int "Number of receive buffers"
+ depends on IBM_EMAC
+ default "128"
+
+config IBM_EMAC_TXB
+ int "Number of transmit buffers"
+ depends on IBM_EMAC
+ default "64"
+
+config IBM_EMAC_POLL_WEIGHT
+ int "MAL NAPI polling weight"
+ depends on IBM_EMAC
+ default "32"
+
+config IBM_EMAC_RX_COPY_THRESHOLD
+ int "RX skb copy threshold (bytes)"
+ depends on IBM_EMAC
+ default "256"
+
+config IBM_EMAC_RX_SKB_HEADROOM
+ int "Additional RX skb headroom (bytes)"
+ depends on IBM_EMAC
+ default "0"
+ help
+ Additional receive skb headroom. Note, that driver
+ will always reserve at least 2 bytes to make IP header
+ aligned, so usually there is no need to add any additional
+ headroom.
+
+ If unsure, set to 0.
+
+config IBM_EMAC_PHY_RX_CLK_FIX
+ bool "PHY Rx clock workaround"
+ depends on IBM_EMAC && (405EP || 440GX || 440EP || 440GR)
+ help
+ Enable this if EMAC attached to a PHY which doesn't generate
+ RX clock if there is no link, if this is the case, you will
+ see "TX disable timeout" or "RX disable timeout" in the system
+ log.
+
+ If unsure, say N.
+
+config IBM_EMAC_DEBUG
+ bool "Debugging"
+ depends on IBM_EMAC
+ default n
+
+config IBM_EMAC_ZMII
+ bool
+ depends on IBM_EMAC && (NP405H || NP405L || 44x)
+ default y
+
+config IBM_EMAC_RGMII
+ bool
+ depends on IBM_EMAC && 440GX
+ default y
+
+config IBM_EMAC_TAH
+ bool
+ depends on IBM_EMAC && 440GX
+ default y
+
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
index f752e5fc65b..73664f226f3 100644
--- a/drivers/net/ibm_emac/ibm_emac_core.c
+++ b/drivers/net/ibm_emac/ibm_emac_core.c
@@ -353,10 +353,9 @@ static void emac_hash_mc(struct ocp_enet_private *dev)
for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) {
int bit;
- DBG2("%d: mc %02x:%02x:%02x:%02x:%02x:%02x" NL,
- dev->def->index,
- dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
- dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]);
+ DECLARE_MAC_BUF(mac);
+ DBG2("%d: mc %s" NL,
+ dev->def->index, print_mac(mac, dmi->dmi_addr));
bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26);
gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f);
@@ -1843,9 +1842,14 @@ static int emac_ethtool_nway_reset(struct net_device *ndev)
return res;
}
-static int emac_ethtool_get_stats_count(struct net_device *ndev)
+static int emac_get_sset_count(struct net_device *ndev, int sset)
{
- return EMAC_ETHTOOL_STATS_COUNT;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return EMAC_ETHTOOL_STATS_COUNT;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset,
@@ -1876,7 +1880,6 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev,
strcpy(info->version, DRV_VERSION);
info->fw_version[0] = '\0';
sprintf(info->bus_info, "PPC 4xx EMAC %d", dev->def->index);
- info->n_stats = emac_ethtool_get_stats_count(ndev);
info->regdump_len = emac_ethtool_get_regs_len(ndev);
}
@@ -1896,12 +1899,10 @@ static const struct ethtool_ops emac_ethtool_ops = {
.get_rx_csum = emac_ethtool_get_rx_csum,
.get_strings = emac_ethtool_get_strings,
- .get_stats_count = emac_ethtool_get_stats_count,
+ .get_sset_count = emac_get_sset_count,
.get_ethtool_stats = emac_ethtool_get_ethtool_stats,
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
};
static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
@@ -1942,6 +1943,7 @@ static int __init emac_probe(struct ocp_device *ocpdev)
struct ocp_device *maldev;
struct ocp_enet_private *dev;
int err, i;
+ DECLARE_MAC_BUF(mac);
DBG("%d: probe" NL, ocpdev->def->index);
@@ -1962,7 +1964,6 @@ static int __init emac_probe(struct ocp_device *ocpdev)
dev->ndev = ndev;
dev->ldev = &ocpdev->dev;
dev->def = ocpdev->def;
- SET_MODULE_OWNER(ndev);
/* Find MAL device we are connected to */
maldev =
@@ -2191,10 +2192,8 @@ static int __init emac_probe(struct ocp_device *ocpdev)
ocp_set_drvdata(ocpdev, dev);
- printk("%s: emac%d, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
- ndev->name, dev->def->index,
- ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
- ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+ printk("%s: emac%d, MAC %s\n",
+ ndev->name, dev->def->index, print_mac(mac, ndev->dev_addr));
if (dev->phy.address >= 0)
printk("%s: found %s PHY (0x%02x)\n", ndev->name,
diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c
index 92f970d402d..1f70906cfb9 100644
--- a/drivers/net/ibm_emac/ibm_emac_debug.c
+++ b/drivers/net/ibm_emac/ibm_emac_debug.c
@@ -132,7 +132,7 @@ void emac_dbg_register(int idx, struct ocp_enet_private *dev)
{
unsigned long flags;
- if (idx >= sizeof(__emacs) / sizeof(__emacs[0])) {
+ if (idx >= ARRAY_SIZE(__emacs)) {
printk(KERN_WARNING
"invalid index %d when registering EMAC for debugging\n",
idx);
@@ -148,7 +148,7 @@ void mal_dbg_register(int idx, struct ibm_ocp_mal *mal)
{
unsigned long flags;
- if (idx >= sizeof(__mals) / sizeof(__mals[0])) {
+ if (idx >= ARRAY_SIZE(__mals)) {
printk(KERN_WARNING
"invalid index %d when registering MAL for debugging\n",
idx);
@@ -167,11 +167,11 @@ void emac_dbg_dump_all(void)
local_irq_save(flags);
- for (i = 0; i < sizeof(__mals) / sizeof(__mals[0]); ++i)
+ for (i = 0; i < ARRAY_SIZE(__mals); ++i)
if (__mals[i])
emac_mal_dump(__mals[i]);
- for (i = 0; i < sizeof(__emacs) / sizeof(__emacs[0]); ++i)
+ for (i = 0; i < ARRAY_SIZE(__emacs); ++i)
if (__emacs[i])
emac_mac_dump(i, __emacs[i]);
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c
index cabd9846a5e..dcd8826fc74 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.c
+++ b/drivers/net/ibm_emac/ibm_emac_mal.c
@@ -207,10 +207,10 @@ static irqreturn_t mal_serr(int irq, void *dev_instance)
static inline void mal_schedule_poll(struct ibm_ocp_mal *mal)
{
- if (likely(netif_rx_schedule_prep(&mal->poll_dev))) {
+ if (likely(napi_schedule_prep(&mal->napi))) {
MAL_DBG2("%d: schedule_poll" NL, mal->def->index);
mal_disable_eob_irq(mal);
- __netif_rx_schedule(&mal->poll_dev);
+ __napi_schedule(&mal->napi);
} else
MAL_DBG2("%d: already in poll" NL, mal->def->index);
}
@@ -273,11 +273,11 @@ static irqreturn_t mal_rxde(int irq, void *dev_instance)
return IRQ_HANDLED;
}
-static int mal_poll(struct net_device *ndev, int *budget)
+static int mal_poll(struct napi_struct *napi, int budget)
{
- struct ibm_ocp_mal *mal = ndev->priv;
+ struct ibm_ocp_mal *mal = container_of(napi, struct ibm_ocp_mal, napi);
struct list_head *l;
- int rx_work_limit = min(ndev->quota, *budget), received = 0, done;
+ int received = 0;
MAL_DBG2("%d: poll(%d) %d ->" NL, mal->def->index, *budget,
rx_work_limit);
@@ -295,38 +295,34 @@ static int mal_poll(struct net_device *ndev, int *budget)
list_for_each(l, &mal->poll_list) {
struct mal_commac *mc =
list_entry(l, struct mal_commac, poll_list);
- int n = mc->ops->poll_rx(mc->dev, rx_work_limit);
+ int n = mc->ops->poll_rx(mc->dev, budget);
if (n) {
received += n;
- rx_work_limit -= n;
- if (rx_work_limit <= 0) {
- done = 0;
+ budget -= n;
+ if (budget <= 0)
goto more_work; // XXX What if this is the last one ?
- }
}
}
/* We need to disable IRQs to protect from RXDE IRQ here */
local_irq_disable();
- __netif_rx_complete(ndev);
+ __napi_complete(napi);
mal_enable_eob_irq(mal);
local_irq_enable();
- done = 1;
-
/* Check for "rotting" packet(s) */
list_for_each(l, &mal->poll_list) {
struct mal_commac *mc =
list_entry(l, struct mal_commac, poll_list);
if (unlikely(mc->ops->peek_rx(mc->dev) || mc->rx_stopped)) {
MAL_DBG2("%d: rotting packet" NL, mal->def->index);
- if (netif_rx_reschedule(ndev, received))
+ if (napi_reschedule(napi))
mal_disable_eob_irq(mal);
else
MAL_DBG2("%d: already in poll list" NL,
mal->def->index);
- if (rx_work_limit > 0)
+ if (budget > 0)
goto again;
else
goto more_work;
@@ -335,12 +331,8 @@ static int mal_poll(struct net_device *ndev, int *budget)
}
more_work:
- ndev->quota -= received;
- *budget -= received;
-
- MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, *budget,
- done ? 0 : 1);
- return done ? 0 : 1;
+ MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, budget, received);
+ return received;
}
static void mal_reset(struct ibm_ocp_mal *mal)
@@ -421,15 +413,15 @@ static int __init mal_probe(struct ocp_device *ocpdev)
ocpdev->def->index);
return -ENOMEM;
}
- mal->dcrbase = maldata->dcr_base;
+
+ /* XXX This only works for native dcr for now */
+ mal->dcrhost = dcr_map(NULL, maldata->dcr_base, 0);
+
mal->def = ocpdev->def;
INIT_LIST_HEAD(&mal->poll_list);
- set_bit(__LINK_STATE_START, &mal->poll_dev.state);
- mal->poll_dev.weight = CONFIG_IBM_EMAC_POLL_WEIGHT;
- mal->poll_dev.poll = mal_poll;
- mal->poll_dev.priv = mal;
- atomic_set(&mal->poll_dev.refcnt, 1);
+ mal->napi.weight = CONFIG_IBM_EMAC_POLL_WEIGHT;
+ mal->napi.poll = mal_poll;
INIT_LIST_HEAD(&mal->list);
@@ -520,11 +512,8 @@ static void __exit mal_remove(struct ocp_device *ocpdev)
MAL_DBG("%d: remove" NL, mal->def->index);
- /* Syncronize with scheduled polling,
- stolen from net/core/dev.c:dev_close()
- */
- clear_bit(__LINK_STATE_START, &mal->poll_dev.state);
- netif_poll_disable(&mal->poll_dev);
+ /* Synchronize with scheduled polling */
+ napi_disable(&mal->napi);
if (!list_empty(&mal->list)) {
/* This is *very* bad */
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h
index 64bc338acc6..b8adbe6d4b0 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.h
+++ b/drivers/net/ibm_emac/ibm_emac_mal.h
@@ -191,11 +191,10 @@ struct mal_commac {
};
struct ibm_ocp_mal {
- int dcrbase;
dcr_host_t dcrhost;
struct list_head poll_list;
- struct net_device poll_dev;
+ struct napi_struct napi;
struct list_head list;
u32 tx_chan_mask;
@@ -209,12 +208,12 @@ struct ibm_ocp_mal {
static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg)
{
- return dcr_read(mal->dcrhost, mal->dcrbase + reg);
+ return dcr_read(mal->dcrhost, reg);
}
static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val)
{
- dcr_write(mal->dcrhost, mal->dcrbase + reg, val);
+ dcr_write(mal->dcrhost, reg, val);
}
/* Register MAL devices */
diff --git a/drivers/net/ibm_newemac/Kconfig b/drivers/net/ibm_newemac/Kconfig
new file mode 100644
index 00000000000..0d3e7380bad
--- /dev/null
+++ b/drivers/net/ibm_newemac/Kconfig
@@ -0,0 +1,63 @@
+config IBM_NEW_EMAC
+ tristate "IBM EMAC Ethernet support"
+ depends on PPC_DCR && PPC_MERGE
+ help
+ This driver supports the IBM EMAC family of Ethernet controllers
+ typically found on 4xx embedded PowerPC chips, but also on the
+ Axon southbridge for Cell.
+
+config IBM_NEW_EMAC_RXB
+ int "Number of receive buffers"
+ depends on IBM_NEW_EMAC
+ default "128"
+
+config IBM_NEW_EMAC_TXB
+ int "Number of transmit buffers"
+ depends on IBM_NEW_EMAC
+ default "64"
+
+config IBM_NEW_EMAC_POLL_WEIGHT
+ int "MAL NAPI polling weight"
+ depends on IBM_NEW_EMAC
+ default "32"
+
+config IBM_NEW_EMAC_RX_COPY_THRESHOLD
+ int "RX skb copy threshold (bytes)"
+ depends on IBM_NEW_EMAC
+ default "256"
+
+config IBM_NEW_EMAC_RX_SKB_HEADROOM
+ int "Additional RX skb headroom (bytes)"
+ depends on IBM_NEW_EMAC
+ default "0"
+ help
+ Additional receive skb headroom. Note, that driver
+ will always reserve at least 2 bytes to make IP header
+ aligned, so usually there is no need to add any additional
+ headroom.
+
+ If unsure, set to 0.
+
+config IBM_NEW_EMAC_DEBUG
+ bool "Debugging"
+ depends on IBM_NEW_EMAC
+ default n
+
+# The options below has to be select'ed by the respective
+# processor types or platforms
+
+config IBM_NEW_EMAC_ZMII
+ bool
+ default n
+
+config IBM_NEW_EMAC_RGMII
+ bool
+ default n
+
+config IBM_NEW_EMAC_TAH
+ bool
+ default n
+
+config IBM_NEW_EMAC_EMAC4
+ bool
+ default n
diff --git a/drivers/net/ibm_newemac/Makefile b/drivers/net/ibm_newemac/Makefile
new file mode 100644
index 00000000000..0b5c9951276
--- /dev/null
+++ b/drivers/net/ibm_newemac/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the PowerPC 4xx on-chip ethernet driver
+#
+
+obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac.o
+
+ibm_newemac-y := mal.o core.o phy.o
+ibm_newemac-$(CONFIG_IBM_NEW_EMAC_ZMII) += zmii.o
+ibm_newemac-$(CONFIG_IBM_NEW_EMAC_RGMII) += rgmii.o
+ibm_newemac-$(CONFIG_IBM_NEW_EMAC_TAH) += tah.o
+ibm_newemac-$(CONFIG_IBM_NEW_EMAC_DEBUG) += debug.o
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
new file mode 100644
index 00000000000..0de3aa2a2e4
--- /dev/null
+++ b/drivers/net/ibm_newemac/core.c
@@ -0,0 +1,2906 @@
+/*
+ * drivers/net/ibm_newemac/core.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Matt Porter <mporter@kernel.crashing.org>
+ * (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * Armin Kuster <akuster@mvista.com>
+ * Johnnie Peters <jpeters@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/bitops.h>
+#include <linux/workqueue.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#include "core.h"
+
+/*
+ * Lack of dma_unmap_???? calls is intentional.
+ *
+ * API-correct usage requires additional support state information to be
+ * maintained for every RX and TX buffer descriptor (BD). Unfortunately, due to
+ * EMAC design (e.g. TX buffer passed from network stack can be split into
+ * several BDs, dma_map_single/dma_map_page can be used to map particular BD),
+ * maintaining such information will add additional overhead.
+ * Current DMA API implementation for 4xx processors only ensures cache coherency
+ * and dma_unmap_???? routines are empty and are likely to stay this way.
+ * I decided to omit dma_unmap_??? calls because I don't want to add additional
+ * complexity just for the sake of following some abstract API, when it doesn't
+ * add any real benefit to the driver. I understand that this decision maybe
+ * controversial, but I really tried to make code API-correct and efficient
+ * at the same time and didn't come up with code I liked :(. --ebs
+ */
+
+#define DRV_NAME "emac"
+#define DRV_VERSION "3.54"
+#define DRV_DESC "PPC 4xx OCP EMAC driver"
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_AUTHOR
+ ("Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>");
+MODULE_LICENSE("GPL");
+
+/*
+ * PPC64 doesn't (yet) have a cacheable_memcpy
+ */
+#ifdef CONFIG_PPC64
+#define cacheable_memcpy(d,s,n) memcpy((d),(s),(n))
+#endif
+
+/* minimum number of free TX descriptors required to wake up TX process */
+#define EMAC_TX_WAKEUP_THRESH (NUM_TX_BUFF / 4)
+
+/* If packet size is less than this number, we allocate small skb and copy packet
+ * contents into it instead of just sending original big skb up
+ */
+#define EMAC_RX_COPY_THRESH CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD
+
+/* Since multiple EMACs share MDIO lines in various ways, we need
+ * to avoid re-using the same PHY ID in cases where the arch didn't
+ * setup precise phy_map entries
+ *
+ * XXX This is something that needs to be reworked as we can have multiple
+ * EMAC "sets" (multiple ASICs containing several EMACs) though we can
+ * probably require in that case to have explicit PHY IDs in the device-tree
+ */
+static u32 busy_phy_map;
+static DEFINE_MUTEX(emac_phy_map_lock);
+
+/* This is the wait queue used to wait on any event related to probe, that
+ * is discovery of MALs, other EMACs, ZMII/RGMIIs, etc...
+ */
+static DECLARE_WAIT_QUEUE_HEAD(emac_probe_wait);
+
+/* Having stable interface names is a doomed idea. However, it would be nice
+ * if we didn't have completely random interface names at boot too :-) It's
+ * just a matter of making everybody's life easier. Since we are doing
+ * threaded probing, it's a bit harder though. The base idea here is that
+ * we make up a list of all emacs in the device-tree before we register the
+ * driver. Every emac will then wait for the previous one in the list to
+ * initialize before itself. We should also keep that list ordered by
+ * cell_index.
+ * That list is only 4 entries long, meaning that additional EMACs don't
+ * get ordering guarantees unless EMAC_BOOT_LIST_SIZE is increased.
+ */
+
+#define EMAC_BOOT_LIST_SIZE 4
+static struct device_node *emac_boot_list[EMAC_BOOT_LIST_SIZE];
+
+/* How long should I wait for dependent devices ? */
+#define EMAC_PROBE_DEP_TIMEOUT (HZ * 5)
+
+/* I don't want to litter system log with timeout errors
+ * when we have brain-damaged PHY.
+ */
+static inline void emac_report_timeout_error(struct emac_instance *dev,
+ const char *error)
+{
+ if (net_ratelimit())
+ printk(KERN_ERR "%s: %s\n", dev->ndev->name, error);
+}
+
+/* PHY polling intervals */
+#define PHY_POLL_LINK_ON HZ
+#define PHY_POLL_LINK_OFF (HZ / 5)
+
+/* Graceful stop timeouts in us.
+ * We should allow up to 1 frame time (full-duplex, ignoring collisions)
+ */
+#define STOP_TIMEOUT_10 1230
+#define STOP_TIMEOUT_100 124
+#define STOP_TIMEOUT_1000 13
+#define STOP_TIMEOUT_1000_JUMBO 73
+
+/* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */
+static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = {
+ "rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum",
+ "tx_packets_csum", "tx_undo", "rx_dropped_stack", "rx_dropped_oom",
+ "rx_dropped_error", "rx_dropped_resize", "rx_dropped_mtu",
+ "rx_stopped", "rx_bd_errors", "rx_bd_overrun", "rx_bd_bad_packet",
+ "rx_bd_runt_packet", "rx_bd_short_event", "rx_bd_alignment_error",
+ "rx_bd_bad_fcs", "rx_bd_packet_too_long", "rx_bd_out_of_range",
+ "rx_bd_in_range", "rx_parity", "rx_fifo_overrun", "rx_overrun",
+ "rx_bad_packet", "rx_runt_packet", "rx_short_event",
+ "rx_alignment_error", "rx_bad_fcs", "rx_packet_too_long",
+ "rx_out_of_range", "rx_in_range", "tx_dropped", "tx_bd_errors",
+ "tx_bd_bad_fcs", "tx_bd_carrier_loss", "tx_bd_excessive_deferral",
+ "tx_bd_excessive_collisions", "tx_bd_late_collision",
+ "tx_bd_multple_collisions", "tx_bd_single_collision",
+ "tx_bd_underrun", "tx_bd_sqe", "tx_parity", "tx_underrun", "tx_sqe",
+ "tx_errors"
+};
+
+static irqreturn_t emac_irq(int irq, void *dev_instance);
+static void emac_clean_tx_ring(struct emac_instance *dev);
+static void __emac_set_multicast_list(struct emac_instance *dev);
+
+static inline int emac_phy_supports_gige(int phy_mode)
+{
+ return phy_mode == PHY_MODE_GMII ||
+ phy_mode == PHY_MODE_RGMII ||
+ phy_mode == PHY_MODE_TBI ||
+ phy_mode == PHY_MODE_RTBI;
+}
+
+static inline int emac_phy_gpcs(int phy_mode)
+{
+ return phy_mode == PHY_MODE_TBI ||
+ phy_mode == PHY_MODE_RTBI;
+}
+
+static inline void emac_tx_enable(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r;
+
+ DBG(dev, "tx_enable" NL);
+
+ r = in_be32(&p->mr0);
+ if (!(r & EMAC_MR0_TXE))
+ out_be32(&p->mr0, r | EMAC_MR0_TXE);
+}
+
+static void emac_tx_disable(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r;
+
+ DBG(dev, "tx_disable" NL);
+
+ r = in_be32(&p->mr0);
+ if (r & EMAC_MR0_TXE) {
+ int n = dev->stop_timeout;
+ out_be32(&p->mr0, r & ~EMAC_MR0_TXE);
+ while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) {
+ udelay(1);
+ --n;
+ }
+ if (unlikely(!n))
+ emac_report_timeout_error(dev, "TX disable timeout");
+ }
+}
+
+static void emac_rx_enable(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r;
+
+ if (unlikely(test_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags)))
+ goto out;
+
+ DBG(dev, "rx_enable" NL);
+
+ r = in_be32(&p->mr0);
+ if (!(r & EMAC_MR0_RXE)) {
+ if (unlikely(!(r & EMAC_MR0_RXI))) {
+ /* Wait if previous async disable is still in progress */
+ int n = dev->stop_timeout;
+ while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) {
+ udelay(1);
+ --n;
+ }
+ if (unlikely(!n))
+ emac_report_timeout_error(dev,
+ "RX disable timeout");
+ }
+ out_be32(&p->mr0, r | EMAC_MR0_RXE);
+ }
+ out:
+ ;
+}
+
+static void emac_rx_disable(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r;
+
+ DBG(dev, "rx_disable" NL);
+
+ r = in_be32(&p->mr0);
+ if (r & EMAC_MR0_RXE) {
+ int n = dev->stop_timeout;
+ out_be32(&p->mr0, r & ~EMAC_MR0_RXE);
+ while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) {
+ udelay(1);
+ --n;
+ }
+ if (unlikely(!n))
+ emac_report_timeout_error(dev, "RX disable timeout");
+ }
+}
+
+static inline void emac_netif_stop(struct emac_instance *dev)
+{
+ netif_tx_lock_bh(dev->ndev);
+ dev->no_mcast = 1;
+ netif_tx_unlock_bh(dev->ndev);
+ dev->ndev->trans_start = jiffies; /* prevent tx timeout */
+ mal_poll_disable(dev->mal, &dev->commac);
+ netif_tx_disable(dev->ndev);
+}
+
+static inline void emac_netif_start(struct emac_instance *dev)
+{
+ netif_tx_lock_bh(dev->ndev);
+ dev->no_mcast = 0;
+ if (dev->mcast_pending && netif_running(dev->ndev))
+ __emac_set_multicast_list(dev);
+ netif_tx_unlock_bh(dev->ndev);
+
+ netif_wake_queue(dev->ndev);
+
+ /* NOTE: unconditional netif_wake_queue is only appropriate
+ * so long as all callers are assured to have free tx slots
+ * (taken from tg3... though the case where that is wrong is
+ * not terribly harmful)
+ */
+ mal_poll_enable(dev->mal, &dev->commac);
+}
+
+static inline void emac_rx_disable_async(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r;
+
+ DBG(dev, "rx_disable_async" NL);
+
+ r = in_be32(&p->mr0);
+ if (r & EMAC_MR0_RXE)
+ out_be32(&p->mr0, r & ~EMAC_MR0_RXE);
+}
+
+static int emac_reset(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ int n = 20;
+
+ DBG(dev, "reset" NL);
+
+ if (!dev->reset_failed) {
+ /* 40x erratum suggests stopping RX channel before reset,
+ * we stop TX as well
+ */
+ emac_rx_disable(dev);
+ emac_tx_disable(dev);
+ }
+
+ out_be32(&p->mr0, EMAC_MR0_SRST);
+ while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n)
+ --n;
+
+ if (n) {
+ dev->reset_failed = 0;
+ return 0;
+ } else {
+ emac_report_timeout_error(dev, "reset timeout");
+ dev->reset_failed = 1;
+ return -ETIMEDOUT;
+ }
+}
+
+static void emac_hash_mc(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u16 gaht[4] = { 0 };
+ struct dev_mc_list *dmi;
+
+ DBG(dev, "hash_mc %d" NL, dev->ndev->mc_count);
+
+ for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) {
+ int bit;
+ DBG2(dev, "mc %02x:%02x:%02x:%02x:%02x:%02x" NL,
+ dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
+ dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]);
+
+ bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26);
+ gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f);
+ }
+ out_be32(&p->gaht1, gaht[0]);
+ out_be32(&p->gaht2, gaht[1]);
+ out_be32(&p->gaht3, gaht[2]);
+ out_be32(&p->gaht4, gaht[3]);
+}
+
+static inline u32 emac_iff2rmr(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ u32 r;
+
+ r = EMAC_RMR_SP | EMAC_RMR_SFCS | EMAC_RMR_IAE | EMAC_RMR_BAE;
+
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ r |= EMAC4_RMR_BASE;
+ else
+ r |= EMAC_RMR_BASE;
+
+ if (ndev->flags & IFF_PROMISC)
+ r |= EMAC_RMR_PME;
+ else if (ndev->flags & IFF_ALLMULTI || ndev->mc_count > 32)
+ r |= EMAC_RMR_PMME;
+ else if (ndev->mc_count > 0)
+ r |= EMAC_RMR_MAE;
+
+ return r;
+}
+
+static u32 __emac_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size)
+{
+ u32 ret = EMAC_MR1_VLE | EMAC_MR1_IST | EMAC_MR1_TR0_MULT;
+
+ DBG2(dev, "__emac_calc_base_mr1" NL);
+
+ switch(tx_size) {
+ case 2048:
+ ret |= EMAC_MR1_TFS_2K;
+ break;
+ default:
+ printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+ dev->ndev->name, tx_size);
+ }
+
+ switch(rx_size) {
+ case 16384:
+ ret |= EMAC_MR1_RFS_16K;
+ break;
+ case 4096:
+ ret |= EMAC_MR1_RFS_4K;
+ break;
+ default:
+ printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+ dev->ndev->name, rx_size);
+ }
+
+ return ret;
+}
+
+static u32 __emac4_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size)
+{
+ u32 ret = EMAC_MR1_VLE | EMAC_MR1_IST | EMAC4_MR1_TR |
+ EMAC4_MR1_OBCI(dev->opb_bus_freq);
+
+ DBG2(dev, "__emac4_calc_base_mr1" NL);
+
+ switch(tx_size) {
+ case 4096:
+ ret |= EMAC4_MR1_TFS_4K;
+ break;
+ case 2048:
+ ret |= EMAC4_MR1_TFS_2K;
+ break;
+ default:
+ printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+ dev->ndev->name, tx_size);
+ }
+
+ switch(rx_size) {
+ case 16384:
+ ret |= EMAC4_MR1_RFS_16K;
+ break;
+ case 4096:
+ ret |= EMAC4_MR1_RFS_4K;
+ break;
+ case 2048:
+ ret |= EMAC4_MR1_RFS_2K;
+ break;
+ default:
+ printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+ dev->ndev->name, rx_size);
+ }
+
+ return ret;
+}
+
+static u32 emac_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size)
+{
+ return emac_has_feature(dev, EMAC_FTR_EMAC4) ?
+ __emac4_calc_base_mr1(dev, tx_size, rx_size) :
+ __emac_calc_base_mr1(dev, tx_size, rx_size);
+}
+
+static inline u32 emac_calc_trtr(struct emac_instance *dev, unsigned int size)
+{
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ return ((size >> 6) - 1) << EMAC_TRTR_SHIFT_EMAC4;
+ else
+ return ((size >> 6) - 1) << EMAC_TRTR_SHIFT;
+}
+
+static inline u32 emac_calc_rwmr(struct emac_instance *dev,
+ unsigned int low, unsigned int high)
+{
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ return (low << 22) | ( (high & 0x3ff) << 6);
+ else
+ return (low << 23) | ( (high & 0x1ff) << 7);
+}
+
+static int emac_configure(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ struct net_device *ndev = dev->ndev;
+ int tx_size, rx_size;
+ u32 r, mr1 = 0;
+
+ DBG(dev, "configure" NL);
+
+ if (emac_reset(dev) < 0)
+ return -ETIMEDOUT;
+
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+ tah_reset(dev->tah_dev);
+
+ DBG(dev, " duplex = %d, pause = %d, asym_pause = %d\n",
+ dev->phy.duplex, dev->phy.pause, dev->phy.asym_pause);
+
+ /* Default fifo sizes */
+ tx_size = dev->tx_fifo_size;
+ rx_size = dev->rx_fifo_size;
+
+ /* Check for full duplex */
+ if (dev->phy.duplex == DUPLEX_FULL)
+ mr1 |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001;
+
+ /* Adjust fifo sizes, mr1 and timeouts based on link speed */
+ dev->stop_timeout = STOP_TIMEOUT_10;
+ switch (dev->phy.speed) {
+ case SPEED_1000:
+ if (emac_phy_gpcs(dev->phy.mode)) {
+ mr1 |= EMAC_MR1_MF_1000GPCS |
+ EMAC_MR1_MF_IPPA(dev->phy.address);
+
+ /* Put some arbitrary OUI, Manuf & Rev IDs so we can
+ * identify this GPCS PHY later.
+ */
+ out_be32(&p->ipcr, 0xdeadbeef);
+ } else
+ mr1 |= EMAC_MR1_MF_1000;
+
+ /* Extended fifo sizes */
+ tx_size = dev->tx_fifo_size_gige;
+ rx_size = dev->rx_fifo_size_gige;
+
+ if (dev->ndev->mtu > ETH_DATA_LEN) {
+ mr1 |= EMAC_MR1_JPSM;
+ dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO;
+ } else
+ dev->stop_timeout = STOP_TIMEOUT_1000;
+ break;
+ case SPEED_100:
+ mr1 |= EMAC_MR1_MF_100;
+ dev->stop_timeout = STOP_TIMEOUT_100;
+ break;
+ default: /* make gcc happy */
+ break;
+ }
+
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_set_speed(dev->rgmii_dev, dev->rgmii_port,
+ dev->phy.speed);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_set_speed(dev->zmii_dev, dev->zmii_port, dev->phy.speed);
+
+ /* on 40x erratum forces us to NOT use integrated flow control,
+ * let's hope it works on 44x ;)
+ */
+ if (!emac_has_feature(dev, EMAC_FTR_NO_FLOW_CONTROL_40x) &&
+ dev->phy.duplex == DUPLEX_FULL) {
+ if (dev->phy.pause)
+ mr1 |= EMAC_MR1_EIFC | EMAC_MR1_APP;
+ else if (dev->phy.asym_pause)
+ mr1 |= EMAC_MR1_APP;
+ }
+
+ /* Add base settings & fifo sizes & program MR1 */
+ mr1 |= emac_calc_base_mr1(dev, tx_size, rx_size);
+ out_be32(&p->mr1, mr1);
+
+ /* Set individual MAC address */
+ out_be32(&p->iahr, (ndev->dev_addr[0] << 8) | ndev->dev_addr[1]);
+ out_be32(&p->ialr, (ndev->dev_addr[2] << 24) |
+ (ndev->dev_addr[3] << 16) | (ndev->dev_addr[4] << 8) |
+ ndev->dev_addr[5]);
+
+ /* VLAN Tag Protocol ID */
+ out_be32(&p->vtpid, 0x8100);
+
+ /* Receive mode register */
+ r = emac_iff2rmr(ndev);
+ if (r & EMAC_RMR_MAE)
+ emac_hash_mc(dev);
+ out_be32(&p->rmr, r);
+
+ /* FIFOs thresholds */
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ r = EMAC4_TMR1((dev->mal_burst_size / dev->fifo_entry_size) + 1,
+ tx_size / 2 / dev->fifo_entry_size);
+ else
+ r = EMAC_TMR1((dev->mal_burst_size / dev->fifo_entry_size) + 1,
+ tx_size / 2 / dev->fifo_entry_size);
+ out_be32(&p->tmr1, r);
+ out_be32(&p->trtr, emac_calc_trtr(dev, tx_size / 2));
+
+ /* PAUSE frame is sent when RX FIFO reaches its high-water mark,
+ there should be still enough space in FIFO to allow the our link
+ partner time to process this frame and also time to send PAUSE
+ frame itself.
+
+ Here is the worst case scenario for the RX FIFO "headroom"
+ (from "The Switch Book") (100Mbps, without preamble, inter-frame gap):
+
+ 1) One maximum-length frame on TX 1522 bytes
+ 2) One PAUSE frame time 64 bytes
+ 3) PAUSE frame decode time allowance 64 bytes
+ 4) One maximum-length frame on RX 1522 bytes
+ 5) Round-trip propagation delay of the link (100Mb) 15 bytes
+ ----------
+ 3187 bytes
+
+ I chose to set high-water mark to RX_FIFO_SIZE / 4 (1024 bytes)
+ low-water mark to RX_FIFO_SIZE / 8 (512 bytes)
+ */
+ r = emac_calc_rwmr(dev, rx_size / 8 / dev->fifo_entry_size,
+ rx_size / 4 / dev->fifo_entry_size);
+ out_be32(&p->rwmr, r);
+
+ /* Set PAUSE timer to the maximum */
+ out_be32(&p->ptr, 0xffff);
+
+ /* IRQ sources */
+ r = EMAC_ISR_OVR | EMAC_ISR_BP | EMAC_ISR_SE |
+ EMAC_ISR_ALE | EMAC_ISR_BFCS | EMAC_ISR_PTLE | EMAC_ISR_ORE |
+ EMAC_ISR_IRE | EMAC_ISR_TE;
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ r |= EMAC4_ISR_TXPE | EMAC4_ISR_RXPE /* | EMAC4_ISR_TXUE |
+ EMAC4_ISR_RXOE | */;
+ out_be32(&p->iser, r);
+
+ /* We need to take GPCS PHY out of isolate mode after EMAC reset */
+ if (emac_phy_gpcs(dev->phy.mode))
+ emac_mii_reset_phy(&dev->phy);
+
+ return 0;
+}
+
+static void emac_reinitialize(struct emac_instance *dev)
+{
+ DBG(dev, "reinitialize" NL);
+
+ emac_netif_stop(dev);
+ if (!emac_configure(dev)) {
+ emac_tx_enable(dev);
+ emac_rx_enable(dev);
+ }
+ emac_netif_start(dev);
+}
+
+static void emac_full_tx_reset(struct emac_instance *dev)
+{
+ DBG(dev, "full_tx_reset" NL);
+
+ emac_tx_disable(dev);
+ mal_disable_tx_channel(dev->mal, dev->mal_tx_chan);
+ emac_clean_tx_ring(dev);
+ dev->tx_cnt = dev->tx_slot = dev->ack_slot = 0;
+
+ emac_configure(dev);
+
+ mal_enable_tx_channel(dev->mal, dev->mal_tx_chan);
+ emac_tx_enable(dev);
+ emac_rx_enable(dev);
+}
+
+static void emac_reset_work(struct work_struct *work)
+{
+ struct emac_instance *dev = container_of(work, struct emac_instance, reset_work);
+
+ DBG(dev, "reset_work" NL);
+
+ mutex_lock(&dev->link_lock);
+ emac_netif_stop(dev);
+ emac_full_tx_reset(dev);
+ emac_netif_start(dev);
+ mutex_unlock(&dev->link_lock);
+}
+
+static void emac_tx_timeout(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ DBG(dev, "tx_timeout" NL);
+
+ schedule_work(&dev->reset_work);
+}
+
+
+static inline int emac_phy_done(struct emac_instance *dev, u32 stacr)
+{
+ int done = !!(stacr & EMAC_STACR_OC);
+
+ if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))
+ done = !done;
+
+ return done;
+};
+
+static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r = 0;
+ int n, err = -ETIMEDOUT;
+
+ mutex_lock(&dev->mdio_lock);
+
+ DBG2(dev, "mdio_read(%02x,%02x)" NL, id, reg);
+
+ /* Enable proper MDIO port */
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_get_mdio(dev->zmii_dev, dev->zmii_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);
+
+ /* Wait for management interface to become idle */
+ n = 10;
+ while (!emac_phy_done(dev, in_be32(&p->stacr))) {
+ udelay(1);
+ if (!--n) {
+ DBG2(dev, " -> timeout wait idle\n");
+ goto bail;
+ }
+ }
+
+ /* Issue read command */
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ r = EMAC4_STACR_BASE(dev->opb_bus_freq);
+ else
+ r = EMAC_STACR_BASE(dev->opb_bus_freq);
+ if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))
+ r |= EMAC_STACR_OC;
+ if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR))
+ r |= EMACX_STACR_STAC_READ;
+ else
+ r |= EMAC_STACR_STAC_READ;
+ r |= (reg & EMAC_STACR_PRA_MASK)
+ | ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT);
+ out_be32(&p->stacr, r);
+
+ /* Wait for read to complete */
+ n = 100;
+ while (!emac_phy_done(dev, (r = in_be32(&p->stacr)))) {
+ udelay(1);
+ if (!--n) {
+ DBG2(dev, " -> timeout wait complete\n");
+ goto bail;
+ }
+ }
+
+ if (unlikely(r & EMAC_STACR_PHYE)) {
+ DBG(dev, "mdio_read(%02x, %02x) failed" NL, id, reg);
+ err = -EREMOTEIO;
+ goto bail;
+ }
+
+ r = ((r >> EMAC_STACR_PHYD_SHIFT) & EMAC_STACR_PHYD_MASK);
+
+ DBG2(dev, "mdio_read -> %04x" NL, r);
+ err = 0;
+ bail:
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_put_mdio(dev->zmii_dev, dev->zmii_port);
+ mutex_unlock(&dev->mdio_lock);
+
+ return err == 0 ? r : err;
+}
+
+static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg,
+ u16 val)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 r = 0;
+ int n, err = -ETIMEDOUT;
+
+ mutex_lock(&dev->mdio_lock);
+
+ DBG2(dev, "mdio_write(%02x,%02x,%04x)" NL, id, reg, val);
+
+ /* Enable proper MDIO port */
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_get_mdio(dev->zmii_dev, dev->zmii_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);
+
+ /* Wait for management interface to be idle */
+ n = 10;
+ while (!emac_phy_done(dev, in_be32(&p->stacr))) {
+ udelay(1);
+ if (!--n) {
+ DBG2(dev, " -> timeout wait idle\n");
+ goto bail;
+ }
+ }
+
+ /* Issue write command */
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ r = EMAC4_STACR_BASE(dev->opb_bus_freq);
+ else
+ r = EMAC_STACR_BASE(dev->opb_bus_freq);
+ if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))
+ r |= EMAC_STACR_OC;
+ if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR))
+ r |= EMACX_STACR_STAC_WRITE;
+ else
+ r |= EMAC_STACR_STAC_WRITE;
+ r |= (reg & EMAC_STACR_PRA_MASK) |
+ ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT) |
+ (val << EMAC_STACR_PHYD_SHIFT);
+ out_be32(&p->stacr, r);
+
+ /* Wait for write to complete */
+ n = 100;
+ while (!emac_phy_done(dev, in_be32(&p->stacr))) {
+ udelay(1);
+ if (!--n) {
+ DBG2(dev, " -> timeout wait complete\n");
+ goto bail;
+ }
+ }
+ err = 0;
+ bail:
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_put_mdio(dev->zmii_dev, dev->zmii_port);
+ mutex_unlock(&dev->mdio_lock);
+}
+
+static int emac_mdio_read(struct net_device *ndev, int id, int reg)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ int res;
+
+ res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev,
+ (u8) id, (u8) reg);
+ return res;
+}
+
+static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ __emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev,
+ (u8) id, (u8) reg, (u16) val);
+}
+
+/* Tx lock BH */
+static void __emac_set_multicast_list(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ u32 rmr = emac_iff2rmr(dev->ndev);
+
+ DBG(dev, "__multicast %08x" NL, rmr);
+
+ /* I decided to relax register access rules here to avoid
+ * full EMAC reset.
+ *
+ * There is a real problem with EMAC4 core if we use MWSW_001 bit
+ * in MR1 register and do a full EMAC reset.
+ * One TX BD status update is delayed and, after EMAC reset, it
+ * never happens, resulting in TX hung (it'll be recovered by TX
+ * timeout handler eventually, but this is just gross).
+ * So we either have to do full TX reset or try to cheat here :)
+ *
+ * The only required change is to RX mode register, so I *think* all
+ * we need is just to stop RX channel. This seems to work on all
+ * tested SoCs. --ebs
+ *
+ * If we need the full reset, we might just trigger the workqueue
+ * and do it async... a bit nasty but should work --BenH
+ */
+ dev->mcast_pending = 0;
+ emac_rx_disable(dev);
+ if (rmr & EMAC_RMR_MAE)
+ emac_hash_mc(dev);
+ out_be32(&p->rmr, rmr);
+ emac_rx_enable(dev);
+}
+
+/* Tx lock BH */
+static void emac_set_multicast_list(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ DBG(dev, "multicast" NL);
+
+ BUG_ON(!netif_running(dev->ndev));
+
+ if (dev->no_mcast) {
+ dev->mcast_pending = 1;
+ return;
+ }
+ __emac_set_multicast_list(dev);
+}
+
+static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu)
+{
+ int rx_sync_size = emac_rx_sync_size(new_mtu);
+ int rx_skb_size = emac_rx_skb_size(new_mtu);
+ int i, ret = 0;
+
+ mutex_lock(&dev->link_lock);
+ emac_netif_stop(dev);
+ emac_rx_disable(dev);
+ mal_disable_rx_channel(dev->mal, dev->mal_rx_chan);
+
+ if (dev->rx_sg_skb) {
+ ++dev->estats.rx_dropped_resize;
+ dev_kfree_skb(dev->rx_sg_skb);
+ dev->rx_sg_skb = NULL;
+ }
+
+ /* Make a first pass over RX ring and mark BDs ready, dropping
+ * non-processed packets on the way. We need this as a separate pass
+ * to simplify error recovery in the case of allocation failure later.
+ */
+ for (i = 0; i < NUM_RX_BUFF; ++i) {
+ if (dev->rx_desc[i].ctrl & MAL_RX_CTRL_FIRST)
+ ++dev->estats.rx_dropped_resize;
+
+ dev->rx_desc[i].data_len = 0;
+ dev->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY |
+ (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);
+ }
+
+ /* Reallocate RX ring only if bigger skb buffers are required */
+ if (rx_skb_size <= dev->rx_skb_size)
+ goto skip;
+
+ /* Second pass, allocate new skbs */
+ for (i = 0; i < NUM_RX_BUFF; ++i) {
+ struct sk_buff *skb = alloc_skb(rx_skb_size, GFP_ATOMIC);
+ if (!skb) {
+ ret = -ENOMEM;
+ goto oom;
+ }
+
+ BUG_ON(!dev->rx_skb[i]);
+ dev_kfree_skb(dev->rx_skb[i]);
+
+ skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2);
+ dev->rx_desc[i].data_ptr =
+ dma_map_single(&dev->ofdev->dev, skb->data - 2, rx_sync_size,
+ DMA_FROM_DEVICE) + 2;
+ dev->rx_skb[i] = skb;
+ }
+ skip:
+ /* Check if we need to change "Jumbo" bit in MR1 */
+ if ((new_mtu > ETH_DATA_LEN) ^ (dev->ndev->mtu > ETH_DATA_LEN)) {
+ /* This is to prevent starting RX channel in emac_rx_enable() */
+ set_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
+
+ dev->ndev->mtu = new_mtu;
+ emac_full_tx_reset(dev);
+ }
+
+ mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(new_mtu));
+ oom:
+ /* Restart RX */
+ clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
+ dev->rx_slot = 0;
+ mal_enable_rx_channel(dev->mal, dev->mal_rx_chan);
+ emac_rx_enable(dev);
+ emac_netif_start(dev);
+ mutex_unlock(&dev->link_lock);
+
+ return ret;
+}
+
+/* Process ctx, rtnl_lock semaphore */
+static int emac_change_mtu(struct net_device *ndev, int new_mtu)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ int ret = 0;
+
+ if (new_mtu < EMAC_MIN_MTU || new_mtu > dev->max_mtu)
+ return -EINVAL;
+
+ DBG(dev, "change_mtu(%d)" NL, new_mtu);
+
+ if (netif_running(ndev)) {
+ /* Check if we really need to reinitalize RX ring */
+ if (emac_rx_skb_size(ndev->mtu) != emac_rx_skb_size(new_mtu))
+ ret = emac_resize_rx_ring(dev, new_mtu);
+ }
+
+ if (!ret) {
+ ndev->mtu = new_mtu;
+ dev->rx_skb_size = emac_rx_skb_size(new_mtu);
+ dev->rx_sync_size = emac_rx_sync_size(new_mtu);
+ }
+
+ return ret;
+}
+
+static void emac_clean_tx_ring(struct emac_instance *dev)
+{
+ int i;
+
+ for (i = 0; i < NUM_TX_BUFF; ++i) {
+ if (dev->tx_skb[i]) {
+ dev_kfree_skb(dev->tx_skb[i]);
+ dev->tx_skb[i] = NULL;
+ if (dev->tx_desc[i].ctrl & MAL_TX_CTRL_READY)
+ ++dev->estats.tx_dropped;
+ }
+ dev->tx_desc[i].ctrl = 0;
+ dev->tx_desc[i].data_ptr = 0;
+ }
+}
+
+static void emac_clean_rx_ring(struct emac_instance *dev)
+{
+ int i;
+
+ for (i = 0; i < NUM_RX_BUFF; ++i)
+ if (dev->rx_skb[i]) {
+ dev->rx_desc[i].ctrl = 0;
+ dev_kfree_skb(dev->rx_skb[i]);
+ dev->rx_skb[i] = NULL;
+ dev->rx_desc[i].data_ptr = 0;
+ }
+
+ if (dev->rx_sg_skb) {
+ dev_kfree_skb(dev->rx_sg_skb);
+ dev->rx_sg_skb = NULL;
+ }
+}
+
+static inline int emac_alloc_rx_skb(struct emac_instance *dev, int slot,
+ gfp_t flags)
+{
+ struct sk_buff *skb = alloc_skb(dev->rx_skb_size, flags);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ dev->rx_skb[slot] = skb;
+ dev->rx_desc[slot].data_len = 0;
+
+ skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2);
+ dev->rx_desc[slot].data_ptr =
+ dma_map_single(&dev->ofdev->dev, skb->data - 2, dev->rx_sync_size,
+ DMA_FROM_DEVICE) + 2;
+ wmb();
+ dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY |
+ (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);
+
+ return 0;
+}
+
+static void emac_print_link_status(struct emac_instance *dev)
+{
+ if (netif_carrier_ok(dev->ndev))
+ printk(KERN_INFO "%s: link is up, %d %s%s\n",
+ dev->ndev->name, dev->phy.speed,
+ dev->phy.duplex == DUPLEX_FULL ? "FDX" : "HDX",
+ dev->phy.pause ? ", pause enabled" :
+ dev->phy.asym_pause ? ", asymmetric pause enabled" : "");
+ else
+ printk(KERN_INFO "%s: link is down\n", dev->ndev->name);
+}
+
+/* Process ctx, rtnl_lock semaphore */
+static int emac_open(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ int err, i;
+
+ DBG(dev, "open" NL);
+
+ /* Setup error IRQ handler */
+ err = request_irq(dev->emac_irq, emac_irq, 0, "EMAC", dev);
+ if (err) {
+ printk(KERN_ERR "%s: failed to request IRQ %d\n",
+ ndev->name, dev->emac_irq);
+ return err;
+ }
+
+ /* Allocate RX ring */
+ for (i = 0; i < NUM_RX_BUFF; ++i)
+ if (emac_alloc_rx_skb(dev, i, GFP_KERNEL)) {
+ printk(KERN_ERR "%s: failed to allocate RX ring\n",
+ ndev->name);
+ goto oom;
+ }
+
+ dev->tx_cnt = dev->tx_slot = dev->ack_slot = dev->rx_slot = 0;
+ clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
+ dev->rx_sg_skb = NULL;
+
+ mutex_lock(&dev->link_lock);
+
+ /* XXX Start PHY polling now. Shouldn't wr do like sungem instead and
+ * always poll the PHY even when the iface is down ? That would allow
+ * things like laptop-net to work. --BenH
+ */
+ if (dev->phy.address >= 0) {
+ int link_poll_interval;
+ if (dev->phy.def->ops->poll_link(&dev->phy)) {
+ dev->phy.def->ops->read_link(&dev->phy);
+ netif_carrier_on(dev->ndev);
+ link_poll_interval = PHY_POLL_LINK_ON;
+ } else {
+ netif_carrier_off(dev->ndev);
+ link_poll_interval = PHY_POLL_LINK_OFF;
+ }
+ dev->link_polling = 1;
+ wmb();
+ schedule_delayed_work(&dev->link_work, link_poll_interval);
+ emac_print_link_status(dev);
+ } else
+ netif_carrier_on(dev->ndev);
+
+ emac_configure(dev);
+ mal_poll_add(dev->mal, &dev->commac);
+ mal_enable_tx_channel(dev->mal, dev->mal_tx_chan);
+ mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(ndev->mtu));
+ mal_enable_rx_channel(dev->mal, dev->mal_rx_chan);
+ emac_tx_enable(dev);
+ emac_rx_enable(dev);
+ emac_netif_start(dev);
+
+ mutex_unlock(&dev->link_lock);
+
+ return 0;
+ oom:
+ emac_clean_rx_ring(dev);
+ free_irq(dev->emac_irq, dev);
+
+ return -ENOMEM;
+}
+
+/* BHs disabled */
+#if 0
+static int emac_link_differs(struct emac_instance *dev)
+{
+ u32 r = in_be32(&dev->emacp->mr1);
+
+ int duplex = r & EMAC_MR1_FDE ? DUPLEX_FULL : DUPLEX_HALF;
+ int speed, pause, asym_pause;
+
+ if (r & EMAC_MR1_MF_1000)
+ speed = SPEED_1000;
+ else if (r & EMAC_MR1_MF_100)
+ speed = SPEED_100;
+ else
+ speed = SPEED_10;
+
+ switch (r & (EMAC_MR1_EIFC | EMAC_MR1_APP)) {
+ case (EMAC_MR1_EIFC | EMAC_MR1_APP):
+ pause = 1;
+ asym_pause = 0;
+ break;
+ case EMAC_MR1_APP:
+ pause = 0;
+ asym_pause = 1;
+ break;
+ default:
+ pause = asym_pause = 0;
+ }
+ return speed != dev->phy.speed || duplex != dev->phy.duplex ||
+ pause != dev->phy.pause || asym_pause != dev->phy.asym_pause;
+}
+#endif
+
+static void emac_link_timer(struct work_struct *work)
+{
+ struct emac_instance *dev =
+ container_of((struct delayed_work *)work,
+ struct emac_instance, link_work);
+ int link_poll_interval;
+
+ mutex_lock(&dev->link_lock);
+
+ DBG2(dev, "link timer" NL);
+
+ if (dev->phy.def->ops->poll_link(&dev->phy)) {
+ if (!netif_carrier_ok(dev->ndev)) {
+ /* Get new link parameters */
+ dev->phy.def->ops->read_link(&dev->phy);
+
+ netif_carrier_on(dev->ndev);
+ emac_netif_stop(dev);
+ emac_full_tx_reset(dev);
+ emac_netif_start(dev);
+ emac_print_link_status(dev);
+ }
+ link_poll_interval = PHY_POLL_LINK_ON;
+ } else {
+ if (netif_carrier_ok(dev->ndev)) {
+ emac_reinitialize(dev);
+ netif_carrier_off(dev->ndev);
+ netif_tx_disable(dev->ndev);
+ emac_print_link_status(dev);
+ }
+ link_poll_interval = PHY_POLL_LINK_OFF;
+ }
+ schedule_delayed_work(&dev->link_work, link_poll_interval);
+
+ mutex_unlock(&dev->link_lock);
+}
+
+static void emac_force_link_update(struct emac_instance *dev)
+{
+ netif_carrier_off(dev->ndev);
+ if (dev->link_polling) {
+ cancel_rearming_delayed_work(&dev->link_work);
+ if (dev->link_polling)
+ schedule_delayed_work(&dev->link_work, PHY_POLL_LINK_OFF);
+ }
+}
+
+/* Process ctx, rtnl_lock semaphore */
+static int emac_close(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ DBG(dev, "close" NL);
+
+ if (dev->phy.address >= 0)
+ cancel_rearming_delayed_work(&dev->link_work);
+
+ emac_netif_stop(dev);
+ flush_scheduled_work();
+
+ emac_rx_disable(dev);
+ emac_tx_disable(dev);
+ mal_disable_rx_channel(dev->mal, dev->mal_rx_chan);
+ mal_disable_tx_channel(dev->mal, dev->mal_tx_chan);
+ mal_poll_del(dev->mal, &dev->commac);
+
+ emac_clean_tx_ring(dev);
+ emac_clean_rx_ring(dev);
+
+ free_irq(dev->emac_irq, dev);
+
+ return 0;
+}
+
+static inline u16 emac_tx_csum(struct emac_instance *dev,
+ struct sk_buff *skb)
+{
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH &&
+ skb->ip_summed == CHECKSUM_PARTIAL)) {
+ ++dev->stats.tx_packets_csum;
+ return EMAC_TX_CTRL_TAH_CSUM;
+ }
+ return 0;
+}
+
+static inline int emac_xmit_finish(struct emac_instance *dev, int len)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+ struct net_device *ndev = dev->ndev;
+
+ /* Send the packet out. If the if makes a significant perf
+ * difference, then we can store the TMR0 value in "dev"
+ * instead
+ */
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ out_be32(&p->tmr0, EMAC4_TMR0_XMIT);
+ else
+ out_be32(&p->tmr0, EMAC_TMR0_XMIT);
+
+ if (unlikely(++dev->tx_cnt == NUM_TX_BUFF)) {
+ netif_stop_queue(ndev);
+ DBG2(dev, "stopped TX queue" NL);
+ }
+
+ ndev->trans_start = jiffies;
+ ++dev->stats.tx_packets;
+ dev->stats.tx_bytes += len;
+
+ return 0;
+}
+
+/* Tx lock BH */
+static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ unsigned int len = skb->len;
+ int slot;
+
+ u16 ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY |
+ MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb);
+
+ slot = dev->tx_slot++;
+ if (dev->tx_slot == NUM_TX_BUFF) {
+ dev->tx_slot = 0;
+ ctrl |= MAL_TX_CTRL_WRAP;
+ }
+
+ DBG2(dev, "xmit(%u) %d" NL, len, slot);
+
+ dev->tx_skb[slot] = skb;
+ dev->tx_desc[slot].data_ptr = dma_map_single(&dev->ofdev->dev,
+ skb->data, len,
+ DMA_TO_DEVICE);
+ dev->tx_desc[slot].data_len = (u16) len;
+ wmb();
+ dev->tx_desc[slot].ctrl = ctrl;
+
+ return emac_xmit_finish(dev, len);
+}
+
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+static inline int emac_xmit_split(struct emac_instance *dev, int slot,
+ u32 pd, int len, int last, u16 base_ctrl)
+{
+ while (1) {
+ u16 ctrl = base_ctrl;
+ int chunk = min(len, MAL_MAX_TX_SIZE);
+ len -= chunk;
+
+ slot = (slot + 1) % NUM_TX_BUFF;
+
+ if (last && !len)
+ ctrl |= MAL_TX_CTRL_LAST;
+ if (slot == NUM_TX_BUFF - 1)
+ ctrl |= MAL_TX_CTRL_WRAP;
+
+ dev->tx_skb[slot] = NULL;
+ dev->tx_desc[slot].data_ptr = pd;
+ dev->tx_desc[slot].data_len = (u16) chunk;
+ dev->tx_desc[slot].ctrl = ctrl;
+ ++dev->tx_cnt;
+
+ if (!len)
+ break;
+
+ pd += chunk;
+ }
+ return slot;
+}
+
+/* Tx lock BH disabled (SG version for TAH equipped EMACs) */
+static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ int len = skb->len, chunk;
+ int slot, i;
+ u16 ctrl;
+ u32 pd;
+
+ /* This is common "fast" path */
+ if (likely(!nr_frags && len <= MAL_MAX_TX_SIZE))
+ return emac_start_xmit(skb, ndev);
+
+ len -= skb->data_len;
+
+ /* Note, this is only an *estimation*, we can still run out of empty
+ * slots because of the additional fragmentation into
+ * MAL_MAX_TX_SIZE-sized chunks
+ */
+ if (unlikely(dev->tx_cnt + nr_frags + mal_tx_chunks(len) > NUM_TX_BUFF))
+ goto stop_queue;
+
+ ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY |
+ emac_tx_csum(dev, skb);
+ slot = dev->tx_slot;
+
+ /* skb data */
+ dev->tx_skb[slot] = NULL;
+ chunk = min(len, MAL_MAX_TX_SIZE);
+ dev->tx_desc[slot].data_ptr = pd =
+ dma_map_single(&dev->ofdev->dev, skb->data, len, DMA_TO_DEVICE);
+ dev->tx_desc[slot].data_len = (u16) chunk;
+ len -= chunk;
+ if (unlikely(len))
+ slot = emac_xmit_split(dev, slot, pd + chunk, len, !nr_frags,
+ ctrl);
+ /* skb fragments */
+ for (i = 0; i < nr_frags; ++i) {
+ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+ len = frag->size;
+
+ if (unlikely(dev->tx_cnt + mal_tx_chunks(len) >= NUM_TX_BUFF))
+ goto undo_frame;
+
+ pd = dma_map_page(&dev->ofdev->dev, frag->page, frag->page_offset, len,
+ DMA_TO_DEVICE);
+
+ slot = emac_xmit_split(dev, slot, pd, len, i == nr_frags - 1,
+ ctrl);
+ }
+
+ DBG2(dev, "xmit_sg(%u) %d - %d" NL, skb->len, dev->tx_slot, slot);
+
+ /* Attach skb to the last slot so we don't release it too early */
+ dev->tx_skb[slot] = skb;
+
+ /* Send the packet out */
+ if (dev->tx_slot == NUM_TX_BUFF - 1)
+ ctrl |= MAL_TX_CTRL_WRAP;
+ wmb();
+ dev->tx_desc[dev->tx_slot].ctrl = ctrl;
+ dev->tx_slot = (slot + 1) % NUM_TX_BUFF;
+
+ return emac_xmit_finish(dev, skb->len);
+
+ undo_frame:
+ /* Well, too bad. Our previous estimation was overly optimistic.
+ * Undo everything.
+ */
+ while (slot != dev->tx_slot) {
+ dev->tx_desc[slot].ctrl = 0;
+ --dev->tx_cnt;
+ if (--slot < 0)
+ slot = NUM_TX_BUFF - 1;
+ }
+ ++dev->estats.tx_undo;
+
+ stop_queue:
+ netif_stop_queue(ndev);
+ DBG2(dev, "stopped TX queue" NL);
+ return 1;
+}
+#else
+# define emac_start_xmit_sg emac_start_xmit
+#endif /* !defined(CONFIG_IBM_NEW_EMAC_TAH) */
+
+/* Tx lock BHs */
+static void emac_parse_tx_error(struct emac_instance *dev, u16 ctrl)
+{
+ struct emac_error_stats *st = &dev->estats;
+
+ DBG(dev, "BD TX error %04x" NL, ctrl);
+
+ ++st->tx_bd_errors;
+ if (ctrl & EMAC_TX_ST_BFCS)
+ ++st->tx_bd_bad_fcs;
+ if (ctrl & EMAC_TX_ST_LCS)
+ ++st->tx_bd_carrier_loss;
+ if (ctrl & EMAC_TX_ST_ED)
+ ++st->tx_bd_excessive_deferral;
+ if (ctrl & EMAC_TX_ST_EC)
+ ++st->tx_bd_excessive_collisions;
+ if (ctrl & EMAC_TX_ST_LC)
+ ++st->tx_bd_late_collision;
+ if (ctrl & EMAC_TX_ST_MC)
+ ++st->tx_bd_multple_collisions;
+ if (ctrl & EMAC_TX_ST_SC)
+ ++st->tx_bd_single_collision;
+ if (ctrl & EMAC_TX_ST_UR)
+ ++st->tx_bd_underrun;
+ if (ctrl & EMAC_TX_ST_SQE)
+ ++st->tx_bd_sqe;
+}
+
+static void emac_poll_tx(void *param)
+{
+ struct emac_instance *dev = param;
+ u32 bad_mask;
+
+ DBG2(dev, "poll_tx, %d %d" NL, dev->tx_cnt, dev->ack_slot);
+
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+ bad_mask = EMAC_IS_BAD_TX_TAH;
+ else
+ bad_mask = EMAC_IS_BAD_TX;
+
+ netif_tx_lock_bh(dev->ndev);
+ if (dev->tx_cnt) {
+ u16 ctrl;
+ int slot = dev->ack_slot, n = 0;
+ again:
+ ctrl = dev->tx_desc[slot].ctrl;
+ if (!(ctrl & MAL_TX_CTRL_READY)) {
+ struct sk_buff *skb = dev->tx_skb[slot];
+ ++n;
+
+ if (skb) {
+ dev_kfree_skb(skb);
+ dev->tx_skb[slot] = NULL;
+ }
+ slot = (slot + 1) % NUM_TX_BUFF;
+
+ if (unlikely(ctrl & bad_mask))
+ emac_parse_tx_error(dev, ctrl);
+
+ if (--dev->tx_cnt)
+ goto again;
+ }
+ if (n) {
+ dev->ack_slot = slot;
+ if (netif_queue_stopped(dev->ndev) &&
+ dev->tx_cnt < EMAC_TX_WAKEUP_THRESH)
+ netif_wake_queue(dev->ndev);
+
+ DBG2(dev, "tx %d pkts" NL, n);
+ }
+ }
+ netif_tx_unlock_bh(dev->ndev);
+}
+
+static inline void emac_recycle_rx_skb(struct emac_instance *dev, int slot,
+ int len)
+{
+ struct sk_buff *skb = dev->rx_skb[slot];
+
+ DBG2(dev, "recycle %d %d" NL, slot, len);
+
+ if (len)
+ dma_map_single(&dev->ofdev->dev, skb->data - 2,
+ EMAC_DMA_ALIGN(len + 2), DMA_FROM_DEVICE);
+
+ dev->rx_desc[slot].data_len = 0;
+ wmb();
+ dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY |
+ (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);
+}
+
+static void emac_parse_rx_error(struct emac_instance *dev, u16 ctrl)
+{
+ struct emac_error_stats *st = &dev->estats;
+
+ DBG(dev, "BD RX error %04x" NL, ctrl);
+
+ ++st->rx_bd_errors;
+ if (ctrl & EMAC_RX_ST_OE)
+ ++st->rx_bd_overrun;
+ if (ctrl & EMAC_RX_ST_BP)
+ ++st->rx_bd_bad_packet;
+ if (ctrl & EMAC_RX_ST_RP)
+ ++st->rx_bd_runt_packet;
+ if (ctrl & EMAC_RX_ST_SE)
+ ++st->rx_bd_short_event;
+ if (ctrl & EMAC_RX_ST_AE)
+ ++st->rx_bd_alignment_error;
+ if (ctrl & EMAC_RX_ST_BFCS)
+ ++st->rx_bd_bad_fcs;
+ if (ctrl & EMAC_RX_ST_PTL)
+ ++st->rx_bd_packet_too_long;
+ if (ctrl & EMAC_RX_ST_ORE)
+ ++st->rx_bd_out_of_range;
+ if (ctrl & EMAC_RX_ST_IRE)
+ ++st->rx_bd_in_range;
+}
+
+static inline void emac_rx_csum(struct emac_instance *dev,
+ struct sk_buff *skb, u16 ctrl)
+{
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+ if (!ctrl && dev->tah_dev) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ ++dev->stats.rx_packets_csum;
+ }
+#endif
+}
+
+static inline int emac_rx_sg_append(struct emac_instance *dev, int slot)
+{
+ if (likely(dev->rx_sg_skb != NULL)) {
+ int len = dev->rx_desc[slot].data_len;
+ int tot_len = dev->rx_sg_skb->len + len;
+
+ if (unlikely(tot_len + 2 > dev->rx_skb_size)) {
+ ++dev->estats.rx_dropped_mtu;
+ dev_kfree_skb(dev->rx_sg_skb);
+ dev->rx_sg_skb = NULL;
+ } else {
+ cacheable_memcpy(skb_tail_pointer(dev->rx_sg_skb),
+ dev->rx_skb[slot]->data, len);
+ skb_put(dev->rx_sg_skb, len);
+ emac_recycle_rx_skb(dev, slot, len);
+ return 0;
+ }
+ }
+ emac_recycle_rx_skb(dev, slot, 0);
+ return -1;
+}
+
+/* NAPI poll context */
+static int emac_poll_rx(void *param, int budget)
+{
+ struct emac_instance *dev = param;
+ int slot = dev->rx_slot, received = 0;
+
+ DBG2(dev, "poll_rx(%d)" NL, budget);
+
+ again:
+ while (budget > 0) {
+ int len;
+ struct sk_buff *skb;
+ u16 ctrl = dev->rx_desc[slot].ctrl;
+
+ if (ctrl & MAL_RX_CTRL_EMPTY)
+ break;
+
+ skb = dev->rx_skb[slot];
+ mb();
+ len = dev->rx_desc[slot].data_len;
+
+ if (unlikely(!MAL_IS_SINGLE_RX(ctrl)))
+ goto sg;
+
+ ctrl &= EMAC_BAD_RX_MASK;
+ if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) {
+ emac_parse_rx_error(dev, ctrl);
+ ++dev->estats.rx_dropped_error;
+ emac_recycle_rx_skb(dev, slot, 0);
+ len = 0;
+ goto next;
+ }
+
+ if (len && len < EMAC_RX_COPY_THRESH) {
+ struct sk_buff *copy_skb =
+ alloc_skb(len + EMAC_RX_SKB_HEADROOM + 2, GFP_ATOMIC);
+ if (unlikely(!copy_skb))
+ goto oom;
+
+ skb_reserve(copy_skb, EMAC_RX_SKB_HEADROOM + 2);
+ cacheable_memcpy(copy_skb->data - 2, skb->data - 2,
+ len + 2);
+ emac_recycle_rx_skb(dev, slot, len);
+ skb = copy_skb;
+ } else if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC)))
+ goto oom;
+
+ skb_put(skb, len);
+ push_packet:
+ skb->dev = dev->ndev;
+ skb->protocol = eth_type_trans(skb, dev->ndev);
+ emac_rx_csum(dev, skb, ctrl);
+
+ if (unlikely(netif_receive_skb(skb) == NET_RX_DROP))
+ ++dev->estats.rx_dropped_stack;
+ next:
+ ++dev->stats.rx_packets;
+ skip:
+ dev->stats.rx_bytes += len;
+ slot = (slot + 1) % NUM_RX_BUFF;
+ --budget;
+ ++received;
+ continue;
+ sg:
+ if (ctrl & MAL_RX_CTRL_FIRST) {
+ BUG_ON(dev->rx_sg_skb);
+ if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) {
+ DBG(dev, "rx OOM %d" NL, slot);
+ ++dev->estats.rx_dropped_oom;
+ emac_recycle_rx_skb(dev, slot, 0);
+ } else {
+ dev->rx_sg_skb = skb;
+ skb_put(skb, len);
+ }
+ } else if (!emac_rx_sg_append(dev, slot) &&
+ (ctrl & MAL_RX_CTRL_LAST)) {
+
+ skb = dev->rx_sg_skb;
+ dev->rx_sg_skb = NULL;
+
+ ctrl &= EMAC_BAD_RX_MASK;
+ if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) {
+ emac_parse_rx_error(dev, ctrl);
+ ++dev->estats.rx_dropped_error;
+ dev_kfree_skb(skb);
+ len = 0;
+ } else
+ goto push_packet;
+ }
+ goto skip;
+ oom:
+ DBG(dev, "rx OOM %d" NL, slot);
+ /* Drop the packet and recycle skb */
+ ++dev->estats.rx_dropped_oom;
+ emac_recycle_rx_skb(dev, slot, 0);
+ goto next;
+ }
+
+ if (received) {
+ DBG2(dev, "rx %d BDs" NL, received);
+ dev->rx_slot = slot;
+ }
+
+ if (unlikely(budget && test_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags))) {
+ mb();
+ if (!(dev->rx_desc[slot].ctrl & MAL_RX_CTRL_EMPTY)) {
+ DBG2(dev, "rx restart" NL);
+ received = 0;
+ goto again;
+ }
+
+ if (dev->rx_sg_skb) {
+ DBG2(dev, "dropping partial rx packet" NL);
+ ++dev->estats.rx_dropped_error;
+ dev_kfree_skb(dev->rx_sg_skb);
+ dev->rx_sg_skb = NULL;
+ }
+
+ clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
+ mal_enable_rx_channel(dev->mal, dev->mal_rx_chan);
+ emac_rx_enable(dev);
+ dev->rx_slot = 0;
+ }
+ return received;
+}
+
+/* NAPI poll context */
+static int emac_peek_rx(void *param)
+{
+ struct emac_instance *dev = param;
+
+ return !(dev->rx_desc[dev->rx_slot].ctrl & MAL_RX_CTRL_EMPTY);
+}
+
+/* NAPI poll context */
+static int emac_peek_rx_sg(void *param)
+{
+ struct emac_instance *dev = param;
+
+ int slot = dev->rx_slot;
+ while (1) {
+ u16 ctrl = dev->rx_desc[slot].ctrl;
+ if (ctrl & MAL_RX_CTRL_EMPTY)
+ return 0;
+ else if (ctrl & MAL_RX_CTRL_LAST)
+ return 1;
+
+ slot = (slot + 1) % NUM_RX_BUFF;
+
+ /* I'm just being paranoid here :) */
+ if (unlikely(slot == dev->rx_slot))
+ return 0;
+ }
+}
+
+/* Hard IRQ */
+static void emac_rxde(void *param)
+{
+ struct emac_instance *dev = param;
+
+ ++dev->estats.rx_stopped;
+ emac_rx_disable_async(dev);
+}
+
+/* Hard IRQ */
+static irqreturn_t emac_irq(int irq, void *dev_instance)
+{
+ struct emac_instance *dev = dev_instance;
+ struct emac_regs __iomem *p = dev->emacp;
+ struct emac_error_stats *st = &dev->estats;
+ u32 isr;
+
+ spin_lock(&dev->lock);
+
+ isr = in_be32(&p->isr);
+ out_be32(&p->isr, isr);
+
+ DBG(dev, "isr = %08x" NL, isr);
+
+ if (isr & EMAC4_ISR_TXPE)
+ ++st->tx_parity;
+ if (isr & EMAC4_ISR_RXPE)
+ ++st->rx_parity;
+ if (isr & EMAC4_ISR_TXUE)
+ ++st->tx_underrun;
+ if (isr & EMAC4_ISR_RXOE)
+ ++st->rx_fifo_overrun;
+ if (isr & EMAC_ISR_OVR)
+ ++st->rx_overrun;
+ if (isr & EMAC_ISR_BP)
+ ++st->rx_bad_packet;
+ if (isr & EMAC_ISR_RP)
+ ++st->rx_runt_packet;
+ if (isr & EMAC_ISR_SE)
+ ++st->rx_short_event;
+ if (isr & EMAC_ISR_ALE)
+ ++st->rx_alignment_error;
+ if (isr & EMAC_ISR_BFCS)
+ ++st->rx_bad_fcs;
+ if (isr & EMAC_ISR_PTLE)
+ ++st->rx_packet_too_long;
+ if (isr & EMAC_ISR_ORE)
+ ++st->rx_out_of_range;
+ if (isr & EMAC_ISR_IRE)
+ ++st->rx_in_range;
+ if (isr & EMAC_ISR_SQE)
+ ++st->tx_sqe;
+ if (isr & EMAC_ISR_TE)
+ ++st->tx_errors;
+
+ spin_unlock(&dev->lock);
+
+ return IRQ_HANDLED;
+}
+
+static struct net_device_stats *emac_stats(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ struct emac_stats *st = &dev->stats;
+ struct emac_error_stats *est = &dev->estats;
+ struct net_device_stats *nst = &dev->nstats;
+ unsigned long flags;
+
+ DBG2(dev, "stats" NL);
+
+ /* Compute "legacy" statistics */
+ spin_lock_irqsave(&dev->lock, flags);
+ nst->rx_packets = (unsigned long)st->rx_packets;
+ nst->rx_bytes = (unsigned long)st->rx_bytes;
+ nst->tx_packets = (unsigned long)st->tx_packets;
+ nst->tx_bytes = (unsigned long)st->tx_bytes;
+ nst->rx_dropped = (unsigned long)(est->rx_dropped_oom +
+ est->rx_dropped_error +
+ est->rx_dropped_resize +
+ est->rx_dropped_mtu);
+ nst->tx_dropped = (unsigned long)est->tx_dropped;
+
+ nst->rx_errors = (unsigned long)est->rx_bd_errors;
+ nst->rx_fifo_errors = (unsigned long)(est->rx_bd_overrun +
+ est->rx_fifo_overrun +
+ est->rx_overrun);
+ nst->rx_frame_errors = (unsigned long)(est->rx_bd_alignment_error +
+ est->rx_alignment_error);
+ nst->rx_crc_errors = (unsigned long)(est->rx_bd_bad_fcs +
+ est->rx_bad_fcs);
+ nst->rx_length_errors = (unsigned long)(est->rx_bd_runt_packet +
+ est->rx_bd_short_event +
+ est->rx_bd_packet_too_long +
+ est->rx_bd_out_of_range +
+ est->rx_bd_in_range +
+ est->rx_runt_packet +
+ est->rx_short_event +
+ est->rx_packet_too_long +
+ est->rx_out_of_range +
+ est->rx_in_range);
+
+ nst->tx_errors = (unsigned long)(est->tx_bd_errors + est->tx_errors);
+ nst->tx_fifo_errors = (unsigned long)(est->tx_bd_underrun +
+ est->tx_underrun);
+ nst->tx_carrier_errors = (unsigned long)est->tx_bd_carrier_loss;
+ nst->collisions = (unsigned long)(est->tx_bd_excessive_deferral +
+ est->tx_bd_excessive_collisions +
+ est->tx_bd_late_collision +
+ est->tx_bd_multple_collisions);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return nst;
+}
+
+static struct mal_commac_ops emac_commac_ops = {
+ .poll_tx = &emac_poll_tx,
+ .poll_rx = &emac_poll_rx,
+ .peek_rx = &emac_peek_rx,
+ .rxde = &emac_rxde,
+};
+
+static struct mal_commac_ops emac_commac_sg_ops = {
+ .poll_tx = &emac_poll_tx,
+ .poll_rx = &emac_poll_rx,
+ .peek_rx = &emac_peek_rx_sg,
+ .rxde = &emac_rxde,
+};
+
+/* Ethtool support */
+static int emac_ethtool_get_settings(struct net_device *ndev,
+ struct ethtool_cmd *cmd)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ cmd->supported = dev->phy.features;
+ cmd->port = PORT_MII;
+ cmd->phy_address = dev->phy.address;
+ cmd->transceiver =
+ dev->phy.address >= 0 ? XCVR_EXTERNAL : XCVR_INTERNAL;
+
+ mutex_lock(&dev->link_lock);
+ cmd->advertising = dev->phy.advertising;
+ cmd->autoneg = dev->phy.autoneg;
+ cmd->speed = dev->phy.speed;
+ cmd->duplex = dev->phy.duplex;
+ mutex_unlock(&dev->link_lock);
+
+ return 0;
+}
+
+static int emac_ethtool_set_settings(struct net_device *ndev,
+ struct ethtool_cmd *cmd)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ u32 f = dev->phy.features;
+
+ DBG(dev, "set_settings(%d, %d, %d, 0x%08x)" NL,
+ cmd->autoneg, cmd->speed, cmd->duplex, cmd->advertising);
+
+ /* Basic sanity checks */
+ if (dev->phy.address < 0)
+ return -EOPNOTSUPP;
+ if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)
+ return -EINVAL;
+ if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0)
+ return -EINVAL;
+ if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL)
+ return -EINVAL;
+
+ if (cmd->autoneg == AUTONEG_DISABLE) {
+ switch (cmd->speed) {
+ case SPEED_10:
+ if (cmd->duplex == DUPLEX_HALF
+ && !(f & SUPPORTED_10baseT_Half))
+ return -EINVAL;
+ if (cmd->duplex == DUPLEX_FULL
+ && !(f & SUPPORTED_10baseT_Full))
+ return -EINVAL;
+ break;
+ case SPEED_100:
+ if (cmd->duplex == DUPLEX_HALF
+ && !(f & SUPPORTED_100baseT_Half))
+ return -EINVAL;
+ if (cmd->duplex == DUPLEX_FULL
+ && !(f & SUPPORTED_100baseT_Full))
+ return -EINVAL;
+ break;
+ case SPEED_1000:
+ if (cmd->duplex == DUPLEX_HALF
+ && !(f & SUPPORTED_1000baseT_Half))
+ return -EINVAL;
+ if (cmd->duplex == DUPLEX_FULL
+ && !(f & SUPPORTED_1000baseT_Full))
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev->link_lock);
+ dev->phy.def->ops->setup_forced(&dev->phy, cmd->speed,
+ cmd->duplex);
+ mutex_unlock(&dev->link_lock);
+
+ } else {
+ if (!(f & SUPPORTED_Autoneg))
+ return -EINVAL;
+
+ mutex_lock(&dev->link_lock);
+ dev->phy.def->ops->setup_aneg(&dev->phy,
+ (cmd->advertising & f) |
+ (dev->phy.advertising &
+ (ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause)));
+ mutex_unlock(&dev->link_lock);
+ }
+ emac_force_link_update(dev);
+
+ return 0;
+}
+
+static void emac_ethtool_get_ringparam(struct net_device *ndev,
+ struct ethtool_ringparam *rp)
+{
+ rp->rx_max_pending = rp->rx_pending = NUM_RX_BUFF;
+ rp->tx_max_pending = rp->tx_pending = NUM_TX_BUFF;
+}
+
+static void emac_ethtool_get_pauseparam(struct net_device *ndev,
+ struct ethtool_pauseparam *pp)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ mutex_lock(&dev->link_lock);
+ if ((dev->phy.features & SUPPORTED_Autoneg) &&
+ (dev->phy.advertising & (ADVERTISED_Pause | ADVERTISED_Asym_Pause)))
+ pp->autoneg = 1;
+
+ if (dev->phy.duplex == DUPLEX_FULL) {
+ if (dev->phy.pause)
+ pp->rx_pause = pp->tx_pause = 1;
+ else if (dev->phy.asym_pause)
+ pp->tx_pause = 1;
+ }
+ mutex_unlock(&dev->link_lock);
+}
+
+static u32 emac_ethtool_get_rx_csum(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ return dev->tah_dev != NULL;
+}
+
+static int emac_get_regs_len(struct emac_instance *dev)
+{
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+ return sizeof(struct emac_ethtool_regs_subhdr) +
+ EMAC4_ETHTOOL_REGS_SIZE;
+ else
+ return sizeof(struct emac_ethtool_regs_subhdr) +
+ EMAC_ETHTOOL_REGS_SIZE;
+}
+
+static int emac_ethtool_get_regs_len(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ int size;
+
+ size = sizeof(struct emac_ethtool_regs_hdr) +
+ emac_get_regs_len(dev) + mal_get_regs_len(dev->mal);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ size += zmii_get_regs_len(dev->zmii_dev);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ size += rgmii_get_regs_len(dev->rgmii_dev);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+ size += tah_get_regs_len(dev->tah_dev);
+
+ return size;
+}
+
+static void *emac_dump_regs(struct emac_instance *dev, void *buf)
+{
+ struct emac_ethtool_regs_subhdr *hdr = buf;
+
+ hdr->index = dev->cell_index;
+ if (emac_has_feature(dev, EMAC_FTR_EMAC4)) {
+ hdr->version = EMAC4_ETHTOOL_REGS_VER;
+ memcpy_fromio(hdr + 1, dev->emacp, EMAC4_ETHTOOL_REGS_SIZE);
+ return ((void *)(hdr + 1) + EMAC4_ETHTOOL_REGS_SIZE);
+ } else {
+ hdr->version = EMAC_ETHTOOL_REGS_VER;
+ memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE);
+ return ((void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE);
+ }
+}
+
+static void emac_ethtool_get_regs(struct net_device *ndev,
+ struct ethtool_regs *regs, void *buf)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ struct emac_ethtool_regs_hdr *hdr = buf;
+
+ hdr->components = 0;
+ buf = hdr + 1;
+
+ buf = mal_dump_regs(dev->mal, buf);
+ buf = emac_dump_regs(dev, buf);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) {
+ hdr->components |= EMAC_ETHTOOL_REGS_ZMII;
+ buf = zmii_dump_regs(dev->zmii_dev, buf);
+ }
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) {
+ hdr->components |= EMAC_ETHTOOL_REGS_RGMII;
+ buf = rgmii_dump_regs(dev->rgmii_dev, buf);
+ }
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) {
+ hdr->components |= EMAC_ETHTOOL_REGS_TAH;
+ buf = tah_dump_regs(dev->tah_dev, buf);
+ }
+}
+
+static int emac_ethtool_nway_reset(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ int res = 0;
+
+ DBG(dev, "nway_reset" NL);
+
+ if (dev->phy.address < 0)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&dev->link_lock);
+ if (!dev->phy.autoneg) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ dev->phy.def->ops->setup_aneg(&dev->phy, dev->phy.advertising);
+ out:
+ mutex_unlock(&dev->link_lock);
+ emac_force_link_update(dev);
+ return res;
+}
+
+static int emac_ethtool_get_stats_count(struct net_device *ndev)
+{
+ return EMAC_ETHTOOL_STATS_COUNT;
+}
+
+static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset,
+ u8 * buf)
+{
+ if (stringset == ETH_SS_STATS)
+ memcpy(buf, &emac_stats_keys, sizeof(emac_stats_keys));
+}
+
+static void emac_ethtool_get_ethtool_stats(struct net_device *ndev,
+ struct ethtool_stats *estats,
+ u64 * tmp_stats)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ memcpy(tmp_stats, &dev->stats, sizeof(dev->stats));
+ tmp_stats += sizeof(dev->stats) / sizeof(u64);
+ memcpy(tmp_stats, &dev->estats, sizeof(dev->estats));
+}
+
+static void emac_ethtool_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *info)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ strcpy(info->driver, "ibm_emac");
+ strcpy(info->version, DRV_VERSION);
+ info->fw_version[0] = '\0';
+ sprintf(info->bus_info, "PPC 4xx EMAC-%d %s",
+ dev->cell_index, dev->ofdev->node->full_name);
+ info->n_stats = emac_ethtool_get_stats_count(ndev);
+ info->regdump_len = emac_ethtool_get_regs_len(ndev);
+}
+
+static const struct ethtool_ops emac_ethtool_ops = {
+ .get_settings = emac_ethtool_get_settings,
+ .set_settings = emac_ethtool_set_settings,
+ .get_drvinfo = emac_ethtool_get_drvinfo,
+
+ .get_regs_len = emac_ethtool_get_regs_len,
+ .get_regs = emac_ethtool_get_regs,
+
+ .nway_reset = emac_ethtool_nway_reset,
+
+ .get_ringparam = emac_ethtool_get_ringparam,
+ .get_pauseparam = emac_ethtool_get_pauseparam,
+
+ .get_rx_csum = emac_ethtool_get_rx_csum,
+
+ .get_strings = emac_ethtool_get_strings,
+ .get_stats_count = emac_ethtool_get_stats_count,
+ .get_ethtool_stats = emac_ethtool_get_ethtool_stats,
+
+ .get_link = ethtool_op_get_link,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+};
+
+static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ uint16_t *data = (uint16_t *) & rq->ifr_ifru;
+
+ DBG(dev, "ioctl %08x" NL, cmd);
+
+ if (dev->phy.address < 0)
+ return -EOPNOTSUPP;
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCDEVPRIVATE:
+ data[0] = dev->phy.address;
+ /* Fall through */
+ case SIOCGMIIREG:
+ case SIOCDEVPRIVATE + 1:
+ data[3] = emac_mdio_read(ndev, dev->phy.address, data[1]);
+ return 0;
+
+ case SIOCSMIIREG:
+ case SIOCDEVPRIVATE + 2:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ emac_mdio_write(ndev, dev->phy.address, data[1], data[2]);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+struct emac_depentry {
+ u32 phandle;
+ struct device_node *node;
+ struct of_device *ofdev;
+ void *drvdata;
+};
+
+#define EMAC_DEP_MAL_IDX 0
+#define EMAC_DEP_ZMII_IDX 1
+#define EMAC_DEP_RGMII_IDX 2
+#define EMAC_DEP_TAH_IDX 3
+#define EMAC_DEP_MDIO_IDX 4
+#define EMAC_DEP_PREV_IDX 5
+#define EMAC_DEP_COUNT 6
+
+static int __devinit emac_check_deps(struct emac_instance *dev,
+ struct emac_depentry *deps)
+{
+ int i, there = 0;
+ struct device_node *np;
+
+ for (i = 0; i < EMAC_DEP_COUNT; i++) {
+ /* no dependency on that item, allright */
+ if (deps[i].phandle == 0) {
+ there++;
+ continue;
+ }
+ /* special case for blist as the dependency might go away */
+ if (i == EMAC_DEP_PREV_IDX) {
+ np = *(dev->blist - 1);
+ if (np == NULL) {
+ deps[i].phandle = 0;
+ there++;
+ continue;
+ }
+ if (deps[i].node == NULL)
+ deps[i].node = of_node_get(np);
+ }
+ if (deps[i].node == NULL)
+ deps[i].node = of_find_node_by_phandle(deps[i].phandle);
+ if (deps[i].node == NULL)
+ continue;
+ if (deps[i].ofdev == NULL)
+ deps[i].ofdev = of_find_device_by_node(deps[i].node);
+ if (deps[i].ofdev == NULL)
+ continue;
+ if (deps[i].drvdata == NULL)
+ deps[i].drvdata = dev_get_drvdata(&deps[i].ofdev->dev);
+ if (deps[i].drvdata != NULL)
+ there++;
+ }
+ return (there == EMAC_DEP_COUNT);
+}
+
+static void emac_put_deps(struct emac_instance *dev)
+{
+ if (dev->mal_dev)
+ of_dev_put(dev->mal_dev);
+ if (dev->zmii_dev)
+ of_dev_put(dev->zmii_dev);
+ if (dev->rgmii_dev)
+ of_dev_put(dev->rgmii_dev);
+ if (dev->mdio_dev)
+ of_dev_put(dev->mdio_dev);
+ if (dev->tah_dev)
+ of_dev_put(dev->tah_dev);
+}
+
+static int __devinit emac_of_bus_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ /* We are only intereted in device addition */
+ if (action == BUS_NOTIFY_BOUND_DRIVER)
+ wake_up_all(&emac_probe_wait);
+ return 0;
+}
+
+static struct notifier_block emac_of_bus_notifier = {
+ .notifier_call = emac_of_bus_notify
+};
+
+static int __devinit emac_wait_deps(struct emac_instance *dev)
+{
+ struct emac_depentry deps[EMAC_DEP_COUNT];
+ int i, err;
+
+ memset(&deps, 0, sizeof(deps));
+
+ deps[EMAC_DEP_MAL_IDX].phandle = dev->mal_ph;
+ deps[EMAC_DEP_ZMII_IDX].phandle = dev->zmii_ph;
+ deps[EMAC_DEP_RGMII_IDX].phandle = dev->rgmii_ph;
+ if (dev->tah_ph)
+ deps[EMAC_DEP_TAH_IDX].phandle = dev->tah_ph;
+ if (dev->mdio_ph)
+ deps[EMAC_DEP_MDIO_IDX].phandle = dev->mdio_ph;
+ if (dev->blist && dev->blist > emac_boot_list)
+ deps[EMAC_DEP_PREV_IDX].phandle = 0xffffffffu;
+ bus_register_notifier(&of_platform_bus_type, &emac_of_bus_notifier);
+ wait_event_timeout(emac_probe_wait,
+ emac_check_deps(dev, deps),
+ EMAC_PROBE_DEP_TIMEOUT);
+ bus_unregister_notifier(&of_platform_bus_type, &emac_of_bus_notifier);
+ err = emac_check_deps(dev, deps) ? 0 : -ENODEV;
+ for (i = 0; i < EMAC_DEP_COUNT; i++) {
+ if (deps[i].node)
+ of_node_put(deps[i].node);
+ if (err && deps[i].ofdev)
+ of_dev_put(deps[i].ofdev);
+ }
+ if (err == 0) {
+ dev->mal_dev = deps[EMAC_DEP_MAL_IDX].ofdev;
+ dev->zmii_dev = deps[EMAC_DEP_ZMII_IDX].ofdev;
+ dev->rgmii_dev = deps[EMAC_DEP_RGMII_IDX].ofdev;
+ dev->tah_dev = deps[EMAC_DEP_TAH_IDX].ofdev;
+ dev->mdio_dev = deps[EMAC_DEP_MDIO_IDX].ofdev;
+ }
+ if (deps[EMAC_DEP_PREV_IDX].ofdev)
+ of_dev_put(deps[EMAC_DEP_PREV_IDX].ofdev);
+ return err;
+}
+
+static int __devinit emac_read_uint_prop(struct device_node *np, const char *name,
+ u32 *val, int fatal)
+{
+ int len;
+ const u32 *prop = of_get_property(np, name, &len);
+ if (prop == NULL || len < sizeof(u32)) {
+ if (fatal)
+ printk(KERN_ERR "%s: missing %s property\n",
+ np->full_name, name);
+ return -ENODEV;
+ }
+ *val = *prop;
+ return 0;
+}
+
+static int __devinit emac_init_phy(struct emac_instance *dev)
+{
+ struct device_node *np = dev->ofdev->node;
+ struct net_device *ndev = dev->ndev;
+ u32 phy_map, adv;
+ int i;
+
+ dev->phy.dev = ndev;
+ dev->phy.mode = dev->phy_mode;
+
+ /* PHY-less configuration.
+ * XXX I probably should move these settings to the dev tree
+ */
+ if (dev->phy_address == 0xffffffff && dev->phy_map == 0xffffffff) {
+ emac_reset(dev);
+
+ /* PHY-less configuration.
+ * XXX I probably should move these settings to the dev tree
+ */
+ dev->phy.address = -1;
+ dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII;
+ dev->phy.pause = 1;
+
+ return 0;
+ }
+
+ mutex_lock(&emac_phy_map_lock);
+ phy_map = dev->phy_map | busy_phy_map;
+
+ DBG(dev, "PHY maps %08x %08x" NL, dev->phy_map, busy_phy_map);
+
+ dev->phy.mdio_read = emac_mdio_read;
+ dev->phy.mdio_write = emac_mdio_write;
+
+ /* Configure EMAC with defaults so we can at least use MDIO
+ * This is needed mostly for 440GX
+ */
+ if (emac_phy_gpcs(dev->phy.mode)) {
+ /* XXX
+ * Make GPCS PHY address equal to EMAC index.
+ * We probably should take into account busy_phy_map
+ * and/or phy_map here.
+ *
+ * Note that the busy_phy_map is currently global
+ * while it should probably be per-ASIC...
+ */
+ dev->phy.address = dev->cell_index;
+ }
+
+ emac_configure(dev);
+
+ if (dev->phy_address != 0xffffffff)
+ phy_map = ~(1 << dev->phy_address);
+
+ for (i = 0; i < 0x20; phy_map >>= 1, ++i)
+ if (!(phy_map & 1)) {
+ int r;
+ busy_phy_map |= 1 << i;
+
+ /* Quick check if there is a PHY at the address */
+ r = emac_mdio_read(dev->ndev, i, MII_BMCR);
+ if (r == 0xffff || r < 0)
+ continue;
+ if (!emac_mii_phy_probe(&dev->phy, i))
+ break;
+ }
+ mutex_unlock(&emac_phy_map_lock);
+ if (i == 0x20) {
+ printk(KERN_WARNING "%s: can't find PHY!\n", np->full_name);
+ return -ENXIO;
+ }
+
+ /* Init PHY */
+ if (dev->phy.def->ops->init)
+ dev->phy.def->ops->init(&dev->phy);
+
+ /* Disable any PHY features not supported by the platform */
+ dev->phy.def->features &= ~dev->phy_feat_exc;
+
+ /* Setup initial link parameters */
+ if (dev->phy.features & SUPPORTED_Autoneg) {
+ adv = dev->phy.features;
+ if (!emac_has_feature(dev, EMAC_FTR_NO_FLOW_CONTROL_40x))
+ adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
+ /* Restart autonegotiation */
+ dev->phy.def->ops->setup_aneg(&dev->phy, adv);
+ } else {
+ u32 f = dev->phy.def->features;
+ int speed = SPEED_10, fd = DUPLEX_HALF;
+
+ /* Select highest supported speed/duplex */
+ if (f & SUPPORTED_1000baseT_Full) {
+ speed = SPEED_1000;
+ fd = DUPLEX_FULL;
+ } else if (f & SUPPORTED_1000baseT_Half)
+ speed = SPEED_1000;
+ else if (f & SUPPORTED_100baseT_Full) {
+ speed = SPEED_100;
+ fd = DUPLEX_FULL;
+ } else if (f & SUPPORTED_100baseT_Half)
+ speed = SPEED_100;
+ else if (f & SUPPORTED_10baseT_Full)
+ fd = DUPLEX_FULL;
+
+ /* Force link parameters */
+ dev->phy.def->ops->setup_forced(&dev->phy, speed, fd);
+ }
+ return 0;
+}
+
+static int __devinit emac_init_config(struct emac_instance *dev)
+{
+ struct device_node *np = dev->ofdev->node;
+ const void *p;
+ unsigned int plen;
+ const char *pm, *phy_modes[] = {
+ [PHY_MODE_NA] = "",
+ [PHY_MODE_MII] = "mii",
+ [PHY_MODE_RMII] = "rmii",
+ [PHY_MODE_SMII] = "smii",
+ [PHY_MODE_RGMII] = "rgmii",
+ [PHY_MODE_TBI] = "tbi",
+ [PHY_MODE_GMII] = "gmii",
+ [PHY_MODE_RTBI] = "rtbi",
+ [PHY_MODE_SGMII] = "sgmii",
+ };
+
+ /* Read config from device-tree */
+ if (emac_read_uint_prop(np, "mal-device", &dev->mal_ph, 1))
+ return -ENXIO;
+ if (emac_read_uint_prop(np, "mal-tx-channel", &dev->mal_tx_chan, 1))
+ return -ENXIO;
+ if (emac_read_uint_prop(np, "mal-rx-channel", &dev->mal_rx_chan, 1))
+ return -ENXIO;
+ if (emac_read_uint_prop(np, "cell-index", &dev->cell_index, 1))
+ return -ENXIO;
+ if (emac_read_uint_prop(np, "max-frame-size", &dev->max_mtu, 0))
+ dev->max_mtu = 1500;
+ if (emac_read_uint_prop(np, "rx-fifo-size", &dev->rx_fifo_size, 0))
+ dev->rx_fifo_size = 2048;
+ if (emac_read_uint_prop(np, "tx-fifo-size", &dev->tx_fifo_size, 0))
+ dev->tx_fifo_size = 2048;
+ if (emac_read_uint_prop(np, "rx-fifo-size-gige", &dev->rx_fifo_size_gige, 0))
+ dev->rx_fifo_size_gige = dev->rx_fifo_size;
+ if (emac_read_uint_prop(np, "tx-fifo-size-gige", &dev->tx_fifo_size_gige, 0))
+ dev->tx_fifo_size_gige = dev->tx_fifo_size;
+ if (emac_read_uint_prop(np, "phy-address", &dev->phy_address, 0))
+ dev->phy_address = 0xffffffff;
+ if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0))
+ dev->phy_map = 0xffffffff;
+ if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1))
+ return -ENXIO;
+ if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0))
+ dev->tah_ph = 0;
+ if (emac_read_uint_prop(np, "tah-channel", &dev->tah_port, 0))
+ dev->tah_ph = 0;
+ if (emac_read_uint_prop(np, "mdio-device", &dev->mdio_ph, 0))
+ dev->mdio_ph = 0;
+ if (emac_read_uint_prop(np, "zmii-device", &dev->zmii_ph, 0))
+ dev->zmii_ph = 0;;
+ if (emac_read_uint_prop(np, "zmii-channel", &dev->zmii_port, 0))
+ dev->zmii_port = 0xffffffff;;
+ if (emac_read_uint_prop(np, "rgmii-device", &dev->rgmii_ph, 0))
+ dev->rgmii_ph = 0;;
+ if (emac_read_uint_prop(np, "rgmii-channel", &dev->rgmii_port, 0))
+ dev->rgmii_port = 0xffffffff;;
+ if (emac_read_uint_prop(np, "fifo-entry-size", &dev->fifo_entry_size, 0))
+ dev->fifo_entry_size = 16;
+ if (emac_read_uint_prop(np, "mal-burst-size", &dev->mal_burst_size, 0))
+ dev->mal_burst_size = 256;
+
+ /* PHY mode needs some decoding */
+ dev->phy_mode = PHY_MODE_NA;
+ pm = of_get_property(np, "phy-mode", &plen);
+ if (pm != NULL) {
+ int i;
+ for (i = 0; i < ARRAY_SIZE(phy_modes); i++)
+ if (!strcasecmp(pm, phy_modes[i])) {
+ dev->phy_mode = i;
+ break;
+ }
+ }
+
+ /* Backward compat with non-final DT */
+ if (dev->phy_mode == PHY_MODE_NA && pm != NULL && plen == 4) {
+ u32 nmode = *(const u32 *)pm;
+ if (nmode > PHY_MODE_NA && nmode <= PHY_MODE_SGMII)
+ dev->phy_mode = nmode;
+ }
+
+ /* Check EMAC version */
+ if (of_device_is_compatible(np, "ibm,emac4"))
+ dev->features |= EMAC_FTR_EMAC4;
+ if (of_device_is_compatible(np, "ibm,emac-axon")
+ || of_device_is_compatible(np, "ibm,emac-440epx"))
+ dev->features |= EMAC_FTR_HAS_AXON_STACR
+ | EMAC_FTR_STACR_OC_INVERT;
+ if (of_device_is_compatible(np, "ibm,emac-440spe"))
+ dev->features |= EMAC_FTR_STACR_OC_INVERT;
+
+ /* Fixup some feature bits based on the device tree and verify
+ * we have support for them compiled in
+ */
+ if (dev->tah_ph != 0) {
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+ dev->features |= EMAC_FTR_HAS_TAH;
+#else
+ printk(KERN_ERR "%s: TAH support not enabled !\n",
+ np->full_name);
+ return -ENXIO;
+#endif
+ }
+
+ if (dev->zmii_ph != 0) {
+#ifdef CONFIG_IBM_NEW_EMAC_ZMII
+ dev->features |= EMAC_FTR_HAS_ZMII;
+#else
+ printk(KERN_ERR "%s: ZMII support not enabled !\n",
+ np->full_name);
+ return -ENXIO;
+#endif
+ }
+
+ if (dev->rgmii_ph != 0) {
+#ifdef CONFIG_IBM_NEW_EMAC_RGMII
+ dev->features |= EMAC_FTR_HAS_RGMII;
+#else
+ printk(KERN_ERR "%s: RGMII support not enabled !\n",
+ np->full_name);
+ return -ENXIO;
+#endif
+ }
+
+ /* Read MAC-address */
+ p = of_get_property(np, "local-mac-address", NULL);
+ if (p == NULL) {
+ printk(KERN_ERR "%s: Can't find local-mac-address property\n",
+ np->full_name);
+ return -ENXIO;
+ }
+ memcpy(dev->ndev->dev_addr, p, 6);
+
+ DBG(dev, "features : 0x%08x / 0x%08x\n", dev->features, EMAC_FTRS_POSSIBLE);
+ DBG(dev, "tx_fifo_size : %d (%d gige)\n", dev->tx_fifo_size, dev->tx_fifo_size_gige);
+ DBG(dev, "rx_fifo_size : %d (%d gige)\n", dev->rx_fifo_size, dev->rx_fifo_size_gige);
+ DBG(dev, "max_mtu : %d\n", dev->max_mtu);
+ DBG(dev, "OPB freq : %d\n", dev->opb_bus_freq);
+
+ return 0;
+}
+
+static int __devinit emac_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct net_device *ndev;
+ struct emac_instance *dev;
+ struct device_node *np = ofdev->node;
+ struct device_node **blist = NULL;
+ int err, i;
+
+ /* Find ourselves in the bootlist if we are there */
+ for (i = 0; i < EMAC_BOOT_LIST_SIZE; i++)
+ if (emac_boot_list[i] == np)
+ blist = &emac_boot_list[i];
+
+ /* Allocate our net_device structure */
+ err = -ENOMEM;
+ ndev = alloc_etherdev(sizeof(struct emac_instance));
+ if (!ndev) {
+ printk(KERN_ERR "%s: could not allocate ethernet device!\n",
+ np->full_name);
+ goto err_gone;
+ }
+ dev = netdev_priv(ndev);
+ dev->ndev = ndev;
+ dev->ofdev = ofdev;
+ dev->blist = blist;
+ SET_NETDEV_DEV(ndev, &ofdev->dev);
+
+ /* Initialize some embedded data structures */
+ mutex_init(&dev->mdio_lock);
+ mutex_init(&dev->link_lock);
+ spin_lock_init(&dev->lock);
+ INIT_WORK(&dev->reset_work, emac_reset_work);
+
+ /* Init various config data based on device-tree */
+ err = emac_init_config(dev);
+ if (err != 0)
+ goto err_free;
+
+ /* Get interrupts. EMAC irq is mandatory, WOL irq is optional */
+ dev->emac_irq = irq_of_parse_and_map(np, 0);
+ dev->wol_irq = irq_of_parse_and_map(np, 1);
+ if (dev->emac_irq == NO_IRQ) {
+ printk(KERN_ERR "%s: Can't map main interrupt\n", np->full_name);
+ goto err_free;
+ }
+ ndev->irq = dev->emac_irq;
+
+ /* Map EMAC regs */
+ if (of_address_to_resource(np, 0, &dev->rsrc_regs)) {
+ printk(KERN_ERR "%s: Can't get registers address\n",
+ np->full_name);
+ goto err_irq_unmap;
+ }
+ // TODO : request_mem_region
+ dev->emacp = ioremap(dev->rsrc_regs.start, sizeof(struct emac_regs));
+ if (dev->emacp == NULL) {
+ printk(KERN_ERR "%s: Can't map device registers!\n",
+ np->full_name);
+ err = -ENOMEM;
+ goto err_irq_unmap;
+ }
+
+ /* Wait for dependent devices */
+ err = emac_wait_deps(dev);
+ if (err) {
+ printk(KERN_ERR
+ "%s: Timeout waiting for dependent devices\n",
+ np->full_name);
+ /* display more info about what's missing ? */
+ goto err_reg_unmap;
+ }
+ dev->mal = dev_get_drvdata(&dev->mal_dev->dev);
+ if (dev->mdio_dev != NULL)
+ dev->mdio_instance = dev_get_drvdata(&dev->mdio_dev->dev);
+
+ /* Register with MAL */
+ dev->commac.ops = &emac_commac_ops;
+ dev->commac.dev = dev;
+ dev->commac.tx_chan_mask = MAL_CHAN_MASK(dev->mal_tx_chan);
+ dev->commac.rx_chan_mask = MAL_CHAN_MASK(dev->mal_rx_chan);
+ err = mal_register_commac(dev->mal, &dev->commac);
+ if (err) {
+ printk(KERN_ERR "%s: failed to register with mal %s!\n",
+ np->full_name, dev->mal_dev->node->full_name);
+ goto err_rel_deps;
+ }
+ dev->rx_skb_size = emac_rx_skb_size(ndev->mtu);
+ dev->rx_sync_size = emac_rx_sync_size(ndev->mtu);
+
+ /* Get pointers to BD rings */
+ dev->tx_desc =
+ dev->mal->bd_virt + mal_tx_bd_offset(dev->mal, dev->mal_tx_chan);
+ dev->rx_desc =
+ dev->mal->bd_virt + mal_rx_bd_offset(dev->mal, dev->mal_rx_chan);
+
+ DBG(dev, "tx_desc %p" NL, dev->tx_desc);
+ DBG(dev, "rx_desc %p" NL, dev->rx_desc);
+
+ /* Clean rings */
+ memset(dev->tx_desc, 0, NUM_TX_BUFF * sizeof(struct mal_descriptor));
+ memset(dev->rx_desc, 0, NUM_RX_BUFF * sizeof(struct mal_descriptor));
+
+ /* Attach to ZMII, if needed */
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII) &&
+ (err = zmii_attach(dev->zmii_dev, dev->zmii_port, &dev->phy_mode)) != 0)
+ goto err_unreg_commac;
+
+ /* Attach to RGMII, if needed */
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII) &&
+ (err = rgmii_attach(dev->rgmii_dev, dev->rgmii_port, dev->phy_mode)) != 0)
+ goto err_detach_zmii;
+
+ /* Attach to TAH, if needed */
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH) &&
+ (err = tah_attach(dev->tah_dev, dev->tah_port)) != 0)
+ goto err_detach_rgmii;
+
+ /* Set some link defaults before we can find out real parameters */
+ dev->phy.speed = SPEED_100;
+ dev->phy.duplex = DUPLEX_FULL;
+ dev->phy.autoneg = AUTONEG_DISABLE;
+ dev->phy.pause = dev->phy.asym_pause = 0;
+ dev->stop_timeout = STOP_TIMEOUT_100;
+ INIT_DELAYED_WORK(&dev->link_work, emac_link_timer);
+
+ /* Find PHY if any */
+ err = emac_init_phy(dev);
+ if (err != 0)
+ goto err_detach_tah;
+
+ /* Fill in the driver function table */
+ ndev->open = &emac_open;
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+ if (dev->tah_dev) {
+ ndev->hard_start_xmit = &emac_start_xmit_sg;
+ ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+ } else
+#endif
+ ndev->hard_start_xmit = &emac_start_xmit;
+ ndev->tx_timeout = &emac_tx_timeout;
+ ndev->watchdog_timeo = 5 * HZ;
+ ndev->stop = &emac_close;
+ ndev->get_stats = &emac_stats;
+ ndev->set_multicast_list = &emac_set_multicast_list;
+ ndev->do_ioctl = &emac_ioctl;
+ if (emac_phy_supports_gige(dev->phy_mode)) {
+ ndev->change_mtu = &emac_change_mtu;
+ dev->commac.ops = &emac_commac_sg_ops;
+ }
+ SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops);
+
+ netif_carrier_off(ndev);
+ netif_stop_queue(ndev);
+
+ err = register_netdev(ndev);
+ if (err) {
+ printk(KERN_ERR "%s: failed to register net device (%d)!\n",
+ np->full_name, err);
+ goto err_detach_tah;
+ }
+
+ /* Set our drvdata last as we don't want them visible until we are
+ * fully initialized
+ */
+ wmb();
+ dev_set_drvdata(&ofdev->dev, dev);
+
+ /* There's a new kid in town ! Let's tell everybody */
+ wake_up_all(&emac_probe_wait);
+
+
+ printk(KERN_INFO
+ "%s: EMAC-%d %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ndev->name, dev->cell_index, np->full_name,
+ ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
+ ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+
+ if (dev->phy.address >= 0)
+ printk("%s: found %s PHY (0x%02x)\n", ndev->name,
+ dev->phy.def->name, dev->phy.address);
+
+ emac_dbg_register(dev);
+
+ /* Life is good */
+ return 0;
+
+ /* I have a bad feeling about this ... */
+
+ err_detach_tah:
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+ tah_detach(dev->tah_dev, dev->tah_port);
+ err_detach_rgmii:
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_detach(dev->rgmii_dev, dev->rgmii_port);
+ err_detach_zmii:
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_detach(dev->zmii_dev, dev->zmii_port);
+ err_unreg_commac:
+ mal_unregister_commac(dev->mal, &dev->commac);
+ err_rel_deps:
+ emac_put_deps(dev);
+ err_reg_unmap:
+ iounmap(dev->emacp);
+ err_irq_unmap:
+ if (dev->wol_irq != NO_IRQ)
+ irq_dispose_mapping(dev->wol_irq);
+ if (dev->emac_irq != NO_IRQ)
+ irq_dispose_mapping(dev->emac_irq);
+ err_free:
+ kfree(ndev);
+ err_gone:
+ /* if we were on the bootlist, remove us as we won't show up and
+ * wake up all waiters to notify them in case they were waiting
+ * on us
+ */
+ if (blist) {
+ *blist = NULL;
+ wake_up_all(&emac_probe_wait);
+ }
+ return err;
+}
+
+static int __devexit emac_remove(struct of_device *ofdev)
+{
+ struct emac_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ DBG(dev, "remove" NL);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+
+ unregister_netdev(dev->ndev);
+
+ if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+ tah_detach(dev->tah_dev, dev->tah_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+ rgmii_detach(dev->rgmii_dev, dev->rgmii_port);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+ zmii_detach(dev->zmii_dev, dev->zmii_port);
+
+ mal_unregister_commac(dev->mal, &dev->commac);
+ emac_put_deps(dev);
+
+ emac_dbg_unregister(dev);
+ iounmap(dev->emacp);
+
+ if (dev->wol_irq != NO_IRQ)
+ irq_dispose_mapping(dev->wol_irq);
+ if (dev->emac_irq != NO_IRQ)
+ irq_dispose_mapping(dev->emac_irq);
+
+ kfree(dev->ndev);
+
+ return 0;
+}
+
+/* XXX Features in here should be replaced by properties... */
+static struct of_device_id emac_match[] =
+{
+ {
+ .type = "network",
+ .compatible = "ibm,emac",
+ },
+ {
+ .type = "network",
+ .compatible = "ibm,emac4",
+ },
+ {},
+};
+
+static struct of_platform_driver emac_driver = {
+ .name = "emac",
+ .match_table = emac_match,
+
+ .probe = emac_probe,
+ .remove = emac_remove,
+};
+
+static void __init emac_make_bootlist(void)
+{
+ struct device_node *np = NULL;
+ int j, max, i = 0, k;
+ int cell_indices[EMAC_BOOT_LIST_SIZE];
+
+ /* Collect EMACs */
+ while((np = of_find_all_nodes(np)) != NULL) {
+ const u32 *idx;
+
+ if (of_match_node(emac_match, np) == NULL)
+ continue;
+ if (of_get_property(np, "unused", NULL))
+ continue;
+ idx = of_get_property(np, "cell-index", NULL);
+ if (idx == NULL)
+ continue;
+ cell_indices[i] = *idx;
+ emac_boot_list[i++] = of_node_get(np);
+ if (i >= EMAC_BOOT_LIST_SIZE) {
+ of_node_put(np);
+ break;
+ }
+ }
+ max = i;
+
+ /* Bubble sort them (doh, what a creative algorithm :-) */
+ for (i = 0; max > 1 && (i < (max - 1)); i++)
+ for (j = i; j < max; j++) {
+ if (cell_indices[i] > cell_indices[j]) {
+ np = emac_boot_list[i];
+ emac_boot_list[i] = emac_boot_list[j];
+ emac_boot_list[j] = np;
+ k = cell_indices[i];
+ cell_indices[i] = cell_indices[j];
+ cell_indices[j] = k;
+ }
+ }
+}
+
+static int __init emac_init(void)
+{
+ int rc;
+
+ printk(KERN_INFO DRV_DESC ", version " DRV_VERSION "\n");
+
+ /* Init debug stuff */
+ emac_init_debug();
+
+ /* Build EMAC boot list */
+ emac_make_bootlist();
+
+ /* Init submodules */
+ rc = mal_init();
+ if (rc)
+ goto err;
+ rc = zmii_init();
+ if (rc)
+ goto err_mal;
+ rc = rgmii_init();
+ if (rc)
+ goto err_zmii;
+ rc = tah_init();
+ if (rc)
+ goto err_rgmii;
+ rc = of_register_platform_driver(&emac_driver);
+ if (rc)
+ goto err_tah;
+
+ return 0;
+
+ err_tah:
+ tah_exit();
+ err_rgmii:
+ rgmii_exit();
+ err_zmii:
+ zmii_exit();
+ err_mal:
+ mal_exit();
+ err:
+ return rc;
+}
+
+static void __exit emac_exit(void)
+{
+ int i;
+
+ of_unregister_platform_driver(&emac_driver);
+
+ tah_exit();
+ rgmii_exit();
+ zmii_exit();
+ mal_exit();
+ emac_fini_debug();
+
+ /* Destroy EMAC boot list */
+ for (i = 0; i < EMAC_BOOT_LIST_SIZE; i++)
+ if (emac_boot_list[i])
+ of_node_put(emac_boot_list[i]);
+}
+
+module_init(emac_init);
+module_exit(emac_exit);
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h
new file mode 100644
index 00000000000..4011803117c
--- /dev/null
+++ b/drivers/net/ibm_newemac/core.h
@@ -0,0 +1,355 @@
+/*
+ * drivers/net/ibm_newemac/core.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Armin Kuster <akuster@mvista.com>
+ * Johnnie Peters <jpeters@mvista.com>
+ * Copyright 2000, 2001 MontaVista Softare Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __IBM_NEWEMAC_CORE_H
+#define __IBM_NEWEMAC_CORE_H
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+
+#include <asm/of_platform.h>
+#include <asm/io.h>
+#include <asm/dcr.h>
+
+#include "emac.h"
+#include "phy.h"
+#include "zmii.h"
+#include "rgmii.h"
+#include "mal.h"
+#include "tah.h"
+#include "debug.h"
+
+#define NUM_TX_BUFF CONFIG_IBM_NEW_EMAC_TXB
+#define NUM_RX_BUFF CONFIG_IBM_NEW_EMAC_RXB
+
+/* Simple sanity check */
+#if NUM_TX_BUFF > 256 || NUM_RX_BUFF > 256
+#error Invalid number of buffer descriptors (greater than 256)
+#endif
+
+#define EMAC_MIN_MTU 46
+
+/* Maximum L2 header length (VLAN tagged, no FCS) */
+#define EMAC_MTU_OVERHEAD (6 * 2 + 2 + 4)
+
+/* RX BD size for the given MTU */
+static inline int emac_rx_size(int mtu)
+{
+ if (mtu > ETH_DATA_LEN)
+ return MAL_MAX_RX_SIZE;
+ else
+ return mal_rx_size(ETH_DATA_LEN + EMAC_MTU_OVERHEAD);
+}
+
+#define EMAC_DMA_ALIGN(x) ALIGN((x), dma_get_cache_alignment())
+
+#define EMAC_RX_SKB_HEADROOM \
+ EMAC_DMA_ALIGN(CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM)
+
+/* Size of RX skb for the given MTU */
+static inline int emac_rx_skb_size(int mtu)
+{
+ int size = max(mtu + EMAC_MTU_OVERHEAD, emac_rx_size(mtu));
+ return EMAC_DMA_ALIGN(size + 2) + EMAC_RX_SKB_HEADROOM;
+}
+
+/* RX DMA sync size */
+static inline int emac_rx_sync_size(int mtu)
+{
+ return EMAC_DMA_ALIGN(emac_rx_size(mtu) + 2);
+}
+
+/* Driver statistcs is split into two parts to make it more cache friendly:
+ * - normal statistics (packet count, etc)
+ * - error statistics
+ *
+ * When statistics is requested by ethtool, these parts are concatenated,
+ * normal one goes first.
+ *
+ * Please, keep these structures in sync with emac_stats_keys.
+ */
+
+/* Normal TX/RX Statistics */
+struct emac_stats {
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 tx_packets;
+ u64 tx_bytes;
+ u64 rx_packets_csum;
+ u64 tx_packets_csum;
+};
+
+/* Error statistics */
+struct emac_error_stats {
+ u64 tx_undo;
+
+ /* Software RX Errors */
+ u64 rx_dropped_stack;
+ u64 rx_dropped_oom;
+ u64 rx_dropped_error;
+ u64 rx_dropped_resize;
+ u64 rx_dropped_mtu;
+ u64 rx_stopped;
+ /* BD reported RX errors */
+ u64 rx_bd_errors;
+ u64 rx_bd_overrun;
+ u64 rx_bd_bad_packet;
+ u64 rx_bd_runt_packet;
+ u64 rx_bd_short_event;
+ u64 rx_bd_alignment_error;
+ u64 rx_bd_bad_fcs;
+ u64 rx_bd_packet_too_long;
+ u64 rx_bd_out_of_range;
+ u64 rx_bd_in_range;
+ /* EMAC IRQ reported RX errors */
+ u64 rx_parity;
+ u64 rx_fifo_overrun;
+ u64 rx_overrun;
+ u64 rx_bad_packet;
+ u64 rx_runt_packet;
+ u64 rx_short_event;
+ u64 rx_alignment_error;
+ u64 rx_bad_fcs;
+ u64 rx_packet_too_long;
+ u64 rx_out_of_range;
+ u64 rx_in_range;
+
+ /* Software TX Errors */
+ u64 tx_dropped;
+ /* BD reported TX errors */
+ u64 tx_bd_errors;
+ u64 tx_bd_bad_fcs;
+ u64 tx_bd_carrier_loss;
+ u64 tx_bd_excessive_deferral;
+ u64 tx_bd_excessive_collisions;
+ u64 tx_bd_late_collision;
+ u64 tx_bd_multple_collisions;
+ u64 tx_bd_single_collision;
+ u64 tx_bd_underrun;
+ u64 tx_bd_sqe;
+ /* EMAC IRQ reported TX errors */
+ u64 tx_parity;
+ u64 tx_underrun;
+ u64 tx_sqe;
+ u64 tx_errors;
+};
+
+#define EMAC_ETHTOOL_STATS_COUNT ((sizeof(struct emac_stats) + \
+ sizeof(struct emac_error_stats)) \
+ / sizeof(u64))
+
+struct emac_instance {
+ struct net_device *ndev;
+ struct resource rsrc_regs;
+ struct emac_regs __iomem *emacp;
+ struct of_device *ofdev;
+ struct device_node **blist; /* bootlist entry */
+
+ /* MAL linkage */
+ u32 mal_ph;
+ struct of_device *mal_dev;
+ u32 mal_rx_chan;
+ u32 mal_tx_chan;
+ struct mal_instance *mal;
+ struct mal_commac commac;
+
+ /* PHY infos */
+ u32 phy_mode;
+ u32 phy_map;
+ u32 phy_address;
+ u32 phy_feat_exc;
+ struct mii_phy phy;
+ struct mutex link_lock;
+ struct delayed_work link_work;
+ int link_polling;
+
+ /* Shared MDIO if any */
+ u32 mdio_ph;
+ struct of_device *mdio_dev;
+ struct emac_instance *mdio_instance;
+ struct mutex mdio_lock;
+
+ /* ZMII infos if any */
+ u32 zmii_ph;
+ u32 zmii_port;
+ struct of_device *zmii_dev;
+
+ /* RGMII infos if any */
+ u32 rgmii_ph;
+ u32 rgmii_port;
+ struct of_device *rgmii_dev;
+
+ /* TAH infos if any */
+ u32 tah_ph;
+ u32 tah_port;
+ struct of_device *tah_dev;
+
+ /* IRQs */
+ int wol_irq;
+ int emac_irq;
+
+ /* OPB bus frequency in Mhz */
+ u32 opb_bus_freq;
+
+ /* Cell index within an ASIC (for clk mgmnt) */
+ u32 cell_index;
+
+ /* Max supported MTU */
+ u32 max_mtu;
+
+ /* Feature bits (from probe table) */
+ unsigned int features;
+
+ /* Tx and Rx fifo sizes & other infos in bytes */
+ u32 tx_fifo_size;
+ u32 tx_fifo_size_gige;
+ u32 rx_fifo_size;
+ u32 rx_fifo_size_gige;
+ u32 fifo_entry_size;
+ u32 mal_burst_size; /* move to MAL ? */
+
+ /* Descriptor management
+ */
+ struct mal_descriptor *tx_desc;
+ int tx_cnt;
+ int tx_slot;
+ int ack_slot;
+
+ struct mal_descriptor *rx_desc;
+ int rx_slot;
+ struct sk_buff *rx_sg_skb; /* 1 */
+ int rx_skb_size;
+ int rx_sync_size;
+
+ struct sk_buff *tx_skb[NUM_TX_BUFF];
+ struct sk_buff *rx_skb[NUM_RX_BUFF];
+
+ /* Stats
+ */
+ struct emac_error_stats estats;
+ struct net_device_stats nstats;
+ struct emac_stats stats;
+
+ /* Misc
+ */
+ int reset_failed;
+ int stop_timeout; /* in us */
+ int no_mcast;
+ int mcast_pending;
+ struct work_struct reset_work;
+ spinlock_t lock;
+};
+
+/*
+ * Features of various EMAC implementations
+ */
+
+/*
+ * No flow control on 40x according to the original driver
+ */
+#define EMAC_FTR_NO_FLOW_CONTROL_40x 0x00000001
+/*
+ * Cell is an EMAC4
+ */
+#define EMAC_FTR_EMAC4 0x00000002
+/*
+ * For the 440SPe, AMCC inexplicably changed the polarity of
+ * the "operation complete" bit in the MII control register.
+ */
+#define EMAC_FTR_STACR_OC_INVERT 0x00000004
+/*
+ * Set if we have a TAH.
+ */
+#define EMAC_FTR_HAS_TAH 0x00000008
+/*
+ * Set if we have a ZMII.
+ */
+#define EMAC_FTR_HAS_ZMII 0x00000010
+/*
+ * Set if we have a RGMII.
+ */
+#define EMAC_FTR_HAS_RGMII 0x00000020
+/*
+ * Set if we have axon-type STACR
+ */
+#define EMAC_FTR_HAS_AXON_STACR 0x00000040
+
+
+/* Right now, we don't quite handle the always/possible masks on the
+ * most optimal way as we don't have a way to say something like
+ * always EMAC4. Patches welcome.
+ */
+enum {
+ EMAC_FTRS_ALWAYS = 0,
+
+ EMAC_FTRS_POSSIBLE =
+#ifdef CONFIG_IBM_NEW_EMAC_EMAC4
+ EMAC_FTR_EMAC4 | EMAC_FTR_HAS_AXON_STACR |
+ EMAC_FTR_STACR_OC_INVERT |
+#endif
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+ EMAC_FTR_HAS_TAH |
+#endif
+#ifdef CONFIG_IBM_NEW_EMAC_ZMII
+ EMAC_FTR_HAS_ZMII |
+#endif
+#ifdef CONFIG_IBM_NEW_EMAC_RGMII
+ EMAC_FTR_HAS_RGMII |
+#endif
+ 0,
+};
+
+static inline int emac_has_feature(struct emac_instance *dev,
+ unsigned long feature)
+{
+ return (EMAC_FTRS_ALWAYS & feature) ||
+ (EMAC_FTRS_POSSIBLE & dev->features & feature);
+}
+
+
+/* Ethtool get_regs complex data.
+ * We want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH
+ * when available.
+ *
+ * Returned BLOB consists of the ibm_emac_ethtool_regs_hdr,
+ * MAL registers, EMAC registers and optional ZMII, RGMII, TAH registers.
+ * Each register component is preceded with emac_ethtool_regs_subhdr.
+ * Order of the optional headers follows their relative bit posititions
+ * in emac_ethtool_regs_hdr.components
+ */
+#define EMAC_ETHTOOL_REGS_ZMII 0x00000001
+#define EMAC_ETHTOOL_REGS_RGMII 0x00000002
+#define EMAC_ETHTOOL_REGS_TAH 0x00000004
+
+struct emac_ethtool_regs_hdr {
+ u32 components;
+};
+
+struct emac_ethtool_regs_subhdr {
+ u32 version;
+ u32 index;
+};
+
+#endif /* __IBM_NEWEMAC_CORE_H */
diff --git a/drivers/net/ibm_newemac/debug.c b/drivers/net/ibm_newemac/debug.c
new file mode 100644
index 00000000000..170524ee0f1
--- /dev/null
+++ b/drivers/net/ibm_newemac/debug.c
@@ -0,0 +1,238 @@
+/*
+ * drivers/net/ibm_newemac/debug.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/sysrq.h>
+#include <asm/io.h>
+
+#include "core.h"
+
+static spinlock_t emac_dbg_lock = SPIN_LOCK_UNLOCKED;
+
+static void emac_desc_dump(struct emac_instance *p)
+{
+ int i;
+ printk("** EMAC %s TX BDs **\n"
+ " tx_cnt = %d tx_slot = %d ack_slot = %d\n",
+ p->ofdev->node->full_name,
+ p->tx_cnt, p->tx_slot, p->ack_slot);
+ for (i = 0; i < NUM_TX_BUFF / 2; ++i)
+ printk
+ ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n",
+ i, p->tx_desc[i].data_ptr, p->tx_skb[i] ? 'V' : ' ',
+ p->tx_desc[i].ctrl, p->tx_desc[i].data_len,
+ NUM_TX_BUFF / 2 + i,
+ p->tx_desc[NUM_TX_BUFF / 2 + i].data_ptr,
+ p->tx_skb[NUM_TX_BUFF / 2 + i] ? 'V' : ' ',
+ p->tx_desc[NUM_TX_BUFF / 2 + i].ctrl,
+ p->tx_desc[NUM_TX_BUFF / 2 + i].data_len);
+
+ printk("** EMAC %s RX BDs **\n"
+ " rx_slot = %d flags = 0x%lx rx_skb_size = %d rx_sync_size = %d\n"
+ " rx_sg_skb = 0x%p\n",
+ p->ofdev->node->full_name,
+ p->rx_slot, p->commac.flags, p->rx_skb_size,
+ p->rx_sync_size, p->rx_sg_skb);
+ for (i = 0; i < NUM_RX_BUFF / 2; ++i)
+ printk
+ ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n",
+ i, p->rx_desc[i].data_ptr, p->rx_skb[i] ? 'V' : ' ',
+ p->rx_desc[i].ctrl, p->rx_desc[i].data_len,
+ NUM_RX_BUFF / 2 + i,
+ p->rx_desc[NUM_RX_BUFF / 2 + i].data_ptr,
+ p->rx_skb[NUM_RX_BUFF / 2 + i] ? 'V' : ' ',
+ p->rx_desc[NUM_RX_BUFF / 2 + i].ctrl,
+ p->rx_desc[NUM_RX_BUFF / 2 + i].data_len);
+}
+
+static void emac_mac_dump(struct emac_instance *dev)
+{
+ struct emac_regs __iomem *p = dev->emacp;
+
+ printk("** EMAC %s registers **\n"
+ "MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n"
+ "RMR = 0x%08x ISR = 0x%08x ISER = 0x%08x\n"
+ "IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n"
+ "IAHT: 0x%04x 0x%04x 0x%04x 0x%04x "
+ "GAHT: 0x%04x 0x%04x 0x%04x 0x%04x\n"
+ "LSA = %04x%08x IPGVR = 0x%04x\n"
+ "STACR = 0x%08x TRTR = 0x%08x RWMR = 0x%08x\n"
+ "OCTX = 0x%08x OCRX = 0x%08x IPCR = 0x%08x\n",
+ dev->ofdev->node->full_name, in_be32(&p->mr0), in_be32(&p->mr1),
+ in_be32(&p->tmr0), in_be32(&p->tmr1),
+ in_be32(&p->rmr), in_be32(&p->isr), in_be32(&p->iser),
+ in_be32(&p->iahr), in_be32(&p->ialr), in_be32(&p->vtpid),
+ in_be32(&p->vtci),
+ in_be32(&p->iaht1), in_be32(&p->iaht2), in_be32(&p->iaht3),
+ in_be32(&p->iaht4),
+ in_be32(&p->gaht1), in_be32(&p->gaht2), in_be32(&p->gaht3),
+ in_be32(&p->gaht4),
+ in_be32(&p->lsah), in_be32(&p->lsal), in_be32(&p->ipgvr),
+ in_be32(&p->stacr), in_be32(&p->trtr), in_be32(&p->rwmr),
+ in_be32(&p->octx), in_be32(&p->ocrx), in_be32(&p->ipcr)
+ );
+
+ emac_desc_dump(dev);
+}
+
+static void emac_mal_dump(struct mal_instance *mal)
+{
+ int i;
+
+ printk("** MAL %s Registers **\n"
+ "CFG = 0x%08x ESR = 0x%08x IER = 0x%08x\n"
+ "TX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n"
+ "RX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n",
+ mal->ofdev->node->full_name,
+ get_mal_dcrn(mal, MAL_CFG), get_mal_dcrn(mal, MAL_ESR),
+ get_mal_dcrn(mal, MAL_IER),
+ get_mal_dcrn(mal, MAL_TXCASR), get_mal_dcrn(mal, MAL_TXCARR),
+ get_mal_dcrn(mal, MAL_TXEOBISR), get_mal_dcrn(mal, MAL_TXDEIR),
+ get_mal_dcrn(mal, MAL_RXCASR), get_mal_dcrn(mal, MAL_RXCARR),
+ get_mal_dcrn(mal, MAL_RXEOBISR), get_mal_dcrn(mal, MAL_RXDEIR)
+ );
+
+ printk("TX|");
+ for (i = 0; i < mal->num_tx_chans; ++i) {
+ if (i && !(i % 4))
+ printk("\n ");
+ printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_TXCTPR(i)));
+ }
+ printk("\nRX|");
+ for (i = 0; i < mal->num_rx_chans; ++i) {
+ if (i && !(i % 4))
+ printk("\n ");
+ printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_RXCTPR(i)));
+ }
+ printk("\n ");
+ for (i = 0; i < mal->num_rx_chans; ++i) {
+ u32 r = get_mal_dcrn(mal, MAL_RCBS(i));
+ if (i && !(i % 3))
+ printk("\n ");
+ printk("RCBS%d = 0x%08x (%d) ", i, r, r * 16);
+ }
+ printk("\n");
+}
+
+static struct emac_instance *__emacs[4];
+static struct mal_instance *__mals[1];
+
+void emac_dbg_register(struct emac_instance *dev)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&emac_dbg_lock, flags);
+ for (i = 0; i < ARRAY_SIZE(__emacs); i++)
+ if (__emacs[i] == NULL) {
+ __emacs[i] = dev;
+ break;
+ }
+ spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+void emac_dbg_unregister(struct emac_instance *dev)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&emac_dbg_lock, flags);
+ for (i = 0; i < ARRAY_SIZE(__emacs); i++)
+ if (__emacs[i] == dev) {
+ __emacs[i] = NULL;
+ break;
+ }
+ spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+void mal_dbg_register(struct mal_instance *mal)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&emac_dbg_lock, flags);
+ for (i = 0; i < ARRAY_SIZE(__mals); i++)
+ if (__mals[i] == NULL) {
+ __mals[i] = mal;
+ break;
+ }
+ spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+void mal_dbg_unregister(struct mal_instance *mal)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&emac_dbg_lock, flags);
+ for (i = 0; i < ARRAY_SIZE(__mals); i++)
+ if (__mals[i] == mal) {
+ __mals[i] = NULL;
+ break;
+ }
+ spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+void emac_dbg_dump_all(void)
+{
+ unsigned int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&emac_dbg_lock, flags);
+
+ for (i = 0; i < ARRAY_SIZE(__mals); ++i)
+ if (__mals[i])
+ emac_mal_dump(__mals[i]);
+
+ for (i = 0; i < ARRAY_SIZE(__emacs); ++i)
+ if (__emacs[i])
+ emac_mac_dump(__emacs[i]);
+
+ spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+static void emac_sysrq_handler(int key, struct tty_struct *tty)
+{
+ emac_dbg_dump_all();
+}
+
+static struct sysrq_key_op emac_sysrq_op = {
+ .handler = emac_sysrq_handler,
+ .help_msg = "emaC",
+ .action_msg = "Show EMAC(s) status",
+};
+
+int __init emac_init_debug(void)
+{
+ return register_sysrq_key('c', &emac_sysrq_op);
+}
+
+void __exit emac_fini_debug(void)
+{
+ unregister_sysrq_key('c', &emac_sysrq_op);
+}
+
+#else
+int __init emac_init_debug(void)
+{
+ return 0;
+}
+void __exit emac_fini_debug(void)
+{
+}
+#endif /* CONFIG_MAGIC_SYSRQ */
diff --git a/drivers/net/ibm_newemac/debug.h b/drivers/net/ibm_newemac/debug.h
new file mode 100644
index 00000000000..1dd2dcbc157
--- /dev/null
+++ b/drivers/net/ibm_newemac/debug.h
@@ -0,0 +1,78 @@
+/*
+ * drivers/net/ibm_newemac/debug.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __IBM_NEWEMAC_DEBUG_H
+#define __IBM_NEWEMAC_DEBUG_H
+
+#include <linux/init.h>
+
+#include "core.h"
+
+#if defined(CONFIG_IBM_NEW_EMAC_DEBUG)
+
+struct emac_instance;
+struct mal_instance;
+
+extern void emac_dbg_register(struct emac_instance *dev);
+extern void emac_dbg_unregister(struct emac_instance *dev);
+extern void mal_dbg_register(struct mal_instance *mal);
+extern void mal_dbg_unregister(struct mal_instance *mal);
+extern int emac_init_debug(void) __init;
+extern void emac_fini_debug(void) __exit;
+extern void emac_dbg_dump_all(void);
+
+# define DBG_LEVEL 1
+
+#else
+
+# define emac_dbg_register(x) do { } while(0)
+# define emac_dbg_unregister(x) do { } while(0)
+# define mal_dbg_register(x) do { } while(0)
+# define mal_dbg_unregister(x) do { } while(0)
+# define emac_init_debug() do { } while(0)
+# define emac_fini_debug() do { } while(0)
+# define emac_dbg_dump_all() do { } while(0)
+
+# define DBG_LEVEL 0
+
+#endif
+
+#define EMAC_DBG(dev, name, fmt, arg...) \
+ printk(KERN_DEBUG #name "%s: " fmt, dev->ofdev->node->full_name, ## arg)
+
+#if DBG_LEVEL > 0
+# define DBG(d,f,x...) EMAC_DBG(d, emac, f, ##x)
+# define MAL_DBG(d,f,x...) EMAC_DBG(d, mal, f, ##x)
+# define ZMII_DBG(d,f,x...) EMAC_DBG(d, zmii, f, ##x)
+# define RGMII_DBG(d,f,x...) EMAC_DBG(d, rgmii, f, ##x)
+# define NL "\n"
+#else
+# define DBG(f,x...) ((void)0)
+# define MAL_DBG(d,f,x...) ((void)0)
+# define ZMII_DBG(d,f,x...) ((void)0)
+# define RGMII_DBG(d,f,x...) ((void)0)
+#endif
+#if DBG_LEVEL > 1
+# define DBG2(d,f,x...) DBG(d,f, ##x)
+# define MAL_DBG2(d,f,x...) MAL_DBG(d,f, ##x)
+# define ZMII_DBG2(d,f,x...) ZMII_DBG(d,f, ##x)
+# define RGMII_DBG2(d,f,x...) RGMII_DBG(d,f, ##x)
+#else
+# define DBG2(f,x...) ((void)0)
+# define MAL_DBG2(d,f,x...) ((void)0)
+# define ZMII_DBG2(d,f,x...) ((void)0)
+# define RGMII_DBG2(d,f,x...) ((void)0)
+#endif
+
+#endif /* __IBM_NEWEMAC_DEBUG_H */
diff --git a/drivers/net/ibm_newemac/emac.h b/drivers/net/ibm_newemac/emac.h
new file mode 100644
index 00000000000..bef92efeead
--- /dev/null
+++ b/drivers/net/ibm_newemac/emac.h
@@ -0,0 +1,268 @@
+/*
+ * drivers/net/ibm_newemac/emac.h
+ *
+ * Register definitions for PowerPC 4xx on-chip ethernet contoller
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Armin Kuster <akuster@mvista.com>
+ * Copyright 2002-2004 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __IBM_NEWEMAC_H
+#define __IBM_NEWEMAC_H
+
+#include <linux/types.h>
+
+/* EMAC registers Write Access rules */
+struct emac_regs {
+ u32 mr0; /* special */
+ u32 mr1; /* Reset */
+ u32 tmr0; /* special */
+ u32 tmr1; /* special */
+ u32 rmr; /* Reset */
+ u32 isr; /* Always */
+ u32 iser; /* Reset */
+ u32 iahr; /* Reset, R, T */
+ u32 ialr; /* Reset, R, T */
+ u32 vtpid; /* Reset, R, T */
+ u32 vtci; /* Reset, R, T */
+ u32 ptr; /* Reset, T */
+ u32 iaht1; /* Reset, R */
+ u32 iaht2; /* Reset, R */
+ u32 iaht3; /* Reset, R */
+ u32 iaht4; /* Reset, R */
+ u32 gaht1; /* Reset, R */
+ u32 gaht2; /* Reset, R */
+ u32 gaht3; /* Reset, R */
+ u32 gaht4; /* Reset, R */
+ u32 lsah;
+ u32 lsal;
+ u32 ipgvr; /* Reset, T */
+ u32 stacr; /* special */
+ u32 trtr; /* special */
+ u32 rwmr; /* Reset */
+ u32 octx;
+ u32 ocrx;
+ u32 ipcr;
+};
+
+/*
+ * PHY mode settings (EMAC <-> ZMII/RGMII bridge <-> PHY)
+ */
+#define PHY_MODE_NA 0
+#define PHY_MODE_MII 1
+#define PHY_MODE_RMII 2
+#define PHY_MODE_SMII 3
+#define PHY_MODE_RGMII 4
+#define PHY_MODE_TBI 5
+#define PHY_MODE_GMII 6
+#define PHY_MODE_RTBI 7
+#define PHY_MODE_SGMII 8
+
+
+#define EMAC_ETHTOOL_REGS_VER 0
+#define EMAC_ETHTOOL_REGS_SIZE (sizeof(struct emac_regs) - sizeof(u32))
+#define EMAC4_ETHTOOL_REGS_VER 1
+#define EMAC4_ETHTOOL_REGS_SIZE sizeof(struct emac_regs)
+
+/* EMACx_MR0 */
+#define EMAC_MR0_RXI 0x80000000
+#define EMAC_MR0_TXI 0x40000000
+#define EMAC_MR0_SRST 0x20000000
+#define EMAC_MR0_TXE 0x10000000
+#define EMAC_MR0_RXE 0x08000000
+#define EMAC_MR0_WKE 0x04000000
+
+/* EMACx_MR1 */
+#define EMAC_MR1_FDE 0x80000000
+#define EMAC_MR1_ILE 0x40000000
+#define EMAC_MR1_VLE 0x20000000
+#define EMAC_MR1_EIFC 0x10000000
+#define EMAC_MR1_APP 0x08000000
+#define EMAC_MR1_IST 0x01000000
+
+#define EMAC_MR1_MF_MASK 0x00c00000
+#define EMAC_MR1_MF_10 0x00000000
+#define EMAC_MR1_MF_100 0x00400000
+#define EMAC_MR1_MF_1000 0x00800000
+#define EMAC_MR1_MF_1000GPCS 0x00c00000
+#define EMAC_MR1_MF_IPPA(id) (((id) & 0x1f) << 6)
+
+#define EMAC_MR1_RFS_4K 0x00300000
+#define EMAC_MR1_RFS_16K 0x00000000
+#define EMAC_MR1_TFS_2K 0x00080000
+#define EMAC_MR1_TR0_MULT 0x00008000
+#define EMAC_MR1_JPSM 0x00000000
+#define EMAC_MR1_MWSW_001 0x00000000
+#define EMAC_MR1_BASE(opb) (EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT)
+
+
+#define EMAC4_MR1_RFS_2K 0x00100000
+#define EMAC4_MR1_RFS_4K 0x00180000
+#define EMAC4_MR1_RFS_16K 0x00280000
+#define EMAC4_MR1_TFS_2K 0x00020000
+#define EMAC4_MR1_TFS_4K 0x00030000
+#define EMAC4_MR1_TR 0x00008000
+#define EMAC4_MR1_MWSW_001 0x00001000
+#define EMAC4_MR1_JPSM 0x00000800
+#define EMAC4_MR1_OBCI_MASK 0x00000038
+#define EMAC4_MR1_OBCI_50 0x00000000
+#define EMAC4_MR1_OBCI_66 0x00000008
+#define EMAC4_MR1_OBCI_83 0x00000010
+#define EMAC4_MR1_OBCI_100 0x00000018
+#define EMAC4_MR1_OBCI_100P 0x00000020
+#define EMAC4_MR1_OBCI(freq) ((freq) <= 50 ? EMAC4_MR1_OBCI_50 : \
+ (freq) <= 66 ? EMAC4_MR1_OBCI_66 : \
+ (freq) <= 83 ? EMAC4_MR1_OBCI_83 : \
+ (freq) <= 100 ? EMAC4_MR1_OBCI_100 : \
+ EMAC4_MR1_OBCI_100P)
+
+/* EMACx_TMR0 */
+#define EMAC_TMR0_GNP 0x80000000
+#define EMAC_TMR0_DEFAULT 0x00000000
+#define EMAC4_TMR0_TFAE_2_32 0x00000001
+#define EMAC4_TMR0_TFAE_4_64 0x00000002
+#define EMAC4_TMR0_TFAE_8_128 0x00000003
+#define EMAC4_TMR0_TFAE_16_256 0x00000004
+#define EMAC4_TMR0_TFAE_32_512 0x00000005
+#define EMAC4_TMR0_TFAE_64_1024 0x00000006
+#define EMAC4_TMR0_TFAE_128_2048 0x00000007
+#define EMAC4_TMR0_DEFAULT EMAC4_TMR0_TFAE_2_32
+#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP | EMAC_TMR0_DEFAULT)
+#define EMAC4_TMR0_XMIT (EMAC_TMR0_GNP | EMAC4_TMR0_DEFAULT)
+
+/* EMACx_TMR1 */
+
+#define EMAC_TMR1(l,h) (((l) << 27) | (((h) & 0xff) << 16))
+#define EMAC4_TMR1(l,h) (((l) << 27) | (((h) & 0x3ff) << 14))
+
+/* EMACx_RMR */
+#define EMAC_RMR_SP 0x80000000
+#define EMAC_RMR_SFCS 0x40000000
+#define EMAC_RMR_RRP 0x20000000
+#define EMAC_RMR_RFP 0x10000000
+#define EMAC_RMR_ROP 0x08000000
+#define EMAC_RMR_RPIR 0x04000000
+#define EMAC_RMR_PPP 0x02000000
+#define EMAC_RMR_PME 0x01000000
+#define EMAC_RMR_PMME 0x00800000
+#define EMAC_RMR_IAE 0x00400000
+#define EMAC_RMR_MIAE 0x00200000
+#define EMAC_RMR_BAE 0x00100000
+#define EMAC_RMR_MAE 0x00080000
+#define EMAC_RMR_BASE 0x00000000
+#define EMAC4_RMR_RFAF_2_32 0x00000001
+#define EMAC4_RMR_RFAF_4_64 0x00000002
+#define EMAC4_RMR_RFAF_8_128 0x00000003
+#define EMAC4_RMR_RFAF_16_256 0x00000004
+#define EMAC4_RMR_RFAF_32_512 0x00000005
+#define EMAC4_RMR_RFAF_64_1024 0x00000006
+#define EMAC4_RMR_RFAF_128_2048 0x00000007
+#define EMAC4_RMR_BASE EMAC4_RMR_RFAF_128_2048
+
+/* EMACx_ISR & EMACx_ISER */
+#define EMAC4_ISR_TXPE 0x20000000
+#define EMAC4_ISR_RXPE 0x10000000
+#define EMAC4_ISR_TXUE 0x08000000
+#define EMAC4_ISR_RXOE 0x04000000
+#define EMAC_ISR_OVR 0x02000000
+#define EMAC_ISR_PP 0x01000000
+#define EMAC_ISR_BP 0x00800000
+#define EMAC_ISR_RP 0x00400000
+#define EMAC_ISR_SE 0x00200000
+#define EMAC_ISR_ALE 0x00100000
+#define EMAC_ISR_BFCS 0x00080000
+#define EMAC_ISR_PTLE 0x00040000
+#define EMAC_ISR_ORE 0x00020000
+#define EMAC_ISR_IRE 0x00010000
+#define EMAC_ISR_SQE 0x00000080
+#define EMAC_ISR_TE 0x00000040
+#define EMAC_ISR_MOS 0x00000002
+#define EMAC_ISR_MOF 0x00000001
+
+/* EMACx_STACR */
+#define EMAC_STACR_PHYD_MASK 0xffff
+#define EMAC_STACR_PHYD_SHIFT 16
+#define EMAC_STACR_OC 0x00008000
+#define EMAC_STACR_PHYE 0x00004000
+#define EMAC_STACR_STAC_MASK 0x00003000
+#define EMAC_STACR_STAC_READ 0x00001000
+#define EMAC_STACR_STAC_WRITE 0x00002000
+#define EMAC_STACR_OPBC_MASK 0x00000C00
+#define EMAC_STACR_OPBC_50 0x00000000
+#define EMAC_STACR_OPBC_66 0x00000400
+#define EMAC_STACR_OPBC_83 0x00000800
+#define EMAC_STACR_OPBC_100 0x00000C00
+#define EMAC_STACR_OPBC(freq) ((freq) <= 50 ? EMAC_STACR_OPBC_50 : \
+ (freq) <= 66 ? EMAC_STACR_OPBC_66 : \
+ (freq) <= 83 ? EMAC_STACR_OPBC_83 : EMAC_STACR_OPBC_100)
+#define EMAC_STACR_BASE(opb) EMAC_STACR_OPBC(opb)
+#define EMAC4_STACR_BASE(opb) 0x00000000
+#define EMAC_STACR_PCDA_MASK 0x1f
+#define EMAC_STACR_PCDA_SHIFT 5
+#define EMAC_STACR_PRA_MASK 0x1f
+#define EMACX_STACR_STAC_MASK 0x00003800
+#define EMACX_STACR_STAC_READ 0x00001000
+#define EMACX_STACR_STAC_WRITE 0x00000800
+#define EMACX_STACR_STAC_IND_ADDR 0x00002000
+#define EMACX_STACR_STAC_IND_READ 0x00003800
+#define EMACX_STACR_STAC_IND_READINC 0x00003000
+#define EMACX_STACR_STAC_IND_WRITE 0x00002800
+
+
+/* EMACx_TRTR */
+#define EMAC_TRTR_SHIFT_EMAC4 27
+#define EMAC_TRTR_SHIFT 24
+
+/* EMAC specific TX descriptor control fields (write access) */
+#define EMAC_TX_CTRL_GFCS 0x0200
+#define EMAC_TX_CTRL_GP 0x0100
+#define EMAC_TX_CTRL_ISA 0x0080
+#define EMAC_TX_CTRL_RSA 0x0040
+#define EMAC_TX_CTRL_IVT 0x0020
+#define EMAC_TX_CTRL_RVT 0x0010
+#define EMAC_TX_CTRL_TAH_CSUM 0x000e
+
+/* EMAC specific TX descriptor status fields (read access) */
+#define EMAC_TX_ST_BFCS 0x0200
+#define EMAC_TX_ST_LCS 0x0080
+#define EMAC_TX_ST_ED 0x0040
+#define EMAC_TX_ST_EC 0x0020
+#define EMAC_TX_ST_LC 0x0010
+#define EMAC_TX_ST_MC 0x0008
+#define EMAC_TX_ST_SC 0x0004
+#define EMAC_TX_ST_UR 0x0002
+#define EMAC_TX_ST_SQE 0x0001
+#define EMAC_IS_BAD_TX (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \
+ EMAC_TX_ST_EC | EMAC_TX_ST_LC | \
+ EMAC_TX_ST_MC | EMAC_TX_ST_UR)
+#define EMAC_IS_BAD_TX_TAH (EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \
+ EMAC_TX_ST_EC | EMAC_TX_ST_LC)
+
+/* EMAC specific RX descriptor status fields (read access) */
+#define EMAC_RX_ST_OE 0x0200
+#define EMAC_RX_ST_PP 0x0100
+#define EMAC_RX_ST_BP 0x0080
+#define EMAC_RX_ST_RP 0x0040
+#define EMAC_RX_ST_SE 0x0020
+#define EMAC_RX_ST_AE 0x0010
+#define EMAC_RX_ST_BFCS 0x0008
+#define EMAC_RX_ST_PTL 0x0004
+#define EMAC_RX_ST_ORE 0x0002
+#define EMAC_RX_ST_IRE 0x0001
+#define EMAC_RX_TAH_BAD_CSUM 0x0003
+#define EMAC_BAD_RX_MASK (EMAC_RX_ST_OE | EMAC_RX_ST_BP | \
+ EMAC_RX_ST_RP | EMAC_RX_ST_SE | \
+ EMAC_RX_ST_AE | EMAC_RX_ST_BFCS | \
+ EMAC_RX_ST_PTL | EMAC_RX_ST_ORE | \
+ EMAC_RX_ST_IRE )
+#endif /* __IBM_NEWEMAC_H */
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c
new file mode 100644
index 00000000000..9a88f71db00
--- /dev/null
+++ b/drivers/net/ibm_newemac/mal.c
@@ -0,0 +1,721 @@
+/*
+ * drivers/net/ibm_newemac/mal.c
+ *
+ * Memory Access Layer (MAL) support
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>,
+ * David Gibson <hermes@gibson.dropbear.id.au>,
+ *
+ * Armin Kuster <akuster@mvista.com>
+ * Copyright 2002 MontaVista Softare Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/delay.h>
+
+#include "core.h"
+
+static int mal_count;
+
+int __devinit mal_register_commac(struct mal_instance *mal,
+ struct mal_commac *commac)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mal->lock, flags);
+
+ MAL_DBG(mal, "reg(%08x, %08x)" NL,
+ commac->tx_chan_mask, commac->rx_chan_mask);
+
+ /* Don't let multiple commacs claim the same channel(s) */
+ if ((mal->tx_chan_mask & commac->tx_chan_mask) ||
+ (mal->rx_chan_mask & commac->rx_chan_mask)) {
+ spin_unlock_irqrestore(&mal->lock, flags);
+ printk(KERN_WARNING "mal%d: COMMAC channels conflict!\n",
+ mal->index);
+ return -EBUSY;
+ }
+
+ if (list_empty(&mal->list))
+ napi_enable(&mal->napi);
+ mal->tx_chan_mask |= commac->tx_chan_mask;
+ mal->rx_chan_mask |= commac->rx_chan_mask;
+ list_add(&commac->list, &mal->list);
+
+ spin_unlock_irqrestore(&mal->lock, flags);
+
+ return 0;
+}
+
+void __devexit mal_unregister_commac(struct mal_instance *mal,
+ struct mal_commac *commac)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mal->lock, flags);
+
+ MAL_DBG(mal, "unreg(%08x, %08x)" NL,
+ commac->tx_chan_mask, commac->rx_chan_mask);
+
+ mal->tx_chan_mask &= ~commac->tx_chan_mask;
+ mal->rx_chan_mask &= ~commac->rx_chan_mask;
+ list_del_init(&commac->list);
+ if (list_empty(&mal->list))
+ napi_disable(&mal->napi);
+
+ spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+int mal_set_rcbs(struct mal_instance *mal, int channel, unsigned long size)
+{
+ BUG_ON(channel < 0 || channel >= mal->num_rx_chans ||
+ size > MAL_MAX_RX_SIZE);
+
+ MAL_DBG(mal, "set_rbcs(%d, %lu)" NL, channel, size);
+
+ if (size & 0xf) {
+ printk(KERN_WARNING
+ "mal%d: incorrect RX size %lu for the channel %d\n",
+ mal->index, size, channel);
+ return -EINVAL;
+ }
+
+ set_mal_dcrn(mal, MAL_RCBS(channel), size >> 4);
+ return 0;
+}
+
+int mal_tx_bd_offset(struct mal_instance *mal, int channel)
+{
+ BUG_ON(channel < 0 || channel >= mal->num_tx_chans);
+
+ return channel * NUM_TX_BUFF;
+}
+
+int mal_rx_bd_offset(struct mal_instance *mal, int channel)
+{
+ BUG_ON(channel < 0 || channel >= mal->num_rx_chans);
+ return mal->num_tx_chans * NUM_TX_BUFF + channel * NUM_RX_BUFF;
+}
+
+void mal_enable_tx_channel(struct mal_instance *mal, int channel)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mal->lock, flags);
+
+ MAL_DBG(mal, "enable_tx(%d)" NL, channel);
+
+ set_mal_dcrn(mal, MAL_TXCASR,
+ get_mal_dcrn(mal, MAL_TXCASR) | MAL_CHAN_MASK(channel));
+
+ spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+void mal_disable_tx_channel(struct mal_instance *mal, int channel)
+{
+ set_mal_dcrn(mal, MAL_TXCARR, MAL_CHAN_MASK(channel));
+
+ MAL_DBG(mal, "disable_tx(%d)" NL, channel);
+}
+
+void mal_enable_rx_channel(struct mal_instance *mal, int channel)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mal->lock, flags);
+
+ MAL_DBG(mal, "enable_rx(%d)" NL, channel);
+
+ set_mal_dcrn(mal, MAL_RXCASR,
+ get_mal_dcrn(mal, MAL_RXCASR) | MAL_CHAN_MASK(channel));
+
+ spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+void mal_disable_rx_channel(struct mal_instance *mal, int channel)
+{
+ set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel));
+
+ MAL_DBG(mal, "disable_rx(%d)" NL, channel);
+}
+
+void mal_poll_add(struct mal_instance *mal, struct mal_commac *commac)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mal->lock, flags);
+
+ MAL_DBG(mal, "poll_add(%p)" NL, commac);
+
+ /* starts disabled */
+ set_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags);
+
+ list_add_tail(&commac->poll_list, &mal->poll_list);
+
+ spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+void mal_poll_del(struct mal_instance *mal, struct mal_commac *commac)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mal->lock, flags);
+
+ MAL_DBG(mal, "poll_del(%p)" NL, commac);
+
+ list_del(&commac->poll_list);
+
+ spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+/* synchronized by mal_poll() */
+static inline void mal_enable_eob_irq(struct mal_instance *mal)
+{
+ MAL_DBG2(mal, "enable_irq" NL);
+
+ // XXX might want to cache MAL_CFG as the DCR read can be slooooow
+ set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) | MAL_CFG_EOPIE);
+}
+
+/* synchronized by NAPI state */
+static inline void mal_disable_eob_irq(struct mal_instance *mal)
+{
+ // XXX might want to cache MAL_CFG as the DCR read can be slooooow
+ set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) & ~MAL_CFG_EOPIE);
+
+ MAL_DBG2(mal, "disable_irq" NL);
+}
+
+static irqreturn_t mal_serr(int irq, void *dev_instance)
+{
+ struct mal_instance *mal = dev_instance;
+
+ u32 esr = get_mal_dcrn(mal, MAL_ESR);
+
+ /* Clear the error status register */
+ set_mal_dcrn(mal, MAL_ESR, esr);
+
+ MAL_DBG(mal, "SERR %08x" NL, esr);
+
+ if (esr & MAL_ESR_EVB) {
+ if (esr & MAL_ESR_DE) {
+ /* We ignore Descriptor error,
+ * TXDE or RXDE interrupt will be generated anyway.
+ */
+ return IRQ_HANDLED;
+ }
+
+ if (esr & MAL_ESR_PEIN) {
+ /* PLB error, it's probably buggy hardware or
+ * incorrect physical address in BD (i.e. bug)
+ */
+ if (net_ratelimit())
+ printk(KERN_ERR
+ "mal%d: system error, "
+ "PLB (ESR = 0x%08x)\n",
+ mal->index, esr);
+ return IRQ_HANDLED;
+ }
+
+ /* OPB error, it's probably buggy hardware or incorrect
+ * EBC setup
+ */
+ if (net_ratelimit())
+ printk(KERN_ERR
+ "mal%d: system error, OPB (ESR = 0x%08x)\n",
+ mal->index, esr);
+ }
+ return IRQ_HANDLED;
+}
+
+static inline void mal_schedule_poll(struct mal_instance *mal)
+{
+ if (likely(napi_schedule_prep(&mal->napi))) {
+ MAL_DBG2(mal, "schedule_poll" NL);
+ mal_disable_eob_irq(mal);
+ __napi_schedule(&mal->napi);
+ } else
+ MAL_DBG2(mal, "already in poll" NL);
+}
+
+static irqreturn_t mal_txeob(int irq, void *dev_instance)
+{
+ struct mal_instance *mal = dev_instance;
+
+ u32 r = get_mal_dcrn(mal, MAL_TXEOBISR);
+
+ MAL_DBG2(mal, "txeob %08x" NL, r);
+
+ mal_schedule_poll(mal);
+ set_mal_dcrn(mal, MAL_TXEOBISR, r);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mal_rxeob(int irq, void *dev_instance)
+{
+ struct mal_instance *mal = dev_instance;
+
+ u32 r = get_mal_dcrn(mal, MAL_RXEOBISR);
+
+ MAL_DBG2(mal, "rxeob %08x" NL, r);
+
+ mal_schedule_poll(mal);
+ set_mal_dcrn(mal, MAL_RXEOBISR, r);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mal_txde(int irq, void *dev_instance)
+{
+ struct mal_instance *mal = dev_instance;
+
+ u32 deir = get_mal_dcrn(mal, MAL_TXDEIR);
+ set_mal_dcrn(mal, MAL_TXDEIR, deir);
+
+ MAL_DBG(mal, "txde %08x" NL, deir);
+
+ if (net_ratelimit())
+ printk(KERN_ERR
+ "mal%d: TX descriptor error (TXDEIR = 0x%08x)\n",
+ mal->index, deir);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mal_rxde(int irq, void *dev_instance)
+{
+ struct mal_instance *mal = dev_instance;
+ struct list_head *l;
+
+ u32 deir = get_mal_dcrn(mal, MAL_RXDEIR);
+
+ MAL_DBG(mal, "rxde %08x" NL, deir);
+
+ list_for_each(l, &mal->list) {
+ struct mal_commac *mc = list_entry(l, struct mal_commac, list);
+ if (deir & mc->rx_chan_mask) {
+ set_bit(MAL_COMMAC_RX_STOPPED, &mc->flags);
+ mc->ops->rxde(mc->dev);
+ }
+ }
+
+ mal_schedule_poll(mal);
+ set_mal_dcrn(mal, MAL_RXDEIR, deir);
+
+ return IRQ_HANDLED;
+}
+
+void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac)
+{
+ /* Spinlock-type semantics: only one caller disable poll at a time */
+ while (test_and_set_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags))
+ msleep(1);
+
+ /* Synchronize with the MAL NAPI poller */
+ napi_synchronize(&mal->napi);
+}
+
+void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac)
+{
+ smp_wmb();
+ clear_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags);
+
+ /* Feels better to trigger a poll here to catch up with events that
+ * may have happened on this channel while disabled. It will most
+ * probably be delayed until the next interrupt but that's mostly a
+ * non-issue in the context where this is called.
+ */
+ napi_schedule(&mal->napi);
+}
+
+static int mal_poll(struct napi_struct *napi, int budget)
+{
+ struct mal_instance *mal = container_of(napi, struct mal_instance, napi);
+ struct list_head *l;
+ int received = 0;
+ unsigned long flags;
+
+ MAL_DBG2(mal, "poll(%d)" NL, budget);
+ again:
+ /* Process TX skbs */
+ list_for_each(l, &mal->poll_list) {
+ struct mal_commac *mc =
+ list_entry(l, struct mal_commac, poll_list);
+ mc->ops->poll_tx(mc->dev);
+ }
+
+ /* Process RX skbs.
+ *
+ * We _might_ need something more smart here to enforce polling
+ * fairness.
+ */
+ list_for_each(l, &mal->poll_list) {
+ struct mal_commac *mc =
+ list_entry(l, struct mal_commac, poll_list);
+ int n;
+ if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags)))
+ continue;
+ n = mc->ops->poll_rx(mc->dev, budget);
+ if (n) {
+ received += n;
+ budget -= n;
+ if (budget <= 0)
+ goto more_work; // XXX What if this is the last one ?
+ }
+ }
+
+ /* We need to disable IRQs to protect from RXDE IRQ here */
+ spin_lock_irqsave(&mal->lock, flags);
+ __napi_complete(napi);
+ mal_enable_eob_irq(mal);
+ spin_unlock_irqrestore(&mal->lock, flags);
+
+ /* Check for "rotting" packet(s) */
+ list_for_each(l, &mal->poll_list) {
+ struct mal_commac *mc =
+ list_entry(l, struct mal_commac, poll_list);
+ if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags)))
+ continue;
+ if (unlikely(mc->ops->peek_rx(mc->dev) ||
+ test_bit(MAL_COMMAC_RX_STOPPED, &mc->flags))) {
+ MAL_DBG2(mal, "rotting packet" NL);
+ if (napi_reschedule(napi))
+ mal_disable_eob_irq(mal);
+ else
+ MAL_DBG2(mal, "already in poll list" NL);
+
+ if (budget > 0)
+ goto again;
+ else
+ goto more_work;
+ }
+ mc->ops->poll_tx(mc->dev);
+ }
+
+ more_work:
+ MAL_DBG2(mal, "poll() %d <- %d" NL, budget, received);
+ return received;
+}
+
+static void mal_reset(struct mal_instance *mal)
+{
+ int n = 10;
+
+ MAL_DBG(mal, "reset" NL);
+
+ set_mal_dcrn(mal, MAL_CFG, MAL_CFG_SR);
+
+ /* Wait for reset to complete (1 system clock) */
+ while ((get_mal_dcrn(mal, MAL_CFG) & MAL_CFG_SR) && n)
+ --n;
+
+ if (unlikely(!n))
+ printk(KERN_ERR "mal%d: reset timeout\n", mal->index);
+}
+
+int mal_get_regs_len(struct mal_instance *mal)
+{
+ return sizeof(struct emac_ethtool_regs_subhdr) +
+ sizeof(struct mal_regs);
+}
+
+void *mal_dump_regs(struct mal_instance *mal, void *buf)
+{
+ struct emac_ethtool_regs_subhdr *hdr = buf;
+ struct mal_regs *regs = (struct mal_regs *)(hdr + 1);
+ int i;
+
+ hdr->version = mal->version;
+ hdr->index = mal->index;
+
+ regs->tx_count = mal->num_tx_chans;
+ regs->rx_count = mal->num_rx_chans;
+
+ regs->cfg = get_mal_dcrn(mal, MAL_CFG);
+ regs->esr = get_mal_dcrn(mal, MAL_ESR);
+ regs->ier = get_mal_dcrn(mal, MAL_IER);
+ regs->tx_casr = get_mal_dcrn(mal, MAL_TXCASR);
+ regs->tx_carr = get_mal_dcrn(mal, MAL_TXCARR);
+ regs->tx_eobisr = get_mal_dcrn(mal, MAL_TXEOBISR);
+ regs->tx_deir = get_mal_dcrn(mal, MAL_TXDEIR);
+ regs->rx_casr = get_mal_dcrn(mal, MAL_RXCASR);
+ regs->rx_carr = get_mal_dcrn(mal, MAL_RXCARR);
+ regs->rx_eobisr = get_mal_dcrn(mal, MAL_RXEOBISR);
+ regs->rx_deir = get_mal_dcrn(mal, MAL_RXDEIR);
+
+ for (i = 0; i < regs->tx_count; ++i)
+ regs->tx_ctpr[i] = get_mal_dcrn(mal, MAL_TXCTPR(i));
+
+ for (i = 0; i < regs->rx_count; ++i) {
+ regs->rx_ctpr[i] = get_mal_dcrn(mal, MAL_RXCTPR(i));
+ regs->rcbs[i] = get_mal_dcrn(mal, MAL_RCBS(i));
+ }
+ return regs + 1;
+}
+
+static int __devinit mal_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct mal_instance *mal;
+ int err = 0, i, bd_size;
+ int index = mal_count++;
+ unsigned int dcr_base;
+ const u32 *prop;
+ u32 cfg;
+
+ mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL);
+ if (!mal) {
+ printk(KERN_ERR
+ "mal%d: out of memory allocating MAL structure!\n",
+ index);
+ return -ENOMEM;
+ }
+ mal->index = index;
+ mal->ofdev = ofdev;
+ mal->version = of_device_is_compatible(ofdev->node, "ibm,mcmal2") ? 2 : 1;
+
+ MAL_DBG(mal, "probe" NL);
+
+ prop = of_get_property(ofdev->node, "num-tx-chans", NULL);
+ if (prop == NULL) {
+ printk(KERN_ERR
+ "mal%d: can't find MAL num-tx-chans property!\n",
+ index);
+ err = -ENODEV;
+ goto fail;
+ }
+ mal->num_tx_chans = prop[0];
+
+ prop = of_get_property(ofdev->node, "num-rx-chans", NULL);
+ if (prop == NULL) {
+ printk(KERN_ERR
+ "mal%d: can't find MAL num-rx-chans property!\n",
+ index);
+ err = -ENODEV;
+ goto fail;
+ }
+ mal->num_rx_chans = prop[0];
+
+ dcr_base = dcr_resource_start(ofdev->node, 0);
+ if (dcr_base == 0) {
+ printk(KERN_ERR
+ "mal%d: can't find DCR resource!\n", index);
+ err = -ENODEV;
+ goto fail;
+ }
+ mal->dcr_host = dcr_map(ofdev->node, dcr_base, 0x100);
+ if (!DCR_MAP_OK(mal->dcr_host)) {
+ printk(KERN_ERR
+ "mal%d: failed to map DCRs !\n", index);
+ err = -ENODEV;
+ goto fail;
+ }
+
+ mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0);
+ mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1);
+ mal->serr_irq = irq_of_parse_and_map(ofdev->node, 2);
+ mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3);
+ mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4);
+ if (mal->txeob_irq == NO_IRQ || mal->rxeob_irq == NO_IRQ ||
+ mal->serr_irq == NO_IRQ || mal->txde_irq == NO_IRQ ||
+ mal->rxde_irq == NO_IRQ) {
+ printk(KERN_ERR
+ "mal%d: failed to map interrupts !\n", index);
+ err = -ENODEV;
+ goto fail_unmap;
+ }
+
+ INIT_LIST_HEAD(&mal->poll_list);
+ INIT_LIST_HEAD(&mal->list);
+ spin_lock_init(&mal->lock);
+
+ netif_napi_add(NULL, &mal->napi, mal_poll,
+ CONFIG_IBM_NEW_EMAC_POLL_WEIGHT);
+
+ /* Load power-on reset defaults */
+ mal_reset(mal);
+
+ /* Set the MAL configuration register */
+ cfg = (mal->version == 2) ? MAL2_CFG_DEFAULT : MAL1_CFG_DEFAULT;
+ cfg |= MAL_CFG_PLBB | MAL_CFG_OPBBL | MAL_CFG_LEA;
+
+ /* Current Axon is not happy with priority being non-0, it can
+ * deadlock, fix it up here
+ */
+ if (of_device_is_compatible(ofdev->node, "ibm,mcmal-axon"))
+ cfg &= ~(MAL2_CFG_RPP_10 | MAL2_CFG_WPP_10);
+
+ /* Apply configuration */
+ set_mal_dcrn(mal, MAL_CFG, cfg);
+
+ /* Allocate space for BD rings */
+ BUG_ON(mal->num_tx_chans <= 0 || mal->num_tx_chans > 32);
+ BUG_ON(mal->num_rx_chans <= 0 || mal->num_rx_chans > 32);
+
+ bd_size = sizeof(struct mal_descriptor) *
+ (NUM_TX_BUFF * mal->num_tx_chans +
+ NUM_RX_BUFF * mal->num_rx_chans);
+ mal->bd_virt =
+ dma_alloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma,
+ GFP_KERNEL);
+ if (mal->bd_virt == NULL) {
+ printk(KERN_ERR
+ "mal%d: out of memory allocating RX/TX descriptors!\n",
+ index);
+ err = -ENOMEM;
+ goto fail_unmap;
+ }
+ memset(mal->bd_virt, 0, bd_size);
+
+ for (i = 0; i < mal->num_tx_chans; ++i)
+ set_mal_dcrn(mal, MAL_TXCTPR(i), mal->bd_dma +
+ sizeof(struct mal_descriptor) *
+ mal_tx_bd_offset(mal, i));
+
+ for (i = 0; i < mal->num_rx_chans; ++i)
+ set_mal_dcrn(mal, MAL_RXCTPR(i), mal->bd_dma +
+ sizeof(struct mal_descriptor) *
+ mal_rx_bd_offset(mal, i));
+
+ err = request_irq(mal->serr_irq, mal_serr, 0, "MAL SERR", mal);
+ if (err)
+ goto fail2;
+ err = request_irq(mal->txde_irq, mal_txde, 0, "MAL TX DE", mal);
+ if (err)
+ goto fail3;
+ err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal);
+ if (err)
+ goto fail4;
+ err = request_irq(mal->rxde_irq, mal_rxde, 0, "MAL RX DE", mal);
+ if (err)
+ goto fail5;
+ err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal);
+ if (err)
+ goto fail6;
+
+ /* Enable all MAL SERR interrupt sources */
+ if (mal->version == 2)
+ set_mal_dcrn(mal, MAL_IER, MAL2_IER_EVENTS);
+ else
+ set_mal_dcrn(mal, MAL_IER, MAL1_IER_EVENTS);
+
+ /* Enable EOB interrupt */
+ mal_enable_eob_irq(mal);
+
+ printk(KERN_INFO
+ "MAL v%d %s, %d TX channels, %d RX channels\n",
+ mal->version, ofdev->node->full_name,
+ mal->num_tx_chans, mal->num_rx_chans);
+
+ /* Advertise this instance to the rest of the world */
+ wmb();
+ dev_set_drvdata(&ofdev->dev, mal);
+
+ mal_dbg_register(mal);
+
+ return 0;
+
+ fail6:
+ free_irq(mal->rxde_irq, mal);
+ fail5:
+ free_irq(mal->txeob_irq, mal);
+ fail4:
+ free_irq(mal->txde_irq, mal);
+ fail3:
+ free_irq(mal->serr_irq, mal);
+ fail2:
+ dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma);
+ fail_unmap:
+ dcr_unmap(mal->dcr_host, 0x100);
+ fail:
+ kfree(mal);
+
+ return err;
+}
+
+static int __devexit mal_remove(struct of_device *ofdev)
+{
+ struct mal_instance *mal = dev_get_drvdata(&ofdev->dev);
+
+ MAL_DBG(mal, "remove" NL);
+
+ /* Synchronize with scheduled polling */
+ napi_disable(&mal->napi);
+
+ if (!list_empty(&mal->list)) {
+ /* This is *very* bad */
+ printk(KERN_EMERG
+ "mal%d: commac list is not empty on remove!\n",
+ mal->index);
+ WARN_ON(1);
+ }
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+
+ free_irq(mal->serr_irq, mal);
+ free_irq(mal->txde_irq, mal);
+ free_irq(mal->txeob_irq, mal);
+ free_irq(mal->rxde_irq, mal);
+ free_irq(mal->rxeob_irq, mal);
+
+ mal_reset(mal);
+
+ mal_dbg_unregister(mal);
+
+ dma_free_coherent(&ofdev->dev,
+ sizeof(struct mal_descriptor) *
+ (NUM_TX_BUFF * mal->num_tx_chans +
+ NUM_RX_BUFF * mal->num_rx_chans), mal->bd_virt,
+ mal->bd_dma);
+ kfree(mal);
+
+ return 0;
+}
+
+static struct of_device_id mal_platform_match[] =
+{
+ {
+ .compatible = "ibm,mcmal",
+ },
+ {
+ .compatible = "ibm,mcmal2",
+ },
+ /* Backward compat */
+ {
+ .type = "mcmal-dma",
+ .compatible = "ibm,mcmal",
+ },
+ {
+ .type = "mcmal-dma",
+ .compatible = "ibm,mcmal2",
+ },
+ {},
+};
+
+static struct of_platform_driver mal_of_driver = {
+ .name = "mcmal",
+ .match_table = mal_platform_match,
+
+ .probe = mal_probe,
+ .remove = mal_remove,
+};
+
+int __init mal_init(void)
+{
+ return of_register_platform_driver(&mal_of_driver);
+}
+
+void mal_exit(void)
+{
+ of_unregister_platform_driver(&mal_of_driver);
+}
diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h
new file mode 100644
index 00000000000..784edb8ea82
--- /dev/null
+++ b/drivers/net/ibm_newemac/mal.h
@@ -0,0 +1,275 @@
+/*
+ * drivers/net/ibm_newemac/mal.h
+ *
+ * Memory Access Layer (MAL) support
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Armin Kuster <akuster@mvista.com>
+ * Copyright 2002 MontaVista Softare Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __IBM_NEWEMAC_MAL_H
+#define __IBM_NEWEMAC_MAL_H
+
+/*
+ * There are some variations on the MAL, we express them in this driver as
+ * MAL Version 1 and 2 though that doesn't match any IBM terminology.
+ *
+ * We call MAL 1 the version in 405GP, 405GPR, 405EP, 440EP, 440GR and
+ * NP405H.
+ *
+ * We call MAL 2 the version in 440GP, 440GX, 440SP, 440SPE and Axon
+ *
+ * The driver expects a "version" property in the emac node containing
+ * a number 1 or 2. New device-trees for EMAC capable platforms are thus
+ * required to include that when porting to arch/powerpc.
+ */
+
+/* MALx DCR registers */
+#define MAL_CFG 0x00
+#define MAL_CFG_SR 0x80000000
+#define MAL_CFG_PLBB 0x00004000
+#define MAL_CFG_OPBBL 0x00000080
+#define MAL_CFG_EOPIE 0x00000004
+#define MAL_CFG_LEA 0x00000002
+#define MAL_CFG_SD 0x00000001
+
+/* MAL V1 CFG bits */
+#define MAL1_CFG_PLBP_MASK 0x00c00000
+#define MAL1_CFG_PLBP_10 0x00800000
+#define MAL1_CFG_GA 0x00200000
+#define MAL1_CFG_OA 0x00100000
+#define MAL1_CFG_PLBLE 0x00080000
+#define MAL1_CFG_PLBT_MASK 0x00078000
+#define MAL1_CFG_DEFAULT (MAL1_CFG_PLBP_10 | MAL1_CFG_PLBT_MASK)
+
+/* MAL V2 CFG bits */
+#define MAL2_CFG_RPP_MASK 0x00c00000
+#define MAL2_CFG_RPP_10 0x00800000
+#define MAL2_CFG_RMBS_MASK 0x00300000
+#define MAL2_CFG_WPP_MASK 0x000c0000
+#define MAL2_CFG_WPP_10 0x00080000
+#define MAL2_CFG_WMBS_MASK 0x00030000
+#define MAL2_CFG_PLBLE 0x00008000
+#define MAL2_CFG_DEFAULT (MAL2_CFG_RMBS_MASK | MAL2_CFG_WMBS_MASK | \
+ MAL2_CFG_RPP_10 | MAL2_CFG_WPP_10)
+
+#define MAL_ESR 0x01
+#define MAL_ESR_EVB 0x80000000
+#define MAL_ESR_CIDT 0x40000000
+#define MAL_ESR_CID_MASK 0x3e000000
+#define MAL_ESR_CID_SHIFT 25
+#define MAL_ESR_DE 0x00100000
+#define MAL_ESR_OTE 0x00040000
+#define MAL_ESR_OSE 0x00020000
+#define MAL_ESR_PEIN 0x00010000
+#define MAL_ESR_DEI 0x00000010
+#define MAL_ESR_OTEI 0x00000004
+#define MAL_ESR_OSEI 0x00000002
+#define MAL_ESR_PBEI 0x00000001
+
+/* MAL V1 ESR bits */
+#define MAL1_ESR_ONE 0x00080000
+#define MAL1_ESR_ONEI 0x00000008
+
+/* MAL V2 ESR bits */
+#define MAL2_ESR_PTE 0x00800000
+#define MAL2_ESR_PRE 0x00400000
+#define MAL2_ESR_PWE 0x00200000
+#define MAL2_ESR_PTEI 0x00000080
+#define MAL2_ESR_PREI 0x00000040
+#define MAL2_ESR_PWEI 0x00000020
+
+
+#define MAL_IER 0x02
+#define MAL_IER_DE 0x00000010
+#define MAL_IER_OTE 0x00000004
+#define MAL_IER_OE 0x00000002
+#define MAL_IER_PE 0x00000001
+/* MAL V1 IER bits */
+#define MAL1_IER_NWE 0x00000008
+#define MAL1_IER_SOC_EVENTS MAL1_IER_NWE
+#define MAL1_IER_EVENTS (MAL1_IER_SOC_EVENTS | MAL_IER_OTE | \
+ MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE)
+
+/* MAL V2 IER bits */
+#define MAL2_IER_PT 0x00000080
+#define MAL2_IER_PRE 0x00000040
+#define MAL2_IER_PWE 0x00000020
+#define MAL2_IER_SOC_EVENTS (MAL2_IER_PT | MAL2_IER_PRE | MAL2_IER_PWE)
+#define MAL2_IER_EVENTS (MAL2_IER_SOC_EVENTS | MAL_IER_OTE | \
+ MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE)
+
+
+#define MAL_TXCASR 0x04
+#define MAL_TXCARR 0x05
+#define MAL_TXEOBISR 0x06
+#define MAL_TXDEIR 0x07
+#define MAL_RXCASR 0x10
+#define MAL_RXCARR 0x11
+#define MAL_RXEOBISR 0x12
+#define MAL_RXDEIR 0x13
+#define MAL_TXCTPR(n) ((n) + 0x20)
+#define MAL_RXCTPR(n) ((n) + 0x40)
+#define MAL_RCBS(n) ((n) + 0x60)
+
+/* In reality MAL can handle TX buffers up to 4095 bytes long,
+ * but this isn't a good round number :) --ebs
+ */
+#define MAL_MAX_TX_SIZE 4080
+#define MAL_MAX_RX_SIZE 4080
+
+static inline int mal_rx_size(int len)
+{
+ len = (len + 0xf) & ~0xf;
+ return len > MAL_MAX_RX_SIZE ? MAL_MAX_RX_SIZE : len;
+}
+
+static inline int mal_tx_chunks(int len)
+{
+ return (len + MAL_MAX_TX_SIZE - 1) / MAL_MAX_TX_SIZE;
+}
+
+#define MAL_CHAN_MASK(n) (0x80000000 >> (n))
+
+/* MAL Buffer Descriptor structure */
+struct mal_descriptor {
+ u16 ctrl; /* MAL / Commac status control bits */
+ u16 data_len; /* Max length is 4K-1 (12 bits) */
+ u32 data_ptr; /* pointer to actual data buffer */
+};
+
+/* the following defines are for the MadMAL status and control registers. */
+/* MADMAL transmit and receive status/control bits */
+#define MAL_RX_CTRL_EMPTY 0x8000
+#define MAL_RX_CTRL_WRAP 0x4000
+#define MAL_RX_CTRL_CM 0x2000
+#define MAL_RX_CTRL_LAST 0x1000
+#define MAL_RX_CTRL_FIRST 0x0800
+#define MAL_RX_CTRL_INTR 0x0400
+#define MAL_RX_CTRL_SINGLE (MAL_RX_CTRL_LAST | MAL_RX_CTRL_FIRST)
+#define MAL_IS_SINGLE_RX(ctrl) (((ctrl) & MAL_RX_CTRL_SINGLE) == MAL_RX_CTRL_SINGLE)
+
+#define MAL_TX_CTRL_READY 0x8000
+#define MAL_TX_CTRL_WRAP 0x4000
+#define MAL_TX_CTRL_CM 0x2000
+#define MAL_TX_CTRL_LAST 0x1000
+#define MAL_TX_CTRL_INTR 0x0400
+
+struct mal_commac_ops {
+ void (*poll_tx) (void *dev);
+ int (*poll_rx) (void *dev, int budget);
+ int (*peek_rx) (void *dev);
+ void (*rxde) (void *dev);
+};
+
+struct mal_commac {
+ struct mal_commac_ops *ops;
+ void *dev;
+ struct list_head poll_list;
+ long flags;
+#define MAL_COMMAC_RX_STOPPED 0
+#define MAL_COMMAC_POLL_DISABLED 1
+ u32 tx_chan_mask;
+ u32 rx_chan_mask;
+ struct list_head list;
+};
+
+struct mal_instance {
+ int version;
+ dcr_host_t dcr_host;
+
+ int num_tx_chans; /* Number of TX channels */
+ int num_rx_chans; /* Number of RX channels */
+ int txeob_irq; /* TX End Of Buffer IRQ */
+ int rxeob_irq; /* RX End Of Buffer IRQ */
+ int txde_irq; /* TX Descriptor Error IRQ */
+ int rxde_irq; /* RX Descriptor Error IRQ */
+ int serr_irq; /* MAL System Error IRQ */
+
+ struct list_head poll_list;
+ struct napi_struct napi;
+
+ struct list_head list;
+ u32 tx_chan_mask;
+ u32 rx_chan_mask;
+
+ dma_addr_t bd_dma;
+ struct mal_descriptor *bd_virt;
+
+ struct of_device *ofdev;
+ int index;
+ spinlock_t lock;
+};
+
+static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg)
+{
+ return dcr_read(mal->dcr_host, reg);
+}
+
+static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val)
+{
+ dcr_write(mal->dcr_host, reg, val);
+}
+
+/* Register MAL devices */
+int mal_init(void);
+void mal_exit(void);
+
+int mal_register_commac(struct mal_instance *mal,
+ struct mal_commac *commac);
+void mal_unregister_commac(struct mal_instance *mal,
+ struct mal_commac *commac);
+int mal_set_rcbs(struct mal_instance *mal, int channel, unsigned long size);
+
+/* Returns BD ring offset for a particular channel
+ (in 'struct mal_descriptor' elements)
+*/
+int mal_tx_bd_offset(struct mal_instance *mal, int channel);
+int mal_rx_bd_offset(struct mal_instance *mal, int channel);
+
+void mal_enable_tx_channel(struct mal_instance *mal, int channel);
+void mal_disable_tx_channel(struct mal_instance *mal, int channel);
+void mal_enable_rx_channel(struct mal_instance *mal, int channel);
+void mal_disable_rx_channel(struct mal_instance *mal, int channel);
+
+void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac);
+void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac);
+
+/* Add/remove EMAC to/from MAL polling list */
+void mal_poll_add(struct mal_instance *mal, struct mal_commac *commac);
+void mal_poll_del(struct mal_instance *mal, struct mal_commac *commac);
+
+/* Ethtool MAL registers */
+struct mal_regs {
+ u32 tx_count;
+ u32 rx_count;
+
+ u32 cfg;
+ u32 esr;
+ u32 ier;
+ u32 tx_casr;
+ u32 tx_carr;
+ u32 tx_eobisr;
+ u32 tx_deir;
+ u32 rx_casr;
+ u32 rx_carr;
+ u32 rx_eobisr;
+ u32 rx_deir;
+ u32 tx_ctpr[32];
+ u32 rx_ctpr[32];
+ u32 rcbs[32];
+};
+
+int mal_get_regs_len(struct mal_instance *mal);
+void *mal_dump_regs(struct mal_instance *mal, void *buf);
+
+#endif /* __IBM_NEWEMAC_MAL_H */
diff --git a/drivers/net/ibm_newemac/phy.c b/drivers/net/ibm_newemac/phy.c
new file mode 100644
index 00000000000..aa1f0ddf1e3
--- /dev/null
+++ b/drivers/net/ibm_newemac/phy.c
@@ -0,0 +1,373 @@
+/*
+ * drivers/net/ibm_newemac/phy.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, PHY support.
+ * Borrowed from sungem_phy.c, though I only kept the generic MII
+ * driver for now.
+ *
+ * This file should be shared with other drivers or eventually
+ * merged as the "low level" part of miilib
+ *
+ * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org)
+ * (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net>
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+
+#include "emac.h"
+#include "phy.h"
+
+static inline int phy_read(struct mii_phy *phy, int reg)
+{
+ return phy->mdio_read(phy->dev, phy->address, reg);
+}
+
+static inline void phy_write(struct mii_phy *phy, int reg, int val)
+{
+ phy->mdio_write(phy->dev, phy->address, reg, val);
+}
+
+int emac_mii_reset_phy(struct mii_phy *phy)
+{
+ int val;
+ int limit = 10000;
+
+ val = phy_read(phy, MII_BMCR);
+ val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);
+ val |= BMCR_RESET;
+ phy_write(phy, MII_BMCR, val);
+
+ udelay(300);
+
+ while (limit--) {
+ val = phy_read(phy, MII_BMCR);
+ if (val >= 0 && (val & BMCR_RESET) == 0)
+ break;
+ udelay(10);
+ }
+ if ((val & BMCR_ISOLATE) && limit > 0)
+ phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
+
+ return limit <= 0;
+}
+
+static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
+{
+ int ctl, adv;
+
+ phy->autoneg = AUTONEG_ENABLE;
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+ phy->pause = phy->asym_pause = 0;
+ phy->advertising = advertise;
+
+ ctl = phy_read(phy, MII_BMCR);
+ if (ctl < 0)
+ return ctl;
+ ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
+
+ /* First clear the PHY */
+ phy_write(phy, MII_BMCR, ctl);
+
+ /* Setup standard advertise */
+ adv = phy_read(phy, MII_ADVERTISE);
+ if (adv < 0)
+ return adv;
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
+ ADVERTISE_PAUSE_ASYM);
+ if (advertise & ADVERTISED_10baseT_Half)
+ adv |= ADVERTISE_10HALF;
+ if (advertise & ADVERTISED_10baseT_Full)
+ adv |= ADVERTISE_10FULL;
+ if (advertise & ADVERTISED_100baseT_Half)
+ adv |= ADVERTISE_100HALF;
+ if (advertise & ADVERTISED_100baseT_Full)
+ adv |= ADVERTISE_100FULL;
+ if (advertise & ADVERTISED_Pause)
+ adv |= ADVERTISE_PAUSE_CAP;
+ if (advertise & ADVERTISED_Asym_Pause)
+ adv |= ADVERTISE_PAUSE_ASYM;
+ phy_write(phy, MII_ADVERTISE, adv);
+
+ if (phy->features &
+ (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
+ adv = phy_read(phy, MII_CTRL1000);
+ if (adv < 0)
+ return adv;
+ adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+ if (advertise & ADVERTISED_1000baseT_Full)
+ adv |= ADVERTISE_1000FULL;
+ if (advertise & ADVERTISED_1000baseT_Half)
+ adv |= ADVERTISE_1000HALF;
+ phy_write(phy, MII_CTRL1000, adv);
+ }
+
+ /* Start/Restart aneg */
+ ctl = phy_read(phy, MII_BMCR);
+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
+{
+ int ctl;
+
+ phy->autoneg = AUTONEG_DISABLE;
+ phy->speed = speed;
+ phy->duplex = fd;
+ phy->pause = phy->asym_pause = 0;
+
+ ctl = phy_read(phy, MII_BMCR);
+ if (ctl < 0)
+ return ctl;
+ ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
+
+ /* First clear the PHY */
+ phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
+
+ /* Select speed & duplex */
+ switch (speed) {
+ case SPEED_10:
+ break;
+ case SPEED_100:
+ ctl |= BMCR_SPEED100;
+ break;
+ case SPEED_1000:
+ ctl |= BMCR_SPEED1000;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (fd == DUPLEX_FULL)
+ ctl |= BMCR_FULLDPLX;
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int genmii_poll_link(struct mii_phy *phy)
+{
+ int status;
+
+ /* Clear latched value with dummy read */
+ phy_read(phy, MII_BMSR);
+ status = phy_read(phy, MII_BMSR);
+ if (status < 0 || (status & BMSR_LSTATUS) == 0)
+ return 0;
+ if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE))
+ return 0;
+ return 1;
+}
+
+static int genmii_read_link(struct mii_phy *phy)
+{
+ if (phy->autoneg == AUTONEG_ENABLE) {
+ int glpa = 0;
+ int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE);
+ if (lpa < 0)
+ return lpa;
+
+ if (phy->features &
+ (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
+ int adv = phy_read(phy, MII_CTRL1000);
+ glpa = phy_read(phy, MII_STAT1000);
+
+ if (glpa < 0 || adv < 0)
+ return adv;
+
+ glpa &= adv << 2;
+ }
+
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+ phy->pause = phy->asym_pause = 0;
+
+ if (glpa & (LPA_1000FULL | LPA_1000HALF)) {
+ phy->speed = SPEED_1000;
+ if (glpa & LPA_1000FULL)
+ phy->duplex = DUPLEX_FULL;
+ } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
+ phy->speed = SPEED_100;
+ if (lpa & LPA_100FULL)
+ phy->duplex = DUPLEX_FULL;
+ } else if (lpa & LPA_10FULL)
+ phy->duplex = DUPLEX_FULL;
+
+ if (phy->duplex == DUPLEX_FULL) {
+ phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
+ phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
+ }
+ } else {
+ int bmcr = phy_read(phy, MII_BMCR);
+ if (bmcr < 0)
+ return bmcr;
+
+ if (bmcr & BMCR_FULLDPLX)
+ phy->duplex = DUPLEX_FULL;
+ else
+ phy->duplex = DUPLEX_HALF;
+ if (bmcr & BMCR_SPEED1000)
+ phy->speed = SPEED_1000;
+ else if (bmcr & BMCR_SPEED100)
+ phy->speed = SPEED_100;
+ else
+ phy->speed = SPEED_10;
+
+ phy->pause = phy->asym_pause = 0;
+ }
+ return 0;
+}
+
+/* Generic implementation for most 10/100/1000 PHYs */
+static struct mii_phy_ops generic_phy_ops = {
+ .setup_aneg = genmii_setup_aneg,
+ .setup_forced = genmii_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = genmii_read_link
+};
+
+static struct mii_phy_def genmii_phy_def = {
+ .phy_id = 0x00000000,
+ .phy_id_mask = 0x00000000,
+ .name = "Generic MII",
+ .ops = &generic_phy_ops
+};
+
+/* CIS8201 */
+#define MII_CIS8201_10BTCSR 0x16
+#define TENBTCSR_ECHO_DISABLE 0x2000
+#define MII_CIS8201_EPCR 0x17
+#define EPCR_MODE_MASK 0x3000
+#define EPCR_GMII_MODE 0x0000
+#define EPCR_RGMII_MODE 0x1000
+#define EPCR_TBI_MODE 0x2000
+#define EPCR_RTBI_MODE 0x3000
+#define MII_CIS8201_ACSR 0x1c
+#define ACSR_PIN_PRIO_SELECT 0x0004
+
+static int cis8201_init(struct mii_phy *phy)
+{
+ int epcr;
+
+ epcr = phy_read(phy, MII_CIS8201_EPCR);
+ if (epcr < 0)
+ return epcr;
+
+ epcr &= ~EPCR_MODE_MASK;
+
+ switch (phy->mode) {
+ case PHY_MODE_TBI:
+ epcr |= EPCR_TBI_MODE;
+ break;
+ case PHY_MODE_RTBI:
+ epcr |= EPCR_RTBI_MODE;
+ break;
+ case PHY_MODE_GMII:
+ epcr |= EPCR_GMII_MODE;
+ break;
+ case PHY_MODE_RGMII:
+ default:
+ epcr |= EPCR_RGMII_MODE;
+ }
+
+ phy_write(phy, MII_CIS8201_EPCR, epcr);
+
+ /* MII regs override strap pins */
+ phy_write(phy, MII_CIS8201_ACSR,
+ phy_read(phy, MII_CIS8201_ACSR) | ACSR_PIN_PRIO_SELECT);
+
+ /* Disable TX_EN -> CRS echo mode, otherwise 10/HDX doesn't work */
+ phy_write(phy, MII_CIS8201_10BTCSR,
+ phy_read(phy, MII_CIS8201_10BTCSR) | TENBTCSR_ECHO_DISABLE);
+
+ return 0;
+}
+
+static struct mii_phy_ops cis8201_phy_ops = {
+ .init = cis8201_init,
+ .setup_aneg = genmii_setup_aneg,
+ .setup_forced = genmii_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = genmii_read_link
+};
+
+static struct mii_phy_def cis8201_phy_def = {
+ .phy_id = 0x000fc410,
+ .phy_id_mask = 0x000ffff0,
+ .name = "CIS8201 Gigabit Ethernet",
+ .ops = &cis8201_phy_ops
+};
+
+static struct mii_phy_def *mii_phy_table[] = {
+ &cis8201_phy_def,
+ &genmii_phy_def,
+ NULL
+};
+
+int emac_mii_phy_probe(struct mii_phy *phy, int address)
+{
+ struct mii_phy_def *def;
+ int i;
+ u32 id;
+
+ phy->autoneg = AUTONEG_DISABLE;
+ phy->advertising = 0;
+ phy->address = address;
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+ phy->pause = phy->asym_pause = 0;
+
+ /* Take PHY out of isolate mode and reset it. */
+ if (emac_mii_reset_phy(phy))
+ return -ENODEV;
+
+ /* Read ID and find matching entry */
+ id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2);
+ for (i = 0; (def = mii_phy_table[i]) != NULL; i++)
+ if ((id & def->phy_id_mask) == def->phy_id)
+ break;
+ /* Should never be NULL (we have a generic entry), but... */
+ if (!def)
+ return -ENODEV;
+
+ phy->def = def;
+
+ /* Determine PHY features if needed */
+ phy->features = def->features;
+ if (!phy->features) {
+ u16 bmsr = phy_read(phy, MII_BMSR);
+ if (bmsr & BMSR_ANEGCAPABLE)
+ phy->features |= SUPPORTED_Autoneg;
+ if (bmsr & BMSR_10HALF)
+ phy->features |= SUPPORTED_10baseT_Half;
+ if (bmsr & BMSR_10FULL)
+ phy->features |= SUPPORTED_10baseT_Full;
+ if (bmsr & BMSR_100HALF)
+ phy->features |= SUPPORTED_100baseT_Half;
+ if (bmsr & BMSR_100FULL)
+ phy->features |= SUPPORTED_100baseT_Full;
+ if (bmsr & BMSR_ESTATEN) {
+ u16 esr = phy_read(phy, MII_ESTATUS);
+ if (esr & ESTATUS_1000_TFULL)
+ phy->features |= SUPPORTED_1000baseT_Full;
+ if (esr & ESTATUS_1000_THALF)
+ phy->features |= SUPPORTED_1000baseT_Half;
+ }
+ phy->features |= SUPPORTED_MII;
+ }
+
+ /* Setup default advertising */
+ phy->advertising = phy->features;
+
+ return 0;
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ibm_newemac/phy.h b/drivers/net/ibm_newemac/phy.h
new file mode 100644
index 00000000000..6feca26afed
--- /dev/null
+++ b/drivers/net/ibm_newemac/phy.h
@@ -0,0 +1,80 @@
+/*
+ * drivers/net/ibm_newemac/phy.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, PHY support
+ *
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * February 2003
+ *
+ * Minor additions by Eugene Surovegin <ebs@ebshome.net>, 2004
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This file basically duplicates sungem_phy.{c,h} with different PHYs
+ * supported. I'm looking into merging that in a single mii layer more
+ * flexible than mii.c
+ */
+
+#ifndef __IBM_NEWEMAC_PHY_H
+#define __IBM_NEWEMAC_PHY_H
+
+struct mii_phy;
+
+/* Operations supported by any kind of PHY */
+struct mii_phy_ops {
+ int (*init) (struct mii_phy * phy);
+ int (*suspend) (struct mii_phy * phy, int wol_options);
+ int (*setup_aneg) (struct mii_phy * phy, u32 advertise);
+ int (*setup_forced) (struct mii_phy * phy, int speed, int fd);
+ int (*poll_link) (struct mii_phy * phy);
+ int (*read_link) (struct mii_phy * phy);
+};
+
+/* Structure used to statically define an mii/gii based PHY */
+struct mii_phy_def {
+ u32 phy_id; /* Concatenated ID1 << 16 | ID2 */
+ u32 phy_id_mask; /* Significant bits */
+ u32 features; /* Ethtool SUPPORTED_* defines or
+ 0 for autodetect */
+ int magic_aneg; /* Autoneg does all speed test for us */
+ const char *name;
+ const struct mii_phy_ops *ops;
+};
+
+/* An instance of a PHY, partially borrowed from mii_if_info */
+struct mii_phy {
+ struct mii_phy_def *def;
+ u32 advertising; /* Ethtool ADVERTISED_* defines */
+ u32 features; /* Copied from mii_phy_def.features
+ or determined automaticaly */
+ int address; /* PHY address */
+ int mode; /* PHY mode */
+
+ /* 1: autoneg enabled, 0: disabled */
+ int autoneg;
+
+ /* forced speed & duplex (no autoneg)
+ * partner speed & duplex & pause (autoneg)
+ */
+ int speed;
+ int duplex;
+ int pause;
+ int asym_pause;
+
+ /* Provided by host chip */
+ struct net_device *dev;
+ int (*mdio_read) (struct net_device * dev, int addr, int reg);
+ void (*mdio_write) (struct net_device * dev, int addr, int reg,
+ int val);
+};
+
+/* Pass in a struct mii_phy with dev, mdio_read and mdio_write
+ * filled, the remaining fields will be filled on return
+ */
+int emac_mii_phy_probe(struct mii_phy *phy, int address);
+int emac_mii_reset_phy(struct mii_phy *phy);
+
+#endif /* __IBM_NEWEMAC_PHY_H */
diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ibm_newemac/rgmii.c
new file mode 100644
index 00000000000..de416951a43
--- /dev/null
+++ b/drivers/net/ibm_newemac/rgmii.c
@@ -0,0 +1,323 @@
+/*
+ * drivers/net/ibm_newemac/rgmii.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/ethtool.h>
+#include <asm/io.h>
+
+#include "emac.h"
+#include "debug.h"
+
+// XXX FIXME: Axon seems to support a subset of the RGMII, we
+// thus need to take that into account and possibly change some
+// of the bit settings below that don't seem to quite match the
+// AXON spec
+
+/* RGMIIx_FER */
+#define RGMII_FER_MASK(idx) (0x7 << ((idx) * 4))
+#define RGMII_FER_RTBI(idx) (0x4 << ((idx) * 4))
+#define RGMII_FER_RGMII(idx) (0x5 << ((idx) * 4))
+#define RGMII_FER_TBI(idx) (0x6 << ((idx) * 4))
+#define RGMII_FER_GMII(idx) (0x7 << ((idx) * 4))
+
+/* RGMIIx_SSR */
+#define RGMII_SSR_MASK(idx) (0x7 << ((idx) * 8))
+#define RGMII_SSR_100(idx) (0x2 << ((idx) * 8))
+#define RGMII_SSR_1000(idx) (0x4 << ((idx) * 8))
+
+/* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */
+static inline int rgmii_valid_mode(int phy_mode)
+{
+ return phy_mode == PHY_MODE_GMII ||
+ phy_mode == PHY_MODE_RGMII ||
+ phy_mode == PHY_MODE_TBI ||
+ phy_mode == PHY_MODE_RTBI;
+}
+
+static inline const char *rgmii_mode_name(int mode)
+{
+ switch (mode) {
+ case PHY_MODE_RGMII:
+ return "RGMII";
+ case PHY_MODE_TBI:
+ return "TBI";
+ case PHY_MODE_GMII:
+ return "GMII";
+ case PHY_MODE_RTBI:
+ return "RTBI";
+ default:
+ BUG();
+ }
+}
+
+static inline u32 rgmii_mode_mask(int mode, int input)
+{
+ switch (mode) {
+ case PHY_MODE_RGMII:
+ return RGMII_FER_RGMII(input);
+ case PHY_MODE_TBI:
+ return RGMII_FER_TBI(input);
+ case PHY_MODE_GMII:
+ return RGMII_FER_GMII(input);
+ case PHY_MODE_RTBI:
+ return RGMII_FER_RTBI(input);
+ default:
+ BUG();
+ }
+}
+
+int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_regs __iomem *p = dev->base;
+
+ RGMII_DBG(dev, "attach(%d)" NL, input);
+
+ /* Check if we need to attach to a RGMII */
+ if (input < 0 || !rgmii_valid_mode(mode)) {
+ printk(KERN_ERR "%s: unsupported settings !\n",
+ ofdev->node->full_name);
+ return -ENODEV;
+ }
+
+ mutex_lock(&dev->lock);
+
+ /* Enable this input */
+ out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input));
+
+ printk(KERN_NOTICE "%s: input %d in %s mode\n",
+ ofdev->node->full_name, input, rgmii_mode_name(mode));
+
+ ++dev->users;
+
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+void rgmii_set_speed(struct of_device *ofdev, int input, int speed)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_regs __iomem *p = dev->base;
+ u32 ssr;
+
+ mutex_lock(&dev->lock);
+
+ ssr = in_be32(&p->ssr) & ~RGMII_SSR_MASK(input);
+
+ RGMII_DBG(dev, "speed(%d, %d)" NL, input, speed);
+
+ if (speed == SPEED_1000)
+ ssr |= RGMII_SSR_1000(input);
+ else if (speed == SPEED_100)
+ ssr |= RGMII_SSR_100(input);
+
+ out_be32(&p->ssr, ssr);
+
+ mutex_unlock(&dev->lock);
+}
+
+void rgmii_get_mdio(struct of_device *ofdev, int input)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_regs __iomem *p = dev->base;
+ u32 fer;
+
+ RGMII_DBG2(dev, "get_mdio(%d)" NL, input);
+
+ if (dev->type != RGMII_AXON)
+ return;
+
+ mutex_lock(&dev->lock);
+
+ fer = in_be32(&p->fer);
+ fer |= 0x00080000u >> input;
+ out_be32(&p->fer, fer);
+ (void)in_be32(&p->fer);
+
+ DBG2(dev, " fer = 0x%08x\n", fer);
+}
+
+void rgmii_put_mdio(struct of_device *ofdev, int input)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_regs __iomem *p = dev->base;
+ u32 fer;
+
+ RGMII_DBG2(dev, "put_mdio(%d)" NL, input);
+
+ if (dev->type != RGMII_AXON)
+ return;
+
+ fer = in_be32(&p->fer);
+ fer &= ~(0x00080000u >> input);
+ out_be32(&p->fer, fer);
+ (void)in_be32(&p->fer);
+
+ DBG2(dev, " fer = 0x%08x\n", fer);
+
+ mutex_unlock(&dev->lock);
+}
+
+void __devexit rgmii_detach(struct of_device *ofdev, int input)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_regs __iomem *p = dev->base;
+
+ mutex_lock(&dev->lock);
+
+ BUG_ON(!dev || dev->users == 0);
+
+ RGMII_DBG(dev, "detach(%d)" NL, input);
+
+ /* Disable this input */
+ out_be32(&p->fer, in_be32(&p->fer) & ~RGMII_FER_MASK(input));
+
+ --dev->users;
+
+ mutex_unlock(&dev->lock);
+}
+
+int rgmii_get_regs_len(struct of_device *ofdev)
+{
+ return sizeof(struct emac_ethtool_regs_subhdr) +
+ sizeof(struct rgmii_regs);
+}
+
+void *rgmii_dump_regs(struct of_device *ofdev, void *buf)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct emac_ethtool_regs_subhdr *hdr = buf;
+ struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1);
+
+ hdr->version = 0;
+ hdr->index = 0; /* for now, are there chips with more than one
+ * rgmii ? if yes, then we'll add a cell_index
+ * like we do for emac
+ */
+ memcpy_fromio(regs, dev->base, sizeof(struct rgmii_regs));
+ return regs + 1;
+}
+
+
+static int __devinit rgmii_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = ofdev->node;
+ struct rgmii_instance *dev;
+ struct resource regs;
+ int rc;
+
+ rc = -ENOMEM;
+ dev = kzalloc(sizeof(struct rgmii_instance), GFP_KERNEL);
+ if (dev == NULL) {
+ printk(KERN_ERR "%s: could not allocate RGMII device!\n",
+ np->full_name);
+ goto err_gone;
+ }
+
+ mutex_init(&dev->lock);
+ dev->ofdev = ofdev;
+
+ rc = -ENXIO;
+ if (of_address_to_resource(np, 0, &regs)) {
+ printk(KERN_ERR "%s: Can't get registers address\n",
+ np->full_name);
+ goto err_free;
+ }
+
+ rc = -ENOMEM;
+ dev->base = (struct rgmii_regs __iomem *)ioremap(regs.start,
+ sizeof(struct rgmii_regs));
+ if (dev->base == NULL) {
+ printk(KERN_ERR "%s: Can't map device registers!\n",
+ np->full_name);
+ goto err_free;
+ }
+
+ /* Check for RGMII type */
+ if (of_device_is_compatible(ofdev->node, "ibm,rgmii-axon"))
+ dev->type = RGMII_AXON;
+ else
+ dev->type = RGMII_STANDARD;
+
+ DBG2(dev, " Boot FER = 0x%08x, SSR = 0x%08x\n",
+ in_be32(&dev->base->fer), in_be32(&dev->base->ssr));
+
+ /* Disable all inputs by default */
+ out_be32(&dev->base->fer, 0);
+
+ printk(KERN_INFO
+ "RGMII %s %s initialized\n",
+ dev->type == RGMII_STANDARD ? "standard" : "axon",
+ ofdev->node->full_name);
+
+ wmb();
+ dev_set_drvdata(&ofdev->dev, dev);
+
+ return 0;
+
+ err_free:
+ kfree(dev);
+ err_gone:
+ return rc;
+}
+
+static int __devexit rgmii_remove(struct of_device *ofdev)
+{
+ struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+
+ WARN_ON(dev->users != 0);
+
+ iounmap(dev->base);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct of_device_id rgmii_match[] =
+{
+ {
+ .type = "rgmii-interface",
+ .compatible = "ibm,rgmii",
+ },
+ {
+ .type = "emac-rgmii",
+ },
+ {},
+};
+
+static struct of_platform_driver rgmii_driver = {
+ .name = "emac-rgmii",
+ .match_table = rgmii_match,
+
+ .probe = rgmii_probe,
+ .remove = rgmii_remove,
+};
+
+int __init rgmii_init(void)
+{
+ return of_register_platform_driver(&rgmii_driver);
+}
+
+void rgmii_exit(void)
+{
+ of_unregister_platform_driver(&rgmii_driver);
+}
diff --git a/drivers/net/ibm_newemac/rgmii.h b/drivers/net/ibm_newemac/rgmii.h
new file mode 100644
index 00000000000..57806833121
--- /dev/null
+++ b/drivers/net/ibm_newemac/rgmii.h
@@ -0,0 +1,76 @@
+/*
+ * drivers/net/ibm_newemac/rgmii.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
+ *
+ * Based on ocp_zmii.h/ibm_emac_zmii.h
+ * Armin Kuster akuster@mvista.com
+ *
+ * Copyright 2004 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __IBM_NEWEMAC_RGMII_H
+#define __IBM_NEWEMAC_RGMII_H
+
+/* RGMII bridge type */
+#define RGMII_STANDARD 0
+#define RGMII_AXON 1
+
+/* RGMII bridge */
+struct rgmii_regs {
+ u32 fer; /* Function enable register */
+ u32 ssr; /* Speed select register */
+};
+
+/* RGMII device */
+struct rgmii_instance {
+ struct rgmii_regs __iomem *base;
+
+ /* Type of RGMII bridge */
+ int type;
+
+ /* Only one EMAC whacks us at a time */
+ struct mutex lock;
+
+ /* number of EMACs using this RGMII bridge */
+ int users;
+
+ /* OF device instance */
+ struct of_device *ofdev;
+};
+
+#ifdef CONFIG_IBM_NEW_EMAC_RGMII
+
+extern int rgmii_init(void);
+extern void rgmii_exit(void);
+extern int rgmii_attach(struct of_device *ofdev, int input, int mode);
+extern void rgmii_detach(struct of_device *ofdev, int input);
+extern void rgmii_get_mdio(struct of_device *ofdev, int input);
+extern void rgmii_put_mdio(struct of_device *ofdev, int input);
+extern void rgmii_set_speed(struct of_device *ofdev, int input, int speed);
+extern int rgmii_get_regs_len(struct of_device *ofdev);
+extern void *rgmii_dump_regs(struct of_device *ofdev, void *buf);
+
+#else
+
+# define rgmii_init() 0
+# define rgmii_exit() do { } while(0)
+# define rgmii_attach(x,y,z) (-ENXIO)
+# define rgmii_detach(x,y) do { } while(0)
+# define rgmii_get_mdio(o,i) do { } while (0)
+# define rgmii_put_mdio(o,i) do { } while (0)
+# define rgmii_set_speed(x,y,z) do { } while(0)
+# define rgmii_get_regs_len(x) 0
+# define rgmii_dump_regs(x,buf) (buf)
+#endif /* !CONFIG_IBM_NEW_EMAC_RGMII */
+
+#endif /* __IBM_NEWEMAC_RGMII_H */
diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ibm_newemac/tah.c
new file mode 100644
index 00000000000..f161fb100e8
--- /dev/null
+++ b/drivers/net/ibm_newemac/tah.c
@@ -0,0 +1,173 @@
+/*
+ * drivers/net/ibm_newemac/tah.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
+ *
+ * Copyright 2004 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <asm/io.h>
+
+#include "emac.h"
+#include "core.h"
+
+int __devinit tah_attach(struct of_device *ofdev, int channel)
+{
+ struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ mutex_lock(&dev->lock);
+ /* Reset has been done at probe() time... nothing else to do for now */
+ ++dev->users;
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+void __devexit tah_detach(struct of_device *ofdev, int channel)
+{
+ struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ mutex_lock(&dev->lock);
+ --dev->users;
+ mutex_unlock(&dev->lock);
+}
+
+void tah_reset(struct of_device *ofdev)
+{
+ struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct tah_regs __iomem *p = dev->base;
+ int n;
+
+ /* Reset TAH */
+ out_be32(&p->mr, TAH_MR_SR);
+ n = 100;
+ while ((in_be32(&p->mr) & TAH_MR_SR) && n)
+ --n;
+
+ if (unlikely(!n))
+ printk(KERN_ERR "%s: reset timeout\n", ofdev->node->full_name);
+
+ /* 10KB TAH TX FIFO accomodates the max MTU of 9000 */
+ out_be32(&p->mr,
+ TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP |
+ TAH_MR_DIG);
+}
+
+int tah_get_regs_len(struct of_device *ofdev)
+{
+ return sizeof(struct emac_ethtool_regs_subhdr) +
+ sizeof(struct tah_regs);
+}
+
+void *tah_dump_regs(struct of_device *ofdev, void *buf)
+{
+ struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct emac_ethtool_regs_subhdr *hdr = buf;
+ struct tah_regs *regs = (struct tah_regs *)(hdr + 1);
+
+ hdr->version = 0;
+ hdr->index = 0; /* for now, are there chips with more than one
+ * zmii ? if yes, then we'll add a cell_index
+ * like we do for emac
+ */
+ memcpy_fromio(regs, dev->base, sizeof(struct tah_regs));
+ return regs + 1;
+}
+
+static int __devinit tah_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = ofdev->node;
+ struct tah_instance *dev;
+ struct resource regs;
+ int rc;
+
+ rc = -ENOMEM;
+ dev = kzalloc(sizeof(struct tah_instance), GFP_KERNEL);
+ if (dev == NULL) {
+ printk(KERN_ERR "%s: could not allocate TAH device!\n",
+ np->full_name);
+ goto err_gone;
+ }
+
+ mutex_init(&dev->lock);
+ dev->ofdev = ofdev;
+
+ rc = -ENXIO;
+ if (of_address_to_resource(np, 0, &regs)) {
+ printk(KERN_ERR "%s: Can't get registers address\n",
+ np->full_name);
+ goto err_free;
+ }
+
+ rc = -ENOMEM;
+ dev->base = (struct tah_regs __iomem *)ioremap(regs.start,
+ sizeof(struct tah_regs));
+ if (dev->base == NULL) {
+ printk(KERN_ERR "%s: Can't map device registers!\n",
+ np->full_name);
+ goto err_free;
+ }
+
+ /* Initialize TAH and enable IPv4 checksum verification, no TSO yet */
+ tah_reset(ofdev);
+
+ printk(KERN_INFO
+ "TAH %s initialized\n", ofdev->node->full_name);
+ wmb();
+ dev_set_drvdata(&ofdev->dev, dev);
+
+ return 0;
+
+ err_free:
+ kfree(dev);
+ err_gone:
+ return rc;
+}
+
+static int __devexit tah_remove(struct of_device *ofdev)
+{
+ struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+
+ WARN_ON(dev->users != 0);
+
+ iounmap(dev->base);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct of_device_id tah_match[] =
+{
+ {
+ .type = "tah",
+ },
+ {},
+};
+
+static struct of_platform_driver tah_driver = {
+ .name = "emac-tah",
+ .match_table = tah_match,
+
+ .probe = tah_probe,
+ .remove = tah_remove,
+};
+
+int __init tah_init(void)
+{
+ return of_register_platform_driver(&tah_driver);
+}
+
+void tah_exit(void)
+{
+ of_unregister_platform_driver(&tah_driver);
+}
diff --git a/drivers/net/ibm_newemac/tah.h b/drivers/net/ibm_newemac/tah.h
new file mode 100644
index 00000000000..bc41853b6e2
--- /dev/null
+++ b/drivers/net/ibm_newemac/tah.h
@@ -0,0 +1,90 @@
+/*
+ * drivers/net/ibm_newemac/tah.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
+ *
+ * Copyright 2004 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __IBM_NEWEMAC_TAH_H
+#define __IBM_NEWEMAC_TAH_H
+
+/* TAH */
+struct tah_regs {
+ u32 revid;
+ u32 pad[3];
+ u32 mr;
+ u32 ssr0;
+ u32 ssr1;
+ u32 ssr2;
+ u32 ssr3;
+ u32 ssr4;
+ u32 ssr5;
+ u32 tsr;
+};
+
+
+/* TAH device */
+struct tah_instance {
+ struct tah_regs __iomem *base;
+
+ /* Only one EMAC whacks us at a time */
+ struct mutex lock;
+
+ /* number of EMACs using this TAH */
+ int users;
+
+ /* OF device instance */
+ struct of_device *ofdev;
+};
+
+
+/* TAH engine */
+#define TAH_MR_CVR 0x80000000
+#define TAH_MR_SR 0x40000000
+#define TAH_MR_ST_256 0x01000000
+#define TAH_MR_ST_512 0x02000000
+#define TAH_MR_ST_768 0x03000000
+#define TAH_MR_ST_1024 0x04000000
+#define TAH_MR_ST_1280 0x05000000
+#define TAH_MR_ST_1536 0x06000000
+#define TAH_MR_TFS_16KB 0x00000000
+#define TAH_MR_TFS_2KB 0x00200000
+#define TAH_MR_TFS_4KB 0x00400000
+#define TAH_MR_TFS_6KB 0x00600000
+#define TAH_MR_TFS_8KB 0x00800000
+#define TAH_MR_TFS_10KB 0x00a00000
+#define TAH_MR_DTFP 0x00100000
+#define TAH_MR_DIG 0x00080000
+
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+
+extern int tah_init(void);
+extern void tah_exit(void);
+extern int tah_attach(struct of_device *ofdev, int channel);
+extern void tah_detach(struct of_device *ofdev, int channel);
+extern void tah_reset(struct of_device *ofdev);
+extern int tah_get_regs_len(struct of_device *ofdev);
+extern void *tah_dump_regs(struct of_device *ofdev, void *buf);
+
+#else
+
+# define tah_init() 0
+# define tah_exit() do { } while(0)
+# define tah_attach(x,y) (-ENXIO)
+# define tah_detach(x,y) do { } while(0)
+# define tah_reset(x) do { } while(0)
+# define tah_get_regs_len(x) 0
+# define tah_dump_regs(x,buf) (buf)
+
+#endif /* !CONFIG_IBM_NEW_EMAC_TAH */
+
+#endif /* __IBM_NEWEMAC_TAH_H */
diff --git a/drivers/net/ibm_newemac/zmii.c b/drivers/net/ibm_newemac/zmii.c
new file mode 100644
index 00000000000..2219ec2740e
--- /dev/null
+++ b/drivers/net/ibm_newemac/zmii.c
@@ -0,0 +1,322 @@
+/*
+ * drivers/net/ibm_newemac/zmii.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Armin Kuster <akuster@mvista.com>
+ * Copyright 2001 MontaVista Softare Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/ethtool.h>
+#include <asm/io.h>
+
+#include "emac.h"
+#include "core.h"
+
+/* ZMIIx_FER */
+#define ZMII_FER_MDI(idx) (0x80000000 >> ((idx) * 4))
+#define ZMII_FER_MDI_ALL (ZMII_FER_MDI(0) | ZMII_FER_MDI(1) | \
+ ZMII_FER_MDI(2) | ZMII_FER_MDI(3))
+
+#define ZMII_FER_SMII(idx) (0x40000000 >> ((idx) * 4))
+#define ZMII_FER_RMII(idx) (0x20000000 >> ((idx) * 4))
+#define ZMII_FER_MII(idx) (0x10000000 >> ((idx) * 4))
+
+/* ZMIIx_SSR */
+#define ZMII_SSR_SCI(idx) (0x40000000 >> ((idx) * 4))
+#define ZMII_SSR_FSS(idx) (0x20000000 >> ((idx) * 4))
+#define ZMII_SSR_SP(idx) (0x10000000 >> ((idx) * 4))
+
+/* ZMII only supports MII, RMII and SMII
+ * we also support autodetection for backward compatibility
+ */
+static inline int zmii_valid_mode(int mode)
+{
+ return mode == PHY_MODE_MII ||
+ mode == PHY_MODE_RMII ||
+ mode == PHY_MODE_SMII ||
+ mode == PHY_MODE_NA;
+}
+
+static inline const char *zmii_mode_name(int mode)
+{
+ switch (mode) {
+ case PHY_MODE_MII:
+ return "MII";
+ case PHY_MODE_RMII:
+ return "RMII";
+ case PHY_MODE_SMII:
+ return "SMII";
+ default:
+ BUG();
+ }
+}
+
+static inline u32 zmii_mode_mask(int mode, int input)
+{
+ switch (mode) {
+ case PHY_MODE_MII:
+ return ZMII_FER_MII(input);
+ case PHY_MODE_RMII:
+ return ZMII_FER_RMII(input);
+ case PHY_MODE_SMII:
+ return ZMII_FER_SMII(input);
+ default:
+ return 0;
+ }
+}
+
+int __devinit zmii_attach(struct of_device *ofdev, int input, int *mode)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_regs __iomem *p = dev->base;
+
+ ZMII_DBG(dev, "init(%d, %d)" NL, input, *mode);
+
+ if (!zmii_valid_mode(*mode))
+ /* Probably an EMAC connected to RGMII,
+ * but it still may need ZMII for MDIO so
+ * we don't fail here.
+ */
+ return 0;
+
+ mutex_lock(&dev->lock);
+
+ /* Autodetect ZMII mode if not specified.
+ * This is only for backward compatibility with the old driver.
+ * Please, always specify PHY mode in your board port to avoid
+ * any surprises.
+ */
+ if (dev->mode == PHY_MODE_NA) {
+ if (*mode == PHY_MODE_NA) {
+ u32 r = dev->fer_save;
+
+ ZMII_DBG(dev, "autodetecting mode, FER = 0x%08x" NL, r);
+
+ if (r & (ZMII_FER_MII(0) | ZMII_FER_MII(1)))
+ dev->mode = PHY_MODE_MII;
+ else if (r & (ZMII_FER_RMII(0) | ZMII_FER_RMII(1)))
+ dev->mode = PHY_MODE_RMII;
+ else
+ dev->mode = PHY_MODE_SMII;
+ } else
+ dev->mode = *mode;
+
+ printk(KERN_NOTICE "%s: bridge in %s mode\n",
+ ofdev->node->full_name, zmii_mode_name(dev->mode));
+ } else {
+ /* All inputs must use the same mode */
+ if (*mode != PHY_MODE_NA && *mode != dev->mode) {
+ printk(KERN_ERR
+ "%s: invalid mode %d specified for input %d\n",
+ ofdev->node->full_name, *mode, input);
+ mutex_unlock(&dev->lock);
+ return -EINVAL;
+ }
+ }
+
+ /* Report back correct PHY mode,
+ * it may be used during PHY initialization.
+ */
+ *mode = dev->mode;
+
+ /* Enable this input */
+ out_be32(&p->fer, in_be32(&p->fer) | zmii_mode_mask(dev->mode, input));
+ ++dev->users;
+
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+void zmii_get_mdio(struct of_device *ofdev, int input)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ u32 fer;
+
+ ZMII_DBG2(dev, "get_mdio(%d)" NL, input);
+
+ mutex_lock(&dev->lock);
+
+ fer = in_be32(&dev->base->fer) & ~ZMII_FER_MDI_ALL;
+ out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input));
+}
+
+void zmii_put_mdio(struct of_device *ofdev, int input)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ ZMII_DBG2(dev, "put_mdio(%d)" NL, input);
+ mutex_unlock(&dev->lock);
+}
+
+
+void zmii_set_speed(struct of_device *ofdev, int input, int speed)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ u32 ssr;
+
+ mutex_lock(&dev->lock);
+
+ ssr = in_be32(&dev->base->ssr);
+
+ ZMII_DBG(dev, "speed(%d, %d)" NL, input, speed);
+
+ if (speed == SPEED_100)
+ ssr |= ZMII_SSR_SP(input);
+ else
+ ssr &= ~ZMII_SSR_SP(input);
+
+ out_be32(&dev->base->ssr, ssr);
+
+ mutex_unlock(&dev->lock);
+}
+
+void __devexit zmii_detach(struct of_device *ofdev, int input)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ BUG_ON(!dev || dev->users == 0);
+
+ mutex_lock(&dev->lock);
+
+ ZMII_DBG(dev, "detach(%d)" NL, input);
+
+ /* Disable this input */
+ out_be32(&dev->base->fer,
+ in_be32(&dev->base->fer) & ~zmii_mode_mask(dev->mode, input));
+
+ --dev->users;
+
+ mutex_unlock(&dev->lock);
+}
+
+int zmii_get_regs_len(struct of_device *ofdev)
+{
+ return sizeof(struct emac_ethtool_regs_subhdr) +
+ sizeof(struct zmii_regs);
+}
+
+void *zmii_dump_regs(struct of_device *ofdev, void *buf)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct emac_ethtool_regs_subhdr *hdr = buf;
+ struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1);
+
+ hdr->version = 0;
+ hdr->index = 0; /* for now, are there chips with more than one
+ * zmii ? if yes, then we'll add a cell_index
+ * like we do for emac
+ */
+ memcpy_fromio(regs, dev->base, sizeof(struct zmii_regs));
+ return regs + 1;
+}
+
+static int __devinit zmii_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = ofdev->node;
+ struct zmii_instance *dev;
+ struct resource regs;
+ int rc;
+
+ rc = -ENOMEM;
+ dev = kzalloc(sizeof(struct zmii_instance), GFP_KERNEL);
+ if (dev == NULL) {
+ printk(KERN_ERR "%s: could not allocate ZMII device!\n",
+ np->full_name);
+ goto err_gone;
+ }
+
+ mutex_init(&dev->lock);
+ dev->ofdev = ofdev;
+ dev->mode = PHY_MODE_NA;
+
+ rc = -ENXIO;
+ if (of_address_to_resource(np, 0, &regs)) {
+ printk(KERN_ERR "%s: Can't get registers address\n",
+ np->full_name);
+ goto err_free;
+ }
+
+ rc = -ENOMEM;
+ dev->base = (struct zmii_regs __iomem *)ioremap(regs.start,
+ sizeof(struct zmii_regs));
+ if (dev->base == NULL) {
+ printk(KERN_ERR "%s: Can't map device registers!\n",
+ np->full_name);
+ goto err_free;
+ }
+
+ /* We may need FER value for autodetection later */
+ dev->fer_save = in_be32(&dev->base->fer);
+
+ /* Disable all inputs by default */
+ out_be32(&dev->base->fer, 0);
+
+ printk(KERN_INFO
+ "ZMII %s initialized\n", ofdev->node->full_name);
+ wmb();
+ dev_set_drvdata(&ofdev->dev, dev);
+
+ return 0;
+
+ err_free:
+ kfree(dev);
+ err_gone:
+ return rc;
+}
+
+static int __devexit zmii_remove(struct of_device *ofdev)
+{
+ struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+
+ WARN_ON(dev->users != 0);
+
+ iounmap(dev->base);
+ kfree(dev);
+
+ return 0;
+}
+
+static struct of_device_id zmii_match[] =
+{
+ {
+ .compatible = "ibm,zmii",
+ },
+ /* For backward compat with old DT */
+ {
+ .type = "emac-zmii",
+ },
+ {},
+};
+
+static struct of_platform_driver zmii_driver = {
+ .name = "emac-zmii",
+ .match_table = zmii_match,
+
+ .probe = zmii_probe,
+ .remove = zmii_remove,
+};
+
+int __init zmii_init(void)
+{
+ return of_register_platform_driver(&zmii_driver);
+}
+
+void zmii_exit(void)
+{
+ of_unregister_platform_driver(&zmii_driver);
+}
diff --git a/drivers/net/ibm_newemac/zmii.h b/drivers/net/ibm_newemac/zmii.h
new file mode 100644
index 00000000000..82a9968b1f7
--- /dev/null
+++ b/drivers/net/ibm_newemac/zmii.h
@@ -0,0 +1,73 @@
+/*
+ * drivers/net/ibm_newemac/zmii.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * Armin Kuster <akuster@mvista.com>
+ * Copyright 2001 MontaVista Softare Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __IBM_NEWEMAC_ZMII_H
+#define __IBM_NEWEMAC_ZMII_H
+
+/* ZMII bridge registers */
+struct zmii_regs {
+ u32 fer; /* Function enable reg */
+ u32 ssr; /* Speed select reg */
+ u32 smiirs; /* SMII status reg */
+};
+
+/* ZMII device */
+struct zmii_instance {
+ struct zmii_regs __iomem *base;
+
+ /* Only one EMAC whacks us at a time */
+ struct mutex lock;
+
+ /* subset of PHY_MODE_XXXX */
+ int mode;
+
+ /* number of EMACs using this ZMII bridge */
+ int users;
+
+ /* FER value left by firmware */
+ u32 fer_save;
+
+ /* OF device instance */
+ struct of_device *ofdev;
+};
+
+#ifdef CONFIG_IBM_NEW_EMAC_ZMII
+
+extern int zmii_init(void);
+extern void zmii_exit(void);
+extern int zmii_attach(struct of_device *ofdev, int input, int *mode);
+extern void zmii_detach(struct of_device *ofdev, int input);
+extern void zmii_get_mdio(struct of_device *ofdev, int input);
+extern void zmii_put_mdio(struct of_device *ofdev, int input);
+extern void zmii_set_speed(struct of_device *ofdev, int input, int speed);
+extern int zmii_get_regs_len(struct of_device *ocpdev);
+extern void *zmii_dump_regs(struct of_device *ofdev, void *buf);
+
+#else
+# define zmii_init() 0
+# define zmii_exit() do { } while(0)
+# define zmii_attach(x,y,z) (-ENXIO)
+# define zmii_detach(x,y) do { } while(0)
+# define zmii_get_mdio(x,y) do { } while(0)
+# define zmii_put_mdio(x,y) do { } while(0)
+# define zmii_set_speed(x,y,z) do { } while(0)
+# define zmii_get_regs_len(x) 0
+# define zmii_dump_regs(x,buf) (buf)
+#endif /* !CONFIG_IBM_NEW_EMAC_ZMII */
+
+#endif /* __IBM_NEWEMAC_ZMII_H */
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index fe85d6fcba3..91d83aca6bc 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -591,7 +591,7 @@ static void irqrx_handler(struct net_device *dev)
skb = dev_alloc_skb(rda.length + 2);
if (skb == NULL)
- priv->stat.rx_dropped++;
+ dev->stats.rx_dropped++;
else {
/* copy out data */
@@ -606,8 +606,8 @@ static void irqrx_handler(struct net_device *dev)
/* bookkeeping */
dev->last_rx = jiffies;
- priv->stat.rx_packets++;
- priv->stat.rx_bytes += rda.length;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += rda.length;
/* pass to the upper layers */
netif_rx(skb);
@@ -617,11 +617,11 @@ static void irqrx_handler(struct net_device *dev)
/* otherwise check error status bits and increase statistics */
else {
- priv->stat.rx_errors++;
+ dev->stats.rx_errors++;
if (rda.status & RCREG_FAER)
- priv->stat.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rda.status & RCREG_CRCR)
- priv->stat.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
}
/* descriptor processed, will become new last descriptor in queue */
@@ -656,8 +656,8 @@ static void irqtx_handler(struct net_device *dev)
memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
/* update statistics */
- priv->stat.tx_packets++;
- priv->stat.tx_bytes += tda.length;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += tda.length;
/* update our pointers */
priv->txused[priv->currtxdescr] = 0;
@@ -680,15 +680,15 @@ static void irqtxerr_handler(struct net_device *dev)
memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
/* update statistics */
- priv->stat.tx_errors++;
+ dev->stats.tx_errors++;
if (tda.status & (TCREG_NCRS | TCREG_CRSL))
- priv->stat.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (tda.status & TCREG_EXC)
- priv->stat.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (tda.status & TCREG_OWC)
- priv->stat.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (tda.status & TCREG_FU)
- priv->stat.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
/* update our pointers */
priv->txused[priv->currtxdescr] = 0;
@@ -824,7 +824,7 @@ static int ibmlana_tx(struct sk_buff *skb, struct net_device *dev)
if (priv->txusedcnt >= TXBUFCNT) {
retval = -EIO;
- priv->stat.tx_dropped++;
+ dev->stats.tx_dropped++;
goto tx_done;
}
@@ -876,14 +876,6 @@ tx_done:
return retval;
}
-/* return pointer to Ethernet statistics */
-
-static struct net_device_stats *ibmlana_stats(struct net_device *dev)
-{
- ibmlana_priv *priv = netdev_priv(dev);
- return &priv->stat;
-}
-
/* switch receiver mode. */
static void ibmlana_set_multicast_list(struct net_device *dev)
@@ -906,8 +898,7 @@ static int ibmlana_probe(struct net_device *dev)
int base = 0, irq = 0, iobase = 0, memlen = 0;
ibmlana_priv *priv;
ibmlana_medium medium;
-
- SET_MODULE_OWNER(dev);
+ DECLARE_MAC_BUF(mac);
/* can't work without an MCA bus ;-) */
if (MCA_bus == 0)
@@ -980,7 +971,6 @@ static int ibmlana_probe(struct net_device *dev)
dev->stop = ibmlana_close;
dev->hard_start_xmit = ibmlana_tx;
dev->do_ioctl = NULL;
- dev->get_stats = ibmlana_stats;
dev->set_multicast_list = ibmlana_set_multicast_list;
dev->flags |= IFF_MULTICAST;
@@ -992,11 +982,10 @@ static int ibmlana_probe(struct net_device *dev)
/* print config */
printk(KERN_INFO "%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, "
- "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
+ "MAC address %s.\n",
dev->name, priv->realirq, dev->base_addr,
dev->mem_start, dev->mem_end - 1,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ print_mac(mac, dev->dev_addr));
printk(KERN_INFO "%s: %s medium\n", dev->name, MediaNames[priv->medium]);
/* reset board */
diff --git a/drivers/net/ibmlana.h b/drivers/net/ibmlana.h
index 6b58bab9e30..aa3ddbdee4b 100644
--- a/drivers/net/ibmlana.h
+++ b/drivers/net/ibmlana.h
@@ -26,7 +26,6 @@ typedef enum {
typedef struct {
unsigned int slot; /* MCA-Slot-# */
- struct net_device_stats stat; /* packet statistics */
int realirq; /* memorizes actual IRQ, even when
currently not allocated */
ibmlana_medium medium; /* physical cannector */
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index acba90f1638..7d7758f3ad8 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -28,7 +28,6 @@
/**************************************************************************/
/*
TODO:
- - remove frag processing code - no longer needed
- add support for sysfs
- possibly remove procfs support
*/
@@ -47,6 +46,9 @@
#include <linux/mm.h>
#include <linux/ethtool.h>
#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <net/net_namespace.h>
#include <asm/semaphore.h>
#include <asm/hvcall.h>
#include <asm/atomic.h>
@@ -83,9 +85,8 @@
static int ibmveth_open(struct net_device *dev);
static int ibmveth_close(struct net_device *dev);
static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int ibmveth_poll(struct net_device *dev, int *budget);
+static int ibmveth_poll(struct napi_struct *napi, int budget);
static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *ibmveth_get_stats(struct net_device *dev);
static void ibmveth_set_multicast_list(struct net_device *dev);
static int ibmveth_change_mtu(struct net_device *dev, int new_mtu);
static void ibmveth_proc_register_driver(void);
@@ -97,7 +98,7 @@ static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
static struct kobj_type ktype_veth_pool;
#ifdef CONFIG_PROC_FS
-#define IBMVETH_PROC_DIR "net/ibmveth"
+#define IBMVETH_PROC_DIR "ibmveth"
static struct proc_dir_entry *ibmveth_proc_dir;
#endif
@@ -110,20 +111,49 @@ MODULE_DESCRIPTION("IBM i/pSeries Virtual Ethernet Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(ibmveth_driver_version);
+struct ibmveth_stat {
+ char name[ETH_GSTRING_LEN];
+ int offset;
+};
+
+#define IBMVETH_STAT_OFF(stat) offsetof(struct ibmveth_adapter, stat)
+#define IBMVETH_GET_STAT(a, off) *((u64 *)(((unsigned long)(a)) + off))
+
+struct ibmveth_stat ibmveth_stats[] = {
+ { "replenish_task_cycles", IBMVETH_STAT_OFF(replenish_task_cycles) },
+ { "replenish_no_mem", IBMVETH_STAT_OFF(replenish_no_mem) },
+ { "replenish_add_buff_failure", IBMVETH_STAT_OFF(replenish_add_buff_failure) },
+ { "replenish_add_buff_success", IBMVETH_STAT_OFF(replenish_add_buff_success) },
+ { "rx_invalid_buffer", IBMVETH_STAT_OFF(rx_invalid_buffer) },
+ { "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) },
+ { "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) },
+ { "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) },
+};
+
/* simple methods of getting data from the current rxq entry */
+static inline u32 ibmveth_rxq_flags(struct ibmveth_adapter *adapter)
+{
+ return adapter->rx_queue.queue_addr[adapter->rx_queue.index].flags_off;
+}
+
+static inline int ibmveth_rxq_toggle(struct ibmveth_adapter *adapter)
+{
+ return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_TOGGLE) >> IBMVETH_RXQ_TOGGLE_SHIFT;
+}
+
static inline int ibmveth_rxq_pending_buffer(struct ibmveth_adapter *adapter)
{
- return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].toggle == adapter->rx_queue.toggle);
+ return (ibmveth_rxq_toggle(adapter) == adapter->rx_queue.toggle);
}
static inline int ibmveth_rxq_buffer_valid(struct ibmveth_adapter *adapter)
{
- return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].valid);
+ return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_VALID);
}
static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter)
{
- return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].offset);
+ return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK);
}
static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
@@ -131,6 +161,11 @@ static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
}
+static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter)
+{
+ return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_CSUM_GOOD);
+}
+
/* setup the initial settings for a buffer pool */
static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active)
{
@@ -228,9 +263,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc
correlator = ((u64)pool->index << 32) | index;
*(u64*)skb->data = correlator;
- desc.desc = 0;
- desc.fields.valid = 1;
- desc.fields.length = pool->buff_size;
+ desc.fields.flags_len = IBMVETH_BUF_VALID | pool->buff_size;
desc.fields.address = dma_addr;
lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
@@ -371,9 +404,8 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
return;
}
- desc.desc = 0;
- desc.fields.valid = 1;
- desc.fields.length = adapter->rx_buff_pool[pool].buff_size;
+ desc.fields.flags_len = IBMVETH_BUF_VALID |
+ adapter->rx_buff_pool[pool].buff_size;
desc.fields.address = adapter->rx_buff_pool[pool].dma_addr[index];
lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
@@ -480,6 +512,8 @@ static int ibmveth_open(struct net_device *netdev)
ibmveth_debug_printk("open starting\n");
+ napi_enable(&adapter->napi);
+
for(i = 0; i<IbmVethNumBufferPools; i++)
rxq_entries += adapter->rx_buff_pool[i].size;
@@ -489,6 +523,7 @@ static int ibmveth_open(struct net_device *netdev)
if(!adapter->buffer_list_addr || !adapter->filter_list_addr) {
ibmveth_error_printk("unable to allocate filter or buffer list pages\n");
ibmveth_cleanup(adapter);
+ napi_disable(&adapter->napi);
return -ENOMEM;
}
@@ -498,6 +533,7 @@ static int ibmveth_open(struct net_device *netdev)
if(!adapter->rx_queue.queue_addr) {
ibmveth_error_printk("unable to allocate rx queue pages\n");
ibmveth_cleanup(adapter);
+ napi_disable(&adapter->napi);
return -ENOMEM;
}
@@ -514,6 +550,7 @@ static int ibmveth_open(struct net_device *netdev)
(dma_mapping_error(adapter->rx_queue.queue_dma))) {
ibmveth_error_printk("unable to map filter or buffer list pages\n");
ibmveth_cleanup(adapter);
+ napi_disable(&adapter->napi);
return -ENOMEM;
}
@@ -524,9 +561,7 @@ static int ibmveth_open(struct net_device *netdev)
memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
mac_address = mac_address >> 16;
- rxq_desc.desc = 0;
- rxq_desc.fields.valid = 1;
- rxq_desc.fields.length = adapter->rx_queue.queue_len;
+ rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | adapter->rx_queue.queue_len;
rxq_desc.fields.address = adapter->rx_queue.queue_dma;
ibmveth_debug_printk("buffer list @ 0x%p\n", adapter->buffer_list_addr);
@@ -545,6 +580,7 @@ static int ibmveth_open(struct net_device *netdev)
rxq_desc.desc,
mac_address);
ibmveth_cleanup(adapter);
+ napi_disable(&adapter->napi);
return -ENONET;
}
@@ -555,6 +591,7 @@ static int ibmveth_open(struct net_device *netdev)
ibmveth_error_printk("unable to alloc pool\n");
adapter->rx_buff_pool[i].active = 0;
ibmveth_cleanup(adapter);
+ napi_disable(&adapter->napi);
return -ENOMEM ;
}
}
@@ -567,6 +604,7 @@ static int ibmveth_open(struct net_device *netdev)
} while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY));
ibmveth_cleanup(adapter);
+ napi_disable(&adapter->napi);
return rc;
}
@@ -587,6 +625,8 @@ static int ibmveth_close(struct net_device *netdev)
ibmveth_debug_printk("close starting\n");
+ napi_disable(&adapter->napi);
+
if (!adapter->pool_config)
netif_stop_queue(netdev);
@@ -634,12 +674,164 @@ static u32 netdev_get_link(struct net_device *dev) {
return 1;
}
+static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+
+ if (data)
+ adapter->rx_csum = 1;
+ else {
+ /*
+ * Since the ibmveth firmware interface does not have the concept of
+ * separate tx/rx checksum offload enable, if rx checksum is disabled
+ * we also have to disable tx checksum offload. Once we disable rx
+ * checksum offload, we are no longer allowed to send tx buffers that
+ * are not properly checksummed.
+ */
+ adapter->rx_csum = 0;
+ dev->features &= ~NETIF_F_IP_CSUM;
+ }
+}
+
+static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+
+ if (data) {
+ dev->features |= NETIF_F_IP_CSUM;
+ adapter->rx_csum = 1;
+ } else
+ dev->features &= ~NETIF_F_IP_CSUM;
+}
+
+static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
+ void (*done) (struct net_device *, u32))
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+ u64 set_attr, clr_attr, ret_attr;
+ long ret;
+ int rc1 = 0, rc2 = 0;
+ int restart = 0;
+
+ if (netif_running(dev)) {
+ restart = 1;
+ adapter->pool_config = 1;
+ ibmveth_close(dev);
+ adapter->pool_config = 0;
+ }
+
+ set_attr = 0;
+ clr_attr = 0;
+
+ if (data)
+ set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
+ else
+ clr_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
+
+ ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr);
+
+ if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) &&
+ !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) &&
+ (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) {
+ ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr,
+ set_attr, &ret_attr);
+
+ if (ret != H_SUCCESS) {
+ rc1 = -EIO;
+ ibmveth_error_printk("unable to change checksum offload settings."
+ " %d rc=%ld\n", data, ret);
+
+ ret = h_illan_attributes(adapter->vdev->unit_address,
+ set_attr, clr_attr, &ret_attr);
+ } else
+ done(dev, data);
+ } else {
+ rc1 = -EIO;
+ ibmveth_error_printk("unable to change checksum offload settings."
+ " %d rc=%ld ret_attr=%lx\n", data, ret, ret_attr);
+ }
+
+ if (restart)
+ rc2 = ibmveth_open(dev);
+
+ return rc1 ? rc1 : rc2;
+}
+
+static int ibmveth_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+
+ if ((data && adapter->rx_csum) || (!data && !adapter->rx_csum))
+ return 0;
+
+ return ibmveth_set_csum_offload(dev, data, ibmveth_set_rx_csum_flags);
+}
+
+static int ibmveth_set_tx_csum(struct net_device *dev, u32 data)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+ int rc = 0;
+
+ if (data && (dev->features & NETIF_F_IP_CSUM))
+ return 0;
+ if (!data && !(dev->features & NETIF_F_IP_CSUM))
+ return 0;
+
+ if (data && !adapter->rx_csum)
+ rc = ibmveth_set_csum_offload(dev, data, ibmveth_set_tx_csum_flags);
+ else
+ ibmveth_set_tx_csum_flags(dev, data);
+
+ return rc;
+}
+
+static u32 ibmveth_get_rx_csum(struct net_device *dev)
+{
+ struct ibmveth_adapter *adapter = dev->priv;
+ return adapter->rx_csum;
+}
+
+static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ int i;
+
+ if (stringset != ETH_SS_STATS)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++, data += ETH_GSTRING_LEN)
+ memcpy(data, ibmveth_stats[i].name, ETH_GSTRING_LEN);
+}
+
+static int ibmveth_get_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(ibmveth_stats);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void ibmveth_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ int i;
+ struct ibmveth_adapter *adapter = dev->priv;
+
+ for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++)
+ data[i] = IBMVETH_GET_STAT(adapter, ibmveth_stats[i].offset);
+}
+
static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
.get_link = netdev_get_link,
- .get_sg = ethtool_op_get_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ibmveth_set_tx_csum,
+ .get_rx_csum = ibmveth_get_rx_csum,
+ .set_rx_csum = ibmveth_set_rx_csum,
+ .get_strings = ibmveth_get_strings,
+ .get_sset_count = ibmveth_get_sset_count,
+ .get_ethtool_stats = ibmveth_get_ethtool_stats,
};
static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -652,9 +844,8 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct ibmveth_adapter *adapter = netdev->priv;
- union ibmveth_buf_desc desc[IbmVethMaxSendFrags];
+ union ibmveth_buf_desc desc;
unsigned long lpar_rc;
- int nfrags = 0, curfrag;
unsigned long correlator;
unsigned long flags;
unsigned int retry_count;
@@ -664,83 +855,48 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
unsigned int tx_send_failed = 0;
unsigned int tx_map_failed = 0;
+ desc.fields.flags_len = IBMVETH_BUF_VALID | skb->len;
+ desc.fields.address = dma_map_single(&adapter->vdev->dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
- if ((skb_shinfo(skb)->nr_frags + 1) > IbmVethMaxSendFrags) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL &&
+ ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) {
+ ibmveth_error_printk("tx: failed to checksum packet\n");
tx_dropped++;
goto out;
}
- memset(&desc, 0, sizeof(desc));
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ unsigned char *buf = skb_transport_header(skb) + skb->csum_offset;
- /* nfrags = number of frags after the initial fragment */
- nfrags = skb_shinfo(skb)->nr_frags;
+ desc.fields.flags_len |= (IBMVETH_BUF_NO_CSUM | IBMVETH_BUF_CSUM_GOOD);
- if(nfrags)
- adapter->tx_multidesc_send++;
-
- /* map the initial fragment */
- desc[0].fields.length = nfrags ? skb->len - skb->data_len : skb->len;
- desc[0].fields.address = dma_map_single(&adapter->vdev->dev, skb->data,
- desc[0].fields.length, DMA_TO_DEVICE);
- desc[0].fields.valid = 1;
+ /* Need to zero out the checksum */
+ buf[0] = 0;
+ buf[1] = 0;
+ }
- if(dma_mapping_error(desc[0].fields.address)) {
- ibmveth_error_printk("tx: unable to map initial fragment\n");
+ if (dma_mapping_error(desc.fields.address)) {
+ ibmveth_error_printk("tx: unable to map xmit buffer\n");
tx_map_failed++;
tx_dropped++;
goto out;
}
- curfrag = nfrags;
-
- /* map fragments past the initial portion if there are any */
- while(curfrag--) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[curfrag];
- desc[curfrag+1].fields.address
- = dma_map_single(&adapter->vdev->dev,
- page_address(frag->page) + frag->page_offset,
- frag->size, DMA_TO_DEVICE);
- desc[curfrag+1].fields.length = frag->size;
- desc[curfrag+1].fields.valid = 1;
-
- if(dma_mapping_error(desc[curfrag+1].fields.address)) {
- ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag);
- tx_map_failed++;
- tx_dropped++;
- /* Free all the mappings we just created */
- while(curfrag < nfrags) {
- dma_unmap_single(&adapter->vdev->dev,
- desc[curfrag+1].fields.address,
- desc[curfrag+1].fields.length,
- DMA_TO_DEVICE);
- curfrag++;
- }
- goto out;
- }
- }
-
/* send the frame. Arbitrarily set retrycount to 1024 */
correlator = 0;
retry_count = 1024;
do {
lpar_rc = h_send_logical_lan(adapter->vdev->unit_address,
- desc[0].desc,
- desc[1].desc,
- desc[2].desc,
- desc[3].desc,
- desc[4].desc,
- desc[5].desc,
- correlator,
- &correlator);
+ desc.desc, 0, 0, 0, 0, 0,
+ correlator, &correlator);
} while ((lpar_rc == H_BUSY) && (retry_count--));
if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) {
- int i;
ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc);
- for(i = 0; i < 6; i++) {
- ibmveth_error_printk("tx: desc[%i] valid=%d, len=%d, address=0x%d\n", i,
- desc[i].fields.valid, desc[i].fields.length, desc[i].fields.address);
- }
+ ibmveth_error_printk("tx: valid=%d, len=%d, address=0x%08x\n",
+ (desc.fields.flags_len & IBMVETH_BUF_VALID) ? 1 : 0,
+ skb->len, desc.fields.address);
tx_send_failed++;
tx_dropped++;
} else {
@@ -749,16 +905,13 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
netdev->trans_start = jiffies;
}
- do {
- dma_unmap_single(&adapter->vdev->dev,
- desc[nfrags].fields.address,
- desc[nfrags].fields.length, DMA_TO_DEVICE);
- } while(--nfrags >= 0);
+ dma_unmap_single(&adapter->vdev->dev, desc.fields.address,
+ skb->len, DMA_TO_DEVICE);
out: spin_lock_irqsave(&adapter->stats_lock, flags);
- adapter->stats.tx_dropped += tx_dropped;
- adapter->stats.tx_bytes += tx_bytes;
- adapter->stats.tx_packets += tx_packets;
+ netdev->stats.tx_dropped += tx_dropped;
+ netdev->stats.tx_bytes += tx_bytes;
+ netdev->stats.tx_packets += tx_packets;
adapter->tx_send_failed += tx_send_failed;
adapter->tx_map_failed += tx_map_failed;
spin_unlock_irqrestore(&adapter->stats_lock, flags);
@@ -767,80 +920,72 @@ out: spin_lock_irqsave(&adapter->stats_lock, flags);
return 0;
}
-static int ibmveth_poll(struct net_device *netdev, int *budget)
+static int ibmveth_poll(struct napi_struct *napi, int budget)
{
- struct ibmveth_adapter *adapter = netdev->priv;
- int max_frames_to_process = netdev->quota;
+ struct ibmveth_adapter *adapter = container_of(napi, struct ibmveth_adapter, napi);
+ struct net_device *netdev = adapter->netdev;
int frames_processed = 0;
- int more_work = 1;
unsigned long lpar_rc;
restart_poll:
do {
- struct net_device *netdev = adapter->netdev;
+ struct sk_buff *skb;
- if(ibmveth_rxq_pending_buffer(adapter)) {
- struct sk_buff *skb;
+ if (!ibmveth_rxq_pending_buffer(adapter))
+ break;
- rmb();
+ rmb();
+ if (!ibmveth_rxq_buffer_valid(adapter)) {
+ wmb(); /* suggested by larson1 */
+ adapter->rx_invalid_buffer++;
+ ibmveth_debug_printk("recycling invalid buffer\n");
+ ibmveth_rxq_recycle_buffer(adapter);
+ } else {
+ int length = ibmveth_rxq_frame_length(adapter);
+ int offset = ibmveth_rxq_frame_offset(adapter);
+ int csum_good = ibmveth_rxq_csum_good(adapter);
- if(!ibmveth_rxq_buffer_valid(adapter)) {
- wmb(); /* suggested by larson1 */
- adapter->rx_invalid_buffer++;
- ibmveth_debug_printk("recycling invalid buffer\n");
- ibmveth_rxq_recycle_buffer(adapter);
- } else {
- int length = ibmveth_rxq_frame_length(adapter);
- int offset = ibmveth_rxq_frame_offset(adapter);
- skb = ibmveth_rxq_get_buffer(adapter);
+ skb = ibmveth_rxq_get_buffer(adapter);
+ if (csum_good)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
- ibmveth_rxq_harvest_buffer(adapter);
+ ibmveth_rxq_harvest_buffer(adapter);
- skb_reserve(skb, offset);
- skb_put(skb, length);
- skb->protocol = eth_type_trans(skb, netdev);
+ skb_reserve(skb, offset);
+ skb_put(skb, length);
+ skb->protocol = eth_type_trans(skb, netdev);
- netif_receive_skb(skb); /* send it up */
+ netif_receive_skb(skb); /* send it up */
- adapter->stats.rx_packets++;
- adapter->stats.rx_bytes += length;
- frames_processed++;
- netdev->last_rx = jiffies;
- }
- } else {
- more_work = 0;
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += length;
+ frames_processed++;
+ netdev->last_rx = jiffies;
}
- } while(more_work && (frames_processed < max_frames_to_process));
+ } while (frames_processed < budget);
ibmveth_replenish_task(adapter);
- if(more_work) {
- /* more work to do - return that we are not done yet */
- netdev->quota -= frames_processed;
- *budget -= frames_processed;
- return 1;
- }
-
- /* we think we are done - reenable interrupts, then check once more to make sure we are done */
- lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_ENABLE);
+ if (frames_processed < budget) {
+ /* We think we are done - reenable interrupts,
+ * then check once more to make sure we are done.
+ */
+ lpar_rc = h_vio_signal(adapter->vdev->unit_address,
+ VIO_IRQ_ENABLE);
- ibmveth_assert(lpar_rc == H_SUCCESS);
+ ibmveth_assert(lpar_rc == H_SUCCESS);
- netif_rx_complete(netdev);
+ netif_rx_complete(netdev, napi);
- if(ibmveth_rxq_pending_buffer(adapter) && netif_rx_reschedule(netdev, frames_processed))
- {
- lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE);
- ibmveth_assert(lpar_rc == H_SUCCESS);
- more_work = 1;
- goto restart_poll;
+ if (ibmveth_rxq_pending_buffer(adapter) &&
+ netif_rx_reschedule(netdev, napi)) {
+ lpar_rc = h_vio_signal(adapter->vdev->unit_address,
+ VIO_IRQ_DISABLE);
+ goto restart_poll;
+ }
}
- netdev->quota -= frames_processed;
- *budget -= frames_processed;
-
- /* we really are done */
- return 0;
+ return frames_processed;
}
static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance)
@@ -849,20 +994,15 @@ static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance)
struct ibmveth_adapter *adapter = netdev->priv;
unsigned long lpar_rc;
- if(netif_rx_schedule_prep(netdev)) {
- lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE);
+ if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+ lpar_rc = h_vio_signal(adapter->vdev->unit_address,
+ VIO_IRQ_DISABLE);
ibmveth_assert(lpar_rc == H_SUCCESS);
- __netif_rx_schedule(netdev);
+ __netif_rx_schedule(netdev, &adapter->napi);
}
return IRQ_HANDLED;
}
-static struct net_device_stats *ibmveth_get_stats(struct net_device *dev)
-{
- struct ibmveth_adapter *adapter = dev->priv;
- return &adapter->stats;
-}
-
static void ibmveth_set_multicast_list(struct net_device *netdev)
{
struct ibmveth_adapter *adapter = netdev->priv;
@@ -962,8 +1102,10 @@ static void ibmveth_poll_controller(struct net_device *dev)
static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
{
int rc, i;
+ long ret;
struct net_device *netdev;
struct ibmveth_adapter *adapter;
+ u64 set_attr, ret_attr;
unsigned char *mac_addr_p;
unsigned int *mcastFilterSize_p;
@@ -994,8 +1136,6 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
if(!netdev)
return -ENOMEM;
- SET_MODULE_OWNER(netdev);
-
adapter = netdev->priv;
dev->dev.driver_data = netdev;
@@ -1004,6 +1144,8 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
adapter->mcastFilterSize= *mcastFilterSize_p;
adapter->pool_config = 0;
+ netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
+
/* Some older boxes running PHYP non-natively have an OF that
returns a 8-byte local-mac-address field (and the first
2 bytes have to be ignored) while newer boxes' OF return
@@ -1020,11 +1162,8 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
netdev->irq = dev->irq;
netdev->open = ibmveth_open;
- netdev->poll = ibmveth_poll;
- netdev->weight = 16;
netdev->stop = ibmveth_close;
netdev->hard_start_xmit = ibmveth_start_xmit;
- netdev->get_stats = ibmveth_get_stats;
netdev->set_multicast_list = ibmveth_set_multicast_list;
netdev->do_ioctl = ibmveth_ioctl;
netdev->ethtool_ops = &netdev_ethtool_ops;
@@ -1044,7 +1183,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
pool_count[i], pool_size[i],
pool_active[i]);
kobj->parent = &dev->dev.kobj;
- sprintf(kobj->name, "pool%d", i);
+ kobject_set_name(kobj, "pool%d", i);
kobj->ktype = &ktype_veth_pool;
kobject_register(kobj);
}
@@ -1057,6 +1196,22 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
ibmveth_debug_printk("registering netdev...\n");
+ ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr);
+
+ if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) &&
+ !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) &&
+ (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) {
+ set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
+
+ ret = h_illan_attributes(dev->unit_address, 0, set_attr, &ret_attr);
+
+ if (ret == H_SUCCESS) {
+ adapter->rx_csum = 1;
+ netdev->features |= NETIF_F_IP_CSUM;
+ } else
+ ret = h_illan_attributes(dev->unit_address, set_attr, 0, &ret_attr);
+ }
+
rc = register_netdev(netdev);
if(rc) {
@@ -1092,15 +1247,14 @@ static int __devexit ibmveth_remove(struct vio_dev *dev)
#ifdef CONFIG_PROC_FS
static void ibmveth_proc_register_driver(void)
{
- ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, NULL);
+ ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, init_net.proc_net);
if (ibmveth_proc_dir) {
- SET_MODULE_OWNER(ibmveth_proc_dir);
}
}
static void ibmveth_proc_unregister_driver(void)
{
- remove_proc_entry(IBMVETH_PROC_DIR, NULL);
+ remove_proc_entry(IBMVETH_PROC_DIR, init_net.proc_net);
}
static void *ibmveth_seq_start(struct seq_file *seq, loff_t *pos)
@@ -1127,22 +1281,16 @@ static int ibmveth_seq_show(struct seq_file *seq, void *v)
struct ibmveth_adapter *adapter = seq->private;
char *current_mac = ((char*) &adapter->netdev->dev_addr);
char *firmware_mac = ((char*) &adapter->mac_addr) ;
+ DECLARE_MAC_BUF(mac);
seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version);
seq_printf(seq, "Unit Address: 0x%x\n", adapter->vdev->unit_address);
- seq_printf(seq, "Current MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
- current_mac[0], current_mac[1], current_mac[2],
- current_mac[3], current_mac[4], current_mac[5]);
- seq_printf(seq, "Firmware MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
- firmware_mac[0], firmware_mac[1], firmware_mac[2],
- firmware_mac[3], firmware_mac[4], firmware_mac[5]);
+ seq_printf(seq, "Current MAC: %s\n", print_mac(mac, current_mac));
+ seq_printf(seq, "Firmware MAC: %s\n", print_mac(mac, firmware_mac));
seq_printf(seq, "\nAdapter Statistics:\n");
- seq_printf(seq, " TX: skbuffs linearized: %ld\n", adapter->tx_linearized);
- seq_printf(seq, " multi-descriptor sends: %ld\n", adapter->tx_multidesc_send);
- seq_printf(seq, " skb_linearize failures: %ld\n", adapter->tx_linearize_failed);
- seq_printf(seq, " vio_map_single failres: %ld\n", adapter->tx_map_failed);
+ seq_printf(seq, " TX: vio_map_single failres: %ld\n", adapter->tx_map_failed);
seq_printf(seq, " send failures: %ld\n", adapter->tx_send_failed);
seq_printf(seq, " RX: replenish task cycles: %ld\n", adapter->replenish_task_cycles);
seq_printf(seq, " alloc_skb_failures: %ld\n", adapter->replenish_no_mem);
@@ -1195,7 +1343,6 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter)
} else {
entry->data = (void *) adapter;
entry->proc_fops = &ibmveth_proc_fops;
- SET_MODULE_OWNER(entry);
}
}
return;
diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h
index 72cc15a6cab..41f61cd1885 100644
--- a/drivers/net/ibmveth.h
+++ b/drivers/net/ibmveth.h
@@ -25,8 +25,6 @@
#ifndef _IBMVETH_H
#define _IBMVETH_H
-#define IbmVethMaxSendFrags 6
-
/* constants for H_MULTICAST_CTRL */
#define IbmVethMcastReceptionModifyBit 0x80000UL
#define IbmVethMcastReceptionEnableBit 0x20000UL
@@ -41,6 +39,12 @@
#define IbmVethMcastRemoveFilter 0x2UL
#define IbmVethMcastClearFilterTable 0x3UL
+#define IBMVETH_ILLAN_PADDED_PKT_CSUM 0x0000000000002000ULL
+#define IBMVETH_ILLAN_TRUNK_PRI_MASK 0x0000000000000F00ULL
+#define IBMVETH_ILLAN_IPV6_TCP_CSUM 0x0000000000000004ULL
+#define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002ULL
+#define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001ULL
+
/* hcall macros */
#define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \
plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac)
@@ -67,6 +71,21 @@ static inline long h_send_logical_lan(unsigned long unit_address,
return rc;
}
+static inline long h_illan_attributes(unsigned long unit_address,
+ unsigned long reset_mask, unsigned long set_mask,
+ unsigned long *ret_attributes)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall(H_ILLAN_ATTRIBUTES, retbuf, unit_address,
+ reset_mask, set_mask);
+
+ *ret_attributes = retbuf[0];
+
+ return rc;
+}
+
#define h_multicast_ctrl(ua, cmd, mac) \
plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac)
@@ -112,6 +131,7 @@ struct ibmveth_rx_q {
struct ibmveth_adapter {
struct vio_dev *vdev;
struct net_device *netdev;
+ struct napi_struct napi;
struct net_device_stats stats;
unsigned int mcastFilterSize;
unsigned long mac_addr;
@@ -122,6 +142,7 @@ struct ibmveth_adapter {
struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools];
struct ibmveth_rx_q rx_queue;
int pool_config;
+ int rx_csum;
/* adapter specific stats */
u64 replenish_task_cycles;
@@ -130,20 +151,19 @@ struct ibmveth_adapter {
u64 replenish_add_buff_success;
u64 rx_invalid_buffer;
u64 rx_no_buffer;
- u64 tx_multidesc_send;
- u64 tx_linearized;
- u64 tx_linearize_failed;
u64 tx_map_failed;
u64 tx_send_failed;
spinlock_t stats_lock;
};
struct ibmveth_buf_desc_fields {
- u32 valid : 1;
- u32 toggle : 1;
- u32 reserved : 6;
- u32 length : 24;
- u32 address;
+ u32 flags_len;
+#define IBMVETH_BUF_VALID 0x80000000
+#define IBMVETH_BUF_TOGGLE 0x40000000
+#define IBMVETH_BUF_NO_CSUM 0x02000000
+#define IBMVETH_BUF_CSUM_GOOD 0x01000000
+#define IBMVETH_BUF_LEN_MASK 0x00FFFFFF
+ u32 address;
};
union ibmveth_buf_desc {
@@ -152,12 +172,16 @@ union ibmveth_buf_desc {
};
struct ibmveth_rx_q_entry {
- u16 toggle : 1;
- u16 valid : 1;
- u16 reserved : 14;
- u16 offset;
- u32 length;
- u64 correlator;
+ u32 flags_off;
+#define IBMVETH_RXQ_TOGGLE 0x80000000
+#define IBMVETH_RXQ_TOGGLE_SHIFT 31
+#define IBMVETH_RXQ_VALID 0x40000000
+#define IBMVETH_RXQ_NO_CSUM 0x02000000
+#define IBMVETH_RXQ_CSUM_GOOD 0x01000000
+#define IBMVETH_RXQ_OFF_MASK 0x0000FFFF
+
+ u32 length;
+ u64 correlator;
};
#endif /* _IBMVETH_H */
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index f5c3598e59a..15949d3df17 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -34,12 +34,12 @@
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <net/pkt_sched.h>
+#include <net/net_namespace.h>
#define TX_TIMEOUT (2*HZ)
#define TX_Q_LIMIT 32
struct ifb_private {
- struct net_device_stats stats;
struct tasklet_struct ifb_tasklet;
int tasklet_pending;
/* mostly debug stats leave in for now */
@@ -60,7 +60,6 @@ static int numifbs = 2;
static void ri_tasklet(unsigned long dev);
static int ifb_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *ifb_get_stats(struct net_device *dev);
static int ifb_open(struct net_device *dev);
static int ifb_close(struct net_device *dev);
@@ -69,7 +68,7 @@ static void ri_tasklet(unsigned long dev)
struct net_device *_dev = (struct net_device *)dev;
struct ifb_private *dp = netdev_priv(_dev);
- struct net_device_stats *stats = &dp->stats;
+ struct net_device_stats *stats = &_dev->stats;
struct sk_buff *skb;
dp->st_task_enter++;
@@ -97,7 +96,7 @@ static void ri_tasklet(unsigned long dev)
stats->tx_packets++;
stats->tx_bytes +=skb->len;
- skb->dev = __dev_get_by_index(skb->iif);
+ skb->dev = __dev_get_by_index(&init_net, skb->iif);
if (!skb->dev) {
dev_kfree_skb(skb);
stats->tx_dropped++;
@@ -139,7 +138,6 @@ resched:
static void ifb_setup(struct net_device *dev)
{
/* Initialize the device structure. */
- dev->get_stats = ifb_get_stats;
dev->hard_start_xmit = ifb_xmit;
dev->open = &ifb_open;
dev->stop = &ifb_close;
@@ -151,14 +149,13 @@ static void ifb_setup(struct net_device *dev)
dev->change_mtu = NULL;
dev->flags |= IFF_NOARP;
dev->flags &= ~IFF_MULTICAST;
- SET_MODULE_OWNER(dev);
random_ether_addr(dev->dev_addr);
}
static int ifb_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ifb_private *dp = netdev_priv(dev);
- struct net_device_stats *stats = &dp->stats;
+ struct net_device_stats *stats = &dev->stats;
int ret = 0;
u32 from = G_TC_FROM(skb->tc_verd);
@@ -185,19 +182,6 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev)
return ret;
}
-static struct net_device_stats *ifb_get_stats(struct net_device *dev)
-{
- struct ifb_private *dp = netdev_priv(dev);
- struct net_device_stats *stats = &dp->stats;
-
- pr_debug("tasklets stats %ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld \n",
- dp->st_task_enter, dp->st_txq_refl_try, dp->st_rxq_enter,
- dp->st_rx2tx_tran, dp->st_rxq_notenter, dp->st_rx_frm_egr,
- dp->st_rx_frm_ing, dp->st_rxq_check, dp->st_rxq_rsch);
-
- return stats;
-}
-
static int ifb_close(struct net_device *dev)
{
struct ifb_private *dp = netdev_priv(dev);
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index 0834ef0eddb..373f72cdbe8 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -5,7 +5,7 @@
*
* Driver for SGI's IOC3 based Ethernet cards as found in the PCI card.
*
- * Copyright (C) 1999, 2000, 2001, 2003 Ralf Baechle
+ * Copyright (C) 1999, 2000, 01, 03, 06 Ralf Baechle
* Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc.
*
* References:
@@ -62,12 +62,7 @@
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/sn/types.h>
-#include <asm/sn/sn0/addrs.h>
-#include <asm/sn/sn0/hubni.h>
-#include <asm/sn/sn0/hubio.h>
-#include <asm/sn/klconfig.h>
#include <asm/sn/ioc3.h>
-#include <asm/sn/sn0/ip27.h>
#include <asm/pci/bridge.h>
/*
@@ -95,6 +90,9 @@ struct ioc3_private {
u32 emcr, ehar_h, ehar_l;
spinlock_t ioc3_lock;
struct mii_if_info mii;
+ unsigned long flags;
+#define IOC3_FLAG_RX_CHECKSUMS 1
+
struct pci_dev *pdev;
/* Members used by autonegotiation */
@@ -445,18 +443,12 @@ static void ioc3_get_eaddr_nic(struct ioc3_private *ip)
*/
static void ioc3_get_eaddr(struct ioc3_private *ip)
{
- int i;
-
+ DECLARE_MAC_BUF(mac);
ioc3_get_eaddr_nic(ip);
- printk("Ethernet address is ");
- for (i = 0; i < 6; i++) {
- printk("%02x", priv_netdev(ip)->dev_addr[i]);
- if (i < 5)
- printk(":");
- }
- printk(".\n");
+ printk("Ethernet address is %s.\n",
+ print_mac(mac, priv_netdev(ip)->dev_addr));
}
static void __ioc3_set_mac_address(struct net_device *dev)
@@ -521,8 +513,6 @@ static struct net_device_stats *ioc3_get_stats(struct net_device *dev)
return &ip->stats;
}
-#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM
-
static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len)
{
struct ethhdr *eh = eth_hdr(skb);
@@ -590,7 +580,6 @@ static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len)
if (csum == 0xffff)
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
-#endif /* CONFIG_SGI_IOC3_ETH_HW_RX_CSUM */
static inline void ioc3_rx(struct ioc3_private *ip)
{
@@ -625,9 +614,9 @@ static inline void ioc3_rx(struct ioc3_private *ip)
goto next;
}
-#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM
- ioc3_tcpudp_checksum(skb, w0 & ERXBUF_IPCKSUM_MASK,len);
-#endif
+ if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS))
+ ioc3_tcpudp_checksum(skb,
+ w0 & ERXBUF_IPCKSUM_MASK, len);
netif_rx(skb);
@@ -1278,7 +1267,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto out_free;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
ip = netdev_priv(dev);
@@ -1338,9 +1326,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->set_multicast_list = ioc3_set_multicast_list;
dev->set_mac_address = ioc3_set_mac_address;
dev->ethtool_ops = &ioc3_ethtool_ops;
-#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
dev->features = NETIF_F_IP_CSUM;
-#endif
sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1);
sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2);
@@ -1430,7 +1416,6 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
uint32_t w0 = 0;
int produce;
-#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
/*
* IOC3 has a fairly simple minded checksumming hardware which simply
* adds up the 1's complement checksum for the entire packet and
@@ -1478,7 +1463,6 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT);
}
-#endif /* CONFIG_SGI_IOC3_ETH_HW_TX_CSUM */
spin_lock_irq(&ip->ioc3_lock);
@@ -1633,12 +1617,37 @@ static u32 ioc3_get_link(struct net_device *dev)
return rc;
}
+static u32 ioc3_get_rx_csum(struct net_device *dev)
+{
+ struct ioc3_private *ip = netdev_priv(dev);
+
+ return ip->flags & IOC3_FLAG_RX_CHECKSUMS;
+}
+
+static int ioc3_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct ioc3_private *ip = netdev_priv(dev);
+
+ spin_lock_bh(&ip->ioc3_lock);
+ if (data)
+ ip->flags |= IOC3_FLAG_RX_CHECKSUMS;
+ else
+ ip->flags &= ~IOC3_FLAG_RX_CHECKSUMS;
+ spin_unlock_bh(&ip->ioc3_lock);
+
+ return 0;
+}
+
static const struct ethtool_ops ioc3_ethtool_ops = {
.get_drvinfo = ioc3_get_drvinfo,
.get_settings = ioc3_get_settings,
.set_settings = ioc3_set_settings,
.nway_reset = ioc3_nway_reset,
.get_link = ioc3_get_link,
+ .get_rx_csum = ioc3_get_rx_csum,
+ .set_rx_csum = ioc3_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_csum
};
static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
new file mode 100644
index 00000000000..dbd23bb65d1
--- /dev/null
+++ b/drivers/net/ipg.c
@@ -0,0 +1,2352 @@
+/*
+ * ipg.c: Device Driver for the IP1000 Gigabit Ethernet Adapter
+ *
+ * Copyright (C) 2003, 2007 IC Plus Corp
+ *
+ * Original Author:
+ *
+ * Craig Rich
+ * Sundance Technology, Inc.
+ * www.sundanceti.com
+ * craig_rich@sundanceti.com
+ *
+ * Current Maintainer:
+ *
+ * Sorbica Shieh.
+ * http://www.icplus.com.tw
+ * sorbica@icplus.com.tw
+ *
+ * Jesse Huang
+ * http://www.icplus.com.tw
+ * jesse@icplus.com.tw
+ */
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/mutex.h>
+
+#include <asm/div64.h>
+
+#define IPG_RX_RING_BYTES (sizeof(struct ipg_rx) * IPG_RFDLIST_LENGTH)
+#define IPG_TX_RING_BYTES (sizeof(struct ipg_tx) * IPG_TFDLIST_LENGTH)
+#define IPG_RESET_MASK \
+ (IPG_AC_GLOBAL_RESET | IPG_AC_RX_RESET | IPG_AC_TX_RESET | \
+ IPG_AC_DMA | IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | \
+ IPG_AC_AUTO_INIT)
+
+#define ipg_w32(val32,reg) iowrite32((val32), ioaddr + (reg))
+#define ipg_w16(val16,reg) iowrite16((val16), ioaddr + (reg))
+#define ipg_w8(val8,reg) iowrite8((val8), ioaddr + (reg))
+
+#define ipg_r32(reg) ioread32(ioaddr + (reg))
+#define ipg_r16(reg) ioread16(ioaddr + (reg))
+#define ipg_r8(reg) ioread8(ioaddr + (reg))
+
+#define JUMBO_FRAME_4k_ONLY
+enum {
+ netdev_io_size = 128
+};
+
+#include "ipg.h"
+#define DRV_NAME "ipg"
+
+MODULE_AUTHOR("IC Plus Corp. 2003");
+MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver "
+ DrvVer);
+MODULE_LICENSE("GPL");
+
+//variable record -- index by leading revision/length
+//Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN
+static unsigned short DefaultPhyParam[] = {
+ // 11/12/03 IP1000A v1-3 rev=0x40
+ /*--------------------------------------------------------------------------
+ (0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2,
+ 27, 0x0c10, 28, 0x0c10, 29, 0x2c10, 31, 0x0003, 23, 0x92f6,
+ 31, 0x0000, 23, 0x003d, 30, 0x00de, 20, 0x20e7, 9, 0x0700,
+ --------------------------------------------------------------------------*/
+ // 12/17/03 IP1000A v1-4 rev=0x40
+ (0x4000 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
+ 0x0000,
+ 30, 0x005e, 9, 0x0700,
+ // 01/09/04 IP1000A v1-5 rev=0x41
+ (0x4100 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
+ 0x0000,
+ 30, 0x005e, 9, 0x0700,
+ 0x0000
+};
+
+static const char *ipg_brand_name[] = {
+ "IC PLUS IP1000 1000/100/10 based NIC",
+ "Sundance Technology ST2021 based NIC",
+ "Tamarack Microelectronics TC9020/9021 based NIC",
+ "Tamarack Microelectronics TC9020/9021 based NIC",
+ "D-Link NIC",
+ "D-Link NIC IP1000A"
+};
+
+static struct pci_device_id ipg_pci_tbl[] __devinitdata = {
+ { PCI_VDEVICE(SUNDANCE, 0x1023), 0 },
+ { PCI_VDEVICE(SUNDANCE, 0x2021), 1 },
+ { PCI_VDEVICE(SUNDANCE, 0x1021), 2 },
+ { PCI_VDEVICE(DLINK, 0x9021), 3 },
+ { PCI_VDEVICE(DLINK, 0x4000), 4 },
+ { PCI_VDEVICE(DLINK, 0x4020), 5 },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, ipg_pci_tbl);
+
+static inline void __iomem *ipg_ioaddr(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ return sp->ioaddr;
+}
+
+#ifdef IPG_DEBUG
+static void ipg_dump_rfdlist(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+ u32 offset;
+
+ IPG_DEBUG_MSG("_dump_rfdlist\n");
+
+ printk(KERN_INFO "rx_current = %2.2x\n", sp->rx_current);
+ printk(KERN_INFO "rx_dirty = %2.2x\n", sp->rx_dirty);
+ printk(KERN_INFO "RFDList start address = %16.16lx\n",
+ (unsigned long) sp->rxd_map);
+ printk(KERN_INFO "RFDListPtr register = %8.8x%8.8x\n",
+ ipg_r32(IPG_RFDLISTPTR1), ipg_r32(IPG_RFDLISTPTR0));
+
+ for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
+ offset = (u32) &sp->rxd[i].next_desc - (u32) sp->rxd;
+ printk(KERN_INFO "%2.2x %4.4x RFDNextPtr = %16.16lx\n", i,
+ offset, (unsigned long) sp->rxd[i].next_desc);
+ offset = (u32) &sp->rxd[i].rfs - (u32) sp->rxd;
+ printk(KERN_INFO "%2.2x %4.4x RFS = %16.16lx\n", i,
+ offset, (unsigned long) sp->rxd[i].rfs);
+ offset = (u32) &sp->rxd[i].frag_info - (u32) sp->rxd;
+ printk(KERN_INFO "%2.2x %4.4x frag_info = %16.16lx\n", i,
+ offset, (unsigned long) sp->rxd[i].frag_info);
+ }
+}
+
+static void ipg_dump_tfdlist(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+ u32 offset;
+
+ IPG_DEBUG_MSG("_dump_tfdlist\n");
+
+ printk(KERN_INFO "tx_current = %2.2x\n", sp->tx_current);
+ printk(KERN_INFO "tx_dirty = %2.2x\n", sp->tx_dirty);
+ printk(KERN_INFO "TFDList start address = %16.16lx\n",
+ (unsigned long) sp->txd_map);
+ printk(KERN_INFO "TFDListPtr register = %8.8x%8.8x\n",
+ ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0));
+
+ for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+ offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd;
+ printk(KERN_INFO "%2.2x %4.4x TFDNextPtr = %16.16lx\n", i,
+ offset, (unsigned long) sp->txd[i].next_desc);
+
+ offset = (u32) &sp->txd[i].tfc - (u32) sp->txd;
+ printk(KERN_INFO "%2.2x %4.4x TFC = %16.16lx\n", i,
+ offset, (unsigned long) sp->txd[i].tfc);
+ offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd;
+ printk(KERN_INFO "%2.2x %4.4x frag_info = %16.16lx\n", i,
+ offset, (unsigned long) sp->txd[i].frag_info);
+ }
+}
+#endif
+
+static void ipg_write_phy_ctl(void __iomem *ioaddr, u8 data)
+{
+ ipg_w8(IPG_PC_RSVD_MASK & data, PHY_CTRL);
+ ndelay(IPG_PC_PHYCTRLWAIT_NS);
+}
+
+static void ipg_drive_phy_ctl_low_high(void __iomem *ioaddr, u8 data)
+{
+ ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | data);
+ ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | data);
+}
+
+static void send_three_state(void __iomem *ioaddr, u8 phyctrlpolarity)
+{
+ phyctrlpolarity |= (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR;
+
+ ipg_drive_phy_ctl_low_high(ioaddr, phyctrlpolarity);
+}
+
+static void send_end(void __iomem *ioaddr, u8 phyctrlpolarity)
+{
+ ipg_w8((IPG_PC_MGMTCLK_LO | (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR |
+ phyctrlpolarity) & IPG_PC_RSVD_MASK, PHY_CTRL);
+}
+
+static u16 read_phy_bit(void __iomem * ioaddr, u8 phyctrlpolarity)
+{
+ u16 bit_data;
+
+ ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | phyctrlpolarity);
+
+ bit_data = ((ipg_r8(PHY_CTRL) & IPG_PC_MGMTDATA) >> 1) & 1;
+
+ ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | phyctrlpolarity);
+
+ return bit_data;
+}
+
+/*
+ * Read a register from the Physical Layer device located
+ * on the IPG NIC, using the IPG PHYCTRL register.
+ */
+static int mdio_read(struct net_device * dev, int phy_id, int phy_reg)
+{
+ void __iomem *ioaddr = ipg_ioaddr(dev);
+ /*
+ * The GMII mangement frame structure for a read is as follows:
+ *
+ * |Preamble|st|op|phyad|regad|ta| data |idle|
+ * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z |
+ *
+ * <32 1s> = 32 consecutive logic 1 values
+ * A = bit of Physical Layer device address (MSB first)
+ * R = bit of register address (MSB first)
+ * z = High impedance state
+ * D = bit of read data (MSB first)
+ *
+ * Transmission order is 'Preamble' field first, bits transmitted
+ * left to right (first to last).
+ */
+ struct {
+ u32 field;
+ unsigned int len;
+ } p[] = {
+ { GMII_PREAMBLE, 32 }, /* Preamble */
+ { GMII_ST, 2 }, /* ST */
+ { GMII_READ, 2 }, /* OP */
+ { phy_id, 5 }, /* PHYAD */
+ { phy_reg, 5 }, /* REGAD */
+ { 0x0000, 2 }, /* TA */
+ { 0x0000, 16 }, /* DATA */
+ { 0x0000, 1 } /* IDLE */
+ };
+ unsigned int i, j;
+ u8 polarity, data;
+
+ polarity = ipg_r8(PHY_CTRL);
+ polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
+
+ /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
+ for (j = 0; j < 5; j++) {
+ for (i = 0; i < p[j].len; i++) {
+ /* For each variable length field, the MSB must be
+ * transmitted first. Rotate through the field bits,
+ * starting with the MSB, and move each bit into the
+ * the 1st (2^1) bit position (this is the bit position
+ * corresponding to the MgmtData bit of the PhyCtrl
+ * register for the IPG).
+ *
+ * Example: ST = 01;
+ *
+ * First write a '0' to bit 1 of the PhyCtrl
+ * register, then write a '1' to bit 1 of the
+ * PhyCtrl register.
+ *
+ * To do this, right shift the MSB of ST by the value:
+ * [field length - 1 - #ST bits already written]
+ * then left shift this result by 1.
+ */
+ data = (p[j].field >> (p[j].len - 1 - i)) << 1;
+ data &= IPG_PC_MGMTDATA;
+ data |= polarity | IPG_PC_MGMTDIR;
+
+ ipg_drive_phy_ctl_low_high(ioaddr, data);
+ }
+ }
+
+ send_three_state(ioaddr, polarity);
+
+ read_phy_bit(ioaddr, polarity);
+
+ /*
+ * For a read cycle, the bits for the next two fields (TA and
+ * DATA) are driven by the PHY (the IPG reads these bits).
+ */
+ for (i = 0; i < p[6].len; i++) {
+ p[6].field |=
+ (read_phy_bit(ioaddr, polarity) << (p[6].len - 1 - i));
+ }
+
+ send_three_state(ioaddr, polarity);
+ send_three_state(ioaddr, polarity);
+ send_three_state(ioaddr, polarity);
+ send_end(ioaddr, polarity);
+
+ /* Return the value of the DATA field. */
+ return p[6].field;
+}
+
+/*
+ * Write to a register from the Physical Layer device located
+ * on the IPG NIC, using the IPG PHYCTRL register.
+ */
+static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val)
+{
+ void __iomem *ioaddr = ipg_ioaddr(dev);
+ /*
+ * The GMII mangement frame structure for a read is as follows:
+ *
+ * |Preamble|st|op|phyad|regad|ta| data |idle|
+ * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z |
+ *
+ * <32 1s> = 32 consecutive logic 1 values
+ * A = bit of Physical Layer device address (MSB first)
+ * R = bit of register address (MSB first)
+ * z = High impedance state
+ * D = bit of write data (MSB first)
+ *
+ * Transmission order is 'Preamble' field first, bits transmitted
+ * left to right (first to last).
+ */
+ struct {
+ u32 field;
+ unsigned int len;
+ } p[] = {
+ { GMII_PREAMBLE, 32 }, /* Preamble */
+ { GMII_ST, 2 }, /* ST */
+ { GMII_WRITE, 2 }, /* OP */
+ { phy_id, 5 }, /* PHYAD */
+ { phy_reg, 5 }, /* REGAD */
+ { 0x0002, 2 }, /* TA */
+ { val & 0xffff, 16 }, /* DATA */
+ { 0x0000, 1 } /* IDLE */
+ };
+ unsigned int i, j;
+ u8 polarity, data;
+
+ polarity = ipg_r8(PHY_CTRL);
+ polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
+
+ /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
+ for (j = 0; j < 7; j++) {
+ for (i = 0; i < p[j].len; i++) {
+ /* For each variable length field, the MSB must be
+ * transmitted first. Rotate through the field bits,
+ * starting with the MSB, and move each bit into the
+ * the 1st (2^1) bit position (this is the bit position
+ * corresponding to the MgmtData bit of the PhyCtrl
+ * register for the IPG).
+ *
+ * Example: ST = 01;
+ *
+ * First write a '0' to bit 1 of the PhyCtrl
+ * register, then write a '1' to bit 1 of the
+ * PhyCtrl register.
+ *
+ * To do this, right shift the MSB of ST by the value:
+ * [field length - 1 - #ST bits already written]
+ * then left shift this result by 1.
+ */
+ data = (p[j].field >> (p[j].len - 1 - i)) << 1;
+ data &= IPG_PC_MGMTDATA;
+ data |= polarity | IPG_PC_MGMTDIR;
+
+ ipg_drive_phy_ctl_low_high(ioaddr, data);
+ }
+ }
+
+ /* The last cycle is a tri-state, so read from the PHY. */
+ for (j = 7; j < 8; j++) {
+ for (i = 0; i < p[j].len; i++) {
+ ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | polarity);
+
+ p[j].field |= ((ipg_r8(PHY_CTRL) &
+ IPG_PC_MGMTDATA) >> 1) << (p[j].len - 1 - i);
+
+ ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | polarity);
+ }
+ }
+}
+
+/* Set LED_Mode JES20040127EEPROM */
+static void ipg_set_led_mode(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ u32 mode;
+
+ mode = ipg_r32(ASIC_CTRL);
+ mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED);
+
+ if ((sp->LED_Mode & 0x03) > 1)
+ mode |= IPG_AC_LED_MODE_BIT_1; /* Write Asic Control Bit 29 */
+
+ if ((sp->LED_Mode & 0x01) == 1)
+ mode |= IPG_AC_LED_MODE; /* Write Asic Control Bit 14 */
+
+ if ((sp->LED_Mode & 0x08) == 8)
+ mode |= IPG_AC_LED_SPEED; /* Write Asic Control Bit 27 */
+
+ ipg_w32(mode, ASIC_CTRL);
+}
+
+/* Set PHYSet JES20040127EEPROM */
+static void ipg_set_phy_set(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ int physet;
+
+ physet = ipg_r8(PHY_SET);
+ physet &= ~(IPG_PS_MEM_LENB9B | IPG_PS_MEM_LEN9 | IPG_PS_NON_COMPDET);
+ physet |= ((sp->LED_Mode & 0x70) >> 4);
+ ipg_w8(physet, PHY_SET);
+}
+
+static int ipg_reset(struct net_device *dev, u32 resetflags)
+{
+ /* Assert functional resets via the IPG AsicCtrl
+ * register as specified by the 'resetflags' input
+ * parameter.
+ */
+ void __iomem *ioaddr = ipg_ioaddr(dev); //JES20040127EEPROM:
+ unsigned int timeout_count = 0;
+
+ IPG_DEBUG_MSG("_reset\n");
+
+ ipg_w32(ipg_r32(ASIC_CTRL) | resetflags, ASIC_CTRL);
+
+ /* Delay added to account for problem with 10Mbps reset. */
+ mdelay(IPG_AC_RESETWAIT);
+
+ while (IPG_AC_RESET_BUSY & ipg_r32(ASIC_CTRL)) {
+ mdelay(IPG_AC_RESETWAIT);
+ if (++timeout_count > IPG_AC_RESET_TIMEOUT)
+ return -ETIME;
+ }
+ /* Set LED Mode in Asic Control JES20040127EEPROM */
+ ipg_set_led_mode(dev);
+
+ /* Set PHYSet Register Value JES20040127EEPROM */
+ ipg_set_phy_set(dev);
+ return 0;
+}
+
+/* Find the GMII PHY address. */
+static int ipg_find_phyaddr(struct net_device *dev)
+{
+ unsigned int phyaddr, i;
+
+ for (i = 0; i < 32; i++) {
+ u32 status;
+
+ /* Search for the correct PHY address among 32 possible. */
+ phyaddr = (IPG_NIC_PHY_ADDRESS + i) % 32;
+
+ /* 10/22/03 Grace change verify from GMII_PHY_STATUS to
+ GMII_PHY_ID1
+ */
+
+ status = mdio_read(dev, phyaddr, MII_BMSR);
+
+ if ((status != 0xFFFF) && (status != 0))
+ return phyaddr;
+ }
+
+ return 0x1f;
+}
+
+/*
+ * Configure IPG based on result of IEEE 802.3 PHY
+ * auto-negotiation.
+ */
+static int ipg_config_autoneg(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int txflowcontrol;
+ unsigned int rxflowcontrol;
+ unsigned int fullduplex;
+ unsigned int gig;
+ u32 mac_ctrl_val;
+ u32 asicctrl;
+ u8 phyctrl;
+
+ IPG_DEBUG_MSG("_config_autoneg\n");
+
+ asicctrl = ipg_r32(ASIC_CTRL);
+ phyctrl = ipg_r8(PHY_CTRL);
+ mac_ctrl_val = ipg_r32(MAC_CTRL);
+
+ /* Set flags for use in resolving auto-negotation, assuming
+ * non-1000Mbps, half duplex, no flow control.
+ */
+ fullduplex = 0;
+ txflowcontrol = 0;
+ rxflowcontrol = 0;
+ gig = 0;
+
+ /* To accomodate a problem in 10Mbps operation,
+ * set a global flag if PHY running in 10Mbps mode.
+ */
+ sp->tenmbpsmode = 0;
+
+ printk(KERN_INFO "%s: Link speed = ", dev->name);
+
+ /* Determine actual speed of operation. */
+ switch (phyctrl & IPG_PC_LINK_SPEED) {
+ case IPG_PC_LINK_SPEED_10MBPS:
+ printk("10Mbps.\n");
+ printk(KERN_INFO "%s: 10Mbps operational mode enabled.\n",
+ dev->name);
+ sp->tenmbpsmode = 1;
+ break;
+ case IPG_PC_LINK_SPEED_100MBPS:
+ printk("100Mbps.\n");
+ break;
+ case IPG_PC_LINK_SPEED_1000MBPS:
+ printk("1000Mbps.\n");
+ gig = 1;
+ break;
+ default:
+ printk("undefined!\n");
+ return 0;
+ }
+
+ if (phyctrl & IPG_PC_DUPLEX_STATUS) {
+ fullduplex = 1;
+ txflowcontrol = 1;
+ rxflowcontrol = 1;
+ }
+
+ /* Configure full duplex, and flow control. */
+ if (fullduplex == 1) {
+ /* Configure IPG for full duplex operation. */
+ printk(KERN_INFO "%s: setting full duplex, ", dev->name);
+
+ mac_ctrl_val |= IPG_MC_DUPLEX_SELECT_FD;
+
+ if (txflowcontrol == 1) {
+ printk("TX flow control");
+ mac_ctrl_val |= IPG_MC_TX_FLOW_CONTROL_ENABLE;
+ } else {
+ printk("no TX flow control");
+ mac_ctrl_val &= ~IPG_MC_TX_FLOW_CONTROL_ENABLE;
+ }
+
+ if (rxflowcontrol == 1) {
+ printk(", RX flow control.");
+ mac_ctrl_val |= IPG_MC_RX_FLOW_CONTROL_ENABLE;
+ } else {
+ printk(", no RX flow control.");
+ mac_ctrl_val &= ~IPG_MC_RX_FLOW_CONTROL_ENABLE;
+ }
+
+ printk("\n");
+ } else {
+ /* Configure IPG for half duplex operation. */
+ printk(KERN_INFO "%s: setting half duplex, "
+ "no TX flow control, no RX flow control.\n", dev->name);
+
+ mac_ctrl_val &= ~IPG_MC_DUPLEX_SELECT_FD &
+ ~IPG_MC_TX_FLOW_CONTROL_ENABLE &
+ ~IPG_MC_RX_FLOW_CONTROL_ENABLE;
+ }
+ ipg_w32(mac_ctrl_val, MAC_CTRL);
+ return 0;
+}
+
+/* Determine and configure multicast operation and set
+ * receive mode for IPG.
+ */
+static void ipg_nic_set_multicast_list(struct net_device *dev)
+{
+ void __iomem *ioaddr = ipg_ioaddr(dev);
+ struct dev_mc_list *mc_list_ptr;
+ unsigned int hashindex;
+ u32 hashtable[2];
+ u8 receivemode;
+
+ IPG_DEBUG_MSG("_nic_set_multicast_list\n");
+
+ receivemode = IPG_RM_RECEIVEUNICAST | IPG_RM_RECEIVEBROADCAST;
+
+ if (dev->flags & IFF_PROMISC) {
+ /* NIC to be configured in promiscuous mode. */
+ receivemode = IPG_RM_RECEIVEALLFRAMES;
+ } else if ((dev->flags & IFF_ALLMULTI) ||
+ (dev->flags & IFF_MULTICAST &
+ (dev->mc_count > IPG_MULTICAST_HASHTABLE_SIZE))) {
+ /* NIC to be configured to receive all multicast
+ * frames. */
+ receivemode |= IPG_RM_RECEIVEMULTICAST;
+ } else if (dev->flags & IFF_MULTICAST & (dev->mc_count > 0)) {
+ /* NIC to be configured to receive selected
+ * multicast addresses. */
+ receivemode |= IPG_RM_RECEIVEMULTICASTHASH;
+ }
+
+ /* Calculate the bits to set for the 64 bit, IPG HASHTABLE.
+ * The IPG applies a cyclic-redundancy-check (the same CRC
+ * used to calculate the frame data FCS) to the destination
+ * address all incoming multicast frames whose destination
+ * address has the multicast bit set. The least significant
+ * 6 bits of the CRC result are used as an addressing index
+ * into the hash table. If the value of the bit addressed by
+ * this index is a 1, the frame is passed to the host system.
+ */
+
+ /* Clear hashtable. */
+ hashtable[0] = 0x00000000;
+ hashtable[1] = 0x00000000;
+
+ /* Cycle through all multicast addresses to filter. */
+ for (mc_list_ptr = dev->mc_list;
+ mc_list_ptr != NULL; mc_list_ptr = mc_list_ptr->next) {
+ /* Calculate CRC result for each multicast address. */
+ hashindex = crc32_le(0xffffffff, mc_list_ptr->dmi_addr,
+ ETH_ALEN);
+
+ /* Use only the least significant 6 bits. */
+ hashindex = hashindex & 0x3F;
+
+ /* Within "hashtable", set bit number "hashindex"
+ * to a logic 1.
+ */
+ set_bit(hashindex, (void *)hashtable);
+ }
+
+ /* Write the value of the hashtable, to the 4, 16 bit
+ * HASHTABLE IPG registers.
+ */
+ ipg_w32(hashtable[0], HASHTABLE_0);
+ ipg_w32(hashtable[1], HASHTABLE_1);
+
+ ipg_w8(IPG_RM_RSVD_MASK & receivemode, RECEIVE_MODE);
+
+ IPG_DEBUG_MSG("ReceiveMode = %x\n", ipg_r8(RECEIVE_MODE));
+}
+
+static int ipg_io_config(struct net_device *dev)
+{
+ void __iomem *ioaddr = ipg_ioaddr(dev);
+ u32 origmacctrl;
+ u32 restoremacctrl;
+
+ IPG_DEBUG_MSG("_io_config\n");
+
+ origmacctrl = ipg_r32(MAC_CTRL);
+
+ restoremacctrl = origmacctrl | IPG_MC_STATISTICS_ENABLE;
+
+ /* Based on compilation option, determine if FCS is to be
+ * stripped on receive frames by IPG.
+ */
+ if (!IPG_STRIP_FCS_ON_RX)
+ restoremacctrl |= IPG_MC_RCV_FCS;
+
+ /* Determine if transmitter and/or receiver are
+ * enabled so we may restore MACCTRL correctly.
+ */
+ if (origmacctrl & IPG_MC_TX_ENABLED)
+ restoremacctrl |= IPG_MC_TX_ENABLE;
+
+ if (origmacctrl & IPG_MC_RX_ENABLED)
+ restoremacctrl |= IPG_MC_RX_ENABLE;
+
+ /* Transmitter and receiver must be disabled before setting
+ * IFSSelect.
+ */
+ ipg_w32((origmacctrl & (IPG_MC_RX_DISABLE | IPG_MC_TX_DISABLE)) &
+ IPG_MC_RSVD_MASK, MAC_CTRL);
+
+ /* Now that transmitter and receiver are disabled, write
+ * to IFSSelect.
+ */
+ ipg_w32((origmacctrl & IPG_MC_IFS_96BIT) & IPG_MC_RSVD_MASK, MAC_CTRL);
+
+ /* Set RECEIVEMODE register. */
+ ipg_nic_set_multicast_list(dev);
+
+ ipg_w16(IPG_MAX_RXFRAME_SIZE, MAX_FRAME_SIZE);
+
+ ipg_w8(IPG_RXDMAPOLLPERIOD_VALUE, RX_DMA_POLL_PERIOD);
+ ipg_w8(IPG_RXDMAURGENTTHRESH_VALUE, RX_DMA_URGENT_THRESH);
+ ipg_w8(IPG_RXDMABURSTTHRESH_VALUE, RX_DMA_BURST_THRESH);
+ ipg_w8(IPG_TXDMAPOLLPERIOD_VALUE, TX_DMA_POLL_PERIOD);
+ ipg_w8(IPG_TXDMAURGENTTHRESH_VALUE, TX_DMA_URGENT_THRESH);
+ ipg_w8(IPG_TXDMABURSTTHRESH_VALUE, TX_DMA_BURST_THRESH);
+ ipg_w16((IPG_IE_HOST_ERROR | IPG_IE_TX_DMA_COMPLETE |
+ IPG_IE_TX_COMPLETE | IPG_IE_INT_REQUESTED |
+ IPG_IE_UPDATE_STATS | IPG_IE_LINK_EVENT |
+ IPG_IE_RX_DMA_COMPLETE | IPG_IE_RX_DMA_PRIORITY), INT_ENABLE);
+ ipg_w16(IPG_FLOWONTHRESH_VALUE, FLOW_ON_THRESH);
+ ipg_w16(IPG_FLOWOFFTHRESH_VALUE, FLOW_OFF_THRESH);
+
+ /* IPG multi-frag frame bug workaround.
+ * Per silicon revision B3 eratta.
+ */
+ ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0200, DEBUG_CTRL);
+
+ /* IPG TX poll now bug workaround.
+ * Per silicon revision B3 eratta.
+ */
+ ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0010, DEBUG_CTRL);
+
+ /* IPG RX poll now bug workaround.
+ * Per silicon revision B3 eratta.
+ */
+ ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0020, DEBUG_CTRL);
+
+ /* Now restore MACCTRL to original setting. */
+ ipg_w32(IPG_MC_RSVD_MASK & restoremacctrl, MAC_CTRL);
+
+ /* Disable unused RMON statistics. */
+ ipg_w32(IPG_RZ_ALL, RMON_STATISTICS_MASK);
+
+ /* Disable unused MIB statistics. */
+ ipg_w32(IPG_SM_MACCONTROLFRAMESXMTD | IPG_SM_MACCONTROLFRAMESRCVD |
+ IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK | IPG_SM_TXJUMBOFRAMES |
+ IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK | IPG_SM_RXJUMBOFRAMES |
+ IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK |
+ IPG_SM_UDPCHECKSUMERRORS | IPG_SM_TCPCHECKSUMERRORS |
+ IPG_SM_IPCHECKSUMERRORS, STATISTICS_MASK);
+
+ return 0;
+}
+
+/*
+ * Create a receive buffer within system memory and update
+ * NIC private structure appropriately.
+ */
+static int ipg_get_rxbuff(struct net_device *dev, int entry)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ struct ipg_rx *rxfd = sp->rxd + entry;
+ struct sk_buff *skb;
+ u64 rxfragsize;
+
+ IPG_DEBUG_MSG("_get_rxbuff\n");
+
+ skb = netdev_alloc_skb(dev, IPG_RXSUPPORT_SIZE + NET_IP_ALIGN);
+ if (!skb) {
+ sp->RxBuff[entry] = NULL;
+ return -ENOMEM;
+ }
+
+ /* Adjust the data start location within the buffer to
+ * align IP address field to a 16 byte boundary.
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ /* Associate the receive buffer with the IPG NIC. */
+ skb->dev = dev;
+
+ /* Save the address of the sk_buff structure. */
+ sp->RxBuff[entry] = skb;
+
+ rxfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+
+ /* Set the RFD fragment length. */
+ rxfragsize = IPG_RXFRAG_SIZE;
+ rxfd->frag_info |= cpu_to_le64((rxfragsize << 48) & IPG_RFI_FRAGLEN);
+
+ return 0;
+}
+
+static int init_rfdlist(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+
+ IPG_DEBUG_MSG("_init_rfdlist\n");
+
+ for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
+ struct ipg_rx *rxfd = sp->rxd + i;
+
+ if (sp->RxBuff[i]) {
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
+ sp->RxBuff[i] = NULL;
+ }
+
+ /* Clear out the RFS field. */
+ rxfd->rfs = 0x0000000000000000;
+
+ if (ipg_get_rxbuff(dev, i) < 0) {
+ /*
+ * A receive buffer was not ready, break the
+ * RFD list here.
+ */
+ IPG_DEBUG_MSG("Cannot allocate Rx buffer.\n");
+
+ /* Just in case we cannot allocate a single RFD.
+ * Should not occur.
+ */
+ if (i == 0) {
+ printk(KERN_ERR "%s: No memory available"
+ " for RFD list.\n", dev->name);
+ return -ENOMEM;
+ }
+ }
+
+ rxfd->next_desc = cpu_to_le64(sp->rxd_map +
+ sizeof(struct ipg_rx)*(i + 1));
+ }
+ sp->rxd[i - 1].next_desc = cpu_to_le64(sp->rxd_map);
+
+ sp->rx_current = 0;
+ sp->rx_dirty = 0;
+
+ /* Write the location of the RFDList to the IPG. */
+ ipg_w32((u32) sp->rxd_map, RFD_LIST_PTR_0);
+ ipg_w32(0x00000000, RFD_LIST_PTR_1);
+
+ return 0;
+}
+
+static void init_tfdlist(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+
+ IPG_DEBUG_MSG("_init_tfdlist\n");
+
+ for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+ struct ipg_tx *txfd = sp->txd + i;
+
+ txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
+
+ if (sp->TxBuff[i]) {
+ IPG_DEV_KFREE_SKB(sp->TxBuff[i]);
+ sp->TxBuff[i] = NULL;
+ }
+
+ txfd->next_desc = cpu_to_le64(sp->txd_map +
+ sizeof(struct ipg_tx)*(i + 1));
+ }
+ sp->txd[i - 1].next_desc = cpu_to_le64(sp->txd_map);
+
+ sp->tx_current = 0;
+ sp->tx_dirty = 0;
+
+ /* Write the location of the TFDList to the IPG. */
+ IPG_DDEBUG_MSG("Starting TFDListPtr = %8.8x\n",
+ (u32) sp->txd_map);
+ ipg_w32((u32) sp->txd_map, TFD_LIST_PTR_0);
+ ipg_w32(0x00000000, TFD_LIST_PTR_1);
+
+ sp->ResetCurrentTFD = 1;
+}
+
+/*
+ * Free all transmit buffers which have already been transfered
+ * via DMA to the IPG.
+ */
+static void ipg_nic_txfree(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int curr;
+ u64 txd_map;
+ unsigned int released, pending;
+
+ txd_map = (u64)sp->txd_map;
+ curr = ipg_r32(TFD_LIST_PTR_0) -
+ do_div(txd_map, sizeof(struct ipg_tx)) - 1;
+
+ IPG_DEBUG_MSG("_nic_txfree\n");
+
+ pending = sp->tx_current - sp->tx_dirty;
+
+ for (released = 0; released < pending; released++) {
+ unsigned int dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH;
+ struct sk_buff *skb = sp->TxBuff[dirty];
+ struct ipg_tx *txfd = sp->txd + dirty;
+
+ IPG_DEBUG_MSG("TFC = %16.16lx\n", (unsigned long) txfd->tfc);
+
+ /* Look at each TFD's TFC field beginning
+ * at the last freed TFD up to the current TFD.
+ * If the TFDDone bit is set, free the associated
+ * buffer.
+ */
+ if (dirty == curr)
+ break;
+
+ /* Setup TFDDONE for compatible issue. */
+ txfd->tfc |= cpu_to_le64(IPG_TFC_TFDDONE);
+
+ /* Free the transmit buffer. */
+ if (skb) {
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN,
+ skb->len, PCI_DMA_TODEVICE);
+
+ IPG_DEV_KFREE_SKB(skb);
+
+ sp->TxBuff[dirty] = NULL;
+ }
+ }
+
+ sp->tx_dirty += released;
+
+ if (netif_queue_stopped(dev) &&
+ (sp->tx_current != (sp->tx_dirty + IPG_TFDLIST_LENGTH))) {
+ netif_wake_queue(dev);
+ }
+}
+
+static void ipg_tx_timeout(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+
+ ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | IPG_AC_NETWORK |
+ IPG_AC_FIFO);
+
+ spin_lock_irq(&sp->lock);
+
+ /* Re-configure after DMA reset. */
+ if (ipg_io_config(dev) < 0) {
+ printk(KERN_INFO "%s: Error during re-configuration.\n",
+ dev->name);
+ }
+
+ init_tfdlist(dev);
+
+ spin_unlock_irq(&sp->lock);
+
+ ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK,
+ MAC_CTRL);
+}
+
+/*
+ * For TxComplete interrupts, free all transmit
+ * buffers which have already been transfered via DMA
+ * to the IPG.
+ */
+static void ipg_nic_txcleanup(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+
+ IPG_DEBUG_MSG("_nic_txcleanup\n");
+
+ for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+ /* Reading the TXSTATUS register clears the
+ * TX_COMPLETE interrupt.
+ */
+ u32 txstatusdword = ipg_r32(TX_STATUS);
+
+ IPG_DEBUG_MSG("TxStatus = %8.8x\n", txstatusdword);
+
+ /* Check for Transmit errors. Error bits only valid if
+ * TX_COMPLETE bit in the TXSTATUS register is a 1.
+ */
+ if (!(txstatusdword & IPG_TS_TX_COMPLETE))
+ break;
+
+ /* If in 10Mbps mode, indicate transmit is ready. */
+ if (sp->tenmbpsmode) {
+ netif_wake_queue(dev);
+ }
+
+ /* Transmit error, increment stat counters. */
+ if (txstatusdword & IPG_TS_TX_ERROR) {
+ IPG_DEBUG_MSG("Transmit error.\n");
+ sp->stats.tx_errors++;
+ }
+
+ /* Late collision, re-enable transmitter. */
+ if (txstatusdword & IPG_TS_LATE_COLLISION) {
+ IPG_DEBUG_MSG("Late collision on transmit.\n");
+ ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
+ IPG_MC_RSVD_MASK, MAC_CTRL);
+ }
+
+ /* Maximum collisions, re-enable transmitter. */
+ if (txstatusdword & IPG_TS_TX_MAX_COLL) {
+ IPG_DEBUG_MSG("Maximum collisions on transmit.\n");
+ ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
+ IPG_MC_RSVD_MASK, MAC_CTRL);
+ }
+
+ /* Transmit underrun, reset and re-enable
+ * transmitter.
+ */
+ if (txstatusdword & IPG_TS_TX_UNDERRUN) {
+ IPG_DEBUG_MSG("Transmitter underrun.\n");
+ sp->stats.tx_fifo_errors++;
+ ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA |
+ IPG_AC_NETWORK | IPG_AC_FIFO);
+
+ /* Re-configure after DMA reset. */
+ if (ipg_io_config(dev) < 0) {
+ printk(KERN_INFO
+ "%s: Error during re-configuration.\n",
+ dev->name);
+ }
+ init_tfdlist(dev);
+
+ ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
+ IPG_MC_RSVD_MASK, MAC_CTRL);
+ }
+ }
+
+ ipg_nic_txfree(dev);
+}
+
+/* Provides statistical information about the IPG NIC. */
+static struct net_device_stats *ipg_nic_get_stats(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ u16 temp1;
+ u16 temp2;
+
+ IPG_DEBUG_MSG("_nic_get_stats\n");
+
+ /* Check to see if the NIC has been initialized via nic_open,
+ * before trying to read statistic registers.
+ */
+ if (!test_bit(__LINK_STATE_START, &dev->state))
+ return &sp->stats;
+
+ sp->stats.rx_packets += ipg_r32(IPG_FRAMESRCVDOK);
+ sp->stats.tx_packets += ipg_r32(IPG_FRAMESXMTDOK);
+ sp->stats.rx_bytes += ipg_r32(IPG_OCTETRCVOK);
+ sp->stats.tx_bytes += ipg_r32(IPG_OCTETXMTOK);
+ temp1 = ipg_r16(IPG_FRAMESLOSTRXERRORS);
+ sp->stats.rx_errors += temp1;
+ sp->stats.rx_missed_errors += temp1;
+ temp1 = ipg_r32(IPG_SINGLECOLFRAMES) + ipg_r32(IPG_MULTICOLFRAMES) +
+ ipg_r32(IPG_LATECOLLISIONS);
+ temp2 = ipg_r16(IPG_CARRIERSENSEERRORS);
+ sp->stats.collisions += temp1;
+ sp->stats.tx_dropped += ipg_r16(IPG_FRAMESABORTXSCOLLS);
+ sp->stats.tx_errors += ipg_r16(IPG_FRAMESWEXDEFERRAL) +
+ ipg_r32(IPG_FRAMESWDEFERREDXMT) + temp1 + temp2;
+ sp->stats.multicast += ipg_r32(IPG_MCSTOCTETRCVDOK);
+
+ /* detailed tx_errors */
+ sp->stats.tx_carrier_errors += temp2;
+
+ /* detailed rx_errors */
+ sp->stats.rx_length_errors += ipg_r16(IPG_INRANGELENGTHERRORS) +
+ ipg_r16(IPG_FRAMETOOLONGERRRORS);
+ sp->stats.rx_crc_errors += ipg_r16(IPG_FRAMECHECKSEQERRORS);
+
+ /* Unutilized IPG statistic registers. */
+ ipg_r32(IPG_MCSTFRAMESRCVDOK);
+
+ return &sp->stats;
+}
+
+/* Restore used receive buffers. */
+static int ipg_nic_rxrestore(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ const unsigned int curr = sp->rx_current;
+ unsigned int dirty = sp->rx_dirty;
+
+ IPG_DEBUG_MSG("_nic_rxrestore\n");
+
+ for (dirty = sp->rx_dirty; curr - dirty > 0; dirty++) {
+ unsigned int entry = dirty % IPG_RFDLIST_LENGTH;
+
+ /* rx_copybreak may poke hole here and there. */
+ if (sp->RxBuff[entry])
+ continue;
+
+ /* Generate a new receive buffer to replace the
+ * current buffer (which will be released by the
+ * Linux system).
+ */
+ if (ipg_get_rxbuff(dev, entry) < 0) {
+ IPG_DEBUG_MSG("Cannot allocate new Rx buffer.\n");
+
+ break;
+ }
+
+ /* Reset the RFS field. */
+ sp->rxd[entry].rfs = 0x0000000000000000;
+ }
+ sp->rx_dirty = dirty;
+
+ return 0;
+}
+
+#ifdef JUMBO_FRAME
+
+/* use jumboindex and jumbosize to control jumbo frame status
+ initial status is jumboindex=-1 and jumbosize=0
+ 1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done.
+ 2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving
+ 3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump
+ previous receiving and need to continue dumping the current one
+*/
+enum {
+ NormalPacket,
+ ErrorPacket
+};
+
+enum {
+ Frame_NoStart_NoEnd = 0,
+ Frame_WithStart = 1,
+ Frame_WithEnd = 10,
+ Frame_WithStart_WithEnd = 11
+};
+
+inline void ipg_nic_rx_free_skb(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH;
+
+ if (sp->RxBuff[entry]) {
+ struct ipg_rx *rxfd = sp->rxd + entry;
+
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
+ sp->RxBuff[entry] = NULL;
+ }
+}
+
+inline int ipg_nic_rx_check_frame_type(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH);
+ int type = Frame_NoStart_NoEnd;
+
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART)
+ type += Frame_WithStart;
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND)
+ type += Frame_WithEnd;
+ return type;
+}
+
+inline int ipg_nic_rx_check_error(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH;
+ struct ipg_rx *rxfd = sp->rxd + entry;
+
+ if (IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) &
+ (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
+ IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
+ IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))) {
+ IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n",
+ (unsigned long) rxfd->rfs);
+
+ /* Increment general receive error statistic. */
+ sp->stats.rx_errors++;
+
+ /* Increment detailed receive error statistics. */
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) {
+ IPG_DEBUG_MSG("RX FIFO overrun occured.\n");
+
+ sp->stats.rx_fifo_errors++;
+ }
+
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) {
+ IPG_DEBUG_MSG("RX runt occured.\n");
+ sp->stats.rx_length_errors++;
+ }
+
+ /* Do nothing for IPG_RFS_RXOVERSIZEDFRAME,
+ * error count handled by a IPG statistic register.
+ */
+
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) {
+ IPG_DEBUG_MSG("RX alignment error occured.\n");
+ sp->stats.rx_frame_errors++;
+ }
+
+ /* Do nothing for IPG_RFS_RXFCSERROR, error count
+ * handled by a IPG statistic register.
+ */
+
+ /* Free the memory associated with the RX
+ * buffer since it is erroneous and we will
+ * not pass it to higher layer processes.
+ */
+ if (sp->RxBuff[entry]) {
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+ IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
+ sp->RxBuff[entry] = NULL;
+ }
+ return ErrorPacket;
+ }
+ return NormalPacket;
+}
+
+static void ipg_nic_rx_with_start_and_end(struct net_device *dev,
+ struct ipg_nic_private *sp,
+ struct ipg_rx *rxfd, unsigned entry)
+{
+ struct SJumbo *jumbo = &sp->Jumbo;
+ struct sk_buff *skb;
+ int framelen;
+
+ if (jumbo->FoundStart) {
+ IPG_DEV_KFREE_SKB(jumbo->skb);
+ jumbo->FoundStart = 0;
+ jumbo->CurrentSize = 0;
+ jumbo->skb = NULL;
+ }
+
+ // 1: found error, 0 no error
+ if (ipg_nic_rx_check_error(dev) != NormalPacket)
+ return;
+
+ skb = sp->RxBuff[entry];
+ if (!skb)
+ return;
+
+ // accept this frame and send to upper layer
+ framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
+ if (framelen > IPG_RXFRAG_SIZE)
+ framelen = IPG_RXFRAG_SIZE;
+
+ skb_put(skb, framelen);
+ skb->protocol = eth_type_trans(skb, dev);
+ skb->ip_summed = CHECKSUM_NONE;
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ sp->RxBuff[entry] = NULL;
+}
+
+static void ipg_nic_rx_with_start(struct net_device *dev,
+ struct ipg_nic_private *sp,
+ struct ipg_rx *rxfd, unsigned entry)
+{
+ struct SJumbo *jumbo = &sp->Jumbo;
+ struct pci_dev *pdev = sp->pdev;
+ struct sk_buff *skb;
+
+ // 1: found error, 0 no error
+ if (ipg_nic_rx_check_error(dev) != NormalPacket)
+ return;
+
+ // accept this frame and send to upper layer
+ skb = sp->RxBuff[entry];
+ if (!skb)
+ return;
+
+ if (jumbo->FoundStart)
+ IPG_DEV_KFREE_SKB(jumbo->skb);
+
+ pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+ skb_put(skb, IPG_RXFRAG_SIZE);
+
+ jumbo->FoundStart = 1;
+ jumbo->CurrentSize = IPG_RXFRAG_SIZE;
+ jumbo->skb = skb;
+
+ sp->RxBuff[entry] = NULL;
+ dev->last_rx = jiffies;
+}
+
+static void ipg_nic_rx_with_end(struct net_device *dev,
+ struct ipg_nic_private *sp,
+ struct ipg_rx *rxfd, unsigned entry)
+{
+ struct SJumbo *jumbo = &sp->Jumbo;
+
+ //1: found error, 0 no error
+ if (ipg_nic_rx_check_error(dev) == NormalPacket) {
+ struct sk_buff *skb = sp->RxBuff[entry];
+
+ if (!skb)
+ return;
+
+ if (jumbo->FoundStart) {
+ int framelen, endframelen;
+
+ framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
+
+ endframeLen = framelen - jumbo->CurrentSize;
+ /*
+ if (framelen > IPG_RXFRAG_SIZE)
+ framelen=IPG_RXFRAG_SIZE;
+ */
+ if (framelen > IPG_RXSUPPORT_SIZE)
+ IPG_DEV_KFREE_SKB(jumbo->skb);
+ else {
+ memcpy(skb_put(jumbo->skb, endframeLen),
+ skb->data, endframeLen);
+
+ jumbo->skb->protocol =
+ eth_type_trans(jumbo->skb, dev);
+
+ jumbo->skb->ip_summed = CHECKSUM_NONE;
+ netif_rx(jumbo->skb);
+ }
+ }
+
+ dev->last_rx = jiffies;
+ jumbo->FoundStart = 0;
+ jumbo->CurrentSize = 0;
+ jumbo->skb = NULL;
+
+ ipg_nic_rx_free_skb(dev);
+ } else {
+ IPG_DEV_KFREE_SKB(jumbo->skb);
+ jumbo->FoundStart = 0;
+ jumbo->CurrentSize = 0;
+ jumbo->skb = NULL;
+ }
+}
+
+static void ipg_nic_rx_no_start_no_end(struct net_device *dev,
+ struct ipg_nic_private *sp,
+ struct ipg_rx *rxfd, unsigned entry)
+{
+ struct SJumbo *jumbo = &sp->Jumbo;
+
+ //1: found error, 0 no error
+ if (ipg_nic_rx_check_error(dev) == NormalPacket) {
+ struct sk_buff *skb = sp->RxBuff[entry];
+
+ if (skb) {
+ if (jumbo->FoundStart) {
+ jumbo->CurrentSize += IPG_RXFRAG_SIZE;
+ if (jumbo->CurrentSize <= IPG_RXSUPPORT_SIZE) {
+ memcpy(skb_put(jumbo->skb,
+ IPG_RXFRAG_SIZE),
+ skb->data, IPG_RXFRAG_SIZE);
+ }
+ }
+ dev->last_rx = jiffies;
+ ipg_nic_rx_free_skb(dev);
+ }
+ } else {
+ IPG_DEV_KFREE_SKB(jumbo->skb);
+ jumbo->FoundStart = 0;
+ jumbo->CurrentSize = 0;
+ jumbo->skb = NULL;
+ }
+}
+
+static int ipg_nic_rx(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ unsigned int curr = sp->rx_current;
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+
+ IPG_DEBUG_MSG("_nic_rx\n");
+
+ for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) {
+ unsigned int entry = curr % IPG_RFDLIST_LENGTH;
+ struct ipg_rx *rxfd = sp->rxd + entry;
+
+ if (!(rxfd->rfs & le64_to_cpu(IPG_RFS_RFDDONE)))
+ break;
+
+ switch (ipg_nic_rx_check_frame_type(dev)) {
+ case Frame_WithStart_WithEnd:
+ ipg_nic_rx_with_start_and_end(dev, tp, rxfd, entry);
+ break;
+ case Frame_WithStart:
+ ipg_nic_rx_with_start(dev, tp, rxfd, entry);
+ break;
+ case Frame_WithEnd:
+ ipg_nic_rx_with_end(dev, tp, rxfd, entry);
+ break;
+ case Frame_NoStart_NoEnd:
+ ipg_nic_rx_no_start_no_end(dev, tp, rxfd, entry);
+ break;
+ }
+ }
+
+ sp->rx_current = curr;
+
+ if (i == IPG_MAXRFDPROCESS_COUNT) {
+ /* There are more RFDs to process, however the
+ * allocated amount of RFD processing time has
+ * expired. Assert Interrupt Requested to make
+ * sure we come back to process the remaining RFDs.
+ */
+ ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL);
+ }
+
+ ipg_nic_rxrestore(dev);
+
+ return 0;
+}
+
+#else
+static int ipg_nic_rx(struct net_device *dev)
+{
+ /* Transfer received Ethernet frames to higher network layers. */
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ unsigned int curr = sp->rx_current;
+ void __iomem *ioaddr = sp->ioaddr;
+ struct ipg_rx *rxfd;
+ unsigned int i;
+
+ IPG_DEBUG_MSG("_nic_rx\n");
+
+#define __RFS_MASK \
+ cpu_to_le64(IPG_RFS_RFDDONE | IPG_RFS_FRAMESTART | IPG_RFS_FRAMEEND)
+
+ for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) {
+ unsigned int entry = curr % IPG_RFDLIST_LENGTH;
+ struct sk_buff *skb = sp->RxBuff[entry];
+ unsigned int framelen;
+
+ rxfd = sp->rxd + entry;
+
+ if (((rxfd->rfs & __RFS_MASK) != __RFS_MASK) || !skb)
+ break;
+
+ /* Get received frame length. */
+ framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
+
+ /* Check for jumbo frame arrival with too small
+ * RXFRAG_SIZE.
+ */
+ if (framelen > IPG_RXFRAG_SIZE) {
+ IPG_DEBUG_MSG
+ ("RFS FrameLen > allocated fragment size.\n");
+
+ framelen = IPG_RXFRAG_SIZE;
+ }
+
+ if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) &
+ (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
+ IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
+ IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR)))) {
+
+ IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n",
+ (unsigned long int) rxfd->rfs);
+
+ /* Increment general receive error statistic. */
+ sp->stats.rx_errors++;
+
+ /* Increment detailed receive error statistics. */
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) {
+ IPG_DEBUG_MSG("RX FIFO overrun occured.\n");
+ sp->stats.rx_fifo_errors++;
+ }
+
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) {
+ IPG_DEBUG_MSG("RX runt occured.\n");
+ sp->stats.rx_length_errors++;
+ }
+
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXOVERSIZEDFRAME) ;
+ /* Do nothing, error count handled by a IPG
+ * statistic register.
+ */
+
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) {
+ IPG_DEBUG_MSG("RX alignment error occured.\n");
+ sp->stats.rx_frame_errors++;
+ }
+
+ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFCSERROR) ;
+ /* Do nothing, error count handled by a IPG
+ * statistic register.
+ */
+
+ /* Free the memory associated with the RX
+ * buffer since it is erroneous and we will
+ * not pass it to higher layer processes.
+ */
+ if (skb) {
+ __le64 info = rxfd->frag_info;
+
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(info) & ~IPG_RFI_FRAGLEN,
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+ IPG_DEV_KFREE_SKB(skb);
+ }
+ } else {
+
+ /* Adjust the new buffer length to accomodate the size
+ * of the received frame.
+ */
+ skb_put(skb, framelen);
+
+ /* Set the buffer's protocol field to Ethernet. */
+ skb->protocol = eth_type_trans(skb, dev);
+
+ /* If the frame contains an IP/TCP/UDP frame,
+ * determine if upper layer must check IP/TCP/UDP
+ * checksums.
+ *
+ * NOTE: DO NOT RELY ON THE TCP/UDP CHECKSUM
+ * VERIFICATION FOR SILICON REVISIONS B3
+ * AND EARLIER!
+ *
+ if ((le64_to_cpu(rxfd->rfs &
+ (IPG_RFS_TCPDETECTED | IPG_RFS_UDPDETECTED |
+ IPG_RFS_IPDETECTED))) &&
+ !(le64_to_cpu(rxfd->rfs &
+ (IPG_RFS_TCPERROR | IPG_RFS_UDPERROR |
+ IPG_RFS_IPERROR)))) {
+ * Indicate IP checksums were performed
+ * by the IPG.
+ *
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else
+ */
+ {
+ /* The IPG encountered an error with (or
+ * there were no) IP/TCP/UDP checksums.
+ * This may or may not indicate an invalid
+ * IP/TCP/UDP frame was received. Let the
+ * upper layer decide.
+ */
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+
+ /* Hand off frame for higher layer processing.
+ * The function netif_rx() releases the sk_buff
+ * when processing completes.
+ */
+ netif_rx(skb);
+
+ /* Record frame receive time (jiffies = Linux
+ * kernel current time stamp).
+ */
+ dev->last_rx = jiffies;
+ }
+
+ /* Assure RX buffer is not reused by IPG. */
+ sp->RxBuff[entry] = NULL;
+ }
+
+ /*
+ * If there are more RFDs to proces and the allocated amount of RFD
+ * processing time has expired, assert Interrupt Requested to make
+ * sure we come back to process the remaining RFDs.
+ */
+ if (i == IPG_MAXRFDPROCESS_COUNT)
+ ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL);
+
+#ifdef IPG_DEBUG
+ /* Check if the RFD list contained no receive frame data. */
+ if (!i)
+ sp->EmptyRFDListCount++;
+#endif
+ while ((le64_to_cpu(rxfd->rfs) & IPG_RFS_RFDDONE) &&
+ !((le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) &&
+ (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND))) {
+ unsigned int entry = curr++ % IPG_RFDLIST_LENGTH;
+
+ rxfd = sp->rxd + entry;
+
+ IPG_DEBUG_MSG("Frame requires multiple RFDs.\n");
+
+ /* An unexpected event, additional code needed to handle
+ * properly. So for the time being, just disregard the
+ * frame.
+ */
+
+ /* Free the memory associated with the RX
+ * buffer since it is erroneous and we will
+ * not pass it to higher layer processes.
+ */
+ if (sp->RxBuff[entry]) {
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
+ }
+
+ /* Assure RX buffer is not reused by IPG. */
+ sp->RxBuff[entry] = NULL;
+ }
+
+ sp->rx_current = curr;
+
+ /* Check to see if there are a minimum number of used
+ * RFDs before restoring any (should improve performance.)
+ */
+ if ((curr - sp->rx_dirty) >= IPG_MINUSEDRFDSTOFREE)
+ ipg_nic_rxrestore(dev);
+
+ return 0;
+}
+#endif
+
+static void ipg_reset_after_host_error(struct work_struct *work)
+{
+ struct ipg_nic_private *sp =
+ container_of(work, struct ipg_nic_private, task.work);
+ struct net_device *dev = sp->dev;
+
+ IPG_DDEBUG_MSG("DMACtrl = %8.8x\n", ioread32(sp->ioaddr + IPG_DMACTRL));
+
+ /*
+ * Acknowledge HostError interrupt by resetting
+ * IPG DMA and HOST.
+ */
+ ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA);
+
+ init_rfdlist(dev);
+ init_tfdlist(dev);
+
+ if (ipg_io_config(dev) < 0) {
+ printk(KERN_INFO "%s: Cannot recover from PCI error.\n",
+ dev->name);
+ schedule_delayed_work(&sp->task, HZ);
+ }
+}
+
+static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst)
+{
+ struct net_device *dev = dev_inst;
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int handled = 0;
+ u16 status;
+
+ IPG_DEBUG_MSG("_interrupt_handler\n");
+
+#ifdef JUMBO_FRAME
+ ipg_nic_rxrestore(dev);
+#endif
+ /* Get interrupt source information, and acknowledge
+ * some (i.e. TxDMAComplete, RxDMAComplete, RxEarly,
+ * IntRequested, MacControlFrame, LinkEvent) interrupts
+ * if issued. Also, all IPG interrupts are disabled by
+ * reading IntStatusAck.
+ */
+ status = ipg_r16(INT_STATUS_ACK);
+
+ IPG_DEBUG_MSG("IntStatusAck = %4.4x\n", status);
+
+ /* Shared IRQ of remove event. */
+ if (!(status & IPG_IS_RSVD_MASK))
+ goto out_enable;
+
+ handled = 1;
+
+ if (unlikely(!netif_running(dev)))
+ goto out;
+
+ spin_lock(&sp->lock);
+
+ /* If RFDListEnd interrupt, restore all used RFDs. */
+ if (status & IPG_IS_RFD_LIST_END) {
+ IPG_DEBUG_MSG("RFDListEnd Interrupt.\n");
+
+ /* The RFD list end indicates an RFD was encountered
+ * with a 0 NextPtr, or with an RFDDone bit set to 1
+ * (indicating the RFD is not read for use by the
+ * IPG.) Try to restore all RFDs.
+ */
+ ipg_nic_rxrestore(dev);
+
+#ifdef IPG_DEBUG
+ /* Increment the RFDlistendCount counter. */
+ sp->RFDlistendCount++;
+#endif
+ }
+
+ /* If RFDListEnd, RxDMAPriority, RxDMAComplete, or
+ * IntRequested interrupt, process received frames. */
+ if ((status & IPG_IS_RX_DMA_PRIORITY) ||
+ (status & IPG_IS_RFD_LIST_END) ||
+ (status & IPG_IS_RX_DMA_COMPLETE) ||
+ (status & IPG_IS_INT_REQUESTED)) {
+#ifdef IPG_DEBUG
+ /* Increment the RFD list checked counter if interrupted
+ * only to check the RFD list. */
+ if (status & (~(IPG_IS_RX_DMA_PRIORITY | IPG_IS_RFD_LIST_END |
+ IPG_IS_RX_DMA_COMPLETE | IPG_IS_INT_REQUESTED) &
+ (IPG_IS_HOST_ERROR | IPG_IS_TX_DMA_COMPLETE |
+ IPG_IS_LINK_EVENT | IPG_IS_TX_COMPLETE |
+ IPG_IS_UPDATE_STATS)))
+ sp->RFDListCheckedCount++;
+#endif
+
+ ipg_nic_rx(dev);
+ }
+
+ /* If TxDMAComplete interrupt, free used TFDs. */
+ if (status & IPG_IS_TX_DMA_COMPLETE)
+ ipg_nic_txfree(dev);
+
+ /* TxComplete interrupts indicate one of numerous actions.
+ * Determine what action to take based on TXSTATUS register.
+ */
+ if (status & IPG_IS_TX_COMPLETE)
+ ipg_nic_txcleanup(dev);
+
+ /* If UpdateStats interrupt, update Linux Ethernet statistics */
+ if (status & IPG_IS_UPDATE_STATS)
+ ipg_nic_get_stats(dev);
+
+ /* If HostError interrupt, reset IPG. */
+ if (status & IPG_IS_HOST_ERROR) {
+ IPG_DDEBUG_MSG("HostError Interrupt\n");
+
+ schedule_delayed_work(&sp->task, 0);
+ }
+
+ /* If LinkEvent interrupt, resolve autonegotiation. */
+ if (status & IPG_IS_LINK_EVENT) {
+ if (ipg_config_autoneg(dev) < 0)
+ printk(KERN_INFO "%s: Auto-negotiation error.\n",
+ dev->name);
+ }
+
+ /* If MACCtrlFrame interrupt, do nothing. */
+ if (status & IPG_IS_MAC_CTRL_FRAME)
+ IPG_DEBUG_MSG("MACCtrlFrame interrupt.\n");
+
+ /* If RxComplete interrupt, do nothing. */
+ if (status & IPG_IS_RX_COMPLETE)
+ IPG_DEBUG_MSG("RxComplete interrupt.\n");
+
+ /* If RxEarly interrupt, do nothing. */
+ if (status & IPG_IS_RX_EARLY)
+ IPG_DEBUG_MSG("RxEarly interrupt.\n");
+
+out_enable:
+ /* Re-enable IPG interrupts. */
+ ipg_w16(IPG_IE_TX_DMA_COMPLETE | IPG_IE_RX_DMA_COMPLETE |
+ IPG_IE_HOST_ERROR | IPG_IE_INT_REQUESTED | IPG_IE_TX_COMPLETE |
+ IPG_IE_LINK_EVENT | IPG_IE_UPDATE_STATS, INT_ENABLE);
+
+ spin_unlock(&sp->lock);
+out:
+ return IRQ_RETVAL(handled);
+}
+
+static void ipg_rx_clear(struct ipg_nic_private *sp)
+{
+ unsigned int i;
+
+ for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
+ if (sp->RxBuff[i]) {
+ struct ipg_rx *rxfd = sp->rxd + i;
+
+ IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
+ sp->RxBuff[i] = NULL;
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
+ sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ }
+ }
+}
+
+static void ipg_tx_clear(struct ipg_nic_private *sp)
+{
+ unsigned int i;
+
+ for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+ if (sp->TxBuff[i]) {
+ struct ipg_tx *txfd = sp->txd + i;
+
+ pci_unmap_single(sp->pdev,
+ le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN,
+ sp->TxBuff[i]->len, PCI_DMA_TODEVICE);
+
+ IPG_DEV_KFREE_SKB(sp->TxBuff[i]);
+
+ sp->TxBuff[i] = NULL;
+ }
+ }
+}
+
+static int ipg_nic_open(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ struct pci_dev *pdev = sp->pdev;
+ int rc;
+
+ IPG_DEBUG_MSG("_nic_open\n");
+
+ sp->rx_buf_sz = IPG_RXSUPPORT_SIZE;
+
+ /* Check for interrupt line conflicts, and request interrupt
+ * line for IPG.
+ *
+ * IMPORTANT: Disable IPG interrupts prior to registering
+ * IRQ.
+ */
+ ipg_w16(0x0000, INT_ENABLE);
+
+ /* Register the interrupt line to be used by the IPG within
+ * the Linux system.
+ */
+ rc = request_irq(pdev->irq, &ipg_interrupt_handler, IRQF_SHARED,
+ dev->name, dev);
+ if (rc < 0) {
+ printk(KERN_INFO "%s: Error when requesting interrupt.\n",
+ dev->name);
+ goto out;
+ }
+
+ dev->irq = pdev->irq;
+
+ rc = -ENOMEM;
+
+ sp->rxd = dma_alloc_coherent(&pdev->dev, IPG_RX_RING_BYTES,
+ &sp->rxd_map, GFP_KERNEL);
+ if (!sp->rxd)
+ goto err_free_irq_0;
+
+ sp->txd = dma_alloc_coherent(&pdev->dev, IPG_TX_RING_BYTES,
+ &sp->txd_map, GFP_KERNEL);
+ if (!sp->txd)
+ goto err_free_rx_1;
+
+ rc = init_rfdlist(dev);
+ if (rc < 0) {
+ printk(KERN_INFO "%s: Error during configuration.\n",
+ dev->name);
+ goto err_free_tx_2;
+ }
+
+ init_tfdlist(dev);
+
+ rc = ipg_io_config(dev);
+ if (rc < 0) {
+ printk(KERN_INFO "%s: Error during configuration.\n",
+ dev->name);
+ goto err_release_tfdlist_3;
+ }
+
+ /* Resolve autonegotiation. */
+ if (ipg_config_autoneg(dev) < 0)
+ printk(KERN_INFO "%s: Auto-negotiation error.\n", dev->name);
+
+#ifdef JUMBO_FRAME
+ /* initialize JUMBO Frame control variable */
+ sp->Jumbo.FoundStart = 0;
+ sp->Jumbo.CurrentSize = 0;
+ sp->Jumbo.skb = 0;
+ dev->mtu = IPG_TXFRAG_SIZE;
+#endif
+
+ /* Enable transmit and receive operation of the IPG. */
+ ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_RX_ENABLE | IPG_MC_TX_ENABLE) &
+ IPG_MC_RSVD_MASK, MAC_CTRL);
+
+ netif_start_queue(dev);
+out:
+ return rc;
+
+err_release_tfdlist_3:
+ ipg_tx_clear(sp);
+ ipg_rx_clear(sp);
+err_free_tx_2:
+ dma_free_coherent(&pdev->dev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);
+err_free_rx_1:
+ dma_free_coherent(&pdev->dev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);
+err_free_irq_0:
+ free_irq(pdev->irq, dev);
+ goto out;
+}
+
+static int ipg_nic_stop(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ struct pci_dev *pdev = sp->pdev;
+
+ IPG_DEBUG_MSG("_nic_stop\n");
+
+ netif_stop_queue(dev);
+
+ IPG_DDEBUG_MSG("RFDlistendCount = %i\n", sp->RFDlistendCount);
+ IPG_DDEBUG_MSG("RFDListCheckedCount = %i\n", sp->rxdCheckedCount);
+ IPG_DDEBUG_MSG("EmptyRFDListCount = %i\n", sp->EmptyRFDListCount);
+ IPG_DUMPTFDLIST(dev);
+
+ do {
+ (void) ipg_r16(INT_STATUS_ACK);
+
+ ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA);
+
+ synchronize_irq(pdev->irq);
+ } while (ipg_r16(INT_ENABLE) & IPG_IE_RSVD_MASK);
+
+ ipg_rx_clear(sp);
+
+ ipg_tx_clear(sp);
+
+ pci_free_consistent(pdev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);
+ pci_free_consistent(pdev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);
+
+ free_irq(pdev->irq, dev);
+
+ return 0;
+}
+
+static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int entry = sp->tx_current % IPG_TFDLIST_LENGTH;
+ unsigned long flags;
+ struct ipg_tx *txfd;
+
+ IPG_DDEBUG_MSG("_nic_hard_start_xmit\n");
+
+ /* If in 10Mbps mode, stop the transmit queue so
+ * no more transmit frames are accepted.
+ */
+ if (sp->tenmbpsmode)
+ netif_stop_queue(dev);
+
+ if (sp->ResetCurrentTFD) {
+ sp->ResetCurrentTFD = 0;
+ entry = 0;
+ }
+
+ txfd = sp->txd + entry;
+
+ sp->TxBuff[entry] = skb;
+
+ /* Clear all TFC fields, except TFDDONE. */
+ txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
+
+ /* Specify the TFC field within the TFD. */
+ txfd->tfc |= cpu_to_le64(IPG_TFC_WORDALIGNDISABLED |
+ (IPG_TFC_FRAMEID & cpu_to_le64(sp->tx_current)) |
+ (IPG_TFC_FRAGCOUNT & (1 << 24)));
+
+ /* Request TxComplete interrupts at an interval defined
+ * by the constant IPG_FRAMESBETWEENTXCOMPLETES.
+ * Request TxComplete interrupt for every frame
+ * if in 10Mbps mode to accomodate problem with 10Mbps
+ * processing.
+ */
+ if (sp->tenmbpsmode)
+ txfd->tfc |= cpu_to_le64(IPG_TFC_TXINDICATE);
+ else if (!((sp->tx_current - sp->tx_dirty + 1) >
+ IPG_FRAMESBETWEENTXDMACOMPLETES)) {
+ txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE);
+ }
+ /* Based on compilation option, determine if FCS is to be
+ * appended to transmit frame by IPG.
+ */
+ if (!(IPG_APPEND_FCS_ON_TX))
+ txfd->tfc |= cpu_to_le64(IPG_TFC_FCSAPPENDDISABLE);
+
+ /* Based on compilation option, determine if IP, TCP and/or
+ * UDP checksums are to be added to transmit frame by IPG.
+ */
+ if (IPG_ADD_IPCHECKSUM_ON_TX)
+ txfd->tfc |= cpu_to_le64(IPG_TFC_IPCHECKSUMENABLE);
+
+ if (IPG_ADD_TCPCHECKSUM_ON_TX)
+ txfd->tfc |= cpu_to_le64(IPG_TFC_TCPCHECKSUMENABLE);
+
+ if (IPG_ADD_UDPCHECKSUM_ON_TX)
+ txfd->tfc |= cpu_to_le64(IPG_TFC_UDPCHECKSUMENABLE);
+
+ /* Based on compilation option, determine if VLAN tag info is to be
+ * inserted into transmit frame by IPG.
+ */
+ if (IPG_INSERT_MANUAL_VLAN_TAG) {
+ txfd->tfc |= cpu_to_le64(IPG_TFC_VLANTAGINSERT |
+ ((u64) IPG_MANUAL_VLAN_VID << 32) |
+ ((u64) IPG_MANUAL_VLAN_CFI << 44) |
+ ((u64) IPG_MANUAL_VLAN_USERPRIORITY << 45));
+ }
+
+ /* The fragment start location within system memory is defined
+ * by the sk_buff structure's data field. The physical address
+ * of this location within the system's virtual memory space
+ * is determined using the IPG_HOST2BUS_MAP function.
+ */
+ txfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,
+ skb->len, PCI_DMA_TODEVICE));
+
+ /* The length of the fragment within system memory is defined by
+ * the sk_buff structure's len field.
+ */
+ txfd->frag_info |= cpu_to_le64(IPG_TFI_FRAGLEN &
+ ((u64) (skb->len & 0xffff) << 48));
+
+ /* Clear the TFDDone bit last to indicate the TFD is ready
+ * for transfer to the IPG.
+ */
+ txfd->tfc &= cpu_to_le64(~IPG_TFC_TFDDONE);
+
+ spin_lock_irqsave(&sp->lock, flags);
+
+ sp->tx_current++;
+
+ mmiowb();
+
+ ipg_w32(IPG_DC_TX_DMA_POLL_NOW, DMA_CTRL);
+
+ if (sp->tx_current == (sp->tx_dirty + IPG_TFDLIST_LENGTH))
+ netif_wake_queue(dev);
+
+ spin_unlock_irqrestore(&sp->lock, flags);
+
+ return NETDEV_TX_OK;
+}
+
+static void ipg_set_phy_default_param(unsigned char rev,
+ struct net_device *dev, int phy_address)
+{
+ unsigned short length;
+ unsigned char revision;
+ unsigned short *phy_param;
+ unsigned short address, value;
+
+ phy_param = &DefaultPhyParam[0];
+ length = *phy_param & 0x00FF;
+ revision = (unsigned char)((*phy_param) >> 8);
+ phy_param++;
+ while (length != 0) {
+ if (rev == revision) {
+ while (length > 1) {
+ address = *phy_param;
+ value = *(phy_param + 1);
+ phy_param += 2;
+ mdio_write(dev, phy_address, address, value);
+ length -= 4;
+ }
+ break;
+ } else {
+ phy_param += length / 2;
+ length = *phy_param & 0x00FF;
+ revision = (unsigned char)((*phy_param) >> 8);
+ phy_param++;
+ }
+ }
+}
+
+/* JES20040127EEPROM */
+static int read_eeprom(struct net_device *dev, int eep_addr)
+{
+ void __iomem *ioaddr = ipg_ioaddr(dev);
+ unsigned int i;
+ int ret = 0;
+ u16 value;
+
+ value = IPG_EC_EEPROM_READOPCODE | (eep_addr & 0xff);
+ ipg_w16(value, EEPROM_CTRL);
+
+ for (i = 0; i < 1000; i++) {
+ u16 data;
+
+ mdelay(10);
+ data = ipg_r16(EEPROM_CTRL);
+ if (!(data & IPG_EC_EEPROM_BUSY)) {
+ ret = ipg_r16(EEPROM_DATA);
+ break;
+ }
+ }
+ return ret;
+}
+
+static void ipg_init_mii(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ struct mii_if_info *mii_if = &sp->mii_if;
+ int phyaddr;
+
+ mii_if->dev = dev;
+ mii_if->mdio_read = mdio_read;
+ mii_if->mdio_write = mdio_write;
+ mii_if->phy_id_mask = 0x1f;
+ mii_if->reg_num_mask = 0x1f;
+
+ mii_if->phy_id = phyaddr = ipg_find_phyaddr(dev);
+
+ if (phyaddr != 0x1f) {
+ u16 mii_phyctrl, mii_1000cr;
+ u8 revisionid = 0;
+
+ mii_1000cr = mdio_read(dev, phyaddr, MII_CTRL1000);
+ mii_1000cr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF |
+ GMII_PHY_1000BASETCONTROL_PreferMaster;
+ mdio_write(dev, phyaddr, MII_CTRL1000, mii_1000cr);
+
+ mii_phyctrl = mdio_read(dev, phyaddr, MII_BMCR);
+
+ /* Set default phyparam */
+ pci_read_config_byte(sp->pdev, PCI_REVISION_ID, &revisionid);
+ ipg_set_phy_default_param(revisionid, dev, phyaddr);
+
+ /* Reset PHY */
+ mii_phyctrl |= BMCR_RESET | BMCR_ANRESTART;
+ mdio_write(dev, phyaddr, MII_BMCR, mii_phyctrl);
+
+ }
+}
+
+static int ipg_hw_init(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ void __iomem *ioaddr = sp->ioaddr;
+ unsigned int i;
+ int rc;
+
+ /* Read/Write and Reset EEPROM Value Jesse20040128EEPROM_VALUE */
+ /* Read LED Mode Configuration from EEPROM */
+ sp->LED_Mode = read_eeprom(dev, 6);
+
+ /* Reset all functions within the IPG. Do not assert
+ * RST_OUT as not compatible with some PHYs.
+ */
+ rc = ipg_reset(dev, IPG_RESET_MASK);
+ if (rc < 0)
+ goto out;
+
+ ipg_init_mii(dev);
+
+ /* Read MAC Address from EEPROM */
+ for (i = 0; i < 3; i++)
+ sp->station_addr[i] = read_eeprom(dev, 16 + i);
+
+ for (i = 0; i < 3; i++)
+ ipg_w16(sp->station_addr[i], STATION_ADDRESS_0 + 2*i);
+
+ /* Set station address in ethernet_device structure. */
+ dev->dev_addr[0] = ipg_r16(STATION_ADDRESS_0) & 0x00ff;
+ dev->dev_addr[1] = (ipg_r16(STATION_ADDRESS_0) & 0xff00) >> 8;
+ dev->dev_addr[2] = ipg_r16(STATION_ADDRESS_1) & 0x00ff;
+ dev->dev_addr[3] = (ipg_r16(STATION_ADDRESS_1) & 0xff00) >> 8;
+ dev->dev_addr[4] = ipg_r16(STATION_ADDRESS_2) & 0x00ff;
+ dev->dev_addr[5] = (ipg_r16(STATION_ADDRESS_2) & 0xff00) >> 8;
+out:
+ return rc;
+}
+
+static int ipg_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ int rc;
+
+ mutex_lock(&sp->mii_mutex);
+ rc = generic_mii_ioctl(&sp->mii_if, if_mii(ifr), cmd, NULL);
+ mutex_unlock(&sp->mii_mutex);
+
+ return rc;
+}
+
+static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu)
+{
+ /* Function to accomodate changes to Maximum Transfer Unit
+ * (or MTU) of IPG NIC. Cannot use default function since
+ * the default will not allow for MTU > 1500 bytes.
+ */
+
+ IPG_DEBUG_MSG("_nic_change_mtu\n");
+
+ /* Check that the new MTU value is between 68 (14 byte header, 46
+ * byte payload, 4 byte FCS) and IPG_MAX_RXFRAME_SIZE, which
+ * corresponds to the MAXFRAMESIZE register in the IPG.
+ */
+ if ((new_mtu < 68) || (new_mtu > IPG_MAX_RXFRAME_SIZE))
+ return -EINVAL;
+
+ dev->mtu = new_mtu;
+
+ return 0;
+}
+
+static int ipg_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ int rc;
+
+ mutex_lock(&sp->mii_mutex);
+ rc = mii_ethtool_gset(&sp->mii_if, cmd);
+ mutex_unlock(&sp->mii_mutex);
+
+ return rc;
+}
+
+static int ipg_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ int rc;
+
+ mutex_lock(&sp->mii_mutex);
+ rc = mii_ethtool_sset(&sp->mii_if, cmd);
+ mutex_unlock(&sp->mii_mutex);
+
+ return rc;
+}
+
+static int ipg_nway_reset(struct net_device *dev)
+{
+ struct ipg_nic_private *sp = netdev_priv(dev);
+ int rc;
+
+ mutex_lock(&sp->mii_mutex);
+ rc = mii_nway_restart(&sp->mii_if);
+ mutex_unlock(&sp->mii_mutex);
+
+ return rc;
+}
+
+static struct ethtool_ops ipg_ethtool_ops = {
+ .get_settings = ipg_get_settings,
+ .set_settings = ipg_set_settings,
+ .nway_reset = ipg_nway_reset,
+};
+
+static void ipg_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct ipg_nic_private *sp = netdev_priv(dev);
+
+ IPG_DEBUG_MSG("_remove\n");
+
+ /* Un-register Ethernet device. */
+ unregister_netdev(dev);
+
+ pci_iounmap(pdev, sp->ioaddr);
+
+ pci_release_regions(pdev);
+
+ free_netdev(dev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+static int __devinit ipg_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ unsigned int i = id->driver_data;
+ struct ipg_nic_private *sp;
+ struct net_device *dev;
+ void __iomem *ioaddr;
+ int rc;
+
+ rc = pci_enable_device(pdev);
+ if (rc < 0)
+ goto out;
+
+ printk(KERN_INFO "%s: %s\n", pci_name(pdev), ipg_brand_name[i]);
+
+ pci_set_master(pdev);
+
+ rc = pci_set_dma_mask(pdev, DMA_40BIT_MASK);
+ if (rc < 0) {
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc < 0) {
+ printk(KERN_ERR "%s: DMA config failed.\n",
+ pci_name(pdev));
+ goto err_disable_0;
+ }
+ }
+
+ /*
+ * Initialize net device.
+ */
+ dev = alloc_etherdev(sizeof(struct ipg_nic_private));
+ if (!dev) {
+ printk(KERN_ERR "%s: alloc_etherdev failed\n", pci_name(pdev));
+ rc = -ENOMEM;
+ goto err_disable_0;
+ }
+
+ sp = netdev_priv(dev);
+ spin_lock_init(&sp->lock);
+ mutex_init(&sp->mii_mutex);
+
+ /* Declare IPG NIC functions for Ethernet device methods.
+ */
+ dev->open = &ipg_nic_open;
+ dev->stop = &ipg_nic_stop;
+ dev->hard_start_xmit = &ipg_nic_hard_start_xmit;
+ dev->get_stats = &ipg_nic_get_stats;
+ dev->set_multicast_list = &ipg_nic_set_multicast_list;
+ dev->do_ioctl = ipg_ioctl;
+ dev->tx_timeout = ipg_tx_timeout;
+ dev->change_mtu = &ipg_nic_change_mtu;
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ SET_ETHTOOL_OPS(dev, &ipg_ethtool_ops);
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ goto err_free_dev_1;
+
+ ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));
+ if (!ioaddr) {
+ printk(KERN_ERR "%s cannot map MMIO\n", pci_name(pdev));
+ rc = -EIO;
+ goto err_release_regions_2;
+ }
+
+ /* Save the pointer to the PCI device information. */
+ sp->ioaddr = ioaddr;
+ sp->pdev = pdev;
+ sp->dev = dev;
+
+ INIT_DELAYED_WORK(&sp->task, ipg_reset_after_host_error);
+
+ pci_set_drvdata(pdev, dev);
+
+ rc = ipg_hw_init(dev);
+ if (rc < 0)
+ goto err_unmap_3;
+
+ rc = register_netdev(dev);
+ if (rc < 0)
+ goto err_unmap_3;
+
+ printk(KERN_INFO "Ethernet device registered as: %s\n", dev->name);
+out:
+ return rc;
+
+err_unmap_3:
+ pci_iounmap(pdev, ioaddr);
+err_release_regions_2:
+ pci_release_regions(pdev);
+err_free_dev_1:
+ free_netdev(dev);
+err_disable_0:
+ pci_disable_device(pdev);
+ goto out;
+}
+
+static struct pci_driver ipg_pci_driver = {
+ .name = IPG_DRIVER_NAME,
+ .id_table = ipg_pci_tbl,
+ .probe = ipg_probe,
+ .remove = __devexit_p(ipg_remove),
+};
+
+static int __init ipg_init_module(void)
+{
+ return pci_register_driver(&ipg_pci_driver);
+}
+
+static void __exit ipg_exit_module(void)
+{
+ pci_unregister_driver(&ipg_pci_driver);
+}
+
+module_init(ipg_init_module);
+module_exit(ipg_exit_module);
diff --git a/drivers/net/ipg.h b/drivers/net/ipg.h
new file mode 100644
index 00000000000..d5d092c9d0a
--- /dev/null
+++ b/drivers/net/ipg.h
@@ -0,0 +1,836 @@
+/*
+ *
+ * ipg.h
+ *
+ * Include file for Gigabit Ethernet device driver for Network
+ * Interface Cards (NICs) utilizing the Tamarack Microelectronics
+ * Inc. IPG Gigabit or Triple Speed Ethernet Media Access
+ * Controller.
+ *
+ * Craig Rich
+ * Sundance Technology, Inc.
+ * 1485 Saratoga Avenue
+ * Suite 200
+ * San Jose, CA 95129
+ * 408 873 4117
+ * www.sundanceti.com
+ * craig_rich@sundanceti.com
+ */
+#ifndef __LINUX_IPG_H
+#define __LINUX_IPG_H
+
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/version.h>
+#include <asm/bitops.h>
+/*#include <asm/spinlock.h>*/
+
+#define DrvVer "2.09d"
+
+#define IPG_DEV_KFREE_SKB(skb) dev_kfree_skb_irq(skb)
+
+/*
+ * Constants
+ */
+
+/* GMII based PHY IDs */
+#define NS 0x2000
+#define MARVELL 0x0141
+#define ICPLUS_PHY 0x243
+
+/* NIC Physical Layer Device MII register fields. */
+#define MII_PHY_SELECTOR_IEEE8023 0x0001
+#define MII_PHY_TECHABILITYFIELD 0x1FE0
+
+/* GMII_PHY_1000 need to set to prefer master */
+#define GMII_PHY_1000BASETCONTROL_PreferMaster 0x0400
+
+/* NIC Physical Layer Device GMII constants. */
+#define GMII_PREAMBLE 0xFFFFFFFF
+#define GMII_ST 0x1
+#define GMII_READ 0x2
+#define GMII_WRITE 0x1
+#define GMII_TA_READ_MASK 0x1
+#define GMII_TA_WRITE 0x2
+
+/* I/O register offsets. */
+enum ipg_regs {
+ DMA_CTRL = 0x00,
+ RX_DMA_STATUS = 0x08, // Unused + reserved
+ TFD_LIST_PTR_0 = 0x10,
+ TFD_LIST_PTR_1 = 0x14,
+ TX_DMA_BURST_THRESH = 0x18,
+ TX_DMA_URGENT_THRESH = 0x19,
+ TX_DMA_POLL_PERIOD = 0x1a,
+ RFD_LIST_PTR_0 = 0x1c,
+ RFD_LIST_PTR_1 = 0x20,
+ RX_DMA_BURST_THRESH = 0x24,
+ RX_DMA_URGENT_THRESH = 0x25,
+ RX_DMA_POLL_PERIOD = 0x26,
+ DEBUG_CTRL = 0x2c,
+ ASIC_CTRL = 0x30,
+ FIFO_CTRL = 0x38, // Unused
+ FLOW_OFF_THRESH = 0x3c,
+ FLOW_ON_THRESH = 0x3e,
+ EEPROM_DATA = 0x48,
+ EEPROM_CTRL = 0x4a,
+ EXPROM_ADDR = 0x4c, // Unused
+ EXPROM_DATA = 0x50, // Unused
+ WAKE_EVENT = 0x51, // Unused
+ COUNTDOWN = 0x54, // Unused
+ INT_STATUS_ACK = 0x5a,
+ INT_ENABLE = 0x5c,
+ INT_STATUS = 0x5e, // Unused
+ TX_STATUS = 0x60,
+ MAC_CTRL = 0x6c,
+ VLAN_TAG = 0x70, // Unused
+ PHY_SET = 0x75, // JES20040127EEPROM
+ PHY_CTRL = 0x76,
+ STATION_ADDRESS_0 = 0x78,
+ STATION_ADDRESS_1 = 0x7a,
+ STATION_ADDRESS_2 = 0x7c,
+ MAX_FRAME_SIZE = 0x86,
+ RECEIVE_MODE = 0x88,
+ HASHTABLE_0 = 0x8c,
+ HASHTABLE_1 = 0x90,
+ RMON_STATISTICS_MASK = 0x98,
+ STATISTICS_MASK = 0x9c,
+ RX_JUMBO_FRAMES = 0xbc, // Unused
+ TCP_CHECKSUM_ERRORS = 0xc0, // Unused
+ IP_CHECKSUM_ERRORS = 0xc2, // Unused
+ UDP_CHECKSUM_ERRORS = 0xc4, // Unused
+ TX_JUMBO_FRAMES = 0xf4 // Unused
+};
+
+/* Ethernet MIB statistic register offsets. */
+#define IPG_OCTETRCVOK 0xA8
+#define IPG_MCSTOCTETRCVDOK 0xAC
+#define IPG_BCSTOCTETRCVOK 0xB0
+#define IPG_FRAMESRCVDOK 0xB4
+#define IPG_MCSTFRAMESRCVDOK 0xB8
+#define IPG_BCSTFRAMESRCVDOK 0xBE
+#define IPG_MACCONTROLFRAMESRCVD 0xC6
+#define IPG_FRAMETOOLONGERRRORS 0xC8
+#define IPG_INRANGELENGTHERRORS 0xCA
+#define IPG_FRAMECHECKSEQERRORS 0xCC
+#define IPG_FRAMESLOSTRXERRORS 0xCE
+#define IPG_OCTETXMTOK 0xD0
+#define IPG_MCSTOCTETXMTOK 0xD4
+#define IPG_BCSTOCTETXMTOK 0xD8
+#define IPG_FRAMESXMTDOK 0xDC
+#define IPG_MCSTFRAMESXMTDOK 0xE0
+#define IPG_FRAMESWDEFERREDXMT 0xE4
+#define IPG_LATECOLLISIONS 0xE8
+#define IPG_MULTICOLFRAMES 0xEC
+#define IPG_SINGLECOLFRAMES 0xF0
+#define IPG_BCSTFRAMESXMTDOK 0xF6
+#define IPG_CARRIERSENSEERRORS 0xF8
+#define IPG_MACCONTROLFRAMESXMTDOK 0xFA
+#define IPG_FRAMESABORTXSCOLLS 0xFC
+#define IPG_FRAMESWEXDEFERRAL 0xFE
+
+/* RMON statistic register offsets. */
+#define IPG_ETHERSTATSCOLLISIONS 0x100
+#define IPG_ETHERSTATSOCTETSTRANSMIT 0x104
+#define IPG_ETHERSTATSPKTSTRANSMIT 0x108
+#define IPG_ETHERSTATSPKTS64OCTESTSTRANSMIT 0x10C
+#define IPG_ETHERSTATSPKTS65TO127OCTESTSTRANSMIT 0x110
+#define IPG_ETHERSTATSPKTS128TO255OCTESTSTRANSMIT 0x114
+#define IPG_ETHERSTATSPKTS256TO511OCTESTSTRANSMIT 0x118
+#define IPG_ETHERSTATSPKTS512TO1023OCTESTSTRANSMIT 0x11C
+#define IPG_ETHERSTATSPKTS1024TO1518OCTESTSTRANSMIT 0x120
+#define IPG_ETHERSTATSCRCALIGNERRORS 0x124
+#define IPG_ETHERSTATSUNDERSIZEPKTS 0x128
+#define IPG_ETHERSTATSFRAGMENTS 0x12C
+#define IPG_ETHERSTATSJABBERS 0x130
+#define IPG_ETHERSTATSOCTETS 0x134
+#define IPG_ETHERSTATSPKTS 0x138
+#define IPG_ETHERSTATSPKTS64OCTESTS 0x13C
+#define IPG_ETHERSTATSPKTS65TO127OCTESTS 0x140
+#define IPG_ETHERSTATSPKTS128TO255OCTESTS 0x144
+#define IPG_ETHERSTATSPKTS256TO511OCTESTS 0x148
+#define IPG_ETHERSTATSPKTS512TO1023OCTESTS 0x14C
+#define IPG_ETHERSTATSPKTS1024TO1518OCTESTS 0x150
+
+/* RMON statistic register equivalents. */
+#define IPG_ETHERSTATSMULTICASTPKTSTRANSMIT 0xE0
+#define IPG_ETHERSTATSBROADCASTPKTSTRANSMIT 0xF6
+#define IPG_ETHERSTATSMULTICASTPKTS 0xB8
+#define IPG_ETHERSTATSBROADCASTPKTS 0xBE
+#define IPG_ETHERSTATSOVERSIZEPKTS 0xC8
+#define IPG_ETHERSTATSDROPEVENTS 0xCE
+
+/* Serial EEPROM offsets */
+#define IPG_EEPROM_CONFIGPARAM 0x00
+#define IPG_EEPROM_ASICCTRL 0x01
+#define IPG_EEPROM_SUBSYSTEMVENDORID 0x02
+#define IPG_EEPROM_SUBSYSTEMID 0x03
+#define IPG_EEPROM_STATIONADDRESS0 0x10
+#define IPG_EEPROM_STATIONADDRESS1 0x11
+#define IPG_EEPROM_STATIONADDRESS2 0x12
+
+/* Register & data structure bit masks */
+
+/* PCI register masks. */
+
+/* IOBaseAddress */
+#define IPG_PIB_RSVD_MASK 0xFFFFFE01
+#define IPG_PIB_IOBASEADDRESS 0xFFFFFF00
+#define IPG_PIB_IOBASEADDRIND 0x00000001
+
+/* MemBaseAddress */
+#define IPG_PMB_RSVD_MASK 0xFFFFFE07
+#define IPG_PMB_MEMBASEADDRIND 0x00000001
+#define IPG_PMB_MEMMAPTYPE 0x00000006
+#define IPG_PMB_MEMMAPTYPE0 0x00000002
+#define IPG_PMB_MEMMAPTYPE1 0x00000004
+#define IPG_PMB_MEMBASEADDRESS 0xFFFFFE00
+
+/* ConfigStatus */
+#define IPG_CS_RSVD_MASK 0xFFB0
+#define IPG_CS_CAPABILITIES 0x0010
+#define IPG_CS_66MHZCAPABLE 0x0020
+#define IPG_CS_FASTBACK2BACK 0x0080
+#define IPG_CS_DATAPARITYREPORTED 0x0100
+#define IPG_CS_DEVSELTIMING 0x0600
+#define IPG_CS_SIGNALEDTARGETABORT 0x0800
+#define IPG_CS_RECEIVEDTARGETABORT 0x1000
+#define IPG_CS_RECEIVEDMASTERABORT 0x2000
+#define IPG_CS_SIGNALEDSYSTEMERROR 0x4000
+#define IPG_CS_DETECTEDPARITYERROR 0x8000
+
+/* TFD data structure masks. */
+
+/* TFDList, TFC */
+#define IPG_TFC_RSVD_MASK 0x0000FFFF9FFFFFFF
+#define IPG_TFC_FRAMEID 0x000000000000FFFF
+#define IPG_TFC_WORDALIGN 0x0000000000030000
+#define IPG_TFC_WORDALIGNTODWORD 0x0000000000000000
+#define IPG_TFC_WORDALIGNTOWORD 0x0000000000020000
+#define IPG_TFC_WORDALIGNDISABLED 0x0000000000030000
+#define IPG_TFC_TCPCHECKSUMENABLE 0x0000000000040000
+#define IPG_TFC_UDPCHECKSUMENABLE 0x0000000000080000
+#define IPG_TFC_IPCHECKSUMENABLE 0x0000000000100000
+#define IPG_TFC_FCSAPPENDDISABLE 0x0000000000200000
+#define IPG_TFC_TXINDICATE 0x0000000000400000
+#define IPG_TFC_TXDMAINDICATE 0x0000000000800000
+#define IPG_TFC_FRAGCOUNT 0x000000000F000000
+#define IPG_TFC_VLANTAGINSERT 0x0000000010000000
+#define IPG_TFC_TFDDONE 0x0000000080000000
+#define IPG_TFC_VID 0x00000FFF00000000
+#define IPG_TFC_CFI 0x0000100000000000
+#define IPG_TFC_USERPRIORITY 0x0000E00000000000
+
+/* TFDList, FragInfo */
+#define IPG_TFI_RSVD_MASK 0xFFFF00FFFFFFFFFF
+#define IPG_TFI_FRAGADDR 0x000000FFFFFFFFFF
+#define IPG_TFI_FRAGLEN 0xFFFF000000000000LL
+
+/* RFD data structure masks. */
+
+/* RFDList, RFS */
+#define IPG_RFS_RSVD_MASK 0x0000FFFFFFFFFFFF
+#define IPG_RFS_RXFRAMELEN 0x000000000000FFFF
+#define IPG_RFS_RXFIFOOVERRUN 0x0000000000010000
+#define IPG_RFS_RXRUNTFRAME 0x0000000000020000
+#define IPG_RFS_RXALIGNMENTERROR 0x0000000000040000
+#define IPG_RFS_RXFCSERROR 0x0000000000080000
+#define IPG_RFS_RXOVERSIZEDFRAME 0x0000000000100000
+#define IPG_RFS_RXLENGTHERROR 0x0000000000200000
+#define IPG_RFS_VLANDETECTED 0x0000000000400000
+#define IPG_RFS_TCPDETECTED 0x0000000000800000
+#define IPG_RFS_TCPERROR 0x0000000001000000
+#define IPG_RFS_UDPDETECTED 0x0000000002000000
+#define IPG_RFS_UDPERROR 0x0000000004000000
+#define IPG_RFS_IPDETECTED 0x0000000008000000
+#define IPG_RFS_IPERROR 0x0000000010000000
+#define IPG_RFS_FRAMESTART 0x0000000020000000
+#define IPG_RFS_FRAMEEND 0x0000000040000000
+#define IPG_RFS_RFDDONE 0x0000000080000000
+#define IPG_RFS_TCI 0x0000FFFF00000000
+
+/* RFDList, FragInfo */
+#define IPG_RFI_RSVD_MASK 0xFFFF00FFFFFFFFFF
+#define IPG_RFI_FRAGADDR 0x000000FFFFFFFFFF
+#define IPG_RFI_FRAGLEN 0xFFFF000000000000LL
+
+/* I/O Register masks. */
+
+/* RMON Statistics Mask */
+#define IPG_RZ_ALL 0x0FFFFFFF
+
+/* Statistics Mask */
+#define IPG_SM_ALL 0x0FFFFFFF
+#define IPG_SM_OCTETRCVOK_FRAMESRCVDOK 0x00000001
+#define IPG_SM_MCSTOCTETRCVDOK_MCSTFRAMESRCVDOK 0x00000002
+#define IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK 0x00000004
+#define IPG_SM_RXJUMBOFRAMES 0x00000008
+#define IPG_SM_TCPCHECKSUMERRORS 0x00000010
+#define IPG_SM_IPCHECKSUMERRORS 0x00000020
+#define IPG_SM_UDPCHECKSUMERRORS 0x00000040
+#define IPG_SM_MACCONTROLFRAMESRCVD 0x00000080
+#define IPG_SM_FRAMESTOOLONGERRORS 0x00000100
+#define IPG_SM_INRANGELENGTHERRORS 0x00000200
+#define IPG_SM_FRAMECHECKSEQERRORS 0x00000400
+#define IPG_SM_FRAMESLOSTRXERRORS 0x00000800
+#define IPG_SM_OCTETXMTOK_FRAMESXMTOK 0x00001000
+#define IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK 0x00002000
+#define IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK 0x00004000
+#define IPG_SM_FRAMESWDEFERREDXMT 0x00008000
+#define IPG_SM_LATECOLLISIONS 0x00010000
+#define IPG_SM_MULTICOLFRAMES 0x00020000
+#define IPG_SM_SINGLECOLFRAMES 0x00040000
+#define IPG_SM_TXJUMBOFRAMES 0x00080000
+#define IPG_SM_CARRIERSENSEERRORS 0x00100000
+#define IPG_SM_MACCONTROLFRAMESXMTD 0x00200000
+#define IPG_SM_FRAMESABORTXSCOLLS 0x00400000
+#define IPG_SM_FRAMESWEXDEFERAL 0x00800000
+
+/* Countdown */
+#define IPG_CD_RSVD_MASK 0x0700FFFF
+#define IPG_CD_COUNT 0x0000FFFF
+#define IPG_CD_COUNTDOWNSPEED 0x01000000
+#define IPG_CD_COUNTDOWNMODE 0x02000000
+#define IPG_CD_COUNTINTENABLED 0x04000000
+
+/* TxDMABurstThresh */
+#define IPG_TB_RSVD_MASK 0xFF
+
+/* TxDMAUrgentThresh */
+#define IPG_TU_RSVD_MASK 0xFF
+
+/* TxDMAPollPeriod */
+#define IPG_TP_RSVD_MASK 0xFF
+
+/* RxDMAUrgentThresh */
+#define IPG_RU_RSVD_MASK 0xFF
+
+/* RxDMAPollPeriod */
+#define IPG_RP_RSVD_MASK 0xFF
+
+/* ReceiveMode */
+#define IPG_RM_RSVD_MASK 0x3F
+#define IPG_RM_RECEIVEUNICAST 0x01
+#define IPG_RM_RECEIVEMULTICAST 0x02
+#define IPG_RM_RECEIVEBROADCAST 0x04
+#define IPG_RM_RECEIVEALLFRAMES 0x08
+#define IPG_RM_RECEIVEMULTICASTHASH 0x10
+#define IPG_RM_RECEIVEIPMULTICAST 0x20
+
+/* PhySet JES20040127EEPROM*/
+#define IPG_PS_MEM_LENB9B 0x01
+#define IPG_PS_MEM_LEN9 0x02
+#define IPG_PS_NON_COMPDET 0x04
+
+/* PhyCtrl */
+#define IPG_PC_RSVD_MASK 0xFF
+#define IPG_PC_MGMTCLK_LO 0x00
+#define IPG_PC_MGMTCLK_HI 0x01
+#define IPG_PC_MGMTCLK 0x01
+#define IPG_PC_MGMTDATA 0x02
+#define IPG_PC_MGMTDIR 0x04
+#define IPG_PC_DUPLEX_POLARITY 0x08
+#define IPG_PC_DUPLEX_STATUS 0x10
+#define IPG_PC_LINK_POLARITY 0x20
+#define IPG_PC_LINK_SPEED 0xC0
+#define IPG_PC_LINK_SPEED_10MBPS 0x40
+#define IPG_PC_LINK_SPEED_100MBPS 0x80
+#define IPG_PC_LINK_SPEED_1000MBPS 0xC0
+
+/* DMACtrl */
+#define IPG_DC_RSVD_MASK 0xC07D9818
+#define IPG_DC_RX_DMA_COMPLETE 0x00000008
+#define IPG_DC_RX_DMA_POLL_NOW 0x00000010
+#define IPG_DC_TX_DMA_COMPLETE 0x00000800
+#define IPG_DC_TX_DMA_POLL_NOW 0x00001000
+#define IPG_DC_TX_DMA_IN_PROG 0x00008000
+#define IPG_DC_RX_EARLY_DISABLE 0x00010000
+#define IPG_DC_MWI_DISABLE 0x00040000
+#define IPG_DC_TX_WRITE_BACK_DISABLE 0x00080000
+#define IPG_DC_TX_BURST_LIMIT 0x00700000
+#define IPG_DC_TARGET_ABORT 0x40000000
+#define IPG_DC_MASTER_ABORT 0x80000000
+
+/* ASICCtrl */
+#define IPG_AC_RSVD_MASK 0x07FFEFF2
+#define IPG_AC_EXP_ROM_SIZE 0x00000002
+#define IPG_AC_PHY_SPEED10 0x00000010
+#define IPG_AC_PHY_SPEED100 0x00000020
+#define IPG_AC_PHY_SPEED1000 0x00000040
+#define IPG_AC_PHY_MEDIA 0x00000080
+#define IPG_AC_FORCED_CFG 0x00000700
+#define IPG_AC_D3RESETDISABLE 0x00000800
+#define IPG_AC_SPEED_UP_MODE 0x00002000
+#define IPG_AC_LED_MODE 0x00004000
+#define IPG_AC_RST_OUT_POLARITY 0x00008000
+#define IPG_AC_GLOBAL_RESET 0x00010000
+#define IPG_AC_RX_RESET 0x00020000
+#define IPG_AC_TX_RESET 0x00040000
+#define IPG_AC_DMA 0x00080000
+#define IPG_AC_FIFO 0x00100000
+#define IPG_AC_NETWORK 0x00200000
+#define IPG_AC_HOST 0x00400000
+#define IPG_AC_AUTO_INIT 0x00800000
+#define IPG_AC_RST_OUT 0x01000000
+#define IPG_AC_INT_REQUEST 0x02000000
+#define IPG_AC_RESET_BUSY 0x04000000
+#define IPG_AC_LED_SPEED 0x08000000 //JES20040127EEPROM
+#define IPG_AC_LED_MODE_BIT_1 0x20000000 //JES20040127EEPROM
+
+/* EepromCtrl */
+#define IPG_EC_RSVD_MASK 0x83FF
+#define IPG_EC_EEPROM_ADDR 0x00FF
+#define IPG_EC_EEPROM_OPCODE 0x0300
+#define IPG_EC_EEPROM_SUBCOMMAD 0x0000
+#define IPG_EC_EEPROM_WRITEOPCODE 0x0100
+#define IPG_EC_EEPROM_READOPCODE 0x0200
+#define IPG_EC_EEPROM_ERASEOPCODE 0x0300
+#define IPG_EC_EEPROM_BUSY 0x8000
+
+/* FIFOCtrl */
+#define IPG_FC_RSVD_MASK 0xC001
+#define IPG_FC_RAM_TEST_MODE 0x0001
+#define IPG_FC_TRANSMITTING 0x4000
+#define IPG_FC_RECEIVING 0x8000
+
+/* TxStatus */
+#define IPG_TS_RSVD_MASK 0xFFFF00DD
+#define IPG_TS_TX_ERROR 0x00000001
+#define IPG_TS_LATE_COLLISION 0x00000004
+#define IPG_TS_TX_MAX_COLL 0x00000008
+#define IPG_TS_TX_UNDERRUN 0x00000010
+#define IPG_TS_TX_IND_REQD 0x00000040
+#define IPG_TS_TX_COMPLETE 0x00000080
+#define IPG_TS_TX_FRAMEID 0xFFFF0000
+
+/* WakeEvent */
+#define IPG_WE_WAKE_PKT_ENABLE 0x01
+#define IPG_WE_MAGIC_PKT_ENABLE 0x02
+#define IPG_WE_LINK_EVT_ENABLE 0x04
+#define IPG_WE_WAKE_POLARITY 0x08
+#define IPG_WE_WAKE_PKT_EVT 0x10
+#define IPG_WE_MAGIC_PKT_EVT 0x20
+#define IPG_WE_LINK_EVT 0x40
+#define IPG_WE_WOL_ENABLE 0x80
+
+/* IntEnable */
+#define IPG_IE_RSVD_MASK 0x1FFE
+#define IPG_IE_HOST_ERROR 0x0002
+#define IPG_IE_TX_COMPLETE 0x0004
+#define IPG_IE_MAC_CTRL_FRAME 0x0008
+#define IPG_IE_RX_COMPLETE 0x0010
+#define IPG_IE_RX_EARLY 0x0020
+#define IPG_IE_INT_REQUESTED 0x0040
+#define IPG_IE_UPDATE_STATS 0x0080
+#define IPG_IE_LINK_EVENT 0x0100
+#define IPG_IE_TX_DMA_COMPLETE 0x0200
+#define IPG_IE_RX_DMA_COMPLETE 0x0400
+#define IPG_IE_RFD_LIST_END 0x0800
+#define IPG_IE_RX_DMA_PRIORITY 0x1000
+
+/* IntStatus */
+#define IPG_IS_RSVD_MASK 0x1FFF
+#define IPG_IS_INTERRUPT_STATUS 0x0001
+#define IPG_IS_HOST_ERROR 0x0002
+#define IPG_IS_TX_COMPLETE 0x0004
+#define IPG_IS_MAC_CTRL_FRAME 0x0008
+#define IPG_IS_RX_COMPLETE 0x0010
+#define IPG_IS_RX_EARLY 0x0020
+#define IPG_IS_INT_REQUESTED 0x0040
+#define IPG_IS_UPDATE_STATS 0x0080
+#define IPG_IS_LINK_EVENT 0x0100
+#define IPG_IS_TX_DMA_COMPLETE 0x0200
+#define IPG_IS_RX_DMA_COMPLETE 0x0400
+#define IPG_IS_RFD_LIST_END 0x0800
+#define IPG_IS_RX_DMA_PRIORITY 0x1000
+
+/* MACCtrl */
+#define IPG_MC_RSVD_MASK 0x7FE33FA3
+#define IPG_MC_IFS_SELECT 0x00000003
+#define IPG_MC_IFS_4352BIT 0x00000003
+#define IPG_MC_IFS_1792BIT 0x00000002
+#define IPG_MC_IFS_1024BIT 0x00000001
+#define IPG_MC_IFS_96BIT 0x00000000
+#define IPG_MC_DUPLEX_SELECT 0x00000020
+#define IPG_MC_DUPLEX_SELECT_FD 0x00000020
+#define IPG_MC_DUPLEX_SELECT_HD 0x00000000
+#define IPG_MC_TX_FLOW_CONTROL_ENABLE 0x00000080
+#define IPG_MC_RX_FLOW_CONTROL_ENABLE 0x00000100
+#define IPG_MC_RCV_FCS 0x00000200
+#define IPG_MC_FIFO_LOOPBACK 0x00000400
+#define IPG_MC_MAC_LOOPBACK 0x00000800
+#define IPG_MC_AUTO_VLAN_TAGGING 0x00001000
+#define IPG_MC_AUTO_VLAN_UNTAGGING 0x00002000
+#define IPG_MC_COLLISION_DETECT 0x00010000
+#define IPG_MC_CARRIER_SENSE 0x00020000
+#define IPG_MC_STATISTICS_ENABLE 0x00200000
+#define IPG_MC_STATISTICS_DISABLE 0x00400000
+#define IPG_MC_STATISTICS_ENABLED 0x00800000
+#define IPG_MC_TX_ENABLE 0x01000000
+#define IPG_MC_TX_DISABLE 0x02000000
+#define IPG_MC_TX_ENABLED 0x04000000
+#define IPG_MC_RX_ENABLE 0x08000000
+#define IPG_MC_RX_DISABLE 0x10000000
+#define IPG_MC_RX_ENABLED 0x20000000
+#define IPG_MC_PAUSED 0x40000000
+
+/*
+ * Tune
+ */
+
+/* Miscellaneous Constants. */
+#define TRUE 1
+#define FALSE 0
+
+/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS append on TX. */
+#define IPG_APPEND_FCS_ON_TX TRUE
+
+/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS strip on RX. */
+#define IPG_STRIP_FCS_ON_RX TRUE
+
+/* Assign IPG_DROP_ON_RX_ETH_ERRORS > 0 to drop RX frames with
+ * Ethernet errors.
+ */
+#define IPG_DROP_ON_RX_ETH_ERRORS TRUE
+
+/* Assign IPG_INSERT_MANUAL_VLAN_TAG > 0 to insert VLAN tags manually
+ * (via TFC).
+ */
+#define IPG_INSERT_MANUAL_VLAN_TAG FALSE
+
+/* Assign IPG_ADD_IPCHECKSUM_ON_TX > 0 for auto IP checksum on TX. */
+#define IPG_ADD_IPCHECKSUM_ON_TX FALSE
+
+/* Assign IPG_ADD_TCPCHECKSUM_ON_TX > 0 for auto TCP checksum on TX.
+ * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
+ */
+#define IPG_ADD_TCPCHECKSUM_ON_TX FALSE
+
+/* Assign IPG_ADD_UDPCHECKSUM_ON_TX > 0 for auto UDP checksum on TX.
+ * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
+ */
+#define IPG_ADD_UDPCHECKSUM_ON_TX FALSE
+
+/* If inserting VLAN tags manually, assign the IPG_MANUAL_VLAN_xx
+ * constants as desired.
+ */
+#define IPG_MANUAL_VLAN_VID 0xABC
+#define IPG_MANUAL_VLAN_CFI 0x1
+#define IPG_MANUAL_VLAN_USERPRIORITY 0x5
+
+#define IPG_IO_REG_RANGE 0xFF
+#define IPG_MEM_REG_RANGE 0x154
+#define IPG_DRIVER_NAME "Sundance Technology IPG Triple-Speed Ethernet"
+#define IPG_NIC_PHY_ADDRESS 0x01
+#define IPG_DMALIST_ALIGN_PAD 0x07
+#define IPG_MULTICAST_HASHTABLE_SIZE 0x40
+
+/* Number of miliseconds to wait after issuing a software reset.
+ * 0x05 <= IPG_AC_RESETWAIT to account for proper 10Mbps operation.
+ */
+#define IPG_AC_RESETWAIT 0x05
+
+/* Number of IPG_AC_RESETWAIT timeperiods before declaring timeout. */
+#define IPG_AC_RESET_TIMEOUT 0x0A
+
+/* Minimum number of nanoseconds used to toggle MDC clock during
+ * MII/GMII register access.
+ */
+#define IPG_PC_PHYCTRLWAIT_NS 200
+
+#define IPG_TFDLIST_LENGTH 0x100
+
+/* Number of frames between TxDMAComplete interrupt.
+ * 0 < IPG_FRAMESBETWEENTXDMACOMPLETES <= IPG_TFDLIST_LENGTH
+ */
+#define IPG_FRAMESBETWEENTXDMACOMPLETES 0x1
+
+#ifdef JUMBO_FRAME
+
+# ifdef JUMBO_FRAME_SIZE_2K
+# define JUMBO_FRAME_SIZE 2048
+# define __IPG_RXFRAG_SIZE 2048
+# else
+# ifdef JUMBO_FRAME_SIZE_3K
+# define JUMBO_FRAME_SIZE 3072
+# define __IPG_RXFRAG_SIZE 3072
+# else
+# ifdef JUMBO_FRAME_SIZE_4K
+# define JUMBO_FRAME_SIZE 4096
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# ifdef JUMBO_FRAME_SIZE_5K
+# define JUMBO_FRAME_SIZE 5120
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# ifdef JUMBO_FRAME_SIZE_6K
+# define JUMBO_FRAME_SIZE 6144
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# ifdef JUMBO_FRAME_SIZE_7K
+# define JUMBO_FRAME_SIZE 7168
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# ifdef JUMBO_FRAME_SIZE_8K
+# define JUMBO_FRAME_SIZE 8192
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# ifdef JUMBO_FRAME_SIZE_9K
+# define JUMBO_FRAME_SIZE 9216
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# ifdef JUMBO_FRAME_SIZE_10K
+# define JUMBO_FRAME_SIZE 10240
+# define __IPG_RXFRAG_SIZE 4088
+# else
+# define JUMBO_FRAME_SIZE 4096
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* Size of allocated received buffers. Nominally 0x0600.
+ * Define larger if expecting jumbo frames.
+ */
+#ifdef JUMBO_FRAME
+//IPG_TXFRAG_SIZE must <= 0x2b00, or TX will crash
+#define IPG_TXFRAG_SIZE JUMBO_FRAME_SIZE
+#endif
+
+/* Size of allocated received buffers. Nominally 0x0600.
+ * Define larger if expecting jumbo frames.
+ */
+#ifdef JUMBO_FRAME
+//4088=4096-8
+#define IPG_RXFRAG_SIZE __IPG_RXFRAG_SIZE
+#define IPG_RXSUPPORT_SIZE IPG_MAX_RXFRAME_SIZE
+#else
+#define IPG_RXFRAG_SIZE 0x0600
+#define IPG_RXSUPPORT_SIZE IPG_RXFRAG_SIZE
+#endif
+
+/* IPG_MAX_RXFRAME_SIZE <= IPG_RXFRAG_SIZE */
+#ifdef JUMBO_FRAME
+#define IPG_MAX_RXFRAME_SIZE JUMBO_FRAME_SIZE
+#else
+#define IPG_MAX_RXFRAME_SIZE 0x0600
+#endif
+
+#define IPG_RFDLIST_LENGTH 0x100
+
+/* Maximum number of RFDs to process per interrupt.
+ * 1 < IPG_MAXRFDPROCESS_COUNT < IPG_RFDLIST_LENGTH
+ */
+#define IPG_MAXRFDPROCESS_COUNT 0x80
+
+/* Minimum margin between last freed RFD, and current RFD.
+ * 1 < IPG_MINUSEDRFDSTOFREE < IPG_RFDLIST_LENGTH
+ */
+#define IPG_MINUSEDRFDSTOFREE 0x80
+
+/* specify the jumbo frame maximum size
+ * per unit is 0x600 (the RxBuffer size that one RFD can carry)
+ */
+#define MAX_JUMBOSIZE 0x8 // max is 12K
+
+/* Key register values loaded at driver start up. */
+
+/* TXDMAPollPeriod is specified in 320ns increments.
+ *
+ * Value Time
+ * ---------------------
+ * 0x00-0x01 320ns
+ * 0x03 ~1us
+ * 0x1F ~10us
+ * 0xFF ~82us
+ */
+#define IPG_TXDMAPOLLPERIOD_VALUE 0x26
+
+/* TxDMAUrgentThresh specifies the minimum amount of
+ * data in the transmit FIFO before asserting an
+ * urgent transmit DMA request.
+ *
+ * Value Min TxFIFO occupied space before urgent TX request
+ * ---------------------------------------------------------------
+ * 0x00-0x04 128 bytes (1024 bits)
+ * 0x27 1248 bytes (~10000 bits)
+ * 0x30 1536 bytes (12288 bits)
+ * 0xFF 8192 bytes (65535 bits)
+ */
+#define IPG_TXDMAURGENTTHRESH_VALUE 0x04
+
+/* TxDMABurstThresh specifies the minimum amount of
+ * free space in the transmit FIFO before asserting an
+ * transmit DMA request.
+ *
+ * Value Min TxFIFO free space before TX request
+ * ----------------------------------------------------
+ * 0x00-0x08 256 bytes
+ * 0x30 1536 bytes
+ * 0xFF 8192 bytes
+ */
+#define IPG_TXDMABURSTTHRESH_VALUE 0x30
+
+/* RXDMAPollPeriod is specified in 320ns increments.
+ *
+ * Value Time
+ * ---------------------
+ * 0x00-0x01 320ns
+ * 0x03 ~1us
+ * 0x1F ~10us
+ * 0xFF ~82us
+ */
+#define IPG_RXDMAPOLLPERIOD_VALUE 0x01
+
+/* RxDMAUrgentThresh specifies the minimum amount of
+ * free space within the receive FIFO before asserting
+ * a urgent receive DMA request.
+ *
+ * Value Min RxFIFO free space before urgent RX request
+ * ---------------------------------------------------------------
+ * 0x00-0x04 128 bytes (1024 bits)
+ * 0x27 1248 bytes (~10000 bits)
+ * 0x30 1536 bytes (12288 bits)
+ * 0xFF 8192 bytes (65535 bits)
+ */
+#define IPG_RXDMAURGENTTHRESH_VALUE 0x30
+
+/* RxDMABurstThresh specifies the minimum amount of
+ * occupied space within the receive FIFO before asserting
+ * a receive DMA request.
+ *
+ * Value Min TxFIFO free space before TX request
+ * ----------------------------------------------------
+ * 0x00-0x08 256 bytes
+ * 0x30 1536 bytes
+ * 0xFF 8192 bytes
+ */
+#define IPG_RXDMABURSTTHRESH_VALUE 0x30
+
+/* FlowOnThresh specifies the maximum amount of occupied
+ * space in the receive FIFO before a PAUSE frame with
+ * maximum pause time transmitted.
+ *
+ * Value Max RxFIFO occupied space before PAUSE
+ * ---------------------------------------------------
+ * 0x0000 0 bytes
+ * 0x0740 29,696 bytes
+ * 0x07FF 32,752 bytes
+ */
+#define IPG_FLOWONTHRESH_VALUE 0x0740
+
+/* FlowOffThresh specifies the minimum amount of occupied
+ * space in the receive FIFO before a PAUSE frame with
+ * zero pause time is transmitted.
+ *
+ * Value Max RxFIFO occupied space before PAUSE
+ * ---------------------------------------------------
+ * 0x0000 0 bytes
+ * 0x00BF 3056 bytes
+ * 0x07FF 32,752 bytes
+ */
+#define IPG_FLOWOFFTHRESH_VALUE 0x00BF
+
+/*
+ * Miscellaneous macros.
+ */
+
+/* Marco for printing debug statements.
+# define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " ## args) */
+#ifdef IPG_DEBUG
+# define IPG_DEBUG_MSG(args...)
+# define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " args)
+# define IPG_DUMPRFDLIST(args) ipg_dump_rfdlist(args)
+# define IPG_DUMPTFDLIST(args) ipg_dump_tfdlist(args)
+#else
+# define IPG_DEBUG_MSG(args...)
+# define IPG_DDEBUG_MSG(args...)
+# define IPG_DUMPRFDLIST(args)
+# define IPG_DUMPTFDLIST(args)
+#endif
+
+/*
+ * End miscellaneous macros.
+ */
+
+/* Transmit Frame Descriptor. The IPG supports 15 fragments,
+ * however Linux requires only a single fragment. Note, each
+ * TFD field is 64 bits wide.
+ */
+struct ipg_tx {
+ __le64 next_desc;
+ __le64 tfc;
+ __le64 frag_info;
+};
+
+/* Receive Frame Descriptor. Note, each RFD field is 64 bits wide.
+ */
+struct ipg_rx {
+ __le64 next_desc;
+ __le64 rfs;
+ __le64 frag_info;
+};
+
+struct SJumbo {
+ int FoundStart;
+ int CurrentSize;
+ struct sk_buff *skb;
+};
+/* Structure of IPG NIC specific data. */
+struct ipg_nic_private {
+ void __iomem *ioaddr;
+ struct ipg_tx *txd;
+ struct ipg_rx *rxd;
+ dma_addr_t txd_map;
+ dma_addr_t rxd_map;
+ struct sk_buff *TxBuff[IPG_TFDLIST_LENGTH];
+ struct sk_buff *RxBuff[IPG_RFDLIST_LENGTH];
+ unsigned int tx_current;
+ unsigned int tx_dirty;
+ unsigned int rx_current;
+ unsigned int rx_dirty;
+// Add by Grace 2005/05/19
+#ifdef JUMBO_FRAME
+ struct SJumbo Jumbo;
+#endif
+ unsigned int rx_buf_sz;
+ struct pci_dev *pdev;
+ struct net_device *dev;
+ struct net_device_stats stats;
+ spinlock_t lock;
+ int tenmbpsmode;
+
+ /*Jesse20040128EEPROM_VALUE */
+ u16 LED_Mode;
+ u16 station_addr[3]; /* Station Address in EEPROM Reg 0x10..0x12 */
+
+ struct mutex mii_mutex;
+ struct mii_if_info mii_if;
+ int ResetCurrentTFD;
+#ifdef IPG_DEBUG
+ int RFDlistendCount;
+ int RFDListCheckedCount;
+ int EmptyRFDListCount;
+#endif
+ struct delayed_work task;
+};
+
+#endif /* __LINUX_IPG_H */
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 2098d0af8ff..65806956728 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -162,7 +162,33 @@ config EP7211_DONGLE
Say Y here if you want to build support for the Cirrus logic
EP7211 chipset's infrared module.
+config KSDAZZLE_DONGLE
+ tristate "KingSun Dazzle IrDA-USB dongle (EXPERIMENTAL)"
+ depends on IRDA && USB && EXPERIMENTAL
+ help
+ Say Y or M here if you want to build support for the KingSun Dazzle
+ IrDA-USB bridge device driver.
+
+ This USB bridge does not conform to the IrDA-USB device class
+ specification, and therefore needs its own specific driver. This
+ dongle supports SIR speeds only (9600 through 115200 bps).
+
+ To compile it as a module, choose M here: the module will be called
+ ksdazzle-sir.
+config KS959_DONGLE
+ tristate "KingSun KS-959 IrDA-USB dongle (EXPERIMENTAL)"
+ depends on IRDA && USB && EXPERIMENTAL
+ help
+ Say Y or M here if you want to build support for the KingSun KS-959
+ IrDA-USB bridge device driver.
+
+ This USB bridge does not conform to the IrDA-USB device class
+ specification, and therefore needs its own specific driver. This
+ dongle supports SIR speeds only (9600 through 57600 bps).
+
+ To compile it as a module, choose M here: the module will be called
+ ks959-sir.
comment "Old SIR device drivers"
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index 2808ef5c7b7..fefbb590908 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -47,6 +47,8 @@ obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o
obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o
obj-$(CONFIG_EP7211_DONGLE) += ep7211-sir.o
obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o
+obj-$(CONFIG_KSDAZZLE_DONGLE) += ksdazzle-sir.o
+obj-$(CONFIG_KS959_DONGLE) += ks959-sir.o
# The SIR helper module
sir-dev-objs := sir_dev.o sir_dongle.o
diff --git a/drivers/net/irda/actisys-sir.c b/drivers/net/irda/actisys-sir.c
index 9715ab5572e..736d2473b7e 100644
--- a/drivers/net/irda/actisys-sir.c
+++ b/drivers/net/irda/actisys-sir.c
@@ -21,7 +21,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
@@ -67,7 +67,7 @@ static int actisys_reset(struct sir_dev *);
/* Note : the 220L doesn't support 38400, but we will fix that below */
static unsigned baud_rates[] = { 9600, 19200, 57600, 115200, 38400 };
-#define MAX_SPEEDS (sizeof(baud_rates)/sizeof(baud_rates[0]))
+#define MAX_SPEEDS ARRAY_SIZE(baud_rates)
static struct dongle_driver act220l = {
.owner = THIS_MODULE,
diff --git a/drivers/net/irda/actisys.c b/drivers/net/irda/actisys.c
index b2e31f4a384..ae0b80a5680 100644
--- a/drivers/net/irda/actisys.c
+++ b/drivers/net/irda/actisys.c
@@ -19,7 +19,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index f9c889c0dd0..9f584521304 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -360,10 +360,6 @@ static int ali_ircc_open(int i, chipio_t *info)
self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
self->tx_fifo.tail = self->tx_buff.head;
-
- /* Keep track of module usage */
- SET_MODULE_OWNER(dev);
-
/* Override the network functions we need to use */
dev->hard_start_xmit = ali_ircc_sir_hard_xmit;
dev->open = ali_ircc_net_open;
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index 4dbdfaaf37b..a1e4508717c 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -627,19 +627,16 @@ static int au1k_irda_rx(struct net_device *dev)
}
-void au1k_irda_interrupt(int irq, void *dev_id)
+static irqreturn_t au1k_irda_interrupt(int dummy, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
-
- if (dev == NULL) {
- printk(KERN_ERR "%s: isr: null dev ptr\n", dev->name);
- return;
- }
+ struct net_device *dev = dev_id;
writel(0, IR_INT_CLEAR); /* ack irda interrupts */
au1k_irda_rx(dev);
au1k_tx_ack(dev);
+
+ return IRQ_HANDLED;
}
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 3ca47bf6dfe..1257e1a7e81 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -595,7 +595,7 @@ toshoboe_startchip (struct toshoboe_cb *self)
OUTB ((physaddr >> 18) & 0xff, OBOE_RING_BASE1);
OUTB ((physaddr >> 26) & 0x3f, OBOE_RING_BASE2);
- /*Enable DMA controler in byte mode and RX */
+ /*Enable DMA controller in byte mode and RX */
OUTB (CONFIG0H_DMA_ON, OBOE_CONFIG0H);
/* Start up the clocks */
@@ -840,7 +840,7 @@ toshoboe_probe (struct toshoboe_cb *self)
/* test 1: SIR filter and back to back */
- for (j = 0; j < (sizeof (bauds) / sizeof (int)); ++j)
+ for (j = 0; j < ARRAY_SIZE(bauds); ++j)
{
int fir = (j > 1);
toshoboe_stopchip (self);
@@ -1660,7 +1660,6 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid)
}
#endif
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pci_dev->dev);
dev->hard_start_xmit = toshoboe_hard_xmit;
dev->open = toshoboe_net_open;
diff --git a/drivers/net/irda/girbil-sir.c b/drivers/net/irda/girbil-sir.c
index 0d2fe87fb9b..738531b16bd 100644
--- a/drivers/net/irda/girbil-sir.c
+++ b/drivers/net/irda/girbil-sir.c
@@ -16,7 +16,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/drivers/net/irda/girbil.c b/drivers/net/irda/girbil.c
index 248aeb0c726..1f57391a618 100644
--- a/drivers/net/irda/girbil.c
+++ b/drivers/net/irda/girbil.c
@@ -16,7 +16,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 3b0fd83fa26..c6355c00fd7 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1635,7 +1635,6 @@ static int irda_usb_probe(struct usb_interface *intf,
if (!net)
goto err_out;
- SET_MODULE_OWNER(net);
SET_NETDEV_DEV(net, &intf->dev);
self = net->priv;
self->netdev = net;
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index 20732458f5a..c79caa5d3d7 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -175,8 +175,6 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
self->tx_buff.data = self->tx_buff.head;
self->netdev = dev;
- /* Keep track of module usage */
- SET_MODULE_OWNER(dev);
/* May be overridden by piggyback drivers */
self->interrupt = irport_interrupt;
diff --git a/drivers/net/irda/irport.h b/drivers/net/irda/irport.h
index 3f46b84c6c8..66fc2433e97 100644
--- a/drivers/net/irda/irport.h
+++ b/drivers/net/irda/irport.h
@@ -17,7 +17,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 6f5f697ec9f..fc753d7f674 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -20,7 +20,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
@@ -434,11 +434,6 @@ static int irtty_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
IRDA_ASSERT(dev != NULL, return -1;);
switch (cmd) {
- case TCGETS:
- case TCGETA:
- err = n_tty_ioctl(tty, file, cmd, arg);
- break;
-
case IRTTY_IOCTDONGLE:
/* this call blocks for completion */
err = sirdev_set_dongle(dev, (IRDA_DONGLE) arg);
@@ -454,7 +449,7 @@ static int irtty_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
err = -EFAULT;
break;
default:
- err = -ENOIOCTLCMD;
+ err = tty_mode_ioctl(tty, file, cmd, arg);
break;
}
return err;
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
index 4e5101a45c3..648e54b3f00 100644
--- a/drivers/net/irda/kingsun-sir.c
+++ b/drivers/net/irda/kingsun-sir.c
@@ -66,7 +66,6 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/module.h>
#include <linux/kref.h>
#include <linux/usb.h>
#include <linux/device.h>
@@ -488,7 +487,6 @@ static int kingsun_probe(struct usb_interface *intf,
if(!net)
goto err_out1;
- SET_MODULE_OWNER(net);
SET_NETDEV_DEV(net, &intf->dev);
kingsun = netdev_priv(net);
kingsun->irlap = NULL;
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
new file mode 100644
index 00000000000..8c257a51341
--- /dev/null
+++ b/drivers/net/irda/ks959-sir.c
@@ -0,0 +1,938 @@
+/*****************************************************************************
+*
+* Filename: ks959-sir.c
+* Version: 0.1.2
+* Description: Irda KingSun KS-959 USB Dongle
+* Status: Experimental
+* Author: Alex Villacís Lasso <a_villacis@palosanto.com>
+* with help from Domen Puncer <domen@coderock.org>
+*
+* Based on stir4200, mcs7780, kingsun-sir drivers.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*****************************************************************************/
+
+/*
+ * Following is my most current (2007-07-17) understanding of how the Kingsun
+ * KS-959 dongle is supposed to work. This information was deduced by
+ * reverse-engineering and examining the USB traffic captured with USBSnoopy
+ * from the WinXP driver. Feel free to update here as more of the dongle is
+ * known.
+ *
+ * My most sincere thanks must go to Domen Puncer <domen@coderock.org> for
+ * invaluable help in cracking the obfuscation and padding required for this
+ * dongle.
+ *
+ * General: This dongle exposes one interface with one interrupt IN endpoint.
+ * However, the interrupt endpoint is NOT used at all for this dongle. Instead,
+ * this dongle uses control transfers for everything, including sending and
+ * receiving the IrDA frame data. Apparently the interrupt endpoint is just a
+ * dummy to ensure the dongle has a valid interface to present to the PC.And I
+ * thought the DonShine dongle was weird... In addition, this dongle uses
+ * obfuscation (?!?!), applied at the USB level, to hide the traffic, both sent
+ * and received, from the dongle. I call it obfuscation because the XOR keying
+ * and padding required to produce an USB traffic acceptable for the dongle can
+ * not be explained by any other technical requirement.
+ *
+ * Transmission: To transmit an IrDA frame, the driver must prepare a control
+ * URB with the following as a setup packet:
+ * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ * bRequest 0x09
+ * wValue <length of valid data before padding, little endian>
+ * wIndex 0x0000
+ * wLength <length of padded data>
+ * The payload packet must be manually wrapped and escaped (as in stir4200.c),
+ * then padded and obfuscated before being sent. Both padding and obfuscation
+ * are implemented in the procedure obfuscate_tx_buffer(). Suffice to say, the
+ * designer/programmer of the dongle used his name as a source for the
+ * obfuscation. WTF?!
+ * Apparently the dongle cannot handle payloads larger than 256 bytes. The
+ * driver has to perform fragmentation in order to send anything larger than
+ * this limit.
+ *
+ * Reception: To receive data, the driver must poll the dongle regularly (like
+ * kingsun-sir.c) with control URBs and the following as a setup packet:
+ * bRequestType USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ * bRequest 0x01
+ * wValue 0x0200
+ * wIndex 0x0000
+ * wLength 0x0800 (size of available buffer)
+ * If there is data to be read, it will be returned as the response payload.
+ * This data is (apparently) not padded, but it is obfuscated. To de-obfuscate
+ * it, the driver must XOR every byte, in sequence, with a value that starts at
+ * 1 and is incremented with each byte processed, and then with 0x55. The value
+ * incremented with each byte processed overflows as an unsigned char. The
+ * resulting bytes form a wrapped SIR frame that is unwrapped and unescaped
+ * as in stir4200.c The incremented value is NOT reset with each frame, but is
+ * kept across the entire session with the dongle. Also, the dongle inserts an
+ * extra garbage byte with value 0x95 (after decoding) every 0xff bytes, which
+ * must be skipped.
+ *
+ * Speed change: To change the speed of the dongle, the driver prepares a
+ * control URB with the following as a setup packet:
+ * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ * bRequest 0x09
+ * wValue 0x0200
+ * wIndex 0x0001
+ * wLength 0x0008 (length of the payload)
+ * The payload is a 8-byte record, apparently identical to the one used in
+ * drivers/usb/serial/cypress_m8.c to change speed:
+ * __u32 baudSpeed;
+ * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits
+ * unsigned int : 1;
+ * unsigned int stopBits : 1;
+ * unsigned int parityEnable : 1;
+ * unsigned int parityType : 1;
+ * unsigned int : 1;
+ * unsigned int reset : 1;
+ * unsigned char reserved[3]; // set to 0
+ *
+ * For now only SIR speeds have been observed with this dongle. Therefore,
+ * nothing is known on what changes (if any) must be done to frame wrapping /
+ * unwrapping for higher than SIR speeds. This driver assumes no change is
+ * necessary and announces support for all the way to 57600 bps. Although the
+ * package announces support for up to 4MBps, tests with a Sony Ericcson K300
+ * phone show corruption when receiving large frames at 115200 bps, the highest
+ * speed announced by the phone. However, transmission at 115200 bps is OK. Go
+ * figure. Since I don't know whether the phone or the dongle is at fault, max
+ * announced speed is 57600 bps until someone produces a device that can run
+ * at higher speeds with this dongle.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/crc32.h>
+
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/crc.h>
+
+#define KS959_VENDOR_ID 0x07d0
+#define KS959_PRODUCT_ID 0x4959
+
+/* These are the currently known USB ids */
+static struct usb_device_id dongles[] = {
+ /* KingSun Co,Ltd IrDA/USB Bridge */
+ {USB_DEVICE(KS959_VENDOR_ID, KS959_PRODUCT_ID)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, dongles);
+
+#define KINGSUN_MTT 0x07
+#define KINGSUN_REQ_RECV 0x01
+#define KINGSUN_REQ_SEND 0x09
+
+#define KINGSUN_RCV_FIFO_SIZE 2048 /* Max length we can receive */
+#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */
+#define KINGSUN_SND_PACKET_SIZE 256 /* Max packet dongle can handle */
+
+struct ks959_speedparams {
+ __le32 baudrate; /* baud rate, little endian */
+ __u8 flags;
+ __u8 reserved[3];
+} __attribute__ ((packed));
+
+#define KS_DATA_5_BITS 0x00
+#define KS_DATA_6_BITS 0x01
+#define KS_DATA_7_BITS 0x02
+#define KS_DATA_8_BITS 0x03
+
+#define KS_STOP_BITS_1 0x00
+#define KS_STOP_BITS_2 0x08
+
+#define KS_PAR_DISABLE 0x00
+#define KS_PAR_EVEN 0x10
+#define KS_PAR_ODD 0x30
+#define KS_RESET 0x80
+
+struct ks959_cb {
+ struct usb_device *usbdev; /* init: probe_irda */
+ struct net_device *netdev; /* network layer */
+ struct irlap_cb *irlap; /* The link layer we are binded to */
+ struct net_device_stats stats; /* network statistics */
+ struct qos_info qos;
+
+ struct usb_ctrlrequest *tx_setuprequest;
+ struct urb *tx_urb;
+ __u8 *tx_buf_clear;
+ unsigned int tx_buf_clear_used;
+ unsigned int tx_buf_clear_sent;
+ __u8 *tx_buf_xored;
+
+ struct usb_ctrlrequest *rx_setuprequest;
+ struct urb *rx_urb;
+ __u8 *rx_buf;
+ __u8 rx_variable_xormask;
+ iobuff_t rx_unwrap_buff;
+ struct timeval rx_time;
+
+ struct usb_ctrlrequest *speed_setuprequest;
+ struct urb *speed_urb;
+ struct ks959_speedparams speedparams;
+ unsigned int new_speed;
+
+ spinlock_t lock;
+ int receiving;
+};
+
+/* Procedure to perform the obfuscation/padding expected by the dongle
+ *
+ * buf_cleartext (IN) Cleartext version of the IrDA frame to transmit
+ * len_cleartext (IN) Length of the cleartext version of IrDA frame
+ * buf_xoredtext (OUT) Obfuscated version of frame built by proc
+ * len_maxbuf (OUT) Maximum space available at buf_xoredtext
+ *
+ * (return) length of obfuscated frame with padding
+ *
+ * If not enough space (as indicated by len_maxbuf vs. required padding),
+ * zero is returned
+ *
+ * The value of lookup_string is actually a required portion of the algorithm.
+ * Seems the designer of the dongle wanted to state who exactly is responsible
+ * for implementing obfuscation. Send your best (or other) wishes to him ]:-)
+ */
+static unsigned int obfuscate_tx_buffer(const __u8 * buf_cleartext,
+ unsigned int len_cleartext,
+ __u8 * buf_xoredtext,
+ unsigned int len_maxbuf)
+{
+ unsigned int len_xoredtext;
+
+ /* Calculate required length with padding, check for necessary space */
+ len_xoredtext = ((len_cleartext + 7) & ~0x7) + 0x10;
+ if (len_xoredtext <= len_maxbuf) {
+ static const __u8 lookup_string[] = "wangshuofei19710";
+ __u8 xor_mask;
+
+ /* Unlike the WinXP driver, we *do* clear out the padding */
+ memset(buf_xoredtext, 0, len_xoredtext);
+
+ xor_mask = lookup_string[(len_cleartext & 0x0f) ^ 0x06] ^ 0x55;
+
+ while (len_cleartext-- > 0) {
+ *buf_xoredtext++ = *buf_cleartext++ ^ xor_mask;
+ }
+ } else {
+ len_xoredtext = 0;
+ }
+ return len_xoredtext;
+}
+
+/* Callback transmission routine */
+static void ks959_speed_irq(struct urb *urb)
+{
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("ks959_speed_irq: urb asynchronously failed - %d",
+ urb->status);
+ }
+}
+
+/* Send a control request to change speed of the dongle */
+static int ks959_change_speed(struct ks959_cb *kingsun, unsigned speed)
+{
+ static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400,
+ 57600, 115200, 576000, 1152000, 4000000, 0
+ };
+ int err;
+ unsigned int i;
+
+ if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL)
+ return -ENOMEM;
+
+ /* Check that requested speed is among the supported ones */
+ for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ;
+ if (supported_speeds[i] == 0)
+ return -EOPNOTSUPP;
+
+ memset(&(kingsun->speedparams), 0, sizeof(struct ks959_speedparams));
+ kingsun->speedparams.baudrate = cpu_to_le32(speed);
+ kingsun->speedparams.flags = KS_DATA_8_BITS;
+
+ /* speed_setuprequest pre-filled in ks959_probe */
+ usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev,
+ usb_sndctrlpipe(kingsun->usbdev, 0),
+ (unsigned char *)kingsun->speed_setuprequest,
+ &(kingsun->speedparams),
+ sizeof(struct ks959_speedparams), ks959_speed_irq,
+ kingsun);
+ kingsun->speed_urb->status = 0;
+ err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC);
+
+ return err;
+}
+
+/* Submit one fragment of an IrDA frame to the dongle */
+static void ks959_send_irq(struct urb *urb);
+static int ks959_submit_tx_fragment(struct ks959_cb *kingsun)
+{
+ unsigned int padlen;
+ unsigned int wraplen;
+ int ret;
+
+ /* Check whether current plaintext can produce a padded buffer that fits
+ within the range handled by the dongle */
+ wraplen = (KINGSUN_SND_PACKET_SIZE & ~0x7) - 0x10;
+ if (wraplen > kingsun->tx_buf_clear_used)
+ wraplen = kingsun->tx_buf_clear_used;
+
+ /* Perform dongle obfuscation. Also remove the portion of the frame that
+ was just obfuscated and will now be sent to the dongle. */
+ padlen = obfuscate_tx_buffer(kingsun->tx_buf_clear, wraplen,
+ kingsun->tx_buf_xored,
+ KINGSUN_SND_PACKET_SIZE);
+
+ /* Calculate how much data can be transmitted in this urb */
+ kingsun->tx_setuprequest->wValue = cpu_to_le16(wraplen);
+ kingsun->tx_setuprequest->wLength = cpu_to_le16(padlen);
+ /* Rest of the fields were filled in ks959_probe */
+ usb_fill_control_urb(kingsun->tx_urb, kingsun->usbdev,
+ usb_sndctrlpipe(kingsun->usbdev, 0),
+ (unsigned char *)kingsun->tx_setuprequest,
+ kingsun->tx_buf_xored, padlen,
+ ks959_send_irq, kingsun);
+ kingsun->tx_urb->status = 0;
+ ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC);
+
+ /* Remember how much data was sent, in order to update at callback */
+ kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0;
+ return ret;
+}
+
+/* Callback transmission routine */
+static void ks959_send_irq(struct urb *urb)
+{
+ struct ks959_cb *kingsun = urb->context;
+ struct net_device *netdev = kingsun->netdev;
+ int ret = 0;
+
+ /* in process of stopping, just drop data */
+ if (!netif_running(kingsun->netdev)) {
+ err("ks959_send_irq: Network not running!");
+ return;
+ }
+
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("ks959_send_irq: urb asynchronously failed - %d",
+ urb->status);
+ return;
+ }
+
+ if (kingsun->tx_buf_clear_used > 0) {
+ /* Update data remaining to be sent */
+ if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) {
+ memmove(kingsun->tx_buf_clear,
+ kingsun->tx_buf_clear +
+ kingsun->tx_buf_clear_sent,
+ kingsun->tx_buf_clear_used -
+ kingsun->tx_buf_clear_sent);
+ }
+ kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent;
+ kingsun->tx_buf_clear_sent = 0;
+
+ if (kingsun->tx_buf_clear_used > 0) {
+ /* There is more data to be sent */
+ if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
+ err("ks959_send_irq: failed tx_urb submit: %d",
+ ret);
+ switch (ret) {
+ case -ENODEV:
+ case -EPIPE:
+ break;
+ default:
+ kingsun->stats.tx_errors++;
+ netif_start_queue(netdev);
+ }
+ }
+ } else {
+ /* All data sent, send next speed && wake network queue */
+ if (kingsun->new_speed != -1 &&
+ cpu_to_le32(kingsun->new_speed) !=
+ kingsun->speedparams.baudrate)
+ ks959_change_speed(kingsun, kingsun->new_speed);
+
+ netif_wake_queue(netdev);
+ }
+ }
+}
+
+/*
+ * Called from net/core when new frame is available.
+ */
+static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct ks959_cb *kingsun;
+ unsigned int wraplen;
+ int ret = 0;
+
+ if (skb == NULL || netdev == NULL)
+ return -EINVAL;
+
+ netif_stop_queue(netdev);
+
+ /* the IRDA wrapping routines don't deal with non linear skb */
+ SKB_LINEAR_ASSERT(skb);
+
+ kingsun = netdev_priv(netdev);
+
+ spin_lock(&kingsun->lock);
+ kingsun->new_speed = irda_get_next_speed(skb);
+
+ /* Append data to the end of whatever data remains to be transmitted */
+ wraplen =
+ async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE);
+ kingsun->tx_buf_clear_used = wraplen;
+
+ if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
+ err("ks959_hard_xmit: failed tx_urb submit: %d", ret);
+ switch (ret) {
+ case -ENODEV:
+ case -EPIPE:
+ break;
+ default:
+ kingsun->stats.tx_errors++;
+ netif_start_queue(netdev);
+ }
+ } else {
+ kingsun->stats.tx_packets++;
+ kingsun->stats.tx_bytes += skb->len;
+
+ }
+
+ dev_kfree_skb(skb);
+ spin_unlock(&kingsun->lock);
+
+ return ret;
+}
+
+/* Receive callback function */
+static void ks959_rcv_irq(struct urb *urb)
+{
+ struct ks959_cb *kingsun = urb->context;
+ int ret;
+
+ /* in process of stopping, just drop data */
+ if (!netif_running(kingsun->netdev)) {
+ kingsun->receiving = 0;
+ return;
+ }
+
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("kingsun_rcv_irq: urb asynchronously failed - %d",
+ urb->status);
+ kingsun->receiving = 0;
+ return;
+ }
+
+ if (urb->actual_length > 0) {
+ __u8 *bytes = urb->transfer_buffer;
+ unsigned int i;
+
+ for (i = 0; i < urb->actual_length; i++) {
+ /* De-obfuscation implemented here: variable portion of
+ xormask is incremented, and then used with the encoded
+ byte for the XOR. The result of the operation is used
+ to unwrap the SIR frame. */
+ kingsun->rx_variable_xormask++;
+ bytes[i] =
+ bytes[i] ^ kingsun->rx_variable_xormask ^ 0x55u;
+
+ /* rx_variable_xormask doubles as an index counter so we
+ can skip the byte at 0xff (wrapped around to 0).
+ */
+ if (kingsun->rx_variable_xormask != 0) {
+ async_unwrap_char(kingsun->netdev,
+ &kingsun->stats,
+ &kingsun->rx_unwrap_buff,
+ bytes[i]);
+ }
+ }
+ kingsun->netdev->last_rx = jiffies;
+ do_gettimeofday(&kingsun->rx_time);
+ kingsun->receiving =
+ (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
+ }
+
+ /* This urb has already been filled in kingsun_net_open. Setup
+ packet must be re-filled, but it is assumed that urb keeps the
+ pointer to the initial setup packet, as well as the payload buffer.
+ Setup packet is already pre-filled at ks959_probe.
+ */
+ urb->status = 0;
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/*
+ * Function kingsun_net_open (dev)
+ *
+ * Network device is taken up. Usually this is done by "ifconfig irda0 up"
+ */
+static int ks959_net_open(struct net_device *netdev)
+{
+ struct ks959_cb *kingsun = netdev_priv(netdev);
+ int err = -ENOMEM;
+ char hwname[16];
+
+ /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
+ kingsun->receiving = 0;
+
+ /* Initialize for SIR to copy data directly into skb. */
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU;
+ kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+ if (!kingsun->rx_unwrap_buff.skb)
+ goto free_mem;
+
+ skb_reserve(kingsun->rx_unwrap_buff.skb, 1);
+ kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data;
+ do_gettimeofday(&kingsun->rx_time);
+
+ kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->rx_urb)
+ goto free_mem;
+
+ kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->tx_urb)
+ goto free_mem;
+
+ kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->speed_urb)
+ goto free_mem;
+
+ /* Initialize speed for dongle */
+ kingsun->new_speed = 9600;
+ err = ks959_change_speed(kingsun, 9600);
+ if (err < 0)
+ goto free_mem;
+
+ /*
+ * Now that everything should be initialized properly,
+ * Open new IrLAP layer instance to take care of us...
+ */
+ sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
+ kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
+ if (!kingsun->irlap) {
+ err("ks959-sir: irlap_open failed");
+ goto free_mem;
+ }
+
+ /* Start reception. Setup request already pre-filled in ks959_probe */
+ usb_fill_control_urb(kingsun->rx_urb, kingsun->usbdev,
+ usb_rcvctrlpipe(kingsun->usbdev, 0),
+ (unsigned char *)kingsun->rx_setuprequest,
+ kingsun->rx_buf, KINGSUN_RCV_FIFO_SIZE,
+ ks959_rcv_irq, kingsun);
+ kingsun->rx_urb->status = 0;
+ err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+ if (err) {
+ err("ks959-sir: first urb-submit failed: %d", err);
+ goto close_irlap;
+ }
+
+ netif_start_queue(netdev);
+
+ /* Situation at this point:
+ - all work buffers allocated
+ - urbs allocated and ready to fill
+ - max rx packet known (in max_rx)
+ - unwrap state machine initialized, in state outside of any frame
+ - receive request in progress
+ - IrLAP layer started, about to hand over packets to send
+ */
+
+ return 0;
+
+ close_irlap:
+ irlap_close(kingsun->irlap);
+ free_mem:
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+ if (kingsun->rx_unwrap_buff.skb) {
+ kfree_skb(kingsun->rx_unwrap_buff.skb);
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->rx_unwrap_buff.head = NULL;
+ }
+ return err;
+}
+
+/*
+ * Function kingsun_net_close (kingsun)
+ *
+ * Network device is taken down. Usually this is done by
+ * "ifconfig irda0 down"
+ */
+static int ks959_net_close(struct net_device *netdev)
+{
+ struct ks959_cb *kingsun = netdev_priv(netdev);
+
+ /* Stop transmit processing */
+ netif_stop_queue(netdev);
+
+ /* Mop up receive && transmit urb's */
+ usb_kill_urb(kingsun->tx_urb);
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+
+ usb_kill_urb(kingsun->speed_urb);
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+
+ usb_kill_urb(kingsun->rx_urb);
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+
+ kfree_skb(kingsun->rx_unwrap_buff.skb);
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->rx_unwrap_buff.head = NULL;
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->receiving = 0;
+
+ /* Stop and remove instance of IrLAP */
+ if (kingsun->irlap)
+ irlap_close(kingsun->irlap);
+
+ kingsun->irlap = NULL;
+
+ return 0;
+}
+
+/*
+ * IOCTLs : Extra out-of-band network commands...
+ */
+static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+ struct if_irda_req *irq = (struct if_irda_req *)rq;
+ struct ks959_cb *kingsun = netdev_priv(netdev);
+ int ret = 0;
+
+ switch (cmd) {
+ case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /* Check if the device is still there */
+ if (netif_device_present(kingsun->netdev))
+ return ks959_change_speed(kingsun, irq->ifr_baudrate);
+ break;
+
+ case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /* Check if the IrDA stack is still there */
+ if (netif_running(kingsun->netdev))
+ irda_device_set_media_busy(kingsun->netdev, TRUE);
+ break;
+
+ case SIOCGRECEIVING:
+ /* Only approximately true */
+ irq->ifr_receiving = kingsun->receiving;
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+/*
+ * Get device stats (for /proc/net/dev and ifconfig)
+ */
+static struct net_device_stats *ks959_net_get_stats(struct net_device *netdev)
+{
+ struct ks959_cb *kingsun = netdev_priv(netdev);
+ return &kingsun->stats;
+}
+
+/*
+ * This routine is called by the USB subsystem for each new device
+ * in the system. We need to check if the device is ours, and in
+ * this case start handling it.
+ */
+static int ks959_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct ks959_cb *kingsun = NULL;
+ struct net_device *net = NULL;
+ int ret = -ENOMEM;
+
+ /* Allocate network device container. */
+ net = alloc_irdadev(sizeof(*kingsun));
+ if (!net)
+ goto err_out1;
+
+ SET_NETDEV_DEV(net, &intf->dev);
+ kingsun = netdev_priv(net);
+ kingsun->netdev = net;
+ kingsun->usbdev = dev;
+ kingsun->irlap = NULL;
+ kingsun->tx_setuprequest = NULL;
+ kingsun->tx_urb = NULL;
+ kingsun->tx_buf_clear = NULL;
+ kingsun->tx_buf_xored = NULL;
+ kingsun->tx_buf_clear_used = 0;
+ kingsun->tx_buf_clear_sent = 0;
+
+ kingsun->rx_setuprequest = NULL;
+ kingsun->rx_urb = NULL;
+ kingsun->rx_buf = NULL;
+ kingsun->rx_variable_xormask = 0;
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->receiving = 0;
+ spin_lock_init(&kingsun->lock);
+
+ kingsun->speed_setuprequest = NULL;
+ kingsun->speed_urb = NULL;
+ kingsun->speedparams.baudrate = 0;
+
+ /* Allocate input buffer */
+ kingsun->rx_buf = kmalloc(KINGSUN_RCV_FIFO_SIZE, GFP_KERNEL);
+ if (!kingsun->rx_buf)
+ goto free_mem;
+
+ /* Allocate input setup packet */
+ kingsun->rx_setuprequest =
+ kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!kingsun->rx_setuprequest)
+ goto free_mem;
+ kingsun->rx_setuprequest->bRequestType =
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ kingsun->rx_setuprequest->bRequest = KINGSUN_REQ_RECV;
+ kingsun->rx_setuprequest->wValue = cpu_to_le16(0x0200);
+ kingsun->rx_setuprequest->wIndex = 0;
+ kingsun->rx_setuprequest->wLength = cpu_to_le16(KINGSUN_RCV_FIFO_SIZE);
+
+ /* Allocate output buffer */
+ kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL);
+ if (!kingsun->tx_buf_clear)
+ goto free_mem;
+ kingsun->tx_buf_xored = kmalloc(KINGSUN_SND_PACKET_SIZE, GFP_KERNEL);
+ if (!kingsun->tx_buf_xored)
+ goto free_mem;
+
+ /* Allocate and initialize output setup packet */
+ kingsun->tx_setuprequest =
+ kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!kingsun->tx_setuprequest)
+ goto free_mem;
+ kingsun->tx_setuprequest->bRequestType =
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ kingsun->tx_setuprequest->bRequest = KINGSUN_REQ_SEND;
+ kingsun->tx_setuprequest->wValue = 0;
+ kingsun->tx_setuprequest->wIndex = 0;
+ kingsun->tx_setuprequest->wLength = 0;
+
+ /* Allocate and initialize speed setup packet */
+ kingsun->speed_setuprequest =
+ kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!kingsun->speed_setuprequest)
+ goto free_mem;
+ kingsun->speed_setuprequest->bRequestType =
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND;
+ kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200);
+ kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001);
+ kingsun->speed_setuprequest->wLength =
+ cpu_to_le16(sizeof(struct ks959_speedparams));
+
+ printk(KERN_INFO "KingSun KS-959 IRDA/USB found at address %d, "
+ "Vendor: %x, Product: %x\n",
+ dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
+
+ /* Initialize QoS for this device */
+ irda_init_max_qos_capabilies(&kingsun->qos);
+
+ /* Baud rates known to be supported. Please uncomment if devices (other
+ than a SonyEriccson K300 phone) can be shown to support higher speed
+ with this dongle.
+ */
+ kingsun->qos.baud_rate.bits =
+ IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600;
+ kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
+ irda_qos_bits_to_value(&kingsun->qos);
+
+ /* Override the network functions we need to use */
+ net->hard_start_xmit = ks959_hard_xmit;
+ net->open = ks959_net_open;
+ net->stop = ks959_net_close;
+ net->get_stats = ks959_net_get_stats;
+ net->do_ioctl = ks959_net_ioctl;
+
+ ret = register_netdev(net);
+ if (ret != 0)
+ goto free_mem;
+
+ info("IrDA: Registered KingSun KS-959 device %s", net->name);
+
+ usb_set_intfdata(intf, kingsun);
+
+ /* Situation at this point:
+ - all work buffers allocated
+ - setup requests pre-filled
+ - urbs not allocated, set to NULL
+ - max rx packet known (is KINGSUN_FIFO_SIZE)
+ - unwrap state machine (partially) initialized, but skb == NULL
+ */
+
+ return 0;
+
+ free_mem:
+ kfree(kingsun->speed_setuprequest);
+ kfree(kingsun->tx_setuprequest);
+ kfree(kingsun->tx_buf_xored);
+ kfree(kingsun->tx_buf_clear);
+ kfree(kingsun->rx_setuprequest);
+ kfree(kingsun->rx_buf);
+ free_netdev(net);
+ err_out1:
+ return ret;
+}
+
+/*
+ * The current device is removed, the USB layer tell us to shut it down...
+ */
+static void ks959_disconnect(struct usb_interface *intf)
+{
+ struct ks959_cb *kingsun = usb_get_intfdata(intf);
+
+ if (!kingsun)
+ return;
+
+ unregister_netdev(kingsun->netdev);
+
+ /* Mop up receive && transmit urb's */
+ if (kingsun->speed_urb != NULL) {
+ usb_kill_urb(kingsun->speed_urb);
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+ }
+ if (kingsun->tx_urb != NULL) {
+ usb_kill_urb(kingsun->tx_urb);
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+ }
+ if (kingsun->rx_urb != NULL) {
+ usb_kill_urb(kingsun->rx_urb);
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+ }
+
+ kfree(kingsun->speed_setuprequest);
+ kfree(kingsun->tx_setuprequest);
+ kfree(kingsun->tx_buf_xored);
+ kfree(kingsun->tx_buf_clear);
+ kfree(kingsun->rx_setuprequest);
+ kfree(kingsun->rx_buf);
+ free_netdev(kingsun->netdev);
+
+ usb_set_intfdata(intf, NULL);
+}
+
+#ifdef CONFIG_PM
+/* USB suspend, so power off the transmitter/receiver */
+static int ks959_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct ks959_cb *kingsun = usb_get_intfdata(intf);
+
+ netif_device_detach(kingsun->netdev);
+ if (kingsun->speed_urb != NULL)
+ usb_kill_urb(kingsun->speed_urb);
+ if (kingsun->tx_urb != NULL)
+ usb_kill_urb(kingsun->tx_urb);
+ if (kingsun->rx_urb != NULL)
+ usb_kill_urb(kingsun->rx_urb);
+ return 0;
+}
+
+/* Coming out of suspend, so reset hardware */
+static int ks959_resume(struct usb_interface *intf)
+{
+ struct ks959_cb *kingsun = usb_get_intfdata(intf);
+
+ if (kingsun->rx_urb != NULL) {
+ /* Setup request already filled in ks959_probe */
+ usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+ }
+ netif_device_attach(kingsun->netdev);
+
+ return 0;
+}
+#endif
+
+/*
+ * USB device callbacks
+ */
+static struct usb_driver irda_driver = {
+ .name = "ks959-sir",
+ .probe = ks959_probe,
+ .disconnect = ks959_disconnect,
+ .id_table = dongles,
+#ifdef CONFIG_PM
+ .suspend = ks959_suspend,
+ .resume = ks959_resume,
+#endif
+};
+
+/*
+ * Module insertion
+ */
+static int __init ks959_init(void)
+{
+ return usb_register(&irda_driver);
+}
+
+module_init(ks959_init);
+
+/*
+ * Module removal
+ */
+static void __exit ks959_cleanup(void)
+{
+ /* Deregister the driver and remove all pending instances */
+ usb_deregister(&irda_driver);
+}
+
+module_exit(ks959_cleanup);
+
+MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun KS-959");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c
new file mode 100644
index 00000000000..d01a28593ce
--- /dev/null
+++ b/drivers/net/irda/ksdazzle-sir.c
@@ -0,0 +1,832 @@
+/*****************************************************************************
+*
+* Filename: ksdazzle.c
+* Version: 0.1.2
+* Description: Irda KingSun Dazzle USB Dongle
+* Status: Experimental
+* Author: Alex Villacís Lasso <a_villacis@palosanto.com>
+*
+* Based on stir4200, mcs7780, kingsun-sir drivers.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*****************************************************************************/
+
+/*
+ * Following is my most current (2007-07-26) understanding of how the Kingsun
+ * 07D0:4100 dongle (sometimes known as the MA-660) is supposed to work. This
+ * information was deduced by examining the USB traffic captured with USBSnoopy
+ * from the WinXP driver. Feel free to update here as more of the dongle is
+ * known.
+ *
+ * General: This dongle exposes one interface with two interrupt endpoints, one
+ * IN and one OUT. In this regard, it is similar to what the Kingsun/Donshine
+ * dongle (07c0:4200) exposes. Traffic is raw and needs to be wrapped and
+ * unwrapped manually as in stir4200, kingsun-sir, and ks959-sir.
+ *
+ * Transmission: To transmit an IrDA frame, it is necessary to wrap it, then
+ * split it into multiple segments of up to 7 bytes each, and transmit each in
+ * sequence. It seems that sending a single big block (like kingsun-sir does)
+ * won't work with this dongle. Each segment needs to be prefixed with a value
+ * equal to (unsigned char)0xF8 + <number of bytes in segment>, inside a payload
+ * of exactly 8 bytes. For example, a segment of 1 byte gets prefixed by 0xF9,
+ * and one of 7 bytes gets prefixed by 0xFF. The bytes at the end of the
+ * payload, not considered by the prefix, are ignored (set to 0 by this
+ * implementation).
+ *
+ * Reception: To receive data, the driver must poll the dongle regularly (like
+ * kingsun-sir.c) with interrupt URBs. If data is available, it will be returned
+ * in payloads from 0 to 8 bytes long. When concatenated, these payloads form
+ * a raw IrDA stream that needs to be unwrapped as in stir4200 and kingsun-sir
+ *
+ * Speed change: To change the speed of the dongle, the driver prepares a
+ * control URB with the following as a setup packet:
+ * bRequestType USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ * bRequest 0x09
+ * wValue 0x0200
+ * wIndex 0x0001
+ * wLength 0x0008 (length of the payload)
+ * The payload is a 8-byte record, apparently identical to the one used in
+ * drivers/usb/serial/cypress_m8.c to change speed:
+ * __u32 baudSpeed;
+ * unsigned int dataBits : 2; // 0 - 5 bits 3 - 8 bits
+ * unsigned int : 1;
+ * unsigned int stopBits : 1;
+ * unsigned int parityEnable : 1;
+ * unsigned int parityType : 1;
+ * unsigned int : 1;
+ * unsigned int reset : 1;
+ * unsigned char reserved[3]; // set to 0
+ *
+ * For now only SIR speeds have been observed with this dongle. Therefore,
+ * nothing is known on what changes (if any) must be done to frame wrapping /
+ * unwrapping for higher than SIR speeds. This driver assumes no change is
+ * necessary and announces support for all the way to 115200 bps.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/crc32.h>
+
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/crc.h>
+
+#define KSDAZZLE_VENDOR_ID 0x07d0
+#define KSDAZZLE_PRODUCT_ID 0x4100
+
+/* These are the currently known USB ids */
+static struct usb_device_id dongles[] = {
+ /* KingSun Co,Ltd IrDA/USB Bridge */
+ {USB_DEVICE(KSDAZZLE_VENDOR_ID, KSDAZZLE_PRODUCT_ID)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, dongles);
+
+#define KINGSUN_MTT 0x07
+#define KINGSUN_REQ_RECV 0x01
+#define KINGSUN_REQ_SEND 0x09
+
+#define KINGSUN_SND_FIFO_SIZE 2048 /* Max packet we can send */
+#define KINGSUN_RCV_MAX 2048 /* Max transfer we can receive */
+
+struct ksdazzle_speedparams {
+ __le32 baudrate; /* baud rate, little endian */
+ __u8 flags;
+ __u8 reserved[3];
+} __attribute__ ((packed));
+
+#define KS_DATA_5_BITS 0x00
+#define KS_DATA_6_BITS 0x01
+#define KS_DATA_7_BITS 0x02
+#define KS_DATA_8_BITS 0x03
+
+#define KS_STOP_BITS_1 0x00
+#define KS_STOP_BITS_2 0x08
+
+#define KS_PAR_DISABLE 0x00
+#define KS_PAR_EVEN 0x10
+#define KS_PAR_ODD 0x30
+#define KS_RESET 0x80
+
+#define KINGSUN_EP_IN 0
+#define KINGSUN_EP_OUT 1
+
+struct ksdazzle_cb {
+ struct usb_device *usbdev; /* init: probe_irda */
+ struct net_device *netdev; /* network layer */
+ struct irlap_cb *irlap; /* The link layer we are binded to */
+ struct net_device_stats stats; /* network statistics */
+ struct qos_info qos;
+
+ struct urb *tx_urb;
+ __u8 *tx_buf_clear;
+ unsigned int tx_buf_clear_used;
+ unsigned int tx_buf_clear_sent;
+ __u8 tx_payload[8];
+
+ struct urb *rx_urb;
+ __u8 *rx_buf;
+ iobuff_t rx_unwrap_buff;
+
+ struct usb_ctrlrequest *speed_setuprequest;
+ struct urb *speed_urb;
+ struct ksdazzle_speedparams speedparams;
+ unsigned int new_speed;
+
+ __u8 ep_in;
+ __u8 ep_out;
+
+ spinlock_t lock;
+ int receiving;
+};
+
+/* Callback transmission routine */
+static void ksdazzle_speed_irq(struct urb *urb)
+{
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("ksdazzle_speed_irq: urb asynchronously failed - %d",
+ urb->status);
+ }
+}
+
+/* Send a control request to change speed of the dongle */
+static int ksdazzle_change_speed(struct ksdazzle_cb *kingsun, unsigned speed)
+{
+ static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400,
+ 57600, 115200, 576000, 1152000, 4000000, 0
+ };
+ int err;
+ unsigned int i;
+
+ if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL)
+ return -ENOMEM;
+
+ /* Check that requested speed is among the supported ones */
+ for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ;
+ if (supported_speeds[i] == 0)
+ return -EOPNOTSUPP;
+
+ memset(&(kingsun->speedparams), 0, sizeof(struct ksdazzle_speedparams));
+ kingsun->speedparams.baudrate = cpu_to_le32(speed);
+ kingsun->speedparams.flags = KS_DATA_8_BITS;
+
+ /* speed_setuprequest pre-filled in ksdazzle_probe */
+ usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev,
+ usb_sndctrlpipe(kingsun->usbdev, 0),
+ (unsigned char *)kingsun->speed_setuprequest,
+ &(kingsun->speedparams),
+ sizeof(struct ksdazzle_speedparams),
+ ksdazzle_speed_irq, kingsun);
+ kingsun->speed_urb->status = 0;
+ err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC);
+
+ return err;
+}
+
+/* Submit one fragment of an IrDA frame to the dongle */
+static void ksdazzle_send_irq(struct urb *urb);
+static int ksdazzle_submit_tx_fragment(struct ksdazzle_cb *kingsun)
+{
+ unsigned int wraplen;
+ int ret;
+
+ /* We can send at most 7 bytes of payload at a time */
+ wraplen = 7;
+ if (wraplen > kingsun->tx_buf_clear_used)
+ wraplen = kingsun->tx_buf_clear_used;
+
+ /* Prepare payload prefix with used length */
+ memset(kingsun->tx_payload, 0, 8);
+ kingsun->tx_payload[0] = (unsigned char)0xf8 + wraplen;
+ memcpy(kingsun->tx_payload + 1, kingsun->tx_buf_clear, wraplen);
+
+ usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
+ usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
+ kingsun->tx_payload, 8, ksdazzle_send_irq, kingsun, 1);
+ kingsun->tx_urb->status = 0;
+ ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC);
+
+ /* Remember how much data was sent, in order to update at callback */
+ kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0;
+ return ret;
+}
+
+/* Callback transmission routine */
+static void ksdazzle_send_irq(struct urb *urb)
+{
+ struct ksdazzle_cb *kingsun = urb->context;
+ struct net_device *netdev = kingsun->netdev;
+ int ret = 0;
+
+ /* in process of stopping, just drop data */
+ if (!netif_running(kingsun->netdev)) {
+ err("ksdazzle_send_irq: Network not running!");
+ return;
+ }
+
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("ksdazzle_send_irq: urb asynchronously failed - %d",
+ urb->status);
+ return;
+ }
+
+ if (kingsun->tx_buf_clear_used > 0) {
+ /* Update data remaining to be sent */
+ if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) {
+ memmove(kingsun->tx_buf_clear,
+ kingsun->tx_buf_clear +
+ kingsun->tx_buf_clear_sent,
+ kingsun->tx_buf_clear_used -
+ kingsun->tx_buf_clear_sent);
+ }
+ kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent;
+ kingsun->tx_buf_clear_sent = 0;
+
+ if (kingsun->tx_buf_clear_used > 0) {
+ /* There is more data to be sent */
+ if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
+ err("ksdazzle_send_irq: failed tx_urb submit: %d", ret);
+ switch (ret) {
+ case -ENODEV:
+ case -EPIPE:
+ break;
+ default:
+ kingsun->stats.tx_errors++;
+ netif_start_queue(netdev);
+ }
+ }
+ } else {
+ /* All data sent, send next speed && wake network queue */
+ if (kingsun->new_speed != -1 &&
+ cpu_to_le32(kingsun->new_speed) !=
+ kingsun->speedparams.baudrate)
+ ksdazzle_change_speed(kingsun,
+ kingsun->new_speed);
+
+ netif_wake_queue(netdev);
+ }
+ }
+}
+
+/*
+ * Called from net/core when new frame is available.
+ */
+static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct ksdazzle_cb *kingsun;
+ unsigned int wraplen;
+ int ret = 0;
+
+ if (skb == NULL || netdev == NULL)
+ return -EINVAL;
+
+ netif_stop_queue(netdev);
+
+ /* the IRDA wrapping routines don't deal with non linear skb */
+ SKB_LINEAR_ASSERT(skb);
+
+ kingsun = netdev_priv(netdev);
+
+ spin_lock(&kingsun->lock);
+ kingsun->new_speed = irda_get_next_speed(skb);
+
+ /* Append data to the end of whatever data remains to be transmitted */
+ wraplen =
+ async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE);
+ kingsun->tx_buf_clear_used = wraplen;
+
+ if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
+ err("ksdazzle_hard_xmit: failed tx_urb submit: %d", ret);
+ switch (ret) {
+ case -ENODEV:
+ case -EPIPE:
+ break;
+ default:
+ kingsun->stats.tx_errors++;
+ netif_start_queue(netdev);
+ }
+ } else {
+ kingsun->stats.tx_packets++;
+ kingsun->stats.tx_bytes += skb->len;
+
+ }
+
+ dev_kfree_skb(skb);
+ spin_unlock(&kingsun->lock);
+
+ return ret;
+}
+
+/* Receive callback function */
+static void ksdazzle_rcv_irq(struct urb *urb)
+{
+ struct ksdazzle_cb *kingsun = urb->context;
+
+ /* in process of stopping, just drop data */
+ if (!netif_running(kingsun->netdev)) {
+ kingsun->receiving = 0;
+ return;
+ }
+
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("ksdazzle_rcv_irq: urb asynchronously failed - %d",
+ urb->status);
+ kingsun->receiving = 0;
+ return;
+ }
+
+ if (urb->actual_length > 0) {
+ __u8 *bytes = urb->transfer_buffer;
+ unsigned int i;
+
+ for (i = 0; i < urb->actual_length; i++) {
+ async_unwrap_char(kingsun->netdev, &kingsun->stats,
+ &kingsun->rx_unwrap_buff, bytes[i]);
+ }
+ kingsun->netdev->last_rx = jiffies;
+ kingsun->receiving =
+ (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
+ }
+
+ /* This urb has already been filled in ksdazzle_net_open. It is assumed that
+ urb keeps the pointer to the payload buffer.
+ */
+ urb->status = 0;
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/*
+ * Function ksdazzle_net_open (dev)
+ *
+ * Network device is taken up. Usually this is done by "ifconfig irda0 up"
+ */
+static int ksdazzle_net_open(struct net_device *netdev)
+{
+ struct ksdazzle_cb *kingsun = netdev_priv(netdev);
+ int err = -ENOMEM;
+ char hwname[16];
+
+ /* At this point, urbs are NULL, and skb is NULL (see ksdazzle_probe) */
+ kingsun->receiving = 0;
+
+ /* Initialize for SIR to copy data directly into skb. */
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU;
+ kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+ if (!kingsun->rx_unwrap_buff.skb)
+ goto free_mem;
+
+ skb_reserve(kingsun->rx_unwrap_buff.skb, 1);
+ kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data;
+
+ kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->rx_urb)
+ goto free_mem;
+
+ kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->tx_urb)
+ goto free_mem;
+
+ kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->speed_urb)
+ goto free_mem;
+
+ /* Initialize speed for dongle */
+ kingsun->new_speed = 9600;
+ err = ksdazzle_change_speed(kingsun, 9600);
+ if (err < 0)
+ goto free_mem;
+
+ /*
+ * Now that everything should be initialized properly,
+ * Open new IrLAP layer instance to take care of us...
+ */
+ sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
+ kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
+ if (!kingsun->irlap) {
+ err("ksdazzle-sir: irlap_open failed");
+ goto free_mem;
+ }
+
+ /* Start reception. */
+ usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
+ usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
+ kingsun->rx_buf, KINGSUN_RCV_MAX, ksdazzle_rcv_irq,
+ kingsun, 1);
+ kingsun->rx_urb->status = 0;
+ err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+ if (err) {
+ err("ksdazzle-sir: first urb-submit failed: %d", err);
+ goto close_irlap;
+ }
+
+ netif_start_queue(netdev);
+
+ /* Situation at this point:
+ - all work buffers allocated
+ - urbs allocated and ready to fill
+ - max rx packet known (in max_rx)
+ - unwrap state machine initialized, in state outside of any frame
+ - receive request in progress
+ - IrLAP layer started, about to hand over packets to send
+ */
+
+ return 0;
+
+ close_irlap:
+ irlap_close(kingsun->irlap);
+ free_mem:
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+ if (kingsun->rx_unwrap_buff.skb) {
+ kfree_skb(kingsun->rx_unwrap_buff.skb);
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->rx_unwrap_buff.head = NULL;
+ }
+ return err;
+}
+
+/*
+ * Function ksdazzle_net_close (dev)
+ *
+ * Network device is taken down. Usually this is done by
+ * "ifconfig irda0 down"
+ */
+static int ksdazzle_net_close(struct net_device *netdev)
+{
+ struct ksdazzle_cb *kingsun = netdev_priv(netdev);
+
+ /* Stop transmit processing */
+ netif_stop_queue(netdev);
+
+ /* Mop up receive && transmit urb's */
+ usb_kill_urb(kingsun->tx_urb);
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+
+ usb_kill_urb(kingsun->speed_urb);
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+
+ usb_kill_urb(kingsun->rx_urb);
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+
+ kfree_skb(kingsun->rx_unwrap_buff.skb);
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->rx_unwrap_buff.head = NULL;
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->receiving = 0;
+
+ /* Stop and remove instance of IrLAP */
+ irlap_close(kingsun->irlap);
+
+ kingsun->irlap = NULL;
+
+ return 0;
+}
+
+/*
+ * IOCTLs : Extra out-of-band network commands...
+ */
+static int ksdazzle_net_ioctl(struct net_device *netdev, struct ifreq *rq,
+ int cmd)
+{
+ struct if_irda_req *irq = (struct if_irda_req *)rq;
+ struct ksdazzle_cb *kingsun = netdev_priv(netdev);
+ int ret = 0;
+
+ switch (cmd) {
+ case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /* Check if the device is still there */
+ if (netif_device_present(kingsun->netdev))
+ return ksdazzle_change_speed(kingsun,
+ irq->ifr_baudrate);
+ break;
+
+ case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /* Check if the IrDA stack is still there */
+ if (netif_running(kingsun->netdev))
+ irda_device_set_media_busy(kingsun->netdev, TRUE);
+ break;
+
+ case SIOCGRECEIVING:
+ /* Only approximately true */
+ irq->ifr_receiving = kingsun->receiving;
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+/*
+ * Get device stats (for /proc/net/dev and ifconfig)
+ */
+static struct net_device_stats *ksdazzle_net_get_stats(struct net_device
+ *netdev)
+{
+ struct ksdazzle_cb *kingsun = netdev_priv(netdev);
+ return &kingsun->stats;
+}
+
+/*
+ * This routine is called by the USB subsystem for each new device
+ * in the system. We need to check if the device is ours, and in
+ * this case start handling it.
+ */
+static int ksdazzle_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct ksdazzle_cb *kingsun = NULL;
+ struct net_device *net = NULL;
+ int ret = -ENOMEM;
+ int pipe, maxp_in, maxp_out;
+ __u8 ep_in;
+ __u8 ep_out;
+
+ /* Check that there really are two interrupt endpoints. Check based on the
+ one in drivers/usb/input/usbmouse.c
+ */
+ interface = intf->cur_altsetting;
+ if (interface->desc.bNumEndpoints != 2) {
+ err("ksdazzle: expected 2 endpoints, found %d",
+ interface->desc.bNumEndpoints);
+ return -ENODEV;
+ }
+ endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
+ if (!usb_endpoint_is_int_in(endpoint)) {
+ err("ksdazzle: endpoint 0 is not interrupt IN");
+ return -ENODEV;
+ }
+
+ ep_in = endpoint->bEndpointAddress;
+ pipe = usb_rcvintpipe(dev, ep_in);
+ maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+ if (maxp_in > 255 || maxp_in <= 1) {
+ err("ksdazzle: endpoint 0 has max packet size %d not in range [2..255]", maxp_in);
+ return -ENODEV;
+ }
+
+ endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
+ if (!usb_endpoint_is_int_out(endpoint)) {
+ err("ksdazzle: endpoint 1 is not interrupt OUT");
+ return -ENODEV;
+ }
+
+ ep_out = endpoint->bEndpointAddress;
+ pipe = usb_sndintpipe(dev, ep_out);
+ maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+ /* Allocate network device container. */
+ net = alloc_irdadev(sizeof(*kingsun));
+ if (!net)
+ goto err_out1;
+
+ SET_NETDEV_DEV(net, &intf->dev);
+ kingsun = netdev_priv(net);
+ kingsun->netdev = net;
+ kingsun->usbdev = dev;
+ kingsun->ep_in = ep_in;
+ kingsun->ep_out = ep_out;
+ kingsun->irlap = NULL;
+ kingsun->tx_urb = NULL;
+ kingsun->tx_buf_clear = NULL;
+ kingsun->tx_buf_clear_used = 0;
+ kingsun->tx_buf_clear_sent = 0;
+
+ kingsun->rx_urb = NULL;
+ kingsun->rx_buf = NULL;
+ kingsun->rx_unwrap_buff.in_frame = FALSE;
+ kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+ kingsun->rx_unwrap_buff.skb = NULL;
+ kingsun->receiving = 0;
+ spin_lock_init(&kingsun->lock);
+
+ kingsun->speed_setuprequest = NULL;
+ kingsun->speed_urb = NULL;
+ kingsun->speedparams.baudrate = 0;
+
+ /* Allocate input buffer */
+ kingsun->rx_buf = kmalloc(KINGSUN_RCV_MAX, GFP_KERNEL);
+ if (!kingsun->rx_buf)
+ goto free_mem;
+
+ /* Allocate output buffer */
+ kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL);
+ if (!kingsun->tx_buf_clear)
+ goto free_mem;
+
+ /* Allocate and initialize speed setup packet */
+ kingsun->speed_setuprequest =
+ kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+ if (!kingsun->speed_setuprequest)
+ goto free_mem;
+ kingsun->speed_setuprequest->bRequestType =
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+ kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND;
+ kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200);
+ kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001);
+ kingsun->speed_setuprequest->wLength =
+ cpu_to_le16(sizeof(struct ksdazzle_speedparams));
+
+ printk(KERN_INFO "KingSun/Dazzle IRDA/USB found at address %d, "
+ "Vendor: %x, Product: %x\n",
+ dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
+
+ /* Initialize QoS for this device */
+ irda_init_max_qos_capabilies(&kingsun->qos);
+
+ /* Baud rates known to be supported. Please uncomment if devices (other
+ than a SonyEriccson K300 phone) can be shown to support higher speeds
+ with this dongle.
+ */
+ kingsun->qos.baud_rate.bits =
+ IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200;
+ kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
+ irda_qos_bits_to_value(&kingsun->qos);
+
+ /* Override the network functions we need to use */
+ net->hard_start_xmit = ksdazzle_hard_xmit;
+ net->open = ksdazzle_net_open;
+ net->stop = ksdazzle_net_close;
+ net->get_stats = ksdazzle_net_get_stats;
+ net->do_ioctl = ksdazzle_net_ioctl;
+
+ ret = register_netdev(net);
+ if (ret != 0)
+ goto free_mem;
+
+ info("IrDA: Registered KingSun/Dazzle device %s", net->name);
+
+ usb_set_intfdata(intf, kingsun);
+
+ /* Situation at this point:
+ - all work buffers allocated
+ - setup requests pre-filled
+ - urbs not allocated, set to NULL
+ - max rx packet known (is KINGSUN_FIFO_SIZE)
+ - unwrap state machine (partially) initialized, but skb == NULL
+ */
+
+ return 0;
+
+ free_mem:
+ kfree(kingsun->speed_setuprequest);
+ kfree(kingsun->tx_buf_clear);
+ kfree(kingsun->rx_buf);
+ free_netdev(net);
+ err_out1:
+ return ret;
+}
+
+/*
+ * The current device is removed, the USB layer tell us to shut it down...
+ */
+static void ksdazzle_disconnect(struct usb_interface *intf)
+{
+ struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
+
+ if (!kingsun)
+ return;
+
+ unregister_netdev(kingsun->netdev);
+
+ /* Mop up receive && transmit urb's */
+ usb_kill_urb(kingsun->speed_urb);
+ usb_free_urb(kingsun->speed_urb);
+ kingsun->speed_urb = NULL;
+
+ usb_kill_urb(kingsun->tx_urb);
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+
+ usb_kill_urb(kingsun->rx_urb);
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+
+ kfree(kingsun->speed_setuprequest);
+ kfree(kingsun->tx_buf_clear);
+ kfree(kingsun->rx_buf);
+ free_netdev(kingsun->netdev);
+
+ usb_set_intfdata(intf, NULL);
+}
+
+#ifdef CONFIG_PM
+/* USB suspend, so power off the transmitter/receiver */
+static int ksdazzle_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
+
+ netif_device_detach(kingsun->netdev);
+ if (kingsun->speed_urb != NULL)
+ usb_kill_urb(kingsun->speed_urb);
+ if (kingsun->tx_urb != NULL)
+ usb_kill_urb(kingsun->tx_urb);
+ if (kingsun->rx_urb != NULL)
+ usb_kill_urb(kingsun->rx_urb);
+ return 0;
+}
+
+/* Coming out of suspend, so reset hardware */
+static int ksdazzle_resume(struct usb_interface *intf)
+{
+ struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
+
+ if (kingsun->rx_urb != NULL) {
+ /* Setup request already filled in ksdazzle_probe */
+ usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+ }
+ netif_device_attach(kingsun->netdev);
+
+ return 0;
+}
+#endif
+
+/*
+ * USB device callbacks
+ */
+static struct usb_driver irda_driver = {
+ .name = "ksdazzle-sir",
+ .probe = ksdazzle_probe,
+ .disconnect = ksdazzle_disconnect,
+ .id_table = dongles,
+#ifdef CONFIG_PM
+ .suspend = ksdazzle_suspend,
+ .resume = ksdazzle_resume,
+#endif
+};
+
+/*
+ * Module insertion
+ */
+static int __init ksdazzle_init(void)
+{
+ return usb_register(&irda_driver);
+}
+
+module_init(ksdazzle_init);
+
+/*
+ * Module removal
+ */
+static void __exit ksdazzle_cleanup(void)
+{
+ /* Deregister the driver and remove all pending instances */
+ usb_deregister(&irda_driver);
+}
+
+module_exit(ksdazzle_cleanup);
+
+MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun Dazzle");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index 0de867288a4..0b769192d4c 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -50,7 +50,6 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/module.h>
#include <linux/kref.h>
#include <linux/usb.h>
#include <linux/device.h>
@@ -465,7 +464,7 @@ static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len)
}
fcs = ~(crc32_le(~0, buf, new_len));
- if(fcs != le32_to_cpu(get_unaligned((u32 *)(buf+new_len)))) {
+ if(fcs != le32_to_cpu(get_unaligned((__le32 *)(buf+new_len)))) {
IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len);
mcs->stats.rx_errors++;
mcs->stats.rx_crc_errors++;
@@ -899,8 +898,6 @@ static int mcs_probe(struct usb_interface *intf,
IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum);
- /* what is it realy for? */
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &intf->dev);
ret = usb_reset_configuration(udev);
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index d96c89751a7..a873d2b315c 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -20,7 +20,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
@@ -437,7 +437,6 @@ static int __init nsc_ircc_open(chipio_t *info)
self->tx_fifo.tail = self->tx_buff.head;
/* Override the network functions we need to use */
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = nsc_ircc_hard_xmit_sir;
dev->open = nsc_ircc_net_open;
dev->stop = nsc_ircc_net_close;
diff --git a/drivers/net/irda/nsc-ircc.h b/drivers/net/irda/nsc-ircc.h
index dacf671abcd..bbdc97ff83c 100644
--- a/drivers/net/irda/nsc-ircc.h
+++ b/drivers/net/irda/nsc-ircc.h
@@ -19,7 +19,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index 55ff0fbe525..8c09344f58d 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -23,6 +23,7 @@
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
+#include <linux/clk.h>
#include <net/irda/irda.h>
#include <net/irda/irmod.h>
@@ -87,8 +88,30 @@ struct pxa_irda {
struct device *dev;
struct pxaficp_platform_data *pdata;
+ struct clk *fir_clk;
+ struct clk *sir_clk;
+ struct clk *cur_clk;
};
+static inline void pxa_irda_disable_clk(struct pxa_irda *si)
+{
+ if (si->cur_clk)
+ clk_disable(si->cur_clk);
+ si->cur_clk = NULL;
+}
+
+static inline void pxa_irda_enable_firclk(struct pxa_irda *si)
+{
+ si->cur_clk = si->fir_clk;
+ clk_enable(si->fir_clk);
+}
+
+static inline void pxa_irda_enable_sirclk(struct pxa_irda *si)
+{
+ si->cur_clk = si->sir_clk;
+ clk_enable(si->sir_clk);
+}
+
#define IS_FIR(si) ((si)->speed >= 4000000)
#define IRDA_FRAME_SIZE_LIMIT 2047
@@ -134,7 +157,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
DCSR(si->rxdma) &= ~DCSR_RUN;
/* disable FICP */
ICCR0 = 0;
- pxa_set_cken(CKEN_FICP, 0);
+ pxa_irda_disable_clk(si);
/* set board transceiver to SIR mode */
si->pdata->transceiver_mode(si->dev, IR_SIRMODE);
@@ -144,7 +167,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
pxa_gpio_mode(GPIO47_STTXD_MD);
/* enable the STUART clock */
- pxa_set_cken(CKEN_STUART, 1);
+ pxa_irda_enable_sirclk(si);
}
/* disable STUART first */
@@ -169,7 +192,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
/* disable STUART */
STIER = 0;
STISR = 0;
- pxa_set_cken(CKEN_STUART, 0);
+ pxa_irda_disable_clk(si);
/* disable FICP first */
ICCR0 = 0;
@@ -182,7 +205,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
pxa_gpio_mode(GPIO47_ICPTXD_MD);
/* enable the FICP clock */
- pxa_set_cken(CKEN_FICP, 1);
+ pxa_irda_enable_firclk(si);
si->speed = speed;
pxa_irda_fir_dma_rx_start(si);
@@ -592,16 +615,15 @@ static void pxa_irda_shutdown(struct pxa_irda *si)
STIER = 0;
/* disable STUART SIR mode */
STISR = 0;
- /* disable the STUART clock */
- pxa_set_cken(CKEN_STUART, 0);
/* disable DMA */
DCSR(si->txdma) &= ~DCSR_RUN;
DCSR(si->rxdma) &= ~DCSR_RUN;
/* disable FICP */
ICCR0 = 0;
- /* disable the FICP clock */
- pxa_set_cken(CKEN_FICP, 0);
+
+ /* disable the STUART or FICP clocks */
+ pxa_irda_disable_clk(si);
DRCMR17 = 0;
DRCMR18 = 0;
@@ -792,6 +814,13 @@ static int pxa_irda_probe(struct platform_device *pdev)
si->dev = &pdev->dev;
si->pdata = pdev->dev.platform_data;
+ si->sir_clk = clk_get(&pdev->dev, "UARTCLK");
+ si->fir_clk = clk_get(&pdev->dev, "FICPCLK");
+ if (IS_ERR(si->sir_clk) || IS_ERR(si->fir_clk)) {
+ err = PTR_ERR(IS_ERR(si->sir_clk) ? si->sir_clk : si->fir_clk);
+ goto err_mem_4;
+ }
+
/*
* Initialise the SIR buffers
*/
@@ -831,6 +860,10 @@ static int pxa_irda_probe(struct platform_device *pdev)
err_mem_5:
kfree(si->rx_buff.head);
err_mem_4:
+ if (si->sir_clk && !IS_ERR(si->sir_clk))
+ clk_put(si->sir_clk);
+ if (si->fir_clk && !IS_ERR(si->fir_clk))
+ clk_put(si->fir_clk);
free_netdev(dev);
err_mem_3:
release_mem_region(__PREG(FICP), 0x1c);
@@ -850,6 +883,8 @@ static int pxa_irda_remove(struct platform_device *_dev)
unregister_netdev(dev);
kfree(si->tx_buff.head);
kfree(si->rx_buff.head);
+ clk_put(si->fir_clk);
+ clk_put(si->sir_clk);
free_netdev(dev);
}
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
index 9d6c8f391b2..6078e03de9a 100644
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -414,7 +414,7 @@ EXPORT_SYMBOL(sirdev_raw_read);
int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts)
{
int ret = -ENXIO;
- if (dev->drv->set_dtr_rts != 0)
+ if (dev->drv->set_dtr_rts)
ret = dev->drv->set_dtr_rts(dev, dtr, rts);
return ret;
}
@@ -913,8 +913,6 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n
dev->drv = drv;
dev->netdev = ndev;
- SET_MODULE_OWNER(ndev);
-
/* Override the network functions we need to use */
ndev->hard_start_xmit = sirdev_hard_xmit;
ndev->open = sirdev_open;
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 36ab98386be..7e7b5828214 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -81,7 +81,7 @@ MODULE_LICENSE("GPL");
static int smsc_nopnp = 1;
module_param_named(nopnp, smsc_nopnp, bool, 0);
-MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
+MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings, defaults to true");
#define DMA_INVAL 255
static int ircc_dma = DMA_INVAL;
@@ -519,8 +519,6 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
goto err_out1;
}
- SET_MODULE_OWNER(dev);
-
dev->hard_start_xmit = smsc_ircc_hard_xmit_sir;
#if SMSC_IRCC2_C_NET_TIMEOUT
dev->tx_timeout = smsc_ircc_timeout;
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 755aa444a4d..042bc2f0417 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -332,7 +332,7 @@ static void fir_eof(struct stir_cb *stir)
}
fcs = ~(crc32_le(~0, rx_buff->data, len));
- if (fcs != le32_to_cpu(get_unaligned((u32 *)(rx_buff->data+len)))) {
+ if (fcs != le32_to_cpu(get_unaligned((__le32 *)(rx_buff->data+len)))) {
pr_debug("crc error calc 0x%x len %d\n", fcs, len);
stir->stats.rx_errors++;
stir->stats.rx_crc_errors++;
@@ -1034,7 +1034,6 @@ static int stir_probe(struct usb_interface *intf,
if(!net)
goto err_out1;
- SET_MODULE_OWNER(net);
SET_NETDEV_DEV(net, &intf->dev);
stir = netdev_priv(net);
stir->netdev = net;
diff --git a/drivers/net/irda/tekram-sir.c b/drivers/net/irda/tekram-sir.c
index 0dd6bc7af3f..d1ce5ae6a17 100644
--- a/drivers/net/irda/tekram-sir.c
+++ b/drivers/net/irda/tekram-sir.c
@@ -18,7 +18,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/drivers/net/irda/tekram.c b/drivers/net/irda/tekram.c
index 8f6258221cb..9bfd2441adb 100644
--- a/drivers/net/irda/tekram.c
+++ b/drivers/net/irda/tekram.c
@@ -16,7 +16,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index ff5358574d0..126ec7c8680 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -429,9 +429,6 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id)
self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
self->tx_fifo.tail = self->tx_buff.head;
- /* Keep track of module usage */
- SET_MODULE_OWNER(dev);
-
/* Override the network functions we need to use */
dev->hard_start_xmit = via_ircc_hard_xmit_sir;
dev->open = via_ircc_net_open;
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index 0538ca9ce05..acd082a96a4 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -1584,8 +1584,6 @@ static int vlsi_irda_init(struct net_device *ndev)
vlsi_irda_dev_t *idev = ndev->priv;
struct pci_dev *pdev = idev->pdev;
- SET_MODULE_OWNER(ndev);
-
ndev->irq = pdev->irq;
ndev->base_addr = pci_resource_start(pdev,0);
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
index ca12a609641..c8b9c74eea5 100644
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -537,10 +537,10 @@ calc_width_bits(unsigned baudrate, unsigned widthselect, unsigned clockselect)
*/
struct ring_descr_hw {
- volatile u16 rd_count; /* tx/rx count [11:0] */
- u16 reserved;
+ volatile __le16 rd_count; /* tx/rx count [11:0] */
+ __le16 reserved;
union {
- u32 addr; /* [23:0] of the buffer's busaddress */
+ __le32 addr; /* [23:0] of the buffer's busaddress */
struct {
u8 addr_res[3];
volatile u8 status; /* descriptor status */
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 5182e800cc1..9fd2451b0fb 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -232,9 +232,6 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq,
self->rx_buff.data = self->rx_buff.head;
self->netdev = dev;
- /* Keep track of module usage */
- SET_MODULE_OWNER(dev);
-
/* Override the network functions we need to use */
dev->hard_start_xmit = w83977af_hard_xmit;
dev->open = w83977af_net_open;
diff --git a/drivers/net/irda/w83977af_ir.h b/drivers/net/irda/w83977af_ir.h
index 0b7661deafe..87c3975baf6 100644
--- a/drivers/net/irda/w83977af_ir.h
+++ b/drivers/net/irda/w83977af_ir.h
@@ -16,7 +16,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
index 0343f12d2ff..d6ff26af37b 100644
--- a/drivers/net/isa-skeleton.c
+++ b/drivers/net/isa-skeleton.c
@@ -133,8 +133,6 @@ static int __init do_netcard_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) /* Check a single specified location. */
return netcard_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
@@ -194,6 +192,7 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr)
static unsigned version_printed;
int i;
int err = -ENODEV;
+ DECLARE_MAC_BUF(mac);
/* Grab the region so that no one else tries to probe our ioports. */
if (!request_region(ioaddr, NETCARD_IO_EXTENT, cardname))
@@ -219,7 +218,9 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr)
/* Retrieve and print the ethernet address. */
for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+ dev->dev_addr[i] = inb(ioaddr + i);
+
+ printk("%s", print_mac(mac, dev->dev_addr));
err = -EAGAIN;
#ifdef jumpered_interrupts
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 0433c41f902..97bd9dc2e52 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -196,7 +196,6 @@ struct veth_lpar_connection {
struct veth_port {
struct device *dev;
- struct net_device_stats stats;
u64 mac_addr;
HvLpIndexMap lpar_map;
@@ -936,9 +935,6 @@ static void veth_release_connection(struct kobject *kobj)
static int veth_open(struct net_device *dev)
{
- struct veth_port *port = (struct veth_port *) dev->priv;
-
- memset(&port->stats, 0, sizeof (port->stats));
netif_start_queue(dev);
return 0;
}
@@ -949,13 +945,6 @@ static int veth_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *veth_get_stats(struct net_device *dev)
-{
- struct veth_port *port = (struct veth_port *) dev->priv;
-
- return &port->stats;
-}
-
static int veth_change_mtu(struct net_device *dev, int new_mtu)
{
if ((new_mtu < 68) || (new_mtu > VETH_MAX_MTU))
@@ -1084,7 +1073,6 @@ static struct net_device * __init veth_probe_one(int vlan,
dev->open = veth_open;
dev->hard_start_xmit = veth_start_xmit;
dev->stop = veth_close;
- dev->get_stats = veth_get_stats;
dev->change_mtu = veth_change_mtu;
dev->set_mac_address = NULL;
dev->set_multicast_list = veth_set_multicast_list;
@@ -1183,7 +1171,6 @@ static void veth_transmit_to_many(struct sk_buff *skb,
HvLpIndexMap lpmask,
struct net_device *dev)
{
- struct veth_port *port = (struct veth_port *) dev->priv;
int i, success, error;
success = error = 0;
@@ -1199,11 +1186,11 @@ static void veth_transmit_to_many(struct sk_buff *skb,
}
if (error)
- port->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (success) {
- port->stats.tx_packets++;
- port->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
}
}
@@ -1541,8 +1528,8 @@ static void veth_receive(struct veth_lpar_connection *cnx,
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_NONE;
netif_rx(skb); /* send it up */
- port->stats.rx_packets++;
- port->stats.rx_bytes += length;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += length;
} while (startchunk += nchunks, startchunk < VETH_MAX_FRAMES_PER_MSG);
/* Ack it */
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index 3569d5b0338..3d2e7217e9a 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -184,6 +184,7 @@ struct ixgb_adapter {
boolean_t rx_csum;
/* OS defined structs */
+ struct napi_struct napi;
struct net_device *netdev;
struct pci_dev *pdev;
struct net_device_stats net_stats;
@@ -195,4 +196,11 @@ struct ixgb_adapter {
uint32_t alloc_rx_buff_failed;
boolean_t have_msi;
};
+
+/* Exported from other modules */
+extern void ixgb_check_options(struct ixgb_adapter *adapter);
+extern void ixgb_set_ethtool_ops(struct net_device *netdev);
+extern char ixgb_driver_name[];
+extern const char ixgb_driver_version[];
+
#endif /* _IXGB_H_ */
diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c
index 52c99d01d56..e8eb0fd6c57 100644
--- a/drivers/net/ixgb/ixgb_ee.c
+++ b/drivers/net/ixgb/ixgb_ee.c
@@ -411,7 +411,7 @@ ixgb_write_eeprom(struct ixgb_hw *hw, uint16_t offset, uint16_t data)
ixgb_cleanup_eeprom(hw);
/* clear the init_ctrl_reg_1 to signify that the cache is invalidated */
- ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR);
+ ee_map->init_ctrl_reg_1 = cpu_to_le16(EEPROM_ICW1_SIGNATURE_CLEAR);
return;
}
@@ -476,19 +476,19 @@ ixgb_get_eeprom_data(struct ixgb_hw *hw)
uint16_t ee_data;
ee_data = ixgb_read_eeprom(hw, i);
checksum += ee_data;
- hw->eeprom[i] = le16_to_cpu(ee_data);
+ hw->eeprom[i] = cpu_to_le16(ee_data);
}
if (checksum != (uint16_t) EEPROM_SUM) {
DEBUGOUT("ixgb_ee: Checksum invalid.\n");
/* clear the init_ctrl_reg_1 to signify that the cache is
* invalidated */
- ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR);
+ ee_map->init_ctrl_reg_1 = cpu_to_le16(EEPROM_ICW1_SIGNATURE_CLEAR);
return (FALSE);
}
- if ((ee_map->init_ctrl_reg_1 & le16_to_cpu(EEPROM_ICW1_SIGNATURE_MASK))
- != le16_to_cpu(EEPROM_ICW1_SIGNATURE_VALID)) {
+ if ((ee_map->init_ctrl_reg_1 & cpu_to_le16(EEPROM_ICW1_SIGNATURE_MASK))
+ != cpu_to_le16(EEPROM_ICW1_SIGNATURE_VALID)) {
DEBUGOUT("ixgb_ee: Signature invalid.\n");
return(FALSE);
}
@@ -511,8 +511,8 @@ ixgb_check_and_get_eeprom_data (struct ixgb_hw* hw)
{
struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
- if ((ee_map->init_ctrl_reg_1 & le16_to_cpu(EEPROM_ICW1_SIGNATURE_MASK))
- == le16_to_cpu(EEPROM_ICW1_SIGNATURE_VALID)) {
+ if ((ee_map->init_ctrl_reg_1 & cpu_to_le16(EEPROM_ICW1_SIGNATURE_MASK))
+ == cpu_to_le16(EEPROM_ICW1_SIGNATURE_VALID)) {
return (TRUE);
} else {
return ixgb_get_eeprom_data(hw);
@@ -528,7 +528,7 @@ ixgb_check_and_get_eeprom_data (struct ixgb_hw* hw)
* Returns:
* Word at indexed offset in eeprom, if valid, 0 otherwise.
******************************************************************************/
-uint16_t
+__le16
ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index)
{
diff --git a/drivers/net/ixgb/ixgb_ee.h b/drivers/net/ixgb/ixgb_ee.h
index ef236b935c1..7908bf3005e 100644
--- a/drivers/net/ixgb/ixgb_ee.h
+++ b/drivers/net/ixgb/ixgb_ee.h
@@ -76,22 +76,22 @@
/* EEPROM structure */
struct ixgb_ee_map_type {
uint8_t mac_addr[IXGB_ETH_LENGTH_OF_ADDRESS];
- uint16_t compatibility;
- uint16_t reserved1[4];
- uint32_t pba_number;
- uint16_t init_ctrl_reg_1;
- uint16_t subsystem_id;
- uint16_t subvendor_id;
- uint16_t device_id;
- uint16_t vendor_id;
- uint16_t init_ctrl_reg_2;
- uint16_t oem_reserved[16];
- uint16_t swdpins_reg;
- uint16_t circuit_ctrl_reg;
+ __le16 compatibility;
+ __le16 reserved1[4];
+ __le32 pba_number;
+ __le16 init_ctrl_reg_1;
+ __le16 subsystem_id;
+ __le16 subvendor_id;
+ __le16 device_id;
+ __le16 vendor_id;
+ __le16 init_ctrl_reg_2;
+ __le16 oem_reserved[16];
+ __le16 swdpins_reg;
+ __le16 circuit_ctrl_reg;
uint8_t d3_power;
uint8_t d0_power;
- uint16_t reserved2[28];
- uint16_t checksum;
+ __le16 reserved2[28];
+ __le16 checksum;
};
/* EEPROM Functions */
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index 0413cd95eda..a267dd86252 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -32,9 +32,6 @@
#include <asm/uaccess.h>
-extern char ixgb_driver_name[];
-extern char ixgb_driver_version[];
-
extern int ixgb_up(struct ixgb_adapter *adapter);
extern void ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog);
extern void ixgb_reset(struct ixgb_adapter *adapter);
@@ -94,8 +91,7 @@ static struct ixgb_stats ixgb_gstrings_stats[] = {
{"tx_csum_offload_errors", IXGB_STAT(hw_csum_tx_error)}
};
-#define IXGB_STATS_LEN \
- sizeof(ixgb_gstrings_stats) / sizeof(struct ixgb_stats)
+#define IXGB_STATS_LEN ARRAY_SIZE(ixgb_gstrings_stats)
static int
ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
@@ -423,7 +419,7 @@ ixgb_get_eeprom(struct net_device *netdev,
{
struct ixgb_adapter *adapter = netdev_priv(netdev);
struct ixgb_hw *hw = &adapter->hw;
- uint16_t *eeprom_buff;
+ __le16 *eeprom_buff;
int i, max_len, first_word, last_word;
int ret_val = 0;
@@ -447,7 +443,7 @@ ixgb_get_eeprom(struct net_device *netdev,
first_word = eeprom->offset >> 1;
last_word = (eeprom->offset + eeprom->len - 1) >> 1;
- eeprom_buff = kmalloc(sizeof(uint16_t) *
+ eeprom_buff = kmalloc(sizeof(__le16) *
(last_word - first_word + 1), GFP_KERNEL);
if(!eeprom_buff)
return -ENOMEM;
@@ -640,8 +636,8 @@ ixgb_phys_id(struct net_device *netdev, uint32_t data)
{
struct ixgb_adapter *adapter = netdev_priv(netdev);
- if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ))
- data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ);
+ if (!data)
+ data = INT_MAX;
if(!adapter->blink_timer.function) {
init_timer(&adapter->blink_timer);
@@ -660,9 +656,14 @@ ixgb_phys_id(struct net_device *netdev, uint32_t data)
}
static int
-ixgb_get_stats_count(struct net_device *netdev)
+ixgb_get_sset_count(struct net_device *netdev, int sset)
{
- return IXGB_STATS_LEN;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return IXGB_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void
@@ -714,15 +715,13 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
.set_rx_csum = ixgb_set_rx_csum,
.get_tx_csum = ixgb_get_tx_csum,
.set_tx_csum = ixgb_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_msglevel = ixgb_get_msglevel,
.set_msglevel = ixgb_set_msglevel,
- .get_tso = ethtool_op_get_tso,
.set_tso = ixgb_set_tso,
.get_strings = ixgb_get_strings,
.phys_id = ixgb_phys_id,
- .get_stats_count = ixgb_get_stats_count,
+ .get_sset_count = ixgb_get_sset_count,
.get_ethtool_stats = ixgb_get_ethtool_stats,
};
diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c
index ecbf45861c6..2c6367ace3c 100644
--- a/drivers/net/ixgb/ixgb_hw.c
+++ b/drivers/net/ixgb/ixgb_hw.c
@@ -1174,7 +1174,7 @@ mac_addr_valid(uint8_t *mac_addr)
*
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
-boolean_t
+static boolean_t
ixgb_link_reset(struct ixgb_hw *hw)
{
boolean_t link_status = FALSE;
@@ -1205,7 +1205,7 @@ ixgb_link_reset(struct ixgb_hw *hw)
*
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
-void
+static void
ixgb_optics_reset(struct ixgb_hw *hw)
{
if (hw->phy_type == ixgb_phy_type_txn17401) {
diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h
index 40ef5ca8871..af5643324ee 100644
--- a/drivers/net/ixgb/ixgb_hw.h
+++ b/drivers/net/ixgb/ixgb_hw.h
@@ -711,7 +711,7 @@ struct ixgb_hw {
uint32_t bar2;
uint32_t bar3;
uint16_t pci_cmd_word; /* PCI command register id from PCI configuration space */
- uint16_t eeprom[IXGB_EEPROM_SIZE]; /* EEPROM contents read at init time */
+ __le16 eeprom[IXGB_EEPROM_SIZE]; /* EEPROM contents read at init time */
unsigned long io_base; /* Our I/O mapped location */
uint32_t lastLFC;
uint32_t lastRFC;
@@ -809,7 +809,7 @@ void ixgb_get_ee_mac_addr(struct ixgb_hw *hw, uint8_t *mac_addr);
uint32_t ixgb_get_ee_pba_number(struct ixgb_hw *hw);
uint16_t ixgb_get_ee_device_id(struct ixgb_hw *hw);
boolean_t ixgb_get_eeprom_data(struct ixgb_hw *hw);
-uint16_t ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index);
+__le16 ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index);
/* Everything else */
void ixgb_led_on(struct ixgb_hw *hw);
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 991c8833e23..3021234b1e1 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -37,8 +37,8 @@ static char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";
#define DRIVERNAPI "-NAPI"
#endif
#define DRV_VERSION "1.0.126-k2"DRIVERNAPI
-char ixgb_driver_version[] = DRV_VERSION;
-static char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
+const char ixgb_driver_version[] = DRV_VERSION;
+static const char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
/* ixgb_pci_tbl - PCI Device ID Table
*
@@ -97,14 +97,13 @@ static irqreturn_t ixgb_intr(int irq, void *data);
static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter);
#ifdef CONFIG_IXGB_NAPI
-static int ixgb_clean(struct net_device *netdev, int *budget);
+static int ixgb_clean(struct napi_struct *napi, int budget);
static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter,
int *work_done, int work_to_do);
#else
static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter);
#endif
static void ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter);
-void ixgb_set_ethtool_ops(struct net_device *netdev);
static void ixgb_tx_timeout(struct net_device *dev);
static void ixgb_tx_timeout_task(struct work_struct *work);
static void ixgb_vlan_rx_register(struct net_device *netdev,
@@ -123,9 +122,6 @@ static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev,
static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev);
static void ixgb_io_resume (struct pci_dev *pdev);
-/* Exported from other modules */
-extern void ixgb_check_options(struct ixgb_adapter *adapter);
-
static struct pci_error_handlers ixgb_err_handler = {
.error_detected = ixgb_io_error_detected,
.slot_reset = ixgb_io_slot_reset,
@@ -288,7 +284,7 @@ ixgb_up(struct ixgb_adapter *adapter)
mod_timer(&adapter->watchdog_timer, jiffies);
#ifdef CONFIG_IXGB_NAPI
- netif_poll_enable(netdev);
+ napi_enable(&adapter->napi);
#endif
ixgb_irq_enable(adapter);
@@ -309,7 +305,7 @@ ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog)
if(kill_watchdog)
del_timer_sync(&adapter->watchdog_timer);
#ifdef CONFIG_IXGB_NAPI
- netif_poll_disable(netdev);
+ napi_disable(&adapter->napi);
#endif
adapter->link_speed = 0;
adapter->link_duplex = 0;
@@ -382,7 +378,6 @@ ixgb_probe(struct pci_dev *pdev,
goto err_alloc_etherdev;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
pci_set_drvdata(pdev, netdev);
@@ -421,8 +416,7 @@ ixgb_probe(struct pci_dev *pdev,
netdev->tx_timeout = &ixgb_tx_timeout;
netdev->watchdog_timeo = 5 * HZ;
#ifdef CONFIG_IXGB_NAPI
- netdev->poll = &ixgb_clean;
- netdev->weight = 64;
+ netif_napi_add(netdev, &adapter->napi, ixgb_clean, 64);
#endif
netdev->vlan_rx_register = ixgb_vlan_rx_register;
netdev->vlan_rx_add_vid = ixgb_vlan_rx_add_vid;
@@ -1087,7 +1081,8 @@ ixgb_set_multi(struct net_device *netdev)
rctl |= IXGB_RCTL_MPE;
IXGB_WRITE_REG(hw, RCTL, rctl);
} else {
- uint8_t mta[netdev->mc_count * IXGB_ETH_LENGTH_OF_ADDRESS];
+ uint8_t mta[IXGB_MAX_NUM_MULTICAST_ADDRESSES *
+ IXGB_ETH_LENGTH_OF_ADDRESS];
IXGB_WRITE_REG(hw, RCTL, rctl);
@@ -1326,8 +1321,8 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
/* Workaround for premature desc write-backs
* in TSO mode. Append 4-byte sentinel desc */
- if (unlikely(mss && !nr_frags && size == len
- && size > 8))
+ if (unlikely(mss && (f == (nr_frags - 1))
+ && size == len && size > 8))
size -= 4;
buffer_info->length = size;
@@ -1746,7 +1741,7 @@ ixgb_intr(int irq, void *data)
}
#ifdef CONFIG_IXGB_NAPI
- if(netif_rx_schedule_prep(netdev)) {
+ if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
/* Disable interrupts and register for poll. The flush
of the posted write is intentionally left out.
@@ -1754,7 +1749,7 @@ ixgb_intr(int irq, void *data)
atomic_inc(&adapter->irq_sem);
IXGB_WRITE_REG(&adapter->hw, IMC, ~0);
- __netif_rx_schedule(netdev);
+ __netif_rx_schedule(netdev, &adapter->napi);
}
#else
/* yes, that is actually a & and it is meant to make sure that
@@ -1776,27 +1771,23 @@ ixgb_intr(int irq, void *data)
**/
static int
-ixgb_clean(struct net_device *netdev, int *budget)
+ixgb_clean(struct napi_struct *napi, int budget)
{
- struct ixgb_adapter *adapter = netdev_priv(netdev);
- int work_to_do = min(*budget, netdev->quota);
+ struct ixgb_adapter *adapter = container_of(napi, struct ixgb_adapter, napi);
+ struct net_device *netdev = adapter->netdev;
int tx_cleaned;
int work_done = 0;
tx_cleaned = ixgb_clean_tx_irq(adapter);
- ixgb_clean_rx_irq(adapter, &work_done, work_to_do);
-
- *budget -= work_done;
- netdev->quota -= work_done;
+ ixgb_clean_rx_irq(adapter, &work_done, budget);
/* if no Tx and not enough Rx work done, exit the polling mode */
if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
- netif_rx_complete(netdev);
+ netif_rx_complete(netdev, napi);
ixgb_irq_enable(adapter);
- return 0;
}
- return 1;
+ return work_done;
}
#endif
diff --git a/drivers/net/ixgb/ixgb_param.c b/drivers/net/ixgb/ixgb_param.c
index 5d5ddabf436..865d14d6e5a 100644
--- a/drivers/net/ixgb/ixgb_param.c
+++ b/drivers/net/ixgb/ixgb_param.c
@@ -44,10 +44,11 @@
*/
#define IXGB_PARAM_INIT { [0 ... IXGB_MAX_NIC] = OPTION_UNSET }
-#define IXGB_PARAM(X, desc) \
- static int __devinitdata X[IXGB_MAX_NIC+1] = IXGB_PARAM_INIT; \
- static int num_##X = 0; \
- module_param_array_named(X, X, int, &num_##X, 0); \
+#define IXGB_PARAM(X, desc) \
+ static int __devinitdata X[IXGB_MAX_NIC+1] \
+ = IXGB_PARAM_INIT; \
+ static unsigned int num_##X = 0; \
+ module_param_array_named(X, X, int, &num_##X, 0); \
MODULE_PARM_DESC(X, desc);
/* Transmit Descriptor Count
@@ -178,8 +179,8 @@ IXGB_PARAM(IntDelayEnable, "Transmit Interrupt Delay Enable");
struct ixgb_option {
enum { enable_option, range_option, list_option } type;
- char *name;
- char *err;
+ const char *name;
+ const char *err;
int def;
union {
struct { /* range_option info */
@@ -197,7 +198,7 @@ struct ixgb_option {
};
static int __devinit
-ixgb_validate_option(int *value, struct ixgb_option *opt)
+ixgb_validate_option(unsigned int *value, const struct ixgb_option *opt)
{
if(*value == OPTION_UNSET) {
*value = opt->def;
@@ -266,7 +267,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
}
{ /* Transmit Descriptor Count */
- struct ixgb_option opt = {
+ const struct ixgb_option opt = {
.type = range_option,
.name = "Transmit Descriptors",
.err = "using default of " __MODULE_STRING(DEFAULT_TXD),
@@ -285,7 +286,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
tx_ring->count = ALIGN(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
}
{ /* Receive Descriptor Count */
- struct ixgb_option opt = {
+ const struct ixgb_option opt = {
.type = range_option,
.name = "Receive Descriptors",
.err = "using default of " __MODULE_STRING(DEFAULT_RXD),
@@ -304,7 +305,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
rx_ring->count = ALIGN(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
}
{ /* Receive Checksum Offload Enable */
- struct ixgb_option opt = {
+ const struct ixgb_option opt = {
.type = enable_option,
.name = "Receive Checksum Offload",
.err = "defaulting to Enabled",
@@ -312,7 +313,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
};
if(num_XsumRX > bd) {
- int rx_csum = XsumRX[bd];
+ unsigned int rx_csum = XsumRX[bd];
ixgb_validate_option(&rx_csum, &opt);
adapter->rx_csum = rx_csum;
} else {
@@ -328,7 +329,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
{ ixgb_fc_full, "Flow Control Enabled" },
{ ixgb_fc_default, "Flow Control Hardware Default" }};
- struct ixgb_option opt = {
+ const struct ixgb_option opt = {
.type = list_option,
.name = "Flow Control",
.err = "reading default settings from EEPROM",
@@ -338,7 +339,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
};
if(num_FlowControl > bd) {
- int fc = FlowControl[bd];
+ unsigned int fc = FlowControl[bd];
ixgb_validate_option(&fc, &opt);
adapter->hw.fc.type = fc;
} else {
@@ -346,7 +347,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
}
}
{ /* Receive Flow Control High Threshold */
- struct ixgb_option opt = {
+ const struct ixgb_option opt = {
.type = range_option,
.name = "Rx Flow Control High Threshold",
.err = "using default of " __MODULE_STRING(DEFAULT_FCRTH),
@@ -366,7 +367,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
"Ignoring RxFCHighThresh when no RxFC\n");
}
{ /* Receive Flow Control Low Threshold */
- struct ixgb_option opt = {
+ const struct ixgb_option opt = {
.type = range_option,
.name = "Rx Flow Control Low Threshold",
.err = "using default of " __MODULE_STRING(DEFAULT_FCRTL),
@@ -386,7 +387,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
"Ignoring RxFCLowThresh when no RxFC\n");
}
{ /* Flow Control Pause Time Request*/
- struct ixgb_option opt = {
+ const struct ixgb_option opt = {
.type = range_option,
.name = "Flow Control Pause Time Request",
.err = "using default of "__MODULE_STRING(DEFAULT_FCPAUSE),
@@ -396,7 +397,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
};
if(num_FCReqTimeout > bd) {
- int pause_time = FCReqTimeout[bd];
+ unsigned int pause_time = FCReqTimeout[bd];
ixgb_validate_option(&pause_time, &opt);
adapter->hw.fc.pause_time = pause_time;
} else {
@@ -419,7 +420,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
}
}
{ /* Receive Interrupt Delay */
- struct ixgb_option opt = {
+ const struct ixgb_option opt = {
.type = range_option,
.name = "Receive Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_RDTR),
@@ -436,7 +437,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
}
}
{ /* Transmit Interrupt Delay */
- struct ixgb_option opt = {
+ const struct ixgb_option opt = {
.type = range_option,
.name = "Transmit Interrupt Delay",
.err = "using default of " __MODULE_STRING(DEFAULT_TIDV),
@@ -454,7 +455,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
}
{ /* Transmit Interrupt Delay Enable */
- struct ixgb_option opt = {
+ const struct ixgb_option opt = {
.type = enable_option,
.name = "Tx Interrupt Delay Enable",
.err = "defaulting to Enabled",
@@ -462,7 +463,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
};
if(num_IntDelayEnable > bd) {
- int ide = IntDelayEnable[bd];
+ unsigned int ide = IntDelayEnable[bd];
ixgb_validate_option(&ide, &opt);
adapter->tx_int_delay_enable = ide;
} else {
diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile
new file mode 100644
index 00000000000..ccd83d9f579
--- /dev/null
+++ b/drivers/net/ixgbe/Makefile
@@ -0,0 +1,36 @@
+################################################################################
+#
+# Intel 10 Gigabit PCI Express Linux driver
+# Copyright(c) 1999 - 2007 Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# Linux NICS <linux.nics@intel.com>
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) 10GbE PCI Express ethernet driver
+#
+
+obj-$(CONFIG_IXGBE) += ixgbe.o
+
+ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
+ ixgbe_82598.o ixgbe_phy.o
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
new file mode 100644
index 00000000000..bc51432b8d2
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -0,0 +1,259 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_H_
+#define _IXGBE_H_
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+
+#include "ixgbe_type.h"
+#include "ixgbe_common.h"
+
+
+#define IXGBE_ERR(args...) printk(KERN_ERR "ixgbe: " args)
+
+#define PFX "ixgbe: "
+#define DPRINTK(nlevel, klevel, fmt, args...) \
+ ((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \
+ printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \
+ __FUNCTION__ , ## args)))
+
+/* TX/RX descriptor defines */
+#define IXGBE_DEFAULT_TXD 1024
+#define IXGBE_MAX_TXD 4096
+#define IXGBE_MIN_TXD 64
+
+#define IXGBE_DEFAULT_RXD 1024
+#define IXGBE_MAX_RXD 4096
+#define IXGBE_MIN_RXD 64
+
+#define IXGBE_DEFAULT_RXQ 1
+#define IXGBE_MAX_RXQ 1
+#define IXGBE_MIN_RXQ 1
+
+#define IXGBE_DEFAULT_ITR_RX_USECS 125 /* 8k irqs/sec */
+#define IXGBE_DEFAULT_ITR_TX_USECS 250 /* 4k irqs/sec */
+#define IXGBE_MIN_ITR_USECS 100 /* 500k irqs/sec */
+#define IXGBE_MAX_ITR_USECS 10000 /* 100 irqs/sec */
+
+/* flow control */
+#define IXGBE_DEFAULT_FCRTL 0x10000
+#define IXGBE_MIN_FCRTL 0
+#define IXGBE_MAX_FCRTL 0x7FF80
+#define IXGBE_DEFAULT_FCRTH 0x20000
+#define IXGBE_MIN_FCRTH 0
+#define IXGBE_MAX_FCRTH 0x7FFF0
+#define IXGBE_DEFAULT_FCPAUSE 0x6800 /* may be too long */
+#define IXGBE_MIN_FCPAUSE 0
+#define IXGBE_MAX_FCPAUSE 0xFFFF
+
+/* Supported Rx Buffer Sizes */
+#define IXGBE_RXBUFFER_64 64 /* Used for packet split */
+#define IXGBE_RXBUFFER_128 128 /* Used for packet split */
+#define IXGBE_RXBUFFER_256 256 /* Used for packet split */
+#define IXGBE_RXBUFFER_2048 2048
+
+#define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_256
+
+#define MAXIMUM_ETHERNET_VLAN_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
+
+/* How many Tx Descriptors do we need to call netif_wake_queue? */
+#define IXGBE_TX_QUEUE_WAKE 16
+
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define IXGBE_RX_BUFFER_WRITE 16 /* Must be power of 2 */
+
+#define IXGBE_TX_FLAGS_CSUM (u32)(1)
+#define IXGBE_TX_FLAGS_VLAN (u32)(1 << 1)
+#define IXGBE_TX_FLAGS_TSO (u32)(1 << 2)
+#define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3)
+#define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000
+#define IXGBE_TX_FLAGS_VLAN_SHIFT 16
+
+/* wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer */
+struct ixgbe_tx_buffer {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ unsigned long time_stamp;
+ u16 length;
+ u16 next_to_watch;
+};
+
+struct ixgbe_rx_buffer {
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ struct page *page;
+ dma_addr_t page_dma;
+};
+
+struct ixgbe_queue_stats {
+ u64 packets;
+ u64 bytes;
+};
+
+struct ixgbe_ring {
+ struct ixgbe_adapter *adapter; /* backlink */
+ void *desc; /* descriptor ring memory */
+ dma_addr_t dma; /* phys. address of descriptor ring */
+ unsigned int size; /* length in bytes */
+ unsigned int count; /* amount of descriptors */
+ unsigned int next_to_use;
+ unsigned int next_to_clean;
+
+ union {
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ struct ixgbe_rx_buffer *rx_buffer_info;
+ };
+
+ u16 head;
+ u16 tail;
+
+ /* To protect race between sender and clean_tx_irq */
+ spinlock_t tx_lock;
+
+ struct ixgbe_queue_stats stats;
+
+ u32 eims_value;
+ u16 itr_register;
+
+ char name[IFNAMSIZ + 5];
+ u16 work_limit; /* max work per interrupt */
+};
+
+/* Helper macros to switch between ints/sec and what the register uses.
+ * And yes, it's the same math going both ways.
+ */
+#define EITR_INTS_PER_SEC_TO_REG(_eitr) \
+ ((_eitr) ? (1000000000 / ((_eitr) * 256)) : 0)
+#define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG
+
+#define IXGBE_DESC_UNUSED(R) \
+ ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+ (R)->next_to_clean - (R)->next_to_use - 1)
+
+#define IXGBE_RX_DESC_ADV(R, i) \
+ (&(((union ixgbe_adv_rx_desc *)((R).desc))[i]))
+#define IXGBE_TX_DESC_ADV(R, i) \
+ (&(((union ixgbe_adv_tx_desc *)((R).desc))[i]))
+#define IXGBE_TX_CTXTDESC_ADV(R, i) \
+ (&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i]))
+
+#define IXGBE_MAX_JUMBO_FRAME_SIZE 16128
+
+/* board specific private data structure */
+struct ixgbe_adapter {
+ struct timer_list watchdog_timer;
+ struct vlan_group *vlgrp;
+ u16 bd_number;
+ u16 rx_buf_len;
+ atomic_t irq_sem;
+ struct work_struct reset_task;
+
+ /* TX */
+ struct ixgbe_ring *tx_ring; /* One per active queue */
+ struct napi_struct napi;
+ u64 restart_queue;
+ u64 lsc_int;
+ u64 hw_tso_ctxt;
+ u64 hw_tso6_ctxt;
+ u32 tx_timeout_count;
+ bool detect_tx_hung;
+
+ /* RX */
+ struct ixgbe_ring *rx_ring; /* One per active queue */
+ u64 hw_csum_tx_good;
+ u64 hw_csum_rx_error;
+ u64 hw_csum_rx_good;
+ u64 non_eop_descs;
+ int num_tx_queues;
+ int num_rx_queues;
+ struct msix_entry *msix_entries;
+
+ u64 rx_hdr_split;
+ u32 alloc_rx_page_failed;
+ u32 alloc_rx_buff_failed;
+
+ u32 flags;
+#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1)
+#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 1)
+#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 2)
+#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 3)
+#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 4)
+
+ /* Interrupt Throttle Rate */
+ u32 rx_eitr;
+ u32 tx_eitr;
+
+ /* OS defined structs */
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct net_device_stats net_stats;
+
+ /* structs defined in ixgbe_hw.h */
+ struct ixgbe_hw hw;
+ u16 msg_enable;
+ struct ixgbe_hw_stats stats;
+ char lsc_name[IFNAMSIZ + 5];
+
+ unsigned long state;
+ u64 tx_busy;
+};
+
+enum ixbge_state_t {
+ __IXGBE_TESTING,
+ __IXGBE_RESETTING,
+ __IXGBE_DOWN
+};
+
+enum ixgbe_boards {
+ board_82598AF,
+ board_82598EB,
+ board_82598AT,
+};
+
+extern struct ixgbe_info ixgbe_82598AF_info;
+extern struct ixgbe_info ixgbe_82598EB_info;
+extern struct ixgbe_info ixgbe_82598AT_info;
+
+extern char ixgbe_driver_name[];
+extern const char ixgbe_driver_version[];
+
+extern int ixgbe_up(struct ixgbe_adapter *adapter);
+extern void ixgbe_down(struct ixgbe_adapter *adapter);
+extern void ixgbe_reset(struct ixgbe_adapter *adapter);
+extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
+extern void ixgbe_set_ethtool_ops(struct net_device *netdev);
+extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rxdr);
+extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *txdr);
+
+#endif /* _IXGBE_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
new file mode 100644
index 00000000000..4d64673164c
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -0,0 +1,588 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "ixgbe.h"
+#include "ixgbe_phy.h"
+
+#define IXGBE_82598_MAX_TX_QUEUES 32
+#define IXGBE_82598_MAX_RX_QUEUES 64
+#define IXGBE_82598_RAR_ENTRIES 16
+
+static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw);
+static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed,
+ bool *autoneg);
+static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw,
+ u32 *speed, bool *autoneg);
+static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw);
+static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw);
+static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed,
+ bool *link_up);
+static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
+ bool autoneg,
+ bool autoneg_wait_to_complete);
+static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw);
+static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed,
+ bool *link_up);
+static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
+ bool autoneg,
+ bool autoneg_wait_to_complete);
+static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw);
+
+
+static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw)
+{
+ hw->mac.num_rx_queues = IXGBE_82598_MAX_TX_QUEUES;
+ hw->mac.num_tx_queues = IXGBE_82598_MAX_RX_QUEUES;
+ hw->mac.num_rx_addrs = IXGBE_82598_RAR_ENTRIES;
+
+ return 0;
+}
+
+/**
+ * ixgbe_get_link_settings_82598 - Determines default link settings
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @autoneg: boolean auto-negotiation value
+ *
+ * Determines the default link settings by reading the AUTOC register.
+ **/
+static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed,
+ bool *autoneg)
+{
+ s32 status = 0;
+ s32 autoc_reg;
+
+ autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+
+ if (hw->mac.link_settings_loaded) {
+ autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE;
+ autoc_reg &= ~IXGBE_AUTOC_LMS_MASK;
+ autoc_reg |= hw->mac.link_attach_type;
+ autoc_reg |= hw->mac.link_mode_select;
+ }
+
+ switch (autoc_reg & IXGBE_AUTOC_LMS_MASK) {
+ case IXGBE_AUTOC_LMS_1G_LINK_NO_AN:
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
+ *autoneg = false;
+ break;
+
+ case IXGBE_AUTOC_LMS_10G_LINK_NO_AN:
+ *speed = IXGBE_LINK_SPEED_10GB_FULL;
+ *autoneg = false;
+ break;
+
+ case IXGBE_AUTOC_LMS_1G_AN:
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
+ *autoneg = true;
+ break;
+
+ case IXGBE_AUTOC_LMS_KX4_AN:
+ case IXGBE_AUTOC_LMS_KX4_AN_1G_AN:
+ *speed = IXGBE_LINK_SPEED_UNKNOWN;
+ if (autoc_reg & IXGBE_AUTOC_KX4_SUPP)
+ *speed |= IXGBE_LINK_SPEED_10GB_FULL;
+ if (autoc_reg & IXGBE_AUTOC_KX_SUPP)
+ *speed |= IXGBE_LINK_SPEED_1GB_FULL;
+ *autoneg = true;
+ break;
+
+ default:
+ status = IXGBE_ERR_LINK_SETUP;
+ break;
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_get_copper_link_settings_82598 - Determines default link settings
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @autoneg: boolean auto-negotiation value
+ *
+ * Determines the default link settings by reading the AUTOC register.
+ **/
+static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw,
+ u32 *speed, bool *autoneg)
+{
+ s32 status = IXGBE_ERR_LINK_SETUP;
+ u16 speed_ability;
+
+ *speed = 0;
+ *autoneg = true;
+
+ status = ixgbe_read_phy_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ &speed_ability);
+
+ if (status == 0) {
+ if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G)
+ *speed |= IXGBE_LINK_SPEED_10GB_FULL;
+ if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G)
+ *speed |= IXGBE_LINK_SPEED_1GB_FULL;
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_get_media_type_82598 - Determines media type
+ * @hw: pointer to hardware structure
+ *
+ * Returns the media type (fiber, copper, backplane)
+ **/
+static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw)
+{
+ enum ixgbe_media_type media_type;
+
+ /* Media type for I82598 is based on device ID */
+ switch (hw->device_id) {
+ case IXGBE_DEV_ID_82598AF_DUAL_PORT:
+ case IXGBE_DEV_ID_82598AF_SINGLE_PORT:
+ case IXGBE_DEV_ID_82598EB_CX4:
+ media_type = ixgbe_media_type_fiber;
+ break;
+ case IXGBE_DEV_ID_82598AT_DUAL_PORT:
+ media_type = ixgbe_media_type_copper;
+ break;
+ default:
+ media_type = ixgbe_media_type_unknown;
+ break;
+ }
+
+ return media_type;
+}
+
+/**
+ * ixgbe_setup_mac_link_82598 - Configures MAC link settings
+ * @hw: pointer to hardware structure
+ *
+ * Configures link settings based on values in the ixgbe_hw struct.
+ * Restarts the link. Performs autonegotiation if needed.
+ **/
+static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw)
+{
+ u32 autoc_reg;
+ u32 links_reg;
+ u32 i;
+ s32 status = 0;
+
+ autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+
+ if (hw->mac.link_settings_loaded) {
+ autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE;
+ autoc_reg &= ~IXGBE_AUTOC_LMS_MASK;
+ autoc_reg |= hw->mac.link_attach_type;
+ autoc_reg |= hw->mac.link_mode_select;
+
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+ msleep(50);
+ }
+
+ /* Restart link */
+ autoc_reg |= IXGBE_AUTOC_AN_RESTART;
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+
+ /* Only poll for autoneg to complete if specified to do so */
+ if (hw->phy.autoneg_wait_to_complete) {
+ if (hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN ||
+ hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN_1G_AN) {
+ links_reg = 0; /* Just in case Autoneg time = 0 */
+ for (i = 0; i < IXGBE_AUTO_NEG_TIME; i++) {
+ links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
+ if (links_reg & IXGBE_LINKS_KX_AN_COMP)
+ break;
+ msleep(100);
+ }
+ if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
+ status = IXGBE_ERR_AUTONEG_NOT_COMPLETE;
+ hw_dbg(hw,
+ "Autonegotiation did not complete.\n");
+ }
+ }
+ }
+
+ /*
+ * We want to save off the original Flow Control configuration just in
+ * case we get disconnected and then reconnected into a different hub
+ * or switch with different Flow Control capabilities.
+ */
+ hw->fc.type = hw->fc.original_type;
+ ixgbe_setup_fc(hw, 0);
+
+ /* Add delay to filter out noises during initial link setup */
+ msleep(50);
+
+ return status;
+}
+
+/**
+ * ixgbe_check_mac_link_82598 - Get link/speed status
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @link_up: true is link is up, false otherwise
+ *
+ * Reads the links register to determine if link is up and the current speed
+ **/
+static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed,
+ bool *link_up)
+{
+ u32 links_reg;
+
+ links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
+
+ if (links_reg & IXGBE_LINKS_UP)
+ *link_up = true;
+ else
+ *link_up = false;
+
+ if (links_reg & IXGBE_LINKS_SPEED)
+ *speed = IXGBE_LINK_SPEED_10GB_FULL;
+ else
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
+
+ return 0;
+}
+
+/**
+ * ixgbe_setup_mac_link_speed_82598 - Set MAC link speed
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg: true if auto-negotiation enabled
+ * @autoneg_wait_to_complete: true if waiting is needed to complete
+ *
+ * Set the link speed in the AUTOC register and restarts link.
+ **/
+static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw,
+ u32 speed, bool autoneg,
+ bool autoneg_wait_to_complete)
+{
+ s32 status = 0;
+
+ /* If speed is 10G, then check for CX4 or XAUI. */
+ if ((speed == IXGBE_LINK_SPEED_10GB_FULL) &&
+ (!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4)))
+ hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN;
+ else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg))
+ hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_LINK_NO_AN;
+ else if (autoneg) {
+ /* BX mode - Autonegotiate 1G */
+ if (!(hw->mac.link_attach_type & IXGBE_AUTOC_1G_PMA_PMD))
+ hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_AN;
+ else /* KX/KX4 mode */
+ hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN_1G_AN;
+ } else {
+ status = IXGBE_ERR_LINK_SETUP;
+ }
+
+ if (status == 0) {
+ hw->phy.autoneg_wait_to_complete = autoneg_wait_to_complete;
+
+ hw->mac.link_settings_loaded = true;
+ /*
+ * Setup and restart the link based on the new values in
+ * ixgbe_hw This will write the AUTOC register based on the new
+ * stored values
+ */
+ hw->phy.ops.setup(hw);
+ }
+
+ return status;
+}
+
+
+/**
+ * ixgbe_setup_copper_link_82598 - Setup copper link settings
+ * @hw: pointer to hardware structure
+ *
+ * Configures link settings based on values in the ixgbe_hw struct.
+ * Restarts the link. Performs autonegotiation if needed. Restart
+ * phy and wait for autonegotiate to finish. Then synchronize the
+ * MAC and PHY.
+ **/
+static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw)
+{
+ s32 status;
+ u32 speed = 0;
+ bool link_up = false;
+
+ /* Set up MAC */
+ hw->phy.ops.setup(hw);
+
+ /* Restart autonegotiation on PHY */
+ status = hw->phy.ops.setup(hw);
+
+ /* Synchronize MAC to PHY speed */
+ if (status == 0)
+ status = hw->phy.ops.check(hw, &speed, &link_up);
+
+ return status;
+}
+
+/**
+ * ixgbe_check_copper_link_82598 - Syncs MAC & PHY link settings
+ * @hw: pointer to hardware structure
+ * @speed: pointer to link speed
+ * @link_up: true if link is up, false otherwise
+ *
+ * Reads the mac link, phy link, and synchronizes the MAC to PHY.
+ **/
+static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed,
+ bool *link_up)
+{
+ s32 status;
+ u32 phy_speed = 0;
+ bool phy_link = false;
+
+ /* This is the speed and link the MAC is set at */
+ hw->phy.ops.check(hw, speed, link_up);
+
+ /*
+ * Check current speed and link status of the PHY register.
+ * This is a vendor specific register and may have to
+ * be changed for other copper PHYs.
+ */
+ status = hw->phy.ops.check(hw, &phy_speed, &phy_link);
+
+ if ((status == 0) && (phy_link)) {
+ /*
+ * Check current link status of the MACs link's register
+ * matches that of the speed in the PHY register
+ */
+ if (*speed != phy_speed) {
+ /*
+ * The copper PHY requires 82598 attach type to be XAUI
+ * for 10G and BX for 1G
+ */
+ hw->mac.link_attach_type =
+ (IXGBE_AUTOC_10G_XAUI | IXGBE_AUTOC_1G_BX);
+
+ /* Synchronize the MAC speed to the PHY speed */
+ status = hw->phy.ops.setup_speed(hw, phy_speed, false,
+ false);
+ if (status == 0)
+ hw->phy.ops.check(hw, speed, link_up);
+ else
+ status = IXGBE_ERR_LINK_SETUP;
+ }
+ } else {
+ *link_up = phy_link;
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_setup_copper_link_speed_82598 - Set the PHY autoneg advertised field
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg: true if autonegotiation enabled
+ * @autoneg_wait_to_complete: true if waiting is needed to complete
+ *
+ * Sets the link speed in the AUTOC register in the MAC and restarts link.
+ **/
+static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
+ bool autoneg,
+ bool autoneg_wait_to_complete)
+{
+ s32 status;
+ bool link_up = 0;
+
+ /* Setup the PHY according to input speed */
+ status = hw->phy.ops.setup_speed(hw, speed, autoneg,
+ autoneg_wait_to_complete);
+
+ /* Synchronize MAC to PHY speed */
+ if (status == 0)
+ status = hw->phy.ops.check(hw, &speed, &link_up);
+
+ return status;
+}
+
+/**
+ * ixgbe_reset_hw_82598 - Performs hardware reset
+ * @hw: pointer to hardware structure
+ *
+ * Resets the hardware by reseting the transmit and receive units, masks and
+ * clears all interrupts, performing a PHY reset, and performing a link (MAC)
+ * reset.
+ **/
+static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw)
+{
+ s32 status = 0;
+ u32 ctrl;
+ u32 gheccr;
+ u32 i;
+ u32 autoc;
+ u8 analog_val;
+
+ /* Call adapter stop to disable tx/rx and clear interrupts */
+ ixgbe_stop_adapter(hw);
+
+ /*
+ * Power up the Atlas TX lanes if they are currently powered down.
+ * Atlas TX lanes are powered down for MAC loopback tests, but
+ * they are not automatically restored on reset.
+ */
+ ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val);
+ if (analog_val & IXGBE_ATLAS_PDN_TX_REG_EN) {
+ /* Enable TX Atlas so packets can be transmitted again */
+ ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val);
+ analog_val &= ~IXGBE_ATLAS_PDN_TX_REG_EN;
+ ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, analog_val);
+
+ ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &analog_val);
+ analog_val &= ~IXGBE_ATLAS_PDN_TX_10G_QL_ALL;
+ ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, analog_val);
+
+ ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &analog_val);
+ analog_val &= ~IXGBE_ATLAS_PDN_TX_1G_QL_ALL;
+ ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, analog_val);
+
+ ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &analog_val);
+ analog_val &= ~IXGBE_ATLAS_PDN_TX_AN_QL_ALL;
+ ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, analog_val);
+ }
+
+ /* Reset PHY */
+ ixgbe_reset_phy(hw);
+
+ /*
+ * Prevent the PCI-E bus from from hanging by disabling PCI-E master
+ * access and verify no pending requests before reset
+ */
+ if (ixgbe_disable_pcie_master(hw) != 0) {
+ status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
+ hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+ }
+
+ /*
+ * Issue global reset to the MAC. This needs to be a SW reset.
+ * If link reset is used, it might reset the MAC when mng is using it
+ */
+ ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+ IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | IXGBE_CTRL_RST));
+ IXGBE_WRITE_FLUSH(hw);
+
+ /* Poll for reset bit to self-clear indicating reset is complete */
+ for (i = 0; i < 10; i++) {
+ udelay(1);
+ ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+ if (!(ctrl & IXGBE_CTRL_RST))
+ break;
+ }
+ if (ctrl & IXGBE_CTRL_RST) {
+ status = IXGBE_ERR_RESET_FAILED;
+ hw_dbg(hw, "Reset polling failed to complete.\n");
+ }
+
+ msleep(50);
+
+ gheccr = IXGBE_READ_REG(hw, IXGBE_GHECCR);
+ gheccr &= ~((1 << 21) | (1 << 18) | (1 << 9) | (1 << 6));
+ IXGBE_WRITE_REG(hw, IXGBE_GHECCR, gheccr);
+
+ /*
+ * AUTOC register which stores link settings gets cleared
+ * and reloaded from EEPROM after reset. We need to restore
+ * our stored value from init in case SW changed the attach
+ * type or speed. If this is the first time and link settings
+ * have not been stored, store default settings from AUTOC.
+ */
+ autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ if (hw->mac.link_settings_loaded) {
+ autoc &= ~(IXGBE_AUTOC_LMS_ATTACH_TYPE);
+ autoc &= ~(IXGBE_AUTOC_LMS_MASK);
+ autoc |= hw->mac.link_attach_type;
+ autoc |= hw->mac.link_mode_select;
+ IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
+ } else {
+ hw->mac.link_attach_type =
+ (autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE);
+ hw->mac.link_mode_select = (autoc & IXGBE_AUTOC_LMS_MASK);
+ hw->mac.link_settings_loaded = true;
+ }
+
+ /* Store the permanent mac address */
+ ixgbe_get_mac_addr(hw, hw->mac.perm_addr);
+
+ return status;
+}
+
+static struct ixgbe_mac_operations mac_ops_82598 = {
+ .reset = &ixgbe_reset_hw_82598,
+ .get_media_type = &ixgbe_get_media_type_82598,
+};
+
+static struct ixgbe_phy_operations phy_ops_82598EB = {
+ .setup = &ixgbe_setup_copper_link_82598,
+ .check = &ixgbe_check_copper_link_82598,
+ .setup_speed = &ixgbe_setup_copper_link_speed_82598,
+ .get_settings = &ixgbe_get_copper_link_settings_82598,
+};
+
+struct ixgbe_info ixgbe_82598EB_info = {
+ .mac = ixgbe_mac_82598EB,
+ .get_invariants = &ixgbe_get_invariants_82598,
+ .mac_ops = &mac_ops_82598,
+ .phy_ops = &phy_ops_82598EB,
+};
+
+static struct ixgbe_phy_operations phy_ops_82598AT = {
+ .setup = &ixgbe_setup_tnx_phy_link,
+ .check = &ixgbe_check_tnx_phy_link,
+ .setup_speed = &ixgbe_setup_tnx_phy_link_speed,
+ .get_settings = &ixgbe_get_copper_link_settings_82598,
+};
+
+struct ixgbe_info ixgbe_82598AT_info = {
+ .mac = ixgbe_mac_82598EB,
+ .get_invariants = &ixgbe_get_invariants_82598,
+ .mac_ops = &mac_ops_82598,
+ .phy_ops = &phy_ops_82598AT,
+};
+
+static struct ixgbe_phy_operations phy_ops_82598AF = {
+ .setup = &ixgbe_setup_mac_link_82598,
+ .check = &ixgbe_check_mac_link_82598,
+ .setup_speed = &ixgbe_setup_mac_link_speed_82598,
+ .get_settings = &ixgbe_get_link_settings_82598,
+};
+
+struct ixgbe_info ixgbe_82598AF_info = {
+ .mac = ixgbe_mac_82598EB,
+ .get_invariants = &ixgbe_get_invariants_82598,
+ .mac_ops = &mac_ops_82598,
+ .phy_ops = &phy_ops_82598AF,
+};
+
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
new file mode 100644
index 00000000000..512e3b22ed0
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -0,0 +1,1175 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "ixgbe_common.h"
+#include "ixgbe_phy.h"
+
+static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw);
+
+static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw);
+static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw);
+static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw);
+static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw);
+
+static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw);
+static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw);
+static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr);
+static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr);
+
+/**
+ * ixgbe_start_hw - Prepare hardware for TX/RX
+ * @hw: pointer to hardware structure
+ *
+ * Starts the hardware by filling the bus info structure and media type, clears
+ * all on chip counters, initializes receive address registers, multicast
+ * table, VLAN filter table, calls routine to set up link and flow control
+ * settings, and leaves transmit and receive units disabled and uninitialized
+ **/
+s32 ixgbe_start_hw(struct ixgbe_hw *hw)
+{
+ u32 ctrl_ext;
+
+ /* Set the media type */
+ hw->phy.media_type = hw->mac.ops.get_media_type(hw);
+
+ /* Identify the PHY */
+ ixgbe_identify_phy(hw);
+
+ /*
+ * Store MAC address from RAR0, clear receive address registers, and
+ * clear the multicast table
+ */
+ ixgbe_init_rx_addrs(hw);
+
+ /* Clear the VLAN filter table */
+ ixgbe_clear_vfta(hw);
+
+ /* Set up link */
+ hw->phy.ops.setup(hw);
+
+ /* Clear statistics registers */
+ ixgbe_clear_hw_cntrs(hw);
+
+ /* Set No Snoop Disable */
+ ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+ ctrl_ext |= IXGBE_CTRL_EXT_NS_DIS;
+ IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
+
+ /* Clear adapter stopped flag */
+ hw->adapter_stopped = false;
+
+ return 0;
+}
+
+/**
+ * ixgbe_init_hw - Generic hardware initialization
+ * @hw: pointer to hardware structure
+ *
+ * Initialize the hardware by reseting the hardware, filling the bus info
+ * structure and media type, clears all on chip counters, initializes receive
+ * address registers, multicast table, VLAN filter table, calls routine to set
+ * up link and flow control settings, and leaves transmit and receive units
+ * disabled and uninitialized
+ **/
+s32 ixgbe_init_hw(struct ixgbe_hw *hw)
+{
+ /* Reset the hardware */
+ hw->mac.ops.reset(hw);
+
+ /* Start the HW */
+ ixgbe_start_hw(hw);
+
+ return 0;
+}
+
+/**
+ * ixgbe_clear_hw_cntrs - Generic clear hardware counters
+ * @hw: pointer to hardware structure
+ *
+ * Clears all hardware statistics counters by reading them from the hardware
+ * Statistics counters are clear on read.
+ **/
+static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw)
+{
+ u16 i = 0;
+
+ IXGBE_READ_REG(hw, IXGBE_CRCERRS);
+ IXGBE_READ_REG(hw, IXGBE_ILLERRC);
+ IXGBE_READ_REG(hw, IXGBE_ERRBC);
+ IXGBE_READ_REG(hw, IXGBE_MSPDC);
+ for (i = 0; i < 8; i++)
+ IXGBE_READ_REG(hw, IXGBE_MPC(i));
+
+ IXGBE_READ_REG(hw, IXGBE_MLFC);
+ IXGBE_READ_REG(hw, IXGBE_MRFC);
+ IXGBE_READ_REG(hw, IXGBE_RLEC);
+ IXGBE_READ_REG(hw, IXGBE_LXONTXC);
+ IXGBE_READ_REG(hw, IXGBE_LXONRXC);
+ IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
+ IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
+
+ for (i = 0; i < 8; i++) {
+ IXGBE_READ_REG(hw, IXGBE_PXONTXC(i));
+ IXGBE_READ_REG(hw, IXGBE_PXONRXC(i));
+ IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i));
+ IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i));
+ }
+
+ IXGBE_READ_REG(hw, IXGBE_PRC64);
+ IXGBE_READ_REG(hw, IXGBE_PRC127);
+ IXGBE_READ_REG(hw, IXGBE_PRC255);
+ IXGBE_READ_REG(hw, IXGBE_PRC511);
+ IXGBE_READ_REG(hw, IXGBE_PRC1023);
+ IXGBE_READ_REG(hw, IXGBE_PRC1522);
+ IXGBE_READ_REG(hw, IXGBE_GPRC);
+ IXGBE_READ_REG(hw, IXGBE_BPRC);
+ IXGBE_READ_REG(hw, IXGBE_MPRC);
+ IXGBE_READ_REG(hw, IXGBE_GPTC);
+ IXGBE_READ_REG(hw, IXGBE_GORCL);
+ IXGBE_READ_REG(hw, IXGBE_GORCH);
+ IXGBE_READ_REG(hw, IXGBE_GOTCL);
+ IXGBE_READ_REG(hw, IXGBE_GOTCH);
+ for (i = 0; i < 8; i++)
+ IXGBE_READ_REG(hw, IXGBE_RNBC(i));
+ IXGBE_READ_REG(hw, IXGBE_RUC);
+ IXGBE_READ_REG(hw, IXGBE_RFC);
+ IXGBE_READ_REG(hw, IXGBE_ROC);
+ IXGBE_READ_REG(hw, IXGBE_RJC);
+ IXGBE_READ_REG(hw, IXGBE_MNGPRC);
+ IXGBE_READ_REG(hw, IXGBE_MNGPDC);
+ IXGBE_READ_REG(hw, IXGBE_MNGPTC);
+ IXGBE_READ_REG(hw, IXGBE_TORL);
+ IXGBE_READ_REG(hw, IXGBE_TORH);
+ IXGBE_READ_REG(hw, IXGBE_TPR);
+ IXGBE_READ_REG(hw, IXGBE_TPT);
+ IXGBE_READ_REG(hw, IXGBE_PTC64);
+ IXGBE_READ_REG(hw, IXGBE_PTC127);
+ IXGBE_READ_REG(hw, IXGBE_PTC255);
+ IXGBE_READ_REG(hw, IXGBE_PTC511);
+ IXGBE_READ_REG(hw, IXGBE_PTC1023);
+ IXGBE_READ_REG(hw, IXGBE_PTC1522);
+ IXGBE_READ_REG(hw, IXGBE_MPTC);
+ IXGBE_READ_REG(hw, IXGBE_BPTC);
+ for (i = 0; i < 16; i++) {
+ IXGBE_READ_REG(hw, IXGBE_QPRC(i));
+ IXGBE_READ_REG(hw, IXGBE_QBRC(i));
+ IXGBE_READ_REG(hw, IXGBE_QPTC(i));
+ IXGBE_READ_REG(hw, IXGBE_QBTC(i));
+ }
+
+ return 0;
+}
+
+/**
+ * ixgbe_get_mac_addr - Generic get MAC address
+ * @hw: pointer to hardware structure
+ * @mac_addr: Adapter MAC address
+ *
+ * Reads the adapter's MAC address from first Receive Address Register (RAR0)
+ * A reset of the adapter must be performed prior to calling this function
+ * in order for the MAC address to have been loaded from the EEPROM into RAR0
+ **/
+s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr)
+{
+ u32 rar_high;
+ u32 rar_low;
+ u16 i;
+
+ rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(0));
+ rar_low = IXGBE_READ_REG(hw, IXGBE_RAL(0));
+
+ for (i = 0; i < 4; i++)
+ mac_addr[i] = (u8)(rar_low >> (i*8));
+
+ for (i = 0; i < 2; i++)
+ mac_addr[i+4] = (u8)(rar_high >> (i*8));
+
+ return 0;
+}
+
+s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num)
+{
+ s32 ret_val;
+ u16 data;
+
+ ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM0_PTR, &data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+ *part_num = (u32)(data << 16);
+
+ ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM1_PTR, &data);
+ if (ret_val) {
+ hw_dbg(hw, "NVM Read Error\n");
+ return ret_val;
+ }
+ *part_num |= data;
+
+ return 0;
+}
+
+/**
+ * ixgbe_stop_adapter - Generic stop TX/RX units
+ * @hw: pointer to hardware structure
+ *
+ * Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts,
+ * disables transmit and receive units. The adapter_stopped flag is used by
+ * the shared code and drivers to determine if the adapter is in a stopped
+ * state and should not touch the hardware.
+ **/
+s32 ixgbe_stop_adapter(struct ixgbe_hw *hw)
+{
+ u32 number_of_queues;
+ u32 reg_val;
+ u16 i;
+
+ /*
+ * Set the adapter_stopped flag so other driver functions stop touching
+ * the hardware
+ */
+ hw->adapter_stopped = true;
+
+ /* Disable the receive unit */
+ reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+ reg_val &= ~(IXGBE_RXCTRL_RXEN);
+ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val);
+ msleep(2);
+
+ /* Clear interrupt mask to stop from interrupts being generated */
+ IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK);
+
+ /* Clear any pending interrupts */
+ IXGBE_READ_REG(hw, IXGBE_EICR);
+
+ /* Disable the transmit unit. Each queue must be disabled. */
+ number_of_queues = hw->mac.num_tx_queues;
+ for (i = 0; i < number_of_queues; i++) {
+ reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
+ if (reg_val & IXGBE_TXDCTL_ENABLE) {
+ reg_val &= ~IXGBE_TXDCTL_ENABLE;
+ IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), reg_val);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * ixgbe_led_on - Turns on the software controllable LEDs.
+ * @hw: pointer to hardware structure
+ * @index: led number to turn on
+ **/
+s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index)
+{
+ u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+
+ /* To turn on the LED, set mode to ON. */
+ led_reg &= ~IXGBE_LED_MODE_MASK(index);
+ led_reg |= IXGBE_LED_ON << IXGBE_LED_MODE_SHIFT(index);
+ IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg);
+
+ return 0;
+}
+
+/**
+ * ixgbe_led_off - Turns off the software controllable LEDs.
+ * @hw: pointer to hardware structure
+ * @index: led number to turn off
+ **/
+s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index)
+{
+ u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+
+ /* To turn off the LED, set mode to OFF. */
+ led_reg &= ~IXGBE_LED_MODE_MASK(index);
+ led_reg |= IXGBE_LED_OFF << IXGBE_LED_MODE_SHIFT(index);
+ IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg);
+
+ return 0;
+}
+
+
+/**
+ * ixgbe_init_eeprom - Initialize EEPROM params
+ * @hw: pointer to hardware structure
+ *
+ * Initializes the EEPROM parameters ixgbe_eeprom_info within the
+ * ixgbe_hw struct in order to set up EEPROM access.
+ **/
+s32 ixgbe_init_eeprom(struct ixgbe_hw *hw)
+{
+ struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+ u32 eec;
+ u16 eeprom_size;
+
+ if (eeprom->type == ixgbe_eeprom_uninitialized) {
+ eeprom->type = ixgbe_eeprom_none;
+
+ /*
+ * Check for EEPROM present first.
+ * If not present leave as none
+ */
+ eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+ if (eec & IXGBE_EEC_PRES) {
+ eeprom->type = ixgbe_eeprom_spi;
+
+ /*
+ * SPI EEPROM is assumed here. This code would need to
+ * change if a future EEPROM is not SPI.
+ */
+ eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >>
+ IXGBE_EEC_SIZE_SHIFT);
+ eeprom->word_size = 1 << (eeprom_size +
+ IXGBE_EEPROM_WORD_SIZE_SHIFT);
+ }
+
+ if (eec & IXGBE_EEC_ADDR_SIZE)
+ eeprom->address_bits = 16;
+ else
+ eeprom->address_bits = 8;
+ hw_dbg(hw, "Eeprom params: type = %d, size = %d, address bits: "
+ "%d\n", eeprom->type, eeprom->word_size,
+ eeprom->address_bits);
+ }
+
+ return 0;
+}
+
+/**
+ * ixgbe_read_eeprom - Read EEPROM word using EERD
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data)
+{
+ u32 eerd;
+ s32 status;
+
+ eerd = (offset << IXGBE_EEPROM_READ_ADDR_SHIFT) +
+ IXGBE_EEPROM_READ_REG_START;
+
+ IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd);
+ status = ixgbe_poll_eeprom_eerd_done(hw);
+
+ if (status == 0)
+ *data = (IXGBE_READ_REG(hw, IXGBE_EERD) >>
+ IXGBE_EEPROM_READ_REG_DATA);
+ else
+ hw_dbg(hw, "Eeprom read timed out\n");
+
+ return status;
+}
+
+/**
+ * ixgbe_poll_eeprom_eerd_done - Poll EERD status
+ * @hw: pointer to hardware structure
+ *
+ * Polls the status bit (bit 1) of the EERD to determine when the read is done.
+ **/
+static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw)
+{
+ u32 i;
+ u32 reg;
+ s32 status = IXGBE_ERR_EEPROM;
+
+ for (i = 0; i < IXGBE_EERD_ATTEMPTS; i++) {
+ reg = IXGBE_READ_REG(hw, IXGBE_EERD);
+ if (reg & IXGBE_EEPROM_READ_REG_DONE) {
+ status = 0;
+ break;
+ }
+ udelay(5);
+ }
+ return status;
+}
+
+/**
+ * ixgbe_get_eeprom_semaphore - Get hardware semaphore
+ * @hw: pointer to hardware structure
+ *
+ * Sets the hardware semaphores so EEPROM access can occur for bit-bang method
+ **/
+static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw)
+{
+ s32 status = IXGBE_ERR_EEPROM;
+ u32 timeout;
+ u32 i;
+ u32 swsm;
+
+ /* Set timeout value based on size of EEPROM */
+ timeout = hw->eeprom.word_size + 1;
+
+ /* Get SMBI software semaphore between device drivers first */
+ for (i = 0; i < timeout; i++) {
+ /*
+ * If the SMBI bit is 0 when we read it, then the bit will be
+ * set and we have the semaphore
+ */
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+ if (!(swsm & IXGBE_SWSM_SMBI)) {
+ status = 0;
+ break;
+ }
+ msleep(1);
+ }
+
+ /* Now get the semaphore between SW/FW through the SWESMBI bit */
+ if (status == 0) {
+ for (i = 0; i < timeout; i++) {
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+
+ /* Set the SW EEPROM semaphore bit to request access */
+ swsm |= IXGBE_SWSM_SWESMBI;
+ IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm);
+
+ /*
+ * If we set the bit successfully then we got the
+ * semaphore.
+ */
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+ if (swsm & IXGBE_SWSM_SWESMBI)
+ break;
+
+ udelay(50);
+ }
+
+ /*
+ * Release semaphores and return error if SW EEPROM semaphore
+ * was not granted because we don't have access to the EEPROM
+ */
+ if (i >= timeout) {
+ hw_dbg(hw, "Driver can't access the Eeprom - Semaphore "
+ "not granted.\n");
+ ixgbe_release_eeprom_semaphore(hw);
+ status = IXGBE_ERR_EEPROM;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_release_eeprom_semaphore - Release hardware semaphore
+ * @hw: pointer to hardware structure
+ *
+ * This function clears hardware semaphore bits.
+ **/
+static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw)
+{
+ u32 swsm;
+
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+
+ /* Release both semaphores by writing 0 to the bits SWESMBI and SMBI */
+ swsm &= ~(IXGBE_SWSM_SWESMBI | IXGBE_SWSM_SMBI);
+ IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm);
+}
+
+/**
+ * ixgbe_calc_eeprom_checksum - Calculates and returns the checksum
+ * @hw: pointer to hardware structure
+ **/
+static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw)
+{
+ u16 i;
+ u16 j;
+ u16 checksum = 0;
+ u16 length = 0;
+ u16 pointer = 0;
+ u16 word = 0;
+
+ /* Include 0x0-0x3F in the checksum */
+ for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) {
+ if (ixgbe_read_eeprom(hw, i, &word) != 0) {
+ hw_dbg(hw, "EEPROM read failed\n");
+ break;
+ }
+ checksum += word;
+ }
+
+ /* Include all data from pointers except for the fw pointer */
+ for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) {
+ ixgbe_read_eeprom(hw, i, &pointer);
+
+ /* Make sure the pointer seems valid */
+ if (pointer != 0xFFFF && pointer != 0) {
+ ixgbe_read_eeprom(hw, pointer, &length);
+
+ if (length != 0xFFFF && length != 0) {
+ for (j = pointer+1; j <= pointer+length; j++) {
+ ixgbe_read_eeprom(hw, j, &word);
+ checksum += word;
+ }
+ }
+ }
+ }
+
+ checksum = (u16)IXGBE_EEPROM_SUM - checksum;
+
+ return checksum;
+}
+
+/**
+ * ixgbe_validate_eeprom_checksum - Validate EEPROM checksum
+ * @hw: pointer to hardware structure
+ * @checksum_val: calculated checksum
+ *
+ * Performs checksum calculation and validates the EEPROM checksum. If the
+ * caller does not need checksum_val, the value can be NULL.
+ **/
+s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val)
+{
+ s32 status;
+ u16 checksum;
+ u16 read_checksum = 0;
+
+ /*
+ * Read the first word from the EEPROM. If this times out or fails, do
+ * not continue or we could be in for a very long wait while every
+ * EEPROM read fails
+ */
+ status = ixgbe_read_eeprom(hw, 0, &checksum);
+
+ if (status == 0) {
+ checksum = ixgbe_calc_eeprom_checksum(hw);
+
+ ixgbe_read_eeprom(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum);
+
+ /*
+ * Verify read checksum from EEPROM is the same as
+ * calculated checksum
+ */
+ if (read_checksum != checksum)
+ status = IXGBE_ERR_EEPROM_CHECKSUM;
+
+ /* If the user cares, return the calculated checksum */
+ if (checksum_val)
+ *checksum_val = checksum;
+ } else {
+ hw_dbg(hw, "EEPROM read failed\n");
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_validate_mac_addr - Validate MAC address
+ * @mac_addr: pointer to MAC address.
+ *
+ * Tests a MAC address to ensure it is a valid Individual Address
+ **/
+s32 ixgbe_validate_mac_addr(u8 *mac_addr)
+{
+ s32 status = 0;
+
+ /* Make sure it is not a multicast address */
+ if (IXGBE_IS_MULTICAST(mac_addr))
+ status = IXGBE_ERR_INVALID_MAC_ADDR;
+ /* Not a broadcast address */
+ else if (IXGBE_IS_BROADCAST(mac_addr))
+ status = IXGBE_ERR_INVALID_MAC_ADDR;
+ /* Reject the zero address */
+ else if (mac_addr[0] == 0 && mac_addr[1] == 0 && mac_addr[2] == 0 &&
+ mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0)
+ status = IXGBE_ERR_INVALID_MAC_ADDR;
+
+ return status;
+}
+
+/**
+ * ixgbe_set_rar - Set RX address register
+ * @hw: pointer to hardware structure
+ * @addr: Address to put into receive address register
+ * @index: Receive address register to write
+ * @vind: Vind to set RAR to
+ * @enable_addr: set flag that address is active
+ *
+ * Puts an ethernet address into a receive address register.
+ **/
+s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind,
+ u32 enable_addr)
+{
+ u32 rar_low, rar_high;
+
+ /*
+ * HW expects these in little endian so we reverse the byte order from
+ * network order (big endian) to little endian
+ */
+ rar_low = ((u32)addr[0] |
+ ((u32)addr[1] << 8) |
+ ((u32)addr[2] << 16) |
+ ((u32)addr[3] << 24));
+
+ rar_high = ((u32)addr[4] |
+ ((u32)addr[5] << 8) |
+ ((vind << IXGBE_RAH_VIND_SHIFT) & IXGBE_RAH_VIND_MASK));
+
+ if (enable_addr != 0)
+ rar_high |= IXGBE_RAH_AV;
+
+ IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low);
+ IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high);
+
+ return 0;
+}
+
+/**
+ * ixgbe_init_rx_addrs - Initializes receive address filters.
+ * @hw: pointer to hardware structure
+ *
+ * Places the MAC address in receive address register 0 and clears the rest
+ * of the receive addresss registers. Clears the multicast table. Assumes
+ * the receiver is in reset when the routine is called.
+ **/
+static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw)
+{
+ u32 i;
+ u32 rar_entries = hw->mac.num_rx_addrs;
+
+ /*
+ * If the current mac address is valid, assume it is a software override
+ * to the permanent address.
+ * Otherwise, use the permanent address from the eeprom.
+ */
+ if (ixgbe_validate_mac_addr(hw->mac.addr) ==
+ IXGBE_ERR_INVALID_MAC_ADDR) {
+ /* Get the MAC address from the RAR0 for later reference */
+ ixgbe_get_mac_addr(hw, hw->mac.addr);
+
+ hw_dbg(hw, " Keeping Current RAR0 Addr =%.2X %.2X %.2X ",
+ hw->mac.addr[0], hw->mac.addr[1],
+ hw->mac.addr[2]);
+ hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3],
+ hw->mac.addr[4], hw->mac.addr[5]);
+ } else {
+ /* Setup the receive address. */
+ hw_dbg(hw, "Overriding MAC Address in RAR[0]\n");
+ hw_dbg(hw, " New MAC Addr =%.2X %.2X %.2X ",
+ hw->mac.addr[0], hw->mac.addr[1],
+ hw->mac.addr[2]);
+ hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3],
+ hw->mac.addr[4], hw->mac.addr[5]);
+
+ ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
+ }
+
+ hw->addr_ctrl.rar_used_count = 1;
+
+ /* Zero out the other receive addresses. */
+ hw_dbg(hw, "Clearing RAR[1-15]\n");
+ for (i = 1; i < rar_entries; i++) {
+ IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0);
+ }
+
+ /* Clear the MTA */
+ hw->addr_ctrl.mc_addr_in_rar_count = 0;
+ hw->addr_ctrl.mta_in_use = 0;
+ IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type);
+
+ hw_dbg(hw, " Clearing MTA\n");
+ for (i = 0; i < IXGBE_MC_TBL_SIZE; i++)
+ IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0);
+
+ return 0;
+}
+
+/**
+ * ixgbe_mta_vector - Determines bit-vector in multicast table to set
+ * @hw: pointer to hardware structure
+ * @mc_addr: the multicast address
+ *
+ * Extracts the 12 bits, from a multicast address, to determine which
+ * bit-vector to set in the multicast table. The hardware uses 12 bits, from
+ * incoming rx multicast addresses, to determine the bit-vector to check in
+ * the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set
+ * by the MO field of the MCSTCTRL. The MO field is set during initalization
+ * to mc_filter_type.
+ **/
+static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr)
+{
+ u32 vector = 0;
+
+ switch (hw->mac.mc_filter_type) {
+ case 0: /* use bits [47:36] of the address */
+ vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4));
+ break;
+ case 1: /* use bits [46:35] of the address */
+ vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5));
+ break;
+ case 2: /* use bits [45:34] of the address */
+ vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6));
+ break;
+ case 3: /* use bits [43:32] of the address */
+ vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8));
+ break;
+ default: /* Invalid mc_filter_type */
+ hw_dbg(hw, "MC filter type param set incorrectly\n");
+ break;
+ }
+
+ /* vector can only be 12-bits or boundary will be exceeded */
+ vector &= 0xFFF;
+ return vector;
+}
+
+/**
+ * ixgbe_set_mta - Set bit-vector in multicast table
+ * @hw: pointer to hardware structure
+ * @hash_value: Multicast address hash value
+ *
+ * Sets the bit-vector in the multicast table.
+ **/
+static void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr)
+{
+ u32 vector;
+ u32 vector_bit;
+ u32 vector_reg;
+ u32 mta_reg;
+
+ hw->addr_ctrl.mta_in_use++;
+
+ vector = ixgbe_mta_vector(hw, mc_addr);
+ hw_dbg(hw, " bit-vector = 0x%03X\n", vector);
+
+ /*
+ * The MTA is a register array of 128 32-bit registers. It is treated
+ * like an array of 4096 bits. We want to set bit
+ * BitArray[vector_value]. So we figure out what register the bit is
+ * in, read it, OR in the new bit, then write back the new value. The
+ * register is determined by the upper 7 bits of the vector value and
+ * the bit within that register are determined by the lower 5 bits of
+ * the value.
+ */
+ vector_reg = (vector >> 5) & 0x7F;
+ vector_bit = vector & 0x1F;
+ mta_reg = IXGBE_READ_REG(hw, IXGBE_MTA(vector_reg));
+ mta_reg |= (1 << vector_bit);
+ IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg);
+}
+
+/**
+ * ixgbe_add_mc_addr - Adds a multicast address.
+ * @hw: pointer to hardware structure
+ * @mc_addr: new multicast address
+ *
+ * Adds it to unused receive address register or to the multicast table.
+ **/
+static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr)
+{
+ u32 rar_entries = hw->mac.num_rx_addrs;
+
+ hw_dbg(hw, " MC Addr =%.2X %.2X %.2X %.2X %.2X %.2X\n",
+ mc_addr[0], mc_addr[1], mc_addr[2],
+ mc_addr[3], mc_addr[4], mc_addr[5]);
+
+ /*
+ * Place this multicast address in the RAR if there is room,
+ * else put it in the MTA
+ */
+ if (hw->addr_ctrl.rar_used_count < rar_entries) {
+ ixgbe_set_rar(hw, hw->addr_ctrl.rar_used_count,
+ mc_addr, 0, IXGBE_RAH_AV);
+ hw_dbg(hw, "Added a multicast address to RAR[%d]\n",
+ hw->addr_ctrl.rar_used_count);
+ hw->addr_ctrl.rar_used_count++;
+ hw->addr_ctrl.mc_addr_in_rar_count++;
+ } else {
+ ixgbe_set_mta(hw, mc_addr);
+ }
+
+ hw_dbg(hw, "ixgbe_add_mc_addr Complete\n");
+}
+
+/**
+ * ixgbe_update_mc_addr_list - Updates MAC list of multicast addresses
+ * @hw: pointer to hardware structure
+ * @mc_addr_list: the list of new multicast addresses
+ * @mc_addr_count: number of addresses
+ * @pad: number of bytes between addresses in the list
+ *
+ * The given list replaces any existing list. Clears the MC addrs from receive
+ * address registers and the multicast table. Uses unsed receive address
+ * registers for the first multicast addresses, and hashes the rest into the
+ * multicast table.
+ **/
+s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list,
+ u32 mc_addr_count, u32 pad)
+{
+ u32 i;
+ u32 rar_entries = hw->mac.num_rx_addrs;
+
+ /*
+ * Set the new number of MC addresses that we are being requested to
+ * use.
+ */
+ hw->addr_ctrl.num_mc_addrs = mc_addr_count;
+ hw->addr_ctrl.rar_used_count -= hw->addr_ctrl.mc_addr_in_rar_count;
+ hw->addr_ctrl.mc_addr_in_rar_count = 0;
+ hw->addr_ctrl.mta_in_use = 0;
+
+ /* Zero out the other receive addresses. */
+ hw_dbg(hw, "Clearing RAR[1-15]\n");
+ for (i = hw->addr_ctrl.rar_used_count; i < rar_entries; i++) {
+ IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0);
+ }
+
+ /* Clear the MTA */
+ hw_dbg(hw, " Clearing MTA\n");
+ for (i = 0; i < IXGBE_MC_TBL_SIZE; i++)
+ IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0);
+
+ /* Add the new addresses */
+ for (i = 0; i < mc_addr_count; i++) {
+ hw_dbg(hw, " Adding the multicast addresses:\n");
+ ixgbe_add_mc_addr(hw, mc_addr_list +
+ (i * (IXGBE_ETH_LENGTH_OF_ADDRESS + pad)));
+ }
+
+ /* Enable mta */
+ if (hw->addr_ctrl.mta_in_use > 0)
+ IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL,
+ IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type);
+
+ hw_dbg(hw, "ixgbe_update_mc_addr_list Complete\n");
+ return 0;
+}
+
+/**
+ * ixgbe_clear_vfta - Clear VLAN filter table
+ * @hw: pointer to hardware structure
+ *
+ * Clears the VLAN filer table, and the VMDq index associated with the filter
+ **/
+static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw)
+{
+ u32 offset;
+ u32 vlanbyte;
+
+ for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++)
+ IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0);
+
+ for (vlanbyte = 0; vlanbyte < 4; vlanbyte++)
+ for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++)
+ IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vlanbyte, offset),
+ 0);
+
+ return 0;
+}
+
+/**
+ * ixgbe_set_vfta - Set VLAN filter table
+ * @hw: pointer to hardware structure
+ * @vlan: VLAN id to write to VLAN filter
+ * @vind: VMDq output index that maps queue to VLAN id in VFTA
+ * @vlan_on: boolean flag to turn on/off VLAN in VFTA
+ *
+ * Turn on/off specified VLAN in the VLAN filter table.
+ **/
+s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind,
+ bool vlan_on)
+{
+ u32 VftaIndex;
+ u32 BitOffset;
+ u32 VftaReg;
+ u32 VftaByte;
+
+ /* Determine 32-bit word position in array */
+ VftaIndex = (vlan >> 5) & 0x7F; /* upper seven bits */
+
+ /* Determine the location of the (VMD) queue index */
+ VftaByte = ((vlan >> 3) & 0x03); /* bits (4:3) indicating byte array */
+ BitOffset = (vlan & 0x7) << 2; /* lower 3 bits indicate nibble */
+
+ /* Set the nibble for VMD queue index */
+ VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex));
+ VftaReg &= (~(0x0F << BitOffset));
+ VftaReg |= (vind << BitOffset);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex), VftaReg);
+
+ /* Determine the location of the bit for this VLAN id */
+ BitOffset = vlan & 0x1F; /* lower five bits */
+
+ VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTA(VftaIndex));
+ if (vlan_on)
+ /* Turn on this VLAN id */
+ VftaReg |= (1 << BitOffset);
+ else
+ /* Turn off this VLAN id */
+ VftaReg &= ~(1 << BitOffset);
+ IXGBE_WRITE_REG(hw, IXGBE_VFTA(VftaIndex), VftaReg);
+
+ return 0;
+}
+
+/**
+ * ixgbe_setup_fc - Configure flow control settings
+ * @hw: pointer to hardware structure
+ * @packetbuf_num: packet buffer number (0-7)
+ *
+ * Configures the flow control settings based on SW configuration.
+ * This function is used for 802.3x flow control configuration only.
+ **/
+s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num)
+{
+ u32 frctl_reg;
+ u32 rmcs_reg;
+
+ if (packetbuf_num < 0 || packetbuf_num > 7)
+ hw_dbg(hw, "Invalid packet buffer number [%d], expected range"
+ "is 0-7\n", packetbuf_num);
+
+ frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+ frctl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE);
+
+ rmcs_reg = IXGBE_READ_REG(hw, IXGBE_RMCS);
+ rmcs_reg &= ~(IXGBE_RMCS_TFCE_PRIORITY | IXGBE_RMCS_TFCE_802_3X);
+
+ /*
+ * We want to save off the original Flow Control configuration just in
+ * case we get disconnected and then reconnected into a different hub
+ * or switch with different Flow Control capabilities.
+ */
+ hw->fc.type = hw->fc.original_type;
+
+ /*
+ * The possible values of the "flow_control" parameter are:
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames but not
+ * send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames but we do not
+ * support receiving pause frames)
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
+ * other: Invalid.
+ */
+ switch (hw->fc.type) {
+ case ixgbe_fc_none:
+ break;
+ case ixgbe_fc_rx_pause:
+ /*
+ * RX Flow control is enabled,
+ * and TX Flow control is disabled.
+ */
+ frctl_reg |= IXGBE_FCTRL_RFCE;
+ break;
+ case ixgbe_fc_tx_pause:
+ /*
+ * TX Flow control is enabled, and RX Flow control is disabled,
+ * by a software over-ride.
+ */
+ rmcs_reg |= IXGBE_RMCS_TFCE_802_3X;
+ break;
+ case ixgbe_fc_full:
+ /*
+ * Flow control (both RX and TX) is enabled by a software
+ * over-ride.
+ */
+ frctl_reg |= IXGBE_FCTRL_RFCE;
+ rmcs_reg |= IXGBE_RMCS_TFCE_802_3X;
+ break;
+ default:
+ /* We should never get here. The value should be 0-3. */
+ hw_dbg(hw, "Flow control param set incorrectly\n");
+ break;
+ }
+
+ /* Enable 802.3x based flow control settings. */
+ IXGBE_WRITE_REG(hw, IXGBE_FCTRL, frctl_reg);
+ IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg);
+
+ /*
+ * We need to set up the Receive Threshold high and low water
+ * marks as well as (optionally) enabling the transmission of
+ * XON frames.
+ */
+ if (hw->fc.type & ixgbe_fc_tx_pause) {
+ if (hw->fc.send_xon) {
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
+ (hw->fc.low_water | IXGBE_FCRTL_XONE));
+ } else {
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
+ hw->fc.low_water);
+ }
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num),
+ (hw->fc.high_water)|IXGBE_FCRTH_FCEN);
+ }
+
+ IXGBE_WRITE_REG(hw, IXGBE_FCTTV(0), hw->fc.pause_time);
+ IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1));
+
+ return 0;
+}
+
+/**
+ * ixgbe_disable_pcie_master - Disable PCI-express master access
+ * @hw: pointer to hardware structure
+ *
+ * Disables PCI-Express master access and verifies there are no pending
+ * requests. IXGBE_ERR_MASTER_REQUESTS_PENDING is returned if master disable
+ * bit hasn't caused the master requests to be disabled, else 0
+ * is returned signifying master requests disabled.
+ **/
+s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
+{
+ u32 ctrl;
+ s32 i;
+ s32 status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
+
+ ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+ ctrl |= IXGBE_CTRL_GIO_DIS;
+ IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
+
+ for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
+ if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) {
+ status = 0;
+ break;
+ }
+ udelay(100);
+ }
+
+ return status;
+}
+
+
+/**
+ * ixgbe_acquire_swfw_sync - Aquire SWFW semaphore
+ * @hw: pointer to hardware structure
+ * @mask: Mask to specify wich semaphore to acquire
+ *
+ * Aquires the SWFW semaphore throught the GSSR register for the specified
+ * function (CSR, PHY0, PHY1, EEPROM, Flash)
+ **/
+s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask)
+{
+ u32 gssr;
+ u32 swmask = mask;
+ u32 fwmask = mask << 5;
+ s32 timeout = 200;
+
+ while (timeout) {
+ if (ixgbe_get_eeprom_semaphore(hw))
+ return -IXGBE_ERR_SWFW_SYNC;
+
+ gssr = IXGBE_READ_REG(hw, IXGBE_GSSR);
+ if (!(gssr & (fwmask | swmask)))
+ break;
+
+ /*
+ * Firmware currently using resource (fwmask) or other software
+ * thread currently using resource (swmask)
+ */
+ ixgbe_release_eeprom_semaphore(hw);
+ msleep(5);
+ timeout--;
+ }
+
+ if (!timeout) {
+ hw_dbg(hw, "Driver can't access resource, GSSR timeout.\n");
+ return -IXGBE_ERR_SWFW_SYNC;
+ }
+
+ gssr |= swmask;
+ IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr);
+
+ ixgbe_release_eeprom_semaphore(hw);
+ return 0;
+}
+
+/**
+ * ixgbe_release_swfw_sync - Release SWFW semaphore
+ * @hw: pointer to hardware structure
+ * @mask: Mask to specify wich semaphore to release
+ *
+ * Releases the SWFW semaphore throught the GSSR register for the specified
+ * function (CSR, PHY0, PHY1, EEPROM, Flash)
+ **/
+void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask)
+{
+ u32 gssr;
+ u32 swmask = mask;
+
+ ixgbe_get_eeprom_semaphore(hw);
+
+ gssr = IXGBE_READ_REG(hw, IXGBE_GSSR);
+ gssr &= ~swmask;
+ IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr);
+
+ ixgbe_release_eeprom_semaphore(hw);
+}
+
+/**
+ * ixgbe_read_analog_reg8- Reads 8 bit 82598 Atlas analog register
+ * @hw: pointer to hardware structure
+ * @reg: analog register to read
+ * @val: read value
+ *
+ * Performs write operation to analog register specified.
+ **/
+s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val)
+{
+ u32 atlas_ctl;
+
+ IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL,
+ IXGBE_ATLASCTL_WRITE_CMD | (reg << 8));
+ IXGBE_WRITE_FLUSH(hw);
+ udelay(10);
+ atlas_ctl = IXGBE_READ_REG(hw, IXGBE_ATLASCTL);
+ *val = (u8)atlas_ctl;
+
+ return 0;
+}
+
+/**
+ * ixgbe_write_analog_reg8- Writes 8 bit Atlas analog register
+ * @hw: pointer to hardware structure
+ * @reg: atlas register to write
+ * @val: value to write
+ *
+ * Performs write operation to Atlas analog register specified.
+ **/
+s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val)
+{
+ u32 atlas_ctl;
+
+ atlas_ctl = (reg << 8) | val;
+ IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, atlas_ctl);
+ IXGBE_WRITE_FLUSH(hw);
+ udelay(10);
+
+ return 0;
+}
+
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
new file mode 100644
index 00000000000..de6ddd5d04a
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -0,0 +1,86 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_COMMON_H_
+#define _IXGBE_COMMON_H_
+
+#include "ixgbe_type.h"
+
+s32 ixgbe_init_hw(struct ixgbe_hw *hw);
+s32 ixgbe_start_hw(struct ixgbe_hw *hw);
+s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr);
+s32 ixgbe_stop_adapter(struct ixgbe_hw *hw);
+s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num);
+
+s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index);
+s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index);
+
+s32 ixgbe_init_eeprom(struct ixgbe_hw *hw);
+s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data);
+s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val);
+
+s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind,
+ u32 enable_addr);
+s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list,
+ u32 mc_addr_count, u32 pad);
+s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on);
+s32 ixgbe_validate_mac_addr(u8 *mac_addr);
+
+s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packtetbuf_num);
+
+s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask);
+void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask);
+s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw);
+
+s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val);
+s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val);
+
+#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
+
+#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg))
+
+#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) (\
+ writel((value), ((a)->hw_addr + (reg) + ((offset) << 2))))
+
+#define IXGBE_READ_REG_ARRAY(a, reg, offset) (\
+ readl((a)->hw_addr + (reg) + ((offset) << 2)))
+
+#define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS)
+
+#ifdef DEBUG
+#define hw_dbg(hw, format, arg...) \
+printk(KERN_DEBUG, "%s: " format, ixgbe_get_hw_dev_name(hw), ##arg);
+#else
+static inline int __attribute__ ((format (printf, 2, 3)))
+hw_dbg(struct ixgbe_hw *hw, const char *format, ...)
+{
+ return 0;
+}
+#endif
+
+#endif /* IXGBE_COMMON */
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
new file mode 100644
index 00000000000..a4e576a0c54
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -0,0 +1,948 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for ixgbe */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+#include "ixgbe.h"
+
+
+#define IXGBE_ALL_RAR_ENTRIES 16
+
+struct ixgbe_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+};
+
+#define IXGBE_STAT(m) sizeof(((struct ixgbe_adapter *)0)->m), \
+ offsetof(struct ixgbe_adapter, m)
+static struct ixgbe_stats ixgbe_gstrings_stats[] = {
+ {"rx_packets", IXGBE_STAT(net_stats.rx_packets)},
+ {"tx_packets", IXGBE_STAT(net_stats.tx_packets)},
+ {"rx_bytes", IXGBE_STAT(net_stats.rx_bytes)},
+ {"tx_bytes", IXGBE_STAT(net_stats.tx_bytes)},
+ {"lsc_int", IXGBE_STAT(lsc_int)},
+ {"tx_busy", IXGBE_STAT(tx_busy)},
+ {"non_eop_descs", IXGBE_STAT(non_eop_descs)},
+ {"rx_errors", IXGBE_STAT(net_stats.rx_errors)},
+ {"tx_errors", IXGBE_STAT(net_stats.tx_errors)},
+ {"rx_dropped", IXGBE_STAT(net_stats.rx_dropped)},
+ {"tx_dropped", IXGBE_STAT(net_stats.tx_dropped)},
+ {"multicast", IXGBE_STAT(net_stats.multicast)},
+ {"broadcast", IXGBE_STAT(stats.bprc)},
+ {"rx_no_buffer_count", IXGBE_STAT(stats.rnbc[0]) },
+ {"collisions", IXGBE_STAT(net_stats.collisions)},
+ {"rx_over_errors", IXGBE_STAT(net_stats.rx_over_errors)},
+ {"rx_crc_errors", IXGBE_STAT(net_stats.rx_crc_errors)},
+ {"rx_frame_errors", IXGBE_STAT(net_stats.rx_frame_errors)},
+ {"rx_fifo_errors", IXGBE_STAT(net_stats.rx_fifo_errors)},
+ {"rx_missed_errors", IXGBE_STAT(net_stats.rx_missed_errors)},
+ {"tx_aborted_errors", IXGBE_STAT(net_stats.tx_aborted_errors)},
+ {"tx_carrier_errors", IXGBE_STAT(net_stats.tx_carrier_errors)},
+ {"tx_fifo_errors", IXGBE_STAT(net_stats.tx_fifo_errors)},
+ {"tx_heartbeat_errors", IXGBE_STAT(net_stats.tx_heartbeat_errors)},
+ {"tx_timeout_count", IXGBE_STAT(tx_timeout_count)},
+ {"tx_restart_queue", IXGBE_STAT(restart_queue)},
+ {"rx_long_length_errors", IXGBE_STAT(stats.roc)},
+ {"rx_short_length_errors", IXGBE_STAT(stats.ruc)},
+ {"tx_tcp4_seg_ctxt", IXGBE_STAT(hw_tso_ctxt)},
+ {"tx_tcp6_seg_ctxt", IXGBE_STAT(hw_tso6_ctxt)},
+ {"tx_flow_control_xon", IXGBE_STAT(stats.lxontxc)},
+ {"rx_flow_control_xon", IXGBE_STAT(stats.lxonrxc)},
+ {"tx_flow_control_xoff", IXGBE_STAT(stats.lxofftxc)},
+ {"rx_flow_control_xoff", IXGBE_STAT(stats.lxoffrxc)},
+ {"rx_csum_offload_good", IXGBE_STAT(hw_csum_rx_good)},
+ {"rx_csum_offload_errors", IXGBE_STAT(hw_csum_rx_error)},
+ {"tx_csum_offload_ctxt", IXGBE_STAT(hw_csum_tx_good)},
+ {"rx_header_split", IXGBE_STAT(rx_hdr_split)},
+ {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)},
+ {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)},
+};
+
+#define IXGBE_QUEUE_STATS_LEN \
+ ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \
+ ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \
+ (sizeof(struct ixgbe_queue_stats) / sizeof(u64)))
+#define IXGBE_GLOBAL_STATS_LEN \
+ sizeof(ixgbe_gstrings_stats) / sizeof(struct ixgbe_stats)
+#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN)
+
+static int ixgbe_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
+ ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
+ ecmd->port = PORT_FIBRE;
+ ecmd->transceiver = XCVR_EXTERNAL;
+
+ if (netif_carrier_ok(adapter->netdev)) {
+ ecmd->speed = SPEED_10000;
+ ecmd->duplex = DUPLEX_FULL;
+ } else {
+ ecmd->speed = -1;
+ ecmd->duplex = -1;
+ }
+
+ ecmd->autoneg = AUTONEG_DISABLE;
+ return 0;
+}
+
+static int ixgbe_set_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ if (ecmd->autoneg == AUTONEG_ENABLE ||
+ ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
+ return -EINVAL;
+
+ if (netif_running(adapter->netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_reset(adapter);
+ ixgbe_up(adapter);
+ } else {
+ ixgbe_reset(adapter);
+ }
+
+ return 0;
+}
+
+static void ixgbe_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ pause->autoneg = AUTONEG_DISABLE;
+
+ if (hw->fc.type == ixgbe_fc_rx_pause) {
+ pause->rx_pause = 1;
+ } else if (hw->fc.type == ixgbe_fc_tx_pause) {
+ pause->tx_pause = 1;
+ } else if (hw->fc.type == ixgbe_fc_full) {
+ pause->rx_pause = 1;
+ pause->tx_pause = 1;
+ }
+}
+
+static int ixgbe_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ if (pause->autoneg == AUTONEG_ENABLE)
+ return -EINVAL;
+
+ if (pause->rx_pause && pause->tx_pause)
+ hw->fc.type = ixgbe_fc_full;
+ else if (pause->rx_pause && !pause->tx_pause)
+ hw->fc.type = ixgbe_fc_rx_pause;
+ else if (!pause->rx_pause && pause->tx_pause)
+ hw->fc.type = ixgbe_fc_tx_pause;
+ else if (!pause->rx_pause && !pause->tx_pause)
+ hw->fc.type = ixgbe_fc_none;
+
+ hw->fc.original_type = hw->fc.type;
+
+ if (netif_running(adapter->netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_up(adapter);
+ } else {
+ ixgbe_reset(adapter);
+ }
+
+ return 0;
+}
+
+static u32 ixgbe_get_rx_csum(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ return (adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED);
+}
+
+static int ixgbe_set_rx_csum(struct net_device *netdev, u32 data)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ if (data)
+ adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
+ else
+ adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED;
+
+ if (netif_running(netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_up(adapter);
+ } else {
+ ixgbe_reset(adapter);
+ }
+
+ return 0;
+}
+
+static u32 ixgbe_get_tx_csum(struct net_device *netdev)
+{
+ return (netdev->features & NETIF_F_HW_CSUM) != 0;
+}
+
+static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data)
+{
+ if (data)
+ netdev->features |= NETIF_F_HW_CSUM;
+ else
+ netdev->features &= ~NETIF_F_HW_CSUM;
+
+ return 0;
+}
+
+static int ixgbe_set_tso(struct net_device *netdev, u32 data)
+{
+
+ if (data) {
+ netdev->features |= NETIF_F_TSO;
+ netdev->features |= NETIF_F_TSO6;
+ } else {
+ netdev->features &= ~NETIF_F_TSO;
+ netdev->features &= ~NETIF_F_TSO6;
+ }
+ return 0;
+}
+
+static u32 ixgbe_get_msglevel(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ return adapter->msg_enable;
+}
+
+static void ixgbe_set_msglevel(struct net_device *netdev, u32 data)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ adapter->msg_enable = data;
+}
+
+static int ixgbe_get_regs_len(struct net_device *netdev)
+{
+#define IXGBE_REGS_LEN 1128
+ return IXGBE_REGS_LEN * sizeof(u32);
+}
+
+#define IXGBE_GET_STAT(_A_, _R_) _A_->stats._R_
+
+static void ixgbe_get_regs(struct net_device *netdev,
+ struct ethtool_regs *regs, void *p)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 *regs_buff = p;
+ u8 i;
+
+ memset(p, 0, IXGBE_REGS_LEN * sizeof(u32));
+
+ regs->version = (1 << 24) | hw->revision_id << 16 | hw->device_id;
+
+ /* General Registers */
+ regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_CTRL);
+ regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_STATUS);
+ regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+ regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_ESDP);
+ regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_EODSDP);
+ regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+ regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_FRTIMER);
+ regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_TCPTIMER);
+
+ /* NVM Register */
+ regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_EEC);
+ regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_EERD);
+ regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_FLA);
+ regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_EEMNGCTL);
+ regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_EEMNGDATA);
+ regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_FLMNGCTL);
+ regs_buff[14] = IXGBE_READ_REG(hw, IXGBE_FLMNGDATA);
+ regs_buff[15] = IXGBE_READ_REG(hw, IXGBE_FLMNGCNT);
+ regs_buff[16] = IXGBE_READ_REG(hw, IXGBE_FLOP);
+ regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC);
+
+ /* Interrupt */
+ regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICR);
+ regs_buff[19] = IXGBE_READ_REG(hw, IXGBE_EICS);
+ regs_buff[20] = IXGBE_READ_REG(hw, IXGBE_EIMS);
+ regs_buff[21] = IXGBE_READ_REG(hw, IXGBE_EIMC);
+ regs_buff[22] = IXGBE_READ_REG(hw, IXGBE_EIAC);
+ regs_buff[23] = IXGBE_READ_REG(hw, IXGBE_EIAM);
+ regs_buff[24] = IXGBE_READ_REG(hw, IXGBE_EITR(0));
+ regs_buff[25] = IXGBE_READ_REG(hw, IXGBE_IVAR(0));
+ regs_buff[26] = IXGBE_READ_REG(hw, IXGBE_MSIXT);
+ regs_buff[27] = IXGBE_READ_REG(hw, IXGBE_MSIXPBA);
+ regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL);
+ regs_buff[29] = IXGBE_READ_REG(hw, IXGBE_GPIE);
+
+ /* Flow Control */
+ regs_buff[30] = IXGBE_READ_REG(hw, IXGBE_PFCTOP);
+ regs_buff[31] = IXGBE_READ_REG(hw, IXGBE_FCTTV(0));
+ regs_buff[32] = IXGBE_READ_REG(hw, IXGBE_FCTTV(1));
+ regs_buff[33] = IXGBE_READ_REG(hw, IXGBE_FCTTV(2));
+ regs_buff[34] = IXGBE_READ_REG(hw, IXGBE_FCTTV(3));
+ for (i = 0; i < 8; i++)
+ regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH(i));
+ regs_buff[51] = IXGBE_READ_REG(hw, IXGBE_FCRTV);
+ regs_buff[52] = IXGBE_READ_REG(hw, IXGBE_TFCS);
+
+ /* Receive DMA */
+ for (i = 0; i < 64; i++)
+ regs_buff[53 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAL(i));
+ for (i = 0; i < 64; i++)
+ regs_buff[117 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAH(i));
+ for (i = 0; i < 64; i++)
+ regs_buff[181 + i] = IXGBE_READ_REG(hw, IXGBE_RDLEN(i));
+ for (i = 0; i < 64; i++)
+ regs_buff[245 + i] = IXGBE_READ_REG(hw, IXGBE_RDH(i));
+ for (i = 0; i < 64; i++)
+ regs_buff[309 + i] = IXGBE_READ_REG(hw, IXGBE_RDT(i));
+ for (i = 0; i < 64; i++)
+ regs_buff[373 + i] = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
+ for (i = 0; i < 16; i++)
+ regs_buff[437 + i] = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i));
+ for (i = 0; i < 16; i++)
+ regs_buff[453 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i));
+ regs_buff[469] = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
+ for (i = 0; i < 8; i++)
+ regs_buff[470 + i] = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
+ regs_buff[478] = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+ regs_buff[479] = IXGBE_READ_REG(hw, IXGBE_DROPEN);
+
+ /* Receive */
+ regs_buff[480] = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
+ regs_buff[481] = IXGBE_READ_REG(hw, IXGBE_RFCTL);
+ for (i = 0; i < 16; i++)
+ regs_buff[482 + i] = IXGBE_READ_REG(hw, IXGBE_RAL(i));
+ for (i = 0; i < 16; i++)
+ regs_buff[498 + i] = IXGBE_READ_REG(hw, IXGBE_RAH(i));
+ regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE);
+ regs_buff[515] = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+ regs_buff[516] = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+ regs_buff[517] = IXGBE_READ_REG(hw, IXGBE_MCSTCTRL);
+ regs_buff[518] = IXGBE_READ_REG(hw, IXGBE_MRQC);
+ regs_buff[519] = IXGBE_READ_REG(hw, IXGBE_VMD_CTL);
+ for (i = 0; i < 8; i++)
+ regs_buff[520 + i] = IXGBE_READ_REG(hw, IXGBE_IMIR(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[528 + i] = IXGBE_READ_REG(hw, IXGBE_IMIREXT(i));
+ regs_buff[536] = IXGBE_READ_REG(hw, IXGBE_IMIRVP);
+
+ /* Transmit */
+ for (i = 0; i < 32; i++)
+ regs_buff[537 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAL(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[569 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAH(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[601 + i] = IXGBE_READ_REG(hw, IXGBE_TDLEN(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[633 + i] = IXGBE_READ_REG(hw, IXGBE_TDH(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[665 + i] = IXGBE_READ_REG(hw, IXGBE_TDT(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[697 + i] = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[729 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAL(i));
+ for (i = 0; i < 32; i++)
+ regs_buff[761 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAH(i));
+ regs_buff[793] = IXGBE_READ_REG(hw, IXGBE_DTXCTL);
+ for (i = 0; i < 16; i++)
+ regs_buff[794 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i));
+ regs_buff[810] = IXGBE_READ_REG(hw, IXGBE_TIPG);
+ for (i = 0; i < 8; i++)
+ regs_buff[811 + i] = IXGBE_READ_REG(hw, IXGBE_TXPBSIZE(i));
+ regs_buff[819] = IXGBE_READ_REG(hw, IXGBE_MNGTXMAP);
+
+ /* Wake Up */
+ regs_buff[820] = IXGBE_READ_REG(hw, IXGBE_WUC);
+ regs_buff[821] = IXGBE_READ_REG(hw, IXGBE_WUFC);
+ regs_buff[822] = IXGBE_READ_REG(hw, IXGBE_WUS);
+ regs_buff[823] = IXGBE_READ_REG(hw, IXGBE_IPAV);
+ regs_buff[824] = IXGBE_READ_REG(hw, IXGBE_IP4AT);
+ regs_buff[825] = IXGBE_READ_REG(hw, IXGBE_IP6AT);
+ regs_buff[826] = IXGBE_READ_REG(hw, IXGBE_WUPL);
+ regs_buff[827] = IXGBE_READ_REG(hw, IXGBE_WUPM);
+ regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT);
+
+ /* DCE */
+ regs_buff[829] = IXGBE_READ_REG(hw, IXGBE_RMCS);
+ regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_DPMCS);
+ regs_buff[831] = IXGBE_READ_REG(hw, IXGBE_PDPMCS);
+ regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RUPPBMR);
+ for (i = 0; i < 8; i++)
+ regs_buff[833 + i] = IXGBE_READ_REG(hw, IXGBE_RT2CR(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[841 + i] = IXGBE_READ_REG(hw, IXGBE_RT2SR(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[849 + i] = IXGBE_READ_REG(hw, IXGBE_TDTQ2TCCR(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[857 + i] = IXGBE_READ_REG(hw, IXGBE_TDTQ2TCSR(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[865 + i] = IXGBE_READ_REG(hw, IXGBE_TDPT2TCCR(i));
+ for (i = 0; i < 8; i++)
+ regs_buff[873 + i] = IXGBE_READ_REG(hw, IXGBE_TDPT2TCSR(i));
+
+ /* Statistics */
+ regs_buff[881] = IXGBE_GET_STAT(adapter, crcerrs);
+ regs_buff[882] = IXGBE_GET_STAT(adapter, illerrc);
+ regs_buff[883] = IXGBE_GET_STAT(adapter, errbc);
+ regs_buff[884] = IXGBE_GET_STAT(adapter, mspdc);
+ for (i = 0; i < 8; i++)
+ regs_buff[885 + i] = IXGBE_GET_STAT(adapter, mpc[i]);
+ regs_buff[893] = IXGBE_GET_STAT(adapter, mlfc);
+ regs_buff[894] = IXGBE_GET_STAT(adapter, mrfc);
+ regs_buff[895] = IXGBE_GET_STAT(adapter, rlec);
+ regs_buff[896] = IXGBE_GET_STAT(adapter, lxontxc);
+ regs_buff[897] = IXGBE_GET_STAT(adapter, lxonrxc);
+ regs_buff[898] = IXGBE_GET_STAT(adapter, lxofftxc);
+ regs_buff[899] = IXGBE_GET_STAT(adapter, lxoffrxc);
+ for (i = 0; i < 8; i++)
+ regs_buff[900 + i] = IXGBE_GET_STAT(adapter, pxontxc[i]);
+ for (i = 0; i < 8; i++)
+ regs_buff[908 + i] = IXGBE_GET_STAT(adapter, pxonrxc[i]);
+ for (i = 0; i < 8; i++)
+ regs_buff[916 + i] = IXGBE_GET_STAT(adapter, pxofftxc[i]);
+ for (i = 0; i < 8; i++)
+ regs_buff[924 + i] = IXGBE_GET_STAT(adapter, pxoffrxc[i]);
+ regs_buff[932] = IXGBE_GET_STAT(adapter, prc64);
+ regs_buff[933] = IXGBE_GET_STAT(adapter, prc127);
+ regs_buff[934] = IXGBE_GET_STAT(adapter, prc255);
+ regs_buff[935] = IXGBE_GET_STAT(adapter, prc511);
+ regs_buff[936] = IXGBE_GET_STAT(adapter, prc1023);
+ regs_buff[937] = IXGBE_GET_STAT(adapter, prc1522);
+ regs_buff[938] = IXGBE_GET_STAT(adapter, gprc);
+ regs_buff[939] = IXGBE_GET_STAT(adapter, bprc);
+ regs_buff[940] = IXGBE_GET_STAT(adapter, mprc);
+ regs_buff[941] = IXGBE_GET_STAT(adapter, gptc);
+ regs_buff[942] = IXGBE_GET_STAT(adapter, gorc);
+ regs_buff[944] = IXGBE_GET_STAT(adapter, gotc);
+ for (i = 0; i < 8; i++)
+ regs_buff[946 + i] = IXGBE_GET_STAT(adapter, rnbc[i]);
+ regs_buff[954] = IXGBE_GET_STAT(adapter, ruc);
+ regs_buff[955] = IXGBE_GET_STAT(adapter, rfc);
+ regs_buff[956] = IXGBE_GET_STAT(adapter, roc);
+ regs_buff[957] = IXGBE_GET_STAT(adapter, rjc);
+ regs_buff[958] = IXGBE_GET_STAT(adapter, mngprc);
+ regs_buff[959] = IXGBE_GET_STAT(adapter, mngpdc);
+ regs_buff[960] = IXGBE_GET_STAT(adapter, mngptc);
+ regs_buff[961] = IXGBE_GET_STAT(adapter, tor);
+ regs_buff[963] = IXGBE_GET_STAT(adapter, tpr);
+ regs_buff[964] = IXGBE_GET_STAT(adapter, tpt);
+ regs_buff[965] = IXGBE_GET_STAT(adapter, ptc64);
+ regs_buff[966] = IXGBE_GET_STAT(adapter, ptc127);
+ regs_buff[967] = IXGBE_GET_STAT(adapter, ptc255);
+ regs_buff[968] = IXGBE_GET_STAT(adapter, ptc511);
+ regs_buff[969] = IXGBE_GET_STAT(adapter, ptc1023);
+ regs_buff[970] = IXGBE_GET_STAT(adapter, ptc1522);
+ regs_buff[971] = IXGBE_GET_STAT(adapter, mptc);
+ regs_buff[972] = IXGBE_GET_STAT(adapter, bptc);
+ regs_buff[973] = IXGBE_GET_STAT(adapter, xec);
+ for (i = 0; i < 16; i++)
+ regs_buff[974 + i] = IXGBE_GET_STAT(adapter, qprc[i]);
+ for (i = 0; i < 16; i++)
+ regs_buff[990 + i] = IXGBE_GET_STAT(adapter, qptc[i]);
+ for (i = 0; i < 16; i++)
+ regs_buff[1006 + i] = IXGBE_GET_STAT(adapter, qbrc[i]);
+ for (i = 0; i < 16; i++)
+ regs_buff[1022 + i] = IXGBE_GET_STAT(adapter, qbtc[i]);
+
+ /* MAC */
+ regs_buff[1038] = IXGBE_READ_REG(hw, IXGBE_PCS1GCFIG);
+ regs_buff[1039] = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL);
+ regs_buff[1040] = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA);
+ regs_buff[1041] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG0);
+ regs_buff[1042] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG1);
+ regs_buff[1043] = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
+ regs_buff[1044] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
+ regs_buff[1045] = IXGBE_READ_REG(hw, IXGBE_PCS1GANNP);
+ regs_buff[1046] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLPNP);
+ regs_buff[1047] = IXGBE_READ_REG(hw, IXGBE_HLREG0);
+ regs_buff[1048] = IXGBE_READ_REG(hw, IXGBE_HLREG1);
+ regs_buff[1049] = IXGBE_READ_REG(hw, IXGBE_PAP);
+ regs_buff[1050] = IXGBE_READ_REG(hw, IXGBE_MACA);
+ regs_buff[1051] = IXGBE_READ_REG(hw, IXGBE_APAE);
+ regs_buff[1052] = IXGBE_READ_REG(hw, IXGBE_ARD);
+ regs_buff[1053] = IXGBE_READ_REG(hw, IXGBE_AIS);
+ regs_buff[1054] = IXGBE_READ_REG(hw, IXGBE_MSCA);
+ regs_buff[1055] = IXGBE_READ_REG(hw, IXGBE_MSRWD);
+ regs_buff[1056] = IXGBE_READ_REG(hw, IXGBE_MLADD);
+ regs_buff[1057] = IXGBE_READ_REG(hw, IXGBE_MHADD);
+ regs_buff[1058] = IXGBE_READ_REG(hw, IXGBE_TREG);
+ regs_buff[1059] = IXGBE_READ_REG(hw, IXGBE_PCSS1);
+ regs_buff[1060] = IXGBE_READ_REG(hw, IXGBE_PCSS2);
+ regs_buff[1061] = IXGBE_READ_REG(hw, IXGBE_XPCSS);
+ regs_buff[1062] = IXGBE_READ_REG(hw, IXGBE_SERDESC);
+ regs_buff[1063] = IXGBE_READ_REG(hw, IXGBE_MACS);
+ regs_buff[1064] = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+ regs_buff[1065] = IXGBE_READ_REG(hw, IXGBE_LINKS);
+ regs_buff[1066] = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
+ regs_buff[1067] = IXGBE_READ_REG(hw, IXGBE_AUTOC3);
+ regs_buff[1068] = IXGBE_READ_REG(hw, IXGBE_ANLP1);
+ regs_buff[1069] = IXGBE_READ_REG(hw, IXGBE_ANLP2);
+ regs_buff[1070] = IXGBE_READ_REG(hw, IXGBE_ATLASCTL);
+
+ /* Diagnostic */
+ regs_buff[1071] = IXGBE_READ_REG(hw, IXGBE_RDSTATCTL);
+ for (i = 0; i < 8; i++)
+ regs_buff[1072] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i));
+ regs_buff[1080] = IXGBE_READ_REG(hw, IXGBE_RDHMPN);
+ regs_buff[1081] = IXGBE_READ_REG(hw, IXGBE_RIC_DW0);
+ regs_buff[1082] = IXGBE_READ_REG(hw, IXGBE_RIC_DW1);
+ regs_buff[1083] = IXGBE_READ_REG(hw, IXGBE_RIC_DW2);
+ regs_buff[1084] = IXGBE_READ_REG(hw, IXGBE_RIC_DW3);
+ regs_buff[1085] = IXGBE_READ_REG(hw, IXGBE_RDPROBE);
+ regs_buff[1086] = IXGBE_READ_REG(hw, IXGBE_TDSTATCTL);
+ for (i = 0; i < 8; i++)
+ regs_buff[1087] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i));
+ regs_buff[1095] = IXGBE_READ_REG(hw, IXGBE_TDHMPN);
+ regs_buff[1096] = IXGBE_READ_REG(hw, IXGBE_TIC_DW0);
+ regs_buff[1097] = IXGBE_READ_REG(hw, IXGBE_TIC_DW1);
+ regs_buff[1098] = IXGBE_READ_REG(hw, IXGBE_TIC_DW2);
+ regs_buff[1099] = IXGBE_READ_REG(hw, IXGBE_TIC_DW3);
+ regs_buff[1100] = IXGBE_READ_REG(hw, IXGBE_TDPROBE);
+ regs_buff[1101] = IXGBE_READ_REG(hw, IXGBE_TXBUFCTRL);
+ regs_buff[1102] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA0);
+ regs_buff[1103] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA1);
+ regs_buff[1104] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA2);
+ regs_buff[1105] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA3);
+ regs_buff[1106] = IXGBE_READ_REG(hw, IXGBE_RXBUFCTRL);
+ regs_buff[1107] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA0);
+ regs_buff[1108] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA1);
+ regs_buff[1109] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA2);
+ regs_buff[1110] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA3);
+ for (i = 0; i < 8; i++)
+ regs_buff[1111] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i));
+ regs_buff[1119] = IXGBE_READ_REG(hw, IXGBE_RFVAL);
+ regs_buff[1120] = IXGBE_READ_REG(hw, IXGBE_MDFTC1);
+ regs_buff[1121] = IXGBE_READ_REG(hw, IXGBE_MDFTC2);
+ regs_buff[1122] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO1);
+ regs_buff[1123] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO2);
+ regs_buff[1124] = IXGBE_READ_REG(hw, IXGBE_MDFTS);
+ regs_buff[1125] = IXGBE_READ_REG(hw, IXGBE_PCIEECCCTL);
+ regs_buff[1126] = IXGBE_READ_REG(hw, IXGBE_PBTXECC);
+ regs_buff[1127] = IXGBE_READ_REG(hw, IXGBE_PBRXECC);
+}
+
+static int ixgbe_get_eeprom_len(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ return adapter->hw.eeprom.word_size * 2;
+}
+
+static int ixgbe_get_eeprom(struct net_device *netdev,
+ struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u16 *eeprom_buff;
+ int first_word, last_word, eeprom_len;
+ int ret_val = 0;
+ u16 i;
+
+ if (eeprom->len == 0)
+ return -EINVAL;
+
+ eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+ first_word = eeprom->offset >> 1;
+ last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+ eeprom_len = last_word - first_word + 1;
+
+ eeprom_buff = kmalloc(sizeof(u16) * eeprom_len, GFP_KERNEL);
+ if (!eeprom_buff)
+ return -ENOMEM;
+
+ for (i = 0; i < eeprom_len; i++) {
+ if ((ret_val = ixgbe_read_eeprom(hw, first_word + i,
+ &eeprom_buff[i])))
+ break;
+ }
+
+ /* Device's eeprom is always little-endian, word addressable */
+ for (i = 0; i < eeprom_len; i++)
+ le16_to_cpus(&eeprom_buff[i]);
+
+ memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
+ kfree(eeprom_buff);
+
+ return ret_val;
+}
+
+static void ixgbe_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ strncpy(drvinfo->driver, ixgbe_driver_name, 32);
+ strncpy(drvinfo->version, ixgbe_driver_version, 32);
+ strncpy(drvinfo->fw_version, "N/A", 32);
+ strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+ drvinfo->n_stats = IXGBE_STATS_LEN;
+ drvinfo->regdump_len = ixgbe_get_regs_len(netdev);
+}
+
+static void ixgbe_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_ring *tx_ring = adapter->tx_ring;
+ struct ixgbe_ring *rx_ring = adapter->rx_ring;
+
+ ring->rx_max_pending = IXGBE_MAX_RXD;
+ ring->tx_max_pending = IXGBE_MAX_TXD;
+ ring->rx_mini_max_pending = 0;
+ ring->rx_jumbo_max_pending = 0;
+ ring->rx_pending = rx_ring->count;
+ ring->tx_pending = tx_ring->count;
+ ring->rx_mini_pending = 0;
+ ring->rx_jumbo_pending = 0;
+}
+
+static int ixgbe_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_tx_buffer *old_buf;
+ struct ixgbe_rx_buffer *old_rx_buf;
+ void *old_desc;
+ int i, err;
+ u32 new_rx_count, new_tx_count, old_size;
+ dma_addr_t old_dma;
+
+ if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+ return -EINVAL;
+
+ new_rx_count = max(ring->rx_pending, (u32)IXGBE_MIN_RXD);
+ new_rx_count = min(new_rx_count, (u32)IXGBE_MAX_RXD);
+ new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE);
+
+ new_tx_count = max(ring->tx_pending, (u32)IXGBE_MIN_TXD);
+ new_tx_count = min(new_tx_count, (u32)IXGBE_MAX_TXD);
+ new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE);
+
+ if ((new_tx_count == adapter->tx_ring->count) &&
+ (new_rx_count == adapter->rx_ring->count)) {
+ /* nothing to do */
+ return 0;
+ }
+
+ if (netif_running(adapter->netdev))
+ ixgbe_down(adapter);
+
+ /*
+ * We can't just free everything and then setup again,
+ * because the ISRs in MSI-X mode get passed pointers
+ * to the tx and rx ring structs.
+ */
+ if (new_tx_count != adapter->tx_ring->count) {
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ /* Save existing descriptor ring */
+ old_buf = adapter->tx_ring[i].tx_buffer_info;
+ old_desc = adapter->tx_ring[i].desc;
+ old_size = adapter->tx_ring[i].size;
+ old_dma = adapter->tx_ring[i].dma;
+ /* Try to allocate a new one */
+ adapter->tx_ring[i].tx_buffer_info = NULL;
+ adapter->tx_ring[i].desc = NULL;
+ adapter->tx_ring[i].count = new_tx_count;
+ err = ixgbe_setup_tx_resources(adapter,
+ &adapter->tx_ring[i]);
+ if (err) {
+ /* Restore the old one so at least
+ the adapter still works, even if
+ we failed the request */
+ adapter->tx_ring[i].tx_buffer_info = old_buf;
+ adapter->tx_ring[i].desc = old_desc;
+ adapter->tx_ring[i].size = old_size;
+ adapter->tx_ring[i].dma = old_dma;
+ goto err_setup;
+ }
+ /* Free the old buffer manually */
+ vfree(old_buf);
+ pci_free_consistent(adapter->pdev, old_size,
+ old_desc, old_dma);
+ }
+ }
+
+ if (new_rx_count != adapter->rx_ring->count) {
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+
+ old_rx_buf = adapter->rx_ring[i].rx_buffer_info;
+ old_desc = adapter->rx_ring[i].desc;
+ old_size = adapter->rx_ring[i].size;
+ old_dma = adapter->rx_ring[i].dma;
+
+ adapter->rx_ring[i].rx_buffer_info = NULL;
+ adapter->rx_ring[i].desc = NULL;
+ adapter->rx_ring[i].dma = 0;
+ adapter->rx_ring[i].count = new_rx_count;
+ err = ixgbe_setup_rx_resources(adapter,
+ &adapter->rx_ring[i]);
+ if (err) {
+ adapter->rx_ring[i].rx_buffer_info = old_rx_buf;
+ adapter->rx_ring[i].desc = old_desc;
+ adapter->rx_ring[i].size = old_size;
+ adapter->rx_ring[i].dma = old_dma;
+ goto err_setup;
+ }
+
+ vfree(old_rx_buf);
+ pci_free_consistent(adapter->pdev, old_size, old_desc,
+ old_dma);
+ }
+ }
+
+ err = 0;
+err_setup:
+ if (netif_running(adapter->netdev))
+ ixgbe_up(adapter);
+
+ return err;
+}
+
+static int ixgbe_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return IXGBE_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void ixgbe_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ u64 *queue_stat;
+ int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64);
+ int j, k;
+ int i;
+
+ ixgbe_update_stats(adapter);
+ for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
+ char *p = (char *)adapter + ixgbe_gstrings_stats[i].stat_offset;
+ data[i] = (ixgbe_gstrings_stats[i].sizeof_stat ==
+ sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+ }
+ for (j = 0; j < adapter->num_tx_queues; j++) {
+ queue_stat = (u64 *)&adapter->tx_ring[j].stats;
+ for (k = 0; k < stat_count; k++)
+ data[i + k] = queue_stat[k];
+ i += k;
+ }
+ for (j = 0; j < adapter->num_rx_queues; j++) {
+ queue_stat = (u64 *)&adapter->rx_ring[j].stats;
+ for (k = 0; k < stat_count; k++)
+ data[i + k] = queue_stat[k];
+ i += k;
+ }
+}
+
+static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *data)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
+ memcpy(p, ixgbe_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ sprintf(p, "tx_queue_%u_packets", i);
+ p += ETH_GSTRING_LEN;
+ sprintf(p, "tx_queue_%u_bytes", i);
+ p += ETH_GSTRING_LEN;
+ }
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ sprintf(p, "rx_queue_%u_packets", i);
+ p += ETH_GSTRING_LEN;
+ sprintf(p, "rx_queue_%u_bytes", i);
+ p += ETH_GSTRING_LEN;
+ }
+/* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */
+ break;
+ }
+}
+
+
+static void ixgbe_get_wol(struct net_device *netdev,
+ struct ethtool_wolinfo *wol)
+{
+ wol->supported = 0;
+ wol->wolopts = 0;
+
+ return;
+}
+
+static int ixgbe_nway_reset(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ if (netif_running(netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_reset(adapter);
+ ixgbe_up(adapter);
+ }
+
+ return 0;
+}
+
+static int ixgbe_phys_id(struct net_device *netdev, u32 data)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ u32 led_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_LEDCTL);
+ u32 i;
+
+ if (!data || data > 300)
+ data = 300;
+
+ for (i = 0; i < (data * 1000); i += 400) {
+ ixgbe_led_on(&adapter->hw, IXGBE_LED_ON);
+ msleep_interruptible(200);
+ ixgbe_led_off(&adapter->hw, IXGBE_LED_ON);
+ msleep_interruptible(200);
+ }
+
+ /* Restore LED settings */
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, led_reg);
+
+ return 0;
+}
+
+static int ixgbe_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ if (adapter->rx_eitr == 0)
+ ec->rx_coalesce_usecs = 0;
+ else
+ ec->rx_coalesce_usecs = 1000000 / adapter->rx_eitr;
+
+ if (adapter->tx_eitr == 0)
+ ec->tx_coalesce_usecs = 0;
+ else
+ ec->tx_coalesce_usecs = 1000000 / adapter->tx_eitr;
+
+ ec->tx_max_coalesced_frames_irq = adapter->tx_ring[0].work_limit;
+ return 0;
+}
+
+static int ixgbe_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ if ((ec->rx_coalesce_usecs > IXGBE_MAX_ITR_USECS) ||
+ ((ec->rx_coalesce_usecs > 0) &&
+ (ec->rx_coalesce_usecs < IXGBE_MIN_ITR_USECS)))
+ return -EINVAL;
+ if ((ec->tx_coalesce_usecs > IXGBE_MAX_ITR_USECS) ||
+ ((ec->tx_coalesce_usecs > 0) &&
+ (ec->tx_coalesce_usecs < IXGBE_MIN_ITR_USECS)))
+ return -EINVAL;
+
+ /* convert to rate of irq's per second */
+ if (ec->rx_coalesce_usecs == 0)
+ adapter->rx_eitr = 0;
+ else
+ adapter->rx_eitr = (1000000 / ec->rx_coalesce_usecs);
+
+ if (ec->tx_coalesce_usecs == 0)
+ adapter->tx_eitr = 0;
+ else
+ adapter->tx_eitr = (1000000 / ec->tx_coalesce_usecs);
+
+ if (ec->tx_max_coalesced_frames_irq)
+ adapter->tx_ring[0].work_limit =
+ ec->tx_max_coalesced_frames_irq;
+
+ if (netif_running(netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_up(adapter);
+ }
+
+ return 0;
+}
+
+
+static struct ethtool_ops ixgbe_ethtool_ops = {
+ .get_settings = ixgbe_get_settings,
+ .set_settings = ixgbe_set_settings,
+ .get_drvinfo = ixgbe_get_drvinfo,
+ .get_regs_len = ixgbe_get_regs_len,
+ .get_regs = ixgbe_get_regs,
+ .get_wol = ixgbe_get_wol,
+ .nway_reset = ixgbe_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_eeprom_len = ixgbe_get_eeprom_len,
+ .get_eeprom = ixgbe_get_eeprom,
+ .get_ringparam = ixgbe_get_ringparam,
+ .set_ringparam = ixgbe_set_ringparam,
+ .get_pauseparam = ixgbe_get_pauseparam,
+ .set_pauseparam = ixgbe_set_pauseparam,
+ .get_rx_csum = ixgbe_get_rx_csum,
+ .set_rx_csum = ixgbe_set_rx_csum,
+ .get_tx_csum = ixgbe_get_tx_csum,
+ .set_tx_csum = ixgbe_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_msglevel = ixgbe_get_msglevel,
+ .set_msglevel = ixgbe_set_msglevel,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ixgbe_set_tso,
+ .get_strings = ixgbe_get_strings,
+ .phys_id = ixgbe_phys_id,
+ .get_sset_count = ixgbe_get_sset_count,
+ .get_ethtool_stats = ixgbe_get_ethtool_stats,
+ .get_coalesce = ixgbe_get_coalesce,
+ .set_coalesce = ixgbe_set_coalesce,
+};
+
+void ixgbe_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &ixgbe_ethtool_ops);
+}
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
new file mode 100644
index 00000000000..00bc525c656
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -0,0 +1,2873 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+
+#include "ixgbe.h"
+#include "ixgbe_common.h"
+
+char ixgbe_driver_name[] = "ixgbe";
+static const char ixgbe_driver_string[] =
+ "Intel(R) 10 Gigabit PCI Express Network Driver";
+
+#define DRV_VERSION "1.1.18"
+const char ixgbe_driver_version[] = DRV_VERSION;
+static const char ixgbe_copyright[] =
+ "Copyright (c) 1999-2007 Intel Corporation.";
+
+static const struct ixgbe_info *ixgbe_info_tbl[] = {
+ [board_82598AF] = &ixgbe_82598AF_info,
+ [board_82598EB] = &ixgbe_82598EB_info,
+ [board_82598AT] = &ixgbe_82598AT_info,
+};
+
+/* ixgbe_pci_tbl - PCI Device ID Table
+ *
+ * Wildcard entries (PCI_ANY_ID) should come last
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ * Class, Class Mask, private data (not used) }
+ */
+static struct pci_device_id ixgbe_pci_tbl[] = {
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT),
+ board_82598AF },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT),
+ board_82598AF },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT_DUAL_PORT),
+ board_82598AT },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4),
+ board_82598EB },
+
+ /* required last entry */
+ {0, }
+};
+MODULE_DEVICE_TABLE(pci, ixgbe_pci_tbl);
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+#define DEFAULT_DEBUG_LEVEL_SHIFT 3
+
+
+#ifdef DEBUG
+/**
+ * ixgbe_get_hw_dev_name - return device name string
+ * used by hardware layer to print debugging information
+ **/
+char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw)
+{
+ struct ixgbe_adapter *adapter = hw->back;
+ struct net_device *netdev = adapter->netdev;
+ return netdev->name;
+}
+#endif
+
+static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, u16 int_alloc_entry,
+ u8 msix_vector)
+{
+ u32 ivar, index;
+
+ msix_vector |= IXGBE_IVAR_ALLOC_VAL;
+ index = (int_alloc_entry >> 2) & 0x1F;
+ ivar = IXGBE_READ_REG(&adapter->hw, IXGBE_IVAR(index));
+ ivar &= ~(0xFF << (8 * (int_alloc_entry & 0x3)));
+ ivar |= (msix_vector << (8 * (int_alloc_entry & 0x3)));
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar);
+}
+
+static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
+ struct ixgbe_tx_buffer
+ *tx_buffer_info)
+{
+ if (tx_buffer_info->dma) {
+ pci_unmap_page(adapter->pdev,
+ tx_buffer_info->dma,
+ tx_buffer_info->length, PCI_DMA_TODEVICE);
+ tx_buffer_info->dma = 0;
+ }
+ if (tx_buffer_info->skb) {
+ dev_kfree_skb_any(tx_buffer_info->skb);
+ tx_buffer_info->skb = NULL;
+ }
+ /* tx_buffer_info must be completely set up in the transmit path */
+}
+
+static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring,
+ unsigned int eop,
+ union ixgbe_adv_tx_desc *eop_desc)
+{
+ /* Detect a transmit hang in hardware, this serializes the
+ * check with the clearing of time_stamp and movement of i */
+ adapter->detect_tx_hung = false;
+ if (tx_ring->tx_buffer_info[eop].dma &&
+ time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ) &&
+ !(IXGBE_READ_REG(&adapter->hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF)) {
+ /* detected Tx unit hang */
+ DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
+ " TDH <%x>\n"
+ " TDT <%x>\n"
+ " next_to_use <%x>\n"
+ " next_to_clean <%x>\n"
+ "tx_buffer_info[next_to_clean]\n"
+ " time_stamp <%lx>\n"
+ " next_to_watch <%x>\n"
+ " jiffies <%lx>\n"
+ " next_to_watch.status <%x>\n",
+ readl(adapter->hw.hw_addr + tx_ring->head),
+ readl(adapter->hw.hw_addr + tx_ring->tail),
+ tx_ring->next_to_use,
+ tx_ring->next_to_clean,
+ tx_ring->tx_buffer_info[eop].time_stamp,
+ eop, jiffies, eop_desc->wb.status);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+ * @adapter: board private structure
+ **/
+static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring)
+{
+ struct net_device *netdev = adapter->netdev;
+ union ixgbe_adv_tx_desc *tx_desc, *eop_desc;
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ unsigned int i, eop;
+ bool cleaned = false;
+ int count = 0;
+
+ i = tx_ring->next_to_clean;
+ eop = tx_ring->tx_buffer_info[i].next_to_watch;
+ eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+ while (eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) {
+ for (cleaned = false; !cleaned;) {
+ tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ cleaned = (i == eop);
+
+ tx_ring->stats.bytes += tx_buffer_info->length;
+ ixgbe_unmap_and_free_tx_resource(adapter,
+ tx_buffer_info);
+ tx_desc->wb.status = 0;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ tx_ring->stats.packets++;
+
+ eop = tx_ring->tx_buffer_info[i].next_to_watch;
+ eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+
+ /* weight of a sort for tx, avoid endless transmit cleanup */
+ if (count++ >= tx_ring->work_limit)
+ break;
+ }
+
+ tx_ring->next_to_clean = i;
+
+#define TX_WAKE_THRESHOLD 32
+ spin_lock(&tx_ring->tx_lock);
+
+ if (cleaned && netif_carrier_ok(netdev) &&
+ (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD) &&
+ !test_bit(__IXGBE_DOWN, &adapter->state))
+ netif_wake_queue(netdev);
+
+ spin_unlock(&tx_ring->tx_lock);
+
+ if (adapter->detect_tx_hung)
+ if (ixgbe_check_tx_hang(adapter, tx_ring, eop, eop_desc))
+ netif_stop_queue(netdev);
+
+ if (count >= tx_ring->work_limit)
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value);
+
+ return cleaned;
+}
+
+/**
+ * ixgbe_receive_skb - Send a completed packet up the stack
+ * @adapter: board private structure
+ * @skb: packet to send up
+ * @is_vlan: packet has a VLAN tag
+ * @tag: VLAN tag from descriptor
+ **/
+static void ixgbe_receive_skb(struct ixgbe_adapter *adapter,
+ struct sk_buff *skb, bool is_vlan,
+ u16 tag)
+{
+ if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
+ if (adapter->vlgrp && is_vlan)
+ vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag);
+ else
+ netif_receive_skb(skb);
+ } else {
+
+ if (adapter->vlgrp && is_vlan)
+ vlan_hwaccel_rx(skb, adapter->vlgrp, tag);
+ else
+ netif_rx(skb);
+ }
+}
+
+static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
+ u32 status_err,
+ struct sk_buff *skb)
+{
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* Ignore Checksum bit is set */
+ if ((status_err & IXGBE_RXD_STAT_IXSM) ||
+ !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
+ return;
+ /* TCP/UDP checksum error bit is set */
+ if (status_err & (IXGBE_RXDADV_ERR_TCPE | IXGBE_RXDADV_ERR_IPE)) {
+ /* let the stack verify checksum errors */
+ adapter->hw_csum_rx_error++;
+ return;
+ }
+ /* It must be a TCP or UDP packet with a valid checksum */
+ if (status_err & (IXGBE_RXD_STAT_L4CS | IXGBE_RXD_STAT_UDPCS))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ adapter->hw_csum_rx_good++;
+}
+
+/**
+ * ixgbe_alloc_rx_buffers - Replace used receive buffers; packet split
+ * @adapter: address of board private structure
+ **/
+static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rx_ring,
+ int cleaned_count)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ union ixgbe_adv_rx_desc *rx_desc;
+ struct ixgbe_rx_buffer *rx_buffer_info;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned int bufsz = adapter->rx_buf_len + NET_IP_ALIGN;
+
+ i = rx_ring->next_to_use;
+ rx_buffer_info = &rx_ring->rx_buffer_info[i];
+
+ while (cleaned_count--) {
+ rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+
+ if (!rx_buffer_info->page &&
+ (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) {
+ rx_buffer_info->page = alloc_page(GFP_ATOMIC);
+ if (!rx_buffer_info->page) {
+ adapter->alloc_rx_page_failed++;
+ goto no_buffers;
+ }
+ rx_buffer_info->page_dma =
+ pci_map_page(pdev, rx_buffer_info->page,
+ 0, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ }
+
+ if (!rx_buffer_info->skb) {
+ skb = netdev_alloc_skb(netdev, bufsz);
+
+ if (!skb) {
+ adapter->alloc_rx_buff_failed++;
+ goto no_buffers;
+ }
+
+ /*
+ * Make buffer alignment 2 beyond a 16 byte boundary
+ * this will result in a 16 byte aligned IP header after
+ * the 14 byte MAC header is removed
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ rx_buffer_info->skb = skb;
+ rx_buffer_info->dma = pci_map_single(pdev, skb->data,
+ bufsz,
+ PCI_DMA_FROMDEVICE);
+ }
+ /* Refresh the desc even if buffer_addrs didn't change because
+ * each write-back erases this info. */
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ rx_desc->read.pkt_addr =
+ cpu_to_le64(rx_buffer_info->page_dma);
+ rx_desc->read.hdr_addr =
+ cpu_to_le64(rx_buffer_info->dma);
+ } else {
+ rx_desc->read.pkt_addr =
+ cpu_to_le64(rx_buffer_info->dma);
+ }
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ rx_buffer_info = &rx_ring->rx_buffer_info[i];
+ }
+no_buffers:
+ if (rx_ring->next_to_use != i) {
+ rx_ring->next_to_use = i;
+ if (i-- == 0)
+ i = (rx_ring->count - 1);
+
+ /*
+ * Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64).
+ */
+ wmb();
+ writel(i, adapter->hw.hw_addr + rx_ring->tail);
+ }
+}
+
+static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rx_ring,
+ int *work_done, int work_to_do)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ union ixgbe_adv_rx_desc *rx_desc, *next_rxd;
+ struct ixgbe_rx_buffer *rx_buffer_info, *next_buffer;
+ struct sk_buff *skb;
+ unsigned int i;
+ u32 upper_len, len, staterr;
+ u16 hdr_info, vlan_tag;
+ bool is_vlan, cleaned = false;
+ int cleaned_count = 0;
+
+ i = rx_ring->next_to_clean;
+ upper_len = 0;
+ rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+ staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+ rx_buffer_info = &rx_ring->rx_buffer_info[i];
+ is_vlan = (staterr & IXGBE_RXD_STAT_VP);
+ vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan);
+
+ while (staterr & IXGBE_RXD_STAT_DD) {
+ if (*work_done >= work_to_do)
+ break;
+ (*work_done)++;
+
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ hdr_info =
+ le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info);
+ len =
+ ((hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >>
+ IXGBE_RXDADV_HDRBUFLEN_SHIFT);
+ if (hdr_info & IXGBE_RXDADV_SPH)
+ adapter->rx_hdr_split++;
+ if (len > IXGBE_RX_HDR_SIZE)
+ len = IXGBE_RX_HDR_SIZE;
+ upper_len = le16_to_cpu(rx_desc->wb.upper.length);
+ } else
+ len = le16_to_cpu(rx_desc->wb.upper.length);
+
+ cleaned = true;
+ skb = rx_buffer_info->skb;
+ prefetch(skb->data - NET_IP_ALIGN);
+ rx_buffer_info->skb = NULL;
+
+ if (len && !skb_shinfo(skb)->nr_frags) {
+ pci_unmap_single(pdev, rx_buffer_info->dma,
+ adapter->rx_buf_len + NET_IP_ALIGN,
+ PCI_DMA_FROMDEVICE);
+ skb_put(skb, len);
+ }
+
+ if (upper_len) {
+ pci_unmap_page(pdev, rx_buffer_info->page_dma,
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ rx_buffer_info->page_dma = 0;
+ skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
+ rx_buffer_info->page, 0, upper_len);
+ rx_buffer_info->page = NULL;
+
+ skb->len += upper_len;
+ skb->data_len += upper_len;
+ skb->truesize += upper_len;
+ }
+
+ i++;
+ if (i == rx_ring->count)
+ i = 0;
+ next_buffer = &rx_ring->rx_buffer_info[i];
+
+ next_rxd = IXGBE_RX_DESC_ADV(*rx_ring, i);
+ prefetch(next_rxd);
+
+ cleaned_count++;
+ if (staterr & IXGBE_RXD_STAT_EOP) {
+ rx_ring->stats.packets++;
+ rx_ring->stats.bytes += skb->len;
+ } else {
+ rx_buffer_info->skb = next_buffer->skb;
+ rx_buffer_info->dma = next_buffer->dma;
+ next_buffer->skb = skb;
+ adapter->non_eop_descs++;
+ goto next_desc;
+ }
+
+ if (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) {
+ dev_kfree_skb_irq(skb);
+ goto next_desc;
+ }
+
+ ixgbe_rx_checksum(adapter, staterr, skb);
+ skb->protocol = eth_type_trans(skb, netdev);
+ ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag);
+ netdev->last_rx = jiffies;
+
+next_desc:
+ rx_desc->wb.upper.status_error = 0;
+
+ /* return some buffers to hardware, one at a time is too slow */
+ if (cleaned_count >= IXGBE_RX_BUFFER_WRITE) {
+ ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
+ cleaned_count = 0;
+ }
+
+ /* use prefetched values */
+ rx_desc = next_rxd;
+ rx_buffer_info = next_buffer;
+
+ staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+ is_vlan = (staterr & IXGBE_RXD_STAT_VP);
+ vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan);
+ }
+
+ rx_ring->next_to_clean = i;
+ cleaned_count = IXGBE_DESC_UNUSED(rx_ring);
+
+ if (cleaned_count)
+ ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
+
+ return cleaned;
+}
+
+#define IXGBE_MAX_INTR 10
+/**
+ * ixgbe_configure_msix - Configure MSI-X hardware
+ * @adapter: board private structure
+ *
+ * ixgbe_configure_msix sets up the hardware to properly generate MSI-X
+ * interrupts.
+ **/
+static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
+{
+ int i, vector = 0;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i),
+ IXGBE_MSIX_VECTOR(vector));
+ writel(EITR_INTS_PER_SEC_TO_REG(adapter->tx_eitr),
+ adapter->hw.hw_addr + adapter->tx_ring[i].itr_register);
+ vector++;
+ }
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(i),
+ IXGBE_MSIX_VECTOR(vector));
+ writel(EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr),
+ adapter->hw.hw_addr + adapter->rx_ring[i].itr_register);
+ vector++;
+ }
+
+ vector = adapter->num_tx_queues + adapter->num_rx_queues;
+ ixgbe_set_ivar(adapter, IXGBE_IVAR_OTHER_CAUSES_INDEX,
+ IXGBE_MSIX_VECTOR(vector));
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(vector), 1950);
+}
+
+static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
+{
+ struct net_device *netdev = data;
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
+
+ if (eicr & IXGBE_EICR_LSC) {
+ adapter->lsc_int++;
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer, jiffies);
+ }
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data)
+{
+ struct ixgbe_ring *txr = data;
+ struct ixgbe_adapter *adapter = txr->adapter;
+
+ ixgbe_clean_tx_irq(adapter, txr);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data)
+{
+ struct ixgbe_ring *rxr = data;
+ struct ixgbe_adapter *adapter = rxr->adapter;
+
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rxr->eims_value);
+ netif_rx_schedule(adapter->netdev, &adapter->napi);
+ return IRQ_HANDLED;
+}
+
+static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
+{
+ struct ixgbe_adapter *adapter = container_of(napi,
+ struct ixgbe_adapter, napi);
+ struct net_device *netdev = adapter->netdev;
+ int work_done = 0;
+ struct ixgbe_ring *rxr = adapter->rx_ring;
+
+ /* Keep link state information with original netdev */
+ if (!netif_carrier_ok(netdev))
+ goto quit_polling;
+
+ ixgbe_clean_rx_irq(adapter, rxr, &work_done, budget);
+
+ /* If no Tx and not enough Rx work done, exit the polling mode */
+ if ((work_done < budget) || !netif_running(netdev)) {
+quit_polling:
+ netif_rx_complete(netdev, napi);
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS,
+ rxr->eims_value);
+ }
+
+ return work_done;
+}
+
+/**
+ * ixgbe_setup_msix - Initialize MSI-X interrupts
+ *
+ * ixgbe_setup_msix allocates MSI-X vectors and requests
+ * interrutps from the kernel.
+ **/
+static int ixgbe_setup_msix(struct ixgbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int i, int_vector = 0, err = 0;
+ int max_msix_count;
+
+ /* +1 for the LSC interrupt */
+ max_msix_count = adapter->num_rx_queues + adapter->num_tx_queues + 1;
+ adapter->msix_entries = kcalloc(max_msix_count,
+ sizeof(struct msix_entry), GFP_KERNEL);
+ if (!adapter->msix_entries)
+ return -ENOMEM;
+
+ for (i = 0; i < max_msix_count; i++)
+ adapter->msix_entries[i].entry = i;
+
+ err = pci_enable_msix(adapter->pdev, adapter->msix_entries,
+ max_msix_count);
+ if (err)
+ goto out;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ sprintf(adapter->tx_ring[i].name, "%s-tx%d", netdev->name, i);
+ err = request_irq(adapter->msix_entries[int_vector].vector,
+ &ixgbe_msix_clean_tx,
+ 0,
+ adapter->tx_ring[i].name,
+ &(adapter->tx_ring[i]));
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "request_irq failed for MSIX interrupt "
+ "Error: %d\n", err);
+ goto release_irqs;
+ }
+ adapter->tx_ring[i].eims_value =
+ (1 << IXGBE_MSIX_VECTOR(int_vector));
+ adapter->tx_ring[i].itr_register = IXGBE_EITR(int_vector);
+ int_vector++;
+ }
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ if (strlen(netdev->name) < (IFNAMSIZ - 5))
+ sprintf(adapter->rx_ring[i].name,
+ "%s-rx%d", netdev->name, i);
+ else
+ memcpy(adapter->rx_ring[i].name,
+ netdev->name, IFNAMSIZ);
+ err = request_irq(adapter->msix_entries[int_vector].vector,
+ &ixgbe_msix_clean_rx, 0,
+ adapter->rx_ring[i].name,
+ &(adapter->rx_ring[i]));
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "request_irq failed for MSIX interrupt "
+ "Error: %d\n", err);
+ goto release_irqs;
+ }
+
+ adapter->rx_ring[i].eims_value =
+ (1 << IXGBE_MSIX_VECTOR(int_vector));
+ adapter->rx_ring[i].itr_register = IXGBE_EITR(int_vector);
+ int_vector++;
+ }
+
+ sprintf(adapter->lsc_name, "%s-lsc", netdev->name);
+ err = request_irq(adapter->msix_entries[int_vector].vector,
+ &ixgbe_msix_lsc, 0, adapter->lsc_name, netdev);
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "request_irq for msix_lsc failed: %d\n", err);
+ goto release_irqs;
+ }
+
+ /* FIXME: implement netif_napi_remove() instead */
+ adapter->napi.poll = ixgbe_clean_rxonly;
+ adapter->flags |= IXGBE_FLAG_MSIX_ENABLED;
+ return 0;
+
+release_irqs:
+ int_vector--;
+ for (; int_vector >= adapter->num_tx_queues; int_vector--)
+ free_irq(adapter->msix_entries[int_vector].vector,
+ &(adapter->rx_ring[int_vector -
+ adapter->num_tx_queues]));
+
+ for (; int_vector >= 0; int_vector--)
+ free_irq(adapter->msix_entries[int_vector].vector,
+ &(adapter->tx_ring[int_vector]));
+out:
+ kfree(adapter->msix_entries);
+ adapter->msix_entries = NULL;
+ adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
+ return err;
+}
+
+/**
+ * ixgbe_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ * @pt_regs: CPU registers structure
+ **/
+static irqreturn_t ixgbe_intr(int irq, void *data)
+{
+ struct net_device *netdev = data;
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 eicr;
+
+ eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
+
+ if (!eicr)
+ return IRQ_NONE; /* Not our interrupt */
+
+ if (eicr & IXGBE_EICR_LSC) {
+ adapter->lsc_int++;
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer, jiffies);
+ }
+ if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+ /* Disable interrupts and register for poll. The flush of the
+ * posted write is intentionally left out. */
+ atomic_inc(&adapter->irq_sem);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
+ __netif_rx_schedule(netdev, &adapter->napi);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ixgbe_request_irq - initialize interrupts
+ * @adapter: board private structure
+ *
+ * Attempts to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ **/
+static int ixgbe_request_irq(struct ixgbe_adapter *adapter, u32 *num_rx_queues)
+{
+ struct net_device *netdev = adapter->netdev;
+ int flags, err;
+ irqreturn_t(*handler) (int, void *) = &ixgbe_intr;
+
+ flags = IRQF_SHARED;
+
+ err = ixgbe_setup_msix(adapter);
+ if (!err)
+ goto request_done;
+
+ /*
+ * if we can't do MSI-X, fall through and try MSI
+ * No need to reallocate memory since we're decreasing the number of
+ * queues. We just won't use the other ones, also it is freed correctly
+ * on ixgbe_remove.
+ */
+ *num_rx_queues = 1;
+
+ /* do MSI */
+ err = pci_enable_msi(adapter->pdev);
+ if (!err) {
+ adapter->flags |= IXGBE_FLAG_MSI_ENABLED;
+ flags &= ~IRQF_SHARED;
+ handler = &ixgbe_intr;
+ }
+
+ err = request_irq(adapter->pdev->irq, handler, flags,
+ netdev->name, netdev);
+ if (err)
+ DPRINTK(PROBE, ERR, "request_irq failed, Error %d\n", err);
+
+request_done:
+ return err;
+}
+
+static void ixgbe_free_irq(struct ixgbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ free_irq(adapter->msix_entries[i].vector,
+ &(adapter->tx_ring[i]));
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ free_irq(adapter->msix_entries[i +
+ adapter->num_tx_queues].vector,
+ &(adapter->rx_ring[i]));
+ i = adapter->num_rx_queues + adapter->num_tx_queues;
+ free_irq(adapter->msix_entries[i].vector, netdev);
+ pci_disable_msix(adapter->pdev);
+ kfree(adapter->msix_entries);
+ adapter->msix_entries = NULL;
+ adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
+ return;
+ }
+
+ free_irq(adapter->pdev->irq, netdev);
+ if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
+ pci_disable_msi(adapter->pdev);
+ adapter->flags &= ~IXGBE_FLAG_MSI_ENABLED;
+ }
+}
+
+/**
+ * ixgbe_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
+{
+ atomic_inc(&adapter->irq_sem);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
+ IXGBE_WRITE_FLUSH(&adapter->hw);
+ synchronize_irq(adapter->pdev->irq);
+}
+
+/**
+ * ixgbe_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
+{
+ if (atomic_dec_and_test(&adapter->irq_sem)) {
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC,
+ (IXGBE_EIMS_ENABLE_MASK &
+ ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC)));
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS,
+ IXGBE_EIMS_ENABLE_MASK);
+ IXGBE_WRITE_FLUSH(&adapter->hw);
+ }
+}
+
+/**
+ * ixgbe_configure_msi_and_legacy - Initialize PIN (INTA...) and MSI interrupts
+ *
+ **/
+static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter)
+{
+ int i;
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ if (adapter->rx_eitr)
+ IXGBE_WRITE_REG(hw, IXGBE_EITR(0),
+ EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr));
+
+ /* for re-triggering the interrupt in non-NAPI mode */
+ adapter->rx_ring[0].eims_value = (1 << IXGBE_MSIX_VECTOR(0));
+ adapter->tx_ring[0].eims_value = (1 << IXGBE_MSIX_VECTOR(0));
+
+ ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(0), 0);
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i), i);
+}
+
+/**
+ * ixgbe_configure_tx - Configure 8254x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
+{
+ u64 tdba;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 i, tdlen;
+
+ /* Setup the HW Tx Head and Tail descriptor pointers */
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ tdba = adapter->tx_ring[i].dma;
+ tdlen = adapter->tx_ring[i].count *
+ sizeof(union ixgbe_adv_tx_desc);
+ IXGBE_WRITE_REG(hw, IXGBE_TDBAL(i), (tdba & DMA_32BIT_MASK));
+ IXGBE_WRITE_REG(hw, IXGBE_TDBAH(i), (tdba >> 32));
+ IXGBE_WRITE_REG(hw, IXGBE_TDLEN(i), tdlen);
+ IXGBE_WRITE_REG(hw, IXGBE_TDH(i), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_TDT(i), 0);
+ adapter->tx_ring[i].head = IXGBE_TDH(i);
+ adapter->tx_ring[i].tail = IXGBE_TDT(i);
+ }
+
+ IXGBE_WRITE_REG(hw, IXGBE_TIPG, IXGBE_TIPG_FIBER_DEFAULT);
+}
+
+#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
+ (((S) & (PAGE_SIZE - 1)) ? 1 : 0))
+
+#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2
+/**
+ * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
+{
+ u64 rdba;
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+ u32 rdlen, rxctrl, rxcsum;
+ u32 random[10];
+ u32 reta, mrqc;
+ int i;
+ u32 fctrl, hlreg0;
+ u32 srrctl;
+ u32 pages;
+
+ /* Decide whether to use packet split mode or not */
+ if (netdev->mtu > ETH_DATA_LEN)
+ adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
+ else
+ adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
+
+ /* Set the RX buffer length according to the mode */
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ adapter->rx_buf_len = IXGBE_RX_HDR_SIZE;
+ } else {
+ if (netdev->mtu <= ETH_DATA_LEN)
+ adapter->rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+ else
+ adapter->rx_buf_len = ALIGN(max_frame, 1024);
+ }
+
+ fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
+ fctrl |= IXGBE_FCTRL_BAM;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl);
+
+ hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
+ if (adapter->netdev->mtu <= ETH_DATA_LEN)
+ hlreg0 &= ~IXGBE_HLREG0_JUMBOEN;
+ else
+ hlreg0 |= IXGBE_HLREG0_JUMBOEN;
+ IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
+
+ pages = PAGE_USE_COUNT(adapter->netdev->mtu);
+
+ srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(0));
+ srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;
+ srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
+
+ if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+ srrctl |= PAGE_SIZE >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+ srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
+ srrctl |= ((IXGBE_RX_HDR_SIZE <<
+ IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
+ IXGBE_SRRCTL_BSIZEHDR_MASK);
+ } else {
+ srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
+
+ if (adapter->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE)
+ srrctl |=
+ IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+ else
+ srrctl |=
+ adapter->rx_buf_len >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+ }
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(0), srrctl);
+
+ rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc);
+ /* disable receives while setting up the descriptors */
+ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
+
+ /* Setup the HW Rx Head and Tail Descriptor Pointers and
+ * the Base and Length of the Rx Descriptor Ring */
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ rdba = adapter->rx_ring[i].dma;
+ IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), (rdba & DMA_32BIT_MASK));
+ IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32));
+ IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), rdlen);
+ IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0);
+ adapter->rx_ring[i].head = IXGBE_RDH(i);
+ adapter->rx_ring[i].tail = IXGBE_RDT(i);
+ }
+
+ if (adapter->num_rx_queues > 1) {
+ /* Random 40bytes used as random key in RSS hash function */
+ get_random_bytes(&random[0], 40);
+
+ switch (adapter->num_rx_queues) {
+ case 8:
+ case 4:
+ /* Bits [3:0] in each byte refers the Rx queue no */
+ reta = 0x00010203;
+ break;
+ case 2:
+ reta = 0x00010001;
+ break;
+ default:
+ reta = 0x00000000;
+ break;
+ }
+
+ /* Fill out redirection table */
+ for (i = 0; i < 32; i++) {
+ IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RETA(0), i, reta);
+ if (adapter->num_rx_queues > 4) {
+ i++;
+ IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RETA(0), i,
+ 0x04050607);
+ }
+ }
+
+ /* Fill out hash function seeds */
+ for (i = 0; i < 10; i++)
+ IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RSSRK(0), i, random[i]);
+
+ mrqc = IXGBE_MRQC_RSSEN
+ /* Perform hash on these packet types */
+ | IXGBE_MRQC_RSS_FIELD_IPV4
+ | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
+ | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
+ | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP
+ | IXGBE_MRQC_RSS_FIELD_IPV6_EX
+ | IXGBE_MRQC_RSS_FIELD_IPV6
+ | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
+ | IXGBE_MRQC_RSS_FIELD_IPV6_UDP
+ | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
+ IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
+
+ /* Multiqueue and packet checksumming are mutually exclusive. */
+ rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
+ rxcsum |= IXGBE_RXCSUM_PCSD;
+ IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
+ } else {
+ /* Enable Receive Checksum Offload for TCP and UDP */
+ rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
+ if (adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED) {
+ /* Enable IPv4 payload checksum for UDP fragments
+ * Must be used in conjunction with packet-split. */
+ rxcsum |= IXGBE_RXCSUM_IPPCSE;
+ } else {
+ /* don't need to clear IPPCSE as it defaults to 0 */
+ }
+ IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
+ }
+ /* Enable Receives */
+ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl);
+ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+}
+
+static void ixgbe_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *grp)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ u32 ctrl;
+
+ ixgbe_irq_disable(adapter);
+ adapter->vlgrp = grp;
+
+ if (grp) {
+ /* enable VLAN tag insert/strip */
+ ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL);
+ ctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE;
+ ctrl &= ~IXGBE_VLNCTRL_CFIEN;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
+ }
+
+ ixgbe_irq_enable(adapter);
+}
+
+static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ /* add VID to filter table */
+ ixgbe_set_vfta(&adapter->hw, vid, 0, true);
+}
+
+static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ ixgbe_irq_disable(adapter);
+ vlan_group_set_device(adapter->vlgrp, vid, NULL);
+ ixgbe_irq_enable(adapter);
+
+ /* remove VID from filter table */
+ ixgbe_set_vfta(&adapter->hw, vid, 0, false);
+}
+
+static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
+{
+ ixgbe_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+
+ if (adapter->vlgrp) {
+ u16 vid;
+ for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ if (!vlan_group_get_device(adapter->vlgrp, vid))
+ continue;
+ ixgbe_vlan_rx_add_vid(adapter->netdev, vid);
+ }
+ }
+}
+
+/**
+ * ixgbe_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated. This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ **/
+static void ixgbe_set_multi(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct dev_mc_list *mc_ptr;
+ u8 *mta_list;
+ u32 fctrl;
+ int i;
+
+ /* Check for Promiscuous and All Multicast modes */
+
+ fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+
+ if (netdev->flags & IFF_PROMISC) {
+ fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+ } else if (netdev->flags & IFF_ALLMULTI) {
+ fctrl |= IXGBE_FCTRL_MPE;
+ fctrl &= ~IXGBE_FCTRL_UPE;
+ } else {
+ fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+ }
+
+ IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
+
+ if (netdev->mc_count) {
+ mta_list = kcalloc(netdev->mc_count, ETH_ALEN, GFP_ATOMIC);
+ if (!mta_list)
+ return;
+
+ /* Shared function expects packed array of only addresses. */
+ mc_ptr = netdev->mc_list;
+
+ for (i = 0; i < netdev->mc_count; i++) {
+ if (!mc_ptr)
+ break;
+ memcpy(mta_list + (i * ETH_ALEN), mc_ptr->dmi_addr,
+ ETH_ALEN);
+ mc_ptr = mc_ptr->next;
+ }
+
+ ixgbe_update_mc_addr_list(hw, mta_list, i, 0);
+ kfree(mta_list);
+ } else {
+ ixgbe_update_mc_addr_list(hw, NULL, 0, 0);
+ }
+
+}
+
+static void ixgbe_configure(struct ixgbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int i;
+
+ ixgbe_set_multi(netdev);
+
+ ixgbe_restore_vlan(adapter);
+
+ ixgbe_configure_tx(adapter);
+ ixgbe_configure_rx(adapter);
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ ixgbe_alloc_rx_buffers(adapter, &adapter->rx_ring[i],
+ (adapter->rx_ring[i].count - 1));
+}
+
+static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int i;
+ u32 gpie = 0;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 txdctl, rxdctl, mhadd;
+ int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+
+ if (adapter->flags & (IXGBE_FLAG_MSIX_ENABLED |
+ IXGBE_FLAG_MSI_ENABLED)) {
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+ gpie = (IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_EIAME |
+ IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD);
+ } else {
+ /* MSI only */
+ gpie = (IXGBE_GPIE_EIAME |
+ IXGBE_GPIE_PBA_SUPPORT);
+ }
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_GPIE, gpie);
+ gpie = IXGBE_READ_REG(&adapter->hw, IXGBE_GPIE);
+ }
+
+ mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
+
+ if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) {
+ mhadd &= ~IXGBE_MHADD_MFS_MASK;
+ mhadd |= max_frame << IXGBE_MHADD_MFS_SHIFT;
+
+ IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
+ }
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ txdctl = IXGBE_READ_REG(&adapter->hw, IXGBE_TXDCTL(i));
+ txdctl |= IXGBE_TXDCTL_ENABLE;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(i), txdctl);
+ }
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ rxdctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(i));
+ rxdctl |= IXGBE_RXDCTL_ENABLE;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(i), rxdctl);
+ }
+ /* enable all receives */
+ rxdctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+ rxdctl |= (IXGBE_RXCTRL_DMBYPS | IXGBE_RXCTRL_RXEN);
+ IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxdctl);
+
+ if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
+ ixgbe_configure_msix(adapter);
+ else
+ ixgbe_configure_msi_and_legacy(adapter);
+
+ clear_bit(__IXGBE_DOWN, &adapter->state);
+ napi_enable(&adapter->napi);
+ ixgbe_irq_enable(adapter);
+
+ /* bring the link up in the watchdog, this could race with our first
+ * link up interrupt but shouldn't be a problem */
+ mod_timer(&adapter->watchdog_timer, jiffies);
+ return 0;
+}
+
+int ixgbe_up(struct ixgbe_adapter *adapter)
+{
+ /* hardware has been reset, we need to reload some things */
+ ixgbe_configure(adapter);
+
+ return ixgbe_up_complete(adapter);
+}
+
+void ixgbe_reset(struct ixgbe_adapter *adapter)
+{
+ if (ixgbe_init_hw(&adapter->hw))
+ DPRINTK(PROBE, ERR, "Hardware Error\n");
+
+ /* reprogram the RAR[0] in case user changed it. */
+ ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV);
+
+}
+
+#ifdef CONFIG_PM
+static int ixgbe_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ u32 err, num_rx_queues = adapter->num_rx_queues;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR "ixgbe: Cannot enable PCI device from " \
+ "suspend\n");
+ return err;
+ }
+ pci_set_master(pdev);
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ if (netif_running(netdev)) {
+ err = ixgbe_request_irq(adapter, &num_rx_queues);
+ if (err)
+ return err;
+ }
+
+ ixgbe_reset(adapter);
+
+ if (netif_running(netdev))
+ ixgbe_up(adapter);
+
+ netif_device_attach(netdev);
+
+ return 0;
+}
+#endif
+
+/**
+ * ixgbe_clean_rx_ring - Free Rx Buffers per Queue
+ * @adapter: board private structure
+ * @rx_ring: ring to free buffers from
+ **/
+static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long size;
+ unsigned int i;
+
+ /* Free all the Rx ring sk_buffs */
+
+ for (i = 0; i < rx_ring->count; i++) {
+ struct ixgbe_rx_buffer *rx_buffer_info;
+
+ rx_buffer_info = &rx_ring->rx_buffer_info[i];
+ if (rx_buffer_info->dma) {
+ pci_unmap_single(pdev, rx_buffer_info->dma,
+ adapter->rx_buf_len,
+ PCI_DMA_FROMDEVICE);
+ rx_buffer_info->dma = 0;
+ }
+ if (rx_buffer_info->skb) {
+ dev_kfree_skb(rx_buffer_info->skb);
+ rx_buffer_info->skb = NULL;
+ }
+ if (!rx_buffer_info->page)
+ continue;
+ pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ rx_buffer_info->page_dma = 0;
+
+ put_page(rx_buffer_info->page);
+ rx_buffer_info->page = NULL;
+ }
+
+ size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
+ memset(rx_ring->rx_buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(rx_ring->desc, 0, rx_ring->size);
+
+ rx_ring->next_to_clean = 0;
+ rx_ring->next_to_use = 0;
+
+ writel(0, adapter->hw.hw_addr + rx_ring->head);
+ writel(0, adapter->hw.hw_addr + rx_ring->tail);
+}
+
+/**
+ * ixgbe_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ * @tx_ring: ring to be cleaned
+ **/
+static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring)
+{
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ unsigned long size;
+ unsigned int i;
+
+ /* Free all the Tx ring sk_buffs */
+
+ for (i = 0; i < tx_ring->count; i++) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info);
+ }
+
+ size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count;
+ memset(tx_ring->tx_buffer_info, 0, size);
+
+ /* Zero out the descriptor ring */
+ memset(tx_ring->desc, 0, tx_ring->size);
+
+ tx_ring->next_to_use = 0;
+ tx_ring->next_to_clean = 0;
+
+ writel(0, adapter->hw.hw_addr + tx_ring->head);
+ writel(0, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+/**
+ * ixgbe_clean_all_tx_rings - Free Tx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void ixgbe_clean_all_tx_rings(struct ixgbe_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ ixgbe_clean_tx_ring(adapter, &adapter->tx_ring[i]);
+}
+
+/**
+ * ixgbe_clean_all_rx_rings - Free Rx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void ixgbe_clean_all_rx_rings(struct ixgbe_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ ixgbe_clean_rx_ring(adapter, &adapter->rx_ring[i]);
+}
+
+void ixgbe_down(struct ixgbe_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ u32 rxctrl;
+
+ /* signal that we are down to the interrupt handler */
+ set_bit(__IXGBE_DOWN, &adapter->state);
+
+ /* disable receives */
+ rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL,
+ rxctrl & ~IXGBE_RXCTRL_RXEN);
+
+ netif_tx_disable(netdev);
+
+ /* disable transmits in the hardware */
+
+ /* flush both disables */
+ IXGBE_WRITE_FLUSH(&adapter->hw);
+ msleep(10);
+
+ ixgbe_irq_disable(adapter);
+
+ napi_disable(&adapter->napi);
+ del_timer_sync(&adapter->watchdog_timer);
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ ixgbe_reset(adapter);
+ ixgbe_clean_all_tx_rings(adapter);
+ ixgbe_clean_all_rx_rings(adapter);
+
+}
+
+static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+#ifdef CONFIG_PM
+ int retval = 0;
+#endif
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_free_irq(adapter);
+ }
+
+#ifdef CONFIG_PM
+ retval = pci_save_state(pdev);
+ if (retval)
+ return retval;
+#endif
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ pci_disable_device(pdev);
+
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static void ixgbe_shutdown(struct pci_dev *pdev)
+{
+ ixgbe_suspend(pdev, PMSG_SUSPEND);
+}
+
+/**
+ * ixgbe_clean - NAPI Rx polling callback
+ * @adapter: board private structure
+ **/
+static int ixgbe_clean(struct napi_struct *napi, int budget)
+{
+ struct ixgbe_adapter *adapter = container_of(napi,
+ struct ixgbe_adapter, napi);
+ struct net_device *netdev = adapter->netdev;
+ int tx_cleaned = 0, work_done = 0;
+
+ /* Keep link state information with original netdev */
+ if (!netif_carrier_ok(adapter->netdev))
+ goto quit_polling;
+
+ /* In non-MSIX case, there is no multi-Tx/Rx queue */
+ tx_cleaned = ixgbe_clean_tx_irq(adapter, adapter->tx_ring);
+ ixgbe_clean_rx_irq(adapter, &adapter->rx_ring[0], &work_done,
+ budget);
+
+ /* If no Tx and not enough Rx work done, exit the polling mode */
+ if ((!tx_cleaned && (work_done < budget)) ||
+ !netif_running(adapter->netdev)) {
+quit_polling:
+ netif_rx_complete(netdev, napi);
+ ixgbe_irq_enable(adapter);
+ }
+
+ return work_done;
+}
+
+/**
+ * ixgbe_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+static void ixgbe_tx_timeout(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ /* Do the reset outside of interrupt context */
+ schedule_work(&adapter->reset_task);
+}
+
+static void ixgbe_reset_task(struct work_struct *work)
+{
+ struct ixgbe_adapter *adapter;
+ adapter = container_of(work, struct ixgbe_adapter, reset_task);
+
+ adapter->tx_timeout_count++;
+
+ ixgbe_down(adapter);
+ ixgbe_up(adapter);
+}
+
+/**
+ * ixgbe_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ *
+ * We allocate one ring per queue at run-time since we don't know the
+ * number of queues at compile-time. The polling_netdev array is
+ * intended for Multiqueue, but should work fine with a single queue.
+ **/
+static int __devinit ixgbe_alloc_queues(struct ixgbe_adapter *adapter)
+{
+ int i;
+
+ adapter->tx_ring = kcalloc(adapter->num_tx_queues,
+ sizeof(struct ixgbe_ring), GFP_KERNEL);
+ if (!adapter->tx_ring)
+ return -ENOMEM;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ adapter->tx_ring[i].count = IXGBE_DEFAULT_TXD;
+
+ adapter->rx_ring = kcalloc(adapter->num_rx_queues,
+ sizeof(struct ixgbe_ring), GFP_KERNEL);
+ if (!adapter->rx_ring) {
+ kfree(adapter->tx_ring);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ adapter->rx_ring[i].adapter = adapter;
+ adapter->rx_ring[i].itr_register = IXGBE_EITR(i);
+ adapter->rx_ring[i].count = IXGBE_DEFAULT_RXD;
+ }
+
+ return 0;
+}
+
+/**
+ * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * ixgbe_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct pci_dev *pdev = adapter->pdev;
+
+ /* default flow control settings */
+ hw->fc.original_type = ixgbe_fc_full;
+ hw->fc.type = ixgbe_fc_full;
+
+ hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN;
+ if (hw->mac.ops.reset(hw)) {
+ dev_err(&pdev->dev, "HW Init failed\n");
+ return -EIO;
+ }
+ if (hw->phy.ops.setup_speed(hw, IXGBE_LINK_SPEED_10GB_FULL, true,
+ false)) {
+ dev_err(&pdev->dev, "Link Speed setup failed\n");
+ return -EIO;
+ }
+
+ /* initialize eeprom parameters */
+ if (ixgbe_init_eeprom(hw)) {
+ dev_err(&pdev->dev, "EEPROM initialization failed\n");
+ return -EIO;
+ }
+
+ /* Set the default values */
+ adapter->num_rx_queues = IXGBE_DEFAULT_RXQ;
+ adapter->num_tx_queues = 1;
+ adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
+
+ if (ixgbe_alloc_queues(adapter)) {
+ dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
+ return -ENOMEM;
+ }
+
+ atomic_set(&adapter->irq_sem, 1);
+ set_bit(__IXGBE_DOWN, &adapter->state);
+
+ return 0;
+}
+
+/**
+ * ixgbe_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: board private structure
+ * @txdr: tx descriptor ring (for a specific queue) to setup
+ *
+ * Return 0 on success, negative on failure
+ **/
+int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *txdr)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ int size;
+
+ size = sizeof(struct ixgbe_tx_buffer) * txdr->count;
+ txdr->tx_buffer_info = vmalloc(size);
+ if (!txdr->tx_buffer_info) {
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate memory for the transmit descriptor ring\n");
+ return -ENOMEM;
+ }
+ memset(txdr->tx_buffer_info, 0, size);
+
+ /* round up to nearest 4K */
+ txdr->size = txdr->count * sizeof(union ixgbe_adv_tx_desc);
+ txdr->size = ALIGN(txdr->size, 4096);
+
+ txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
+ if (!txdr->desc) {
+ vfree(txdr->tx_buffer_info);
+ DPRINTK(PROBE, ERR,
+ "Memory allocation failed for the tx desc ring\n");
+ return -ENOMEM;
+ }
+
+ txdr->adapter = adapter;
+ txdr->next_to_use = 0;
+ txdr->next_to_clean = 0;
+ txdr->work_limit = txdr->count;
+ spin_lock_init(&txdr->tx_lock);
+
+ return 0;
+}
+
+/**
+ * ixgbe_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ * @rxdr: rx descriptor ring (for a specific queue) to setup
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rxdr)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ int size, desc_len;
+
+ size = sizeof(struct ixgbe_rx_buffer) * rxdr->count;
+ rxdr->rx_buffer_info = vmalloc(size);
+ if (!rxdr->rx_buffer_info) {
+ DPRINTK(PROBE, ERR,
+ "vmalloc allocation failed for the rx desc ring\n");
+ return -ENOMEM;
+ }
+ memset(rxdr->rx_buffer_info, 0, size);
+
+ desc_len = sizeof(union ixgbe_adv_rx_desc);
+
+ /* Round up to nearest 4K */
+ rxdr->size = rxdr->count * desc_len;
+ rxdr->size = ALIGN(rxdr->size, 4096);
+
+ rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
+
+ if (!rxdr->desc) {
+ DPRINTK(PROBE, ERR,
+ "Memory allocation failed for the rx desc ring\n");
+ vfree(rxdr->rx_buffer_info);
+ return -ENOMEM;
+ }
+
+ rxdr->next_to_clean = 0;
+ rxdr->next_to_use = 0;
+ rxdr->adapter = adapter;
+
+ return 0;
+}
+
+/**
+ * ixgbe_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ * @tx_ring: Tx descriptor ring for a specific queue
+ *
+ * Free all transmit software resources
+ **/
+static void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ ixgbe_clean_tx_ring(adapter, tx_ring);
+
+ vfree(tx_ring->tx_buffer_info);
+ tx_ring->tx_buffer_info = NULL;
+
+ pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma);
+
+ tx_ring->desc = NULL;
+}
+
+/**
+ * ixgbe_free_all_tx_resources - Free Tx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]);
+}
+
+/**
+ * ixgbe_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ * @rx_ring: ring to clean the resources from
+ *
+ * Free all receive software resources
+ **/
+static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *rx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ ixgbe_clean_rx_ring(adapter, rx_ring);
+
+ vfree(rx_ring->rx_buffer_info);
+ rx_ring->rx_buffer_info = NULL;
+
+ pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
+
+ rx_ring->desc = NULL;
+}
+
+/**
+ * ixgbe_free_all_rx_resources - Free Rx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]);
+}
+
+/**
+ * ixgbe_setup_all_tx_resources - wrapper to allocate Tx resources
+ * (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not). It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter)
+{
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]);
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "Allocation for Tx Queue %u failed\n", i);
+ break;
+ }
+ }
+
+ return err;
+}
+
+/**
+ * ixgbe_setup_all_rx_resources - wrapper to allocate Rx resources
+ * (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not). It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+
+static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter)
+{
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_rx_queues; i++) {
+ err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]);
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "Allocation for Rx Queue %u failed\n", i);
+ break;
+ }
+ }
+
+ return err;
+}
+
+/**
+ * ixgbe_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+
+ if ((max_frame < (ETH_ZLEN + ETH_FCS_LEN)) ||
+ (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE))
+ return -EINVAL;
+
+ netdev->mtu = new_mtu;
+
+ if (netif_running(netdev)) {
+ ixgbe_down(adapter);
+ ixgbe_up(adapter);
+ }
+
+ return 0;
+}
+
+/**
+ * ixgbe_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP). At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int ixgbe_open(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ int err;
+ u32 ctrl_ext;
+ u32 num_rx_queues = adapter->num_rx_queues;
+
+ /* Let firmware know the driver has taken over */
+ ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
+ ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
+
+try_intr_reinit:
+ /* allocate transmit descriptors */
+ err = ixgbe_setup_all_tx_resources(adapter);
+ if (err)
+ goto err_setup_tx;
+
+ if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
+ num_rx_queues = 1;
+ adapter->num_rx_queues = num_rx_queues;
+ }
+
+ /* allocate receive descriptors */
+ err = ixgbe_setup_all_rx_resources(adapter);
+ if (err)
+ goto err_setup_rx;
+
+ ixgbe_configure(adapter);
+
+ err = ixgbe_request_irq(adapter, &num_rx_queues);
+ if (err)
+ goto err_req_irq;
+
+ /* ixgbe_request might have reduced num_rx_queues */
+ if (num_rx_queues < adapter->num_rx_queues) {
+ /* We didn't get MSI-X, so we need to release everything,
+ * set our Rx queue count to num_rx_queues, and redo the
+ * whole init process.
+ */
+ ixgbe_free_irq(adapter);
+ if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
+ pci_disable_msi(adapter->pdev);
+ adapter->flags &= ~IXGBE_FLAG_MSI_ENABLED;
+ }
+ ixgbe_free_all_rx_resources(adapter);
+ ixgbe_free_all_tx_resources(adapter);
+ adapter->num_rx_queues = num_rx_queues;
+
+ /* Reset the hardware, and start over. */
+ ixgbe_reset(adapter);
+
+ goto try_intr_reinit;
+ }
+
+ err = ixgbe_up_complete(adapter);
+ if (err)
+ goto err_up;
+
+ return 0;
+
+err_up:
+ ixgbe_free_irq(adapter);
+err_req_irq:
+ ixgbe_free_all_rx_resources(adapter);
+err_setup_rx:
+ ixgbe_free_all_tx_resources(adapter);
+err_setup_tx:
+ ixgbe_reset(adapter);
+
+ return err;
+}
+
+/**
+ * ixgbe_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS. The hardware is still under the drivers control, but
+ * needs to be disabled. A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static int ixgbe_close(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ u32 ctrl_ext;
+
+ ixgbe_down(adapter);
+ ixgbe_free_irq(adapter);
+
+ ixgbe_free_all_tx_resources(adapter);
+ ixgbe_free_all_rx_resources(adapter);
+
+ ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
+ ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
+
+ return 0;
+}
+
+/**
+ * ixgbe_update_stats - Update the board statistics counters.
+ * @adapter: board private structure
+ **/
+void ixgbe_update_stats(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u64 good_rx, missed_rx, bprc;
+
+ adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
+ good_rx = IXGBE_READ_REG(hw, IXGBE_GPRC);
+ missed_rx = IXGBE_READ_REG(hw, IXGBE_MPC(0));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(1));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(2));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(3));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(4));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(5));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(6));
+ missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(7));
+ adapter->stats.gprc += (good_rx - missed_rx);
+
+ adapter->stats.mpc[0] += missed_rx;
+ adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
+ bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
+ adapter->stats.bprc += bprc;
+ adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
+ adapter->stats.mprc -= bprc;
+ adapter->stats.roc += IXGBE_READ_REG(hw, IXGBE_ROC);
+ adapter->stats.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64);
+ adapter->stats.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127);
+ adapter->stats.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255);
+ adapter->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
+ adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
+ adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
+
+ adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
+ adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
+ adapter->stats.lxontxc += IXGBE_READ_REG(hw, IXGBE_LXONTXC);
+ adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
+ adapter->stats.lxofftxc += IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
+ adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
+ adapter->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
+ adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
+ adapter->stats.rnbc[0] += IXGBE_READ_REG(hw, IXGBE_RNBC(0));
+ adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
+ adapter->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
+ adapter->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
+ adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
+ adapter->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
+ adapter->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
+ adapter->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
+ adapter->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
+ adapter->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
+ adapter->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
+ adapter->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
+ adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
+ adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
+
+ /* Fill out the OS statistics structure */
+ adapter->net_stats.rx_packets = adapter->stats.gprc;
+ adapter->net_stats.tx_packets = adapter->stats.gptc;
+ adapter->net_stats.rx_bytes = adapter->stats.gorc;
+ adapter->net_stats.tx_bytes = adapter->stats.gotc;
+ adapter->net_stats.multicast = adapter->stats.mprc;
+
+ /* Rx Errors */
+ adapter->net_stats.rx_errors = adapter->stats.crcerrs +
+ adapter->stats.rlec;
+ adapter->net_stats.rx_dropped = 0;
+ adapter->net_stats.rx_length_errors = adapter->stats.rlec;
+ adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
+ adapter->net_stats.rx_missed_errors = adapter->stats.mpc[0];
+
+}
+
+/**
+ * ixgbe_watchdog - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void ixgbe_watchdog(unsigned long data)
+{
+ struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
+ struct net_device *netdev = adapter->netdev;
+ bool link_up;
+ u32 link_speed = 0;
+
+ adapter->hw.phy.ops.check(&adapter->hw, &(link_speed), &link_up);
+
+ if (link_up) {
+ if (!netif_carrier_ok(netdev)) {
+ u32 frctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
+ u32 rmcs = IXGBE_READ_REG(&adapter->hw, IXGBE_RMCS);
+#define FLOW_RX (frctl & IXGBE_FCTRL_RFCE)
+#define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X)
+ DPRINTK(LINK, INFO, "NIC Link is Up %s, "
+ "Flow Control: %s\n",
+ (link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
+ "10 Gbps" :
+ (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
+ "1 Gpbs" : "unknown speed")),
+ ((FLOW_RX && FLOW_TX) ? "RX/TX" :
+ (FLOW_RX ? "RX" :
+ (FLOW_TX ? "TX" : "None"))));
+
+ netif_carrier_on(netdev);
+ netif_wake_queue(netdev);
+ } else {
+ /* Force detection of hung controller */
+ adapter->detect_tx_hung = true;
+ }
+ } else {
+ if (netif_carrier_ok(netdev)) {
+ DPRINTK(LINK, INFO, "NIC Link is Down\n");
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+ }
+
+ ixgbe_update_stats(adapter);
+
+ /* Reset the timer */
+ if (!test_bit(__IXGBE_DOWN, &adapter->state))
+ mod_timer(&adapter->watchdog_timer,
+ round_jiffies(jiffies + 2 * HZ));
+}
+
+#define IXGBE_MAX_TXD_PWR 14
+#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR)
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \
+ (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
+#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
+ MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */
+
+static int ixgbe_tso(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring, struct sk_buff *skb,
+ u32 tx_flags, u8 *hdr_len)
+{
+ struct ixgbe_adv_tx_context_desc *context_desc;
+ unsigned int i;
+ int err;
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0;
+ u32 mss_l4len_idx = 0, l4len;
+ *hdr_len = 0;
+
+ if (skb_is_gso(skb)) {
+ if (skb_header_cloned(skb)) {
+ err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+ if (err)
+ return err;
+ }
+ l4len = tcp_hdrlen(skb);
+ *hdr_len += l4len;
+
+ if (skb->protocol == ntohs(ETH_P_IP)) {
+ struct iphdr *iph = ip_hdr(skb);
+ iph->tot_len = 0;
+ iph->check = 0;
+ tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+ iph->daddr, 0,
+ IPPROTO_TCP,
+ 0);
+ adapter->hw_tso_ctxt++;
+ } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+ ipv6_hdr(skb)->payload_len = 0;
+ tcp_hdr(skb)->check =
+ ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
+ 0, IPPROTO_TCP, 0);
+ adapter->hw_tso6_ctxt++;
+ }
+
+ i = tx_ring->next_to_use;
+
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+
+ /* VLAN MACLEN IPLEN */
+ if (tx_flags & IXGBE_TX_FLAGS_VLAN)
+ vlan_macip_lens |=
+ (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
+ vlan_macip_lens |= ((skb_network_offset(skb)) <<
+ IXGBE_ADVTXD_MACLEN_SHIFT);
+ *hdr_len += skb_network_offset(skb);
+ vlan_macip_lens |=
+ (skb_transport_header(skb) - skb_network_header(skb));
+ *hdr_len +=
+ (skb_transport_header(skb) - skb_network_header(skb));
+ context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
+ context_desc->seqnum_seed = 0;
+
+ /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
+ type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT |
+ IXGBE_ADVTXD_DTYP_CTXT);
+
+ if (skb->protocol == ntohs(ETH_P_IP))
+ type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
+ type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
+
+ /* MSS L4LEN IDX */
+ mss_l4len_idx |=
+ (skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT);
+ mss_l4len_idx |= (l4len << IXGBE_ADVTXD_L4LEN_SHIFT);
+ context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
+
+ tx_buffer_info->time_stamp = jiffies;
+ tx_buffer_info->next_to_watch = i;
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ tx_ring->next_to_use = i;
+
+ return true;
+ }
+ return false;
+}
+
+static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring,
+ struct sk_buff *skb, u32 tx_flags)
+{
+ struct ixgbe_adv_tx_context_desc *context_desc;
+ unsigned int i;
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL ||
+ (tx_flags & IXGBE_TX_FLAGS_VLAN)) {
+ i = tx_ring->next_to_use;
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+
+ if (tx_flags & IXGBE_TX_FLAGS_VLAN)
+ vlan_macip_lens |=
+ (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
+ vlan_macip_lens |= (skb_network_offset(skb) <<
+ IXGBE_ADVTXD_MACLEN_SHIFT);
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ vlan_macip_lens |= (skb_transport_header(skb) -
+ skb_network_header(skb));
+
+ context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
+ context_desc->seqnum_seed = 0;
+
+ type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT |
+ IXGBE_ADVTXD_DTYP_CTXT);
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (skb->protocol == ntohs(ETH_P_IP))
+ type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
+
+ if (skb->sk->sk_protocol == IPPROTO_TCP)
+ type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
+ }
+
+ context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
+ context_desc->mss_l4len_idx = 0;
+
+ tx_buffer_info->time_stamp = jiffies;
+ tx_buffer_info->next_to_watch = i;
+ adapter->hw_csum_tx_good++;
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ tx_ring->next_to_use = i;
+
+ return true;
+ }
+ return false;
+}
+
+static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring,
+ struct sk_buff *skb, unsigned int first)
+{
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ unsigned int len = skb->len;
+ unsigned int offset = 0, size, count = 0, i;
+ unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+ unsigned int f;
+
+ len -= skb->data_len;
+
+ i = tx_ring->next_to_use;
+
+ while (len) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
+
+ tx_buffer_info->length = size;
+ tx_buffer_info->dma = pci_map_single(adapter->pdev,
+ skb->data + offset,
+ size, PCI_DMA_TODEVICE);
+ tx_buffer_info->time_stamp = jiffies;
+ tx_buffer_info->next_to_watch = i;
+
+ len -= size;
+ offset += size;
+ count++;
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ for (f = 0; f < nr_frags; f++) {
+ struct skb_frag_struct *frag;
+
+ frag = &skb_shinfo(skb)->frags[f];
+ len = frag->size;
+ offset = frag->page_offset;
+
+ while (len) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
+
+ tx_buffer_info->length = size;
+ tx_buffer_info->dma = pci_map_page(adapter->pdev,
+ frag->page,
+ offset,
+ size, PCI_DMA_TODEVICE);
+ tx_buffer_info->time_stamp = jiffies;
+ tx_buffer_info->next_to_watch = i;
+
+ len -= size;
+ offset += size;
+ count++;
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+ }
+ if (i == 0)
+ i = tx_ring->count - 1;
+ else
+ i = i - 1;
+ tx_ring->tx_buffer_info[i].skb = skb;
+ tx_ring->tx_buffer_info[first].next_to_watch = i;
+
+ return count;
+}
+
+static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
+ struct ixgbe_ring *tx_ring,
+ int tx_flags, int count, u32 paylen, u8 hdr_len)
+{
+ union ixgbe_adv_tx_desc *tx_desc = NULL;
+ struct ixgbe_tx_buffer *tx_buffer_info;
+ u32 olinfo_status = 0, cmd_type_len = 0;
+ unsigned int i;
+ u32 txd_cmd = IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS | IXGBE_TXD_CMD_IFCS;
+
+ cmd_type_len |= IXGBE_ADVTXD_DTYP_DATA;
+
+ cmd_type_len |= IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT;
+
+ if (tx_flags & IXGBE_TX_FLAGS_VLAN)
+ cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE;
+
+ if (tx_flags & IXGBE_TX_FLAGS_TSO) {
+ cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE;
+
+ olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
+ IXGBE_ADVTXD_POPTS_SHIFT;
+
+ if (tx_flags & IXGBE_TX_FLAGS_IPV4)
+ olinfo_status |= IXGBE_TXD_POPTS_IXSM <<
+ IXGBE_ADVTXD_POPTS_SHIFT;
+
+ } else if (tx_flags & IXGBE_TX_FLAGS_CSUM)
+ olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
+ IXGBE_ADVTXD_POPTS_SHIFT;
+
+ olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT);
+
+ i = tx_ring->next_to_use;
+ while (count--) {
+ tx_buffer_info = &tx_ring->tx_buffer_info[i];
+ tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+ tx_desc->read.buffer_addr = cpu_to_le64(tx_buffer_info->dma);
+ tx_desc->read.cmd_type_len =
+ cpu_to_le32(cmd_type_len | tx_buffer_info->length);
+ tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
+
+ i++;
+ if (i == tx_ring->count)
+ i = 0;
+ }
+
+ tx_desc->read.cmd_type_len |= cpu_to_le32(txd_cmd);
+
+ /*
+ * Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64).
+ */
+ wmb();
+
+ tx_ring->next_to_use = i;
+ writel(i, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_ring *tx_ring;
+ unsigned int len = skb->len;
+ unsigned int first;
+ unsigned int tx_flags = 0;
+ unsigned long flags = 0;
+ u8 hdr_len;
+ int tso;
+ unsigned int mss = 0;
+ int count = 0;
+ unsigned int f;
+ unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+ len -= skb->data_len;
+
+ tx_ring = adapter->tx_ring;
+
+ if (skb->len <= 0) {
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+ mss = skb_shinfo(skb)->gso_size;
+
+ if (mss)
+ count++;
+ else if (skb->ip_summed == CHECKSUM_PARTIAL)
+ count++;
+
+ count += TXD_USE_COUNT(len);
+ for (f = 0; f < nr_frags; f++)
+ count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
+
+ spin_lock_irqsave(&tx_ring->tx_lock, flags);
+ if (IXGBE_DESC_UNUSED(tx_ring) < (count + 2)) {
+ adapter->tx_busy++;
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+ if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+ tx_flags |= IXGBE_TX_FLAGS_VLAN;
+ tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT);
+ }
+
+ if (skb->protocol == ntohs(ETH_P_IP))
+ tx_flags |= IXGBE_TX_FLAGS_IPV4;
+ first = tx_ring->next_to_use;
+ tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len);
+ if (tso < 0) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ if (tso)
+ tx_flags |= IXGBE_TX_FLAGS_TSO;
+ else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) &&
+ (skb->ip_summed == CHECKSUM_PARTIAL))
+ tx_flags |= IXGBE_TX_FLAGS_CSUM;
+
+ ixgbe_tx_queue(adapter, tx_ring, tx_flags,
+ ixgbe_tx_map(adapter, tx_ring, skb, first),
+ skb->len, hdr_len);
+
+ netdev->trans_start = jiffies;
+
+ spin_lock_irqsave(&tx_ring->tx_lock, flags);
+ /* Make sure there is space in the ring for the next send. */
+ if (IXGBE_DESC_UNUSED(tx_ring) < DESC_NEEDED)
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+
+ return NETDEV_TX_OK;
+}
+
+/**
+ * ixgbe_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ **/
+static struct net_device_stats *ixgbe_get_stats(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ /* only return the current stats */
+ return &adapter->net_stats;
+}
+
+/**
+ * ixgbe_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int ixgbe_set_mac(struct net_device *netdev, void *p)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len);
+
+ ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV);
+
+ return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void ixgbe_netpoll(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ disable_irq(adapter->pdev->irq);
+ adapter->flags |= IXGBE_FLAG_IN_NETPOLL;
+ ixgbe_intr(adapter->pdev->irq, netdev);
+ adapter->flags &= ~IXGBE_FLAG_IN_NETPOLL;
+ enable_irq(adapter->pdev->irq);
+}
+#endif
+
+/**
+ * ixgbe_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in ixgbe_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * ixgbe_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int __devinit ixgbe_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *netdev;
+ struct ixgbe_adapter *adapter = NULL;
+ struct ixgbe_hw *hw;
+ const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
+ unsigned long mmio_start, mmio_len;
+ static int cards_found;
+ int i, err, pci_using_dac;
+ u16 link_status, link_speed, link_width;
+ u32 part_num;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK) &&
+ !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
+ pci_using_dac = 1;
+ } else {
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ dev_err(&pdev->dev, "No usable DMA "
+ "configuration, aborting\n");
+ goto err_dma;
+ }
+ }
+ pci_using_dac = 0;
+ }
+
+ err = pci_request_regions(pdev, ixgbe_driver_name);
+ if (err) {
+ dev_err(&pdev->dev, "pci_request_regions failed 0x%x\n", err);
+ goto err_pci_reg;
+ }
+
+ pci_set_master(pdev);
+
+ netdev = alloc_etherdev(sizeof(struct ixgbe_adapter));
+ if (!netdev) {
+ err = -ENOMEM;
+ goto err_alloc_etherdev;
+ }
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ pci_set_drvdata(pdev, netdev);
+ adapter = netdev_priv(netdev);
+
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ hw = &adapter->hw;
+ hw->back = adapter;
+ adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
+
+ mmio_start = pci_resource_start(pdev, 0);
+ mmio_len = pci_resource_len(pdev, 0);
+
+ hw->hw_addr = ioremap(mmio_start, mmio_len);
+ if (!hw->hw_addr) {
+ err = -EIO;
+ goto err_ioremap;
+ }
+
+ for (i = 1; i <= 5; i++) {
+ if (pci_resource_len(pdev, i) == 0)
+ continue;
+ }
+
+ netdev->open = &ixgbe_open;
+ netdev->stop = &ixgbe_close;
+ netdev->hard_start_xmit = &ixgbe_xmit_frame;
+ netdev->get_stats = &ixgbe_get_stats;
+ netdev->set_multicast_list = &ixgbe_set_multi;
+ netdev->set_mac_address = &ixgbe_set_mac;
+ netdev->change_mtu = &ixgbe_change_mtu;
+ ixgbe_set_ethtool_ops(netdev);
+ netdev->tx_timeout = &ixgbe_tx_timeout;
+ netdev->watchdog_timeo = 5 * HZ;
+ netif_napi_add(netdev, &adapter->napi, ixgbe_clean, 64);
+ netdev->vlan_rx_register = ixgbe_vlan_rx_register;
+ netdev->vlan_rx_add_vid = ixgbe_vlan_rx_add_vid;
+ netdev->vlan_rx_kill_vid = ixgbe_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = ixgbe_netpoll;
+#endif
+ strcpy(netdev->name, pci_name(pdev));
+
+ netdev->mem_start = mmio_start;
+ netdev->mem_end = mmio_start + mmio_len;
+
+ adapter->bd_number = cards_found;
+
+ /* PCI config space info */
+ hw->vendor_id = pdev->vendor;
+ hw->device_id = pdev->device;
+ hw->revision_id = pdev->revision;
+ hw->subsystem_vendor_id = pdev->subsystem_vendor;
+ hw->subsystem_device_id = pdev->subsystem_device;
+
+ /* Setup hw api */
+ memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops));
+ memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops));
+
+ err = ii->get_invariants(hw);
+ if (err)
+ goto err_hw_init;
+
+ /* setup the private structure */
+ err = ixgbe_sw_init(adapter);
+ if (err)
+ goto err_sw_init;
+
+ netdev->features = NETIF_F_SG |
+ NETIF_F_HW_CSUM |
+ NETIF_F_HW_VLAN_TX |
+ NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER;
+
+ netdev->features |= NETIF_F_TSO;
+
+ netdev->features |= NETIF_F_TSO6;
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+
+ /* make sure the EEPROM is good */
+ if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
+ dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n");
+ err = -EIO;
+ goto err_eeprom;
+ }
+
+ memcpy(netdev->dev_addr, hw->mac.perm_addr, netdev->addr_len);
+ memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len);
+
+ if (ixgbe_validate_mac_addr(netdev->dev_addr)) {
+ err = -EIO;
+ goto err_eeprom;
+ }
+
+ init_timer(&adapter->watchdog_timer);
+ adapter->watchdog_timer.function = &ixgbe_watchdog;
+ adapter->watchdog_timer.data = (unsigned long)adapter;
+
+ INIT_WORK(&adapter->reset_task, ixgbe_reset_task);
+
+ /* initialize default flow control settings */
+ hw->fc.original_type = ixgbe_fc_full;
+ hw->fc.type = ixgbe_fc_full;
+ hw->fc.high_water = IXGBE_DEFAULT_FCRTH;
+ hw->fc.low_water = IXGBE_DEFAULT_FCRTL;
+ hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE;
+
+ /* Interrupt Throttle Rate */
+ adapter->rx_eitr = (1000000 / IXGBE_DEFAULT_ITR_RX_USECS);
+ adapter->tx_eitr = (1000000 / IXGBE_DEFAULT_ITR_TX_USECS);
+
+ /* print bus type/speed/width info */
+ pci_read_config_word(pdev, IXGBE_PCI_LINK_STATUS, &link_status);
+ link_speed = link_status & IXGBE_PCI_LINK_SPEED;
+ link_width = link_status & IXGBE_PCI_LINK_WIDTH;
+ dev_info(&pdev->dev, "(PCI Express:%s:%s) "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" :
+ (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" :
+ "Unknown"),
+ ((link_width == IXGBE_PCI_LINK_WIDTH_8) ? "Width x8" :
+ (link_width == IXGBE_PCI_LINK_WIDTH_4) ? "Width x4" :
+ (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" :
+ (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" :
+ "Unknown"),
+ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+ ixgbe_read_part_num(hw, &part_num);
+ dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
+ hw->mac.type, hw->phy.type,
+ (part_num >> 8), (part_num & 0xff));
+
+ /* reset the hardware with the new settings */
+ ixgbe_start_hw(hw);
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ strcpy(netdev->name, "eth%d");
+ err = register_netdev(netdev);
+ if (err)
+ goto err_register;
+
+
+ dev_info(&pdev->dev, "Intel(R) 10 Gigabit Network Connection\n");
+ cards_found++;
+ return 0;
+
+err_register:
+err_hw_init:
+err_sw_init:
+err_eeprom:
+ iounmap(hw->hw_addr);
+err_ioremap:
+ free_netdev(netdev);
+err_alloc_etherdev:
+ pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+ pci_disable_device(pdev);
+ return err;
+}
+
+/**
+ * ixgbe_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * ixgbe_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit ixgbe_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+ set_bit(__IXGBE_DOWN, &adapter->state);
+ del_timer_sync(&adapter->watchdog_timer);
+
+ flush_scheduled_work();
+
+ unregister_netdev(netdev);
+
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+
+ iounmap(adapter->hw.hw_addr);
+ pci_release_regions(pdev);
+
+ free_netdev(netdev);
+
+ pci_disable_device(pdev);
+}
+
+/**
+ * ixgbe_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbe_adapter *adapter = netdev->priv;
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev))
+ ixgbe_down(adapter);
+ pci_disable_device(pdev);
+
+ /* Request a slot slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * ixgbe_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ */
+static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbe_adapter *adapter = netdev->priv;
+
+ if (pci_enable_device(pdev)) {
+ DPRINTK(PROBE, ERR,
+ "Cannot re-enable PCI device after reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ pci_set_master(pdev);
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ ixgbe_reset(adapter);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * ixgbe_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation.
+ */
+static void ixgbe_io_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgbe_adapter *adapter = netdev->priv;
+
+ if (netif_running(netdev)) {
+ if (ixgbe_up(adapter)) {
+ DPRINTK(PROBE, INFO, "ixgbe_up failed after reset\n");
+ return;
+ }
+ }
+
+ netif_device_attach(netdev);
+
+}
+
+static struct pci_error_handlers ixgbe_err_handler = {
+ .error_detected = ixgbe_io_error_detected,
+ .slot_reset = ixgbe_io_slot_reset,
+ .resume = ixgbe_io_resume,
+};
+
+static struct pci_driver ixgbe_driver = {
+ .name = ixgbe_driver_name,
+ .id_table = ixgbe_pci_tbl,
+ .probe = ixgbe_probe,
+ .remove = __devexit_p(ixgbe_remove),
+#ifdef CONFIG_PM
+ .suspend = ixgbe_suspend,
+ .resume = ixgbe_resume,
+#endif
+ .shutdown = ixgbe_shutdown,
+ .err_handler = &ixgbe_err_handler
+};
+
+/**
+ * ixgbe_init_module - Driver Registration Routine
+ *
+ * ixgbe_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+static int __init ixgbe_init_module(void)
+{
+ int ret;
+ printk(KERN_INFO "%s: %s - version %s\n", ixgbe_driver_name,
+ ixgbe_driver_string, ixgbe_driver_version);
+
+ printk(KERN_INFO "%s: %s\n", ixgbe_driver_name, ixgbe_copyright);
+
+ ret = pci_register_driver(&ixgbe_driver);
+ return ret;
+}
+module_init(ixgbe_init_module);
+
+/**
+ * ixgbe_exit_module - Driver Exit Cleanup Routine
+ *
+ * ixgbe_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+static void __exit ixgbe_exit_module(void)
+{
+ pci_unregister_driver(&ixgbe_driver);
+}
+module_exit(ixgbe_exit_module);
+
+/* ixgbe_main.c */
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c
new file mode 100644
index 00000000000..8002931ae82
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_phy.c
@@ -0,0 +1,494 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "ixgbe_common.h"
+#include "ixgbe_phy.h"
+
+static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id);
+static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw);
+static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr);
+static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u16 phy_data);
+
+/**
+ * ixgbe_identify_phy - Get physical layer module
+ * @hw: pointer to hardware structure
+ *
+ * Determines the physical layer module found on the current adapter.
+ **/
+s32 ixgbe_identify_phy(struct ixgbe_hw *hw)
+{
+ s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
+ u32 phy_addr;
+
+ for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
+ if (ixgbe_validate_phy_addr(hw, phy_addr)) {
+ hw->phy.addr = phy_addr;
+ ixgbe_get_phy_id(hw);
+ hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id);
+ status = 0;
+ break;
+ }
+ }
+ return status;
+}
+
+/**
+ * ixgbe_validate_phy_addr - Determines phy address is valid
+ * @hw: pointer to hardware structure
+ *
+ **/
+static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr)
+{
+ u16 phy_id = 0;
+ bool valid = false;
+
+ hw->phy.addr = phy_addr;
+ ixgbe_read_phy_reg(hw,
+ IXGBE_MDIO_PHY_ID_HIGH,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ &phy_id);
+
+ if (phy_id != 0xFFFF && phy_id != 0x0)
+ valid = true;
+
+ return valid;
+}
+
+/**
+ * ixgbe_get_phy_id - Get the phy type
+ * @hw: pointer to hardware structure
+ *
+ **/
+static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw)
+{
+ u32 status;
+ u16 phy_id_high = 0;
+ u16 phy_id_low = 0;
+
+ status = ixgbe_read_phy_reg(hw,
+ IXGBE_MDIO_PHY_ID_HIGH,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ &phy_id_high);
+
+ if (status == 0) {
+ hw->phy.id = (u32)(phy_id_high << 16);
+ status = ixgbe_read_phy_reg(hw,
+ IXGBE_MDIO_PHY_ID_LOW,
+ IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+ &phy_id_low);
+ hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK);
+ hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK);
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_get_phy_type_from_id - Get the phy type
+ * @hw: pointer to hardware structure
+ *
+ **/
+static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
+{
+ enum ixgbe_phy_type phy_type;
+
+ switch (phy_id) {
+ case TN1010_PHY_ID:
+ phy_type = ixgbe_phy_tn;
+ break;
+ case QT2022_PHY_ID:
+ phy_type = ixgbe_phy_qt;
+ break;
+ default:
+ phy_type = ixgbe_phy_unknown;
+ break;
+ }
+
+ return phy_type;
+}
+
+/**
+ * ixgbe_reset_phy - Performs a PHY reset
+ * @hw: pointer to hardware structure
+ **/
+s32 ixgbe_reset_phy(struct ixgbe_hw *hw)
+{
+ /*
+ * Perform soft PHY reset to the PHY_XS.
+ * This will cause a soft reset to the PHY
+ */
+ return ixgbe_write_phy_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
+ IXGBE_MDIO_PHY_XS_DEV_TYPE,
+ IXGBE_MDIO_PHY_XS_RESET);
+}
+
+/**
+ * ixgbe_read_phy_reg - Reads a value from a specified PHY register
+ * @hw: pointer to hardware structure
+ * @reg_addr: 32 bit address of PHY register to read
+ * @phy_data: Pointer to read data from PHY register
+ **/
+s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u16 *phy_data)
+{
+ u32 command;
+ u32 i;
+ u32 timeout = 10;
+ u32 data;
+ s32 status = 0;
+ u16 gssr;
+
+ if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
+ gssr = IXGBE_GSSR_PHY1_SM;
+ else
+ gssr = IXGBE_GSSR_PHY0_SM;
+
+ if (ixgbe_acquire_swfw_sync(hw, gssr) != 0)
+ status = IXGBE_ERR_SWFW_SYNC;
+
+ if (status == 0) {
+ /* Setup and write the address cycle command */
+ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
+ (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+ (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+ (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
+
+ IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+ /*
+ * Check every 10 usec to see if the address cycle completed.
+ * The MDI Command bit will clear when the operation is
+ * complete
+ */
+ for (i = 0; i < timeout; i++) {
+ udelay(10);
+
+ command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
+ break;
+ }
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
+ hw_dbg(hw, "PHY address command did not complete.\n");
+ status = IXGBE_ERR_PHY;
+ }
+
+ if (status == 0) {
+ /*
+ * Address cycle complete, setup and write the read
+ * command
+ */
+ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
+ (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+ (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+ (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
+
+ IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+ /*
+ * Check every 10 usec to see if the address cycle
+ * completed. The MDI Command bit will clear when the
+ * operation is complete
+ */
+ for (i = 0; i < timeout; i++) {
+ udelay(10);
+
+ command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
+ break;
+ }
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
+ hw_dbg(hw,
+ "PHY read command didn't complete\n");
+ status = IXGBE_ERR_PHY;
+ } else {
+ /*
+ * Read operation is complete. Get the data
+ * from MSRWD
+ */
+ data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
+ data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
+ *phy_data = (u16)(data);
+ }
+ }
+
+ ixgbe_release_swfw_sync(hw, gssr);
+ }
+ return status;
+}
+
+/**
+ * ixgbe_write_phy_reg - Writes a value to specified PHY register
+ * @hw: pointer to hardware structure
+ * @reg_addr: 32 bit PHY register to write
+ * @device_type: 5 bit device type
+ * @phy_data: Data to write to the PHY register
+ **/
+static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u16 phy_data)
+{
+ u32 command;
+ u32 i;
+ u32 timeout = 10;
+ s32 status = 0;
+ u16 gssr;
+
+ if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
+ gssr = IXGBE_GSSR_PHY1_SM;
+ else
+ gssr = IXGBE_GSSR_PHY0_SM;
+
+ if (ixgbe_acquire_swfw_sync(hw, gssr) != 0)
+ status = IXGBE_ERR_SWFW_SYNC;
+
+ if (status == 0) {
+ /* Put the data in the MDI single read and write data register*/
+ IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
+
+ /* Setup and write the address cycle command */
+ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
+ (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+ (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+ (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
+
+ IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+ /*
+ * Check every 10 usec to see if the address cycle completed.
+ * The MDI Command bit will clear when the operation is
+ * complete
+ */
+ for (i = 0; i < timeout; i++) {
+ udelay(10);
+
+ command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) {
+ hw_dbg(hw, "PHY address cmd didn't complete\n");
+ break;
+ }
+ }
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) != 0)
+ status = IXGBE_ERR_PHY;
+
+ if (status == 0) {
+ /*
+ * Address cycle complete, setup and write the write
+ * command
+ */
+ command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
+ (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+ (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+ (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
+
+ IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+ /*
+ * Check every 10 usec to see if the address cycle
+ * completed. The MDI Command bit will clear when the
+ * operation is complete
+ */
+ for (i = 0; i < timeout; i++) {
+ udelay(10);
+
+ command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) {
+ hw_dbg(hw, "PHY write command did not "
+ "complete.\n");
+ break;
+ }
+ }
+
+ if ((command & IXGBE_MSCA_MDI_COMMAND) != 0)
+ status = IXGBE_ERR_PHY;
+ }
+
+ ixgbe_release_swfw_sync(hw, gssr);
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_setup_tnx_phy_link - Set and restart autoneg
+ * @hw: pointer to hardware structure
+ *
+ * Restart autonegotiation and PHY and waits for completion.
+ **/
+s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw)
+{
+ s32 status = IXGBE_NOT_IMPLEMENTED;
+ u32 time_out;
+ u32 max_time_out = 10;
+ u16 autoneg_speed_selection_register = 0x10;
+ u16 autoneg_restart_mask = 0x0200;
+ u16 autoneg_complete_mask = 0x0020;
+ u16 autoneg_reg = 0;
+
+ /*
+ * Set advertisement settings in PHY based on autoneg_advertised
+ * settings. If autoneg_advertised = 0, then advertise default values
+ * txn devices cannot be "forced" to a autoneg 10G and fail. But can
+ * for a 1G.
+ */
+ ixgbe_read_phy_reg(hw,
+ autoneg_speed_selection_register,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_reg);
+
+ if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL)
+ autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */
+ else
+ autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */
+
+ ixgbe_write_phy_reg(hw,
+ autoneg_speed_selection_register,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ autoneg_reg);
+
+
+ /* Restart PHY autonegotiation and wait for completion */
+ ixgbe_read_phy_reg(hw,
+ IXGBE_MDIO_AUTO_NEG_CONTROL,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_reg);
+
+ autoneg_reg |= autoneg_restart_mask;
+
+ ixgbe_write_phy_reg(hw,
+ IXGBE_MDIO_AUTO_NEG_CONTROL,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ autoneg_reg);
+
+ /* Wait for autonegotiation to finish */
+ for (time_out = 0; time_out < max_time_out; time_out++) {
+ udelay(10);
+ /* Restart PHY autonegotiation and wait for completion */
+ status = ixgbe_read_phy_reg(hw,
+ IXGBE_MDIO_AUTO_NEG_STATUS,
+ IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+ &autoneg_reg);
+
+ autoneg_reg &= autoneg_complete_mask;
+ if (autoneg_reg == autoneg_complete_mask) {
+ status = 0;
+ break;
+ }
+ }
+
+ if (time_out == max_time_out)
+ status = IXGBE_ERR_LINK_SETUP;
+
+ return status;
+}
+
+/**
+ * ixgbe_check_tnx_phy_link - Determine link and speed status
+ * @hw: pointer to hardware structure
+ *
+ * Reads the VS1 register to determine if link is up and the current speed for
+ * the PHY.
+ **/
+s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed,
+ bool *link_up)
+{
+ s32 status = 0;
+ u32 time_out;
+ u32 max_time_out = 10;
+ u16 phy_link = 0;
+ u16 phy_speed = 0;
+ u16 phy_data = 0;
+
+ /* Initialize speed and link to default case */
+ *link_up = false;
+ *speed = IXGBE_LINK_SPEED_10GB_FULL;
+
+ /*
+ * Check current speed and link status of the PHY register.
+ * This is a vendor specific register and may have to
+ * be changed for other copper PHYs.
+ */
+ for (time_out = 0; time_out < max_time_out; time_out++) {
+ udelay(10);
+ if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) {
+ *link_up = true;
+ if (phy_speed ==
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS)
+ *speed = IXGBE_LINK_SPEED_1GB_FULL;
+ break;
+ } else {
+ status = ixgbe_read_phy_reg(hw,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS,
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+ &phy_data);
+ phy_link = phy_data &
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS;
+ phy_speed = phy_data &
+ IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * ixgbe_setup_tnx_phy_link_speed - Sets the auto advertised capabilities
+ * @hw: pointer to hardware structure
+ * @speed: new link speed
+ * @autoneg: true if autonegotiation enabled
+ **/
+s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed,
+ bool autoneg,
+ bool autoneg_wait_to_complete)
+{
+ /*
+ * Clear autoneg_advertised and set new values based on input link
+ * speed.
+ */
+ hw->phy.autoneg_advertised = 0;
+
+ if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+ hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
+ if (speed & IXGBE_LINK_SPEED_1GB_FULL)
+ hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
+
+ /* Setup link based on the new speed settings */
+ ixgbe_setup_tnx_phy_link(hw);
+
+ return 0;
+}
diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h
new file mode 100644
index 00000000000..199e8f670f3
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_phy.h
@@ -0,0 +1,50 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_PHY_H_
+#define _IXGBE_PHY_H_
+
+#include "ixgbe_type.h"
+
+s32 ixgbe_init_shared_code_phy(struct ixgbe_hw *hw);
+s32 ixgbe_setup_phy_link(struct ixgbe_hw *hw);
+s32 ixgbe_check_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up);
+s32 ixgbe_setup_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg,
+ bool autoneg_wait_to_complete);
+s32 ixgbe_identify_phy(struct ixgbe_hw *hw);
+s32 ixgbe_reset_phy(struct ixgbe_hw *hw);
+s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u16 *phy_data);
+
+/* PHY specific */
+s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw);
+s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up);
+s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg,
+ bool autoneg_wait_to_complete);
+
+#endif /* _IXGBE_PHY_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
new file mode 100644
index 00000000000..fdcde16a2a9
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -0,0 +1,1332 @@
+/*******************************************************************************
+
+ Intel 10 Gigabit PCI Express Linux driver
+ Copyright(c) 1999 - 2007 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Contact Information:
+ Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_TYPE_H_
+#define _IXGBE_TYPE_H_
+
+#include <linux/types.h>
+
+/* Vendor ID */
+#define IXGBE_INTEL_VENDOR_ID 0x8086
+
+/* Device IDs */
+#define IXGBE_DEV_ID_82598AF_DUAL_PORT 0x10C6
+#define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7
+#define IXGBE_DEV_ID_82598AT_DUAL_PORT 0x10C8
+#define IXGBE_DEV_ID_82598EB_CX4 0x10DD
+
+/* General Registers */
+#define IXGBE_CTRL 0x00000
+#define IXGBE_STATUS 0x00008
+#define IXGBE_CTRL_EXT 0x00018
+#define IXGBE_ESDP 0x00020
+#define IXGBE_EODSDP 0x00028
+#define IXGBE_LEDCTL 0x00200
+#define IXGBE_FRTIMER 0x00048
+#define IXGBE_TCPTIMER 0x0004C
+
+/* NVM Registers */
+#define IXGBE_EEC 0x10010
+#define IXGBE_EERD 0x10014
+#define IXGBE_FLA 0x1001C
+#define IXGBE_EEMNGCTL 0x10110
+#define IXGBE_EEMNGDATA 0x10114
+#define IXGBE_FLMNGCTL 0x10118
+#define IXGBE_FLMNGDATA 0x1011C
+#define IXGBE_FLMNGCNT 0x10120
+#define IXGBE_FLOP 0x1013C
+#define IXGBE_GRC 0x10200
+
+/* Interrupt Registers */
+#define IXGBE_EICR 0x00800
+#define IXGBE_EICS 0x00808
+#define IXGBE_EIMS 0x00880
+#define IXGBE_EIMC 0x00888
+#define IXGBE_EIAC 0x00810
+#define IXGBE_EIAM 0x00890
+#define IXGBE_EITR(_i) (0x00820 + ((_i) * 4)) /* 0x820-0x86c */
+#define IXGBE_IVAR(_i) (0x00900 + ((_i) * 4)) /* 24 at 0x900-0x960 */
+#define IXGBE_MSIXT 0x00000 /* MSI-X Table. 0x0000 - 0x01C */
+#define IXGBE_MSIXPBA 0x02000 /* MSI-X Pending bit array */
+#define IXGBE_PBACL 0x11068
+#define IXGBE_GPIE 0x00898
+
+/* Flow Control Registers */
+#define IXGBE_PFCTOP 0x03008
+#define IXGBE_FCTTV(_i) (0x03200 + ((_i) * 4)) /* 4 of these (0-3) */
+#define IXGBE_FCRTL(_i) (0x03220 + ((_i) * 8)) /* 8 of these (0-7) */
+#define IXGBE_FCRTH(_i) (0x03260 + ((_i) * 8)) /* 8 of these (0-7) */
+#define IXGBE_FCRTV 0x032A0
+#define IXGBE_TFCS 0x0CE00
+
+/* Receive DMA Registers */
+#define IXGBE_RDBAL(_i) (0x01000 + ((_i) * 0x40)) /* 64 of each (0-63)*/
+#define IXGBE_RDBAH(_i) (0x01004 + ((_i) * 0x40))
+#define IXGBE_RDLEN(_i) (0x01008 + ((_i) * 0x40))
+#define IXGBE_RDH(_i) (0x01010 + ((_i) * 0x40))
+#define IXGBE_RDT(_i) (0x01018 + ((_i) * 0x40))
+#define IXGBE_RXDCTL(_i) (0x01028 + ((_i) * 0x40))
+#define IXGBE_RSCCTL(_i) (0x0102C + ((_i) * 0x40))
+#define IXGBE_SRRCTL(_i) (0x02100 + ((_i) * 4))
+ /* array of 16 (0x02100-0x0213C) */
+#define IXGBE_DCA_RXCTRL(_i) (0x02200 + ((_i) * 4))
+ /* array of 16 (0x02200-0x0223C) */
+#define IXGBE_RDRXCTL 0x02F00
+#define IXGBE_RXPBSIZE(_i) (0x03C00 + ((_i) * 4))
+ /* 8 of these 0x03C00 - 0x03C1C */
+#define IXGBE_RXCTRL 0x03000
+#define IXGBE_DROPEN 0x03D04
+#define IXGBE_RXPBSIZE_SHIFT 10
+
+/* Receive Registers */
+#define IXGBE_RXCSUM 0x05000
+#define IXGBE_RFCTL 0x05008
+#define IXGBE_MTA(_i) (0x05200 + ((_i) * 4))
+ /* Multicast Table Array - 128 entries */
+#define IXGBE_RAL(_i) (0x05400 + ((_i) * 8)) /* 16 of these (0-15) */
+#define IXGBE_RAH(_i) (0x05404 + ((_i) * 8)) /* 16 of these (0-15) */
+#define IXGBE_PSRTYPE 0x05480
+ /* 0x5480-0x54BC Packet split receive type */
+#define IXGBE_VFTA(_i) (0x0A000 + ((_i) * 4))
+ /* array of 4096 1-bit vlan filters */
+#define IXGBE_VFTAVIND(_j, _i) (0x0A200 + ((_j) * 0x200) + ((_i) * 4))
+ /*array of 4096 4-bit vlan vmdq indicies */
+#define IXGBE_FCTRL 0x05080
+#define IXGBE_VLNCTRL 0x05088
+#define IXGBE_MCSTCTRL 0x05090
+#define IXGBE_MRQC 0x05818
+#define IXGBE_VMD_CTL 0x0581C
+#define IXGBE_IMIR(_i) (0x05A80 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_IMIRVP 0x05AC0
+#define IXGBE_RETA(_i) (0x05C00 + ((_i) * 4)) /* 32 of these (0-31) */
+#define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* 10 of these (0-9) */
+
+/* Transmit DMA registers */
+#define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40))/* 32 of these (0-31)*/
+#define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40))
+#define IXGBE_TDLEN(_i) (0x06008 + ((_i) * 0x40))
+#define IXGBE_TDH(_i) (0x06010 + ((_i) * 0x40))
+#define IXGBE_TDT(_i) (0x06018 + ((_i) * 0x40))
+#define IXGBE_TXDCTL(_i) (0x06028 + ((_i) * 0x40))
+#define IXGBE_TDWBAL(_i) (0x06038 + ((_i) * 0x40))
+#define IXGBE_TDWBAH(_i) (0x0603C + ((_i) * 0x40))
+#define IXGBE_DTXCTL 0x07E00
+#define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4))
+ /* there are 16 of these (0-15) */
+#define IXGBE_TIPG 0x0CB00
+#define IXGBE_TXPBSIZE(_i) (0x0CC00 + ((_i) *0x04))
+ /* there are 8 of these */
+#define IXGBE_MNGTXMAP 0x0CD10
+#define IXGBE_TIPG_FIBER_DEFAULT 3
+#define IXGBE_TXPBSIZE_SHIFT 10
+
+/* Wake up registers */
+#define IXGBE_WUC 0x05800
+#define IXGBE_WUFC 0x05808
+#define IXGBE_WUS 0x05810
+#define IXGBE_IPAV 0x05838
+#define IXGBE_IP4AT 0x05840 /* IPv4 table 0x5840-0x5858 */
+#define IXGBE_IP6AT 0x05880 /* IPv6 table 0x5880-0x588F */
+#define IXGBE_WUPL 0x05900
+#define IXGBE_WUPM 0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */
+#define IXGBE_FHFT 0x09000 /* Flex host filter table 9000-93FC */
+
+/* Music registers */
+#define IXGBE_RMCS 0x03D00
+#define IXGBE_DPMCS 0x07F40
+#define IXGBE_PDPMCS 0x0CD00
+#define IXGBE_RUPPBMR 0x050A0
+#define IXGBE_RT2CR(_i) (0x03C20 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_RT2SR(_i) (0x03C40 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_TDTQ2TCCR(_i) (0x0602C + ((_i) * 0x40)) /* 8 of these (0-7) */
+#define IXGBE_TDTQ2TCSR(_i) (0x0622C + ((_i) * 0x40)) /* 8 of these (0-7) */
+#define IXGBE_TDPT2TCCR(_i) (0x0CD20 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_TDPT2TCSR(_i) (0x0CD40 + ((_i) * 4)) /* 8 of these (0-7) */
+
+/* Stats registers */
+#define IXGBE_CRCERRS 0x04000
+#define IXGBE_ILLERRC 0x04004
+#define IXGBE_ERRBC 0x04008
+#define IXGBE_MSPDC 0x04010
+#define IXGBE_MPC(_i) (0x03FA0 + ((_i) * 4)) /* 8 of these 3FA0-3FBC*/
+#define IXGBE_MLFC 0x04034
+#define IXGBE_MRFC 0x04038
+#define IXGBE_RLEC 0x04040
+#define IXGBE_LXONTXC 0x03F60
+#define IXGBE_LXONRXC 0x0CF60
+#define IXGBE_LXOFFTXC 0x03F68
+#define IXGBE_LXOFFRXC 0x0CF68
+#define IXGBE_PXONTXC(_i) (0x03F00 + ((_i) * 4)) /* 8 of these 3F00-3F1C*/
+#define IXGBE_PXONRXC(_i) (0x0CF00 + ((_i) * 4)) /* 8 of these CF00-CF1C*/
+#define IXGBE_PXOFFTXC(_i) (0x03F20 + ((_i) * 4)) /* 8 of these 3F20-3F3C*/
+#define IXGBE_PXOFFRXC(_i) (0x0CF20 + ((_i) * 4)) /* 8 of these CF20-CF3C*/
+#define IXGBE_PRC64 0x0405C
+#define IXGBE_PRC127 0x04060
+#define IXGBE_PRC255 0x04064
+#define IXGBE_PRC511 0x04068
+#define IXGBE_PRC1023 0x0406C
+#define IXGBE_PRC1522 0x04070
+#define IXGBE_GPRC 0x04074
+#define IXGBE_BPRC 0x04078
+#define IXGBE_MPRC 0x0407C
+#define IXGBE_GPTC 0x04080
+#define IXGBE_GORCL 0x04088
+#define IXGBE_GORCH 0x0408C
+#define IXGBE_GOTCL 0x04090
+#define IXGBE_GOTCH 0x04094
+#define IXGBE_RNBC(_i) (0x03FC0 + ((_i) * 4)) /* 8 of these 3FC0-3FDC*/
+#define IXGBE_RUC 0x040A4
+#define IXGBE_RFC 0x040A8
+#define IXGBE_ROC 0x040AC
+#define IXGBE_RJC 0x040B0
+#define IXGBE_MNGPRC 0x040B4
+#define IXGBE_MNGPDC 0x040B8
+#define IXGBE_MNGPTC 0x0CF90
+#define IXGBE_TORL 0x040C0
+#define IXGBE_TORH 0x040C4
+#define IXGBE_TPR 0x040D0
+#define IXGBE_TPT 0x040D4
+#define IXGBE_PTC64 0x040D8
+#define IXGBE_PTC127 0x040DC
+#define IXGBE_PTC255 0x040E0
+#define IXGBE_PTC511 0x040E4
+#define IXGBE_PTC1023 0x040E8
+#define IXGBE_PTC1522 0x040EC
+#define IXGBE_MPTC 0x040F0
+#define IXGBE_BPTC 0x040F4
+#define IXGBE_XEC 0x04120
+
+#define IXGBE_RQSMR(_i) (0x02300 + ((_i) * 4)) /* 16 of these */
+#define IXGBE_TQSMR(_i) (0x07300 + ((_i) * 4)) /* 8 of these */
+
+#define IXGBE_QPRC(_i) (0x01030 + ((_i) * 0x40)) /* 16 of these */
+#define IXGBE_QPTC(_i) (0x06030 + ((_i) * 0x40)) /* 16 of these */
+#define IXGBE_QBRC(_i) (0x01034 + ((_i) * 0x40)) /* 16 of these */
+#define IXGBE_QBTC(_i) (0x06034 + ((_i) * 0x40)) /* 16 of these */
+
+/* Management */
+#define IXGBE_MAVTV(_i) (0x05010 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_MFUTP(_i) (0x05030 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_MANC 0x05820
+#define IXGBE_MFVAL 0x05824
+#define IXGBE_MANC2H 0x05860
+#define IXGBE_MDEF(_i) (0x05890 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_MIPAF 0x058B0
+#define IXGBE_MMAL(_i) (0x05910 + ((_i) * 8)) /* 4 of these (0-3) */
+#define IXGBE_MMAH(_i) (0x05914 + ((_i) * 8)) /* 4 of these (0-3) */
+#define IXGBE_FTFT 0x09400 /* 0x9400-0x97FC */
+
+/* ARC Subsystem registers */
+#define IXGBE_HICR 0x15F00
+#define IXGBE_FWSTS 0x15F0C
+#define IXGBE_HSMC0R 0x15F04
+#define IXGBE_HSMC1R 0x15F08
+#define IXGBE_SWSR 0x15F10
+#define IXGBE_HFDR 0x15FE8
+#define IXGBE_FLEX_MNG 0x15800 /* 0x15800 - 0x15EFC */
+
+/* PCI-E registers */
+#define IXGBE_GCR 0x11000
+#define IXGBE_GTV 0x11004
+#define IXGBE_FUNCTAG 0x11008
+#define IXGBE_GLT 0x1100C
+#define IXGBE_GSCL_1 0x11010
+#define IXGBE_GSCL_2 0x11014
+#define IXGBE_GSCL_3 0x11018
+#define IXGBE_GSCL_4 0x1101C
+#define IXGBE_GSCN_0 0x11020
+#define IXGBE_GSCN_1 0x11024
+#define IXGBE_GSCN_2 0x11028
+#define IXGBE_GSCN_3 0x1102C
+#define IXGBE_FACTPS 0x10150
+#define IXGBE_PCIEANACTL 0x11040
+#define IXGBE_SWSM 0x10140
+#define IXGBE_FWSM 0x10148
+#define IXGBE_GSSR 0x10160
+#define IXGBE_MREVID 0x11064
+#define IXGBE_DCA_ID 0x11070
+#define IXGBE_DCA_CTRL 0x11074
+
+/* Diagnostic Registers */
+#define IXGBE_RDSTATCTL 0x02C20
+#define IXGBE_RDSTAT(_i) (0x02C00 + ((_i) * 4)) /* 0x02C00-0x02C1C */
+#define IXGBE_RDHMPN 0x02F08
+#define IXGBE_RIC_DW0 0x02F10
+#define IXGBE_RIC_DW1 0x02F14
+#define IXGBE_RIC_DW2 0x02F18
+#define IXGBE_RIC_DW3 0x02F1C
+#define IXGBE_RDPROBE 0x02F20
+#define IXGBE_TDSTATCTL 0x07C20
+#define IXGBE_TDSTAT(_i) (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */
+#define IXGBE_TDHMPN 0x07F08
+#define IXGBE_TIC_DW0 0x07F10
+#define IXGBE_TIC_DW1 0x07F14
+#define IXGBE_TIC_DW2 0x07F18
+#define IXGBE_TIC_DW3 0x07F1C
+#define IXGBE_TDPROBE 0x07F20
+#define IXGBE_TXBUFCTRL 0x0C600
+#define IXGBE_TXBUFDATA0 0x0C610
+#define IXGBE_TXBUFDATA1 0x0C614
+#define IXGBE_TXBUFDATA2 0x0C618
+#define IXGBE_TXBUFDATA3 0x0C61C
+#define IXGBE_RXBUFCTRL 0x03600
+#define IXGBE_RXBUFDATA0 0x03610
+#define IXGBE_RXBUFDATA1 0x03614
+#define IXGBE_RXBUFDATA2 0x03618
+#define IXGBE_RXBUFDATA3 0x0361C
+#define IXGBE_PCIE_DIAG(_i) (0x11090 + ((_i) * 4)) /* 8 of these */
+#define IXGBE_RFVAL 0x050A4
+#define IXGBE_MDFTC1 0x042B8
+#define IXGBE_MDFTC2 0x042C0
+#define IXGBE_MDFTFIFO1 0x042C4
+#define IXGBE_MDFTFIFO2 0x042C8
+#define IXGBE_MDFTS 0x042CC
+#define IXGBE_RXDATAWRPTR(_i) (0x03700 + ((_i) * 4)) /* 8 of these 3700-370C*/
+#define IXGBE_RXDESCWRPTR(_i) (0x03710 + ((_i) * 4)) /* 8 of these 3710-371C*/
+#define IXGBE_RXDATARDPTR(_i) (0x03720 + ((_i) * 4)) /* 8 of these 3720-372C*/
+#define IXGBE_RXDESCRDPTR(_i) (0x03730 + ((_i) * 4)) /* 8 of these 3730-373C*/
+#define IXGBE_TXDATAWRPTR(_i) (0x0C700 + ((_i) * 4)) /* 8 of these C700-C70C*/
+#define IXGBE_TXDESCWRPTR(_i) (0x0C710 + ((_i) * 4)) /* 8 of these C710-C71C*/
+#define IXGBE_TXDATARDPTR(_i) (0x0C720 + ((_i) * 4)) /* 8 of these C720-C72C*/
+#define IXGBE_TXDESCRDPTR(_i) (0x0C730 + ((_i) * 4)) /* 8 of these C730-C73C*/
+#define IXGBE_PCIEECCCTL 0x1106C
+#define IXGBE_PBTXECC 0x0C300
+#define IXGBE_PBRXECC 0x03300
+#define IXGBE_GHECCR 0x110B0
+
+/* MAC Registers */
+#define IXGBE_PCS1GCFIG 0x04200
+#define IXGBE_PCS1GLCTL 0x04208
+#define IXGBE_PCS1GLSTA 0x0420C
+#define IXGBE_PCS1GDBG0 0x04210
+#define IXGBE_PCS1GDBG1 0x04214
+#define IXGBE_PCS1GANA 0x04218
+#define IXGBE_PCS1GANLP 0x0421C
+#define IXGBE_PCS1GANNP 0x04220
+#define IXGBE_PCS1GANLPNP 0x04224
+#define IXGBE_HLREG0 0x04240
+#define IXGBE_HLREG1 0x04244
+#define IXGBE_PAP 0x04248
+#define IXGBE_MACA 0x0424C
+#define IXGBE_APAE 0x04250
+#define IXGBE_ARD 0x04254
+#define IXGBE_AIS 0x04258
+#define IXGBE_MSCA 0x0425C
+#define IXGBE_MSRWD 0x04260
+#define IXGBE_MLADD 0x04264
+#define IXGBE_MHADD 0x04268
+#define IXGBE_TREG 0x0426C
+#define IXGBE_PCSS1 0x04288
+#define IXGBE_PCSS2 0x0428C
+#define IXGBE_XPCSS 0x04290
+#define IXGBE_SERDESC 0x04298
+#define IXGBE_MACS 0x0429C
+#define IXGBE_AUTOC 0x042A0
+#define IXGBE_LINKS 0x042A4
+#define IXGBE_AUTOC2 0x042A8
+#define IXGBE_AUTOC3 0x042AC
+#define IXGBE_ANLP1 0x042B0
+#define IXGBE_ANLP2 0x042B4
+#define IXGBE_ATLASCTL 0x04800
+
+/* RSCCTL Bit Masks */
+#define IXGBE_RSCCTL_RSCEN 0x01
+#define IXGBE_RSCCTL_MAXDESC_1 0x00
+#define IXGBE_RSCCTL_MAXDESC_4 0x04
+#define IXGBE_RSCCTL_MAXDESC_8 0x08
+#define IXGBE_RSCCTL_MAXDESC_16 0x0C
+
+/* CTRL Bit Masks */
+#define IXGBE_CTRL_GIO_DIS 0x00000004 /* Global IO Master Disable bit */
+#define IXGBE_CTRL_LNK_RST 0x00000008 /* Link Reset. Resets everything. */
+#define IXGBE_CTRL_RST 0x04000000 /* Reset (SW) */
+
+/* FACTPS */
+#define IXGBE_FACTPS_LFS 0x40000000 /* LAN Function Select */
+
+/* MHADD Bit Masks */
+#define IXGBE_MHADD_MFS_MASK 0xFFFF0000
+#define IXGBE_MHADD_MFS_SHIFT 16
+
+/* Extended Device Control */
+#define IXGBE_CTRL_EXT_NS_DIS 0x00010000 /* No Snoop disable */
+#define IXGBE_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */
+#define IXGBE_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
+
+/* Direct Cache Access (DCA) definitions */
+#define IXGBE_DCA_CTRL_DCA_ENABLE 0x00000000 /* DCA Enable */
+#define IXGBE_DCA_CTRL_DCA_DISABLE 0x00000001 /* DCA Disable */
+
+#define IXGBE_DCA_CTRL_DCA_MODE_CB1 0x00 /* DCA Mode CB1 */
+#define IXGBE_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */
+
+#define IXGBE_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */
+#define IXGBE_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */
+#define IXGBE_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */
+#define IXGBE_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */
+
+#define IXGBE_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */
+#define IXGBE_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */
+#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* TX Desc writeback RO bit */
+#define IXGBE_DCA_MAX_QUEUES_82598 16 /* DCA regs only on 16 queues */
+
+/* MSCA Bit Masks */
+#define IXGBE_MSCA_NP_ADDR_MASK 0x0000FFFF /* MDI Address (new protocol) */
+#define IXGBE_MSCA_NP_ADDR_SHIFT 0
+#define IXGBE_MSCA_DEV_TYPE_MASK 0x001F0000 /* Device Type (new protocol) */
+#define IXGBE_MSCA_DEV_TYPE_SHIFT 16 /* Register Address (old protocol */
+#define IXGBE_MSCA_PHY_ADDR_MASK 0x03E00000 /* PHY Address mask */
+#define IXGBE_MSCA_PHY_ADDR_SHIFT 21 /* PHY Address shift*/
+#define IXGBE_MSCA_OP_CODE_MASK 0x0C000000 /* OP CODE mask */
+#define IXGBE_MSCA_OP_CODE_SHIFT 26 /* OP CODE shift */
+#define IXGBE_MSCA_ADDR_CYCLE 0x00000000 /* OP CODE 00 (addr cycle) */
+#define IXGBE_MSCA_WRITE 0x04000000 /* OP CODE 01 (write) */
+#define IXGBE_MSCA_READ 0x08000000 /* OP CODE 10 (read) */
+#define IXGBE_MSCA_READ_AUTOINC 0x0C000000 /* OP CODE 11 (read, auto inc)*/
+#define IXGBE_MSCA_ST_CODE_MASK 0x30000000 /* ST Code mask */
+#define IXGBE_MSCA_ST_CODE_SHIFT 28 /* ST Code shift */
+#define IXGBE_MSCA_NEW_PROTOCOL 0x00000000 /* ST CODE 00 (new protocol) */
+#define IXGBE_MSCA_OLD_PROTOCOL 0x10000000 /* ST CODE 01 (old protocol) */
+#define IXGBE_MSCA_MDI_COMMAND 0x40000000 /* Initiate MDI command */
+#define IXGBE_MSCA_MDI_IN_PROG_EN 0x80000000 /* MDI in progress enable */
+
+/* MSRWD bit masks */
+#define IXGBE_MSRWD_WRITE_DATA_MASK 0x0000FFFF
+#define IXGBE_MSRWD_WRITE_DATA_SHIFT 0
+#define IXGBE_MSRWD_READ_DATA_MASK 0xFFFF0000
+#define IXGBE_MSRWD_READ_DATA_SHIFT 16
+
+/* Atlas registers */
+#define IXGBE_ATLAS_PDN_LPBK 0x24
+#define IXGBE_ATLAS_PDN_10G 0xB
+#define IXGBE_ATLAS_PDN_1G 0xC
+#define IXGBE_ATLAS_PDN_AN 0xD
+
+/* Atlas bit masks */
+#define IXGBE_ATLASCTL_WRITE_CMD 0x00010000
+#define IXGBE_ATLAS_PDN_TX_REG_EN 0x10
+#define IXGBE_ATLAS_PDN_TX_10G_QL_ALL 0xF0
+#define IXGBE_ATLAS_PDN_TX_1G_QL_ALL 0xF0
+#define IXGBE_ATLAS_PDN_TX_AN_QL_ALL 0xF0
+
+/* Device Type definitions for new protocol MDIO commands */
+#define IXGBE_MDIO_PMA_PMD_DEV_TYPE 0x1
+#define IXGBE_MDIO_PCS_DEV_TYPE 0x3
+#define IXGBE_MDIO_PHY_XS_DEV_TYPE 0x4
+#define IXGBE_MDIO_AUTO_NEG_DEV_TYPE 0x7
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE 0x1E /* Device 30 */
+
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL 0x0 /* VS1 Control Reg */
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS 0x1 /* VS1 Status Reg */
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS 0x0008 /* 1 = Link Up */
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS 0x0010 /* 0 - 10G, 1 - 1G */
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_10G_SPEED 0x0018
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_1G_SPEED 0x0010
+
+#define IXGBE_MDIO_AUTO_NEG_CONTROL 0x0 /* AUTO_NEG Control Reg */
+#define IXGBE_MDIO_AUTO_NEG_STATUS 0x1 /* AUTO_NEG Status Reg */
+#define IXGBE_MDIO_PHY_XS_CONTROL 0x0 /* PHY_XS Control Reg */
+#define IXGBE_MDIO_PHY_XS_RESET 0x8000 /* PHY_XS Reset */
+#define IXGBE_MDIO_PHY_ID_HIGH 0x2 /* PHY ID High Reg*/
+#define IXGBE_MDIO_PHY_ID_LOW 0x3 /* PHY ID Low Reg*/
+#define IXGBE_MDIO_PHY_SPEED_ABILITY 0x4 /* Speed Abilty Reg */
+#define IXGBE_MDIO_PHY_SPEED_10G 0x0001 /* 10G capable */
+#define IXGBE_MDIO_PHY_SPEED_1G 0x0010 /* 1G capable */
+
+#define IXGBE_PHY_REVISION_MASK 0xFFFFFFF0
+#define IXGBE_MAX_PHY_ADDR 32
+
+/* PHY IDs*/
+#define TN1010_PHY_ID 0x00A19410
+#define QT2022_PHY_ID 0x0043A400
+
+/* General purpose Interrupt Enable */
+#define IXGBE_GPIE_MSIX_MODE 0x00000010 /* MSI-X mode */
+#define IXGBE_GPIE_OCD 0x00000020 /* Other Clear Disable */
+#define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */
+#define IXGBE_GPIE_EIAME 0x40000000
+#define IXGBE_GPIE_PBA_SUPPORT 0x80000000
+
+/* Transmit Flow Control status */
+#define IXGBE_TFCS_TXOFF 0x00000001
+#define IXGBE_TFCS_TXOFF0 0x00000100
+#define IXGBE_TFCS_TXOFF1 0x00000200
+#define IXGBE_TFCS_TXOFF2 0x00000400
+#define IXGBE_TFCS_TXOFF3 0x00000800
+#define IXGBE_TFCS_TXOFF4 0x00001000
+#define IXGBE_TFCS_TXOFF5 0x00002000
+#define IXGBE_TFCS_TXOFF6 0x00004000
+#define IXGBE_TFCS_TXOFF7 0x00008000
+
+/* TCP Timer */
+#define IXGBE_TCPTIMER_KS 0x00000100
+#define IXGBE_TCPTIMER_COUNT_ENABLE 0x00000200
+#define IXGBE_TCPTIMER_COUNT_FINISH 0x00000400
+#define IXGBE_TCPTIMER_LOOP 0x00000800
+#define IXGBE_TCPTIMER_DURATION_MASK 0x000000FF
+
+/* HLREG0 Bit Masks */
+#define IXGBE_HLREG0_TXCRCEN 0x00000001 /* bit 0 */
+#define IXGBE_HLREG0_RXCRCSTRP 0x00000002 /* bit 1 */
+#define IXGBE_HLREG0_JUMBOEN 0x00000004 /* bit 2 */
+#define IXGBE_HLREG0_TXPADEN 0x00000400 /* bit 10 */
+#define IXGBE_HLREG0_TXPAUSEEN 0x00001000 /* bit 12 */
+#define IXGBE_HLREG0_RXPAUSEEN 0x00004000 /* bit 14 */
+#define IXGBE_HLREG0_LPBK 0x00008000 /* bit 15 */
+#define IXGBE_HLREG0_MDCSPD 0x00010000 /* bit 16 */
+#define IXGBE_HLREG0_CONTMDC 0x00020000 /* bit 17 */
+#define IXGBE_HLREG0_CTRLFLTR 0x00040000 /* bit 18 */
+#define IXGBE_HLREG0_PREPEND 0x00F00000 /* bits 20-23 */
+#define IXGBE_HLREG0_PRIPAUSEEN 0x01000000 /* bit 24 */
+#define IXGBE_HLREG0_RXPAUSERECDA 0x06000000 /* bits 25-26 */
+#define IXGBE_HLREG0_RXLNGTHERREN 0x08000000 /* bit 27 */
+#define IXGBE_HLREG0_RXPADSTRIPEN 0x10000000 /* bit 28 */
+
+/* VMD_CTL bitmasks */
+#define IXGBE_VMD_CTL_VMDQ_EN 0x00000001
+#define IXGBE_VMD_CTL_VMDQ_FILTER 0x00000002
+
+/* RDHMPN and TDHMPN bitmasks */
+#define IXGBE_RDHMPN_RDICADDR 0x007FF800
+#define IXGBE_RDHMPN_RDICRDREQ 0x00800000
+#define IXGBE_RDHMPN_RDICADDR_SHIFT 11
+#define IXGBE_TDHMPN_TDICADDR 0x003FF800
+#define IXGBE_TDHMPN_TDICRDREQ 0x00800000
+#define IXGBE_TDHMPN_TDICADDR_SHIFT 11
+
+/* Receive Checksum Control */
+#define IXGBE_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */
+#define IXGBE_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */
+
+/* FCRTL Bit Masks */
+#define IXGBE_FCRTL_XONE 0x80000000 /* bit 31, XON enable */
+#define IXGBE_FCRTH_FCEN 0x80000000 /* Rx Flow control enable */
+
+/* PAP bit masks*/
+#define IXGBE_PAP_TXPAUSECNT_MASK 0x0000FFFF /* Pause counter mask */
+
+/* RMCS Bit Masks */
+#define IXGBE_RMCS_RRM 0x00000002 /* Receive Recylce Mode enable */
+/* Receive Arbitration Control: 0 Round Robin, 1 DFP */
+#define IXGBE_RMCS_RAC 0x00000004
+#define IXGBE_RMCS_DFP IXGBE_RMCS_RAC /* Deficit Fixed Priority ena */
+#define IXGBE_RMCS_TFCE_802_3X 0x00000008 /* Tx Priority flow control ena */
+#define IXGBE_RMCS_TFCE_PRIORITY 0x00000010 /* Tx Priority flow control ena */
+#define IXGBE_RMCS_ARBDIS 0x00000040 /* Arbitration disable bit */
+
+/* Interrupt register bitmasks */
+
+/* Extended Interrupt Cause Read */
+#define IXGBE_EICR_RTX_QUEUE 0x0000FFFF /* RTx Queue Interrupt */
+#define IXGBE_EICR_LSC 0x00100000 /* Link Status Change */
+#define IXGBE_EICR_MNG 0x00400000 /* Managability Event Interrupt */
+#define IXGBE_EICR_PBUR 0x10000000 /* Packet Buffer Handler Error */
+#define IXGBE_EICR_DHER 0x20000000 /* Descriptor Handler Error */
+#define IXGBE_EICR_TCP_TIMER 0x40000000 /* TCP Timer */
+#define IXGBE_EICR_OTHER 0x80000000 /* Interrupt Cause Active */
+
+/* Extended Interrupt Cause Set */
+#define IXGBE_EICS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EICS_LSC IXGBE_EICR_LSC /* Link Status Change */
+#define IXGBE_EICR_GPI_SDP0 0x01000000 /* Gen Purpose Interrupt on SDP0 */
+#define IXGBE_EICS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */
+#define IXGBE_EICS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */
+#define IXGBE_EICS_DHER IXGBE_EICR_DHER /* Desc Handler Error */
+#define IXGBE_EICS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */
+#define IXGBE_EICS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */
+
+/* Extended Interrupt Mask Set */
+#define IXGBE_EIMS_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EIMS_LSC IXGBE_EICR_LSC /* Link Status Change */
+#define IXGBE_EIMS_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */
+#define IXGBE_EIMS_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */
+#define IXGBE_EIMS_DHER IXGBE_EICR_DHER /* Descr Handler Error */
+#define IXGBE_EIMS_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */
+#define IXGBE_EIMS_OTHER IXGBE_EICR_OTHER /* INT Cause Active */
+
+/* Extended Interrupt Mask Clear */
+#define IXGBE_EIMC_RTX_QUEUE IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EIMC_LSC IXGBE_EICR_LSC /* Link Status Change */
+#define IXGBE_EIMC_MNG IXGBE_EICR_MNG /* MNG Event Interrupt */
+#define IXGBE_EIMC_PBUR IXGBE_EICR_PBUR /* Pkt Buf Handler Error */
+#define IXGBE_EIMC_DHER IXGBE_EICR_DHER /* Desc Handler Error */
+#define IXGBE_EIMC_TCP_TIMER IXGBE_EICR_TCP_TIMER /* TCP Timer */
+#define IXGBE_EIMC_OTHER IXGBE_EICR_OTHER /* INT Cause Active */
+
+#define IXGBE_EIMS_ENABLE_MASK (\
+ IXGBE_EIMS_RTX_QUEUE | \
+ IXGBE_EIMS_LSC | \
+ IXGBE_EIMS_TCP_TIMER | \
+ IXGBE_EIMS_OTHER)
+
+/* Immediate Interrupt RX (A.K.A. Low Latency Interrupt) */
+#define IXGBE_IMIR_PORT_IM_EN 0x00010000 /* TCP port enable */
+#define IXGBE_IMIR_PORT_BP 0x00020000 /* TCP port check bypass */
+#define IXGBE_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */
+#define IXGBE_IMIREXT_CTRL_URG 0x00002000 /* Check URG bit in header */
+#define IXGBE_IMIREXT_CTRL_ACK 0x00004000 /* Check ACK bit in header */
+#define IXGBE_IMIREXT_CTRL_PSH 0x00008000 /* Check PSH bit in header */
+#define IXGBE_IMIREXT_CTRL_RST 0x00010000 /* Check RST bit in header */
+#define IXGBE_IMIREXT_CTRL_SYN 0x00020000 /* Check SYN bit in header */
+#define IXGBE_IMIREXT_CTRL_FIN 0x00040000 /* Check FIN bit in header */
+#define IXGBE_IMIREXT_CTRL_BP 0x00080000 /* Bypass check of control bits */
+
+/* Interrupt clear mask */
+#define IXGBE_IRQ_CLEAR_MASK 0xFFFFFFFF
+
+/* Interrupt Vector Allocation Registers */
+#define IXGBE_IVAR_REG_NUM 25
+#define IXGBE_IVAR_TXRX_ENTRY 96
+#define IXGBE_IVAR_RX_ENTRY 64
+#define IXGBE_IVAR_RX_QUEUE(_i) (0 + (_i))
+#define IXGBE_IVAR_TX_QUEUE(_i) (64 + (_i))
+#define IXGBE_IVAR_TX_ENTRY 32
+
+#define IXGBE_IVAR_TCP_TIMER_INDEX 96 /* 0 based index */
+#define IXGBE_IVAR_OTHER_CAUSES_INDEX 97 /* 0 based index */
+
+#define IXGBE_MSIX_VECTOR(_i) (0 + (_i))
+
+#define IXGBE_IVAR_ALLOC_VAL 0x80 /* Interrupt Allocation valid */
+
+/* VLAN Control Bit Masks */
+#define IXGBE_VLNCTRL_VET 0x0000FFFF /* bits 0-15 */
+#define IXGBE_VLNCTRL_CFI 0x10000000 /* bit 28 */
+#define IXGBE_VLNCTRL_CFIEN 0x20000000 /* bit 29 */
+#define IXGBE_VLNCTRL_VFE 0x40000000 /* bit 30 */
+#define IXGBE_VLNCTRL_VME 0x80000000 /* bit 31 */
+
+#define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.1q protocol */
+
+/* STATUS Bit Masks */
+#define IXGBE_STATUS_LAN_ID 0x0000000C /* LAN ID */
+#define IXGBE_STATUS_GIO 0x00080000 /* GIO Master Enable Status */
+
+#define IXGBE_STATUS_LAN_ID_0 0x00000000 /* LAN ID 0 */
+#define IXGBE_STATUS_LAN_ID_1 0x00000004 /* LAN ID 1 */
+
+/* ESDP Bit Masks */
+#define IXGBE_ESDP_SDP4 0x00000001 /* SDP4 Data Value */
+#define IXGBE_ESDP_SDP5 0x00000002 /* SDP5 Data Value */
+#define IXGBE_ESDP_SDP4_DIR 0x00000004 /* SDP4 IO direction */
+#define IXGBE_ESDP_SDP5_DIR 0x00000008 /* SDP5 IO direction */
+
+/* LEDCTL Bit Masks */
+#define IXGBE_LED_IVRT_BASE 0x00000040
+#define IXGBE_LED_BLINK_BASE 0x00000080
+#define IXGBE_LED_MODE_MASK_BASE 0x0000000F
+#define IXGBE_LED_OFFSET(_base, _i) (_base << (8 * (_i)))
+#define IXGBE_LED_MODE_SHIFT(_i) (8*(_i))
+#define IXGBE_LED_IVRT(_i) IXGBE_LED_OFFSET(IXGBE_LED_IVRT_BASE, _i)
+#define IXGBE_LED_BLINK(_i) IXGBE_LED_OFFSET(IXGBE_LED_BLINK_BASE, _i)
+#define IXGBE_LED_MODE_MASK(_i) IXGBE_LED_OFFSET(IXGBE_LED_MODE_MASK_BASE, _i)
+
+/* LED modes */
+#define IXGBE_LED_LINK_UP 0x0
+#define IXGBE_LED_LINK_10G 0x1
+#define IXGBE_LED_MAC 0x2
+#define IXGBE_LED_FILTER 0x3
+#define IXGBE_LED_LINK_ACTIVE 0x4
+#define IXGBE_LED_LINK_1G 0x5
+#define IXGBE_LED_ON 0xE
+#define IXGBE_LED_OFF 0xF
+
+/* AUTOC Bit Masks */
+#define IXGBE_AUTOC_KX4_SUPP 0x80000000
+#define IXGBE_AUTOC_KX_SUPP 0x40000000
+#define IXGBE_AUTOC_PAUSE 0x30000000
+#define IXGBE_AUTOC_RF 0x08000000
+#define IXGBE_AUTOC_PD_TMR 0x06000000
+#define IXGBE_AUTOC_AN_RX_LOOSE 0x01000000
+#define IXGBE_AUTOC_AN_RX_DRIFT 0x00800000
+#define IXGBE_AUTOC_AN_RX_ALIGN 0x007C0000
+#define IXGBE_AUTOC_AN_RESTART 0x00001000
+#define IXGBE_AUTOC_FLU 0x00000001
+#define IXGBE_AUTOC_LMS_SHIFT 13
+#define IXGBE_AUTOC_LMS_MASK (0x7 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_1G_LINK_NO_AN (0x0 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_10G_LINK_NO_AN (0x1 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_1G_AN (0x2 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_KX4_AN (0x4 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_KX4_AN_1G_AN (0x6 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_ATTACH_TYPE (0x7 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
+
+#define IXGBE_AUTOC_1G_PMA_PMD 0x00000200
+#define IXGBE_AUTOC_10G_PMA_PMD 0x00000180
+#define IXGBE_AUTOC_10G_PMA_PMD_SHIFT 7
+#define IXGBE_AUTOC_1G_PMA_PMD_SHIFT 9
+#define IXGBE_AUTOC_10G_XAUI (0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_10G_KX4 (0x1 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_10G_CX4 (0x2 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_1G_BX (0x0 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_1G_KX (0x1 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT)
+
+/* LINKS Bit Masks */
+#define IXGBE_LINKS_KX_AN_COMP 0x80000000
+#define IXGBE_LINKS_UP 0x40000000
+#define IXGBE_LINKS_SPEED 0x20000000
+#define IXGBE_LINKS_MODE 0x18000000
+#define IXGBE_LINKS_RX_MODE 0x06000000
+#define IXGBE_LINKS_TX_MODE 0x01800000
+#define IXGBE_LINKS_XGXS_EN 0x00400000
+#define IXGBE_LINKS_PCS_1G_EN 0x00200000
+#define IXGBE_LINKS_1G_AN_EN 0x00100000
+#define IXGBE_LINKS_KX_AN_IDLE 0x00080000
+#define IXGBE_LINKS_1G_SYNC 0x00040000
+#define IXGBE_LINKS_10G_ALIGN 0x00020000
+#define IXGBE_LINKS_10G_LANE_SYNC 0x00017000
+#define IXGBE_LINKS_TL_FAULT 0x00001000
+#define IXGBE_LINKS_SIGNAL 0x00000F00
+
+#define IXGBE_AUTO_NEG_TIME 45 /* 4.5 Seconds */
+
+/* SW Semaphore Register bitmasks */
+#define IXGBE_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
+#define IXGBE_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
+#define IXGBE_SWSM_WMNG 0x00000004 /* Wake MNG Clock */
+
+/* GSSR definitions */
+#define IXGBE_GSSR_EEP_SM 0x0001
+#define IXGBE_GSSR_PHY0_SM 0x0002
+#define IXGBE_GSSR_PHY1_SM 0x0004
+#define IXGBE_GSSR_MAC_CSR_SM 0x0008
+#define IXGBE_GSSR_FLASH_SM 0x0010
+
+/* EEC Register */
+#define IXGBE_EEC_SK 0x00000001 /* EEPROM Clock */
+#define IXGBE_EEC_CS 0x00000002 /* EEPROM Chip Select */
+#define IXGBE_EEC_DI 0x00000004 /* EEPROM Data In */
+#define IXGBE_EEC_DO 0x00000008 /* EEPROM Data Out */
+#define IXGBE_EEC_FWE_MASK 0x00000030 /* FLASH Write Enable */
+#define IXGBE_EEC_FWE_DIS 0x00000010 /* Disable FLASH writes */
+#define IXGBE_EEC_FWE_EN 0x00000020 /* Enable FLASH writes */
+#define IXGBE_EEC_FWE_SHIFT 4
+#define IXGBE_EEC_REQ 0x00000040 /* EEPROM Access Request */
+#define IXGBE_EEC_GNT 0x00000080 /* EEPROM Access Grant */
+#define IXGBE_EEC_PRES 0x00000100 /* EEPROM Present */
+#define IXGBE_EEC_ARD 0x00000200 /* EEPROM Auto Read Done */
+/* EEPROM Addressing bits based on type (0-small, 1-large) */
+#define IXGBE_EEC_ADDR_SIZE 0x00000400
+#define IXGBE_EEC_SIZE 0x00007800 /* EEPROM Size */
+
+#define IXGBE_EEC_SIZE_SHIFT 11
+#define IXGBE_EEPROM_WORD_SIZE_SHIFT 6
+#define IXGBE_EEPROM_OPCODE_BITS 8
+
+/* Checksum and EEPROM pointers */
+#define IXGBE_EEPROM_CHECKSUM 0x3F
+#define IXGBE_EEPROM_SUM 0xBABA
+#define IXGBE_PCIE_ANALOG_PTR 0x03
+#define IXGBE_ATLAS0_CONFIG_PTR 0x04
+#define IXGBE_ATLAS1_CONFIG_PTR 0x05
+#define IXGBE_PCIE_GENERAL_PTR 0x06
+#define IXGBE_PCIE_CONFIG0_PTR 0x07
+#define IXGBE_PCIE_CONFIG1_PTR 0x08
+#define IXGBE_CORE0_PTR 0x09
+#define IXGBE_CORE1_PTR 0x0A
+#define IXGBE_MAC0_PTR 0x0B
+#define IXGBE_MAC1_PTR 0x0C
+#define IXGBE_CSR0_CONFIG_PTR 0x0D
+#define IXGBE_CSR1_CONFIG_PTR 0x0E
+#define IXGBE_FW_PTR 0x0F
+#define IXGBE_PBANUM0_PTR 0x15
+#define IXGBE_PBANUM1_PTR 0x16
+
+/* EEPROM Commands - SPI */
+#define IXGBE_EEPROM_MAX_RETRY_SPI 5000 /* Max wait 5ms for RDY signal */
+#define IXGBE_EEPROM_STATUS_RDY_SPI 0x01
+#define IXGBE_EEPROM_READ_OPCODE_SPI 0x03 /* EEPROM read opcode */
+#define IXGBE_EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */
+#define IXGBE_EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = addr bit-8 */
+#define IXGBE_EEPROM_WREN_OPCODE_SPI 0x06 /* EEPROM set Write Ena latch */
+/* EEPROM reset Write Enbale latch */
+#define IXGBE_EEPROM_WRDI_OPCODE_SPI 0x04
+#define IXGBE_EEPROM_RDSR_OPCODE_SPI 0x05 /* EEPROM read Status reg */
+#define IXGBE_EEPROM_WRSR_OPCODE_SPI 0x01 /* EEPROM write Status reg */
+#define IXGBE_EEPROM_ERASE4K_OPCODE_SPI 0x20 /* EEPROM ERASE 4KB */
+#define IXGBE_EEPROM_ERASE64K_OPCODE_SPI 0xD8 /* EEPROM ERASE 64KB */
+#define IXGBE_EEPROM_ERASE256_OPCODE_SPI 0xDB /* EEPROM ERASE 256B */
+
+/* EEPROM Read Register */
+#define IXGBE_EEPROM_READ_REG_DATA 16 /* data offset in EEPROM read reg */
+#define IXGBE_EEPROM_READ_REG_DONE 2 /* Offset to READ done bit */
+#define IXGBE_EEPROM_READ_REG_START 1 /* First bit to start operation */
+#define IXGBE_EEPROM_READ_ADDR_SHIFT 2 /* Shift to the address bits */
+
+#define IXGBE_ETH_LENGTH_OF_ADDRESS 6
+
+#ifndef IXGBE_EEPROM_GRANT_ATTEMPTS
+#define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
+#endif
+
+#ifndef IXGBE_EERD_ATTEMPTS
+/* Number of 5 microseconds we wait for EERD read to complete */
+#define IXGBE_EERD_ATTEMPTS 100000
+#endif
+
+/* PCI Bus Info */
+#define IXGBE_PCI_LINK_STATUS 0xB2
+#define IXGBE_PCI_LINK_WIDTH 0x3F0
+#define IXGBE_PCI_LINK_WIDTH_1 0x10
+#define IXGBE_PCI_LINK_WIDTH_2 0x20
+#define IXGBE_PCI_LINK_WIDTH_4 0x40
+#define IXGBE_PCI_LINK_WIDTH_8 0x80
+#define IXGBE_PCI_LINK_SPEED 0xF
+#define IXGBE_PCI_LINK_SPEED_2500 0x1
+#define IXGBE_PCI_LINK_SPEED_5000 0x2
+
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800
+
+/* PHY Types */
+#define IXGBE_M88E1145_E_PHY_ID 0x01410CD0
+
+/* Check whether address is multicast. This is little-endian specific check.*/
+#define IXGBE_IS_MULTICAST(Address) \
+ (bool)(((u8 *)(Address))[0] & ((u8)0x01))
+
+/* Check whether an address is broadcast. */
+#define IXGBE_IS_BROADCAST(Address) \
+ ((((u8 *)(Address))[0] == ((u8)0xff)) && \
+ (((u8 *)(Address))[1] == ((u8)0xff)))
+
+/* RAH */
+#define IXGBE_RAH_VIND_MASK 0x003C0000
+#define IXGBE_RAH_VIND_SHIFT 18
+#define IXGBE_RAH_AV 0x80000000
+
+/* Filters */
+#define IXGBE_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */
+#define IXGBE_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
+
+/* Header split receive */
+#define IXGBE_RFCTL_ISCSI_DIS 0x00000001
+#define IXGBE_RFCTL_ISCSI_DWC_MASK 0x0000003E
+#define IXGBE_RFCTL_ISCSI_DWC_SHIFT 1
+#define IXGBE_RFCTL_NFSW_DIS 0x00000040
+#define IXGBE_RFCTL_NFSR_DIS 0x00000080
+#define IXGBE_RFCTL_NFS_VER_MASK 0x00000300
+#define IXGBE_RFCTL_NFS_VER_SHIFT 8
+#define IXGBE_RFCTL_NFS_VER_2 0
+#define IXGBE_RFCTL_NFS_VER_3 1
+#define IXGBE_RFCTL_NFS_VER_4 2
+#define IXGBE_RFCTL_IPV6_DIS 0x00000400
+#define IXGBE_RFCTL_IPV6_XSUM_DIS 0x00000800
+#define IXGBE_RFCTL_IPFRSP_DIS 0x00004000
+#define IXGBE_RFCTL_IPV6_EX_DIS 0x00010000
+#define IXGBE_RFCTL_NEW_IPV6_EXT_DIS 0x00020000
+
+/* Transmit Config masks */
+#define IXGBE_TXDCTL_ENABLE 0x02000000 /* Enable specific Tx Queue */
+#define IXGBE_TXDCTL_SWFLSH 0x04000000 /* Tx Desc. write-back flushing */
+/* Enable short packet padding to 64 bytes */
+#define IXGBE_TX_PAD_ENABLE 0x00000400
+#define IXGBE_JUMBO_FRAME_ENABLE 0x00000004 /* Allow jumbo frames */
+/* This allows for 16K packets + 4k for vlan */
+#define IXGBE_MAX_FRAME_SZ 0x40040000
+
+#define IXGBE_TDWBAL_HEAD_WB_ENABLE 0x1 /* Tx head write-back enable */
+#define IXGBE_TDWBAL_SEQNUM_WB_ENABLE 0x2 /* Tx seq. # write-back enable */
+
+/* Receive Config masks */
+#define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */
+#define IXGBE_RXCTRL_DMBYPS 0x00000002 /* Descriptor Monitor Bypass */
+#define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */
+
+#define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */
+#define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/
+#define IXGBE_FCTRL_UPE 0x00000200 /* Unicast Promiscuous Ena */
+#define IXGBE_FCTRL_BAM 0x00000400 /* Broadcast Accept Mode */
+#define IXGBE_FCTRL_PMCF 0x00001000 /* Pass MAC Control Frames */
+#define IXGBE_FCTRL_DPF 0x00002000 /* Discard Pause Frame */
+/* Receive Priority Flow Control Enbale */
+#define IXGBE_FCTRL_RPFCE 0x00004000
+#define IXGBE_FCTRL_RFCE 0x00008000 /* Receive Flow Control Ena */
+
+/* Multiple Receive Queue Control */
+#define IXGBE_MRQC_RSSEN 0x00000001 /* RSS Enable */
+#define IXGBE_MRQC_RSS_FIELD_MASK 0xFFFF0000
+#define IXGBE_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
+#define IXGBE_MRQC_RSS_FIELD_IPV4 0x00020000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP 0x00040000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_EX 0x00080000
+#define IXGBE_MRQC_RSS_FIELD_IPV6 0x00100000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_TCP 0x00200000
+#define IXGBE_MRQC_RSS_FIELD_IPV4_UDP 0x00400000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_UDP 0x00800000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP 0x01000000
+
+#define IXGBE_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */
+#define IXGBE_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */
+#define IXGBE_TXD_CMD_EOP 0x01000000 /* End of Packet */
+#define IXGBE_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */
+#define IXGBE_TXD_CMD_IC 0x04000000 /* Insert Checksum */
+#define IXGBE_TXD_CMD_RS 0x08000000 /* Report Status */
+#define IXGBE_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */
+#define IXGBE_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */
+#define IXGBE_TXD_STAT_DD 0x00000001 /* Descriptor Done */
+
+/* Receive Descriptor bit definitions */
+#define IXGBE_RXD_STAT_DD 0x01 /* Descriptor Done */
+#define IXGBE_RXD_STAT_EOP 0x02 /* End of Packet */
+#define IXGBE_RXD_STAT_IXSM 0x04 /* Ignore checksum */
+#define IXGBE_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */
+#define IXGBE_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */
+#define IXGBE_RXD_STAT_L4CS 0x20 /* L4 xsum calculated */
+#define IXGBE_RXD_STAT_IPCS 0x40 /* IP xsum calculated */
+#define IXGBE_RXD_STAT_PIF 0x80 /* passed in-exact filter */
+#define IXGBE_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */
+#define IXGBE_RXD_STAT_VEXT 0x200 /* 1st VLAN found */
+#define IXGBE_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */
+#define IXGBE_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */
+#define IXGBE_RXD_STAT_ACK 0x8000 /* ACK Packet indication */
+#define IXGBE_RXD_ERR_CE 0x01 /* CRC Error */
+#define IXGBE_RXD_ERR_LE 0x02 /* Length Error */
+#define IXGBE_RXD_ERR_PE 0x08 /* Packet Error */
+#define IXGBE_RXD_ERR_OSE 0x10 /* Oversize Error */
+#define IXGBE_RXD_ERR_USE 0x20 /* Undersize Error */
+#define IXGBE_RXD_ERR_TCPE 0x40 /* TCP/UDP Checksum Error */
+#define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */
+#define IXGBE_RXDADV_HBO 0x00800000
+#define IXGBE_RXDADV_ERR_CE 0x01000000 /* CRC Error */
+#define IXGBE_RXDADV_ERR_LE 0x02000000 /* Length Error */
+#define IXGBE_RXDADV_ERR_PE 0x08000000 /* Packet Error */
+#define IXGBE_RXDADV_ERR_OSE 0x10000000 /* Oversize Error */
+#define IXGBE_RXDADV_ERR_USE 0x20000000 /* Undersize Error */
+#define IXGBE_RXDADV_ERR_TCPE 0x40000000 /* TCP/UDP Checksum Error */
+#define IXGBE_RXDADV_ERR_IPE 0x80000000 /* IP Checksum Error */
+#define IXGBE_RXD_VLAN_ID_MASK 0x0FFF /* VLAN ID is in lower 12 bits */
+#define IXGBE_RXD_PRI_MASK 0xE000 /* Priority is in upper 3 bits */
+#define IXGBE_RXD_PRI_SHIFT 13
+#define IXGBE_RXD_CFI_MASK 0x1000 /* CFI is bit 12 */
+#define IXGBE_RXD_CFI_SHIFT 12
+
+/* SRRCTL bit definitions */
+#define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10 /* so many KBs */
+#define IXGBE_SRRCTL_BSIZEPKT_MASK 0x0000007F
+#define IXGBE_SRRCTL_BSIZEHDR_MASK 0x00003F00
+#define IXGBE_SRRCTL_DESCTYPE_LEGACY 0x00000000
+#define IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
+
+#define IXGBE_RXDPS_HDRSTAT_HDRSP 0x00008000
+#define IXGBE_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF
+
+#define IXGBE_RXDADV_RSSTYPE_MASK 0x0000000F
+#define IXGBE_RXDADV_PKTTYPE_MASK 0x0000FFF0
+#define IXGBE_RXDADV_HDRBUFLEN_MASK 0x00007FE0
+#define IXGBE_RXDADV_HDRBUFLEN_SHIFT 5
+#define IXGBE_RXDADV_SPLITHEADER_EN 0x00001000
+#define IXGBE_RXDADV_SPH 0x8000
+
+/* RSS Hash results */
+#define IXGBE_RXDADV_RSSTYPE_NONE 0x00000000
+#define IXGBE_RXDADV_RSSTYPE_IPV4_TCP 0x00000001
+#define IXGBE_RXDADV_RSSTYPE_IPV4 0x00000002
+#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP 0x00000003
+#define IXGBE_RXDADV_RSSTYPE_IPV6_EX 0x00000004
+#define IXGBE_RXDADV_RSSTYPE_IPV6 0x00000005
+#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006
+#define IXGBE_RXDADV_RSSTYPE_IPV4_UDP 0x00000007
+#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP 0x00000008
+#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009
+
+/* RSS Packet Types as indicated in the receive descriptor. */
+#define IXGBE_RXDADV_PKTTYPE_NONE 0x00000000
+#define IXGBE_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPv4 hdr present */
+#define IXGBE_RXDADV_PKTTYPE_IPV4_EX 0x00000020 /* IPv4 hdr + extensions */
+#define IXGBE_RXDADV_PKTTYPE_IPV6 0x00000040 /* IPv6 hdr present */
+#define IXGBE_RXDADV_PKTTYPE_IPV6_EX 0x00000080 /* IPv6 hdr + extensions */
+#define IXGBE_RXDADV_PKTTYPE_TCP 0x00000100 /* TCP hdr present */
+#define IXGBE_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */
+#define IXGBE_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */
+#define IXGBE_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */
+
+/* Masks to determine if packets should be dropped due to frame errors */
+#define IXGBE_RXD_ERR_FRAME_ERR_MASK (\
+ IXGBE_RXD_ERR_CE | \
+ IXGBE_RXD_ERR_LE | \
+ IXGBE_RXD_ERR_PE | \
+ IXGBE_RXD_ERR_OSE | \
+ IXGBE_RXD_ERR_USE)
+
+#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK (\
+ IXGBE_RXDADV_ERR_CE | \
+ IXGBE_RXDADV_ERR_LE | \
+ IXGBE_RXDADV_ERR_PE | \
+ IXGBE_RXDADV_ERR_OSE | \
+ IXGBE_RXDADV_ERR_USE)
+
+/* Multicast bit mask */
+#define IXGBE_MCSTCTRL_MFE 0x4
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE 8
+#define IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE 8
+#define IXGBE_REQ_TX_BUFFER_GRANULARITY 1024
+
+/* Vlan-specific macros */
+#define IXGBE_RX_DESC_SPECIAL_VLAN_MASK 0x0FFF /* VLAN ID in lower 12 bits */
+#define IXGBE_RX_DESC_SPECIAL_PRI_MASK 0xE000 /* Priority in upper 3 bits */
+#define IXGBE_RX_DESC_SPECIAL_PRI_SHIFT 0x000D /* Priority in upper 3 of 16 */
+#define IXGBE_TX_DESC_SPECIAL_PRI_SHIFT IXGBE_RX_DESC_SPECIAL_PRI_SHIFT
+
+/* Transmit Descriptor - Legacy */
+struct ixgbe_legacy_tx_desc {
+ u64 buffer_addr; /* Address of the descriptor's data buffer */
+ union {
+ u32 data;
+ struct {
+ u16 length; /* Data buffer length */
+ u8 cso; /* Checksum offset */
+ u8 cmd; /* Descriptor control */
+ } flags;
+ } lower;
+ union {
+ u32 data;
+ struct {
+ u8 status; /* Descriptor status */
+ u8 css; /* Checksum start */
+ u16 vlan;
+ } fields;
+ } upper;
+};
+
+/* Transmit Descriptor - Advanced */
+union ixgbe_adv_tx_desc {
+ struct {
+ u64 buffer_addr; /* Address of descriptor's data buf */
+ u32 cmd_type_len;
+ u32 olinfo_status;
+ } read;
+ struct {
+ u64 rsvd; /* Reserved */
+ u32 nxtseq_seed;
+ u32 status;
+ } wb;
+};
+
+/* Receive Descriptor - Legacy */
+struct ixgbe_legacy_rx_desc {
+ u64 buffer_addr; /* Address of the descriptor's data buffer */
+ u16 length; /* Length of data DMAed into data buffer */
+ u16 csum; /* Packet checksum */
+ u8 status; /* Descriptor status */
+ u8 errors; /* Descriptor Errors */
+ u16 vlan;
+};
+
+/* Receive Descriptor - Advanced */
+union ixgbe_adv_rx_desc {
+ struct {
+ u64 pkt_addr; /* Packet buffer address */
+ u64 hdr_addr; /* Header buffer address */
+ } read;
+ struct {
+ struct {
+ struct {
+ u16 pkt_info; /* RSS type, Packet type */
+ u16 hdr_info; /* Split Header, header len */
+ } lo_dword;
+ union {
+ u32 rss; /* RSS Hash */
+ struct {
+ u16 ip_id; /* IP id */
+ u16 csum; /* Packet Checksum */
+ } csum_ip;
+ } hi_dword;
+ } lower;
+ struct {
+ u32 status_error; /* ext status/error */
+ u16 length; /* Packet length */
+ u16 vlan; /* VLAN tag */
+ } upper;
+ } wb; /* writeback */
+};
+
+/* Context descriptors */
+struct ixgbe_adv_tx_context_desc {
+ u32 vlan_macip_lens;
+ u32 seqnum_seed;
+ u32 type_tucmd_mlhl;
+ u32 mss_l4len_idx;
+};
+
+/* Adv Transmit Descriptor Config Masks */
+#define IXGBE_ADVTXD_DTALEN_MASK 0x0000FFFF /* Data buffer length(bytes) */
+#define IXGBE_ADVTXD_DTYP_MASK 0x00F00000 /* DTYP mask */
+#define IXGBE_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Desc */
+#define IXGBE_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */
+#define IXGBE_ADVTXD_DCMD_EOP IXGBE_TXD_CMD_EOP /* End of Packet */
+#define IXGBE_ADVTXD_DCMD_IFCS IXGBE_TXD_CMD_IFCS /* Insert FCS */
+#define IXGBE_ADVTXD_DCMD_RDMA 0x04000000 /* RDMA */
+#define IXGBE_ADVTXD_DCMD_RS IXGBE_TXD_CMD_RS /* Report Status */
+#define IXGBE_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000 /* DDP hdr type or iSCSI */
+#define IXGBE_ADVTXD_DCMD_DEXT IXGBE_TXD_CMD_DEXT /* Desc ext (1=Adv) */
+#define IXGBE_ADVTXD_DCMD_VLE IXGBE_TXD_CMD_VLE /* VLAN pkt enable */
+#define IXGBE_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */
+#define IXGBE_ADVTXD_STAT_DD IXGBE_TXD_STAT_DD /* Descriptor Done */
+#define IXGBE_ADVTXD_STAT_SN_CRC 0x00000002 /* NXTSEQ/SEED present in WB */
+#define IXGBE_ADVTXD_STAT_RSV 0x0000000C /* STA Reserved */
+#define IXGBE_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */
+#define IXGBE_ADVTXD_POPTS_SHIFT 8 /* Adv desc POPTS shift */
+#define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \
+ IXGBE_ADVTXD_POPTS_SHIFT)
+#define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \
+ IXGBE_ADVTXD_POPTS_SHIFT)
+#define IXGBE_ADVTXD_POPTS_EOM 0x00000400 /* Enable L bit-RDMA DDP hdr */
+#define IXGBE_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */
+#define IXGBE_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */
+#define IXGBE_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */
+#define IXGBE_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU*/
+#define IXGBE_ADVTXD_POPTS_RSV 0x00002000 /* POPTS Reserved */
+#define IXGBE_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */
+#define IXGBE_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */
+#define IXGBE_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */
+#define IXGBE_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */
+#define IXGBE_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */
+#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */
+#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */
+#define IXGBE_ADVTXD_TUCMD_MKRREQ 0x00002000 /* Req requires Markers and CRC */
+#define IXGBE_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */
+#define IXGBE_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */
+
+/* Link speed */
+#define IXGBE_LINK_SPEED_UNKNOWN 0
+#define IXGBE_LINK_SPEED_100_FULL 0x0008
+#define IXGBE_LINK_SPEED_1GB_FULL 0x0020
+#define IXGBE_LINK_SPEED_10GB_FULL 0x0080
+
+
+enum ixgbe_eeprom_type {
+ ixgbe_eeprom_uninitialized = 0,
+ ixgbe_eeprom_spi,
+ ixgbe_eeprom_none /* No NVM support */
+};
+
+enum ixgbe_mac_type {
+ ixgbe_mac_unknown = 0,
+ ixgbe_mac_82598EB,
+ ixgbe_num_macs
+};
+
+enum ixgbe_phy_type {
+ ixgbe_phy_unknown = 0,
+ ixgbe_phy_tn,
+ ixgbe_phy_qt,
+ ixgbe_phy_xaui
+};
+
+enum ixgbe_media_type {
+ ixgbe_media_type_unknown = 0,
+ ixgbe_media_type_fiber,
+ ixgbe_media_type_copper,
+ ixgbe_media_type_backplane
+};
+
+/* Flow Control Settings */
+enum ixgbe_fc_type {
+ ixgbe_fc_none = 0,
+ ixgbe_fc_rx_pause,
+ ixgbe_fc_tx_pause,
+ ixgbe_fc_full,
+ ixgbe_fc_default
+};
+
+struct ixgbe_addr_filter_info {
+ u32 num_mc_addrs;
+ u32 rar_used_count;
+ u32 mc_addr_in_rar_count;
+ u32 mta_in_use;
+};
+
+/* Flow control parameters */
+struct ixgbe_fc_info {
+ u32 high_water; /* Flow Control High-water */
+ u32 low_water; /* Flow Control Low-water */
+ u16 pause_time; /* Flow Control Pause timer */
+ bool send_xon; /* Flow control send XON */
+ bool strict_ieee; /* Strict IEEE mode */
+ enum ixgbe_fc_type type; /* Type of flow control */
+ enum ixgbe_fc_type original_type;
+};
+
+/* Statistics counters collected by the MAC */
+struct ixgbe_hw_stats {
+ u64 crcerrs;
+ u64 illerrc;
+ u64 errbc;
+ u64 mspdc;
+ u64 mpctotal;
+ u64 mpc[8];
+ u64 mlfc;
+ u64 mrfc;
+ u64 rlec;
+ u64 lxontxc;
+ u64 lxonrxc;
+ u64 lxofftxc;
+ u64 lxoffrxc;
+ u64 pxontxc[8];
+ u64 pxonrxc[8];
+ u64 pxofftxc[8];
+ u64 pxoffrxc[8];
+ u64 prc64;
+ u64 prc127;
+ u64 prc255;
+ u64 prc511;
+ u64 prc1023;
+ u64 prc1522;
+ u64 gprc;
+ u64 bprc;
+ u64 mprc;
+ u64 gptc;
+ u64 gorc;
+ u64 gotc;
+ u64 rnbc[8];
+ u64 ruc;
+ u64 rfc;
+ u64 roc;
+ u64 rjc;
+ u64 mngprc;
+ u64 mngpdc;
+ u64 mngptc;
+ u64 tor;
+ u64 tpr;
+ u64 tpt;
+ u64 ptc64;
+ u64 ptc127;
+ u64 ptc255;
+ u64 ptc511;
+ u64 ptc1023;
+ u64 ptc1522;
+ u64 mptc;
+ u64 bptc;
+ u64 xec;
+ u64 rqsmr[16];
+ u64 tqsmr[8];
+ u64 qprc[16];
+ u64 qptc[16];
+ u64 qbrc[16];
+ u64 qbtc[16];
+};
+
+/* forward declaration */
+struct ixgbe_hw;
+
+struct ixgbe_mac_operations {
+ s32 (*reset)(struct ixgbe_hw *);
+ enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *);
+};
+
+struct ixgbe_phy_operations {
+ s32 (*setup)(struct ixgbe_hw *);
+ s32 (*check)(struct ixgbe_hw *, u32 *, bool *);
+ s32 (*setup_speed)(struct ixgbe_hw *, u32, bool, bool);
+ s32 (*get_settings)(struct ixgbe_hw *, u32 *, bool *);
+};
+
+struct ixgbe_mac_info {
+ struct ixgbe_mac_operations ops;
+ enum ixgbe_mac_type type;
+ u8 addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
+ u8 perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
+ s32 mc_filter_type;
+ u32 num_rx_queues;
+ u32 num_tx_queues;
+ u32 num_rx_addrs;
+ u32 link_attach_type;
+ u32 link_mode_select;
+ bool link_settings_loaded;
+};
+
+
+struct ixgbe_eeprom_info {
+ enum ixgbe_eeprom_type type;
+ u16 word_size;
+ u16 address_bits;
+};
+
+struct ixgbe_phy_info {
+ struct ixgbe_phy_operations ops;
+
+ enum ixgbe_phy_type type;
+ u32 addr;
+ u32 id;
+ u32 revision;
+ enum ixgbe_media_type media_type;
+ u32 autoneg_advertised;
+ bool autoneg_wait_to_complete;
+};
+
+struct ixgbe_info {
+ enum ixgbe_mac_type mac;
+ s32 (*get_invariants)(struct ixgbe_hw *);
+ struct ixgbe_mac_operations *mac_ops;
+ struct ixgbe_phy_operations *phy_ops;
+};
+
+struct ixgbe_hw {
+ u8 __iomem *hw_addr;
+ void *back;
+ struct ixgbe_mac_info mac;
+ struct ixgbe_addr_filter_info addr_ctrl;
+ struct ixgbe_fc_info fc;
+ struct ixgbe_phy_info phy;
+ struct ixgbe_eeprom_info eeprom;
+ u16 device_id;
+ u16 vendor_id;
+ u16 subsystem_device_id;
+ u16 subsystem_vendor_id;
+ u8 revision_id;
+ bool adapter_stopped;
+};
+
+/* Error Codes */
+#define IXGBE_ERR_EEPROM -1
+#define IXGBE_ERR_EEPROM_CHECKSUM -2
+#define IXGBE_ERR_PHY -3
+#define IXGBE_ERR_CONFIG -4
+#define IXGBE_ERR_PARAM -5
+#define IXGBE_ERR_MAC_TYPE -6
+#define IXGBE_ERR_UNKNOWN_PHY -7
+#define IXGBE_ERR_LINK_SETUP -8
+#define IXGBE_ERR_ADAPTER_STOPPED -9
+#define IXGBE_ERR_INVALID_MAC_ADDR -10
+#define IXGBE_ERR_DEVICE_NOT_SUPPORTED -11
+#define IXGBE_ERR_MASTER_REQUESTS_PENDING -12
+#define IXGBE_ERR_INVALID_LINK_SETTINGS -13
+#define IXGBE_ERR_AUTONEG_NOT_COMPLETE -14
+#define IXGBE_ERR_RESET_FAILED -15
+#define IXGBE_ERR_SWFW_SYNC -16
+#define IXGBE_ERR_PHY_ADDR_INVALID -17
+#define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF
+
+#endif /* _IXGBE_TYPE_H_ */
diff --git a/drivers/net/ixp2000/enp2611.c b/drivers/net/ixp2000/enp2611.c
index d3f4235c585..b02a981c87a 100644
--- a/drivers/net/ixp2000/enp2611.c
+++ b/drivers/net/ixp2000/enp2611.c
@@ -210,7 +210,6 @@ static int __init enp2611_init_module(void)
return -ENOMEM;
}
- SET_MODULE_OWNER(nds[i]);
nds[i]->get_stats = enp2611_get_stats;
pm3386_init_port(i);
pm3386_get_mac(i, nds[i]->dev_addr);
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index d9ce1aef148..6c0dd49149d 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -74,9 +74,9 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
}
-static int ixpdev_rx(struct net_device *dev, int *budget)
+static int ixpdev_rx(struct net_device *dev, int processed, int budget)
{
- while (*budget > 0) {
+ while (processed < budget) {
struct ixpdev_rx_desc *desc;
struct sk_buff *skb;
void *buf;
@@ -122,29 +122,34 @@ static int ixpdev_rx(struct net_device *dev, int *budget)
err:
ixp2000_reg_write(RING_RX_PENDING, _desc);
- dev->quota--;
- (*budget)--;
+ processed++;
}
- return 1;
+ return processed;
}
/* dev always points to nds[0]. */
-static int ixpdev_poll(struct net_device *dev, int *budget)
+static int ixpdev_poll(struct napi_struct *napi, int budget)
{
+ struct ixpdev_priv *ip = container_of(napi, struct ixpdev_priv, napi);
+ struct net_device *dev = ip->dev;
+ int rx;
+
/* @@@ Have to stop polling when nds[0] is administratively
* downed while we are polling. */
+ rx = 0;
do {
ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff);
- if (ixpdev_rx(dev, budget))
- return 1;
+ rx = ixpdev_rx(dev, rx, budget);
+ if (rx >= budget)
+ break;
} while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff);
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff);
- return 0;
+ return rx;
}
static void ixpdev_tx_complete(void)
@@ -199,9 +204,12 @@ static irqreturn_t ixpdev_interrupt(int irq, void *dev_id)
* Any of the eight receive units signaled RX?
*/
if (status & 0x00ff) {
+ struct net_device *dev = nds[0];
+ struct ixpdev_priv *ip = netdev_priv(dev);
+
ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff);
- if (likely(__netif_rx_schedule_prep(nds[0]))) {
- __netif_rx_schedule(nds[0]);
+ if (likely(napi_schedule_prep(&ip->napi))) {
+ __netif_rx_schedule(dev, &ip->napi);
} else {
printk(KERN_CRIT "ixp2000: irq while polling!!\n");
}
@@ -232,11 +240,13 @@ static int ixpdev_open(struct net_device *dev)
struct ixpdev_priv *ip = netdev_priv(dev);
int err;
+ napi_enable(&ip->napi);
if (!nds_open++) {
err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt,
IRQF_SHARED, "ixp2000_eth", nds);
if (err) {
nds_open--;
+ napi_disable(&ip->napi);
return err;
}
@@ -254,6 +264,7 @@ static int ixpdev_close(struct net_device *dev)
struct ixpdev_priv *ip = netdev_priv(dev);
netif_stop_queue(dev);
+ napi_disable(&ip->napi);
set_port_admin_status(ip->channel, 0);
if (!--nds_open) {
@@ -274,7 +285,6 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv)
return NULL;
dev->hard_start_xmit = ixpdev_xmit;
- dev->poll = ixpdev_poll;
dev->open = ixpdev_open;
dev->stop = ixpdev_close;
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -282,9 +292,10 @@ struct net_device *ixpdev_alloc(int channel, int sizeof_priv)
#endif
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
- dev->weight = 64;
ip = netdev_priv(dev);
+ ip->dev = dev;
+ netif_napi_add(dev, &ip->napi, ixpdev_poll, 64);
ip->channel = channel;
ip->tx_queue_entries = 0;
diff --git a/drivers/net/ixp2000/ixpdev.h b/drivers/net/ixp2000/ixpdev.h
index bd686cb6305..391ece62324 100644
--- a/drivers/net/ixp2000/ixpdev.h
+++ b/drivers/net/ixp2000/ixpdev.h
@@ -14,6 +14,8 @@
struct ixpdev_priv
{
+ struct net_device *dev;
+ struct napi_struct napi;
int channel;
int tx_queue_entries;
};
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index 75f6f441e87..5c154fe1385 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -45,7 +45,6 @@
#include <asm/jazzdma.h>
static char jazz_sonic_string[] = "jazzsonic";
-static struct platform_device *jazz_sonic_device;
#define SONIC_MEM_SIZE 0x100
@@ -70,14 +69,6 @@ static unsigned int sonic_debug = 1;
#endif
/*
- * Base address and interrupt of the SONIC controller on JAZZ boards
- */
-static struct {
- unsigned int port;
- unsigned int irq;
-} sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}};
-
-/*
* We cannot use station (ethernet) address prefixes to detect the
* sonic controller since these are board manufacturer depended.
* So we check for known Silicon Revision IDs instead.
@@ -215,13 +206,12 @@ static int __init jazz_sonic_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sonic_local *lp;
+ struct resource *res;
int err = 0;
- int i;
+ DECLARE_MAC_BUF(mac);
- /*
- * Don't probe if we're not running on a Jazz board.
- */
- if (mips_machgroup != MACH_GROUP_JAZZ)
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
return -ENODEV;
dev = alloc_etherdev(sizeof(struct sonic_local));
@@ -231,37 +221,20 @@ static int __init jazz_sonic_probe(struct platform_device *pdev)
lp = netdev_priv(dev);
lp->device = &pdev->dev;
SET_NETDEV_DEV(dev, &pdev->dev);
- SET_MODULE_OWNER(dev);
netdev_boot_setup_check(dev);
- if (dev->base_addr >= KSEG0) { /* Check a single specified location. */
- err = sonic_probe1(dev);
- } else if (dev->base_addr != 0) { /* Don't probe at all. */
- err = -ENXIO;
- } else {
- for (i = 0; sonic_portlist[i].port; i++) {
- dev->base_addr = sonic_portlist[i].port;
- dev->irq = sonic_portlist[i].irq;
- if (sonic_probe1(dev) == 0)
- break;
- }
- if (!sonic_portlist[i].port)
- err = -ENODEV;
- }
+ dev->base_addr = res->start;
+ dev->irq = platform_get_irq(pdev, 0);
+ err = sonic_probe1(dev);
if (err)
goto out;
err = register_netdev(dev);
if (err)
goto out1;
- printk("%s: MAC ", dev->name);
- for (i = 0; i < 6; i++) {
- printk("%2.2x", dev->dev_addr[i]);
- if (i < 5)
- printk(":");
- }
- printk(" IRQ %d\n", dev->irq);
+ printk("%s: MAC %s IRQ %d\n",
+ dev->name, print_mac(mac, dev->dev_addr), dev->irq);
return 0;
@@ -303,38 +276,12 @@ static struct platform_driver jazz_sonic_driver = {
static int __init jazz_sonic_init_module(void)
{
- int err;
-
- if ((err = platform_driver_register(&jazz_sonic_driver))) {
- printk(KERN_ERR "Driver registration failed\n");
- return err;
- }
-
- jazz_sonic_device = platform_device_alloc(jazz_sonic_string, 0);
- if (!jazz_sonic_device)
- goto out_unregister;
-
- if (platform_device_add(jazz_sonic_device)) {
- platform_device_put(jazz_sonic_device);
- jazz_sonic_device = NULL;
- }
-
- return 0;
-
-out_unregister:
- platform_driver_unregister(&jazz_sonic_driver);
-
- return -ENOMEM;
+ return platform_driver_register(&jazz_sonic_driver);
}
static void __exit jazz_sonic_cleanup_module(void)
{
platform_driver_unregister(&jazz_sonic_driver);
-
- if (jazz_sonic_device) {
- platform_device_unregister(jazz_sonic_device);
- jazz_sonic_device = NULL;
- }
}
module_init(jazz_sonic_init_module);
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index a4e5fab1262..977ed3401bb 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -466,6 +466,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
unsigned long flags;
int err = -ENOMEM;
void __iomem *bios;
+ DECLARE_MAC_BUF(mac);
/* First we look for special cases.
Check for HP's on-board ethernet by looking for 'HP' in the BIOS.
@@ -521,14 +522,14 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
/* We can't allocate dev->priv from alloc_etherdev() because it must
a ISA DMA-able region. */
- SET_MODULE_OWNER(dev);
chipname = chip_table[lance_version].name;
- printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
+ printk("%s: %s at %#3x, ", dev->name, chipname, ioaddr);
/* There is a 16 byte station address PROM at the base address.
The first six bytes are the station address. */
for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+ dev->dev_addr[i] = inb(ioaddr + i);
+ printk("%s", print_mac(mac, dev->dev_addr));
dev->base_addr = ioaddr;
/* Make certain the data structures used by the LANCE are aligned and DMAble. */
diff --git a/drivers/net/lguest_net.c b/drivers/net/lguest_net.c
deleted file mode 100644
index cab57911a80..00000000000
--- a/drivers/net/lguest_net.c
+++ /dev/null
@@ -1,557 +0,0 @@
-/*D:500
- * The Guest network driver.
- *
- * This is very simple a virtual network driver, and our last Guest driver.
- * The only trick is that it can talk directly to multiple other recipients
- * (ie. other Guests on the same network). It can also be used with only the
- * Host on the network.
- :*/
-
-/* Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-//#define DEBUG
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/module.h>
-#include <linux/mm_types.h>
-#include <linux/io.h>
-#include <linux/lguest_bus.h>
-
-#define SHARED_SIZE PAGE_SIZE
-#define MAX_LANS 4
-#define NUM_SKBS 8
-
-/*M:011 Network code master Jeff Garzik points out numerous shortcomings in
- * this driver if it aspires to greatness.
- *
- * Firstly, it doesn't use "NAPI": the networking's New API, and is poorer for
- * it. As he says "NAPI means system-wide load leveling, across multiple
- * network interfaces. Lack of NAPI can mean competition at higher loads."
- *
- * He also points out that we don't implement set_mac_address, so users cannot
- * change the devices hardware address. When I asked why one would want to:
- * "Bonding, and situations where you /do/ want the MAC address to "leak" out
- * of the host onto the wider net."
- *
- * Finally, he would like module unloading: "It is not unrealistic to think of
- * [un|re|]loading the net support module in an lguest guest. And, adding
- * module support makes the programmer more responsible, because they now have
- * to learn to clean up after themselves. Any driver that cannot clean up
- * after itself is an incomplete driver in my book."
- :*/
-
-/*D:530 The "struct lguestnet_info" contains all the information we need to
- * know about the network device. */
-struct lguestnet_info
-{
- /* The mapped device page(s) (an array of "struct lguest_net"). */
- struct lguest_net *peer;
- /* The physical address of the device page(s) */
- unsigned long peer_phys;
- /* The size of the device page(s). */
- unsigned long mapsize;
-
- /* The lguest_device I come from */
- struct lguest_device *lgdev;
-
- /* My peerid (ie. my slot in the array). */
- unsigned int me;
-
- /* Receive queue: the network packets waiting to be filled. */
- struct sk_buff *skb[NUM_SKBS];
- struct lguest_dma dma[NUM_SKBS];
-};
-/*:*/
-
-/* How many bytes left in this page. */
-static unsigned int rest_of_page(void *data)
-{
- return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE);
-}
-
-/*D:570 Each peer (ie. Guest or Host) on the network binds their receive
- * buffers to a different key: we simply use the physical address of the
- * device's memory page plus the peer number. The Host insists that all keys
- * be a multiple of 4, so we multiply the peer number by 4. */
-static unsigned long peer_key(struct lguestnet_info *info, unsigned peernum)
-{
- return info->peer_phys + 4 * peernum;
-}
-
-/* This is the routine which sets up a "struct lguest_dma" to point to a
- * network packet, similar to req_to_dma() in lguest_blk.c. The structure of a
- * "struct sk_buff" has grown complex over the years: it consists of a "head"
- * linear section pointed to by "skb->data", and possibly an array of
- * "fragments" in the case of a non-linear packet.
- *
- * Our receive buffers don't use fragments at all but outgoing skbs might, so
- * we handle it. */
-static void skb_to_dma(const struct sk_buff *skb, unsigned int headlen,
- struct lguest_dma *dma)
-{
- unsigned int i, seg;
-
- /* First, we put the linear region into the "struct lguest_dma". Each
- * entry can't go over a page boundary, so even though all our packets
- * are 1514 bytes or less, we might need to use two entries here: */
- for (i = seg = 0; i < headlen; seg++, i += rest_of_page(skb->data+i)) {
- dma->addr[seg] = virt_to_phys(skb->data + i);
- dma->len[seg] = min((unsigned)(headlen - i),
- rest_of_page(skb->data + i));
- }
-
- /* Now we handle the fragments: at least they're guaranteed not to go
- * over a page. skb_shinfo(skb) returns a pointer to the structure
- * which tells us about the number of fragments and the fragment
- * array. */
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++, seg++) {
- const skb_frag_t *f = &skb_shinfo(skb)->frags[i];
- /* Should not happen with MTU less than 64k - 2 * PAGE_SIZE. */
- if (seg == LGUEST_MAX_DMA_SECTIONS) {
- /* We will end up sending a truncated packet should
- * this ever happen. Plus, a cool log message! */
- printk("Woah dude! Megapacket!\n");
- break;
- }
- dma->addr[seg] = page_to_phys(f->page) + f->page_offset;
- dma->len[seg] = f->size;
- }
-
- /* If after all that we didn't use the entire "struct lguest_dma"
- * array, we terminate it with a 0 length. */
- if (seg < LGUEST_MAX_DMA_SECTIONS)
- dma->len[seg] = 0;
-}
-
-/*
- * Packet transmission.
- *
- * Our packet transmission is a little unusual. A real network card would just
- * send out the packet and leave the receivers to decide if they're interested.
- * Instead, we look through the network device memory page and see if any of
- * the ethernet addresses match the packet destination, and if so we send it to
- * that Guest.
- *
- * This is made a little more complicated in two cases. The first case is
- * broadcast packets: for that we send the packet to all Guests on the network,
- * one at a time. The second case is "promiscuous" mode, where a Guest wants
- * to see all the packets on the network. We need a way for the Guest to tell
- * us it wants to see all packets, so it sets the "multicast" bit on its
- * published MAC address, which is never valid in a real ethernet address.
- */
-#define PROMISC_BIT 0x01
-
-/* This is the callback which is summoned whenever the network device's
- * multicast or promiscuous state changes. If the card is in promiscuous mode,
- * we advertise that in our ethernet address in the device's memory. We do the
- * same if Linux wants any or all multicast traffic. */
-static void lguestnet_set_multicast(struct net_device *dev)
-{
- struct lguestnet_info *info = netdev_priv(dev);
-
- if ((dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) || dev->mc_count)
- info->peer[info->me].mac[0] |= PROMISC_BIT;
- else
- info->peer[info->me].mac[0] &= ~PROMISC_BIT;
-}
-
-/* A simple test function to see if a peer wants to see all packets.*/
-static int promisc(struct lguestnet_info *info, unsigned int peer)
-{
- return info->peer[peer].mac[0] & PROMISC_BIT;
-}
-
-/* Another simple function to see if a peer's advertised ethernet address
- * matches a packet's destination ethernet address. */
-static int mac_eq(const unsigned char mac[ETH_ALEN],
- struct lguestnet_info *info, unsigned int peer)
-{
- /* Ignore multicast bit, which peer turns on to mean promisc. */
- if ((info->peer[peer].mac[0] & (~PROMISC_BIT)) != mac[0])
- return 0;
- return memcmp(mac+1, info->peer[peer].mac+1, ETH_ALEN-1) == 0;
-}
-
-/* This is the function which actually sends a packet once we've decided a
- * peer wants it: */
-static void transfer_packet(struct net_device *dev,
- struct sk_buff *skb,
- unsigned int peernum)
-{
- struct lguestnet_info *info = netdev_priv(dev);
- struct lguest_dma dma;
-
- /* We use our handy "struct lguest_dma" packing function to prepare
- * the skb for sending. */
- skb_to_dma(skb, skb_headlen(skb), &dma);
- pr_debug("xfer length %04x (%u)\n", htons(skb->len), skb->len);
-
- /* This is the actual send call which copies the packet. */
- lguest_send_dma(peer_key(info, peernum), &dma);
-
- /* Check that the entire packet was transmitted. If not, it could mean
- * that the other Guest registered a short receive buffer, but this
- * driver should never do that. More likely, the peer is dead. */
- if (dma.used_len != skb->len) {
- dev->stats.tx_carrier_errors++;
- pr_debug("Bad xfer to peer %i: %i of %i (dma %p/%i)\n",
- peernum, dma.used_len, skb->len,
- (void *)dma.addr[0], dma.len[0]);
- } else {
- /* On success we update the stats. */
- dev->stats.tx_bytes += skb->len;
- dev->stats.tx_packets++;
- }
-}
-
-/* Another helper function to tell is if a slot in the device memory is unused.
- * Since we always set the Local Assignment bit in the ethernet address, the
- * first byte can never be 0. */
-static int unused_peer(const struct lguest_net peer[], unsigned int num)
-{
- return peer[num].mac[0] == 0;
-}
-
-/* Finally, here is the routine which handles an outgoing packet. It's called
- * "start_xmit" for traditional reasons. */
-static int lguestnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- unsigned int i;
- int broadcast;
- struct lguestnet_info *info = netdev_priv(dev);
- /* Extract the destination ethernet address from the packet. */
- const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
-
- pr_debug("%s: xmit %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name, dest[0],dest[1],dest[2],dest[3],dest[4],dest[5]);
-
- /* If it's a multicast packet, we broadcast to everyone. That's not
- * very efficient, but there are very few applications which actually
- * use multicast, which is a shame really.
- *
- * As etherdevice.h points out: "By definition the broadcast address is
- * also a multicast address." So we don't have to test for broadcast
- * packets separately. */
- broadcast = is_multicast_ether_addr(dest);
-
- /* Look through all the published ethernet addresses to see if we
- * should send this packet. */
- for (i = 0; i < info->mapsize/sizeof(struct lguest_net); i++) {
- /* We don't send to ourselves (we actually can't SEND_DMA to
- * ourselves anyway), and don't send to unused slots.*/
- if (i == info->me || unused_peer(info->peer, i))
- continue;
-
- /* If it's broadcast we send it. If they want every packet we
- * send it. If the destination matches their address we send
- * it. Otherwise we go to the next peer. */
- if (!broadcast && !promisc(info, i) && !mac_eq(dest, info, i))
- continue;
-
- pr_debug("lguestnet %s: sending from %i to %i\n",
- dev->name, info->me, i);
- /* Our routine which actually does the transfer. */
- transfer_packet(dev, skb, i);
- }
-
- /* An xmit routine is expected to dispose of the packet, so we do. */
- dev_kfree_skb(skb);
-
- /* As per kernel convention, 0 means success. This is why I love
- * networking: even if we never sent to anyone, that's still
- * success! */
- return 0;
-}
-
-/*D:560
- * Packet receiving.
- *
- * First, here's a helper routine which fills one of our array of receive
- * buffers: */
-static int fill_slot(struct net_device *dev, unsigned int slot)
-{
- struct lguestnet_info *info = netdev_priv(dev);
-
- /* We can receive ETH_DATA_LEN (1500) byte packets, plus a standard
- * ethernet header of ETH_HLEN (14) bytes. */
- info->skb[slot] = netdev_alloc_skb(dev, ETH_HLEN + ETH_DATA_LEN);
- if (!info->skb[slot]) {
- printk("%s: could not fill slot %i\n", dev->name, slot);
- return -ENOMEM;
- }
-
- /* skb_to_dma() is a helper which sets up the "struct lguest_dma" to
- * point to the data in the skb: we also use it for sending out a
- * packet. */
- skb_to_dma(info->skb[slot], ETH_HLEN + ETH_DATA_LEN, &info->dma[slot]);
-
- /* This is a Write Memory Barrier: it ensures that the entry in the
- * receive buffer array is written *before* we set the "used_len" entry
- * to 0. If the Host were looking at the receive buffer array from a
- * different CPU, it could potentially see "used_len = 0" and not see
- * the updated receive buffer information. This would be a horribly
- * nasty bug, so make sure the compiler and CPU know this has to happen
- * first. */
- wmb();
- /* Writing 0 to "used_len" tells the Host it can use this receive
- * buffer now. */
- info->dma[slot].used_len = 0;
- return 0;
-}
-
-/* This is the actual receive routine. When we receive an interrupt from the
- * Host to tell us a packet has been delivered, we arrive here: */
-static irqreturn_t lguestnet_rcv(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct lguestnet_info *info = netdev_priv(dev);
- unsigned int i, done = 0;
-
- /* Look through our entire receive array for an entry which has data
- * in it. */
- for (i = 0; i < ARRAY_SIZE(info->dma); i++) {
- unsigned int length;
- struct sk_buff *skb;
-
- length = info->dma[i].used_len;
- if (length == 0)
- continue;
-
- /* We've found one! Remember the skb (we grabbed the length
- * above), and immediately refill the slot we've taken it
- * from. */
- done++;
- skb = info->skb[i];
- fill_slot(dev, i);
-
- /* This shouldn't happen: micropackets could be sent by a
- * badly-behaved Guest on the network, but the Host will never
- * stuff more data in the buffer than the buffer length. */
- if (length < ETH_HLEN || length > ETH_HLEN + ETH_DATA_LEN) {
- pr_debug(KERN_WARNING "%s: unbelievable skb len: %i\n",
- dev->name, length);
- dev_kfree_skb(skb);
- continue;
- }
-
- /* skb_put(), what a great function! I've ranted about this
- * function before (http://lkml.org/lkml/1999/9/26/24). You
- * call it after you've added data to the end of an skb (in
- * this case, it was the Host which wrote the data). */
- skb_put(skb, length);
-
- /* The ethernet header contains a protocol field: we use the
- * standard helper to extract it, and place the result in
- * skb->protocol. The helper also sets up skb->pkt_type and
- * eats up the ethernet header from the front of the packet. */
- skb->protocol = eth_type_trans(skb, dev);
-
- /* If this device doesn't need checksums for sending, we also
- * don't need to check the packets when they come in. */
- if (dev->features & NETIF_F_NO_CSUM)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
-
- /* As a last resort for debugging the driver or the lguest I/O
- * subsystem, you can uncomment the "#define DEBUG" at the top
- * of this file, which turns all the pr_debug() into printk()
- * and floods the logs. */
- pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
- ntohs(skb->protocol), skb->len, skb->pkt_type);
-
- /* Update the packet and byte counts (visible from ifconfig,
- * and good for debugging). */
- dev->stats.rx_bytes += skb->len;
- dev->stats.rx_packets++;
-
- /* Hand our fresh network packet into the stack's "network
- * interface receive" routine. That will free the packet
- * itself when it's finished. */
- netif_rx(skb);
- }
-
- /* If we found any packets, we assume the interrupt was for us. */
- return done ? IRQ_HANDLED : IRQ_NONE;
-}
-
-/*D:550 This is where we start: when the device is brought up by dhcpd or
- * ifconfig. At this point we advertise our MAC address to the rest of the
- * network, and register receive buffers ready for incoming packets. */
-static int lguestnet_open(struct net_device *dev)
-{
- int i;
- struct lguestnet_info *info = netdev_priv(dev);
-
- /* Copy our MAC address into the device page, so others on the network
- * can find us. */
- memcpy(info->peer[info->me].mac, dev->dev_addr, ETH_ALEN);
-
- /* We might already be in promisc mode (dev->flags & IFF_PROMISC). Our
- * set_multicast callback handles this already, so we call it now. */
- lguestnet_set_multicast(dev);
-
- /* Allocate packets and put them into our "struct lguest_dma" array.
- * If we fail to allocate all the packets we could still limp along,
- * but it's a sign of real stress so we should probably give up now. */
- for (i = 0; i < ARRAY_SIZE(info->dma); i++) {
- if (fill_slot(dev, i) != 0)
- goto cleanup;
- }
-
- /* Finally we tell the Host where our array of "struct lguest_dma"
- * receive buffers is, binding it to the key corresponding to the
- * device's physical memory plus our peerid. */
- if (lguest_bind_dma(peer_key(info,info->me), info->dma,
- NUM_SKBS, lgdev_irq(info->lgdev)) != 0)
- goto cleanup;
- return 0;
-
-cleanup:
- while (--i >= 0)
- dev_kfree_skb(info->skb[i]);
- return -ENOMEM;
-}
-/*:*/
-
-/* The close routine is called when the device is no longer in use: we clean up
- * elegantly. */
-static int lguestnet_close(struct net_device *dev)
-{
- unsigned int i;
- struct lguestnet_info *info = netdev_priv(dev);
-
- /* Clear all trace of our existence out of the device memory by setting
- * the slot which held our MAC address to 0 (unused). */
- memset(&info->peer[info->me], 0, sizeof(info->peer[info->me]));
-
- /* Unregister our array of receive buffers */
- lguest_unbind_dma(peer_key(info, info->me), info->dma);
- for (i = 0; i < ARRAY_SIZE(info->dma); i++)
- dev_kfree_skb(info->skb[i]);
- return 0;
-}
-
-/*D:510 The network device probe function is basically a standard ethernet
- * device setup. It reads the "struct lguest_device_desc" and sets the "struct
- * net_device". Oh, the line-by-line excitement! Let's skip over it. :*/
-static int lguestnet_probe(struct lguest_device *lgdev)
-{
- int err, irqf = IRQF_SHARED;
- struct net_device *dev;
- struct lguestnet_info *info;
- struct lguest_device_desc *desc = &lguest_devices[lgdev->index];
-
- pr_debug("lguest_net: probing for device %i\n", lgdev->index);
-
- dev = alloc_etherdev(sizeof(struct lguestnet_info));
- if (!dev)
- return -ENOMEM;
-
- SET_MODULE_OWNER(dev);
-
- /* Ethernet defaults with some changes */
- ether_setup(dev);
- dev->set_mac_address = NULL;
-
- dev->dev_addr[0] = 0x02; /* set local assignment bit (IEEE802) */
- dev->dev_addr[1] = 0x00;
- memcpy(&dev->dev_addr[2], &lguest_data.guestid, 2);
- dev->dev_addr[4] = 0x00;
- dev->dev_addr[5] = 0x00;
-
- dev->open = lguestnet_open;
- dev->stop = lguestnet_close;
- dev->hard_start_xmit = lguestnet_start_xmit;
-
- /* We don't actually support multicast yet, but turning on/off
- * promisc also calls dev->set_multicast_list. */
- dev->set_multicast_list = lguestnet_set_multicast;
- SET_NETDEV_DEV(dev, &lgdev->dev);
-
- /* The network code complains if you have "scatter-gather" capability
- * if you don't also handle checksums (it seem that would be
- * "illogical"). So we use a lie of omission and don't tell it that we
- * can handle scattered packets unless we also don't want checksums,
- * even though to us they're completely independent. */
- if (desc->features & LGUEST_NET_F_NOCSUM)
- dev->features = NETIF_F_SG|NETIF_F_NO_CSUM;
-
- info = netdev_priv(dev);
- info->mapsize = PAGE_SIZE * desc->num_pages;
- info->peer_phys = ((unsigned long)desc->pfn << PAGE_SHIFT);
- info->lgdev = lgdev;
- info->peer = lguest_map(info->peer_phys, desc->num_pages);
- if (!info->peer) {
- err = -ENOMEM;
- goto free;
- }
-
- /* This stores our peerid (upper bits reserved for future). */
- info->me = (desc->features & (info->mapsize-1));
-
- err = register_netdev(dev);
- if (err) {
- pr_debug("lguestnet: registering device failed\n");
- goto unmap;
- }
-
- if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS)
- irqf |= IRQF_SAMPLE_RANDOM;
- if (request_irq(lgdev_irq(lgdev), lguestnet_rcv, irqf, "lguestnet",
- dev) != 0) {
- pr_debug("lguestnet: cannot get irq %i\n", lgdev_irq(lgdev));
- goto unregister;
- }
-
- pr_debug("lguestnet: registered device %s\n", dev->name);
- /* Finally, we put the "struct net_device" in the generic "struct
- * lguest_device"s private pointer. Again, it's not necessary, but
- * makes sure the cool kernel kids don't tease us. */
- lgdev->private = dev;
- return 0;
-
-unregister:
- unregister_netdev(dev);
-unmap:
- lguest_unmap(info->peer);
-free:
- free_netdev(dev);
- return err;
-}
-
-static struct lguest_driver lguestnet_drv = {
- .name = "lguestnet",
- .owner = THIS_MODULE,
- .device_type = LGUEST_DEVICE_T_NET,
- .probe = lguestnet_probe,
-};
-
-static __init int lguestnet_init(void)
-{
- return register_lguest_driver(&lguestnet_drv);
-}
-module_init(lguestnet_init);
-
-MODULE_DESCRIPTION("Lguest network driver");
-MODULE_LICENSE("GPL");
-
-/*D:580
- * This is the last of the Drivers, and with this we have covered the many and
- * wonderous and fine (and boring) details of the Guest.
- *
- * "make Launcher" beckons, where we answer questions like "Where do Guests
- * come from?", and "What do you do when someone asks for optimization?"
- */
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
index 5884f5bd04a..9a855e51214 100644
--- a/drivers/net/lib82596.c
+++ b/drivers/net/lib82596.c
@@ -322,7 +322,6 @@ struct i596_private {
struct i596_cmd *cmd_head;
int cmd_backlog;
u32 last_cmd;
- struct net_device_stats stats;
int next_tx_cmd;
int options;
spinlock_t lock; /* serialize access to chip */
@@ -352,7 +351,6 @@ static int i596_open(struct net_device *dev);
static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t i596_interrupt(int irq, void *dev_id);
static int i596_close(struct net_device *dev);
-static struct net_device_stats *i596_get_stats(struct net_device *dev);
static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
static void i596_tx_timeout (struct net_device *dev);
static void print_eth(unsigned char *buf, char *str);
@@ -725,7 +723,7 @@ memory_squeeze:
printk(KERN_ERR
"%s: i596_rx Memory squeeze, dropping packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
} else {
if (!rx_in_place) {
/* 16 byte align the data fields */
@@ -742,28 +740,28 @@ memory_squeeze:
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
} else {
DEB(DEB_ERRORS, printk(KERN_DEBUG
"%s: Error, rfd.stat = 0x%04x\n",
dev->name, rfd->stat));
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rfd->stat & SWAP16(0x0100))
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (rfd->stat & SWAP16(0x8000))
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rfd->stat & SWAP16(0x0001))
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (rfd->stat & SWAP16(0x0002))
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (rfd->stat & SWAP16(0x0004))
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rfd->stat & SWAP16(0x0008))
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rfd->stat & SWAP16(0x0010))
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
/* Clear the buffer descriptor count and EOF + F flags */
@@ -821,8 +819,8 @@ static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private
dev_kfree_skb(skb);
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
ptr->v_next = NULL;
ptr->b_next = I596_NULL;
@@ -951,10 +949,10 @@ static void i596_tx_timeout (struct net_device *dev)
"%s: transmit timed out, status resetting.\n",
dev->name));
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* Try to restart the adaptor */
- if (lp->last_restart == lp->stats.tx_packets) {
+ if (lp->last_restart == dev->stats.tx_packets) {
DEB(DEB_ERRORS, printk(KERN_DEBUG "Resetting board.\n"));
/* Shutdown and restart */
i596_reset (dev, lp);
@@ -964,7 +962,7 @@ static void i596_tx_timeout (struct net_device *dev)
lp->dma->scb.command = SWAP16(CUC_START | RX_START);
DMA_WBACK_INV(dev, &(lp->dma->scb), sizeof(struct i596_scb));
ca (dev);
- lp->last_restart = lp->stats.tx_packets;
+ lp->last_restart = dev->stats.tx_packets;
}
dev->trans_start = jiffies;
@@ -999,7 +997,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
DEB(DEB_ERRORS, printk(KERN_DEBUG
"%s: xmit ring full, dropping packet.\n",
dev->name));
- lp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
} else {
@@ -1025,8 +1023,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
DMA_WBACK_INV(dev, tbd, sizeof(struct i596_tbd));
i596_add_cmd(dev, &tx_cmd->cmd);
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += length;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += length;
}
netif_start_queue(dev);
@@ -1036,15 +1034,12 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
static void print_eth(unsigned char *add, char *str)
{
- int i;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
- printk(KERN_DEBUG "i596 0x%p, ", add);
- for (i = 0; i < 6; i++)
- printk(" %02X", add[i + 6]);
- printk(" -->");
- for (i = 0; i < 6; i++)
- printk(" %02X", add[i]);
- printk(" %02X%02X, %s\n", add[12], add[13], str);
+ printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n",
+ add, print_mac(mac, add + 6), print_mac(mac2, add),
+ add[12], add[13], str);
}
static int __devinit i82596_probe(struct net_device *dev)
@@ -1076,7 +1071,6 @@ static int __devinit i82596_probe(struct net_device *dev)
dev->open = i596_open;
dev->stop = i596_close;
dev->hard_start_xmit = i596_start_xmit;
- dev->get_stats = i596_get_stats;
dev->set_multicast_list = set_multicast_list;
dev->tx_timeout = i596_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -1130,12 +1124,6 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id)
struct i596_dma *dma;
unsigned short status, ack_cmd = 0;
- if (dev == NULL) {
- printk(KERN_WARNING "%s: irq %d for unknown device.\n",
- __FUNCTION__, irq);
- return IRQ_NONE;
- }
-
lp = netdev_priv(dev);
dma = lp->dma;
@@ -1146,7 +1134,7 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id)
DEB(DEB_INTS, printk(KERN_DEBUG
"%s: i596 interrupt, IRQ %d, status %4.4x.\n",
- dev->name, irq, status));
+ dev->name, dev->irq, status));
ack_cmd = status & 0xf000;
@@ -1197,17 +1185,17 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id)
DEB(DEB_TXADDR,
print_eth(skb->data, "tx-done"));
} else {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (ptr->status & SWAP16(0x0020))
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (!(ptr->status & SWAP16(0x0040)))
- lp->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
if (ptr->status & SWAP16(0x0400))
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (ptr->status & SWAP16(0x0800))
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (ptr->status & SWAP16(0x1000))
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
}
dma_unmap_single(dev->dev.parent,
tx_cmd->dma_addr,
@@ -1292,8 +1280,8 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id)
"%s: i596 interrupt receive unit inactive, status 0x%x\n",
dev->name, status));
ack_cmd |= RX_START;
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
rebuild_rx_bufs(dev);
}
}
@@ -1346,13 +1334,6 @@ static int i596_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *i596_get_stats(struct net_device *dev)
-{
- struct i596_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/*
* Set or clear the multicast filter for this adaptor.
*/
@@ -1362,6 +1343,7 @@ static void set_multicast_list(struct net_device *dev)
struct i596_private *lp = netdev_priv(dev);
struct i596_dma *dma = lp->dma;
int config = 0, cnt;
+ DECLARE_MAC_BUF(mac);
DEB(DEB_MULTI,
printk(KERN_DEBUG
@@ -1425,8 +1407,8 @@ static void set_multicast_list(struct net_device *dev)
if (i596_debug > 1)
DEB(DEB_MULTI,
printk(KERN_DEBUG
- "%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name, cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]));
+ "%s: Adding address %s\n",
+ dev->name, print_mac(mac, cp)));
}
DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd));
i596_add_cmd(dev, &cmd->cmd);
diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
index 0a08d0c4e7b..b3698909788 100644
--- a/drivers/net/lne390.c
+++ b/drivers/net/lne390.c
@@ -111,8 +111,6 @@ static int __init do_lne390_probe(struct net_device *dev)
int mem_start = dev->mem_start;
int ret;
- SET_MODULE_OWNER(dev);
-
if (ioaddr > 0x1ff) { /* Check a single specified location. */
if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -171,6 +169,7 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr)
{
int i, revision, ret;
unsigned long eisa_id;
+ DECLARE_MAC_BUF(mac);
if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV;
@@ -202,10 +201,12 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr)
}
#endif
- printk("lne390.c: LNE390%X in EISA slot %d, address", 0xa+revision, ioaddr/0x1000);
for(i = 0; i < ETHER_ADDR_LEN; i++)
- printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i)));
- printk(".\nlne390.c: ");
+ dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i);
+ printk("lne390.c: LNE390%X in EISA slot %d, address %s.\n",
+ 0xa+revision, ioaddr/0x1000, print_mac(mac, dev->dev_addr));
+
+ printk("lne390.c: ");
/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
if (dev->irq == 0) {
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 5106c2328d1..662b8d16803 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -57,12 +57,12 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/percpu.h>
+#include <net/net_namespace.h>
struct pcpu_lstats {
unsigned long packets;
unsigned long bytes;
};
-static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats);
#define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16)
@@ -134,7 +134,7 @@ static void emulate_large_send_offload(struct sk_buff *skb)
*/
static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct pcpu_lstats *lb_stats;
+ struct pcpu_lstats *pcpu_lstats, *lb_stats;
skb_orphan(skb);
@@ -154,8 +154,9 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
dev->last_rx = jiffies;
- /* it's OK to use __get_cpu_var() because BHs are off */
- lb_stats = &__get_cpu_var(pcpu_lstats);
+ /* it's OK to use per_cpu_ptr() because BHs are off */
+ pcpu_lstats = netdev_priv(dev);
+ lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id());
lb_stats->bytes += skb->len;
lb_stats->packets++;
@@ -166,15 +167,17 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
static struct net_device_stats *get_stats(struct net_device *dev)
{
+ const struct pcpu_lstats *pcpu_lstats;
struct net_device_stats *stats = &dev->stats;
unsigned long bytes = 0;
unsigned long packets = 0;
int i;
+ pcpu_lstats = netdev_priv(dev);
for_each_possible_cpu(i) {
const struct pcpu_lstats *lb_stats;
- lb_stats = &per_cpu(pcpu_lstats, i);
+ lb_stats = per_cpu_ptr(pcpu_lstats, i);
bytes += lb_stats->bytes;
packets += lb_stats->packets;
}
@@ -192,51 +195,106 @@ static u32 always_on(struct net_device *dev)
static const struct ethtool_ops loopback_ethtool_ops = {
.get_link = always_on,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_tx_csum = always_on,
.get_sg = always_on,
.get_rx_csum = always_on,
};
+static int loopback_dev_init(struct net_device *dev)
+{
+ struct pcpu_lstats *lstats;
+
+ lstats = alloc_percpu(struct pcpu_lstats);
+ if (!lstats)
+ return -ENOMEM;
+
+ dev->priv = lstats;
+ return 0;
+}
+
+static void loopback_dev_free(struct net_device *dev)
+{
+ struct pcpu_lstats *lstats = netdev_priv(dev);
+
+ free_percpu(lstats);
+ free_netdev(dev);
+}
+
/*
- * The loopback device is special. There is only one instance and
- * it is statically allocated. Don't do this for other devices.
+ * The loopback device is special. There is only one instance
+ * per network namespace.
*/
-struct net_device loopback_dev = {
- .name = "lo",
- .get_stats = &get_stats,
- .mtu = (16 * 1024) + 20 + 20 + 12,
- .hard_start_xmit = loopback_xmit,
- .hard_header = eth_header,
- .hard_header_cache = eth_header_cache,
- .header_cache_update = eth_header_cache_update,
- .hard_header_len = ETH_HLEN, /* 14 */
- .addr_len = ETH_ALEN, /* 6 */
- .tx_queue_len = 0,
- .type = ARPHRD_LOOPBACK, /* 0x0001*/
- .rebuild_header = eth_rebuild_header,
- .flags = IFF_LOOPBACK,
- .features = NETIF_F_SG | NETIF_F_FRAGLIST
+static void loopback_setup(struct net_device *dev)
+{
+ dev->get_stats = &get_stats;
+ dev->mtu = (16 * 1024) + 20 + 20 + 12;
+ dev->hard_start_xmit = loopback_xmit;
+ dev->hard_header_len = ETH_HLEN; /* 14 */
+ dev->addr_len = ETH_ALEN; /* 6 */
+ dev->tx_queue_len = 0;
+ dev->type = ARPHRD_LOOPBACK; /* 0x0001*/
+ dev->flags = IFF_LOOPBACK;
+ dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
#ifdef LOOPBACK_TSO
- | NETIF_F_TSO
+ | NETIF_F_TSO
#endif
- | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA
- | NETIF_F_LLTX,
- .ethtool_ops = &loopback_ethtool_ops,
-};
+ | NETIF_F_NO_CSUM
+ | NETIF_F_HIGHDMA
+ | NETIF_F_LLTX
+ | NETIF_F_NETNS_LOCAL,
+ dev->ethtool_ops = &loopback_ethtool_ops;
+ dev->header_ops = &eth_header_ops;
+ dev->init = loopback_dev_init;
+ dev->destructor = loopback_dev_free;
+}
/* Setup and register the loopback device. */
-static int __init loopback_init(void)
+static __net_init int loopback_net_init(struct net *net)
{
- int err = register_netdev(&loopback_dev);
+ struct net_device *dev;
+ int err;
+
+ err = -ENOMEM;
+ dev = alloc_netdev(0, "lo", loopback_setup);
+ if (!dev)
+ goto out;
+ dev->nd_net = net;
+ err = register_netdev(dev);
if (err)
- panic("loopback: Failed to register netdevice: %d\n", err);
+ goto out_free_netdev;
+
+ net->loopback_dev = dev;
+ return 0;
+
+out_free_netdev:
+ free_netdev(dev);
+out:
+ if (net == &init_net)
+ panic("loopback: Failed to register netdevice: %d\n", err);
return err;
+}
+
+static __net_exit void loopback_net_exit(struct net *net)
+{
+ struct net_device *dev = net->loopback_dev;
+
+ unregister_netdev(dev);
+}
+
+static struct pernet_operations __net_initdata loopback_net_ops = {
+ .init = loopback_net_init,
+ .exit = loopback_net_exit,
};
-module_init(loopback_init);
+static int __init loopback_init(void)
+{
+ return register_pernet_device(&loopback_net_ops);
+}
-EXPORT_SYMBOL(loopback_dev);
+/* Loopback is special. It should be initialized before any other network
+ * device and network subsystem.
+ */
+fs_initcall(loopback_init);
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index 5fc18da1873..c5095ecd8b1 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -350,7 +350,6 @@ struct i596_private { /* aligned to a 16-byte boundary */
struct i596_cmd *cmd_head;
int cmd_backlog;
unsigned long last_cmd;
- struct net_device_stats stats;
spinlock_t cmd_lock;
};
@@ -381,7 +380,6 @@ static int i596_open(struct net_device *dev);
static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t i596_interrupt(int irq, void *dev_id);
static int i596_close(struct net_device *dev);
-static struct net_device_stats *i596_get_stats(struct net_device *dev);
static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
static void print_eth(char *);
static void set_multicast_list(struct net_device *dev);
@@ -515,8 +513,6 @@ CLEAR_INT(void) {
outb(0, IOADDR+8);
}
-#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
-
#if 0
/* selftest or dump */
static void
@@ -532,7 +528,7 @@ i596_port_do(struct net_device *dev, int portcmd, char *cmdname) {
mdelay(30); /* random, unmotivated */
printk("lp486e i82596 %s result:\n", cmdname);
- for (m = SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
+ for (m = ARRAY_SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
;
for (i = 0; i < m; i++) {
printk(" %04x", lp->dump.dump[i]);
@@ -672,7 +668,7 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp,
if (skb == NULL) {
printk ("%s: i596_rx Memory squeeze, "
"dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return 1;
}
@@ -681,27 +677,27 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp,
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
+ dev->stats.rx_packets++;
} else {
#if 0
printk("Frame reception error status %04x\n",
rfd->stat);
#endif
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rfd->stat & RFD_COLLISION)
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (rfd->stat & RFD_SHORT_FRAME_ERR)
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rfd->stat & RFD_DMA_ERR)
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (rfd->stat & RFD_NOBUFS_ERR)
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (rfd->stat & RFD_ALIGN_ERR)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rfd->stat & RFD_CRC_ERR)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rfd->stat & RFD_LENGTH_ERR)
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
rfd->stat = rfd->count = 0;
return 0;
@@ -757,8 +753,8 @@ i596_cleanup_cmd(struct net_device *dev) {
dev_kfree_skb_any(tx_cmd_tbd->skb);
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
cmd->pa_next = I596_NULL;
kfree((unsigned char *)tx_cmd);
@@ -869,7 +865,6 @@ static int i596_open(struct net_device *dev)
}
static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
- struct i596_private *lp = dev->priv;
struct tx_cmd *tx_cmd;
short length;
@@ -886,7 +881,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
if (tx_cmd == NULL) {
printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb (skb);
} else {
struct i596_tbd *tx_cmd_tbd;
@@ -909,7 +904,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
i596_add_cmd (dev, (struct i596_cmd *) tx_cmd);
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
return 0;
@@ -922,10 +917,10 @@ i596_tx_timeout (struct net_device *dev) {
/* Transmitter timeout, serious problems. */
printk(KERN_WARNING "%s: transmit timed out, status resetting.\n", dev->name);
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* Try to restart the adaptor */
- if (lp->last_restart == lp->stats.tx_packets) {
+ if (lp->last_restart == dev->stats.tx_packets) {
printk ("Resetting board.\n");
/* Shutdown and restart */
@@ -935,7 +930,7 @@ i596_tx_timeout (struct net_device *dev) {
printk ("Kicking board.\n");
lp->scb.command = (CUC_START | RX_START);
CA();
- lp->last_restart = lp->stats.tx_packets;
+ lp->last_restart = dev->stats.tx_packets;
}
netif_wake_queue(dev);
}
@@ -1023,7 +1018,6 @@ static int __init lp486e_probe(struct net_device *dev) {
dev->open = &i596_open;
dev->stop = &i596_close;
dev->hard_start_xmit = &i596_start_xmit;
- dev->get_stats = &i596_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->watchdog_timeo = 5*HZ;
dev->tx_timeout = i596_tx_timeout;
@@ -1080,20 +1074,20 @@ i596_handle_CU_completion(struct net_device *dev,
if (i596_debug)
print_eth(pa_to_va(tx_cmd_tbd->pa_data));
} else {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (i596_debug)
printk("transmission failure:%04x\n",
cmd->status);
if (cmd->status & 0x0020)
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (!(cmd->status & 0x0040))
- lp->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
if (cmd->status & 0x0400)
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (cmd->status & 0x0800)
- lp->stats.collisions++;
+ dev->stats.collisions++;
if (cmd->status & 0x1000)
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
}
dev_kfree_skb_irq(tx_cmd_tbd->skb);
@@ -1244,12 +1238,6 @@ static int i596_close(struct net_device *dev) {
return 0;
}
-static struct net_device_stats * i596_get_stats(struct net_device *dev) {
- struct i596_private *lp = dev->priv;
-
- return &lp->stats;
-}
-
/*
* Set or clear the multicast filter for this adaptor.
*/
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index 90b0c3ed4bb..9e700749bb3 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -313,8 +313,6 @@ struct net_device * __init mac8390_probe(int unit)
if (unit >= 0)
sprintf(dev->name, "eth%d", unit);
- SET_MODULE_OWNER(dev);
-
while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) {
/* Have we seen it already? */
if (slots & (1<<ndev->board->slot))
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index 62c1c6262fe..a19b5958cee 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -99,9 +99,9 @@ static char *version =
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
+#include <linux/bitops.h>
#include <asm/system.h>
-#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/hwtest.h>
#include <asm/macints.h>
@@ -181,6 +181,7 @@ struct net_device * __init mac89x0_probe(int unit)
unsigned long ioaddr;
unsigned short sig;
int err = -ENODEV;
+ DECLARE_MAC_BUF(mac);
dev = alloc_etherdev(sizeof(struct net_local));
if (!dev)
@@ -191,8 +192,6 @@ struct net_device * __init mac89x0_probe(int unit)
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
-
if (once_is_enough)
goto out;
once_is_enough = 1;
@@ -274,13 +273,11 @@ struct net_device * __init mac89x0_probe(int unit)
}
dev->irq = SLOT2IRQ(slot);
- printk(" IRQ %d ADDR ", dev->irq);
- /* print the ethernet address. */
- for (i = 0; i < ETH_ALEN; i++)
- printk("%2.2x%s", dev->dev_addr[i],
- ((i < ETH_ALEN-1) ? ":" : ""));
- printk("\n");
+ /* print the IRQ and ethernet address. */
+
+ printk(" IRQ %d ADDR %s\n",
+ dev->irq, print_mac(mac, dev->dev_addr));
dev->open = net_open;
dev->stop = net_close;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index a4bb0264180..047ea7be485 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -470,47 +470,41 @@ static int macb_rx(struct macb *bp, int budget)
return received;
}
-static int macb_poll(struct net_device *dev, int *budget)
+static int macb_poll(struct napi_struct *napi, int budget)
{
- struct macb *bp = netdev_priv(dev);
- int orig_budget, work_done, retval = 0;
+ struct macb *bp = container_of(napi, struct macb, napi);
+ struct net_device *dev = bp->dev;
+ int work_done;
u32 status;
status = macb_readl(bp, RSR);
macb_writel(bp, RSR, status);
+ work_done = 0;
if (!status) {
/*
* This may happen if an interrupt was pending before
* this function was called last time, and no packets
* have been received since.
*/
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
goto out;
}
dev_dbg(&bp->pdev->dev, "poll: status = %08lx, budget = %d\n",
- (unsigned long)status, *budget);
+ (unsigned long)status, budget);
if (!(status & MACB_BIT(REC))) {
dev_warn(&bp->pdev->dev,
"No RX buffers complete, status = %02lx\n",
(unsigned long)status);
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
goto out;
}
- orig_budget = *budget;
- if (orig_budget > dev->quota)
- orig_budget = dev->quota;
-
- work_done = macb_rx(bp, orig_budget);
- if (work_done < orig_budget) {
- netif_rx_complete(dev);
- retval = 0;
- } else {
- retval = 1;
- }
+ work_done = macb_rx(bp, budget);
+ if (work_done < budget)
+ netif_rx_complete(dev, napi);
/*
* We've done what we can to clean the buffers. Make sure we
@@ -521,7 +515,7 @@ out:
/* TODO: Handle errors */
- return retval;
+ return work_done;
}
static irqreturn_t macb_interrupt(int irq, void *dev_id)
@@ -545,7 +539,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
}
if (status & MACB_RX_INT_FLAGS) {
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &bp->napi)) {
/*
* There's no point taking any more interrupts
* until we have processed the buffers
@@ -553,7 +547,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
dev_dbg(&bp->pdev->dev,
"scheduling RX softirq\n");
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &bp->napi);
}
}
@@ -937,6 +931,8 @@ static int macb_open(struct net_device *dev)
return err;
}
+ napi_enable(&bp->napi);
+
macb_init_rings(bp);
macb_init_hw(bp);
@@ -954,6 +950,7 @@ static int macb_close(struct net_device *dev)
unsigned long flags;
netif_stop_queue(dev);
+ napi_disable(&bp->napi);
if (bp->phy_dev)
phy_stop(bp->phy_dev);
@@ -1074,6 +1071,7 @@ static int __devinit macb_probe(struct platform_device *pdev)
unsigned long pclk_hz;
u32 config;
int err = -ENXIO;
+ DECLARE_MAC_BUF(mac);
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
@@ -1088,7 +1086,6 @@ static int __devinit macb_probe(struct platform_device *pdev)
goto err_out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/* TODO: Actually, we have some interesting features... */
@@ -1146,8 +1143,7 @@ static int __devinit macb_probe(struct platform_device *pdev)
dev->get_stats = macb_get_stats;
dev->set_multicast_list = macb_set_rx_mode;
dev->do_ioctl = macb_ioctl;
- dev->poll = macb_poll;
- dev->weight = 64;
+ netif_napi_add(dev, &bp->napi, macb_poll, 64);
dev->ethtool_ops = &macb_ethtool_ops;
dev->base_addr = regs->start;
@@ -1195,10 +1191,9 @@ static int __devinit macb_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d "
- "(%02x:%02x:%02x:%02x:%02x:%02x)\n",
+ "(%s)\n",
dev->name, dev->base_addr, dev->irq,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ print_mac(mac, dev->dev_addr));
phydev = bp->phy_dev;
printk(KERN_INFO "%s: attached PHY driver [%s] "
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 4e3283ebd97..57b85acf0d1 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -374,6 +374,7 @@ struct macb {
struct clk *pclk;
struct clk *hclk;
struct net_device *dev;
+ struct napi_struct napi;
struct net_device_stats stats;
struct macb_stats hw_stats;
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 52b9332810c..95ebe72f320 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -57,7 +57,6 @@ struct mace_data {
unsigned char tx_fullup;
unsigned char tx_active;
unsigned char tx_bad_runt;
- struct net_device_stats stats;
struct timer_list tx_timeout;
int timeout_active;
int port_aaui;
@@ -78,7 +77,6 @@ struct mace_data {
static int mace_open(struct net_device *dev);
static int mace_close(struct net_device *dev);
static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *mace_stats(struct net_device *dev);
static void mace_set_multicast(struct net_device *dev);
static void mace_reset(struct net_device *dev);
static int mace_set_address(struct net_device *dev, void *addr);
@@ -103,6 +101,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
struct mace_data *mp;
const unsigned char *addr;
int j, rev, rc = -EBUSY;
+ DECLARE_MAC_BUF(mac);
if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n",
@@ -143,7 +142,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
rc = -ENOMEM;
goto err_release;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
mp = dev->priv;
@@ -189,7 +187,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1);
mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1;
- memset(&mp->stats, 0, sizeof(mp->stats));
memset((char *) mp->tx_cmds, 0,
(NCMDS_TX*N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
init_timer(&mp->tx_timeout);
@@ -214,7 +211,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
dev->open = mace_open;
dev->stop = mace_close;
dev->hard_start_xmit = mace_xmit_start;
- dev->get_stats = mace_stats;
dev->set_multicast_list = mace_set_multicast;
dev->set_mac_address = mace_set_address;
@@ -245,11 +241,9 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
goto err_free_rx_irq;
}
- printk(KERN_INFO "%s: MACE at", dev->name);
- for (j = 0; j < 6; ++j) {
- printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
- }
- printk(", chip revision %d.%d\n", mp->chipid >> 8, mp->chipid & 0xff);
+ printk(KERN_INFO "%s: MACE at %s, chip revision %d.%d\n",
+ dev->name, print_mac(mac, dev->dev_addr),
+ mp->chipid >> 8, mp->chipid & 0xff);
return 0;
@@ -585,13 +579,6 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static struct net_device_stats *mace_stats(struct net_device *dev)
-{
- struct mace_data *p = (struct mace_data *) dev->priv;
-
- return &p->stats;
-}
-
static void mace_set_multicast(struct net_device *dev)
{
struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -645,19 +632,19 @@ static void mace_set_multicast(struct net_device *dev)
spin_unlock_irqrestore(&mp->lock, flags);
}
-static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
+static void mace_handle_misc_intrs(struct mace_data *mp, int intr, struct net_device *dev)
{
volatile struct mace __iomem *mb = mp->mace;
static int mace_babbles, mace_jabbers;
if (intr & MPCO)
- mp->stats.rx_missed_errors += 256;
- mp->stats.rx_missed_errors += in_8(&mb->mpc); /* reading clears it */
+ dev->stats.rx_missed_errors += 256;
+ dev->stats.rx_missed_errors += in_8(&mb->mpc); /* reading clears it */
if (intr & RNTPCO)
- mp->stats.rx_length_errors += 256;
- mp->stats.rx_length_errors += in_8(&mb->rntpc); /* reading clears it */
+ dev->stats.rx_length_errors += 256;
+ dev->stats.rx_length_errors += in_8(&mb->rntpc); /* reading clears it */
if (intr & CERR)
- ++mp->stats.tx_heartbeat_errors;
+ ++dev->stats.tx_heartbeat_errors;
if (intr & BABBLE)
if (mace_babbles++ < 4)
printk(KERN_DEBUG "mace: babbling transmitter\n");
@@ -681,7 +668,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
spin_lock_irqsave(&mp->lock, flags);
intr = in_8(&mb->ir); /* read interrupt register */
in_8(&mb->xmtrc); /* get retries */
- mace_handle_misc_intrs(mp, intr);
+ mace_handle_misc_intrs(mp, intr, dev);
i = mp->tx_empty;
while (in_8(&mb->pr) & XMTSV) {
@@ -694,7 +681,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
*/
intr = in_8(&mb->ir);
if (intr != 0)
- mace_handle_misc_intrs(mp, intr);
+ mace_handle_misc_intrs(mp, intr, dev);
if (mp->tx_bad_runt) {
fs = in_8(&mb->xmtfs);
mp->tx_bad_runt = 0;
@@ -768,14 +755,14 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
}
/* Update stats */
if (fs & (UFLO|LCOL|LCAR|RTRY)) {
- ++mp->stats.tx_errors;
+ ++dev->stats.tx_errors;
if (fs & LCAR)
- ++mp->stats.tx_carrier_errors;
+ ++dev->stats.tx_carrier_errors;
if (fs & (UFLO|LCOL|RTRY))
- ++mp->stats.tx_aborted_errors;
+ ++dev->stats.tx_aborted_errors;
} else {
- mp->stats.tx_bytes += mp->tx_bufs[i]->len;
- ++mp->stats.tx_packets;
+ dev->stats.tx_bytes += mp->tx_bufs[i]->len;
+ ++dev->stats.tx_packets;
}
dev_kfree_skb_irq(mp->tx_bufs[i]);
--mp->tx_active;
@@ -829,7 +816,7 @@ static void mace_tx_timeout(unsigned long data)
goto out;
/* update various counters */
- mace_handle_misc_intrs(mp, in_8(&mb->ir));
+ mace_handle_misc_intrs(mp, in_8(&mb->ir), dev);
cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty;
@@ -849,7 +836,7 @@ static void mace_tx_timeout(unsigned long data)
/* fix up the transmit side */
i = mp->tx_empty;
mp->tx_active = 0;
- ++mp->stats.tx_errors;
+ ++dev->stats.tx_errors;
if (mp->tx_bad_runt) {
mp->tx_bad_runt = 0;
} else if (i != mp->tx_fill) {
@@ -917,18 +904,18 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id)
/* got a packet, have a look at it */
skb = mp->rx_bufs[i];
if (skb == 0) {
- ++mp->stats.rx_dropped;
+ ++dev->stats.rx_dropped;
} else if (nb > 8) {
data = skb->data;
frame_status = (data[nb-3] << 8) + data[nb-4];
if (frame_status & (RS_OFLO|RS_CLSN|RS_FRAMERR|RS_FCSERR)) {
- ++mp->stats.rx_errors;
+ ++dev->stats.rx_errors;
if (frame_status & RS_OFLO)
- ++mp->stats.rx_over_errors;
+ ++dev->stats.rx_over_errors;
if (frame_status & RS_FRAMERR)
- ++mp->stats.rx_frame_errors;
+ ++dev->stats.rx_frame_errors;
if (frame_status & RS_FCSERR)
- ++mp->stats.rx_crc_errors;
+ ++dev->stats.rx_crc_errors;
} else {
/* Mace feature AUTO_STRIP_RCV is on by default, dropping the
* FCS on frames with 802.3 headers. This means that Ethernet
@@ -940,15 +927,15 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id)
nb -= 8;
skb_put(skb, nb);
skb->protocol = eth_type_trans(skb, dev);
- mp->stats.rx_bytes += skb->len;
+ dev->stats.rx_bytes += skb->len;
netif_rx(skb);
dev->last_rx = jiffies;
mp->rx_bufs[i] = NULL;
- ++mp->stats.rx_packets;
+ ++dev->stats.rx_packets;
}
} else {
- ++mp->stats.rx_errors;
- ++mp->stats.rx_length_errors;
+ ++dev->stats.rx_errors;
+ ++dev->stats.rx_length_errors;
}
/* advance to next */
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 9a343b96597..18770527df9 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -65,7 +65,6 @@ struct mace_data {
unsigned char *rx_ring;
dma_addr_t rx_ring_phys;
int dma_intr;
- struct net_device_stats stats;
int rx_slot, rx_tail;
int tx_slot, tx_sloti, tx_count;
int chipid;
@@ -92,7 +91,6 @@ struct mace_frame {
static int mace_open(struct net_device *dev);
static int mace_close(struct net_device *dev);
static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *mace_stats(struct net_device *dev);
static void mace_set_multicast(struct net_device *dev);
static int mace_set_address(struct net_device *dev, void *addr);
static void mace_reset(struct net_device *dev);
@@ -196,6 +194,7 @@ static int __devinit mace_probe(struct platform_device *pdev)
unsigned char checksum = 0;
static int found = 0;
int err;
+ DECLARE_MAC_BUF(mac);
if (found || macintosh_config->ether_type != MAC_ETHER_MACE)
return -ENODEV;
@@ -210,7 +209,6 @@ static int __devinit mace_probe(struct platform_device *pdev)
mp->device = &pdev->dev;
SET_NETDEV_DEV(dev, &pdev->dev);
- SET_MODULE_OWNER(dev);
dev->base_addr = (u32)MACE_BASE;
mp->mace = (volatile struct mace *) MACE_BASE;
@@ -243,20 +241,16 @@ static int __devinit mace_probe(struct platform_device *pdev)
return -ENODEV;
}
- memset(&mp->stats, 0, sizeof(mp->stats));
-
dev->open = mace_open;
dev->stop = mace_close;
dev->hard_start_xmit = mace_xmit_start;
dev->tx_timeout = mace_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
- dev->get_stats = mace_stats;
dev->set_multicast_list = mace_set_multicast;
dev->set_mac_address = mace_set_address;
- printk(KERN_INFO "%s: 68K MACE, hardware address %.2X", dev->name, dev->dev_addr[0]);
- for (j = 1 ; j < 6 ; j++) printk(":%.2X", dev->dev_addr[j]);
- printk("\n");
+ printk(KERN_INFO "%s: 68K MACE, hardware address %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
err = register_netdev(dev);
if (!err)
@@ -473,8 +467,8 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
mp->tx_count--;
local_irq_restore(flags);
- mp->stats.tx_packets++;
- mp->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
/* We need to copy into our xmit buffer to take care of alignment and caching issues */
skb_copy_from_linear_data(skb, mp->tx_ring, skb->len);
@@ -493,12 +487,6 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
-static struct net_device_stats *mace_stats(struct net_device *dev)
-{
- struct mace_data *mp = netdev_priv(dev);
- return &mp->stats;
-}
-
static void mace_set_multicast(struct net_device *dev)
{
struct mace_data *mp = netdev_priv(dev);
@@ -550,19 +538,20 @@ static void mace_set_multicast(struct net_device *dev)
local_irq_restore(flags);
}
-static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
+static void mace_handle_misc_intrs(struct net_device *dev, int intr)
{
+ struct mace_data *mp = netdev_priv(dev);
volatile struct mace *mb = mp->mace;
static int mace_babbles, mace_jabbers;
if (intr & MPCO)
- mp->stats.rx_missed_errors += 256;
- mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */
+ dev->stats.rx_missed_errors += 256;
+ dev->stats.rx_missed_errors += mb->mpc; /* reading clears it */
if (intr & RNTPCO)
- mp->stats.rx_length_errors += 256;
- mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */
+ dev->stats.rx_length_errors += 256;
+ dev->stats.rx_length_errors += mb->rntpc; /* reading clears it */
if (intr & CERR)
- ++mp->stats.tx_heartbeat_errors;
+ ++dev->stats.tx_heartbeat_errors;
if (intr & BABBLE)
if (mace_babbles++ < 4)
printk(KERN_DEBUG "macmace: babbling transmitter\n");
@@ -583,7 +572,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
local_irq_save(flags);
intr = mb->ir; /* read interrupt register */
- mace_handle_misc_intrs(mp, intr);
+ mace_handle_misc_intrs(dev, intr);
if (intr & XMTINT) {
fs = mb->xmtfs;
@@ -601,14 +590,14 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
}
/* Update stats */
if (fs & (UFLO|LCOL|LCAR|RTRY)) {
- ++mp->stats.tx_errors;
+ ++dev->stats.tx_errors;
if (fs & LCAR)
- ++mp->stats.tx_carrier_errors;
+ ++dev->stats.tx_carrier_errors;
else if (fs & (UFLO|LCOL|RTRY)) {
- ++mp->stats.tx_aborted_errors;
+ ++dev->stats.tx_aborted_errors;
if (mb->xmtfs & UFLO) {
printk(KERN_ERR "%s: DMA underrun.\n", dev->name);
- mp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
mace_txdma_reset(dev);
}
}
@@ -657,28 +646,27 @@ static void mace_tx_timeout(struct net_device *dev)
static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
{
- struct mace_data *mp = netdev_priv(dev);
struct sk_buff *skb;
unsigned int frame_status = mf->rcvsts;
if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) {
- mp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (frame_status & RS_OFLO) {
printk(KERN_DEBUG "%s: fifo overflow.\n", dev->name);
- mp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
}
if (frame_status & RS_CLSN)
- mp->stats.collisions++;
+ dev->stats.collisions++;
if (frame_status & RS_FRAMERR)
- mp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (frame_status & RS_FCSERR)
- mp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
} else {
unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 );
skb = dev_alloc_skb(frame_length + 2);
if (!skb) {
- mp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
skb_reserve(skb, 2);
@@ -687,8 +675,8 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- mp->stats.rx_packets++;
- mp->stats.rx_bytes += frame_length;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += frame_length;
}
}
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index e9ecdbf352a..b267161418e 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -223,6 +223,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
struct sonic_local *lp = netdev_priv(dev);
const int prom_addr = ONBOARD_SONIC_PROM_BASE;
int i;
+ DECLARE_MAC_BUF(mac);
/* On NuBus boards we can sometimes look in the ROM resources.
No such luck for comm-slot/onboard. */
@@ -266,13 +267,8 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
dev->dev_addr[1] = val >> 8;
dev->dev_addr[0] = val & 0xff;
- printk(KERN_INFO "HW Address from CAM 15: ");
- for (i = 0; i < 6; i++) {
- printk("%2.2x", dev->dev_addr[i]);
- if (i < 5)
- printk(":");
- }
- printk("\n");
+ printk(KERN_INFO "HW Address from CAM 15: %s\n",
+ print_mac(mac, dev->dev_addr));
} else return 0;
if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
@@ -567,7 +563,7 @@ static int __init mac_sonic_probe(struct platform_device *pdev)
struct net_device *dev;
struct sonic_local *lp;
int err;
- int i;
+ DECLARE_MAC_BUF(mac);
dev = alloc_etherdev(sizeof(struct sonic_local));
if (!dev)
@@ -576,7 +572,6 @@ static int __init mac_sonic_probe(struct platform_device *pdev)
lp = netdev_priv(dev);
lp->device = &pdev->dev;
SET_NETDEV_DEV(dev, &pdev->dev);
- SET_MODULE_OWNER(dev);
/* This will catch fatal stuff like -ENOMEM as well as success */
err = mac_onboard_sonic_probe(dev);
@@ -592,13 +587,8 @@ found:
if (err)
goto out;
- printk("%s: MAC ", dev->name);
- for (i = 0; i < 6; i++) {
- printk("%2.2x", dev->dev_addr[i]);
- if (i < 5)
- printk(":");
- }
- printk(" IRQ %d\n", dev->irq);
+ printk("%s: MAC %s IRQ %d\n",
+ dev->name, print_mac(mac, dev->dev_addr), dev->irq);
return 0;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index dc74d006e01..2e4bcd5654c 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -164,16 +164,24 @@ static int macvlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
const struct macvlan_dev *vlan = netdev_priv(dev);
struct net_device *lowerdev = vlan->lowerdev;
- return lowerdev->hard_header(skb, lowerdev, type, daddr,
- saddr ? : dev->dev_addr, len);
+ return dev_hard_header(skb, lowerdev, type, daddr,
+ saddr ? : dev->dev_addr, len);
}
+static const struct header_ops macvlan_hard_header_ops = {
+ .create = macvlan_hard_header,
+ .rebuild = eth_rebuild_header,
+ .parse = eth_header_parse,
+ .cache = eth_header_cache,
+ .cache_update = eth_header_cache_update,
+};
+
static int macvlan_open(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
@@ -282,10 +290,6 @@ static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev)
static const struct ethtool_ops macvlan_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_rx_csum = macvlan_ethtool_get_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_tso = ethtool_op_get_tso,
- .get_ufo = ethtool_op_get_ufo,
- .get_sg = ethtool_op_get_sg,
.get_drvinfo = macvlan_ethtool_get_drvinfo,
};
@@ -299,9 +303,9 @@ static void macvlan_setup(struct net_device *dev)
dev->change_mtu = macvlan_change_mtu;
dev->change_rx_flags = macvlan_change_rx_flags;
dev->set_multicast_list = macvlan_set_multicast_list;
- dev->hard_header = macvlan_hard_header;
dev->hard_start_xmit = macvlan_hard_start_xmit;
dev->destructor = free_netdev;
+ dev->header_ops = &macvlan_hard_header_ops,
dev->ethtool_ops = &macvlan_ethtool_ops;
dev->tx_queue_len = 0;
}
@@ -376,7 +380,7 @@ static int macvlan_newlink(struct net_device *dev,
if (!tb[IFLA_LINK])
return -EINVAL;
- lowerdev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK]));
+ lowerdev = __dev_get_by_index(dev->nd_net, nla_get_u32(tb[IFLA_LINK]));
if (lowerdev == NULL)
return -ENODEV;
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index 32bed6bc6c0..0c89b028a80 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -33,7 +33,6 @@
#include <asm/ip32/ip32_ints.h>
#include <asm/io.h>
-#include <asm/scatterlist.h>
#include "meth.h"
@@ -66,7 +65,6 @@ module_param(timeout, int, 0);
* packets in and out, so there is place for a packet
*/
struct meth_private {
- struct net_device_stats stats;
/* in-memory copy of MAC Control register */
unsigned long mac_ctrl;
/* in-memory copy of DMA Control register */
@@ -96,11 +94,11 @@ char o2meth_eaddr[8]={0,0,0,0,0,0,0,0};
static inline void load_eaddr(struct net_device *dev)
{
int i;
- DPRINTK("Loading MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
- (int)o2meth_eaddr[0]&0xFF,(int)o2meth_eaddr[1]&0xFF,(int)o2meth_eaddr[2]&0xFF,
- (int)o2meth_eaddr[3]&0xFF,(int)o2meth_eaddr[4]&0xFF,(int)o2meth_eaddr[5]&0xFF);
+ DECLARE_MAC_BUF(mac);
+
for (i = 0; i < 6; i++)
dev->dev_addr[i] = o2meth_eaddr[i];
+ DPRINTK("Loading MAC Address: %s\n", print_mac(mac, dev->dev_addr));
mace->eth.mac_addr = (*(unsigned long*)o2meth_eaddr) >> 16;
}
@@ -401,15 +399,15 @@ static void meth_rx(struct net_device* dev, unsigned long int_status)
printk(KERN_DEBUG "%s: bogus packet size: %ld, status=%#2lx.\n",
dev->name, priv->rx_write,
priv->rx_ring[priv->rx_write]->status.raw);
- priv->stats.rx_errors++;
- priv->stats.rx_length_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
skb = priv->rx_skbs[priv->rx_write];
} else {
skb = alloc_skb(METH_RX_BUFF_SIZE, GFP_ATOMIC);
if (!skb) {
/* Ouch! No memory! Drop packet on the floor */
DPRINTK("No mem: dropping packet\n");
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
skb = priv->rx_skbs[priv->rx_write];
} else {
struct sk_buff *skb_c = priv->rx_skbs[priv->rx_write];
@@ -421,13 +419,13 @@ static void meth_rx(struct net_device* dev, unsigned long int_status)
priv->rx_skbs[priv->rx_write] = skb;
skb_c->protocol = eth_type_trans(skb_c, dev);
dev->last_rx = jiffies;
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
netif_rx(skb_c);
}
}
} else {
- priv->stats.rx_errors++;
+ dev->stats.rx_errors++;
skb=priv->rx_skbs[priv->rx_write];
#if MFE_DEBUG>0
printk(KERN_WARNING "meth: RX error: status=0x%016lx\n",status);
@@ -490,10 +488,10 @@ static void meth_tx_cleanup(struct net_device* dev, unsigned long int_status)
#endif
if (status & METH_TX_ST_DONE) {
if (status & METH_TX_ST_SUCCESS){
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
} else {
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
#if MFE_DEBUG>=1
DPRINTK("TX error: status=%016lx <",status);
if(status & METH_TX_ST_SUCCESS)
@@ -734,7 +732,7 @@ static void meth_tx_timeout(struct net_device *dev)
/* Try to reset the interface. */
meth_reset(dev);
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* Clear all rings */
meth_free_tx_ring(priv);
@@ -773,12 +771,6 @@ static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
/*
* Return statistics to the caller
*/
-static struct net_device_stats *meth_stats(struct net_device *dev)
-{
- struct meth_private *priv = netdev_priv(dev);
- return &priv->stats;
-}
-
/*
* The init function.
*/
@@ -796,7 +788,6 @@ static int __init meth_probe(struct platform_device *pdev)
dev->stop = meth_release;
dev->hard_start_xmit = meth_tx;
dev->do_ioctl = meth_ioctl;
- dev->get_stats = meth_stats;
#ifdef HAVE_TX_TIMEOUT
dev->tx_timeout = meth_tx_timeout;
dev->watchdog_timeo = timeout;
diff --git a/drivers/net/meth.h b/drivers/net/meth.h
index ea3b8fc86d1..a78dc1ca8c2 100644
--- a/drivers/net/meth.h
+++ b/drivers/net/meth.h
@@ -28,9 +28,6 @@
#define RX_BUFFER_OFFSET (sizeof(rx_status_vector)+2) /* staus vector + 2 bytes of padding */
#define RX_BUCKET_SIZE 256
-#undef BIT
-#define BIT(x) (1UL << (x))
-
/* For more detailed explanations of what each field menas,
see Nick's great comments to #defines below (or docs, if
you are lucky enough toget hold of them :)*/
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index 9853c74f6bb..aafc3ce59cb 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -7,13 +7,12 @@
#define DEBUG
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/netdevice.h>
#include <linux/platform_device.h>
-#include <asm/io.h>
#include <asm/mips-boards/simint.h>
#include "mipsnet.h" /* actual device IO mapping */
@@ -22,10 +21,6 @@
#define mipsnet_reg_address(dev, field) (dev->base_addr + field_offset(field))
-struct mipsnet_priv {
- struct net_device_stats stats;
-};
-
static char mipsnet_string[] = "mipsnet";
/*
@@ -35,12 +30,12 @@ static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata,
int len)
{
uint32_t available_len = inl(mipsnet_reg_address(dev, rxDataCount));
+
if (available_len < len)
return -EFAULT;
- for (; len > 0; len--, kdata++) {
+ for (; len > 0; len--, kdata++)
*kdata = inb(mipsnet_reg_address(dev, rxDataBuffer));
- }
return inl(mipsnet_reg_address(dev, rxDataCount));
}
@@ -50,32 +45,22 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev,
{
int count_to_go = skb->len;
char *buf_ptr = skb->data;
- struct mipsnet_priv *mp = netdev_priv(dev);
-
- pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n",
- dev->name, __FUNCTION__, skb->len);
outl(skb->len, mipsnet_reg_address(dev, txDataCount));
- pr_debug("%s: %s(): sending data to MIPSNET txDataBuffer(%d)\n",
- dev->name, __FUNCTION__, skb->len);
-
- for (; count_to_go; buf_ptr++, count_to_go--) {
+ for (; count_to_go; buf_ptr++, count_to_go--)
outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer));
- }
- mp->stats.tx_packets++;
- mp->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
return skb->len;
}
static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
{
- pr_debug("%s:%s(): transmitting %d bytes\n",
- dev->name, __FUNCTION__, skb->len);
-
- /* Only one packet at a time. Once TXDONE interrupt is serviced, the
+ /*
+ * Only one packet at a time. Once TXDONE interrupt is serviced, the
* queue will be restarted.
*/
netif_stop_queue(dev);
@@ -88,10 +73,10 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
{
struct sk_buff *skb;
size_t len = count;
- struct mipsnet_priv *mp = netdev_priv(dev);
- if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) {
- mp->stats.rx_dropped++;
+ skb = alloc_skb(len + 2, GFP_KERNEL);
+ if (!skb) {
+ dev->stats.rx_dropped++;
return -ENOMEM;
}
@@ -102,12 +87,10 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_UNNECESSARY;
- pr_debug("%s:%s(): pushing RXed data to kernel\n",
- dev->name, __FUNCTION__);
netif_rx(skb);
- mp->stats.rx_packets++;
- mp->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
return count;
}
@@ -120,43 +103,30 @@ static irqreturn_t mipsnet_interrupt(int irq, void *dev_id)
uint64_t interruptFlags;
if (irq == dev->irq) {
- pr_debug("%s:%s(): irq %d for device\n",
- dev->name, __FUNCTION__, irq);
-
retval = IRQ_HANDLED;
interruptFlags =
inl(mipsnet_reg_address(dev, interruptControl));
- pr_debug("%s:%s(): intCtl=0x%016llx\n", dev->name,
- __FUNCTION__, interruptFlags);
if (interruptFlags & MIPSNET_INTCTL_TXDONE) {
- pr_debug("%s:%s(): got TXDone\n",
- dev->name, __FUNCTION__);
outl(MIPSNET_INTCTL_TXDONE,
mipsnet_reg_address(dev, interruptControl));
- // only one packet at a time, we are done.
+ /* only one packet at a time, we are done. */
netif_wake_queue(dev);
} else if (interruptFlags & MIPSNET_INTCTL_RXDONE) {
- pr_debug("%s:%s(): got RX data\n",
- dev->name, __FUNCTION__);
mipsnet_get_fromdev(dev,
- inl(mipsnet_reg_address(dev, rxDataCount)));
- pr_debug("%s:%s(): clearing RX int\n",
- dev->name, __FUNCTION__);
+ inl(mipsnet_reg_address(dev, rxDataCount)));
outl(MIPSNET_INTCTL_RXDONE,
mipsnet_reg_address(dev, interruptControl));
} else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) {
- pr_debug("%s:%s(): got test interrupt\n",
- dev->name, __FUNCTION__);
- // TESTBIT is cleared on read.
- // And takes effect after a write with 0
+ /*
+ * TESTBIT is cleared on read.
+ * And takes effect after a write with 0
+ */
outl(0, mipsnet_reg_address(dev, interruptControl));
} else {
- pr_debug("%s:%s(): no valid fags 0x%016llx\n",
- dev->name, __FUNCTION__, interruptFlags);
- // Maybe shared IRQ, just ignore, no clearing.
+ /* Maybe shared IRQ, just ignore, no clearing. */
retval = IRQ_NONE;
}
@@ -166,30 +136,23 @@ static irqreturn_t mipsnet_interrupt(int irq, void *dev_id)
retval = IRQ_NONE;
}
return retval;
-} //mipsnet_interrupt()
+}
static int mipsnet_open(struct net_device *dev)
{
int err;
- pr_debug("%s: mipsnet_open\n", dev->name);
err = request_irq(dev->irq, &mipsnet_interrupt,
IRQF_SHARED, dev->name, (void *) dev);
if (err) {
- pr_debug("%s: %s(): can't get irq %d\n",
- dev->name, __FUNCTION__, dev->irq);
release_region(dev->base_addr, MIPSNET_IO_EXTENT);
return err;
}
- pr_debug("%s: %s(): got IO region at 0x%04lx and irq %d for dev.\n",
- dev->name, __FUNCTION__, dev->base_addr, dev->irq);
-
-
netif_start_queue(dev);
- // test interrupt handler
+ /* test interrupt handler */
outl(MIPSNET_INTCTL_TESTBIT,
mipsnet_reg_address(dev, interruptControl));
@@ -199,22 +162,13 @@ static int mipsnet_open(struct net_device *dev)
static int mipsnet_close(struct net_device *dev)
{
- pr_debug("%s: %s()\n", dev->name, __FUNCTION__);
netif_stop_queue(dev);
- return 0;
-}
-
-static struct net_device_stats *mipsnet_get_stats(struct net_device *dev)
-{
- struct mipsnet_priv *mp = netdev_priv(dev);
- return &mp->stats;
+ return 0;
}
static void mipsnet_set_mclist(struct net_device *dev)
{
- // we don't do anything
- return;
}
static int __init mipsnet_probe(struct device *dev)
@@ -222,7 +176,7 @@ static int __init mipsnet_probe(struct device *dev)
struct net_device *netdev;
int err;
- netdev = alloc_etherdev(sizeof(struct mipsnet_priv));
+ netdev = alloc_etherdev(0);
if (!netdev) {
err = -ENOMEM;
goto out;
@@ -233,7 +187,6 @@ static int __init mipsnet_probe(struct device *dev)
netdev->open = mipsnet_open;
netdev->stop = mipsnet_close;
netdev->hard_start_xmit = mipsnet_xmit;
- netdev->get_stats = mipsnet_get_stats;
netdev->set_multicast_list = mipsnet_set_mclist;
/*
@@ -241,13 +194,10 @@ static int __init mipsnet_probe(struct device *dev)
*/
netdev->base_addr = 0x4200;
netdev->irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB0 +
- inl(mipsnet_reg_address(netdev, interruptInfo));
+ inl(mipsnet_reg_address(netdev, interruptInfo));
- // Get the io region now, get irq on open()
+ /* Get the io region now, get irq on open() */
if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) {
- pr_debug("%s: %s(): IO region {start: 0x%04lux, len: %d} "
- "for dev is not availble.\n", netdev->name,
- __FUNCTION__, netdev->base_addr, MIPSNET_IO_EXTENT);
err = -EBUSY;
goto out_free_netdev;
}
@@ -311,8 +261,6 @@ static int __init mipsnet_init_module(void)
static void __exit mipsnet_exit_module(void)
{
- pr_debug("MIPSNet Ethernet driver exiting\n");
-
driver_unregister(&mipsnet_driver);
}
diff --git a/drivers/net/mipsnet.h b/drivers/net/mipsnet.h
index 026c732024c..0132c6714a4 100644
--- a/drivers/net/mipsnet.h
+++ b/drivers/net/mipsnet.h
@@ -9,32 +9,34 @@
/*
* Id of this Net device, as seen by the core.
*/
-#define MIPS_NET_DEV_ID ((uint64_t) \
- ((uint64_t)'M'<< 0)| \
- ((uint64_t)'I'<< 8)| \
- ((uint64_t)'P'<<16)| \
- ((uint64_t)'S'<<24)| \
- ((uint64_t)'N'<<32)| \
- ((uint64_t)'E'<<40)| \
- ((uint64_t)'T'<<48)| \
- ((uint64_t)'0'<<56))
+#define MIPS_NET_DEV_ID ((uint64_t) \
+ ((uint64_t) 'M' << 0)| \
+ ((uint64_t) 'I' << 8)| \
+ ((uint64_t) 'P' << 16)| \
+ ((uint64_t) 'S' << 24)| \
+ ((uint64_t) 'N' << 32)| \
+ ((uint64_t) 'E' << 40)| \
+ ((uint64_t) 'T' << 48)| \
+ ((uint64_t) '0' << 56))
/*
* Net status/control block as seen by sw in the core.
* (Why not use bit fields? can't be bothered with cross-platform struct
* packing.)
*/
-typedef struct _net_control_block {
- /// dev info for probing
- /// reads as MIPSNET%d where %d is some form of version
- uint64_t devId; /*0x00 */
+struct net_control_block {
+ /*
+ * dev info for probing
+ * reads as MIPSNET%d where %d is some form of version
+ */
+ uint64_t devId; /* 0x00 */
/*
* read only busy flag.
* Set and cleared by the Net Device to indicate that an rx or a tx
* is in progress.
*/
- uint32_t busy; /*0x08 */
+ uint32_t busy; /* 0x08 */
/*
* Set by the Net Device.
@@ -43,16 +45,16 @@ typedef struct _net_control_block {
* rxDataBuffer. The value will decrease till 0 until all the data
* from rxDataBuffer has been read.
*/
- uint32_t rxDataCount; /*0x0c */
+ uint32_t rxDataCount; /* 0x0c */
#define MIPSNET_MAX_RXTX_DATACOUNT (1<<16)
/*
- * Settable from the MIPS core, cleared by the Net Device.
- * The core should set the number of bytes it wants to send,
- * then it should write those bytes of data to txDataBuffer.
- * The device will clear txDataCount has been processed (not necessarily sent).
+ * Settable from the MIPS core, cleared by the Net Device. The core
+ * should set the number of bytes it wants to send, then it should
+ * write those bytes of data to txDataBuffer. The device will clear
+ * txDataCount has been processed (not necessarily sent).
*/
- uint32_t txDataCount; /*0x10 */
+ uint32_t txDataCount; /* 0x10 */
/*
* Interrupt control
@@ -69,39 +71,42 @@ typedef struct _net_control_block {
* To clear the test interrupt, write 0 to this register.
*/
uint32_t interruptControl; /*0x14 */
-#define MIPSNET_INTCTL_TXDONE ((uint32_t)(1<< 0))
-#define MIPSNET_INTCTL_RXDONE ((uint32_t)(1<< 1))
-#define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1<<31))
-#define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE|MIPSNET_INTCTL_RXDONE|MIPSNET_INTCTL_TESTBIT)
+#define MIPSNET_INTCTL_TXDONE ((uint32_t)(1 << 0))
+#define MIPSNET_INTCTL_RXDONE ((uint32_t)(1 << 1))
+#define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1 << 31))
+#define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE | \
+ MIPSNET_INTCTL_RXDONE | \
+ MIPSNET_INTCTL_TESTBIT)
/*
- * Readonly core-specific interrupt info for the device to signal the core.
- * The meaning of the contents of this field might change.
- */
- /*###\todo: the whole memIntf interrupt scheme is messy: the device should have
- * no control what so ever of what VPE/register set is being used.
- * The MemIntf should only expose interrupt lines, and something in the
- * config should be responsible for the line<->core/vpe bindings.
+ * Readonly core-specific interrupt info for the device to signal the
+ * core. The meaning of the contents of this field might change.
+ *
+ * TODO: the whole memIntf interrupt scheme is messy: the device should
+ * have no control what so ever of what VPE/register set is being
+ * used. The MemIntf should only expose interrupt lines, and
+ * something in the config should be responsible for the
+ * line<->core/vpe bindings.
*/
- uint32_t interruptInfo; /*0x18 */
+ uint32_t interruptInfo; /* 0x18 */
/*
* This is where the received data is read out.
* There is more data to read until rxDataReady is 0.
* Only 1 byte at this regs offset is used.
*/
- uint32_t rxDataBuffer; /*0x1c */
+ uint32_t rxDataBuffer; /* 0x1c */
/*
- * This is where the data to transmit is written.
- * Data should be written for the amount specified in the txDataCount register.
- * Only 1 byte at this regs offset is used.
+ * This is where the data to transmit is written. Data should be
+ * written for the amount specified in the txDataCount register. Only
+ * 1 byte at this regs offset is used.
*/
- uint32_t txDataBuffer; /*0x20 */
-} MIPS_T_NetControl;
+ uint32_t txDataBuffer; /* 0x20 */
+};
#define MIPSNET_IO_EXTENT 0x40 /* being generous */
-#define field_offset(field) ((int)&((MIPS_T_NetControl*)(0))->field)
+#define field_offset(field) (offsetof(struct net_control_block, field))
#endif /* __MIPSNET_H */
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c
index f8d63d39f59..b226e019bc8 100644
--- a/drivers/net/mlx4/alloc.c
+++ b/drivers/net/mlx4/alloc.c
@@ -171,9 +171,10 @@ void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf)
buf->u.direct.map);
else {
for (i = 0; i < buf->nbufs; ++i)
- dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
- buf->u.page_list[i].buf,
- buf->u.page_list[i].map);
+ if (buf->u.page_list[i].buf)
+ dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+ buf->u.page_list[i].buf,
+ buf->u.page_list[i].map);
kfree(buf->u.page_list);
}
}
diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c
index a9f31753661..db49051b97b 100644
--- a/drivers/net/mlx4/cmd.c
+++ b/drivers/net/mlx4/cmd.c
@@ -95,7 +95,7 @@ enum {
};
enum {
- GO_BIT_TIMEOUT = 10000
+ GO_BIT_TIMEOUT_MSECS = 10000
};
struct mlx4_cmd_context {
@@ -155,7 +155,7 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
end = jiffies;
if (event)
- end += HZ * 10;
+ end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS);
while (cmd_pending(dev)) {
if (time_after_eq(jiffies, end))
@@ -184,6 +184,13 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
(event ? (1 << HCR_E_BIT) : 0) |
(op_modifier << HCR_OPMOD_SHIFT) |
op), hcr + 6);
+
+ /*
+ * Make sure that our HCR writes don't get mixed in with
+ * writes from another CPU starting a FW command.
+ */
+ mmiowb();
+
cmd->toggle = cmd->toggle ^ 1;
ret = 0;
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c
index 39253d0c159..d4441fee3d8 100644
--- a/drivers/net/mlx4/cq.c
+++ b/drivers/net/mlx4/cq.c
@@ -231,7 +231,7 @@ void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq)
}
EXPORT_SYMBOL_GPL(mlx4_cq_free);
-int __devinit mlx4_init_cq_table(struct mlx4_dev *dev)
+int mlx4_init_cq_table(struct mlx4_dev *dev)
{
struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table;
int err;
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 2095c843fa1..9c36c203403 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -300,8 +300,7 @@ static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
MLX4_CMD_TIME_CLASS_A);
}
-static void __devinit __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev,
- struct mlx4_eq *eq)
+static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int index;
@@ -323,8 +322,8 @@ static void __devinit __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev,
return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4);
}
-static int __devinit mlx4_create_eq(struct mlx4_dev *dev, int nent,
- u8 intr, struct mlx4_eq *eq)
+static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
+ u8 intr, struct mlx4_eq *eq)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_cmd_mailbox *mailbox;
@@ -485,7 +484,7 @@ static void mlx4_free_irqs(struct mlx4_dev *dev)
free_irq(eq_table->eq[i].irq, eq_table->eq + i);
}
-static int __devinit mlx4_map_clr_int(struct mlx4_dev *dev)
+static int mlx4_map_clr_int(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -506,7 +505,7 @@ static void mlx4_unmap_clr_int(struct mlx4_dev *dev)
iounmap(priv->clr_base);
}
-int __devinit mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt)
+int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int ret;
@@ -548,7 +547,7 @@ void mlx4_unmap_eq_icm(struct mlx4_dev *dev)
__free_page(priv->eq_table.icm_page);
}
-int __devinit mlx4_init_eq_table(struct mlx4_dev *dev)
+int mlx4_init_eq_table(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int err;
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
index c45cbe43a0c..50648738d67 100644
--- a/drivers/net/mlx4/fw.c
+++ b/drivers/net/mlx4/fw.c
@@ -76,7 +76,7 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u32 flags)
[ 0] = "RC transport",
[ 1] = "UC transport",
[ 2] = "UD transport",
- [ 3] = "SRC transport",
+ [ 3] = "XRC transport",
[ 4] = "reliable multicast",
[ 5] = "FCoIB support",
[ 6] = "SRQ support",
@@ -736,7 +736,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
MLX4_PUT(inbox, (u8) (PAGE_SHIFT - 12), INIT_HCA_UAR_PAGE_SZ_OFFSET);
MLX4_PUT(inbox, param->log_uar_sz, INIT_HCA_LOG_UAR_SZ_OFFSET);
- err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 1000);
+ err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 10000);
if (err)
mlx4_err(dev, "INIT_HCA returns %d\n", err);
diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c
index b7a4aa8476f..2a5bef6388f 100644
--- a/drivers/net/mlx4/icm.c
+++ b/drivers/net/mlx4/icm.c
@@ -34,6 +34,7 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/mm.h>
+#include <linux/scatterlist.h>
#include <linux/mlx4/cmd.h>
@@ -50,19 +51,41 @@ enum {
MLX4_TABLE_CHUNK_SIZE = 1 << 18
};
-void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm)
+static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk)
{
- struct mlx4_icm_chunk *chunk, *tmp;
int i;
- list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) {
- if (chunk->nsg > 0)
- pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages,
- PCI_DMA_BIDIRECTIONAL);
+ if (chunk->nsg > 0)
+ pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages,
+ PCI_DMA_BIDIRECTIONAL);
+
+ for (i = 0; i < chunk->npages; ++i)
+ __free_pages(sg_page(&chunk->mem[i]),
+ get_order(chunk->mem[i].length));
+}
+
+static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk)
+{
+ int i;
+
+ for (i = 0; i < chunk->npages; ++i)
+ dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length,
+ lowmem_page_address(sg_page(&chunk->mem[i])),
+ sg_dma_address(&chunk->mem[i]));
+}
+
+void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent)
+{
+ struct mlx4_icm_chunk *chunk, *tmp;
- for (i = 0; i < chunk->npages; ++i)
- __free_pages(chunk->mem[i].page,
- get_order(chunk->mem[i].length));
+ if (!icm)
+ return;
+
+ list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) {
+ if (coherent)
+ mlx4_free_icm_coherent(dev, chunk);
+ else
+ mlx4_free_icm_pages(dev, chunk);
kfree(chunk);
}
@@ -70,16 +93,46 @@ void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm)
kfree(icm);
}
+static int mlx4_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask)
+{
+ struct page *page;
+
+ page = alloc_pages(gfp_mask, order);
+ if (!page)
+ return -ENOMEM;
+
+ sg_set_page(mem, page, PAGE_SIZE << order, 0);
+ return 0;
+}
+
+static int mlx4_alloc_icm_coherent(struct device *dev, struct scatterlist *mem,
+ int order, gfp_t gfp_mask)
+{
+ void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order,
+ &sg_dma_address(mem), gfp_mask);
+ if (!buf)
+ return -ENOMEM;
+
+ sg_set_buf(mem, buf, PAGE_SIZE << order);
+ BUG_ON(mem->offset);
+ sg_dma_len(mem) = PAGE_SIZE << order;
+ return 0;
+}
+
struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
- gfp_t gfp_mask)
+ gfp_t gfp_mask, int coherent)
{
struct mlx4_icm *icm;
struct mlx4_icm_chunk *chunk = NULL;
int cur_order;
+ int ret;
+
+ /* We use sg_set_buf for coherent allocs, which assumes low memory */
+ BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM));
icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
if (!icm)
- return icm;
+ return NULL;
icm->refcount = 0;
INIT_LIST_HEAD(&icm->chunk_list);
@@ -93,6 +146,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
if (!chunk)
goto fail;
+ sg_init_table(chunk->mem, MLX4_ICM_CHUNK_LEN);
chunk->npages = 0;
chunk->nsg = 0;
list_add_tail(&chunk->list, &icm->chunk_list);
@@ -101,12 +155,20 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
while (1 << cur_order > npages)
--cur_order;
- chunk->mem[chunk->npages].page = alloc_pages(gfp_mask, cur_order);
- if (chunk->mem[chunk->npages].page) {
- chunk->mem[chunk->npages].length = PAGE_SIZE << cur_order;
- chunk->mem[chunk->npages].offset = 0;
+ if (coherent)
+ ret = mlx4_alloc_icm_coherent(&dev->pdev->dev,
+ &chunk->mem[chunk->npages],
+ cur_order, gfp_mask);
+ else
+ ret = mlx4_alloc_icm_pages(&chunk->mem[chunk->npages],
+ cur_order, gfp_mask);
- if (++chunk->npages == MLX4_ICM_CHUNK_LEN) {
+ if (!ret) {
+ ++chunk->npages;
+
+ if (coherent)
+ ++chunk->nsg;
+ else if (chunk->npages == MLX4_ICM_CHUNK_LEN) {
chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
chunk->npages,
PCI_DMA_BIDIRECTIONAL);
@@ -125,7 +187,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
}
}
- if (chunk) {
+ if (!coherent && chunk) {
chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
chunk->npages,
PCI_DMA_BIDIRECTIONAL);
@@ -137,7 +199,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
return icm;
fail:
- mlx4_free_icm(dev, icm);
+ mlx4_free_icm(dev, icm, coherent);
return NULL;
}
@@ -202,7 +264,7 @@ int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj)
table->icm[i] = mlx4_alloc_icm(dev, MLX4_TABLE_CHUNK_SIZE >> PAGE_SHIFT,
(table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
- __GFP_NOWARN);
+ __GFP_NOWARN, table->coherent);
if (!table->icm[i]) {
ret = -ENOMEM;
goto out;
@@ -210,7 +272,7 @@ int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj)
if (mlx4_MAP_ICM(dev, table->icm[i], table->virt +
(u64) i * MLX4_TABLE_CHUNK_SIZE)) {
- mlx4_free_icm(dev, table->icm[i]);
+ mlx4_free_icm(dev, table->icm[i], table->coherent);
table->icm[i] = NULL;
ret = -ENOMEM;
goto out;
@@ -234,16 +296,16 @@ void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj)
if (--table->icm[i]->refcount == 0) {
mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE,
MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
- mlx4_free_icm(dev, table->icm[i]);
+ mlx4_free_icm(dev, table->icm[i], table->coherent);
table->icm[i] = NULL;
}
mutex_unlock(&table->mutex);
}
-void *mlx4_table_find(struct mlx4_icm_table *table, int obj)
+void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle)
{
- int idx, offset, i;
+ int idx, offset, dma_offset, i;
struct mlx4_icm_chunk *chunk;
struct mlx4_icm *icm;
struct page *page = NULL;
@@ -253,17 +315,28 @@ void *mlx4_table_find(struct mlx4_icm_table *table, int obj)
mutex_lock(&table->mutex);
- idx = obj & (table->num_obj - 1);
- icm = table->icm[idx / (MLX4_TABLE_CHUNK_SIZE / table->obj_size)];
- offset = idx % (MLX4_TABLE_CHUNK_SIZE / table->obj_size);
+ idx = (obj & (table->num_obj - 1)) * table->obj_size;
+ icm = table->icm[idx / MLX4_TABLE_CHUNK_SIZE];
+ dma_offset = offset = idx % MLX4_TABLE_CHUNK_SIZE;
if (!icm)
goto out;
list_for_each_entry(chunk, &icm->chunk_list, list) {
for (i = 0; i < chunk->npages; ++i) {
+ if (dma_handle && dma_offset >= 0) {
+ if (sg_dma_len(&chunk->mem[i]) > dma_offset)
+ *dma_handle = sg_dma_address(&chunk->mem[i]) +
+ dma_offset;
+ dma_offset -= sg_dma_len(&chunk->mem[i]);
+ }
+ /*
+ * DMA mapping can merge pages but not split them,
+ * so if we found the page, dma_handle has already
+ * been assigned to.
+ */
if (chunk->mem[i].length > offset) {
- page = chunk->mem[i].page;
+ page = sg_page(&chunk->mem[i]);
goto out;
}
offset -= chunk->mem[i].length;
@@ -309,7 +382,7 @@ void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
u64 virt, int obj_size, int nobj, int reserved,
- int use_lowmem)
+ int use_lowmem, int use_coherent)
{
int obj_per_chunk;
int num_icm;
@@ -327,6 +400,7 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
table->num_obj = nobj;
table->obj_size = obj_size;
table->lowmem = use_lowmem;
+ table->coherent = use_coherent;
mutex_init(&table->mutex);
for (i = 0; i * MLX4_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) {
@@ -336,11 +410,11 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
table->icm[i] = mlx4_alloc_icm(dev, chunk_size >> PAGE_SHIFT,
(use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
- __GFP_NOWARN);
+ __GFP_NOWARN, use_coherent);
if (!table->icm[i])
goto err;
if (mlx4_MAP_ICM(dev, table->icm[i], virt + i * MLX4_TABLE_CHUNK_SIZE)) {
- mlx4_free_icm(dev, table->icm[i]);
+ mlx4_free_icm(dev, table->icm[i], use_coherent);
table->icm[i] = NULL;
goto err;
}
@@ -359,7 +433,7 @@ err:
if (table->icm[i]) {
mlx4_UNMAP_ICM(dev, virt + i * MLX4_TABLE_CHUNK_SIZE,
MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
- mlx4_free_icm(dev, table->icm[i]);
+ mlx4_free_icm(dev, table->icm[i], use_coherent);
}
return -ENOMEM;
@@ -373,7 +447,7 @@ void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table)
if (table->icm[i]) {
mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE,
MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
- mlx4_free_icm(dev, table->icm[i]);
+ mlx4_free_icm(dev, table->icm[i], table->coherent);
}
kfree(table->icm);
diff --git a/drivers/net/mlx4/icm.h b/drivers/net/mlx4/icm.h
index bea223d879a..6c44edf3584 100644
--- a/drivers/net/mlx4/icm.h
+++ b/drivers/net/mlx4/icm.h
@@ -67,8 +67,9 @@ struct mlx4_icm_iter {
struct mlx4_dev;
-struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, gfp_t gfp_mask);
-void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm);
+struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
+ gfp_t gfp_mask, int coherent);
+void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent);
int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
@@ -78,11 +79,11 @@ void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
int start, int end);
int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
u64 virt, int obj_size, int nobj, int reserved,
- int use_lowmem);
+ int use_lowmem, int use_coherent);
void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table);
int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
-void *mlx4_table_find(struct mlx4_icm_table *table, int obj);
+void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle);
int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
int start, int end);
void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 4dc9dc19b71..89b3f0b7cdc 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -61,7 +61,7 @@ MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0");
#ifdef CONFIG_PCI_MSI
-static int msi_x;
+static int msi_x = 1;
module_param(msi_x, int, 0444);
MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
@@ -85,7 +85,7 @@ static struct mlx4_profile default_profile = {
.num_mtt = 1 << 20,
};
-static int __devinit mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
+static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
{
int err;
int i;
@@ -149,7 +149,8 @@ static int __devinit mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev
dev->caps.max_cqes = dev_cap->max_cq_sz - 1;
dev->caps.reserved_cqs = dev_cap->reserved_cqs;
dev->caps.reserved_eqs = dev_cap->reserved_eqs;
- dev->caps.reserved_mtts = dev_cap->reserved_mtts;
+ dev->caps.reserved_mtts = DIV_ROUND_UP(dev_cap->reserved_mtts,
+ MLX4_MTT_ENTRY_PER_SEG);
dev->caps.reserved_mrws = dev_cap->reserved_mrws;
dev->caps.reserved_uars = dev_cap->reserved_uars;
dev->caps.reserved_pds = dev_cap->reserved_pds;
@@ -168,7 +169,7 @@ static int __devinit mlx4_load_fw(struct mlx4_dev *dev)
int err;
priv->fw.fw_icm = mlx4_alloc_icm(dev, priv->fw.fw_pages,
- GFP_HIGHUSER | __GFP_NOWARN);
+ GFP_HIGHUSER | __GFP_NOWARN, 0);
if (!priv->fw.fw_icm) {
mlx4_err(dev, "Couldn't allocate FW area, aborting.\n");
return -ENOMEM;
@@ -192,7 +193,7 @@ err_unmap_fa:
mlx4_UNMAP_FA(dev);
err_free:
- mlx4_free_icm(dev, priv->fw.fw_icm);
+ mlx4_free_icm(dev, priv->fw.fw_icm, 0);
return err;
}
@@ -207,7 +208,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
((u64) (MLX4_CMPT_TYPE_QP *
cmpt_entry_sz) << MLX4_CMPT_SHIFT),
cmpt_entry_sz, dev->caps.num_qps,
- dev->caps.reserved_qps, 0);
+ dev->caps.reserved_qps, 0, 0);
if (err)
goto err;
@@ -216,7 +217,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
((u64) (MLX4_CMPT_TYPE_SRQ *
cmpt_entry_sz) << MLX4_CMPT_SHIFT),
cmpt_entry_sz, dev->caps.num_srqs,
- dev->caps.reserved_srqs, 0);
+ dev->caps.reserved_srqs, 0, 0);
if (err)
goto err_qp;
@@ -225,7 +226,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
((u64) (MLX4_CMPT_TYPE_CQ *
cmpt_entry_sz) << MLX4_CMPT_SHIFT),
cmpt_entry_sz, dev->caps.num_cqs,
- dev->caps.reserved_cqs, 0);
+ dev->caps.reserved_cqs, 0, 0);
if (err)
goto err_srq;
@@ -236,7 +237,7 @@ static int __devinit mlx4_init_cmpt_table(struct mlx4_dev *dev, u64 cmpt_base,
cmpt_entry_sz,
roundup_pow_of_two(MLX4_NUM_EQ +
dev->caps.reserved_eqs),
- MLX4_NUM_EQ + dev->caps.reserved_eqs, 0);
+ MLX4_NUM_EQ + dev->caps.reserved_eqs, 0, 0);
if (err)
goto err_cq;
@@ -255,10 +256,8 @@ err:
return err;
}
-static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
- struct mlx4_dev_cap *dev_cap,
- struct mlx4_init_hca_param *init_hca,
- u64 icm_size)
+static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap,
+ struct mlx4_init_hca_param *init_hca, u64 icm_size)
{
struct mlx4_priv *priv = mlx4_priv(dev);
u64 aux_pages;
@@ -275,7 +274,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
(unsigned long long) aux_pages << 2);
priv->fw.aux_icm = mlx4_alloc_icm(dev, aux_pages,
- GFP_HIGHUSER | __GFP_NOWARN);
+ GFP_HIGHUSER | __GFP_NOWARN, 0);
if (!priv->fw.aux_icm) {
mlx4_err(dev, "Couldn't allocate aux memory, aborting.\n");
return -ENOMEM;
@@ -299,11 +298,22 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
goto err_unmap_cmpt;
}
+ /*
+ * Reserved MTT entries must be aligned up to a cacheline
+ * boundary, since the FW will write to them, while the driver
+ * writes to all other MTT entries. (The variable
+ * dev->caps.mtt_entry_sz below is really the MTT segment
+ * size, not the raw entry size)
+ */
+ dev->caps.reserved_mtts =
+ ALIGN(dev->caps.reserved_mtts * dev->caps.mtt_entry_sz,
+ dma_get_cache_alignment()) / dev->caps.mtt_entry_sz;
+
err = mlx4_init_icm_table(dev, &priv->mr_table.mtt_table,
init_hca->mtt_base,
dev->caps.mtt_entry_sz,
dev->caps.num_mtt_segs,
- dev->caps.reserved_mtts, 1);
+ dev->caps.reserved_mtts, 1, 0);
if (err) {
mlx4_err(dev, "Failed to map MTT context memory, aborting.\n");
goto err_unmap_eq;
@@ -313,7 +323,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->dmpt_base,
dev_cap->dmpt_entry_sz,
dev->caps.num_mpts,
- dev->caps.reserved_mrws, 1);
+ dev->caps.reserved_mrws, 1, 1);
if (err) {
mlx4_err(dev, "Failed to map dMPT context memory, aborting.\n");
goto err_unmap_mtt;
@@ -323,7 +333,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->qpc_base,
dev_cap->qpc_entry_sz,
dev->caps.num_qps,
- dev->caps.reserved_qps, 0);
+ dev->caps.reserved_qps, 0, 0);
if (err) {
mlx4_err(dev, "Failed to map QP context memory, aborting.\n");
goto err_unmap_dmpt;
@@ -333,7 +343,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->auxc_base,
dev_cap->aux_entry_sz,
dev->caps.num_qps,
- dev->caps.reserved_qps, 0);
+ dev->caps.reserved_qps, 0, 0);
if (err) {
mlx4_err(dev, "Failed to map AUXC context memory, aborting.\n");
goto err_unmap_qp;
@@ -343,7 +353,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->altc_base,
dev_cap->altc_entry_sz,
dev->caps.num_qps,
- dev->caps.reserved_qps, 0);
+ dev->caps.reserved_qps, 0, 0);
if (err) {
mlx4_err(dev, "Failed to map ALTC context memory, aborting.\n");
goto err_unmap_auxc;
@@ -353,7 +363,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->rdmarc_base,
dev_cap->rdmarc_entry_sz << priv->qp_table.rdmarc_shift,
dev->caps.num_qps,
- dev->caps.reserved_qps, 0);
+ dev->caps.reserved_qps, 0, 0);
if (err) {
mlx4_err(dev, "Failed to map RDMARC context memory, aborting\n");
goto err_unmap_altc;
@@ -363,7 +373,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->cqc_base,
dev_cap->cqc_entry_sz,
dev->caps.num_cqs,
- dev->caps.reserved_cqs, 0);
+ dev->caps.reserved_cqs, 0, 0);
if (err) {
mlx4_err(dev, "Failed to map CQ context memory, aborting.\n");
goto err_unmap_rdmarc;
@@ -373,7 +383,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->srqc_base,
dev_cap->srq_entry_sz,
dev->caps.num_srqs,
- dev->caps.reserved_srqs, 0);
+ dev->caps.reserved_srqs, 0, 0);
if (err) {
mlx4_err(dev, "Failed to map SRQ context memory, aborting.\n");
goto err_unmap_cq;
@@ -388,7 +398,7 @@ static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
init_hca->mc_base, MLX4_MGM_ENTRY_SIZE,
dev->caps.num_mgms + dev->caps.num_amgms,
dev->caps.num_mgms + dev->caps.num_amgms,
- 0);
+ 0, 0);
if (err) {
mlx4_err(dev, "Failed to map MCG context memory, aborting.\n");
goto err_unmap_srq;
@@ -433,7 +443,7 @@ err_unmap_aux:
mlx4_UNMAP_ICM_AUX(dev);
err_free_aux:
- mlx4_free_icm(dev, priv->fw.aux_icm);
+ mlx4_free_icm(dev, priv->fw.aux_icm, 0);
return err;
}
@@ -458,7 +468,7 @@ static void mlx4_free_icms(struct mlx4_dev *dev)
mlx4_unmap_eq_icm(dev);
mlx4_UNMAP_ICM_AUX(dev);
- mlx4_free_icm(dev, priv->fw.aux_icm);
+ mlx4_free_icm(dev, priv->fw.aux_icm, 0);
}
static void mlx4_close_hca(struct mlx4_dev *dev)
@@ -466,10 +476,10 @@ static void mlx4_close_hca(struct mlx4_dev *dev)
mlx4_CLOSE_HCA(dev, 0);
mlx4_free_icms(dev);
mlx4_UNMAP_FA(dev);
- mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm);
+ mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0);
}
-static int __devinit mlx4_init_hca(struct mlx4_dev *dev)
+static int mlx4_init_hca(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_adapter adapter;
@@ -524,8 +534,8 @@ static int __devinit mlx4_init_hca(struct mlx4_dev *dev)
}
priv->eq_table.inta_pin = adapter.inta_pin;
- priv->rev_id = adapter.revision_id;
- memcpy(priv->board_id, adapter.board_id, sizeof priv->board_id);
+ dev->rev_id = adapter.revision_id;
+ memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id);
return 0;
@@ -537,12 +547,12 @@ err_free_icm:
err_stop_fw:
mlx4_UNMAP_FA(dev);
- mlx4_free_icm(dev, priv->fw.fw_icm);
+ mlx4_free_icm(dev, priv->fw.fw_icm, 0);
return err;
}
-static int __devinit mlx4_setup_hca(struct mlx4_dev *dev)
+static int mlx4_setup_hca(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int err;
@@ -599,13 +609,17 @@ static int __devinit mlx4_setup_hca(struct mlx4_dev *dev)
err = mlx4_NOP(dev);
if (err) {
- mlx4_err(dev, "NOP command failed to generate interrupt "
- "(IRQ %d), aborting.\n",
- priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
- if (dev->flags & MLX4_FLAG_MSI_X)
- mlx4_err(dev, "Try again with MSI-X disabled.\n");
- else
+ if (dev->flags & MLX4_FLAG_MSI_X) {
+ mlx4_warn(dev, "NOP command failed to generate MSI-X "
+ "interrupt IRQ %d).\n",
+ priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
+ mlx4_warn(dev, "Trying again without MSI-X.\n");
+ } else {
+ mlx4_err(dev, "NOP command failed to generate interrupt "
+ "(IRQ %d), aborting.\n",
+ priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n");
+ }
goto err_cmd_poll;
}
@@ -705,19 +719,12 @@ no_msi:
priv->eq_table.eq[i].irq = dev->pdev->irq;
}
-static int __devinit mlx4_init_one(struct pci_dev *pdev,
- const struct pci_device_id *id)
+static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
- static int mlx4_version_printed;
struct mlx4_priv *priv;
struct mlx4_dev *dev;
int err;
- if (!mlx4_version_printed) {
- printk(KERN_INFO "%s", mlx4_version);
- ++mlx4_version_printed;
- }
-
printk(KERN_INFO PFX "Initializing %s\n",
pci_name(pdev));
@@ -803,8 +810,6 @@ static int __devinit mlx4_init_one(struct pci_dev *pdev,
goto err_free_dev;
}
- mlx4_enable_msi_x(dev);
-
if (mlx4_cmd_init(dev)) {
mlx4_err(dev, "Failed to init command interface, aborting.\n");
goto err_free_dev;
@@ -814,7 +819,15 @@ static int __devinit mlx4_init_one(struct pci_dev *pdev,
if (err)
goto err_cmd;
+ mlx4_enable_msi_x(dev);
+
err = mlx4_setup_hca(dev);
+ if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) {
+ dev->flags &= ~MLX4_FLAG_MSI_X;
+ pci_disable_msix(pdev);
+ err = mlx4_setup_hca(dev);
+ }
+
if (err)
goto err_close;
@@ -838,15 +851,15 @@ err_cleanup:
mlx4_cleanup_uar_table(dev);
err_close:
+ if (dev->flags & MLX4_FLAG_MSI_X)
+ pci_disable_msix(pdev);
+
mlx4_close_hca(dev);
err_cmd:
mlx4_cmd_cleanup(dev);
err_free_dev:
- if (dev->flags & MLX4_FLAG_MSI_X)
- pci_disable_msix(pdev);
-
kfree(priv);
err_release_bar2:
@@ -861,7 +874,20 @@ err_disable_pdev:
return err;
}
-static void __devexit mlx4_remove_one(struct pci_dev *pdev)
+static int __devinit mlx4_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ static int mlx4_version_printed;
+
+ if (!mlx4_version_printed) {
+ printk(KERN_INFO "%s", mlx4_version);
+ ++mlx4_version_printed;
+ }
+
+ return __mlx4_init_one(pdev, id);
+}
+
+static void mlx4_remove_one(struct pci_dev *pdev)
{
struct mlx4_dev *dev = pci_get_drvdata(pdev);
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -902,7 +928,7 @@ static void __devexit mlx4_remove_one(struct pci_dev *pdev)
int mlx4_restart_one(struct pci_dev *pdev)
{
mlx4_remove_one(pdev);
- return mlx4_init_one(pdev, NULL);
+ return __mlx4_init_one(pdev, NULL);
}
static struct pci_device_id mlx4_pci_table[] = {
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c
index 672024a0ee7..a99e7729d33 100644
--- a/drivers/net/mlx4/mcg.c
+++ b/drivers/net/mlx4/mcg.c
@@ -359,7 +359,7 @@ out:
}
EXPORT_SYMBOL_GPL(mlx4_multicast_detach);
-int __devinit mlx4_init_mcg_table(struct mlx4_dev *dev)
+int mlx4_init_mcg_table(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int err;
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index be304a7c2c9..53a1cdddfc1 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -56,11 +56,7 @@ enum {
};
enum {
- MLX4_BOARD_ID_LEN = 64
-};
-
-enum {
- MLX4_MGM_ENTRY_SIZE = 0x40,
+ MLX4_MGM_ENTRY_SIZE = 0x100,
MLX4_QP_PER_MGM = 4 * (MLX4_MGM_ENTRY_SIZE / 16 - 2),
MLX4_MTT_ENTRY_PER_SEG = 8
};
@@ -133,6 +129,7 @@ struct mlx4_icm_table {
int num_obj;
int obj_size;
int lowmem;
+ int coherent;
struct mutex mutex;
struct mlx4_icm **icm;
};
@@ -277,9 +274,6 @@ struct mlx4_priv {
struct mlx4_uar driver_uar;
void __iomem *kar;
-
- u32 rev_id;
- char board_id[MLX4_BOARD_ID_LEN];
};
static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index 5b87183e62c..0c05a10bae3 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -68,6 +68,9 @@ struct mlx4_mpt_entry {
#define MLX4_MTT_FLAG_PRESENT 1
+#define MLX4_MPT_STATUS_SW 0xF0
+#define MLX4_MPT_STATUS_HW 0x00
+
static u32 mlx4_buddy_alloc(struct mlx4_buddy *buddy, int order)
{
int o;
@@ -349,58 +352,57 @@ err_table:
}
EXPORT_SYMBOL_GPL(mlx4_mr_enable);
-static int mlx4_WRITE_MTT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
- int num_mtt)
+static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
+ int start_index, int npages, u64 *page_list)
{
- return mlx4_cmd(dev, mailbox->dma, num_mtt, 0, MLX4_CMD_WRITE_MTT,
- MLX4_CMD_TIME_CLASS_B);
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ __be64 *mtts;
+ dma_addr_t dma_handle;
+ int i;
+ int s = start_index * sizeof (u64);
+
+ /* All MTTs must fit in the same page */
+ if (start_index / (PAGE_SIZE / sizeof (u64)) !=
+ (start_index + npages - 1) / (PAGE_SIZE / sizeof (u64)))
+ return -EINVAL;
+
+ if (start_index & (MLX4_MTT_ENTRY_PER_SEG - 1))
+ return -EINVAL;
+
+ mtts = mlx4_table_find(&priv->mr_table.mtt_table, mtt->first_seg +
+ s / dev->caps.mtt_entry_sz, &dma_handle);
+ if (!mtts)
+ return -ENOMEM;
+
+ for (i = 0; i < npages; ++i)
+ mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
+
+ dma_sync_single(&dev->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE);
+
+ return 0;
}
int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
int start_index, int npages, u64 *page_list)
{
- struct mlx4_cmd_mailbox *mailbox;
- __be64 *mtt_entry;
- int i;
- int err = 0;
+ int chunk;
+ int err;
if (mtt->order < 0)
return -EINVAL;
- mailbox = mlx4_alloc_cmd_mailbox(dev);
- if (IS_ERR(mailbox))
- return PTR_ERR(mailbox);
-
- mtt_entry = mailbox->buf;
-
while (npages > 0) {
- mtt_entry[0] = cpu_to_be64(mlx4_mtt_addr(dev, mtt) + start_index * 8);
- mtt_entry[1] = 0;
-
- for (i = 0; i < npages && i < MLX4_MAILBOX_SIZE / 8 - 2; ++i)
- mtt_entry[i + 2] = cpu_to_be64(page_list[i] |
- MLX4_MTT_FLAG_PRESENT);
-
- /*
- * If we have an odd number of entries to write, add
- * one more dummy entry for firmware efficiency.
- */
- if (i & 1)
- mtt_entry[i + 2] = 0;
-
- err = mlx4_WRITE_MTT(dev, mailbox, (i + 1) & ~1);
+ chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages);
+ err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list);
if (err)
- goto out;
+ return err;
- npages -= i;
- start_index += i;
- page_list += i;
+ npages -= chunk;
+ start_index += chunk;
+ page_list += chunk;
}
-out:
- mlx4_free_cmd_mailbox(dev, mailbox);
-
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(mlx4_write_mtt);
@@ -428,7 +430,7 @@ int mlx4_buf_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
}
EXPORT_SYMBOL_GPL(mlx4_buf_write_mtt);
-int __devinit mlx4_init_mr_table(struct mlx4_dev *dev)
+int mlx4_init_mr_table(struct mlx4_dev *dev)
{
struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
int err;
@@ -444,7 +446,7 @@ int __devinit mlx4_init_mr_table(struct mlx4_dev *dev)
goto err_buddy;
if (dev->caps.reserved_mtts) {
- if (mlx4_alloc_mtt_range(dev, ilog2(dev->caps.reserved_mtts)) == -1) {
+ if (mlx4_alloc_mtt_range(dev, fls(dev->caps.reserved_mtts - 1)) == -1) {
mlx4_warn(dev, "MTT table of order %d is too small.\n",
mr_table->mtt_buddy.max_order);
err = -ENOMEM;
@@ -470,3 +472,165 @@ void mlx4_cleanup_mr_table(struct mlx4_dev *dev)
mlx4_buddy_cleanup(&mr_table->mtt_buddy);
mlx4_bitmap_cleanup(&mr_table->mpt_bitmap);
}
+
+static inline int mlx4_check_fmr(struct mlx4_fmr *fmr, u64 *page_list,
+ int npages, u64 iova)
+{
+ int i, page_mask;
+
+ if (npages > fmr->max_pages)
+ return -EINVAL;
+
+ page_mask = (1 << fmr->page_shift) - 1;
+
+ /* We are getting page lists, so va must be page aligned. */
+ if (iova & page_mask)
+ return -EINVAL;
+
+ /* Trust the user not to pass misaligned data in page_list */
+ if (0)
+ for (i = 0; i < npages; ++i) {
+ if (page_list[i] & ~page_mask)
+ return -EINVAL;
+ }
+
+ if (fmr->maps >= fmr->max_maps)
+ return -EINVAL;
+
+ return 0;
+}
+
+int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list,
+ int npages, u64 iova, u32 *lkey, u32 *rkey)
+{
+ u32 key;
+ int i, err;
+
+ err = mlx4_check_fmr(fmr, page_list, npages, iova);
+ if (err)
+ return err;
+
+ ++fmr->maps;
+
+ key = key_to_hw_index(fmr->mr.key);
+ key += dev->caps.num_mpts;
+ *lkey = *rkey = fmr->mr.key = hw_index_to_key(key);
+
+ *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW;
+
+ /* Make sure MPT status is visible before writing MTT entries */
+ wmb();
+
+ for (i = 0; i < npages; ++i)
+ fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
+
+ dma_sync_single(&dev->pdev->dev, fmr->dma_handle,
+ npages * sizeof(u64), DMA_TO_DEVICE);
+
+ fmr->mpt->key = cpu_to_be32(key);
+ fmr->mpt->lkey = cpu_to_be32(key);
+ fmr->mpt->length = cpu_to_be64(npages * (1ull << fmr->page_shift));
+ fmr->mpt->start = cpu_to_be64(iova);
+
+ /* Make MTT entries are visible before setting MPT status */
+ wmb();
+
+ *(u8 *) fmr->mpt = MLX4_MPT_STATUS_HW;
+
+ /* Make sure MPT status is visible before consumer can use FMR */
+ wmb();
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_map_phys_fmr);
+
+int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages,
+ int max_maps, u8 page_shift, struct mlx4_fmr *fmr)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ u64 mtt_seg;
+ int err = -ENOMEM;
+
+ if (page_shift < 12 || page_shift >= 32)
+ return -EINVAL;
+
+ /* All MTTs must fit in the same page */
+ if (max_pages * sizeof *fmr->mtts > PAGE_SIZE)
+ return -EINVAL;
+
+ fmr->page_shift = page_shift;
+ fmr->max_pages = max_pages;
+ fmr->max_maps = max_maps;
+ fmr->maps = 0;
+
+ err = mlx4_mr_alloc(dev, pd, 0, 0, access, max_pages,
+ page_shift, &fmr->mr);
+ if (err)
+ return err;
+
+ mtt_seg = fmr->mr.mtt.first_seg * dev->caps.mtt_entry_sz;
+
+ fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table,
+ fmr->mr.mtt.first_seg,
+ &fmr->dma_handle);
+ if (!fmr->mtts) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ fmr->mpt = mlx4_table_find(&priv->mr_table.dmpt_table,
+ key_to_hw_index(fmr->mr.key), NULL);
+ if (!fmr->mpt) {
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ return 0;
+
+err_free:
+ mlx4_mr_free(dev, &fmr->mr);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_fmr_alloc);
+
+int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr)
+{
+ return mlx4_mr_enable(dev, &fmr->mr);
+}
+EXPORT_SYMBOL_GPL(mlx4_fmr_enable);
+
+void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr,
+ u32 *lkey, u32 *rkey)
+{
+ u32 key;
+
+ if (!fmr->maps)
+ return;
+
+ key = key_to_hw_index(fmr->mr.key);
+ key &= dev->caps.num_mpts - 1;
+ *lkey = *rkey = fmr->mr.key = hw_index_to_key(key);
+
+ fmr->maps = 0;
+
+ *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW;
+}
+EXPORT_SYMBOL_GPL(mlx4_fmr_unmap);
+
+int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr)
+{
+ if (fmr->maps)
+ return -EBUSY;
+
+ fmr->mr.enabled = 0;
+ mlx4_mr_free(dev, &fmr->mr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_fmr_free);
+
+int mlx4_SYNC_TPT(struct mlx4_dev *dev)
+{
+ return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000);
+}
+EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT);
diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c
index 23dea1ee775..3a93c5f0f7a 100644
--- a/drivers/net/mlx4/pd.c
+++ b/drivers/net/mlx4/pd.c
@@ -57,7 +57,7 @@ void mlx4_pd_free(struct mlx4_dev *dev, u32 pdn)
}
EXPORT_SYMBOL_GPL(mlx4_pd_free);
-int __devinit mlx4_init_pd_table(struct mlx4_dev *dev)
+int mlx4_init_pd_table(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c
index 19b48c71cf7..42b47639c81 100644
--- a/drivers/net/mlx4/qp.c
+++ b/drivers/net/mlx4/qp.c
@@ -240,7 +240,8 @@ void mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp)
mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn);
mlx4_table_put(dev, &qp_table->qp_table, qp->qpn);
- mlx4_bitmap_free(&qp_table->bitmap, qp->qpn);
+ if (qp->qpn >= dev->caps.sqp_start + 8)
+ mlx4_bitmap_free(&qp_table->bitmap, qp->qpn);
}
EXPORT_SYMBOL_GPL(mlx4_qp_free);
@@ -250,7 +251,7 @@ static int mlx4_CONF_SPECIAL_QP(struct mlx4_dev *dev, u32 base_qpn)
MLX4_CMD_TIME_CLASS_B);
}
-int __devinit mlx4_init_qp_table(struct mlx4_dev *dev)
+int mlx4_init_qp_table(struct mlx4_dev *dev)
{
struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
int err;
diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c
index b061c86d683..d23f46d692e 100644
--- a/drivers/net/mlx4/srq.c
+++ b/drivers/net/mlx4/srq.c
@@ -227,7 +227,7 @@ int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_waterm
err = mlx4_QUERY_SRQ(dev, mailbox, srq->srqn);
if (err)
goto err_out;
- *limit_watermark = srq_context->limit_watermark;
+ *limit_watermark = be16_to_cpu(srq_context->limit_watermark);
err_out:
mlx4_free_cmd_mailbox(dev, mailbox);
@@ -235,7 +235,7 @@ err_out:
}
EXPORT_SYMBOL_GPL(mlx4_srq_query);
-int __devinit mlx4_init_srq_table(struct mlx4_dev *dev)
+int mlx4_init_srq_table(struct mlx4_dev *dev)
{
struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
int err;
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 315335671f0..651c2699d5e 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1,5 +1,5 @@
/*
- * drivers/net/mv643xx_eth.c - Driver for MV643XX ethernet ports
+ * Driver for Marvell Discovery (MV643XX) and Marvell Orion ethernet ports
* Copyright (C) 2002 Matthew Dharm <mdharm@momenco.com>
*
* Based on the 64360 driver from:
@@ -43,14 +43,567 @@
#include <linux/ethtool.h>
#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+
+#include <linux/mv643xx_eth.h>
+
#include <asm/io.h>
#include <asm/types.h>
#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/delay.h>
-#include "mv643xx_eth.h"
+#include <asm/dma-mapping.h>
+
+#define MV643XX_CHECKSUM_OFFLOAD_TX
+#define MV643XX_NAPI
+#define MV643XX_TX_FAST_REFILL
+#undef MV643XX_COAL
+
+/*
+ * Number of RX / TX descriptors on RX / TX rings.
+ * Note that allocating RX descriptors is done by allocating the RX
+ * ring AND a preallocated RX buffers (skb's) for each descriptor.
+ * The TX descriptors only allocates the TX descriptors ring,
+ * with no pre allocated TX buffers (skb's are allocated by higher layers.
+ */
+
+/* Default TX ring size is 1000 descriptors */
+#define MV643XX_DEFAULT_TX_QUEUE_SIZE 1000
+
+/* Default RX ring size is 400 descriptors */
+#define MV643XX_DEFAULT_RX_QUEUE_SIZE 400
+
+#define MV643XX_TX_COAL 100
+#ifdef MV643XX_COAL
+#define MV643XX_RX_COAL 100
+#endif
+
+#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
+#define MAX_DESCS_PER_SKB (MAX_SKB_FRAGS + 1)
+#else
+#define MAX_DESCS_PER_SKB 1
+#endif
+
+#define ETH_VLAN_HLEN 4
+#define ETH_FCS_LEN 4
+#define ETH_HW_IP_ALIGN 2 /* hw aligns IP header */
+#define ETH_WRAPPER_LEN (ETH_HW_IP_ALIGN + ETH_HLEN + \
+ ETH_VLAN_HLEN + ETH_FCS_LEN)
+#define ETH_RX_SKB_SIZE (dev->mtu + ETH_WRAPPER_LEN + \
+ dma_get_cache_alignment())
+
+/*
+ * Registers shared between all ports.
+ */
+#define PHY_ADDR_REG 0x0000
+#define SMI_REG 0x0004
+
+/*
+ * Per-port registers.
+ */
+#define PORT_CONFIG_REG(p) (0x0400 + ((p) << 10))
+#define PORT_CONFIG_EXTEND_REG(p) (0x0404 + ((p) << 10))
+#define MAC_ADDR_LOW(p) (0x0414 + ((p) << 10))
+#define MAC_ADDR_HIGH(p) (0x0418 + ((p) << 10))
+#define SDMA_CONFIG_REG(p) (0x041c + ((p) << 10))
+#define PORT_SERIAL_CONTROL_REG(p) (0x043c + ((p) << 10))
+#define PORT_STATUS_REG(p) (0x0444 + ((p) << 10))
+#define TRANSMIT_QUEUE_COMMAND_REG(p) (0x0448 + ((p) << 10))
+#define MAXIMUM_TRANSMIT_UNIT(p) (0x0458 + ((p) << 10))
+#define INTERRUPT_CAUSE_REG(p) (0x0460 + ((p) << 10))
+#define INTERRUPT_CAUSE_EXTEND_REG(p) (0x0464 + ((p) << 10))
+#define INTERRUPT_MASK_REG(p) (0x0468 + ((p) << 10))
+#define INTERRUPT_EXTEND_MASK_REG(p) (0x046c + ((p) << 10))
+#define TX_FIFO_URGENT_THRESHOLD_REG(p) (0x0474 + ((p) << 10))
+#define RX_CURRENT_QUEUE_DESC_PTR_0(p) (0x060c + ((p) << 10))
+#define RECEIVE_QUEUE_COMMAND_REG(p) (0x0680 + ((p) << 10))
+#define TX_CURRENT_QUEUE_DESC_PTR_0(p) (0x06c0 + ((p) << 10))
+#define MIB_COUNTERS_BASE(p) (0x1000 + ((p) << 7))
+#define DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(p) (0x1400 + ((p) << 10))
+#define DA_FILTER_OTHER_MULTICAST_TABLE_BASE(p) (0x1500 + ((p) << 10))
+#define DA_FILTER_UNICAST_TABLE_BASE(p) (0x1600 + ((p) << 10))
+
+/* These macros describe Ethernet Port configuration reg (Px_cR) bits */
+#define UNICAST_NORMAL_MODE (0 << 0)
+#define UNICAST_PROMISCUOUS_MODE (1 << 0)
+#define DEFAULT_RX_QUEUE(queue) ((queue) << 1)
+#define DEFAULT_RX_ARP_QUEUE(queue) ((queue) << 4)
+#define RECEIVE_BC_IF_NOT_IP_OR_ARP (0 << 7)
+#define REJECT_BC_IF_NOT_IP_OR_ARP (1 << 7)
+#define RECEIVE_BC_IF_IP (0 << 8)
+#define REJECT_BC_IF_IP (1 << 8)
+#define RECEIVE_BC_IF_ARP (0 << 9)
+#define REJECT_BC_IF_ARP (1 << 9)
+#define TX_AM_NO_UPDATE_ERROR_SUMMARY (1 << 12)
+#define CAPTURE_TCP_FRAMES_DIS (0 << 14)
+#define CAPTURE_TCP_FRAMES_EN (1 << 14)
+#define CAPTURE_UDP_FRAMES_DIS (0 << 15)
+#define CAPTURE_UDP_FRAMES_EN (1 << 15)
+#define DEFAULT_RX_TCP_QUEUE(queue) ((queue) << 16)
+#define DEFAULT_RX_UDP_QUEUE(queue) ((queue) << 19)
+#define DEFAULT_RX_BPDU_QUEUE(queue) ((queue) << 22)
+
+#define PORT_CONFIG_DEFAULT_VALUE \
+ UNICAST_NORMAL_MODE | \
+ DEFAULT_RX_QUEUE(0) | \
+ DEFAULT_RX_ARP_QUEUE(0) | \
+ RECEIVE_BC_IF_NOT_IP_OR_ARP | \
+ RECEIVE_BC_IF_IP | \
+ RECEIVE_BC_IF_ARP | \
+ CAPTURE_TCP_FRAMES_DIS | \
+ CAPTURE_UDP_FRAMES_DIS | \
+ DEFAULT_RX_TCP_QUEUE(0) | \
+ DEFAULT_RX_UDP_QUEUE(0) | \
+ DEFAULT_RX_BPDU_QUEUE(0)
+
+/* These macros describe Ethernet Port configuration extend reg (Px_cXR) bits*/
+#define CLASSIFY_EN (1 << 0)
+#define SPAN_BPDU_PACKETS_AS_NORMAL (0 << 1)
+#define SPAN_BPDU_PACKETS_TO_RX_QUEUE_7 (1 << 1)
+#define PARTITION_DISABLE (0 << 2)
+#define PARTITION_ENABLE (1 << 2)
+
+#define PORT_CONFIG_EXTEND_DEFAULT_VALUE \
+ SPAN_BPDU_PACKETS_AS_NORMAL | \
+ PARTITION_DISABLE
+
+/* These macros describe Ethernet Port Sdma configuration reg (SDCR) bits */
+#define RIFB (1 << 0)
+#define RX_BURST_SIZE_1_64BIT (0 << 1)
+#define RX_BURST_SIZE_2_64BIT (1 << 1)
+#define RX_BURST_SIZE_4_64BIT (2 << 1)
+#define RX_BURST_SIZE_8_64BIT (3 << 1)
+#define RX_BURST_SIZE_16_64BIT (4 << 1)
+#define BLM_RX_NO_SWAP (1 << 4)
+#define BLM_RX_BYTE_SWAP (0 << 4)
+#define BLM_TX_NO_SWAP (1 << 5)
+#define BLM_TX_BYTE_SWAP (0 << 5)
+#define DESCRIPTORS_BYTE_SWAP (1 << 6)
+#define DESCRIPTORS_NO_SWAP (0 << 6)
+#define IPG_INT_RX(value) (((value) & 0x3fff) << 8)
+#define TX_BURST_SIZE_1_64BIT (0 << 22)
+#define TX_BURST_SIZE_2_64BIT (1 << 22)
+#define TX_BURST_SIZE_4_64BIT (2 << 22)
+#define TX_BURST_SIZE_8_64BIT (3 << 22)
+#define TX_BURST_SIZE_16_64BIT (4 << 22)
+
+#if defined(__BIG_ENDIAN)
+#define PORT_SDMA_CONFIG_DEFAULT_VALUE \
+ RX_BURST_SIZE_4_64BIT | \
+ IPG_INT_RX(0) | \
+ TX_BURST_SIZE_4_64BIT
+#elif defined(__LITTLE_ENDIAN)
+#define PORT_SDMA_CONFIG_DEFAULT_VALUE \
+ RX_BURST_SIZE_4_64BIT | \
+ BLM_RX_NO_SWAP | \
+ BLM_TX_NO_SWAP | \
+ IPG_INT_RX(0) | \
+ TX_BURST_SIZE_4_64BIT
+#else
+#error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined
+#endif
+
+/* These macros describe Ethernet Port serial control reg (PSCR) bits */
+#define SERIAL_PORT_DISABLE (0 << 0)
+#define SERIAL_PORT_ENABLE (1 << 0)
+#define DO_NOT_FORCE_LINK_PASS (0 << 1)
+#define FORCE_LINK_PASS (1 << 1)
+#define ENABLE_AUTO_NEG_FOR_DUPLX (0 << 2)
+#define DISABLE_AUTO_NEG_FOR_DUPLX (1 << 2)
+#define ENABLE_AUTO_NEG_FOR_FLOW_CTRL (0 << 3)
+#define DISABLE_AUTO_NEG_FOR_FLOW_CTRL (1 << 3)
+#define ADV_NO_FLOW_CTRL (0 << 4)
+#define ADV_SYMMETRIC_FLOW_CTRL (1 << 4)
+#define FORCE_FC_MODE_NO_PAUSE_DIS_TX (0 << 5)
+#define FORCE_FC_MODE_TX_PAUSE_DIS (1 << 5)
+#define FORCE_BP_MODE_NO_JAM (0 << 7)
+#define FORCE_BP_MODE_JAM_TX (1 << 7)
+#define FORCE_BP_MODE_JAM_TX_ON_RX_ERR (2 << 7)
+#define SERIAL_PORT_CONTROL_RESERVED (1 << 9)
+#define FORCE_LINK_FAIL (0 << 10)
+#define DO_NOT_FORCE_LINK_FAIL (1 << 10)
+#define RETRANSMIT_16_ATTEMPTS (0 << 11)
+#define RETRANSMIT_FOREVER (1 << 11)
+#define ENABLE_AUTO_NEG_SPEED_GMII (0 << 13)
+#define DISABLE_AUTO_NEG_SPEED_GMII (1 << 13)
+#define DTE_ADV_0 (0 << 14)
+#define DTE_ADV_1 (1 << 14)
+#define DISABLE_AUTO_NEG_BYPASS (0 << 15)
+#define ENABLE_AUTO_NEG_BYPASS (1 << 15)
+#define AUTO_NEG_NO_CHANGE (0 << 16)
+#define RESTART_AUTO_NEG (1 << 16)
+#define MAX_RX_PACKET_1518BYTE (0 << 17)
+#define MAX_RX_PACKET_1522BYTE (1 << 17)
+#define MAX_RX_PACKET_1552BYTE (2 << 17)
+#define MAX_RX_PACKET_9022BYTE (3 << 17)
+#define MAX_RX_PACKET_9192BYTE (4 << 17)
+#define MAX_RX_PACKET_9700BYTE (5 << 17)
+#define MAX_RX_PACKET_MASK (7 << 17)
+#define CLR_EXT_LOOPBACK (0 << 20)
+#define SET_EXT_LOOPBACK (1 << 20)
+#define SET_HALF_DUPLEX_MODE (0 << 21)
+#define SET_FULL_DUPLEX_MODE (1 << 21)
+#define DISABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX (0 << 22)
+#define ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX (1 << 22)
+#define SET_GMII_SPEED_TO_10_100 (0 << 23)
+#define SET_GMII_SPEED_TO_1000 (1 << 23)
+#define SET_MII_SPEED_TO_10 (0 << 24)
+#define SET_MII_SPEED_TO_100 (1 << 24)
+
+#define PORT_SERIAL_CONTROL_DEFAULT_VALUE \
+ DO_NOT_FORCE_LINK_PASS | \
+ ENABLE_AUTO_NEG_FOR_DUPLX | \
+ DISABLE_AUTO_NEG_FOR_FLOW_CTRL | \
+ ADV_SYMMETRIC_FLOW_CTRL | \
+ FORCE_FC_MODE_NO_PAUSE_DIS_TX | \
+ FORCE_BP_MODE_NO_JAM | \
+ (1 << 9) /* reserved */ | \
+ DO_NOT_FORCE_LINK_FAIL | \
+ RETRANSMIT_16_ATTEMPTS | \
+ ENABLE_AUTO_NEG_SPEED_GMII | \
+ DTE_ADV_0 | \
+ DISABLE_AUTO_NEG_BYPASS | \
+ AUTO_NEG_NO_CHANGE | \
+ MAX_RX_PACKET_9700BYTE | \
+ CLR_EXT_LOOPBACK | \
+ SET_FULL_DUPLEX_MODE | \
+ ENABLE_FLOW_CTRL_TX_RX_IN_FULL_DUPLEX
+
+/* These macros describe Ethernet Serial Status reg (PSR) bits */
+#define PORT_STATUS_MODE_10_BIT (1 << 0)
+#define PORT_STATUS_LINK_UP (1 << 1)
+#define PORT_STATUS_FULL_DUPLEX (1 << 2)
+#define PORT_STATUS_FLOW_CONTROL (1 << 3)
+#define PORT_STATUS_GMII_1000 (1 << 4)
+#define PORT_STATUS_MII_100 (1 << 5)
+/* PSR bit 6 is undocumented */
+#define PORT_STATUS_TX_IN_PROGRESS (1 << 7)
+#define PORT_STATUS_AUTONEG_BYPASSED (1 << 8)
+#define PORT_STATUS_PARTITION (1 << 9)
+#define PORT_STATUS_TX_FIFO_EMPTY (1 << 10)
+/* PSR bits 11-31 are reserved */
+
+#define PORT_DEFAULT_TRANSMIT_QUEUE_SIZE 800
+#define PORT_DEFAULT_RECEIVE_QUEUE_SIZE 400
+
+#define DESC_SIZE 64
+
+#define ETH_RX_QUEUES_ENABLED (1 << 0) /* use only Q0 for receive */
+#define ETH_TX_QUEUES_ENABLED (1 << 0) /* use only Q0 for transmit */
+
+#define ETH_INT_CAUSE_RX_DONE (ETH_RX_QUEUES_ENABLED << 2)
+#define ETH_INT_CAUSE_RX_ERROR (ETH_RX_QUEUES_ENABLED << 9)
+#define ETH_INT_CAUSE_RX (ETH_INT_CAUSE_RX_DONE | ETH_INT_CAUSE_RX_ERROR)
+#define ETH_INT_CAUSE_EXT 0x00000002
+#define ETH_INT_UNMASK_ALL (ETH_INT_CAUSE_RX | ETH_INT_CAUSE_EXT)
+
+#define ETH_INT_CAUSE_TX_DONE (ETH_TX_QUEUES_ENABLED << 0)
+#define ETH_INT_CAUSE_TX_ERROR (ETH_TX_QUEUES_ENABLED << 8)
+#define ETH_INT_CAUSE_TX (ETH_INT_CAUSE_TX_DONE | ETH_INT_CAUSE_TX_ERROR)
+#define ETH_INT_CAUSE_PHY 0x00010000
+#define ETH_INT_CAUSE_STATE 0x00100000
+#define ETH_INT_UNMASK_ALL_EXT (ETH_INT_CAUSE_TX | ETH_INT_CAUSE_PHY | \
+ ETH_INT_CAUSE_STATE)
+
+#define ETH_INT_MASK_ALL 0x00000000
+#define ETH_INT_MASK_ALL_EXT 0x00000000
+
+#define PHY_WAIT_ITERATIONS 1000 /* 1000 iterations * 10uS = 10mS max */
+#define PHY_WAIT_MICRO_SECONDS 10
+
+/* Buffer offset from buffer pointer */
+#define RX_BUF_OFFSET 0x2
+
+/* Gigabit Ethernet Unit Global Registers */
+
+/* MIB Counters register definitions */
+#define ETH_MIB_GOOD_OCTETS_RECEIVED_LOW 0x0
+#define ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH 0x4
+#define ETH_MIB_BAD_OCTETS_RECEIVED 0x8
+#define ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR 0xc
+#define ETH_MIB_GOOD_FRAMES_RECEIVED 0x10
+#define ETH_MIB_BAD_FRAMES_RECEIVED 0x14
+#define ETH_MIB_BROADCAST_FRAMES_RECEIVED 0x18
+#define ETH_MIB_MULTICAST_FRAMES_RECEIVED 0x1c
+#define ETH_MIB_FRAMES_64_OCTETS 0x20
+#define ETH_MIB_FRAMES_65_TO_127_OCTETS 0x24
+#define ETH_MIB_FRAMES_128_TO_255_OCTETS 0x28
+#define ETH_MIB_FRAMES_256_TO_511_OCTETS 0x2c
+#define ETH_MIB_FRAMES_512_TO_1023_OCTETS 0x30
+#define ETH_MIB_FRAMES_1024_TO_MAX_OCTETS 0x34
+#define ETH_MIB_GOOD_OCTETS_SENT_LOW 0x38
+#define ETH_MIB_GOOD_OCTETS_SENT_HIGH 0x3c
+#define ETH_MIB_GOOD_FRAMES_SENT 0x40
+#define ETH_MIB_EXCESSIVE_COLLISION 0x44
+#define ETH_MIB_MULTICAST_FRAMES_SENT 0x48
+#define ETH_MIB_BROADCAST_FRAMES_SENT 0x4c
+#define ETH_MIB_UNREC_MAC_CONTROL_RECEIVED 0x50
+#define ETH_MIB_FC_SENT 0x54
+#define ETH_MIB_GOOD_FC_RECEIVED 0x58
+#define ETH_MIB_BAD_FC_RECEIVED 0x5c
+#define ETH_MIB_UNDERSIZE_RECEIVED 0x60
+#define ETH_MIB_FRAGMENTS_RECEIVED 0x64
+#define ETH_MIB_OVERSIZE_RECEIVED 0x68
+#define ETH_MIB_JABBER_RECEIVED 0x6c
+#define ETH_MIB_MAC_RECEIVE_ERROR 0x70
+#define ETH_MIB_BAD_CRC_EVENT 0x74
+#define ETH_MIB_COLLISION 0x78
+#define ETH_MIB_LATE_COLLISION 0x7c
+
+/* Port serial status reg (PSR) */
+#define ETH_INTERFACE_PCM 0x00000001
+#define ETH_LINK_IS_UP 0x00000002
+#define ETH_PORT_AT_FULL_DUPLEX 0x00000004
+#define ETH_RX_FLOW_CTRL_ENABLED 0x00000008
+#define ETH_GMII_SPEED_1000 0x00000010
+#define ETH_MII_SPEED_100 0x00000020
+#define ETH_TX_IN_PROGRESS 0x00000080
+#define ETH_BYPASS_ACTIVE 0x00000100
+#define ETH_PORT_AT_PARTITION_STATE 0x00000200
+#define ETH_PORT_TX_FIFO_EMPTY 0x00000400
+
+/* SMI reg */
+#define ETH_SMI_BUSY 0x10000000 /* 0 - Write, 1 - Read */
+#define ETH_SMI_READ_VALID 0x08000000 /* 0 - Write, 1 - Read */
+#define ETH_SMI_OPCODE_WRITE 0 /* Completion of Read */
+#define ETH_SMI_OPCODE_READ 0x04000000 /* Operation is in progress */
+
+/* Interrupt Cause Register Bit Definitions */
+
+/* SDMA command status fields macros */
+
+/* Tx & Rx descriptors status */
+#define ETH_ERROR_SUMMARY 0x00000001
+
+/* Tx & Rx descriptors command */
+#define ETH_BUFFER_OWNED_BY_DMA 0x80000000
+
+/* Tx descriptors status */
+#define ETH_LC_ERROR 0
+#define ETH_UR_ERROR 0x00000002
+#define ETH_RL_ERROR 0x00000004
+#define ETH_LLC_SNAP_FORMAT 0x00000200
+
+/* Rx descriptors status */
+#define ETH_OVERRUN_ERROR 0x00000002
+#define ETH_MAX_FRAME_LENGTH_ERROR 0x00000004
+#define ETH_RESOURCE_ERROR 0x00000006
+#define ETH_VLAN_TAGGED 0x00080000
+#define ETH_BPDU_FRAME 0x00100000
+#define ETH_UDP_FRAME_OVER_IP_V_4 0x00200000
+#define ETH_OTHER_FRAME_TYPE 0x00400000
+#define ETH_LAYER_2_IS_ETH_V_2 0x00800000
+#define ETH_FRAME_TYPE_IP_V_4 0x01000000
+#define ETH_FRAME_HEADER_OK 0x02000000
+#define ETH_RX_LAST_DESC 0x04000000
+#define ETH_RX_FIRST_DESC 0x08000000
+#define ETH_UNKNOWN_DESTINATION_ADDR 0x10000000
+#define ETH_RX_ENABLE_INTERRUPT 0x20000000
+#define ETH_LAYER_4_CHECKSUM_OK 0x40000000
+
+/* Rx descriptors byte count */
+#define ETH_FRAME_FRAGMENTED 0x00000004
+
+/* Tx descriptors command */
+#define ETH_LAYER_4_CHECKSUM_FIRST_DESC 0x00000400
+#define ETH_FRAME_SET_TO_VLAN 0x00008000
+#define ETH_UDP_FRAME 0x00010000
+#define ETH_GEN_TCP_UDP_CHECKSUM 0x00020000
+#define ETH_GEN_IP_V_4_CHECKSUM 0x00040000
+#define ETH_ZERO_PADDING 0x00080000
+#define ETH_TX_LAST_DESC 0x00100000
+#define ETH_TX_FIRST_DESC 0x00200000
+#define ETH_GEN_CRC 0x00400000
+#define ETH_TX_ENABLE_INTERRUPT 0x00800000
+#define ETH_AUTO_MODE 0x40000000
+
+#define ETH_TX_IHL_SHIFT 11
+
+/* typedefs */
+
+typedef enum _eth_func_ret_status {
+ ETH_OK, /* Returned as expected. */
+ ETH_ERROR, /* Fundamental error. */
+ ETH_RETRY, /* Could not process request. Try later.*/
+ ETH_END_OF_JOB, /* Ring has nothing to process. */
+ ETH_QUEUE_FULL, /* Ring resource error. */
+ ETH_QUEUE_LAST_RESOURCE /* Ring resources about to exhaust. */
+} ETH_FUNC_RET_STATUS;
+
+typedef enum _eth_target {
+ ETH_TARGET_DRAM,
+ ETH_TARGET_DEVICE,
+ ETH_TARGET_CBS,
+ ETH_TARGET_PCI0,
+ ETH_TARGET_PCI1
+} ETH_TARGET;
+
+/* These are for big-endian machines. Little endian needs different
+ * definitions.
+ */
+#if defined(__BIG_ENDIAN)
+struct eth_rx_desc {
+ u16 byte_cnt; /* Descriptor buffer byte count */
+ u16 buf_size; /* Buffer size */
+ u32 cmd_sts; /* Descriptor command status */
+ u32 next_desc_ptr; /* Next descriptor pointer */
+ u32 buf_ptr; /* Descriptor buffer pointer */
+};
+
+struct eth_tx_desc {
+ u16 byte_cnt; /* buffer byte count */
+ u16 l4i_chk; /* CPU provided TCP checksum */
+ u32 cmd_sts; /* Command/status field */
+ u32 next_desc_ptr; /* Pointer to next descriptor */
+ u32 buf_ptr; /* pointer to buffer for this descriptor*/
+};
+#elif defined(__LITTLE_ENDIAN)
+struct eth_rx_desc {
+ u32 cmd_sts; /* Descriptor command status */
+ u16 buf_size; /* Buffer size */
+ u16 byte_cnt; /* Descriptor buffer byte count */
+ u32 buf_ptr; /* Descriptor buffer pointer */
+ u32 next_desc_ptr; /* Next descriptor pointer */
+};
+
+struct eth_tx_desc {
+ u32 cmd_sts; /* Command/status field */
+ u16 l4i_chk; /* CPU provided TCP checksum */
+ u16 byte_cnt; /* buffer byte count */
+ u32 buf_ptr; /* pointer to buffer for this descriptor*/
+ u32 next_desc_ptr; /* Pointer to next descriptor */
+};
+#else
+#error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined
+#endif
+
+/* Unified struct for Rx and Tx operations. The user is not required to */
+/* be familier with neither Tx nor Rx descriptors. */
+struct pkt_info {
+ unsigned short byte_cnt; /* Descriptor buffer byte count */
+ unsigned short l4i_chk; /* Tx CPU provided TCP Checksum */
+ unsigned int cmd_sts; /* Descriptor command status */
+ dma_addr_t buf_ptr; /* Descriptor buffer pointer */
+ struct sk_buff *return_info; /* User resource return information */
+};
+
+/* Ethernet port specific information */
+struct mv643xx_mib_counters {
+ u64 good_octets_received;
+ u32 bad_octets_received;
+ u32 internal_mac_transmit_err;
+ u32 good_frames_received;
+ u32 bad_frames_received;
+ u32 broadcast_frames_received;
+ u32 multicast_frames_received;
+ u32 frames_64_octets;
+ u32 frames_65_to_127_octets;
+ u32 frames_128_to_255_octets;
+ u32 frames_256_to_511_octets;
+ u32 frames_512_to_1023_octets;
+ u32 frames_1024_to_max_octets;
+ u64 good_octets_sent;
+ u32 good_frames_sent;
+ u32 excessive_collision;
+ u32 multicast_frames_sent;
+ u32 broadcast_frames_sent;
+ u32 unrec_mac_control_received;
+ u32 fc_sent;
+ u32 good_fc_received;
+ u32 bad_fc_received;
+ u32 undersize_received;
+ u32 fragments_received;
+ u32 oversize_received;
+ u32 jabber_received;
+ u32 mac_receive_error;
+ u32 bad_crc_event;
+ u32 collision;
+ u32 late_collision;
+};
+
+struct mv643xx_private {
+ int port_num; /* User Ethernet port number */
+
+ u32 rx_sram_addr; /* Base address of rx sram area */
+ u32 rx_sram_size; /* Size of rx sram area */
+ u32 tx_sram_addr; /* Base address of tx sram area */
+ u32 tx_sram_size; /* Size of tx sram area */
+
+ int rx_resource_err; /* Rx ring resource error flag */
+
+ /* Tx/Rx rings managment indexes fields. For driver use */
+
+ /* Next available and first returning Rx resource */
+ int rx_curr_desc_q, rx_used_desc_q;
+
+ /* Next available and first returning Tx resource */
+ int tx_curr_desc_q, tx_used_desc_q;
+
+#ifdef MV643XX_TX_FAST_REFILL
+ u32 tx_clean_threshold;
+#endif
+
+ struct eth_rx_desc *p_rx_desc_area;
+ dma_addr_t rx_desc_dma;
+ int rx_desc_area_size;
+ struct sk_buff **rx_skb;
+
+ struct eth_tx_desc *p_tx_desc_area;
+ dma_addr_t tx_desc_dma;
+ int tx_desc_area_size;
+ struct sk_buff **tx_skb;
+
+ struct work_struct tx_timeout_task;
+
+ struct net_device *dev;
+ struct napi_struct napi;
+ struct net_device_stats stats;
+ struct mv643xx_mib_counters mib_counters;
+ spinlock_t lock;
+ /* Size of Tx Ring per queue */
+ int tx_ring_size;
+ /* Number of tx descriptors in use */
+ int tx_desc_count;
+ /* Size of Rx Ring per queue */
+ int rx_ring_size;
+ /* Number of rx descriptors in use */
+ int rx_desc_count;
+
+ /*
+ * Used in case RX Ring is empty, which can be caused when
+ * system does not have resources (skb's)
+ */
+ struct timer_list timeout;
+
+ u32 rx_int_coal;
+ u32 tx_int_coal;
+ struct mii_if_info mii;
+};
/* Static function declarations */
+static void eth_port_init(struct mv643xx_private *mp);
+static void eth_port_reset(unsigned int eth_port_num);
+static void eth_port_start(struct net_device *dev);
+
+static void ethernet_phy_reset(unsigned int eth_port_num);
+
+static void eth_port_write_smi_reg(unsigned int eth_port_num,
+ unsigned int phy_reg, unsigned int value);
+
+static void eth_port_read_smi_reg(unsigned int eth_port_num,
+ unsigned int phy_reg, unsigned int *value);
+
+static void eth_clear_mib_counters(unsigned int eth_port_num);
+
+static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp,
+ struct pkt_info *p_pkt_info);
+static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv643xx_private *mp,
+ struct pkt_info *p_pkt_info);
+
static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr);
static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr);
static void eth_port_set_multicast_list(struct net_device *);
@@ -63,10 +616,9 @@ static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num);
static int mv643xx_eth_open(struct net_device *);
static int mv643xx_eth_stop(struct net_device *);
static int mv643xx_eth_change_mtu(struct net_device *, int);
-static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *);
static void eth_port_init_mac_tables(unsigned int eth_port_num);
#ifdef MV643XX_NAPI
-static int mv643xx_poll(struct net_device *dev, int *budget);
+static int mv643xx_poll(struct napi_struct *napi, int budget);
#endif
static int ethernet_phy_get(unsigned int eth_port_num);
static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr);
@@ -79,26 +631,19 @@ static const struct ethtool_ops mv643xx_ethtool_ops;
static char mv643xx_driver_name[] = "mv643xx_eth";
static char mv643xx_driver_version[] = "1.0";
-static void __iomem *mv643xx_eth_shared_base;
+static void __iomem *mv643xx_eth_base;
-/* used to protect MV643XX_ETH_SMI_REG, which is shared across ports */
+/* used to protect SMI_REG, which is shared across ports */
static DEFINE_SPINLOCK(mv643xx_eth_phy_lock);
static inline u32 mv_read(int offset)
{
- void __iomem *reg_base;
-
- reg_base = mv643xx_eth_shared_base - MV643XX_ETH_SHARED_REGS;
-
- return readl(reg_base + offset);
+ return readl(mv643xx_eth_base + offset);
}
static inline void mv_write(int offset, u32 data)
{
- void __iomem *reg_base;
-
- reg_base = mv643xx_eth_shared_base - MV643XX_ETH_SHARED_REGS;
- writel(data, reg_base + offset);
+ writel(data, mv643xx_eth_base + offset);
}
/*
@@ -222,12 +767,12 @@ static void mv643xx_eth_set_rx_mode(struct net_device *dev)
struct mv643xx_private *mp = netdev_priv(dev);
u32 config_reg;
- config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num));
+ config_reg = mv_read(PORT_CONFIG_REG(mp->port_num));
if (dev->flags & IFF_PROMISC)
- config_reg |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
+ config_reg |= (u32) UNICAST_PROMISCUOUS_MODE;
else
- config_reg &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE;
- mv_write(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num), config_reg);
+ config_reg &= ~(u32) UNICAST_PROMISCUOUS_MODE;
+ mv_write(PORT_CONFIG_REG(mp->port_num), config_reg);
eth_port_set_multicast_list(dev);
}
@@ -341,7 +886,7 @@ int mv643xx_eth_free_tx_descs(struct net_device *dev, int force)
if (cmd_sts & ETH_ERROR_SUMMARY) {
printk("%s: Error in TX\n", dev->name);
- mp->stats.tx_errors++;
+ dev->stats.tx_errors++;
}
spin_unlock_irqrestore(&mp->lock, flags);
@@ -388,7 +933,7 @@ static void mv643xx_eth_free_all_tx_descs(struct net_device *dev)
static int mv643xx_eth_receive_queue(struct net_device *dev, int budget)
{
struct mv643xx_private *mp = netdev_priv(dev);
- struct net_device_stats *stats = &mp->stats;
+ struct net_device_stats *stats = &dev->stats;
unsigned int received_packets = 0;
struct sk_buff *skb;
struct pkt_info pkt_info;
@@ -463,41 +1008,37 @@ static void mv643xx_eth_update_pscr(struct net_device *dev,
u32 o_pscr, n_pscr;
unsigned int queues;
- o_pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num));
+ o_pscr = mv_read(PORT_SERIAL_CONTROL_REG(port_num));
n_pscr = o_pscr;
/* clear speed, duplex and rx buffer size fields */
- n_pscr &= ~(MV643XX_ETH_SET_MII_SPEED_TO_100 |
- MV643XX_ETH_SET_GMII_SPEED_TO_1000 |
- MV643XX_ETH_SET_FULL_DUPLEX_MODE |
- MV643XX_ETH_MAX_RX_PACKET_MASK);
+ n_pscr &= ~(SET_MII_SPEED_TO_100 |
+ SET_GMII_SPEED_TO_1000 |
+ SET_FULL_DUPLEX_MODE |
+ MAX_RX_PACKET_MASK);
if (ecmd->duplex == DUPLEX_FULL)
- n_pscr |= MV643XX_ETH_SET_FULL_DUPLEX_MODE;
+ n_pscr |= SET_FULL_DUPLEX_MODE;
if (ecmd->speed == SPEED_1000)
- n_pscr |= MV643XX_ETH_SET_GMII_SPEED_TO_1000 |
- MV643XX_ETH_MAX_RX_PACKET_9700BYTE;
+ n_pscr |= SET_GMII_SPEED_TO_1000 |
+ MAX_RX_PACKET_9700BYTE;
else {
if (ecmd->speed == SPEED_100)
- n_pscr |= MV643XX_ETH_SET_MII_SPEED_TO_100;
- n_pscr |= MV643XX_ETH_MAX_RX_PACKET_1522BYTE;
+ n_pscr |= SET_MII_SPEED_TO_100;
+ n_pscr |= MAX_RX_PACKET_1522BYTE;
}
if (n_pscr != o_pscr) {
- if ((o_pscr & MV643XX_ETH_SERIAL_PORT_ENABLE) == 0)
- mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
- n_pscr);
+ if ((o_pscr & SERIAL_PORT_ENABLE) == 0)
+ mv_write(PORT_SERIAL_CONTROL_REG(port_num), n_pscr);
else {
queues = mv643xx_eth_port_disable_tx(port_num);
- o_pscr &= ~MV643XX_ETH_SERIAL_PORT_ENABLE;
- mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
- o_pscr);
- mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
- n_pscr);
- mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num),
- n_pscr);
+ o_pscr &= ~SERIAL_PORT_ENABLE;
+ mv_write(PORT_SERIAL_CONTROL_REG(port_num), o_pscr);
+ mv_write(PORT_SERIAL_CONTROL_REG(port_num), n_pscr);
+ mv_write(PORT_SERIAL_CONTROL_REG(port_num), n_pscr);
if (queues)
mv643xx_eth_port_enable_tx(port_num, queues);
}
@@ -523,13 +1064,13 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id)
unsigned int port_num = mp->port_num;
/* Read interrupt cause registers */
- eth_int_cause = mv_read(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num)) &
+ eth_int_cause = mv_read(INTERRUPT_CAUSE_REG(port_num)) &
ETH_INT_UNMASK_ALL;
if (eth_int_cause & ETH_INT_CAUSE_EXT) {
eth_int_cause_ext = mv_read(
- MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) &
+ INTERRUPT_CAUSE_EXTEND_REG(port_num)) &
ETH_INT_UNMASK_ALL_EXT;
- mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num),
+ mv_write(INTERRUPT_CAUSE_EXTEND_REG(port_num),
~eth_int_cause_ext);
}
@@ -557,12 +1098,12 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id)
#ifdef MV643XX_NAPI
if (eth_int_cause & ETH_INT_CAUSE_RX) {
/* schedule the NAPI poll routine to maintain port */
- mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
- ETH_INT_MASK_ALL);
+ mv_write(INTERRUPT_MASK_REG(port_num), ETH_INT_MASK_ALL);
+
/* wait for previous write to complete */
- mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
+ mv_read(INTERRUPT_MASK_REG(port_num));
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &mp->napi);
}
#else
if (eth_int_cause & ETH_INT_CAUSE_RX)
@@ -612,9 +1153,9 @@ static unsigned int eth_port_set_rx_coal(unsigned int eth_port_num,
unsigned int coal = ((t_clk / 1000000) * delay) / 64;
/* Set RX Coalescing mechanism */
- mv_write(MV643XX_ETH_SDMA_CONFIG_REG(eth_port_num),
+ mv_write(SDMA_CONFIG_REG(eth_port_num),
((coal & 0x3fff) << 8) |
- (mv_read(MV643XX_ETH_SDMA_CONFIG_REG(eth_port_num))
+ (mv_read(SDMA_CONFIG_REG(eth_port_num))
& 0xffc000ff));
return coal;
@@ -650,8 +1191,7 @@ static unsigned int eth_port_set_tx_coal(unsigned int eth_port_num,
unsigned int coal;
coal = ((t_clk / 1000000) * delay) / 64;
/* Set TX Coalescing mechanism */
- mv_write(MV643XX_ETH_TX_FIFO_URGENT_THRESHOLD_REG(eth_port_num),
- coal << 4);
+ mv_write(TX_FIFO_URGENT_THRESHOLD_REG(eth_port_num), coal << 4);
return coal;
}
@@ -787,10 +1327,10 @@ static int mv643xx_eth_open(struct net_device *dev)
int err;
/* Clear any pending ethernet port interrupts */
- mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
- mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
+ mv_write(INTERRUPT_CAUSE_REG(port_num), 0);
+ mv_write(INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
/* wait for previous write to complete */
- mv_read (MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num));
+ mv_read (INTERRUPT_CAUSE_EXTEND_REG(port_num));
err = request_irq(dev->irq, mv643xx_eth_int_handler,
IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev);
@@ -880,6 +1420,10 @@ static int mv643xx_eth_open(struct net_device *dev)
mv643xx_eth_rx_refill_descs(dev); /* Fill RX ring with skb's */
+#ifdef MV643XX_NAPI
+ napi_enable(&mp->napi);
+#endif
+
eth_port_start(dev);
/* Interrupt Coalescing */
@@ -893,11 +1437,10 @@ static int mv643xx_eth_open(struct net_device *dev)
eth_port_set_tx_coal(port_num, 133000000, MV643XX_TX_COAL);
/* Unmask phy and link status changes interrupts */
- mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num),
- ETH_INT_UNMASK_ALL_EXT);
+ mv_write(INTERRUPT_EXTEND_MASK_REG(port_num), ETH_INT_UNMASK_ALL_EXT);
/* Unmask RX buffer and TX end interrupt */
- mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL);
+ mv_write(INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL);
return 0;
@@ -977,12 +1520,12 @@ static int mv643xx_eth_stop(struct net_device *dev)
unsigned int port_num = mp->port_num;
/* Mask all interrupts on ethernet port */
- mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_MASK_ALL);
+ mv_write(INTERRUPT_MASK_REG(port_num), ETH_INT_MASK_ALL);
/* wait for previous write to complete */
- mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
+ mv_read(INTERRUPT_MASK_REG(port_num));
#ifdef MV643XX_NAPI
- netif_poll_disable(dev);
+ napi_disable(&mp->napi);
#endif
netif_carrier_off(dev);
netif_stop_queue(dev);
@@ -992,10 +1535,6 @@ static int mv643xx_eth_stop(struct net_device *dev)
mv643xx_eth_free_tx_rings(dev);
mv643xx_eth_free_rx_rings(dev);
-#ifdef MV643XX_NAPI
- netif_poll_enable(dev);
-#endif
-
free_irq(dev->irq, dev);
return 0;
@@ -1007,11 +1546,12 @@ static int mv643xx_eth_stop(struct net_device *dev)
*
* This function is used in case of NAPI
*/
-static int mv643xx_poll(struct net_device *dev, int *budget)
+static int mv643xx_poll(struct napi_struct *napi, int budget)
{
- struct mv643xx_private *mp = netdev_priv(dev);
- int done = 1, orig_budget, work_done;
+ struct mv643xx_private *mp = container_of(napi, struct mv643xx_private, napi);
+ struct net_device *dev = mp->dev;
unsigned int port_num = mp->port_num;
+ int work_done;
#ifdef MV643XX_TX_FAST_REFILL
if (++mp->tx_clean_threshold > 5) {
@@ -1020,27 +1560,19 @@ static int mv643xx_poll(struct net_device *dev, int *budget)
}
#endif
- if ((mv_read(MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num)))
- != (u32) mp->rx_used_desc_q) {
- orig_budget = *budget;
- if (orig_budget > dev->quota)
- orig_budget = dev->quota;
- work_done = mv643xx_eth_receive_queue(dev, orig_budget);
- *budget -= work_done;
- dev->quota -= work_done;
- if (work_done >= orig_budget)
- done = 0;
- }
+ work_done = 0;
+ if ((mv_read(RX_CURRENT_QUEUE_DESC_PTR_0(port_num)))
+ != (u32) mp->rx_used_desc_q)
+ work_done = mv643xx_eth_receive_queue(dev, budget);
- if (done) {
- netif_rx_complete(dev);
- mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
- mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
- mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
- ETH_INT_UNMASK_ALL);
+ if (work_done < budget) {
+ netif_rx_complete(dev, napi);
+ mv_write(INTERRUPT_CAUSE_REG(port_num), 0);
+ mv_write(INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
+ mv_write(INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL);
}
- return done ? 0 : 1;
+ return work_done;
}
#endif
@@ -1198,7 +1730,7 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp,
static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct mv643xx_private *mp = netdev_priv(dev);
- struct net_device_stats *stats = &mp->stats;
+ struct net_device_stats *stats = &dev->stats;
unsigned long flags;
BUG_ON(netif_queue_stopped(dev));
@@ -1234,36 +1766,19 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0; /* success */
}
-/*
- * mv643xx_eth_get_stats
- *
- * Returns a pointer to the interface statistics.
- *
- * Input : dev - a pointer to the required interface
- *
- * Output : a pointer to the interface's statistics
- */
-
-static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev)
-{
- struct mv643xx_private *mp = netdev_priv(dev);
-
- return &mp->stats;
-}
-
#ifdef CONFIG_NET_POLL_CONTROLLER
static void mv643xx_netpoll(struct net_device *netdev)
{
struct mv643xx_private *mp = netdev_priv(netdev);
int port_num = mp->port_num;
- mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_MASK_ALL);
+ mv_write(INTERRUPT_MASK_REG(port_num), ETH_INT_MASK_ALL);
/* wait for previous write to complete */
- mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
+ mv_read(INTERRUPT_MASK_REG(port_num));
mv643xx_eth_int_handler(netdev->irq, netdev);
- mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL);
+ mv_write(INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL);
}
#endif
@@ -1319,6 +1834,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
struct ethtool_cmd cmd;
int duplex = DUPLEX_HALF;
int speed = 0; /* default to auto-negotiation */
+ DECLARE_MAC_BUF(mac);
pd = pdev->dev.platform_data;
if (pd == NULL) {
@@ -1333,6 +1849,10 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
mp = netdev_priv(dev);
+ mp->dev = dev;
+#ifdef MV643XX_NAPI
+ netif_napi_add(dev, &mp->napi, mv643xx_poll, 64);
+#endif
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
BUG_ON(!res);
@@ -1341,16 +1861,11 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
dev->open = mv643xx_eth_open;
dev->stop = mv643xx_eth_stop;
dev->hard_start_xmit = mv643xx_eth_start_xmit;
- dev->get_stats = mv643xx_eth_get_stats;
dev->set_mac_address = mv643xx_eth_set_mac_address;
dev->set_multicast_list = mv643xx_eth_set_rx_mode;
/* No need to Tx Timeout */
dev->tx_timeout = mv643xx_eth_tx_timeout;
-#ifdef MV643XX_NAPI
- dev->poll = mv643xx_poll;
- dev->weight = 64;
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = mv643xx_netpoll;
@@ -1381,8 +1896,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
/* set default config values */
eth_port_uc_addr_get(port_num, dev->dev_addr);
- mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE;
- mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE;
+ mp->rx_ring_size = PORT_DEFAULT_RECEIVE_QUEUE_SIZE;
+ mp->tx_ring_size = PORT_DEFAULT_TRANSMIT_QUEUE_SIZE;
if (is_valid_ether_addr(pd->mac_addr))
memcpy(dev->dev_addr, pd->mac_addr, 6);
@@ -1431,7 +1946,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
mv643xx_eth_update_pscr(dev, &cmd);
mv643xx_set_settings(dev, &cmd);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_netdev(dev);
if (err)
@@ -1439,8 +1953,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
p = dev->dev_addr;
printk(KERN_NOTICE
- "%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name, port_num, p[0], p[1], p[2], p[3], p[4], p[5]);
+ "%s: port %d with MAC address %s\n",
+ dev->name, port_num, print_mac(mac, p));
if (dev->features & NETIF_F_SG)
printk(KERN_NOTICE "%s: Scatter Gather Enabled\n", dev->name);
@@ -1495,9 +2009,8 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
if (res == NULL)
return -ENODEV;
- mv643xx_eth_shared_base = ioremap(res->start,
- MV643XX_ETH_SHARED_REGS_SIZE);
- if (mv643xx_eth_shared_base == NULL)
+ mv643xx_eth_base = ioremap(res->start, res->end - res->start + 1);
+ if (mv643xx_eth_base == NULL)
return -ENOMEM;
return 0;
@@ -1506,8 +2019,8 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
static int mv643xx_eth_shared_remove(struct platform_device *pdev)
{
- iounmap(mv643xx_eth_shared_base);
- mv643xx_eth_shared_base = NULL;
+ iounmap(mv643xx_eth_base);
+ mv643xx_eth_base = NULL;
return 0;
}
@@ -1519,8 +2032,8 @@ static void mv643xx_eth_shutdown(struct platform_device *pdev)
unsigned int port_num = mp->port_num;
/* Mask all interrupts on ethernet port */
- mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), 0);
- mv_read (MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
+ mv_write(INTERRUPT_MASK_REG(port_num), 0);
+ mv_read (INTERRUPT_MASK_REG(port_num));
eth_port_reset(port_num);
}
@@ -1787,49 +2300,49 @@ static void eth_port_start(struct net_device *dev)
/* Assignment of Tx CTRP of given queue */
tx_curr_desc = mp->tx_curr_desc_q;
- mv_write(MV643XX_ETH_TX_CURRENT_QUEUE_DESC_PTR_0(port_num),
+ mv_write(TX_CURRENT_QUEUE_DESC_PTR_0(port_num),
(u32)((struct eth_tx_desc *)mp->tx_desc_dma + tx_curr_desc));
/* Assignment of Rx CRDP of given queue */
rx_curr_desc = mp->rx_curr_desc_q;
- mv_write(MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num),
+ mv_write(RX_CURRENT_QUEUE_DESC_PTR_0(port_num),
(u32)((struct eth_rx_desc *)mp->rx_desc_dma + rx_curr_desc));
/* Add the assigned Ethernet address to the port's address table */
eth_port_uc_addr_set(port_num, dev->dev_addr);
/* Assign port configuration and command. */
- mv_write(MV643XX_ETH_PORT_CONFIG_REG(port_num),
- MV643XX_ETH_PORT_CONFIG_DEFAULT_VALUE);
+ mv_write(PORT_CONFIG_REG(port_num),
+ PORT_CONFIG_DEFAULT_VALUE);
- mv_write(MV643XX_ETH_PORT_CONFIG_EXTEND_REG(port_num),
- MV643XX_ETH_PORT_CONFIG_EXTEND_DEFAULT_VALUE);
+ mv_write(PORT_CONFIG_EXTEND_REG(port_num),
+ PORT_CONFIG_EXTEND_DEFAULT_VALUE);
- pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num));
+ pscr = mv_read(PORT_SERIAL_CONTROL_REG(port_num));
- pscr &= ~(MV643XX_ETH_SERIAL_PORT_ENABLE | MV643XX_ETH_FORCE_LINK_PASS);
- mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr);
+ pscr &= ~(SERIAL_PORT_ENABLE | FORCE_LINK_PASS);
+ mv_write(PORT_SERIAL_CONTROL_REG(port_num), pscr);
- pscr |= MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL |
- MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII |
- MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX |
- MV643XX_ETH_DO_NOT_FORCE_LINK_FAIL |
- MV643XX_ETH_SERIAL_PORT_CONTROL_RESERVED;
+ pscr |= DISABLE_AUTO_NEG_FOR_FLOW_CTRL |
+ DISABLE_AUTO_NEG_SPEED_GMII |
+ DISABLE_AUTO_NEG_FOR_DUPLX |
+ DO_NOT_FORCE_LINK_FAIL |
+ SERIAL_PORT_CONTROL_RESERVED;
- mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr);
+ mv_write(PORT_SERIAL_CONTROL_REG(port_num), pscr);
- pscr |= MV643XX_ETH_SERIAL_PORT_ENABLE;
- mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr);
+ pscr |= SERIAL_PORT_ENABLE;
+ mv_write(PORT_SERIAL_CONTROL_REG(port_num), pscr);
/* Assign port SDMA configuration */
- mv_write(MV643XX_ETH_SDMA_CONFIG_REG(port_num),
- MV643XX_ETH_PORT_SDMA_CONFIG_DEFAULT_VALUE);
+ mv_write(SDMA_CONFIG_REG(port_num),
+ PORT_SDMA_CONFIG_DEFAULT_VALUE);
/* Enable port Rx. */
mv643xx_eth_port_enable_rx(port_num, ETH_RX_QUEUES_ENABLED);
/* Disable port bandwidth limits by clearing MTU register */
- mv_write(MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port_num), 0);
+ mv_write(MAXIMUM_TRANSMIT_UNIT(port_num), 0);
/* save phy settings across reset */
mv643xx_get_settings(dev, &ethtool_cmd);
@@ -1850,11 +2363,11 @@ static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr)
mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) |
(p_addr[3] << 0);
- mv_write(MV643XX_ETH_MAC_ADDR_LOW(port_num), mac_l);
- mv_write(MV643XX_ETH_MAC_ADDR_HIGH(port_num), mac_h);
+ mv_write(MAC_ADDR_LOW(port_num), mac_l);
+ mv_write(MAC_ADDR_HIGH(port_num), mac_h);
/* Accept frames with this address */
- table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(port_num);
+ table = DA_FILTER_UNICAST_TABLE_BASE(port_num);
eth_port_set_filter_table_entry(table, p_addr[5] & 0x0f);
}
@@ -1866,8 +2379,8 @@ static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr)
unsigned int mac_h;
unsigned int mac_l;
- mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(port_num));
- mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(port_num));
+ mac_h = mv_read(MAC_ADDR_HIGH(port_num));
+ mac_l = mv_read(MAC_ADDR_LOW(port_num));
p_addr[0] = (mac_h >> 24) & 0xff;
p_addr[1] = (mac_h >> 16) & 0xff;
@@ -1927,7 +2440,7 @@ static void eth_port_mc_addr(unsigned int eth_port_num, unsigned char *p_addr)
if ((p_addr[0] == 0x01) && (p_addr[1] == 0x00) &&
(p_addr[2] == 0x5E) && (p_addr[3] == 0x00) && (p_addr[4] == 0x00)) {
- table = MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE
+ table = DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE
(eth_port_num);
eth_port_set_filter_table_entry(table, p_addr[5]);
return;
@@ -2001,7 +2514,7 @@ static void eth_port_mc_addr(unsigned int eth_port_num, unsigned char *p_addr)
for (i = 0; i < 8; i++)
crc_result = crc_result | (crc[i] << i);
- table = MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(eth_port_num);
+ table = DA_FILTER_OTHER_MULTICAST_TABLE_BASE(eth_port_num);
eth_port_set_filter_table_entry(table, crc_result);
}
@@ -2031,7 +2544,7 @@ static void eth_port_set_multicast_list(struct net_device *dev)
* 3-1 Queue ETH_Q0=0
* 7-4 Reserved = 0;
*/
- mv_write(MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101);
+ mv_write(DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101);
/* Set all entries in DA filter other multicast
* table (Ex_dFOMT)
@@ -2041,7 +2554,7 @@ static void eth_port_set_multicast_list(struct net_device *dev)
* 3-1 Queue ETH_Q0=0
* 7-4 Reserved = 0;
*/
- mv_write(MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101);
+ mv_write(DA_FILTER_OTHER_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101);
}
return;
}
@@ -2051,11 +2564,11 @@ static void eth_port_set_multicast_list(struct net_device *dev)
*/
for (table_index = 0; table_index <= 0xFC; table_index += 4) {
/* Clear DA filter special multicast table (Ex_dFSMT) */
- mv_write(MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE
+ mv_write(DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE
(eth_port_num) + table_index, 0);
/* Clear DA filter other multicast table (Ex_dFOMT) */
- mv_write(MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE
+ mv_write(DA_FILTER_OTHER_MULTICAST_TABLE_BASE
(eth_port_num) + table_index, 0);
}
@@ -2089,15 +2602,15 @@ static void eth_port_init_mac_tables(unsigned int eth_port_num)
/* Clear DA filter unicast table (Ex_dFUT) */
for (table_index = 0; table_index <= 0xC; table_index += 4)
- mv_write(MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE
+ mv_write(DA_FILTER_UNICAST_TABLE_BASE
(eth_port_num) + table_index, 0);
for (table_index = 0; table_index <= 0xFC; table_index += 4) {
/* Clear DA filter special multicast table (Ex_dFSMT) */
- mv_write(MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE
+ mv_write(DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE
(eth_port_num) + table_index, 0);
/* Clear DA filter other multicast table (Ex_dFOMT) */
- mv_write(MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE
+ mv_write(DA_FILTER_OTHER_MULTICAST_TABLE_BASE
(eth_port_num) + table_index, 0);
}
}
@@ -2126,12 +2639,12 @@ static void eth_clear_mib_counters(unsigned int eth_port_num)
/* Perform dummy reads from MIB counters */
for (i = ETH_MIB_GOOD_OCTETS_RECEIVED_LOW; i < ETH_MIB_LATE_COLLISION;
i += 4)
- mv_read(MV643XX_ETH_MIB_COUNTERS_BASE(eth_port_num) + i);
+ mv_read(MIB_COUNTERS_BASE(eth_port_num) + i);
}
static inline u32 read_mib(struct mv643xx_private *mp, int offset)
{
- return mv_read(MV643XX_ETH_MIB_COUNTERS_BASE(mp->port_num) + offset);
+ return mv_read(MIB_COUNTERS_BASE(mp->port_num) + offset);
}
static void eth_update_mib_counters(struct mv643xx_private *mp)
@@ -2216,7 +2729,7 @@ static int ethernet_phy_get(unsigned int eth_port_num)
{
unsigned int reg_data;
- reg_data = mv_read(MV643XX_ETH_PHY_ADDR_REG);
+ reg_data = mv_read(PHY_ADDR_REG);
return ((reg_data >> (5 * eth_port_num)) & 0x1f);
}
@@ -2243,10 +2756,10 @@ static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr)
u32 reg_data;
int addr_shift = 5 * eth_port_num;
- reg_data = mv_read(MV643XX_ETH_PHY_ADDR_REG);
+ reg_data = mv_read(PHY_ADDR_REG);
reg_data &= ~(0x1f << addr_shift);
reg_data |= (phy_addr & 0x1f) << addr_shift;
- mv_write(MV643XX_ETH_PHY_ADDR_REG, reg_data);
+ mv_write(PHY_ADDR_REG, reg_data);
}
/*
@@ -2284,13 +2797,13 @@ static void ethernet_phy_reset(unsigned int eth_port_num)
static void mv643xx_eth_port_enable_tx(unsigned int port_num,
unsigned int queues)
{
- mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), queues);
+ mv_write(TRANSMIT_QUEUE_COMMAND_REG(port_num), queues);
}
static void mv643xx_eth_port_enable_rx(unsigned int port_num,
unsigned int queues)
{
- mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), queues);
+ mv_write(RECEIVE_QUEUE_COMMAND_REG(port_num), queues);
}
static unsigned int mv643xx_eth_port_disable_tx(unsigned int port_num)
@@ -2298,21 +2811,18 @@ static unsigned int mv643xx_eth_port_disable_tx(unsigned int port_num)
u32 queues;
/* Stop Tx port activity. Check port Tx activity. */
- queues = mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num))
- & 0xFF;
+ queues = mv_read(TRANSMIT_QUEUE_COMMAND_REG(port_num)) & 0xFF;
if (queues) {
/* Issue stop command for active queues only */
- mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num),
- (queues << 8));
+ mv_write(TRANSMIT_QUEUE_COMMAND_REG(port_num), (queues << 8));
/* Wait for all Tx activity to terminate. */
/* Check port cause register that all Tx queues are stopped */
- while (mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num))
- & 0xFF)
+ while (mv_read(TRANSMIT_QUEUE_COMMAND_REG(port_num)) & 0xFF)
udelay(PHY_WAIT_MICRO_SECONDS);
/* Wait for Tx FIFO to empty */
- while (mv_read(MV643XX_ETH_PORT_STATUS_REG(port_num)) &
+ while (mv_read(PORT_STATUS_REG(port_num)) &
ETH_PORT_TX_FIFO_EMPTY)
udelay(PHY_WAIT_MICRO_SECONDS);
}
@@ -2325,17 +2835,14 @@ static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num)
u32 queues;
/* Stop Rx port activity. Check port Rx activity. */
- queues = mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num))
- & 0xFF;
+ queues = mv_read(RECEIVE_QUEUE_COMMAND_REG(port_num)) & 0xFF;
if (queues) {
/* Issue stop command for active queues only */
- mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num),
- (queues << 8));
+ mv_write(RECEIVE_QUEUE_COMMAND_REG(port_num), (queues << 8));
/* Wait for all Rx activity to terminate. */
/* Check port cause register that all Rx queues are stopped */
- while (mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num))
- & 0xFF)
+ while (mv_read(RECEIVE_QUEUE_COMMAND_REG(port_num)) & 0xFF)
udelay(PHY_WAIT_MICRO_SECONDS);
}
@@ -2371,11 +2878,11 @@ static void eth_port_reset(unsigned int port_num)
eth_clear_mib_counters(port_num);
/* Reset the Enable bit in the Configuration Register */
- reg_data = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num));
- reg_data &= ~(MV643XX_ETH_SERIAL_PORT_ENABLE |
- MV643XX_ETH_DO_NOT_FORCE_LINK_FAIL |
- MV643XX_ETH_FORCE_LINK_PASS);
- mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), reg_data);
+ reg_data = mv_read(PORT_SERIAL_CONTROL_REG(port_num));
+ reg_data &= ~(SERIAL_PORT_ENABLE |
+ DO_NOT_FORCE_LINK_FAIL |
+ FORCE_LINK_PASS);
+ mv_write(PORT_SERIAL_CONTROL_REG(port_num), reg_data);
}
@@ -2410,7 +2917,7 @@ static void eth_port_read_smi_reg(unsigned int port_num,
spin_lock_irqsave(&mv643xx_eth_phy_lock, flags);
/* wait for the SMI register to become available */
- for (i = 0; mv_read(MV643XX_ETH_SMI_REG) & ETH_SMI_BUSY; i++) {
+ for (i = 0; mv_read(SMI_REG) & ETH_SMI_BUSY; i++) {
if (i == PHY_WAIT_ITERATIONS) {
printk("mv643xx PHY busy timeout, port %d\n", port_num);
goto out;
@@ -2418,11 +2925,11 @@ static void eth_port_read_smi_reg(unsigned int port_num,
udelay(PHY_WAIT_MICRO_SECONDS);
}
- mv_write(MV643XX_ETH_SMI_REG,
+ mv_write(SMI_REG,
(phy_addr << 16) | (phy_reg << 21) | ETH_SMI_OPCODE_READ);
/* now wait for the data to be valid */
- for (i = 0; !(mv_read(MV643XX_ETH_SMI_REG) & ETH_SMI_READ_VALID); i++) {
+ for (i = 0; !(mv_read(SMI_REG) & ETH_SMI_READ_VALID); i++) {
if (i == PHY_WAIT_ITERATIONS) {
printk("mv643xx PHY read timeout, port %d\n", port_num);
goto out;
@@ -2430,7 +2937,7 @@ static void eth_port_read_smi_reg(unsigned int port_num,
udelay(PHY_WAIT_MICRO_SECONDS);
}
- *value = mv_read(MV643XX_ETH_SMI_REG) & 0xffff;
+ *value = mv_read(SMI_REG) & 0xffff;
out:
spin_unlock_irqrestore(&mv643xx_eth_phy_lock, flags);
}
@@ -2468,7 +2975,7 @@ static void eth_port_write_smi_reg(unsigned int eth_port_num,
spin_lock_irqsave(&mv643xx_eth_phy_lock, flags);
/* wait for the SMI register to become available */
- for (i = 0; mv_read(MV643XX_ETH_SMI_REG) & ETH_SMI_BUSY; i++) {
+ for (i = 0; mv_read(SMI_REG) & ETH_SMI_BUSY; i++) {
if (i == PHY_WAIT_ITERATIONS) {
printk("mv643xx PHY busy timeout, port %d\n",
eth_port_num);
@@ -2477,7 +2984,7 @@ static void eth_port_write_smi_reg(unsigned int eth_port_num,
udelay(PHY_WAIT_MICRO_SECONDS);
}
- mv_write(MV643XX_ETH_SMI_REG, (phy_addr << 16) | (phy_reg << 21) |
+ mv_write(SMI_REG, (phy_addr << 16) | (phy_reg << 21) |
ETH_SMI_OPCODE_WRITE | (value & 0xffff));
out:
spin_unlock_irqrestore(&mv643xx_eth_phy_lock, flags);
@@ -2687,8 +3194,7 @@ static const struct mv643xx_stats mv643xx_gstrings_stats[] = {
{ "late_collision", MV643XX_STAT(mib_counters.late_collision) },
};
-#define MV643XX_STATS_LEN \
- sizeof(mv643xx_gstrings_stats) / sizeof(struct mv643xx_stats)
+#define MV643XX_STATS_LEN ARRAY_SIZE(mv643xx_gstrings_stats)
static void mv643xx_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
@@ -2700,9 +3206,14 @@ static void mv643xx_get_drvinfo(struct net_device *netdev,
drvinfo->n_stats = MV643XX_STATS_LEN;
}
-static int mv643xx_get_stats_count(struct net_device *netdev)
+static int mv643xx_get_sset_count(struct net_device *netdev, int sset)
{
- return MV643XX_STATS_LEN;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return MV643XX_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void mv643xx_get_ethtool_stats(struct net_device *netdev,
@@ -2762,9 +3273,8 @@ static const struct ethtool_ops mv643xx_ethtool_ops = {
.set_settings = mv643xx_set_settings,
.get_drvinfo = mv643xx_get_drvinfo,
.get_link = mv643xx_eth_get_link,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_stats_count = mv643xx_get_stats_count,
+ .get_sset_count = mv643xx_get_sset_count,
.get_ethtool_stats = mv643xx_get_ethtool_stats,
.get_strings = mv643xx_get_strings,
.nway_reset = mv643xx_eth_nway_restart,
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
deleted file mode 100644
index 565b96696ac..00000000000
--- a/drivers/net/mv643xx_eth.h
+++ /dev/null
@@ -1,368 +0,0 @@
-#ifndef __MV643XX_ETH_H__
-#define __MV643XX_ETH_H__
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
-#include <linux/mii.h>
-
-#include <linux/mv643xx.h>
-
-#include <asm/dma-mapping.h>
-
-/* Checksum offload for Tx works for most packets, but
- * fails if previous packet sent did not use hw csum
- */
-#define MV643XX_CHECKSUM_OFFLOAD_TX
-#define MV643XX_NAPI
-#define MV643XX_TX_FAST_REFILL
-#undef MV643XX_COAL
-
-/*
- * Number of RX / TX descriptors on RX / TX rings.
- * Note that allocating RX descriptors is done by allocating the RX
- * ring AND a preallocated RX buffers (skb's) for each descriptor.
- * The TX descriptors only allocates the TX descriptors ring,
- * with no pre allocated TX buffers (skb's are allocated by higher layers.
- */
-
-/* Default TX ring size is 1000 descriptors */
-#define MV643XX_DEFAULT_TX_QUEUE_SIZE 1000
-
-/* Default RX ring size is 400 descriptors */
-#define MV643XX_DEFAULT_RX_QUEUE_SIZE 400
-
-#define MV643XX_TX_COAL 100
-#ifdef MV643XX_COAL
-#define MV643XX_RX_COAL 100
-#endif
-
-#ifdef MV643XX_CHECKSUM_OFFLOAD_TX
-#define MAX_DESCS_PER_SKB (MAX_SKB_FRAGS + 1)
-#else
-#define MAX_DESCS_PER_SKB 1
-#endif
-
-#define ETH_VLAN_HLEN 4
-#define ETH_FCS_LEN 4
-#define ETH_HW_IP_ALIGN 2 /* hw aligns IP header */
-#define ETH_WRAPPER_LEN (ETH_HW_IP_ALIGN + ETH_HLEN + \
- ETH_VLAN_HLEN + ETH_FCS_LEN)
-#define ETH_RX_SKB_SIZE (dev->mtu + ETH_WRAPPER_LEN + dma_get_cache_alignment())
-
-#define ETH_RX_QUEUES_ENABLED (1 << 0) /* use only Q0 for receive */
-#define ETH_TX_QUEUES_ENABLED (1 << 0) /* use only Q0 for transmit */
-
-#define ETH_INT_CAUSE_RX_DONE (ETH_RX_QUEUES_ENABLED << 2)
-#define ETH_INT_CAUSE_RX_ERROR (ETH_RX_QUEUES_ENABLED << 9)
-#define ETH_INT_CAUSE_RX (ETH_INT_CAUSE_RX_DONE | ETH_INT_CAUSE_RX_ERROR)
-#define ETH_INT_CAUSE_EXT 0x00000002
-#define ETH_INT_UNMASK_ALL (ETH_INT_CAUSE_RX | ETH_INT_CAUSE_EXT)
-
-#define ETH_INT_CAUSE_TX_DONE (ETH_TX_QUEUES_ENABLED << 0)
-#define ETH_INT_CAUSE_TX_ERROR (ETH_TX_QUEUES_ENABLED << 8)
-#define ETH_INT_CAUSE_TX (ETH_INT_CAUSE_TX_DONE | ETH_INT_CAUSE_TX_ERROR)
-#define ETH_INT_CAUSE_PHY 0x00010000
-#define ETH_INT_CAUSE_STATE 0x00100000
-#define ETH_INT_UNMASK_ALL_EXT (ETH_INT_CAUSE_TX | ETH_INT_CAUSE_PHY | \
- ETH_INT_CAUSE_STATE)
-
-#define ETH_INT_MASK_ALL 0x00000000
-#define ETH_INT_MASK_ALL_EXT 0x00000000
-
-#define PHY_WAIT_ITERATIONS 1000 /* 1000 iterations * 10uS = 10mS max */
-#define PHY_WAIT_MICRO_SECONDS 10
-
-/* Buffer offset from buffer pointer */
-#define RX_BUF_OFFSET 0x2
-
-/* Gigabit Ethernet Unit Global Registers */
-
-/* MIB Counters register definitions */
-#define ETH_MIB_GOOD_OCTETS_RECEIVED_LOW 0x0
-#define ETH_MIB_GOOD_OCTETS_RECEIVED_HIGH 0x4
-#define ETH_MIB_BAD_OCTETS_RECEIVED 0x8
-#define ETH_MIB_INTERNAL_MAC_TRANSMIT_ERR 0xc
-#define ETH_MIB_GOOD_FRAMES_RECEIVED 0x10
-#define ETH_MIB_BAD_FRAMES_RECEIVED 0x14
-#define ETH_MIB_BROADCAST_FRAMES_RECEIVED 0x18
-#define ETH_MIB_MULTICAST_FRAMES_RECEIVED 0x1c
-#define ETH_MIB_FRAMES_64_OCTETS 0x20
-#define ETH_MIB_FRAMES_65_TO_127_OCTETS 0x24
-#define ETH_MIB_FRAMES_128_TO_255_OCTETS 0x28
-#define ETH_MIB_FRAMES_256_TO_511_OCTETS 0x2c
-#define ETH_MIB_FRAMES_512_TO_1023_OCTETS 0x30
-#define ETH_MIB_FRAMES_1024_TO_MAX_OCTETS 0x34
-#define ETH_MIB_GOOD_OCTETS_SENT_LOW 0x38
-#define ETH_MIB_GOOD_OCTETS_SENT_HIGH 0x3c
-#define ETH_MIB_GOOD_FRAMES_SENT 0x40
-#define ETH_MIB_EXCESSIVE_COLLISION 0x44
-#define ETH_MIB_MULTICAST_FRAMES_SENT 0x48
-#define ETH_MIB_BROADCAST_FRAMES_SENT 0x4c
-#define ETH_MIB_UNREC_MAC_CONTROL_RECEIVED 0x50
-#define ETH_MIB_FC_SENT 0x54
-#define ETH_MIB_GOOD_FC_RECEIVED 0x58
-#define ETH_MIB_BAD_FC_RECEIVED 0x5c
-#define ETH_MIB_UNDERSIZE_RECEIVED 0x60
-#define ETH_MIB_FRAGMENTS_RECEIVED 0x64
-#define ETH_MIB_OVERSIZE_RECEIVED 0x68
-#define ETH_MIB_JABBER_RECEIVED 0x6c
-#define ETH_MIB_MAC_RECEIVE_ERROR 0x70
-#define ETH_MIB_BAD_CRC_EVENT 0x74
-#define ETH_MIB_COLLISION 0x78
-#define ETH_MIB_LATE_COLLISION 0x7c
-
-/* Port serial status reg (PSR) */
-#define ETH_INTERFACE_PCM 0x00000001
-#define ETH_LINK_IS_UP 0x00000002
-#define ETH_PORT_AT_FULL_DUPLEX 0x00000004
-#define ETH_RX_FLOW_CTRL_ENABLED 0x00000008
-#define ETH_GMII_SPEED_1000 0x00000010
-#define ETH_MII_SPEED_100 0x00000020
-#define ETH_TX_IN_PROGRESS 0x00000080
-#define ETH_BYPASS_ACTIVE 0x00000100
-#define ETH_PORT_AT_PARTITION_STATE 0x00000200
-#define ETH_PORT_TX_FIFO_EMPTY 0x00000400
-
-/* SMI reg */
-#define ETH_SMI_BUSY 0x10000000 /* 0 - Write, 1 - Read */
-#define ETH_SMI_READ_VALID 0x08000000 /* 0 - Write, 1 - Read */
-#define ETH_SMI_OPCODE_WRITE 0 /* Completion of Read */
-#define ETH_SMI_OPCODE_READ 0x04000000 /* Operation is in progress */
-
-/* Interrupt Cause Register Bit Definitions */
-
-/* SDMA command status fields macros */
-
-/* Tx & Rx descriptors status */
-#define ETH_ERROR_SUMMARY 0x00000001
-
-/* Tx & Rx descriptors command */
-#define ETH_BUFFER_OWNED_BY_DMA 0x80000000
-
-/* Tx descriptors status */
-#define ETH_LC_ERROR 0
-#define ETH_UR_ERROR 0x00000002
-#define ETH_RL_ERROR 0x00000004
-#define ETH_LLC_SNAP_FORMAT 0x00000200
-
-/* Rx descriptors status */
-#define ETH_OVERRUN_ERROR 0x00000002
-#define ETH_MAX_FRAME_LENGTH_ERROR 0x00000004
-#define ETH_RESOURCE_ERROR 0x00000006
-#define ETH_VLAN_TAGGED 0x00080000
-#define ETH_BPDU_FRAME 0x00100000
-#define ETH_UDP_FRAME_OVER_IP_V_4 0x00200000
-#define ETH_OTHER_FRAME_TYPE 0x00400000
-#define ETH_LAYER_2_IS_ETH_V_2 0x00800000
-#define ETH_FRAME_TYPE_IP_V_4 0x01000000
-#define ETH_FRAME_HEADER_OK 0x02000000
-#define ETH_RX_LAST_DESC 0x04000000
-#define ETH_RX_FIRST_DESC 0x08000000
-#define ETH_UNKNOWN_DESTINATION_ADDR 0x10000000
-#define ETH_RX_ENABLE_INTERRUPT 0x20000000
-#define ETH_LAYER_4_CHECKSUM_OK 0x40000000
-
-/* Rx descriptors byte count */
-#define ETH_FRAME_FRAGMENTED 0x00000004
-
-/* Tx descriptors command */
-#define ETH_LAYER_4_CHECKSUM_FIRST_DESC 0x00000400
-#define ETH_FRAME_SET_TO_VLAN 0x00008000
-#define ETH_UDP_FRAME 0x00010000
-#define ETH_GEN_TCP_UDP_CHECKSUM 0x00020000
-#define ETH_GEN_IP_V_4_CHECKSUM 0x00040000
-#define ETH_ZERO_PADDING 0x00080000
-#define ETH_TX_LAST_DESC 0x00100000
-#define ETH_TX_FIRST_DESC 0x00200000
-#define ETH_GEN_CRC 0x00400000
-#define ETH_TX_ENABLE_INTERRUPT 0x00800000
-#define ETH_AUTO_MODE 0x40000000
-
-#define ETH_TX_IHL_SHIFT 11
-
-/* typedefs */
-
-typedef enum _eth_func_ret_status {
- ETH_OK, /* Returned as expected. */
- ETH_ERROR, /* Fundamental error. */
- ETH_RETRY, /* Could not process request. Try later.*/
- ETH_END_OF_JOB, /* Ring has nothing to process. */
- ETH_QUEUE_FULL, /* Ring resource error. */
- ETH_QUEUE_LAST_RESOURCE /* Ring resources about to exhaust. */
-} ETH_FUNC_RET_STATUS;
-
-typedef enum _eth_target {
- ETH_TARGET_DRAM,
- ETH_TARGET_DEVICE,
- ETH_TARGET_CBS,
- ETH_TARGET_PCI0,
- ETH_TARGET_PCI1
-} ETH_TARGET;
-
-/* These are for big-endian machines. Little endian needs different
- * definitions.
- */
-#if defined(__BIG_ENDIAN)
-struct eth_rx_desc {
- u16 byte_cnt; /* Descriptor buffer byte count */
- u16 buf_size; /* Buffer size */
- u32 cmd_sts; /* Descriptor command status */
- u32 next_desc_ptr; /* Next descriptor pointer */
- u32 buf_ptr; /* Descriptor buffer pointer */
-};
-
-struct eth_tx_desc {
- u16 byte_cnt; /* buffer byte count */
- u16 l4i_chk; /* CPU provided TCP checksum */
- u32 cmd_sts; /* Command/status field */
- u32 next_desc_ptr; /* Pointer to next descriptor */
- u32 buf_ptr; /* pointer to buffer for this descriptor*/
-};
-
-#elif defined(__LITTLE_ENDIAN)
-struct eth_rx_desc {
- u32 cmd_sts; /* Descriptor command status */
- u16 buf_size; /* Buffer size */
- u16 byte_cnt; /* Descriptor buffer byte count */
- u32 buf_ptr; /* Descriptor buffer pointer */
- u32 next_desc_ptr; /* Next descriptor pointer */
-};
-
-struct eth_tx_desc {
- u32 cmd_sts; /* Command/status field */
- u16 l4i_chk; /* CPU provided TCP checksum */
- u16 byte_cnt; /* buffer byte count */
- u32 buf_ptr; /* pointer to buffer for this descriptor*/
- u32 next_desc_ptr; /* Pointer to next descriptor */
-};
-#else
-#error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined
-#endif
-
-/* Unified struct for Rx and Tx operations. The user is not required to */
-/* be familier with neither Tx nor Rx descriptors. */
-struct pkt_info {
- unsigned short byte_cnt; /* Descriptor buffer byte count */
- unsigned short l4i_chk; /* Tx CPU provided TCP Checksum */
- unsigned int cmd_sts; /* Descriptor command status */
- dma_addr_t buf_ptr; /* Descriptor buffer pointer */
- struct sk_buff *return_info; /* User resource return information */
-};
-
-/* Ethernet port specific information */
-
-struct mv643xx_mib_counters {
- u64 good_octets_received;
- u32 bad_octets_received;
- u32 internal_mac_transmit_err;
- u32 good_frames_received;
- u32 bad_frames_received;
- u32 broadcast_frames_received;
- u32 multicast_frames_received;
- u32 frames_64_octets;
- u32 frames_65_to_127_octets;
- u32 frames_128_to_255_octets;
- u32 frames_256_to_511_octets;
- u32 frames_512_to_1023_octets;
- u32 frames_1024_to_max_octets;
- u64 good_octets_sent;
- u32 good_frames_sent;
- u32 excessive_collision;
- u32 multicast_frames_sent;
- u32 broadcast_frames_sent;
- u32 unrec_mac_control_received;
- u32 fc_sent;
- u32 good_fc_received;
- u32 bad_fc_received;
- u32 undersize_received;
- u32 fragments_received;
- u32 oversize_received;
- u32 jabber_received;
- u32 mac_receive_error;
- u32 bad_crc_event;
- u32 collision;
- u32 late_collision;
-};
-
-struct mv643xx_private {
- int port_num; /* User Ethernet port number */
-
- u32 rx_sram_addr; /* Base address of rx sram area */
- u32 rx_sram_size; /* Size of rx sram area */
- u32 tx_sram_addr; /* Base address of tx sram area */
- u32 tx_sram_size; /* Size of tx sram area */
-
- int rx_resource_err; /* Rx ring resource error flag */
-
- /* Tx/Rx rings managment indexes fields. For driver use */
-
- /* Next available and first returning Rx resource */
- int rx_curr_desc_q, rx_used_desc_q;
-
- /* Next available and first returning Tx resource */
- int tx_curr_desc_q, tx_used_desc_q;
-
-#ifdef MV643XX_TX_FAST_REFILL
- u32 tx_clean_threshold;
-#endif
-
- struct eth_rx_desc *p_rx_desc_area;
- dma_addr_t rx_desc_dma;
- int rx_desc_area_size;
- struct sk_buff **rx_skb;
-
- struct eth_tx_desc *p_tx_desc_area;
- dma_addr_t tx_desc_dma;
- int tx_desc_area_size;
- struct sk_buff **tx_skb;
-
- struct work_struct tx_timeout_task;
-
- struct net_device_stats stats;
- struct mv643xx_mib_counters mib_counters;
- spinlock_t lock;
- /* Size of Tx Ring per queue */
- int tx_ring_size;
- /* Number of tx descriptors in use */
- int tx_desc_count;
- /* Size of Rx Ring per queue */
- int rx_ring_size;
- /* Number of rx descriptors in use */
- int rx_desc_count;
-
- /*
- * Used in case RX Ring is empty, which can be caused when
- * system does not have resources (skb's)
- */
- struct timer_list timeout;
-
- u32 rx_int_coal;
- u32 tx_int_coal;
- struct mii_if_info mii;
-};
-
-/* Port operation control routines */
-static void eth_port_init(struct mv643xx_private *mp);
-static void eth_port_reset(unsigned int eth_port_num);
-static void eth_port_start(struct net_device *dev);
-
-/* PHY and MIB routines */
-static void ethernet_phy_reset(unsigned int eth_port_num);
-
-static void eth_port_write_smi_reg(unsigned int eth_port_num,
- unsigned int phy_reg, unsigned int value);
-
-static void eth_port_read_smi_reg(unsigned int eth_port_num,
- unsigned int phy_reg, unsigned int *value);
-
-static void eth_clear_mib_counters(unsigned int eth_port_num);
-
-/* Port data flow control routines */
-static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp,
- struct pkt_info *p_pkt_info);
-static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv643xx_private *mp,
- struct pkt_info *p_pkt_info);
-
-#endif /* __MV643XX_ETH_H__ */
diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c
index e246d00bba6..06ca4252155 100644
--- a/drivers/net/mvme147.c
+++ b/drivers/net/mvme147.c
@@ -67,6 +67,7 @@ struct net_device * __init mvme147lance_probe(int unit)
u_long *addr;
u_long address;
int err;
+ DECLARE_MAC_BUF(mac);
if (!MACH_IS_MVME147 || called)
return ERR_PTR(-ENODEV);
@@ -79,14 +80,11 @@ struct net_device * __init mvme147lance_probe(int unit)
if (unit >= 0)
sprintf(dev->name, "eth%d", unit);
- SET_MODULE_OWNER(dev);
-
/* Fill the dev fields */
dev->base_addr = (unsigned long)MVME147_LANCE_BASE;
dev->open = &m147lance_open;
dev->stop = &m147lance_close;
dev->hard_start_xmit = &lance_start_xmit;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
dev->tx_timeout = &lance_tx_timeout;
dev->dma = 0;
@@ -103,12 +101,10 @@ struct net_device * __init mvme147lance_probe(int unit)
address=address>>8;
dev->dev_addr[3]=address&0xff;
- printk("%s: MVME147 at 0x%08lx, irq %d, Hardware Address %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name, dev->base_addr, MVME147_LANCE_IRQ,
- dev->dev_addr[0],
- dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4],
- dev->dev_addr[5]);
+ printk("%s: MVME147 at 0x%08lx, irq %d, "
+ "Hardware Address %s\n",
+ dev->name, dev->base_addr, MVME147_LANCE_IRQ,
+ print_mac(mac, dev->dev_addr));
lp = (struct m147lance_private *)dev->priv;
lp->ram = __get_dma_pages(GFP_ATOMIC, 3); /* 16K */
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 556962f9612..0f306ddb563 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -48,6 +48,7 @@
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
+#include <linux/inet_lro.h>
#include <linux/ip.h>
#include <linux/inet.h>
#include <linux/in.h>
@@ -62,6 +63,8 @@
#include <linux/io.h>
#include <linux/log2.h>
#include <net/checksum.h>
+#include <net/ip.h>
+#include <net/tcp.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/processor.h>
@@ -72,7 +75,7 @@
#include "myri10ge_mcp.h"
#include "myri10ge_mcp_gen_header.h"
-#define MYRI10GE_VERSION_STR "1.3.2-1.269"
+#define MYRI10GE_VERSION_STR "1.3.2-1.287"
MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -89,6 +92,8 @@ MODULE_LICENSE("Dual BSD/GPL");
#define MYRI10GE_EEPROM_STRINGS_SIZE 256
#define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2)
+#define MYRI10GE_MAX_LRO_DESCRIPTORS 8
+#define MYRI10GE_LRO_MAX_PKTS 64
#define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff)
#define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff
@@ -151,6 +156,8 @@ struct myri10ge_rx_done {
dma_addr_t bus;
int cnt;
int idx;
+ struct net_lro_mgr lro_mgr;
+ struct net_lro_desc lro_desc[MYRI10GE_MAX_LRO_DESCRIPTORS];
};
struct myri10ge_priv {
@@ -163,6 +170,7 @@ struct myri10ge_priv {
int small_bytes;
int big_bytes;
struct net_device *dev;
+ struct napi_struct napi;
struct net_device_stats stats;
u8 __iomem *sram;
int sram_size;
@@ -206,6 +214,8 @@ struct myri10ge_priv {
unsigned long serial_number;
int vendor_specific_offset;
int fw_multicast_support;
+ unsigned long features;
+ u32 max_tso6;
u32 read_dma;
u32 write_dma;
u32 read_write_dma;
@@ -277,6 +287,14 @@ static int myri10ge_debug = -1; /* defaults above */
module_param(myri10ge_debug, int, 0);
MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)");
+static int myri10ge_lro = 1;
+module_param(myri10ge_lro, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_lro, "Enable large receive offload\n");
+
+static int myri10ge_lro_max_pkts = MYRI10GE_LRO_MAX_PKTS;
+module_param(myri10ge_lro_max_pkts, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_lro, "Number of LRO packets to be aggregated\n");
+
static int myri10ge_fill_thresh = 256;
module_param(myri10ge_fill_thresh, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed\n");
@@ -295,6 +313,7 @@ MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled\n");
#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)
static void myri10ge_set_multicast_list(struct net_device *dev);
+static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev);
static inline void put_be32(__be32 val, __be32 __iomem * p)
{
@@ -596,6 +615,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
__be32 buf[16];
u32 dma_low, dma_high, size;
int status, i;
+ struct myri10ge_cmd cmd;
size = 0;
status = myri10ge_load_hotplug_firmware(mgp, &size);
@@ -672,6 +692,14 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
dev_info(&mgp->pdev->dev, "handoff confirmed\n");
myri10ge_dummy_rdma(mgp, 1);
+ /* probe for IPv6 TSO support */
+ mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
+ &cmd, 0);
+ if (status == 0) {
+ mgp->max_tso6 = cmd.data0;
+ mgp->features |= NETIF_F_TSO6;
+ }
return 0;
}
@@ -1020,9 +1048,19 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
remainder -= MYRI10GE_ALLOC_SIZE;
}
+ if (mgp->csum_flag && myri10ge_lro) {
+ rx_frags[0].page_offset += MXGEFW_PAD;
+ rx_frags[0].size -= MXGEFW_PAD;
+ len -= MXGEFW_PAD;
+ lro_receive_frags(&mgp->rx_done.lro_mgr, rx_frags,
+ len, len, (void *)(unsigned long)csum, csum);
+ return 1;
+ }
+
hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN;
- /* allocate an skb to attach the page(s) to. */
+ /* allocate an skb to attach the page(s) to. This is done
+ * after trying LRO, so as to avoid skb allocation overheads */
skb = netdev_alloc_skb(dev, MYRI10GE_HLEN + 16);
if (unlikely(skb == NULL)) {
@@ -1100,7 +1138,7 @@ static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index)
}
}
-static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
+static inline int myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int budget)
{
struct myri10ge_rx_done *rx_done = &mgp->rx_done;
unsigned long rx_bytes = 0;
@@ -1109,10 +1147,11 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
int idx = rx_done->idx;
int cnt = rx_done->cnt;
+ int work_done = 0;
u16 length;
__wsum checksum;
- while (rx_done->entry[idx].length != 0 && *limit != 0) {
+ while (rx_done->entry[idx].length != 0 && work_done < budget) {
length = ntohs(rx_done->entry[idx].length);
rx_done->entry[idx].length = 0;
checksum = csum_unfold(rx_done->entry[idx].checksum);
@@ -1128,16 +1167,16 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
rx_bytes += rx_ok * (unsigned long)length;
cnt++;
idx = cnt & (myri10ge_max_intr_slots - 1);
-
- /* limit potential for livelock by only handling a
- * limited number of frames. */
- (*limit)--;
+ work_done++;
}
rx_done->idx = idx;
rx_done->cnt = cnt;
mgp->stats.rx_packets += rx_packets;
mgp->stats.rx_bytes += rx_bytes;
+ if (myri10ge_lro)
+ lro_flush_all(&rx_done->lro_mgr);
+
/* restock receive rings if needed */
if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt < myri10ge_fill_thresh)
myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
@@ -1145,6 +1184,7 @@ static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt < myri10ge_fill_thresh)
myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0);
+ return work_done;
}
static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
@@ -1189,26 +1229,21 @@ static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
}
}
-static int myri10ge_poll(struct net_device *netdev, int *budget)
+static int myri10ge_poll(struct napi_struct *napi, int budget)
{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
- struct myri10ge_rx_done *rx_done = &mgp->rx_done;
- int limit, orig_limit, work_done;
+ struct myri10ge_priv *mgp =
+ container_of(napi, struct myri10ge_priv, napi);
+ struct net_device *netdev = mgp->dev;
+ int work_done;
/* process as many rx events as NAPI will allow */
- limit = min(*budget, netdev->quota);
- orig_limit = limit;
- myri10ge_clean_rx_done(mgp, &limit);
- work_done = orig_limit - limit;
- *budget -= work_done;
- netdev->quota -= work_done;
-
- if (rx_done->entry[rx_done->idx].length == 0 || !netif_running(netdev)) {
- netif_rx_complete(netdev);
+ work_done = myri10ge_clean_rx_done(mgp, budget);
+
+ if (work_done < budget || !netif_running(netdev)) {
+ netif_rx_complete(netdev, napi);
put_be32(htonl(3), mgp->irq_claim);
- return 0;
}
- return 1;
+ return work_done;
}
static irqreturn_t myri10ge_intr(int irq, void *arg)
@@ -1226,7 +1261,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg)
/* low bit indicates receives are present, so schedule
* napi poll handler */
if (stats->valid & 1)
- netif_rx_schedule(mgp->dev);
+ netif_rx_schedule(mgp->dev, &mgp->napi);
if (!mgp->msi_enabled) {
put_be32(0, mgp->irq_deassert);
@@ -1361,6 +1396,18 @@ static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
return 0;
}
+static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ unsigned long flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO);
+
+ if (tso_enabled)
+ netdev->features |= flags;
+ else
+ netdev->features &= ~flags;
+ return 0;
+}
+
static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
@@ -1379,7 +1426,8 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
"dropped_pause", "dropped_bad_phy", "dropped_bad_crc32",
"dropped_unicast_filtered", "dropped_multicast_filtered",
"dropped_runt", "dropped_overrun", "dropped_no_small_buffer",
- "dropped_no_big_buffer"
+ "dropped_no_big_buffer", "LRO aggregated", "LRO flushed",
+ "LRO avg aggr", "LRO no_desc"
};
#define MYRI10GE_NET_STATS_LEN 21
@@ -1396,9 +1444,14 @@ myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data)
}
}
-static int myri10ge_get_stats_count(struct net_device *netdev)
+static int myri10ge_get_sset_count(struct net_device *netdev, int sset)
{
- return MYRI10GE_STATS_LEN;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return MYRI10GE_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void
@@ -1445,6 +1498,14 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun);
data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer);
data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_big_buffer);
+ data[i++] = mgp->rx_done.lro_mgr.stats.aggregated;
+ data[i++] = mgp->rx_done.lro_mgr.stats.flushed;
+ if (mgp->rx_done.lro_mgr.stats.flushed)
+ data[i++] = mgp->rx_done.lro_mgr.stats.aggregated /
+ mgp->rx_done.lro_mgr.stats.flushed;
+ else
+ data[i++] = 0;
+ data[i++] = mgp->rx_done.lro_mgr.stats.no_desc;
}
static void myri10ge_set_msglevel(struct net_device *netdev, u32 value)
@@ -1469,15 +1530,12 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
.get_ringparam = myri10ge_get_ringparam,
.get_rx_csum = myri10ge_get_rx_csum,
.set_rx_csum = myri10ge_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_hw_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = ethtool_op_set_tso,
+ .set_tso = myri10ge_set_tso,
.get_link = ethtool_op_get_link,
.get_strings = myri10ge_get_strings,
- .get_stats_count = myri10ge_get_stats_count,
+ .get_sset_count = myri10ge_get_sset_count,
.get_ethtool_stats = myri10ge_get_ethtool_stats,
.set_msglevel = myri10ge_set_msglevel,
.get_msglevel = myri10ge_get_msglevel
@@ -1718,10 +1776,69 @@ static void myri10ge_free_irq(struct myri10ge_priv *mgp)
pci_disable_msi(pdev);
}
+static int
+myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
+ void **ip_hdr, void **tcpudp_hdr,
+ u64 * hdr_flags, void *priv)
+{
+ struct ethhdr *eh;
+ struct vlan_ethhdr *veh;
+ struct iphdr *iph;
+ u8 *va = page_address(frag->page) + frag->page_offset;
+ unsigned long ll_hlen;
+ __wsum csum = (__wsum) (unsigned long)priv;
+
+ /* find the mac header, aborting if not IPv4 */
+
+ eh = (struct ethhdr *)va;
+ *mac_hdr = eh;
+ ll_hlen = ETH_HLEN;
+ if (eh->h_proto != htons(ETH_P_IP)) {
+ if (eh->h_proto == htons(ETH_P_8021Q)) {
+ veh = (struct vlan_ethhdr *)va;
+ if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
+ return -1;
+
+ ll_hlen += VLAN_HLEN;
+
+ /*
+ * HW checksum starts ETH_HLEN bytes into
+ * frame, so we must subtract off the VLAN
+ * header's checksum before csum can be used
+ */
+ csum = csum_sub(csum, csum_partial(va + ETH_HLEN,
+ VLAN_HLEN, 0));
+ } else {
+ return -1;
+ }
+ }
+ *hdr_flags = LRO_IPV4;
+
+ iph = (struct iphdr *)(va + ll_hlen);
+ *ip_hdr = iph;
+ if (iph->protocol != IPPROTO_TCP)
+ return -1;
+ *hdr_flags |= LRO_TCP;
+ *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2);
+
+ /* verify the IP checksum */
+ if (unlikely(ip_fast_csum((u8 *) iph, iph->ihl)))
+ return -1;
+
+ /* verify the checksum */
+ if (unlikely(csum_tcpudp_magic(iph->saddr, iph->daddr,
+ ntohs(iph->tot_len) - (iph->ihl << 2),
+ IPPROTO_TCP, csum)))
+ return -1;
+
+ return 0;
+}
+
static int myri10ge_open(struct net_device *dev)
{
struct myri10ge_priv *mgp;
struct myri10ge_cmd cmd;
+ struct net_lro_mgr *lro_mgr;
int status, big_pow2;
mgp = netdev_priv(dev);
@@ -1853,7 +1970,19 @@ static int myri10ge_open(struct net_device *dev)
mgp->link_state = htonl(~0U);
mgp->rdma_tags_available = 15;
- netif_poll_enable(mgp->dev); /* must happen prior to any irq */
+ lro_mgr = &mgp->rx_done.lro_mgr;
+ lro_mgr->dev = dev;
+ lro_mgr->features = LRO_F_NAPI;
+ lro_mgr->ip_summed = CHECKSUM_COMPLETE;
+ lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
+ lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS;
+ lro_mgr->lro_arr = mgp->rx_done.lro_desc;
+ lro_mgr->get_frag_header = myri10ge_get_frag_header;
+ lro_mgr->max_aggr = myri10ge_lro_max_pkts;
+ if (lro_mgr->max_aggr > MAX_SKB_FRAGS)
+ lro_mgr->max_aggr = MAX_SKB_FRAGS;
+
+ napi_enable(&mgp->napi); /* must happen prior to any irq */
status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0);
if (status) {
@@ -1897,7 +2026,7 @@ static int myri10ge_close(struct net_device *dev)
del_timer_sync(&mgp->watchdog_timer);
mgp->running = MYRI10GE_ETH_STOPPING;
- netif_poll_disable(mgp->dev);
+ napi_disable(&mgp->napi);
netif_carrier_off(dev);
netif_stop_queue(dev);
old_down_cnt = mgp->down_cnt;
@@ -2061,7 +2190,8 @@ again:
pseudo_hdr_offset = cksum_offset + skb->csum_offset;
/* If the headers are excessively large, then we must
* fall back to a software checksum */
- if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) {
+ if (unlikely(!mss && (cksum_offset > 255 ||
+ pseudo_hdr_offset > 127))) {
if (skb_checksum_help(skb))
goto drop;
cksum_offset = 0;
@@ -2081,9 +2211,18 @@ again:
/* negative cum_len signifies to the
* send loop that we are still in the
* header portion of the TSO packet.
- * TSO header must be at most 134 bytes long */
+ * TSO header can be at most 1KB long */
cum_len = -(skb_transport_offset(skb) + tcp_hdrlen(skb));
+ /* for IPv6 TSO, the checksum offset stores the
+ * TCP header length, to save the firmware from
+ * the need to parse the headers */
+ if (skb_is_gso_v6(skb)) {
+ cksum_offset = tcp_hdrlen(skb);
+ /* Can only handle headers <= max_tso6 long */
+ if (unlikely(-cum_len > mgp->max_tso6))
+ return myri10ge_sw_tso(skb, dev);
+ }
/* for TSO, pseudo_hdr_offset holds mss.
* The firmware figures out where to put
* the checksum by parsing the header. */
@@ -2198,10 +2337,12 @@ again:
req++;
count++;
rdma_count++;
- if (unlikely(cksum_offset > seglen))
- cksum_offset -= seglen;
- else
- cksum_offset = 0;
+ if (cksum_offset != 0 && !(mss && skb_is_gso_v6(skb))) {
+ if (unlikely(cksum_offset > seglen))
+ cksum_offset -= seglen;
+ else
+ cksum_offset = 0;
+ }
}
if (frag_idx == frag_cnt)
break;
@@ -2284,6 +2425,41 @@ drop:
}
+static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev)
+{
+ struct sk_buff *segs, *curr;
+ struct myri10ge_priv *mgp = dev->priv;
+ int status;
+
+ segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6);
+ if (unlikely(IS_ERR(segs)))
+ goto drop;
+
+ while (segs) {
+ curr = segs;
+ segs = segs->next;
+ curr->next = NULL;
+ status = myri10ge_xmit(curr, dev);
+ if (status != 0) {
+ dev_kfree_skb_any(curr);
+ if (segs != NULL) {
+ curr = segs;
+ segs = segs->next;
+ curr->next = NULL;
+ dev_kfree_skb_any(segs);
+ }
+ goto drop;
+ }
+ }
+ dev_kfree_skb_any(skb);
+ return 0;
+
+drop:
+ dev_kfree_skb_any(skb);
+ mgp->stats.tx_dropped += 1;
+ return 0;
+}
+
static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
{
struct myri10ge_priv *mgp = netdev_priv(dev);
@@ -2297,6 +2473,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
struct dev_mc_list *mc_list;
__be32 data[2] = { 0, 0 };
int err;
+ DECLARE_MAC_BUF(mac);
mgp = netdev_priv(dev);
/* can be called from atomic contexts,
@@ -2344,14 +2521,8 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
printk(KERN_ERR "myri10ge: %s: Failed "
"MXGEFW_JOIN_MULTICAST_GROUP, error status:"
"%d\t", dev->name, err);
- printk(KERN_ERR "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
- ((unsigned char *)&mc_list->dmi_addr)[0],
- ((unsigned char *)&mc_list->dmi_addr)[1],
- ((unsigned char *)&mc_list->dmi_addr)[2],
- ((unsigned char *)&mc_list->dmi_addr)[3],
- ((unsigned char *)&mc_list->dmi_addr)[4],
- ((unsigned char *)&mc_list->dmi_addr)[5]
- );
+ printk(KERN_ERR "MAC %s\n",
+ print_mac(mac, mc_list->dmi_addr));
goto abort;
}
}
@@ -2608,7 +2779,6 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
}
#ifdef CONFIG_PM
-
static int myri10ge_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct myri10ge_priv *mgp;
@@ -2689,7 +2859,6 @@ abort_with_enabled:
return -EIO;
}
-
#endif /* CONFIG_PM */
static u32 myri10ge_read_reboot(struct myri10ge_priv *mgp)
@@ -2855,8 +3024,8 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
SET_NETDEV_DEV(netdev, &pdev->dev);
mgp = netdev_priv(netdev);
- memset(mgp, 0, sizeof(*mgp));
mgp->dev = netdev;
+ netif_napi_add(netdev, &mgp->napi, myri10ge_poll, myri10ge_napi_weight);
mgp->pdev = pdev;
mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
mgp->pause = myri10ge_flow_control;
@@ -2889,7 +3058,8 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (status != 0) {
dac_enabled = 0;
dev_err(&pdev->dev,
- "64-bit pci address mask was refused, trying 32-bit");
+ "64-bit pci address mask was refused, "
+ "trying 32-bit\n");
status = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
}
if (status != 0) {
@@ -2978,11 +3148,9 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->change_mtu = myri10ge_change_mtu;
netdev->set_multicast_list = myri10ge_set_multicast_list;
netdev->set_mac_address = myri10ge_set_mac_address;
- netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
+ netdev->features = mgp->features;
if (dac_enabled)
netdev->features |= NETIF_F_HIGHDMA;
- netdev->poll = myri10ge_poll;
- netdev->weight = myri10ge_napi_weight;
/* make sure we can get an irq, and that MSI can be
* setup (if available). Also ensure netdev->irq
diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h
index a1d2a22296a..58e57178c56 100644
--- a/drivers/net/myri10ge/myri10ge_mcp.h
+++ b/drivers/net/myri10ge/myri10ge_mcp.h
@@ -10,7 +10,7 @@ struct mcp_dma_addr {
__be32 low;
};
-/* 4 Bytes */
+/* 4 Bytes. 8 Bytes for NDIS drivers. */
struct mcp_slot {
__sum16 checksum;
__be16 length;
@@ -205,8 +205,87 @@ enum myri10ge_mcp_cmd_type {
/* same than DMA_TEST (same args) but abort with UNALIGNED on unaligned
* chipset */
- MXGEFW_CMD_UNALIGNED_STATUS
- /* return data = boolean, true if the chipset is known to be unaligned */
+ MXGEFW_CMD_UNALIGNED_STATUS,
+ /* return data = boolean, true if the chipset is known to be unaligned */
+
+ MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS,
+ /* data0 = number of big buffers to use. It must be 0 or a power of 2.
+ * 0 indicates that the NIC consumes as many buffers as they are required
+ * for packet. This is the default behavior.
+ * A power of 2 number indicates that the NIC always uses the specified
+ * number of buffers for each big receive packet.
+ * It is up to the driver to ensure that this value is big enough for
+ * the NIC to be able to receive maximum-sized packets.
+ */
+
+ MXGEFW_CMD_GET_MAX_RSS_QUEUES,
+ MXGEFW_CMD_ENABLE_RSS_QUEUES,
+ /* data0 = number of slices n (0, 1, ..., n-1) to enable
+ * data1 = interrupt mode. 0=share one INTx/MSI, 1=use one MSI-X per queue.
+ * If all queues share one interrupt, the driver must have set
+ * RSS_SHARED_INTERRUPT_DMA before enabling queues.
+ */
+ MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET,
+ MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA,
+ /* data0, data1 = bus address lsw, msw */
+ MXGEFW_CMD_GET_RSS_TABLE_OFFSET,
+ /* get the offset of the indirection table */
+ MXGEFW_CMD_SET_RSS_TABLE_SIZE,
+ /* set the size of the indirection table */
+ MXGEFW_CMD_GET_RSS_KEY_OFFSET,
+ /* get the offset of the secret key */
+ MXGEFW_CMD_RSS_KEY_UPDATED,
+ /* tell nic that the secret key's been updated */
+ MXGEFW_CMD_SET_RSS_ENABLE,
+ /* data0 = enable/disable rss
+ * 0: disable rss. nic does not distribute receive packets.
+ * 1: enable rss. nic distributes receive packets among queues.
+ * data1 = hash type
+ * 1: IPV4
+ * 2: TCP_IPV4
+ * 3: IPV4 | TCP_IPV4
+ */
+
+ MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE,
+ /* Return data = the max. size of the entire headers of a IPv6 TSO packet.
+ * If the header size of a IPv6 TSO packet is larger than the specified
+ * value, then the driver must not use TSO.
+ * This size restriction only applies to IPv6 TSO.
+ * For IPv4 TSO, the maximum size of the headers is fixed, and the NIC
+ * always has enough header buffer to store maximum-sized headers.
+ */
+
+ MXGEFW_CMD_SET_TSO_MODE,
+ /* data0 = TSO mode.
+ * 0: Linux/FreeBSD style (NIC default)
+ * 1: NDIS/NetBSD style
+ */
+
+ MXGEFW_CMD_MDIO_READ,
+ /* data0 = dev_addr (PMA/PMD or PCS ...), data1 = register/addr */
+ MXGEFW_CMD_MDIO_WRITE,
+ /* data0 = dev_addr, data1 = register/addr, data2 = value */
+
+ MXGEFW_CMD_XFP_I2C_READ,
+ /* Starts to get a fresh copy of one byte or of the whole xfp i2c table, the
+ * obtained data is cached inside the xaui-xfi chip :
+ * data0 : "all" flag : 0 => get one byte, 1=> get 256 bytes,
+ * data1 : if (data0 == 0): index of byte to refresh [ not used otherwise ]
+ * The operation might take ~1ms for a single byte or ~65ms when refreshing all 256 bytes
+ * During the i2c operation, MXGEFW_CMD_XFP_I2C_READ or MXGEFW_CMD_XFP_BYTE attempts
+ * will return MXGEFW_CMD_ERROR_BUSY
+ */
+ MXGEFW_CMD_XFP_BYTE,
+ /* Return the last obtained copy of a given byte in the xfp i2c table
+ * (copy cached during the last relevant MXGEFW_CMD_XFP_I2C_READ)
+ * data0 : index of the desired table entry
+ * Return data = the byte stored at the requested index in the table
+ */
+
+ MXGEFW_CMD_GET_VPUMP_OFFSET,
+ /* Return data = NIC memory offset of mcp_vpump_public_global */
+ MXGEFW_CMD_RESET_VPUMP,
+ /* Resets the VPUMP state */
};
enum myri10ge_mcp_cmd_status {
@@ -220,7 +299,10 @@ enum myri10ge_mcp_cmd_status {
MXGEFW_CMD_ERROR_BAD_PORT,
MXGEFW_CMD_ERROR_RESOURCES,
MXGEFW_CMD_ERROR_MULTICAST,
- MXGEFW_CMD_ERROR_UNALIGNED
+ MXGEFW_CMD_ERROR_UNALIGNED,
+ MXGEFW_CMD_ERROR_NO_MDIO,
+ MXGEFW_CMD_ERROR_XFP_FAILURE,
+ MXGEFW_CMD_ERROR_XFP_ABSENT
};
#define MXGEFW_OLD_IRQ_DATA_LEN 40
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 13444da9327..656a260fc95 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -134,7 +134,7 @@ static int myri_do_handshake(struct myri_eth *mp)
myri_disable_irq(mp->lregs, cregs);
- while (tick++ <= 25) {
+ while (tick++ < 25) {
u32 softstate;
/* Wake it up. */
@@ -311,12 +311,12 @@ static void myri_is_not_so_happy(struct myri_eth *mp)
#ifdef DEBUG_HEADER
static void dump_ehdr(struct ethhdr *ehdr)
{
- printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)"
- "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n",
- ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2],
- ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4],
- ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2],
- ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4],
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ printk("ehdr[h_dst(%s)"
+ "h_source(%s)"
+ "h_proto(%04x)]\n",
+ print_mac(mac, ehdr->h_dest), print_mac(mac2, ehdr->h_source),
ehdr->h_proto);
}
@@ -325,13 +325,7 @@ static void dump_ehdr_and_myripad(unsigned char *stuff)
struct ethhdr *ehdr = (struct ethhdr *) (stuff + 2);
printk("pad[%02x:%02x]", stuff[0], stuff[1]);
- printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)"
- "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n",
- ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2],
- ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4],
- ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2],
- ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4],
- ehdr->h_proto);
+ dump_ehdr(ehdr);
}
#endif
@@ -353,7 +347,7 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev)
sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE);
dev_kfree_skb(skb);
mp->tx_skbs[entry] = NULL;
- mp->enet_stats.tx_packets++;
+ dev->stats.tx_packets++;
entry = NEXT_TX(entry);
}
mp->tx_old = entry;
@@ -434,20 +428,20 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) {
DRX(("ERROR["));
- mp->enet_stats.rx_errors++;
+ dev->stats.rx_errors++;
if (len < (ETH_HLEN + MYRI_PAD_LEN)) {
DRX(("BAD_LENGTH] "));
- mp->enet_stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} else {
DRX(("NO_PADDING] "));
- mp->enet_stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
}
/* Return it to the LANAI. */
drop_it:
drops++;
DRX(("DROP "));
- mp->enet_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
sbus_dma_sync_single_for_device(mp->myri_sdev,
sbus_readl(&rxd->myri_scatters[0].addr),
RX_ALLOC_SIZE,
@@ -527,8 +521,8 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
netif_rx(skb);
dev->last_rx = jiffies;
- mp->enet_stats.rx_packets++;
- mp->enet_stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
next:
DRX(("NEXT\n"));
entry = NEXT_RX(entry);
@@ -596,7 +590,7 @@ static void myri_tx_timeout(struct net_device *dev)
printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
- mp->enet_stats.tx_errors++;
+ dev->stats.tx_errors++;
myri_init(mp, 0);
netif_wake_queue(dev);
}
@@ -682,8 +676,9 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
* saddr=NULL means use device source address
* daddr=NULL means leave destination address (eg unresolved arp)
*/
-static int myri_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len)
+static int myri_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
unsigned char *pad = (unsigned char *) skb_push(skb, MYRI_PAD_LEN);
@@ -765,18 +760,18 @@ static int myri_rebuild_header(struct sk_buff *skb)
return 0;
}
-int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+static int myri_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
{
unsigned short type = hh->hh_type;
unsigned char *pad;
struct ethhdr *eth;
- struct net_device *dev = neigh->dev;
+ const struct net_device *dev = neigh->dev;
pad = ((unsigned char *) hh->hh_data) +
HH_DATA_OFF(sizeof(*eth) + MYRI_PAD_LEN);
eth = (struct ethhdr *) (pad + MYRI_PAD_LEN);
- if (type == __constant_htons(ETH_P_802_3))
+ if (type == htons(ETH_P_802_3))
return -1;
/* Refill MyriNet padding identifiers, this is just being anal. */
@@ -792,7 +787,9 @@ int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh)
/* Called by Address Resolution module to notify changes in address. */
-void myri_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr)
+void myri_header_cache_update(struct hh_cache *hh,
+ const struct net_device *dev,
+ const unsigned char * haddr)
{
memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)),
haddr, dev->addr_len);
@@ -806,9 +803,6 @@ static int myri_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-static struct net_device_stats *myri_get_stats(struct net_device *dev)
-{ return &(((struct myri_eth *)dev->priv)->enet_stats); }
-
static void myri_set_multicast(struct net_device *dev)
{
/* Do nothing, all MyriCOM nodes transmit multicast frames
@@ -890,6 +884,13 @@ static void dump_eeprom(struct myri_eth *mp)
}
#endif
+static const struct header_ops myri_header_ops = {
+ .create = myri_header,
+ .rebuild = myri_rebuild_header,
+ .cache = myri_header_cache,
+ .cache_update = myri_header_cache_update,
+};
+
static int __devinit myri_ether_init(struct sbus_dev *sdev)
{
static int num;
@@ -898,6 +899,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
struct myri_eth *mp;
unsigned char prop_buf[32];
int i;
+ DECLARE_MAC_BUF(mac);
DET(("myri_ether_init(%p,%d):\n", sdev, num));
dev = alloc_etherdev(sizeof(struct myri_eth));
@@ -908,7 +910,6 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
if (version_printed++ == 0)
printk(version);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
mp = (struct myri_eth *) dev->priv;
@@ -1061,7 +1062,6 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
dev->hard_start_xmit = &myri_start_xmit;
dev->tx_timeout = &myri_tx_timeout;
dev->watchdog_timeo = 5*HZ;
- dev->get_stats = &myri_get_stats;
dev->set_multicast_list = &myri_set_multicast;
dev->irq = sdev->irqs[0];
@@ -1075,11 +1075,9 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
dev->mtu = MYRINET_MTU;
dev->change_mtu = myri_change_mtu;
- dev->hard_header = myri_header;
- dev->rebuild_header = myri_rebuild_header;
+ dev->header_ops = &myri_header_ops;
+
dev->hard_header_len = (ETH_HLEN + MYRI_PAD_LEN);
- dev->hard_header_cache = myri_header_cache;
- dev->header_cache_update= myri_header_cache_update;
/* Load code onto the LANai. */
DET(("Loading LANAI firmware\n"));
@@ -1094,12 +1092,8 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
num++;
- printk("%s: MyriCOM MyriNET Ethernet ", dev->name);
-
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- i == 5 ? ' ' : ':');
- printk("\n");
+ printk("%s: MyriCOM MyriNET Ethernet %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
return 0;
diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h
index 2f69ef7cdcc..5d93fcc95d5 100644
--- a/drivers/net/myri_sbus.h
+++ b/drivers/net/myri_sbus.h
@@ -280,7 +280,6 @@ struct myri_eth {
void __iomem *lregs; /* Quick ptr to LANAI regs. */
struct sk_buff *rx_skbs[RX_RING_SIZE+1];/* RX skb's */
struct sk_buff *tx_skbs[TX_RING_SIZE]; /* TX skb's */
- struct net_device_stats enet_stats; /* Interface stats. */
/* These are less frequently accessed. */
void __iomem *regs; /* MyriCOM register space. */
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index b47a12d684f..87cde062fd6 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -108,7 +108,7 @@ static int full_duplex[MAX_UNITS];
#define TX_TIMEOUT (2*HZ)
#define NATSEMI_HW_TIMEOUT 400
-#define NATSEMI_TIMER_FREQ 3*HZ
+#define NATSEMI_TIMER_FREQ 5*HZ
#define NATSEMI_PG0_NREGS 64
#define NATSEMI_RFDR_NREGS 8
#define NATSEMI_PG1_NREGS 4
@@ -560,6 +560,8 @@ struct netdev_private {
/* address of a sent-in-place packet/buffer, for later free() */
struct sk_buff *tx_skbuff[TX_RING_SIZE];
dma_addr_t tx_dma[TX_RING_SIZE];
+ struct net_device *dev;
+ struct napi_struct napi;
struct net_device_stats stats;
/* Media monitoring timer */
struct timer_list timer;
@@ -636,7 +638,7 @@ static void init_registers(struct net_device *dev);
static int start_tx(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t intr_handler(int irq, void *dev_instance);
static void netdev_error(struct net_device *dev, int intr_status);
-static int natsemi_poll(struct net_device *dev, int *budget);
+static int natsemi_poll(struct napi_struct *napi, int budget);
static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do);
static void netdev_tx_done(struct net_device *dev);
static int natsemi_change_mtu(struct net_device *dev, int new_mtu);
@@ -803,6 +805,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
const int pcibar = 1; /* PCI base address register */
int prev_eedata;
u32 tmp;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -835,7 +838,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
dev = alloc_etherdev(sizeof (struct netdev_private));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
i = pci_request_regions(pdev, DRV_NAME);
@@ -861,6 +863,8 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
dev->irq = irq;
np = netdev_priv(dev);
+ netif_napi_add(dev, &np->napi, natsemi_poll, 64);
+ np->dev = dev;
np->pci_dev = pdev;
pci_set_drvdata(pdev, dev);
@@ -931,8 +935,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
dev->do_ioctl = &netdev_ioctl;
dev->tx_timeout = &tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
- dev->poll = natsemi_poll;
- dev->weight = 64;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = &natsemi_poll_controller;
@@ -958,12 +960,10 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
goto err_create_file;
if (netif_msg_drv(np)) {
- printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ",
- dev->name, natsemi_pci_info[chip_idx].name, iostart,
- pci_name(np->pci_dev));
- for (i = 0; i < ETH_ALEN-1; i++)
- printk("%02x:", dev->dev_addr[i]);
- printk("%02x, IRQ %d", dev->dev_addr[i], irq);
+ printk(KERN_INFO "natsemi %s: %s at %#08lx "
+ "(%s), %s, IRQ %d",
+ dev->name, natsemi_pci_info[chip_idx].name, iostart,
+ pci_name(np->pci_dev), print_mac(mac, dev->dev_addr), irq);
if (dev->if_port == PORT_TP)
printk(", port TP.\n");
else if (np->ignore_phy)
@@ -997,7 +997,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that
made udelay() unreliable.
The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is
- depricated.
+ deprecated.
*/
#define eeprom_delay(ee_addr) readl(ee_addr)
@@ -1554,6 +1554,8 @@ static int netdev_open(struct net_device *dev)
free_irq(dev->irq, dev);
return i;
}
+ napi_enable(&np->napi);
+
init_ring(dev);
spin_lock_irq(&np->lock);
init_registers(dev);
@@ -1575,7 +1577,7 @@ static int netdev_open(struct net_device *dev)
/* Set the timer to check for link beat. */
init_timer(&np->timer);
- np->timer.expires = jiffies + NATSEMI_TIMER_FREQ;
+ np->timer.expires = round_jiffies(jiffies + NATSEMI_TIMER_FREQ);
np->timer.data = (unsigned long)dev;
np->timer.function = &netdev_timer; /* timer handler */
add_timer(&np->timer);
@@ -1614,7 +1616,7 @@ static void do_cable_magic(struct net_device *dev)
* (these values all come from National)
*/
if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) {
- struct netdev_private *np = netdev_priv(dev);
+ np = netdev_priv(dev);
/* the bug has been triggered - fix the coefficient */
writew(TSTDAT_FIXED, ioaddr + TSTDAT);
@@ -1797,7 +1799,7 @@ static void netdev_timer(unsigned long data)
struct net_device *dev = (struct net_device *)data;
struct netdev_private *np = netdev_priv(dev);
void __iomem * ioaddr = ns_ioaddr(dev);
- int next_tick = 5*HZ;
+ int next_tick = NATSEMI_TIMER_FREQ;
if (netif_msg_timer(np)) {
/* DO NOT read the IntrStatus register,
@@ -1855,7 +1857,11 @@ static void netdev_timer(unsigned long data)
next_tick = 1;
}
}
- mod_timer(&np->timer, jiffies + next_tick);
+
+ if (next_tick > 1)
+ mod_timer(&np->timer, round_jiffies(jiffies + next_tick));
+ else
+ mod_timer(&np->timer, jiffies + next_tick);
}
static void dump_ring(struct net_device *dev)
@@ -2200,10 +2206,10 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]);
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &np->napi)) {
/* Disable interrupts and register for poll */
natsemi_irq_disable(dev);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &np->napi);
} else
printk(KERN_WARNING
"%s: Ignoring interrupt, status %#08x, mask %#08x.\n",
@@ -2216,12 +2222,11 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
/* This is the NAPI poll routine. As well as the standard RX handling
* it also handles all other interrupts that the chip might raise.
*/
-static int natsemi_poll(struct net_device *dev, int *budget)
+static int natsemi_poll(struct napi_struct *napi, int budget)
{
- struct netdev_private *np = netdev_priv(dev);
+ struct netdev_private *np = container_of(napi, struct netdev_private, napi);
+ struct net_device *dev = np->dev;
void __iomem * ioaddr = ns_ioaddr(dev);
-
- int work_to_do = min(*budget, dev->quota);
int work_done = 0;
do {
@@ -2236,7 +2241,7 @@ static int natsemi_poll(struct net_device *dev, int *budget)
if (np->intr_status &
(IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
IntrRxErr | IntrRxOverrun)) {
- netdev_rx(dev, &work_done, work_to_do);
+ netdev_rx(dev, &work_done, budget);
}
if (np->intr_status &
@@ -2250,16 +2255,13 @@ static int natsemi_poll(struct net_device *dev, int *budget)
if (np->intr_status & IntrAbnormalSummary)
netdev_error(dev, np->intr_status);
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (work_done >= work_to_do)
- return 1;
+ if (work_done >= budget)
+ return work_done;
np->intr_status = readl(ioaddr + IntrStatus);
} while (np->intr_status);
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
/* Reenable interrupts providing nothing is trying to shut
* the chip down. */
@@ -2268,7 +2270,7 @@ static int natsemi_poll(struct net_device *dev, int *budget)
natsemi_irq_enable(dev);
spin_unlock(&np->lock);
- return 0;
+ return work_done;
}
/* This routine is logically part of the interrupt handler, but separated
@@ -2505,8 +2507,8 @@ static void __set_rx_mode(struct net_device *dev)
memset(mc_filter, 0, sizeof(mc_filter));
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
- int i = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff;
- mc_filter[i/8] |= (1 << (i & 0x07));
+ int b = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff;
+ mc_filter[b/8] |= (1 << (b & 0x07));
}
rx_mode = RxFilterEnable | AcceptBroadcast
| AcceptMulticast | AcceptMyPhys;
@@ -3158,6 +3160,8 @@ static int netdev_close(struct net_device *dev)
dev->name, np->cur_tx, np->dirty_tx,
np->cur_rx, np->dirty_rx);
+ napi_disable(&np->napi);
+
/*
* FIXME: what if someone tries to close a device
* that is suspended?
@@ -3253,7 +3257,7 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev)
* disable_irq() to enforce synchronization.
* * natsemi_poll: checks before reenabling interrupts. suspend
* sets hands_off, disables interrupts and then waits with
- * netif_poll_disable().
+ * napi_disable().
*
* Interrupts must be disabled, otherwise hands_off can cause irq storms.
*/
@@ -3279,7 +3283,7 @@ static int natsemi_suspend (struct pci_dev *pdev, pm_message_t state)
spin_unlock_irq(&np->lock);
enable_irq(dev->irq);
- netif_poll_disable(dev);
+ napi_disable(&np->napi);
/* Update the error counts. */
__get_stats(dev);
@@ -3311,15 +3315,23 @@ static int natsemi_resume (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata (pdev);
struct netdev_private *np = netdev_priv(dev);
+ int ret = 0;
rtnl_lock();
if (netif_device_present(dev))
goto out;
if (netif_running(dev)) {
BUG_ON(!np->hands_off);
- pci_enable_device(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "pci_enable_device() failed: %d\n", ret);
+ goto out;
+ }
/* pci_power_on(pdev); */
+ napi_enable(&np->napi);
+
natsemi_reset(dev);
init_ring(dev);
disable_irq(dev->irq);
@@ -3330,13 +3342,12 @@ static int natsemi_resume (struct pci_dev *pdev)
spin_unlock_irq(&np->lock);
enable_irq(dev->irq);
- mod_timer(&np->timer, jiffies + 1*HZ);
+ mod_timer(&np->timer, round_jiffies(jiffies + 1*HZ));
}
netif_device_attach(dev);
- netif_poll_enable(dev);
out:
rtnl_unlock();
- return 0;
+ return ret;
}
#endif /* CONFIG_PM */
diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c
index 38fd525f0f1..fbc7531d3c7 100644
--- a/drivers/net/ne-h8300.c
+++ b/drivers/net/ne-h8300.c
@@ -93,7 +93,7 @@ static int __init init_reg_offset(struct net_device *dev,unsigned long base_addr
bus_width = *(volatile unsigned char *)ABWCR;
bus_width &= 1 << ((base_addr >> 21) & 7);
- for (i = 0; i < sizeof(reg_offset) / sizeof(u32); i++)
+ for (i = 0; i < ARRAY_SIZE(reg_offset); i++)
if (bus_width == 0)
reg_offset[i] = i * 2 + 1;
else
@@ -115,7 +115,7 @@ static int h8300_ne_irq[] = {EXT_IRQ5};
static inline int init_dev(struct net_device *dev)
{
- if (h8300_ne_count < (sizeof(h8300_ne_base) / sizeof(unsigned long))) {
+ if (h8300_ne_count < ARRAY_SIZE(h8300_ne_base)) {
dev->base_addr = h8300_ne_base[h8300_ne_count];
dev->irq = h8300_ne_irq[h8300_ne_count];
h8300_ne_count++;
@@ -149,8 +149,6 @@ static int __init do_ne_probe(struct net_device *dev)
{
unsigned int base_addr = dev->base_addr;
- SET_MODULE_OWNER(dev);
-
/* First check any supplied i/o locations. User knows best. <cough> */
if (base_addr > 0x1ff) /* Check a single specified location. */
return ne_probe1(dev, base_addr);
@@ -206,6 +204,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
static unsigned version_printed;
struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
unsigned char bus_width;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -259,7 +258,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
{E8390_RREAD+E8390_START, E8390_CMD},
};
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
}
@@ -298,12 +297,11 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
dev->base_addr = ioaddr;
- for(i = 0; i < ETHER_ADDR_LEN; i++) {
- printk(" %2.2x", SA_prom[i]);
+ for(i = 0; i < ETHER_ADDR_LEN; i++)
dev->dev_addr[i] = SA_prom[i];
- }
+ printk(" %s\n", print_mac(mac, dev->dev_addr));
- printk("\n%s: %s found at %#x, using IRQ %d.\n",
+ printk("%s: %s found at %#x, using IRQ %d.\n",
dev->name, name, ioaddr, dev->irq);
ei_status.name = name;
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index c9f74bf5f49..874d291cbae 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -191,8 +191,6 @@ static int __init do_ne_probe(struct net_device *dev)
int orig_irq = dev->irq;
#endif
- SET_MODULE_OWNER(dev);
-
/* First check any supplied i/o locations. User knows best. <cough> */
if (base_addr > 0x1ff) /* Check a single specified location. */
return ne_probe1(dev, base_addr);
@@ -293,6 +291,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
int neX000, ctron, copam, bad_card;
int reg0, ret;
static unsigned version_printed;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -377,7 +376,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
{E8390_RREAD+E8390_START, E8390_CMD},
};
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
}
@@ -505,16 +504,14 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
for (i = 0 ; i < ETHER_ADDR_LEN ; i++) {
dev->dev_addr[i] = SA_prom[i]
= inb_p(ioaddr + EN1_PHYS_SHIFT(i));
- printk(" %2.2x", SA_prom[i]);
}
#else
for(i = 0; i < ETHER_ADDR_LEN; i++) {
- printk(" %2.2x", SA_prom[i]);
dev->dev_addr[i] = SA_prom[i];
}
#endif
- printk("\n");
+ printk("%s\n", print_mac(mac, dev->dev_addr));
ei_status.name = name;
ei_status.tx_start_page = start_page;
diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c
index 089b5bb702f..f4cd8c7e81b 100644
--- a/drivers/net/ne2.c
+++ b/drivers/net/ne2.c
@@ -251,8 +251,6 @@ static int __init do_ne2_probe(struct net_device *dev)
int i;
int adapter_found = 0;
- SET_MODULE_OWNER(dev);
-
/* Do not check any supplied i/o locations.
POS registers usually don't fail :) */
@@ -304,6 +302,7 @@ out:
static int ne2_procinfo(char *buf, int slot, struct net_device *dev)
{
int len=0;
+ DECLARE_MAC_BUF(mac);
len += sprintf(buf+len, "The NE/2 Ethernet Adapter\n" );
len += sprintf(buf+len, "Driver written by Wim Dumon ");
@@ -314,12 +313,7 @@ static int ne2_procinfo(char *buf, int slot, struct net_device *dev)
len += sprintf(buf+len, "Based on the original NE2000 drivers\n" );
len += sprintf(buf+len, "Base IO: %#x\n", (unsigned int)dev->base_addr);
len += sprintf(buf+len, "IRQ : %d\n", dev->irq);
-
-#define HW_ADDR(i) dev->dev_addr[i]
- len += sprintf(buf+len, "HW addr : %x:%x:%x:%x:%x:%x\n",
- HW_ADDR(0), HW_ADDR(1), HW_ADDR(2),
- HW_ADDR(3), HW_ADDR(4), HW_ADDR(5) );
-#undef HW_ADDR
+ len += sprintf(buf+len, "HW addr : %s\n", print_mac(mac, dev->dev_addr));
return len;
}
@@ -332,6 +326,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
const char *name = "NE/2";
int start_page, stop_page;
static unsigned version_printed;
+ DECLARE_MAC_BUF(mac);
if (ei_debug && version_printed++ == 0)
printk(version);
@@ -432,7 +427,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
{E8390_RREAD+E8390_START, E8390_CMD},
};
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
outb_p(program_seq[i].value, base_addr +
program_seq[i].offset);
@@ -471,12 +466,12 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
dev->base_addr = base_addr;
- for(i = 0; i < ETHER_ADDR_LEN; i++) {
- printk(" %2.2x", SA_prom[i]);
+ for(i = 0; i < ETHER_ADDR_LEN; i++)
dev->dev_addr[i] = SA_prom[i];
- }
- printk("\n%s: %s found at %#x, using IRQ %d.\n",
+ printk(" %s\n", print_mac(mac, dev->dev_addr));
+
+ printk("%s: %s found at %#x, using IRQ %d.\n",
dev->name, name, base_addr, dev->irq);
mca_set_adapter_procfn(slot, (MCA_ProcFn) ne2_procinfo, dev);
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index f81d9398d60..b569c90da4b 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -212,6 +212,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
static unsigned int fnd_cnt;
long ioaddr;
int flags = pci_clone_list[chip_idx].flags;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -265,7 +266,6 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
dev_err(&pdev->dev, "cannot allocate ethernet device\n");
goto err_out_free_res;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/* Reset card. Who knows what dain-bramaged state it was left in. */
@@ -308,7 +308,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
{0x00, EN0_RSARHI},
{E8390_RREAD+E8390_START, E8390_CMD},
};
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
outb(program_seq[i].value, ioaddr + program_seq[i].offset);
}
@@ -366,12 +366,12 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
if (i)
goto err_out_free_netdev;
- printk("%s: %s found at %#lx, IRQ %d, ",
- dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq);
- for(i = 0; i < 6; i++) {
- printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":");
+ for(i = 0; i < 6; i++)
dev->dev_addr[i] = SA_prom[i];
- }
+ printk("%s: %s found at %#lx, IRQ %d, %s.\n",
+ dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq,
+ print_mac(mac, dev->dev_addr));
+
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
return 0;
@@ -636,8 +636,6 @@ static void ne2k_pci_get_drvinfo(struct net_device *dev,
static const struct ethtool_ops ne2k_pci_ethtool_ops = {
.get_drvinfo = ne2k_pci_get_drvinfo,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
};
static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev)
diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c
index 1a6fed76d4c..425043a88db 100644
--- a/drivers/net/ne3210.c
+++ b/drivers/net/ne3210.c
@@ -99,6 +99,7 @@ static int __init ne3210_eisa_probe (struct device *device)
int i, retval, port_index;
struct eisa_device *edev = to_eisa_device (device);
struct net_device *dev;
+ DECLARE_MAC_BUF(mac);
/* Allocate dev->priv and fill in 8390 specific dev fields. */
if (!(dev = alloc_ei_netdev ())) {
@@ -106,7 +107,6 @@ static int __init ne3210_eisa_probe (struct device *device)
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, device);
device->driver_data = dev;
ioaddr = edev->base_addr;
@@ -128,17 +128,15 @@ static int __init ne3210_eisa_probe (struct device *device)
inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2));
#endif
-
port_index = inb(ioaddr + NE3210_CFG2) >> 6;
- printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr:",
- edev->slot, ifmap[port_index]);
for(i = 0; i < ETHER_ADDR_LEN; i++)
- printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i)));
-
+ dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i);
+ printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %s.\n",
+ edev->slot, ifmap[port_index], print_mac(mac, dev->dev_addr));
/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
- printk(".\nne3210.c: using IRQ %d, ", dev->irq);
+ printk("ne3210.c: using IRQ %d, ", dev->irq);
retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
if (retval) {
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 69233f6aa05..5ffbb889164 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -35,95 +35,780 @@
****************************************************************/
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/console.h>
-#include <linux/tty_driver.h>
#include <linux/moduleparam.h>
#include <linux/string.h>
-#include <linux/sysrq.h>
-#include <linux/smp.h>
#include <linux/netpoll.h>
+#include <linux/inet.h>
+#include <linux/configfs.h>
MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>");
MODULE_DESCRIPTION("Console driver for network interfaces");
MODULE_LICENSE("GPL");
-static char config[256];
-module_param_string(netconsole, config, 256, 0);
+#define MAX_PARAM_LENGTH 256
+#define MAX_PRINT_CHUNK 1000
+
+static char config[MAX_PARAM_LENGTH];
+module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);
MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]\n");
-static struct netpoll np = {
- .name = "netconsole",
- .dev_name = "eth0",
- .local_port = 6665,
- .remote_port = 6666,
- .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+#ifndef MODULE
+static int __init option_setup(char *opt)
+{
+ strlcpy(config, opt, MAX_PARAM_LENGTH);
+ return 1;
+}
+__setup("netconsole=", option_setup);
+#endif /* MODULE */
+
+/* Linked list of all configured targets */
+static LIST_HEAD(target_list);
+
+/* This needs to be a spinlock because write_msg() cannot sleep */
+static DEFINE_SPINLOCK(target_list_lock);
+
+/**
+ * struct netconsole_target - Represents a configured netconsole target.
+ * @list: Links this target into the target_list.
+ * @item: Links us into the configfs subsystem hierarchy.
+ * @enabled: On / off knob to enable / disable target.
+ * Visible from userspace (read-write).
+ * We maintain a strict 1:1 correspondence between this and
+ * whether the corresponding netpoll is active or inactive.
+ * Also, other parameters of a target may be modified at
+ * runtime only when it is disabled (enabled == 0).
+ * @np: The netpoll structure for this target.
+ * Contains the other userspace visible parameters:
+ * dev_name (read-write)
+ * local_port (read-write)
+ * remote_port (read-write)
+ * local_ip (read-write)
+ * remote_ip (read-write)
+ * local_mac (read-only)
+ * remote_mac (read-write)
+ */
+struct netconsole_target {
+ struct list_head list;
+#ifdef CONFIG_NETCONSOLE_DYNAMIC
+ struct config_item item;
+#endif
+ int enabled;
+ struct netpoll np;
};
-static int configured = 0;
-#define MAX_PRINT_CHUNK 1000
+#ifdef CONFIG_NETCONSOLE_DYNAMIC
-static void write_msg(struct console *con, const char *msg, unsigned int len)
+static struct configfs_subsystem netconsole_subsys;
+
+static int __init dynamic_netconsole_init(void)
{
- int frag, left;
- unsigned long flags;
+ config_group_init(&netconsole_subsys.su_group);
+ mutex_init(&netconsole_subsys.su_mutex);
+ return configfs_register_subsystem(&netconsole_subsys);
+}
- if (!np.dev)
- return;
+static void __exit dynamic_netconsole_exit(void)
+{
+ configfs_unregister_subsystem(&netconsole_subsys);
+}
+
+/*
+ * Targets that were created by parsing the boot/module option string
+ * do not exist in the configfs hierarchy (and have NULL names) and will
+ * never go away, so make these a no-op for them.
+ */
+static void netconsole_target_get(struct netconsole_target *nt)
+{
+ if (config_item_name(&nt->item))
+ config_item_get(&nt->item);
+}
+
+static void netconsole_target_put(struct netconsole_target *nt)
+{
+ if (config_item_name(&nt->item))
+ config_item_put(&nt->item);
+}
+
+#else /* !CONFIG_NETCONSOLE_DYNAMIC */
+
+static int __init dynamic_netconsole_init(void)
+{
+ return 0;
+}
- local_irq_save(flags);
+static void __exit dynamic_netconsole_exit(void)
+{
+}
- for(left = len; left; ) {
- frag = min(left, MAX_PRINT_CHUNK);
- netpoll_send_udp(&np, msg, frag);
- msg += frag;
- left -= frag;
+/*
+ * No danger of targets going away from under us when dynamic
+ * reconfigurability is off.
+ */
+static void netconsole_target_get(struct netconsole_target *nt)
+{
+}
+
+static void netconsole_target_put(struct netconsole_target *nt)
+{
+}
+
+#endif /* CONFIG_NETCONSOLE_DYNAMIC */
+
+/* Allocate new target (from boot/module param) and setup netpoll for it */
+static struct netconsole_target *alloc_param_target(char *target_config)
+{
+ int err = -ENOMEM;
+ struct netconsole_target *nt;
+
+ /*
+ * Allocate and initialize with defaults.
+ * Note that these targets get their config_item fields zeroed-out.
+ */
+ nt = kzalloc(sizeof(*nt), GFP_KERNEL);
+ if (!nt) {
+ printk(KERN_ERR "netconsole: failed to allocate memory\n");
+ goto fail;
}
- local_irq_restore(flags);
+ nt->np.name = "netconsole";
+ strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
+ nt->np.local_port = 6665;
+ nt->np.remote_port = 6666;
+ memset(nt->np.remote_mac, 0xff, ETH_ALEN);
+
+ /* Parse parameters and setup netpoll */
+ err = netpoll_parse_options(&nt->np, target_config);
+ if (err)
+ goto fail;
+
+ err = netpoll_setup(&nt->np);
+ if (err)
+ goto fail;
+
+ nt->enabled = 1;
+
+ return nt;
+
+fail:
+ kfree(nt);
+ return ERR_PTR(err);
}
-static struct console netconsole = {
- .name = "netcon",
- .flags = CON_ENABLED | CON_PRINTBUFFER,
- .write = write_msg
+/* Cleanup netpoll for given target (from boot/module param) and free it */
+static void free_param_target(struct netconsole_target *nt)
+{
+ netpoll_cleanup(&nt->np);
+ kfree(nt);
+}
+
+#ifdef CONFIG_NETCONSOLE_DYNAMIC
+
+/*
+ * Our subsystem hierarchy is:
+ *
+ * /sys/kernel/config/netconsole/
+ * |
+ * <target>/
+ * | enabled
+ * | dev_name
+ * | local_port
+ * | remote_port
+ * | local_ip
+ * | remote_ip
+ * | local_mac
+ * | remote_mac
+ * |
+ * <target>/...
+ */
+
+struct netconsole_target_attr {
+ struct configfs_attribute attr;
+ ssize_t (*show)(struct netconsole_target *nt,
+ char *buf);
+ ssize_t (*store)(struct netconsole_target *nt,
+ const char *buf,
+ size_t count);
};
-static int option_setup(char *opt)
+static struct netconsole_target *to_target(struct config_item *item)
{
- configured = !netpoll_parse_options(&np, opt);
- return 1;
+ return item ?
+ container_of(item, struct netconsole_target, item) :
+ NULL;
}
-__setup("netconsole=", option_setup);
+/*
+ * Wrapper over simple_strtol (base 10) with sanity and range checking.
+ * We return (signed) long only because we may want to return errors.
+ * Do not use this to convert numbers that are allowed to be negative.
+ */
+static long strtol10_check_range(const char *cp, long min, long max)
+{
+ long ret;
+ char *p = (char *) cp;
+
+ WARN_ON(min < 0);
+ WARN_ON(max < min);
+
+ ret = simple_strtol(p, &p, 10);
+
+ if (*p && (*p != '\n')) {
+ printk(KERN_ERR "netconsole: invalid input\n");
+ return -EINVAL;
+ }
+ if ((ret < min) || (ret > max)) {
+ printk(KERN_ERR "netconsole: input %ld must be between "
+ "%ld and %ld\n", ret, min, max);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+/*
+ * Attribute operations for netconsole_target.
+ */
+
+static ssize_t show_enabled(struct netconsole_target *nt, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled);
+}
+
+static ssize_t show_dev_name(struct netconsole_target *nt, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", nt->np.dev_name);
+}
+
+static ssize_t show_local_port(struct netconsole_target *nt, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.local_port);
+}
+
+static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.remote_port);
+}
+
+static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
+ HIPQUAD(nt->np.local_ip));
+}
+
+static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
+ HIPQUAD(nt->np.remote_ip));
+}
+
+static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
+{
+ DECLARE_MAC_BUF(mac);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ print_mac(mac, nt->np.local_mac));
+}
+
+static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf)
+{
+ DECLARE_MAC_BUF(mac);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ print_mac(mac, nt->np.remote_mac));
+}
-static int init_netconsole(void)
+/*
+ * This one is special -- targets created through the configfs interface
+ * are not enabled (and the corresponding netpoll activated) by default.
+ * The user is expected to set the desired parameters first (which
+ * would enable him to dynamically add new netpoll targets for new
+ * network interfaces as and when they come up).
+ */
+static ssize_t store_enabled(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
{
int err;
+ long enabled;
+
+ enabled = strtol10_check_range(buf, 0, 1);
+ if (enabled < 0)
+ return enabled;
+
+ if (enabled) { /* 1 */
+
+ /*
+ * Skip netpoll_parse_options() -- all the attributes are
+ * already configured via configfs. Just print them out.
+ */
+ netpoll_print_options(&nt->np);
+
+ err = netpoll_setup(&nt->np);
+ if (err)
+ return err;
+
+ printk(KERN_INFO "netconsole: network logging started\n");
+
+ } else { /* 0 */
+ netpoll_cleanup(&nt->np);
+ }
+
+ nt->enabled = enabled;
+
+ return strnlen(buf, count);
+}
+
+static ssize_t store_dev_name(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
+{
+ size_t len;
+
+ if (nt->enabled) {
+ printk(KERN_ERR "netconsole: target (%s) is enabled, "
+ "disable to update parameters\n",
+ config_item_name(&nt->item));
+ return -EINVAL;
+ }
+
+ strlcpy(nt->np.dev_name, buf, IFNAMSIZ);
+
+ /* Get rid of possible trailing newline from echo(1) */
+ len = strnlen(nt->np.dev_name, IFNAMSIZ);
+ if (nt->np.dev_name[len - 1] == '\n')
+ nt->np.dev_name[len - 1] = '\0';
+
+ return strnlen(buf, count);
+}
+
+static ssize_t store_local_port(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
+{
+ long local_port;
+#define __U16_MAX ((__u16) ~0U)
+
+ if (nt->enabled) {
+ printk(KERN_ERR "netconsole: target (%s) is enabled, "
+ "disable to update parameters\n",
+ config_item_name(&nt->item));
+ return -EINVAL;
+ }
+
+ local_port = strtol10_check_range(buf, 0, __U16_MAX);
+ if (local_port < 0)
+ return local_port;
+
+ nt->np.local_port = local_port;
+
+ return strnlen(buf, count);
+}
+
+static ssize_t store_remote_port(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
+{
+ long remote_port;
+#define __U16_MAX ((__u16) ~0U)
+
+ if (nt->enabled) {
+ printk(KERN_ERR "netconsole: target (%s) is enabled, "
+ "disable to update parameters\n",
+ config_item_name(&nt->item));
+ return -EINVAL;
+ }
+
+ remote_port = strtol10_check_range(buf, 0, __U16_MAX);
+ if (remote_port < 0)
+ return remote_port;
+
+ nt->np.remote_port = remote_port;
+
+ return strnlen(buf, count);
+}
+
+static ssize_t store_local_ip(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
+{
+ if (nt->enabled) {
+ printk(KERN_ERR "netconsole: target (%s) is enabled, "
+ "disable to update parameters\n",
+ config_item_name(&nt->item));
+ return -EINVAL;
+ }
+
+ nt->np.local_ip = ntohl(in_aton(buf));
+
+ return strnlen(buf, count);
+}
+
+static ssize_t store_remote_ip(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
+{
+ if (nt->enabled) {
+ printk(KERN_ERR "netconsole: target (%s) is enabled, "
+ "disable to update parameters\n",
+ config_item_name(&nt->item));
+ return -EINVAL;
+ }
+
+ nt->np.remote_ip = ntohl(in_aton(buf));
+
+ return strnlen(buf, count);
+}
+
+static ssize_t store_remote_mac(struct netconsole_target *nt,
+ const char *buf,
+ size_t count)
+{
+ u8 remote_mac[ETH_ALEN];
+ char *p = (char *) buf;
+ int i;
- if(strlen(config))
- option_setup(config);
+ if (nt->enabled) {
+ printk(KERN_ERR "netconsole: target (%s) is enabled, "
+ "disable to update parameters\n",
+ config_item_name(&nt->item));
+ return -EINVAL;
+ }
- if(!configured) {
- printk("netconsole: not configured, aborting\n");
- return 0;
+ for (i = 0; i < ETH_ALEN - 1; i++) {
+ remote_mac[i] = simple_strtoul(p, &p, 16);
+ if (*p != ':')
+ goto invalid;
+ p++;
}
+ remote_mac[ETH_ALEN - 1] = simple_strtoul(p, &p, 16);
+ if (*p && (*p != '\n'))
+ goto invalid;
+
+ memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
+
+ return strnlen(buf, count);
+
+invalid:
+ printk(KERN_ERR "netconsole: invalid input\n");
+ return -EINVAL;
+}
+
+/*
+ * Attribute definitions for netconsole_target.
+ */
+
+#define NETCONSOLE_TARGET_ATTR_RO(_name) \
+static struct netconsole_target_attr netconsole_target_##_name = \
+ __CONFIGFS_ATTR(_name, S_IRUGO, show_##_name, NULL)
- err = netpoll_setup(&np);
+#define NETCONSOLE_TARGET_ATTR_RW(_name) \
+static struct netconsole_target_attr netconsole_target_##_name = \
+ __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name)
+
+NETCONSOLE_TARGET_ATTR_RW(enabled);
+NETCONSOLE_TARGET_ATTR_RW(dev_name);
+NETCONSOLE_TARGET_ATTR_RW(local_port);
+NETCONSOLE_TARGET_ATTR_RW(remote_port);
+NETCONSOLE_TARGET_ATTR_RW(local_ip);
+NETCONSOLE_TARGET_ATTR_RW(remote_ip);
+NETCONSOLE_TARGET_ATTR_RO(local_mac);
+NETCONSOLE_TARGET_ATTR_RW(remote_mac);
+
+static struct configfs_attribute *netconsole_target_attrs[] = {
+ &netconsole_target_enabled.attr,
+ &netconsole_target_dev_name.attr,
+ &netconsole_target_local_port.attr,
+ &netconsole_target_remote_port.attr,
+ &netconsole_target_local_ip.attr,
+ &netconsole_target_remote_ip.attr,
+ &netconsole_target_local_mac.attr,
+ &netconsole_target_remote_mac.attr,
+ NULL,
+};
+
+/*
+ * Item operations and type for netconsole_target.
+ */
+
+static void netconsole_target_release(struct config_item *item)
+{
+ kfree(to_target(item));
+}
+
+static ssize_t netconsole_target_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *buf)
+{
+ ssize_t ret = -EINVAL;
+ struct netconsole_target *nt = to_target(item);
+ struct netconsole_target_attr *na =
+ container_of(attr, struct netconsole_target_attr, attr);
+
+ if (na->show)
+ ret = na->show(nt, buf);
+
+ return ret;
+}
+
+static ssize_t netconsole_target_attr_store(struct config_item *item,
+ struct configfs_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ ssize_t ret = -EINVAL;
+ struct netconsole_target *nt = to_target(item);
+ struct netconsole_target_attr *na =
+ container_of(attr, struct netconsole_target_attr, attr);
+
+ if (na->store)
+ ret = na->store(nt, buf, count);
+
+ return ret;
+}
+
+static struct configfs_item_operations netconsole_target_item_ops = {
+ .release = netconsole_target_release,
+ .show_attribute = netconsole_target_attr_show,
+ .store_attribute = netconsole_target_attr_store,
+};
+
+static struct config_item_type netconsole_target_type = {
+ .ct_attrs = netconsole_target_attrs,
+ .ct_item_ops = &netconsole_target_item_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+/*
+ * Group operations and type for netconsole_subsys.
+ */
+
+static struct config_item *make_netconsole_target(struct config_group *group,
+ const char *name)
+{
+ unsigned long flags;
+ struct netconsole_target *nt;
+
+ /*
+ * Allocate and initialize with defaults.
+ * Target is disabled at creation (enabled == 0).
+ */
+ nt = kzalloc(sizeof(*nt), GFP_KERNEL);
+ if (!nt) {
+ printk(KERN_ERR "netconsole: failed to allocate memory\n");
+ return NULL;
+ }
+
+ nt->np.name = "netconsole";
+ strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
+ nt->np.local_port = 6665;
+ nt->np.remote_port = 6666;
+ memset(nt->np.remote_mac, 0xff, ETH_ALEN);
+
+ /* Initialize the config_item member */
+ config_item_init_type_name(&nt->item, name, &netconsole_target_type);
+
+ /* Adding, but it is disabled */
+ spin_lock_irqsave(&target_list_lock, flags);
+ list_add(&nt->list, &target_list);
+ spin_unlock_irqrestore(&target_list_lock, flags);
+
+ return &nt->item;
+}
+
+static void drop_netconsole_target(struct config_group *group,
+ struct config_item *item)
+{
+ unsigned long flags;
+ struct netconsole_target *nt = to_target(item);
+
+ spin_lock_irqsave(&target_list_lock, flags);
+ list_del(&nt->list);
+ spin_unlock_irqrestore(&target_list_lock, flags);
+
+ /*
+ * The target may have never been enabled, or was manually disabled
+ * before being removed so netpoll may have already been cleaned up.
+ */
+ if (nt->enabled)
+ netpoll_cleanup(&nt->np);
+
+ config_item_put(&nt->item);
+}
+
+static struct configfs_group_operations netconsole_subsys_group_ops = {
+ .make_item = make_netconsole_target,
+ .drop_item = drop_netconsole_target,
+};
+
+static struct config_item_type netconsole_subsys_type = {
+ .ct_group_ops = &netconsole_subsys_group_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+/* The netconsole configfs subsystem */
+static struct configfs_subsystem netconsole_subsys = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = "netconsole",
+ .ci_type = &netconsole_subsys_type,
+ },
+ },
+};
+
+#endif /* CONFIG_NETCONSOLE_DYNAMIC */
+
+/* Handle network interface device notifications */
+static int netconsole_netdev_event(struct notifier_block *this,
+ unsigned long event,
+ void *ptr)
+{
+ unsigned long flags;
+ struct netconsole_target *nt;
+ struct net_device *dev = ptr;
+
+ if (!(event == NETDEV_CHANGEADDR || event == NETDEV_CHANGENAME))
+ goto done;
+
+ spin_lock_irqsave(&target_list_lock, flags);
+ list_for_each_entry(nt, &target_list, list) {
+ netconsole_target_get(nt);
+ if (nt->np.dev == dev) {
+ switch (event) {
+ case NETDEV_CHANGEADDR:
+ memcpy(nt->np.local_mac, dev->dev_addr, ETH_ALEN);
+ break;
+
+ case NETDEV_CHANGENAME:
+ strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
+ break;
+ }
+ }
+ netconsole_target_put(nt);
+ }
+ spin_unlock_irqrestore(&target_list_lock, flags);
+
+done:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block netconsole_netdev_notifier = {
+ .notifier_call = netconsole_netdev_event,
+};
+
+static void write_msg(struct console *con, const char *msg, unsigned int len)
+{
+ int frag, left;
+ unsigned long flags;
+ struct netconsole_target *nt;
+ const char *tmp;
+
+ /* Avoid taking lock and disabling interrupts unnecessarily */
+ if (list_empty(&target_list))
+ return;
+
+ spin_lock_irqsave(&target_list_lock, flags);
+ list_for_each_entry(nt, &target_list, list) {
+ netconsole_target_get(nt);
+ if (nt->enabled && netif_running(nt->np.dev)) {
+ /*
+ * We nest this inside the for-each-target loop above
+ * so that we're able to get as much logging out to
+ * at least one target if we die inside here, instead
+ * of unnecessarily keeping all targets in lock-step.
+ */
+ tmp = msg;
+ for (left = len; left;) {
+ frag = min(left, MAX_PRINT_CHUNK);
+ netpoll_send_udp(&nt->np, tmp, frag);
+ tmp += frag;
+ left -= frag;
+ }
+ }
+ netconsole_target_put(nt);
+ }
+ spin_unlock_irqrestore(&target_list_lock, flags);
+}
+
+static struct console netconsole = {
+ .name = "netcon",
+ .flags = CON_ENABLED | CON_PRINTBUFFER,
+ .write = write_msg,
+};
+
+static int __init init_netconsole(void)
+{
+ int err;
+ struct netconsole_target *nt, *tmp;
+ unsigned long flags;
+ char *target_config;
+ char *input = config;
+
+ if (strnlen(input, MAX_PARAM_LENGTH)) {
+ while ((target_config = strsep(&input, ";"))) {
+ nt = alloc_param_target(target_config);
+ if (IS_ERR(nt)) {
+ err = PTR_ERR(nt);
+ goto fail;
+ }
+ spin_lock_irqsave(&target_list_lock, flags);
+ list_add(&nt->list, &target_list);
+ spin_unlock_irqrestore(&target_list_lock, flags);
+ }
+ }
+
+ err = register_netdevice_notifier(&netconsole_netdev_notifier);
+ if (err)
+ goto fail;
+
+ err = dynamic_netconsole_init();
if (err)
- return err;
+ goto undonotifier;
register_console(&netconsole);
printk(KERN_INFO "netconsole: network logging started\n");
- return 0;
+
+ return err;
+
+undonotifier:
+ unregister_netdevice_notifier(&netconsole_netdev_notifier);
+
+fail:
+ printk(KERN_ERR "netconsole: cleaning up\n");
+
+ /*
+ * Remove all targets and destroy them (only targets created
+ * from the boot/module option exist here). Skipping the list
+ * lock is safe here, and netpoll_cleanup() will sleep.
+ */
+ list_for_each_entry_safe(nt, tmp, &target_list, list) {
+ list_del(&nt->list);
+ free_param_target(nt);
+ }
+
+ return err;
}
-static void cleanup_netconsole(void)
+static void __exit cleanup_netconsole(void)
{
+ struct netconsole_target *nt, *tmp;
+
unregister_console(&netconsole);
- netpoll_cleanup(&np);
+ dynamic_netconsole_exit();
+ unregister_netdevice_notifier(&netconsole_netdev_notifier);
+
+ /*
+ * Targets created via configfs pin references on our module
+ * and would first be rmdir(2)'ed from userspace. We reach
+ * here only when they are already destroyed, and only those
+ * created from the boot/module option are left, so remove and
+ * destroy them. Skipping the list lock is safe here, and
+ * netpoll_cleanup() will sleep.
+ */
+ list_for_each_entry_safe(nt, tmp, &target_list, list) {
+ list_del(&nt->list);
+ free_param_target(nt);
+ }
}
module_init(init_netconsole);
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index 2b8da0a5499..5267e031daa 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -97,7 +97,6 @@
struct netx_eth_priv {
void __iomem *sram_base, *xpec_base, *xmac_base;
int id;
- struct net_device_stats stats;
struct mii_if_info mii;
u32 msg_enable;
struct xc *xc;
@@ -129,8 +128,8 @@ netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
FIFO_PTR_FRAMELEN(len));
ndev->trans_start = jiffies;
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += skb->len;
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
netif_stop_queue(ndev);
spin_unlock_irq(&priv->lock);
@@ -156,7 +155,7 @@ static void netx_eth_receive(struct net_device *ndev)
if (unlikely(skb == NULL)) {
printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
ndev->name);
- priv->stats.rx_dropped++;
+ ndev->stats.rx_dropped++;
return;
}
@@ -170,8 +169,8 @@ static void netx_eth_receive(struct net_device *ndev)
ndev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, ndev);
netif_rx(skb);
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
}
static irqreturn_t
@@ -210,12 +209,6 @@ netx_eth_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static struct net_device_stats *netx_eth_query_statistics(struct net_device *ndev)
-{
- struct netx_eth_priv *priv = netdev_priv(ndev);
- return &priv->stats;
-}
-
static int netx_eth_open(struct net_device *ndev)
{
struct netx_eth_priv *priv = netdev_priv(ndev);
@@ -323,7 +316,6 @@ static int netx_eth_enable(struct net_device *ndev)
ndev->hard_start_xmit = netx_eth_hard_start_xmit;
ndev->tx_timeout = netx_eth_timeout;
ndev->watchdog_timeo = msecs_to_jiffies(5000);
- ndev->get_stats = netx_eth_query_statistics;
ndev->set_multicast_list = netx_eth_set_multicast_list;
priv->msg_enable = NETIF_MSG_LINK;
@@ -390,7 +382,6 @@ static int netx_eth_drv_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto exit;
}
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
platform_set_drvdata(pdev, ndev);
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index d4c92cc879d..fbc2553275d 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -880,6 +880,7 @@ struct netxen_adapter {
struct netxen_adapter *master;
struct net_device *netdev;
struct pci_dev *pdev;
+ struct napi_struct napi;
struct net_device_stats net_stats;
unsigned char mac_addr[ETH_ALEN];
int mtu;
@@ -918,7 +919,7 @@ struct netxen_adapter {
u16 link_duplex;
u16 state;
u16 link_autoneg;
- int rcsum;
+ int rx_csum;
int status;
spinlock_t stats_lock;
@@ -1118,7 +1119,7 @@ static const struct netxen_brdinfo netxen_boards[] = {
{NETXEN_BRDTYPE_P2_SB31_2G, 2, "Dual Gb"},
};
-#define NUM_SUPPORTED_BOARDS (sizeof(netxen_boards)/sizeof(struct netxen_brdinfo))
+#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(netxen_boards)
static inline void get_brd_port_by_type(u32 type, int *ports)
{
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index a6138b474b4..cfb847b0cae 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -115,8 +115,6 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
- drvinfo->n_stats = NETXEN_NIC_STATS_LEN;
- drvinfo->testinfo_len = NETXEN_NIC_TEST_LEN;
drvinfo->regdump_len = NETXEN_NIC_REGS_LEN;
drvinfo->eedump_len = netxen_nic_get_eeprom_len(dev);
}
@@ -518,17 +516,17 @@ netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
ring->rx_jumbo_pending = 0;
for (i = 0; i < MAX_RCV_CTX; ++i) {
ring->rx_pending += adapter->recv_ctx[i].
- rcv_desc[RCV_DESC_NORMAL_CTXID].rcv_pending;
+ rcv_desc[RCV_DESC_NORMAL_CTXID].max_rx_desc_count;
ring->rx_jumbo_pending += adapter->recv_ctx[i].
- rcv_desc[RCV_DESC_JUMBO_CTXID].rcv_pending;
+ rcv_desc[RCV_DESC_JUMBO_CTXID].max_rx_desc_count;
}
+ ring->tx_pending = adapter->max_tx_desc_count;
- ring->rx_max_pending = adapter->max_rx_desc_count;
- ring->tx_max_pending = adapter->max_tx_desc_count;
- ring->rx_jumbo_max_pending = adapter->max_jumbo_rx_desc_count;
+ ring->rx_max_pending = MAX_RCV_DESCRIPTORS;
+ ring->tx_max_pending = MAX_CMD_DESCRIPTORS_HOST;
+ ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS;
ring->rx_mini_max_pending = 0;
ring->rx_mini_pending = 0;
- ring->rx_jumbo_pending = 0;
}
static void
@@ -672,9 +670,16 @@ static int netxen_nic_reg_test(struct net_device *dev)
return 0;
}
-static int netxen_nic_diag_test_count(struct net_device *dev)
+static int netxen_get_sset_count(struct net_device *dev, int sset)
{
- return NETXEN_NIC_TEST_LEN;
+ switch (sset) {
+ case ETH_SS_TEST:
+ return NETXEN_NIC_TEST_LEN;
+ case ETH_SS_STATS:
+ return NETXEN_NIC_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void
@@ -709,11 +714,6 @@ netxen_nic_get_strings(struct net_device *dev, u32 stringset, u8 * data)
}
}
-static int netxen_nic_get_stats_count(struct net_device *dev)
-{
- return NETXEN_NIC_STATS_LEN;
-}
-
static void
netxen_nic_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 * data)
@@ -731,6 +731,19 @@ netxen_nic_get_ethtool_stats(struct net_device *dev,
}
}
+static u32 netxen_nic_get_rx_csum(struct net_device *dev)
+{
+ struct netxen_adapter *adapter = netdev_priv(dev);
+ return adapter->rx_csum;
+}
+
+static int netxen_nic_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct netxen_adapter *adapter = netdev_priv(dev);
+ adapter->rx_csum = !!data;
+ return 0;
+}
+
struct ethtool_ops netxen_nic_ethtool_ops = {
.get_settings = netxen_nic_get_settings,
.set_settings = netxen_nic_set_settings,
@@ -744,15 +757,13 @@ struct ethtool_ops netxen_nic_ethtool_ops = {
.get_ringparam = netxen_nic_get_ringparam,
.get_pauseparam = netxen_nic_get_pauseparam,
.set_pauseparam = netxen_nic_set_pauseparam,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
- .self_test_count = netxen_nic_diag_test_count,
.self_test = netxen_nic_diag_test,
.get_strings = netxen_nic_get_strings,
- .get_stats_count = netxen_nic_get_stats_count,
.get_ethtool_stats = netxen_nic_get_ethtool_stats,
+ .get_sset_count = netxen_get_sset_count,
+ .get_rx_csum = netxen_nic_get_rx_csum,
+ .set_rx_csum = netxen_nic_set_rx_csum,
};
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index a7b8d7f2325..2c19b8df98f 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -569,7 +569,7 @@ int netxen_is_flash_supported(struct netxen_adapter *adapter)
/* if the flash size less than 4Mb, make huge war cry and die */
for (j = 1; j < 4; j++) {
addr = j * NETXEN_NIC_WINDOW_MARGIN;
- for (i = 0; i < (sizeof(locs) / sizeof(locs[0])); i++) {
+ for (i = 0; i < ARRAY_SIZE(locs); i++) {
if (netxen_rom_fast_read(adapter, locs[i], &val01) == 0
&& netxen_rom_fast_read(adapter, (addr + locs[i]),
&val02) == 0) {
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 1811bcb8c38..37589265297 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -1118,10 +1118,13 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
skb = (struct sk_buff *)buffer->skb;
- if (likely(netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) {
+ if (likely(adapter->rx_csum &&
+ netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) {
adapter->stats.csummed++;
skb->ip_summed = CHECKSUM_UNNECESSARY;
- }
+ } else
+ skb->ip_summed = CHECKSUM_NONE;
+
skb->dev = netdev;
if (desc_ctx == RCV_DESC_LRO_CTXID) {
/* True length was only available on the last pkt */
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 3122d010163..a80f0cd6b52 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -39,7 +39,6 @@
#include "netxen_nic_phan_reg.h"
#include <linux/dma-mapping.h>
-#include <linux/vmalloc.h>
#include <net/ip.h>
MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
@@ -54,9 +53,6 @@ static char netxen_nic_driver_string[] = "NetXen Network Driver version "
#define NETXEN_ADAPTER_UP_MAGIC 777
#define NETXEN_NIC_PEG_TUNE 0
-#define DMA_32BIT_MASK 0x00000000ffffffffULL
-#define DMA_35BIT_MASK 0x00000007ffffffffULL
-
/* Local functions to NetXen NIC driver */
static int __devinit netxen_nic_probe(struct pci_dev *pdev,
const struct pci_device_id *ent);
@@ -68,7 +64,7 @@ static void netxen_tx_timeout(struct net_device *netdev);
static void netxen_tx_timeout_task(struct work_struct *work);
static void netxen_watchdog(unsigned long);
static int netxen_handle_int(struct netxen_adapter *, struct net_device *);
-static int netxen_nic_poll(struct net_device *dev, int *budget);
+static int netxen_nic_poll(struct napi_struct *napi, int budget);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void netxen_nic_poll_controller(struct net_device *netdev);
#endif
@@ -286,6 +282,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
int valid_mac = 0;
u32 val;
int pci_func_id = PCI_FUNC(pdev->devfn);
+ DECLARE_MAC_BUF(mac);
printk(KERN_INFO "%s \n", netxen_nic_driver_string);
@@ -326,11 +323,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_free_res;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
adapter = netdev->priv;
- memset(adapter, 0 , sizeof(struct netxen_adapter));
adapter->ahw.pdev = pdev;
adapter->ahw.pci_func = pci_func_id;
@@ -402,12 +397,16 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->netdev = netdev;
adapter->pdev = pdev;
+ netif_napi_add(netdev, &adapter->napi,
+ netxen_nic_poll, NETXEN_NETDEV_WEIGHT);
+
/* this will be read from FW later */
adapter->intr_scheme = -1;
/* This will be reset for mezz cards */
adapter->portnum = pci_func_id;
adapter->status &= ~NETXEN_NETDEV_STATUS;
+ adapter->rx_csum = 1;
netdev->open = netxen_nic_open;
netdev->stop = netxen_nic_close;
@@ -422,8 +421,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netxen_nic_change_mtu(netdev, netdev->mtu);
SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
- netdev->poll = netxen_nic_poll;
- netdev->weight = NETXEN_NETDEV_WEIGHT;
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = netxen_nic_poll_controller;
#endif
@@ -575,15 +572,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
memcpy(netdev->perm_addr, netdev->dev_addr,
netdev->addr_len);
if (!is_valid_ether_addr(netdev->perm_addr)) {
- printk(KERN_ERR "%s: Bad MAC address "
- "%02x:%02x:%02x:%02x:%02x:%02x.\n",
- netxen_nic_driver_name,
- netdev->dev_addr[0],
- netdev->dev_addr[1],
- netdev->dev_addr[2],
- netdev->dev_addr[3],
- netdev->dev_addr[4],
- netdev->dev_addr[5]);
+ printk(KERN_ERR "%s: Bad MAC address %s.\n",
+ netxen_nic_driver_name,
+ print_mac(mac, netdev->dev_addr));
} else {
if (adapter->macaddr_set)
adapter->macaddr_set(adapter,
@@ -885,6 +876,8 @@ static int netxen_nic_open(struct net_device *netdev)
if (!adapter->driver_mismatch)
mod_timer(&adapter->watchdog_timer, jiffies);
+ napi_enable(&adapter->napi);
+
netxen_nic_enable_int(adapter);
/* Done here again so that even if phantom sw overwrote it,
@@ -894,6 +887,7 @@ static int netxen_nic_open(struct net_device *netdev)
del_timer_sync(&adapter->watchdog_timer);
printk(KERN_ERR "%s: Failed to initialize port %d\n",
netxen_nic_driver_name, adapter->portnum);
+ napi_disable(&adapter->napi);
return -EIO;
}
if (adapter->macaddr_set)
@@ -923,6 +917,7 @@ static int netxen_nic_close(struct net_device *netdev)
netif_carrier_off(netdev);
netif_stop_queue(netdev);
+ napi_disable(&adapter->napi);
netxen_nic_disable_int(adapter);
@@ -1243,11 +1238,11 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
netxen_nic_disable_int(adapter);
if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) {
- if (netif_rx_schedule_prep(netdev)) {
+ if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
/*
* Interrupts are already disabled.
*/
- __netif_rx_schedule(netdev);
+ __netif_rx_schedule(netdev, &adapter->napi);
} else {
static unsigned int intcount = 0;
if ((++intcount & 0xfff) == 0xfff)
@@ -1273,17 +1268,10 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
*/
irqreturn_t netxen_intr(int irq, void *data)
{
- struct netxen_adapter *adapter;
- struct net_device *netdev;
+ struct netxen_adapter *adapter = data;
+ struct net_device *netdev = adapter->netdev;
u32 our_int = 0;
- if (unlikely(!irq)) {
- return IRQ_NONE; /* Not our interrupt */
- }
-
- adapter = (struct netxen_adapter *)data;
- netdev = adapter->netdev;
-
if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
/* not our interrupt */
@@ -1305,14 +1293,13 @@ irqreturn_t netxen_intr(int irq, void *data)
return IRQ_HANDLED;
}
-static int netxen_nic_poll(struct net_device *netdev, int *budget)
+static int netxen_nic_poll(struct napi_struct *napi, int budget)
{
- struct netxen_adapter *adapter = netdev_priv(netdev);
- int work_to_do = min(*budget, netdev->quota);
+ struct netxen_adapter *adapter = container_of(napi, struct netxen_adapter, napi);
+ struct net_device *netdev = adapter->netdev;
int done = 1;
int ctx;
- int this_work_done;
- int work_done = 0;
+ int work_done;
DPRINTK(INFO, "polling for %d descriptors\n", *budget);
@@ -1330,16 +1317,11 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget)
* packets are on one context, it gets only half of the quota,
* and ends up not processing it.
*/
- this_work_done = netxen_process_rcv_ring(adapter, ctx,
- work_to_do /
- MAX_RCV_CTX);
- work_done += this_work_done;
+ work_done += netxen_process_rcv_ring(adapter, ctx,
+ budget / MAX_RCV_CTX);
}
- netdev->quota -= work_done;
- *budget -= work_done;
-
- if (work_done >= work_to_do && netxen_nic_rx_has_work(adapter) != 0)
+ if (work_done >= budget && netxen_nic_rx_has_work(adapter) != 0)
done = 0;
if (netxen_process_cmd_ring((unsigned long)adapter) == 0)
@@ -1348,11 +1330,11 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget)
DPRINTK(INFO, "new work_done: %d work_to_do: %d\n",
work_done, work_to_do);
if (done) {
- netif_rx_complete(netdev);
+ netif_rx_complete(netdev, napi);
netxen_nic_enable_int(adapter);
}
- return !done;
+ return work_done;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index 05e0577a0e1..5b9e1b300fa 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -603,6 +603,7 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
int phy = physical_port[adapter->portnum];
unsigned char mac_addr[6];
int i;
+ DECLARE_MAC_BUF(mac);
for (i = 0; i < 10; i++) {
temp[0] = temp[1] = 0;
@@ -627,15 +628,10 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
if (i == 10) {
printk(KERN_ERR "%s: cannot set Mac addr for %s\n",
netxen_nic_driver_name, adapter->netdev->name);
- printk(KERN_ERR "MAC address set: "
- "%02x:%02x:%02x:%02x:%02x:%02x.\n",
- addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
-
- printk(KERN_ERR "MAC address get: "
- "%02x:%02x:%02x:%02x:%02x:%02x.\n",
- mac_addr[0],
- mac_addr[1],
- mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
+ printk(KERN_ERR "MAC address set: %s.\n",
+ print_mac(mac, addr));
+ printk(KERN_ERR "MAC address get: %s.\n",
+ print_mac(mac, mac_addr));
}
return 0;
}
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index 22a3b3dc7d8..a20005c09e0 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -89,7 +89,6 @@ static unsigned int ports[] __initdata =
/* Information that needs to be kept for each board. */
struct ni5010_local {
- struct net_device_stats stats;
int o_pkt_size;
spinlock_t lock;
};
@@ -103,7 +102,6 @@ static irqreturn_t ni5010_interrupt(int irq, void *dev_id);
static void ni5010_rx(struct net_device *dev);
static void ni5010_timeout(struct net_device *dev);
static int ni5010_close(struct net_device *dev);
-static struct net_device_stats *ni5010_get_stats(struct net_device *dev);
static void ni5010_set_multicast_list(struct net_device *dev);
static void reset_receiver(struct net_device *dev);
@@ -135,8 +133,6 @@ struct net_device * __init ni5010_probe(int unit)
PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name));
- SET_MODULE_OWNER(dev);
-
if (io > 0x1ff) { /* Check a single specified location. */
err = ni5010_probe1(dev, io);
} else if (io != 0) { /* Don't probe at all. */
@@ -207,6 +203,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
unsigned int data = 0;
int boguscount = 40;
int err = -ENODEV;
+ DECLARE_MAC_BUF(mac);
dev->base_addr = ioaddr;
dev->irq = irq;
@@ -272,8 +269,9 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
for (i=0; i<6; i++) {
outw(i, IE_GP);
- printk("%2.2x ", dev->dev_addr[i] = inb(IE_SAPROM));
+ dev->dev_addr[i] = inb(IE_SAPROM);
}
+ printk("%s ", print_mac(mac, dev->dev_addr));
PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
@@ -336,7 +334,6 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
dev->open = ni5010_open;
dev->stop = ni5010_close;
dev->hard_start_xmit = ni5010_send_packet;
- dev->get_stats = ni5010_get_stats;
dev->set_multicast_list = ni5010_set_multicast_list;
dev->tx_timeout = ni5010_timeout;
dev->watchdog_timeo = HZ/20;
@@ -521,7 +518,6 @@ static void dump_packet(void *buf, int len)
/* We have a good packet, get it out of the buffer. */
static void ni5010_rx(struct net_device *dev)
{
- struct ni5010_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
unsigned char rcv_stat;
struct sk_buff *skb;
@@ -534,11 +530,11 @@ static void ni5010_rx(struct net_device *dev)
if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) {
PRINTK((KERN_INFO "%s: receive error.\n", dev->name));
- lp->stats.rx_errors++;
- if (rcv_stat & RS_RUNT) lp->stats.rx_length_errors++;
- if (rcv_stat & RS_ALIGN) lp->stats.rx_frame_errors++;
- if (rcv_stat & RS_CRC_ERR) lp->stats.rx_crc_errors++;
- if (rcv_stat & RS_OFLW) lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ if (rcv_stat & RS_RUNT) dev->stats.rx_length_errors++;
+ if (rcv_stat & RS_ALIGN) dev->stats.rx_frame_errors++;
+ if (rcv_stat & RS_CRC_ERR) dev->stats.rx_crc_errors++;
+ if (rcv_stat & RS_OFLW) dev->stats.rx_fifo_errors++;
outb(0xff, EDLC_RCLR); /* Clear the interrupt */
return;
}
@@ -549,8 +545,8 @@ static void ni5010_rx(struct net_device *dev)
if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) {
PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n",
dev->name, i_pkt_size));
- lp->stats.rx_errors++;
- lp->stats.rx_length_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
return;
}
@@ -558,7 +554,7 @@ static void ni5010_rx(struct net_device *dev)
skb = dev_alloc_skb(i_pkt_size + 3);
if (skb == NULL) {
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
@@ -575,12 +571,11 @@ static void ni5010_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += i_pkt_size;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += i_pkt_size;
PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n",
dev->name, i_pkt_size));
-
}
static int process_xmt_interrupt(struct net_device *dev)
@@ -604,14 +599,14 @@ static int process_xmt_interrupt(struct net_device *dev)
/* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */
outb(MM_EN_XMT | MM_MUX, IE_MMODE);
outb(XM_ALL, EDLC_XMASK); /* Enable xmt IRQ's */
- lp->stats.collisions++;
+ dev->stats.collisions++;
return 1;
}
/* FIXME: handle other xmt error conditions */
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += lp->o_pkt_size;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += lp->o_pkt_size;
netif_wake_queue(dev);
PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n",
@@ -640,24 +635,6 @@ static int ni5010_close(struct net_device *dev)
}
-/* Get the current statistics. This may be called with the card open or
- closed. */
-static struct net_device_stats *ni5010_get_stats(struct net_device *dev)
-{
- struct ni5010_local *lp = netdev_priv(dev);
-
- PRINTK2((KERN_DEBUG "%s: entering ni5010_get_stats\n", dev->name));
-
- if (NI5010_DEBUG) ni5010_show_registers(dev);
-
- /* cli(); */
- /* Update the statistics from the device registers. */
- /* We do this in the interrupt handler */
- /* sti(); */
-
- return &lp->stats;
-}
-
/* Set or clear the multicast filter for this adaptor.
num_addrs == -1 Promiscuous mode, receive all packets
num_addrs == 0 Normal mode, clear multicast list
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 5e7999db209..6b3384a24f0 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -382,8 +382,6 @@ struct net_device * __init ni52_probe(int unit)
memend = dev->mem_end;
}
- SET_MODULE_OWNER(dev);
-
if (io > 0x1ff) { /* Check a single specified location. */
err = ni52_probe1(dev, io);
} else if (io > 0) { /* Don't probe at all. */
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 4ef5fe34519..3edc971d0ec 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -183,7 +183,7 @@ static struct card {
short addr_offset;
unsigned char *vendor_id;
char *cardname;
- long config;
+ unsigned long config;
} cards[] = {
{
.id0 = NI65_ID0,
@@ -550,7 +550,6 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr)
}
dev->base_addr = ioaddr;
- SET_MODULE_OWNER(dev);
dev->open = ni65_open;
dev->stop = ni65_close;
dev->hard_start_xmit = ni65_send_packet;
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
new file mode 100644
index 00000000000..112ab079ce7
--- /dev/null
+++ b/drivers/net/niu.c
@@ -0,0 +1,7914 @@
+/* niu.c: Neptune ethernet driver.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/mii.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/ipv6.h>
+#include <linux/log2.h>
+#include <linux/jiffies.h>
+#include <linux/crc32.h>
+
+#include <linux/io.h>
+
+#ifdef CONFIG_SPARC64
+#include <linux/of_device.h>
+#endif
+
+#include "niu.h"
+
+#define DRV_MODULE_NAME "niu"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_MODULE_VERSION "0.5"
+#define DRV_MODULE_RELDATE "October 5, 2007"
+
+static char version[] __devinitdata =
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("NIU ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+#ifndef DMA_44BIT_MASK
+#define DMA_44BIT_MASK 0x00000fffffffffffULL
+#endif
+
+#ifndef readq
+static u64 readq(void __iomem *reg)
+{
+ return (((u64)readl(reg + 0x4UL) << 32) |
+ (u64)readl(reg));
+}
+
+static void writeq(u64 val, void __iomem *reg)
+{
+ writel(val & 0xffffffff, reg);
+ writel(val >> 32, reg + 0x4UL);
+}
+#endif
+
+static struct pci_device_id niu_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_SUN, 0xabcd)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(pci, niu_pci_tbl);
+
+#define NIU_TX_TIMEOUT (5 * HZ)
+
+#define nr64(reg) readq(np->regs + (reg))
+#define nw64(reg, val) writeq((val), np->regs + (reg))
+
+#define nr64_mac(reg) readq(np->mac_regs + (reg))
+#define nw64_mac(reg, val) writeq((val), np->mac_regs + (reg))
+
+#define nr64_ipp(reg) readq(np->regs + np->ipp_off + (reg))
+#define nw64_ipp(reg, val) writeq((val), np->regs + np->ipp_off + (reg))
+
+#define nr64_pcs(reg) readq(np->regs + np->pcs_off + (reg))
+#define nw64_pcs(reg, val) writeq((val), np->regs + np->pcs_off + (reg))
+
+#define nr64_xpcs(reg) readq(np->regs + np->xpcs_off + (reg))
+#define nw64_xpcs(reg, val) writeq((val), np->regs + np->xpcs_off + (reg))
+
+#define NIU_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
+
+static int niu_debug;
+static int debug = -1;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "NIU debug level");
+
+#define niudbg(TYPE, f, a...) \
+do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \
+ printk(KERN_DEBUG PFX f, ## a); \
+} while (0)
+
+#define niuinfo(TYPE, f, a...) \
+do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \
+ printk(KERN_INFO PFX f, ## a); \
+} while (0)
+
+#define niuwarn(TYPE, f, a...) \
+do { if ((np)->msg_enable & NETIF_MSG_##TYPE) \
+ printk(KERN_WARNING PFX f, ## a); \
+} while (0)
+
+#define niu_lock_parent(np, flags) \
+ spin_lock_irqsave(&np->parent->lock, flags)
+#define niu_unlock_parent(np, flags) \
+ spin_unlock_irqrestore(&np->parent->lock, flags)
+
+static int __niu_wait_bits_clear_mac(struct niu *np, unsigned long reg,
+ u64 bits, int limit, int delay)
+{
+ while (--limit >= 0) {
+ u64 val = nr64_mac(reg);
+
+ if (!(val & bits))
+ break;
+ udelay(delay);
+ }
+ if (limit < 0)
+ return -ENODEV;
+ return 0;
+}
+
+static int __niu_set_and_wait_clear_mac(struct niu *np, unsigned long reg,
+ u64 bits, int limit, int delay,
+ const char *reg_name)
+{
+ int err;
+
+ nw64_mac(reg, bits);
+ err = __niu_wait_bits_clear_mac(np, reg, bits, limit, delay);
+ if (err)
+ dev_err(np->device, PFX "%s: bits (%llx) of register %s "
+ "would not clear, val[%llx]\n",
+ np->dev->name, (unsigned long long) bits, reg_name,
+ (unsigned long long) nr64_mac(reg));
+ return err;
+}
+
+#define niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \
+({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
+ __niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \
+})
+
+static int __niu_wait_bits_clear_ipp(struct niu *np, unsigned long reg,
+ u64 bits, int limit, int delay)
+{
+ while (--limit >= 0) {
+ u64 val = nr64_ipp(reg);
+
+ if (!(val & bits))
+ break;
+ udelay(delay);
+ }
+ if (limit < 0)
+ return -ENODEV;
+ return 0;
+}
+
+static int __niu_set_and_wait_clear_ipp(struct niu *np, unsigned long reg,
+ u64 bits, int limit, int delay,
+ const char *reg_name)
+{
+ int err;
+ u64 val;
+
+ val = nr64_ipp(reg);
+ val |= bits;
+ nw64_ipp(reg, val);
+
+ err = __niu_wait_bits_clear_ipp(np, reg, bits, limit, delay);
+ if (err)
+ dev_err(np->device, PFX "%s: bits (%llx) of register %s "
+ "would not clear, val[%llx]\n",
+ np->dev->name, (unsigned long long) bits, reg_name,
+ (unsigned long long) nr64_ipp(reg));
+ return err;
+}
+
+#define niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \
+({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
+ __niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \
+})
+
+static int __niu_wait_bits_clear(struct niu *np, unsigned long reg,
+ u64 bits, int limit, int delay)
+{
+ while (--limit >= 0) {
+ u64 val = nr64(reg);
+
+ if (!(val & bits))
+ break;
+ udelay(delay);
+ }
+ if (limit < 0)
+ return -ENODEV;
+ return 0;
+}
+
+#define niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY) \
+({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
+ __niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY); \
+})
+
+static int __niu_set_and_wait_clear(struct niu *np, unsigned long reg,
+ u64 bits, int limit, int delay,
+ const char *reg_name)
+{
+ int err;
+
+ nw64(reg, bits);
+ err = __niu_wait_bits_clear(np, reg, bits, limit, delay);
+ if (err)
+ dev_err(np->device, PFX "%s: bits (%llx) of register %s "
+ "would not clear, val[%llx]\n",
+ np->dev->name, (unsigned long long) bits, reg_name,
+ (unsigned long long) nr64(reg));
+ return err;
+}
+
+#define niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \
+({ BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
+ __niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \
+})
+
+static void niu_ldg_rearm(struct niu *np, struct niu_ldg *lp, int on)
+{
+ u64 val = (u64) lp->timer;
+
+ if (on)
+ val |= LDG_IMGMT_ARM;
+
+ nw64(LDG_IMGMT(lp->ldg_num), val);
+}
+
+static int niu_ldn_irq_enable(struct niu *np, int ldn, int on)
+{
+ unsigned long mask_reg, bits;
+ u64 val;
+
+ if (ldn < 0 || ldn > LDN_MAX)
+ return -EINVAL;
+
+ if (ldn < 64) {
+ mask_reg = LD_IM0(ldn);
+ bits = LD_IM0_MASK;
+ } else {
+ mask_reg = LD_IM1(ldn - 64);
+ bits = LD_IM1_MASK;
+ }
+
+ val = nr64(mask_reg);
+ if (on)
+ val &= ~bits;
+ else
+ val |= bits;
+ nw64(mask_reg, val);
+
+ return 0;
+}
+
+static int niu_enable_ldn_in_ldg(struct niu *np, struct niu_ldg *lp, int on)
+{
+ struct niu_parent *parent = np->parent;
+ int i;
+
+ for (i = 0; i <= LDN_MAX; i++) {
+ int err;
+
+ if (parent->ldg_map[i] != lp->ldg_num)
+ continue;
+
+ err = niu_ldn_irq_enable(np, i, on);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int niu_enable_interrupts(struct niu *np, int on)
+{
+ int i;
+
+ for (i = 0; i < np->num_ldg; i++) {
+ struct niu_ldg *lp = &np->ldg[i];
+ int err;
+
+ err = niu_enable_ldn_in_ldg(np, lp, on);
+ if (err)
+ return err;
+ }
+ for (i = 0; i < np->num_ldg; i++)
+ niu_ldg_rearm(np, &np->ldg[i], on);
+
+ return 0;
+}
+
+static u32 phy_encode(u32 type, int port)
+{
+ return (type << (port * 2));
+}
+
+static u32 phy_decode(u32 val, int port)
+{
+ return (val >> (port * 2)) & PORT_TYPE_MASK;
+}
+
+static int mdio_wait(struct niu *np)
+{
+ int limit = 1000;
+ u64 val;
+
+ while (--limit > 0) {
+ val = nr64(MIF_FRAME_OUTPUT);
+ if ((val >> MIF_FRAME_OUTPUT_TA_SHIFT) & 0x1)
+ return val & MIF_FRAME_OUTPUT_DATA;
+
+ udelay(10);
+ }
+
+ return -ENODEV;
+}
+
+static int mdio_read(struct niu *np, int port, int dev, int reg)
+{
+ int err;
+
+ nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg));
+ err = mdio_wait(np);
+ if (err < 0)
+ return err;
+
+ nw64(MIF_FRAME_OUTPUT, MDIO_READ_OP(port, dev));
+ return mdio_wait(np);
+}
+
+static int mdio_write(struct niu *np, int port, int dev, int reg, int data)
+{
+ int err;
+
+ nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg));
+ err = mdio_wait(np);
+ if (err < 0)
+ return err;
+
+ nw64(MIF_FRAME_OUTPUT, MDIO_WRITE_OP(port, dev, data));
+ err = mdio_wait(np);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int mii_read(struct niu *np, int port, int reg)
+{
+ nw64(MIF_FRAME_OUTPUT, MII_READ_OP(port, reg));
+ return mdio_wait(np);
+}
+
+static int mii_write(struct niu *np, int port, int reg, int data)
+{
+ int err;
+
+ nw64(MIF_FRAME_OUTPUT, MII_WRITE_OP(port, reg, data));
+ err = mdio_wait(np);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int esr2_set_tx_cfg(struct niu *np, unsigned long channel, u32 val)
+{
+ int err;
+
+ err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+ ESR2_TI_PLL_TX_CFG_L(channel),
+ val & 0xffff);
+ if (!err)
+ err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+ ESR2_TI_PLL_TX_CFG_H(channel),
+ val >> 16);
+ return err;
+}
+
+static int esr2_set_rx_cfg(struct niu *np, unsigned long channel, u32 val)
+{
+ int err;
+
+ err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+ ESR2_TI_PLL_RX_CFG_L(channel),
+ val & 0xffff);
+ if (!err)
+ err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+ ESR2_TI_PLL_RX_CFG_H(channel),
+ val >> 16);
+ return err;
+}
+
+/* Mode is always 10G fiber. */
+static int serdes_init_niu(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u32 tx_cfg, rx_cfg;
+ unsigned long i;
+
+ tx_cfg = (PLL_TX_CFG_ENTX | PLL_TX_CFG_SWING_1375MV);
+ rx_cfg = (PLL_RX_CFG_ENRX | PLL_RX_CFG_TERM_0P8VDDT |
+ PLL_RX_CFG_ALIGN_ENA | PLL_RX_CFG_LOS_LTHRESH |
+ PLL_RX_CFG_EQ_LP_ADAPTIVE);
+
+ if (lp->loopback_mode == LOOPBACK_PHY) {
+ u16 test_cfg = PLL_TEST_CFG_LOOPBACK_CML_DIS;
+
+ mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+ ESR2_TI_PLL_TEST_CFG_L, test_cfg);
+
+ tx_cfg |= PLL_TX_CFG_ENTEST;
+ rx_cfg |= PLL_RX_CFG_ENTEST;
+ }
+
+ /* Initialize all 4 lanes of the SERDES. */
+ for (i = 0; i < 4; i++) {
+ int err = esr2_set_tx_cfg(np, i, tx_cfg);
+ if (err)
+ return err;
+ }
+
+ for (i = 0; i < 4; i++) {
+ int err = esr2_set_rx_cfg(np, i, rx_cfg);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int esr_read_rxtx_ctrl(struct niu *np, unsigned long chan, u32 *val)
+{
+ int err;
+
+ err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, ESR_RXTX_CTRL_L(chan));
+ if (err >= 0) {
+ *val = (err & 0xffff);
+ err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_CTRL_H(chan));
+ if (err >= 0)
+ *val |= ((err & 0xffff) << 16);
+ err = 0;
+ }
+ return err;
+}
+
+static int esr_read_glue0(struct niu *np, unsigned long chan, u32 *val)
+{
+ int err;
+
+ err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_GLUE_CTRL0_L(chan));
+ if (err >= 0) {
+ *val = (err & 0xffff);
+ err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_GLUE_CTRL0_H(chan));
+ if (err >= 0) {
+ *val |= ((err & 0xffff) << 16);
+ err = 0;
+ }
+ }
+ return err;
+}
+
+static int esr_read_reset(struct niu *np, u32 *val)
+{
+ int err;
+
+ err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_RESET_CTRL_L);
+ if (err >= 0) {
+ *val = (err & 0xffff);
+ err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_RESET_CTRL_H);
+ if (err >= 0) {
+ *val |= ((err & 0xffff) << 16);
+ err = 0;
+ }
+ }
+ return err;
+}
+
+static int esr_write_rxtx_ctrl(struct niu *np, unsigned long chan, u32 val)
+{
+ int err;
+
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_CTRL_L(chan), val & 0xffff);
+ if (!err)
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_CTRL_H(chan), (val >> 16));
+ return err;
+}
+
+static int esr_write_glue0(struct niu *np, unsigned long chan, u32 val)
+{
+ int err;
+
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_GLUE_CTRL0_L(chan), val & 0xffff);
+ if (!err)
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_GLUE_CTRL0_H(chan), (val >> 16));
+ return err;
+}
+
+static int esr_reset(struct niu *np)
+{
+ u32 reset;
+ int err;
+
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_RESET_CTRL_L, 0x0000);
+ if (err)
+ return err;
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_RESET_CTRL_H, 0xffff);
+ if (err)
+ return err;
+ udelay(200);
+
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_RESET_CTRL_L, 0xffff);
+ if (err)
+ return err;
+ udelay(200);
+
+ err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+ ESR_RXTX_RESET_CTRL_H, 0x0000);
+ if (err)
+ return err;
+ udelay(200);
+
+ err = esr_read_reset(np, &reset);
+ if (err)
+ return err;
+ if (reset != 0) {
+ dev_err(np->device, PFX "Port %u ESR_RESET "
+ "did not clear [%08x]\n",
+ np->port, reset);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int serdes_init_10g(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ unsigned long ctrl_reg, test_cfg_reg, i;
+ u64 ctrl_val, test_cfg_val, sig, mask, val;
+ int err;
+
+ switch (np->port) {
+ case 0:
+ ctrl_reg = ENET_SERDES_0_CTRL_CFG;
+ test_cfg_reg = ENET_SERDES_0_TEST_CFG;
+ break;
+ case 1:
+ ctrl_reg = ENET_SERDES_1_CTRL_CFG;
+ test_cfg_reg = ENET_SERDES_1_TEST_CFG;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ ctrl_val = (ENET_SERDES_CTRL_SDET_0 |
+ ENET_SERDES_CTRL_SDET_1 |
+ ENET_SERDES_CTRL_SDET_2 |
+ ENET_SERDES_CTRL_SDET_3 |
+ (0x5 << ENET_SERDES_CTRL_EMPH_0_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_1_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_2_SHIFT) |
+ (0x5 << ENET_SERDES_CTRL_EMPH_3_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_0_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_1_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_2_SHIFT) |
+ (0x1 << ENET_SERDES_CTRL_LADJ_3_SHIFT));
+ test_cfg_val = 0;
+
+ if (lp->loopback_mode == LOOPBACK_PHY) {
+ test_cfg_val |= ((ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_0_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_1_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_2_SHIFT) |
+ (ENET_TEST_MD_PAD_LOOPBACK <<
+ ENET_SERDES_TEST_MD_3_SHIFT));
+ }
+
+ nw64(ctrl_reg, ctrl_val);
+ nw64(test_cfg_reg, test_cfg_val);
+
+ /* Initialize all 4 lanes of the SERDES. */
+ for (i = 0; i < 4; i++) {
+ u32 rxtx_ctrl, glue0;
+
+ err = esr_read_rxtx_ctrl(np, i, &rxtx_ctrl);
+ if (err)
+ return err;
+ err = esr_read_glue0(np, i, &glue0);
+ if (err)
+ return err;
+
+ rxtx_ctrl &= ~(ESR_RXTX_CTRL_VMUXLO);
+ rxtx_ctrl |= (ESR_RXTX_CTRL_ENSTRETCH |
+ (2 << ESR_RXTX_CTRL_VMUXLO_SHIFT));
+
+ glue0 &= ~(ESR_GLUE_CTRL0_SRATE |
+ ESR_GLUE_CTRL0_THCNT |
+ ESR_GLUE_CTRL0_BLTIME);
+ glue0 |= (ESR_GLUE_CTRL0_RXLOSENAB |
+ (0xf << ESR_GLUE_CTRL0_SRATE_SHIFT) |
+ (0xff << ESR_GLUE_CTRL0_THCNT_SHIFT) |
+ (BLTIME_300_CYCLES <<
+ ESR_GLUE_CTRL0_BLTIME_SHIFT));
+
+ err = esr_write_rxtx_ctrl(np, i, rxtx_ctrl);
+ if (err)
+ return err;
+ err = esr_write_glue0(np, i, glue0);
+ if (err)
+ return err;
+ }
+
+ err = esr_reset(np);
+ if (err)
+ return err;
+
+ sig = nr64(ESR_INT_SIGNALS);
+ switch (np->port) {
+ case 0:
+ mask = ESR_INT_SIGNALS_P0_BITS;
+ val = (ESR_INT_SRDY0_P0 |
+ ESR_INT_DET0_P0 |
+ ESR_INT_XSRDY_P0 |
+ ESR_INT_XDP_P0_CH3 |
+ ESR_INT_XDP_P0_CH2 |
+ ESR_INT_XDP_P0_CH1 |
+ ESR_INT_XDP_P0_CH0);
+ break;
+
+ case 1:
+ mask = ESR_INT_SIGNALS_P1_BITS;
+ val = (ESR_INT_SRDY0_P1 |
+ ESR_INT_DET0_P1 |
+ ESR_INT_XSRDY_P1 |
+ ESR_INT_XDP_P1_CH3 |
+ ESR_INT_XDP_P1_CH2 |
+ ESR_INT_XDP_P1_CH1 |
+ ESR_INT_XDP_P1_CH0);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if ((sig & mask) != val) {
+ dev_err(np->device, PFX "Port %u signal bits [%08x] are not "
+ "[%08x]\n", np->port, (int) (sig & mask), (int) val);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int serdes_init_1g(struct niu *np)
+{
+ u64 val;
+
+ val = nr64(ENET_SERDES_1_PLL_CFG);
+ val &= ~ENET_SERDES_PLL_FBDIV2;
+ switch (np->port) {
+ case 0:
+ val |= ENET_SERDES_PLL_HRATE0;
+ break;
+ case 1:
+ val |= ENET_SERDES_PLL_HRATE1;
+ break;
+ case 2:
+ val |= ENET_SERDES_PLL_HRATE2;
+ break;
+ case 3:
+ val |= ENET_SERDES_PLL_HRATE3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ nw64(ENET_SERDES_1_PLL_CFG, val);
+
+ return 0;
+}
+
+static int bcm8704_reset(struct niu *np)
+{
+ int err, limit;
+
+ err = mdio_read(np, np->phy_addr,
+ BCM8704_PHYXS_DEV_ADDR, MII_BMCR);
+ if (err < 0)
+ return err;
+ err |= BMCR_RESET;
+ err = mdio_write(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
+ MII_BMCR, err);
+ if (err)
+ return err;
+
+ limit = 1000;
+ while (--limit >= 0) {
+ err = mdio_read(np, np->phy_addr,
+ BCM8704_PHYXS_DEV_ADDR, MII_BMCR);
+ if (err < 0)
+ return err;
+ if (!(err & BMCR_RESET))
+ break;
+ }
+ if (limit < 0) {
+ dev_err(np->device, PFX "Port %u PHY will not reset "
+ "(bmcr=%04x)\n", np->port, (err & 0xffff));
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/* When written, certain PHY registers need to be read back twice
+ * in order for the bits to settle properly.
+ */
+static int bcm8704_user_dev3_readback(struct niu *np, int reg)
+{
+ int err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg);
+ if (err < 0)
+ return err;
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int bcm8704_init_user_dev3(struct niu *np)
+{
+ int err;
+
+ err = mdio_write(np, np->phy_addr,
+ BCM8704_USER_DEV3_ADDR, BCM8704_USER_CONTROL,
+ (USER_CONTROL_OPTXRST_LVL |
+ USER_CONTROL_OPBIASFLT_LVL |
+ USER_CONTROL_OBTMPFLT_LVL |
+ USER_CONTROL_OPPRFLT_LVL |
+ USER_CONTROL_OPTXFLT_LVL |
+ USER_CONTROL_OPRXLOS_LVL |
+ USER_CONTROL_OPRXFLT_LVL |
+ USER_CONTROL_OPTXON_LVL |
+ (0x3f << USER_CONTROL_RES1_SHIFT)));
+ if (err)
+ return err;
+
+ err = mdio_write(np, np->phy_addr,
+ BCM8704_USER_DEV3_ADDR, BCM8704_USER_PMD_TX_CONTROL,
+ (USER_PMD_TX_CTL_XFP_CLKEN |
+ (1 << USER_PMD_TX_CTL_TX_DAC_TXD_SH) |
+ (2 << USER_PMD_TX_CTL_TX_DAC_TXCK_SH) |
+ USER_PMD_TX_CTL_TSCK_LPWREN));
+ if (err)
+ return err;
+
+ err = bcm8704_user_dev3_readback(np, BCM8704_USER_CONTROL);
+ if (err)
+ return err;
+ err = bcm8704_user_dev3_readback(np, BCM8704_USER_PMD_TX_CONTROL);
+ if (err)
+ return err;
+
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_OPT_DIGITAL_CTRL);
+ if (err < 0)
+ return err;
+ err &= ~USER_ODIG_CTRL_GPIOS;
+ err |= (0x3 << USER_ODIG_CTRL_GPIOS_SHIFT);
+ err = mdio_write(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_OPT_DIGITAL_CTRL, err);
+ if (err)
+ return err;
+
+ mdelay(1000);
+
+ return 0;
+}
+
+static int xcvr_init_10g(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u16 analog_stat0, tx_alarm_status;
+ int err;
+ u64 val;
+
+ val = nr64_mac(XMAC_CONFIG);
+ val &= ~XMAC_CONFIG_LED_POLARITY;
+ val |= XMAC_CONFIG_FORCE_LED_ON;
+ nw64_mac(XMAC_CONFIG, val);
+
+ /* XXX shared resource, lock parent XXX */
+ val = nr64(MIF_CONFIG);
+ val |= MIF_CONFIG_INDIRECT_MODE;
+ nw64(MIF_CONFIG, val);
+
+ err = bcm8704_reset(np);
+ if (err)
+ return err;
+
+ err = bcm8704_init_user_dev3(np);
+ if (err)
+ return err;
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
+ MII_BMCR);
+ if (err < 0)
+ return err;
+ err &= ~BMCR_LOOPBACK;
+
+ if (lp->loopback_mode == LOOPBACK_MAC)
+ err |= BMCR_LOOPBACK;
+
+ err = mdio_write(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
+ MII_BMCR, err);
+ if (err)
+ return err;
+
+#if 1
+ err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
+ MII_STAT1000);
+ if (err < 0)
+ return err;
+ pr_info(PFX "Port %u PMA_PMD(MII_STAT1000) [%04x]\n",
+ np->port, err);
+
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, 0x20);
+ if (err < 0)
+ return err;
+ pr_info(PFX "Port %u USER_DEV3(0x20) [%04x]\n",
+ np->port, err);
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
+ MII_NWAYTEST);
+ if (err < 0)
+ return err;
+ pr_info(PFX "Port %u PHYXS(MII_NWAYTEST) [%04x]\n",
+ np->port, err);
+#endif
+
+ /* XXX dig this out it might not be so useful XXX */
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_ANALOG_STATUS0);
+ if (err < 0)
+ return err;
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_ANALOG_STATUS0);
+ if (err < 0)
+ return err;
+ analog_stat0 = err;
+
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_TX_ALARM_STATUS);
+ if (err < 0)
+ return err;
+ err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+ BCM8704_USER_TX_ALARM_STATUS);
+ if (err < 0)
+ return err;
+ tx_alarm_status = err;
+
+ if (analog_stat0 != 0x03fc) {
+ if ((analog_stat0 == 0x43bc) && (tx_alarm_status != 0)) {
+ pr_info(PFX "Port %u cable not connected "
+ "or bad cable.\n", np->port);
+ } else if (analog_stat0 == 0x639c) {
+ pr_info(PFX "Port %u optical module is bad "
+ "or missing.\n", np->port);
+ }
+ }
+
+ return 0;
+}
+
+static int mii_reset(struct niu *np)
+{
+ int limit, err;
+
+ err = mii_write(np, np->phy_addr, MII_BMCR, BMCR_RESET);
+ if (err)
+ return err;
+
+ limit = 1000;
+ while (--limit >= 0) {
+ udelay(500);
+ err = mii_read(np, np->phy_addr, MII_BMCR);
+ if (err < 0)
+ return err;
+ if (!(err & BMCR_RESET))
+ break;
+ }
+ if (limit < 0) {
+ dev_err(np->device, PFX "Port %u MII would not reset, "
+ "bmcr[%04x]\n", np->port, err);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int mii_init_common(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u16 bmcr, bmsr, adv, estat;
+ int err;
+
+ err = mii_reset(np);
+ if (err)
+ return err;
+
+ err = mii_read(np, np->phy_addr, MII_BMSR);
+ if (err < 0)
+ return err;
+ bmsr = err;
+
+ estat = 0;
+ if (bmsr & BMSR_ESTATEN) {
+ err = mii_read(np, np->phy_addr, MII_ESTATUS);
+ if (err < 0)
+ return err;
+ estat = err;
+ }
+
+ bmcr = 0;
+ err = mii_write(np, np->phy_addr, MII_BMCR, bmcr);
+ if (err)
+ return err;
+
+ if (lp->loopback_mode == LOOPBACK_MAC) {
+ bmcr |= BMCR_LOOPBACK;
+ if (lp->active_speed == SPEED_1000)
+ bmcr |= BMCR_SPEED1000;
+ if (lp->active_duplex == DUPLEX_FULL)
+ bmcr |= BMCR_FULLDPLX;
+ }
+
+ if (lp->loopback_mode == LOOPBACK_PHY) {
+ u16 aux;
+
+ aux = (BCM5464R_AUX_CTL_EXT_LB |
+ BCM5464R_AUX_CTL_WRITE_1);
+ err = mii_write(np, np->phy_addr, BCM5464R_AUX_CTL, aux);
+ if (err)
+ return err;
+ }
+
+ /* XXX configurable XXX */
+ /* XXX for now don't advertise half-duplex or asym pause... XXX */
+ adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
+ if (bmsr & BMSR_10FULL)
+ adv |= ADVERTISE_10FULL;
+ if (bmsr & BMSR_100FULL)
+ adv |= ADVERTISE_100FULL;
+ err = mii_write(np, np->phy_addr, MII_ADVERTISE, adv);
+ if (err)
+ return err;
+
+ if (bmsr & BMSR_ESTATEN) {
+ u16 ctrl1000 = 0;
+
+ if (estat & ESTATUS_1000_TFULL)
+ ctrl1000 |= ADVERTISE_1000FULL;
+ err = mii_write(np, np->phy_addr, MII_CTRL1000, ctrl1000);
+ if (err)
+ return err;
+ }
+ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+
+ err = mii_write(np, np->phy_addr, MII_BMCR, bmcr);
+ if (err)
+ return err;
+
+ err = mii_read(np, np->phy_addr, MII_BMCR);
+ if (err < 0)
+ return err;
+ err = mii_read(np, np->phy_addr, MII_BMSR);
+ if (err < 0)
+ return err;
+#if 0
+ pr_info(PFX "Port %u after MII init bmcr[%04x] bmsr[%04x]\n",
+ np->port, bmcr, bmsr);
+#endif
+
+ return 0;
+}
+
+static int xcvr_init_1g(struct niu *np)
+{
+ u64 val;
+
+ /* XXX shared resource, lock parent XXX */
+ val = nr64(MIF_CONFIG);
+ val &= ~MIF_CONFIG_INDIRECT_MODE;
+ nw64(MIF_CONFIG, val);
+
+ return mii_init_common(np);
+}
+
+static int niu_xcvr_init(struct niu *np)
+{
+ const struct niu_phy_ops *ops = np->phy_ops;
+ int err;
+
+ err = 0;
+ if (ops->xcvr_init)
+ err = ops->xcvr_init(np);
+
+ return err;
+}
+
+static int niu_serdes_init(struct niu *np)
+{
+ const struct niu_phy_ops *ops = np->phy_ops;
+ int err;
+
+ err = 0;
+ if (ops->serdes_init)
+ err = ops->serdes_init(np);
+
+ return err;
+}
+
+static void niu_init_xif(struct niu *);
+
+static int niu_link_status_common(struct niu *np, int link_up)
+{
+ struct niu_link_config *lp = &np->link_config;
+ struct net_device *dev = np->dev;
+ unsigned long flags;
+
+ if (!netif_carrier_ok(dev) && link_up) {
+ niuinfo(LINK, "%s: Link is up at %s, %s duplex\n",
+ dev->name,
+ (lp->active_speed == SPEED_10000 ?
+ "10Gb/sec" :
+ (lp->active_speed == SPEED_1000 ?
+ "1Gb/sec" :
+ (lp->active_speed == SPEED_100 ?
+ "100Mbit/sec" : "10Mbit/sec"))),
+ (lp->active_duplex == DUPLEX_FULL ?
+ "full" : "half"));
+
+ spin_lock_irqsave(&np->lock, flags);
+ niu_init_xif(np);
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ netif_carrier_on(dev);
+ } else if (netif_carrier_ok(dev) && !link_up) {
+ niuwarn(LINK, "%s: Link is down\n", dev->name);
+ netif_carrier_off(dev);
+ }
+
+ return 0;
+}
+
+static int link_status_10g(struct niu *np, int *link_up_p)
+{
+ unsigned long flags;
+ int err, link_up;
+
+ link_up = 0;
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ err = -EINVAL;
+ if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+ goto out;
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
+ BCM8704_PMD_RCV_SIGDET);
+ if (err < 0)
+ goto out;
+ if (!(err & PMD_RCV_SIGDET_GLOBAL)) {
+ err = 0;
+ goto out;
+ }
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
+ BCM8704_PCS_10G_R_STATUS);
+ if (err < 0)
+ goto out;
+ if (!(err & PCS_10G_R_STATUS_BLK_LOCK)) {
+ err = 0;
+ goto out;
+ }
+
+ err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
+ BCM8704_PHYXS_XGXS_LANE_STAT);
+ if (err < 0)
+ goto out;
+
+ if (err != (PHYXS_XGXS_LANE_STAT_ALINGED |
+ PHYXS_XGXS_LANE_STAT_MAGIC |
+ PHYXS_XGXS_LANE_STAT_LANE3 |
+ PHYXS_XGXS_LANE_STAT_LANE2 |
+ PHYXS_XGXS_LANE_STAT_LANE1 |
+ PHYXS_XGXS_LANE_STAT_LANE0)) {
+ err = 0;
+ goto out;
+ }
+
+ link_up = 1;
+ np->link_config.active_speed = SPEED_10000;
+ np->link_config.active_duplex = DUPLEX_FULL;
+ err = 0;
+
+out:
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ *link_up_p = link_up;
+ return err;
+}
+
+static int link_status_1g(struct niu *np, int *link_up_p)
+{
+ u16 current_speed, bmsr;
+ unsigned long flags;
+ u8 current_duplex;
+ int err, link_up;
+
+ link_up = 0;
+ current_speed = SPEED_INVALID;
+ current_duplex = DUPLEX_INVALID;
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ err = -EINVAL;
+ if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+ goto out;
+
+ err = mii_read(np, np->phy_addr, MII_BMSR);
+ if (err < 0)
+ goto out;
+
+ bmsr = err;
+ if (bmsr & BMSR_LSTATUS) {
+ u16 adv, lpa, common, estat;
+
+ err = mii_read(np, np->phy_addr, MII_ADVERTISE);
+ if (err < 0)
+ goto out;
+ adv = err;
+
+ err = mii_read(np, np->phy_addr, MII_LPA);
+ if (err < 0)
+ goto out;
+ lpa = err;
+
+ common = adv & lpa;
+
+ err = mii_read(np, np->phy_addr, MII_ESTATUS);
+ if (err < 0)
+ goto out;
+ estat = err;
+
+ link_up = 1;
+ if (estat & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) {
+ current_speed = SPEED_1000;
+ if (estat & ESTATUS_1000_TFULL)
+ current_duplex = DUPLEX_FULL;
+ else
+ current_duplex = DUPLEX_HALF;
+ } else {
+ if (common & ADVERTISE_100BASE4) {
+ current_speed = SPEED_100;
+ current_duplex = DUPLEX_HALF;
+ } else if (common & ADVERTISE_100FULL) {
+ current_speed = SPEED_100;
+ current_duplex = DUPLEX_FULL;
+ } else if (common & ADVERTISE_100HALF) {
+ current_speed = SPEED_100;
+ current_duplex = DUPLEX_HALF;
+ } else if (common & ADVERTISE_10FULL) {
+ current_speed = SPEED_10;
+ current_duplex = DUPLEX_FULL;
+ } else if (common & ADVERTISE_10HALF) {
+ current_speed = SPEED_10;
+ current_duplex = DUPLEX_HALF;
+ } else
+ link_up = 0;
+ }
+ }
+ err = 0;
+
+out:
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ *link_up_p = link_up;
+ return err;
+}
+
+static int niu_link_status(struct niu *np, int *link_up_p)
+{
+ const struct niu_phy_ops *ops = np->phy_ops;
+ int err;
+
+ err = 0;
+ if (ops->link_status)
+ err = ops->link_status(np, link_up_p);
+
+ return err;
+}
+
+static void niu_timer(unsigned long __opaque)
+{
+ struct niu *np = (struct niu *) __opaque;
+ unsigned long off;
+ int err, link_up;
+
+ err = niu_link_status(np, &link_up);
+ if (!err)
+ niu_link_status_common(np, link_up);
+
+ if (netif_carrier_ok(np->dev))
+ off = 5 * HZ;
+ else
+ off = 1 * HZ;
+ np->timer.expires = jiffies + off;
+
+ add_timer(&np->timer);
+}
+
+static const struct niu_phy_ops phy_ops_10g_fiber_niu = {
+ .serdes_init = serdes_init_niu,
+ .xcvr_init = xcvr_init_10g,
+ .link_status = link_status_10g,
+};
+
+static const struct niu_phy_ops phy_ops_10g_fiber = {
+ .serdes_init = serdes_init_10g,
+ .xcvr_init = xcvr_init_10g,
+ .link_status = link_status_10g,
+};
+
+static const struct niu_phy_ops phy_ops_10g_copper = {
+ .serdes_init = serdes_init_10g,
+ .link_status = link_status_10g, /* XXX */
+};
+
+static const struct niu_phy_ops phy_ops_1g_fiber = {
+ .serdes_init = serdes_init_1g,
+ .xcvr_init = xcvr_init_1g,
+ .link_status = link_status_1g,
+};
+
+static const struct niu_phy_ops phy_ops_1g_copper = {
+ .xcvr_init = xcvr_init_1g,
+ .link_status = link_status_1g,
+};
+
+struct niu_phy_template {
+ const struct niu_phy_ops *ops;
+ u32 phy_addr_base;
+};
+
+static const struct niu_phy_template phy_template_niu = {
+ .ops = &phy_ops_10g_fiber_niu,
+ .phy_addr_base = 16,
+};
+
+static const struct niu_phy_template phy_template_10g_fiber = {
+ .ops = &phy_ops_10g_fiber,
+ .phy_addr_base = 8,
+};
+
+static const struct niu_phy_template phy_template_10g_copper = {
+ .ops = &phy_ops_10g_copper,
+ .phy_addr_base = 10,
+};
+
+static const struct niu_phy_template phy_template_1g_fiber = {
+ .ops = &phy_ops_1g_fiber,
+ .phy_addr_base = 0,
+};
+
+static const struct niu_phy_template phy_template_1g_copper = {
+ .ops = &phy_ops_1g_copper,
+ .phy_addr_base = 0,
+};
+
+static int niu_determine_phy_disposition(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ u8 plat_type = parent->plat_type;
+ const struct niu_phy_template *tp;
+ u32 phy_addr_off = 0;
+
+ if (plat_type == PLAT_TYPE_NIU) {
+ tp = &phy_template_niu;
+ phy_addr_off += np->port;
+ } else {
+ switch (np->flags & (NIU_FLAGS_10G | NIU_FLAGS_FIBER)) {
+ case 0:
+ /* 1G copper */
+ tp = &phy_template_1g_copper;
+ if (plat_type == PLAT_TYPE_VF_P0)
+ phy_addr_off = 10;
+ else if (plat_type == PLAT_TYPE_VF_P1)
+ phy_addr_off = 26;
+
+ phy_addr_off += (np->port ^ 0x3);
+ break;
+
+ case NIU_FLAGS_10G:
+ /* 10G copper */
+ tp = &phy_template_1g_copper;
+ break;
+
+ case NIU_FLAGS_FIBER:
+ /* 1G fiber */
+ tp = &phy_template_1g_fiber;
+ break;
+
+ case NIU_FLAGS_10G | NIU_FLAGS_FIBER:
+ /* 10G fiber */
+ tp = &phy_template_10g_fiber;
+ if (plat_type == PLAT_TYPE_VF_P0 ||
+ plat_type == PLAT_TYPE_VF_P1)
+ phy_addr_off = 8;
+ phy_addr_off += np->port;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ np->phy_ops = tp->ops;
+ np->phy_addr = tp->phy_addr_base + phy_addr_off;
+
+ return 0;
+}
+
+static int niu_init_link(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ int err, ignore;
+
+ if (parent->plat_type == PLAT_TYPE_NIU) {
+ err = niu_xcvr_init(np);
+ if (err)
+ return err;
+ msleep(200);
+ }
+ err = niu_serdes_init(np);
+ if (err)
+ return err;
+ msleep(200);
+ err = niu_xcvr_init(np);
+ if (!err)
+ niu_link_status(np, &ignore);
+ return 0;
+}
+
+static void niu_set_primary_mac(struct niu *np, unsigned char *addr)
+{
+ u16 reg0 = addr[4] << 8 | addr[5];
+ u16 reg1 = addr[2] << 8 | addr[3];
+ u16 reg2 = addr[0] << 8 | addr[1];
+
+ if (np->flags & NIU_FLAGS_XMAC) {
+ nw64_mac(XMAC_ADDR0, reg0);
+ nw64_mac(XMAC_ADDR1, reg1);
+ nw64_mac(XMAC_ADDR2, reg2);
+ } else {
+ nw64_mac(BMAC_ADDR0, reg0);
+ nw64_mac(BMAC_ADDR1, reg1);
+ nw64_mac(BMAC_ADDR2, reg2);
+ }
+}
+
+static int niu_num_alt_addr(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ return XMAC_NUM_ALT_ADDR;
+ else
+ return BMAC_NUM_ALT_ADDR;
+}
+
+static int niu_set_alt_mac(struct niu *np, int index, unsigned char *addr)
+{
+ u16 reg0 = addr[4] << 8 | addr[5];
+ u16 reg1 = addr[2] << 8 | addr[3];
+ u16 reg2 = addr[0] << 8 | addr[1];
+
+ if (index >= niu_num_alt_addr(np))
+ return -EINVAL;
+
+ if (np->flags & NIU_FLAGS_XMAC) {
+ nw64_mac(XMAC_ALT_ADDR0(index), reg0);
+ nw64_mac(XMAC_ALT_ADDR1(index), reg1);
+ nw64_mac(XMAC_ALT_ADDR2(index), reg2);
+ } else {
+ nw64_mac(BMAC_ALT_ADDR0(index), reg0);
+ nw64_mac(BMAC_ALT_ADDR1(index), reg1);
+ nw64_mac(BMAC_ALT_ADDR2(index), reg2);
+ }
+
+ return 0;
+}
+
+static int niu_enable_alt_mac(struct niu *np, int index, int on)
+{
+ unsigned long reg;
+ u64 val, mask;
+
+ if (index >= niu_num_alt_addr(np))
+ return -EINVAL;
+
+ if (np->flags & NIU_FLAGS_XMAC)
+ reg = XMAC_ADDR_CMPEN;
+ else
+ reg = BMAC_ADDR_CMPEN;
+
+ mask = 1 << index;
+
+ val = nr64_mac(reg);
+ if (on)
+ val |= mask;
+ else
+ val &= ~mask;
+ nw64_mac(reg, val);
+
+ return 0;
+}
+
+static void __set_rdc_table_num_hw(struct niu *np, unsigned long reg,
+ int num, int mac_pref)
+{
+ u64 val = nr64_mac(reg);
+ val &= ~(HOST_INFO_MACRDCTBLN | HOST_INFO_MPR);
+ val |= num;
+ if (mac_pref)
+ val |= HOST_INFO_MPR;
+ nw64_mac(reg, val);
+}
+
+static int __set_rdc_table_num(struct niu *np,
+ int xmac_index, int bmac_index,
+ int rdc_table_num, int mac_pref)
+{
+ unsigned long reg;
+
+ if (rdc_table_num & ~HOST_INFO_MACRDCTBLN)
+ return -EINVAL;
+ if (np->flags & NIU_FLAGS_XMAC)
+ reg = XMAC_HOST_INFO(xmac_index);
+ else
+ reg = BMAC_HOST_INFO(bmac_index);
+ __set_rdc_table_num_hw(np, reg, rdc_table_num, mac_pref);
+ return 0;
+}
+
+static int niu_set_primary_mac_rdc_table(struct niu *np, int table_num,
+ int mac_pref)
+{
+ return __set_rdc_table_num(np, 17, 0, table_num, mac_pref);
+}
+
+static int niu_set_multicast_mac_rdc_table(struct niu *np, int table_num,
+ int mac_pref)
+{
+ return __set_rdc_table_num(np, 16, 8, table_num, mac_pref);
+}
+
+static int niu_set_alt_mac_rdc_table(struct niu *np, int idx,
+ int table_num, int mac_pref)
+{
+ if (idx >= niu_num_alt_addr(np))
+ return -EINVAL;
+ return __set_rdc_table_num(np, idx, idx + 1, table_num, mac_pref);
+}
+
+static u64 vlan_entry_set_parity(u64 reg_val)
+{
+ u64 port01_mask;
+ u64 port23_mask;
+
+ port01_mask = 0x00ff;
+ port23_mask = 0xff00;
+
+ if (hweight64(reg_val & port01_mask) & 1)
+ reg_val |= ENET_VLAN_TBL_PARITY0;
+ else
+ reg_val &= ~ENET_VLAN_TBL_PARITY0;
+
+ if (hweight64(reg_val & port23_mask) & 1)
+ reg_val |= ENET_VLAN_TBL_PARITY1;
+ else
+ reg_val &= ~ENET_VLAN_TBL_PARITY1;
+
+ return reg_val;
+}
+
+static void vlan_tbl_write(struct niu *np, unsigned long index,
+ int port, int vpr, int rdc_table)
+{
+ u64 reg_val = nr64(ENET_VLAN_TBL(index));
+
+ reg_val &= ~((ENET_VLAN_TBL_VPR |
+ ENET_VLAN_TBL_VLANRDCTBLN) <<
+ ENET_VLAN_TBL_SHIFT(port));
+ if (vpr)
+ reg_val |= (ENET_VLAN_TBL_VPR <<
+ ENET_VLAN_TBL_SHIFT(port));
+ reg_val |= (rdc_table << ENET_VLAN_TBL_SHIFT(port));
+
+ reg_val = vlan_entry_set_parity(reg_val);
+
+ nw64(ENET_VLAN_TBL(index), reg_val);
+}
+
+static void vlan_tbl_clear(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < ENET_VLAN_TBL_NUM_ENTRIES; i++)
+ nw64(ENET_VLAN_TBL(i), 0);
+}
+
+static int tcam_wait_bit(struct niu *np, u64 bit)
+{
+ int limit = 1000;
+
+ while (--limit > 0) {
+ if (nr64(TCAM_CTL) & bit)
+ break;
+ udelay(1);
+ }
+ if (limit < 0)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int tcam_flush(struct niu *np, int index)
+{
+ nw64(TCAM_KEY_0, 0x00);
+ nw64(TCAM_KEY_MASK_0, 0xff);
+ nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_WRITE | index));
+
+ return tcam_wait_bit(np, TCAM_CTL_STAT);
+}
+
+#if 0
+static int tcam_read(struct niu *np, int index,
+ u64 *key, u64 *mask)
+{
+ int err;
+
+ nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_READ | index));
+ err = tcam_wait_bit(np, TCAM_CTL_STAT);
+ if (!err) {
+ key[0] = nr64(TCAM_KEY_0);
+ key[1] = nr64(TCAM_KEY_1);
+ key[2] = nr64(TCAM_KEY_2);
+ key[3] = nr64(TCAM_KEY_3);
+ mask[0] = nr64(TCAM_KEY_MASK_0);
+ mask[1] = nr64(TCAM_KEY_MASK_1);
+ mask[2] = nr64(TCAM_KEY_MASK_2);
+ mask[3] = nr64(TCAM_KEY_MASK_3);
+ }
+ return err;
+}
+#endif
+
+static int tcam_write(struct niu *np, int index,
+ u64 *key, u64 *mask)
+{
+ nw64(TCAM_KEY_0, key[0]);
+ nw64(TCAM_KEY_1, key[1]);
+ nw64(TCAM_KEY_2, key[2]);
+ nw64(TCAM_KEY_3, key[3]);
+ nw64(TCAM_KEY_MASK_0, mask[0]);
+ nw64(TCAM_KEY_MASK_1, mask[1]);
+ nw64(TCAM_KEY_MASK_2, mask[2]);
+ nw64(TCAM_KEY_MASK_3, mask[3]);
+ nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_WRITE | index));
+
+ return tcam_wait_bit(np, TCAM_CTL_STAT);
+}
+
+#if 0
+static int tcam_assoc_read(struct niu *np, int index, u64 *data)
+{
+ int err;
+
+ nw64(TCAM_CTL, (TCAM_CTL_RWC_RAM_READ | index));
+ err = tcam_wait_bit(np, TCAM_CTL_STAT);
+ if (!err)
+ *data = nr64(TCAM_KEY_1);
+
+ return err;
+}
+#endif
+
+static int tcam_assoc_write(struct niu *np, int index, u64 assoc_data)
+{
+ nw64(TCAM_KEY_1, assoc_data);
+ nw64(TCAM_CTL, (TCAM_CTL_RWC_RAM_WRITE | index));
+
+ return tcam_wait_bit(np, TCAM_CTL_STAT);
+}
+
+static void tcam_enable(struct niu *np, int on)
+{
+ u64 val = nr64(FFLP_CFG_1);
+
+ if (on)
+ val &= ~FFLP_CFG_1_TCAM_DIS;
+ else
+ val |= FFLP_CFG_1_TCAM_DIS;
+ nw64(FFLP_CFG_1, val);
+}
+
+static void tcam_set_lat_and_ratio(struct niu *np, u64 latency, u64 ratio)
+{
+ u64 val = nr64(FFLP_CFG_1);
+
+ val &= ~(FFLP_CFG_1_FFLPINITDONE |
+ FFLP_CFG_1_CAMLAT |
+ FFLP_CFG_1_CAMRATIO);
+ val |= (latency << FFLP_CFG_1_CAMLAT_SHIFT);
+ val |= (ratio << FFLP_CFG_1_CAMRATIO_SHIFT);
+ nw64(FFLP_CFG_1, val);
+
+ val = nr64(FFLP_CFG_1);
+ val |= FFLP_CFG_1_FFLPINITDONE;
+ nw64(FFLP_CFG_1, val);
+}
+
+static int tcam_user_eth_class_enable(struct niu *np, unsigned long class,
+ int on)
+{
+ unsigned long reg;
+ u64 val;
+
+ if (class < CLASS_CODE_ETHERTYPE1 ||
+ class > CLASS_CODE_ETHERTYPE2)
+ return -EINVAL;
+
+ reg = L2_CLS(class - CLASS_CODE_ETHERTYPE1);
+ val = nr64(reg);
+ if (on)
+ val |= L2_CLS_VLD;
+ else
+ val &= ~L2_CLS_VLD;
+ nw64(reg, val);
+
+ return 0;
+}
+
+#if 0
+static int tcam_user_eth_class_set(struct niu *np, unsigned long class,
+ u64 ether_type)
+{
+ unsigned long reg;
+ u64 val;
+
+ if (class < CLASS_CODE_ETHERTYPE1 ||
+ class > CLASS_CODE_ETHERTYPE2 ||
+ (ether_type & ~(u64)0xffff) != 0)
+ return -EINVAL;
+
+ reg = L2_CLS(class - CLASS_CODE_ETHERTYPE1);
+ val = nr64(reg);
+ val &= ~L2_CLS_ETYPE;
+ val |= (ether_type << L2_CLS_ETYPE_SHIFT);
+ nw64(reg, val);
+
+ return 0;
+}
+#endif
+
+static int tcam_user_ip_class_enable(struct niu *np, unsigned long class,
+ int on)
+{
+ unsigned long reg;
+ u64 val;
+
+ if (class < CLASS_CODE_USER_PROG1 ||
+ class > CLASS_CODE_USER_PROG4)
+ return -EINVAL;
+
+ reg = L3_CLS(class - CLASS_CODE_USER_PROG1);
+ val = nr64(reg);
+ if (on)
+ val |= L3_CLS_VALID;
+ else
+ val &= ~L3_CLS_VALID;
+ nw64(reg, val);
+
+ return 0;
+}
+
+#if 0
+static int tcam_user_ip_class_set(struct niu *np, unsigned long class,
+ int ipv6, u64 protocol_id,
+ u64 tos_mask, u64 tos_val)
+{
+ unsigned long reg;
+ u64 val;
+
+ if (class < CLASS_CODE_USER_PROG1 ||
+ class > CLASS_CODE_USER_PROG4 ||
+ (protocol_id & ~(u64)0xff) != 0 ||
+ (tos_mask & ~(u64)0xff) != 0 ||
+ (tos_val & ~(u64)0xff) != 0)
+ return -EINVAL;
+
+ reg = L3_CLS(class - CLASS_CODE_USER_PROG1);
+ val = nr64(reg);
+ val &= ~(L3_CLS_IPVER | L3_CLS_PID |
+ L3_CLS_TOSMASK | L3_CLS_TOS);
+ if (ipv6)
+ val |= L3_CLS_IPVER;
+ val |= (protocol_id << L3_CLS_PID_SHIFT);
+ val |= (tos_mask << L3_CLS_TOSMASK_SHIFT);
+ val |= (tos_val << L3_CLS_TOS_SHIFT);
+ nw64(reg, val);
+
+ return 0;
+}
+#endif
+
+static int tcam_early_init(struct niu *np)
+{
+ unsigned long i;
+ int err;
+
+ tcam_enable(np, 0);
+ tcam_set_lat_and_ratio(np,
+ DEFAULT_TCAM_LATENCY,
+ DEFAULT_TCAM_ACCESS_RATIO);
+ for (i = CLASS_CODE_ETHERTYPE1; i <= CLASS_CODE_ETHERTYPE2; i++) {
+ err = tcam_user_eth_class_enable(np, i, 0);
+ if (err)
+ return err;
+ }
+ for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_USER_PROG4; i++) {
+ err = tcam_user_ip_class_enable(np, i, 0);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int tcam_flush_all(struct niu *np)
+{
+ unsigned long i;
+
+ for (i = 0; i < np->parent->tcam_num_entries; i++) {
+ int err = tcam_flush(np, i);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static u64 hash_addr_regval(unsigned long index, unsigned long num_entries)
+{
+ return ((u64)index | (num_entries == 1 ?
+ HASH_TBL_ADDR_AUTOINC : 0));
+}
+
+#if 0
+static int hash_read(struct niu *np, unsigned long partition,
+ unsigned long index, unsigned long num_entries,
+ u64 *data)
+{
+ u64 val = hash_addr_regval(index, num_entries);
+ unsigned long i;
+
+ if (partition >= FCRAM_NUM_PARTITIONS ||
+ index + num_entries > FCRAM_SIZE)
+ return -EINVAL;
+
+ nw64(HASH_TBL_ADDR(partition), val);
+ for (i = 0; i < num_entries; i++)
+ data[i] = nr64(HASH_TBL_DATA(partition));
+
+ return 0;
+}
+#endif
+
+static int hash_write(struct niu *np, unsigned long partition,
+ unsigned long index, unsigned long num_entries,
+ u64 *data)
+{
+ u64 val = hash_addr_regval(index, num_entries);
+ unsigned long i;
+
+ if (partition >= FCRAM_NUM_PARTITIONS ||
+ index + (num_entries * 8) > FCRAM_SIZE)
+ return -EINVAL;
+
+ nw64(HASH_TBL_ADDR(partition), val);
+ for (i = 0; i < num_entries; i++)
+ nw64(HASH_TBL_DATA(partition), data[i]);
+
+ return 0;
+}
+
+static void fflp_reset(struct niu *np)
+{
+ u64 val;
+
+ nw64(FFLP_CFG_1, FFLP_CFG_1_PIO_FIO_RST);
+ udelay(10);
+ nw64(FFLP_CFG_1, 0);
+
+ val = FFLP_CFG_1_FCRAMOUTDR_NORMAL | FFLP_CFG_1_FFLPINITDONE;
+ nw64(FFLP_CFG_1, val);
+}
+
+static void fflp_set_timings(struct niu *np)
+{
+ u64 val = nr64(FFLP_CFG_1);
+
+ val &= ~FFLP_CFG_1_FFLPINITDONE;
+ val |= (DEFAULT_FCRAMRATIO << FFLP_CFG_1_FCRAMRATIO_SHIFT);
+ nw64(FFLP_CFG_1, val);
+
+ val = nr64(FFLP_CFG_1);
+ val |= FFLP_CFG_1_FFLPINITDONE;
+ nw64(FFLP_CFG_1, val);
+
+ val = nr64(FCRAM_REF_TMR);
+ val &= ~(FCRAM_REF_TMR_MAX | FCRAM_REF_TMR_MIN);
+ val |= (DEFAULT_FCRAM_REFRESH_MAX << FCRAM_REF_TMR_MAX_SHIFT);
+ val |= (DEFAULT_FCRAM_REFRESH_MIN << FCRAM_REF_TMR_MIN_SHIFT);
+ nw64(FCRAM_REF_TMR, val);
+}
+
+static int fflp_set_partition(struct niu *np, u64 partition,
+ u64 mask, u64 base, int enable)
+{
+ unsigned long reg;
+ u64 val;
+
+ if (partition >= FCRAM_NUM_PARTITIONS ||
+ (mask & ~(u64)0x1f) != 0 ||
+ (base & ~(u64)0x1f) != 0)
+ return -EINVAL;
+
+ reg = FLW_PRT_SEL(partition);
+
+ val = nr64(reg);
+ val &= ~(FLW_PRT_SEL_EXT | FLW_PRT_SEL_MASK | FLW_PRT_SEL_BASE);
+ val |= (mask << FLW_PRT_SEL_MASK_SHIFT);
+ val |= (base << FLW_PRT_SEL_BASE_SHIFT);
+ if (enable)
+ val |= FLW_PRT_SEL_EXT;
+ nw64(reg, val);
+
+ return 0;
+}
+
+static int fflp_disable_all_partitions(struct niu *np)
+{
+ unsigned long i;
+
+ for (i = 0; i < FCRAM_NUM_PARTITIONS; i++) {
+ int err = fflp_set_partition(np, 0, 0, 0, 0);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static void fflp_llcsnap_enable(struct niu *np, int on)
+{
+ u64 val = nr64(FFLP_CFG_1);
+
+ if (on)
+ val |= FFLP_CFG_1_LLCSNAP;
+ else
+ val &= ~FFLP_CFG_1_LLCSNAP;
+ nw64(FFLP_CFG_1, val);
+}
+
+static void fflp_errors_enable(struct niu *np, int on)
+{
+ u64 val = nr64(FFLP_CFG_1);
+
+ if (on)
+ val &= ~FFLP_CFG_1_ERRORDIS;
+ else
+ val |= FFLP_CFG_1_ERRORDIS;
+ nw64(FFLP_CFG_1, val);
+}
+
+static int fflp_hash_clear(struct niu *np)
+{
+ struct fcram_hash_ipv4 ent;
+ unsigned long i;
+
+ /* IPV4 hash entry with valid bit clear, rest is don't care. */
+ memset(&ent, 0, sizeof(ent));
+ ent.header = HASH_HEADER_EXT;
+
+ for (i = 0; i < FCRAM_SIZE; i += sizeof(ent)) {
+ int err = hash_write(np, 0, i, 1, (u64 *) &ent);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int fflp_early_init(struct niu *np)
+{
+ struct niu_parent *parent;
+ unsigned long flags;
+ int err;
+
+ niu_lock_parent(np, flags);
+
+ parent = np->parent;
+ err = 0;
+ if (!(parent->flags & PARENT_FLGS_CLS_HWINIT)) {
+ niudbg(PROBE, "fflp_early_init: Initting hw on port %u\n",
+ np->port);
+ if (np->parent->plat_type != PLAT_TYPE_NIU) {
+ fflp_reset(np);
+ fflp_set_timings(np);
+ err = fflp_disable_all_partitions(np);
+ if (err) {
+ niudbg(PROBE, "fflp_disable_all_partitions "
+ "failed, err=%d\n", err);
+ goto out;
+ }
+ }
+
+ err = tcam_early_init(np);
+ if (err) {
+ niudbg(PROBE, "tcam_early_init failed, err=%d\n",
+ err);
+ goto out;
+ }
+ fflp_llcsnap_enable(np, 1);
+ fflp_errors_enable(np, 0);
+ nw64(H1POLY, 0);
+ nw64(H2POLY, 0);
+
+ err = tcam_flush_all(np);
+ if (err) {
+ niudbg(PROBE, "tcam_flush_all failed, err=%d\n",
+ err);
+ goto out;
+ }
+ if (np->parent->plat_type != PLAT_TYPE_NIU) {
+ err = fflp_hash_clear(np);
+ if (err) {
+ niudbg(PROBE, "fflp_hash_clear failed, "
+ "err=%d\n", err);
+ goto out;
+ }
+ }
+
+ vlan_tbl_clear(np);
+
+ niudbg(PROBE, "fflp_early_init: Success\n");
+ parent->flags |= PARENT_FLGS_CLS_HWINIT;
+ }
+out:
+ niu_unlock_parent(np, flags);
+ return err;
+}
+
+static int niu_set_flow_key(struct niu *np, unsigned long class_code, u64 key)
+{
+ if (class_code < CLASS_CODE_USER_PROG1 ||
+ class_code > CLASS_CODE_SCTP_IPV6)
+ return -EINVAL;
+
+ nw64(FLOW_KEY(class_code - CLASS_CODE_USER_PROG1), key);
+ return 0;
+}
+
+static int niu_set_tcam_key(struct niu *np, unsigned long class_code, u64 key)
+{
+ if (class_code < CLASS_CODE_USER_PROG1 ||
+ class_code > CLASS_CODE_SCTP_IPV6)
+ return -EINVAL;
+
+ nw64(TCAM_KEY(class_code - CLASS_CODE_USER_PROG1), key);
+ return 0;
+}
+
+static void niu_rx_skb_append(struct sk_buff *skb, struct page *page,
+ u32 offset, u32 size)
+{
+ int i = skb_shinfo(skb)->nr_frags;
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ frag->page = page;
+ frag->page_offset = offset;
+ frag->size = size;
+
+ skb->len += size;
+ skb->data_len += size;
+ skb->truesize += size;
+
+ skb_shinfo(skb)->nr_frags = i + 1;
+}
+
+static unsigned int niu_hash_rxaddr(struct rx_ring_info *rp, u64 a)
+{
+ a >>= PAGE_SHIFT;
+ a ^= (a >> ilog2(MAX_RBR_RING_SIZE));
+
+ return (a & (MAX_RBR_RING_SIZE - 1));
+}
+
+static struct page *niu_find_rxpage(struct rx_ring_info *rp, u64 addr,
+ struct page ***link)
+{
+ unsigned int h = niu_hash_rxaddr(rp, addr);
+ struct page *p, **pp;
+
+ addr &= PAGE_MASK;
+ pp = &rp->rxhash[h];
+ for (; (p = *pp) != NULL; pp = (struct page **) &p->mapping) {
+ if (p->index == addr) {
+ *link = pp;
+ break;
+ }
+ }
+
+ return p;
+}
+
+static void niu_hash_page(struct rx_ring_info *rp, struct page *page, u64 base)
+{
+ unsigned int h = niu_hash_rxaddr(rp, base);
+
+ page->index = base;
+ page->mapping = (struct address_space *) rp->rxhash[h];
+ rp->rxhash[h] = page;
+}
+
+static int niu_rbr_add_page(struct niu *np, struct rx_ring_info *rp,
+ gfp_t mask, int start_index)
+{
+ struct page *page;
+ u64 addr;
+ int i;
+
+ page = alloc_page(mask);
+ if (!page)
+ return -ENOMEM;
+
+ addr = np->ops->map_page(np->device, page, 0,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+
+ niu_hash_page(rp, page, addr);
+ if (rp->rbr_blocks_per_page > 1)
+ atomic_add(rp->rbr_blocks_per_page - 1,
+ &compound_head(page)->_count);
+
+ for (i = 0; i < rp->rbr_blocks_per_page; i++) {
+ __le32 *rbr = &rp->rbr[start_index + i];
+
+ *rbr = cpu_to_le32(addr >> RBR_DESCR_ADDR_SHIFT);
+ addr += rp->rbr_block_size;
+ }
+
+ return 0;
+}
+
+static void niu_rbr_refill(struct niu *np, struct rx_ring_info *rp, gfp_t mask)
+{
+ int index = rp->rbr_index;
+
+ rp->rbr_pending++;
+ if ((rp->rbr_pending % rp->rbr_blocks_per_page) == 0) {
+ int err = niu_rbr_add_page(np, rp, mask, index);
+
+ if (unlikely(err)) {
+ rp->rbr_pending--;
+ return;
+ }
+
+ rp->rbr_index += rp->rbr_blocks_per_page;
+ BUG_ON(rp->rbr_index > rp->rbr_table_size);
+ if (rp->rbr_index == rp->rbr_table_size)
+ rp->rbr_index = 0;
+
+ if (rp->rbr_pending >= rp->rbr_kick_thresh) {
+ nw64(RBR_KICK(rp->rx_channel), rp->rbr_pending);
+ rp->rbr_pending = 0;
+ }
+ }
+}
+
+static int niu_rx_pkt_ignore(struct niu *np, struct rx_ring_info *rp)
+{
+ unsigned int index = rp->rcr_index;
+ int num_rcr = 0;
+
+ rp->rx_dropped++;
+ while (1) {
+ struct page *page, **link;
+ u64 addr, val;
+ u32 rcr_size;
+
+ num_rcr++;
+
+ val = le64_to_cpup(&rp->rcr[index]);
+ addr = (val & RCR_ENTRY_PKT_BUF_ADDR) <<
+ RCR_ENTRY_PKT_BUF_ADDR_SHIFT;
+ page = niu_find_rxpage(rp, addr, &link);
+
+ rcr_size = rp->rbr_sizes[(val & RCR_ENTRY_PKTBUFSZ) >>
+ RCR_ENTRY_PKTBUFSZ_SHIFT];
+ if ((page->index + PAGE_SIZE) - rcr_size == addr) {
+ *link = (struct page *) page->mapping;
+ np->ops->unmap_page(np->device, page->index,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ page->index = 0;
+ page->mapping = NULL;
+ __free_page(page);
+ rp->rbr_refill_pending++;
+ }
+
+ index = NEXT_RCR(rp, index);
+ if (!(val & RCR_ENTRY_MULTI))
+ break;
+
+ }
+ rp->rcr_index = index;
+
+ return num_rcr;
+}
+
+static int niu_process_rx_pkt(struct niu *np, struct rx_ring_info *rp)
+{
+ unsigned int index = rp->rcr_index;
+ struct sk_buff *skb;
+ int len, num_rcr;
+
+ skb = netdev_alloc_skb(np->dev, RX_SKB_ALLOC_SIZE);
+ if (unlikely(!skb))
+ return niu_rx_pkt_ignore(np, rp);
+
+ num_rcr = 0;
+ while (1) {
+ struct page *page, **link;
+ u32 rcr_size, append_size;
+ u64 addr, val, off;
+
+ num_rcr++;
+
+ val = le64_to_cpup(&rp->rcr[index]);
+
+ len = (val & RCR_ENTRY_L2_LEN) >>
+ RCR_ENTRY_L2_LEN_SHIFT;
+ len -= ETH_FCS_LEN;
+
+ addr = (val & RCR_ENTRY_PKT_BUF_ADDR) <<
+ RCR_ENTRY_PKT_BUF_ADDR_SHIFT;
+ page = niu_find_rxpage(rp, addr, &link);
+
+ rcr_size = rp->rbr_sizes[(val & RCR_ENTRY_PKTBUFSZ) >>
+ RCR_ENTRY_PKTBUFSZ_SHIFT];
+
+ off = addr & ~PAGE_MASK;
+ append_size = rcr_size;
+ if (num_rcr == 1) {
+ int ptype;
+
+ off += 2;
+ append_size -= 2;
+
+ ptype = (val >> RCR_ENTRY_PKT_TYPE_SHIFT);
+ if ((ptype == RCR_PKT_TYPE_TCP ||
+ ptype == RCR_PKT_TYPE_UDP) &&
+ !(val & (RCR_ENTRY_NOPORT |
+ RCR_ENTRY_ERROR)))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+ if (!(val & RCR_ENTRY_MULTI))
+ append_size = len - skb->len;
+
+ niu_rx_skb_append(skb, page, off, append_size);
+ if ((page->index + rp->rbr_block_size) - rcr_size == addr) {
+ *link = (struct page *) page->mapping;
+ np->ops->unmap_page(np->device, page->index,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ page->index = 0;
+ page->mapping = NULL;
+ rp->rbr_refill_pending++;
+ } else
+ get_page(page);
+
+ index = NEXT_RCR(rp, index);
+ if (!(val & RCR_ENTRY_MULTI))
+ break;
+
+ }
+ rp->rcr_index = index;
+
+ skb_reserve(skb, NET_IP_ALIGN);
+ __pskb_pull_tail(skb, min(len, NIU_RXPULL_MAX));
+
+ rp->rx_packets++;
+ rp->rx_bytes += skb->len;
+
+ skb->protocol = eth_type_trans(skb, np->dev);
+ netif_receive_skb(skb);
+
+ return num_rcr;
+}
+
+static int niu_rbr_fill(struct niu *np, struct rx_ring_info *rp, gfp_t mask)
+{
+ int blocks_per_page = rp->rbr_blocks_per_page;
+ int err, index = rp->rbr_index;
+
+ err = 0;
+ while (index < (rp->rbr_table_size - blocks_per_page)) {
+ err = niu_rbr_add_page(np, rp, mask, index);
+ if (err)
+ break;
+
+ index += blocks_per_page;
+ }
+
+ rp->rbr_index = index;
+ return err;
+}
+
+static void niu_rbr_free(struct niu *np, struct rx_ring_info *rp)
+{
+ int i;
+
+ for (i = 0; i < MAX_RBR_RING_SIZE; i++) {
+ struct page *page;
+
+ page = rp->rxhash[i];
+ while (page) {
+ struct page *next = (struct page *) page->mapping;
+ u64 base = page->index;
+
+ np->ops->unmap_page(np->device, base, PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ page->index = 0;
+ page->mapping = NULL;
+
+ __free_page(page);
+
+ page = next;
+ }
+ }
+
+ for (i = 0; i < rp->rbr_table_size; i++)
+ rp->rbr[i] = cpu_to_le32(0);
+ rp->rbr_index = 0;
+}
+
+static int release_tx_packet(struct niu *np, struct tx_ring_info *rp, int idx)
+{
+ struct tx_buff_info *tb = &rp->tx_buffs[idx];
+ struct sk_buff *skb = tb->skb;
+ struct tx_pkt_hdr *tp;
+ u64 tx_flags;
+ int i, len;
+
+ tp = (struct tx_pkt_hdr *) skb->data;
+ tx_flags = le64_to_cpup(&tp->flags);
+
+ rp->tx_packets++;
+ rp->tx_bytes += (((tx_flags & TXHDR_LEN) >> TXHDR_LEN_SHIFT) -
+ ((tx_flags & TXHDR_PAD) / 2));
+
+ len = skb_headlen(skb);
+ np->ops->unmap_single(np->device, tb->mapping,
+ len, DMA_TO_DEVICE);
+
+ if (le64_to_cpu(rp->descr[idx]) & TX_DESC_MARK)
+ rp->mark_pending--;
+
+ tb->skb = NULL;
+ do {
+ idx = NEXT_TX(rp, idx);
+ len -= MAX_TX_DESC_LEN;
+ } while (len > 0);
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ tb = &rp->tx_buffs[idx];
+ BUG_ON(tb->skb != NULL);
+ np->ops->unmap_page(np->device, tb->mapping,
+ skb_shinfo(skb)->frags[i].size,
+ DMA_TO_DEVICE);
+ idx = NEXT_TX(rp, idx);
+ }
+
+ dev_kfree_skb(skb);
+
+ return idx;
+}
+
+#define NIU_TX_WAKEUP_THRESH(rp) ((rp)->pending / 4)
+
+static void niu_tx_work(struct niu *np, struct tx_ring_info *rp)
+{
+ u16 pkt_cnt, tmp;
+ int cons;
+ u64 cs;
+
+ cs = rp->tx_cs;
+ if (unlikely(!(cs & (TX_CS_MK | TX_CS_MMK))))
+ goto out;
+
+ tmp = pkt_cnt = (cs & TX_CS_PKT_CNT) >> TX_CS_PKT_CNT_SHIFT;
+ pkt_cnt = (pkt_cnt - rp->last_pkt_cnt) &
+ (TX_CS_PKT_CNT >> TX_CS_PKT_CNT_SHIFT);
+
+ rp->last_pkt_cnt = tmp;
+
+ cons = rp->cons;
+
+ niudbg(TX_DONE, "%s: niu_tx_work() pkt_cnt[%u] cons[%d]\n",
+ np->dev->name, pkt_cnt, cons);
+
+ while (pkt_cnt--)
+ cons = release_tx_packet(np, rp, cons);
+
+ rp->cons = cons;
+ smp_mb();
+
+out:
+ if (unlikely(netif_queue_stopped(np->dev) &&
+ (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))) {
+ netif_tx_lock(np->dev);
+ if (netif_queue_stopped(np->dev) &&
+ (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))
+ netif_wake_queue(np->dev);
+ netif_tx_unlock(np->dev);
+ }
+}
+
+static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget)
+{
+ int qlen, rcr_done = 0, work_done = 0;
+ struct rxdma_mailbox *mbox = rp->mbox;
+ u64 stat;
+
+#if 1
+ stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel));
+ qlen = nr64(RCRSTAT_A(rp->rx_channel)) & RCRSTAT_A_QLEN;
+#else
+ stat = le64_to_cpup(&mbox->rx_dma_ctl_stat);
+ qlen = (le64_to_cpup(&mbox->rcrstat_a) & RCRSTAT_A_QLEN);
+#endif
+ mbox->rx_dma_ctl_stat = 0;
+ mbox->rcrstat_a = 0;
+
+ niudbg(RX_STATUS, "%s: niu_rx_work(chan[%d]), stat[%llx] qlen=%d\n",
+ np->dev->name, rp->rx_channel, (unsigned long long) stat, qlen);
+
+ rcr_done = work_done = 0;
+ qlen = min(qlen, budget);
+ while (work_done < qlen) {
+ rcr_done += niu_process_rx_pkt(np, rp);
+ work_done++;
+ }
+
+ if (rp->rbr_refill_pending >= rp->rbr_kick_thresh) {
+ unsigned int i;
+
+ for (i = 0; i < rp->rbr_refill_pending; i++)
+ niu_rbr_refill(np, rp, GFP_ATOMIC);
+ rp->rbr_refill_pending = 0;
+ }
+
+ stat = (RX_DMA_CTL_STAT_MEX |
+ ((u64)work_done << RX_DMA_CTL_STAT_PKTREAD_SHIFT) |
+ ((u64)rcr_done << RX_DMA_CTL_STAT_PTRREAD_SHIFT));
+
+ nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat);
+
+ return work_done;
+}
+
+static int niu_poll_core(struct niu *np, struct niu_ldg *lp, int budget)
+{
+ u64 v0 = lp->v0;
+ u32 tx_vec = (v0 >> 32);
+ u32 rx_vec = (v0 & 0xffffffff);
+ int i, work_done = 0;
+
+ niudbg(INTR, "%s: niu_poll_core() v0[%016llx]\n",
+ np->dev->name, (unsigned long long) v0);
+
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+ if (tx_vec & (1 << rp->tx_channel))
+ niu_tx_work(np, rp);
+ nw64(LD_IM0(LDN_TXDMA(rp->tx_channel)), 0);
+ }
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ if (rx_vec & (1 << rp->rx_channel)) {
+ int this_work_done;
+
+ this_work_done = niu_rx_work(np, rp,
+ budget);
+
+ budget -= this_work_done;
+ work_done += this_work_done;
+ }
+ nw64(LD_IM0(LDN_RXDMA(rp->rx_channel)), 0);
+ }
+
+ return work_done;
+}
+
+static int niu_poll(struct napi_struct *napi, int budget)
+{
+ struct niu_ldg *lp = container_of(napi, struct niu_ldg, napi);
+ struct niu *np = lp->np;
+ int work_done;
+
+ work_done = niu_poll_core(np, lp, budget);
+
+ if (work_done < budget) {
+ netif_rx_complete(np->dev, napi);
+ niu_ldg_rearm(np, lp, 1);
+ }
+ return work_done;
+}
+
+static void niu_log_rxchan_errors(struct niu *np, struct rx_ring_info *rp,
+ u64 stat)
+{
+ dev_err(np->device, PFX "%s: RX channel %u errors ( ",
+ np->dev->name, rp->rx_channel);
+
+ if (stat & RX_DMA_CTL_STAT_RBR_TMOUT)
+ printk("RBR_TMOUT ");
+ if (stat & RX_DMA_CTL_STAT_RSP_CNT_ERR)
+ printk("RSP_CNT ");
+ if (stat & RX_DMA_CTL_STAT_BYTE_EN_BUS)
+ printk("BYTE_EN_BUS ");
+ if (stat & RX_DMA_CTL_STAT_RSP_DAT_ERR)
+ printk("RSP_DAT ");
+ if (stat & RX_DMA_CTL_STAT_RCR_ACK_ERR)
+ printk("RCR_ACK ");
+ if (stat & RX_DMA_CTL_STAT_RCR_SHA_PAR)
+ printk("RCR_SHA_PAR ");
+ if (stat & RX_DMA_CTL_STAT_RBR_PRE_PAR)
+ printk("RBR_PRE_PAR ");
+ if (stat & RX_DMA_CTL_STAT_CONFIG_ERR)
+ printk("CONFIG ");
+ if (stat & RX_DMA_CTL_STAT_RCRINCON)
+ printk("RCRINCON ");
+ if (stat & RX_DMA_CTL_STAT_RCRFULL)
+ printk("RCRFULL ");
+ if (stat & RX_DMA_CTL_STAT_RBRFULL)
+ printk("RBRFULL ");
+ if (stat & RX_DMA_CTL_STAT_RBRLOGPAGE)
+ printk("RBRLOGPAGE ");
+ if (stat & RX_DMA_CTL_STAT_CFIGLOGPAGE)
+ printk("CFIGLOGPAGE ");
+ if (stat & RX_DMA_CTL_STAT_DC_FIFO_ERR)
+ printk("DC_FIDO ");
+
+ printk(")\n");
+}
+
+static int niu_rx_error(struct niu *np, struct rx_ring_info *rp)
+{
+ u64 stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel));
+ int err = 0;
+
+ dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n",
+ np->dev->name, rp->rx_channel, (unsigned long long) stat);
+
+ niu_log_rxchan_errors(np, rp, stat);
+
+ if (stat & (RX_DMA_CTL_STAT_CHAN_FATAL |
+ RX_DMA_CTL_STAT_PORT_FATAL))
+ err = -EINVAL;
+
+ nw64(RX_DMA_CTL_STAT(rp->rx_channel),
+ stat & RX_DMA_CTL_WRITE_CLEAR_ERRS);
+
+ return err;
+}
+
+static void niu_log_txchan_errors(struct niu *np, struct tx_ring_info *rp,
+ u64 cs)
+{
+ dev_err(np->device, PFX "%s: TX channel %u errors ( ",
+ np->dev->name, rp->tx_channel);
+
+ if (cs & TX_CS_MBOX_ERR)
+ printk("MBOX ");
+ if (cs & TX_CS_PKT_SIZE_ERR)
+ printk("PKT_SIZE ");
+ if (cs & TX_CS_TX_RING_OFLOW)
+ printk("TX_RING_OFLOW ");
+ if (cs & TX_CS_PREF_BUF_PAR_ERR)
+ printk("PREF_BUF_PAR ");
+ if (cs & TX_CS_NACK_PREF)
+ printk("NACK_PREF ");
+ if (cs & TX_CS_NACK_PKT_RD)
+ printk("NACK_PKT_RD ");
+ if (cs & TX_CS_CONF_PART_ERR)
+ printk("CONF_PART ");
+ if (cs & TX_CS_PKT_PRT_ERR)
+ printk("PKT_PTR ");
+
+ printk(")\n");
+}
+
+static int niu_tx_error(struct niu *np, struct tx_ring_info *rp)
+{
+ u64 cs, logh, logl;
+
+ cs = nr64(TX_CS(rp->tx_channel));
+ logh = nr64(TX_RNG_ERR_LOGH(rp->tx_channel));
+ logl = nr64(TX_RNG_ERR_LOGL(rp->tx_channel));
+
+ dev_err(np->device, PFX "%s: TX channel %u error, "
+ "cs[%llx] logh[%llx] logl[%llx]\n",
+ np->dev->name, rp->tx_channel,
+ (unsigned long long) cs,
+ (unsigned long long) logh,
+ (unsigned long long) logl);
+
+ niu_log_txchan_errors(np, rp, cs);
+
+ return -ENODEV;
+}
+
+static int niu_mif_interrupt(struct niu *np)
+{
+ u64 mif_status = nr64(MIF_STATUS);
+ int phy_mdint = 0;
+
+ if (np->flags & NIU_FLAGS_XMAC) {
+ u64 xrxmac_stat = nr64_mac(XRXMAC_STATUS);
+
+ if (xrxmac_stat & XRXMAC_STATUS_PHY_MDINT)
+ phy_mdint = 1;
+ }
+
+ dev_err(np->device, PFX "%s: MIF interrupt, "
+ "stat[%llx] phy_mdint(%d)\n",
+ np->dev->name, (unsigned long long) mif_status, phy_mdint);
+
+ return -ENODEV;
+}
+
+static void niu_xmac_interrupt(struct niu *np)
+{
+ struct niu_xmac_stats *mp = &np->mac_stats.xmac;
+ u64 val;
+
+ val = nr64_mac(XTXMAC_STATUS);
+ if (val & XTXMAC_STATUS_FRAME_CNT_EXP)
+ mp->tx_frames += TXMAC_FRM_CNT_COUNT;
+ if (val & XTXMAC_STATUS_BYTE_CNT_EXP)
+ mp->tx_bytes += TXMAC_BYTE_CNT_COUNT;
+ if (val & XTXMAC_STATUS_TXFIFO_XFR_ERR)
+ mp->tx_fifo_errors++;
+ if (val & XTXMAC_STATUS_TXMAC_OFLOW)
+ mp->tx_overflow_errors++;
+ if (val & XTXMAC_STATUS_MAX_PSIZE_ERR)
+ mp->tx_max_pkt_size_errors++;
+ if (val & XTXMAC_STATUS_TXMAC_UFLOW)
+ mp->tx_underflow_errors++;
+
+ val = nr64_mac(XRXMAC_STATUS);
+ if (val & XRXMAC_STATUS_LCL_FLT_STATUS)
+ mp->rx_local_faults++;
+ if (val & XRXMAC_STATUS_RFLT_DET)
+ mp->rx_remote_faults++;
+ if (val & XRXMAC_STATUS_LFLT_CNT_EXP)
+ mp->rx_link_faults += LINK_FAULT_CNT_COUNT;
+ if (val & XRXMAC_STATUS_ALIGNERR_CNT_EXP)
+ mp->rx_align_errors += RXMAC_ALIGN_ERR_CNT_COUNT;
+ if (val & XRXMAC_STATUS_RXFRAG_CNT_EXP)
+ mp->rx_frags += RXMAC_FRAG_CNT_COUNT;
+ if (val & XRXMAC_STATUS_RXMULTF_CNT_EXP)
+ mp->rx_mcasts += RXMAC_MC_FRM_CNT_COUNT;
+ if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP)
+ mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT;
+ if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP)
+ mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST1_CNT_EXP)
+ mp->rx_hist_cnt1 += RXMAC_HIST_CNT1_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST2_CNT_EXP)
+ mp->rx_hist_cnt2 += RXMAC_HIST_CNT2_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST3_CNT_EXP)
+ mp->rx_hist_cnt3 += RXMAC_HIST_CNT3_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST4_CNT_EXP)
+ mp->rx_hist_cnt4 += RXMAC_HIST_CNT4_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST5_CNT_EXP)
+ mp->rx_hist_cnt5 += RXMAC_HIST_CNT5_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST6_CNT_EXP)
+ mp->rx_hist_cnt6 += RXMAC_HIST_CNT6_COUNT;
+ if (val & XRXMAC_STATUS_RXHIST7_CNT_EXP)
+ mp->rx_hist_cnt7 += RXMAC_HIST_CNT7_COUNT;
+ if (val & XRXMAC_STAT_MSK_RXOCTET_CNT_EXP)
+ mp->rx_octets += RXMAC_BT_CNT_COUNT;
+ if (val & XRXMAC_STATUS_CVIOLERR_CNT_EXP)
+ mp->rx_code_violations += RXMAC_CD_VIO_CNT_COUNT;
+ if (val & XRXMAC_STATUS_LENERR_CNT_EXP)
+ mp->rx_len_errors += RXMAC_MPSZER_CNT_COUNT;
+ if (val & XRXMAC_STATUS_CRCERR_CNT_EXP)
+ mp->rx_crc_errors += RXMAC_CRC_ER_CNT_COUNT;
+ if (val & XRXMAC_STATUS_RXUFLOW)
+ mp->rx_underflows++;
+ if (val & XRXMAC_STATUS_RXOFLOW)
+ mp->rx_overflows++;
+
+ val = nr64_mac(XMAC_FC_STAT);
+ if (val & XMAC_FC_STAT_TX_MAC_NPAUSE)
+ mp->pause_off_state++;
+ if (val & XMAC_FC_STAT_TX_MAC_PAUSE)
+ mp->pause_on_state++;
+ if (val & XMAC_FC_STAT_RX_MAC_RPAUSE)
+ mp->pause_received++;
+}
+
+static void niu_bmac_interrupt(struct niu *np)
+{
+ struct niu_bmac_stats *mp = &np->mac_stats.bmac;
+ u64 val;
+
+ val = nr64_mac(BTXMAC_STATUS);
+ if (val & BTXMAC_STATUS_UNDERRUN)
+ mp->tx_underflow_errors++;
+ if (val & BTXMAC_STATUS_MAX_PKT_ERR)
+ mp->tx_max_pkt_size_errors++;
+ if (val & BTXMAC_STATUS_BYTE_CNT_EXP)
+ mp->tx_bytes += BTXMAC_BYTE_CNT_COUNT;
+ if (val & BTXMAC_STATUS_FRAME_CNT_EXP)
+ mp->tx_frames += BTXMAC_FRM_CNT_COUNT;
+
+ val = nr64_mac(BRXMAC_STATUS);
+ if (val & BRXMAC_STATUS_OVERFLOW)
+ mp->rx_overflows++;
+ if (val & BRXMAC_STATUS_FRAME_CNT_EXP)
+ mp->rx_frames += BRXMAC_FRAME_CNT_COUNT;
+ if (val & BRXMAC_STATUS_ALIGN_ERR_EXP)
+ mp->rx_align_errors += BRXMAC_ALIGN_ERR_CNT_COUNT;
+ if (val & BRXMAC_STATUS_CRC_ERR_EXP)
+ mp->rx_crc_errors += BRXMAC_ALIGN_ERR_CNT_COUNT;
+ if (val & BRXMAC_STATUS_LEN_ERR_EXP)
+ mp->rx_len_errors += BRXMAC_CODE_VIOL_ERR_CNT_COUNT;
+
+ val = nr64_mac(BMAC_CTRL_STATUS);
+ if (val & BMAC_CTRL_STATUS_NOPAUSE)
+ mp->pause_off_state++;
+ if (val & BMAC_CTRL_STATUS_PAUSE)
+ mp->pause_on_state++;
+ if (val & BMAC_CTRL_STATUS_PAUSE_RECV)
+ mp->pause_received++;
+}
+
+static int niu_mac_interrupt(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_xmac_interrupt(np);
+ else
+ niu_bmac_interrupt(np);
+
+ return 0;
+}
+
+static void niu_log_device_error(struct niu *np, u64 stat)
+{
+ dev_err(np->device, PFX "%s: Core device errors ( ",
+ np->dev->name);
+
+ if (stat & SYS_ERR_MASK_META2)
+ printk("META2 ");
+ if (stat & SYS_ERR_MASK_META1)
+ printk("META1 ");
+ if (stat & SYS_ERR_MASK_PEU)
+ printk("PEU ");
+ if (stat & SYS_ERR_MASK_TXC)
+ printk("TXC ");
+ if (stat & SYS_ERR_MASK_RDMC)
+ printk("RDMC ");
+ if (stat & SYS_ERR_MASK_TDMC)
+ printk("TDMC ");
+ if (stat & SYS_ERR_MASK_ZCP)
+ printk("ZCP ");
+ if (stat & SYS_ERR_MASK_FFLP)
+ printk("FFLP ");
+ if (stat & SYS_ERR_MASK_IPP)
+ printk("IPP ");
+ if (stat & SYS_ERR_MASK_MAC)
+ printk("MAC ");
+ if (stat & SYS_ERR_MASK_SMX)
+ printk("SMX ");
+
+ printk(")\n");
+}
+
+static int niu_device_error(struct niu *np)
+{
+ u64 stat = nr64(SYS_ERR_STAT);
+
+ dev_err(np->device, PFX "%s: Core device error, stat[%llx]\n",
+ np->dev->name, (unsigned long long) stat);
+
+ niu_log_device_error(np, stat);
+
+ return -ENODEV;
+}
+
+static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp)
+{
+ u64 v0 = lp->v0;
+ u64 v1 = lp->v1;
+ u64 v2 = lp->v2;
+ int i, err = 0;
+
+ if (v1 & 0x00000000ffffffffULL) {
+ u32 rx_vec = (v1 & 0xffffffff);
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ if (rx_vec & (1 << rp->rx_channel)) {
+ int r = niu_rx_error(np, rp);
+ if (r)
+ err = r;
+ }
+ }
+ }
+ if (v1 & 0x7fffffff00000000ULL) {
+ u32 tx_vec = (v1 >> 32) & 0x7fffffff;
+
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ if (tx_vec & (1 << rp->tx_channel)) {
+ int r = niu_tx_error(np, rp);
+ if (r)
+ err = r;
+ }
+ }
+ }
+ if ((v0 | v1) & 0x8000000000000000ULL) {
+ int r = niu_mif_interrupt(np);
+ if (r)
+ err = r;
+ }
+ if (v2) {
+ if (v2 & 0x01ef) {
+ int r = niu_mac_interrupt(np);
+ if (r)
+ err = r;
+ }
+ if (v2 & 0x0210) {
+ int r = niu_device_error(np);
+ if (r)
+ err = r;
+ }
+ }
+
+ if (err)
+ niu_enable_interrupts(np, 0);
+
+ return -EINVAL;
+}
+
+static void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp,
+ int ldn)
+{
+ struct rxdma_mailbox *mbox = rp->mbox;
+ u64 stat_write, stat = le64_to_cpup(&mbox->rx_dma_ctl_stat);
+
+ stat_write = (RX_DMA_CTL_STAT_RCRTHRES |
+ RX_DMA_CTL_STAT_RCRTO);
+ nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat_write);
+
+ niudbg(INTR, "%s: rxchan_intr stat[%llx]\n",
+ np->dev->name, (unsigned long long) stat);
+}
+
+static void niu_txchan_intr(struct niu *np, struct tx_ring_info *rp,
+ int ldn)
+{
+ rp->tx_cs = nr64(TX_CS(rp->tx_channel));
+
+ niudbg(INTR, "%s: txchan_intr cs[%llx]\n",
+ np->dev->name, (unsigned long long) rp->tx_cs);
+}
+
+static void __niu_fastpath_interrupt(struct niu *np, int ldg, u64 v0)
+{
+ struct niu_parent *parent = np->parent;
+ u32 rx_vec, tx_vec;
+ int i;
+
+ tx_vec = (v0 >> 32);
+ rx_vec = (v0 & 0xffffffff);
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+ int ldn = LDN_RXDMA(rp->rx_channel);
+
+ if (parent->ldg_map[ldn] != ldg)
+ continue;
+
+ nw64(LD_IM0(ldn), LD_IM0_MASK);
+ if (rx_vec & (1 << rp->rx_channel))
+ niu_rxchan_intr(np, rp, ldn);
+ }
+
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+ int ldn = LDN_TXDMA(rp->tx_channel);
+
+ if (parent->ldg_map[ldn] != ldg)
+ continue;
+
+ nw64(LD_IM0(ldn), LD_IM0_MASK);
+ if (tx_vec & (1 << rp->tx_channel))
+ niu_txchan_intr(np, rp, ldn);
+ }
+}
+
+static void niu_schedule_napi(struct niu *np, struct niu_ldg *lp,
+ u64 v0, u64 v1, u64 v2)
+{
+ if (likely(netif_rx_schedule_prep(np->dev, &lp->napi))) {
+ lp->v0 = v0;
+ lp->v1 = v1;
+ lp->v2 = v2;
+ __niu_fastpath_interrupt(np, lp->ldg_num, v0);
+ __netif_rx_schedule(np->dev, &lp->napi);
+ }
+}
+
+static irqreturn_t niu_interrupt(int irq, void *dev_id)
+{
+ struct niu_ldg *lp = dev_id;
+ struct niu *np = lp->np;
+ int ldg = lp->ldg_num;
+ unsigned long flags;
+ u64 v0, v1, v2;
+
+ if (netif_msg_intr(np))
+ printk(KERN_DEBUG PFX "niu_interrupt() ldg[%p](%d) ",
+ lp, ldg);
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ v0 = nr64(LDSV0(ldg));
+ v1 = nr64(LDSV1(ldg));
+ v2 = nr64(LDSV2(ldg));
+
+ if (netif_msg_intr(np))
+ printk("v0[%llx] v1[%llx] v2[%llx]\n",
+ (unsigned long long) v0,
+ (unsigned long long) v1,
+ (unsigned long long) v2);
+
+ if (unlikely(!v0 && !v1 && !v2)) {
+ spin_unlock_irqrestore(&np->lock, flags);
+ return IRQ_NONE;
+ }
+
+ if (unlikely((v0 & ((u64)1 << LDN_MIF)) || v1 || v2)) {
+ int err = niu_slowpath_interrupt(np, lp);
+ if (err)
+ goto out;
+ }
+ if (likely(v0 & ~((u64)1 << LDN_MIF)))
+ niu_schedule_napi(np, lp, v0, v1, v2);
+ else
+ niu_ldg_rearm(np, lp, 1);
+out:
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static void niu_free_rx_ring_info(struct niu *np, struct rx_ring_info *rp)
+{
+ if (rp->mbox) {
+ np->ops->free_coherent(np->device,
+ sizeof(struct rxdma_mailbox),
+ rp->mbox, rp->mbox_dma);
+ rp->mbox = NULL;
+ }
+ if (rp->rcr) {
+ np->ops->free_coherent(np->device,
+ MAX_RCR_RING_SIZE * sizeof(__le64),
+ rp->rcr, rp->rcr_dma);
+ rp->rcr = NULL;
+ rp->rcr_table_size = 0;
+ rp->rcr_index = 0;
+ }
+ if (rp->rbr) {
+ niu_rbr_free(np, rp);
+
+ np->ops->free_coherent(np->device,
+ MAX_RBR_RING_SIZE * sizeof(__le32),
+ rp->rbr, rp->rbr_dma);
+ rp->rbr = NULL;
+ rp->rbr_table_size = 0;
+ rp->rbr_index = 0;
+ }
+ kfree(rp->rxhash);
+ rp->rxhash = NULL;
+}
+
+static void niu_free_tx_ring_info(struct niu *np, struct tx_ring_info *rp)
+{
+ if (rp->mbox) {
+ np->ops->free_coherent(np->device,
+ sizeof(struct txdma_mailbox),
+ rp->mbox, rp->mbox_dma);
+ rp->mbox = NULL;
+ }
+ if (rp->descr) {
+ int i;
+
+ for (i = 0; i < MAX_TX_RING_SIZE; i++) {
+ if (rp->tx_buffs[i].skb)
+ (void) release_tx_packet(np, rp, i);
+ }
+
+ np->ops->free_coherent(np->device,
+ MAX_TX_RING_SIZE * sizeof(__le64),
+ rp->descr, rp->descr_dma);
+ rp->descr = NULL;
+ rp->pending = 0;
+ rp->prod = 0;
+ rp->cons = 0;
+ rp->wrap_bit = 0;
+ }
+}
+
+static void niu_free_channels(struct niu *np)
+{
+ int i;
+
+ if (np->rx_rings) {
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ niu_free_rx_ring_info(np, rp);
+ }
+ kfree(np->rx_rings);
+ np->rx_rings = NULL;
+ np->num_rx_rings = 0;
+ }
+
+ if (np->tx_rings) {
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ niu_free_tx_ring_info(np, rp);
+ }
+ kfree(np->tx_rings);
+ np->tx_rings = NULL;
+ np->num_tx_rings = 0;
+ }
+}
+
+static int niu_alloc_rx_ring_info(struct niu *np,
+ struct rx_ring_info *rp)
+{
+ BUILD_BUG_ON(sizeof(struct rxdma_mailbox) != 64);
+
+ rp->rxhash = kzalloc(MAX_RBR_RING_SIZE * sizeof(struct page *),
+ GFP_KERNEL);
+ if (!rp->rxhash)
+ return -ENOMEM;
+
+ rp->mbox = np->ops->alloc_coherent(np->device,
+ sizeof(struct rxdma_mailbox),
+ &rp->mbox_dma, GFP_KERNEL);
+ if (!rp->mbox)
+ return -ENOMEM;
+ if ((unsigned long)rp->mbox & (64UL - 1)) {
+ dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+ "RXDMA mailbox %p\n", np->dev->name, rp->mbox);
+ return -EINVAL;
+ }
+
+ rp->rcr = np->ops->alloc_coherent(np->device,
+ MAX_RCR_RING_SIZE * sizeof(__le64),
+ &rp->rcr_dma, GFP_KERNEL);
+ if (!rp->rcr)
+ return -ENOMEM;
+ if ((unsigned long)rp->rcr & (64UL - 1)) {
+ dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+ "RXDMA RCR table %p\n", np->dev->name, rp->rcr);
+ return -EINVAL;
+ }
+ rp->rcr_table_size = MAX_RCR_RING_SIZE;
+ rp->rcr_index = 0;
+
+ rp->rbr = np->ops->alloc_coherent(np->device,
+ MAX_RBR_RING_SIZE * sizeof(__le32),
+ &rp->rbr_dma, GFP_KERNEL);
+ if (!rp->rbr)
+ return -ENOMEM;
+ if ((unsigned long)rp->rbr & (64UL - 1)) {
+ dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+ "RXDMA RBR table %p\n", np->dev->name, rp->rbr);
+ return -EINVAL;
+ }
+ rp->rbr_table_size = MAX_RBR_RING_SIZE;
+ rp->rbr_index = 0;
+ rp->rbr_pending = 0;
+
+ return 0;
+}
+
+static void niu_set_max_burst(struct niu *np, struct tx_ring_info *rp)
+{
+ int mtu = np->dev->mtu;
+
+ /* These values are recommended by the HW designers for fair
+ * utilization of DRR amongst the rings.
+ */
+ rp->max_burst = mtu + 32;
+ if (rp->max_burst > 4096)
+ rp->max_burst = 4096;
+}
+
+static int niu_alloc_tx_ring_info(struct niu *np,
+ struct tx_ring_info *rp)
+{
+ BUILD_BUG_ON(sizeof(struct txdma_mailbox) != 64);
+
+ rp->mbox = np->ops->alloc_coherent(np->device,
+ sizeof(struct txdma_mailbox),
+ &rp->mbox_dma, GFP_KERNEL);
+ if (!rp->mbox)
+ return -ENOMEM;
+ if ((unsigned long)rp->mbox & (64UL - 1)) {
+ dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+ "TXDMA mailbox %p\n", np->dev->name, rp->mbox);
+ return -EINVAL;
+ }
+
+ rp->descr = np->ops->alloc_coherent(np->device,
+ MAX_TX_RING_SIZE * sizeof(__le64),
+ &rp->descr_dma, GFP_KERNEL);
+ if (!rp->descr)
+ return -ENOMEM;
+ if ((unsigned long)rp->descr & (64UL - 1)) {
+ dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+ "TXDMA descr table %p\n", np->dev->name, rp->descr);
+ return -EINVAL;
+ }
+
+ rp->pending = MAX_TX_RING_SIZE;
+ rp->prod = 0;
+ rp->cons = 0;
+ rp->wrap_bit = 0;
+
+ /* XXX make these configurable... XXX */
+ rp->mark_freq = rp->pending / 4;
+
+ niu_set_max_burst(np, rp);
+
+ return 0;
+}
+
+static void niu_size_rbr(struct niu *np, struct rx_ring_info *rp)
+{
+ u16 bss;
+
+ bss = min(PAGE_SHIFT, 15);
+
+ rp->rbr_block_size = 1 << bss;
+ rp->rbr_blocks_per_page = 1 << (PAGE_SHIFT-bss);
+
+ rp->rbr_sizes[0] = 256;
+ rp->rbr_sizes[1] = 1024;
+ if (np->dev->mtu > ETH_DATA_LEN) {
+ switch (PAGE_SIZE) {
+ case 4 * 1024:
+ rp->rbr_sizes[2] = 4096;
+ break;
+
+ default:
+ rp->rbr_sizes[2] = 8192;
+ break;
+ }
+ } else {
+ rp->rbr_sizes[2] = 2048;
+ }
+ rp->rbr_sizes[3] = rp->rbr_block_size;
+}
+
+static int niu_alloc_channels(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ int first_rx_channel, first_tx_channel;
+ int i, port, err;
+
+ port = np->port;
+ first_rx_channel = first_tx_channel = 0;
+ for (i = 0; i < port; i++) {
+ first_rx_channel += parent->rxchan_per_port[i];
+ first_tx_channel += parent->txchan_per_port[i];
+ }
+
+ np->num_rx_rings = parent->rxchan_per_port[port];
+ np->num_tx_rings = parent->txchan_per_port[port];
+
+ np->rx_rings = kzalloc(np->num_rx_rings * sizeof(struct rx_ring_info),
+ GFP_KERNEL);
+ err = -ENOMEM;
+ if (!np->rx_rings)
+ goto out_err;
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ rp->np = np;
+ rp->rx_channel = first_rx_channel + i;
+
+ err = niu_alloc_rx_ring_info(np, rp);
+ if (err)
+ goto out_err;
+
+ niu_size_rbr(np, rp);
+
+ /* XXX better defaults, configurable, etc... XXX */
+ rp->nonsyn_window = 64;
+ rp->nonsyn_threshold = rp->rcr_table_size - 64;
+ rp->syn_window = 64;
+ rp->syn_threshold = rp->rcr_table_size - 64;
+ rp->rcr_pkt_threshold = 16;
+ rp->rcr_timeout = 8;
+ rp->rbr_kick_thresh = RBR_REFILL_MIN;
+ if (rp->rbr_kick_thresh < rp->rbr_blocks_per_page)
+ rp->rbr_kick_thresh = rp->rbr_blocks_per_page;
+
+ err = niu_rbr_fill(np, rp, GFP_KERNEL);
+ if (err)
+ return err;
+ }
+
+ np->tx_rings = kzalloc(np->num_tx_rings * sizeof(struct tx_ring_info),
+ GFP_KERNEL);
+ err = -ENOMEM;
+ if (!np->tx_rings)
+ goto out_err;
+
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ rp->np = np;
+ rp->tx_channel = first_tx_channel + i;
+
+ err = niu_alloc_tx_ring_info(np, rp);
+ if (err)
+ goto out_err;
+ }
+
+ return 0;
+
+out_err:
+ niu_free_channels(np);
+ return err;
+}
+
+static int niu_tx_cs_sng_poll(struct niu *np, int channel)
+{
+ int limit = 1000;
+
+ while (--limit > 0) {
+ u64 val = nr64(TX_CS(channel));
+ if (val & TX_CS_SNG_STATE)
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static int niu_tx_channel_stop(struct niu *np, int channel)
+{
+ u64 val = nr64(TX_CS(channel));
+
+ val |= TX_CS_STOP_N_GO;
+ nw64(TX_CS(channel), val);
+
+ return niu_tx_cs_sng_poll(np, channel);
+}
+
+static int niu_tx_cs_reset_poll(struct niu *np, int channel)
+{
+ int limit = 1000;
+
+ while (--limit > 0) {
+ u64 val = nr64(TX_CS(channel));
+ if (!(val & TX_CS_RST))
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static int niu_tx_channel_reset(struct niu *np, int channel)
+{
+ u64 val = nr64(TX_CS(channel));
+ int err;
+
+ val |= TX_CS_RST;
+ nw64(TX_CS(channel), val);
+
+ err = niu_tx_cs_reset_poll(np, channel);
+ if (!err)
+ nw64(TX_RING_KICK(channel), 0);
+
+ return err;
+}
+
+static int niu_tx_channel_lpage_init(struct niu *np, int channel)
+{
+ u64 val;
+
+ nw64(TX_LOG_MASK1(channel), 0);
+ nw64(TX_LOG_VAL1(channel), 0);
+ nw64(TX_LOG_MASK2(channel), 0);
+ nw64(TX_LOG_VAL2(channel), 0);
+ nw64(TX_LOG_PAGE_RELO1(channel), 0);
+ nw64(TX_LOG_PAGE_RELO2(channel), 0);
+ nw64(TX_LOG_PAGE_HDL(channel), 0);
+
+ val = (u64)np->port << TX_LOG_PAGE_VLD_FUNC_SHIFT;
+ val |= (TX_LOG_PAGE_VLD_PAGE0 | TX_LOG_PAGE_VLD_PAGE1);
+ nw64(TX_LOG_PAGE_VLD(channel), val);
+
+ /* XXX TXDMA 32bit mode? XXX */
+
+ return 0;
+}
+
+static void niu_txc_enable_port(struct niu *np, int on)
+{
+ unsigned long flags;
+ u64 val, mask;
+
+ niu_lock_parent(np, flags);
+ val = nr64(TXC_CONTROL);
+ mask = (u64)1 << np->port;
+ if (on) {
+ val |= TXC_CONTROL_ENABLE | mask;
+ } else {
+ val &= ~mask;
+ if ((val & ~TXC_CONTROL_ENABLE) == 0)
+ val &= ~TXC_CONTROL_ENABLE;
+ }
+ nw64(TXC_CONTROL, val);
+ niu_unlock_parent(np, flags);
+}
+
+static void niu_txc_set_imask(struct niu *np, u64 imask)
+{
+ unsigned long flags;
+ u64 val;
+
+ niu_lock_parent(np, flags);
+ val = nr64(TXC_INT_MASK);
+ val &= ~TXC_INT_MASK_VAL(np->port);
+ val |= (imask << TXC_INT_MASK_VAL_SHIFT(np->port));
+ niu_unlock_parent(np, flags);
+}
+
+static void niu_txc_port_dma_enable(struct niu *np, int on)
+{
+ u64 val = 0;
+
+ if (on) {
+ int i;
+
+ for (i = 0; i < np->num_tx_rings; i++)
+ val |= (1 << np->tx_rings[i].tx_channel);
+ }
+ nw64(TXC_PORT_DMA(np->port), val);
+}
+
+static int niu_init_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
+{
+ int err, channel = rp->tx_channel;
+ u64 val, ring_len;
+
+ err = niu_tx_channel_stop(np, channel);
+ if (err)
+ return err;
+
+ err = niu_tx_channel_reset(np, channel);
+ if (err)
+ return err;
+
+ err = niu_tx_channel_lpage_init(np, channel);
+ if (err)
+ return err;
+
+ nw64(TXC_DMA_MAX(channel), rp->max_burst);
+ nw64(TX_ENT_MSK(channel), 0);
+
+ if (rp->descr_dma & ~(TX_RNG_CFIG_STADDR_BASE |
+ TX_RNG_CFIG_STADDR)) {
+ dev_err(np->device, PFX "%s: TX ring channel %d "
+ "DMA addr (%llx) is not aligned.\n",
+ np->dev->name, channel,
+ (unsigned long long) rp->descr_dma);
+ return -EINVAL;
+ }
+
+ /* The length field in TX_RNG_CFIG is measured in 64-byte
+ * blocks. rp->pending is the number of TX descriptors in
+ * our ring, 8 bytes each, thus we divide by 8 bytes more
+ * to get the proper value the chip wants.
+ */
+ ring_len = (rp->pending / 8);
+
+ val = ((ring_len << TX_RNG_CFIG_LEN_SHIFT) |
+ rp->descr_dma);
+ nw64(TX_RNG_CFIG(channel), val);
+
+ if (((rp->mbox_dma >> 32) & ~TXDMA_MBH_MBADDR) ||
+ ((u32)rp->mbox_dma & ~TXDMA_MBL_MBADDR)) {
+ dev_err(np->device, PFX "%s: TX ring channel %d "
+ "MBOX addr (%llx) is has illegal bits.\n",
+ np->dev->name, channel,
+ (unsigned long long) rp->mbox_dma);
+ return -EINVAL;
+ }
+ nw64(TXDMA_MBH(channel), rp->mbox_dma >> 32);
+ nw64(TXDMA_MBL(channel), rp->mbox_dma & TXDMA_MBL_MBADDR);
+
+ nw64(TX_CS(channel), 0);
+
+ rp->last_pkt_cnt = 0;
+
+ return 0;
+}
+
+static void niu_init_rdc_groups(struct niu *np)
+{
+ struct niu_rdc_tables *tp = &np->parent->rdc_group_cfg[np->port];
+ int i, first_table_num = tp->first_table_num;
+
+ for (i = 0; i < tp->num_tables; i++) {
+ struct rdc_table *tbl = &tp->tables[i];
+ int this_table = first_table_num + i;
+ int slot;
+
+ for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++)
+ nw64(RDC_TBL(this_table, slot),
+ tbl->rxdma_channel[slot]);
+ }
+
+ nw64(DEF_RDC(np->port), np->parent->rdc_default[np->port]);
+}
+
+static void niu_init_drr_weight(struct niu *np)
+{
+ int type = phy_decode(np->parent->port_phy, np->port);
+ u64 val;
+
+ switch (type) {
+ case PORT_TYPE_10G:
+ val = PT_DRR_WEIGHT_DEFAULT_10G;
+ break;
+
+ case PORT_TYPE_1G:
+ default:
+ val = PT_DRR_WEIGHT_DEFAULT_1G;
+ break;
+ }
+ nw64(PT_DRR_WT(np->port), val);
+}
+
+static int niu_init_hostinfo(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port];
+ int i, err, num_alt = niu_num_alt_addr(np);
+ int first_rdc_table = tp->first_table_num;
+
+ err = niu_set_primary_mac_rdc_table(np, first_rdc_table, 1);
+ if (err)
+ return err;
+
+ err = niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1);
+ if (err)
+ return err;
+
+ for (i = 0; i < num_alt; i++) {
+ err = niu_set_alt_mac_rdc_table(np, i, first_rdc_table, 1);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int niu_rx_channel_reset(struct niu *np, int channel)
+{
+ return niu_set_and_wait_clear(np, RXDMA_CFIG1(channel),
+ RXDMA_CFIG1_RST, 1000, 10,
+ "RXDMA_CFIG1");
+}
+
+static int niu_rx_channel_lpage_init(struct niu *np, int channel)
+{
+ u64 val;
+
+ nw64(RX_LOG_MASK1(channel), 0);
+ nw64(RX_LOG_VAL1(channel), 0);
+ nw64(RX_LOG_MASK2(channel), 0);
+ nw64(RX_LOG_VAL2(channel), 0);
+ nw64(RX_LOG_PAGE_RELO1(channel), 0);
+ nw64(RX_LOG_PAGE_RELO2(channel), 0);
+ nw64(RX_LOG_PAGE_HDL(channel), 0);
+
+ val = (u64)np->port << RX_LOG_PAGE_VLD_FUNC_SHIFT;
+ val |= (RX_LOG_PAGE_VLD_PAGE0 | RX_LOG_PAGE_VLD_PAGE1);
+ nw64(RX_LOG_PAGE_VLD(channel), val);
+
+ return 0;
+}
+
+static void niu_rx_channel_wred_init(struct niu *np, struct rx_ring_info *rp)
+{
+ u64 val;
+
+ val = (((u64)rp->nonsyn_window << RDC_RED_PARA_WIN_SHIFT) |
+ ((u64)rp->nonsyn_threshold << RDC_RED_PARA_THRE_SHIFT) |
+ ((u64)rp->syn_window << RDC_RED_PARA_WIN_SYN_SHIFT) |
+ ((u64)rp->syn_threshold << RDC_RED_PARA_THRE_SYN_SHIFT));
+ nw64(RDC_RED_PARA(rp->rx_channel), val);
+}
+
+static int niu_compute_rbr_cfig_b(struct rx_ring_info *rp, u64 *ret)
+{
+ u64 val = 0;
+
+ switch (rp->rbr_block_size) {
+ case 4 * 1024:
+ val |= (RBR_BLKSIZE_4K << RBR_CFIG_B_BLKSIZE_SHIFT);
+ break;
+ case 8 * 1024:
+ val |= (RBR_BLKSIZE_8K << RBR_CFIG_B_BLKSIZE_SHIFT);
+ break;
+ case 16 * 1024:
+ val |= (RBR_BLKSIZE_16K << RBR_CFIG_B_BLKSIZE_SHIFT);
+ break;
+ case 32 * 1024:
+ val |= (RBR_BLKSIZE_32K << RBR_CFIG_B_BLKSIZE_SHIFT);
+ break;
+ default:
+ return -EINVAL;
+ }
+ val |= RBR_CFIG_B_VLD2;
+ switch (rp->rbr_sizes[2]) {
+ case 2 * 1024:
+ val |= (RBR_BUFSZ2_2K << RBR_CFIG_B_BUFSZ2_SHIFT);
+ break;
+ case 4 * 1024:
+ val |= (RBR_BUFSZ2_4K << RBR_CFIG_B_BUFSZ2_SHIFT);
+ break;
+ case 8 * 1024:
+ val |= (RBR_BUFSZ2_8K << RBR_CFIG_B_BUFSZ2_SHIFT);
+ break;
+ case 16 * 1024:
+ val |= (RBR_BUFSZ2_16K << RBR_CFIG_B_BUFSZ2_SHIFT);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ val |= RBR_CFIG_B_VLD1;
+ switch (rp->rbr_sizes[1]) {
+ case 1 * 1024:
+ val |= (RBR_BUFSZ1_1K << RBR_CFIG_B_BUFSZ1_SHIFT);
+ break;
+ case 2 * 1024:
+ val |= (RBR_BUFSZ1_2K << RBR_CFIG_B_BUFSZ1_SHIFT);
+ break;
+ case 4 * 1024:
+ val |= (RBR_BUFSZ1_4K << RBR_CFIG_B_BUFSZ1_SHIFT);
+ break;
+ case 8 * 1024:
+ val |= (RBR_BUFSZ1_8K << RBR_CFIG_B_BUFSZ1_SHIFT);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ val |= RBR_CFIG_B_VLD0;
+ switch (rp->rbr_sizes[0]) {
+ case 256:
+ val |= (RBR_BUFSZ0_256 << RBR_CFIG_B_BUFSZ0_SHIFT);
+ break;
+ case 512:
+ val |= (RBR_BUFSZ0_512 << RBR_CFIG_B_BUFSZ0_SHIFT);
+ break;
+ case 1 * 1024:
+ val |= (RBR_BUFSZ0_1K << RBR_CFIG_B_BUFSZ0_SHIFT);
+ break;
+ case 2 * 1024:
+ val |= (RBR_BUFSZ0_2K << RBR_CFIG_B_BUFSZ0_SHIFT);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ *ret = val;
+ return 0;
+}
+
+static int niu_enable_rx_channel(struct niu *np, int channel, int on)
+{
+ u64 val = nr64(RXDMA_CFIG1(channel));
+ int limit;
+
+ if (on)
+ val |= RXDMA_CFIG1_EN;
+ else
+ val &= ~RXDMA_CFIG1_EN;
+ nw64(RXDMA_CFIG1(channel), val);
+
+ limit = 1000;
+ while (--limit > 0) {
+ if (nr64(RXDMA_CFIG1(channel)) & RXDMA_CFIG1_QST)
+ break;
+ udelay(10);
+ }
+ if (limit <= 0)
+ return -ENODEV;
+ return 0;
+}
+
+static int niu_init_one_rx_channel(struct niu *np, struct rx_ring_info *rp)
+{
+ int err, channel = rp->rx_channel;
+ u64 val;
+
+ err = niu_rx_channel_reset(np, channel);
+ if (err)
+ return err;
+
+ err = niu_rx_channel_lpage_init(np, channel);
+ if (err)
+ return err;
+
+ niu_rx_channel_wred_init(np, rp);
+
+ nw64(RX_DMA_ENT_MSK(channel), RX_DMA_ENT_MSK_RBR_EMPTY);
+ nw64(RX_DMA_CTL_STAT(channel),
+ (RX_DMA_CTL_STAT_MEX |
+ RX_DMA_CTL_STAT_RCRTHRES |
+ RX_DMA_CTL_STAT_RCRTO |
+ RX_DMA_CTL_STAT_RBR_EMPTY));
+ nw64(RXDMA_CFIG1(channel), rp->mbox_dma >> 32);
+ nw64(RXDMA_CFIG2(channel), (rp->mbox_dma & 0x00000000ffffffc0));
+ nw64(RBR_CFIG_A(channel),
+ ((u64)rp->rbr_table_size << RBR_CFIG_A_LEN_SHIFT) |
+ (rp->rbr_dma & (RBR_CFIG_A_STADDR_BASE | RBR_CFIG_A_STADDR)));
+ err = niu_compute_rbr_cfig_b(rp, &val);
+ if (err)
+ return err;
+ nw64(RBR_CFIG_B(channel), val);
+ nw64(RCRCFIG_A(channel),
+ ((u64)rp->rcr_table_size << RCRCFIG_A_LEN_SHIFT) |
+ (rp->rcr_dma & (RCRCFIG_A_STADDR_BASE | RCRCFIG_A_STADDR)));
+ nw64(RCRCFIG_B(channel),
+ ((u64)rp->rcr_pkt_threshold << RCRCFIG_B_PTHRES_SHIFT) |
+ RCRCFIG_B_ENTOUT |
+ ((u64)rp->rcr_timeout << RCRCFIG_B_TIMEOUT_SHIFT));
+
+ err = niu_enable_rx_channel(np, channel, 1);
+ if (err)
+ return err;
+
+ nw64(RBR_KICK(channel), rp->rbr_index);
+
+ val = nr64(RX_DMA_CTL_STAT(channel));
+ val |= RX_DMA_CTL_STAT_RBR_EMPTY;
+ nw64(RX_DMA_CTL_STAT(channel), val);
+
+ return 0;
+}
+
+static int niu_init_rx_channels(struct niu *np)
+{
+ unsigned long flags;
+ u64 seed = jiffies_64;
+ int err, i;
+
+ niu_lock_parent(np, flags);
+ nw64(RX_DMA_CK_DIV, np->parent->rxdma_clock_divider);
+ nw64(RED_RAN_INIT, RED_RAN_INIT_OPMODE | (seed & RED_RAN_INIT_VAL));
+ niu_unlock_parent(np, flags);
+
+ /* XXX RXDMA 32bit mode? XXX */
+
+ niu_init_rdc_groups(np);
+ niu_init_drr_weight(np);
+
+ err = niu_init_hostinfo(np);
+ if (err)
+ return err;
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ err = niu_init_one_rx_channel(np, rp);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int niu_set_ip_frag_rule(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ struct niu_classifier *cp = &np->clas;
+ struct niu_tcam_entry *tp;
+ int index, err;
+
+ /* XXX fix this allocation scheme XXX */
+ index = cp->tcam_index;
+ tp = &parent->tcam[index];
+
+ /* Note that the noport bit is the same in both ipv4 and
+ * ipv6 format TCAM entries.
+ */
+ memset(tp, 0, sizeof(*tp));
+ tp->key[1] = TCAM_V4KEY1_NOPORT;
+ tp->key_mask[1] = TCAM_V4KEY1_NOPORT;
+ tp->assoc_data = (TCAM_ASSOCDATA_TRES_USE_OFFSET |
+ ((u64)0 << TCAM_ASSOCDATA_OFFSET_SHIFT));
+ err = tcam_write(np, index, tp->key, tp->key_mask);
+ if (err)
+ return err;
+ err = tcam_assoc_write(np, index, tp->assoc_data);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int niu_init_classifier_hw(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ struct niu_classifier *cp = &np->clas;
+ int i, err;
+
+ nw64(H1POLY, cp->h1_init);
+ nw64(H2POLY, cp->h2_init);
+
+ err = niu_init_hostinfo(np);
+ if (err)
+ return err;
+
+ for (i = 0; i < ENET_VLAN_TBL_NUM_ENTRIES; i++) {
+ struct niu_vlan_rdc *vp = &cp->vlan_mappings[i];
+
+ vlan_tbl_write(np, i, np->port,
+ vp->vlan_pref, vp->rdc_num);
+ }
+
+ for (i = 0; i < cp->num_alt_mac_mappings; i++) {
+ struct niu_altmac_rdc *ap = &cp->alt_mac_mappings[i];
+
+ err = niu_set_alt_mac_rdc_table(np, ap->alt_mac_num,
+ ap->rdc_num, ap->mac_pref);
+ if (err)
+ return err;
+ }
+
+ for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_SCTP_IPV6; i++) {
+ int index = i - CLASS_CODE_USER_PROG1;
+
+ err = niu_set_tcam_key(np, i, parent->tcam_key[index]);
+ if (err)
+ return err;
+ err = niu_set_flow_key(np, i, parent->flow_key[index]);
+ if (err)
+ return err;
+ }
+
+ err = niu_set_ip_frag_rule(np);
+ if (err)
+ return err;
+
+ tcam_enable(np, 1);
+
+ return 0;
+}
+
+static int niu_zcp_write(struct niu *np, int index, u64 *data)
+{
+ nw64(ZCP_RAM_DATA0, data[0]);
+ nw64(ZCP_RAM_DATA1, data[1]);
+ nw64(ZCP_RAM_DATA2, data[2]);
+ nw64(ZCP_RAM_DATA3, data[3]);
+ nw64(ZCP_RAM_DATA4, data[4]);
+ nw64(ZCP_RAM_BE, ZCP_RAM_BE_VAL);
+ nw64(ZCP_RAM_ACC,
+ (ZCP_RAM_ACC_WRITE |
+ (0 << ZCP_RAM_ACC_ZFCID_SHIFT) |
+ (ZCP_RAM_SEL_CFIFO(np->port) << ZCP_RAM_ACC_RAM_SEL_SHIFT)));
+
+ return niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
+ 1000, 100);
+}
+
+static int niu_zcp_read(struct niu *np, int index, u64 *data)
+{
+ int err;
+
+ err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
+ 1000, 100);
+ if (err) {
+ dev_err(np->device, PFX "%s: ZCP read busy won't clear, "
+ "ZCP_RAM_ACC[%llx]\n", np->dev->name,
+ (unsigned long long) nr64(ZCP_RAM_ACC));
+ return err;
+ }
+
+ nw64(ZCP_RAM_ACC,
+ (ZCP_RAM_ACC_READ |
+ (0 << ZCP_RAM_ACC_ZFCID_SHIFT) |
+ (ZCP_RAM_SEL_CFIFO(np->port) << ZCP_RAM_ACC_RAM_SEL_SHIFT)));
+
+ err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
+ 1000, 100);
+ if (err) {
+ dev_err(np->device, PFX "%s: ZCP read busy2 won't clear, "
+ "ZCP_RAM_ACC[%llx]\n", np->dev->name,
+ (unsigned long long) nr64(ZCP_RAM_ACC));
+ return err;
+ }
+
+ data[0] = nr64(ZCP_RAM_DATA0);
+ data[1] = nr64(ZCP_RAM_DATA1);
+ data[2] = nr64(ZCP_RAM_DATA2);
+ data[3] = nr64(ZCP_RAM_DATA3);
+ data[4] = nr64(ZCP_RAM_DATA4);
+
+ return 0;
+}
+
+static void niu_zcp_cfifo_reset(struct niu *np)
+{
+ u64 val = nr64(RESET_CFIFO);
+
+ val |= RESET_CFIFO_RST(np->port);
+ nw64(RESET_CFIFO, val);
+ udelay(10);
+
+ val &= ~RESET_CFIFO_RST(np->port);
+ nw64(RESET_CFIFO, val);
+}
+
+static int niu_init_zcp(struct niu *np)
+{
+ u64 data[5], rbuf[5];
+ int i, max, err;
+
+ if (np->parent->plat_type != PLAT_TYPE_NIU) {
+ if (np->port == 0 || np->port == 1)
+ max = ATLAS_P0_P1_CFIFO_ENTRIES;
+ else
+ max = ATLAS_P2_P3_CFIFO_ENTRIES;
+ } else
+ max = NIU_CFIFO_ENTRIES;
+
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 0;
+ data[4] = 0;
+
+ for (i = 0; i < max; i++) {
+ err = niu_zcp_write(np, i, data);
+ if (err)
+ return err;
+ err = niu_zcp_read(np, i, rbuf);
+ if (err)
+ return err;
+ }
+
+ niu_zcp_cfifo_reset(np);
+ nw64(CFIFO_ECC(np->port), 0);
+ nw64(ZCP_INT_STAT, ZCP_INT_STAT_ALL);
+ (void) nr64(ZCP_INT_STAT);
+ nw64(ZCP_INT_MASK, ZCP_INT_MASK_ALL);
+
+ return 0;
+}
+
+static void niu_ipp_write(struct niu *np, int index, u64 *data)
+{
+ u64 val = nr64_ipp(IPP_CFIG);
+
+ nw64_ipp(IPP_CFIG, val | IPP_CFIG_DFIFO_PIO_W);
+ nw64_ipp(IPP_DFIFO_WR_PTR, index);
+ nw64_ipp(IPP_DFIFO_WR0, data[0]);
+ nw64_ipp(IPP_DFIFO_WR1, data[1]);
+ nw64_ipp(IPP_DFIFO_WR2, data[2]);
+ nw64_ipp(IPP_DFIFO_WR3, data[3]);
+ nw64_ipp(IPP_DFIFO_WR4, data[4]);
+ nw64_ipp(IPP_CFIG, val & ~IPP_CFIG_DFIFO_PIO_W);
+}
+
+static void niu_ipp_read(struct niu *np, int index, u64 *data)
+{
+ nw64_ipp(IPP_DFIFO_RD_PTR, index);
+ data[0] = nr64_ipp(IPP_DFIFO_RD0);
+ data[1] = nr64_ipp(IPP_DFIFO_RD1);
+ data[2] = nr64_ipp(IPP_DFIFO_RD2);
+ data[3] = nr64_ipp(IPP_DFIFO_RD3);
+ data[4] = nr64_ipp(IPP_DFIFO_RD4);
+}
+
+static int niu_ipp_reset(struct niu *np)
+{
+ return niu_set_and_wait_clear_ipp(np, IPP_CFIG, IPP_CFIG_SOFT_RST,
+ 1000, 100, "IPP_CFIG");
+}
+
+static int niu_init_ipp(struct niu *np)
+{
+ u64 data[5], rbuf[5], val;
+ int i, max, err;
+
+ if (np->parent->plat_type != PLAT_TYPE_NIU) {
+ if (np->port == 0 || np->port == 1)
+ max = ATLAS_P0_P1_DFIFO_ENTRIES;
+ else
+ max = ATLAS_P2_P3_DFIFO_ENTRIES;
+ } else
+ max = NIU_DFIFO_ENTRIES;
+
+ data[0] = 0;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 0;
+ data[4] = 0;
+
+ for (i = 0; i < max; i++) {
+ niu_ipp_write(np, i, data);
+ niu_ipp_read(np, i, rbuf);
+ }
+
+ (void) nr64_ipp(IPP_INT_STAT);
+ (void) nr64_ipp(IPP_INT_STAT);
+
+ err = niu_ipp_reset(np);
+ if (err)
+ return err;
+
+ (void) nr64_ipp(IPP_PKT_DIS);
+ (void) nr64_ipp(IPP_BAD_CS_CNT);
+ (void) nr64_ipp(IPP_ECC);
+
+ (void) nr64_ipp(IPP_INT_STAT);
+
+ nw64_ipp(IPP_MSK, ~IPP_MSK_ALL);
+
+ val = nr64_ipp(IPP_CFIG);
+ val &= ~IPP_CFIG_IP_MAX_PKT;
+ val |= (IPP_CFIG_IPP_ENABLE |
+ IPP_CFIG_DFIFO_ECC_EN |
+ IPP_CFIG_DROP_BAD_CRC |
+ IPP_CFIG_CKSUM_EN |
+ (0x1ffff << IPP_CFIG_IP_MAX_PKT_SHIFT));
+ nw64_ipp(IPP_CFIG, val);
+
+ return 0;
+}
+
+static void niu_init_xif_xmac(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u64 val;
+
+ val = nr64_mac(XMAC_CONFIG);
+
+ if ((np->flags & NIU_FLAGS_10G) != 0 &&
+ (np->flags & NIU_FLAGS_FIBER) != 0) {
+ if (netif_carrier_ok(np->dev)) {
+ val |= XMAC_CONFIG_LED_POLARITY;
+ val &= ~XMAC_CONFIG_FORCE_LED_ON;
+ } else {
+ val |= XMAC_CONFIG_FORCE_LED_ON;
+ val &= ~XMAC_CONFIG_LED_POLARITY;
+ }
+ }
+
+ val &= ~XMAC_CONFIG_SEL_POR_CLK_SRC;
+
+ val |= XMAC_CONFIG_TX_OUTPUT_EN;
+
+ if (lp->loopback_mode == LOOPBACK_MAC) {
+ val &= ~XMAC_CONFIG_SEL_POR_CLK_SRC;
+ val |= XMAC_CONFIG_LOOPBACK;
+ } else {
+ val &= ~XMAC_CONFIG_LOOPBACK;
+ }
+
+ if (np->flags & NIU_FLAGS_10G) {
+ val &= ~XMAC_CONFIG_LFS_DISABLE;
+ } else {
+ val |= XMAC_CONFIG_LFS_DISABLE;
+ if (!(np->flags & NIU_FLAGS_FIBER))
+ val |= XMAC_CONFIG_1G_PCS_BYPASS;
+ else
+ val &= ~XMAC_CONFIG_1G_PCS_BYPASS;
+ }
+
+ val &= ~XMAC_CONFIG_10G_XPCS_BYPASS;
+
+ if (lp->active_speed == SPEED_100)
+ val |= XMAC_CONFIG_SEL_CLK_25MHZ;
+ else
+ val &= ~XMAC_CONFIG_SEL_CLK_25MHZ;
+
+ nw64_mac(XMAC_CONFIG, val);
+
+ val = nr64_mac(XMAC_CONFIG);
+ val &= ~XMAC_CONFIG_MODE_MASK;
+ if (np->flags & NIU_FLAGS_10G) {
+ val |= XMAC_CONFIG_MODE_XGMII;
+ } else {
+ if (lp->active_speed == SPEED_100)
+ val |= XMAC_CONFIG_MODE_MII;
+ else
+ val |= XMAC_CONFIG_MODE_GMII;
+ }
+
+ nw64_mac(XMAC_CONFIG, val);
+}
+
+static void niu_init_xif_bmac(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u64 val;
+
+ val = BMAC_XIF_CONFIG_TX_OUTPUT_EN;
+
+ if (lp->loopback_mode == LOOPBACK_MAC)
+ val |= BMAC_XIF_CONFIG_MII_LOOPBACK;
+ else
+ val &= ~BMAC_XIF_CONFIG_MII_LOOPBACK;
+
+ if (lp->active_speed == SPEED_1000)
+ val |= BMAC_XIF_CONFIG_GMII_MODE;
+ else
+ val &= ~BMAC_XIF_CONFIG_GMII_MODE;
+
+ val &= ~(BMAC_XIF_CONFIG_LINK_LED |
+ BMAC_XIF_CONFIG_LED_POLARITY);
+
+ if (!(np->flags & NIU_FLAGS_10G) &&
+ !(np->flags & NIU_FLAGS_FIBER) &&
+ lp->active_speed == SPEED_100)
+ val |= BMAC_XIF_CONFIG_25MHZ_CLOCK;
+ else
+ val &= ~BMAC_XIF_CONFIG_25MHZ_CLOCK;
+
+ nw64_mac(BMAC_XIF_CONFIG, val);
+}
+
+static void niu_init_xif(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_init_xif_xmac(np);
+ else
+ niu_init_xif_bmac(np);
+}
+
+static void niu_pcs_mii_reset(struct niu *np)
+{
+ u64 val = nr64_pcs(PCS_MII_CTL);
+ val |= PCS_MII_CTL_RST;
+ nw64_pcs(PCS_MII_CTL, val);
+}
+
+static void niu_xpcs_reset(struct niu *np)
+{
+ u64 val = nr64_xpcs(XPCS_CONTROL1);
+ val |= XPCS_CONTROL1_RESET;
+ nw64_xpcs(XPCS_CONTROL1, val);
+}
+
+static int niu_init_pcs(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+ u64 val;
+
+ switch (np->flags & (NIU_FLAGS_10G | NIU_FLAGS_FIBER)) {
+ case NIU_FLAGS_FIBER:
+ /* 1G fiber */
+ nw64_pcs(PCS_CONF, PCS_CONF_MASK | PCS_CONF_ENABLE);
+ nw64_pcs(PCS_DPATH_MODE, 0);
+ niu_pcs_mii_reset(np);
+ break;
+
+ case NIU_FLAGS_10G:
+ case NIU_FLAGS_10G | NIU_FLAGS_FIBER:
+ if (!(np->flags & NIU_FLAGS_XMAC))
+ return -EINVAL;
+
+ /* 10G copper or fiber */
+ val = nr64_mac(XMAC_CONFIG);
+ val &= ~XMAC_CONFIG_10G_XPCS_BYPASS;
+ nw64_mac(XMAC_CONFIG, val);
+
+ niu_xpcs_reset(np);
+
+ val = nr64_xpcs(XPCS_CONTROL1);
+ if (lp->loopback_mode == LOOPBACK_PHY)
+ val |= XPCS_CONTROL1_LOOPBACK;
+ else
+ val &= ~XPCS_CONTROL1_LOOPBACK;
+ nw64_xpcs(XPCS_CONTROL1, val);
+
+ nw64_xpcs(XPCS_DESKEW_ERR_CNT, 0);
+ (void) nr64_xpcs(XPCS_SYMERR_CNT01);
+ (void) nr64_xpcs(XPCS_SYMERR_CNT23);
+ break;
+
+ case 0:
+ /* 1G copper */
+ nw64_pcs(PCS_DPATH_MODE, PCS_DPATH_MODE_MII);
+ niu_pcs_mii_reset(np);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int niu_reset_tx_xmac(struct niu *np)
+{
+ return niu_set_and_wait_clear_mac(np, XTXMAC_SW_RST,
+ (XTXMAC_SW_RST_REG_RS |
+ XTXMAC_SW_RST_SOFT_RST),
+ 1000, 100, "XTXMAC_SW_RST");
+}
+
+static int niu_reset_tx_bmac(struct niu *np)
+{
+ int limit;
+
+ nw64_mac(BTXMAC_SW_RST, BTXMAC_SW_RST_RESET);
+ limit = 1000;
+ while (--limit >= 0) {
+ if (!(nr64_mac(BTXMAC_SW_RST) & BTXMAC_SW_RST_RESET))
+ break;
+ udelay(100);
+ }
+ if (limit < 0) {
+ dev_err(np->device, PFX "Port %u TX BMAC would not reset, "
+ "BTXMAC_SW_RST[%llx]\n",
+ np->port,
+ (unsigned long long) nr64_mac(BTXMAC_SW_RST));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int niu_reset_tx_mac(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ return niu_reset_tx_xmac(np);
+ else
+ return niu_reset_tx_bmac(np);
+}
+
+static void niu_init_tx_xmac(struct niu *np, u64 min, u64 max)
+{
+ u64 val;
+
+ val = nr64_mac(XMAC_MIN);
+ val &= ~(XMAC_MIN_TX_MIN_PKT_SIZE |
+ XMAC_MIN_RX_MIN_PKT_SIZE);
+ val |= (min << XMAC_MIN_RX_MIN_PKT_SIZE_SHFT);
+ val |= (min << XMAC_MIN_TX_MIN_PKT_SIZE_SHFT);
+ nw64_mac(XMAC_MIN, val);
+
+ nw64_mac(XMAC_MAX, max);
+
+ nw64_mac(XTXMAC_STAT_MSK, ~(u64)0);
+
+ val = nr64_mac(XMAC_IPG);
+ if (np->flags & NIU_FLAGS_10G) {
+ val &= ~XMAC_IPG_IPG_XGMII;
+ val |= (IPG_12_15_XGMII << XMAC_IPG_IPG_XGMII_SHIFT);
+ } else {
+ val &= ~XMAC_IPG_IPG_MII_GMII;
+ val |= (IPG_12_MII_GMII << XMAC_IPG_IPG_MII_GMII_SHIFT);
+ }
+ nw64_mac(XMAC_IPG, val);
+
+ val = nr64_mac(XMAC_CONFIG);
+ val &= ~(XMAC_CONFIG_ALWAYS_NO_CRC |
+ XMAC_CONFIG_STRETCH_MODE |
+ XMAC_CONFIG_VAR_MIN_IPG_EN |
+ XMAC_CONFIG_TX_ENABLE);
+ nw64_mac(XMAC_CONFIG, val);
+
+ nw64_mac(TXMAC_FRM_CNT, 0);
+ nw64_mac(TXMAC_BYTE_CNT, 0);
+}
+
+static void niu_init_tx_bmac(struct niu *np, u64 min, u64 max)
+{
+ u64 val;
+
+ nw64_mac(BMAC_MIN_FRAME, min);
+ nw64_mac(BMAC_MAX_FRAME, max);
+
+ nw64_mac(BTXMAC_STATUS_MASK, ~(u64)0);
+ nw64_mac(BMAC_CTRL_TYPE, 0x8808);
+ nw64_mac(BMAC_PREAMBLE_SIZE, 7);
+
+ val = nr64_mac(BTXMAC_CONFIG);
+ val &= ~(BTXMAC_CONFIG_FCS_DISABLE |
+ BTXMAC_CONFIG_ENABLE);
+ nw64_mac(BTXMAC_CONFIG, val);
+}
+
+static void niu_init_tx_mac(struct niu *np)
+{
+ u64 min, max;
+
+ min = 64;
+ if (np->dev->mtu > ETH_DATA_LEN)
+ max = 9216;
+ else
+ max = 1522;
+
+ /* The XMAC_MIN register only accepts values for TX min which
+ * have the low 3 bits cleared.
+ */
+ BUILD_BUG_ON(min & 0x7);
+
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_init_tx_xmac(np, min, max);
+ else
+ niu_init_tx_bmac(np, min, max);
+}
+
+static int niu_reset_rx_xmac(struct niu *np)
+{
+ int limit;
+
+ nw64_mac(XRXMAC_SW_RST,
+ XRXMAC_SW_RST_REG_RS | XRXMAC_SW_RST_SOFT_RST);
+ limit = 1000;
+ while (--limit >= 0) {
+ if (!(nr64_mac(XRXMAC_SW_RST) & (XRXMAC_SW_RST_REG_RS |
+ XRXMAC_SW_RST_SOFT_RST)))
+ break;
+ udelay(100);
+ }
+ if (limit < 0) {
+ dev_err(np->device, PFX "Port %u RX XMAC would not reset, "
+ "XRXMAC_SW_RST[%llx]\n",
+ np->port,
+ (unsigned long long) nr64_mac(XRXMAC_SW_RST));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int niu_reset_rx_bmac(struct niu *np)
+{
+ int limit;
+
+ nw64_mac(BRXMAC_SW_RST, BRXMAC_SW_RST_RESET);
+ limit = 1000;
+ while (--limit >= 0) {
+ if (!(nr64_mac(BRXMAC_SW_RST) & BRXMAC_SW_RST_RESET))
+ break;
+ udelay(100);
+ }
+ if (limit < 0) {
+ dev_err(np->device, PFX "Port %u RX BMAC would not reset, "
+ "BRXMAC_SW_RST[%llx]\n",
+ np->port,
+ (unsigned long long) nr64_mac(BRXMAC_SW_RST));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int niu_reset_rx_mac(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ return niu_reset_rx_xmac(np);
+ else
+ return niu_reset_rx_bmac(np);
+}
+
+static void niu_init_rx_xmac(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port];
+ int first_rdc_table = tp->first_table_num;
+ unsigned long i;
+ u64 val;
+
+ nw64_mac(XMAC_ADD_FILT0, 0);
+ nw64_mac(XMAC_ADD_FILT1, 0);
+ nw64_mac(XMAC_ADD_FILT2, 0);
+ nw64_mac(XMAC_ADD_FILT12_MASK, 0);
+ nw64_mac(XMAC_ADD_FILT00_MASK, 0);
+ for (i = 0; i < MAC_NUM_HASH; i++)
+ nw64_mac(XMAC_HASH_TBL(i), 0);
+ nw64_mac(XRXMAC_STAT_MSK, ~(u64)0);
+ niu_set_primary_mac_rdc_table(np, first_rdc_table, 1);
+ niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1);
+
+ val = nr64_mac(XMAC_CONFIG);
+ val &= ~(XMAC_CONFIG_RX_MAC_ENABLE |
+ XMAC_CONFIG_PROMISCUOUS |
+ XMAC_CONFIG_PROMISC_GROUP |
+ XMAC_CONFIG_ERR_CHK_DIS |
+ XMAC_CONFIG_RX_CRC_CHK_DIS |
+ XMAC_CONFIG_RESERVED_MULTICAST |
+ XMAC_CONFIG_RX_CODEV_CHK_DIS |
+ XMAC_CONFIG_ADDR_FILTER_EN |
+ XMAC_CONFIG_RCV_PAUSE_ENABLE |
+ XMAC_CONFIG_STRIP_CRC |
+ XMAC_CONFIG_PASS_FLOW_CTRL |
+ XMAC_CONFIG_MAC2IPP_PKT_CNT_EN);
+ val |= (XMAC_CONFIG_HASH_FILTER_EN);
+ nw64_mac(XMAC_CONFIG, val);
+
+ nw64_mac(RXMAC_BT_CNT, 0);
+ nw64_mac(RXMAC_BC_FRM_CNT, 0);
+ nw64_mac(RXMAC_MC_FRM_CNT, 0);
+ nw64_mac(RXMAC_FRAG_CNT, 0);
+ nw64_mac(RXMAC_HIST_CNT1, 0);
+ nw64_mac(RXMAC_HIST_CNT2, 0);
+ nw64_mac(RXMAC_HIST_CNT3, 0);
+ nw64_mac(RXMAC_HIST_CNT4, 0);
+ nw64_mac(RXMAC_HIST_CNT5, 0);
+ nw64_mac(RXMAC_HIST_CNT6, 0);
+ nw64_mac(RXMAC_HIST_CNT7, 0);
+ nw64_mac(RXMAC_MPSZER_CNT, 0);
+ nw64_mac(RXMAC_CRC_ER_CNT, 0);
+ nw64_mac(RXMAC_CD_VIO_CNT, 0);
+ nw64_mac(LINK_FAULT_CNT, 0);
+}
+
+static void niu_init_rx_bmac(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port];
+ int first_rdc_table = tp->first_table_num;
+ unsigned long i;
+ u64 val;
+
+ nw64_mac(BMAC_ADD_FILT0, 0);
+ nw64_mac(BMAC_ADD_FILT1, 0);
+ nw64_mac(BMAC_ADD_FILT2, 0);
+ nw64_mac(BMAC_ADD_FILT12_MASK, 0);
+ nw64_mac(BMAC_ADD_FILT00_MASK, 0);
+ for (i = 0; i < MAC_NUM_HASH; i++)
+ nw64_mac(BMAC_HASH_TBL(i), 0);
+ niu_set_primary_mac_rdc_table(np, first_rdc_table, 1);
+ niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1);
+ nw64_mac(BRXMAC_STATUS_MASK, ~(u64)0);
+
+ val = nr64_mac(BRXMAC_CONFIG);
+ val &= ~(BRXMAC_CONFIG_ENABLE |
+ BRXMAC_CONFIG_STRIP_PAD |
+ BRXMAC_CONFIG_STRIP_FCS |
+ BRXMAC_CONFIG_PROMISC |
+ BRXMAC_CONFIG_PROMISC_GRP |
+ BRXMAC_CONFIG_ADDR_FILT_EN |
+ BRXMAC_CONFIG_DISCARD_DIS);
+ val |= (BRXMAC_CONFIG_HASH_FILT_EN);
+ nw64_mac(BRXMAC_CONFIG, val);
+
+ val = nr64_mac(BMAC_ADDR_CMPEN);
+ val |= BMAC_ADDR_CMPEN_EN0;
+ nw64_mac(BMAC_ADDR_CMPEN, val);
+}
+
+static void niu_init_rx_mac(struct niu *np)
+{
+ niu_set_primary_mac(np, np->dev->dev_addr);
+
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_init_rx_xmac(np);
+ else
+ niu_init_rx_bmac(np);
+}
+
+static void niu_enable_tx_xmac(struct niu *np, int on)
+{
+ u64 val = nr64_mac(XMAC_CONFIG);
+
+ if (on)
+ val |= XMAC_CONFIG_TX_ENABLE;
+ else
+ val &= ~XMAC_CONFIG_TX_ENABLE;
+ nw64_mac(XMAC_CONFIG, val);
+}
+
+static void niu_enable_tx_bmac(struct niu *np, int on)
+{
+ u64 val = nr64_mac(BTXMAC_CONFIG);
+
+ if (on)
+ val |= BTXMAC_CONFIG_ENABLE;
+ else
+ val &= ~BTXMAC_CONFIG_ENABLE;
+ nw64_mac(BTXMAC_CONFIG, val);
+}
+
+static void niu_enable_tx_mac(struct niu *np, int on)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_enable_tx_xmac(np, on);
+ else
+ niu_enable_tx_bmac(np, on);
+}
+
+static void niu_enable_rx_xmac(struct niu *np, int on)
+{
+ u64 val = nr64_mac(XMAC_CONFIG);
+
+ val &= ~(XMAC_CONFIG_HASH_FILTER_EN |
+ XMAC_CONFIG_PROMISCUOUS);
+
+ if (np->flags & NIU_FLAGS_MCAST)
+ val |= XMAC_CONFIG_HASH_FILTER_EN;
+ if (np->flags & NIU_FLAGS_PROMISC)
+ val |= XMAC_CONFIG_PROMISCUOUS;
+
+ if (on)
+ val |= XMAC_CONFIG_RX_MAC_ENABLE;
+ else
+ val &= ~XMAC_CONFIG_RX_MAC_ENABLE;
+ nw64_mac(XMAC_CONFIG, val);
+}
+
+static void niu_enable_rx_bmac(struct niu *np, int on)
+{
+ u64 val = nr64_mac(BRXMAC_CONFIG);
+
+ val &= ~(BRXMAC_CONFIG_HASH_FILT_EN |
+ BRXMAC_CONFIG_PROMISC);
+
+ if (np->flags & NIU_FLAGS_MCAST)
+ val |= BRXMAC_CONFIG_HASH_FILT_EN;
+ if (np->flags & NIU_FLAGS_PROMISC)
+ val |= BRXMAC_CONFIG_PROMISC;
+
+ if (on)
+ val |= BRXMAC_CONFIG_ENABLE;
+ else
+ val &= ~BRXMAC_CONFIG_ENABLE;
+ nw64_mac(BRXMAC_CONFIG, val);
+}
+
+static void niu_enable_rx_mac(struct niu *np, int on)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_enable_rx_xmac(np, on);
+ else
+ niu_enable_rx_bmac(np, on);
+}
+
+static int niu_init_mac(struct niu *np)
+{
+ int err;
+
+ niu_init_xif(np);
+ err = niu_init_pcs(np);
+ if (err)
+ return err;
+
+ err = niu_reset_tx_mac(np);
+ if (err)
+ return err;
+ niu_init_tx_mac(np);
+ err = niu_reset_rx_mac(np);
+ if (err)
+ return err;
+ niu_init_rx_mac(np);
+
+ /* This looks hookey but the RX MAC reset we just did will
+ * undo some of the state we setup in niu_init_tx_mac() so we
+ * have to call it again. In particular, the RX MAC reset will
+ * set the XMAC_MAX register back to it's default value.
+ */
+ niu_init_tx_mac(np);
+ niu_enable_tx_mac(np, 1);
+
+ niu_enable_rx_mac(np, 1);
+
+ return 0;
+}
+
+static void niu_stop_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
+{
+ (void) niu_tx_channel_stop(np, rp->tx_channel);
+}
+
+static void niu_stop_tx_channels(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ niu_stop_one_tx_channel(np, rp);
+ }
+}
+
+static void niu_reset_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
+{
+ (void) niu_tx_channel_reset(np, rp->tx_channel);
+}
+
+static void niu_reset_tx_channels(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ niu_reset_one_tx_channel(np, rp);
+ }
+}
+
+static void niu_stop_one_rx_channel(struct niu *np, struct rx_ring_info *rp)
+{
+ (void) niu_enable_rx_channel(np, rp->rx_channel, 0);
+}
+
+static void niu_stop_rx_channels(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ niu_stop_one_rx_channel(np, rp);
+ }
+}
+
+static void niu_reset_one_rx_channel(struct niu *np, struct rx_ring_info *rp)
+{
+ int channel = rp->rx_channel;
+
+ (void) niu_rx_channel_reset(np, channel);
+ nw64(RX_DMA_ENT_MSK(channel), RX_DMA_ENT_MSK_ALL);
+ nw64(RX_DMA_CTL_STAT(channel), 0);
+ (void) niu_enable_rx_channel(np, channel, 0);
+}
+
+static void niu_reset_rx_channels(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ niu_reset_one_rx_channel(np, rp);
+ }
+}
+
+static void niu_disable_ipp(struct niu *np)
+{
+ u64 rd, wr, val;
+ int limit;
+
+ rd = nr64_ipp(IPP_DFIFO_RD_PTR);
+ wr = nr64_ipp(IPP_DFIFO_WR_PTR);
+ limit = 100;
+ while (--limit >= 0 && (rd != wr)) {
+ rd = nr64_ipp(IPP_DFIFO_RD_PTR);
+ wr = nr64_ipp(IPP_DFIFO_WR_PTR);
+ }
+ if (limit < 0 &&
+ (rd != 0 && wr != 1)) {
+ dev_err(np->device, PFX "%s: IPP would not quiesce, "
+ "rd_ptr[%llx] wr_ptr[%llx]\n",
+ np->dev->name,
+ (unsigned long long) nr64_ipp(IPP_DFIFO_RD_PTR),
+ (unsigned long long) nr64_ipp(IPP_DFIFO_WR_PTR));
+ }
+
+ val = nr64_ipp(IPP_CFIG);
+ val &= ~(IPP_CFIG_IPP_ENABLE |
+ IPP_CFIG_DFIFO_ECC_EN |
+ IPP_CFIG_DROP_BAD_CRC |
+ IPP_CFIG_CKSUM_EN);
+ nw64_ipp(IPP_CFIG, val);
+
+ (void) niu_ipp_reset(np);
+}
+
+static int niu_init_hw(struct niu *np)
+{
+ int i, err;
+
+ niudbg(IFUP, "%s: Initialize TXC\n", np->dev->name);
+ niu_txc_enable_port(np, 1);
+ niu_txc_port_dma_enable(np, 1);
+ niu_txc_set_imask(np, 0);
+
+ niudbg(IFUP, "%s: Initialize TX channels\n", np->dev->name);
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ err = niu_init_one_tx_channel(np, rp);
+ if (err)
+ return err;
+ }
+
+ niudbg(IFUP, "%s: Initialize RX channels\n", np->dev->name);
+ err = niu_init_rx_channels(np);
+ if (err)
+ goto out_uninit_tx_channels;
+
+ niudbg(IFUP, "%s: Initialize classifier\n", np->dev->name);
+ err = niu_init_classifier_hw(np);
+ if (err)
+ goto out_uninit_rx_channels;
+
+ niudbg(IFUP, "%s: Initialize ZCP\n", np->dev->name);
+ err = niu_init_zcp(np);
+ if (err)
+ goto out_uninit_rx_channels;
+
+ niudbg(IFUP, "%s: Initialize IPP\n", np->dev->name);
+ err = niu_init_ipp(np);
+ if (err)
+ goto out_uninit_rx_channels;
+
+ niudbg(IFUP, "%s: Initialize MAC\n", np->dev->name);
+ err = niu_init_mac(np);
+ if (err)
+ goto out_uninit_ipp;
+
+ return 0;
+
+out_uninit_ipp:
+ niudbg(IFUP, "%s: Uninit IPP\n", np->dev->name);
+ niu_disable_ipp(np);
+
+out_uninit_rx_channels:
+ niudbg(IFUP, "%s: Uninit RX channels\n", np->dev->name);
+ niu_stop_rx_channels(np);
+ niu_reset_rx_channels(np);
+
+out_uninit_tx_channels:
+ niudbg(IFUP, "%s: Uninit TX channels\n", np->dev->name);
+ niu_stop_tx_channels(np);
+ niu_reset_tx_channels(np);
+
+ return err;
+}
+
+static void niu_stop_hw(struct niu *np)
+{
+ niudbg(IFDOWN, "%s: Disable interrupts\n", np->dev->name);
+ niu_enable_interrupts(np, 0);
+
+ niudbg(IFDOWN, "%s: Disable RX MAC\n", np->dev->name);
+ niu_enable_rx_mac(np, 0);
+
+ niudbg(IFDOWN, "%s: Disable IPP\n", np->dev->name);
+ niu_disable_ipp(np);
+
+ niudbg(IFDOWN, "%s: Stop TX channels\n", np->dev->name);
+ niu_stop_tx_channels(np);
+
+ niudbg(IFDOWN, "%s: Stop RX channels\n", np->dev->name);
+ niu_stop_rx_channels(np);
+
+ niudbg(IFDOWN, "%s: Reset TX channels\n", np->dev->name);
+ niu_reset_tx_channels(np);
+
+ niudbg(IFDOWN, "%s: Reset RX channels\n", np->dev->name);
+ niu_reset_rx_channels(np);
+}
+
+static int niu_request_irq(struct niu *np)
+{
+ int i, j, err;
+
+ err = 0;
+ for (i = 0; i < np->num_ldg; i++) {
+ struct niu_ldg *lp = &np->ldg[i];
+
+ err = request_irq(lp->irq, niu_interrupt,
+ IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+ np->dev->name, lp);
+ if (err)
+ goto out_free_irqs;
+
+ }
+
+ return 0;
+
+out_free_irqs:
+ for (j = 0; j < i; j++) {
+ struct niu_ldg *lp = &np->ldg[j];
+
+ free_irq(lp->irq, lp);
+ }
+ return err;
+}
+
+static void niu_free_irq(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_ldg; i++) {
+ struct niu_ldg *lp = &np->ldg[i];
+
+ free_irq(lp->irq, lp);
+ }
+}
+
+static void niu_enable_napi(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_ldg; i++)
+ napi_enable(&np->ldg[i].napi);
+}
+
+static void niu_disable_napi(struct niu *np)
+{
+ int i;
+
+ for (i = 0; i < np->num_ldg; i++)
+ napi_disable(&np->ldg[i].napi);
+}
+
+static int niu_open(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+ int err;
+
+ netif_carrier_off(dev);
+
+ err = niu_alloc_channels(np);
+ if (err)
+ goto out_err;
+
+ err = niu_enable_interrupts(np, 0);
+ if (err)
+ goto out_free_channels;
+
+ err = niu_request_irq(np);
+ if (err)
+ goto out_free_channels;
+
+ niu_enable_napi(np);
+
+ spin_lock_irq(&np->lock);
+
+ err = niu_init_hw(np);
+ if (!err) {
+ init_timer(&np->timer);
+ np->timer.expires = jiffies + HZ;
+ np->timer.data = (unsigned long) np;
+ np->timer.function = niu_timer;
+
+ err = niu_enable_interrupts(np, 1);
+ if (err)
+ niu_stop_hw(np);
+ }
+
+ spin_unlock_irq(&np->lock);
+
+ if (err) {
+ niu_disable_napi(np);
+ goto out_free_irq;
+ }
+
+ netif_start_queue(dev);
+
+ if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+ netif_carrier_on(dev);
+
+ add_timer(&np->timer);
+
+ return 0;
+
+out_free_irq:
+ niu_free_irq(np);
+
+out_free_channels:
+ niu_free_channels(np);
+
+out_err:
+ return err;
+}
+
+static void niu_full_shutdown(struct niu *np, struct net_device *dev)
+{
+ cancel_work_sync(&np->reset_task);
+
+ niu_disable_napi(np);
+ netif_stop_queue(dev);
+
+ del_timer_sync(&np->timer);
+
+ spin_lock_irq(&np->lock);
+
+ niu_stop_hw(np);
+
+ spin_unlock_irq(&np->lock);
+}
+
+static int niu_close(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+
+ niu_full_shutdown(np, dev);
+
+ niu_free_irq(np);
+
+ niu_free_channels(np);
+
+ return 0;
+}
+
+static void niu_sync_xmac_stats(struct niu *np)
+{
+ struct niu_xmac_stats *mp = &np->mac_stats.xmac;
+
+ mp->tx_frames += nr64_mac(TXMAC_FRM_CNT);
+ mp->tx_bytes += nr64_mac(TXMAC_BYTE_CNT);
+
+ mp->rx_link_faults += nr64_mac(LINK_FAULT_CNT);
+ mp->rx_align_errors += nr64_mac(RXMAC_ALIGN_ERR_CNT);
+ mp->rx_frags += nr64_mac(RXMAC_FRAG_CNT);
+ mp->rx_mcasts += nr64_mac(RXMAC_MC_FRM_CNT);
+ mp->rx_bcasts += nr64_mac(RXMAC_BC_FRM_CNT);
+ mp->rx_hist_cnt1 += nr64_mac(RXMAC_HIST_CNT1);
+ mp->rx_hist_cnt2 += nr64_mac(RXMAC_HIST_CNT2);
+ mp->rx_hist_cnt3 += nr64_mac(RXMAC_HIST_CNT3);
+ mp->rx_hist_cnt4 += nr64_mac(RXMAC_HIST_CNT4);
+ mp->rx_hist_cnt5 += nr64_mac(RXMAC_HIST_CNT5);
+ mp->rx_hist_cnt6 += nr64_mac(RXMAC_HIST_CNT6);
+ mp->rx_hist_cnt7 += nr64_mac(RXMAC_HIST_CNT7);
+ mp->rx_octets += nr64_mac(RXMAC_BT_CNT);
+ mp->rx_code_violations += nr64_mac(RXMAC_CD_VIO_CNT);
+ mp->rx_len_errors += nr64_mac(RXMAC_MPSZER_CNT);
+ mp->rx_crc_errors += nr64_mac(RXMAC_CRC_ER_CNT);
+}
+
+static void niu_sync_bmac_stats(struct niu *np)
+{
+ struct niu_bmac_stats *mp = &np->mac_stats.bmac;
+
+ mp->tx_bytes += nr64_mac(BTXMAC_BYTE_CNT);
+ mp->tx_frames += nr64_mac(BTXMAC_FRM_CNT);
+
+ mp->rx_frames += nr64_mac(BRXMAC_FRAME_CNT);
+ mp->rx_align_errors += nr64_mac(BRXMAC_ALIGN_ERR_CNT);
+ mp->rx_crc_errors += nr64_mac(BRXMAC_ALIGN_ERR_CNT);
+ mp->rx_len_errors += nr64_mac(BRXMAC_CODE_VIOL_ERR_CNT);
+}
+
+static void niu_sync_mac_stats(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_sync_xmac_stats(np);
+ else
+ niu_sync_bmac_stats(np);
+}
+
+static void niu_get_rx_stats(struct niu *np)
+{
+ unsigned long pkts, dropped, errors, bytes;
+ int i;
+
+ pkts = dropped = errors = bytes = 0;
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ pkts += rp->rx_packets;
+ bytes += rp->rx_bytes;
+ dropped += rp->rx_dropped;
+ errors += rp->rx_errors;
+ }
+ np->net_stats.rx_packets = pkts;
+ np->net_stats.rx_bytes = bytes;
+ np->net_stats.rx_dropped = dropped;
+ np->net_stats.rx_errors = errors;
+}
+
+static void niu_get_tx_stats(struct niu *np)
+{
+ unsigned long pkts, errors, bytes;
+ int i;
+
+ pkts = errors = bytes = 0;
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ pkts += rp->tx_packets;
+ bytes += rp->tx_bytes;
+ errors += rp->tx_errors;
+ }
+ np->net_stats.tx_packets = pkts;
+ np->net_stats.tx_bytes = bytes;
+ np->net_stats.tx_errors = errors;
+}
+
+static struct net_device_stats *niu_get_stats(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+
+ niu_get_rx_stats(np);
+ niu_get_tx_stats(np);
+
+ return &np->net_stats;
+}
+
+static void niu_load_hash_xmac(struct niu *np, u16 *hash)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ nw64_mac(XMAC_HASH_TBL(i), hash[i]);
+}
+
+static void niu_load_hash_bmac(struct niu *np, u16 *hash)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ nw64_mac(BMAC_HASH_TBL(i), hash[i]);
+}
+
+static void niu_load_hash(struct niu *np, u16 *hash)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ niu_load_hash_xmac(np, hash);
+ else
+ niu_load_hash_bmac(np, hash);
+}
+
+static void niu_set_rx_mode(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+ int i, alt_cnt, err;
+ struct dev_addr_list *addr;
+ unsigned long flags;
+ u16 hash[16] = { 0, };
+
+ spin_lock_irqsave(&np->lock, flags);
+ niu_enable_rx_mac(np, 0);
+
+ np->flags &= ~(NIU_FLAGS_MCAST | NIU_FLAGS_PROMISC);
+ if (dev->flags & IFF_PROMISC)
+ np->flags |= NIU_FLAGS_PROMISC;
+ if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 0))
+ np->flags |= NIU_FLAGS_MCAST;
+
+ alt_cnt = dev->uc_count;
+ if (alt_cnt > niu_num_alt_addr(np)) {
+ alt_cnt = 0;
+ np->flags |= NIU_FLAGS_PROMISC;
+ }
+
+ if (alt_cnt) {
+ int index = 0;
+
+ for (addr = dev->uc_list; addr; addr = addr->next) {
+ err = niu_set_alt_mac(np, index,
+ addr->da_addr);
+ if (err)
+ printk(KERN_WARNING PFX "%s: Error %d "
+ "adding alt mac %d\n",
+ dev->name, err, index);
+ err = niu_enable_alt_mac(np, index, 1);
+ if (err)
+ printk(KERN_WARNING PFX "%s: Error %d "
+ "enabling alt mac %d\n",
+ dev->name, err, index);
+
+ index++;
+ }
+ } else {
+ for (i = 0; i < niu_num_alt_addr(np); i++) {
+ err = niu_enable_alt_mac(np, i, 0);
+ if (err)
+ printk(KERN_WARNING PFX "%s: Error %d "
+ "disabling alt mac %d\n",
+ dev->name, err, i);
+ }
+ }
+ if (dev->flags & IFF_ALLMULTI) {
+ for (i = 0; i < 16; i++)
+ hash[i] = 0xffff;
+ } else if (dev->mc_count > 0) {
+ for (addr = dev->mc_list; addr; addr = addr->next) {
+ u32 crc = ether_crc_le(ETH_ALEN, addr->da_addr);
+
+ crc >>= 24;
+ hash[crc >> 4] |= (1 << (15 - (crc & 0xf)));
+ }
+ }
+
+ if (np->flags & NIU_FLAGS_MCAST)
+ niu_load_hash(np, hash);
+
+ niu_enable_rx_mac(np, 1);
+ spin_unlock_irqrestore(&np->lock, flags);
+}
+
+static int niu_set_mac_addr(struct net_device *dev, void *p)
+{
+ struct niu *np = netdev_priv(dev);
+ struct sockaddr *addr = p;
+ unsigned long flags;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+
+ if (!netif_running(dev))
+ return 0;
+
+ spin_lock_irqsave(&np->lock, flags);
+ niu_enable_rx_mac(np, 0);
+ niu_set_primary_mac(np, dev->dev_addr);
+ niu_enable_rx_mac(np, 1);
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ return 0;
+}
+
+static int niu_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ return -EOPNOTSUPP;
+}
+
+static void niu_netif_stop(struct niu *np)
+{
+ np->dev->trans_start = jiffies; /* prevent tx timeout */
+
+ niu_disable_napi(np);
+
+ netif_tx_disable(np->dev);
+}
+
+static void niu_netif_start(struct niu *np)
+{
+ /* NOTE: unconditional netif_wake_queue is only appropriate
+ * so long as all callers are assured to have free tx slots
+ * (such as after niu_init_hw).
+ */
+ netif_wake_queue(np->dev);
+
+ niu_enable_napi(np);
+
+ niu_enable_interrupts(np, 1);
+}
+
+static void niu_reset_task(struct work_struct *work)
+{
+ struct niu *np = container_of(work, struct niu, reset_task);
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&np->lock, flags);
+ if (!netif_running(np->dev)) {
+ spin_unlock_irqrestore(&np->lock, flags);
+ return;
+ }
+
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ del_timer_sync(&np->timer);
+
+ niu_netif_stop(np);
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ niu_stop_hw(np);
+
+ err = niu_init_hw(np);
+ if (!err) {
+ np->timer.expires = jiffies + HZ;
+ add_timer(&np->timer);
+ niu_netif_start(np);
+ }
+
+ spin_unlock_irqrestore(&np->lock, flags);
+}
+
+static void niu_tx_timeout(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+
+ dev_err(np->device, PFX "%s: Transmit timed out, resetting\n",
+ dev->name);
+
+ schedule_work(&np->reset_task);
+}
+
+static void niu_set_txd(struct tx_ring_info *rp, int index,
+ u64 mapping, u64 len, u64 mark,
+ u64 n_frags)
+{
+ __le64 *desc = &rp->descr[index];
+
+ *desc = cpu_to_le64(mark |
+ (n_frags << TX_DESC_NUM_PTR_SHIFT) |
+ (len << TX_DESC_TR_LEN_SHIFT) |
+ (mapping & TX_DESC_SAD));
+}
+
+static u64 niu_compute_tx_flags(struct sk_buff *skb, struct ethhdr *ehdr,
+ u64 pad_bytes, u64 len)
+{
+ u16 eth_proto, eth_proto_inner;
+ u64 csum_bits, l3off, ihl, ret;
+ u8 ip_proto;
+ int ipv6;
+
+ eth_proto = be16_to_cpu(ehdr->h_proto);
+ eth_proto_inner = eth_proto;
+ if (eth_proto == ETH_P_8021Q) {
+ struct vlan_ethhdr *vp = (struct vlan_ethhdr *) ehdr;
+ __be16 val = vp->h_vlan_encapsulated_proto;
+
+ eth_proto_inner = be16_to_cpu(val);
+ }
+
+ ipv6 = ihl = 0;
+ switch (skb->protocol) {
+ case __constant_htons(ETH_P_IP):
+ ip_proto = ip_hdr(skb)->protocol;
+ ihl = ip_hdr(skb)->ihl;
+ break;
+ case __constant_htons(ETH_P_IPV6):
+ ip_proto = ipv6_hdr(skb)->nexthdr;
+ ihl = (40 >> 2);
+ ipv6 = 1;
+ break;
+ default:
+ ip_proto = ihl = 0;
+ break;
+ }
+
+ csum_bits = TXHDR_CSUM_NONE;
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ u64 start, stuff;
+
+ csum_bits = (ip_proto == IPPROTO_TCP ?
+ TXHDR_CSUM_TCP :
+ (ip_proto == IPPROTO_UDP ?
+ TXHDR_CSUM_UDP : TXHDR_CSUM_SCTP));
+
+ start = skb_transport_offset(skb) -
+ (pad_bytes + sizeof(struct tx_pkt_hdr));
+ stuff = start + skb->csum_offset;
+
+ csum_bits |= (start / 2) << TXHDR_L4START_SHIFT;
+ csum_bits |= (stuff / 2) << TXHDR_L4STUFF_SHIFT;
+ }
+
+ l3off = skb_network_offset(skb) -
+ (pad_bytes + sizeof(struct tx_pkt_hdr));
+
+ ret = (((pad_bytes / 2) << TXHDR_PAD_SHIFT) |
+ (len << TXHDR_LEN_SHIFT) |
+ ((l3off / 2) << TXHDR_L3START_SHIFT) |
+ (ihl << TXHDR_IHL_SHIFT) |
+ ((eth_proto_inner < 1536) ? TXHDR_LLC : 0) |
+ ((eth_proto == ETH_P_8021Q) ? TXHDR_VLAN : 0) |
+ (ipv6 ? TXHDR_IP_VER : 0) |
+ csum_bits);
+
+ return ret;
+}
+
+static struct tx_ring_info *tx_ring_select(struct niu *np, struct sk_buff *skb)
+{
+ return &np->tx_rings[0];
+}
+
+static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+ unsigned long align, headroom;
+ struct tx_ring_info *rp;
+ struct tx_pkt_hdr *tp;
+ unsigned int len, nfg;
+ struct ethhdr *ehdr;
+ int prod, i, tlen;
+ u64 mapping, mrk;
+
+ rp = tx_ring_select(np, skb);
+
+ if (niu_tx_avail(rp) <= (skb_shinfo(skb)->nr_frags + 1)) {
+ netif_stop_queue(dev);
+ dev_err(np->device, PFX "%s: BUG! Tx ring full when "
+ "queue awake!\n", dev->name);
+ rp->tx_errors++;
+ return NETDEV_TX_BUSY;
+ }
+
+ if (skb->len < ETH_ZLEN) {
+ unsigned int pad_bytes = ETH_ZLEN - skb->len;
+
+ if (skb_pad(skb, pad_bytes))
+ goto out;
+ skb_put(skb, pad_bytes);
+ }
+
+ len = sizeof(struct tx_pkt_hdr) + 15;
+ if (skb_headroom(skb) < len) {
+ struct sk_buff *skb_new;
+
+ skb_new = skb_realloc_headroom(skb, len);
+ if (!skb_new) {
+ rp->tx_errors++;
+ goto out_drop;
+ }
+ kfree_skb(skb);
+ skb = skb_new;
+ }
+
+ align = ((unsigned long) skb->data & (16 - 1));
+ headroom = align + sizeof(struct tx_pkt_hdr);
+
+ ehdr = (struct ethhdr *) skb->data;
+ tp = (struct tx_pkt_hdr *) skb_push(skb, headroom);
+
+ len = skb->len - sizeof(struct tx_pkt_hdr);
+ tp->flags = cpu_to_le64(niu_compute_tx_flags(skb, ehdr, align, len));
+ tp->resv = 0;
+
+ len = skb_headlen(skb);
+ mapping = np->ops->map_single(np->device, skb->data,
+ len, DMA_TO_DEVICE);
+
+ prod = rp->prod;
+
+ rp->tx_buffs[prod].skb = skb;
+ rp->tx_buffs[prod].mapping = mapping;
+
+ mrk = TX_DESC_SOP;
+ if (++rp->mark_counter == rp->mark_freq) {
+ rp->mark_counter = 0;
+ mrk |= TX_DESC_MARK;
+ rp->mark_pending++;
+ }
+
+ tlen = len;
+ nfg = skb_shinfo(skb)->nr_frags;
+ while (tlen > 0) {
+ tlen -= MAX_TX_DESC_LEN;
+ nfg++;
+ }
+
+ while (len > 0) {
+ unsigned int this_len = len;
+
+ if (this_len > MAX_TX_DESC_LEN)
+ this_len = MAX_TX_DESC_LEN;
+
+ niu_set_txd(rp, prod, mapping, this_len, mrk, nfg);
+ mrk = nfg = 0;
+
+ prod = NEXT_TX(rp, prod);
+ mapping += this_len;
+ len -= this_len;
+ }
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ len = frag->size;
+ mapping = np->ops->map_page(np->device, frag->page,
+ frag->page_offset, len,
+ DMA_TO_DEVICE);
+
+ rp->tx_buffs[prod].skb = NULL;
+ rp->tx_buffs[prod].mapping = mapping;
+
+ niu_set_txd(rp, prod, mapping, len, 0, 0);
+
+ prod = NEXT_TX(rp, prod);
+ }
+
+ if (prod < rp->prod)
+ rp->wrap_bit ^= TX_RING_KICK_WRAP;
+ rp->prod = prod;
+
+ nw64(TX_RING_KICK(rp->tx_channel), rp->wrap_bit | (prod << 3));
+
+ if (unlikely(niu_tx_avail(rp) <= (MAX_SKB_FRAGS + 1))) {
+ netif_stop_queue(dev);
+ if (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp))
+ netif_wake_queue(dev);
+ }
+
+ dev->trans_start = jiffies;
+
+out:
+ return NETDEV_TX_OK;
+
+out_drop:
+ rp->tx_errors++;
+ kfree_skb(skb);
+ goto out;
+}
+
+static int niu_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct niu *np = netdev_priv(dev);
+ int err, orig_jumbo, new_jumbo;
+
+ if (new_mtu < 68 || new_mtu > NIU_MAX_MTU)
+ return -EINVAL;
+
+ orig_jumbo = (dev->mtu > ETH_DATA_LEN);
+ new_jumbo = (new_mtu > ETH_DATA_LEN);
+
+ dev->mtu = new_mtu;
+
+ if (!netif_running(dev) ||
+ (orig_jumbo == new_jumbo))
+ return 0;
+
+ niu_full_shutdown(np, dev);
+
+ niu_free_channels(np);
+
+ niu_enable_napi(np);
+
+ err = niu_alloc_channels(np);
+ if (err)
+ return err;
+
+ spin_lock_irq(&np->lock);
+
+ err = niu_init_hw(np);
+ if (!err) {
+ init_timer(&np->timer);
+ np->timer.expires = jiffies + HZ;
+ np->timer.data = (unsigned long) np;
+ np->timer.function = niu_timer;
+
+ err = niu_enable_interrupts(np, 1);
+ if (err)
+ niu_stop_hw(np);
+ }
+
+ spin_unlock_irq(&np->lock);
+
+ if (!err) {
+ netif_start_queue(dev);
+ if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+ netif_carrier_on(dev);
+
+ add_timer(&np->timer);
+ }
+
+ return err;
+}
+
+static void niu_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct niu *np = netdev_priv(dev);
+ struct niu_vpd *vpd = &np->vpd;
+
+ strcpy(info->driver, DRV_MODULE_NAME);
+ strcpy(info->version, DRV_MODULE_VERSION);
+ sprintf(info->fw_version, "%d.%d",
+ vpd->fcode_major, vpd->fcode_minor);
+ if (np->parent->plat_type != PLAT_TYPE_NIU)
+ strcpy(info->bus_info, pci_name(np->pdev));
+}
+
+static int niu_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct niu *np = netdev_priv(dev);
+ struct niu_link_config *lp;
+
+ lp = &np->link_config;
+
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->phy_address = np->phy_addr;
+ cmd->supported = lp->supported;
+ cmd->advertising = lp->advertising;
+ cmd->autoneg = lp->autoneg;
+ cmd->speed = lp->active_speed;
+ cmd->duplex = lp->active_duplex;
+
+ return 0;
+}
+
+static int niu_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ return -EINVAL;
+}
+
+static u32 niu_get_msglevel(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+ return np->msg_enable;
+}
+
+static void niu_set_msglevel(struct net_device *dev, u32 value)
+{
+ struct niu *np = netdev_priv(dev);
+ np->msg_enable = value;
+}
+
+static int niu_get_eeprom_len(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+
+ return np->eeprom_len;
+}
+
+static int niu_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct niu *np = netdev_priv(dev);
+ u32 offset, len, val;
+
+ offset = eeprom->offset;
+ len = eeprom->len;
+
+ if (offset + len < offset)
+ return -EINVAL;
+ if (offset >= np->eeprom_len)
+ return -EINVAL;
+ if (offset + len > np->eeprom_len)
+ len = eeprom->len = np->eeprom_len - offset;
+
+ if (offset & 3) {
+ u32 b_offset, b_count;
+
+ b_offset = offset & 3;
+ b_count = 4 - b_offset;
+ if (b_count > len)
+ b_count = len;
+
+ val = nr64(ESPC_NCR((offset - b_offset) / 4));
+ memcpy(data, ((char *)&val) + b_offset, b_count);
+ data += b_count;
+ len -= b_count;
+ offset += b_count;
+ }
+ while (len >= 4) {
+ val = nr64(ESPC_NCR(offset / 4));
+ memcpy(data, &val, 4);
+ data += 4;
+ len -= 4;
+ offset += 4;
+ }
+ if (len) {
+ val = nr64(ESPC_NCR(offset / 4));
+ memcpy(data, &val, len);
+ }
+ return 0;
+}
+
+static const struct {
+ const char string[ETH_GSTRING_LEN];
+} niu_xmac_stat_keys[] = {
+ { "tx_frames" },
+ { "tx_bytes" },
+ { "tx_fifo_errors" },
+ { "tx_overflow_errors" },
+ { "tx_max_pkt_size_errors" },
+ { "tx_underflow_errors" },
+ { "rx_local_faults" },
+ { "rx_remote_faults" },
+ { "rx_link_faults" },
+ { "rx_align_errors" },
+ { "rx_frags" },
+ { "rx_mcasts" },
+ { "rx_bcasts" },
+ { "rx_hist_cnt1" },
+ { "rx_hist_cnt2" },
+ { "rx_hist_cnt3" },
+ { "rx_hist_cnt4" },
+ { "rx_hist_cnt5" },
+ { "rx_hist_cnt6" },
+ { "rx_hist_cnt7" },
+ { "rx_octets" },
+ { "rx_code_violations" },
+ { "rx_len_errors" },
+ { "rx_crc_errors" },
+ { "rx_underflows" },
+ { "rx_overflows" },
+ { "pause_off_state" },
+ { "pause_on_state" },
+ { "pause_received" },
+};
+
+#define NUM_XMAC_STAT_KEYS ARRAY_SIZE(niu_xmac_stat_keys)
+
+static const struct {
+ const char string[ETH_GSTRING_LEN];
+} niu_bmac_stat_keys[] = {
+ { "tx_underflow_errors" },
+ { "tx_max_pkt_size_errors" },
+ { "tx_bytes" },
+ { "tx_frames" },
+ { "rx_overflows" },
+ { "rx_frames" },
+ { "rx_align_errors" },
+ { "rx_crc_errors" },
+ { "rx_len_errors" },
+ { "pause_off_state" },
+ { "pause_on_state" },
+ { "pause_received" },
+};
+
+#define NUM_BMAC_STAT_KEYS ARRAY_SIZE(niu_bmac_stat_keys)
+
+static const struct {
+ const char string[ETH_GSTRING_LEN];
+} niu_rxchan_stat_keys[] = {
+ { "rx_channel" },
+ { "rx_packets" },
+ { "rx_bytes" },
+ { "rx_dropped" },
+ { "rx_errors" },
+};
+
+#define NUM_RXCHAN_STAT_KEYS ARRAY_SIZE(niu_rxchan_stat_keys)
+
+static const struct {
+ const char string[ETH_GSTRING_LEN];
+} niu_txchan_stat_keys[] = {
+ { "tx_channel" },
+ { "tx_packets" },
+ { "tx_bytes" },
+ { "tx_errors" },
+};
+
+#define NUM_TXCHAN_STAT_KEYS ARRAY_SIZE(niu_txchan_stat_keys)
+
+static void niu_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ struct niu *np = netdev_priv(dev);
+ int i;
+
+ if (stringset != ETH_SS_STATS)
+ return;
+
+ if (np->flags & NIU_FLAGS_XMAC) {
+ memcpy(data, niu_xmac_stat_keys,
+ sizeof(niu_xmac_stat_keys));
+ data += sizeof(niu_xmac_stat_keys);
+ } else {
+ memcpy(data, niu_bmac_stat_keys,
+ sizeof(niu_bmac_stat_keys));
+ data += sizeof(niu_bmac_stat_keys);
+ }
+ for (i = 0; i < np->num_rx_rings; i++) {
+ memcpy(data, niu_rxchan_stat_keys,
+ sizeof(niu_rxchan_stat_keys));
+ data += sizeof(niu_rxchan_stat_keys);
+ }
+ for (i = 0; i < np->num_tx_rings; i++) {
+ memcpy(data, niu_txchan_stat_keys,
+ sizeof(niu_txchan_stat_keys));
+ data += sizeof(niu_txchan_stat_keys);
+ }
+}
+
+static int niu_get_stats_count(struct net_device *dev)
+{
+ struct niu *np = netdev_priv(dev);
+
+ return ((np->flags & NIU_FLAGS_XMAC ?
+ NUM_XMAC_STAT_KEYS :
+ NUM_BMAC_STAT_KEYS) +
+ (np->num_rx_rings * NUM_RXCHAN_STAT_KEYS) +
+ (np->num_tx_rings * NUM_TXCHAN_STAT_KEYS));
+}
+
+static void niu_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct niu *np = netdev_priv(dev);
+ int i;
+
+ niu_sync_mac_stats(np);
+ if (np->flags & NIU_FLAGS_XMAC) {
+ memcpy(data, &np->mac_stats.xmac,
+ sizeof(struct niu_xmac_stats));
+ data += (sizeof(struct niu_xmac_stats) / sizeof(u64));
+ } else {
+ memcpy(data, &np->mac_stats.bmac,
+ sizeof(struct niu_bmac_stats));
+ data += (sizeof(struct niu_bmac_stats) / sizeof(u64));
+ }
+ for (i = 0; i < np->num_rx_rings; i++) {
+ struct rx_ring_info *rp = &np->rx_rings[i];
+
+ data[0] = rp->rx_channel;
+ data[1] = rp->rx_packets;
+ data[2] = rp->rx_bytes;
+ data[3] = rp->rx_dropped;
+ data[4] = rp->rx_errors;
+ data += 5;
+ }
+ for (i = 0; i < np->num_tx_rings; i++) {
+ struct tx_ring_info *rp = &np->tx_rings[i];
+
+ data[0] = rp->tx_channel;
+ data[1] = rp->tx_packets;
+ data[2] = rp->tx_bytes;
+ data[3] = rp->tx_errors;
+ data += 4;
+ }
+}
+
+static u64 niu_led_state_save(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ return nr64_mac(XMAC_CONFIG);
+ else
+ return nr64_mac(BMAC_XIF_CONFIG);
+}
+
+static void niu_led_state_restore(struct niu *np, u64 val)
+{
+ if (np->flags & NIU_FLAGS_XMAC)
+ nw64_mac(XMAC_CONFIG, val);
+ else
+ nw64_mac(BMAC_XIF_CONFIG, val);
+}
+
+static void niu_force_led(struct niu *np, int on)
+{
+ u64 val, reg, bit;
+
+ if (np->flags & NIU_FLAGS_XMAC) {
+ reg = XMAC_CONFIG;
+ bit = XMAC_CONFIG_FORCE_LED_ON;
+ } else {
+ reg = BMAC_XIF_CONFIG;
+ bit = BMAC_XIF_CONFIG_LINK_LED;
+ }
+
+ val = nr64_mac(reg);
+ if (on)
+ val |= bit;
+ else
+ val &= ~bit;
+ nw64_mac(reg, val);
+}
+
+static int niu_phys_id(struct net_device *dev, u32 data)
+{
+ struct niu *np = netdev_priv(dev);
+ u64 orig_led_state;
+ int i;
+
+ if (!netif_running(dev))
+ return -EAGAIN;
+
+ if (data == 0)
+ data = 2;
+
+ orig_led_state = niu_led_state_save(np);
+ for (i = 0; i < (data * 2); i++) {
+ int on = ((i % 2) == 0);
+
+ niu_force_led(np, on);
+
+ if (msleep_interruptible(500))
+ break;
+ }
+ niu_led_state_restore(np, orig_led_state);
+
+ return 0;
+}
+
+static const struct ethtool_ops niu_ethtool_ops = {
+ .get_drvinfo = niu_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = niu_get_msglevel,
+ .set_msglevel = niu_set_msglevel,
+ .get_eeprom_len = niu_get_eeprom_len,
+ .get_eeprom = niu_get_eeprom,
+ .get_settings = niu_get_settings,
+ .set_settings = niu_set_settings,
+ .get_strings = niu_get_strings,
+ .get_stats_count = niu_get_stats_count,
+ .get_ethtool_stats = niu_get_ethtool_stats,
+ .phys_id = niu_phys_id,
+};
+
+static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent,
+ int ldg, int ldn)
+{
+ if (ldg < NIU_LDG_MIN || ldg > NIU_LDG_MAX)
+ return -EINVAL;
+ if (ldn < 0 || ldn > LDN_MAX)
+ return -EINVAL;
+
+ parent->ldg_map[ldn] = ldg;
+
+ if (np->parent->plat_type == PLAT_TYPE_NIU) {
+ /* On N2 NIU, the ldn-->ldg assignments are setup and fixed by
+ * the firmware, and we're not supposed to change them.
+ * Validate the mapping, because if it's wrong we probably
+ * won't get any interrupts and that's painful to debug.
+ */
+ if (nr64(LDG_NUM(ldn)) != ldg) {
+ dev_err(np->device, PFX "Port %u, mis-matched "
+ "LDG assignment "
+ "for ldn %d, should be %d is %llu\n",
+ np->port, ldn, ldg,
+ (unsigned long long) nr64(LDG_NUM(ldn)));
+ return -EINVAL;
+ }
+ } else
+ nw64(LDG_NUM(ldn), ldg);
+
+ return 0;
+}
+
+static int niu_set_ldg_timer_res(struct niu *np, int res)
+{
+ if (res < 0 || res > LDG_TIMER_RES_VAL)
+ return -EINVAL;
+
+
+ nw64(LDG_TIMER_RES, res);
+
+ return 0;
+}
+
+static int niu_set_ldg_sid(struct niu *np, int ldg, int func, int vector)
+{
+ if ((ldg < NIU_LDG_MIN || ldg > NIU_LDG_MAX) ||
+ (func < 0 || func > 3) ||
+ (vector < 0 || vector > 0x1f))
+ return -EINVAL;
+
+ nw64(SID(ldg), (func << SID_FUNC_SHIFT) | vector);
+
+ return 0;
+}
+
+static int __devinit niu_pci_eeprom_read(struct niu *np, u32 addr)
+{
+ u64 frame, frame_base = (ESPC_PIO_STAT_READ_START |
+ (addr << ESPC_PIO_STAT_ADDR_SHIFT));
+ int limit;
+
+ if (addr > (ESPC_PIO_STAT_ADDR >> ESPC_PIO_STAT_ADDR_SHIFT))
+ return -EINVAL;
+
+ frame = frame_base;
+ nw64(ESPC_PIO_STAT, frame);
+ limit = 64;
+ do {
+ udelay(5);
+ frame = nr64(ESPC_PIO_STAT);
+ if (frame & ESPC_PIO_STAT_READ_END)
+ break;
+ } while (limit--);
+ if (!(frame & ESPC_PIO_STAT_READ_END)) {
+ dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n",
+ (unsigned long long) frame);
+ return -ENODEV;
+ }
+
+ frame = frame_base;
+ nw64(ESPC_PIO_STAT, frame);
+ limit = 64;
+ do {
+ udelay(5);
+ frame = nr64(ESPC_PIO_STAT);
+ if (frame & ESPC_PIO_STAT_READ_END)
+ break;
+ } while (limit--);
+ if (!(frame & ESPC_PIO_STAT_READ_END)) {
+ dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n",
+ (unsigned long long) frame);
+ return -ENODEV;
+ }
+
+ frame = nr64(ESPC_PIO_STAT);
+ return (frame & ESPC_PIO_STAT_DATA) >> ESPC_PIO_STAT_DATA_SHIFT;
+}
+
+static int __devinit niu_pci_eeprom_read16(struct niu *np, u32 off)
+{
+ int err = niu_pci_eeprom_read(np, off);
+ u16 val;
+
+ if (err < 0)
+ return err;
+ val = (err << 8);
+ err = niu_pci_eeprom_read(np, off + 1);
+ if (err < 0)
+ return err;
+ val |= (err & 0xff);
+
+ return val;
+}
+
+static int __devinit niu_pci_eeprom_read16_swp(struct niu *np, u32 off)
+{
+ int err = niu_pci_eeprom_read(np, off);
+ u16 val;
+
+ if (err < 0)
+ return err;
+
+ val = (err & 0xff);
+ err = niu_pci_eeprom_read(np, off + 1);
+ if (err < 0)
+ return err;
+
+ val |= (err & 0xff) << 8;
+
+ return val;
+}
+
+static int __devinit niu_pci_vpd_get_propname(struct niu *np,
+ u32 off,
+ char *namebuf,
+ int namebuf_len)
+{
+ int i;
+
+ for (i = 0; i < namebuf_len; i++) {
+ int err = niu_pci_eeprom_read(np, off + i);
+ if (err < 0)
+ return err;
+ *namebuf++ = err;
+ if (!err)
+ break;
+ }
+ if (i >= namebuf_len)
+ return -EINVAL;
+
+ return i + 1;
+}
+
+static void __devinit niu_vpd_parse_version(struct niu *np)
+{
+ struct niu_vpd *vpd = &np->vpd;
+ int len = strlen(vpd->version) + 1;
+ const char *s = vpd->version;
+ int i;
+
+ for (i = 0; i < len - 5; i++) {
+ if (!strncmp(s + i, "FCode ", 5))
+ break;
+ }
+ if (i >= len - 5)
+ return;
+
+ s += i + 5;
+ sscanf(s, "%d.%d", &vpd->fcode_major, &vpd->fcode_minor);
+
+ niudbg(PROBE, "VPD_SCAN: FCODE major(%d) minor(%d)\n",
+ vpd->fcode_major, vpd->fcode_minor);
+ if (vpd->fcode_major > NIU_VPD_MIN_MAJOR ||
+ (vpd->fcode_major == NIU_VPD_MIN_MAJOR &&
+ vpd->fcode_minor >= NIU_VPD_MIN_MINOR))
+ np->flags |= NIU_FLAGS_VPD_VALID;
+}
+
+/* ESPC_PIO_EN_ENABLE must be set */
+static int __devinit niu_pci_vpd_scan_props(struct niu *np,
+ u32 start, u32 end)
+{
+ unsigned int found_mask = 0;
+#define FOUND_MASK_MODEL 0x00000001
+#define FOUND_MASK_BMODEL 0x00000002
+#define FOUND_MASK_VERS 0x00000004
+#define FOUND_MASK_MAC 0x00000008
+#define FOUND_MASK_NMAC 0x00000010
+#define FOUND_MASK_PHY 0x00000020
+#define FOUND_MASK_ALL 0x0000003f
+
+ niudbg(PROBE, "VPD_SCAN: start[%x] end[%x]\n",
+ start, end);
+ while (start < end) {
+ int len, err, instance, type, prop_len;
+ char namebuf[64];
+ u8 *prop_buf;
+ int max_len;
+
+ if (found_mask == FOUND_MASK_ALL) {
+ niu_vpd_parse_version(np);
+ return 1;
+ }
+
+ err = niu_pci_eeprom_read(np, start + 2);
+ if (err < 0)
+ return err;
+ len = err;
+ start += 3;
+
+ instance = niu_pci_eeprom_read(np, start);
+ type = niu_pci_eeprom_read(np, start + 3);
+ prop_len = niu_pci_eeprom_read(np, start + 4);
+ err = niu_pci_vpd_get_propname(np, start + 5, namebuf, 64);
+ if (err < 0)
+ return err;
+
+ prop_buf = NULL;
+ max_len = 0;
+ if (!strcmp(namebuf, "model")) {
+ prop_buf = np->vpd.model;
+ max_len = NIU_VPD_MODEL_MAX;
+ found_mask |= FOUND_MASK_MODEL;
+ } else if (!strcmp(namebuf, "board-model")) {
+ prop_buf = np->vpd.board_model;
+ max_len = NIU_VPD_BD_MODEL_MAX;
+ found_mask |= FOUND_MASK_BMODEL;
+ } else if (!strcmp(namebuf, "version")) {
+ prop_buf = np->vpd.version;
+ max_len = NIU_VPD_VERSION_MAX;
+ found_mask |= FOUND_MASK_VERS;
+ } else if (!strcmp(namebuf, "local-mac-address")) {
+ prop_buf = np->vpd.local_mac;
+ max_len = ETH_ALEN;
+ found_mask |= FOUND_MASK_MAC;
+ } else if (!strcmp(namebuf, "num-mac-addresses")) {
+ prop_buf = &np->vpd.mac_num;
+ max_len = 1;
+ found_mask |= FOUND_MASK_NMAC;
+ } else if (!strcmp(namebuf, "phy-type")) {
+ prop_buf = np->vpd.phy_type;
+ max_len = NIU_VPD_PHY_TYPE_MAX;
+ found_mask |= FOUND_MASK_PHY;
+ }
+
+ if (max_len && prop_len > max_len) {
+ dev_err(np->device, PFX "Property '%s' length (%d) is "
+ "too long.\n", namebuf, prop_len);
+ return -EINVAL;
+ }
+
+ if (prop_buf) {
+ u32 off = start + 5 + err;
+ int i;
+
+ niudbg(PROBE, "VPD_SCAN: Reading in property [%s] "
+ "len[%d]\n", namebuf, prop_len);
+ for (i = 0; i < prop_len; i++)
+ *prop_buf++ = niu_pci_eeprom_read(np, off + i);
+ }
+
+ start += len;
+ }
+
+ return 0;
+}
+
+/* ESPC_PIO_EN_ENABLE must be set */
+static void __devinit niu_pci_vpd_fetch(struct niu *np, u32 start)
+{
+ u32 offset;
+ int err;
+
+ err = niu_pci_eeprom_read16_swp(np, start + 1);
+ if (err < 0)
+ return;
+
+ offset = err + 3;
+
+ while (start + offset < ESPC_EEPROM_SIZE) {
+ u32 here = start + offset;
+ u32 end;
+
+ err = niu_pci_eeprom_read(np, here);
+ if (err != 0x90)
+ return;
+
+ err = niu_pci_eeprom_read16_swp(np, here + 1);
+ if (err < 0)
+ return;
+
+ here = start + offset + 3;
+ end = start + offset + err;
+
+ offset += err;
+
+ err = niu_pci_vpd_scan_props(np, here, end);
+ if (err < 0 || err == 1)
+ return;
+ }
+}
+
+/* ESPC_PIO_EN_ENABLE must be set */
+static u32 __devinit niu_pci_vpd_offset(struct niu *np)
+{
+ u32 start = 0, end = ESPC_EEPROM_SIZE, ret;
+ int err;
+
+ while (start < end) {
+ ret = start;
+
+ /* ROM header signature? */
+ err = niu_pci_eeprom_read16(np, start + 0);
+ if (err != 0x55aa)
+ return 0;
+
+ /* Apply offset to PCI data structure. */
+ err = niu_pci_eeprom_read16(np, start + 23);
+ if (err < 0)
+ return 0;
+ start += err;
+
+ /* Check for "PCIR" signature. */
+ err = niu_pci_eeprom_read16(np, start + 0);
+ if (err != 0x5043)
+ return 0;
+ err = niu_pci_eeprom_read16(np, start + 2);
+ if (err != 0x4952)
+ return 0;
+
+ /* Check for OBP image type. */
+ err = niu_pci_eeprom_read(np, start + 20);
+ if (err < 0)
+ return 0;
+ if (err != 0x01) {
+ err = niu_pci_eeprom_read(np, ret + 2);
+ if (err < 0)
+ return 0;
+
+ start = ret + (err * 512);
+ continue;
+ }
+
+ err = niu_pci_eeprom_read16_swp(np, start + 8);
+ if (err < 0)
+ return err;
+ ret += err;
+
+ err = niu_pci_eeprom_read(np, ret + 0);
+ if (err != 0x82)
+ return 0;
+
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __devinit niu_phy_type_prop_decode(struct niu *np,
+ const char *phy_prop)
+{
+ if (!strcmp(phy_prop, "mif")) {
+ /* 1G copper, MII */
+ np->flags &= ~(NIU_FLAGS_FIBER |
+ NIU_FLAGS_10G);
+ np->mac_xcvr = MAC_XCVR_MII;
+ } else if (!strcmp(phy_prop, "xgf")) {
+ /* 10G fiber, XPCS */
+ np->flags |= (NIU_FLAGS_10G |
+ NIU_FLAGS_FIBER);
+ np->mac_xcvr = MAC_XCVR_XPCS;
+ } else if (!strcmp(phy_prop, "pcs")) {
+ /* 1G fiber, PCS */
+ np->flags &= ~NIU_FLAGS_10G;
+ np->flags |= NIU_FLAGS_FIBER;
+ np->mac_xcvr = MAC_XCVR_PCS;
+ } else if (!strcmp(phy_prop, "xgc")) {
+ /* 10G copper, XPCS */
+ np->flags |= NIU_FLAGS_10G;
+ np->flags &= ~NIU_FLAGS_FIBER;
+ np->mac_xcvr = MAC_XCVR_XPCS;
+ } else {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void __devinit niu_pci_vpd_validate(struct niu *np)
+{
+ struct net_device *dev = np->dev;
+ struct niu_vpd *vpd = &np->vpd;
+ u8 val8;
+
+ if (!is_valid_ether_addr(&vpd->local_mac[0])) {
+ dev_err(np->device, PFX "VPD MAC invalid, "
+ "falling back to SPROM.\n");
+
+ np->flags &= ~NIU_FLAGS_VPD_VALID;
+ return;
+ }
+
+ if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
+ dev_err(np->device, PFX "Illegal phy string [%s].\n",
+ np->vpd.phy_type);
+ dev_err(np->device, PFX "Falling back to SPROM.\n");
+ np->flags &= ~NIU_FLAGS_VPD_VALID;
+ return;
+ }
+
+ memcpy(dev->perm_addr, vpd->local_mac, ETH_ALEN);
+
+ val8 = dev->perm_addr[5];
+ dev->perm_addr[5] += np->port;
+ if (dev->perm_addr[5] < val8)
+ dev->perm_addr[4]++;
+
+ memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+}
+
+static int __devinit niu_pci_probe_sprom(struct niu *np)
+{
+ struct net_device *dev = np->dev;
+ int len, i;
+ u64 val, sum;
+ u8 val8;
+
+ val = (nr64(ESPC_VER_IMGSZ) & ESPC_VER_IMGSZ_IMGSZ);
+ val >>= ESPC_VER_IMGSZ_IMGSZ_SHIFT;
+ len = val / 4;
+
+ np->eeprom_len = len;
+
+ niudbg(PROBE, "SPROM: Image size %llu\n", (unsigned long long) val);
+
+ sum = 0;
+ for (i = 0; i < len; i++) {
+ val = nr64(ESPC_NCR(i));
+ sum += (val >> 0) & 0xff;
+ sum += (val >> 8) & 0xff;
+ sum += (val >> 16) & 0xff;
+ sum += (val >> 24) & 0xff;
+ }
+ niudbg(PROBE, "SPROM: Checksum %x\n", (int)(sum & 0xff));
+ if ((sum & 0xff) != 0xab) {
+ dev_err(np->device, PFX "Bad SPROM checksum "
+ "(%x, should be 0xab)\n", (int) (sum & 0xff));
+ return -EINVAL;
+ }
+
+ val = nr64(ESPC_PHY_TYPE);
+ switch (np->port) {
+ case 0:
+ val8 = (val & ESPC_PHY_TYPE_PORT0) >>
+ ESPC_PHY_TYPE_PORT0_SHIFT;
+ break;
+ case 1:
+ val8 = (val & ESPC_PHY_TYPE_PORT1) >>
+ ESPC_PHY_TYPE_PORT1_SHIFT;
+ break;
+ case 2:
+ val8 = (val & ESPC_PHY_TYPE_PORT2) >>
+ ESPC_PHY_TYPE_PORT2_SHIFT;
+ break;
+ case 3:
+ val8 = (val & ESPC_PHY_TYPE_PORT3) >>
+ ESPC_PHY_TYPE_PORT3_SHIFT;
+ break;
+ default:
+ dev_err(np->device, PFX "Bogus port number %u\n",
+ np->port);
+ return -EINVAL;
+ }
+ niudbg(PROBE, "SPROM: PHY type %x\n", val8);
+
+ switch (val8) {
+ case ESPC_PHY_TYPE_1G_COPPER:
+ /* 1G copper, MII */
+ np->flags &= ~(NIU_FLAGS_FIBER |
+ NIU_FLAGS_10G);
+ np->mac_xcvr = MAC_XCVR_MII;
+ break;
+
+ case ESPC_PHY_TYPE_1G_FIBER:
+ /* 1G fiber, PCS */
+ np->flags &= ~NIU_FLAGS_10G;
+ np->flags |= NIU_FLAGS_FIBER;
+ np->mac_xcvr = MAC_XCVR_PCS;
+ break;
+
+ case ESPC_PHY_TYPE_10G_COPPER:
+ /* 10G copper, XPCS */
+ np->flags |= NIU_FLAGS_10G;
+ np->flags &= ~NIU_FLAGS_FIBER;
+ np->mac_xcvr = MAC_XCVR_XPCS;
+ break;
+
+ case ESPC_PHY_TYPE_10G_FIBER:
+ /* 10G fiber, XPCS */
+ np->flags |= (NIU_FLAGS_10G |
+ NIU_FLAGS_FIBER);
+ np->mac_xcvr = MAC_XCVR_XPCS;
+ break;
+
+ default:
+ dev_err(np->device, PFX "Bogus SPROM phy type %u\n", val8);
+ return -EINVAL;
+ }
+
+ val = nr64(ESPC_MAC_ADDR0);
+ niudbg(PROBE, "SPROM: MAC_ADDR0[%08llx]\n",
+ (unsigned long long) val);
+ dev->perm_addr[0] = (val >> 0) & 0xff;
+ dev->perm_addr[1] = (val >> 8) & 0xff;
+ dev->perm_addr[2] = (val >> 16) & 0xff;
+ dev->perm_addr[3] = (val >> 24) & 0xff;
+
+ val = nr64(ESPC_MAC_ADDR1);
+ niudbg(PROBE, "SPROM: MAC_ADDR1[%08llx]\n",
+ (unsigned long long) val);
+ dev->perm_addr[4] = (val >> 0) & 0xff;
+ dev->perm_addr[5] = (val >> 8) & 0xff;
+
+ if (!is_valid_ether_addr(&dev->perm_addr[0])) {
+ dev_err(np->device, PFX "SPROM MAC address invalid\n");
+ dev_err(np->device, PFX "[ \n");
+ for (i = 0; i < 6; i++)
+ printk("%02x ", dev->perm_addr[i]);
+ printk("]\n");
+ return -EINVAL;
+ }
+
+ val8 = dev->perm_addr[5];
+ dev->perm_addr[5] += np->port;
+ if (dev->perm_addr[5] < val8)
+ dev->perm_addr[4]++;
+
+ memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+
+ val = nr64(ESPC_MOD_STR_LEN);
+ niudbg(PROBE, "SPROM: MOD_STR_LEN[%llu]\n",
+ (unsigned long long) val);
+ if (val >= 8 * 4)
+ return -EINVAL;
+
+ for (i = 0; i < val; i += 4) {
+ u64 tmp = nr64(ESPC_NCR(5 + (i / 4)));
+
+ np->vpd.model[i + 3] = (tmp >> 0) & 0xff;
+ np->vpd.model[i + 2] = (tmp >> 8) & 0xff;
+ np->vpd.model[i + 1] = (tmp >> 16) & 0xff;
+ np->vpd.model[i + 0] = (tmp >> 24) & 0xff;
+ }
+ np->vpd.model[val] = '\0';
+
+ val = nr64(ESPC_BD_MOD_STR_LEN);
+ niudbg(PROBE, "SPROM: BD_MOD_STR_LEN[%llu]\n",
+ (unsigned long long) val);
+ if (val >= 4 * 4)
+ return -EINVAL;
+
+ for (i = 0; i < val; i += 4) {
+ u64 tmp = nr64(ESPC_NCR(14 + (i / 4)));
+
+ np->vpd.board_model[i + 3] = (tmp >> 0) & 0xff;
+ np->vpd.board_model[i + 2] = (tmp >> 8) & 0xff;
+ np->vpd.board_model[i + 1] = (tmp >> 16) & 0xff;
+ np->vpd.board_model[i + 0] = (tmp >> 24) & 0xff;
+ }
+ np->vpd.board_model[val] = '\0';
+
+ np->vpd.mac_num =
+ nr64(ESPC_NUM_PORTS_MACS) & ESPC_NUM_PORTS_MACS_VAL;
+ niudbg(PROBE, "SPROM: NUM_PORTS_MACS[%d]\n",
+ np->vpd.mac_num);
+
+ return 0;
+}
+
+static int __devinit niu_get_and_validate_port(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+
+ if (np->port <= 1)
+ np->flags |= NIU_FLAGS_XMAC;
+
+ if (!parent->num_ports) {
+ if (parent->plat_type == PLAT_TYPE_NIU) {
+ parent->num_ports = 2;
+ } else {
+ parent->num_ports = nr64(ESPC_NUM_PORTS_MACS) &
+ ESPC_NUM_PORTS_MACS_VAL;
+
+ if (!parent->num_ports)
+ parent->num_ports = 4;
+ }
+ }
+
+ niudbg(PROBE, "niu_get_and_validate_port: port[%d] num_ports[%d]\n",
+ np->port, parent->num_ports);
+ if (np->port >= parent->num_ports)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int __devinit phy_record(struct niu_parent *parent,
+ struct phy_probe_info *p,
+ int dev_id_1, int dev_id_2, u8 phy_port,
+ int type)
+{
+ u32 id = (dev_id_1 << 16) | dev_id_2;
+ u8 idx;
+
+ if (dev_id_1 < 0 || dev_id_2 < 0)
+ return 0;
+ if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) {
+ if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704)
+ return 0;
+ } else {
+ if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R)
+ return 0;
+ }
+
+ pr_info("niu%d: Found PHY %08x type %s at phy_port %u\n",
+ parent->index, id,
+ (type == PHY_TYPE_PMA_PMD ?
+ "PMA/PMD" :
+ (type == PHY_TYPE_PCS ?
+ "PCS" : "MII")),
+ phy_port);
+
+ if (p->cur[type] >= NIU_MAX_PORTS) {
+ printk(KERN_ERR PFX "Too many PHY ports.\n");
+ return -EINVAL;
+ }
+ idx = p->cur[type];
+ p->phy_id[type][idx] = id;
+ p->phy_port[type][idx] = phy_port;
+ p->cur[type] = idx + 1;
+ return 0;
+}
+
+static int __devinit port_has_10g(struct phy_probe_info *p, int port)
+{
+ int i;
+
+ for (i = 0; i < p->cur[PHY_TYPE_PMA_PMD]; i++) {
+ if (p->phy_port[PHY_TYPE_PMA_PMD][i] == port)
+ return 1;
+ }
+ for (i = 0; i < p->cur[PHY_TYPE_PCS]; i++) {
+ if (p->phy_port[PHY_TYPE_PCS][i] == port)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int __devinit count_10g_ports(struct phy_probe_info *p, int *lowest)
+{
+ int port, cnt;
+
+ cnt = 0;
+ *lowest = 32;
+ for (port = 8; port < 32; port++) {
+ if (port_has_10g(p, port)) {
+ if (!cnt)
+ *lowest = port;
+ cnt++;
+ }
+ }
+
+ return cnt;
+}
+
+static int __devinit count_1g_ports(struct phy_probe_info *p, int *lowest)
+{
+ *lowest = 32;
+ if (p->cur[PHY_TYPE_MII])
+ *lowest = p->phy_port[PHY_TYPE_MII][0];
+
+ return p->cur[PHY_TYPE_MII];
+}
+
+static void __devinit niu_n2_divide_channels(struct niu_parent *parent)
+{
+ int num_ports = parent->num_ports;
+ int i;
+
+ for (i = 0; i < num_ports; i++) {
+ parent->rxchan_per_port[i] = (16 / num_ports);
+ parent->txchan_per_port[i] = (16 / num_ports);
+
+ pr_info(PFX "niu%d: Port %u [%u RX chans] "
+ "[%u TX chans]\n",
+ parent->index, i,
+ parent->rxchan_per_port[i],
+ parent->txchan_per_port[i]);
+ }
+}
+
+static void __devinit niu_divide_channels(struct niu_parent *parent,
+ int num_10g, int num_1g)
+{
+ int num_ports = parent->num_ports;
+ int rx_chans_per_10g, rx_chans_per_1g;
+ int tx_chans_per_10g, tx_chans_per_1g;
+ int i, tot_rx, tot_tx;
+
+ if (!num_10g || !num_1g) {
+ rx_chans_per_10g = rx_chans_per_1g =
+ (NIU_NUM_RXCHAN / num_ports);
+ tx_chans_per_10g = tx_chans_per_1g =
+ (NIU_NUM_TXCHAN / num_ports);
+ } else {
+ rx_chans_per_1g = NIU_NUM_RXCHAN / 8;
+ rx_chans_per_10g = (NIU_NUM_RXCHAN -
+ (rx_chans_per_1g * num_1g)) /
+ num_10g;
+
+ tx_chans_per_1g = NIU_NUM_TXCHAN / 6;
+ tx_chans_per_10g = (NIU_NUM_TXCHAN -
+ (tx_chans_per_1g * num_1g)) /
+ num_10g;
+ }
+
+ tot_rx = tot_tx = 0;
+ for (i = 0; i < num_ports; i++) {
+ int type = phy_decode(parent->port_phy, i);
+
+ if (type == PORT_TYPE_10G) {
+ parent->rxchan_per_port[i] = rx_chans_per_10g;
+ parent->txchan_per_port[i] = tx_chans_per_10g;
+ } else {
+ parent->rxchan_per_port[i] = rx_chans_per_1g;
+ parent->txchan_per_port[i] = tx_chans_per_1g;
+ }
+ pr_info(PFX "niu%d: Port %u [%u RX chans] "
+ "[%u TX chans]\n",
+ parent->index, i,
+ parent->rxchan_per_port[i],
+ parent->txchan_per_port[i]);
+ tot_rx += parent->rxchan_per_port[i];
+ tot_tx += parent->txchan_per_port[i];
+ }
+
+ if (tot_rx > NIU_NUM_RXCHAN) {
+ printk(KERN_ERR PFX "niu%d: Too many RX channels (%d), "
+ "resetting to one per port.\n",
+ parent->index, tot_rx);
+ for (i = 0; i < num_ports; i++)
+ parent->rxchan_per_port[i] = 1;
+ }
+ if (tot_tx > NIU_NUM_TXCHAN) {
+ printk(KERN_ERR PFX "niu%d: Too many TX channels (%d), "
+ "resetting to one per port.\n",
+ parent->index, tot_tx);
+ for (i = 0; i < num_ports; i++)
+ parent->txchan_per_port[i] = 1;
+ }
+ if (tot_rx < NIU_NUM_RXCHAN || tot_tx < NIU_NUM_TXCHAN) {
+ printk(KERN_WARNING PFX "niu%d: Driver bug, wasted channels, "
+ "RX[%d] TX[%d]\n",
+ parent->index, tot_rx, tot_tx);
+ }
+}
+
+static void __devinit niu_divide_rdc_groups(struct niu_parent *parent,
+ int num_10g, int num_1g)
+{
+ int i, num_ports = parent->num_ports;
+ int rdc_group, rdc_groups_per_port;
+ int rdc_channel_base;
+
+ rdc_group = 0;
+ rdc_groups_per_port = NIU_NUM_RDC_TABLES / num_ports;
+
+ rdc_channel_base = 0;
+
+ for (i = 0; i < num_ports; i++) {
+ struct niu_rdc_tables *tp = &parent->rdc_group_cfg[i];
+ int grp, num_channels = parent->rxchan_per_port[i];
+ int this_channel_offset;
+
+ tp->first_table_num = rdc_group;
+ tp->num_tables = rdc_groups_per_port;
+ this_channel_offset = 0;
+ for (grp = 0; grp < tp->num_tables; grp++) {
+ struct rdc_table *rt = &tp->tables[grp];
+ int slot;
+
+ pr_info(PFX "niu%d: Port %d RDC tbl(%d) [ ",
+ parent->index, i, tp->first_table_num + grp);
+ for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++) {
+ rt->rxdma_channel[slot] =
+ rdc_channel_base + this_channel_offset;
+
+ printk("%d ", rt->rxdma_channel[slot]);
+
+ if (++this_channel_offset == num_channels)
+ this_channel_offset = 0;
+ }
+ printk("]\n");
+ }
+
+ parent->rdc_default[i] = rdc_channel_base;
+
+ rdc_channel_base += num_channels;
+ rdc_group += rdc_groups_per_port;
+ }
+}
+
+static int __devinit fill_phy_probe_info(struct niu *np,
+ struct niu_parent *parent,
+ struct phy_probe_info *info)
+{
+ unsigned long flags;
+ int port, err;
+
+ memset(info, 0, sizeof(*info));
+
+ /* Port 0 to 7 are reserved for onboard Serdes, probe the rest. */
+ niu_lock_parent(np, flags);
+ err = 0;
+ for (port = 8; port < 32; port++) {
+ int dev_id_1, dev_id_2;
+
+ dev_id_1 = mdio_read(np, port,
+ NIU_PMA_PMD_DEV_ADDR, MII_PHYSID1);
+ dev_id_2 = mdio_read(np, port,
+ NIU_PMA_PMD_DEV_ADDR, MII_PHYSID2);
+ err = phy_record(parent, info, dev_id_1, dev_id_2, port,
+ PHY_TYPE_PMA_PMD);
+ if (err)
+ break;
+ dev_id_1 = mdio_read(np, port,
+ NIU_PCS_DEV_ADDR, MII_PHYSID1);
+ dev_id_2 = mdio_read(np, port,
+ NIU_PCS_DEV_ADDR, MII_PHYSID2);
+ err = phy_record(parent, info, dev_id_1, dev_id_2, port,
+ PHY_TYPE_PCS);
+ if (err)
+ break;
+ dev_id_1 = mii_read(np, port, MII_PHYSID1);
+ dev_id_2 = mii_read(np, port, MII_PHYSID2);
+ err = phy_record(parent, info, dev_id_1, dev_id_2, port,
+ PHY_TYPE_MII);
+ if (err)
+ break;
+ }
+ niu_unlock_parent(np, flags);
+
+ return err;
+}
+
+static int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
+{
+ struct phy_probe_info *info = &parent->phy_probe_info;
+ int lowest_10g, lowest_1g;
+ int num_10g, num_1g;
+ u32 val;
+ int err;
+
+ err = fill_phy_probe_info(np, parent, info);
+ if (err)
+ return err;
+
+ num_10g = count_10g_ports(info, &lowest_10g);
+ num_1g = count_1g_ports(info, &lowest_1g);
+
+ switch ((num_10g << 4) | num_1g) {
+ case 0x24:
+ if (lowest_1g == 10)
+ parent->plat_type = PLAT_TYPE_VF_P0;
+ else if (lowest_1g == 26)
+ parent->plat_type = PLAT_TYPE_VF_P1;
+ else
+ goto unknown_vg_1g_port;
+
+ /* fallthru */
+ case 0x22:
+ val = (phy_encode(PORT_TYPE_10G, 0) |
+ phy_encode(PORT_TYPE_10G, 1) |
+ phy_encode(PORT_TYPE_1G, 2) |
+ phy_encode(PORT_TYPE_1G, 3));
+ break;
+
+ case 0x20:
+ val = (phy_encode(PORT_TYPE_10G, 0) |
+ phy_encode(PORT_TYPE_10G, 1));
+ break;
+
+ case 0x10:
+ val = phy_encode(PORT_TYPE_10G, np->port);
+ break;
+
+ case 0x14:
+ if (lowest_1g == 10)
+ parent->plat_type = PLAT_TYPE_VF_P0;
+ else if (lowest_1g == 26)
+ parent->plat_type = PLAT_TYPE_VF_P1;
+ else
+ goto unknown_vg_1g_port;
+
+ /* fallthru */
+ case 0x13:
+ if ((lowest_10g & 0x7) == 0)
+ val = (phy_encode(PORT_TYPE_10G, 0) |
+ phy_encode(PORT_TYPE_1G, 1) |
+ phy_encode(PORT_TYPE_1G, 2) |
+ phy_encode(PORT_TYPE_1G, 3));
+ else
+ val = (phy_encode(PORT_TYPE_1G, 0) |
+ phy_encode(PORT_TYPE_10G, 1) |
+ phy_encode(PORT_TYPE_1G, 2) |
+ phy_encode(PORT_TYPE_1G, 3));
+ break;
+
+ case 0x04:
+ if (lowest_1g == 10)
+ parent->plat_type = PLAT_TYPE_VF_P0;
+ else if (lowest_1g == 26)
+ parent->plat_type = PLAT_TYPE_VF_P1;
+ else
+ goto unknown_vg_1g_port;
+
+ val = (phy_encode(PORT_TYPE_1G, 0) |
+ phy_encode(PORT_TYPE_1G, 1) |
+ phy_encode(PORT_TYPE_1G, 2) |
+ phy_encode(PORT_TYPE_1G, 3));
+ break;
+
+ default:
+ printk(KERN_ERR PFX "Unsupported port config "
+ "10G[%d] 1G[%d]\n",
+ num_10g, num_1g);
+ return -EINVAL;
+ }
+
+ parent->port_phy = val;
+
+ if (parent->plat_type == PLAT_TYPE_NIU)
+ niu_n2_divide_channels(parent);
+ else
+ niu_divide_channels(parent, num_10g, num_1g);
+
+ niu_divide_rdc_groups(parent, num_10g, num_1g);
+
+ return 0;
+
+unknown_vg_1g_port:
+ printk(KERN_ERR PFX "Cannot identify platform type, 1gport=%d\n",
+ lowest_1g);
+ return -EINVAL;
+}
+
+static int __devinit niu_probe_ports(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ int err, i;
+
+ niudbg(PROBE, "niu_probe_ports(): port_phy[%08x]\n",
+ parent->port_phy);
+
+ if (parent->port_phy == PORT_PHY_UNKNOWN) {
+ err = walk_phys(np, parent);
+ if (err)
+ return err;
+
+ niu_set_ldg_timer_res(np, 2);
+ for (i = 0; i <= LDN_MAX; i++)
+ niu_ldn_irq_enable(np, i, 0);
+ }
+
+ if (parent->port_phy == PORT_PHY_INVALID)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int __devinit niu_classifier_swstate_init(struct niu *np)
+{
+ struct niu_classifier *cp = &np->clas;
+
+ niudbg(PROBE, "niu_classifier_swstate_init: num_tcam(%d)\n",
+ np->parent->tcam_num_entries);
+
+ cp->tcam_index = (u16) np->port;
+ cp->h1_init = 0xffffffff;
+ cp->h2_init = 0xffff;
+
+ return fflp_early_init(np);
+}
+
+static void __devinit niu_link_config_init(struct niu *np)
+{
+ struct niu_link_config *lp = &np->link_config;
+
+ lp->advertising = (ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_10000baseT_Full |
+ ADVERTISED_Autoneg);
+ lp->speed = lp->active_speed = SPEED_INVALID;
+ lp->duplex = lp->active_duplex = DUPLEX_INVALID;
+#if 0
+ lp->loopback_mode = LOOPBACK_MAC;
+ lp->active_speed = SPEED_10000;
+ lp->active_duplex = DUPLEX_FULL;
+#else
+ lp->loopback_mode = LOOPBACK_DISABLED;
+#endif
+}
+
+static int __devinit niu_init_mac_ipp_pcs_base(struct niu *np)
+{
+ switch (np->port) {
+ case 0:
+ np->mac_regs = np->regs + XMAC_PORT0_OFF;
+ np->ipp_off = 0x00000;
+ np->pcs_off = 0x04000;
+ np->xpcs_off = 0x02000;
+ break;
+
+ case 1:
+ np->mac_regs = np->regs + XMAC_PORT1_OFF;
+ np->ipp_off = 0x08000;
+ np->pcs_off = 0x0a000;
+ np->xpcs_off = 0x08000;
+ break;
+
+ case 2:
+ np->mac_regs = np->regs + BMAC_PORT2_OFF;
+ np->ipp_off = 0x04000;
+ np->pcs_off = 0x0e000;
+ np->xpcs_off = ~0UL;
+ break;
+
+ case 3:
+ np->mac_regs = np->regs + BMAC_PORT3_OFF;
+ np->ipp_off = 0x0c000;
+ np->pcs_off = 0x12000;
+ np->xpcs_off = ~0UL;
+ break;
+
+ default:
+ dev_err(np->device, PFX "Port %u is invalid, cannot "
+ "compute MAC block offset.\n", np->port);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void __devinit niu_try_msix(struct niu *np, u8 *ldg_num_map)
+{
+ struct msix_entry msi_vec[NIU_NUM_LDG];
+ struct niu_parent *parent = np->parent;
+ struct pci_dev *pdev = np->pdev;
+ int i, num_irqs, err;
+ u8 first_ldg;
+
+ first_ldg = (NIU_NUM_LDG / parent->num_ports) * np->port;
+ for (i = 0; i < (NIU_NUM_LDG / parent->num_ports); i++)
+ ldg_num_map[i] = first_ldg + i;
+
+ num_irqs = (parent->rxchan_per_port[np->port] +
+ parent->txchan_per_port[np->port] +
+ (np->port == 0 ? 3 : 1));
+ BUG_ON(num_irqs > (NIU_NUM_LDG / parent->num_ports));
+
+retry:
+ for (i = 0; i < num_irqs; i++) {
+ msi_vec[i].vector = 0;
+ msi_vec[i].entry = i;
+ }
+
+ err = pci_enable_msix(pdev, msi_vec, num_irqs);
+ if (err < 0) {
+ np->flags &= ~NIU_FLAGS_MSIX;
+ return;
+ }
+ if (err > 0) {
+ num_irqs = err;
+ goto retry;
+ }
+
+ np->flags |= NIU_FLAGS_MSIX;
+ for (i = 0; i < num_irqs; i++)
+ np->ldg[i].irq = msi_vec[i].vector;
+ np->num_ldg = num_irqs;
+}
+
+static int __devinit niu_n2_irq_init(struct niu *np, u8 *ldg_num_map)
+{
+#ifdef CONFIG_SPARC64
+ struct of_device *op = np->op;
+ const u32 *int_prop;
+ int i;
+
+ int_prop = of_get_property(op->node, "interrupts", NULL);
+ if (!int_prop)
+ return -ENODEV;
+
+ for (i = 0; i < op->num_irqs; i++) {
+ ldg_num_map[i] = int_prop[i];
+ np->ldg[i].irq = op->irqs[i];
+ }
+
+ np->num_ldg = op->num_irqs;
+
+ return 0;
+#else
+ return -EINVAL;
+#endif
+}
+
+static int __devinit niu_ldg_init(struct niu *np)
+{
+ struct niu_parent *parent = np->parent;
+ u8 ldg_num_map[NIU_NUM_LDG];
+ int first_chan, num_chan;
+ int i, err, ldg_rotor;
+ u8 port;
+
+ np->num_ldg = 1;
+ np->ldg[0].irq = np->dev->irq;
+ if (parent->plat_type == PLAT_TYPE_NIU) {
+ err = niu_n2_irq_init(np, ldg_num_map);
+ if (err)
+ return err;
+ } else
+ niu_try_msix(np, ldg_num_map);
+
+ port = np->port;
+ for (i = 0; i < np->num_ldg; i++) {
+ struct niu_ldg *lp = &np->ldg[i];
+
+ netif_napi_add(np->dev, &lp->napi, niu_poll, 64);
+
+ lp->np = np;
+ lp->ldg_num = ldg_num_map[i];
+ lp->timer = 2; /* XXX */
+
+ /* On N2 NIU the firmware has setup the SID mappings so they go
+ * to the correct values that will route the LDG to the proper
+ * interrupt in the NCU interrupt table.
+ */
+ if (np->parent->plat_type != PLAT_TYPE_NIU) {
+ err = niu_set_ldg_sid(np, lp->ldg_num, port, i);
+ if (err)
+ return err;
+ }
+ }
+
+ /* We adopt the LDG assignment ordering used by the N2 NIU
+ * 'interrupt' properties because that simplifies a lot of
+ * things. This ordering is:
+ *
+ * MAC
+ * MIF (if port zero)
+ * SYSERR (if port zero)
+ * RX channels
+ * TX channels
+ */
+
+ ldg_rotor = 0;
+
+ err = niu_ldg_assign_ldn(np, parent, ldg_num_map[ldg_rotor],
+ LDN_MAC(port));
+ if (err)
+ return err;
+
+ ldg_rotor++;
+ if (ldg_rotor == np->num_ldg)
+ ldg_rotor = 0;
+
+ if (port == 0) {
+ err = niu_ldg_assign_ldn(np, parent,
+ ldg_num_map[ldg_rotor],
+ LDN_MIF);
+ if (err)
+ return err;
+
+ ldg_rotor++;
+ if (ldg_rotor == np->num_ldg)
+ ldg_rotor = 0;
+
+ err = niu_ldg_assign_ldn(np, parent,
+ ldg_num_map[ldg_rotor],
+ LDN_DEVICE_ERROR);
+ if (err)
+ return err;
+
+ ldg_rotor++;
+ if (ldg_rotor == np->num_ldg)
+ ldg_rotor = 0;
+
+ }
+
+ first_chan = 0;
+ for (i = 0; i < port; i++)
+ first_chan += parent->rxchan_per_port[port];
+ num_chan = parent->rxchan_per_port[port];
+
+ for (i = first_chan; i < (first_chan + num_chan); i++) {
+ err = niu_ldg_assign_ldn(np, parent,
+ ldg_num_map[ldg_rotor],
+ LDN_RXDMA(i));
+ if (err)
+ return err;
+ ldg_rotor++;
+ if (ldg_rotor == np->num_ldg)
+ ldg_rotor = 0;
+ }
+
+ first_chan = 0;
+ for (i = 0; i < port; i++)
+ first_chan += parent->txchan_per_port[port];
+ num_chan = parent->txchan_per_port[port];
+ for (i = first_chan; i < (first_chan + num_chan); i++) {
+ err = niu_ldg_assign_ldn(np, parent,
+ ldg_num_map[ldg_rotor],
+ LDN_TXDMA(i));
+ if (err)
+ return err;
+ ldg_rotor++;
+ if (ldg_rotor == np->num_ldg)
+ ldg_rotor = 0;
+ }
+
+ return 0;
+}
+
+static void __devexit niu_ldg_free(struct niu *np)
+{
+ if (np->flags & NIU_FLAGS_MSIX)
+ pci_disable_msix(np->pdev);
+}
+
+static int __devinit niu_get_of_props(struct niu *np)
+{
+#ifdef CONFIG_SPARC64
+ struct net_device *dev = np->dev;
+ struct device_node *dp;
+ const char *phy_type;
+ const u8 *mac_addr;
+ int prop_len;
+
+ if (np->parent->plat_type == PLAT_TYPE_NIU)
+ dp = np->op->node;
+ else
+ dp = pci_device_to_OF_node(np->pdev);
+
+ phy_type = of_get_property(dp, "phy-type", &prop_len);
+ if (!phy_type) {
+ dev_err(np->device, PFX "%s: OF node lacks "
+ "phy-type property\n",
+ dp->full_name);
+ return -EINVAL;
+ }
+
+ if (!strcmp(phy_type, "none"))
+ return -ENODEV;
+
+ strcpy(np->vpd.phy_type, phy_type);
+
+ if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
+ dev_err(np->device, PFX "%s: Illegal phy string [%s].\n",
+ dp->full_name, np->vpd.phy_type);
+ return -EINVAL;
+ }
+
+ mac_addr = of_get_property(dp, "local-mac-address", &prop_len);
+ if (!mac_addr) {
+ dev_err(np->device, PFX "%s: OF node lacks "
+ "local-mac-address property\n",
+ dp->full_name);
+ return -EINVAL;
+ }
+ if (prop_len != dev->addr_len) {
+ dev_err(np->device, PFX "%s: OF MAC address prop len (%d) "
+ "is wrong.\n",
+ dp->full_name, prop_len);
+ }
+ memcpy(dev->perm_addr, mac_addr, dev->addr_len);
+ if (!is_valid_ether_addr(&dev->perm_addr[0])) {
+ int i;
+
+ dev_err(np->device, PFX "%s: OF MAC address is invalid\n",
+ dp->full_name);
+ dev_err(np->device, PFX "%s: [ \n",
+ dp->full_name);
+ for (i = 0; i < 6; i++)
+ printk("%02x ", dev->perm_addr[i]);
+ printk("]\n");
+ return -EINVAL;
+ }
+
+ memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+
+ return 0;
+#else
+ return -EINVAL;
+#endif
+}
+
+static int __devinit niu_get_invariants(struct niu *np)
+{
+ int err, have_props;
+ u32 offset;
+
+ err = niu_get_of_props(np);
+ if (err == -ENODEV)
+ return err;
+
+ have_props = !err;
+
+ err = niu_get_and_validate_port(np);
+ if (err)
+ return err;
+
+ err = niu_init_mac_ipp_pcs_base(np);
+ if (err)
+ return err;
+
+ if (!have_props) {
+ if (np->parent->plat_type == PLAT_TYPE_NIU)
+ return -EINVAL;
+
+ nw64(ESPC_PIO_EN, ESPC_PIO_EN_ENABLE);
+ offset = niu_pci_vpd_offset(np);
+ niudbg(PROBE, "niu_get_invariants: VPD offset [%08x]\n",
+ offset);
+ if (offset)
+ niu_pci_vpd_fetch(np, offset);
+ nw64(ESPC_PIO_EN, 0);
+
+ if (np->flags & NIU_FLAGS_VPD_VALID)
+ niu_pci_vpd_validate(np);
+
+ if (!(np->flags & NIU_FLAGS_VPD_VALID)) {
+ err = niu_pci_probe_sprom(np);
+ if (err)
+ return err;
+ }
+ }
+
+ err = niu_probe_ports(np);
+ if (err)
+ return err;
+
+ niu_ldg_init(np);
+
+ niu_classifier_swstate_init(np);
+ niu_link_config_init(np);
+
+ err = niu_determine_phy_disposition(np);
+ if (!err)
+ err = niu_init_link(np);
+
+ return err;
+}
+
+static LIST_HEAD(niu_parent_list);
+static DEFINE_MUTEX(niu_parent_lock);
+static int niu_parent_index;
+
+static ssize_t show_port_phy(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *plat_dev = to_platform_device(dev);
+ struct niu_parent *p = plat_dev->dev.platform_data;
+ u32 port_phy = p->port_phy;
+ char *orig_buf = buf;
+ int i;
+
+ if (port_phy == PORT_PHY_UNKNOWN ||
+ port_phy == PORT_PHY_INVALID)
+ return 0;
+
+ for (i = 0; i < p->num_ports; i++) {
+ const char *type_str;
+ int type;
+
+ type = phy_decode(port_phy, i);
+ if (type == PORT_TYPE_10G)
+ type_str = "10G";
+ else
+ type_str = "1G";
+ buf += sprintf(buf,
+ (i == 0) ? "%s" : " %s",
+ type_str);
+ }
+ buf += sprintf(buf, "\n");
+ return buf - orig_buf;
+}
+
+static ssize_t show_plat_type(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *plat_dev = to_platform_device(dev);
+ struct niu_parent *p = plat_dev->dev.platform_data;
+ const char *type_str;
+
+ switch (p->plat_type) {
+ case PLAT_TYPE_ATLAS:
+ type_str = "atlas";
+ break;
+ case PLAT_TYPE_NIU:
+ type_str = "niu";
+ break;
+ case PLAT_TYPE_VF_P0:
+ type_str = "vf_p0";
+ break;
+ case PLAT_TYPE_VF_P1:
+ type_str = "vf_p1";
+ break;
+ default:
+ type_str = "unknown";
+ break;
+ }
+
+ return sprintf(buf, "%s\n", type_str);
+}
+
+static ssize_t __show_chan_per_port(struct device *dev,
+ struct device_attribute *attr, char *buf,
+ int rx)
+{
+ struct platform_device *plat_dev = to_platform_device(dev);
+ struct niu_parent *p = plat_dev->dev.platform_data;
+ char *orig_buf = buf;
+ u8 *arr;
+ int i;
+
+ arr = (rx ? p->rxchan_per_port : p->txchan_per_port);
+
+ for (i = 0; i < p->num_ports; i++) {
+ buf += sprintf(buf,
+ (i == 0) ? "%d" : " %d",
+ arr[i]);
+ }
+ buf += sprintf(buf, "\n");
+
+ return buf - orig_buf;
+}
+
+static ssize_t show_rxchan_per_port(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return __show_chan_per_port(dev, attr, buf, 1);
+}
+
+static ssize_t show_txchan_per_port(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return __show_chan_per_port(dev, attr, buf, 1);
+}
+
+static ssize_t show_num_ports(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *plat_dev = to_platform_device(dev);
+ struct niu_parent *p = plat_dev->dev.platform_data;
+
+ return sprintf(buf, "%d\n", p->num_ports);
+}
+
+static struct device_attribute niu_parent_attributes[] = {
+ __ATTR(port_phy, S_IRUGO, show_port_phy, NULL),
+ __ATTR(plat_type, S_IRUGO, show_plat_type, NULL),
+ __ATTR(rxchan_per_port, S_IRUGO, show_rxchan_per_port, NULL),
+ __ATTR(txchan_per_port, S_IRUGO, show_txchan_per_port, NULL),
+ __ATTR(num_ports, S_IRUGO, show_num_ports, NULL),
+ {}
+};
+
+static struct niu_parent * __devinit niu_new_parent(struct niu *np,
+ union niu_parent_id *id,
+ u8 ptype)
+{
+ struct platform_device *plat_dev;
+ struct niu_parent *p;
+ int i;
+
+ niudbg(PROBE, "niu_new_parent: Creating new parent.\n");
+
+ plat_dev = platform_device_register_simple("niu", niu_parent_index,
+ NULL, 0);
+ if (!plat_dev)
+ return NULL;
+
+ for (i = 0; attr_name(niu_parent_attributes[i]); i++) {
+ int err = device_create_file(&plat_dev->dev,
+ &niu_parent_attributes[i]);
+ if (err)
+ goto fail_unregister;
+ }
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ goto fail_unregister;
+
+ p->index = niu_parent_index++;
+
+ plat_dev->dev.platform_data = p;
+ p->plat_dev = plat_dev;
+
+ memcpy(&p->id, id, sizeof(*id));
+ p->plat_type = ptype;
+ INIT_LIST_HEAD(&p->list);
+ atomic_set(&p->refcnt, 0);
+ list_add(&p->list, &niu_parent_list);
+ spin_lock_init(&p->lock);
+
+ p->rxdma_clock_divider = 7500;
+
+ p->tcam_num_entries = NIU_PCI_TCAM_ENTRIES;
+ if (p->plat_type == PLAT_TYPE_NIU)
+ p->tcam_num_entries = NIU_NONPCI_TCAM_ENTRIES;
+
+ for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_SCTP_IPV6; i++) {
+ int index = i - CLASS_CODE_USER_PROG1;
+
+ p->tcam_key[index] = TCAM_KEY_TSEL;
+ p->flow_key[index] = (FLOW_KEY_IPSA |
+ FLOW_KEY_IPDA |
+ FLOW_KEY_PROTO |
+ (FLOW_KEY_L4_BYTE12 <<
+ FLOW_KEY_L4_0_SHIFT) |
+ (FLOW_KEY_L4_BYTE12 <<
+ FLOW_KEY_L4_1_SHIFT));
+ }
+
+ for (i = 0; i < LDN_MAX + 1; i++)
+ p->ldg_map[i] = LDG_INVALID;
+
+ return p;
+
+fail_unregister:
+ platform_device_unregister(plat_dev);
+ return NULL;
+}
+
+static struct niu_parent * __devinit niu_get_parent(struct niu *np,
+ union niu_parent_id *id,
+ u8 ptype)
+{
+ struct niu_parent *p, *tmp;
+ int port = np->port;
+
+ niudbg(PROBE, "niu_get_parent: platform_type[%u] port[%u]\n",
+ ptype, port);
+
+ mutex_lock(&niu_parent_lock);
+ p = NULL;
+ list_for_each_entry(tmp, &niu_parent_list, list) {
+ if (!memcmp(id, &tmp->id, sizeof(*id))) {
+ p = tmp;
+ break;
+ }
+ }
+ if (!p)
+ p = niu_new_parent(np, id, ptype);
+
+ if (p) {
+ char port_name[6];
+ int err;
+
+ sprintf(port_name, "port%d", port);
+ err = sysfs_create_link(&p->plat_dev->dev.kobj,
+ &np->device->kobj,
+ port_name);
+ if (!err) {
+ p->ports[port] = np;
+ atomic_inc(&p->refcnt);
+ }
+ }
+ mutex_unlock(&niu_parent_lock);
+
+ return p;
+}
+
+static void niu_put_parent(struct niu *np)
+{
+ struct niu_parent *p = np->parent;
+ u8 port = np->port;
+ char port_name[6];
+
+ BUG_ON(!p || p->ports[port] != np);
+
+ niudbg(PROBE, "niu_put_parent: port[%u]\n", port);
+
+ sprintf(port_name, "port%d", port);
+
+ mutex_lock(&niu_parent_lock);
+
+ sysfs_remove_link(&p->plat_dev->dev.kobj, port_name);
+
+ p->ports[port] = NULL;
+ np->parent = NULL;
+
+ if (atomic_dec_and_test(&p->refcnt)) {
+ list_del(&p->list);
+ platform_device_unregister(p->plat_dev);
+ }
+
+ mutex_unlock(&niu_parent_lock);
+}
+
+static void *niu_pci_alloc_coherent(struct device *dev, size_t size,
+ u64 *handle, gfp_t flag)
+{
+ dma_addr_t dh;
+ void *ret;
+
+ ret = dma_alloc_coherent(dev, size, &dh, flag);
+ if (ret)
+ *handle = dh;
+ return ret;
+}
+
+static void niu_pci_free_coherent(struct device *dev, size_t size,
+ void *cpu_addr, u64 handle)
+{
+ dma_free_coherent(dev, size, cpu_addr, handle);
+}
+
+static u64 niu_pci_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ return dma_map_page(dev, page, offset, size, direction);
+}
+
+static void niu_pci_unmap_page(struct device *dev, u64 dma_address,
+ size_t size, enum dma_data_direction direction)
+{
+ return dma_unmap_page(dev, dma_address, size, direction);
+}
+
+static u64 niu_pci_map_single(struct device *dev, void *cpu_addr,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ return dma_map_single(dev, cpu_addr, size, direction);
+}
+
+static void niu_pci_unmap_single(struct device *dev, u64 dma_address,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ dma_unmap_single(dev, dma_address, size, direction);
+}
+
+static const struct niu_ops niu_pci_ops = {
+ .alloc_coherent = niu_pci_alloc_coherent,
+ .free_coherent = niu_pci_free_coherent,
+ .map_page = niu_pci_map_page,
+ .unmap_page = niu_pci_unmap_page,
+ .map_single = niu_pci_map_single,
+ .unmap_single = niu_pci_unmap_single,
+};
+
+static void __devinit niu_driver_version(void)
+{
+ static int niu_version_printed;
+
+ if (niu_version_printed++ == 0)
+ pr_info("%s", version);
+}
+
+static struct net_device * __devinit niu_alloc_and_init(
+ struct device *gen_dev, struct pci_dev *pdev,
+ struct of_device *op, const struct niu_ops *ops,
+ u8 port)
+{
+ struct net_device *dev = alloc_etherdev(sizeof(struct niu));
+ struct niu *np;
+
+ if (!dev) {
+ dev_err(gen_dev, PFX "Etherdev alloc failed, aborting.\n");
+ return NULL;
+ }
+
+ SET_NETDEV_DEV(dev, gen_dev);
+
+ np = netdev_priv(dev);
+ np->dev = dev;
+ np->pdev = pdev;
+ np->op = op;
+ np->device = gen_dev;
+ np->ops = ops;
+
+ np->msg_enable = niu_debug;
+
+ spin_lock_init(&np->lock);
+ INIT_WORK(&np->reset_task, niu_reset_task);
+
+ np->port = port;
+
+ return dev;
+}
+
+static void __devinit niu_assign_netdev_ops(struct net_device *dev)
+{
+ dev->open = niu_open;
+ dev->stop = niu_close;
+ dev->get_stats = niu_get_stats;
+ dev->set_multicast_list = niu_set_rx_mode;
+ dev->set_mac_address = niu_set_mac_addr;
+ dev->do_ioctl = niu_ioctl;
+ dev->tx_timeout = niu_tx_timeout;
+ dev->hard_start_xmit = niu_start_xmit;
+ dev->ethtool_ops = &niu_ethtool_ops;
+ dev->watchdog_timeo = NIU_TX_TIMEOUT;
+ dev->change_mtu = niu_change_mtu;
+}
+
+static void __devinit niu_device_announce(struct niu *np)
+{
+ struct net_device *dev = np->dev;
+ int i;
+
+ pr_info("%s: NIU Ethernet ", dev->name);
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", dev->dev_addr[i],
+ i == 5 ? '\n' : ':');
+
+ pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n",
+ dev->name,
+ (np->flags & NIU_FLAGS_XMAC ? "XMAC" : "BMAC"),
+ (np->flags & NIU_FLAGS_10G ? "10G" : "1G"),
+ (np->flags & NIU_FLAGS_FIBER ? "FIBER" : "COPPER"),
+ (np->mac_xcvr == MAC_XCVR_MII ? "MII" :
+ (np->mac_xcvr == MAC_XCVR_PCS ? "PCS" : "XPCS")),
+ np->vpd.phy_type);
+}
+
+static int __devinit niu_pci_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ unsigned long niureg_base, niureg_len;
+ union niu_parent_id parent_id;
+ struct net_device *dev;
+ struct niu *np;
+ int err, pos;
+ u64 dma_mask;
+ u16 val16;
+
+ niu_driver_version();
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_err(&pdev->dev, PFX "Cannot enable PCI device, "
+ "aborting.\n");
+ return err;
+ }
+
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
+ !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+ dev_err(&pdev->dev, PFX "Cannot find proper PCI device "
+ "base addresses, aborting.\n");
+ err = -ENODEV;
+ goto err_out_disable_pdev;
+ }
+
+ err = pci_request_regions(pdev, DRV_MODULE_NAME);
+ if (err) {
+ dev_err(&pdev->dev, PFX "Cannot obtain PCI resources, "
+ "aborting.\n");
+ goto err_out_disable_pdev;
+ }
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ if (pos <= 0) {
+ dev_err(&pdev->dev, PFX "Cannot find PCI Express capability, "
+ "aborting.\n");
+ goto err_out_free_res;
+ }
+
+ dev = niu_alloc_and_init(&pdev->dev, pdev, NULL,
+ &niu_pci_ops, PCI_FUNC(pdev->devfn));
+ if (!dev) {
+ err = -ENOMEM;
+ goto err_out_free_res;
+ }
+ np = netdev_priv(dev);
+
+ memset(&parent_id, 0, sizeof(parent_id));
+ parent_id.pci.domain = pci_domain_nr(pdev->bus);
+ parent_id.pci.bus = pdev->bus->number;
+ parent_id.pci.device = PCI_SLOT(pdev->devfn);
+
+ np->parent = niu_get_parent(np, &parent_id,
+ PLAT_TYPE_ATLAS);
+ if (!np->parent) {
+ err = -ENOMEM;
+ goto err_out_free_dev;
+ }
+
+ pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &val16);
+ val16 &= ~PCI_EXP_DEVCTL_NOSNOOP_EN;
+ val16 |= (PCI_EXP_DEVCTL_CERE |
+ PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_FERE |
+ PCI_EXP_DEVCTL_URRE |
+ PCI_EXP_DEVCTL_RELAX_EN);
+ pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, val16);
+
+ dma_mask = DMA_44BIT_MASK;
+ err = pci_set_dma_mask(pdev, dma_mask);
+ if (!err) {
+ dev->features |= NETIF_F_HIGHDMA;
+ err = pci_set_consistent_dma_mask(pdev, dma_mask);
+ if (err) {
+ dev_err(&pdev->dev, PFX "Unable to obtain 44 bit "
+ "DMA for consistent allocations, "
+ "aborting.\n");
+ goto err_out_release_parent;
+ }
+ }
+ if (err || dma_mask == DMA_32BIT_MASK) {
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ dev_err(&pdev->dev, PFX "No usable DMA configuration, "
+ "aborting.\n");
+ goto err_out_release_parent;
+ }
+ }
+
+ dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM);
+
+ niureg_base = pci_resource_start(pdev, 0);
+ niureg_len = pci_resource_len(pdev, 0);
+
+ np->regs = ioremap_nocache(niureg_base, niureg_len);
+ if (!np->regs) {
+ dev_err(&pdev->dev, PFX "Cannot map device registers, "
+ "aborting.\n");
+ err = -ENOMEM;
+ goto err_out_release_parent;
+ }
+
+ pci_set_master(pdev);
+ pci_save_state(pdev);
+
+ dev->irq = pdev->irq;
+
+ niu_assign_netdev_ops(dev);
+
+ err = niu_get_invariants(np);
+ if (err) {
+ if (err != -ENODEV)
+ dev_err(&pdev->dev, PFX "Problem fetching invariants "
+ "of chip, aborting.\n");
+ goto err_out_iounmap;
+ }
+
+ err = register_netdev(dev);
+ if (err) {
+ dev_err(&pdev->dev, PFX "Cannot register net device, "
+ "aborting.\n");
+ goto err_out_iounmap;
+ }
+
+ pci_set_drvdata(pdev, dev);
+
+ niu_device_announce(np);
+
+ return 0;
+
+err_out_iounmap:
+ if (np->regs) {
+ iounmap(np->regs);
+ np->regs = NULL;
+ }
+
+err_out_release_parent:
+ niu_put_parent(np);
+
+err_out_free_dev:
+ free_netdev(dev);
+
+err_out_free_res:
+ pci_release_regions(pdev);
+
+err_out_disable_pdev:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ return err;
+}
+
+static void __devexit niu_pci_remove_one(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ if (dev) {
+ struct niu *np = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ if (np->regs) {
+ iounmap(np->regs);
+ np->regs = NULL;
+ }
+
+ niu_ldg_free(np);
+
+ niu_put_parent(np);
+
+ free_netdev(dev);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ }
+}
+
+static int niu_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct niu *np = netdev_priv(dev);
+ unsigned long flags;
+
+ if (!netif_running(dev))
+ return 0;
+
+ flush_scheduled_work();
+ niu_netif_stop(np);
+
+ del_timer_sync(&np->timer);
+
+ spin_lock_irqsave(&np->lock, flags);
+ niu_enable_interrupts(np, 0);
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ netif_device_detach(dev);
+
+ spin_lock_irqsave(&np->lock, flags);
+ niu_stop_hw(np);
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ pci_save_state(pdev);
+
+ return 0;
+}
+
+static int niu_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct niu *np = netdev_priv(dev);
+ unsigned long flags;
+ int err;
+
+ if (!netif_running(dev))
+ return 0;
+
+ pci_restore_state(pdev);
+
+ netif_device_attach(dev);
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ err = niu_init_hw(np);
+ if (!err) {
+ np->timer.expires = jiffies + HZ;
+ add_timer(&np->timer);
+ niu_netif_start(np);
+ }
+
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ return err;
+}
+
+static struct pci_driver niu_pci_driver = {
+ .name = DRV_MODULE_NAME,
+ .id_table = niu_pci_tbl,
+ .probe = niu_pci_init_one,
+ .remove = __devexit_p(niu_pci_remove_one),
+ .suspend = niu_suspend,
+ .resume = niu_resume,
+};
+
+#ifdef CONFIG_SPARC64
+static void *niu_phys_alloc_coherent(struct device *dev, size_t size,
+ u64 *dma_addr, gfp_t flag)
+{
+ unsigned long order = get_order(size);
+ unsigned long page = __get_free_pages(flag, order);
+
+ if (page == 0UL)
+ return NULL;
+ memset((char *)page, 0, PAGE_SIZE << order);
+ *dma_addr = __pa(page);
+
+ return (void *) page;
+}
+
+static void niu_phys_free_coherent(struct device *dev, size_t size,
+ void *cpu_addr, u64 handle)
+{
+ unsigned long order = get_order(size);
+
+ free_pages((unsigned long) cpu_addr, order);
+}
+
+static u64 niu_phys_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ return page_to_phys(page) + offset;
+}
+
+static void niu_phys_unmap_page(struct device *dev, u64 dma_address,
+ size_t size, enum dma_data_direction direction)
+{
+ /* Nothing to do. */
+}
+
+static u64 niu_phys_map_single(struct device *dev, void *cpu_addr,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ return __pa(cpu_addr);
+}
+
+static void niu_phys_unmap_single(struct device *dev, u64 dma_address,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ /* Nothing to do. */
+}
+
+static const struct niu_ops niu_phys_ops = {
+ .alloc_coherent = niu_phys_alloc_coherent,
+ .free_coherent = niu_phys_free_coherent,
+ .map_page = niu_phys_map_page,
+ .unmap_page = niu_phys_unmap_page,
+ .map_single = niu_phys_map_single,
+ .unmap_single = niu_phys_unmap_single,
+};
+
+static unsigned long res_size(struct resource *r)
+{
+ return r->end - r->start + 1UL;
+}
+
+static int __devinit niu_of_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ union niu_parent_id parent_id;
+ struct net_device *dev;
+ struct niu *np;
+ const u32 *reg;
+ int err;
+
+ niu_driver_version();
+
+ reg = of_get_property(op->node, "reg", NULL);
+ if (!reg) {
+ dev_err(&op->dev, PFX "%s: No 'reg' property, aborting.\n",
+ op->node->full_name);
+ return -ENODEV;
+ }
+
+ dev = niu_alloc_and_init(&op->dev, NULL, op,
+ &niu_phys_ops, reg[0] & 0x1);
+ if (!dev) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ np = netdev_priv(dev);
+
+ memset(&parent_id, 0, sizeof(parent_id));
+ parent_id.of = of_get_parent(op->node);
+
+ np->parent = niu_get_parent(np, &parent_id,
+ PLAT_TYPE_NIU);
+ if (!np->parent) {
+ err = -ENOMEM;
+ goto err_out_free_dev;
+ }
+
+ dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM);
+
+ np->regs = of_ioremap(&op->resource[1], 0,
+ res_size(&op->resource[1]),
+ "niu regs");
+ if (!np->regs) {
+ dev_err(&op->dev, PFX "Cannot map device registers, "
+ "aborting.\n");
+ err = -ENOMEM;
+ goto err_out_release_parent;
+ }
+
+ np->vir_regs_1 = of_ioremap(&op->resource[2], 0,
+ res_size(&op->resource[2]),
+ "niu vregs-1");
+ if (!np->vir_regs_1) {
+ dev_err(&op->dev, PFX "Cannot map device vir registers 1, "
+ "aborting.\n");
+ err = -ENOMEM;
+ goto err_out_iounmap;
+ }
+
+ np->vir_regs_2 = of_ioremap(&op->resource[3], 0,
+ res_size(&op->resource[3]),
+ "niu vregs-2");
+ if (!np->vir_regs_2) {
+ dev_err(&op->dev, PFX "Cannot map device vir registers 2, "
+ "aborting.\n");
+ err = -ENOMEM;
+ goto err_out_iounmap;
+ }
+
+ niu_assign_netdev_ops(dev);
+
+ err = niu_get_invariants(np);
+ if (err) {
+ if (err != -ENODEV)
+ dev_err(&op->dev, PFX "Problem fetching invariants "
+ "of chip, aborting.\n");
+ goto err_out_iounmap;
+ }
+
+ err = register_netdev(dev);
+ if (err) {
+ dev_err(&op->dev, PFX "Cannot register net device, "
+ "aborting.\n");
+ goto err_out_iounmap;
+ }
+
+ dev_set_drvdata(&op->dev, dev);
+
+ niu_device_announce(np);
+
+ return 0;
+
+err_out_iounmap:
+ if (np->vir_regs_1) {
+ of_iounmap(&op->resource[2], np->vir_regs_1,
+ res_size(&op->resource[2]));
+ np->vir_regs_1 = NULL;
+ }
+
+ if (np->vir_regs_2) {
+ of_iounmap(&op->resource[3], np->vir_regs_2,
+ res_size(&op->resource[3]));
+ np->vir_regs_2 = NULL;
+ }
+
+ if (np->regs) {
+ of_iounmap(&op->resource[1], np->regs,
+ res_size(&op->resource[1]));
+ np->regs = NULL;
+ }
+
+err_out_release_parent:
+ niu_put_parent(np);
+
+err_out_free_dev:
+ free_netdev(dev);
+
+err_out:
+ return err;
+}
+
+static int __devexit niu_of_remove(struct of_device *op)
+{
+ struct net_device *dev = dev_get_drvdata(&op->dev);
+
+ if (dev) {
+ struct niu *np = netdev_priv(dev);
+
+ unregister_netdev(dev);
+
+ if (np->vir_regs_1) {
+ of_iounmap(&op->resource[2], np->vir_regs_1,
+ res_size(&op->resource[2]));
+ np->vir_regs_1 = NULL;
+ }
+
+ if (np->vir_regs_2) {
+ of_iounmap(&op->resource[3], np->vir_regs_2,
+ res_size(&op->resource[3]));
+ np->vir_regs_2 = NULL;
+ }
+
+ if (np->regs) {
+ of_iounmap(&op->resource[1], np->regs,
+ res_size(&op->resource[1]));
+ np->regs = NULL;
+ }
+
+ niu_ldg_free(np);
+
+ niu_put_parent(np);
+
+ free_netdev(dev);
+ dev_set_drvdata(&op->dev, NULL);
+ }
+ return 0;
+}
+
+static struct of_device_id niu_match[] = {
+ {
+ .name = "network",
+ .compatible = "SUNW,niusl",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, niu_match);
+
+static struct of_platform_driver niu_of_driver = {
+ .name = "niu",
+ .match_table = niu_match,
+ .probe = niu_of_probe,
+ .remove = __devexit_p(niu_of_remove),
+};
+
+#endif /* CONFIG_SPARC64 */
+
+static int __init niu_init(void)
+{
+ int err = 0;
+
+ BUILD_BUG_ON(PAGE_SIZE < 4 * 1024);
+
+ niu_debug = netif_msg_init(debug, NIU_MSG_DEFAULT);
+
+#ifdef CONFIG_SPARC64
+ err = of_register_driver(&niu_of_driver, &of_bus_type);
+#endif
+
+ if (!err) {
+ err = pci_register_driver(&niu_pci_driver);
+#ifdef CONFIG_SPARC64
+ if (err)
+ of_unregister_driver(&niu_of_driver);
+#endif
+ }
+
+ return err;
+}
+
+static void __exit niu_exit(void)
+{
+ pci_unregister_driver(&niu_pci_driver);
+#ifdef CONFIG_SPARC64
+ of_unregister_driver(&niu_of_driver);
+#endif
+}
+
+module_init(niu_init);
+module_exit(niu_exit);
diff --git a/drivers/net/niu.h b/drivers/net/niu.h
new file mode 100644
index 00000000000..10e3f111b6d
--- /dev/null
+++ b/drivers/net/niu.h
@@ -0,0 +1,3222 @@
+/* niu.h: Definitions for Neptune ethernet driver.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#ifndef _NIU_H
+#define _NIU_H
+
+#define PIO 0x000000UL
+#define FZC_PIO 0x080000UL
+#define FZC_MAC 0x180000UL
+#define FZC_IPP 0x280000UL
+#define FFLP 0x300000UL
+#define FZC_FFLP 0x380000UL
+#define PIO_VADDR 0x400000UL
+#define ZCP 0x500000UL
+#define FZC_ZCP 0x580000UL
+#define DMC 0x600000UL
+#define FZC_DMC 0x680000UL
+#define TXC 0x700000UL
+#define FZC_TXC 0x780000UL
+#define PIO_LDSV 0x800000UL
+#define PIO_PIO_LDGIM 0x900000UL
+#define PIO_IMASK0 0xa00000UL
+#define PIO_IMASK1 0xb00000UL
+#define FZC_PROM 0xc80000UL
+#define FZC_PIM 0xd80000UL
+
+#define LDSV0(LDG) (PIO_LDSV + 0x00000UL + (LDG) * 0x2000UL)
+#define LDSV1(LDG) (PIO_LDSV + 0x00008UL + (LDG) * 0x2000UL)
+#define LDSV2(LDG) (PIO_LDSV + 0x00010UL + (LDG) * 0x2000UL)
+
+#define LDG_IMGMT(LDG) (PIO_LDSV + 0x00018UL + (LDG) * 0x2000UL)
+#define LDG_IMGMT_ARM 0x0000000080000000ULL
+#define LDG_IMGMT_TIMER 0x000000000000003fULL
+
+#define LD_IM0(IDX) (PIO_IMASK0 + 0x00000UL + (IDX) * 0x2000UL)
+#define LD_IM0_MASK 0x0000000000000003ULL
+
+#define LD_IM1(IDX) (PIO_IMASK1 + 0x00000UL + (IDX) * 0x2000UL)
+#define LD_IM1_MASK 0x0000000000000003ULL
+
+#define LDG_TIMER_RES (FZC_PIO + 0x00008UL)
+#define LDG_TIMER_RES_VAL 0x00000000000fffffULL
+
+#define DIRTY_TID_CTL (FZC_PIO + 0x00010UL)
+#define DIRTY_TID_CTL_NPTHRED 0x00000000003f0000ULL
+#define DIRTY_TID_CTL_RDTHRED 0x00000000000003f0ULL
+#define DIRTY_TID_CTL_DTIDCLR 0x0000000000000002ULL
+#define DIRTY_TID_CTL_DTIDENAB 0x0000000000000001ULL
+
+#define DIRTY_TID_STAT (FZC_PIO + 0x00018UL)
+#define DIRTY_TID_STAT_NPWSTAT 0x0000000000003f00ULL
+#define DIRTY_TID_STAT_RDSTAT 0x000000000000003fULL
+
+#define RST_CTL (FZC_PIO + 0x00038UL)
+#define RST_CTL_MAC_RST3 0x0000000000400000ULL
+#define RST_CTL_MAC_RST2 0x0000000000200000ULL
+#define RST_CTL_MAC_RST1 0x0000000000100000ULL
+#define RST_CTL_MAC_RST0 0x0000000000080000ULL
+#define RST_CTL_ACK_TO_EN 0x0000000000000800ULL
+#define RST_CTL_ACK_TO_VAL 0x00000000000007feULL
+
+#define SMX_CFIG_DAT (FZC_PIO + 0x00040UL)
+#define SMX_CFIG_DAT_RAS_DET 0x0000000080000000ULL
+#define SMX_CFIG_DAT_RAS_INJ 0x0000000040000000ULL
+#define SMX_CFIG_DAT_XACT_TO 0x000000000fffffffULL
+
+#define SMX_INT_STAT (FZC_PIO + 0x00048UL)
+#define SMX_INT_STAT_STAT 0x00000000ffffffffULL
+
+#define SMX_CTL (FZC_PIO + 0x00050UL)
+#define SMX_CTL_CTL 0x00000000ffffffffULL
+
+#define SMX_DBG_VEC (FZC_PIO + 0x00058UL)
+#define SMX_DBG_VEC_VEC 0x00000000ffffffffULL
+
+#define PIO_DBG_SEL (FZC_PIO + 0x00060UL)
+#define PIO_DBG_SEL_SEL 0x000000000000003fULL
+
+#define PIO_TRAIN_VEC (FZC_PIO + 0x00068UL)
+#define PIO_TRAIN_VEC_VEC 0x00000000ffffffffULL
+
+#define PIO_ARB_CTL (FZC_PIO + 0x00070UL)
+#define PIO_ARB_CTL_CTL 0x00000000ffffffffULL
+
+#define PIO_ARB_DBG_VEC (FZC_PIO + 0x00078UL)
+#define PIO_ARB_DBG_VEC_VEC 0x00000000ffffffffULL
+
+#define SYS_ERR_MASK (FZC_PIO + 0x00090UL)
+#define SYS_ERR_MASK_META2 0x0000000000000400ULL
+#define SYS_ERR_MASK_META1 0x0000000000000200ULL
+#define SYS_ERR_MASK_PEU 0x0000000000000100ULL
+#define SYS_ERR_MASK_TXC 0x0000000000000080ULL
+#define SYS_ERR_MASK_RDMC 0x0000000000000040ULL
+#define SYS_ERR_MASK_TDMC 0x0000000000000020ULL
+#define SYS_ERR_MASK_ZCP 0x0000000000000010ULL
+#define SYS_ERR_MASK_FFLP 0x0000000000000008ULL
+#define SYS_ERR_MASK_IPP 0x0000000000000004ULL
+#define SYS_ERR_MASK_MAC 0x0000000000000002ULL
+#define SYS_ERR_MASK_SMX 0x0000000000000001ULL
+
+#define SYS_ERR_STAT (FZC_PIO + 0x00098UL)
+#define SYS_ERR_STAT_META2 0x0000000000000400ULL
+#define SYS_ERR_STAT_META1 0x0000000000000200ULL
+#define SYS_ERR_STAT_PEU 0x0000000000000100ULL
+#define SYS_ERR_STAT_TXC 0x0000000000000080ULL
+#define SYS_ERR_STAT_RDMC 0x0000000000000040ULL
+#define SYS_ERR_STAT_TDMC 0x0000000000000020ULL
+#define SYS_ERR_STAT_ZCP 0x0000000000000010ULL
+#define SYS_ERR_STAT_FFLP 0x0000000000000008ULL
+#define SYS_ERR_STAT_IPP 0x0000000000000004ULL
+#define SYS_ERR_STAT_MAC 0x0000000000000002ULL
+#define SYS_ERR_STAT_SMX 0x0000000000000001ULL
+
+#define SID(LDG) (FZC_PIO + 0x10200UL + (LDG) * 8UL)
+#define SID_FUNC 0x0000000000000060ULL
+#define SID_FUNC_SHIFT 5
+#define SID_VECTOR 0x000000000000001fULL
+#define SID_VECTOR_SHIFT 0
+
+#define LDG_NUM(LDN) (FZC_PIO + 0x20000UL + (LDN) * 8UL)
+
+#define XMAC_PORT0_OFF (FZC_MAC + 0x000000)
+#define XMAC_PORT1_OFF (FZC_MAC + 0x006000)
+#define BMAC_PORT2_OFF (FZC_MAC + 0x00c000)
+#define BMAC_PORT3_OFF (FZC_MAC + 0x010000)
+
+/* XMAC registers, offset from np->mac_regs */
+
+#define XTXMAC_SW_RST 0x00000UL
+#define XTXMAC_SW_RST_REG_RS 0x0000000000000002ULL
+#define XTXMAC_SW_RST_SOFT_RST 0x0000000000000001ULL
+
+#define XRXMAC_SW_RST 0x00008UL
+#define XRXMAC_SW_RST_REG_RS 0x0000000000000002ULL
+#define XRXMAC_SW_RST_SOFT_RST 0x0000000000000001ULL
+
+#define XTXMAC_STATUS 0x00020UL
+#define XTXMAC_STATUS_FRAME_CNT_EXP 0x0000000000000800ULL
+#define XTXMAC_STATUS_BYTE_CNT_EXP 0x0000000000000400ULL
+#define XTXMAC_STATUS_TXFIFO_XFR_ERR 0x0000000000000010ULL
+#define XTXMAC_STATUS_TXMAC_OFLOW 0x0000000000000008ULL
+#define XTXMAC_STATUS_MAX_PSIZE_ERR 0x0000000000000004ULL
+#define XTXMAC_STATUS_TXMAC_UFLOW 0x0000000000000002ULL
+#define XTXMAC_STATUS_FRAME_XMITED 0x0000000000000001ULL
+
+#define XRXMAC_STATUS 0x00028UL
+#define XRXMAC_STATUS_RXHIST7_CNT_EXP 0x0000000000100000ULL
+#define XRXMAC_STATUS_LCL_FLT_STATUS 0x0000000000080000ULL
+#define XRXMAC_STATUS_RFLT_DET 0x0000000000040000ULL
+#define XRXMAC_STATUS_LFLT_CNT_EXP 0x0000000000020000ULL
+#define XRXMAC_STATUS_PHY_MDINT 0x0000000000010000ULL
+#define XRXMAC_STATUS_ALIGNERR_CNT_EXP 0x0000000000010000ULL
+#define XRXMAC_STATUS_RXFRAG_CNT_EXP 0x0000000000008000ULL
+#define XRXMAC_STATUS_RXMULTF_CNT_EXP 0x0000000000004000ULL
+#define XRXMAC_STATUS_RXBCAST_CNT_EXP 0x0000000000002000ULL
+#define XRXMAC_STATUS_RXHIST6_CNT_EXP 0x0000000000001000ULL
+#define XRXMAC_STATUS_RXHIST5_CNT_EXP 0x0000000000000800ULL
+#define XRXMAC_STATUS_RXHIST4_CNT_EXP 0x0000000000000400ULL
+#define XRXMAC_STATUS_RXHIST3_CNT_EXP 0x0000000000000200ULL
+#define XRXMAC_STATUS_RXHIST2_CNT_EXP 0x0000000000000100ULL
+#define XRXMAC_STATUS_RXHIST1_CNT_EXP 0x0000000000000080ULL
+#define XRXMAC_STATUS_RXOCTET_CNT_EXP 0x0000000000000040ULL
+#define XRXMAC_STATUS_CVIOLERR_CNT_EXP 0x0000000000000020ULL
+#define XRXMAC_STATUS_LENERR_CNT_EXP 0x0000000000000010ULL
+#define XRXMAC_STATUS_CRCERR_CNT_EXP 0x0000000000000008ULL
+#define XRXMAC_STATUS_RXUFLOW 0x0000000000000004ULL
+#define XRXMAC_STATUS_RXOFLOW 0x0000000000000002ULL
+#define XRXMAC_STATUS_FRAME_RCVD 0x0000000000000001ULL
+
+#define XMAC_FC_STAT 0x00030UL
+#define XMAC_FC_STAT_RX_RCV_PAUSE_TIME 0x00000000ffff0000ULL
+#define XMAC_FC_STAT_TX_MAC_NPAUSE 0x0000000000000004ULL
+#define XMAC_FC_STAT_TX_MAC_PAUSE 0x0000000000000002ULL
+#define XMAC_FC_STAT_RX_MAC_RPAUSE 0x0000000000000001ULL
+
+#define XTXMAC_STAT_MSK 0x00040UL
+#define XTXMAC_STAT_MSK_FRAME_CNT_EXP 0x0000000000000800ULL
+#define XTXMAC_STAT_MSK_BYTE_CNT_EXP 0x0000000000000400ULL
+#define XTXMAC_STAT_MSK_TXFIFO_XFR_ERR 0x0000000000000010ULL
+#define XTXMAC_STAT_MSK_TXMAC_OFLOW 0x0000000000000008ULL
+#define XTXMAC_STAT_MSK_MAX_PSIZE_ERR 0x0000000000000004ULL
+#define XTXMAC_STAT_MSK_TXMAC_UFLOW 0x0000000000000002ULL
+#define XTXMAC_STAT_MSK_FRAME_XMITED 0x0000000000000001ULL
+
+#define XRXMAC_STAT_MSK 0x00048UL
+#define XRXMAC_STAT_MSK_LCL_FLT_STAT_MSK 0x0000000000080000ULL
+#define XRXMAC_STAT_MSK_RFLT_DET 0x0000000000040000ULL
+#define XRXMAC_STAT_MSK_LFLT_CNT_EXP 0x0000000000020000ULL
+#define XRXMAC_STAT_MSK_PHY_MDINT 0x0000000000010000ULL
+#define XRXMAC_STAT_MSK_RXFRAG_CNT_EXP 0x0000000000008000ULL
+#define XRXMAC_STAT_MSK_RXMULTF_CNT_EXP 0x0000000000004000ULL
+#define XRXMAC_STAT_MSK_RXBCAST_CNT_EXP 0x0000000000002000ULL
+#define XRXMAC_STAT_MSK_RXHIST6_CNT_EXP 0x0000000000001000ULL
+#define XRXMAC_STAT_MSK_RXHIST5_CNT_EXP 0x0000000000000800ULL
+#define XRXMAC_STAT_MSK_RXHIST4_CNT_EXP 0x0000000000000400ULL
+#define XRXMAC_STAT_MSK_RXHIST3_CNT_EXP 0x0000000000000200ULL
+#define XRXMAC_STAT_MSK_RXHIST2_CNT_EXP 0x0000000000000100ULL
+#define XRXMAC_STAT_MSK_RXHIST1_CNT_EXP 0x0000000000000080ULL
+#define XRXMAC_STAT_MSK_RXOCTET_CNT_EXP 0x0000000000000040ULL
+#define XRXMAC_STAT_MSK_CVIOLERR_CNT_EXP 0x0000000000000020ULL
+#define XRXMAC_STAT_MSK_LENERR_CNT_EXP 0x0000000000000010ULL
+#define XRXMAC_STAT_MSK_CRCERR_CNT_EXP 0x0000000000000008ULL
+#define XRXMAC_STAT_MSK_RXUFLOW_CNT_EXP 0x0000000000000004ULL
+#define XRXMAC_STAT_MSK_RXOFLOW_CNT_EXP 0x0000000000000002ULL
+#define XRXMAC_STAT_MSK_FRAME_RCVD 0x0000000000000001ULL
+
+#define XMAC_FC_MSK 0x00050UL
+#define XMAC_FC_MSK_TX_MAC_NPAUSE 0x0000000000000004ULL
+#define XMAC_FC_MSK_TX_MAC_PAUSE 0x0000000000000002ULL
+#define XMAC_FC_MSK_RX_MAC_RPAUSE 0x0000000000000001ULL
+
+#define XMAC_CONFIG 0x00060UL
+#define XMAC_CONFIG_SEL_CLK_25MHZ 0x0000000080000000ULL
+#define XMAC_CONFIG_1G_PCS_BYPASS 0x0000000040000000ULL
+#define XMAC_CONFIG_10G_XPCS_BYPASS 0x0000000020000000ULL
+#define XMAC_CONFIG_MODE_MASK 0x0000000018000000ULL
+#define XMAC_CONFIG_MODE_XGMII 0x0000000000000000ULL
+#define XMAC_CONFIG_MODE_GMII 0x0000000008000000ULL
+#define XMAC_CONFIG_MODE_MII 0x0000000010000000ULL
+#define XMAC_CONFIG_LFS_DISABLE 0x0000000004000000ULL
+#define XMAC_CONFIG_LOOPBACK 0x0000000002000000ULL
+#define XMAC_CONFIG_TX_OUTPUT_EN 0x0000000001000000ULL
+#define XMAC_CONFIG_SEL_POR_CLK_SRC 0x0000000000800000ULL
+#define XMAC_CONFIG_LED_POLARITY 0x0000000000400000ULL
+#define XMAC_CONFIG_FORCE_LED_ON 0x0000000000200000ULL
+#define XMAC_CONFIG_PASS_FLOW_CTRL 0x0000000000100000ULL
+#define XMAC_CONFIG_RCV_PAUSE_ENABLE 0x0000000000080000ULL
+#define XMAC_CONFIG_MAC2IPP_PKT_CNT_EN 0x0000000000040000ULL
+#define XMAC_CONFIG_STRIP_CRC 0x0000000000020000ULL
+#define XMAC_CONFIG_ADDR_FILTER_EN 0x0000000000010000ULL
+#define XMAC_CONFIG_HASH_FILTER_EN 0x0000000000008000ULL
+#define XMAC_CONFIG_RX_CODEV_CHK_DIS 0x0000000000004000ULL
+#define XMAC_CONFIG_RESERVED_MULTICAST 0x0000000000002000ULL
+#define XMAC_CONFIG_RX_CRC_CHK_DIS 0x0000000000001000ULL
+#define XMAC_CONFIG_ERR_CHK_DIS 0x0000000000000800ULL
+#define XMAC_CONFIG_PROMISC_GROUP 0x0000000000000400ULL
+#define XMAC_CONFIG_PROMISCUOUS 0x0000000000000200ULL
+#define XMAC_CONFIG_RX_MAC_ENABLE 0x0000000000000100ULL
+#define XMAC_CONFIG_WARNING_MSG_EN 0x0000000000000080ULL
+#define XMAC_CONFIG_ALWAYS_NO_CRC 0x0000000000000008ULL
+#define XMAC_CONFIG_VAR_MIN_IPG_EN 0x0000000000000004ULL
+#define XMAC_CONFIG_STRETCH_MODE 0x0000000000000002ULL
+#define XMAC_CONFIG_TX_ENABLE 0x0000000000000001ULL
+
+#define XMAC_IPG 0x00080UL
+#define XMAC_IPG_STRETCH_CONST 0x0000000000e00000ULL
+#define XMAC_IPG_STRETCH_CONST_SHIFT 21
+#define XMAC_IPG_STRETCH_RATIO 0x00000000001f0000ULL
+#define XMAC_IPG_STRETCH_RATIO_SHIFT 16
+#define XMAC_IPG_IPG_MII_GMII 0x000000000000ff00ULL
+#define XMAC_IPG_IPG_MII_GMII_SHIFT 8
+#define XMAC_IPG_IPG_XGMII 0x0000000000000007ULL
+#define XMAC_IPG_IPG_XGMII_SHIFT 0
+
+#define IPG_12_15_XGMII 3
+#define IPG_16_19_XGMII 4
+#define IPG_20_23_XGMII 5
+#define IPG_12_MII_GMII 10
+#define IPG_13_MII_GMII 11
+#define IPG_14_MII_GMII 12
+#define IPG_15_MII_GMII 13
+#define IPG_16_MII_GMII 14
+
+#define XMAC_MIN 0x00088UL
+#define XMAC_MIN_RX_MIN_PKT_SIZE 0x000000003ff00000ULL
+#define XMAC_MIN_RX_MIN_PKT_SIZE_SHFT 20
+#define XMAC_MIN_SLOT_TIME 0x000000000003fc00ULL
+#define XMAC_MIN_SLOT_TIME_SHFT 10
+#define XMAC_MIN_TX_MIN_PKT_SIZE 0x00000000000003ffULL
+#define XMAC_MIN_TX_MIN_PKT_SIZE_SHFT 0
+
+#define XMAC_MAX 0x00090UL
+#define XMAC_MAX_FRAME_SIZE 0x0000000000003fffULL
+#define XMAC_MAX_FRAME_SIZE_SHFT 0
+
+#define XMAC_ADDR0 0x000a0UL
+#define XMAC_ADDR0_ADDR0 0x000000000000ffffULL
+
+#define XMAC_ADDR1 0x000a8UL
+#define XMAC_ADDR1_ADDR1 0x000000000000ffffULL
+
+#define XMAC_ADDR2 0x000b0UL
+#define XMAC_ADDR2_ADDR2 0x000000000000ffffULL
+
+#define XMAC_ADDR_CMPEN 0x00208UL
+#define XMAC_ADDR_CMPEN_EN15 0x0000000000008000ULL
+#define XMAC_ADDR_CMPEN_EN14 0x0000000000004000ULL
+#define XMAC_ADDR_CMPEN_EN13 0x0000000000002000ULL
+#define XMAC_ADDR_CMPEN_EN12 0x0000000000001000ULL
+#define XMAC_ADDR_CMPEN_EN11 0x0000000000000800ULL
+#define XMAC_ADDR_CMPEN_EN10 0x0000000000000400ULL
+#define XMAC_ADDR_CMPEN_EN9 0x0000000000000200ULL
+#define XMAC_ADDR_CMPEN_EN8 0x0000000000000100ULL
+#define XMAC_ADDR_CMPEN_EN7 0x0000000000000080ULL
+#define XMAC_ADDR_CMPEN_EN6 0x0000000000000040ULL
+#define XMAC_ADDR_CMPEN_EN5 0x0000000000000020ULL
+#define XMAC_ADDR_CMPEN_EN4 0x0000000000000010ULL
+#define XMAC_ADDR_CMPEN_EN3 0x0000000000000008ULL
+#define XMAC_ADDR_CMPEN_EN2 0x0000000000000004ULL
+#define XMAC_ADDR_CMPEN_EN1 0x0000000000000002ULL
+#define XMAC_ADDR_CMPEN_EN0 0x0000000000000001ULL
+
+#define XMAC_NUM_ALT_ADDR 16
+
+#define XMAC_ALT_ADDR0(NUM) (0x00218UL + (NUM)*0x18UL)
+#define XMAC_ALT_ADDR0_ADDR0 0x000000000000ffffULL
+
+#define XMAC_ALT_ADDR1(NUM) (0x00220UL + (NUM)*0x18UL)
+#define XMAC_ALT_ADDR1_ADDR1 0x000000000000ffffULL
+
+#define XMAC_ALT_ADDR2(NUM) (0x00228UL + (NUM)*0x18UL)
+#define XMAC_ALT_ADDR2_ADDR2 0x000000000000ffffULL
+
+#define XMAC_ADD_FILT0 0x00818UL
+#define XMAC_ADD_FILT0_FILT0 0x000000000000ffffULL
+
+#define XMAC_ADD_FILT1 0x00820UL
+#define XMAC_ADD_FILT1_FILT1 0x000000000000ffffULL
+
+#define XMAC_ADD_FILT2 0x00828UL
+#define XMAC_ADD_FILT2_FILT2 0x000000000000ffffULL
+
+#define XMAC_ADD_FILT12_MASK 0x00830UL
+#define XMAC_ADD_FILT12_MASK_VAL 0x00000000000000ffULL
+
+#define XMAC_ADD_FILT00_MASK 0x00838UL
+#define XMAC_ADD_FILT00_MASK_VAL 0x000000000000ffffULL
+
+#define XMAC_HASH_TBL(NUM) (0x00840UL + (NUM) * 0x8UL)
+#define XMAC_HASH_TBL_VAL 0x000000000000ffffULL
+
+#define XMAC_NUM_HOST_INFO 20
+
+#define XMAC_HOST_INFO(NUM) (0x00900UL + (NUM) * 0x8UL)
+
+#define XMAC_PA_DATA0 0x00b80UL
+#define XMAC_PA_DATA0_VAL 0x00000000ffffffffULL
+
+#define XMAC_PA_DATA1 0x00b88UL
+#define XMAC_PA_DATA1_VAL 0x00000000ffffffffULL
+
+#define XMAC_DEBUG_SEL 0x00b90UL
+#define XMAC_DEBUG_SEL_XMAC 0x0000000000000078ULL
+#define XMAC_DEBUG_SEL_MAC 0x0000000000000007ULL
+
+#define XMAC_TRAIN_VEC 0x00b98UL
+#define XMAC_TRAIN_VEC_VAL 0x00000000ffffffffULL
+
+#define RXMAC_BT_CNT 0x00100UL
+#define RXMAC_BT_CNT_COUNT 0x00000000ffffffffULL
+
+#define RXMAC_BC_FRM_CNT 0x00108UL
+#define RXMAC_BC_FRM_CNT_COUNT 0x00000000001fffffULL
+
+#define RXMAC_MC_FRM_CNT 0x00110UL
+#define RXMAC_MC_FRM_CNT_COUNT 0x00000000001fffffULL
+
+#define RXMAC_FRAG_CNT 0x00118UL
+#define RXMAC_FRAG_CNT_COUNT 0x00000000001fffffULL
+
+#define RXMAC_HIST_CNT1 0x00120UL
+#define RXMAC_HIST_CNT1_COUNT 0x00000000001fffffULL
+
+#define RXMAC_HIST_CNT2 0x00128UL
+#define RXMAC_HIST_CNT2_COUNT 0x00000000001fffffULL
+
+#define RXMAC_HIST_CNT3 0x00130UL
+#define RXMAC_HIST_CNT3_COUNT 0x00000000000fffffULL
+
+#define RXMAC_HIST_CNT4 0x00138UL
+#define RXMAC_HIST_CNT4_COUNT 0x000000000007ffffULL
+
+#define RXMAC_HIST_CNT5 0x00140UL
+#define RXMAC_HIST_CNT5_COUNT 0x000000000003ffffULL
+
+#define RXMAC_HIST_CNT6 0x00148UL
+#define RXMAC_HIST_CNT6_COUNT 0x000000000000ffffULL
+
+#define RXMAC_MPSZER_CNT 0x00150UL
+#define RXMAC_MPSZER_CNT_COUNT 0x00000000000000ffULL
+
+#define RXMAC_CRC_ER_CNT 0x00158UL
+#define RXMAC_CRC_ER_CNT_COUNT 0x00000000000000ffULL
+
+#define RXMAC_CD_VIO_CNT 0x00160UL
+#define RXMAC_CD_VIO_CNT_COUNT 0x00000000000000ffULL
+
+#define RXMAC_ALIGN_ERR_CNT 0x00168UL
+#define RXMAC_ALIGN_ERR_CNT_COUNT 0x00000000000000ffULL
+
+#define TXMAC_FRM_CNT 0x00170UL
+#define TXMAC_FRM_CNT_COUNT 0x00000000ffffffffULL
+
+#define TXMAC_BYTE_CNT 0x00178UL
+#define TXMAC_BYTE_CNT_COUNT 0x00000000ffffffffULL
+
+#define LINK_FAULT_CNT 0x00180UL
+#define LINK_FAULT_CNT_COUNT 0x00000000000000ffULL
+
+#define RXMAC_HIST_CNT7 0x00188UL
+#define RXMAC_HIST_CNT7_COUNT 0x0000000007ffffffULL
+
+#define XMAC_SM_REG 0x001a8UL
+#define XMAC_SM_REG_STATE 0x00000000ffffffffULL
+
+#define XMAC_INTER1 0x001b0UL
+#define XMAC_INTERN1_SIGNALS1 0x00000000ffffffffULL
+
+#define XMAC_INTER2 0x001b8UL
+#define XMAC_INTERN2_SIGNALS2 0x00000000ffffffffULL
+
+/* BMAC registers, offset from np->mac_regs */
+
+#define BTXMAC_SW_RST 0x00000UL
+#define BTXMAC_SW_RST_RESET 0x0000000000000001ULL
+
+#define BRXMAC_SW_RST 0x00008UL
+#define BRXMAC_SW_RST_RESET 0x0000000000000001ULL
+
+#define BMAC_SEND_PAUSE 0x00010UL
+#define BMAC_SEND_PAUSE_SEND 0x0000000000010000ULL
+#define BMAC_SEND_PAUSE_TIME 0x000000000000ffffULL
+
+#define BTXMAC_STATUS 0x00020UL
+#define BTXMAC_STATUS_XMIT 0x0000000000000001ULL
+#define BTXMAC_STATUS_UNDERRUN 0x0000000000000002ULL
+#define BTXMAC_STATUS_MAX_PKT_ERR 0x0000000000000004ULL
+#define BTXMAC_STATUS_BYTE_CNT_EXP 0x0000000000000400ULL
+#define BTXMAC_STATUS_FRAME_CNT_EXP 0x0000000000000800ULL
+
+#define BRXMAC_STATUS 0x00028UL
+#define BRXMAC_STATUS_RX_PKT 0x0000000000000001ULL
+#define BRXMAC_STATUS_OVERFLOW 0x0000000000000002ULL
+#define BRXMAC_STATUS_FRAME_CNT_EXP 0x0000000000000004ULL
+#define BRXMAC_STATUS_ALIGN_ERR_EXP 0x0000000000000008ULL
+#define BRXMAC_STATUS_CRC_ERR_EXP 0x0000000000000010ULL
+#define BRXMAC_STATUS_LEN_ERR_EXP 0x0000000000000020ULL
+
+#define BMAC_CTRL_STATUS 0x00030UL
+#define BMAC_CTRL_STATUS_PAUSE_RECV 0x0000000000000001ULL
+#define BMAC_CTRL_STATUS_PAUSE 0x0000000000000002ULL
+#define BMAC_CTRL_STATUS_NOPAUSE 0x0000000000000004ULL
+#define BMAC_CTRL_STATUS_TIME 0x00000000ffff0000ULL
+#define BMAC_CTRL_STATUS_TIME_SHIFT 16
+
+#define BTXMAC_STATUS_MASK 0x00040UL
+#define BRXMAC_STATUS_MASK 0x00048UL
+#define BMAC_CTRL_STATUS_MASK 0x00050UL
+
+#define BTXMAC_CONFIG 0x00060UL
+#define BTXMAC_CONFIG_ENABLE 0x0000000000000001ULL
+#define BTXMAC_CONFIG_FCS_DISABLE 0x0000000000000002ULL
+
+#define BRXMAC_CONFIG 0x00068UL
+#define BRXMAC_CONFIG_DISCARD_DIS 0x0000000000000080ULL
+#define BRXMAC_CONFIG_ADDR_FILT_EN 0x0000000000000040ULL
+#define BRXMAC_CONFIG_HASH_FILT_EN 0x0000000000000020ULL
+#define BRXMAC_CONFIG_PROMISC_GRP 0x0000000000000010ULL
+#define BRXMAC_CONFIG_PROMISC 0x0000000000000008ULL
+#define BRXMAC_CONFIG_STRIP_FCS 0x0000000000000004ULL
+#define BRXMAC_CONFIG_STRIP_PAD 0x0000000000000002ULL
+#define BRXMAC_CONFIG_ENABLE 0x0000000000000001ULL
+
+#define BMAC_CTRL_CONFIG 0x00070UL
+#define BMAC_CTRL_CONFIG_TX_PAUSE_EN 0x0000000000000001ULL
+#define BMAC_CTRL_CONFIG_RX_PAUSE_EN 0x0000000000000002ULL
+#define BMAC_CTRL_CONFIG_PASS_CTRL 0x0000000000000004ULL
+
+#define BMAC_XIF_CONFIG 0x00078UL
+#define BMAC_XIF_CONFIG_TX_OUTPUT_EN 0x0000000000000001ULL
+#define BMAC_XIF_CONFIG_MII_LOOPBACK 0x0000000000000002ULL
+#define BMAC_XIF_CONFIG_GMII_MODE 0x0000000000000008ULL
+#define BMAC_XIF_CONFIG_LINK_LED 0x0000000000000020ULL
+#define BMAC_XIF_CONFIG_LED_POLARITY 0x0000000000000040ULL
+#define BMAC_XIF_CONFIG_25MHZ_CLOCK 0x0000000000000080ULL
+
+#define BMAC_MIN_FRAME 0x000a0UL
+#define BMAC_MIN_FRAME_VAL 0x00000000000003ffULL
+
+#define BMAC_MAX_FRAME 0x000a8UL
+#define BMAC_MAX_FRAME_MAX_BURST 0x000000003fff0000ULL
+#define BMAC_MAX_FRAME_MAX_BURST_SHIFT 16
+#define BMAC_MAX_FRAME_MAX_FRAME 0x0000000000003fffULL
+#define BMAC_MAX_FRAME_MAX_FRAME_SHIFT 0
+
+#define BMAC_PREAMBLE_SIZE 0x000b0UL
+#define BMAC_PREAMBLE_SIZE_VAL 0x00000000000003ffULL
+
+#define BMAC_CTRL_TYPE 0x000c8UL
+
+#define BMAC_ADDR0 0x00100UL
+#define BMAC_ADDR0_ADDR0 0x000000000000ffffULL
+
+#define BMAC_ADDR1 0x00108UL
+#define BMAC_ADDR1_ADDR1 0x000000000000ffffULL
+
+#define BMAC_ADDR2 0x00110UL
+#define BMAC_ADDR2_ADDR2 0x000000000000ffffULL
+
+#define BMAC_NUM_ALT_ADDR 7
+
+#define BMAC_ALT_ADDR0(NUM) (0x00118UL + (NUM)*0x18UL)
+#define BMAC_ALT_ADDR0_ADDR0 0x000000000000ffffULL
+
+#define BMAC_ALT_ADDR1(NUM) (0x00120UL + (NUM)*0x18UL)
+#define BMAC_ALT_ADDR1_ADDR1 0x000000000000ffffULL
+
+#define BMAC_ALT_ADDR2(NUM) (0x00128UL + (NUM)*0x18UL)
+#define BMAC_ALT_ADDR2_ADDR2 0x000000000000ffffULL
+
+#define BMAC_FC_ADDR0 0x00268UL
+#define BMAC_FC_ADDR0_ADDR0 0x000000000000ffffULL
+
+#define BMAC_FC_ADDR1 0x00270UL
+#define BMAC_FC_ADDR1_ADDR1 0x000000000000ffffULL
+
+#define BMAC_FC_ADDR2 0x00278UL
+#define BMAC_FC_ADDR2_ADDR2 0x000000000000ffffULL
+
+#define BMAC_ADD_FILT0 0x00298UL
+#define BMAC_ADD_FILT0_FILT0 0x000000000000ffffULL
+
+#define BMAC_ADD_FILT1 0x002a0UL
+#define BMAC_ADD_FILT1_FILT1 0x000000000000ffffULL
+
+#define BMAC_ADD_FILT2 0x002a8UL
+#define BMAC_ADD_FILT2_FILT2 0x000000000000ffffULL
+
+#define BMAC_ADD_FILT12_MASK 0x002b0UL
+#define BMAC_ADD_FILT12_MASK_VAL 0x00000000000000ffULL
+
+#define BMAC_ADD_FILT00_MASK 0x002b8UL
+#define BMAC_ADD_FILT00_MASK_VAL 0x000000000000ffffULL
+
+#define BMAC_HASH_TBL(NUM) (0x002c0UL + (NUM) * 0x8UL)
+#define BMAC_HASH_TBL_VAL 0x000000000000ffffULL
+
+#define BRXMAC_FRAME_CNT 0x00370
+#define BRXMAC_FRAME_CNT_COUNT 0x000000000000ffffULL
+
+#define BRXMAC_MAX_LEN_ERR_CNT 0x00378
+
+#define BRXMAC_ALIGN_ERR_CNT 0x00380
+#define BRXMAC_ALIGN_ERR_CNT_COUNT 0x000000000000ffffULL
+
+#define BRXMAC_CRC_ERR_CNT 0x00388
+#define BRXMAC_ALIGN_ERR_CNT_COUNT 0x000000000000ffffULL
+
+#define BRXMAC_CODE_VIOL_ERR_CNT 0x00390
+#define BRXMAC_CODE_VIOL_ERR_CNT_COUNT 0x000000000000ffffULL
+
+#define BMAC_STATE_MACHINE 0x003a0
+
+#define BMAC_ADDR_CMPEN 0x003f8UL
+#define BMAC_ADDR_CMPEN_EN15 0x0000000000008000ULL
+#define BMAC_ADDR_CMPEN_EN14 0x0000000000004000ULL
+#define BMAC_ADDR_CMPEN_EN13 0x0000000000002000ULL
+#define BMAC_ADDR_CMPEN_EN12 0x0000000000001000ULL
+#define BMAC_ADDR_CMPEN_EN11 0x0000000000000800ULL
+#define BMAC_ADDR_CMPEN_EN10 0x0000000000000400ULL
+#define BMAC_ADDR_CMPEN_EN9 0x0000000000000200ULL
+#define BMAC_ADDR_CMPEN_EN8 0x0000000000000100ULL
+#define BMAC_ADDR_CMPEN_EN7 0x0000000000000080ULL
+#define BMAC_ADDR_CMPEN_EN6 0x0000000000000040ULL
+#define BMAC_ADDR_CMPEN_EN5 0x0000000000000020ULL
+#define BMAC_ADDR_CMPEN_EN4 0x0000000000000010ULL
+#define BMAC_ADDR_CMPEN_EN3 0x0000000000000008ULL
+#define BMAC_ADDR_CMPEN_EN2 0x0000000000000004ULL
+#define BMAC_ADDR_CMPEN_EN1 0x0000000000000002ULL
+#define BMAC_ADDR_CMPEN_EN0 0x0000000000000001ULL
+
+#define BMAC_NUM_HOST_INFO 9
+
+#define BMAC_HOST_INFO(NUM) (0x00400UL + (NUM) * 0x8UL)
+
+#define BTXMAC_BYTE_CNT 0x00448UL
+#define BTXMAC_BYTE_CNT_COUNT 0x00000000ffffffffULL
+
+#define BTXMAC_FRM_CNT 0x00450UL
+#define BTXMAC_FRM_CNT_COUNT 0x00000000ffffffffULL
+
+#define BRXMAC_BYTE_CNT 0x00458UL
+#define BRXMAC_BYTE_CNT_COUNT 0x00000000ffffffffULL
+
+#define HOST_INFO_MPR 0x0000000000000100ULL
+#define HOST_INFO_MACRDCTBLN 0x0000000000000007ULL
+
+/* XPCS registers, offset from np->regs + np->xpcs_off */
+
+#define XPCS_CONTROL1 (FZC_MAC + 0x00000UL)
+#define XPCS_CONTROL1_RESET 0x0000000000008000ULL
+#define XPCS_CONTROL1_LOOPBACK 0x0000000000004000ULL
+#define XPCS_CONTROL1_SPEED_SELECT3 0x0000000000002000ULL
+#define XPCS_CONTROL1_CSR_LOW_PWR 0x0000000000000800ULL
+#define XPCS_CONTROL1_CSR_SPEED1 0x0000000000000040ULL
+#define XPCS_CONTROL1_CSR_SPEED0 0x000000000000003cULL
+
+#define XPCS_STATUS1 (FZC_MAC + 0x00008UL)
+#define XPCS_STATUS1_CSR_FAULT 0x0000000000000080ULL
+#define XPCS_STATUS1_CSR_RXLNK_STAT 0x0000000000000004ULL
+#define XPCS_STATUS1_CSR_LPWR_ABLE 0x0000000000000002ULL
+
+#define XPCS_DEVICE_IDENTIFIER (FZC_MAC + 0x00010UL)
+#define XPCS_DEVICE_IDENTIFIER_VAL 0x00000000ffffffffULL
+
+#define XPCS_SPEED_ABILITY (FZC_MAC + 0x00018UL)
+#define XPCS_SPEED_ABILITY_10GIG 0x0000000000000001ULL
+
+#define XPCS_DEV_IN_PKG (FZC_MAC + 0x00020UL)
+#define XPCS_DEV_IN_PKG_CSR_VEND2 0x0000000080000000ULL
+#define XPCS_DEV_IN_PKG_CSR_VEND1 0x0000000040000000ULL
+#define XPCS_DEV_IN_PKG_DTE_XS 0x0000000000000020ULL
+#define XPCS_DEV_IN_PKG_PHY_XS 0x0000000000000010ULL
+#define XPCS_DEV_IN_PKG_PCS 0x0000000000000008ULL
+#define XPCS_DEV_IN_PKG_WIS 0x0000000000000004ULL
+#define XPCS_DEV_IN_PKG_PMD_PMA 0x0000000000000002ULL
+#define XPCS_DEV_IN_PKG_CLS22 0x0000000000000001ULL
+
+#define XPCS_CONTROL2 (FZC_MAC + 0x00028UL)
+#define XPCS_CONTROL2_CSR_PSC_SEL 0x0000000000000003ULL
+
+#define XPCS_STATUS2 (FZC_MAC + 0x00030UL)
+#define XPCS_STATUS2_CSR_DEV_PRES 0x000000000000c000ULL
+#define XPCS_STATUS2_CSR_TX_FAULT 0x0000000000000800ULL
+#define XPCS_STATUS2_CSR_RCV_FAULT 0x0000000000000400ULL
+#define XPCS_STATUS2_TEN_GBASE_W 0x0000000000000004ULL
+#define XPCS_STATUS2_TEN_GBASE_X 0x0000000000000002ULL
+#define XPCS_STATUS2_TEN_GBASE_R 0x0000000000000001ULL
+
+#define XPCS_PKG_ID (FZC_MAC + 0x00038UL)
+#define XPCS_PKG_ID_VAL 0x00000000ffffffffULL
+
+#define XPCS_STATUS(IDX) (FZC_MAC + 0x00040UL)
+#define XPCS_STATUS_CSR_LANE_ALIGN 0x0000000000001000ULL
+#define XPCS_STATUS_CSR_PATTEST_CAP 0x0000000000000800ULL
+#define XPCS_STATUS_CSR_LANE3_SYNC 0x0000000000000008ULL
+#define XPCS_STATUS_CSR_LANE2_SYNC 0x0000000000000004ULL
+#define XPCS_STATUS_CSR_LANE1_SYNC 0x0000000000000002ULL
+#define XPCS_STATUS_CSR_LANE0_SYNC 0x0000000000000001ULL
+
+#define XPCS_TEST_CONTROL (FZC_MAC + 0x00048UL)
+#define XPCS_TEST_CONTROL_TXTST_EN 0x0000000000000004ULL
+#define XPCS_TEST_CONTROL_TPAT_SEL 0x0000000000000003ULL
+
+#define XPCS_CFG_VENDOR1 (FZC_MAC + 0x00050UL)
+#define XPCS_CFG_VENDOR1_DBG_IOTST 0x0000000000000080ULL
+#define XPCS_CFG_VENDOR1_DBG_SEL 0x0000000000000078ULL
+#define XPCS_CFG_VENDOR1_BYPASS_DET 0x0000000000000004ULL
+#define XPCS_CFG_VENDOR1_TXBUF_EN 0x0000000000000002ULL
+#define XPCS_CFG_VENDOR1_XPCS_EN 0x0000000000000001ULL
+
+#define XPCS_DIAG_VENDOR2 (FZC_MAC + 0x00058UL)
+#define XPCS_DIAG_VENDOR2_SSM_LANE3 0x0000000001e00000ULL
+#define XPCS_DIAG_VENDOR2_SSM_LANE2 0x00000000001e0000ULL
+#define XPCS_DIAG_VENDOR2_SSM_LANE1 0x000000000001e000ULL
+#define XPCS_DIAG_VENDOR2_SSM_LANE0 0x0000000000001e00ULL
+#define XPCS_DIAG_VENDOR2_EBUF_SM 0x00000000000001feULL
+#define XPCS_DIAG_VENDOR2_RCV_SM 0x0000000000000001ULL
+
+#define XPCS_MASK1 (FZC_MAC + 0x00060UL)
+#define XPCS_MASK1_FAULT_MASK 0x0000000000000080ULL
+#define XPCS_MASK1_RXALIGN_STAT_MSK 0x0000000000000004ULL
+
+#define XPCS_PKT_COUNT (FZC_MAC + 0x00068UL)
+#define XPCS_PKT_COUNT_TX 0x00000000ffff0000ULL
+#define XPCS_PKT_COUNT_RX 0x000000000000ffffULL
+
+#define XPCS_TX_SM (FZC_MAC + 0x00070UL)
+#define XPCS_TX_SM_VAL 0x000000000000000fULL
+
+#define XPCS_DESKEW_ERR_CNT (FZC_MAC + 0x00078UL)
+#define XPCS_DESKEW_ERR_CNT_VAL 0x00000000000000ffULL
+
+#define XPCS_SYMERR_CNT01 (FZC_MAC + 0x00080UL)
+#define XPCS_SYMERR_CNT01_LANE1 0x00000000ffff0000ULL
+#define XPCS_SYMERR_CNT01_LANE0 0x000000000000ffffULL
+
+#define XPCS_SYMERR_CNT23 (FZC_MAC + 0x00088UL)
+#define XPCS_SYMERR_CNT23_LANE3 0x00000000ffff0000ULL
+#define XPCS_SYMERR_CNT23_LANE2 0x000000000000ffffULL
+
+#define XPCS_TRAINING_VECTOR (FZC_MAC + 0x00090UL)
+#define XPCS_TRAINING_VECTOR_VAL 0x00000000ffffffffULL
+
+/* PCS registers, offset from np->regs + np->pcs_off */
+
+#define PCS_MII_CTL (FZC_MAC + 0x00000UL)
+#define PCS_MII_CTL_RST 0x0000000000008000ULL
+#define PCS_MII_CTL_10_100_SPEED 0x0000000000002000ULL
+#define PCS_MII_AUTONEG_EN 0x0000000000001000ULL
+#define PCS_MII_PWR_DOWN 0x0000000000000800ULL
+#define PCS_MII_ISOLATE 0x0000000000000400ULL
+#define PCS_MII_AUTONEG_RESTART 0x0000000000000200ULL
+#define PCS_MII_DUPLEX 0x0000000000000100ULL
+#define PCS_MII_COLL_TEST 0x0000000000000080ULL
+#define PCS_MII_1000MB_SPEED 0x0000000000000040ULL
+
+#define PCS_MII_STAT (FZC_MAC + 0x00008UL)
+#define PCS_MII_STAT_EXT_STATUS 0x0000000000000100ULL
+#define PCS_MII_STAT_AUTONEG_DONE 0x0000000000000020ULL
+#define PCS_MII_STAT_REMOTE_FAULT 0x0000000000000010ULL
+#define PCS_MII_STAT_AUTONEG_ABLE 0x0000000000000008ULL
+#define PCS_MII_STAT_LINK_STATUS 0x0000000000000004ULL
+#define PCS_MII_STAT_JABBER_DET 0x0000000000000002ULL
+#define PCS_MII_STAT_EXT_CAP 0x0000000000000001ULL
+
+#define PCS_MII_ADV (FZC_MAC + 0x00010UL)
+#define PCS_MII_ADV_NEXT_PAGE 0x0000000000008000ULL
+#define PCS_MII_ADV_ACK 0x0000000000004000ULL
+#define PCS_MII_ADV_REMOTE_FAULT 0x0000000000003000ULL
+#define PCS_MII_ADV_ASM_DIR 0x0000000000000100ULL
+#define PCS_MII_ADV_PAUSE 0x0000000000000080ULL
+#define PCS_MII_ADV_HALF_DUPLEX 0x0000000000000040ULL
+#define PCS_MII_ADV_FULL_DUPLEX 0x0000000000000020ULL
+
+#define PCS_MII_PARTNER (FZC_MAC + 0x00018UL)
+#define PCS_MII_PARTNER_NEXT_PAGE 0x0000000000008000ULL
+#define PCS_MII_PARTNER_ACK 0x0000000000004000ULL
+#define PCS_MII_PARTNER_REMOTE_FAULT 0x0000000000002000ULL
+#define PCS_MII_PARTNER_PAUSE 0x0000000000000180ULL
+#define PCS_MII_PARTNER_HALF_DUPLEX 0x0000000000000040ULL
+#define PCS_MII_PARTNER_FULL_DUPLEX 0x0000000000000020ULL
+
+#define PCS_CONF (FZC_MAC + 0x00020UL)
+#define PCS_CONF_MASK 0x0000000000000040ULL
+#define PCS_CONF_10MS_TMR_OVERRIDE 0x0000000000000020ULL
+#define PCS_CONF_JITTER_STUDY 0x0000000000000018ULL
+#define PCS_CONF_SIGDET_ACTIVE_LOW 0x0000000000000004ULL
+#define PCS_CONF_SIGDET_OVERRIDE 0x0000000000000002ULL
+#define PCS_CONF_ENABLE 0x0000000000000001ULL
+
+#define PCS_STATE (FZC_MAC + 0x00028UL)
+#define PCS_STATE_D_PARTNER_FAIL 0x0000000020000000ULL
+#define PCS_STATE_D_WAIT_C_CODES_ACK 0x0000000010000000ULL
+#define PCS_STATE_D_SYNC_LOSS 0x0000000008000000ULL
+#define PCS_STATE_D_NO_GOOD_C_CODES 0x0000000004000000ULL
+#define PCS_STATE_D_SERDES 0x0000000002000000ULL
+#define PCS_STATE_D_BREAKLINK_C_CODES 0x0000000001000000ULL
+#define PCS_STATE_L_SIGDET 0x0000000000400000ULL
+#define PCS_STATE_L_SYNC_LOSS 0x0000000000200000ULL
+#define PCS_STATE_L_C_CODES 0x0000000000100000ULL
+#define PCS_STATE_LINK_CFG_STATE 0x000000000001e000ULL
+#define PCS_STATE_SEQ_DET_STATE 0x0000000000001800ULL
+#define PCS_STATE_WORD_SYNC_STATE 0x0000000000000700ULL
+#define PCS_STATE_NO_IDLE 0x000000000000000fULL
+
+#define PCS_INTERRUPT (FZC_MAC + 0x00030UL)
+#define PCS_INTERRUPT_LSTATUS 0x0000000000000004ULL
+
+#define PCS_DPATH_MODE (FZC_MAC + 0x000a0UL)
+#define PCS_DPATH_MODE_PCS 0x0000000000000000ULL
+#define PCS_DPATH_MODE_MII 0x0000000000000002ULL
+#define PCS_DPATH_MODE_LINKUP_F_ENAB 0x0000000000000001ULL
+
+#define PCS_PKT_CNT (FZC_MAC + 0x000c0UL)
+#define PCS_PKT_CNT_RX 0x0000000007ff0000ULL
+#define PCS_PKT_CNT_TX 0x00000000000007ffULL
+
+#define MIF_BB_MDC (FZC_MAC + 0x16000UL)
+#define MIF_BB_MDC_CLK 0x0000000000000001ULL
+
+#define MIF_BB_MDO (FZC_MAC + 0x16008UL)
+#define MIF_BB_MDO_DAT 0x0000000000000001ULL
+
+#define MIF_BB_MDO_EN (FZC_MAC + 0x16010UL)
+#define MIF_BB_MDO_EN_VAL 0x0000000000000001ULL
+
+#define MIF_FRAME_OUTPUT (FZC_MAC + 0x16018UL)
+#define MIF_FRAME_OUTPUT_ST 0x00000000c0000000ULL
+#define MIF_FRAME_OUTPUT_ST_SHIFT 30
+#define MIF_FRAME_OUTPUT_OP_ADDR 0x0000000000000000ULL
+#define MIF_FRAME_OUTPUT_OP_WRITE 0x0000000010000000ULL
+#define MIF_FRAME_OUTPUT_OP_READ_INC 0x0000000020000000ULL
+#define MIF_FRAME_OUTPUT_OP_READ 0x0000000030000000ULL
+#define MIF_FRAME_OUTPUT_OP_SHIFT 28
+#define MIF_FRAME_OUTPUT_PORT 0x000000000f800000ULL
+#define MIF_FRAME_OUTPUT_PORT_SHIFT 23
+#define MIF_FRAME_OUTPUT_REG 0x00000000007c0000ULL
+#define MIF_FRAME_OUTPUT_REG_SHIFT 18
+#define MIF_FRAME_OUTPUT_TA 0x0000000000030000ULL
+#define MIF_FRAME_OUTPUT_TA_SHIFT 16
+#define MIF_FRAME_OUTPUT_DATA 0x000000000000ffffULL
+#define MIF_FRAME_OUTPUT_DATA_SHIFT 0
+
+#define MDIO_ADDR_OP(port, dev, reg) \
+ ((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+ MIF_FRAME_OUTPUT_OP_ADDR | \
+ (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+ (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+ (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \
+ (reg << MIF_FRAME_OUTPUT_DATA_SHIFT))
+
+#define MDIO_READ_OP(port, dev) \
+ ((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+ MIF_FRAME_OUTPUT_OP_READ | \
+ (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+ (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+ (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT))
+
+#define MDIO_WRITE_OP(port, dev, data) \
+ ((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+ MIF_FRAME_OUTPUT_OP_WRITE | \
+ (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+ (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+ (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \
+ (data << MIF_FRAME_OUTPUT_DATA_SHIFT))
+
+#define MII_READ_OP(port, reg) \
+ ((1 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+ (2 << MIF_FRAME_OUTPUT_OP_SHIFT) | \
+ (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+ (reg << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+ (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT))
+
+#define MII_WRITE_OP(port, reg, data) \
+ ((1 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+ (1 << MIF_FRAME_OUTPUT_OP_SHIFT) | \
+ (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+ (reg << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+ (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \
+ (data << MIF_FRAME_OUTPUT_DATA_SHIFT))
+
+#define MIF_CONFIG (FZC_MAC + 0x16020UL)
+#define MIF_CONFIG_ATCA_GE 0x0000000000010000ULL
+#define MIF_CONFIG_INDIRECT_MODE 0x0000000000008000ULL
+#define MIF_CONFIG_POLL_PRT_PHYADDR 0x0000000000003c00ULL
+#define MIF_CONFIG_POLL_DEV_REG_ADDR 0x00000000000003e0ULL
+#define MIF_CONFIG_BB_MODE 0x0000000000000010ULL
+#define MIF_CONFIG_POLL_EN 0x0000000000000008ULL
+#define MIF_CONFIG_BB_SER_SEL 0x0000000000000006ULL
+#define MIF_CONFIG_MANUAL_MODE 0x0000000000000001ULL
+
+#define MIF_POLL_STATUS (FZC_MAC + 0x16028UL)
+#define MIF_POLL_STATUS_DATA 0x00000000ffff0000ULL
+#define MIF_POLL_STATUS_STAT 0x000000000000ffffULL
+
+#define MIF_POLL_MASK (FZC_MAC + 0x16030UL)
+#define MIF_POLL_MASK_VAL 0x000000000000ffffULL
+
+#define MIF_SM (FZC_MAC + 0x16038UL)
+#define MIF_SM_PORT_ADDR 0x00000000001f0000ULL
+#define MIF_SM_MDI_1 0x0000000000004000ULL
+#define MIF_SM_MDI_0 0x0000000000002400ULL
+#define MIF_SM_MDCLK 0x0000000000001000ULL
+#define MIF_SM_MDO_EN 0x0000000000000800ULL
+#define MIF_SM_MDO 0x0000000000000400ULL
+#define MIF_SM_MDI 0x0000000000000200ULL
+#define MIF_SM_CTL 0x00000000000001c0ULL
+#define MIF_SM_EX 0x000000000000003fULL
+
+#define MIF_STATUS (FZC_MAC + 0x16040UL)
+#define MIF_STATUS_MDINT1 0x0000000000000020ULL
+#define MIF_STATUS_MDINT0 0x0000000000000010ULL
+
+#define MIF_MASK (FZC_MAC + 0x16048UL)
+#define MIF_MASK_MDINT1 0x0000000000000020ULL
+#define MIF_MASK_MDINT0 0x0000000000000010ULL
+#define MIF_MASK_PEU_ERR 0x0000000000000008ULL
+#define MIF_MASK_YC 0x0000000000000004ULL
+#define MIF_MASK_XGE_ERR0 0x0000000000000002ULL
+#define MIF_MASK_MIF_INIT_DONE 0x0000000000000001ULL
+
+#define ENET_SERDES_RESET (FZC_MAC + 0x14000UL)
+#define ENET_SERDES_RESET_1 0x0000000000000002ULL
+#define ENET_SERDES_RESET_0 0x0000000000000001ULL
+
+#define ENET_SERDES_CFG (FZC_MAC + 0x14008UL)
+#define ENET_SERDES_BE_LOOPBACK 0x0000000000000002ULL
+#define ENET_SERDES_CFG_FORCE_RDY 0x0000000000000001ULL
+
+#define ENET_SERDES_0_PLL_CFG (FZC_MAC + 0x14010UL)
+#define ENET_SERDES_PLL_FBDIV0 0x0000000000000001ULL
+#define ENET_SERDES_PLL_FBDIV1 0x0000000000000002ULL
+#define ENET_SERDES_PLL_FBDIV2 0x0000000000000004ULL
+#define ENET_SERDES_PLL_HRATE0 0x0000000000000008ULL
+#define ENET_SERDES_PLL_HRATE1 0x0000000000000010ULL
+#define ENET_SERDES_PLL_HRATE2 0x0000000000000020ULL
+#define ENET_SERDES_PLL_HRATE3 0x0000000000000040ULL
+
+#define ENET_SERDES_0_CTRL_CFG (FZC_MAC + 0x14018UL)
+#define ENET_SERDES_CTRL_SDET_0 0x0000000000000001ULL
+#define ENET_SERDES_CTRL_SDET_1 0x0000000000000002ULL
+#define ENET_SERDES_CTRL_SDET_2 0x0000000000000004ULL
+#define ENET_SERDES_CTRL_SDET_3 0x0000000000000008ULL
+#define ENET_SERDES_CTRL_EMPH_0 0x0000000000000070ULL
+#define ENET_SERDES_CTRL_EMPH_0_SHIFT 4
+#define ENET_SERDES_CTRL_EMPH_1 0x0000000000000380ULL
+#define ENET_SERDES_CTRL_EMPH_1_SHIFT 7
+#define ENET_SERDES_CTRL_EMPH_2 0x0000000000001c00ULL
+#define ENET_SERDES_CTRL_EMPH_2_SHIFT 10
+#define ENET_SERDES_CTRL_EMPH_3 0x000000000000e000ULL
+#define ENET_SERDES_CTRL_EMPH_3_SHIFT 13
+#define ENET_SERDES_CTRL_LADJ_0 0x0000000000070000ULL
+#define ENET_SERDES_CTRL_LADJ_0_SHIFT 16
+#define ENET_SERDES_CTRL_LADJ_1 0x0000000000380000ULL
+#define ENET_SERDES_CTRL_LADJ_1_SHIFT 19
+#define ENET_SERDES_CTRL_LADJ_2 0x0000000001c00000ULL
+#define ENET_SERDES_CTRL_LADJ_2_SHIFT 22
+#define ENET_SERDES_CTRL_LADJ_3 0x000000000e000000ULL
+#define ENET_SERDES_CTRL_LADJ_3_SHIFT 25
+#define ENET_SERDES_CTRL_RXITERM_0 0x0000000010000000ULL
+#define ENET_SERDES_CTRL_RXITERM_1 0x0000000020000000ULL
+#define ENET_SERDES_CTRL_RXITERM_2 0x0000000040000000ULL
+#define ENET_SERDES_CTRL_RXITERM_3 0x0000000080000000ULL
+
+#define ENET_SERDES_0_TEST_CFG (FZC_MAC + 0x14020UL)
+#define ENET_SERDES_TEST_MD_0 0x0000000000000003ULL
+#define ENET_SERDES_TEST_MD_0_SHIFT 0
+#define ENET_SERDES_TEST_MD_1 0x000000000000000cULL
+#define ENET_SERDES_TEST_MD_1_SHIFT 2
+#define ENET_SERDES_TEST_MD_2 0x0000000000000030ULL
+#define ENET_SERDES_TEST_MD_2_SHIFT 4
+#define ENET_SERDES_TEST_MD_3 0x00000000000000c0ULL
+#define ENET_SERDES_TEST_MD_3_SHIFT 6
+
+#define ENET_TEST_MD_NO_LOOPBACK 0x0
+#define ENET_TEST_MD_EWRAP 0x1
+#define ENET_TEST_MD_PAD_LOOPBACK 0x2
+#define ENET_TEST_MD_REV_LOOPBACK 0x3
+
+#define ENET_SERDES_1_PLL_CFG (FZC_MAC + 0x14028UL)
+#define ENET_SERDES_1_CTRL_CFG (FZC_MAC + 0x14030UL)
+#define ENET_SERDES_1_TEST_CFG (FZC_MAC + 0x14038UL)
+
+#define ENET_RGMII_CFG_REG (FZC_MAC + 0x14040UL)
+
+#define ESR_INT_SIGNALS (FZC_MAC + 0x14800UL)
+#define ESR_INT_SIGNALS_ALL 0x00000000ffffffffULL
+#define ESR_INT_SIGNALS_P0_BITS 0x0000000033e0000fULL
+#define ESR_INT_SIGNALS_P1_BITS 0x000000000c1f00f0ULL
+#define ESR_INT_SRDY0_P0 0x0000000020000000ULL
+#define ESR_INT_DET0_P0 0x0000000010000000ULL
+#define ESR_INT_SRDY0_P1 0x0000000008000000ULL
+#define ESR_INT_DET0_P1 0x0000000004000000ULL
+#define ESR_INT_XSRDY_P0 0x0000000002000000ULL
+#define ESR_INT_XDP_P0_CH3 0x0000000001000000ULL
+#define ESR_INT_XDP_P0_CH2 0x0000000000800000ULL
+#define ESR_INT_XDP_P0_CH1 0x0000000000400000ULL
+#define ESR_INT_XDP_P0_CH0 0x0000000000200000ULL
+#define ESR_INT_XSRDY_P1 0x0000000000100000ULL
+#define ESR_INT_XDP_P1_CH3 0x0000000000080000ULL
+#define ESR_INT_XDP_P1_CH2 0x0000000000040000ULL
+#define ESR_INT_XDP_P1_CH1 0x0000000000020000ULL
+#define ESR_INT_XDP_P1_CH0 0x0000000000010000ULL
+#define ESR_INT_SLOSS_P1_CH3 0x0000000000000080ULL
+#define ESR_INT_SLOSS_P1_CH2 0x0000000000000040ULL
+#define ESR_INT_SLOSS_P1_CH1 0x0000000000000020ULL
+#define ESR_INT_SLOSS_P1_CH0 0x0000000000000010ULL
+#define ESR_INT_SLOSS_P0_CH3 0x0000000000000008ULL
+#define ESR_INT_SLOSS_P0_CH2 0x0000000000000004ULL
+#define ESR_INT_SLOSS_P0_CH1 0x0000000000000002ULL
+#define ESR_INT_SLOSS_P0_CH0 0x0000000000000001ULL
+
+#define ESR_DEBUG_SEL (FZC_MAC + 0x14808UL)
+#define ESR_DEBUG_SEL_VAL 0x000000000000003fULL
+
+/* SerDes registers behind MIF */
+#define NIU_ESR_DEV_ADDR 0x1e
+#define ESR_BASE 0x0000
+
+#define ESR_RXTX_COMM_CTRL_L (ESR_BASE + 0x0000)
+#define ESR_RXTX_COMM_CTRL_H (ESR_BASE + 0x0001)
+
+#define ESR_RXTX_RESET_CTRL_L (ESR_BASE + 0x0002)
+#define ESR_RXTX_RESET_CTRL_H (ESR_BASE + 0x0003)
+
+#define ESR_RX_POWER_CTRL_L (ESR_BASE + 0x0004)
+#define ESR_RX_POWER_CTRL_H (ESR_BASE + 0x0005)
+
+#define ESR_TX_POWER_CTRL_L (ESR_BASE + 0x0006)
+#define ESR_TX_POWER_CTRL_H (ESR_BASE + 0x0007)
+
+#define ESR_MISC_POWER_CTRL_L (ESR_BASE + 0x0008)
+#define ESR_MISC_POWER_CTRL_H (ESR_BASE + 0x0009)
+
+#define ESR_RXTX_CTRL_L(CHAN) (ESR_BASE + 0x0080 + (CHAN) * 0x10)
+#define ESR_RXTX_CTRL_H(CHAN) (ESR_BASE + 0x0081 + (CHAN) * 0x10)
+#define ESR_RXTX_CTRL_BIASCNTL 0x80000000
+#define ESR_RXTX_CTRL_RESV1 0x7c000000
+#define ESR_RXTX_CTRL_TDENFIFO 0x02000000
+#define ESR_RXTX_CTRL_TDWS20 0x01000000
+#define ESR_RXTX_CTRL_VMUXLO 0x00c00000
+#define ESR_RXTX_CTRL_VMUXLO_SHIFT 22
+#define ESR_RXTX_CTRL_VPULSELO 0x00300000
+#define ESR_RXTX_CTRL_VPULSELO_SHIFT 20
+#define ESR_RXTX_CTRL_RESV2 0x000f0000
+#define ESR_RXTX_CTRL_RESV3 0x0000c000
+#define ESR_RXTX_CTRL_RXPRESWIN 0x00003000
+#define ESR_RXTX_CTRL_RXPRESWIN_SHIFT 12
+#define ESR_RXTX_CTRL_RESV4 0x00000800
+#define ESR_RXTX_CTRL_RISEFALL 0x00000700
+#define ESR_RXTX_CTRL_RISEFALL_SHIFT 8
+#define ESR_RXTX_CTRL_RESV5 0x000000fe
+#define ESR_RXTX_CTRL_ENSTRETCH 0x00000001
+
+#define ESR_RXTX_TUNING_L(CHAN) (ESR_BASE + 0x0082 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING_H(CHAN) (ESR_BASE + 0x0083 + (CHAN) * 0x10)
+
+#define ESR_RX_SYNCCHAR_L(CHAN) (ESR_BASE + 0x0084 + (CHAN) * 0x10)
+#define ESR_RX_SYNCCHAR_H(CHAN) (ESR_BASE + 0x0085 + (CHAN) * 0x10)
+
+#define ESR_RXTX_TEST_L(CHAN) (ESR_BASE + 0x0086 + (CHAN) * 0x10)
+#define ESR_RXTX_TEST_H(CHAN) (ESR_BASE + 0x0087 + (CHAN) * 0x10)
+
+#define ESR_GLUE_CTRL0_L(CHAN) (ESR_BASE + 0x0088 + (CHAN) * 0x10)
+#define ESR_GLUE_CTRL0_H(CHAN) (ESR_BASE + 0x0089 + (CHAN) * 0x10)
+#define ESR_GLUE_CTRL0_RESV1 0xf8000000
+#define ESR_GLUE_CTRL0_BLTIME 0x07000000
+#define ESR_GLUE_CTRL0_BLTIME_SHIFT 24
+#define ESR_GLUE_CTRL0_RESV2 0x00ff0000
+#define ESR_GLUE_CTRL0_RXLOS_TEST 0x00008000
+#define ESR_GLUE_CTRL0_RESV3 0x00004000
+#define ESR_GLUE_CTRL0_RXLOSENAB 0x00002000
+#define ESR_GLUE_CTRL0_FASTRESYNC 0x00001000
+#define ESR_GLUE_CTRL0_SRATE 0x00000f00
+#define ESR_GLUE_CTRL0_SRATE_SHIFT 8
+#define ESR_GLUE_CTRL0_THCNT 0x000000ff
+#define ESR_GLUE_CTRL0_THCNT_SHIFT 0
+
+#define BLTIME_64_CYCLES 0
+#define BLTIME_128_CYCLES 1
+#define BLTIME_256_CYCLES 2
+#define BLTIME_300_CYCLES 3
+#define BLTIME_384_CYCLES 4
+#define BLTIME_512_CYCLES 5
+#define BLTIME_1024_CYCLES 6
+#define BLTIME_2048_CYCLES 7
+
+#define ESR_GLUE_CTRL1_L(CHAN) (ESR_BASE + 0x008a + (CHAN) * 0x10)
+#define ESR_GLUE_CTRL1_H(CHAN) (ESR_BASE + 0x008b + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING1_L(CHAN) (ESR_BASE + 0x00c2 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING1_H(CHAN) (ESR_BASE + 0x00c2 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING2_L(CHAN) (ESR_BASE + 0x0102 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING2_H(CHAN) (ESR_BASE + 0x0102 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING3_L(CHAN) (ESR_BASE + 0x0142 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING3_H(CHAN) (ESR_BASE + 0x0142 + (CHAN) * 0x10)
+
+#define NIU_ESR2_DEV_ADDR 0x1e
+#define ESR2_BASE 0x8000
+
+#define ESR2_TI_PLL_CFG_L (ESR2_BASE + 0x000)
+#define ESR2_TI_PLL_CFG_H (ESR2_BASE + 0x001)
+#define PLL_CFG_STD 0x00000c00
+#define PLL_CFG_STD_SHIFT 10
+#define PLL_CFG_LD 0x00000300
+#define PLL_CFG_LD_SHIFT 8
+#define PLL_CFG_MPY 0x0000001e
+#define PLL_CFG_MPY_SHIFT 1
+#define PLL_CFG_ENPLL 0x00000001
+
+#define ESR2_TI_PLL_STS_L (ESR2_BASE + 0x002)
+#define ESR2_TI_PLL_STS_H (ESR2_BASE + 0x003)
+#define PLL_STS_LOCK 0x00000001
+
+#define ESR2_TI_PLL_TEST_CFG_L (ESR2_BASE + 0x004)
+#define ESR2_TI_PLL_TEST_CFG_H (ESR2_BASE + 0x005)
+#define PLL_TEST_INVPATT 0x00004000
+#define PLL_TEST_RATE 0x00003000
+#define PLL_TEST_RATE_SHIFT 12
+#define PLL_TEST_CFG_ENBSAC 0x00000400
+#define PLL_TEST_CFG_ENBSRX 0x00000200
+#define PLL_TEST_CFG_ENBSTX 0x00000100
+#define PLL_TEST_CFG_LOOPBACK_PAD 0x00000040
+#define PLL_TEST_CFG_LOOPBACK_CML_DIS 0x00000080
+#define PLL_TEST_CFG_LOOPBACK_CML_EN 0x000000c0
+#define PLL_TEST_CFG_CLKBYP 0x00000030
+#define PLL_TEST_CFG_CLKBYP_SHIFT 4
+#define PLL_TEST_CFG_EN_RXPATT 0x00000008
+#define PLL_TEST_CFG_EN_TXPATT 0x00000004
+#define PLL_TEST_CFG_TPATT 0x00000003
+#define PLL_TEST_CFG_TPATT_SHIFT 0
+
+#define ESR2_TI_PLL_TX_CFG_L(CHAN) (ESR2_BASE + 0x100 + (CHAN) * 4)
+#define ESR2_TI_PLL_TX_CFG_H(CHAN) (ESR2_BASE + 0x101 + (CHAN) * 4)
+#define PLL_TX_CFG_RDTCT 0x00600000
+#define PLL_TX_CFG_RDTCT_SHIFT 21
+#define PLL_TX_CFG_ENIDL 0x00100000
+#define PLL_TX_CFG_BSTX 0x00020000
+#define PLL_TX_CFG_ENFTP 0x00010000
+#define PLL_TX_CFG_DE 0x0000f000
+#define PLL_TX_CFG_DE_SHIFT 12
+#define PLL_TX_CFG_SWING_125MV 0x00000000
+#define PLL_TX_CFG_SWING_250MV 0x00000200
+#define PLL_TX_CFG_SWING_500MV 0x00000400
+#define PLL_TX_CFG_SWING_625MV 0x00000600
+#define PLL_TX_CFG_SWING_750MV 0x00000800
+#define PLL_TX_CFG_SWING_1000MV 0x00000a00
+#define PLL_TX_CFG_SWING_1250MV 0x00000c00
+#define PLL_TX_CFG_SWING_1375MV 0x00000e00
+#define PLL_TX_CFG_CM 0x00000100
+#define PLL_TX_CFG_INVPAIR 0x00000080
+#define PLL_TX_CFG_RATE 0x00000060
+#define PLL_TX_CFG_RATE_SHIFT 5
+#define PLL_TX_CFG_BUSWIDTH 0x0000001c
+#define PLL_TX_CFG_BUSWIDTH_SHIFT 2
+#define PLL_TX_CFG_ENTEST 0x00000002
+#define PLL_TX_CFG_ENTX 0x00000001
+
+#define ESR2_TI_PLL_TX_STS_L(CHAN) (ESR2_BASE + 0x102 + (CHAN) * 4)
+#define ESR2_TI_PLL_TX_STS_H(CHAN) (ESR2_BASE + 0x103 + (CHAN) * 4)
+#define PLL_TX_STS_RDTCTIP 0x00000002
+#define PLL_TX_STS_TESTFAIL 0x00000001
+
+#define ESR2_TI_PLL_RX_CFG_L(CHAN) (ESR2_BASE + 0x120 + (CHAN) * 4)
+#define ESR2_TI_PLL_RX_CFG_H(CHAN) (ESR2_BASE + 0x121 + (CHAN) * 4)
+#define PLL_RX_CFG_BSINRXN 0x02000000
+#define PLL_RX_CFG_BSINRXP 0x01000000
+#define PLL_RX_CFG_EQ_MAX_LF 0x00000000
+#define PLL_RX_CFG_EQ_LP_ADAPTIVE 0x00080000
+#define PLL_RX_CFG_EQ_LP_1084MHZ 0x00400000
+#define PLL_RX_CFG_EQ_LP_805MHZ 0x00480000
+#define PLL_RX_CFG_EQ_LP_573MHZ 0x00500000
+#define PLL_RX_CFG_EQ_LP_402MHZ 0x00580000
+#define PLL_RX_CFG_EQ_LP_304MHZ 0x00600000
+#define PLL_RX_CFG_EQ_LP_216MHZ 0x00680000
+#define PLL_RX_CFG_EQ_LP_156MHZ 0x00700000
+#define PLL_RX_CFG_EQ_LP_135MHZ 0x00780000
+#define PLL_RX_CFG_EQ_SHIFT 19
+#define PLL_RX_CFG_CDR 0x00070000
+#define PLL_RX_CFG_CDR_SHIFT 16
+#define PLL_RX_CFG_LOS_DIS 0x00000000
+#define PLL_RX_CFG_LOS_HTHRESH 0x00004000
+#define PLL_RX_CFG_LOS_LTHRESH 0x00008000
+#define PLL_RX_CFG_ALIGN_DIS 0x00000000
+#define PLL_RX_CFG_ALIGN_ENA 0x00001000
+#define PLL_RX_CFG_ALIGN_JOG 0x00002000
+#define PLL_RX_CFG_TERM_VDDT 0x00000000
+#define PLL_RX_CFG_TERM_0P8VDDT 0x00000100
+#define PLL_RX_CFG_TERM_FLOAT 0x00000300
+#define PLL_RX_CFG_INVPAIR 0x00000080
+#define PLL_RX_CFG_RATE 0x00000060
+#define PLL_RX_CFG_RATE_SHIFT 5
+#define PLL_RX_CFG_BUSWIDTH 0x0000001c
+#define PLL_RX_CFG_BUSWIDTH_SHIFT 2
+#define PLL_RX_CFG_ENTEST 0x00000002
+#define PLL_RX_CFG_ENRX 0x00000001
+
+#define ESR2_TI_PLL_RX_STS_L(CHAN) (ESR2_BASE + 0x122 + (CHAN) * 4)
+#define ESR2_TI_PLL_RX_STS_H(CHAN) (ESR2_BASE + 0x123 + (CHAN) * 4)
+#define PLL_RX_STS_CRCIDTCT 0x00000200
+#define PLL_RX_STS_CWDTCT 0x00000100
+#define PLL_RX_STS_BSRXN 0x00000020
+#define PLL_RX_STS_BSRXP 0x00000010
+#define PLL_RX_STS_LOSDTCT 0x00000008
+#define PLL_RX_STS_ODDCG 0x00000004
+#define PLL_RX_STS_SYNC 0x00000002
+#define PLL_RX_STS_TESTFAIL 0x00000001
+
+#define ENET_VLAN_TBL(IDX) (FZC_FFLP + 0x00000UL + (IDX) * 8UL)
+#define ENET_VLAN_TBL_PARITY1 0x0000000000020000ULL
+#define ENET_VLAN_TBL_PARITY0 0x0000000000010000ULL
+#define ENET_VLAN_TBL_VPR 0x0000000000000008ULL
+#define ENET_VLAN_TBL_VLANRDCTBLN 0x0000000000000007ULL
+#define ENET_VLAN_TBL_SHIFT(PORT) ((PORT) * 4)
+
+#define ENET_VLAN_TBL_NUM_ENTRIES 4096
+
+#define FFLP_VLAN_PAR_ERR (FZC_FFLP + 0x0800UL)
+#define FFLP_VLAN_PAR_ERR_ERR 0x0000000080000000ULL
+#define FFLP_VLAN_PAR_ERR_M_ERR 0x0000000040000000ULL
+#define FFLP_VLAN_PAR_ERR_ADDR 0x000000003ffc0000ULL
+#define FFLP_VLAN_PAR_ERR_DATA 0x000000000003ffffULL
+
+#define L2_CLS(IDX) (FZC_FFLP + 0x20000UL + (IDX) * 8UL)
+#define L2_CLS_VLD 0x0000000000010000ULL
+#define L2_CLS_ETYPE 0x000000000000ffffULL
+#define L2_CLS_ETYPE_SHIFT 0
+
+#define L3_CLS(IDX) (FZC_FFLP + 0x20010UL + (IDX) * 8UL)
+#define L3_CLS_VALID 0x0000000002000000ULL
+#define L3_CLS_IPVER 0x0000000001000000ULL
+#define L3_CLS_PID 0x0000000000ff0000ULL
+#define L3_CLS_PID_SHIFT 16
+#define L3_CLS_TOSMASK 0x000000000000ff00ULL
+#define L3_CLS_TOSMASK_SHIFT 8
+#define L3_CLS_TOS 0x00000000000000ffULL
+#define L3_CLS_TOS_SHIFT 0
+
+#define TCAM_KEY(IDX) (FZC_FFLP + 0x20030UL + (IDX) * 8UL)
+#define TCAM_KEY_DISC 0x0000000000000008ULL
+#define TCAM_KEY_TSEL 0x0000000000000004ULL
+#define TCAM_KEY_IPADDR 0x0000000000000001ULL
+
+#define TCAM_KEY_0 (FZC_FFLP + 0x20090UL)
+#define TCAM_KEY_0_KEY 0x00000000000000ffULL /* bits 192-199 */
+
+#define TCAM_KEY_1 (FZC_FFLP + 0x20098UL)
+#define TCAM_KEY_1_KEY 0xffffffffffffffffULL /* bits 128-191 */
+
+#define TCAM_KEY_2 (FZC_FFLP + 0x200a0UL)
+#define TCAM_KEY_2_KEY 0xffffffffffffffffULL /* bits 64-127 */
+
+#define TCAM_KEY_3 (FZC_FFLP + 0x200a8UL)
+#define TCAM_KEY_3_KEY 0xffffffffffffffffULL /* bits 0-63 */
+
+#define TCAM_KEY_MASK_0 (FZC_FFLP + 0x200b0UL)
+#define TCAM_KEY_MASK_0_KEY_SEL 0x00000000000000ffULL /* bits 192-199 */
+
+#define TCAM_KEY_MASK_1 (FZC_FFLP + 0x200b8UL)
+#define TCAM_KEY_MASK_1_KEY_SEL 0xffffffffffffffffULL /* bits 128-191 */
+
+#define TCAM_KEY_MASK_2 (FZC_FFLP + 0x200c0UL)
+#define TCAM_KEY_MASK_2_KEY_SEL 0xffffffffffffffffULL /* bits 64-127 */
+
+#define TCAM_KEY_MASK_3 (FZC_FFLP + 0x200c8UL)
+#define TCAM_KEY_MASK_3_KEY_SEL 0xffffffffffffffffULL /* bits 0-63 */
+
+#define TCAM_CTL (FZC_FFLP + 0x200d0UL)
+#define TCAM_CTL_RWC 0x00000000001c0000ULL
+#define TCAM_CTL_RWC_TCAM_WRITE 0x0000000000000000ULL
+#define TCAM_CTL_RWC_TCAM_READ 0x0000000000040000ULL
+#define TCAM_CTL_RWC_TCAM_COMPARE 0x0000000000080000ULL
+#define TCAM_CTL_RWC_RAM_WRITE 0x0000000000100000ULL
+#define TCAM_CTL_RWC_RAM_READ 0x0000000000140000ULL
+#define TCAM_CTL_STAT 0x0000000000020000ULL
+#define TCAM_CTL_MATCH 0x0000000000010000ULL
+#define TCAM_CTL_LOC 0x00000000000003ffULL
+
+#define TCAM_ERR (FZC_FFLP + 0x200d8UL)
+#define TCAM_ERR_ERR 0x0000000080000000ULL
+#define TCAM_ERR_P_ECC 0x0000000040000000ULL
+#define TCAM_ERR_MULT 0x0000000020000000ULL
+#define TCAM_ERR_ADDR 0x0000000000ff0000ULL
+#define TCAM_ERR_SYNDROME 0x000000000000ffffULL
+
+#define HASH_LOOKUP_ERR_LOG1 (FZC_FFLP + 0x200e0UL)
+#define HASH_LOOKUP_ERR_LOG1_ERR 0x0000000000000008ULL
+#define HASH_LOOKUP_ERR_LOG1_MULT_LK 0x0000000000000004ULL
+#define HASH_LOOKUP_ERR_LOG1_CU 0x0000000000000002ULL
+#define HASH_LOOKUP_ERR_LOG1_MULT_BIT 0x0000000000000001ULL
+
+#define HASH_LOOKUP_ERR_LOG2 (FZC_FFLP + 0x200e8UL)
+#define HASH_LOOKUP_ERR_LOG2_H1 0x000000007ffff800ULL
+#define HASH_LOOKUP_ERR_LOG2_SUBAREA 0x0000000000000700ULL
+#define HASH_LOOKUP_ERR_LOG2_SYNDROME 0x00000000000000ffULL
+
+#define FFLP_CFG_1 (FZC_FFLP + 0x20100UL)
+#define FFLP_CFG_1_TCAM_DIS 0x0000000004000000ULL
+#define FFLP_CFG_1_PIO_DBG_SEL 0x0000000003800000ULL
+#define FFLP_CFG_1_PIO_FIO_RST 0x0000000000400000ULL
+#define FFLP_CFG_1_PIO_FIO_LAT 0x0000000000300000ULL
+#define FFLP_CFG_1_CAMLAT 0x00000000000f0000ULL
+#define FFLP_CFG_1_CAMLAT_SHIFT 16
+#define FFLP_CFG_1_CAMRATIO 0x000000000000f000ULL
+#define FFLP_CFG_1_CAMRATIO_SHIFT 12
+#define FFLP_CFG_1_FCRAMRATIO 0x0000000000000f00ULL
+#define FFLP_CFG_1_FCRAMRATIO_SHIFT 8
+#define FFLP_CFG_1_FCRAMOUTDR_MASK 0x00000000000000f0ULL
+#define FFLP_CFG_1_FCRAMOUTDR_NORMAL 0x0000000000000000ULL
+#define FFLP_CFG_1_FCRAMOUTDR_STRONG 0x0000000000000050ULL
+#define FFLP_CFG_1_FCRAMOUTDR_WEAK 0x00000000000000a0ULL
+#define FFLP_CFG_1_FCRAMQS 0x0000000000000008ULL
+#define FFLP_CFG_1_ERRORDIS 0x0000000000000004ULL
+#define FFLP_CFG_1_FFLPINITDONE 0x0000000000000002ULL
+#define FFLP_CFG_1_LLCSNAP 0x0000000000000001ULL
+
+#define DEFAULT_FCRAMRATIO 10
+
+#define DEFAULT_TCAM_LATENCY 4
+#define DEFAULT_TCAM_ACCESS_RATIO 10
+
+#define TCP_CFLAG_MSK (FZC_FFLP + 0x20108UL)
+#define TCP_CFLAG_MSK_MASK 0x0000000000000fffULL
+
+#define FCRAM_REF_TMR (FZC_FFLP + 0x20110UL)
+#define FCRAM_REF_TMR_MAX 0x00000000ffff0000ULL
+#define FCRAM_REF_TMR_MAX_SHIFT 16
+#define FCRAM_REF_TMR_MIN 0x000000000000ffffULL
+#define FCRAM_REF_TMR_MIN_SHIFT 0
+
+#define DEFAULT_FCRAM_REFRESH_MAX 512
+#define DEFAULT_FCRAM_REFRESH_MIN 512
+
+#define FCRAM_FIO_ADDR (FZC_FFLP + 0x20118UL)
+#define FCRAM_FIO_ADDR_ADDR 0x00000000000000ffULL
+
+#define FCRAM_FIO_DAT (FZC_FFLP + 0x20120UL)
+#define FCRAM_FIO_DAT_DATA 0x000000000000ffffULL
+
+#define FCRAM_ERR_TST0 (FZC_FFLP + 0x20128UL)
+#define FCRAM_ERR_TST0_SYND 0x00000000000000ffULL
+
+#define FCRAM_ERR_TST1 (FZC_FFLP + 0x20130UL)
+#define FCRAM_ERR_TST1_DAT 0x00000000ffffffffULL
+
+#define FCRAM_ERR_TST2 (FZC_FFLP + 0x20138UL)
+#define FCRAM_ERR_TST2_DAT 0x00000000ffffffffULL
+
+#define FFLP_ERR_MASK (FZC_FFLP + 0x20140UL)
+#define FFLP_ERR_MASK_HSH_TBL_DAT 0x00000000000007f8ULL
+#define FFLP_ERR_MASK_HSH_TBL_LKUP 0x0000000000000004ULL
+#define FFLP_ERR_MASK_TCAM 0x0000000000000002ULL
+#define FFLP_ERR_MASK_VLAN 0x0000000000000001ULL
+
+#define FFLP_DBG_TRAIN_VCT (FZC_FFLP + 0x20148UL)
+#define FFLP_DBG_TRAIN_VCT_VECTOR 0x00000000ffffffffULL
+
+#define FCRAM_PHY_RD_LAT (FZC_FFLP + 0x20150UL)
+#define FCRAM_PHY_RD_LAT_LAT 0x00000000000000ffULL
+
+/* Ethernet TCAM format */
+#define TCAM_ETHKEY0_RESV1 0xffffffffffffff00ULL
+#define TCAM_ETHKEY0_CLASS_CODE 0x00000000000000f8ULL
+#define TCAM_ETHKEY0_CLASS_CODE_SHIFT 3
+#define TCAM_ETHKEY0_RESV2 0x0000000000000007ULL
+#define TCAM_ETHKEY1_FRAME_BYTE0_7(NUM) (0xff << ((7 - NUM) * 8))
+#define TCAM_ETHKEY2_FRAME_BYTE8 0xff00000000000000ULL
+#define TCAM_ETHKEY2_FRAME_BYTE8_SHIFT 56
+#define TCAM_ETHKEY2_FRAME_BYTE9 0x00ff000000000000ULL
+#define TCAM_ETHKEY2_FRAME_BYTE9_SHIFT 48
+#define TCAM_ETHKEY2_FRAME_BYTE10 0x0000ff0000000000ULL
+#define TCAM_ETHKEY2_FRAME_BYTE10_SHIFT 40
+#define TCAM_ETHKEY2_FRAME_RESV 0x000000ffffffffffULL
+#define TCAM_ETHKEY3_FRAME_RESV 0xffffffffffffffffULL
+
+/* IPV4 TCAM format */
+#define TCAM_V4KEY0_RESV1 0xffffffffffffff00ULL
+#define TCAM_V4KEY0_CLASS_CODE 0x00000000000000f8ULL
+#define TCAM_V4KEY0_CLASS_CODE_SHIFT 3
+#define TCAM_V4KEY0_RESV2 0x0000000000000007ULL
+#define TCAM_V4KEY1_L2RDCNUM 0xf800000000000000ULL
+#define TCAM_V4KEY1_L2RDCNUM_SHIFT 59
+#define TCAM_V4KEY1_NOPORT 0x0400000000000000ULL
+#define TCAM_V4KEY1_RESV 0x03ffffffffffffffULL
+#define TCAM_V4KEY2_RESV 0xffff000000000000ULL
+#define TCAM_V4KEY2_TOS 0x0000ff0000000000ULL
+#define TCAM_V4KEY2_TOS_SHIFT 40
+#define TCAM_V4KEY2_PROTO 0x000000ff00000000ULL
+#define TCAM_V4KEY2_PROTO_SHIFT 32
+#define TCAM_V4KEY2_PORT_SPI 0x00000000ffffffffULL
+#define TCAM_V4KEY2_PORT_SPI_SHIFT 0
+#define TCAM_V4KEY3_SADDR 0xffffffff00000000ULL
+#define TCAM_V4KEY3_SADDR_SHIFT 32
+#define TCAM_V4KEY3_DADDR 0x00000000ffffffffULL
+#define TCAM_V4KEY3_DADDR_SHIFT 0
+
+/* IPV6 TCAM format */
+#define TCAM_V6KEY0_RESV1 0xffffffffffffff00ULL
+#define TCAM_V6KEY0_CLASS_CODE 0x00000000000000f8ULL
+#define TCAM_V6KEY0_CLASS_CODE_SHIFT 3
+#define TCAM_V6KEY0_RESV2 0x0000000000000007ULL
+#define TCAM_V6KEY1_L2RDCNUM 0xf800000000000000ULL
+#define TCAM_V6KEY1_L2RDCNUM_SHIFT 59
+#define TCAM_V6KEY1_NOPORT 0x0400000000000000ULL
+#define TCAM_V6KEY1_RESV 0x03ff000000000000ULL
+#define TCAM_V6KEY1_TOS 0x0000ff0000000000ULL
+#define TCAM_V6KEY1_TOS_SHIFT 40
+#define TCAM_V6KEY1_NEXT_HDR 0x000000ff00000000ULL
+#define TCAM_V6KEY1_NEXT_HDR_SHIFT 32
+#define TCAM_V6KEY1_PORT_SPI 0x00000000ffffffffULL
+#define TCAM_V6KEY1_PORT_SPI_SHIFT 0
+#define TCAM_V6KEY2_ADDR_HIGH 0xffffffffffffffffULL
+#define TCAM_V6KEY3_ADDR_LOW 0xffffffffffffffffULL
+
+#define TCAM_ASSOCDATA_SYNDROME 0x000003fffc000000ULL
+#define TCAM_ASSOCDATA_SYNDROME_SHIFT 26
+#define TCAM_ASSOCDATA_ZFID 0x0000000003ffc000ULL
+#define TCAM_ASSOCDATA_ZFID_SHIFT 14
+#define TCAM_ASSOCDATA_V4_ECC_OK 0x0000000000002000ULL
+#define TCAM_ASSOCDATA_DISC 0x0000000000001000ULL
+#define TCAM_ASSOCDATA_TRES_MASK 0x0000000000000c00ULL
+#define TCAM_ASSOCDATA_TRES_USE_L2RDC 0x0000000000000000ULL
+#define TCAM_ASSOCDATA_TRES_USE_OFFSET 0x0000000000000400ULL
+#define TCAM_ASSOCDATA_TRES_OVR_RDC 0x0000000000000800ULL
+#define TCAM_ASSOCDATA_TRES_OVR_RDC_OFF 0x0000000000000c00ULL
+#define TCAM_ASSOCDATA_RDCTBL 0x0000000000000380ULL
+#define TCAM_ASSOCDATA_RDCTBL_SHIFT 7
+#define TCAM_ASSOCDATA_OFFSET 0x000000000000007cULL
+#define TCAM_ASSOCDATA_OFFSET_SHIFT 2
+#define TCAM_ASSOCDATA_ZFVLD 0x0000000000000002ULL
+#define TCAM_ASSOCDATA_AGE 0x0000000000000001ULL
+
+#define FLOW_KEY(IDX) (FZC_FFLP + 0x40000UL + (IDX) * 8UL)
+#define FLOW_KEY_PORT 0x0000000000000200ULL
+#define FLOW_KEY_L2DA 0x0000000000000100ULL
+#define FLOW_KEY_VLAN 0x0000000000000080ULL
+#define FLOW_KEY_IPSA 0x0000000000000040ULL
+#define FLOW_KEY_IPDA 0x0000000000000020ULL
+#define FLOW_KEY_PROTO 0x0000000000000010ULL
+#define FLOW_KEY_L4_0 0x000000000000000cULL
+#define FLOW_KEY_L4_0_SHIFT 2
+#define FLOW_KEY_L4_1 0x0000000000000003ULL
+#define FLOW_KEY_L4_1_SHIFT 0
+
+#define FLOW_KEY_L4_NONE 0x0
+#define FLOW_KEY_L4_RESV 0x1
+#define FLOW_KEY_L4_BYTE12 0x2
+#define FLOW_KEY_L4_BYTE56 0x3
+
+#define H1POLY (FZC_FFLP + 0x40060UL)
+#define H1POLY_INITVAL 0x00000000ffffffffULL
+
+#define H2POLY (FZC_FFLP + 0x40068UL)
+#define H2POLY_INITVAL 0x000000000000ffffULL
+
+#define FLW_PRT_SEL(IDX) (FZC_FFLP + 0x40070UL + (IDX) * 8UL)
+#define FLW_PRT_SEL_EXT 0x0000000000010000ULL
+#define FLW_PRT_SEL_MASK 0x0000000000001f00ULL
+#define FLW_PRT_SEL_MASK_SHIFT 8
+#define FLW_PRT_SEL_BASE 0x000000000000001fULL
+#define FLW_PRT_SEL_BASE_SHIFT 0
+
+#define HASH_TBL_ADDR(IDX) (FFLP + 0x00000UL + (IDX) * 8192UL)
+#define HASH_TBL_ADDR_AUTOINC 0x0000000000800000ULL
+#define HASH_TBL_ADDR_ADDR 0x00000000007fffffULL
+
+#define HASH_TBL_DATA(IDX) (FFLP + 0x00008UL + (IDX) * 8192UL)
+#define HASH_TBL_DATA_DATA 0xffffffffffffffffULL
+
+/* FCRAM hash table entries are up to 8 64-bit words in size.
+ * The layout of each entry is determined by the settings in the
+ * first word, which is the header.
+ *
+ * The indexing is controllable per partition (there is one partition
+ * per RDC group, thus a total of eight) using the BASE and MASK fields
+ * of FLW_PRT_SEL above.
+ */
+#define FCRAM_SIZE 0x800000
+#define FCRAM_NUM_PARTITIONS 8
+
+/* Generic HASH entry header, used for all non-optimized formats. */
+#define HASH_HEADER_FMT 0x8000000000000000ULL
+#define HASH_HEADER_EXT 0x4000000000000000ULL
+#define HASH_HEADER_VALID 0x2000000000000000ULL
+#define HASH_HEADER_RESVD 0x1000000000000000ULL
+#define HASH_HEADER_L2_DADDR 0x0ffffffffffff000ULL
+#define HASH_HEADER_L2_DADDR_SHIFT 12
+#define HASH_HEADER_VLAN 0x0000000000000fffULL
+#define HASH_HEADER_VLAN_SHIFT 0
+
+/* Optimized format, just a header with a special layout defined below.
+ * Set FMT and EXT both to zero to indicate this layout is being used.
+ */
+#define HASH_OPT_HEADER_FMT 0x8000000000000000ULL
+#define HASH_OPT_HEADER_EXT 0x4000000000000000ULL
+#define HASH_OPT_HEADER_VALID 0x2000000000000000ULL
+#define HASH_OPT_HEADER_RDCOFF 0x1f00000000000000ULL
+#define HASH_OPT_HEADER_RDCOFF_SHIFT 56
+#define HASH_OPT_HEADER_HASH2 0x00ffff0000000000ULL
+#define HASH_OPT_HEADER_HASH2_SHIFT 40
+#define HASH_OPT_HEADER_RESVD 0x000000ff00000000ULL
+#define HASH_OPT_HEADER_USERINFO 0x00000000ffffffffULL
+#define HASH_OPT_HEADER_USERINFO_SHIFT 0
+
+/* Port and protocol word used for ipv4 and ipv6 layouts. */
+#define HASH_PORT_DPORT 0xffff000000000000ULL
+#define HASH_PORT_DPORT_SHIFT 48
+#define HASH_PORT_SPORT 0x0000ffff00000000ULL
+#define HASH_PORT_SPORT_SHIFT 32
+#define HASH_PORT_PROTO 0x00000000ff000000ULL
+#define HASH_PORT_PROTO_SHIFT 24
+#define HASH_PORT_PORT_OFF 0x0000000000c00000ULL
+#define HASH_PORT_PORT_OFF_SHIFT 22
+#define HASH_PORT_PORT_RESV 0x00000000003fffffULL
+
+/* Action word used for ipv4 and ipv6 layouts. */
+#define HASH_ACTION_RESV1 0xe000000000000000ULL
+#define HASH_ACTION_RDCOFF 0x1f00000000000000ULL
+#define HASH_ACTION_RDCOFF_SHIFT 56
+#define HASH_ACTION_ZFVALID 0x0080000000000000ULL
+#define HASH_ACTION_RESV2 0x0070000000000000ULL
+#define HASH_ACTION_ZFID 0x000fff0000000000ULL
+#define HASH_ACTION_ZFID_SHIFT 40
+#define HASH_ACTION_RESV3 0x000000ff00000000ULL
+#define HASH_ACTION_USERINFO 0x00000000ffffffffULL
+#define HASH_ACTION_USERINFO_SHIFT 0
+
+/* IPV4 address word. Addresses are in network endian. */
+#define HASH_IP4ADDR_SADDR 0xffffffff00000000ULL
+#define HASH_IP4ADDR_SADDR_SHIFT 32
+#define HASH_IP4ADDR_DADDR 0x00000000ffffffffULL
+#define HASH_IP4ADDR_DADDR_SHIFT 0
+
+/* IPV6 address layout is 4 words, first two are saddr, next two
+ * are daddr. Addresses are in network endian.
+ */
+
+struct fcram_hash_opt {
+ u64 header;
+};
+
+/* EXT=1, FMT=0 */
+struct fcram_hash_ipv4 {
+ u64 header;
+ u64 addrs;
+ u64 ports;
+ u64 action;
+};
+
+/* EXT=1, FMT=1 */
+struct fcram_hash_ipv6 {
+ u64 header;
+ u64 addrs[4];
+ u64 ports;
+ u64 action;
+};
+
+#define HASH_TBL_DATA_LOG(IDX) (FFLP + 0x00010UL + (IDX) * 8192UL)
+#define HASH_TBL_DATA_LOG_ERR 0x0000000080000000ULL
+#define HASH_TBL_DATA_LOG_ADDR 0x000000007fffff00ULL
+#define HASH_TBL_DATA_LOG_SYNDROME 0x00000000000000ffULL
+
+#define RX_DMA_CK_DIV (FZC_DMC + 0x00000UL)
+#define RX_DMA_CK_DIV_CNT 0x000000000000ffffULL
+
+#define DEF_RDC(IDX) (FZC_DMC + 0x00008UL + (IDX) * 0x8UL)
+#define DEF_RDC_VAL 0x000000000000001fULL
+
+#define PT_DRR_WT(IDX) (FZC_DMC + 0x00028UL + (IDX) * 0x8UL)
+#define PT_DRR_WT_VAL 0x000000000000ffffULL
+
+#define PT_DRR_WEIGHT_DEFAULT_10G 0x0400
+#define PT_DRR_WEIGHT_DEFAULT_1G 0x0066
+
+#define PT_USE(IDX) (FZC_DMC + 0x00048UL + (IDX) * 0x8UL)
+#define PT_USE_CNT 0x00000000000fffffULL
+
+#define RED_RAN_INIT (FZC_DMC + 0x00068UL)
+#define RED_RAN_INIT_OPMODE 0x0000000000010000ULL
+#define RED_RAN_INIT_VAL 0x000000000000ffffULL
+
+#define RX_ADDR_MD (FZC_DMC + 0x00070UL)
+#define RX_ADDR_MD_DBG_PT_MUX_SEL 0x000000000000000cULL
+#define RX_ADDR_MD_RAM_ACC 0x0000000000000002ULL
+#define RX_ADDR_MD_MODE32 0x0000000000000001ULL
+
+#define RDMC_PRE_PAR_ERR (FZC_DMC + 0x00078UL)
+#define RDMC_PRE_PAR_ERR_ERR 0x0000000000008000ULL
+#define RDMC_PRE_PAR_ERR_MERR 0x0000000000004000ULL
+#define RDMC_PRE_PAR_ERR_ADDR 0x00000000000000ffULL
+
+#define RDMC_SHA_PAR_ERR (FZC_DMC + 0x00080UL)
+#define RDMC_SHA_PAR_ERR_ERR 0x0000000000008000ULL
+#define RDMC_SHA_PAR_ERR_MERR 0x0000000000004000ULL
+#define RDMC_SHA_PAR_ERR_ADDR 0x00000000000000ffULL
+
+#define RDMC_MEM_ADDR (FZC_DMC + 0x00088UL)
+#define RDMC_MEM_ADDR_PRE_SHAD 0x0000000000000100ULL
+#define RDMC_MEM_ADDR_ADDR 0x00000000000000ffULL
+
+#define RDMC_MEM_DAT0 (FZC_DMC + 0x00090UL)
+#define RDMC_MEM_DAT0_DATA 0x00000000ffffffffULL /* bits 31:0 */
+
+#define RDMC_MEM_DAT1 (FZC_DMC + 0x00098UL)
+#define RDMC_MEM_DAT1_DATA 0x00000000ffffffffULL /* bits 63:32 */
+
+#define RDMC_MEM_DAT2 (FZC_DMC + 0x000a0UL)
+#define RDMC_MEM_DAT2_DATA 0x00000000ffffffffULL /* bits 95:64 */
+
+#define RDMC_MEM_DAT3 (FZC_DMC + 0x000a8UL)
+#define RDMC_MEM_DAT3_DATA 0x00000000ffffffffULL /* bits 127:96 */
+
+#define RDMC_MEM_DAT4 (FZC_DMC + 0x000b0UL)
+#define RDMC_MEM_DAT4_DATA 0x00000000000fffffULL /* bits 147:128 */
+
+#define RX_CTL_DAT_FIFO_STAT (FZC_DMC + 0x000b8UL)
+#define RX_CTL_DAT_FIFO_STAT_ID_MISMATCH 0x0000000000000100ULL
+#define RX_CTL_DAT_FIFO_STAT_ZCP_EOP_ERR 0x00000000000000f0ULL
+#define RX_CTL_DAT_FIFO_STAT_IPP_EOP_ERR 0x000000000000000fULL
+
+#define RX_CTL_DAT_FIFO_MASK (FZC_DMC + 0x000c0UL)
+#define RX_CTL_DAT_FIFO_MASK_ID_MISMATCH 0x0000000000000100ULL
+#define RX_CTL_DAT_FIFO_MASK_ZCP_EOP_ERR 0x00000000000000f0ULL
+#define RX_CTL_DAT_FIFO_MASK_IPP_EOP_ERR 0x000000000000000fULL
+
+#define RDMC_TRAINING_VECTOR (FZC_DMC + 0x000c8UL)
+#define RDMC_TRAINING_VECTOR_TRAINING_VECTOR 0x00000000ffffffffULL
+
+#define RX_CTL_DAT_FIFO_STAT_DBG (FZC_DMC + 0x000d0UL)
+#define RX_CTL_DAT_FIFO_STAT_DBG_ID_MISMATCH 0x0000000000000100ULL
+#define RX_CTL_DAT_FIFO_STAT_DBG_ZCP_EOP_ERR 0x00000000000000f0ULL
+#define RX_CTL_DAT_FIFO_STAT_DBG_IPP_EOP_ERR 0x000000000000000fULL
+
+#define RDC_TBL(TBL,SLOT) (FZC_ZCP + 0x10000UL + \
+ (TBL) * (8UL * 16UL) + \
+ (SLOT) * 8UL)
+#define RDC_TBL_RDC 0x000000000000000fULL
+
+#define RX_LOG_PAGE_VLD(IDX) (FZC_DMC + 0x20000UL + (IDX) * 0x40UL)
+#define RX_LOG_PAGE_VLD_FUNC 0x000000000000000cULL
+#define RX_LOG_PAGE_VLD_FUNC_SHIFT 2
+#define RX_LOG_PAGE_VLD_PAGE1 0x0000000000000002ULL
+#define RX_LOG_PAGE_VLD_PAGE0 0x0000000000000001ULL
+
+#define RX_LOG_MASK1(IDX) (FZC_DMC + 0x20008UL + (IDX) * 0x40UL)
+#define RX_LOG_MASK1_MASK 0x00000000ffffffffULL
+
+#define RX_LOG_VAL1(IDX) (FZC_DMC + 0x20010UL + (IDX) * 0x40UL)
+#define RX_LOG_VAL1_VALUE 0x00000000ffffffffULL
+
+#define RX_LOG_MASK2(IDX) (FZC_DMC + 0x20018UL + (IDX) * 0x40UL)
+#define RX_LOG_MASK2_MASK 0x00000000ffffffffULL
+
+#define RX_LOG_VAL2(IDX) (FZC_DMC + 0x20020UL + (IDX) * 0x40UL)
+#define RX_LOG_VAL2_VALUE 0x00000000ffffffffULL
+
+#define RX_LOG_PAGE_RELO1(IDX) (FZC_DMC + 0x20028UL + (IDX) * 0x40UL)
+#define RX_LOG_PAGE_RELO1_RELO 0x00000000ffffffffULL
+
+#define RX_LOG_PAGE_RELO2(IDX) (FZC_DMC + 0x20030UL + (IDX) * 0x40UL)
+#define RX_LOG_PAGE_RELO2_RELO 0x00000000ffffffffULL
+
+#define RX_LOG_PAGE_HDL(IDX) (FZC_DMC + 0x20038UL + (IDX) * 0x40UL)
+#define RX_LOG_PAGE_HDL_HANDLE 0x00000000000fffffULL
+
+#define TX_LOG_PAGE_VLD(IDX) (FZC_DMC + 0x40000UL + (IDX) * 0x200UL)
+#define TX_LOG_PAGE_VLD_FUNC 0x000000000000000cULL
+#define TX_LOG_PAGE_VLD_FUNC_SHIFT 2
+#define TX_LOG_PAGE_VLD_PAGE1 0x0000000000000002ULL
+#define TX_LOG_PAGE_VLD_PAGE0 0x0000000000000001ULL
+
+#define TX_LOG_MASK1(IDX) (FZC_DMC + 0x40008UL + (IDX) * 0x200UL)
+#define TX_LOG_MASK1_MASK 0x00000000ffffffffULL
+
+#define TX_LOG_VAL1(IDX) (FZC_DMC + 0x40010UL + (IDX) * 0x200UL)
+#define TX_LOG_VAL1_VALUE 0x00000000ffffffffULL
+
+#define TX_LOG_MASK2(IDX) (FZC_DMC + 0x40018UL + (IDX) * 0x200UL)
+#define TX_LOG_MASK2_MASK 0x00000000ffffffffULL
+
+#define TX_LOG_VAL2(IDX) (FZC_DMC + 0x40020UL + (IDX) * 0x200UL)
+#define TX_LOG_VAL2_VALUE 0x00000000ffffffffULL
+
+#define TX_LOG_PAGE_RELO1(IDX) (FZC_DMC + 0x40028UL + (IDX) * 0x200UL)
+#define TX_LOG_PAGE_RELO1_RELO 0x00000000ffffffffULL
+
+#define TX_LOG_PAGE_RELO2(IDX) (FZC_DMC + 0x40030UL + (IDX) * 0x200UL)
+#define TX_LOG_PAGE_RELO2_RELO 0x00000000ffffffffULL
+
+#define TX_LOG_PAGE_HDL(IDX) (FZC_DMC + 0x40038UL + (IDX) * 0x200UL)
+#define TX_LOG_PAGE_HDL_HANDLE 0x00000000000fffffULL
+
+#define TX_ADDR_MD (FZC_DMC + 0x45000UL)
+#define TX_ADDR_MD_MODE32 0x0000000000000001ULL
+
+#define RDC_RED_PARA(IDX) (FZC_DMC + 0x30000UL + (IDX) * 0x40UL)
+#define RDC_RED_PARA_THRE_SYN 0x00000000fff00000ULL
+#define RDC_RED_PARA_THRE_SYN_SHIFT 20
+#define RDC_RED_PARA_WIN_SYN 0x00000000000f0000ULL
+#define RDC_RED_PARA_WIN_SYN_SHIFT 16
+#define RDC_RED_PARA_THRE 0x000000000000fff0ULL
+#define RDC_RED_PARA_THRE_SHIFT 4
+#define RDC_RED_PARA_WIN 0x000000000000000fULL
+#define RDC_RED_PARA_WIN_SHIFT 0
+
+#define RED_DIS_CNT(IDX) (FZC_DMC + 0x30008UL + (IDX) * 0x40UL)
+#define RED_DIS_CNT_OFLOW 0x0000000000010000ULL
+#define RED_DIS_CNT_COUNT 0x000000000000ffffULL
+
+#define IPP_CFIG (FZC_IPP + 0x00000UL)
+#define IPP_CFIG_SOFT_RST 0x0000000080000000ULL
+#define IPP_CFIG_IP_MAX_PKT 0x0000000001ffff00ULL
+#define IPP_CFIG_IP_MAX_PKT_SHIFT 8
+#define IPP_CFIG_FFLP_CS_PIO_W 0x0000000000000080ULL
+#define IPP_CFIG_PFIFO_PIO_W 0x0000000000000040ULL
+#define IPP_CFIG_DFIFO_PIO_W 0x0000000000000020ULL
+#define IPP_CFIG_CKSUM_EN 0x0000000000000010ULL
+#define IPP_CFIG_DROP_BAD_CRC 0x0000000000000008ULL
+#define IPP_CFIG_DFIFO_ECC_EN 0x0000000000000004ULL
+#define IPP_CFIG_DEBUG_BUS_OUT_EN 0x0000000000000002ULL
+#define IPP_CFIG_IPP_ENABLE 0x0000000000000001ULL
+
+#define IPP_PKT_DIS (FZC_IPP + 0x00020UL)
+#define IPP_PKT_DIS_COUNT 0x0000000000003fffULL
+
+#define IPP_BAD_CS_CNT (FZC_IPP + 0x00028UL)
+#define IPP_BAD_CS_CNT_COUNT 0x0000000000003fffULL
+
+#define IPP_ECC (FZC_IPP + 0x00030UL)
+#define IPP_ECC_COUNT 0x00000000000000ffULL
+
+#define IPP_INT_STAT (FZC_IPP + 0x00040UL)
+#define IPP_INT_STAT_SOP_MISS 0x0000000080000000ULL
+#define IPP_INT_STAT_EOP_MISS 0x0000000040000000ULL
+#define IPP_INT_STAT_DFIFO_UE 0x0000000030000000ULL
+#define IPP_INT_STAT_DFIFO_CE 0x000000000c000000ULL
+#define IPP_INT_STAT_DFIFO_ECC 0x0000000003000000ULL
+#define IPP_INT_STAT_DFIFO_ECC_IDX 0x00000000007ff000ULL
+#define IPP_INT_STAT_PFIFO_PERR 0x0000000000000800ULL
+#define IPP_INT_STAT_ECC_ERR_MAX 0x0000000000000400ULL
+#define IPP_INT_STAT_PFIFO_ERR_IDX 0x00000000000003f0ULL
+#define IPP_INT_STAT_PFIFO_OVER 0x0000000000000008ULL
+#define IPP_INT_STAT_PFIFO_UND 0x0000000000000004ULL
+#define IPP_INT_STAT_BAD_CS_MX 0x0000000000000002ULL
+#define IPP_INT_STAT_PKT_DIS_MX 0x0000000000000001ULL
+#define IPP_INT_STAT_ALL 0x00000000ff7fffffULL
+
+#define IPP_MSK (FZC_IPP + 0x00048UL)
+#define IPP_MSK_ECC_ERR_MX 0x0000000000000080ULL
+#define IPP_MSK_DFIFO_EOP_SOP 0x0000000000000040ULL
+#define IPP_MSK_DFIFO_UC 0x0000000000000020ULL
+#define IPP_MSK_PFIFO_PAR 0x0000000000000010ULL
+#define IPP_MSK_PFIFO_OVER 0x0000000000000008ULL
+#define IPP_MSK_PFIFO_UND 0x0000000000000004ULL
+#define IPP_MSK_BAD_CS 0x0000000000000002ULL
+#define IPP_MSK_PKT_DIS_CNT 0x0000000000000001ULL
+#define IPP_MSK_ALL 0x00000000000000ffULL
+
+#define IPP_PFIFO_RD0 (FZC_IPP + 0x00060UL)
+#define IPP_PFIFO_RD0_DATA 0x00000000ffffffffULL /* bits 31:0 */
+
+#define IPP_PFIFO_RD1 (FZC_IPP + 0x00068UL)
+#define IPP_PFIFO_RD1_DATA 0x00000000ffffffffULL /* bits 63:32 */
+
+#define IPP_PFIFO_RD2 (FZC_IPP + 0x00070UL)
+#define IPP_PFIFO_RD2_DATA 0x00000000ffffffffULL /* bits 95:64 */
+
+#define IPP_PFIFO_RD3 (FZC_IPP + 0x00078UL)
+#define IPP_PFIFO_RD3_DATA 0x00000000ffffffffULL /* bits 127:96 */
+
+#define IPP_PFIFO_RD4 (FZC_IPP + 0x00080UL)
+#define IPP_PFIFO_RD4_DATA 0x00000000ffffffffULL /* bits 145:128 */
+
+#define IPP_PFIFO_WR0 (FZC_IPP + 0x00088UL)
+#define IPP_PFIFO_WR0_DATA 0x00000000ffffffffULL /* bits 31:0 */
+
+#define IPP_PFIFO_WR1 (FZC_IPP + 0x00090UL)
+#define IPP_PFIFO_WR1_DATA 0x00000000ffffffffULL /* bits 63:32 */
+
+#define IPP_PFIFO_WR2 (FZC_IPP + 0x00098UL)
+#define IPP_PFIFO_WR2_DATA 0x00000000ffffffffULL /* bits 95:64 */
+
+#define IPP_PFIFO_WR3 (FZC_IPP + 0x000a0UL)
+#define IPP_PFIFO_WR3_DATA 0x00000000ffffffffULL /* bits 127:96 */
+
+#define IPP_PFIFO_WR4 (FZC_IPP + 0x000a8UL)
+#define IPP_PFIFO_WR4_DATA 0x00000000ffffffffULL /* bits 145:128 */
+
+#define IPP_PFIFO_RD_PTR (FZC_IPP + 0x000b0UL)
+#define IPP_PFIFO_RD_PTR_PTR 0x000000000000003fULL
+
+#define IPP_PFIFO_WR_PTR (FZC_IPP + 0x000b8UL)
+#define IPP_PFIFO_WR_PTR_PTR 0x000000000000007fULL
+
+#define IPP_DFIFO_RD0 (FZC_IPP + 0x000c0UL)
+#define IPP_DFIFO_RD0_DATA 0x00000000ffffffffULL /* bits 31:0 */
+
+#define IPP_DFIFO_RD1 (FZC_IPP + 0x000c8UL)
+#define IPP_DFIFO_RD1_DATA 0x00000000ffffffffULL /* bits 63:32 */
+
+#define IPP_DFIFO_RD2 (FZC_IPP + 0x000d0UL)
+#define IPP_DFIFO_RD2_DATA 0x00000000ffffffffULL /* bits 95:64 */
+
+#define IPP_DFIFO_RD3 (FZC_IPP + 0x000d8UL)
+#define IPP_DFIFO_RD3_DATA 0x00000000ffffffffULL /* bits 127:96 */
+
+#define IPP_DFIFO_RD4 (FZC_IPP + 0x000e0UL)
+#define IPP_DFIFO_RD4_DATA 0x00000000ffffffffULL /* bits 145:128 */
+
+#define IPP_DFIFO_WR0 (FZC_IPP + 0x000e8UL)
+#define IPP_DFIFO_WR0_DATA 0x00000000ffffffffULL /* bits 31:0 */
+
+#define IPP_DFIFO_WR1 (FZC_IPP + 0x000f0UL)
+#define IPP_DFIFO_WR1_DATA 0x00000000ffffffffULL /* bits 63:32 */
+
+#define IPP_DFIFO_WR2 (FZC_IPP + 0x000f8UL)
+#define IPP_DFIFO_WR2_DATA 0x00000000ffffffffULL /* bits 95:64 */
+
+#define IPP_DFIFO_WR3 (FZC_IPP + 0x00100UL)
+#define IPP_DFIFO_WR3_DATA 0x00000000ffffffffULL /* bits 127:96 */
+
+#define IPP_DFIFO_WR4 (FZC_IPP + 0x00108UL)
+#define IPP_DFIFO_WR4_DATA 0x00000000ffffffffULL /* bits 145:128 */
+
+#define IPP_DFIFO_RD_PTR (FZC_IPP + 0x00110UL)
+#define IPP_DFIFO_RD_PTR_PTR 0x0000000000000fffULL
+
+#define IPP_DFIFO_WR_PTR (FZC_IPP + 0x00118UL)
+#define IPP_DFIFO_WR_PTR_PTR 0x0000000000000fffULL
+
+#define IPP_SM (FZC_IPP + 0x00120UL)
+#define IPP_SM_SM 0x00000000ffffffffULL
+
+#define IPP_CS_STAT (FZC_IPP + 0x00128UL)
+#define IPP_CS_STAT_BCYC_CNT 0x00000000ff000000ULL
+#define IPP_CS_STAT_IP_LEN 0x0000000000fff000ULL
+#define IPP_CS_STAT_CS_FAIL 0x0000000000000800ULL
+#define IPP_CS_STAT_TERM 0x0000000000000400ULL
+#define IPP_CS_STAT_BAD_NUM 0x0000000000000200ULL
+#define IPP_CS_STAT_CS_STATE 0x00000000000001ffULL
+
+#define IPP_FFLP_CS_INFO (FZC_IPP + 0x00130UL)
+#define IPP_FFLP_CS_INFO_PKT_ID 0x0000000000003c00ULL
+#define IPP_FFLP_CS_INFO_L4_PROTO 0x0000000000000300ULL
+#define IPP_FFLP_CS_INFO_V4_HD_LEN 0x00000000000000f0ULL
+#define IPP_FFLP_CS_INFO_L3_VER 0x000000000000000cULL
+#define IPP_FFLP_CS_INFO_L2_OP 0x0000000000000003ULL
+
+#define IPP_DBG_SEL (FZC_IPP + 0x00138UL)
+#define IPP_DBG_SEL_SEL 0x000000000000000fULL
+
+#define IPP_DFIFO_ECC_SYND (FZC_IPP + 0x00140UL)
+#define IPP_DFIFO_ECC_SYND_SYND 0x000000000000ffffULL
+
+#define IPP_DFIFO_EOP_RD_PTR (FZC_IPP + 0x00148UL)
+#define IPP_DFIFO_EOP_RD_PTR_PTR 0x0000000000000fffULL
+
+#define IPP_ECC_CTL (FZC_IPP + 0x00150UL)
+#define IPP_ECC_CTL_DIS_DBL 0x0000000080000000ULL
+#define IPP_ECC_CTL_COR_DBL 0x0000000000020000ULL
+#define IPP_ECC_CTL_COR_SNG 0x0000000000010000ULL
+#define IPP_ECC_CTL_COR_ALL 0x0000000000000400ULL
+#define IPP_ECC_CTL_COR_1 0x0000000000000100ULL
+#define IPP_ECC_CTL_COR_LST 0x0000000000000004ULL
+#define IPP_ECC_CTL_COR_SND 0x0000000000000002ULL
+#define IPP_ECC_CTL_COR_FSR 0x0000000000000001ULL
+
+#define NIU_DFIFO_ENTRIES 1024
+#define ATLAS_P0_P1_DFIFO_ENTRIES 2048
+#define ATLAS_P2_P3_DFIFO_ENTRIES 1024
+
+#define ZCP_CFIG (FZC_ZCP + 0x00000UL)
+#define ZCP_CFIG_ZCP_32BIT_MODE 0x0000000001000000ULL
+#define ZCP_CFIG_ZCP_DEBUG_SEL 0x0000000000ff0000ULL
+#define ZCP_CFIG_DMA_TH 0x000000000000ffe0ULL
+#define ZCP_CFIG_ECC_CHK_DIS 0x0000000000000010ULL
+#define ZCP_CFIG_PAR_CHK_DIS 0x0000000000000008ULL
+#define ZCP_CFIG_DIS_BUFF_RSP_IF 0x0000000000000004ULL
+#define ZCP_CFIG_DIS_BUFF_REQ_IF 0x0000000000000002ULL
+#define ZCP_CFIG_ZC_ENABLE 0x0000000000000001ULL
+
+#define ZCP_INT_STAT (FZC_ZCP + 0x00008UL)
+#define ZCP_INT_STAT_RRFIFO_UNDERRUN 0x0000000000008000ULL
+#define ZCP_INT_STAT_RRFIFO_OVERRUN 0x0000000000004000ULL
+#define ZCP_INT_STAT_RSPFIFO_UNCOR_ERR 0x0000000000001000ULL
+#define ZCP_INT_STAT_BUFFER_OVERFLOW 0x0000000000000800ULL
+#define ZCP_INT_STAT_STAT_TBL_PERR 0x0000000000000400ULL
+#define ZCP_INT_STAT_DYN_TBL_PERR 0x0000000000000200ULL
+#define ZCP_INT_STAT_BUF_TBL_PERR 0x0000000000000100ULL
+#define ZCP_INT_STAT_TT_PROGRAM_ERR 0x0000000000000080ULL
+#define ZCP_INT_STAT_RSP_TT_INDEX_ERR 0x0000000000000040ULL
+#define ZCP_INT_STAT_SLV_TT_INDEX_ERR 0x0000000000000020ULL
+#define ZCP_INT_STAT_ZCP_TT_INDEX_ERR 0x0000000000000010ULL
+#define ZCP_INT_STAT_CFIFO_ECC3 0x0000000000000008ULL
+#define ZCP_INT_STAT_CFIFO_ECC2 0x0000000000000004ULL
+#define ZCP_INT_STAT_CFIFO_ECC1 0x0000000000000002ULL
+#define ZCP_INT_STAT_CFIFO_ECC0 0x0000000000000001ULL
+#define ZCP_INT_STAT_ALL 0x000000000000ffffULL
+
+#define ZCP_INT_MASK (FZC_ZCP + 0x00010UL)
+#define ZCP_INT_MASK_RRFIFO_UNDERRUN 0x0000000000008000ULL
+#define ZCP_INT_MASK_RRFIFO_OVERRUN 0x0000000000004000ULL
+#define ZCP_INT_MASK_LOJ 0x0000000000002000ULL
+#define ZCP_INT_MASK_RSPFIFO_UNCOR_ERR 0x0000000000001000ULL
+#define ZCP_INT_MASK_BUFFER_OVERFLOW 0x0000000000000800ULL
+#define ZCP_INT_MASK_STAT_TBL_PERR 0x0000000000000400ULL
+#define ZCP_INT_MASK_DYN_TBL_PERR 0x0000000000000200ULL
+#define ZCP_INT_MASK_BUF_TBL_PERR 0x0000000000000100ULL
+#define ZCP_INT_MASK_TT_PROGRAM_ERR 0x0000000000000080ULL
+#define ZCP_INT_MASK_RSP_TT_INDEX_ERR 0x0000000000000040ULL
+#define ZCP_INT_MASK_SLV_TT_INDEX_ERR 0x0000000000000020ULL
+#define ZCP_INT_MASK_ZCP_TT_INDEX_ERR 0x0000000000000010ULL
+#define ZCP_INT_MASK_CFIFO_ECC3 0x0000000000000008ULL
+#define ZCP_INT_MASK_CFIFO_ECC2 0x0000000000000004ULL
+#define ZCP_INT_MASK_CFIFO_ECC1 0x0000000000000002ULL
+#define ZCP_INT_MASK_CFIFO_ECC0 0x0000000000000001ULL
+#define ZCP_INT_MASK_ALL 0x000000000000ffffULL
+
+#define BAM4BUF (FZC_ZCP + 0x00018UL)
+#define BAM4BUF_LOJ 0x0000000080000000ULL
+#define BAM4BUF_EN_CK 0x0000000040000000ULL
+#define BAM4BUF_IDX_END0 0x000000003ff00000ULL
+#define BAM4BUF_IDX_ST0 0x00000000000ffc00ULL
+#define BAM4BUF_OFFSET0 0x00000000000003ffULL
+
+#define BAM8BUF (FZC_ZCP + 0x00020UL)
+#define BAM8BUF_LOJ 0x0000000080000000ULL
+#define BAM8BUF_EN_CK 0x0000000040000000ULL
+#define BAM8BUF_IDX_END1 0x000000003ff00000ULL
+#define BAM8BUF_IDX_ST1 0x00000000000ffc00ULL
+#define BAM8BUF_OFFSET1 0x00000000000003ffULL
+
+#define BAM16BUF (FZC_ZCP + 0x00028UL)
+#define BAM16BUF_LOJ 0x0000000080000000ULL
+#define BAM16BUF_EN_CK 0x0000000040000000ULL
+#define BAM16BUF_IDX_END2 0x000000003ff00000ULL
+#define BAM16BUF_IDX_ST2 0x00000000000ffc00ULL
+#define BAM16BUF_OFFSET2 0x00000000000003ffULL
+
+#define BAM32BUF (FZC_ZCP + 0x00030UL)
+#define BAM32BUF_LOJ 0x0000000080000000ULL
+#define BAM32BUF_EN_CK 0x0000000040000000ULL
+#define BAM32BUF_IDX_END3 0x000000003ff00000ULL
+#define BAM32BUF_IDX_ST3 0x00000000000ffc00ULL
+#define BAM32BUF_OFFSET3 0x00000000000003ffULL
+
+#define DST4BUF (FZC_ZCP + 0x00038UL)
+#define DST4BUF_DS_OFFSET0 0x00000000000003ffULL
+
+#define DST8BUF (FZC_ZCP + 0x00040UL)
+#define DST8BUF_DS_OFFSET1 0x00000000000003ffULL
+
+#define DST16BUF (FZC_ZCP + 0x00048UL)
+#define DST16BUF_DS_OFFSET2 0x00000000000003ffULL
+
+#define DST32BUF (FZC_ZCP + 0x00050UL)
+#define DST32BUF_DS_OFFSET3 0x00000000000003ffULL
+
+#define ZCP_RAM_DATA0 (FZC_ZCP + 0x00058UL)
+#define ZCP_RAM_DATA0_DAT0 0x00000000ffffffffULL
+
+#define ZCP_RAM_DATA1 (FZC_ZCP + 0x00060UL)
+#define ZCP_RAM_DAT10_DAT1 0x00000000ffffffffULL
+
+#define ZCP_RAM_DATA2 (FZC_ZCP + 0x00068UL)
+#define ZCP_RAM_DATA2_DAT2 0x00000000ffffffffULL
+
+#define ZCP_RAM_DATA3 (FZC_ZCP + 0x00070UL)
+#define ZCP_RAM_DATA3_DAT3 0x00000000ffffffffULL
+
+#define ZCP_RAM_DATA4 (FZC_ZCP + 0x00078UL)
+#define ZCP_RAM_DATA4_DAT4 0x00000000000000ffULL
+
+#define ZCP_RAM_BE (FZC_ZCP + 0x00080UL)
+#define ZCP_RAM_BE_VAL 0x000000000001ffffULL
+
+#define ZCP_RAM_ACC (FZC_ZCP + 0x00088UL)
+#define ZCP_RAM_ACC_BUSY 0x0000000080000000ULL
+#define ZCP_RAM_ACC_READ 0x0000000040000000ULL
+#define ZCP_RAM_ACC_WRITE 0x0000000000000000ULL
+#define ZCP_RAM_ACC_LOJ 0x0000000020000000ULL
+#define ZCP_RAM_ACC_ZFCID 0x000000001ffe0000ULL
+#define ZCP_RAM_ACC_ZFCID_SHIFT 17
+#define ZCP_RAM_ACC_RAM_SEL 0x000000000001f000ULL
+#define ZCP_RAM_ACC_RAM_SEL_SHIFT 12
+#define ZCP_RAM_ACC_CFIFOADDR 0x0000000000000fffULL
+#define ZCP_RAM_ACC_CFIFOADDR_SHIFT 0
+
+#define ZCP_RAM_SEL_BAM(INDEX) (0x00 + (INDEX))
+#define ZCP_RAM_SEL_TT_STATIC 0x08
+#define ZCP_RAM_SEL_TT_DYNAMIC 0x09
+#define ZCP_RAM_SEL_CFIFO(PORT) (0x10 + (PORT))
+
+#define NIU_CFIFO_ENTRIES 1024
+#define ATLAS_P0_P1_CFIFO_ENTRIES 2048
+#define ATLAS_P2_P3_CFIFO_ENTRIES 1024
+
+#define CHK_BIT_DATA (FZC_ZCP + 0x00090UL)
+#define CHK_BIT_DATA_DATA 0x000000000000ffffULL
+
+#define RESET_CFIFO (FZC_ZCP + 0x00098UL)
+#define RESET_CFIFO_RST(PORT) (0x1 << (PORT))
+
+#define CFIFO_ECC(PORT) (FZC_ZCP + 0x000a0UL + (PORT) * 8UL)
+#define CFIFO_ECC_DIS_DBLBIT_ERR 0x0000000080000000ULL
+#define CFIFO_ECC_DBLBIT_ERR 0x0000000000020000ULL
+#define CFIFO_ECC_SINGLEBIT_ERR 0x0000000000010000ULL
+#define CFIFO_ECC_ALL_PKT 0x0000000000000400ULL
+#define CFIFO_ECC_LAST_LINE 0x0000000000000004ULL
+#define CFIFO_ECC_2ND_LINE 0x0000000000000002ULL
+#define CFIFO_ECC_1ST_LINE 0x0000000000000001ULL
+
+#define ZCP_TRAINING_VECTOR (FZC_ZCP + 0x000c0UL)
+#define ZCP_TRAINING_VECTOR_VECTOR 0x00000000ffffffffULL
+
+#define ZCP_STATE_MACHINE (FZC_ZCP + 0x000c8UL)
+#define ZCP_STATE_MACHINE_SM 0x00000000ffffffffULL
+
+/* Same bits as ZCP_INT_STAT */
+#define ZCP_INT_STAT_TEST (FZC_ZCP + 0x00108UL)
+
+#define RXDMA_CFIG1(IDX) (DMC + 0x00000UL + (IDX) * 0x200UL)
+#define RXDMA_CFIG1_EN 0x0000000080000000ULL
+#define RXDMA_CFIG1_RST 0x0000000040000000ULL
+#define RXDMA_CFIG1_QST 0x0000000020000000ULL
+#define RXDMA_CFIG1_MBADDR_H 0x0000000000000fffULL /* mboxaddr 43:32 */
+
+#define RXDMA_CFIG2(IDX) (DMC + 0x00008UL + (IDX) * 0x200UL)
+#define RXDMA_CFIG2_MBADDR_L 0x00000000ffffffc0ULL /* mboxaddr 31:6 */
+#define RXDMA_CFIG2_OFFSET 0x0000000000000006ULL
+#define RXDMA_CFIG2_OFFSET_SHIFT 1
+#define RXDMA_CFIG2_FULL_HDR 0x0000000000000001ULL
+
+#define RBR_CFIG_A(IDX) (DMC + 0x00010UL + (IDX) * 0x200UL)
+#define RBR_CFIG_A_LEN 0xffff000000000000ULL
+#define RBR_CFIG_A_LEN_SHIFT 48
+#define RBR_CFIG_A_STADDR_BASE 0x00000ffffffc0000ULL
+#define RBR_CFIG_A_STADDR 0x000000000003ffc0ULL
+
+#define RBR_CFIG_B(IDX) (DMC + 0x00018UL + (IDX) * 0x200UL)
+#define RBR_CFIG_B_BLKSIZE 0x0000000003000000ULL
+#define RBR_CFIG_B_BLKSIZE_SHIFT 24
+#define RBR_CFIG_B_VLD2 0x0000000000800000ULL
+#define RBR_CFIG_B_BUFSZ2 0x0000000000030000ULL
+#define RBR_CFIG_B_BUFSZ2_SHIFT 16
+#define RBR_CFIG_B_VLD1 0x0000000000008000ULL
+#define RBR_CFIG_B_BUFSZ1 0x0000000000000300ULL
+#define RBR_CFIG_B_BUFSZ1_SHIFT 8
+#define RBR_CFIG_B_VLD0 0x0000000000000080ULL
+#define RBR_CFIG_B_BUFSZ0 0x0000000000000003ULL
+#define RBR_CFIG_B_BUFSZ0_SHIFT 0
+
+#define RBR_BLKSIZE_4K 0x0
+#define RBR_BLKSIZE_8K 0x1
+#define RBR_BLKSIZE_16K 0x2
+#define RBR_BLKSIZE_32K 0x3
+#define RBR_BUFSZ2_2K 0x0
+#define RBR_BUFSZ2_4K 0x1
+#define RBR_BUFSZ2_8K 0x2
+#define RBR_BUFSZ2_16K 0x3
+#define RBR_BUFSZ1_1K 0x0
+#define RBR_BUFSZ1_2K 0x1
+#define RBR_BUFSZ1_4K 0x2
+#define RBR_BUFSZ1_8K 0x3
+#define RBR_BUFSZ0_256 0x0
+#define RBR_BUFSZ0_512 0x1
+#define RBR_BUFSZ0_1K 0x2
+#define RBR_BUFSZ0_2K 0x3
+
+#define RBR_KICK(IDX) (DMC + 0x00020UL + (IDX) * 0x200UL)
+#define RBR_KICK_BKADD 0x000000000000ffffULL
+
+#define RBR_STAT(IDX) (DMC + 0x00028UL + (IDX) * 0x200UL)
+#define RBR_STAT_QLEN 0x000000000000ffffULL
+
+#define RBR_HDH(IDX) (DMC + 0x00030UL + (IDX) * 0x200UL)
+#define RBR_HDH_HEAD_H 0x0000000000000fffULL
+
+#define RBR_HDL(IDX) (DMC + 0x00038UL + (IDX) * 0x200UL)
+#define RBR_HDL_HEAD_L 0x00000000fffffffcULL
+
+#define RCRCFIG_A(IDX) (DMC + 0x00040UL + (IDX) * 0x200UL)
+#define RCRCFIG_A_LEN 0xffff000000000000ULL
+#define RCRCFIG_A_LEN_SHIFT 48
+#define RCRCFIG_A_STADDR_BASE 0x00000ffffff80000ULL
+#define RCRCFIG_A_STADDR 0x000000000007ffc0ULL
+
+#define RCRCFIG_B(IDX) (DMC + 0x00048UL + (IDX) * 0x200UL)
+#define RCRCFIG_B_PTHRES 0x00000000ffff0000ULL
+#define RCRCFIG_B_PTHRES_SHIFT 16
+#define RCRCFIG_B_ENTOUT 0x0000000000008000ULL
+#define RCRCFIG_B_TIMEOUT 0x000000000000003fULL
+#define RCRCFIG_B_TIMEOUT_SHIFT 0
+
+#define RCRSTAT_A(IDX) (DMC + 0x00050UL + (IDX) * 0x200UL)
+#define RCRSTAT_A_QLEN 0x000000000000ffffULL
+
+#define RCRSTAT_B(IDX) (DMC + 0x00058UL + (IDX) * 0x200UL)
+#define RCRSTAT_B_TIPTR_H 0x0000000000000fffULL
+
+#define RCRSTAT_C(IDX) (DMC + 0x00060UL + (IDX) * 0x200UL)
+#define RCRSTAT_C_TIPTR_L 0x00000000fffffff8ULL
+
+#define RX_DMA_CTL_STAT(IDX) (DMC + 0x00070UL + (IDX) * 0x200UL)
+#define RX_DMA_CTL_STAT_RBR_TMOUT 0x0020000000000000ULL
+#define RX_DMA_CTL_STAT_RSP_CNT_ERR 0x0010000000000000ULL
+#define RX_DMA_CTL_STAT_BYTE_EN_BUS 0x0008000000000000ULL
+#define RX_DMA_CTL_STAT_RSP_DAT_ERR 0x0004000000000000ULL
+#define RX_DMA_CTL_STAT_RCR_ACK_ERR 0x0002000000000000ULL
+#define RX_DMA_CTL_STAT_DC_FIFO_ERR 0x0001000000000000ULL
+#define RX_DMA_CTL_STAT_MEX 0x0000800000000000ULL
+#define RX_DMA_CTL_STAT_RCRTHRES 0x0000400000000000ULL
+#define RX_DMA_CTL_STAT_RCRTO 0x0000200000000000ULL
+#define RX_DMA_CTL_STAT_RCR_SHA_PAR 0x0000100000000000ULL
+#define RX_DMA_CTL_STAT_RBR_PRE_PAR 0x0000080000000000ULL
+#define RX_DMA_CTL_STAT_PORT_DROP_PKT 0x0000040000000000ULL
+#define RX_DMA_CTL_STAT_WRED_DROP 0x0000020000000000ULL
+#define RX_DMA_CTL_STAT_RBR_PRE_EMTY 0x0000010000000000ULL
+#define RX_DMA_CTL_STAT_RCRSHADOW_FULL 0x0000008000000000ULL
+#define RX_DMA_CTL_STAT_CONFIG_ERR 0x0000004000000000ULL
+#define RX_DMA_CTL_STAT_RCRINCON 0x0000002000000000ULL
+#define RX_DMA_CTL_STAT_RCRFULL 0x0000001000000000ULL
+#define RX_DMA_CTL_STAT_RBR_EMPTY 0x0000000800000000ULL
+#define RX_DMA_CTL_STAT_RBRFULL 0x0000000400000000ULL
+#define RX_DMA_CTL_STAT_RBRLOGPAGE 0x0000000200000000ULL
+#define RX_DMA_CTL_STAT_CFIGLOGPAGE 0x0000000100000000ULL
+#define RX_DMA_CTL_STAT_PTRREAD 0x00000000ffff0000ULL
+#define RX_DMA_CTL_STAT_PTRREAD_SHIFT 16
+#define RX_DMA_CTL_STAT_PKTREAD 0x000000000000ffffULL
+#define RX_DMA_CTL_STAT_PKTREAD_SHIFT 0
+
+#define RX_DMA_CTL_STAT_CHAN_FATAL (RX_DMA_CTL_STAT_RBR_TMOUT | \
+ RX_DMA_CTL_STAT_RSP_CNT_ERR | \
+ RX_DMA_CTL_STAT_BYTE_EN_BUS | \
+ RX_DMA_CTL_STAT_RSP_DAT_ERR | \
+ RX_DMA_CTL_STAT_RCR_ACK_ERR | \
+ RX_DMA_CTL_STAT_RCR_SHA_PAR | \
+ RX_DMA_CTL_STAT_RBR_PRE_PAR | \
+ RX_DMA_CTL_STAT_CONFIG_ERR | \
+ RX_DMA_CTL_STAT_RCRINCON | \
+ RX_DMA_CTL_STAT_RCRFULL | \
+ RX_DMA_CTL_STAT_RBRFULL | \
+ RX_DMA_CTL_STAT_RBRLOGPAGE | \
+ RX_DMA_CTL_STAT_CFIGLOGPAGE)
+
+#define RX_DMA_CTL_STAT_PORT_FATAL (RX_DMA_CTL_STAT_DC_FIFO_ERR)
+
+#define RX_DMA_CTL_WRITE_CLEAR_ERRS (RX_DMA_CTL_STAT_RBR_EMPTY | \
+ RX_DMA_CTL_STAT_RCRSHADOW_FULL | \
+ RX_DMA_CTL_STAT_RBR_PRE_EMTY | \
+ RX_DMA_CTL_STAT_WRED_DROP | \
+ RX_DMA_CTL_STAT_PORT_DROP_PKT | \
+ RX_DMA_CTL_STAT_RCRTO | \
+ RX_DMA_CTL_STAT_RCRTHRES | \
+ RX_DMA_CTL_STAT_DC_FIFO_ERR)
+
+#define RCR_FLSH(IDX) (DMC + 0x00078UL + (IDX) * 0x200UL)
+#define RCR_FLSH_FLSH 0x0000000000000001ULL
+
+#define RXMISC(IDX) (DMC + 0x00090UL + (IDX) * 0x200UL)
+#define RXMISC_OFLOW 0x0000000000010000ULL
+#define RXMISC_COUNT 0x000000000000ffffULL
+
+#define RX_DMA_CTL_STAT_DBG(IDX) (DMC + 0x00098UL + (IDX) * 0x200UL)
+#define RX_DMA_CTL_STAT_DBG_RBR_TMOUT 0x0020000000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RSP_CNT_ERR 0x0010000000000000ULL
+#define RX_DMA_CTL_STAT_DBG_BYTE_EN_BUS 0x0008000000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RSP_DAT_ERR 0x0004000000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCR_ACK_ERR 0x0002000000000000ULL
+#define RX_DMA_CTL_STAT_DBG_DC_FIFO_ERR 0x0001000000000000ULL
+#define RX_DMA_CTL_STAT_DBG_MEX 0x0000800000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCRTHRES 0x0000400000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCRTO 0x0000200000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCR_SHA_PAR 0x0000100000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RBR_PRE_PAR 0x0000080000000000ULL
+#define RX_DMA_CTL_STAT_DBG_PORT_DROP_PKT 0x0000040000000000ULL
+#define RX_DMA_CTL_STAT_DBG_WRED_DROP 0x0000020000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RBR_PRE_EMTY 0x0000010000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCRSHADOW_FULL 0x0000008000000000ULL
+#define RX_DMA_CTL_STAT_DBG_CONFIG_ERR 0x0000004000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCRINCON 0x0000002000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RCRFULL 0x0000001000000000ULL
+#define RX_DMA_CTL_STAT_DBG_RBR_EMPTY 0x0000000800000000ULL
+#define RX_DMA_CTL_STAT_DBG_RBRFULL 0x0000000400000000ULL
+#define RX_DMA_CTL_STAT_DBG_RBRLOGPAGE 0x0000000200000000ULL
+#define RX_DMA_CTL_STAT_DBG_CFIGLOGPAGE 0x0000000100000000ULL
+#define RX_DMA_CTL_STAT_DBG_PTRREAD 0x00000000ffff0000ULL
+#define RX_DMA_CTL_STAT_DBG_PKTREAD 0x000000000000ffffULL
+
+#define RX_DMA_ENT_MSK(IDX) (DMC + 0x00068UL + (IDX) * 0x200UL)
+#define RX_DMA_ENT_MSK_RBR_TMOUT 0x0000000000200000ULL
+#define RX_DMA_ENT_MSK_RSP_CNT_ERR 0x0000000000100000ULL
+#define RX_DMA_ENT_MSK_BYTE_EN_BUS 0x0000000000080000ULL
+#define RX_DMA_ENT_MSK_RSP_DAT_ERR 0x0000000000040000ULL
+#define RX_DMA_ENT_MSK_RCR_ACK_ERR 0x0000000000020000ULL
+#define RX_DMA_ENT_MSK_DC_FIFO_ERR 0x0000000000010000ULL
+#define RX_DMA_ENT_MSK_RCRTHRES 0x0000000000004000ULL
+#define RX_DMA_ENT_MSK_RCRTO 0x0000000000002000ULL
+#define RX_DMA_ENT_MSK_RCR_SHA_PAR 0x0000000000001000ULL
+#define RX_DMA_ENT_MSK_RBR_PRE_PAR 0x0000000000000800ULL
+#define RX_DMA_ENT_MSK_PORT_DROP_PKT 0x0000000000000400ULL
+#define RX_DMA_ENT_MSK_WRED_DROP 0x0000000000000200ULL
+#define RX_DMA_ENT_MSK_RBR_PRE_EMTY 0x0000000000000100ULL
+#define RX_DMA_ENT_MSK_RCR_SHADOW_FULL 0x0000000000000080ULL
+#define RX_DMA_ENT_MSK_CONFIG_ERR 0x0000000000000040ULL
+#define RX_DMA_ENT_MSK_RCRINCON 0x0000000000000020ULL
+#define RX_DMA_ENT_MSK_RCRFULL 0x0000000000000010ULL
+#define RX_DMA_ENT_MSK_RBR_EMPTY 0x0000000000000008ULL
+#define RX_DMA_ENT_MSK_RBRFULL 0x0000000000000004ULL
+#define RX_DMA_ENT_MSK_RBRLOGPAGE 0x0000000000000002ULL
+#define RX_DMA_ENT_MSK_CFIGLOGPAGE 0x0000000000000001ULL
+#define RX_DMA_ENT_MSK_ALL 0x00000000003f7fffULL
+
+#define TX_RNG_CFIG(IDX) (DMC + 0x40000UL + (IDX) * 0x200UL)
+#define TX_RNG_CFIG_LEN 0x1fff000000000000ULL
+#define TX_RNG_CFIG_LEN_SHIFT 48
+#define TX_RNG_CFIG_STADDR_BASE 0x00000ffffff80000ULL
+#define TX_RNG_CFIG_STADDR 0x000000000007ffc0ULL
+
+#define TX_RING_HDL(IDX) (DMC + 0x40010UL + (IDX) * 0x200UL)
+#define TX_RING_HDL_WRAP 0x0000000000080000ULL
+#define TX_RING_HDL_HEAD 0x000000000007fff8ULL
+#define TX_RING_HDL_HEAD_SHIFT 3
+
+#define TX_RING_KICK(IDX) (DMC + 0x40018UL + (IDX) * 0x200UL)
+#define TX_RING_KICK_WRAP 0x0000000000080000ULL
+#define TX_RING_KICK_TAIL 0x000000000007fff8ULL
+
+#define TX_ENT_MSK(IDX) (DMC + 0x40020UL + (IDX) * 0x200UL)
+#define TX_ENT_MSK_MK 0x0000000000008000ULL
+#define TX_ENT_MSK_MBOX_ERR 0x0000000000000080ULL
+#define TX_ENT_MSK_PKT_SIZE_ERR 0x0000000000000040ULL
+#define TX_ENT_MSK_TX_RING_OFLOW 0x0000000000000020ULL
+#define TX_ENT_MSK_PREF_BUF_ECC_ERR 0x0000000000000010ULL
+#define TX_ENT_MSK_NACK_PREF 0x0000000000000008ULL
+#define TX_ENT_MSK_NACK_PKT_RD 0x0000000000000004ULL
+#define TX_ENT_MSK_CONF_PART_ERR 0x0000000000000002ULL
+#define TX_ENT_MSK_PKT_PRT_ERR 0x0000000000000001ULL
+
+#define TX_CS(IDX) (DMC + 0x40028UL + (IDX)*0x200UL)
+#define TX_CS_PKT_CNT 0x0fff000000000000ULL
+#define TX_CS_PKT_CNT_SHIFT 48
+#define TX_CS_LASTMARK 0x00000fff00000000ULL
+#define TX_CS_LASTMARK_SHIFT 32
+#define TX_CS_RST 0x0000000080000000ULL
+#define TX_CS_RST_STATE 0x0000000040000000ULL
+#define TX_CS_MB 0x0000000020000000ULL
+#define TX_CS_STOP_N_GO 0x0000000010000000ULL
+#define TX_CS_SNG_STATE 0x0000000008000000ULL
+#define TX_CS_MK 0x0000000000008000ULL
+#define TX_CS_MMK 0x0000000000004000ULL
+#define TX_CS_MBOX_ERR 0x0000000000000080ULL
+#define TX_CS_PKT_SIZE_ERR 0x0000000000000040ULL
+#define TX_CS_TX_RING_OFLOW 0x0000000000000020ULL
+#define TX_CS_PREF_BUF_PAR_ERR 0x0000000000000010ULL
+#define TX_CS_NACK_PREF 0x0000000000000008ULL
+#define TX_CS_NACK_PKT_RD 0x0000000000000004ULL
+#define TX_CS_CONF_PART_ERR 0x0000000000000002ULL
+#define TX_CS_PKT_PRT_ERR 0x0000000000000001ULL
+
+#define TXDMA_MBH(IDX) (DMC + 0x40030UL + (IDX) * 0x200UL)
+#define TXDMA_MBH_MBADDR 0x0000000000000fffULL
+
+#define TXDMA_MBL(IDX) (DMC + 0x40038UL + (IDX) * 0x200UL)
+#define TXDMA_MBL_MBADDR 0x00000000ffffffc0ULL
+
+#define TX_DMA_PRE_ST(IDX) (DMC + 0x40040UL + (IDX) * 0x200UL)
+#define TX_DMA_PRE_ST_SHADOW_HD 0x000000000007ffffULL
+
+#define TX_RNG_ERR_LOGH(IDX) (DMC + 0x40048UL + (IDX) * 0x200UL)
+#define TX_RNG_ERR_LOGH_ERR 0x0000000080000000ULL
+#define TX_RNG_ERR_LOGH_MERR 0x0000000040000000ULL
+#define TX_RNG_ERR_LOGH_ERRCODE 0x0000000038000000ULL
+#define TX_RNG_ERR_LOGH_ERRADDR 0x0000000000000fffULL
+
+#define TX_RNG_ERR_LOGL(IDX) (DMC + 0x40050UL + (IDX) * 0x200UL)
+#define TX_RNG_ERR_LOGL_ERRADDR 0x00000000ffffffffULL
+
+#define TDMC_INTR_DBG(IDX) (DMC + 0x40060UL + (IDX) * 0x200UL)
+#define TDMC_INTR_DBG_MK 0x0000000000008000ULL
+#define TDMC_INTR_DBG_MBOX_ERR 0x0000000000000080ULL
+#define TDMC_INTR_DBG_PKT_SIZE_ERR 0x0000000000000040ULL
+#define TDMC_INTR_DBG_TX_RING_OFLOW 0x0000000000000020ULL
+#define TDMC_INTR_DBG_PREF_BUF_PAR_ERR 0x0000000000000010ULL
+#define TDMC_INTR_DBG_NACK_PREF 0x0000000000000008ULL
+#define TDMC_INTR_DBG_NACK_PKT_RD 0x0000000000000004ULL
+#define TDMC_INTR_DBG_CONF_PART_ERR 0x0000000000000002ULL
+#define TDMC_INTR_DBG_PKT_PART_ERR 0x0000000000000001ULL
+
+#define TX_CS_DBG(IDX) (DMC + 0x40068UL + (IDX) * 0x200UL)
+#define TX_CS_DBG_PKT_CNT 0x0fff000000000000ULL
+
+#define TDMC_INJ_PAR_ERR(IDX) (DMC + 0x45040UL + (IDX) * 0x200UL)
+#define TDMC_INJ_PAR_ERR_VAL 0x000000000000ffffULL
+
+#define TDMC_DBG_SEL(IDX) (DMC + 0x45080UL + (IDX) * 0x200UL)
+#define TDMC_DBG_SEL_DBG_SEL 0x000000000000003fULL
+
+#define TDMC_TRAINING_VECTOR(IDX) (DMC + 0x45088UL + (IDX) * 0x200UL)
+#define TDMC_TRAINING_VECTOR_VEC 0x00000000ffffffffULL
+
+#define TXC_DMA_MAX(CHAN) (FZC_TXC + 0x00000UL + (CHAN)*0x1000UL)
+#define TXC_DMA_MAX_LEN(CHAN) (FZC_TXC + 0x00008UL + (CHAN)*0x1000UL)
+
+#define TXC_CONTROL (FZC_TXC + 0x20000UL)
+#define TXC_CONTROL_ENABLE 0x0000000000000010ULL
+#define TXC_CONTROL_PORT_ENABLE(X) (1 << (X))
+
+#define TXC_TRAINING_VEC (FZC_TXC + 0x20008UL)
+#define TXC_TRAINING_VEC_MASK 0x00000000ffffffffULL
+
+#define TXC_DEBUG (FZC_TXC + 0x20010UL)
+#define TXC_DEBUG_SELECT 0x000000000000003fULL
+
+#define TXC_MAX_REORDER (FZC_TXC + 0x20018UL)
+#define TXC_MAX_REORDER_PORT3 0x000000000f000000ULL
+#define TXC_MAX_REORDER_PORT2 0x00000000000f0000ULL
+#define TXC_MAX_REORDER_PORT1 0x0000000000000f00ULL
+#define TXC_MAX_REORDER_PORT0 0x000000000000000fULL
+
+#define TXC_PORT_CTL(PORT) (FZC_TXC + 0x20020UL + (PORT)*0x100UL)
+#define TXC_PORT_CTL_CLR_ALL_STAT 0x0000000000000001ULL
+
+#define TXC_PKT_STUFFED(PORT) (FZC_TXC + 0x20030UL + (PORT)*0x100UL)
+#define TXC_PKT_STUFFED_PP_REORDER 0x00000000ffff0000ULL
+#define TXC_PKT_STUFFED_PP_PACKETASSY 0x000000000000ffffULL
+
+#define TXC_PKT_XMIT(PORT) (FZC_TXC + 0x20038UL + (PORT)*0x100UL)
+#define TXC_PKT_XMIT_BYTES 0x00000000ffff0000ULL
+#define TXC_PKT_XMIT_PKTS 0x000000000000ffffULL
+
+#define TXC_ROECC_CTL(PORT) (FZC_TXC + 0x20040UL + (PORT)*0x100UL)
+#define TXC_ROECC_CTL_DISABLE_UE 0x0000000080000000ULL
+#define TXC_ROECC_CTL_DBL_BIT_ERR 0x0000000000020000ULL
+#define TXC_ROECC_CTL_SNGL_BIT_ERR 0x0000000000010000ULL
+#define TXC_ROECC_CTL_ALL_PKTS 0x0000000000000400ULL
+#define TXC_ROECC_CTL_ALT_PKTS 0x0000000000000200ULL
+#define TXC_ROECC_CTL_ONE_PKT_ONLY 0x0000000000000100ULL
+#define TXC_ROECC_CTL_LST_PKT_LINE 0x0000000000000004ULL
+#define TXC_ROECC_CTL_2ND_PKT_LINE 0x0000000000000002ULL
+#define TXC_ROECC_CTL_1ST_PKT_LINE 0x0000000000000001ULL
+
+#define TXC_ROECC_ST(PORT) (FZC_TXC + 0x20048UL + (PORT)*0x100UL)
+#define TXC_ROECC_CLR_ST 0x0000000080000000ULL
+#define TXC_ROECC_CE 0x0000000000020000ULL
+#define TXC_ROECC_UE 0x0000000000010000ULL
+#define TXC_ROECC_ST_ECC_ADDR 0x00000000000003ffULL
+
+#define TXC_RO_DATA0(PORT) (FZC_TXC + 0x20050UL + (PORT)*0x100UL)
+#define TXC_RO_DATA0_DATA0 0x00000000ffffffffULL /* bits 31:0 */
+
+#define TXC_RO_DATA1(PORT) (FZC_TXC + 0x20058UL + (PORT)*0x100UL)
+#define TXC_RO_DATA1_DATA1 0x00000000ffffffffULL /* bits 63:32 */
+
+#define TXC_RO_DATA2(PORT) (FZC_TXC + 0x20060UL + (PORT)*0x100UL)
+#define TXC_RO_DATA2_DATA2 0x00000000ffffffffULL /* bits 95:64 */
+
+#define TXC_RO_DATA3(PORT) (FZC_TXC + 0x20068UL + (PORT)*0x100UL)
+#define TXC_RO_DATA3_DATA3 0x00000000ffffffffULL /* bits 127:96 */
+
+#define TXC_RO_DATA4(PORT) (FZC_TXC + 0x20070UL + (PORT)*0x100UL)
+#define TXC_RO_DATA4_DATA4 0x0000000000ffffffULL /* bits 151:128 */
+
+#define TXC_SFECC_CTL(PORT) (FZC_TXC + 0x20078UL + (PORT)*0x100UL)
+#define TXC_SFECC_CTL_DISABLE_UE 0x0000000080000000ULL
+#define TXC_SFECC_CTL_DBL_BIT_ERR 0x0000000000020000ULL
+#define TXC_SFECC_CTL_SNGL_BIT_ERR 0x0000000000010000ULL
+#define TXC_SFECC_CTL_ALL_PKTS 0x0000000000000400ULL
+#define TXC_SFECC_CTL_ALT_PKTS 0x0000000000000200ULL
+#define TXC_SFECC_CTL_ONE_PKT_ONLY 0x0000000000000100ULL
+#define TXC_SFECC_CTL_LST_PKT_LINE 0x0000000000000004ULL
+#define TXC_SFECC_CTL_2ND_PKT_LINE 0x0000000000000002ULL
+#define TXC_SFECC_CTL_1ST_PKT_LINE 0x0000000000000001ULL
+
+#define TXC_SFECC_ST(PORT) (FZC_TXC + 0x20080UL + (PORT)*0x100UL)
+#define TXC_SFECC_ST_CLR_ST 0x0000000080000000ULL
+#define TXC_SFECC_ST_CE 0x0000000000020000ULL
+#define TXC_SFECC_ST_UE 0x0000000000010000ULL
+#define TXC_SFECC_ST_ECC_ADDR 0x00000000000003ffULL
+
+#define TXC_SF_DATA0(PORT) (FZC_TXC + 0x20088UL + (PORT)*0x100UL)
+#define TXC_SF_DATA0_DATA0 0x00000000ffffffffULL /* bits 31:0 */
+
+#define TXC_SF_DATA1(PORT) (FZC_TXC + 0x20090UL + (PORT)*0x100UL)
+#define TXC_SF_DATA1_DATA1 0x00000000ffffffffULL /* bits 63:32 */
+
+#define TXC_SF_DATA2(PORT) (FZC_TXC + 0x20098UL + (PORT)*0x100UL)
+#define TXC_SF_DATA2_DATA2 0x00000000ffffffffULL /* bits 95:64 */
+
+#define TXC_SF_DATA3(PORT) (FZC_TXC + 0x200a0UL + (PORT)*0x100UL)
+#define TXC_SF_DATA3_DATA3 0x00000000ffffffffULL /* bits 127:96 */
+
+#define TXC_SF_DATA4(PORT) (FZC_TXC + 0x200a8UL + (PORT)*0x100UL)
+#define TXC_SF_DATA4_DATA4 0x0000000000ffffffULL /* bits 151:128 */
+
+#define TXC_RO_TIDS(PORT) (FZC_TXC + 0x200b0UL + (PORT)*0x100UL)
+#define TXC_RO_TIDS_IN_USE 0x00000000ffffffffULL
+
+#define TXC_RO_STATE0(PORT) (FZC_TXC + 0x200b8UL + (PORT)*0x100UL)
+#define TXC_RO_STATE0_DUPLICATE_TID 0x00000000ffffffffULL
+
+#define TXC_RO_STATE1(PORT) (FZC_TXC + 0x200c0UL + (PORT)*0x100UL)
+#define TXC_RO_STATE1_UNUSED_TID 0x00000000ffffffffULL
+
+#define TXC_RO_STATE2(PORT) (FZC_TXC + 0x200c8UL + (PORT)*0x100UL)
+#define TXC_RO_STATE2_TRANS_TIMEOUT 0x00000000ffffffffULL
+
+#define TXC_RO_STATE3(PORT) (FZC_TXC + 0x200d0UL + (PORT)*0x100UL)
+#define TXC_RO_STATE3_ENAB_SPC_WMARK 0x0000000080000000ULL
+#define TXC_RO_STATE3_RO_SPC_WMARK 0x000000007fe00000ULL
+#define TXC_RO_STATE3_ROFIFO_SPC_AVAIL 0x00000000001ff800ULL
+#define TXC_RO_STATE3_ENAB_RO_WMARK 0x0000000000000100ULL
+#define TXC_RO_STATE3_HIGH_RO_USED 0x00000000000000f0ULL
+#define TXC_RO_STATE3_NUM_RO_USED 0x000000000000000fULL
+
+#define TXC_RO_CTL(PORT) (FZC_TXC + 0x200d8UL + (PORT)*0x100UL)
+#define TXC_RO_CTL_CLR_FAIL_STATE 0x0000000080000000ULL
+#define TXC_RO_CTL_RO_ADDR 0x000000000f000000ULL
+#define TXC_RO_CTL_ADDR_FAILED 0x0000000000400000ULL
+#define TXC_RO_CTL_DMA_FAILED 0x0000000000200000ULL
+#define TXC_RO_CTL_LEN_FAILED 0x0000000000100000ULL
+#define TXC_RO_CTL_CAPT_ADDR_FAILED 0x0000000000040000ULL
+#define TXC_RO_CTL_CAPT_DMA_FAILED 0x0000000000020000ULL
+#define TXC_RO_CTL_CAPT_LEN_FAILED 0x0000000000010000ULL
+#define TXC_RO_CTL_RO_STATE_RD_DONE 0x0000000000000080ULL
+#define TXC_RO_CTL_RO_STATE_WR_DONE 0x0000000000000040ULL
+#define TXC_RO_CTL_RO_STATE_RD 0x0000000000000020ULL
+#define TXC_RO_CTL_RO_STATE_WR 0x0000000000000010ULL
+#define TXC_RO_CTL_RO_STATE_ADDR 0x000000000000000fULL
+
+#define TXC_RO_ST_DATA0(PORT) (FZC_TXC + 0x200e0UL + (PORT)*0x100UL)
+#define TXC_RO_ST_DATA0_DATA0 0x00000000ffffffffULL
+
+#define TXC_RO_ST_DATA1(PORT) (FZC_TXC + 0x200e8UL + (PORT)*0x100UL)
+#define TXC_RO_ST_DATA1_DATA1 0x00000000ffffffffULL
+
+#define TXC_RO_ST_DATA2(PORT) (FZC_TXC + 0x200f0UL + (PORT)*0x100UL)
+#define TXC_RO_ST_DATA2_DATA2 0x00000000ffffffffULL
+
+#define TXC_RO_ST_DATA3(PORT) (FZC_TXC + 0x200f8UL + (PORT)*0x100UL)
+#define TXC_RO_ST_DATA3_DATA3 0x00000000ffffffffULL
+
+#define TXC_PORT_PACKET_REQ(PORT) (FZC_TXC + 0x20100UL + (PORT)*0x100UL)
+#define TXC_PORT_PACKET_REQ_GATHER_REQ 0x00000000f0000000ULL
+#define TXC_PORT_PACKET_REQ_PKT_REQ 0x000000000fff0000ULL
+#define TXC_PORT_PACKET_REQ_PERR_ABRT 0x000000000000ffffULL
+
+ /* bits are same as TXC_INT_STAT */
+#define TXC_INT_STAT_DBG (FZC_TXC + 0x20420UL)
+
+#define TXC_INT_STAT (FZC_TXC + 0x20428UL)
+#define TXC_INT_STAT_VAL_SHIFT(PORT) ((PORT) * 8)
+#define TXC_INT_STAT_VAL(PORT) (0x3f << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define TXC_INT_STAT_SF_CE(PORT) (0x01 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define TXC_INT_STAT_SF_UE(PORT) (0x02 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define TXC_INT_STAT_RO_CE(PORT) (0x04 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define TXC_INT_STAT_RO_UE(PORT) (0x08 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define TXC_INT_STAT_REORDER_ERR(PORT) (0x10 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define TXC_INT_STAT_PKTASM_DEAD(PORT) (0x20 << TXC_INT_STAT_VAL_SHIFT(PORT))
+
+#define TXC_INT_MASK (FZC_TXC + 0x20430UL)
+#define TXC_INT_MASK_VAL_SHIFT(PORT) ((PORT) * 8)
+#define TXC_INT_MASK_VAL(PORT) (0x3f << TXC_INT_STAT_VAL_SHIFT(PORT))
+
+#define TXC_INT_MASK_SF_CE 0x01
+#define TXC_INT_MASK_SF_UE 0x02
+#define TXC_INT_MASK_RO_CE 0x04
+#define TXC_INT_MASK_RO_UE 0x08
+#define TXC_INT_MASK_REORDER_ERR 0x10
+#define TXC_INT_MASK_PKTASM_DEAD 0x20
+#define TXC_INT_MASK_ALL 0x3f
+
+#define TXC_PORT_DMA(IDX) (FZC_TXC + 0x20028UL + (IDX)*0x100UL)
+
+#define ESPC_PIO_EN (FZC_PROM + 0x40000UL)
+#define ESPC_PIO_EN_ENABLE 0x0000000000000001ULL
+
+#define ESPC_PIO_STAT (FZC_PROM + 0x40008UL)
+#define ESPC_PIO_STAT_READ_START 0x0000000080000000ULL
+#define ESPC_PIO_STAT_READ_END 0x0000000040000000ULL
+#define ESPC_PIO_STAT_WRITE_INIT 0x0000000020000000ULL
+#define ESPC_PIO_STAT_WRITE_END 0x0000000010000000ULL
+#define ESPC_PIO_STAT_ADDR 0x0000000003ffff00ULL
+#define ESPC_PIO_STAT_ADDR_SHIFT 8
+#define ESPC_PIO_STAT_DATA 0x00000000000000ffULL
+#define ESPC_PIO_STAT_DATA_SHIFT 0
+
+#define ESPC_NCR(IDX) (FZC_PROM + 0x40020UL + (IDX)*0x8UL)
+#define ESPC_NCR_VAL 0x00000000ffffffffULL
+
+#define ESPC_MAC_ADDR0 ESPC_NCR(0)
+#define ESPC_MAC_ADDR1 ESPC_NCR(1)
+#define ESPC_NUM_PORTS_MACS ESPC_NCR(2)
+#define ESPC_NUM_PORTS_MACS_VAL 0x00000000000000ffULL
+#define ESPC_MOD_STR_LEN ESPC_NCR(4)
+#define ESPC_MOD_STR_1 ESPC_NCR(5)
+#define ESPC_MOD_STR_2 ESPC_NCR(6)
+#define ESPC_MOD_STR_3 ESPC_NCR(7)
+#define ESPC_MOD_STR_4 ESPC_NCR(8)
+#define ESPC_MOD_STR_5 ESPC_NCR(9)
+#define ESPC_MOD_STR_6 ESPC_NCR(10)
+#define ESPC_MOD_STR_7 ESPC_NCR(11)
+#define ESPC_MOD_STR_8 ESPC_NCR(12)
+#define ESPC_BD_MOD_STR_LEN ESPC_NCR(13)
+#define ESPC_BD_MOD_STR_1 ESPC_NCR(14)
+#define ESPC_BD_MOD_STR_2 ESPC_NCR(15)
+#define ESPC_BD_MOD_STR_3 ESPC_NCR(16)
+#define ESPC_BD_MOD_STR_4 ESPC_NCR(17)
+
+#define ESPC_PHY_TYPE ESPC_NCR(18)
+#define ESPC_PHY_TYPE_PORT0 0x00000000ff000000ULL
+#define ESPC_PHY_TYPE_PORT0_SHIFT 24
+#define ESPC_PHY_TYPE_PORT1 0x0000000000ff0000ULL
+#define ESPC_PHY_TYPE_PORT1_SHIFT 16
+#define ESPC_PHY_TYPE_PORT2 0x000000000000ff00ULL
+#define ESPC_PHY_TYPE_PORT2_SHIFT 8
+#define ESPC_PHY_TYPE_PORT3 0x00000000000000ffULL
+#define ESPC_PHY_TYPE_PORT3_SHIFT 0
+
+#define ESPC_PHY_TYPE_1G_COPPER 3
+#define ESPC_PHY_TYPE_1G_FIBER 2
+#define ESPC_PHY_TYPE_10G_COPPER 1
+#define ESPC_PHY_TYPE_10G_FIBER 0
+
+#define ESPC_MAX_FM_SZ ESPC_NCR(19)
+
+#define ESPC_INTR_NUM ESPC_NCR(20)
+#define ESPC_INTR_NUM_PORT0 0x00000000ff000000ULL
+#define ESPC_INTR_NUM_PORT1 0x0000000000ff0000ULL
+#define ESPC_INTR_NUM_PORT2 0x000000000000ff00ULL
+#define ESPC_INTR_NUM_PORT3 0x00000000000000ffULL
+
+#define ESPC_VER_IMGSZ ESPC_NCR(21)
+#define ESPC_VER_IMGSZ_IMGSZ 0x00000000ffff0000ULL
+#define ESPC_VER_IMGSZ_IMGSZ_SHIFT 16
+#define ESPC_VER_IMGSZ_VER 0x000000000000ffffULL
+#define ESPC_VER_IMGSZ_VER_SHIFT 0
+
+#define ESPC_CHKSUM ESPC_NCR(22)
+#define ESPC_CHKSUM_SUM 0x00000000000000ffULL
+
+#define ESPC_EEPROM_SIZE 0x100000
+
+#define CLASS_CODE_UNRECOG 0x00
+#define CLASS_CODE_DUMMY1 0x01
+#define CLASS_CODE_ETHERTYPE1 0x02
+#define CLASS_CODE_ETHERTYPE2 0x03
+#define CLASS_CODE_USER_PROG1 0x04
+#define CLASS_CODE_USER_PROG2 0x05
+#define CLASS_CODE_USER_PROG3 0x06
+#define CLASS_CODE_USER_PROG4 0x07
+#define CLASS_CODE_TCP_IPV4 0x08
+#define CLASS_CODE_UDP_IPV4 0x09
+#define CLASS_CODE_AH_ESP_IPV4 0x0a
+#define CLASS_CODE_SCTP_IPV4 0x0b
+#define CLASS_CODE_TCP_IPV6 0x0c
+#define CLASS_CODE_UDP_IPV6 0x0d
+#define CLASS_CODE_AH_ESP_IPV6 0x0e
+#define CLASS_CODE_SCTP_IPV6 0x0f
+#define CLASS_CODE_ARP 0x10
+#define CLASS_CODE_RARP 0x11
+#define CLASS_CODE_DUMMY2 0x12
+#define CLASS_CODE_DUMMY3 0x13
+#define CLASS_CODE_DUMMY4 0x14
+#define CLASS_CODE_DUMMY5 0x15
+#define CLASS_CODE_DUMMY6 0x16
+#define CLASS_CODE_DUMMY7 0x17
+#define CLASS_CODE_DUMMY8 0x18
+#define CLASS_CODE_DUMMY9 0x19
+#define CLASS_CODE_DUMMY10 0x1a
+#define CLASS_CODE_DUMMY11 0x1b
+#define CLASS_CODE_DUMMY12 0x1c
+#define CLASS_CODE_DUMMY13 0x1d
+#define CLASS_CODE_DUMMY14 0x1e
+#define CLASS_CODE_DUMMY15 0x1f
+
+/* Logical devices and device groups */
+#define LDN_RXDMA(CHAN) (0 + (CHAN))
+#define LDN_RESV1(OFF) (16 + (OFF))
+#define LDN_TXDMA(CHAN) (32 + (CHAN))
+#define LDN_RESV2(OFF) (56 + (OFF))
+#define LDN_MIF 63
+#define LDN_MAC(PORT) (64 + (PORT))
+#define LDN_DEVICE_ERROR 68
+#define LDN_MAX LDN_DEVICE_ERROR
+
+#define NIU_LDG_MIN 0
+#define NIU_LDG_MAX 63
+#define NIU_NUM_LDG 64
+#define LDG_INVALID 0xff
+
+/* PHY stuff */
+#define NIU_PMA_PMD_DEV_ADDR 1
+#define NIU_PCS_DEV_ADDR 3
+
+#define NIU_PHY_ID_MASK 0xfffff0f0
+#define NIU_PHY_ID_BCM8704 0x00206030
+#define NIU_PHY_ID_BCM5464R 0x002060b0
+
+#define BCM8704_PMA_PMD_DEV_ADDR 1
+#define BCM8704_PCS_DEV_ADDR 2
+#define BCM8704_USER_DEV3_ADDR 3
+#define BCM8704_PHYXS_DEV_ADDR 4
+#define BCM8704_USER_DEV4_ADDR 4
+
+#define BCM8704_PMD_RCV_SIGDET 0x000a
+#define PMD_RCV_SIGDET_LANE3 0x0010
+#define PMD_RCV_SIGDET_LANE2 0x0008
+#define PMD_RCV_SIGDET_LANE1 0x0004
+#define PMD_RCV_SIGDET_LANE0 0x0002
+#define PMD_RCV_SIGDET_GLOBAL 0x0001
+
+#define BCM8704_PCS_10G_R_STATUS 0x0020
+#define PCS_10G_R_STATUS_LINKSTAT 0x1000
+#define PCS_10G_R_STATUS_PRBS31_ABLE 0x0004
+#define PCS_10G_R_STATUS_HI_BER 0x0002
+#define PCS_10G_R_STATUS_BLK_LOCK 0x0001
+
+#define BCM8704_USER_CONTROL 0xc800
+#define USER_CONTROL_OPTXENB_LVL 0x8000
+#define USER_CONTROL_OPTXRST_LVL 0x4000
+#define USER_CONTROL_OPBIASFLT_LVL 0x2000
+#define USER_CONTROL_OBTMPFLT_LVL 0x1000
+#define USER_CONTROL_OPPRFLT_LVL 0x0800
+#define USER_CONTROL_OPTXFLT_LVL 0x0400
+#define USER_CONTROL_OPRXLOS_LVL 0x0200
+#define USER_CONTROL_OPRXFLT_LVL 0x0100
+#define USER_CONTROL_OPTXON_LVL 0x0080
+#define USER_CONTROL_RES1 0x007f
+#define USER_CONTROL_RES1_SHIFT 0
+
+#define BCM8704_USER_ANALOG_CLK 0xc801
+#define BCM8704_USER_PMD_RX_CONTROL 0xc802
+
+#define BCM8704_USER_PMD_TX_CONTROL 0xc803
+#define USER_PMD_TX_CTL_RES1 0xfe00
+#define USER_PMD_TX_CTL_XFP_CLKEN 0x0100
+#define USER_PMD_TX_CTL_TX_DAC_TXD 0x00c0
+#define USER_PMD_TX_CTL_TX_DAC_TXD_SH 6
+#define USER_PMD_TX_CTL_TX_DAC_TXCK 0x0030
+#define USER_PMD_TX_CTL_TX_DAC_TXCK_SH 4
+#define USER_PMD_TX_CTL_TSD_LPWREN 0x0008
+#define USER_PMD_TX_CTL_TSCK_LPWREN 0x0004
+#define USER_PMD_TX_CTL_CMU_LPWREN 0x0002
+#define USER_PMD_TX_CTL_SFIFORST 0x0001
+
+#define BCM8704_USER_ANALOG_STATUS0 0xc804
+#define BCM8704_USER_OPT_DIGITAL_CTRL 0xc808
+#define BCM8704_USER_TX_ALARM_STATUS 0x9004
+
+#define USER_ODIG_CTRL_FMODE 0x8000
+#define USER_ODIG_CTRL_TX_PDOWN 0x4000
+#define USER_ODIG_CTRL_RX_PDOWN 0x2000
+#define USER_ODIG_CTRL_EFILT_EN 0x1000
+#define USER_ODIG_CTRL_OPT_RST 0x0800
+#define USER_ODIG_CTRL_PCS_TIB 0x0400
+#define USER_ODIG_CTRL_PCS_RI 0x0200
+#define USER_ODIG_CTRL_RESV1 0x0180
+#define USER_ODIG_CTRL_GPIOS 0x0060
+#define USER_ODIG_CTRL_GPIOS_SHIFT 5
+#define USER_ODIG_CTRL_RESV2 0x0010
+#define USER_ODIG_CTRL_LB_ERR_DIS 0x0008
+#define USER_ODIG_CTRL_RESV3 0x0006
+#define USER_ODIG_CTRL_TXONOFF_PD_DIS 0x0001
+
+#define BCM8704_PHYXS_XGXS_LANE_STAT 0x0018
+#define PHYXS_XGXS_LANE_STAT_ALINGED 0x1000
+#define PHYXS_XGXS_LANE_STAT_PATTEST 0x0800
+#define PHYXS_XGXS_LANE_STAT_MAGIC 0x0400
+#define PHYXS_XGXS_LANE_STAT_LANE3 0x0008
+#define PHYXS_XGXS_LANE_STAT_LANE2 0x0004
+#define PHYXS_XGXS_LANE_STAT_LANE1 0x0002
+#define PHYXS_XGXS_LANE_STAT_LANE0 0x0001
+
+#define BCM5464R_AUX_CTL 24
+#define BCM5464R_AUX_CTL_EXT_LB 0x8000
+#define BCM5464R_AUX_CTL_EXT_PLEN 0x4000
+#define BCM5464R_AUX_CTL_ER1000 0x3000
+#define BCM5464R_AUX_CTL_ER1000_SHIFT 12
+#define BCM5464R_AUX_CTL_RESV1 0x0800
+#define BCM5464R_AUX_CTL_WRITE_1 0x0400
+#define BCM5464R_AUX_CTL_RESV2 0x0300
+#define BCM5464R_AUX_CTL_PRESP_DIS 0x0080
+#define BCM5464R_AUX_CTL_RESV3 0x0040
+#define BCM5464R_AUX_CTL_ER100 0x0030
+#define BCM5464R_AUX_CTL_ER100_SHIFT 4
+#define BCM5464R_AUX_CTL_DIAG_MODE 0x0008
+#define BCM5464R_AUX_CTL_SR_SEL 0x0007
+#define BCM5464R_AUX_CTL_SR_SEL_SHIFT 0
+
+#define BCM5464R_CTRL1000_AS_MASTER 0x0800
+#define BCM5464R_CTRL1000_ENABLE_AS_MASTER 0x1000
+
+#define RCR_ENTRY_MULTI 0x8000000000000000ULL
+#define RCR_ENTRY_PKT_TYPE 0x6000000000000000ULL
+#define RCR_ENTRY_PKT_TYPE_SHIFT 61
+#define RCR_ENTRY_ZERO_COPY 0x1000000000000000ULL
+#define RCR_ENTRY_NOPORT 0x0800000000000000ULL
+#define RCR_ENTRY_PROMISC 0x0400000000000000ULL
+#define RCR_ENTRY_ERROR 0x0380000000000000ULL
+#define RCR_ENTRY_DCF_ERR 0x0040000000000000ULL
+#define RCR_ENTRY_L2_LEN 0x003fff0000000000ULL
+#define RCR_ENTRY_L2_LEN_SHIFT 40
+#define RCR_ENTRY_PKTBUFSZ 0x000000c000000000ULL
+#define RCR_ENTRY_PKTBUFSZ_SHIFT 38
+#define RCR_ENTRY_PKT_BUF_ADDR 0x0000003fffffffffULL /* bits 43:6 */
+#define RCR_ENTRY_PKT_BUF_ADDR_SHIFT 6
+
+#define RCR_PKT_TYPE_OTHER 0x0
+#define RCR_PKT_TYPE_TCP 0x1
+#define RCR_PKT_TYPE_UDP 0x2
+#define RCR_PKT_TYPE_SCTP 0x3
+
+#define NIU_RXPULL_MAX ETH_HLEN
+
+struct rx_pkt_hdr0 {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ u8 inputport:2,
+ maccheck:1,
+ class:4;
+ u8 vlan:1,
+ llcsnap:1,
+ noport:1,
+ badip:1,
+ tcamhit:1,
+ tres:2,
+ tzfvld:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ u8 class:4,
+ maccheck:1,
+ inputport:2;
+ u8 tzfvld:1,
+ tres:2,
+ tcamhit:1,
+ badip:1,
+ noport:1,
+ llcsnap:1,
+ vlan:1;
+#endif
+};
+
+struct rx_pkt_hdr1 {
+ u8 hwrsvd1;
+ u8 tcammatch;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ u8 hwrsvd2:2,
+ hashit:1,
+ exact:1,
+ hzfvld:1,
+ hashsidx:3;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ u8 hashsidx:3,
+ hzfvld:1,
+ exact:1,
+ hashit:1,
+ hwrsvd2:2;
+#endif
+ u8 zcrsvd;
+
+ /* Bits 11:8 of zero copy flow ID. */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ u8 hwrsvd3:4, zflowid0:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ u8 zflowid0:4, hwrsvd3:4;
+#endif
+
+ /* Bits 7:0 of zero copy flow ID. */
+ u8 zflowid1;
+
+ /* Bits 15:8 of hash value, H2. */
+ u8 hashval2_0;
+
+ /* Bits 7:0 of hash value, H2. */
+ u8 hashval2_1;
+
+ /* Bits 19:16 of hash value, H1. */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ u8 hwrsvd4:4, hashval1_0:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ u8 hashval1_0:4, hwrsvd4:4;
+#endif
+
+ /* Bits 15:8 of hash value, H1. */
+ u8 hashval1_1;
+
+ /* Bits 7:0 of hash value, H1. */
+ u8 hashval1_2;
+
+ u8 usrdata_0; /* Bits 39:32 of user data. */
+ u8 usrdata_1; /* Bits 31:24 of user data. */
+ u8 usrdata_2; /* Bits 23:16 of user data. */
+ u8 usrdata_3; /* Bits 15:8 of user data. */
+ u8 usrdata_4; /* Bits 7:0 of user data. */
+};
+
+struct tx_dma_mbox {
+ u64 tx_dma_pre_st;
+ u64 tx_cs;
+ u64 tx_ring_kick;
+ u64 tx_ring_hdl;
+ u64 resv1;
+ u32 tx_rng_err_logl;
+ u32 tx_rng_err_logh;
+ u64 resv2;
+ u64 resv3;
+};
+
+struct tx_pkt_hdr {
+ __le64 flags;
+#define TXHDR_PAD 0x0000000000000007ULL
+#define TXHDR_PAD_SHIFT 0
+#define TXHDR_LEN 0x000000003fff0000ULL
+#define TXHDR_LEN_SHIFT 16
+#define TXHDR_L4STUFF 0x0000003f00000000ULL
+#define TXHDR_L4STUFF_SHIFT 32
+#define TXHDR_L4START 0x00003f0000000000ULL
+#define TXHDR_L4START_SHIFT 40
+#define TXHDR_L3START 0x000f000000000000ULL
+#define TXHDR_L3START_SHIFT 48
+#define TXHDR_IHL 0x00f0000000000000ULL
+#define TXHDR_IHL_SHIFT 52
+#define TXHDR_VLAN 0x0100000000000000ULL
+#define TXHDR_LLC 0x0200000000000000ULL
+#define TXHDR_IP_VER 0x2000000000000000ULL
+#define TXHDR_CSUM_NONE 0x0000000000000000ULL
+#define TXHDR_CSUM_TCP 0x4000000000000000ULL
+#define TXHDR_CSUM_UDP 0x8000000000000000ULL
+#define TXHDR_CSUM_SCTP 0xc000000000000000ULL
+ __le64 resv;
+};
+
+#define TX_DESC_SOP 0x8000000000000000ULL
+#define TX_DESC_MARK 0x4000000000000000ULL
+#define TX_DESC_NUM_PTR 0x3c00000000000000ULL
+#define TX_DESC_NUM_PTR_SHIFT 58
+#define TX_DESC_TR_LEN 0x01fff00000000000ULL
+#define TX_DESC_TR_LEN_SHIFT 44
+#define TX_DESC_SAD 0x00000fffffffffffULL
+#define TX_DESC_SAD_SHIFT 0
+
+struct tx_buff_info {
+ struct sk_buff *skb;
+ u64 mapping;
+};
+
+struct txdma_mailbox {
+ __le64 tx_dma_pre_st;
+ __le64 tx_cs;
+ __le64 tx_ring_kick;
+ __le64 tx_ring_hdl;
+ __le64 resv1;
+ __le32 tx_rng_err_logl;
+ __le32 tx_rng_err_logh;
+ __le64 resv2[2];
+} __attribute__((aligned(64)));
+
+#define MAX_TX_RING_SIZE 256
+#define MAX_TX_DESC_LEN 4076
+
+struct tx_ring_info {
+ struct tx_buff_info tx_buffs[MAX_TX_RING_SIZE];
+ struct niu *np;
+ u64 tx_cs;
+ int pending;
+ int prod;
+ int cons;
+ int wrap_bit;
+ u16 last_pkt_cnt;
+ u16 tx_channel;
+ u16 mark_counter;
+ u16 mark_freq;
+ u16 mark_pending;
+ u16 __pad;
+ struct txdma_mailbox *mbox;
+ __le64 *descr;
+
+ u64 tx_packets;
+ u64 tx_bytes;
+ u64 tx_errors;
+
+ u64 mbox_dma;
+ u64 descr_dma;
+ int max_burst;
+};
+
+#define NEXT_TX(tp, index) \
+ (((index) + 1) < (tp)->pending ? ((index) + 1) : 0)
+
+static inline u32 niu_tx_avail(struct tx_ring_info *tp)
+{
+ return (tp->pending -
+ ((tp->prod - tp->cons) & (MAX_TX_RING_SIZE - 1)));
+}
+
+struct rxdma_mailbox {
+ __le64 rx_dma_ctl_stat;
+ __le64 rbr_stat;
+ __le32 rbr_hdl;
+ __le32 rbr_hdh;
+ __le64 resv1;
+ __le32 rcrstat_c;
+ __le32 rcrstat_b;
+ __le64 rcrstat_a;
+ __le64 resv2[2];
+} __attribute__((aligned(64)));
+
+#define MAX_RBR_RING_SIZE 128
+#define MAX_RCR_RING_SIZE (MAX_RBR_RING_SIZE * 2)
+
+#define RBR_REFILL_MIN 16
+
+#define RX_SKB_ALLOC_SIZE 128 + NET_IP_ALIGN
+
+struct rx_ring_info {
+ struct niu *np;
+ int rx_channel;
+ u16 rbr_block_size;
+ u16 rbr_blocks_per_page;
+ u16 rbr_sizes[4];
+ unsigned int rcr_index;
+ unsigned int rcr_table_size;
+ unsigned int rbr_index;
+ unsigned int rbr_pending;
+ unsigned int rbr_refill_pending;
+ unsigned int rbr_kick_thresh;
+ unsigned int rbr_table_size;
+ struct page **rxhash;
+ struct rxdma_mailbox *mbox;
+ __le64 *rcr;
+ __le32 *rbr;
+#define RBR_DESCR_ADDR_SHIFT 12
+
+ u64 rx_packets;
+ u64 rx_bytes;
+ u64 rx_dropped;
+ u64 rx_errors;
+
+ u64 mbox_dma;
+ u64 rcr_dma;
+ u64 rbr_dma;
+
+ /* WRED */
+ int nonsyn_window;
+ int nonsyn_threshold;
+ int syn_window;
+ int syn_threshold;
+
+ /* interrupt mitigation */
+ int rcr_pkt_threshold;
+ int rcr_timeout;
+};
+
+#define NEXT_RCR(rp, index) \
+ (((index) + 1) < (rp)->rcr_table_size ? ((index) + 1) : 0)
+#define NEXT_RBR(rp, index) \
+ (((index) + 1) < (rp)->rbr_table_size ? ((index) + 1) : 0)
+
+#define NIU_MAX_PORTS 4
+#define NIU_NUM_RXCHAN 16
+#define NIU_NUM_TXCHAN 24
+#define MAC_NUM_HASH 16
+
+#define NIU_MAX_MTU 9216
+
+#define NIU_VPD_MIN_MAJOR 3
+#define NIU_VPD_MIN_MINOR 4
+
+#define NIU_VPD_MODEL_MAX 32
+#define NIU_VPD_BD_MODEL_MAX 16
+#define NIU_VPD_VERSION_MAX 64
+#define NIU_VPD_PHY_TYPE_MAX 8
+
+struct niu_vpd {
+ char model[NIU_VPD_MODEL_MAX];
+ char board_model[NIU_VPD_BD_MODEL_MAX];
+ char version[NIU_VPD_VERSION_MAX];
+ char phy_type[NIU_VPD_PHY_TYPE_MAX];
+ u8 mac_num;
+ u8 __pad;
+ u8 local_mac[6];
+ int fcode_major;
+ int fcode_minor;
+};
+
+struct niu_altmac_rdc {
+ u8 alt_mac_num;
+ u8 rdc_num;
+ u8 mac_pref;
+};
+
+struct niu_vlan_rdc {
+ u8 rdc_num;
+ u8 vlan_pref;
+};
+
+struct niu_classifier {
+ struct niu_altmac_rdc alt_mac_mappings[16];
+ struct niu_vlan_rdc vlan_mappings[ENET_VLAN_TBL_NUM_ENTRIES];
+
+ u16 tcam_index;
+ u16 num_alt_mac_mappings;
+
+ u32 h1_init;
+ u16 h2_init;
+};
+
+#define NIU_NUM_RDC_TABLES 8
+#define NIU_RDC_TABLE_SLOTS 16
+
+struct rdc_table {
+ u8 rxdma_channel[NIU_RDC_TABLE_SLOTS];
+};
+
+struct niu_rdc_tables {
+ struct rdc_table tables[NIU_NUM_RDC_TABLES];
+ int first_table_num;
+ int num_tables;
+};
+
+#define PHY_TYPE_PMA_PMD 0
+#define PHY_TYPE_PCS 1
+#define PHY_TYPE_MII 2
+#define PHY_TYPE_MAX 3
+
+struct phy_probe_info {
+ u32 phy_id[PHY_TYPE_MAX][NIU_MAX_PORTS];
+ u8 phy_port[PHY_TYPE_MAX][NIU_MAX_PORTS];
+ u8 cur[PHY_TYPE_MAX];
+
+ struct device_attribute phy_port_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS];
+ struct device_attribute phy_type_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS];
+ struct device_attribute phy_id_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS];
+};
+
+struct niu_tcam_entry {
+ u64 key[4];
+ u64 key_mask[4];
+ u64 assoc_data;
+};
+
+struct device_node;
+union niu_parent_id {
+ struct {
+ int domain;
+ int bus;
+ int device;
+ } pci;
+ struct device_node *of;
+};
+
+struct niu;
+struct niu_parent {
+ struct platform_device *plat_dev;
+ int index;
+
+ union niu_parent_id id;
+
+ struct niu *ports[NIU_MAX_PORTS];
+
+ atomic_t refcnt;
+ struct list_head list;
+
+ spinlock_t lock;
+
+ u32 flags;
+#define PARENT_FLGS_CLS_HWINIT 0x00000001
+
+ u32 port_phy;
+#define PORT_PHY_UNKNOWN 0x00000000
+#define PORT_PHY_INVALID 0xffffffff
+#define PORT_TYPE_10G 0x01
+#define PORT_TYPE_1G 0x02
+#define PORT_TYPE_MASK 0x03
+
+ u8 rxchan_per_port[NIU_MAX_PORTS];
+ u8 txchan_per_port[NIU_MAX_PORTS];
+
+ struct niu_rdc_tables rdc_group_cfg[NIU_MAX_PORTS];
+ u8 rdc_default[NIU_MAX_PORTS];
+
+ u8 ldg_map[LDN_MAX + 1];
+
+ u8 plat_type;
+#define PLAT_TYPE_INVALID 0x00
+#define PLAT_TYPE_ATLAS 0x01
+#define PLAT_TYPE_NIU 0x02
+#define PLAT_TYPE_VF_P0 0x03
+#define PLAT_TYPE_VF_P1 0x04
+
+ u8 num_ports;
+
+ u16 tcam_num_entries;
+#define NIU_PCI_TCAM_ENTRIES 256
+#define NIU_NONPCI_TCAM_ENTRIES 128
+#define NIU_TCAM_ENTRIES_MAX 256
+
+ int rxdma_clock_divider;
+
+ struct phy_probe_info phy_probe_info;
+
+ struct niu_tcam_entry tcam[NIU_TCAM_ENTRIES_MAX];
+ u64 l2_cls[2];
+ u64 l3_cls[4];
+ u64 tcam_key[12];
+ u64 flow_key[12];
+};
+
+struct niu_ops {
+ void *(*alloc_coherent)(struct device *dev, size_t size,
+ u64 *handle, gfp_t flag);
+ void (*free_coherent)(struct device *dev, size_t size,
+ void *cpu_addr, u64 handle);
+ u64 (*map_page)(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction);
+ void (*unmap_page)(struct device *dev, u64 dma_address,
+ size_t size, enum dma_data_direction direction);
+ u64 (*map_single)(struct device *dev, void *cpu_addr,
+ size_t size,
+ enum dma_data_direction direction);
+ void (*unmap_single)(struct device *dev, u64 dma_address,
+ size_t size, enum dma_data_direction direction);
+};
+
+struct niu_link_config {
+ /* Describes what we're trying to get. */
+ u32 advertising;
+ u32 supported;
+ u16 speed;
+ u8 duplex;
+ u8 autoneg;
+
+ /* Describes what we actually have. */
+ u16 active_speed;
+ u8 active_duplex;
+#define SPEED_INVALID 0xffff
+#define DUPLEX_INVALID 0xff
+#define AUTONEG_INVALID 0xff
+
+ u8 loopback_mode;
+#define LOOPBACK_DISABLED 0x00
+#define LOOPBACK_PHY 0x01
+#define LOOPBACK_MAC 0x02
+};
+
+struct niu_ldg {
+ struct napi_struct napi;
+ struct niu *np;
+ u8 ldg_num;
+ u8 timer;
+ u64 v0, v1, v2;
+ unsigned int irq;
+};
+
+struct niu_xmac_stats {
+ u64 tx_frames;
+ u64 tx_bytes;
+ u64 tx_fifo_errors;
+ u64 tx_overflow_errors;
+ u64 tx_max_pkt_size_errors;
+ u64 tx_underflow_errors;
+
+ u64 rx_local_faults;
+ u64 rx_remote_faults;
+ u64 rx_link_faults;
+ u64 rx_align_errors;
+ u64 rx_frags;
+ u64 rx_mcasts;
+ u64 rx_bcasts;
+ u64 rx_hist_cnt1;
+ u64 rx_hist_cnt2;
+ u64 rx_hist_cnt3;
+ u64 rx_hist_cnt4;
+ u64 rx_hist_cnt5;
+ u64 rx_hist_cnt6;
+ u64 rx_hist_cnt7;
+ u64 rx_octets;
+ u64 rx_code_violations;
+ u64 rx_len_errors;
+ u64 rx_crc_errors;
+ u64 rx_underflows;
+ u64 rx_overflows;
+
+ u64 pause_off_state;
+ u64 pause_on_state;
+ u64 pause_received;
+};
+
+struct niu_bmac_stats {
+ u64 tx_underflow_errors;
+ u64 tx_max_pkt_size_errors;
+ u64 tx_bytes;
+ u64 tx_frames;
+
+ u64 rx_overflows;
+ u64 rx_frames;
+ u64 rx_align_errors;
+ u64 rx_crc_errors;
+ u64 rx_len_errors;
+
+ u64 pause_off_state;
+ u64 pause_on_state;
+ u64 pause_received;
+};
+
+union niu_mac_stats {
+ struct niu_xmac_stats xmac;
+ struct niu_bmac_stats bmac;
+};
+
+struct niu_phy_ops {
+ int (*serdes_init)(struct niu *np);
+ int (*xcvr_init)(struct niu *np);
+ int (*link_status)(struct niu *np, int *);
+};
+
+struct of_device;
+struct niu {
+ void __iomem *regs;
+ struct net_device *dev;
+ struct pci_dev *pdev;
+ struct device *device;
+ struct niu_parent *parent;
+
+ u32 flags;
+#define NIU_FLAGS_MSIX 0x00400000 /* MSI-X in use */
+#define NIU_FLAGS_MCAST 0x00200000 /* multicast filter enabled */
+#define NIU_FLAGS_PROMISC 0x00100000 /* PROMISC enabled */
+#define NIU_FLAGS_VPD_VALID 0x00080000 /* VPD has valid version */
+#define NIU_FLAGS_10G 0x00040000 /* 0=1G 1=10G */
+#define NIU_FLAGS_FIBER 0x00020000 /* 0=COPPER 1=FIBER */
+#define NIU_FLAGS_XMAC 0x00010000 /* 0=BMAC 1=XMAC */
+
+ u32 msg_enable;
+
+ /* Protects hw programming, and ring state. */
+ spinlock_t lock;
+
+ const struct niu_ops *ops;
+ struct net_device_stats net_stats;
+ union niu_mac_stats mac_stats;
+
+ struct rx_ring_info *rx_rings;
+ struct tx_ring_info *tx_rings;
+ int num_rx_rings;
+ int num_tx_rings;
+
+ struct niu_ldg ldg[NIU_NUM_LDG];
+ int num_ldg;
+
+ void __iomem *mac_regs;
+ unsigned long ipp_off;
+ unsigned long pcs_off;
+ unsigned long xpcs_off;
+
+ struct timer_list timer;
+ const struct niu_phy_ops *phy_ops;
+ int phy_addr;
+
+ struct niu_link_config link_config;
+
+ struct work_struct reset_task;
+
+ u8 port;
+ u8 mac_xcvr;
+#define MAC_XCVR_MII 1
+#define MAC_XCVR_PCS 2
+#define MAC_XCVR_XPCS 3
+
+ struct niu_classifier clas;
+
+ struct niu_vpd vpd;
+ u32 eeprom_len;
+
+ struct of_device *op;
+ void __iomem *vir_regs_1;
+ void __iomem *vir_regs_2;
+};
+
+#endif /* _NIU_H */
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index ea80e6cb3de..ea71f6d8266 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1,4 +1,4 @@
-#define VERSION "0.22"
+#define VERSION "0.23"
/* ns83820.c by Benjamin LaHaise with contributions.
*
* Questions/comments/discussion to linux-ns83820@kvack.org.
@@ -1247,6 +1247,149 @@ static struct net_device_stats *ns83820_get_stats(struct net_device *ndev)
return &dev->stats;
}
+/* Let ethtool retrieve info */
+static int ns83820_get_settings(struct net_device *ndev,
+ struct ethtool_cmd *cmd)
+{
+ struct ns83820 *dev = PRIV(ndev);
+ u32 cfg, tanar, tbicr;
+ int have_optical = 0;
+ int fullduplex = 0;
+
+ /*
+ * Here's the list of available ethtool commands from other drivers:
+ * cmd->advertising =
+ * cmd->speed =
+ * cmd->duplex =
+ * cmd->port = 0;
+ * cmd->phy_address =
+ * cmd->transceiver = 0;
+ * cmd->autoneg =
+ * cmd->maxtxpkt = 0;
+ * cmd->maxrxpkt = 0;
+ */
+
+ /* read current configuration */
+ cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
+ tanar = readl(dev->base + TANAR);
+ tbicr = readl(dev->base + TBICR);
+
+ if (dev->CFG_cache & CFG_TBI_EN) {
+ /* we have an optical interface */
+ have_optical = 1;
+ fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
+
+ } else {
+ /* We have copper */
+ fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
+ }
+
+ cmd->supported = SUPPORTED_Autoneg;
+
+ /* we have optical interface */
+ if (dev->CFG_cache & CFG_TBI_EN) {
+ cmd->supported |= SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_FIBRE;
+ cmd->port = PORT_FIBRE;
+ } /* TODO: else copper related support */
+
+ cmd->duplex = fullduplex ? DUPLEX_FULL : DUPLEX_HALF;
+ switch (cfg / CFG_SPDSTS0 & 3) {
+ case 2:
+ cmd->speed = SPEED_1000;
+ break;
+ case 1:
+ cmd->speed = SPEED_100;
+ break;
+ default:
+ cmd->speed = SPEED_10;
+ break;
+ }
+ cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE) ? 1: 0;
+ return 0;
+}
+
+/* Let ethool change settings*/
+static int ns83820_set_settings(struct net_device *ndev,
+ struct ethtool_cmd *cmd)
+{
+ struct ns83820 *dev = PRIV(ndev);
+ u32 cfg, tanar;
+ int have_optical = 0;
+ int fullduplex = 0;
+
+ /* read current configuration */
+ cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
+ tanar = readl(dev->base + TANAR);
+
+ if (dev->CFG_cache & CFG_TBI_EN) {
+ /* we have optical */
+ have_optical = 1;
+ fullduplex = (tanar & TANAR_FULL_DUP);
+
+ } else {
+ /* we have copper */
+ fullduplex = cfg & CFG_DUPSTS;
+ }
+
+ spin_lock_irq(&dev->misc_lock);
+ spin_lock(&dev->tx_lock);
+
+ /* Set duplex */
+ if (cmd->duplex != fullduplex) {
+ if (have_optical) {
+ /*set full duplex*/
+ if (cmd->duplex == DUPLEX_FULL) {
+ /* force full duplex */
+ writel(readl(dev->base + TXCFG)
+ | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP,
+ dev->base + TXCFG);
+ writel(readl(dev->base + RXCFG) | RXCFG_RX_FD,
+ dev->base + RXCFG);
+ /* Light up full duplex LED */
+ writel(readl(dev->base + GPIOR) | GPIOR_GP1_OUT,
+ dev->base + GPIOR);
+ } else {
+ /*TODO: set half duplex */
+ }
+
+ } else {
+ /*we have copper*/
+ /* TODO: Set duplex for copper cards */
+ }
+ printk(KERN_INFO "%s: Duplex set via ethtool\n",
+ ndev->name);
+ }
+
+ /* Set autonegotiation */
+ if (1) {
+ if (cmd->autoneg == AUTONEG_ENABLE) {
+ /* restart auto negotiation */
+ writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN,
+ dev->base + TBICR);
+ writel(TBICR_MR_AN_ENABLE, dev->base + TBICR);
+ dev->linkstate = LINK_AUTONEGOTIATE;
+
+ printk(KERN_INFO "%s: autoneg enabled via ethtool\n",
+ ndev->name);
+ } else {
+ /* disable auto negotiation */
+ writel(0x00000000, dev->base + TBICR);
+ }
+
+ printk(KERN_INFO "%s: autoneg %s via ethtool\n", ndev->name,
+ cmd->autoneg ? "ENABLED" : "DISABLED");
+ }
+
+ phy_intr(ndev);
+ spin_unlock(&dev->tx_lock);
+ spin_unlock_irq(&dev->misc_lock);
+
+ return 0;
+}
+/* end ethtool get/set support -df */
+
static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
{
struct ns83820 *dev = PRIV(ndev);
@@ -1263,8 +1406,10 @@ static u32 ns83820_get_link(struct net_device *ndev)
}
static const struct ethtool_ops ops = {
- .get_drvinfo = ns83820_get_drvinfo,
- .get_link = ns83820_get_link
+ .get_settings = ns83820_get_settings,
+ .set_settings = ns83820_set_settings,
+ .get_drvinfo = ns83820_get_drvinfo,
+ .get_link = ns83820_get_link
};
/* this function is called in irq context from the ISR */
@@ -1817,6 +1962,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
long addr;
int err;
int using_dac = 0;
+ DECLARE_MAC_BUF(mac);
/* See if we can set the dma mask early on; failure is fatal. */
if (sizeof(dma_addr_t) == 8 &&
@@ -1843,7 +1989,6 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
spin_lock_init(&dev->misc_lock);
dev->pci_dev = pci_dev;
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pci_dev->dev);
INIT_WORK(&dev->tq_refill, queue_refill);
@@ -2082,13 +2227,11 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
ndev->features |= NETIF_F_HIGHDMA;
}
- printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n",
+ printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %s io=0x%08lx irq=%d f=%s\n",
ndev->name,
(unsigned)readl(dev->base + SRR) >> 8,
(unsigned)readl(dev->base + SRR) & 0xff,
- ndev->dev_addr[0], ndev->dev_addr[1],
- ndev->dev_addr[2], ndev->dev_addr[3],
- ndev->dev_addr[4], ndev->dev_addr[5],
+ print_mac(mac, ndev->dev_addr),
addr, pci_dev->irq,
(ndev->features & NETIF_F_HIGHDMA) ? "h,sg" : "sg"
);
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index 0b3066a6fe4..09b4fde8d92 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -34,24 +34,29 @@
#include <net/checksum.h>
#include <asm/irq.h>
+#include <asm/firmware.h>
#include "pasemi_mac.h"
+/* We have our own align, since ppc64 in general has it at 0 because
+ * of design flaws in some of the server bridge chips. However, for
+ * PWRficient doing the unaligned copies is more expensive than doing
+ * unaligned DMA, so make sure the data is aligned instead.
+ */
+#define LOCAL_SKB_ALIGN 2
/* TODO list
*
- * - Get rid of pci_{read,write}_config(), map registers with ioremap
- * for performance
- * - PHY support
* - Multicast support
* - Large MTU support
- * - Other performance improvements
+ * - SW LRO
+ * - Multiqueue RX/TX
*/
/* Must be a power of two */
-#define RX_RING_SIZE 512
-#define TX_RING_SIZE 512
+#define RX_RING_SIZE 4096
+#define TX_RING_SIZE 4096
#define DEFAULT_MSG_ENABLE \
(NETIF_MSG_DRV | \
@@ -63,12 +68,16 @@
NETIF_MSG_RX_ERR | \
NETIF_MSG_TX_ERR)
-#define TX_DESC(mac, num) ((mac)->tx->desc[(num) & (TX_RING_SIZE-1)])
-#define TX_DESC_INFO(mac, num) ((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)])
-#define RX_DESC(mac, num) ((mac)->rx->desc[(num) & (RX_RING_SIZE-1)])
-#define RX_DESC_INFO(mac, num) ((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)])
+#define TX_RING(mac, num) ((mac)->tx->ring[(num) & (TX_RING_SIZE-1)])
+#define TX_RING_INFO(mac, num) ((mac)->tx->ring_info[(num) & (TX_RING_SIZE-1)])
+#define RX_RING(mac, num) ((mac)->rx->ring[(num) & (RX_RING_SIZE-1)])
+#define RX_RING_INFO(mac, num) ((mac)->rx->ring_info[(num) & (RX_RING_SIZE-1)])
#define RX_BUFF(mac, num) ((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)])
+#define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \
+ & ((ring)->size - 1))
+#define RING_AVAIL(ring) ((ring->size) - RING_USED(ring))
+
#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
MODULE_LICENSE("GPL");
@@ -81,6 +90,43 @@ MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value");
static struct pasdma_status *dma_status;
+static int translation_enabled(void)
+{
+#if defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE)
+ return 1;
+#else
+ return firmware_has_feature(FW_FEATURE_LPAR);
+#endif
+}
+
+static void write_iob_reg(struct pasemi_mac *mac, unsigned int reg,
+ unsigned int val)
+{
+ out_le32(mac->iob_regs+reg, val);
+}
+
+static unsigned int read_mac_reg(struct pasemi_mac *mac, unsigned int reg)
+{
+ return in_le32(mac->regs+reg);
+}
+
+static void write_mac_reg(struct pasemi_mac *mac, unsigned int reg,
+ unsigned int val)
+{
+ out_le32(mac->regs+reg, val);
+}
+
+static unsigned int read_dma_reg(struct pasemi_mac *mac, unsigned int reg)
+{
+ return in_le32(mac->dma_regs+reg);
+}
+
+static void write_dma_reg(struct pasemi_mac *mac, unsigned int reg,
+ unsigned int val)
+{
+ out_le32(mac->dma_regs+reg, val);
+}
+
static int pasemi_get_mac_addr(struct pasemi_mac *mac)
{
struct pci_dev *pdev = mac->pdev;
@@ -128,11 +174,36 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac)
return 0;
}
+static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac,
+ struct sk_buff *skb,
+ dma_addr_t *dmas)
+{
+ int f;
+ int nfrags = skb_shinfo(skb)->nr_frags;
+
+ pci_unmap_single(mac->dma_pdev, dmas[0], skb_headlen(skb),
+ PCI_DMA_TODEVICE);
+
+ for (f = 0; f < nfrags; f++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
+
+ pci_unmap_page(mac->dma_pdev, dmas[f+1], frag->size,
+ PCI_DMA_TODEVICE);
+ }
+ dev_kfree_skb_irq(skb);
+
+ /* Freed descriptor slot + main SKB ptr + nfrags additional ptrs,
+ * aligned up to a power of 2
+ */
+ return (nfrags + 3) & ~1;
+}
+
static int pasemi_mac_setup_rx_resources(struct net_device *dev)
{
struct pasemi_mac_rxring *ring;
struct pasemi_mac *mac = netdev_priv(dev);
int chan_id = mac->dma_rxch;
+ unsigned int cfg;
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
@@ -141,22 +212,22 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev)
spin_lock_init(&ring->lock);
- ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+ ring->size = RX_RING_SIZE;
+ ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
RX_RING_SIZE, GFP_KERNEL);
- if (!ring->desc_info)
- goto out_desc_info;
+ if (!ring->ring_info)
+ goto out_ring_info;
/* Allocate descriptors */
- ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
- RX_RING_SIZE *
- sizeof(struct pas_dma_xct_descr),
+ ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev,
+ RX_RING_SIZE * sizeof(u64),
&ring->dma, GFP_KERNEL);
- if (!ring->desc)
- goto out_desc;
+ if (!ring->ring)
+ goto out_ring_desc;
- memset(ring->desc, 0, RX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+ memset(ring->ring, 0, RX_RING_SIZE * sizeof(u64));
ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev,
RX_RING_SIZE * sizeof(u64),
@@ -166,22 +237,34 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev)
memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64));
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEL(chan_id),
- PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma));
+ write_dma_reg(mac, PAS_DMA_RXCHAN_BASEL(chan_id), PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma));
+
+ write_dma_reg(mac, PAS_DMA_RXCHAN_BASEU(chan_id),
+ PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) |
+ PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 3));
+
+ cfg = PAS_DMA_RXCHAN_CFG_HBU(2);
+
+ if (translation_enabled())
+ cfg |= PAS_DMA_RXCHAN_CFG_CTR;
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEU(chan_id),
- PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) |
- PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2));
+ write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), cfg);
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_CFG(chan_id),
- PAS_DMA_RXCHAN_CFG_HBU(1));
+ write_dma_reg(mac, PAS_DMA_RXINT_BASEL(mac->dma_if),
+ PAS_DMA_RXINT_BASEL_BRBL(ring->buf_dma));
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEL(mac->dma_if),
- PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers)));
+ write_dma_reg(mac, PAS_DMA_RXINT_BASEU(mac->dma_if),
+ PAS_DMA_RXINT_BASEU_BRBH(ring->buf_dma >> 32) |
+ PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEU(mac->dma_if),
- PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) |
- PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
+ cfg = PAS_DMA_RXINT_CFG_DHL(3) | PAS_DMA_RXINT_CFG_L2 |
+ PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP |
+ PAS_DMA_RXINT_CFG_HEN;
+
+ if (translation_enabled())
+ cfg |= PAS_DMA_RXINT_CFG_ITRR | PAS_DMA_RXINT_CFG_ITR;
+
+ write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), cfg);
ring->next_to_fill = 0;
ring->next_to_clean = 0;
@@ -194,11 +277,11 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev)
out_buffers:
dma_free_coherent(&mac->dma_pdev->dev,
- RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
- mac->rx->desc, mac->rx->dma);
-out_desc:
- kfree(ring->desc_info);
-out_desc_info:
+ RX_RING_SIZE * sizeof(u64),
+ mac->rx->ring, mac->rx->dma);
+out_ring_desc:
+ kfree(ring->ring_info);
+out_ring_info:
kfree(ring);
out_ring:
return -ENOMEM;
@@ -211,6 +294,7 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev)
u32 val;
int chan_id = mac->dma_txch;
struct pasemi_mac_txring *ring;
+ unsigned int cfg;
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring)
@@ -218,35 +302,39 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev)
spin_lock_init(&ring->lock);
- ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+ ring->size = TX_RING_SIZE;
+ ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
TX_RING_SIZE, GFP_KERNEL);
- if (!ring->desc_info)
- goto out_desc_info;
+ if (!ring->ring_info)
+ goto out_ring_info;
/* Allocate descriptors */
- ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
- TX_RING_SIZE *
- sizeof(struct pas_dma_xct_descr),
+ ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev,
+ TX_RING_SIZE * sizeof(u64),
&ring->dma, GFP_KERNEL);
- if (!ring->desc)
- goto out_desc;
+ if (!ring->ring)
+ goto out_ring_desc;
- memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+ memset(ring->ring, 0, TX_RING_SIZE * sizeof(u64));
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEL(chan_id),
- PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
+ write_dma_reg(mac, PAS_DMA_TXCHAN_BASEL(chan_id),
+ PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32);
- val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2);
+ val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 3);
+
+ write_dma_reg(mac, PAS_DMA_TXCHAN_BASEU(chan_id), val);
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEU(chan_id), val);
+ cfg = PAS_DMA_TXCHAN_CFG_TY_IFACE |
+ PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) |
+ PAS_DMA_TXCHAN_CFG_UP |
+ PAS_DMA_TXCHAN_CFG_WT(2);
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_CFG(chan_id),
- PAS_DMA_TXCHAN_CFG_TY_IFACE |
- PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) |
- PAS_DMA_TXCHAN_CFG_UP |
- PAS_DMA_TXCHAN_CFG_WT(2));
+ if (translation_enabled())
+ cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR;
- ring->next_to_use = 0;
+ write_dma_reg(mac, PAS_DMA_TXCHAN_CFG(chan_id), cfg);
+
+ ring->next_to_fill = 0;
ring->next_to_clean = 0;
snprintf(ring->irq_name, sizeof(ring->irq_name),
@@ -255,9 +343,9 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev)
return 0;
-out_desc:
- kfree(ring->desc_info);
-out_desc_info:
+out_ring_desc:
+ kfree(ring->ring_info);
+out_ring_info:
kfree(ring);
out_ring:
return -ENOMEM;
@@ -266,33 +354,37 @@ out_ring:
static void pasemi_mac_free_tx_resources(struct net_device *dev)
{
struct pasemi_mac *mac = netdev_priv(dev);
- unsigned int i;
+ unsigned int i, j;
struct pasemi_mac_buffer *info;
- struct pas_dma_xct_descr *dp;
-
- for (i = 0; i < TX_RING_SIZE; i++) {
- info = &TX_DESC_INFO(mac, i);
- dp = &TX_DESC(mac, i);
- if (info->dma) {
- if (info->skb) {
- pci_unmap_single(mac->dma_pdev,
- info->dma,
- info->skb->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb_any(info->skb);
- }
- info->dma = 0;
- info->skb = NULL;
- dp->mactx = 0;
- dp->ptr = 0;
- }
+ dma_addr_t dmas[MAX_SKB_FRAGS+1];
+ int freed;
+ int start, limit;
+
+ start = mac->tx->next_to_clean;
+ limit = mac->tx->next_to_fill;
+
+ /* Compensate for when fill has wrapped and clean has not */
+ if (start > limit)
+ limit += TX_RING_SIZE;
+
+ for (i = start; i < limit; i += freed) {
+ info = &TX_RING_INFO(mac, i+1);
+ if (info->dma && info->skb) {
+ for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++)
+ dmas[j] = TX_RING_INFO(mac, i+1+j).dma;
+ freed = pasemi_mac_unmap_tx_skb(mac, info->skb, dmas);
+ } else
+ freed = 2;
}
+ for (i = 0; i < TX_RING_SIZE; i++)
+ TX_RING(mac, i) = 0;
+
dma_free_coherent(&mac->dma_pdev->dev,
- TX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
- mac->tx->desc, mac->tx->dma);
+ TX_RING_SIZE * sizeof(u64),
+ mac->tx->ring, mac->tx->dma);
- kfree(mac->tx->desc_info);
+ kfree(mac->tx->ring_info);
kfree(mac->tx);
mac->tx = NULL;
}
@@ -302,72 +394,66 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev)
struct pasemi_mac *mac = netdev_priv(dev);
unsigned int i;
struct pasemi_mac_buffer *info;
- struct pas_dma_xct_descr *dp;
for (i = 0; i < RX_RING_SIZE; i++) {
- info = &RX_DESC_INFO(mac, i);
- dp = &RX_DESC(mac, i);
- if (info->skb) {
- if (info->dma) {
- pci_unmap_single(mac->dma_pdev,
- info->dma,
- info->skb->len,
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb_any(info->skb);
- }
- info->dma = 0;
- info->skb = NULL;
- dp->macrx = 0;
- dp->ptr = 0;
+ info = &RX_RING_INFO(mac, i);
+ if (info->skb && info->dma) {
+ pci_unmap_single(mac->dma_pdev,
+ info->dma,
+ info->skb->len,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(info->skb);
}
+ info->dma = 0;
+ info->skb = NULL;
}
+ for (i = 0; i < RX_RING_SIZE; i++)
+ RX_RING(mac, i) = 0;
+
dma_free_coherent(&mac->dma_pdev->dev,
- RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
- mac->rx->desc, mac->rx->dma);
+ RX_RING_SIZE * sizeof(u64),
+ mac->rx->ring, mac->rx->dma);
dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
mac->rx->buffers, mac->rx->buf_dma);
- kfree(mac->rx->desc_info);
+ kfree(mac->rx->ring_info);
kfree(mac->rx);
mac->rx = NULL;
}
-static void pasemi_mac_replenish_rx_ring(struct net_device *dev)
+static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit)
{
struct pasemi_mac *mac = netdev_priv(dev);
- unsigned int i;
- int start = mac->rx->next_to_fill;
- unsigned int limit, count;
-
- limit = (mac->rx->next_to_clean + RX_RING_SIZE -
- mac->rx->next_to_fill) & (RX_RING_SIZE - 1);
-
- /* Check to see if we're doing first-time setup */
- if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0))
- limit = RX_RING_SIZE;
+ int fill, count;
if (limit <= 0)
return;
- i = start;
- for (count = limit; count; count--) {
- struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i);
- u64 *buff = &RX_BUFF(mac, i);
+ fill = mac->rx->next_to_fill;
+ for (count = 0; count < limit; count++) {
+ struct pasemi_mac_buffer *info = &RX_RING_INFO(mac, fill);
+ u64 *buff = &RX_BUFF(mac, fill);
struct sk_buff *skb;
dma_addr_t dma;
+ /* Entry in use? */
+ WARN_ON(*buff);
+
/* skb might still be in there for recycle on short receives */
if (info->skb)
skb = info->skb;
- else
+ else {
skb = dev_alloc_skb(BUF_SIZE);
+ skb_reserve(skb, LOCAL_SKB_ALIGN);
+ }
if (unlikely(!skb))
break;
- dma = pci_map_single(mac->dma_pdev, skb->data, skb->len,
+ dma = pci_map_single(mac->dma_pdev, skb->data,
+ BUF_SIZE - LOCAL_SKB_ALIGN,
PCI_DMA_FROMDEVICE);
if (unlikely(dma_mapping_error(dma))) {
@@ -378,19 +464,15 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev)
info->skb = skb;
info->dma = dma;
*buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
- i++;
+ fill++;
}
wmb();
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXCHAN_INCR(mac->dma_rxch),
- limit - count);
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXINT_INCR(mac->dma_if),
- limit - count);
+ write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), count);
- mac->rx->next_to_fill += limit - count;
+ mac->rx->next_to_fill = (mac->rx->next_to_fill + count) &
+ (RX_RING_SIZE - 1);
}
static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac)
@@ -404,9 +486,7 @@ static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac)
reg = PAS_IOB_DMA_RXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_RXCH_RESET_PINTC;
- pci_write_config_dword(mac->iob_pdev,
- PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch),
- reg);
+ write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
}
static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac)
@@ -418,69 +498,106 @@ static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac)
reg = PAS_IOB_DMA_TXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_TXCH_RESET_PINTC;
- pci_write_config_dword(mac->iob_pdev,
- PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg);
+ write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg);
}
+static inline void pasemi_mac_rx_error(struct pasemi_mac *mac, u64 macrx)
+{
+ unsigned int rcmdsta, ccmdsta;
+
+ if (!netif_msg_rx_err(mac))
+ return;
+
+ rcmdsta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+ ccmdsta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+
+ printk(KERN_ERR "pasemi_mac: rx error. macrx %016lx, rx status %lx\n",
+ macrx, *mac->rx_status);
+
+ printk(KERN_ERR "pasemi_mac: rcmdsta %08x ccmdsta %08x\n",
+ rcmdsta, ccmdsta);
+}
+
+static inline void pasemi_mac_tx_error(struct pasemi_mac *mac, u64 mactx)
+{
+ unsigned int cmdsta;
+
+ if (!netif_msg_tx_err(mac))
+ return;
+
+ cmdsta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+
+ printk(KERN_ERR "pasemi_mac: tx error. mactx 0x%016lx, "\
+ "tx status 0x%016lx\n", mactx, *mac->tx_status);
+
+ printk(KERN_ERR "pasemi_mac: tcmdsta 0x%08x\n", cmdsta);
+}
+
static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
{
unsigned int n;
int count;
- struct pas_dma_xct_descr *dp;
struct pasemi_mac_buffer *info;
struct sk_buff *skb;
- unsigned int i, len;
+ unsigned int len;
u64 macrx;
dma_addr_t dma;
+ int buf_index;
+ u64 eval;
spin_lock(&mac->rx->lock);
n = mac->rx->next_to_clean;
- for (count = limit; count; count--) {
+ prefetch(&RX_RING(mac, n));
- rmb();
+ for (count = 0; count < limit; count++) {
+ macrx = RX_RING(mac, n);
- dp = &RX_DESC(mac, n);
- macrx = dp->macrx;
+ if ((macrx & XCT_MACRX_E) ||
+ (*mac->rx_status & PAS_STATUS_ERROR))
+ pasemi_mac_rx_error(mac, macrx);
if (!(macrx & XCT_MACRX_O))
break;
-
info = NULL;
- /* We have to scan for our skb since there's no way
- * to back-map them from the descriptor, and if we
- * have several receive channels then they might not
- * show up in the same order as they were put on the
- * interface ring.
- */
+ BUG_ON(!(macrx & XCT_MACRX_RR_8BRES));
- dma = (dp->ptr & XCT_PTR_ADDR_M);
- for (i = n; i < (n + RX_RING_SIZE); i++) {
- info = &RX_DESC_INFO(mac, i);
- if (info->dma == dma)
- break;
- }
+ eval = (RX_RING(mac, n+1) & XCT_RXRES_8B_EVAL_M) >>
+ XCT_RXRES_8B_EVAL_S;
+ buf_index = eval-1;
+
+ dma = (RX_RING(mac, n+2) & XCT_PTR_ADDR_M);
+ info = &RX_RING_INFO(mac, buf_index);
skb = info->skb;
- info->dma = 0;
- pci_unmap_single(mac->dma_pdev, dma, skb->len,
- PCI_DMA_FROMDEVICE);
+ prefetch(skb);
+ prefetch(&skb->data_len);
len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
+ pci_unmap_single(mac->dma_pdev, dma, len, PCI_DMA_FROMDEVICE);
+
+ if (macrx & XCT_MACRX_CRC) {
+ /* CRC error flagged */
+ mac->netdev->stats.rx_errors++;
+ mac->netdev->stats.rx_crc_errors++;
+ dev_kfree_skb_irq(skb);
+ goto next;
+ }
+
if (len < 256) {
- struct sk_buff *new_skb =
- netdev_alloc_skb(mac->netdev, len + NET_IP_ALIGN);
+ struct sk_buff *new_skb;
+
+ new_skb = netdev_alloc_skb(mac->netdev,
+ len + LOCAL_SKB_ALIGN);
if (new_skb) {
- skb_reserve(new_skb, NET_IP_ALIGN);
- memcpy(new_skb->data - NET_IP_ALIGN,
- skb->data - NET_IP_ALIGN,
- len + NET_IP_ALIGN);
+ skb_reserve(new_skb, LOCAL_SKB_ALIGN);
+ memcpy(new_skb->data, skb->data, len);
/* save the skb in buffer_info as good */
skb = new_skb;
}
@@ -488,73 +605,131 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
} else
info->skb = NULL;
- skb_put(skb, len);
+ info->dma = 0;
- skb->protocol = eth_type_trans(skb, mac->netdev);
+ /* Don't include CRC */
+ skb_put(skb, len-4);
- if ((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) {
- skb->ip_summed = CHECKSUM_COMPLETE;
+ if (likely((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK)) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->csum = (macrx & XCT_MACRX_CSUM_M) >>
XCT_MACRX_CSUM_S;
} else
skb->ip_summed = CHECKSUM_NONE;
- mac->stats.rx_bytes += len;
- mac->stats.rx_packets++;
+ mac->netdev->stats.rx_bytes += len;
+ mac->netdev->stats.rx_packets++;
+ skb->protocol = eth_type_trans(skb, mac->netdev);
netif_receive_skb(skb);
- dp->ptr = 0;
- dp->macrx = 0;
+next:
+ RX_RING(mac, n) = 0;
+ RX_RING(mac, n+1) = 0;
+
+ /* Need to zero it out since hardware doesn't, since the
+ * replenish loop uses it to tell when it's done.
+ */
+ RX_BUFF(mac, buf_index) = 0;
+
+ n += 4;
+ }
- n++;
+ if (n > RX_RING_SIZE) {
+ /* Errata 5971 workaround: L2 target of headers */
+ write_iob_reg(mac, PAS_IOB_COM_PKTHDRCNT, 0);
+ n &= (RX_RING_SIZE-1);
}
- mac->rx->next_to_clean += limit - count;
- pasemi_mac_replenish_rx_ring(mac->netdev);
+ mac->rx->next_to_clean = n;
+
+ /* Increase is in number of 16-byte entries, and since each descriptor
+ * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with
+ * count*2.
+ */
+ write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count << 1);
+
+ pasemi_mac_replenish_rx_ring(mac->netdev, count);
spin_unlock(&mac->rx->lock);
return count;
}
+/* Can't make this too large or we blow the kernel stack limits */
+#define TX_CLEAN_BATCHSIZE (128/MAX_SKB_FRAGS)
+
static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
{
- int i;
- struct pasemi_mac_buffer *info;
- struct pas_dma_xct_descr *dp;
- int start, count;
- int flags;
-
+ int i, j;
+ unsigned int start, descr_count, buf_count, batch_limit;
+ unsigned int ring_limit;
+ unsigned int total_count;
+ unsigned long flags;
+ struct sk_buff *skbs[TX_CLEAN_BATCHSIZE];
+ dma_addr_t dmas[TX_CLEAN_BATCHSIZE][MAX_SKB_FRAGS+1];
+
+ total_count = 0;
+ batch_limit = TX_CLEAN_BATCHSIZE;
+restart:
spin_lock_irqsave(&mac->tx->lock, flags);
start = mac->tx->next_to_clean;
- count = 0;
+ ring_limit = mac->tx->next_to_fill;
- for (i = start; i < mac->tx->next_to_use; i++) {
- dp = &TX_DESC(mac, i);
- if (!dp || (dp->mactx & XCT_MACTX_O))
+ /* Compensate for when fill has wrapped but clean has not */
+ if (start > ring_limit)
+ ring_limit += TX_RING_SIZE;
+
+ buf_count = 0;
+ descr_count = 0;
+
+ for (i = start;
+ descr_count < batch_limit && i < ring_limit;
+ i += buf_count) {
+ u64 mactx = TX_RING(mac, i);
+ struct sk_buff *skb;
+
+ if ((mactx & XCT_MACTX_E) ||
+ (*mac->tx_status & PAS_STATUS_ERROR))
+ pasemi_mac_tx_error(mac, mactx);
+
+ if (unlikely(mactx & XCT_MACTX_O))
+ /* Not yet transmitted */
break;
- count++;
+ skb = TX_RING_INFO(mac, i+1).skb;
+ skbs[descr_count] = skb;
- info = &TX_DESC_INFO(mac, i);
+ buf_count = 2 + skb_shinfo(skb)->nr_frags;
+ for (j = 0; j <= skb_shinfo(skb)->nr_frags; j++)
+ dmas[descr_count][j] = TX_RING_INFO(mac, i+1+j).dma;
- pci_unmap_single(mac->dma_pdev, info->dma,
- info->skb->len, PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(info->skb);
+ TX_RING(mac, i) = 0;
+ TX_RING(mac, i+1) = 0;
- info->skb = NULL;
- info->dma = 0;
- dp->mactx = 0;
- dp->ptr = 0;
+ /* Since we always fill with an even number of entries, make
+ * sure we skip any unused one at the end as well.
+ */
+ if (buf_count & 1)
+ buf_count++;
+ descr_count++;
}
- mac->tx->next_to_clean += count;
- spin_unlock_irqrestore(&mac->tx->lock, flags);
+ mac->tx->next_to_clean = i & (TX_RING_SIZE-1);
+ spin_unlock_irqrestore(&mac->tx->lock, flags);
netif_wake_queue(mac->netdev);
- return count;
+ for (i = 0; i < descr_count; i++)
+ pasemi_mac_unmap_tx_skb(mac, skbs[i], dmas[i]);
+
+ total_count += descr_count;
+
+ /* If the batch was full, try to clean more */
+ if (descr_count == batch_limit)
+ goto restart;
+
+ return total_count;
}
@@ -567,15 +742,10 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
if (!(*mac->rx_status & PAS_STATUS_CAUSE_M))
return IRQ_NONE;
- if (*mac->rx_status & PAS_STATUS_ERROR)
- printk("rx_status reported error\n");
-
/* Don't reset packet count so it won't fire again but clear
* all others.
*/
- pci_read_config_dword(mac->dma_pdev, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), &reg);
-
reg = 0;
if (*mac->rx_status & PAS_STATUS_SOFT)
reg |= PAS_IOB_DMA_RXCH_RESET_SINTC;
@@ -584,11 +754,9 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
if (*mac->rx_status & PAS_STATUS_TIMER)
reg |= PAS_IOB_DMA_RXCH_RESET_TINTC;
- netif_rx_schedule(dev);
-
- pci_write_config_dword(mac->iob_pdev,
- PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
+ netif_rx_schedule(dev, &mac->napi);
+ write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
return IRQ_HANDLED;
}
@@ -613,9 +781,7 @@ static irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
if (*mac->tx_status & PAS_STATUS_ERROR)
reg |= PAS_IOB_DMA_TXCH_RESET_DINTC;
- pci_write_config_dword(mac->iob_pdev,
- PAS_IOB_DMA_TXCH_RESET(mac->dma_txch),
- reg);
+ write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg);
return IRQ_HANDLED;
}
@@ -641,7 +807,7 @@ static void pasemi_adjust_link(struct net_device *dev)
} else
netif_carrier_on(dev);
- pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags);
+ flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
new_flags = flags & ~(PAS_MAC_CFG_PCFG_HD | PAS_MAC_CFG_PCFG_SPD_M |
PAS_MAC_CFG_PCFG_TSR_M);
@@ -673,7 +839,7 @@ static void pasemi_adjust_link(struct net_device *dev)
mac->link = mac->phydev->link;
if (new_flags != flags)
- pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, new_flags);
+ write_mac_reg(mac, PAS_MAC_CFG_PCFG, new_flags);
if (msg && netif_msg_link(mac))
printk(KERN_INFO "%s: Link is up at %d Mbps, %s duplex.\n",
@@ -736,39 +902,30 @@ static int pasemi_mac_open(struct net_device *dev)
int ret;
/* enable rx section */
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_RXCMD,
- PAS_DMA_COM_RXCMD_EN);
+ write_dma_reg(mac, PAS_DMA_COM_RXCMD, PAS_DMA_COM_RXCMD_EN);
/* enable tx section */
- pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_TXCMD,
- PAS_DMA_COM_TXCMD_EN);
+ write_dma_reg(mac, PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN);
flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) |
PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) |
PAS_MAC_CFG_TXP_TIFT(8) | PAS_MAC_CFG_TXP_TIFG(12);
- pci_write_config_dword(mac->pdev, PAS_MAC_CFG_TXP, flags);
+ write_mac_reg(mac, PAS_MAC_CFG_TXP, flags);
- flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
- PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
-
- flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
-
- pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
- PAS_IOB_DMA_RXCH_CFG_CNTTH(0));
+ write_iob_reg(mac, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
+ PAS_IOB_DMA_RXCH_CFG_CNTTH(0));
- pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch),
- PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
+ write_iob_reg(mac, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch),
+ PAS_IOB_DMA_TXCH_CFG_CNTTH(128));
/* Clear out any residual packet count state from firmware */
pasemi_mac_restart_rx_intr(mac);
pasemi_mac_restart_tx_intr(mac);
/* 0xffffff is max value, about 16ms */
- pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
- PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff));
-
- pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+ write_iob_reg(mac, PAS_IOB_DMA_COM_TIMEOUTCFG,
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff));
ret = pasemi_mac_setup_rx_resources(dev);
if (ret)
@@ -778,27 +935,48 @@ static int pasemi_mac_open(struct net_device *dev)
if (ret)
goto out_tx_resources;
- pci_write_config_dword(mac->pdev, PAS_MAC_IPC_CHNL,
- PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) |
- PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch));
+ write_mac_reg(mac, PAS_MAC_IPC_CHNL,
+ PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) |
+ PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch));
/* enable rx if */
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
- PAS_DMA_RXINT_RCMDSTA_EN);
+ write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+ PAS_DMA_RXINT_RCMDSTA_EN |
+ PAS_DMA_RXINT_RCMDSTA_DROPS_M |
+ PAS_DMA_RXINT_RCMDSTA_BP |
+ PAS_DMA_RXINT_RCMDSTA_OO |
+ PAS_DMA_RXINT_RCMDSTA_BT);
/* enable rx channel */
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
- PAS_DMA_RXCHAN_CCMDSTA_EN |
- PAS_DMA_RXCHAN_CCMDSTA_DU);
+ write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+ PAS_DMA_RXCHAN_CCMDSTA_EN |
+ PAS_DMA_RXCHAN_CCMDSTA_DU |
+ PAS_DMA_RXCHAN_CCMDSTA_OD |
+ PAS_DMA_RXCHAN_CCMDSTA_FD |
+ PAS_DMA_RXCHAN_CCMDSTA_DT);
/* enable tx channel */
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
- PAS_DMA_TXCHAN_TCMDSTA_EN);
+ write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+ PAS_DMA_TXCHAN_TCMDSTA_EN |
+ PAS_DMA_TXCHAN_TCMDSTA_SZ |
+ PAS_DMA_TXCHAN_TCMDSTA_DB |
+ PAS_DMA_TXCHAN_TCMDSTA_DE |
+ PAS_DMA_TXCHAN_TCMDSTA_DA);
+
+ pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE);
+
+ write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), RX_RING_SIZE>>1);
- pasemi_mac_replenish_rx_ring(dev);
+ flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
+ PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
+
+ if (mac->type == MAC_TYPE_GMAC)
+ flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
+ else
+ flags |= PAS_MAC_CFG_PCFG_TSR_10G | PAS_MAC_CFG_PCFG_SPD_10G;
+
+ /* Enable interface in MAC */
+ write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
ret = pasemi_mac_phy_init(dev);
/* Some configs don't have PHYs (XAUI etc), so don't complain about
@@ -808,7 +986,7 @@ static int pasemi_mac_open(struct net_device *dev)
dev_warn(&mac->pdev->dev, "phy init failed: %d\n", ret);
netif_start_queue(dev);
- netif_poll_enable(dev);
+ napi_enable(&mac->napi);
/* Interrupts are a bit different for our DMA controller: While
* it's got one a regular PCI device header, the interrupt there
@@ -845,7 +1023,7 @@ static int pasemi_mac_open(struct net_device *dev)
out_rx_int:
free_irq(mac->tx_irq, dev);
out_tx_int:
- netif_poll_disable(dev);
+ napi_disable(&mac->napi);
netif_stop_queue(dev);
pasemi_mac_free_tx_resources(dev);
out_tx_resources:
@@ -860,7 +1038,7 @@ out_rx_resources:
static int pasemi_mac_close(struct net_device *dev)
{
struct pasemi_mac *mac = netdev_priv(dev);
- unsigned int stat;
+ unsigned int sta;
int retries;
if (mac->phydev) {
@@ -869,68 +1047,74 @@ static int pasemi_mac_close(struct net_device *dev)
}
netif_stop_queue(dev);
+ napi_disable(&mac->napi);
+
+ sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+ if (sta & (PAS_DMA_RXINT_RCMDSTA_BP |
+ PAS_DMA_RXINT_RCMDSTA_OO |
+ PAS_DMA_RXINT_RCMDSTA_BT))
+ printk(KERN_DEBUG "pasemi_mac: rcmdsta error: 0x%08x\n", sta);
+
+ sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+ if (sta & (PAS_DMA_RXCHAN_CCMDSTA_DU |
+ PAS_DMA_RXCHAN_CCMDSTA_OD |
+ PAS_DMA_RXCHAN_CCMDSTA_FD |
+ PAS_DMA_RXCHAN_CCMDSTA_DT))
+ printk(KERN_DEBUG "pasemi_mac: ccmdsta error: 0x%08x\n", sta);
+
+ sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+ if (sta & (PAS_DMA_TXCHAN_TCMDSTA_SZ |
+ PAS_DMA_TXCHAN_TCMDSTA_DB |
+ PAS_DMA_TXCHAN_TCMDSTA_DE |
+ PAS_DMA_TXCHAN_TCMDSTA_DA))
+ printk(KERN_DEBUG "pasemi_mac: tcmdsta error: 0x%08x\n", sta);
/* Clean out any pending buffers */
pasemi_mac_clean_tx(mac);
pasemi_mac_clean_rx(mac, RX_RING_SIZE);
/* Disable interface */
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
- PAS_DMA_TXCHAN_TCMDSTA_ST);
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
- PAS_DMA_RXINT_RCMDSTA_ST);
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
- PAS_DMA_RXCHAN_CCMDSTA_ST);
+ write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), PAS_DMA_TXCHAN_TCMDSTA_ST);
+ write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), PAS_DMA_RXINT_RCMDSTA_ST);
+ write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), PAS_DMA_RXCHAN_CCMDSTA_ST);
for (retries = 0; retries < MAX_RETRIES; retries++) {
- pci_read_config_dword(mac->dma_pdev,
- PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
- &stat);
- if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT))
+ sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+ if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT))
break;
cond_resched();
}
- if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+ if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)
dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
for (retries = 0; retries < MAX_RETRIES; retries++) {
- pci_read_config_dword(mac->dma_pdev,
- PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
- &stat);
- if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT))
+ sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+ if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT))
break;
cond_resched();
}
- if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+ if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)
dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
for (retries = 0; retries < MAX_RETRIES; retries++) {
- pci_read_config_dword(mac->dma_pdev,
- PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
- &stat);
- if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT))
+ sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+ if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT))
break;
cond_resched();
}
- if (stat & PAS_DMA_RXINT_RCMDSTA_ACT)
+ if (sta & PAS_DMA_RXINT_RCMDSTA_ACT)
dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
/* Then, disable the channel. This must be done separately from
* stopping, since you can't disable when active.
*/
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0);
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0);
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+ write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0);
+ write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0);
+ write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
free_irq(mac->tx_irq, dev);
free_irq(mac->rx_irq, dev);
@@ -946,13 +1130,13 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
{
struct pasemi_mac *mac = netdev_priv(dev);
struct pasemi_mac_txring *txring;
- struct pasemi_mac_buffer *info;
- struct pas_dma_xct_descr *dp;
- u64 dflags;
- dma_addr_t map;
- int flags;
+ u64 dflags, mactx;
+ dma_addr_t map[MAX_SKB_FRAGS+1];
+ unsigned int map_size[MAX_SKB_FRAGS+1];
+ unsigned long flags;
+ int i, nfrags;
- dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD;
+ dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_CRC_PAD;
if (skb->ip_summed == CHECKSUM_PARTIAL) {
const unsigned char *nh = skb_network_header(skb);
@@ -971,71 +1155,87 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
}
}
- map = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+ nfrags = skb_shinfo(skb)->nr_frags;
- if (dma_mapping_error(map))
- return NETDEV_TX_BUSY;
+ map[0] = pci_map_single(mac->dma_pdev, skb->data, skb_headlen(skb),
+ PCI_DMA_TODEVICE);
+ map_size[0] = skb_headlen(skb);
+ if (dma_mapping_error(map[0]))
+ goto out_err_nolock;
+
+ for (i = 0; i < nfrags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ map[i+1] = pci_map_page(mac->dma_pdev, frag->page,
+ frag->page_offset, frag->size,
+ PCI_DMA_TODEVICE);
+ map_size[i+1] = frag->size;
+ if (dma_mapping_error(map[i+1])) {
+ nfrags = i;
+ goto out_err_nolock;
+ }
+ }
+
+ mactx = dflags | XCT_MACTX_LLEN(skb->len);
txring = mac->tx;
spin_lock_irqsave(&txring->lock, flags);
- if (txring->next_to_clean - txring->next_to_use == TX_RING_SIZE) {
- spin_unlock_irqrestore(&txring->lock, flags);
- pasemi_mac_clean_tx(mac);
- pasemi_mac_restart_tx_intr(mac);
- spin_lock_irqsave(&txring->lock, flags);
-
- if (txring->next_to_clean - txring->next_to_use ==
- TX_RING_SIZE) {
- /* Still no room -- stop the queue and wait for tx
- * intr when there's room.
- */
- netif_stop_queue(dev);
- goto out_err;
- }
+ /* Avoid stepping on the same cache line that the DMA controller
+ * is currently about to send, so leave at least 8 words available.
+ * Total free space needed is mactx + fragments + 8
+ */
+ if (RING_AVAIL(txring) < nfrags + 10) {
+ /* no room -- stop the queue and wait for tx intr */
+ netif_stop_queue(dev);
+ goto out_err;
}
+ TX_RING(mac, txring->next_to_fill) = mactx;
+ txring->next_to_fill++;
+ TX_RING_INFO(mac, txring->next_to_fill).skb = skb;
+ for (i = 0; i <= nfrags; i++) {
+ TX_RING(mac, txring->next_to_fill+i) =
+ XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]);
+ TX_RING_INFO(mac, txring->next_to_fill+i).dma = map[i];
+ }
- dp = &TX_DESC(mac, txring->next_to_use);
- info = &TX_DESC_INFO(mac, txring->next_to_use);
+ /* We have to add an even number of 8-byte entries to the ring
+ * even if the last one is unused. That means always an odd number
+ * of pointers + one mactx descriptor.
+ */
+ if (nfrags & 1)
+ nfrags++;
- dp->mactx = dflags | XCT_MACTX_LLEN(skb->len);
- dp->ptr = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map);
- info->dma = map;
- info->skb = skb;
+ txring->next_to_fill = (txring->next_to_fill + nfrags + 1) &
+ (TX_RING_SIZE-1);
- txring->next_to_use++;
- mac->stats.tx_packets++;
- mac->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
spin_unlock_irqrestore(&txring->lock, flags);
- pci_write_config_dword(mac->dma_pdev,
- PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1);
+ write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), (nfrags+2) >> 1);
return NETDEV_TX_OK;
out_err:
spin_unlock_irqrestore(&txring->lock, flags);
- pci_unmap_single(mac->dma_pdev, map, skb->len, PCI_DMA_TODEVICE);
- return NETDEV_TX_BUSY;
-}
+out_err_nolock:
+ while (nfrags--)
+ pci_unmap_single(mac->dma_pdev, map[nfrags], map_size[nfrags],
+ PCI_DMA_TODEVICE);
-static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev)
-{
- struct pasemi_mac *mac = netdev_priv(dev);
-
- return &mac->stats;
+ return NETDEV_TX_BUSY;
}
-
static void pasemi_mac_set_rx_mode(struct net_device *dev)
{
struct pasemi_mac *mac = netdev_priv(dev);
unsigned int flags;
- pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags);
+ flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
/* Set promiscuous */
if (dev->flags & IFF_PROMISC)
@@ -1043,30 +1243,92 @@ static void pasemi_mac_set_rx_mode(struct net_device *dev)
else
flags &= ~PAS_MAC_CFG_PCFG_PR;
- pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+ write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
}
-static int pasemi_mac_poll(struct net_device *dev, int *budget)
+static int pasemi_mac_poll(struct napi_struct *napi, int budget)
{
- int pkts, limit = min(*budget, dev->quota);
- struct pasemi_mac *mac = netdev_priv(dev);
-
- pkts = pasemi_mac_clean_rx(mac, limit);
-
- dev->quota -= pkts;
- *budget -= pkts;
+ struct pasemi_mac *mac = container_of(napi, struct pasemi_mac, napi);
+ struct net_device *dev = mac->netdev;
+ int pkts;
- if (pkts < limit) {
+ pasemi_mac_clean_tx(mac);
+ pkts = pasemi_mac_clean_rx(mac, budget);
+ if (pkts < budget) {
/* all done, no more packets present */
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
pasemi_mac_restart_rx_intr(mac);
- return 0;
- } else {
- /* used up our quantum, so reschedule */
- return 1;
}
+ return pkts;
+}
+
+static void __iomem * __devinit map_onedev(struct pci_dev *p, int index)
+{
+ struct device_node *dn;
+ void __iomem *ret;
+
+ dn = pci_device_to_OF_node(p);
+ if (!dn)
+ goto fallback;
+
+ ret = of_iomap(dn, index);
+ if (!ret)
+ goto fallback;
+
+ return ret;
+fallback:
+ /* This is hardcoded and ugly, but we have some firmware versions
+ * that don't provide the register space in the device tree. Luckily
+ * they are at well-known locations so we can just do the math here.
+ */
+ return ioremap(0xe0000000 + (p->devfn << 12), 0x2000);
+}
+
+static int __devinit pasemi_mac_map_regs(struct pasemi_mac *mac)
+{
+ struct resource res;
+ struct device_node *dn;
+ int err;
+
+ mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
+ if (!mac->dma_pdev) {
+ dev_err(&mac->pdev->dev, "Can't find DMA Controller\n");
+ return -ENODEV;
+ }
+
+ mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
+ if (!mac->iob_pdev) {
+ dev_err(&mac->pdev->dev, "Can't find I/O Bridge\n");
+ return -ENODEV;
+ }
+
+ mac->regs = map_onedev(mac->pdev, 0);
+ mac->dma_regs = map_onedev(mac->dma_pdev, 0);
+ mac->iob_regs = map_onedev(mac->iob_pdev, 0);
+
+ if (!mac->regs || !mac->dma_regs || !mac->iob_regs) {
+ dev_err(&mac->pdev->dev, "Can't map registers\n");
+ return -ENODEV;
+ }
+
+ /* The dma status structure is located in the I/O bridge, and
+ * is cache coherent.
+ */
+ if (!dma_status) {
+ dn = pci_device_to_OF_node(mac->iob_pdev);
+ if (dn)
+ err = of_address_to_resource(dn, 1, &res);
+ if (!dn || err) {
+ /* Fallback for old firmware */
+ res.start = 0xfd800000;
+ res.end = res.start + 0x1000;
+ }
+ dma_status = __ioremap(res.start, res.end-res.start, 0);
+ }
+
+ return 0;
}
static int __devinit
@@ -1076,6 +1338,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct net_device *dev;
struct pasemi_mac *mac;
int err;
+ DECLARE_MAC_BUF(mac_buf);
err = pci_enable_device(pdev);
if (err)
@@ -1089,7 +1352,6 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_disable_device;
}
- SET_MODULE_OWNER(dev);
pci_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -1097,21 +1359,10 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
mac->pdev = pdev;
mac->netdev = dev;
- mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
- if (!mac->dma_pdev) {
- dev_err(&pdev->dev, "Can't find DMA Controller\n");
- err = -ENODEV;
- goto out_free_netdev;
- }
+ netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64);
- mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
-
- if (!mac->iob_pdev) {
- dev_err(&pdev->dev, "Can't find I/O Bridge\n");
- err = -ENODEV;
- goto out_put_dma_pdev;
- }
+ dev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX | NETIF_F_SG;
/* These should come out of the device tree eventually */
mac->dma_txch = index;
@@ -1148,18 +1399,11 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->open = pasemi_mac_open;
dev->stop = pasemi_mac_close;
dev->hard_start_xmit = pasemi_mac_start_tx;
- dev->get_stats = pasemi_mac_get_stats;
dev->set_multicast_list = pasemi_mac_set_rx_mode;
- dev->weight = 64;
- dev->poll = pasemi_mac_poll;
- dev->features = NETIF_F_HW_CSUM;
- /* The dma status structure is located in the I/O bridge, and
- * is cache coherent.
- */
- if (!dma_status)
- /* XXXOJN This should come from the device tree */
- dma_status = __ioremap(0xfd800000, 0x1000, 0);
+ err = pasemi_mac_map_regs(mac);
+ if (err)
+ goto out;
mac->rx_status = &dma_status->rx_sta[mac->dma_rxch];
mac->tx_status = &dma_status->tx_sta[mac->dma_txch];
@@ -1175,21 +1419,27 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n",
err);
goto out;
- } else
+ } else if netif_msg_probe(mac)
printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, "
- "hw addr %02x:%02x:%02x:%02x:%02x:%02x\n",
+ "hw addr %s\n",
dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI",
mac->dma_if, mac->dma_txch, mac->dma_rxch,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ print_mac(mac_buf, dev->dev_addr));
return err;
out:
- pci_dev_put(mac->iob_pdev);
-out_put_dma_pdev:
- pci_dev_put(mac->dma_pdev);
-out_free_netdev:
+ if (mac->iob_pdev)
+ pci_dev_put(mac->iob_pdev);
+ if (mac->dma_pdev)
+ pci_dev_put(mac->dma_pdev);
+ if (mac->dma_regs)
+ iounmap(mac->dma_regs);
+ if (mac->iob_regs)
+ iounmap(mac->iob_regs);
+ if (mac->regs)
+ iounmap(mac->regs);
+
free_netdev(dev);
out_disable_device:
pci_disable_device(pdev);
@@ -1213,6 +1463,10 @@ static void __devexit pasemi_mac_remove(struct pci_dev *pdev)
pci_dev_put(mac->dma_pdev);
pci_dev_put(mac->iob_pdev);
+ iounmap(mac->regs);
+ iounmap(mac->dma_regs);
+ iounmap(mac->iob_regs);
+
pci_set_drvdata(pdev, NULL);
free_netdev(netdev);
}
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h
index c29ee159c33..60368df7263 100644
--- a/drivers/net/pasemi_mac.h
+++ b/drivers/net/pasemi_mac.h
@@ -28,35 +28,38 @@
struct pasemi_mac_txring {
spinlock_t lock;
- struct pas_dma_xct_descr *desc;
+ u64 *ring;
dma_addr_t dma;
unsigned int size;
- unsigned int next_to_use;
+ unsigned int next_to_fill;
unsigned int next_to_clean;
- struct pasemi_mac_buffer *desc_info;
+ struct pasemi_mac_buffer *ring_info;
char irq_name[10]; /* "eth%d tx" */
};
struct pasemi_mac_rxring {
spinlock_t lock;
- struct pas_dma_xct_descr *desc; /* RX channel descriptor ring */
+ u64 *ring; /* RX channel descriptor ring */
dma_addr_t dma;
u64 *buffers; /* RX interface buffer ring */
dma_addr_t buf_dma;
unsigned int size;
unsigned int next_to_fill;
unsigned int next_to_clean;
- struct pasemi_mac_buffer *desc_info;
+ struct pasemi_mac_buffer *ring_info;
char irq_name[10]; /* "eth%d rx" */
};
struct pasemi_mac {
struct net_device *netdev;
+ void __iomem *regs;
+ void __iomem *dma_regs;
+ void __iomem *iob_regs;
struct pci_dev *pdev;
struct pci_dev *dma_pdev;
struct pci_dev *iob_pdev;
struct phy_device *phydev;
- struct net_device_stats stats;
+ struct napi_struct napi;
/* Pointer to the cacheable per-channel status registers */
u64 *rx_status;
@@ -85,7 +88,7 @@ struct pasemi_mac {
char phy_id[BUS_ID_SIZE];
};
-/* Software status descriptor (desc_info) */
+/* Software status descriptor (ring_info) */
struct pasemi_mac_buffer {
struct sk_buff *skb;
dma_addr_t dma;
@@ -98,20 +101,7 @@ struct pasdma_status {
u64 tx_sta[20];
};
-/* descriptor structure */
-struct pas_dma_xct_descr {
- union {
- u64 mactx;
- u64 macrx;
- };
- union {
- u64 ptr;
- u64 rxb;
- };
-};
-
/* MAC CFG register offsets */
-
enum {
PAS_MAC_CFG_PCFG = 0x80,
PAS_MAC_CFG_TXP = 0x98,
@@ -215,6 +205,20 @@ enum {
#define PAS_DMA_RXINT_RCMDSTA_ACT 0x00010000
#define PAS_DMA_RXINT_RCMDSTA_DROPS_M 0xfffe0000
#define PAS_DMA_RXINT_RCMDSTA_DROPS_S 17
+#define PAS_DMA_RXINT_CFG(i) (0x204+(i)*_PAS_DMA_RXINT_STRIDE)
+#define PAS_DMA_RXINT_CFG_RBP 0x80000000
+#define PAS_DMA_RXINT_CFG_ITRR 0x40000000
+#define PAS_DMA_RXINT_CFG_DHL_M 0x07000000
+#define PAS_DMA_RXINT_CFG_DHL_S 24
+#define PAS_DMA_RXINT_CFG_DHL(x) (((x) << PAS_DMA_RXINT_CFG_DHL_S) & \
+ PAS_DMA_RXINT_CFG_DHL_M)
+#define PAS_DMA_RXINT_CFG_ITR 0x00400000
+#define PAS_DMA_RXINT_CFG_LW 0x00200000
+#define PAS_DMA_RXINT_CFG_L2 0x00100000
+#define PAS_DMA_RXINT_CFG_HEN 0x00080000
+#define PAS_DMA_RXINT_CFG_WIF 0x00000002
+#define PAS_DMA_RXINT_CFG_WIL 0x00000001
+
#define PAS_DMA_RXINT_INCR(i) (0x210+(i)*_PAS_DMA_RXINT_STRIDE)
#define PAS_DMA_RXINT_INCR_INCR_M 0x0000ffff
#define PAS_DMA_RXINT_INCR_INCR_S 0
@@ -241,6 +245,10 @@ enum {
#define PAS_DMA_TXCHAN_TCMDSTA_EN 0x00000001 /* Enabled */
#define PAS_DMA_TXCHAN_TCMDSTA_ST 0x00000002 /* Stop interface */
#define PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000 /* Active */
+#define PAS_DMA_TXCHAN_TCMDSTA_SZ 0x00000800
+#define PAS_DMA_TXCHAN_TCMDSTA_DB 0x00000400
+#define PAS_DMA_TXCHAN_TCMDSTA_DE 0x00000200
+#define PAS_DMA_TXCHAN_TCMDSTA_DA 0x00000100
#define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE)
#define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */
#define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c
@@ -251,9 +259,11 @@ enum {
#define PAS_DMA_TXCHAN_CFG_WT_S 6
#define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \
PAS_DMA_TXCHAN_CFG_WT_M)
-#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */
-#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */
+#define PAS_DMA_TXCHAN_CFG_TRD 0x00010000 /* translate data */
+#define PAS_DMA_TXCHAN_CFG_TRR 0x00008000 /* translate rings */
#define PAS_DMA_TXCHAN_CFG_UP 0x00004000 /* update tx descr when sent */
+#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */
+#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */
#define PAS_DMA_TXCHAN_INCR(c) (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE)
#define PAS_DMA_TXCHAN_BASEL(c) (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE)
#define PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0
@@ -283,7 +293,11 @@ enum {
#define PAS_DMA_RXCHAN_CCMDSTA_ST 0x00000002 /* Stop interface */
#define PAS_DMA_RXCHAN_CCMDSTA_ACT 0x00010000 /* Active */
#define PAS_DMA_RXCHAN_CCMDSTA_DU 0x00020000
+#define PAS_DMA_RXCHAN_CCMDSTA_OD 0x00002000
+#define PAS_DMA_RXCHAN_CCMDSTA_FD 0x00001000
+#define PAS_DMA_RXCHAN_CCMDSTA_DT 0x00000800
#define PAS_DMA_RXCHAN_CFG(c) (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_CFG_CTR 0x00000400
#define PAS_DMA_RXCHAN_CFG_HBU_M 0x00000380
#define PAS_DMA_RXCHAN_CFG_HBU_S 7
#define PAS_DMA_RXCHAN_CFG_HBU(x) (((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \
@@ -317,6 +331,12 @@ enum {
#define PAS_STATUS_SOFT 0x4000000000000000ull
#define PAS_STATUS_INT 0x8000000000000000ull
+#define PAS_IOB_COM_PKTHDRCNT 0x120
+#define PAS_IOB_COM_PKTHDRCNT_PKTHDR1_M 0x0fff0000
+#define PAS_IOB_COM_PKTHDRCNT_PKTHDR1_S 16
+#define PAS_IOB_COM_PKTHDRCNT_PKTHDR0_M 0x00000fff
+#define PAS_IOB_COM_PKTHDRCNT_PKTHDR0_S 0
+
#define PAS_IOB_DMA_RXCH_CFG(i) (0x1100 + (i)*4)
#define PAS_IOB_DMA_RXCH_CFG_CNTTH_M 0x00000fff
#define PAS_IOB_DMA_RXCH_CFG_CNTTH_S 0
@@ -412,10 +432,9 @@ enum {
/* Receive descriptor fields */
#define XCT_MACRX_T 0x8000000000000000ull
#define XCT_MACRX_ST 0x4000000000000000ull
-#define XCT_MACRX_NORES 0x0000000000000000ull
-#define XCT_MACRX_8BRES 0x1000000000000000ull
-#define XCT_MACRX_24BRES 0x2000000000000000ull
-#define XCT_MACRX_40BRES 0x3000000000000000ull
+#define XCT_MACRX_RR_M 0x3000000000000000ull
+#define XCT_MACRX_RR_NORES 0x0000000000000000ull
+#define XCT_MACRX_RR_8BRES 0x1000000000000000ull
#define XCT_MACRX_O 0x0400000000000000ull
#define XCT_MACRX_E 0x0200000000000000ull
#define XCT_MACRX_FF 0x0100000000000000ull
@@ -463,6 +482,17 @@ enum {
#define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \
XCT_PTR_ADDR_M)
+/* Receive interface 8byte result fields */
+#define XCT_RXRES_8B_L4O_M 0xff00000000000000ull
+#define XCT_RXRES_8B_L4O_S 56
+#define XCT_RXRES_8B_RULE_M 0x00ffff0000000000ull
+#define XCT_RXRES_8B_RULE_S 40
+#define XCT_RXRES_8B_EVAL_M 0x000000ffff000000ull
+#define XCT_RXRES_8B_EVAL_S 24
+#define XCT_RXRES_8B_HTYPE_M 0x0000000000f00000ull
+#define XCT_RXRES_8B_HASH_M 0x00000000000fffffull
+#define XCT_RXRES_8B_HASH_S 0
+
/* Receive interface buffer fields */
#define XCT_RXB_LEN_M 0x0ffff00000000000ull
#define XCT_RXB_LEN_S 44
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 3cdbe118200..ed402e00e73 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -457,7 +457,6 @@ struct netdrv_private {
void *mmio_addr;
int drv_flags;
struct pci_dev *pci_dev;
- struct net_device_stats stats;
struct timer_list timer; /* Media selection timer. */
unsigned char *rx_ring;
unsigned int cur_rx; /* Index into the Rx buffer of next Rx pkt. */
@@ -505,7 +504,6 @@ static int netdrv_start_xmit (struct sk_buff *skb,
static irqreturn_t netdrv_interrupt (int irq, void *dev_instance);
static int netdrv_close (struct net_device *dev);
static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *netdrv_get_stats (struct net_device *dev);
static void netdrv_set_rx_mode (struct net_device *dev);
static void netdrv_hw_start (struct net_device *dev);
@@ -604,7 +602,6 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
DPRINTK ("EXIT, returning -ENOMEM\n");
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
tp = dev->priv;
@@ -740,6 +737,7 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
int i, addr_len, option;
void *ioaddr = NULL;
static int board_idx = -1;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -776,7 +774,6 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
dev->open = netdrv_open;
dev->hard_start_xmit = netdrv_start_xmit;
dev->stop = netdrv_close;
- dev->get_stats = netdrv_get_stats;
dev->set_multicast_list = netdrv_set_rx_mode;
dev->do_ioctl = netdrv_ioctl;
dev->tx_timeout = netdrv_tx_timeout;
@@ -800,15 +797,11 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev,
tp->phys[0] = 32;
- printk (KERN_INFO "%s: %s at 0x%lx, "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
- "IRQ %d\n",
+ printk (KERN_INFO "%s: %s at 0x%lx, %sIRQ %d\n",
dev->name,
board_info[ent->driver_data].name,
dev->base_addr,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5],
+ print_mac(mac, dev->dev_addr),
dev->irq);
printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n",
@@ -1277,7 +1270,7 @@ static void netdrv_tx_clear (struct netdrv_private *tp)
if (rp->skb) {
dev_kfree_skb (rp->skb);
rp->skb = NULL;
- tp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
}
}
}
@@ -1390,25 +1383,25 @@ static void netdrv_tx_interrupt (struct net_device *dev,
/* There was an major error, log it. */
DPRINTK ("%s: Transmit error, Tx status %8.8x.\n",
dev->name, txstatus);
- tp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (txstatus & TxAborted) {
- tp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
NETDRV_W32 (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift));
}
if (txstatus & TxCarrierLost)
- tp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (txstatus & TxOutOfWindow)
- tp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
} else {
if (txstatus & TxUnderrun) {
/* Add 64 to the Tx FIFO threshold. */
if (tp->tx_flag < 0x00300000)
tp->tx_flag += 0x00020000;
- tp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
}
- tp->stats.collisions += (txstatus >> 24) & 15;
- tp->stats.tx_bytes += txstatus & 0x7ff;
- tp->stats.tx_packets++;
+ dev->stats.collisions += (txstatus >> 24) & 15;
+ dev->stats.tx_bytes += txstatus & 0x7ff;
+ dev->stats.tx_packets++;
}
/* Free the original skb. */
@@ -1461,13 +1454,13 @@ static void netdrv_rx_err (u32 rx_status, struct net_device *dev,
dev->name, rx_status);
/* A.C.: The chip hangs here. */
}
- tp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rx_status & (RxBadSymbol | RxBadAlign))
- tp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rx_status & (RxRunt | RxTooLong))
- tp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rx_status & RxCRCErr)
- tp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
/* Reset the receiver, based on RealTek recommendation. (Bug?) */
tp->cur_rx = 0;
@@ -1573,13 +1566,13 @@ static void netdrv_rx_interrupt (struct net_device *dev,
skb->protocol = eth_type_trans (skb, dev);
netif_rx (skb);
dev->last_rx = jiffies;
- tp->stats.rx_bytes += pkt_size;
- tp->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_size;
+ dev->stats.rx_packets++;
} else {
printk (KERN_WARNING
"%s: Memory squeeze, dropping packet.\n",
dev->name);
- tp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
@@ -1608,7 +1601,7 @@ static void netdrv_weird_interrupt (struct net_device *dev,
assert (ioaddr != NULL);
/* Update the error count. */
- tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
+ dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
NETDRV_W32 (RxMissed, 0);
if ((status & RxUnderrun) && link_changed &&
@@ -1629,14 +1622,14 @@ static void netdrv_weird_interrupt (struct net_device *dev,
/* XXX along with netdrv_rx_err, are we double-counting errors? */
if (status &
(RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
- tp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (status & (PCSTimeout))
- tp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (status & (RxUnderrun | RxFIFOOver))
- tp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (status & RxOverflow) {
- tp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
tp->cur_rx = NETDRV_R16 (RxBufAddr) % RX_BUF_LEN;
NETDRV_W16_F (RxBufPtr, tp->cur_rx - 16);
}
@@ -1740,7 +1733,7 @@ static int netdrv_close (struct net_device *dev)
NETDRV_W16 (IntrMask, 0x0000);
/* Update the error counts. */
- tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
+ dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
NETDRV_W32 (RxMissed, 0);
spin_unlock_irqrestore (&tp->lock, flags);
@@ -1807,31 +1800,6 @@ static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
return rc;
}
-
-static struct net_device_stats *netdrv_get_stats (struct net_device *dev)
-{
- struct netdrv_private *tp = dev->priv;
- void *ioaddr = tp->mmio_addr;
-
- DPRINTK ("ENTER\n");
-
- assert (tp != NULL);
-
- if (netif_running(dev)) {
- unsigned long flags;
-
- spin_lock_irqsave (&tp->lock, flags);
-
- tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
- NETDRV_W32 (RxMissed, 0);
-
- spin_unlock_irqrestore (&tp->lock, flags);
- }
-
- DPRINTK ("EXIT\n");
- return &tp->stats;
-}
-
/* Set or clear the multicast filter for this adaptor.
This routine is not state sensitive and need not be SMP locked. */
@@ -1909,7 +1877,7 @@ static int netdrv_suspend (struct pci_dev *pdev, pm_message_t state)
NETDRV_W8 (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear));
/* Update the error counts. */
- tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
+ dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
NETDRV_W32 (RxMissed, 0);
spin_unlock_irqrestore (&tp->lock, flags);
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 2b395ee21f7..ad134a61302 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -274,7 +274,7 @@ static int tc574_probe(struct pcmcia_device *link)
spin_lock_init(&lp->window_lock);
link->io.NumPorts1 = 32;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = &el3_interrupt;
link->irq.Instance = dev;
@@ -343,6 +343,7 @@ static int tc574_config(struct pcmcia_device *link)
u16 *phys_addr;
char *cardname;
union wn3_config config;
+ DECLARE_MAC_BUF(mac);
phys_addr = (u16 *)dev->dev_addr;
@@ -458,10 +459,10 @@ static int tc574_config(struct pcmcia_device *link)
strcpy(lp->node.dev_name, dev->name);
- printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ",
- dev->name, cardname, dev->base_addr, dev->irq);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n"));
+ printk(KERN_INFO "%s: %s at io %#3lx, irq %d, "
+ "hw_addr %s.\n",
+ dev->name, cardname, dev->base_addr, dev->irq,
+ print_mac(mac, dev->dev_addr));
printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",
8 << config.u.ram_size, ram_split[config.u.ram_split],
config.u.autoselect ? "autoselect " : "");
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 503f2685fb7..a98fe07cce7 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -188,7 +188,7 @@ static int tc589_probe(struct pcmcia_device *link)
spin_lock_init(&lp->lock);
link->io.NumPorts1 = 16;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = &el3_interrupt;
link->irq.Instance = dev;
@@ -197,7 +197,6 @@ static int tc589_probe(struct pcmcia_device *link)
link->conf.ConfigIndex = 1;
/* The EL3-specific entries in the device structure. */
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = &el3_start_xmit;
dev->set_config = &el3_config;
dev->get_stats = &el3_get_stats;
@@ -256,6 +255,7 @@ static int tc589_config(struct pcmcia_device *link)
int last_fn, last_ret, i, j, multi = 0, fifo;
kio_addr_t ioaddr;
char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "3c589_config(0x%p)\n", link);
@@ -331,11 +331,10 @@ static int tc589_config(struct pcmcia_device *link)
strcpy(lp->node.dev_name, dev->name);
- printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, hw_addr ",
- dev->name, (multi ? "562" : "589"), dev->base_addr,
- dev->irq);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, "
+ "hw_addr %s\n",
+ dev->name, (multi ? "562" : "589"), dev->base_addr, dev->irq,
+ print_mac(mac, dev->dev_addr));
printk(KERN_INFO " %dK FIFO split %s Rx:Tx, %s xcvr\n",
(fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
if_names[dev->if_port]);
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 50dff1b81d3..8d910a372f8 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -158,7 +158,7 @@ static int axnet_probe(struct pcmcia_device *link)
info = PRIV(dev);
info->p_dev = link;
link->priv = dev;
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -232,7 +232,7 @@ static int get_prom(struct pcmcia_device *link)
axnet_reset_8390(dev);
mdelay(10);
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
for (i = 0; i < 6; i += 2) {
@@ -292,6 +292,7 @@ static int axnet_config(struct pcmcia_device *link)
cisparse_t parse;
int i, j, last_ret, last_fn;
u_short buf[64];
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "axnet_config(0x%p)\n", link);
@@ -403,11 +404,11 @@ static int axnet_config(struct pcmcia_device *link)
strcpy(info->node.dev_name, dev->name);
- printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, hw_addr ",
+ printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, "
+ "hw_addr %s\n",
dev->name, ((info->flags & IS_AX88790) ? 7 : 1),
- dev->base_addr, dev->irq);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ dev->base_addr, dev->irq,
+ print_mac(mac, dev->dev_addr));
if (info->phy_id != -1) {
DEBUG(0, " MII transceiver at index %d, status %x.\n", info->phy_id, j);
} else {
@@ -771,6 +772,7 @@ static struct pcmcia_device_id axnet_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202),
+ PCMCIA_DEVICE_MANF_CARD(0xffff, 0x1090),
PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc),
PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
@@ -1728,9 +1730,6 @@ static void axdev_setup(struct net_device *dev)
if (ei_debug > 1)
printk(version_8390);
- SET_MODULE_OWNER(dev);
-
-
ei_local = (struct ei_device *)netdev_priv(dev);
spin_lock_init(&ei_local->page_lock);
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 85d5f2ca4bb..8c719b4df54 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -249,7 +249,7 @@ static int fmvj18x_probe(struct pcmcia_device *link)
link->io.IOAddrLines = 5;
/* Interrupt setup */
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = &fjn_interrupt;
link->irq.Instance = dev;
@@ -259,7 +259,6 @@ static int fmvj18x_probe(struct pcmcia_device *link)
link->conf.IntType = INT_MEMORY_AND_IO;
/* The FMVJ18x specific entries in the device structure. */
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = &fjn_start_xmit;
dev->set_config = &fjn_config;
dev->get_stats = &fjn_get_stats;
@@ -347,6 +346,7 @@ static int fmvj18x_config(struct pcmcia_device *link)
cardtype_t cardtype;
char *card_name = "unknown";
u_char *node_id;
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "fmvj18x_config(0x%p)\n", link);
@@ -534,11 +534,10 @@ static int fmvj18x_config(struct pcmcia_device *link)
strcpy(lp->node.dev_name, dev->name);
/* print current configuration */
- printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, hw_addr ",
+ printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, "
+ "hw_addr %s\n",
dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2",
- dev->base_addr, dev->irq);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr));
return 0;
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 997c2d0c83b..a355a93b908 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -474,7 +474,6 @@ static int nmclan_probe(struct pcmcia_device *link)
lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = &mace_start_xmit;
dev->set_config = &mace_config;
dev->get_stats = &mace_get_stats;
@@ -659,6 +658,7 @@ static int nmclan_config(struct pcmcia_device *link)
u_char buf[64];
int i, last_ret, last_fn;
kio_addr_t ioaddr;
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "nmclan_config(0x%p)\n", link);
@@ -717,10 +717,10 @@ static int nmclan_config(struct pcmcia_device *link)
strcpy(lp->node.dev_name, dev->name);
- printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port, hw_addr ",
- dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port,"
+ " hw_addr %s\n",
+ dev->name, dev->base_addr, dev->irq, if_names[dev->if_port],
+ print_mac(mac, dev->dev_addr));
return 0;
cs_failed:
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 63de89e93b7..db6a97d1d7b 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -38,7 +38,7 @@
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/netdevice.h>
-#include <../drivers/net/8390.h>
+#include "../8390.h"
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
@@ -207,7 +207,7 @@ static hw_info_t hw_info[] = {
{ /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 }
};
-#define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t))
+#define NR_INFO ARRAY_SIZE(hw_info)
static hw_info_t default_info = { 0, 0, 0, 0, 0 };
static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII };
@@ -254,12 +254,11 @@ static int pcnet_probe(struct pcmcia_device *link)
info->p_dev = link;
link->priv = dev;
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
- SET_MODULE_OWNER(dev);
dev->open = &pcnet_open;
dev->stop = &pcnet_close;
dev->set_config = &set_config;
@@ -375,7 +374,7 @@ static hw_info_t *get_prom(struct pcmcia_device *link)
pcnet_reset_8390(dev);
mdelay(10);
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++)
outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
for (i = 0; i < 32; i++)
@@ -522,6 +521,7 @@ static int pcnet_config(struct pcmcia_device *link)
int has_shmem = 0;
u_short buf[64];
hw_info_t *hw_info;
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "pcnet_config(0x%p)\n", link);
@@ -671,9 +671,7 @@ static int pcnet_config(struct pcmcia_device *link)
printk (" mem %#5lx,", dev->mem_start);
if (info->flags & HAS_MISC_REG)
printk(" %s xcvr,", if_names[dev->if_port]);
- printk(" hw_addr ");
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ printk(" hw_addr %s\n", print_mac(mac, dev->dev_addr));
return 0;
cs_failed:
@@ -1664,6 +1662,7 @@ static struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDF", 0x1b7827b2, 0xfec71e40),
PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDL/T", 0x1b7827b2, 0x79fba4f7),
PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDS", 0x1b7827b2, 0x931afaab),
+ PCMCIA_DEVICE_PROD_ID12("LEMEL", "LM-N89TX PRO", 0xbbefb52f, 0xd2897a97),
PCMCIA_DEVICE_PROD_ID12("Linksys", "Combo PCMCIA EthernetCard (EC2T)", 0x0733cc81, 0x32ee8c78),
PCMCIA_DEVICE_PROD_ID12("LINKSYS", "E-CARD", 0xf7cb0b07, 0x6701da11),
PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 Integrated PC Card (PCM100)", 0x0733cc81, 0x453c3f9d),
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index af6728cb49c..c9868e9dac4 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -328,7 +328,7 @@ static int smc91c92_probe(struct pcmcia_device *link)
link->io.NumPorts1 = 16;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
link->io.IOAddrLines = 4;
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = &smc_interrupt;
link->irq.Instance = dev;
@@ -336,7 +336,6 @@ static int smc91c92_probe(struct pcmcia_device *link)
link->conf.IntType = INT_MEMORY_AND_IO;
/* The SMC91c92-specific entries in the device structure. */
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = &smc_start_xmit;
dev->get_stats = &smc_get_stats;
dev->set_config = &s9k_config;
@@ -963,6 +962,7 @@ static int smc91c92_config(struct pcmcia_device *link)
int i, j, rev;
kio_addr_t ioaddr;
u_long mir;
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "smc91c92_config(0x%p)\n", link);
@@ -1075,10 +1075,9 @@ static int smc91c92_config(struct pcmcia_device *link)
strcpy(smc->node.dev_name, dev->name);
printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
- "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr,
- dev->irq);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ "hw_addr %s\n",
+ dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq,
+ print_mac(mac, dev->dev_addr));
if (rev > 0) {
if (mir & 0x3ff)
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 258d6f39618..1f09bea6db5 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -580,7 +580,6 @@ xirc2ps_probe(struct pcmcia_device *link)
link->irq.Instance = dev;
/* Fill in card specific entries */
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = &do_start_xmit;
dev->set_config = &do_config;
dev->get_stats = &do_get_stats;
@@ -732,6 +731,7 @@ xirc2ps_config(struct pcmcia_device * link)
u_char buf[64];
cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data;
cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+ DECLARE_MAC_BUF(mac);
local->dingo_ccr = NULL;
@@ -886,7 +886,7 @@ xirc2ps_config(struct pcmcia_device * link)
}
printk(KNOT_XIRC "no ports available\n");
} else {
- link->irq.Attributes |= IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes |= IRQ_TYPE_DYNAMIC_SHARING;
link->io.NumPorts1 = 16;
for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
link->io.BasePort1 = ioaddr;
@@ -1033,11 +1033,9 @@ xirc2ps_config(struct pcmcia_device * link)
strcpy(local->node.dev_name, dev->name);
/* give some infos about the hardware */
- printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr",
- dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq);
- for (i = 0; i < 6; i++)
- printk("%c%02X", i?':':' ', dev->dev_addr[i]);
- printk("\n");
+ printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr %s\n",
+ dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq,
+ print_mac(mac, dev->dev_addr));
return 0;
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index e6a67531de9..ff92aca0a7b 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -23,11 +23,11 @@
#define DRV_NAME "pcnet32"
#ifdef CONFIG_PCNET32_NAPI
-#define DRV_VERSION "1.33-NAPI"
+#define DRV_VERSION "1.34-NAPI"
#else
-#define DRV_VERSION "1.33"
+#define DRV_VERSION "1.34"
#endif
-#define DRV_RELDATE "27.Jun.2006"
+#define DRV_RELDATE "14.Aug.2007"
#define PFX DRV_NAME ": "
static const char *const version =
@@ -210,31 +210,31 @@ static int homepna[MAX_UNITS];
/* The PCNET32 Rx and Tx ring descriptors. */
struct pcnet32_rx_head {
- u32 base;
- s16 buf_length; /* two`s complement of length */
- s16 status;
- u32 msg_length;
- u32 reserved;
+ __le32 base;
+ __le16 buf_length; /* two`s complement of length */
+ __le16 status;
+ __le32 msg_length;
+ __le32 reserved;
};
struct pcnet32_tx_head {
- u32 base;
- s16 length; /* two`s complement of length */
- s16 status;
- u32 misc;
- u32 reserved;
+ __le32 base;
+ __le16 length; /* two`s complement of length */
+ __le16 status;
+ __le32 misc;
+ __le32 reserved;
};
/* The PCNET32 32-Bit initialization block, described in databook. */
struct pcnet32_init_block {
- u16 mode;
- u16 tlen_rlen;
+ __le16 mode;
+ __le16 tlen_rlen;
u8 phys_addr[6];
- u16 reserved;
- u32 filter[2];
+ __le16 reserved;
+ __le32 filter[2];
/* Receive and transmit ring base, along with extra bits. */
- u32 rx_ring;
- u32 tx_ring;
+ __le32 rx_ring;
+ __le32 tx_ring;
};
/* PCnet32 access functions */
@@ -280,7 +280,8 @@ struct pcnet32_private {
unsigned int dirty_rx, /* ring entries to be freed. */
dirty_tx;
- struct net_device_stats stats;
+ struct net_device *dev;
+ struct napi_struct napi;
char tx_full;
char phycount; /* number of phys found */
int options;
@@ -440,15 +441,25 @@ static struct pcnet32_access pcnet32_dwio = {
static void pcnet32_netif_stop(struct net_device *dev)
{
+#ifdef CONFIG_PCNET32_NAPI
+ struct pcnet32_private *lp = netdev_priv(dev);
+#endif
dev->trans_start = jiffies;
- netif_poll_disable(dev);
+#ifdef CONFIG_PCNET32_NAPI
+ napi_disable(&lp->napi);
+#endif
netif_tx_disable(dev);
}
static void pcnet32_netif_start(struct net_device *dev)
{
+#ifdef CONFIG_PCNET32_NAPI
+ struct pcnet32_private *lp = netdev_priv(dev);
+#endif
netif_wake_queue(dev);
- netif_poll_enable(dev);
+#ifdef CONFIG_PCNET32_NAPI
+ napi_enable(&lp->napi);
+#endif
}
/*
@@ -602,9 +613,9 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
new_dma_addr_list[new] =
pci_map_single(lp->pci_dev, rx_skbuff->data,
PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- new_rx_ring[new].base = (u32) le32_to_cpu(new_dma_addr_list[new]);
- new_rx_ring[new].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
- new_rx_ring[new].status = le16_to_cpu(0x8000);
+ new_rx_ring[new].base = cpu_to_le32(new_dma_addr_list[new]);
+ new_rx_ring[new].buf_length = cpu_to_le16(2 - PKT_BUF_SZ);
+ new_rx_ring[new].status = cpu_to_le16(0x8000);
}
/* and free any unneeded buffers */
for (; new < lp->rx_ring_size; new++) {
@@ -816,7 +827,7 @@ static int pcnet32_set_ringparam(struct net_device *dev,
if ((1 << i) != lp->rx_ring_size)
pcnet32_realloc_rx_ring(dev, lp, i);
- dev->weight = lp->rx_ring_size / 2;
+ lp->napi.weight = lp->rx_ring_size / 2;
if (netif_running(dev)) {
pcnet32_netif_start(dev);
@@ -839,9 +850,14 @@ static void pcnet32_get_strings(struct net_device *dev, u32 stringset,
memcpy(data, pcnet32_gstrings_test, sizeof(pcnet32_gstrings_test));
}
-static int pcnet32_self_test_count(struct net_device *dev)
+static int pcnet32_get_sset_count(struct net_device *dev, int sset)
{
- return PCNET32_TEST_LEN;
+ switch (sset) {
+ case ETH_SS_TEST:
+ return PCNET32_TEST_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void pcnet32_ethtool_test(struct net_device *dev,
@@ -875,7 +891,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
int x, i; /* counters */
int numbuffs = 4; /* number of TX/RX buffers and descs */
u16 status = 0x8300; /* TX ring status */
- u16 teststatus; /* test of ring status */
+ __le16 teststatus; /* test of ring status */
int rc; /* return code */
int size; /* size of packets */
unsigned char *packet; /* source packet data */
@@ -922,7 +938,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
packet = skb->data;
skb_put(skb, size); /* create space for data */
lp->tx_skbuff[x] = skb;
- lp->tx_ring[x].length = le16_to_cpu(-skb->len);
+ lp->tx_ring[x].length = cpu_to_le16(-skb->len);
lp->tx_ring[x].misc = 0;
/* put DA and SA into the skb */
@@ -942,10 +958,9 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
lp->tx_dma_addr[x] =
pci_map_single(lp->pci_dev, skb->data, skb->len,
PCI_DMA_TODEVICE);
- lp->tx_ring[x].base =
- (u32) le32_to_cpu(lp->tx_dma_addr[x]);
+ lp->tx_ring[x].base = cpu_to_le32(lp->tx_dma_addr[x]);
wmb(); /* Make sure owner changes after all others are visible */
- lp->tx_ring[x].status = le16_to_cpu(status);
+ lp->tx_ring[x].status = cpu_to_le16(status);
}
}
@@ -956,7 +971,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
x = a->read_csr(ioaddr, CSR15) & 0xfffc;
lp->a.write_csr(ioaddr, CSR15, x | 0x0044);
- teststatus = le16_to_cpu(0x8000);
+ teststatus = cpu_to_le16(0x8000);
lp->a.write_csr(ioaddr, CSR0, CSR0_START); /* Set STRT bit */
/* Check status of descriptors */
@@ -1086,6 +1101,7 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
mod_timer(&lp->blink_timer, jiffies);
set_current_state(TASK_INTERRUPTIBLE);
+ /* AV: the limit here makes no sense whatsoever */
if ((!data) || (data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ)))
data = (u32) (MAX_SCHEDULE_TIMEOUT / HZ);
@@ -1165,15 +1181,15 @@ static void pcnet32_rx_entry(struct net_device *dev,
* buffers, with only the last correctly noting the error.
*/
if (status & 0x01) /* Only count a general error at the */
- lp->stats.rx_errors++; /* end of a packet. */
+ dev->stats.rx_errors++; /* end of a packet. */
if (status & 0x20)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & 0x10)
- lp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (status & 0x08)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (status & 0x04)
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
return;
}
@@ -1184,13 +1200,13 @@ static void pcnet32_rx_entry(struct net_device *dev,
if (netif_msg_drv(lp))
printk(KERN_ERR "%s: Impossible packet size %d!\n",
dev->name, pkt_len);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
return;
}
if (pkt_len < 60) {
if (netif_msg_rx_err(lp))
printk(KERN_ERR "%s: Runt packet!\n", dev->name);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
return;
}
@@ -1211,7 +1227,7 @@ static void pcnet32_rx_entry(struct net_device *dev,
newskb->data,
PKT_BUF_SZ - 2,
PCI_DMA_FROMDEVICE);
- rxp->base = le32_to_cpu(lp->rx_dma_addr[entry]);
+ rxp->base = cpu_to_le32(lp->rx_dma_addr[entry]);
rx_in_place = 1;
} else
skb = NULL;
@@ -1224,7 +1240,7 @@ static void pcnet32_rx_entry(struct net_device *dev,
printk(KERN_ERR
"%s: Memory squeeze, dropping packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
skb->dev = dev;
@@ -1243,7 +1259,7 @@ static void pcnet32_rx_entry(struct net_device *dev,
pkt_len,
PCI_DMA_FROMDEVICE);
}
- lp->stats.rx_bytes += skb->len;
+ dev->stats.rx_bytes += skb->len;
skb->protocol = eth_type_trans(skb, dev);
#ifdef CONFIG_PCNET32_NAPI
netif_receive_skb(skb);
@@ -1251,11 +1267,11 @@ static void pcnet32_rx_entry(struct net_device *dev,
netif_rx(skb);
#endif
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
+ dev->stats.rx_packets++;
return;
}
-static int pcnet32_rx(struct net_device *dev, int quota)
+static int pcnet32_rx(struct net_device *dev, int budget)
{
struct pcnet32_private *lp = netdev_priv(dev);
int entry = lp->cur_rx & lp->rx_mod_mask;
@@ -1263,16 +1279,16 @@ static int pcnet32_rx(struct net_device *dev, int quota)
int npackets = 0;
/* If we own the next entry, it's a new packet. Send it up. */
- while (quota > npackets && (short)le16_to_cpu(rxp->status) >= 0) {
+ while (npackets < budget && (short)le16_to_cpu(rxp->status) >= 0) {
pcnet32_rx_entry(dev, lp, rxp, entry);
npackets += 1;
/*
* The docs say that the buffer length isn't touched, but Andrew
* Boyd of QNX reports that some revs of the 79C965 clear it.
*/
- rxp->buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+ rxp->buf_length = cpu_to_le16(2 - PKT_BUF_SZ);
wmb(); /* Make sure owner changes after others are visible */
- rxp->status = le16_to_cpu(0x8000);
+ rxp->status = cpu_to_le16(0x8000);
entry = (++lp->cur_rx) & lp->rx_mod_mask;
rxp = &lp->rx_ring[entry];
}
@@ -1299,21 +1315,21 @@ static int pcnet32_tx(struct net_device *dev)
if (status & 0x4000) {
/* There was a major error, log it. */
int err_status = le32_to_cpu(lp->tx_ring[entry].misc);
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (netif_msg_tx_err(lp))
printk(KERN_ERR
"%s: Tx error status=%04x err_status=%08x\n",
dev->name, status,
err_status);
if (err_status & 0x04000000)
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (err_status & 0x08000000)
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (err_status & 0x10000000)
- lp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
#ifndef DO_DXSUFLO
if (err_status & 0x40000000) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
/* Ackk! On FIFO errors the Tx unit is turned off! */
/* Remove this verbosity later! */
if (netif_msg_tx_err(lp))
@@ -1324,7 +1340,7 @@ static int pcnet32_tx(struct net_device *dev)
}
#else
if (err_status & 0x40000000) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (!lp->dxsuflo) { /* If controller doesn't recover ... */
/* Ackk! On FIFO errors the Tx unit is turned off! */
/* Remove this verbosity later! */
@@ -1338,8 +1354,8 @@ static int pcnet32_tx(struct net_device *dev)
#endif
} else {
if (status & 0x1800)
- lp->stats.collisions++;
- lp->stats.tx_packets++;
+ dev->stats.collisions++;
+ dev->stats.tx_packets++;
}
/* We must free the original skb */
@@ -1379,15 +1395,16 @@ static int pcnet32_tx(struct net_device *dev)
}
#ifdef CONFIG_PCNET32_NAPI
-static int pcnet32_poll(struct net_device *dev, int *budget)
+static int pcnet32_poll(struct napi_struct *napi, int budget)
{
- struct pcnet32_private *lp = netdev_priv(dev);
- int quota = min(dev->quota, *budget);
+ struct pcnet32_private *lp = container_of(napi, struct pcnet32_private, napi);
+ struct net_device *dev = lp->dev;
unsigned long ioaddr = dev->base_addr;
unsigned long flags;
+ int work_done;
u16 val;
- quota = pcnet32_rx(dev, quota);
+ work_done = pcnet32_rx(dev, budget);
spin_lock_irqsave(&lp->lock, flags);
if (pcnet32_tx(dev)) {
@@ -1399,28 +1416,22 @@ static int pcnet32_poll(struct net_device *dev, int *budget)
}
spin_unlock_irqrestore(&lp->lock, flags);
- *budget -= quota;
- dev->quota -= quota;
-
- if (dev->quota == 0) {
- return 1;
- }
-
- netif_rx_complete(dev);
-
- spin_lock_irqsave(&lp->lock, flags);
+ if (work_done < budget) {
+ spin_lock_irqsave(&lp->lock, flags);
- /* clear interrupt masks */
- val = lp->a.read_csr(ioaddr, CSR3);
- val &= 0x00ff;
- lp->a.write_csr(ioaddr, CSR3, val);
+ __netif_rx_complete(dev, napi);
- /* Set interrupt enable. */
- lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
- mmiowb();
- spin_unlock_irqrestore(&lp->lock, flags);
+ /* clear interrupt masks */
+ val = lp->a.read_csr(ioaddr, CSR3);
+ val &= 0x00ff;
+ lp->a.write_csr(ioaddr, CSR3, val);
- return 0;
+ /* Set interrupt enable. */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
+ mmiowb();
+ spin_unlock_irqrestore(&lp->lock, flags);
+ }
+ return work_done;
}
#endif
@@ -1506,15 +1517,12 @@ static const struct ethtool_ops pcnet32_ethtool_ops = {
.get_link = pcnet32_get_link,
.get_ringparam = pcnet32_get_ringparam,
.set_ringparam = pcnet32_set_ringparam,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .get_tso = ethtool_op_get_tso,
.get_strings = pcnet32_get_strings,
- .self_test_count = pcnet32_self_test_count,
.self_test = pcnet32_ethtool_test,
.phys_id = pcnet32_phys_id,
.get_regs_len = pcnet32_get_regs_len,
.get_regs = pcnet32_get_regs,
+ .get_sset_count = pcnet32_get_sset_count,
};
/* only probes for non-PCI devices, the rest are handled by
@@ -1815,9 +1823,10 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
}
lp->pci_dev = pdev;
+ lp->dev = dev;
+
spin_lock_init(&lp->lock);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
lp->name = chipname;
lp->shared_irq = shared;
@@ -1843,6 +1852,13 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
lp->mii_if.mdio_read = mdio_read;
lp->mii_if.mdio_write = mdio_write;
+ /* napi.weight is used in both the napi and non-napi cases */
+ lp->napi.weight = lp->rx_ring_size / 2;
+
+#ifdef CONFIG_PCNET32_NAPI
+ netif_napi_add(dev, &lp->napi, pcnet32_poll, lp->rx_ring_size / 2);
+#endif
+
if (fdx && !(lp->options & PCNET32_PORT_ASEL) &&
((cards_found >= MAX_UNITS) || full_duplex[cards_found]))
lp->options |= PCNET32_PORT_FD;
@@ -1865,15 +1881,15 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
&& dev->dev_addr[2] == 0x75)
lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI;
- lp->init_block->mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */
+ lp->init_block->mode = cpu_to_le16(0x0003); /* Disable Rx and Tx. */
lp->init_block->tlen_rlen =
- le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
+ cpu_to_le16(lp->tx_len_bits | lp->rx_len_bits);
for (i = 0; i < 6; i++)
lp->init_block->phys_addr[i] = dev->dev_addr[i];
lp->init_block->filter[0] = 0x00000000;
lp->init_block->filter[1] = 0x00000000;
- lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
- lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+ lp->init_block->rx_ring = cpu_to_le32(lp->rx_ring_dma_addr);
+ lp->init_block->tx_ring = cpu_to_le32(lp->tx_ring_dma_addr);
/* switch pcnet32 to 32bit mode */
a->write_bcr(ioaddr, 20, 2);
@@ -1953,10 +1969,6 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
dev->ethtool_ops = &pcnet32_ethtool_ops;
dev->tx_timeout = pcnet32_tx_timeout;
dev->watchdog_timeo = (5 * HZ);
- dev->weight = lp->rx_ring_size / 2;
-#ifdef CONFIG_PCNET32_NAPI
- dev->poll = pcnet32_poll;
-#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = pcnet32_poll_controller;
@@ -2268,7 +2280,7 @@ static int pcnet32_open(struct net_device *dev)
#endif
lp->init_block->mode =
- le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+ cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7);
pcnet32_load_multicast(dev);
if (pcnet32_init_ring(dev)) {
@@ -2276,6 +2288,10 @@ static int pcnet32_open(struct net_device *dev)
goto err_free_ring;
}
+#ifdef CONFIG_PCNET32_NAPI
+ napi_enable(&lp->napi);
+#endif
+
/* Re-initialize the PCNET32, and start it when done. */
lp->a.write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
lp->a.write_csr(ioaddr, 2, (lp->init_dma_addr >> 16));
@@ -2391,10 +2407,10 @@ static int pcnet32_init_ring(struct net_device *dev)
lp->rx_dma_addr[i] =
pci_map_single(lp->pci_dev, rx_skbuff->data,
PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- lp->rx_ring[i].base = (u32) le32_to_cpu(lp->rx_dma_addr[i]);
- lp->rx_ring[i].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+ lp->rx_ring[i].base = cpu_to_le32(lp->rx_dma_addr[i]);
+ lp->rx_ring[i].buf_length = cpu_to_le16(2 - PKT_BUF_SZ);
wmb(); /* Make sure owner changes after all others are visible */
- lp->rx_ring[i].status = le16_to_cpu(0x8000);
+ lp->rx_ring[i].status = cpu_to_le16(0x8000);
}
/* The Tx buffer address is filled in as needed, but we do need to clear
* the upper ownership bit. */
@@ -2406,11 +2422,11 @@ static int pcnet32_init_ring(struct net_device *dev)
}
lp->init_block->tlen_rlen =
- le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
+ cpu_to_le16(lp->tx_len_bits | lp->rx_len_bits);
for (i = 0; i < 6; i++)
lp->init_block->phys_addr[i] = dev->dev_addr[i];
- lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
- lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+ lp->init_block->rx_ring = cpu_to_le32(lp->rx_ring_dma_addr);
+ lp->init_block->tx_ring = cpu_to_le32(lp->tx_ring_dma_addr);
wmb(); /* Make sure all changes are visible */
return 0;
}
@@ -2461,7 +2477,7 @@ static void pcnet32_tx_timeout(struct net_device *dev)
"%s: transmit timed out, status %4.4x, resetting.\n",
dev->name, lp->a.read_csr(ioaddr, CSR0));
lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (netif_msg_tx_err(lp)) {
int i;
printk(KERN_DEBUG
@@ -2519,19 +2535,19 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Caution: the write order is important here, set the status
* with the "ownership" bits last. */
- lp->tx_ring[entry].length = le16_to_cpu(-skb->len);
+ lp->tx_ring[entry].length = cpu_to_le16(-skb->len);
lp->tx_ring[entry].misc = 0x00000000;
lp->tx_skbuff[entry] = skb;
lp->tx_dma_addr[entry] =
pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
- lp->tx_ring[entry].base = (u32) le32_to_cpu(lp->tx_dma_addr[entry]);
+ lp->tx_ring[entry].base = cpu_to_le32(lp->tx_dma_addr[entry]);
wmb(); /* Make sure owner changes after all others are visible */
- lp->tx_ring[entry].status = le16_to_cpu(status);
+ lp->tx_ring[entry].status = cpu_to_le16(status);
lp->cur_tx++;
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
/* Trigger an immediate send poll. */
lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN | CSR0_TXPOLL);
@@ -2576,7 +2592,7 @@ pcnet32_interrupt(int irq, void *dev_id)
/* Log misc errors. */
if (csr0 & 0x4000)
- lp->stats.tx_errors++; /* Tx babble. */
+ dev->stats.tx_errors++; /* Tx babble. */
if (csr0 & 0x1000) {
/*
* This happens when our receive ring is full. This
@@ -2589,7 +2605,7 @@ pcnet32_interrupt(int irq, void *dev_id)
* don't get a rx interrupt, but a missed frame
* interrupt sooner or later.
*/
- lp->stats.rx_errors++; /* Missed a Rx frame. */
+ dev->stats.rx_errors++; /* Missed a Rx frame. */
}
if (csr0 & 0x0800) {
if (netif_msg_drv(lp))
@@ -2599,18 +2615,18 @@ pcnet32_interrupt(int irq, void *dev_id)
/* unlike for the lance, there is no restart needed */
}
#ifdef CONFIG_PCNET32_NAPI
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &lp->napi)) {
u16 val;
/* set interrupt masks */
val = lp->a.read_csr(ioaddr, CSR3);
val |= 0x5f00;
lp->a.write_csr(ioaddr, CSR3, val);
mmiowb();
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &lp->napi);
break;
}
#else
- pcnet32_rx(dev, dev->weight);
+ pcnet32_rx(dev, lp->napi.weight);
if (pcnet32_tx(dev)) {
/* reset the chip to clear the error condition, then restart */
lp->a.reset(ioaddr);
@@ -2645,10 +2661,13 @@ static int pcnet32_close(struct net_device *dev)
del_timer_sync(&lp->watchdog_timer);
netif_stop_queue(dev);
+#ifdef CONFIG_PCNET32_NAPI
+ napi_disable(&lp->napi);
+#endif
spin_lock_irqsave(&lp->lock, flags);
- lp->stats.rx_missed_errors = lp->a.read_csr(ioaddr, 112);
+ dev->stats.rx_missed_errors = lp->a.read_csr(ioaddr, 112);
if (netif_msg_ifdown(lp))
printk(KERN_DEBUG
@@ -2685,10 +2704,10 @@ static struct net_device_stats *pcnet32_get_stats(struct net_device *dev)
unsigned long flags;
spin_lock_irqsave(&lp->lock, flags);
- lp->stats.rx_missed_errors = lp->a.read_csr(ioaddr, 112);
+ dev->stats.rx_missed_errors = lp->a.read_csr(ioaddr, 112);
spin_unlock_irqrestore(&lp->lock, flags);
- return &lp->stats;
+ return &dev->stats;
}
/* taken from the sunlance driver, which it took from the depca driver */
@@ -2696,7 +2715,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
{
struct pcnet32_private *lp = netdev_priv(dev);
volatile struct pcnet32_init_block *ib = lp->init_block;
- volatile u16 *mcast_table = (u16 *) & ib->filter;
+ volatile __le16 *mcast_table = (__le16 *)ib->filter;
struct dev_mc_list *dmi = dev->mc_list;
unsigned long ioaddr = dev->base_addr;
char *addrs;
@@ -2705,8 +2724,8 @@ static void pcnet32_load_multicast(struct net_device *dev)
/* set all multicast bits */
if (dev->flags & IFF_ALLMULTI) {
- ib->filter[0] = 0xffffffff;
- ib->filter[1] = 0xffffffff;
+ ib->filter[0] = cpu_to_le32(~0U);
+ ib->filter[1] = cpu_to_le32(~0U);
lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff);
lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff);
lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff);
@@ -2728,9 +2747,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
crc = ether_crc_le(6, addrs);
crc = crc >> 26;
- mcast_table[crc >> 4] =
- le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) |
- (1 << (crc & 0xf)));
+ mcast_table[crc >> 4] |= cpu_to_le16(1 << (crc & 0xf));
}
for (i = 0; i < 4; i++)
lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i,
@@ -2756,12 +2773,12 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
printk(KERN_INFO "%s: Promiscuous mode enabled.\n",
dev->name);
lp->init_block->mode =
- le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
+ cpu_to_le16(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
7);
lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
} else {
lp->init_block->mode =
- le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+ cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7);
lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
pcnet32_load_multicast(dev);
}
@@ -2943,6 +2960,33 @@ static void pcnet32_watchdog(struct net_device *dev)
mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
}
+static int pcnet32_pm_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ if (netif_running(dev)) {
+ netif_device_detach(dev);
+ pcnet32_close(dev);
+ }
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
+}
+
+static int pcnet32_pm_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ if (netif_running(dev)) {
+ pcnet32_open(dev);
+ netif_device_attach(dev);
+ }
+ return 0;
+}
+
static void __devexit pcnet32_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
@@ -2966,6 +3010,8 @@ static struct pci_driver pcnet32_driver = {
.probe = pcnet32_probe_pci,
.remove = __devexit_p(pcnet32_remove_one),
.id_table = pcnet32_pci_tbl,
+ .suspend = pcnet32_pm_suspend,
+ .resume = pcnet32_pm_resume,
};
/* An additional parameter that may be passed in... */
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index dd09011c7ee..54b2ba99664 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -76,4 +76,27 @@ config FIXED_MII_100_FDX
bool "Emulation for 100M Fdx fixed PHY behavior"
depends on FIXED_PHY
+config FIXED_MII_1000_FDX
+ bool "Emulation for 1000M Fdx fixed PHY behavior"
+ depends on FIXED_PHY
+
+config FIXED_MII_AMNT
+ int "Number of emulated PHYs to allocate "
+ depends on FIXED_PHY
+ default "1"
+ ---help---
+ Sometimes it is required to have several independent emulated
+ PHYs on the bus (in case of multi-eth but phy-less HW for instance).
+ This control will have specified number allocated for each fixed
+ PHY type enabled.
+
+config MDIO_BITBANG
+ tristate "Support for bitbanged MDIO buses"
+ help
+ This module implements the MDIO bus protocol in software,
+ for use by low level drivers that export the ability to
+ drive the relevant pins.
+
+ If in doubt, say N.
+
endif # PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 8885650647f..3d6cc7b67a8 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_FIXED_PHY) += fixed.o
+obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index bb966911a13..56191822fa2 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -30,53 +30,31 @@
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
+#include <linux/phy_fixed.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
-#define MII_REGS_NUM 7
-
-/*
- The idea is to emulate normal phy behavior by responding with
- pre-defined values to mii BMCR read, so that read_status hook could
- take all the needed info.
-*/
-
-struct fixed_phy_status {
- u8 link;
- u16 speed;
- u8 duplex;
-};
-
-/*-----------------------------------------------------------------------------
- * Private information hoder for mii_bus
- *-----------------------------------------------------------------------------*/
-struct fixed_info {
- u16 *regs;
- u8 regs_num;
- struct fixed_phy_status phy_status;
- struct phy_device *phydev; /* pointer to the container */
- /* link & speed cb */
- int(*link_update)(struct net_device*, struct fixed_phy_status*);
-
-};
+/* we need to track the allocated pointers in order to free them on exit */
+static struct fixed_info *fixed_phy_ptrs[CONFIG_FIXED_MII_AMNT*MAX_PHY_AMNT];
/*-----------------------------------------------------------------------------
* If something weird is required to be done with link/speed,
* network driver is able to assign a function to implement this.
* May be useful for PHY's that need to be software-driven.
*-----------------------------------------------------------------------------*/
-int fixed_mdio_set_link_update(struct phy_device* phydev,
- int(*link_update)(struct net_device*, struct fixed_phy_status*))
+int fixed_mdio_set_link_update(struct phy_device *phydev,
+ int (*link_update) (struct net_device *,
+ struct fixed_phy_status *))
{
struct fixed_info *fixed;
- if(link_update == NULL)
+ if (link_update == NULL)
return -EINVAL;
- if(phydev) {
- if(phydev->bus) {
+ if (phydev) {
+ if (phydev->bus) {
fixed = phydev->bus->priv;
fixed->link_update = link_update;
return 0;
@@ -84,54 +62,64 @@ int fixed_mdio_set_link_update(struct phy_device* phydev,
}
return -EINVAL;
}
+
EXPORT_SYMBOL(fixed_mdio_set_link_update);
+struct fixed_info *fixed_mdio_get_phydev (int phydev_ind)
+{
+ if (phydev_ind >= MAX_PHY_AMNT)
+ return NULL;
+ return fixed_phy_ptrs[phydev_ind];
+}
+
+EXPORT_SYMBOL(fixed_mdio_get_phydev);
+
/*-----------------------------------------------------------------------------
* This is used for updating internal mii regs from the status
*-----------------------------------------------------------------------------*/
-#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX)
+#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)
static int fixed_mdio_update_regs(struct fixed_info *fixed)
{
u16 *regs = fixed->regs;
u16 bmsr = 0;
u16 bmcr = 0;
- if(!regs) {
+ if (!regs) {
printk(KERN_ERR "%s: regs not set up", __FUNCTION__);
return -EINVAL;
}
- if(fixed->phy_status.link)
+ if (fixed->phy_status.link)
bmsr |= BMSR_LSTATUS;
- if(fixed->phy_status.duplex) {
+ if (fixed->phy_status.duplex) {
bmcr |= BMCR_FULLDPLX;
- switch ( fixed->phy_status.speed ) {
+ switch (fixed->phy_status.speed) {
case 100:
bmsr |= BMSR_100FULL;
bmcr |= BMCR_SPEED100;
- break;
+ break;
case 10:
bmsr |= BMSR_10FULL;
- break;
+ break;
}
} else {
- switch ( fixed->phy_status.speed ) {
+ switch (fixed->phy_status.speed) {
case 100:
bmsr |= BMSR_100HALF;
bmcr |= BMCR_SPEED100;
- break;
+ break;
case 10:
bmsr |= BMSR_100HALF;
- break;
+ break;
}
}
- regs[MII_BMCR] = bmcr;
- regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx*/
+ regs[MII_BMCR] = bmcr;
+ regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx */
return 0;
}
@@ -141,29 +129,30 @@ static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location)
struct fixed_info *fixed = bus->priv;
/* if user has registered link update callback, use it */
- if(fixed->phydev)
- if(fixed->phydev->attached_dev) {
- if(fixed->link_update) {
+ if (fixed->phydev)
+ if (fixed->phydev->attached_dev) {
+ if (fixed->link_update) {
fixed->link_update(fixed->phydev->attached_dev,
- &fixed->phy_status);
+ &fixed->phy_status);
fixed_mdio_update_regs(fixed);
}
- }
+ }
if ((unsigned int)location >= fixed->regs_num)
return -1;
return fixed->regs[location];
}
-static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val)
+static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location,
+ u16 val)
{
- /* do nothing for now*/
+ /* do nothing for now */
return 0;
}
static int fixed_mii_reset(struct mii_bus *bus)
{
- /*nothing here - no way/need to reset it*/
+ /*nothing here - no way/need to reset it */
return 0;
}
#endif
@@ -171,8 +160,8 @@ static int fixed_mii_reset(struct mii_bus *bus)
static int fixed_config_aneg(struct phy_device *phydev)
{
/* :TODO:03/13/2006 09:45:37 PM::
- The full autoneg funcionality can be emulated,
- but no need to have anything here for now
+ The full autoneg funcionality can be emulated,
+ but no need to have anything here for now
*/
return 0;
}
@@ -182,59 +171,79 @@ static int fixed_config_aneg(struct phy_device *phydev)
* match will never return true...
*-----------------------------------------------------------------------------*/
static struct phy_driver fixed_mdio_driver = {
- .name = "Fixed PHY",
- .features = PHY_BASIC_FEATURES,
- .config_aneg = fixed_config_aneg,
- .read_status = genphy_read_status,
- .driver = { .owner = THIS_MODULE,},
+ .name = "Fixed PHY",
+#ifdef CONFIG_FIXED_MII_1000_FDX
+ .features = PHY_GBIT_FEATURES,
+#else
+ .features = PHY_BASIC_FEATURES,
+#endif
+ .config_aneg = fixed_config_aneg,
+ .read_status = genphy_read_status,
+ .driver = { .owner = THIS_MODULE, },
};
+static void fixed_mdio_release(struct device *dev)
+{
+ struct phy_device *phydev = container_of(dev, struct phy_device, dev);
+ struct mii_bus *bus = phydev->bus;
+ struct fixed_info *fixed = bus->priv;
+
+ kfree(phydev);
+ kfree(bus->dev);
+ kfree(bus);
+ kfree(fixed->regs);
+ kfree(fixed);
+}
+
/*-----------------------------------------------------------------------------
* This func is used to create all the necessary stuff, bind
* the fixed phy driver and register all it on the mdio_bus_type.
- * speed is either 10 or 100, duplex is boolean.
+ * speed is either 10 or 100 or 1000, duplex is boolean.
* number is used to create multiple fixed PHYs, so that several devices can
* utilize them simultaneously.
+ *
+ * The device on mdio bus will look like [bus_id]:[phy_id],
+ * bus_id = number
+ * phy_id = speed+duplex.
*-----------------------------------------------------------------------------*/
-#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX)
-static int fixed_mdio_register_device(int number, int speed, int duplex)
+#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)
+struct fixed_info *fixed_mdio_register_device(
+ int bus_id, int speed, int duplex, u8 phy_id)
{
struct mii_bus *new_bus;
struct fixed_info *fixed;
struct phy_device *phydev;
- int err = 0;
+ int err;
- struct device* dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+ struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
- if (NULL == dev)
- return -ENOMEM;
+ if (dev == NULL)
+ goto err_dev_alloc;
new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
- if (NULL == new_bus) {
- kfree(dev);
- return -ENOMEM;
- }
+ if (new_bus == NULL)
+ goto err_bus_alloc;
+
fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL);
- if (NULL == fixed) {
- kfree(dev);
- kfree(new_bus);
- return -ENOMEM;
- }
+ if (fixed == NULL)
+ goto err_fixed_alloc;
+
+ fixed->regs = kzalloc(MII_REGS_NUM * sizeof(int), GFP_KERNEL);
+ if (NULL == fixed->regs)
+ goto err_fixed_regs_alloc;
- fixed->regs = kzalloc(MII_REGS_NUM*sizeof(int), GFP_KERNEL);
fixed->regs_num = MII_REGS_NUM;
fixed->phy_status.speed = speed;
fixed->phy_status.duplex = duplex;
fixed->phy_status.link = 1;
- new_bus->name = "Fixed MII Bus",
- new_bus->read = &fixed_mii_read,
- new_bus->write = &fixed_mii_write,
- new_bus->reset = &fixed_mii_reset,
-
- /*set up workspace*/
+ new_bus->name = "Fixed MII Bus";
+ new_bus->read = &fixed_mii_read;
+ new_bus->write = &fixed_mii_write;
+ new_bus->reset = &fixed_mii_reset;
+ /*set up workspace */
fixed_mdio_update_regs(fixed);
new_bus->priv = fixed;
@@ -243,119 +252,110 @@ static int fixed_mdio_register_device(int number, int speed, int duplex)
/* create phy_device and register it on the mdio bus */
phydev = phy_device_create(new_bus, 0, 0);
+ if (phydev == NULL)
+ goto err_phy_dev_create;
/*
- Put the phydev pointer into the fixed pack so that bus read/write code could
- be able to access for instance attached netdev. Well it doesn't have to do
- so, only in case of utilizing user-specified link-update...
+ * Put the phydev pointer into the fixed pack so that bus read/write
+ * code could be able to access for instance attached netdev. Well it
+ * doesn't have to do so, only in case of utilizing user-specified
+ * link-update...
*/
- fixed->phydev = phydev;
- if(NULL == phydev) {
- err = -ENOMEM;
- goto device_create_fail;
- }
+ fixed->phydev = phydev;
+ phydev->speed = speed;
+ phydev->duplex = duplex;
phydev->irq = PHY_IGNORE_INTERRUPT;
phydev->dev.bus = &mdio_bus_type;
- if(number)
- snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
- "fixed_%d@%d:%d", number, speed, duplex);
- else
- snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
- "fixed@%d:%d", speed, duplex);
- phydev->bus = new_bus;
+ snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
+ PHY_ID_FMT, bus_id, phy_id);
- err = device_register(&phydev->dev);
- if(err) {
- printk(KERN_ERR "Phy %s failed to register\n",
- phydev->dev.bus_id);
- goto bus_register_fail;
- }
+ phydev->bus = new_bus;
- /*
- the mdio bus has phy_id match... In order not to do it
- artificially, we are binding the driver here by hand;
- it will be the same for all the fixed phys anyway.
- */
phydev->dev.driver = &fixed_mdio_driver.driver;
-
+ phydev->dev.release = fixed_mdio_release;
err = phydev->dev.driver->probe(&phydev->dev);
- if(err < 0) {
- printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id);
- goto probe_fail;
+ if (err < 0) {
+ printk(KERN_ERR "Phy %s: problems with fixed driver\n",
+ phydev->dev.bus_id);
+ goto err_out;
}
+ err = device_register(&phydev->dev);
+ if (err) {
+ printk(KERN_ERR "Phy %s failed to register\n",
+ phydev->dev.bus_id);
+ goto err_out;
+ }
+ //phydev->state = PHY_RUNNING; /* make phy go up quick, but in 10Mbit/HDX
+ return fixed;
- err = device_bind_driver(&phydev->dev);
- if (err)
- goto probe_fail;
-
- return 0;
-
-probe_fail:
- device_unregister(&phydev->dev);
-bus_register_fail:
+err_out:
kfree(phydev);
-device_create_fail:
- kfree(dev);
- kfree(new_bus);
+err_phy_dev_create:
+ kfree(fixed->regs);
+err_fixed_regs_alloc:
kfree(fixed);
+err_fixed_alloc:
+ kfree(new_bus);
+err_bus_alloc:
+ kfree(dev);
+err_dev_alloc:
+
+ return NULL;
- return err;
}
#endif
-
MODULE_DESCRIPTION("Fixed PHY device & driver for PAL");
MODULE_AUTHOR("Vitaly Bordug");
MODULE_LICENSE("GPL");
static int __init fixed_init(void)
{
-#if 0
- int ret;
- int duplex = 0;
-#endif
-
- /* register on the bus... Not expected to be matched with anything there... */
+ int cnt = 0;
+ int i;
+/* register on the bus... Not expected to be matched
+ * with anything there...
+ *
+ */
phy_driver_register(&fixed_mdio_driver);
- /* So let the fun begin...
- We will create several mdio devices here, and will bound the upper
- driver to them.
-
- Then the external software can lookup the phy bus by searching
- fixed@speed:duplex, e.g. fixed@100:1, to be connected to the
- virtual 100M Fdx phy.
-
- In case several virtual PHYs required, the bus_id will be in form
- fixed_<num>@<speed>:<duplex>, which make it able even to define
- driver-specific link control callback, if for instance PHY is completely
- SW-driven.
-
- */
-
-#ifdef CONFIG_FIXED_MII_DUPLEX
-#if 0
- duplex = 1;
-#endif
+/* We will create several mdio devices here, and will bound the upper
+ * driver to them.
+ *
+ * Then the external software can lookup the phy bus by searching
+ * for 0:101, to be connected to the virtual 100M Fdx phy.
+ *
+ * In case several virtual PHYs required, the bus_id will be in form
+ * [num]:[duplex]+[speed], which make it able even to define
+ * driver-specific link control callback, if for instance PHY is
+ * completely SW-driven.
+ */
+ for (i=1; i <= CONFIG_FIXED_MII_AMNT; i++) {
+#ifdef CONFIG_FIXED_MII_1000_FDX
+ fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(0, 1000, 1, i);
#endif
-
#ifdef CONFIG_FIXED_MII_100_FDX
- fixed_mdio_register_device(0, 100, 1);
+ fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(1, 100, 1, i);
#endif
-
#ifdef CONFIG_FIXED_MII_10_FDX
- fixed_mdio_register_device(0, 10, 1);
+ fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(2, 10, 1, i);
#endif
+ }
+
return 0;
}
static void __exit fixed_exit(void)
{
+ int i;
+
phy_driver_unregister(&fixed_mdio_driver);
- /* :WARNING:02/18/2006 04:32:40 AM:: Cleanup all the created stuff */
+ for (i=0; i < MAX_PHY_AMNT; i++)
+ if ( fixed_phy_ptrs[i] )
+ device_unregister(&fixed_phy_ptrs[i]->phydev->dev);
}
module_init(fixed_init);
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index d2ede5ff9ff..035fd41fb61 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -265,7 +265,7 @@ static struct phy_driver marvell_drivers[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
- .driver = {.owner = THIS_MODULE,},
+ .driver = { .owner = THIS_MODULE },
},
{
.phy_id = 0x01410c90,
@@ -278,7 +278,7 @@ static struct phy_driver marvell_drivers[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
- .driver = {.owner = THIS_MODULE,},
+ .driver = { .owner = THIS_MODULE },
},
{
.phy_id = 0x01410cc0,
@@ -291,7 +291,7 @@ static struct phy_driver marvell_drivers[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
- .driver = {.owner = THIS_MODULE,},
+ .driver = { .owner = THIS_MODULE },
},
{
.phy_id = 0x01410cd0,
@@ -304,8 +304,21 @@ static struct phy_driver marvell_drivers[] = {
.read_status = &genphy_read_status,
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
- .driver = {.owner = THIS_MODULE,},
- }
+ .driver = { .owner = THIS_MODULE },
+ },
+ {
+ .phy_id = 0x01410e30,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Marvell 88E1240",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = &m88e1111_config_init,
+ .config_aneg = &marvell_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &marvell_ack_interrupt,
+ .config_intr = &marvell_config_intr,
+ .driver = { .owner = THIS_MODULE },
+ },
};
static int __init marvell_init(void)
diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
new file mode 100644
index 00000000000..2747b1f89ff
--- /dev/null
+++ b/drivers/net/phy/mdio-bitbang.c
@@ -0,0 +1,189 @@
+/*
+ * Bitbanged MDIO support.
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ * Copyright (c) 2007 Freescale Semiconductor
+ *
+ * Based on CPM2 MDIO code which is:
+ *
+ * Copyright (c) 2003 Intracom S.A.
+ * by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/mdio-bitbang.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#define MDIO_READ 1
+#define MDIO_WRITE 0
+
+#define MDIO_SETUP_TIME 10
+#define MDIO_HOLD_TIME 10
+
+/* Minimum MDC period is 400 ns, plus some margin for error. MDIO_DELAY
+ * is done twice per period.
+ */
+#define MDIO_DELAY 250
+
+/* The PHY may take up to 300 ns to produce data, plus some margin
+ * for error.
+ */
+#define MDIO_READ_DELAY 350
+
+/* MDIO must already be configured as output. */
+static void mdiobb_send_bit(struct mdiobb_ctrl *ctrl, int val)
+{
+ const struct mdiobb_ops *ops = ctrl->ops;
+
+ ops->set_mdio_data(ctrl, val);
+ ndelay(MDIO_DELAY);
+ ops->set_mdc(ctrl, 1);
+ ndelay(MDIO_DELAY);
+ ops->set_mdc(ctrl, 0);
+}
+
+/* MDIO must already be configured as input. */
+static int mdiobb_get_bit(struct mdiobb_ctrl *ctrl)
+{
+ const struct mdiobb_ops *ops = ctrl->ops;
+
+ ndelay(MDIO_DELAY);
+ ops->set_mdc(ctrl, 1);
+ ndelay(MDIO_READ_DELAY);
+ ops->set_mdc(ctrl, 0);
+
+ return ops->get_mdio_data(ctrl);
+}
+
+/* MDIO must already be configured as output. */
+static void mdiobb_send_num(struct mdiobb_ctrl *ctrl, u16 val, int bits)
+{
+ int i;
+
+ for (i = bits - 1; i >= 0; i--)
+ mdiobb_send_bit(ctrl, (val >> i) & 1);
+}
+
+/* MDIO must already be configured as input. */
+static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits)
+{
+ int i;
+ u16 ret = 0;
+
+ for (i = bits - 1; i >= 0; i--) {
+ ret <<= 1;
+ ret |= mdiobb_get_bit(ctrl);
+ }
+
+ return ret;
+}
+
+/* Utility to send the preamble, address, and
+ * register (common to read and write).
+ */
+static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int read, u8 phy, u8 reg)
+{
+ const struct mdiobb_ops *ops = ctrl->ops;
+ int i;
+
+ ops->set_mdio_dir(ctrl, 1);
+
+ /*
+ * Send a 32 bit preamble ('1's) with an extra '1' bit for good
+ * measure. The IEEE spec says this is a PHY optional
+ * requirement. The AMD 79C874 requires one after power up and
+ * one after a MII communications error. This means that we are
+ * doing more preambles than we need, but it is safer and will be
+ * much more robust.
+ */
+
+ for (i = 0; i < 32; i++)
+ mdiobb_send_bit(ctrl, 1);
+
+ /* send the start bit (01) and the read opcode (10) or write (10) */
+ mdiobb_send_bit(ctrl, 0);
+ mdiobb_send_bit(ctrl, 1);
+ mdiobb_send_bit(ctrl, read);
+ mdiobb_send_bit(ctrl, !read);
+
+ mdiobb_send_num(ctrl, phy, 5);
+ mdiobb_send_num(ctrl, reg, 5);
+}
+
+
+static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
+{
+ struct mdiobb_ctrl *ctrl = bus->priv;
+ int ret, i;
+
+ mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
+ ctrl->ops->set_mdio_dir(ctrl, 0);
+
+ /* check the turnaround bit: the PHY should be driving it to zero */
+ if (mdiobb_get_bit(ctrl) != 0) {
+ /* PHY didn't drive TA low -- flush any bits it
+ * may be trying to send.
+ */
+ for (i = 0; i < 32; i++)
+ mdiobb_get_bit(ctrl);
+
+ return 0xffff;
+ }
+
+ ret = mdiobb_get_num(ctrl, 16);
+ mdiobb_get_bit(ctrl);
+ return ret;
+}
+
+static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
+{
+ struct mdiobb_ctrl *ctrl = bus->priv;
+
+ mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
+
+ /* send the turnaround (10) */
+ mdiobb_send_bit(ctrl, 1);
+ mdiobb_send_bit(ctrl, 0);
+
+ mdiobb_send_num(ctrl, val, 16);
+
+ ctrl->ops->set_mdio_dir(ctrl, 0);
+ mdiobb_get_bit(ctrl);
+ return 0;
+}
+
+struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
+{
+ struct mii_bus *bus;
+
+ bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+ if (!bus)
+ return NULL;
+
+ __module_get(ctrl->ops->owner);
+
+ bus->read = mdiobb_read;
+ bus->write = mdiobb_write;
+ bus->priv = ctrl;
+
+ return bus;
+}
+
+void free_mdio_bitbang(struct mii_bus *bus)
+{
+ struct mdiobb_ctrl *ctrl = bus->priv;
+
+ module_put(ctrl->ops->owner);
+ kfree(bus);
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index cb230f44d6f..9bc11773705 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -7,7 +7,7 @@
* Author: Andy Fleming
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
- * Copyright (c) 2006 Maciej W. Rozycki
+ * Copyright (c) 2006, 2007 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -35,6 +35,7 @@
#include <linux/timer.h>
#include <linux/workqueue.h>
+#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
@@ -204,7 +205,7 @@ static const struct phy_setting settings[] = {
},
};
-#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting))
+#define MAX_NUM_SETTINGS ARRAY_SIZE(settings)
/**
* phy_find_setting - find a PHY settings array entry that matches speed & duplex
@@ -424,7 +425,7 @@ int phy_start_aneg(struct phy_device *phydev)
{
int err;
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
if (AUTONEG_DISABLE == phydev->autoneg)
phy_sanitize_settings(phydev);
@@ -445,7 +446,7 @@ int phy_start_aneg(struct phy_device *phydev)
}
out_unlock:
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
return err;
}
EXPORT_SYMBOL(phy_start_aneg);
@@ -490,10 +491,10 @@ void phy_stop_machine(struct phy_device *phydev)
{
del_timer_sync(&phydev->phy_timer);
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
if (phydev->state > PHY_UP)
phydev->state = PHY_UP;
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
phydev->adjust_state = NULL;
}
@@ -537,9 +538,9 @@ static void phy_force_reduction(struct phy_device *phydev)
*/
void phy_error(struct phy_device *phydev)
{
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
phydev->state = PHY_HALTED;
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
}
/**
@@ -562,6 +563,7 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
* queue will write the PHY to disable and clear the
* interrupt, and then reenable the irq line. */
disable_irq_nosync(irq);
+ atomic_inc(&phydev->irq_disable);
schedule_work(&phydev->phy_queue);
@@ -632,6 +634,7 @@ int phy_start_interrupts(struct phy_device *phydev)
INIT_WORK(&phydev->phy_queue, phy_change);
+ atomic_set(&phydev->irq_disable, 0);
if (request_irq(phydev->irq, phy_interrupt,
IRQF_SHARED,
"phy_interrupt",
@@ -662,13 +665,22 @@ int phy_stop_interrupts(struct phy_device *phydev)
if (err)
phy_error(phydev);
+ free_irq(phydev->irq, phydev);
+
/*
- * Finish any pending work; we might have been scheduled to be called
- * from keventd ourselves, but cancel_work_sync() handles that.
+ * Cannot call flush_scheduled_work() here as desired because
+ * of rtnl_lock(), but we do not really care about what would
+ * be done, except from enable_irq(), so cancel any work
+ * possibly pending and take care of the matter below.
*/
cancel_work_sync(&phydev->phy_queue);
-
- free_irq(phydev->irq, phydev);
+ /*
+ * If work indeed has been cancelled, disable_irq() will have
+ * been left unbalanced from phy_interrupt() and enable_irq()
+ * has to be called so that other devices on the line work.
+ */
+ while (atomic_dec_return(&phydev->irq_disable) >= 0)
+ enable_irq(phydev->irq);
return err;
}
@@ -690,11 +702,12 @@ static void phy_change(struct work_struct *work)
if (err)
goto phy_err;
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
phydev->state = PHY_CHANGELINK;
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
+ atomic_dec(&phydev->irq_disable);
enable_irq(phydev->irq);
/* Reenable interrupts */
@@ -708,6 +721,7 @@ static void phy_change(struct work_struct *work)
irq_enable_err:
disable_irq(phydev->irq);
+ atomic_inc(&phydev->irq_disable);
phy_err:
phy_error(phydev);
}
@@ -718,13 +732,11 @@ phy_err:
*/
void phy_stop(struct phy_device *phydev)
{
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
if (PHY_HALTED == phydev->state)
goto out_unlock;
- phydev->state = PHY_HALTED;
-
if (phydev->irq != PHY_POLL) {
/* Disable PHY Interrupts */
phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
@@ -733,8 +745,10 @@ void phy_stop(struct phy_device *phydev)
phy_clear_interrupt(phydev);
}
+ phydev->state = PHY_HALTED;
+
out_unlock:
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
/*
* Cannot call flush_scheduled_work() here as desired because
@@ -782,7 +796,7 @@ static void phy_timer(unsigned long data)
int needs_aneg = 0;
int err = 0;
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
if (phydev->adjust_state)
phydev->adjust_state(phydev->attached_dev);
@@ -948,7 +962,7 @@ static void phy_timer(unsigned long data)
break;
}
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
if (needs_aneg)
err = phy_start_aneg(phydev);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 49328e05050..f6e484812a9 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -670,9 +670,9 @@ static int phy_remove(struct device *dev)
phydev = to_phy_device(dev);
- spin_lock(&phydev->lock);
+ spin_lock_bh(&phydev->lock);
phydev->state = PHY_DOWN;
- spin_unlock(&phydev->lock);
+ spin_unlock_bh(&phydev->lock);
if (phydev->drv->remove)
phydev->drv->remove(phydev);
@@ -706,7 +706,7 @@ int phy_driver_register(struct phy_driver *new_driver)
return retval;
}
- pr_info("%s: Registered new driver\n", new_driver->name);
+ pr_debug("%s: Registered new driver\n", new_driver->name);
return 0;
}
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 8754cf3356b..5071fcd8a0b 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -143,18 +143,17 @@ static void plip_bh(struct work_struct *work);
static void plip_timer_bh(struct work_struct *work);
/* Interrupt handler */
-static void plip_interrupt(int irq, void *dev_id);
+static void plip_interrupt(void *dev_id);
/* Functions for DEV methods */
static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev);
static int plip_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr,
- void *saddr, unsigned len);
-static int plip_hard_header_cache(struct neighbour *neigh,
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len);
+static int plip_hard_header_cache(const struct neighbour *neigh,
struct hh_cache *hh);
static int plip_open(struct net_device *dev);
static int plip_close(struct net_device *dev);
-static struct net_device_stats *plip_get_stats(struct net_device *dev);
static int plip_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static int plip_preempt(void *handle);
static void plip_wakeup(void *handle);
@@ -206,7 +205,6 @@ struct plip_local {
};
struct net_local {
- struct net_device_stats enet_stats;
struct net_device *dev;
struct work_struct immediate;
struct delayed_work deferred;
@@ -221,11 +219,6 @@ struct net_local {
int is_deferred;
int port_owner;
int should_relinquish;
- int (*orig_hard_header)(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr,
- void *saddr, unsigned len);
- int (*orig_hard_header_cache)(struct neighbour *neigh,
- struct hh_cache *hh);
spinlock_t lock;
atomic_t kill_timer;
struct semaphore killed_timer_sem;
@@ -267,6 +260,11 @@ static inline unsigned char read_status (struct net_device *dev)
return port->ops->read_status (port);
}
+static const struct header_ops plip_header_ops = {
+ .create = plip_hard_header,
+ .cache = plip_hard_header_cache,
+};
+
/* Entry point of PLIP driver.
Probe the hardware, and register/initialize the driver.
@@ -285,19 +283,13 @@ plip_init_netdev(struct net_device *dev)
dev->hard_start_xmit = plip_tx_packet;
dev->open = plip_open;
dev->stop = plip_close;
- dev->get_stats = plip_get_stats;
dev->do_ioctl = plip_ioctl;
- dev->header_cache_update = NULL;
+
dev->tx_queue_len = 10;
dev->flags = IFF_POINTOPOINT|IFF_NOARP;
memset(dev->dev_addr, 0xfc, ETH_ALEN);
- /* Set the private structure */
- nl->orig_hard_header = dev->hard_header;
- dev->hard_header = plip_hard_header;
-
- nl->orig_hard_header_cache = dev->hard_header_cache;
- dev->hard_header_cache = plip_hard_header_cache;
+ dev->header_ops = &plip_header_ops;
nl->port_owner = 0;
@@ -388,7 +380,7 @@ plip_timer_bh(struct work_struct *work)
container_of(work, struct net_local, timer.work);
if (!(atomic_read (&nl->kill_timer))) {
- plip_interrupt (-1, nl->dev);
+ plip_interrupt (nl->dev);
schedule_delayed_work(&nl->timer, 1);
}
@@ -430,8 +422,8 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl,
dev->name, snd->state, c0);
} else
error = HS_TIMEOUT;
- nl->enet_stats.tx_errors++;
- nl->enet_stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
} else if (nl->connection == PLIP_CN_RECEIVE) {
if (rcv->state == PLIP_PK_TRIGGER) {
/* Transmission was interrupted. */
@@ -448,7 +440,7 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl,
printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n",
dev->name, rcv->state, c0);
}
- nl->enet_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
rcv->state = PLIP_PK_DONE;
if (rcv->skb) {
@@ -661,7 +653,7 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl,
&rcv->nibble, &rcv->data))
return TIMEOUT;
if (rcv->data != rcv->checksum) {
- nl->enet_stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (net_debug)
printk(KERN_DEBUG "%s: checksum error\n", dev->name);
return ERROR;
@@ -673,8 +665,8 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl,
rcv->skb->protocol=plip_type_trans(rcv->skb, dev);
netif_rx(rcv->skb);
dev->last_rx = jiffies;
- nl->enet_stats.rx_bytes += rcv->length.h;
- nl->enet_stats.rx_packets++;
+ dev->stats.rx_bytes += rcv->length.h;
+ dev->stats.rx_packets++;
rcv->skb = NULL;
if (net_debug > 2)
printk(KERN_DEBUG "%s: receive end\n", dev->name);
@@ -776,7 +768,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
if (nl->connection == PLIP_CN_RECEIVE) {
spin_unlock_irq(&nl->lock);
/* Interrupted. */
- nl->enet_stats.collisions++;
+ dev->stats.collisions++;
return OK;
}
c0 = read_status(dev);
@@ -792,7 +784,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
{enable,disable}_irq *counts*
them. -- AV */
ENABLE(dev->irq);
- nl->enet_stats.collisions++;
+ dev->stats.collisions++;
return OK;
}
disable_parport_interrupts (dev);
@@ -840,9 +832,9 @@ plip_send_packet(struct net_device *dev, struct net_local *nl,
&snd->nibble, snd->checksum))
return TIMEOUT;
- nl->enet_stats.tx_bytes += snd->skb->len;
+ dev->stats.tx_bytes += snd->skb->len;
dev_kfree_skb(snd->skb);
- nl->enet_stats.tx_packets++;
+ dev->stats.tx_packets++;
snd->state = PLIP_PK_DONE;
case PLIP_PK_DONE:
@@ -905,7 +897,7 @@ plip_error(struct net_device *dev, struct net_local *nl,
/* Handle the parallel port interrupts. */
static void
-plip_interrupt(int irq, void *dev_id)
+plip_interrupt(void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *nl;
@@ -996,14 +988,14 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
}
static void
-plip_rewrite_address(struct net_device *dev, struct ethhdr *eth)
+plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth)
{
- struct in_device *in_dev;
+ const struct in_device *in_dev = dev->ip_ptr;
- if ((in_dev=dev->ip_ptr) != NULL) {
+ if (in_dev) {
/* Any address will do - we take the first */
- struct in_ifaddr *ifa=in_dev->ifa_list;
- if (ifa != NULL) {
+ const struct in_ifaddr *ifa = in_dev->ifa_list;
+ if (ifa) {
memcpy(eth->h_source, dev->dev_addr, 6);
memset(eth->h_dest, 0xfc, 2);
memcpy(eth->h_dest+2, &ifa->ifa_address, 4);
@@ -1013,26 +1005,25 @@ plip_rewrite_address(struct net_device *dev, struct ethhdr *eth)
static int
plip_hard_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr,
- void *saddr, unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
- struct net_local *nl = netdev_priv(dev);
int ret;
- if ((ret = nl->orig_hard_header(skb, dev, type, daddr, saddr, len)) >= 0)
+ ret = eth_header(skb, dev, type, daddr, saddr, len);
+ if (ret >= 0)
plip_rewrite_address (dev, (struct ethhdr *)skb->data);
return ret;
}
-int plip_hard_header_cache(struct neighbour *neigh,
+int plip_hard_header_cache(const struct neighbour *neigh,
struct hh_cache *hh)
{
- struct net_local *nl = neigh->dev->priv;
int ret;
- if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0)
- {
+ ret = eth_header_cache(neigh, hh);
+ if (ret == 0) {
struct ethhdr *eth;
eth = (struct ethhdr*)(((u8*)hh->hh_data) +
@@ -1199,15 +1190,6 @@ plip_wakeup(void *handle)
return;
}
-static struct net_device_stats *
-plip_get_stats(struct net_device *dev)
-{
- struct net_local *nl = netdev_priv(dev);
- struct net_device_stats *r = &nl->enet_stats;
-
- return r;
-}
-
static int
plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
@@ -1278,7 +1260,6 @@ static void plip_attach (struct parport *port)
strcpy(dev->name, name);
- SET_MODULE_OWNER(dev);
dev->irq = port->irq;
dev->base_addr = port->base;
if (port->irq == -1) {
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index 27f5b904f48..f023d5b67e6 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -160,7 +160,7 @@ ppp_asynctty_open(struct tty_struct *tty)
err = -ENOMEM;
ap = kzalloc(sizeof(*ap), GFP_KERNEL);
- if (ap == 0)
+ if (!ap)
goto out;
/* initialize the asyncppp structure */
@@ -215,7 +215,7 @@ ppp_asynctty_close(struct tty_struct *tty)
ap = tty->disc_data;
tty->disc_data = NULL;
write_unlock_irq(&disc_data_lock);
- if (ap == 0)
+ if (!ap)
return;
/*
@@ -230,10 +230,10 @@ ppp_asynctty_close(struct tty_struct *tty)
tasklet_kill(&ap->tsk);
ppp_unregister_channel(&ap->chan);
- if (ap->rpkt != 0)
+ if (ap->rpkt)
kfree_skb(ap->rpkt);
skb_queue_purge(&ap->rqueue);
- if (ap->tpkt != 0)
+ if (ap->tpkt)
kfree_skb(ap->tpkt);
kfree(ap);
}
@@ -285,13 +285,13 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
int err, val;
int __user *p = (int __user *)arg;
- if (ap == 0)
+ if (!ap)
return -ENXIO;
err = -EFAULT;
switch (cmd) {
case PPPIOCGCHAN:
err = -ENXIO;
- if (ap == 0)
+ if (!ap)
break;
err = -EFAULT;
if (put_user(ppp_channel_index(&ap->chan), p))
@@ -301,7 +301,7 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
case PPPIOCGUNIT:
err = -ENXIO;
- if (ap == 0)
+ if (!ap)
break;
err = -EFAULT;
if (put_user(ppp_unit_number(&ap->chan), p))
@@ -309,16 +309,11 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
err = 0;
break;
- case TCGETS:
- case TCGETA:
- err = n_tty_ioctl(tty, file, cmd, arg);
- break;
-
case TCFLSH:
/* flush our buffers and the serial port's buffer */
if (arg == TCIOFLUSH || arg == TCOFLUSH)
ppp_async_flush_output(ap);
- err = n_tty_ioctl(tty, file, cmd, arg);
+ err = tty_perform_flush(tty, arg);
break;
case FIONREAD:
@@ -329,7 +324,8 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
break;
default:
- err = -ENOIOCTLCMD;
+ /* Try the various mode ioctls */
+ err = tty_mode_ioctl(tty, file, cmd, arg);
}
ap_put(ap);
@@ -354,7 +350,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
struct asyncppp *ap = ap_get(tty);
unsigned long flags;
- if (ap == 0)
+ if (!ap)
return;
spin_lock_irqsave(&ap->recv_lock, flags);
ppp_async_input(ap, buf, cflags, count);
@@ -373,7 +369,7 @@ ppp_asynctty_wakeup(struct tty_struct *tty)
struct asyncppp *ap = ap_get(tty);
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- if (ap == 0)
+ if (!ap)
return;
set_bit(XMIT_WAKEUP, &ap->xmit_flags);
tasklet_schedule(&ap->tsk);
@@ -688,7 +684,7 @@ ppp_async_push(struct asyncppp *ap)
tty_stuffed = 1;
continue;
}
- if (ap->optr >= ap->olim && ap->tpkt != 0) {
+ if (ap->optr >= ap->olim && ap->tpkt) {
if (ppp_async_encode(ap)) {
/* finished processing ap->tpkt */
clear_bit(XMIT_FULL, &ap->xmit_flags);
@@ -708,7 +704,7 @@ ppp_async_push(struct asyncppp *ap)
clear_bit(XMIT_BUSY, &ap->xmit_flags);
/* any more work to do? if not, exit the loop */
if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags)
- || (!tty_stuffed && ap->tpkt != 0)))
+ || (!tty_stuffed && ap->tpkt)))
break;
/* more work to do, see if we can do it now */
if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags))
@@ -719,7 +715,7 @@ ppp_async_push(struct asyncppp *ap)
flush:
clear_bit(XMIT_BUSY, &ap->xmit_flags);
- if (ap->tpkt != 0) {
+ if (ap->tpkt) {
kfree_skb(ap->tpkt);
ap->tpkt = NULL;
clear_bit(XMIT_FULL, &ap->xmit_flags);
@@ -852,7 +848,7 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
s = 0;
for (i = 0; i < count; ++i) {
c = buf[i];
- if (flags != 0 && flags[i] != 0)
+ if (flags && flags[i] != 0)
continue;
s |= (c & 0x80)? SC_RCV_B7_1: SC_RCV_B7_0;
c = ((c >> 4) ^ c) & 0xf;
@@ -869,7 +865,7 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
n = scan_ordinary(ap, buf, count);
f = 0;
- if (flags != 0 && (ap->state & SC_TOSS) == 0) {
+ if (flags && (ap->state & SC_TOSS) == 0) {
/* check the flags to see if any char had an error */
for (j = 0; j < n; ++j)
if ((f = flags[j]) != 0)
@@ -882,9 +878,9 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
} else if (n > 0 && (ap->state & SC_TOSS) == 0) {
/* stuff the chars in the skb */
skb = ap->rpkt;
- if (skb == 0) {
+ if (!skb) {
skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2);
- if (skb == 0)
+ if (!skb)
goto nomem;
ap->rpkt = skb;
}
@@ -931,7 +927,7 @@ ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
++n;
buf += n;
- if (flags != 0)
+ if (flags)
flags += n;
count -= n;
}
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 4b49d0e8c7e..4f690378bb7 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -367,7 +367,7 @@ static int ppp_release(struct inode *inode, struct file *file)
struct ppp_file *pf = file->private_data;
struct ppp *ppp;
- if (pf != 0) {
+ if (pf) {
file->private_data = NULL;
if (pf->kind == INTERFACE) {
ppp = PF_TO_PPP(pf);
@@ -398,7 +398,7 @@ static ssize_t ppp_read(struct file *file, char __user *buf,
ret = count;
- if (pf == 0)
+ if (!pf)
return -ENXIO;
add_wait_queue(&pf->rwait, &wait);
for (;;) {
@@ -431,7 +431,7 @@ static ssize_t ppp_read(struct file *file, char __user *buf,
set_current_state(TASK_RUNNING);
remove_wait_queue(&pf->rwait, &wait);
- if (skb == 0)
+ if (!skb)
goto out;
ret = -EOVERFLOW;
@@ -455,11 +455,11 @@ static ssize_t ppp_write(struct file *file, const char __user *buf,
struct sk_buff *skb;
ssize_t ret;
- if (pf == 0)
+ if (!pf)
return -ENXIO;
ret = -ENOMEM;
skb = alloc_skb(count + pf->hdrlen, GFP_KERNEL);
- if (skb == 0)
+ if (!skb)
goto out;
skb_reserve(skb, pf->hdrlen);
ret = -EFAULT;
@@ -491,11 +491,11 @@ static unsigned int ppp_poll(struct file *file, poll_table *wait)
struct ppp_file *pf = file->private_data;
unsigned int mask;
- if (pf == 0)
+ if (!pf)
return 0;
poll_wait(file, &pf->rwait, wait);
mask = POLLOUT | POLLWRNORM;
- if (skb_peek(&pf->rq) != 0)
+ if (skb_peek(&pf->rq))
mask |= POLLIN | POLLRDNORM;
if (pf->dead)
mask |= POLLHUP;
@@ -559,7 +559,7 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
void __user *argp = (void __user *)arg;
int __user *p = argp;
- if (pf == 0)
+ if (!pf)
return ppp_unattached_ioctl(pf, file, cmd, arg);
if (cmd == PPPIOCDETACH) {
@@ -689,13 +689,13 @@ static int ppp_ioctl(struct inode *inode, struct file *file,
val &= 0xffff;
}
vj = slhc_init(val2+1, val+1);
- if (vj == 0) {
+ if (!vj) {
printk(KERN_ERR "PPP: no memory (VJ compressor)\n");
err = -ENOMEM;
break;
}
ppp_lock(ppp);
- if (ppp->vj != 0)
+ if (ppp->vj)
slhc_free(ppp->vj);
ppp->vj = vj;
ppp_unlock(ppp);
@@ -786,7 +786,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
if (get_user(unit, p))
break;
ppp = ppp_create_interface(unit, &err);
- if (ppp == 0)
+ if (!ppp)
break;
file->private_data = &ppp->file;
ppp->owner = file;
@@ -803,7 +803,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
mutex_lock(&all_ppp_mutex);
err = -ENXIO;
ppp = ppp_find_unit(unit);
- if (ppp != 0) {
+ if (ppp) {
atomic_inc(&ppp->file.refcnt);
file->private_data = &ppp->file;
err = 0;
@@ -817,7 +817,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file,
spin_lock_bh(&all_channels_lock);
err = -ENXIO;
chan = ppp_find_channel(unit);
- if (chan != 0) {
+ if (chan) {
atomic_inc(&chan->file.refcnt);
file->private_data = &chan->file;
err = 0;
@@ -946,9 +946,9 @@ ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGPPPCSTATS:
memset(&cstats, 0, sizeof(cstats));
- if (ppp->xc_state != 0)
+ if (ppp->xc_state)
ppp->xcomp->comp_stat(ppp->xc_state, &cstats.c);
- if (ppp->rc_state != 0)
+ if (ppp->rc_state)
ppp->rcomp->decomp_stat(ppp->rc_state, &cstats.d);
if (copy_to_user(addr, &cstats, sizeof(cstats)))
break;
@@ -993,14 +993,14 @@ ppp_xmit_process(struct ppp *ppp)
struct sk_buff *skb;
ppp_xmit_lock(ppp);
- if (ppp->dev != 0) {
+ if (ppp->dev) {
ppp_push(ppp);
- while (ppp->xmit_pending == 0
- && (skb = skb_dequeue(&ppp->file.xq)) != 0)
+ while (!ppp->xmit_pending
+ && (skb = skb_dequeue(&ppp->file.xq)))
ppp_send_frame(ppp, skb);
/* If there's no work left to do, tell the core net
code that we can accept some more. */
- if (ppp->xmit_pending == 0 && skb_peek(&ppp->file.xq) == 0)
+ if (!ppp->xmit_pending && !skb_peek(&ppp->file.xq))
netif_wake_queue(ppp->dev);
}
ppp_xmit_unlock(ppp);
@@ -1100,12 +1100,12 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
switch (proto) {
case PPP_IP:
- if (ppp->vj == 0 || (ppp->flags & SC_COMP_TCP) == 0)
+ if (!ppp->vj || (ppp->flags & SC_COMP_TCP) == 0)
break;
/* try to do VJ TCP header compression */
new_skb = alloc_skb(skb->len + ppp->dev->hard_header_len - 2,
GFP_ATOMIC);
- if (new_skb == 0) {
+ if (!new_skb) {
printk(KERN_ERR "PPP: no memory (VJ comp pkt)\n");
goto drop;
}
@@ -1140,7 +1140,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
}
/* try to do packet compression */
- if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
+ if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state
&& proto != PPP_LCP && proto != PPP_CCP) {
if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) {
if (net_ratelimit())
@@ -1185,7 +1185,7 @@ ppp_push(struct ppp *ppp)
struct channel *pch;
struct sk_buff *skb = ppp->xmit_pending;
- if (skb == 0)
+ if (!skb)
return;
list = &ppp->channels;
@@ -1355,7 +1355,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
if (flen == len && nfree == 0)
bits |= E;
frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC);
- if (frag == 0)
+ if (!frag)
goto noskb;
q = skb_put(frag, flen + hdrlen);
@@ -1425,7 +1425,7 @@ ppp_channel_push(struct channel *pch)
struct ppp *ppp;
spin_lock_bh(&pch->downl);
- if (pch->chan != 0) {
+ if (pch->chan) {
while (!skb_queue_empty(&pch->file.xq)) {
skb = skb_dequeue(&pch->file.xq);
if (!pch->chan->ops->start_xmit(pch->chan, skb)) {
@@ -1443,7 +1443,7 @@ ppp_channel_push(struct channel *pch)
if (skb_queue_empty(&pch->file.xq)) {
read_lock_bh(&pch->upl);
ppp = pch->ppp;
- if (ppp != 0)
+ if (ppp)
ppp_xmit_process(ppp);
read_unlock_bh(&pch->upl);
}
@@ -1462,7 +1462,7 @@ ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
{
ppp_recv_lock(ppp);
/* ppp->dev == 0 means interface is closing down */
- if (ppp->dev != 0)
+ if (ppp->dev)
ppp_receive_frame(ppp, skb, pch);
else
kfree_skb(skb);
@@ -1475,19 +1475,19 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
struct channel *pch = chan->ppp;
int proto;
- if (pch == 0 || skb->len == 0) {
+ if (!pch || skb->len == 0) {
kfree_skb(skb);
return;
}
proto = PPP_PROTO(skb);
read_lock_bh(&pch->upl);
- if (pch->ppp == 0 || proto >= 0xc000 || proto == PPP_CCPFRAG) {
+ if (!pch->ppp || proto >= 0xc000 || proto == PPP_CCPFRAG) {
/* put it on the channel queue */
skb_queue_tail(&pch->file.rq, skb);
/* drop old frames if queue too long */
while (pch->file.rq.qlen > PPP_MAX_RQLEN
- && (skb = skb_dequeue(&pch->file.rq)) != 0)
+ && (skb = skb_dequeue(&pch->file.rq)))
kfree_skb(skb);
wake_up_interruptible(&pch->file.rwait);
} else {
@@ -1503,13 +1503,13 @@ ppp_input_error(struct ppp_channel *chan, int code)
struct channel *pch = chan->ppp;
struct sk_buff *skb;
- if (pch == 0)
+ if (!pch)
return;
read_lock_bh(&pch->upl);
- if (pch->ppp != 0) {
+ if (pch->ppp) {
skb = alloc_skb(0, GFP_ATOMIC);
- if (skb != 0) {
+ if (skb) {
skb->len = 0; /* probably unnecessary */
skb->cb[0] = code;
ppp_do_recv(pch->ppp, skb, pch);
@@ -1548,7 +1548,7 @@ static void
ppp_receive_error(struct ppp *ppp)
{
++ppp->stats.rx_errors;
- if (ppp->vj != 0)
+ if (ppp->vj)
slhc_toss(ppp->vj);
}
@@ -1563,7 +1563,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
* Note that some decompressors need to see uncompressed frames
* that come in as well as compressed frames.
*/
- if (ppp->rc_state != 0 && (ppp->rstate & SC_DECOMP_RUN)
+ if (ppp->rc_state && (ppp->rstate & SC_DECOMP_RUN)
&& (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0)
skb = ppp_decompress_frame(ppp, skb);
@@ -1574,13 +1574,13 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
switch (proto) {
case PPP_VJC_COMP:
/* decompress VJ compressed packets */
- if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
+ if (!ppp->vj || (ppp->flags & SC_REJ_COMP_TCP))
goto err;
if (skb_tailroom(skb) < 124 || skb_cloned(skb)) {
/* copy to a new sk_buff with more tailroom */
ns = dev_alloc_skb(skb->len + 128);
- if (ns == 0) {
+ if (!ns) {
printk(KERN_ERR"PPP: no memory (VJ decomp)\n");
goto err;
}
@@ -1606,7 +1606,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
break;
case PPP_VJC_UNCOMP:
- if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
+ if (!ppp->vj || (ppp->flags & SC_REJ_COMP_TCP))
goto err;
/* Until we fix the decompressor need to make sure
@@ -1636,7 +1636,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
skb_queue_tail(&ppp->file.rq, skb);
/* limit queue length by dropping old frames */
while (ppp->file.rq.qlen > PPP_MAX_RQLEN
- && (skb = skb_dequeue(&ppp->file.rq)) != 0)
+ && (skb = skb_dequeue(&ppp->file.rq)))
kfree_skb(skb);
/* wake up any process polling or blocking on read */
wake_up_interruptible(&ppp->file.rwait);
@@ -1718,7 +1718,7 @@ ppp_decompress_frame(struct ppp *ppp, struct sk_buff *skb)
}
ns = dev_alloc_skb(obuff_size);
- if (ns == 0) {
+ if (!ns) {
printk(KERN_ERR "ppp_decompress_frame: no memory\n");
goto err;
}
@@ -1836,7 +1836,7 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
ppp->minseq = ppp->mrq.next->sequence;
/* Pull completed packets off the queue and receive them. */
- while ((skb = ppp_mp_reconstruct(ppp)) != 0)
+ while ((skb = ppp_mp_reconstruct(ppp)))
ppp_receive_nonmp_frame(ppp, skb);
return;
@@ -2002,7 +2002,7 @@ ppp_register_channel(struct ppp_channel *chan)
struct channel *pch;
pch = kzalloc(sizeof(struct channel), GFP_KERNEL);
- if (pch == 0)
+ if (!pch)
return -ENOMEM;
pch->ppp = NULL;
pch->chan = chan;
@@ -2030,7 +2030,7 @@ int ppp_channel_index(struct ppp_channel *chan)
{
struct channel *pch = chan->ppp;
- if (pch != 0)
+ if (pch)
return pch->file.index;
return -1;
}
@@ -2043,9 +2043,9 @@ int ppp_unit_number(struct ppp_channel *chan)
struct channel *pch = chan->ppp;
int unit = -1;
- if (pch != 0) {
+ if (pch) {
read_lock_bh(&pch->upl);
- if (pch->ppp != 0)
+ if (pch->ppp)
unit = pch->ppp->file.index;
read_unlock_bh(&pch->upl);
}
@@ -2061,7 +2061,7 @@ ppp_unregister_channel(struct ppp_channel *chan)
{
struct channel *pch = chan->ppp;
- if (pch == 0)
+ if (!pch)
return; /* should never happen */
chan->ppp = NULL;
@@ -2093,7 +2093,7 @@ ppp_output_wakeup(struct ppp_channel *chan)
{
struct channel *pch = chan->ppp;
- if (pch == 0)
+ if (!pch)
return;
ppp_channel_push(pch);
}
@@ -2124,18 +2124,18 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg)
cp = find_compressor(ccp_option[0]);
#ifdef CONFIG_KMOD
- if (cp == 0) {
+ if (!cp) {
request_module("ppp-compress-%d", ccp_option[0]);
cp = find_compressor(ccp_option[0]);
}
#endif /* CONFIG_KMOD */
- if (cp == 0)
+ if (!cp)
goto out;
err = -ENOBUFS;
if (data.transmit) {
state = cp->comp_alloc(ccp_option, data.length);
- if (state != 0) {
+ if (state) {
ppp_xmit_lock(ppp);
ppp->xstate &= ~SC_COMP_RUN;
ocomp = ppp->xcomp;
@@ -2143,7 +2143,7 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg)
ppp->xcomp = cp;
ppp->xc_state = state;
ppp_xmit_unlock(ppp);
- if (ostate != 0) {
+ if (ostate) {
ocomp->comp_free(ostate);
module_put(ocomp->owner);
}
@@ -2153,7 +2153,7 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg)
} else {
state = cp->decomp_alloc(ccp_option, data.length);
- if (state != 0) {
+ if (state) {
ppp_recv_lock(ppp);
ppp->rstate &= ~SC_DECOMP_RUN;
ocomp = ppp->rcomp;
@@ -2161,7 +2161,7 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg)
ppp->rcomp = cp;
ppp->rc_state = state;
ppp_recv_unlock(ppp);
- if (ostate != 0) {
+ if (ostate) {
ocomp->decomp_free(ostate);
module_put(ocomp->owner);
}
@@ -2228,7 +2228,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
break;
if (inbound) {
/* we will start receiving compressed packets */
- if (ppp->rc_state == 0)
+ if (!ppp->rc_state)
break;
if (ppp->rcomp->decomp_init(ppp->rc_state, dp, len,
ppp->file.index, 0, ppp->mru, ppp->debug)) {
@@ -2237,7 +2237,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
}
} else {
/* we will soon start sending compressed packets */
- if (ppp->xc_state == 0)
+ if (!ppp->xc_state)
break;
if (ppp->xcomp->comp_init(ppp->xc_state, dp, len,
ppp->file.index, 0, ppp->debug))
@@ -2320,11 +2320,11 @@ ppp_register_compressor(struct compressor *cp)
int ret;
spin_lock(&compressor_list_lock);
ret = -EEXIST;
- if (find_comp_entry(cp->compress_proto) != 0)
+ if (find_comp_entry(cp->compress_proto))
goto out;
ret = -ENOMEM;
ce = kmalloc(sizeof(struct compressor_entry), GFP_ATOMIC);
- if (ce == 0)
+ if (!ce)
goto out;
ret = 0;
ce->comp = cp;
@@ -2342,7 +2342,7 @@ ppp_unregister_compressor(struct compressor *cp)
spin_lock(&compressor_list_lock);
ce = find_comp_entry(cp->compress_proto);
- if (ce != 0 && ce->comp == cp) {
+ if (ce && ce->comp == cp) {
list_del(&ce->list);
kfree(ce);
}
@@ -2358,7 +2358,7 @@ find_compressor(int type)
spin_lock(&compressor_list_lock);
ce = find_comp_entry(type);
- if (ce != 0) {
+ if (ce) {
cp = ce->comp;
if (!try_module_get(cp->owner))
cp = NULL;
@@ -2383,7 +2383,7 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st)
st->p.ppp_opackets = ppp->stats.tx_packets;
st->p.ppp_oerrors = ppp->stats.tx_errors;
st->p.ppp_obytes = ppp->stats.tx_bytes;
- if (vj == 0)
+ if (!vj)
return;
st->vj.vjs_packets = vj->sls_o_compressed + vj->sls_o_uncompressed;
st->vj.vjs_compressed = vj->sls_o_compressed;
@@ -2604,11 +2604,11 @@ ppp_connect_channel(struct channel *pch, int unit)
mutex_lock(&all_ppp_mutex);
ppp = ppp_find_unit(unit);
- if (ppp == 0)
+ if (!ppp)
goto out;
write_lock_bh(&pch->upl);
ret = -EINVAL;
- if (pch->ppp != 0)
+ if (pch->ppp)
goto outl;
ppp_lock(ppp);
@@ -2644,7 +2644,7 @@ ppp_disconnect_channel(struct channel *pch)
ppp = pch->ppp;
pch->ppp = NULL;
write_unlock_bh(&pch->upl);
- if (ppp != 0) {
+ if (ppp) {
/* remove it from the ppp unit's list */
ppp_lock(ppp);
list_del(&pch->clist);
diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c
index c0b6d19d145..b35d7944950 100644
--- a/drivers/net/ppp_mppe.c
+++ b/drivers/net/ppp_mppe.c
@@ -55,7 +55,7 @@
#include <linux/mm.h>
#include <linux/ppp_defs.h>
#include <linux/ppp-comp.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include "ppp_mppe.h"
@@ -68,9 +68,7 @@ MODULE_VERSION("1.0.2");
static unsigned int
setup_sg(struct scatterlist *sg, const void *address, unsigned int length)
{
- sg[0].page = virt_to_page(address);
- sg[0].offset = offset_in_page(address);
- sg[0].length = length;
+ sg_set_buf(sg, address, length);
return length;
}
@@ -142,6 +140,8 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state)
struct scatterlist sg[4];
unsigned int nbytes;
+ sg_init_table(sg, 4);
+
nbytes = setup_sg(&sg[0], state->master_key, state->keylen);
nbytes += setup_sg(&sg[1], sha_pad->sha_pad1,
sizeof(sha_pad->sha_pad1));
@@ -168,6 +168,8 @@ static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
if (!initial_key) {
crypto_blkcipher_setkey(state->arc4, state->sha1_digest,
state->keylen);
+ sg_init_table(sg_in, 1);
+ sg_init_table(sg_out, 1);
setup_sg(sg_in, state->sha1_digest, state->keylen);
setup_sg(sg_out, state->session_key, state->keylen);
if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
@@ -423,6 +425,8 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
isize -= 2;
/* Encrypt packet */
+ sg_init_table(sg_in, 1);
+ sg_init_table(sg_out, 1);
setup_sg(sg_in, ibuf, isize);
setup_sg(sg_out, obuf, osize);
if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, isize) != 0) {
@@ -610,6 +614,8 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
* Decrypt the first byte in order to check if it is
* a compressed or uncompressed protocol field.
*/
+ sg_init_table(sg_in, 1);
+ sg_init_table(sg_out, 1);
setup_sg(sg_in, ibuf, 1);
setup_sg(sg_out, obuf, 1);
if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, 1) != 0) {
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index ce64032a465..f0c6a1926a0 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -209,7 +209,7 @@ ppp_sync_open(struct tty_struct *tty)
ap = kzalloc(sizeof(*ap), GFP_KERNEL);
err = -ENOMEM;
- if (ap == 0)
+ if (!ap)
goto out;
/* initialize the syncppp structure */
@@ -262,7 +262,7 @@ ppp_sync_close(struct tty_struct *tty)
ap = tty->disc_data;
tty->disc_data = NULL;
write_unlock_irq(&disc_data_lock);
- if (ap == 0)
+ if (!ap)
return;
/*
@@ -278,7 +278,7 @@ ppp_sync_close(struct tty_struct *tty)
ppp_unregister_channel(&ap->chan);
skb_queue_purge(&ap->rqueue);
- if (ap->tpkt != 0)
+ if (ap->tpkt)
kfree_skb(ap->tpkt);
kfree(ap);
}
@@ -325,13 +325,13 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
int __user *p = (int __user *)arg;
int err, val;
- if (ap == 0)
+ if (!ap)
return -ENXIO;
err = -EFAULT;
switch (cmd) {
case PPPIOCGCHAN:
err = -ENXIO;
- if (ap == 0)
+ if (!ap)
break;
err = -EFAULT;
if (put_user(ppp_channel_index(&ap->chan), p))
@@ -341,7 +341,7 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
case PPPIOCGUNIT:
err = -ENXIO;
- if (ap == 0)
+ if (!ap)
break;
err = -EFAULT;
if (put_user(ppp_unit_number(&ap->chan), p))
@@ -349,16 +349,11 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
err = 0;
break;
- case TCGETS:
- case TCGETA:
- err = n_tty_ioctl(tty, file, cmd, arg);
- break;
-
case TCFLSH:
/* flush our buffers and the serial port's buffer */
if (arg == TCIOFLUSH || arg == TCOFLUSH)
ppp_sync_flush_output(ap);
- err = n_tty_ioctl(tty, file, cmd, arg);
+ err = tty_perform_flush(tty, arg);
break;
case FIONREAD:
@@ -369,7 +364,8 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file,
break;
default:
- err = -ENOIOCTLCMD;
+ err = tty_mode_ioctl(tty, file, cmd, arg);
+ break;
}
sp_put(ap);
@@ -394,7 +390,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
struct syncppp *ap = sp_get(tty);
unsigned long flags;
- if (ap == 0)
+ if (!ap)
return;
spin_lock_irqsave(&ap->recv_lock, flags);
ppp_sync_input(ap, buf, cflags, count);
@@ -413,7 +409,7 @@ ppp_sync_wakeup(struct tty_struct *tty)
struct syncppp *ap = sp_get(tty);
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- if (ap == 0)
+ if (!ap)
return;
set_bit(XMIT_WAKEUP, &ap->xmit_flags);
tasklet_schedule(&ap->tsk);
@@ -655,7 +651,7 @@ ppp_sync_push(struct syncppp *ap)
for (;;) {
if (test_and_clear_bit(XMIT_WAKEUP, &ap->xmit_flags))
tty_stuffed = 0;
- if (!tty_stuffed && ap->tpkt != 0) {
+ if (!tty_stuffed && ap->tpkt) {
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
sent = tty->driver->write(tty, ap->tpkt->data, ap->tpkt->len);
if (sent < 0)
@@ -673,7 +669,7 @@ ppp_sync_push(struct syncppp *ap)
/* haven't made any progress */
spin_unlock_bh(&ap->xmit_lock);
if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags)
- || (!tty_stuffed && ap->tpkt != 0)))
+ || (!tty_stuffed && ap->tpkt)))
break;
if (!spin_trylock_bh(&ap->xmit_lock))
break;
@@ -681,7 +677,7 @@ ppp_sync_push(struct syncppp *ap)
return done;
flush:
- if (ap->tpkt != 0) {
+ if (ap->tpkt) {
kfree_skb(ap->tpkt);
ap->tpkt = NULL;
clear_bit(XMIT_FULL, &ap->xmit_flags);
@@ -736,7 +732,8 @@ ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
ppp_print_buffer ("receive buffer", buf, count);
/* stuff the chars in the skb */
- if ((skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2)) == 0) {
+ skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2);
+ if (!skb) {
printk(KERN_ERR "PPPsync: no memory (input pkt)\n");
goto err;
}
@@ -744,7 +741,7 @@ ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
if (buf[0] != PPP_ALLSTATIONS)
skb_reserve(skb, 2 + (buf[0] & 1));
- if (flags != 0 && *flags) {
+ if (flags && *flags) {
/* error flag set, ignore frame */
goto err;
} else if (count > skb_tailroom(skb)) {
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 9b30cd600a6..a005d8f4c38 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -78,6 +78,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <net/net_namespace.h>
#include <net/sock.h>
#include <asm/uaccess.h>
@@ -102,7 +103,7 @@ static inline int cmp_2_addr(struct pppoe_addr *a, struct pppoe_addr *b)
(memcmp(a->remote, b->remote, ETH_ALEN) == 0));
}
-static inline int cmp_addr(struct pppoe_addr *a, unsigned long sid, char *addr)
+static inline int cmp_addr(struct pppoe_addr *a, __be16 sid, char *addr)
{
return (a->sid == sid &&
(memcmp(a->remote,addr,ETH_ALEN) == 0));
@@ -112,7 +113,7 @@ static inline int cmp_addr(struct pppoe_addr *a, unsigned long sid, char *addr)
#error 8 must be a multiple of PPPOE_HASH_BITS
#endif
-static int hash_item(unsigned int sid, unsigned char *addr)
+static int hash_item(__be16 sid, unsigned char *addr)
{
unsigned char hash = 0;
unsigned int i;
@@ -121,7 +122,7 @@ static int hash_item(unsigned int sid, unsigned char *addr)
hash ^= addr[i];
}
for (i = 0 ; i < sizeof(sid_t)*8 ; i += 8 ){
- hash ^= sid>>i;
+ hash ^= (__force __u32)sid>>i;
}
for (i = 8 ; (i>>=1) >= PPPOE_HASH_BITS ; ) {
hash ^= hash>>i;
@@ -138,7 +139,7 @@ static struct pppox_sock *item_hash_table[PPPOE_HASH_SIZE];
* Set/get/delete/rehash items (internal versions)
*
**********************************************************************/
-static struct pppox_sock *__get_item(unsigned long sid, unsigned char *addr, int ifindex)
+static struct pppox_sock *__get_item(__be16 sid, unsigned char *addr, int ifindex)
{
int hash = hash_item(sid, addr);
struct pppox_sock *ret;
@@ -170,7 +171,7 @@ static int __set_item(struct pppox_sock *po)
return 0;
}
-static struct pppox_sock *__delete_item(unsigned long sid, char *addr, int ifindex)
+static struct pppox_sock *__delete_item(__be16 sid, char *addr, int ifindex)
{
int hash = hash_item(sid, addr);
struct pppox_sock *ret, **src;
@@ -196,7 +197,7 @@ static struct pppox_sock *__delete_item(unsigned long sid, char *addr, int ifind
* Set/get/delete/rehash items
*
**********************************************************************/
-static inline struct pppox_sock *get_item(unsigned long sid,
+static inline struct pppox_sock *get_item(__be16 sid,
unsigned char *addr, int ifindex)
{
struct pppox_sock *po;
@@ -215,7 +216,7 @@ static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp)
struct net_device *dev;
int ifindex;
- dev = dev_get_by_name(sp->sa_addr.pppoe.dev);
+ dev = dev_get_by_name(&init_net, sp->sa_addr.pppoe.dev);
if(!dev)
return NULL;
ifindex = dev->ifindex;
@@ -223,7 +224,7 @@ static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp)
return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex);
}
-static inline struct pppox_sock *delete_item(unsigned long sid, char *addr, int ifindex)
+static inline struct pppox_sock *delete_item(__be16 sid, char *addr, int ifindex)
{
struct pppox_sock *ret;
@@ -300,6 +301,9 @@ static int pppoe_device_event(struct notifier_block *this,
{
struct net_device *dev = (struct net_device *) ptr;
+ if (dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
/* Only look at sockets that are using this specific device. */
switch (event) {
case NETDEV_CHANGEMTU:
@@ -388,12 +392,15 @@ static int pppoe_rcv(struct sk_buff *skb,
if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
goto out;
+ if (dev->nd_net != &init_net)
+ goto drop;
+
if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
goto drop;
ph = pppoe_hdr(skb);
- po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
+ po = get_item(ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
if (po != NULL)
return sk_receive_skb(sk_pppox(po), skb, 0);
drop:
@@ -417,6 +424,9 @@ static int pppoe_disc_rcv(struct sk_buff *skb,
struct pppoe_hdr *ph;
struct pppox_sock *po;
+ if (dev->nd_net != &init_net)
+ goto abort;
+
if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
goto abort;
@@ -427,7 +437,7 @@ static int pppoe_disc_rcv(struct sk_buff *skb,
if (ph->code != PADT_CODE)
goto abort;
- po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
+ po = get_item(ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
if (po) {
struct sock *sk = sk_pppox(po);
@@ -476,12 +486,12 @@ static struct proto pppoe_sk_proto = {
* Initialize a new struct sock.
*
**********************************************************************/
-static int pppoe_create(struct socket *sock)
+static int pppoe_create(struct net *net, struct socket *sock)
{
int error = -ENOMEM;
struct sock *sk;
- sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, 1);
+ sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto);
if (!sk)
goto out;
@@ -593,7 +603,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
/* Don't re-bind if sid==0 */
if (sp->sa_addr.pppoe.sid != 0) {
- dev = dev_get_by_name(sp->sa_addr.pppoe.dev);
+ dev = dev_get_by_name(&init_net, sp->sa_addr.pppoe.dev);
error = -ENODEV;
if (!dev)
@@ -824,8 +834,8 @@ static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock,
}
error = total_len;
- dev->hard_header(skb, dev, ETH_P_PPP_SES,
- po->pppoe_pa.remote, NULL, total_len);
+ dev_hard_header(skb, dev, ETH_P_PPP_SES,
+ po->pppoe_pa.remote, NULL, total_len);
memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
@@ -876,8 +886,8 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
skb->protocol = __constant_htons(ETH_P_PPP_SES);
skb->dev = dev;
- dev->hard_header(skb, dev, ETH_P_PPP_SES,
- po->pppoe_pa.remote, NULL, data_len);
+ dev_hard_header(skb, dev, ETH_P_PPP_SES,
+ po->pppoe_pa.remote, NULL, data_len);
dev_queue_xmit(skb);
@@ -945,6 +955,7 @@ static int pppoe_seq_show(struct seq_file *seq, void *v)
{
struct pppox_sock *po;
char *dev_name;
+ DECLARE_MAC_BUF(mac);
if (v == SEQ_START_TOKEN) {
seq_puts(seq, "Id Address Device\n");
@@ -954,11 +965,8 @@ static int pppoe_seq_show(struct seq_file *seq, void *v)
po = v;
dev_name = po->pppoe_pa.dev;
- seq_printf(seq, "%08X %02X:%02X:%02X:%02X:%02X:%02X %8s\n",
- po->pppoe_pa.sid,
- po->pppoe_pa.remote[0], po->pppoe_pa.remote[1],
- po->pppoe_pa.remote[2], po->pppoe_pa.remote[3],
- po->pppoe_pa.remote[4], po->pppoe_pa.remote[5], dev_name);
+ seq_printf(seq, "%08X %s %8s\n",
+ po->pppoe_pa.sid, print_mac(mac, po->pppoe_pa.remote), dev_name);
out:
return 0;
}
@@ -1042,7 +1050,7 @@ static int __init pppoe_proc_init(void)
{
struct proc_dir_entry *p;
- p = create_proc_entry("net/pppoe", S_IRUGO, NULL);
+ p = create_proc_entry("pppoe", S_IRUGO, init_net.proc_net);
if (!p)
return -ENOMEM;
@@ -1113,7 +1121,7 @@ static void __exit pppoe_exit(void)
dev_remove_pack(&pppoes_ptype);
dev_remove_pack(&pppoed_ptype);
unregister_netdevice_notifier(&pppoe_notifier);
- remove_proc_entry("net/pppoe", NULL);
+ remove_proc_entry("pppoe", init_net.proc_net);
proto_unregister(&pppoe_sk_proto);
}
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index abe91cb595f..a7556cd2df7 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -91,6 +91,7 @@
#include <linux/hash.h>
#include <linux/sort.h>
#include <linux/proc_fs.h>
+#include <net/net_namespace.h>
#include <net/dst.h>
#include <net/ip.h>
#include <net/udp.h>
@@ -487,7 +488,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
{
struct pppol2tp_session *session = NULL;
struct pppol2tp_tunnel *tunnel;
- unsigned char *ptr;
+ unsigned char *ptr, *optr;
u16 hdrflags;
u16 tunnel_id, session_id;
int length;
@@ -495,7 +496,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
tunnel = pppol2tp_sock_to_tunnel(sock);
if (tunnel == NULL)
- goto error;
+ goto no_tunnel;
/* UDP always verifies the packet length. */
__skb_pull(skb, sizeof(struct udphdr));
@@ -508,7 +509,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
}
/* Point to L2TP header */
- ptr = skb->data;
+ optr = ptr = skb->data;
/* Get L2TP header flags */
hdrflags = ntohs(*(__be16*)ptr);
@@ -636,12 +637,14 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
/* If offset bit set, skip it. */
if (hdrflags & L2TP_HDRFLAG_O) {
offset = ntohs(*(__be16 *)ptr);
- skb->transport_header += 2 + offset;
- if (!pskb_may_pull(skb, skb_transport_offset(skb) + 2))
- goto discard;
+ ptr += 2 + offset;
}
- __skb_pull(skb, skb_transport_offset(skb));
+ offset = ptr - optr;
+ if (!pskb_may_pull(skb, offset))
+ goto discard;
+
+ __skb_pull(skb, offset);
/* Skip PPP header, if present. In testing, Microsoft L2TP clients
* don't send the PPP header (PPP header compression enabled), but
@@ -651,6 +654,9 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
* Note that skb->data[] isn't dereferenced from a u16 ptr here since
* the field may be unaligned.
*/
+ if (!pskb_may_pull(skb, 2))
+ goto discard;
+
if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03))
skb_pull(skb, 2);
@@ -708,6 +714,10 @@ discard:
return 0;
error:
+ /* Put UDP header back */
+ __skb_push(skb, sizeof(struct udphdr));
+
+no_tunnel:
return 1;
}
@@ -1049,6 +1059,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
/* Get routing info from the tunnel socket */
dst_release(skb->dst);
skb->dst = sk_dst_get(sk_tun);
+ skb_orphan(skb);
+ skb->sk = sk_tun;
/* Queue the packet to IP for output */
len = skb->len;
@@ -1410,12 +1422,12 @@ static struct proto pppol2tp_sk_proto = {
/* socket() handler. Initialize a new struct sock.
*/
-static int pppol2tp_create(struct socket *sock)
+static int pppol2tp_create(struct net *net, struct socket *sock)
{
int error = -ENOMEM;
struct sock *sk;
- sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, 1);
+ sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto);
if (!sk)
goto out;
@@ -2444,7 +2456,7 @@ static int __init pppol2tp_init(void)
goto out_unregister_pppol2tp_proto;
#ifdef CONFIG_PROC_FS
- pppol2tp_proc = create_proc_entry("pppol2tp", 0, proc_net);
+ pppol2tp_proc = create_proc_entry("pppol2tp", 0, init_net.proc_net);
if (!pppol2tp_proc) {
err = -ENOMEM;
goto out_unregister_pppox_proto;
@@ -2469,7 +2481,7 @@ static void __exit pppol2tp_exit(void)
unregister_pppox_proto(PX_PROTO_OL2TP);
#ifdef CONFIG_PROC_FS
- remove_proc_entry("pppol2tp", proc_net);
+ remove_proc_entry("pppol2tp", init_net.proc_net);
#endif
proto_unregister(&pppol2tp_sk_proto);
}
diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c
index 25c52b55c38..c6898c1fc54 100644
--- a/drivers/net/pppox.c
+++ b/drivers/net/pppox.c
@@ -104,10 +104,13 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
EXPORT_SYMBOL(pppox_ioctl);
-static int pppox_create(struct socket *sock, int protocol)
+static int pppox_create(struct net *net, struct socket *sock, int protocol)
{
int rc = -EPROTOTYPE;
+ if (net != &init_net)
+ return -EAFNOSUPPORT;
+
if (protocol < 0 || protocol > PX_MAX_PROTO)
goto out;
@@ -123,7 +126,7 @@ static int pppox_create(struct socket *sock, int protocol)
!try_module_get(pppox_protos[protocol]->owner))
goto out;
- rc = pppox_protos[protocol]->create(sock);
+ rc = pppox_protos[protocol]->create(net, sock);
module_put(pppox_protos[protocol]->owner);
out:
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
index e5650391843..0a42bf51746 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -351,19 +351,13 @@ static int gelic_net_alloc_rx_skbs(struct gelic_net_card *card)
static void gelic_net_release_tx_descr(struct gelic_net_card *card,
struct gelic_net_descr *descr)
{
- struct sk_buff *skb;
+ struct sk_buff *skb = descr->skb;
+ BUG_ON(!(descr->data_status & (1 << GELIC_NET_TXDESC_TAIL)));
- if (descr->data_status & (1 << GELIC_NET_TXDESC_TAIL)) {
- /* 2nd descriptor */
- skb = descr->skb;
- dma_unmap_single(ctodev(card), descr->buf_addr, skb->len,
- DMA_TO_DEVICE);
- dev_kfree_skb_any(skb);
- } else {
- dma_unmap_single(ctodev(card), descr->buf_addr,
- descr->buf_size, DMA_TO_DEVICE);
- }
+ dma_unmap_single(ctodev(card), descr->buf_addr, skb->len,
+ DMA_TO_DEVICE);
+ dev_kfree_skb_any(skb);
descr->buf_addr = 0;
descr->buf_size = 0;
@@ -426,7 +420,7 @@ static void gelic_net_release_tx_chain(struct gelic_net_card *card, int stop)
release ++;
}
out:
- if (!stop && (2 < release))
+ if (!stop && release)
netif_wake_queue(card->netdev);
}
@@ -556,6 +550,7 @@ static int gelic_net_stop(struct net_device *netdev)
{
struct gelic_net_card *card = netdev_priv(netdev);
+ napi_disable(&card->napi);
netif_stop_queue(netdev);
/* turn off DMA, force end */
@@ -592,13 +587,10 @@ gelic_net_get_next_tx_descr(struct gelic_net_card *card)
{
if (!card->tx_chain.head)
return NULL;
- /* see if we can two consecutive free descrs */
+ /* see if the next descriptor is free */
if (card->tx_chain.tail != card->tx_chain.head->next &&
gelic_net_get_descr_status(card->tx_chain.head) ==
- GELIC_NET_DESCR_NOT_IN_USE &&
- card->tx_chain.tail != card->tx_chain.head->next->next &&
- gelic_net_get_descr_status(card->tx_chain.head->next) ==
- GELIC_NET_DESCR_NOT_IN_USE )
+ GELIC_NET_DESCR_NOT_IN_USE)
return card->tx_chain.head;
else
return NULL;
@@ -609,44 +601,66 @@ gelic_net_get_next_tx_descr(struct gelic_net_card *card)
* gelic_net_set_txdescr_cmdstat - sets the tx descriptor command field
* @descr: descriptor structure to fill out
* @skb: packet to consider
- * @middle: middle of frame
*
* fills out the command and status field of the descriptor structure,
* depending on hardware checksum settings. This function assumes a wmb()
* has executed before.
*/
static void gelic_net_set_txdescr_cmdstat(struct gelic_net_descr *descr,
- struct sk_buff *skb, int middle)
+ struct sk_buff *skb)
{
- u32 eofr;
-
- if (middle)
- eofr = 0;
- else
- eofr = GELIC_NET_DMAC_CMDSTAT_END_FRAME;
-
if (skb->ip_summed != CHECKSUM_PARTIAL)
- descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS | eofr;
+ descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS |
+ GELIC_NET_DMAC_CMDSTAT_END_FRAME;
else {
/* is packet ip?
* if yes: tcp? udp? */
if (skb->protocol == htons(ETH_P_IP)) {
if (ip_hdr(skb)->protocol == IPPROTO_TCP)
descr->dmac_cmd_status =
- GELIC_NET_DMAC_CMDSTAT_TCPCS | eofr;
+ GELIC_NET_DMAC_CMDSTAT_TCPCS |
+ GELIC_NET_DMAC_CMDSTAT_END_FRAME;
+
else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
descr->dmac_cmd_status =
- GELIC_NET_DMAC_CMDSTAT_UDPCS | eofr;
+ GELIC_NET_DMAC_CMDSTAT_UDPCS |
+ GELIC_NET_DMAC_CMDSTAT_END_FRAME;
else /*
* the stack should checksum non-tcp and non-udp
* packets on his own: NETIF_F_IP_CSUM
*/
descr->dmac_cmd_status =
- GELIC_NET_DMAC_CMDSTAT_NOCS | eofr;
+ GELIC_NET_DMAC_CMDSTAT_NOCS |
+ GELIC_NET_DMAC_CMDSTAT_END_FRAME;
}
}
}
+static inline struct sk_buff *gelic_put_vlan_tag(struct sk_buff *skb,
+ unsigned short tag)
+{
+ struct vlan_ethhdr *veth;
+ static unsigned int c;
+
+ if (skb_headroom(skb) < VLAN_HLEN) {
+ struct sk_buff *sk_tmp = skb;
+ pr_debug("%s: hd=%d c=%ud\n", __func__, skb_headroom(skb), c);
+ skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN);
+ if (!skb)
+ return NULL;
+ dev_kfree_skb_any(sk_tmp);
+ }
+ veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
+
+ /* Move the mac addresses to the top of buffer */
+ memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
+
+ veth->h_vlan_proto = __constant_htons(ETH_P_8021Q);
+ veth->h_vlan_TCI = htons(tag);
+
+ return skb;
+}
+
/**
* gelic_net_prepare_tx_descr_v - get dma address of skb_data
* @card: card structure
@@ -660,65 +674,35 @@ static int gelic_net_prepare_tx_descr_v(struct gelic_net_card *card,
struct gelic_net_descr *descr,
struct sk_buff *skb)
{
- dma_addr_t buf[2];
- unsigned int vlan_len;
- struct gelic_net_descr *sec_descr = descr->next;
+ dma_addr_t buf;
- if (skb->len < GELIC_NET_VLAN_POS)
- return -EINVAL;
-
- vlan_len = GELIC_NET_VLAN_POS;
- memcpy(&descr->vlan, skb->data, vlan_len);
if (card->vlan_index != -1) {
- /* internal vlan tag used */
- descr->vlan.h_vlan_proto = htons(ETH_P_8021Q); /* vlan 0x8100*/
- descr->vlan.h_vlan_TCI = htons(card->vlan_id[card->vlan_index]);
- vlan_len += VLAN_HLEN; /* added for above two lines */
+ struct sk_buff *skb_tmp;
+ skb_tmp = gelic_put_vlan_tag(skb,
+ card->vlan_id[card->vlan_index]);
+ if (!skb_tmp)
+ return -ENOMEM;
+ skb = skb_tmp;
}
- /* map data area */
- buf[0] = dma_map_single(ctodev(card), &descr->vlan,
- vlan_len, DMA_TO_DEVICE);
+ buf = dma_map_single(ctodev(card), skb->data, skb->len, DMA_TO_DEVICE);
- if (!buf[0]) {
- dev_err(ctodev(card),
- "dma map 1 failed (%p, %i). Dropping packet\n",
- skb->data, vlan_len);
- return -ENOMEM;
- }
-
- buf[1] = dma_map_single(ctodev(card), skb->data + GELIC_NET_VLAN_POS,
- skb->len - GELIC_NET_VLAN_POS,
- DMA_TO_DEVICE);
-
- if (!buf[1]) {
+ if (!buf) {
dev_err(ctodev(card),
"dma map 2 failed (%p, %i). Dropping packet\n",
- skb->data + GELIC_NET_VLAN_POS,
- skb->len - GELIC_NET_VLAN_POS);
- dma_unmap_single(ctodev(card), buf[0], vlan_len,
- DMA_TO_DEVICE);
+ skb->data, skb->len);
return -ENOMEM;
}
- /* first descr */
- descr->buf_addr = buf[0];
- descr->buf_size = vlan_len;
- descr->skb = NULL; /* not used */
+ descr->buf_addr = buf;
+ descr->buf_size = skb->len;
+ descr->skb = skb;
descr->data_status = 0;
- descr->next_descr_addr = descr->next->bus_addr;
- gelic_net_set_txdescr_cmdstat(descr, skb, 1); /* not the frame end */
-
- /* second descr */
- sec_descr->buf_addr = buf[1];
- sec_descr->buf_size = skb->len - GELIC_NET_VLAN_POS;
- sec_descr->skb = skb;
- sec_descr->data_status = 0;
- sec_descr->next_descr_addr = 0; /* terminate hw descr */
- gelic_net_set_txdescr_cmdstat(sec_descr, skb, 0);
+ descr->next_descr_addr = 0; /* terminate hw descr */
+ gelic_net_set_txdescr_cmdstat(descr, skb);
/* bump free descriptor pointer */
- card->tx_chain.head = sec_descr->next;
+ card->tx_chain.head = descr->next;
return 0;
}
@@ -732,25 +716,17 @@ static int gelic_net_kick_txdma(struct gelic_net_card *card,
struct gelic_net_descr *descr)
{
int status = 0;
- int count = 10;
if (card->tx_dma_progress)
return 0;
if (gelic_net_get_descr_status(descr) == GELIC_NET_DESCR_CARDOWNED) {
card->tx_dma_progress = 1;
- /* sometimes we need retry here */
- while (count--) {
- status = lv1_net_start_tx_dma(bus_id(card),
- dev_id(card),
- descr->bus_addr, 0);
- if (!status)
- break;
- }
- if (!count)
+ status = lv1_net_start_tx_dma(bus_id(card), dev_id(card),
+ descr->bus_addr, 0);
+ if (status)
dev_info(ctodev(card), "lv1_net_start_txdma failed," \
- "status=%d %#lx\n",
- status, card->irq_status);
+ "status=%d\n", status);
}
return status;
}
@@ -987,32 +963,24 @@ refill:
* if the quota is exceeded, but the driver has still packets.
*
*/
-static int gelic_net_poll(struct net_device *netdev, int *budget)
+static int gelic_net_poll(struct napi_struct *napi, int budget)
{
- struct gelic_net_card *card = netdev_priv(netdev);
- int packets_to_do, packets_done = 0;
- int no_more_packets = 0;
-
- packets_to_do = min(*budget, netdev->quota);
+ struct gelic_net_card *card = container_of(napi, struct gelic_net_card, napi);
+ struct net_device *netdev = card->netdev;
+ int packets_done = 0;
- while (packets_to_do) {
- if (gelic_net_decode_one_descr(card)) {
- packets_done++;
- packets_to_do--;
- } else {
- /* no more packets for the stack */
- no_more_packets = 1;
+ while (packets_done < budget) {
+ if (!gelic_net_decode_one_descr(card))
break;
- }
+
+ packets_done++;
}
- netdev->quota -= packets_done;
- *budget -= packets_done;
- if (no_more_packets) {
- netif_rx_complete(netdev);
+
+ if (packets_done < budget) {
+ netif_rx_complete(netdev, napi);
gelic_net_rx_irq_on(card);
- return 0;
- } else
- return 1;
+ }
+ return packets_done;
}
/**
* gelic_net_change_mtu - changes the MTU of an interface
@@ -1055,7 +1023,7 @@ static irqreturn_t gelic_net_interrupt(int irq, void *ptr)
if (status & GELIC_NET_RXINT) {
gelic_net_rx_irq_off(card);
- netif_rx_schedule(netdev);
+ netif_rx_schedule(netdev, &card->napi);
}
if (status & GELIC_NET_TXINT) {
@@ -1159,6 +1127,8 @@ static int gelic_net_open(struct net_device *netdev)
if (gelic_net_alloc_rx_skbs(card))
goto alloc_skbs_failed;
+ napi_enable(&card->napi);
+
card->tx_dma_progress = 0;
card->ghiintmask = GELIC_NET_RXINT | GELIC_NET_TXINT;
@@ -1360,9 +1330,6 @@ static void gelic_net_setup_netdev_ops(struct net_device *netdev)
/* tx watchdog */
netdev->tx_timeout = &gelic_net_tx_timeout;
netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
- /* NAPI */
- netdev->poll = &gelic_net_poll;
- netdev->weight = GELIC_NET_NAPI_WEIGHT;
netdev->ethtool_ops = &gelic_net_ethtool_ops;
}
@@ -1381,8 +1348,8 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card)
unsigned int i;
int status;
u64 v1, v2;
+ DECLARE_MAC_BUF(mac);
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &card->dev->core);
spin_lock_init(&card->tx_dma_lock);
@@ -1390,6 +1357,9 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card)
gelic_net_setup_netdev_ops(netdev);
+ netif_napi_add(netdev, &card->napi,
+ gelic_net_poll, GELIC_NET_NAPI_WEIGHT);
+
netdev->features = NETIF_F_IP_CSUM;
status = lv1_net_control(bus_id(card), dev_id(card),
@@ -1404,10 +1374,8 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card)
v1 <<= 16;
memcpy(addr.sa_data, &v1, ETH_ALEN);
memcpy(netdev->dev_addr, addr.sa_data, ETH_ALEN);
- dev_info(ctodev(card), "MAC addr %02x:%02x:%02x:%02x:%02x:%02x\n",
- netdev->dev_addr[0], netdev->dev_addr[1],
- netdev->dev_addr[2], netdev->dev_addr[3],
- netdev->dev_addr[4], netdev->dev_addr[5]);
+ dev_info(ctodev(card), "MAC addr %s\n",
+ print_mac(mac, netdev->dev_addr));
card->vlan_index = -1; /* no vlan */
for (i = 0; i < GELIC_NET_VLAN_MAX; i++) {
@@ -1430,8 +1398,11 @@ static int gelic_net_setup_netdev(struct gelic_net_card *card)
dev_dbg(ctodev(card), "vlan_id:%d, %lx\n", i, v1);
}
}
- if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1])
+
+ if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1]) {
card->vlan_index = GELIC_NET_VLAN_WIRED - 1;
+ netdev->hard_header_len += VLAN_HLEN;
+ }
status = register_netdev(netdev);
if (status) {
diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h
index a9c4c4fc254..968560269a3 100644
--- a/drivers/net/ps3_gelic_net.h
+++ b/drivers/net/ps3_gelic_net.h
@@ -194,6 +194,7 @@ struct gelic_net_descr_chain {
struct gelic_net_card {
struct net_device *netdev;
+ struct napi_struct napi;
/*
* hypervisor requires irq_status should be
* 8 bytes aligned, but u64 member is
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index ea151315050..a5791114b7b 100755..100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -31,7 +31,6 @@
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/if_vlan.h>
-#include <linux/init.h>
#include <linux/delay.h>
#include <linux/mm.h>
@@ -82,7 +81,7 @@ typedef enum {
} PHY_DEVICE_et;
typedef struct {
- PHY_DEVICE_et phyDevice;
+ PHY_DEVICE_et phyDevice;
u32 phyIdOUI;
u16 phyIdModel;
char *name;
@@ -331,7 +330,7 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
PCI_DMA_FROMDEVICE);
err = pci_dma_mapping_error(map);
if(err) {
- printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
+ printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
qdev->ndev->name, err);
dev_kfree_skb(lrg_buf_cb->skb);
lrg_buf_cb->skb = NULL;
@@ -885,14 +884,14 @@ static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev)
u16 reg;
/* Enable Auto-negotiation sense */
- ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg,
+ ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg,
PHYAddr[qdev->mac_index]);
reg |= PETBI_TBI_AUTO_SENSE;
- ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg,
+ ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg,
PHYAddr[qdev->mac_index]);
ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER,
- PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX,
+ PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX,
PHYAddr[qdev->mac_index]);
ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG,
@@ -946,7 +945,7 @@ static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr)
ql_mii_write_reg_ex(qdev, 0x10, 0x2806, miiAddr);
/* Write new PHYAD w/bit 5 set */
ql_mii_write_reg_ex(qdev, 0x11, 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr);
- /*
+ /*
* Disable diagnostic mode bit 2 = 0
* Power up device bit 11 = 0
* Link up (on) and activity (blink)
@@ -956,18 +955,18 @@ static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr)
ql_mii_write_reg(qdev, 0x1c, 0xfaf0);
}
-static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev,
+static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev,
u16 phyIdReg0, u16 phyIdReg1)
{
PHY_DEVICE_et result = PHY_TYPE_UNKNOWN;
- u32 oui;
+ u32 oui;
u16 model;
- int i;
+ int i;
if (phyIdReg0 == 0xffff) {
return result;
}
-
+
if (phyIdReg1 == 0xffff) {
return result;
}
@@ -985,7 +984,7 @@ static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev,
printk(KERN_INFO "%s: Phy: %s\n",
qdev->ndev->name, PHY_DEVICES[i].name);
-
+
break;
}
}
@@ -1034,7 +1033,7 @@ static int ql_is_full_dup(struct ql3_adapter *qdev)
{
if (ql_mii_read_reg(qdev, 0x1A, &reg))
return 0;
-
+
return ((reg & 0x0080) && (reg & 0x1000)) != 0;
}
case PHY_VITESSE_VSC8211:
@@ -1083,19 +1082,19 @@ static int PHY_Setup(struct ql3_adapter *qdev)
/* Check if we have a Agere PHY */
if ((reg1 == 0xffff) || (reg2 == 0xffff)) {
- /* Determine which MII address we should be using
+ /* Determine which MII address we should be using
determined by the index of the card */
if (qdev->mac_index == 0) {
miiAddr = MII_AGERE_ADDR_1;
} else {
miiAddr = MII_AGERE_ADDR_2;
}
-
+
err =ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, &reg1, miiAddr);
if(err != 0) {
printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
qdev->ndev->name);
- return err;
+ return err;
}
err = ql_mii_read_reg_ex(qdev, PHY_ID_1_REG, &reg2, miiAddr);
@@ -1104,9 +1103,9 @@ static int PHY_Setup(struct ql3_adapter *qdev)
qdev->ndev->name);
return err;
}
-
+
/* We need to remember to initialize the Agere PHY */
- agereAddrChangeNeeded = true;
+ agereAddrChangeNeeded = true;
}
/* Determine the particular PHY we have on board to apply
@@ -1115,7 +1114,7 @@ static int PHY_Setup(struct ql3_adapter *qdev)
if ((qdev->phyType == PHY_AGERE_ET1011C) && agereAddrChangeNeeded) {
/* need this here so address gets changed */
- phyAgereSpecificInit(qdev, miiAddr);
+ phyAgereSpecificInit(qdev, miiAddr);
} else if (qdev->phyType == PHY_TYPE_UNKNOWN) {
printk(KERN_ERR "%s: PHY is unknown\n", qdev->ndev->name);
return -EIO;
@@ -1428,7 +1427,7 @@ static int ql_this_adapter_controls_port(struct ql3_adapter *qdev)
static void ql_phy_reset_ex(struct ql3_adapter *qdev)
{
- ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET,
+ ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET,
PHYAddr[qdev->mac_index]);
}
@@ -1439,7 +1438,7 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
if(qdev->phyType == PHY_AGERE_ET1011C) {
/* turn off external loopback */
- ql_mii_write_reg(qdev, 0x13, 0x0000);
+ ql_mii_write_reg(qdev, 0x13, 0x0000);
}
if(qdev->mac_index == 0)
@@ -1453,23 +1452,18 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
portConfiguration = PORT_CONFIG_DEFAULT;
/* Set the 1000 advertisements */
- ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, &reg,
+ ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, &reg,
PHYAddr[qdev->mac_index]);
reg &= ~PHY_GIG_ALL_PARAMS;
- if(portConfiguration &
- PORT_CONFIG_FULL_DUPLEX_ENABLED &
- PORT_CONFIG_1000MB_SPEED) {
- reg |= PHY_GIG_ADV_1000F;
- }
-
- if(portConfiguration &
- PORT_CONFIG_HALF_DUPLEX_ENABLED &
- PORT_CONFIG_1000MB_SPEED) {
- reg |= PHY_GIG_ADV_1000H;
+ if(portConfiguration & PORT_CONFIG_1000MB_SPEED) {
+ if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED)
+ reg |= PHY_GIG_ADV_1000F;
+ else
+ reg |= PHY_GIG_ADV_1000H;
}
- ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg,
+ ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg,
PHYAddr[qdev->mac_index]);
/* Set the 10/100 & pause negotiation advertisements */
@@ -1483,7 +1477,7 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) {
if(portConfiguration & PORT_CONFIG_100MB_SPEED)
reg |= PHY_NEG_ADV_100F;
-
+
if(portConfiguration & PORT_CONFIG_10MB_SPEED)
reg |= PHY_NEG_ADV_10F;
}
@@ -1491,22 +1485,22 @@ static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) {
if(portConfiguration & PORT_CONFIG_100MB_SPEED)
reg |= PHY_NEG_ADV_100H;
-
+
if(portConfiguration & PORT_CONFIG_10MB_SPEED)
reg |= PHY_NEG_ADV_10H;
}
if(portConfiguration &
PORT_CONFIG_1000MB_SPEED) {
- reg |= 1;
+ reg |= 1;
}
- ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg,
+ ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg,
PHYAddr[qdev->mac_index]);
ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, PHYAddr[qdev->mac_index]);
-
- ql_mii_write_reg_ex(qdev, CONTROL_REG,
+
+ ql_mii_write_reg_ex(qdev, CONTROL_REG,
reg | PHY_CTRL_RESTART_NEG | PHY_CTRL_AUTO_NEG,
PHYAddr[qdev->mac_index]);
}
@@ -1646,8 +1640,11 @@ static int ql_finish_auto_neg(struct ql3_adapter *qdev)
return 0;
}
-static void ql_link_state_machine(struct ql3_adapter *qdev)
+static void ql_link_state_machine_work(struct work_struct *work)
{
+ struct ql3_adapter *qdev =
+ container_of(work, struct ql3_adapter, link_state_work.work);
+
u32 curr_link_state;
unsigned long hw_flags;
@@ -1661,7 +1658,11 @@ static void ql_link_state_machine(struct ql3_adapter *qdev)
"%s: Reset in progress, skip processing link "
"state.\n", qdev->ndev->name);
- spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+ /* Restart timer on 2 second interval. */
+ mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);\
+
return;
}
@@ -1706,6 +1707,9 @@ static void ql_link_state_machine(struct ql3_adapter *qdev)
break;
}
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+ /* Restart timer on 2 second interval. */
+ mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
}
/*
@@ -1753,7 +1757,7 @@ static int ql_mii_setup(struct ql3_adapter *qdev)
return -1;
if (qdev->device_id == QL3032_DEVICE_ID)
- ql_write_page0_reg(qdev,
+ ql_write_page0_reg(qdev,
&port_regs->macMIIMgmtControlReg, 0x0f00000);
/* Divide 125MHz clock by 28 to meet PHY timing requirements */
@@ -1866,8 +1870,6 @@ static void ql_get_drvinfo(struct net_device *ndev,
strncpy(drvinfo->version, ql3xxx_driver_version, 32);
strncpy(drvinfo->fw_version, "N/A", 32);
strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
- drvinfo->n_stats = 0;
- drvinfo->testinfo_len = 0;
drvinfo->regdump_len = 0;
drvinfo->eedump_len = 0;
}
@@ -1939,7 +1941,7 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev)
err = pci_dma_mapping_error(map);
if(err) {
- printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
+ printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
qdev->ndev->name, err);
dev_kfree_skb(lrg_buf_cb->skb);
lrg_buf_cb->skb = NULL;
@@ -2047,14 +2049,14 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
printk(KERN_WARNING "Frame short but, frame was padded and sent.\n");
}
-
+
tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
/* Check the transmit response flags for any errors */
if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
printk(KERN_ERR "Frame too short to be legal, frame not sent.\n");
- qdev->stats.tx_errors++;
+ qdev->ndev->stats.tx_errors++;
retval = -EIO;
goto frame_not_sent;
}
@@ -2062,7 +2064,7 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
if(tx_cb->seg_count == 0) {
printk(KERN_ERR "tx_cb->seg_count == 0: %d\n", mac_rsp->transaction_id);
- qdev->stats.tx_errors++;
+ qdev->ndev->stats.tx_errors++;
retval = -EIO;
goto invalid_seg_count;
}
@@ -2081,8 +2083,8 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
PCI_DMA_TODEVICE);
}
}
- qdev->stats.tx_packets++;
- qdev->stats.tx_bytes += tx_cb->skb->len;
+ qdev->ndev->stats.tx_packets++;
+ qdev->ndev->stats.tx_bytes += tx_cb->skb->len;
frame_not_sent:
dev_kfree_skb_irq(tx_cb->skb);
@@ -2111,13 +2113,13 @@ static struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev)
/*
* The difference between 3022 and 3032 for inbound completions:
- * 3022 uses two buffers per completion. The first buffer contains
- * (some) header info, the second the remainder of the headers plus
- * the data. For this chip we reserve some space at the top of the
- * receive buffer so that the header info in buffer one can be
- * prepended to the buffer two. Buffer two is the sent up while
+ * 3022 uses two buffers per completion. The first buffer contains
+ * (some) header info, the second the remainder of the headers plus
+ * the data. For this chip we reserve some space at the top of the
+ * receive buffer so that the header info in buffer one can be
+ * prepended to the buffer two. Buffer two is the sent up while
* buffer one is returned to the hardware to be reused.
- * 3032 receives all of it's data and headers in one buffer for a
+ * 3032 receives all of it's data and headers in one buffer for a
* simpler process. 3032 also supports checksum verification as
* can be seen in ql_process_macip_rx_intr().
*/
@@ -2141,8 +2143,8 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
lrg_buf_cb2 = ql_get_lbuf(qdev);
skb = lrg_buf_cb2->skb;
- qdev->stats.rx_packets++;
- qdev->stats.rx_bytes += length;
+ qdev->ndev->stats.rx_packets++;
+ qdev->ndev->stats.rx_bytes += length;
skb_put(skb, length);
pci_unmap_single(qdev->pdev,
@@ -2208,13 +2210,13 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
skb_push(skb2, size), size);
} else {
u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum);
- if (checksum &
- (IB_IP_IOCB_RSP_3032_ICE |
- IB_IP_IOCB_RSP_3032_CE)) {
+ if (checksum &
+ (IB_IP_IOCB_RSP_3032_ICE |
+ IB_IP_IOCB_RSP_3032_CE)) {
printk(KERN_ERR
"%s: Bad checksum for this %s packet, checksum = %x.\n",
__func__,
- ((checksum &
+ ((checksum &
IB_IP_IOCB_RSP_3032_TCP) ? "TCP" :
"UDP"),checksum);
} else if ((checksum & IB_IP_IOCB_RSP_3032_TCP) ||
@@ -2226,8 +2228,8 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
skb2->protocol = eth_type_trans(skb2, qdev->ndev);
netif_receive_skb(skb2);
- qdev->stats.rx_packets++;
- qdev->stats.rx_bytes += length;
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += length;
ndev->last_rx = jiffies;
lrg_buf_cb2->skb = NULL;
@@ -2310,10 +2312,10 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev,
return work_done;
}
-static int ql_poll(struct net_device *ndev, int *budget)
+static int ql_poll(struct napi_struct *napi, int budget)
{
- struct ql3_adapter *qdev = netdev_priv(ndev);
- int work_to_do = min(*budget, ndev->quota);
+ struct ql3_adapter *qdev = container_of(napi, struct ql3_adapter, napi);
+ struct net_device *ndev = qdev->ndev;
int rx_cleaned = 0, tx_cleaned = 0;
unsigned long hw_flags;
struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
@@ -2321,16 +2323,13 @@ static int ql_poll(struct net_device *ndev, int *budget)
if (!netif_carrier_ok(ndev))
goto quit_polling;
- ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, work_to_do);
- *budget -= rx_cleaned;
- ndev->quota -= rx_cleaned;
+ ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, budget);
- if( tx_cleaned + rx_cleaned != work_to_do ||
+ if (tx_cleaned + rx_cleaned != budget ||
!netif_running(ndev)) {
quit_polling:
- netif_rx_complete(ndev);
-
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ __netif_rx_complete(ndev, napi);
ql_update_small_bufq_prod_index(qdev);
ql_update_lrg_bufq_prod_index(qdev);
writel(qdev->rsp_consumer_index,
@@ -2338,9 +2337,8 @@ quit_polling:
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
ql_enable_interrupts(qdev);
- return 0;
}
- return 1;
+ return tx_cleaned + rx_cleaned;
}
static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
@@ -2390,8 +2388,8 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
spin_unlock(&qdev->adapter_lock);
} else if (value & ISP_IMR_DISABLE_CMPL_INT) {
ql_disable_interrupts(qdev);
- if (likely(netif_rx_schedule_prep(ndev))) {
- __netif_rx_schedule(ndev);
+ if (likely(netif_rx_schedule_prep(ndev, &qdev->napi))) {
+ __netif_rx_schedule(ndev, &qdev->napi);
}
} else {
return IRQ_NONE;
@@ -2401,12 +2399,12 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
}
/*
- * Get the total number of segments needed for the
+ * Get the total number of segments needed for the
* given number of fragments. This is necessary because
* outbound address lists (OAL) will be used when more than
- * two frags are given. Each address list has 5 addr/len
+ * two frags are given. Each address list has 5 addr/len
* pairs. The 5th pair in each AOL is used to point to
- * the next AOL if more frags are coming.
+ * the next AOL if more frags are coming.
* That is why the frags:segment count ratio is not linear.
*/
static int ql_get_seg_count(struct ql3_adapter *qdev,
@@ -2483,12 +2481,12 @@ static int ql_send_map(struct ql3_adapter *qdev,
err = pci_dma_mapping_error(map);
if(err) {
- printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
+ printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
qdev->ndev->name, err);
return NETDEV_TX_BUSY;
}
-
+
oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
@@ -2518,7 +2516,7 @@ static int ql_send_map(struct ql3_adapter *qdev,
err = pci_dma_mapping_error(map);
if(err) {
- printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n",
+ printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n",
qdev->ndev->name, err);
goto map_error;
}
@@ -2544,7 +2542,7 @@ static int ql_send_map(struct ql3_adapter *qdev,
err = pci_dma_mapping_error(map);
if(err) {
- printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n",
+ printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n",
qdev->ndev->name, err);
goto map_error;
}
@@ -2565,10 +2563,10 @@ static int ql_send_map(struct ql3_adapter *qdev,
map_error:
/* A PCI mapping failed and now we will need to back out
- * We need to traverse through the oal's and associated pages which
+ * We need to traverse through the oal's and associated pages which
* have been mapped and now we must unmap them to clean up properly
*/
-
+
seg = 1;
oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
oal = tx_cb->oal;
@@ -2606,11 +2604,11 @@ map_error:
* The difference between 3022 and 3032 sends:
* 3022 only supports a simple single segment transmission.
* 3032 supports checksumming and scatter/gather lists (fragments).
- * The 3032 supports sglists by using the 3 addr/len pairs (ALP)
- * in the IOCB plus a chain of outbound address lists (OAL) that
- * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th)
- * will used to point to an OAL when more ALP entries are required.
- * The IOCB is always the top of the chain followed by one or more
+ * The 3032 supports sglists by using the 3 addr/len pairs (ALP)
+ * in the IOCB plus a chain of outbound address lists (OAL) that
+ * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th)
+ * will used to point to an OAL when more ALP entries are required.
+ * The IOCB is always the top of the chain followed by one or more
* OALs (when necessary).
*/
static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
@@ -2624,14 +2622,14 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
return NETDEV_TX_BUSY;
}
-
+
tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
if((tx_cb->seg_count = ql_get_seg_count(qdev,
(skb_shinfo(skb)->nr_frags))) == -1) {
printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__);
return NETDEV_TX_OK;
}
-
+
mac_iocb_ptr = tx_cb->queue_entry;
memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req));
mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
@@ -2643,12 +2641,12 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
if (qdev->device_id == QL3032_DEVICE_ID &&
skb->ip_summed == CHECKSUM_PARTIAL)
ql_hw_csum_setup(skb, mac_iocb_ptr);
-
+
if(ql_send_map(qdev,mac_iocb_ptr,tx_cb,skb) != NETDEV_TX_OK) {
printk(KERN_ERR PFX"%s: Could not map the segments!\n",__func__);
return NETDEV_TX_BUSY;
}
-
+
wmb();
qdev->req_producer_index++;
if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES)
@@ -2746,7 +2744,7 @@ static int ql_alloc_buffer_queues(struct ql3_adapter *qdev)
"%s: qdev->lrg_buf alloc failed.\n", qdev->ndev->name);
return -ENOMEM;
}
-
+
qdev->lrg_buf_q_alloc_virt_addr =
pci_alloc_consistent(qdev->pdev,
qdev->lrg_buf_q_alloc_size,
@@ -3562,6 +3560,7 @@ static void ql_display_dev_info(struct net_device *ndev)
{
struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
struct pci_dev *pdev = qdev->pdev;
+ DECLARE_MAC_BUF(mac);
printk(KERN_INFO PFX
"\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n",
@@ -3587,10 +3586,8 @@ static void ql_display_dev_info(struct net_device *ndev)
if (netif_msg_probe(qdev))
printk(KERN_INFO PFX
- "%s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
- ndev->name, ndev->dev_addr[0], ndev->dev_addr[1],
- ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4],
- ndev->dev_addr[5]);
+ "%s: MAC address %s\n",
+ ndev->name, print_mac(mac, ndev->dev_addr));
}
static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
@@ -3617,7 +3614,7 @@ static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
del_timer_sync(&qdev->adapter_timer);
- netif_poll_disable(ndev);
+ napi_disable(&qdev->napi);
if (do_reset) {
int soft_reset;
@@ -3705,7 +3702,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev)
mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
- netif_poll_enable(ndev);
+ napi_enable(&qdev->napi);
ql_enable_interrupts(qdev);
return 0;
@@ -3758,12 +3755,6 @@ static int ql3xxx_open(struct net_device *ndev)
return (ql_adapter_up(qdev));
}
-static struct net_device_stats *ql3xxx_get_stats(struct net_device *dev)
-{
- struct ql3_adapter *qdev = (struct ql3_adapter *)dev->priv;
- return &qdev->stats;
-}
-
static void ql3xxx_set_multicast_list(struct net_device *ndev)
{
/*
@@ -3955,19 +3946,7 @@ static void ql_get_board_info(struct ql3_adapter *qdev)
static void ql3xxx_timer(unsigned long ptr)
{
struct ql3_adapter *qdev = (struct ql3_adapter *)ptr;
-
- if (test_bit(QL_RESET_ACTIVE,&qdev->flags)) {
- printk(KERN_DEBUG PFX
- "%s: Reset in progress.\n",
- qdev->ndev->name);
- goto end;
- }
-
- ql_link_state_machine(qdev);
-
- /* Restart timer on 2 second interval. */
-end:
- mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
+ queue_delayed_work(qdev->workqueue, &qdev->link_state_work, 0);
}
static int __devinit ql3xxx_probe(struct pci_dev *pdev,
@@ -4016,7 +3995,6 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
goto err_out_free_regions;
}
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
pci_set_drvdata(pdev, ndev);
@@ -4054,15 +4032,13 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
ndev->open = ql3xxx_open;
ndev->hard_start_xmit = ql3xxx_send;
ndev->stop = ql3xxx_close;
- ndev->get_stats = ql3xxx_get_stats;
ndev->set_multicast_list = ql3xxx_set_multicast_list;
SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops);
ndev->set_mac_address = ql3xxx_set_mac_address;
ndev->tx_timeout = ql3xxx_tx_timeout;
ndev->watchdog_timeo = 5 * HZ;
- ndev->poll = &ql_poll;
- ndev->weight = 64;
+ netif_napi_add(ndev, &qdev->napi, ql_poll, 64);
ndev->irq = pdev->irq;
@@ -4120,6 +4096,7 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
qdev->workqueue = create_singlethread_workqueue(ndev->name);
INIT_DELAYED_WORK(&qdev->reset_work, ql_reset_work);
INIT_DELAYED_WORK(&qdev->tx_timeout_work, ql_tx_timeout_work);
+ INIT_DELAYED_WORK(&qdev->link_state_work, ql_link_state_machine_work);
init_timer(&qdev->adapter_timer);
qdev->adapter_timer.function = ql3xxx_timer;
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
index 4a832c46c27..d0ffb30ef37 100755..100644
--- a/drivers/net/qla3xxx.h
+++ b/drivers/net/qla3xxx.h
@@ -556,7 +556,7 @@ enum {
IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007,
IP_ADDR_INDEX_REG_6 = 0x0008,
IP_ADDR_INDEX_REG_OFFSET_MASK = 0x0030,
- IP_ADDR_INDEX_REG_E = 0x0040,
+ IP_ADDR_INDEX_REG_E = 0x0040,
};
enum {
QL3032_PORT_CONTROL_DS = 0x0001,
@@ -1112,7 +1112,7 @@ struct ql_rcv_buf_cb {
* OAL has 5 entries:
* 1 thru 4 point to frags
* fifth points to next oal.
- */
+ */
#define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1)
struct oal_entry {
@@ -1137,7 +1137,7 @@ struct ql_tx_buf_cb {
struct ob_mac_iocb_req *queue_entry ;
int seg_count;
struct oal *oal;
- struct map_list map[MAX_SKB_FRAGS+1];
+ struct map_list map[MAX_SKB_FRAGS+1];
};
/* definitions for type field */
@@ -1175,6 +1175,8 @@ struct ql3_adapter {
struct pci_dev *pdev;
struct net_device *ndev; /* Parent NET device */
+ struct napi_struct napi;
+
/* Hardware information */
u8 chip_rev_id;
u8 pci_slot;
@@ -1281,10 +1283,10 @@ struct ql3_adapter {
u32 update_ob_opcode; /* Opcode to use for updating NCB */
u32 mb_bit_mask; /* MA Bits mask to use on transmission */
u32 numPorts;
- struct net_device_stats stats;
struct workqueue_struct *workqueue;
struct delayed_work reset_work;
struct delayed_work tx_timeout_work;
+ struct delayed_work link_state_work;
u32 max_frame_size;
u32 device_id;
u16 phyType;
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index c76dd29c8e9..1f647b9ce35 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -44,7 +44,8 @@
printk( "Assertion failed! %s,%s,%s,line=%d\n", \
#expr,__FILE__,__FUNCTION__,__LINE__); \
}
-#define dprintk(fmt, args...) do { printk(PFX fmt, ## args); } while (0)
+#define dprintk(fmt, args...) \
+ do { printk(KERN_DEBUG PFX fmt, ## args); } while (0)
#else
#define assert(expr) do {} while (0)
#define dprintk(fmt, args...) do {} while (0)
@@ -111,19 +112,15 @@ enum mac_version {
RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
- RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be 8168Bf
- RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb 8101Ec
- RTL_GIGA_MAC_VER_14 = 0x0e, // 8101
- RTL_GIGA_MAC_VER_15 = 0x0f // 8101
-};
-
-enum phy_version {
- RTL_GIGA_PHY_VER_C = 0x03, /* PHY Reg 0x03 bit0-3 == 0x0000 */
- RTL_GIGA_PHY_VER_D = 0x04, /* PHY Reg 0x03 bit0-3 == 0x0000 */
- RTL_GIGA_PHY_VER_E = 0x05, /* PHY Reg 0x03 bit0-3 == 0x0000 */
- RTL_GIGA_PHY_VER_F = 0x06, /* PHY Reg 0x03 bit0-3 == 0x0001 */
- RTL_GIGA_PHY_VER_G = 0x07, /* PHY Reg 0x03 bit0-3 == 0x0002 */
- RTL_GIGA_PHY_VER_H = 0x08, /* PHY Reg 0x03 bit0-3 == 0x0003 */
+ RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be
+ RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb
+ RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ?
+ RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ?
+ RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec
+ RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf
+ RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP
+ RTL_GIGA_MAC_VER_19 = 0x13, // 8168C
+ RTL_GIGA_MAC_VER_20 = 0x14 // 8168C
};
#define _R(NAME,MAC,MASK) \
@@ -144,7 +141,12 @@ static const struct {
_R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E
_R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139
_R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139
- _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880) // PCI-E 8139
+ _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139
+ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E
+ _R("RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E
+ _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880) // PCI-E
};
#undef _R
@@ -165,10 +167,12 @@ static struct pci_device_id rtl8169_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 },
- { PCI_DEVICE(0x1259, 0xc107), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 },
{ PCI_VENDOR_ID_LINKSYS, 0x1032,
PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
+ { 0x0001, 0x8168,
+ PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },
{0,},
};
@@ -277,6 +281,7 @@ enum rtl_register_content {
TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
/* Config1 register p.24 */
+ MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */
PMEnable = (1 << 0), /* Power Management Enable */
/* Config2 register p. 25 */
@@ -380,16 +385,22 @@ struct ring_info {
u8 __pad[sizeof(void *) - sizeof(u32)];
};
+enum features {
+ RTL_FEATURE_WOL = (1 << 0),
+ RTL_FEATURE_MSI = (1 << 1),
+};
+
struct rtl8169_private {
void __iomem *mmio_addr; /* memory map physical address */
struct pci_dev *pci_dev; /* Index of PCI device */
struct net_device *dev;
- struct net_device_stats stats; /* statistics of net device */
+#ifdef CONFIG_R8169_NAPI
+ struct napi_struct napi;
+#endif
spinlock_t lock; /* spin lock flag */
u32 msg_enable;
int chipset;
int mac_version;
- int phy_version;
u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
u32 dirty_rx;
@@ -419,7 +430,7 @@ struct rtl8169_private {
unsigned int (*phy_reset_pending)(void __iomem *);
unsigned int (*link_ok)(void __iomem *);
struct delayed_work task;
- unsigned wol_enabled : 1;
+ unsigned features;
};
MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -443,13 +454,13 @@ static void rtl_set_rx_mode(struct net_device *dev);
static void rtl8169_tx_timeout(struct net_device *dev);
static struct net_device_stats *rtl8169_get_stats(struct net_device *dev);
static int rtl8169_rx_interrupt(struct net_device *, struct rtl8169_private *,
- void __iomem *);
+ void __iomem *, u32 budget);
static int rtl8169_change_mtu(struct net_device *dev, int new_mtu);
static void rtl8169_down(struct net_device *dev);
static void rtl8169_rx_clear(struct rtl8169_private *tp);
#ifdef CONFIG_R8169_NAPI
-static int rtl8169_poll(struct net_device *dev, int *budget);
+static int rtl8169_poll(struct napi_struct *napi, int budget);
#endif
static const unsigned int rtl8169_rx_config =
@@ -459,7 +470,7 @@ static void mdio_write(void __iomem *ioaddr, int reg_addr, int value)
{
int i;
- RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0xFF) << 16 | value);
+ RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0x1f) << 16 | (value & 0xffff));
for (i = 20; i > 0; i--) {
/*
@@ -476,7 +487,7 @@ static int mdio_read(void __iomem *ioaddr, int reg_addr)
{
int i, value = -1;
- RTL_W32(PHYAR, 0x0 | (reg_addr & 0xFF) << 16);
+ RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16);
for (i = 20; i > 0; i--) {
/*
@@ -484,7 +495,7 @@ static int mdio_read(void __iomem *ioaddr, int reg_addr)
* the specified MII register.
*/
if (RTL_R32(PHYAR) & 0x80000000) {
- value = (int) (RTL_R32(PHYAR) & 0xFFFF);
+ value = RTL_R32(PHYAR) & 0xffff;
break;
}
udelay(25);
@@ -625,7 +636,10 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
RTL_W8(Cfg9346, Cfg9346_Lock);
- tp->wol_enabled = (wol->wolopts) ? 1 : 0;
+ if (wol->wolopts)
+ tp->features |= RTL_FEATURE_WOL;
+ else
+ tp->features &= ~RTL_FEATURE_WOL;
spin_unlock_irq(&tp->lock);
@@ -706,7 +720,8 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
/* This tweak comes straight from Realtek's driver. */
if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) &&
- (tp->mac_version == RTL_GIGA_MAC_VER_13)) {
+ ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_16))) {
auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA;
}
}
@@ -714,7 +729,8 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
/* The 8100e/8101e do Fast Ethernet only. */
if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
(tp->mac_version == RTL_GIGA_MAC_VER_14) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_15)) {
+ (tp->mac_version == RTL_GIGA_MAC_VER_15) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) &&
netif_msg_link(tp)) {
printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n",
@@ -725,7 +741,8 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
- if (tp->mac_version == RTL_GIGA_MAC_VER_12) {
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_12) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_17)) {
/* Vendor specific (0x1f) and reserved (0x0e) MII registers. */
mdio_write(ioaddr, 0x1f, 0x0000);
mdio_write(ioaddr, 0x0e, 0x0000);
@@ -976,24 +993,29 @@ static const char rtl8169_gstrings[][ETH_GSTRING_LEN] = {
};
struct rtl8169_counters {
- u64 tx_packets;
- u64 rx_packets;
- u64 tx_errors;
- u32 rx_errors;
- u16 rx_missed;
- u16 align_errors;
- u32 tx_one_collision;
- u32 tx_multi_collision;
- u64 rx_unicast;
- u64 rx_broadcast;
- u32 rx_multicast;
- u16 tx_aborted;
- u16 tx_underun;
+ __le64 tx_packets;
+ __le64 rx_packets;
+ __le64 tx_errors;
+ __le32 rx_errors;
+ __le16 rx_missed;
+ __le16 align_errors;
+ __le32 tx_one_collision;
+ __le32 tx_multi_collision;
+ __le64 rx_unicast;
+ __le64 rx_broadcast;
+ __le32 rx_multicast;
+ __le16 tx_aborted;
+ __le16 tx_underun;
};
-static int rtl8169_get_stats_count(struct net_device *dev)
+static int rtl8169_get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(rtl8169_gstrings);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(rtl8169_gstrings);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void rtl8169_get_ethtool_stats(struct net_device *dev,
@@ -1060,17 +1082,14 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
.set_msglevel = rtl8169_set_msglevel,
.get_rx_csum = rtl8169_get_rx_csum,
.set_rx_csum = rtl8169_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_regs = rtl8169_get_regs,
.get_wol = rtl8169_get_wol,
.set_wol = rtl8169_set_wol,
.get_strings = rtl8169_get_strings,
- .get_stats_count = rtl8169_get_stats_count,
+ .get_sset_count = rtl8169_get_sset_count,
.get_ethtool_stats = rtl8169_get_ethtool_stats,
};
@@ -1101,26 +1120,51 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
*/
const struct {
u32 mask;
+ u32 val;
int mac_version;
} mac_info[] = {
- { 0x38800000, RTL_GIGA_MAC_VER_15 },
- { 0x38000000, RTL_GIGA_MAC_VER_12 },
- { 0x34000000, RTL_GIGA_MAC_VER_13 },
- { 0x30800000, RTL_GIGA_MAC_VER_14 },
- { 0x30000000, RTL_GIGA_MAC_VER_11 },
- { 0x98000000, RTL_GIGA_MAC_VER_06 },
- { 0x18000000, RTL_GIGA_MAC_VER_05 },
- { 0x10000000, RTL_GIGA_MAC_VER_04 },
- { 0x04000000, RTL_GIGA_MAC_VER_03 },
- { 0x00800000, RTL_GIGA_MAC_VER_02 },
- { 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */
+ /* 8168B family. */
+ { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
+ { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 },
+ { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 },
+ { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_20 },
+
+ /* 8168B family. */
+ { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 },
+ { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 },
+ { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 },
+ { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
+
+ /* 8101 family. */
+ { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 },
+ { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 },
+ { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 },
+ /* FIXME: where did these entries come from ? -- FR */
+ { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 },
+ { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 },
+
+ /* 8110 family. */
+ { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 },
+ { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 },
+ { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 },
+ { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 },
+ { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
+ { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
+
+ { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */
}, *p = mac_info;
u32 reg;
- reg = RTL_R32(TxConfig) & 0xfc800000;
- while ((reg & p->mask) != p->mask)
+ reg = RTL_R32(TxConfig);
+ while ((reg & p->mask) != p->val)
p++;
tp->mac_version = p->mac_version;
+
+ if (p->mask == 0x00000000) {
+ struct pci_dev *pdev = tp->pci_dev;
+
+ dev_info(&pdev->dev, "unknown MAC (%08x)\n", reg);
+ }
}
static void rtl8169_print_mac_version(struct rtl8169_private *tp)
@@ -1128,54 +1172,21 @@ static void rtl8169_print_mac_version(struct rtl8169_private *tp)
dprintk("mac_version = 0x%02x\n", tp->mac_version);
}
-static void rtl8169_get_phy_version(struct rtl8169_private *tp,
- void __iomem *ioaddr)
-{
- const struct {
- u16 mask;
- u16 set;
- int phy_version;
- } phy_info[] = {
- { 0x000f, 0x0002, RTL_GIGA_PHY_VER_G },
- { 0x000f, 0x0001, RTL_GIGA_PHY_VER_F },
- { 0x000f, 0x0000, RTL_GIGA_PHY_VER_E },
- { 0x0000, 0x0000, RTL_GIGA_PHY_VER_D } /* Catch-all */
- }, *p = phy_info;
+struct phy_reg {
u16 reg;
+ u16 val;
+};
- reg = mdio_read(ioaddr, MII_PHYSID2) & 0xffff;
- while ((reg & p->mask) != p->set)
- p++;
- tp->phy_version = p->phy_version;
-}
-
-static void rtl8169_print_phy_version(struct rtl8169_private *tp)
+static void rtl_phy_write(void __iomem *ioaddr, struct phy_reg *regs, int len)
{
- struct {
- int version;
- char *msg;
- u32 reg;
- } phy_print[] = {
- { RTL_GIGA_PHY_VER_G, "RTL_GIGA_PHY_VER_G", 0x0002 },
- { RTL_GIGA_PHY_VER_F, "RTL_GIGA_PHY_VER_F", 0x0001 },
- { RTL_GIGA_PHY_VER_E, "RTL_GIGA_PHY_VER_E", 0x0000 },
- { RTL_GIGA_PHY_VER_D, "RTL_GIGA_PHY_VER_D", 0x0000 },
- { 0, NULL, 0x0000 }
- }, *p;
-
- for (p = phy_print; p->msg; p++) {
- if (tp->phy_version == p->version) {
- dprintk("phy_version == %s (%04x)\n", p->msg, p->reg);
- return;
- }
+ while (len-- > 0) {
+ mdio_write(ioaddr, regs->reg, regs->val);
+ regs++;
}
- dprintk("phy_version == Unknown\n");
}
-static void rtl8169_hw_phy_config(struct net_device *dev)
+static void rtl8169s_hw_phy_config(void __iomem *ioaddr)
{
- struct rtl8169_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
struct {
u16 regs[5]; /* Beware of bit-sign propagation */
} phy_magic[5] = { {
@@ -1208,33 +1219,9 @@ static void rtl8169_hw_phy_config(struct net_device *dev)
}, *p = phy_magic;
unsigned int i;
- rtl8169_print_mac_version(tp);
- rtl8169_print_phy_version(tp);
-
- if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
- return;
- if (tp->phy_version >= RTL_GIGA_PHY_VER_H)
- return;
-
- dprintk("MAC version != 0 && PHY version == 0 or 1\n");
- dprintk("Do final_reg2.cfg\n");
-
- /* Shazam ! */
-
- if (tp->mac_version == RTL_GIGA_MAC_VER_04) {
- mdio_write(ioaddr, 31, 0x0002);
- mdio_write(ioaddr, 1, 0x90d0);
- mdio_write(ioaddr, 31, 0x0000);
- return;
- }
-
- if ((tp->mac_version != RTL_GIGA_MAC_VER_02) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_03))
- return;
-
- mdio_write(ioaddr, 31, 0x0001); //w 31 2 0 1
- mdio_write(ioaddr, 21, 0x1000); //w 21 15 0 1000
- mdio_write(ioaddr, 24, 0x65c7); //w 24 15 0 65c7
+ mdio_write(ioaddr, 0x1f, 0x0001); //w 31 2 0 1
+ mdio_write(ioaddr, 0x15, 0x1000); //w 21 15 0 1000
+ mdio_write(ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7
rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) {
@@ -1247,7 +1234,100 @@ static void rtl8169_hw_phy_config(struct net_device *dev)
rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1
rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
}
- mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0
+ mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0
+}
+
+static void rtl8169sb_hw_phy_config(void __iomem *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0002 },
+ { 0x01, 0x90d0 },
+ { 0x1f, 0x0000 }
+ };
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cp_hw_phy_config(void __iomem *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0000 },
+ { 0x1d, 0x0f00 },
+ { 0x1f, 0x0002 },
+ { 0x0c, 0x1ec8 },
+ { 0x1f, 0x0000 }
+ };
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168c_hw_phy_config(void __iomem *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0001 },
+ { 0x12, 0x2300 },
+ { 0x1f, 0x0002 },
+ { 0x00, 0x88d4 },
+ { 0x01, 0x82b1 },
+ { 0x03, 0x7002 },
+ { 0x08, 0x9e30 },
+ { 0x09, 0x01f0 },
+ { 0x0a, 0x5500 },
+ { 0x0c, 0x00c8 },
+ { 0x1f, 0x0003 },
+ { 0x12, 0xc096 },
+ { 0x16, 0x000a },
+ { 0x1f, 0x0000 }
+ };
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cx_hw_phy_config(void __iomem *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0000 },
+ { 0x12, 0x2300 },
+ { 0x1f, 0x0003 },
+ { 0x16, 0x0f0a },
+ { 0x1f, 0x0000 },
+ { 0x1f, 0x0002 },
+ { 0x0c, 0x7eb8 },
+ { 0x1f, 0x0000 }
+ };
+
+ rtl_phy_write(ioaddr, 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);
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_01:
+ break;
+ case RTL_GIGA_MAC_VER_02:
+ case RTL_GIGA_MAC_VER_03:
+ rtl8169s_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_04:
+ rtl8169sb_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_18:
+ rtl8168cp_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_19:
+ rtl8168c_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_20:
+ rtl8168cx_hw_phy_config(ioaddr);
+ break;
+ default:
+ break;
+ }
}
static void rtl8169_phy_timer(unsigned long __opaque)
@@ -1259,7 +1339,6 @@ static void rtl8169_phy_timer(unsigned long __opaque)
unsigned long timeout = RTL8169_PHY_TIMEOUT;
assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
- assert(tp->phy_version < RTL_GIGA_PHY_VER_H);
if (!(tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL))
return;
@@ -1294,8 +1373,7 @@ static inline void rtl8169_delete_timer(struct net_device *dev)
struct rtl8169_private *tp = netdev_priv(dev);
struct timer_list *timer = &tp->timer;
- if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) ||
- (tp->phy_version >= RTL_GIGA_PHY_VER_H))
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
return;
del_timer_sync(timer);
@@ -1306,8 +1384,7 @@ static inline void rtl8169_request_timer(struct net_device *dev)
struct rtl8169_private *tp = netdev_priv(dev);
struct timer_list *timer = &tp->timer;
- if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) ||
- (tp->phy_version >= RTL_GIGA_PHY_VER_H))
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
return;
mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT);
@@ -1359,7 +1436,7 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
- rtl8169_hw_phy_config(dev);
+ rtl_hw_phy_config(dev);
dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
RTL_W8(0x82, 0x01);
@@ -1454,6 +1531,7 @@ static const struct rtl_cfg_info {
unsigned int align;
u16 intr_event;
u16 napi_event;
+ unsigned msi;
} rtl_cfg_infos [] = {
[RTL_CFG_0] = {
.hw_start = rtl_hw_start_8169,
@@ -1461,7 +1539,8 @@ static const struct rtl_cfg_info {
.align = 0,
.intr_event = SYSErr | LinkChg | RxOverflow |
RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
- .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow
+ .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+ .msi = 0
},
[RTL_CFG_1] = {
.hw_start = rtl_hw_start_8168,
@@ -1469,7 +1548,8 @@ static const struct rtl_cfg_info {
.align = 8,
.intr_event = SYSErr | LinkChg | RxOverflow |
TxErr | TxOK | RxOK | RxErr,
- .napi_event = TxErr | TxOK | RxOK | RxOverflow
+ .napi_event = TxErr | TxOK | RxOK | RxOverflow,
+ .msi = RTL_FEATURE_MSI
},
[RTL_CFG_2] = {
.hw_start = rtl_hw_start_8101,
@@ -1477,10 +1557,39 @@ static const struct rtl_cfg_info {
.align = 8,
.intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout |
RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
- .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow
+ .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+ .msi = RTL_FEATURE_MSI
}
};
+/* Cfg9346_Unlock assumed. */
+static unsigned rtl_try_msi(struct pci_dev *pdev, void __iomem *ioaddr,
+ const struct rtl_cfg_info *cfg)
+{
+ unsigned msi = 0;
+ u8 cfg2;
+
+ cfg2 = RTL_R8(Config2) & ~MSIEnable;
+ if (cfg->msi) {
+ if (pci_enable_msi(pdev)) {
+ dev_info(&pdev->dev, "no MSI. Back to INTx.\n");
+ } else {
+ cfg2 |= MSIEnable;
+ msi = RTL_FEATURE_MSI;
+ }
+ }
+ RTL_W8(Config2, cfg2);
+ return msi;
+}
+
+static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp)
+{
+ if (tp->features & RTL_FEATURE_MSI) {
+ pci_disable_msi(pdev);
+ tp->features &= ~RTL_FEATURE_MSI;
+ }
+}
+
static int __devinit
rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -1505,7 +1614,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
tp = netdev_priv(dev);
tp->dev = dev;
@@ -1594,10 +1702,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Identify chip attached to board */
rtl8169_get_mac_version(tp, ioaddr);
- rtl8169_get_phy_version(tp, ioaddr);
rtl8169_print_mac_version(tp);
- rtl8169_print_phy_version(tp);
for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) {
if (tp->mac_version == rtl_chip_info[i].mac_version)
@@ -1617,9 +1723,11 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
RTL_W8(Cfg9346, Cfg9346_Unlock);
RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
+ tp->features |= rtl_try_msi(pdev, ioaddr, cfg);
RTL_W8(Cfg9346, Cfg9346_Lock);
- if (RTL_R8(PHYstatus) & TBI_Enable) {
+ if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) &&
+ (RTL_R8(PHYstatus) & TBI_Enable)) {
tp->set_speed = rtl8169_set_speed_tbi;
tp->get_settings = rtl8169_gset_tbi;
tp->phy_reset_enable = rtl8169_tbi_reset_enable;
@@ -1656,8 +1764,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->set_mac_address = rtl_set_mac_address;
#ifdef CONFIG_R8169_NAPI
- dev->poll = rtl8169_poll;
- dev->weight = R8169_NAPI_WEIGHT;
+ netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);
#endif
#ifdef CONFIG_R8169_VLAN
@@ -1685,7 +1792,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rc = register_netdev(dev);
if (rc < 0)
- goto err_out_unmap_5;
+ goto err_out_msi_5;
pci_set_drvdata(pdev, dev);
@@ -1708,7 +1815,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
out:
return rc;
-err_out_unmap_5:
+err_out_msi_5:
+ rtl_disable_msi(pdev, tp);
iounmap(ioaddr);
err_out_free_res_4:
pci_release_regions(pdev);
@@ -1729,6 +1837,7 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
flush_scheduled_work();
unregister_netdev(dev);
+ rtl_disable_msi(pdev, tp);
rtl8169_release_board(pdev, dev, tp->mmio_addr);
pci_set_drvdata(pdev, NULL);
}
@@ -1772,11 +1881,16 @@ static int rtl8169_open(struct net_device *dev)
smp_mb();
- retval = request_irq(dev->irq, rtl8169_interrupt, IRQF_SHARED,
+ retval = request_irq(dev->irq, rtl8169_interrupt,
+ (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
dev->name, dev);
if (retval < 0)
goto err_release_ring_2;
+#ifdef CONFIG_R8169_NAPI
+ napi_enable(&tp->napi);
+#endif
+
rtl_hw_start(dev);
rtl8169_request_timer(dev);
@@ -1928,7 +2042,7 @@ static void rtl_hw_start_8169(struct net_device *dev)
if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
(tp->mac_version == RTL_GIGA_MAC_VER_03)) {
- dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0. "
+ dprintk("Set MAC Reg C+CR Offset 0xE0. "
"Bit-3 and bit-14 MUST be 1\n");
tp->cp_cmd |= (1 << 14);
}
@@ -2024,7 +2138,8 @@ static void rtl_hw_start_8101(struct net_device *dev)
void __iomem *ioaddr = tp->mmio_addr;
struct pci_dev *pdev = tp->pci_dev;
- if (tp->mac_version == RTL_GIGA_MAC_VER_13) {
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
pci_write_config_word(pdev, 0x68, 0x00);
pci_write_config_word(pdev, 0x69, 0x08);
}
@@ -2082,7 +2197,9 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
if (ret < 0)
goto out;
- netif_poll_enable(dev);
+#ifdef CONFIG_R8169_NAPI
+ napi_enable(&tp->napi);
+#endif
rtl_hw_start(dev);
@@ -2252,7 +2369,7 @@ static void rtl8169_tx_clear(struct rtl8169_private *tp)
dev_kfree_skb(skb);
tx_skb->skb = NULL;
}
- tp->stats.tx_dropped++;
+ tp->dev->stats.tx_dropped++;
}
}
tp->cur_tx = tp->dirty_tx = 0;
@@ -2274,11 +2391,15 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev)
synchronize_irq(dev->irq);
/* Wait for any pending NAPI task to complete */
- netif_poll_disable(dev);
+#ifdef CONFIG_R8169_NAPI
+ napi_disable(&tp->napi);
+#endif
rtl8169_irq_mask_and_ack(ioaddr);
- netif_poll_enable(dev);
+#ifdef CONFIG_R8169_NAPI
+ napi_enable(&tp->napi);
+#endif
}
static void rtl8169_reinit_task(struct work_struct *work)
@@ -2299,7 +2420,7 @@ static void rtl8169_reinit_task(struct work_struct *work)
ret = rtl8169_open(dev);
if (unlikely(ret < 0)) {
if (net_ratelimit() && netif_msg_drv(tp)) {
- printk(PFX KERN_ERR "%s: reinit failure (status = %d)."
+ printk(KERN_ERR PFX "%s: reinit failure (status = %d)."
" Rescheduling.\n", dev->name, ret);
}
rtl8169_schedule_work(dev, rtl8169_reinit_task);
@@ -2322,16 +2443,17 @@ static void rtl8169_reset_task(struct work_struct *work)
rtl8169_wait_for_quiescence(dev);
- rtl8169_rx_interrupt(dev, tp, tp->mmio_addr);
+ rtl8169_rx_interrupt(dev, tp, tp->mmio_addr, ~(u32)0);
rtl8169_tx_clear(tp);
if (tp->dirty_rx == tp->cur_rx) {
rtl8169_init_ring_indexes(tp);
rtl_hw_start(dev);
netif_wake_queue(dev);
+ rtl8169_check_link_status(dev, tp, tp->mmio_addr);
} else {
if (net_ratelimit() && netif_msg_intr(tp)) {
- printk(PFX KERN_EMERG "%s: Rx buffers shortage\n",
+ printk(KERN_EMERG PFX "%s: Rx buffers shortage\n",
dev->name);
}
rtl8169_schedule_work(dev, rtl8169_reset_task);
@@ -2485,7 +2607,7 @@ err_stop:
netif_stop_queue(dev);
ret = NETDEV_TX_BUSY;
err_update_stats:
- tp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
goto out;
}
@@ -2560,8 +2682,8 @@ static void rtl8169_tx_interrupt(struct net_device *dev,
if (status & DescOwn)
break;
- tp->stats.tx_bytes += len;
- tp->stats.tx_packets++;
+ dev->stats.tx_bytes += len;
+ dev->stats.tx_packets++;
rtl8169_unmap_tx_skb(tp->pci_dev, tx_skb, tp->TxDescArray + entry);
@@ -2636,14 +2758,14 @@ out:
static int rtl8169_rx_interrupt(struct net_device *dev,
struct rtl8169_private *tp,
- void __iomem *ioaddr)
+ void __iomem *ioaddr, u32 budget)
{
unsigned int cur_rx, rx_left;
unsigned int delta, count;
cur_rx = tp->cur_rx;
rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
- rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota);
+ rx_left = rtl8169_rx_quota(rx_left, budget);
for (; rx_left > 0; rx_left--, cur_rx++) {
unsigned int entry = cur_rx % NUM_RX_DESC;
@@ -2661,14 +2783,14 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
"%s: Rx ERROR. status = %08x\n",
dev->name, status);
}
- tp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (status & (RxRWT | RxRUNT))
- tp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (status & RxCRC)
- tp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (status & RxFOVF) {
rtl8169_schedule_work(dev, rtl8169_reset_task);
- tp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
}
rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
} else {
@@ -2683,8 +2805,8 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
* sized frames.
*/
if (unlikely(rtl8169_fragmented_frame(status))) {
- tp->stats.rx_dropped++;
- tp->stats.rx_length_errors++;
+ dev->stats.rx_dropped++;
+ dev->stats.rx_length_errors++;
rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
continue;
}
@@ -2708,8 +2830,8 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
rtl8169_rx_skb(skb);
dev->last_rx = jiffies;
- tp->stats.rx_bytes += pkt_size;
- tp->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_size;
+ dev->stats.rx_packets++;
}
/* Work around for AMD plateform. */
@@ -2792,8 +2914,8 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
tp->intr_mask = ~tp->napi_event;
- if (likely(netif_rx_schedule_prep(dev)))
- __netif_rx_schedule(dev);
+ if (likely(netif_rx_schedule_prep(dev, &tp->napi)))
+ __netif_rx_schedule(dev, &tp->napi);
else if (netif_msg_intr(tp)) {
printk(KERN_INFO "%s: interrupt %04x in poll\n",
dev->name, status);
@@ -2803,7 +2925,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
#else
/* Rx interrupt */
if (status & (RxOK | RxOverflow | RxFIFOOver))
- rtl8169_rx_interrupt(dev, tp, ioaddr);
+ rtl8169_rx_interrupt(dev, tp, ioaddr, ~(u32)0);
/* Tx interrupt */
if (status & (TxOK | TxErr))
@@ -2826,20 +2948,18 @@ out:
}
#ifdef CONFIG_R8169_NAPI
-static int rtl8169_poll(struct net_device *dev, int *budget)
+static int rtl8169_poll(struct napi_struct *napi, int budget)
{
- unsigned int work_done, work_to_do = min(*budget, dev->quota);
- struct rtl8169_private *tp = netdev_priv(dev);
+ struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
+ struct net_device *dev = tp->dev;
void __iomem *ioaddr = tp->mmio_addr;
+ int work_done;
- work_done = rtl8169_rx_interrupt(dev, tp, ioaddr);
+ work_done = rtl8169_rx_interrupt(dev, tp, ioaddr, (u32) budget);
rtl8169_tx_interrupt(dev, tp, ioaddr);
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (work_done < work_to_do) {
- netif_rx_complete(dev);
+ if (work_done < budget) {
+ netif_rx_complete(dev, napi);
tp->intr_mask = 0xffff;
/*
* 20040426: the barrier is not strictly required but the
@@ -2851,7 +2971,7 @@ static int rtl8169_poll(struct net_device *dev, int *budget)
RTL_W16(IntrMask, tp->intr_event);
}
- return (work_done >= work_to_do);
+ return work_done;
}
#endif
@@ -2859,31 +2979,29 @@ static void rtl8169_down(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
- unsigned int poll_locked = 0;
unsigned int intrmask;
rtl8169_delete_timer(dev);
netif_stop_queue(dev);
+#ifdef CONFIG_R8169_NAPI
+ napi_disable(&tp->napi);
+#endif
+
core_down:
spin_lock_irq(&tp->lock);
rtl8169_asic_down(ioaddr);
/* Update the error counts. */
- tp->stats.rx_missed_errors += RTL_R32(RxMissed);
+ dev->stats.rx_missed_errors += RTL_R32(RxMissed);
RTL_W32(RxMissed, 0);
spin_unlock_irq(&tp->lock);
synchronize_irq(dev->irq);
- if (!poll_locked) {
- netif_poll_disable(dev);
- poll_locked++;
- }
-
/* Give a racing hard_start_xmit a few cycles to complete. */
synchronize_sched(); /* FIXME: should this be synchronize_irq()? */
@@ -2918,8 +3036,6 @@ static int rtl8169_close(struct net_device *dev)
free_irq(dev->irq, dev);
- netif_poll_enable(dev);
-
pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
tp->RxPhyAddr);
pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,
@@ -2977,7 +3093,9 @@ static void rtl_set_rx_mode(struct net_device *dev)
(tp->mac_version == RTL_GIGA_MAC_VER_12) ||
(tp->mac_version == RTL_GIGA_MAC_VER_13) ||
(tp->mac_version == RTL_GIGA_MAC_VER_14) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_15)) {
+ (tp->mac_version == RTL_GIGA_MAC_VER_15) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_16) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_17)) {
mc_filter[0] = 0xffffffff;
mc_filter[1] = 0xffffffff;
}
@@ -3004,12 +3122,12 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev)
if (netif_running(dev)) {
spin_lock_irqsave(&tp->lock, flags);
- tp->stats.rx_missed_errors += RTL_R32(RxMissed);
+ dev->stats.rx_missed_errors += RTL_R32(RxMissed);
RTL_W32(RxMissed, 0);
spin_unlock_irqrestore(&tp->lock, flags);
}
- return &tp->stats;
+ return &dev->stats;
}
#ifdef CONFIG_PM
@@ -3030,14 +3148,15 @@ static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state)
rtl8169_asic_down(ioaddr);
- tp->stats.rx_missed_errors += RTL_R32(RxMissed);
+ dev->stats.rx_missed_errors += RTL_R32(RxMissed);
RTL_W32(RxMissed, 0);
spin_unlock_irq(&tp->lock);
out_pci_suspend:
pci_save_state(pdev);
- pci_enable_wake(pdev, pci_choose_state(pdev, state), tp->wol_enabled);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state),
+ (tp->features & RTL_FEATURE_WOL) ? 1 : 0);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index df6b73872fd..e7fd08adbba 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -53,7 +53,6 @@ struct rionet_private {
struct rio_mport *mport;
struct sk_buff *rx_skb[RIONET_RX_RING_SIZE];
struct sk_buff *tx_skb[RIONET_TX_RING_SIZE];
- struct net_device_stats stats;
int rx_slot;
int tx_slot;
int tx_cnt;
@@ -91,12 +90,6 @@ static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES];
#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001)
#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4))
-static struct net_device_stats *rionet_stats(struct net_device *ndev)
-{
- struct rionet_private *rnet = ndev->priv;
- return &rnet->stats;
-}
-
static int rionet_rx_clean(struct net_device *ndev)
{
int i;
@@ -120,15 +113,15 @@ static int rionet_rx_clean(struct net_device *ndev)
error = netif_rx(rnet->rx_skb[i]);
if (error == NET_RX_DROP) {
- rnet->stats.rx_dropped++;
+ ndev->stats.rx_dropped++;
} else if (error == NET_RX_BAD) {
if (netif_msg_rx_err(rnet))
printk(KERN_WARNING "%s: bad rx packet\n",
DRV_NAME);
- rnet->stats.rx_errors++;
+ ndev->stats.rx_errors++;
} else {
- rnet->stats.rx_packets++;
- rnet->stats.rx_bytes += RIO_MAX_MSG_SIZE;
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE;
}
} while ((i = (i + 1) % RIONET_RX_RING_SIZE) != rnet->rx_slot);
@@ -163,8 +156,8 @@ static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev,
rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len);
rnet->tx_skb[rnet->tx_slot] = skb;
- rnet->stats.tx_packets++;
- rnet->stats.tx_bytes += skb->len;
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += skb->len;
if (++rnet->tx_cnt == RIONET_TX_RING_SIZE)
netif_stop_queue(ndev);
@@ -439,6 +432,7 @@ static int rionet_setup_netdev(struct rio_mport *mport)
struct net_device *ndev = NULL;
struct rionet_private *rnet;
u16 device_id;
+ DECLARE_MAC_BUF(mac);
/* Allocate our net_device structure */
ndev = alloc_etherdev(sizeof(struct rionet_private));
@@ -466,13 +460,10 @@ static int rionet_setup_netdev(struct rio_mport *mport)
ndev->open = &rionet_open;
ndev->hard_start_xmit = &rionet_start_xmit;
ndev->stop = &rionet_close;
- ndev->get_stats = &rionet_stats;
ndev->mtu = RIO_MAX_MSG_SIZE - 14;
ndev->features = NETIF_F_LLTX;
SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops);
- SET_MODULE_OWNER(ndev);
-
spin_lock_init(&rnet->lock);
spin_lock_init(&rnet->tx_lock);
@@ -482,13 +473,12 @@ static int rionet_setup_netdev(struct rio_mport *mport)
if (rc != 0)
goto out;
- printk("%s: %s %s Version %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ printk("%s: %s %s Version %s, MAC %s\n",
ndev->name,
DRV_NAME,
DRV_DESC,
DRV_VERSION,
- ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
- ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+ print_mac(mac, ndev->dev_addr));
out:
return rc;
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 5c2e41fac6d..73a7e6529ee 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -78,14 +78,6 @@ static char version[] __devinitdata = "rrunner.c: v0.50 11/11/2002 Jes Sorensen
* stack will need to know about I/O vectors or something similar.
*/
-/*
- * These are checked at init time to see if they are at least 256KB
- * and increased to 256KB if they are not. This is done to avoid ending
- * up with socket buffers smaller than the MTU size,
- */
-extern __u32 sysctl_wmem_max;
-extern __u32 sysctl_rmem_max;
-
static int __devinit rr_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -109,7 +101,6 @@ static int __devinit rr_init_one(struct pci_dev *pdev,
rrpriv = netdev_priv(dev);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_request_regions(pdev, "rrunner")) {
@@ -127,7 +118,6 @@ static int __devinit rr_init_one(struct pci_dev *pdev,
dev->open = &rr_open;
dev->hard_start_xmit = &rr_start_xmit;
dev->stop = &rr_close;
- dev->get_stats = &rr_get_stats;
dev->do_ioctl = &rr_ioctl;
dev->base_addr = pci_resource_start(pdev, 0);
@@ -522,7 +512,7 @@ static int __devinit rr_init(struct net_device *dev)
struct rr_regs __iomem *regs;
struct eeprom *hw = NULL;
u32 sram_size, rev;
- int i;
+ DECLARE_MAC_BUF(mac);
rrpriv = netdev_priv(dev);
regs = rrpriv->regs;
@@ -560,27 +550,11 @@ static int __devinit rr_init(struct net_device *dev)
*(u32 *)(dev->dev_addr+2) =
htonl(rr_read_eeprom_word(rrpriv, &hw->manf.BoardULA[4]));
- printk(" MAC: ");
-
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x\n", dev->dev_addr[i]);
+ printk(" MAC: %s\n", print_mac(mac, dev->dev_addr));
sram_size = rr_read_eeprom_word(rrpriv, (void *)8);
printk(" SRAM size 0x%06x\n", sram_size);
- if (sysctl_rmem_max < 262144){
- printk(" Receive socket buffer limit too low (%i), "
- "setting to 262144\n", sysctl_rmem_max);
- sysctl_rmem_max = 262144;
- }
-
- if (sysctl_wmem_max < 262144){
- printk(" Transmit socket buffer limit too low (%i), "
- "setting to 262144\n", sysctl_wmem_max);
- sysctl_wmem_max = 262144;
- }
-
return 0;
}
@@ -809,7 +783,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
case E_CON_REJ:
printk(KERN_WARNING "%s: Connection rejected\n",
dev->name);
- rrpriv->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
break;
case E_CON_TMOUT:
printk(KERN_WARNING "%s: Connection timeout\n",
@@ -818,7 +792,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
case E_DISC_ERR:
printk(KERN_WARNING "%s: HIPPI disconnect error\n",
dev->name);
- rrpriv->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
break;
case E_INT_PRTY:
printk(KERN_ERR "%s: HIPPI Internal Parity error\n",
@@ -834,7 +808,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
case E_TX_LINK_DROP:
printk(KERN_WARNING "%s: Link lost during transmit\n",
dev->name);
- rrpriv->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
&regs->HostCtrl);
wmb();
@@ -974,7 +948,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index)
printk("len %x, mode %x\n", pkt_len, desc->mode);
#endif
if ( (rrpriv->rx_ring[index].mode & PACKET_BAD) == PACKET_BAD){
- rrpriv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto defer;
}
@@ -987,7 +961,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index)
skb = alloc_skb(pkt_len, GFP_ATOMIC);
if (skb == NULL){
printk(KERN_WARNING "%s: Unable to allocate skb (%i bytes), deferring packet\n", dev->name, pkt_len);
- rrpriv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto defer;
} else {
pci_dma_sync_single_for_cpu(rrpriv->pci_dev,
@@ -1025,7 +999,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index)
} else {
printk("%s: Out of memory, deferring "
"packet\n", dev->name);
- rrpriv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto defer;
}
}
@@ -1034,8 +1008,8 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index)
netif_rx(skb); /* send it up */
dev->last_rx = jiffies;
- rrpriv->stats.rx_packets++;
- rrpriv->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
defer:
desc->mode = 0;
@@ -1103,8 +1077,8 @@ static irqreturn_t rr_interrupt(int irq, void *dev_id)
desc = &(rrpriv->tx_ring[txcon]);
skb = rrpriv->tx_skbuff[txcon];
- rrpriv->stats.tx_packets++;
- rrpriv->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
pci_unmap_single(rrpriv->pci_dev,
desc->addr.addrlo, skb->len,
@@ -1492,16 +1466,6 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
-static struct net_device_stats *rr_get_stats(struct net_device *dev)
-{
- struct rr_private *rrpriv;
-
- rrpriv = netdev_priv(dev);
-
- return(&rrpriv->stats);
-}
-
-
/*
* Read the firmware out of the EEPROM and put it into the SRAM
* (or from user space - later)
diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h
index 9f3e050c4dc..6a79825bc8c 100644
--- a/drivers/net/rrunner.h
+++ b/drivers/net/rrunner.h
@@ -819,7 +819,6 @@ struct rr_private
u32 tx_full;
u32 fw_rev;
volatile short fw_running;
- struct net_device_stats stats;
struct pci_dev *pci_dev;
};
@@ -834,7 +833,6 @@ static irqreturn_t rr_interrupt(int irq, void *dev_id);
static int rr_open(struct net_device *dev);
static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int rr_close(struct net_device *dev);
-static struct net_device_stats *rr_get_stats(struct net_device *dev);
static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static unsigned int rr_read_eeprom(struct rr_private *rrpriv,
unsigned long offset,
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index cfa26791447..01f08d726ac 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -20,17 +20,17 @@ struct XENA_dev_config {
/* General Control-Status Registers */
u64 general_int_status;
-#define GEN_INTR_TXPIC BIT(0)
-#define GEN_INTR_TXDMA BIT(1)
-#define GEN_INTR_TXMAC BIT(2)
-#define GEN_INTR_TXXGXS BIT(3)
-#define GEN_INTR_TXTRAFFIC BIT(8)
-#define GEN_INTR_RXPIC BIT(32)
-#define GEN_INTR_RXDMA BIT(33)
-#define GEN_INTR_RXMAC BIT(34)
-#define GEN_INTR_MC BIT(35)
-#define GEN_INTR_RXXGXS BIT(36)
-#define GEN_INTR_RXTRAFFIC BIT(40)
+#define GEN_INTR_TXPIC s2BIT(0)
+#define GEN_INTR_TXDMA s2BIT(1)
+#define GEN_INTR_TXMAC s2BIT(2)
+#define GEN_INTR_TXXGXS s2BIT(3)
+#define GEN_INTR_TXTRAFFIC s2BIT(8)
+#define GEN_INTR_RXPIC s2BIT(32)
+#define GEN_INTR_RXDMA s2BIT(33)
+#define GEN_INTR_RXMAC s2BIT(34)
+#define GEN_INTR_MC s2BIT(35)
+#define GEN_INTR_RXXGXS s2BIT(36)
+#define GEN_INTR_RXTRAFFIC s2BIT(40)
#define GEN_ERROR_INTR GEN_INTR_TXPIC | GEN_INTR_RXPIC | \
GEN_INTR_TXDMA | GEN_INTR_RXDMA | \
GEN_INTR_TXMAC | GEN_INTR_RXMAC | \
@@ -54,36 +54,36 @@ struct XENA_dev_config {
u64 adapter_status;
-#define ADAPTER_STATUS_TDMA_READY BIT(0)
-#define ADAPTER_STATUS_RDMA_READY BIT(1)
-#define ADAPTER_STATUS_PFC_READY BIT(2)
-#define ADAPTER_STATUS_TMAC_BUF_EMPTY BIT(3)
-#define ADAPTER_STATUS_PIC_QUIESCENT BIT(5)
-#define ADAPTER_STATUS_RMAC_REMOTE_FAULT BIT(6)
-#define ADAPTER_STATUS_RMAC_LOCAL_FAULT BIT(7)
+#define ADAPTER_STATUS_TDMA_READY s2BIT(0)
+#define ADAPTER_STATUS_RDMA_READY s2BIT(1)
+#define ADAPTER_STATUS_PFC_READY s2BIT(2)
+#define ADAPTER_STATUS_TMAC_BUF_EMPTY s2BIT(3)
+#define ADAPTER_STATUS_PIC_QUIESCENT s2BIT(5)
+#define ADAPTER_STATUS_RMAC_REMOTE_FAULT s2BIT(6)
+#define ADAPTER_STATUS_RMAC_LOCAL_FAULT s2BIT(7)
#define ADAPTER_STATUS_RMAC_PCC_IDLE vBIT(0xFF,8,8)
#define ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE vBIT(0x0F,8,8)
#define ADAPTER_STATUS_RC_PRC_QUIESCENT vBIT(0xFF,16,8)
-#define ADAPTER_STATUS_MC_DRAM_READY BIT(24)
-#define ADAPTER_STATUS_MC_QUEUES_READY BIT(25)
-#define ADAPTER_STATUS_M_PLL_LOCK BIT(30)
-#define ADAPTER_STATUS_P_PLL_LOCK BIT(31)
+#define ADAPTER_STATUS_MC_DRAM_READY s2BIT(24)
+#define ADAPTER_STATUS_MC_QUEUES_READY s2BIT(25)
+#define ADAPTER_STATUS_M_PLL_LOCK s2BIT(30)
+#define ADAPTER_STATUS_P_PLL_LOCK s2BIT(31)
u64 adapter_control;
-#define ADAPTER_CNTL_EN BIT(7)
-#define ADAPTER_EOI_TX_ON BIT(15)
-#define ADAPTER_LED_ON BIT(23)
+#define ADAPTER_CNTL_EN s2BIT(7)
+#define ADAPTER_EOI_TX_ON s2BIT(15)
+#define ADAPTER_LED_ON s2BIT(23)
#define ADAPTER_UDPI(val) vBIT(val,36,4)
-#define ADAPTER_WAIT_INT BIT(48)
-#define ADAPTER_ECC_EN BIT(55)
+#define ADAPTER_WAIT_INT s2BIT(48)
+#define ADAPTER_ECC_EN s2BIT(55)
u64 serr_source;
-#define SERR_SOURCE_PIC BIT(0)
-#define SERR_SOURCE_TXDMA BIT(1)
-#define SERR_SOURCE_RXDMA BIT(2)
-#define SERR_SOURCE_MAC BIT(3)
-#define SERR_SOURCE_MC BIT(4)
-#define SERR_SOURCE_XGXS BIT(5)
+#define SERR_SOURCE_PIC s2BIT(0)
+#define SERR_SOURCE_TXDMA s2BIT(1)
+#define SERR_SOURCE_RXDMA s2BIT(2)
+#define SERR_SOURCE_MAC s2BIT(3)
+#define SERR_SOURCE_MC s2BIT(4)
+#define SERR_SOURCE_XGXS s2BIT(5)
#define SERR_SOURCE_ANY (SERR_SOURCE_PIC | \
SERR_SOURCE_TXDMA | \
SERR_SOURCE_RXDMA | \
@@ -101,41 +101,41 @@ struct XENA_dev_config {
#define PCI_MODE_PCIX_M2_66 0x5
#define PCI_MODE_PCIX_M2_100 0x6
#define PCI_MODE_PCIX_M2_133 0x7
-#define PCI_MODE_UNSUPPORTED BIT(0)
-#define PCI_MODE_32_BITS BIT(8)
-#define PCI_MODE_UNKNOWN_MODE BIT(9)
+#define PCI_MODE_UNSUPPORTED s2BIT(0)
+#define PCI_MODE_32_BITS s2BIT(8)
+#define PCI_MODE_UNKNOWN_MODE s2BIT(9)
u8 unused_0[0x800 - 0x128];
/* PCI-X Controller registers */
u64 pic_int_status;
u64 pic_int_mask;
-#define PIC_INT_TX BIT(0)
-#define PIC_INT_FLSH BIT(1)
-#define PIC_INT_MDIO BIT(2)
-#define PIC_INT_IIC BIT(3)
-#define PIC_INT_GPIO BIT(4)
-#define PIC_INT_RX BIT(32)
+#define PIC_INT_TX s2BIT(0)
+#define PIC_INT_FLSH s2BIT(1)
+#define PIC_INT_MDIO s2BIT(2)
+#define PIC_INT_IIC s2BIT(3)
+#define PIC_INT_GPIO s2BIT(4)
+#define PIC_INT_RX s2BIT(32)
u64 txpic_int_reg;
u64 txpic_int_mask;
-#define PCIX_INT_REG_ECC_SG_ERR BIT(0)
-#define PCIX_INT_REG_ECC_DB_ERR BIT(1)
-#define PCIX_INT_REG_FLASHR_R_FSM_ERR BIT(8)
-#define PCIX_INT_REG_FLASHR_W_FSM_ERR BIT(9)
-#define PCIX_INT_REG_INI_TX_FSM_SERR BIT(10)
-#define PCIX_INT_REG_INI_TXO_FSM_ERR BIT(11)
-#define PCIX_INT_REG_TRT_FSM_SERR BIT(13)
-#define PCIX_INT_REG_SRT_FSM_SERR BIT(14)
-#define PCIX_INT_REG_PIFR_FSM_SERR BIT(15)
-#define PCIX_INT_REG_WRC_TX_SEND_FSM_SERR BIT(21)
-#define PCIX_INT_REG_RRC_TX_REQ_FSM_SERR BIT(23)
-#define PCIX_INT_REG_INI_RX_FSM_SERR BIT(48)
-#define PCIX_INT_REG_RA_RX_FSM_SERR BIT(50)
+#define PCIX_INT_REG_ECC_SG_ERR s2BIT(0)
+#define PCIX_INT_REG_ECC_DB_ERR s2BIT(1)
+#define PCIX_INT_REG_FLASHR_R_FSM_ERR s2BIT(8)
+#define PCIX_INT_REG_FLASHR_W_FSM_ERR s2BIT(9)
+#define PCIX_INT_REG_INI_TX_FSM_SERR s2BIT(10)
+#define PCIX_INT_REG_INI_TXO_FSM_ERR s2BIT(11)
+#define PCIX_INT_REG_TRT_FSM_SERR s2BIT(13)
+#define PCIX_INT_REG_SRT_FSM_SERR s2BIT(14)
+#define PCIX_INT_REG_PIFR_FSM_SERR s2BIT(15)
+#define PCIX_INT_REG_WRC_TX_SEND_FSM_SERR s2BIT(21)
+#define PCIX_INT_REG_RRC_TX_REQ_FSM_SERR s2BIT(23)
+#define PCIX_INT_REG_INI_RX_FSM_SERR s2BIT(48)
+#define PCIX_INT_REG_RA_RX_FSM_SERR s2BIT(50)
/*
-#define PCIX_INT_REG_WRC_RX_SEND_FSM_SERR BIT(52)
-#define PCIX_INT_REG_RRC_RX_REQ_FSM_SERR BIT(54)
-#define PCIX_INT_REG_RRC_RX_SPLIT_FSM_SERR BIT(58)
+#define PCIX_INT_REG_WRC_RX_SEND_FSM_SERR s2BIT(52)
+#define PCIX_INT_REG_RRC_RX_REQ_FSM_SERR s2BIT(54)
+#define PCIX_INT_REG_RRC_RX_SPLIT_FSM_SERR s2BIT(58)
*/
u64 txpic_alarms;
u64 rxpic_int_reg;
@@ -144,92 +144,92 @@ struct XENA_dev_config {
u64 flsh_int_reg;
u64 flsh_int_mask;
-#define PIC_FLSH_INT_REG_CYCLE_FSM_ERR BIT(63)
-#define PIC_FLSH_INT_REG_ERR BIT(62)
+#define PIC_FLSH_INT_REG_CYCLE_FSM_ERR s2BIT(63)
+#define PIC_FLSH_INT_REG_ERR s2BIT(62)
u64 flash_alarms;
u64 mdio_int_reg;
u64 mdio_int_mask;
-#define MDIO_INT_REG_MDIO_BUS_ERR BIT(0)
-#define MDIO_INT_REG_DTX_BUS_ERR BIT(8)
-#define MDIO_INT_REG_LASI BIT(39)
+#define MDIO_INT_REG_MDIO_BUS_ERR s2BIT(0)
+#define MDIO_INT_REG_DTX_BUS_ERR s2BIT(8)
+#define MDIO_INT_REG_LASI s2BIT(39)
u64 mdio_alarms;
u64 iic_int_reg;
u64 iic_int_mask;
-#define IIC_INT_REG_BUS_FSM_ERR BIT(4)
-#define IIC_INT_REG_BIT_FSM_ERR BIT(5)
-#define IIC_INT_REG_CYCLE_FSM_ERR BIT(6)
-#define IIC_INT_REG_REQ_FSM_ERR BIT(7)
-#define IIC_INT_REG_ACK_ERR BIT(8)
+#define IIC_INT_REG_BUS_FSM_ERR s2BIT(4)
+#define IIC_INT_REG_BIT_FSM_ERR s2BIT(5)
+#define IIC_INT_REG_CYCLE_FSM_ERR s2BIT(6)
+#define IIC_INT_REG_REQ_FSM_ERR s2BIT(7)
+#define IIC_INT_REG_ACK_ERR s2BIT(8)
u64 iic_alarms;
u8 unused4[0x08];
u64 gpio_int_reg;
-#define GPIO_INT_REG_DP_ERR_INT BIT(0)
-#define GPIO_INT_REG_LINK_DOWN BIT(1)
-#define GPIO_INT_REG_LINK_UP BIT(2)
+#define GPIO_INT_REG_DP_ERR_INT s2BIT(0)
+#define GPIO_INT_REG_LINK_DOWN s2BIT(1)
+#define GPIO_INT_REG_LINK_UP s2BIT(2)
u64 gpio_int_mask;
-#define GPIO_INT_MASK_LINK_DOWN BIT(1)
-#define GPIO_INT_MASK_LINK_UP BIT(2)
+#define GPIO_INT_MASK_LINK_DOWN s2BIT(1)
+#define GPIO_INT_MASK_LINK_UP s2BIT(2)
u64 gpio_alarms;
u8 unused5[0x38];
u64 tx_traffic_int;
-#define TX_TRAFFIC_INT_n(n) BIT(n)
+#define TX_TRAFFIC_INT_n(n) s2BIT(n)
u64 tx_traffic_mask;
u64 rx_traffic_int;
-#define RX_TRAFFIC_INT_n(n) BIT(n)
+#define RX_TRAFFIC_INT_n(n) s2BIT(n)
u64 rx_traffic_mask;
/* PIC Control registers */
u64 pic_control;
-#define PIC_CNTL_RX_ALARM_MAP_1 BIT(0)
+#define PIC_CNTL_RX_ALARM_MAP_1 s2BIT(0)
#define PIC_CNTL_SHARED_SPLITS(n) vBIT(n,11,5)
u64 swapper_ctrl;
-#define SWAPPER_CTRL_PIF_R_FE BIT(0)
-#define SWAPPER_CTRL_PIF_R_SE BIT(1)
-#define SWAPPER_CTRL_PIF_W_FE BIT(8)
-#define SWAPPER_CTRL_PIF_W_SE BIT(9)
-#define SWAPPER_CTRL_TXP_FE BIT(16)
-#define SWAPPER_CTRL_TXP_SE BIT(17)
-#define SWAPPER_CTRL_TXD_R_FE BIT(18)
-#define SWAPPER_CTRL_TXD_R_SE BIT(19)
-#define SWAPPER_CTRL_TXD_W_FE BIT(20)
-#define SWAPPER_CTRL_TXD_W_SE BIT(21)
-#define SWAPPER_CTRL_TXF_R_FE BIT(22)
-#define SWAPPER_CTRL_TXF_R_SE BIT(23)
-#define SWAPPER_CTRL_RXD_R_FE BIT(32)
-#define SWAPPER_CTRL_RXD_R_SE BIT(33)
-#define SWAPPER_CTRL_RXD_W_FE BIT(34)
-#define SWAPPER_CTRL_RXD_W_SE BIT(35)
-#define SWAPPER_CTRL_RXF_W_FE BIT(36)
-#define SWAPPER_CTRL_RXF_W_SE BIT(37)
-#define SWAPPER_CTRL_XMSI_FE BIT(40)
-#define SWAPPER_CTRL_XMSI_SE BIT(41)
-#define SWAPPER_CTRL_STATS_FE BIT(48)
-#define SWAPPER_CTRL_STATS_SE BIT(49)
+#define SWAPPER_CTRL_PIF_R_FE s2BIT(0)
+#define SWAPPER_CTRL_PIF_R_SE s2BIT(1)
+#define SWAPPER_CTRL_PIF_W_FE s2BIT(8)
+#define SWAPPER_CTRL_PIF_W_SE s2BIT(9)
+#define SWAPPER_CTRL_TXP_FE s2BIT(16)
+#define SWAPPER_CTRL_TXP_SE s2BIT(17)
+#define SWAPPER_CTRL_TXD_R_FE s2BIT(18)
+#define SWAPPER_CTRL_TXD_R_SE s2BIT(19)
+#define SWAPPER_CTRL_TXD_W_FE s2BIT(20)
+#define SWAPPER_CTRL_TXD_W_SE s2BIT(21)
+#define SWAPPER_CTRL_TXF_R_FE s2BIT(22)
+#define SWAPPER_CTRL_TXF_R_SE s2BIT(23)
+#define SWAPPER_CTRL_RXD_R_FE s2BIT(32)
+#define SWAPPER_CTRL_RXD_R_SE s2BIT(33)
+#define SWAPPER_CTRL_RXD_W_FE s2BIT(34)
+#define SWAPPER_CTRL_RXD_W_SE s2BIT(35)
+#define SWAPPER_CTRL_RXF_W_FE s2BIT(36)
+#define SWAPPER_CTRL_RXF_W_SE s2BIT(37)
+#define SWAPPER_CTRL_XMSI_FE s2BIT(40)
+#define SWAPPER_CTRL_XMSI_SE s2BIT(41)
+#define SWAPPER_CTRL_STATS_FE s2BIT(48)
+#define SWAPPER_CTRL_STATS_SE s2BIT(49)
u64 pif_rd_swapper_fb;
#define IF_RD_SWAPPER_FB 0x0123456789ABCDEF
u64 scheduled_int_ctrl;
-#define SCHED_INT_CTRL_TIMER_EN BIT(0)
-#define SCHED_INT_CTRL_ONE_SHOT BIT(1)
-#define SCHED_INT_CTRL_INT2MSI TBD
+#define SCHED_INT_CTRL_TIMER_EN s2BIT(0)
+#define SCHED_INT_CTRL_ONE_SHOT s2BIT(1)
+#define SCHED_INT_CTRL_INT2MSI(val) vBIT(val,10,6)
#define SCHED_INT_PERIOD TBD
u64 txreqtimeout;
#define TXREQTO_VAL(val) vBIT(val,0,32)
-#define TXREQTO_EN BIT(63)
+#define TXREQTO_EN s2BIT(63)
u64 statsreqtimeout;
#define STATREQTO_VAL(n) TBD
-#define STATREQTO_EN BIT(63)
+#define STATREQTO_EN s2BIT(63)
u64 read_retry_delay;
u64 read_retry_acceleration;
@@ -255,10 +255,10 @@ struct XENA_dev_config {
/* Automated statistics collection */
u64 stat_cfg;
-#define STAT_CFG_STAT_EN BIT(0)
-#define STAT_CFG_ONE_SHOT_EN BIT(1)
-#define STAT_CFG_STAT_NS_EN BIT(8)
-#define STAT_CFG_STAT_RO BIT(9)
+#define STAT_CFG_STAT_EN s2BIT(0)
+#define STAT_CFG_ONE_SHOT_EN s2BIT(1)
+#define STAT_CFG_STAT_NS_EN s2BIT(8)
+#define STAT_CFG_STAT_RO s2BIT(9)
#define STAT_TRSF_PER(n) TBD
#define PER_SEC 0x208d5
#define SET_UPDT_PERIOD(n) vBIT((PER_SEC*n),32,32)
@@ -290,18 +290,18 @@ struct XENA_dev_config {
#define I2C_CONTROL_DEV_ID(id) vBIT(id,1,3)
#define I2C_CONTROL_ADDR(addr) vBIT(addr,5,11)
#define I2C_CONTROL_BYTE_CNT(cnt) vBIT(cnt,22,2)
-#define I2C_CONTROL_READ BIT(24)
-#define I2C_CONTROL_NACK BIT(25)
+#define I2C_CONTROL_READ s2BIT(24)
+#define I2C_CONTROL_NACK s2BIT(25)
#define I2C_CONTROL_CNTL_START vBIT(0xE,28,4)
#define I2C_CONTROL_CNTL_END(val) (val & vBIT(0x1,28,4))
#define I2C_CONTROL_GET_DATA(val) (u32)(val & 0xFFFFFFFF)
#define I2C_CONTROL_SET_DATA(val) vBIT(val,32,32)
u64 gpio_control;
-#define GPIO_CTRL_GPIO_0 BIT(8)
+#define GPIO_CTRL_GPIO_0 s2BIT(8)
u64 misc_control;
-#define FAULT_BEHAVIOUR BIT(0)
-#define EXT_REQ_EN BIT(1)
+#define FAULT_BEHAVIOUR s2BIT(0)
+#define EXT_REQ_EN s2BIT(1)
#define MISC_LINK_STABILITY_PRD(val) vBIT(val,29,3)
u8 unused7_1[0x230 - 0x208];
@@ -317,41 +317,74 @@ struct XENA_dev_config {
/* TxDMA registers */
u64 txdma_int_status;
u64 txdma_int_mask;
-#define TXDMA_PFC_INT BIT(0)
-#define TXDMA_TDA_INT BIT(1)
-#define TXDMA_PCC_INT BIT(2)
-#define TXDMA_TTI_INT BIT(3)
-#define TXDMA_LSO_INT BIT(4)
-#define TXDMA_TPA_INT BIT(5)
-#define TXDMA_SM_INT BIT(6)
+#define TXDMA_PFC_INT s2BIT(0)
+#define TXDMA_TDA_INT s2BIT(1)
+#define TXDMA_PCC_INT s2BIT(2)
+#define TXDMA_TTI_INT s2BIT(3)
+#define TXDMA_LSO_INT s2BIT(4)
+#define TXDMA_TPA_INT s2BIT(5)
+#define TXDMA_SM_INT s2BIT(6)
u64 pfc_err_reg;
+#define PFC_ECC_SG_ERR s2BIT(7)
+#define PFC_ECC_DB_ERR s2BIT(15)
+#define PFC_SM_ERR_ALARM s2BIT(23)
+#define PFC_MISC_0_ERR s2BIT(31)
+#define PFC_MISC_1_ERR s2BIT(32)
+#define PFC_PCIX_ERR s2BIT(39)
u64 pfc_err_mask;
u64 pfc_err_alarm;
u64 tda_err_reg;
+#define TDA_Fn_ECC_SG_ERR vBIT(0xff,0,8)
+#define TDA_Fn_ECC_DB_ERR vBIT(0xff,8,8)
+#define TDA_SM0_ERR_ALARM s2BIT(22)
+#define TDA_SM1_ERR_ALARM s2BIT(23)
+#define TDA_PCIX_ERR s2BIT(39)
u64 tda_err_mask;
u64 tda_err_alarm;
u64 pcc_err_reg;
-#define PCC_FB_ECC_DB_ERR vBIT(0xFF, 16, 8)
+#define PCC_FB_ECC_SG_ERR vBIT(0xFF,0,8)
+#define PCC_TXB_ECC_SG_ERR vBIT(0xFF,8,8)
+#define PCC_FB_ECC_DB_ERR vBIT(0xFF,16, 8)
+#define PCC_TXB_ECC_DB_ERR vBIT(0xff,24,8)
+#define PCC_SM_ERR_ALARM vBIT(0xff,32,8)
+#define PCC_WR_ERR_ALARM vBIT(0xff,40,8)
+#define PCC_N_SERR vBIT(0xff,48,8)
+#define PCC_6_COF_OV_ERR s2BIT(56)
+#define PCC_7_COF_OV_ERR s2BIT(57)
+#define PCC_6_LSO_OV_ERR s2BIT(58)
+#define PCC_7_LSO_OV_ERR s2BIT(59)
#define PCC_ENABLE_FOUR vBIT(0x0F,0,8)
-
u64 pcc_err_mask;
u64 pcc_err_alarm;
u64 tti_err_reg;
+#define TTI_ECC_SG_ERR s2BIT(7)
+#define TTI_ECC_DB_ERR s2BIT(15)
+#define TTI_SM_ERR_ALARM s2BIT(23)
u64 tti_err_mask;
u64 tti_err_alarm;
u64 lso_err_reg;
+#define LSO6_SEND_OFLOW s2BIT(12)
+#define LSO7_SEND_OFLOW s2BIT(13)
+#define LSO6_ABORT s2BIT(14)
+#define LSO7_ABORT s2BIT(15)
+#define LSO6_SM_ERR_ALARM s2BIT(22)
+#define LSO7_SM_ERR_ALARM s2BIT(23)
u64 lso_err_mask;
u64 lso_err_alarm;
u64 tpa_err_reg;
+#define TPA_TX_FRM_DROP s2BIT(7)
+#define TPA_SM_ERR_ALARM s2BIT(23)
+
u64 tpa_err_mask;
u64 tpa_err_alarm;
u64 sm_err_reg;
+#define SM_SM_ERR_ALARM s2BIT(15)
u64 sm_err_mask;
u64 sm_err_alarm;
@@ -364,7 +397,7 @@ struct XENA_dev_config {
#define X_MAX_FIFOS 8
#define X_FIFO_MAX_LEN 0x1FFF /*8191 */
u64 tx_fifo_partition_0;
-#define TX_FIFO_PARTITION_EN BIT(0)
+#define TX_FIFO_PARTITION_EN s2BIT(0)
#define TX_FIFO_PARTITION_0_PRI(val) vBIT(val,5,3)
#define TX_FIFO_PARTITION_0_LEN(val) vBIT(val,19,13)
#define TX_FIFO_PARTITION_1_PRI(val) vBIT(val,37,3)
@@ -404,16 +437,16 @@ struct XENA_dev_config {
u64 tx_w_round_robin_4;
u64 tti_command_mem;
-#define TTI_CMD_MEM_WE BIT(7)
-#define TTI_CMD_MEM_STROBE_NEW_CMD BIT(15)
-#define TTI_CMD_MEM_STROBE_BEING_EXECUTED BIT(15)
+#define TTI_CMD_MEM_WE s2BIT(7)
+#define TTI_CMD_MEM_STROBE_NEW_CMD s2BIT(15)
+#define TTI_CMD_MEM_STROBE_BEING_EXECUTED s2BIT(15)
#define TTI_CMD_MEM_OFFSET(n) vBIT(n,26,6)
u64 tti_data1_mem;
#define TTI_DATA1_MEM_TX_TIMER_VAL(n) vBIT(n,6,26)
#define TTI_DATA1_MEM_TX_TIMER_AC_CI(n) vBIT(n,38,2)
-#define TTI_DATA1_MEM_TX_TIMER_AC_EN BIT(38)
-#define TTI_DATA1_MEM_TX_TIMER_CI_EN BIT(39)
+#define TTI_DATA1_MEM_TX_TIMER_AC_EN s2BIT(38)
+#define TTI_DATA1_MEM_TX_TIMER_CI_EN s2BIT(39)
#define TTI_DATA1_MEM_TX_URNG_A(n) vBIT(n,41,7)
#define TTI_DATA1_MEM_TX_URNG_B(n) vBIT(n,49,7)
#define TTI_DATA1_MEM_TX_URNG_C(n) vBIT(n,57,7)
@@ -426,11 +459,11 @@ struct XENA_dev_config {
/* Tx Protocol assist */
u64 tx_pa_cfg;
-#define TX_PA_CFG_IGNORE_FRM_ERR BIT(1)
-#define TX_PA_CFG_IGNORE_SNAP_OUI BIT(2)
-#define TX_PA_CFG_IGNORE_LLC_CTRL BIT(3)
-#define TX_PA_CFG_IGNORE_L2_ERR BIT(6)
-#define RX_PA_CFG_STRIP_VLAN_TAG BIT(15)
+#define TX_PA_CFG_IGNORE_FRM_ERR s2BIT(1)
+#define TX_PA_CFG_IGNORE_SNAP_OUI s2BIT(2)
+#define TX_PA_CFG_IGNORE_LLC_CTRL s2BIT(3)
+#define TX_PA_CFG_IGNORE_L2_ERR s2BIT(6)
+#define RX_PA_CFG_STRIP_VLAN_TAG s2BIT(15)
/* Recent add, used only debug purposes. */
u64 pcc_enable;
@@ -444,28 +477,58 @@ struct XENA_dev_config {
/* RxDMA Registers */
u64 rxdma_int_status;
u64 rxdma_int_mask;
-#define RXDMA_INT_RC_INT_M BIT(0)
-#define RXDMA_INT_RPA_INT_M BIT(1)
-#define RXDMA_INT_RDA_INT_M BIT(2)
-#define RXDMA_INT_RTI_INT_M BIT(3)
+#define RXDMA_INT_RC_INT_M s2BIT(0)
+#define RXDMA_INT_RPA_INT_M s2BIT(1)
+#define RXDMA_INT_RDA_INT_M s2BIT(2)
+#define RXDMA_INT_RTI_INT_M s2BIT(3)
u64 rda_err_reg;
+#define RDA_RXDn_ECC_SG_ERR vBIT(0xFF,0,8)
+#define RDA_RXDn_ECC_DB_ERR vBIT(0xFF,8,8)
+#define RDA_FRM_ECC_SG_ERR s2BIT(23)
+#define RDA_FRM_ECC_DB_N_AERR s2BIT(31)
+#define RDA_SM1_ERR_ALARM s2BIT(38)
+#define RDA_SM0_ERR_ALARM s2BIT(39)
+#define RDA_MISC_ERR s2BIT(47)
+#define RDA_PCIX_ERR s2BIT(55)
+#define RDA_RXD_ECC_DB_SERR s2BIT(63)
u64 rda_err_mask;
u64 rda_err_alarm;
u64 rc_err_reg;
+#define RC_PRCn_ECC_SG_ERR vBIT(0xFF,0,8)
+#define RC_PRCn_ECC_DB_ERR vBIT(0xFF,8,8)
+#define RC_FTC_ECC_SG_ERR s2BIT(23)
+#define RC_FTC_ECC_DB_ERR s2BIT(31)
+#define RC_PRCn_SM_ERR_ALARM vBIT(0xFF,32,8)
+#define RC_FTC_SM_ERR_ALARM s2BIT(47)
+#define RC_RDA_FAIL_WR_Rn vBIT(0xFF,48,8)
u64 rc_err_mask;
u64 rc_err_alarm;
u64 prc_pcix_err_reg;
+#define PRC_PCI_AB_RD_Rn vBIT(0xFF,0,8)
+#define PRC_PCI_DP_RD_Rn vBIT(0xFF,8,8)
+#define PRC_PCI_AB_WR_Rn vBIT(0xFF,16,8)
+#define PRC_PCI_DP_WR_Rn vBIT(0xFF,24,8)
+#define PRC_PCI_AB_F_WR_Rn vBIT(0xFF,32,8)
+#define PRC_PCI_DP_F_WR_Rn vBIT(0xFF,40,8)
u64 prc_pcix_err_mask;
u64 prc_pcix_err_alarm;
u64 rpa_err_reg;
+#define RPA_ECC_SG_ERR s2BIT(7)
+#define RPA_ECC_DB_ERR s2BIT(15)
+#define RPA_FLUSH_REQUEST s2BIT(22)
+#define RPA_SM_ERR_ALARM s2BIT(23)
+#define RPA_CREDIT_ERR s2BIT(31)
u64 rpa_err_mask;
u64 rpa_err_alarm;
u64 rti_err_reg;
+#define RTI_ECC_SG_ERR s2BIT(7)
+#define RTI_ECC_DB_ERR s2BIT(15)
+#define RTI_SM_ERR_ALARM s2BIT(23)
u64 rti_err_mask;
u64 rti_err_alarm;
@@ -505,49 +568,49 @@ struct XENA_dev_config {
#endif
u64 prc_rxd0_n[RX_MAX_RINGS];
u64 prc_ctrl_n[RX_MAX_RINGS];
-#define PRC_CTRL_RC_ENABLED BIT(7)
-#define PRC_CTRL_RING_MODE (BIT(14)|BIT(15))
+#define PRC_CTRL_RC_ENABLED s2BIT(7)
+#define PRC_CTRL_RING_MODE (s2BIT(14)|s2BIT(15))
#define PRC_CTRL_RING_MODE_1 vBIT(0,14,2)
#define PRC_CTRL_RING_MODE_3 vBIT(1,14,2)
#define PRC_CTRL_RING_MODE_5 vBIT(2,14,2)
#define PRC_CTRL_RING_MODE_x vBIT(3,14,2)
-#define PRC_CTRL_NO_SNOOP (BIT(22)|BIT(23))
-#define PRC_CTRL_NO_SNOOP_DESC BIT(22)
-#define PRC_CTRL_NO_SNOOP_BUFF BIT(23)
-#define PRC_CTRL_BIMODAL_INTERRUPT BIT(37)
-#define PRC_CTRL_GROUP_READS BIT(38)
+#define PRC_CTRL_NO_SNOOP (s2BIT(22)|s2BIT(23))
+#define PRC_CTRL_NO_SNOOP_DESC s2BIT(22)
+#define PRC_CTRL_NO_SNOOP_BUFF s2BIT(23)
+#define PRC_CTRL_BIMODAL_INTERRUPT s2BIT(37)
+#define PRC_CTRL_GROUP_READS s2BIT(38)
#define PRC_CTRL_RXD_BACKOFF_INTERVAL(val) vBIT(val,40,24)
u64 prc_alarm_action;
-#define PRC_ALARM_ACTION_RR_R0_STOP BIT(3)
-#define PRC_ALARM_ACTION_RW_R0_STOP BIT(7)
-#define PRC_ALARM_ACTION_RR_R1_STOP BIT(11)
-#define PRC_ALARM_ACTION_RW_R1_STOP BIT(15)
-#define PRC_ALARM_ACTION_RR_R2_STOP BIT(19)
-#define PRC_ALARM_ACTION_RW_R2_STOP BIT(23)
-#define PRC_ALARM_ACTION_RR_R3_STOP BIT(27)
-#define PRC_ALARM_ACTION_RW_R3_STOP BIT(31)
-#define PRC_ALARM_ACTION_RR_R4_STOP BIT(35)
-#define PRC_ALARM_ACTION_RW_R4_STOP BIT(39)
-#define PRC_ALARM_ACTION_RR_R5_STOP BIT(43)
-#define PRC_ALARM_ACTION_RW_R5_STOP BIT(47)
-#define PRC_ALARM_ACTION_RR_R6_STOP BIT(51)
-#define PRC_ALARM_ACTION_RW_R6_STOP BIT(55)
-#define PRC_ALARM_ACTION_RR_R7_STOP BIT(59)
-#define PRC_ALARM_ACTION_RW_R7_STOP BIT(63)
+#define PRC_ALARM_ACTION_RR_R0_STOP s2BIT(3)
+#define PRC_ALARM_ACTION_RW_R0_STOP s2BIT(7)
+#define PRC_ALARM_ACTION_RR_R1_STOP s2BIT(11)
+#define PRC_ALARM_ACTION_RW_R1_STOP s2BIT(15)
+#define PRC_ALARM_ACTION_RR_R2_STOP s2BIT(19)
+#define PRC_ALARM_ACTION_RW_R2_STOP s2BIT(23)
+#define PRC_ALARM_ACTION_RR_R3_STOP s2BIT(27)
+#define PRC_ALARM_ACTION_RW_R3_STOP s2BIT(31)
+#define PRC_ALARM_ACTION_RR_R4_STOP s2BIT(35)
+#define PRC_ALARM_ACTION_RW_R4_STOP s2BIT(39)
+#define PRC_ALARM_ACTION_RR_R5_STOP s2BIT(43)
+#define PRC_ALARM_ACTION_RW_R5_STOP s2BIT(47)
+#define PRC_ALARM_ACTION_RR_R6_STOP s2BIT(51)
+#define PRC_ALARM_ACTION_RW_R6_STOP s2BIT(55)
+#define PRC_ALARM_ACTION_RR_R7_STOP s2BIT(59)
+#define PRC_ALARM_ACTION_RW_R7_STOP s2BIT(63)
/* Receive traffic interrupts */
u64 rti_command_mem;
-#define RTI_CMD_MEM_WE BIT(7)
-#define RTI_CMD_MEM_STROBE BIT(15)
-#define RTI_CMD_MEM_STROBE_NEW_CMD BIT(15)
-#define RTI_CMD_MEM_STROBE_CMD_BEING_EXECUTED BIT(15)
+#define RTI_CMD_MEM_WE s2BIT(7)
+#define RTI_CMD_MEM_STROBE s2BIT(15)
+#define RTI_CMD_MEM_STROBE_NEW_CMD s2BIT(15)
+#define RTI_CMD_MEM_STROBE_CMD_BEING_EXECUTED s2BIT(15)
#define RTI_CMD_MEM_OFFSET(n) vBIT(n,29,3)
u64 rti_data1_mem;
#define RTI_DATA1_MEM_RX_TIMER_VAL(n) vBIT(n,3,29)
-#define RTI_DATA1_MEM_RX_TIMER_AC_EN BIT(38)
-#define RTI_DATA1_MEM_RX_TIMER_CI_EN BIT(39)
+#define RTI_DATA1_MEM_RX_TIMER_AC_EN s2BIT(38)
+#define RTI_DATA1_MEM_RX_TIMER_CI_EN s2BIT(39)
#define RTI_DATA1_MEM_RX_URNG_A(n) vBIT(n,41,7)
#define RTI_DATA1_MEM_RX_URNG_B(n) vBIT(n,49,7)
#define RTI_DATA1_MEM_RX_URNG_C(n) vBIT(n,57,7)
@@ -559,10 +622,10 @@ struct XENA_dev_config {
#define RTI_DATA2_MEM_RX_UFC_D(n) vBIT(n,48,16)
u64 rx_pa_cfg;
-#define RX_PA_CFG_IGNORE_FRM_ERR BIT(1)
-#define RX_PA_CFG_IGNORE_SNAP_OUI BIT(2)
-#define RX_PA_CFG_IGNORE_LLC_CTRL BIT(3)
-#define RX_PA_CFG_IGNORE_L2_ERR BIT(6)
+#define RX_PA_CFG_IGNORE_FRM_ERR s2BIT(1)
+#define RX_PA_CFG_IGNORE_SNAP_OUI s2BIT(2)
+#define RX_PA_CFG_IGNORE_LLC_CTRL s2BIT(3)
+#define RX_PA_CFG_IGNORE_L2_ERR s2BIT(6)
u64 unused_11_1;
@@ -578,38 +641,64 @@ struct XENA_dev_config {
/* Media Access Controller Register */
u64 mac_int_status;
u64 mac_int_mask;
-#define MAC_INT_STATUS_TMAC_INT BIT(0)
-#define MAC_INT_STATUS_RMAC_INT BIT(1)
+#define MAC_INT_STATUS_TMAC_INT s2BIT(0)
+#define MAC_INT_STATUS_RMAC_INT s2BIT(1)
u64 mac_tmac_err_reg;
-#define TMAC_ERR_REG_TMAC_ECC_DB_ERR BIT(15)
-#define TMAC_ERR_REG_TMAC_TX_BUF_OVRN BIT(23)
-#define TMAC_ERR_REG_TMAC_TX_CRI_ERR BIT(31)
+#define TMAC_ECC_SG_ERR s2BIT(7)
+#define TMAC_ECC_DB_ERR s2BIT(15)
+#define TMAC_TX_BUF_OVRN s2BIT(23)
+#define TMAC_TX_CRI_ERR s2BIT(31)
+#define TMAC_TX_SM_ERR s2BIT(39)
+#define TMAC_DESC_ECC_SG_ERR s2BIT(47)
+#define TMAC_DESC_ECC_DB_ERR s2BIT(55)
+
u64 mac_tmac_err_mask;
u64 mac_tmac_err_alarm;
u64 mac_rmac_err_reg;
-#define RMAC_ERR_REG_RX_BUFF_OVRN BIT(0)
-#define RMAC_ERR_REG_RTS_ECC_DB_ERR BIT(14)
-#define RMAC_ERR_REG_ECC_DB_ERR BIT(15)
-#define RMAC_LINK_STATE_CHANGE_INT BIT(31)
+#define RMAC_RX_BUFF_OVRN s2BIT(0)
+#define RMAC_FRM_RCVD_INT s2BIT(1)
+#define RMAC_UNUSED_INT s2BIT(2)
+#define RMAC_RTS_PNUM_ECC_SG_ERR s2BIT(5)
+#define RMAC_RTS_DS_ECC_SG_ERR s2BIT(6)
+#define RMAC_RD_BUF_ECC_SG_ERR s2BIT(7)
+#define RMAC_RTH_MAP_ECC_SG_ERR s2BIT(8)
+#define RMAC_RTH_SPDM_ECC_SG_ERR s2BIT(9)
+#define RMAC_RTS_VID_ECC_SG_ERR s2BIT(10)
+#define RMAC_DA_SHADOW_ECC_SG_ERR s2BIT(11)
+#define RMAC_RTS_PNUM_ECC_DB_ERR s2BIT(13)
+#define RMAC_RTS_DS_ECC_DB_ERR s2BIT(14)
+#define RMAC_RD_BUF_ECC_DB_ERR s2BIT(15)
+#define RMAC_RTH_MAP_ECC_DB_ERR s2BIT(16)
+#define RMAC_RTH_SPDM_ECC_DB_ERR s2BIT(17)
+#define RMAC_RTS_VID_ECC_DB_ERR s2BIT(18)
+#define RMAC_DA_SHADOW_ECC_DB_ERR s2BIT(19)
+#define RMAC_LINK_STATE_CHANGE_INT s2BIT(31)
+#define RMAC_RX_SM_ERR s2BIT(39)
+#define RMAC_SINGLE_ECC_ERR (s2BIT(5) | s2BIT(6) | s2BIT(7) |\
+ s2BIT(8) | s2BIT(9) | s2BIT(10)|\
+ s2BIT(11))
+#define RMAC_DOUBLE_ECC_ERR (s2BIT(13) | s2BIT(14) | s2BIT(15) |\
+ s2BIT(16) | s2BIT(17) | s2BIT(18)|\
+ s2BIT(19))
u64 mac_rmac_err_mask;
u64 mac_rmac_err_alarm;
u8 unused14[0x100 - 0x40];
u64 mac_cfg;
-#define MAC_CFG_TMAC_ENABLE BIT(0)
-#define MAC_CFG_RMAC_ENABLE BIT(1)
-#define MAC_CFG_LAN_NOT_WAN BIT(2)
-#define MAC_CFG_TMAC_LOOPBACK BIT(3)
-#define MAC_CFG_TMAC_APPEND_PAD BIT(4)
-#define MAC_CFG_RMAC_STRIP_FCS BIT(5)
-#define MAC_CFG_RMAC_STRIP_PAD BIT(6)
-#define MAC_CFG_RMAC_PROM_ENABLE BIT(7)
-#define MAC_RMAC_DISCARD_PFRM BIT(8)
-#define MAC_RMAC_BCAST_ENABLE BIT(9)
-#define MAC_RMAC_ALL_ADDR_ENABLE BIT(10)
+#define MAC_CFG_TMAC_ENABLE s2BIT(0)
+#define MAC_CFG_RMAC_ENABLE s2BIT(1)
+#define MAC_CFG_LAN_NOT_WAN s2BIT(2)
+#define MAC_CFG_TMAC_LOOPBACK s2BIT(3)
+#define MAC_CFG_TMAC_APPEND_PAD s2BIT(4)
+#define MAC_CFG_RMAC_STRIP_FCS s2BIT(5)
+#define MAC_CFG_RMAC_STRIP_PAD s2BIT(6)
+#define MAC_CFG_RMAC_PROM_ENABLE s2BIT(7)
+#define MAC_RMAC_DISCARD_PFRM s2BIT(8)
+#define MAC_RMAC_BCAST_ENABLE s2BIT(9)
+#define MAC_RMAC_ALL_ADDR_ENABLE s2BIT(10)
#define MAC_RMAC_INVLD_IPG_THR(val) vBIT(val,16,8)
u64 tmac_avg_ipg;
@@ -621,14 +710,14 @@ struct XENA_dev_config {
#define RMAC_MAX_PYLD_LEN_JUMBO_DEF vBIT(9600,2,14)
u64 rmac_err_cfg;
-#define RMAC_ERR_FCS BIT(0)
-#define RMAC_ERR_FCS_ACCEPT BIT(1)
-#define RMAC_ERR_TOO_LONG BIT(1)
-#define RMAC_ERR_TOO_LONG_ACCEPT BIT(1)
-#define RMAC_ERR_RUNT BIT(2)
-#define RMAC_ERR_RUNT_ACCEPT BIT(2)
-#define RMAC_ERR_LEN_MISMATCH BIT(3)
-#define RMAC_ERR_LEN_MISMATCH_ACCEPT BIT(3)
+#define RMAC_ERR_FCS s2BIT(0)
+#define RMAC_ERR_FCS_ACCEPT s2BIT(1)
+#define RMAC_ERR_TOO_LONG s2BIT(1)
+#define RMAC_ERR_TOO_LONG_ACCEPT s2BIT(1)
+#define RMAC_ERR_RUNT s2BIT(2)
+#define RMAC_ERR_RUNT_ACCEPT s2BIT(2)
+#define RMAC_ERR_LEN_MISMATCH s2BIT(3)
+#define RMAC_ERR_LEN_MISMATCH_ACCEPT s2BIT(3)
u64 rmac_cfg_key;
#define RMAC_CFG_KEY(val) vBIT(val,0,16)
@@ -639,15 +728,15 @@ struct XENA_dev_config {
#define MAC_MC_ADDR_START_OFFSET 16
#define MAC_MC_ALL_MC_ADDR_OFFSET 63 /* enables all multicast pkts */
u64 rmac_addr_cmd_mem;
-#define RMAC_ADDR_CMD_MEM_WE BIT(7)
+#define RMAC_ADDR_CMD_MEM_WE s2BIT(7)
#define RMAC_ADDR_CMD_MEM_RD 0
-#define RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD BIT(15)
-#define RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING BIT(15)
+#define RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD s2BIT(15)
+#define RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING s2BIT(15)
#define RMAC_ADDR_CMD_MEM_OFFSET(n) vBIT(n,26,6)
u64 rmac_addr_data0_mem;
#define RMAC_ADDR_DATA0_MEM_ADDR(n) vBIT(n,0,48)
-#define RMAC_ADDR_DATA0_MEM_USER BIT(48)
+#define RMAC_ADDR_DATA0_MEM_USER s2BIT(48)
u64 rmac_addr_data1_mem;
#define RMAC_ADDR_DATA1_MEM_MASK(n) vBIT(n,0,48)
@@ -664,10 +753,10 @@ struct XENA_dev_config {
u64 tmac_ipg_cfg;
u64 rmac_pause_cfg;
-#define RMAC_PAUSE_GEN BIT(0)
-#define RMAC_PAUSE_GEN_ENABLE BIT(0)
-#define RMAC_PAUSE_RX BIT(1)
-#define RMAC_PAUSE_RX_ENABLE BIT(1)
+#define RMAC_PAUSE_GEN s2BIT(0)
+#define RMAC_PAUSE_GEN_ENABLE s2BIT(0)
+#define RMAC_PAUSE_RX s2BIT(1)
+#define RMAC_PAUSE_RX_ENABLE s2BIT(1)
#define RMAC_PAUSE_HG_PTIME_DEF vBIT(0xFFFF,16,16)
#define RMAC_PAUSE_HG_PTIME(val) vBIT(val,16,16)
@@ -698,29 +787,29 @@ struct XENA_dev_config {
#define MAX_DIX_MAP 4
u64 rts_dix_map_n[MAX_DIX_MAP];
#define RTS_DIX_MAP_ETYPE(val) vBIT(val,0,16)
-#define RTS_DIX_MAP_SCW(val) BIT(val,21)
+#define RTS_DIX_MAP_SCW(val) s2BIT(val,21)
u64 rts_q_alternates;
u64 rts_default_q;
u64 rts_ctrl;
-#define RTS_CTRL_IGNORE_SNAP_OUI BIT(2)
-#define RTS_CTRL_IGNORE_LLC_CTRL BIT(3)
+#define RTS_CTRL_IGNORE_SNAP_OUI s2BIT(2)
+#define RTS_CTRL_IGNORE_LLC_CTRL s2BIT(3)
u64 rts_pn_cam_ctrl;
-#define RTS_PN_CAM_CTRL_WE BIT(7)
-#define RTS_PN_CAM_CTRL_STROBE_NEW_CMD BIT(15)
-#define RTS_PN_CAM_CTRL_STROBE_BEING_EXECUTED BIT(15)
+#define RTS_PN_CAM_CTRL_WE s2BIT(7)
+#define RTS_PN_CAM_CTRL_STROBE_NEW_CMD s2BIT(15)
+#define RTS_PN_CAM_CTRL_STROBE_BEING_EXECUTED s2BIT(15)
#define RTS_PN_CAM_CTRL_OFFSET(n) vBIT(n,24,8)
u64 rts_pn_cam_data;
-#define RTS_PN_CAM_DATA_TCP_SELECT BIT(7)
+#define RTS_PN_CAM_DATA_TCP_SELECT s2BIT(7)
#define RTS_PN_CAM_DATA_PORT(val) vBIT(val,8,16)
#define RTS_PN_CAM_DATA_SCW(val) vBIT(val,24,8)
u64 rts_ds_mem_ctrl;
-#define RTS_DS_MEM_CTRL_WE BIT(7)
-#define RTS_DS_MEM_CTRL_STROBE_NEW_CMD BIT(15)
-#define RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED BIT(15)
+#define RTS_DS_MEM_CTRL_WE s2BIT(7)
+#define RTS_DS_MEM_CTRL_STROBE_NEW_CMD s2BIT(15)
+#define RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED s2BIT(15)
#define RTS_DS_MEM_CTRL_OFFSET(n) vBIT(n,26,6)
u64 rts_ds_mem_data;
#define RTS_DS_MEM_DATA(n) vBIT(n,0,8)
@@ -734,22 +823,23 @@ struct XENA_dev_config {
/* memory controller registers */
u64 mc_int_status;
-#define MC_INT_STATUS_MC_INT BIT(0)
+#define MC_INT_STATUS_MC_INT s2BIT(0)
u64 mc_int_mask;
-#define MC_INT_MASK_MC_INT BIT(0)
+#define MC_INT_MASK_MC_INT s2BIT(0)
u64 mc_err_reg;
-#define MC_ERR_REG_ECC_DB_ERR_L BIT(14)
-#define MC_ERR_REG_ECC_DB_ERR_U BIT(15)
-#define MC_ERR_REG_MIRI_ECC_DB_ERR_0 BIT(18)
-#define MC_ERR_REG_MIRI_ECC_DB_ERR_1 BIT(20)
-#define MC_ERR_REG_MIRI_CRI_ERR_0 BIT(22)
-#define MC_ERR_REG_MIRI_CRI_ERR_1 BIT(23)
-#define MC_ERR_REG_SM_ERR BIT(31)
-#define MC_ERR_REG_ECC_ALL_SNG (BIT(2) | BIT(3) | BIT(4) | BIT(5) |\
- BIT(17) | BIT(19))
-#define MC_ERR_REG_ECC_ALL_DBL (BIT(10) | BIT(11) | BIT(12) |\
- BIT(13) | BIT(18) | BIT(20))
+#define MC_ERR_REG_ECC_DB_ERR_L s2BIT(14)
+#define MC_ERR_REG_ECC_DB_ERR_U s2BIT(15)
+#define MC_ERR_REG_MIRI_ECC_DB_ERR_0 s2BIT(18)
+#define MC_ERR_REG_MIRI_ECC_DB_ERR_1 s2BIT(20)
+#define MC_ERR_REG_MIRI_CRI_ERR_0 s2BIT(22)
+#define MC_ERR_REG_MIRI_CRI_ERR_1 s2BIT(23)
+#define MC_ERR_REG_SM_ERR s2BIT(31)
+#define MC_ERR_REG_ECC_ALL_SNG (s2BIT(2) | s2BIT(3) | s2BIT(4) | s2BIT(5) |\
+ s2BIT(17) | s2BIT(19))
+#define MC_ERR_REG_ECC_ALL_DBL (s2BIT(10) | s2BIT(11) | s2BIT(12) |\
+ s2BIT(13) | s2BIT(18) | s2BIT(20))
+#define PLL_LOCK_N s2BIT(39)
u64 mc_err_mask;
u64 mc_err_alarm;
@@ -767,8 +857,8 @@ struct XENA_dev_config {
#define RX_QUEUE_CFG_Q7_SZ(n) vBIT(n,56,8)
u64 mc_rldram_mrs;
-#define MC_RLDRAM_QUEUE_SIZE_ENABLE BIT(39)
-#define MC_RLDRAM_MRS_ENABLE BIT(47)
+#define MC_RLDRAM_QUEUE_SIZE_ENABLE s2BIT(39)
+#define MC_RLDRAM_MRS_ENABLE s2BIT(47)
u64 mc_rldram_interleave;
@@ -781,11 +871,11 @@ struct XENA_dev_config {
u64 mc_rldram_ref_per;
u8 unused20[0x220 - 0x208];
u64 mc_rldram_test_ctrl;
-#define MC_RLDRAM_TEST_MODE BIT(47)
-#define MC_RLDRAM_TEST_WRITE BIT(7)
-#define MC_RLDRAM_TEST_GO BIT(15)
-#define MC_RLDRAM_TEST_DONE BIT(23)
-#define MC_RLDRAM_TEST_PASS BIT(31)
+#define MC_RLDRAM_TEST_MODE s2BIT(47)
+#define MC_RLDRAM_TEST_WRITE s2BIT(7)
+#define MC_RLDRAM_TEST_GO s2BIT(15)
+#define MC_RLDRAM_TEST_DONE s2BIT(23)
+#define MC_RLDRAM_TEST_PASS s2BIT(31)
u8 unused21[0x240 - 0x228];
u64 mc_rldram_test_add;
@@ -798,7 +888,7 @@ struct XENA_dev_config {
u8 unused24_1[0x360 - 0x308];
u64 mc_rldram_ctrl;
-#define MC_RLDRAM_ENABLE_ODT BIT(7)
+#define MC_RLDRAM_ENABLE_ODT s2BIT(7)
u8 unused24_2[0x640 - 0x368];
u64 mc_rldram_ref_per_herc;
@@ -816,18 +906,24 @@ struct XENA_dev_config {
/* XGXS control registers */
u64 xgxs_int_status;
-#define XGXS_INT_STATUS_TXGXS BIT(0)
-#define XGXS_INT_STATUS_RXGXS BIT(1)
+#define XGXS_INT_STATUS_TXGXS s2BIT(0)
+#define XGXS_INT_STATUS_RXGXS s2BIT(1)
u64 xgxs_int_mask;
-#define XGXS_INT_MASK_TXGXS BIT(0)
-#define XGXS_INT_MASK_RXGXS BIT(1)
+#define XGXS_INT_MASK_TXGXS s2BIT(0)
+#define XGXS_INT_MASK_RXGXS s2BIT(1)
u64 xgxs_txgxs_err_reg;
-#define TXGXS_ECC_DB_ERR BIT(15)
+#define TXGXS_ECC_SG_ERR s2BIT(7)
+#define TXGXS_ECC_DB_ERR s2BIT(15)
+#define TXGXS_ESTORE_UFLOW s2BIT(31)
+#define TXGXS_TX_SM_ERR s2BIT(39)
+
u64 xgxs_txgxs_err_mask;
u64 xgxs_txgxs_err_alarm;
u64 xgxs_rxgxs_err_reg;
+#define RXGXS_ESTORE_OFLOW s2BIT(7)
+#define RXGXS_RX_SM_ERR s2BIT(39)
u64 xgxs_rxgxs_err_mask;
u64 xgxs_rxgxs_err_alarm;
@@ -846,10 +942,10 @@ struct XENA_dev_config {
#define SPI_CONTROL_BYTECNT(cnt) vBIT(cnt,29,3)
#define SPI_CONTROL_CMD(cmd) vBIT(cmd,32,8)
#define SPI_CONTROL_ADDR(addr) vBIT(addr,40,24)
-#define SPI_CONTROL_SEL1 BIT(4)
-#define SPI_CONTROL_REQ BIT(7)
-#define SPI_CONTROL_NACK BIT(5)
-#define SPI_CONTROL_DONE BIT(6)
+#define SPI_CONTROL_SEL1 s2BIT(4)
+#define SPI_CONTROL_REQ s2BIT(7)
+#define SPI_CONTROL_NACK s2BIT(5)
+#define SPI_CONTROL_DONE s2BIT(6)
u64 spi_data;
#define SPI_DATA_WRITE(data,len) vBIT(data,0,len)
};
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 24feb00600e..63266670624 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -37,8 +37,8 @@
* tx_fifo_len: This too is an array of 8. Each element defines the number of
* Tx descriptors that can be associated with each corresponding FIFO.
* intr_type: This defines the type of interrupt. The values can be 0(INTA),
- * 2(MSI_X). Default value is '0(INTA)'
- * lro: Specifies whether to enable Large Receive Offload (LRO) or not.
+ * 2(MSI_X). Default value is '2(MSI_X)'
+ * lro_enable: Specifies whether to enable Large Receive Offload (LRO) or not.
* Possible values '1' for enable '0' for disable. Default is '0'
* lro_max_pkts: This parameter defines maximum number of packets can be
* aggregated as a single large packet
@@ -84,7 +84,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.25.1"
+#define DRV_VERSION "2.0.26.6"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -130,6 +130,11 @@ static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring)
return 0;
}
+static inline int is_s2io_card_up(const struct s2io_nic * sp)
+{
+ return test_bit(__S2IO_STATE_CARD_UP, &sp->state);
+}
+
/* Ethtool related variables and Macros. */
static char s2io_gstrings[][ETH_GSTRING_LEN] = {
"Register test\t(offline)",
@@ -263,47 +268,71 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = {
{"serious_err_cnt"},
{"soft_reset_cnt"},
{"fifo_full_cnt"},
- {"ring_full_cnt"},
- ("alarm_transceiver_temp_high"),
- ("alarm_transceiver_temp_low"),
- ("alarm_laser_bias_current_high"),
- ("alarm_laser_bias_current_low"),
- ("alarm_laser_output_power_high"),
- ("alarm_laser_output_power_low"),
- ("warn_transceiver_temp_high"),
- ("warn_transceiver_temp_low"),
- ("warn_laser_bias_current_high"),
- ("warn_laser_bias_current_low"),
- ("warn_laser_output_power_high"),
- ("warn_laser_output_power_low"),
- ("lro_aggregated_pkts"),
- ("lro_flush_both_count"),
- ("lro_out_of_sequence_pkts"),
- ("lro_flush_due_to_max_pkts"),
- ("lro_avg_aggr_pkts"),
- ("mem_alloc_fail_cnt"),
- ("pci_map_fail_cnt"),
- ("watchdog_timer_cnt"),
- ("mem_allocated"),
- ("mem_freed"),
- ("link_up_cnt"),
- ("link_down_cnt"),
- ("link_up_time"),
- ("link_down_time"),
- ("tx_tcode_buf_abort_cnt"),
- ("tx_tcode_desc_abort_cnt"),
- ("tx_tcode_parity_err_cnt"),
- ("tx_tcode_link_loss_cnt"),
- ("tx_tcode_list_proc_err_cnt"),
- ("rx_tcode_parity_err_cnt"),
- ("rx_tcode_abort_cnt"),
- ("rx_tcode_parity_abort_cnt"),
- ("rx_tcode_rda_fail_cnt"),
- ("rx_tcode_unkn_prot_cnt"),
- ("rx_tcode_fcs_err_cnt"),
- ("rx_tcode_buf_size_err_cnt"),
- ("rx_tcode_rxd_corrupt_cnt"),
- ("rx_tcode_unkn_err_cnt")
+ {"ring_0_full_cnt"},
+ {"ring_1_full_cnt"},
+ {"ring_2_full_cnt"},
+ {"ring_3_full_cnt"},
+ {"ring_4_full_cnt"},
+ {"ring_5_full_cnt"},
+ {"ring_6_full_cnt"},
+ {"ring_7_full_cnt"},
+ {"alarm_transceiver_temp_high"},
+ {"alarm_transceiver_temp_low"},
+ {"alarm_laser_bias_current_high"},
+ {"alarm_laser_bias_current_low"},
+ {"alarm_laser_output_power_high"},
+ {"alarm_laser_output_power_low"},
+ {"warn_transceiver_temp_high"},
+ {"warn_transceiver_temp_low"},
+ {"warn_laser_bias_current_high"},
+ {"warn_laser_bias_current_low"},
+ {"warn_laser_output_power_high"},
+ {"warn_laser_output_power_low"},
+ {"lro_aggregated_pkts"},
+ {"lro_flush_both_count"},
+ {"lro_out_of_sequence_pkts"},
+ {"lro_flush_due_to_max_pkts"},
+ {"lro_avg_aggr_pkts"},
+ {"mem_alloc_fail_cnt"},
+ {"pci_map_fail_cnt"},
+ {"watchdog_timer_cnt"},
+ {"mem_allocated"},
+ {"mem_freed"},
+ {"link_up_cnt"},
+ {"link_down_cnt"},
+ {"link_up_time"},
+ {"link_down_time"},
+ {"tx_tcode_buf_abort_cnt"},
+ {"tx_tcode_desc_abort_cnt"},
+ {"tx_tcode_parity_err_cnt"},
+ {"tx_tcode_link_loss_cnt"},
+ {"tx_tcode_list_proc_err_cnt"},
+ {"rx_tcode_parity_err_cnt"},
+ {"rx_tcode_abort_cnt"},
+ {"rx_tcode_parity_abort_cnt"},
+ {"rx_tcode_rda_fail_cnt"},
+ {"rx_tcode_unkn_prot_cnt"},
+ {"rx_tcode_fcs_err_cnt"},
+ {"rx_tcode_buf_size_err_cnt"},
+ {"rx_tcode_rxd_corrupt_cnt"},
+ {"rx_tcode_unkn_err_cnt"},
+ {"tda_err_cnt"},
+ {"pfc_err_cnt"},
+ {"pcc_err_cnt"},
+ {"tti_err_cnt"},
+ {"tpa_err_cnt"},
+ {"sm_err_cnt"},
+ {"lso_err_cnt"},
+ {"mac_tmac_err_cnt"},
+ {"mac_rmac_err_cnt"},
+ {"xgxs_txgxs_err_cnt"},
+ {"xgxs_rxgxs_err_cnt"},
+ {"rc_err_cnt"},
+ {"prc_pcix_err_cnt"},
+ {"rpa_err_cnt"},
+ {"rda_err_cnt"},
+ {"rti_err_cnt"},
+ {"mc_err_cnt"}
};
#define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN
@@ -326,6 +355,16 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = {
timer.data = (unsigned long) arg; \
mod_timer(&timer, (jiffies + exp)) \
+/* copy mac addr to def_mac_addr array */
+static void do_s2io_copy_mac_addr(struct s2io_nic *sp, int offset, u64 mac_addr)
+{
+ sp->def_mac_addr[offset].mac_addr[5] = (u8) (mac_addr);
+ sp->def_mac_addr[offset].mac_addr[4] = (u8) (mac_addr >> 8);
+ sp->def_mac_addr[offset].mac_addr[3] = (u8) (mac_addr >> 16);
+ sp->def_mac_addr[offset].mac_addr[2] = (u8) (mac_addr >> 24);
+ sp->def_mac_addr[offset].mac_addr[1] = (u8) (mac_addr >> 32);
+ sp->def_mac_addr[offset].mac_addr[0] = (u8) (mac_addr >> 40);
+}
/* Add the vlan */
static void s2io_vlan_rx_register(struct net_device *dev,
struct vlan_group *grp)
@@ -423,14 +462,15 @@ S2IO_PARM_INT(mc_pause_threshold_q4q7, 187);
S2IO_PARM_INT(shared_splits, 0);
S2IO_PARM_INT(tmac_util_period, 5);
S2IO_PARM_INT(rmac_util_period, 5);
-S2IO_PARM_INT(bimodal, 0);
S2IO_PARM_INT(l3l4hdr_size, 128);
/* Frequency of Rx desc syncs expressed as power of 2 */
S2IO_PARM_INT(rxsync_frequency, 3);
/* Interrupt type. Values can be 0(INTA), 2(MSI_X) */
-S2IO_PARM_INT(intr_type, 0);
+S2IO_PARM_INT(intr_type, 2);
/* Large receive offload feature */
-S2IO_PARM_INT(lro, 0);
+static unsigned int lro_enable;
+module_param_named(lro, lro_enable, uint, 0);
+
/* Max pkts to be aggregated by LRO at one time. If not specified,
* aggregation happens until we hit max IP pkt size(64K)
*/
@@ -532,7 +572,7 @@ static int init_shared_mem(struct s2io_nic *nic)
for (i = 0; i < config->tx_fifo_num; i++) {
int fifo_len = config->tx_cfg[i].fifo_len;
int list_holder_size = fifo_len * sizeof(struct list_info_hold);
- mac_control->fifos[i].list_info = kmalloc(list_holder_size,
+ mac_control->fifos[i].list_info = kzalloc(list_holder_size,
GFP_KERNEL);
if (!mac_control->fifos[i].list_info) {
DBG_PRINT(INFO_DBG,
@@ -540,7 +580,6 @@ static int init_shared_mem(struct s2io_nic *nic)
return -ENOMEM;
}
mem_allocated += list_holder_size;
- memset(mac_control->fifos[i].list_info, 0, list_holder_size);
}
for (i = 0; i < config->tx_fifo_num; i++) {
int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
@@ -671,7 +710,7 @@ static int init_shared_mem(struct s2io_nic *nic)
GFP_KERNEL);
if (!rx_blocks->rxds)
return -ENOMEM;
- mem_allocated +=
+ mem_allocated +=
(sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]);
for (l=0; l<rxd_count[nic->rxd_mode];l++) {
rx_blocks->rxds[l].virt_addr =
@@ -733,7 +772,7 @@ static int init_shared_mem(struct s2io_nic *nic)
(BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
if (!ba->ba_0_org)
return -ENOMEM;
- mem_allocated +=
+ mem_allocated +=
(BUF0_LEN + ALIGN_SIZE);
tmp = (unsigned long)ba->ba_0_org;
tmp += ALIGN_SIZE;
@@ -744,7 +783,7 @@ static int init_shared_mem(struct s2io_nic *nic)
(BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
if (!ba->ba_1_org)
return -ENOMEM;
- mem_allocated
+ mem_allocated
+= (BUF1_LEN + ALIGN_SIZE);
tmp = (unsigned long) ba->ba_1_org;
tmp += ALIGN_SIZE;
@@ -829,7 +868,7 @@ static void free_shared_mem(struct s2io_nic *nic)
mac_control->fifos[i].
list_info[mem_blks].
list_phy_addr);
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= PAGE_SIZE;
}
/* If we got a zero DMA address during allocation,
@@ -844,11 +883,11 @@ static void free_shared_mem(struct s2io_nic *nic)
dev->name);
DBG_PRINT(INIT_DBG, "Virtual address %p\n",
mac_control->zerodma_virt_addr);
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= PAGE_SIZE;
}
kfree(mac_control->fifos[i].list_info);
- nic->mac_control.stats_info->sw_stat.mem_freed +=
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
(nic->config.tx_cfg[i].fifo_len *sizeof(struct list_info_hold));
}
@@ -866,7 +905,7 @@ static void free_shared_mem(struct s2io_nic *nic)
tmp_v_addr, tmp_p_addr);
nic->mac_control.stats_info->sw_stat.mem_freed += size;
kfree(mac_control->rings[i].rx_blocks[j].rxds);
- nic->mac_control.stats_info->sw_stat.mem_freed +=
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
( sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]);
}
}
@@ -892,11 +931,12 @@ static void free_shared_mem(struct s2io_nic *nic)
k++;
}
kfree(mac_control->rings[i].ba[j]);
- nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd) *
- (rxd_count[nic->rxd_mode] + 1));
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
+ (sizeof(struct buffAdd) *
+ (rxd_count[nic->rxd_mode] + 1));
}
kfree(mac_control->rings[i].ba);
- nic->mac_control.stats_info->sw_stat.mem_freed +=
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
(sizeof(struct buffAdd *) * blk_cnt);
}
}
@@ -906,12 +946,12 @@ static void free_shared_mem(struct s2io_nic *nic)
mac_control->stats_mem_sz,
mac_control->stats_mem,
mac_control->stats_mem_phy);
- nic->mac_control.stats_info->sw_stat.mem_freed +=
+ nic->mac_control.stats_info->sw_stat.mem_freed +=
mac_control->stats_mem_sz;
}
if (nic->ufo_in_band_v) {
kfree(nic->ufo_in_band_v);
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= (ufo_size * sizeof(u64));
}
}
@@ -1456,7 +1496,7 @@ static int init_nic(struct s2io_nic *nic)
&bar0->rts_frm_len_n[i]);
}
}
-
+
/* Disable differentiated services steering logic */
for (i = 0; i < 64; i++) {
if (rts_ds_steer(nic, i, 0) == FAILURE) {
@@ -1536,90 +1576,57 @@ static int init_nic(struct s2io_nic *nic)
time++;
}
- if (nic->config.bimodal) {
- int k = 0;
- for (k = 0; k < config->rx_ring_num; k++) {
- val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
- val64 |= TTI_CMD_MEM_OFFSET(0x38+k);
- writeq(val64, &bar0->tti_command_mem);
-
+ /* RTI Initialization */
+ if (nic->device_type == XFRAME_II_DEVICE) {
/*
- * Once the operation completes, the Strobe bit of the command
- * register will be reset. We poll for this particular condition
- * We wait for a maximum of 500ms for the operation to complete,
- * if it's not complete by then we return error.
- */
- time = 0;
- while (TRUE) {
- val64 = readq(&bar0->tti_command_mem);
- if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
- break;
- }
- if (time > 10) {
- DBG_PRINT(ERR_DBG,
- "%s: TTI init Failed\n",
- dev->name);
- return -1;
- }
- time++;
- msleep(50);
- }
- }
- } else {
-
- /* RTI Initialization */
- if (nic->device_type == XFRAME_II_DEVICE) {
- /*
- * Programmed to generate Apprx 500 Intrs per
- * second
- */
- int count = (nic->config.bus_speed * 125)/4;
- val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
- } else {
- val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
- }
- val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
- RTI_DATA1_MEM_RX_URNG_B(0x10) |
- RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
-
- writeq(val64, &bar0->rti_data1_mem);
+ * Programmed to generate Apprx 500 Intrs per
+ * second
+ */
+ int count = (nic->config.bus_speed * 125)/4;
+ val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
+ } else
+ val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
+ val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
+ RTI_DATA1_MEM_RX_URNG_B(0x10) |
+ RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
+
+ writeq(val64, &bar0->rti_data1_mem);
+
+ val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
+ RTI_DATA2_MEM_RX_UFC_B(0x2) ;
+ if (nic->config.intr_type == MSI_X)
+ val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
+ RTI_DATA2_MEM_RX_UFC_D(0x40));
+ else
+ val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \
+ RTI_DATA2_MEM_RX_UFC_D(0x80));
+ writeq(val64, &bar0->rti_data2_mem);
- val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
- RTI_DATA2_MEM_RX_UFC_B(0x2) ;
- if (nic->intr_type == MSI_X)
- val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
- RTI_DATA2_MEM_RX_UFC_D(0x40));
- else
- val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \
- RTI_DATA2_MEM_RX_UFC_D(0x80));
- writeq(val64, &bar0->rti_data2_mem);
+ for (i = 0; i < config->rx_ring_num; i++) {
+ val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD
+ | RTI_CMD_MEM_OFFSET(i);
+ writeq(val64, &bar0->rti_command_mem);
- for (i = 0; i < config->rx_ring_num; i++) {
- val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD
- | RTI_CMD_MEM_OFFSET(i);
- writeq(val64, &bar0->rti_command_mem);
+ /*
+ * Once the operation completes, the Strobe bit of the
+ * command register will be reset. We poll for this
+ * particular condition. We wait for a maximum of 500ms
+ * for the operation to complete, if it's not complete
+ * by then we return error.
+ */
+ time = 0;
+ while (TRUE) {
+ val64 = readq(&bar0->rti_command_mem);
+ if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD))
+ break;
- /*
- * Once the operation completes, the Strobe bit of the
- * command register will be reset. We poll for this
- * particular condition. We wait for a maximum of 500ms
- * for the operation to complete, if it's not complete
- * by then we return error.
- */
- time = 0;
- while (TRUE) {
- val64 = readq(&bar0->rti_command_mem);
- if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) {
- break;
- }
- if (time > 10) {
- DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
- dev->name);
- return -1;
- }
- time++;
- msleep(50);
+ if (time > 10) {
+ DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
+ dev->name);
+ return -1;
}
+ time++;
+ msleep(50);
}
}
@@ -1709,7 +1716,7 @@ static int init_nic(struct s2io_nic *nic)
MISC_LINK_STABILITY_PRD(3);
writeq(val64, &bar0->misc_control);
val64 = readq(&bar0->pic_control2);
- val64 &= ~(BIT(13)|BIT(14)|BIT(15));
+ val64 &= ~(s2BIT(13)|s2BIT(14)|s2BIT(15));
writeq(val64, &bar0->pic_control2);
}
if (strstr(nic->product_name, "CX4")) {
@@ -1724,7 +1731,7 @@ static int init_nic(struct s2io_nic *nic)
static int s2io_link_fault_indication(struct s2io_nic *nic)
{
- if (nic->intr_type != INTA)
+ if (nic->config.intr_type != INTA)
return MAC_RMAC_ERR_TIMER;
if (nic->device_type == XFRAME_II_DEVICE)
return LINK_UP_DOWN_INTERRUPT;
@@ -1733,6 +1740,150 @@ static int s2io_link_fault_indication(struct s2io_nic *nic)
}
/**
+ * do_s2io_write_bits - update alarm bits in alarm register
+ * @value: alarm bits
+ * @flag: interrupt status
+ * @addr: address value
+ * Description: update alarm bits in alarm register
+ * Return Value:
+ * NONE.
+ */
+static void do_s2io_write_bits(u64 value, int flag, void __iomem *addr)
+{
+ u64 temp64;
+
+ temp64 = readq(addr);
+
+ if(flag == ENABLE_INTRS)
+ temp64 &= ~((u64) value);
+ else
+ temp64 |= ((u64) value);
+ writeq(temp64, addr);
+}
+
+static void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag)
+{
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
+ register u64 gen_int_mask = 0;
+
+ if (mask & TX_DMA_INTR) {
+
+ gen_int_mask |= TXDMA_INT_M;
+
+ do_s2io_write_bits(TXDMA_TDA_INT | TXDMA_PFC_INT |
+ TXDMA_PCC_INT | TXDMA_TTI_INT |
+ TXDMA_LSO_INT | TXDMA_TPA_INT |
+ TXDMA_SM_INT, flag, &bar0->txdma_int_mask);
+
+ do_s2io_write_bits(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM |
+ PFC_MISC_0_ERR | PFC_MISC_1_ERR |
+ PFC_PCIX_ERR | PFC_ECC_SG_ERR, flag,
+ &bar0->pfc_err_mask);
+
+ do_s2io_write_bits(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM |
+ TDA_SM1_ERR_ALARM | TDA_Fn_ECC_SG_ERR |
+ TDA_PCIX_ERR, flag, &bar0->tda_err_mask);
+
+ do_s2io_write_bits(PCC_FB_ECC_DB_ERR | PCC_TXB_ECC_DB_ERR |
+ PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM |
+ PCC_N_SERR | PCC_6_COF_OV_ERR |
+ PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR |
+ PCC_7_LSO_OV_ERR | PCC_FB_ECC_SG_ERR |
+ PCC_TXB_ECC_SG_ERR, flag, &bar0->pcc_err_mask);
+
+ do_s2io_write_bits(TTI_SM_ERR_ALARM | TTI_ECC_SG_ERR |
+ TTI_ECC_DB_ERR, flag, &bar0->tti_err_mask);
+
+ do_s2io_write_bits(LSO6_ABORT | LSO7_ABORT |
+ LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM |
+ LSO6_SEND_OFLOW | LSO7_SEND_OFLOW,
+ flag, &bar0->lso_err_mask);
+
+ do_s2io_write_bits(TPA_SM_ERR_ALARM | TPA_TX_FRM_DROP,
+ flag, &bar0->tpa_err_mask);
+
+ do_s2io_write_bits(SM_SM_ERR_ALARM, flag, &bar0->sm_err_mask);
+
+ }
+
+ if (mask & TX_MAC_INTR) {
+ gen_int_mask |= TXMAC_INT_M;
+ do_s2io_write_bits(MAC_INT_STATUS_TMAC_INT, flag,
+ &bar0->mac_int_mask);
+ do_s2io_write_bits(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR |
+ TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR |
+ TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR,
+ flag, &bar0->mac_tmac_err_mask);
+ }
+
+ if (mask & TX_XGXS_INTR) {
+ gen_int_mask |= TXXGXS_INT_M;
+ do_s2io_write_bits(XGXS_INT_STATUS_TXGXS, flag,
+ &bar0->xgxs_int_mask);
+ do_s2io_write_bits(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR |
+ TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR,
+ flag, &bar0->xgxs_txgxs_err_mask);
+ }
+
+ if (mask & RX_DMA_INTR) {
+ gen_int_mask |= RXDMA_INT_M;
+ do_s2io_write_bits(RXDMA_INT_RC_INT_M | RXDMA_INT_RPA_INT_M |
+ RXDMA_INT_RDA_INT_M | RXDMA_INT_RTI_INT_M,
+ flag, &bar0->rxdma_int_mask);
+ do_s2io_write_bits(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR |
+ RC_PRCn_SM_ERR_ALARM | RC_FTC_SM_ERR_ALARM |
+ RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR |
+ RC_RDA_FAIL_WR_Rn, flag, &bar0->rc_err_mask);
+ do_s2io_write_bits(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn |
+ PRC_PCI_AB_F_WR_Rn | PRC_PCI_DP_RD_Rn |
+ PRC_PCI_DP_WR_Rn | PRC_PCI_DP_F_WR_Rn, flag,
+ &bar0->prc_pcix_err_mask);
+ do_s2io_write_bits(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR |
+ RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, flag,
+ &bar0->rpa_err_mask);
+ do_s2io_write_bits(RDA_RXDn_ECC_DB_ERR | RDA_FRM_ECC_DB_N_AERR |
+ RDA_SM1_ERR_ALARM | RDA_SM0_ERR_ALARM |
+ RDA_RXD_ECC_DB_SERR | RDA_RXDn_ECC_SG_ERR |
+ RDA_FRM_ECC_SG_ERR | RDA_MISC_ERR|RDA_PCIX_ERR,
+ flag, &bar0->rda_err_mask);
+ do_s2io_write_bits(RTI_SM_ERR_ALARM |
+ RTI_ECC_SG_ERR | RTI_ECC_DB_ERR,
+ flag, &bar0->rti_err_mask);
+ }
+
+ if (mask & RX_MAC_INTR) {
+ gen_int_mask |= RXMAC_INT_M;
+ do_s2io_write_bits(MAC_INT_STATUS_RMAC_INT, flag,
+ &bar0->mac_int_mask);
+ do_s2io_write_bits(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR |
+ RMAC_UNUSED_INT | RMAC_SINGLE_ECC_ERR |
+ RMAC_DOUBLE_ECC_ERR |
+ RMAC_LINK_STATE_CHANGE_INT,
+ flag, &bar0->mac_rmac_err_mask);
+ }
+
+ if (mask & RX_XGXS_INTR)
+ {
+ gen_int_mask |= RXXGXS_INT_M;
+ do_s2io_write_bits(XGXS_INT_STATUS_RXGXS, flag,
+ &bar0->xgxs_int_mask);
+ do_s2io_write_bits(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, flag,
+ &bar0->xgxs_rxgxs_err_mask);
+ }
+
+ if (mask & MC_INTR) {
+ gen_int_mask |= MC_INT_M;
+ do_s2io_write_bits(MC_INT_MASK_MC_INT, flag, &bar0->mc_int_mask);
+ do_s2io_write_bits(MC_ERR_REG_SM_ERR | MC_ERR_REG_ECC_ALL_SNG |
+ MC_ERR_REG_ECC_ALL_DBL | PLL_LOCK_N, flag,
+ &bar0->mc_err_mask);
+ }
+ nic->general_int_mask = gen_int_mask;
+
+ /* Remove this line when alarm interrupts are enabled */
+ nic->general_int_mask = 0;
+}
+/**
* en_dis_able_nic_intrs - Enable or Disable the interrupts
* @nic: device private variable,
* @mask: A mask indicating which Intr block must be modified and,
@@ -1746,17 +1897,16 @@ static int s2io_link_fault_indication(struct s2io_nic *nic)
static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
{
struct XENA_dev_config __iomem *bar0 = nic->bar0;
- register u64 val64 = 0, temp64 = 0;
+ register u64 temp64 = 0, intr_mask = 0;
+
+ intr_mask = nic->general_int_mask;
/* Top level interrupt classification */
/* PIC Interrupts */
- if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
+ if (mask & TX_PIC_INTR) {
/* Enable PIC Intrs in the general intr mask register */
- val64 = TXPIC_INT_M;
+ intr_mask |= TXPIC_INT_M;
if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
/*
* If Hercules adapter enable GPIO otherwise
* disable all PCIX, Flash, MDIO, IIC and GPIO
@@ -1765,64 +1915,25 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
*/
if (s2io_link_fault_indication(nic) ==
LINK_UP_DOWN_INTERRUPT ) {
- temp64 = readq(&bar0->pic_int_mask);
- temp64 &= ~((u64) PIC_INT_GPIO);
- writeq(temp64, &bar0->pic_int_mask);
- temp64 = readq(&bar0->gpio_int_mask);
- temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP);
- writeq(temp64, &bar0->gpio_int_mask);
- } else {
+ do_s2io_write_bits(PIC_INT_GPIO, flag,
+ &bar0->pic_int_mask);
+ do_s2io_write_bits(GPIO_INT_MASK_LINK_UP, flag,
+ &bar0->gpio_int_mask);
+ } else
writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
- }
- /*
- * No MSI Support is available presently, so TTI and
- * RTI interrupts are also disabled.
- */
} else if (flag == DISABLE_INTRS) {
/*
* Disable PIC Intrs in the general
* intr mask register
*/
writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
- /* MAC Interrupts */
- /* Enabling/Disabling MAC interrupts */
- if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
- val64 = TXMAC_INT_M | RXMAC_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * All MAC block error interrupts are disabled for now
- * TODO
- */
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable MAC Intrs in the general intr mask register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask);
- writeq(DISABLE_ALL_INTRS,
- &bar0->mac_rmac_err_mask);
-
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
}
}
/* Tx traffic interrupts */
if (mask & TX_TRAFFIC_INTR) {
- val64 = TXTRAFFIC_INT_M;
+ intr_mask |= TXTRAFFIC_INT_M;
if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
/*
* Enable all the Tx side interrupts
* writing 0 Enables all 64 TX interrupt levels
@@ -1834,19 +1945,13 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
* register.
*/
writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
}
}
/* Rx traffic interrupts */
if (mask & RX_TRAFFIC_INTR) {
- val64 = RXTRAFFIC_INT_M;
+ intr_mask |= RXTRAFFIC_INT_M;
if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
/* writing 0 Enables all 8 RX interrupt levels */
writeq(0x0, &bar0->rx_traffic_mask);
} else if (flag == DISABLE_INTRS) {
@@ -1855,11 +1960,17 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
* register.
*/
writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
}
}
+
+ temp64 = readq(&bar0->general_int_mask);
+ if (flag == ENABLE_INTRS)
+ temp64 &= ~((u64) intr_mask);
+ else
+ temp64 = DISABLE_ALL_INTRS;
+ writeq(temp64, &bar0->general_int_mask);
+
+ nic->general_int_mask = readq(&bar0->general_int_mask);
}
/**
@@ -1872,7 +1983,7 @@ static int verify_pcc_quiescent(struct s2io_nic *sp, int flag)
int ret = 0, herc;
struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = readq(&bar0->adapter_status);
-
+
herc = (sp->device_type == XFRAME_II_DEVICE);
if (flag == FALSE) {
@@ -2018,8 +2129,6 @@ static int start_nic(struct s2io_nic *nic)
&bar0->prc_rxd0_n[i]);
val64 = readq(&bar0->prc_ctrl_n[i]);
- if (nic->config.bimodal)
- val64 |= PRC_CTRL_BIMODAL_INTERRUPT;
if (nic->rxd_mode == RXD_MODE_1)
val64 |= PRC_CTRL_RC_ENABLED;
else
@@ -2063,14 +2172,6 @@ static int start_nic(struct s2io_nic *nic)
writeq(val64, &bar0->adapter_control);
/*
- * Clearing any possible Link state change interrupts that
- * could have popped up just before Enabling the card.
- */
- val64 = readq(&bar0->mac_rmac_err_reg);
- if (val64)
- writeq(val64, &bar0->mac_rmac_err_reg);
-
- /*
* Verify if the device is ready to be enabled, if so enable
* it.
*/
@@ -2187,7 +2288,7 @@ static void free_tx_buffers(struct s2io_nic *nic)
mac_control->fifos[i].list_info[j].list_virt_addr;
skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
if (skb) {
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= skb->truesize;
dev_kfree_skb(skb);
cnt++;
@@ -2223,9 +2324,9 @@ static void stop_nic(struct s2io_nic *nic)
config = &nic->config;
/* Disable all interrupts */
+ en_dis_err_alarms(nic, ENA_ALL_INTRS, DISABLE_INTRS);
interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
- interruptible |= TX_PIC_INTR | RX_PIC_INTR;
- interruptible |= TX_MAC_INTR | RX_MAC_INTR;
+ interruptible |= TX_PIC_INTR;
en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
/* Clearing Adapter_En bit of ADAPTER_CONTROL Register */
@@ -2326,7 +2427,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
}
if ((rxdp->Control_1 & RXD_OWN_XENA) &&
((nic->rxd_mode == RXD_MODE_3B) &&
- (rxdp->Control_2 & BIT(0)))) {
+ (rxdp->Control_2 & s2BIT(0)))) {
mac_control->rings[ring_no].rx_curr_put_info.
offset = off;
goto end;
@@ -2352,7 +2453,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
mem_alloc_fail_cnt++;
return -ENOMEM ;
}
- nic->mac_control.stats_info->sw_stat.mem_allocated
+ nic->mac_control.stats_info->sw_stat.mem_allocated
+= skb->truesize;
if (nic->rxd_mode == RXD_MODE_1) {
/* 1 buffer mode - normal operation mode */
@@ -2367,7 +2468,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
DMA_ERROR_CODE))
goto pci_map_failed;
- rxdp->Control_2 =
+ rxdp->Control_2 =
SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
} else if (nic->rxd_mode == RXD_MODE_3B) {
@@ -2439,7 +2540,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
rxdp->Control_2 |= SET_BUFFER2_SIZE_3
(dev->mtu + 4);
}
- rxdp->Control_2 |= BIT(0);
+ rxdp->Control_2 |= s2BIT(0);
}
rxdp->Host_Control = (unsigned long) (skb);
if (alloc_tab & ((1 << rxsync_frequency) - 1))
@@ -2568,7 +2669,7 @@ static void free_rx_buffers(struct s2io_nic *sp)
/**
* s2io_poll - Rx interrupt handler for NAPI support
- * @dev : pointer to the device structure.
+ * @napi : pointer to the napi structure.
* @budget : The number of packets that were budgeted to be processed
* during one pass through the 'Poll" function.
* Description:
@@ -2579,22 +2680,23 @@ static void free_rx_buffers(struct s2io_nic *sp)
* 0 on success and 1 if there are No Rx packets to be processed.
*/
-static int s2io_poll(struct net_device *dev, int *budget)
+static int s2io_poll(struct napi_struct *napi, int budget)
{
- struct s2io_nic *nic = dev->priv;
+ struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi);
+ struct net_device *dev = nic->dev;
int pkt_cnt = 0, org_pkts_to_process;
struct mac_info *mac_control;
struct config_param *config;
struct XENA_dev_config __iomem *bar0 = nic->bar0;
int i;
- atomic_inc(&nic->isr_cnt);
+ if (!is_s2io_card_up(nic))
+ return 0;
+
mac_control = &nic->mac_control;
config = &nic->config;
- nic->pkts_to_process = *budget;
- if (nic->pkts_to_process > dev->quota)
- nic->pkts_to_process = dev->quota;
+ nic->pkts_to_process = budget;
org_pkts_to_process = nic->pkts_to_process;
writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
@@ -2608,12 +2710,8 @@ static int s2io_poll(struct net_device *dev, int *budget)
goto no_rx;
}
}
- if (!pkt_cnt)
- pkt_cnt = 1;
- dev->quota -= pkt_cnt;
- *budget -= pkt_cnt;
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
@@ -2625,13 +2723,9 @@ static int s2io_poll(struct net_device *dev, int *budget)
/* Re enable the Rx interrupts. */
writeq(0x0, &bar0->rx_traffic_mask);
readl(&bar0->rx_traffic_mask);
- atomic_dec(&nic->isr_cnt);
- return 0;
+ return pkt_cnt;
no_rx:
- dev->quota -= pkt_cnt;
- *budget -= pkt_cnt;
-
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
@@ -2639,8 +2733,7 @@ no_rx:
break;
}
}
- atomic_dec(&nic->isr_cnt);
- return 1;
+ return pkt_cnt;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2667,7 +2760,6 @@ static void s2io_netpoll(struct net_device *dev)
disable_irq(dev->irq);
- atomic_inc(&nic->isr_cnt);
mac_control = &nic->mac_control;
config = &nic->config;
@@ -2692,7 +2784,6 @@ static void s2io_netpoll(struct net_device *dev)
break;
}
}
- atomic_dec(&nic->isr_cnt);
enable_irq(dev->irq);
return;
}
@@ -2724,12 +2815,6 @@ static void rx_intr_handler(struct ring_info *ring_data)
struct RxD3* rxdp3;
spin_lock(&nic->rx_lock);
- if (atomic_read(&nic->card_state) == CARD_DOWN) {
- DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
- __FUNCTION__, dev->name);
- spin_unlock(&nic->rx_lock);
- return;
- }
get_info = ring_data->rx_curr_get_info;
get_block = get_info.block_index;
@@ -3164,135 +3249,6 @@ static void s2io_updt_xpak_counter(struct net_device *dev)
}
/**
- * alarm_intr_handler - Alarm Interrrupt handler
- * @nic: device private variable
- * Description: If the interrupt was neither because of Rx packet or Tx
- * complete, this function is called. If the interrupt was to indicate
- * a loss of link, the OSM link status handler is invoked for any other
- * alarm interrupt the block that raised the interrupt is displayed
- * and a H/W reset is issued.
- * Return Value:
- * NONE
-*/
-
-static void alarm_intr_handler(struct s2io_nic *nic)
-{
- struct net_device *dev = (struct net_device *) nic->dev;
- struct XENA_dev_config __iomem *bar0 = nic->bar0;
- register u64 val64 = 0, err_reg = 0;
- u64 cnt;
- int i;
- if (atomic_read(&nic->card_state) == CARD_DOWN)
- return;
- if (pci_channel_offline(nic->pdev))
- return;
- nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
- /* Handling the XPAK counters update */
- if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
- /* waiting for an hour */
- nic->mac_control.stats_info->xpak_stat.xpak_timer_count++;
- } else {
- s2io_updt_xpak_counter(dev);
- /* reset the count to zero */
- nic->mac_control.stats_info->xpak_stat.xpak_timer_count = 0;
- }
-
- /* Handling link status change error Intr */
- if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
- err_reg = readq(&bar0->mac_rmac_err_reg);
- writeq(err_reg, &bar0->mac_rmac_err_reg);
- if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
- schedule_work(&nic->set_link_task);
- }
- }
-
- /* Handling Ecc errors */
- val64 = readq(&bar0->mc_err_reg);
- writeq(val64, &bar0->mc_err_reg);
- if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
- if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
- nic->mac_control.stats_info->sw_stat.
- double_ecc_errs++;
- DBG_PRINT(INIT_DBG, "%s: Device indicates ",
- dev->name);
- DBG_PRINT(INIT_DBG, "double ECC error!!\n");
- if (nic->device_type != XFRAME_II_DEVICE) {
- /* Reset XframeI only if critical error */
- if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
- MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
- netif_stop_queue(dev);
- schedule_work(&nic->rst_timer_task);
- nic->mac_control.stats_info->sw_stat.
- soft_reset_cnt++;
- }
- }
- } else {
- nic->mac_control.stats_info->sw_stat.
- single_ecc_errs++;
- }
- }
-
- /* In case of a serious error, the device will be Reset. */
- val64 = readq(&bar0->serr_source);
- if (val64 & SERR_SOURCE_ANY) {
- nic->mac_control.stats_info->sw_stat.serious_err_cnt++;
- DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
- DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
- (unsigned long long)val64);
- netif_stop_queue(dev);
- schedule_work(&nic->rst_timer_task);
- nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
- }
-
- /*
- * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
- * Error occurs, the adapter will be recycled by disabling the
- * adapter enable bit and enabling it again after the device
- * becomes Quiescent.
- */
- val64 = readq(&bar0->pcc_err_reg);
- writeq(val64, &bar0->pcc_err_reg);
- if (val64 & PCC_FB_ECC_DB_ERR) {
- u64 ac = readq(&bar0->adapter_control);
- ac &= ~(ADAPTER_CNTL_EN);
- writeq(ac, &bar0->adapter_control);
- ac = readq(&bar0->adapter_control);
- schedule_work(&nic->set_link_task);
- }
- /* Check for data parity error */
- val64 = readq(&bar0->pic_int_status);
- if (val64 & PIC_INT_GPIO) {
- val64 = readq(&bar0->gpio_int_reg);
- if (val64 & GPIO_INT_REG_DP_ERR_INT) {
- nic->mac_control.stats_info->sw_stat.parity_err_cnt++;
- schedule_work(&nic->rst_timer_task);
- nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
- }
- }
-
- /* Check for ring full counter */
- if (nic->device_type & XFRAME_II_DEVICE) {
- val64 = readq(&bar0->ring_bump_counter1);
- for (i=0; i<4; i++) {
- cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
- cnt >>= 64 - ((i+1)*16);
- nic->mac_control.stats_info->sw_stat.ring_full_cnt
- += cnt;
- }
-
- val64 = readq(&bar0->ring_bump_counter2);
- for (i=0; i<4; i++) {
- cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
- cnt >>= 64 - ((i+1)*16);
- nic->mac_control.stats_info->sw_stat.ring_full_cnt
- += cnt;
- }
- }
-
- /* Other type of interrupts are not being handled now, TODO */
-}
-
-/**
* wait_for_cmd_complete - waits for a command to complete.
* @sp : private member of the device structure, which is a pointer to the
* s2io_nic structure.
@@ -3421,12 +3377,12 @@ static void s2io_reset(struct s2io_nic * sp)
pci_write_config_dword(sp->pdev, 0x68, 0x7C);
/* Clearing PCI_STATUS error reflected here */
- writeq(BIT(62), &bar0->txpic_int_reg);
+ writeq(s2BIT(62), &bar0->txpic_int_reg);
}
/* Reset device statistics maintained by OS */
memset(&sp->stats, 0, sizeof (struct net_device_stats));
-
+
up_cnt = sp->mac_control.stats_info->sw_stat.link_up_cnt;
down_cnt = sp->mac_control.stats_info->sw_stat.link_down_cnt;
up_time = sp->mac_control.stats_info->sw_stat.link_up_time;
@@ -3468,7 +3424,7 @@ static void s2io_reset(struct s2io_nic * sp)
}
/* restore the previously assigned mac address */
- s2io_set_mac_addr(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr);
+ do_s2io_prog_unicast(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr);
sp->device_enabled_once = FALSE;
}
@@ -3565,7 +3521,7 @@ static int s2io_set_swapper(struct s2io_nic * sp)
SWAPPER_CTRL_RXF_W_FE |
SWAPPER_CTRL_XMSI_FE |
SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
- if (sp->intr_type == INTA)
+ if (sp->config.intr_type == INTA)
val64 |= SWAPPER_CTRL_XMSI_SE;
writeq(val64, &bar0->swapper_ctrl);
#else
@@ -3588,7 +3544,7 @@ static int s2io_set_swapper(struct s2io_nic * sp)
SWAPPER_CTRL_RXF_W_FE |
SWAPPER_CTRL_XMSI_FE |
SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
- if (sp->intr_type == INTA)
+ if (sp->config.intr_type == INTA)
val64 |= SWAPPER_CTRL_XMSI_SE;
writeq(val64, &bar0->swapper_ctrl);
#endif
@@ -3619,7 +3575,7 @@ static int wait_for_msix_trans(struct s2io_nic *nic, int i)
do {
val64 = readq(&bar0->xmsi_access);
- if (!(val64 & BIT(15)))
+ if (!(val64 & s2BIT(15)))
break;
mdelay(1);
cnt++;
@@ -3641,7 +3597,7 @@ static void restore_xmsi_data(struct s2io_nic *nic)
for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
writeq(nic->msix_info[i].data, &bar0->xmsi_data);
- val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
+ val64 = (s2BIT(7) | s2BIT(15) | vBIT(i, 26, 6));
writeq(val64, &bar0->xmsi_access);
if (wait_for_msix_trans(nic, i)) {
DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
@@ -3658,7 +3614,7 @@ static void store_xmsi_data(struct s2io_nic *nic)
/* Store and display */
for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
- val64 = (BIT(15) | vBIT(i, 26, 6));
+ val64 = (s2BIT(15) | vBIT(i, 26, 6));
writeq(val64, &bar0->xmsi_access);
if (wait_for_msix_trans(nic, i)) {
DBG_PRINT(ERR_DBG, "failed in %s\n", __FUNCTION__);
@@ -3680,34 +3636,31 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
u16 msi_control; /* Temp variable */
int ret, i, j, msix_indx = 1;
- nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
+ nic->entries = kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct msix_entry),
GFP_KERNEL);
- if (nic->entries == NULL) {
+ if (!nic->entries) {
DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \
__FUNCTION__);
nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
return -ENOMEM;
}
- nic->mac_control.stats_info->sw_stat.mem_allocated
+ nic->mac_control.stats_info->sw_stat.mem_allocated
+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
- memset(nic->entries, 0,MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
nic->s2io_entries =
- kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
+ kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct s2io_msix_entry),
GFP_KERNEL);
- if (nic->s2io_entries == NULL) {
- DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n",
+ if (!nic->s2io_entries) {
+ DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n",
__FUNCTION__);
nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
kfree(nic->entries);
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
return -ENOMEM;
}
- nic->mac_control.stats_info->sw_stat.mem_allocated
+ nic->mac_control.stats_info->sw_stat.mem_allocated
+= (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
- memset(nic->s2io_entries, 0,
- MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
nic->entries[i].entry = i;
@@ -3725,27 +3678,15 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
}
writeq(tx_mat, &bar0->tx_mat0_n[0]);
- if (!nic->config.bimodal) {
- rx_mat = readq(&bar0->rx_mat);
- for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
- rx_mat |= RX_MAT_SET(j, msix_indx);
- nic->s2io_entries[msix_indx].arg
- = &nic->mac_control.rings[j];
- nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
- nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
- }
- writeq(rx_mat, &bar0->rx_mat);
- } else {
- tx_mat = readq(&bar0->tx_mat0_n[7]);
- for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
- tx_mat |= TX_MAT_SET(i, msix_indx);
- nic->s2io_entries[msix_indx].arg
- = &nic->mac_control.rings[j];
- nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
- nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
- }
- writeq(tx_mat, &bar0->tx_mat0_n[7]);
+ rx_mat = readq(&bar0->rx_mat);
+ for (j = 0; j < nic->config.rx_ring_num; j++, msix_indx++) {
+ rx_mat |= RX_MAT_SET(j, msix_indx);
+ nic->s2io_entries[msix_indx].arg
+ = &nic->mac_control.rings[j];
+ nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
+ nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
}
+ writeq(rx_mat, &bar0->rx_mat);
nic->avail_msix_vectors = 0;
ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
@@ -3757,10 +3698,10 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
kfree(nic->entries);
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
kfree(nic->s2io_entries);
- nic->mac_control.stats_info->sw_stat.mem_freed
+ nic->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
nic->entries = NULL;
nic->s2io_entries = NULL;
@@ -3781,6 +3722,93 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
return 0;
}
+/* Handle software interrupt used during MSI(X) test */
+static irqreturn_t __devinit s2io_test_intr(int irq, void *dev_id)
+{
+ struct s2io_nic *sp = dev_id;
+
+ sp->msi_detected = 1;
+ wake_up(&sp->msi_wait);
+
+ return IRQ_HANDLED;
+}
+
+/* Test interrupt path by forcing a a software IRQ */
+static int __devinit s2io_test_msi(struct s2io_nic *sp)
+{
+ struct pci_dev *pdev = sp->pdev;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+ int err;
+ u64 val64, saved64;
+
+ err = request_irq(sp->entries[1].vector, s2io_test_intr, 0,
+ sp->name, sp);
+ if (err) {
+ DBG_PRINT(ERR_DBG, "%s: PCI %s: cannot assign irq %d\n",
+ sp->dev->name, pci_name(pdev), pdev->irq);
+ return err;
+ }
+
+ init_waitqueue_head (&sp->msi_wait);
+ sp->msi_detected = 0;
+
+ saved64 = val64 = readq(&bar0->scheduled_int_ctrl);
+ val64 |= SCHED_INT_CTRL_ONE_SHOT;
+ val64 |= SCHED_INT_CTRL_TIMER_EN;
+ val64 |= SCHED_INT_CTRL_INT2MSI(1);
+ writeq(val64, &bar0->scheduled_int_ctrl);
+
+ wait_event_timeout(sp->msi_wait, sp->msi_detected, HZ/10);
+
+ if (!sp->msi_detected) {
+ /* MSI(X) test failed, go back to INTx mode */
+ DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated"
+ "using MSI(X) during test\n", sp->dev->name,
+ pci_name(pdev));
+
+ err = -EOPNOTSUPP;
+ }
+
+ free_irq(sp->entries[1].vector, sp);
+
+ writeq(saved64, &bar0->scheduled_int_ctrl);
+
+ return err;
+}
+
+static void remove_msix_isr(struct s2io_nic *sp)
+{
+ int i;
+ u16 msi_control;
+
+ for (i = 0; i < MAX_REQUESTED_MSI_X; i++) {
+ if (sp->s2io_entries[i].in_use ==
+ MSIX_REGISTERED_SUCCESS) {
+ int vector = sp->entries[i].vector;
+ void *arg = sp->s2io_entries[i].arg;
+ free_irq(vector, arg);
+ }
+ }
+
+ kfree(sp->entries);
+ kfree(sp->s2io_entries);
+ sp->entries = NULL;
+ sp->s2io_entries = NULL;
+
+ pci_read_config_word(sp->pdev, 0x42, &msi_control);
+ msi_control &= 0xFFFE; /* Disable MSI */
+ pci_write_config_word(sp->pdev, 0x42, msi_control);
+
+ pci_disable_msix(sp->pdev);
+}
+
+static void remove_inta_isr(struct s2io_nic *sp)
+{
+ struct net_device *dev = sp->dev;
+
+ free_irq(sp->pdev->irq, dev);
+}
+
/* ********************************************************* *
* Functions defined below concern the OS part of the driver *
* ********************************************************* */
@@ -3809,6 +3837,31 @@ static int s2io_open(struct net_device *dev)
netif_carrier_off(dev);
sp->last_link_state = 0;
+ napi_enable(&sp->napi);
+
+ if (sp->config.intr_type == MSI_X) {
+ int ret = s2io_enable_msi_x(sp);
+
+ if (!ret) {
+ ret = s2io_test_msi(sp);
+ /* rollback MSI-X, will re-enable during add_isr() */
+ remove_msix_isr(sp);
+ }
+ if (ret) {
+
+ DBG_PRINT(ERR_DBG,
+ "%s: MSI-X requested but failed to enable\n",
+ dev->name);
+ sp->config.intr_type = INTA;
+ }
+ }
+
+ /* NAPI doesn't work well with MSI(X) */
+ if (sp->config.intr_type != INTA) {
+ if(sp->config.napi)
+ sp->config.napi = 0;
+ }
+
/* Initialize H/W and enable interrupts */
err = s2io_card_up(sp);
if (err) {
@@ -3817,7 +3870,7 @@ static int s2io_open(struct net_device *dev)
goto hw_init_failed;
}
- if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
+ if (do_s2io_prog_unicast(dev, dev->dev_addr) == FAILURE) {
DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
s2io_card_down(sp);
err = -ENODEV;
@@ -3828,15 +3881,16 @@ static int s2io_open(struct net_device *dev)
return 0;
hw_init_failed:
- if (sp->intr_type == MSI_X) {
+ napi_disable(&sp->napi);
+ if (sp->config.intr_type == MSI_X) {
if (sp->entries) {
kfree(sp->entries);
- sp->mac_control.stats_info->sw_stat.mem_freed
+ sp->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
}
if (sp->s2io_entries) {
kfree(sp->s2io_entries);
- sp->mac_control.stats_info->sw_stat.mem_freed
+ sp->mac_control.stats_info->sw_stat.mem_freed
+= (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
}
}
@@ -3861,6 +3915,7 @@ static int s2io_close(struct net_device *dev)
struct s2io_nic *sp = dev->priv;
netif_stop_queue(dev);
+ napi_disable(&sp->napi);
/* Reset card, kill tasklet and free Tx and Rx buffers. */
s2io_card_down(sp);
@@ -3907,7 +3962,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
}
spin_lock_irqsave(&sp->tx_lock, flags);
- if (atomic_read(&sp->card_state) == CARD_DOWN) {
+ if (!is_s2io_card_up(sp)) {
DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
dev->name);
spin_unlock_irqrestore(&sp->tx_lock, flags);
@@ -4059,8 +4114,9 @@ static void
s2io_alarm_handle(unsigned long data)
{
struct s2io_nic *sp = (struct s2io_nic *)data;
+ struct net_device *dev = sp->dev;
- alarm_intr_handler(sp);
+ s2io_handle_errors(dev);
mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
}
@@ -4098,12 +4154,12 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
struct ring_info *ring = (struct ring_info *)dev_id;
struct s2io_nic *sp = ring->nic;
- atomic_inc(&sp->isr_cnt);
+ if (!is_s2io_card_up(sp))
+ return IRQ_HANDLED;
rx_intr_handler(ring);
s2io_chk_rx_buffers(sp, ring->ring_no);
- atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
@@ -4112,9 +4168,10 @@ static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
struct fifo_info *fifo = (struct fifo_info *)dev_id;
struct s2io_nic *sp = fifo->nic;
- atomic_inc(&sp->isr_cnt);
+ if (!is_s2io_card_up(sp))
+ return IRQ_HANDLED;
+
tx_intr_handler(fifo);
- atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
static void s2io_txpic_intr_handle(struct s2io_nic *sp)
@@ -4179,6 +4236,292 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp)
}
/**
+ * do_s2io_chk_alarm_bit - Check for alarm and incrment the counter
+ * @value: alarm bits
+ * @addr: address value
+ * @cnt: counter variable
+ * Description: Check for alarm and increment the counter
+ * Return Value:
+ * 1 - if alarm bit set
+ * 0 - if alarm bit is not set
+ */
+static int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr,
+ unsigned long long *cnt)
+{
+ u64 val64;
+ val64 = readq(addr);
+ if ( val64 & value ) {
+ writeq(val64, addr);
+ (*cnt)++;
+ return 1;
+ }
+ return 0;
+
+}
+
+/**
+ * s2io_handle_errors - Xframe error indication handler
+ * @nic: device private variable
+ * Description: Handle alarms such as loss of link, single or
+ * double ECC errors, critical and serious errors.
+ * Return Value:
+ * NONE
+ */
+static void s2io_handle_errors(void * dev_id)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+ u64 temp64 = 0,val64=0;
+ int i = 0;
+
+ struct swStat *sw_stat = &sp->mac_control.stats_info->sw_stat;
+ struct xpakStat *stats = &sp->mac_control.stats_info->xpak_stat;
+
+ if (!is_s2io_card_up(sp))
+ return;
+
+ if (pci_channel_offline(sp->pdev))
+ return;
+
+ memset(&sw_stat->ring_full_cnt, 0,
+ sizeof(sw_stat->ring_full_cnt));
+
+ /* Handling the XPAK counters update */
+ if(stats->xpak_timer_count < 72000) {
+ /* waiting for an hour */
+ stats->xpak_timer_count++;
+ } else {
+ s2io_updt_xpak_counter(dev);
+ /* reset the count to zero */
+ stats->xpak_timer_count = 0;
+ }
+
+ /* Handling link status change error Intr */
+ if (s2io_link_fault_indication(sp) == MAC_RMAC_ERR_TIMER) {
+ val64 = readq(&bar0->mac_rmac_err_reg);
+ writeq(val64, &bar0->mac_rmac_err_reg);
+ if (val64 & RMAC_LINK_STATE_CHANGE_INT)
+ schedule_work(&sp->set_link_task);
+ }
+
+ /* In case of a serious error, the device will be Reset. */
+ if (do_s2io_chk_alarm_bit(SERR_SOURCE_ANY, &bar0->serr_source,
+ &sw_stat->serious_err_cnt))
+ goto reset;
+
+ /* Check for data parity error */
+ if (do_s2io_chk_alarm_bit(GPIO_INT_REG_DP_ERR_INT, &bar0->gpio_int_reg,
+ &sw_stat->parity_err_cnt))
+ goto reset;
+
+ /* Check for ring full counter */
+ if (sp->device_type == XFRAME_II_DEVICE) {
+ val64 = readq(&bar0->ring_bump_counter1);
+ for (i=0; i<4; i++) {
+ temp64 = ( val64 & vBIT(0xFFFF,(i*16),16));
+ temp64 >>= 64 - ((i+1)*16);
+ sw_stat->ring_full_cnt[i] += temp64;
+ }
+
+ val64 = readq(&bar0->ring_bump_counter2);
+ for (i=0; i<4; i++) {
+ temp64 = ( val64 & vBIT(0xFFFF,(i*16),16));
+ temp64 >>= 64 - ((i+1)*16);
+ sw_stat->ring_full_cnt[i+4] += temp64;
+ }
+ }
+
+ val64 = readq(&bar0->txdma_int_status);
+ /*check for pfc_err*/
+ if (val64 & TXDMA_PFC_INT) {
+ if (do_s2io_chk_alarm_bit(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM|
+ PFC_MISC_0_ERR | PFC_MISC_1_ERR|
+ PFC_PCIX_ERR, &bar0->pfc_err_reg,
+ &sw_stat->pfc_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(PFC_ECC_SG_ERR, &bar0->pfc_err_reg,
+ &sw_stat->pfc_err_cnt);
+ }
+
+ /*check for tda_err*/
+ if (val64 & TXDMA_TDA_INT) {
+ if(do_s2io_chk_alarm_bit(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM |
+ TDA_SM1_ERR_ALARM, &bar0->tda_err_reg,
+ &sw_stat->tda_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(TDA_Fn_ECC_SG_ERR | TDA_PCIX_ERR,
+ &bar0->tda_err_reg, &sw_stat->tda_err_cnt);
+ }
+ /*check for pcc_err*/
+ if (val64 & TXDMA_PCC_INT) {
+ if (do_s2io_chk_alarm_bit(PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM
+ | PCC_N_SERR | PCC_6_COF_OV_ERR
+ | PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR
+ | PCC_7_LSO_OV_ERR | PCC_FB_ECC_DB_ERR
+ | PCC_TXB_ECC_DB_ERR, &bar0->pcc_err_reg,
+ &sw_stat->pcc_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(PCC_FB_ECC_SG_ERR | PCC_TXB_ECC_SG_ERR,
+ &bar0->pcc_err_reg, &sw_stat->pcc_err_cnt);
+ }
+
+ /*check for tti_err*/
+ if (val64 & TXDMA_TTI_INT) {
+ if (do_s2io_chk_alarm_bit(TTI_SM_ERR_ALARM, &bar0->tti_err_reg,
+ &sw_stat->tti_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(TTI_ECC_SG_ERR | TTI_ECC_DB_ERR,
+ &bar0->tti_err_reg, &sw_stat->tti_err_cnt);
+ }
+
+ /*check for lso_err*/
+ if (val64 & TXDMA_LSO_INT) {
+ if (do_s2io_chk_alarm_bit(LSO6_ABORT | LSO7_ABORT
+ | LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM,
+ &bar0->lso_err_reg, &sw_stat->lso_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(LSO6_SEND_OFLOW | LSO7_SEND_OFLOW,
+ &bar0->lso_err_reg, &sw_stat->lso_err_cnt);
+ }
+
+ /*check for tpa_err*/
+ if (val64 & TXDMA_TPA_INT) {
+ if (do_s2io_chk_alarm_bit(TPA_SM_ERR_ALARM, &bar0->tpa_err_reg,
+ &sw_stat->tpa_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(TPA_TX_FRM_DROP, &bar0->tpa_err_reg,
+ &sw_stat->tpa_err_cnt);
+ }
+
+ /*check for sm_err*/
+ if (val64 & TXDMA_SM_INT) {
+ if (do_s2io_chk_alarm_bit(SM_SM_ERR_ALARM, &bar0->sm_err_reg,
+ &sw_stat->sm_err_cnt))
+ goto reset;
+ }
+
+ val64 = readq(&bar0->mac_int_status);
+ if (val64 & MAC_INT_STATUS_TMAC_INT) {
+ if (do_s2io_chk_alarm_bit(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR,
+ &bar0->mac_tmac_err_reg,
+ &sw_stat->mac_tmac_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR
+ | TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR,
+ &bar0->mac_tmac_err_reg,
+ &sw_stat->mac_tmac_err_cnt);
+ }
+
+ val64 = readq(&bar0->xgxs_int_status);
+ if (val64 & XGXS_INT_STATUS_TXGXS) {
+ if (do_s2io_chk_alarm_bit(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR,
+ &bar0->xgxs_txgxs_err_reg,
+ &sw_stat->xgxs_txgxs_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR,
+ &bar0->xgxs_txgxs_err_reg,
+ &sw_stat->xgxs_txgxs_err_cnt);
+ }
+
+ val64 = readq(&bar0->rxdma_int_status);
+ if (val64 & RXDMA_INT_RC_INT_M) {
+ if (do_s2io_chk_alarm_bit(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR
+ | RC_PRCn_SM_ERR_ALARM |RC_FTC_SM_ERR_ALARM,
+ &bar0->rc_err_reg, &sw_stat->rc_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR
+ | RC_RDA_FAIL_WR_Rn, &bar0->rc_err_reg,
+ &sw_stat->rc_err_cnt);
+ if (do_s2io_chk_alarm_bit(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn
+ | PRC_PCI_AB_F_WR_Rn, &bar0->prc_pcix_err_reg,
+ &sw_stat->prc_pcix_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(PRC_PCI_DP_RD_Rn | PRC_PCI_DP_WR_Rn
+ | PRC_PCI_DP_F_WR_Rn, &bar0->prc_pcix_err_reg,
+ &sw_stat->prc_pcix_err_cnt);
+ }
+
+ if (val64 & RXDMA_INT_RPA_INT_M) {
+ if (do_s2io_chk_alarm_bit(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR,
+ &bar0->rpa_err_reg, &sw_stat->rpa_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(RPA_ECC_SG_ERR | RPA_ECC_DB_ERR,
+ &bar0->rpa_err_reg, &sw_stat->rpa_err_cnt);
+ }
+
+ if (val64 & RXDMA_INT_RDA_INT_M) {
+ if (do_s2io_chk_alarm_bit(RDA_RXDn_ECC_DB_ERR
+ | RDA_FRM_ECC_DB_N_AERR | RDA_SM1_ERR_ALARM
+ | RDA_SM0_ERR_ALARM | RDA_RXD_ECC_DB_SERR,
+ &bar0->rda_err_reg, &sw_stat->rda_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(RDA_RXDn_ECC_SG_ERR | RDA_FRM_ECC_SG_ERR
+ | RDA_MISC_ERR | RDA_PCIX_ERR,
+ &bar0->rda_err_reg, &sw_stat->rda_err_cnt);
+ }
+
+ if (val64 & RXDMA_INT_RTI_INT_M) {
+ if (do_s2io_chk_alarm_bit(RTI_SM_ERR_ALARM, &bar0->rti_err_reg,
+ &sw_stat->rti_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(RTI_ECC_SG_ERR | RTI_ECC_DB_ERR,
+ &bar0->rti_err_reg, &sw_stat->rti_err_cnt);
+ }
+
+ val64 = readq(&bar0->mac_int_status);
+ if (val64 & MAC_INT_STATUS_RMAC_INT) {
+ if (do_s2io_chk_alarm_bit(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR,
+ &bar0->mac_rmac_err_reg,
+ &sw_stat->mac_rmac_err_cnt))
+ goto reset;
+ do_s2io_chk_alarm_bit(RMAC_UNUSED_INT|RMAC_SINGLE_ECC_ERR|
+ RMAC_DOUBLE_ECC_ERR, &bar0->mac_rmac_err_reg,
+ &sw_stat->mac_rmac_err_cnt);
+ }
+
+ val64 = readq(&bar0->xgxs_int_status);
+ if (val64 & XGXS_INT_STATUS_RXGXS) {
+ if (do_s2io_chk_alarm_bit(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR,
+ &bar0->xgxs_rxgxs_err_reg,
+ &sw_stat->xgxs_rxgxs_err_cnt))
+ goto reset;
+ }
+
+ val64 = readq(&bar0->mc_int_status);
+ if(val64 & MC_INT_STATUS_MC_INT) {
+ if (do_s2io_chk_alarm_bit(MC_ERR_REG_SM_ERR, &bar0->mc_err_reg,
+ &sw_stat->mc_err_cnt))
+ goto reset;
+
+ /* Handling Ecc errors */
+ if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
+ writeq(val64, &bar0->mc_err_reg);
+ if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
+ sw_stat->double_ecc_errs++;
+ if (sp->device_type != XFRAME_II_DEVICE) {
+ /*
+ * Reset XframeI only if critical error
+ */
+ if (val64 &
+ (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
+ MC_ERR_REG_MIRI_ECC_DB_ERR_1))
+ goto reset;
+ }
+ } else
+ sw_stat->single_ecc_errs++;
+ }
+ }
+ return;
+
+reset:
+ netif_stop_queue(dev);
+ schedule_work(&sp->rst_timer_task);
+ sw_stat->soft_reset_cnt++;
+ return;
+}
+
+/**
* s2io_isr - ISR handler of the device .
* @irq: the irq of the device.
* @dev_id: a void pointer to the dev structure of the NIC.
@@ -4205,7 +4548,9 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
if (pci_channel_offline(sp->pdev))
return IRQ_NONE;
- atomic_inc(&sp->isr_cnt);
+ if (!is_s2io_card_up(sp))
+ return IRQ_NONE;
+
mac_control = &sp->mac_control;
config = &sp->config;
@@ -4215,73 +4560,75 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
* 1. Rx of packet.
* 2. Tx complete.
* 3. Link down.
- * 4. Error in any functional blocks of the NIC.
*/
reason = readq(&bar0->general_int_status);
- if (!reason) {
- /* The interrupt was not raised by us. */
- atomic_dec(&sp->isr_cnt);
- return IRQ_NONE;
- }
- else if (unlikely(reason == S2IO_MINUS_ONE) ) {
- /* Disable device and get out */
- atomic_dec(&sp->isr_cnt);
- return IRQ_NONE;
+ if (unlikely(reason == S2IO_MINUS_ONE) ) {
+ /* Nothing much can be done. Get out */
+ return IRQ_HANDLED;
}
- if (napi) {
- if (reason & GEN_INTR_RXTRAFFIC) {
- if ( likely ( netif_rx_schedule_prep(dev)) ) {
- __netif_rx_schedule(dev);
- writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
+ if (reason & (GEN_INTR_RXTRAFFIC |
+ GEN_INTR_TXTRAFFIC | GEN_INTR_TXPIC))
+ {
+ writeq(S2IO_MINUS_ONE, &bar0->general_int_mask);
+
+ if (config->napi) {
+ if (reason & GEN_INTR_RXTRAFFIC) {
+ if (likely(netif_rx_schedule_prep(dev,
+ &sp->napi))) {
+ __netif_rx_schedule(dev, &sp->napi);
+ writeq(S2IO_MINUS_ONE,
+ &bar0->rx_traffic_mask);
+ } else
+ writeq(S2IO_MINUS_ONE,
+ &bar0->rx_traffic_int);
}
- else
+ } else {
+ /*
+ * rx_traffic_int reg is an R1 register, writing all 1's
+ * will ensure that the actual interrupt causing bit
+ * get's cleared and hence a read can be avoided.
+ */
+ if (reason & GEN_INTR_RXTRAFFIC)
writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+
+ for (i = 0; i < config->rx_ring_num; i++)
+ rx_intr_handler(&mac_control->rings[i]);
}
- } else {
+
/*
- * Rx handler is called by default, without checking for the
- * cause of interrupt.
- * rx_traffic_int reg is an R1 register, writing all 1's
+ * tx_traffic_int reg is an R1 register, writing all 1's
* will ensure that the actual interrupt causing bit get's
* cleared and hence a read can be avoided.
*/
- if (reason & GEN_INTR_RXTRAFFIC)
- writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+ if (reason & GEN_INTR_TXTRAFFIC)
+ writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
- for (i = 0; i < config->rx_ring_num; i++) {
- rx_intr_handler(&mac_control->rings[i]);
- }
- }
+ for (i = 0; i < config->tx_fifo_num; i++)
+ tx_intr_handler(&mac_control->fifos[i]);
- /*
- * tx_traffic_int reg is an R1 register, writing all 1's
- * will ensure that the actual interrupt causing bit get's
- * cleared and hence a read can be avoided.
- */
- if (reason & GEN_INTR_TXTRAFFIC)
- writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
+ if (reason & GEN_INTR_TXPIC)
+ s2io_txpic_intr_handle(sp);
- for (i = 0; i < config->tx_fifo_num; i++)
- tx_intr_handler(&mac_control->fifos[i]);
+ /*
+ * Reallocate the buffers from the interrupt handler itself.
+ */
+ if (!config->napi) {
+ for (i = 0; i < config->rx_ring_num; i++)
+ s2io_chk_rx_buffers(sp, i);
+ }
+ writeq(sp->general_int_mask, &bar0->general_int_mask);
+ readl(&bar0->general_int_status);
- if (reason & GEN_INTR_TXPIC)
- s2io_txpic_intr_handle(sp);
- /*
- * If the Rx buffer count is below the panic threshold then
- * reallocate the buffers from the interrupt handler itself,
- * else schedule a tasklet to reallocate the buffers.
- */
- if (!napi) {
- for (i = 0; i < config->rx_ring_num; i++)
- s2io_chk_rx_buffers(sp, i);
- }
+ return IRQ_HANDLED;
- writeq(0, &bar0->general_int_mask);
- readl(&bar0->general_int_status);
+ }
+ else if (!reason) {
+ /* The interrupt was not raised by us */
+ return IRQ_NONE;
+ }
- atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
}
@@ -4294,7 +4641,7 @@ static void s2io_updt_stats(struct s2io_nic *sp)
u64 val64;
int cnt = 0;
- if (atomic_read(&sp->card_state) == CARD_UP) {
+ if (is_s2io_card_up(sp)) {
/* Apprx 30us on a 133 MHz bus */
val64 = SET_UPDT_CLICKS(10) |
STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
@@ -4302,13 +4649,13 @@ static void s2io_updt_stats(struct s2io_nic *sp)
do {
udelay(100);
val64 = readq(&bar0->stat_cfg);
- if (!(val64 & BIT(0)))
+ if (!(val64 & s2BIT(0)))
break;
cnt++;
if (cnt == 5)
break; /* Updt failed */
} while(1);
- }
+ }
}
/**
@@ -4525,8 +4872,48 @@ static void s2io_set_multicast(struct net_device *dev)
}
}
+/* add unicast MAC address to CAM */
+static int do_s2io_add_unicast(struct s2io_nic *sp, u64 addr, int off)
+{
+ u64 val64;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+
+ writeq(RMAC_ADDR_DATA0_MEM_ADDR(addr),
+ &bar0->rmac_addr_data0_mem);
+
+ val64 =
+ RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
+ RMAC_ADDR_CMD_MEM_OFFSET(off);
+ writeq(val64, &bar0->rmac_addr_cmd_mem);
+
+ /* Wait till command completes */
+ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+ RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
+ S2IO_BIT_RESET)) {
+ DBG_PRINT(INFO_DBG, "add_mac_addr failed\n");
+ return FAILURE;
+ }
+ return SUCCESS;
+}
+
+/**
+ * s2io_set_mac_addr driver entry point
+ */
+static int s2io_set_mac_addr(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ /* store the MAC address in CAM */
+ return (do_s2io_prog_unicast(dev, dev->dev_addr));
+}
+
/**
- * s2io_set_mac_addr - Programs the Xframe mac address
+ * do_s2io_prog_unicast - Programs the Xframe mac address
* @dev : pointer to the device structure.
* @addr: a uchar pointer to the new mac address which is to be set.
* Description : This procedure will program the Xframe to receive
@@ -4534,56 +4921,31 @@ static void s2io_set_multicast(struct net_device *dev)
* Return value: SUCCESS on success and an appropriate (-)ve integer
* as defined in errno.h file on failure.
*/
-
-static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
+static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr)
{
struct s2io_nic *sp = dev->priv;
- struct XENA_dev_config __iomem *bar0 = sp->bar0;
- register u64 val64, mac_addr = 0;
+ register u64 mac_addr = 0, perm_addr = 0;
int i;
- u64 old_mac_addr = 0;
/*
- * Set the new MAC address as the new unicast filter and reflect this
- * change on the device address registered with the OS. It will be
- * at offset 0.
- */
+ * Set the new MAC address as the new unicast filter and reflect this
+ * change on the device address registered with the OS. It will be
+ * at offset 0.
+ */
for (i = 0; i < ETH_ALEN; i++) {
mac_addr <<= 8;
mac_addr |= addr[i];
- old_mac_addr <<= 8;
- old_mac_addr |= sp->def_mac_addr[0].mac_addr[i];
+ perm_addr <<= 8;
+ perm_addr |= sp->def_mac_addr[0].mac_addr[i];
}
- if(0 == mac_addr)
+ /* check if the dev_addr is different than perm_addr */
+ if (mac_addr == perm_addr)
return SUCCESS;
/* Update the internal structure with this new mac address */
- if(mac_addr != old_mac_addr) {
- memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
- sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_addr);
- sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_addr >> 8);
- sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_addr >> 16);
- sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_addr >> 24);
- sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_addr >> 32);
- sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_addr >> 40);
- }
-
- writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
- &bar0->rmac_addr_data0_mem);
-
- val64 =
- RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
- RMAC_ADDR_CMD_MEM_OFFSET(0);
- writeq(val64, &bar0->rmac_addr_cmd_mem);
- /* Wait till command completes */
- if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
- RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) {
- DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
- return FAILURE;
- }
-
- return SUCCESS;
+ do_s2io_copy_mac_addr(sp, 0, mac_addr);
+ return (do_s2io_add_unicast(sp, mac_addr, 0));
}
/**
@@ -4631,7 +4993,9 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
info->port = PORT_FIBRE;
- /* info->transceiver?? TODO */
+
+ /* info->transceiver */
+ info->transceiver = XCVR_EXTERNAL;
if (netif_carrier_ok(sp->dev)) {
info->speed = 10000;
@@ -4668,12 +5032,6 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev,
strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
info->regdump_len = XENA_REG_SPACE;
info->eedump_len = XENA_EEPROM_SPACE;
- info->testinfo_len = S2IO_TEST_LEN;
-
- if (sp->device_type == XFRAME_I_DEVICE)
- info->n_stats = XFRAME_I_STAT_LEN;
- else
- info->n_stats = XFRAME_II_STAT_LEN;
}
/**
@@ -4803,13 +5161,13 @@ static void s2io_ethtool_gringparam(struct net_device *dev,
ering->rx_max_pending = MAX_RX_DESC_2;
ering->tx_max_pending = MAX_TX_DESC;
- for (i = 0 ; i < sp->config.tx_fifo_num ; i++)
+ for (i = 0 ; i < sp->config.tx_fifo_num ; i++)
tx_desc_count += sp->config.tx_cfg[i].fifo_len;
-
+
DBG_PRINT(INFO_DBG,"\nmax txds : %d\n",sp->config.max_txds);
ering->tx_pending = tx_desc_count;
rx_desc_count = 0;
- for (i = 0 ; i < sp->config.rx_ring_num ; i++)
+ for (i = 0 ; i < sp->config.rx_ring_num ; i++)
rx_desc_count += sp->config.rx_cfg[i].num_rxd;
ering->rx_pending = rx_desc_count;
@@ -5567,7 +5925,7 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *estats,
u64 * tmp_stats)
{
- int i = 0;
+ int i = 0, k;
struct s2io_nic *sp = dev->priv;
struct stat_block *stat_info = sp->mac_control.stats_info;
@@ -5762,7 +6120,8 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt;
tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt;
tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt;
- tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt;
+ for (k = 0; k < MAX_RX_RINGS; k++)
+ tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt[k];
tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high;
tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low;
tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high;
@@ -5819,6 +6178,23 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
tmp_stats[i++] = stat_info->sw_stat.rx_buf_size_err_cnt;
tmp_stats[i++] = stat_info->sw_stat.rx_rxd_corrupt_cnt;
tmp_stats[i++] = stat_info->sw_stat.rx_unkn_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.tda_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.pfc_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.pcc_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.tti_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.tpa_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.sm_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.lso_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.mac_tmac_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.mac_rmac_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.xgxs_txgxs_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.xgxs_rxgxs_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rc_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.prc_pcix_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rpa_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rda_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rti_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.mc_err_cnt;
}
static int s2io_ethtool_get_regs_len(struct net_device *dev)
@@ -5851,9 +6227,25 @@ static int s2io_get_eeprom_len(struct net_device *dev)
return (XENA_EEPROM_SPACE);
}
-static int s2io_ethtool_self_test_count(struct net_device *dev)
+static int s2io_get_sset_count(struct net_device *dev, int sset)
{
- return (S2IO_TEST_LEN);
+ struct s2io_nic *sp = dev->priv;
+
+ switch (sset) {
+ case ETH_SS_TEST:
+ return S2IO_TEST_LEN;
+ case ETH_SS_STATS:
+ switch(sp->device_type) {
+ case XFRAME_I_DEVICE:
+ return XFRAME_I_STAT_LEN;
+ case XFRAME_II_DEVICE:
+ return XFRAME_II_STAT_LEN;
+ default:
+ return 0;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void s2io_ethtool_get_strings(struct net_device *dev,
@@ -5880,22 +6272,6 @@ static void s2io_ethtool_get_strings(struct net_device *dev,
sizeof(ethtool_driver_stats_keys));
}
}
-static int s2io_ethtool_get_stats_count(struct net_device *dev)
-{
- struct s2io_nic *sp = dev->priv;
- int stat_count = 0;
- switch(sp->device_type) {
- case XFRAME_I_DEVICE:
- stat_count = XFRAME_I_STAT_LEN;
- break;
-
- case XFRAME_II_DEVICE:
- stat_count = XFRAME_II_STAT_LEN;
- break;
- }
-
- return stat_count;
-}
static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
{
@@ -5936,20 +6312,16 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.set_pauseparam = s2io_ethtool_setpause_data,
.get_rx_csum = s2io_ethtool_get_rx_csum,
.set_rx_csum = s2io_ethtool_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = s2io_ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_tso = s2io_ethtool_op_get_tso,
.set_tso = s2io_ethtool_op_set_tso,
- .get_ufo = ethtool_op_get_ufo,
.set_ufo = ethtool_op_set_ufo,
- .self_test_count = s2io_ethtool_self_test_count,
.self_test = s2io_ethtool_test,
.get_strings = s2io_ethtool_get_strings,
.phys_id = s2io_ethtool_idnic,
- .get_stats_count = s2io_ethtool_get_stats_count,
- .get_ethtool_stats = s2io_get_ethtool_stats
+ .get_ethtool_stats = s2io_get_ethtool_stats,
+ .get_sset_count = s2io_get_sset_count,
};
/**
@@ -6072,7 +6444,7 @@ static void s2io_set_link(struct work_struct *work)
if (!netif_running(dev))
goto out_unlock;
- if (test_and_set_bit(0, &(nic->link_state))) {
+ if (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(nic->state))) {
/* The card is being reset, no point doing anything */
goto out_unlock;
}
@@ -6110,13 +6482,10 @@ static void s2io_set_link(struct work_struct *work)
netif_stop_queue(dev);
}
}
- val64 = readq(&bar0->adapter_status);
- if (!LINK_IS_UP(val64)) {
- DBG_PRINT(ERR_DBG, "%s:", dev->name);
- DBG_PRINT(ERR_DBG, " Link down after enabling ");
- DBG_PRINT(ERR_DBG, "device \n");
- } else
- s2io_link(nic, LINK_UP);
+ val64 = readq(&bar0->adapter_control);
+ val64 |= ADAPTER_LED_ON;
+ writeq(val64, &bar0->adapter_control);
+ s2io_link(nic, LINK_UP);
} else {
if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
subid)) {
@@ -6125,9 +6494,13 @@ static void s2io_set_link(struct work_struct *work)
writeq(val64, &bar0->gpio_control);
val64 = readq(&bar0->gpio_control);
}
+ /* turn off LED */
+ val64 = readq(&bar0->adapter_control);
+ val64 = val64 &(~ADAPTER_LED_ON);
+ writeq(val64, &bar0->adapter_control);
s2io_link(nic, LINK_DOWN);
}
- clear_bit(0, &(nic->link_state));
+ clear_bit(__S2IO_STATE_LINK_TASK, &(nic->state));
out_unlock:
rtnl_unlock();
@@ -6162,7 +6535,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
mem_alloc_fail_cnt++;
return -ENOMEM ;
}
- sp->mac_control.stats_info->sw_stat.mem_allocated
+ sp->mac_control.stats_info->sw_stat.mem_allocated
+= (*skb)->truesize;
/* storing the mapped addr in a temp variable
* such it will be used for next rxd whose
@@ -6195,7 +6568,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
mem_alloc_fail_cnt++;
return -ENOMEM;
}
- sp->mac_control.stats_info->sw_stat.mem_allocated
+ sp->mac_control.stats_info->sw_stat.mem_allocated
+= (*skb)->truesize;
rxdp3->Buffer2_ptr = *temp2 =
pci_map_single(sp->pdev, (*skb)->data,
@@ -6308,18 +6681,18 @@ static int s2io_add_isr(struct s2io_nic * sp)
struct net_device *dev = sp->dev;
int err = 0;
- if (sp->intr_type == MSI_X)
+ if (sp->config.intr_type == MSI_X)
ret = s2io_enable_msi_x(sp);
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
- sp->intr_type = INTA;
+ sp->config.intr_type = INTA;
}
/* Store the values of the MSIX table in the struct s2io_nic structure */
store_xmsi_data(sp);
/* After proper initialization of H/W, register ISR */
- if (sp->intr_type == MSI_X) {
+ if (sp->config.intr_type == MSI_X) {
int i, msix_tx_cnt=0,msix_rx_cnt=0;
for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
@@ -6361,17 +6734,24 @@ static int s2io_add_isr(struct s2io_nic * sp)
}
}
if (err) {
+ remove_msix_isr(sp);
DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
"failed\n", dev->name, i);
- DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
- return -1;
+ DBG_PRINT(ERR_DBG, "%s: defaulting to INTA\n",
+ dev->name);
+ sp->config.intr_type = INTA;
+ break;
}
sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
}
- printk("MSI-X-TX %d entries enabled\n",msix_tx_cnt);
- printk("MSI-X-RX %d entries enabled\n",msix_rx_cnt);
+ if (!err) {
+ printk(KERN_INFO "MSI-X-TX %d entries enabled\n",
+ msix_tx_cnt);
+ printk(KERN_INFO "MSI-X-RX %d entries enabled\n",
+ msix_rx_cnt);
+ }
}
- if (sp->intr_type == INTA) {
+ if (sp->config.intr_type == INTA) {
err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
sp->name, dev);
if (err) {
@@ -6384,36 +6764,10 @@ static int s2io_add_isr(struct s2io_nic * sp)
}
static void s2io_rem_isr(struct s2io_nic * sp)
{
- int cnt = 0;
- struct net_device *dev = sp->dev;
-
- if (sp->intr_type == MSI_X) {
- int i;
- u16 msi_control;
-
- for (i=1; (sp->s2io_entries[i].in_use ==
- MSIX_REGISTERED_SUCCESS); i++) {
- int vector = sp->entries[i].vector;
- void *arg = sp->s2io_entries[i].arg;
-
- free_irq(vector, arg);
- }
- pci_read_config_word(sp->pdev, 0x42, &msi_control);
- msi_control &= 0xFFFE; /* Disable MSI */
- pci_write_config_word(sp->pdev, 0x42, msi_control);
-
- pci_disable_msix(sp->pdev);
- } else {
- free_irq(sp->pdev->irq, dev);
- }
- /* Waiting till all Interrupt handlers are complete */
- cnt = 0;
- do {
- msleep(10);
- if (!atomic_read(&sp->isr_cnt))
- break;
- cnt++;
- } while(cnt < 5);
+ if (sp->config.intr_type == MSI_X)
+ remove_msix_isr(sp);
+ else
+ remove_inta_isr(sp);
}
static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
@@ -6425,10 +6779,10 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
del_timer_sync(&sp->alarm_timer);
/* If s2io_set_link task is executing, wait till it completes. */
- while (test_and_set_bit(0, &(sp->link_state))) {
+ while (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(sp->state))) {
msleep(50);
}
- atomic_set(&sp->card_state, CARD_DOWN);
+ clear_bit(__S2IO_STATE_CARD_UP, &sp->state);
/* disable Tx and Rx traffic on the NIC */
if (do_io)
@@ -6479,7 +6833,7 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
free_rx_buffers(sp);
spin_unlock_irqrestore(&sp->rx_lock, flags);
- clear_bit(0, &(sp->link_state));
+ clear_bit(__S2IO_STATE_LINK_TASK, &(sp->state));
}
static void s2io_card_down(struct s2io_nic * sp)
@@ -6550,7 +6904,7 @@ static int s2io_card_up(struct s2io_nic * sp)
/* Add interrupt service routine */
if (s2io_add_isr(sp) != 0) {
- if (sp->intr_type == MSI_X)
+ if (sp->config.intr_type == MSI_X)
s2io_rem_isr(sp);
s2io_reset(sp);
free_rx_buffers(sp);
@@ -6563,17 +6917,16 @@ static int s2io_card_up(struct s2io_nic * sp)
tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
/* Enable select interrupts */
- if (sp->intr_type != INTA)
+ en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS);
+ if (sp->config.intr_type != INTA)
en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
else {
interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
- interruptible |= TX_PIC_INTR | RX_PIC_INTR;
- interruptible |= TX_MAC_INTR | RX_MAC_INTR;
+ interruptible |= TX_PIC_INTR;
en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS);
}
-
- atomic_set(&sp->card_state, CARD_UP);
+ set_bit(__S2IO_STATE_CARD_UP, &sp->state);
return 0;
}
@@ -6727,7 +7080,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%x\n",
dev->name, err_mask);
sp->stats.rx_crc_errors++;
- sp->mac_control.stats_info->sw_stat.mem_freed
+ sp->mac_control.stats_info->sw_stat.mem_freed
+= skb->truesize;
dev_kfree_skb(skb);
atomic_dec(&sp->rx_bufs_left[ring_no]);
@@ -6776,7 +7129,8 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
int ret = 0;
ret = s2io_club_tcp_session(skb->data, &tcp,
- &tcp_len, &lro, rxdp, sp);
+ &tcp_len, &lro,
+ rxdp, sp);
switch (ret) {
case 3: /* Begin anew */
lro->parent = skb;
@@ -6881,13 +7235,13 @@ static void s2io_link(struct s2io_nic * sp, int link)
DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
netif_carrier_off(dev);
if(sp->mac_control.stats_info->sw_stat.link_up_cnt)
- sp->mac_control.stats_info->sw_stat.link_up_time =
+ sp->mac_control.stats_info->sw_stat.link_up_time =
jiffies - sp->start_time;
sp->mac_control.stats_info->sw_stat.link_down_cnt++;
} else {
DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
if (sp->mac_control.stats_info->sw_stat.link_down_cnt)
- sp->mac_control.stats_info->sw_stat.link_down_time =
+ sp->mac_control.stats_info->sw_stat.link_down_time =
jiffies - sp->start_time;
sp->mac_control.stats_info->sw_stat.link_up_cnt++;
netif_carrier_on(dev);
@@ -6944,19 +7298,12 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
if (*dev_intr_type != INTA)
napi = 0;
-#ifndef CONFIG_PCI_MSI
- if (*dev_intr_type != INTA) {
- DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
- "MSI/MSI-X. Defaulting to INTA\n");
- *dev_intr_type = INTA;
- }
-#else
if ((*dev_intr_type != INTA) && (*dev_intr_type != MSI_X)) {
DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
"Defaulting to INTA\n");
*dev_intr_type = INTA;
}
-#endif
+
if ((*dev_intr_type == MSI_X) &&
((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
(pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
@@ -7033,6 +7380,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
struct config_param *config;
int mode;
u8 dev_intr_type = intr_type;
+ DECLARE_MAC_BUF(mac);
if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
return ret;
@@ -7076,7 +7424,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
pci_set_master(pdev);
pci_set_drvdata(pdev, dev);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/* Private member variable initialized to s2io NIC structure */
@@ -7091,7 +7438,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
if (rx_ring_mode == 2)
sp->rxd_mode = RXD_MODE_3B;
- sp->intr_type = dev_intr_type;
+ sp->config.intr_type = dev_intr_type;
if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
(pdev->device == PCI_DEVICE_ID_HERC_UNI))
@@ -7099,7 +7446,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
else
sp->device_type = XFRAME_I_DEVICE;
- sp->lro = lro;
+ sp->lro = lro_enable;
/* Initialize some PCI/PCI-X fields of the NIC. */
s2io_init_pci(sp);
@@ -7114,6 +7461,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
mac_control = &sp->mac_control;
config = &sp->config;
+ config->napi = napi;
+
/* Tx side parameters. */
config->tx_fifo_num = tx_fifo_num;
for (i = 0; i < MAX_TX_FIFOS; i++) {
@@ -7161,9 +7510,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
for (i = 0; i < config->rx_ring_num; i++)
atomic_set(&sp->rx_bufs_left[i], 0);
- /* Initialize the number of ISRs currently running */
- atomic_set(&sp->isr_cnt, 0);
-
/* initialize the shared memory used by the NIC and the host */
if (init_shared_mem(sp)) {
DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
@@ -7206,6 +7552,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->get_stats = &s2io_get_stats;
dev->set_multicast_list = &s2io_set_multicast;
dev->do_ioctl = &s2io_ioctl;
+ dev->set_mac_address = &s2io_set_mac_addr;
dev->change_mtu = &s2io_change_mtu;
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
@@ -7215,8 +7562,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
* will use eth_mac_addr() for dev->set_mac_address
* mac address will be set every time dev->open() is called
*/
- dev->poll = s2io_poll;
- dev->weight = 32;
+ netif_napi_add(dev, &sp->napi, s2io_poll, 32);
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = s2io_netpoll;
@@ -7292,7 +7638,10 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Set the factory defined MAC address initially */
dev->addr_len = ETH_ALEN;
memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
+ memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
+ /* Store the values of the MSIX table in the s2io_nic structure */
+ store_xmsi_data(sp);
/* reset Nic and bring it to known state */
s2io_reset(sp);
@@ -7300,9 +7649,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
* Initialize the tasklet status and link state flags
* and the card state parameter
*/
- atomic_set(&(sp->card_state), 0);
sp->tasklet_status = 0;
- sp->link_state = 0;
+ sp->state = 0;
/* Initialize spinlocks */
spin_lock_init(&sp->tx_lock);
@@ -7338,14 +7686,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
sp->product_name, pdev->revision);
DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
s2io_driver_version);
- DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
- "%02x:%02x:%02x:%02x:%02x:%02x", dev->name,
- sp->def_mac_addr[0].mac_addr[0],
- sp->def_mac_addr[0].mac_addr[1],
- sp->def_mac_addr[0].mac_addr[2],
- sp->def_mac_addr[0].mac_addr[3],
- sp->def_mac_addr[0].mac_addr[4],
- sp->def_mac_addr[0].mac_addr[5]);
+ DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
if (sp->device_type & XFRAME_II_DEVICE) {
mode = s2io_print_pci_mode(sp);
@@ -7369,7 +7711,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
if (napi)
DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
- switch(sp->intr_type) {
+ switch(sp->config.intr_type) {
case INTA:
DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
break;
@@ -7386,14 +7728,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Initialize device name */
sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
- /* Initialize bimodal Interrupts */
- sp->config.bimodal = bimodal;
- if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) {
- sp->config.bimodal = 0;
- DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n",
- dev->name);
- }
-
/*
* Make Link state as off at this point, when the Link change
* interrupt comes the state will be automatically changed to
@@ -7459,7 +7793,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
* the module loadable parameters and initializes PCI configuration space.
*/
-int __init s2io_starter(void)
+static int __init s2io_starter(void)
{
return pci_register_driver(&s2io_driver);
}
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 92983ee7df8..cc1797a071a 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -14,7 +14,7 @@
#define _S2IO_H
#define TBD 0
-#define BIT(loc) (0x8000000000000000ULL >> (loc))
+#define s2BIT(loc) (0x8000000000000000ULL >> (loc))
#define vBIT(val, loc, sz) (((u64)val) << (64-loc-sz))
#define INV(d) ((d&0xff)<<24) | (((d>>8)&0xff)<<16) | (((d>>16)&0xff)<<8)| ((d>>24)&0xff)
@@ -91,7 +91,7 @@ struct swStat {
unsigned long long serious_err_cnt;
unsigned long long soft_reset_cnt;
unsigned long long fifo_full_cnt;
- unsigned long long ring_full_cnt;
+ unsigned long long ring_full_cnt[8];
/* LRO statistics */
unsigned long long clubbed_frms_cnt;
unsigned long long sending_both;
@@ -126,6 +126,26 @@ struct swStat {
unsigned long long rx_buf_size_err_cnt;
unsigned long long rx_rxd_corrupt_cnt;
unsigned long long rx_unkn_err_cnt;
+
+ /* Error/alarm statistics*/
+ unsigned long long tda_err_cnt;
+ unsigned long long pfc_err_cnt;
+ unsigned long long pcc_err_cnt;
+ unsigned long long tti_err_cnt;
+ unsigned long long lso_err_cnt;
+ unsigned long long tpa_err_cnt;
+ unsigned long long sm_err_cnt;
+ unsigned long long mac_tmac_err_cnt;
+ unsigned long long mac_rmac_err_cnt;
+ unsigned long long xgxs_txgxs_err_cnt;
+ unsigned long long xgxs_rxgxs_err_cnt;
+ unsigned long long rc_err_cnt;
+ unsigned long long prc_pcix_err_cnt;
+ unsigned long long rpa_err_cnt;
+ unsigned long long rda_err_cnt;
+ unsigned long long rti_err_cnt;
+ unsigned long long mc_err_cnt;
+
};
/* Xpak releated alarm and warnings */
@@ -412,6 +432,11 @@ struct config_param {
struct tx_fifo_config tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */
u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */
u64 tx_intr_type;
+#define INTA 0
+#define MSI_X 2
+ u8 intr_type;
+ u8 napi;
+
/* Specifies if Tx Intr is UTILZ or PER_LIST type. */
/* Rx Side */
@@ -419,7 +444,6 @@ struct config_param {
#define MAX_RX_BLOCKS_PER_RING 150
struct rx_ring_config rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */
- u8 bimodal; /*Flag for setting bimodal interrupts*/
#define HEADER_ETHERNET_II_802_3_SIZE 14
#define HEADER_802_2_SIZE 3
@@ -449,42 +473,42 @@ struct TxFIFO_element {
u64 List_Control;
#define TX_FIFO_LAST_TXD_NUM( val) vBIT(val,0,8)
-#define TX_FIFO_FIRST_LIST BIT(14)
-#define TX_FIFO_LAST_LIST BIT(15)
+#define TX_FIFO_FIRST_LIST s2BIT(14)
+#define TX_FIFO_LAST_LIST s2BIT(15)
#define TX_FIFO_FIRSTNLAST_LIST vBIT(3,14,2)
-#define TX_FIFO_SPECIAL_FUNC BIT(23)
-#define TX_FIFO_DS_NO_SNOOP BIT(31)
-#define TX_FIFO_BUFF_NO_SNOOP BIT(30)
+#define TX_FIFO_SPECIAL_FUNC s2BIT(23)
+#define TX_FIFO_DS_NO_SNOOP s2BIT(31)
+#define TX_FIFO_BUFF_NO_SNOOP s2BIT(30)
};
/* Tx descriptor structure */
struct TxD {
u64 Control_1;
/* bit mask */
-#define TXD_LIST_OWN_XENA BIT(7)
-#define TXD_T_CODE (BIT(12)|BIT(13)|BIT(14)|BIT(15))
+#define TXD_LIST_OWN_XENA s2BIT(7)
+#define TXD_T_CODE (s2BIT(12)|s2BIT(13)|s2BIT(14)|s2BIT(15))
#define TXD_T_CODE_OK(val) (|(val & TXD_T_CODE))
#define GET_TXD_T_CODE(val) ((val & TXD_T_CODE)<<12)
-#define TXD_GATHER_CODE (BIT(22) | BIT(23))
-#define TXD_GATHER_CODE_FIRST BIT(22)
-#define TXD_GATHER_CODE_LAST BIT(23)
-#define TXD_TCP_LSO_EN BIT(30)
-#define TXD_UDP_COF_EN BIT(31)
-#define TXD_UFO_EN BIT(31) | BIT(30)
+#define TXD_GATHER_CODE (s2BIT(22) | s2BIT(23))
+#define TXD_GATHER_CODE_FIRST s2BIT(22)
+#define TXD_GATHER_CODE_LAST s2BIT(23)
+#define TXD_TCP_LSO_EN s2BIT(30)
+#define TXD_UDP_COF_EN s2BIT(31)
+#define TXD_UFO_EN s2BIT(31) | s2BIT(30)
#define TXD_TCP_LSO_MSS(val) vBIT(val,34,14)
#define TXD_UFO_MSS(val) vBIT(val,34,14)
#define TXD_BUFFER0_SIZE(val) vBIT(val,48,16)
u64 Control_2;
-#define TXD_TX_CKO_CONTROL (BIT(5)|BIT(6)|BIT(7))
-#define TXD_TX_CKO_IPV4_EN BIT(5)
-#define TXD_TX_CKO_TCP_EN BIT(6)
-#define TXD_TX_CKO_UDP_EN BIT(7)
-#define TXD_VLAN_ENABLE BIT(15)
+#define TXD_TX_CKO_CONTROL (s2BIT(5)|s2BIT(6)|s2BIT(7))
+#define TXD_TX_CKO_IPV4_EN s2BIT(5)
+#define TXD_TX_CKO_TCP_EN s2BIT(6)
+#define TXD_TX_CKO_UDP_EN s2BIT(7)
+#define TXD_VLAN_ENABLE s2BIT(15)
#define TXD_VLAN_TAG(val) vBIT(val,16,16)
#define TXD_INT_NUMBER(val) vBIT(val,34,6)
-#define TXD_INT_TYPE_PER_LIST BIT(47)
-#define TXD_INT_TYPE_UTILZ BIT(46)
+#define TXD_INT_TYPE_PER_LIST s2BIT(47)
+#define TXD_INT_TYPE_UTILZ s2BIT(46)
#define TXD_SET_MARKER vBIT(0x6,0,4)
u64 Buffer_Pointer;
@@ -501,14 +525,14 @@ struct list_info_hold {
struct RxD_t {
u64 Host_Control; /* reserved for host */
u64 Control_1;
-#define RXD_OWN_XENA BIT(7)
-#define RXD_T_CODE (BIT(12)|BIT(13)|BIT(14)|BIT(15))
+#define RXD_OWN_XENA s2BIT(7)
+#define RXD_T_CODE (s2BIT(12)|s2BIT(13)|s2BIT(14)|s2BIT(15))
#define RXD_FRAME_PROTO vBIT(0xFFFF,24,8)
-#define RXD_FRAME_PROTO_IPV4 BIT(27)
-#define RXD_FRAME_PROTO_IPV6 BIT(28)
-#define RXD_FRAME_IP_FRAG BIT(29)
-#define RXD_FRAME_PROTO_TCP BIT(30)
-#define RXD_FRAME_PROTO_UDP BIT(31)
+#define RXD_FRAME_PROTO_IPV4 s2BIT(27)
+#define RXD_FRAME_PROTO_IPV6 s2BIT(28)
+#define RXD_FRAME_IP_FRAG s2BIT(29)
+#define RXD_FRAME_PROTO_TCP s2BIT(30)
+#define RXD_FRAME_PROTO_UDP s2BIT(31)
#define TCP_OR_UDP_FRAME (RXD_FRAME_PROTO_TCP | RXD_FRAME_PROTO_UDP)
#define RXD_GET_L3_CKSUM(val) ((u16)(val>> 16) & 0xFFFF)
#define RXD_GET_L4_CKSUM(val) ((u16)(val) & 0xFFFF)
@@ -777,6 +801,13 @@ struct lro {
u8 saw_ts;
};
+/* These flags represent the devices temporary state */
+enum s2io_device_state_t
+{
+ __S2IO_STATE_LINK_TASK=0,
+ __S2IO_STATE_CARD_UP
+};
+
/* Structure representing one instance of the NIC */
struct s2io_nic {
int rxd_mode;
@@ -786,6 +817,7 @@ struct s2io_nic {
*/
int pkts_to_process;
struct net_device *dev;
+ struct napi_struct napi;
struct mac_info mac_control;
struct config_param config;
struct pci_dev *pdev;
@@ -854,13 +886,11 @@ struct s2io_nic {
int task_flag;
unsigned long long start_time;
-#define CARD_DOWN 1
-#define CARD_UP 2
- atomic_t card_state;
- volatile unsigned long link_state;
struct vlan_group *vlgrp;
#define MSIX_FLG 0xA5
struct msix_entry *entries;
+ int msi_detected;
+ wait_queue_head_t msi_wait;
struct s2io_msix_entry *s2io_entries;
char desc[MAX_REQUESTED_MSI_X][25];
@@ -878,13 +908,9 @@ struct s2io_nic {
unsigned long sending_both;
u8 lro;
u16 lro_max_aggr_per_sess;
-
-#define INTA 0
-#define MSI_X 2
- u8 intr_type;
-
+ volatile unsigned long state;
spinlock_t rx_lock;
- atomic_t isr_cnt;
+ u64 general_int_mask;
u64 *ufo_in_band_v;
#define VPD_STRING_LEN 80
u8 product_name[VPD_STRING_LEN];
@@ -972,26 +998,26 @@ static inline void SPECIAL_REG_WRITE(u64 val, void __iomem *addr, int order)
/* Interrupt masks for the general interrupt mask register */
#define DISABLE_ALL_INTRS 0xFFFFFFFFFFFFFFFFULL
-#define TXPIC_INT_M BIT(0)
-#define TXDMA_INT_M BIT(1)
-#define TXMAC_INT_M BIT(2)
-#define TXXGXS_INT_M BIT(3)
-#define TXTRAFFIC_INT_M BIT(8)
-#define PIC_RX_INT_M BIT(32)
-#define RXDMA_INT_M BIT(33)
-#define RXMAC_INT_M BIT(34)
-#define MC_INT_M BIT(35)
-#define RXXGXS_INT_M BIT(36)
-#define RXTRAFFIC_INT_M BIT(40)
+#define TXPIC_INT_M s2BIT(0)
+#define TXDMA_INT_M s2BIT(1)
+#define TXMAC_INT_M s2BIT(2)
+#define TXXGXS_INT_M s2BIT(3)
+#define TXTRAFFIC_INT_M s2BIT(8)
+#define PIC_RX_INT_M s2BIT(32)
+#define RXDMA_INT_M s2BIT(33)
+#define RXMAC_INT_M s2BIT(34)
+#define MC_INT_M s2BIT(35)
+#define RXXGXS_INT_M s2BIT(36)
+#define RXTRAFFIC_INT_M s2BIT(40)
/* PIC level Interrupts TODO*/
/* DMA level Inressupts */
-#define TXDMA_PFC_INT_M BIT(0)
-#define TXDMA_PCC_INT_M BIT(2)
+#define TXDMA_PFC_INT_M s2BIT(0)
+#define TXDMA_PCC_INT_M s2BIT(2)
/* PFC block interrupts */
-#define PFC_MISC_ERR_1 BIT(0) /* Interrupt to indicate FIFO full */
+#define PFC_MISC_ERR_1 s2BIT(0) /* Interrupt to indicate FIFO full */
/* PCC block interrupts. */
#define PCC_FB_ECC_ERR vBIT(0xff, 16, 8) /* Interrupt to indicate
@@ -1009,7 +1035,7 @@ static void free_shared_mem(struct s2io_nic *sp);
static int init_nic(struct s2io_nic *nic);
static void rx_intr_handler(struct ring_info *ring_data);
static void tx_intr_handler(struct fifo_info *fifo_data);
-static void alarm_intr_handler(struct s2io_nic *sp);
+static void s2io_handle_errors(void * dev_id);
static int s2io_starter(void);
static void s2io_closer(void);
@@ -1019,9 +1045,9 @@ static void s2io_set_multicast(struct net_device *dev);
static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp);
static void s2io_link(struct s2io_nic * sp, int link);
static void s2io_reset(struct s2io_nic * sp);
-static int s2io_poll(struct net_device *dev, int *budget);
+static int s2io_poll(struct napi_struct *napi, int budget);
static void s2io_init_pci(struct s2io_nic * sp);
-static int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
+static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr);
static void s2io_alarm_handle(unsigned long data);
static irqreturn_t
s2io_msix_ring_handle(int irq, void *dev_id);
diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c
index 7dae4d40497..c65199df8a7 100644
--- a/drivers/net/saa9730.c
+++ b/drivers/net/saa9730.c
@@ -97,13 +97,16 @@ static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp)
&lp->evm_saa9730_regs->InterruptBlock1);
}
-static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp)
+static void __used show_saa9730_regs(struct net_device *dev)
{
+ struct lan_saa9730_private *lp = netdev_priv(dev);
int i, j;
+
printk("TxmBufferA = %p\n", lp->TxmBuffer[0][0]);
printk("TxmBufferB = %p\n", lp->TxmBuffer[1][0]);
printk("RcvBufferA = %p\n", lp->RcvBuffer[0][0]);
printk("RcvBufferB = %p\n", lp->RcvBuffer[1][0]);
+
for (i = 0; i < LAN_SAA9730_BUFFERS; i++) {
for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) {
printk("TxmBuffer[%d][%d] = %x\n", i, j,
@@ -146,35 +149,37 @@ static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp)
readl(&lp->lan_saa9730_regs->RxCtl));
printk("lp->lan_saa9730_regs->RxStatus = %x\n",
readl(&lp->lan_saa9730_regs->RxStatus));
+
for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) {
writel(i, &lp->lan_saa9730_regs->CamAddress);
printk("lp->lan_saa9730_regs->CamData = %x\n",
readl(&lp->lan_saa9730_regs->CamData));
}
- printk("lp->stats.tx_packets = %lx\n", lp->stats.tx_packets);
- printk("lp->stats.tx_errors = %lx\n", lp->stats.tx_errors);
- printk("lp->stats.tx_aborted_errors = %lx\n",
- lp->stats.tx_aborted_errors);
- printk("lp->stats.tx_window_errors = %lx\n",
- lp->stats.tx_window_errors);
- printk("lp->stats.tx_carrier_errors = %lx\n",
- lp->stats.tx_carrier_errors);
- printk("lp->stats.tx_fifo_errors = %lx\n",
- lp->stats.tx_fifo_errors);
- printk("lp->stats.tx_heartbeat_errors = %lx\n",
- lp->stats.tx_heartbeat_errors);
- printk("lp->stats.collisions = %lx\n", lp->stats.collisions);
-
- printk("lp->stats.rx_packets = %lx\n", lp->stats.rx_packets);
- printk("lp->stats.rx_errors = %lx\n", lp->stats.rx_errors);
- printk("lp->stats.rx_dropped = %lx\n", lp->stats.rx_dropped);
- printk("lp->stats.rx_crc_errors = %lx\n", lp->stats.rx_crc_errors);
- printk("lp->stats.rx_frame_errors = %lx\n",
- lp->stats.rx_frame_errors);
- printk("lp->stats.rx_fifo_errors = %lx\n",
- lp->stats.rx_fifo_errors);
- printk("lp->stats.rx_length_errors = %lx\n",
- lp->stats.rx_length_errors);
+
+ printk("dev->stats.tx_packets = %lx\n", dev->stats.tx_packets);
+ printk("dev->stats.tx_errors = %lx\n", dev->stats.tx_errors);
+ printk("dev->stats.tx_aborted_errors = %lx\n",
+ dev->stats.tx_aborted_errors);
+ printk("dev->stats.tx_window_errors = %lx\n",
+ dev->stats.tx_window_errors);
+ printk("dev->stats.tx_carrier_errors = %lx\n",
+ dev->stats.tx_carrier_errors);
+ printk("dev->stats.tx_fifo_errors = %lx\n",
+ dev->stats.tx_fifo_errors);
+ printk("dev->stats.tx_heartbeat_errors = %lx\n",
+ dev->stats.tx_heartbeat_errors);
+ printk("dev->stats.collisions = %lx\n", dev->stats.collisions);
+
+ printk("dev->stats.rx_packets = %lx\n", dev->stats.rx_packets);
+ printk("dev->stats.rx_errors = %lx\n", dev->stats.rx_errors);
+ printk("dev->stats.rx_dropped = %lx\n", dev->stats.rx_dropped);
+ printk("dev->stats.rx_crc_errors = %lx\n", dev->stats.rx_crc_errors);
+ printk("dev->stats.rx_frame_errors = %lx\n",
+ dev->stats.rx_frame_errors);
+ printk("dev->stats.rx_fifo_errors = %lx\n",
+ dev->stats.rx_fifo_errors);
+ printk("dev->stats.rx_length_errors = %lx\n",
+ dev->stats.rx_length_errors);
printk("lp->lan_saa9730_regs->DebugPCIMasterAddr = %x\n",
readl(&lp->lan_saa9730_regs->DebugPCIMasterAddr));
@@ -605,24 +610,24 @@ static int lan_saa9730_tx(struct net_device *dev)
printk("lan_saa9730_tx: tx error = %x\n",
tx_status);
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (tx_status &
(TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF))
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (tx_status &
(TX_STATUS_LATE_COLL << TX_STAT_CTL_STATUS_SHF))
- lp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (tx_status &
(TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF))
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (tx_status &
(TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF))
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (tx_status &
(TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF))
- lp->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
- lp->stats.collisions +=
+ dev->stats.collisions +=
tx_status & TX_STATUS_TX_COLL_MSK;
}
@@ -684,10 +689,10 @@ static int lan_saa9730_rx(struct net_device *dev)
printk
("%s: Memory squeeze, deferring packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
} else {
- lp->stats.rx_bytes += len;
- lp->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
skb_reserve(skb, 2); /* 16 byte align */
skb_put(skb, len); /* make room */
skb_copy_to_linear_data(skb,
@@ -704,19 +709,19 @@ static int lan_saa9730_rx(struct net_device *dev)
("lan_saa9730_rx: We got an error packet = %x\n",
rx_status);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rx_status &
(RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF))
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rx_status &
(RX_STATUS_ALIGN_ERR << RX_STAT_CTL_STATUS_SHF))
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rx_status &
(RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF))
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (rx_status &
(RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF))
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
/* Indicate we have processed the buffer. */
@@ -853,9 +858,9 @@ static void lan_saa9730_tx_timeout(struct net_device *dev)
struct lan_saa9730_private *lp = netdev_priv(dev);
/* Transmitter timeout, serious problems */
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
printk("%s: transmit timed out, reset\n", dev->name);
- /*show_saa9730_regs(lp); */
+ /*show_saa9730_regs(dev); */
lan_saa9730_restart(lp);
dev->trans_start = jiffies;
@@ -886,8 +891,8 @@ static int lan_saa9730_start_xmit(struct sk_buff *skb,
return -1;
}
- lp->stats.tx_bytes += len;
- lp->stats.tx_packets++;
+ dev->stats.tx_bytes += len;
+ dev->stats.tx_packets++;
dev->trans_start = jiffies;
netif_wake_queue(dev);
@@ -919,14 +924,6 @@ static int lan_saa9730_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *lan_saa9730_get_stats(struct net_device
- *dev)
-{
- struct lan_saa9730_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
static void lan_saa9730_set_multicast(struct net_device *dev)
{
struct lan_saa9730_private *lp = netdev_priv(dev);
@@ -1040,7 +1037,6 @@ static int lan_saa9730_init(struct net_device *dev, struct pci_dev *pdev,
dev->open = lan_saa9730_open;
dev->hard_start_xmit = lan_saa9730_start_xmit;
dev->stop = lan_saa9730_close;
- dev->get_stats = lan_saa9730_get_stats;
dev->set_multicast_list = lan_saa9730_set_multicast;
dev->tx_timeout = lan_saa9730_tx_timeout;
dev->watchdog_timeo = (HZ >> 1);
diff --git a/drivers/net/saa9730.h b/drivers/net/saa9730.h
index f656f2f40bb..010a120ea93 100644
--- a/drivers/net/saa9730.h
+++ b/drivers/net/saa9730.h
@@ -378,7 +378,6 @@ struct lan_saa9730_private {
unsigned char PhysicalAddress[LAN_SAA9730_CAM_ENTRIES][6];
- struct net_device_stats stats;
spinlock_t lock;
};
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index 1de3eec1a79..487f9d2ac5b 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -76,7 +76,6 @@ struct sb1000_private {
unsigned char rx_session_id[NPIDS];
unsigned char rx_frame_id[NPIDS];
unsigned char rx_pkt_type[NPIDS];
- struct net_device_stats stats;
};
/* prototypes for Linux interface */
@@ -85,7 +84,6 @@ static int sb1000_open(struct net_device *dev);
static int sb1000_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd);
static int sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t sb1000_interrupt(int irq, void *dev_id);
-static struct net_device_stats *sb1000_stats(struct net_device *dev);
static int sb1000_close(struct net_device *dev);
@@ -189,7 +187,6 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id)
*/
dev->flags = IFF_POINTOPOINT|IFF_NOARP;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (sb1000_debug > 0)
@@ -200,7 +197,6 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id)
dev->do_ioctl = sb1000_dev_ioctl;
dev->hard_start_xmit = sb1000_start_xmit;
dev->stop = sb1000_close;
- dev->get_stats = sb1000_stats;
/* hardware address is 0:0:serial_number */
dev->dev_addr[2] = serial_number >> 24 & 0xff;
@@ -740,7 +736,7 @@ sb1000_rx(struct net_device *dev)
unsigned int skbsize;
struct sk_buff *skb;
struct sb1000_private *lp = netdev_priv(dev);
- struct net_device_stats *stats = &lp->stats;
+ struct net_device_stats *stats = &dev->stats;
/* SB1000 frame constants */
const int FrameSize = FRAMESIZE;
@@ -1003,11 +999,11 @@ static int sb1000_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
switch (cmd) {
case SIOCGCMSTATS: /* get statistics */
- stats[0] = lp->stats.rx_bytes;
+ stats[0] = dev->stats.rx_bytes;
stats[1] = lp->rx_frames;
- stats[2] = lp->stats.rx_packets;
- stats[3] = lp->stats.rx_errors;
- stats[4] = lp->stats.rx_dropped;
+ stats[2] = dev->stats.rx_packets;
+ stats[3] = dev->stats.rx_errors;
+ stats[4] = dev->stats.rx_dropped;
if(copy_to_user(ifr->ifr_data, stats, sizeof(stats)))
return -EFAULT;
status = 0;
@@ -1133,12 +1129,6 @@ static irqreturn_t sb1000_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static struct net_device_stats *sb1000_stats(struct net_device *dev)
-{
- struct sb1000_private *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
static int sb1000_close(struct net_device *dev)
{
int i;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index e7fdcf15b5a..7b53d658e33 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2001,2002,2003,2004 Broadcom Corporation
+ * Copyright (c) 2006, 2007 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -18,7 +19,12 @@
*
* This driver is designed for the Broadcom SiByte SOC built-in
* Ethernet controllers. Written by Mitch Lichtenberg at Broadcom Corp.
+ *
+ * Updated to the driver model and the PHY abstraction layer
+ * by Maciej W. Rozycki.
*/
+
+#include <linux/bug.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -32,9 +38,15 @@
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/bitops.h>
-#include <asm/processor.h> /* Processor type for cache alignment. */
-#include <asm/io.h>
+#include <linux/err.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+
#include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/processor.h> /* Processor type for cache alignment. */
/* This is only here until the firmware is ready. In that case,
the firmware leaves the ethernet address in the register for us. */
@@ -48,7 +60,7 @@
/* These identify the driver base version and may not be removed. */
#if 0
-static char version1[] __devinitdata =
+static char version1[] __initdata =
"sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg\n";
#endif
@@ -57,8 +69,6 @@ static char version1[] __devinitdata =
#define CONFIG_SBMAC_COALESCE
-#define MAX_UNITS 4 /* More are supported, limit only on options */
-
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (2*HZ)
@@ -74,26 +84,6 @@ static int debug = 1;
module_param(debug, int, S_IRUGO);
MODULE_PARM_DESC(debug, "Debug messages");
-/* mii status msgs */
-static int noisy_mii = 1;
-module_param(noisy_mii, int, S_IRUGO);
-MODULE_PARM_DESC(noisy_mii, "MII status messages");
-
-/* Used to pass the media type, etc.
- Both 'options[]' and 'full_duplex[]' should exist for driver
- interoperability.
- The media type is usually passed in 'options[]'.
-*/
-#ifdef MODULE
-static int options[MAX_UNITS] = {-1, -1, -1, -1};
-module_param_array(options, int, NULL, S_IRUGO);
-MODULE_PARM_DESC(options, "1-" __MODULE_STRING(MAX_UNITS));
-
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1};
-module_param_array(full_duplex, int, NULL, S_IRUGO);
-MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS));
-#endif
-
#ifdef CONFIG_SBMAC_COALESCE
static int int_pktcnt_tx = 255;
module_param(int_pktcnt_tx, int, S_IRUGO);
@@ -112,6 +102,7 @@ module_param(int_timeout_rx, int, S_IRUGO);
MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");
#endif
+#include <asm/sibyte/board.h>
#include <asm/sibyte/sb1250.h>
#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
#include <asm/sibyte/bcm1480_regs.h>
@@ -135,22 +126,43 @@ MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");
#error invalid SiByte MAC configuation
#endif
+#ifdef K_INT_PHY
+#define SBMAC_PHY_INT K_INT_PHY
+#else
+#define SBMAC_PHY_INT PHY_POLL
+#endif
+
/**********************************************************************
* Simple types
********************************************************************* */
+enum sbmac_speed {
+ sbmac_speed_none = 0,
+ sbmac_speed_10 = SPEED_10,
+ sbmac_speed_100 = SPEED_100,
+ sbmac_speed_1000 = SPEED_1000,
+};
-typedef enum { sbmac_speed_auto, sbmac_speed_10,
- sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t;
-
-typedef enum { sbmac_duplex_auto, sbmac_duplex_half,
- sbmac_duplex_full } sbmac_duplex_t;
+enum sbmac_duplex {
+ sbmac_duplex_none = -1,
+ sbmac_duplex_half = DUPLEX_HALF,
+ sbmac_duplex_full = DUPLEX_FULL,
+};
-typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame,
- sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t;
+enum sbmac_fc {
+ sbmac_fc_none,
+ sbmac_fc_disabled,
+ sbmac_fc_frame,
+ sbmac_fc_collision,
+ sbmac_fc_carrier,
+};
-typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
- sbmac_state_broken } sbmac_state_t;
+enum sbmac_state {
+ sbmac_state_uninit,
+ sbmac_state_off,
+ sbmac_state_on,
+ sbmac_state_broken,
+};
/**********************************************************************
@@ -176,55 +188,61 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
* DMA Descriptor structure
********************************************************************* */
-typedef struct sbdmadscr_s {
+struct sbdmadscr {
uint64_t dscr_a;
uint64_t dscr_b;
-} sbdmadscr_t;
-
-typedef unsigned long paddr_t;
+};
/**********************************************************************
* DMA Controller structure
********************************************************************* */
-typedef struct sbmacdma_s {
+struct sbmacdma {
/*
* This stuff is used to identify the channel and the registers
* associated with it.
*/
-
- struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */
- int sbdma_channel; /* channel number */
- int sbdma_txdir; /* direction (1=transmit) */
- int sbdma_maxdescr; /* total # of descriptors in ring */
+ struct sbmac_softc *sbdma_eth; /* back pointer to associated
+ MAC */
+ int sbdma_channel; /* channel number */
+ int sbdma_txdir; /* direction (1=transmit) */
+ int sbdma_maxdescr; /* total # of descriptors
+ in ring */
#ifdef CONFIG_SBMAC_COALESCE
- int sbdma_int_pktcnt; /* # descriptors rx/tx before interrupt*/
- int sbdma_int_timeout; /* # usec rx/tx interrupt */
+ int sbdma_int_pktcnt;
+ /* # descriptors rx/tx
+ before interrupt */
+ int sbdma_int_timeout;
+ /* # usec rx/tx interrupt */
#endif
-
- volatile void __iomem *sbdma_config0; /* DMA config register 0 */
- volatile void __iomem *sbdma_config1; /* DMA config register 1 */
- volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */
- volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */
- volatile void __iomem *sbdma_curdscr; /* current descriptor address */
- volatile void __iomem *sbdma_oodpktlost;/* pkt drop (rx only) */
-
+ void __iomem *sbdma_config0; /* DMA config register 0 */
+ void __iomem *sbdma_config1; /* DMA config register 1 */
+ void __iomem *sbdma_dscrbase;
+ /* descriptor base address */
+ void __iomem *sbdma_dscrcnt; /* descriptor count register */
+ void __iomem *sbdma_curdscr; /* current descriptor
+ address */
+ void __iomem *sbdma_oodpktlost;
+ /* pkt drop (rx only) */
/*
* This stuff is for maintenance of the ring
*/
-
- sbdmadscr_t *sbdma_dscrtable_unaligned;
- sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */
- sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */
-
- struct sk_buff **sbdma_ctxtable; /* context table, one per descr */
-
- paddr_t sbdma_dscrtable_phys; /* and also the phys addr */
- sbdmadscr_t *sbdma_addptr; /* next dscr for sw to add */
- sbdmadscr_t *sbdma_remptr; /* next dscr for sw to remove */
-} sbmacdma_t;
+ void *sbdma_dscrtable_unaligned;
+ struct sbdmadscr *sbdma_dscrtable;
+ /* base of descriptor table */
+ struct sbdmadscr *sbdma_dscrtable_end;
+ /* end of descriptor table */
+ struct sk_buff **sbdma_ctxtable;
+ /* context table, one
+ per descr */
+ dma_addr_t sbdma_dscrtable_phys;
+ /* and also the phys addr */
+ struct sbdmadscr *sbdma_addptr; /* next dscr for sw to add */
+ struct sbdmadscr *sbdma_remptr; /* next dscr for sw
+ to remove */
+};
/**********************************************************************
@@ -236,47 +254,43 @@ struct sbmac_softc {
/*
* Linux-specific things
*/
+ struct net_device *sbm_dev; /* pointer to linux device */
+ struct napi_struct napi;
+ struct phy_device *phy_dev; /* the associated PHY device */
+ struct mii_bus mii_bus; /* the MII bus */
+ int phy_irq[PHY_MAX_ADDR];
+ spinlock_t sbm_lock; /* spin lock */
+ int sbm_devflags; /* current device flags */
- struct net_device *sbm_dev; /* pointer to linux device */
- spinlock_t sbm_lock; /* spin lock */
- struct timer_list sbm_timer; /* for monitoring MII */
- struct net_device_stats sbm_stats;
- int sbm_devflags; /* current device flags */
-
- int sbm_phy_oldbmsr;
- int sbm_phy_oldanlpar;
- int sbm_phy_oldk1stsr;
- int sbm_phy_oldlinkstat;
- int sbm_buffersize;
-
- unsigned char sbm_phys[2];
+ int sbm_buffersize;
/*
* Controller-specific things
*/
-
- void __iomem *sbm_base; /* MAC's base address */
- sbmac_state_t sbm_state; /* current state */
-
- volatile void __iomem *sbm_macenable; /* MAC Enable Register */
- volatile void __iomem *sbm_maccfg; /* MAC Configuration Register */
- volatile void __iomem *sbm_fifocfg; /* FIFO configuration register */
- volatile void __iomem *sbm_framecfg; /* Frame configuration register */
- volatile void __iomem *sbm_rxfilter; /* receive filter register */
- volatile void __iomem *sbm_isr; /* Interrupt status register */
- volatile void __iomem *sbm_imr; /* Interrupt mask register */
- volatile void __iomem *sbm_mdio; /* MDIO register */
-
- sbmac_speed_t sbm_speed; /* current speed */
- sbmac_duplex_t sbm_duplex; /* current duplex */
- sbmac_fc_t sbm_fc; /* current flow control setting */
-
- unsigned char sbm_hwaddr[ETHER_ADDR_LEN];
-
- sbmacdma_t sbm_txdma; /* for now, only use channel 0 */
- sbmacdma_t sbm_rxdma;
- int rx_hw_checksum;
- int sbe_idx;
+ void __iomem *sbm_base; /* MAC's base address */
+ enum sbmac_state sbm_state; /* current state */
+
+ void __iomem *sbm_macenable; /* MAC Enable Register */
+ void __iomem *sbm_maccfg; /* MAC Config Register */
+ void __iomem *sbm_fifocfg; /* FIFO Config Register */
+ void __iomem *sbm_framecfg; /* Frame Config Register */
+ void __iomem *sbm_rxfilter; /* Receive Filter Register */
+ void __iomem *sbm_isr; /* Interrupt Status Register */
+ void __iomem *sbm_imr; /* Interrupt Mask Register */
+ void __iomem *sbm_mdio; /* MDIO Register */
+
+ enum sbmac_speed sbm_speed; /* current speed */
+ enum sbmac_duplex sbm_duplex; /* current duplex */
+ enum sbmac_fc sbm_fc; /* cur. flow control setting */
+ int sbm_pause; /* current pause setting */
+ int sbm_link; /* current link state */
+
+ unsigned char sbm_hwaddr[ETHER_ADDR_LEN];
+
+ struct sbmacdma sbm_txdma; /* only channel 0 for now */
+ struct sbmacdma sbm_rxdma;
+ int rx_hw_checksum;
+ int sbe_idx;
};
@@ -288,55 +302,58 @@ struct sbmac_softc {
* Prototypes
********************************************************************* */
-static void sbdma_initctx(sbmacdma_t *d,
- struct sbmac_softc *s,
- int chan,
- int txrx,
- int maxdescr);
-static void sbdma_channel_start(sbmacdma_t *d, int rxtx);
-static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m);
-static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m);
-static void sbdma_emptyring(sbmacdma_t *d);
-static void sbdma_fillring(sbmacdma_t *d);
-static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int work_to_do, int poll);
-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll);
+static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan,
+ int txrx, int maxdescr);
+static void sbdma_channel_start(struct sbmacdma *d, int rxtx);
+static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *m);
+static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *m);
+static void sbdma_emptyring(struct sbmacdma *d);
+static void sbdma_fillring(struct sbmacdma *d);
+static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d,
+ int work_to_do, int poll);
+static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d,
+ int poll);
static int sbmac_initctx(struct sbmac_softc *s);
static void sbmac_channel_start(struct sbmac_softc *s);
static void sbmac_channel_stop(struct sbmac_softc *s);
-static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t);
-static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff);
+static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *,
+ enum sbmac_state);
+static void sbmac_promiscuous_mode(struct sbmac_softc *sc, int onoff);
static uint64_t sbmac_addr2reg(unsigned char *ptr);
-static irqreturn_t sbmac_intr(int irq,void *dev_instance);
+static irqreturn_t sbmac_intr(int irq, void *dev_instance);
static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
static void sbmac_setmulti(struct sbmac_softc *sc);
-static int sbmac_init(struct net_device *dev, int idx);
-static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed);
-static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc);
+static int sbmac_init(struct platform_device *pldev, long long base);
+static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed);
+static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex,
+ enum sbmac_fc fc);
static int sbmac_open(struct net_device *dev);
-static void sbmac_timer(unsigned long data);
static void sbmac_tx_timeout (struct net_device *dev);
-static struct net_device_stats *sbmac_get_stats(struct net_device *dev);
static void sbmac_set_rx_mode(struct net_device *dev);
static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int sbmac_close(struct net_device *dev);
-static int sbmac_poll(struct net_device *poll_dev, int *budget);
+static int sbmac_poll(struct napi_struct *napi, int budget);
-static int sbmac_mii_poll(struct sbmac_softc *s,int noisy);
+static void sbmac_mii_poll(struct net_device *dev);
static int sbmac_mii_probe(struct net_device *dev);
-static void sbmac_mii_sync(struct sbmac_softc *s);
-static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt);
-static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx);
-static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
- unsigned int regval);
+static void sbmac_mii_sync(void __iomem *sbm_mdio);
+static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data,
+ int bitcnt);
+static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx);
+static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
+ u16 val);
/**********************************************************************
* Globals
********************************************************************* */
-static uint64_t sbmac_orig_hwaddr[MAX_UNITS];
+static char sbmac_string[] = "sb1250-mac";
+static char sbmac_pretty[] = "SB1250 MAC";
+
+static char sbmac_mdio_string[] = "sb1250-mac-mdio";
/**********************************************************************
@@ -348,185 +365,66 @@ static uint64_t sbmac_orig_hwaddr[MAX_UNITS];
#define MII_COMMAND_WRITE 0x01
#define MII_COMMAND_ACK 0x02
-#define BMCR_RESET 0x8000
-#define BMCR_LOOPBACK 0x4000
-#define BMCR_SPEED0 0x2000
-#define BMCR_ANENABLE 0x1000
-#define BMCR_POWERDOWN 0x0800
-#define BMCR_ISOLATE 0x0400
-#define BMCR_RESTARTAN 0x0200
-#define BMCR_DUPLEX 0x0100
-#define BMCR_COLTEST 0x0080
-#define BMCR_SPEED1 0x0040
-#define BMCR_SPEED1000 BMCR_SPEED1
-#define BMCR_SPEED100 BMCR_SPEED0
-#define BMCR_SPEED10 0
-
-#define BMSR_100BT4 0x8000
-#define BMSR_100BT_FDX 0x4000
-#define BMSR_100BT_HDX 0x2000
-#define BMSR_10BT_FDX 0x1000
-#define BMSR_10BT_HDX 0x0800
-#define BMSR_100BT2_FDX 0x0400
-#define BMSR_100BT2_HDX 0x0200
-#define BMSR_1000BT_XSR 0x0100
-#define BMSR_PRESUP 0x0040
-#define BMSR_ANCOMPLT 0x0020
-#define BMSR_REMFAULT 0x0010
-#define BMSR_AUTONEG 0x0008
-#define BMSR_LINKSTAT 0x0004
-#define BMSR_JABDETECT 0x0002
-#define BMSR_EXTCAPAB 0x0001
-
-#define PHYIDR1 0x2000
-#define PHYIDR2 0x5C60
-
-#define ANAR_NP 0x8000
-#define ANAR_RF 0x2000
-#define ANAR_ASYPAUSE 0x0800
-#define ANAR_PAUSE 0x0400
-#define ANAR_T4 0x0200
-#define ANAR_TXFD 0x0100
-#define ANAR_TXHD 0x0080
-#define ANAR_10FD 0x0040
-#define ANAR_10HD 0x0020
-#define ANAR_PSB 0x0001
-
-#define ANLPAR_NP 0x8000
-#define ANLPAR_ACK 0x4000
-#define ANLPAR_RF 0x2000
-#define ANLPAR_ASYPAUSE 0x0800
-#define ANLPAR_PAUSE 0x0400
-#define ANLPAR_T4 0x0200
-#define ANLPAR_TXFD 0x0100
-#define ANLPAR_TXHD 0x0080
-#define ANLPAR_10FD 0x0040
-#define ANLPAR_10HD 0x0020
-#define ANLPAR_PSB 0x0001 /* 802.3 */
-
-#define ANER_PDF 0x0010
-#define ANER_LPNPABLE 0x0008
-#define ANER_NPABLE 0x0004
-#define ANER_PAGERX 0x0002
-#define ANER_LPANABLE 0x0001
-
-#define ANNPTR_NP 0x8000
-#define ANNPTR_MP 0x2000
-#define ANNPTR_ACK2 0x1000
-#define ANNPTR_TOGTX 0x0800
-#define ANNPTR_CODE 0x0008
-
-#define ANNPRR_NP 0x8000
-#define ANNPRR_MP 0x2000
-#define ANNPRR_ACK3 0x1000
-#define ANNPRR_TOGTX 0x0800
-#define ANNPRR_CODE 0x0008
-
-#define K1TCR_TESTMODE 0x0000
-#define K1TCR_MSMCE 0x1000
-#define K1TCR_MSCV 0x0800
-#define K1TCR_RPTR 0x0400
-#define K1TCR_1000BT_FDX 0x200
-#define K1TCR_1000BT_HDX 0x100
-
-#define K1STSR_MSMCFLT 0x8000
-#define K1STSR_MSCFGRES 0x4000
-#define K1STSR_LRSTAT 0x2000
-#define K1STSR_RRSTAT 0x1000
-#define K1STSR_LP1KFD 0x0800
-#define K1STSR_LP1KHD 0x0400
-#define K1STSR_LPASMDIR 0x0200
-
-#define K1SCR_1KX_FDX 0x8000
-#define K1SCR_1KX_HDX 0x4000
-#define K1SCR_1KT_FDX 0x2000
-#define K1SCR_1KT_HDX 0x1000
-
-#define STRAP_PHY1 0x0800
-#define STRAP_NCMODE 0x0400
-#define STRAP_MANMSCFG 0x0200
-#define STRAP_ANENABLE 0x0100
-#define STRAP_MSVAL 0x0080
-#define STRAP_1KHDXADV 0x0010
-#define STRAP_1KFDXADV 0x0008
-#define STRAP_100ADV 0x0004
-#define STRAP_SPEEDSEL 0x0000
-#define STRAP_SPEED100 0x0001
-
-#define PHYSUP_SPEED1000 0x10
-#define PHYSUP_SPEED100 0x08
-#define PHYSUP_SPEED10 0x00
-#define PHYSUP_LINKUP 0x04
-#define PHYSUP_FDX 0x02
-
-#define MII_BMCR 0x00 /* Basic mode control register (rw) */
-#define MII_BMSR 0x01 /* Basic mode status register (ro) */
-#define MII_PHYIDR1 0x02
-#define MII_PHYIDR2 0x03
-
-#define MII_K1STSR 0x0A /* 1K Status Register (ro) */
-#define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */
-
-
#define M_MAC_MDIO_DIR_OUTPUT 0 /* for clarity */
#define ENABLE 1
#define DISABLE 0
/**********************************************************************
- * SBMAC_MII_SYNC(s)
+ * SBMAC_MII_SYNC(sbm_mdio)
*
* Synchronize with the MII - send a pattern of bits to the MII
* that will guarantee that it is ready to accept a command.
*
* Input parameters:
- * s - sbmac structure
+ * sbm_mdio - address of the MAC's MDIO register
*
* Return value:
* nothing
********************************************************************* */
-static void sbmac_mii_sync(struct sbmac_softc *s)
+static void sbmac_mii_sync(void __iomem *sbm_mdio)
{
int cnt;
uint64_t bits;
int mac_mdio_genc;
- mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+ mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT;
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
for (cnt = 0; cnt < 32; cnt++) {
- __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio);
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
}
}
/**********************************************************************
- * SBMAC_MII_SENDDATA(s,data,bitcnt)
+ * SBMAC_MII_SENDDATA(sbm_mdio, data, bitcnt)
*
* Send some bits to the MII. The bits to be sent are right-
* justified in the 'data' parameter.
*
* Input parameters:
- * s - sbmac structure
- * data - data to send
- * bitcnt - number of bits to send
+ * sbm_mdio - address of the MAC's MDIO register
+ * data - data to send
+ * bitcnt - number of bits to send
********************************************************************* */
-static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt)
+static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data,
+ int bitcnt)
{
int i;
uint64_t bits;
unsigned int curmask;
int mac_mdio_genc;
- mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+ mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
bits = M_MAC_MDIO_DIR_OUTPUT;
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
curmask = 1 << (bitcnt - 1);
@@ -534,9 +432,9 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc
if (data & curmask)
bits |= M_MAC_MDIO_OUT;
else bits &= ~M_MAC_MDIO_OUT;
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
- __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
- __raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
+ __raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio);
+ __raw_writeq(bits | mac_mdio_genc, sbm_mdio);
curmask >>= 1;
}
}
@@ -544,21 +442,22 @@ static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitc
/**********************************************************************
- * SBMAC_MII_READ(s,phyaddr,regidx)
- *
+ * SBMAC_MII_READ(bus, phyaddr, regidx)
* Read a PHY register.
*
* Input parameters:
- * s - sbmac structure
+ * bus - MDIO bus handle
* phyaddr - PHY's address
- * regidx = index of register to read
+ * regnum - index of register to read
*
* Return value:
- * value read, or 0 if an error occurred.
+ * value read, or 0xffff if an error occurred.
********************************************************************* */
-static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
+static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
{
+ struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv;
+ void __iomem *sbm_mdio = sc->sbm_mdio;
int idx;
int error;
int regval;
@@ -568,8 +467,7 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
* Synchronize ourselves so that the PHY knows the next
* thing coming down is a command
*/
-
- sbmac_mii_sync(s);
+ sbmac_mii_sync(sbm_mdio);
/*
* Send the data to the PHY. The sequence is
@@ -578,37 +476,37 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
* the PHY addr (5 bits)
* the register index (5 bits)
*/
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2);
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_READ, 2);
+ sbmac_mii_senddata(sbm_mdio, phyaddr, 5);
+ sbmac_mii_senddata(sbm_mdio, regidx, 5);
- sbmac_mii_senddata(s,MII_COMMAND_START, 2);
- sbmac_mii_senddata(s,MII_COMMAND_READ, 2);
- sbmac_mii_senddata(s,phyaddr, 5);
- sbmac_mii_senddata(s,regidx, 5);
-
- mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+ mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
/*
* Switch the port around without a clock transition.
*/
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
/*
* Send out a clock pulse to signal we want the status
*/
-
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc,
+ sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
/*
* If an error occurred, the PHY will signal '1' back
*/
- error = __raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN;
+ error = __raw_readq(sbm_mdio) & M_MAC_MDIO_IN;
/*
* Issue an 'idle' clock pulse, but keep the direction
* the same.
*/
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc,
+ sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
regval = 0;
@@ -616,55 +514,60 @@ static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
regval <<= 1;
if (error == 0) {
- if (__raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN)
+ if (__raw_readq(sbm_mdio) & M_MAC_MDIO_IN)
regval |= 1;
}
- __raw_writeq(M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
- __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc,
+ sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
}
/* Switch back to output */
- __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio);
+ __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio);
if (error == 0)
return regval;
- return 0;
+ return 0xffff;
}
/**********************************************************************
- * SBMAC_MII_WRITE(s,phyaddr,regidx,regval)
+ * SBMAC_MII_WRITE(bus, phyaddr, regidx, regval)
*
* Write a value to a PHY register.
*
* Input parameters:
- * s - sbmac structure
+ * bus - MDIO bus handle
* phyaddr - PHY to use
- * regidx - register within the PHY
- * regval - data to write to register
+ * regidx - register within the PHY
+ * regval - data to write to register
*
* Return value:
- * nothing
+ * 0 for success
********************************************************************* */
-static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
- unsigned int regval)
+static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
+ u16 regval)
{
+ struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv;
+ void __iomem *sbm_mdio = sc->sbm_mdio;
int mac_mdio_genc;
- sbmac_mii_sync(s);
+ sbmac_mii_sync(sbm_mdio);
+
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2);
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_WRITE, 2);
+ sbmac_mii_senddata(sbm_mdio, phyaddr, 5);
+ sbmac_mii_senddata(sbm_mdio, regidx, 5);
+ sbmac_mii_senddata(sbm_mdio, MII_COMMAND_ACK, 2);
+ sbmac_mii_senddata(sbm_mdio, regval, 16);
- sbmac_mii_senddata(s,MII_COMMAND_START,2);
- sbmac_mii_senddata(s,MII_COMMAND_WRITE,2);
- sbmac_mii_senddata(s,phyaddr, 5);
- sbmac_mii_senddata(s,regidx, 5);
- sbmac_mii_senddata(s,MII_COMMAND_ACK,2);
- sbmac_mii_senddata(s,regval,16);
+ mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
- mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+ __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio);
- __raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio);
+ return 0;
}
@@ -677,8 +580,8 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
* way.
*
* Input parameters:
- * d - sbmacdma_t structure (DMA channel context)
- * s - sbmac_softc structure (pointer to a MAC)
+ * d - struct sbmacdma (DMA channel context)
+ * s - struct sbmac_softc (pointer to a MAC)
* chan - channel number (0..1 right now)
* txrx - Identifies DMA_TX or DMA_RX for channel direction
* maxdescr - number of descriptors
@@ -687,11 +590,8 @@ static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
* nothing
********************************************************************* */
-static void sbdma_initctx(sbmacdma_t *d,
- struct sbmac_softc *s,
- int chan,
- int txrx,
- int maxdescr)
+static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan,
+ int txrx, int maxdescr)
{
#ifdef CONFIG_SBMAC_COALESCE
int int_pktcnt, int_timeout;
@@ -710,27 +610,27 @@ static void sbdma_initctx(sbmacdma_t *d,
s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING;
#endif
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR)));
- __raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR)));
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BYTES);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_COLLISIONS);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_LATE_COL);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_EX_COL);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_FCS_ERROR);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_ABORT);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BAD);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_GOOD);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_RUNT);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_OVERSIZE);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BYTES);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_MCAST);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BCAST);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BAD);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_GOOD);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_RUNT);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_OVERSIZE);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_FCS_ERROR);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_LENGTH_ERROR);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_CODE_ERROR);
+ __raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_ALIGN_ERROR);
/*
* initialize register pointers
@@ -758,18 +658,17 @@ static void sbdma_initctx(sbmacdma_t *d,
d->sbdma_maxdescr = maxdescr;
- d->sbdma_dscrtable_unaligned =
- d->sbdma_dscrtable = (sbdmadscr_t *)
- kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL);
+ d->sbdma_dscrtable_unaligned = kcalloc(d->sbdma_maxdescr + 1,
+ sizeof(*d->sbdma_dscrtable),
+ GFP_KERNEL);
/*
* The descriptor table must be aligned to at least 16 bytes or the
* MAC will corrupt it.
*/
- d->sbdma_dscrtable = (sbdmadscr_t *)
- ALIGN((unsigned long)d->sbdma_dscrtable, sizeof(sbdmadscr_t));
-
- memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t));
+ d->sbdma_dscrtable = (struct sbdmadscr *)
+ ALIGN((unsigned long)d->sbdma_dscrtable_unaligned,
+ sizeof(*d->sbdma_dscrtable));
d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr;
@@ -779,10 +678,8 @@ static void sbdma_initctx(sbmacdma_t *d,
* And context table
*/
- d->sbdma_ctxtable = (struct sk_buff **)
- kmalloc(d->sbdma_maxdescr*sizeof(struct sk_buff *), GFP_KERNEL);
-
- memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *));
+ d->sbdma_ctxtable = kcalloc(d->sbdma_maxdescr,
+ sizeof(*d->sbdma_ctxtable), GFP_KERNEL);
#ifdef CONFIG_SBMAC_COALESCE
/*
@@ -819,7 +716,7 @@ static void sbdma_initctx(sbmacdma_t *d,
* nothing
********************************************************************* */
-static void sbdma_channel_start(sbmacdma_t *d, int rxtx )
+static void sbdma_channel_start(struct sbmacdma *d, int rxtx)
{
/*
* Turn on the DMA channel
@@ -860,7 +757,7 @@ static void sbdma_channel_start(sbmacdma_t *d, int rxtx )
* nothing
********************************************************************* */
-static void sbdma_channel_stop(sbmacdma_t *d)
+static void sbdma_channel_stop(struct sbmacdma *d)
{
/*
* Turn off the DMA channel
@@ -909,10 +806,10 @@ static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset)
********************************************************************* */
-static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
+static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb)
{
- sbdmadscr_t *dsc;
- sbdmadscr_t *nextdsc;
+ struct sbdmadscr *dsc;
+ struct sbdmadscr *nextdsc;
struct sk_buff *sb_new = NULL;
int pktsize = ENET_PACKET_SIZE;
@@ -953,7 +850,7 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
if (sb == NULL) {
sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN);
if (sb_new == NULL) {
- printk(KERN_INFO "%s: sk_buff allocation failed\n",
+ pr_info("%s: sk_buff allocation failed\n",
d->sbdma_eth->sbm_dev->name);
return -ENOBUFS;
}
@@ -1024,10 +921,10 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
********************************************************************* */
-static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb)
+static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *sb)
{
- sbdmadscr_t *dsc;
- sbdmadscr_t *nextdsc;
+ struct sbdmadscr *dsc;
+ struct sbdmadscr *nextdsc;
uint64_t phys;
uint64_t ncb;
int length;
@@ -1113,7 +1010,7 @@ static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb)
* nothing
********************************************************************* */
-static void sbdma_emptyring(sbmacdma_t *d)
+static void sbdma_emptyring(struct sbmacdma *d)
{
int idx;
struct sk_buff *sb;
@@ -1141,7 +1038,7 @@ static void sbdma_emptyring(sbmacdma_t *d)
* nothing
********************************************************************* */
-static void sbdma_fillring(sbmacdma_t *d)
+static void sbdma_fillring(struct sbmacdma *d)
{
int idx;
@@ -1188,12 +1085,13 @@ static void sbmac_netpoll(struct net_device *netdev)
* nothing
********************************************************************* */
-static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d,
- int work_to_do, int poll)
+static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d,
+ int work_to_do, int poll)
{
+ struct net_device *dev = sc->sbm_dev;
int curidx;
int hwidx;
- sbdmadscr_t *dsc;
+ struct sbdmadscr *dsc;
struct sk_buff *sb;
int len;
int work_done = 0;
@@ -1203,7 +1101,7 @@ static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d,
again:
/* Check if the HW dropped any frames */
- sc->sbm_stats.rx_fifo_errors
+ dev->stats.rx_fifo_errors
+= __raw_readq(sc->sbm_rxdma.sbdma_oodpktlost) & 0xffff;
__raw_writeq(0, sc->sbm_rxdma.sbdma_oodpktlost);
@@ -1225,8 +1123,9 @@ again:
prefetch(dsc);
prefetch(&d->sbdma_ctxtable[curidx]);
- hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
- d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+ hwidx = ((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+ d->sbdma_dscrtable_phys) /
+ sizeof(*d->sbdma_dscrtable);
/*
* If they're the same, that means we've processed all
@@ -1262,7 +1161,7 @@ again:
if (unlikely (sbdma_add_rcvbuffer(d,NULL) ==
-ENOBUFS)) {
- sc->sbm_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */
/* No point in continuing at the moment */
printk(KERN_ERR "dropped packet (1)\n");
@@ -1298,13 +1197,13 @@ again:
dropped = netif_rx(sb);
if (dropped == NET_RX_DROP) {
- sc->sbm_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
goto done;
}
else {
- sc->sbm_stats.rx_bytes += len;
- sc->sbm_stats.rx_packets++;
+ dev->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
}
}
} else {
@@ -1312,7 +1211,7 @@ again:
* Packet was mangled somehow. Just drop it and
* put it back on the receive ring.
*/
- sc->sbm_stats.rx_errors++;
+ dev->stats.rx_errors++;
sbdma_add_rcvbuffer(d,sb);
}
@@ -1350,11 +1249,13 @@ done:
* nothing
********************************************************************* */
-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll)
+static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d,
+ int poll)
{
+ struct net_device *dev = sc->sbm_dev;
int curidx;
int hwidx;
- sbdmadscr_t *dsc;
+ struct sbdmadscr *dsc;
struct sk_buff *sb;
unsigned long flags;
int packets_handled = 0;
@@ -1364,8 +1265,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll)
if (d->sbdma_remptr == d->sbdma_addptr)
goto end_unlock;
- hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
- d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+ hwidx = ((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+ d->sbdma_dscrtable_phys) / sizeof(*d->sbdma_dscrtable);
for (;;) {
/*
@@ -1402,8 +1303,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll)
* Stats
*/
- sc->sbm_stats.tx_bytes += sb->len;
- sc->sbm_stats.tx_packets++;
+ dev->stats.tx_bytes += sb->len;
+ dev->stats.tx_packets++;
/*
* for transmits, we just free buffers.
@@ -1468,14 +1369,6 @@ static int sbmac_initctx(struct sbmac_softc *s)
s->sbm_imr = s->sbm_base + R_MAC_INT_MASK;
s->sbm_mdio = s->sbm_base + R_MAC_MDIO;
- s->sbm_phys[0] = 1;
- s->sbm_phys[1] = 0;
-
- s->sbm_phy_oldbmsr = 0;
- s->sbm_phy_oldanlpar = 0;
- s->sbm_phy_oldk1stsr = 0;
- s->sbm_phy_oldlinkstat = 0;
-
/*
* Initialize the DMA channels. Right now, only one per MAC is used
* Note: Only do this _once_, as it allocates memory from the kernel!
@@ -1490,19 +1383,11 @@ static int sbmac_initctx(struct sbmac_softc *s)
s->sbm_state = sbmac_state_off;
- /*
- * Initial speed is (XXX TEMP) 10MBit/s HDX no FC
- */
-
- s->sbm_speed = sbmac_speed_10;
- s->sbm_duplex = sbmac_duplex_half;
- s->sbm_fc = sbmac_fc_disabled;
-
return 0;
}
-static void sbdma_uninitctx(struct sbmacdma_s *d)
+static void sbdma_uninitctx(struct sbmacdma *d)
{
if (d->sbdma_dscrtable_unaligned) {
kfree(d->sbdma_dscrtable_unaligned);
@@ -1538,7 +1423,7 @@ static void sbmac_uninitctx(struct sbmac_softc *sc)
static void sbmac_channel_start(struct sbmac_softc *s)
{
uint64_t reg;
- volatile void __iomem *port;
+ void __iomem *port;
uint64_t cfg,fifo,framecfg;
int idx, th_value;
@@ -1801,10 +1686,10 @@ static void sbmac_channel_stop(struct sbmac_softc *s)
* Return value:
* old state
********************************************************************* */
-static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc,
- sbmac_state_t state)
+static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *sc,
+ enum sbmac_state state)
{
- sbmac_state_t oldstate = sc->sbm_state;
+ enum sbmac_state oldstate = sc->sbm_state;
/*
* If same as previous state, return
@@ -1939,14 +1824,14 @@ static uint64_t sbmac_addr2reg(unsigned char *ptr)
*
* Input parameters:
* s - sbmac structure
- * speed - speed to set MAC to (see sbmac_speed_t enum)
+ * speed - speed to set MAC to (see enum sbmac_speed)
*
* Return value:
* 1 if successful
* 0 indicates invalid parameters
********************************************************************* */
-static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
+static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed)
{
uint64_t cfg;
uint64_t framecfg;
@@ -2004,8 +1889,6 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN;
break;
- case sbmac_speed_auto: /* XXX not implemented */
- /* fall through */
default:
return 0;
}
@@ -2028,15 +1911,16 @@ static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
*
* Input parameters:
* s - sbmac structure
- * duplex - duplex setting (see sbmac_duplex_t)
- * fc - flow control setting (see sbmac_fc_t)
+ * duplex - duplex setting (see enum sbmac_duplex)
+ * fc - flow control setting (see enum sbmac_fc)
*
* Return value:
* 1 if ok
* 0 if an invalid parameter combination was specified
********************************************************************* */
-static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc)
+static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex,
+ enum sbmac_fc fc)
{
uint64_t cfg;
@@ -2078,8 +1962,6 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc
cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR;
break;
- case sbmac_fc_auto: /* XXX not implemented */
- /* fall through */
case sbmac_fc_frame: /* not valid in half duplex */
default: /* invalid selection */
return 0;
@@ -2098,15 +1980,12 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc
case sbmac_fc_collision: /* not valid in full duplex */
case sbmac_fc_carrier: /* not valid in full duplex */
- case sbmac_fc_auto: /* XXX not implemented */
- /* fall through */
default:
return 0;
}
break;
- case sbmac_duplex_auto:
- /* XXX not implemented */
- break;
+ default:
+ return 0;
}
/*
@@ -2154,20 +2033,13 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance)
* Transmits on channel 0
*/
- if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
+ if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0))
sbdma_tx_process(sc,&(sc->sbm_txdma), 0);
-#ifdef CONFIG_NETPOLL_TRAP
- if (netpoll_trap()) {
- if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
- __netif_schedule(dev);
- }
-#endif
- }
if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &sc->napi)) {
__raw_writeq(0, sc->sbm_imr);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &sc->napi);
/* Depend on the exit from poll to reenable intr */
}
else {
@@ -2236,7 +2108,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
static void sbmac_setmulti(struct sbmac_softc *sc)
{
uint64_t reg;
- volatile void __iomem *port;
+ void __iomem *port;
int idx;
struct dev_mc_list *mclist;
struct net_device *dev = sc->sbm_dev;
@@ -2392,7 +2264,7 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu)
if (new_mtu > ENET_PACKET_SIZE)
return -EINVAL;
_dev->mtu = new_mtu;
- printk(KERN_INFO "changing the mtu to %d\n", new_mtu);
+ pr_info("changing the mtu to %d\n", new_mtu);
return 0;
}
@@ -2408,19 +2280,17 @@ static int sb1250_change_mtu(struct net_device *_dev, int new_mtu)
* status
********************************************************************* */
-static int sbmac_init(struct net_device *dev, int idx)
+static int sbmac_init(struct platform_device *pldev, long long base)
{
- struct sbmac_softc *sc;
+ struct net_device *dev = pldev->dev.driver_data;
+ int idx = pldev->id;
+ struct sbmac_softc *sc = netdev_priv(dev);
unsigned char *eaddr;
uint64_t ea_reg;
int i;
int err;
+ DECLARE_MAC_BUF(mac);
- sc = netdev_priv(dev);
-
- /* Determine controller base address */
-
- sc->sbm_base = IOADDR(dev->base_addr);
sc->sbm_dev = dev;
sc->sbe_idx = idx;
@@ -2465,58 +2335,67 @@ static int sbmac_init(struct net_device *dev, int idx)
dev->open = sbmac_open;
dev->hard_start_xmit = sbmac_start_tx;
dev->stop = sbmac_close;
- dev->get_stats = sbmac_get_stats;
dev->set_multicast_list = sbmac_set_rx_mode;
dev->do_ioctl = sbmac_mii_ioctl;
dev->tx_timeout = sbmac_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
- dev->poll = sbmac_poll;
- dev->weight = 16;
+
+ netif_napi_add(dev, &sc->napi, sbmac_poll, 16);
dev->change_mtu = sb1250_change_mtu;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = sbmac_netpoll;
#endif
+ dev->irq = UNIT_INT(idx);
+
/* This is needed for PASS2 for Rx H/W checksum feature */
sbmac_set_iphdr_offset(sc);
err = register_netdev(dev);
- if (err)
- goto out_uninit;
-
- if (sc->rx_hw_checksum == ENABLE) {
- printk(KERN_INFO "%s: enabling TCP rcv checksum\n",
- sc->sbm_dev->name);
+ if (err) {
+ printk(KERN_ERR "%s.%d: unable to register netdev\n",
+ sbmac_string, idx);
+ sbmac_uninitctx(sc);
+ return err;
}
+ pr_info("%s.%d: registered as %s\n", sbmac_string, idx, dev->name);
+
+ if (sc->rx_hw_checksum == ENABLE)
+ pr_info("%s: enabling TCP rcv checksum\n", dev->name);
+
/*
* Display Ethernet address (this is called during the config
* process so we need to finish off the config message that
* was being displayed)
*/
- printk(KERN_INFO
- "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n",
- dev->name, dev->base_addr,
- eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]);
-
+ pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %s\n",
+ dev->name, base, print_mac(mac, eaddr));
- return 0;
+ sc->mii_bus.name = sbmac_mdio_string;
+ sc->mii_bus.id = idx;
+ sc->mii_bus.priv = sc;
+ sc->mii_bus.read = sbmac_mii_read;
+ sc->mii_bus.write = sbmac_mii_write;
+ sc->mii_bus.irq = sc->phy_irq;
+ for (i = 0; i < PHY_MAX_ADDR; ++i)
+ sc->mii_bus.irq[i] = SBMAC_PHY_INT;
-out_uninit:
- sbmac_uninitctx(sc);
+ sc->mii_bus.dev = &pldev->dev;
+ dev_set_drvdata(&pldev->dev, &sc->mii_bus);
- return err;
+ return 0;
}
static int sbmac_open(struct net_device *dev)
{
struct sbmac_softc *sc = netdev_priv(dev);
+ int err;
- if (debug > 1) {
- printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq);
- }
+ if (debug > 1)
+ pr_debug("%s: sbmac_open() irq %d.\n", dev->name, dev->irq);
/*
* map/route interrupt (clear status first, in case something
@@ -2525,23 +2404,35 @@ static int sbmac_open(struct net_device *dev)
*/
__raw_readq(sc->sbm_isr);
- if (request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev))
- return -EBUSY;
+ err = request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev);
+ if (err) {
+ printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name,
+ dev->irq);
+ goto out_err;
+ }
/*
- * Probe phy address
+ * Probe PHY address
*/
-
- if(sbmac_mii_probe(dev) == -1) {
- printk("%s: failed to probe PHY.\n", dev->name);
- return -EINVAL;
+ err = mdiobus_register(&sc->mii_bus);
+ if (err) {
+ printk(KERN_ERR "%s: unable to register MDIO bus\n",
+ dev->name);
+ goto out_unirq;
}
+ sc->sbm_speed = sbmac_speed_none;
+ sc->sbm_duplex = sbmac_duplex_none;
+ sc->sbm_fc = sbmac_fc_none;
+ sc->sbm_pause = -1;
+ sc->sbm_link = 0;
+
/*
- * Configure default speed
+ * Attach to the PHY
*/
-
- sbmac_mii_poll(sc,noisy_mii);
+ err = sbmac_mii_probe(dev);
+ if (err)
+ goto out_unregister;
/*
* Turn on the channel
@@ -2549,200 +2440,133 @@ static int sbmac_open(struct net_device *dev)
sbmac_set_channel_state(sc,sbmac_state_on);
- /*
- * XXX Station address is in dev->dev_addr
- */
-
- if (dev->if_port == 0)
- dev->if_port = 0;
-
netif_start_queue(dev);
sbmac_set_rx_mode(dev);
- /* Set the timer to check for link beat. */
- init_timer(&sc->sbm_timer);
- sc->sbm_timer.expires = jiffies + 2 * HZ/100;
- sc->sbm_timer.data = (unsigned long)dev;
- sc->sbm_timer.function = &sbmac_timer;
- add_timer(&sc->sbm_timer);
+ phy_start(sc->phy_dev);
+
+ napi_enable(&sc->napi);
return 0;
+
+out_unregister:
+ mdiobus_unregister(&sc->mii_bus);
+
+out_unirq:
+ free_irq(dev->irq, dev);
+
+out_err:
+ return err;
}
static int sbmac_mii_probe(struct net_device *dev)
{
+ struct sbmac_softc *sc = netdev_priv(dev);
+ struct phy_device *phy_dev;
int i;
- struct sbmac_softc *s = netdev_priv(dev);
- u16 bmsr, id1, id2;
- u32 vendor, device;
-
- for (i=1; i<31; i++) {
- bmsr = sbmac_mii_read(s, i, MII_BMSR);
- if (bmsr != 0) {
- s->sbm_phys[0] = i;
- id1 = sbmac_mii_read(s, i, MII_PHYIDR1);
- id2 = sbmac_mii_read(s, i, MII_PHYIDR2);
- vendor = ((u32)id1 << 6) | ((id2 >> 10) & 0x3f);
- device = (id2 >> 4) & 0x3f;
-
- printk(KERN_INFO "%s: found phy %d, vendor %06x part %02x\n",
- dev->name, i, vendor, device);
- return i;
- }
- }
- return -1;
-}
-
-
-static int sbmac_mii_poll(struct sbmac_softc *s,int noisy)
-{
- int bmsr,bmcr,k1stsr,anlpar;
- int chg;
- char buffer[100];
- char *p = buffer;
- /* Read the mode status and mode control registers. */
- bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR);
- bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR);
-
- /* get the link partner status */
- anlpar = sbmac_mii_read(s,s->sbm_phys[0],MII_ANLPAR);
-
- /* if supported, read the 1000baseT register */
- if (bmsr & BMSR_1000BT_XSR) {
- k1stsr = sbmac_mii_read(s,s->sbm_phys[0],MII_K1STSR);
- }
- else {
- k1stsr = 0;
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ phy_dev = sc->mii_bus.phy_map[i];
+ if (phy_dev)
+ break;
}
-
- chg = 0;
-
- if ((bmsr & BMSR_LINKSTAT) == 0) {
- /*
- * If link status is down, clear out old info so that when
- * it comes back up it will force us to reconfigure speed
- */
- s->sbm_phy_oldbmsr = 0;
- s->sbm_phy_oldanlpar = 0;
- s->sbm_phy_oldk1stsr = 0;
- return 0;
+ if (!phy_dev) {
+ printk(KERN_ERR "%s: no PHY found\n", dev->name);
+ return -ENXIO;
}
- if ((s->sbm_phy_oldbmsr != bmsr) ||
- (s->sbm_phy_oldanlpar != anlpar) ||
- (s->sbm_phy_oldk1stsr != k1stsr)) {
- if (debug > 1) {
- printk(KERN_DEBUG "%s: bmsr:%x/%x anlpar:%x/%x k1stsr:%x/%x\n",
- s->sbm_dev->name,
- s->sbm_phy_oldbmsr,bmsr,
- s->sbm_phy_oldanlpar,anlpar,
- s->sbm_phy_oldk1stsr,k1stsr);
- }
- s->sbm_phy_oldbmsr = bmsr;
- s->sbm_phy_oldanlpar = anlpar;
- s->sbm_phy_oldk1stsr = k1stsr;
- chg = 1;
+ phy_dev = phy_connect(dev, phy_dev->dev.bus_id, &sbmac_mii_poll, 0,
+ PHY_INTERFACE_MODE_GMII);
+ if (IS_ERR(phy_dev)) {
+ printk(KERN_ERR "%s: could not attach to PHY\n", dev->name);
+ return PTR_ERR(phy_dev);
}
- if (chg == 0)
- return 0;
+ /* Remove any features not supported by the controller */
+ phy_dev->supported &= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_MII |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause;
+ phy_dev->advertising = phy_dev->supported;
- p += sprintf(p,"Link speed: ");
-
- if (k1stsr & K1STSR_LP1KFD) {
- s->sbm_speed = sbmac_speed_1000;
- s->sbm_duplex = sbmac_duplex_full;
- s->sbm_fc = sbmac_fc_frame;
- p += sprintf(p,"1000BaseT FDX");
- }
- else if (k1stsr & K1STSR_LP1KHD) {
- s->sbm_speed = sbmac_speed_1000;
- s->sbm_duplex = sbmac_duplex_half;
- s->sbm_fc = sbmac_fc_disabled;
- p += sprintf(p,"1000BaseT HDX");
- }
- else if (anlpar & ANLPAR_TXFD) {
- s->sbm_speed = sbmac_speed_100;
- s->sbm_duplex = sbmac_duplex_full;
- s->sbm_fc = (anlpar & ANLPAR_PAUSE) ? sbmac_fc_frame : sbmac_fc_disabled;
- p += sprintf(p,"100BaseT FDX");
- }
- else if (anlpar & ANLPAR_TXHD) {
- s->sbm_speed = sbmac_speed_100;
- s->sbm_duplex = sbmac_duplex_half;
- s->sbm_fc = sbmac_fc_disabled;
- p += sprintf(p,"100BaseT HDX");
- }
- else if (anlpar & ANLPAR_10FD) {
- s->sbm_speed = sbmac_speed_10;
- s->sbm_duplex = sbmac_duplex_full;
- s->sbm_fc = sbmac_fc_frame;
- p += sprintf(p,"10BaseT FDX");
- }
- else if (anlpar & ANLPAR_10HD) {
- s->sbm_speed = sbmac_speed_10;
- s->sbm_duplex = sbmac_duplex_half;
- s->sbm_fc = sbmac_fc_collision;
- p += sprintf(p,"10BaseT HDX");
- }
- else {
- p += sprintf(p,"Unknown");
- }
+ pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+ dev->name, phy_dev->drv->name,
+ phy_dev->dev.bus_id, phy_dev->irq);
- if (noisy) {
- printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer);
- }
+ sc->phy_dev = phy_dev;
- return 1;
+ return 0;
}
-static void sbmac_timer(unsigned long data)
+static void sbmac_mii_poll(struct net_device *dev)
{
- struct net_device *dev = (struct net_device *)data;
struct sbmac_softc *sc = netdev_priv(dev);
- int next_tick = HZ;
- int mii_status;
+ struct phy_device *phy_dev = sc->phy_dev;
+ unsigned long flags;
+ enum sbmac_fc fc;
+ int link_chg, speed_chg, duplex_chg, pause_chg, fc_chg;
+
+ link_chg = (sc->sbm_link != phy_dev->link);
+ speed_chg = (sc->sbm_speed != phy_dev->speed);
+ duplex_chg = (sc->sbm_duplex != phy_dev->duplex);
+ pause_chg = (sc->sbm_pause != phy_dev->pause);
+
+ if (!link_chg && !speed_chg && !duplex_chg && !pause_chg)
+ return; /* Hmmm... */
+
+ if (!phy_dev->link) {
+ if (link_chg) {
+ sc->sbm_link = phy_dev->link;
+ sc->sbm_speed = sbmac_speed_none;
+ sc->sbm_duplex = sbmac_duplex_none;
+ sc->sbm_fc = sbmac_fc_disabled;
+ sc->sbm_pause = -1;
+ pr_info("%s: link unavailable\n", dev->name);
+ }
+ return;
+ }
- spin_lock_irq (&sc->sbm_lock);
+ if (phy_dev->duplex == DUPLEX_FULL) {
+ if (phy_dev->pause)
+ fc = sbmac_fc_frame;
+ else
+ fc = sbmac_fc_disabled;
+ } else
+ fc = sbmac_fc_collision;
+ fc_chg = (sc->sbm_fc != fc);
- /* make IFF_RUNNING follow the MII status bit "Link established" */
- mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR);
+ pr_info("%s: link available: %dbase-%cD\n", dev->name, phy_dev->speed,
+ phy_dev->duplex == DUPLEX_FULL ? 'F' : 'H');
- if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) {
- sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT;
- if (mii_status & BMSR_LINKSTAT) {
- netif_carrier_on(dev);
- }
- else {
- netif_carrier_off(dev);
- }
- }
+ spin_lock_irqsave(&sc->sbm_lock, flags);
- /*
- * Poll the PHY to see what speed we should be running at
- */
+ sc->sbm_speed = phy_dev->speed;
+ sc->sbm_duplex = phy_dev->duplex;
+ sc->sbm_fc = fc;
+ sc->sbm_pause = phy_dev->pause;
+ sc->sbm_link = phy_dev->link;
- if (sbmac_mii_poll(sc,noisy_mii)) {
- if (sc->sbm_state != sbmac_state_off) {
- /*
- * something changed, restart the channel
- */
- if (debug > 1) {
- printk("%s: restarting channel because speed changed\n",
- sc->sbm_dev->name);
- }
- sbmac_channel_stop(sc);
- sbmac_channel_start(sc);
- }
+ if ((speed_chg || duplex_chg || fc_chg) &&
+ sc->sbm_state != sbmac_state_off) {
+ /*
+ * something changed, restart the channel
+ */
+ if (debug > 1)
+ pr_debug("%s: restarting channel "
+ "because PHY state changed\n", dev->name);
+ sbmac_channel_stop(sc);
+ sbmac_channel_start(sc);
}
- spin_unlock_irq (&sc->sbm_lock);
-
- sc->sbm_timer.expires = jiffies + next_tick;
- add_timer(&sc->sbm_timer);
+ spin_unlock_irqrestore(&sc->sbm_lock, flags);
}
@@ -2754,7 +2578,7 @@ static void sbmac_tx_timeout (struct net_device *dev)
dev->trans_start = jiffies;
- sc->sbm_stats.tx_errors++;
+ dev->stats.tx_errors++;
spin_unlock_irq (&sc->sbm_lock);
@@ -2764,22 +2588,6 @@ static void sbmac_tx_timeout (struct net_device *dev)
-static struct net_device_stats *sbmac_get_stats(struct net_device *dev)
-{
- struct sbmac_softc *sc = netdev_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&sc->sbm_lock, flags);
-
- /* XXX update other stats here */
-
- spin_unlock_irqrestore(&sc->sbm_lock, flags);
-
- return &sc->sbm_stats;
-}
-
-
-
static void sbmac_set_rx_mode(struct net_device *dev)
{
unsigned long flags;
@@ -2811,62 +2619,34 @@ static void sbmac_set_rx_mode(struct net_device *dev)
static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct sbmac_softc *sc = netdev_priv(dev);
- u16 *data = (u16 *)&rq->ifr_ifru;
- unsigned long flags;
- int retval;
- spin_lock_irqsave(&sc->sbm_lock, flags);
- retval = 0;
-
- switch(cmd) {
- case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
- data[0] = sc->sbm_phys[0] & 0x1f;
- /* Fall Through */
- case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
- data[3] = sbmac_mii_read(sc, data[0] & 0x1f, data[1] & 0x1f);
- break;
- case SIOCDEVPRIVATE+2: /* Write the specified MII register */
- if (!capable(CAP_NET_ADMIN)) {
- retval = -EPERM;
- break;
- }
- if (debug > 1) {
- printk(KERN_DEBUG "%s: sbmac_mii_ioctl: write %02X %02X %02X\n",dev->name,
- data[0],data[1],data[2]);
- }
- sbmac_mii_write(sc, data[0] & 0x1f, data[1] & 0x1f, data[2]);
- break;
- default:
- retval = -EOPNOTSUPP;
- }
+ if (!netif_running(dev) || !sc->phy_dev)
+ return -EINVAL;
- spin_unlock_irqrestore(&sc->sbm_lock, flags);
- return retval;
+ return phy_mii_ioctl(sc->phy_dev, if_mii(rq), cmd);
}
static int sbmac_close(struct net_device *dev)
{
struct sbmac_softc *sc = netdev_priv(dev);
- unsigned long flags;
- int irq;
- sbmac_set_channel_state(sc,sbmac_state_off);
+ napi_disable(&sc->napi);
- del_timer_sync(&sc->sbm_timer);
+ phy_stop(sc->phy_dev);
- spin_lock_irqsave(&sc->sbm_lock, flags);
+ sbmac_set_channel_state(sc, sbmac_state_off);
netif_stop_queue(dev);
- if (debug > 1) {
- printk(KERN_DEBUG "%s: Shutting down ethercard\n",dev->name);
- }
+ if (debug > 1)
+ pr_debug("%s: Shutting down ethercard\n", dev->name);
- spin_unlock_irqrestore(&sc->sbm_lock, flags);
+ phy_disconnect(sc->phy_dev);
+ sc->phy_dev = NULL;
+
+ mdiobus_unregister(&sc->mii_bus);
- irq = dev->irq;
- synchronize_irq(irq);
- free_irq(irq, dev);
+ free_irq(dev->irq, dev);
sbdma_emptyring(&(sc->sbm_txdma));
sbdma_emptyring(&(sc->sbm_rxdma));
@@ -2874,26 +2654,17 @@ static int sbmac_close(struct net_device *dev)
return 0;
}
-static int sbmac_poll(struct net_device *dev, int *budget)
+static int sbmac_poll(struct napi_struct *napi, int budget)
{
- int work_to_do;
+ struct sbmac_softc *sc = container_of(napi, struct sbmac_softc, napi);
+ struct net_device *dev = sc->sbm_dev;
int work_done;
- struct sbmac_softc *sc = netdev_priv(dev);
-
- work_to_do = min(*budget, dev->quota);
- work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), work_to_do, 1);
-
- if (work_done > work_to_do)
- printk(KERN_ERR "%s exceeded work_to_do budget=%d quota=%d work-done=%d\n",
- sc->sbm_dev->name, *budget, dev->quota, work_done);
+ work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), budget, 1);
sbdma_tx_process(sc, &(sc->sbm_txdma), 1);
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (work_done < work_to_do) {
- netif_rx_complete(dev);
+ if (work_done < budget) {
+ netif_rx_complete(dev, napi);
#ifdef CONFIG_SBMAC_COALESCE
__raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
@@ -2905,57 +2676,198 @@ static int sbmac_poll(struct net_device *dev, int *budget)
#endif
}
- return (work_done >= work_to_do);
+ return work_done;
+}
+
+
+static int __init sbmac_probe(struct platform_device *pldev)
+{
+ struct net_device *dev;
+ struct sbmac_softc *sc;
+ void __iomem *sbm_base;
+ struct resource *res;
+ u64 sbmac_orig_hwaddr;
+ int err;
+
+ res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+ BUG_ON(!res);
+ sbm_base = ioremap_nocache(res->start, res->end - res->start + 1);
+ if (!sbm_base) {
+ printk(KERN_ERR "%s: unable to map device registers\n",
+ pldev->dev.bus_id);
+ err = -ENOMEM;
+ goto out_out;
+ }
+
+ /*
+ * The R_MAC_ETHERNET_ADDR register will be set to some nonzero
+ * value for us by the firmware if we're going to use this MAC.
+ * If we find a zero, skip this MAC.
+ */
+ sbmac_orig_hwaddr = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR);
+ pr_debug("%s: %sconfiguring MAC at 0x%08Lx\n", pldev->dev.bus_id,
+ sbmac_orig_hwaddr ? "" : "not ", (long long)res->start);
+ if (sbmac_orig_hwaddr == 0) {
+ err = 0;
+ goto out_unmap;
+ }
+
+ /*
+ * Okay, cool. Initialize this MAC.
+ */
+ dev = alloc_etherdev(sizeof(struct sbmac_softc));
+ if (!dev) {
+ printk(KERN_ERR "%s: unable to allocate etherdev\n",
+ pldev->dev.bus_id);
+ err = -ENOMEM;
+ goto out_unmap;
+ }
+
+ pldev->dev.driver_data = dev;
+ SET_NETDEV_DEV(dev, &pldev->dev);
+
+ sc = netdev_priv(dev);
+ sc->sbm_base = sbm_base;
+
+ err = sbmac_init(pldev, res->start);
+ if (err)
+ goto out_kfree;
+
+ return 0;
+
+out_kfree:
+ free_netdev(dev);
+ __raw_writeq(sbmac_orig_hwaddr, sbm_base + R_MAC_ETHERNET_ADDR);
+
+out_unmap:
+ iounmap(sbm_base);
+
+out_out:
+ return err;
+}
+
+static int __exit sbmac_remove(struct platform_device *pldev)
+{
+ struct net_device *dev = pldev->dev.driver_data;
+ struct sbmac_softc *sc = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ sbmac_uninitctx(sc);
+ iounmap(sc->sbm_base);
+ free_netdev(dev);
+
+ return 0;
}
+
+static struct platform_device **sbmac_pldev;
+static int sbmac_max_units;
+
#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
-static void
-sbmac_setup_hwaddr(int chan,char *addr)
+static void __init sbmac_setup_hwaddr(int idx, char *addr)
{
+ void __iomem *sbm_base;
+ unsigned long start, end;
uint8_t eaddr[6];
uint64_t val;
- unsigned long port;
- port = A_MAC_CHANNEL_BASE(chan);
- sbmac_parse_hwaddr(addr,eaddr);
+ if (idx >= sbmac_max_units)
+ return;
+
+ start = A_MAC_CHANNEL_BASE(idx);
+ end = A_MAC_CHANNEL_BASE(idx + 1) - 1;
+
+ sbm_base = ioremap_nocache(start, end - start + 1);
+ if (!sbm_base) {
+ printk(KERN_ERR "%s: unable to map device registers\n",
+ sbmac_string);
+ return;
+ }
+
+ sbmac_parse_hwaddr(addr, eaddr);
val = sbmac_addr2reg(eaddr);
- __raw_writeq(val, IOADDR(port+R_MAC_ETHERNET_ADDR));
- val = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR));
+ __raw_writeq(val, sbm_base + R_MAC_ETHERNET_ADDR);
+ val = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR);
+
+ iounmap(sbm_base);
}
#endif
-static struct net_device *dev_sbmac[MAX_UNITS];
+static int __init sbmac_platform_probe_one(int idx)
+{
+ struct platform_device *pldev;
+ struct {
+ struct resource r;
+ char name[strlen(sbmac_pretty) + 4];
+ } *res;
+ int err;
+
+ res = kzalloc(sizeof(*res), GFP_KERNEL);
+ if (!res) {
+ printk(KERN_ERR "%s.%d: unable to allocate memory\n",
+ sbmac_string, idx);
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ /*
+ * This is the base address of the MAC.
+ */
+ snprintf(res->name, sizeof(res->name), "%s %d", sbmac_pretty, idx);
+ res->r.name = res->name;
+ res->r.flags = IORESOURCE_MEM;
+ res->r.start = A_MAC_CHANNEL_BASE(idx);
+ res->r.end = A_MAC_CHANNEL_BASE(idx + 1) - 1;
+
+ pldev = platform_device_register_simple(sbmac_string, idx, &res->r, 1);
+ if (IS_ERR(pldev)) {
+ printk(KERN_ERR "%s.%d: unable to register platform device\n",
+ sbmac_string, idx);
+ err = PTR_ERR(pldev);
+ goto out_kfree;
+ }
+
+ if (!pldev->dev.driver) {
+ err = 0; /* No hardware at this address. */
+ goto out_unregister;
+ }
+
+ sbmac_pldev[idx] = pldev;
+ return 0;
+
+out_unregister:
+ platform_device_unregister(pldev);
+
+out_kfree:
+ kfree(res);
+
+out_err:
+ return err;
+}
-static int __init
-sbmac_init_module(void)
+static void __init sbmac_platform_probe(void)
{
- int idx;
- struct net_device *dev;
- unsigned long port;
- int chip_max_units;
+ int i;
/* Set the number of available units based on the SOC type. */
switch (soc_type) {
case K_SYS_SOC_TYPE_BCM1250:
case K_SYS_SOC_TYPE_BCM1250_ALT:
- chip_max_units = 3;
+ sbmac_max_units = 3;
break;
case K_SYS_SOC_TYPE_BCM1120:
case K_SYS_SOC_TYPE_BCM1125:
case K_SYS_SOC_TYPE_BCM1125H:
- case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */
- chip_max_units = 2;
+ case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */
+ sbmac_max_units = 2;
break;
case K_SYS_SOC_TYPE_BCM1x55:
case K_SYS_SOC_TYPE_BCM1x80:
- chip_max_units = 4;
+ sbmac_max_units = 4;
break;
default:
- chip_max_units = 0;
- break;
+ return; /* none */
}
- if (chip_max_units > MAX_UNITS)
- chip_max_units = MAX_UNITS;
/*
* For bringup when not using the firmware, we can pre-fill
@@ -2963,89 +2875,71 @@ sbmac_init_module(void)
* specified in this file (or maybe from the config file?)
*/
#ifdef SBMAC_ETH0_HWADDR
- if (chip_max_units > 0)
- sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR);
+ sbmac_setup_hwaddr(0, SBMAC_ETH0_HWADDR);
#endif
#ifdef SBMAC_ETH1_HWADDR
- if (chip_max_units > 1)
- sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR);
+ sbmac_setup_hwaddr(1, SBMAC_ETH1_HWADDR);
#endif
#ifdef SBMAC_ETH2_HWADDR
- if (chip_max_units > 2)
- sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR);
+ sbmac_setup_hwaddr(2, SBMAC_ETH2_HWADDR);
#endif
#ifdef SBMAC_ETH3_HWADDR
- if (chip_max_units > 3)
- sbmac_setup_hwaddr(3,SBMAC_ETH3_HWADDR);
+ sbmac_setup_hwaddr(3, SBMAC_ETH3_HWADDR);
#endif
+ sbmac_pldev = kcalloc(sbmac_max_units, sizeof(*sbmac_pldev),
+ GFP_KERNEL);
+ if (!sbmac_pldev) {
+ printk(KERN_ERR "%s: unable to allocate memory\n",
+ sbmac_string);
+ return;
+ }
+
/*
* Walk through the Ethernet controllers and find
* those who have their MAC addresses set.
*/
- for (idx = 0; idx < chip_max_units; idx++) {
+ for (i = 0; i < sbmac_max_units; i++)
+ if (sbmac_platform_probe_one(i))
+ break;
+}
- /*
- * This is the base address of the MAC.
- */
- port = A_MAC_CHANNEL_BASE(idx);
+static void __exit sbmac_platform_cleanup(void)
+{
+ int i;
- /*
- * The R_MAC_ETHERNET_ADDR register will be set to some nonzero
- * value for us by the firmware if we are going to use this MAC.
- * If we find a zero, skip this MAC.
- */
+ for (i = 0; i < sbmac_max_units; i++)
+ platform_device_unregister(sbmac_pldev[i]);
+ kfree(sbmac_pldev);
+}
- sbmac_orig_hwaddr[idx] = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR));
- if (sbmac_orig_hwaddr[idx] == 0) {
- printk(KERN_DEBUG "sbmac: not configuring MAC at "
- "%lx\n", port);
- continue;
- }
- /*
- * Okay, cool. Initialize this MAC.
- */
+static struct platform_driver sbmac_driver = {
+ .probe = sbmac_probe,
+ .remove = __exit_p(sbmac_remove),
+ .driver = {
+ .name = sbmac_string,
+ },
+};
- dev = alloc_etherdev(sizeof(struct sbmac_softc));
- if (!dev)
- return -ENOMEM;
+static int __init sbmac_init_module(void)
+{
+ int err;
- printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port);
+ err = platform_driver_register(&sbmac_driver);
+ if (err)
+ return err;
- dev->irq = UNIT_INT(idx);
- dev->base_addr = port;
- dev->mem_end = 0;
- if (sbmac_init(dev, idx)) {
- port = A_MAC_CHANNEL_BASE(idx);
- __raw_writeq(sbmac_orig_hwaddr[idx], IOADDR(port+R_MAC_ETHERNET_ADDR));
- free_netdev(dev);
- continue;
- }
- dev_sbmac[idx] = dev;
- }
- return 0;
-}
+ sbmac_platform_probe();
+ return err;
+}
-static void __exit
-sbmac_cleanup_module(void)
+static void __exit sbmac_cleanup_module(void)
{
- struct net_device *dev;
- int idx;
-
- for (idx = 0; idx < MAX_UNITS; idx++) {
- struct sbmac_softc *sc;
- dev = dev_sbmac[idx];
- if (!dev)
- continue;
-
- sc = netdev_priv(dev);
- unregister_netdev(dev);
- sbmac_uninitctx(sc);
- free_netdev(dev);
- }
+ sbmac_platform_cleanup();
+ platform_driver_unregister(&sbmac_driver);
}
module_init(sbmac_init_module);
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
index 872cb1cc9c4..37b42394560 100644
--- a/drivers/net/sc92031.c
+++ b/drivers/net/sc92031.c
@@ -1372,9 +1372,14 @@ static void sc92031_ethtool_get_strings(struct net_device *dev,
SILAN_STATS_NUM * ETH_GSTRING_LEN);
}
-static int sc92031_ethtool_get_stats_count(struct net_device *dev)
+static int sc92031_ethtool_get_sset_count(struct net_device *dev, int sset)
{
- return SILAN_STATS_NUM;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return SILAN_STATS_NUM;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev,
@@ -1396,13 +1401,9 @@ static struct ethtool_ops sc92031_ethtool_ops = {
.set_wol = sc92031_ethtool_set_wol,
.nway_reset = sc92031_ethtool_nway_reset,
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .get_tso = ethtool_op_get_tso,
.get_strings = sc92031_ethtool_get_strings,
- .get_stats_count = sc92031_ethtool_get_stats_count,
+ .get_sset_count = sc92031_ethtool_get_sset_count,
.get_ethtool_stats = sc92031_ethtool_get_ethtool_stats,
- .get_ufo = ethtool_op_get_ufo,
};
static int __devinit sc92031_probe(struct pci_dev *pdev,
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index 4bce7c4f373..48c64fb20ee 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -67,7 +67,6 @@ static unsigned int net_debug = NET_DEBUG;
/* Information that need to be kept for each board. */
struct net_local {
- struct net_device_stats stats;
unsigned short receive_ptr; /* What address in packet memory do we expect a recv_pkt_header? */
long open_time; /* Useless example local info. */
};
@@ -86,7 +85,6 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t seeq8005_interrupt(int irq, void *dev_id);
static void seeq8005_rx(struct net_device *dev);
static int seeq8005_close(struct net_device *dev);
-static struct net_device_stats *seeq8005_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
/* Example routines you must write ;->. */
@@ -160,6 +158,7 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
int old_dmaar;
int old_rear;
int retval;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005"))
return -ENODEV;
@@ -303,7 +302,8 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
/* Retrieve and print the ethernet address. */
for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i] = SA_prom[i+6]);
+ dev->dev_addr[i] = SA_prom[i+6];
+ printk("%s", print_mac(mac, dev->dev_addr));
if (dev->irq == 0xff)
; /* Do nothing: a user-level program will set it. */
@@ -338,7 +338,6 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
dev->hard_start_xmit = seeq8005_send_packet;
dev->tx_timeout = seeq8005_timeout;
dev->watchdog_timeo = HZ/20;
- dev->get_stats = seeq8005_get_stats;
dev->set_multicast_list = set_multicast_list;
dev->flags &= ~IFF_MULTICAST;
@@ -391,7 +390,6 @@ static void seeq8005_timeout(struct net_device *dev)
static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
{
- struct net_local *lp = netdev_priv(dev);
short length = skb->len;
unsigned char *buf;
@@ -407,7 +405,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
hardware_send_packet(dev, buf, length);
dev->trans_start = jiffies;
- lp->stats.tx_bytes += length;
+ dev->stats.tx_bytes += length;
dev_kfree_skb (skb);
/* You might need to clean up and record Tx statistics here. */
@@ -463,7 +461,7 @@ static irqreturn_t seeq8005_interrupt(int irq, void *dev_id)
if (status & SEEQSTAT_TX_INT) {
handled = 1;
outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
netif_wake_queue(dev); /* Inform upper layers. */
}
if (status & SEEQSTAT_RX_INT) {
@@ -531,11 +529,11 @@ static void seeq8005_rx(struct net_device *dev)
}
if (pkt_hdr & SEEQPKTS_ANY_ERROR) { /* There was an error. */
- lp->stats.rx_errors++;
- if (pkt_hdr & SEEQPKTS_SHORT) lp->stats.rx_frame_errors++;
- if (pkt_hdr & SEEQPKTS_DRIB) lp->stats.rx_frame_errors++;
- if (pkt_hdr & SEEQPKTS_OVERSIZE) lp->stats.rx_over_errors++;
- if (pkt_hdr & SEEQPKTS_CRC_ERR) lp->stats.rx_crc_errors++;
+ dev->stats.rx_errors++;
+ if (pkt_hdr & SEEQPKTS_SHORT) dev->stats.rx_frame_errors++;
+ if (pkt_hdr & SEEQPKTS_DRIB) dev->stats.rx_frame_errors++;
+ if (pkt_hdr & SEEQPKTS_OVERSIZE) dev->stats.rx_over_errors++;
+ if (pkt_hdr & SEEQPKTS_CRC_ERR) dev->stats.rx_crc_errors++;
/* skip over this packet */
outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA);
@@ -547,7 +545,7 @@ static void seeq8005_rx(struct net_device *dev)
skb = dev_alloc_skb(pkt_len);
if (skb == NULL) {
printk("%s: Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
skb_reserve(skb, 2); /* align data on 16 byte */
@@ -567,8 +565,8 @@ static void seeq8005_rx(struct net_device *dev)
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
} while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
@@ -599,15 +597,6 @@ static int seeq8005_close(struct net_device *dev)
}
-/* Get the current statistics. This may be called with the card open or
- closed. */
-static struct net_device_stats *seeq8005_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/* Set or clear the multicast filter for this adaptor.
num_addrs == -1 Promiscuous mode, receive all packets
num_addrs == 0 Normal mode, clear multicast list
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 0fb74cb51c4..ff405631035 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -75,6 +75,7 @@ struct sgiseeq_init_block { /* Note the name ;-) */
struct sgiseeq_private {
struct sgiseeq_init_block *srings;
+ dma_addr_t srings_dma;
/* Ptrs to the descriptors in uncached space. */
struct sgiseeq_rx_desc *rx_desc;
@@ -92,8 +93,6 @@ struct sgiseeq_private {
unsigned char control;
unsigned char mode;
- struct net_device_stats stats;
-
spinlock_t tx_lock;
};
@@ -266,18 +265,17 @@ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
return 0;
}
-static inline void record_rx_errors(struct sgiseeq_private *sp,
- unsigned char status)
+static void record_rx_errors(struct net_device *dev, unsigned char status)
{
if (status & SEEQ_RSTAT_OVERF ||
status & SEEQ_RSTAT_SFRAME)
- sp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (status & SEEQ_RSTAT_CERROR)
- sp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (status & SEEQ_RSTAT_DERROR)
- sp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & SEEQ_RSTAT_REOF)
- sp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
static inline void rx_maybe_restart(struct sgiseeq_private *sp,
@@ -327,8 +325,8 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp
if (memcmp(eth_hdr(skb)->h_source, dev->dev_addr, ETH_ALEN)) {
netif_rx(skb);
dev->last_rx = jiffies;
- sp->stats.rx_packets++;
- sp->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
} else {
/* Silently drop my own packets */
dev_kfree_skb_irq(skb);
@@ -336,10 +334,10 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp
} else {
printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
dev->name);
- sp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
}
} else {
- record_rx_errors(sp, pkt_status);
+ record_rx_errors(dev, pkt_status);
}
/* Return the entry to the ring pool. */
@@ -391,11 +389,11 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp
if (!(status & (HPC3_ETXCTRL_ACTIVE | SEEQ_TSTAT_PTRANS))) {
/* Oops, HPC detected some sort of error. */
if (status & SEEQ_TSTAT_R16)
- sp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (status & SEEQ_TSTAT_UFLOW)
- sp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (status & SEEQ_TSTAT_LCLS)
- sp->stats.collisions++;
+ dev->stats.collisions++;
}
/* Ack 'em... */
@@ -411,7 +409,7 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp
}
break;
}
- sp->stats.tx_packets++;
+ dev->stats.tx_packets++;
sp->tx_old = NEXT_TX(sp->tx_old);
td->tdma.cntinfo &= ~(HPCDMA_XIU | HPCDMA_XIE);
td->tdma.cntinfo |= HPCDMA_EOX;
@@ -515,7 +513,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Setup... */
skblen = skb->len;
len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
- sp->stats.tx_bytes += len;
+ dev->stats.tx_bytes += len;
entry = sp->tx_new;
td = &sp->tx_desc[entry];
@@ -568,13 +566,6 @@ static void timeout(struct net_device *dev)
netif_wake_queue(dev);
}
-static struct net_device_stats *sgiseeq_get_stats(struct net_device *dev)
-{
- struct sgiseeq_private *sp = netdev_priv(dev);
-
- return &sp->stats;
-}
-
static void sgiseeq_set_multicast(struct net_device *dev)
{
struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
@@ -631,6 +622,7 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
struct sgiseeq_private *sp;
struct net_device *dev;
int err, i;
+ DECLARE_MAC_BUF(mac);
dev = alloc_etherdev(sizeof (struct sgiseeq_private));
if (!dev) {
@@ -643,13 +635,20 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
sp = netdev_priv(dev);
/* Make private data page aligned */
- sr = (struct sgiseeq_init_block *) get_zeroed_page(GFP_KERNEL);
+ sr = dma_alloc_coherent(&pdev->dev, sizeof(*sp->srings),
+ &sp->srings_dma, GFP_KERNEL);
if (!sr) {
printk(KERN_ERR "Sgiseeq: Page alloc failed, aborting.\n");
err = -ENOMEM;
goto err_out_free_dev;
}
sp->srings = sr;
+ sp->rx_desc = sp->srings->rxvector;
+ sp->tx_desc = sp->srings->txvector;
+
+ /* A couple calculations now, saves many cycles later. */
+ setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS);
+ setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS);
memcpy(dev->dev_addr, pd->mac, ETH_ALEN);
@@ -662,19 +661,6 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
sp->name = sgiseeqstr;
sp->mode = SEEQ_RCMD_RBCAST;
- sp->rx_desc = (struct sgiseeq_rx_desc *)
- CKSEG1ADDR(ALIGNED(&sp->srings->rxvector[0]));
- dma_cache_wback_inv((unsigned long)&sp->srings->rxvector,
- sizeof(sp->srings->rxvector));
- sp->tx_desc = (struct sgiseeq_tx_desc *)
- CKSEG1ADDR(ALIGNED(&sp->srings->txvector[0]));
- dma_cache_wback_inv((unsigned long)&sp->srings->txvector,
- sizeof(sp->srings->txvector));
-
- /* A couple calculations now, saves many cycles later. */
- setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS);
- setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS);
-
/* Setup PIO and DMA transfer timing */
sp->hregs->pconfig = 0x161;
sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
@@ -699,7 +685,6 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
dev->hard_start_xmit = sgiseeq_start_xmit;
dev->tx_timeout = timeout;
dev->watchdog_timeo = (200 * HZ) / 1000;
- dev->get_stats = sgiseeq_get_stats;
dev->set_multicast_list = sgiseeq_set_multicast;
dev->set_mac_address = sgiseeq_set_mac_address;
dev->irq = irq;
@@ -711,9 +696,8 @@ static int __init sgiseeq_probe(struct platform_device *pdev)
goto err_out_free_page;
}
- printk(KERN_INFO "%s: %s ", dev->name, sgiseeqstr);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+ printk(KERN_INFO "%s: %s %s\n",
+ dev->name, sgiseeqstr, print_mac(mac, dev->dev_addr));
return 0;
@@ -732,7 +716,8 @@ static int __exit sgiseeq_remove(struct platform_device *pdev)
struct sgiseeq_private *sp = netdev_priv(dev);
unregister_netdev(dev);
- free_page((unsigned long) sp->srings);
+ dma_free_coherent(&pdev->dev, sizeof(*sp->srings), sp->srings,
+ sp->srings_dma);
free_netdev(dev);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
index 4c3d98ff4cd..228f650250f 100644
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -86,6 +86,7 @@
#include <net/dst.h>
#include <net/arp.h>
+#include <net/net_namespace.h>
struct shaper_cb {
unsigned long shapeclock; /* Time it should go out */
@@ -170,7 +171,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
if(time_after(SHAPERCB(skb)->shapeclock,jiffies + SHAPER_LATENCY)) {
dev_kfree_skb(skb);
- shaper->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
} else
skb_queue_tail(&shaper->sendq, skb);
}
@@ -181,7 +182,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
ptr=skb_dequeue(&shaper->sendq);
dev_kfree_skb(ptr);
- shaper->stats.collisions++;
+ dev->stats.collisions++;
}
shaper_kick(shaper);
spin_unlock(&shaper->lock);
@@ -206,8 +207,8 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb)
shaper->dev->name,newskb->priority);
dev_queue_xmit(newskb);
- shaper->stats.tx_bytes += skb->len;
- shaper->stats.tx_packets++;
+ shaper->dev->stats.tx_bytes += skb->len;
+ shaper->dev->stats.tx_packets++;
if(sh_debug)
printk("Kicked new frame out.\n");
@@ -329,22 +330,17 @@ static int shaper_close(struct net_device *dev)
* ARP and other resolutions and not before.
*/
-static struct net_device_stats *shaper_get_stats(struct net_device *dev)
-{
- struct shaper *sh=dev->priv;
- return &sh->stats;
-}
-
static int shaper_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr, unsigned len)
+ unsigned short type,
+ const void *daddr, const void *saddr, unsigned len)
{
struct shaper *sh=dev->priv;
int v;
if(sh_debug)
printk("Shaper header\n");
- skb->dev=sh->dev;
- v=sh->hard_header(skb,sh->dev,type,daddr,saddr,len);
- skb->dev=dev;
+ skb->dev = sh->dev;
+ v = dev_hard_header(skb, sh->dev, type, daddr, saddr, len);
+ skb->dev = dev;
return v;
}
@@ -356,7 +352,7 @@ static int shaper_rebuild_header(struct sk_buff *skb)
if(sh_debug)
printk("Shaper rebuild header\n");
skb->dev=sh->dev;
- v=sh->rebuild_header(skb);
+ v = sh->dev->header_ops->rebuild(skb);
skb->dev=dev;
return v;
}
@@ -420,51 +416,17 @@ static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
#endif
+static const struct header_ops shaper_ops = {
+ .create = shaper_header,
+ .rebuild = shaper_rebuild_header,
+};
+
static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net_device *dev)
{
sh->dev = dev;
- sh->hard_start_xmit=dev->hard_start_xmit;
sh->get_stats=dev->get_stats;
- if(dev->hard_header)
- {
- sh->hard_header=dev->hard_header;
- shdev->hard_header = shaper_header;
- }
- else
- shdev->hard_header = NULL;
-
- if(dev->rebuild_header)
- {
- sh->rebuild_header = dev->rebuild_header;
- shdev->rebuild_header = shaper_rebuild_header;
- }
- else
- shdev->rebuild_header = NULL;
-#if 0
- if(dev->hard_header_cache)
- {
- sh->hard_header_cache = dev->hard_header_cache;
- shdev->hard_header_cache= shaper_cache;
- }
- else
- {
- shdev->hard_header_cache= NULL;
- }
-
- if(dev->header_cache_update)
- {
- sh->header_cache_update = dev->header_cache_update;
- shdev->header_cache_update = shaper_cache_update;
- }
- else
- shdev->header_cache_update= NULL;
-#else
- shdev->header_cache_update = NULL;
- shdev->hard_header_cache = NULL;
-#endif
shdev->neigh_setup = shaper_neigh_setup_dev;
-
shdev->hard_header_len=dev->hard_header_len;
shdev->type=dev->type;
shdev->addr_len=dev->addr_len;
@@ -488,7 +450,7 @@ static int shaper_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
case SHAPER_SET_DEV:
{
- struct net_device *them=__dev_get_by_name(ss->ss_name);
+ struct net_device *them=__dev_get_by_name(&init_net, ss->ss_name);
if(them==NULL)
return -ENODEV;
if(sh->dev)
@@ -532,14 +494,11 @@ static void __init shaper_setup(struct net_device *dev)
* Set up the shaper.
*/
- SET_MODULE_OWNER(dev);
-
shaper_init_priv(dev);
dev->open = shaper_open;
dev->stop = shaper_close;
dev->hard_start_xmit = shaper_start_xmit;
- dev->get_stats = shaper_get_stats;
dev->set_multicast_list = NULL;
/*
@@ -550,12 +509,6 @@ static void __init shaper_setup(struct net_device *dev)
* Handlers for when we attach to a device.
*/
- dev->hard_header = shaper_header;
- dev->rebuild_header = shaper_rebuild_header;
-#if 0
- dev->hard_header_cache = shaper_cache;
- dev->header_cache_update= shaper_cache_update;
-#endif
dev->neigh_setup = shaper_neigh_setup_dev;
dev->do_ioctl = shaper_ioctl;
dev->hard_header_len = 0;
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index d470b19c081..720088396bb 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -47,24 +47,13 @@
#define PHY_ID_ANY 0x1f
#define MII_REG_ANY 0x1f
-#ifdef CONFIG_SIS190_NAPI
-#define NAPI_SUFFIX "-NAPI"
-#else
-#define NAPI_SUFFIX ""
-#endif
-
-#define DRV_VERSION "1.2" NAPI_SUFFIX
+#define DRV_VERSION "1.2"
#define DRV_NAME "sis190"
#define SIS190_DRIVER_NAME DRV_NAME " Gigabit Ethernet driver " DRV_VERSION
#define PFX DRV_NAME ": "
-#ifdef CONFIG_SIS190_NAPI
-#define sis190_rx_skb netif_receive_skb
-#define sis190_rx_quota(count, quota) min(count, quota)
-#else
#define sis190_rx_skb netif_rx
#define sis190_rx_quota(count, quota) count
-#endif
#define MAC_ADDR_LEN 6
@@ -281,7 +270,6 @@ struct sis190_private {
void __iomem *mmio_addr;
struct pci_dev *pci_dev;
struct net_device *dev;
- struct net_device_stats stats;
spinlock_t lock;
u32 rx_buf_sz;
u32 cur_rx;
@@ -580,7 +568,7 @@ static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats)
static int sis190_rx_interrupt(struct net_device *dev,
struct sis190_private *tp, void __iomem *ioaddr)
{
- struct net_device_stats *stats = &tp->stats;
+ struct net_device_stats *stats = &dev->stats;
u32 rx_left, cur_rx = tp->cur_rx;
u32 delta, count;
@@ -694,8 +682,8 @@ static void sis190_tx_interrupt(struct net_device *dev,
skb = tp->Tx_skbuff[entry];
- tp->stats.tx_packets++;
- tp->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
sis190_unmap_tx_skb(tp->pci_dev, skb, txd);
tp->Tx_skbuff[entry] = NULL;
@@ -1091,7 +1079,7 @@ static void sis190_tx_clear(struct sis190_private *tp)
tp->Tx_skbuff[i] = NULL;
dev_kfree_skb(skb);
- tp->stats.tx_dropped++;
+ tp->dev->stats.tx_dropped++;
}
tp->cur_tx = tp->dirty_tx = 0;
}
@@ -1115,10 +1103,8 @@ static void sis190_down(struct net_device *dev)
synchronize_irq(dev->irq);
- if (!poll_locked) {
- netif_poll_disable(dev);
+ if (!poll_locked)
poll_locked++;
- }
synchronize_sched();
@@ -1137,8 +1123,6 @@ static int sis190_close(struct net_device *dev)
free_irq(dev->irq, dev);
- netif_poll_enable(dev);
-
pci_free_consistent(pdev, TX_RING_BYTES, tp->TxDescRing, tp->tx_dma);
pci_free_consistent(pdev, RX_RING_BYTES, tp->RxDescRing, tp->rx_dma);
@@ -1158,7 +1142,7 @@ static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb->len < ETH_ZLEN)) {
if (skb_padto(skb, ETH_ZLEN)) {
- tp->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
goto out;
}
len = ETH_ZLEN;
@@ -1211,13 +1195,6 @@ out:
return NETDEV_TX_OK;
}
-static struct net_device_stats *sis190_get_stats(struct net_device *dev)
-{
- struct sis190_private *tp = netdev_priv(dev);
-
- return &tp->stats;
-}
-
static void sis190_free_phy(struct list_head *first_phy)
{
struct sis190_phy *cur, *next;
@@ -1436,7 +1413,6 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev)
goto err_out_0;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
tp = netdev_priv(dev);
@@ -1783,6 +1759,7 @@ static int __devinit sis190_init_one(struct pci_dev *pdev,
struct net_device *dev;
void __iomem *ioaddr;
int rc;
+ DECLARE_MAC_BUF(mac);
if (!printed_version) {
net_drv(&debug, KERN_INFO SIS190_DRIVER_NAME " loaded.\n");
@@ -1811,7 +1788,6 @@ static int __devinit sis190_init_one(struct pci_dev *pdev,
dev->open = sis190_open;
dev->stop = sis190_close;
dev->do_ioctl = sis190_ioctl;
- dev->get_stats = sis190_get_stats;
dev->tx_timeout = sis190_tx_timeout;
dev->watchdog_timeo = SIS190_TX_TIMEOUT;
dev->hard_start_xmit = sis190_start_xmit;
@@ -1834,12 +1810,9 @@ static int __devinit sis190_init_one(struct pci_dev *pdev,
goto err_remove_mii;
net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
- pci_name(pdev), sis_chip_info[ent->driver_data].name,
- ioaddr, dev->irq,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5]);
+ "%s\n",
+ pci_name(pdev), sis_chip_info[ent->driver_data].name,
+ ioaddr, dev->irq, print_mac(mac, dev->dev_addr));
net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name,
(tp->features & F_HAS_RGMII) ? "RGMII" : "GMII");
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 7c6e4808399..0857d2c88aa 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -158,7 +158,6 @@ typedef struct _BufferDesc {
} BufferDesc;
struct sis900_private {
- struct net_device_stats stats;
struct pci_dev * pci_dev;
spinlock_t lock;
@@ -221,7 +220,6 @@ static void sis900_finish_xmit (struct net_device *net_dev);
static irqreturn_t sis900_interrupt(int irq, void *dev_instance);
static int sis900_close(struct net_device *net_dev);
static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *sis900_get_stats(struct net_device *net_dev);
static u16 sis900_mcast_bitnr(u8 *addr, u8 revision);
static void set_rx_mode(struct net_device *net_dev);
static void sis900_reset(struct net_device *net_dev);
@@ -406,6 +404,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
int i, ret;
const char *card_name = card_names[pci_id->driver_data];
const char *dev_name = pci_name(pci_dev);
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -430,7 +429,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
net_dev = alloc_etherdev(sizeof(struct sis900_private));
if (!net_dev)
return -ENOMEM;
- SET_MODULE_OWNER(net_dev);
SET_NETDEV_DEV(net_dev, &pci_dev->dev);
/* We do a request_region() to register /proc/ioports info. */
@@ -467,7 +465,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
net_dev->open = &sis900_open;
net_dev->hard_start_xmit = &sis900_start_xmit;
net_dev->stop = &sis900_close;
- net_dev->get_stats = &sis900_get_stats;
net_dev->set_config = &sis900_set_config;
net_dev->set_multicast_list = &set_rx_mode;
net_dev->do_ioctl = &mii_ioctl;
@@ -537,11 +534,9 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
goto err_unmap_rx;
/* print some information about our NIC */
- printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name,
- card_name, ioaddr, net_dev->irq);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", (u8)net_dev->dev_addr[i]);
- printk("%2.2x.\n", net_dev->dev_addr[i]);
+ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n",
+ net_dev->name, card_name, ioaddr, net_dev->irq,
+ print_mac(mac, net_dev->dev_addr));
/* Detect Wake on Lan support */
ret = (inl(net_dev->base_addr + CFGPMC) & PMESP) >> 27;
@@ -1543,7 +1538,7 @@ static void sis900_tx_timeout(struct net_device *net_dev)
sis_priv->tx_skbuff[i] = NULL;
sis_priv->tx_ring[i].cmdsts = 0;
sis_priv->tx_ring[i].bufptr = 0;
- sis_priv->stats.tx_dropped++;
+ net_dev->stats.tx_dropped++;
}
}
sis_priv->tx_full = 0;
@@ -1740,15 +1735,15 @@ static int sis900_rx(struct net_device *net_dev)
printk(KERN_DEBUG "%s: Corrupted packet "
"received, buffer status = 0x%8.8x/%d.\n",
net_dev->name, rx_status, data_size);
- sis_priv->stats.rx_errors++;
+ net_dev->stats.rx_errors++;
if (rx_status & OVERRUN)
- sis_priv->stats.rx_over_errors++;
+ net_dev->stats.rx_over_errors++;
if (rx_status & (TOOLONG|RUNT))
- sis_priv->stats.rx_length_errors++;
+ net_dev->stats.rx_length_errors++;
if (rx_status & (RXISERR | FAERR))
- sis_priv->stats.rx_frame_errors++;
+ net_dev->stats.rx_frame_errors++;
if (rx_status & CRCERR)
- sis_priv->stats.rx_crc_errors++;
+ net_dev->stats.rx_crc_errors++;
/* reset buffer descriptor state */
sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
} else {
@@ -1769,7 +1764,7 @@ static int sis900_rx(struct net_device *net_dev)
* in the rx ring
*/
skb = sis_priv->rx_skbuff[entry];
- sis_priv->stats.rx_dropped++;
+ net_dev->stats.rx_dropped++;
goto refill_rx_ring;
}
@@ -1794,10 +1789,10 @@ static int sis900_rx(struct net_device *net_dev)
/* some network statistics */
if ((rx_status & BCAST) == MCAST)
- sis_priv->stats.multicast++;
+ net_dev->stats.multicast++;
net_dev->last_rx = jiffies;
- sis_priv->stats.rx_bytes += rx_size;
- sis_priv->stats.rx_packets++;
+ net_dev->stats.rx_bytes += rx_size;
+ net_dev->stats.rx_packets++;
sis_priv->dirty_rx++;
refill_rx_ring:
sis_priv->rx_skbuff[entry] = skb;
@@ -1828,7 +1823,7 @@ refill_rx_ring:
printk(KERN_INFO "%s: Memory squeeze,"
"deferring packet.\n",
net_dev->name);
- sis_priv->stats.rx_dropped++;
+ net_dev->stats.rx_dropped++;
break;
}
sis_priv->rx_skbuff[entry] = skb;
@@ -1879,20 +1874,20 @@ static void sis900_finish_xmit (struct net_device *net_dev)
printk(KERN_DEBUG "%s: Transmit "
"error, Tx status %8.8x.\n",
net_dev->name, tx_status);
- sis_priv->stats.tx_errors++;
+ net_dev->stats.tx_errors++;
if (tx_status & UNDERRUN)
- sis_priv->stats.tx_fifo_errors++;
+ net_dev->stats.tx_fifo_errors++;
if (tx_status & ABORT)
- sis_priv->stats.tx_aborted_errors++;
+ net_dev->stats.tx_aborted_errors++;
if (tx_status & NOCARRIER)
- sis_priv->stats.tx_carrier_errors++;
+ net_dev->stats.tx_carrier_errors++;
if (tx_status & OWCOLL)
- sis_priv->stats.tx_window_errors++;
+ net_dev->stats.tx_window_errors++;
} else {
/* packet successfully transmitted */
- sis_priv->stats.collisions += (tx_status & COLCNT) >> 16;
- sis_priv->stats.tx_bytes += tx_status & DSIZE;
- sis_priv->stats.tx_packets++;
+ net_dev->stats.collisions += (tx_status & COLCNT) >> 16;
+ net_dev->stats.tx_bytes += tx_status & DSIZE;
+ net_dev->stats.tx_packets++;
}
/* Free the original skb. */
skb = sis_priv->tx_skbuff[entry];
@@ -2139,21 +2134,6 @@ static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd)
}
/**
- * sis900_get_stats - Get sis900 read/write statistics
- * @net_dev: the net device to get statistics for
- *
- * get tx/rx statistics for sis900
- */
-
-static struct net_device_stats *
-sis900_get_stats(struct net_device *net_dev)
-{
- struct sis900_private *sis_priv = net_dev->priv;
-
- return &sis_priv->stats;
-}
-
-/**
* sis900_set_config - Set media type by net_device.set_config
* @dev: the net device for media type change
* @map: ifmap passed by ifconfig
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index 7dc9c9ebf5e..20890e44f99 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -4877,7 +4877,6 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
goto out_free_netdev;
}
- SET_MODULE_OWNER(dev);
dev->open = &SkGeOpen;
dev->stop = &SkGeClose;
dev->hard_start_xmit = &SkGeXmit;
diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c
index 4fe624b0dd2..c77cc14b322 100644
--- a/drivers/net/skfp/drvfbi.c
+++ b/drivers/net/skfp/drvfbi.c
@@ -43,25 +43,6 @@ static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ;
/*
* valid configuration values are:
*/
-#ifdef ISA
-const int opt_ints[] = {8, 3, 4, 5, 9, 10, 11, 12, 15} ;
-const int opt_iops[] = {8,
- 0x100, 0x120, 0x180, 0x1a0, 0x220, 0x240, 0x320, 0x340};
-const int opt_dmas[] = {4, 3, 5, 6, 7} ;
-const int opt_eproms[] = {15, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
- 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ;
-#endif
-#ifdef EISA
-const int opt_ints[] = {5, 9, 10, 11} ;
-const int opt_dmas[] = {0, 5, 6, 7} ;
-const int opt_eproms[] = {0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
- 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ;
-#endif
-
-#ifdef MCA
-int opt_ints[] = {3, 11, 10, 9} ; /* FM1 */
-int opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ;
-#endif /* MCA */
/*
* xPOS_ID:xxxx
@@ -78,17 +59,9 @@ int opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ;
*/
#ifndef MULT_OEM
#ifndef OEM_CONCEPT
-#ifndef MCA
const u_char oem_id[] = "xPOS_ID:xxxx" ;
-#else
-const u_char oem_id[] = "xPOSID1:xxxx" ; /* FM1 card id. */
-#endif
#else /* OEM_CONCEPT */
-#ifndef MCA
const u_char oem_id[] = OEM_ID ;
-#else
-const u_char oem_id[] = OEM_ID1 ; /* FM1 card id. */
-#endif /* MCA */
#endif /* OEM_CONCEPT */
#define ID_BYTE0 8
#define OEMID(smc,i) oem_id[ID_BYTE0 + i]
@@ -109,23 +82,6 @@ extern int AIX_vpdReadByte() ;
/* Prototype of a local function. */
static void smt_stop_watchdog(struct s_smc *smc);
-#ifdef MCA
-static int read_card_id() ;
-static void DisableSlotAccess() ;
-static void EnableSlotAccess() ;
-#ifdef AIX
-extern int attach_POS_addr() ;
-extern int detach_POS_addr() ;
-extern u_char read_POS() ;
-extern void write_POS() ;
-extern int AIX_vpdReadByte() ;
-#else
-#define read_POS(smc,a1,a2) ((u_char) inp(a1))
-#define write_POS(smc,a1,a2,a3) outp((a1),(a3))
-#endif
-#endif /* MCA */
-
-
/*
* FDDI card reset
*/
@@ -139,51 +95,6 @@ static void card_start(struct s_smc *smc)
smt_stop_watchdog(smc) ;
-#ifdef ISA
- outpw(CSR_A,0) ; /* reset for all chips */
- for (i = 10 ; i ; i--) /* delay for PLC's */
- (void)inpw(ISR_A) ;
- OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(2)) ;
- /* counter 2, mode 2 */
- OUT_82c54_TIMER(2,97) ; /* LSB */
- OUT_82c54_TIMER(2,0) ; /* MSB ( 15.6 us ) */
- outpw(CSR_A,CS_CRESET) ;
-#endif
-#ifdef EISA
- outpw(CSR_A,0) ; /* reset for all chips */
- for (i = 10 ; i ; i--) /* delay for PLC's */
- (void)inpw(ISR_A) ;
- outpw(CSR_A,CS_CRESET) ;
- smc->hw.led = (2<<6) ;
- outpw(CSR_A,CS_CRESET | smc->hw.led) ;
-#endif
-#ifdef MCA
- outp(ADDR(CARD_DIS),0) ; /* reset for all chips */
- for (i = 10 ; i ; i--) /* delay for PLC's */
- (void)inpw(ISR_A) ;
- outp(ADDR(CARD_EN),0) ;
- /* first I/O after reset must not be a access to FORMAC or PLC */
-
- /*
- * bus timeout (MCA)
- */
- OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(3)) ;
- /* counter 2, mode 3 */
- OUT_82c54_TIMER(2,(2*24)) ; /* 3.9 us * 2 square wave */
- OUT_82c54_TIMER(2,0) ; /* MSB */
-
- /* POS 102 indicated an activ Check Line or Buss Error monitoring */
- if (inpw(CSA_A) & (POS_EN_CHKINT | POS_EN_BUS_ERR)) {
- outp(ADDR(IRQ_CHCK_EN),0) ;
- }
-
- if (!((i = inpw(CSR_A)) & CS_SAS)) {
- if (!(i & CS_BYSTAT)) {
- outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */
- }
- }
- outpw(LEDR_A,LED_1) ; /* yellow */
-#endif /* MCA */
#ifdef PCI
/*
* make sure no transfer activity is pending
@@ -253,15 +164,7 @@ void card_stop(struct s_smc *smc)
{
smt_stop_watchdog(smc) ;
smc->hw.mac_ring_is_up = 0 ; /* ring down */
-#ifdef ISA
- outpw(CSR_A,0) ; /* reset for all chips */
-#endif
-#ifdef EISA
- outpw(CSR_A,0) ; /* reset for all chips */
-#endif
-#ifdef MCA
- outp(ADDR(CARD_DIS),0) ; /* reset for all chips */
-#endif
+
#ifdef PCI
/*
* make sure no transfer activity is pending
@@ -284,60 +187,6 @@ void mac1_irq(struct s_smc *smc, u_short stu, u_short stl)
{
int restart_tx = 0 ;
again:
-#ifndef PCI
-#ifndef ISA
-/*
- * FORMAC+ bug modified the queue pointer if many read/write accesses happens!?
- */
- if (stl & (FM_SPCEPDS | /* parit/coding err. syn.q.*/
- FM_SPCEPDA0 | /* parit/coding err. a.q.0 */
- FM_SPCEPDA1 | /* parit/coding err. a.q.1 */
- FM_SPCEPDA2)) { /* parit/coding err. a.q.2 */
- SMT_PANIC(smc,SMT_E0132, SMT_E0132_MSG) ;
- }
- if (stl & (FM_STBURS | /* tx buffer underrun syn.q.*/
- FM_STBURA0 | /* tx buffer underrun a.q.0 */
- FM_STBURA1 | /* tx buffer underrun a.q.1 */
- FM_STBURA2)) { /* tx buffer underrun a.q.2 */
- SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ;
- }
-#endif
- if ( (stu & (FM_SXMTABT | /* transmit abort */
-#ifdef SYNC
- FM_STXABRS | /* syn. tx abort */
-#endif /* SYNC */
- FM_STXABRA0)) || /* asyn. tx abort */
- (stl & (FM_SQLCKS | /* lock for syn. q. */
- FM_SQLCKA0)) ) { /* lock for asyn. q. */
- formac_tx_restart(smc) ; /* init tx */
- restart_tx = 1 ;
- stu = inpw(FM_A(FM_ST1U)) ;
- stl = inpw(FM_A(FM_ST1L)) ;
- stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ;
- if (stu || stl)
- goto again ;
- }
-
-#ifndef SYNC
- if (stu & (FM_STECFRMA0 | /* end of chain asyn tx */
- FM_STEFRMA0)) { /* end of frame asyn tx */
- /* free tx_queue */
- smc->hw.n_a_send = 0 ;
- if (++smc->hw.fp.tx_free < smc->hw.fp.tx_max) {
- start_next_send(smc);
- }
- restart_tx = 1 ;
- }
-#else /* SYNC */
- if (stu & (FM_STEFRMA0 | /* end of asyn tx */
- FM_STEFRMS)) { /* end of sync tx */
- restart_tx = 1 ;
- }
-#endif /* SYNC */
- if (restart_tx)
- llc_restart_tx(smc) ;
-}
-#else /* PCI */
/*
* parity error: note encoding error is not possible in tag mode
@@ -378,7 +227,7 @@ again:
if (restart_tx)
llc_restart_tx(smc) ;
}
-#endif /* PCI */
+
/*
* interrupt source= plc1
* this function is called in nwfbisr.asm
@@ -387,10 +236,6 @@ void plc1_irq(struct s_smc *smc)
{
u_short st = inpw(PLC(PB,PL_INTR_EVENT)) ;
-#if (defined(ISA) || defined(EISA))
- /* reset PLC Int. bits */
- outpw(PLC1_I,inpw(PLC1_I)) ;
-#endif
plc_irq(smc,PB,st) ;
}
@@ -402,10 +247,6 @@ void plc2_irq(struct s_smc *smc)
{
u_short st = inpw(PLC(PA,PL_INTR_EVENT)) ;
-#if (defined(ISA) || defined(EISA))
- /* reset PLC Int. bits */
- outpw(PLC2_I,inpw(PLC2_I)) ;
-#endif
plc_irq(smc,PA,st) ;
}
@@ -446,43 +287,15 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
char PmdType ;
int i ;
-#if (defined(ISA) || defined(MCA))
- for (i = 0; i < 4 ;i++) { /* read mac address from board */
- smc->hw.fddi_phys_addr.a[i] =
- bitrev8(inpw(PR_A(i+SA_MAC)));
- }
- for (i = 4; i < 6; i++) {
- smc->hw.fddi_phys_addr.a[i] =
- bitrev8(inpw(PR_A(i+SA_MAC+PRA_OFF)));
- }
-#endif
-#ifdef EISA
- /*
- * Note: We get trouble on an Alpha machine if we make a inpw()
- * instead of inp()
- */
- for (i = 0; i < 4 ;i++) { /* read mac address from board */
- smc->hw.fddi_phys_addr.a[i] =
- bitrev8(inp(PR_A(i+SA_MAC)));
- }
- for (i = 4; i < 6; i++) {
- smc->hw.fddi_phys_addr.a[i] =
- bitrev8(inp(PR_A(i+SA_MAC+PRA_OFF)));
- }
-#endif
#ifdef PCI
for (i = 0; i < 6; i++) { /* read mac address from board */
smc->hw.fddi_phys_addr.a[i] =
bitrev8(inp(ADDR(B2_MAC_0+i)));
}
#endif
-#ifndef PCI
- ConnectorType = inpw(PR_A(SA_PMD_TYPE)) & 0xff ;
- PmdType = inpw(PR_A(SA_PMD_TYPE+1)) & 0xff ;
-#else
+
ConnectorType = inp(ADDR(B2_CONN_TYP)) ;
PmdType = inp(ADDR(B2_PMD_TYP)) ;
-#endif
smc->y[PA].pmd_type[PMD_SK_CONN] =
smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ;
@@ -512,20 +325,12 @@ void init_board(struct s_smc *smc, u_char *mac_addr)
card_start(smc) ;
read_address(smc,mac_addr) ;
-#ifndef PCI
- if (inpw(CSR_A) & CS_SAS)
-#else
if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL))
-#endif
smc->s.sas = SMT_SAS ; /* Single att. station */
else
smc->s.sas = SMT_DAS ; /* Dual att. station */
-#ifndef PCI
- if (inpw(CSR_A) & CS_BYSTAT)
-#else
if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST))
-#endif
smc->mib.fddiSMTBypassPresent = 0 ;
/* without opt. bypass */
else
@@ -538,42 +343,12 @@ void init_board(struct s_smc *smc, u_char *mac_addr)
*/
void sm_pm_bypass_req(struct s_smc *smc, int mode)
{
-#if (defined(ISA) || defined(EISA))
- int csra_v ;
-#endif
-
DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ?
"BP_INSERT" : "BP_DEINSERT",0) ;
if (smc->s.sas != SMT_DAS)
return ;
-#if (defined(ISA) || defined(EISA))
-
- csra_v = inpw(CSR_A) & ~CS_BYPASS ;
-#ifdef EISA
- csra_v |= smc->hw.led ;
-#endif
-
- switch(mode) {
- case BP_INSERT :
- outpw(CSR_A,csra_v | CS_BYPASS) ;
- break ;
- case BP_DEINSERT :
- outpw(CSR_A,csra_v) ;
- break ;
- }
-#endif /* ISA / EISA */
-#ifdef MCA
- switch(mode) {
- case BP_INSERT :
- outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */
- break ;
- case BP_DEINSERT :
- outp(ADDR(BYPASS(STAT_BYP)),0) ; /* bypass station */
- break ;
- }
-#endif
#ifdef PCI
switch(mode) {
case BP_INSERT :
@@ -591,31 +366,14 @@ void sm_pm_bypass_req(struct s_smc *smc, int mode)
*/
int sm_pm_bypass_present(struct s_smc *smc)
{
-#ifndef PCI
- return( (inpw(CSR_A) & CS_BYSTAT) ? FALSE : TRUE ) ;
-#else
return( (inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE: FALSE) ;
-#endif
}
void plc_clear_irq(struct s_smc *smc, int p)
{
SK_UNUSED(p) ;
-#if (defined(ISA) || defined(EISA))
- switch (p) {
- case PA :
- /* reset PLC Int. bits */
- outpw(PLC2_I,inpw(PLC2_I)) ;
- break ;
- case PB :
- /* reset PLC Int. bits */
- outpw(PLC1_I,inpw(PLC1_I)) ;
- break ;
- }
-#else
SK_UNUSED(smc) ;
-#endif
}
@@ -645,51 +403,6 @@ static void led_indication(struct s_smc *smc, int led_event)
phy = &smc->y[PB] ;
mib_b = phy->mib ;
-#ifdef EISA
- /* Ring up = yellow led OFF*/
- if (led_event == LED_Y_ON) {
- smc->hw.led |= CS_LED_1 ;
- }
- else if (led_event == LED_Y_OFF) {
- smc->hw.led &= ~CS_LED_1 ;
- }
- else {
- /* Link at Port A or B = green led ON */
- if (mib_a->fddiPORTPCMState == PC8_ACTIVE ||
- mib_b->fddiPORTPCMState == PC8_ACTIVE) {
- smc->hw.led |= CS_LED_0 ;
- }
- else {
- smc->hw.led &= ~CS_LED_0 ;
- }
- }
-#endif
-#ifdef MCA
- led_state = inpw(LEDR_A) ;
-
- /* Ring up = yellow led OFF*/
- if (led_event == LED_Y_ON) {
- led_state |= LED_1 ;
- }
- else if (led_event == LED_Y_OFF) {
- led_state &= ~LED_1 ;
- }
- else {
- led_state &= ~(LED_2|LED_0) ;
-
- /* Link at Port A = green led A ON */
- if (mib_a->fddiPORTPCMState == PC8_ACTIVE) {
- led_state |= LED_2 ;
- }
-
- /* Link at Port B/S = green led B ON */
- if (mib_b->fddiPORTPCMState == PC8_ACTIVE) {
- led_state |= LED_0 ;
- }
- }
-
- outpw(LEDR_A, led_state) ;
-#endif /* MCA */
#ifdef PCI
led_state = 0 ;
@@ -824,446 +537,6 @@ int set_oi_id_def(struct s_smc *smc)
}
#endif /* MULT_OEM */
-
-#ifdef MCA
-/************************
- *
- * BEGIN_MANUAL_ENTRY()
- *
- * exist_board
- *
- * Check if an MCA board is present in the specified slot.
- *
- * int exist_board(
- * struct s_smc *smc,
- * int slot) ;
- * In
- * smc - A pointer to the SMT Context struct.
- *
- * slot - The number of the slot to inspect.
- * Out
- * 0 = No adapter present.
- * 1 = Found FM1 adapter.
- *
- * Pseudo
- * Read MCA ID
- * for all valid OEM_IDs
- * compare with ID read
- * if equal, return 1
- * return(0
- *
- * Note
- * The smc pointer must be valid now.
- *
- * END_MANUAL_ENTRY()
- *
- ************************/
-#define LONG_CARD_ID(lo, hi) ((((hi) & 0xff) << 8) | ((lo) & 0xff))
-int exist_board(struct s_smc *smc, int slot)
-{
-#ifdef MULT_OEM
- SK_LOC_DECL(u_char,id[2]) ;
- int idi ;
-#endif /* MULT_OEM */
-
- /* No longer valid. */
- if (smc == NULL)
- return(0) ;
-
-#ifndef MULT_OEM
- if (read_card_id(smc, slot)
- == LONG_CARD_ID(OEMID(smc,0), OEMID(smc,1)))
- return (1) ; /* Found FM adapter. */
-
-#else /* MULT_OEM */
- idi = read_card_id(smc, slot) ;
- id[0] = idi & 0xff ;
- id[1] = idi >> 8 ;
-
- smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
- for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
- if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
- continue ;
-
- if (is_equal_num(&id[0],&OEMID(smc,0),2))
- return (1) ;
- }
-#endif /* MULT_OEM */
- return (0) ; /* No adapter found. */
-}
-
-/************************
- *
- * read_card_id
- *
- * Read the MCA card id from the specified slot.
- * In
- * smc - A pointer to the SMT Context struct.
- * CAVEAT: This pointer may be NULL and *must not* be used within this
- * function. It's only purpose is for drivers that need some information
- * for the inp() and outp() macros.
- *
- * slot - The number of the slot for which the card id is returned.
- * Out
- * Returns the card id read from the specified slot. If an illegal slot
- * number is specified, the function returns zero.
- *
- ************************/
-static int read_card_id(struct s_smc *smc, int slot)
-/* struct s_smc *smc ; Do not use. */
-{
- int card_id ;
-
- SK_UNUSED(smc) ; /* Make LINT happy. */
- if ((slot < 1) || (slot > 15)) /* max 16 slots, 0 = motherboard */
- return (0) ; /* Illegal slot number specified. */
-
- EnableSlotAccess(smc, slot) ;
-
- card_id = ((read_POS(smc,POS_ID_HIGH,slot - 1) & 0xff) << 8) |
- (read_POS(smc,POS_ID_LOW,slot - 1) & 0xff) ;
-
- DisableSlotAccess(smc) ;
-
- return (card_id) ;
-}
-
-/************************
- *
- * BEGIN_MANUAL_ENTRY()
- *
- * get_board_para
- *
- * Get adapter configuration information. Fill all board specific
- * parameters within the 'smc' structure.
- *
- * int get_board_para(
- * struct s_smc *smc,
- * int slot) ;
- * In
- * smc - A pointer to the SMT Context struct, to which this function will
- * write some adapter configuration data.
- *
- * slot - The number of the slot, in which the adapter is installed.
- * Out
- * 0 = No adapter present.
- * 1 = Ok.
- * 2 = Adapter present, but card enable bit not set.
- *
- * END_MANUAL_ENTRY()
- *
- ************************/
-int get_board_para(struct s_smc *smc, int slot)
-{
- int val ;
- int i ;
-
- /* Check if adapter present & get type of adapter. */
- switch (exist_board(smc, slot)) {
- case 0: /* Adapter not present. */
- return (0) ;
- case 1: /* FM Rev. 1 */
- smc->hw.rev = FM1_REV ;
- smc->hw.VFullRead = 0x0a ;
- smc->hw.VFullWrite = 0x05 ;
- smc->hw.DmaWriteExtraBytes = 8 ; /* 2 extra words. */
- break ;
- }
- smc->hw.slot = slot ;
-
- EnableSlotAccess(smc, slot) ;
-
- if (!(read_POS(smc,POS_102, slot - 1) & POS_CARD_EN)) {
- DisableSlotAccess(smc) ;
- return (2) ; /* Card enable bit not set. */
- }
-
- val = read_POS(smc,POS_104, slot - 1) ; /* I/O, IRQ */
-
-#ifndef MEM_MAPPED_IO /* is defined by the operating system */
- i = val & POS_IOSEL ; /* I/O base addr. (0x0200 .. 0xfe00) */
- smc->hw.iop = (i + 1) * 0x0400 - 0x200 ;
-#endif
- i = ((val & POS_IRQSEL) >> 6) & 0x03 ; /* IRQ <0, 1> */
- smc->hw.irq = opt_ints[i] ;
-
- /* FPROM base addr. */
- i = ((read_POS(smc,POS_103, slot - 1) & POS_MSEL) >> 4) & 0x07 ;
- smc->hw.eprom = opt_eproms[i] ;
-
- DisableSlotAccess(smc) ;
-
- /* before this, the smc->hw.iop must be set !!! */
- smc->hw.slot_32 = inpw(CSF_A) & SLOT_32 ;
-
- return (1) ;
-}
-
-/* Enable access to specified MCA slot. */
-static void EnableSlotAccess(struct s_smc *smc, int slot)
-{
- SK_UNUSED(slot) ;
-
-#ifndef AIX
- SK_UNUSED(smc) ;
-
- /* System mode. */
- outp(POS_SYS_SETUP, POS_SYSTEM) ;
-
- /* Select slot. */
- outp(POS_CHANNEL_POS, POS_CHANNEL_BIT | (slot-1)) ;
-#else
- attach_POS_addr (smc) ;
-#endif
-}
-
-/* Disable access to MCA slot formerly enabled via EnableSlotAccess(). */
-static void DisableSlotAccess(struct s_smc *smc)
-{
-#ifndef AIX
- SK_UNUSED(smc) ;
-
- outp(POS_CHANNEL_POS, 0) ;
-#else
- detach_POS_addr (smc) ;
-#endif
-}
-#endif /* MCA */
-
-#ifdef EISA
-#ifndef MEM_MAPPED_IO
-#define SADDR(slot) (((slot)<<12)&0xf000)
-#else /* MEM_MAPPED_IO */
-#define SADDR(slot) (smc->hw.iop)
-#endif /* MEM_MAPPED_IO */
-
-/************************
- *
- * BEGIN_MANUAL_ENTRY()
- *
- * exist_board
- *
- * Check if an EISA board is present in the specified slot.
- *
- * int exist_board(
- * struct s_smc *smc,
- * int slot) ;
- * In
- * smc - A pointer to the SMT Context struct.
- *
- * slot - The number of the slot to inspect.
- * Out
- * 0 = No adapter present.
- * 1 = Found adapter.
- *
- * Pseudo
- * Read EISA ID
- * for all valid OEM_IDs
- * compare with ID read
- * if equal, return 1
- * return(0
- *
- * Note
- * The smc pointer must be valid now.
- *
- ************************/
-int exist_board(struct s_smc *smc, int slot)
-{
- int i ;
-#ifdef MULT_OEM
- SK_LOC_DECL(u_char,id[4]) ;
-#endif /* MULT_OEM */
-
- /* No longer valid. */
- if (smc == NULL)
- return(0);
-
- SK_UNUSED(slot) ;
-
-#ifndef MULT_OEM
- for (i = 0 ; i < 4 ; i++) {
- if (inp(SADDR(slot)+PRA(i)) != OEMID(smc,i))
- return(0) ;
- }
- return(1) ;
-#else /* MULT_OEM */
- for (i = 0 ; i < 4 ; i++)
- id[i] = inp(SADDR(slot)+PRA(i)) ;
-
- smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
-
- for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
- if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
- continue ;
-
- if (is_equal_num(&id[0],&OEMID(smc,0),4))
- return (1) ;
- }
- return (0) ; /* No adapter found. */
-#endif /* MULT_OEM */
-}
-
-
-int get_board_para(struct s_smc *smc, int slot)
-{
- int i ;
-
- if (!exist_board(smc,slot))
- return(0) ;
-
- smc->hw.slot = slot ;
-#ifndef MEM_MAPPED_IO /* if defined by the operating system */
- smc->hw.iop = SADDR(slot) ;
-#endif
-
- if (!(inp(C0_A(0))&CFG_CARD_EN)) {
- return(2) ; /* CFG_CARD_EN bit not set! */
- }
-
- smc->hw.irq = opt_ints[(inp(C1_A(0)) & CFG_IRQ_SEL)] ;
- smc->hw.dma = opt_dmas[((inp(C1_A(0)) & CFG_DRQ_SEL)>>3)] ;
-
- if ((i = inp(C2_A(0)) & CFG_EPROM_SEL) != 0x0f)
- smc->hw.eprom = opt_eproms[i] ;
- else
- smc->hw.eprom = 0 ;
-
- smc->hw.DmaWriteExtraBytes = 8 ;
-
- return(1) ;
-}
-#endif /* EISA */
-
-#ifdef ISA
-#ifndef MULT_OEM
-const u_char sklogo[6] = SKLOGO_STR ;
-#define SIZE_SKLOGO(smc) sizeof(sklogo)
-#define SKLOGO(smc,i) sklogo[i]
-#else /* MULT_OEM */
-#define SIZE_SKLOGO(smc) smc->hw.oem_id->oi_logo_len
-#define SKLOGO(smc,i) smc->hw.oem_id->oi_logo[i]
-#endif /* MULT_OEM */
-
-
-int exist_board(struct s_smc *smc, HW_PTR port)
-{
- int i ;
-#ifdef MULT_OEM
- int bytes_read ;
- u_char board_logo[15] ;
- SK_LOC_DECL(u_char,id[4]) ;
-#endif /* MULT_OEM */
-
- /* No longer valid. */
- if (smc == NULL)
- return(0);
-
- SK_UNUSED(smc) ;
-#ifndef MULT_OEM
- for (i = SADDRL ; i < (signed) (SADDRL+SIZE_SKLOGO(smc)) ; i++) {
- if ((u_char)inpw((PRA(i)+port)) != SKLOGO(smc,i-SADDRL)) {
- return(0) ;
- }
- }
-
- /* check MAC address (S&K or other) */
- for (i = 0 ; i < 3 ; i++) {
- if ((u_char)inpw((PRA(i)+port)) != OEMID(smc,i))
- return(0) ;
- }
- return(1) ;
-#else /* MULT_OEM */
- smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
- board_logo[0] = (u_char)inpw((PRA(SADDRL)+port)) ;
- bytes_read = 1 ;
-
- for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
- if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
- continue ;
-
- /* Test all read bytes with current OEM_entry */
- /* for (i=0; (i<bytes_read) && (i < SIZE_SKLOGO(smc)); i++) { */
- for (i = 0; i < bytes_read; i++) {
- if (board_logo[i] != SKLOGO(smc,i))
- break ;
- }
-
- /* If mismatch, switch to next OEM entry */
- if ((board_logo[i] != SKLOGO(smc,i)) && (i < bytes_read))
- continue ;
-
- --i ;
- while (bytes_read < SIZE_SKLOGO(smc)) {
- // inpw next byte SK_Logo
- i++ ;
- board_logo[i] = (u_char)inpw((PRA(SADDRL+i)+port)) ;
- bytes_read++ ;
- if (board_logo[i] != SKLOGO(smc,i))
- break ;
- }
-
- for (i = 0 ; i < 3 ; i++)
- id[i] = (u_char)inpw((PRA(i)+port)) ;
-
- if ((board_logo[i] == SKLOGO(smc,i))
- && (bytes_read == SIZE_SKLOGO(smc))) {
-
- if (is_equal_num(&id[0],&OEMID(smc,0),3))
- return(1);
- }
- } /* for */
- return(0) ;
-#endif /* MULT_OEM */
-}
-
-int get_board_para(struct s_smc *smc, int slot)
-{
- SK_UNUSED(smc) ;
- SK_UNUSED(slot) ;
- return(0) ; /* for ISA not supported */
-}
-#endif /* ISA */
-
-#ifdef PCI
-#ifdef USE_BIOS_FUN
-int exist_board(struct s_smc *smc, int slot)
-{
- u_short dev_id ;
- u_short ven_id ;
- int found ;
- int i ;
-
- found = FALSE ; /* make sure we returned with adatper not found*/
- /* if an empty oemids.h was included */
-
-#ifdef MULT_OEM
- smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
- for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
- if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
- continue ;
-#endif
- ven_id = OEMID(smc,0) + (OEMID(smc,1) << 8) ;
- dev_id = OEMID(smc,2) + (OEMID(smc,3) << 8) ;
- for (i = 0; i < slot; i++) {
- if (pci_find_device(i,&smc->hw.pci_handle,
- dev_id,ven_id) != 0) {
-
- found = FALSE ;
- } else {
- found = TRUE ;
- }
- }
- if (found) {
- return(1) ; /* adapter was found */
- }
-#ifdef MULT_OEM
- }
-#endif
- return(0) ; /* adapter was not found */
-}
-#endif /* PCI */
-#endif /* USE_BIOS_FUNC */
-
void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr)
{
int i ;
diff --git a/drivers/net/skfp/h/mbuf.h b/drivers/net/skfp/h/mbuf.h
index b339d1f2e0e..f2aadcda9e7 100644
--- a/drivers/net/skfp/h/mbuf.h
+++ b/drivers/net/skfp/h/mbuf.h
@@ -15,11 +15,7 @@
#ifndef _MBUF_
#define _MBUF_
-#ifndef PCI
-#define M_SIZE 4550
-#else
#define M_SIZE 4504
-#endif
#ifndef MAX_MBUF
#define MAX_MBUF 4
diff --git a/drivers/net/skfp/h/skfbi.h b/drivers/net/skfp/h/skfbi.h
index ba347d6910f..c1ba26c06d7 100644
--- a/drivers/net/skfp/h/skfbi.h
+++ b/drivers/net/skfp/h/skfbi.h
@@ -15,797 +15,11 @@
#ifndef _SKFBI_H_
#define _SKFBI_H_
-#ifdef SYNC
-#define exist_board_far exist_board
-#define get_board_para_far get_board_para
-#endif
-
-/*
- * physical address offset + IO-Port base address
- */
-#ifndef PCI
-#define ADDR(a) ((a)+smc->hw.iop)
-#define ADDRS(smc,a) ((a)+(smc)->hw.iop)
-#endif
-
/*
- * FDDI-Fx (x := {I(SA), E(ISA), M(CA), P(CI)})
+ * FDDI-Fx (x := {I(SA), P(CI)})
* address calculation & function defines
*/
-#ifdef EISA
-
-/*
- * Configuration PROM: !! all 8-Bit IO's !!
- * |<- MAC-Address ->|
- * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/
- * val: |PROD_ID0..3| | free | |00|00|5A|40| |nn|mm|00|00|
- * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/
- * IO- ^ ^ ^ ^ ^
- * port 0C80 0C83 0C88 0C90 0C98
- * | \
- * | \
- * | \______________________________________________
- * EISA Expansion Board Product ID: \
- * BIT: |7 6 5 4 3 2 1 0| \
- * | PROD_ID0 | PROD_ID1 | PROD_ID2 | PROD_ID3 |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * |0| MAN_C0 | MAN_C1 | MAN_C2 | PROD1 | PROD0 | REV1 | REV0 |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * ^=reserved | product numb. | revision numb |
- * MAN_Cx = compressed manufacterer code (x:=0..2)
- * ASCII : 'A'..'Z' : 0x41..0x5A -> compr.(c-0x40) : 0x01..0x1A (5Bits!)
- */
-
-#ifndef MULT_OEM
-#ifndef OEM_CONCEPT
-#define MAN_C0 ('S'-0x40)
-#define MAN_C1 ('K'-0x40)
-#define MAN_C2 ('D'-0x40)
-#define PROD_ID0 (u_char)((MAN_C0<<2) | (MAN_C1>>3))
-#define PROD_ID1 (u_char)(((MAN_C1<<5) & 0xff) | MAN_C2)
-#define PROD_ID2 (u_char)(1) /* prod. nr. */
-#define PROD_ID3 (u_char)(0) /* rev. nr. */
-
-#ifndef OEM_USER_DATA
-#define OEM_USER_DATA "SK-NET FDDI V2.0 Userdata"
-#endif
-#else /* OEM_CONCEPT */
-
-/* MAN_C(0|1|2) no longer present (ra). */
-#define PROD_ID0 (u_char)OEM_PROD_ID0
-#define PROD_ID1 (u_char)OEM_PROD_ID1
-#define PROD_ID2 (u_char)OEM_PROD_ID2
-#define PROD_ID3 (u_char)OEM_PROD_ID3
-#endif /* OEM_CONCEPT */
-
-#define SKLOGO PROD_ID0, PROD_ID1, PROD_ID2, PROD_ID3
-#endif /* MULT_OEM */
-
-#define SADDRL (0) /* start address SKLOGO */
-#define SA_MAC (0x10) /* start addr. MAC_AD within the PROM */
-#define PRA_OFF (4)
-#define SA_PMD_TYPE (8) /* start addr. PMD-Type */
-
-#define SKFDDI_PSZ 32 /* address PROM size */
-
-/*
- * address transmission from logical to physical offset address on board
- */
-#define FMA(a) (0x0400|((a)<<1)) /* FORMAC+ (r/w) */
-#define P1A(a) (0x0800|((a)<<1)) /* PLC1 (r/w) */
-#define P2A(a) (0x0840|((a)<<1)) /* PLC2 (r/w) */
-#define TIA(a) (0x0880|((a)<<1)) /* Timer (r/w) */
-#define PRA(a) (0x0c80| (a)) /* configuration PROM */
-#define C0A(a) (0x0c84| (a)) /* config. RAM */
-#define C1A(a) (0x0ca0| (a)) /* IRQ-, DMA-nr., EPROM type */
-#define C2A(a) (0x0ca4| (a)) /* EPROM and PAGE selector */
-
-#define CONF C0A(0) /* config RAM (card enable bit port) */
-#define PGRA C2A(0) /* Flash page register */
-#define CDID PRA(0) /* Card ID I/O port addr. offset */
-
-
-/*
- * physical address offset + slot specific IO-Port base address
- */
-#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */
-#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */
-#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */
-#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */
-#define PR_A(a) (PRA(a)+smc->hw.iop) /* config. PROM */
-#define C0_A(a) (C0A(a)+smc->hw.iop) /* config. RAM */
-#define C1_A(a) (C1A(a)+smc->hw.iop) /* config. RAM */
-#define C2_A(a) (C2A(a)+smc->hw.iop) /* config. RAM */
-
-
-#define CSRA 0x0008 /* control/status register address (r/w) */
-#define ISRA 0x0008 /* int. source register address (upper 8Bits) */
-#define PLC1I 0x001a /* clear PLC1 interrupt (write only) */
-#define PLC2I 0x0020 /* clear PLC2 interrupt (write only) */
-#define CSFA 0x001c /* control/status FIFO BUSY flags (read only) */
-#define RQAA 0x001c /* Request reg. (write only) */
-#define WCTA 0x001e /* word counter (r/w) */
-#define FFLAG 0x005e /* FLAG/V_FULL (FIFO almost full, write only)*/
-
-#define CSR_A (CSRA+smc->hw.iop) /* control/status register address (r/w) */
-#ifdef UNIX
-#define CSR_AS(smc) (CSRA+(smc)->hw.iop) /* control/status register address (r/w) */
-#endif
-#define ISR_A (ISRA+smc->hw.iop) /* int. source register address (upper 8Bits) */
-#define PLC1_I (PLC1I+smc->hw.iop) /* clear PLC1 internupt (write only) */
-#define PLC2_I (PLC2I+smc->hw.iop) /* clear PLC2 interrupt (write only) */
-#define CSF_A (CSFA+smc->hw.iop) /* control/status FIFO BUSY flags (r/w) */
-#define RQA_A (RQAA+smc->hw.iop) /* Request reg. (write only) */
-#define WCT_A (WCTA+smc->hw.iop) /* word counter (r/w) */
-#define FFLAG_A (FFLAG+smc->hw.iop) /* FLAG/V_FULL (FIFO almost full, write only)*/
-
-/*
- * control/status register CSRA bits
- */
-/* write */
-#define CS_CRESET 0x01 /* Card reset (0=reset) */
-#define CS_RESET_FIFO 0x02 /* FIFO reset (0=reset) */
-#define CS_IMSK 0x04 /* enable IRQ (1=enable, 0=disable) */
-#define CS_EN_IRQ_TC 0x08 /* enable IRQ from transfer counter */
-#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/
-#define CS_LED_0 0x40 /* switch LED 0 */
-#define CS_LED_1 0x80 /* switch LED 1 */
-/* read */
-#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */
-#define CS_SAS 0x80 /* single attachement station (=1) */
-
-/*
- * control/status register CSFA bits (FIFO)
- */
-#define CSF_MUX0 0x01
-#define CSF_MUX1 0x02
-#define CSF_HSREQ0 0x04
-#define CSF_HSREQ1 0x08
-#define CSF_HSREQ2 0x10
-#define CSF_BUSY_DMA 0x40
-#define CSF_BUSY_FIFO 0x80
-
-/*
- * Interrupt source register ISRA (upper 8 data bits) read only & low activ.
- */
-#define IS_MINTR1 0x0100 /* FORMAC ST1U/L & ~IMSK1U/L*/
-#define IS_MINTR2 0x0200 /* FORMAC ST2U/L & ~IMSK2U/L*/
-#define IS_PLINT1 0x0400 /* PLC1 */
-#define IS_PLINT2 0x0800 /* PLC2 */
-#define IS_TIMINT 0x1000 /* Timer 82C54-2 */
-#define IS_TC 0x2000 /* transf. counter */
-
-#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT|IS_TC)
-
-/*
- * CONFIG<0> RAM (C0_A())
- */
-#define CFG_CARD_EN 0x01 /* card enable */
-
-/*
- * CONFIG<1> RAM (C1_A())
- */
-#define CFG_IRQ_SEL 0x03 /* IRQ select (4 nr.) */
-#define CFG_IRQ_TT 0x04 /* IRQ trigger type (LEVEL/EDGE) */
-#define CFG_DRQ_SEL 0x18 /* DMA requ. (4 nr.) */
-#define CFG_BOOT_EN 0x20 /* 0=BOOT-, 1=Application Software */
-#define CFG_PROG_EN 0x40 /* V_Prog for FLASH_PROM (1=on) */
-
-/*
- * CONFIG<2> RAM (C2_A())
- */
-#define CFG_EPROM_SEL 0x0f /* FPROM start address selection */
-#define CFG_PAGE 0xf0 /* FPROM page selection */
-
-
-#define READ_PROM(a) ((u_char)inp(a))
-#define GET_PAGE(i) outp(C2_A(0),((int)(i)<<4) | (inp(C2_A(0)) & ~CFG_PAGE))
-#define FPROM_SW() (inp(C1_A(0)) & CFG_BOOT_EN)
-
-#define MAX_PAGES 16 /* 16 pages */
-#define MAX_FADDR 0x2000 /* 8K per page */
-#define VPP_ON() outp(C1_A(0),inp(C1_A(0)) | CFG_PROG_EN)
-#define VPP_OFF() outp(C1_A(0),inp(C1_A(0)) & ~CFG_PROG_EN)
-
-#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA)
-#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO)
-#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO))
-#define BUS_CHECK()
-
-#ifdef UNISYS
-/* For UNISYS use another macro with drv_usecewait function */
-#define CHECK_DMA() {u_long k = 1000000; \
- while (k && (DMA_BUSY())) { k--; drv_usecwait(20); } \
- if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
-#else
-#define CHECK_DMA() {u_long k = 1000000 ;\
- while (k && (DMA_BUSY())) k-- ;\
- if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
-#endif
-
-#define CHECK_FIFO() {u_long k = 1000000 ;\
- while (k && (FIFO_BUSY())) k-- ;\
- if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; }
-
-#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\
- while (k && (DMA_FIFO_BUSY())) k-- ;\
- if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; }
-
-#define GET_ISR() ~inpw(ISR_A)
-#define CHECK_ISR() ~inpw(ISR_A)
-
-#ifndef UNIX
-#ifndef WINNT
-#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&\
- (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led)
-#else /* WINNT */
-#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A)&\
- (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led)
-#endif /* WINNT */
-#else /* UNIX */
-#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\
- (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|(smc)->hw.led)
-#endif
-
-#ifndef UNIX
-#define STI_FBI() outpw(CSR_A,(inpw(CSR_A)&\
- (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|smc->hw.led)
-#else
-#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\
- (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|(smc)->hw.led)
-#endif
-
-/* EISA DMA Controller */
-#define DMA_WRITE_SINGLE_MASK_BIT_M 0x0a /* Master DMA Controller */
-#define DMA_WRITE_SINGLE_MASK_BIT_S 0xd4 /* Slave DMA Controller */
-#define DMA_CLEAR_BYTE_POINTER_M 0x0c
-#define DMA_CLEAR_BYTE_POINTER_S 0xd8
-
-#endif /* EISA */
-
-#ifdef MCA
-
-/*
- * POS Register: !! all I/O's are 8-Bit !!
- */
-#define POS_SYS_SETUP 0x94 /* system setup register */
-#define POS_SYSTEM 0xff /* system mode */
-
-#define POS_CHANNEL_POS 0x96 /* register slot ID */
-#define POS_CHANNEL_BIT 0x08 /* mask for -"- */
-
-#define POS_BASE 0x100 /* POS base address */
-#define POS_ID_LOW POS_BASE /* card ID low */
-#define POS_ID_HIGH (POS_BASE+1) /* card ID high */
-#define POS_102 (POS_BASE+2) /* card en., arbitration level .. */
-#define POS_103 (POS_BASE+3) /* FPROM addr, page */
-#define POS_104 (POS_BASE+4) /* I/O, IRQ */
-#define POS_105 (POS_BASE+5) /* POS_CHCK */
-#define POS_106 (POS_BASE+6) /* to read VPD */
-#define POS_107 (POS_BASE+7) /* added without function */
-
-/* FM1 card IDs */
-#define FM1_CARD_ID0 0x83
-#define FM1_CARD_ID1 0
-
-#define FM1_IBM_ID0 0x9c
-#define FM1_IBM_ID1 0x8f
-
-
-/* FM2 card IDs */
-#define FM2_CARD_ID0 0xab
-#define FM2_CARD_ID1 0
-
-#define FM2_IBM_ID0 0x7e
-#define FM2_IBM_ID1 0x8f
-
-/* Board revision. */
-#define FM1_REV 0
-#define FM2_REV 1
-
-#define MAX_SLOT 8
-
-/*
- * POS_102
- */
-#define POS_CARD_EN 0x01 /* card enable =1 */
-#define POS_SDAT_EN 0x02 /* enable 32-bit streaming data mode */
-#define POS_EN_CHKINT 0x04 /* enable int. from check line asserted */
-#define POS_EN_BUS_ERR 0x08 /* enable int. on invalid busmaster transf. */
-#define POS_FAIRNESS 0x10 /* fairnes on =1 */
-/* attention: arbitration level used with bit 0 POS 105 */
-#define POS_LARBIT 0xe0 /* arbitration level (0,0,0)->level = 0x8
- (1,1,1)->level = 0xf */
-/*
- * POS_103
- */
-#define POS_PAGE 0x07 /* FPROM page selection */
-#define POS_BOOT_EN 0x08 /* boot PROM enable =1 */
-#define POS_MSEL 0x70 /* memory start address for FPROM mapping */
-#define PROG_EN 0x80 /* FM1: Vpp prog on/off */
-#define POS_SDR 0x80 /* FM2: Streaming data bit */
-
-/*
- * POS_104
- */
-#define POS_IOSEL 0x3f /* selected I/O base address */
-#define POS_IRQSEL 0xc0 /* selected interrupt */
-
-/*
- * POS_105
- */
-#define POS_CHCK 0x80
-#define POS_SYNC_ERR 0x20 /* FM2: synchronous error reporting */
-#define POS_PAR_DATA 0x10 /* FM2: data parity enable bit */
-#define POS_PAR_ADDR 0x08 /* FM2: address parity enable bit */
-#define POS_IRQHSEL 0x02 /* FM2: Highest bit for IRQ_selection */
-#define POS_HARBIT 0x01 /* Highest bit in Bus arbitration selection */
-
-#define SA_MAC (0) /* start addr. MAC_AD within the PROM */
-#define PRA_OFF (0)
-#define SA_PMD_TYPE (8) /* start addr. PMD-Type */
-
-/*
- * address transmission from logical to physical offset address on board
- */
-#define FMA(a) (0x0100|((a)<<1)) /* FORMAC+ (r/w) */
-#define P2(a) (0x00c0|((a)<<1)) /* PLC2 (r/w) (DAS) */
-#define P1(a) (0x0080|((a)<<1)) /* PLC1 (r/w) */
-#define TI(a) (0x0060|((a)<<1)) /* Timer (r/w) */
-#define PR(a) (0x0040|((a)<<1)) /* configuration PROM */
-#define CS(a) (0x0020| (a)) /* control/status */
-#define FF(a) (0x0010|((a)<<1)) /* FIFO ASIC */
-#define CT(a) (0x0000|((a)<<1)) /* counter */
-
-/*
- * counter
- */
-#define ACLA CT(0) /* address counter low */
-#define ACHA CT(1) /* address counter high */
-#define BCN CT(2) /* byte counter */
-#define MUX CT(3) /* MUX-register */
-#define WCN CT(0x08) /* word counter */
-#define FFLG CT(0x09) /* FIFO Flags */
-
-/*
- * test/control register (FM2 only)
- */
-#define CNT_TST 0x018 /* Counter test control register */
-#define CNT_STP 0x01a /* Counter test step reg. (8 Bit) */
-
-/*
- * CS register (read only)
- */
-#define CSRA CS(0) /* control/status register address */
-#define CSFA CS(2) /* control/status FIFO BUSY ... */
-#define ISRA CS(4) /* first int. source register address */
-#define ISR2 CS(6) /* second int. source register address */
-#define LEDR CS(0x0c) /* LED register r/w */
-#define CSIL CS(0x10) /* I/O mapped POS_ID_low (100) */
-#define CSIH CS(0x12) /* - " - POS_ID_HIGH (101) */
-#define CSA CS(0x14) /* - " - POS_102 */
-#define CSM CS(0x0e) /* - " - POS_103 */
-#define CSM_FM1 CS(0x16) /* - " - POS_103 (copy in FM1) */
-#define CSI CS(0x18) /* - " - POS_104 */
-#define CSS CS(0x1a) /* - " - POS_105 */
-#define CSP_06 CS(0x1c) /* - " - POS_106 */
-#define WDOG_ST 0x1c /* Watchdog status (FM2 only) */
-#define WDOG_EN 0x1c /* Watchdog enabling (FM2 only, 8Bit) */
-#define WDOG_DIS 0x1e /* Watchdog disabling (FM2 only, 8Bit) */
-
-#define PGRA CSM /* Flash page register */
-
-
-#define WCTA FF(0) /* word counter */
-#define FFLAG FF(1) /* FLAG/V_FULL (FIFO almost full, write only)*/
-
-/*
- * Timer register (FM2 only)
- */
-#define RTM_CNT 0x28 /* RTM Counter */
-#define TI_DIV 0x60 /* Timer Prescaler */
-#define TI_CH1 0x62 /* Timer channel 1 counter */
-#define TI_STOP 0x64 /* Stop timer on channel 1 */
-#define TI_STRT 0x66 /* Start timer on channel 1 */
-#define TI_INI2 0x68 /* Timer: Bus master preemption */
-#define TI_CNT2 0x6a /* Timer */
-#define TI_INI3 0x6c /* Timer: Streaming data */
-#define TI_CNT3 0x6e /* Timer */
-#define WDOG_LO 0x70 /* Watchdog counter low */
-#define WDOG_HI 0x72 /* Watchdog counter high */
-#define RTM_PRE 0x74 /* restr. token prescaler */
-#define RTM_TIM 0x76 /* restr. token timer */
-
-/*
- * Recommended Timeout values (for FM2 timer only)
- */
-#define TOUT_BM_PRE 188 /* 3.76 usec */
-#define TOUT_S_DAT 374 /* 7.48 usec */
-
-/*
- * CS register (write only)
- */
-#define HSR(p) CS(0x18|(p)) /* Host request register */
-
-#define RTM_PUT 0x36 /* restr. token counter write */
-#define RTM_GET 0x28 /* - " - clear */
-#define RTM_CLEAR 0x34 /* - " - read */
-
-/*
- * BCN Bit definitions
- */
-#define BCN_BUSY 0x8000 /* DMA Busy flag */
-#define BCN_AZERO 0x4000 /* Almost zero flag (BCN < 4) */
-#define BCN_STREAM 0x2000 /* Allow streaming data (BCN >= 8) */
-
-/*
- * WCN Bit definitions
- */
-#define WCN_ZERO 0x2000 /* Zero flag (counted to zero) */
-#define WCN_AZERO 0x1000 /* Almost zero flag (BCN < 4) */
-
-/*
- * CNT_TST Bit definitions
- */
-#define CNT_MODE 0x01 /* Go into test mode */
-#define CNT_D32 0x02 /* 16/32 BIT test mode */
-
-/*
- * FIFO Flag FIFO Flags/Vfull register
- */
-#define FF_VFULL 0x003f /* V_full value mask */
-#define FFLG_FULL 0x2000 /* FULL flag */
-#define FFLG_A_FULL 0x1000 /* Almost full flag */
-#define FFLG_VFULL 0x0800 /* V_full Flag */
-#define FFLG_A_EMP 0x0400 /* almost empty flag */
-#define FFLG_EMP 0x0200 /* empty flag */
-#define FFLG_T_EMP 0x0100 /* totally empty flag */
-
-/*
- * WDOG Watchdog status register
- */
-#define WDOG_ALM 0x01 /* Watchdog alarm Bit */
-#define WDOG_ACT 0x02 /* Watchdog active Bit */
-
-/*
- * CS(0) CONTROLS
- */
-#define CS_CRESET 0x0001
-#define FIFO_RST 0x0002
-#define CS_IMSK 0x0004
-#define EN_IRQ_CHCK 0x0008
-#define EN_IRQ_TOKEN 0x0010
-#define EN_IRQ_TC 0x0020
-#define TOKEN_STATUS 0x0040
-#define RTM_CHANGE 0x0080
-
-#define CS_SAS 0x0100
-#define CS_BYSTAT 0x0200 /* bypass connected (0=conn.) */
-#define CS_BYPASS 0x0400 /* bypass on/off indication */
-
-/*
- * CS(2) FIFOSTAT
- */
-#define HSREQ 0x0007
-#define BIGDIR 0x0008
-#define CSF_BUSY_FIFO 0x0010
-#define CSF_BUSY_DMA 0x0020
-#define SLOT_32 0x0040
-
-#define LED_0 0x0001
-#define LED_1 0x0002
-#define LED_2 0x0100
-
-#define MAX_PAGES 8 /* pages */
-#define MAX_FADDR 0x4000 /* 16K per page */
-
-/*
- * IRQ = ISRA || ISR2 ;
- *
- * ISRA = IRQ_OTH_EN && (IS_LAN | IS_BUS) ;
- * ISR2 = IRQ_TC_EN && IS_TC ;
- *
- * IS_LAN = (IS_MINTR1 | IS_MINTR2 | IS_PLINT1 | IS_PLINT2 | IS_TIMINT) ||
- * (IRQ_EN_TOKEN && IS_TOKEN) ;
- * IS_BUS = IRQ_CHCK_EN && (IS_BUSERR | IS_CHCK_L) ;
- */
-/*
- * ISRA !!! activ high !!!
- */
-#define IS_MINTR1 0x0001 /* FORMAC ST1U/L & ~IMSK1U/L*/
-#define IS_MINTR2 0x0002 /* FORMAC ST2U/L & ~IMSK2U/L*/
-#define IS_PLINT1 0x0004 /* PLC1 */
-#define IS_PLINT2 0x0008 /* PLC2 */
-#define IS_TIMINT 0x0010 /* Timer 82C54-2 */
-#define IS_TOKEN 0x0020 /* restrictet token monitoring */
-#define IS_CHCK_L 0x0040 /* check line asserted */
-#define IS_BUSERR 0x0080 /* bus error */
-/*
- * ISR2
- */
-#define IS_TC 0x0001 /* terminal count irq */
-#define IS_SFDBKRTN 0x0002 /* selected feedback return */
-#define IS_D16 0x0004 /* DS16 */
-#define IS_D32 0x0008 /* DS32 */
-#define IS_DPEI 0x0010 /* Data Parity Indication */
-
-#define ALL_IRSR 0x00ff
-
-#define FM_A(a) ADDR(FMA(a)) /* FORMAC Plus physical addr */
-#define P1_A(a) ADDR(P1(a)) /* PLC1 (r/w) */
-#define P2_A(a) ADDR(P2(a)) /* PLC2 (r/w) (DAS) */
-#define TI_A(a) ADDR(TI(a)) /* Timer (r/w) FM1 only! */
-#define PR_A(a) ADDR(PR(a)) /* config. PROM */
-#define CS_A(a) ADDR(CS(a)) /* control/status */
-
-#define ISR1_A ADDR(ISRA) /* first int. source register address */
-#define ISR2_A ADDR(ISR2) /* second -"- */
-#define CSR_A ADDR(CSRA) /* control/status register address */
-#define CSF_A ADDR(CSFA) /* control/status FIFO BUSY flags (r/w) */
-
-#define CSIL_A ADDR(CSIL) /* I/O mapped POS_ID_low (102) */
-#define CSIH_A ADDR(CSIH) /* - " - POS_ID_HIGH (101) */
-#define CSA_A ADDR(CSA) /* - " - POS_102 */
-#define CSI_A ADDR(CSI) /* - " - POS_104 */
-#define CSM_A ADDR(CSM) /* - " - POS_103 */
-#define CSM_FM1_A ADDR(CSM_FM1) /* - " - POS_103 (2nd copy, FM1) */
-#define CSP_06_A ADDR(CSP_06) /* - " - POS_106 */
-
-#define WCT_A ADDR(WCTA) /* word counter (r/w) */
-#define FFLAG_A ADDR(FFLAG) /* FLAG/V_FULL (FIFO almost full, write only)*/
-
-#define ACL_A ADDR(ACLA) /* address counter low */
-#define ACH_A ADDR(ACHA) /* address counter high */
-#define BCN_A ADDR(BCN) /* byte counter */
-#define MUX_A ADDR(MUX) /* MUX-register */
-
-#define ISR_A ADDR(ISRA) /* Interrupt Source Register */
-#define FIFO_RESET_A ADDR(FIFO_RESET) /* reset the FIFO */
-#define FIFO_EN_A ADDR(FIFO_EN) /* enable the FIFO */
-
-#define WDOG_EN_A ADDR(WDOG_EN) /* reset and start the WDOG */
-#define WDOG_DIS_A ADDR(WDOG_DIS) /* disable the WDOG */
-/*
- * all control reg. (read!) are 8 bit (except PAGE_RG_A and LEDR_A)
- */
-#define HSR_A(p) ADDR(HSR(p)) /* Host request register */
-
-#define STAT_BYP 0 /* bypass station */
-#define STAT_INS 2 /* insert station */
-#define BYPASS(o) CS(0x10|(o)) /* o=STAT_BYP || STAT_INS */
-
-#define IRQ_TC_EN CS(0x0b) /* enable/disable IRQ on TC */
-#define IRQ_TC_DIS CS(0x0a)
-#define IRQ_TOKEN_EN CS(9) /* enable/disable IRQ on restr. Token */
-#define IRQ_TOKEN_DIS CS(8)
-#define IRQ_CHCK_EN CS(7) /* -"- IRQ after CHCK line */
-#define IRQ_CHCK_DIS CS(6)
-#define IRQ_OTH_EN CS(5) /* -"- other IRQ's */
-#define IRQ_OTH_DIS CS(4)
-#define FIFO_EN CS(3) /* disable (reset), enable FIFO */
-#define FIFO_RESET CS(2)
-#define CARD_EN CS(1) /* disable (reset), enable card */
-#define CARD_DIS CS(0)
-
-#define LEDR_A ADDR(LEDR) /* D0=green, D1=yellow, D8=L2 */
-#define PAGE_RG_A ADDR(CSM) /* D<2..0> */
-#define IRQ_CHCK_EN_A ADDR(IRQ_CHCK_EN)
-#define IRQ_CHCK_DIS_A ADDR(IRQ_CHCK_DIS)
-
-#define GET_PAGE(bank) outpw(PAGE_RG_A,(inpw(PAGE_RG_A) &\
- (~POS_PAGE)) |(int) (bank))
-#define VPP_ON() if (smc->hw.rev == FM1_REV) { \
- outpw(PAGE_RG_A, \
- (inpw(PAGE_RG_A) & POS_PAGE) | PROG_EN); \
- }
-#define VPP_OFF() if (smc->hw.rev == FM1_REV) { \
- outpw(PAGE_RG_A,(inpw(PAGE_RG_A) & POS_PAGE)); \
- }
-
-#define SKFDDI_PSZ 16 /* address PROM size */
-
-#define READ_PROM(a) ((u_char)inp(a))
-
-#define GET_ISR() ~inpw(ISR1_A)
-#ifndef TCI
-#define CHECK_ISR() ~inpw(ISR1_A)
-#define CHECK_ISR_SMP(iop) ~inpw((iop)+ISRA)
-#else
-#define CHECK_ISR() (~inpw(ISR1_A) | ~inpw(ISR2_A))
-#define CHECK_ISR_SMP(iop) (~inpw((iop)+ISRA) | ~inpw((iop)+ISR2))
-#endif
-
-#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA)
-#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO)
-#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO))
-#define BUS_CHECK() { int i ; \
- if ((i = GET_ISR()) & IS_BUSERR) \
- SMT_PANIC(smc,HWM_E0020,HWM_E0020_MSG) ; \
- if (i & IS_CHCK_L) \
- SMT_PANIC(smc,HWM_E0014,HWM_E0014_MSG) ; \
- }
-
-#define CHECK_DMA() { u_long k = 10000 ; \
- while (k && (DMA_BUSY())) { \
- k-- ; \
- BUS_CHECK() ; \
- } \
- if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
-
-#define CHECK_FIFO() {u_long k = 1000000 ;\
- while (k && (FIFO_BUSY())) k-- ;\
- if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; }
-
-#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\
- while (k && (DMA_FIFO_BUSY())) { \
- k-- ;\
- BUS_CHECK() ; \
- } \
- if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; }
-
-#ifndef UNIX
-#define CLI_FBI() outp(ADDR(IRQ_OTH_DIS),0)
-#else
-#define CLI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_DIS),0)
-#endif
-
-#ifndef TCI
-#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0)
-#else
-#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0) ;\
- outp((iop)+IRQ_TC_DIS,0)
-#endif
-
-#ifndef UNIX
-#define STI_FBI() outp(ADDR(IRQ_OTH_EN),0)
-#else
-#define STI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_EN),0)
-#endif
-
-/*
- * Terminal count primitives
- */
-#define CLI_TCI(smc) outp(ADDRS((smc),IRQ_TC_DIS),0)
-#define STI_TCI(smc) outp(ADDRS((smc),IRQ_TC_EN),0)
-#define CHECK_TC(smc,k) {(k) = 10000 ;\
- while ((k) && (~inpw(ISR2_A) & IS_TC)) (k)-- ;\
- if (!k) SMT_PANIC(smc,HWM_E0018,HWM_E0018_MSG) ; }
-
-#endif /* MCA */
-
-#ifdef ISA
-
-/*
- * address transmission from logic NPADDR6-0 to physical offset address on board
- */
-#define FMA(a) (0x8000|(((a)&0x07)<<1)|(((a)&0x78)<<7)) /* FORMAC+ (r/w) */
-#define PRA(a) (0x1000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PROM (read only)*/
-#define P1A(a) (0x4000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC1 (r/w) */
-#define P2A(a) (0x5000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC2 (r/w) */
-#define TIA(a) (0x6000|(((a)&0x03)<<1)) /* Timer (r/w) */
-
-#define ISRA 0x0000 /* int. source register address (read only) */
-#define ACLA 0x0000 /* address counter low address (write only) */
-#define ACHA 0x0002 /* address counter high address (write only) */
-#define TRCA 0x0004 /* transfer counter address (write only) */
-#define PGRA 0x0006 /* page register address (write only) */
-#define RQAA 0x2000 /* Request reg. (write only) */
-#define CSRA 0x3000 /* control/status register address (r/w) */
-
-/*
- * physical address offset + IO-Port base address
- */
-#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */
-#define PR_A(a) (PRA(a)+smc->hw.iop) /* PROM (read only)*/
-#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */
-#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */
-#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */
-
-#define ISR_A (0x0000+smc->hw.iop) /* int. source register address (read only) */
-#define ACL_A (0x0000+smc->hw.iop) /* address counter low address (write only) */
-#define ACH_A (0x0002+smc->hw.iop) /* address counter high address (write only)*/
-#define TRC_A (0x0004+smc->hw.iop) /* transfer counter address (write only) */
-#define PGR_A (0x0006+smc->hw.iop) /* page register address (write only) */
-#define RQA_A (0x2000+smc->hw.iop) /* Request reg. (write only) */
-#define CSR_A (0x3000+smc->hw.iop) /* control/status register address (r/w) */
-#ifdef UNIX
-#define CSR_AS(smc) (0x3000+(smc)->hw.iop) /* control/status register address */
-#endif
-#define PLC1_I (0x3400+smc->hw.iop) /* clear PLC1 interrupt bit */
-#define PLC2_I (0x3800+smc->hw.iop) /* clear PLC2 interrupt bit */
-
-#ifndef MULT_OEM
-#ifndef OEM_CONCEPT
-#define SKLOGO_STR "SKFDDI"
-#else /* OEM_CONCEPT */
-#define SKLOGO_STR OEM_FDDI_LOGO
-#endif /* OEM_CONCEPT */
-#endif /* MULT_OEM */
-#define SADDRL (24) /* start address SKLOGO */
-#define SA_MAC (0) /* start addr. MAC_AD within the PROM */
-#define PRA_OFF (0)
-#define SA_PMD_TYPE (8) /* start addr. PMD-Type */
-
-#define CDID (PRA(SADDRL)) /* Card ID int/O port addr. offset */
-#define NEXT_CDID ((PRA(SADDRL+1)) - CDID)
-
-#define SKFDDI_PSZ 32 /* address PROM size */
-
-#define READ_PROM(a) ((u_char)inpw(a))
-#define GET_PAGE(i) outpw(PGR_A,(int)(i))
-
-#define MAX_PAGES 16 /* 16 pages */
-#define MAX_FADDR 0x2000 /* 8K per page */
-#define VPP_OFF() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)))
-#define VPP_ON() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)) | \
- CS_VPPSW)
-
-/*
- * control/status register CSRA bits (log. addr: 0x3000)
- */
-/* write */
-#define CS_CRESET 0x01 /* Card reset (0=reset) */
-#define CS_IMSK 0x02 /* enable IRQ (1=enable, 0=disable) */
-#define CS_RESINT1 0x04 /* PLINT1 reset */
-#define CS_VPPSW 0x10 /* 12V power switch (0=off, 1=on) */
-#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/
-#define CS_RESINT2 0x40 /* PLINT2 reset */
-/* read */
-#define CS_BUSY 0x04 /* master transfer activ (=1) */
-#define CS_SW_EPROM 0x08 /* 0=Application Soft. 1=BOOT-EPROM */
-#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */
-#define CS_SAS 0x80 /* single attachement station (=1) */
-
-/*
- * Interrupt source register ISRA (log. addr: 0x0000) read only & low activ.
- */
-#define IS_MINTR1 0x01 /* FORMAC ST1U/L && ~IMSK1U/L*/
-#define IS_MINTR2 0x02 /* FORMAC ST2U/L && ~IMSK2U/L*/
-#define IS_PLINT1 0x04 /* PLC1 */
-#define IS_PLINT2 0x08 /* PLC2 */
-#define IS_TIMINT 0x10 /* Timer 82C54-2 */
-
-#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT)
-
-#define FPROM_SW() (inpw(CSR_A)&CS_SW_EPROM)
-#define DMA_BUSY() (inpw(CSR_A)&CS_BUSY)
-#define CHECK_FIFO()
-#define BUS_CHECK()
-
-/*
- * set Host Request register (wr.)
- */
-#define SET_HRQ(qup) outpw(RQA_A+((qup)<<1),0)
-
-#ifndef UNIX
-#ifndef WINNT
-#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&(CS_CRESET|CS_BYPASS|CS_VPPSW)))
-#else
-#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A) & \
- (CS_CRESET|CS_BYPASS|CS_VPPSW)))
-#endif
-#else
-#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))& \
- (CS_CRESET|CS_BYPASS|CS_VPPSW)))
-#endif
-
-#ifndef UNIX
-#define STI_FBI() outpw(CSR_A,(inpw(CSR_A) & \
- (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK)
-#else
-#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc)) & \
- (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK)
-#endif
-
-#define CHECK_DMA() {unsigned k = 10000 ;\
- while (k && (DMA_BUSY())) k-- ;\
- if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
-
-#define GET_ISR() ~inpw(ISR_A)
-
-#endif /* ISA */
-
/*--------------------------------------------------------------------------*/
#ifdef PCI
diff --git a/drivers/net/skfp/h/skfbiinc.h b/drivers/net/skfp/h/skfbiinc.h
index 79d55ad2cd2..ac2d7192f1c 100644
--- a/drivers/net/skfp/h/skfbiinc.h
+++ b/drivers/net/skfp/h/skfbiinc.h
@@ -22,32 +22,6 @@
*/
#define ERR_FLAGS (FS_MSRABT | FS_SEAC2 | FS_SFRMERR | FS_SFRMTY1)
-#ifdef ISA
-#define DMA_BUSY_CHECK CSRA
-#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT)
-#define HRQR (RQAA+(RQ_RRQ<<1))
-#define HRQW (RQAA+(RQ_WA2<<1))
-#define HRQA0 (RQAA+(RQ_WA0<<1))
-#define HRQSQ (RQAA+(RQ_WSQ<<1))
-#endif
-
-#ifdef EISA
-#define DMA_BUSY_CHECK CSRA
-#define DMA_HIGH_WORD 0x0400
-#define DMA_MASK_M 0x0a
-#define DMA_MODE_M 0x0b
-#define DMA_BYTE_PTR_M 0x0c
-#define DMA_MASK_S 0x0d4
-#define DMA_MODE_S 0x0d6
-#define DMA_BYTE_PTR_S 0x0d8
-#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TC)
-#endif /* EISA */
-
-#ifdef MCA
-#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
- IS_CHCK_L | IS_BUSERR)
-#endif
-
#ifdef PCI
#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
IS_MINTR2 | IS_MINTR3 | IS_R1_P | \
diff --git a/drivers/net/skfp/h/targethw.h b/drivers/net/skfp/h/targethw.h
index 22c4923241d..626dc726359 100644
--- a/drivers/net/skfp/h/targethw.h
+++ b/drivers/net/skfp/h/targethw.h
@@ -53,11 +53,6 @@ struct s_oem_ids {
u_char oi_sub_id[4] ; /* sub id bytes, representation as */
/* defined by hardware, */
#endif
-#ifdef ISA
- u_char oi_logo_len ; /* the length of the adapter logo */
- u_char oi_logo[6] ; /* the adapter logo */
- u_char oi_reserved1 ;
-#endif /* ISA */
} ;
#endif /* MULT_OEM */
@@ -70,43 +65,17 @@ struct s_smt_hw {
short dma ; /* DMA channel */
short irq ; /* IRQ level */
short eprom ; /* FLASH prom */
-#ifndef PCI
- short DmaWriteExtraBytes ; /* add bytes for DMA write */
-#endif
#ifndef SYNC
u_short n_a_send ; /* pending send requests */
#endif
-#if (defined(EISA) || defined(MCA) || defined(PCI))
+#if defined(PCI)
short slot ; /* slot number */
short max_slots ; /* maximum number of slots */
-#endif
-
-#if (defined(PCI) || defined(MCA))
short wdog_used ; /* TRUE if the watch dog is used */
#endif
-#ifdef MCA
- short slot_32 ; /* 32bit slot (1) or 16bit slot (0) */
- short rev ; /* Board revision (FMx_REV). */
- short VFullRead ; /* V_full value for DMA read */
- short VFullWrite ; /* V_full value for DMA write */
-#endif
-
-#ifdef EISA
- short led ; /* LED for FE card */
-
- short dma_rmode ; /* read mode */
- short dma_wmode ; /* write mode */
- short dma_emode ; /* extend mode */
-
- /* DMA controller channel dependent io addresses */
- u_short dma_base_word_count ;
- u_short dma_base_address ;
- u_short dma_base_address_page ;
-#endif
-
#ifdef PCI
u_short pci_handle ; /* handle to access the BIOS func */
u_long is_imask ; /* int maske for the int source reg */
diff --git a/drivers/net/skfp/hwt.c b/drivers/net/skfp/hwt.c
index e01f8a0f35c..053151468f9 100644
--- a/drivers/net/skfp/hwt.c
+++ b/drivers/net/skfp/hwt.c
@@ -77,25 +77,10 @@ void hwt_start(struct s_smc *smc, u_long time)
*/
if (!cnt)
cnt++ ;
-#ifndef PCI
- /*
- * 6.25MHz -> CLK0 : T0 (cnt0 = 16us) -> OUT0
- * OUT0 -> CLK1 : T1 (cnt1) OUT1 -> ISRA(IS_TIMINT)
- */
- OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */
- OUT_82c54_TIMER(1,cnt & 0xff) ; /* LSB */
- OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ; /* MSB */
- /*
- * start timer by switching counter 0 to mode 3
- * T0 resolution 16 us (CLK0=0.16us)
- */
- OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ; /* counter 0, mode 3 */
- OUT_82c54_TIMER(0,100) ; /* LSB */
- OUT_82c54_TIMER(0,0) ; /* MSB */
-#else /* PCI */
+
outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ; /* Load timer value. */
outpw(ADDR(B2_TI_CRTL), TIM_START) ; /* Start timer. */
-#endif /* PCI */
+
smc->hw.timer_activ = TRUE ;
}
@@ -115,15 +100,8 @@ void hwt_start(struct s_smc *smc, u_long time)
************************/
void hwt_stop(struct s_smc *smc)
{
-#ifndef PCI
- /* stop counter 0 by switching to mode 0 */
- OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ; /* counter 0, mode 0 */
- OUT_82c54_TIMER(0,0) ; /* LSB */
- OUT_82c54_TIMER(0,0) ; /* MSB */
-#else /* PCI */
outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;
-#endif /* PCI */
smc->hw.timer_activ = FALSE ;
}
@@ -168,11 +146,6 @@ void hwt_init(struct s_smc *smc)
void hwt_restart(struct s_smc *smc)
{
hwt_stop(smc) ;
-#ifndef PCI
- OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */
- OUT_82c54_TIMER(1,1 ) ; /* LSB */
- OUT_82c54_TIMER(1,0 ) ; /* MSB */
-#endif
}
/************************
@@ -191,21 +164,12 @@ void hwt_restart(struct s_smc *smc)
u_long hwt_read(struct s_smc *smc)
{
u_short tr ;
-#ifndef PCI
- u_short is ;
-#else
u_long is ;
-#endif
if (smc->hw.timer_activ) {
hwt_stop(smc) ;
-#ifndef PCI
- OUT_82c54_TIMER(3,1<<6) ; /* latch command */
- tr = IN_82c54_TIMER(1) & 0xff ;
- tr += (IN_82c54_TIMER(1) & 0xff)<<8 ;
-#else /* PCI */
tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;
-#endif /* PCI */
+
is = GET_ISR() ;
/* Check if timer expired (or wraparound). */
if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index a7ef6c8b772..7cf9b9f35de 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -260,9 +260,7 @@ static int skfp_init_one(struct pci_dev *pdev,
dev->set_multicast_list = &skfp_ctl_set_multicast_list;
dev->set_mac_address = &skfp_ctl_set_mac_address;
dev->do_ioctl = &skfp_ioctl;
- dev->header_cache_update = NULL; /* not supported */
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/* Initialize board structure with bus-specific info */
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index 75afc1f07ba..ced2c8f76be 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -1654,7 +1654,7 @@ static const struct smt_pdef {
{ SMT_P4053, 0, SWAP_SMT_P4053 } ,
} ;
-#define N_SMT_PLEN (sizeof(smt_pdef)/sizeof(smt_pdef[0]))
+#define N_SMT_PLEN ARRAY_SIZE(smt_pdef)
int smt_check_para(struct s_smc *smc, struct smt_header *sm,
const u_short list[])
diff --git a/drivers/net/skfp/srf.c b/drivers/net/skfp/srf.c
index 16573aca8b6..6caf713b744 100644
--- a/drivers/net/skfp/srf.c
+++ b/drivers/net/skfp/srf.c
@@ -43,7 +43,7 @@ static void clear_reported(struct s_smc *smc);
static void smt_send_srf(struct s_smc *smc);
static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index);
-#define MAX_EVCS (sizeof(smc->evcs)/sizeof(smc->evcs[0]))
+#define MAX_EVCS ARRAY_SIZE(smc->evcs)
struct evc_init {
u_char code ;
@@ -67,7 +67,7 @@ static const struct evc_init evc_inits[] = {
{ SMT_EVENT_PORT_PATH_CHANGE, INDEX_PORT,NUMPHYS,SMT_P4053 } ,
} ;
-#define MAX_INIT_EVC (sizeof(evc_inits)/sizeof(evc_inits[0]))
+#define MAX_INIT_EVC ARRAY_SIZE(evc_inits)
void smt_init_evc(struct s_smc *smc)
{
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index e3d8520209b..6d62250fba0 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -36,13 +36,15 @@
#include <linux/delay.h>
#include <linux/crc32.h>
#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <linux/mii.h>
#include <asm/irq.h>
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.11"
+#define DRV_VERSION "1.12"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
@@ -57,7 +59,10 @@
#define TX_WATCHDOG (5 * HZ)
#define NAPI_WEIGHT 64
#define BLINK_MS 250
-#define LINK_HZ (HZ/2)
+#define LINK_HZ HZ
+
+#define SKGE_EEPROM_MAGIC 0x9933aabb
+
MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
@@ -410,9 +415,14 @@ static const struct skge_stat {
{ "rx_fcs_error", XM_RXF_FCS_ERR, GM_RXF_FCS_ERR },
};
-static int skge_get_stats_count(struct net_device *dev)
+static int skge_get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(skge_stats);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(skge_stats);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void skge_get_ethtool_stats(struct net_device *dev,
@@ -440,15 +450,15 @@ static struct net_device_stats *skge_get_stats(struct net_device *dev)
else
yukon_get_stats(skge, data);
- skge->net_stats.tx_bytes = data[0];
- skge->net_stats.rx_bytes = data[1];
- skge->net_stats.tx_packets = data[2] + data[4] + data[6];
- skge->net_stats.rx_packets = data[3] + data[5] + data[7];
- skge->net_stats.multicast = data[3] + data[5];
- skge->net_stats.collisions = data[10];
- skge->net_stats.tx_aborted_errors = data[12];
+ dev->stats.tx_bytes = data[0];
+ dev->stats.rx_bytes = data[1];
+ dev->stats.tx_packets = data[2] + data[4] + data[6];
+ dev->stats.rx_packets = data[3] + data[5] + data[7];
+ dev->stats.multicast = data[3] + data[5];
+ dev->stats.collisions = data[10];
+ dev->stats.tx_aborted_errors = data[12];
- return &skge->net_stats;
+ return &dev->stats;
}
static void skge_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -793,6 +803,98 @@ static int skge_phys_id(struct net_device *dev, u32 data)
return 0;
}
+static int skge_get_eeprom_len(struct net_device *dev)
+{
+ struct skge_port *skge = netdev_priv(dev);
+ u32 reg2;
+
+ pci_read_config_dword(skge->hw->pdev, PCI_DEV_REG2, &reg2);
+ return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8);
+}
+
+static u32 skge_vpd_read(struct pci_dev *pdev, int cap, u16 offset)
+{
+ u32 val;
+
+ pci_write_config_word(pdev, cap + PCI_VPD_ADDR, offset);
+
+ do {
+ pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
+ } while (!(offset & PCI_VPD_ADDR_F));
+
+ pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &val);
+ return val;
+}
+
+static void skge_vpd_write(struct pci_dev *pdev, int cap, u16 offset, u32 val)
+{
+ pci_write_config_dword(pdev, cap + PCI_VPD_DATA, val);
+ pci_write_config_word(pdev, cap + PCI_VPD_ADDR,
+ offset | PCI_VPD_ADDR_F);
+
+ do {
+ pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
+ } while (offset & PCI_VPD_ADDR_F);
+}
+
+static int skge_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+ u8 *data)
+{
+ struct skge_port *skge = netdev_priv(dev);
+ struct pci_dev *pdev = skge->hw->pdev;
+ int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD);
+ int length = eeprom->len;
+ u16 offset = eeprom->offset;
+
+ if (!cap)
+ return -EINVAL;
+
+ eeprom->magic = SKGE_EEPROM_MAGIC;
+
+ while (length > 0) {
+ u32 val = skge_vpd_read(pdev, cap, offset);
+ int n = min_t(int, length, sizeof(val));
+
+ memcpy(data, &val, n);
+ length -= n;
+ data += n;
+ offset += n;
+ }
+ return 0;
+}
+
+static int skge_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+ u8 *data)
+{
+ struct skge_port *skge = netdev_priv(dev);
+ struct pci_dev *pdev = skge->hw->pdev;
+ int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD);
+ int length = eeprom->len;
+ u16 offset = eeprom->offset;
+
+ if (!cap)
+ return -EINVAL;
+
+ if (eeprom->magic != SKGE_EEPROM_MAGIC)
+ return -EINVAL;
+
+ while (length > 0) {
+ u32 val;
+ int n = min_t(int, length, sizeof(val));
+
+ if (n < sizeof(val))
+ val = skge_vpd_read(pdev, cap, offset);
+ memcpy(&val, data, n);
+
+ skge_vpd_write(pdev, cap, offset, val);
+
+ length -= n;
+ data += n;
+ offset += n;
+ }
+ return 0;
+}
+
static const struct ethtool_ops skge_ethtool_ops = {
.get_settings = skge_get_settings,
.set_settings = skge_set_settings,
@@ -805,21 +907,22 @@ static const struct ethtool_ops skge_ethtool_ops = {
.set_msglevel = skge_set_msglevel,
.nway_reset = skge_nway_reset,
.get_link = ethtool_op_get_link,
+ .get_eeprom_len = skge_get_eeprom_len,
+ .get_eeprom = skge_get_eeprom,
+ .set_eeprom = skge_set_eeprom,
.get_ringparam = skge_get_ring_param,
.set_ringparam = skge_set_ring_param,
.get_pauseparam = skge_get_pauseparam,
.set_pauseparam = skge_set_pauseparam,
.get_coalesce = skge_get_coalesce,
.set_coalesce = skge_set_coalesce,
- .get_sg = ethtool_op_get_sg,
.set_sg = skge_set_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = skge_set_tx_csum,
.get_rx_csum = skge_get_rx_csum,
.set_rx_csum = skge_set_rx_csum,
.get_strings = skge_get_strings,
.phys_id = skge_phys_id,
- .get_stats_count = skge_get_stats_count,
+ .get_sset_count = skge_get_sset_count,
.get_ethtool_stats = skge_get_ethtool_stats,
};
@@ -992,19 +1095,15 @@ static void xm_link_down(struct skge_hw *hw, int port)
{
struct net_device *dev = hw->dev[port];
struct skge_port *skge = netdev_priv(dev);
- u16 cmd, msk;
+ u16 cmd = xm_read16(hw, port, XM_MMU_CMD);
- if (hw->phy_type == SK_PHY_XMAC) {
- msk = xm_read16(hw, port, XM_IMSK);
- msk |= XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND;
- xm_write16(hw, port, XM_IMSK, msk);
- }
+ xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE);
- cmd = xm_read16(hw, port, XM_MMU_CMD);
cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
xm_write16(hw, port, XM_MMU_CMD, cmd);
+
/* dummy read to ensure writing */
- (void) xm_read16(hw, port, XM_MMU_CMD);
+ xm_read16(hw, port, XM_MMU_CMD);
if (netif_carrier_ok(dev))
skge_link_down(skge);
@@ -1100,7 +1199,7 @@ static void genesis_reset(struct skge_hw *hw, int port)
/* reset the statistics module */
xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT);
- xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */
+ xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE);
xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */
xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */
xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */
@@ -1138,7 +1237,7 @@ static void bcom_check_link(struct skge_hw *hw, int port)
u16 status;
/* read twice because of latch */
- (void) xm_phy_read(hw, port, PHY_BCOM_STAT);
+ xm_phy_read(hw, port, PHY_BCOM_STAT);
status = xm_phy_read(hw, port, PHY_BCOM_STAT);
if ((status & PHY_ST_LSYNC) == 0) {
@@ -1339,7 +1438,7 @@ static void xm_phy_init(struct skge_port *skge)
mod_timer(&skge->link_timer, jiffies + LINK_HZ);
}
-static void xm_check_link(struct net_device *dev)
+static int xm_check_link(struct net_device *dev)
{
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
@@ -1347,25 +1446,25 @@ static void xm_check_link(struct net_device *dev)
u16 status;
/* read twice because of latch */
- (void) xm_phy_read(hw, port, PHY_XMAC_STAT);
+ xm_phy_read(hw, port, PHY_XMAC_STAT);
status = xm_phy_read(hw, port, PHY_XMAC_STAT);
if ((status & PHY_ST_LSYNC) == 0) {
xm_link_down(hw, port);
- return;
+ return 0;
}
if (skge->autoneg == AUTONEG_ENABLE) {
u16 lpa, res;
if (!(status & PHY_ST_AN_OVER))
- return;
+ return 0;
lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
if (lpa & PHY_B_AN_RF) {
printk(KERN_NOTICE PFX "%s: remote fault\n",
dev->name);
- return;
+ return 0;
}
res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI);
@@ -1381,7 +1480,7 @@ static void xm_check_link(struct net_device *dev)
default:
printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
dev->name);
- return;
+ return 0;
}
/* We are using IEEE 802.3z/D5.0 Table 37-4 */
@@ -1405,11 +1504,14 @@ static void xm_check_link(struct net_device *dev)
if (!netif_carrier_ok(dev))
genesis_link_up(skge);
+ return 1;
}
/* Poll to check for link coming up.
+ *
* Since internal PHY is wired to a level triggered pin, can't
- * get an interrupt when carrier is detected.
+ * get an interrupt when carrier is detected, need to poll for
+ * link coming up.
*/
static void xm_link_timer(unsigned long arg)
{
@@ -1417,29 +1519,35 @@ static void xm_link_timer(unsigned long arg)
struct net_device *dev = skge->netdev;
struct skge_hw *hw = skge->hw;
int port = skge->port;
+ int i;
+ unsigned long flags;
if (!netif_running(dev))
return;
- if (netif_carrier_ok(dev)) {
+ spin_lock_irqsave(&hw->phy_lock, flags);
+
+ /*
+ * Verify that the link by checking GPIO register three times.
+ * This pin has the signal from the link_sync pin connected to it.
+ */
+ for (i = 0; i < 3; i++) {
+ if (xm_read16(hw, port, XM_GP_PORT) & XM_GP_INP_ASS)
+ goto link_down;
+ }
+
+ /* Re-enable interrupt to detect link down */
+ if (xm_check_link(dev)) {
+ u16 msk = xm_read16(hw, port, XM_IMSK);
+ msk &= ~XM_IS_INP_ASS;
+ xm_write16(hw, port, XM_IMSK, msk);
xm_read16(hw, port, XM_ISRC);
- if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS))
- goto nochange;
} else {
- if (xm_read32(hw, port, XM_GP_PORT) & XM_GP_INP_ASS)
- goto nochange;
- xm_read16(hw, port, XM_ISRC);
- if (xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)
- goto nochange;
+link_down:
+ mod_timer(&skge->link_timer,
+ round_jiffies(jiffies + LINK_HZ));
}
-
- spin_lock(&hw->phy_lock);
- xm_check_link(dev);
- spin_unlock(&hw->phy_lock);
-
-nochange:
- if (netif_running(dev))
- mod_timer(&skge->link_timer, jiffies + LINK_HZ);
+ spin_unlock_irqrestore(&hw->phy_lock, flags);
}
static void genesis_mac_init(struct skge_hw *hw, int port)
@@ -1676,24 +1784,27 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data)
static void genesis_mac_intr(struct skge_hw *hw, int port)
{
- struct skge_port *skge = netdev_priv(hw->dev[port]);
+ struct net_device *dev = hw->dev[port];
+ struct skge_port *skge = netdev_priv(dev);
u16 status = xm_read16(hw, port, XM_ISRC);
if (netif_msg_intr(skge))
printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
- skge->netdev->name, status);
+ dev->name, status);
- if (hw->phy_type == SK_PHY_XMAC &&
- (status & (XM_IS_INP_ASS | XM_IS_LIPA_RC)))
- xm_link_down(hw, port);
+ if (hw->phy_type == SK_PHY_XMAC && (status & XM_IS_INP_ASS)) {
+ xm_link_down(hw, port);
+ mod_timer(&skge->link_timer, jiffies + 1);
+ }
if (status & XM_IS_TXF_UR) {
xm_write32(hw, port, XM_MODE, XM_MD_FTF);
- ++skge->net_stats.tx_fifo_errors;
+ ++dev->stats.tx_fifo_errors;
}
+
if (status & XM_IS_RXF_OV) {
xm_write32(hw, port, XM_MODE, XM_MD_FRF);
- ++skge->net_stats.rx_fifo_errors;
+ ++dev->stats.rx_fifo_errors;
}
}
@@ -1750,11 +1861,12 @@ static void genesis_link_up(struct skge_port *skge)
}
xm_write32(hw, port, XM_MODE, mode);
- msk = XM_DEF_MSK;
- if (hw->phy_type != SK_PHY_XMAC)
- msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */
+ /* Turn on detection of Tx underrun, Rx overrun */
+ msk = xm_read16(hw, port, XM_IMSK);
+ msk &= ~(XM_IS_RXF_OV | XM_IS_TXF_UR);
xm_write16(hw, port, XM_IMSK, msk);
+
xm_read16(hw, port, XM_ISRC);
/* get MMU Command Reg. */
@@ -2189,12 +2301,12 @@ static void yukon_mac_intr(struct skge_hw *hw, int port)
dev->name, status);
if (status & GM_IS_RX_FF_OR) {
- ++skge->net_stats.rx_fifo_errors;
+ ++dev->stats.rx_fifo_errors;
skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_CLI_RX_FO);
}
if (status & GM_IS_TX_FF_UR) {
- ++skge->net_stats.tx_fifo_errors;
+ ++dev->stats.tx_fifo_errors;
skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_FU);
}
@@ -2528,7 +2640,7 @@ static int skge_up(struct net_device *dev)
skge_write32(hw, B0_IMSK, hw->intr_mask);
spin_unlock_irq(&hw->hw_lock);
- netif_poll_enable(dev);
+ napi_enable(&skge->napi);
return 0;
free_rx_ring:
@@ -2541,6 +2653,15 @@ static int skge_up(struct net_device *dev)
return err;
}
+/* stop receiver */
+static void skge_rx_stop(struct skge_hw *hw, int port)
+{
+ skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_STOP);
+ skge_write32(hw, RB_ADDR(port ? Q_R2 : Q_R1, RB_CTRL),
+ RB_RST_SET|RB_DIS_OP_MD);
+ skge_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_SET_RESET);
+}
+
static int skge_down(struct net_device *dev)
{
struct skge_port *skge = netdev_priv(dev);
@@ -2558,7 +2679,7 @@ static int skge_down(struct net_device *dev)
if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
del_timer_sync(&skge->link_timer);
- netif_poll_disable(dev);
+ napi_disable(&skge->napi);
netif_carrier_off(dev);
spin_lock_irq(&hw->hw_lock);
@@ -2592,11 +2713,8 @@ static int skge_down(struct net_device *dev)
/* Reset the RAM Buffer async Tx queue */
skge_write8(hw, RB_ADDR(port == 0 ? Q_XA1 : Q_XA2, RB_CTRL), RB_RST_SET);
- /* stop receiver */
- skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_STOP);
- skge_write32(hw, RB_ADDR(port ? Q_R2 : Q_R1, RB_CTRL),
- RB_RST_SET|RB_DIS_OP_MD);
- skge_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_SET_RESET);
+
+ skge_rx_stop(hw, port);
if (hw->chip_id == CHIP_ID_GENESIS) {
skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_SET);
@@ -2779,7 +2897,11 @@ static void skge_tx_timeout(struct net_device *dev)
static int skge_change_mtu(struct net_device *dev, int new_mtu)
{
+ struct skge_port *skge = netdev_priv(dev);
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
int err;
+ u16 ctl, reg;
if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
return -EINVAL;
@@ -2789,13 +2911,40 @@ static int skge_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
- skge_down(dev);
+ skge_write32(hw, B0_IMSK, 0);
+ dev->trans_start = jiffies; /* prevent tx timeout */
+ netif_stop_queue(dev);
+ napi_disable(&skge->napi);
+
+ ctl = gma_read16(hw, port, GM_GP_CTRL);
+ gma_write16(hw, port, GM_GP_CTRL, ctl & ~GM_GPCR_RX_ENA);
+
+ skge_rx_clean(skge);
+ skge_rx_stop(hw, port);
dev->mtu = new_mtu;
- err = skge_up(dev);
+ reg = GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF);
+ if (new_mtu > 1500)
+ reg |= GM_SMOD_JUMBO_ENA;
+ gma_write16(hw, port, GM_SERIAL_MODE, reg);
+
+ skge_write8(hw, RB_ADDR(rxqaddr[port], RB_CTRL), RB_ENA_OP_MD);
+
+ err = skge_rx_fill(dev);
+ wmb();
+ if (!err)
+ skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_START | CSR_IRQ_CL_F);
+ skge_write32(hw, B0_IMSK, hw->intr_mask);
+
if (err)
dev_close(dev);
+ else {
+ gma_write16(hw, port, GM_GP_CTRL, ctl);
+
+ napi_enable(&skge->napi);
+ netif_wake_queue(dev);
+ }
return err;
}
@@ -2991,18 +3140,18 @@ error:
if (skge->hw->chip_id == CHIP_ID_GENESIS) {
if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR))
- skge->net_stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (status & XMR_FS_FRA_ERR)
- skge->net_stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & XMR_FS_FCS_ERR)
- skge->net_stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
} else {
if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE))
- skge->net_stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (status & GMR_FS_FRAGMENT)
- skge->net_stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & GMR_FS_CRC_ERR)
- skge->net_stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
}
resubmit:
@@ -3044,14 +3193,13 @@ static void skge_tx_done(struct net_device *dev)
}
}
-static int skge_poll(struct net_device *dev, int *budget)
+static int skge_poll(struct napi_struct *napi, int to_do)
{
- struct skge_port *skge = netdev_priv(dev);
+ struct skge_port *skge = container_of(napi, struct skge_port, napi);
+ struct net_device *dev = skge->netdev;
struct skge_hw *hw = skge->hw;
struct skge_ring *ring = &skge->rx_ring;
struct skge_element *e;
- unsigned long flags;
- int to_do = min(dev->quota, *budget);
int work_done = 0;
skge_tx_done(dev);
@@ -3082,20 +3230,16 @@ static int skge_poll(struct net_device *dev, int *budget)
wmb();
skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_START);
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (work_done >= to_do)
- return 1; /* not done */
-
- spin_lock_irqsave(&hw->hw_lock, flags);
- __netif_rx_complete(dev);
- hw->intr_mask |= napimask[skge->port];
- skge_write32(hw, B0_IMSK, hw->intr_mask);
- skge_read32(hw, B0_IMSK);
- spin_unlock_irqrestore(&hw->hw_lock, flags);
+ if (work_done < to_do) {
+ spin_lock_irq(&hw->hw_lock);
+ __netif_rx_complete(dev, napi);
+ hw->intr_mask |= napimask[skge->port];
+ skge_write32(hw, B0_IMSK, hw->intr_mask);
+ skge_read32(hw, B0_IMSK);
+ spin_unlock_irq(&hw->hw_lock);
+ }
- return 0;
+ return work_done;
}
/* Parity errors seem to happen when Genesis is connected to a switch
@@ -3105,10 +3249,7 @@ static void skge_mac_parity(struct skge_hw *hw, int port)
{
struct net_device *dev = hw->dev[port];
- if (dev) {
- struct skge_port *skge = netdev_priv(dev);
- ++skge->net_stats.tx_heartbeat_errors;
- }
+ ++dev->stats.tx_heartbeat_errors;
if (hw->chip_id == CHIP_ID_GENESIS)
skge_write16(hw, SK_REG(port, TX_MFF_CTRL1),
@@ -3252,17 +3393,16 @@ static irqreturn_t skge_intr(int irq, void *dev_id)
}
if (status & (IS_XA1_F|IS_R1_F)) {
+ struct skge_port *skge = netdev_priv(hw->dev[0]);
hw->intr_mask &= ~(IS_XA1_F|IS_R1_F);
- netif_rx_schedule(hw->dev[0]);
+ netif_rx_schedule(hw->dev[0], &skge->napi);
}
if (status & IS_PA_TO_TX1)
skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX1);
if (status & IS_PA_TO_RX1) {
- struct skge_port *skge = netdev_priv(hw->dev[0]);
-
- ++skge->net_stats.rx_over_errors;
+ ++hw->dev[0]->stats.rx_over_errors;
skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX1);
}
@@ -3271,14 +3411,15 @@ static irqreturn_t skge_intr(int irq, void *dev_id)
skge_mac_intr(hw, 0);
if (hw->dev[1]) {
+ struct skge_port *skge = netdev_priv(hw->dev[1]);
+
if (status & (IS_XA2_F|IS_R2_F)) {
hw->intr_mask &= ~(IS_XA2_F|IS_R2_F);
- netif_rx_schedule(hw->dev[1]);
+ netif_rx_schedule(hw->dev[1], &skge->napi);
}
if (status & IS_PA_TO_RX2) {
- struct skge_port *skge = netdev_priv(hw->dev[1]);
- ++skge->net_stats.rx_over_errors;
+ ++hw->dev[1]->stats.rx_over_errors;
skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2);
}
@@ -3540,6 +3681,145 @@ static int skge_reset(struct skge_hw *hw)
return 0;
}
+
+#ifdef CONFIG_SKGE_DEBUG
+
+static struct dentry *skge_debug;
+
+static int skge_debug_show(struct seq_file *seq, void *v)
+{
+ struct net_device *dev = seq->private;
+ const struct skge_port *skge = netdev_priv(dev);
+ const struct skge_hw *hw = skge->hw;
+ const struct skge_element *e;
+
+ if (!netif_running(dev))
+ return -ENETDOWN;
+
+ seq_printf(seq, "IRQ src=%x mask=%x\n", skge_read32(hw, B0_ISRC),
+ skge_read32(hw, B0_IMSK));
+
+ seq_printf(seq, "Tx Ring: (%d)\n", skge_avail(&skge->tx_ring));
+ for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) {
+ const struct skge_tx_desc *t = e->desc;
+ seq_printf(seq, "%#x dma=%#x%08x %#x csum=%#x/%x/%x\n",
+ t->control, t->dma_hi, t->dma_lo, t->status,
+ t->csum_offs, t->csum_write, t->csum_start);
+ }
+
+ seq_printf(seq, "\nRx Ring: \n");
+ for (e = skge->rx_ring.to_clean; ; e = e->next) {
+ const struct skge_rx_desc *r = e->desc;
+
+ if (r->control & BMU_OWN)
+ break;
+
+ seq_printf(seq, "%#x dma=%#x%08x %#x %#x csum=%#x/%x\n",
+ r->control, r->dma_hi, r->dma_lo, r->status,
+ r->timestamp, r->csum1, r->csum1_start);
+ }
+
+ return 0;
+}
+
+static int skge_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, skge_debug_show, inode->i_private);
+}
+
+static const struct file_operations skge_debug_fops = {
+ .owner = THIS_MODULE,
+ .open = skge_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/*
+ * Use network device events to create/remove/rename
+ * debugfs file entries
+ */
+static int skge_device_event(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+ struct skge_port *skge;
+ struct dentry *d;
+
+ if (dev->open != &skge_up || !skge_debug)
+ goto done;
+
+ skge = netdev_priv(dev);
+ switch(event) {
+ case NETDEV_CHANGENAME:
+ if (skge->debugfs) {
+ d = debugfs_rename(skge_debug, skge->debugfs,
+ skge_debug, dev->name);
+ if (d)
+ skge->debugfs = d;
+ else {
+ pr_info(PFX "%s: rename failed\n", dev->name);
+ debugfs_remove(skge->debugfs);
+ }
+ }
+ break;
+
+ case NETDEV_GOING_DOWN:
+ if (skge->debugfs) {
+ debugfs_remove(skge->debugfs);
+ skge->debugfs = NULL;
+ }
+ break;
+
+ case NETDEV_UP:
+ d = debugfs_create_file(dev->name, S_IRUGO,
+ skge_debug, dev,
+ &skge_debug_fops);
+ if (!d || IS_ERR(d))
+ pr_info(PFX "%s: debugfs create failed\n",
+ dev->name);
+ else
+ skge->debugfs = d;
+ break;
+ }
+
+done:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block skge_notifier = {
+ .notifier_call = skge_device_event,
+};
+
+
+static __init void skge_debug_init(void)
+{
+ struct dentry *ent;
+
+ ent = debugfs_create_dir("skge", NULL);
+ if (!ent || IS_ERR(ent)) {
+ pr_info(PFX "debugfs create directory failed\n");
+ return;
+ }
+
+ skge_debug = ent;
+ register_netdevice_notifier(&skge_notifier);
+}
+
+static __exit void skge_debug_cleanup(void)
+{
+ if (skge_debug) {
+ unregister_netdevice_notifier(&skge_notifier);
+ debugfs_remove(skge_debug);
+ skge_debug = NULL;
+ }
+}
+
+#else
+#define skge_debug_init()
+#define skge_debug_cleanup()
+#endif
+
/* Initialize network device */
static struct net_device *skge_devinit(struct skge_hw *hw, int port,
int highmem)
@@ -3552,7 +3832,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
return NULL;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &hw->pdev->dev);
dev->open = skge_up;
dev->stop = skge_down;
@@ -3569,8 +3848,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
SET_ETHTOOL_OPS(dev, &skge_ethtool_ops);
dev->tx_timeout = skge_tx_timeout;
dev->watchdog_timeo = TX_WATCHDOG;
- dev->poll = skge_poll;
- dev->weight = NAPI_WEIGHT;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = skge_netpoll;
#endif
@@ -3580,6 +3857,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
dev->features |= NETIF_F_HIGHDMA;
skge = netdev_priv(dev);
+ netif_napi_add(dev, &skge->napi, skge_poll, NAPI_WEIGHT);
skge->netdev = dev;
skge->hw = hw;
skge->msg_enable = netif_msg_init(debug, default_msg);
@@ -3623,12 +3901,11 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
static void __devinit skge_show_addr(struct net_device *dev)
{
const struct skge_port *skge = netdev_priv(dev);
+ DECLARE_MAC_BUF(mac);
if (netif_msg_probe(skge))
- printk(KERN_INFO PFX "%s: addr %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_INFO PFX "%s: addr %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
}
static int __devinit skge_probe(struct pci_dev *pdev,
@@ -3907,12 +4184,14 @@ static struct pci_driver skge_driver = {
static int __init skge_init_module(void)
{
+ skge_debug_init();
return pci_register_driver(&skge_driver);
}
static void __exit skge_cleanup_module(void)
{
pci_unregister_driver(&skge_driver);
+ skge_debug_cleanup();
}
module_init(skge_init_module);
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index edd71468220..17caccbb768 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -1,5 +1,5 @@
/*
- * Definitions for the new Marvell Yukon / SysKonenct driver.
+ * Definitions for the new Marvell Yukon / SysKonnect driver.
*/
#ifndef _SKGE_H
#define _SKGE_H
@@ -8,8 +8,10 @@
#define PCI_DEV_REG1 0x40
#define PCI_PHY_COMA 0x8000000
#define PCI_VIO 0x2000000
+
#define PCI_DEV_REG2 0x44
-#define PCI_REV_DESC 0x4
+#define PCI_VPD_ROM_SZ 7L<<14 /* VPD ROM size 0=256, 1=512, ... */
+#define PCI_REV_DESC 1<<2 /* Reverse Descriptor bytes */
#define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
PCI_STATUS_SIG_SYSTEM_ERROR | \
@@ -1351,8 +1353,6 @@ enum {
PHY_M_PC_EN_DET_PLUS = 3<<8, /* Energy Detect Plus (Mode 2) */
};
-#define PHY_M_PC_MDI_XMODE(x) ((((u16)(x)<<5) & PHY_M_PC_MDIX_MSK)
-
enum {
PHY_M_PC_MAN_MDI = 0, /* 00 = Manual MDI configuration */
PHY_M_PC_MAN_MDIX = 1, /* 01 = Manual MDIX configuration */
@@ -2193,11 +2193,9 @@ enum {
XM_IS_TXF_UR = 1<<2, /* Bit 2: Transmit FIFO Underrun */
XM_IS_TX_COMP = 1<<1, /* Bit 1: Frame Tx Complete */
XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */
-};
-
-#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | \
- XM_IS_RXF_OV | XM_IS_TXF_UR))
+ XM_IMSK_DISABLE = 0xffff,
+};
/* XM_HW_CFG 16 bit r/w Hardware Config Register */
enum {
@@ -2448,6 +2446,7 @@ enum pause_status {
struct skge_port {
struct skge_hw *hw;
struct net_device *netdev;
+ struct napi_struct napi;
int port;
u32 msg_enable;
@@ -2470,8 +2469,9 @@ struct skge_port {
void *mem; /* PCI memory for rings */
dma_addr_t dma;
unsigned long mem_size;
-
- struct net_device_stats net_stats;
+#ifdef CONFIG_SKGE_DEBUG
+ struct dentry *debugfs;
+#endif
};
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index ea117fc3d5e..a2070db725c 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -31,6 +31,7 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/pci.h>
+#include <linux/aer.h>
#include <linux/ip.h>
#include <net/ip.h>
#include <linux/tcp.h>
@@ -51,7 +52,7 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.18"
+#define DRV_VERSION "1.20"
#define PFX DRV_NAME " "
/*
@@ -120,6 +121,7 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) }, /* 88E8039 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4354) }, /* 88E8040 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4356) }, /* 88EC033 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4357) }, /* 88E8042 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x435A) }, /* 88E8048 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4360) }, /* 88E8052 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, /* 88E8050 */
@@ -133,6 +135,7 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) }, /* 88EC042 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436C) }, /* 88E8072 */
{ 0 }
};
@@ -155,7 +158,7 @@ static const char *yukon2_name[] = {
static void sky2_set_multicast(struct net_device *dev);
-/* Access to external PHY */
+/* Access to PHY via serial interconnect */
static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)
{
int i;
@@ -165,13 +168,22 @@ static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)
GM_SMI_CT_PHY_AD(PHY_ADDR_MARV) | GM_SMI_CT_REG_AD(reg));
for (i = 0; i < PHY_RETRIES; i++) {
- if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
+ u16 ctrl = gma_read16(hw, port, GM_SMI_CTRL);
+ if (ctrl == 0xffff)
+ goto io_error;
+
+ if (!(ctrl & GM_SMI_CT_BUSY))
return 0;
- udelay(1);
+
+ udelay(10);
}
- printk(KERN_WARNING PFX "%s: phy write timeout\n", hw->dev[port]->name);
+ dev_warn(&hw->pdev->dev,"%s: phy write timeout\n", hw->dev[port]->name);
return -ETIMEDOUT;
+
+io_error:
+ dev_err(&hw->pdev->dev, "%s: phy I/O error\n", hw->dev[port]->name);
+ return -EIO;
}
static int __gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg, u16 *val)
@@ -182,23 +194,29 @@ static int __gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg, u16 *val)
| GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD);
for (i = 0; i < PHY_RETRIES; i++) {
- if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL) {
+ u16 ctrl = gma_read16(hw, port, GM_SMI_CTRL);
+ if (ctrl == 0xffff)
+ goto io_error;
+
+ if (ctrl & GM_SMI_CT_RD_VAL) {
*val = gma_read16(hw, port, GM_SMI_DATA);
return 0;
}
- udelay(1);
+ udelay(10);
}
+ dev_warn(&hw->pdev->dev, "%s: phy read timeout\n", hw->dev[port]->name);
return -ETIMEDOUT;
+io_error:
+ dev_err(&hw->pdev->dev, "%s: phy I/O error\n", hw->dev[port]->name);
+ return -EIO;
}
-static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
+static inline u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
{
u16 v;
-
- if (__gm_phy_read(hw, port, reg, &v) != 0)
- printk(KERN_WARNING PFX "%s: phy read timeout\n", hw->dev[port]->name);
+ __gm_phy_read(hw, port, reg, &v);
return v;
}
@@ -222,21 +240,22 @@ static void sky2_power_on(struct sky2_hw *hw)
sky2_write8(hw, B2_Y2_CLK_GATE, 0);
if (hw->flags & SKY2_HW_ADV_POWER_CTL) {
+ struct pci_dev *pdev = hw->pdev;
u32 reg;
- sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+ pci_write_config_dword(pdev, PCI_DEV_REG3, 0);
- reg = sky2_pci_read32(hw, PCI_DEV_REG4);
+ pci_read_config_dword(pdev, PCI_DEV_REG4, &reg);
/* set all bits to 0 except bits 15..12 and 8 */
reg &= P_ASPM_CONTROL_MSK;
- sky2_pci_write32(hw, PCI_DEV_REG4, reg);
+ pci_write_config_dword(pdev, PCI_DEV_REG4, reg);
- reg = sky2_pci_read32(hw, PCI_DEV_REG5);
+ pci_read_config_dword(pdev, PCI_DEV_REG5, &reg);
/* set all bits to 0 except bits 28 & 27 */
reg &= P_CTL_TIM_VMAIN_AV_MSK;
- sky2_pci_write32(hw, PCI_DEV_REG5, reg);
+ pci_write_config_dword(pdev, PCI_DEV_REG5, reg);
- sky2_pci_write32(hw, PCI_CFG_REG_1, 0);
+ pci_write_config_dword(pdev, PCI_CFG_REG_1, 0);
/* Enable workaround for dev 4.107 on Yukon-Ultra & Extreme */
reg = sky2_read32(hw, B2_GP_IO);
@@ -271,8 +290,6 @@ static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
/* disable all GMAC IRQ's */
sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), 0);
- /* disable PHY IRQs */
- gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);
gma_write16(hw, port, GM_MC_ADDR_H1, 0); /* clear MC hash */
gma_write16(hw, port, GM_MC_ADDR_H2, 0);
@@ -294,10 +311,10 @@ static const u16 copper_fc_adv[] = {
/* flow control to advertise bits when using 1000BaseX */
static const u16 fiber_fc_adv[] = {
- [FC_BOTH] = PHY_M_P_BOTH_MD_X,
+ [FC_NONE] = PHY_M_P_NO_PAUSE_X,
[FC_TX] = PHY_M_P_ASYM_MD_X,
[FC_RX] = PHY_M_P_SYM_MD_X,
- [FC_NONE] = PHY_M_P_NO_PAUSE_X,
+ [FC_BOTH] = PHY_M_P_BOTH_MD_X,
};
/* flow control to GMA disable bits */
@@ -602,25 +619,24 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff)
{
+ struct pci_dev *pdev = hw->pdev;
u32 reg1;
- static const u32 phy_power[]
- = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
-
- /* looks like this XL is back asswards .. */
- if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
- onoff = !onoff;
+ static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
+ static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA };
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+ pci_read_config_dword(pdev, PCI_DEV_REG1, &reg1);
+ /* Turn on/off phy power saving */
if (onoff)
- /* Turn off phy power saving */
reg1 &= ~phy_power[port];
else
reg1 |= phy_power[port];
- sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
- sky2_pci_read32(hw, PCI_DEV_REG1);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+ if (onoff && hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+ reg1 |= coma_mode[port];
+
+ pci_write_config_dword(pdev, PCI_DEV_REG1, reg1);
+ pci_read_config_dword(pdev, PCI_DEV_REG1, &reg1);
+
udelay(100);
}
@@ -688,11 +704,9 @@ static void sky2_wol_init(struct sky2_port *sky2)
sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
/* Turn on legacy PCI-Express PME mode */
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+ pci_read_config_dword(hw->pdev, PCI_DEV_REG1, &reg1);
reg1 |= PCI_Y2_PME_LEGACY;
- sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+ pci_write_config_dword(hw->pdev, PCI_DEV_REG1, reg1);
/* block receiver */
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
@@ -1130,7 +1144,7 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp
u16 port = sky2->port;
netif_tx_lock_bh(dev);
- netif_poll_disable(sky2->hw->dev[0]);
+ napi_disable(&hw->napi);
sky2->vlgrp = grp;
if (grp) {
@@ -1145,7 +1159,7 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp
TX_VLAN_TAG_OFF);
}
- netif_poll_enable(sky2->hw->dev[0]);
+ napi_enable(&hw->napi);
netif_tx_unlock_bh(dev);
}
#endif
@@ -1309,9 +1323,9 @@ static int sky2_up(struct net_device *dev)
struct sky2_port *osky2 = netdev_priv(otherdev);
u16 cmd;
- cmd = sky2_pci_read16(hw, cap + PCI_X_CMD);
+ pci_read_config_word(hw->pdev, cap + PCI_X_CMD, &cmd);
cmd &= ~PCI_X_CMD_MAX_SPLIT;
- sky2_pci_write16(hw, cap + PCI_X_CMD, cmd);
+ pci_write_config_word(hw->pdev, cap + PCI_X_CMD, cmd);
sky2->rx_csum = 0;
osky2->rx_csum = 0;
@@ -1632,8 +1646,8 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
printk(KERN_DEBUG "%s: tx done %u\n",
dev->name, idx);
- sky2->net_stats.tx_packets++;
- sky2->net_stats.tx_bytes += re->skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += re->skb->len;
dev_kfree_skb_any(re->skb);
sky2->tx_next = RING_NEXT(idx, TX_RING_SIZE);
@@ -1681,6 +1695,8 @@ static int sky2_down(struct net_device *dev)
imask &= ~portirq_msk[port];
sky2_write32(hw, B0_IMSK, imask);
+ synchronize_irq(hw->pdev->irq);
+
sky2_gmac_reset(hw, port);
/* Stop transmitter */
@@ -1694,6 +1710,9 @@ static int sky2_down(struct net_device *dev)
ctrl &= ~(GM_GPCR_TX_ENA | GM_GPCR_RX_ENA);
gma_write16(hw, port, GM_GP_CTRL, ctrl);
+ /* Make sure no packets are pending */
+ napi_synchronize(&hw->napi);
+
sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
/* Workaround shared GMAC reset */
@@ -1731,8 +1750,6 @@ static int sky2_down(struct net_device *dev)
/* turn off LED's */
sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
- synchronize_irq(hw->pdev->irq);
-
sky2_tx_clean(dev);
sky2_rx_clean(sky2);
@@ -1803,29 +1820,6 @@ static void sky2_link_up(struct sky2_port *sky2)
sky2_write8(hw, SK_REG(port, LNK_LED_REG),
LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF);
- if (hw->flags & SKY2_HW_NEWER_PHY) {
- u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
- u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */
-
- switch(sky2->speed) {
- case SPEED_10:
- led |= PHY_M_LEDC_INIT_CTRL(7);
- break;
-
- case SPEED_100:
- led |= PHY_M_LEDC_STA1_CTRL(7);
- break;
-
- case SPEED_1000:
- led |= PHY_M_LEDC_STA0_CTRL(7);
- break;
- }
-
- gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
- gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, led);
- gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
- }
-
if (netif_msg_link(sky2))
printk(KERN_INFO PFX
"%s: Link is up at %d Mbps, %s duplex, flow control %s\n",
@@ -2016,7 +2010,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
dev->trans_start = jiffies; /* prevent tx timeout */
netif_stop_queue(dev);
- netif_poll_disable(hw->dev[0]);
+ napi_disable(&hw->napi);
synchronize_irq(hw->pdev->irq);
@@ -2043,12 +2037,13 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
err = sky2_rx_start(sky2);
sky2_write32(hw, B0_IMSK, imask);
+ napi_enable(&hw->napi);
+
if (err)
dev_close(dev);
else {
gma_write16(hw, port, GM_GP_CTRL, ctl);
- netif_poll_enable(hw->dev[0]);
netif_wake_queue(dev);
}
@@ -2195,16 +2190,16 @@ resubmit:
len_error:
/* Truncation of overlength packets
causes PHY length to not match MAC length */
- ++sky2->net_stats.rx_length_errors;
+ ++dev->stats.rx_length_errors;
if (netif_msg_rx_err(sky2) && net_ratelimit())
pr_info(PFX "%s: rx length error: status %#x length %d\n",
dev->name, status, length);
goto resubmit;
error:
- ++sky2->net_stats.rx_errors;
+ ++dev->stats.rx_errors;
if (status & GMR_FS_RX_FF_OV) {
- sky2->net_stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
goto resubmit;
}
@@ -2213,11 +2208,11 @@ error:
dev->name, status, length);
if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE))
- sky2->net_stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (status & GMR_FS_FRAGMENT)
- sky2->net_stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & GMR_FS_CRC_ERR)
- sky2->net_stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
goto resubmit;
}
@@ -2235,36 +2230,40 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
}
/* Process status response ring */
-static int sky2_status_intr(struct sky2_hw *hw, int to_do)
+static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
{
int work_done = 0;
unsigned rx[2] = { 0, 0 };
- u16 hwidx = sky2_read16(hw, STAT_PUT_IDX);
rmb();
-
- while (hw->st_idx != hwidx) {
+ do {
struct sky2_port *sky2;
struct sky2_status_le *le = hw->st_le + hw->st_idx;
- unsigned port = le->css & CSS_LINK_BIT;
+ unsigned port;
struct net_device *dev;
struct sk_buff *skb;
u32 status;
u16 length;
+ u8 opcode = le->opcode;
+
+ if (!(opcode & HW_OWNER))
+ break;
hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE);
+ port = le->css & CSS_LINK_BIT;
dev = hw->dev[port];
sky2 = netdev_priv(dev);
length = le16_to_cpu(le->length);
status = le32_to_cpu(le->status);
- switch (le->opcode & ~HW_OWNER) {
+ le->opcode = 0;
+ switch (opcode & ~HW_OWNER) {
case OP_RXSTAT:
++rx[port];
skb = sky2_receive(dev, length, status);
if (unlikely(!skb)) {
- sky2->net_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
@@ -2279,8 +2278,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
}
skb->protocol = eth_type_trans(skb, dev);
- sky2->net_stats.rx_packets++;
- sky2->net_stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
dev->last_rx = jiffies;
#ifdef SKY2_VLAN_TAG_USED
@@ -2352,9 +2351,9 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
default:
if (net_ratelimit())
printk(KERN_WARNING PFX
- "unknown status opcode 0x%x\n", le->opcode);
+ "unknown status opcode 0x%x\n", opcode);
}
- }
+ } while (hw->st_idx != idx);
/* Fully processed status ring so clear irq */
sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
@@ -2415,7 +2414,11 @@ static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status)
static void sky2_hw_intr(struct sky2_hw *hw)
{
+ struct pci_dev *pdev = hw->pdev;
u32 status = sky2_read32(hw, B0_HWE_ISRC);
+ u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK);
+
+ status &= hwmsk;
if (status & Y2_IS_TIST_OV)
sky2_write8(hw, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ);
@@ -2423,38 +2426,37 @@ static void sky2_hw_intr(struct sky2_hw *hw)
if (status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) {
u16 pci_err;
- pci_err = sky2_pci_read16(hw, PCI_STATUS);
+ pci_read_config_word(pdev, PCI_STATUS, &pci_err);
if (net_ratelimit())
- dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n",
+ dev_err(&pdev->dev, "PCI hardware error (0x%x)\n",
pci_err);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- sky2_pci_write16(hw, PCI_STATUS,
- pci_err | PCI_STATUS_ERROR_BITS);
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+ pci_write_config_word(pdev, PCI_STATUS,
+ pci_err | PCI_STATUS_ERROR_BITS);
}
if (status & Y2_IS_PCI_EXP) {
/* PCI-Express uncorrectable Error occurred */
- u32 pex_err;
+ int aer = pci_find_aer_capability(hw->pdev);
+ u32 err;
- pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT);
+ if (aer) {
+ pci_read_config_dword(pdev, aer + PCI_ERR_UNCOR_STATUS,
+ &err);
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+ } else {
+ /* Either AER not configured, or not working
+ * because of bad MMCONFIG, so just do recover
+ * manually.
+ */
+ err = sky2_read32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS);
+ sky2_write32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS,
+ 0xfffffffful);
+ }
if (net_ratelimit())
- dev_err(&hw->pdev->dev, "PCI Express error (0x%x)\n",
- pex_err);
-
- /* clear the interrupt */
- sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- sky2_pci_write32(hw, PEX_UNC_ERR_STAT,
- 0xffffffffUL);
- sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
-
- if (pex_err & PEX_FATAL_ERRORS) {
- u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK);
- hwmsk &= ~Y2_IS_PCI_EXP;
- sky2_write32(hw, B0_HWE_IMSK, hwmsk);
- }
+ dev_err(&pdev->dev, "PCI Express error (0x%x)\n", err);
+
}
if (status & Y2_HWE_L1_MASK)
@@ -2481,12 +2483,12 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port)
gma_read16(hw, port, GM_TX_IRQ_SRC);
if (status & GM_IS_RX_FF_OR) {
- ++sky2->net_stats.rx_fifo_errors;
+ ++dev->stats.rx_fifo_errors;
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_CLI_RX_FO);
}
if (status & GM_IS_TX_FF_UR) {
- ++sky2->net_stats.tx_fifo_errors;
+ ++dev->stats.tx_fifo_errors;
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_FU);
}
}
@@ -2544,18 +2546,15 @@ static int sky2_rx_hung(struct net_device *dev)
static void sky2_watchdog(unsigned long arg)
{
struct sky2_hw *hw = (struct sky2_hw *) arg;
- struct net_device *dev;
/* Check for lost IRQ once a second */
if (sky2_read32(hw, B0_ISRC)) {
- dev = hw->dev[0];
- if (__netif_rx_schedule_prep(dev))
- __netif_rx_schedule(dev);
+ napi_schedule(&hw->napi);
} else {
int i, active = 0;
for (i = 0; i < hw->ports; i++) {
- dev = hw->dev[i];
+ struct net_device *dev = hw->dev[i];
if (!netif_running(dev))
continue;
++active;
@@ -2605,11 +2604,12 @@ static void sky2_err_intr(struct sky2_hw *hw, u32 status)
sky2_le_error(hw, 1, Q_XA2, TX_RING_SIZE);
}
-static int sky2_poll(struct net_device *dev0, int *budget)
+static int sky2_poll(struct napi_struct *napi, int work_limit)
{
- struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw;
- int work_done;
+ struct sky2_hw *hw = container_of(napi, struct sky2_hw, napi);
u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
+ int work_done = 0;
+ u16 idx;
if (unlikely(status & Y2_IS_ERROR))
sky2_err_intr(hw, status);
@@ -2620,13 +2620,12 @@ static int sky2_poll(struct net_device *dev0, int *budget)
if (status & Y2_IS_IRQ_PHY2)
sky2_phy_intr(hw, 1);
- work_done = sky2_status_intr(hw, min(dev0->quota, *budget));
- *budget -= work_done;
- dev0->quota -= work_done;
+ while ((idx = sky2_read16(hw, STAT_PUT_IDX)) != hw->st_idx) {
+ work_done += sky2_status_intr(hw, work_limit - work_done, idx);
- /* More work? */
- if (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX))
- return 1;
+ if (work_done >= work_limit)
+ goto done;
+ }
/* Bug/Errata workaround?
* Need to kick the TX irq moderation timer.
@@ -2635,16 +2634,16 @@ static int sky2_poll(struct net_device *dev0, int *budget)
sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
}
- netif_rx_complete(dev0);
-
+ napi_complete(napi);
sky2_read32(hw, B0_Y2_SP_LISR);
- return 0;
+done:
+
+ return work_done;
}
static irqreturn_t sky2_intr(int irq, void *dev_id)
{
struct sky2_hw *hw = dev_id;
- struct net_device *dev0 = hw->dev[0];
u32 status;
/* Reading this mask interrupts as side effect */
@@ -2653,8 +2652,8 @@ static irqreturn_t sky2_intr(int irq, void *dev_id)
return IRQ_NONE;
prefetch(&hw->st_le[hw->st_idx]);
- if (likely(__netif_rx_schedule_prep(dev0)))
- __netif_rx_schedule(dev0);
+
+ napi_schedule(&hw->napi);
return IRQ_HANDLED;
}
@@ -2663,10 +2662,8 @@ static irqreturn_t sky2_intr(int irq, void *dev_id)
static void sky2_netpoll(struct net_device *dev)
{
struct sky2_port *sky2 = netdev_priv(dev);
- struct net_device *dev0 = sky2->hw->dev[0];
- if (netif_running(dev) && __netif_rx_schedule_prep(dev0))
- __netif_rx_schedule(dev0);
+ napi_schedule(&sky2->hw->napi);
}
#endif
@@ -2706,10 +2703,13 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
static int __devinit sky2_init(struct sky2_hw *hw)
{
+ int rc;
u8 t8;
- /* Enable all clocks */
- sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+ /* Enable all clocks and check for bad PCI access */
+ rc = pci_write_config_dword(hw->pdev, PCI_DEV_REG3, 0);
+ if (rc)
+ return rc;
sky2_write8(hw, B0_CTST, CS_RST_CLR);
@@ -2783,8 +2783,10 @@ static int __devinit sky2_init(struct sky2_hw *hw)
static void sky2_reset(struct sky2_hw *hw)
{
+ struct pci_dev *pdev = hw->pdev;
u16 status;
- int i;
+ int i, cap;
+ u32 hwe_mask = Y2_HWE_ALL_MASK;
/* disable ASF */
if (hw->chip_id == CHIP_ID_YUKON_EX) {
@@ -2800,19 +2802,38 @@ static void sky2_reset(struct sky2_hw *hw)
sky2_write8(hw, B0_CTST, CS_RST_SET);
sky2_write8(hw, B0_CTST, CS_RST_CLR);
- /* clear PCI errors, if any */
- status = sky2_pci_read16(hw, PCI_STATUS);
-
+ /* allow writes to PCI config */
sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- sky2_pci_write16(hw, PCI_STATUS, status | PCI_STATUS_ERROR_BITS);
+ /* clear PCI errors, if any */
+ pci_read_config_word(pdev, PCI_STATUS, &status);
+ status |= PCI_STATUS_ERROR_BITS;
+ pci_write_config_word(pdev, PCI_STATUS, status);
sky2_write8(hw, B0_CTST, CS_MRST_CLR);
- /* clear any PEX errors */
- if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP))
- sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL);
+ cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ if (cap) {
+ if (pci_find_aer_capability(pdev)) {
+ /* Check for advanced error reporting */
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+ pci_cleanup_aer_correct_error_status(pdev);
+ } else {
+ dev_warn(&pdev->dev,
+ "PCI Express Advanced Error Reporting"
+ " not configured or MMCONFIG problem?\n");
+
+ sky2_write32(hw, Y2_CFG_AER + PCI_ERR_UNCOR_STATUS,
+ 0xfffffffful);
+ }
+
+ /* If error bit is stuck on ignore it */
+ if (sky2_read32(hw, B0_HWE_ISRC) & Y2_IS_PCI_EXP)
+ dev_info(&pdev->dev, "ignoring stuck error report bit\n");
+ else if (pci_enable_pcie_error_reporting(pdev))
+ hwe_mask |= Y2_IS_PCI_EXP;
+ }
sky2_power_on(hw);
@@ -2826,8 +2847,6 @@ static void sky2_reset(struct sky2_hw *hw)
| GMC_BYP_RETR_ON);
}
- sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
-
/* Clear I2C IRQ noise */
sky2_write32(hw, B2_I2C_IRQ, 1);
@@ -2866,7 +2885,7 @@ static void sky2_reset(struct sky2_hw *hw)
sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_XS2), SK_RI_TO_53);
}
- sky2_write32(hw, B0_HWE_IMSK, Y2_HWE_ALL_MASK);
+ sky2_write32(hw, B0_HWE_IMSK, hwe_mask);
for (i = 0; i < hw->ports; i++)
sky2_gmac_reset(hw, i);
@@ -2913,8 +2932,7 @@ static void sky2_restart(struct work_struct *work)
rtnl_lock();
sky2_write32(hw, B0_IMSK, 0);
sky2_read32(hw, B0_IMSK);
-
- netif_poll_disable(hw->dev[0]);
+ napi_disable(&hw->napi);
for (i = 0; i < hw->ports; i++) {
dev = hw->dev[i];
@@ -2924,7 +2942,7 @@ static void sky2_restart(struct work_struct *work)
sky2_reset(hw);
sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
- netif_poll_enable(hw->dev[0]);
+ napi_enable(&hw->napi);
for (i = 0; i < hw->ports; i++) {
dev = hw->dev[i];
@@ -3192,9 +3210,14 @@ static void sky2_set_msglevel(struct net_device *netdev, u32 value)
sky2->msg_enable = value;
}
-static int sky2_get_stats_count(struct net_device *dev)
+static int sky2_get_sset_count(struct net_device *dev, int sset)
{
- return ARRAY_SIZE(sky2_stats);
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(sky2_stats);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void sky2_get_ethtool_stats(struct net_device *dev,
@@ -3218,12 +3241,6 @@ static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data)
}
}
-static struct net_device_stats *sky2_get_stats(struct net_device *dev)
-{
- struct sky2_port *sky2 = netdev_priv(dev);
- return &sky2->net_stats;
-}
-
static int sky2_set_mac_address(struct net_device *dev, void *p)
{
struct sky2_port *sky2 = netdev_priv(dev);
@@ -3564,20 +3581,64 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
{
const struct sky2_port *sky2 = netdev_priv(dev);
const void __iomem *io = sky2->hw->regs;
+ unsigned int b;
regs->version = 1;
- memset(p, 0, regs->len);
-
- memcpy_fromio(p, io, B3_RAM_ADDR);
- /* skip diagnostic ram region */
- memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1, 0x2000 - B3_RI_WTO_R1);
+ for (b = 0; b < 128; b++) {
+ /* This complicated switch statement is to make sure and
+ * only access regions that are unreserved.
+ * Some blocks are only valid on dual port cards.
+ * and block 3 has some special diagnostic registers that
+ * are poison.
+ */
+ switch (b) {
+ case 3:
+ /* skip diagnostic ram region */
+ memcpy_fromio(p + 0x10, io + 0x10, 128 - 0x10);
+ break;
- /* copy GMAC registers */
- memcpy_fromio(p + BASE_GMAC_1, io + BASE_GMAC_1, 0x1000);
- if (sky2->hw->ports > 1)
- memcpy_fromio(p + BASE_GMAC_2, io + BASE_GMAC_2, 0x1000);
+ /* dual port cards only */
+ case 5: /* Tx Arbiter 2 */
+ case 9: /* RX2 */
+ case 14 ... 15: /* TX2 */
+ case 17: case 19: /* Ram Buffer 2 */
+ case 22 ... 23: /* Tx Ram Buffer 2 */
+ case 25: /* Rx MAC Fifo 1 */
+ case 27: /* Tx MAC Fifo 2 */
+ case 31: /* GPHY 2 */
+ case 40 ... 47: /* Pattern Ram 2 */
+ case 52: case 54: /* TCP Segmentation 2 */
+ case 112 ... 116: /* GMAC 2 */
+ if (sky2->hw->ports == 1)
+ goto reserved;
+ /* fall through */
+ case 0: /* Control */
+ case 2: /* Mac address */
+ case 4: /* Tx Arbiter 1 */
+ case 7: /* PCI express reg */
+ case 8: /* RX1 */
+ case 12 ... 13: /* TX1 */
+ case 16: case 18:/* Rx Ram Buffer 1 */
+ case 20 ... 21: /* Tx Ram Buffer 1 */
+ case 24: /* Rx MAC Fifo 1 */
+ case 26: /* Tx MAC Fifo 1 */
+ case 28 ... 29: /* Descriptor and status unit */
+ case 30: /* GPHY 1*/
+ case 32 ... 39: /* Pattern Ram 1 */
+ case 48: case 50: /* TCP Segmentation 1 */
+ case 56 ... 60: /* PCI space */
+ case 80 ... 84: /* GMAC 1 */
+ memcpy_fromio(p, io, 128);
+ break;
+ default:
+reserved:
+ memset(p, 0, 128);
+ }
+ p += 128;
+ io += 128;
+ }
}
/* In order to do Jumbo packets on these chips, need to turn off the
@@ -3613,26 +3674,31 @@ static int sky2_get_eeprom_len(struct net_device *dev)
struct sky2_port *sky2 = netdev_priv(dev);
u16 reg2;
- reg2 = sky2_pci_read32(sky2->hw, PCI_DEV_REG2);
+ pci_read_config_word(sky2->hw->pdev, PCI_DEV_REG2, &reg2);
return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8);
}
-static u32 sky2_vpd_read(struct sky2_hw *hw, int cap, u16 offset)
+static u32 sky2_vpd_read(struct pci_dev *pdev, int cap, u16 offset)
{
- sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset);
+ u32 val;
+
+ pci_write_config_word(pdev, cap + PCI_VPD_ADDR, offset);
- while (!(sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F))
- cpu_relax();
- return sky2_pci_read32(hw, cap + PCI_VPD_DATA);
+ do {
+ pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
+ } while (!(offset & PCI_VPD_ADDR_F));
+
+ pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &val);
+ return val;
}
-static void sky2_vpd_write(struct sky2_hw *hw, int cap, u16 offset, u32 val)
+static void sky2_vpd_write(struct pci_dev *pdev, int cap, u16 offset, u32 val)
{
- sky2_pci_write32(hw, cap + PCI_VPD_DATA, val);
- sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F);
+ pci_write_config_word(pdev, cap + PCI_VPD_DATA, val);
+ pci_write_config_dword(pdev, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F);
do {
- cpu_relax();
- } while (sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F);
+ pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
+ } while (offset & PCI_VPD_ADDR_F);
}
static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
@@ -3649,7 +3715,7 @@ static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
eeprom->magic = SKY2_EEPROM_MAGIC;
while (length > 0) {
- u32 val = sky2_vpd_read(sky2->hw, cap, offset);
+ u32 val = sky2_vpd_read(sky2->hw->pdev, cap, offset);
int n = min_t(int, length, sizeof(val));
memcpy(data, &val, n);
@@ -3679,10 +3745,10 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
int n = min_t(int, length, sizeof(val));
if (n < sizeof(val))
- val = sky2_vpd_read(sky2->hw, cap, offset);
+ val = sky2_vpd_read(sky2->hw->pdev, cap, offset);
memcpy(&val, data, n);
- sky2_vpd_write(sky2->hw, cap, offset, val);
+ sky2_vpd_write(sky2->hw->pdev, cap, offset, val);
length -= n;
data += n;
@@ -3707,11 +3773,8 @@ static const struct ethtool_ops sky2_ethtool_ops = {
.get_eeprom_len = sky2_get_eeprom_len,
.get_eeprom = sky2_get_eeprom,
.set_eeprom = sky2_set_eeprom,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = sky2_set_tx_csum,
- .get_tso = ethtool_op_get_tso,
.set_tso = sky2_set_tso,
.get_rx_csum = sky2_get_rx_csum,
.set_rx_csum = sky2_set_rx_csum,
@@ -3723,7 +3786,7 @@ static const struct ethtool_ops sky2_ethtool_ops = {
.get_pauseparam = sky2_get_pauseparam,
.set_pauseparam = sky2_set_pauseparam,
.phys_id = sky2_phys_id,
- .get_stats_count = sky2_get_stats_count,
+ .get_sset_count = sky2_get_sset_count,
.get_ethtool_stats = sky2_get_ethtool_stats,
};
@@ -3735,7 +3798,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
{
struct net_device *dev = seq->private;
const struct sky2_port *sky2 = netdev_priv(dev);
- const struct sky2_hw *hw = sky2->hw;
+ struct sky2_hw *hw = sky2->hw;
unsigned port = sky2->port;
unsigned idx, last;
int sop;
@@ -3748,7 +3811,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
sky2_read32(hw, B0_IMSK),
sky2_read32(hw, B0_Y2_SP_ICR));
- netif_poll_disable(hw->dev[0]);
+ napi_disable(&hw->napi);
last = sky2_read16(hw, STAT_PUT_IDX);
if (hw->st_idx == last)
@@ -3818,7 +3881,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
last = sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)),
sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_LAST_IDX)));
- netif_poll_enable(hw->dev[0]);
+ napi_enable(&hw->napi);
return 0;
}
@@ -3843,42 +3906,34 @@ static int sky2_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
+ struct sky2_port *sky2 = netdev_priv(dev);
- if (dev->open == sky2_up) {
- struct sky2_port *sky2 = netdev_priv(dev);
+ if (dev->open != sky2_up || !sky2_debug)
+ return NOTIFY_DONE;
- switch(event) {
- case NETDEV_CHANGENAME:
- if (!netif_running(dev))
- break;
- /* fallthrough */
- case NETDEV_DOWN:
- case NETDEV_GOING_DOWN:
- if (sky2->debugfs) {
- printk(KERN_DEBUG PFX "%s: remove debugfs\n",
- dev->name);
- debugfs_remove(sky2->debugfs);
- sky2->debugfs = NULL;
- }
+ switch(event) {
+ case NETDEV_CHANGENAME:
+ if (sky2->debugfs) {
+ sky2->debugfs = debugfs_rename(sky2_debug, sky2->debugfs,
+ sky2_debug, dev->name);
+ }
+ break;
- if (event != NETDEV_CHANGENAME)
- break;
- /* fallthrough for changename */
- case NETDEV_UP:
- if (sky2_debug) {
- struct dentry *d;
- d = debugfs_create_file(dev->name, S_IRUGO,
- sky2_debug, dev,
- &sky2_debug_fops);
- if (d == NULL || IS_ERR(d))
- printk(KERN_INFO PFX
- "%s: debugfs create failed\n",
- dev->name);
- else
- sky2->debugfs = d;
- }
- break;
+ case NETDEV_GOING_DOWN:
+ if (sky2->debugfs) {
+ printk(KERN_DEBUG PFX "%s: remove debugfs\n",
+ dev->name);
+ debugfs_remove(sky2->debugfs);
+ sky2->debugfs = NULL;
}
+ break;
+
+ case NETDEV_UP:
+ sky2->debugfs = debugfs_create_file(dev->name, S_IRUGO,
+ sky2_debug, dev,
+ &sky2_debug_fops);
+ if (IS_ERR(sky2->debugfs))
+ sky2->debugfs = NULL;
}
return NOTIFY_DONE;
@@ -3925,31 +3980,23 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
struct net_device *dev = alloc_etherdev(sizeof(*sky2));
if (!dev) {
- dev_err(&hw->pdev->dev, "etherdev alloc failed");
+ dev_err(&hw->pdev->dev, "etherdev alloc failed\n");
return NULL;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &hw->pdev->dev);
dev->irq = hw->pdev->irq;
dev->open = sky2_up;
dev->stop = sky2_down;
dev->do_ioctl = sky2_ioctl;
dev->hard_start_xmit = sky2_xmit_frame;
- dev->get_stats = sky2_get_stats;
dev->set_multicast_list = sky2_set_multicast;
dev->set_mac_address = sky2_set_mac_address;
dev->change_mtu = sky2_change_mtu;
SET_ETHTOOL_OPS(dev, &sky2_ethtool_ops);
dev->tx_timeout = sky2_tx_timeout;
dev->watchdog_timeo = TX_WATCHDOG;
- if (port == 0)
- dev->poll = sky2_poll;
- dev->weight = NAPI_WEIGHT;
#ifdef CONFIG_NET_POLL_CONTROLLER
- /* Network console (only works on port 0)
- * because netpoll makes assumptions about NAPI
- */
if (port == 0)
dev->poll_controller = sky2_netpoll;
#endif
@@ -4000,12 +4047,11 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
static void __devinit sky2_show_addr(struct net_device *dev)
{
const struct sky2_port *sky2 = netdev_priv(dev);
+ DECLARE_MAC_BUF(mac);
if (netif_msg_probe(sky2))
- printk(KERN_INFO PFX "%s: addr %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_INFO PFX "%s: addr %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
}
/* Handle software interrupt used during MSI test */
@@ -4138,15 +4184,14 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
*/
{
u32 reg;
- reg = sky2_pci_read32(hw, PCI_DEV_REG2);
+ pci_read_config_dword(pdev,PCI_DEV_REG2, &reg);
reg &= ~PCI_REV_DESC;
- sky2_pci_write32(hw, PCI_DEV_REG2, reg);
+ pci_write_config_dword(pdev, PCI_DEV_REG2, reg);
}
#endif
/* ring for status responses */
- hw->st_le = pci_alloc_consistent(hw->pdev, STATUS_LE_BYTES,
- &hw->st_dma);
+ hw->st_le = pci_alloc_consistent(pdev, STATUS_LE_BYTES, &hw->st_dma);
if (!hw->st_le)
goto err_out_iounmap;
@@ -4181,6 +4226,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
goto err_out_free_netdev;
}
+ netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT);
+
err = request_irq(pdev->irq, sky2_intr,
(hw->flags & SKY2_HW_USE_MSI) ? 0 : IRQF_SHARED,
dev->name, hw);
@@ -4189,6 +4236,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
goto err_out_unregister;
}
sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
+ napi_enable(&hw->napi);
sky2_show_addr(dev);
@@ -4222,7 +4270,7 @@ err_out_free_netdev:
free_netdev(dev);
err_out_free_pci:
sky2_write8(hw, B0_CTST, CS_RST_SET);
- pci_free_consistent(hw->pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
+ pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
err_out_iounmap:
iounmap(hw->regs);
err_out_free_hw:
@@ -4239,23 +4287,18 @@ err_out:
static void __devexit sky2_remove(struct pci_dev *pdev)
{
struct sky2_hw *hw = pci_get_drvdata(pdev);
- struct net_device *dev0, *dev1;
+ int i;
if (!hw)
return;
del_timer_sync(&hw->watchdog_timer);
+ cancel_work_sync(&hw->restart_work);
- flush_scheduled_work();
+ for (i = hw->ports-1; i >= 0; --i)
+ unregister_netdev(hw->dev[i]);
sky2_write32(hw, B0_IMSK, 0);
- synchronize_irq(hw->pdev->irq);
-
- dev0 = hw->dev[0];
- dev1 = hw->dev[1];
- if (dev1)
- unregister_netdev(dev1);
- unregister_netdev(dev0);
sky2_power_aux(hw);
@@ -4270,9 +4313,9 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
pci_release_regions(pdev);
pci_disable_device(pdev);
- if (dev1)
- free_netdev(dev1);
- free_netdev(dev0);
+ for (i = hw->ports-1; i >= 0; --i)
+ free_netdev(hw->dev[i]);
+
iounmap(hw->regs);
kfree(hw);
@@ -4288,8 +4331,6 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
if (!hw)
return 0;
- netif_poll_disable(hw->dev[0]);
-
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
struct sky2_port *sky2 = netdev_priv(dev);
@@ -4304,6 +4345,7 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
}
sky2_write32(hw, B0_IMSK, 0);
+ napi_disable(&hw->napi);
sky2_power_aux(hw);
pci_save_state(pdev);
@@ -4335,11 +4377,11 @@ static int sky2_resume(struct pci_dev *pdev)
if (hw->chip_id == CHIP_ID_YUKON_EX ||
hw->chip_id == CHIP_ID_YUKON_EC_U ||
hw->chip_id == CHIP_ID_YUKON_FE_P)
- sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+ pci_write_config_dword(pdev, PCI_DEV_REG3, 0);
sky2_reset(hw);
-
sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
+ napi_enable(&hw->napi);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
@@ -4356,8 +4398,6 @@ static int sky2_resume(struct pci_dev *pdev)
}
}
- netif_poll_enable(hw->dev[0]);
-
return 0;
out:
dev_err(&pdev->dev, "resume failed (%d)\n", err);
@@ -4374,7 +4414,7 @@ static void sky2_shutdown(struct pci_dev *pdev)
if (!hw)
return;
- netif_poll_disable(hw->dev[0]);
+ del_timer_sync(&hw->watchdog_timer);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 8bc5c54e3ef..69525fd7908 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -18,14 +18,6 @@ enum {
PCI_CFG_REG_1 = 0x94,
};
-enum {
- PEX_DEV_CAP = 0xe4,
- PEX_DEV_CTRL = 0xe8,
- PEX_DEV_STA = 0xea,
- PEX_LNK_STAT = 0xf2,
- PEX_UNC_ERR_STAT= 0x104,
-};
-
/* Yukon-2 */
enum pci_dev_reg_1 {
PCI_Y2_PIG_ENA = 1<<31, /* Enable Plug-in-Go (YUKON-2) */
@@ -151,38 +143,6 @@ enum pci_cfg_reg1 {
PCI_STATUS_REC_TARGET_ABORT | \
PCI_STATUS_PARITY)
-enum pex_dev_ctrl {
- PEX_DC_MAX_RRS_MSK = 7<<12, /* Bit 14..12: Max. Read Request Size */
- PEX_DC_EN_NO_SNOOP = 1<<11,/* Enable No Snoop */
- PEX_DC_EN_AUX_POW = 1<<10,/* Enable AUX Power */
- PEX_DC_EN_PHANTOM = 1<<9, /* Enable Phantom Functions */
- PEX_DC_EN_EXT_TAG = 1<<8, /* Enable Extended Tag Field */
- PEX_DC_MAX_PLS_MSK = 7<<5, /* Bit 7.. 5: Max. Payload Size Mask */
- PEX_DC_EN_REL_ORD = 1<<4, /* Enable Relaxed Ordering */
- PEX_DC_EN_UNS_RQ_RP = 1<<3, /* Enable Unsupported Request Reporting */
- PEX_DC_EN_FAT_ER_RP = 1<<2, /* Enable Fatal Error Reporting */
- PEX_DC_EN_NFA_ER_RP = 1<<1, /* Enable Non-Fatal Error Reporting */
- PEX_DC_EN_COR_ER_RP = 1<<0, /* Enable Correctable Error Reporting */
-};
-#define PEX_DC_MAX_RD_RQ_SIZE(x) (((x)<<12) & PEX_DC_MAX_RRS_MSK)
-
-/* PEX_UNC_ERR_STAT PEX Uncorrectable Errors Status Register (Yukon-2) */
-enum pex_err {
- PEX_UNSUP_REQ = 1<<20, /* Unsupported Request Error */
-
- PEX_MALFOR_TLP = 1<<18, /* Malformed TLP */
-
- PEX_UNEXP_COMP = 1<<16, /* Unexpected Completion */
-
- PEX_COMP_TO = 1<<14, /* Completion Timeout */
- PEX_FLOW_CTRL_P = 1<<13, /* Flow Control Protocol Error */
- PEX_POIS_TLP = 1<<12, /* Poisoned TLP */
-
- PEX_DATA_LINK_P = 1<<4, /* Data Link Protocol Error */
- PEX_FATAL_ERRORS= (PEX_MALFOR_TLP | PEX_FLOW_CTRL_P | PEX_DATA_LINK_P),
-};
-
-
enum csr_regs {
B0_RAP = 0x0000,
B0_CTST = 0x0004,
@@ -287,7 +247,8 @@ enum csr_regs {
B3_PA_CTRL = 0x01f0,
B3_PA_TEST = 0x01f2,
- Y2_CFG_SPC = 0x1c00,
+ Y2_CFG_SPC = 0x1c00, /* PCI config space region */
+ Y2_CFG_AER = 0x1d00, /* PCI Advanced Error Report region */
};
/* B0_CTST 16 bit Control/Status register */
@@ -419,7 +380,6 @@ enum {
Y2_IS_PAR_RX2 | Y2_IS_TCP_TXS2| Y2_IS_TCP_TXA2,
Y2_HWE_ALL_MASK = Y2_IS_TIST_OV | Y2_IS_MST_ERR | Y2_IS_IRQ_STAT |
- Y2_IS_PCI_EXP |
Y2_HWE_L1_MASK | Y2_HWE_L2_MASK,
};
@@ -1850,6 +1810,28 @@ enum {
/* GPHY_CTRL 32 bit GPHY Control Reg (YUKON only) */
enum {
+ GPC_TX_PAUSE = 1<<30, /* Tx pause enabled (ro) */
+ GPC_RX_PAUSE = 1<<29, /* Rx pause enabled (ro) */
+ GPC_SPEED = 3<<27, /* PHY speed (ro) */
+ GPC_LINK = 1<<26, /* Link up (ro) */
+ GPC_DUPLEX = 1<<25, /* Duplex (ro) */
+ GPC_CLOCK = 1<<24, /* 125Mhz clock stable (ro) */
+
+ GPC_PDOWN = 1<<23, /* Internal regulator 2.5 power down */
+ GPC_TSTMODE = 1<<22, /* Test mode */
+ GPC_REG18 = 1<<21, /* Reg18 Power down */
+ GPC_REG12SEL = 3<<19, /* Reg12 power setting */
+ GPC_REG18SEL = 3<<17, /* Reg18 power setting */
+ GPC_SPILOCK = 1<<16, /* SPI lock (ASF) */
+
+ GPC_LEDMUX = 3<<14, /* LED Mux */
+ GPC_INTPOL = 1<<13, /* Interrupt polarity */
+ GPC_DETECT = 1<<12, /* Energy detect */
+ GPC_1000HD = 1<<11, /* Enable 1000Mbit HD */
+ GPC_SLAVE = 1<<10, /* Slave mode */
+ GPC_PAUSE = 1<<9, /* Pause enable */
+ GPC_LEDCTL = 3<<6, /* GPHY Leds */
+
GPC_RST_CLR = 1<<1, /* Clear GPHY Reset */
GPC_RST_SET = 1<<0, /* Set GPHY Reset */
};
@@ -2050,13 +2032,12 @@ struct sky2_port {
#ifdef CONFIG_SKY2_DEBUG
struct dentry *debugfs;
#endif
- struct net_device_stats net_stats;
-
};
struct sky2_hw {
void __iomem *regs;
struct pci_dev *pdev;
+ struct napi_struct napi;
struct net_device *dev[2];
unsigned long flags;
#define SKY2_HW_USE_MSI 0x00000001
@@ -2147,25 +2128,4 @@ static inline void gma_set_addr(struct sky2_hw *hw, unsigned port, unsigned reg,
gma_write16(hw, port, reg+4,(u16) addr[2] | ((u16) addr[3] << 8));
gma_write16(hw, port, reg+8,(u16) addr[4] | ((u16) addr[5] << 8));
}
-
-/* PCI config space access */
-static inline u32 sky2_pci_read32(const struct sky2_hw *hw, unsigned reg)
-{
- return sky2_read32(hw, Y2_CFG_SPC + reg);
-}
-
-static inline u16 sky2_pci_read16(const struct sky2_hw *hw, unsigned reg)
-{
- return sky2_read16(hw, Y2_CFG_SPC + reg);
-}
-
-static inline void sky2_pci_write32(struct sky2_hw *hw, unsigned reg, u32 val)
-{
- sky2_write32(hw, Y2_CFG_SPC + reg, val);
-}
-
-static inline void sky2_pci_write16(struct sky2_hw *hw, unsigned reg, u16 val)
-{
- sky2_write16(hw, Y2_CFG_SPC + reg, val);
-}
#endif
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 3fd4735006f..251a3ce376a 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -639,8 +639,6 @@ static void sl_setup(struct net_device *dev)
dev->addr_len = 0;
dev->tx_queue_len = 10;
- SET_MODULE_OWNER(dev);
-
/* New-style flags. */
dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;
}
@@ -1220,14 +1218,8 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
return 0;
/* VSV changes end */
#endif
-
- /* Allow stty to read, but not set, the serial port */
- case TCGETS:
- case TCGETA:
- return n_tty_ioctl(tty, file, cmd, arg);
-
default:
- return -ENOIOCTLCMD;
+ return tty_mode_ioctl(tty, file, cmd, arg);
}
}
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index ae1ae343bee..d6abb68e6e2 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -196,6 +196,7 @@ static int __init ultramca_probe(struct device *gen_dev)
int tirq = 0;
int base_addr = ultra_io[ultra_found];
int irq = ultra_irq[ultra_found];
+ DECLARE_MAC_BUF(mac);
if (base_addr || irq) {
printk(KERN_INFO "Probing for SMC MCA adapter");
@@ -264,7 +265,6 @@ static int __init ultramca_probe(struct device *gen_dev)
if(!dev)
return -ENODEV;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, gen_dev);
mca_device_set_name(mca_dev, smc_mca_adapter_names[adapter]);
mca_device_set_claim(mca_dev, 1);
@@ -331,10 +331,11 @@ static int __init ultramca_probe(struct device *gen_dev)
reg4 = inb(ioaddr + 4) & 0x7f;
outb(reg4, ioaddr + 4);
- printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x,", slot + 1, ioaddr);
-
for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
+ dev->dev_addr[i] = inb(ioaddr + 8 + i);
+
+ printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x, %s",
+ slot + 1, ioaddr, print_mac(mac, dev->dev_addr));
/* Switch from the station address to the alternate register set
* and read the useful registers there.
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index a52b22d7db6..00d6cf1af48 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -142,8 +142,6 @@ static int __init do_ultra_probe(struct net_device *dev)
int base_addr = dev->base_addr;
int irq = dev->irq;
- SET_MODULE_OWNER(dev);
-
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = &ultra_poll;
#endif
@@ -200,6 +198,7 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr)
unsigned char num_pages, irqreg, addr, piomode;
unsigned char idreg = inb(ioaddr + 7);
unsigned char reg4 = inb(ioaddr + 4) & 0x7f;
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -226,10 +225,11 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr)
model_name = (idreg & 0xF0) == 0x20 ? "SMC Ultra" : "SMC EtherEZ";
- printk("%s: %s at %#3x,", dev->name, model_name, ioaddr);
-
for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
+ dev->dev_addr[i] = inb(ioaddr + 8 + i);
+
+ printk("%s: %s at %#3x, %s", dev->name, model_name,
+ ioaddr, print_mac(mac, dev->dev_addr));
/* Switch from the station address to the alternate register set and
read the useful registers there. */
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index 88a30e56c64..a5a91ace28c 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -132,8 +132,6 @@ struct net_device * __init ultra32_probe(int unit)
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
-
irq = dev->irq;
/* EISA spec allows for up to 16 slots, but 8 is typical. */
@@ -165,6 +163,7 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr)
unsigned char idreg;
unsigned char reg4;
const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"};
+ DECLARE_MAC_BUF(mac);
if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -205,10 +204,11 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr)
model_name = "SMC Ultra32";
- printk("%s: %s at 0x%X,", dev->name, model_name, ioaddr);
-
for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
+ dev->dev_addr[i] = inb(ioaddr + 8 + i);
+
+ printk("%s: %s at 0x%X, %s",
+ dev->name, model_name, ioaddr, print_mac(mac, dev->dev_addr));
/* Switch from the station address to the alternate register set and
read the useful registers there. */
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index db43e42bee3..dd18af0ce67 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -115,13 +115,6 @@ struct smc911x_local {
*/
struct sk_buff *pending_tx_skb;
- /*
- * these are things that the kernel wants me to keep, so users
- * can find out semi-useless statistics of how well the card is
- * performing
- */
- struct net_device_stats stats;
-
/* version/revision of the SMC911x chip */
u16 version;
u16 revision;
@@ -315,8 +308,8 @@ static void smc911x_reset(struct net_device *dev)
if (lp->pending_tx_skb != NULL) {
dev_kfree_skb (lp->pending_tx_skb);
lp->pending_tx_skb = NULL;
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
}
}
@@ -449,14 +442,14 @@ static inline void smc911x_rcv(struct net_device *dev)
pkt_len = (status & RX_STS_PKT_LEN_) >> 16;
if (status & RX_STS_ES_) {
/* Deal with a bad packet */
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (status & RX_STS_CRC_ERR_)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
else {
if (status & RX_STS_LEN_ERR_)
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (status & RX_STS_MCAST_)
- lp->stats.multicast++;
+ dev->stats.multicast++;
}
/* Remove the bad packet data from the RX FIFO */
smc911x_drop_pkt(dev);
@@ -467,7 +460,7 @@ static inline void smc911x_rcv(struct net_device *dev)
if (unlikely(skb == NULL)) {
PRINTK( "%s: Low memory, rcvd packet dropped.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
smc911x_drop_pkt(dev);
return;
}
@@ -503,8 +496,8 @@ static inline void smc911x_rcv(struct net_device *dev)
dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len-4;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len-4;
#endif
}
}
@@ -616,8 +609,8 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk("%s: No Tx free space %d < %d\n",
dev->name, free, skb->len);
lp->pending_tx_skb = NULL;
- lp->stats.tx_errors++;
- lp->stats.tx_dropped++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
return 0;
}
@@ -667,8 +660,8 @@ static void smc911x_tx(struct net_device *dev)
dev->name,
(SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TSUSED_) >> 16);
tx_status = SMC_GET_TX_STS_FIFO();
- lp->stats.tx_packets++;
- lp->stats.tx_bytes+=tx_status>>16;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes+=tx_status>>16;
DBG(SMC_DEBUG_TX, "%s: Tx FIFO tag 0x%04x status 0x%04x\n",
dev->name, (tx_status & 0xffff0000) >> 16,
tx_status & 0x0000ffff);
@@ -676,22 +669,22 @@ static void smc911x_tx(struct net_device *dev)
* full-duplex mode */
if ((tx_status & TX_STS_ES_) && !(lp->ctl_rfduplx &&
!(tx_status & 0x00000306))) {
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
}
if (tx_status & TX_STS_MANY_COLL_) {
- lp->stats.collisions+=16;
- lp->stats.tx_aborted_errors++;
+ dev->stats.collisions+=16;
+ dev->stats.tx_aborted_errors++;
} else {
- lp->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3;
+ dev->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3;
}
/* carrier error only has meaning for half-duplex communication */
if ((tx_status & (TX_STS_LOC_ | TX_STS_NO_CARR_)) &&
!lp->ctl_rfduplx) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
}
if (tx_status & TX_STS_LATE_COLL_) {
- lp->stats.collisions++;
- lp->stats.tx_aborted_errors++;
+ dev->stats.collisions++;
+ dev->stats.tx_aborted_errors++;
}
}
}
@@ -1121,11 +1114,11 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id)
/* Handle various error conditions */
if (status & INT_STS_RXE_) {
SMC_ACK_INT(INT_STS_RXE_);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
if (status & INT_STS_RXDFH_INT_) {
SMC_ACK_INT(INT_STS_RXDFH_INT_);
- lp->stats.rx_dropped+=SMC_GET_RX_DROP();
+ dev->stats.rx_dropped+=SMC_GET_RX_DROP();
}
/* Undocumented interrupt-what is the right thing to do here? */
if (status & INT_STS_RXDF_INT_) {
@@ -1140,8 +1133,8 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id)
cr &= ~MAC_CR_RXEN_;
SMC_SET_MAC_CR(cr);
DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
}
SMC_ACK_INT(INT_STS_RDFL_);
}
@@ -1152,8 +1145,8 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id)
SMC_SET_MAC_CR(cr);
rx_overrun=1;
DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
}
SMC_ACK_INT(INT_STS_RDFO_);
}
@@ -1230,7 +1223,7 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id)
}
#endif
- /* Handle PHY interupt condition */
+ /* Handle PHY interrupt condition */
if (status & INT_STS_PHY_INT_) {
DBG(SMC_DEBUG_MISC, "%s: PHY irq\n", dev->name);
smc911x_phy_interrupt(dev);
@@ -1307,8 +1300,8 @@ smc911x_rx_dma_irq(int dma, void *data)
dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
spin_lock_irqsave(&lp->lock, flags);
pkts = (SMC_GET_RX_FIFO_INF() & RX_FIFO_INF_RXSUSED_) >> 16;
@@ -1568,19 +1561,6 @@ static int smc911x_close(struct net_device *dev)
}
/*
- * Get the current statistics.
- * This may be called with the card open or closed.
- */
-static struct net_device_stats *smc911x_query_statistics(struct net_device *dev)
-{
- struct smc911x_local *lp = netdev_priv(dev);
- DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
-
-
- return &lp->stats;
-}
-
-/*
* Ethtool support
*/
static int
@@ -2056,7 +2036,6 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr)
dev->hard_start_xmit = smc911x_hard_start_xmit;
dev->tx_timeout = smc911x_timeout;
dev->watchdog_timeo = msecs_to_jiffies(watchdog);
- dev->get_stats = smc911x_query_statistics;
dev->set_multicast_list = smc911x_set_multicast_list;
dev->ethtool_ops = &smc911x_ethtool_ops;
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2084,7 +2063,7 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr)
/* Grab the IRQ */
retval = request_irq(dev->irq, &smc911x_interrupt,
- IRQF_SHARED | IRQF_TRIGGER_FALLING, dev->name, dev);
+ IRQF_SHARED | SMC_IRQ_SENSE, dev->name, dev);
if (retval)
goto err_out;
@@ -2181,7 +2160,6 @@ static int smc911x_drv_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto release_1;
}
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
ndev->dma = (unsigned char)-1;
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
index 962a710459f..16a0edc078f 100644
--- a/drivers/net/smc911x.h
+++ b/drivers/net/smc911x.h
@@ -36,6 +36,12 @@
#define SMC_USE_PXA_DMA 1
#define SMC_USE_16BIT 0
#define SMC_USE_32BIT 1
+ #define SMC_IRQ_SENSE IRQF_TRIGGER_FALLING
+#elif CONFIG_SH_MAGIC_PANEL_R2
+ #define SMC_USE_SH_DMA 0
+ #define SMC_USE_16BIT 0
+ #define SMC_USE_32BIT 1
+ #define SMC_IRQ_SENSE IRQF_TRIGGER_LOW
#endif
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 36c1ebadbf2..cb2698de519 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -191,13 +191,6 @@ static struct devlist smc_devlist[] __initdata = {
/* store this information for the driver.. */
struct smc_local {
/*
- these are things that the kernel wants me to keep, so users
- can find out semi-useless statistics of how well the card is
- performing
- */
- struct net_device_stats stats;
-
- /*
If I have to wait until memory is available to send
a packet, I will store the skbuff here, until I get the
desired memory. Then, I'll send it out and free it.
@@ -249,12 +242,6 @@ static void smc_timeout(struct net_device *dev);
static int smc_close(struct net_device *dev);
/*
- . This routine allows the proc file system to query the driver's
- . statistics.
-*/
-static struct net_device_stats * smc_query_statistics( struct net_device *dev);
-
-/*
. Finally, a call to set promiscuous mode ( for TCPDUMP and related
. programs ) and multicast modes.
*/
@@ -514,7 +501,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
if ( lp->saved_skb) {
/* THIS SHOULD NEVER HAPPEN. */
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
printk(CARDNAME": Bad Craziness - sent packet while busy.\n" );
return 1;
}
@@ -744,8 +731,6 @@ struct net_device * __init smc_init(int unit)
irq = dev->irq;
}
- SET_MODULE_OWNER(dev);
-
if (io > 0x1ff) { /* Check a single specified location. */
err = smc_probe(dev, io);
} else if (io != 0) { /* Don't probe at all. */
@@ -891,6 +876,8 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
word memory_info_register;
word memory_cfg_register;
+ DECLARE_MAC_BUF(mac);
+
/* Grab the region so that no one else tries to probe our ioports. */
if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME))
return -EBUSY;
@@ -1046,10 +1033,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
/*
. Print the Ethernet address
*/
- printk("ADDR: ");
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i] );
- printk("%2.2x \n", dev->dev_addr[5] );
+ printk("ADDR: %s\n", print_mac(mac, dev->dev_addr));
/* set the private data to zero by default */
memset(dev->priv, 0, sizeof(struct smc_local));
@@ -1067,7 +1051,6 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
dev->hard_start_xmit = smc_wait_to_send_packet;
dev->tx_timeout = smc_timeout;
dev->watchdog_timeo = HZ/20;
- dev->get_stats = smc_query_statistics;
dev->set_multicast_list = smc_set_multicast_list;
return 0;
@@ -1201,7 +1184,6 @@ static void smc_timeout(struct net_device *dev)
*/
static void smc_rcv(struct net_device *dev)
{
- struct smc_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int packet_number;
word status;
@@ -1245,13 +1227,13 @@ static void smc_rcv(struct net_device *dev)
/* set multicast stats */
if ( status & RS_MULTICAST )
- lp->stats.multicast++;
+ dev->stats.multicast++;
skb = dev_alloc_skb( packet_length + 5);
if ( skb == NULL ) {
printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n");
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto done;
}
@@ -1291,16 +1273,16 @@ static void smc_rcv(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev );
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += packet_length;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += packet_length;
} else {
/* error ... */
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
- if ( status & RS_ALGNERR ) lp->stats.rx_frame_errors++;
+ if ( status & RS_ALGNERR ) dev->stats.rx_frame_errors++;
if ( status & (RS_TOOSHORT | RS_TOOLONG ) )
- lp->stats.rx_length_errors++;
- if ( status & RS_BADCRC) lp->stats.rx_crc_errors++;
+ dev->stats.rx_length_errors++;
+ if ( status & RS_BADCRC) dev->stats.rx_crc_errors++;
}
done:
@@ -1348,12 +1330,12 @@ static void smc_tx( struct net_device * dev )
tx_status = inw( ioaddr + DATA_1 );
PRINTK3((CARDNAME": TX DONE STATUS: %4x \n", tx_status ));
- lp->stats.tx_errors++;
- if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++;
+ dev->stats.tx_errors++;
+ if ( tx_status & TS_LOSTCAR ) dev->stats.tx_carrier_errors++;
if ( tx_status & TS_LATCOL ) {
printk(KERN_DEBUG CARDNAME
": Late collision occurred on last xmit.\n");
- lp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
}
#if 0
if ( tx_status & TS_16COL ) { ... }
@@ -1448,10 +1430,10 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id)
SMC_SELECT_BANK( 0 );
card_stats = inw( ioaddr + COUNTER );
/* single collisions */
- lp->stats.collisions += card_stats & 0xF;
+ dev->stats.collisions += card_stats & 0xF;
card_stats >>= 4;
/* multiple collisions */
- lp->stats.collisions += card_stats & 0xF;
+ dev->stats.collisions += card_stats & 0xF;
/* these are for when linux supports these statistics */
@@ -1460,7 +1442,7 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id)
": TX_BUFFER_EMPTY handled\n"));
outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT );
mask &= ~IM_TX_EMPTY_INT;
- lp->stats.tx_packets += lp->packets_waiting;
+ dev->stats.tx_packets += lp->packets_waiting;
lp->packets_waiting = 0;
} else if (status & IM_ALLOC_INT ) {
@@ -1479,8 +1461,8 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id)
PRINTK2((CARDNAME": Handoff done successfully.\n"));
} else if (status & IM_RX_OVRN_INT ) {
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT );
} else if (status & IM_EPH_INT ) {
PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n"));
@@ -1523,16 +1505,6 @@ static int smc_close(struct net_device *dev)
return 0;
}
-/*------------------------------------------------------------
- . Get the current statistics.
- . This may be called with the card open or closed.
- .-------------------------------------------------------------*/
-static struct net_device_stats* smc_query_statistics(struct net_device *dev) {
- struct smc_local *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/*-----------------------------------------------------------
. smc_set_multicast_list
.
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 01cc3c742c3..7da7589d45d 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -173,56 +173,6 @@ MODULE_LICENSE("GPL");
*/
#define MII_DELAY 1
-/* store this information for the driver.. */
-struct smc_local {
- /*
- * If I have to wait until memory is available to send a
- * packet, I will store the skbuff here, until I get the
- * desired memory. Then, I'll send it out and free it.
- */
- struct sk_buff *pending_tx_skb;
- struct tasklet_struct tx_task;
-
- /*
- * these are things that the kernel wants me to keep, so users
- * can find out semi-useless statistics of how well the card is
- * performing
- */
- struct net_device_stats stats;
-
- /* version/revision of the SMC91x chip */
- int version;
-
- /* Contains the current active transmission mode */
- int tcr_cur_mode;
-
- /* Contains the current active receive mode */
- int rcr_cur_mode;
-
- /* Contains the current active receive/phy mode */
- int rpc_cur_mode;
- int ctl_rfduplx;
- int ctl_rspeed;
-
- u32 msg_enable;
- u32 phy_type;
- struct mii_if_info mii;
-
- /* work queue */
- struct work_struct phy_configure;
- struct net_device *dev;
- int work_pending;
-
- spinlock_t lock;
-
-#ifdef SMC_USE_PXA_DMA
- /* DMA needs the physical address of the chip */
- u_long physaddr;
-#endif
- void __iomem *base;
- void __iomem *datacs;
-};
-
#if SMC_DEBUG > 0
#define DBG(n, args...) \
do { \
@@ -332,8 +282,8 @@ static void smc_reset(struct net_device *dev)
/* free any pending tx skb */
if (pending_skb) {
dev_kfree_skb(pending_skb);
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
}
/*
@@ -512,13 +462,13 @@ static inline void smc_rcv(struct net_device *dev)
}
SMC_WAIT_MMU_BUSY();
SMC_SET_MMU_CMD(MC_RELEASE);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (status & RS_ALGNERR)
- lp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (status & (RS_TOOSHORT | RS_TOOLONG))
- lp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (status & RS_BADCRC)
- lp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
} else {
struct sk_buff *skb;
unsigned char *data;
@@ -526,7 +476,7 @@ static inline void smc_rcv(struct net_device *dev)
/* set multicast stats */
if (status & RS_MULTICAST)
- lp->stats.multicast++;
+ dev->stats.multicast++;
/*
* Actual payload is packet_len - 6 (or 5 if odd byte).
@@ -542,7 +492,7 @@ static inline void smc_rcv(struct net_device *dev)
dev->name);
SMC_WAIT_MMU_BUSY();
SMC_SET_MMU_CMD(MC_RELEASE);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
@@ -570,8 +520,8 @@ static inline void smc_rcv(struct net_device *dev)
dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += data_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += data_len;
}
}
@@ -644,8 +594,8 @@ static void smc_hardware_send_pkt(unsigned long data)
packet_no = SMC_GET_AR();
if (unlikely(packet_no & AR_FAILED)) {
printk("%s: Memory allocation failed.\n", dev->name);
- lp->stats.tx_errors++;
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_fifo_errors++;
smc_special_unlock(&lp->lock);
goto done;
}
@@ -688,8 +638,8 @@ static void smc_hardware_send_pkt(unsigned long data)
smc_special_unlock(&lp->lock);
dev->trans_start = jiffies;
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += len;
SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT);
@@ -729,8 +679,8 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
if (unlikely(numPages > 7)) {
printk("%s: Far too big packet error.\n", dev->name);
- lp->stats.tx_errors++;
- lp->stats.tx_dropped++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
return 0;
}
@@ -803,17 +753,17 @@ static void smc_tx(struct net_device *dev)
dev->name, tx_status, packet_no);
if (!(tx_status & ES_TX_SUC))
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (tx_status & ES_LOSTCARR)
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (tx_status & (ES_LATCOL | ES_16COL)) {
PRINTK("%s: %s occurred on last xmit\n", dev->name,
(tx_status & ES_LATCOL) ?
"late collision" : "too many collisions");
- lp->stats.tx_window_errors++;
- if (!(lp->stats.tx_window_errors & 63) && net_ratelimit()) {
+ dev->stats.tx_window_errors++;
+ if (!(dev->stats.tx_window_errors & 63) && net_ratelimit()) {
printk(KERN_INFO "%s: unexpectedly large number of "
"bad collisions. Please check duplex "
"setting.\n", dev->name);
@@ -1347,19 +1297,19 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id)
SMC_SELECT_BANK(2);
/* single collisions */
- lp->stats.collisions += card_stats & 0xF;
+ dev->stats.collisions += card_stats & 0xF;
card_stats >>= 4;
/* multiple collisions */
- lp->stats.collisions += card_stats & 0xF;
+ dev->stats.collisions += card_stats & 0xF;
} else if (status & IM_RX_OVRN_INT) {
DBG(1, "%s: RX overrun (EPH_ST 0x%04x)\n", dev->name,
({ int eph_st; SMC_SELECT_BANK(0);
eph_st = SMC_GET_EPH_STATUS();
SMC_SELECT_BANK(2); eph_st; }) );
SMC_ACK_INT(IM_RX_OVRN_INT);
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
} else if (status & IM_EPH_INT) {
smc_eph_interrupt(dev);
} else if (status & IM_MDINT) {
@@ -1628,19 +1578,6 @@ static int smc_close(struct net_device *dev)
}
/*
- * Get the current statistics.
- * This may be called with the card open or closed.
- */
-static struct net_device_stats *smc_query_statistics(struct net_device *dev)
-{
- struct smc_local *lp = netdev_priv(dev);
-
- DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
-
- return &lp->stats;
-}
-
-/*
* Ethtool support
*/
static int
@@ -1842,9 +1779,10 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
{
struct smc_local *lp = netdev_priv(dev);
static int version_printed = 0;
- int i, retval;
+ int retval;
unsigned int val, revision_register;
const char *version_string;
+ DECLARE_MAC_BUF(mac);
DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
@@ -1965,7 +1903,6 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
dev->hard_start_xmit = smc_hard_start_xmit;
dev->tx_timeout = smc_timeout;
dev->watchdog_timeo = msecs_to_jiffies(watchdog);
- dev->get_stats = smc_query_statistics;
dev->set_multicast_list = smc_set_multicast_list;
dev->ethtool_ops = &smc_ethtool_ops;
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2035,10 +1972,8 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
"set using ifconfig\n", dev->name);
} else {
/* Print the Ethernet address */
- printk("%s: Ethernet addr: ", dev->name);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x\n", dev->dev_addr[5]);
+ printk("%s: Ethernet addr: %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
}
if (lp->phy_type == 0) {
@@ -2212,7 +2147,6 @@ static int smc_drv_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto out_release_io;
}
- SET_MODULE_OWNER(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
ndev->dma = (unsigned char)-1;
@@ -2238,17 +2172,19 @@ static int smc_drv_probe(struct platform_device *pdev)
goto out_release_attrib;
}
- platform_set_drvdata(pdev, ndev);
- ret = smc_probe(ndev, addr);
- if (ret != 0)
- goto out_iounmap;
#ifdef SMC_USE_PXA_DMA
- else {
+ {
struct smc_local *lp = netdev_priv(ndev);
+ lp->device = &pdev->dev;
lp->physaddr = res->start;
}
#endif
+ platform_set_drvdata(pdev, ndev);
+ ret = smc_probe(ndev, addr);
+ if (ret != 0)
+ goto out_iounmap;
+
smc_request_datacs(pdev, ndev);
return 0;
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index 6ff3a1627af..db34e1eb67e 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -224,6 +224,21 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
}
}
+#elif defined(CONFIG_MACH_ZYLONITE)
+
+#define SMC_CAN_USE_8BIT 1
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 0
+#define SMC_IO_SHIFT 0
+#define SMC_NOWAIT 1
+#define SMC_USE_PXA_DMA 1
+#define SMC_inb(a, r) readb((a) + (r))
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_insw(a, r, p, l) insw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l)
+#define SMC_outb(v, a, r) writeb(v, (a) + (r))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+
#elif defined(CONFIG_ARCH_OMAP)
/* We can only do 16-bit reads and writes in the static memory space. */
@@ -284,6 +299,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
#elif defined(CONFIG_SUPERH)
#ifdef CONFIG_SOLUTION_ENGINE
+#define SMC_IRQ_FLAGS (0)
#define SMC_CAN_USE_8BIT 0
#define SMC_CAN_USE_16BIT 1
#define SMC_CAN_USE_32BIT 0
@@ -461,6 +477,52 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r,
#endif
+
+/* store this information for the driver.. */
+struct smc_local {
+ /*
+ * If I have to wait until memory is available to send a
+ * packet, I will store the skbuff here, until I get the
+ * desired memory. Then, I'll send it out and free it.
+ */
+ struct sk_buff *pending_tx_skb;
+ struct tasklet_struct tx_task;
+
+ /* version/revision of the SMC91x chip */
+ int version;
+
+ /* Contains the current active transmission mode */
+ int tcr_cur_mode;
+
+ /* Contains the current active receive mode */
+ int rcr_cur_mode;
+
+ /* Contains the current active receive/phy mode */
+ int rpc_cur_mode;
+ int ctl_rfduplx;
+ int ctl_rspeed;
+
+ u32 msg_enable;
+ u32 phy_type;
+ struct mii_if_info mii;
+
+ /* work queue */
+ struct work_struct phy_configure;
+ struct net_device *dev;
+ int work_pending;
+
+ spinlock_t lock;
+
+#ifdef SMC_USE_PXA_DMA
+ /* DMA needs the physical address of the chip */
+ u_long physaddr;
+ struct device *device;
+#endif
+ void __iomem *base;
+ void __iomem *datacs;
+};
+
+
#ifdef SMC_USE_PXA_DMA
/*
* Let's use the DMA engine on the XScale PXA2xx for RX packets. This is
@@ -475,11 +537,12 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r,
#ifdef SMC_insl
#undef SMC_insl
#define SMC_insl(a, r, p, l) \
- smc_pxa_dma_insl(a, lp->physaddr, r, dev->dma, p, l)
+ smc_pxa_dma_insl(a, lp, r, dev->dma, p, l)
static inline void
-smc_pxa_dma_insl(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
+smc_pxa_dma_insl(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
u_char *buf, int len)
{
+ u_long physaddr = lp->physaddr;
dma_addr_t dmabuf;
/* fallback if no DMA available */
@@ -496,7 +559,7 @@ smc_pxa_dma_insl(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
}
len *= 4;
- dmabuf = dma_map_single(NULL, buf, len, DMA_FROM_DEVICE);
+ dmabuf = dma_map_single(lp->device, buf, len, DMA_FROM_DEVICE);
DCSR(dma) = DCSR_NODESC;
DTADR(dma) = dmabuf;
DSADR(dma) = physaddr + reg;
@@ -506,18 +569,19 @@ smc_pxa_dma_insl(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
while (!(DCSR(dma) & DCSR_STOPSTATE))
cpu_relax();
DCSR(dma) = 0;
- dma_unmap_single(NULL, dmabuf, len, DMA_FROM_DEVICE);
+ dma_unmap_single(lp->device, dmabuf, len, DMA_FROM_DEVICE);
}
#endif
#ifdef SMC_insw
#undef SMC_insw
#define SMC_insw(a, r, p, l) \
- smc_pxa_dma_insw(a, lp->physaddr, r, dev->dma, p, l)
+ smc_pxa_dma_insw(a, lp, r, dev->dma, p, l)
static inline void
-smc_pxa_dma_insw(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
+smc_pxa_dma_insw(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
u_char *buf, int len)
{
+ u_long physaddr = lp->physaddr;
dma_addr_t dmabuf;
/* fallback if no DMA available */
@@ -534,7 +598,7 @@ smc_pxa_dma_insw(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
}
len *= 2;
- dmabuf = dma_map_single(NULL, buf, len, DMA_FROM_DEVICE);
+ dmabuf = dma_map_single(lp->device, buf, len, DMA_FROM_DEVICE);
DCSR(dma) = DCSR_NODESC;
DTADR(dma) = dmabuf;
DSADR(dma) = physaddr + reg;
@@ -544,7 +608,7 @@ smc_pxa_dma_insw(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
while (!(DCSR(dma) & DCSR_STOPSTATE))
cpu_relax();
DCSR(dma) = 0;
- dma_unmap_single(NULL, dmabuf, len, DMA_FROM_DEVICE);
+ dma_unmap_single(lp->device, dmabuf, len, DMA_FROM_DEVICE);
}
#endif
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 82d837ab4db..bccae7e5c6a 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -46,7 +46,7 @@
#include <linux/vmalloc.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
#include <asm/pci-bridge.h>
#include <net/checksum.h>
@@ -795,6 +795,7 @@ spider_net_set_low_watermark(struct spider_net_card *card)
static int
spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
{
+ struct net_device *dev = card->netdev;
struct spider_net_descr_chain *chain = &card->tx_chain;
struct spider_net_descr *descr;
struct spider_net_hw_descr *hwdescr;
@@ -815,8 +816,8 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
status = spider_net_get_descr_status(hwdescr);
switch (status) {
case SPIDER_NET_DESCR_COMPLETE:
- card->netdev_stats.tx_packets++;
- card->netdev_stats.tx_bytes += descr->skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += descr->skb->len;
break;
case SPIDER_NET_DESCR_CARDOWNED:
@@ -835,11 +836,11 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
if (netif_msg_tx_err(card))
dev_err(&card->netdev->dev, "forcing end of tx descriptor "
"with status x%02x\n", status);
- card->netdev_stats.tx_errors++;
+ dev->stats.tx_errors++;
break;
default:
- card->netdev_stats.tx_dropped++;
+ dev->stats.tx_dropped++;
if (!brutal) {
spin_unlock_irqrestore(&chain->lock, flags);
return 1;
@@ -919,7 +920,7 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
spider_net_release_tx_chain(card, 0);
if (spider_net_prepare_tx_descr(card, skb) != 0) {
- card->netdev_stats.tx_dropped++;
+ netdev->stats.tx_dropped++;
netif_stop_queue(netdev);
return NETDEV_TX_BUSY;
}
@@ -979,16 +980,12 @@ static void
spider_net_pass_skb_up(struct spider_net_descr *descr,
struct spider_net_card *card)
{
- struct spider_net_hw_descr *hwdescr= descr->hwdescr;
- struct sk_buff *skb;
- struct net_device *netdev;
- u32 data_status, data_error;
-
- data_status = hwdescr->data_status;
- data_error = hwdescr->data_error;
- netdev = card->netdev;
+ struct spider_net_hw_descr *hwdescr = descr->hwdescr;
+ struct sk_buff *skb = descr->skb;
+ struct net_device *netdev = card->netdev;
+ u32 data_status = hwdescr->data_status;
+ u32 data_error = hwdescr->data_error;
- skb = descr->skb;
skb_put(skb, hwdescr->valid_size);
/* the card seems to add 2 bytes of junk in front
@@ -1015,8 +1012,8 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
}
/* update netdevice statistics */
- card->netdev_stats.rx_packets++;
- card->netdev_stats.rx_bytes += skb->len;
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += skb->len;
/* pass skb up to stack */
netif_receive_skb(skb);
@@ -1184,6 +1181,7 @@ static int spider_net_resync_tail_ptr(struct spider_net_card *card)
static int
spider_net_decode_one_descr(struct spider_net_card *card)
{
+ struct net_device *dev = card->netdev;
struct spider_net_descr_chain *chain = &card->rx_chain;
struct spider_net_descr *descr = chain->tail;
struct spider_net_hw_descr *hwdescr = descr->hwdescr;
@@ -1210,9 +1208,9 @@ spider_net_decode_one_descr(struct spider_net_card *card)
(status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
(status == SPIDER_NET_DESCR_FORCE_END) ) {
if (netif_msg_rx_err(card))
- dev_err(&card->netdev->dev,
+ dev_err(&dev->dev,
"dropping RX descriptor with state %d\n", status);
- card->netdev_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto bad_desc;
}
@@ -1278,34 +1276,26 @@ bad_desc:
* (using netif_receive_skb). If all/enough packets are up, the driver
* reenables interrupts and returns 0. If not, 1 is returned.
*/
-static int
-spider_net_poll(struct net_device *netdev, int *budget)
+static int spider_net_poll(struct napi_struct *napi, int budget)
{
- struct spider_net_card *card = netdev_priv(netdev);
- int packets_to_do, packets_done = 0;
- int no_more_packets = 0;
-
- packets_to_do = min(*budget, netdev->quota);
-
- while (packets_to_do) {
- if (spider_net_decode_one_descr(card)) {
- packets_done++;
- packets_to_do--;
- } else {
- /* no more packets for the stack */
- no_more_packets = 1;
+ struct spider_net_card *card = container_of(napi, struct spider_net_card, napi);
+ struct net_device *netdev = card->netdev;
+ int packets_done = 0;
+
+ while (packets_done < budget) {
+ if (!spider_net_decode_one_descr(card))
break;
- }
+
+ packets_done++;
}
if ((packets_done == 0) && (card->num_rx_ints != 0)) {
- no_more_packets = spider_net_resync_tail_ptr(card);
+ if (!spider_net_resync_tail_ptr(card))
+ packets_done = budget;
spider_net_resync_head_ptr(card);
}
card->num_rx_ints = 0;
- netdev->quota -= packets_done;
- *budget -= packets_done;
spider_net_refill_rx_chain(card);
spider_net_enable_rxdmac(card);
@@ -1313,28 +1303,13 @@ spider_net_poll(struct net_device *netdev, int *budget)
/* if all packets are in the stack, enable interrupts and return 0 */
/* if not, return 1 */
- if (no_more_packets) {
- netif_rx_complete(netdev);
+ if (packets_done < budget) {
+ netif_rx_complete(netdev, napi);
spider_net_rx_irq_on(card);
card->ignore_rx_ramfull = 0;
- return 0;
}
- return 1;
-}
-
-/**
- * spider_net_get_stats - get interface statistics
- * @netdev: interface device structure
- *
- * returns the interface statistics residing in the spider_net_card struct
- */
-static struct net_device_stats *
-spider_net_get_stats(struct net_device *netdev)
-{
- struct spider_net_card *card = netdev_priv(netdev);
- struct net_device_stats *stats = &card->netdev_stats;
- return stats;
+ return packets_done;
}
/**
@@ -1560,7 +1535,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
spider_net_refill_rx_chain(card);
spider_net_enable_rxdmac(card);
card->num_rx_ints ++;
- netif_rx_schedule(card->netdev);
+ netif_rx_schedule(card->netdev,
+ &card->napi);
}
show_error = 0;
break;
@@ -1580,7 +1556,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
spider_net_refill_rx_chain(card);
spider_net_enable_rxdmac(card);
card->num_rx_ints ++;
- netif_rx_schedule(card->netdev);
+ netif_rx_schedule(card->netdev,
+ &card->napi);
show_error = 0;
break;
@@ -1594,7 +1571,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
spider_net_refill_rx_chain(card);
spider_net_enable_rxdmac(card);
card->num_rx_ints ++;
- netif_rx_schedule(card->netdev);
+ netif_rx_schedule(card->netdev,
+ &card->napi);
show_error = 0;
break;
@@ -1661,7 +1639,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
/**
* spider_net_interrupt - interrupt handler for spider_net
- * @irq: interupt number
+ * @irq: interrupt number
* @ptr: pointer to net_device
* @regs: PU registers
*
@@ -1686,11 +1664,11 @@ spider_net_interrupt(int irq, void *ptr)
if (status_reg & SPIDER_NET_RXINT ) {
spider_net_rx_irq_off(card);
- netif_rx_schedule(netdev);
+ netif_rx_schedule(netdev, &card->napi);
card->num_rx_ints ++;
}
if (status_reg & SPIDER_NET_TXINT)
- netif_rx_schedule(netdev);
+ netif_rx_schedule(netdev, &card->napi);
if (status_reg & SPIDER_NET_LINKINT)
spider_net_link_reset(netdev);
@@ -2034,7 +2012,7 @@ spider_net_open(struct net_device *netdev)
netif_start_queue(netdev);
netif_carrier_on(netdev);
- netif_poll_enable(netdev);
+ napi_enable(&card->napi);
spider_net_enable_interrupts(card);
@@ -2204,7 +2182,7 @@ spider_net_stop(struct net_device *netdev)
{
struct spider_net_card *card = netdev_priv(netdev);
- netif_poll_disable(netdev);
+ napi_disable(&card->napi);
netif_carrier_off(netdev);
netif_stop_queue(netdev);
del_timer_sync(&card->tx_timer);
@@ -2296,7 +2274,6 @@ spider_net_setup_netdev_ops(struct net_device *netdev)
netdev->open = &spider_net_open;
netdev->stop = &spider_net_stop;
netdev->hard_start_xmit = &spider_net_xmit;
- netdev->get_stats = &spider_net_get_stats;
netdev->set_multicast_list = &spider_net_set_multi;
netdev->set_mac_address = &spider_net_set_mac;
netdev->change_mtu = &spider_net_change_mtu;
@@ -2304,9 +2281,6 @@ spider_net_setup_netdev_ops(struct net_device *netdev)
/* tx watchdog */
netdev->tx_timeout = &spider_net_tx_timeout;
netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT;
- /* NAPI */
- netdev->poll = &spider_net_poll;
- netdev->weight = SPIDER_NET_NAPI_WEIGHT;
/* HW VLAN */
#ifdef CONFIG_NET_POLL_CONTROLLER
/* poll controller */
@@ -2333,7 +2307,6 @@ spider_net_setup_netdev(struct spider_net_card *card)
struct sockaddr addr;
const u8 *mac;
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &card->pdev->dev);
pci_set_drvdata(card->pdev, netdev);
@@ -2351,6 +2324,9 @@ spider_net_setup_netdev(struct spider_net_card *card)
card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
+ netif_napi_add(netdev, &card->napi,
+ spider_net_poll, SPIDER_NET_NAPI_WEIGHT);
+
spider_net_setup_netdev_ops(netdev);
netdev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX;
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index dbbdb8cee3c..e1d05c0f47e 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -466,6 +466,8 @@ struct spider_net_card {
struct pci_dev *pdev;
struct mii_phy phy;
+ struct napi_struct napi;
+
int medium;
void __iomem *regs;
@@ -485,7 +487,6 @@ struct spider_net_card {
/* for ethtool */
int msg_enable;
- struct net_device_stats netdev_stats;
struct spider_net_extra_stats spider_stats;
struct spider_net_options options;
@@ -493,7 +494,4 @@ struct spider_net_card {
struct spider_net_descr darray[0];
};
-#define pr_err(fmt,arg...) \
- printk(KERN_ERR fmt ,##arg)
-
#endif
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
index d940474e024..85691d2a0be 100644
--- a/drivers/net/spider_net_ethtool.c
+++ b/drivers/net/spider_net_ethtool.c
@@ -28,8 +28,6 @@
#include "spider_net.h"
-#define SPIDER_NET_NUM_STATS 13
-
static struct {
const char str[ETH_GSTRING_LEN];
} ethtool_stats_keys[] = {
@@ -147,9 +145,14 @@ spider_net_ethtool_get_ringparam(struct net_device *netdev,
ering->rx_pending = card->rx_chain.num_desc;
}
-static int spider_net_get_stats_count(struct net_device *netdev)
+static int spider_net_get_sset_count(struct net_device *netdev, int sset)
{
- return SPIDER_NET_NUM_STATS;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(ethtool_stats_keys);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void spider_net_get_ethtool_stats(struct net_device *netdev,
@@ -157,13 +160,13 @@ static void spider_net_get_ethtool_stats(struct net_device *netdev,
{
struct spider_net_card *card = netdev->priv;
- data[0] = card->netdev_stats.tx_packets;
- data[1] = card->netdev_stats.tx_bytes;
- data[2] = card->netdev_stats.rx_packets;
- data[3] = card->netdev_stats.rx_bytes;
- data[4] = card->netdev_stats.tx_errors;
- data[5] = card->netdev_stats.tx_dropped;
- data[6] = card->netdev_stats.rx_dropped;
+ data[0] = netdev->stats.tx_packets;
+ data[1] = netdev->stats.tx_bytes;
+ data[2] = netdev->stats.rx_packets;
+ data[3] = netdev->stats.rx_bytes;
+ data[4] = netdev->stats.tx_errors;
+ data[5] = netdev->stats.tx_dropped;
+ data[6] = netdev->stats.rx_dropped;
data[7] = card->spider_stats.rx_desc_error;
data[8] = card->spider_stats.tx_timeouts;
data[9] = card->spider_stats.alloc_rx_skb_error;
@@ -188,11 +191,10 @@ const struct ethtool_ops spider_net_ethtool_ops = {
.nway_reset = spider_net_ethtool_nway_reset,
.get_rx_csum = spider_net_ethtool_get_rx_csum,
.set_rx_csum = spider_net_ethtool_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
.get_ringparam = spider_net_ethtool_get_ringparam,
.get_strings = spider_net_get_strings,
- .get_stats_count = spider_net_get_stats_count,
+ .get_sset_count = spider_net_get_sset_count,
.get_ethtool_stats = spider_net_get_ethtool_stats,
};
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 8b6478663a5..bcc430bd9e4 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -155,7 +155,7 @@ static int full_duplex[MAX_UNITS] = {0, };
#if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR))
/* 64-bit dma_addr_t */
#define ADDR_64BITS /* This chip uses 64 bit addresses. */
-#define netdrv_addr_t u64
+#define netdrv_addr_t __le64
#define cpu_to_dma(x) cpu_to_le64(x)
#define dma_to_cpu(x) le64_to_cpu(x)
#define RX_DESC_Q_ADDR_SIZE RxDescQAddr64bit
@@ -164,7 +164,7 @@ static int full_duplex[MAX_UNITS] = {0, };
#define TX_COMPL_Q_ADDR_SIZE TxComplQAddr64bit
#define RX_DESC_ADDR_SIZE RxDescAddr64bit
#else /* 32-bit dma_addr_t */
-#define netdrv_addr_t u32
+#define netdrv_addr_t __le32
#define cpu_to_dma(x) cpu_to_le32(x)
#define dma_to_cpu(x) le32_to_cpu(x)
#define RX_DESC_Q_ADDR_SIZE RxDescQAddr32bit
@@ -178,16 +178,13 @@ static int full_duplex[MAX_UNITS] = {0, };
#define skb_num_frags(skb) (skb_shinfo(skb)->nr_frags + 1)
#ifdef HAVE_NETDEV_POLL
-#define init_poll(dev) \
-do { \
- dev->poll = &netdev_poll; \
- dev->weight = max_interrupt_work; \
-} while (0)
-#define netdev_rx(dev, ioaddr) \
+#define init_poll(dev, np) \
+ netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work)
+#define netdev_rx(dev, np, ioaddr) \
do { \
u32 intr_enable; \
- if (netif_rx_schedule_prep(dev)) { \
- __netif_rx_schedule(dev); \
+ if (netif_rx_schedule_prep(dev, &np->napi)) { \
+ __netif_rx_schedule(dev, &np->napi); \
intr_enable = readl(ioaddr + IntrEnable); \
intr_enable &= ~(IntrRxDone | IntrRxEmpty); \
writel(intr_enable, ioaddr + IntrEnable); \
@@ -204,12 +201,12 @@ do { \
} while (0)
#define netdev_receive_skb(skb) netif_receive_skb(skb)
#define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_receive_skb(skb, vlgrp, vlid)
-static int netdev_poll(struct net_device *dev, int *budget);
+static int netdev_poll(struct napi_struct *napi, int budget);
#else /* not HAVE_NETDEV_POLL */
-#define init_poll(dev)
+#define init_poll(dev, np)
#define netdev_receive_skb(skb) netif_rx(skb)
#define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_rx(skb, vlgrp, vlid)
-#define netdev_rx(dev, ioaddr) \
+#define netdev_rx(dev, np, ioaddr) \
do { \
int quota = np->dirty_rx + RX_RING_SIZE - np->cur_rx; \
__netdev_rx(dev, &quota);\
@@ -497,7 +494,7 @@ enum intr_ctrl_bits {
/* The Rx and Tx buffer descriptors. */
struct starfire_rx_desc {
- dma_addr_t rxaddr;
+ netdrv_addr_t rxaddr;
};
enum rx_desc_bits {
RxDescValid=1, RxDescEndRing=2,
@@ -505,25 +502,25 @@ enum rx_desc_bits {
/* Completion queue entry. */
struct short_rx_done_desc {
- u32 status; /* Low 16 bits is length. */
+ __le32 status; /* Low 16 bits is length. */
};
struct basic_rx_done_desc {
- u32 status; /* Low 16 bits is length. */
- u16 vlanid;
- u16 status2;
+ __le32 status; /* Low 16 bits is length. */
+ __le16 vlanid;
+ __le16 status2;
};
struct csum_rx_done_desc {
- u32 status; /* Low 16 bits is length. */
- u16 csum; /* Partial checksum */
- u16 status2;
+ __le32 status; /* Low 16 bits is length. */
+ __le16 csum; /* Partial checksum */
+ __le16 status2;
};
struct full_rx_done_desc {
- u32 status; /* Low 16 bits is length. */
- u16 status3;
- u16 status2;
- u16 vlanid;
- u16 csum; /* partial checksum */
- u32 timestamp;
+ __le32 status; /* Low 16 bits is length. */
+ __le16 status3;
+ __le16 status2;
+ __le16 vlanid;
+ __le16 csum; /* partial checksum */
+ __le32 timestamp;
};
/* XXX: this is ugly and I'm not sure it's worth the trouble -Ion */
#ifdef VLAN_SUPPORT
@@ -540,15 +537,15 @@ enum rx_done_bits {
/* Type 1 Tx descriptor. */
struct starfire_tx_desc_1 {
- u32 status; /* Upper bits are status, lower 16 length. */
- u32 addr;
+ __le32 status; /* Upper bits are status, lower 16 length. */
+ __le32 addr;
};
/* Type 2 Tx descriptor. */
struct starfire_tx_desc_2 {
- u32 status; /* Upper bits are status, lower 16 length. */
- u32 reserved;
- u64 addr;
+ __le32 status; /* Upper bits are status, lower 16 length. */
+ __le32 reserved;
+ __le64 addr;
};
#ifdef ADDR_64BITS
@@ -566,9 +563,9 @@ enum tx_desc_bits {
TxRingWrap=0x04000000, TxCalTCP=0x02000000,
};
struct tx_done_desc {
- u32 status; /* timestamp, index. */
+ __le32 status; /* timestamp, index. */
#if 0
- u32 intrstatus; /* interrupt status */
+ __le32 intrstatus; /* interrupt status */
#endif
};
@@ -599,6 +596,8 @@ struct netdev_private {
struct tx_done_desc *tx_done_q;
dma_addr_t tx_done_q_dma;
unsigned int tx_done;
+ struct napi_struct napi;
+ struct net_device *dev;
struct net_device_stats stats;
struct pci_dev *pci_dev;
#ifdef VLAN_SUPPORT
@@ -695,6 +694,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
void __iomem *base;
int drv_flags, io_size;
int boguscnt;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -720,7 +720,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
printk(KERN_ERR DRV_NAME " %d: cannot alloc etherdev, aborting\n", card_idx);
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
irq = pdev->irq;
@@ -791,6 +790,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
dev->irq = irq;
np = netdev_priv(dev);
+ np->dev = dev;
np->base = base;
spin_lock_init(&np->lock);
pci_set_drvdata(pdev, dev);
@@ -851,7 +851,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
dev->hard_start_xmit = &start_tx;
dev->tx_timeout = tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
- init_poll(dev);
+ init_poll(dev, np);
dev->stop = &netdev_close;
dev->get_stats = &get_stats;
dev->set_multicast_list = &set_rx_mode;
@@ -864,11 +864,9 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
if (register_netdev(dev))
goto err_out_cleardev;
- printk(KERN_INFO "%s: %s at %p, ",
- dev->name, netdrv_tbl[chip_idx].name, base);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+ printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+ dev->name, netdrv_tbl[chip_idx].name, base,
+ print_mac(mac, dev->dev_addr), irq);
if (drv_flags & CanHaveMII) {
int phy, phy_idx = 0;
@@ -965,7 +963,7 @@ static int netdev_open(struct net_device *dev)
dev->name, dev->irq);
/* Allocate the various queues. */
- if (np->queue_mem == 0) {
+ if (!np->queue_mem) {
tx_done_q_size = ((sizeof(struct tx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN;
rx_done_q_size = ((sizeof(rx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN;
tx_ring_size = ((sizeof(starfire_tx_desc) * TX_RING_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN;
@@ -1038,11 +1036,11 @@ static int netdev_open(struct net_device *dev)
writew(0, ioaddr + PerfFilterTable + 4);
writew(0, ioaddr + PerfFilterTable + 8);
for (i = 1; i < 16; i++) {
- u16 *eaddrs = (u16 *)dev->dev_addr;
+ __be16 *eaddrs = (__be16 *)dev->dev_addr;
void __iomem *setup_frm = ioaddr + PerfFilterTable + i * 16;
- writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4;
- writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4;
- writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8;
+ writew(be16_to_cpu(eaddrs[2]), setup_frm); setup_frm += 4;
+ writew(be16_to_cpu(eaddrs[1]), setup_frm); setup_frm += 4;
+ writew(be16_to_cpu(eaddrs[0]), setup_frm); setup_frm += 8;
}
/* Initialize other registers. */
@@ -1056,6 +1054,9 @@ static int netdev_open(struct net_device *dev)
writel(np->intr_timer_ctrl, ioaddr + IntrTimerCtrl);
+#ifdef HAVE_NETDEV_POLL
+ napi_enable(&np->napi);
+#endif
netif_start_queue(dev);
if (debug > 1)
@@ -1330,7 +1331,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
handled = 1;
if (intr_status & (IntrRxDone | IntrRxEmpty))
- netdev_rx(dev, ioaddr);
+ netdev_rx(dev, np, ioaddr);
/* Scavenge the skbuff list based on the Tx-done queue.
There are redundant checks here that may be cleaned up
@@ -1470,13 +1471,16 @@ static int __netdev_rx(struct net_device *dev, int *quota)
}
#ifndef final_version /* Remove after testing. */
/* You will want this info for the initial debug. */
- if (debug > 5)
- printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
- "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x.\n",
- skb->data[0], skb->data[1], skb->data[2], skb->data[3],
- skb->data[4], skb->data[5], skb->data[6], skb->data[7],
- skb->data[8], skb->data[9], skb->data[10],
- skb->data[11], skb->data[12], skb->data[13]);
+ if (debug > 5) {
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+
+ printk(KERN_DEBUG " Rx data %s %s"
+ " %2.2x%2.2x.\n",
+ print_mac(mac, &skb->data[0]),
+ print_mac(mac2, &skb->data[6]),
+ skb->data[12], skb->data[13]);
+ }
#endif
skb->protocol = eth_type_trans(skb, dev);
@@ -1531,36 +1535,35 @@ static int __netdev_rx(struct net_device *dev, int *quota)
#ifdef HAVE_NETDEV_POLL
-static int netdev_poll(struct net_device *dev, int *budget)
+static int netdev_poll(struct napi_struct *napi, int budget)
{
+ struct netdev_private *np = container_of(napi, struct netdev_private, napi);
+ struct net_device *dev = np->dev;
u32 intr_status;
- struct netdev_private *np = netdev_priv(dev);
void __iomem *ioaddr = np->base;
- int retcode = 0, quota = dev->quota;
+ int quota = budget;
do {
writel(IntrRxDone | IntrRxEmpty, ioaddr + IntrClear);
- retcode = __netdev_rx(dev, &quota);
- *budget -= (dev->quota - quota);
- dev->quota = quota;
- if (retcode)
+ if (__netdev_rx(dev, &quota))
goto out;
intr_status = readl(ioaddr + IntrStatus);
} while (intr_status & (IntrRxDone | IntrRxEmpty));
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
intr_status = readl(ioaddr + IntrEnable);
intr_status |= IntrRxDone | IntrRxEmpty;
writel(intr_status, ioaddr + IntrEnable);
out:
if (debug > 5)
- printk(KERN_DEBUG " exiting netdev_poll(): %d.\n", retcode);
+ printk(KERN_DEBUG " exiting netdev_poll(): %d.\n",
+ budget - quota);
/* Restart Rx engine if stopped. */
- return retcode;
+ return budget - quota;
}
#endif /* HAVE_NETDEV_POLL */
@@ -1764,26 +1767,26 @@ static void set_rx_mode(struct net_device *dev)
} else if (dev->mc_count <= 14) {
/* Use the 16 element perfect filter, skip first two entries. */
void __iomem *filter_addr = ioaddr + PerfFilterTable + 2 * 16;
- u16 *eaddrs;
+ __be16 *eaddrs;
for (i = 2, mclist = dev->mc_list; mclist && i < dev->mc_count + 2;
i++, mclist = mclist->next) {
- eaddrs = (u16 *)mclist->dmi_addr;
- writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4;
- writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
- writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8;
+ eaddrs = (__be16 *)mclist->dmi_addr;
+ writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 4;
+ writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
+ writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 8;
}
- eaddrs = (u16 *)dev->dev_addr;
+ eaddrs = (__be16 *)dev->dev_addr;
while (i++ < 16) {
- writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4;
- writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
- writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8;
+ writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4;
+ writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
+ writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 8;
}
rx_mode |= AcceptBroadcast|PerfectFilter;
} else {
/* Must use a multicast hash table. */
void __iomem *filter_addr;
- u16 *eaddrs;
- u16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */
+ __be16 *eaddrs;
+ __le16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */
memset(mc_filter, 0, sizeof(mc_filter));
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
@@ -1791,17 +1794,17 @@ static void set_rx_mode(struct net_device *dev)
/* The chip uses the upper 9 CRC bits
as index into the hash table */
int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23;
- __u32 *fptr = (__u32 *) &mc_filter[(bit_nr >> 4) & ~1];
+ __le32 *fptr = (__le32 *) &mc_filter[(bit_nr >> 4) & ~1];
*fptr |= cpu_to_le32(1 << (bit_nr & 31));
}
/* Clear the perfect filter list, skip first two entries. */
filter_addr = ioaddr + PerfFilterTable + 2 * 16;
- eaddrs = (u16 *)dev->dev_addr;
+ eaddrs = (__be16 *)dev->dev_addr;
for (i = 2; i < 16; i++) {
- writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4;
- writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
- writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8;
+ writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4;
+ writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
+ writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 8;
}
for (filter_addr = ioaddr + HashTable, i = 0; i < 32; filter_addr+= 16, i++)
writew(mc_filter[i], filter_addr);
@@ -1904,6 +1907,9 @@ static int netdev_close(struct net_device *dev)
int i;
netif_stop_queue(dev);
+#ifdef HAVE_NETDEV_POLL
+ napi_disable(&np->napi);
+#endif
if (debug > 1) {
printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %#8.8x.\n",
diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c
index e6f90427160..b65be5d70fe 100644
--- a/drivers/net/stnic.c
+++ b/drivers/net/stnic.c
@@ -112,7 +112,6 @@ static int __init stnic_probe(void)
dev = alloc_ei_netdev();
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
#ifdef CONFIG_SH_STANDARD_BIOS
sh_bios_get_node_addr (stnic_eadr);
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index b77ab6e8fd3..9b2a7f7bb25 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -311,7 +311,6 @@ struct net_device * __init sun3_82586_probe(int unit)
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
dev->irq = IE_IRQ;
dev->base_addr = ioaddr;
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index f1548c03332..f8d46134dac 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -152,7 +152,6 @@ struct lance_private {
struct lance_memory *mem;
int new_rx, new_tx; /* The next free ring entry */
int old_tx, old_rx; /* ring entry to be processed */
- struct net_device_stats stats;
/* These two must be longs for set_bit() */
long tx_full;
long lock;
@@ -241,7 +240,6 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
static irqreturn_t lance_interrupt( int irq, void *dev_id);
static int lance_rx( struct net_device *dev );
static int lance_close( struct net_device *dev );
-static struct net_device_stats *lance_get_stats( struct net_device *dev );
static void set_multicast_list( struct net_device *dev );
/************************* End of Prototypes **************************/
@@ -274,7 +272,6 @@ struct net_device * __init sun3lance_probe(int unit)
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
- SET_MODULE_OWNER(dev);
if (!lance_probe(dev))
goto out;
@@ -303,6 +300,7 @@ static int __init lance_probe( struct net_device *dev)
static int did_version;
volatile unsigned short *ioaddr_probe;
unsigned short tmp1, tmp2;
+ DECLARE_MAC_BUF(mac);
#ifdef CONFIG_SUN3
ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE);
@@ -378,8 +376,7 @@ static int __init lance_probe( struct net_device *dev)
MEM->init.hwaddr[4] = dev->dev_addr[5];
MEM->init.hwaddr[5] = dev->dev_addr[4];
- for( i = 0; i < 6; ++i )
- printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" );
+ printk("%s\n", print_mac(mac, dev->dev_addr));
MEM->init.mode = 0x0000;
MEM->init.filter[0] = 0x00000000;
@@ -402,15 +399,12 @@ static int __init lance_probe( struct net_device *dev)
dev->open = &lance_open;
dev->hard_start_xmit = &lance_start_xmit;
dev->stop = &lance_close;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->set_mac_address = NULL;
// KLUDGE -- REMOVE ME
set_bit(__LINK_STATE_PRESENT, &dev->state);
- memset( &lp->stats, 0, sizeof(lp->stats) );
-
return 1;
}
@@ -535,7 +529,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
* little endian mode.
*/
REGA(CSR3) = CSR3_BSWP;
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if(lance_debug >= 2) {
int i;
@@ -596,17 +590,12 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
/* Fill in a Tx ring entry */
#if 0
if (lance_debug >= 2) {
- u_char *p;
- int i;
- printk( "%s: TX pkt %d type 0x%04x from ", dev->name,
- lp->new_tx, ((u_short *)skb->data)[6]);
- for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" to ");
- for( p = (u_char *)skb->data, i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" data at 0x%08x len %d\n", (int)skb->data,
- (int)skb->len );
+ printk( "%s: TX pkt %d type 0x%04x"
+ " from %s to %s"
+ " data at 0x%08x len %d\n",
+ dev->name, lp->new_tx, ((u_short *)skb->data)[6],
+ DEV_ADDR(&skb->data[6]), DEV_ADDR(skb->data),
+ (int)skb->data, (int)skb->len );
}
#endif
/* We're not prepared for the int until the last flags are set/reset.
@@ -635,7 +624,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
lp->new_tx = (lp->new_tx + 1) & TX_RING_MOD_MASK;
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
/* Trigger an immediate send poll. */
REGA(CSR0) = CSR0_INEA | CSR0_TDMD | CSR0_STRT;
@@ -713,12 +702,12 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id)
if (head->flag & TMD1_ERR) {
int status = head->misc;
- lp->stats.tx_errors++;
- if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
- if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
- if (status & TMD3_LCOL) lp->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
+ if (status & TMD3_RTRY) dev->stats.tx_aborted_errors++;
+ if (status & TMD3_LCAR) dev->stats.tx_carrier_errors++;
+ if (status & TMD3_LCOL) dev->stats.tx_window_errors++;
if (status & (TMD3_UFLO | TMD3_BUFF)) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk("%s: Tx FIFO error\n",
dev->name);
REGA(CSR0) = CSR0_STOP;
@@ -731,9 +720,9 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id)
head->flag &= ~(TMD1_ENP | TMD1_STP);
if(head->flag & (TMD1_ONE | TMD1_MORE))
- lp->stats.collisions++;
+ dev->stats.collisions++;
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
DPRINTK(3, ("cleared tx ring %d\n", old_tx));
}
old_tx = (old_tx +1) & TX_RING_MOD_MASK;
@@ -753,8 +742,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id)
lance_rx( dev );
/* Log misc errors. */
- if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
- if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
+ if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */
+ if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */
if (csr0 & CSR0_MERR) {
DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
"status %04x.\n", dev->name, csr0 ));
@@ -800,11 +789,11 @@ static int lance_rx( struct net_device *dev )
full-sized buffers it's possible for a jabber packet to use two
buffers, with only the last correctly noting the error. */
if (status & RMD1_ENP) /* Only count a general error at the */
- lp->stats.rx_errors++; /* end of a packet.*/
- if (status & RMD1_FRAM) lp->stats.rx_frame_errors++;
- if (status & RMD1_OFLO) lp->stats.rx_over_errors++;
- if (status & RMD1_CRC) lp->stats.rx_crc_errors++;
- if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++; /* end of a packet.*/
+ if (status & RMD1_FRAM) dev->stats.rx_frame_errors++;
+ if (status & RMD1_OFLO) dev->stats.rx_over_errors++;
+ if (status & RMD1_CRC) dev->stats.rx_crc_errors++;
+ if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++;
head->flag &= (RMD1_ENP|RMD1_STP);
} else {
/* Malloc up new buffer, compatible with net-3. */
@@ -814,7 +803,7 @@ static int lance_rx( struct net_device *dev )
if (pkt_len < 60) {
printk( "%s: Runt packet!\n", dev->name );
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
else {
skb = dev_alloc_skb( pkt_len+2 );
@@ -822,7 +811,7 @@ static int lance_rx( struct net_device *dev )
DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
dev->name ));
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
head->msg_length = 0;
head->flag |= RMD1_OWN_CHIP;
lp->new_rx = (lp->new_rx+1) &
@@ -831,13 +820,14 @@ static int lance_rx( struct net_device *dev )
#if 0
if (lance_debug >= 3) {
- u_char *data = PKTBUF_ADDR(head), *p;
- printk( "%s: RX pkt %d type 0x%04x from ", dev->name, entry, ((u_short *)data)[6]);
- for( p = &data[6], i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
- printk(" to ");
- for( p = data, i = 0; i < 6; i++ )
- printk("%02x%s", *p++, i != 5 ? ":" : "" );
+ u_char *data = PKTBUF_ADDR(head);
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2)
+ printk("%s: RX pkt %d type 0x%04x"
+ " from %s to %s",
+ dev->name, lp->new_tx, ((u_short *)data)[6],
+ print_mac(mac, &data[6]), print_mac(mac2, data));
+
printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
"len %d at %08x\n",
data[15], data[16], data[17], data[18],
@@ -860,8 +850,8 @@ static int lance_rx( struct net_device *dev )
skb->protocol = eth_type_trans( skb, dev );
netif_rx( skb );
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
}
@@ -898,14 +888,6 @@ static int lance_close( struct net_device *dev )
}
-static struct net_device_stats *lance_get_stats( struct net_device *dev )
-{
- struct lance_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
-
/* Set or clear the multicast filter for this adaptor.
num_addrs == -1 Promiscuous mode, receive all packets
num_addrs == 0 Normal mode, clear multicast list
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index b3e0158def4..fe3ac6f9ae8 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -1082,12 +1082,12 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
struct bigmac *bp;
u8 bsizes, bsizes_more;
int i;
+ DECLARE_MAC_BUF(mac);
/* Get a new device struct for this interface. */
dev = alloc_etherdev(sizeof(struct bigmac));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -1227,11 +1227,8 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp);
- printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- i == 5 ? ' ' : ':');
- printk("\n");
+ printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
return 0;
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index a8f2af8f778..ff98f5d597f 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -466,8 +466,8 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
#else
int bar = 1;
#endif
- int phy, phy_idx = 0;
-
+ int phy, phy_end, phy_idx = 0;
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -485,7 +485,6 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*np));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_request_regions(pdev, DRV_NAME))
@@ -547,19 +546,25 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
if (i)
goto err_out_unmap_rx;
- printk(KERN_INFO "%s: %s at %p, ",
- dev->name, pci_id_tbl[chip_idx].name, ioaddr);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+ printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+ dev->name, pci_id_tbl[chip_idx].name, ioaddr,
+ print_mac(mac, dev->dev_addr), irq);
np->phys[0] = 1; /* Default setting */
np->mii_preamble_required++;
+
/*
* It seems some phys doesn't deal well with address 0 being accessed
- * first, so leave address zero to the end of the loop (32 & 31).
+ * first
*/
- for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) {
+ if (sundance_pci_tbl[np->chip_id].device == 0x0200) {
+ phy = 0;
+ phy_end = 31;
+ } else {
+ phy = 1;
+ phy_end = 32; /* wraps to zero, due to 'phy & 0x1f' */
+ }
+ for (; phy <= phy_end && phy_idx < MII_CNT; phy++) {
int phyx = phy & 0x1f;
int mii_status = mdio_read(dev, phyx, MII_BMSR);
if (mii_status != 0xffff && mii_status != 0x0000) {
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 43280385503..f6fedcc32de 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -19,7 +19,7 @@
*
* gem_change_mtu() and gem_set_multicast() are called with a read_lock()
* help by net/core/dev.c, thus they can't schedule. That means they can't
- * call netif_poll_disable() neither, thus force gem_poll() to keep a spinlock
+ * call napi_disable() neither, thus force gem_poll() to keep a spinlock
* where it could have been dropped. change_mtu especially would love also to
* be able to msleep instead of horrid locked delays when resetting the HW,
* but that read_lock() makes it impossible, unless I defer it's action to
@@ -878,19 +878,20 @@ static int gem_rx(struct gem *gp, int work_to_do)
return work_done;
}
-static int gem_poll(struct net_device *dev, int *budget)
+static int gem_poll(struct napi_struct *napi, int budget)
{
- struct gem *gp = dev->priv;
+ struct gem *gp = container_of(napi, struct gem, napi);
+ struct net_device *dev = gp->dev;
unsigned long flags;
+ int work_done;
/*
* NAPI locking nightmare: See comment at head of driver
*/
spin_lock_irqsave(&gp->lock, flags);
+ work_done = 0;
do {
- int work_to_do, work_done;
-
/* Handle anomalies */
if (gp->status & GREG_STAT_ABNORMAL) {
if (gem_abnormal_irq(dev, gp, gp->status))
@@ -906,29 +907,25 @@ static int gem_poll(struct net_device *dev, int *budget)
/* Run RX thread. We don't use any locking here,
* code willing to do bad things - like cleaning the
- * rx ring - must call netif_poll_disable(), which
+ * rx ring - must call napi_disable(), which
* schedule_timeout()'s if polling is already disabled.
*/
- work_to_do = min(*budget, dev->quota);
-
- work_done = gem_rx(gp, work_to_do);
+ work_done += gem_rx(gp, budget);
- *budget -= work_done;
- dev->quota -= work_done;
-
- if (work_done >= work_to_do)
- return 1;
+ if (work_done >= budget)
+ return work_done;
spin_lock_irqsave(&gp->lock, flags);
gp->status = readl(gp->regs + GREG_STAT);
} while (gp->status & GREG_STAT_NAPI);
- __netif_rx_complete(dev);
+ __netif_rx_complete(dev, napi);
gem_enable_ints(gp);
spin_unlock_irqrestore(&gp->lock, flags);
- return 0;
+
+ return work_done;
}
static irqreturn_t gem_interrupt(int irq, void *dev_id)
@@ -946,17 +943,17 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id)
spin_lock_irqsave(&gp->lock, flags);
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &gp->napi)) {
u32 gem_status = readl(gp->regs + GREG_STAT);
if (gem_status == 0) {
- netif_poll_enable(dev);
+ napi_enable(&gp->napi);
spin_unlock_irqrestore(&gp->lock, flags);
return IRQ_NONE;
}
gp->status = gem_status;
gem_disable_ints(gp);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &gp->napi);
}
spin_unlock_irqrestore(&gp->lock, flags);
@@ -2284,7 +2281,7 @@ static void gem_reset_task(struct work_struct *work)
mutex_lock(&gp->pm_mutex);
- netif_poll_disable(gp->dev);
+ napi_disable(&gp->napi);
spin_lock_irq(&gp->lock);
spin_lock(&gp->tx_lock);
@@ -2307,7 +2304,7 @@ static void gem_reset_task(struct work_struct *work)
spin_unlock(&gp->tx_lock);
spin_unlock_irq(&gp->lock);
- netif_poll_enable(gp->dev);
+ napi_enable(&gp->napi);
mutex_unlock(&gp->pm_mutex);
}
@@ -2324,6 +2321,8 @@ static int gem_open(struct net_device *dev)
if (!gp->asleep)
rc = gem_do_start(dev);
gp->opened = (rc == 0);
+ if (gp->opened)
+ napi_enable(&gp->napi);
mutex_unlock(&gp->pm_mutex);
@@ -2334,12 +2333,10 @@ static int gem_close(struct net_device *dev)
{
struct gem *gp = dev->priv;
- /* Note: we don't need to call netif_poll_disable() here because
- * our caller (dev_close) already did it for us
- */
-
mutex_lock(&gp->pm_mutex);
+ napi_disable(&gp->napi);
+
gp->opened = 0;
if (!gp->asleep)
gem_do_stop(dev, 0);
@@ -2358,8 +2355,6 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state)
mutex_lock(&gp->pm_mutex);
- netif_poll_disable(dev);
-
printk(KERN_INFO "%s: suspending, WakeOnLan %s\n",
dev->name,
(gp->wake_on_lan && gp->opened) ? "enabled" : "disabled");
@@ -2373,6 +2368,8 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state)
/* If the driver is opened, we stop the MAC */
if (gp->opened) {
+ napi_disable(&gp->napi);
+
/* Stop traffic, mark us closed */
netif_device_detach(dev);
@@ -2463,6 +2460,7 @@ static int gem_resume(struct pci_dev *pdev)
/* Re-attach net device */
netif_device_attach(dev);
+ napi_enable(&gp->napi);
}
spin_lock_irqsave(&gp->lock, flags);
@@ -2482,8 +2480,6 @@ static int gem_resume(struct pci_dev *pdev)
spin_unlock(&gp->tx_lock);
spin_unlock_irqrestore(&gp->lock, flags);
- netif_poll_enable(dev);
-
mutex_unlock(&gp->pm_mutex);
return 0;
@@ -2968,7 +2964,8 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
unsigned long gemreg_base, gemreg_len;
struct net_device *dev;
struct gem *gp;
- int i, err, pci_using_dac;
+ int err, pci_using_dac;
+ DECLARE_MAC_BUF(mac);
if (gem_version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -3026,7 +3023,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
err = -ENOMEM;
goto err_disable_device;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
gp = dev->priv;
@@ -3121,8 +3117,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
dev->get_stats = gem_get_stats;
dev->set_multicast_list = gem_set_multicast;
dev->do_ioctl = gem_ioctl;
- dev->poll = gem_poll;
- dev->weight = 64;
+ netif_napi_add(dev, &gp->napi, gem_poll, 64);
dev->ethtool_ops = &gem_ethtool_ops;
dev->tx_timeout = gem_tx_timeout;
dev->watchdog_timeo = 5 * HZ;
@@ -3154,12 +3149,9 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
goto err_out_free_consistent;
}
- printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
- dev->name);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- i == 5 ? ' ' : ':');
- printk("\n");
+ printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet "
+ "%s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1)
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
index 58cf87c5751..76d760acc9e 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -993,6 +993,7 @@ struct gem {
u32 msg_enable;
u32 status;
+ struct napi_struct napi;
struct net_device_stats net_stats;
int tx_fifo_sz;
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 8b35f13318e..9cc13dd8a82 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1281,7 +1281,7 @@ static void happy_meal_init_rings(struct happy_meal *hp)
skb->dev = dev;
/* Because we reserve afterwards. */
- skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET));
+ skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET + 4));
hme_write_rxd(hp, &hb->happy_meal_rxd[i],
(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)),
hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
@@ -1700,6 +1700,11 @@ static int happy_meal_init(struct happy_meal *hp)
HMD(("tx old[%08x] and rx [%08x] ON!\n",
hme_read32(hp, bregs + BMAC_TXCFG),
hme_read32(hp, bregs + BMAC_RXCFG)));
+
+ /* Set larger TX/RX size to allow for 802.1q */
+ hme_write32(hp, bregs + BMAC_TXMAX, ETH_FRAME_LEN + 8);
+ hme_write32(hp, bregs + BMAC_RXMAX, ETH_FRAME_LEN + 8);
+
hme_write32(hp, bregs + BMAC_TXCFG,
hme_read32(hp, bregs + BMAC_TXCFG) | BIGMAC_TXCFG_ENABLE);
hme_write32(hp, bregs + BMAC_RXCFG,
@@ -2039,7 +2044,7 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
hp->rx_skbs[elem] = new_skb;
new_skb->dev = dev;
- skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET));
+ skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET + 4));
hme_write_rxd(hp, this,
(RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
@@ -2664,6 +2669,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
struct net_device *dev;
int i, qfe_slot = -1;
int err = -ENODEV;
+ DECLARE_MAC_BUF(mac);
if (is_qfe) {
qp = quattro_sbus_find(sdev);
@@ -2680,7 +2686,6 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
dev = alloc_etherdev(sizeof(struct happy_meal));
if (!dev)
goto err_out;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
if (hme_version_printed++ == 0)
@@ -2809,8 +2814,8 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
dev->watchdog_timeo = 5*HZ;
dev->ethtool_ops = &hme_ethtool_ops;
- /* Happy Meal can do it all... except VLAN. */
- dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_VLAN_CHALLENGED;
+ /* Happy Meal can do it all... */
+ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
dev->irq = sdev->irqs[0];
@@ -2851,10 +2856,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
dev->name);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c",
- dev->dev_addr[i], i == 5 ? ' ' : ':');
- printk("\n");
+ printk("%s\n", print_mac(mac, dev->dev_addr));
return 0;
@@ -2989,6 +2991,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
int i, qfe_slot = -1;
char prom_name[64];
int err;
+ DECLARE_MAC_BUF(mac);
/* Now make sure pci_dev cookie is there. */
#ifdef CONFIG_SPARC
@@ -3022,7 +3025,6 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
err = -ENOMEM;
if (!dev)
goto err_out;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (hme_version_printed++ == 0)
@@ -3203,10 +3205,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
dev->name);
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':');
-
- printk("\n");
+ printk("%s\n", print_mac(mac, dev->dev_addr));
return 0;
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 68e4f660367..26ade68aeab 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -248,7 +248,6 @@ struct lance_private {
int rx_new, tx_new;
int rx_old, tx_old;
- struct net_device_stats stats;
struct sbus_dma *ledma; /* If set this points to ledma */
char tpe; /* cable-selection is TPE */
char auto_select; /* cable-selection by carrier */
@@ -519,17 +518,17 @@ static void lance_rx_dvma(struct net_device *dev)
/* We got an incomplete frame? */
if ((bits & LE_R1_POK) != LE_R1_POK) {
- lp->stats.rx_over_errors++;
- lp->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
} else if (bits & LE_R1_ERR) {
/* Count only the end frame as a rx error,
* not the beginning
*/
- if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
- if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
- if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
- if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
- if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+ if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++;
+ if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++;
+ if (bits & LE_R1_OFL) dev->stats.rx_over_errors++;
+ if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
+ if (bits & LE_R1_EOP) dev->stats.rx_errors++;
} else {
len = (rd->mblength & 0xfff) - 4;
skb = dev_alloc_skb(len + 2);
@@ -537,14 +536,14 @@ static void lance_rx_dvma(struct net_device *dev)
if (skb == NULL) {
printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
rd->mblength = 0;
rd->rmd1_bits = LE_R1_OWN;
lp->rx_new = RX_NEXT(entry);
return;
}
- lp->stats.rx_bytes += len;
+ dev->stats.rx_bytes += len;
skb_reserve(skb, 2); /* 16 byte align */
skb_put(skb, len); /* make room */
@@ -554,7 +553,7 @@ static void lance_rx_dvma(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
+ dev->stats.rx_packets++;
}
/* Return the packet to the pool */
@@ -586,12 +585,12 @@ static void lance_tx_dvma(struct net_device *dev)
if (bits & LE_T1_ERR) {
u16 status = td->misc;
- lp->stats.tx_errors++;
- if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
- if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
+ if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) dev->stats.tx_window_errors++;
if (status & LE_T3_CLOS) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (lp->auto_select) {
lp->tpe = 1 - lp->tpe;
printk(KERN_NOTICE "%s: Carrier Lost, trying %s\n",
@@ -608,7 +607,7 @@ static void lance_tx_dvma(struct net_device *dev)
* transmitter, restart the adapter.
*/
if (status & (LE_T3_BUF|LE_T3_UFL)) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
dev->name);
@@ -626,13 +625,13 @@ static void lance_tx_dvma(struct net_device *dev)
/* One collision before packet was sent. */
if (bits & LE_T1_EONE)
- lp->stats.collisions++;
+ dev->stats.collisions++;
/* More than one collision, be optimistic. */
if (bits & LE_T1_EMORE)
- lp->stats.collisions += 2;
+ dev->stats.collisions += 2;
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
j = TX_NEXT(j);
@@ -692,17 +691,17 @@ static void lance_rx_pio(struct net_device *dev)
/* We got an incomplete frame? */
if ((bits & LE_R1_POK) != LE_R1_POK) {
- lp->stats.rx_over_errors++;
- lp->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
+ dev->stats.rx_errors++;
} else if (bits & LE_R1_ERR) {
/* Count only the end frame as a rx error,
* not the beginning
*/
- if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
- if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
- if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
- if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
- if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+ if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++;
+ if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++;
+ if (bits & LE_R1_OFL) dev->stats.rx_over_errors++;
+ if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
+ if (bits & LE_R1_EOP) dev->stats.rx_errors++;
} else {
len = (sbus_readw(&rd->mblength) & 0xfff) - 4;
skb = dev_alloc_skb(len + 2);
@@ -710,14 +709,14 @@ static void lance_rx_pio(struct net_device *dev)
if (skb == NULL) {
printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n",
dev->name);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
sbus_writew(0, &rd->mblength);
sbus_writeb(LE_R1_OWN, &rd->rmd1_bits);
lp->rx_new = RX_NEXT(entry);
return;
}
- lp->stats.rx_bytes += len;
+ dev->stats.rx_bytes += len;
skb_reserve (skb, 2); /* 16 byte align */
skb_put(skb, len); /* make room */
@@ -725,7 +724,7 @@ static void lance_rx_pio(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
+ dev->stats.rx_packets++;
}
/* Return the packet to the pool */
@@ -757,12 +756,12 @@ static void lance_tx_pio(struct net_device *dev)
if (bits & LE_T1_ERR) {
u16 status = sbus_readw(&td->misc);
- lp->stats.tx_errors++;
- if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
- if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+ dev->stats.tx_errors++;
+ if (status & LE_T3_RTY) dev->stats.tx_aborted_errors++;
+ if (status & LE_T3_LCOL) dev->stats.tx_window_errors++;
if (status & LE_T3_CLOS) {
- lp->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (lp->auto_select) {
lp->tpe = 1 - lp->tpe;
printk(KERN_NOTICE "%s: Carrier Lost, trying %s\n",
@@ -779,7 +778,7 @@ static void lance_tx_pio(struct net_device *dev)
* transmitter, restart the adapter.
*/
if (status & (LE_T3_BUF|LE_T3_UFL)) {
- lp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
dev->name);
@@ -797,13 +796,13 @@ static void lance_tx_pio(struct net_device *dev)
/* One collision before packet was sent. */
if (bits & LE_T1_EONE)
- lp->stats.collisions++;
+ dev->stats.collisions++;
/* More than one collision, be optimistic. */
if (bits & LE_T1_EMORE)
- lp->stats.collisions += 2;
+ dev->stats.collisions += 2;
- lp->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
j = TX_NEXT(j);
@@ -844,10 +843,10 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id)
lp->tx(dev);
if (csr0 & LE_C0_BABL)
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (csr0 & LE_C0_MISS)
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (csr0 & LE_C0_MERR) {
if (lp->dregs) {
@@ -1127,7 +1126,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irq(&lp->lock);
- lp->stats.tx_bytes += len;
+ dev->stats.tx_bytes += len;
entry = lp->tx_new & TX_RING_MOD_MASK;
if (lp->pio_buffer) {
@@ -1170,13 +1169,6 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static struct net_device_stats *lance_get_stats(struct net_device *dev)
-{
- struct lance_private *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/* taken from the depca driver */
static void lance_load_multicast(struct net_device *dev)
{
@@ -1329,13 +1321,13 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
struct net_device *dev;
struct lance_private *lp;
int i;
+ DECLARE_MAC_BUF(mac);
dev = alloc_etherdev(sizeof(struct lance_private) + 8);
if (!dev)
return -ENOMEM;
lp = netdev_priv(dev);
- memset(lp, 0, sizeof(*lp));
if (sparc_lance_debug && version_printed++ == 0)
printk (KERN_INFO "%s", version);
@@ -1458,14 +1450,12 @@ no_link_test:
lp->dregs = NULL;
lp->dev = dev;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
dev->open = &lance_open;
dev->stop = &lance_close;
dev->hard_start_xmit = &lance_start_xmit;
dev->tx_timeout = &lance_tx_timeout;
dev->watchdog_timeo = 5*HZ;
- dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
dev->ethtool_ops = &sparc_lance_ethtool_ops;
@@ -1489,12 +1479,8 @@ no_link_test:
dev_set_drvdata(&sdev->ofdev.dev, lp);
- printk(KERN_INFO "%s: LANCE ", dev->name);
-
- for (i = 0; i < 6; i++)
- printk("%2.2x%c", dev->dev_addr[i],
- i == 5 ? ' ': ':');
- printk("\n");
+ printk(KERN_INFO "%s: LANCE %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
return 0;
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index 1b65ae8a1c7..ff23c6489ef 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -260,31 +260,31 @@ static int qe_is_bolixed(struct sunqe *qep, u32 qe_status)
if (qe_status & CREG_STAT_EDEFER) {
printk(KERN_ERR "%s: Excessive transmit defers.\n", dev->name);
- qep->net_stats.tx_errors++;
+ dev->stats.tx_errors++;
}
if (qe_status & CREG_STAT_CLOSS) {
printk(KERN_ERR "%s: Carrier lost, link down?\n", dev->name);
- qep->net_stats.tx_errors++;
- qep->net_stats.tx_carrier_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_carrier_errors++;
}
if (qe_status & CREG_STAT_ERETRIES) {
printk(KERN_ERR "%s: Excessive transmit retries (more than 16).\n", dev->name);
- qep->net_stats.tx_errors++;
+ dev->stats.tx_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_LCOLL) {
printk(KERN_ERR "%s: Late transmit collision.\n", dev->name);
- qep->net_stats.tx_errors++;
- qep->net_stats.collisions++;
+ dev->stats.tx_errors++;
+ dev->stats.collisions++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_FUFLOW) {
printk(KERN_ERR "%s: Transmit fifo underflow, driver bug.\n", dev->name);
- qep->net_stats.tx_errors++;
+ dev->stats.tx_errors++;
mace_hwbug_workaround = 1;
}
@@ -297,104 +297,104 @@ static int qe_is_bolixed(struct sunqe *qep, u32 qe_status)
}
if (qe_status & CREG_STAT_CCOFLOW) {
- qep->net_stats.tx_errors += 256;
- qep->net_stats.collisions += 256;
+ dev->stats.tx_errors += 256;
+ dev->stats.collisions += 256;
}
if (qe_status & CREG_STAT_TXDERROR) {
printk(KERN_ERR "%s: Transmit descriptor is bogus, driver bug.\n", dev->name);
- qep->net_stats.tx_errors++;
- qep->net_stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_TXLERR) {
printk(KERN_ERR "%s: Transmit late error.\n", dev->name);
- qep->net_stats.tx_errors++;
+ dev->stats.tx_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_TXPERR) {
printk(KERN_ERR "%s: Transmit DMA parity error.\n", dev->name);
- qep->net_stats.tx_errors++;
- qep->net_stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_TXSERR) {
printk(KERN_ERR "%s: Transmit DMA sbus error ack.\n", dev->name);
- qep->net_stats.tx_errors++;
- qep->net_stats.tx_aborted_errors++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_RCCOFLOW) {
- qep->net_stats.rx_errors += 256;
- qep->net_stats.collisions += 256;
+ dev->stats.rx_errors += 256;
+ dev->stats.collisions += 256;
}
if (qe_status & CREG_STAT_RUOFLOW) {
- qep->net_stats.rx_errors += 256;
- qep->net_stats.rx_over_errors += 256;
+ dev->stats.rx_errors += 256;
+ dev->stats.rx_over_errors += 256;
}
if (qe_status & CREG_STAT_MCOFLOW) {
- qep->net_stats.rx_errors += 256;
- qep->net_stats.rx_missed_errors += 256;
+ dev->stats.rx_errors += 256;
+ dev->stats.rx_missed_errors += 256;
}
if (qe_status & CREG_STAT_RXFOFLOW) {
printk(KERN_ERR "%s: Receive fifo overflow.\n", dev->name);
- qep->net_stats.rx_errors++;
- qep->net_stats.rx_over_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_over_errors++;
}
if (qe_status & CREG_STAT_RLCOLL) {
printk(KERN_ERR "%s: Late receive collision.\n", dev->name);
- qep->net_stats.rx_errors++;
- qep->net_stats.collisions++;
+ dev->stats.rx_errors++;
+ dev->stats.collisions++;
}
if (qe_status & CREG_STAT_FCOFLOW) {
- qep->net_stats.rx_errors += 256;
- qep->net_stats.rx_frame_errors += 256;
+ dev->stats.rx_errors += 256;
+ dev->stats.rx_frame_errors += 256;
}
if (qe_status & CREG_STAT_CECOFLOW) {
- qep->net_stats.rx_errors += 256;
- qep->net_stats.rx_crc_errors += 256;
+ dev->stats.rx_errors += 256;
+ dev->stats.rx_crc_errors += 256;
}
if (qe_status & CREG_STAT_RXDROP) {
printk(KERN_ERR "%s: Receive packet dropped.\n", dev->name);
- qep->net_stats.rx_errors++;
- qep->net_stats.rx_dropped++;
- qep->net_stats.rx_missed_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_dropped++;
+ dev->stats.rx_missed_errors++;
}
if (qe_status & CREG_STAT_RXSMALL) {
printk(KERN_ERR "%s: Receive buffer too small, driver bug.\n", dev->name);
- qep->net_stats.rx_errors++;
- qep->net_stats.rx_length_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
}
if (qe_status & CREG_STAT_RXLERR) {
printk(KERN_ERR "%s: Receive late error.\n", dev->name);
- qep->net_stats.rx_errors++;
+ dev->stats.rx_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_RXPERR) {
printk(KERN_ERR "%s: Receive DMA parity error.\n", dev->name);
- qep->net_stats.rx_errors++;
- qep->net_stats.rx_missed_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_missed_errors++;
mace_hwbug_workaround = 1;
}
if (qe_status & CREG_STAT_RXSERR) {
printk(KERN_ERR "%s: Receive DMA sbus error ack.\n", dev->name);
- qep->net_stats.rx_errors++;
- qep->net_stats.rx_missed_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_missed_errors++;
mace_hwbug_workaround = 1;
}
@@ -409,6 +409,7 @@ static int qe_is_bolixed(struct sunqe *qep, u32 qe_status)
static void qe_rx(struct sunqe *qep)
{
struct qe_rxd *rxbase = &qep->qe_block->qe_rxd[0];
+ struct net_device *dev = qep->dev;
struct qe_rxd *this;
struct sunqe_buffers *qbufs = qep->buffers;
__u32 qbufs_dvma = qep->buffers_dvma;
@@ -428,14 +429,14 @@ static void qe_rx(struct sunqe *qep)
/* Check for errors. */
if (len < ETH_ZLEN) {
- qep->net_stats.rx_errors++;
- qep->net_stats.rx_length_errors++;
- qep->net_stats.rx_dropped++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
+ dev->stats.rx_dropped++;
} else {
skb = dev_alloc_skb(len + 2);
if (skb == NULL) {
drops++;
- qep->net_stats.rx_dropped++;
+ dev->stats.rx_dropped++;
} else {
skb_reserve(skb, 2);
skb_put(skb, len);
@@ -444,8 +445,8 @@ static void qe_rx(struct sunqe *qep)
skb->protocol = eth_type_trans(skb, qep->dev);
netif_rx(skb);
qep->dev->last_rx = jiffies;
- qep->net_stats.rx_packets++;
- qep->net_stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
}
}
end_rxd->rx_addr = this_qbuf_dvma;
@@ -603,8 +604,8 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
sbus_writel(CREG_CTRL_TWAKEUP, qep->qcregs + CREG_CTRL);
- qep->net_stats.tx_packets++;
- qep->net_stats.tx_bytes += len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += len;
if (TX_BUFFS_AVAIL(qep) <= 0) {
/* Halt the net queue and enable tx interrupts.
@@ -622,13 +623,6 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-static struct net_device_stats *qe_get_stats(struct net_device *dev)
-{
- struct sunqe *qep = (struct sunqe *) dev->priv;
-
- return &qep->net_stats;
-}
-
static void qe_set_multicast(struct net_device *dev)
{
struct sunqe *qep = (struct sunqe *) dev->priv;
@@ -898,13 +892,11 @@ static int __init qec_ether_init(struct sbus_dev *sdev)
/* Stop this QE. */
qe_stop(qe);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
dev->open = qe_open;
dev->stop = qe_close;
dev->hard_start_xmit = qe_start_xmit;
- dev->get_stats = qe_get_stats;
dev->set_multicast_list = qe_set_multicast;
dev->tx_timeout = qe_tx_timeout;
dev->watchdog_timeo = 5*HZ;
diff --git a/drivers/net/sunqe.h b/drivers/net/sunqe.h
index af34f36111e..347c8ddc159 100644
--- a/drivers/net/sunqe.h
+++ b/drivers/net/sunqe.h
@@ -342,7 +342,6 @@ struct sunqe {
__u32 buffers_dvma; /* DVMA visible address. */
struct sunqec *parent;
u8 mconfig; /* Base MACE mconfig value */
- struct net_device_stats net_stats; /* Statistical counters */
struct sbus_dev *qe_sdev; /* QE's SBUS device struct */
struct net_device *dev; /* QE's netdevice struct */
int channel; /* Who am I? */
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index ec41469eee8..d887c05588d 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -414,6 +414,9 @@ enum tc35815_timer_state {
struct tc35815_local {
struct pci_dev *pci_dev;
+ struct net_device *dev;
+ struct napi_struct napi;
+
/* statistics */
struct net_device_stats stats;
struct {
@@ -566,7 +569,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t tc35815_interrupt(int irq, void *dev_id);
#ifdef TC35815_NAPI
static int tc35815_rx(struct net_device *dev, int limit);
-static int tc35815_poll(struct net_device *dev, int *budget);
+static int tc35815_poll(struct napi_struct *napi, int budget);
#else
static void tc35815_rx(struct net_device *dev);
#endif
@@ -682,9 +685,9 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev,
dev_err(&pdev->dev, "unable to alloc new ethernet\n");
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
lp = dev->priv;
+ lp->dev = dev;
/* enable device (incl. PCI PM wakeup), and bus-mastering */
rc = pci_enable_device (pdev);
@@ -738,8 +741,7 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev,
dev->tx_timeout = tc35815_tx_timeout;
dev->watchdog_timeo = TC35815_TX_TIMEOUT;
#ifdef TC35815_NAPI
- dev->poll = tc35815_poll;
- dev->weight = NAPI_WEIGHT;
+ netif_napi_add(dev, &lp->napi, tc35815_poll, NAPI_WEIGHT);
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = tc35815_poll_controller;
@@ -748,8 +750,6 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev,
dev->irq = pdev->irq;
dev->base_addr = (unsigned long) ioaddr;
- /* dev->priv/lp zeroed and aligned in alloc_etherdev */
- lp = dev->priv;
spin_lock_init(&lp->lock);
lp->pci_dev = pdev;
lp->boardtype = ent->driver_data;
@@ -1237,6 +1237,10 @@ tc35815_open(struct net_device *dev)
return -EAGAIN;
}
+#ifdef TC35815_NAPI
+ napi_enable(&lp->napi);
+#endif
+
/* Reset the hardware here. Don't forget to set the station address. */
spin_lock_irq(&lp->lock);
tc35815_chip_init(dev);
@@ -1436,6 +1440,7 @@ static int tc35815_do_interrupt(struct net_device *dev, u32 status)
static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
+ struct tc35815_local *lp = netdev_priv(dev);
struct tc35815_regs __iomem *tr =
(struct tc35815_regs __iomem *)dev->base_addr;
#ifdef TC35815_NAPI
@@ -1444,8 +1449,8 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
if (!(dmactl & DMA_IntMask)) {
/* disable interrupts */
tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
- if (netif_rx_schedule_prep(dev))
- __netif_rx_schedule(dev);
+ if (netif_rx_schedule_prep(dev, &lp->napi))
+ __netif_rx_schedule(dev, &lp->napi);
else {
printk(KERN_ERR "%s: interrupt taken in poll\n",
dev->name);
@@ -1456,7 +1461,6 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
}
return IRQ_NONE;
#else
- struct tc35815_local *lp = dev->priv;
int handled;
u32 status;
@@ -1650,7 +1654,7 @@ tc35815_rx(struct net_device *dev)
panic_queues(dev);
}
#endif
- /* pass BD to controler */
+ /* pass BD to controller */
#ifndef TC35815_USE_PACKEDBUFFER
if (!lp->rx_skbs[curid].skb) {
lp->rx_skbs[curid].skb =
@@ -1690,7 +1694,7 @@ tc35815_rx(struct net_device *dev)
}
#endif
for (i = 0; i < (bd_count + 1) / 2 + 1; i++) {
- /* pass FD to controler */
+ /* pass FD to controller */
#ifdef DEBUG
lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);
#else
@@ -1726,13 +1730,12 @@ tc35815_rx(struct net_device *dev)
}
#ifdef TC35815_NAPI
-static int
-tc35815_poll(struct net_device *dev, int *budget)
+static int tc35815_poll(struct napi_struct *napi, int budget)
{
- struct tc35815_local *lp = dev->priv;
+ struct tc35815_local *lp = container_of(napi, struct tc35815_local, napi);
+ struct net_device *dev = lp->dev;
struct tc35815_regs __iomem *tr =
(struct tc35815_regs __iomem *)dev->base_addr;
- int limit = min(*budget, dev->quota);
int received = 0, handled;
u32 status;
@@ -1744,23 +1747,19 @@ tc35815_poll(struct net_device *dev, int *budget)
handled = tc35815_do_interrupt(dev, status, limit);
if (handled >= 0) {
received += handled;
- limit -= handled;
- if (limit <= 0)
+ if (received >= budget)
break;
}
status = tc_readl(&tr->Int_Src);
} while (status);
spin_unlock(&lp->lock);
- dev->quota -= received;
- *budget -= received;
- if (limit <= 0)
- return 1;
-
- netif_rx_complete(dev);
- /* enable interrupts */
- tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
- return 0;
+ if (received < budget) {
+ netif_rx_complete(dev, napi);
+ /* enable interrupts */
+ tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
+ }
+ return received;
}
#endif
@@ -1949,7 +1948,11 @@ static int
tc35815_close(struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
+
netif_stop_queue(dev);
+#ifdef TC35815_NAPI
+ napi_disable(&lp->napi);
+#endif
/* Flush the Tx and disable Rx here. */
@@ -2158,10 +2161,16 @@ static void tc35815_set_msglevel(struct net_device *dev, u32 datum)
lp->msg_enable = datum;
}
-static int tc35815_get_stats_count(struct net_device *dev)
+static int tc35815_get_sset_count(struct net_device *dev, int sset)
{
struct tc35815_local *lp = dev->priv;
- return sizeof(lp->lstats) / sizeof(int);
+
+ switch (sset) {
+ case ETH_SS_STATS:
+ return sizeof(lp->lstats) / sizeof(int);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
@@ -2196,7 +2205,7 @@ static const struct ethtool_ops tc35815_ethtool_ops = {
.get_msglevel = tc35815_get_msglevel,
.set_msglevel = tc35815_set_msglevel,
.get_strings = tc35815_get_strings,
- .get_stats_count = tc35815_get_stats_count,
+ .get_sset_count = tc35815_get_sset_count,
.get_ethtool_stats = tc35815_get_ethtool_stats,
};
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
new file mode 100644
index 00000000000..21230c97b2a
--- /dev/null
+++ b/drivers/net/tehuti.c
@@ -0,0 +1,2507 @@
+/*
+ * Tehuti Networks(R) Network Driver
+ * ethtool interface implementation
+ * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * RX HW/SW interaction overview
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * There are 2 types of RX communication channels betwean driver and NIC.
+ * 1) RX Free Fifo - RXF - holds descriptors of empty buffers to accept incoming
+ * traffic. This Fifo is filled by SW and is readen by HW. Each descriptor holds
+ * info about buffer's location, size and ID. An ID field is used to identify a
+ * buffer when it's returned with data via RXD Fifo (see below)
+ * 2) RX Data Fifo - RXD - holds descriptors of full buffers. This Fifo is
+ * filled by HW and is readen by SW. Each descriptor holds status and ID.
+ * HW pops descriptor from RXF Fifo, stores ID, fills buffer with incoming data,
+ * via dma moves it into host memory, builds new RXD descriptor with same ID,
+ * pushes it into RXD Fifo and raises interrupt to indicate new RX data.
+ *
+ * Current NIC configuration (registers + firmware) makes NIC use 2 RXF Fifos.
+ * One holds 1.5K packets and another - 26K packets. Depending on incoming
+ * packet size, HW desides on a RXF Fifo to pop buffer from. When packet is
+ * filled with data, HW builds new RXD descriptor for it and push it into single
+ * RXD Fifo.
+ *
+ * RX SW Data Structures
+ * ~~~~~~~~~~~~~~~~~~~~~
+ * skb db - used to keep track of all skbs owned by SW and their dma addresses.
+ * For RX case, ownership lasts from allocating new empty skb for RXF until
+ * accepting full skb from RXD and passing it to OS. Each RXF Fifo has its own
+ * skb db. Implemented as array with bitmask.
+ * fifo - keeps info about fifo's size and location, relevant HW registers,
+ * usage and skb db. Each RXD and RXF Fifo has its own fifo structure.
+ * Implemented as simple struct.
+ *
+ * RX SW Execution Flow
+ * ~~~~~~~~~~~~~~~~~~~~
+ * Upon initialization (ifconfig up) driver creates RX fifos and initializes
+ * relevant registers. At the end of init phase, driver enables interrupts.
+ * NIC sees that there is no RXF buffers and raises
+ * RD_INTR interrupt, isr fills skbs and Rx begins.
+ * Driver has two receive operation modes:
+ * NAPI - interrupt-driven mixed with polling
+ * interrupt-driven only
+ *
+ * Interrupt-driven only flow is following. When buffer is ready, HW raises
+ * interrupt and isr is called. isr collects all available packets
+ * (bdx_rx_receive), refills skbs (bdx_rx_alloc_skbs) and exit.
+
+ * Rx buffer allocation note
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Driver cares to feed such amount of RxF descriptors that respective amount of
+ * RxD descriptors can not fill entire RxD fifo. The main reason is lack of
+ * overflow check in Bordeaux for RxD fifo free/used size.
+ * FIXME: this is NOT fully implemented, more work should be done
+ *
+ */
+
+#include "tehuti.h"
+#include "tehuti_fw.h"
+
+static struct pci_device_id __devinitdata bdx_pci_tbl[] = {
+ {0x1FC9, 0x3009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x1FC9, 0x3010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x1FC9, 0x3014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0}
+};
+
+MODULE_DEVICE_TABLE(pci, bdx_pci_tbl);
+
+/* Definitions needed by ISR or NAPI functions */
+static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f);
+static void bdx_tx_cleanup(struct bdx_priv *priv);
+static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget);
+
+/* Definitions needed by FW loading */
+static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size);
+
+/* Definitions needed by hw_start */
+static int bdx_tx_init(struct bdx_priv *priv);
+static int bdx_rx_init(struct bdx_priv *priv);
+
+/* Definitions needed by bdx_close */
+static void bdx_rx_free(struct bdx_priv *priv);
+static void bdx_tx_free(struct bdx_priv *priv);
+
+/* Definitions needed by bdx_probe */
+static void bdx_ethtool_ops(struct net_device *netdev);
+
+/*************************************************************************
+ * Print Info *
+ *************************************************************************/
+
+static void print_hw_id(struct pci_dev *pdev)
+{
+ struct pci_nic *nic = pci_get_drvdata(pdev);
+ u16 pci_link_status = 0;
+ u16 pci_ctrl = 0;
+
+ pci_read_config_word(pdev, PCI_LINK_STATUS_REG, &pci_link_status);
+ pci_read_config_word(pdev, PCI_DEV_CTRL_REG, &pci_ctrl);
+
+ printk(KERN_INFO "tehuti: %s%s\n", BDX_NIC_NAME,
+ nic->port_num == 1 ? "" : ", 2-Port");
+ printk(KERN_INFO
+ "tehuti: srom 0x%x fpga %d build %u lane# %d"
+ " max_pl 0x%x mrrs 0x%x\n",
+ readl(nic->regs + SROM_VER), readl(nic->regs + FPGA_VER) & 0xFFF,
+ readl(nic->regs + FPGA_SEED),
+ GET_LINK_STATUS_LANES(pci_link_status),
+ GET_DEV_CTRL_MAXPL(pci_ctrl), GET_DEV_CTRL_MRRS(pci_ctrl));
+}
+
+static void print_fw_id(struct pci_nic *nic)
+{
+ printk(KERN_INFO "tehuti: fw 0x%x\n", readl(nic->regs + FW_VER));
+}
+
+static void print_eth_id(struct net_device *ndev)
+{
+ printk(KERN_INFO "%s: %s, Port %c\n", ndev->name, BDX_NIC_NAME,
+ (ndev->if_port == 0) ? 'A' : 'B');
+
+}
+
+/*************************************************************************
+ * Code *
+ *************************************************************************/
+
+#define bdx_enable_interrupts(priv) \
+ do { WRITE_REG(priv, regIMR, IR_RUN); } while (0)
+#define bdx_disable_interrupts(priv) \
+ do { WRITE_REG(priv, regIMR, 0); } while (0)
+
+/* bdx_fifo_init
+ * create TX/RX descriptor fifo for host-NIC communication.
+ * 1K extra space is allocated at the end of the fifo to simplify
+ * processing of descriptors that wraps around fifo's end
+ * @priv - NIC private structure
+ * @f - fifo to initialize
+ * @fsz_type - fifo size type: 0-4KB, 1-8KB, 2-16KB, 3-32KB
+ * @reg_XXX - offsets of registers relative to base address
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ */
+static int
+bdx_fifo_init(struct bdx_priv *priv, struct fifo *f, int fsz_type,
+ u16 reg_CFG0, u16 reg_CFG1, u16 reg_RPTR, u16 reg_WPTR)
+{
+ u16 memsz = FIFO_SIZE * (1 << fsz_type);
+
+ memset(f, 0, sizeof(struct fifo));
+ /* pci_alloc_consistent gives us 4k-aligned memory */
+ f->va = pci_alloc_consistent(priv->pdev,
+ memsz + FIFO_EXTRA_SPACE, &f->da);
+ if (!f->va) {
+ ERR("pci_alloc_consistent failed\n");
+ RET(-ENOMEM);
+ }
+ f->reg_CFG0 = reg_CFG0;
+ f->reg_CFG1 = reg_CFG1;
+ f->reg_RPTR = reg_RPTR;
+ f->reg_WPTR = reg_WPTR;
+ f->rptr = 0;
+ f->wptr = 0;
+ f->memsz = memsz;
+ f->size_mask = memsz - 1;
+ WRITE_REG(priv, reg_CFG0, (u32) ((f->da & TX_RX_CFG0_BASE) | fsz_type));
+ WRITE_REG(priv, reg_CFG1, H32_64(f->da));
+
+ RET(0);
+}
+
+/* bdx_fifo_free - free all resources used by fifo
+ * @priv - NIC private structure
+ * @f - fifo to release
+ */
+static void bdx_fifo_free(struct bdx_priv *priv, struct fifo *f)
+{
+ ENTER;
+ if (f->va) {
+ pci_free_consistent(priv->pdev,
+ f->memsz + FIFO_EXTRA_SPACE, f->va, f->da);
+ f->va = NULL;
+ }
+ RET();
+}
+
+/*
+ * bdx_link_changed - notifies OS about hw link state.
+ * @bdx_priv - hw adapter structure
+ */
+static void bdx_link_changed(struct bdx_priv *priv)
+{
+ u32 link = READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT;
+
+ if (!link) {
+ if (netif_carrier_ok(priv->ndev)) {
+ netif_stop_queue(priv->ndev);
+ netif_carrier_off(priv->ndev);
+ ERR("%s: Link Down\n", priv->ndev->name);
+ }
+ } else {
+ if (!netif_carrier_ok(priv->ndev)) {
+ netif_wake_queue(priv->ndev);
+ netif_carrier_on(priv->ndev);
+ ERR("%s: Link Up\n", priv->ndev->name);
+ }
+ }
+}
+
+static void bdx_isr_extra(struct bdx_priv *priv, u32 isr)
+{
+ if (isr & IR_RX_FREE_0) {
+ bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0);
+ DBG("RX_FREE_0\n");
+ }
+
+ if (isr & IR_LNKCHG0)
+ bdx_link_changed(priv);
+
+ if (isr & IR_PCIE_LINK)
+ ERR("%s: PCI-E Link Fault\n", priv->ndev->name);
+
+ if (isr & IR_PCIE_TOUT)
+ ERR("%s: PCI-E Time Out\n", priv->ndev->name);
+
+}
+
+/* bdx_isr - Interrupt Service Routine for Bordeaux NIC
+ * @irq - interrupt number
+ * @ndev - network device
+ * @regs - CPU registers
+ *
+ * Return IRQ_NONE if it was not our interrupt, IRQ_HANDLED - otherwise
+ *
+ * It reads ISR register to know interrupt reasons, and proceed them one by one.
+ * Reasons of interest are:
+ * RX_DESC - new packet has arrived and RXD fifo holds its descriptor
+ * RX_FREE - number of free Rx buffers in RXF fifo gets low
+ * TX_FREE - packet was transmited and RXF fifo holds its descriptor
+ */
+
+static irqreturn_t bdx_isr_napi(int irq, void *dev)
+{
+ struct net_device *ndev = dev;
+ struct bdx_priv *priv = ndev->priv;
+ u32 isr;
+
+ ENTER;
+ isr = (READ_REG(priv, regISR) & IR_RUN);
+ if (unlikely(!isr)) {
+ bdx_enable_interrupts(priv);
+ return IRQ_NONE; /* Not our interrupt */
+ }
+
+ if (isr & IR_EXTRA)
+ bdx_isr_extra(priv, isr);
+
+ if (isr & (IR_RX_DESC_0 | IR_TX_FREE_0)) {
+ if (likely(netif_rx_schedule_prep(ndev, &priv->napi))) {
+ __netif_rx_schedule(ndev, &priv->napi);
+ RET(IRQ_HANDLED);
+ } else {
+ /* NOTE: we get here if intr has slipped into window
+ * between these lines in bdx_poll:
+ * bdx_enable_interrupts(priv);
+ * return 0;
+ * currently intrs are disabled (since we read ISR),
+ * and we have failed to register next poll.
+ * so we read the regs to trigger chip
+ * and allow further interupts. */
+ READ_REG(priv, regTXF_WPTR_0);
+ READ_REG(priv, regRXD_WPTR_0);
+ }
+ }
+
+ bdx_enable_interrupts(priv);
+ RET(IRQ_HANDLED);
+}
+
+static int bdx_poll(struct napi_struct *napi, int budget)
+{
+ struct bdx_priv *priv = container_of(napi, struct bdx_priv, napi);
+ struct net_device *dev = priv->ndev;
+ int work_done;
+
+ ENTER;
+ bdx_tx_cleanup(priv);
+ work_done = bdx_rx_receive(priv, &priv->rxd_fifo0, budget);
+ if ((work_done < budget) ||
+ (priv->napi_stop++ >= 30)) {
+ DBG("rx poll is done. backing to isr-driven\n");
+
+ /* from time to time we exit to let NAPI layer release
+ * device lock and allow waiting tasks (eg rmmod) to advance) */
+ priv->napi_stop = 0;
+
+ netif_rx_complete(dev, napi);
+ bdx_enable_interrupts(priv);
+ }
+ return work_done;
+}
+
+/* bdx_fw_load - loads firmware to NIC
+ * @priv - NIC private structure
+ * Firmware is loaded via TXD fifo, so it must be initialized first.
+ * Firware must be loaded once per NIC not per PCI device provided by NIC (NIC
+ * can have few of them). So all drivers use semaphore register to choose one
+ * that will actually load FW to NIC.
+ */
+
+static int bdx_fw_load(struct bdx_priv *priv)
+{
+ int master, i;
+
+ ENTER;
+ master = READ_REG(priv, regINIT_SEMAPHORE);
+ if (!READ_REG(priv, regINIT_STATUS) && master) {
+ bdx_tx_push_desc_safe(priv, s_firmLoad, sizeof(s_firmLoad));
+ mdelay(100);
+ }
+ for (i = 0; i < 200; i++) {
+ if (READ_REG(priv, regINIT_STATUS))
+ break;
+ mdelay(2);
+ }
+ if (master)
+ WRITE_REG(priv, regINIT_SEMAPHORE, 1);
+
+ if (i == 200) {
+ ERR("%s: firmware loading failed\n", priv->ndev->name);
+ DBG("VPC = 0x%x VIC = 0x%x INIT_STATUS = 0x%x i=%d\n",
+ READ_REG(priv, regVPC),
+ READ_REG(priv, regVIC), READ_REG(priv, regINIT_STATUS), i);
+ RET(-EIO);
+ } else {
+ DBG("%s: firmware loading success\n", priv->ndev->name);
+ RET(0);
+ }
+}
+
+static void bdx_restore_mac(struct net_device *ndev, struct bdx_priv *priv)
+{
+ u32 val;
+
+ ENTER;
+ DBG("mac0=%x mac1=%x mac2=%x\n",
+ READ_REG(priv, regUNC_MAC0_A),
+ READ_REG(priv, regUNC_MAC1_A), READ_REG(priv, regUNC_MAC2_A));
+
+ val = (ndev->dev_addr[0] << 8) | (ndev->dev_addr[1]);
+ WRITE_REG(priv, regUNC_MAC2_A, val);
+ val = (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]);
+ WRITE_REG(priv, regUNC_MAC1_A, val);
+ val = (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]);
+ WRITE_REG(priv, regUNC_MAC0_A, val);
+
+ DBG("mac0=%x mac1=%x mac2=%x\n",
+ READ_REG(priv, regUNC_MAC0_A),
+ READ_REG(priv, regUNC_MAC1_A), READ_REG(priv, regUNC_MAC2_A));
+ RET();
+}
+
+/* bdx_hw_start - inits registers and starts HW's Rx and Tx engines
+ * @priv - NIC private structure
+ */
+static int bdx_hw_start(struct bdx_priv *priv)
+{
+ int rc = -EIO;
+ struct net_device *ndev = priv->ndev;
+
+ ENTER;
+ bdx_link_changed(priv);
+
+ /* 10G overall max length (vlan, eth&ip header, ip payload, crc) */
+ WRITE_REG(priv, regFRM_LENGTH, 0X3FE0);
+ WRITE_REG(priv, regPAUSE_QUANT, 0x96);
+ WRITE_REG(priv, regRX_FIFO_SECTION, 0x800010);
+ WRITE_REG(priv, regTX_FIFO_SECTION, 0xE00010);
+ WRITE_REG(priv, regRX_FULLNESS, 0);
+ WRITE_REG(priv, regTX_FULLNESS, 0);
+ WRITE_REG(priv, regCTRLST,
+ regCTRLST_BASE | regCTRLST_RX_ENA | regCTRLST_TX_ENA);
+
+ WRITE_REG(priv, regVGLB, 0);
+ WRITE_REG(priv, regMAX_FRAME_A,
+ priv->rxf_fifo0.m.pktsz & MAX_FRAME_AB_VAL);
+
+ DBG("RDINTCM=%08x\n", priv->rdintcm); /*NOTE: test script uses this */
+ WRITE_REG(priv, regRDINTCM0, priv->rdintcm);
+ WRITE_REG(priv, regRDINTCM2, 0); /*cpu_to_le32(rcm.val)); */
+
+ DBG("TDINTCM=%08x\n", priv->tdintcm); /*NOTE: test script uses this */
+ WRITE_REG(priv, regTDINTCM0, priv->tdintcm); /* old val = 0x300064 */
+
+ /* Enable timer interrupt once in 2 secs. */
+ /*WRITE_REG(priv, regGTMR0, ((GTMR_SEC * 2) & GTMR_DATA)); */
+ bdx_restore_mac(priv->ndev, priv);
+
+ WRITE_REG(priv, regGMAC_RXF_A, GMAC_RX_FILTER_OSEN |
+ GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB);
+
+#define BDX_IRQ_TYPE ((priv->nic->irq_type == IRQ_MSI)?0:IRQF_SHARED)
+ if ((rc = request_irq(priv->pdev->irq, &bdx_isr_napi, BDX_IRQ_TYPE,
+ ndev->name, ndev)))
+ goto err_irq;
+ bdx_enable_interrupts(priv);
+
+ RET(0);
+
+err_irq:
+ RET(rc);
+}
+
+static void bdx_hw_stop(struct bdx_priv *priv)
+{
+ ENTER;
+ bdx_disable_interrupts(priv);
+ free_irq(priv->pdev->irq, priv->ndev);
+
+ netif_carrier_off(priv->ndev);
+ netif_stop_queue(priv->ndev);
+
+ RET();
+}
+
+static int bdx_hw_reset_direct(void __iomem *regs)
+{
+ u32 val, i;
+ ENTER;
+
+ /* reset sequences: read, write 1, read, write 0 */
+ val = readl(regs + regCLKPLL);
+ writel((val | CLKPLL_SFTRST) + 0x8, regs + regCLKPLL);
+ udelay(50);
+ val = readl(regs + regCLKPLL);
+ writel(val & ~CLKPLL_SFTRST, regs + regCLKPLL);
+
+ /* check that the PLLs are locked and reset ended */
+ for (i = 0; i < 70; i++, mdelay(10))
+ if ((readl(regs + regCLKPLL) & CLKPLL_LKD) == CLKPLL_LKD) {
+ /* do any PCI-E read transaction */
+ readl(regs + regRXD_CFG0_0);
+ return 0;
+ }
+ ERR("tehuti: HW reset failed\n");
+ return 1; /* failure */
+}
+
+static int bdx_hw_reset(struct bdx_priv *priv)
+{
+ u32 val, i;
+ ENTER;
+
+ if (priv->port == 0) {
+ /* reset sequences: read, write 1, read, write 0 */
+ val = READ_REG(priv, regCLKPLL);
+ WRITE_REG(priv, regCLKPLL, (val | CLKPLL_SFTRST) + 0x8);
+ udelay(50);
+ val = READ_REG(priv, regCLKPLL);
+ WRITE_REG(priv, regCLKPLL, val & ~CLKPLL_SFTRST);
+ }
+ /* check that the PLLs are locked and reset ended */
+ for (i = 0; i < 70; i++, mdelay(10))
+ if ((READ_REG(priv, regCLKPLL) & CLKPLL_LKD) == CLKPLL_LKD) {
+ /* do any PCI-E read transaction */
+ READ_REG(priv, regRXD_CFG0_0);
+ return 0;
+ }
+ ERR("tehuti: HW reset failed\n");
+ return 1; /* failure */
+}
+
+static int bdx_sw_reset(struct bdx_priv *priv)
+{
+ int i;
+
+ ENTER;
+ /* 1. load MAC (obsolete) */
+ /* 2. disable Rx (and Tx) */
+ WRITE_REG(priv, regGMAC_RXF_A, 0);
+ mdelay(100);
+ /* 3. disable port */
+ WRITE_REG(priv, regDIS_PORT, 1);
+ /* 4. disable queue */
+ WRITE_REG(priv, regDIS_QU, 1);
+ /* 5. wait until hw is disabled */
+ for (i = 0; i < 50; i++) {
+ if (READ_REG(priv, regRST_PORT) & 1)
+ break;
+ mdelay(10);
+ }
+ if (i == 50)
+ ERR("%s: SW reset timeout. continuing anyway\n",
+ priv->ndev->name);
+
+ /* 6. disable intrs */
+ WRITE_REG(priv, regRDINTCM0, 0);
+ WRITE_REG(priv, regTDINTCM0, 0);
+ WRITE_REG(priv, regIMR, 0);
+ READ_REG(priv, regISR);
+
+ /* 7. reset queue */
+ WRITE_REG(priv, regRST_QU, 1);
+ /* 8. reset port */
+ WRITE_REG(priv, regRST_PORT, 1);
+ /* 9. zero all read and write pointers */
+ for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10)
+ DBG("%x = %x\n", i, READ_REG(priv, i) & TXF_WPTR_WR_PTR);
+ for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10)
+ WRITE_REG(priv, i, 0);
+ /* 10. unseet port disable */
+ WRITE_REG(priv, regDIS_PORT, 0);
+ /* 11. unset queue disable */
+ WRITE_REG(priv, regDIS_QU, 0);
+ /* 12. unset queue reset */
+ WRITE_REG(priv, regRST_QU, 0);
+ /* 13. unset port reset */
+ WRITE_REG(priv, regRST_PORT, 0);
+ /* 14. enable Rx */
+ /* skiped. will be done later */
+ /* 15. save MAC (obsolete) */
+ for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10)
+ DBG("%x = %x\n", i, READ_REG(priv, i) & TXF_WPTR_WR_PTR);
+
+ RET(0);
+}
+
+/* bdx_reset - performs right type of reset depending on hw type */
+static int bdx_reset(struct bdx_priv *priv)
+{
+ ENTER;
+ RET((priv->pdev->device == 0x3009)
+ ? bdx_hw_reset(priv)
+ : bdx_sw_reset(priv));
+}
+
+/**
+ * bdx_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS. The hardware is still under the drivers control, but
+ * needs to be disabled. A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static int bdx_close(struct net_device *ndev)
+{
+ struct bdx_priv *priv = NULL;
+
+ ENTER;
+ priv = ndev->priv;
+
+ napi_disable(&priv->napi);
+
+ bdx_reset(priv);
+ bdx_hw_stop(priv);
+ bdx_rx_free(priv);
+ bdx_tx_free(priv);
+ RET(0);
+}
+
+/**
+ * bdx_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP). At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int bdx_open(struct net_device *ndev)
+{
+ struct bdx_priv *priv;
+ int rc;
+
+ ENTER;
+ priv = ndev->priv;
+ bdx_reset(priv);
+ if (netif_running(ndev))
+ netif_stop_queue(priv->ndev);
+
+ if ((rc = bdx_tx_init(priv)))
+ goto err;
+
+ if ((rc = bdx_rx_init(priv)))
+ goto err;
+
+ if ((rc = bdx_fw_load(priv)))
+ goto err;
+
+ bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0);
+
+ if ((rc = bdx_hw_start(priv)))
+ goto err;
+
+ napi_enable(&priv->napi);
+
+ print_fw_id(priv->nic);
+
+ RET(0);
+
+err:
+ bdx_close(ndev);
+ RET(rc);
+}
+
+static void __init bdx_firmware_endianess(void)
+{
+ int i;
+ for (i = 0; i < sizeof(s_firmLoad) / sizeof(u32); i++)
+ s_firmLoad[i] = CPU_CHIP_SWAP32(s_firmLoad[i]);
+}
+
+static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd)
+{
+ struct bdx_priv *priv = ndev->priv;
+ u32 data[3];
+ int error;
+
+ ENTER;
+
+ DBG("jiffies=%ld cmd=%d\n", jiffies, cmd);
+ if (cmd != SIOCDEVPRIVATE) {
+ error = copy_from_user(data, ifr->ifr_data, sizeof(data));
+ if (error) {
+ ERR("cant copy from user\n");
+ RET(error);
+ }
+ DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]);
+ }
+
+ switch (data[0]) {
+
+ case BDX_OP_READ:
+ data[2] = READ_REG(priv, data[1]);
+ DBG("read_reg(0x%x)=0x%x (dec %d)\n", data[1], data[2],
+ data[2]);
+ error = copy_to_user(ifr->ifr_data, data, sizeof(data));
+ if (error)
+ RET(error);
+ break;
+
+ case BDX_OP_WRITE:
+ WRITE_REG(priv, data[1], data[2]);
+ DBG("write_reg(0x%x, 0x%x)\n", data[1], data[2]);
+ break;
+
+ default:
+ RET(-EOPNOTSUPP);
+ }
+ return 0;
+}
+
+static int bdx_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
+{
+ ENTER;
+ if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15))
+ RET(bdx_ioctl_priv(ndev, ifr, cmd));
+ else
+ RET(-EOPNOTSUPP);
+}
+
+/*
+ * __bdx_vlan_rx_vid - private helper for adding/killing VLAN vid
+ * by passing VLAN filter table to hardware
+ * @ndev network device
+ * @vid VLAN vid
+ * @op add or kill operation
+ */
+static void __bdx_vlan_rx_vid(struct net_device *ndev, uint16_t vid, int enable)
+{
+ struct bdx_priv *priv = ndev->priv;
+ u32 reg, bit, val;
+
+ ENTER;
+ DBG2("vid=%d value=%d\n", (int)vid, enable);
+ if (unlikely(vid >= 4096)) {
+ ERR("tehuti: invalid VID: %u (> 4096)\n", vid);
+ RET();
+ }
+ reg = regVLAN_0 + (vid / 32) * 4;
+ bit = 1 << vid % 32;
+ val = READ_REG(priv, reg);
+ DBG2("reg=%x, val=%x, bit=%d\n", reg, val, bit);
+ if (enable)
+ val |= bit;
+ else
+ val &= ~bit;
+ DBG2("new val %x\n", val);
+ WRITE_REG(priv, reg, val);
+ RET();
+}
+
+/*
+ * bdx_vlan_rx_add_vid - kernel hook for adding VLAN vid to hw filtering table
+ * @ndev network device
+ * @vid VLAN vid to add
+ */
+static void bdx_vlan_rx_add_vid(struct net_device *ndev, uint16_t vid)
+{
+ __bdx_vlan_rx_vid(ndev, vid, 1);
+}
+
+/*
+ * bdx_vlan_rx_kill_vid - kernel hook for killing VLAN vid in hw filtering table
+ * @ndev network device
+ * @vid VLAN vid to kill
+ */
+static void bdx_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vid)
+{
+ __bdx_vlan_rx_vid(ndev, vid, 0);
+}
+
+/*
+ * bdx_vlan_rx_register - kernel hook for adding VLAN group
+ * @ndev network device
+ * @grp VLAN group
+ */
+static void
+bdx_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp)
+{
+ struct bdx_priv *priv = ndev->priv;
+
+ ENTER;
+ DBG("device='%s', group='%p'\n", ndev->name, grp);
+ priv->vlgrp = grp;
+ RET();
+}
+
+/**
+ * bdx_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int bdx_change_mtu(struct net_device *ndev, int new_mtu)
+{
+ ENTER;
+
+ if (new_mtu == ndev->mtu)
+ RET(0);
+
+ /* enforce minimum frame size */
+ if (new_mtu < ETH_ZLEN) {
+ ERR("%s: %s mtu %d is less then minimal %d\n",
+ BDX_DRV_NAME, ndev->name, new_mtu, ETH_ZLEN);
+ RET(-EINVAL);
+ }
+
+ ndev->mtu = new_mtu;
+ if (netif_running(ndev)) {
+ bdx_close(ndev);
+ bdx_open(ndev);
+ }
+ RET(0);
+}
+
+static void bdx_setmulti(struct net_device *ndev)
+{
+ struct bdx_priv *priv = ndev->priv;
+
+ u32 rxf_val =
+ GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB | GMAC_RX_FILTER_OSEN;
+ int i;
+
+ ENTER;
+ /* IMF - imperfect (hash) rx multicat filter */
+ /* PMF - perfect rx multicat filter */
+
+ /* FIXME: RXE(OFF) */
+ if (ndev->flags & IFF_PROMISC) {
+ rxf_val |= GMAC_RX_FILTER_PRM;
+ } else if (ndev->flags & IFF_ALLMULTI) {
+ /* set IMF to accept all multicast frmaes */
+ for (i = 0; i < MAC_MCST_HASH_NUM; i++)
+ WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, ~0);
+ } else if (ndev->mc_count) {
+ u8 hash;
+ struct dev_mc_list *mclist;
+ u32 reg, val;
+
+ /* set IMF to deny all multicast frames */
+ for (i = 0; i < MAC_MCST_HASH_NUM; i++)
+ WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, 0);
+ /* set PMF to deny all multicast frames */
+ for (i = 0; i < MAC_MCST_NUM; i++) {
+ WRITE_REG(priv, regRX_MAC_MCST0 + i * 8, 0);
+ WRITE_REG(priv, regRX_MAC_MCST1 + i * 8, 0);
+ }
+
+ /* use PMF to accept first MAC_MCST_NUM (15) addresses */
+ /* TBD: sort addreses and write them in ascending order
+ * into RX_MAC_MCST regs. we skip this phase now and accept ALL
+ * multicast frames throu IMF */
+ mclist = ndev->mc_list;
+
+ /* accept the rest of addresses throu IMF */
+ for (; mclist; mclist = mclist->next) {
+ hash = 0;
+ for (i = 0; i < ETH_ALEN; i++)
+ hash ^= mclist->dmi_addr[i];
+ reg = regRX_MCST_HASH0 + ((hash >> 5) << 2);
+ val = READ_REG(priv, reg);
+ val |= (1 << (hash % 32));
+ WRITE_REG(priv, reg, val);
+ }
+
+ } else {
+ DBG("only own mac %d\n", ndev->mc_count);
+ rxf_val |= GMAC_RX_FILTER_AB;
+ }
+ WRITE_REG(priv, regGMAC_RXF_A, rxf_val);
+ /* enable RX */
+ /* FIXME: RXE(ON) */
+ RET();
+}
+
+static int bdx_set_mac(struct net_device *ndev, void *p)
+{
+ struct bdx_priv *priv = ndev->priv;
+ struct sockaddr *addr = p;
+
+ ENTER;
+ /*
+ if (netif_running(dev))
+ return -EBUSY
+ */
+ memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
+ bdx_restore_mac(ndev, priv);
+ RET(0);
+}
+
+static int bdx_read_mac(struct bdx_priv *priv)
+{
+ u16 macAddress[3], i;
+ ENTER;
+
+ macAddress[2] = READ_REG(priv, regUNC_MAC0_A);
+ macAddress[2] = READ_REG(priv, regUNC_MAC0_A);
+ macAddress[1] = READ_REG(priv, regUNC_MAC1_A);
+ macAddress[1] = READ_REG(priv, regUNC_MAC1_A);
+ macAddress[0] = READ_REG(priv, regUNC_MAC2_A);
+ macAddress[0] = READ_REG(priv, regUNC_MAC2_A);
+ for (i = 0; i < 3; i++) {
+ priv->ndev->dev_addr[i * 2 + 1] = macAddress[i];
+ priv->ndev->dev_addr[i * 2] = macAddress[i] >> 8;
+ }
+ RET(0);
+}
+
+static u64 bdx_read_l2stat(struct bdx_priv *priv, int reg)
+{
+ u64 val;
+
+ val = READ_REG(priv, reg);
+ val |= ((u64) READ_REG(priv, reg + 8)) << 32;
+ return val;
+}
+
+/*Do the statistics-update work*/
+static void bdx_update_stats(struct bdx_priv *priv)
+{
+ struct bdx_stats *stats = &priv->hw_stats;
+ u64 *stats_vector = (u64 *) stats;
+ int i;
+ int addr;
+
+ /*Fill HW structure */
+ addr = 0x7200;
+ /*First 12 statistics - 0x7200 - 0x72B0 */
+ for (i = 0; i < 12; i++) {
+ stats_vector[i] = bdx_read_l2stat(priv, addr);
+ addr += 0x10;
+ }
+ BDX_ASSERT(addr != 0x72C0);
+ /* 0x72C0-0x72E0 RSRV */
+ addr = 0x72F0;
+ for (; i < 16; i++) {
+ stats_vector[i] = bdx_read_l2stat(priv, addr);
+ addr += 0x10;
+ }
+ BDX_ASSERT(addr != 0x7330);
+ /* 0x7330-0x7360 RSRV */
+ addr = 0x7370;
+ for (; i < 19; i++) {
+ stats_vector[i] = bdx_read_l2stat(priv, addr);
+ addr += 0x10;
+ }
+ BDX_ASSERT(addr != 0x73A0);
+ /* 0x73A0-0x73B0 RSRV */
+ addr = 0x73C0;
+ for (; i < 23; i++) {
+ stats_vector[i] = bdx_read_l2stat(priv, addr);
+ addr += 0x10;
+ }
+ BDX_ASSERT(addr != 0x7400);
+ BDX_ASSERT((sizeof(struct bdx_stats) / sizeof(u64)) != i);
+}
+
+static struct net_device_stats *bdx_get_stats(struct net_device *ndev)
+{
+ struct bdx_priv *priv = ndev->priv;
+ struct net_device_stats *net_stat = &priv->net_stats;
+ return net_stat;
+}
+
+static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len,
+ u16 rxd_vlan);
+static void print_rxfd(struct rxf_desc *rxfd);
+
+/*************************************************************************
+ * Rx DB *
+ *************************************************************************/
+
+static void bdx_rxdb_destroy(struct rxdb *db)
+{
+ if (db)
+ vfree(db);
+}
+
+static struct rxdb *bdx_rxdb_create(int nelem)
+{
+ struct rxdb *db;
+ int i;
+
+ db = vmalloc(sizeof(struct rxdb)
+ + (nelem * sizeof(int))
+ + (nelem * sizeof(struct rx_map)));
+ if (likely(db != NULL)) {
+ db->stack = (int *)(db + 1);
+ db->elems = (void *)(db->stack + nelem);
+ db->nelem = nelem;
+ db->top = nelem;
+ for (i = 0; i < nelem; i++)
+ db->stack[i] = nelem - i - 1; /* to make first allocs
+ close to db struct*/
+ }
+
+ return db;
+}
+
+static inline int bdx_rxdb_alloc_elem(struct rxdb *db)
+{
+ BDX_ASSERT(db->top <= 0);
+ return db->stack[--(db->top)];
+}
+
+static inline void *bdx_rxdb_addr_elem(struct rxdb *db, int n)
+{
+ BDX_ASSERT((n < 0) || (n >= db->nelem));
+ return db->elems + n;
+}
+
+static inline int bdx_rxdb_available(struct rxdb *db)
+{
+ return db->top;
+}
+
+static inline void bdx_rxdb_free_elem(struct rxdb *db, int n)
+{
+ BDX_ASSERT((n >= db->nelem) || (n < 0));
+ db->stack[(db->top)++] = n;
+}
+
+/*************************************************************************
+ * Rx Init *
+ *************************************************************************/
+
+/* bdx_rx_init - initialize RX all related HW and SW resources
+ * @priv - NIC private structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * It creates rxf and rxd fifos, update relevant HW registers, preallocate
+ * skb for rx. It assumes that Rx is desabled in HW
+ * funcs are grouped for better cache usage
+ *
+ * RxD fifo is smaller then RxF fifo by design. Upon high load, RxD will be
+ * filled and packets will be dropped by nic without getting into host or
+ * cousing interrupt. Anyway, in that condition, host has no chance to proccess
+ * all packets, but dropping in nic is cheaper, since it takes 0 cpu cycles
+ */
+
+/* TBD: ensure proper packet size */
+
+static int bdx_rx_init(struct bdx_priv *priv)
+{
+ ENTER;
+
+ if (bdx_fifo_init(priv, &priv->rxd_fifo0.m, priv->rxd_size,
+ regRXD_CFG0_0, regRXD_CFG1_0,
+ regRXD_RPTR_0, regRXD_WPTR_0))
+ goto err_mem;
+ if (bdx_fifo_init(priv, &priv->rxf_fifo0.m, priv->rxf_size,
+ regRXF_CFG0_0, regRXF_CFG1_0,
+ regRXF_RPTR_0, regRXF_WPTR_0))
+ goto err_mem;
+ if (!
+ (priv->rxdb =
+ bdx_rxdb_create(priv->rxf_fifo0.m.memsz /
+ sizeof(struct rxf_desc))))
+ goto err_mem;
+
+ priv->rxf_fifo0.m.pktsz = priv->ndev->mtu + VLAN_ETH_HLEN;
+ return 0;
+
+err_mem:
+ ERR("%s: %s: Rx init failed\n", BDX_DRV_NAME, priv->ndev->name);
+ return -ENOMEM;
+}
+
+/* bdx_rx_free_skbs - frees and unmaps all skbs allocated for the fifo
+ * @priv - NIC private structure
+ * @f - RXF fifo
+ */
+static void bdx_rx_free_skbs(struct bdx_priv *priv, struct rxf_fifo *f)
+{
+ struct rx_map *dm;
+ struct rxdb *db = priv->rxdb;
+ u16 i;
+
+ ENTER;
+ DBG("total=%d free=%d busy=%d\n", db->nelem, bdx_rxdb_available(db),
+ db->nelem - bdx_rxdb_available(db));
+ while (bdx_rxdb_available(db) > 0) {
+ i = bdx_rxdb_alloc_elem(db);
+ dm = bdx_rxdb_addr_elem(db, i);
+ dm->dma = 0;
+ }
+ for (i = 0; i < db->nelem; i++) {
+ dm = bdx_rxdb_addr_elem(db, i);
+ if (dm->dma) {
+ pci_unmap_single(priv->pdev,
+ dm->dma, f->m.pktsz,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(dm->skb);
+ }
+ }
+}
+
+/* bdx_rx_free - release all Rx resources
+ * @priv - NIC private structure
+ * It assumes that Rx is desabled in HW
+ */
+static void bdx_rx_free(struct bdx_priv *priv)
+{
+ ENTER;
+ if (priv->rxdb) {
+ bdx_rx_free_skbs(priv, &priv->rxf_fifo0);
+ bdx_rxdb_destroy(priv->rxdb);
+ priv->rxdb = NULL;
+ }
+ bdx_fifo_free(priv, &priv->rxf_fifo0.m);
+ bdx_fifo_free(priv, &priv->rxd_fifo0.m);
+
+ RET();
+}
+
+/*************************************************************************
+ * Rx Engine *
+ *************************************************************************/
+
+/* bdx_rx_alloc_skbs - fill rxf fifo with new skbs
+ * @priv - nic's private structure
+ * @f - RXF fifo that needs skbs
+ * It allocates skbs, build rxf descs and push it (rxf descr) into rxf fifo.
+ * skb's virtual and physical addresses are stored in skb db.
+ * To calculate free space, func uses cached values of RPTR and WPTR
+ * When needed, it also updates RPTR and WPTR.
+ */
+
+/* TBD: do not update WPTR if no desc were written */
+
+static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f)
+{
+ struct sk_buff *skb;
+ struct rxf_desc *rxfd;
+ struct rx_map *dm;
+ int dno, delta, idx;
+ struct rxdb *db = priv->rxdb;
+
+ ENTER;
+ dno = bdx_rxdb_available(db) - 1;
+ while (dno > 0) {
+ if (!(skb = dev_alloc_skb(f->m.pktsz + NET_IP_ALIGN))) {
+ ERR("NO MEM: dev_alloc_skb failed\n");
+ break;
+ }
+ skb->dev = priv->ndev;
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ idx = bdx_rxdb_alloc_elem(db);
+ dm = bdx_rxdb_addr_elem(db, idx);
+ dm->dma = pci_map_single(priv->pdev,
+ skb->data, f->m.pktsz,
+ PCI_DMA_FROMDEVICE);
+ dm->skb = skb;
+ rxfd = (struct rxf_desc *)(f->m.va + f->m.wptr);
+ rxfd->info = CPU_CHIP_SWAP32(0x10003); /* INFO=1 BC=3 */
+ rxfd->va_lo = idx;
+ rxfd->pa_lo = CPU_CHIP_SWAP32(L32_64(dm->dma));
+ rxfd->pa_hi = CPU_CHIP_SWAP32(H32_64(dm->dma));
+ rxfd->len = CPU_CHIP_SWAP32(f->m.pktsz);
+ print_rxfd(rxfd);
+
+ f->m.wptr += sizeof(struct rxf_desc);
+ delta = f->m.wptr - f->m.memsz;
+ if (unlikely(delta >= 0)) {
+ f->m.wptr = delta;
+ if (delta > 0) {
+ memcpy(f->m.va, f->m.va + f->m.memsz, delta);
+ DBG("wrapped descriptor\n");
+ }
+ }
+ dno--;
+ }
+ /*TBD: to do - delayed rxf wptr like in txd */
+ WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR);
+ RET();
+}
+
+static inline void
+NETIF_RX_MUX(struct bdx_priv *priv, u32 rxd_val1, u16 rxd_vlan,
+ struct sk_buff *skb)
+{
+ ENTER;
+ DBG("rxdd->flags.bits.vtag=%d vlgrp=%p\n", GET_RXD_VTAG(rxd_val1),
+ priv->vlgrp);
+ if (priv->vlgrp && GET_RXD_VTAG(rxd_val1)) {
+ DBG("%s: vlan rcv vlan '%x' vtag '%x', device name '%s'\n",
+ priv->ndev->name,
+ GET_RXD_VLAN_ID(rxd_vlan),
+ GET_RXD_VTAG(rxd_val1),
+ vlan_group_get_device(priv->vlgrp,
+ GET_RXD_VLAN_ID(rxd_vlan))->name);
+ /* NAPI variant of receive functions */
+ vlan_hwaccel_receive_skb(skb, priv->vlgrp,
+ GET_RXD_VLAN_ID(rxd_vlan));
+ } else {
+ netif_receive_skb(skb);
+ }
+}
+
+static void bdx_recycle_skb(struct bdx_priv *priv, struct rxd_desc *rxdd)
+{
+ struct rxf_desc *rxfd;
+ struct rx_map *dm;
+ struct rxf_fifo *f;
+ struct rxdb *db;
+ struct sk_buff *skb;
+ int delta;
+
+ ENTER;
+ DBG("priv=%p rxdd=%p\n", priv, rxdd);
+ f = &priv->rxf_fifo0;
+ db = priv->rxdb;
+ DBG("db=%p f=%p\n", db, f);
+ dm = bdx_rxdb_addr_elem(db, rxdd->va_lo);
+ DBG("dm=%p\n", dm);
+ skb = dm->skb;
+ rxfd = (struct rxf_desc *)(f->m.va + f->m.wptr);
+ rxfd->info = CPU_CHIP_SWAP32(0x10003); /* INFO=1 BC=3 */
+ rxfd->va_lo = rxdd->va_lo;
+ rxfd->pa_lo = CPU_CHIP_SWAP32(L32_64(dm->dma));
+ rxfd->pa_hi = CPU_CHIP_SWAP32(H32_64(dm->dma));
+ rxfd->len = CPU_CHIP_SWAP32(f->m.pktsz);
+ print_rxfd(rxfd);
+
+ f->m.wptr += sizeof(struct rxf_desc);
+ delta = f->m.wptr - f->m.memsz;
+ if (unlikely(delta >= 0)) {
+ f->m.wptr = delta;
+ if (delta > 0) {
+ memcpy(f->m.va, f->m.va + f->m.memsz, delta);
+ DBG("wrapped descriptor\n");
+ }
+ }
+ RET();
+}
+
+/* bdx_rx_receive - recieves full packets from RXD fifo and pass them to OS
+ * NOTE: a special treatment is given to non-continous descriptors
+ * that start near the end, wraps around and continue at the beginning. a second
+ * part is copied right after the first, and then descriptor is interpreted as
+ * normal. fifo has an extra space to allow such operations
+ * @priv - nic's private structure
+ * @f - RXF fifo that needs skbs
+ */
+
+/* TBD: replace memcpy func call by explicite inline asm */
+
+static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget)
+{
+ struct sk_buff *skb, *skb2;
+ struct rxd_desc *rxdd;
+ struct rx_map *dm;
+ struct rxf_fifo *rxf_fifo;
+ int tmp_len, size;
+ int done = 0;
+ int max_done = BDX_MAX_RX_DONE;
+ struct rxdb *db = NULL;
+ /* Unmarshalled descriptor - copy of descriptor in host order */
+ u32 rxd_val1;
+ u16 len;
+ u16 rxd_vlan;
+
+ ENTER;
+ max_done = budget;
+
+ priv->ndev->last_rx = jiffies;
+ f->m.wptr = READ_REG(priv, f->m.reg_WPTR) & TXF_WPTR_WR_PTR;
+
+ size = f->m.wptr - f->m.rptr;
+ if (size < 0)
+ size = f->m.memsz + size; /* size is negative :-) */
+
+ while (size > 0) {
+
+ rxdd = (struct rxd_desc *)(f->m.va + f->m.rptr);
+ rxd_val1 = CPU_CHIP_SWAP32(rxdd->rxd_val1);
+
+ len = CPU_CHIP_SWAP16(rxdd->len);
+
+ rxd_vlan = CPU_CHIP_SWAP16(rxdd->rxd_vlan);
+
+ print_rxdd(rxdd, rxd_val1, len, rxd_vlan);
+
+ tmp_len = GET_RXD_BC(rxd_val1) << 3;
+ BDX_ASSERT(tmp_len <= 0);
+ size -= tmp_len;
+ if (size < 0) /* test for partially arrived descriptor */
+ break;
+
+ f->m.rptr += tmp_len;
+
+ tmp_len = f->m.rptr - f->m.memsz;
+ if (unlikely(tmp_len >= 0)) {
+ f->m.rptr = tmp_len;
+ if (tmp_len > 0) {
+ DBG("wrapped desc rptr=%d tmp_len=%d\n",
+ f->m.rptr, tmp_len);
+ memcpy(f->m.va + f->m.memsz, f->m.va, tmp_len);
+ }
+ }
+
+ if (unlikely(GET_RXD_ERR(rxd_val1))) {
+ DBG("rxd_err = 0x%x\n", GET_RXD_ERR(rxd_val1));
+ priv->net_stats.rx_errors++;
+ bdx_recycle_skb(priv, rxdd);
+ continue;
+ }
+
+ rxf_fifo = &priv->rxf_fifo0;
+ db = priv->rxdb;
+ dm = bdx_rxdb_addr_elem(db, rxdd->va_lo);
+ skb = dm->skb;
+
+ if (len < BDX_COPYBREAK &&
+ (skb2 = dev_alloc_skb(len + NET_IP_ALIGN))) {
+ skb_reserve(skb2, NET_IP_ALIGN);
+ /*skb_put(skb2, len); */
+ pci_dma_sync_single_for_cpu(priv->pdev,
+ dm->dma, rxf_fifo->m.pktsz,
+ PCI_DMA_FROMDEVICE);
+ memcpy(skb2->data, skb->data, len);
+ bdx_recycle_skb(priv, rxdd);
+ skb = skb2;
+ } else {
+ pci_unmap_single(priv->pdev,
+ dm->dma, rxf_fifo->m.pktsz,
+ PCI_DMA_FROMDEVICE);
+ bdx_rxdb_free_elem(db, rxdd->va_lo);
+ }
+
+ priv->net_stats.rx_bytes += len;
+
+ skb_put(skb, len);
+ skb->dev = priv->ndev;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->protocol = eth_type_trans(skb, priv->ndev);
+
+ /* Non-IP packets aren't checksum-offloaded */
+ if (GET_RXD_PKT_ID(rxd_val1) == 0)
+ skb->ip_summed = CHECKSUM_NONE;
+
+ NETIF_RX_MUX(priv, rxd_val1, rxd_vlan, skb);
+
+ if (++done >= max_done)
+ break;
+ }
+
+ priv->net_stats.rx_packets += done;
+
+ /* FIXME: do smth to minimize pci accesses */
+ WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR);
+
+ bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0);
+
+ RET(done);
+}
+
+/*************************************************************************
+ * Debug / Temprorary Code *
+ *************************************************************************/
+static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len,
+ u16 rxd_vlan)
+{
+ DBG("ERROR: rxdd bc %d rxfq %d to %d type %d err %d rxp %d "
+ "pkt_id %d vtag %d len %d vlan_id %d cfi %d prio %d "
+ "va_lo %d va_hi %d\n",
+ GET_RXD_BC(rxd_val1), GET_RXD_RXFQ(rxd_val1), GET_RXD_TO(rxd_val1),
+ GET_RXD_TYPE(rxd_val1), GET_RXD_ERR(rxd_val1),
+ GET_RXD_RXP(rxd_val1), GET_RXD_PKT_ID(rxd_val1),
+ GET_RXD_VTAG(rxd_val1), len, GET_RXD_VLAN_ID(rxd_vlan),
+ GET_RXD_CFI(rxd_vlan), GET_RXD_PRIO(rxd_vlan), rxdd->va_lo,
+ rxdd->va_hi);
+}
+
+static void print_rxfd(struct rxf_desc *rxfd)
+{
+ DBG("=== RxF desc CHIP ORDER/ENDIANESS =============\n"
+ "info 0x%x va_lo %u pa_lo 0x%x pa_hi 0x%x len 0x%x\n",
+ rxfd->info, rxfd->va_lo, rxfd->pa_lo, rxfd->pa_hi, rxfd->len);
+}
+
+/*
+ * TX HW/SW interaction overview
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * There are 2 types of TX communication channels betwean driver and NIC.
+ * 1) TX Free Fifo - TXF - holds ack descriptors for sent packets
+ * 2) TX Data Fifo - TXD - holds descriptors of full buffers.
+ *
+ * Currently NIC supports TSO, checksuming and gather DMA
+ * UFO and IP fragmentation is on the way
+ *
+ * RX SW Data Structures
+ * ~~~~~~~~~~~~~~~~~~~~~
+ * txdb - used to keep track of all skbs owned by SW and their dma addresses.
+ * For TX case, ownership lasts from geting packet via hard_xmit and until HW
+ * acknowledges sent by TXF descriptors.
+ * Implemented as cyclic buffer.
+ * fifo - keeps info about fifo's size and location, relevant HW registers,
+ * usage and skb db. Each RXD and RXF Fifo has its own fifo structure.
+ * Implemented as simple struct.
+ *
+ * TX SW Execution Flow
+ * ~~~~~~~~~~~~~~~~~~~~
+ * OS calls driver's hard_xmit method with packet to sent.
+ * Driver creates DMA mappings, builds TXD descriptors and kicks HW
+ * by updating TXD WPTR.
+ * When packet is sent, HW write us TXF descriptor and SW frees original skb.
+ * To prevent TXD fifo overflow without reading HW registers every time,
+ * SW deploys "tx level" technique.
+ * Upon strart up, tx level is initialized to TXD fifo length.
+ * For every sent packet, SW gets its TXD descriptor sizei
+ * (from precalculated array) and substructs it from tx level.
+ * The size is also stored in txdb. When TXF ack arrives, SW fetch size of
+ * original TXD descriptor from txdb and adds it to tx level.
+ * When Tx level drops under some predefined treshhold, the driver
+ * stops the TX queue. When TX level rises above that level,
+ * the tx queue is enabled again.
+ *
+ * This technique avoids eccessive reading of RPTR and WPTR registers.
+ * As our benchmarks shows, it adds 1.5 Gbit/sec to NIS's throuput.
+ */
+
+/*************************************************************************
+ * Tx DB *
+ *************************************************************************/
+static inline int bdx_tx_db_size(struct txdb *db)
+{
+ int taken = db->wptr - db->rptr;
+ if (taken < 0)
+ taken = db->size + 1 + taken; /* (size + 1) equals memsz */
+
+ return db->size - taken;
+}
+
+/* __bdx_tx_ptr_next - helper function, increment read/write pointer + wrap
+ * @d - tx data base
+ * @ptr - read or write pointer
+ */
+static inline void __bdx_tx_db_ptr_next(struct txdb *db, struct tx_map **pptr)
+{
+ BDX_ASSERT(db == NULL || pptr == NULL); /* sanity */
+
+ BDX_ASSERT(*pptr != db->rptr && /* expect either read */
+ *pptr != db->wptr); /* or write pointer */
+
+ BDX_ASSERT(*pptr < db->start || /* pointer has to be */
+ *pptr >= db->end); /* in range */
+
+ ++*pptr;
+ if (unlikely(*pptr == db->end))
+ *pptr = db->start;
+}
+
+/* bdx_tx_db_inc_rptr - increment read pointer
+ * @d - tx data base
+ */
+static inline void bdx_tx_db_inc_rptr(struct txdb *db)
+{
+ BDX_ASSERT(db->rptr == db->wptr); /* can't read from empty db */
+ __bdx_tx_db_ptr_next(db, &db->rptr);
+}
+
+/* bdx_tx_db_inc_rptr - increment write pointer
+ * @d - tx data base
+ */
+static inline void bdx_tx_db_inc_wptr(struct txdb *db)
+{
+ __bdx_tx_db_ptr_next(db, &db->wptr);
+ BDX_ASSERT(db->rptr == db->wptr); /* we can not get empty db as
+ a result of write */
+}
+
+/* bdx_tx_db_init - creates and initializes tx db
+ * @d - tx data base
+ * @sz_type - size of tx fifo
+ * Returns 0 on success, error code otherwise
+ */
+static int bdx_tx_db_init(struct txdb *d, int sz_type)
+{
+ int memsz = FIFO_SIZE * (1 << (sz_type + 1));
+
+ d->start = vmalloc(memsz);
+ if (!d->start)
+ return -ENOMEM;
+
+ /*
+ * In order to differentiate between db is empty and db is full
+ * states at least one element should always be empty in order to
+ * avoid rptr == wptr which means db is empty
+ */
+ d->size = memsz / sizeof(struct tx_map) - 1;
+ d->end = d->start + d->size + 1; /* just after last element */
+
+ /* all dbs are created equally empty */
+ d->rptr = d->start;
+ d->wptr = d->start;
+
+ return 0;
+}
+
+/* bdx_tx_db_close - closes tx db and frees all memory
+ * @d - tx data base
+ */
+static void bdx_tx_db_close(struct txdb *d)
+{
+ BDX_ASSERT(d == NULL);
+
+ if (d->start) {
+ vfree(d->start);
+ d->start = NULL;
+ }
+}
+
+/*************************************************************************
+ * Tx Engine *
+ *************************************************************************/
+
+/* sizes of tx desc (including padding if needed) as function
+ * of skb's frag number */
+static struct {
+ u16 bytes;
+ u16 qwords; /* qword = 64 bit */
+} txd_sizes[MAX_SKB_FRAGS + 1];
+
+/* txdb_map_skb - creates and stores dma mappings for skb's data blocks
+ * @priv - NIC private structure
+ * @skb - socket buffer to map
+ *
+ * It makes dma mappings for skb's data blocks and writes them to PBL of
+ * new tx descriptor. It also stores them in the tx db, so they could be
+ * unmaped after data was sent. It is reponsibility of a caller to make
+ * sure that there is enough space in the tx db. Last element holds pointer
+ * to skb itself and marked with zero length
+ */
+static inline void
+bdx_tx_map_skb(struct bdx_priv *priv, struct sk_buff *skb,
+ struct txd_desc *txdd)
+{
+ struct txdb *db = &priv->txdb;
+ struct pbl *pbl = &txdd->pbl[0];
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ int i;
+
+ db->wptr->len = skb->len - skb->data_len;
+ db->wptr->addr.dma = pci_map_single(priv->pdev, skb->data,
+ db->wptr->len, PCI_DMA_TODEVICE);
+ pbl->len = CPU_CHIP_SWAP32(db->wptr->len);
+ pbl->pa_lo = CPU_CHIP_SWAP32(L32_64(db->wptr->addr.dma));
+ pbl->pa_hi = CPU_CHIP_SWAP32(H32_64(db->wptr->addr.dma));
+ DBG("=== pbl len: 0x%x ================\n", pbl->len);
+ DBG("=== pbl pa_lo: 0x%x ================\n", pbl->pa_lo);
+ DBG("=== pbl pa_hi: 0x%x ================\n", pbl->pa_hi);
+ bdx_tx_db_inc_wptr(db);
+
+ for (i = 0; i < nr_frags; i++) {
+ struct skb_frag_struct *frag;
+
+ frag = &skb_shinfo(skb)->frags[i];
+ db->wptr->len = frag->size;
+ db->wptr->addr.dma =
+ pci_map_page(priv->pdev, frag->page, frag->page_offset,
+ frag->size, PCI_DMA_TODEVICE);
+
+ pbl++;
+ pbl->len = CPU_CHIP_SWAP32(db->wptr->len);
+ pbl->pa_lo = CPU_CHIP_SWAP32(L32_64(db->wptr->addr.dma));
+ pbl->pa_hi = CPU_CHIP_SWAP32(H32_64(db->wptr->addr.dma));
+ bdx_tx_db_inc_wptr(db);
+ }
+
+ /* add skb clean up info. */
+ db->wptr->len = -txd_sizes[nr_frags].bytes;
+ db->wptr->addr.skb = skb;
+ bdx_tx_db_inc_wptr(db);
+}
+
+/* init_txd_sizes - precalculate sizes of descriptors for skbs up to 16 frags
+ * number of frags is used as index to fetch correct descriptors size,
+ * instead of calculating it each time */
+static void __init init_txd_sizes(void)
+{
+ int i, lwords;
+
+ /* 7 - is number of lwords in txd with one phys buffer
+ * 3 - is number of lwords used for every additional phys buffer */
+ for (i = 0; i < MAX_SKB_FRAGS + 1; i++) {
+ lwords = 7 + (i * 3);
+ if (lwords & 1)
+ lwords++; /* pad it with 1 lword */
+ txd_sizes[i].qwords = lwords >> 1;
+ txd_sizes[i].bytes = lwords << 2;
+ }
+}
+
+/* bdx_tx_init - initialize all Tx related stuff.
+ * Namely, TXD and TXF fifos, database etc */
+static int bdx_tx_init(struct bdx_priv *priv)
+{
+ if (bdx_fifo_init(priv, &priv->txd_fifo0.m, priv->txd_size,
+ regTXD_CFG0_0,
+ regTXD_CFG1_0, regTXD_RPTR_0, regTXD_WPTR_0))
+ goto err_mem;
+ if (bdx_fifo_init(priv, &priv->txf_fifo0.m, priv->txf_size,
+ regTXF_CFG0_0,
+ regTXF_CFG1_0, regTXF_RPTR_0, regTXF_WPTR_0))
+ goto err_mem;
+
+ /* The TX db has to keep mappings for all packets sent (on TxD)
+ * and not yet reclaimed (on TxF) */
+ if (bdx_tx_db_init(&priv->txdb, max(priv->txd_size, priv->txf_size)))
+ goto err_mem;
+
+ priv->tx_level = BDX_MAX_TX_LEVEL;
+#ifdef BDX_DELAY_WPTR
+ priv->tx_update_mark = priv->tx_level - 1024;
+#endif
+ return 0;
+
+err_mem:
+ ERR("tehuti: %s: Tx init failed\n", priv->ndev->name);
+ return -ENOMEM;
+}
+
+/*
+ * bdx_tx_space - calculates avalable space in TX fifo
+ * @priv - NIC private structure
+ * Returns avaliable space in TX fifo in bytes
+ */
+static inline int bdx_tx_space(struct bdx_priv *priv)
+{
+ struct txd_fifo *f = &priv->txd_fifo0;
+ int fsize;
+
+ f->m.rptr = READ_REG(priv, f->m.reg_RPTR) & TXF_WPTR_WR_PTR;
+ fsize = f->m.rptr - f->m.wptr;
+ if (fsize <= 0)
+ fsize = f->m.memsz + fsize;
+ return (fsize);
+}
+
+/* bdx_tx_transmit - send packet to NIC
+ * @skb - packet to send
+ * ndev - network device assigned to NIC
+ * Return codes:
+ * o NETDEV_TX_OK everything ok.
+ * o NETDEV_TX_BUSY Cannot transmit packet, try later
+ * Usually a bug, means queue start/stop flow control is broken in
+ * the driver. Note: the driver must NOT put the skb in its DMA ring.
+ * o NETDEV_TX_LOCKED Locking failed, please retry quickly.
+ */
+static int bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct bdx_priv *priv = ndev->priv;
+ struct txd_fifo *f = &priv->txd_fifo0;
+ int txd_checksum = 7; /* full checksum */
+ int txd_lgsnd = 0;
+ int txd_vlan_id = 0;
+ int txd_vtag = 0;
+ int txd_mss = 0;
+
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ struct txd_desc *txdd;
+ int len;
+ unsigned long flags;
+
+ ENTER;
+ local_irq_save(flags);
+ if (!spin_trylock(&priv->tx_lock)) {
+ local_irq_restore(flags);
+ DBG("%s[%s]: TX locked, returning NETDEV_TX_LOCKED\n",
+ BDX_DRV_NAME, ndev->name);
+ return NETDEV_TX_LOCKED;
+ }
+
+ /* build tx descriptor */
+ BDX_ASSERT(f->m.wptr >= f->m.memsz); /* started with valid wptr */
+ txdd = (struct txd_desc *)(f->m.va + f->m.wptr);
+ if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL))
+ txd_checksum = 0;
+
+ if (skb_shinfo(skb)->gso_size) {
+ txd_mss = skb_shinfo(skb)->gso_size;
+ txd_lgsnd = 1;
+ DBG("skb %p skb len %d gso size = %d\n", skb, skb->len,
+ txd_mss);
+ }
+
+ if (vlan_tx_tag_present(skb)) {
+ /*Cut VLAN ID to 12 bits */
+ txd_vlan_id = vlan_tx_tag_get(skb) & BITS_MASK(12);
+ txd_vtag = 1;
+ }
+
+ txdd->length = CPU_CHIP_SWAP16(skb->len);
+ txdd->mss = CPU_CHIP_SWAP16(txd_mss);
+ txdd->txd_val1 =
+ CPU_CHIP_SWAP32(TXD_W1_VAL
+ (txd_sizes[nr_frags].qwords, txd_checksum, txd_vtag,
+ txd_lgsnd, txd_vlan_id));
+ DBG("=== TxD desc =====================\n");
+ DBG("=== w1: 0x%x ================\n", txdd->txd_val1);
+ DBG("=== w2: mss 0x%x len 0x%x\n", txdd->mss, txdd->length);
+
+ bdx_tx_map_skb(priv, skb, txdd);
+
+ /* increment TXD write pointer. In case of
+ fifo wrapping copy reminder of the descriptor
+ to the beginning */
+ f->m.wptr += txd_sizes[nr_frags].bytes;
+ len = f->m.wptr - f->m.memsz;
+ if (unlikely(len >= 0)) {
+ f->m.wptr = len;
+ if (len > 0) {
+ BDX_ASSERT(len > f->m.memsz);
+ memcpy(f->m.va, f->m.va + f->m.memsz, len);
+ }
+ }
+ BDX_ASSERT(f->m.wptr >= f->m.memsz); /* finished with valid wptr */
+
+ priv->tx_level -= txd_sizes[nr_frags].bytes;
+ BDX_ASSERT(priv->tx_level <= 0 || priv->tx_level > BDX_MAX_TX_LEVEL);
+#ifdef BDX_DELAY_WPTR
+ if (priv->tx_level > priv->tx_update_mark) {
+ /* Force memory writes to complete before letting h/w
+ know there are new descriptors to fetch.
+ (might be needed on platforms like IA64)
+ wmb(); */
+ WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR);
+ } else {
+ if (priv->tx_noupd++ > BDX_NO_UPD_PACKETS) {
+ priv->tx_noupd = 0;
+ WRITE_REG(priv, f->m.reg_WPTR,
+ f->m.wptr & TXF_WPTR_WR_PTR);
+ }
+ }
+#else
+ /* Force memory writes to complete before letting h/w
+ know there are new descriptors to fetch.
+ (might be needed on platforms like IA64)
+ wmb(); */
+ WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR);
+
+#endif
+ ndev->trans_start = jiffies;
+
+ priv->net_stats.tx_packets++;
+ priv->net_stats.tx_bytes += skb->len;
+
+ if (priv->tx_level < BDX_MIN_TX_LEVEL) {
+ DBG("%s: %s: TX Q STOP level %d\n",
+ BDX_DRV_NAME, ndev->name, priv->tx_level);
+ netif_stop_queue(ndev);
+ }
+
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ return NETDEV_TX_OK;
+}
+
+/* bdx_tx_cleanup - clean TXF fifo, run in the context of IRQ.
+ * @priv - bdx adapter
+ * It scans TXF fifo for descriptors, frees DMA mappings and reports to OS
+ * that those packets were sent
+ */
+static void bdx_tx_cleanup(struct bdx_priv *priv)
+{
+ struct txf_fifo *f = &priv->txf_fifo0;
+ struct txdb *db = &priv->txdb;
+ int tx_level = 0;
+
+ ENTER;
+ f->m.wptr = READ_REG(priv, f->m.reg_WPTR) & TXF_WPTR_MASK;
+ BDX_ASSERT(f->m.rptr >= f->m.memsz); /* started with valid rptr */
+
+ while (f->m.wptr != f->m.rptr) {
+ f->m.rptr += BDX_TXF_DESC_SZ;
+ f->m.rptr &= f->m.size_mask;
+
+ /* unmap all the fragments */
+ /* first has to come tx_maps containing dma */
+ BDX_ASSERT(db->rptr->len == 0);
+ do {
+ BDX_ASSERT(db->rptr->addr.dma == 0);
+ pci_unmap_page(priv->pdev, db->rptr->addr.dma,
+ db->rptr->len, PCI_DMA_TODEVICE);
+ bdx_tx_db_inc_rptr(db);
+ } while (db->rptr->len > 0);
+ tx_level -= db->rptr->len; /* '-' koz len is negative */
+
+ /* now should come skb pointer - free it */
+ dev_kfree_skb_irq(db->rptr->addr.skb);
+ bdx_tx_db_inc_rptr(db);
+ }
+
+ /* let h/w know which TXF descriptors were cleaned */
+ BDX_ASSERT((f->m.wptr & TXF_WPTR_WR_PTR) >= f->m.memsz);
+ WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR);
+
+ /* We reclaimed resources, so in case the Q is stopped by xmit callback,
+ * we resume the transmition and use tx_lock to synchronize with xmit.*/
+ spin_lock(&priv->tx_lock);
+ priv->tx_level += tx_level;
+ BDX_ASSERT(priv->tx_level <= 0 || priv->tx_level > BDX_MAX_TX_LEVEL);
+#ifdef BDX_DELAY_WPTR
+ if (priv->tx_noupd) {
+ priv->tx_noupd = 0;
+ WRITE_REG(priv, priv->txd_fifo0.m.reg_WPTR,
+ priv->txd_fifo0.m.wptr & TXF_WPTR_WR_PTR);
+ }
+#endif
+
+ if (unlikely(netif_queue_stopped(priv->ndev)
+ && netif_carrier_ok(priv->ndev)
+ && (priv->tx_level >= BDX_MIN_TX_LEVEL))) {
+ DBG("%s: %s: TX Q WAKE level %d\n",
+ BDX_DRV_NAME, priv->ndev->name, priv->tx_level);
+ netif_wake_queue(priv->ndev);
+ }
+ spin_unlock(&priv->tx_lock);
+}
+
+/* bdx_tx_free_skbs - frees all skbs from TXD fifo.
+ * It gets called when OS stops this dev, eg upon "ifconfig down" or rmmod
+ */
+static void bdx_tx_free_skbs(struct bdx_priv *priv)
+{
+ struct txdb *db = &priv->txdb;
+
+ ENTER;
+ while (db->rptr != db->wptr) {
+ if (likely(db->rptr->len))
+ pci_unmap_page(priv->pdev, db->rptr->addr.dma,
+ db->rptr->len, PCI_DMA_TODEVICE);
+ else
+ dev_kfree_skb(db->rptr->addr.skb);
+ bdx_tx_db_inc_rptr(db);
+ }
+ RET();
+}
+
+/* bdx_tx_free - frees all Tx resources */
+static void bdx_tx_free(struct bdx_priv *priv)
+{
+ ENTER;
+ bdx_tx_free_skbs(priv);
+ bdx_fifo_free(priv, &priv->txd_fifo0.m);
+ bdx_fifo_free(priv, &priv->txf_fifo0.m);
+ bdx_tx_db_close(&priv->txdb);
+}
+
+/* bdx_tx_push_desc - push descriptor to TxD fifo
+ * @priv - NIC private structure
+ * @data - desc's data
+ * @size - desc's size
+ *
+ * Pushes desc to TxD fifo and overlaps it if needed.
+ * NOTE: this func does not check for available space. this is responsibility
+ * of the caller. Neither does it check that data size is smaller then
+ * fifo size.
+ */
+static void bdx_tx_push_desc(struct bdx_priv *priv, void *data, int size)
+{
+ struct txd_fifo *f = &priv->txd_fifo0;
+ int i = f->m.memsz - f->m.wptr;
+
+ if (size == 0)
+ return;
+
+ if (i > size) {
+ memcpy(f->m.va + f->m.wptr, data, size);
+ f->m.wptr += size;
+ } else {
+ memcpy(f->m.va + f->m.wptr, data, i);
+ f->m.wptr = size - i;
+ memcpy(f->m.va, data + i, f->m.wptr);
+ }
+ WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR);
+}
+
+/* bdx_tx_push_desc_safe - push descriptor to TxD fifo in a safe way
+ * @priv - NIC private structure
+ * @data - desc's data
+ * @size - desc's size
+ *
+ * NOTE: this func does check for available space and, if neccessary, waits for
+ * NIC to read existing data before writing new one.
+ */
+static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size)
+{
+ int timer = 0;
+ ENTER;
+
+ while (size > 0) {
+ /* we substruct 8 because when fifo is full rptr == wptr
+ which also means that fifo is empty, we can understand
+ the difference, but could hw do the same ??? :) */
+ int avail = bdx_tx_space(priv) - 8;
+ if (avail <= 0) {
+ if (timer++ > 300) { /* prevent endless loop */
+ DBG("timeout while writing desc to TxD fifo\n");
+ break;
+ }
+ udelay(50); /* give hw a chance to clean fifo */
+ continue;
+ }
+ avail = MIN(avail, size);
+ DBG("about to push %d bytes starting %p size %d\n", avail,
+ data, size);
+ bdx_tx_push_desc(priv, data, avail);
+ size -= avail;
+ data += avail;
+ }
+ RET();
+}
+
+/**
+ * bdx_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in bdx_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * bdx_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ *
+ * functions and their order used as explained in
+ * /usr/src/linux/Documentation/DMA-{API,mapping}.txt
+ *
+ */
+
+/* TBD: netif_msg should be checked and implemented. I disable it for now */
+static int __devinit
+bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct net_device *ndev;
+ struct bdx_priv *priv;
+ int err, pci_using_dac, port;
+ unsigned long pciaddr;
+ u32 regionSize;
+ struct pci_nic *nic;
+
+ ENTER;
+
+ nic = vmalloc(sizeof(*nic));
+ if (!nic)
+ RET(-ENOMEM);
+
+ /************** pci *****************/
+ if ((err = pci_enable_device(pdev))) /* it trigers interrupt, dunno why. */
+ goto err_pci; /* it's not a problem though */
+
+ if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) &&
+ !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) {
+ pci_using_dac = 1;
+ } else {
+ if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) ||
+ (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) {
+ printk(KERN_ERR "tehuti: No usable DMA configuration"
+ ", aborting\n");
+ goto err_dma;
+ }
+ pci_using_dac = 0;
+ }
+
+ if ((err = pci_request_regions(pdev, BDX_DRV_NAME)))
+ goto err_dma;
+
+ pci_set_master(pdev);
+
+ pciaddr = pci_resource_start(pdev, 0);
+ if (!pciaddr) {
+ err = -EIO;
+ ERR("tehuti: no MMIO resource\n");
+ goto err_out_res;
+ }
+ if ((regionSize = pci_resource_len(pdev, 0)) < BDX_REGS_SIZE) {
+ err = -EIO;
+ ERR("tehuti: MMIO resource (%x) too small\n", regionSize);
+ goto err_out_res;
+ }
+
+ nic->regs = ioremap(pciaddr, regionSize);
+ if (!nic->regs) {
+ err = -EIO;
+ ERR("tehuti: ioremap failed\n");
+ goto err_out_res;
+ }
+
+ if (pdev->irq < 2) {
+ err = -EIO;
+ ERR("tehuti: invalid irq (%d)\n", pdev->irq);
+ goto err_out_iomap;
+ }
+ pci_set_drvdata(pdev, nic);
+
+ if (pdev->device == 0x3014)
+ nic->port_num = 2;
+ else
+ nic->port_num = 1;
+
+ print_hw_id(pdev);
+
+ bdx_hw_reset_direct(nic->regs);
+
+ nic->irq_type = IRQ_INTX;
+#ifdef BDX_MSI
+ if ((readl(nic->regs + FPGA_VER) & 0xFFF) >= 378) {
+ if ((err = pci_enable_msi(pdev)))
+ ERR("Tehuti: Can't eneble msi. error is %d\n", err);
+ else
+ nic->irq_type = IRQ_MSI;
+ } else
+ DBG("HW does not support MSI\n");
+#endif
+
+ /************** netdev **************/
+ for (port = 0; port < nic->port_num; port++) {
+ if (!(ndev = alloc_etherdev(sizeof(struct bdx_priv)))) {
+ err = -ENOMEM;
+ printk(KERN_ERR "tehuti: alloc_etherdev failed\n");
+ goto err_out_iomap;
+ }
+
+ ndev->open = bdx_open;
+ ndev->stop = bdx_close;
+ ndev->hard_start_xmit = bdx_tx_transmit;
+ ndev->do_ioctl = bdx_ioctl;
+ ndev->set_multicast_list = bdx_setmulti;
+ ndev->get_stats = bdx_get_stats;
+ ndev->change_mtu = bdx_change_mtu;
+ ndev->set_mac_address = bdx_set_mac;
+ ndev->tx_queue_len = BDX_NDEV_TXQ_LEN;
+ ndev->vlan_rx_register = bdx_vlan_rx_register;
+ ndev->vlan_rx_add_vid = bdx_vlan_rx_add_vid;
+ ndev->vlan_rx_kill_vid = bdx_vlan_rx_kill_vid;
+
+ bdx_ethtool_ops(ndev); /* ethtool interface */
+
+ /* these fields are used for info purposes only
+ * so we can have them same for all ports of the board */
+ ndev->if_port = port;
+ ndev->base_addr = pciaddr;
+ ndev->mem_start = pciaddr;
+ ndev->mem_end = pciaddr + regionSize;
+ ndev->irq = pdev->irq;
+ ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO
+ | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER
+ /*| NETIF_F_FRAGLIST */
+ ;
+
+ if (pci_using_dac)
+ ndev->features |= NETIF_F_HIGHDMA;
+
+ /************** priv ****************/
+ priv = nic->priv[port] = ndev->priv;
+
+ memset(priv, 0, sizeof(struct bdx_priv));
+ priv->pBdxRegs = nic->regs + port * 0x8000;
+ priv->port = port;
+ priv->pdev = pdev;
+ priv->ndev = ndev;
+ priv->nic = nic;
+ priv->msg_enable = BDX_DEF_MSG_ENABLE;
+
+ netif_napi_add(ndev, &priv->napi, bdx_poll, 64);
+
+ if ((readl(nic->regs + FPGA_VER) & 0xFFF) == 308) {
+ DBG("HW statistics not supported\n");
+ priv->stats_flag = 0;
+ } else {
+ priv->stats_flag = 1;
+ }
+
+ /* Initialize fifo sizes. */
+ priv->txd_size = 2;
+ priv->txf_size = 2;
+ priv->rxd_size = 2;
+ priv->rxf_size = 3;
+
+ /* Initialize the initial coalescing registers. */
+ priv->rdintcm = INT_REG_VAL(0x20, 1, 4, 12);
+ priv->tdintcm = INT_REG_VAL(0x20, 1, 0, 12);
+
+ /* ndev->xmit_lock spinlock is not used.
+ * Private priv->tx_lock is used for synchronization
+ * between transmit and TX irq cleanup. In addition
+ * set multicast list callback has to use priv->tx_lock.
+ */
+#ifdef BDX_LLTX
+ ndev->features |= NETIF_F_LLTX;
+#endif
+ spin_lock_init(&priv->tx_lock);
+
+ /*bdx_hw_reset(priv); */
+ if (bdx_read_mac(priv)) {
+ printk(KERN_ERR "tehuti: load MAC address failed\n");
+ goto err_out_iomap;
+ }
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+ if ((err = register_netdev(ndev))) {
+ printk(KERN_ERR "tehuti: register_netdev failed\n");
+ goto err_out_free;
+ }
+ netif_carrier_off(ndev);
+ netif_stop_queue(ndev);
+
+ print_eth_id(ndev);
+ }
+ RET(0);
+
+err_out_free:
+ free_netdev(ndev);
+err_out_iomap:
+ iounmap(nic->regs);
+err_out_res:
+ pci_release_regions(pdev);
+err_dma:
+ pci_disable_device(pdev);
+err_pci:
+ vfree(nic);
+
+ RET(err);
+}
+
+/****************** Ethtool interface *********************/
+/* get strings for tests */
+static const char
+ bdx_test_names[][ETH_GSTRING_LEN] = {
+ "No tests defined"
+};
+
+/* get strings for statistics counters */
+static const char
+ bdx_stat_names[][ETH_GSTRING_LEN] = {
+ "InUCast", /* 0x7200 */
+ "InMCast", /* 0x7210 */
+ "InBCast", /* 0x7220 */
+ "InPkts", /* 0x7230 */
+ "InErrors", /* 0x7240 */
+ "InDropped", /* 0x7250 */
+ "FrameTooLong", /* 0x7260 */
+ "FrameSequenceErrors", /* 0x7270 */
+ "InVLAN", /* 0x7280 */
+ "InDroppedDFE", /* 0x7290 */
+ "InDroppedIntFull", /* 0x72A0 */
+ "InFrameAlignErrors", /* 0x72B0 */
+
+ /* 0x72C0-0x72E0 RSRV */
+
+ "OutUCast", /* 0x72F0 */
+ "OutMCast", /* 0x7300 */
+ "OutBCast", /* 0x7310 */
+ "OutPkts", /* 0x7320 */
+
+ /* 0x7330-0x7360 RSRV */
+
+ "OutVLAN", /* 0x7370 */
+ "InUCastOctects", /* 0x7380 */
+ "OutUCastOctects", /* 0x7390 */
+
+ /* 0x73A0-0x73B0 RSRV */
+
+ "InBCastOctects", /* 0x73C0 */
+ "OutBCastOctects", /* 0x73D0 */
+ "InOctects", /* 0x73E0 */
+ "OutOctects", /* 0x73F0 */
+};
+
+/*
+ * bdx_get_settings - get device-specific settings
+ * @netdev
+ * @ecmd
+ */
+static int bdx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+ u32 rdintcm;
+ u32 tdintcm;
+ struct bdx_priv *priv = netdev->priv;
+
+ rdintcm = priv->rdintcm;
+ tdintcm = priv->tdintcm;
+
+ ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
+ ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
+ ecmd->speed = SPEED_10000;
+ ecmd->duplex = DUPLEX_FULL;
+ ecmd->port = PORT_FIBRE;
+ ecmd->transceiver = XCVR_EXTERNAL; /* what does it mean? */
+ ecmd->autoneg = AUTONEG_DISABLE;
+
+ /* PCK_TH measures in multiples of FIFO bytes
+ We translate to packets */
+ ecmd->maxtxpkt =
+ ((GET_PCK_TH(tdintcm) * PCK_TH_MULT) / BDX_TXF_DESC_SZ);
+ ecmd->maxrxpkt =
+ ((GET_PCK_TH(rdintcm) * PCK_TH_MULT) / sizeof(struct rxf_desc));
+
+ return 0;
+}
+
+/*
+ * bdx_get_drvinfo - report driver information
+ * @netdev
+ * @drvinfo
+ */
+static void
+bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
+{
+ struct bdx_priv *priv = netdev->priv;
+
+ strlcat(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver));
+ strlcat(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version));
+ strlcat(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+ strlcat(drvinfo->bus_info, pci_name(priv->pdev),
+ sizeof(drvinfo->bus_info));
+
+ drvinfo->n_stats = ((priv->stats_flag) ?
+ (sizeof(bdx_stat_names) / ETH_GSTRING_LEN) : 0);
+ drvinfo->testinfo_len = 0;
+ drvinfo->regdump_len = 0;
+ drvinfo->eedump_len = 0;
+}
+
+/*
+ * bdx_get_rx_csum - report whether receive checksums are turned on or off
+ * @netdev
+ */
+static u32 bdx_get_rx_csum(struct net_device *netdev)
+{
+ return 1; /* always on */
+}
+
+/*
+ * bdx_get_tx_csum - report whether transmit checksums are turned on or off
+ * @netdev
+ */
+static u32 bdx_get_tx_csum(struct net_device *netdev)
+{
+ return (netdev->features & NETIF_F_IP_CSUM) != 0;
+}
+
+/*
+ * bdx_get_coalesce - get interrupt coalescing parameters
+ * @netdev
+ * @ecoal
+ */
+static int
+bdx_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal)
+{
+ u32 rdintcm;
+ u32 tdintcm;
+ struct bdx_priv *priv = netdev->priv;
+
+ rdintcm = priv->rdintcm;
+ tdintcm = priv->tdintcm;
+
+ /* PCK_TH measures in multiples of FIFO bytes
+ We translate to packets */
+ ecoal->rx_coalesce_usecs = GET_INT_COAL(rdintcm) * INT_COAL_MULT;
+ ecoal->rx_max_coalesced_frames =
+ ((GET_PCK_TH(rdintcm) * PCK_TH_MULT) / sizeof(struct rxf_desc));
+
+ ecoal->tx_coalesce_usecs = GET_INT_COAL(tdintcm) * INT_COAL_MULT;
+ ecoal->tx_max_coalesced_frames =
+ ((GET_PCK_TH(tdintcm) * PCK_TH_MULT) / BDX_TXF_DESC_SZ);
+
+ /* adaptive parameters ignored */
+ return 0;
+}
+
+/*
+ * bdx_set_coalesce - set interrupt coalescing parameters
+ * @netdev
+ * @ecoal
+ */
+static int
+bdx_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal)
+{
+ u32 rdintcm;
+ u32 tdintcm;
+ struct bdx_priv *priv = netdev->priv;
+ int rx_coal;
+ int tx_coal;
+ int rx_max_coal;
+ int tx_max_coal;
+
+ /* Check for valid input */
+ rx_coal = ecoal->rx_coalesce_usecs / INT_COAL_MULT;
+ tx_coal = ecoal->tx_coalesce_usecs / INT_COAL_MULT;
+ rx_max_coal = ecoal->rx_max_coalesced_frames;
+ tx_max_coal = ecoal->tx_max_coalesced_frames;
+
+ /* Translate from packets to multiples of FIFO bytes */
+ rx_max_coal =
+ (((rx_max_coal * sizeof(struct rxf_desc)) + PCK_TH_MULT - 1)
+ / PCK_TH_MULT);
+ tx_max_coal =
+ (((tx_max_coal * BDX_TXF_DESC_SZ) + PCK_TH_MULT - 1)
+ / PCK_TH_MULT);
+
+ if ((rx_coal > 0x7FFF) || (tx_coal > 0x7FFF)
+ || (rx_max_coal > 0xF) || (tx_max_coal > 0xF))
+ return -EINVAL;
+
+ rdintcm = INT_REG_VAL(rx_coal, GET_INT_COAL_RC(priv->rdintcm),
+ GET_RXF_TH(priv->rdintcm), rx_max_coal);
+ tdintcm = INT_REG_VAL(tx_coal, GET_INT_COAL_RC(priv->tdintcm), 0,
+ tx_max_coal);
+
+ priv->rdintcm = rdintcm;
+ priv->tdintcm = tdintcm;
+
+ WRITE_REG(priv, regRDINTCM0, rdintcm);
+ WRITE_REG(priv, regTDINTCM0, tdintcm);
+
+ return 0;
+}
+
+/* Convert RX fifo size to number of pending packets */
+static inline int bdx_rx_fifo_size_to_packets(int rx_size)
+{
+ return ((FIFO_SIZE * (1 << rx_size)) / sizeof(struct rxf_desc));
+}
+
+/* Convert TX fifo size to number of pending packets */
+static inline int bdx_tx_fifo_size_to_packets(int tx_size)
+{
+ return ((FIFO_SIZE * (1 << tx_size)) / BDX_TXF_DESC_SZ);
+}
+
+/*
+ * bdx_get_ringparam - report ring sizes
+ * @netdev
+ * @ring
+ */
+static void
+bdx_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
+{
+ struct bdx_priv *priv = netdev->priv;
+
+ /*max_pending - the maximum-sized FIFO we allow */
+ ring->rx_max_pending = bdx_rx_fifo_size_to_packets(3);
+ ring->tx_max_pending = bdx_tx_fifo_size_to_packets(3);
+ ring->rx_pending = bdx_rx_fifo_size_to_packets(priv->rxf_size);
+ ring->tx_pending = bdx_tx_fifo_size_to_packets(priv->txd_size);
+}
+
+/*
+ * bdx_set_ringparam - set ring sizes
+ * @netdev
+ * @ring
+ */
+static int
+bdx_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
+{
+ struct bdx_priv *priv = netdev->priv;
+ int rx_size = 0;
+ int tx_size = 0;
+
+ for (; rx_size < 4; rx_size++) {
+ if (bdx_rx_fifo_size_to_packets(rx_size) >= ring->rx_pending)
+ break;
+ }
+ if (rx_size == 4)
+ rx_size = 3;
+
+ for (; tx_size < 4; tx_size++) {
+ if (bdx_tx_fifo_size_to_packets(tx_size) >= ring->tx_pending)
+ break;
+ }
+ if (tx_size == 4)
+ tx_size = 3;
+
+ /*Is there anything to do? */
+ if ((rx_size == priv->rxf_size)
+ && (tx_size == priv->txd_size))
+ return 0;
+
+ priv->rxf_size = rx_size;
+ if (rx_size > 1)
+ priv->rxd_size = rx_size - 1;
+ else
+ priv->rxd_size = rx_size;
+
+ priv->txf_size = priv->txd_size = tx_size;
+
+ if (netif_running(netdev)) {
+ bdx_close(netdev);
+ bdx_open(netdev);
+ }
+ return 0;
+}
+
+/*
+ * bdx_get_strings - return a set of strings that describe the requested objects
+ * @netdev
+ * @data
+ */
+static void bdx_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+ switch (stringset) {
+ case ETH_SS_TEST:
+ memcpy(data, *bdx_test_names, sizeof(bdx_test_names));
+ break;
+ case ETH_SS_STATS:
+ memcpy(data, *bdx_stat_names, sizeof(bdx_stat_names));
+ break;
+ }
+}
+
+/*
+ * bdx_get_stats_count - return number of 64bit statistics counters
+ * @netdev
+ */
+static int bdx_get_stats_count(struct net_device *netdev)
+{
+ struct bdx_priv *priv = netdev->priv;
+ BDX_ASSERT(sizeof(bdx_stat_names) / ETH_GSTRING_LEN
+ != sizeof(struct bdx_stats) / sizeof(u64));
+ return ((priv->stats_flag) ? (sizeof(bdx_stat_names) / ETH_GSTRING_LEN)
+ : 0);
+}
+
+/*
+ * bdx_get_ethtool_stats - return device's hardware L2 statistics
+ * @netdev
+ * @stats
+ * @data
+ */
+static void bdx_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct bdx_priv *priv = netdev->priv;
+
+ if (priv->stats_flag) {
+
+ /* Update stats from HW */
+ bdx_update_stats(priv);
+
+ /* Copy data to user buffer */
+ memcpy(data, &priv->hw_stats, sizeof(priv->hw_stats));
+ }
+}
+
+/*
+ * bdx_ethtool_ops - ethtool interface implementation
+ * @netdev
+ */
+static void bdx_ethtool_ops(struct net_device *netdev)
+{
+ static struct ethtool_ops bdx_ethtool_ops = {
+ .get_settings = bdx_get_settings,
+ .get_drvinfo = bdx_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_coalesce = bdx_get_coalesce,
+ .set_coalesce = bdx_set_coalesce,
+ .get_ringparam = bdx_get_ringparam,
+ .set_ringparam = bdx_set_ringparam,
+ .get_rx_csum = bdx_get_rx_csum,
+ .get_tx_csum = bdx_get_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .get_tso = ethtool_op_get_tso,
+ .get_strings = bdx_get_strings,
+ .get_stats_count = bdx_get_stats_count,
+ .get_ethtool_stats = bdx_get_ethtool_stats,
+ };
+
+ SET_ETHTOOL_OPS(netdev, &bdx_ethtool_ops);
+}
+
+/**
+ * bdx_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * bdx_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device. The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit bdx_remove(struct pci_dev *pdev)
+{
+ struct pci_nic *nic = pci_get_drvdata(pdev);
+ struct net_device *ndev;
+ int port;
+
+ for (port = 0; port < nic->port_num; port++) {
+ ndev = nic->priv[port]->ndev;
+ unregister_netdev(ndev);
+ free_netdev(ndev);
+ }
+
+ /*bdx_hw_reset_direct(nic->regs); */
+#ifdef BDX_MSI
+ if (nic->irq_type == IRQ_MSI)
+ pci_disable_msi(pdev);
+#endif
+
+ iounmap(nic->regs);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ vfree(nic);
+
+ RET();
+}
+
+static struct pci_driver bdx_pci_driver = {
+ .name = BDX_DRV_NAME,
+ .id_table = bdx_pci_tbl,
+ .probe = bdx_probe,
+ .remove = __devexit_p(bdx_remove),
+};
+
+/*
+ * print_driver_id - print parameters of the driver build
+ */
+static void __init print_driver_id(void)
+{
+ printk(KERN_INFO "%s: %s, %s\n", BDX_DRV_NAME, BDX_DRV_DESC,
+ BDX_DRV_VERSION);
+ printk(KERN_INFO "%s: Options: hw_csum %s\n", BDX_DRV_NAME,
+ BDX_MSI_STRING);
+}
+
+static int __init bdx_module_init(void)
+{
+ ENTER;
+ bdx_firmware_endianess();
+ init_txd_sizes();
+ print_driver_id();
+ RET(pci_register_driver(&bdx_pci_driver));
+}
+
+module_init(bdx_module_init);
+
+static void __exit bdx_module_exit(void)
+{
+ ENTER;
+ pci_unregister_driver(&bdx_pci_driver);
+ RET();
+}
+
+module_exit(bdx_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(BDX_DRV_DESC);
diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h
new file mode 100644
index 00000000000..efd170f451b
--- /dev/null
+++ b/drivers/net/tehuti.h
@@ -0,0 +1,564 @@
+/*
+ * Tehuti Networks(R) Network Driver
+ * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _TEHUTI_H
+#define _TEHUTI_H
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <linux/uaccess.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/if_vlan.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <asm/byteorder.h>
+
+/* Compile Time Switches */
+/* start */
+#define BDX_TSO
+#define BDX_LLTX
+#define BDX_DELAY_WPTR
+/* #define BDX_MSI */
+/* end */
+
+#if !defined CONFIG_PCI_MSI
+# undef BDX_MSI
+#endif
+
+#define BDX_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK)
+
+/* ioctl ops */
+#define BDX_OP_READ 1
+#define BDX_OP_WRITE 2
+
+/* RX copy break size */
+#define BDX_COPYBREAK 257
+
+#define DRIVER_AUTHOR "Tehuti Networks(R)"
+#define BDX_DRV_DESC "Tehuti Networks(R) Network Driver"
+#define BDX_DRV_NAME "tehuti"
+#define BDX_NIC_NAME "Tehuti 10 Giga TOE SmartNIC"
+#define BDX_NIC2PORT_NAME "Tehuti 2-Port 10 Giga TOE SmartNIC"
+#define BDX_DRV_VERSION "7.29.3"
+
+#ifdef BDX_MSI
+# define BDX_MSI_STRING "msi "
+#else
+# define BDX_MSI_STRING ""
+#endif
+
+/* netdev tx queue len for Luxor. default value is, btw, 1000
+ * ifcontig eth1 txqueuelen 3000 - to change it at runtime */
+#define BDX_NDEV_TXQ_LEN 3000
+
+#define FIFO_SIZE 4096
+#define FIFO_EXTRA_SPACE 1024
+
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+
+#if BITS_PER_LONG == 64
+# define H32_64(x) (u32) ((u64)(x) >> 32)
+# define L32_64(x) (u32) ((u64)(x) & 0xffffffff)
+#elif BITS_PER_LONG == 32
+# define H32_64(x) 0
+# define L32_64(x) ((u32) (x))
+#else /* BITS_PER_LONG == ?? */
+# error BITS_PER_LONG is undefined. Must be 64 or 32
+#endif /* BITS_PER_LONG */
+
+#ifdef __BIG_ENDIAN
+# define CPU_CHIP_SWAP32(x) swab32(x)
+# define CPU_CHIP_SWAP16(x) swab16(x)
+#else
+# define CPU_CHIP_SWAP32(x) (x)
+# define CPU_CHIP_SWAP16(x) (x)
+#endif
+
+#define READ_REG(pp, reg) readl(pp->pBdxRegs + reg)
+#define WRITE_REG(pp, reg, val) writel(val, pp->pBdxRegs + reg)
+
+#ifndef DMA_64BIT_MASK
+# define DMA_64BIT_MASK 0xffffffffffffffffULL
+#endif
+
+#ifndef DMA_32BIT_MASK
+# define DMA_32BIT_MASK 0x00000000ffffffffULL
+#endif
+
+#ifndef NET_IP_ALIGN
+# define NET_IP_ALIGN 2
+#endif
+
+#ifndef NETDEV_TX_OK
+# define NETDEV_TX_OK 0
+#endif
+
+#define LUXOR_MAX_PORT 2
+#define BDX_MAX_RX_DONE 150
+#define BDX_TXF_DESC_SZ 16
+#define BDX_MAX_TX_LEVEL (priv->txd_fifo0.m.memsz - 16)
+#define BDX_MIN_TX_LEVEL 256
+#define BDX_NO_UPD_PACKETS 40
+
+struct pci_nic {
+ int port_num;
+ void __iomem *regs;
+ int irq_type;
+ struct bdx_priv *priv[LUXOR_MAX_PORT];
+};
+
+enum { IRQ_INTX, IRQ_MSI, IRQ_MSIX };
+
+#define PCK_TH_MULT 128
+#define INT_COAL_MULT 2
+
+#define BITS_MASK(nbits) ((1<<nbits)-1)
+#define GET_BITS_SHIFT(x, nbits, nshift) (((x)>>nshift)&BITS_MASK(nbits))
+#define BITS_SHIFT_MASK(nbits, nshift) (BITS_MASK(nbits)<<nshift)
+#define BITS_SHIFT_VAL(x, nbits, nshift) (((x)&BITS_MASK(nbits))<<nshift)
+#define BITS_SHIFT_CLEAR(x, nbits, nshift) \
+ ((x)&(~BITS_SHIFT_MASK(nbits, nshift)))
+
+#define GET_INT_COAL(x) GET_BITS_SHIFT(x, 15, 0)
+#define GET_INT_COAL_RC(x) GET_BITS_SHIFT(x, 1, 15)
+#define GET_RXF_TH(x) GET_BITS_SHIFT(x, 4, 16)
+#define GET_PCK_TH(x) GET_BITS_SHIFT(x, 4, 20)
+
+#define INT_REG_VAL(coal, coal_rc, rxf_th, pck_th) \
+ ((coal)|((coal_rc)<<15)|((rxf_th)<<16)|((pck_th)<<20))
+
+struct fifo {
+ dma_addr_t da; /* physical address of fifo (used by HW) */
+ char *va; /* virtual address of fifo (used by SW) */
+ u32 rptr, wptr; /* cached values of RPTR and WPTR registers,
+ they're 32 bits on both 32 and 64 archs */
+ u16 reg_CFG0, reg_CFG1;
+ u16 reg_RPTR, reg_WPTR;
+ u16 memsz; /* memory size allocated for fifo */
+ u16 size_mask;
+ u16 pktsz; /* skb packet size to allocate */
+ u16 rcvno; /* number of buffers that come from this RXF */
+};
+
+struct txf_fifo {
+ struct fifo m; /* minimal set of variables used by all fifos */
+};
+
+struct txd_fifo {
+ struct fifo m; /* minimal set of variables used by all fifos */
+};
+
+struct rxf_fifo {
+ struct fifo m; /* minimal set of variables used by all fifos */
+};
+
+struct rxd_fifo {
+ struct fifo m; /* minimal set of variables used by all fifos */
+};
+
+struct rx_map {
+ u64 dma;
+ struct sk_buff *skb;
+};
+
+struct rxdb {
+ int *stack;
+ struct rx_map *elems;
+ int nelem;
+ int top;
+};
+
+union bdx_dma_addr {
+ dma_addr_t dma;
+ struct sk_buff *skb;
+};
+
+/* Entry in the db.
+ * if len == 0 addr is dma
+ * if len != 0 addr is skb */
+struct tx_map {
+ union bdx_dma_addr addr;
+ int len;
+};
+
+/* tx database - implemented as circular fifo buffer*/
+struct txdb {
+ struct tx_map *start; /* points to the first element */
+ struct tx_map *end; /* points just AFTER the last element */
+ struct tx_map *rptr; /* points to the next element to read */
+ struct tx_map *wptr; /* points to the next element to write */
+ int size; /* number of elements in the db */
+};
+
+/*Internal stats structure*/
+struct bdx_stats {
+ u64 InUCast; /* 0x7200 */
+ u64 InMCast; /* 0x7210 */
+ u64 InBCast; /* 0x7220 */
+ u64 InPkts; /* 0x7230 */
+ u64 InErrors; /* 0x7240 */
+ u64 InDropped; /* 0x7250 */
+ u64 FrameTooLong; /* 0x7260 */
+ u64 FrameSequenceErrors; /* 0x7270 */
+ u64 InVLAN; /* 0x7280 */
+ u64 InDroppedDFE; /* 0x7290 */
+ u64 InDroppedIntFull; /* 0x72A0 */
+ u64 InFrameAlignErrors; /* 0x72B0 */
+
+ /* 0x72C0-0x72E0 RSRV */
+
+ u64 OutUCast; /* 0x72F0 */
+ u64 OutMCast; /* 0x7300 */
+ u64 OutBCast; /* 0x7310 */
+ u64 OutPkts; /* 0x7320 */
+
+ /* 0x7330-0x7360 RSRV */
+
+ u64 OutVLAN; /* 0x7370 */
+ u64 InUCastOctects; /* 0x7380 */
+ u64 OutUCastOctects; /* 0x7390 */
+
+ /* 0x73A0-0x73B0 RSRV */
+
+ u64 InBCastOctects; /* 0x73C0 */
+ u64 OutBCastOctects; /* 0x73D0 */
+ u64 InOctects; /* 0x73E0 */
+ u64 OutOctects; /* 0x73F0 */
+};
+
+struct bdx_priv {
+ void __iomem *pBdxRegs;
+ struct net_device *ndev;
+
+ struct napi_struct napi;
+
+ /* RX FIFOs: 1 for data (full) descs, and 2 for free descs */
+ struct rxd_fifo rxd_fifo0;
+ struct rxf_fifo rxf_fifo0;
+ struct rxdb *rxdb; /* rx dbs to store skb pointers */
+ int napi_stop;
+ struct vlan_group *vlgrp;
+
+ /* Tx FIFOs: 1 for data desc, 1 for empty (acks) desc */
+ struct txd_fifo txd_fifo0;
+ struct txf_fifo txf_fifo0;
+
+ struct txdb txdb;
+ int tx_level;
+#ifdef BDX_DELAY_WPTR
+ int tx_update_mark;
+ int tx_noupd;
+#endif
+ spinlock_t tx_lock; /* NETIF_F_LLTX mode */
+
+ /* rarely used */
+ u8 port;
+ u32 msg_enable;
+ int stats_flag;
+ struct bdx_stats hw_stats;
+ struct net_device_stats net_stats;
+ struct pci_dev *pdev;
+
+ struct pci_nic *nic;
+
+ u8 txd_size;
+ u8 txf_size;
+ u8 rxd_size;
+ u8 rxf_size;
+ u32 rdintcm;
+ u32 tdintcm;
+};
+
+/* RX FREE descriptor - 64bit*/
+struct rxf_desc {
+ u32 info; /* Buffer Count + Info - described below */
+ u32 va_lo; /* VAdr[31:0] */
+ u32 va_hi; /* VAdr[63:32] */
+ u32 pa_lo; /* PAdr[31:0] */
+ u32 pa_hi; /* PAdr[63:32] */
+ u32 len; /* Buffer Length */
+};
+
+#define GET_RXD_BC(x) GET_BITS_SHIFT((x), 5, 0)
+#define GET_RXD_RXFQ(x) GET_BITS_SHIFT((x), 2, 8)
+#define GET_RXD_TO(x) GET_BITS_SHIFT((x), 1, 15)
+#define GET_RXD_TYPE(x) GET_BITS_SHIFT((x), 4, 16)
+#define GET_RXD_ERR(x) GET_BITS_SHIFT((x), 6, 21)
+#define GET_RXD_RXP(x) GET_BITS_SHIFT((x), 1, 27)
+#define GET_RXD_PKT_ID(x) GET_BITS_SHIFT((x), 3, 28)
+#define GET_RXD_VTAG(x) GET_BITS_SHIFT((x), 1, 31)
+#define GET_RXD_VLAN_ID(x) GET_BITS_SHIFT((x), 12, 0)
+#define GET_RXD_CFI(x) GET_BITS_SHIFT((x), 1, 12)
+#define GET_RXD_PRIO(x) GET_BITS_SHIFT((x), 3, 13)
+
+struct rxd_desc {
+ u32 rxd_val1;
+ u16 len;
+ u16 rxd_vlan;
+ u32 va_lo;
+ u32 va_hi;
+};
+
+/* PBL describes each virtual buffer to be */
+/* transmitted from the host.*/
+struct pbl {
+ u32 pa_lo;
+ u32 pa_hi;
+ u32 len;
+};
+
+/* First word for TXD descriptor. It means: type = 3 for regular Tx packet,
+ * hw_csum = 7 for ip+udp+tcp hw checksums */
+#define TXD_W1_VAL(bc, checksum, vtag, lgsnd, vlan_id) \
+ ((bc) | ((checksum)<<5) | ((vtag)<<8) | \
+ ((lgsnd)<<9) | (0x30000) | ((vlan_id)<<20))
+
+struct txd_desc {
+ u32 txd_val1;
+ u16 mss;
+ u16 length;
+ u32 va_lo;
+ u32 va_hi;
+ struct pbl pbl[0]; /* Fragments */
+} __attribute__ ((packed));
+
+/* Register region size */
+#define BDX_REGS_SIZE 0x1000
+
+/* Registers from 0x0000-0x00fc were remapped to 0x4000-0x40fc */
+#define regTXD_CFG1_0 0x4000
+#define regRXF_CFG1_0 0x4010
+#define regRXD_CFG1_0 0x4020
+#define regTXF_CFG1_0 0x4030
+#define regTXD_CFG0_0 0x4040
+#define regRXF_CFG0_0 0x4050
+#define regRXD_CFG0_0 0x4060
+#define regTXF_CFG0_0 0x4070
+#define regTXD_WPTR_0 0x4080
+#define regRXF_WPTR_0 0x4090
+#define regRXD_WPTR_0 0x40A0
+#define regTXF_WPTR_0 0x40B0
+#define regTXD_RPTR_0 0x40C0
+#define regRXF_RPTR_0 0x40D0
+#define regRXD_RPTR_0 0x40E0
+#define regTXF_RPTR_0 0x40F0
+#define regTXF_RPTR_3 0x40FC
+
+/* hardware versioning */
+#define FW_VER 0x5010
+#define SROM_VER 0x5020
+#define FPGA_VER 0x5030
+#define FPGA_SEED 0x5040
+
+/* Registers from 0x0100-0x0150 were remapped to 0x5100-0x5150 */
+#define regISR regISR0
+#define regISR0 0x5100
+
+#define regIMR regIMR0
+#define regIMR0 0x5110
+
+#define regRDINTCM0 0x5120
+#define regRDINTCM2 0x5128
+
+#define regTDINTCM0 0x5130
+
+#define regISR_MSK0 0x5140
+
+#define regINIT_SEMAPHORE 0x5170
+#define regINIT_STATUS 0x5180
+
+#define regMAC_LNK_STAT 0x0200
+#define MAC_LINK_STAT 0x4 /* Link state */
+
+#define regGMAC_RXF_A 0x1240
+
+#define regUNC_MAC0_A 0x1250
+#define regUNC_MAC1_A 0x1260
+#define regUNC_MAC2_A 0x1270
+
+#define regVLAN_0 0x1800
+
+#define regMAX_FRAME_A 0x12C0
+
+#define regRX_MAC_MCST0 0x1A80
+#define regRX_MAC_MCST1 0x1A84
+#define MAC_MCST_NUM 15
+#define regRX_MCST_HASH0 0x1A00
+#define MAC_MCST_HASH_NUM 8
+
+#define regVPC 0x2300
+#define regVIC 0x2320
+#define regVGLB 0x2340
+
+#define regCLKPLL 0x5000
+
+/*for 10G only*/
+#define regREVISION 0x6000
+#define regSCRATCH 0x6004
+#define regCTRLST 0x6008
+#define regMAC_ADDR_0 0x600C
+#define regMAC_ADDR_1 0x6010
+#define regFRM_LENGTH 0x6014
+#define regPAUSE_QUANT 0x6018
+#define regRX_FIFO_SECTION 0x601C
+#define regTX_FIFO_SECTION 0x6020
+#define regRX_FULLNESS 0x6024
+#define regTX_FULLNESS 0x6028
+#define regHASHTABLE 0x602C
+#define regMDIO_ST 0x6030
+#define regMDIO_CTL 0x6034
+#define regMDIO_DATA 0x6038
+#define regMDIO_ADDR 0x603C
+
+#define regRST_PORT 0x7000
+#define regDIS_PORT 0x7010
+#define regRST_QU 0x7020
+#define regDIS_QU 0x7030
+
+#define regCTRLST_TX_ENA 0x0001
+#define regCTRLST_RX_ENA 0x0002
+#define regCTRLST_PRM_ENA 0x0010
+#define regCTRLST_PAD_ENA 0x0020
+
+#define regCTRLST_BASE (regCTRLST_PAD_ENA|regCTRLST_PRM_ENA)
+
+#define regRX_FLT 0x1400
+
+/* TXD TXF RXF RXD CONFIG 0x0000 --- 0x007c*/
+#define TX_RX_CFG1_BASE 0xffffffff /*0-31 */
+#define TX_RX_CFG0_BASE 0xfffff000 /*31:12 */
+#define TX_RX_CFG0_RSVD 0x0ffc /*11:2 */
+#define TX_RX_CFG0_SIZE 0x0003 /*1:0 */
+
+/* TXD TXF RXF RXD WRITE 0x0080 --- 0x00BC */
+#define TXF_WPTR_WR_PTR 0x7ff8 /*14:3 */
+
+/* TXD TXF RXF RXD READ 0x00CO --- 0x00FC */
+#define TXF_RPTR_RD_PTR 0x7ff8 /*14:3 */
+
+#define TXF_WPTR_MASK 0x7ff0 /* last 4 bits are dropped
+ * size is rounded to 16 */
+
+/* regISR 0x0100 */
+/* regIMR 0x0110 */
+#define IMR_INPROG 0x80000000 /*31 */
+#define IR_LNKCHG1 0x10000000 /*28 */
+#define IR_LNKCHG0 0x08000000 /*27 */
+#define IR_GPIO 0x04000000 /*26 */
+#define IR_RFRSH 0x02000000 /*25 */
+#define IR_RSVD 0x01000000 /*24 */
+#define IR_SWI 0x00800000 /*23 */
+#define IR_RX_FREE_3 0x00400000 /*22 */
+#define IR_RX_FREE_2 0x00200000 /*21 */
+#define IR_RX_FREE_1 0x00100000 /*20 */
+#define IR_RX_FREE_0 0x00080000 /*19 */
+#define IR_TX_FREE_3 0x00040000 /*18 */
+#define IR_TX_FREE_2 0x00020000 /*17 */
+#define IR_TX_FREE_1 0x00010000 /*16 */
+#define IR_TX_FREE_0 0x00008000 /*15 */
+#define IR_RX_DESC_3 0x00004000 /*14 */
+#define IR_RX_DESC_2 0x00002000 /*13 */
+#define IR_RX_DESC_1 0x00001000 /*12 */
+#define IR_RX_DESC_0 0x00000800 /*11 */
+#define IR_PSE 0x00000400 /*10 */
+#define IR_TMR3 0x00000200 /*9 */
+#define IR_TMR2 0x00000100 /*8 */
+#define IR_TMR1 0x00000080 /*7 */
+#define IR_TMR0 0x00000040 /*6 */
+#define IR_VNT 0x00000020 /*5 */
+#define IR_RxFL 0x00000010 /*4 */
+#define IR_SDPERR 0x00000008 /*3 */
+#define IR_TR 0x00000004 /*2 */
+#define IR_PCIE_LINK 0x00000002 /*1 */
+#define IR_PCIE_TOUT 0x00000001 /*0 */
+
+#define IR_EXTRA (IR_RX_FREE_0 | IR_LNKCHG0 | IR_PSE | \
+ IR_TMR0 | IR_PCIE_LINK | IR_PCIE_TOUT)
+#define IR_RUN (IR_EXTRA | IR_RX_DESC_0 | IR_TX_FREE_0)
+#define IR_ALL 0xfdfffff7
+
+#define IR_LNKCHG0_ofst 27
+
+#define GMAC_RX_FILTER_OSEN 0x1000 /* shared OS enable */
+#define GMAC_RX_FILTER_TXFC 0x0400 /* Tx flow control */
+#define GMAC_RX_FILTER_RSV0 0x0200 /* reserved */
+#define GMAC_RX_FILTER_FDA 0x0100 /* filter out direct address */
+#define GMAC_RX_FILTER_AOF 0x0080 /* accept over run */
+#define GMAC_RX_FILTER_ACF 0x0040 /* accept control frames */
+#define GMAC_RX_FILTER_ARUNT 0x0020 /* accept under run */
+#define GMAC_RX_FILTER_ACRC 0x0010 /* accept crc error */
+#define GMAC_RX_FILTER_AM 0x0008 /* accept multicast */
+#define GMAC_RX_FILTER_AB 0x0004 /* accept broadcast */
+#define GMAC_RX_FILTER_PRM 0x0001 /* [0:1] promiscous mode */
+
+#define MAX_FRAME_AB_VAL 0x3fff /* 13:0 */
+
+#define CLKPLL_PLLLKD 0x0200 /*9 */
+#define CLKPLL_RSTEND 0x0100 /*8 */
+#define CLKPLL_SFTRST 0x0001 /*0 */
+
+#define CLKPLL_LKD (CLKPLL_PLLLKD|CLKPLL_RSTEND)
+
+/*
+ * PCI-E Device Control Register (Offset 0x88)
+ * Source: Luxor Data Sheet, 7.1.3.3.3
+ */
+#define PCI_DEV_CTRL_REG 0x88
+#define GET_DEV_CTRL_MAXPL(x) GET_BITS_SHIFT(x, 3, 5)
+#define GET_DEV_CTRL_MRRS(x) GET_BITS_SHIFT(x, 3, 12)
+
+/*
+ * PCI-E Link Status Register (Offset 0x92)
+ * Source: Luxor Data Sheet, 7.1.3.3.7
+ */
+#define PCI_LINK_STATUS_REG 0x92
+#define GET_LINK_STATUS_LANES(x) GET_BITS_SHIFT(x, 6, 4)
+
+/* Debugging Macros */
+
+#define ERR(fmt, args...) printk(KERN_ERR fmt, ## args)
+#define DBG2(fmt, args...) \
+ printk(KERN_ERR "%s:%-5d: " fmt, __FUNCTION__, __LINE__, ## args)
+
+#define BDX_ASSERT(x) BUG_ON(x)
+
+#ifdef DEBUG
+
+#define ENTER do { \
+ printk(KERN_ERR "%s:%-5d: ENTER\n", __FUNCTION__, __LINE__); \
+} while (0)
+
+#define RET(args...) do { \
+ printk(KERN_ERR "%s:%-5d: RETURN\n", __FUNCTION__, __LINE__); \
+return args; } while (0)
+
+#define DBG(fmt, args...) \
+ printk(KERN_ERR "%s:%-5d: " fmt, __FUNCTION__, __LINE__, ## args)
+#else
+#define ENTER do { } while (0)
+#define RET(args...) return args
+#define DBG(fmt, args...) do { } while (0)
+#endif
+
+#endif /* _BDX__H */
diff --git a/drivers/net/tehuti_fw.h b/drivers/net/tehuti_fw.h
new file mode 100644
index 00000000000..2c603a8a438
--- /dev/null
+++ b/drivers/net/tehuti_fw.h
@@ -0,0 +1,10712 @@
+/*
+ * Tehuti Networks(R) Network Driver
+ * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/* Loading Firmware */
+/* INT_MEM Ver */
+static u32 s_firmLoad[] = {
+ 0x000f0002,
+ 0x40718000,
+ 0x0000002d,
+ 0xc0000000,
+ 0x000f0002,
+ 0x00718001,
+ 0x0000002d,
+ 0xc0800000,
+ 0x000f0002,
+ 0x00718002,
+ 0x0000002d,
+ 0xc1000000,
+ 0x000f0002,
+ 0x00718003,
+ 0x0000002d,
+ 0xc1800000,
+ 0x000f0002,
+ 0x00718004,
+ 0x0000002d,
+ 0xc2000000,
+ 0x000f0002,
+ 0x00718005,
+ 0x0000002d,
+ 0xc2800000,
+ 0x000f0002,
+ 0x00718006,
+ 0x0000002d,
+ 0xc3000000,
+ 0x000f0002,
+ 0x00718007,
+ 0x0000002d,
+ 0xc3800000,
+ 0x000f0002,
+ 0x00718008,
+ 0x0000002d,
+ 0xc4000000,
+ 0x000f0002,
+ 0x00718009,
+ 0x0000002d,
+ 0xc4800000,
+ 0x000f0002,
+ 0x0071800a,
+ 0x0000002d,
+ 0xc5000000,
+ 0x000f0002,
+ 0x0071800b,
+ 0x0000002d,
+ 0xc5800000,
+ 0x000f0002,
+ 0x0071800c,
+ 0x0000002d,
+ 0xc6000000,
+ 0x000f0002,
+ 0x0071800d,
+ 0x0000002d,
+ 0xc6800000,
+ 0x000f0002,
+ 0x0071800e,
+ 0x0000002d,
+ 0xc7000000,
+ 0x000f0002,
+ 0x0071800f,
+ 0x0000002d,
+ 0xc7800000,
+ 0x000f0002,
+ 0x00718010,
+ 0x0000002d,
+ 0xc8000000,
+ 0x000f0002,
+ 0x00718011,
+ 0x0000002d,
+ 0xc8800000,
+ 0x000f0002,
+ 0x00718012,
+ 0x0000002d,
+ 0xc9000000,
+ 0x000f0002,
+ 0x00718013,
+ 0x0000002d,
+ 0xc9800000,
+ 0x000f0002,
+ 0x00718014,
+ 0x0000002d,
+ 0xca000000,
+ 0x000f0002,
+ 0x00718015,
+ 0x0000002d,
+ 0xca800000,
+ 0x000f0002,
+ 0x00718016,
+ 0x0000002d,
+ 0xcb000000,
+ 0x000f0002,
+ 0x00718017,
+ 0x0000002d,
+ 0xcb800000,
+ 0x000f0002,
+ 0x00718018,
+ 0x0000002d,
+ 0xcc000000,
+ 0x000f0002,
+ 0x00718019,
+ 0x0000002d,
+ 0xcc800000,
+ 0x000f0002,
+ 0x0071801a,
+ 0x0000002d,
+ 0xcd000000,
+ 0x000f0002,
+ 0x0071801b,
+ 0x0000002d,
+ 0xcd800000,
+ 0x000f0002,
+ 0x0071801c,
+ 0x0000002d,
+ 0xce000000,
+ 0x000f0002,
+ 0x0071801d,
+ 0x0000002d,
+ 0xce800000,
+ 0x000f0002,
+ 0x0071801e,
+ 0x0000002d,
+ 0xcf000000,
+ 0x000f0002,
+ 0x0071801f,
+ 0x0000002d,
+ 0xcf800000,
+ 0x000f0002,
+ 0x00718020,
+ 0x0000002d,
+ 0xd0000000,
+ 0x000f0002,
+ 0x00718021,
+ 0x0000002d,
+ 0xd0800000,
+ 0x000f0002,
+ 0x00718022,
+ 0x0000002d,
+ 0xd1000000,
+ 0x000f0002,
+ 0x00718023,
+ 0x0000002d,
+ 0xd1800000,
+ 0x000f0002,
+ 0x00718024,
+ 0x0000002d,
+ 0xd2000000,
+ 0x000f0002,
+ 0x00718025,
+ 0x0000002d,
+ 0xd2800000,
+ 0x000f0002,
+ 0x00718026,
+ 0x0000002d,
+ 0xd3000000,
+ 0x000f0002,
+ 0x00718027,
+ 0x0000002d,
+ 0xd3800000,
+ 0x000f0002,
+ 0x00718028,
+ 0x0000002d,
+ 0xd4000000,
+ 0x000f0002,
+ 0x00718029,
+ 0x0000002d,
+ 0xd4800000,
+ 0x000f0002,
+ 0x0071802a,
+ 0x0000002d,
+ 0xd5000000,
+ 0x000f0002,
+ 0x0071802b,
+ 0x0000002d,
+ 0xd5800000,
+ 0x000f0002,
+ 0x0071802c,
+ 0x0000002d,
+ 0xd6000000,
+ 0x000f0002,
+ 0x0071802d,
+ 0x0000002d,
+ 0xd6800000,
+ 0x000f0002,
+ 0x0071802e,
+ 0x0000002d,
+ 0xd7000000,
+ 0x000f0002,
+ 0x0071802f,
+ 0x0000002d,
+ 0xd7800000,
+ 0x000f0002,
+ 0x00718030,
+ 0x0000002d,
+ 0xd8000000,
+ 0x000f0002,
+ 0x00718031,
+ 0x0000002d,
+ 0xd8800000,
+ 0x000f0002,
+ 0x00718032,
+ 0x0000002d,
+ 0xd9000000,
+ 0x000f0002,
+ 0x00718033,
+ 0x0000002d,
+ 0xd9800000,
+ 0x000f0002,
+ 0x00718034,
+ 0x0000002d,
+ 0xda000000,
+ 0x000f0002,
+ 0x00718035,
+ 0x0000002d,
+ 0xda800000,
+ 0x000f0002,
+ 0x00718036,
+ 0x0000002d,
+ 0xdb000000,
+ 0x000f0002,
+ 0x00718037,
+ 0x0000002d,
+ 0xdb800000,
+ 0x000f0002,
+ 0x00718038,
+ 0x0000007b,
+ 0xdd608000,
+ 0x000f0002,
+ 0x00718039,
+ 0x0000002d,
+ 0xdd000000,
+ 0x000f0002,
+ 0x0071803a,
+ 0x0000002d,
+ 0xdb800000,
+ 0x000f0002,
+ 0x0071803b,
+ 0x0000002d,
+ 0xdd000000,
+ 0x000f0002,
+ 0x0071803c,
+ 0x0000002d,
+ 0xdd000000,
+ 0x000f0002,
+ 0x0071803d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718040,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718041,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718042,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718043,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718044,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718045,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718046,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718047,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718048,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718049,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718050,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718051,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718052,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718053,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718054,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718055,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718056,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718057,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718058,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718059,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718060,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718061,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718062,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718063,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718064,
+ 0x0000002d,
+ 0xdb000000,
+ 0x000f0002,
+ 0x00718065,
+ 0x0000003f,
+ 0xdd000104,
+ 0x000f0002,
+ 0x00718066,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718067,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718068,
+ 0x0000003f,
+ 0xdd000804,
+ 0x000f0002,
+ 0x00718069,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071806a,
+ 0x0000003f,
+ 0xdd003004,
+ 0x000f0002,
+ 0x0071806b,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071806c,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071806d,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x0071806e,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071806f,
+ 0x0000003f,
+ 0xdd003d04,
+ 0x000f0002,
+ 0x00718070,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718071,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718072,
+ 0x0000003f,
+ 0xdd000704,
+ 0x000f0002,
+ 0x00718073,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718074,
+ 0x0000003f,
+ 0xdd002884,
+ 0x000f0002,
+ 0x00718075,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718076,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718077,
+ 0x0000003f,
+ 0xdd003704,
+ 0x000f0002,
+ 0x00718078,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718079,
+ 0x0000003f,
+ 0xdd002904,
+ 0x000f0002,
+ 0x0071807a,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071807b,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071807c,
+ 0x0000003f,
+ 0xdd04aa04,
+ 0x000f0002,
+ 0x0071807d,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071807e,
+ 0x0000003f,
+ 0xdd002804,
+ 0x000f0002,
+ 0x0071807f,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718080,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718081,
+ 0x0000003f,
+ 0xdd003104,
+ 0x000f0002,
+ 0x00718082,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718083,
+ 0x0000003f,
+ 0xdd002b84,
+ 0x000f0002,
+ 0x00718084,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718085,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718086,
+ 0x0000003f,
+ 0xdd01e404,
+ 0x000f0002,
+ 0x00718087,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718088,
+ 0x0000003f,
+ 0xd7800084,
+ 0x000f0002,
+ 0x00718089,
+ 0x0000003f,
+ 0xd7980001,
+ 0x000f0002,
+ 0x0071808a,
+ 0x00000059,
+ 0xd78037ef,
+ 0x000f0002,
+ 0x0071808b,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071808c,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071808d,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071808e,
+ 0x0000002d,
+ 0xd7d6027f,
+ 0x000f0002,
+ 0x0071808f,
+ 0x00000018,
+ 0x17ff0081,
+ 0x000f0002,
+ 0x00718090,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718091,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718092,
+ 0x0000002d,
+ 0xd7d800b8,
+ 0x000f0002,
+ 0x00718093,
+ 0x00000018,
+ 0x17eb0081,
+ 0x000f0002,
+ 0x00718094,
+ 0x0000003f,
+ 0xdd002904,
+ 0x000f0002,
+ 0x00718095,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718096,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718097,
+ 0x0000003f,
+ 0xdd04aa84,
+ 0x000f0002,
+ 0x00718098,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718099,
+ 0x0000003f,
+ 0xdd002b04,
+ 0x000f0002,
+ 0x0071809a,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071809b,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071809c,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x0071809d,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071809e,
+ 0x0000003f,
+ 0xdd002984,
+ 0x000f0002,
+ 0x0071809f,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180a0,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180a1,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x007180a2,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180a3,
+ 0x0000003f,
+ 0xdd002a04,
+ 0x000f0002,
+ 0x007180a4,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180a5,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180a6,
+ 0x0000003f,
+ 0xdd009184,
+ 0x000f0002,
+ 0x007180a7,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180a8,
+ 0x0000003f,
+ 0xd6801984,
+ 0x000f0002,
+ 0x007180a9,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007180aa,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007180ab,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007180ac,
+ 0x0000003f,
+ 0xdd002b04,
+ 0x000f0002,
+ 0x007180ad,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180ae,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180af,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x007180b0,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180b1,
+ 0x0000003f,
+ 0xdd002a84,
+ 0x000f0002,
+ 0x007180b2,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180b3,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180b4,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x007180b5,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180b6,
+ 0x0000003f,
+ 0xd6800c84,
+ 0x000f0002,
+ 0x007180b7,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007180b8,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007180b9,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007180ba,
+ 0x0000003f,
+ 0xdd002a84,
+ 0x000f0002,
+ 0x007180bb,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180bc,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180bd,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x007180be,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180bf,
+ 0x0000003f,
+ 0xd6800f84,
+ 0x000f0002,
+ 0x007180c0,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007180c1,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007180c2,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007180c3,
+ 0x0000003f,
+ 0xdd002a04,
+ 0x000f0002,
+ 0x007180c4,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180c5,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180c6,
+ 0x0000003f,
+ 0xdd001184,
+ 0x000f0002,
+ 0x007180c7,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180c8,
+ 0x0000003f,
+ 0xdd002884,
+ 0x000f0002,
+ 0x007180c9,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180ca,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180cb,
+ 0x0000003f,
+ 0xdd003784,
+ 0x000f0002,
+ 0x007180cc,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180cd,
+ 0x0000002d,
+ 0xd3800000,
+ 0x000f0002,
+ 0x007180ce,
+ 0x0000003f,
+ 0xd2003780,
+ 0x000f0002,
+ 0x007180cf,
+ 0x0000003f,
+ 0xd1800404,
+ 0x000f0002,
+ 0x007180d0,
+ 0x0000003f,
+ 0xd1840001,
+ 0x000f0002,
+ 0x007180d1,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180d2,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180d3,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180d4,
+ 0x0000003f,
+ 0xd17fff84,
+ 0x000f0002,
+ 0x007180d5,
+ 0x0000003f,
+ 0xd17fff81,
+ 0x000f0002,
+ 0x007180d6,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180d7,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180d8,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180d9,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180da,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180db,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180dc,
+ 0x0000003f,
+ 0xd6800784,
+ 0x000f0002,
+ 0x007180dd,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007180de,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007180df,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007180e0,
+ 0x00000049,
+ 0xdd003b63,
+ 0x000f0002,
+ 0x007180e1,
+ 0x00000059,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180e2,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180e3,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180e4,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180e5,
+ 0x0000002d,
+ 0xdd06027f,
+ 0x000f0002,
+ 0x007180e6,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x007180e7,
+ 0x00000045,
+ 0xdd003139,
+ 0x000f0002,
+ 0x007180e8,
+ 0x00000094,
+ 0x000b313b,
+ 0x000f0002,
+ 0x007180e9,
+ 0x00000094,
+ 0x0009313d,
+ 0x000f0002,
+ 0x007180ea,
+ 0x00000094,
+ 0x0007313f,
+ 0x000f0002,
+ 0x007180eb,
+ 0x00000094,
+ 0x00053b76,
+ 0x000f0002,
+ 0x007180ec,
+ 0x00000009,
+ 0xc1ed3d7a,
+ 0x000f0002,
+ 0x007180ed,
+ 0x0000003f,
+ 0xd200b780,
+ 0x000f0002,
+ 0x007180ee,
+ 0x0000003f,
+ 0xdd002884,
+ 0x000f0002,
+ 0x007180ef,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007180f0,
+ 0x00000069,
+ 0xdd003264,
+ 0x000f0002,
+ 0x007180f1,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007180f2,
+ 0x0000003f,
+ 0xd6800784,
+ 0x000f0002,
+ 0x007180f3,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007180f4,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007180f5,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007180f6,
+ 0x00000049,
+ 0xdd003b63,
+ 0x000f0002,
+ 0x007180f7,
+ 0x00000059,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007180f8,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180f9,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180fa,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180fb,
+ 0x0000002d,
+ 0xdd06027f,
+ 0x000f0002,
+ 0x007180fc,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x007180fd,
+ 0x00000045,
+ 0xdd00313a,
+ 0x000f0002,
+ 0x007180fe,
+ 0x00000018,
+ 0x1d2d3b76,
+ 0x000f0002,
+ 0x007180ff,
+ 0x00000045,
+ 0xdd00313c,
+ 0x000f0002,
+ 0x00718100,
+ 0x00000018,
+ 0x1d133b76,
+ 0x000f0002,
+ 0x00718101,
+ 0x00000045,
+ 0xdd00313e,
+ 0x000f0002,
+ 0x00718102,
+ 0x00000018,
+ 0x1d1b3b76,
+ 0x000f0002,
+ 0x00718103,
+ 0x0000003f,
+ 0xdd003004,
+ 0x000f0002,
+ 0x00718104,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718105,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718106,
+ 0x0000003f,
+ 0xdd000104,
+ 0x000f0002,
+ 0x00718107,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718108,
+ 0x00000009,
+ 0xc52d3d7a,
+ 0x000f0002,
+ 0x00718109,
+ 0x00000029,
+ 0xd2010064,
+ 0x000f0002,
+ 0x0071810a,
+ 0x0000003f,
+ 0xdd002884,
+ 0x000f0002,
+ 0x0071810b,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071810c,
+ 0x00000069,
+ 0xdd003264,
+ 0x000f0002,
+ 0x0071810d,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071810e,
+ 0x00000009,
+ 0xc2293d7a,
+ 0x000f0002,
+ 0x0071810f,
+ 0x00000029,
+ 0xd2000064,
+ 0x000f0002,
+ 0x00718110,
+ 0x0000003f,
+ 0xdd002884,
+ 0x000f0002,
+ 0x00718111,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718112,
+ 0x00000069,
+ 0xdd003264,
+ 0x000f0002,
+ 0x00718113,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718114,
+ 0x00000049,
+ 0xdd003b63,
+ 0x000f0002,
+ 0x00718115,
+ 0x00000059,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x00718116,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718117,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718118,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718119,
+ 0x0000002d,
+ 0xdd06027f,
+ 0x000f0002,
+ 0x0071811a,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x0071811b,
+ 0x00000045,
+ 0xdd00313a,
+ 0x000f0002,
+ 0x0071811c,
+ 0x00000018,
+ 0x1d0f3b76,
+ 0x000f0002,
+ 0x0071811d,
+ 0x0000003f,
+ 0xdd003004,
+ 0x000f0002,
+ 0x0071811e,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071811f,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718120,
+ 0x0000003f,
+ 0xdd000104,
+ 0x000f0002,
+ 0x00718121,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718122,
+ 0x00000009,
+ 0xc52d3d7a,
+ 0x000f0002,
+ 0x00718123,
+ 0x0000002d,
+ 0xd1080082,
+ 0x000f0002,
+ 0x00718124,
+ 0x00000008,
+ 0x23c33d7a,
+ 0x000f0002,
+ 0x00718125,
+ 0x00000049,
+ 0xd6003b0a,
+ 0x000f0002,
+ 0x00718126,
+ 0x0000003f,
+ 0xd3000004,
+ 0x000f0002,
+ 0x00718127,
+ 0x0000003f,
+ 0xd3040001,
+ 0x000f0002,
+ 0x00718128,
+ 0x0000002f,
+ 0xd6814085,
+ 0x000f0002,
+ 0x00718129,
+ 0x0000003f,
+ 0xd4ffff84,
+ 0x000f0002,
+ 0x0071812a,
+ 0x0000003f,
+ 0xd4800781,
+ 0x000f0002,
+ 0x0071812b,
+ 0x0000003f,
+ 0xd1ffff84,
+ 0x000f0002,
+ 0x0071812c,
+ 0x0000003f,
+ 0xd1800001,
+ 0x000f0002,
+ 0x0071812d,
+ 0x00000049,
+ 0xdd003666,
+ 0x000f0002,
+ 0x0071812e,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x0071812f,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x00718130,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x00718131,
+ 0x00000069,
+ 0xdd003b69,
+ 0x000f0002,
+ 0x00718132,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x00718133,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x00718134,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x00718135,
+ 0x00000069,
+ 0xdd003b69,
+ 0x000f0002,
+ 0x00718136,
+ 0x00000061,
+ 0xf600046c,
+ 0x000f0002,
+ 0x00718137,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x00718138,
+ 0x00000018,
+ 0x3d6b0081,
+ 0x000f0002,
+ 0x00718139,
+ 0x00000049,
+ 0xd600058b,
+ 0x000f0002,
+ 0x0071813a,
+ 0x0000002f,
+ 0xd6810106,
+ 0x000f0002,
+ 0x0071813b,
+ 0x0000002d,
+ 0xd2000000,
+ 0x000f0002,
+ 0x0071813c,
+ 0x00000021,
+ 0xd20000e4,
+ 0x000f0002,
+ 0x0071813d,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071813e,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x0071813f,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x00718140,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x00718141,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718142,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718143,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x00718144,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x00718145,
+ 0x0000002d,
+ 0xd1000000,
+ 0x000f0002,
+ 0x00718146,
+ 0x00000049,
+ 0xd17a33e4,
+ 0x000f0002,
+ 0x00718147,
+ 0x0000002f,
+ 0xd1710162,
+ 0x000f0002,
+ 0x00718148,
+ 0x0000002f,
+ 0xd1610162,
+ 0x000f0002,
+ 0x00718149,
+ 0x00000049,
+ 0xd14033e3,
+ 0x000f0002,
+ 0x0071814a,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071814b,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x0071814c,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x0071814d,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x0071814e,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x0071814f,
+ 0x00000069,
+ 0xd8003162,
+ 0x000f0002,
+ 0x00718150,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x00718151,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x00718152,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718153,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x00718154,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x00718155,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x00718156,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718157,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718158,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x00718159,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x0071815a,
+ 0x0000002d,
+ 0xd1000000,
+ 0x000f0002,
+ 0x0071815b,
+ 0x0000002d,
+ 0xd16c07e4,
+ 0x000f0002,
+ 0x0071815c,
+ 0x00000049,
+ 0xd14033e3,
+ 0x000f0002,
+ 0x0071815d,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071815e,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x0071815f,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x00718160,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x00718161,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718162,
+ 0x00000069,
+ 0xd8003162,
+ 0x000f0002,
+ 0x00718163,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x00718164,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x00718165,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718166,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x00718167,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x00718168,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x00718169,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x0071816a,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x0071816b,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x0071816c,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x0071816d,
+ 0x0000002d,
+ 0xd1000000,
+ 0x000f0002,
+ 0x0071816e,
+ 0x00000049,
+ 0xd17833e4,
+ 0x000f0002,
+ 0x0071816f,
+ 0x0000002f,
+ 0xd1710162,
+ 0x000f0002,
+ 0x00718170,
+ 0x0000002f,
+ 0xd1610162,
+ 0x000f0002,
+ 0x00718171,
+ 0x00000049,
+ 0xd14033e3,
+ 0x000f0002,
+ 0x00718172,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718173,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x00718174,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x00718175,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x00718176,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718177,
+ 0x00000069,
+ 0xd8003162,
+ 0x000f0002,
+ 0x00718178,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x00718179,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x0071817a,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x0071817b,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x0071817c,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x0071817d,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x0071817e,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x0071817f,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x00718180,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x00718181,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x00718182,
+ 0x0000002d,
+ 0xd1000000,
+ 0x000f0002,
+ 0x00718183,
+ 0x0000002d,
+ 0xd16807e4,
+ 0x000f0002,
+ 0x00718184,
+ 0x00000049,
+ 0xd14033e3,
+ 0x000f0002,
+ 0x00718185,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718186,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x00718187,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x00718188,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x00718189,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x0071818a,
+ 0x00000069,
+ 0xd8003162,
+ 0x000f0002,
+ 0x0071818b,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x0071818c,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x0071818d,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x0071818e,
+ 0x00000008,
+ 0x22790081,
+ 0x000f0002,
+ 0x0071818f,
+ 0x00000049,
+ 0xd600060c,
+ 0x000f0002,
+ 0x00718190,
+ 0x0000002f,
+ 0xd6810106,
+ 0x000f0002,
+ 0x00718191,
+ 0x0000003f,
+ 0xd4800002,
+ 0x000f0002,
+ 0x00718192,
+ 0x0000003f,
+ 0xd4800084,
+ 0x000f0002,
+ 0x00718193,
+ 0x0000003f,
+ 0xd5000102,
+ 0x000f0002,
+ 0x00718194,
+ 0x0000003f,
+ 0xd5000184,
+ 0x000f0002,
+ 0x00718195,
+ 0x0000003f,
+ 0xd5800202,
+ 0x000f0002,
+ 0x00718196,
+ 0x0000003f,
+ 0xd5800204,
+ 0x000f0002,
+ 0x00718197,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718198,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x00718199,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x0071819a,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x0071819b,
+ 0x00000069,
+ 0xd80034e9,
+ 0x000f0002,
+ 0x0071819c,
+ 0x00000069,
+ 0xd800356a,
+ 0x000f0002,
+ 0x0071819d,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x0071819e,
+ 0x00000031,
+ 0xd600016c,
+ 0x000f0002,
+ 0x0071819f,
+ 0x00000041,
+ 0xd48034eb,
+ 0x000f0002,
+ 0x007181a0,
+ 0x00000041,
+ 0xd500356b,
+ 0x000f0002,
+ 0x007181a1,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007181a2,
+ 0x00000018,
+ 0x37eb0081,
+ 0x000f0002,
+ 0x007181a3,
+ 0x00000049,
+ 0xd6003b0d,
+ 0x000f0002,
+ 0x007181a4,
+ 0x00000049,
+ 0xd6803b07,
+ 0x000f0002,
+ 0x007181a5,
+ 0x0000002d,
+ 0xd1000000,
+ 0x000f0002,
+ 0x007181a6,
+ 0x00000049,
+ 0xdd003666,
+ 0x000f0002,
+ 0x007181a7,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181a8,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181a9,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181aa,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181ab,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181ac,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181ad,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181ae,
+ 0x00000069,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x007181af,
+ 0x00000061,
+ 0xf600046c,
+ 0x000f0002,
+ 0x007181b0,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007181b1,
+ 0x00000018,
+ 0x37eb0081,
+ 0x000f0002,
+ 0x007181b2,
+ 0x00000049,
+ 0xd6003b0e,
+ 0x000f0002,
+ 0x007181b3,
+ 0x00000049,
+ 0xd6803b08,
+ 0x000f0002,
+ 0x007181b4,
+ 0x00000049,
+ 0xd5803b09,
+ 0x000f0002,
+ 0x007181b5,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181b6,
+ 0x0000002d,
+ 0xdd06017f,
+ 0x000f0002,
+ 0x007181b7,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x007181b8,
+ 0x00000049,
+ 0xd800366c,
+ 0x000f0002,
+ 0x007181b9,
+ 0x00000069,
+ 0xd80035eb,
+ 0x000f0002,
+ 0x007181ba,
+ 0x00000069,
+ 0xd80033e7,
+ 0x000f0002,
+ 0x007181bb,
+ 0x00000069,
+ 0xd80037ef,
+ 0x000f0002,
+ 0x007181bc,
+ 0x00000041,
+ 0xd60007ec,
+ 0x000f0002,
+ 0x007181bd,
+ 0x00000041,
+ 0xd580086b,
+ 0x000f0002,
+ 0x007181be,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007181bf,
+ 0x00000018,
+ 0x37ed0081,
+ 0x000f0002,
+ 0x007181c0,
+ 0x0000003f,
+ 0xd4ffff80,
+ 0x000f0002,
+ 0x007181c1,
+ 0x0000003f,
+ 0xd5020004,
+ 0x000f0002,
+ 0x007181c2,
+ 0x0000003f,
+ 0xd5180001,
+ 0x000f0002,
+ 0x007181c3,
+ 0x00000049,
+ 0xdd003b6a,
+ 0x000f0002,
+ 0x007181c4,
+ 0x00000069,
+ 0xdd003b69,
+ 0x000f0002,
+ 0x007181c5,
+ 0x00000069,
+ 0xdd003b69,
+ 0x000f0002,
+ 0x007181c6,
+ 0x00000021,
+ 0xd50000ea,
+ 0x000f0002,
+ 0x007181c7,
+ 0x00000049,
+ 0xdd0e3b6a,
+ 0x000f0002,
+ 0x007181c8,
+ 0x00000035,
+ 0xd104007a,
+ 0x000f0002,
+ 0x007181c9,
+ 0x00000018,
+ 0x37f50081,
+ 0x000f0002,
+ 0x007181ca,
+ 0x0000003f,
+ 0xd4ffff80,
+ 0x000f0002,
+ 0x007181cb,
+ 0x0000003f,
+ 0xd5040004,
+ 0x000f0002,
+ 0x007181cc,
+ 0x0000003f,
+ 0xd5180001,
+ 0x000f0002,
+ 0x007181cd,
+ 0x00000069,
+ 0xdd003b69,
+ 0x000f0002,
+ 0x007181ce,
+ 0x00000069,
+ 0xdd003b69,
+ 0x000f0002,
+ 0x007181cf,
+ 0x00000049,
+ 0xdd003b6a,
+ 0x000f0002,
+ 0x007181d0,
+ 0x00000051,
+ 0xf50000ea,
+ 0x000f0002,
+ 0x007181d1,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181d2,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181d3,
+ 0x00000049,
+ 0xdd0e3b6a,
+ 0x000f0002,
+ 0x007181d4,
+ 0x00000035,
+ 0xd104807a,
+ 0x000f0002,
+ 0x007181d5,
+ 0x00000018,
+ 0x37f50081,
+ 0x000f0002,
+ 0x007181d6,
+ 0x0000003f,
+ 0xc77f7f04,
+ 0x000f0002,
+ 0x007181d7,
+ 0x0000003f,
+ 0xc77f7f01,
+ 0x000f0002,
+ 0x007181d8,
+ 0x0000003f,
+ 0xd6804000,
+ 0x000f0002,
+ 0x007181d9,
+ 0x0000003f,
+ 0xd103c000,
+ 0x000f0002,
+ 0x007181da,
+ 0x00000025,
+ 0xde2000e2,
+ 0x000f0002,
+ 0x007181db,
+ 0x00000049,
+ 0xde80274e,
+ 0x000f0002,
+ 0x007181dc,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181dd,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181de,
+ 0x00000035,
+ 0xd10000e2,
+ 0x000f0002,
+ 0x007181df,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007181e0,
+ 0x00000018,
+ 0x37f50081,
+ 0x000f0002,
+ 0x007181e1,
+ 0x0000003f,
+ 0xdd003004,
+ 0x000f0002,
+ 0x007181e2,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007181e3,
+ 0x00000069,
+ 0xdd001d3a,
+ 0x000f0002,
+ 0x007181e4,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007181e5,
+ 0x0000007d,
+ 0xc760a713,
+ 0x000f0002,
+ 0x007181e6,
+ 0x00000031,
+ 0xc0800041,
+ 0x000f0002,
+ 0x007181e7,
+ 0x00000031,
+ 0xc4000048,
+ 0x000f0002,
+ 0x007181e8,
+ 0x00000031,
+ 0xc2800045,
+ 0x000f0002,
+ 0x007181e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f4,
+ 0x0000002d,
+ 0xdb000000,
+ 0x000f0002,
+ 0x007181f5,
+ 0x0000003f,
+ 0xdd003004,
+ 0x000f0002,
+ 0x007181f6,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007181f7,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007181f8,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x007181f9,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007181fa,
+ 0x0000002d,
+ 0xd3800000,
+ 0x000f0002,
+ 0x007181fb,
+ 0x0000003f,
+ 0xdd000404,
+ 0x000f0002,
+ 0x007181fc,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007181fd,
+ 0x00000069,
+ 0xdd000a14,
+ 0x000f0002,
+ 0x007181fe,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x007181ff,
+ 0x00000049,
+ 0xd1043394,
+ 0x000f0002,
+ 0x00718200,
+ 0x0000003f,
+ 0xdd000484,
+ 0x000f0002,
+ 0x00718201,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718202,
+ 0x00000069,
+ 0xdd003162,
+ 0x000f0002,
+ 0x00718203,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718204,
+ 0x0000003f,
+ 0xdd000504,
+ 0x000f0002,
+ 0x00718205,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718206,
+ 0x00000069,
+ 0xdd000a95,
+ 0x000f0002,
+ 0x00718207,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718208,
+ 0x00000049,
+ 0xd1043395,
+ 0x000f0002,
+ 0x00718209,
+ 0x0000003f,
+ 0xdd000584,
+ 0x000f0002,
+ 0x0071820a,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071820b,
+ 0x00000069,
+ 0xdd003162,
+ 0x000f0002,
+ 0x0071820c,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071820d,
+ 0x0000003f,
+ 0xdd000604,
+ 0x000f0002,
+ 0x0071820e,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071820f,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718210,
+ 0x0000003f,
+ 0xdd000084,
+ 0x000f0002,
+ 0x00718211,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718212,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718213,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718214,
+ 0x00000069,
+ 0xdd000b16,
+ 0x000f0002,
+ 0x00718215,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718216,
+ 0x0000003f,
+ 0xdd001004,
+ 0x000f0002,
+ 0x00718217,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718218,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718219,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x0071821a,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071821b,
+ 0x0000003f,
+ 0xdd001084,
+ 0x000f0002,
+ 0x0071821c,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071821d,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071821e,
+ 0x0000003f,
+ 0xdd018004,
+ 0x000f0002,
+ 0x0071821f,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718220,
+ 0x0000003f,
+ 0xdd001104,
+ 0x000f0002,
+ 0x00718221,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718222,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718223,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718224,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718225,
+ 0x0000003f,
+ 0xdd001184,
+ 0x000f0002,
+ 0x00718226,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718227,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718228,
+ 0x0000003f,
+ 0xdd160004,
+ 0x000f0002,
+ 0x00718229,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071822a,
+ 0x0000003f,
+ 0xdd001204,
+ 0x000f0002,
+ 0x0071822b,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071822c,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071822d,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x0071822e,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071822f,
+ 0x0000003f,
+ 0xdd001284,
+ 0x000f0002,
+ 0x00718230,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718231,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718232,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718233,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718234,
+ 0x0000003f,
+ 0xdd001304,
+ 0x000f0002,
+ 0x00718235,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718236,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718237,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718238,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718239,
+ 0x0000003f,
+ 0xdd001384,
+ 0x000f0002,
+ 0x0071823a,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071823b,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071823c,
+ 0x0000003f,
+ 0xdd050004,
+ 0x000f0002,
+ 0x0071823d,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071823e,
+ 0x0000003f,
+ 0xdd002004,
+ 0x000f0002,
+ 0x0071823f,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718240,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718241,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718242,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718243,
+ 0x0000003f,
+ 0xdd002084,
+ 0x000f0002,
+ 0x00718244,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718245,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718246,
+ 0x0000003f,
+ 0xdd019004,
+ 0x000f0002,
+ 0x00718247,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718248,
+ 0x0000003f,
+ 0xdd002104,
+ 0x000f0002,
+ 0x00718249,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071824a,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071824b,
+ 0x0000003f,
+ 0xdd000084,
+ 0x000f0002,
+ 0x0071824c,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071824d,
+ 0x0000003f,
+ 0xdd002184,
+ 0x000f0002,
+ 0x0071824e,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071824f,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718250,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718251,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718252,
+ 0x0000003f,
+ 0xdd002204,
+ 0x000f0002,
+ 0x00718253,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718254,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718255,
+ 0x0000003f,
+ 0xdd000284,
+ 0x000f0002,
+ 0x00718256,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718257,
+ 0x0000003f,
+ 0xdd002284,
+ 0x000f0002,
+ 0x00718258,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718259,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071825a,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x0071825b,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071825c,
+ 0x0000003f,
+ 0xdd002304,
+ 0x000f0002,
+ 0x0071825d,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071825e,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071825f,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718260,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718261,
+ 0x0000003f,
+ 0xdd001804,
+ 0x000f0002,
+ 0x00718262,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718263,
+ 0x00000069,
+ 0xdd000b97,
+ 0x000f0002,
+ 0x00718264,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718265,
+ 0x00000049,
+ 0xd1043397,
+ 0x000f0002,
+ 0x00718266,
+ 0x0000003f,
+ 0xdd001884,
+ 0x000f0002,
+ 0x00718267,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718268,
+ 0x00000069,
+ 0xdd003162,
+ 0x000f0002,
+ 0x00718269,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071826a,
+ 0x0000003f,
+ 0xdd001904,
+ 0x000f0002,
+ 0x0071826b,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071826c,
+ 0x00000069,
+ 0xdd000c18,
+ 0x000f0002,
+ 0x0071826d,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071826e,
+ 0x00000049,
+ 0xd1043398,
+ 0x000f0002,
+ 0x0071826f,
+ 0x0000003f,
+ 0xdd001984,
+ 0x000f0002,
+ 0x00718270,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718271,
+ 0x00000069,
+ 0xdd003162,
+ 0x000f0002,
+ 0x00718272,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718273,
+ 0x0000003f,
+ 0xdd001a04,
+ 0x000f0002,
+ 0x00718274,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718275,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718276,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x00718277,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718278,
+ 0x0000003f,
+ 0xdd001a84,
+ 0x000f0002,
+ 0x00718279,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071827a,
+ 0x00000069,
+ 0xdd000b16,
+ 0x000f0002,
+ 0x0071827b,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071827c,
+ 0x0000003f,
+ 0xdd001c04,
+ 0x000f0002,
+ 0x0071827d,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071827e,
+ 0x00000069,
+ 0xdd000c99,
+ 0x000f0002,
+ 0x0071827f,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718280,
+ 0x0000003f,
+ 0xdd001c84,
+ 0x000f0002,
+ 0x00718281,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718282,
+ 0x00000069,
+ 0xdd000d1a,
+ 0x000f0002,
+ 0x00718283,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718284,
+ 0x0000003f,
+ 0xdd001d04,
+ 0x000f0002,
+ 0x00718285,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718286,
+ 0x00000069,
+ 0xdd000d9b,
+ 0x000f0002,
+ 0x00718287,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718288,
+ 0x00000049,
+ 0xd104339b,
+ 0x000f0002,
+ 0x00718289,
+ 0x0000003f,
+ 0xdd001d84,
+ 0x000f0002,
+ 0x0071828a,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071828b,
+ 0x00000069,
+ 0xdd003162,
+ 0x000f0002,
+ 0x0071828c,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x0071828d,
+ 0x0000003f,
+ 0xdd001e04,
+ 0x000f0002,
+ 0x0071828e,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071828f,
+ 0x00000069,
+ 0xdd000e1c,
+ 0x000f0002,
+ 0x00718290,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718291,
+ 0x0000003f,
+ 0xdd000104,
+ 0x000f0002,
+ 0x00718292,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x00718293,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718294,
+ 0x0000003f,
+ 0xdd000f04,
+ 0x000f0002,
+ 0x00718295,
+ 0x00000069,
+ 0xdd003d7a,
+ 0x000f0002,
+ 0x00718296,
+ 0x0000007d,
+ 0xc760a713,
+ 0x000f0002,
+ 0x00718297,
+ 0x00000031,
+ 0xc0800041,
+ 0x000f0002,
+ 0x00718298,
+ 0x00000031,
+ 0xc4000048,
+ 0x000f0002,
+ 0x00718299,
+ 0x00000031,
+ 0xc2800045,
+ 0x000f0002,
+ 0x0071829a,
+ 0x00000031,
+ 0xd680006d,
+/* BRDX_INIT_SDRAM */
+ 0x000f000f,
+ 0x00700064,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000040,
+ 0x00000100,
+ 0x00000400,
+ 0x00000064,
+ 0x00000054,
+ 0x00000000,
+ 0x00002400,
+ 0x00002800,
+ 0x00000400,
+ 0x00002880,
+ 0x00000180,
+ 0x00000003,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000051,
+ 0x0000017d,
+ 0x00000008,
+ 0x00000051,
+ 0x0000005d,
+ 0x00000000,
+ 0x00000009,
+ 0x00005000,
+ 0x00000000,
+ 0x00000000,
+/* BRDX_INIT */
+ 0x000f000f,
+ 0x007001f4,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000040,
+ 0x00000100,
+ 0x00000400,
+ 0x00000064,
+ 0x00000054,
+ 0x00000000,
+ 0x00002400,
+ 0x00002800,
+ 0x00000400,
+ 0x00002880,
+ 0x00000180,
+ 0x00000003,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000051,
+ 0x0000017d,
+ 0x00000008,
+ 0x00000051,
+ 0x0000005d,
+ 0x00000000,
+ 0x00000009,
+ 0x00005000,
+ 0x00000000,
+ 0x00000000,
+/* ZERO_INIT */
+ 0x000f0002,
+ 0x00700000,
+ 0x00000001,
+ 0x00000000,
+/* ZERO_INIT */
+ 0x000f0002,
+ 0x00700000,
+ 0x00000001,
+ 0x00000000,
+/* Loading operational Firmware */
+ 0x000f0002,
+ 0x00718000,
+ 0x00000025,
+ 0xdd0e0002,
+ 0x000f0002,
+ 0x00718001,
+ 0x00000004,
+ 0x01d13b76,
+ 0x000f0002,
+ 0x00718002,
+ 0x00000025,
+ 0xdd0e0082,
+ 0x000f0002,
+ 0x00718003,
+ 0x00000004,
+ 0x02893b76,
+ 0x000f0002,
+ 0x00718004,
+ 0x00000025,
+ 0xdd0e0102,
+ 0x000f0002,
+ 0x00718005,
+ 0x00000004,
+ 0x02853b76,
+ 0x000f0002,
+ 0x00718006,
+ 0x00000025,
+ 0xdd0e0182,
+ 0x000f0002,
+ 0x00718007,
+ 0x00000004,
+ 0x03fd3b76,
+ 0x000f0002,
+ 0x00718008,
+ 0x00000009,
+ 0xcf813b76,
+ 0x000f0002,
+ 0x00718009,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071800a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071800b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071800c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071800d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071800e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071800f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718010,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718011,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718012,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718013,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718014,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718015,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718016,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718017,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718018,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718019,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071801a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071801b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071801c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071801d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071801e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071801f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718020,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718021,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718022,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718023,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718024,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718025,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718026,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718027,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718028,
+ 0x00000049,
+ 0xc0003b00,
+ 0x000f0002,
+ 0x00718029,
+ 0x00000049,
+ 0xc0803b02,
+ 0x000f0002,
+ 0x0071802a,
+ 0x00000049,
+ 0xc1003b03,
+ 0x000f0002,
+ 0x0071802b,
+ 0x00000049,
+ 0xc1803b04,
+ 0x000f0002,
+ 0x0071802c,
+ 0x00000029,
+ 0xdf600076,
+ 0x000f0002,
+ 0x0071802d,
+ 0x00000049,
+ 0xdf443b7d,
+ 0x000f0002,
+ 0x0071802e,
+ 0x00000079,
+ 0xfd609076,
+ 0x000f0002,
+ 0x0071802f,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718030,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718031,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718032,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718033,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718034,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718035,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718036,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718037,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718038,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718039,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071803f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718040,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718041,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718042,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718043,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718044,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718045,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718046,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718047,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718048,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718049,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071804f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718050,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718051,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718052,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718053,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718054,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718055,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718056,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718057,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718058,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718059,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071805f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718060,
+ 0x0000003f,
+ 0xdf000003,
+ 0x000f0002,
+ 0x00718061,
+ 0x0000002d,
+ 0xdde00f81,
+ 0x000f0002,
+ 0x00718062,
+ 0x0000003f,
+ 0xdd800283,
+ 0x000f0002,
+ 0x00718063,
+ 0x0000002d,
+ 0xdd040180,
+ 0x000f0002,
+ 0x00718064,
+ 0x0000007d,
+ 0xfd150080,
+ 0x000f0002,
+ 0x00718065,
+ 0x0000007a,
+ 0x10203b76,
+ 0x000f0002,
+ 0x00718066,
+ 0x0000007a,
+ 0x30207b76,
+ 0x000f0002,
+ 0x00718067,
+ 0x00000021,
+ 0xd0240060,
+ 0x000f0002,
+ 0x00718068,
+ 0x0000003f,
+ 0xdd000104,
+ 0x000f0002,
+ 0x00718069,
+ 0x0000003f,
+ 0xdd400281,
+ 0x000f0002,
+ 0x0071806a,
+ 0x00000079,
+ 0xdd31bb03,
+ 0x000f0002,
+ 0x0071806b,
+ 0x00000079,
+ 0xdd31fb04,
+ 0x000f0002,
+ 0x0071806c,
+ 0x00000079,
+ 0xdd31bb76,
+ 0x000f0002,
+ 0x0071806d,
+ 0x00000079,
+ 0xdd31fb76,
+ 0x000f0002,
+ 0x0071806e,
+ 0x00000079,
+ 0xfd210101,
+ 0x000f0002,
+ 0x0071806f,
+ 0x0000007d,
+ 0xfd2b4081,
+ 0x000f0002,
+ 0x00718070,
+ 0x00000040,
+ 0x3d003002,
+ 0x000f0002,
+ 0x00718071,
+ 0x00000048,
+ 0x1d003b02,
+ 0x000f0002,
+ 0x00718072,
+ 0x00000079,
+ 0xdd217b76,
+ 0x000f0002,
+ 0x00718073,
+ 0x0000002d,
+ 0xdd04057f,
+ 0x000f0002,
+ 0x00718074,
+ 0x00000018,
+ 0x3d7f3b76,
+ 0x000f0002,
+ 0x00718075,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718076,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718077,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718078,
+ 0x00000021,
+ 0xe3371f76,
+ 0x000f0002,
+ 0x00718079,
+ 0x00000049,
+ 0xdd003b79,
+ 0x000f0002,
+ 0x0071807a,
+ 0x00000079,
+ 0xdd21bb76,
+ 0x000f0002,
+ 0x0071807b,
+ 0x00000049,
+ 0xdd003b79,
+ 0x000f0002,
+ 0x0071807c,
+ 0x00000079,
+ 0xdd21bb76,
+ 0x000f0002,
+ 0x0071807d,
+ 0x00000049,
+ 0xdd003b79,
+ 0x000f0002,
+ 0x0071807e,
+ 0x00000079,
+ 0xdd21bb76,
+ 0x000f0002,
+ 0x0071807f,
+ 0x00000079,
+ 0xfd609076,
+ 0x000f0002,
+ 0x00718080,
+ 0x00000079,
+ 0xdd21fb76,
+ 0x000f0002,
+ 0x00718081,
+ 0x0000003f,
+ 0xdf000083,
+ 0x000f0002,
+ 0x00718082,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718083,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718084,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718085,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718086,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718087,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718088,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718089,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071808a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071808b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071808c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071808d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071808e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071808f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718090,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718091,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718092,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718093,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718094,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718095,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718096,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718097,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718098,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718099,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071809a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071809b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071809c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071809d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071809e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071809f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180a0,
+ 0x0000002d,
+ 0xd0080803,
+ 0x000f0002,
+ 0x007180a1,
+ 0x00000008,
+ 0x21b5fb76,
+ 0x000f0002,
+ 0x007180a2,
+ 0x00000079,
+ 0xdd010081,
+ 0x000f0002,
+ 0x007180a3,
+ 0x00000079,
+ 0xdd018102,
+ 0x000f0002,
+ 0x007180a4,
+ 0x0000007d,
+ 0xfd018083,
+ 0x000f0002,
+ 0x007180a5,
+ 0x00000079,
+ 0xd0903b76,
+ 0x000f0002,
+ 0x007180a6,
+ 0x00000049,
+ 0xd0583b7a,
+ 0x000f0002,
+ 0x007180a7,
+ 0x00000049,
+ 0xd2043b00,
+ 0x000f0002,
+ 0x007180a8,
+ 0x0000003d,
+ 0xdd400003,
+ 0x000f0002,
+ 0x007180a9,
+ 0x00000024,
+ 0x32000264,
+ 0x000f0002,
+ 0x007180aa,
+ 0x0000003d,
+ 0xdd7ff803,
+ 0x000f0002,
+ 0x007180ab,
+ 0x00000029,
+ 0xd020017a,
+ 0x000f0002,
+ 0x007180ac,
+ 0x00000049,
+ 0xd0a43b0e,
+ 0x000f0002,
+ 0x007180ad,
+ 0x0000002d,
+ 0xdd0442ff,
+ 0x000f0002,
+ 0x007180ae,
+ 0x00000018,
+ 0x3d7f3b76,
+ 0x000f0002,
+ 0x007180af,
+ 0x0000002d,
+ 0xdd060082,
+ 0x000f0002,
+ 0x007180b0,
+ 0x00000038,
+ 0x300001e0,
+ 0x000f0002,
+ 0x007180b1,
+ 0x00000039,
+ 0xd0000160,
+ 0x000f0002,
+ 0x007180b2,
+ 0x00000079,
+ 0xd1b13b7c,
+ 0x000f0002,
+ 0x007180b3,
+ 0x0000002d,
+ 0xdde00fe3,
+ 0x000f0002,
+ 0x007180b4,
+ 0x00000049,
+ 0xd08030e4,
+ 0x000f0002,
+ 0x007180b5,
+ 0x00000079,
+ 0xdd317b7c,
+ 0x000f0002,
+ 0x007180b6,
+ 0x00000079,
+ 0xdd313b7c,
+ 0x000f0002,
+ 0x007180b7,
+ 0x0000007d,
+ 0xfd374082,
+ 0x000f0002,
+ 0x007180b8,
+ 0x00000008,
+ 0x017d3b76,
+ 0x000f0002,
+ 0x007180b9,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180ba,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180bb,
+ 0x00000049,
+ 0xdd000387,
+ 0x000f0002,
+ 0x007180bc,
+ 0x00000079,
+ 0xdd310408,
+ 0x000f0002,
+ 0x007180bd,
+ 0x00000079,
+ 0xdd317d7a,
+ 0x000f0002,
+ 0x007180be,
+ 0x00000049,
+ 0xd3003b7c,
+ 0x000f0002,
+ 0x007180bf,
+ 0x00000079,
+ 0xd381bb7c,
+ 0x000f0002,
+ 0x007180c0,
+ 0x0000007f,
+ 0xd101b27c,
+ 0x000f0002,
+ 0x007180c1,
+ 0x00000048,
+ 0x51003264,
+ 0x000f0002,
+ 0x007180c2,
+ 0x0000003d,
+ 0xdd400003,
+ 0x000f0002,
+ 0x007180c3,
+ 0x00000008,
+ 0x01953162,
+ 0x000f0002,
+ 0x007180c4,
+ 0x00000021,
+ 0xd3000666,
+ 0x000f0002,
+ 0x007180c5,
+ 0x00000020,
+ 0x538000e7,
+ 0x000f0002,
+ 0x007180c6,
+ 0x0000003f,
+ 0xdd000800,
+ 0x000f0002,
+ 0x007180c7,
+ 0x00000079,
+ 0xdd01b366,
+ 0x000f0002,
+ 0x007180c8,
+ 0x00000079,
+ 0xdd01b3e7,
+ 0x000f0002,
+ 0x007180c9,
+ 0x00000075,
+ 0xf1018662,
+ 0x000f0002,
+ 0x007180ca,
+ 0x00000075,
+ 0xd201b164,
+ 0x000f0002,
+ 0x007180cb,
+ 0x00000078,
+ 0x1d007b76,
+ 0x000f0002,
+ 0x007180cc,
+ 0x00000025,
+ 0xdd0001e3,
+ 0x000f0002,
+ 0x007180cd,
+ 0x00000008,
+ 0x01b13162,
+ 0x000f0002,
+ 0x007180ce,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180cf,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180d0,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180d1,
+ 0x00000021,
+ 0xe3379f63,
+ 0x000f0002,
+ 0x007180d2,
+ 0x00000049,
+ 0xd3003b7c,
+ 0x000f0002,
+ 0x007180d3,
+ 0x00000079,
+ 0xd381bb7c,
+ 0x000f0002,
+ 0x007180d4,
+ 0x0000007f,
+ 0xd101b27c,
+ 0x000f0002,
+ 0x007180d5,
+ 0x00000048,
+ 0x51003264,
+ 0x000f0002,
+ 0x007180d6,
+ 0x00000075,
+ 0xd201b164,
+ 0x000f0002,
+ 0x007180d7,
+ 0x00000078,
+ 0x1d007b76,
+ 0x000f0002,
+ 0x007180d8,
+ 0x0000003f,
+ 0xdd000004,
+ 0x000f0002,
+ 0x007180d9,
+ 0x00000079,
+ 0xdd01c081,
+ 0x000f0002,
+ 0x007180da,
+ 0x00000079,
+ 0xfd609076,
+ 0x000f0002,
+ 0x007180db,
+ 0x0000002d,
+ 0xdd080803,
+ 0x000f0002,
+ 0x007180dc,
+ 0x00000078,
+ 0x3d01c081,
+ 0x000f0002,
+ 0x007180dd,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007180de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007180e8,
+ 0x00000049,
+ 0xd18e3b03,
+ 0x000f0002,
+ 0x007180e9,
+ 0x0000002f,
+ 0xd18100e3,
+ 0x000f0002,
+ 0x007180ea,
+ 0x0000003f,
+ 0xd1801803,
+ 0x000f0002,
+ 0x007180eb,
+ 0x00000049,
+ 0xd1043b03,
+ 0x000f0002,
+ 0x007180ec,
+ 0x0000003f,
+ 0xdd800203,
+ 0x000f0002,
+ 0x007180ed,
+ 0x00000049,
+ 0xd2043b02,
+ 0x000f0002,
+ 0x007180ee,
+ 0x00000049,
+ 0xd2843b00,
+ 0x000f0002,
+ 0x007180ef,
+ 0x00000025,
+ 0xdd0000e2,
+ 0x000f0002,
+ 0x007180f0,
+ 0x00000094,
+ 0x00134162,
+ 0x000f0002,
+ 0x007180f1,
+ 0x00000094,
+ 0x000b4362,
+ 0x000f0002,
+ 0x007180f2,
+ 0x00000094,
+ 0x001548e2,
+ 0x000f0002,
+ 0x007180f3,
+ 0x00000094,
+ 0x001b4962,
+ 0x000f0002,
+ 0x007180f4,
+ 0x00000094,
+ 0x002f4076,
+ 0x000f0002,
+ 0x007180f5,
+ 0x00000009,
+ 0xcf813d7a,
+ 0x000f0002,
+ 0x007180f6,
+ 0x0000001d,
+ 0xfd2b80e5,
+ 0x000f0002,
+ 0x007180f7,
+ 0x00000030,
+ 0x31838063,
+ 0x000f0002,
+ 0x007180f8,
+ 0x00000030,
+ 0x11828063,
+ 0x000f0002,
+ 0x007180f9,
+ 0x0000001d,
+ 0xfd2580e5,
+ 0x000f0002,
+ 0x007180fa,
+ 0x00000030,
+ 0x31830063,
+ 0x000f0002,
+ 0x007180fb,
+ 0x00000030,
+ 0x11820063,
+ 0x000f0002,
+ 0x007180fc,
+ 0x0000002f,
+ 0xd18100e3,
+ 0x000f0002,
+ 0x007180fd,
+ 0x0000001d,
+ 0xfd0980e5,
+ 0x000f0002,
+ 0x007180fe,
+ 0x00000030,
+ 0x3183d363,
+ 0x000f0002,
+ 0x007180ff,
+ 0x00000030,
+ 0x1183d263,
+ 0x000f0002,
+ 0x00718100,
+ 0x0000002f,
+ 0xd18100e3,
+ 0x000f0002,
+ 0x00718101,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x00718102,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x00718103,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x00718104,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x00718105,
+ 0x00000025,
+ 0xd2000264,
+ 0x000f0002,
+ 0x00718106,
+ 0x00000018,
+ 0x7d77fd7a,
+ 0x000f0002,
+ 0x00718107,
+ 0x00000049,
+ 0xde203b63,
+ 0x000f0002,
+ 0x00718108,
+ 0x00000049,
+ 0xde803b79,
+ 0x000f0002,
+ 0x00718109,
+ 0x00000021,
+ 0xd18000e3,
+ 0x000f0002,
+ 0x0071810a,
+ 0x00000009,
+ 0xcf813d7a,
+ 0x000f0002,
+ 0x0071810b,
+ 0x00000049,
+ 0xdd0031e3,
+ 0x000f0002,
+ 0x0071810c,
+ 0x00000069,
+ 0xdd0e3b78,
+ 0x000f0002,
+ 0x0071810d,
+ 0x00000061,
+ 0xdd003b76,
+ 0x000f0002,
+ 0x0071810e,
+ 0x0000003f,
+ 0xdd000184,
+ 0x000f0002,
+ 0x0071810f,
+ 0x0000003f,
+ 0xdd000001,
+ 0x000f0002,
+ 0x00718110,
+ 0x00000035,
+ 0xdd0000fa,
+ 0x000f0002,
+ 0x00718111,
+ 0x00000018,
+ 0x3b7f3b76,
+ 0x000f0002,
+ 0x00718112,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718113,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718114,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x00718115,
+ 0x00000021,
+ 0xd18000e3,
+ 0x000f0002,
+ 0x00718116,
+ 0x00000069,
+ 0xdd043b79,
+ 0x000f0002,
+ 0x00718117,
+ 0x00000061,
+ 0xf18000e3,
+ 0x000f0002,
+ 0x00718118,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x00718119,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x0071811a,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x0071811b,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x0071811c,
+ 0x00000025,
+ 0xd2000264,
+ 0x000f0002,
+ 0x0071811d,
+ 0x00000098,
+ 0x605dbb76,
+ 0x000f0002,
+ 0x0071811e,
+ 0x00000009,
+ 0xcf813d7a,
+ 0x000f0002,
+ 0x0071811f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718120,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718121,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718122,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718123,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718124,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718125,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718126,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718127,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718128,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718129,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071812a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071812b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071812c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071812d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071812e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071812f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718130,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718131,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718132,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718133,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718134,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718135,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718136,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718137,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718138,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718139,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071813a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071813b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071813c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071813d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071813e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071813f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718140,
+ 0x00000049,
+ 0xd4083b01,
+ 0x000f0002,
+ 0x00718141,
+ 0x00000009,
+ 0xc28b3d7a,
+ 0x000f0002,
+ 0x00718142,
+ 0x0000003f,
+ 0xd4000380,
+ 0x000f0002,
+ 0x00718143,
+ 0x00000009,
+ 0xc28b3d7a,
+ 0x000f0002,
+ 0x00718144,
+ 0x00000049,
+ 0xd40e3b03,
+ 0x000f0002,
+ 0x00718145,
+ 0x0000003f,
+ 0xd6420000,
+ 0x000f0002,
+ 0x00718146,
+ 0x0000002f,
+ 0xd2814080,
+ 0x000f0002,
+ 0x00718147,
+ 0x0000002d,
+ 0xd2840365,
+ 0x000f0002,
+ 0x00718148,
+ 0x0000003f,
+ 0xd6800080,
+ 0x000f0002,
+ 0x00718149,
+ 0x0000003f,
+ 0xdd040004,
+ 0x000f0002,
+ 0x0071814a,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x0071814b,
+ 0x00000069,
+ 0xdd003b6d,
+ 0x000f0002,
+ 0x0071814c,
+ 0x00000069,
+ 0xdd003b6d,
+ 0x000f0002,
+ 0x0071814d,
+ 0x00000031,
+ 0xd303d265,
+ 0x000f0002,
+ 0x0071814e,
+ 0x00000049,
+ 0xde403b66,
+ 0x000f0002,
+ 0x0071814f,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x00718150,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x00718151,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x00718152,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x00718153,
+ 0x00000049,
+ 0xd5803b7e,
+ 0x000f0002,
+ 0x00718154,
+ 0x00000021,
+ 0xde4000e6,
+ 0x000f0002,
+ 0x00718155,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x00718156,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x00718157,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x00718158,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x00718159,
+ 0x00000049,
+ 0xd5003b7e,
+ 0x000f0002,
+ 0x0071815a,
+ 0x00000079,
+ 0xdd013b76,
+ 0x000f0002,
+ 0x0071815b,
+ 0x0000002d,
+ 0xdd04407f,
+ 0x000f0002,
+ 0x0071815c,
+ 0x00000018,
+ 0x3d7f3b76,
+ 0x000f0002,
+ 0x0071815d,
+ 0x00000079,
+ 0xdd01bb76,
+ 0x000f0002,
+ 0x0071815e,
+ 0x00000075,
+ 0xfd0180e8,
+ 0x000f0002,
+ 0x0071815f,
+ 0x00000094,
+ 0x00154168,
+ 0x000f0002,
+ 0x00718160,
+ 0x00000094,
+ 0x002544e8,
+ 0x000f0002,
+ 0x00718161,
+ 0x00000094,
+ 0x002341e8,
+ 0x000f0002,
+ 0x00718162,
+ 0x00000094,
+ 0x00174568,
+ 0x000f0002,
+ 0x00718163,
+ 0x00000094,
+ 0x00154268,
+ 0x000f0002,
+ 0x00718164,
+ 0x00000094,
+ 0x002742e8,
+ 0x000f0002,
+ 0x00718165,
+ 0x00000094,
+ 0x002d4368,
+ 0x000f0002,
+ 0x00718166,
+ 0x00000094,
+ 0x002d4468,
+ 0x000f0002,
+ 0x00718167,
+ 0x00000094,
+ 0x003343e8,
+ 0x000f0002,
+ 0x00718168,
+ 0x00000004,
+ 0x03973b76,
+ 0x000f0002,
+ 0x00718169,
+ 0x0000000d,
+ 0xe30dc165,
+ 0x000f0002,
+ 0x0071816a,
+ 0x00000030,
+ 0x32030076,
+ 0x000f0002,
+ 0x0071816b,
+ 0x00000030,
+ 0x12020076,
+ 0x000f0002,
+ 0x0071816c,
+ 0x0000003f,
+ 0xd4800000,
+ 0x000f0002,
+ 0x0071816d,
+ 0x0000003f,
+ 0xd1808000,
+ 0x000f0002,
+ 0x0071816e,
+ 0x0000000d,
+ 0xe33fc165,
+ 0x000f0002,
+ 0x0071816f,
+ 0x00000030,
+ 0x32046076,
+ 0x000f0002,
+ 0x00718170,
+ 0x00000030,
+ 0x12044076,
+ 0x000f0002,
+ 0x00718171,
+ 0x0000003f,
+ 0xd4828000,
+ 0x000f0002,
+ 0x00718172,
+ 0x0000003f,
+ 0xd1808000,
+ 0x000f0002,
+ 0x00718173,
+ 0x0000000d,
+ 0xe33fc165,
+ 0x000f0002,
+ 0x00718174,
+ 0x00000030,
+ 0x32042076,
+ 0x000f0002,
+ 0x00718175,
+ 0x00000030,
+ 0x12040076,
+ 0x000f0002,
+ 0x00718176,
+ 0x0000003f,
+ 0xd4820000,
+ 0x000f0002,
+ 0x00718177,
+ 0x0000000d,
+ 0xe363c165,
+ 0x000f0002,
+ 0x00718178,
+ 0x00000030,
+ 0x32032076,
+ 0x000f0002,
+ 0x00718179,
+ 0x00000030,
+ 0x12030076,
+ 0x000f0002,
+ 0x0071817a,
+ 0x0000003f,
+ 0xd4830000,
+ 0x000f0002,
+ 0x0071817b,
+ 0x00000049,
+ 0xd2803b76,
+ 0x000f0002,
+ 0x0071817c,
+ 0x0000000d,
+ 0xe30dc165,
+ 0x000f0002,
+ 0x0071817d,
+ 0x00000030,
+ 0x32038076,
+ 0x000f0002,
+ 0x0071817e,
+ 0x00000030,
+ 0x12028076,
+ 0x000f0002,
+ 0x0071817f,
+ 0x0000003f,
+ 0xd4810000,
+ 0x000f0002,
+ 0x00718180,
+ 0x0000003f,
+ 0xd6020000,
+ 0x000f0002,
+ 0x00718181,
+ 0x0000003f,
+ 0xd1810000,
+ 0x000f0002,
+ 0x00718182,
+ 0x0000000d,
+ 0xe33fc165,
+ 0x000f0002,
+ 0x00718183,
+ 0x00000030,
+ 0x32042076,
+ 0x000f0002,
+ 0x00718184,
+ 0x00000030,
+ 0x12040076,
+ 0x000f0002,
+ 0x00718185,
+ 0x0000003f,
+ 0xd4820000,
+ 0x000f0002,
+ 0x00718186,
+ 0x00000041,
+ 0xd48034eb,
+ 0x000f0002,
+ 0x00718187,
+ 0x00000079,
+ 0xdd01bb6a,
+ 0x000f0002,
+ 0x00718188,
+ 0x00000079,
+ 0xdd01bb76,
+ 0x000f0002,
+ 0x00718189,
+ 0x0000003f,
+ 0xd2001803,
+ 0x000f0002,
+ 0x0071818a,
+ 0x0000003f,
+ 0xd1810000,
+ 0x000f0002,
+ 0x0071818b,
+ 0x00000075,
+ 0xfd018063,
+ 0x000f0002,
+ 0x0071818c,
+ 0x00000098,
+ 0x80693b64,
+ 0x000f0002,
+ 0x0071818d,
+ 0x00000051,
+ 0xf20000e4,
+ 0x000f0002,
+ 0x0071818e,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x0071818f,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x00718190,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x00718191,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x00718192,
+ 0x0000002d,
+ 0xdd04407f,
+ 0x000f0002,
+ 0x00718193,
+ 0x00000018,
+ 0x3d7f3b76,
+ 0x000f0002,
+ 0x00718194,
+ 0x00000049,
+ 0xd3c03b38,
+ 0x000f0002,
+ 0x00718195,
+ 0x00000049,
+ 0xdd003b64,
+ 0x000f0002,
+ 0x00718196,
+ 0x00000051,
+ 0xf20000e4,
+ 0x000f0002,
+ 0x00718197,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x00718198,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x00718199,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x0071819a,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x0071819b,
+ 0x00000049,
+ 0xd3a03b38,
+ 0x000f0002,
+ 0x0071819c,
+ 0x00000019,
+ 0xdd61bb76,
+ 0x000f0002,
+ 0x0071819d,
+ 0x00000049,
+ 0xdd003b67,
+ 0x000f0002,
+ 0x0071819e,
+ 0x00000075,
+ 0xf1818263,
+ 0x000f0002,
+ 0x0071819f,
+ 0x00000041,
+ 0xd48034eb,
+ 0x000f0002,
+ 0x007181a0,
+ 0x00000079,
+ 0xdd01bb6a,
+ 0x000f0002,
+ 0x007181a1,
+ 0x00000079,
+ 0xdd01bb76,
+ 0x000f0002,
+ 0x007181a2,
+ 0x0000003f,
+ 0xd2001803,
+ 0x000f0002,
+ 0x007181a3,
+ 0x0000003f,
+ 0xd1808000,
+ 0x000f0002,
+ 0x007181a4,
+ 0x00000075,
+ 0xfd018063,
+ 0x000f0002,
+ 0x007181a5,
+ 0x00000098,
+ 0x80373b64,
+ 0x000f0002,
+ 0x007181a6,
+ 0x00000051,
+ 0xf20000e4,
+ 0x000f0002,
+ 0x007181a7,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x007181a8,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007181a9,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007181aa,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007181ab,
+ 0x0000002d,
+ 0xdd04407f,
+ 0x000f0002,
+ 0x007181ac,
+ 0x00000018,
+ 0x3d7f3b76,
+ 0x000f0002,
+ 0x007181ad,
+ 0x00000049,
+ 0xd3803b38,
+ 0x000f0002,
+ 0x007181ae,
+ 0x00000019,
+ 0xdd6fbb76,
+ 0x000f0002,
+ 0x007181af,
+ 0x00000049,
+ 0xdd003b67,
+ 0x000f0002,
+ 0x007181b0,
+ 0x00000075,
+ 0xf1818263,
+ 0x000f0002,
+ 0x007181b1,
+ 0x00000041,
+ 0xd48034eb,
+ 0x000f0002,
+ 0x007181b2,
+ 0x00000079,
+ 0xdd01bb6a,
+ 0x000f0002,
+ 0x007181b3,
+ 0x00000079,
+ 0xdd01bb63,
+ 0x000f0002,
+ 0x007181b4,
+ 0x00000075,
+ 0xfd018063,
+ 0x000f0002,
+ 0x007181b5,
+ 0x00000098,
+ 0x80173b64,
+ 0x000f0002,
+ 0x007181b6,
+ 0x00000049,
+ 0xde403b64,
+ 0x000f0002,
+ 0x007181b7,
+ 0x0000003f,
+ 0xd6800184,
+ 0x000f0002,
+ 0x007181b8,
+ 0x0000003f,
+ 0xd6800001,
+ 0x000f0002,
+ 0x007181b9,
+ 0x00000035,
+ 0xd68000ed,
+ 0x000f0002,
+ 0x007181ba,
+ 0x00000018,
+ 0x37ff0081,
+ 0x000f0002,
+ 0x007181bb,
+ 0x0000002d,
+ 0xdd04407f,
+ 0x000f0002,
+ 0x007181bc,
+ 0x00000018,
+ 0x3d7f3b76,
+ 0x000f0002,
+ 0x007181bd,
+ 0x00000021,
+ 0xd20000e4,
+ 0x000f0002,
+ 0x007181be,
+ 0x00000019,
+ 0xd3ef7b7e,
+ 0x000f0002,
+ 0x007181bf,
+ 0x00000075,
+ 0xf1818263,
+ 0x000f0002,
+ 0x007181c0,
+ 0x0000003f,
+ 0xd6800000,
+ 0x000f0002,
+ 0x007181c1,
+ 0x0000003f,
+ 0xdd040004,
+ 0x000f0002,
+ 0x007181c2,
+ 0x0000003f,
+ 0xdd180001,
+ 0x000f0002,
+ 0x007181c3,
+ 0x00000069,
+ 0xdd003b6d,
+ 0x000f0002,
+ 0x007181c4,
+ 0x00000069,
+ 0xdd003b6d,
+ 0x000f0002,
+ 0x007181c5,
+ 0x0000003f,
+ 0xdd000000,
+ 0x000f0002,
+ 0x007181c6,
+ 0x0000002d,
+ 0xdd540180,
+ 0x000f0002,
+ 0x007181c7,
+ 0x00000079,
+ 0xf3e08076,
+ 0x000f0002,
+ 0x007181c8,
+ 0x00000049,
+ 0xd600367a,
+ 0x000f0002,
+ 0x007181c9,
+ 0x00000079,
+ 0xdd01fb76,
+ 0x000f0002,
+ 0x007181ca,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181cb,
+ 0x00000049,
+ 0xdd003b03,
+ 0x000f0002,
+ 0x007181cc,
+ 0x00000059,
+ 0xfd003b76,
+ 0x000f0002,
+ 0x007181cd,
+ 0x0000003f,
+ 0xdd801c03,
+ 0x000f0002,
+ 0x007181ce,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181cf,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181d0,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007181d1,
+ 0x0000002d,
+ 0xdd06027f,
+ 0x000f0002,
+ 0x007181d2,
+ 0x00000018,
+ 0x1d7f3d7a,
+ 0x000f0002,
+ 0x007181d3,
+ 0x00000031,
+ 0xd483886b,
+ 0x000f0002,
+ 0x007181d4,
+ 0x00000079,
+ 0xdd01bb6a,
+ 0x000f0002,
+ 0x007181d5,
+ 0x00000079,
+ 0xf1819076,
+ 0x000f0002,
+ 0x007181d6,
+ 0x00000075,
+ 0xfd018063,
+ 0x000f0002,
+ 0x007181d7,
+ 0x00000098,
+ 0x8053bb76,
+ 0x000f0002,
+ 0x007181d8,
+ 0x00000019,
+ 0xdd7f7b79,
+ 0x000f0002,
+ 0x007181d9,
+ 0x00000075,
+ 0xf1818263,
+ 0x000f0002,
+ 0x007181da,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181db,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181dc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181dd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181f9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181fa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181fb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181fc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181fd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007181fe,
+ 0x0000003f,
+ 0xdd800203,
+ 0x000f0002,
+ 0x007181ff,
+ 0x00000049,
+ 0xd1843b02,
+ 0x000f0002,
+ 0x00718200,
+ 0x00000049,
+ 0xdd003b03,
+ 0x000f0002,
+ 0x00718201,
+ 0x00000069,
+ 0xdd003b7a,
+ 0x000f0002,
+ 0x00718202,
+ 0x00000049,
+ 0xdd003b79,
+ 0x000f0002,
+ 0x00718203,
+ 0x00000065,
+ 0xf1800263,
+ 0x000f0002,
+ 0x00718204,
+ 0x00000018,
+ 0x7d7d3b76,
+ 0x000f0002,
+ 0x00718205,
+ 0x00000009,
+ 0xcf813d7a,
+ 0x000f0002,
+ 0x00718206,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718207,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718208,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718209,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071820a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071820b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071820c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071820d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071820e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071820f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718210,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718211,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718212,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718213,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718214,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718215,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718216,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718217,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718218,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718219,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071821a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071821b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071821c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071821d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071821e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071821f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718220,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718221,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718222,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718223,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718224,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718225,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718226,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718227,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718228,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718229,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071822a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071822b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071822c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071822d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071822e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071822f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718230,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718231,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718232,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718233,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718234,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718235,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718236,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718237,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718238,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718239,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071823a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071823b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071823c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071823d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071823e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071823f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718240,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718241,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718242,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718243,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718244,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718245,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718246,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718247,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718248,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718249,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071824a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071824b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071824c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071824d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071824e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071824f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718250,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718251,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718252,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718253,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718254,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718255,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718256,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718257,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718258,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718259,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071825a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071825b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071825c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071825d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071825e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071825f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718260,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718261,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718262,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718263,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718264,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718265,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718266,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718267,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718268,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718269,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071826a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071826b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071826c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071826d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071826e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071826f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718270,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718271,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718272,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718273,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718274,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718275,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718276,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718277,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718278,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718279,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071827a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071827b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071827c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071827d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071827e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071827f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718280,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718281,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718282,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718283,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718284,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718285,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718286,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718287,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718288,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718289,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071828a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071828b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071828c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071828d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071828e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071828f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718290,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718291,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718292,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718293,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718294,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718295,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718296,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718297,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718298,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718299,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071829a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071829b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071829c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071829d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071829e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071829f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182a9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182aa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ab,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ac,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ad,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ae,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182af,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182b9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ba,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182bb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182bc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182bd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182be,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182bf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182c9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ca,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182cb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182cc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182cd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ce,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182cf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182d9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182da,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182db,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182dc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182dd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182f9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182fa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182fb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182fc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182fd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182fe,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007182ff,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718300,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718301,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718302,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718303,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718304,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718305,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718306,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718307,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718308,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718309,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071830a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071830b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071830c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071830d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071830e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071830f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718310,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718311,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718312,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718313,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718314,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718315,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718316,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718317,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718318,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718319,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071831a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071831b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071831c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071831d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071831e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071831f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718320,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718321,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718322,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718323,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718324,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718325,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718326,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718327,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718328,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718329,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071832a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071832b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071832c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071832d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071832e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071832f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718330,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718331,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718332,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718333,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718334,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718335,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718336,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718337,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718338,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718339,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071833a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071833b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071833c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071833d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071833e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071833f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718340,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718341,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718342,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718343,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718344,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718345,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718346,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718347,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718348,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718349,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071834a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071834b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071834c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071834d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071834e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071834f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718350,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718351,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718352,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718353,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718354,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718355,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718356,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718357,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718358,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718359,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071835a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071835b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071835c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071835d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071835e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071835f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718360,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718361,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718362,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718363,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718364,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718365,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718366,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718367,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718368,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718369,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071836a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071836b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071836c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071836d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071836e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071836f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718370,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718371,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718372,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718373,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718374,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718375,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718376,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718377,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718378,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718379,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071837a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071837b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071837c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071837d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071837e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071837f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718380,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718381,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718382,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718383,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718384,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718385,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718386,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718387,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718388,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718389,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071838a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071838b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071838c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071838d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071838e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071838f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718390,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718391,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718392,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718393,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718394,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718395,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718396,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718397,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718398,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718399,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071839a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071839b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071839c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071839d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071839e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071839f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183a9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183aa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ab,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ac,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ad,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ae,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183af,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183b9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ba,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183bb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183bc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183bd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183be,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183bf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183c9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ca,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183cb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183cc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183cd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ce,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183cf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183d9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183da,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183db,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183dc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183dd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183f9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183fa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183fb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183fc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183fd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183fe,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007183ff,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718400,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718401,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718402,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718403,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718404,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718405,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718406,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718407,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718408,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718409,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071840a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071840b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071840c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071840d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071840e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071840f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718410,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718411,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718412,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718413,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718414,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718415,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718416,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718417,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718418,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718419,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071841a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071841b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071841c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071841d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071841e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071841f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718420,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718421,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718422,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718423,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718424,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718425,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718426,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718427,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718428,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718429,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071842a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071842b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071842c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071842d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071842e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071842f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718430,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718431,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718432,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718433,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718434,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718435,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718436,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718437,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718438,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718439,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071843a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071843b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071843c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071843d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071843e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071843f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718440,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718441,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718442,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718443,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718444,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718445,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718446,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718447,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718448,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718449,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071844a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071844b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071844c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071844d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071844e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071844f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718450,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718451,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718452,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718453,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718454,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718455,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718456,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718457,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718458,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718459,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071845a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071845b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071845c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071845d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071845e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071845f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718460,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718461,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718462,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718463,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718464,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718465,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718466,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718467,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718468,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718469,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071846a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071846b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071846c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071846d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071846e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071846f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718470,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718471,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718472,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718473,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718474,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718475,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718476,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718477,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718478,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718479,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071847a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071847b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071847c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071847d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071847e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071847f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718480,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718481,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718482,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718483,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718484,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718485,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718486,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718487,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718488,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718489,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071848a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071848b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071848c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071848d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071848e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071848f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718490,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718491,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718492,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718493,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718494,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718495,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718496,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718497,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718498,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718499,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071849a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071849b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071849c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071849d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071849e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071849f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184a9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184aa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ab,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ac,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ad,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ae,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184af,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184b9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ba,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184bb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184bc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184bd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184be,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184bf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184c9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ca,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184cb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184cc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184cd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ce,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184cf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184d9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184da,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184db,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184dc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184dd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184f9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184fa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184fb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184fc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184fd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184fe,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007184ff,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718500,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718501,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718502,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718503,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718504,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718505,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718506,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718507,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718508,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718509,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071850a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071850b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071850c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071850d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071850e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071850f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718510,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718511,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718512,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718513,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718514,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718515,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718516,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718517,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718518,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718519,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071851a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071851b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071851c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071851d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071851e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071851f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718520,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718521,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718522,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718523,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718524,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718525,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718526,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718527,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718528,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718529,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071852a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071852b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071852c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071852d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071852e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071852f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718530,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718531,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718532,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718533,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718534,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718535,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718536,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718537,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718538,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718539,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071853a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071853b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071853c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071853d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071853e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071853f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718540,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718541,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718542,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718543,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718544,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718545,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718546,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718547,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718548,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718549,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071854a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071854b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071854c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071854d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071854e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071854f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718550,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718551,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718552,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718553,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718554,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718555,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718556,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718557,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718558,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718559,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071855a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071855b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071855c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071855d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071855e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071855f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718560,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718561,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718562,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718563,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718564,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718565,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718566,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718567,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718568,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718569,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071856a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071856b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071856c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071856d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071856e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071856f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718570,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718571,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718572,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718573,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718574,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718575,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718576,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718577,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718578,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718579,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071857a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071857b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071857c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071857d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071857e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071857f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718580,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718581,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718582,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718583,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718584,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718585,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718586,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718587,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718588,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718589,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071858a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071858b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071858c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071858d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071858e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071858f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718590,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718591,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718592,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718593,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718594,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718595,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718596,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718597,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718598,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718599,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071859a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071859b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071859c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071859d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071859e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071859f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185a9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185aa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ab,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ac,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ad,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ae,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185af,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185b9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ba,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185bb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185bc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185bd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185be,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185bf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185c9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ca,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185cb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185cc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185cd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ce,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185cf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185d9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185da,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185db,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185dc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185dd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185f9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185fa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185fb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185fc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185fd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185fe,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007185ff,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718600,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718601,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718602,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718603,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718604,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718605,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718606,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718607,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718608,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718609,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071860a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071860b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071860c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071860d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071860e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071860f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718610,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718611,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718612,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718613,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718614,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718615,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718616,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718617,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718618,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718619,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071861a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071861b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071861c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071861d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071861e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071861f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718620,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718621,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718622,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718623,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718624,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718625,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718626,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718627,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718628,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718629,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071862a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071862b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071862c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071862d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071862e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071862f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718630,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718631,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718632,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718633,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718634,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718635,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718636,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718637,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718638,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718639,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071863a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071863b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071863c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071863d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071863e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071863f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718640,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718641,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718642,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718643,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718644,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718645,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718646,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718647,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718648,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718649,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071864a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071864b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071864c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071864d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071864e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071864f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718650,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718651,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718652,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718653,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718654,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718655,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718656,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718657,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718658,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718659,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071865a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071865b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071865c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071865d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071865e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071865f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718660,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718661,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718662,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718663,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718664,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718665,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718666,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718667,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718668,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718669,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071866a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071866b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071866c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071866d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071866e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071866f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718670,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718671,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718672,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718673,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718674,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718675,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718676,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718677,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718678,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718679,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071867a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071867b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071867c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071867d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071867e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071867f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718680,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718681,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718682,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718683,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718684,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718685,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718686,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718687,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718688,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718689,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071868a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071868b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071868c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071868d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071868e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071868f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718690,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718691,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718692,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718693,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718694,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718695,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718696,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718697,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718698,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718699,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071869a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071869b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071869c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071869d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071869e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071869f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186a9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186aa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ab,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ac,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ad,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ae,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186af,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186b9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ba,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186bb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186bc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186bd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186be,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186bf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186c9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ca,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186cb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186cc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186cd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ce,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186cf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186d9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186da,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186db,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186dc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186dd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186de,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186df,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186e9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ea,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186eb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ec,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ed,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ee,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ef,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186f9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186fa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186fb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186fc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186fd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186fe,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007186ff,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718700,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718701,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718702,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718703,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718704,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718705,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718706,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718707,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718708,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718709,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071870a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071870b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071870c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071870d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071870e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071870f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718710,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718711,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718712,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718713,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718714,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718715,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718716,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718717,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718718,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718719,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071871a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071871b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071871c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071871d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071871e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071871f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718720,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718721,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718722,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718723,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718724,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718725,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718726,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718727,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718728,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718729,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071872a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071872b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071872c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071872d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071872e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071872f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718730,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718731,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718732,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718733,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718734,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718735,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718736,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718737,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718738,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718739,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071873a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071873b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071873c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071873d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071873e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071873f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718740,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718741,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718742,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718743,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718744,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718745,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718746,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718747,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718748,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718749,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071874a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071874b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071874c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071874d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071874e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071874f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718750,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718751,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718752,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718753,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718754,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718755,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718756,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718757,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718758,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718759,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071875a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071875b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071875c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071875d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071875e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071875f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718760,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718761,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718762,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718763,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718764,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718765,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718766,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718767,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718768,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718769,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071876a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071876b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071876c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071876d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071876e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071876f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718770,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718771,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718772,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718773,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718774,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718775,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718776,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718777,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718778,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718779,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071877a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071877b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071877c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071877d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071877e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071877f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718780,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718781,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718782,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718783,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718784,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718785,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718786,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718787,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718788,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718789,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071878a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071878b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071878c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071878d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071878e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071878f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718790,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718791,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718792,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718793,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718794,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718795,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718796,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718797,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718798,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x00718799,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071879a,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071879b,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071879c,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071879d,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071879e,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x0071879f,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187a9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187aa,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187ab,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187ac,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187ad,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187ae,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187af,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b0,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b1,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b2,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b3,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b4,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b5,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b6,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b7,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b8,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187b9,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187ba,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187bb,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187bc,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187bd,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187be,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187bf,
+ 0x00000000,
+ 0x00000000,
+ 0x000f0002,
+ 0x007187c0,
+ 0x00000079,
+ 0xfd609076,
+ 0x000f0002,
+ 0x007187c1,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007187c2,
+ 0x0000003d,
+ 0xf780006f,
+ 0x000f0002,
+ 0x007187c3,
+ 0x0000003d,
+ 0xf780006f,
+/* FINISH INIT Descriptor */
+ 0x000f0002,
+ 0x807187c4,
+ 0x0000003d,
+ 0xf780006f,
+};
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 9034a05734e..4942f7d1893 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -64,8 +64,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.81"
-#define DRV_MODULE_RELDATE "September 5, 2007"
+#define DRV_MODULE_VERSION "3.86"
+#define DRV_MODULE_RELDATE "November 9, 2007"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -198,6 +198,11 @@ static struct pci_device_id tg3_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5784)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5764)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
{PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -312,6 +317,16 @@ static u32 tg3_read32(struct tg3 *tp, u32 off)
return (readl(tp->regs + off));
}
+static void tg3_ape_write32(struct tg3 *tp, u32 off, u32 val)
+{
+ writel(val, tp->aperegs + off);
+}
+
+static u32 tg3_ape_read32(struct tg3 *tp, u32 off)
+{
+ return (readl(tp->aperegs + off));
+}
+
static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
{
unsigned long flags;
@@ -498,6 +513,73 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
spin_unlock_irqrestore(&tp->indirect_lock, flags);
}
+static void tg3_ape_lock_init(struct tg3 *tp)
+{
+ int i;
+
+ /* Make sure the driver hasn't any stale locks. */
+ for (i = 0; i < 8; i++)
+ tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + 4 * i,
+ APE_LOCK_GRANT_DRIVER);
+}
+
+static int tg3_ape_lock(struct tg3 *tp, int locknum)
+{
+ int i, off;
+ int ret = 0;
+ u32 status;
+
+ if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+ return 0;
+
+ switch (locknum) {
+ case TG3_APE_LOCK_MEM:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ off = 4 * locknum;
+
+ tg3_ape_write32(tp, TG3_APE_LOCK_REQ + off, APE_LOCK_REQ_DRIVER);
+
+ /* Wait for up to 1 millisecond to acquire lock. */
+ for (i = 0; i < 100; i++) {
+ status = tg3_ape_read32(tp, TG3_APE_LOCK_GRANT + off);
+ if (status == APE_LOCK_GRANT_DRIVER)
+ break;
+ udelay(10);
+ }
+
+ if (status != APE_LOCK_GRANT_DRIVER) {
+ /* Revoke the lock request. */
+ tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off,
+ APE_LOCK_GRANT_DRIVER);
+
+ ret = -EBUSY;
+ }
+
+ return ret;
+}
+
+static void tg3_ape_unlock(struct tg3 *tp, int locknum)
+{
+ int off;
+
+ if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+ return;
+
+ switch (locknum) {
+ case TG3_APE_LOCK_MEM:
+ break;
+ default:
+ return;
+ }
+
+ off = 4 * locknum;
+ tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off, APE_LOCK_GRANT_DRIVER);
+}
+
static void tg3_disable_ints(struct tg3 *tp)
{
tw32(TG3PCI_MISC_HOST_CTRL,
@@ -574,7 +656,7 @@ static void tg3_restart_ints(struct tg3 *tp)
static inline void tg3_netif_stop(struct tg3 *tp)
{
tp->dev->trans_start = jiffies; /* prevent tx timeout */
- netif_poll_disable(tp->dev);
+ napi_disable(&tp->napi);
netif_tx_disable(tp->dev);
}
@@ -585,7 +667,7 @@ static inline void tg3_netif_start(struct tg3 *tp)
* so long as all callers are assured to have free tx slots
* (such as after tg3_init_hw)
*/
- netif_poll_enable(tp->dev);
+ napi_enable(&tp->napi);
tp->hw_status->status |= SD_STATUS_UPDATED;
tg3_enable_ints(tp);
}
@@ -595,7 +677,8 @@ static void tg3_switch_clocks(struct tg3 *tp)
u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL);
u32 orig_clock_ctrl;
- if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
+ if ((tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) ||
+ (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
return;
orig_clock_ctrl = clock_ctrl;
@@ -1023,6 +1106,24 @@ static int tg3_phy_reset(struct tg3 *tp)
if (err)
return err;
+ if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) {
+ u32 val;
+
+ val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
+ if ((val & CPMU_LSPD_1000MB_MACCLK_MASK) ==
+ CPMU_LSPD_1000MB_MACCLK_12_5) {
+ val &= ~CPMU_LSPD_1000MB_MACCLK_MASK;
+ udelay(40);
+ tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val);
+ }
+
+ /* Disable GPHY autopowerdown. */
+ tg3_writephy(tp, MII_TG3_MISC_SHDW,
+ MII_TG3_MISC_SHDW_WREN |
+ MII_TG3_MISC_SHDW_APD_SEL |
+ MII_TG3_MISC_SHDW_APD_WKTM_84MS);
+ }
+
out:
if (tp->tg3_flags2 & TG3_FLG2_PHY_ADC_BUG) {
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
@@ -1214,6 +1315,8 @@ static void tg3_nvram_unlock(struct tg3 *);
static void tg3_power_down_phy(struct tg3 *tp)
{
+ u32 val;
+
if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
u32 sg_dig_ctrl = tr32(SG_DIG_CTRL);
@@ -1228,8 +1331,6 @@ static void tg3_power_down_phy(struct tg3 *tp)
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
- u32 val;
-
tg3_bmcr_reset(tp);
val = tr32(GRC_MISC_CFG);
tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ);
@@ -1249,6 +1350,14 @@ static void tg3_power_down_phy(struct tg3 *tp)
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 &&
(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
return;
+
+ if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) {
+ val = tr32(TG3_CPMU_LSPD_1000MB_CLK);
+ val &= ~CPMU_LSPD_1000MB_MACCLK_MASK;
+ val |= CPMU_LSPD_1000MB_MACCLK_12_5;
+ tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val);
+ }
+
tg3_writephy(tp, MII_BMCR, BMCR_PDOWN);
}
@@ -1400,6 +1509,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
tw32_wait_f(TG3PCI_CLOCK_CTRL, base_val | CLOCK_CTRL_ALTCLK |
CLOCK_CTRL_PWRDOWN_PLL133, 40);
} else if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
+ (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)) {
/* do nothing */
} else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
@@ -1444,7 +1554,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
}
if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) &&
- !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+ !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+ !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
tg3_power_down_phy(tp);
tg3_frob_aux_power(tp);
@@ -3041,6 +3152,23 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
err = tg3_setup_copper_phy(tp, force_reset);
}
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
+ tp->pci_chip_rev_id == CHIPREV_ID_5784_A1) {
+ u32 val, scale;
+
+ val = tr32(TG3_CPMU_CLCK_STAT) & CPMU_CLCK_STAT_MAC_CLCK_MASK;
+ if (val == CPMU_CLCK_STAT_MAC_CLCK_62_5)
+ scale = 65;
+ else if (val == CPMU_CLCK_STAT_MAC_CLCK_6_25)
+ scale = 6;
+ else
+ scale = 12;
+
+ val = tr32(GRC_MISC_CFG) & ~GRC_MISC_CFG_PRESCALAR_MASK;
+ val |= (scale << GRC_MISC_CFG_PRESCALAR_SHIFT);
+ tw32(GRC_MISC_CFG, val);
+ }
+
if (tp->link_config.active_speed == SPEED_1000 &&
tp->link_config.active_duplex == DUPLEX_HALF)
tw32(MAC_TX_LENGTHS,
@@ -3471,11 +3599,9 @@ next_pkt_nopost:
return received;
}
-static int tg3_poll(struct net_device *netdev, int *budget)
+static int tg3_poll_work(struct tg3 *tp, int work_done, int budget)
{
- struct tg3 *tp = netdev_priv(netdev);
struct tg3_hw_status *sblk = tp->hw_status;
- int done;
/* handle link change and other phy events */
if (!(tp->tg3_flags &
@@ -3493,44 +3619,59 @@ static int tg3_poll(struct net_device *netdev, int *budget)
/* run TX completion thread */
if (sblk->idx[0].tx_consumer != tp->tx_cons) {
tg3_tx(tp);
- if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) {
- netif_rx_complete(netdev);
- schedule_work(&tp->reset_task);
- return 0;
- }
+ if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
+ return work_done;
}
/* run RX thread, within the bounds set by NAPI.
* All RX "locking" is done by ensuring outside
- * code synchronizes with dev->poll()
+ * code synchronizes with tg3->napi.poll()
*/
- if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) {
- int orig_budget = *budget;
- int work_done;
+ if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr)
+ work_done += tg3_rx(tp, budget - work_done);
- if (orig_budget > netdev->quota)
- orig_budget = netdev->quota;
+ return work_done;
+}
- work_done = tg3_rx(tp, orig_budget);
+static int tg3_poll(struct napi_struct *napi, int budget)
+{
+ struct tg3 *tp = container_of(napi, struct tg3, napi);
+ int work_done = 0;
+ struct tg3_hw_status *sblk = tp->hw_status;
- *budget -= work_done;
- netdev->quota -= work_done;
- }
+ while (1) {
+ work_done = tg3_poll_work(tp, work_done, budget);
- if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
- tp->last_tag = sblk->status_tag;
- rmb();
- } else
- sblk->status &= ~SD_STATUS_UPDATED;
+ if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
+ goto tx_recovery;
+
+ if (unlikely(work_done >= budget))
+ break;
+
+ if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
+ /* tp->last_tag is used in tg3_restart_ints() below
+ * to tell the hw how much work has been processed,
+ * so we must read it before checking for more work.
+ */
+ tp->last_tag = sblk->status_tag;
+ rmb();
+ } else
+ sblk->status &= ~SD_STATUS_UPDATED;
- /* if no more work, tell net stack and NIC we're done */
- done = !tg3_has_work(tp);
- if (done) {
- netif_rx_complete(netdev);
- tg3_restart_ints(tp);
+ if (likely(!tg3_has_work(tp))) {
+ netif_rx_complete(tp->dev, napi);
+ tg3_restart_ints(tp);
+ break;
+ }
}
- return (done ? 0 : 1);
+ return work_done;
+
+tx_recovery:
+ /* work_done is guaranteed to be less than budget. */
+ netif_rx_complete(tp->dev, napi);
+ schedule_work(&tp->reset_task);
+ return work_done;
}
static void tg3_irq_quiesce(struct tg3 *tp)
@@ -3577,7 +3718,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id)
prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
if (likely(!tg3_irq_sync(tp)))
- netif_rx_schedule(dev); /* schedule NAPI poll */
+ netif_rx_schedule(dev, &tp->napi);
return IRQ_HANDLED;
}
@@ -3602,7 +3743,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id)
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
if (likely(!tg3_irq_sync(tp)))
- netif_rx_schedule(dev); /* schedule NAPI poll */
+ netif_rx_schedule(dev, &tp->napi);
return IRQ_RETVAL(1);
}
@@ -3644,7 +3785,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id)
sblk->status &= ~SD_STATUS_UPDATED;
if (likely(tg3_has_work(tp))) {
prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
- netif_rx_schedule(dev); /* schedule NAPI poll */
+ netif_rx_schedule(dev, &tp->napi);
} else {
/* No work, shared interrupt perhaps? re-enable
* interrupts, and flush that PCI write
@@ -3690,7 +3831,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
if (tg3_irq_sync(tp))
goto out;
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &tp->napi)) {
prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
/* Update last_tag to mark that this status has been
* seen. Because interrupt may be shared, we may be
@@ -3698,7 +3839,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
* if tg3_poll() is not scheduled.
*/
tp->last_tag = sblk->status_tag;
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &tp->napi);
}
out:
return IRQ_RETVAL(handled);
@@ -3737,7 +3878,7 @@ static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
tg3_full_unlock(tp);
del_timer_sync(&tp->timer);
tp->irq_sync = 0;
- netif_poll_enable(tp->dev);
+ napi_enable(&tp->napi);
dev_close(tp->dev);
tg3_full_lock(tp, 0);
}
@@ -3932,7 +4073,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = skb_headlen(skb);
/* We are running in BH disabled context with netif_tx_lock
- * and TX reclaim runs via tp->poll inside of a software
+ * and TX reclaim runs via tp->napi.poll inside of a software
* interrupt. Furthermore, IRQ processing runs lockless so we have
* no IRQ context deadlocks to worry about either. Rejoice!
*/
@@ -4087,7 +4228,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
len = skb_headlen(skb);
/* We are running in BH disabled context with netif_tx_lock
- * and TX reclaim runs via tp->poll inside of a software
+ * and TX reclaim runs via tp->napi.poll inside of a software
* interrupt. Furthermore, IRQ processing runs lockless so we have
* no IRQ context deadlocks to worry about either. Rejoice!
*/
@@ -4732,6 +4873,80 @@ static void tg3_disable_nvram_access(struct tg3 *tp)
}
}
+static void tg3_ape_send_event(struct tg3 *tp, u32 event)
+{
+ int i;
+ u32 apedata;
+
+ apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
+ if (apedata != APE_SEG_SIG_MAGIC)
+ return;
+
+ apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
+ if (apedata != APE_FW_STATUS_READY)
+ return;
+
+ /* Wait for up to 1 millisecond for APE to service previous event. */
+ for (i = 0; i < 10; i++) {
+ if (tg3_ape_lock(tp, TG3_APE_LOCK_MEM))
+ return;
+
+ apedata = tg3_ape_read32(tp, TG3_APE_EVENT_STATUS);
+
+ if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+ tg3_ape_write32(tp, TG3_APE_EVENT_STATUS,
+ event | APE_EVENT_STATUS_EVENT_PENDING);
+
+ tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);
+
+ if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+ break;
+
+ udelay(100);
+ }
+
+ if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+ tg3_ape_write32(tp, TG3_APE_EVENT, APE_EVENT_1);
+}
+
+static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
+{
+ u32 event;
+ u32 apedata;
+
+ if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+ return;
+
+ switch (kind) {
+ case RESET_KIND_INIT:
+ tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG,
+ APE_HOST_SEG_SIG_MAGIC);
+ tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN,
+ APE_HOST_SEG_LEN_MAGIC);
+ apedata = tg3_ape_read32(tp, TG3_APE_HOST_INIT_COUNT);
+ tg3_ape_write32(tp, TG3_APE_HOST_INIT_COUNT, ++apedata);
+ tg3_ape_write32(tp, TG3_APE_HOST_DRIVER_ID,
+ APE_HOST_DRIVER_ID_MAGIC);
+ tg3_ape_write32(tp, TG3_APE_HOST_BEHAVIOR,
+ APE_HOST_BEHAV_NO_PHYLOCK);
+
+ event = APE_EVENT_STATUS_STATE_START;
+ break;
+ case RESET_KIND_SHUTDOWN:
+ event = APE_EVENT_STATUS_STATE_UNLOAD;
+ break;
+ case RESET_KIND_SUSPEND:
+ event = APE_EVENT_STATUS_STATE_SUSPEND;
+ break;
+ default:
+ return;
+ }
+
+ event |= APE_EVENT_STATUS_DRIVER_EVNT | APE_EVENT_STATUS_STATE_CHNGE;
+
+ tg3_ape_send_event(tp, event);
+}
+
/* tp->lock is held. */
static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
{
@@ -4759,6 +4974,10 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
break;
};
}
+
+ if (kind == RESET_KIND_INIT ||
+ kind == RESET_KIND_SUSPEND)
+ tg3_ape_driver_state_change(tp, kind);
}
/* tp->lock is held. */
@@ -4780,6 +4999,9 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
break;
};
}
+
+ if (kind == RESET_KIND_SHUTDOWN)
+ tg3_ape_driver_state_change(tp, kind);
}
/* tp->lock is held. */
@@ -4850,10 +5072,7 @@ static int tg3_poll_fw(struct tg3 *tp)
/* Save PCI command register before chip reset */
static void tg3_save_pci_state(struct tg3 *tp)
{
- u32 val;
-
- pci_read_config_dword(tp->pdev, TG3PCI_COMMAND, &val);
- tp->pci_cmd = val;
+ pci_read_config_word(tp->pdev, PCI_COMMAND, &tp->pci_cmd);
}
/* Restore PCI state after chip reset */
@@ -4870,17 +5089,35 @@ static void tg3_restore_pci_state(struct tg3 *tp)
if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
(tp->tg3_flags & TG3_FLAG_PCIX_MODE))
val |= PCISTATE_RETRY_SAME_DMA;
+ /* Allow reads and writes to the APE register and memory space. */
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
+ PCISTATE_ALLOW_APE_SHMEM_WR;
pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
- pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd);
+ pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd);
+
+ if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)
+ pcie_set_readrq(tp->pdev, 4096);
+ else {
+ pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
+ tp->pci_cacheline_sz);
+ pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER,
+ tp->pci_lat_timer);
+ }
/* Make sure PCI-X relaxed ordering bit is clear. */
- pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
- val &= ~PCIX_CAPS_RELAXED_ORDERING;
- pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val);
+ if (tp->pcix_cap) {
+ u16 pcix_cmd;
+
+ pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+ &pcix_cmd);
+ pcix_cmd &= ~PCI_X_CMD_ERO;
+ pci_write_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+ pcix_cmd);
+ }
if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
- u32 val;
/* Chip reset on 5780 will reset MSI enable bit,
* so need to restore it.
@@ -4924,7 +5161,9 @@ static int tg3_chip_reset(struct tg3 *tp)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
tw32(GRC_FASTBOOT_PC, 0);
/*
@@ -5037,7 +5276,7 @@ static int tg3_chip_reset(struct tg3 *tp)
tw32(GRC_MODE, tp->grc_mode);
if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
- u32 val = tr32(0xc4);
+ val = tr32(0xc4);
tw32(0xc4, val | (1 << 15));
}
@@ -5066,7 +5305,7 @@ static int tg3_chip_reset(struct tg3 *tp)
if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
- u32 val = tr32(0x7c00);
+ val = tr32(0x7c00);
tw32(0x7c00, val | (1 << 25));
}
@@ -5092,7 +5331,8 @@ static int tg3_chip_reset(struct tg3 *tp)
/* tp->lock is held. */
static void tg3_stop_fw(struct tg3 *tp)
{
- if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+ if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+ !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
u32 val;
int i;
@@ -6149,14 +6389,38 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tg3_write_sig_legacy(tp, RESET_KIND_INIT);
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
+ tp->pci_chip_rev_id == CHIPREV_ID_5784_A1) {
+ val = tr32(TG3_CPMU_CTRL);
+ val &= ~(CPMU_CTRL_LINK_AWARE_MODE | CPMU_CTRL_LINK_IDLE_MODE);
+ tw32(TG3_CPMU_CTRL, val);
+
+ val = tr32(TG3_CPMU_LSPD_10MB_CLK);
+ val &= ~CPMU_LSPD_10MB_MACCLK_MASK;
+ val |= CPMU_LSPD_10MB_MACCLK_6_25;
+ tw32(TG3_CPMU_LSPD_10MB_CLK, val);
+
+ val = tr32(TG3_CPMU_LNK_AWARE_PWRMD);
+ val &= ~CPMU_LNK_AWARE_MACCLK_MASK;
+ val |= CPMU_LNK_AWARE_MACCLK_6_25;
+ tw32(TG3_CPMU_LNK_AWARE_PWRMD, val);
+
+ val = tr32(TG3_CPMU_HST_ACC);
+ val &= ~CPMU_HST_ACC_MACCLK_MASK;
+ val |= CPMU_HST_ACC_MACCLK_6_25;
+ tw32(TG3_CPMU_HST_ACC, val);
+ }
+
/* This works around an issue with Athlon chipsets on
* B3 tigon3 silicon. This bit has no effect on any
* other revision. But do not set this on PCI Express
- * chips.
+ * chips and don't even touch the clocks if the CPMU is present.
*/
- if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
- tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT;
- tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
+ if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) {
+ if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
+ tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT;
+ tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
+ }
if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
(tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
@@ -6165,6 +6429,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(TG3PCI_PCISTATE, val);
}
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+ /* Allow reads and writes to the
+ * APE register and memory space.
+ */
+ val = tr32(TG3PCI_PCISTATE);
+ val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
+ PCISTATE_ALLOW_APE_SHMEM_WR;
+ tw32(TG3PCI_PCISTATE, val);
+ }
+
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_BX) {
/* Enable some hw fixes. */
val = tr32(TG3PCI_MSI_DATA);
@@ -6181,10 +6455,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (err)
return err;
- /* This value is determined during the probe time DMA
- * engine test, tg3_test_dma.
- */
- tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) {
+ /* This value is determined during the probe time DMA
+ * engine test, tg3_test_dma.
+ */
+ tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+ }
tp->grc_mode &= ~(GRC_MODE_HOST_SENDBDS |
GRC_MODE_4X_NIC_SEND_RINGS |
@@ -6418,6 +6695,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
RDMAC_MODE_LNGREAD_ENAB);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+ rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB |
+ RDMAC_MODE_MBUF_RBD_CRPT_ENAB |
+ RDMAC_MODE_MBUF_SBD_CRPT_ENAB;
+
/* If statement applies to 5705 and 5750 PCI devices only */
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) ||
@@ -6579,22 +6861,28 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
/* Enable host coalescing bug fix */
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) ||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787))
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761))
val |= (1 << 29);
tw32_f(WDMAC_MODE, val);
udelay(40);
- if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
- val = tr32(TG3PCI_X_CAPS);
+ if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) {
+ u16 pcix_cmd;
+
+ pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+ &pcix_cmd);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
- val &= ~PCIX_CAPS_BURST_MASK;
- val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
+ pcix_cmd &= ~PCI_X_CMD_MAX_READ;
+ pcix_cmd |= PCI_X_CMD_READ_2K;
} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
- val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK);
- val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
+ pcix_cmd &= ~(PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ);
+ pcix_cmd |= PCI_X_CMD_READ_2K;
}
- tw32(TG3PCI_X_CAPS, val);
+ pci_write_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+ pcix_cmd);
}
tw32_f(RDMAC_MODE, rdmac_mode);
@@ -6603,7 +6891,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE);
if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
- tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ tw32(SNDDATAC_MODE,
+ SNDDATAC_MODE_ENABLE | SNDDATAC_MODE_CDELAY);
+ else
+ tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
+
tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE);
tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
@@ -6630,7 +6924,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
udelay(100);
tp->rx_mode = RX_MODE_ENABLE;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE;
tw32_f(MAC_RX_MODE, tp->rx_mode);
@@ -6760,6 +7055,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
break;
};
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ /* Write our heartbeat update interval to APE. */
+ tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS,
+ APE_HOST_HEARTBEAT_INT_DISABLE);
+
tg3_write_sig_post_reset(tp, RESET_KIND_INIT);
return 0;
@@ -7127,10 +7427,6 @@ static int tg3_open(struct net_device *dev)
} else if (pci_enable_msi(tp->pdev) == 0) {
u32 msi_mode;
- /* Hardware bug - MSI won't work if INTX disabled. */
- if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
- pci_intx(tp->pdev, 1);
-
msi_mode = tr32(MSGINT_MODE);
tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
@@ -7147,6 +7443,8 @@ static int tg3_open(struct net_device *dev)
return err;
}
+ napi_enable(&tp->napi);
+
tg3_full_lock(tp, 0);
err = tg3_init_hw(tp, 1);
@@ -7174,6 +7472,7 @@ static int tg3_open(struct net_device *dev)
tg3_full_unlock(tp);
if (err) {
+ napi_disable(&tp->napi);
free_irq(tp->pdev->irq, dev);
if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
pci_disable_msi(tp->pdev);
@@ -7199,6 +7498,8 @@ static int tg3_open(struct net_device *dev)
tg3_full_unlock(tp);
+ napi_disable(&tp->napi);
+
return err;
}
@@ -7460,6 +7761,7 @@ static int tg3_close(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
+ napi_disable(&tp->napi);
cancel_work_sync(&tp->reset_task);
netif_stop_queue(dev);
@@ -7995,7 +8297,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
buf = data;
if (b_offset || odd_len) {
buf = kmalloc(len, GFP_KERNEL);
- if (buf == 0)
+ if (!buf)
return -ENOMEM;
if (b_offset)
memcpy(buf, &start, 4);
@@ -8027,7 +8329,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
SUPPORTED_100baseT_Full |
SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
- SUPPORTED_MII);
+ SUPPORTED_TP);
cmd->port = PORT_TP;
} else {
cmd->supported |= SUPPORTED_FIBRE;
@@ -8075,7 +8377,8 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
tp->link_config.autoneg = cmd->autoneg;
if (cmd->autoneg == AUTONEG_ENABLE) {
- tp->link_config.advertising = cmd->advertising;
+ tp->link_config.advertising = (cmd->advertising |
+ ADVERTISED_Autoneg);
tp->link_config.speed = SPEED_INVALID;
tp->link_config.duplex = DUPLEX_INVALID;
} else {
@@ -8163,10 +8466,12 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
}
if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) {
- if (value)
+ if (value) {
dev->features |= NETIF_F_TSO6;
- else
- dev->features &= ~NETIF_F_TSO6;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ dev->features |= NETIF_F_TSO_ECN;
+ } else
+ dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN);
}
return ethtool_op_set_tso(dev, value);
}
@@ -8344,7 +8649,9 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data)
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
ethtool_op_set_tx_ipv6_csum(dev, data);
else
ethtool_op_set_tx_csum(dev, data);
@@ -8352,14 +8659,16 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data)
return 0;
}
-static int tg3_get_stats_count (struct net_device *dev)
+static int tg3_get_sset_count (struct net_device *dev, int sset)
{
- return TG3_NUM_STATS;
-}
-
-static int tg3_get_test_count (struct net_device *dev)
-{
- return TG3_NUM_TEST;
+ switch (sset) {
+ case ETH_SS_TEST:
+ return TG3_NUM_TEST;
+ case ETH_SS_STATS:
+ return TG3_NUM_STATS;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf)
@@ -8417,14 +8726,16 @@ static void tg3_get_ethtool_stats (struct net_device *dev,
}
#define NVRAM_TEST_SIZE 0x100
-#define NVRAM_SELFBOOT_FORMAT1_SIZE 0x14
+#define NVRAM_SELFBOOT_FORMAT1_0_SIZE 0x14
+#define NVRAM_SELFBOOT_FORMAT1_2_SIZE 0x18
+#define NVRAM_SELFBOOT_FORMAT1_3_SIZE 0x1c
#define NVRAM_SELFBOOT_HW_SIZE 0x20
#define NVRAM_SELFBOOT_DATA_SIZE 0x1c
static int tg3_test_nvram(struct tg3 *tp)
{
u32 *buf, csum, magic;
- int i, j, err = 0, size;
+ int i, j, k, err = 0, size;
if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
return -EIO;
@@ -8432,9 +8743,22 @@ static int tg3_test_nvram(struct tg3 *tp)
if (magic == TG3_EEPROM_MAGIC)
size = NVRAM_TEST_SIZE;
else if ((magic & TG3_EEPROM_MAGIC_FW_MSK) == TG3_EEPROM_MAGIC_FW) {
- if ((magic & 0xe00000) == 0x200000)
- size = NVRAM_SELFBOOT_FORMAT1_SIZE;
- else
+ if ((magic & TG3_EEPROM_SB_FORMAT_MASK) ==
+ TG3_EEPROM_SB_FORMAT_1) {
+ switch (magic & TG3_EEPROM_SB_REVISION_MASK) {
+ case TG3_EEPROM_SB_REVISION_0:
+ size = NVRAM_SELFBOOT_FORMAT1_0_SIZE;
+ break;
+ case TG3_EEPROM_SB_REVISION_2:
+ size = NVRAM_SELFBOOT_FORMAT1_2_SIZE;
+ break;
+ case TG3_EEPROM_SB_REVISION_3:
+ size = NVRAM_SELFBOOT_FORMAT1_3_SIZE;
+ break;
+ default:
+ return 0;
+ }
+ } else
return 0;
} else if ((magic & TG3_EEPROM_MAGIC_HW_MSK) == TG3_EEPROM_MAGIC_HW)
size = NVRAM_SELFBOOT_HW_SIZE;
@@ -8461,8 +8785,17 @@ static int tg3_test_nvram(struct tg3 *tp)
TG3_EEPROM_MAGIC_FW) {
u8 *buf8 = (u8 *) buf, csum8 = 0;
- for (i = 0; i < size; i++)
- csum8 += buf8[i];
+ if ((cpu_to_be32(buf[0]) & TG3_EEPROM_SB_REVISION_MASK) ==
+ TG3_EEPROM_SB_REVISION_2) {
+ /* For rev 2, the csum doesn't include the MBA. */
+ for (i = 0; i < TG3_EEPROM_SB_F1R2_MBA_OFF; i++)
+ csum8 += buf8[i];
+ for (i = TG3_EEPROM_SB_F1R2_MBA_OFF + 4; i < size; i++)
+ csum8 += buf8[i];
+ } else {
+ for (i = 0; i < size; i++)
+ csum8 += buf8[i];
+ }
if (csum8 == 0) {
err = 0;
@@ -8478,7 +8811,6 @@ static int tg3_test_nvram(struct tg3 *tp)
u8 data[NVRAM_SELFBOOT_DATA_SIZE];
u8 parity[NVRAM_SELFBOOT_DATA_SIZE];
u8 *buf8 = (u8 *) buf;
- int j, k;
/* Separate the parity bits and the data bytes. */
for (i = 0, j = 0, k = 0; i < NVRAM_SELFBOOT_HW_SIZE; i++) {
@@ -8788,7 +9120,7 @@ static int tg3_do_mem_test(struct tg3 *tp, u32 offset, u32 len)
int i;
u32 j;
- for (i = 0; i < sizeof(test_pattern)/sizeof(u32); i++) {
+ for (i = 0; i < ARRAY_SIZE(test_pattern); i++) {
for (j = 0; j < len; j += 4) {
u32 val;
@@ -8839,7 +9171,9 @@ static int tg3_test_memory(struct tg3 *tp)
if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
mem_tbl = mem_tbl_5755;
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
mem_tbl = mem_tbl_5906;
@@ -9036,6 +9370,7 @@ out:
static int tg3_test_loopback(struct tg3 *tp)
{
int err = 0;
+ u32 cpmuctrl = 0;
if (!netif_running(tp->dev))
return TG3_LOOPBACK_FAILED;
@@ -9044,8 +9379,40 @@ static int tg3_test_loopback(struct tg3 *tp)
if (err)
return TG3_LOOPBACK_FAILED;
+ if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) {
+ int i;
+ u32 status;
+
+ tw32(TG3_CPMU_MUTEX_REQ, CPMU_MUTEX_REQ_DRIVER);
+
+ /* Wait for up to 40 microseconds to acquire lock. */
+ for (i = 0; i < 4; i++) {
+ status = tr32(TG3_CPMU_MUTEX_GNT);
+ if (status == CPMU_MUTEX_GNT_DRIVER)
+ break;
+ udelay(10);
+ }
+
+ if (status != CPMU_MUTEX_GNT_DRIVER)
+ return TG3_LOOPBACK_FAILED;
+
+ /* Turn off power management based on link speed. */
+ cpmuctrl = tr32(TG3_CPMU_CTRL);
+ tw32(TG3_CPMU_CTRL,
+ cpmuctrl & ~(CPMU_CTRL_LINK_SPEED_MODE |
+ CPMU_CTRL_LINK_AWARE_MODE));
+ }
+
if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
err |= TG3_MAC_LOOPBACK_FAILED;
+
+ if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) {
+ tw32(TG3_CPMU_CTRL, cpmuctrl);
+
+ /* Release the mutex */
+ tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER);
+ }
+
if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK))
err |= TG3_PHY_LOOPBACK_FAILED;
@@ -9284,20 +9651,16 @@ static const struct ethtool_ops tg3_ethtool_ops = {
.set_pauseparam = tg3_set_pauseparam,
.get_rx_csum = tg3_get_rx_csum,
.set_rx_csum = tg3_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = tg3_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = tg3_set_tso,
- .self_test_count = tg3_get_test_count,
.self_test = tg3_self_test,
.get_strings = tg3_get_strings,
.phys_id = tg3_phys_id,
- .get_stats_count = tg3_get_stats_count,
.get_ethtool_stats = tg3_get_ethtool_stats,
.get_coalesce = tg3_get_coalesce,
.set_coalesce = tg3_set_coalesce,
+ .get_sset_count = tg3_get_sset_count,
};
static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
@@ -9555,6 +9918,81 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp)
}
}
+static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp)
+{
+ u32 nvcfg1, protect = 0;
+
+ nvcfg1 = tr32(NVRAM_CFG1);
+
+ /* NVRAM protection for TPM */
+ if (nvcfg1 & (1 << 27)) {
+ tp->tg3_flags2 |= TG3_FLG2_PROTECTED_NVRAM;
+ protect = 1;
+ }
+
+ nvcfg1 &= NVRAM_CFG1_5752VENDOR_MASK;
+ switch (nvcfg1) {
+ case FLASH_5761VENDOR_ATMEL_ADB021D:
+ case FLASH_5761VENDOR_ATMEL_ADB041D:
+ case FLASH_5761VENDOR_ATMEL_ADB081D:
+ case FLASH_5761VENDOR_ATMEL_ADB161D:
+ case FLASH_5761VENDOR_ATMEL_MDB021D:
+ case FLASH_5761VENDOR_ATMEL_MDB041D:
+ case FLASH_5761VENDOR_ATMEL_MDB081D:
+ case FLASH_5761VENDOR_ATMEL_MDB161D:
+ tp->nvram_jedecnum = JEDEC_ATMEL;
+ tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS;
+ tp->nvram_pagesize = 256;
+ break;
+ case FLASH_5761VENDOR_ST_A_M45PE20:
+ case FLASH_5761VENDOR_ST_A_M45PE40:
+ case FLASH_5761VENDOR_ST_A_M45PE80:
+ case FLASH_5761VENDOR_ST_A_M45PE16:
+ case FLASH_5761VENDOR_ST_M_M45PE20:
+ case FLASH_5761VENDOR_ST_M_M45PE40:
+ case FLASH_5761VENDOR_ST_M_M45PE80:
+ case FLASH_5761VENDOR_ST_M_M45PE16:
+ tp->nvram_jedecnum = JEDEC_ST;
+ tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tp->nvram_pagesize = 256;
+ break;
+ }
+
+ if (protect) {
+ tp->nvram_size = tr32(NVRAM_ADDR_LOCKOUT);
+ } else {
+ switch (nvcfg1) {
+ case FLASH_5761VENDOR_ATMEL_ADB161D:
+ case FLASH_5761VENDOR_ATMEL_MDB161D:
+ case FLASH_5761VENDOR_ST_A_M45PE16:
+ case FLASH_5761VENDOR_ST_M_M45PE16:
+ tp->nvram_size = 0x100000;
+ break;
+ case FLASH_5761VENDOR_ATMEL_ADB081D:
+ case FLASH_5761VENDOR_ATMEL_MDB081D:
+ case FLASH_5761VENDOR_ST_A_M45PE80:
+ case FLASH_5761VENDOR_ST_M_M45PE80:
+ tp->nvram_size = 0x80000;
+ break;
+ case FLASH_5761VENDOR_ATMEL_ADB041D:
+ case FLASH_5761VENDOR_ATMEL_MDB041D:
+ case FLASH_5761VENDOR_ST_A_M45PE40:
+ case FLASH_5761VENDOR_ST_M_M45PE40:
+ tp->nvram_size = 0x40000;
+ break;
+ case FLASH_5761VENDOR_ATMEL_ADB021D:
+ case FLASH_5761VENDOR_ATMEL_MDB021D:
+ case FLASH_5761VENDOR_ST_A_M45PE20:
+ case FLASH_5761VENDOR_ST_M_M45PE20:
+ tp->nvram_size = 0x20000;
+ break;
+ }
+ }
+}
+
static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp)
{
tp->nvram_jedecnum = JEDEC_ATMEL;
@@ -9594,8 +10032,11 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
tg3_get_5752_nvram_info(tp);
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
tg3_get_5755_nvram_info(tp);
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
tg3_get_5787_nvram_info(tp);
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ tg3_get_5761_nvram_info(tp);
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
tg3_get_5906_nvram_info(tp);
else
@@ -9673,6 +10114,7 @@ static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr)
if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
(tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
(tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+ !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) &&
(tp->nvram_jedecnum == JEDEC_ATMEL))
addr = ((addr / tp->nvram_pagesize) <<
@@ -9687,6 +10129,7 @@ static u32 tg3_nvram_logical_addr(struct tg3 *tp, u32 addr)
if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
(tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
(tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+ !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) &&
(tp->nvram_jedecnum == JEDEC_ATMEL))
addr = ((addr >> ATMEL_AT45DB0X1B_PAGE_POS) *
@@ -9907,6 +10350,8 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) &&
(tp->nvram_jedecnum == JEDEC_ST) &&
(nvram_cmd & NVRAM_CMD_FIRST)) {
@@ -10077,8 +10522,12 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT;
tp->tg3_flags2 |= TG3_FLG2_IS_NIC;
}
- if (tr32(VCPU_CFGSHDW) & VCPU_CFGSHDW_ASPM_DBNC)
+ val = tr32(VCPU_CFGSHDW);
+ if (val & VCPU_CFGSHDW_ASPM_DBNC)
tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
+ if ((val & VCPU_CFGSHDW_WOL_ENABLE) &&
+ (val & VCPU_CFGSHDW_WOL_MAGPKT))
+ tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
return;
}
@@ -10178,6 +10627,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL)
tp->led_ctrl = LED_CTRL_MODE_PHY_2;
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
+ tp->pci_chip_rev_id == CHIPREV_ID_5784_A1)
+ tp->led_ctrl = LED_CTRL_MODE_MAC;
+
if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) {
tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
if ((tp->pdev->subsystem_vendor ==
@@ -10195,10 +10648,16 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
}
+ if (nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE)
+ tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE;
if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
!(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL))
tp->tg3_flags &= ~TG3_FLAG_WOL_CAP;
+ if (tp->tg3_flags & TG3_FLAG_WOL_CAP &&
+ nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)
+ tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
+
if (cfg2 & (1 << 17))
tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING;
@@ -10227,7 +10686,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
* firwmare access to the PHY hardware.
*/
err = 0;
- if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+ if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+ (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
hw_phy_id = hw_phy_id_masked = PHY_ID_INVALID;
} else {
/* Now read the physical PHY_ID from the chip and verify
@@ -10274,6 +10734,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
}
if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) &&
+ !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) &&
!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
u32 bmsr, adv_reg, tg3_ctrl, mask;
@@ -10443,9 +10904,24 @@ out_not_found:
strcpy(tp->board_part_number, "none");
}
+static int __devinit tg3_fw_img_is_valid(struct tg3 *tp, u32 offset)
+{
+ u32 val;
+
+ if (tg3_nvram_read_swab(tp, offset, &val) ||
+ (val & 0xfc000000) != 0x0c000000 ||
+ tg3_nvram_read_swab(tp, offset + 4, &val) ||
+ val != 0)
+ return 0;
+
+ return 1;
+}
+
static void __devinit tg3_read_fw_ver(struct tg3 *tp)
{
u32 val, offset, start;
+ u32 ver_offset;
+ int i, bcnt;
if (tg3_nvram_read_swab(tp, 0, &val))
return;
@@ -10458,29 +10934,71 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
return;
offset = tg3_nvram_logical_addr(tp, offset);
- if (tg3_nvram_read_swab(tp, offset, &val))
+
+ if (!tg3_fw_img_is_valid(tp, offset) ||
+ tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
return;
- if ((val & 0xfc000000) == 0x0c000000) {
- u32 ver_offset, addr;
- int i;
+ offset = offset + ver_offset - start;
+ for (i = 0; i < 16; i += 4) {
+ if (tg3_nvram_read(tp, offset + i, &val))
+ return;
+
+ val = le32_to_cpu(val);
+ memcpy(tp->fw_ver + i, &val, 4);
+ }
+
+ if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+ (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+ return;
- if (tg3_nvram_read_swab(tp, offset + 4, &val) ||
- tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
+ for (offset = TG3_NVM_DIR_START;
+ offset < TG3_NVM_DIR_END;
+ offset += TG3_NVM_DIRENT_SIZE) {
+ if (tg3_nvram_read_swab(tp, offset, &val))
return;
- if (val != 0)
+ if ((val >> TG3_NVM_DIRTYPE_SHIFT) == TG3_NVM_DIRTYPE_ASFINI)
+ break;
+ }
+
+ if (offset == TG3_NVM_DIR_END)
+ return;
+
+ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ start = 0x08000000;
+ else if (tg3_nvram_read_swab(tp, offset - 4, &start))
+ return;
+
+ if (tg3_nvram_read_swab(tp, offset + 4, &offset) ||
+ !tg3_fw_img_is_valid(tp, offset) ||
+ tg3_nvram_read_swab(tp, offset + 8, &val))
+ return;
+
+ offset += val - start;
+
+ bcnt = strlen(tp->fw_ver);
+
+ tp->fw_ver[bcnt++] = ',';
+ tp->fw_ver[bcnt++] = ' ';
+
+ for (i = 0; i < 4; i++) {
+ if (tg3_nvram_read(tp, offset, &val))
return;
- addr = offset + ver_offset - start;
- for (i = 0; i < 16; i += 4) {
- if (tg3_nvram_read(tp, addr + i, &val))
- return;
+ val = le32_to_cpu(val);
+ offset += sizeof(val);
- val = cpu_to_le32(val);
- memcpy(tp->fw_ver + i, &val, 4);
+ if (bcnt > TG3_VER_SIZE - sizeof(val)) {
+ memcpy(&tp->fw_ver[bcnt], &val, TG3_VER_SIZE - bcnt);
+ break;
}
+
+ memcpy(&tp->fw_ver[bcnt], &val, sizeof(val));
+ bcnt += sizeof(val);
}
+
+ tp->fw_ver[TG3_VER_SIZE - 1] = 0;
}
static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
@@ -10525,6 +11043,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->pci_chip_rev_id = (misc_ctrl_reg >>
MISC_HOST_CTRL_CHIPREV_SHIFT);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) {
+ u32 prod_id_asic_rev;
+
+ pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV,
+ &prod_id_asic_rev);
+ tp->pci_chip_rev_id = prod_id_asic_rev & PROD_ID_ASIC_REV_MASK;
+ }
/* Wrong chip ID in 5752 A0. This code can be removed later
* as A0 is not in production.
@@ -10644,6 +11169,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
@@ -10663,6 +11190,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
@@ -10680,12 +11209,17 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE;
pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP);
if (pcie_cap != 0) {
tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
+
+ pcie_set_readrq(tp->pdev, 4096);
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
u16 lnkctl;
@@ -10720,10 +11254,20 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
cacheline_sz_reg);
}
+ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
+ (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+ tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX);
+ if (!tp->pcix_cap) {
+ printk(KERN_ERR PFX "Cannot find PCI-X "
+ "capability, aborting.\n");
+ return -EIO;
+ }
+ }
+
pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
&pci_state_reg);
- if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) {
+ if (tp->pcix_cap && (pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) {
tp->tg3_flags |= TG3_FLAG_PCIX_MODE;
/* If this is a 5700 BX chipset, and we are in PCI-X
@@ -10734,7 +11278,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
*/
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) {
u32 pm_reg;
- u16 pci_cmd;
tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
@@ -10742,11 +11285,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
* space registers clobbered due to this bug.
* So explicitly force the chip into D0 here.
*/
- pci_read_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT,
+ pci_read_config_dword(tp->pdev,
+ tp->pm_cap + PCI_PM_CTRL,
&pm_reg);
pm_reg &= ~PCI_PM_CTRL_STATE_MASK;
pm_reg |= PCI_PM_CTRL_PME_ENABLE | 0 /* D0 */;
- pci_write_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT,
+ pci_write_config_dword(tp->pdev,
+ tp->pm_cap + PCI_PM_CTRL,
pm_reg);
/* Also, force SERR#/PERR# in PCI command. */
@@ -10844,6 +11389,27 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
*/
tg3_get_eeprom_hw_cfg(tp);
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+ /* Allow reads and writes to the
+ * APE register and memory space.
+ */
+ pci_state_reg |= PCISTATE_ALLOW_APE_CTLSPC_WR |
+ PCISTATE_ALLOW_APE_SHMEM_WR;
+ pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE,
+ pci_state_reg);
+ }
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+ tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;
+
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 ||
+ tp->pci_chip_rev_id == CHIPREV_ID_5784_A1 ||
+ tp->pci_chip_rev_id == CHIPREV_ID_5761_A0 ||
+ tp->pci_chip_rev_id == CHIPREV_ID_5761_A1)
+ tp->tg3_flags3 |= TG3_FLG3_5761_5784_AX_FIXES;
+ }
+
/* Set up tp->grc_local_ctrl before calling tg3_set_power_state().
* GPIO1 driven high will bring 5700's external PHY out of reset.
* It is also used as eeprom write protect on LOMs.
@@ -10910,7 +11476,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 &&
tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722)
tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
@@ -11053,6 +11621,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
tp->dev->hard_start_xmit = tg3_start_xmit;
else
@@ -11073,11 +11643,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
tp->rx_std_max_post = 8;
- /* By default, disable wake-on-lan. User can change this
- * using ETHTOOL_SWOL.
- */
- tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
-
if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND)
tp->pwrmgmt_thresh = tr32(PCIE_PWR_MGMT_THRESH) &
PCIE_PWR_MGMT_L1_THRESH_MSK;
@@ -11674,8 +12239,10 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
case PHY_ID_BCM5780: return "5780";
case PHY_ID_BCM5755: return "5755";
case PHY_ID_BCM5787: return "5787";
+ case PHY_ID_BCM5784: return "5784";
case PHY_ID_BCM5756: return "5722/5756";
case PHY_ID_BCM5906: return "5906";
+ case PHY_ID_BCM5761: return "5761";
case PHY_ID_BCM8002: return "8002/serdes";
case 0: return "serdes";
default: return "unknown";
@@ -11833,7 +12400,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
goto err_out_free_res;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
#if TG3_VLAN_TAG_USED
@@ -11880,7 +12446,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
INIT_WORK(&tp->reset_task, tg3_reset_task);
tp->regs = ioremap_nocache(tg3reg_base, tg3reg_len);
- if (tp->regs == 0UL) {
+ if (!tp->regs) {
printk(KERN_ERR PFX "Cannot map device registers, "
"aborting.\n");
err = -ENOMEM;
@@ -11900,9 +12466,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
dev->set_mac_address = tg3_set_mac_addr;
dev->do_ioctl = tg3_ioctl;
dev->tx_timeout = tg3_tx_timeout;
- dev->poll = tg3_poll;
+ netif_napi_add(dev, &tp->napi, tg3_poll, 64);
dev->ethtool_ops = &tg3_ethtool_ops;
- dev->weight = 64;
dev->watchdog_timeo = TG3_TX_TIMEOUT;
dev->change_mtu = tg3_change_mtu;
dev->irq = pdev->irq;
@@ -11980,6 +12545,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906))
dev->features |= NETIF_F_TSO6;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ dev->features |= NETIF_F_TSO_ECN;
}
@@ -11997,6 +12564,28 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
goto err_out_iounmap;
}
+ if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+ if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+ printk(KERN_ERR PFX "Cannot find proper PCI device "
+ "base address for APE, aborting.\n");
+ err = -ENODEV;
+ goto err_out_iounmap;
+ }
+
+ tg3reg_base = pci_resource_start(pdev, 2);
+ tg3reg_len = pci_resource_len(pdev, 2);
+
+ tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len);
+ if (tp->aperegs == 0UL) {
+ printk(KERN_ERR PFX "Cannot map APE registers, "
+ "aborting.\n");
+ err = -ENOMEM;
+ goto err_out_iounmap;
+ }
+
+ tg3_ape_lock_init(tp);
+ }
+
/*
* Reset chip in case UNDI or EFI driver did not shutdown
* DMA self test will enable WDMAC and we'll see (spurious)
@@ -12011,7 +12600,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
err = tg3_test_dma(tp);
if (err) {
printk(KERN_ERR PFX "DMA engine test failed, aborting.\n");
- goto err_out_iounmap;
+ goto err_out_apeunmap;
}
/* Tigon3 can do ipv4 only... and some chips have buggy
@@ -12020,7 +12609,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) {
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
dev->features |= NETIF_F_IPV6_CSUM;
tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
@@ -12038,7 +12629,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
if (err) {
printk(KERN_ERR PFX "Cannot register net device, "
"aborting.\n");
- goto err_out_iounmap;
+ goto err_out_apeunmap;
}
printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %s Ethernet ",
@@ -12071,6 +12662,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
return 0;
+err_out_apeunmap:
+ if (tp->aperegs) {
+ iounmap(tp->aperegs);
+ tp->aperegs = NULL;
+ }
+
err_out_iounmap:
if (tp->regs) {
iounmap(tp->regs);
@@ -12098,6 +12695,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
flush_scheduled_work();
unregister_netdev(dev);
+ if (tp->aperegs) {
+ iounmap(tp->aperegs);
+ tp->aperegs = NULL;
+ }
if (tp->regs) {
iounmap(tp->regs);
tp->regs = NULL;
@@ -12176,11 +12777,6 @@ static int tg3_resume(struct pci_dev *pdev)
if (err)
return err;
- /* Hardware bug - MSI won't work if INTX disabled. */
- if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) &&
- (tp->tg3_flags2 & TG3_FLG2_USING_MSI))
- pci_intx(tp->pdev, 1);
-
netif_device_attach(dev);
tg3_full_lock(tp, 0);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 5c21f49026c..da18fb22071 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -57,32 +57,7 @@
#define TG3PCI_IRQ_PIN 0x0000003d
#define TG3PCI_MIN_GNT 0x0000003e
#define TG3PCI_MAX_LAT 0x0000003f
-#define TG3PCI_X_CAPS 0x00000040
-#define PCIX_CAPS_RELAXED_ORDERING 0x00020000
-#define PCIX_CAPS_SPLIT_MASK 0x00700000
-#define PCIX_CAPS_SPLIT_SHIFT 20
-#define PCIX_CAPS_BURST_MASK 0x000c0000
-#define PCIX_CAPS_BURST_SHIFT 18
-#define PCIX_CAPS_MAX_BURST_CPIOB 2
-#define TG3PCI_PM_CAP_PTR 0x00000041
-#define TG3PCI_X_COMMAND 0x00000042
-#define TG3PCI_X_STATUS 0x00000044
-#define TG3PCI_PM_CAP_ID 0x00000048
-#define TG3PCI_VPD_CAP_PTR 0x00000049
-#define TG3PCI_PM_CAPS 0x0000004a
-#define TG3PCI_PM_CTRL_STAT 0x0000004c
-#define TG3PCI_BR_SUPP_EXT 0x0000004e
-#define TG3PCI_PM_DATA 0x0000004f
-#define TG3PCI_VPD_CAP_ID 0x00000050
-#define TG3PCI_MSI_CAP_PTR 0x00000051
-#define TG3PCI_VPD_ADDR_FLAG 0x00000052
-#define VPD_ADDR_FLAG_WRITE 0x00008000
-#define TG3PCI_VPD_DATA 0x00000054
-#define TG3PCI_MSI_CAP_ID 0x00000058
-#define TG3PCI_NXT_CAP_PTR 0x00000059
-#define TG3PCI_MSI_CTRL 0x0000005a
-#define TG3PCI_MSI_ADDR_LOW 0x0000005c
-#define TG3PCI_MSI_ADDR_HIGH 0x00000060
+/* 0x40 --> 0x64 unused */
#define TG3PCI_MSI_DATA 0x00000064
/* 0x66 --> 0x68 unused */
#define TG3PCI_MISC_HOST_CTRL 0x00000068
@@ -133,6 +108,10 @@
#define CHIPREV_ID_5752_A1 0x6001
#define CHIPREV_ID_5714_A2 0x9002
#define CHIPREV_ID_5906_A1 0xc001
+#define CHIPREV_ID_5784_A0 0x5784000
+#define CHIPREV_ID_5784_A1 0x5784001
+#define CHIPREV_ID_5761_A0 0x5761000
+#define CHIPREV_ID_5761_A1 0x5761001
#define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12)
#define ASIC_REV_5700 0x07
#define ASIC_REV_5701 0x00
@@ -146,6 +125,9 @@
#define ASIC_REV_5755 0x0a
#define ASIC_REV_5787 0x0b
#define ASIC_REV_5906 0x0c
+#define ASIC_REV_USE_PROD_ID_REG 0x0f
+#define ASIC_REV_5784 0x5784
+#define ASIC_REV_5761 0x5761
#define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8)
#define CHIPREV_5700_AX 0x70
#define CHIPREV_5700_BX 0x71
@@ -213,6 +195,8 @@
#define PCISTATE_ROM_RETRY_ENABLE 0x00000040
#define PCISTATE_FLAT_VIEW 0x00000100
#define PCISTATE_RETRY_SAME_DMA 0x00002000
+#define PCISTATE_ALLOW_APE_CTLSPC_WR 0x00010000
+#define PCISTATE_ALLOW_APE_SHMEM_WR 0x00020000
#define TG3PCI_CLOCK_CTRL 0x00000074
#define CLOCK_CTRL_CORECLK_DISABLE 0x00000200
#define CLOCK_CTRL_RXCLK_DISABLE 0x00000400
@@ -239,7 +223,9 @@
#define TG3PCI_DUAL_MAC_CTRL 0x000000b8
#define DUAL_MAC_CTRL_CH_MASK 0x00000003
#define DUAL_MAC_CTRL_ID 0x00000004
-/* 0xbc --> 0x100 unused */
+#define TG3PCI_PRODID_ASICREV 0x000000bc
+#define PROD_ID_ASIC_REV_MASK 0x0fffffff
+/* 0xc0 --> 0x100 unused */
/* 0x100 --> 0x200 unused */
@@ -683,6 +669,7 @@
#define SNDDATAC_MODE 0x00001000
#define SNDDATAC_MODE_RESET 0x00000001
#define SNDDATAC_MODE_ENABLE 0x00000002
+#define SNDDATAC_MODE_CDELAY 0x00000010
/* 0x1004 --> 0x1400 unused */
/* Send BD ring selector */
@@ -865,7 +852,44 @@
#define RCVLSC_MODE_ATTN_ENABLE 0x00000004
#define RCVLSC_STATUS 0x00003404
#define RCVLSC_STATUS_ERROR_ATTN 0x00000004
-/* 0x3408 --> 0x3800 unused */
+/* 0x3408 --> 0x3600 unused */
+
+/* CPMU registers */
+#define TG3_CPMU_CTRL 0x00003600
+#define CPMU_CTRL_LINK_IDLE_MODE 0x00000200
+#define CPMU_CTRL_LINK_AWARE_MODE 0x00000400
+#define CPMU_CTRL_LINK_SPEED_MODE 0x00004000
+#define TG3_CPMU_LSPD_10MB_CLK 0x00003604
+#define CPMU_LSPD_10MB_MACCLK_MASK 0x001f0000
+#define CPMU_LSPD_10MB_MACCLK_6_25 0x00130000
+/* 0x3608 --> 0x360c unused */
+
+#define TG3_CPMU_LSPD_1000MB_CLK 0x0000360c
+#define CPMU_LSPD_1000MB_MACCLK_62_5 0x00000000
+#define CPMU_LSPD_1000MB_MACCLK_12_5 0x00110000
+#define CPMU_LSPD_1000MB_MACCLK_MASK 0x001f0000
+#define TG3_CPMU_LNK_AWARE_PWRMD 0x00003610
+#define CPMU_LNK_AWARE_MACCLK_MASK 0x001f0000
+#define CPMU_LNK_AWARE_MACCLK_6_25 0x00130000
+/* 0x3614 --> 0x361c unused */
+
+#define TG3_CPMU_HST_ACC 0x0000361c
+#define CPMU_HST_ACC_MACCLK_MASK 0x001f0000
+#define CPMU_HST_ACC_MACCLK_6_25 0x00130000
+/* 0x3620 --> 0x3630 unused */
+
+#define TG3_CPMU_CLCK_STAT 0x00003630
+#define CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001f0000
+#define CPMU_CLCK_STAT_MAC_CLCK_62_5 0x00000000
+#define CPMU_CLCK_STAT_MAC_CLCK_12_5 0x00110000
+#define CPMU_CLCK_STAT_MAC_CLCK_6_25 0x00130000
+/* 0x3634 --> 0x365c unused */
+
+#define TG3_CPMU_MUTEX_REQ 0x0000365c
+#define CPMU_MUTEX_REQ_DRIVER 0x00001000
+#define TG3_CPMU_MUTEX_GNT 0x00003660
+#define CPMU_MUTEX_GNT_DRIVER 0x00001000
+/* 0x3664 --> 0x3800 unused */
/* Mbuf cluster free registers */
#define MBFREE_MODE 0x00003800
@@ -1045,7 +1069,10 @@
#define RDMAC_MODE_FIFOOREAD_ENAB 0x00000100
#define RDMAC_MODE_LNGREAD_ENAB 0x00000200
#define RDMAC_MODE_SPLIT_ENABLE 0x00000800
+#define RDMAC_MODE_BD_SBD_CRPT_ENAB 0x00000800
#define RDMAC_MODE_SPLIT_RESET 0x00001000
+#define RDMAC_MODE_MBUF_RBD_CRPT_ENAB 0x00001000
+#define RDMAC_MODE_MBUF_SBD_CRPT_ENAB 0x00002000
#define RDMAC_MODE_FIFO_SIZE_128 0x00020000
#define RDMAC_MODE_FIFO_LONG_BURST 0x00030000
#define RDMAC_STATUS 0x00004804
@@ -1151,6 +1178,8 @@
#define VCPU_STATUS_DRV_RESET 0x08000000
#define VCPU_CFGSHDW 0x00005104
+#define VCPU_CFGSHDW_WOL_ENABLE 0x00000001
+#define VCPU_CFGSHDW_WOL_MAGPKT 0x00000004
#define VCPU_CFGSHDW_ASPM_DBNC 0x00001000
/* Mailboxes */
@@ -1474,6 +1503,22 @@
#define FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ 0x03000002
#define FLASH_5787VENDOR_MICRO_EEPROM_64KHZ 0x03000000
#define FLASH_5787VENDOR_MICRO_EEPROM_376KHZ 0x02000000
+#define FLASH_5761VENDOR_ATMEL_MDB021D 0x00800003
+#define FLASH_5761VENDOR_ATMEL_MDB041D 0x00800000
+#define FLASH_5761VENDOR_ATMEL_MDB081D 0x00800002
+#define FLASH_5761VENDOR_ATMEL_MDB161D 0x00800001
+#define FLASH_5761VENDOR_ATMEL_ADB021D 0x00000003
+#define FLASH_5761VENDOR_ATMEL_ADB041D 0x00000000
+#define FLASH_5761VENDOR_ATMEL_ADB081D 0x00000002
+#define FLASH_5761VENDOR_ATMEL_ADB161D 0x00000001
+#define FLASH_5761VENDOR_ST_M_M45PE20 0x02800001
+#define FLASH_5761VENDOR_ST_M_M45PE40 0x02800000
+#define FLASH_5761VENDOR_ST_M_M45PE80 0x02800002
+#define FLASH_5761VENDOR_ST_M_M45PE16 0x02800003
+#define FLASH_5761VENDOR_ST_A_M45PE20 0x02000001
+#define FLASH_5761VENDOR_ST_A_M45PE40 0x02000000
+#define FLASH_5761VENDOR_ST_A_M45PE80 0x02000002
+#define FLASH_5761VENDOR_ST_A_M45PE16 0x02000003
#define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000
#define FLASH_5752PAGE_SIZE_256 0x00000000
#define FLASH_5752PAGE_SIZE_512 0x10000000
@@ -1504,9 +1549,11 @@
#define ACCESS_ENABLE 0x00000001
#define ACCESS_WR_ENABLE 0x00000002
#define NVRAM_WRITE1 0x00007028
-/* 0x702c --> 0x7400 unused */
+/* 0x702c unused */
+
+#define NVRAM_ADDR_LOCKOUT 0x00007030
+/* 0x7034 --> 0x7c00 unused */
-/* 0x7400 --> 0x7c00 unused */
#define PCIE_TRANSACTION_CFG 0x00007c04
#define PCIE_TRANS_CFG_1SHOT_MSI 0x20000000
#define PCIE_TRANS_CFG_LOM 0x00000020
@@ -1517,9 +1564,21 @@
#define TG3_EEPROM_MAGIC 0x669955aa
#define TG3_EEPROM_MAGIC_FW 0xa5000000
#define TG3_EEPROM_MAGIC_FW_MSK 0xff000000
+#define TG3_EEPROM_SB_FORMAT_MASK 0x00e00000
+#define TG3_EEPROM_SB_FORMAT_1 0x00200000
+#define TG3_EEPROM_SB_REVISION_MASK 0x001f0000
+#define TG3_EEPROM_SB_REVISION_0 0x00000000
+#define TG3_EEPROM_SB_REVISION_2 0x00020000
+#define TG3_EEPROM_SB_REVISION_3 0x00030000
#define TG3_EEPROM_MAGIC_HW 0xabcd
#define TG3_EEPROM_MAGIC_HW_MSK 0xffff
+#define TG3_NVM_DIR_START 0x18
+#define TG3_NVM_DIR_END 0x78
+#define TG3_NVM_DIRENT_SIZE 0xc
+#define TG3_NVM_DIRTYPE_SHIFT 24
+#define TG3_NVM_DIRTYPE_ASFINI 1
+
/* 32K Window into NIC internal memory */
#define NIC_SRAM_WIN_BASE 0x00008000
@@ -1552,6 +1611,7 @@
#define NIC_SRAM_DATA_CFG_MINI_PCI 0x00001000
#define NIC_SRAM_DATA_CFG_FIBER_WOL 0x00004000
#define NIC_SRAM_DATA_CFG_NO_GPIO2 0x00100000
+#define NIC_SRAM_DATA_CFG_APE_ENABLE 0x00200000
#define NIC_SRAM_DATA_VER 0x00000b5c
#define NIC_SRAM_DATA_VER_SHIFT 16
@@ -1664,6 +1724,12 @@
#define MII_TG3_ISTAT 0x1a /* IRQ status register */
#define MII_TG3_IMASK 0x1b /* IRQ mask register */
+#define MII_TG3_MISC_SHDW 0x1c
+#define MII_TG3_MISC_SHDW_WREN 0x8000
+#define MII_TG3_MISC_SHDW_APD_SEL 0x2800
+
+#define MII_TG3_MISC_SHDW_APD_WKTM_84MS 0x0001
+
/* ISTAT/IMASK event bits */
#define MII_TG3_INT_LINKCHG 0x0002
#define MII_TG3_INT_SPEEDCHG 0x0004
@@ -1680,6 +1746,49 @@
#define MII_TG3_TEST1_TRIM_EN 0x0010
#define MII_TG3_TEST1_CRC_EN 0x8000
+/* APE registers. Accessible through BAR1 */
+#define TG3_APE_EVENT 0x000c
+#define APE_EVENT_1 0x00000001
+#define TG3_APE_LOCK_REQ 0x002c
+#define APE_LOCK_REQ_DRIVER 0x00001000
+#define TG3_APE_LOCK_GRANT 0x004c
+#define APE_LOCK_GRANT_DRIVER 0x00001000
+#define TG3_APE_SEG_SIG 0x4000
+#define APE_SEG_SIG_MAGIC 0x41504521
+
+/* APE shared memory. Accessible through BAR1 */
+#define TG3_APE_FW_STATUS 0x400c
+#define APE_FW_STATUS_READY 0x00000100
+#define TG3_APE_HOST_SEG_SIG 0x4200
+#define APE_HOST_SEG_SIG_MAGIC 0x484f5354
+#define TG3_APE_HOST_SEG_LEN 0x4204
+#define APE_HOST_SEG_LEN_MAGIC 0x0000001c
+#define TG3_APE_HOST_INIT_COUNT 0x4208
+#define TG3_APE_HOST_DRIVER_ID 0x420c
+#define APE_HOST_DRIVER_ID_MAGIC 0xf0035100
+#define TG3_APE_HOST_BEHAVIOR 0x4210
+#define APE_HOST_BEHAV_NO_PHYLOCK 0x00000001
+#define TG3_APE_HOST_HEARTBEAT_INT_MS 0x4214
+#define APE_HOST_HEARTBEAT_INT_DISABLE 0
+#define APE_HOST_HEARTBEAT_INT_5SEC 5000
+#define TG3_APE_HOST_HEARTBEAT_COUNT 0x4218
+
+#define TG3_APE_EVENT_STATUS 0x4300
+
+#define APE_EVENT_STATUS_DRIVER_EVNT 0x00000010
+#define APE_EVENT_STATUS_STATE_CHNGE 0x00000500
+#define APE_EVENT_STATUS_STATE_START 0x00010000
+#define APE_EVENT_STATUS_STATE_UNLOAD 0x00020000
+#define APE_EVENT_STATUS_STATE_WOL 0x00030000
+#define APE_EVENT_STATUS_STATE_SUSPEND 0x00040000
+#define APE_EVENT_STATUS_EVENT_PENDING 0x80000000
+
+/* APE convenience enumerations. */
+#define TG3_APE_LOCK_MEM 4
+
+#define TG3_EEPROM_SB_F1R2_MBA_OFF 0x10
+
+
/* There are two ways to manage the TX descriptors on the tigon3.
* Either the descriptors are in host DMA'able memory, or they
* exist only in the cards on-chip SRAM. All 16 send bds are under
@@ -2155,6 +2264,7 @@ struct tg3 {
void (*write32_mbox) (struct tg3 *, u32,
u32);
void __iomem *regs;
+ void __iomem *aperegs;
struct net_device *dev;
struct pci_dev *pdev;
@@ -2176,6 +2286,7 @@ struct tg3 {
dma_addr_t tx_desc_mapping;
/* begin "rx thread" cacheline section */
+ struct napi_struct napi;
void (*write32_rx_mbox) (struct tg3 *, u32,
u32);
u32 rx_rcb_ptr;
@@ -2237,7 +2348,7 @@ struct tg3 {
#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000
#define TG3_FLAG_10_100_ONLY 0x01000000
#define TG3_FLAG_PAUSE_AUTONEG 0x02000000
-
+#define TG3_FLAG_CPMU_PRESENT 0x04000000
#define TG3_FLAG_40BIT_DMA_BUG 0x08000000
#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000
#define TG3_FLAG_SUPPORT_MSI 0x20000000
@@ -2279,6 +2390,10 @@ struct tg3 {
#define TG3_FLG2_PHY_JITTER_BUG 0x20000000
#define TG3_FLG2_NO_FWARE_REPORTED 0x40000000
#define TG3_FLG2_PHY_ADJUST_TRIM 0x80000000
+ u32 tg3_flags3;
+#define TG3_FLG3_NO_NVRAM_ADDR_TRANS 0x00000001
+#define TG3_FLG3_ENABLE_APE 0x00000002
+#define TG3_FLG3_5761_5784_AX_FIXES 0x00000004
struct timer_list timer;
u16 timer_counter;
@@ -2309,7 +2424,7 @@ struct tg3 {
u32 pwrmgmt_thresh;
/* PCI block */
- u16 pci_chip_rev_id;
+ u32 pci_chip_rev_id;
u8 pci_cacheline_sz;
u8 pci_lat_timer;
u8 pci_hdr_type;
@@ -2317,6 +2432,7 @@ struct tg3 {
int pm_cap;
int msi_cap;
+ int pcix_cap;
/* PHY info */
u32 phy_id;
@@ -2335,6 +2451,8 @@ struct tg3 {
#define PHY_ID_BCM5755 0xbc050cc0
#define PHY_ID_BCM5787 0xbc050ce0
#define PHY_ID_BCM5756 0xbc050ed0
+#define PHY_ID_BCM5784 0xbc050fa0
+#define PHY_ID_BCM5761 0xbc050fd0
#define PHY_ID_BCM5906 0xdc00ac40
#define PHY_ID_BCM8002 0x60010140
#define PHY_ID_INVALID 0xffffffff
@@ -2345,10 +2463,11 @@ struct tg3 {
#define PHY_REV_BCM5411_X0 0x1 /* Found on Netgear GA302T */
u32 led_ctrl;
- u32 pci_cmd;
+ u16 pci_cmd;
char board_part_number[24];
- char fw_ver[16];
+#define TG3_VER_SIZE 32
+ char fw_ver[TG3_VER_SIZE];
u32 nic_sram_data_cfg;
u32 pci_clock_ctrl;
struct pci_dev *pdev_peer;
@@ -2364,7 +2483,8 @@ struct tg3 {
(X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \
(X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
(X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \
- (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002)
+ (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM5761 || \
+ (X) == PHY_ID_BCM8002)
struct tg3_hw_stats *hw_stats;
dma_addr_t stats_mapping;
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 74eb12107e6..c99ce74a7af 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -556,7 +556,6 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
rc = -ENOMEM;
goto err_out_regions;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
priv = netdev_priv(dev);
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index 9f1b6ab9c22..5d31519a6c6 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -156,7 +156,7 @@ static void print_rx_state(struct net_device *dev) ;
static void print_tx_state(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
struct xl_tx_desc *txd ;
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
int i ;
@@ -179,7 +179,7 @@ static void print_tx_state(struct net_device *dev)
static void print_rx_state(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
struct xl_rx_desc *rxd ;
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
int i ;
@@ -213,7 +213,7 @@ static void print_rx_state(struct net_device *dev)
static u16 xl_ee_read(struct net_device *dev, int ee_addr)
{
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
/* Wait for EEProm to not be busy */
@@ -245,7 +245,7 @@ static u16 xl_ee_read(struct net_device *dev, int ee_addr)
static void xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value)
{
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
/* Wait for EEProm to not be busy */
@@ -305,11 +305,11 @@ static int __devinit xl_probe(struct pci_dev *pdev,
pci_release_regions(pdev) ;
return -ENOMEM ;
}
- xl_priv = dev->priv ;
+ xl_priv = netdev_priv(dev);
#if XL_DEBUG
printk("pci_device: %p, dev:%p, dev->priv: %p, ba[0]: %10x, ba[1]:%10x\n",
- pdev, dev, dev->priv, (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start) ;
+ pdev, dev, netdev_priv(dev), (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start);
#endif
dev->irq=pdev->irq;
@@ -344,7 +344,6 @@ static int __devinit xl_probe(struct pci_dev *pdev,
dev->set_multicast_list=&xl_set_rx_mode;
dev->get_stats=&xl_get_stats ;
dev->set_mac_address=&xl_set_mac_address ;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
pci_set_drvdata(pdev,dev) ;
@@ -365,7 +364,7 @@ static int __devinit xl_probe(struct pci_dev *pdev,
static int __devinit xl_init(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
printk(KERN_INFO "%s \n", version);
printk(KERN_INFO "%s: I/O at %hx, MMIO at %p, using irq %d\n",
@@ -385,7 +384,7 @@ static int __devinit xl_init(struct net_device *dev)
static int xl_hw_reset(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
unsigned long t ;
u16 i ;
@@ -568,7 +567,7 @@ static int xl_hw_reset(struct net_device *dev)
static int xl_open(struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
u8 i ;
u16 hwaddr[3] ; /* Should be u8[6] but we get word return values */
@@ -641,14 +640,14 @@ static int xl_open(struct net_device *dev)
* Now to set up the Rx and Tx buffer structures
*/
/* These MUST be on 8 byte boundaries */
- xl_priv->xl_tx_ring = kmalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL) ;
+ xl_priv->xl_tx_ring = kzalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL);
if (xl_priv->xl_tx_ring == NULL) {
printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n",
dev->name);
free_irq(dev->irq,dev);
return -ENOMEM;
}
- xl_priv->xl_rx_ring = kmalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL) ;
+ xl_priv->xl_rx_ring = kzalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL);
if (xl_priv->xl_tx_ring == NULL) {
printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n",
dev->name);
@@ -656,8 +655,6 @@ static int xl_open(struct net_device *dev)
kfree(xl_priv->xl_tx_ring);
return -ENOMEM;
}
- memset(xl_priv->xl_tx_ring,0,sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) ;
- memset(xl_priv->xl_rx_ring,0,sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) ;
/* Setup Rx Ring */
for (i=0 ; i < XL_RX_RING_SIZE ; i++) {
@@ -726,7 +723,7 @@ static int xl_open(struct net_device *dev)
static int xl_open_hw(struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
u8 __iomem *xl_mmio = xl_priv->xl_mmio ;
u16 vsoff ;
char ver_str[33];
@@ -763,7 +760,7 @@ static int xl_open_hw(struct net_device *dev)
if (xl_priv->xl_laa[0]) { /* If using a LAA address */
for (i=10;i<16;i++) {
writel( (MEM_BYTE_WRITE | 0xD0000 | xl_priv->srb) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ;
- writeb(xl_priv->xl_laa[i],xl_mmio + MMIO_MACDATA) ;
+ writeb(xl_priv->xl_laa[i-10],xl_mmio + MMIO_MACDATA) ;
}
memcpy(dev->dev_addr,xl_priv->xl_laa,dev->addr_len) ;
} else { /* Regular hardware address */
@@ -875,7 +872,7 @@ static int xl_open_hw(struct net_device *dev)
static void adv_rx_ring(struct net_device *dev) /* Advance rx_ring, cut down on bloat in xl_rx */
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
int prev_ring_loc ;
prev_ring_loc = (xl_priv->rx_ring_tail + XL_RX_RING_SIZE - 1) & (XL_RX_RING_SIZE - 1);
@@ -890,7 +887,7 @@ static void adv_rx_ring(struct net_device *dev) /* Advance rx_ring, cut down on
static void xl_rx(struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
struct sk_buff *skb, *skb2 ;
int frame_length = 0, copy_len = 0 ;
@@ -997,7 +994,7 @@ static void xl_rx(struct net_device *dev)
static void xl_reset(struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
unsigned long t;
@@ -1020,7 +1017,7 @@ static void xl_reset(struct net_device *dev)
static void xl_freemem(struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv=netdev_priv(dev);
int i ;
for (i=0;i<XL_RX_RING_SIZE;i++) {
@@ -1044,15 +1041,10 @@ static void xl_freemem(struct net_device *dev)
static irqreturn_t xl_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
- struct xl_private *xl_priv =(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv =netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
u16 intstatus, macstatus ;
- if (!dev) {
- printk(KERN_WARNING "Device structure dead, aaahhhh !\n") ;
- return IRQ_NONE;
- }
-
intstatus = readw(xl_mmio + MMIO_INTSTATUS) ;
if (!(intstatus & 1)) /* We didn't generate the interrupt */
@@ -1171,7 +1163,7 @@ static irqreturn_t xl_interrupt(int irq, void *dev_id)
static int xl_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
struct xl_tx_desc *txd ;
int tx_head, tx_tail, tx_prev ;
unsigned long flags ;
@@ -1232,7 +1224,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev)
static void xl_dn_comp(struct net_device *dev)
{
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
struct xl_tx_desc *txd ;
@@ -1268,7 +1260,7 @@ static void xl_dn_comp(struct net_device *dev)
static int xl_close(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
unsigned long t ;
@@ -1366,7 +1358,7 @@ static int xl_close(struct net_device *dev)
static void xl_set_rx_mode(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
struct dev_mc_list *dmi ;
unsigned char dev_mc_address[4] ;
u16 options ;
@@ -1407,7 +1399,7 @@ static void xl_set_rx_mode(struct net_device *dev)
static void xl_srb_bh(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
u8 srb_cmd, ret_code ;
int i ;
@@ -1476,14 +1468,14 @@ static void xl_srb_bh(struct net_device *dev)
static struct net_device_stats * xl_get_stats(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
return (struct net_device_stats *) &xl_priv->xl_stats;
}
static int xl_set_mac_address (struct net_device *dev, void *addr)
{
struct sockaddr *saddr = addr ;
- struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
if (netif_running(dev)) {
printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ;
@@ -1504,7 +1496,7 @@ static int xl_set_mac_address (struct net_device *dev, void *addr)
static void xl_arb_cmd(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
u8 arb_cmd ;
u16 lan_status, lan_status_diff ;
@@ -1632,7 +1624,7 @@ static void xl_arb_cmd(struct net_device *dev)
static void xl_asb_cmd(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
if (xl_priv->asb_queued == 1)
@@ -1663,7 +1655,7 @@ static void xl_asb_cmd(struct net_device *dev)
*/
static void xl_asb_bh(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
u8 ret_code ;
@@ -1691,7 +1683,7 @@ static void xl_asb_bh(struct net_device *dev)
static void xl_srb_cmd(struct net_device *dev, int srb_cmd)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
switch (srb_cmd) {
@@ -1748,7 +1740,7 @@ static void xl_srb_cmd(struct net_device *dev, int srb_cmd)
static void xl_wait_misr_flags(struct net_device *dev)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+ struct xl_private *xl_priv = netdev_priv(dev);
u8 __iomem * xl_mmio = xl_priv->xl_mmio ;
int i ;
@@ -1773,7 +1765,7 @@ static void xl_wait_misr_flags(struct net_device *dev)
static int xl_change_mtu(struct net_device *dev, int mtu)
{
- struct xl_private *xl_priv = (struct xl_private *) dev->priv;
+ struct xl_private *xl_priv = netdev_priv(dev);
u16 max_mtu ;
if (xl_priv->xl_ring_speed == 4)
@@ -1795,7 +1787,7 @@ static int xl_change_mtu(struct net_device *dev, int mtu)
static void __devexit xl_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+ struct xl_private *xl_priv=netdev_priv(dev);
unregister_netdev(dev);
iounmap(xl_priv->xl_mmio) ;
diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c
index 1bdd3beefbe..124cfd4fbcf 100644
--- a/drivers/net/tokenring/abyss.c
+++ b/drivers/net/tokenring/abyss.c
@@ -97,8 +97,9 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_
static int versionprinted;
struct net_device *dev;
struct net_local *tp;
- int i, ret, pci_irq_line;
+ int ret, pci_irq_line;
unsigned long pci_ioaddr;
+ DECLARE_MAC_BUF(mac);
if (versionprinted++ == 0)
printk("%s", version);
@@ -116,8 +117,6 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
-
if (!request_region(pci_ioaddr, ABYSS_IO_EXTENT, dev->name)) {
ret = -EBUSY;
goto err_out_trdev;
@@ -147,12 +146,9 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_
}
abyss_read_eeprom(dev);
-
- printk("%s: Ring Station Address: ", dev->name);
- printk("%2.2x", dev->dev_addr[0]);
- for (i = 1; i < 6; i++)
- printk(":%2.2x", dev->dev_addr[i]);
- printk("\n");
+
+ printk("%s: Ring Station Address: %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
tp = netdev_priv(dev);
tp->setnselout = abyss_setnselout_pins;
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 1e8958ee2d0..e494c63bfbd 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -116,9 +116,6 @@ in the event that chatty debug messages are desired - jjs 12/30/98 */
#define ENABLE_PAGING 1
#endif
-#define FALSE 0
-#define TRUE (!FALSE)
-
/* changes the output format of driver initialization */
#define TR_VERBOSE 0
@@ -327,7 +324,7 @@ static void ibmtr_cleanup_card(struct net_device *dev)
release_region(dev->base_addr, IBMTR_IO_EXTENT);
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
iounmap(ti->mmio);
iounmap(ti->sram_virt);
}
@@ -384,7 +381,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0;
void __iomem * t_mmio = NULL;
- struct tok_info *ti = dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
void __iomem *cd_chanid;
unsigned char *tchanid, ctemp;
#ifndef PCMCIA
@@ -392,6 +389,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
unsigned long timeout;
static int version_printed;
#endif
+ DECLARE_MAC_BUF(mac);
/* Query the adapter PIO base port which will return
* indication of where MMIO was placed. We also have a
@@ -705,9 +703,8 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
channel_def[cardpresent - 1], adapter_def(ti->adapter_type));
DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n",
irq, PIOaddr, ti->mapped_ram_size / 2);
- DPRINTK("Hardware address : %02X:%02X:%02X:%02X:%02X:%02X\n",
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ DPRINTK("Hardware address : %s\n",
+ print_mac(mac, dev->dev_addr));
if (ti->page_mask)
DPRINTK("Shared RAM paging enabled. "
"Page size: %uK Shared Ram size %dK\n",
@@ -823,7 +820,7 @@ static unsigned char __devinit get_sram_size(struct tok_info *adapt_info)
static int __devinit trdev_init(struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
SET_PAGE(ti->srb_page);
ti->open_failure = NO ;
@@ -846,7 +843,7 @@ static int tok_init_card(struct net_device *dev)
unsigned long i;
PIOaddr = dev->base_addr;
- ti = (struct tok_info *) dev->priv;
+ ti = netdev_priv(dev);
/* Special processing for first interrupt after reset */
ti->do_tok_int = FIRST_INT;
/* Reset adapter */
@@ -868,7 +865,7 @@ static int tok_init_card(struct net_device *dev)
/*****************************************************************************/
static int tok_open(struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
int i;
/*the case we were left in a failure state during a previous open */
@@ -927,7 +924,7 @@ static void tok_open_adapter(unsigned long dev_addr)
struct tok_info *ti;
int i;
- ti = (struct tok_info *) dev->priv;
+ ti = netdev_priv(dev);
SET_PAGE(ti->init_srb_page);
writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
for (i = 0; i < sizeof(struct dir_open_adapter); i++)
@@ -962,7 +959,7 @@ static void tok_open_adapter(unsigned long dev_addr)
static void open_sap(unsigned char type, struct net_device *dev)
{
int i;
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
SET_PAGE(ti->srb_page);
for (i = 0; i < sizeof(struct dlc_open_sap); i++)
@@ -986,7 +983,7 @@ static void open_sap(unsigned char type, struct net_device *dev)
static void tok_set_multicast_list(struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
struct dev_mc_list *mclist;
unsigned char address[4];
@@ -1029,7 +1026,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct tok_info *ti;
unsigned long flags;
- ti = (struct tok_info *) dev->priv;
+ ti = netdev_priv(dev);
netif_stop_queue(dev);
@@ -1051,7 +1048,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
static int tok_close(struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
/* Important for PCMCIA hot unplug, otherwise, we'll pull the card, */
/* unloading the module from memory, and then if a timer pops, ouch */
@@ -1094,7 +1091,7 @@ static void __iomem *map_address(struct tok_info *ti, unsigned index, __u8 *page
static void dir_open_adapter (struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
unsigned char ret_code;
__u16 err;
@@ -1179,7 +1176,7 @@ static irqreturn_t tok_interrupt(int irq, void *dev_id)
#if TR_VERBOSE
DPRINTK("Int from tok_driver, dev : %p irq%d\n", dev,irq);
#endif
- ti = (struct tok_info *) dev->priv;
+ ti = netdev_priv(dev);
if (ti->sram_phys & 1)
return IRQ_NONE; /* PCMCIA card extraction flag */
spin_lock(&(ti->lock));
@@ -1498,7 +1495,7 @@ static void initial_tok_int(struct net_device *dev)
struct tok_info *ti;
unsigned char init_status; /*BMS 12/2000*/
- ti = (struct tok_info *) dev->priv;
+ ti = netdev_priv(dev);
ti->do_tok_int = NOT_FIRST;
@@ -1542,7 +1539,7 @@ static void initial_tok_int(struct net_device *dev)
ti->ring_speed = init_status & 0x01 ? 16 : 4;
DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n",
ti->ring_speed, (unsigned int)dev->mem_start);
- ti->auto_speedsave=readb(ti->init_srb+INIT_STATUS_2_OFST)&4?TRUE:FALSE;
+ ti->auto_speedsave = (readb(ti->init_srb+INIT_STATUS_2_OFST) & 4) != 0;
if (ti->open_mode == MANUAL) wake_up(&ti->wait_for_reset);
else tok_open_adapter((unsigned long)dev);
@@ -1560,7 +1557,7 @@ static void initial_tok_int(struct net_device *dev)
static void tr_tx(struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
struct trh_hdr *trhdr = (struct trh_hdr *) ti->current_skb->data;
unsigned int hdr_len;
__u32 dhb=0,dhb_base;
@@ -1674,7 +1671,7 @@ static void tr_tx(struct net_device *dev)
static void tr_rx(struct net_device *dev)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
__u32 rbuffer;
void __iomem *rbuf, *rbufdata, *llc;
__u8 rbuffer_page = 0;
@@ -1742,18 +1739,20 @@ static void tr_rx(struct net_device *dev)
if (!IPv4_p) {
void __iomem *trhhdr = rbuf + offsetof(struct rec_buf, data);
-
+ u8 saddr[6];
+ u8 daddr[6];
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ int i;
+ for (i = 0 ; i < 6 ; i++)
+ saddr[i] = readb(trhhdr + SADDR_OFST + i);
+ for (i = 0 ; i < 6 ; i++)
+ daddr[i] = readb(trhhdr + DADDR_OFST + i);
DPRINTK("Probably non-IP frame received.\n");
DPRINTK("ssap: %02X dsap: %02X "
- "saddr: %02X:%02X:%02X:%02X:%02X:%02X "
- "daddr: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ "saddr: %s daddr: %$s\n",
readb(llc + SSAP_OFST), readb(llc + DSAP_OFST),
- readb(trhhdr+SADDR_OFST), readb(trhhdr+ SADDR_OFST+1),
- readb(trhhdr+SADDR_OFST+2), readb(trhhdr+SADDR_OFST+3),
- readb(trhhdr+SADDR_OFST+4), readb(trhhdr+SADDR_OFST+5),
- readb(trhhdr+DADDR_OFST), readb(trhhdr+DADDR_OFST + 1),
- readb(trhhdr+DADDR_OFST+2), readb(trhhdr+DADDR_OFST+3),
- readb(trhhdr+DADDR_OFST+4), readb(trhhdr+DADDR_OFST+5));
+ print_mac(mac, saddr), print_mac(mac2, daddr));
}
#endif
@@ -1846,7 +1845,7 @@ static void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev)
void tok_rerun(unsigned long dev_addr){
struct net_device *dev = (struct net_device *)dev_addr;
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
if ( ti->open_action == RESTART){
ti->do_tok_int = FIRST_INT;
@@ -1868,7 +1867,7 @@ static void ibmtr_readlog(struct net_device *dev)
{
struct tok_info *ti;
- ti = (struct tok_info *) dev->priv;
+ ti = netdev_priv(dev);
ti->readlog_pending = 0;
SET_PAGE(ti->srb_page);
@@ -1891,7 +1890,7 @@ static struct net_device_stats *tok_get_stats(struct net_device *dev)
{
struct tok_info *toki;
- toki = (struct tok_info *) dev->priv;
+ toki = netdev_priv(dev);
return (struct net_device_stats *) &toki->tr_stats;
}
@@ -1899,7 +1898,7 @@ static struct net_device_stats *tok_get_stats(struct net_device *dev)
static int ibmtr_change_mtu(struct net_device *dev, int mtu)
{
- struct tok_info *ti = (struct tok_info *) dev->priv;
+ struct tok_info *ti = netdev_priv(dev);
if (ti->ring_speed == 16 && mtu > ti->maxmtu16)
return -EINVAL;
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 5d849c089a3..47d84cd2809 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -123,6 +123,7 @@
#include <linux/bitops.h>
#include <linux/jiffies.h>
+#include <net/net_namespace.h>
#include <net/checksum.h>
#include <asm/io.h>
@@ -244,13 +245,12 @@ static int __devinit streamer_init_one(struct pci_dev *pdev,
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
- streamer_priv = dev->priv;
+ streamer_priv = netdev_priv(dev);
#if STREAMER_NETWORK_MONITOR
#ifdef CONFIG_PROC_FS
if (!dev_streamer)
- create_proc_read_entry("net/streamer_tr", 0, 0,
+ create_proc_read_entry("streamer_tr", 0, init_net.proc_net,
streamer_proc_info, NULL);
streamer_priv->next = dev_streamer;
dev_streamer = streamer_priv;
@@ -404,7 +404,7 @@ static void __devexit streamer_remove_one(struct pci_dev *pdev)
return;
}
- streamer_priv=dev->priv;
+ streamer_priv=netdev_priv(dev);
if (streamer_priv == NULL) {
printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev->priv is NULL\n");
return;
@@ -423,7 +423,7 @@ static void __devexit streamer_remove_one(struct pci_dev *pdev)
}
}
if (!dev_streamer)
- remove_proc_entry("net/streamer_tr", NULL);
+ remove_proc_entry("streamer_tr", init_net.proc_net);
}
#endif
#endif
@@ -447,8 +447,11 @@ static int streamer_reset(struct net_device *dev)
unsigned int uaa_addr;
struct sk_buff *skb = NULL;
__u16 misr;
+#if STREAMER_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
- streamer_priv = (struct streamer_private *) dev->priv;
+ streamer_priv = netdev_priv(dev);
streamer_mmio = streamer_priv->streamer_mmio;
writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL);
@@ -575,11 +578,8 @@ static int streamer_reset(struct net_device *dev)
dev->dev_addr[i+1]= addr & 0xff;
}
#if STREAMER_DEBUG
- printk("Adapter address: ");
- for (i = 0; i < 6; i++) {
- printk("%02x:", dev->dev_addr[i]);
- }
- printk("\n");
+ printk("Adapter address: %s\n",
+ print_mac(mac, dev->dev_addr));
#endif
}
return 0;
@@ -587,7 +587,7 @@ static int streamer_reset(struct net_device *dev)
static int streamer_open(struct net_device *dev)
{
- struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+ struct streamer_private *streamer_priv = netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
unsigned long flags;
char open_error[255];
@@ -904,7 +904,7 @@ static int streamer_open(struct net_device *dev)
static void streamer_rx(struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
struct streamer_rx_desc *rx_desc;
int rx_ring_last_received, length, frame_length, buffer_cnt = 0;
@@ -1029,7 +1029,7 @@ static irqreturn_t streamer_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
__u16 sisr;
__u16 misr;
@@ -1152,7 +1152,7 @@ static irqreturn_t streamer_interrupt(int irq, void *dev_id)
static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
unsigned long flags ;
@@ -1203,7 +1203,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
static int streamer_close(struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
unsigned long flags;
int i;
@@ -1269,7 +1269,7 @@ static int streamer_close(struct net_device *dev)
static void streamer_set_rx_mode(struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
__u8 options = 0;
struct dev_mc_list *dmi;
@@ -1328,7 +1328,7 @@ static void streamer_set_rx_mode(struct net_device *dev)
static void streamer_srb_bh(struct net_device *dev)
{
- struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+ struct streamer_private *streamer_priv = netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
__u16 srb_word;
@@ -1493,14 +1493,14 @@ static void streamer_srb_bh(struct net_device *dev)
static struct net_device_stats *streamer_get_stats(struct net_device *dev)
{
struct streamer_private *streamer_priv;
- streamer_priv = (struct streamer_private *) dev->priv;
+ streamer_priv = netdev_priv(dev);
return (struct net_device_stats *) &streamer_priv->streamer_stats;
}
static int streamer_set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *saddr = addr;
- struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+ struct streamer_private *streamer_priv = netdev_priv(dev);
if (netif_running(dev))
{
@@ -1525,7 +1525,7 @@ static int streamer_set_mac_address(struct net_device *dev, void *addr)
static void streamer_arb_cmd(struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
__u8 header_len;
__u16 frame_len, buffer_len;
@@ -1539,6 +1539,7 @@ static void streamer_arb_cmd(struct net_device *dev)
#if STREAMER_NETWORK_MONITOR
struct trh_hdr *mac_hdr;
+ DECLARE_MAC_BUF(mac);
#endif
writew(streamer_priv->arb, streamer_mmio + LAPA);
@@ -1611,15 +1612,11 @@ static void streamer_arb_cmd(struct net_device *dev)
dev->name);
mac_hdr = tr_hdr(mac_frame);
printk(KERN_WARNING
- "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n",
- dev->name, mac_hdr->daddr[0], mac_hdr->daddr[1],
- mac_hdr->daddr[2], mac_hdr->daddr[3],
- mac_hdr->daddr[4], mac_hdr->daddr[5]);
+ "%s: MAC Frame Dest. Addr: %s\n",
+ dev->name, print_mac(mac, mac_hdr->daddr));
printk(KERN_WARNING
- "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n",
- dev->name, mac_hdr->saddr[0], mac_hdr->saddr[1],
- mac_hdr->saddr[2], mac_hdr->saddr[3],
- mac_hdr->saddr[4], mac_hdr->saddr[5]);
+ "%s: MAC Frame Srce. Addr: %s\n",
+ dev->name, DEV->ADDR6(mac_hdr->saddr));
#endif
netif_rx(mac_frame);
@@ -1740,7 +1737,7 @@ drop_frame:
static void streamer_asb_bh(struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
if (streamer_priv->asb_queued == 1)
@@ -1784,7 +1781,7 @@ static void streamer_asb_bh(struct net_device *dev)
static int streamer_change_mtu(struct net_device *dev, int mtu)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u16 max_mtu;
if (streamer_priv->streamer_ring_speed == 4)
@@ -1848,12 +1845,14 @@ static int streamer_proc_info(char *buffer, char **start, off_t offset,
static int sprintf_info(char *buffer, struct net_device *dev)
{
struct streamer_private *streamer_priv =
- (struct streamer_private *) dev->priv;
+ netdev_priv(dev);
__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
struct streamer_adapter_addr_table sat;
struct streamer_parameters_table spt;
int size = 0;
int i;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
writew(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA);
for (i = 0; i < 14; i += 2) {
@@ -1875,37 +1874,30 @@ static int sprintf_info(char *buffer, struct net_device *dev)
size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name);
size += sprintf(buffer + size,
- "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n",
- dev->name, dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4],
- dev->dev_addr[5], sat.node_addr[0], sat.node_addr[1],
- sat.node_addr[2], sat.node_addr[3], sat.node_addr[4],
- sat.node_addr[5], sat.func_addr[0], sat.func_addr[1],
- sat.func_addr[2], sat.func_addr[3]);
+ "%6s: %s : %s : %02x:%02x:%02x:%02x\n",
+ dev->name, print_mac(mac, dev->dev_addr),
+ print_mac(mac2, sat.node_addr),
+ sat.func_addr[0], sat.func_addr[1],
+ sat.func_addr[2], sat.func_addr[3]);
size += sprintf(buffer + size, "\n%6s: Token Ring Parameters Table:\n", dev->name);
size += sprintf(buffer + size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", dev->name);
size += sprintf(buffer + size,
- "%6s: %02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x :\n",
+ "%6s: %02x:%02x:%02x:%02x : %s : %s : %04x : %04x : %04x :\n",
dev->name, spt.phys_addr[0], spt.phys_addr[1],
spt.phys_addr[2], spt.phys_addr[3],
- spt.up_node_addr[0], spt.up_node_addr[1],
- spt.up_node_addr[2], spt.up_node_addr[3],
- spt.up_node_addr[4], spt.up_node_addr[4],
- spt.poll_addr[0], spt.poll_addr[1], spt.poll_addr[2],
- spt.poll_addr[3], spt.poll_addr[4], spt.poll_addr[5],
+ print_mac(mac, spt.up_node_addr),
+ print_mac(mac2, spt.poll_addr),
ntohs(spt.acc_priority), ntohs(spt.auth_source_class),
ntohs(spt.att_code));
size += sprintf(buffer + size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", dev->name);
size += sprintf(buffer + size,
- "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x : %04x : %04x : %04x : \n",
- dev->name, spt.source_addr[0], spt.source_addr[1],
- spt.source_addr[2], spt.source_addr[3],
- spt.source_addr[4], spt.source_addr[5],
+ "%6s: %s : %04x : %04x : %04x : %04x : %04x : %04x : \n",
+ dev->name, print_mac(mac, spt.source_addr),
ntohs(spt.beacon_type), ntohs(spt.major_vector),
ntohs(spt.lan_status), ntohs(spt.local_ring),
ntohs(spt.mon_error), ntohs(spt.frame_correl));
@@ -1914,14 +1906,12 @@ static int sprintf_info(char *buffer, struct net_device *dev)
dev->name);
size += sprintf(buffer + size,
- "%6s: : %02x : %02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x : \n",
+ "%6s: : %02x : %02x : %s : %02x:%02x:%02x:%02x : \n",
dev->name, ntohs(spt.beacon_transmit),
- ntohs(spt.beacon_receive), spt.beacon_naun[0],
- spt.beacon_naun[1], spt.beacon_naun[2],
- spt.beacon_naun[3], spt.beacon_naun[4],
- spt.beacon_naun[5], spt.beacon_phys[0],
- spt.beacon_phys[1], spt.beacon_phys[2],
- spt.beacon_phys[3]);
+ ntohs(spt.beacon_receive),
+ print_mac(mac, spt.beacon_naun),
+ spt.beacon_phys[0], spt.beacon_phys[1],
+ spt.beacon_phys[2], spt.beacon_phys[3]);
return size;
}
#endif
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index f8f4d74f01f..5a4151362fc 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -151,7 +151,8 @@ static int __devinit madgemc_probe(struct device *device)
struct net_local *tp;
struct card_info *card;
struct mca_device *mdev = to_mca_device(device);
- int ret = 0, i = 0;
+ int ret = 0;
+ DECLARE_MAC_BUF(mac);
if (versionprinted++ == 0)
printk("%s", version);
@@ -168,7 +169,6 @@ static int __devinit madgemc_probe(struct device *device)
goto getout;
}
- SET_MODULE_OWNER(dev);
dev->dma = 0;
card = kmalloc(sizeof(struct card_info), GFP_KERNEL);
@@ -323,11 +323,8 @@ static int __devinit madgemc_probe(struct device *device)
mca_device_set_name(mdev, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME);
mca_set_adapter_procfn(mdev->slot, madgemc_mcaproc, dev);
- printk("%s: Ring Station Address: ", dev->name);
- printk("%2.2x", dev->dev_addr[0]);
- for (i = 1; i < 6; i++)
- printk(":%2.2x", dev->dev_addr[i]);
- printk("\n");
+ printk("%s: Ring Station Address: %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
if (tmsdev_init(dev, device)) {
printk("%s: unable to get memory for dev->priv.\n",
@@ -690,14 +687,14 @@ static int madgemc_close(struct net_device *dev)
static int madgemc_mcaproc(char *buf, int slot, void *d)
{
struct net_device *dev = (struct net_device *)d;
- struct net_local *tp = dev->priv;
+ struct net_local *tp = netdev_priv(dev);
struct card_info *curcard = tp->tmspriv;
int len = 0;
+ DECLARE_MAC_BUF(mac);
len += sprintf(buf+len, "-------\n");
if (curcard) {
struct net_local *tp = netdev_priv(dev);
- int i;
len += sprintf(buf+len, "Card Revision: %d\n", curcard->cardrev);
len += sprintf(buf+len, "RAM Size: %dkb\n", curcard->ramsize);
@@ -717,11 +714,8 @@ static int madgemc_mcaproc(char *buf, int slot, void *d)
}
len += sprintf(buf+len, " (%s)\n", (curcard->fairness)?"Unfair":"Fair");
- len += sprintf(buf+len, "Ring Station Address: ");
- len += sprintf(buf+len, "%2.2x", dev->dev_addr[0]);
- for (i = 1; i < 6; i++)
- len += sprintf(buf+len, " %2.2x", dev->dev_addr[i]);
- len += sprintf(buf+len, "\n");
+ len += sprintf(buf+len, "Ring Station Address: %s\n",
+ print_mac(mac, dev->dev_addr));
} else
len += sprintf(buf+len, "Card not configured\n");
@@ -736,7 +730,7 @@ static int __devexit madgemc_remove(struct device *device)
BUG_ON(!dev);
- tp = dev->priv;
+ tp = netdev_priv(dev);
card = tp->tmspriv;
kfree(card);
tp->tmspriv = NULL;
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 09b3cfb8e80..74c1f0f189f 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -102,6 +102,7 @@
#include <linux/jiffies.h>
#include <net/checksum.h>
+#include <net/net_namespace.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -219,14 +220,14 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device
goto op_release_dev;
}
- olympic_priv = dev->priv ;
+ olympic_priv = netdev_priv(dev) ;
spin_lock_init(&olympic_priv->olympic_lock) ;
init_waitqueue_head(&olympic_priv->srb_wait);
init_waitqueue_head(&olympic_priv->trb_wait);
#if OLYMPIC_DEBUG
- printk(KERN_INFO "pci_device: %p, dev:%p, dev->priv: %p\n", pdev, dev, dev->priv);
+ printk(KERN_INFO "pci_device: %p, dev:%p, dev->priv: %p\n", pdev, dev, netdev_priv(dev));
#endif
dev->irq=pdev->irq;
dev->base_addr=pci_resource_start(pdev, 0);
@@ -260,7 +261,6 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device
dev->set_multicast_list=&olympic_set_rx_mode;
dev->get_stats=&olympic_get_stats ;
dev->set_mac_address=&olympic_set_mac_address ;
- SET_MODULE_OWNER(dev) ;
SET_NETDEV_DEV(dev, &pdev->dev);
pci_set_drvdata(pdev,dev) ;
@@ -268,9 +268,9 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device
printk("Olympic: %s registered as: %s\n",olympic_priv->olympic_card_name,dev->name);
if (olympic_priv->olympic_network_monitor) { /* Must go after register_netdev as we need the device name */
char proc_name[20] ;
- strcpy(proc_name,"net/olympic_") ;
+ strcpy(proc_name,"olympic_") ;
strcat(proc_name,dev->name) ;
- create_proc_read_entry(proc_name,0,NULL,olympic_proc_info,(void *)dev) ;
+ create_proc_read_entry(proc_name,0,init_net.proc_net,olympic_proc_info,(void *)dev) ;
printk("Olympic: Network Monitor information: /proc/%s\n",proc_name);
}
return 0 ;
@@ -297,7 +297,7 @@ static int __devinit olympic_init(struct net_device *dev)
unsigned long t;
unsigned int uaa_addr;
- olympic_priv=(struct olympic_private *)dev->priv;
+ olympic_priv=netdev_priv(dev);
olympic_mmio=olympic_priv->olympic_mmio;
printk("%s \n", version);
@@ -418,14 +418,15 @@ static int __devinit olympic_init(struct net_device *dev)
writel(uaa_addr,olympic_mmio+LAPA);
adapter_addr=olympic_priv->olympic_lap + (uaa_addr & (~0xf800));
+ memcpy_fromio(&dev->dev_addr[0], adapter_addr,6);
+
#if OLYMPIC_DEBUG
- printk("adapter address: %02x:%02x:%02x:%02x:%02x:%02x\n",
- readb(adapter_addr), readb(adapter_addr+1),readb(adapter_addr+2),
- readb(adapter_addr+3),readb(adapter_addr+4),readb(adapter_addr+5));
+ {
+ DECLARE_MAC_BUF(mac);
+ printk("adapter address: %s\n", print_mac(mac, dev->dev_addr));
+ }
#endif
- memcpy_fromio(&dev->dev_addr[0], adapter_addr,6);
-
olympic_priv->olympic_addr_table_addr = swab16(readw(init_srb + 12));
olympic_priv->olympic_parms_addr = swab16(readw(init_srb + 14));
@@ -435,11 +436,12 @@ static int __devinit olympic_init(struct net_device *dev)
static int olympic_open(struct net_device *dev)
{
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*init_srb;
unsigned long flags, t;
int i, open_finished = 1 ;
u8 resp, err;
+ DECLARE_MAC_BUF(mac);
DECLARE_WAITQUEUE(wait,current) ;
@@ -567,14 +569,8 @@ static int olympic_open(struct net_device *dev)
goto out;
case 0x32:
- printk(KERN_WARNING "%s: Invalid LAA: %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name,
- olympic_priv->olympic_laa[0],
- olympic_priv->olympic_laa[1],
- olympic_priv->olympic_laa[2],
- olympic_priv->olympic_laa[3],
- olympic_priv->olympic_laa[4],
- olympic_priv->olympic_laa[5]) ;
+ printk(KERN_WARNING "%s: Invalid LAA: %s\n",
+ dev->name, print_mac(mac, olympic_priv->olympic_laa));
goto out;
default:
@@ -704,30 +700,26 @@ static int olympic_open(struct net_device *dev)
#endif
if (olympic_priv->olympic_network_monitor) {
- u8 __iomem *oat ;
- u8 __iomem *opt ;
- oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ;
- opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ;
-
- printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name,
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5));
+ u8 __iomem *oat;
+ u8 __iomem *opt;
+ int i;
+ u8 addr[6];
+ DECLARE_MAC_BUF(mac);
+ oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr);
+ opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr);
+
+ for (i = 0; i < 6; i++)
+ addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+i);
+ printk("%s: Node Address: %s\n",dev->name, print_mac(mac, addr));
printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name,
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)),
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
- printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name,
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5));
+
+ for (i = 0; i < 6; i++)
+ addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+i);
+ printk("%s: NAUN Address: %s\n",dev->name, print_mac(mac, addr));
}
netif_start_queue(dev);
@@ -755,7 +747,7 @@ out:
*/
static void olympic_rx(struct net_device *dev)
{
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio;
struct olympic_rx_status *rx_status;
struct olympic_rx_desc *rx_desc ;
@@ -897,7 +889,7 @@ static void olympic_rx(struct net_device *dev)
static void olympic_freemem(struct net_device *dev)
{
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
int i;
for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
@@ -930,7 +922,7 @@ static void olympic_freemem(struct net_device *dev)
static irqreturn_t olympic_interrupt(int irq, void *dev_id)
{
struct net_device *dev= (struct net_device *)dev_id;
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio;
u32 sisr;
u8 __iomem *adapter_check_area ;
@@ -1046,7 +1038,7 @@ static irqreturn_t olympic_interrupt(int irq, void *dev_id)
static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio;
unsigned long flags ;
@@ -1077,7 +1069,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
static int olympic_close(struct net_device *dev)
{
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*srb;
unsigned long t,flags;
@@ -1147,7 +1139,7 @@ static int olympic_close(struct net_device *dev)
static void olympic_set_rx_mode(struct net_device *dev)
{
- struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ;
+ struct olympic_private *olympic_priv = netdev_priv(dev);
u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ;
u8 options = 0;
u8 __iomem *srb;
@@ -1215,7 +1207,7 @@ static void olympic_set_rx_mode(struct net_device *dev)
static void olympic_srb_bh(struct net_device *dev)
{
- struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ;
+ struct olympic_private *olympic_priv = netdev_priv(dev);
u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ;
u8 __iomem *srb;
@@ -1361,14 +1353,14 @@ static void olympic_srb_bh(struct net_device *dev)
static struct net_device_stats * olympic_get_stats(struct net_device *dev)
{
struct olympic_private *olympic_priv ;
- olympic_priv=(struct olympic_private *) dev->priv;
+ olympic_priv=netdev_priv(dev);
return (struct net_device_stats *) &olympic_priv->olympic_stats;
}
static int olympic_set_mac_address (struct net_device *dev, void *addr)
{
struct sockaddr *saddr = addr ;
- struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ;
+ struct olympic_private *olympic_priv = netdev_priv(dev);
if (netif_running(dev)) {
printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ;
@@ -1389,7 +1381,7 @@ static int olympic_set_mac_address (struct net_device *dev, void *addr)
static void olympic_arb_cmd(struct net_device *dev)
{
- struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
+ struct olympic_private *olympic_priv = netdev_priv(dev);
u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio;
u8 __iomem *arb_block, *asb_block, *srb ;
u8 header_len ;
@@ -1445,11 +1437,14 @@ static void olympic_arb_cmd(struct net_device *dev)
mac_frame->protocol = tr_type_trans(mac_frame, dev);
if (olympic_priv->olympic_network_monitor) {
- struct trh_hdr *mac_hdr ;
- printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ;
+ struct trh_hdr *mac_hdr;
+ DECLARE_MAC_BUF(mac);
+ printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name);
mac_hdr = tr_hdr(mac_frame);
- printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ;
- printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ;
+ printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %s\n",
+ dev->name, print_mac(mac, mac_hdr->daddr));
+ printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %s\n",
+ dev->name, print_mac(mac, mac_hdr->saddr));
}
netif_rx(mac_frame);
dev->last_rx = jiffies;
@@ -1575,7 +1570,7 @@ drop_frame:
static void olympic_asb_bh(struct net_device *dev)
{
- struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ;
+ struct olympic_private *olympic_priv = netdev_priv(dev);
u8 __iomem *arb_block, *asb_block ;
arb_block = (olympic_priv->olympic_lap + olympic_priv->arb) ;
@@ -1615,7 +1610,7 @@ static void olympic_asb_bh(struct net_device *dev)
static int olympic_change_mtu(struct net_device *dev, int mtu)
{
- struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
+ struct olympic_private *olympic_priv = netdev_priv(dev);
u16 max_mtu ;
if (olympic_priv->olympic_ring_speed == 4)
@@ -1637,33 +1632,31 @@ static int olympic_change_mtu(struct net_device *dev, int mtu)
static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
{
struct net_device *dev = (struct net_device *)data ;
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ;
u8 __iomem *opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ;
int size = 0 ;
int len=0;
off_t begin=0;
off_t pos=0;
-
+ u8 addr[6];
+ u8 addr2[6];
+ int i;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+
size = sprintf(buffer,
"IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapter %s\n",dev->name);
size += sprintf(buffer+size, "\n%6s: Adapter Address : Node Address : Functional Addr\n",
dev->name);
- size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n",
+ for (i = 0 ; i < 6 ; i++)
+ addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr) + i);
+
+ size += sprintf(buffer+size, "%6s: %s : %s : %02x:%02x:%02x:%02x\n",
dev->name,
- dev->dev_addr[0],
- dev->dev_addr[1],
- dev->dev_addr[2],
- dev->dev_addr[3],
- dev->dev_addr[4],
- dev->dev_addr[5],
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
- readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5),
+ print_mac(mac, dev->dev_addr),
+ print_mac(mac2, addr),
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)),
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
@@ -1673,25 +1666,20 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt
size += sprintf(buffer+size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n",
dev->name) ;
-
- size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x :\n",
+
+ for (i = 0 ; i < 6 ; i++)
+ addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr) + i);
+ for (i = 0 ; i < 6 ; i++)
+ addr2[i] = readb(opt+offsetof(struct olympic_parameters_table, poll_addr) + i);
+
+ size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %s : %s : %04x : %04x : %04x :\n",
dev->name,
readb(opt+offsetof(struct olympic_parameters_table, phys_addr)),
readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1),
readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2),
readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
- readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5),
- readb(opt+offsetof(struct olympic_parameters_table, poll_addr)),
- readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+1),
- readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+2),
- readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+3),
- readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+4),
- readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+5),
+ print_mac(mac, addr),
+ print_mac(mac2, addr2),
swab16(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, att_code))));
@@ -1699,14 +1687,11 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt
size += sprintf(buffer+size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n",
dev->name) ;
- size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x : %04x : %04x : %04x : %04x : %04x : \n",
+ for (i = 0 ; i < 6 ; i++)
+ addr[i] = readb(opt+offsetof(struct olympic_parameters_table, source_addr) + i);
+ size += sprintf(buffer+size, "%6s: %s : %04x : %04x : %04x : %04x : %04x : %04x : \n",
dev->name,
- readb(opt+offsetof(struct olympic_parameters_table, source_addr)),
- readb(opt+offsetof(struct olympic_parameters_table, source_addr)+1),
- readb(opt+offsetof(struct olympic_parameters_table, source_addr)+2),
- readb(opt+offsetof(struct olympic_parameters_table, source_addr)+3),
- readb(opt+offsetof(struct olympic_parameters_table, source_addr)+4),
- readb(opt+offsetof(struct olympic_parameters_table, source_addr)+5),
+ print_mac(mac, addr),
swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, major_vector))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, lan_status))),
@@ -1717,16 +1702,13 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt
size += sprintf(buffer+size, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n",
dev->name) ;
- size += sprintf(buffer+size, "%6s: : %02x : %02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x : \n",
+ for (i = 0 ; i < 6 ; i++)
+ addr[i] = readb(opt+offsetof(struct olympic_parameters_table, beacon_naun) + i);
+ size += sprintf(buffer+size, "%6s: : %02x : %02x : %s : %02x:%02x:%02x:%02x : \n",
dev->name,
swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))),
- readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)),
- readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+1),
- readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+2),
- readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+3),
- readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+4),
- readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+5),
+ print_mac(mac, addr),
readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)),
readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1),
readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2),
@@ -1748,13 +1730,13 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt
static void __devexit olympic_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev) ;
- struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+ struct olympic_private *olympic_priv=netdev_priv(dev);
if (olympic_priv->olympic_network_monitor) {
char proc_name[20] ;
- strcpy(proc_name,"net/olympic_") ;
+ strcpy(proc_name,"olympic_") ;
strcat(proc_name,dev->name) ;
- remove_proc_entry(proc_name,NULL);
+ remove_proc_entry(proc_name,init_net.proc_net);
}
unregister_netdev(dev) ;
iounmap(olympic_priv->olympic_mmio) ;
diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c
index cb7dbb63c9d..ca6b65919b3 100644
--- a/drivers/net/tokenring/proteon.c
+++ b/drivers/net/tokenring/proteon.c
@@ -122,11 +122,11 @@ static int __init setup_card(struct net_device *dev, struct device *pdev)
static int versionprinted;
const unsigned *port;
int j,err = 0;
+ DECLARE_MAC_BUF(mac);
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
if (dev->base_addr) /* probe specific location */
err = proteon_probe1(dev, dev->base_addr);
else {
@@ -153,11 +153,8 @@ static int __init setup_card(struct net_device *dev, struct device *pdev)
proteon_read_eeprom(dev);
- printk(KERN_DEBUG "proteon.c: Ring Station Address: ");
- printk("%2.2x", dev->dev_addr[0]);
- for (j = 1; j < 6; j++)
- printk(":%2.2x", dev->dev_addr[j]);
- printk("\n");
+ printk(KERN_DEBUG "proteon.c: Ring Station Address: %s\n",
+ print_mac(mac, dev->dev_addr));
tp = netdev_priv(dev);
tp->setnselout = proteon_setnselout_pins;
diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c
index 33afea31d87..32e8d5a9f95 100644
--- a/drivers/net/tokenring/skisa.c
+++ b/drivers/net/tokenring/skisa.c
@@ -139,11 +139,11 @@ static int __init setup_card(struct net_device *dev, struct device *pdev)
static int versionprinted;
const unsigned *port;
int j, err = 0;
+ DECLARE_MAC_BUF(mac);
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
if (dev->base_addr) /* probe specific location */
err = sk_isa_probe1(dev, dev->base_addr);
else {
@@ -170,11 +170,8 @@ static int __init setup_card(struct net_device *dev, struct device *pdev)
sk_isa_read_eeprom(dev);
- printk(KERN_DEBUG "skisa.c: Ring Station Address: ");
- printk("%2.2x", dev->dev_addr[0]);
- for (j = 1; j < 6; j++)
- printk(":%2.2x", dev->dev_addr[j]);
- printk("\n");
+ printk(KERN_DEBUG "skisa.c: Ring Station Address: %s\n",
+ print_mac(mac, dev->dev_addr));
tp = netdev_priv(dev);
tp->setnselout = sk_isa_setnselout_pins;
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index f83bb5cb0d3..93da3a36cde 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -3583,8 +3583,6 @@ struct net_device __init *smctr_probe(int unit)
if (!dev)
return ERR_PTR(-ENOMEM);
- SET_MODULE_OWNER(dev);
-
if (unit >= 0) {
sprintf(dev->name, "tr%d", unit);
netdev_boot_setup_check(dev);
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index 12bd294045a..d5fa36d3651 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -2124,7 +2124,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev)
/* Get the frame size (Byte swap for Intel).
* Do this early (see workaround comment below)
*/
- Length = be16_to_cpu((unsigned short)rpl->FrameSize);
+ Length = be16_to_cpu(rpl->FrameSize);
/* Check if the Frame_Start, Frame_End and
* Frame_Complete bits are set.
@@ -2140,7 +2140,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev)
* Length2 is there because there have also been
* cases where the FrameSize was partially written
*/
- Length2 = be16_to_cpu((unsigned short)rpl->FrameSize);
+ Length2 = be16_to_cpu(rpl->FrameSize);
if(Length == 0 || Length != Length2)
{
diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h
index 2a16078ac3f..7daf74e31cc 100644
--- a/drivers/net/tokenring/tms380tr.h
+++ b/drivers/net/tokenring/tms380tr.h
@@ -476,13 +476,13 @@ typedef struct {
* bytes = 0xC000
*/
u_int32_t FunctAddr; /* High order bytes = 0xC000 */
- u_int16_t RxListSize; /* RPL size: 0 (=26), 14, 20 or
+ __be16 RxListSize; /* RPL size: 0 (=26), 14, 20 or
* 26 bytes read by the adapter.
* (Depending on the number of
* fragments/list)
*/
- u_int16_t TxListSize; /* TPL size */
- u_int16_t BufSize; /* Is automatically rounded up to the
+ __be16 TxListSize; /* TPL size */
+ __be16 BufSize; /* Is automatically rounded up to the
* nearest nK boundary.
*/
u_int16_t FullDuplex;
@@ -580,14 +580,14 @@ typedef struct {
/*--------------------- Send and Receive definitions -------------------*/
#pragma pack(1)
typedef struct {
- u_int16_t DataCount; /* Value 0, even and odd values are
+ __be16 DataCount; /* Value 0, even and odd values are
* permitted; value is unaltered most
* significant bit set: following
* fragments last fragment: most
* significant bit is not evaluated.
* (???)
*/
- u_int32_t DataAddr; /* Pointer to frame data fragment;
+ __be32 DataAddr; /* Pointer to frame data fragment;
* even or odd.
*/
} Fragment;
@@ -679,7 +679,7 @@ typedef struct {
typedef struct s_TPL TPL;
struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */
- u_int32_t NextTPLAddr; /* Pointer to next TPL in chain; if
+ __be32 NextTPLAddr; /* Pointer to next TPL in chain; if
* pointer is odd: this is the last
* TPL. Pointing to itself can cause
* problems!
@@ -689,7 +689,7 @@ struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */
* significant bit first! Set by the
* adapter: CSTAT_COMPLETE status.
*/
- u_int16_t FrameSize; /* Number of bytes to be transmitted
+ __be16 FrameSize; /* Number of bytes to be transmitted
* as a frame including AC/FC,
* Destination, Source, Routing field
* not including CRC, FS, End Delimiter
@@ -1020,7 +1020,7 @@ enum SKB_STAT {
#pragma pack(1)
typedef struct s_RPL RPL;
struct s_RPL { /* Receive Parameter List */
- u_int32_t NextRPLAddr; /* Pointer to next RPL in chain
+ __be32 NextRPLAddr; /* Pointer to next RPL in chain
* (normalized = physical 32 bit
* address) if pointer is odd: this
* is last RPL. Pointing to itself can
@@ -1031,7 +1031,7 @@ struct s_RPL { /* Receive Parameter List */
* adapter in lists that start or end
* a frame.
*/
- volatile u_int16_t FrameSize; /* Number of bytes received as a
+ volatile __be16 FrameSize; /* Number of bytes received as a
* frame including AC/FC, Destination,
* Source, Routing field not including
* CRC, FS (Frame Status), End Delimiter
diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c
index 3b2f00b9b7b..1c18f782f52 100644
--- a/drivers/net/tokenring/tmspci.c
+++ b/drivers/net/tokenring/tmspci.c
@@ -96,10 +96,11 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
static int versionprinted;
struct net_device *dev;
struct net_local *tp;
- int i, ret;
+ int ret;
unsigned int pci_irq_line;
unsigned long pci_ioaddr;
struct card_info *cardinfo = &card_info_table[ent->driver_data];
+ DECLARE_MAC_BUF(mac);
if (versionprinted++ == 0)
printk("%s", version);
@@ -115,7 +116,6 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
dev = alloc_trdev(sizeof(struct net_local));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
if (!request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, dev->name)) {
ret = -EBUSY;
@@ -137,11 +137,8 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
tms_pci_read_eeprom(dev);
- printk("%s: Ring Station Address: ", dev->name);
- printk("%2.2x", dev->dev_addr[0]);
- for (i = 1; i < 6; i++)
- printk(":%2.2x", dev->dev_addr[i]);
- printk("\n");
+ printk("%s: Ring Station Address: %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
ret = tmsdev_init(dev, &pdev->dev);
if (ret) {
@@ -149,7 +146,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
goto err_out_irq;
}
- tp = dev->priv;
+ tp = netdev_priv(dev);
tp->setnselout = tms_pci_setnselout_pins;
tp->sifreadb = tms_pci_sifreadb;
@@ -210,7 +207,7 @@ static void tms_pci_read_eeprom(struct net_device *dev)
static unsigned short tms_pci_setnselout_pins(struct net_device *dev)
{
unsigned short val = 0;
- struct net_local *tp = dev->priv;
+ struct net_local *tp = netdev_priv(dev);
struct card_info *cardinfo = tp->tmspriv;
if(tp->DataRate == SPEED_4)
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index 1aabc91f645..35d15e85007 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -47,7 +47,6 @@
#include <linux/rtnetlink.h>
#include <linux/timer.h>
#include <linux/platform_device.h>
-#include <linux/etherdevice.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -79,6 +78,9 @@ struct tsi108_prv_data {
void __iomem *regs; /* Base of normal regs */
void __iomem *phyregs; /* Base of register bank used for PHY access */
+ struct net_device *dev;
+ struct napi_struct napi;
+
unsigned int phy; /* Index of PHY for this interface */
unsigned int irq_num;
unsigned int id;
@@ -837,13 +839,13 @@ static int tsi108_refill_rx(struct net_device *dev, int budget)
return done;
}
-static int tsi108_poll(struct net_device *dev, int *budget)
+static int tsi108_poll(struct napi_struct *napi, int budget)
{
- struct tsi108_prv_data *data = netdev_priv(dev);
+ struct tsi108_prv_data *data = container_of(napi, struct tsi108_prv_data, napi);
+ struct net_device *dev = data->dev;
u32 estat = TSI_READ(TSI108_EC_RXESTAT);
u32 intstat = TSI_READ(TSI108_EC_INTSTAT);
- int total_budget = min(*budget, dev->quota);
- int num_received = 0, num_filled = 0, budget_used;
+ int num_received = 0, num_filled = 0;
intstat &= TSI108_INT_RXQUEUE0 | TSI108_INT_RXTHRESH |
TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR | TSI108_INT_RXWAIT;
@@ -852,7 +854,7 @@ static int tsi108_poll(struct net_device *dev, int *budget)
TSI_WRITE(TSI108_EC_INTSTAT, intstat);
if (data->rxpending || (estat & TSI108_EC_RXESTAT_Q0_DESCINT))
- num_received = tsi108_complete_rx(dev, total_budget);
+ num_received = tsi108_complete_rx(dev, budget);
/* This should normally fill no more slots than the number of
* packets received in tsi108_complete_rx(). The exception
@@ -867,7 +869,7 @@ static int tsi108_poll(struct net_device *dev, int *budget)
*/
if (data->rxfree < TSI108_RXRING_LEN)
- num_filled = tsi108_refill_rx(dev, total_budget * 2);
+ num_filled = tsi108_refill_rx(dev, budget * 2);
if (intstat & TSI108_INT_RXERROR) {
u32 err = TSI_READ(TSI108_EC_RXERR);
@@ -890,14 +892,9 @@ static int tsi108_poll(struct net_device *dev, int *budget)
spin_unlock_irq(&data->misclock);
}
- budget_used = max(num_received, num_filled / 2);
-
- *budget -= budget_used;
- dev->quota -= budget_used;
-
- if (budget_used != total_budget) {
+ if (num_received < budget) {
data->rxpending = 0;
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
TSI_WRITE(TSI108_EC_INTMASK,
TSI_READ(TSI108_EC_INTMASK)
@@ -906,14 +903,11 @@ static int tsi108_poll(struct net_device *dev, int *budget)
TSI108_INT_RXOVERRUN |
TSI108_INT_RXERROR |
TSI108_INT_RXWAIT));
-
- /* IRQs are level-triggered, so no need to re-check */
- return 0;
} else {
data->rxpending = 1;
}
- return 1;
+ return num_received;
}
static void tsi108_rx_int(struct net_device *dev)
@@ -931,7 +925,7 @@ static void tsi108_rx_int(struct net_device *dev)
* from tsi108_check_rxring().
*/
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &data->napi)) {
/* Mask, rather than ack, the receive interrupts. The ack
* will happen in tsi108_poll().
*/
@@ -942,7 +936,7 @@ static void tsi108_rx_int(struct net_device *dev)
| TSI108_INT_RXTHRESH |
TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR |
TSI108_INT_RXWAIT);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &data->napi);
} else {
if (!netif_running(dev)) {
/* This can happen if an interrupt occurs while the
@@ -1401,6 +1395,8 @@ static int tsi108_open(struct net_device *dev)
TSI_WRITE(TSI108_EC_TXQ_PTRLOW, data->txdma);
tsi108_init_phy(dev);
+ napi_enable(&data->napi);
+
setup_timer(&data->timer, tsi108_timed_checker, (unsigned long)dev);
mod_timer(&data->timer, jiffies + 1);
@@ -1425,6 +1421,7 @@ static int tsi108_close(struct net_device *dev)
struct tsi108_prv_data *data = netdev_priv(dev);
netif_stop_queue(dev);
+ napi_disable(&data->napi);
del_timer_sync(&data->timer);
@@ -1543,6 +1540,7 @@ tsi108_init_one(struct platform_device *pdev)
struct tsi108_prv_data *data = NULL;
hw_info *einfo;
int err = 0;
+ DECLARE_MAC_BUF(mac);
einfo = pdev->dev.platform_data;
@@ -1562,6 +1560,7 @@ tsi108_init_one(struct platform_device *pdev)
printk("tsi108_eth%d: probe...\n", pdev->id);
data = netdev_priv(dev);
+ data->dev = dev;
pr_debug("tsi108_eth%d:regs:phyresgs:phy:irq_num=0x%x:0x%x:0x%x:0x%x\n",
pdev->id, einfo->regs, einfo->phyregs,
@@ -1597,9 +1596,8 @@ tsi108_init_one(struct platform_device *pdev)
dev->set_mac_address = tsi108_set_mac;
dev->set_multicast_list = tsi108_set_rx_mode;
dev->get_stats = tsi108_get_stats;
- dev->poll = tsi108_poll;
+ netif_napi_add(dev, &data->napi, tsi108_poll, 64);
dev->do_ioctl = tsi108_do_ioctl;
- dev->weight = 64; /* 64 is more suitable for GigE interface - klai */
/* Apparently, the Linux networking code won't use scatter-gather
* if the hardware doesn't do checksums. However, it's faster
@@ -1610,7 +1608,6 @@ tsi108_init_one(struct platform_device *pdev)
*/
dev->features = NETIF_F_HIGHDMA;
- SET_MODULE_OWNER(dev);
spin_lock_init(&data->txlock);
spin_lock_init(&data->misclock);
@@ -1632,10 +1629,8 @@ tsi108_init_one(struct platform_device *pdev)
goto register_fail;
}
- printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: "
- "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
#ifdef DEBUG
data->msg_enable = DEBUG;
dump_eth_one(dev);
diff --git a/drivers/net/tulip/Kconfig b/drivers/net/tulip/Kconfig
index 1c537d5a306..20ac1503021 100644
--- a/drivers/net/tulip/Kconfig
+++ b/drivers/net/tulip/Kconfig
@@ -24,8 +24,7 @@ config DE2104X
will say Y here.) Do read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will
+ To compile this driver as a module, choose M here. The module will
be called de2104x.
config TULIP
@@ -42,8 +41,7 @@ config TULIP
will say Y here.) Do read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will
+ To compile this driver as a module, choose M here. The module will
be called tulip.
config TULIP_MWI
@@ -67,7 +65,7 @@ config TULIP_MMIO
If in doubt, say N.
config TULIP_NAPI
- bool "Use NAPI RX polling "
+ bool "Use RX polling (NAPI)"
depends on TULIP
help
NAPI is a new driver API designed to reduce CPU and interrupt load
@@ -78,18 +76,16 @@ config TULIP_NAPI
deployed on potentially unfriendly networks (e.g. in a firewall),
then say Y here.
- See <file:Documentation/networking/NAPI_HOWTO.txt> for more
- information.
-
If in doubt, say N.
config TULIP_NAPI_HW_MITIGATION
- bool "Use Interrupt Mitigation "
+ bool "Use Interrupt Mitigation"
depends on TULIP_NAPI
---help---
- Use HW to reduce RX interrupts. Not strict necessary since NAPI reduces
- RX interrupts but itself. Although this reduces RX interrupts even at
- low levels traffic at the cost of a small latency.
+ Use HW to reduce RX interrupts. Not strictly necessary since NAPI
+ reduces RX interrupts by itself. Interrupt mitigation reduces RX
+ interrupts even at low levels of traffic at the cost of a small
+ latency.
If in doubt, say Y.
@@ -106,8 +102,7 @@ config DE4X5
information is contained in
<file:Documentation/networking/de4x5.txt>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will
+ To compile this driver as a module, choose M here. The module will
be called de4x5.
config WINBOND_840
@@ -131,8 +126,7 @@ config DM9102
(Ethernet) card, say Y. Some information is contained in the file
<file:Documentation/networking/dmfe.txt>.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will
+ To compile this driver as a module, choose M here. The module will
be called dmfe.
config ULI526X
@@ -143,8 +137,7 @@ config ULI526X
This driver is for ULi M5261/M5263 10/100M Ethernet Controller
(<http://www.uli.com.tw/>).
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will
+ To compile this driver as a module, choose M here. The module will
be called uli526x.
config PCMCIA_XIRCOM
@@ -156,8 +149,7 @@ config PCMCIA_XIRCOM
as with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and
ASIX.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will
+ To compile this driver as a module, choose M here. The module will
be called xircom_cb. If unsure, say N.
config PCMCIA_XIRTULIP
@@ -170,8 +162,7 @@ config PCMCIA_XIRTULIP
as with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and
ASIX.
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module will
+ To compile this driver as a module, choose M here. The module will
be called xircom_tulip_cb. If unsure, say N.
endif # NET_TULIP
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index d380e0b3f05..77d9dd7ea34 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -264,10 +264,10 @@ struct de_srom_info_leaf {
} __attribute__((packed));
struct de_desc {
- u32 opts1;
- u32 opts2;
- u32 addr1;
- u32 addr2;
+ __le32 opts1;
+ __le32 opts2;
+ __le32 addr1;
+ __le32 addr2;
};
struct media_info {
@@ -1670,8 +1670,6 @@ static void de_get_regs(struct net_device *dev, struct ethtool_regs *regs,
static const struct ethtool_ops de_ethtool_ops = {
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
.get_drvinfo = de_get_drvinfo,
.get_regs_len = de_get_regs_len,
.get_settings = de_get_settings,
@@ -1773,8 +1771,8 @@ static void __devinit de21041_get_srom_info (struct de_private *de)
/* download entire eeprom */
for (i = 0; i < DE_EEPROM_WORDS; i++)
- ((u16 *)ee_data)[i] =
- le16_to_cpu(tulip_read_eeprom(de->regs, i, ee_addr_size));
+ ((__le16 *)ee_data)[i] =
+ cpu_to_le16(tulip_read_eeprom(de->regs, i, ee_addr_size));
/* DEC now has a specification but early board makers
just put the address in the first EEPROM locations. */
@@ -1931,6 +1929,7 @@ static int __devinit de_init_one (struct pci_dev *pdev,
void __iomem *regs;
unsigned long pciaddr;
static int board_idx = -1;
+ DECLARE_MAC_BUF(mac);
board_idx++;
@@ -1944,7 +1943,6 @@ static int __devinit de_init_one (struct pci_dev *pdev,
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
dev->open = de_open;
dev->stop = de_close;
@@ -2045,15 +2043,11 @@ static int __devinit de_init_one (struct pci_dev *pdev,
goto err_out_iomap;
/* print info about board and interface just registered */
- printk (KERN_INFO "%s: %s at 0x%lx, "
- "%02x:%02x:%02x:%02x:%02x:%02x, "
- "IRQ %d\n",
+ printk (KERN_INFO "%s: %s at 0x%lx, %s, IRQ %d\n",
dev->name,
de->de21040 ? "21040" : "21041",
dev->base_addr,
- dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5],
+ print_mac(mac, dev->dev_addr),
dev->irq);
pci_set_drvdata(pdev, dev);
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 09902891a6e..41f34bb91ca 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -482,7 +482,7 @@
static char version[] __devinitdata = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n";
#define c_char const char
-#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a)))
+#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((__le16 *)(a)))
/*
** MII Information
@@ -756,10 +756,10 @@ struct de4x5_srom {
/* Multiple of 4 for DC21040 */
/* Allows 512 byte alignment */
struct de4x5_desc {
- volatile s32 status;
- u32 des1;
- u32 buf;
- u32 next;
+ volatile __le32 status;
+ __le32 des1;
+ __le32 buf;
+ __le32 next;
DESC_ALIGN
};
@@ -1041,7 +1041,7 @@ static struct InfoLeaf infoleaf_array[] = {
{DC21142, dc21142_infoleaf},
{DC21143, dc21143_infoleaf}
};
-#define INFOLEAF_SIZE (sizeof(infoleaf_array)/(sizeof(int)+sizeof(int *)))
+#define INFOLEAF_SIZE ARRAY_SIZE(infoleaf_array)
/*
** List the SROM info block functions
@@ -1056,7 +1056,7 @@ static int (*dc_infoblock[])(struct net_device *dev, u_char, u_char *) = {
compact_infoblock
};
-#define COMPACT (sizeof(dc_infoblock)/sizeof(int *) - 1)
+#define COMPACT (ARRAY_SIZE(dc_infoblock) - 1)
/*
** Miscellaneous defines...
@@ -1088,6 +1088,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
struct de4x5_private *lp = netdev_priv(dev);
struct pci_dev *pdev = NULL;
int i, status=0;
+ DECLARE_MAC_BUF(mac);
gendev->driver_data = dev;
@@ -1123,12 +1124,8 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
dev->base_addr = iobase;
printk ("%s: %s at 0x%04lx", gendev->bus_id, name, iobase);
- printk(", h/w address ");
status = get_hw_addr(dev);
- for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */
- printk("%2.2x:", dev->dev_addr[i]);
- }
- printk("%2.2x,\n", dev->dev_addr[i]);
+ printk(", h/w address %s\n", print_mac(mac, dev->dev_addr));
if (status != 0) {
printk(" which has an Ethernet PROM CRC error.\n");
@@ -1261,7 +1258,6 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
}
/* The DE4X5-specific entries in the device structure. */
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, gendev);
dev->open = &de4x5_open;
dev->hard_start_xmit = &de4x5_queue_pkt;
@@ -3946,7 +3942,7 @@ create_packet(struct net_device *dev, char *frame, int len)
static int
EISA_signature(char *name, struct device *device)
{
- int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
+ int i, status = 0, siglen = ARRAY_SIZE(de4x5_signatures);
struct eisa_device *edev;
*name = '\0';
@@ -3967,7 +3963,7 @@ EISA_signature(char *name, struct device *device)
static int
PCI_signature(char *name, struct de4x5_private *lp)
{
- int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
+ int i, status = 0, siglen = ARRAY_SIZE(de4x5_signatures);
if (lp->chipset == DC21040) {
strcpy(name, "DE434/5");
@@ -5073,7 +5069,7 @@ mii_get_phy(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
u_long iobase = dev->base_addr;
- int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table);
+ int i, j, k, n, limit=ARRAY_SIZE(phy_info);
int id;
lp->active = 0;
@@ -5469,19 +5465,16 @@ static void
de4x5_dbg_srom(struct de4x5_srom *p)
{
int i;
+ DECLARE_MAC_BUF(mac);
if (de4x5_debug & DEBUG_SROM) {
printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id));
printk("Sub-system ID: %04x\n", *((u_short *)p->sub_system_id));
printk("ID Block CRC: %02x\n", (u_char)(p->id_block_crc));
printk("SROM version: %02x\n", (u_char)(p->version));
- printk("# controllers: %02x\n", (u_char)(p->num_controllers));
+ printk("# controllers: %02x\n", (u_char)(p->num_controllers));
- printk("Hardware Address: ");
- for (i=0;i<ETH_ALEN-1;i++) {
- printk("%02x:", (u_char)*(p->ieee_addr+i));
- }
- printk("%02x\n", (u_char)*(p->ieee_addr+i));
+ printk("Hardware Address: %s\n", print_mac(mac, p->ieee_addr));
printk("CRC checksum: %04x\n", (u_short)(p->chksum));
for (i=0; i<64; i++) {
printk("%3d %04x\n", i<<1, (u_short)*((u_short *)p+i));
@@ -5495,21 +5488,12 @@ static void
de4x5_dbg_rx(struct sk_buff *skb, int len)
{
int i, j;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
if (de4x5_debug & DEBUG_RX) {
- printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n",
- (u_char)skb->data[0],
- (u_char)skb->data[1],
- (u_char)skb->data[2],
- (u_char)skb->data[3],
- (u_char)skb->data[4],
- (u_char)skb->data[5],
- (u_char)skb->data[6],
- (u_char)skb->data[7],
- (u_char)skb->data[8],
- (u_char)skb->data[9],
- (u_char)skb->data[10],
- (u_char)skb->data[11],
+ printk("R: %s <- %s len/SAP:%02x%02x [%d]\n",
+ print_mac(mac, skb->data), print_mac(mac2, &skb->data[6]),
(u_char)skb->data[12],
(u_char)skb->data[13],
len);
diff --git a/drivers/net/tulip/de4x5.h b/drivers/net/tulip/de4x5.h
index 12af0cc037f..9fb8d7f0799 100644
--- a/drivers/net/tulip/de4x5.h
+++ b/drivers/net/tulip/de4x5.h
@@ -1017,4 +1017,4 @@ struct de4x5_ioctl {
#define DE4X5_SET_OMR 0x0d /* Set the OMR Register contents */
#define DE4X5_GET_REG 0x0e /* Get the DE4X5 Registers */
-#define MOTO_SROM_BUG ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((s32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
+#define MOTO_SROM_BUG ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((__le32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index dab74feb44b..ca90566d5bc 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -362,6 +362,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
struct net_device *dev;
u32 pci_pmr;
int i, err;
+ DECLARE_MAC_BUF(mac);
DMFE_DBUG(0, "dmfe_init_one()", 0);
@@ -372,7 +373,6 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*db));
if (dev == NULL)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
@@ -471,13 +471,13 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
if (err)
goto err_out_res;
- printk(KERN_INFO "%s: Davicom DM%04lx at pci%s,",
- dev->name,
- ent->driver_data >> 16,
- pci_name(pdev));
- for (i = 0; i < 6; i++)
- printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
- printk(", irq %d.\n", dev->irq);
+ printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, "
+ "%s, irq %d.\n",
+ dev->name,
+ ent->driver_data >> 16,
+ pci_name(pdev),
+ print_mac(mac, dev->dev_addr),
+ dev->irq);
pci_set_master(pdev);
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 53efd6694e7..36533144638 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -103,28 +103,29 @@ int tulip_refill_rx(struct net_device *dev)
void oom_timer(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
- netif_rx_schedule(dev);
+ struct tulip_private *tp = netdev_priv(dev);
+ netif_rx_schedule(dev, &tp->napi);
}
-int tulip_poll(struct net_device *dev, int *budget)
+int tulip_poll(struct napi_struct *napi, int budget)
{
- struct tulip_private *tp = netdev_priv(dev);
+ struct tulip_private *tp = container_of(napi, struct tulip_private, napi);
+ struct net_device *dev = tp->dev;
int entry = tp->cur_rx % RX_RING_SIZE;
- int rx_work_limit = *budget;
+ int work_done = 0;
+#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
int received = 0;
+#endif
if (!netif_running(dev))
goto done;
- if (rx_work_limit > dev->quota)
- rx_work_limit = dev->quota;
-
#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
/* that one buffer is needed for mit activation; or might be a
bug in the ring buffer code; check later -- JHS*/
- if (rx_work_limit >=RX_RING_SIZE) rx_work_limit--;
+ if (budget >=RX_RING_SIZE) budget--;
#endif
if (tulip_debug > 4)
@@ -144,14 +145,13 @@ int tulip_poll(struct net_device *dev, int *budget)
while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
s32 status = le32_to_cpu(tp->rx_ring[entry].status);
-
if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx)
break;
if (tulip_debug > 5)
printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
dev->name, entry, status);
- if (--rx_work_limit < 0)
+ if (work_done++ >= budget)
goto not_done;
if ((status & 0x38008300) != 0x0300) {
@@ -238,7 +238,9 @@ int tulip_poll(struct net_device *dev, int *budget)
tp->stats.rx_packets++;
tp->stats.rx_bytes += pkt_len;
}
- received++;
+#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
+ received++;
+#endif
entry = (++tp->cur_rx) % RX_RING_SIZE;
if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4)
@@ -296,17 +298,15 @@ done:
#endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */
- dev->quota -= received;
- *budget -= received;
-
tulip_refill_rx(dev);
/* If RX ring is not full we are out of memory. */
- if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom;
+ if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
+ goto oom;
/* Remove us from polling list and enable RX intr. */
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7);
/* The last op happens after poll completion. Which means the following:
@@ -320,28 +320,20 @@ done:
* processed irqs. But it must not result in losing events.
*/
- return 0;
+ return work_done;
not_done:
- if (!received) {
-
- received = dev->quota; /* Not to happen */
- }
- dev->quota -= received;
- *budget -= received;
-
if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 ||
tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
tulip_refill_rx(dev);
- if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom;
-
- return 1;
+ if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
+ goto oom;
+ return work_done;
oom: /* Executed with RX ints disabled */
-
/* Start timer, stop polling, but do not enable rx interrupts. */
mod_timer(&tp->oom_timer, jiffies+1);
@@ -350,9 +342,9 @@ done:
* before we did netif_rx_complete(). See? We would lose it. */
/* remove ourselves from the polling list */
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
- return 0;
+ return work_done;
}
#else /* CONFIG_TULIP_NAPI */
@@ -534,7 +526,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
rxd++;
/* Mask RX intrs and add the device to poll list. */
iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7);
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &tp->napi);
if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass)))
break;
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 16f26a8364f..3f69f53d776 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -178,18 +178,18 @@ enum tulip_busconfig_bits {
/* The Tulip Rx and Tx buffer descriptors. */
struct tulip_rx_desc {
- s32 status;
- s32 length;
- u32 buffer1;
- u32 buffer2;
+ __le32 status;
+ __le32 length;
+ __le32 buffer1;
+ __le32 buffer2;
};
struct tulip_tx_desc {
- s32 status;
- s32 length;
- u32 buffer1;
- u32 buffer2; /* We use only buffer 1. */
+ __le32 status;
+ __le32 length;
+ __le32 buffer1;
+ __le32 buffer2; /* We use only buffer 1. */
};
@@ -353,6 +353,7 @@ struct tulip_private {
int chip_id;
int revision;
int flags;
+ struct napi_struct napi;
struct net_device_stats stats;
struct timer_list timer; /* Media selection timer. */
struct timer_list oom_timer; /* Out of memory timer. */
@@ -429,7 +430,7 @@ extern int tulip_rx_copybreak;
irqreturn_t tulip_interrupt(int irq, void *dev_instance);
int tulip_refill_rx(struct net_device *dev);
#ifdef CONFIG_TULIP_NAPI
-int tulip_poll(struct net_device *dev, int *budget);
+int tulip_poll(struct napi_struct *napi, int budget);
#endif
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index eca984f89bb..e5e2c9c4ebf 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -292,8 +292,13 @@ static void tulip_up(struct net_device *dev)
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
int next_tick = 3*HZ;
+ u32 reg;
int i;
+#ifdef CONFIG_TULIP_NAPI
+ napi_enable(&tp->napi);
+#endif
+
/* Wake the chip from sleep/snooze mode. */
tulip_set_power_state (tp, 0, 0);
@@ -303,14 +308,14 @@ static void tulip_up(struct net_device *dev)
/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
iowrite32(0x00000001, ioaddr + CSR0);
- pci_read_config_dword(tp->pdev, PCI_COMMAND, &i); /* flush write */
+ pci_read_config_dword(tp->pdev, PCI_COMMAND, &reg); /* flush write */
udelay(100);
/* Deassert reset.
Wait the specified 50 PCI cycles after a reset by initializing
Tx and Rx queues and the address filter list. */
iowrite32(tp->csr0, ioaddr + CSR0);
- pci_read_config_dword(tp->pdev, PCI_COMMAND, &i); /* flush write */
+ pci_read_config_dword(tp->pdev, PCI_COMMAND, &reg); /* flush write */
udelay(100);
if (tulip_debug > 1)
@@ -322,8 +327,8 @@ static void tulip_up(struct net_device *dev)
tp->dirty_rx = tp->dirty_tx = 0;
if (tp->flags & MC_HASH_ONLY) {
- u32 addr_low = le32_to_cpu(get_unaligned((u32 *)dev->dev_addr));
- u32 addr_high = le16_to_cpu(get_unaligned((u16 *)(dev->dev_addr+4)));
+ u32 addr_low = le32_to_cpu(get_unaligned((__le32 *)dev->dev_addr));
+ u32 addr_high = le16_to_cpu(get_unaligned((__le16 *)(dev->dev_addr+4)));
if (tp->chip_id == AX88140) {
iowrite32(0, ioaddr + CSR13);
iowrite32(addr_low, ioaddr + CSR14);
@@ -728,6 +733,10 @@ static void tulip_down (struct net_device *dev)
flush_scheduled_work();
+#ifdef CONFIG_TULIP_NAPI
+ napi_disable(&tp->napi);
+#endif
+
del_timer_sync (&tp->timer);
#ifdef CONFIG_TULIP_NAPI
del_timer_sync (&tp->oom_timer);
@@ -1043,12 +1052,11 @@ static void set_rx_mode(struct net_device *dev)
filterbit &= 0x3f;
mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
if (tulip_debug > 2) {
- printk(KERN_INFO "%s: Added filter for %2.2x:%2.2x:%2.2x:"
- "%2.2x:%2.2x:%2.2x %8.8x bit %d.\n", dev->name,
- mclist->dmi_addr[0], mclist->dmi_addr[1],
- mclist->dmi_addr[2], mclist->dmi_addr[3],
- mclist->dmi_addr[4], mclist->dmi_addr[5],
- ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
+ DECLARE_MAC_BUF(mac);
+ printk(KERN_INFO "%s: Added filter for %s"
+ " %8.8x bit %d.\n",
+ dev->name, print_mac(mac, mclist->dmi_addr),
+ ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
}
}
if (mc_filter[0] == tp->mc_filter[0] &&
@@ -1248,6 +1256,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
const char *chip_name = tulip_tbl[chip_idx].chip_name;
unsigned int eeprom_missing = 0;
unsigned int force_csr0 = 0;
+ DECLARE_MAC_BUF(mac);
#ifndef MODULE
static int did_version; /* Already printed version info. */
@@ -1337,7 +1346,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
printk (KERN_ERR PFX "%s: I/O region (0x%llx@0x%llx) too small, "
@@ -1436,13 +1444,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
do
value = ioread32(ioaddr + CSR9);
while (value < 0 && --boguscnt > 0);
- put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i);
+ put_unaligned(cpu_to_le16(value), ((__le16*)dev->dev_addr) + i);
sum += value & 0xffff;
}
} else if (chip_idx == COMET) {
/* No need to read the EEPROM. */
- put_unaligned(cpu_to_le32(ioread32(ioaddr + 0xA4)), (u32 *)dev->dev_addr);
- put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (u16 *)(dev->dev_addr + 4));
+ put_unaligned(cpu_to_le32(ioread32(ioaddr + 0xA4)), (__le32 *)dev->dev_addr);
+ put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (__le16 *)(dev->dev_addr + 4));
for (i = 0; i < 6; i ++)
sum += dev->dev_addr[i];
} else {
@@ -1606,8 +1614,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
dev->tx_timeout = tulip_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
#ifdef CONFIG_TULIP_NAPI
- dev->poll = tulip_poll;
- dev->weight = 16;
+ netif_napi_add(dev, &tp->napi, tulip_poll, 16);
#endif
dev->stop = tulip_close;
dev->get_stats = tulip_get_stats;
@@ -1633,8 +1640,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
if (eeprom_missing)
printk(" EEPROM not present,");
- for (i = 0; i < 6; i++)
- printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]);
+ printk(" %s", print_mac(mac, dev->dev_addr));
printk(", IRQ %d.\n", irq);
if (tp->chip_id == PNIC2)
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index ca2548eb7d6..a7afeea156b 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -34,9 +34,9 @@
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
+#include <linux/bitops.h>
#include <asm/processor.h>
-#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
@@ -112,13 +112,13 @@
/* Structure/enum declaration ------------------------------- */
struct tx_desc {
- u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
+ __le32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
char *tx_buf_ptr; /* Data for us */
struct tx_desc *next_tx_desc;
} __attribute__(( aligned(32) ));
struct rx_desc {
- u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
+ __le32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
struct sk_buff *rx_skb_ptr; /* Data for us */
struct rx_desc *next_rx_desc;
} __attribute__(( aligned(32) ));
@@ -258,6 +258,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
struct uli526x_board_info *db; /* board information structure */
struct net_device *dev;
int i, err;
+ DECLARE_MAC_BUF(mac);
ULI526X_DBUG(0, "uli526x_init_one()", 0);
@@ -268,7 +269,6 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*db));
if (dev == NULL)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
@@ -344,7 +344,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
/* read 64 word srom data */
for (i = 0; i < 64; i++)
- ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i));
+ ((__le16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i));
/* Set Node address */
if(((u16 *) db->srom)[0] == 0xffff || ((u16 *) db->srom)[0] == 0) /* SROM absent, so read MAC address from ID Table */
@@ -373,11 +373,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
if (err)
goto err_out_res;
- printk(KERN_INFO "%s: ULi M%04lx at pci%s,",dev->name,ent->driver_data >> 16,pci_name(pdev));
-
- for (i = 0; i < 6; i++)
- printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
- printk(", irq %d.\n", dev->irq);
+ printk(KERN_INFO "%s: ULi M%04lx at pci%s, %s, irq %d.\n",
+ dev->name,ent->driver_data >> 16,pci_name(pdev),
+ print_mac(mac, dev->dev_addr), dev->irq);
pci_set_master(pdev);
@@ -666,11 +664,6 @@ static irqreturn_t uli526x_interrupt(int irq, void *dev_id)
unsigned long ioaddr = dev->base_addr;
unsigned long flags;
- if (!dev) {
- ULI526X_DBUG(1, "uli526x_interrupt() without DEVICE arg", 0);
- return IRQ_NONE;
- }
-
spin_lock_irqsave(&db->lock, flags);
outl(0, ioaddr + DCR7);
@@ -1110,19 +1103,15 @@ static void uli526x_timer(unsigned long data)
/*
- * Dynamic reset the ULI526X board
* Stop ULI526X board
* Free Tx/Rx allocated memory
- * Reset ULI526X board
- * Re-initialize ULI526X board
+ * Init system variable
*/
-static void uli526x_dynamic_reset(struct net_device *dev)
+static void uli526x_reset_prepare(struct net_device *dev)
{
struct uli526x_board_info *db = netdev_priv(dev);
- ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0);
-
/* Sopt MAC controller */
db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */
update_cr6(db->cr6_data, dev->base_addr);
@@ -1141,6 +1130,22 @@ static void uli526x_dynamic_reset(struct net_device *dev)
db->link_failed = 1;
db->init=1;
db->wait_reset = 0;
+}
+
+
+/*
+ * Dynamic reset the ULI526X board
+ * Stop ULI526X board
+ * Free Tx/Rx allocated memory
+ * Reset ULI526X board
+ * Re-initialize ULI526X board
+ */
+
+static void uli526x_dynamic_reset(struct net_device *dev)
+{
+ ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0);
+
+ uli526x_reset_prepare(dev);
/* Re-initialize ULI526X board */
uli526x_init(dev);
@@ -1150,6 +1155,88 @@ static void uli526x_dynamic_reset(struct net_device *dev)
}
+#ifdef CONFIG_PM
+
+/*
+ * Suspend the interface.
+ */
+
+static int uli526x_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ pci_power_t power_state;
+ int err;
+
+ ULI526X_DBUG(0, "uli526x_suspend", 0);
+
+ if (!netdev_priv(dev))
+ return 0;
+
+ pci_save_state(pdev);
+
+ if (!netif_running(dev))
+ return 0;
+
+ netif_device_detach(dev);
+ uli526x_reset_prepare(dev);
+
+ power_state = pci_choose_state(pdev, state);
+ pci_enable_wake(pdev, power_state, 0);
+ err = pci_set_power_state(pdev, power_state);
+ if (err) {
+ netif_device_attach(dev);
+ /* Re-initialize ULI526X board */
+ uli526x_init(dev);
+ /* Restart upper layer interface */
+ netif_wake_queue(dev);
+ }
+
+ return err;
+}
+
+/*
+ * Resume the interface.
+ */
+
+static int uli526x_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ int err;
+
+ ULI526X_DBUG(0, "uli526x_resume", 0);
+
+ if (!netdev_priv(dev))
+ return 0;
+
+ pci_restore_state(pdev);
+
+ if (!netif_running(dev))
+ return 0;
+
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err) {
+ printk(KERN_WARNING "%s: Could not put device into D0\n",
+ dev->name);
+ return err;
+ }
+
+ netif_device_attach(dev);
+ /* Re-initialize ULI526X board */
+ uli526x_init(dev);
+ /* Restart upper layer interface */
+ netif_wake_queue(dev);
+
+ return 0;
+}
+
+#else /* !CONFIG_PM */
+
+#define uli526x_suspend NULL
+#define uli526x_resume NULL
+
+#endif /* !CONFIG_PM */
+
+
/*
* free all allocated rx buffer
*/
@@ -1512,7 +1599,6 @@ static void uli526x_process_mode(struct uli526x_board_info *db)
case ULI526X_100MFD: phy_reg = 0x2100; break;
}
phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
- phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
}
}
}
@@ -1689,6 +1775,8 @@ static struct pci_driver uli526x_driver = {
.id_table = uli526x_pci_tbl,
.probe = uli526x_init_one,
.remove = __devexit_p(uli526x_remove_one),
+ .suspend = uli526x_suspend,
+ .resume = uli526x_resume,
};
MODULE_AUTHOR("Peer Chen, peer.chen@uli.com.tw");
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 5824f6a3549..35d0cfcf8c4 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -354,6 +354,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
int irq;
int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
void __iomem *ioaddr;
+ DECLARE_MAC_BUF(mac);
i = pci_enable_device(pdev);
if (i) return i;
@@ -370,7 +371,6 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*np));
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_request_regions(pdev, DRV_NAME))
@@ -381,7 +381,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
goto err_out_free_res;
for (i = 0; i < 3; i++)
- ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i));
+ ((__le16 *)dev->dev_addr)[i] = cpu_to_le16(eeprom_read(ioaddr, i));
/* Reset the chip to erase previous misconfiguration.
No hold time required! */
@@ -434,11 +434,9 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
if (i)
goto err_out_cleardev;
- printk(KERN_INFO "%s: %s at %p, ",
- dev->name, pci_id_tbl[chip_idx].name, ioaddr);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+ printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+ dev->name, pci_id_tbl[chip_idx].name, ioaddr,
+ print_mac(mac, dev->dev_addr), irq);
if (np->drv_flags & CanHaveMII) {
int phy, phy_idx = 0;
@@ -485,7 +483,7 @@ err_out_netdev:
a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that
made udelay() unreliable.
The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is
- depricated.
+ deprecated.
*/
#define eeprom_delay(ee_addr) ioread32(ee_addr)
@@ -1246,16 +1244,16 @@ static int netdev_rx(struct net_device *dev)
}
#ifndef final_version /* Remove after testing. */
/* You will want this info for the initial debug. */
- if (debug > 5)
- printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
- "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
- "%d.%d.%d.%d.\n",
- skb->data[0], skb->data[1], skb->data[2], skb->data[3],
- skb->data[4], skb->data[5], skb->data[6], skb->data[7],
- skb->data[8], skb->data[9], skb->data[10],
- skb->data[11], skb->data[12], skb->data[13],
- skb->data[14], skb->data[15], skb->data[16],
- skb->data[17]);
+ if (debug > 5) {
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+
+ printk(KERN_DEBUG " Rx data %s %s"
+ " %2.2x%2.2x %d.%d.%d.%d.\n",
+ print_mac(mac, &skb->data[0]), print_mac(mac2, &skb->data[6]),
+ skb->data[12], skb->data[13],
+ skb->data[14], skb->data[15], skb->data[16], skb->data[17]);
+ }
#endif
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
@@ -1452,8 +1450,6 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.get_link = netdev_get_link,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
- .get_sg = ethtool_op_get_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
};
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 16a54e6b8d4..70befe33e45 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -252,7 +252,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
goto tx_buf_fail;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -271,7 +270,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
dev->hard_start_xmit = &xircom_start_xmit;
dev->stop = &xircom_close;
dev->get_stats = &xircom_get_stats;
- dev->priv = private;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = &xircom_poll_controller;
#endif
@@ -1076,6 +1074,7 @@ static void read_mac_address(struct xircom_private *card)
unsigned char j, tuple, link, data_id, data_count;
unsigned long flags;
int i;
+ DECLARE_MAC_BUF(mac);
enter("read_mac_address");
@@ -1105,11 +1104,7 @@ static void read_mac_address(struct xircom_private *card)
}
}
spin_unlock_irqrestore(&card->lock, flags);
-#ifdef DEBUG
- for (i = 0; i < 6; i++)
- printk("%c%2.2X", i ? ':' : ' ', card->dev->dev_addr[i]);
- printk("\n");
-#endif
+ pr_debug(" %s\n", print_mac(mac, card->dev->dev_addr));
leave("read_mac_address");
}
diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
index fc439f33335..c3f8e303c6c 100644
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -547,7 +547,6 @@ static int __devinit xircom_init_one(struct pci_dev *pdev, const struct pci_devi
printk (KERN_ERR DRV_NAME "%d: cannot alloc etherdev, aborting\n", board_idx);
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
dev->base_addr = ioaddr;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 62b2b300501..1f764469597 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -62,6 +62,7 @@
#include <linux/if_ether.h>
#include <linux/if_tun.h>
#include <linux/crc32.h>
+#include <net/net_namespace.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -109,7 +110,7 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
/* We won't see all dropped packets individually, so overrun
* error is more appropriate. */
- tun->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
} else {
/* Single queue mode.
* Driver handles dropping of all packets itself. */
@@ -128,7 +129,7 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
drop:
- tun->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
kfree_skb(skb);
return 0;
}
@@ -158,23 +159,28 @@ tun_net_mclist(struct net_device *dev)
struct tun_struct *tun = netdev_priv(dev);
const struct dev_mc_list *mclist;
int i;
+ DECLARE_MAC_BUF(mac);
DBG(KERN_DEBUG "%s: tun_net_mclist: mc_count %d\n",
dev->name, dev->mc_count);
memset(tun->chr_filter, 0, sizeof tun->chr_filter);
for (i = 0, mclist = dev->mc_list; i < dev->mc_count && mclist != NULL;
i++, mclist = mclist->next) {
add_multi(tun->net_filter, mclist->dmi_addr);
- DBG(KERN_DEBUG "%s: tun_net_mclist: %x:%x:%x:%x:%x:%x\n",
- dev->name,
- mclist->dmi_addr[0], mclist->dmi_addr[1], mclist->dmi_addr[2],
- mclist->dmi_addr[3], mclist->dmi_addr[4], mclist->dmi_addr[5]);
+ DBG(KERN_DEBUG "%s: tun_net_mclist: %s\n",
+ dev->name, print_mac(mac, mclist->dmi_addr));
}
}
-static struct net_device_stats *tun_net_stats(struct net_device *dev)
+#define MIN_MTU 68
+#define MAX_MTU 65535
+
+static int
+tun_net_change_mtu(struct net_device *dev, int new_mtu)
{
- struct tun_struct *tun = netdev_priv(dev);
- return &tun->stats;
+ if (new_mtu < MIN_MTU || new_mtu + dev->hard_header_len > MAX_MTU)
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
}
/* Initialize net device. */
@@ -188,6 +194,7 @@ static void tun_net_init(struct net_device *dev)
dev->hard_header_len = 0;
dev->addr_len = 0;
dev->mtu = 1500;
+ dev->change_mtu = tun_net_change_mtu;
/* Zero header length */
dev->type = ARPHRD_NONE;
@@ -200,6 +207,7 @@ static void tun_net_init(struct net_device *dev)
dev->set_multicast_list = tun_net_mclist;
ether_setup(dev);
+ dev->change_mtu = tun_net_change_mtu;
/* random address already created for us by tun_set_iff, use it */
memcpy(dev->dev_addr, tun->dev_addr, min(sizeof(tun->dev_addr), sizeof(dev->dev_addr)) );
@@ -249,14 +257,14 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv,
align = NET_IP_ALIGN;
if (!(skb = alloc_skb(len + align, GFP_KERNEL))) {
- tun->stats.rx_dropped++;
+ tun->dev->stats.rx_dropped++;
return -ENOMEM;
}
if (align)
skb_reserve(skb, align);
if (memcpy_fromiovec(skb_put(skb, len), iv, len)) {
- tun->stats.rx_dropped++;
+ tun->dev->stats.rx_dropped++;
kfree_skb(skb);
return -EFAULT;
}
@@ -278,8 +286,8 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv,
netif_rx_ni(skb);
tun->dev->last_rx = jiffies;
- tun->stats.rx_packets++;
- tun->stats.rx_bytes += len;
+ tun->dev->stats.rx_packets++;
+ tun->dev->stats.rx_bytes += len;
return count;
}
@@ -335,8 +343,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
skb_copy_datagram_iovec(skb, 0, iv, len);
total += len;
- tun->stats.tx_packets++;
- tun->stats.tx_bytes += len;
+ tun->dev->stats.tx_packets++;
+ tun->dev->stats.tx_bytes += len;
return total;
}
@@ -349,6 +357,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
DECLARE_WAITQUEUE(wait, current);
struct sk_buff *skb;
ssize_t len, ret = 0;
+ DECLARE_MAC_BUF(mac);
if (!tun)
return -EBADFD;
@@ -403,16 +412,14 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
(addr[0] == 0x33 && addr[1] == 0x33)) &&
((tun->if_flags & IFF_ALLMULTI) ||
(tun->chr_filter[bit_nr >> 5] & (1 << (bit_nr & 31)))))) {
- DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %x:%x:%x:%x:%x:%x\n",
- tun->dev->name, addr[0], addr[1], addr[2],
- addr[3], addr[4], addr[5]);
+ DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %s\n",
+ tun->dev->name, print_mac(mac, addr));
ret = tun_put_user(tun, skb, (struct iovec *) iv, len);
kfree_skb(skb);
break;
} else {
- DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %x:%x:%x:%x:%x:%x\n",
- tun->dev->name, addr[0], addr[1], addr[2],
- addr[3], addr[4], addr[5]);
+ DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %s\n",
+ tun->dev->name, print_mac(mac, addr));
kfree_skb(skb);
continue;
}
@@ -434,11 +441,9 @@ static void tun_setup(struct net_device *dev)
tun->owner = -1;
tun->group = -1;
- SET_MODULE_OWNER(dev);
dev->open = tun_net_open;
dev->hard_start_xmit = tun_net_xmit;
dev->stop = tun_net_close;
- dev->get_stats = tun_net_stats;
dev->ethtool_ops = &tun_ethtool_ops;
dev->destructor = free_netdev;
}
@@ -475,7 +480,7 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr)
!capable(CAP_NET_ADMIN))
return -EPERM;
}
- else if (__dev_get_by_name(ifr->ifr_name))
+ else if (__dev_get_by_name(&init_net, ifr->ifr_name))
return -EINVAL;
else {
char *name;
@@ -557,6 +562,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file,
struct tun_struct *tun = file->private_data;
void __user* argp = (void __user*)arg;
struct ifreq ifr;
+ DECLARE_MAC_BUF(mac);
if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89)
if (copy_from_user(&ifr, argp, sizeof ifr))
@@ -685,22 +691,16 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file,
/** Add the specified group to the character device's multicast filter
* list. */
add_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data);
- DBG(KERN_DEBUG "%s: add multi: %x:%x:%x:%x:%x:%x\n",
- tun->dev->name,
- (u8)ifr.ifr_hwaddr.sa_data[0], (u8)ifr.ifr_hwaddr.sa_data[1],
- (u8)ifr.ifr_hwaddr.sa_data[2], (u8)ifr.ifr_hwaddr.sa_data[3],
- (u8)ifr.ifr_hwaddr.sa_data[4], (u8)ifr.ifr_hwaddr.sa_data[5]);
+ DBG(KERN_DEBUG "%s: add multi: %s\n",
+ tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data));
return 0;
case SIOCDELMULTI:
/** Remove the specified group from the character device's multicast
* filter list. */
del_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data);
- DBG(KERN_DEBUG "%s: del multi: %x:%x:%x:%x:%x:%x\n",
- tun->dev->name,
- (u8)ifr.ifr_hwaddr.sa_data[0], (u8)ifr.ifr_hwaddr.sa_data[1],
- (u8)ifr.ifr_hwaddr.sa_data[2], (u8)ifr.ifr_hwaddr.sa_data[3],
- (u8)ifr.ifr_hwaddr.sa_data[4], (u8)ifr.ifr_hwaddr.sa_data[5]);
+ DBG(KERN_DEBUG "%s: del multi: %s\n",
+ tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data));
return 0;
default:
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 03587205546..94ac5869bb1 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -284,6 +284,7 @@ struct typhoon {
struct basic_ring rxLoRing;
struct pci_dev * pdev;
struct net_device * dev;
+ struct napi_struct napi;
spinlock_t state_lock;
struct vlan_group * vlgrp;
struct basic_ring rxHiRing;
@@ -299,9 +300,9 @@ struct typhoon {
const char * name;
struct typhoon_shared * shared;
dma_addr_t shared_dma;
- u16 xcvr_select;
- u16 wol_events;
- u32 offload;
+ __le16 xcvr_select;
+ __le16 wol_events;
+ __le32 offload;
/* unused stuff (future use) */
int capabilities;
@@ -827,7 +828,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
first_txd->processFlags |=
TYPHOON_TX_PF_INSERT_VLAN | TYPHOON_TX_PF_VLAN_PRIORITY;
first_txd->processFlags |=
- cpu_to_le32(htons(vlan_tx_tag_get(skb)) <<
+ cpu_to_le32(ntohs(vlan_tx_tag_get(skb)) <<
TYPHOON_TX_PF_VLAN_TAG_SHIFT);
}
@@ -919,7 +920,7 @@ typhoon_set_rx_mode(struct net_device *dev)
struct typhoon *tp = netdev_priv(dev);
struct cmd_desc xp_cmd;
u32 mc_filter[2];
- u16 filter;
+ __le16 filter;
filter = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST;
if(dev->flags & IFF_PROMISC) {
@@ -1130,7 +1131,7 @@ typhoon_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct typhoon *tp = netdev_priv(dev);
struct cmd_desc xp_cmd;
- int xcvr;
+ __le16 xcvr;
int err;
err = -EINVAL;
@@ -1235,11 +1236,8 @@ static const struct ethtool_ops typhoon_ethtool_ops = {
.set_wol = typhoon_set_wol,
.get_link = ethtool_op_get_link,
.get_rx_csum = typhoon_get_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.get_ringparam = typhoon_get_ringparam,
};
@@ -1538,7 +1536,7 @@ out_timeout:
static u32
typhoon_clean_tx(struct typhoon *tp, struct transmit_ring *txRing,
- volatile u32 * index)
+ volatile __le32 * index)
{
u32 lastRead = txRing->lastRead;
struct tx_desc *tx;
@@ -1574,7 +1572,7 @@ typhoon_clean_tx(struct typhoon *tp, struct transmit_ring *txRing,
static void
typhoon_tx_complete(struct typhoon *tp, struct transmit_ring *txRing,
- volatile u32 * index)
+ volatile __le32 * index)
{
u32 lastRead;
int numDesc = MAX_SKB_FRAGS + 1;
@@ -1664,8 +1662,8 @@ typhoon_alloc_rx_skb(struct typhoon *tp, u32 idx)
}
static int
-typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready,
- volatile u32 * cleared, int budget)
+typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile __le32 * ready,
+ volatile __le32 * cleared, int budget)
{
struct rx_desc *rx;
struct sk_buff *skb, *new_skb;
@@ -1675,7 +1673,7 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready,
u32 rxaddr;
int pkt_len;
u32 idx;
- u32 csum_bits;
+ __le32 csum_bits;
int received;
received = 0;
@@ -1759,12 +1757,12 @@ typhoon_fill_free_ring(struct typhoon *tp)
}
static int
-typhoon_poll(struct net_device *dev, int *total_budget)
+typhoon_poll(struct napi_struct *napi, int budget)
{
- struct typhoon *tp = netdev_priv(dev);
+ struct typhoon *tp = container_of(napi, struct typhoon, napi);
+ struct net_device *dev = tp->dev;
struct typhoon_indexes *indexes = tp->indexes;
- int orig_budget = *total_budget;
- int budget, work_done, done;
+ int work_done;
rmb();
if(!tp->awaiting_resp && indexes->respReady != indexes->respCleared)
@@ -1773,30 +1771,16 @@ typhoon_poll(struct net_device *dev, int *total_budget)
if(le32_to_cpu(indexes->txLoCleared) != tp->txLoRing.lastRead)
typhoon_tx_complete(tp, &tp->txLoRing, &indexes->txLoCleared);
- if(orig_budget > dev->quota)
- orig_budget = dev->quota;
-
- budget = orig_budget;
work_done = 0;
- done = 1;
if(indexes->rxHiCleared != indexes->rxHiReady) {
- work_done = typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady,
+ work_done += typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady,
&indexes->rxHiCleared, budget);
- budget -= work_done;
}
if(indexes->rxLoCleared != indexes->rxLoReady) {
work_done += typhoon_rx(tp, &tp->rxLoRing, &indexes->rxLoReady,
- &indexes->rxLoCleared, budget);
- }
-
- if(work_done) {
- *total_budget -= work_done;
- dev->quota -= work_done;
-
- if(work_done >= orig_budget)
- done = 0;
+ &indexes->rxLoCleared, budget - work_done);
}
if(le32_to_cpu(indexes->rxBuffCleared) == tp->rxBuffRing.lastWrite) {
@@ -1804,20 +1788,20 @@ typhoon_poll(struct net_device *dev, int *total_budget)
typhoon_fill_free_ring(tp);
}
- if(done) {
- netif_rx_complete(dev);
+ if (work_done < budget) {
+ netif_rx_complete(dev, napi);
iowrite32(TYPHOON_INTR_NONE,
tp->ioaddr + TYPHOON_REG_INTR_MASK);
typhoon_post_pci_writes(tp->ioaddr);
}
- return (done ? 0 : 1);
+ return work_done;
}
static irqreturn_t
typhoon_interrupt(int irq, void *dev_instance)
{
- struct net_device *dev = (struct net_device *) dev_instance;
+ struct net_device *dev = dev_instance;
struct typhoon *tp = dev->priv;
void __iomem *ioaddr = tp->ioaddr;
u32 intr_status;
@@ -1828,10 +1812,10 @@ typhoon_interrupt(int irq, void *dev_instance)
iowrite32(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS);
- if(netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &tp->napi)) {
iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
typhoon_post_pci_writes(ioaddr);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &tp->napi);
} else {
printk(KERN_ERR "%s: Error, poll already scheduled\n",
dev->name);
@@ -1856,7 +1840,7 @@ typhoon_free_rx_rings(struct typhoon *tp)
}
static int
-typhoon_sleep(struct typhoon *tp, pci_power_t state, u16 events)
+typhoon_sleep(struct typhoon *tp, pci_power_t state, __le16 events)
{
struct pci_dev *pdev = tp->pdev;
void __iomem *ioaddr = tp->ioaddr;
@@ -1944,8 +1928,8 @@ typhoon_start_runtime(struct typhoon *tp)
goto error_out;
INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS);
- xp_cmd.parm1 = cpu_to_le16(ntohs(*(u16 *)&dev->dev_addr[0]));
- xp_cmd.parm2 = cpu_to_le32(ntohl(*(u32 *)&dev->dev_addr[2]));
+ xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0]));
+ xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2]));
err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
if(err < 0)
goto error_out;
@@ -2119,9 +2103,13 @@ typhoon_open(struct net_device *dev)
if(err < 0)
goto out_sleep;
+ napi_enable(&tp->napi);
+
err = typhoon_start_runtime(tp);
- if(err < 0)
+ if(err < 0) {
+ napi_disable(&tp->napi);
goto out_irq;
+ }
netif_start_queue(dev);
return 0;
@@ -2150,6 +2138,7 @@ typhoon_close(struct net_device *dev)
struct typhoon *tp = netdev_priv(dev);
netif_stop_queue(dev);
+ napi_disable(&tp->napi);
if(typhoon_stop_runtime(tp, WaitSleep) < 0)
printk(KERN_ERR "%s: unable to stop runtime\n", dev->name);
@@ -2240,8 +2229,8 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
}
INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS);
- xp_cmd.parm1 = cpu_to_le16(ntohs(*(u16 *)&dev->dev_addr[0]));
- xp_cmd.parm2 = cpu_to_le32(ntohl(*(u32 *)&dev->dev_addr[2]));
+ xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0]));
+ xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2]));
if(typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL) < 0) {
printk(KERN_ERR "%s: unable to set mac address in suspend\n",
dev->name);
@@ -2327,8 +2316,8 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dma_addr_t shared_dma;
struct cmd_desc xp_cmd;
struct resp_desc xp_resp[3];
- int i;
int err = 0;
+ DECLARE_MAC_BUF(mac);
if(!did_version++)
printk(KERN_INFO "%s", version);
@@ -2340,7 +2329,6 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
err = -ENOMEM;
goto error_out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = pci_enable_device(pdev);
@@ -2477,8 +2465,8 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto error_out_reset;
}
- *(u16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
- *(u32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
+ *(__be16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
+ *(__be32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
if(!is_valid_ether_addr(dev->dev_addr)) {
printk(ERR_PFX "%s: Could not obtain valid ethernet address, "
@@ -2521,8 +2509,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->stop = typhoon_close;
dev->set_multicast_list = typhoon_set_rx_mode;
dev->tx_timeout = typhoon_tx_timeout;
- dev->poll = typhoon_poll;
- dev->weight = 16;
+ netif_napi_add(dev, &tp->napi, typhoon_poll, 16);
dev->watchdog_timeo = TX_TIMEOUT;
dev->get_stats = typhoon_get_stats;
dev->set_mac_address = typhoon_set_mac_address;
@@ -2545,13 +2532,11 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, dev);
- printk(KERN_INFO "%s: %s at %s 0x%llx, ",
+ printk(KERN_INFO "%s: %s at %s 0x%llx, %s\n",
dev->name, typhoon_card_info[card_id].name,
use_mmio ? "MMIO" : "IO",
- (unsigned long long)pci_resource_start(pdev, use_mmio));
- for(i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x\n", dev->dev_addr[i]);
+ (unsigned long long)pci_resource_start(pdev, use_mmio),
+ print_mac(mac, dev->dev_addr));
/* xp_resp still contains the response to the READ_VERSIONS command.
* For debugging, let the user know what version he has.
diff --git a/drivers/net/typhoon.h b/drivers/net/typhoon.h
index 2f14a050051..19df20889b8 100644
--- a/drivers/net/typhoon.h
+++ b/drivers/net/typhoon.h
@@ -64,19 +64,19 @@ struct transmit_ring {
*/
struct typhoon_indexes {
/* The first four are written by the host, and read by the NIC */
- volatile u32 rxHiCleared;
- volatile u32 rxLoCleared;
- volatile u32 rxBuffReady;
- volatile u32 respCleared;
+ volatile __le32 rxHiCleared;
+ volatile __le32 rxLoCleared;
+ volatile __le32 rxBuffReady;
+ volatile __le32 respCleared;
/* The remaining are written by the NIC, and read by the host */
- volatile u32 txLoCleared;
- volatile u32 txHiCleared;
- volatile u32 rxLoReady;
- volatile u32 rxBuffCleared;
- volatile u32 cmdCleared;
- volatile u32 respReady;
- volatile u32 rxHiReady;
+ volatile __le32 txLoCleared;
+ volatile __le32 txHiCleared;
+ volatile __le32 rxLoReady;
+ volatile __u32 rxBuffCleared; /* AV: really? */
+ volatile __le32 cmdCleared;
+ volatile __le32 respReady;
+ volatile __le32 rxHiReady;
} __attribute__ ((packed));
/* The host<->Typhoon interface
@@ -100,31 +100,31 @@ struct typhoon_indexes {
* be zero.
*/
struct typhoon_interface {
- u32 ringIndex;
- u32 ringIndexHi;
- u32 txLoAddr;
- u32 txLoAddrHi;
- u32 txLoSize;
- u32 txHiAddr;
- u32 txHiAddrHi;
- u32 txHiSize;
- u32 rxLoAddr;
- u32 rxLoAddrHi;
- u32 rxLoSize;
- u32 rxBuffAddr;
- u32 rxBuffAddrHi;
- u32 rxBuffSize;
- u32 cmdAddr;
- u32 cmdAddrHi;
- u32 cmdSize;
- u32 respAddr;
- u32 respAddrHi;
- u32 respSize;
- u32 zeroAddr;
- u32 zeroAddrHi;
- u32 rxHiAddr;
- u32 rxHiAddrHi;
- u32 rxHiSize;
+ __le32 ringIndex;
+ __le32 ringIndexHi;
+ __le32 txLoAddr;
+ __le32 txLoAddrHi;
+ __le32 txLoSize;
+ __le32 txHiAddr;
+ __le32 txHiAddrHi;
+ __le32 txHiSize;
+ __le32 rxLoAddr;
+ __le32 rxLoAddrHi;
+ __le32 rxLoSize;
+ __le32 rxBuffAddr;
+ __le32 rxBuffAddrHi;
+ __le32 rxBuffSize;
+ __le32 cmdAddr;
+ __le32 cmdAddrHi;
+ __le32 cmdSize;
+ __le32 respAddr;
+ __le32 respAddrHi;
+ __le32 respSize;
+ __le32 zeroAddr;
+ __le32 zeroAddrHi;
+ __le32 rxHiAddr;
+ __le32 rxHiAddrHi;
+ __le32 rxHiSize;
} __attribute__ ((packed));
/* The Typhoon transmit/fragment descriptor
@@ -165,10 +165,10 @@ struct tx_desc {
#define TYPHOON_RX_ERROR 0x40
#define TYPHOON_DESC_VALID 0x80
u8 numDesc;
- u16 len;
+ __le16 len;
u32 addr;
u32 addrHi;
- u32 processFlags;
+ __le32 processFlags;
#define TYPHOON_TX_PF_NO_CRC __constant_cpu_to_le32(0x00000001)
#define TYPHOON_TX_PF_IP_CHKSUM __constant_cpu_to_le32(0x00000002)
#define TYPHOON_TX_PF_TCP_CHKSUM __constant_cpu_to_le32(0x00000004)
@@ -197,12 +197,12 @@ struct tx_desc {
struct tcpopt_desc {
u8 flags;
u8 numDesc;
- u16 mss_flags;
+ __le16 mss_flags;
#define TYPHOON_TSO_FIRST __constant_cpu_to_le16(0x1000)
#define TYPHOON_TSO_LAST __constant_cpu_to_le16(0x2000)
- u32 respAddrLo;
- u32 bytesTx;
- u32 status;
+ __le32 respAddrLo;
+ __le32 bytesTx;
+ __le32 status;
} __attribute__ ((packed));
/* The IPSEC Offload descriptor
@@ -216,12 +216,12 @@ struct tcpopt_desc {
struct ipsec_desc {
u8 flags;
u8 numDesc;
- u16 ipsecFlags;
+ __le16 ipsecFlags;
#define TYPHOON_IPSEC_GEN_IV __constant_cpu_to_le16(0x0000)
#define TYPHOON_IPSEC_USE_IV __constant_cpu_to_le16(0x0001)
- u32 sa1;
- u32 sa2;
- u32 reserved;
+ __le32 sa1;
+ __le32 sa2;
+ __le32 reserved;
} __attribute__ ((packed));
/* The Typhoon receive descriptor (Updated by NIC)
@@ -239,10 +239,10 @@ struct ipsec_desc {
struct rx_desc {
u8 flags;
u8 numDesc;
- u16 frameLen;
+ __le16 frameLen;
u32 addr;
u32 addrHi;
- u32 rxStatus;
+ __le32 rxStatus;
#define TYPHOON_RX_ERR_INTERNAL __constant_cpu_to_le32(0x00000000)
#define TYPHOON_RX_ERR_FIFO_UNDERRUN __constant_cpu_to_le32(0x00000001)
#define TYPHOON_RX_ERR_BAD_SSD __constant_cpu_to_le32(0x00000002)
@@ -264,10 +264,10 @@ struct rx_desc {
#define TYPHOON_RX_IP_CHK_GOOD __constant_cpu_to_le32(0x00000100)
#define TYPHOON_RX_TCP_CHK_GOOD __constant_cpu_to_le32(0x00000200)
#define TYPHOON_RX_UDP_CHK_GOOD __constant_cpu_to_le32(0x00000400)
- u16 filterResults;
+ __le16 filterResults;
#define TYPHOON_RX_FILTER_MASK __constant_cpu_to_le16(0x7fff)
#define TYPHOON_RX_FILTERED __constant_cpu_to_le16(0x8000)
- u16 ipsecResults;
+ __le16 ipsecResults;
#define TYPHOON_RX_OUTER_AH_GOOD __constant_cpu_to_le16(0x0001)
#define TYPHOON_RX_OUTER_ESP_GOOD __constant_cpu_to_le16(0x0002)
#define TYPHOON_RX_INNER_AH_GOOD __constant_cpu_to_le16(0x0004)
@@ -278,7 +278,7 @@ struct rx_desc {
#define TYPHOON_RX_INNER_ESP_FAIL __constant_cpu_to_le16(0x0080)
#define TYPHOON_RX_UNKNOWN_SA __constant_cpu_to_le16(0x0100)
#define TYPHOON_RX_ESP_FORMAT_ERR __constant_cpu_to_le16(0x0200)
- u32 vlanTag;
+ __be32 vlanTag;
} __attribute__ ((packed));
/* The Typhoon free buffer descriptor, used to give a buffer to the NIC
@@ -292,8 +292,8 @@ struct rx_desc {
* from the NIC
*/
struct rx_free {
- u32 physAddr;
- u32 physAddrHi;
+ __le32 physAddr;
+ __le32 physAddrHi;
u32 virtAddr;
u32 virtAddrHi;
} __attribute__ ((packed));
@@ -312,7 +312,7 @@ struct rx_free {
struct cmd_desc {
u8 flags;
u8 numDesc;
- u16 cmd;
+ __le16 cmd;
#define TYPHOON_CMD_TX_ENABLE __constant_cpu_to_le16(0x0001)
#define TYPHOON_CMD_TX_DISABLE __constant_cpu_to_le16(0x0002)
#define TYPHOON_CMD_RX_ENABLE __constant_cpu_to_le16(0x0003)
@@ -339,9 +339,9 @@ struct cmd_desc {
#define TYPHOON_CMD_GET_IPSEC_ENABLE __constant_cpu_to_le16(0x0067)
#define TYPHOON_CMD_GET_CMD_LVL __constant_cpu_to_le16(0x0069)
u16 seqNo;
- u16 parm1;
- u32 parm2;
- u32 parm3;
+ __le16 parm1;
+ __le32 parm2;
+ __le32 parm3;
} __attribute__ ((packed));
/* The Typhoon response descriptor, see command descriptor for details
@@ -349,11 +349,11 @@ struct cmd_desc {
struct resp_desc {
u8 flags;
u8 numDesc;
- u16 cmd;
- u16 seqNo;
- u16 parm1;
- u32 parm2;
- u32 parm3;
+ __le16 cmd;
+ __le16 seqNo;
+ __le16 parm1;
+ __le32 parm2;
+ __le32 parm3;
} __attribute__ ((packed));
#define INIT_COMMAND_NO_RESPONSE(x, command) \
@@ -386,31 +386,31 @@ struct resp_desc {
struct stats_resp {
u8 flags;
u8 numDesc;
- u16 cmd;
- u16 seqNo;
- u16 unused;
- u32 txPackets;
- u64 txBytes;
- u32 txDeferred;
- u32 txLateCollisions;
- u32 txCollisions;
- u32 txCarrierLost;
- u32 txMultipleCollisions;
- u32 txExcessiveCollisions;
- u32 txFifoUnderruns;
- u32 txMulticastTxOverflows;
- u32 txFiltered;
- u32 rxPacketsGood;
- u64 rxBytesGood;
- u32 rxFifoOverruns;
- u32 BadSSD;
- u32 rxCrcErrors;
- u32 rxOversized;
- u32 rxBroadcast;
- u32 rxMulticast;
- u32 rxOverflow;
- u32 rxFiltered;
- u32 linkStatus;
+ __le16 cmd;
+ __le16 seqNo;
+ __le16 unused;
+ __le32 txPackets;
+ __le64 txBytes;
+ __le32 txDeferred;
+ __le32 txLateCollisions;
+ __le32 txCollisions;
+ __le32 txCarrierLost;
+ __le32 txMultipleCollisions;
+ __le32 txExcessiveCollisions;
+ __le32 txFifoUnderruns;
+ __le32 txMulticastTxOverflows;
+ __le32 txFiltered;
+ __le32 rxPacketsGood;
+ __le64 rxBytesGood;
+ __le32 rxFifoOverruns;
+ __le32 BadSSD;
+ __le32 rxCrcErrors;
+ __le32 rxOversized;
+ __le32 rxBroadcast;
+ __le32 rxMulticast;
+ __le32 rxOverflow;
+ __le32 rxFiltered;
+ __le32 linkStatus;
#define TYPHOON_LINK_STAT_MASK __constant_cpu_to_le32(0x00000001)
#define TYPHOON_LINK_GOOD __constant_cpu_to_le32(0x00000001)
#define TYPHOON_LINK_BAD __constant_cpu_to_le32(0x00000000)
@@ -420,8 +420,8 @@ struct stats_resp {
#define TYPHOON_LINK_DUPLEX_MASK __constant_cpu_to_le32(0x00000004)
#define TYPHOON_LINK_FULL_DUPLEX __constant_cpu_to_le32(0x00000004)
#define TYPHOON_LINK_HALF_DUPLEX __constant_cpu_to_le32(0x00000000)
- u32 unused2;
- u32 unused3;
+ __le32 unused2;
+ __le32 unused3;
} __attribute__ ((packed));
/* TYPHOON_CMD_XCVR_SELECT xcvr values (resp.parm1)
@@ -509,17 +509,17 @@ struct sa_descriptor {
*/
struct typhoon_file_header {
u8 tag[8];
- u32 version;
- u32 numSections;
- u32 startAddr;
- u32 hmacDigest[5];
+ __le32 version;
+ __le32 numSections;
+ __le32 startAddr;
+ __le32 hmacDigest[5];
} __attribute__ ((packed));
struct typhoon_section_header {
- u32 len;
+ __le32 len;
u16 checksum;
u16 reserved;
- u32 startAddr;
+ __le32 startAddr;
} __attribute__ ((packed));
/* The Typhoon Register offsets
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 9a38dfe45f8..a3ff270593f 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -63,7 +63,7 @@
#define UGETH_MSG_DEFAULT (NETIF_MSG_IFUP << 1 ) - 1
void uec_set_ethtool_ops(struct net_device *netdev);
-
+
static DEFINE_SPINLOCK(ugeth_lock);
static struct {
@@ -2214,9 +2214,7 @@ static void ucc_geth_set_multi(struct net_device *dev)
struct dev_mc_list *dmi;
struct ucc_fast *uf_regs;
struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
- u8 tempaddr[6];
- u8 *mcptr, *tdptr;
- int i, j;
+ int i;
ugeth = netdev_priv(dev);
@@ -2255,19 +2253,10 @@ static void ucc_geth_set_multi(struct net_device *dev)
if (!(dmi->dmi_addr[0] & 1))
continue;
- /* The address in dmi_addr is LSB first,
- * and taddr is MSB first. We have to
- * copy bytes MSB first from dmi_addr.
- */
- mcptr = (u8 *) dmi->dmi_addr + 5;
- tdptr = (u8 *) tempaddr;
- for (j = 0; j < 6; j++)
- *tdptr++ = *mcptr--;
-
/* Ask CPM to run CRC and set bit in
* filter mask.
*/
- hw_add_addr_in_hash(ugeth, tempaddr);
+ hw_add_addr_in_hash(ugeth, dmi->dmi_addr);
}
}
}
@@ -2919,7 +2908,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
test = in_be16(&ugeth->p_tx_glbl_pram->temoder);
/* Function code register value to be used later */
- function_code = QE_BMR_BYTE_ORDER_BO_MOT | UCC_FAST_FUNCTION_CODE_GBL;
+ function_code = UCC_BMR_BO_BE | UCC_BMR_GBL;
/* Required for QE */
/* function code register */
@@ -3350,14 +3339,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
return 0;
}
-/* returns a net_device_stats structure pointer */
-static struct net_device_stats *ucc_geth_get_stats(struct net_device *dev)
-{
- struct ucc_geth_private *ugeth = netdev_priv(dev);
-
- return &(ugeth->stats);
-}
-
/* ucc_geth_timeout gets called when a packet has not been
* transmitted after a set amount of time.
* For now, assume that clearing out all the structures, and
@@ -3368,7 +3349,7 @@ static void ucc_geth_timeout(struct net_device *dev)
ugeth_vdbg("%s: IN", __FUNCTION__);
- ugeth->stats.tx_errors++;
+ dev->stats.tx_errors++;
ugeth_dump_regs(ugeth);
@@ -3396,7 +3377,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irq(&ugeth->lock);
- ugeth->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
/* Start from the next BD that should be filled */
bd = ugeth->txBd[txQ];
@@ -3462,9 +3443,12 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
u16 length, howmany = 0;
u32 bd_status;
u8 *bdBuffer;
+ struct net_device * dev;
ugeth_vdbg("%s: IN", __FUNCTION__);
+ dev = ugeth->dev;
+
/* collect received buffers */
bd = ugeth->rxBd[rxQ];
@@ -3488,9 +3472,9 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
dev_kfree_skb_any(skb);
ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL;
- ugeth->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
} else {
- ugeth->stats.rx_packets++;
+ dev->stats.rx_packets++;
howmany++;
/* Prep the skb for the packet */
@@ -3499,7 +3483,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
/* Tell the skb what kind of packet this is */
skb->protocol = eth_type_trans(skb, ugeth->dev);
- ugeth->stats.rx_bytes += length;
+ dev->stats.rx_bytes += length;
/* Send the packet up the stack */
#ifdef CONFIG_UGETH_NAPI
netif_receive_skb(skb);
@@ -3514,7 +3498,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
if (!skb) {
if (netif_msg_rx_err(ugeth))
ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__);
- ugeth->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
@@ -3556,7 +3540,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
if ((bd == ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0))
break;
- ugeth->stats.tx_packets++;
+ dev->stats.tx_packets++;
/* Free the sk buffer associated with this TxBD */
dev_kfree_skb_irq(ugeth->
@@ -3582,47 +3566,37 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
}
#ifdef CONFIG_UGETH_NAPI
-static int ucc_geth_poll(struct net_device *dev, int *budget)
+static int ucc_geth_poll(struct napi_struct *napi, int budget)
{
- struct ucc_geth_private *ugeth = netdev_priv(dev);
+ struct ucc_geth_private *ugeth = container_of(napi, struct ucc_geth_private, napi);
+ struct net_device *dev = ugeth->dev;
struct ucc_geth_info *ug_info;
- struct ucc_fast_private *uccf;
- int howmany;
- u8 i;
- int rx_work_limit;
- register u32 uccm;
+ int howmany, i;
ug_info = ugeth->ug_info;
- rx_work_limit = *budget;
- if (rx_work_limit > dev->quota)
- rx_work_limit = dev->quota;
-
howmany = 0;
+ for (i = 0; i < ug_info->numQueuesRx; i++)
+ howmany += ucc_geth_rx(ugeth, i, budget - howmany);
- for (i = 0; i < ug_info->numQueuesRx; i++) {
- howmany += ucc_geth_rx(ugeth, i, rx_work_limit);
- }
-
- dev->quota -= howmany;
- rx_work_limit -= howmany;
- *budget -= howmany;
+ if (howmany < budget) {
+ struct ucc_fast_private *uccf;
+ u32 uccm;
- if (rx_work_limit > 0) {
- netif_rx_complete(dev);
+ netif_rx_complete(dev, napi);
uccf = ugeth->uccf;
uccm = in_be32(uccf->p_uccm);
uccm |= UCCE_RX_EVENTS;
out_be32(uccf->p_uccm, uccm);
}
- return (rx_work_limit > 0) ? 0 : 1;
+ return howmany;
}
#endif /* CONFIG_UGETH_NAPI */
static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
{
- struct net_device *dev = (struct net_device *)info;
+ struct net_device *dev = info;
struct ucc_geth_private *ugeth = netdev_priv(dev);
struct ucc_fast_private *uccf;
struct ucc_geth_info *ug_info;
@@ -3651,10 +3625,10 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
/* check for receive events that require processing */
if (ucce & UCCE_RX_EVENTS) {
#ifdef CONFIG_UGETH_NAPI
- if (netif_rx_schedule_prep(dev)) {
- uccm &= ~UCCE_RX_EVENTS;
+ if (netif_rx_schedule_prep(dev, &ugeth->napi)) {
+ uccm &= ~UCCE_RX_EVENTS;
out_be32(uccf->p_uccm, uccm);
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &ugeth->napi);
}
#else
rx_mask = UCCE_RXBF_SINGLE_MASK;
@@ -3683,10 +3657,10 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
/* Errors and other events */
if (ucce & UCCE_OTHER) {
if (ucce & UCCE_BSY) {
- ugeth->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
if (ucce & UCCE_TXE) {
- ugeth->stats.tx_errors++;
+ dev->stats.tx_errors++;
}
}
@@ -3717,12 +3691,15 @@ static int ucc_geth_open(struct net_device *dev)
return err;
}
+#ifdef CONFIG_UGETH_NAPI
+ napi_enable(&ugeth->napi);
+#endif
err = ucc_geth_startup(ugeth);
if (err) {
if (netif_msg_ifup(ugeth))
ugeth_err("%s: Cannot configure net device, aborting.",
dev->name);
- return err;
+ goto out_err;
}
err = adjust_enet_interface(ugeth);
@@ -3730,7 +3707,7 @@ static int ucc_geth_open(struct net_device *dev)
if (netif_msg_ifup(ugeth))
ugeth_err("%s: Cannot configure net device, aborting.",
dev->name);
- return err;
+ goto out_err;
}
/* Set MACSTNADDR1, MACSTNADDR2 */
@@ -3748,7 +3725,7 @@ static int ucc_geth_open(struct net_device *dev)
if (err) {
if (netif_msg_ifup(ugeth))
ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name);
- return err;
+ goto out_err;
}
phy_start(ugeth->phydev);
@@ -3761,7 +3738,7 @@ static int ucc_geth_open(struct net_device *dev)
ugeth_err("%s: Cannot get IRQ for net device, aborting.",
dev->name);
ucc_geth_stop(ugeth);
- return err;
+ goto out_err;
}
err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
@@ -3769,12 +3746,18 @@ static int ucc_geth_open(struct net_device *dev)
if (netif_msg_ifup(ugeth))
ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
ucc_geth_stop(ugeth);
- return err;
+ goto out_err;
}
netif_start_queue(dev);
return err;
+
+out_err:
+#ifdef CONFIG_UGETH_NAPI
+ napi_disable(&ugeth->napi);
+#endif
+ return err;
}
/* Stops the kernel queue, and halts the controller */
@@ -3784,6 +3767,10 @@ static int ucc_geth_close(struct net_device *dev)
ugeth_vdbg("%s: IN", __FUNCTION__);
+#ifdef CONFIG_UGETH_NAPI
+ napi_disable(&ugeth->napi);
+#endif
+
ucc_geth_stop(ugeth);
phy_disconnect(ugeth->phydev);
@@ -3954,7 +3941,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
/* Set the dev->base_addr to the gfar reg region */
dev->base_addr = (unsigned long)(ug_info->uf_info.regs);
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, device);
/* Fill in the dev structure */
@@ -3964,11 +3950,9 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
dev->tx_timeout = ucc_geth_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
#ifdef CONFIG_UGETH_NAPI
- dev->poll = ucc_geth_poll;
- dev->weight = UCC_GETH_DEV_WEIGHT;
+ netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT);
#endif /* CONFIG_UGETH_NAPI */
dev->stop = ucc_geth_close;
- dev->get_stats = ucc_geth_get_stats;
// dev->change_mtu = ucc_geth_change_mtu;
dev->mtu = 1500;
dev->set_multicast_list = ucc_geth_set_multi;
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index bb4dac8c0c6..4fb95b3af94 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -44,6 +44,7 @@
struct ucc_geth {
struct ucc_fast uccf;
+ u8 res0[0x100 - sizeof(struct ucc_fast)];
u32 maccfg1; /* mac configuration reg. 1 */
u32 maccfg2; /* mac configuration reg. 2 */
@@ -1184,7 +1185,7 @@ struct ucc_geth_private {
struct ucc_geth_info *ug_info;
struct ucc_fast_private *uccf;
struct net_device *dev;
- struct net_device_stats stats; /* linux network statistics */
+ struct napi_struct napi;
struct ucc_geth *ug_regs;
struct ucc_geth_init_pram *p_init_enet_param_shadow;
struct ucc_geth_exf_global_pram *p_exf_glbl_param;
diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c
index 64bef7c1236..9a9622c13e2 100644
--- a/drivers/net/ucc_geth_ethtool.c
+++ b/drivers/net/ucc_geth_ethtool.c
@@ -276,20 +276,26 @@ uec_set_ringparam(struct net_device *netdev,
return ret;
}
-static int uec_get_stats_count(struct net_device *netdev)
+static int uec_get_sset_count(struct net_device *netdev, int sset)
{
struct ucc_geth_private *ugeth = netdev_priv(netdev);
u32 stats_mode = ugeth->ug_info->statisticsMode;
int len = 0;
- if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE)
- len += UEC_HW_STATS_LEN;
- if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX)
- len += UEC_TX_FW_STATS_LEN;
- if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
- len += UEC_RX_FW_STATS_LEN;
+ switch (sset) {
+ case ETH_SS_STATS:
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE)
+ len += UEC_HW_STATS_LEN;
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX)
+ len += UEC_TX_FW_STATS_LEN;
+ if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
+ len += UEC_RX_FW_STATS_LEN;
+
+ return len;
- return len;
+ default:
+ return -EOPNOTSUPP;
+ }
}
static void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
@@ -353,8 +359,6 @@ uec_get_drvinfo(struct net_device *netdev,
strncpy(drvinfo->version, DRV_VERSION, 32);
strncpy(drvinfo->fw_version, "N/A", 32);
strncpy(drvinfo->bus_info, "QUICC ENGINE", 32);
- drvinfo->n_stats = uec_get_stats_count(netdev);
- drvinfo->testinfo_len = 0;
drvinfo->eedump_len = 0;
drvinfo->regdump_len = uec_get_regs_len(netdev);
}
@@ -373,10 +377,8 @@ static const struct ethtool_ops uec_ethtool_ops = {
.set_ringparam = uec_set_ringparam,
.get_pauseparam = uec_get_pauseparam,
.set_pauseparam = uec_set_pauseparam,
- .get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .get_stats_count = uec_get_stats_count,
+ .get_sset_count = uec_get_sset_count,
.get_strings = uec_get_strings,
.get_ethtool_stats = uec_get_ethtool_stats,
};
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
index 6c257b88ce5..df884f0ad8e 100644
--- a/drivers/net/ucc_geth_mii.c
+++ b/drivers/net/ucc_geth_mii.c
@@ -32,7 +32,6 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <asm/ocp.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/phy.h>
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 8dc09a3790c..a12c9c41b21 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -71,7 +71,7 @@ config USB_PEGASUS
select MII
---help---
Say Y here if you know you have Pegasus or Pegasus-II based adapter.
- If in doubt then look at <file:drivers/usb/net/pegasus.h> for the
+ If in doubt then look at <file:drivers/net/usb/pegasus.h> for the
complete list of supported devices.
If your particular adapter is not in the list and you are _sure_ it
@@ -93,13 +93,9 @@ config USB_RTL8150
To compile this driver as a module, choose M here: the
module will be called rtl8150.
-config USB_USBNET_MII
- tristate
- default n
-
config USB_USBNET
tristate "Multi-purpose USB Networking Framework"
- select MII if USB_USBNET_MII != n
+ select MII
---help---
This driver supports several kinds of network links over USB,
with "minidrivers" built around a common network driver core
@@ -135,7 +131,6 @@ config USB_NET_AX8817X
tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters"
depends on USB_USBNET && NET_ETHERNET
select CRC32
- select USB_USBNET_MII
default y
help
This option adds support for ASIX AX88xxx based USB 2.0
@@ -190,7 +185,6 @@ config USB_NET_DM9601
tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices"
depends on USB_USBNET
select CRC32
- select USB_USBNET_MII
help
This option adds support for Davicom DM9601 based USB 1.1
10/100 Ethernet adapters.
@@ -225,7 +219,6 @@ config USB_NET_PLUSB
config USB_NET_MCS7830
tristate "MosChip MCS7830 based Ethernet adapters"
depends on USB_USBNET
- select USB_USBNET_MII
help
Choose this option if you're using a 10/100 Ethernet USB2
adapter based on the MosChip 7830 controller. This includes
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 6d95cacd528..61daa096de6 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1474,6 +1474,7 @@ static struct usb_driver asix_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
+ .supports_autosuspend = 1,
};
static int __init asix_init(void)
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index a2de32fabc1..2c685734b7a 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -586,6 +586,10 @@ static const struct usb_device_id products[] = {
USB_DEVICE(0x0a46, 0x0268), /* ShanTou ST268 USB NIC */
.driver_info = (unsigned long)&dm9601_info,
},
+ {
+ USB_DEVICE(0x0a46, 0x8515), /* ADMtek ADM8515 USB NIC */
+ .driver_info = (unsigned long)&dm9601_info,
+ },
{}, // END
};
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 524dc5f5e46..58a53a64175 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -1152,8 +1152,6 @@ err_fw:
INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl);
- SET_MODULE_OWNER(netdev);
-
usb_set_intfdata(intf, kaweth);
#if 0
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index 6240b978fe3..f55a5951733 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -114,8 +114,8 @@ static void mcs7830_async_cmd_callback(struct urb *urb)
struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
if (urb->status < 0)
- printk(KERN_DEBUG "mcs7830_async_cmd_callback() failed with %d",
- urb->status);
+ printk(KERN_DEBUG "%s() failed with %d\n",
+ __FUNCTION__, urb->status);
kfree(req);
usb_free_urb(urb);
@@ -129,15 +129,15 @@ static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
- dev_dbg(&dev->udev->dev, "Error allocating URB "
- "in write_cmd_async!");
+ dev_dbg(&dev->udev->dev,
+ "Error allocating URB in write_cmd_async!\n");
return;
}
req = kmalloc(sizeof *req, GFP_ATOMIC);
if (!req) {
- dev_err(&dev->udev->dev, "Failed to allocate memory for "
- "control request");
+ dev_err(&dev->udev->dev,
+ "Failed to allocate memory for control request\n");
goto out;
}
req->bRequestType = MCS7830_WR_BMREQ;
@@ -153,8 +153,8 @@ static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0) {
- dev_err(&dev->udev->dev, "Error submitting the control "
- "message: ret=%d", ret);
+ dev_err(&dev->udev->dev,
+ "Error submitting the control message: ret=%d\n", ret);
goto out;
}
return;
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 04cba6bf3d5..d1ed68a11e7 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -1297,6 +1297,7 @@ static int pegasus_probe(struct usb_interface *intf,
pegasus_t *pegasus;
int dev_index = id - pegasus_ids;
int res = -ENOMEM;
+ DECLARE_MAC_BUF(mac);
usb_get_dev(dev);
net = alloc_etherdev(sizeof(struct pegasus));
@@ -1306,7 +1307,6 @@ static int pegasus_probe(struct usb_interface *intf,
}
pegasus = netdev_priv(net);
- memset(pegasus, 0, sizeof (struct pegasus));
pegasus->dev_index = dev_index;
init_waitqueue_head(&pegasus->ctrl_wait);
@@ -1322,7 +1322,6 @@ static int pegasus_probe(struct usb_interface *intf,
pegasus->intf = intf;
pegasus->usb = dev;
pegasus->net = net;
- SET_MODULE_OWNER(net);
net->open = pegasus_open;
net->stop = pegasus_close;
net->watchdog_timeo = PEGASUS_TX_TIMEOUT;
@@ -1369,12 +1368,10 @@ static int pegasus_probe(struct usb_interface *intf,
queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
CARRIER_CHECK_DELAY);
- dev_info(&intf->dev, "%s, %s, %02x:%02x:%02x:%02x:%02x:%02x\n",
- net->name,
- usb_dev_id[dev_index].name,
- net->dev_addr [0], net->dev_addr [1],
- net->dev_addr [2], net->dev_addr [3],
- net->dev_addr [4], net->dev_addr [5]);
+ dev_info(&intf->dev, "%s, %s, %s\n",
+ net->name,
+ usb_dev_id[dev_index].name,
+ print_mac(mac, net->dev_addr));
return 0;
out3:
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index cd991a0f75b..1ebe3259be0 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -512,11 +512,19 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
}
tmp = le32_to_cpu(u.init_c->max_transfer_size);
if (tmp < dev->hard_mtu) {
- dev_err(&intf->dev,
- "dev can't take %u byte packets (max %u)\n",
- dev->hard_mtu, tmp);
- retval = -EINVAL;
- goto fail_and_release;
+ if (tmp <= net->hard_header_len) {
+ dev_err(&intf->dev,
+ "dev can't take %u byte packets (max %u)\n",
+ dev->hard_mtu, tmp);
+ retval = -EINVAL;
+ goto fail_and_release;
+ }
+ dev->hard_mtu = tmp;
+ net->mtu = dev->hard_mtu - net->hard_header_len;
+ dev_warn(&intf->dev,
+ "dev can't take %u byte packets (max %u), "
+ "adjusting MTU to %u\n",
+ dev->hard_mtu, tmp, net->mtu);
}
/* REVISIT: peripheral "alignment" request is ignored ... */
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index fa598f0340c..33cbc306226 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -905,7 +905,6 @@ static int rtl8150_probe(struct usb_interface *intf,
}
dev = netdev_priv(netdev);
- memset(dev, 0, sizeof(rtl8150_t));
dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
if (!dev->intr_buff) {
@@ -918,7 +917,6 @@ static int rtl8150_probe(struct usb_interface *intf,
dev->udev = udev;
dev->netdev = netdev;
- SET_MODULE_OWNER(netdev);
netdev->open = rtl8150_open;
netdev->stop = rtl8150_close;
netdev->do_ioctl = rtl8150_ioctl;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 37bf4f2c0a4..8ed1fc5cbc7 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -590,6 +590,7 @@ static int usbnet_stop (struct net_device *net)
dev->flags = 0;
del_timer_sync (&dev->delay);
tasklet_kill (&dev->bh);
+ usb_autopm_put_interface(dev->intf);
return 0;
}
@@ -603,9 +604,19 @@ static int usbnet_stop (struct net_device *net)
static int usbnet_open (struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
- int retval = 0;
+ int retval;
struct driver_info *info = dev->driver_info;
+ if ((retval = usb_autopm_get_interface(dev->intf)) < 0) {
+ if (netif_msg_ifup (dev))
+ devinfo (dev,
+ "resumption fail (%d) usbnet usb-%s-%s, %s",
+ retval,
+ dev->udev->bus->bus_name, dev->udev->devpath,
+ info->description);
+ goto done_nopm;
+ }
+
// put into "known safe" state
if (info->reset && (retval = info->reset (dev)) < 0) {
if (netif_msg_ifup (dev))
@@ -659,7 +670,10 @@ static int usbnet_open (struct net_device *net)
// delay posting reads until we're fully open
tasklet_schedule (&dev->bh);
+ return retval;
done:
+ usb_autopm_put_interface(dev->intf);
+done_nopm:
return retval;
}
@@ -669,9 +683,6 @@ done:
* they'll probably want to use this base set.
*/
-#if defined(CONFIG_MII) || defined(CONFIG_MII_MODULE)
-#define HAVE_MII
-
int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd)
{
struct usbnet *dev = netdev_priv(net);
@@ -730,8 +741,6 @@ int usbnet_nway_reset(struct net_device *net)
}
EXPORT_SYMBOL_GPL(usbnet_nway_reset);
-#endif /* HAVE_MII */
-
void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
{
struct usbnet *dev = netdev_priv(net);
@@ -762,12 +771,10 @@ EXPORT_SYMBOL_GPL(usbnet_set_msglevel);
/* drivers may override default ethtool_ops in their bind() routine */
static struct ethtool_ops usbnet_ethtool_ops = {
-#ifdef HAVE_MII
.get_settings = usbnet_get_settings,
.set_settings = usbnet_set_settings,
.get_link = usbnet_get_link,
.nway_reset = usbnet_nway_reset,
-#endif
.get_drvinfo = usbnet_get_drvinfo,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
@@ -1120,6 +1127,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
struct usb_device *xdev;
int status;
const char *name;
+ DECLARE_MAC_BUF(mac);
name = udev->dev.driver->name;
info = (struct driver_info *) prod->driver_info;
@@ -1143,6 +1151,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev = netdev_priv(net);
dev->udev = xdev;
+ dev->intf = udev;
dev->driver_info = info;
dev->driver_name = name;
dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
@@ -1158,7 +1167,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
init_timer (&dev->delay);
mutex_init (&dev->phy_mutex);
- SET_MODULE_OWNER (net);
dev->net = net;
strcpy (net->name, "usb%d");
memcpy (net->dev_addr, node_id, sizeof node_id);
@@ -1227,14 +1235,11 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
if (status)
goto out3;
if (netif_msg_probe (dev))
- devinfo (dev, "register '%s' at usb-%s-%s, %s, "
- "%02x:%02x:%02x:%02x:%02x:%02x",
+ devinfo (dev, "register '%s' at usb-%s-%s, %s, %s",
udev->dev.driver->name,
xdev->bus->bus_name, xdev->devpath,
dev->driver_info->description,
- net->dev_addr [0], net->dev_addr [1],
- net->dev_addr [2], net->dev_addr [3],
- net->dev_addr [4], net->dev_addr [5]);
+ print_mac(mac, net->dev_addr));
// ok, it's ready to go.
usb_set_intfdata (udev, dev);
@@ -1267,12 +1272,18 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
struct usbnet *dev = usb_get_intfdata(intf);
if (!dev->suspend_count++) {
- /* accelerate emptying of the rx and queues, to avoid
+ /*
+ * accelerate emptying of the rx and queues, to avoid
* having everything error out.
*/
netif_device_detach (dev->net);
(void) unlink_urbs (dev, &dev->rxq);
(void) unlink_urbs (dev, &dev->txq);
+ /*
+ * reattach so runtime management can use and
+ * wake the device
+ */
+ netif_device_attach (dev->net);
}
return 0;
}
@@ -1282,10 +1293,9 @@ int usbnet_resume (struct usb_interface *intf)
{
struct usbnet *dev = usb_get_intfdata(intf);
- if (!--dev->suspend_count) {
- netif_device_attach (dev->net);
+ if (!--dev->suspend_count)
tasklet_schedule (&dev->bh);
- }
+
return 0;
}
EXPORT_SYMBOL_GPL(usbnet_resume);
diff --git a/drivers/net/usb/usbnet.h b/drivers/net/usb/usbnet.h
index a6c5820767d..1fae4347e83 100644
--- a/drivers/net/usb/usbnet.h
+++ b/drivers/net/usb/usbnet.h
@@ -28,6 +28,7 @@
struct usbnet {
/* housekeeping */
struct usb_device *udev;
+ struct usb_interface *intf;
struct driver_info *driver_info;
const char *driver_name;
wait_queue_head_t *wait;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
new file mode 100644
index 00000000000..fdd1e034569
--- /dev/null
+++ b/drivers/net/veth.c
@@ -0,0 +1,482 @@
+/*
+ * drivers/net/veth.c
+ *
+ * Copyright (C) 2007 OpenVZ http://openvz.org, SWsoft Inc
+ *
+ * Author: Pavel Emelianov <xemul@openvz.org>
+ * Ethtool interface from: Eric W. Biederman <ebiederm@xmission.com>
+ *
+ */
+
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
+
+#include <net/dst.h>
+#include <net/xfrm.h>
+#include <net/veth.h>
+
+#define DRV_NAME "veth"
+#define DRV_VERSION "1.0"
+
+struct veth_net_stats {
+ unsigned long rx_packets;
+ unsigned long tx_packets;
+ unsigned long rx_bytes;
+ unsigned long tx_bytes;
+ unsigned long tx_dropped;
+};
+
+struct veth_priv {
+ struct net_device *peer;
+ struct net_device *dev;
+ struct list_head list;
+ struct veth_net_stats *stats;
+ unsigned ip_summed;
+};
+
+static LIST_HEAD(veth_list);
+
+/*
+ * ethtool interface
+ */
+
+static struct {
+ const char string[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+ { "peer_ifindex" },
+};
+
+static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ cmd->supported = 0;
+ cmd->advertising = 0;
+ cmd->speed = SPEED_10000;
+ cmd->duplex = DUPLEX_FULL;
+ cmd->port = PORT_TP;
+ cmd->phy_address = 0;
+ cmd->transceiver = XCVR_INTERNAL;
+ cmd->autoneg = AUTONEG_DISABLE;
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+ return 0;
+}
+
+static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->fw_version, "N/A");
+}
+
+static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+ switch(stringset) {
+ case ETH_SS_STATS:
+ memcpy(buf, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
+ break;
+ }
+}
+
+static int veth_get_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(ethtool_stats_keys);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void veth_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct veth_priv *priv;
+
+ priv = netdev_priv(dev);
+ data[0] = priv->peer->ifindex;
+}
+
+static u32 veth_get_rx_csum(struct net_device *dev)
+{
+ struct veth_priv *priv;
+
+ priv = netdev_priv(dev);
+ return priv->ip_summed == CHECKSUM_UNNECESSARY;
+}
+
+static int veth_set_rx_csum(struct net_device *dev, u32 data)
+{
+ struct veth_priv *priv;
+
+ priv = netdev_priv(dev);
+ priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
+ return 0;
+}
+
+static u32 veth_get_tx_csum(struct net_device *dev)
+{
+ return (dev->features & NETIF_F_NO_CSUM) != 0;
+}
+
+static int veth_set_tx_csum(struct net_device *dev, u32 data)
+{
+ if (data)
+ dev->features |= NETIF_F_NO_CSUM;
+ else
+ dev->features &= ~NETIF_F_NO_CSUM;
+ return 0;
+}
+
+static struct ethtool_ops veth_ethtool_ops = {
+ .get_settings = veth_get_settings,
+ .get_drvinfo = veth_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_rx_csum = veth_get_rx_csum,
+ .set_rx_csum = veth_set_rx_csum,
+ .get_tx_csum = veth_get_tx_csum,
+ .set_tx_csum = veth_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_strings = veth_get_strings,
+ .get_sset_count = veth_get_sset_count,
+ .get_ethtool_stats = veth_get_ethtool_stats,
+};
+
+/*
+ * xmit
+ */
+
+static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_device *rcv = NULL;
+ struct veth_priv *priv, *rcv_priv;
+ struct veth_net_stats *stats;
+ int length, cpu;
+
+ skb_orphan(skb);
+
+ priv = netdev_priv(dev);
+ rcv = priv->peer;
+ rcv_priv = netdev_priv(rcv);
+
+ cpu = smp_processor_id();
+ stats = per_cpu_ptr(priv->stats, cpu);
+
+ if (!(rcv->flags & IFF_UP))
+ goto outf;
+
+ skb->pkt_type = PACKET_HOST;
+ skb->protocol = eth_type_trans(skb, rcv);
+ if (dev->features & NETIF_F_NO_CSUM)
+ skb->ip_summed = rcv_priv->ip_summed;
+
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ skb->mark = 0;
+ secpath_reset(skb);
+ nf_reset(skb);
+
+ length = skb->len;
+
+ stats->tx_bytes += length;
+ stats->tx_packets++;
+
+ stats = per_cpu_ptr(rcv_priv->stats, cpu);
+ stats->rx_bytes += length;
+ stats->rx_packets++;
+
+ netif_rx(skb);
+ return 0;
+
+outf:
+ kfree_skb(skb);
+ stats->tx_dropped++;
+ return 0;
+}
+
+/*
+ * general routines
+ */
+
+static struct net_device_stats *veth_get_stats(struct net_device *dev)
+{
+ struct veth_priv *priv;
+ struct net_device_stats *dev_stats;
+ int cpu;
+ struct veth_net_stats *stats;
+
+ priv = netdev_priv(dev);
+ dev_stats = &dev->stats;
+
+ dev_stats->rx_packets = 0;
+ dev_stats->tx_packets = 0;
+ dev_stats->rx_bytes = 0;
+ dev_stats->tx_bytes = 0;
+ dev_stats->tx_dropped = 0;
+
+ for_each_online_cpu(cpu) {
+ stats = per_cpu_ptr(priv->stats, cpu);
+
+ dev_stats->rx_packets += stats->rx_packets;
+ dev_stats->tx_packets += stats->tx_packets;
+ dev_stats->rx_bytes += stats->rx_bytes;
+ dev_stats->tx_bytes += stats->tx_bytes;
+ dev_stats->tx_dropped += stats->tx_dropped;
+ }
+
+ return dev_stats;
+}
+
+static int veth_open(struct net_device *dev)
+{
+ struct veth_priv *priv;
+
+ priv = netdev_priv(dev);
+ if (priv->peer == NULL)
+ return -ENOTCONN;
+
+ if (priv->peer->flags & IFF_UP) {
+ netif_carrier_on(dev);
+ netif_carrier_on(priv->peer);
+ }
+ return 0;
+}
+
+static int veth_close(struct net_device *dev)
+{
+ struct veth_priv *priv;
+
+ if (netif_carrier_ok(dev)) {
+ priv = netdev_priv(dev);
+ netif_carrier_off(dev);
+ netif_carrier_off(priv->peer);
+ }
+ return 0;
+}
+
+static int veth_dev_init(struct net_device *dev)
+{
+ struct veth_net_stats *stats;
+ struct veth_priv *priv;
+
+ stats = alloc_percpu(struct veth_net_stats);
+ if (stats == NULL)
+ return -ENOMEM;
+
+ priv = netdev_priv(dev);
+ priv->stats = stats;
+ return 0;
+}
+
+static void veth_dev_free(struct net_device *dev)
+{
+ struct veth_priv *priv;
+
+ priv = netdev_priv(dev);
+ free_percpu(priv->stats);
+ free_netdev(dev);
+}
+
+static void veth_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+
+ dev->hard_start_xmit = veth_xmit;
+ dev->get_stats = veth_get_stats;
+ dev->open = veth_open;
+ dev->stop = veth_close;
+ dev->ethtool_ops = &veth_ethtool_ops;
+ dev->features |= NETIF_F_LLTX;
+ dev->init = veth_dev_init;
+ dev->destructor = veth_dev_free;
+}
+
+/*
+ * netlink interface
+ */
+
+static int veth_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+ if (tb[IFLA_ADDRESS]) {
+ if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+ return -EINVAL;
+ if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+ return -EADDRNOTAVAIL;
+ }
+ return 0;
+}
+
+static struct rtnl_link_ops veth_link_ops;
+
+static int veth_newlink(struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
+{
+ int err;
+ struct net_device *peer;
+ struct veth_priv *priv;
+ char ifname[IFNAMSIZ];
+ struct nlattr *peer_tb[IFLA_MAX + 1], **tbp;
+
+ /*
+ * create and register peer first
+ *
+ * struct ifinfomsg is at the head of VETH_INFO_PEER, but we
+ * skip it since no info from it is useful yet
+ */
+
+ if (data != NULL && data[VETH_INFO_PEER] != NULL) {
+ struct nlattr *nla_peer;
+
+ nla_peer = data[VETH_INFO_PEER];
+ err = nla_parse(peer_tb, IFLA_MAX,
+ nla_data(nla_peer) + sizeof(struct ifinfomsg),
+ nla_len(nla_peer) - sizeof(struct ifinfomsg),
+ ifla_policy);
+ if (err < 0)
+ return err;
+
+ err = veth_validate(peer_tb, NULL);
+ if (err < 0)
+ return err;
+
+ tbp = peer_tb;
+ } else
+ tbp = tb;
+
+ if (tbp[IFLA_IFNAME])
+ nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ);
+ else
+ snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d");
+
+ peer = rtnl_create_link(dev->nd_net, ifname, &veth_link_ops, tbp);
+ if (IS_ERR(peer))
+ return PTR_ERR(peer);
+
+ if (tbp[IFLA_ADDRESS] == NULL)
+ random_ether_addr(peer->dev_addr);
+
+ err = register_netdevice(peer);
+ if (err < 0)
+ goto err_register_peer;
+
+ netif_carrier_off(peer);
+
+ /*
+ * register dev last
+ *
+ * note, that since we've registered new device the dev's name
+ * should be re-allocated
+ */
+
+ if (tb[IFLA_ADDRESS] == NULL)
+ random_ether_addr(dev->dev_addr);
+
+ if (tb[IFLA_IFNAME])
+ nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ);
+ else
+ snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d");
+
+ if (strchr(dev->name, '%')) {
+ err = dev_alloc_name(dev, dev->name);
+ if (err < 0)
+ goto err_alloc_name;
+ }
+
+ err = register_netdevice(dev);
+ if (err < 0)
+ goto err_register_dev;
+
+ netif_carrier_off(dev);
+
+ /*
+ * tie the deviced together
+ */
+
+ priv = netdev_priv(dev);
+ priv->dev = dev;
+ priv->peer = peer;
+ list_add(&priv->list, &veth_list);
+
+ priv = netdev_priv(peer);
+ priv->dev = peer;
+ priv->peer = dev;
+ INIT_LIST_HEAD(&priv->list);
+ return 0;
+
+err_register_dev:
+ /* nothing to do */
+err_alloc_name:
+ unregister_netdevice(peer);
+ return err;
+
+err_register_peer:
+ free_netdev(peer);
+ return err;
+}
+
+static void veth_dellink(struct net_device *dev)
+{
+ struct veth_priv *priv;
+ struct net_device *peer;
+
+ priv = netdev_priv(dev);
+ peer = priv->peer;
+
+ if (!list_empty(&priv->list))
+ list_del(&priv->list);
+
+ priv = netdev_priv(peer);
+ if (!list_empty(&priv->list))
+ list_del(&priv->list);
+
+ unregister_netdevice(dev);
+ unregister_netdevice(peer);
+}
+
+static const struct nla_policy veth_policy[VETH_INFO_MAX + 1];
+
+static struct rtnl_link_ops veth_link_ops = {
+ .kind = DRV_NAME,
+ .priv_size = sizeof(struct veth_priv),
+ .setup = veth_setup,
+ .validate = veth_validate,
+ .newlink = veth_newlink,
+ .dellink = veth_dellink,
+ .policy = veth_policy,
+ .maxtype = VETH_INFO_MAX,
+};
+
+/*
+ * init/fini
+ */
+
+static __init int veth_init(void)
+{
+ return rtnl_link_register(&veth_link_ops);
+}
+
+static __exit void veth_exit(void)
+{
+ struct veth_priv *priv, *next;
+
+ rtnl_lock();
+ /*
+ * cannot trust __rtnl_link_unregister() to unregister all
+ * devices, as each ->dellink call will remove two devices
+ * from the list at once.
+ */
+ list_for_each_entry_safe(priv, next, &veth_list, list)
+ veth_dellink(priv->dev);
+
+ __rtnl_link_unregister(&veth_link_ops);
+ rtnl_unlock();
+}
+
+module_init(veth_init);
+module_exit(veth_exit);
+
+MODULE_DESCRIPTION("Virtual Ethernet Tunnel");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_RTNL_LINK(DRV_NAME);
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index b56dff26772..07263cd93f9 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -335,16 +335,16 @@ enum wol_bits {
/* The Rx and Tx buffer descriptors. */
struct rx_desc {
- s32 rx_status;
- u32 desc_length; /* Chain flag, Buffer/frame length */
- u32 addr;
- u32 next_desc;
+ __le32 rx_status;
+ __le32 desc_length; /* Chain flag, Buffer/frame length */
+ __le32 addr;
+ __le32 next_desc;
};
struct tx_desc {
- s32 tx_status;
- u32 desc_length; /* Chain flag, Tx Config, Frame length */
- u32 addr;
- u32 next_desc;
+ __le32 tx_status;
+ __le32 desc_length; /* Chain flag, Tx Config, Frame length */
+ __le32 addr;
+ __le32 next_desc;
};
/* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */
@@ -389,6 +389,8 @@ struct rhine_private {
struct pci_dev *pdev;
long pioaddr;
+ struct net_device *dev;
+ struct napi_struct napi;
struct net_device_stats stats;
spinlock_t lock;
@@ -582,28 +584,25 @@ static void rhine_poll(struct net_device *dev)
#endif
#ifdef CONFIG_VIA_RHINE_NAPI
-static int rhine_napipoll(struct net_device *dev, int *budget)
+static int rhine_napipoll(struct napi_struct *napi, int budget)
{
- struct rhine_private *rp = netdev_priv(dev);
+ struct rhine_private *rp = container_of(napi, struct rhine_private, napi);
+ struct net_device *dev = rp->dev;
void __iomem *ioaddr = rp->base;
- int done, limit = min(dev->quota, *budget);
+ int work_done;
- done = rhine_rx(dev, limit);
- *budget -= done;
- dev->quota -= done;
+ work_done = rhine_rx(dev, budget);
- if (done < limit) {
- netif_rx_complete(dev);
+ if (work_done < budget) {
+ netif_rx_complete(dev, napi);
iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
IntrTxDone | IntrTxError | IntrTxUnderrun |
IntrPCIErr | IntrStatsMax | IntrLinkChange,
ioaddr + IntrEnable);
- return 0;
}
- else
- return 1;
+ return work_done;
}
#endif
@@ -639,6 +638,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
#else
int bar = 0;
#endif
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -703,10 +703,10 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
printk(KERN_ERR "alloc_etherdev failed\n");
goto err_out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
rp = netdev_priv(dev);
+ rp->dev = dev;
rp->quirks = quirks;
rp->pioaddr = pioaddr;
rp->pdev = pdev;
@@ -785,8 +785,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
dev->poll_controller = rhine_poll;
#endif
#ifdef CONFIG_VIA_RHINE_NAPI
- dev->poll = rhine_napipoll;
- dev->weight = 64;
+ netif_napi_add(dev, &rp->napi, rhine_napipoll, 64);
#endif
if (rp->quirks & rqRhineI)
dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
@@ -796,18 +795,14 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
if (rc)
goto err_out_unmap;
- printk(KERN_INFO "%s: VIA %s at 0x%lx, ",
+ printk(KERN_INFO "%s: VIA %s at 0x%lx, %s, IRQ %d.\n",
dev->name, name,
#ifdef USE_MMIO
- memaddr
+ memaddr,
#else
- (long)ioaddr
+ (long)ioaddr,
#endif
- );
-
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq);
+ print_mac(mac, dev->dev_addr), pdev->irq);
pci_set_drvdata(pdev, dev);
@@ -1061,7 +1056,9 @@ static void init_registers(struct net_device *dev)
rhine_set_rx_mode(dev);
- netif_poll_enable(dev);
+#ifdef CONFIG_VIA_RHINE_NAPI
+ napi_enable(&rp->napi);
+#endif
/* Enable interrupts by setting the interrupt mask. */
iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
@@ -1196,6 +1193,10 @@ static void rhine_tx_timeout(struct net_device *dev)
/* protect against concurrent rx interrupts */
disable_irq(rp->pdev->irq);
+#ifdef CONFIG_VIA_RHINE_NAPI
+ napi_disable(&rp->napi);
+#endif
+
spin_lock(&rp->lock);
/* clear all descriptors */
@@ -1324,7 +1325,7 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance)
IntrPCIErr | IntrStatsMax | IntrLinkChange,
ioaddr + IntrEnable);
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &rp->napi);
#else
rhine_rx(dev, RX_RING_SIZE);
#endif
@@ -1809,8 +1810,6 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.set_msglevel = netdev_set_msglevel,
.get_wol = rhine_get_wol,
.set_wol = rhine_set_wol,
- .get_sg = ethtool_op_get_sg,
- .get_tx_csum = ethtool_op_get_tx_csum,
};
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1837,7 +1836,9 @@ static int rhine_close(struct net_device *dev)
spin_lock_irq(&rp->lock);
netif_stop_queue(dev);
- netif_poll_disable(dev);
+#ifdef CONFIG_VIA_RHINE_NAPI
+ napi_disable(&rp->napi);
+#endif
if (debug > 1)
printk(KERN_DEBUG "%s: Shutting down ethercard, "
@@ -1936,6 +1937,9 @@ static int rhine_suspend(struct pci_dev *pdev, pm_message_t state)
if (!netif_running(dev))
return 0;
+#ifdef CONFIG_VIA_RHINE_NAPI
+ napi_disable(&rp->napi);
+#endif
netif_device_detach(dev);
pci_save_state(pdev);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 93574add406..450e29d7a9f 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -72,6 +72,7 @@
#include <linux/mii.h>
#include <linux/in.h>
#include <linux/if_arp.h>
+#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
@@ -84,6 +85,163 @@
static int velocity_nics = 0;
static int msglevel = MSG_LEVEL_INFO;
+/**
+ * mac_get_cam_mask - Read a CAM mask
+ * @regs: register block for this velocity
+ * @mask: buffer to store mask
+ *
+ * Fetch the mask bits of the selected CAM and store them into the
+ * provided mask buffer.
+ */
+
+static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+{
+ int i;
+
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+ writeb(0, &regs->CAMADDR);
+
+ /* read mask */
+ for (i = 0; i < 8; i++)
+ *mask++ = readb(&(regs->MARCAM[i]));
+
+ /* disable CAMEN */
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+}
+
+
+/**
+ * mac_set_cam_mask - Set a CAM mask
+ * @regs: register block for this velocity
+ * @mask: CAM mask to load
+ *
+ * Store a new mask into a CAM
+ */
+
+static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+{
+ int i;
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+ writeb(CAMADDR_CAMEN, &regs->CAMADDR);
+
+ for (i = 0; i < 8; i++) {
+ writeb(*mask++, &(regs->MARCAM[i]));
+ }
+ /* disable CAMEN */
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+{
+ int i;
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+ writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
+
+ for (i = 0; i < 8; i++) {
+ writeb(*mask++, &(regs->MARCAM[i]));
+ }
+ /* disable CAMEN */
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+/**
+ * mac_set_cam - set CAM data
+ * @regs: register block of this velocity
+ * @idx: Cam index
+ * @addr: 2 or 6 bytes of CAM data
+ *
+ * Load an address or vlan tag into a CAM
+ */
+
+static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
+{
+ int i;
+
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+ idx &= (64 - 1);
+
+ writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
+
+ for (i = 0; i < 6; i++) {
+ writeb(*addr++, &(regs->MARCAM[i]));
+ }
+ BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
+
+ udelay(10);
+
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx,
+ const u8 *addr)
+{
+
+ /* Select CAM mask */
+ BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+ idx &= (64 - 1);
+
+ writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, &regs->CAMADDR);
+ writew(*((u16 *) addr), &regs->MARCAM[0]);
+
+ BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
+
+ udelay(10);
+
+ writeb(0, &regs->CAMADDR);
+
+ /* Select mar */
+ BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+
+/**
+ * mac_wol_reset - reset WOL after exiting low power
+ * @regs: register block of this velocity
+ *
+ * Called after we drop out of wake on lan mode in order to
+ * reset the Wake on lan features. This function doesn't restore
+ * the rest of the logic from the result of sleep/wakeup
+ */
+
+static void mac_wol_reset(struct mac_regs __iomem * regs)
+{
+
+ /* Turn off SWPTAG right after leaving power mode */
+ BYTE_REG_BITS_OFF(STICKHW_SWPTAG, &regs->STICKHW);
+ /* clear sticky bits */
+ BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
+
+ BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, &regs->CHIPGCR);
+ BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+ /* disable force PME-enable */
+ writeb(WOLCFG_PMEOVR, &regs->WOLCFGClr);
+ /* disable power-event config bit */
+ writew(0xFFFF, &regs->WOLCRClr);
+ /* clear power status */
+ writew(0xFFFF, &regs->WOLSRClr);
+}
static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static const struct ethtool_ops velocity_ethtool_ops;
@@ -111,15 +269,6 @@ VELOCITY_PARAM(RxDescriptors, "Number of receive descriptors");
#define TX_DESC_DEF 64
VELOCITY_PARAM(TxDescriptors, "Number of transmit descriptors");
-#define VLAN_ID_MIN 0
-#define VLAN_ID_MAX 4095
-#define VLAN_ID_DEF 0
-/* VID_setting[] is used for setting the VID of NIC.
- 0: default VID.
- 1-4094: other VIDs.
-*/
-VELOCITY_PARAM(VID_setting, "802.1Q VLAN ID");
-
#define RX_THRESH_MIN 0
#define RX_THRESH_MAX 3
#define RX_THRESH_DEF 0
@@ -147,13 +296,6 @@ VELOCITY_PARAM(rx_thresh, "Receive fifo threshold");
*/
VELOCITY_PARAM(DMA_length, "DMA length");
-#define TAGGING_DEF 0
-/* enable_tagging[] is used for enabling 802.1Q VID tagging.
- 0: disable VID seeting(default).
- 1: enable VID setting.
-*/
-VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging");
-
#define IP_ALIG_DEF 0
/* IP_byte_align[] is used for IP header DWORD byte aligned
0: indicate the IP header won't be DWORD byte aligned.(Default) .
@@ -324,7 +466,7 @@ MODULE_DEVICE_TABLE(pci, velocity_id_table);
* a pointer a static string valid while the driver is loaded.
*/
-static char __devinit *get_chip_name(enum chip_type chip_id)
+static const char __devinit *get_chip_name(enum chip_type chip_id)
{
int i;
for (i = 0; chip_info_table[i].name != NULL; i++)
@@ -442,8 +584,7 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
velocity_set_int_opt(&opts->DMA_length, DMA_length[index], DMA_LENGTH_MIN, DMA_LENGTH_MAX, DMA_LENGTH_DEF, "DMA_length", devname);
velocity_set_int_opt(&opts->numrx, RxDescriptors[index], RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, "RxDescriptors", devname);
velocity_set_int_opt(&opts->numtx, TxDescriptors[index], TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, "TxDescriptors", devname);
- velocity_set_int_opt(&opts->vid, VID_setting[index], VLAN_ID_MIN, VLAN_ID_MAX, VLAN_ID_DEF, "VID_setting", devname);
- velocity_set_bool_opt(&opts->flags, enable_tagging[index], TAGGING_DEF, VELOCITY_FLAGS_TAGGING, "enable_tagging", devname);
+
velocity_set_bool_opt(&opts->flags, txcsum_offload[index], TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, "txcsum_offload", devname);
velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname);
velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname);
@@ -465,6 +606,7 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
static void velocity_init_cam_filter(struct velocity_info *vptr)
{
struct mac_regs __iomem * regs = vptr->mac_regs;
+ unsigned short vid;
/* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
@@ -473,27 +615,52 @@ static void velocity_init_cam_filter(struct velocity_info *vptr)
/* Disable all CAMs */
memset(vptr->vCAMmask, 0, sizeof(u8) * 8);
memset(vptr->mCAMmask, 0, sizeof(u8) * 8);
- mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
- mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+ mac_set_vlan_cam_mask(regs, vptr->vCAMmask);
+ mac_set_cam_mask(regs, vptr->mCAMmask);
/* Enable first VCAM */
- if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
- /* If Tagging option is enabled and VLAN ID is not zero, then
- turn on MCFG_RTGOPT also */
- if (vptr->options.vid != 0)
- WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
-
- mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid), VELOCITY_VLAN_ID_CAM);
+ if (vptr->vlgrp) {
+ for (vid = 0; vid < VLAN_VID_MASK; vid++) {
+ if (vlan_group_get_device(vptr->vlgrp, vid)) {
+ /* If Tagging option is enabled and
+ VLAN ID is not zero, then
+ turn on MCFG_RTGOPT also */
+ if (vid != 0)
+ WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
+
+ mac_set_vlan_cam(regs, 0, (u8 *) &vid);
+ }
+ }
vptr->vCAMmask[0] |= 1;
- mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
+ mac_set_vlan_cam_mask(regs, vptr->vCAMmask);
} else {
u16 temp = 0;
- mac_set_cam(regs, 0, (u8 *) &temp, VELOCITY_VLAN_ID_CAM);
+ mac_set_vlan_cam(regs, 0, (u8 *) &temp);
temp = 1;
- mac_set_cam_mask(regs, (u8 *) &temp, VELOCITY_VLAN_ID_CAM);
+ mac_set_vlan_cam_mask(regs, (u8 *) &temp);
}
}
+static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+
+ spin_lock_irq(&vptr->lock);
+ velocity_init_cam_filter(vptr);
+ spin_unlock_irq(&vptr->lock);
+}
+
+static void velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+
+ spin_lock_irq(&vptr->lock);
+ vlan_group_set_device(vptr->vlgrp, vid, NULL);
+ velocity_init_cam_filter(vptr);
+ spin_unlock_irq(&vptr->lock);
+}
+
+
/**
* velocity_rx_reset - handle a receive reset
* @vptr: velocity we are resetting
@@ -712,7 +879,6 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
/* Chain it all together */
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
vptr = netdev_priv(dev);
@@ -791,13 +957,17 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
dev->do_ioctl = velocity_ioctl;
dev->ethtool_ops = &velocity_ethtool_ops;
dev->change_mtu = velocity_change_mtu;
+
+ dev->vlan_rx_add_vid = velocity_vlan_rx_add_vid;
+ dev->vlan_rx_kill_vid = velocity_vlan_rx_kill_vid;
+
#ifdef VELOCITY_ZERO_COPY_SUPPORT
dev->features |= NETIF_F_SG;
#endif
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER;
- if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) {
+ if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
dev->features |= NETIF_F_IP_CSUM;
- }
ret = register_netdev(dev);
if (ret < 0)
@@ -1071,14 +1241,12 @@ static int velocity_rx_refill(struct velocity_info *vptr)
static int velocity_init_rd_ring(struct velocity_info *vptr)
{
- int ret = -ENOMEM;
- unsigned int rsize = sizeof(struct velocity_rd_info) *
- vptr->options.numrx;
+ int ret;
- vptr->rd_info = kmalloc(rsize, GFP_KERNEL);
- if(vptr->rd_info == NULL)
- goto out;
- memset(vptr->rd_info, 0, rsize);
+ vptr->rd_info = kcalloc(vptr->options.numrx,
+ sizeof(struct velocity_rd_info), GFP_KERNEL);
+ if (!vptr->rd_info)
+ return -ENOMEM;
vptr->rd_filled = vptr->rd_dirty = vptr->rd_curr = 0;
@@ -1088,7 +1256,7 @@ static int velocity_init_rd_ring(struct velocity_info *vptr)
"%s: failed to allocate RX buffer.\n", vptr->dev->name);
velocity_free_rd_ring(vptr);
}
-out:
+
return ret;
}
@@ -1142,21 +1310,19 @@ static int velocity_init_td_ring(struct velocity_info *vptr)
dma_addr_t curr;
struct tx_desc *td;
struct velocity_td_info *td_info;
- unsigned int tsize = sizeof(struct velocity_td_info) *
- vptr->options.numtx;
/* Init the TD ring entries */
for (j = 0; j < vptr->num_txq; j++) {
curr = vptr->td_pool_dma[j];
- vptr->td_infos[j] = kmalloc(tsize, GFP_KERNEL);
- if(vptr->td_infos[j] == NULL)
- {
+ vptr->td_infos[j] = kcalloc(vptr->options.numtx,
+ sizeof(struct velocity_td_info),
+ GFP_KERNEL);
+ if (!vptr->td_infos[j]) {
while(--j >= 0)
kfree(vptr->td_infos[j]);
return -ENOMEM;
}
- memset(vptr->td_infos[j], 0, tsize);
for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) {
td = &(vptr->td_rings[j][i]);
@@ -1482,7 +1648,7 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
*
* Scan the queues looking for transmitted packets that
* we can complete and clean up. Update any statistics as
- * neccessary/
+ * necessary/
*/
static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
@@ -1797,6 +1963,11 @@ static int velocity_change_mtu(struct net_device *dev, int new_mtu)
return -EINVAL;
}
+ if (!netif_running(dev)) {
+ dev->mtu = new_mtu;
+ return 0;
+ }
+
if (new_mtu != oldmtu) {
spin_lock_irqsave(&vptr->lock, flags);
@@ -1994,8 +2165,8 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
td_ptr->tdesc1.CMDZ = 2;
}
- if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
- td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff);
+ if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
+ td_ptr->tdesc1.pqinf.VID = vlan_tx_tag_get(skb);
td_ptr->tdesc1.pqinf.priority = 0;
td_ptr->tdesc1.pqinf.CFI = 0;
td_ptr->tdesc1.TCR |= TCR0_VETAG;
@@ -2121,14 +2292,14 @@ static void velocity_set_multi(struct net_device *dev)
rx_mode = (RCR_AM | RCR_AB);
} else {
int offset = MCAM_SIZE - vptr->multicast_limit;
- mac_get_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+ mac_get_cam_mask(regs, vptr->mCAMmask);
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
- mac_set_cam(regs, i + offset, mclist->dmi_addr, VELOCITY_MULTICAST_CAM);
+ mac_set_cam(regs, i + offset, mclist->dmi_addr);
vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
}
- mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+ mac_set_cam_mask(regs, vptr->mCAMmask);
rx_mode = (RCR_AM | RCR_AB);
}
if (dev->mtu > 1500)
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index b9e114d36c0..aa9179623d9 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -1173,7 +1173,7 @@ enum chip_type {
struct velocity_info_tbl {
enum chip_type chip_id;
- char *name;
+ const char *name;
int txqueue;
u32 flags;
};
@@ -1194,14 +1194,6 @@ struct velocity_info_tbl {
#define mac_disable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Clr))
#define mac_enable_int(regs) writel(CR0_GINTMSK1,&((regs)->CR0Set))
-#define mac_hw_mibs_read(regs, MIBs) {\
- int i;\
- BYTE_REG_BITS_ON(MIBCR_MPTRINI,&((regs)->MIBCR));\
- for (i=0;i<HW_MIB_SIZE;i++) {\
- (MIBs)[i]=readl(&((regs)->MIBData));\
- }\
-}
-
#define mac_set_dma_length(regs, n) {\
BYTE_REG_BITS_SET((n),0x07,&((regs)->DCFG));\
}
@@ -1226,195 +1218,17 @@ struct velocity_info_tbl {
writew(TRDCSR_WAK<<(n*4),&((regs)->TDCSRSet));\
}
-#define mac_eeprom_reload(regs) {\
- int i=0;\
- BYTE_REG_BITS_ON(EECSR_RELOAD,&((regs)->EECSR));\
- do {\
- udelay(10);\
- if (i++>0x1000) {\
- break;\
- }\
- }while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&((regs)->EECSR)));\
-}
-
-enum velocity_cam_type {
- VELOCITY_VLAN_ID_CAM = 0,
- VELOCITY_MULTICAST_CAM
-};
-
-/**
- * mac_get_cam_mask - Read a CAM mask
- * @regs: register block for this velocity
- * @mask: buffer to store mask
- * @cam_type: CAM to fetch
- *
- * Fetch the mask bits of the selected CAM and store them into the
- * provided mask buffer.
- */
-
-static inline void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask, enum velocity_cam_type cam_type)
-{
- int i;
- /* Select CAM mask */
- BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
- if (cam_type == VELOCITY_VLAN_ID_CAM)
- writeb(CAMADDR_VCAMSL, &regs->CAMADDR);
- else
- writeb(0, &regs->CAMADDR);
-
- /* read mask */
- for (i = 0; i < 8; i++)
- *mask++ = readb(&(regs->MARCAM[i]));
-
- /* disable CAMEN */
- writeb(0, &regs->CAMADDR);
-
- /* Select mar */
- BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+static inline void mac_eeprom_reload(struct mac_regs __iomem * regs) {
+ int i=0;
+ BYTE_REG_BITS_ON(EECSR_RELOAD,&(regs->EECSR));
+ do {
+ udelay(10);
+ if (i++>0x1000)
+ break;
+ } while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&(regs->EECSR)));
}
-/**
- * mac_set_cam_mask - Set a CAM mask
- * @regs: register block for this velocity
- * @mask: CAM mask to load
- * @cam_type: CAM to store
- *
- * Store a new mask into a CAM
- */
-
-static inline void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask, enum velocity_cam_type cam_type)
-{
- int i;
- /* Select CAM mask */
- BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
- if (cam_type == VELOCITY_VLAN_ID_CAM)
- writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
- else
- writeb(CAMADDR_CAMEN, &regs->CAMADDR);
-
- for (i = 0; i < 8; i++) {
- writeb(*mask++, &(regs->MARCAM[i]));
- }
- /* disable CAMEN */
- writeb(0, &regs->CAMADDR);
-
- /* Select mar */
- BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-}
-
-/**
- * mac_set_cam - set CAM data
- * @regs: register block of this velocity
- * @idx: Cam index
- * @addr: 2 or 6 bytes of CAM data
- * @cam_type: CAM to load
- *
- * Load an address or vlan tag into a CAM
- */
-
-static inline void mac_set_cam(struct mac_regs __iomem * regs, int idx, u8 *addr, enum velocity_cam_type cam_type)
-{
- int i;
-
- /* Select CAM mask */
- BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
- idx &= (64 - 1);
-
- if (cam_type == VELOCITY_VLAN_ID_CAM)
- writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, &regs->CAMADDR);
- else
- writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
-
- if (cam_type == VELOCITY_VLAN_ID_CAM)
- writew(*((u16 *) addr), &regs->MARCAM[0]);
- else {
- for (i = 0; i < 6; i++) {
- writeb(*addr++, &(regs->MARCAM[i]));
- }
- }
- BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
-
- udelay(10);
-
- writeb(0, &regs->CAMADDR);
-
- /* Select mar */
- BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-}
-
-/**
- * mac_get_cam - fetch CAM data
- * @regs: register block of this velocity
- * @idx: Cam index
- * @addr: buffer to hold up to 6 bytes of CAM data
- * @cam_type: CAM to load
- *
- * Load an address or vlan tag from a CAM into the buffer provided by
- * the caller. VLAN tags are 2 bytes the address cam entries are 6.
- */
-
-static inline void mac_get_cam(struct mac_regs __iomem * regs, int idx, u8 *addr, enum velocity_cam_type cam_type)
-{
- int i;
-
- /* Select CAM mask */
- BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
- idx &= (64 - 1);
-
- if (cam_type == VELOCITY_VLAN_ID_CAM)
- writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, &regs->CAMADDR);
- else
- writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
-
- BYTE_REG_BITS_ON(CAMCR_CAMRD, &regs->CAMCR);
-
- udelay(10);
-
- if (cam_type == VELOCITY_VLAN_ID_CAM)
- *((u16 *) addr) = readw(&(regs->MARCAM[0]));
- else
- for (i = 0; i < 6; i++, addr++)
- *((u8 *) addr) = readb(&(regs->MARCAM[i]));
-
- writeb(0, &regs->CAMADDR);
-
- /* Select mar */
- BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-}
-
-/**
- * mac_wol_reset - reset WOL after exiting low power
- * @regs: register block of this velocity
- *
- * Called after we drop out of wake on lan mode in order to
- * reset the Wake on lan features. This function doesn't restore
- * the rest of the logic from the result of sleep/wakeup
- */
-
-static inline void mac_wol_reset(struct mac_regs __iomem * regs)
-{
-
- /* Turn off SWPTAG right after leaving power mode */
- BYTE_REG_BITS_OFF(STICKHW_SWPTAG, &regs->STICKHW);
- /* clear sticky bits */
- BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
-
- BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, &regs->CHIPGCR);
- BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
- /* disable force PME-enable */
- writeb(WOLCFG_PMEOVR, &regs->WOLCFGClr);
- /* disable power-event config bit */
- writew(0xFFFF, &regs->WOLCRClr);
- /* clear power status */
- writew(0xFFFF, &regs->WOLSRClr);
-}
-
-
/*
* Header for WOL definitions. Used to compute hashes
*/
@@ -1701,7 +1515,7 @@ struct velocity_opt {
int numrx; /* Number of RX descriptors */
int numtx; /* Number of TX descriptors */
enum speed_opt spd_dpx; /* Media link mode */
- int vid; /* vlan id */
+
int DMA_length; /* DMA length */
int rx_thresh; /* RX_THRESH */
int flow_cntl;
@@ -1727,6 +1541,7 @@ struct velocity_info {
dma_addr_t tx_bufs_dma;
u8 *tx_bufs;
+ struct vlan_group *vlgrp;
u8 ip_addr[4];
enum chip_type chip_id;
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
new file mode 100644
index 00000000000..a75be57fb20
--- /dev/null
+++ b/drivers/net/virtio_net.c
@@ -0,0 +1,438 @@
+/* A simple network driver using virtio.
+ *
+ * Copyright 2007 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+//#define DEBUG
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/virtio.h>
+#include <linux/virtio_net.h>
+#include <linux/scatterlist.h>
+
+/* FIXME: MTU in config. */
+#define MAX_PACKET_LEN (ETH_HLEN+ETH_DATA_LEN)
+
+struct virtnet_info
+{
+ struct virtio_device *vdev;
+ struct virtqueue *rvq, *svq;
+ struct net_device *dev;
+ struct napi_struct napi;
+
+ /* Number of input buffers, and max we've ever had. */
+ unsigned int num, max;
+
+ /* Receive & send queues. */
+ struct sk_buff_head recv;
+ struct sk_buff_head send;
+};
+
+static inline struct virtio_net_hdr *skb_vnet_hdr(struct sk_buff *skb)
+{
+ return (struct virtio_net_hdr *)skb->cb;
+}
+
+static inline void vnet_hdr_to_sg(struct scatterlist *sg, struct sk_buff *skb)
+{
+ sg_init_one(sg, skb_vnet_hdr(skb), sizeof(struct virtio_net_hdr));
+}
+
+static bool skb_xmit_done(struct virtqueue *rvq)
+{
+ struct virtnet_info *vi = rvq->vdev->priv;
+
+ /* In case we were waiting for output buffers. */
+ netif_wake_queue(vi->dev);
+ return true;
+}
+
+static void receive_skb(struct net_device *dev, struct sk_buff *skb,
+ unsigned len)
+{
+ struct virtio_net_hdr *hdr = skb_vnet_hdr(skb);
+
+ if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
+ pr_debug("%s: short packet %i\n", dev->name, len);
+ dev->stats.rx_length_errors++;
+ goto drop;
+ }
+ len -= sizeof(struct virtio_net_hdr);
+ BUG_ON(len > MAX_PACKET_LEN);
+
+ skb_trim(skb, len);
+ skb->protocol = eth_type_trans(skb, dev);
+ pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
+ ntohs(skb->protocol), skb->len, skb->pkt_type);
+ dev->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+
+ if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
+ pr_debug("Needs csum!\n");
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ skb->csum_start = hdr->csum_start;
+ skb->csum_offset = hdr->csum_offset;
+ if (skb->csum_start > skb->len - 2
+ || skb->csum_offset > skb->len - 2) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s: csum=%u/%u len=%u\n",
+ dev->name, skb->csum_start,
+ skb->csum_offset, skb->len);
+ goto frame_err;
+ }
+ }
+
+ if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
+ pr_debug("GSO!\n");
+ switch (hdr->gso_type) {
+ case VIRTIO_NET_HDR_GSO_TCPV4:
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+ break;
+ case VIRTIO_NET_HDR_GSO_TCPV4_ECN:
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCP_ECN;
+ break;
+ case VIRTIO_NET_HDR_GSO_UDP:
+ skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+ break;
+ case VIRTIO_NET_HDR_GSO_TCPV6:
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+ break;
+ default:
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s: bad gso type %u.\n",
+ dev->name, hdr->gso_type);
+ goto frame_err;
+ }
+
+ skb_shinfo(skb)->gso_size = hdr->gso_size;
+ if (skb_shinfo(skb)->gso_size == 0) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s: zero gso size.\n",
+ dev->name);
+ goto frame_err;
+ }
+
+ /* Header must be checked, and gso_segs computed. */
+ skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+ skb_shinfo(skb)->gso_segs = 0;
+ }
+
+ netif_receive_skb(skb);
+ return;
+
+frame_err:
+ dev->stats.rx_frame_errors++;
+drop:
+ dev_kfree_skb(skb);
+}
+
+static void try_fill_recv(struct virtnet_info *vi)
+{
+ struct sk_buff *skb;
+ struct scatterlist sg[1+MAX_SKB_FRAGS];
+ int num, err;
+
+ sg_init_table(sg, 1+MAX_SKB_FRAGS);
+ for (;;) {
+ skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN);
+ if (unlikely(!skb))
+ break;
+
+ skb_put(skb, MAX_PACKET_LEN);
+ vnet_hdr_to_sg(sg, skb);
+ num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
+ skb_queue_head(&vi->recv, skb);
+
+ err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, num, skb);
+ if (err) {
+ skb_unlink(skb, &vi->recv);
+ kfree_skb(skb);
+ break;
+ }
+ vi->num++;
+ }
+ if (unlikely(vi->num > vi->max))
+ vi->max = vi->num;
+ vi->rvq->vq_ops->kick(vi->rvq);
+}
+
+static bool skb_recv_done(struct virtqueue *rvq)
+{
+ struct virtnet_info *vi = rvq->vdev->priv;
+ netif_rx_schedule(vi->dev, &vi->napi);
+ /* Suppress further interrupts. */
+ return false;
+}
+
+static int virtnet_poll(struct napi_struct *napi, int budget)
+{
+ struct virtnet_info *vi = container_of(napi, struct virtnet_info, napi);
+ struct sk_buff *skb = NULL;
+ unsigned int len, received = 0;
+
+again:
+ while (received < budget &&
+ (skb = vi->rvq->vq_ops->get_buf(vi->rvq, &len)) != NULL) {
+ __skb_unlink(skb, &vi->recv);
+ receive_skb(vi->dev, skb, len);
+ vi->num--;
+ received++;
+ }
+
+ /* FIXME: If we oom and completely run out of inbufs, we need
+ * to start a timer trying to fill more. */
+ if (vi->num < vi->max / 2)
+ try_fill_recv(vi);
+
+ /* All done? */
+ if (!skb) {
+ netif_rx_complete(vi->dev, napi);
+ if (unlikely(!vi->rvq->vq_ops->restart(vi->rvq))
+ && netif_rx_reschedule(vi->dev, napi))
+ goto again;
+ }
+
+ return received;
+}
+
+static void free_old_xmit_skbs(struct virtnet_info *vi)
+{
+ struct sk_buff *skb;
+ unsigned int len;
+
+ while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) {
+ pr_debug("Sent skb %p\n", skb);
+ __skb_unlink(skb, &vi->send);
+ vi->dev->stats.tx_bytes += len;
+ vi->dev->stats.tx_packets++;
+ kfree_skb(skb);
+ }
+}
+
+static int start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
+ int num, err;
+ struct scatterlist sg[1+MAX_SKB_FRAGS];
+ struct virtio_net_hdr *hdr;
+ const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
+ DECLARE_MAC_BUF(mac);
+
+ sg_init_table(sg, 1+MAX_SKB_FRAGS);
+
+ pr_debug("%s: xmit %p %s\n", dev->name, skb, print_mac(mac, dest));
+
+ free_old_xmit_skbs(vi);
+
+ /* Encode metadata header at front. */
+ hdr = skb_vnet_hdr(skb);
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
+ hdr->csum_start = skb->csum_start - skb_headroom(skb);
+ hdr->csum_offset = skb->csum_offset;
+ } else {
+ hdr->flags = 0;
+ hdr->csum_offset = hdr->csum_start = 0;
+ }
+
+ if (skb_is_gso(skb)) {
+ hdr->gso_size = skb_shinfo(skb)->gso_size;
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
+ hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4_ECN;
+ else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+ hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+ else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+ hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
+ hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
+ else
+ BUG();
+ } else {
+ hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
+ hdr->gso_size = 0;
+ }
+
+ vnet_hdr_to_sg(sg, skb);
+ num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
+ __skb_queue_head(&vi->send, skb);
+ err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
+ if (err) {
+ pr_debug("%s: virtio not prepared to send\n", dev->name);
+ skb_unlink(skb, &vi->send);
+ netif_stop_queue(dev);
+ return NETDEV_TX_BUSY;
+ }
+ vi->svq->vq_ops->kick(vi->svq);
+
+ return 0;
+}
+
+static int virtnet_open(struct net_device *dev)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
+
+ try_fill_recv(vi);
+
+ /* If we didn't even get one input buffer, we're useless. */
+ if (vi->num == 0)
+ return -ENOMEM;
+
+ napi_enable(&vi->napi);
+ return 0;
+}
+
+static int virtnet_close(struct net_device *dev)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
+ struct sk_buff *skb;
+
+ napi_disable(&vi->napi);
+
+ /* networking core has neutered skb_xmit_done/skb_recv_done, so don't
+ * worry about races vs. get(). */
+ vi->rvq->vq_ops->shutdown(vi->rvq);
+ while ((skb = __skb_dequeue(&vi->recv)) != NULL) {
+ kfree_skb(skb);
+ vi->num--;
+ }
+ vi->svq->vq_ops->shutdown(vi->svq);
+ while ((skb = __skb_dequeue(&vi->send)) != NULL)
+ kfree_skb(skb);
+
+ BUG_ON(vi->num != 0);
+ return 0;
+}
+
+static int virtnet_probe(struct virtio_device *vdev)
+{
+ int err;
+ unsigned int len;
+ struct net_device *dev;
+ struct virtnet_info *vi;
+ void *token;
+
+ /* Allocate ourselves a network device with room for our info */
+ dev = alloc_etherdev(sizeof(struct virtnet_info));
+ if (!dev)
+ return -ENOMEM;
+
+ /* Set up network device as normal. */
+ ether_setup(dev);
+ dev->open = virtnet_open;
+ dev->stop = virtnet_close;
+ dev->hard_start_xmit = start_xmit;
+ dev->features = NETIF_F_HIGHDMA;
+ SET_NETDEV_DEV(dev, &vdev->dev);
+
+ /* Do we support "hardware" checksums? */
+ token = vdev->config->find(vdev, VIRTIO_CONFIG_NET_F, &len);
+ if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_NO_CSUM)) {
+ /* This opens up the world of extra features. */
+ dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
+ if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO4))
+ dev->features |= NETIF_F_TSO;
+ if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_UFO))
+ dev->features |= NETIF_F_UFO;
+ if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO4_ECN))
+ dev->features |= NETIF_F_TSO_ECN;
+ if (virtio_use_bit(vdev, token, len, VIRTIO_NET_F_TSO6))
+ dev->features |= NETIF_F_TSO6;
+ }
+
+ /* Configuration may specify what MAC to use. Otherwise random. */
+ token = vdev->config->find(vdev, VIRTIO_CONFIG_NET_MAC_F, &len);
+ if (token) {
+ dev->addr_len = len;
+ vdev->config->get(vdev, token, dev->dev_addr, len);
+ } else
+ random_ether_addr(dev->dev_addr);
+
+ /* Set up our device-specific information */
+ vi = netdev_priv(dev);
+ netif_napi_add(dev, &vi->napi, virtnet_poll, 16);
+ vi->dev = dev;
+ vi->vdev = vdev;
+
+ /* We expect two virtqueues, receive then send. */
+ vi->rvq = vdev->config->find_vq(vdev, skb_recv_done);
+ if (IS_ERR(vi->rvq)) {
+ err = PTR_ERR(vi->rvq);
+ goto free;
+ }
+
+ vi->svq = vdev->config->find_vq(vdev, skb_xmit_done);
+ if (IS_ERR(vi->svq)) {
+ err = PTR_ERR(vi->svq);
+ goto free_recv;
+ }
+
+ /* Initialize our empty receive and send queues. */
+ skb_queue_head_init(&vi->recv);
+ skb_queue_head_init(&vi->send);
+
+ err = register_netdev(dev);
+ if (err) {
+ pr_debug("virtio_net: registering device failed\n");
+ goto free_send;
+ }
+ pr_debug("virtnet: registered device %s\n", dev->name);
+ vdev->priv = vi;
+ return 0;
+
+free_send:
+ vdev->config->del_vq(vi->svq);
+free_recv:
+ vdev->config->del_vq(vi->rvq);
+free:
+ free_netdev(dev);
+ return err;
+}
+
+static void virtnet_remove(struct virtio_device *vdev)
+{
+ unregister_netdev(vdev->priv);
+ free_netdev(vdev->priv);
+}
+
+static struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static struct virtio_driver virtio_net = {
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = virtnet_probe,
+ .remove = __devexit_p(virtnet_remove),
+};
+
+static int __init init(void)
+{
+ return register_virtio_driver(&virtio_net);
+}
+
+static void __exit fini(void)
+{
+ unregister_virtio_driver(&virtio_net);
+}
+module_init(init);
+module_exit(fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio network driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index 8ead774d14c..c4c8eab8574 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -363,7 +363,6 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
hdlc = dev_to_hdlc(dev);
spin_lock_init(&card->lock);
- SET_MODULE_OWNER(dev);
dev->irq = irq;
dev->mem_start = winbase;
dev->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1;
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 26058b4f8f3..ff37bf437a9 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -154,8 +154,8 @@ struct cosa_data {
int nchannels; /* # of channels on this card */
int driver_status; /* For communicating with firmware */
int firmware_status; /* Downloaded, reseted, etc. */
- long int rxbitmap, txbitmap; /* Bitmap of channels who are willing to send/receive data */
- long int rxtx; /* RX or TX in progress? */
+ unsigned long rxbitmap, txbitmap;/* Bitmap of channels who are willing to send/receive data */
+ unsigned long rxtx; /* RX or TX in progress? */
int enabled;
int usage; /* usage count */
int txchan, txsize, rxsize;
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index a8af28b273d..8a1778cf98d 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -131,14 +131,15 @@ static int cycx_wan_update(struct wan_device *wandev),
cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev);
/* Network device interface */
-static int cycx_netdevice_init(struct net_device *dev),
- cycx_netdevice_open(struct net_device *dev),
- cycx_netdevice_stop(struct net_device *dev),
- cycx_netdevice_hard_header(struct sk_buff *skb,
- struct net_device *dev, u16 type,
- void *daddr, void *saddr, unsigned len),
- cycx_netdevice_rebuild_header(struct sk_buff *skb),
- cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
+static int cycx_netdevice_init(struct net_device *dev);
+static int cycx_netdevice_open(struct net_device *dev);
+static int cycx_netdevice_stop(struct net_device *dev);
+static int cycx_netdevice_hard_header(struct sk_buff *skb,
+ struct net_device *dev, u16 type,
+ const void *daddr, const void *saddr,
+ unsigned len);
+static int cycx_netdevice_rebuild_header(struct sk_buff *skb);
+static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev);
static struct net_device_stats *
@@ -468,7 +469,14 @@ static int cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev)
return 0;
}
+
/* Network Device Interface */
+
+static const struct header_ops cycx_header_ops = {
+ .create = cycx_netdevice_hard_header,
+ .rebuild = cycx_netdevice_rebuild_header,
+};
+
/* Initialize Linux network interface.
*
* This routine is called only once for each interface, during Linux network
@@ -483,8 +491,8 @@ static int cycx_netdevice_init(struct net_device *dev)
/* Initialize device driver entry points */
dev->open = cycx_netdevice_open;
dev->stop = cycx_netdevice_stop;
- dev->hard_header = cycx_netdevice_hard_header;
- dev->rebuild_header = cycx_netdevice_rebuild_header;
+ dev->header_ops = &cycx_header_ops;
+
dev->hard_start_xmit = cycx_netdevice_hard_start_xmit;
dev->get_stats = cycx_netdevice_get_stats;
@@ -508,7 +516,6 @@ static int cycx_netdevice_init(struct net_device *dev)
/* Set transmit buffer queue length */
dev->tx_queue_len = 10;
- SET_MODULE_OWNER(dev);
/* Initialize socket buffers */
cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
@@ -555,7 +562,8 @@ static int cycx_netdevice_stop(struct net_device *dev)
* Return: media header length. */
static int cycx_netdevice_hard_header(struct sk_buff *skb,
struct net_device *dev, u16 type,
- void *daddr, void *saddr, unsigned len)
+ const void *daddr, const void *saddr,
+ unsigned len)
{
skb->protocol = type;
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 66be20c292b..96b232446c0 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -66,8 +66,8 @@ static void dlci_setup(struct net_device *);
*/
static int dlci_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
struct frhdr hdr;
struct dlci_local *dlp;
@@ -361,7 +361,7 @@ static int dlci_add(struct dlci_add *dlci)
/* validate slave device */
- slave = dev_get_by_name(dlci->devname);
+ slave = dev_get_by_name(&init_net, dlci->devname);
if (!slave)
return -ENODEV;
@@ -427,7 +427,7 @@ static int dlci_del(struct dlci_add *dlci)
int err;
/* validate slave device */
- master = __dev_get_by_name(dlci->devname);
+ master = __dev_get_by_name(&init_net, dlci->devname);
if (!master)
return(-ENODEV);
@@ -485,6 +485,10 @@ static int dlci_ioctl(unsigned int cmd, void __user *arg)
return(err);
}
+static const struct header_ops dlci_header_ops = {
+ .create = dlci_header,
+};
+
static void dlci_setup(struct net_device *dev)
{
struct dlci_local *dlp = dev->priv;
@@ -494,7 +498,7 @@ static void dlci_setup(struct net_device *dev)
dev->stop = dlci_close;
dev->do_ioctl = dlci_dev_ioctl;
dev->hard_start_xmit = dlci_transmit;
- dev->hard_header = dlci_header;
+ dev->header_ops = &dlci_header_ops;
dev->get_stats = dlci_get_stats;
dev->change_mtu = dlci_change_mtu;
dev->destructor = free_netdev;
@@ -513,6 +517,9 @@ static int dlci_dev_event(struct notifier_block *unused,
{
struct net_device *dev = (struct net_device *) ptr;
+ if (dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
if (event == NETDEV_UNREGISTER) {
struct dlci_local *dlp;
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 50d2f9108dc..33dc713b530 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -925,7 +925,6 @@ static int dscc4_found1(struct pci_dev *pdev, void __iomem *ioaddr)
d->do_ioctl = dscc4_ioctl;
d->tx_timeout = dscc4_tx_timeout;
d->watchdog_timeo = TX_TIMEOUT;
- SET_MODULE_OWNER(d);
SET_NETDEV_DEV(d, &pdev->dev);
dpriv->dev_id = i;
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index 65ad2e24caf..d553e6f3285 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -36,6 +36,7 @@
#include <linux/rtnetlink.h>
#include <linux/notifier.h>
#include <linux/hdlc.h>
+#include <net/net_namespace.h>
static const char* version = "HDLC support module revision 1.21";
@@ -66,6 +67,12 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *p, struct net_device *orig_dev)
{
struct hdlc_device_desc *desc = dev_to_desc(dev);
+
+ if (dev->nd_net != &init_net) {
+ kfree_skb(skb);
+ return 0;
+ }
+
if (desc->netif_rx)
return desc->netif_rx(skb);
@@ -102,6 +109,9 @@ static int hdlc_device_event(struct notifier_block *this, unsigned long event,
unsigned long flags;
int on;
+ if (dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
if (dev->get_stats != hdlc_get_stats)
return NOTIFY_DONE; /* not an HDLC device */
@@ -222,6 +232,8 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EINVAL;
}
+static const struct header_ops hdlc_null_ops;
+
static void hdlc_setup_dev(struct net_device *dev)
{
/* Re-init all variables changed by HDLC protocol drivers,
@@ -233,13 +245,9 @@ static void hdlc_setup_dev(struct net_device *dev)
dev->type = ARPHRD_RAWHDLC;
dev->hard_header_len = 16;
dev->addr_len = 0;
- dev->hard_header = NULL;
- dev->rebuild_header = NULL;
- dev->set_mac_address = NULL;
- dev->hard_header_cache = NULL;
- dev->header_cache_update = NULL;
+ dev->header_ops = &hdlc_null_ops;
+
dev->change_mtu = hdlc_change_mtu;
- dev->hard_header_parse = NULL;
}
static void hdlc_setup(struct net_device *dev)
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index 9ec6cf2e510..038a6e748bb 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -74,7 +74,7 @@ static inline struct cisco_state * state(hdlc_device *hdlc)
static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
- u16 type, void *daddr, void *saddr,
+ u16 type, const void *daddr, const void *saddr,
unsigned int len)
{
struct hdlc_header *data;
@@ -309,7 +309,6 @@ static void cisco_stop(struct net_device *dev)
}
-
static struct hdlc_proto proto = {
.start = cisco_start,
.stop = cisco_stop,
@@ -317,7 +316,10 @@ static struct hdlc_proto proto = {
.ioctl = cisco_ioctl,
.module = THIS_MODULE,
};
-
+
+static const struct header_ops cisco_header_ops = {
+ .create = cisco_hard_header,
+};
static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
{
@@ -365,7 +367,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
memcpy(&state(hdlc)->settings, &new_settings, size);
dev->hard_start_xmit = hdlc->xmit;
- dev->hard_header = cisco_hard_header;
+ dev->header_ops = &cisco_header_ops;
dev->type = ARPHRD_CISCO;
netif_dormant_on(dev);
return 0;
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index 4591437dd2f..3caeb528eac 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -73,7 +73,7 @@ static void ppp_close(struct net_device *dev)
sppp_close(dev);
sppp_detach(dev);
- dev->rebuild_header = NULL;
+
dev->change_mtu = state(hdlc)->old_change_mtu;
dev->mtu = HDLC_MAX_MTU;
dev->hard_header_len = 16;
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index bf5f8d9b5c8..83dbc924fcb 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -241,8 +241,6 @@ static struct sv11_device *sv11_init(int iobase, int irq)
if(!sv->netdev.dev)
goto fail2;
- SET_MODULE_OWNER(sv->netdev.dev);
-
dev=&sv->sync;
/*
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 6c302e9dbca..fb37b809523 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -91,6 +91,9 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
int len, err;
struct lapbethdev *lapbeth;
+ if (dev->nd_net != &init_net)
+ goto drop;
+
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
return NET_RX_DROP;
@@ -213,7 +216,7 @@ static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb)
skb->dev = dev = lapbeth->ethdev;
- dev->hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
+ dev_hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
dev_queue_xmit(skb);
}
@@ -326,7 +329,6 @@ static void lapbeth_setup(struct net_device *dev)
dev->hard_header_len = 3;
dev->mtu = 1000;
dev->addr_len = 0;
- SET_MODULE_OWNER(dev);
}
/*
@@ -391,6 +393,9 @@ static int lapbeth_device_event(struct notifier_block *this,
struct lapbethdev *lapbeth;
struct net_device *dev = ptr;
+ if (dev->nd_net != &init_net)
+ return NOTIFY_DONE;
+
if (!dev_is_ethdev(dev))
return NOTIFY_DONE;
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index ae132c1c545..37c52e13175 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -142,9 +142,10 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
* To date internally, just copy this out to the user.
*/
case LMCIOCGINFO: /*fold01*/
- if (copy_to_user(ifr->ifr_data, &sc->ictl, sizeof (lmc_ctl_t)))
- return -EFAULT;
- ret = 0;
+ if (copy_to_user(ifr->ifr_data, &sc->ictl, sizeof(lmc_ctl_t)))
+ ret = -EFAULT;
+ else
+ ret = 0;
break;
case LMCIOCSINFO: /*fold01*/
@@ -159,8 +160,10 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
break;
}
- if (copy_from_user(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t)))
- return -EFAULT;
+ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(lmc_ctl_t))) {
+ ret = -EFAULT;
+ break;
+ }
sc->lmc_media->set_status (sc, &ctl);
@@ -190,8 +193,10 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
break;
}
- if (copy_from_user(&new_type, ifr->ifr_data, sizeof(u_int16_t)))
- return -EFAULT;
+ if (copy_from_user(&new_type, ifr->ifr_data, sizeof(u_int16_t))) {
+ ret = -EFAULT;
+ break;
+ }
if (new_type == old_type)
@@ -229,9 +234,10 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
sc->lmc_xinfo.Magic1 = 0xDEADBEEF;
if (copy_to_user(ifr->ifr_data, &sc->lmc_xinfo,
- sizeof (struct lmc_xinfo)))
- return -EFAULT;
- ret = 0;
+ sizeof(struct lmc_xinfo)))
+ ret = -EFAULT;
+ else
+ ret = 0;
break;
@@ -262,9 +268,9 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
if (copy_to_user(ifr->ifr_data, &sc->stats,
sizeof (struct lmc_statistics)))
- return -EFAULT;
-
- ret = 0;
+ ret = -EFAULT;
+ else
+ ret = 0;
break;
case LMCIOCCLEARLMCSTATS: /*fold01*/
@@ -292,8 +298,10 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
break;
}
- if (copy_from_user(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t)))
- return -EFAULT;
+ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(lmc_ctl_t))) {
+ ret = -EFAULT;
+ break;
+ }
sc->lmc_media->set_circuit_type(sc, ctl.circuit_type);
sc->ictl.circuit_type = ctl.circuit_type;
ret = 0;
@@ -318,12 +326,15 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
#ifdef DEBUG
case LMCIOCDUMPEVENTLOG:
- if (copy_to_user(ifr->ifr_data, &lmcEventLogIndex, sizeof (u32)))
- return -EFAULT;
+ if (copy_to_user(ifr->ifr_data, &lmcEventLogIndex, sizeof(u32))) {
+ ret = -EFAULT;
+ break;
+ }
if (copy_to_user(ifr->ifr_data + sizeof (u32), lmcEventLogBuf, sizeof (lmcEventLogBuf)))
- return -EFAULT;
+ ret = -EFAULT;
+ else
+ ret = 0;
- ret = 0;
break;
#endif /* end ifdef _DBG_EVENTLOG */
case LMCIOCT1CONTROL: /*fold01*/
@@ -346,8 +357,10 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/
*/
netif_stop_queue(dev);
- if (copy_from_user(&xc, ifr->ifr_data, sizeof (struct lmc_xilinx_control)))
- return -EFAULT;
+ if (copy_from_user(&xc, ifr->ifr_data, sizeof(struct lmc_xilinx_control))) {
+ ret = -EFAULT;
+ break;
+ }
switch(xc.command){
case lmc_xilinx_reset: /*fold02*/
{
@@ -883,7 +896,6 @@ static int __devinit lmc_init_one(struct pci_dev *pdev,
dev->base_addr = pci_resource_start(pdev, 0);
dev->irq = pdev->irq;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/*
diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c
index 31e1799571a..426c0678d98 100644
--- a/drivers/net/wan/lmc/lmc_proto.c
+++ b/drivers/net/wan/lmc/lmc_proto.c
@@ -111,7 +111,7 @@ void lmc_proto_attach(lmc_softc_t *sc) /*FOLD00*/
* They set a few basics because they don't use sync_ppp
*/
dev->flags |= IFF_POINTOPOINT;
- dev->hard_header = NULL;
+
dev->hard_header_len = 0;
dev->addr_len = 0;
}
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
index cbdf0b748bd..0a566b0daac 100644
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -459,7 +459,6 @@ static int __init n2_run(unsigned long io, unsigned long irq,
port->log_node = 1;
spin_lock_init(&port->lock);
- SET_MODULE_OWNER(dev);
dev->irq = irq;
dev->mem_start = winbase;
dev->mem_end = winbase + USE_WINDOWSIZE - 1;
diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c
index 6353cb5c658..bf1b0159042 100644
--- a/drivers/net/wan/pc300too.c
+++ b/drivers/net/wan/pc300too.c
@@ -468,7 +468,6 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
port->phy_node = i;
spin_lock_init(&port->lock);
- SET_MODULE_OWNER(dev);
dev->irq = card->irq;
dev->mem_start = ramphys;
dev->mem_end = ramphys + ramsize - 1;
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index 092e51d8903..b595b64e753 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -415,7 +415,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
port->phy_node = i;
spin_lock_init(&port->lock);
- SET_MODULE_OWNER(dev);
dev->irq = card->irq;
dev->mem_start = ramphys;
dev->mem_end = ramphys + ramsize - 1;
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index 1cc18e787a6..2e8b5c2de88 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -54,6 +54,7 @@
#include <linux/init.h>
#include <linux/delay.h>
+#include <net/net_namespace.h>
#include <net/arp.h>
#include <asm/io.h>
@@ -215,8 +216,6 @@ static void __init sbni_devsetup(struct net_device *dev)
dev->get_stats = &sbni_get_stats;
dev->set_multicast_list = &set_multicast_list;
dev->do_ioctl = &sbni_ioctl;
-
- SET_MODULE_OWNER( dev );
}
int __init sbni_probe(int unit)
@@ -503,8 +502,8 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev )
static irqreturn_t
sbni_interrupt( int irq, void *dev_id )
{
- struct net_device *dev = (struct net_device *) dev_id;
- struct net_local *nl = (struct net_local *) dev->priv;
+ struct net_device *dev = dev_id;
+ struct net_local *nl = dev->priv;
int repeat;
spin_lock( &nl->lock );
@@ -1361,7 +1360,7 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd )
if (copy_from_user( slave_name, ifr->ifr_data, sizeof slave_name ))
return -EFAULT;
- slave_dev = dev_get_by_name( slave_name );
+ slave_dev = dev_get_by_name(&init_net, slave_name );
if( !slave_dev || !(slave_dev->flags & IFF_UP) ) {
printk( KERN_ERR "%s: trying to enslave non-active "
"device %s\n", dev->name, slave_name );
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 792e588d7d6..05df0a345b6 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -1342,11 +1342,11 @@ static int sdla_set_config(struct net_device *dev, struct ifmap *map)
if (flp->initialized)
return(-EINVAL);
- for(i=0;i < sizeof(valid_port) / sizeof (int) ; i++)
+ for(i=0; i < ARRAY_SIZE(valid_port); i++)
if (valid_port[i] == map->base_addr)
break;
- if (i == sizeof(valid_port) / sizeof(int))
+ if (i == ARRAY_SIZE(valid_port))
return(-EINVAL);
if (!request_region(map->base_addr, SDLA_IO_EXTENTS, dev->name)){
@@ -1487,12 +1487,12 @@ got_type:
}
}
- for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++)
+ for(i=0; i < ARRAY_SIZE(valid_mem); i++)
if (valid_mem[i] == map->mem_start)
break;
err = -EINVAL;
- if (i == sizeof(valid_mem) / sizeof(int))
+ if (i == ARRAY_SIZE(valid_mem))
goto fail2;
if (flp->type == SDLA_S502A && (map->mem_start & 0xF000) >> 12 == 0x0E)
@@ -1603,7 +1603,6 @@ static void setup_sdla(struct net_device *dev)
netdev_boot_setup_check(dev);
- SET_MODULE_OWNER(dev);
dev->flags = 0;
dev->type = 0xFFFF;
dev->hard_header_len = 0;
diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
index 67fc67cfd45..232ecba5340 100644
--- a/drivers/net/wan/syncppp.c
+++ b/drivers/net/wan/syncppp.c
@@ -51,6 +51,7 @@
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
+#include <net/net_namespace.h>
#include <net/syncppp.h>
#include <asm/byteorder.h>
@@ -358,8 +359,10 @@ done:
* Handle transmit packets.
*/
-static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type,
- void *daddr, void *saddr, unsigned int len)
+static int sppp_hard_header(struct sk_buff *skb,
+ struct net_device *dev, __u16 type,
+ const void *daddr, const void *saddr,
+ unsigned int len)
{
struct sppp *sp = (struct sppp *)sppp_of(dev);
struct ppp_header *h;
@@ -391,10 +394,9 @@ static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 t
return sizeof(struct ppp_header);
}
-static int sppp_rebuild_header(struct sk_buff *skb)
-{
- return 0;
-}
+static const struct header_ops sppp_header_ops = {
+ .create = sppp_hard_header,
+};
/*
* Send keepalive packets, every 10 seconds.
@@ -1097,8 +1099,8 @@ void sppp_attach(struct ppp_device *pd)
* hard_start_xmit.
*/
- dev->hard_header = sppp_hard_header;
- dev->rebuild_header = sppp_rebuild_header;
+ dev->header_ops = &sppp_header_ops;
+
dev->tx_queue_len = 10;
dev->type = ARPHRD_HDLC;
dev->addr_len = 0;
@@ -1114,8 +1116,6 @@ void sppp_attach(struct ppp_device *pd)
dev->stop = sppp_close;
#endif
dev->change_mtu = sppp_change_mtu;
- dev->hard_header_cache = NULL;
- dev->header_cache_update = NULL;
dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;
}
@@ -1445,6 +1445,11 @@ static void sppp_print_bytes (u_char *p, u16 len)
static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev)
{
+ if (dev->nd_net != &init_net) {
+ kfree_skb(skb);
+ return 0;
+ }
+
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
return NET_RX_DROP;
sppp_input(dev,skb);
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index 3c78f985638..8e320b76ae0 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -779,7 +779,6 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
port->dev = dev;
hdlc = dev_to_hdlc(dev);
spin_lock_init(&port->lock);
- SET_MODULE_OWNER(dev);
dev->tx_queue_len = 50;
dev->do_ioctl = wanxl_ioctl;
dev->open = wanxl_open;
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index c48b1cc63fd..1e89d4de1bb 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -719,12 +719,8 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file,
return 0;
case SIOCSIFHWADDR:
return -EINVAL;
- /* Allow stty to read, but not set, the serial port */
- case TCGETS:
- case TCGETA:
- return n_tty_ioctl(tty, file, cmd, arg);
default:
- return -ENOIOCTLCMD;
+ return tty_mode_ioctl(tty, file, cmd, arg);
}
}
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index a0326818ff2..fa14255282a 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -93,8 +93,6 @@ static int __init do_wd_probe(struct net_device *dev)
int mem_start = dev->mem_start;
int mem_end = dev->mem_end;
- SET_MODULE_OWNER(dev);
-
if (base_addr > 0x1ff) { /* Check a user specified location. */
r = request_region(base_addr, WD_IO_EXTENT, "wd-probe");
if ( r == NULL)
@@ -158,6 +156,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
int word16 = 0; /* 0 = 8 bit, 1 = 16 bit */
const char *model_name;
static unsigned version_printed;
+ DECLARE_MAC_BUF(mac);
for (i = 0; i < 8; i++)
checksum += inb(ioaddr + 8 + i);
@@ -176,9 +175,11 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
if (ei_debug && version_printed++ == 0)
printk(version);
- printk("%s: WD80x3 at %#3x,", dev->name, ioaddr);
for (i = 0; i < 6; i++)
- printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
+ dev->dev_addr[i] = inb(ioaddr + 8 + i);
+
+ printk("%s: WD80x3 at %#3x, %s",
+ dev->name, ioaddr, print_mac(mac, dev->dev_addr));
/* The following PureData probe code was contributed by
Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index ae27af0141c..2b733c58291 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -63,11 +63,6 @@ config WAVELAN
a Radio LAN (wireless Ethernet-like Local Area Network) using the
radio frequencies 900 MHz and 2.4 GHz.
- This driver support the ISA version of the WaveLAN card. A separate
- driver for the PCMCIA (PC-card) hardware is available in David
- Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
- for location).
-
If you want to use an ISA WaveLAN card under Linux, say Y and read
the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>. Some more specific
@@ -280,6 +275,19 @@ config LIBERTAS_USB
---help---
A driver for Marvell Libertas 8388 USB devices.
+config LIBERTAS_CS
+ tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards"
+ depends on LIBERTAS && PCMCIA && EXPERIMENTAL
+ select FW_LOADER
+ ---help---
+ A driver for Marvell Libertas 8385 CompactFlash devices.
+
+config LIBERTAS_SDIO
+ tristate "Marvell Libertas 8385 and 8686 SDIO 802.11b/g cards"
+ depends on LIBERTAS && MMC
+ ---help---
+ A driver for Marvell Libertas 8385 and 8686 SDIO devices.
+
config LIBERTAS_DEBUG
bool "Enable full debugging output in the Libertas module."
depends on LIBERTAS
@@ -317,7 +325,7 @@ config HERMES
Cabletron/EnteraSys Roamabout, ELSA AirLancer, MELCO Buffalo, Avaya,
IBM High Rate Wireless, Farralon Syyline, Samsung MagicLAN, Netgear
MA401, LinkSys WPC-11, D-Link DWL-650, 3Com AirConnect, Intel
- PRO/Wireless, and Symbol Spectrum24 High Rate amongst others.
+ IPW2011, and Symbol Spectrum24 High Rate amongst others.
This option includes the guts of the driver, but in order to
actually use a card you will also need to enable support for PCMCIA
@@ -379,30 +387,6 @@ config PCI_HERMES
common. Some of the built-in wireless adaptors in laptops are of
this variety.
-config ATMEL
- tristate "Atmel at76c50x chipset 802.11b support"
- depends on (PCI || PCMCIA) && WLAN_80211
- select WIRELESS_EXT
- select FW_LOADER
- select CRC32
- ---help---
- A driver 802.11b wireless cards based on the Atmel fast-vnet
- chips. This driver supports standard Linux wireless extensions.
-
- Many cards based on this chipset do not have flash memory
- and need their firmware loaded at start-up. If yours is
- one of these, you will need to provide a firmware image
- to be loaded into the card by the driver. The Atmel
- firmware package can be downloaded from
- <http://www.thekelleys.org.uk/atmel>
-
-config PCI_ATMEL
- tristate "Atmel at76c506 PCI cards"
- depends on ATMEL && PCI
- ---help---
- Enable support for PCI and mini-PCI cards containing the
- Atmel at76c506 chip.
-
config PCMCIA_HERMES
tristate "Hermes PCMCIA card support"
depends on PCMCIA && HERMES
@@ -414,12 +398,7 @@ config PCMCIA_HERMES
such as the Linksys, D-Link and Farallon Skyline. It should also
work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN.
- To use your PC-cards, you will need supporting software from David
- Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
- for location). You also want to check out the PCMCIA-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
- You will also very likely also need the Wireless Tools in order to
+ You will very likely need the Wireless Tools in order to
configure your card and that /etc/pcmcia/wireless.opts works:
<http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
@@ -437,6 +416,40 @@ config PCMCIA_SPECTRUM
for downloading Symbol firmware are available at
<http://sourceforge.net/projects/orinoco/>
+config ATMEL
+ tristate "Atmel at76c50x chipset 802.11b support"
+ depends on (PCI || PCMCIA) && WLAN_80211
+ select WIRELESS_EXT
+ select FW_LOADER
+ select CRC32
+ ---help---
+ A driver 802.11b wireless cards based on the Atmel fast-vnet
+ chips. This driver supports standard Linux wireless extensions.
+
+ Many cards based on this chipset do not have flash memory
+ and need their firmware loaded at start-up. If yours is
+ one of these, you will need to provide a firmware image
+ to be loaded into the card by the driver. The Atmel
+ firmware package can be downloaded from
+ <http://www.thekelleys.org.uk/atmel>
+
+config PCI_ATMEL
+ tristate "Atmel at76c506 PCI cards"
+ depends on ATMEL && PCI
+ ---help---
+ Enable support for PCI and mini-PCI cards containing the
+ Atmel at76c506 chip.
+
+config PCMCIA_ATMEL
+ tristate "Atmel at76c502/at76c504 PCMCIA cards"
+ depends on ATMEL && PCMCIA
+ select WIRELESS_EXT
+ select FW_LOADER
+ select CRC32
+ ---help---
+ Enable support for PCMCIA cards containing the
+ Atmel at76c502 and at76c504 chips.
+
config AIRO_CS
tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
depends on PCMCIA && (BROKEN || !M32R) && WLAN_80211
@@ -457,21 +470,6 @@ config AIRO_CS
and Cisco proprietary API, so both the Linux Wireless Tools and the
Cisco Linux utilities can be used to configure the card.
- To use your PC-cards, you will need supporting software from David
- Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
- for location). You also want to check out the PCMCIA-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
-config PCMCIA_ATMEL
- tristate "Atmel at76c502/at76c504 PCMCIA cards"
- depends on ATMEL && PCMCIA
- select WIRELESS_EXT
- select FW_LOADER
- select CRC32
- ---help---
- Enable support for PCMCIA cards containing the
- Atmel at76c502 and at76c504 chips.
-
config PCMCIA_WL3501
tristate "Planet WL3501 PCMCIA cards"
depends on EXPERIMENTAL && PCMCIA && WLAN_80211
@@ -558,8 +556,52 @@ config RTL8187
Thanks to Realtek for their support!
+config ADM8211
+ tristate "ADMtek ADM8211 support"
+ depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL
+ select CRC32
+ select EEPROM_93CX6
+ ---help---
+ This driver is for ADM8211A, ADM8211B, and ADM8211C based cards.
+ These are PCI/mini-PCI/Cardbus 802.11b chips found in cards such as:
+
+ Xterasys Cardbus XN-2411b
+ Blitz NetWave Point PC
+ TrendNet 221pc
+ Belkin F5D6001
+ SMC 2635W
+ Linksys WPC11 v1
+ Fiberline FL-WL-200X
+ 3com Office Connect (3CRSHPW796)
+ Corega WLPCIB-11
+ SMC 2602W V2 EU
+ D-Link DWL-520 Revision C
+
+ However, some of these cards have been replaced with other chips
+ like the RTL8180L (Xterasys Cardbus XN-2411b, Belkin F5D6001) or
+ the Ralink RT2400 (SMC2635W) without a model number change.
+
+ Thanks to Infineon-ADMtek for their support of this driver.
+
+config P54_COMMON
+ tristate "Softmac Prism54 support"
+ depends on MAC80211 && WLAN_80211 && FW_LOADER && EXPERIMENTAL
+
+config P54_USB
+ tristate "Prism54 USB support"
+ depends on P54_COMMON && USB
+ select CRC32
+
+config P54_PCI
+ tristate "Prism54 PCI support"
+ depends on P54_COMMON && PCI
+
+source "drivers/net/wireless/iwlwifi/Kconfig"
source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/bcm43xx/Kconfig"
+source "drivers/net/wireless/b43/Kconfig"
+source "drivers/net/wireless/b43legacy/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
+source "drivers/net/wireless/rt2x00/Kconfig"
endmenu
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 4eb6d975288..6f32b53ee12 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -36,6 +36,8 @@ obj-$(CONFIG_PRISM54) += prism54/
obj-$(CONFIG_HOSTAP) += hostap/
obj-$(CONFIG_BCM43XX) += bcm43xx/
+obj-$(CONFIG_B43) += b43/
+obj-$(CONFIG_B43LEGACY) += b43legacy/
obj-$(CONFIG_ZD1211RW) += zd1211rw/
# 16-bit wireless PCMCIA client drivers
@@ -47,3 +49,12 @@ obj-$(CONFIG_LIBERTAS) += libertas/
rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o
obj-$(CONFIG_RTL8187) += rtl8187.o
+
+obj-$(CONFIG_ADM8211) += adm8211.o
+
+obj-$(CONFIG_IWLWIFI) += iwlwifi/
+obj-$(CONFIG_RT2X00) += rt2x00/
+
+obj-$(CONFIG_P54_COMMON) += p54common.o
+obj-$(CONFIG_P54_USB) += p54usb.o
+obj-$(CONFIG_P54_PCI) += p54pci.o
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
new file mode 100644
index 00000000000..5bf7913aadd
--- /dev/null
+++ b/drivers/net/wireless/adm8211.c
@@ -0,0 +1,2053 @@
+
+/*
+ * Linux device driver for ADMtek ADM8211 (IEEE 802.11b MAC/BBP)
+ *
+ * Copyright (c) 2003, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2007, Michael Wu <flamingice@sourmilk.net>
+ * Some parts copyright (c) 2003 by David Young <dyoung@pobox.com>
+ * and used with permission.
+ *
+ * Much thanks to Infineon-ADMtek for their support of this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/init.h>
+#include <linux/if.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/eeprom_93cx6.h>
+#include <net/mac80211.h>
+
+#include "adm8211.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_AUTHOR("Jouni Malinen <j@w1.fi>");
+MODULE_DESCRIPTION("Driver for IEEE 802.11b wireless cards based on ADMtek ADM8211");
+MODULE_SUPPORTED_DEVICE("ADM8211");
+MODULE_LICENSE("GPL");
+
+static unsigned int tx_ring_size __read_mostly = 16;
+static unsigned int rx_ring_size __read_mostly = 16;
+
+module_param(tx_ring_size, uint, 0);
+module_param(rx_ring_size, uint, 0);
+
+static struct pci_device_id adm8211_pci_id_table[] __devinitdata = {
+ /* ADMtek ADM8211 */
+ { PCI_DEVICE(0x10B7, 0x6000) }, /* 3Com 3CRSHPW796 */
+ { PCI_DEVICE(0x1200, 0x8201) }, /* ? */
+ { PCI_DEVICE(0x1317, 0x8201) }, /* ADM8211A */
+ { PCI_DEVICE(0x1317, 0x8211) }, /* ADM8211B/C */
+ { 0 }
+};
+
+static void adm8211_eeprom_register_read(struct eeprom_93cx6 *eeprom)
+{
+ struct adm8211_priv *priv = eeprom->data;
+ u32 reg = ADM8211_CSR_READ(SPR);
+
+ eeprom->reg_data_in = reg & ADM8211_SPR_SDI;
+ eeprom->reg_data_out = reg & ADM8211_SPR_SDO;
+ eeprom->reg_data_clock = reg & ADM8211_SPR_SCLK;
+ eeprom->reg_chip_select = reg & ADM8211_SPR_SCS;
+}
+
+static void adm8211_eeprom_register_write(struct eeprom_93cx6 *eeprom)
+{
+ struct adm8211_priv *priv = eeprom->data;
+ u32 reg = 0x4000 | ADM8211_SPR_SRS;
+
+ if (eeprom->reg_data_in)
+ reg |= ADM8211_SPR_SDI;
+ if (eeprom->reg_data_out)
+ reg |= ADM8211_SPR_SDO;
+ if (eeprom->reg_data_clock)
+ reg |= ADM8211_SPR_SCLK;
+ if (eeprom->reg_chip_select)
+ reg |= ADM8211_SPR_SCS;
+
+ ADM8211_CSR_WRITE(SPR, reg);
+ ADM8211_CSR_READ(SPR); /* eeprom_delay */
+}
+
+static int adm8211_read_eeprom(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int words, i;
+ struct ieee80211_chan_range chan_range;
+ u16 cr49;
+ struct eeprom_93cx6 eeprom = {
+ .data = priv,
+ .register_read = adm8211_eeprom_register_read,
+ .register_write = adm8211_eeprom_register_write
+ };
+
+ if (ADM8211_CSR_READ(CSR_TEST0) & ADM8211_CSR_TEST0_EPTYP) {
+ /* 256 * 16-bit = 512 bytes */
+ eeprom.width = PCI_EEPROM_WIDTH_93C66;
+ words = 256;
+ } else {
+ /* 64 * 16-bit = 128 bytes */
+ eeprom.width = PCI_EEPROM_WIDTH_93C46;
+ words = 64;
+ }
+
+ priv->eeprom_len = words * 2;
+ priv->eeprom = kmalloc(priv->eeprom_len, GFP_KERNEL);
+ if (!priv->eeprom)
+ return -ENOMEM;
+
+ eeprom_93cx6_multiread(&eeprom, 0, (__le16 __force *)priv->eeprom, words);
+
+ cr49 = le16_to_cpu(priv->eeprom->cr49);
+ priv->rf_type = (cr49 >> 3) & 0x7;
+ switch (priv->rf_type) {
+ case ADM8211_TYPE_INTERSIL:
+ case ADM8211_TYPE_RFMD:
+ case ADM8211_TYPE_MARVEL:
+ case ADM8211_TYPE_AIROHA:
+ case ADM8211_TYPE_ADMTEK:
+ break;
+
+ default:
+ if (priv->pdev->revision < ADM8211_REV_CA)
+ priv->rf_type = ADM8211_TYPE_RFMD;
+ else
+ priv->rf_type = ADM8211_TYPE_AIROHA;
+
+ printk(KERN_WARNING "%s (adm8211): Unknown RFtype %d\n",
+ pci_name(priv->pdev), (cr49 >> 3) & 0x7);
+ }
+
+ priv->bbp_type = cr49 & 0x7;
+ switch (priv->bbp_type) {
+ case ADM8211_TYPE_INTERSIL:
+ case ADM8211_TYPE_RFMD:
+ case ADM8211_TYPE_MARVEL:
+ case ADM8211_TYPE_AIROHA:
+ case ADM8211_TYPE_ADMTEK:
+ break;
+ default:
+ if (priv->pdev->revision < ADM8211_REV_CA)
+ priv->bbp_type = ADM8211_TYPE_RFMD;
+ else
+ priv->bbp_type = ADM8211_TYPE_ADMTEK;
+
+ printk(KERN_WARNING "%s (adm8211): Unknown BBPtype: %d\n",
+ pci_name(priv->pdev), cr49 >> 3);
+ }
+
+ if (priv->eeprom->country_code >= ARRAY_SIZE(cranges)) {
+ printk(KERN_WARNING "%s (adm8211): Invalid country code (%d)\n",
+ pci_name(priv->pdev), priv->eeprom->country_code);
+
+ chan_range = cranges[2];
+ } else
+ chan_range = cranges[priv->eeprom->country_code];
+
+ printk(KERN_DEBUG "%s (adm8211): Channel range: %d - %d\n",
+ pci_name(priv->pdev), (int)chan_range.min, (int)chan_range.max);
+
+ priv->modes[0].num_channels = chan_range.max - chan_range.min + 1;
+ priv->modes[0].channels = priv->channels;
+
+ memcpy(priv->channels, adm8211_channels, sizeof(adm8211_channels));
+
+ for (i = 1; i <= ARRAY_SIZE(adm8211_channels); i++)
+ if (i >= chan_range.min && i <= chan_range.max)
+ priv->channels[i - 1].flag =
+ IEEE80211_CHAN_W_SCAN |
+ IEEE80211_CHAN_W_ACTIVE_SCAN |
+ IEEE80211_CHAN_W_IBSS;
+
+ switch (priv->eeprom->specific_bbptype) {
+ case ADM8211_BBP_RFMD3000:
+ case ADM8211_BBP_RFMD3002:
+ case ADM8211_BBP_ADM8011:
+ priv->specific_bbptype = priv->eeprom->specific_bbptype;
+ break;
+
+ default:
+ if (priv->pdev->revision < ADM8211_REV_CA)
+ priv->specific_bbptype = ADM8211_BBP_RFMD3000;
+ else
+ priv->specific_bbptype = ADM8211_BBP_ADM8011;
+
+ printk(KERN_WARNING "%s (adm8211): Unknown specific BBP: %d\n",
+ pci_name(priv->pdev), priv->eeprom->specific_bbptype);
+ }
+
+ switch (priv->eeprom->specific_rftype) {
+ case ADM8211_RFMD2948:
+ case ADM8211_RFMD2958:
+ case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+ case ADM8211_MAX2820:
+ case ADM8211_AL2210L:
+ priv->transceiver_type = priv->eeprom->specific_rftype;
+ break;
+
+ default:
+ if (priv->pdev->revision == ADM8211_REV_BA)
+ priv->transceiver_type = ADM8211_RFMD2958_RF3000_CONTROL_POWER;
+ else if (priv->pdev->revision == ADM8211_REV_CA)
+ priv->transceiver_type = ADM8211_AL2210L;
+ else if (priv->pdev->revision == ADM8211_REV_AB)
+ priv->transceiver_type = ADM8211_RFMD2948;
+
+ printk(KERN_WARNING "%s (adm8211): Unknown transceiver: %d\n",
+ pci_name(priv->pdev), priv->eeprom->specific_rftype);
+
+ break;
+ }
+
+ printk(KERN_DEBUG "%s (adm8211): RFtype=%d BBPtype=%d Specific BBP=%d "
+ "Transceiver=%d\n", pci_name(priv->pdev), priv->rf_type,
+ priv->bbp_type, priv->specific_bbptype, priv->transceiver_type);
+
+ return 0;
+}
+
+static inline void adm8211_write_sram(struct ieee80211_hw *dev,
+ u32 addr, u32 data)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ ADM8211_CSR_WRITE(WEPCTL, addr | ADM8211_WEPCTL_TABLE_WR |
+ (priv->pdev->revision < ADM8211_REV_BA ?
+ 0 : ADM8211_WEPCTL_SEL_WEPTABLE ));
+ ADM8211_CSR_READ(WEPCTL);
+ msleep(1);
+
+ ADM8211_CSR_WRITE(WESK, data);
+ ADM8211_CSR_READ(WESK);
+ msleep(1);
+}
+
+static void adm8211_write_sram_bytes(struct ieee80211_hw *dev,
+ unsigned int addr, u8 *buf,
+ unsigned int len)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg = ADM8211_CSR_READ(WEPCTL);
+ unsigned int i;
+
+ if (priv->pdev->revision < ADM8211_REV_BA) {
+ for (i = 0; i < len; i += 2) {
+ u16 val = buf[i] | (buf[i + 1] << 8);
+ adm8211_write_sram(dev, addr + i / 2, val);
+ }
+ } else {
+ for (i = 0; i < len; i += 4) {
+ u32 val = (buf[i + 0] << 0 ) | (buf[i + 1] << 8 ) |
+ (buf[i + 2] << 16) | (buf[i + 3] << 24);
+ adm8211_write_sram(dev, addr + i / 4, val);
+ }
+ }
+
+ ADM8211_CSR_WRITE(WEPCTL, reg);
+}
+
+static void adm8211_clear_sram(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg = ADM8211_CSR_READ(WEPCTL);
+ unsigned int addr;
+
+ for (addr = 0; addr < ADM8211_SRAM_SIZE; addr++)
+ adm8211_write_sram(dev, addr, 0);
+
+ ADM8211_CSR_WRITE(WEPCTL, reg);
+}
+
+static int adm8211_get_stats(struct ieee80211_hw *dev,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ memcpy(stats, &priv->stats, sizeof(*stats));
+
+ return 0;
+}
+
+static int adm8211_get_tx_stats(struct ieee80211_hw *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct adm8211_priv *priv = dev->priv;
+ struct ieee80211_tx_queue_stats_data *data = &stats->data[0];
+
+ data->len = priv->cur_tx - priv->dirty_tx;
+ data->limit = priv->tx_ring_size - 2;
+ data->count = priv->dirty_tx;
+
+ return 0;
+}
+
+static void adm8211_interrupt_tci(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int dirty_tx;
+
+ spin_lock(&priv->lock);
+
+ for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) {
+ unsigned int entry = dirty_tx % priv->tx_ring_size;
+ u32 status = le32_to_cpu(priv->tx_ring[entry].status);
+ struct ieee80211_tx_status tx_status;
+ struct adm8211_tx_ring_info *info;
+ struct sk_buff *skb;
+
+ if (status & TDES0_CONTROL_OWN ||
+ !(status & TDES0_CONTROL_DONE))
+ break;
+
+ info = &priv->tx_buffers[entry];
+ skb = info->skb;
+
+ /* TODO: check TDES0_STATUS_TUF and TDES0_STATUS_TRO */
+
+ pci_unmap_single(priv->pdev, info->mapping,
+ info->skb->len, PCI_DMA_TODEVICE);
+
+ memset(&tx_status, 0, sizeof(tx_status));
+ skb_pull(skb, sizeof(struct adm8211_tx_hdr));
+ memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen);
+ memcpy(&tx_status.control, &info->tx_control,
+ sizeof(tx_status.control));
+ if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
+ if (status & TDES0_STATUS_ES)
+ tx_status.excessive_retries = 1;
+ else
+ tx_status.flags |= IEEE80211_TX_STATUS_ACK;
+ }
+ ieee80211_tx_status_irqsafe(dev, skb, &tx_status);
+
+ info->skb = NULL;
+ }
+
+ if (priv->cur_tx - dirty_tx < priv->tx_ring_size - 2)
+ ieee80211_wake_queue(dev, 0);
+
+ priv->dirty_tx = dirty_tx;
+ spin_unlock(&priv->lock);
+}
+
+
+static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int entry = priv->cur_rx % priv->rx_ring_size;
+ u32 status;
+ unsigned int pktlen;
+ struct sk_buff *skb, *newskb;
+ unsigned int limit = priv->rx_ring_size;
+ static const u8 rate_tbl[] = {10, 20, 55, 110, 220};
+ u8 rssi, rate;
+
+ while (!(priv->rx_ring[entry].status & cpu_to_le32(RDES0_STATUS_OWN))) {
+ if (!limit--)
+ break;
+
+ status = le32_to_cpu(priv->rx_ring[entry].status);
+ rate = (status & RDES0_STATUS_RXDR) >> 12;
+ rssi = le32_to_cpu(priv->rx_ring[entry].length) &
+ RDES1_STATUS_RSSI;
+
+ pktlen = status & RDES0_STATUS_FL;
+ if (pktlen > RX_PKT_SIZE) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: frame too long (%d)\n",
+ wiphy_name(dev->wiphy), pktlen);
+ pktlen = RX_PKT_SIZE;
+ }
+
+ if (!priv->soft_rx_crc && status & RDES0_STATUS_ES) {
+ skb = NULL; /* old buffer will be reused */
+ /* TODO: update RX error stats */
+ /* TODO: check RDES0_STATUS_CRC*E */
+ } else if (pktlen < RX_COPY_BREAK) {
+ skb = dev_alloc_skb(pktlen);
+ if (skb) {
+ pci_dma_sync_single_for_cpu(
+ priv->pdev,
+ priv->rx_buffers[entry].mapping,
+ pktlen, PCI_DMA_FROMDEVICE);
+ memcpy(skb_put(skb, pktlen),
+ skb_tail_pointer(priv->rx_buffers[entry].skb),
+ pktlen);
+ pci_dma_sync_single_for_device(
+ priv->pdev,
+ priv->rx_buffers[entry].mapping,
+ RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+ }
+ } else {
+ newskb = dev_alloc_skb(RX_PKT_SIZE);
+ if (newskb) {
+ skb = priv->rx_buffers[entry].skb;
+ skb_put(skb, pktlen);
+ pci_unmap_single(
+ priv->pdev,
+ priv->rx_buffers[entry].mapping,
+ RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+ priv->rx_buffers[entry].skb = newskb;
+ priv->rx_buffers[entry].mapping =
+ pci_map_single(priv->pdev,
+ skb_tail_pointer(newskb),
+ RX_PKT_SIZE,
+ PCI_DMA_FROMDEVICE);
+ } else {
+ skb = NULL;
+ /* TODO: update rx dropped stats */
+ }
+
+ priv->rx_ring[entry].buffer1 =
+ cpu_to_le32(priv->rx_buffers[entry].mapping);
+ }
+
+ priv->rx_ring[entry].status = cpu_to_le32(RDES0_STATUS_OWN |
+ RDES0_STATUS_SQL);
+ priv->rx_ring[entry].length =
+ cpu_to_le32(RX_PKT_SIZE |
+ (entry == priv->rx_ring_size - 1 ?
+ RDES1_CONTROL_RER : 0));
+
+ if (skb) {
+ struct ieee80211_rx_status rx_status = {0};
+
+ if (priv->pdev->revision < ADM8211_REV_CA)
+ rx_status.ssi = rssi;
+ else
+ rx_status.ssi = 100 - rssi;
+
+ if (rate <= 4)
+ rx_status.rate = rate_tbl[rate];
+
+ rx_status.channel = priv->channel;
+ rx_status.freq = adm8211_channels[priv->channel - 1].freq;
+ rx_status.phymode = MODE_IEEE80211B;
+
+ ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ }
+
+ entry = (++priv->cur_rx) % priv->rx_ring_size;
+ }
+
+ /* TODO: check LPC and update stats? */
+}
+
+
+static irqreturn_t adm8211_interrupt(int irq, void *dev_id)
+{
+#define ADM8211_INT(x) \
+do { \
+ if (unlikely(stsr & ADM8211_STSR_ ## x)) \
+ printk(KERN_DEBUG "%s: " #x "\n", wiphy_name(dev->wiphy)); \
+} while (0)
+
+ struct ieee80211_hw *dev = dev_id;
+ struct adm8211_priv *priv = dev->priv;
+ u32 stsr = ADM8211_CSR_READ(STSR);
+ ADM8211_CSR_WRITE(STSR, stsr);
+ if (stsr == 0xffffffff)
+ return IRQ_HANDLED;
+
+ if (!(stsr & (ADM8211_STSR_NISS | ADM8211_STSR_AISS)))
+ return IRQ_HANDLED;
+
+ if (stsr & ADM8211_STSR_RCI)
+ adm8211_interrupt_rci(dev);
+ if (stsr & ADM8211_STSR_TCI)
+ adm8211_interrupt_tci(dev);
+
+ /*ADM8211_INT(LinkOn);*/
+ /*ADM8211_INT(LinkOff);*/
+
+ ADM8211_INT(PCF);
+ ADM8211_INT(BCNTC);
+ ADM8211_INT(GPINT);
+ ADM8211_INT(ATIMTC);
+ ADM8211_INT(TSFTF);
+ ADM8211_INT(TSCZ);
+ ADM8211_INT(SQL);
+ ADM8211_INT(WEPTD);
+ ADM8211_INT(ATIME);
+ /*ADM8211_INT(TBTT);*/
+ ADM8211_INT(TEIS);
+ ADM8211_INT(FBE);
+ ADM8211_INT(REIS);
+ ADM8211_INT(GPTT);
+ ADM8211_INT(RPS);
+ ADM8211_INT(RDU);
+ ADM8211_INT(TUF);
+ /*ADM8211_INT(TRT);*/
+ /*ADM8211_INT(TLT);*/
+ /*ADM8211_INT(TDU);*/
+ ADM8211_INT(TPS);
+
+ return IRQ_HANDLED;
+
+#undef ADM8211_INT
+}
+
+#define WRITE_SYN(name,v_mask,v_shift,a_mask,a_shift,bits,prewrite,postwrite)\
+static void adm8211_rf_write_syn_ ## name (struct ieee80211_hw *dev, \
+ u16 addr, u32 value) { \
+ struct adm8211_priv *priv = dev->priv; \
+ unsigned int i; \
+ u32 reg, bitbuf; \
+ \
+ value &= v_mask; \
+ addr &= a_mask; \
+ bitbuf = (value << v_shift) | (addr << a_shift); \
+ \
+ ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_IF_SELECT_1); \
+ ADM8211_CSR_READ(SYNRF); \
+ ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_IF_SELECT_0); \
+ ADM8211_CSR_READ(SYNRF); \
+ \
+ if (prewrite) { \
+ ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_WRITE_SYNDATA_0); \
+ ADM8211_CSR_READ(SYNRF); \
+ } \
+ \
+ for (i = 0; i <= bits; i++) { \
+ if (bitbuf & (1 << (bits - i))) \
+ reg = ADM8211_SYNRF_WRITE_SYNDATA_1; \
+ else \
+ reg = ADM8211_SYNRF_WRITE_SYNDATA_0; \
+ \
+ ADM8211_CSR_WRITE(SYNRF, reg); \
+ ADM8211_CSR_READ(SYNRF); \
+ \
+ ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_WRITE_CLOCK_1); \
+ ADM8211_CSR_READ(SYNRF); \
+ ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_WRITE_CLOCK_0); \
+ ADM8211_CSR_READ(SYNRF); \
+ } \
+ \
+ if (postwrite == 1) { \
+ ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_IF_SELECT_0); \
+ ADM8211_CSR_READ(SYNRF); \
+ } \
+ if (postwrite == 2) { \
+ ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_IF_SELECT_1); \
+ ADM8211_CSR_READ(SYNRF); \
+ } \
+ \
+ ADM8211_CSR_WRITE(SYNRF, 0); \
+ ADM8211_CSR_READ(SYNRF); \
+}
+
+WRITE_SYN(max2820, 0x00FFF, 0, 0x0F, 12, 15, 1, 1)
+WRITE_SYN(al2210l, 0xFFFFF, 4, 0x0F, 0, 23, 1, 1)
+WRITE_SYN(rfmd2958, 0x3FFFF, 0, 0x1F, 18, 23, 0, 1)
+WRITE_SYN(rfmd2948, 0x0FFFF, 4, 0x0F, 0, 21, 0, 2)
+
+#undef WRITE_SYN
+
+static int adm8211_write_bbp(struct ieee80211_hw *dev, u8 addr, u8 data)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int timeout;
+ u32 reg;
+
+ timeout = 10;
+ while (timeout > 0) {
+ reg = ADM8211_CSR_READ(BBPCTL);
+ if (!(reg & (ADM8211_BBPCTL_WR | ADM8211_BBPCTL_RD)))
+ break;
+ timeout--;
+ msleep(2);
+ }
+
+ if (timeout == 0) {
+ printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed"
+ " prewrite (reg=0x%08x)\n",
+ wiphy_name(dev->wiphy), addr, data, reg);
+ return -ETIMEDOUT;
+ }
+
+ switch (priv->bbp_type) {
+ case ADM8211_TYPE_INTERSIL:
+ reg = ADM8211_BBPCTL_MMISEL; /* three wire interface */
+ break;
+ case ADM8211_TYPE_RFMD:
+ reg = (0x20 << 24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP |
+ (0x01 << 18);
+ break;
+ case ADM8211_TYPE_ADMTEK:
+ reg = (0x20 << 24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP |
+ (0x05 << 18);
+ break;
+ }
+ reg |= ADM8211_BBPCTL_WR | (addr << 8) | data;
+
+ ADM8211_CSR_WRITE(BBPCTL, reg);
+
+ timeout = 10;
+ while (timeout > 0) {
+ reg = ADM8211_CSR_READ(BBPCTL);
+ if (!(reg & ADM8211_BBPCTL_WR))
+ break;
+ timeout--;
+ msleep(2);
+ }
+
+ if (timeout == 0) {
+ ADM8211_CSR_WRITE(BBPCTL, ADM8211_CSR_READ(BBPCTL) &
+ ~ADM8211_BBPCTL_WR);
+ printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed"
+ " postwrite (reg=0x%08x)\n",
+ wiphy_name(dev->wiphy), addr, data, reg);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan)
+{
+ static const u32 adm8211_rfmd2958_reg5[] =
+ {0x22BD, 0x22D2, 0x22E8, 0x22FE, 0x2314, 0x232A, 0x2340,
+ 0x2355, 0x236B, 0x2381, 0x2397, 0x23AD, 0x23C2, 0x23F7};
+ static const u32 adm8211_rfmd2958_reg6[] =
+ {0x05D17, 0x3A2E8, 0x2E8BA, 0x22E8B, 0x1745D, 0x0BA2E, 0x00000,
+ 0x345D1, 0x28BA2, 0x1D174, 0x11745, 0x05D17, 0x3A2E8, 0x11745};
+
+ struct adm8211_priv *priv = dev->priv;
+ u8 ant_power = priv->ant_power > 0x3F ?
+ priv->eeprom->antenna_power[chan - 1] : priv->ant_power;
+ u8 tx_power = priv->tx_power > 0x3F ?
+ priv->eeprom->tx_power[chan - 1] : priv->tx_power;
+ u8 lpf_cutoff = priv->lpf_cutoff == 0xFF ?
+ priv->eeprom->lpf_cutoff[chan - 1] : priv->lpf_cutoff;
+ u8 lnags_thresh = priv->lnags_threshold == 0xFF ?
+ priv->eeprom->lnags_threshold[chan - 1] : priv->lnags_threshold;
+ u32 reg;
+
+ ADM8211_IDLE();
+
+ /* Program synthesizer to new channel */
+ switch (priv->transceiver_type) {
+ case ADM8211_RFMD2958:
+ case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+ adm8211_rf_write_syn_rfmd2958(dev, 0x00, 0x04007);
+ adm8211_rf_write_syn_rfmd2958(dev, 0x02, 0x00033);
+
+ adm8211_rf_write_syn_rfmd2958(dev, 0x05,
+ adm8211_rfmd2958_reg5[chan - 1]);
+ adm8211_rf_write_syn_rfmd2958(dev, 0x06,
+ adm8211_rfmd2958_reg6[chan - 1]);
+ break;
+
+ case ADM8211_RFMD2948:
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_MAIN_CONF,
+ SI4126_MAIN_XINDIV2);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_POWERDOWN,
+ SI4126_POWERDOWN_PDIB |
+ SI4126_POWERDOWN_PDRB);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_PHASE_DET_GAIN, 0);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_N_DIV,
+ (chan == 14 ?
+ 2110 : (2033 + (chan * 5))));
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_N_DIV, 1496);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_R_DIV, 44);
+ adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_R_DIV, 44);
+ break;
+
+ case ADM8211_MAX2820:
+ adm8211_rf_write_syn_max2820(dev, 0x3,
+ (chan == 14 ? 0x054 : (0x7 + (chan * 5))));
+ break;
+
+ case ADM8211_AL2210L:
+ adm8211_rf_write_syn_al2210l(dev, 0x0,
+ (chan == 14 ? 0x229B4 : (0x22967 + (chan * 5))));
+ break;
+
+ default:
+ printk(KERN_DEBUG "%s: unsupported transceiver type %d\n",
+ wiphy_name(dev->wiphy), priv->transceiver_type);
+ break;
+ }
+
+ /* write BBP regs */
+ if (priv->bbp_type == ADM8211_TYPE_RFMD) {
+
+ /* SMC 2635W specific? adm8211b doesn't use the 2948 though.. */
+ /* TODO: remove if SMC 2635W doesn't need this */
+ if (priv->transceiver_type == ADM8211_RFMD2948) {
+ reg = ADM8211_CSR_READ(GPIO);
+ reg &= 0xfffc0000;
+ reg |= ADM8211_CSR_GPIO_EN0;
+ if (chan != 14)
+ reg |= ADM8211_CSR_GPIO_O0;
+ ADM8211_CSR_WRITE(GPIO, reg);
+ }
+
+ if (priv->transceiver_type == ADM8211_RFMD2958) {
+ /* set PCNT2 */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x0B, 0x07100);
+ /* set PCNT1 P_DESIRED/MID_BIAS */
+ reg = le16_to_cpu(priv->eeprom->cr49);
+ reg >>= 13;
+ reg <<= 15;
+ reg |= ant_power << 9;
+ adm8211_rf_write_syn_rfmd2958(dev, 0x0A, reg);
+ /* set TXRX TX_GAIN */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x09, 0x00050 |
+ (priv->pdev->revision < ADM8211_REV_CA ? tx_power : 0));
+ } else {
+ reg = ADM8211_CSR_READ(PLCPHD);
+ reg &= 0xff00ffff;
+ reg |= tx_power << 18;
+ ADM8211_CSR_WRITE(PLCPHD, reg);
+ }
+
+ ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_SELRF |
+ ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST);
+ ADM8211_CSR_READ(SYNRF);
+ msleep(30);
+
+ /* RF3000 BBP */
+ if (priv->transceiver_type != ADM8211_RFMD2958)
+ adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT,
+ tx_power<<2);
+ adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, lpf_cutoff);
+ adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, lnags_thresh);
+ adm8211_write_bbp(dev, 0x1c, priv->pdev->revision == ADM8211_REV_BA ?
+ priv->eeprom->cr28 : 0);
+ adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29);
+
+ ADM8211_CSR_WRITE(SYNRF, 0);
+
+ /* Nothing to do for ADMtek BBP */
+ } else if (priv->bbp_type != ADM8211_TYPE_ADMTEK)
+ printk(KERN_DEBUG "%s: unsupported BBP type %d\n",
+ wiphy_name(dev->wiphy), priv->bbp_type);
+
+ ADM8211_RESTORE();
+
+ /* update current channel for adhoc (and maybe AP mode) */
+ reg = ADM8211_CSR_READ(CAP0);
+ reg &= ~0xF;
+ reg |= chan;
+ ADM8211_CSR_WRITE(CAP0, reg);
+
+ return 0;
+}
+
+static void adm8211_update_mode(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ ADM8211_IDLE();
+
+ priv->soft_rx_crc = 0;
+ switch (priv->mode) {
+ case IEEE80211_IF_TYPE_STA:
+ priv->nar &= ~(ADM8211_NAR_PR | ADM8211_NAR_EA);
+ priv->nar |= ADM8211_NAR_ST | ADM8211_NAR_SR;
+ break;
+ case IEEE80211_IF_TYPE_IBSS:
+ priv->nar &= ~ADM8211_NAR_PR;
+ priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR;
+
+ /* don't trust the error bits on rev 0x20 and up in adhoc */
+ if (priv->pdev->revision >= ADM8211_REV_BA)
+ priv->soft_rx_crc = 1;
+ break;
+ case IEEE80211_IF_TYPE_MNTR:
+ priv->nar &= ~(ADM8211_NAR_EA | ADM8211_NAR_ST);
+ priv->nar |= ADM8211_NAR_PR | ADM8211_NAR_SR;
+ break;
+ }
+
+ ADM8211_RESTORE();
+}
+
+static void adm8211_hw_init_syn(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ switch (priv->transceiver_type) {
+ case ADM8211_RFMD2958:
+ case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+ /* comments taken from ADMtek vendor driver */
+
+ /* Reset RF2958 after power on */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x1F, 0x00000);
+ /* Initialize RF VCO Core Bias to maximum */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x0C, 0x3001F);
+ /* Initialize IF PLL */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x01, 0x29C03);
+ /* Initialize IF PLL Coarse Tuning */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x03, 0x1FF6F);
+ /* Initialize RF PLL */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x04, 0x29403);
+ /* Initialize RF PLL Coarse Tuning */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x07, 0x1456F);
+ /* Initialize TX gain and filter BW (R9) */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x09,
+ (priv->transceiver_type == ADM8211_RFMD2958 ?
+ 0x10050 : 0x00050));
+ /* Initialize CAL register */
+ adm8211_rf_write_syn_rfmd2958(dev, 0x08, 0x3FFF8);
+ break;
+
+ case ADM8211_MAX2820:
+ adm8211_rf_write_syn_max2820(dev, 0x1, 0x01E);
+ adm8211_rf_write_syn_max2820(dev, 0x2, 0x001);
+ adm8211_rf_write_syn_max2820(dev, 0x3, 0x054);
+ adm8211_rf_write_syn_max2820(dev, 0x4, 0x310);
+ adm8211_rf_write_syn_max2820(dev, 0x5, 0x000);
+ break;
+
+ case ADM8211_AL2210L:
+ adm8211_rf_write_syn_al2210l(dev, 0x0, 0x0196C);
+ adm8211_rf_write_syn_al2210l(dev, 0x1, 0x007CB);
+ adm8211_rf_write_syn_al2210l(dev, 0x2, 0x3582F);
+ adm8211_rf_write_syn_al2210l(dev, 0x3, 0x010A9);
+ adm8211_rf_write_syn_al2210l(dev, 0x4, 0x77280);
+ adm8211_rf_write_syn_al2210l(dev, 0x5, 0x45641);
+ adm8211_rf_write_syn_al2210l(dev, 0x6, 0xEA130);
+ adm8211_rf_write_syn_al2210l(dev, 0x7, 0x80000);
+ adm8211_rf_write_syn_al2210l(dev, 0x8, 0x7850F);
+ adm8211_rf_write_syn_al2210l(dev, 0x9, 0xF900C);
+ adm8211_rf_write_syn_al2210l(dev, 0xA, 0x00000);
+ adm8211_rf_write_syn_al2210l(dev, 0xB, 0x00000);
+ break;
+
+ case ADM8211_RFMD2948:
+ default:
+ break;
+ }
+}
+
+static int adm8211_hw_init_bbp(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg;
+
+ /* write addresses */
+ if (priv->bbp_type == ADM8211_TYPE_INTERSIL) {
+ ADM8211_CSR_WRITE(MMIWA, 0x100E0C0A);
+ ADM8211_CSR_WRITE(MMIRD0, 0x00007C7E);
+ ADM8211_CSR_WRITE(MMIRD1, 0x00100000);
+ } else if (priv->bbp_type == ADM8211_TYPE_RFMD ||
+ priv->bbp_type == ADM8211_TYPE_ADMTEK) {
+ /* check specific BBP type */
+ switch (priv->specific_bbptype) {
+ case ADM8211_BBP_RFMD3000:
+ case ADM8211_BBP_RFMD3002:
+ ADM8211_CSR_WRITE(MMIWA, 0x00009101);
+ ADM8211_CSR_WRITE(MMIRD0, 0x00000301);
+ break;
+
+ case ADM8211_BBP_ADM8011:
+ ADM8211_CSR_WRITE(MMIWA, 0x00008903);
+ ADM8211_CSR_WRITE(MMIRD0, 0x00001716);
+
+ reg = ADM8211_CSR_READ(BBPCTL);
+ reg &= ~ADM8211_BBPCTL_TYPE;
+ reg |= 0x5 << 18;
+ ADM8211_CSR_WRITE(BBPCTL, reg);
+ break;
+ }
+
+ switch (priv->pdev->revision) {
+ case ADM8211_REV_CA:
+ if (priv->transceiver_type == ADM8211_RFMD2958 ||
+ priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER ||
+ priv->transceiver_type == ADM8211_RFMD2948)
+ ADM8211_CSR_WRITE(SYNCTL, 0x1 << 22);
+ else if (priv->transceiver_type == ADM8211_MAX2820 ||
+ priv->transceiver_type == ADM8211_AL2210L)
+ ADM8211_CSR_WRITE(SYNCTL, 0x3 << 22);
+ break;
+
+ case ADM8211_REV_BA:
+ reg = ADM8211_CSR_READ(MMIRD1);
+ reg &= 0x0000FFFF;
+ reg |= 0x7e100000;
+ ADM8211_CSR_WRITE(MMIRD1, reg);
+ break;
+
+ case ADM8211_REV_AB:
+ case ADM8211_REV_AF:
+ default:
+ ADM8211_CSR_WRITE(MMIRD1, 0x7e100000);
+ break;
+ }
+
+ /* For RFMD */
+ ADM8211_CSR_WRITE(MACTEST, 0x800);
+ }
+
+ adm8211_hw_init_syn(dev);
+
+ /* Set RF Power control IF pin to PE1+PHYRST# */
+ ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_SELRF |
+ ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST);
+ ADM8211_CSR_READ(SYNRF);
+ msleep(20);
+
+ /* write BBP regs */
+ if (priv->bbp_type == ADM8211_TYPE_RFMD) {
+ /* RF3000 BBP */
+ /* another set:
+ * 11: c8
+ * 14: 14
+ * 15: 50 (chan 1..13; chan 14: d0)
+ * 1c: 00
+ * 1d: 84
+ */
+ adm8211_write_bbp(dev, RF3000_CCA_CTRL, 0x80);
+ /* antenna selection: diversity */
+ adm8211_write_bbp(dev, RF3000_DIVERSITY__RSSI, 0x80);
+ adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT, 0x74);
+ adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, 0x38);
+ adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, 0x40);
+
+ if (priv->eeprom->major_version < 2) {
+ adm8211_write_bbp(dev, 0x1c, 0x00);
+ adm8211_write_bbp(dev, 0x1d, 0x80);
+ } else {
+ if (priv->pdev->revision == ADM8211_REV_BA)
+ adm8211_write_bbp(dev, 0x1c, priv->eeprom->cr28);
+ else
+ adm8211_write_bbp(dev, 0x1c, 0x00);
+
+ adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29);
+ }
+ } else if (priv->bbp_type == ADM8211_TYPE_ADMTEK) {
+ /* reset baseband */
+ adm8211_write_bbp(dev, 0x00, 0xFF);
+ /* antenna selection: diversity */
+ adm8211_write_bbp(dev, 0x07, 0x0A);
+
+ /* TODO: find documentation for this */
+ switch (priv->transceiver_type) {
+ case ADM8211_RFMD2958:
+ case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+ adm8211_write_bbp(dev, 0x00, 0x00);
+ adm8211_write_bbp(dev, 0x01, 0x00);
+ adm8211_write_bbp(dev, 0x02, 0x00);
+ adm8211_write_bbp(dev, 0x03, 0x00);
+ adm8211_write_bbp(dev, 0x06, 0x0f);
+ adm8211_write_bbp(dev, 0x09, 0x00);
+ adm8211_write_bbp(dev, 0x0a, 0x00);
+ adm8211_write_bbp(dev, 0x0b, 0x00);
+ adm8211_write_bbp(dev, 0x0c, 0x00);
+ adm8211_write_bbp(dev, 0x0f, 0xAA);
+ adm8211_write_bbp(dev, 0x10, 0x8c);
+ adm8211_write_bbp(dev, 0x11, 0x43);
+ adm8211_write_bbp(dev, 0x18, 0x40);
+ adm8211_write_bbp(dev, 0x20, 0x23);
+ adm8211_write_bbp(dev, 0x21, 0x02);
+ adm8211_write_bbp(dev, 0x22, 0x28);
+ adm8211_write_bbp(dev, 0x23, 0x30);
+ adm8211_write_bbp(dev, 0x24, 0x2d);
+ adm8211_write_bbp(dev, 0x28, 0x35);
+ adm8211_write_bbp(dev, 0x2a, 0x8c);
+ adm8211_write_bbp(dev, 0x2b, 0x81);
+ adm8211_write_bbp(dev, 0x2c, 0x44);
+ adm8211_write_bbp(dev, 0x2d, 0x0A);
+ adm8211_write_bbp(dev, 0x29, 0x40);
+ adm8211_write_bbp(dev, 0x60, 0x08);
+ adm8211_write_bbp(dev, 0x64, 0x01);
+ break;
+
+ case ADM8211_MAX2820:
+ adm8211_write_bbp(dev, 0x00, 0x00);
+ adm8211_write_bbp(dev, 0x01, 0x00);
+ adm8211_write_bbp(dev, 0x02, 0x00);
+ adm8211_write_bbp(dev, 0x03, 0x00);
+ adm8211_write_bbp(dev, 0x06, 0x0f);
+ adm8211_write_bbp(dev, 0x09, 0x05);
+ adm8211_write_bbp(dev, 0x0a, 0x02);
+ adm8211_write_bbp(dev, 0x0b, 0x00);
+ adm8211_write_bbp(dev, 0x0c, 0x0f);
+ adm8211_write_bbp(dev, 0x0f, 0x55);
+ adm8211_write_bbp(dev, 0x10, 0x8d);
+ adm8211_write_bbp(dev, 0x11, 0x43);
+ adm8211_write_bbp(dev, 0x18, 0x4a);
+ adm8211_write_bbp(dev, 0x20, 0x20);
+ adm8211_write_bbp(dev, 0x21, 0x02);
+ adm8211_write_bbp(dev, 0x22, 0x23);
+ adm8211_write_bbp(dev, 0x23, 0x30);
+ adm8211_write_bbp(dev, 0x24, 0x2d);
+ adm8211_write_bbp(dev, 0x2a, 0x8c);
+ adm8211_write_bbp(dev, 0x2b, 0x81);
+ adm8211_write_bbp(dev, 0x2c, 0x44);
+ adm8211_write_bbp(dev, 0x29, 0x4a);
+ adm8211_write_bbp(dev, 0x60, 0x2b);
+ adm8211_write_bbp(dev, 0x64, 0x01);
+ break;
+
+ case ADM8211_AL2210L:
+ adm8211_write_bbp(dev, 0x00, 0x00);
+ adm8211_write_bbp(dev, 0x01, 0x00);
+ adm8211_write_bbp(dev, 0x02, 0x00);
+ adm8211_write_bbp(dev, 0x03, 0x00);
+ adm8211_write_bbp(dev, 0x06, 0x0f);
+ adm8211_write_bbp(dev, 0x07, 0x05);
+ adm8211_write_bbp(dev, 0x08, 0x03);
+ adm8211_write_bbp(dev, 0x09, 0x00);
+ adm8211_write_bbp(dev, 0x0a, 0x00);
+ adm8211_write_bbp(dev, 0x0b, 0x00);
+ adm8211_write_bbp(dev, 0x0c, 0x10);
+ adm8211_write_bbp(dev, 0x0f, 0x55);
+ adm8211_write_bbp(dev, 0x10, 0x8d);
+ adm8211_write_bbp(dev, 0x11, 0x43);
+ adm8211_write_bbp(dev, 0x18, 0x4a);
+ adm8211_write_bbp(dev, 0x20, 0x20);
+ adm8211_write_bbp(dev, 0x21, 0x02);
+ adm8211_write_bbp(dev, 0x22, 0x23);
+ adm8211_write_bbp(dev, 0x23, 0x30);
+ adm8211_write_bbp(dev, 0x24, 0x2d);
+ adm8211_write_bbp(dev, 0x2a, 0xaa);
+ adm8211_write_bbp(dev, 0x2b, 0x81);
+ adm8211_write_bbp(dev, 0x2c, 0x44);
+ adm8211_write_bbp(dev, 0x29, 0xfa);
+ adm8211_write_bbp(dev, 0x60, 0x2d);
+ adm8211_write_bbp(dev, 0x64, 0x01);
+ break;
+
+ case ADM8211_RFMD2948:
+ break;
+
+ default:
+ printk(KERN_DEBUG "%s: unsupported transceiver %d\n",
+ wiphy_name(dev->wiphy), priv->transceiver_type);
+ break;
+ }
+ } else
+ printk(KERN_DEBUG "%s: unsupported BBP %d\n",
+ wiphy_name(dev->wiphy), priv->bbp_type);
+
+ ADM8211_CSR_WRITE(SYNRF, 0);
+
+ /* Set RF CAL control source to MAC control */
+ reg = ADM8211_CSR_READ(SYNCTL);
+ reg |= ADM8211_SYNCTL_SELCAL;
+ ADM8211_CSR_WRITE(SYNCTL, reg);
+
+ return 0;
+}
+
+/* configures hw beacons/probe responses */
+static int adm8211_set_rate(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg;
+ int i = 0;
+ u8 rate_buf[12] = {0};
+
+ /* write supported rates */
+ if (priv->pdev->revision != ADM8211_REV_BA) {
+ rate_buf[0] = ARRAY_SIZE(adm8211_rates);
+ for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++)
+ rate_buf[i + 1] = (adm8211_rates[i].rate / 5) | 0x80;
+ } else {
+ /* workaround for rev BA specific bug */
+ rate_buf[0] = 0x04;
+ rate_buf[1] = 0x82;
+ rate_buf[2] = 0x04;
+ rate_buf[3] = 0x0b;
+ rate_buf[4] = 0x16;
+ }
+
+ adm8211_write_sram_bytes(dev, ADM8211_SRAM_SUPP_RATE, rate_buf,
+ ARRAY_SIZE(adm8211_rates) + 1);
+
+ reg = ADM8211_CSR_READ(PLCPHD) & 0x00FFFFFF; /* keep bits 0-23 */
+ reg |= 1 << 15; /* short preamble */
+ reg |= 110 << 24;
+ ADM8211_CSR_WRITE(PLCPHD, reg);
+
+ /* MTMLT = 512 TU (max TX MSDU lifetime)
+ * BCNTSIG = plcp_signal (beacon, probe resp, and atim TX rate)
+ * SRTYLIM = 224 (short retry limit, TX header value is default) */
+ ADM8211_CSR_WRITE(TXLMT, (512 << 16) | (110 << 8) | (224 << 0));
+
+ return 0;
+}
+
+static void adm8211_hw_init(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg;
+ u8 cline;
+
+ reg = le32_to_cpu(ADM8211_CSR_READ(PAR));
+ reg |= ADM8211_PAR_MRLE | ADM8211_PAR_MRME;
+ reg &= ~(ADM8211_PAR_BAR | ADM8211_PAR_CAL);
+
+ if (!pci_set_mwi(priv->pdev)) {
+ reg |= 0x1 << 24;
+ pci_read_config_byte(priv->pdev, PCI_CACHE_LINE_SIZE, &cline);
+
+ switch (cline) {
+ case 0x8: reg |= (0x1 << 14);
+ break;
+ case 0x16: reg |= (0x2 << 14);
+ break;
+ case 0x32: reg |= (0x3 << 14);
+ break;
+ default: reg |= (0x0 << 14);
+ break;
+ }
+ }
+
+ ADM8211_CSR_WRITE(PAR, reg);
+
+ reg = ADM8211_CSR_READ(CSR_TEST1);
+ reg &= ~(0xF << 28);
+ reg |= (1 << 28) | (1 << 31);
+ ADM8211_CSR_WRITE(CSR_TEST1, reg);
+
+ /* lose link after 4 lost beacons */
+ reg = (0x04 << 21) | ADM8211_WCSR_TSFTWE | ADM8211_WCSR_LSOE;
+ ADM8211_CSR_WRITE(WCSR, reg);
+
+ /* Disable APM, enable receive FIFO threshold, and set drain receive
+ * threshold to store-and-forward */
+ reg = ADM8211_CSR_READ(CMDR);
+ reg &= ~(ADM8211_CMDR_APM | ADM8211_CMDR_DRT);
+ reg |= ADM8211_CMDR_RTE | ADM8211_CMDR_DRT_SF;
+ ADM8211_CSR_WRITE(CMDR, reg);
+
+ adm8211_set_rate(dev);
+
+ /* 4-bit values:
+ * PWR1UP = 8 * 2 ms
+ * PWR0PAPE = 8 us or 5 us
+ * PWR1PAPE = 1 us or 3 us
+ * PWR0TRSW = 5 us
+ * PWR1TRSW = 12 us
+ * PWR0PE2 = 13 us
+ * PWR1PE2 = 1 us
+ * PWR0TXPE = 8 or 6 */
+ if (priv->pdev->revision < ADM8211_REV_CA)
+ ADM8211_CSR_WRITE(TOFS2, 0x8815cd18);
+ else
+ ADM8211_CSR_WRITE(TOFS2, 0x8535cd16);
+
+ /* Enable store and forward for transmit */
+ priv->nar = ADM8211_NAR_SF | ADM8211_NAR_PB;
+ ADM8211_CSR_WRITE(NAR, priv->nar);
+
+ /* Reset RF */
+ ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_RADIO);
+ ADM8211_CSR_READ(SYNRF);
+ msleep(10);
+ ADM8211_CSR_WRITE(SYNRF, 0);
+ ADM8211_CSR_READ(SYNRF);
+ msleep(5);
+
+ /* Set CFP Max Duration to 0x10 TU */
+ reg = ADM8211_CSR_READ(CFPP);
+ reg &= ~(0xffff << 8);
+ reg |= 0x0010 << 8;
+ ADM8211_CSR_WRITE(CFPP, reg);
+
+ /* USCNT = 0x16 (number of system clocks, 22 MHz, in 1us
+ * TUCNT = 0x3ff - Tu counter 1024 us */
+ ADM8211_CSR_WRITE(TOFS0, (0x16 << 24) | 0x3ff);
+
+ /* SLOT=20 us, SIFS=110 cycles of 22 MHz (5 us),
+ * DIFS=50 us, EIFS=100 us */
+ if (priv->pdev->revision < ADM8211_REV_CA)
+ ADM8211_CSR_WRITE(IFST, (20 << 23) | (110 << 15) |
+ (50 << 9) | 100);
+ else
+ ADM8211_CSR_WRITE(IFST, (20 << 23) | (24 << 15) |
+ (50 << 9) | 100);
+
+ /* PCNT = 1 (MAC idle time awake/sleep, unit S)
+ * RMRD = 2346 * 8 + 1 us (max RX duration) */
+ ADM8211_CSR_WRITE(RMD, (1 << 16) | 18769);
+
+ /* MART=65535 us, MIRT=256 us, TSFTOFST=0 us */
+ ADM8211_CSR_WRITE(RSPT, 0xffffff00);
+
+ /* Initialize BBP (and SYN) */
+ adm8211_hw_init_bbp(dev);
+
+ /* make sure interrupts are off */
+ ADM8211_CSR_WRITE(IER, 0);
+
+ /* ACK interrupts */
+ ADM8211_CSR_WRITE(STSR, ADM8211_CSR_READ(STSR));
+
+ /* Setup WEP (turns it off for now) */
+ reg = ADM8211_CSR_READ(MACTEST);
+ reg &= ~(7 << 20);
+ ADM8211_CSR_WRITE(MACTEST, reg);
+
+ reg = ADM8211_CSR_READ(WEPCTL);
+ reg &= ~ADM8211_WEPCTL_WEPENABLE;
+ reg |= ADM8211_WEPCTL_WEPRXBYP;
+ ADM8211_CSR_WRITE(WEPCTL, reg);
+
+ /* Clear the missed-packet counter. */
+ ADM8211_CSR_READ(LPC);
+}
+
+static int adm8211_hw_reset(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg, tmp;
+ int timeout = 100;
+
+ /* Power-on issue */
+ /* TODO: check if this is necessary */
+ ADM8211_CSR_WRITE(FRCTL, 0);
+
+ /* Reset the chip */
+ tmp = ADM8211_CSR_READ(PAR);
+ ADM8211_CSR_WRITE(PAR, ADM8211_PAR_SWR);
+
+ while ((ADM8211_CSR_READ(PAR) & ADM8211_PAR_SWR) && timeout--)
+ msleep(50);
+
+ if (timeout <= 0)
+ return -ETIMEDOUT;
+
+ ADM8211_CSR_WRITE(PAR, tmp);
+
+ if (priv->pdev->revision == ADM8211_REV_BA &&
+ (priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER ||
+ priv->transceiver_type == ADM8211_RFMD2958)) {
+ reg = ADM8211_CSR_READ(CSR_TEST1);
+ reg |= (1 << 4) | (1 << 5);
+ ADM8211_CSR_WRITE(CSR_TEST1, reg);
+ } else if (priv->pdev->revision == ADM8211_REV_CA) {
+ reg = ADM8211_CSR_READ(CSR_TEST1);
+ reg &= ~((1 << 4) | (1 << 5));
+ ADM8211_CSR_WRITE(CSR_TEST1, reg);
+ }
+
+ ADM8211_CSR_WRITE(FRCTL, 0);
+
+ reg = ADM8211_CSR_READ(CSR_TEST0);
+ reg |= ADM8211_CSR_TEST0_EPRLD; /* EEPROM Recall */
+ ADM8211_CSR_WRITE(CSR_TEST0, reg);
+
+ adm8211_clear_sram(dev);
+
+ return 0;
+}
+
+static u64 adm8211_get_tsft(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 tsftl;
+ u64 tsft;
+
+ tsftl = ADM8211_CSR_READ(TSFTL);
+ tsft = ADM8211_CSR_READ(TSFTH);
+ tsft <<= 32;
+ tsft |= tsftl;
+
+ return tsft;
+}
+
+static void adm8211_set_interval(struct ieee80211_hw *dev,
+ unsigned short bi, unsigned short li)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg;
+
+ /* BP (beacon interval) = data->beacon_interval
+ * LI (listen interval) = data->listen_interval (in beacon intervals) */
+ reg = (bi << 16) | li;
+ ADM8211_CSR_WRITE(BPLI, reg);
+}
+
+static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u32 reg;
+
+ ADM8211_CSR_WRITE(BSSID0, le32_to_cpu(*(__le32 *)bssid));
+ reg = ADM8211_CSR_READ(ABDA1);
+ reg &= 0x0000ffff;
+ reg |= (bssid[4] << 16) | (bssid[5] << 24);
+ ADM8211_CSR_WRITE(ABDA1, reg);
+}
+
+static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len)
+{
+ struct adm8211_priv *priv = dev->priv;
+ u8 buf[36];
+
+ if (ssid_len > 32)
+ return -EINVAL;
+
+ memset(buf, 0, sizeof(buf));
+ buf[0] = ssid_len;
+ memcpy(buf + 1, ssid, ssid_len);
+ adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33);
+ /* TODO: configure beacon for adhoc? */
+ return 0;
+}
+
+static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ if (conf->channel != priv->channel) {
+ priv->channel = conf->channel;
+ adm8211_rf_set_channel(dev, priv->channel);
+ }
+
+ return 0;
+}
+
+static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) {
+ adm8211_set_bssid(dev, conf->bssid);
+ memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+ }
+
+ if (conf->ssid_len != priv->ssid_len ||
+ memcmp(conf->ssid, priv->ssid, conf->ssid_len)) {
+ adm8211_set_ssid(dev, conf->ssid, conf->ssid_len);
+ priv->ssid_len = conf->ssid_len;
+ memcpy(priv->ssid, conf->ssid, conf->ssid_len);
+ }
+
+ return 0;
+}
+
+static void adm8211_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_mc_list *mclist)
+{
+ static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int bit_nr, new_flags;
+ u32 mc_filter[2];
+ int i;
+
+ new_flags = 0;
+
+ if (*total_flags & FIF_PROMISC_IN_BSS) {
+ new_flags |= FIF_PROMISC_IN_BSS;
+ priv->nar |= ADM8211_NAR_PR;
+ priv->nar &= ~ADM8211_NAR_MM;
+ mc_filter[1] = mc_filter[0] = ~0;
+ } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
+ new_flags |= FIF_ALLMULTI;
+ priv->nar &= ~ADM8211_NAR_PR;
+ priv->nar |= ADM8211_NAR_MM;
+ mc_filter[1] = mc_filter[0] = ~0;
+ } else {
+ priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0; i < mc_count; i++) {
+ if (!mclist)
+ break;
+ bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+ bit_nr &= 0x3F;
+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+ mclist = mclist->next;
+ }
+ }
+
+ ADM8211_IDLE_RX();
+
+ ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
+ ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
+ ADM8211_CSR_READ(NAR);
+
+ if (priv->nar & ADM8211_NAR_PR)
+ dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
+ else
+ dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+
+ if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ adm8211_set_bssid(dev, bcast);
+ else
+ adm8211_set_bssid(dev, priv->bssid);
+
+ ADM8211_RESTORE();
+
+ *total_flags = new_flags;
+}
+
+static int adm8211_add_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct adm8211_priv *priv = dev->priv;
+ if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+ return -EOPNOTSUPP;
+
+ switch (conf->type) {
+ case IEEE80211_IF_TYPE_STA:
+ priv->mode = conf->type;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ ADM8211_IDLE();
+
+ ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)conf->mac_addr));
+ ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(conf->mac_addr + 4)));
+
+ adm8211_update_mode(dev);
+
+ ADM8211_RESTORE();
+
+ return 0;
+}
+
+static void adm8211_remove_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct adm8211_priv *priv = dev->priv;
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
+}
+
+static int adm8211_init_rings(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ struct adm8211_desc *desc = NULL;
+ struct adm8211_rx_ring_info *rx_info;
+ struct adm8211_tx_ring_info *tx_info;
+ unsigned int i;
+
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ desc = &priv->rx_ring[i];
+ desc->status = 0;
+ desc->length = cpu_to_le32(RX_PKT_SIZE);
+ priv->rx_buffers[i].skb = NULL;
+ }
+ /* Mark the end of RX ring; hw returns to base address after this
+ * descriptor */
+ desc->length |= cpu_to_le32(RDES1_CONTROL_RER);
+
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ desc = &priv->rx_ring[i];
+ rx_info = &priv->rx_buffers[i];
+
+ rx_info->skb = dev_alloc_skb(RX_PKT_SIZE);
+ if (rx_info->skb == NULL)
+ break;
+ rx_info->mapping = pci_map_single(priv->pdev,
+ skb_tail_pointer(rx_info->skb),
+ RX_PKT_SIZE,
+ PCI_DMA_FROMDEVICE);
+ desc->buffer1 = cpu_to_le32(rx_info->mapping);
+ desc->status = cpu_to_le32(RDES0_STATUS_OWN | RDES0_STATUS_SQL);
+ }
+
+ /* Setup TX ring. TX buffers descriptors will be filled in as needed */
+ for (i = 0; i < priv->tx_ring_size; i++) {
+ desc = &priv->tx_ring[i];
+ tx_info = &priv->tx_buffers[i];
+
+ tx_info->skb = NULL;
+ tx_info->mapping = 0;
+ desc->status = 0;
+ }
+ desc->length = cpu_to_le32(TDES1_CONTROL_TER);
+
+ priv->cur_rx = priv->cur_tx = priv->dirty_tx = 0;
+ ADM8211_CSR_WRITE(RDB, priv->rx_ring_dma);
+ ADM8211_CSR_WRITE(TDBD, priv->tx_ring_dma);
+
+ return 0;
+}
+
+static void adm8211_free_rings(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int i;
+
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ if (!priv->rx_buffers[i].skb)
+ continue;
+
+ pci_unmap_single(
+ priv->pdev,
+ priv->rx_buffers[i].mapping,
+ RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+
+ dev_kfree_skb(priv->rx_buffers[i].skb);
+ }
+
+ for (i = 0; i < priv->tx_ring_size; i++) {
+ if (!priv->tx_buffers[i].skb)
+ continue;
+
+ pci_unmap_single(priv->pdev,
+ priv->tx_buffers[i].mapping,
+ priv->tx_buffers[i].skb->len,
+ PCI_DMA_TODEVICE);
+
+ dev_kfree_skb(priv->tx_buffers[i].skb);
+ }
+}
+
+static int adm8211_start(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ int retval;
+
+ /* Power up MAC and RF chips */
+ retval = adm8211_hw_reset(dev);
+ if (retval) {
+ printk(KERN_ERR "%s: hardware reset failed\n",
+ wiphy_name(dev->wiphy));
+ goto fail;
+ }
+
+ retval = adm8211_init_rings(dev);
+ if (retval) {
+ printk(KERN_ERR "%s: failed to initialize rings\n",
+ wiphy_name(dev->wiphy));
+ goto fail;
+ }
+
+ /* Init hardware */
+ adm8211_hw_init(dev);
+ adm8211_rf_set_channel(dev, priv->channel);
+
+ retval = request_irq(priv->pdev->irq, &adm8211_interrupt,
+ IRQF_SHARED, "adm8211", dev);
+ if (retval) {
+ printk(KERN_ERR "%s: failed to register IRQ handler\n",
+ wiphy_name(dev->wiphy));
+ goto fail;
+ }
+
+ ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE |
+ ADM8211_IER_RCIE | ADM8211_IER_TCIE |
+ ADM8211_IER_TDUIE | ADM8211_IER_GPTIE);
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
+ adm8211_update_mode(dev);
+ ADM8211_CSR_WRITE(RDR, 0);
+
+ adm8211_set_interval(dev, 100, 10);
+ return 0;
+
+fail:
+ return retval;
+}
+
+static void adm8211_stop(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+
+ priv->mode = IEEE80211_IF_TYPE_INVALID;
+ priv->nar = 0;
+ ADM8211_CSR_WRITE(NAR, 0);
+ ADM8211_CSR_WRITE(IER, 0);
+ ADM8211_CSR_READ(NAR);
+
+ free_irq(priv->pdev->irq, dev);
+
+ adm8211_free_rings(dev);
+}
+
+static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int len,
+ int plcp_signal, int short_preamble)
+{
+ /* Alternative calculation from NetBSD: */
+
+/* IEEE 802.11b durations for DSSS PHY in microseconds */
+#define IEEE80211_DUR_DS_LONG_PREAMBLE 144
+#define IEEE80211_DUR_DS_SHORT_PREAMBLE 72
+#define IEEE80211_DUR_DS_FAST_PLCPHDR 24
+#define IEEE80211_DUR_DS_SLOW_PLCPHDR 48
+#define IEEE80211_DUR_DS_SLOW_ACK 112
+#define IEEE80211_DUR_DS_FAST_ACK 56
+#define IEEE80211_DUR_DS_SLOW_CTS 112
+#define IEEE80211_DUR_DS_FAST_CTS 56
+#define IEEE80211_DUR_DS_SLOT 20
+#define IEEE80211_DUR_DS_SIFS 10
+
+ int remainder;
+
+ *dur = (80 * (24 + payload_len) + plcp_signal - 1)
+ / plcp_signal;
+
+ if (plcp_signal <= PLCP_SIGNAL_2M)
+ /* 1-2Mbps WLAN: send ACK/CTS at 1Mbps */
+ *dur += 3 * (IEEE80211_DUR_DS_SIFS +
+ IEEE80211_DUR_DS_SHORT_PREAMBLE +
+ IEEE80211_DUR_DS_FAST_PLCPHDR) +
+ IEEE80211_DUR_DS_SLOW_CTS + IEEE80211_DUR_DS_SLOW_ACK;
+ else
+ /* 5-11Mbps WLAN: send ACK/CTS at 2Mbps */
+ *dur += 3 * (IEEE80211_DUR_DS_SIFS +
+ IEEE80211_DUR_DS_SHORT_PREAMBLE +
+ IEEE80211_DUR_DS_FAST_PLCPHDR) +
+ IEEE80211_DUR_DS_FAST_CTS + IEEE80211_DUR_DS_FAST_ACK;
+
+ /* lengthen duration if long preamble */
+ if (!short_preamble)
+ *dur += 3 * (IEEE80211_DUR_DS_LONG_PREAMBLE -
+ IEEE80211_DUR_DS_SHORT_PREAMBLE) +
+ 3 * (IEEE80211_DUR_DS_SLOW_PLCPHDR -
+ IEEE80211_DUR_DS_FAST_PLCPHDR);
+
+
+ *plcp = (80 * len) / plcp_signal;
+ remainder = (80 * len) % plcp_signal;
+ if (plcp_signal == PLCP_SIGNAL_11M &&
+ remainder <= 30 && remainder > 0)
+ *plcp = (*plcp | 0x8000) + 1;
+ else if (remainder)
+ (*plcp)++;
+}
+
+/* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */
+static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
+ u16 plcp_signal,
+ struct ieee80211_tx_control *control,
+ size_t hdrlen)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned long flags;
+ dma_addr_t mapping;
+ unsigned int entry;
+ u32 flag;
+
+ mapping = pci_map_single(priv->pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size / 2)
+ flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+ else
+ flag = TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+
+ if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size - 2)
+ ieee80211_stop_queue(dev, 0);
+
+ entry = priv->cur_tx % priv->tx_ring_size;
+
+ priv->tx_buffers[entry].skb = skb;
+ priv->tx_buffers[entry].mapping = mapping;
+ memcpy(&priv->tx_buffers[entry].tx_control, control, sizeof(*control));
+ priv->tx_buffers[entry].hdrlen = hdrlen;
+ priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping);
+
+ if (entry == priv->tx_ring_size - 1)
+ flag |= TDES1_CONTROL_TER;
+ priv->tx_ring[entry].length = cpu_to_le32(flag | skb->len);
+
+ /* Set TX rate (SIGNAL field in PLCP PPDU format) */
+ flag = TDES0_CONTROL_OWN | (plcp_signal << 20) | 8 /* ? */;
+ priv->tx_ring[entry].status = cpu_to_le32(flag);
+
+ priv->cur_tx++;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Trigger transmit poll */
+ ADM8211_CSR_WRITE(TDR, 0);
+}
+
+/* Put adm8211_tx_hdr on skb and transmit */
+static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct adm8211_tx_hdr *txhdr;
+ u16 fc;
+ size_t payload_len, hdrlen;
+ int plcp, dur, len, plcp_signal, short_preamble;
+ struct ieee80211_hdr *hdr;
+
+ if (control->tx_rate < 0) {
+ short_preamble = 1;
+ plcp_signal = -control->tx_rate;
+ } else {
+ short_preamble = 0;
+ plcp_signal = control->tx_rate;
+ }
+
+ hdr = (struct ieee80211_hdr *)skb->data;
+ fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED;
+ hdrlen = ieee80211_get_hdrlen(fc);
+ memcpy(skb->cb, skb->data, hdrlen);
+ hdr = (struct ieee80211_hdr *)skb->cb;
+ skb_pull(skb, hdrlen);
+ payload_len = skb->len;
+
+ txhdr = (struct adm8211_tx_hdr *) skb_push(skb, sizeof(*txhdr));
+ memset(txhdr, 0, sizeof(*txhdr));
+ memcpy(txhdr->da, ieee80211_get_DA(hdr), ETH_ALEN);
+ txhdr->signal = plcp_signal;
+ txhdr->frame_body_size = cpu_to_le16(payload_len);
+ txhdr->frame_control = hdr->frame_control;
+
+ len = hdrlen + payload_len + FCS_LEN;
+ if (fc & IEEE80211_FCTL_PROTECTED)
+ len += 8;
+
+ txhdr->frag = cpu_to_le16(0x0FFF);
+ adm8211_calc_durations(&dur, &plcp, payload_len,
+ len, plcp_signal, short_preamble);
+ txhdr->plcp_frag_head_len = cpu_to_le16(plcp);
+ txhdr->plcp_frag_tail_len = cpu_to_le16(plcp);
+ txhdr->dur_frag_head = cpu_to_le16(dur);
+ txhdr->dur_frag_tail = cpu_to_le16(dur);
+
+ txhdr->header_control = cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER);
+
+ if (short_preamble)
+ txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);
+
+ if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
+
+ if (fc & IEEE80211_FCTL_PROTECTED)
+ txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);
+
+ txhdr->retry_limit = control->retry_limit;
+
+ adm8211_tx_raw(dev, skb, plcp_signal, control, hdrlen);
+
+ return NETDEV_TX_OK;
+}
+
+static int adm8211_alloc_rings(struct ieee80211_hw *dev)
+{
+ struct adm8211_priv *priv = dev->priv;
+ unsigned int ring_size;
+
+ priv->rx_buffers = kmalloc(sizeof(*priv->rx_buffers) * priv->rx_ring_size +
+ sizeof(*priv->tx_buffers) * priv->tx_ring_size, GFP_KERNEL);
+ if (!priv->rx_buffers)
+ return -ENOMEM;
+
+ priv->tx_buffers = (void *)priv->rx_buffers +
+ sizeof(*priv->rx_buffers) * priv->rx_ring_size;
+
+ /* Allocate TX/RX descriptors */
+ ring_size = sizeof(struct adm8211_desc) * priv->rx_ring_size +
+ sizeof(struct adm8211_desc) * priv->tx_ring_size;
+ priv->rx_ring = pci_alloc_consistent(priv->pdev, ring_size,
+ &priv->rx_ring_dma);
+
+ if (!priv->rx_ring) {
+ kfree(priv->rx_buffers);
+ priv->rx_buffers = NULL;
+ priv->tx_buffers = NULL;
+ return -ENOMEM;
+ }
+
+ priv->tx_ring = (struct adm8211_desc *)(priv->rx_ring +
+ priv->rx_ring_size);
+ priv->tx_ring_dma = priv->rx_ring_dma +
+ sizeof(struct adm8211_desc) * priv->rx_ring_size;
+
+ return 0;
+}
+
+static const struct ieee80211_ops adm8211_ops = {
+ .tx = adm8211_tx,
+ .start = adm8211_start,
+ .stop = adm8211_stop,
+ .add_interface = adm8211_add_interface,
+ .remove_interface = adm8211_remove_interface,
+ .config = adm8211_config,
+ .config_interface = adm8211_config_interface,
+ .configure_filter = adm8211_configure_filter,
+ .get_stats = adm8211_get_stats,
+ .get_tx_stats = adm8211_get_tx_stats,
+ .get_tsf = adm8211_get_tsft
+};
+
+static int __devinit adm8211_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct ieee80211_hw *dev;
+ struct adm8211_priv *priv;
+ unsigned long mem_addr, mem_len;
+ unsigned int io_addr, io_len;
+ int err;
+ u32 reg;
+ u8 perm_addr[ETH_ALEN];
+ DECLARE_MAC_BUF(mac);
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Cannot enable new PCI device\n",
+ pci_name(pdev));
+ return err;
+ }
+
+ io_addr = pci_resource_start(pdev, 0);
+ io_len = pci_resource_len(pdev, 0);
+ mem_addr = pci_resource_start(pdev, 1);
+ mem_len = pci_resource_len(pdev, 1);
+ if (io_len < 256 || mem_len < 1024) {
+ printk(KERN_ERR "%s (adm8211): Too short PCI resources\n",
+ pci_name(pdev));
+ goto err_disable_pdev;
+ }
+
+
+ /* check signature */
+ pci_read_config_dword(pdev, 0x80 /* CR32 */, &reg);
+ if (reg != ADM8211_SIG1 && reg != ADM8211_SIG2) {
+ printk(KERN_ERR "%s (adm8211): Invalid signature (0x%x)\n",
+ pci_name(pdev), reg);
+ goto err_disable_pdev;
+ }
+
+ err = pci_request_regions(pdev, "adm8211");
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Cannot obtain PCI resources\n",
+ pci_name(pdev));
+ return err; /* someone else grabbed it? don't disable it */
+ }
+
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
+ pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+ printk(KERN_ERR "%s (adm8211): No suitable DMA available\n",
+ pci_name(pdev));
+ goto err_free_reg;
+ }
+
+ pci_set_master(pdev);
+
+ dev = ieee80211_alloc_hw(sizeof(*priv), &adm8211_ops);
+ if (!dev) {
+ printk(KERN_ERR "%s (adm8211): ieee80211 alloc failed\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto err_free_reg;
+ }
+ priv = dev->priv;
+ priv->pdev = pdev;
+
+ spin_lock_init(&priv->lock);
+
+ SET_IEEE80211_DEV(dev, &pdev->dev);
+
+ pci_set_drvdata(pdev, dev);
+
+ priv->map = pci_iomap(pdev, 1, mem_len);
+ if (!priv->map)
+ priv->map = pci_iomap(pdev, 0, io_len);
+
+ if (!priv->map) {
+ printk(KERN_ERR "%s (adm8211): Cannot map device memory\n",
+ pci_name(pdev));
+ goto err_free_dev;
+ }
+
+ priv->rx_ring_size = rx_ring_size;
+ priv->tx_ring_size = tx_ring_size;
+
+ if (adm8211_alloc_rings(dev)) {
+ printk(KERN_ERR "%s (adm8211): Cannot allocate TX/RX ring\n",
+ pci_name(pdev));
+ goto err_iounmap;
+ }
+
+ *(u32 *)perm_addr = le32_to_cpu((__force __le32)ADM8211_CSR_READ(PAR0));
+ *(u16 *)&perm_addr[4] =
+ le16_to_cpu((__force __le16)ADM8211_CSR_READ(PAR1) & 0xFFFF);
+
+ if (!is_valid_ether_addr(perm_addr)) {
+ printk(KERN_WARNING "%s (adm8211): Invalid hwaddr in EEPROM!\n",
+ pci_name(pdev));
+ random_ether_addr(perm_addr);
+ }
+ SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+
+ dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
+ dev->flags = IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED;
+ /* IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
+
+ dev->channel_change_time = 1000;
+ dev->max_rssi = 100; /* FIXME: find better value */
+
+ priv->modes[0].mode = MODE_IEEE80211B;
+ /* channel info filled in by adm8211_read_eeprom */
+ memcpy(priv->rates, adm8211_rates, sizeof(adm8211_rates));
+ priv->modes[0].num_rates = ARRAY_SIZE(adm8211_rates);
+ priv->modes[0].rates = priv->rates;
+
+ dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */
+
+ priv->retry_limit = 3;
+ priv->ant_power = 0x40;
+ priv->tx_power = 0x40;
+ priv->lpf_cutoff = 0xFF;
+ priv->lnags_threshold = 0xFF;
+ priv->mode = IEEE80211_IF_TYPE_INVALID;
+
+ /* Power-on issue. EEPROM won't read correctly without */
+ if (pdev->revision >= ADM8211_REV_BA) {
+ ADM8211_CSR_WRITE(FRCTL, 0);
+ ADM8211_CSR_READ(FRCTL);
+ ADM8211_CSR_WRITE(FRCTL, 1);
+ ADM8211_CSR_READ(FRCTL);
+ msleep(100);
+ }
+
+ err = adm8211_read_eeprom(dev);
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Can't alloc eeprom buffer\n",
+ pci_name(pdev));
+ goto err_free_desc;
+ }
+
+ priv->channel = priv->modes[0].channels[0].chan;
+
+ err = ieee80211_register_hwmode(dev, &priv->modes[0]);
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Can't register hwmode\n",
+ pci_name(pdev));
+ goto err_free_desc;
+ }
+
+ err = ieee80211_register_hw(dev);
+ if (err) {
+ printk(KERN_ERR "%s (adm8211): Cannot register device\n",
+ pci_name(pdev));
+ goto err_free_desc;
+ }
+
+ printk(KERN_INFO "%s: hwaddr %s, Rev 0x%02x\n",
+ wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
+ pdev->revision);
+
+ return 0;
+
+ err_free_desc:
+ pci_free_consistent(pdev,
+ sizeof(struct adm8211_desc) * priv->rx_ring_size +
+ sizeof(struct adm8211_desc) * priv->tx_ring_size,
+ priv->rx_ring, priv->rx_ring_dma);
+ kfree(priv->rx_buffers);
+
+ err_iounmap:
+ pci_iounmap(pdev, priv->map);
+
+ err_free_dev:
+ pci_set_drvdata(pdev, NULL);
+ ieee80211_free_hw(dev);
+
+ err_free_reg:
+ pci_release_regions(pdev);
+
+ err_disable_pdev:
+ pci_disable_device(pdev);
+ return err;
+}
+
+
+static void __devexit adm8211_remove(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+ struct adm8211_priv *priv;
+
+ if (!dev)
+ return;
+
+ ieee80211_unregister_hw(dev);
+
+ priv = dev->priv;
+
+ pci_free_consistent(pdev,
+ sizeof(struct adm8211_desc) * priv->rx_ring_size +
+ sizeof(struct adm8211_desc) * priv->tx_ring_size,
+ priv->rx_ring, priv->rx_ring_dma);
+
+ kfree(priv->rx_buffers);
+ kfree(priv->eeprom);
+ pci_iounmap(pdev, priv->map);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ ieee80211_free_hw(dev);
+}
+
+
+#ifdef CONFIG_PM
+static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+ struct adm8211_priv *priv = dev->priv;
+
+ if (priv->mode != IEEE80211_IF_TYPE_INVALID) {
+ ieee80211_stop_queues(dev);
+ adm8211_stop(dev);
+ }
+
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
+}
+
+static int adm8211_resume(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+ struct adm8211_priv *priv = dev->priv;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ if (priv->mode != IEEE80211_IF_TYPE_INVALID) {
+ adm8211_start(dev);
+ ieee80211_start_queues(dev);
+ }
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+
+MODULE_DEVICE_TABLE(pci, adm8211_pci_id_table);
+
+/* TODO: implement enable_wake */
+static struct pci_driver adm8211_driver = {
+ .name = "adm8211",
+ .id_table = adm8211_pci_id_table,
+ .probe = adm8211_probe,
+ .remove = __devexit_p(adm8211_remove),
+#ifdef CONFIG_PM
+ .suspend = adm8211_suspend,
+ .resume = adm8211_resume,
+#endif /* CONFIG_PM */
+};
+
+
+
+static int __init adm8211_init(void)
+{
+ return pci_register_driver(&adm8211_driver);
+}
+
+
+static void __exit adm8211_exit(void)
+{
+ pci_unregister_driver(&adm8211_driver);
+}
+
+
+module_init(adm8211_init);
+module_exit(adm8211_exit);
diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h
new file mode 100644
index 00000000000..ef326fed42e
--- /dev/null
+++ b/drivers/net/wireless/adm8211.h
@@ -0,0 +1,656 @@
+#ifndef ADM8211_H
+#define ADM8211_H
+
+/* ADM8211 Registers */
+
+/* CR32 (SIG) signature */
+#define ADM8211_SIG1 0x82011317 /* ADM8211A */
+#define ADM8211_SIG2 0x82111317 /* ADM8211B/ADM8211C */
+
+#define ADM8211_CSR_READ(r) ioread32(&priv->map->r)
+#define ADM8211_CSR_WRITE(r, val) iowrite32((val), &priv->map->r)
+
+/* CSR (Host Control and Status Registers) */
+struct adm8211_csr {
+ __le32 PAR; /* 0x00 CSR0 */
+ __le32 FRCTL; /* 0x04 CSR0A */
+ __le32 TDR; /* 0x08 CSR1 */
+ __le32 WTDP; /* 0x0C CSR1A */
+ __le32 RDR; /* 0x10 CSR2 */
+ __le32 WRDP; /* 0x14 CSR2A */
+ __le32 RDB; /* 0x18 CSR3 */
+ __le32 TDBH; /* 0x1C CSR3A */
+ __le32 TDBD; /* 0x20 CSR4 */
+ __le32 TDBP; /* 0x24 CSR4A */
+ __le32 STSR; /* 0x28 CSR5 */
+ __le32 TDBB; /* 0x2C CSR5A */
+ __le32 NAR; /* 0x30 CSR6 */
+ __le32 CSR6A; /* reserved */
+ __le32 IER; /* 0x38 CSR7 */
+ __le32 TKIPSCEP; /* 0x3C CSR7A */
+ __le32 LPC; /* 0x40 CSR8 */
+ __le32 CSR_TEST1; /* 0x44 CSR8A */
+ __le32 SPR; /* 0x48 CSR9 */
+ __le32 CSR_TEST0; /* 0x4C CSR9A */
+ __le32 WCSR; /* 0x50 CSR10 */
+ __le32 WPDR; /* 0x54 CSR10A */
+ __le32 GPTMR; /* 0x58 CSR11 */
+ __le32 GPIO; /* 0x5C CSR11A */
+ __le32 BBPCTL; /* 0x60 CSR12 */
+ __le32 SYNCTL; /* 0x64 CSR12A */
+ __le32 PLCPHD; /* 0x68 CSR13 */
+ __le32 MMIWA; /* 0x6C CSR13A */
+ __le32 MMIRD0; /* 0x70 CSR14 */
+ __le32 MMIRD1; /* 0x74 CSR14A */
+ __le32 TXBR; /* 0x78 CSR15 */
+ __le32 SYNDATA; /* 0x7C CSR15A */
+ __le32 ALCS; /* 0x80 CSR16 */
+ __le32 TOFS2; /* 0x84 CSR17 */
+ __le32 CMDR; /* 0x88 CSR18 */
+ __le32 PCIC; /* 0x8C CSR19 */
+ __le32 PMCSR; /* 0x90 CSR20 */
+ __le32 PAR0; /* 0x94 CSR21 */
+ __le32 PAR1; /* 0x98 CSR22 */
+ __le32 MAR0; /* 0x9C CSR23 */
+ __le32 MAR1; /* 0xA0 CSR24 */
+ __le32 ATIMDA0; /* 0xA4 CSR25 */
+ __le32 ABDA1; /* 0xA8 CSR26 */
+ __le32 BSSID0; /* 0xAC CSR27 */
+ __le32 TXLMT; /* 0xB0 CSR28 */
+ __le32 MIBCNT; /* 0xB4 CSR29 */
+ __le32 BCNT; /* 0xB8 CSR30 */
+ __le32 TSFTH; /* 0xBC CSR31 */
+ __le32 TSC; /* 0xC0 CSR32 */
+ __le32 SYNRF; /* 0xC4 CSR33 */
+ __le32 BPLI; /* 0xC8 CSR34 */
+ __le32 CAP0; /* 0xCC CSR35 */
+ __le32 CAP1; /* 0xD0 CSR36 */
+ __le32 RMD; /* 0xD4 CSR37 */
+ __le32 CFPP; /* 0xD8 CSR38 */
+ __le32 TOFS0; /* 0xDC CSR39 */
+ __le32 TOFS1; /* 0xE0 CSR40 */
+ __le32 IFST; /* 0xE4 CSR41 */
+ __le32 RSPT; /* 0xE8 CSR42 */
+ __le32 TSFTL; /* 0xEC CSR43 */
+ __le32 WEPCTL; /* 0xF0 CSR44 */
+ __le32 WESK; /* 0xF4 CSR45 */
+ __le32 WEPCNT; /* 0xF8 CSR46 */
+ __le32 MACTEST; /* 0xFC CSR47 */
+ __le32 FER; /* 0x100 */
+ __le32 FEMR; /* 0x104 */
+ __le32 FPSR; /* 0x108 */
+ __le32 FFER; /* 0x10C */
+} __attribute__ ((packed));
+
+/* CSR0 - PAR (PCI Address Register) */
+#define ADM8211_PAR_MWIE (1 << 24)
+#define ADM8211_PAR_MRLE (1 << 23)
+#define ADM8211_PAR_MRME (1 << 21)
+#define ADM8211_PAR_RAP ((1 << 18) | (1 << 17))
+#define ADM8211_PAR_CAL ((1 << 15) | (1 << 14))
+#define ADM8211_PAR_PBL 0x00003f00
+#define ADM8211_PAR_BLE (1 << 7)
+#define ADM8211_PAR_DSL 0x0000007c
+#define ADM8211_PAR_BAR (1 << 1)
+#define ADM8211_PAR_SWR (1 << 0)
+
+/* CSR1 - FRCTL (Frame Control Register) */
+#define ADM8211_FRCTL_PWRMGT (1 << 31)
+#define ADM8211_FRCTL_MAXPSP (1 << 27)
+#define ADM8211_FRCTL_DRVPRSP (1 << 26)
+#define ADM8211_FRCTL_DRVBCON (1 << 25)
+#define ADM8211_FRCTL_AID 0x0000ffff
+#define ADM8211_FRCTL_AID_ON 0x0000c000
+
+/* CSR5 - STSR (Status Register) */
+#define ADM8211_STSR_PCF (1 << 31)
+#define ADM8211_STSR_BCNTC (1 << 30)
+#define ADM8211_STSR_GPINT (1 << 29)
+#define ADM8211_STSR_LinkOff (1 << 28)
+#define ADM8211_STSR_ATIMTC (1 << 27)
+#define ADM8211_STSR_TSFTF (1 << 26)
+#define ADM8211_STSR_TSCZ (1 << 25)
+#define ADM8211_STSR_LinkOn (1 << 24)
+#define ADM8211_STSR_SQL (1 << 23)
+#define ADM8211_STSR_WEPTD (1 << 22)
+#define ADM8211_STSR_ATIME (1 << 21)
+#define ADM8211_STSR_TBTT (1 << 20)
+#define ADM8211_STSR_NISS (1 << 16)
+#define ADM8211_STSR_AISS (1 << 15)
+#define ADM8211_STSR_TEIS (1 << 14)
+#define ADM8211_STSR_FBE (1 << 13)
+#define ADM8211_STSR_REIS (1 << 12)
+#define ADM8211_STSR_GPTT (1 << 11)
+#define ADM8211_STSR_RPS (1 << 8)
+#define ADM8211_STSR_RDU (1 << 7)
+#define ADM8211_STSR_RCI (1 << 6)
+#define ADM8211_STSR_TUF (1 << 5)
+#define ADM8211_STSR_TRT (1 << 4)
+#define ADM8211_STSR_TLT (1 << 3)
+#define ADM8211_STSR_TDU (1 << 2)
+#define ADM8211_STSR_TPS (1 << 1)
+#define ADM8211_STSR_TCI (1 << 0)
+
+/* CSR6 - NAR (Network Access Register) */
+#define ADM8211_NAR_TXCF (1 << 31)
+#define ADM8211_NAR_HF (1 << 30)
+#define ADM8211_NAR_UTR (1 << 29)
+#define ADM8211_NAR_SQ (1 << 28)
+#define ADM8211_NAR_CFP (1 << 27)
+#define ADM8211_NAR_SF (1 << 21)
+#define ADM8211_NAR_TR ((1 << 15) | (1 << 14))
+#define ADM8211_NAR_ST (1 << 13)
+#define ADM8211_NAR_OM ((1 << 11) | (1 << 10))
+#define ADM8211_NAR_MM (1 << 7)
+#define ADM8211_NAR_PR (1 << 6)
+#define ADM8211_NAR_EA (1 << 5)
+#define ADM8211_NAR_PB (1 << 3)
+#define ADM8211_NAR_STPDMA (1 << 2)
+#define ADM8211_NAR_SR (1 << 1)
+#define ADM8211_NAR_CTX (1 << 0)
+
+#define ADM8211_IDLE() \
+do { \
+ if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST)) { \
+ ADM8211_CSR_WRITE(NAR, priv->nar & \
+ ~(ADM8211_NAR_SR | ADM8211_NAR_ST));\
+ ADM8211_CSR_READ(NAR); \
+ msleep(20); \
+ } \
+} while (0)
+
+#define ADM8211_IDLE_RX() \
+do { \
+ if (priv->nar & ADM8211_NAR_SR) { \
+ ADM8211_CSR_WRITE(NAR, priv->nar & ~ADM8211_NAR_SR); \
+ ADM8211_CSR_READ(NAR); \
+ mdelay(20); \
+ } \
+} while (0)
+
+#define ADM8211_RESTORE() \
+do { \
+ if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST)) \
+ ADM8211_CSR_WRITE(NAR, priv->nar); \
+} while (0)
+
+/* CSR7 - IER (Interrupt Enable Register) */
+#define ADM8211_IER_PCFIE (1 << 31)
+#define ADM8211_IER_BCNTCIE (1 << 30)
+#define ADM8211_IER_GPIE (1 << 29)
+#define ADM8211_IER_LinkOffIE (1 << 28)
+#define ADM8211_IER_ATIMTCIE (1 << 27)
+#define ADM8211_IER_TSFTFIE (1 << 26)
+#define ADM8211_IER_TSCZE (1 << 25)
+#define ADM8211_IER_LinkOnIE (1 << 24)
+#define ADM8211_IER_SQLIE (1 << 23)
+#define ADM8211_IER_WEPIE (1 << 22)
+#define ADM8211_IER_ATIMEIE (1 << 21)
+#define ADM8211_IER_TBTTIE (1 << 20)
+#define ADM8211_IER_NIE (1 << 16)
+#define ADM8211_IER_AIE (1 << 15)
+#define ADM8211_IER_TEIE (1 << 14)
+#define ADM8211_IER_FBEIE (1 << 13)
+#define ADM8211_IER_REIE (1 << 12)
+#define ADM8211_IER_GPTIE (1 << 11)
+#define ADM8211_IER_RSIE (1 << 8)
+#define ADM8211_IER_RUIE (1 << 7)
+#define ADM8211_IER_RCIE (1 << 6)
+#define ADM8211_IER_TUIE (1 << 5)
+#define ADM8211_IER_TRTIE (1 << 4)
+#define ADM8211_IER_TLTTIE (1 << 3)
+#define ADM8211_IER_TDUIE (1 << 2)
+#define ADM8211_IER_TPSIE (1 << 1)
+#define ADM8211_IER_TCIE (1 << 0)
+
+/* CSR9 - SPR (Serial Port Register) */
+#define ADM8211_SPR_SRS (1 << 11)
+#define ADM8211_SPR_SDO (1 << 3)
+#define ADM8211_SPR_SDI (1 << 2)
+#define ADM8211_SPR_SCLK (1 << 1)
+#define ADM8211_SPR_SCS (1 << 0)
+
+/* CSR9A - CSR_TEST0 */
+#define ADM8211_CSR_TEST0_EPNE (1 << 18)
+#define ADM8211_CSR_TEST0_EPSNM (1 << 17)
+#define ADM8211_CSR_TEST0_EPTYP (1 << 16)
+#define ADM8211_CSR_TEST0_EPRLD (1 << 15)
+
+/* CSR10 - WCSR (Wake-up Control/Status Register) */
+#define ADM8211_WCSR_CRCT (1 << 30)
+#define ADM8211_WCSR_TSFTWE (1 << 20)
+#define ADM8211_WCSR_TIMWE (1 << 19)
+#define ADM8211_WCSR_ATIMWE (1 << 18)
+#define ADM8211_WCSR_KEYWE (1 << 17)
+#define ADM8211_WCSR_MPRE (1 << 9)
+#define ADM8211_WCSR_LSOE (1 << 8)
+#define ADM8211_WCSR_KEYUP (1 << 6)
+#define ADM8211_WCSR_TSFTW (1 << 5)
+#define ADM8211_WCSR_TIMW (1 << 4)
+#define ADM8211_WCSR_ATIMW (1 << 3)
+#define ADM8211_WCSR_MPR (1 << 1)
+#define ADM8211_WCSR_LSO (1 << 0)
+
+/* CSR11A - GPIO */
+#define ADM8211_CSR_GPIO_EN5 (1 << 17)
+#define ADM8211_CSR_GPIO_EN4 (1 << 16)
+#define ADM8211_CSR_GPIO_EN3 (1 << 15)
+#define ADM8211_CSR_GPIO_EN2 (1 << 14)
+#define ADM8211_CSR_GPIO_EN1 (1 << 13)
+#define ADM8211_CSR_GPIO_EN0 (1 << 12)
+#define ADM8211_CSR_GPIO_O5 (1 << 11)
+#define ADM8211_CSR_GPIO_O4 (1 << 10)
+#define ADM8211_CSR_GPIO_O3 (1 << 9)
+#define ADM8211_CSR_GPIO_O2 (1 << 8)
+#define ADM8211_CSR_GPIO_O1 (1 << 7)
+#define ADM8211_CSR_GPIO_O0 (1 << 6)
+#define ADM8211_CSR_GPIO_IN 0x0000003f
+
+/* CSR12 - BBPCTL (BBP Control port) */
+#define ADM8211_BBPCTL_MMISEL (1 << 31)
+#define ADM8211_BBPCTL_SPICADD (0x7F << 24)
+#define ADM8211_BBPCTL_RF3000 (0x20 << 24)
+#define ADM8211_BBPCTL_TXCE (1 << 23)
+#define ADM8211_BBPCTL_RXCE (1 << 22)
+#define ADM8211_BBPCTL_CCAP (1 << 21)
+#define ADM8211_BBPCTL_TYPE 0x001c0000
+#define ADM8211_BBPCTL_WR (1 << 17)
+#define ADM8211_BBPCTL_RD (1 << 16)
+#define ADM8211_BBPCTL_ADDR 0x0000ff00
+#define ADM8211_BBPCTL_DATA 0x000000ff
+
+/* CSR12A - SYNCTL (Synthesizer Control port) */
+#define ADM8211_SYNCTL_WR (1 << 31)
+#define ADM8211_SYNCTL_RD (1 << 30)
+#define ADM8211_SYNCTL_CS0 (1 << 29)
+#define ADM8211_SYNCTL_CS1 (1 << 28)
+#define ADM8211_SYNCTL_CAL (1 << 27)
+#define ADM8211_SYNCTL_SELCAL (1 << 26)
+#define ADM8211_SYNCTL_RFtype ((1 << 24) || (1 << 23) || (1 << 22))
+#define ADM8211_SYNCTL_RFMD (1 << 22)
+#define ADM8211_SYNCTL_GENERAL (0x7 << 22)
+/* SYNCTL 21:0 Data (Si4126: 18-bit data, 4-bit address) */
+
+/* CSR18 - CMDR (Command Register) */
+#define ADM8211_CMDR_PM (1 << 19)
+#define ADM8211_CMDR_APM (1 << 18)
+#define ADM8211_CMDR_RTE (1 << 4)
+#define ADM8211_CMDR_DRT ((1 << 3) | (1 << 2))
+#define ADM8211_CMDR_DRT_8DW (0x0 << 2)
+#define ADM8211_CMDR_DRT_16DW (0x1 << 2)
+#define ADM8211_CMDR_DRT_SF (0x2 << 2)
+
+/* CSR33 - SYNRF (SYNRF direct control) */
+#define ADM8211_SYNRF_SELSYN (1 << 31)
+#define ADM8211_SYNRF_SELRF (1 << 30)
+#define ADM8211_SYNRF_LERF (1 << 29)
+#define ADM8211_SYNRF_LEIF (1 << 28)
+#define ADM8211_SYNRF_SYNCLK (1 << 27)
+#define ADM8211_SYNRF_SYNDATA (1 << 26)
+#define ADM8211_SYNRF_PE1 (1 << 25)
+#define ADM8211_SYNRF_PE2 (1 << 24)
+#define ADM8211_SYNRF_PA_PE (1 << 23)
+#define ADM8211_SYNRF_TR_SW (1 << 22)
+#define ADM8211_SYNRF_TR_SWN (1 << 21)
+#define ADM8211_SYNRF_RADIO (1 << 20)
+#define ADM8211_SYNRF_CAL_EN (1 << 19)
+#define ADM8211_SYNRF_PHYRST (1 << 18)
+
+#define ADM8211_SYNRF_IF_SELECT_0 (1 << 31)
+#define ADM8211_SYNRF_IF_SELECT_1 ((1 << 31) | (1 << 28))
+#define ADM8211_SYNRF_WRITE_SYNDATA_0 (1 << 31)
+#define ADM8211_SYNRF_WRITE_SYNDATA_1 ((1 << 31) | (1 << 26))
+#define ADM8211_SYNRF_WRITE_CLOCK_0 (1 << 31)
+#define ADM8211_SYNRF_WRITE_CLOCK_1 ((1 << 31) | (1 << 27))
+
+/* CSR44 - WEPCTL (WEP Control) */
+#define ADM8211_WEPCTL_WEPENABLE (1 << 31)
+#define ADM8211_WEPCTL_WPAENABLE (1 << 30)
+#define ADM8211_WEPCTL_CURRENT_TABLE (1 << 29)
+#define ADM8211_WEPCTL_TABLE_WR (1 << 28)
+#define ADM8211_WEPCTL_TABLE_RD (1 << 27)
+#define ADM8211_WEPCTL_WEPRXBYP (1 << 25)
+#define ADM8211_WEPCTL_SEL_WEPTABLE (1 << 23)
+#define ADM8211_WEPCTL_ADDR (0x000001ff)
+
+/* CSR45 - WESK (Data Entry for Share/Individual Key) */
+#define ADM8211_WESK_DATA (0x0000ffff)
+
+/* FER (Function Event Register) */
+#define ADM8211_FER_INTR_EV_ENT (1 << 15)
+
+
+/* Si4126 RF Synthesizer - Control Registers */
+#define SI4126_MAIN_CONF 0
+#define SI4126_PHASE_DET_GAIN 1
+#define SI4126_POWERDOWN 2
+#define SI4126_RF1_N_DIV 3 /* only Si4136 */
+#define SI4126_RF2_N_DIV 4
+#define SI4126_IF_N_DIV 5
+#define SI4126_RF1_R_DIV 6 /* only Si4136 */
+#define SI4126_RF2_R_DIV 7
+#define SI4126_IF_R_DIV 8
+
+/* Main Configuration */
+#define SI4126_MAIN_XINDIV2 (1 << 6)
+#define SI4126_MAIN_IFDIV ((1 << 11) | (1 << 10))
+/* Powerdown */
+#define SI4126_POWERDOWN_PDIB (1 << 1)
+#define SI4126_POWERDOWN_PDRB (1 << 0)
+
+
+/* RF3000 BBP - Control Port Registers */
+/* 0x00 - reserved */
+#define RF3000_MODEM_CTRL__RX_STATUS 0x01
+#define RF3000_CCA_CTRL 0x02
+#define RF3000_DIVERSITY__RSSI 0x03
+#define RF3000_RX_SIGNAL_FIELD 0x04
+#define RF3000_RX_LEN_MSB 0x05
+#define RF3000_RX_LEN_LSB 0x06
+#define RF3000_RX_SERVICE_FIELD 0x07
+#define RF3000_TX_VAR_GAIN__TX_LEN_EXT 0x11
+#define RF3000_TX_LEN_MSB 0x12
+#define RF3000_TX_LEN_LSB 0x13
+#define RF3000_LOW_GAIN_CALIB 0x14
+#define RF3000_HIGH_GAIN_CALIB 0x15
+
+/* ADM8211 revisions */
+#define ADM8211_REV_AB 0x11
+#define ADM8211_REV_AF 0x15
+#define ADM8211_REV_BA 0x20
+#define ADM8211_REV_CA 0x30
+
+struct adm8211_desc {
+ __le32 status;
+ __le32 length;
+ __le32 buffer1;
+ __le32 buffer2;
+};
+
+#define RDES0_STATUS_OWN (1 << 31)
+#define RDES0_STATUS_ES (1 << 30)
+#define RDES0_STATUS_SQL (1 << 29)
+#define RDES0_STATUS_DE (1 << 28)
+#define RDES0_STATUS_FS (1 << 27)
+#define RDES0_STATUS_LS (1 << 26)
+#define RDES0_STATUS_PCF (1 << 25)
+#define RDES0_STATUS_SFDE (1 << 24)
+#define RDES0_STATUS_SIGE (1 << 23)
+#define RDES0_STATUS_CRC16E (1 << 22)
+#define RDES0_STATUS_RXTOE (1 << 21)
+#define RDES0_STATUS_CRC32E (1 << 20)
+#define RDES0_STATUS_ICVE (1 << 19)
+#define RDES0_STATUS_DA1 (1 << 17)
+#define RDES0_STATUS_DA0 (1 << 16)
+#define RDES0_STATUS_RXDR ((1 << 15) | (1 << 14) | (1 << 13) | (1 << 12))
+#define RDES0_STATUS_FL (0x00000fff)
+
+#define RDES1_CONTROL_RER (1 << 25)
+#define RDES1_CONTROL_RCH (1 << 24)
+#define RDES1_CONTROL_RBS2 (0x00fff000)
+#define RDES1_CONTROL_RBS1 (0x00000fff)
+
+#define RDES1_STATUS_RSSI (0x0000007f)
+
+
+#define TDES0_CONTROL_OWN (1 << 31)
+#define TDES0_CONTROL_DONE (1 << 30)
+#define TDES0_CONTROL_TXDR (0x0ff00000)
+
+#define TDES0_STATUS_OWN (1 << 31)
+#define TDES0_STATUS_DONE (1 << 30)
+#define TDES0_STATUS_ES (1 << 29)
+#define TDES0_STATUS_TLT (1 << 28)
+#define TDES0_STATUS_TRT (1 << 27)
+#define TDES0_STATUS_TUF (1 << 26)
+#define TDES0_STATUS_TRO (1 << 25)
+#define TDES0_STATUS_SOFBR (1 << 24)
+#define TDES0_STATUS_ACR (0x00000fff)
+
+#define TDES1_CONTROL_IC (1 << 31)
+#define TDES1_CONTROL_LS (1 << 30)
+#define TDES1_CONTROL_FS (1 << 29)
+#define TDES1_CONTROL_TER (1 << 25)
+#define TDES1_CONTROL_TCH (1 << 24)
+#define TDES1_CONTROL_RBS2 (0x00fff000)
+#define TDES1_CONTROL_RBS1 (0x00000fff)
+
+/* SRAM offsets */
+#define ADM8211_SRAM(x) (priv->pdev->revision < ADM8211_REV_BA ? \
+ ADM8211_SRAM_A_ ## x : ADM8211_SRAM_B_ ## x)
+
+#define ADM8211_SRAM_INDIV_KEY 0x0000
+#define ADM8211_SRAM_A_SHARE_KEY 0x0160
+#define ADM8211_SRAM_B_SHARE_KEY 0x00c0
+
+#define ADM8211_SRAM_A_SSID 0x0180
+#define ADM8211_SRAM_B_SSID 0x00d4
+#define ADM8211_SRAM_SSID ADM8211_SRAM(SSID)
+
+#define ADM8211_SRAM_A_SUPP_RATE 0x0191
+#define ADM8211_SRAM_B_SUPP_RATE 0x00dd
+#define ADM8211_SRAM_SUPP_RATE ADM8211_SRAM(SUPP_RATE)
+
+#define ADM8211_SRAM_A_SIZE 0x0200
+#define ADM8211_SRAM_B_SIZE 0x01c0
+#define ADM8211_SRAM_SIZE ADM8211_SRAM(SIZE)
+
+struct adm8211_rx_ring_info {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+};
+
+struct adm8211_tx_ring_info {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+ struct ieee80211_tx_control tx_control;
+ size_t hdrlen;
+};
+
+#define PLCP_SIGNAL_1M 0x0a
+#define PLCP_SIGNAL_2M 0x14
+#define PLCP_SIGNAL_5M5 0x37
+#define PLCP_SIGNAL_11M 0x6e
+
+struct adm8211_tx_hdr {
+ u8 da[6];
+ u8 signal; /* PLCP signal / TX rate in 100 Kbps */
+ u8 service;
+ __le16 frame_body_size;
+ __le16 frame_control;
+ __le16 plcp_frag_tail_len;
+ __le16 plcp_frag_head_len;
+ __le16 dur_frag_tail;
+ __le16 dur_frag_head;
+ u8 addr4[6];
+
+#define ADM8211_TXHDRCTL_SHORT_PREAMBLE (1 << 0)
+#define ADM8211_TXHDRCTL_MORE_FRAG (1 << 1)
+#define ADM8211_TXHDRCTL_MORE_DATA (1 << 2)
+#define ADM8211_TXHDRCTL_FRAG_NO (1 << 3) /* ? */
+#define ADM8211_TXHDRCTL_ENABLE_RTS (1 << 4)
+#define ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE (1 << 5)
+#define ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER (1 << 15) /* ? */
+ __le16 header_control;
+ __le16 frag;
+ u8 reserved_0;
+ u8 retry_limit;
+
+ u32 wep2key0;
+ u32 wep2key1;
+ u32 wep2key2;
+ u32 wep2key3;
+
+ u8 keyid;
+ u8 entry_control; // huh??
+ u16 reserved_1;
+ u32 reserved_2;
+} __attribute__ ((packed));
+
+
+#define RX_COPY_BREAK 128
+#define RX_PKT_SIZE 2500
+
+struct adm8211_eeprom {
+ __le16 signature; /* 0x00 */
+ u8 major_version; /* 0x02 */
+ u8 minor_version; /* 0x03 */
+ u8 reserved_1[4]; /* 0x04 */
+ u8 hwaddr[6]; /* 0x08 */
+ u8 reserved_2[8]; /* 0x1E */
+ __le16 cr49; /* 0x16 */
+ u8 cr03; /* 0x18 */
+ u8 cr28; /* 0x19 */
+ u8 cr29; /* 0x1A */
+ u8 country_code; /* 0x1B */
+
+/* specific bbp types */
+#define ADM8211_BBP_RFMD3000 0x00
+#define ADM8211_BBP_RFMD3002 0x01
+#define ADM8211_BBP_ADM8011 0x04
+ u8 specific_bbptype; /* 0x1C */
+ u8 specific_rftype; /* 0x1D */
+ u8 reserved_3[2]; /* 0x1E */
+ __le16 device_id; /* 0x20 */
+ __le16 vendor_id; /* 0x22 */
+ __le16 subsystem_id; /* 0x24 */
+ __le16 subsystem_vendor_id; /* 0x26 */
+ u8 maxlat; /* 0x28 */
+ u8 mingnt; /* 0x29 */
+ __le16 cis_pointer_low; /* 0x2A */
+ __le16 cis_pointer_high; /* 0x2C */
+ __le16 csr18; /* 0x2E */
+ u8 reserved_4[16]; /* 0x30 */
+ u8 d1_pwrdara; /* 0x40 */
+ u8 d0_pwrdara; /* 0x41 */
+ u8 d3_pwrdara; /* 0x42 */
+ u8 d2_pwrdara; /* 0x43 */
+ u8 antenna_power[14]; /* 0x44 */
+ __le16 cis_wordcnt; /* 0x52 */
+ u8 tx_power[14]; /* 0x54 */
+ u8 lpf_cutoff[14]; /* 0x62 */
+ u8 lnags_threshold[14]; /* 0x70 */
+ __le16 checksum; /* 0x7E */
+ u8 cis_data[0]; /* 0x80, 384 bytes */
+} __attribute__ ((packed));
+
+static const struct ieee80211_rate adm8211_rates[] = {
+ { .rate = 10,
+ .val = 10,
+ .val2 = -10,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 20,
+ .val = 20,
+ .val2 = -20,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 55,
+ .val = 55,
+ .val2 = -55,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 110,
+ .val = 110,
+ .val2 = -110,
+ .flags = IEEE80211_RATE_CCK_2 }
+};
+
+struct ieee80211_chan_range {
+ u8 min;
+ u8 max;
+};
+
+static const struct ieee80211_channel adm8211_channels[] = {
+ { .chan = 1,
+ .freq = 2412},
+ { .chan = 2,
+ .freq = 2417},
+ { .chan = 3,
+ .freq = 2422},
+ { .chan = 4,
+ .freq = 2427},
+ { .chan = 5,
+ .freq = 2432},
+ { .chan = 6,
+ .freq = 2437},
+ { .chan = 7,
+ .freq = 2442},
+ { .chan = 8,
+ .freq = 2447},
+ { .chan = 9,
+ .freq = 2452},
+ { .chan = 10,
+ .freq = 2457},
+ { .chan = 11,
+ .freq = 2462},
+ { .chan = 12,
+ .freq = 2467},
+ { .chan = 13,
+ .freq = 2472},
+ { .chan = 14,
+ .freq = 2484},
+};
+
+struct adm8211_priv {
+ struct pci_dev *pdev;
+ spinlock_t lock;
+ struct adm8211_csr __iomem *map;
+ struct adm8211_desc *rx_ring;
+ struct adm8211_desc *tx_ring;
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_ring_dma;
+ struct adm8211_rx_ring_info *rx_buffers;
+ struct adm8211_tx_ring_info *tx_buffers;
+ unsigned int rx_ring_size, tx_ring_size;
+ unsigned int cur_tx, dirty_tx, cur_rx;
+
+ struct ieee80211_low_level_stats stats;
+ struct ieee80211_hw_mode modes[1];
+ struct ieee80211_channel channels[ARRAY_SIZE(adm8211_channels)];
+ struct ieee80211_rate rates[ARRAY_SIZE(adm8211_rates)];
+ int mode;
+
+ int channel;
+ u8 bssid[ETH_ALEN];
+ u8 ssid[32];
+ size_t ssid_len;
+
+ u8 soft_rx_crc;
+ u8 retry_limit;
+
+ u8 ant_power;
+ u8 tx_power;
+ u8 lpf_cutoff;
+ u8 lnags_threshold;
+ struct adm8211_eeprom *eeprom;
+ size_t eeprom_len;
+
+ u32 nar;
+
+#define ADM8211_TYPE_INTERSIL 0x00
+#define ADM8211_TYPE_RFMD 0x01
+#define ADM8211_TYPE_MARVEL 0x02
+#define ADM8211_TYPE_AIROHA 0x03
+#define ADM8211_TYPE_ADMTEK 0x05
+ unsigned int rf_type:3;
+ unsigned int bbp_type:3;
+
+ u8 specific_bbptype;
+ enum {
+ ADM8211_RFMD2948 = 0x0,
+ ADM8211_RFMD2958 = 0x1,
+ ADM8211_RFMD2958_RF3000_CONTROL_POWER = 0x2,
+ ADM8211_MAX2820 = 0x8,
+ ADM8211_AL2210L = 0xC, /* Airoha */
+ } transceiver_type;
+};
+
+static const struct ieee80211_chan_range cranges[] = {
+ {1, 11}, /* FCC */
+ {1, 11}, /* IC */
+ {1, 13}, /* ETSI */
+ {10, 11}, /* SPAIN */
+ {10, 13}, /* FRANCE */
+ {14, 14}, /* MMK */
+ {1, 14}, /* MMK2 */
+};
+
+#endif /* ADM8211_H */
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index ee1cc14db38..074055e18c5 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -241,8 +241,8 @@ static int proc_perm = 0644;
MODULE_AUTHOR("Benjamin Reed");
MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \
- cards. Direct support for ISA/PCI/MPI cards and support \
- for PCMCIA when used with airo_cs.");
+cards. Direct support for ISA/PCI/MPI cards and support \
+for PCMCIA when used with airo_cs.");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350");
module_param_array(io, int, NULL, 0);
@@ -2481,7 +2481,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
EXPORT_SYMBOL(stop_airo_card);
-static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
+static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN);
return ETH_ALEN;
@@ -2696,14 +2696,13 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci)
return rc;
}
+static const struct header_ops airo_header_ops = {
+ .parse = wll_header_parse,
+};
+
static void wifi_setup(struct net_device *dev)
{
- dev->hard_header = NULL;
- dev->rebuild_header = NULL;
- dev->hard_header_cache = NULL;
- dev->header_cache_update= NULL;
-
- dev->hard_header_parse = wll_header_parse;
+ dev->header_ops = &airo_header_ops;
dev->hard_start_xmit = &airo_start_xmit11;
dev->get_stats = &airo_get_stats;
dev->set_mac_address = &airo_set_mac_address;
@@ -2821,6 +2820,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
struct net_device *dev;
struct airo_info *ai;
int i, rc;
+ DECLARE_MAC_BUF(mac);
/* Create the network device object. */
dev = alloc_netdev(sizeof(*ai), "", ether_setup);
@@ -2870,7 +2870,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
dev->base_addr = port;
SET_NETDEV_DEV(dev, dmdev);
- SET_MODULE_OWNER(dev);
reset_card (dev, 1);
msleep(400);
@@ -2924,9 +2923,8 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
goto err_out_reg;
set_bit(FLAG_REGISTERED,&ai->flags);
- airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x",
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
+ airo_print_info(dev->name, "MAC enabled %s",
+ print_mac(mac, dev->dev_addr));
/* Allocate the transmit buffers */
if (probe && !test_bit(FLAG_MPI,&ai->flags))
@@ -2983,6 +2981,7 @@ int reset_airo_card( struct net_device *dev )
{
int i;
struct airo_info *ai = dev->priv;
+ DECLARE_MAC_BUF(mac);
if (reset_card (dev, 1))
return -1;
@@ -2991,9 +2990,8 @@ int reset_airo_card( struct net_device *dev )
airo_print_err(dev->name, "MAC could not be enabled");
return -1;
}
- airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x",
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ airo_print_info(dev->name, "MAC enabled %s",
+ print_mac(mac, dev->dev_addr));
/* Allocate the transmit buffers if needed */
if (!test_bit(FLAG_MPI,&ai->flags))
for( i = 0; i < MAX_FIDS; i++ )
@@ -5427,6 +5425,7 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
int i;
char *ptr;
APListRid APList_rid;
+ DECLARE_MAC_BUF(mac);
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
@@ -5450,13 +5449,8 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
// We end when we find a zero MAC
if ( !*(int*)APList_rid.ap[i] &&
!*(int*)&APList_rid.ap[i][2]) break;
- ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x\n",
- (int)APList_rid.ap[i][0],
- (int)APList_rid.ap[i][1],
- (int)APList_rid.ap[i][2],
- (int)APList_rid.ap[i][3],
- (int)APList_rid.ap[i][4],
- (int)APList_rid.ap[i][5]);
+ ptr += sprintf(ptr, "%s\n",
+ print_mac(mac, APList_rid.ap[i]));
}
if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
@@ -5475,6 +5469,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
int rc;
/* If doLoseSync is not 1, we won't do a Lose Sync */
int doLoseSync = -1;
+ DECLARE_MAC_BUF(mac);
if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
@@ -5511,13 +5506,8 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
we have to add a spin lock... */
rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
while(rc == 0 && BSSList_rid.index != 0xffff) {
- ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x %*s rssi = %d",
- (int)BSSList_rid.bssid[0],
- (int)BSSList_rid.bssid[1],
- (int)BSSList_rid.bssid[2],
- (int)BSSList_rid.bssid[3],
- (int)BSSList_rid.bssid[4],
- (int)BSSList_rid.bssid[5],
+ ptr += sprintf(ptr, "%s %*s rssi = %d",
+ print_mac(mac, BSSList_rid.bssid),
(int)BSSList_rid.ssidLen,
BSSList_rid.ssid,
(int)BSSList_rid.dBm);
@@ -7579,9 +7569,9 @@ static const iw_handler airo_private_handler[] =
static const struct iw_handler_def airo_handler_def =
{
- .num_standard = sizeof(airo_handler)/sizeof(iw_handler),
- .num_private = sizeof(airo_private_handler)/sizeof(iw_handler),
- .num_private_args = sizeof(airo_private_args)/sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(airo_handler),
+ .num_private = ARRAY_SIZE(airo_private_handler),
+ .num_private_args = ARRAY_SIZE(airo_private_args),
.standard = airo_handler,
.private = airo_private_handler,
.private_args = airo_private_args,
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
index 7d5b8c2cc61..6f7eb9f5922 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/airport.c
@@ -197,7 +197,6 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
return -EBUSY;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
macio_set_drvdata(mdev, dev);
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index 498e8486d12..dbdfc9e39d2 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -1469,10 +1469,10 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
while (dmi)
{ if (dmi->dmi_addrlen == 6)
{
+ DECLARE_MAC_BUF(mac);
if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP)
- printk(KERN_ERR "%s mcl %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name,
- dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
- dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]);
+ printk(KERN_ERR "%s mcl %s\n",
+ dev->name, print_mac(mac, dmi->dmi_addr));
for (i = 0; i < 6; i++)
if (dmi->dmi_addr[i] != hw_dst_addr[i])
break;
@@ -1512,17 +1512,18 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
{
char immedDestAddress[6];
char immedSrcAddress[6];
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+ DECLARE_MAC_BUF(mac4);
memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6);
memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6);
- printk(KERN_WARNING "%s t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x imd %2x:%2x:%2x:%2x:%2x:%2x ims %2x:%2x:%2x:%2x:%2x:%2x\n", dev->name,
- (unsigned char) skbtmp[0], (unsigned char) skbtmp[1], (unsigned char) skbtmp[2], (unsigned char) skbtmp[3],
- (unsigned char) skbtmp[4], (unsigned char) skbtmp[5], (unsigned char) skbtmp[6], (unsigned char) skbtmp[7],
- (unsigned char) skbtmp[8], (unsigned char) skbtmp[9], (unsigned char) skbtmp[10], (unsigned char) skbtmp[11],
- immedDestAddress[0], immedDestAddress[1], immedDestAddress[2],
- immedDestAddress[3], immedDestAddress[4], immedDestAddress[5],
- immedSrcAddress[0], immedSrcAddress[1], immedSrcAddress[2],
- immedSrcAddress[3], immedSrcAddress[4], immedSrcAddress[5]);
+ printk(KERN_WARNING "%s t %s f %s imd %s ims %s\n",
+ dev->name, print_mac(mac, skbtmp),
+ print_mac(mac2, &skbtmp[6]),
+ print_mac(mac3, immedDestAddress),
+ print_mac(mac4, immedSrcAddress));
}
skb->protocol = eth_type_trans(skb, dev);
IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
@@ -1792,8 +1793,6 @@ struct net_device * __init arlan_probe(int unit)
if (!dev)
return ERR_PTR(-ENOMEM);
- SET_MODULE_OWNER(dev);
-
if (unit >= 0) {
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
diff --git a/drivers/net/wireless/arlan-proc.c b/drivers/net/wireless/arlan-proc.c
index 015abd928ab..c6e70dbc5de 100644
--- a/drivers/net/wireless/arlan-proc.c
+++ b/drivers/net/wireless/arlan-proc.c
@@ -435,7 +435,7 @@ static int arlan_sysctl_info(ctl_table * ctl, int write, struct file *filp,
goto final;
}
else
- priva = arlan_device[devnum]->priv;
+ priva = netdev_priv(arlan_device[devnum]);
if (priva == NULL)
{
@@ -654,7 +654,7 @@ static int arlan_sysctl_info161719(ctl_table * ctl, int write, struct file *filp
goto final;
}
else
- priva = arlan_device[devnum]->priv;
+ priva = netdev_priv(arlan_device[devnum]);
if (priva == NULL)
{
printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
@@ -688,7 +688,7 @@ static int arlan_sysctl_infotxRing(ctl_table * ctl, int write, struct file *filp
goto final;
}
else
- priva = arlan_device[devnum]->priv;
+ priva = netdev_priv(arlan_device[devnum]);
if (priva == NULL)
{
printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
@@ -716,7 +716,7 @@ static int arlan_sysctl_inforxRing(ctl_table * ctl, int write, struct file *filp
pos += sprintf(arlan_drive_info + pos, "No device found here \n");
goto final;
} else
- priva = arlan_device[devnum]->priv;
+ priva = netdev_priv(arlan_device[devnum]);
if (priva == NULL)
{
printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
@@ -745,7 +745,7 @@ static int arlan_sysctl_info18(ctl_table * ctl, int write, struct file *filp,
goto final;
}
else
- priva = arlan_device[devnum]->priv;
+ priva = netdev_priv(arlan_device[devnum]);
if (priva == NULL)
{
printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
@@ -780,7 +780,7 @@ static int arlan_configure(ctl_table * ctl, int write, struct file *filp,
}
else if (arlan_device[devnum] != NULL)
{
- priv = arlan_device[devnum]->priv;
+ priv = netdev_priv(arlan_device[devnum]);
arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_CONF);
}
@@ -805,7 +805,7 @@ static int arlan_sysctl_reset(ctl_table * ctl, int write, struct file *filp,
}
else if (arlan_device[devnum] != NULL)
{
- priv = arlan_device[devnum]->priv;
+ priv = netdev_priv(arlan_device[devnum]);
arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_RESET);
} else
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 51a7db53afa..059ce3f07db 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -1484,6 +1484,7 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
struct net_device *dev;
struct atmel_private *priv;
int rc;
+ DECLARE_MAC_BUF(mac);
/* Create the network device object. */
dev = alloc_etherdev(sizeof(*priv));
@@ -1598,12 +1599,9 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
if (!ent)
printk(KERN_WARNING "atmel: unable to create /proc entry.\n");
- printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
- dev->name, DRIVER_MAJOR, DRIVER_MINOR,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
+ printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %s\n",
+ dev->name, DRIVER_MAJOR, DRIVER_MINOR, print_mac(mac, dev->dev_addr));
- SET_MODULE_OWNER(dev);
return dev;
err_out_res:
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
new file mode 100644
index 00000000000..fdbc351ac33
--- /dev/null
+++ b/drivers/net/wireless/b43/Kconfig
@@ -0,0 +1,133 @@
+config B43
+ tristate "Broadcom 43xx wireless support (mac80211 stack)"
+ depends on SSB_POSSIBLE && MAC80211 && WLAN_80211
+ select SSB
+ select FW_LOADER
+ select HW_RANDOM
+ ---help---
+ b43 is a driver for the Broadcom 43xx series wireless devices.
+
+ Check "lspci" for something like
+ "Broadcom Corporation BCM43XX 802.11 Wireless LAN Controller"
+ to determine whether you own such a device.
+
+ This driver supports the new BCM43xx IEEE 802.11G devices, but not
+ the old IEEE 802.11B devices. Old devices are supported by
+ the b43legacy driver.
+ Note that this has nothing to do with the standard that your AccessPoint
+ supports (A, B, G or a combination).
+ IEEE 802.11G devices can talk to IEEE 802.11B AccessPoints.
+
+ It is safe to include both b43 and b43legacy as the underlying glue
+ layer will automatically load the correct version for your device.
+
+ This driver uses V4 firmware, which must be installed separately using
+ b43-fwcutter.
+
+ This driver can be built as a module (recommended) that will be called "b43".
+ If unsure, say M.
+
+# Auto-select SSB PCI-HOST support, if possible
+config B43_PCI_AUTOSELECT
+ bool
+ depends on B43 && SSB_PCIHOST_POSSIBLE
+ select SSB_PCIHOST
+ default y
+
+# Auto-select SSB PCICORE driver, if possible
+config B43_PCICORE_AUTOSELECT
+ bool
+ depends on B43 && SSB_DRIVER_PCICORE_POSSIBLE
+ select SSB_DRIVER_PCICORE
+ default y
+
+config B43_PCMCIA
+ bool "Broadcom 43xx PCMCIA device support (EXPERIMENTAL)"
+ depends on B43 && SSB_PCMCIAHOST_POSSIBLE && EXPERIMENTAL
+ select SSB_PCMCIAHOST
+ ---help---
+ Broadcom 43xx PCMCIA device support.
+
+ Support for 16bit PCMCIA devices.
+ Please note that most PC-CARD devices are _NOT_ 16bit PCMCIA
+ devices, but 32bit CardBUS devices. CardBUS devices are supported
+ out of the box by b43.
+
+ With this config option you can drive b43 cards in
+ CompactFlash formfactor in a PCMCIA adaptor.
+ CF b43 cards can sometimes be found in handheld PCs.
+
+ It's safe to select Y here, even if you don't have a B43 PCMCIA device.
+
+ If unsure, say N.
+
+# This config option automatically enables b43 LEDS support,
+# if it's possible.
+config B43_LEDS
+ bool
+ depends on B43 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43)
+ default y
+
+# This config option automatically enables b43 RFKILL support,
+# if it's possible.
+config B43_RFKILL
+ bool
+ depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43)
+ default y
+
+config B43_DEBUG
+ bool "Broadcom 43xx debugging"
+ depends on B43
+ ---help---
+ Broadcom 43xx debugging messages.
+
+ Say Y, if you want to find out why the driver does not
+ work for you.
+
+config B43_DMA
+ bool
+ depends on B43
+config B43_PIO
+ bool
+ depends on B43
+
+choice
+ prompt "Broadcom 43xx data transfer mode"
+ depends on B43
+ default B43_DMA_AND_PIO_MODE
+
+config B43_DMA_AND_PIO_MODE
+ bool "DMA + PIO"
+ select B43_DMA
+ select B43_PIO
+ ---help---
+ Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
+ data transfer modes.
+ The actually used mode is selectable through the module
+ parameter "pio". If the module parameter is pio=0, DMA is used.
+ Otherwise PIO is used. DMA is default.
+
+ If unsure, choose this option.
+
+config B43_DMA_MODE
+ bool "DMA (Direct Memory Access) only"
+ select B43_DMA
+ ---help---
+ Only include Direct Memory Access (DMA).
+ This reduces the size of the driver module, by omitting the PIO code.
+
+config B43_PIO_MODE
+ bool "PIO (Programmed I/O) only"
+ select B43_PIO
+ ---help---
+ Only include Programmed I/O (PIO).
+ This reduces the size of the driver module, by omitting the DMA code.
+ Please note that PIO transfers are slow (compared to DMA).
+
+ Also note that not all devices of the 43xx series support PIO.
+ The 4306 (Apple Airport Extreme and others) supports PIO, while
+ the 4318 is known to _not_ support PIO.
+
+ Only use PIO, if DMA does not work for you.
+
+endchoice
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
new file mode 100644
index 00000000000..485e59e2dfa
--- /dev/null
+++ b/drivers/net/wireless/b43/Makefile
@@ -0,0 +1,20 @@
+# b43 core
+b43-y += main.o
+b43-y += tables.o
+b43-y += phy.o
+b43-y += sysfs.o
+b43-y += xmit.o
+b43-y += lo.o
+# b43 RFKILL button support
+b43-$(CONFIG_B43_RFKILL) += rfkill.o
+# b43 LED support
+b43-$(CONFIG_B43_LEDS) += leds.o
+# b43 PCMCIA support
+b43-$(CONFIG_B43_PCMCIA) += pcmcia.o
+# b43 debugging
+b43-$(CONFIG_B43_DEBUG) += debugfs.o
+# b43 DMA and PIO
+b43-$(CONFIG_B43_DMA) += dma.o
+b43-$(CONFIG_B43_PIO) += pio.o
+
+obj-$(CONFIG_B43) += b43.o
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
new file mode 100644
index 00000000000..a28ad230d63
--- /dev/null
+++ b/drivers/net/wireless/b43/b43.h
@@ -0,0 +1,854 @@
+#ifndef B43_H_
+#define B43_H_
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/hw_random.h>
+#include <linux/ssb/ssb.h>
+#include <net/mac80211.h>
+
+#include "debugfs.h"
+#include "leds.h"
+#include "rfkill.h"
+#include "lo.h"
+#include "phy.h"
+
+#ifdef CONFIG_B43_DEBUG
+# define B43_DEBUG 1
+#else
+# define B43_DEBUG 0
+#endif
+
+#define B43_RX_MAX_SSI 60
+
+/* MMIO offsets */
+#define B43_MMIO_DMA0_REASON 0x20
+#define B43_MMIO_DMA0_IRQ_MASK 0x24
+#define B43_MMIO_DMA1_REASON 0x28
+#define B43_MMIO_DMA1_IRQ_MASK 0x2C
+#define B43_MMIO_DMA2_REASON 0x30
+#define B43_MMIO_DMA2_IRQ_MASK 0x34
+#define B43_MMIO_DMA3_REASON 0x38
+#define B43_MMIO_DMA3_IRQ_MASK 0x3C
+#define B43_MMIO_DMA4_REASON 0x40
+#define B43_MMIO_DMA4_IRQ_MASK 0x44
+#define B43_MMIO_DMA5_REASON 0x48
+#define B43_MMIO_DMA5_IRQ_MASK 0x4C
+#define B43_MMIO_MACCTL 0x120
+#define B43_MMIO_STATUS2_BITFIELD 0x124
+#define B43_MMIO_GEN_IRQ_REASON 0x128
+#define B43_MMIO_GEN_IRQ_MASK 0x12C
+#define B43_MMIO_RAM_CONTROL 0x130
+#define B43_MMIO_RAM_DATA 0x134
+#define B43_MMIO_PS_STATUS 0x140
+#define B43_MMIO_RADIO_HWENABLED_HI 0x158
+#define B43_MMIO_SHM_CONTROL 0x160
+#define B43_MMIO_SHM_DATA 0x164
+#define B43_MMIO_SHM_DATA_UNALIGNED 0x166
+#define B43_MMIO_XMITSTAT_0 0x170
+#define B43_MMIO_XMITSTAT_1 0x174
+#define B43_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
+#define B43_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
+
+/* 32-bit DMA */
+#define B43_MMIO_DMA32_BASE0 0x200
+#define B43_MMIO_DMA32_BASE1 0x220
+#define B43_MMIO_DMA32_BASE2 0x240
+#define B43_MMIO_DMA32_BASE3 0x260
+#define B43_MMIO_DMA32_BASE4 0x280
+#define B43_MMIO_DMA32_BASE5 0x2A0
+/* 64-bit DMA */
+#define B43_MMIO_DMA64_BASE0 0x200
+#define B43_MMIO_DMA64_BASE1 0x240
+#define B43_MMIO_DMA64_BASE2 0x280
+#define B43_MMIO_DMA64_BASE3 0x2C0
+#define B43_MMIO_DMA64_BASE4 0x300
+#define B43_MMIO_DMA64_BASE5 0x340
+/* PIO */
+#define B43_MMIO_PIO1_BASE 0x300
+#define B43_MMIO_PIO2_BASE 0x310
+#define B43_MMIO_PIO3_BASE 0x320
+#define B43_MMIO_PIO4_BASE 0x330
+
+#define B43_MMIO_PHY_VER 0x3E0
+#define B43_MMIO_PHY_RADIO 0x3E2
+#define B43_MMIO_PHY0 0x3E6
+#define B43_MMIO_ANTENNA 0x3E8
+#define B43_MMIO_CHANNEL 0x3F0
+#define B43_MMIO_CHANNEL_EXT 0x3F4
+#define B43_MMIO_RADIO_CONTROL 0x3F6
+#define B43_MMIO_RADIO_DATA_HIGH 0x3F8
+#define B43_MMIO_RADIO_DATA_LOW 0x3FA
+#define B43_MMIO_PHY_CONTROL 0x3FC
+#define B43_MMIO_PHY_DATA 0x3FE
+#define B43_MMIO_MACFILTER_CONTROL 0x420
+#define B43_MMIO_MACFILTER_DATA 0x422
+#define B43_MMIO_RCMTA_COUNT 0x43C
+#define B43_MMIO_RADIO_HWENABLED_LO 0x49A
+#define B43_MMIO_GPIO_CONTROL 0x49C
+#define B43_MMIO_GPIO_MASK 0x49E
+#define B43_MMIO_TSF_0 0x632 /* core rev < 3 only */
+#define B43_MMIO_TSF_1 0x634 /* core rev < 3 only */
+#define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */
+#define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */
+#define B43_MMIO_RNG 0x65A
+#define B43_MMIO_POWERUP_DELAY 0x6A8
+
+/* SPROM boardflags_lo values */
+#define B43_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */
+#define B43_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */
+#define B43_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */
+#define B43_BFL_RSSI 0x0008 /* software calculates nrssi slope. */
+#define B43_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */
+#define B43_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */
+#define B43_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */
+#define B43_BFL_ENETADM 0x0080 /* has ADMtek switch */
+#define B43_BFL_ENETVLAN 0x0100 /* can do vlan */
+#define B43_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */
+#define B43_BFL_NOPCI 0x0400 /* leaves PCI floating */
+#define B43_BFL_FEM 0x0800 /* supports the Front End Module */
+#define B43_BFL_EXTLNA 0x1000 /* has an external LNA */
+#define B43_BFL_HGPA 0x2000 /* had high gain PA */
+#define B43_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */
+#define B43_BFL_ALTIQ 0x8000 /* alternate I/Q settings */
+
+/* GPIO register offset, in both ChipCommon and PCI core. */
+#define B43_GPIO_CONTROL 0x6c
+
+/* SHM Routing */
+enum {
+ B43_SHM_UCODE, /* Microcode memory */
+ B43_SHM_SHARED, /* Shared memory */
+ B43_SHM_SCRATCH, /* Scratch memory */
+ B43_SHM_HW, /* Internal hardware register */
+ B43_SHM_RCMTA, /* Receive match transmitter address (rev >= 5 only) */
+};
+/* SHM Routing modifiers */
+#define B43_SHM_AUTOINC_R 0x0200 /* Auto-increment address on read */
+#define B43_SHM_AUTOINC_W 0x0100 /* Auto-increment address on write */
+#define B43_SHM_AUTOINC_RW (B43_SHM_AUTOINC_R | \
+ B43_SHM_AUTOINC_W)
+
+/* Misc SHM_SHARED offsets */
+#define B43_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */
+#define B43_SHM_SH_PCTLWDPOS 0x0008
+#define B43_SHM_SH_RXPADOFF 0x0034 /* RX Padding data offset (PIO only) */
+#define B43_SHM_SH_PHYVER 0x0050 /* PHY version */
+#define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */
+#define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */
+#define B43_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */
+#define B43_SHM_SH_HOSTFHI 0x0060 /* Hostflags for ucode options (high) */
+#define B43_SHM_SH_RFATT 0x0064 /* Current radio attenuation value */
+#define B43_SHM_SH_RADAR 0x0066 /* Radar register */
+#define B43_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */
+#define B43_SHM_SH_RFRXSP1 0x0072 /* RF RX SP Register 1 */
+#define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */
+#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5Ghz channel */
+#define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */
+/* SHM_SHARED TX FIFO variables */
+#define B43_SHM_SH_SIZE01 0x0098 /* TX FIFO size for FIFO 0 (low) and 1 (high) */
+#define B43_SHM_SH_SIZE23 0x009A /* TX FIFO size for FIFO 2 and 3 */
+#define B43_SHM_SH_SIZE45 0x009C /* TX FIFO size for FIFO 4 and 5 */
+#define B43_SHM_SH_SIZE67 0x009E /* TX FIFO size for FIFO 6 and 7 */
+/* SHM_SHARED background noise */
+#define B43_SHM_SH_JSSI0 0x0088 /* Measure JSSI 0 */
+#define B43_SHM_SH_JSSI1 0x008A /* Measure JSSI 1 */
+#define B43_SHM_SH_JSSIAUX 0x008C /* Measure JSSI AUX */
+/* SHM_SHARED crypto engine */
+#define B43_SHM_SH_DEFAULTIV 0x003C /* Default IV location */
+#define B43_SHM_SH_NRRXTRANS 0x003E /* # of soft RX transmitter addresses (max 8) */
+#define B43_SHM_SH_KTP 0x0056 /* Key table pointer */
+#define B43_SHM_SH_TKIPTSCTTAK 0x0318
+#define B43_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block (v4 firmware) */
+#define B43_SHM_SH_PSM 0x05F4 /* PSM transmitter address match block (rev < 5) */
+/* SHM_SHARED WME variables */
+#define B43_SHM_SH_EDCFSTAT 0x000E /* EDCF status */
+#define B43_SHM_SH_TXFCUR 0x0030 /* TXF current index */
+#define B43_SHM_SH_EDCFQ 0x0240 /* EDCF Q info */
+/* SHM_SHARED powersave mode related */
+#define B43_SHM_SH_SLOTT 0x0010 /* Slot time */
+#define B43_SHM_SH_DTIMPER 0x0012 /* DTIM period */
+#define B43_SHM_SH_NOSLPZNATDTIM 0x004C /* NOSLPZNAT DTIM */
+/* SHM_SHARED beacon variables */
+#define B43_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */
+#define B43_SHM_SH_BTL1 0x001A /* Beacon template length 1 */
+#define B43_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */
+#define B43_SHM_SH_TIMBPOS 0x001E /* TIM B position in beacon */
+#define B43_SHM_SH_SFFBLIM 0x0044 /* Short frame fallback retry limit */
+#define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */
+#define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */
+/* SHM_SHARED ACK/CTS control */
+#define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */
+/* SHM_SHARED probe response variables */
+#define B43_SHM_SH_PRSSID 0x0160 /* Probe Response SSID */
+#define B43_SHM_SH_PRSSIDLEN 0x0048 /* Probe Response SSID length */
+#define B43_SHM_SH_PRTLEN 0x004A /* Probe Response template length */
+#define B43_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */
+#define B43_SHM_SH_PRPHYCTL 0x0188 /* Probe Response PHY TX control word */
+/* SHM_SHARED rate tables */
+#define B43_SHM_SH_OFDMDIRECT 0x01C0 /* Pointer to OFDM direct map */
+#define B43_SHM_SH_OFDMBASIC 0x01E0 /* Pointer to OFDM basic rate map */
+#define B43_SHM_SH_CCKDIRECT 0x0200 /* Pointer to CCK direct map */
+#define B43_SHM_SH_CCKBASIC 0x0220 /* Pointer to CCK basic rate map */
+/* SHM_SHARED microcode soft registers */
+#define B43_SHM_SH_UCODEREV 0x0000 /* Microcode revision */
+#define B43_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */
+#define B43_SHM_SH_UCODEDATE 0x0004 /* Microcode date */
+#define B43_SHM_SH_UCODETIME 0x0006 /* Microcode time */
+#define B43_SHM_SH_UCODESTAT 0x0040 /* Microcode debug status code */
+#define B43_SHM_SH_UCODESTAT_INVALID 0
+#define B43_SHM_SH_UCODESTAT_INIT 1
+#define B43_SHM_SH_UCODESTAT_ACTIVE 2
+#define B43_SHM_SH_UCODESTAT_SUSP 3 /* suspended */
+#define B43_SHM_SH_UCODESTAT_SLEEP 4 /* asleep (PS) */
+#define B43_SHM_SH_MAXBFRAMES 0x0080 /* Maximum number of frames in a burst */
+#define B43_SHM_SH_SPUWKUP 0x0094 /* pre-wakeup for synth PU in us */
+#define B43_SHM_SH_PRETBTT 0x0096 /* pre-TBTT in us */
+
+/* SHM_SCRATCH offsets */
+#define B43_SHM_SC_MINCONT 0x0003 /* Minimum contention window */
+#define B43_SHM_SC_MAXCONT 0x0004 /* Maximum contention window */
+#define B43_SHM_SC_CURCONT 0x0005 /* Current contention window */
+#define B43_SHM_SC_SRLIMIT 0x0006 /* Short retry count limit */
+#define B43_SHM_SC_LRLIMIT 0x0007 /* Long retry count limit */
+#define B43_SHM_SC_DTIMC 0x0008 /* Current DTIM count */
+#define B43_SHM_SC_BTL0LEN 0x0015 /* Beacon 0 template length */
+#define B43_SHM_SC_BTL1LEN 0x0016 /* Beacon 1 template length */
+#define B43_SHM_SC_SCFB 0x0017 /* Short frame transmit count threshold for rate fallback */
+#define B43_SHM_SC_LCFB 0x0018 /* Long frame transmit count threshold for rate fallback */
+
+/* Hardware Radio Enable masks */
+#define B43_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
+#define B43_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
+/* HostFlags. See b43_hf_read/write() */
+#define B43_HF_ANTDIVHELP 0x00000001 /* ucode antenna div helper */
+#define B43_HF_SYMW 0x00000002 /* G-PHY SYM workaround */
+#define B43_HF_RXPULLW 0x00000004 /* RX pullup workaround */
+#define B43_HF_CCKBOOST 0x00000008 /* 4dB CCK power boost (exclusive with OFDM boost) */
+#define B43_HF_BTCOEX 0x00000010 /* Bluetooth coexistance */
+#define B43_HF_GDCW 0x00000020 /* G-PHY DV canceller filter bw workaround */
+#define B43_HF_OFDMPABOOST 0x00000040 /* Enable PA gain boost for OFDM */
+#define B43_HF_ACPR 0x00000080 /* Disable for Japan, channel 14 */
+#define B43_HF_EDCF 0x00000100 /* on if WME and MAC suspended */
+#define B43_HF_TSSIRPSMW 0x00000200 /* TSSI reset PSM ucode workaround */
+#define B43_HF_DSCRQ 0x00000400 /* Disable slow clock request in ucode */
+#define B43_HF_ACIW 0x00000800 /* ACI workaround: shift bits by 2 on PHY CRS */
+#define B43_HF_2060W 0x00001000 /* 2060 radio workaround */
+#define B43_HF_RADARW 0x00002000 /* Radar workaround */
+#define B43_HF_USEDEFKEYS 0x00004000 /* Enable use of default keys */
+#define B43_HF_BT4PRIOCOEX 0x00010000 /* Bluetooth 2-priority coexistance */
+#define B43_HF_FWKUP 0x00020000 /* Fast wake-up ucode */
+#define B43_HF_VCORECALC 0x00040000 /* Force VCO recalculation when powering up synthpu */
+#define B43_HF_PCISCW 0x00080000 /* PCI slow clock workaround */
+#define B43_HF_4318TSSI 0x00200000 /* 4318 TSSI */
+#define B43_HF_FBCMCFIFO 0x00400000 /* Flush bcast/mcast FIFO immediately */
+#define B43_HF_HWPCTL 0x00800000 /* Enable hardwarre power control */
+#define B43_HF_BTCOEXALT 0x01000000 /* Bluetooth coexistance in alternate pins */
+#define B43_HF_TXBTCHECK 0x02000000 /* Bluetooth check during transmission */
+#define B43_HF_SKCFPUP 0x04000000 /* Skip CFP update */
+
+/* MacFilter offsets. */
+#define B43_MACFILTER_SELF 0x0000
+#define B43_MACFILTER_BSSID 0x0003
+
+/* PowerControl */
+#define B43_PCTL_IN 0xB0
+#define B43_PCTL_OUT 0xB4
+#define B43_PCTL_OUTENABLE 0xB8
+#define B43_PCTL_XTAL_POWERUP 0x40
+#define B43_PCTL_PLL_POWERDOWN 0x80
+
+/* PowerControl Clock Modes */
+#define B43_PCTL_CLK_FAST 0x00
+#define B43_PCTL_CLK_SLOW 0x01
+#define B43_PCTL_CLK_DYNAMIC 0x02
+
+#define B43_PCTL_FORCE_SLOW 0x0800
+#define B43_PCTL_FORCE_PLL 0x1000
+#define B43_PCTL_DYN_XTAL 0x2000
+
+/* PHYVersioning */
+#define B43_PHYTYPE_A 0x00
+#define B43_PHYTYPE_B 0x01
+#define B43_PHYTYPE_G 0x02
+
+/* PHYRegisters */
+#define B43_PHY_ILT_A_CTRL 0x0072
+#define B43_PHY_ILT_A_DATA1 0x0073
+#define B43_PHY_ILT_A_DATA2 0x0074
+#define B43_PHY_G_LO_CONTROL 0x0810
+#define B43_PHY_ILT_G_CTRL 0x0472
+#define B43_PHY_ILT_G_DATA1 0x0473
+#define B43_PHY_ILT_G_DATA2 0x0474
+#define B43_PHY_A_PCTL 0x007B
+#define B43_PHY_G_PCTL 0x0029
+#define B43_PHY_A_CRS 0x0029
+#define B43_PHY_RADIO_BITFIELD 0x0401
+#define B43_PHY_G_CRS 0x0429
+#define B43_PHY_NRSSILT_CTRL 0x0803
+#define B43_PHY_NRSSILT_DATA 0x0804
+
+/* RadioRegisters */
+#define B43_RADIOCTL_ID 0x01
+
+/* MAC Control bitfield */
+#define B43_MACCTL_ENABLED 0x00000001 /* MAC Enabled */
+#define B43_MACCTL_PSM_RUN 0x00000002 /* Run Microcode */
+#define B43_MACCTL_PSM_JMP0 0x00000004 /* Microcode jump to 0 */
+#define B43_MACCTL_SHM_ENABLED 0x00000100 /* SHM Enabled */
+#define B43_MACCTL_SHM_UPPER 0x00000200 /* SHM Upper */
+#define B43_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */
+#define B43_MACCTL_PSM_DBG 0x00002000 /* Microcode debugging enabled */
+#define B43_MACCTL_GPOUTSMSK 0x0000C000 /* GPOUT Select Mask */
+#define B43_MACCTL_BE 0x00010000 /* Big Endian mode */
+#define B43_MACCTL_INFRA 0x00020000 /* Infrastructure mode */
+#define B43_MACCTL_AP 0x00040000 /* AccessPoint mode */
+#define B43_MACCTL_RADIOLOCK 0x00080000 /* Radio lock */
+#define B43_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */
+#define B43_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep frames with bad PLCP */
+#define B43_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */
+#define B43_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */
+#define B43_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */
+#define B43_MACCTL_HWPS 0x02000000 /* Hardware Power Saving */
+#define B43_MACCTL_AWAKE 0x04000000 /* Device is awake */
+#define B43_MACCTL_CLOSEDNET 0x08000000 /* Closed net (no SSID bcast) */
+#define B43_MACCTL_TBTTHOLD 0x10000000 /* TBTT Hold */
+#define B43_MACCTL_DISCTXSTAT 0x20000000 /* Discard TX status */
+#define B43_MACCTL_DISCPMQ 0x40000000 /* Discard Power Management Queue */
+#define B43_MACCTL_GMODE 0x80000000 /* G Mode */
+
+/* 802.11 core specific TM State Low flags */
+#define B43_TMSLOW_GMODE 0x20000000 /* G Mode Enable */
+#define B43_TMSLOW_PLLREFSEL 0x00200000 /* PLL Frequency Reference Select */
+#define B43_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Control Enable (rev >= 5) */
+#define B43_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */
+#define B43_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */
+
+/* 802.11 core specific TM State High flags */
+#define B43_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available (rev >= 5) */
+#define B43_TMSHIGH_APHY 0x00020000 /* A-PHY available (rev >= 5) */
+#define B43_TMSHIGH_GPHY 0x00010000 /* G-PHY available (rev >= 5) */
+
+/* Generic-Interrupt reasons. */
+#define B43_IRQ_MAC_SUSPENDED 0x00000001
+#define B43_IRQ_BEACON 0x00000002
+#define B43_IRQ_TBTT_INDI 0x00000004
+#define B43_IRQ_BEACON_TX_OK 0x00000008
+#define B43_IRQ_BEACON_CANCEL 0x00000010
+#define B43_IRQ_ATIM_END 0x00000020
+#define B43_IRQ_PMQ 0x00000040
+#define B43_IRQ_PIO_WORKAROUND 0x00000100
+#define B43_IRQ_MAC_TXERR 0x00000200
+#define B43_IRQ_PHY_TXERR 0x00000800
+#define B43_IRQ_PMEVENT 0x00001000
+#define B43_IRQ_TIMER0 0x00002000
+#define B43_IRQ_TIMER1 0x00004000
+#define B43_IRQ_DMA 0x00008000
+#define B43_IRQ_TXFIFO_FLUSH_OK 0x00010000
+#define B43_IRQ_CCA_MEASURE_OK 0x00020000
+#define B43_IRQ_NOISESAMPLE_OK 0x00040000
+#define B43_IRQ_UCODE_DEBUG 0x08000000
+#define B43_IRQ_RFKILL 0x10000000
+#define B43_IRQ_TX_OK 0x20000000
+#define B43_IRQ_PHY_G_CHANGED 0x40000000
+#define B43_IRQ_TIMEOUT 0x80000000
+
+#define B43_IRQ_ALL 0xFFFFFFFF
+#define B43_IRQ_MASKTEMPLATE (B43_IRQ_MAC_SUSPENDED | \
+ B43_IRQ_BEACON | \
+ B43_IRQ_TBTT_INDI | \
+ B43_IRQ_ATIM_END | \
+ B43_IRQ_PMQ | \
+ B43_IRQ_MAC_TXERR | \
+ B43_IRQ_PHY_TXERR | \
+ B43_IRQ_DMA | \
+ B43_IRQ_TXFIFO_FLUSH_OK | \
+ B43_IRQ_NOISESAMPLE_OK | \
+ B43_IRQ_UCODE_DEBUG | \
+ B43_IRQ_RFKILL | \
+ B43_IRQ_TX_OK)
+
+/* Device specific rate values.
+ * The actual values defined here are (rate_in_mbps * 2).
+ * Some code depends on this. Don't change it. */
+#define B43_CCK_RATE_1MB 0x02
+#define B43_CCK_RATE_2MB 0x04
+#define B43_CCK_RATE_5MB 0x0B
+#define B43_CCK_RATE_11MB 0x16
+#define B43_OFDM_RATE_6MB 0x0C
+#define B43_OFDM_RATE_9MB 0x12
+#define B43_OFDM_RATE_12MB 0x18
+#define B43_OFDM_RATE_18MB 0x24
+#define B43_OFDM_RATE_24MB 0x30
+#define B43_OFDM_RATE_36MB 0x48
+#define B43_OFDM_RATE_48MB 0x60
+#define B43_OFDM_RATE_54MB 0x6C
+/* Convert a b43 rate value to a rate in 100kbps */
+#define B43_RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
+
+#define B43_DEFAULT_SHORT_RETRY_LIMIT 7
+#define B43_DEFAULT_LONG_RETRY_LIMIT 4
+
+/* Max size of a security key */
+#define B43_SEC_KEYSIZE 16
+/* Security algorithms. */
+enum {
+ B43_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
+ B43_SEC_ALGO_WEP40,
+ B43_SEC_ALGO_TKIP,
+ B43_SEC_ALGO_AES,
+ B43_SEC_ALGO_WEP104,
+ B43_SEC_ALGO_AES_LEGACY,
+};
+
+struct b43_dmaring;
+struct b43_pioqueue;
+
+/* The firmware file header */
+#define B43_FW_TYPE_UCODE 'u'
+#define B43_FW_TYPE_PCM 'p'
+#define B43_FW_TYPE_IV 'i'
+struct b43_fw_header {
+ /* File type */
+ u8 type;
+ /* File format version */
+ u8 ver;
+ u8 __padding[2];
+ /* Size of the data. For ucode and PCM this is in bytes.
+ * For IV this is number-of-ivs. */
+ __be32 size;
+} __attribute__((__packed__));
+
+/* Initial Value file format */
+#define B43_IV_OFFSET_MASK 0x7FFF
+#define B43_IV_32BIT 0x8000
+struct b43_iv {
+ __be16 offset_size;
+ union {
+ __be16 d16;
+ __be32 d32;
+ } data __attribute__((__packed__));
+} __attribute__((__packed__));
+
+
+#define B43_PHYMODE(phytype) (1 << (phytype))
+#define B43_PHYMODE_A B43_PHYMODE(B43_PHYTYPE_A)
+#define B43_PHYMODE_B B43_PHYMODE(B43_PHYTYPE_B)
+#define B43_PHYMODE_G B43_PHYMODE(B43_PHYTYPE_G)
+
+struct b43_phy {
+ /* Possible PHYMODEs on this PHY */
+ u8 possible_phymodes;
+ /* GMODE bit enabled? */
+ bool gmode;
+ /* Possible ieee80211 subsystem hwmodes for this PHY.
+ * Which mode is selected, depends on thr GMODE enabled bit */
+#define B43_MAX_PHYHWMODES 2
+ struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES];
+
+ /* Analog Type */
+ u8 analog;
+ /* B43_PHYTYPE_ */
+ u8 type;
+ /* PHY revision number. */
+ u8 rev;
+
+ /* Radio versioning */
+ u16 radio_manuf; /* Radio manufacturer */
+ u16 radio_ver; /* Radio version */
+ u8 radio_rev; /* Radio revision */
+
+ bool locked; /* Only used in b43_phy_{un}lock() */
+ bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */
+
+ /* ACI (adjacent channel interference) flags. */
+ bool aci_enable;
+ bool aci_wlan_automatic;
+ bool aci_hw_rssi;
+
+ /* Radio switched on/off */
+ bool radio_on;
+ struct {
+ /* Values saved when turning the radio off.
+ * They are needed when turning it on again. */
+ bool valid;
+ u16 rfover;
+ u16 rfoverval;
+ } radio_off_context;
+
+ u16 minlowsig[2];
+ u16 minlowsigpos[2];
+
+ /* TSSI to dBm table in use */
+ const s8 *tssi2dbm;
+ /* Target idle TSSI */
+ int tgt_idle_tssi;
+ /* Current idle TSSI */
+ int cur_idle_tssi;
+
+ /* LocalOscillator control values. */
+ struct b43_txpower_lo_control *lo_control;
+ /* Values from b43_calc_loopback_gain() */
+ s16 max_lb_gain; /* Maximum Loopback gain in hdB */
+ s16 trsw_rx_gain; /* TRSW RX gain in hdB */
+ s16 lna_lod_gain; /* LNA lod */
+ s16 lna_gain; /* LNA */
+ s16 pga_gain; /* PGA */
+
+ /* PHY lock for core.rev < 3
+ * This lock is only used by b43_phy_{un}lock()
+ */
+ spinlock_t lock;
+
+ /* Desired TX power level (in dBm).
+ * This is set by the user and adjusted in b43_phy_xmitpower(). */
+ u8 power_level;
+ /* A-PHY TX Power control value. */
+ u16 txpwr_offset;
+
+ /* Current TX power level attenuation control values */
+ struct b43_bbatt bbatt;
+ struct b43_rfatt rfatt;
+ u8 tx_control; /* B43_TXCTL_XXX */
+#ifdef CONFIG_B43_DEBUG
+ bool manual_txpower_control; /* Manual TX-power control enabled? */
+#endif
+ /* Hardware Power Control enabled? */
+ bool hardware_power_control;
+
+ /* Current Interference Mitigation mode */
+ int interfmode;
+ /* Stack of saved values from the Interference Mitigation code.
+ * Each value in the stack is layed out as follows:
+ * bit 0-11: offset
+ * bit 12-15: register ID
+ * bit 16-32: value
+ * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
+ */
+#define B43_INTERFSTACK_SIZE 26
+ u32 interfstack[B43_INTERFSTACK_SIZE]; //FIXME: use a data structure
+
+ /* Saved values from the NRSSI Slope calculation */
+ s16 nrssi[2];
+ s32 nrssislope;
+ /* In memory nrssi lookup table. */
+ s8 nrssi_lt[64];
+
+ /* current channel */
+ u8 channel;
+
+ u16 lofcal;
+
+ u16 initval; //FIXME rename?
+};
+
+/* Data structures for DMA transmission, per 80211 core. */
+struct b43_dma {
+ struct b43_dmaring *tx_ring0;
+ struct b43_dmaring *tx_ring1;
+ struct b43_dmaring *tx_ring2;
+ struct b43_dmaring *tx_ring3;
+ struct b43_dmaring *tx_ring4;
+ struct b43_dmaring *tx_ring5;
+
+ struct b43_dmaring *rx_ring0;
+ struct b43_dmaring *rx_ring3; /* only available on core.rev < 5 */
+};
+
+/* Data structures for PIO transmission, per 80211 core. */
+struct b43_pio {
+ struct b43_pioqueue *queue0;
+ struct b43_pioqueue *queue1;
+ struct b43_pioqueue *queue2;
+ struct b43_pioqueue *queue3;
+};
+
+/* Context information for a noise calculation (Link Quality). */
+struct b43_noise_calculation {
+ u8 channel_at_start;
+ bool calculation_running;
+ u8 nr_samples;
+ s8 samples[8][4];
+};
+
+struct b43_stats {
+ u8 link_noise;
+ /* Store the last TX/RX times here for updating the leds. */
+ unsigned long last_tx;
+ unsigned long last_rx;
+};
+
+struct b43_key {
+ /* If keyconf is NULL, this key is disabled.
+ * keyconf is a cookie. Don't derefenrence it outside of the set_key
+ * path, because b43 doesn't own it. */
+ struct ieee80211_key_conf *keyconf;
+ u8 algorithm;
+};
+
+struct b43_wldev;
+
+/* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */
+struct b43_wl {
+ /* Pointer to the active wireless device on this chip */
+ struct b43_wldev *current_dev;
+ /* Pointer to the ieee80211 hardware data structure */
+ struct ieee80211_hw *hw;
+
+ spinlock_t irq_lock;
+ struct mutex mutex;
+ spinlock_t leds_lock;
+
+ /* We can only have one operating interface (802.11 core)
+ * at a time. General information about this interface follows.
+ */
+
+ /* Opaque ID of the operating interface from the ieee80211
+ * subsystem. Do not modify.
+ */
+ int if_id;
+ /* The MAC address of the operating interface. */
+ u8 mac_addr[ETH_ALEN];
+ /* Current BSSID */
+ u8 bssid[ETH_ALEN];
+ /* Interface type. (IEEE80211_IF_TYPE_XXX) */
+ int if_type;
+ /* Is the card operating in AP, STA or IBSS mode? */
+ bool operating;
+ /* filter flags */
+ unsigned int filter_flags;
+ /* Stats about the wireless interface */
+ struct ieee80211_low_level_stats ieee_stats;
+
+ struct hwrng rng;
+ u8 rng_initialized;
+ char rng_name[30 + 1];
+
+ /* The RF-kill button */
+ struct b43_rfkill rfkill;
+
+ /* List of all wireless devices on this chip */
+ struct list_head devlist;
+ u8 nr_devs;
+};
+
+/* Pointers to the firmware data and meta information about it. */
+struct b43_firmware {
+ /* Microcode */
+ const struct firmware *ucode;
+ /* PCM code */
+ const struct firmware *pcm;
+ /* Initial MMIO values for the firmware */
+ const struct firmware *initvals;
+ /* Initial MMIO values for the firmware, band-specific */
+ const struct firmware *initvals_band;
+ /* Firmware revision */
+ u16 rev;
+ /* Firmware patchlevel */
+ u16 patch;
+};
+
+/* Device (802.11 core) initialization status. */
+enum {
+ B43_STAT_UNINIT = 0, /* Uninitialized. */
+ B43_STAT_INITIALIZED = 1, /* Initialized, but not started, yet. */
+ B43_STAT_STARTED = 2, /* Up and running. */
+};
+#define b43_status(wldev) atomic_read(&(wldev)->__init_status)
+#define b43_set_status(wldev, stat) do { \
+ atomic_set(&(wldev)->__init_status, (stat)); \
+ smp_wmb(); \
+ } while (0)
+
+/* XXX--- HOW LOCKING WORKS IN B43 ---XXX
+ *
+ * You should always acquire both, wl->mutex and wl->irq_lock unless:
+ * - You don't need to acquire wl->irq_lock, if the interface is stopped.
+ * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet
+ * and packet TX path (and _ONLY_ there.)
+ */
+
+/* Data structure for one wireless device (802.11 core) */
+struct b43_wldev {
+ struct ssb_device *dev;
+ struct b43_wl *wl;
+
+ /* The device initialization status.
+ * Use b43_status() to query. */
+ atomic_t __init_status;
+ /* Saved init status for handling suspend. */
+ int suspend_init_status;
+
+ bool __using_pio; /* Internal, use b43_using_pio(). */
+ bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */
+ bool reg124_set_0x4; /* Some variable to keep track of IRQ stuff. */
+ bool short_preamble; /* TRUE, if short preamble is enabled. */
+ bool short_slot; /* TRUE, if short slot timing is enabled. */
+ bool radio_hw_enable; /* saved state of radio hardware enabled state */
+
+ /* PHY/Radio device. */
+ struct b43_phy phy;
+ union {
+ /* DMA engines. */
+ struct b43_dma dma;
+ /* PIO engines. */
+ struct b43_pio pio;
+ };
+
+ /* Various statistics about the physical device. */
+ struct b43_stats stats;
+
+ /* The device LEDs. */
+ struct b43_led led_tx;
+ struct b43_led led_rx;
+ struct b43_led led_assoc;
+ struct b43_led led_radio;
+
+ /* Reason code of the last interrupt. */
+ u32 irq_reason;
+ u32 dma_reason[6];
+ /* saved irq enable/disable state bitfield. */
+ u32 irq_savedstate;
+ /* Link Quality calculation context. */
+ struct b43_noise_calculation noisecalc;
+ /* if > 0 MAC is suspended. if == 0 MAC is enabled. */
+ int mac_suspended;
+
+ /* Interrupt Service Routine tasklet (bottom-half) */
+ struct tasklet_struct isr_tasklet;
+
+ /* Periodic tasks */
+ struct delayed_work periodic_work;
+ unsigned int periodic_state;
+
+ struct work_struct restart_work;
+
+ /* encryption/decryption */
+ u16 ktp; /* Key table pointer */
+ u8 max_nr_keys;
+ struct b43_key key[58];
+
+ /* Cached beacon template while uploading the template. */
+ struct sk_buff *cached_beacon;
+
+ /* Firmware data */
+ struct b43_firmware fw;
+
+ /* Devicelist in struct b43_wl (all 802.11 cores) */
+ struct list_head list;
+
+ /* Debugging stuff follows. */
+#ifdef CONFIG_B43_DEBUG
+ struct b43_dfsentry *dfsentry;
+#endif
+};
+
+static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
+{
+ return hw->priv;
+}
+
+/* Helper function, which returns a boolean.
+ * TRUE, if PIO is used; FALSE, if DMA is used.
+ */
+#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
+static inline int b43_using_pio(struct b43_wldev *dev)
+{
+ return dev->__using_pio;
+}
+#elif defined(CONFIG_B43_DMA)
+static inline int b43_using_pio(struct b43_wldev *dev)
+{
+ return 0;
+}
+#elif defined(CONFIG_B43_PIO)
+static inline int b43_using_pio(struct b43_wldev *dev)
+{
+ return 1;
+}
+#else
+# error "Using neither DMA nor PIO? Confused..."
+#endif
+
+static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ return ssb_get_drvdata(ssb_dev);
+}
+
+/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */
+static inline int b43_is_mode(struct b43_wl *wl, int type)
+{
+ return (wl->operating && wl->if_type == type);
+}
+
+static inline u16 b43_read16(struct b43_wldev *dev, u16 offset)
+{
+ return ssb_read16(dev->dev, offset);
+}
+
+static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value)
+{
+ ssb_write16(dev->dev, offset, value);
+}
+
+static inline u32 b43_read32(struct b43_wldev *dev, u16 offset)
+{
+ return ssb_read32(dev->dev, offset);
+}
+
+static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)
+{
+ ssb_write32(dev->dev, offset, value);
+}
+
+/* Message printing */
+void b43info(struct b43_wl *wl, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+void b43err(struct b43_wl *wl, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+void b43warn(struct b43_wl *wl, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+#if B43_DEBUG
+void b43dbg(struct b43_wl *wl, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+#else /* DEBUG */
+# define b43dbg(wl, fmt...) do { /* nothing */ } while (0)
+#endif /* DEBUG */
+
+/* A WARN_ON variant that vanishes when b43 debugging is disabled.
+ * This _also_ evaluates the arg with debugging disabled. */
+#if B43_DEBUG
+# define B43_WARN_ON(x) WARN_ON(x)
+#else
+static inline bool __b43_warn_on_dummy(bool x) { return x; }
+# define B43_WARN_ON(x) __b43_warn_on_dummy(unlikely(!!(x)))
+#endif
+
+/** Limit a value between two limits */
+#ifdef limit_value
+# undef limit_value
+#endif
+#define limit_value(value, min, max) \
+ ({ \
+ typeof(value) __value = (value); \
+ typeof(value) __min = (min); \
+ typeof(value) __max = (max); \
+ if (__value < __min) \
+ __value = __min; \
+ else if (__value > __max) \
+ __value = __max; \
+ __value; \
+ })
+
+/* Convert an integer to a Q5.2 value */
+#define INT_TO_Q52(i) ((i) << 2)
+/* Convert a Q5.2 value to an integer (precision loss!) */
+#define Q52_TO_INT(q52) ((q52) >> 2)
+/* Macros for printing a value in Q5.2 format */
+#define Q52_FMT "%u.%u"
+#define Q52_ARG(q52) Q52_TO_INT(q52), ((((q52) & 0x3) * 100) / 4)
+
+#endif /* B43_H_ */
diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c
new file mode 100644
index 00000000000..ef0075d9f9c
--- /dev/null
+++ b/drivers/net/wireless/b43/debugfs.c
@@ -0,0 +1,656 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ debugfs driver debugging code
+
+ Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+
+#include "b43.h"
+#include "main.h"
+#include "debugfs.h"
+#include "dma.h"
+#include "pio.h"
+#include "xmit.h"
+
+
+/* The root directory. */
+static struct dentry *rootdir;
+
+struct b43_debugfs_fops {
+ ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize);
+ int (*write)(struct b43_wldev *dev, const char *buf, size_t count);
+ struct file_operations fops;
+ /* Offset of struct b43_dfs_file in struct b43_dfsentry */
+ size_t file_struct_offset;
+ /* Take wl->irq_lock before calling read/write? */
+ bool take_irqlock;
+};
+
+static inline
+struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev,
+ const struct b43_debugfs_fops *dfops)
+{
+ void *p;
+
+ p = dev->dfsentry;
+ p += dfops->file_struct_offset;
+
+ return p;
+}
+
+
+#define fappend(fmt, x...) \
+ do { \
+ if (bufsize - count) \
+ count += snprintf(buf + count, \
+ bufsize - count, \
+ fmt , ##x); \
+ else \
+ printk(KERN_ERR "b43: fappend overflow\n"); \
+ } while (0)
+
+
+/* wl->irq_lock is locked */
+static ssize_t tsf_read_file(struct b43_wldev *dev,
+ char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ u64 tsf;
+
+ b43_tsf_read(dev, &tsf);
+ fappend("0x%08x%08x\n",
+ (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
+ (unsigned int)(tsf & 0xFFFFFFFFULL));
+
+ return count;
+}
+
+/* wl->irq_lock is locked */
+static int tsf_write_file(struct b43_wldev *dev,
+ const char *buf, size_t count)
+{
+ u64 tsf;
+
+ if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1)
+ return -EINVAL;
+ b43_tsf_write(dev, tsf);
+
+ return 0;
+}
+
+/* wl->irq_lock is locked */
+static ssize_t ucode_regs_read_file(struct b43_wldev *dev,
+ char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ fappend("r%d = 0x%04x\n", i,
+ b43_shm_read16(dev, B43_SHM_SCRATCH, i));
+ }
+
+ return count;
+}
+
+/* wl->irq_lock is locked */
+static ssize_t shm_read_file(struct b43_wldev *dev,
+ char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ int i;
+ u16 tmp;
+ __le16 *le16buf = (__le16 *)buf;
+
+ for (i = 0; i < 0x1000; i++) {
+ if (bufsize < sizeof(tmp))
+ break;
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i);
+ le16buf[i] = cpu_to_le16(tmp);
+ count += sizeof(tmp);
+ bufsize -= sizeof(tmp);
+ }
+
+ return count;
+}
+
+static ssize_t txstat_read_file(struct b43_wldev *dev,
+ char *buf, size_t bufsize)
+{
+ struct b43_txstatus_log *log = &dev->dfsentry->txstatlog;
+ ssize_t count = 0;
+ unsigned long flags;
+ int i, idx;
+ struct b43_txstatus *stat;
+
+ spin_lock_irqsave(&log->lock, flags);
+ if (log->end < 0) {
+ fappend("Nothing transmitted, yet\n");
+ goto out_unlock;
+ }
+ fappend("b43 TX status reports:\n\n"
+ "index | cookie | seq | phy_stat | frame_count | "
+ "rts_count | supp_reason | pm_indicated | "
+ "intermediate | for_ampdu | acked\n" "---\n");
+ i = log->end + 1;
+ idx = 0;
+ while (1) {
+ if (i == B43_NR_LOGGED_TXSTATUS)
+ i = 0;
+ stat = &(log->log[i]);
+ if (stat->cookie) {
+ fappend("%03d | "
+ "0x%04X | 0x%04X | 0x%02X | "
+ "0x%X | 0x%X | "
+ "%u | %u | "
+ "%u | %u | %u\n",
+ idx,
+ stat->cookie, stat->seq, stat->phy_stat,
+ stat->frame_count, stat->rts_count,
+ stat->supp_reason, stat->pm_indicated,
+ stat->intermediate, stat->for_ampdu,
+ stat->acked);
+ idx++;
+ }
+ if (i == log->end)
+ break;
+ i++;
+ }
+out_unlock:
+ spin_unlock_irqrestore(&log->lock, flags);
+
+ return count;
+}
+
+static ssize_t txpower_g_read_file(struct b43_wldev *dev,
+ char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+
+ if (dev->phy.type != B43_PHYTYPE_G) {
+ fappend("Device is not a G-PHY\n");
+ goto out;
+ }
+ fappend("Control: %s\n", dev->phy.manual_txpower_control ?
+ "MANUAL" : "AUTOMATIC");
+ fappend("Baseband attenuation: %u\n", dev->phy.bbatt.att);
+ fappend("Radio attenuation: %u\n", dev->phy.rfatt.att);
+ fappend("TX Mixer Gain: %s\n",
+ (dev->phy.tx_control & B43_TXCTL_TXMIX) ? "ON" : "OFF");
+ fappend("PA Gain 2dB: %s\n",
+ (dev->phy.tx_control & B43_TXCTL_PA2DB) ? "ON" : "OFF");
+ fappend("PA Gain 3dB: %s\n",
+ (dev->phy.tx_control & B43_TXCTL_PA3DB) ? "ON" : "OFF");
+ fappend("\n\n");
+ fappend("You can write to this file:\n");
+ fappend("Writing \"auto\" enables automatic txpower control.\n");
+ fappend
+ ("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" "
+ "enables manual txpower control.\n");
+ fappend("Example: 5 4 0 0 1\n");
+ fappend("Enables manual control with Baseband attenuation 5, "
+ "Radio attenuation 4, No TX Mixer Gain, "
+ "No PA Gain 2dB, With PA Gain 3dB.\n");
+out:
+ return count;
+}
+
+static int txpower_g_write_file(struct b43_wldev *dev,
+ const char *buf, size_t count)
+{
+ unsigned long phy_flags;
+
+ if (dev->phy.type != B43_PHYTYPE_G)
+ return -ENODEV;
+ if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) {
+ /* Automatic control */
+ dev->phy.manual_txpower_control = 0;
+ b43_phy_xmitpower(dev);
+ } else {
+ int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0;
+ /* Manual control */
+ if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt,
+ &txmix, &pa2db, &pa3db) != 5)
+ return -EINVAL;
+ b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
+ dev->phy.manual_txpower_control = 1;
+ dev->phy.bbatt.att = bbatt;
+ dev->phy.rfatt.att = rfatt;
+ dev->phy.tx_control = 0;
+ if (txmix)
+ dev->phy.tx_control |= B43_TXCTL_TXMIX;
+ if (pa2db)
+ dev->phy.tx_control |= B43_TXCTL_PA2DB;
+ if (pa3db)
+ dev->phy.tx_control |= B43_TXCTL_PA3DB;
+ b43_phy_lock(dev, phy_flags);
+ b43_radio_lock(dev);
+ b43_set_txpower_g(dev, &dev->phy.bbatt,
+ &dev->phy.rfatt, dev->phy.tx_control);
+ b43_radio_unlock(dev);
+ b43_phy_unlock(dev, phy_flags);
+ }
+
+ return 0;
+}
+
+/* wl->irq_lock is locked */
+static int restart_write_file(struct b43_wldev *dev,
+ const char *buf, size_t count)
+{
+ int err = 0;
+
+ if (count > 0 && buf[0] == '1') {
+ b43_controller_restart(dev, "manually restarted");
+ } else
+ err = -EINVAL;
+
+ return err;
+}
+
+static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize,
+ struct b43_loctl table[B43_NR_BB][B43_NR_RF])
+{
+ unsigned int i, j;
+ struct b43_loctl *ctl;
+
+ for (i = 0; i < B43_NR_BB; i++) {
+ for (j = 0; j < B43_NR_RF; j++) {
+ ctl = &(table[i][j]);
+ fappend("(bbatt %2u, rfatt %2u) -> "
+ "(I %+3d, Q %+3d, Used: %d, Calibrated: %d)\n",
+ i, j, ctl->i, ctl->q,
+ ctl->used,
+ b43_loctl_is_calibrated(ctl));
+ }
+ }
+
+ return count;
+}
+
+static ssize_t loctls_read_file(struct b43_wldev *dev,
+ char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ struct b43_txpower_lo_control *lo;
+ int i, err = 0;
+
+ if (dev->phy.type != B43_PHYTYPE_G) {
+ fappend("Device is not a G-PHY\n");
+ err = -ENODEV;
+ goto out;
+ }
+ lo = dev->phy.lo_control;
+ fappend("-- Local Oscillator calibration data --\n\n");
+ fappend("Measured: %d, Rebuild: %d, HW-power-control: %d\n",
+ lo->lo_measured,
+ lo->rebuild,
+ dev->phy.hardware_power_control);
+ fappend("TX Bias: 0x%02X, TX Magn: 0x%02X\n",
+ lo->tx_bias, lo->tx_magn);
+ fappend("Power Vector: 0x%08X%08X\n",
+ (unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32),
+ (unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL));
+ fappend("\nControl table WITH PADMIX:\n");
+ count = append_lo_table(count, buf, bufsize, lo->with_padmix);
+ fappend("\nControl table WITHOUT PADMIX:\n");
+ count = append_lo_table(count, buf, bufsize, lo->no_padmix);
+ fappend("\nUsed RF attenuation values: Value(WithPadmix flag)\n");
+ for (i = 0; i < lo->rfatt_list.len; i++) {
+ fappend("%u(%d), ",
+ lo->rfatt_list.list[i].att,
+ lo->rfatt_list.list[i].with_padmix);
+ }
+ fappend("\n");
+ fappend("\nUsed Baseband attenuation values:\n");
+ for (i = 0; i < lo->bbatt_list.len; i++) {
+ fappend("%u, ",
+ lo->bbatt_list.list[i].att);
+ }
+ fappend("\n");
+
+out:
+ return err ? err : count;
+}
+
+#undef fappend
+
+static int b43_debugfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct b43_wldev *dev;
+ struct b43_debugfs_fops *dfops;
+ struct b43_dfs_file *dfile;
+ ssize_t ret;
+ char *buf;
+ const size_t bufsize = 1024 * 128;
+ const size_t buforder = get_order(bufsize);
+ int err = 0;
+
+ if (!count)
+ return 0;
+ dev = file->private_data;
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->wl->mutex);
+ if (b43_status(dev) < B43_STAT_INITIALIZED) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
+ dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
+ if (!dfops->read) {
+ err = -ENOSYS;
+ goto out_unlock;
+ }
+ dfile = fops_to_dfs_file(dev, dfops);
+
+ if (!dfile->buffer) {
+ buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
+ if (!buf) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+ /* Sparse warns about the following memset, because it has a big
+ * size value. That warning is bogus, so I will ignore it. --mb */
+ memset(buf, 0, bufsize);
+ if (dfops->take_irqlock) {
+ spin_lock_irq(&dev->wl->irq_lock);
+ ret = dfops->read(dev, buf, bufsize);
+ spin_unlock_irq(&dev->wl->irq_lock);
+ } else
+ ret = dfops->read(dev, buf, bufsize);
+ if (ret <= 0) {
+ free_pages((unsigned long)buf, buforder);
+ err = ret;
+ goto out_unlock;
+ }
+ dfile->data_len = ret;
+ dfile->buffer = buf;
+ }
+
+ ret = simple_read_from_buffer(userbuf, count, ppos,
+ dfile->buffer,
+ dfile->data_len);
+ if (*ppos >= dfile->data_len) {
+ free_pages((unsigned long)dfile->buffer, buforder);
+ dfile->buffer = NULL;
+ dfile->data_len = 0;
+ }
+out_unlock:
+ mutex_unlock(&dev->wl->mutex);
+
+ return err ? err : ret;
+}
+
+static ssize_t b43_debugfs_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct b43_wldev *dev;
+ struct b43_debugfs_fops *dfops;
+ char *buf;
+ int err = 0;
+
+ if (!count)
+ return 0;
+ if (count > PAGE_SIZE)
+ return -E2BIG;
+ dev = file->private_data;
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->wl->mutex);
+ if (b43_status(dev) < B43_STAT_INITIALIZED) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
+ dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
+ if (!dfops->write) {
+ err = -ENOSYS;
+ goto out_unlock;
+ }
+
+ buf = (char *)get_zeroed_page(GFP_KERNEL);
+ if (!buf) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+ if (copy_from_user(buf, userbuf, count)) {
+ err = -EFAULT;
+ goto out_freepage;
+ }
+ if (dfops->take_irqlock) {
+ spin_lock_irq(&dev->wl->irq_lock);
+ err = dfops->write(dev, buf, count);
+ spin_unlock_irq(&dev->wl->irq_lock);
+ } else
+ err = dfops->write(dev, buf, count);
+ if (err)
+ goto out_freepage;
+
+out_freepage:
+ free_page((unsigned long)buf);
+out_unlock:
+ mutex_unlock(&dev->wl->mutex);
+
+ return err ? err : count;
+}
+
+
+#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \
+ static struct b43_debugfs_fops fops_##name = { \
+ .read = _read, \
+ .write = _write, \
+ .fops = { \
+ .open = b43_debugfs_open, \
+ .read = b43_debugfs_read, \
+ .write = b43_debugfs_write, \
+ }, \
+ .file_struct_offset = offsetof(struct b43_dfsentry, \
+ file_##name), \
+ .take_irqlock = _take_irqlock, \
+ }
+
+B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
+B43_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1);
+B43_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1);
+B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
+B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0);
+B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
+B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0);
+
+
+int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
+{
+ return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
+}
+
+static void b43_remove_dynamic_debug(struct b43_wldev *dev)
+{
+ struct b43_dfsentry *e = dev->dfsentry;
+ int i;
+
+ for (i = 0; i < __B43_NR_DYNDBG; i++)
+ debugfs_remove(e->dyn_debug_dentries[i]);
+}
+
+static void b43_add_dynamic_debug(struct b43_wldev *dev)
+{
+ struct b43_dfsentry *e = dev->dfsentry;
+ struct dentry *d;
+
+#define add_dyn_dbg(name, id, initstate) do { \
+ e->dyn_debug[id] = (initstate); \
+ d = debugfs_create_bool(name, 0600, e->subdir, \
+ &(e->dyn_debug[id])); \
+ if (!IS_ERR(d)) \
+ e->dyn_debug_dentries[id] = d; \
+ } while (0)
+
+ add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, 0);
+ add_dyn_dbg("debug_dmaoverflow", B43_DBG_DMAOVERFLOW, 0);
+ add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0);
+ add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0);
+ add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
+
+#undef add_dyn_dbg
+}
+
+void b43_debugfs_add_device(struct b43_wldev *dev)
+{
+ struct b43_dfsentry *e;
+ struct b43_txstatus_log *log;
+ char devdir[16];
+
+ B43_WARN_ON(!dev);
+ e = kzalloc(sizeof(*e), GFP_KERNEL);
+ if (!e) {
+ b43err(dev->wl, "debugfs: add device OOM\n");
+ return;
+ }
+ e->dev = dev;
+ log = &e->txstatlog;
+ log->log = kcalloc(B43_NR_LOGGED_TXSTATUS,
+ sizeof(struct b43_txstatus), GFP_KERNEL);
+ if (!log->log) {
+ b43err(dev->wl, "debugfs: add device txstatus OOM\n");
+ kfree(e);
+ return;
+ }
+ log->end = -1;
+ spin_lock_init(&log->lock);
+
+ dev->dfsentry = e;
+
+ snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
+ e->subdir = debugfs_create_dir(devdir, rootdir);
+ if (!e->subdir || IS_ERR(e->subdir)) {
+ if (e->subdir == ERR_PTR(-ENODEV)) {
+ b43dbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
+ "enabled in kernel config\n");
+ } else {
+ b43err(dev->wl, "debugfs: cannot create %s directory\n",
+ devdir);
+ }
+ dev->dfsentry = NULL;
+ kfree(log->log);
+ kfree(e);
+ return;
+ }
+
+#define ADD_FILE(name, mode) \
+ do { \
+ struct dentry *d; \
+ d = debugfs_create_file(__stringify(name), \
+ mode, e->subdir, dev, \
+ &fops_##name.fops); \
+ e->file_##name.dentry = NULL; \
+ if (!IS_ERR(d)) \
+ e->file_##name.dentry = d; \
+ } while (0)
+
+
+ ADD_FILE(tsf, 0600);
+ ADD_FILE(ucode_regs, 0400);
+ ADD_FILE(shm, 0400);
+ ADD_FILE(txstat, 0400);
+ ADD_FILE(txpower_g, 0600);
+ ADD_FILE(restart, 0200);
+ ADD_FILE(loctls, 0400);
+
+#undef ADD_FILE
+
+ b43_add_dynamic_debug(dev);
+}
+
+void b43_debugfs_remove_device(struct b43_wldev *dev)
+{
+ struct b43_dfsentry *e;
+
+ if (!dev)
+ return;
+ e = dev->dfsentry;
+ if (!e)
+ return;
+ b43_remove_dynamic_debug(dev);
+
+ debugfs_remove(e->file_tsf.dentry);
+ debugfs_remove(e->file_ucode_regs.dentry);
+ debugfs_remove(e->file_shm.dentry);
+ debugfs_remove(e->file_txstat.dentry);
+ debugfs_remove(e->file_txpower_g.dentry);
+ debugfs_remove(e->file_restart.dentry);
+ debugfs_remove(e->file_loctls.dentry);
+
+ debugfs_remove(e->subdir);
+ kfree(e->txstatlog.log);
+ kfree(e);
+}
+
+void b43_debugfs_log_txstat(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+ struct b43_dfsentry *e = dev->dfsentry;
+ struct b43_txstatus_log *log;
+ struct b43_txstatus *cur;
+ int i;
+
+ if (!e)
+ return;
+ log = &e->txstatlog;
+ B43_WARN_ON(!irqs_disabled());
+ spin_lock(&log->lock);
+ i = log->end + 1;
+ if (i == B43_NR_LOGGED_TXSTATUS)
+ i = 0;
+ log->end = i;
+ cur = &(log->log[i]);
+ memcpy(cur, status, sizeof(*cur));
+ spin_unlock(&log->lock);
+}
+
+void b43_debugfs_init(void)
+{
+ rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (IS_ERR(rootdir))
+ rootdir = NULL;
+}
+
+void b43_debugfs_exit(void)
+{
+ debugfs_remove(rootdir);
+}
diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h
new file mode 100644
index 00000000000..6eebe858db5
--- /dev/null
+++ b/drivers/net/wireless/b43/debugfs.h
@@ -0,0 +1,89 @@
+#ifndef B43_DEBUGFS_H_
+#define B43_DEBUGFS_H_
+
+struct b43_wldev;
+struct b43_txstatus;
+
+enum b43_dyndbg { /* Dynamic debugging features */
+ B43_DBG_XMITPOWER,
+ B43_DBG_DMAOVERFLOW,
+ B43_DBG_DMAVERBOSE,
+ B43_DBG_PWORK_FAST,
+ B43_DBG_PWORK_STOP,
+ __B43_NR_DYNDBG,
+};
+
+#ifdef CONFIG_B43_DEBUG
+
+struct dentry;
+
+#define B43_NR_LOGGED_TXSTATUS 100
+
+struct b43_txstatus_log {
+ struct b43_txstatus *log;
+ int end;
+ spinlock_t lock;
+};
+
+struct b43_dfs_file {
+ struct dentry *dentry;
+ char *buffer;
+ size_t data_len;
+};
+
+struct b43_dfsentry {
+ struct b43_wldev *dev;
+ struct dentry *subdir;
+
+ struct b43_dfs_file file_tsf;
+ struct b43_dfs_file file_ucode_regs;
+ struct b43_dfs_file file_shm;
+ struct b43_dfs_file file_txstat;
+ struct b43_dfs_file file_txpower_g;
+ struct b43_dfs_file file_restart;
+ struct b43_dfs_file file_loctls;
+
+ struct b43_txstatus_log txstatlog;
+
+ /* Enabled/Disabled list for the dynamic debugging features. */
+ u32 dyn_debug[__B43_NR_DYNDBG];
+ /* Dentries for the dynamic debugging entries. */
+ struct dentry *dyn_debug_dentries[__B43_NR_DYNDBG];
+};
+
+int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature);
+
+void b43_debugfs_init(void);
+void b43_debugfs_exit(void);
+void b43_debugfs_add_device(struct b43_wldev *dev);
+void b43_debugfs_remove_device(struct b43_wldev *dev);
+void b43_debugfs_log_txstat(struct b43_wldev *dev,
+ const struct b43_txstatus *status);
+
+#else /* CONFIG_B43_DEBUG */
+
+static inline int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
+{
+ return 0;
+}
+
+static inline void b43_debugfs_init(void)
+{
+}
+static inline void b43_debugfs_exit(void)
+{
+}
+static inline void b43_debugfs_add_device(struct b43_wldev *dev)
+{
+}
+static inline void b43_debugfs_remove_device(struct b43_wldev *dev)
+{
+}
+static inline void b43_debugfs_log_txstat(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+}
+
+#endif /* CONFIG_B43_DEBUG */
+
+#endif /* B43_DEBUGFS_H_ */
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
new file mode 100644
index 00000000000..5e8f8ac0f1d
--- /dev/null
+++ b/drivers/net/wireless/b43/dma.c
@@ -0,0 +1,1494 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ DMA ringbuffer and descriptor allocation/management
+
+ Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+
+ Some code in this file is derived from the b44.c driver
+ Copyright (C) 2002 David S. Miller
+ Copyright (C) Pekka Pietikainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "dma.h"
+#include "main.h"
+#include "debugfs.h"
+#include "xmit.h"
+
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+
+/* 32bit DMA ops. */
+static
+struct b43_dmadesc_generic *op32_idx2desc(struct b43_dmaring *ring,
+ int slot,
+ struct b43_dmadesc_meta **meta)
+{
+ struct b43_dmadesc32 *desc;
+
+ *meta = &(ring->meta[slot]);
+ desc = ring->descbase;
+ desc = &(desc[slot]);
+
+ return (struct b43_dmadesc_generic *)desc;
+}
+
+static void op32_fill_descriptor(struct b43_dmaring *ring,
+ struct b43_dmadesc_generic *desc,
+ dma_addr_t dmaaddr, u16 bufsize,
+ int start, int end, int irq)
+{
+ struct b43_dmadesc32 *descbase = ring->descbase;
+ int slot;
+ u32 ctl;
+ u32 addr;
+ u32 addrext;
+
+ slot = (int)(&(desc->dma32) - descbase);
+ B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+
+ addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
+ addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ addr |= ssb_dma_translation(ring->dev->dev);
+ ctl = (bufsize - ring->frameoffset)
+ & B43_DMA32_DCTL_BYTECNT;
+ if (slot == ring->nr_slots - 1)
+ ctl |= B43_DMA32_DCTL_DTABLEEND;
+ if (start)
+ ctl |= B43_DMA32_DCTL_FRAMESTART;
+ if (end)
+ ctl |= B43_DMA32_DCTL_FRAMEEND;
+ if (irq)
+ ctl |= B43_DMA32_DCTL_IRQ;
+ ctl |= (addrext << B43_DMA32_DCTL_ADDREXT_SHIFT)
+ & B43_DMA32_DCTL_ADDREXT_MASK;
+
+ desc->dma32.control = cpu_to_le32(ctl);
+ desc->dma32.address = cpu_to_le32(addr);
+}
+
+static void op32_poke_tx(struct b43_dmaring *ring, int slot)
+{
+ b43_dma_write(ring, B43_DMA32_TXINDEX,
+ (u32) (slot * sizeof(struct b43_dmadesc32)));
+}
+
+static void op32_tx_suspend(struct b43_dmaring *ring)
+{
+ b43_dma_write(ring, B43_DMA32_TXCTL, b43_dma_read(ring, B43_DMA32_TXCTL)
+ | B43_DMA32_TXSUSPEND);
+}
+
+static void op32_tx_resume(struct b43_dmaring *ring)
+{
+ b43_dma_write(ring, B43_DMA32_TXCTL, b43_dma_read(ring, B43_DMA32_TXCTL)
+ & ~B43_DMA32_TXSUSPEND);
+}
+
+static int op32_get_current_rxslot(struct b43_dmaring *ring)
+{
+ u32 val;
+
+ val = b43_dma_read(ring, B43_DMA32_RXSTATUS);
+ val &= B43_DMA32_RXDPTR;
+
+ return (val / sizeof(struct b43_dmadesc32));
+}
+
+static void op32_set_current_rxslot(struct b43_dmaring *ring, int slot)
+{
+ b43_dma_write(ring, B43_DMA32_RXINDEX,
+ (u32) (slot * sizeof(struct b43_dmadesc32)));
+}
+
+static const struct b43_dma_ops dma32_ops = {
+ .idx2desc = op32_idx2desc,
+ .fill_descriptor = op32_fill_descriptor,
+ .poke_tx = op32_poke_tx,
+ .tx_suspend = op32_tx_suspend,
+ .tx_resume = op32_tx_resume,
+ .get_current_rxslot = op32_get_current_rxslot,
+ .set_current_rxslot = op32_set_current_rxslot,
+};
+
+/* 64bit DMA ops. */
+static
+struct b43_dmadesc_generic *op64_idx2desc(struct b43_dmaring *ring,
+ int slot,
+ struct b43_dmadesc_meta **meta)
+{
+ struct b43_dmadesc64 *desc;
+
+ *meta = &(ring->meta[slot]);
+ desc = ring->descbase;
+ desc = &(desc[slot]);
+
+ return (struct b43_dmadesc_generic *)desc;
+}
+
+static void op64_fill_descriptor(struct b43_dmaring *ring,
+ struct b43_dmadesc_generic *desc,
+ dma_addr_t dmaaddr, u16 bufsize,
+ int start, int end, int irq)
+{
+ struct b43_dmadesc64 *descbase = ring->descbase;
+ int slot;
+ u32 ctl0 = 0, ctl1 = 0;
+ u32 addrlo, addrhi;
+ u32 addrext;
+
+ slot = (int)(&(desc->dma64) - descbase);
+ B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+
+ addrlo = (u32) (dmaaddr & 0xFFFFFFFF);
+ addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
+ addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ addrhi |= ssb_dma_translation(ring->dev->dev);
+ if (slot == ring->nr_slots - 1)
+ ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
+ if (start)
+ ctl0 |= B43_DMA64_DCTL0_FRAMESTART;
+ if (end)
+ ctl0 |= B43_DMA64_DCTL0_FRAMEEND;
+ if (irq)
+ ctl0 |= B43_DMA64_DCTL0_IRQ;
+ ctl1 |= (bufsize - ring->frameoffset)
+ & B43_DMA64_DCTL1_BYTECNT;
+ ctl1 |= (addrext << B43_DMA64_DCTL1_ADDREXT_SHIFT)
+ & B43_DMA64_DCTL1_ADDREXT_MASK;
+
+ desc->dma64.control0 = cpu_to_le32(ctl0);
+ desc->dma64.control1 = cpu_to_le32(ctl1);
+ desc->dma64.address_low = cpu_to_le32(addrlo);
+ desc->dma64.address_high = cpu_to_le32(addrhi);
+}
+
+static void op64_poke_tx(struct b43_dmaring *ring, int slot)
+{
+ b43_dma_write(ring, B43_DMA64_TXINDEX,
+ (u32) (slot * sizeof(struct b43_dmadesc64)));
+}
+
+static void op64_tx_suspend(struct b43_dmaring *ring)
+{
+ b43_dma_write(ring, B43_DMA64_TXCTL, b43_dma_read(ring, B43_DMA64_TXCTL)
+ | B43_DMA64_TXSUSPEND);
+}
+
+static void op64_tx_resume(struct b43_dmaring *ring)
+{
+ b43_dma_write(ring, B43_DMA64_TXCTL, b43_dma_read(ring, B43_DMA64_TXCTL)
+ & ~B43_DMA64_TXSUSPEND);
+}
+
+static int op64_get_current_rxslot(struct b43_dmaring *ring)
+{
+ u32 val;
+
+ val = b43_dma_read(ring, B43_DMA64_RXSTATUS);
+ val &= B43_DMA64_RXSTATDPTR;
+
+ return (val / sizeof(struct b43_dmadesc64));
+}
+
+static void op64_set_current_rxslot(struct b43_dmaring *ring, int slot)
+{
+ b43_dma_write(ring, B43_DMA64_RXINDEX,
+ (u32) (slot * sizeof(struct b43_dmadesc64)));
+}
+
+static const struct b43_dma_ops dma64_ops = {
+ .idx2desc = op64_idx2desc,
+ .fill_descriptor = op64_fill_descriptor,
+ .poke_tx = op64_poke_tx,
+ .tx_suspend = op64_tx_suspend,
+ .tx_resume = op64_tx_resume,
+ .get_current_rxslot = op64_get_current_rxslot,
+ .set_current_rxslot = op64_set_current_rxslot,
+};
+
+static inline int free_slots(struct b43_dmaring *ring)
+{
+ return (ring->nr_slots - ring->used_slots);
+}
+
+static inline int next_slot(struct b43_dmaring *ring, int slot)
+{
+ B43_WARN_ON(!(slot >= -1 && slot <= ring->nr_slots - 1));
+ if (slot == ring->nr_slots - 1)
+ return 0;
+ return slot + 1;
+}
+
+static inline int prev_slot(struct b43_dmaring *ring, int slot)
+{
+ B43_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1));
+ if (slot == 0)
+ return ring->nr_slots - 1;
+ return slot - 1;
+}
+
+#ifdef CONFIG_B43_DEBUG
+static void update_max_used_slots(struct b43_dmaring *ring,
+ int current_used_slots)
+{
+ if (current_used_slots <= ring->max_used_slots)
+ return;
+ ring->max_used_slots = current_used_slots;
+ if (b43_debug(ring->dev, B43_DBG_DMAVERBOSE)) {
+ b43dbg(ring->dev->wl,
+ "max_used_slots increased to %d on %s ring %d\n",
+ ring->max_used_slots,
+ ring->tx ? "TX" : "RX", ring->index);
+ }
+}
+#else
+static inline
+ void update_max_used_slots(struct b43_dmaring *ring, int current_used_slots)
+{
+}
+#endif /* DEBUG */
+
+/* Request a slot for usage. */
+static inline int request_slot(struct b43_dmaring *ring)
+{
+ int slot;
+
+ B43_WARN_ON(!ring->tx);
+ B43_WARN_ON(ring->stopped);
+ B43_WARN_ON(free_slots(ring) == 0);
+
+ slot = next_slot(ring, ring->current_slot);
+ ring->current_slot = slot;
+ ring->used_slots++;
+
+ update_max_used_slots(ring, ring->used_slots);
+
+ return slot;
+}
+
+/* Mac80211-queue to b43-ring mapping */
+static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev,
+ int queue_priority)
+{
+ struct b43_dmaring *ring;
+
+/*FIXME: For now we always run on TX-ring-1 */
+ return dev->dma.tx_ring1;
+
+ /* 0 = highest priority */
+ switch (queue_priority) {
+ default:
+ B43_WARN_ON(1);
+ /* fallthrough */
+ case 0:
+ ring = dev->dma.tx_ring3;
+ break;
+ case 1:
+ ring = dev->dma.tx_ring2;
+ break;
+ case 2:
+ ring = dev->dma.tx_ring1;
+ break;
+ case 3:
+ ring = dev->dma.tx_ring0;
+ break;
+ case 4:
+ ring = dev->dma.tx_ring4;
+ break;
+ case 5:
+ ring = dev->dma.tx_ring5;
+ break;
+ }
+
+ return ring;
+}
+
+/* Bcm43xx-ring to mac80211-queue mapping */
+static inline int txring_to_priority(struct b43_dmaring *ring)
+{
+ static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, };
+
+/*FIXME: have only one queue, for now */
+ return 0;
+
+ return idx_to_prio[ring->index];
+}
+
+u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
+{
+ static const u16 map64[] = {
+ B43_MMIO_DMA64_BASE0,
+ B43_MMIO_DMA64_BASE1,
+ B43_MMIO_DMA64_BASE2,
+ B43_MMIO_DMA64_BASE3,
+ B43_MMIO_DMA64_BASE4,
+ B43_MMIO_DMA64_BASE5,
+ };
+ static const u16 map32[] = {
+ B43_MMIO_DMA32_BASE0,
+ B43_MMIO_DMA32_BASE1,
+ B43_MMIO_DMA32_BASE2,
+ B43_MMIO_DMA32_BASE3,
+ B43_MMIO_DMA32_BASE4,
+ B43_MMIO_DMA32_BASE5,
+ };
+
+ if (dma64bit) {
+ B43_WARN_ON(!(controller_idx >= 0 &&
+ controller_idx < ARRAY_SIZE(map64)));
+ return map64[controller_idx];
+ }
+ B43_WARN_ON(!(controller_idx >= 0 &&
+ controller_idx < ARRAY_SIZE(map32)));
+ return map32[controller_idx];
+}
+
+static inline
+ dma_addr_t map_descbuffer(struct b43_dmaring *ring,
+ unsigned char *buf, size_t len, int tx)
+{
+ dma_addr_t dmaaddr;
+
+ if (tx) {
+ dmaaddr = dma_map_single(ring->dev->dev->dev,
+ buf, len, DMA_TO_DEVICE);
+ } else {
+ dmaaddr = dma_map_single(ring->dev->dev->dev,
+ buf, len, DMA_FROM_DEVICE);
+ }
+
+ return dmaaddr;
+}
+
+static inline
+ void unmap_descbuffer(struct b43_dmaring *ring,
+ dma_addr_t addr, size_t len, int tx)
+{
+ if (tx) {
+ dma_unmap_single(ring->dev->dev->dev, addr, len, DMA_TO_DEVICE);
+ } else {
+ dma_unmap_single(ring->dev->dev->dev,
+ addr, len, DMA_FROM_DEVICE);
+ }
+}
+
+static inline
+ void sync_descbuffer_for_cpu(struct b43_dmaring *ring,
+ dma_addr_t addr, size_t len)
+{
+ B43_WARN_ON(ring->tx);
+ dma_sync_single_for_cpu(ring->dev->dev->dev,
+ addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+ void sync_descbuffer_for_device(struct b43_dmaring *ring,
+ dma_addr_t addr, size_t len)
+{
+ B43_WARN_ON(ring->tx);
+ dma_sync_single_for_device(ring->dev->dev->dev,
+ addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+ void free_descriptor_buffer(struct b43_dmaring *ring,
+ struct b43_dmadesc_meta *meta)
+{
+ if (meta->skb) {
+ dev_kfree_skb_any(meta->skb);
+ meta->skb = NULL;
+ }
+}
+
+static int alloc_ringmemory(struct b43_dmaring *ring)
+{
+ struct device *dev = ring->dev->dev->dev;
+
+ ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
+ &(ring->dmabase), GFP_KERNEL);
+ if (!ring->descbase) {
+ b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
+ return -ENOMEM;
+ }
+ memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE);
+
+ return 0;
+}
+
+static void free_ringmemory(struct b43_dmaring *ring)
+{
+ struct device *dev = ring->dev->dev->dev;
+
+ dma_free_coherent(dev, B43_DMA_RINGMEMSIZE,
+ ring->descbase, ring->dmabase);
+}
+
+/* Reset the RX DMA channel */
+int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+{
+ int i;
+ u32 value;
+ u16 offset;
+
+ might_sleep();
+
+ offset = dma64 ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
+ b43_write32(dev, mmio_base + offset, 0);
+ for (i = 0; i < 10; i++) {
+ offset = dma64 ? B43_DMA64_RXSTATUS : B43_DMA32_RXSTATUS;
+ value = b43_read32(dev, mmio_base + offset);
+ if (dma64) {
+ value &= B43_DMA64_RXSTAT;
+ if (value == B43_DMA64_RXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ } else {
+ value &= B43_DMA32_RXSTATE;
+ if (value == B43_DMA32_RXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ }
+ msleep(1);
+ }
+ if (i != -1) {
+ b43err(dev->wl, "DMA RX reset timed out\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/* Reset the RX DMA channel */
+int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+{
+ int i;
+ u32 value;
+ u16 offset;
+
+ might_sleep();
+
+ for (i = 0; i < 10; i++) {
+ offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+ value = b43_read32(dev, mmio_base + offset);
+ if (dma64) {
+ value &= B43_DMA64_TXSTAT;
+ if (value == B43_DMA64_TXSTAT_DISABLED ||
+ value == B43_DMA64_TXSTAT_IDLEWAIT ||
+ value == B43_DMA64_TXSTAT_STOPPED)
+ break;
+ } else {
+ value &= B43_DMA32_TXSTATE;
+ if (value == B43_DMA32_TXSTAT_DISABLED ||
+ value == B43_DMA32_TXSTAT_IDLEWAIT ||
+ value == B43_DMA32_TXSTAT_STOPPED)
+ break;
+ }
+ msleep(1);
+ }
+ offset = dma64 ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
+ b43_write32(dev, mmio_base + offset, 0);
+ for (i = 0; i < 10; i++) {
+ offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+ value = b43_read32(dev, mmio_base + offset);
+ if (dma64) {
+ value &= B43_DMA64_TXSTAT;
+ if (value == B43_DMA64_TXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ } else {
+ value &= B43_DMA32_TXSTATE;
+ if (value == B43_DMA32_TXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ }
+ msleep(1);
+ }
+ if (i != -1) {
+ b43err(dev->wl, "DMA TX reset timed out\n");
+ return -ENODEV;
+ }
+ /* ensure the reset is completed. */
+ msleep(1);
+
+ return 0;
+}
+
+static int setup_rx_descbuffer(struct b43_dmaring *ring,
+ struct b43_dmadesc_generic *desc,
+ struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
+{
+ struct b43_rxhdr_fw4 *rxhdr;
+ struct b43_hwtxstatus *txstat;
+ dma_addr_t dmaaddr;
+ struct sk_buff *skb;
+
+ B43_WARN_ON(ring->tx);
+
+ skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+ if (unlikely(!skb))
+ return -ENOMEM;
+ dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
+ if (dma_mapping_error(dmaaddr)) {
+ /* ugh. try to realloc in zone_dma */
+ gfp_flags |= GFP_DMA;
+
+ dev_kfree_skb_any(skb);
+
+ skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+ if (unlikely(!skb))
+ return -ENOMEM;
+ dmaaddr = map_descbuffer(ring, skb->data,
+ ring->rx_buffersize, 0);
+ }
+
+ if (dma_mapping_error(dmaaddr)) {
+ dev_kfree_skb_any(skb);
+ return -EIO;
+ }
+
+ meta->skb = skb;
+ meta->dmaaddr = dmaaddr;
+ ring->ops->fill_descriptor(ring, desc, dmaaddr,
+ ring->rx_buffersize, 0, 0, 0);
+
+ rxhdr = (struct b43_rxhdr_fw4 *)(skb->data);
+ rxhdr->frame_len = 0;
+ txstat = (struct b43_hwtxstatus *)(skb->data);
+ txstat->cookie = 0;
+
+ return 0;
+}
+
+/* Allocate the initial descbuffers.
+ * This is used for an RX ring only.
+ */
+static int alloc_initial_descbuffers(struct b43_dmaring *ring)
+{
+ int i, err = -ENOMEM;
+ struct b43_dmadesc_generic *desc;
+ struct b43_dmadesc_meta *meta;
+
+ for (i = 0; i < ring->nr_slots; i++) {
+ desc = ring->ops->idx2desc(ring, i, &meta);
+
+ err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
+ if (err) {
+ b43err(ring->dev->wl,
+ "Failed to allocate initial descbuffers\n");
+ goto err_unwind;
+ }
+ }
+ mb();
+ ring->used_slots = ring->nr_slots;
+ err = 0;
+ out:
+ return err;
+
+ err_unwind:
+ for (i--; i >= 0; i--) {
+ desc = ring->ops->idx2desc(ring, i, &meta);
+
+ unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
+ dev_kfree_skb(meta->skb);
+ }
+ goto out;
+}
+
+/* Do initial setup of the DMA controller.
+ * Reset the controller, write the ring busaddress
+ * and switch the "enable" bit on.
+ */
+static int dmacontroller_setup(struct b43_dmaring *ring)
+{
+ int err = 0;
+ u32 value;
+ u32 addrext;
+ u32 trans = ssb_dma_translation(ring->dev->dev);
+
+ if (ring->tx) {
+ if (ring->dma64) {
+ u64 ringbase = (u64) (ring->dmabase);
+
+ addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = B43_DMA64_TXENABLE;
+ value |= (addrext << B43_DMA64_TXADDREXT_SHIFT)
+ & B43_DMA64_TXADDREXT_MASK;
+ b43_dma_write(ring, B43_DMA64_TXCTL, value);
+ b43_dma_write(ring, B43_DMA64_TXRINGLO,
+ (ringbase & 0xFFFFFFFF));
+ b43_dma_write(ring, B43_DMA64_TXRINGHI,
+ ((ringbase >> 32) &
+ ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ } else {
+ u32 ringbase = (u32) (ring->dmabase);
+
+ addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = B43_DMA32_TXENABLE;
+ value |= (addrext << B43_DMA32_TXADDREXT_SHIFT)
+ & B43_DMA32_TXADDREXT_MASK;
+ b43_dma_write(ring, B43_DMA32_TXCTL, value);
+ b43_dma_write(ring, B43_DMA32_TXRING,
+ (ringbase & ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ }
+ } else {
+ err = alloc_initial_descbuffers(ring);
+ if (err)
+ goto out;
+ if (ring->dma64) {
+ u64 ringbase = (u64) (ring->dmabase);
+
+ addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = (ring->frameoffset << B43_DMA64_RXFROFF_SHIFT);
+ value |= B43_DMA64_RXENABLE;
+ value |= (addrext << B43_DMA64_RXADDREXT_SHIFT)
+ & B43_DMA64_RXADDREXT_MASK;
+ b43_dma_write(ring, B43_DMA64_RXCTL, value);
+ b43_dma_write(ring, B43_DMA64_RXRINGLO,
+ (ringbase & 0xFFFFFFFF));
+ b43_dma_write(ring, B43_DMA64_RXRINGHI,
+ ((ringbase >> 32) &
+ ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ b43_dma_write(ring, B43_DMA64_RXINDEX, 200);
+ } else {
+ u32 ringbase = (u32) (ring->dmabase);
+
+ addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = (ring->frameoffset << B43_DMA32_RXFROFF_SHIFT);
+ value |= B43_DMA32_RXENABLE;
+ value |= (addrext << B43_DMA32_RXADDREXT_SHIFT)
+ & B43_DMA32_RXADDREXT_MASK;
+ b43_dma_write(ring, B43_DMA32_RXCTL, value);
+ b43_dma_write(ring, B43_DMA32_RXRING,
+ (ringbase & ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ b43_dma_write(ring, B43_DMA32_RXINDEX, 200);
+ }
+ }
+
+ out:
+ return err;
+}
+
+/* Shutdown the DMA controller. */
+static void dmacontroller_cleanup(struct b43_dmaring *ring)
+{
+ if (ring->tx) {
+ b43_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
+ ring->dma64);
+ if (ring->dma64) {
+ b43_dma_write(ring, B43_DMA64_TXRINGLO, 0);
+ b43_dma_write(ring, B43_DMA64_TXRINGHI, 0);
+ } else
+ b43_dma_write(ring, B43_DMA32_TXRING, 0);
+ } else {
+ b43_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
+ ring->dma64);
+ if (ring->dma64) {
+ b43_dma_write(ring, B43_DMA64_RXRINGLO, 0);
+ b43_dma_write(ring, B43_DMA64_RXRINGHI, 0);
+ } else
+ b43_dma_write(ring, B43_DMA32_RXRING, 0);
+ }
+}
+
+static void free_all_descbuffers(struct b43_dmaring *ring)
+{
+ struct b43_dmadesc_generic *desc;
+ struct b43_dmadesc_meta *meta;
+ int i;
+
+ if (!ring->used_slots)
+ return;
+ for (i = 0; i < ring->nr_slots; i++) {
+ desc = ring->ops->idx2desc(ring, i, &meta);
+
+ if (!meta->skb) {
+ B43_WARN_ON(!ring->tx);
+ continue;
+ }
+ if (ring->tx) {
+ unmap_descbuffer(ring, meta->dmaaddr,
+ meta->skb->len, 1);
+ } else {
+ unmap_descbuffer(ring, meta->dmaaddr,
+ ring->rx_buffersize, 0);
+ }
+ free_descriptor_buffer(ring, meta);
+ }
+}
+
+static u64 supported_dma_mask(struct b43_wldev *dev)
+{
+ u32 tmp;
+ u16 mmio_base;
+
+ tmp = b43_read32(dev, SSB_TMSHIGH);
+ if (tmp & SSB_TMSHIGH_DMA64)
+ return DMA_64BIT_MASK;
+ mmio_base = b43_dmacontroller_base(0, 0);
+ b43_write32(dev, mmio_base + B43_DMA32_TXCTL, B43_DMA32_TXADDREXT_MASK);
+ tmp = b43_read32(dev, mmio_base + B43_DMA32_TXCTL);
+ if (tmp & B43_DMA32_TXADDREXT_MASK)
+ return DMA_32BIT_MASK;
+
+ return DMA_30BIT_MASK;
+}
+
+/* Main initialization function. */
+static
+struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
+ int controller_index,
+ int for_tx, int dma64)
+{
+ struct b43_dmaring *ring;
+ int err;
+ int nr_slots;
+ dma_addr_t dma_test;
+
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+ if (!ring)
+ goto out;
+
+ nr_slots = B43_RXRING_SLOTS;
+ if (for_tx)
+ nr_slots = B43_TXRING_SLOTS;
+
+ ring->meta = kcalloc(nr_slots, sizeof(struct b43_dmadesc_meta),
+ GFP_KERNEL);
+ if (!ring->meta)
+ goto err_kfree_ring;
+ if (for_tx) {
+ ring->txhdr_cache = kcalloc(nr_slots,
+ sizeof(struct b43_txhdr_fw4),
+ GFP_KERNEL);
+ if (!ring->txhdr_cache)
+ goto err_kfree_meta;
+
+ /* test for ability to dma to txhdr_cache */
+ dma_test = dma_map_single(dev->dev->dev,
+ ring->txhdr_cache,
+ sizeof(struct b43_txhdr_fw4),
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dma_test)) {
+ /* ugh realloc */
+ kfree(ring->txhdr_cache);
+ ring->txhdr_cache = kcalloc(nr_slots,
+ sizeof(struct
+ b43_txhdr_fw4),
+ GFP_KERNEL | GFP_DMA);
+ if (!ring->txhdr_cache)
+ goto err_kfree_meta;
+
+ dma_test = dma_map_single(dev->dev->dev,
+ ring->txhdr_cache,
+ sizeof(struct b43_txhdr_fw4),
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dma_test))
+ goto err_kfree_txhdr_cache;
+ }
+
+ dma_unmap_single(dev->dev->dev,
+ dma_test, sizeof(struct b43_txhdr_fw4),
+ DMA_TO_DEVICE);
+ }
+
+ ring->dev = dev;
+ ring->nr_slots = nr_slots;
+ ring->mmio_base = b43_dmacontroller_base(dma64, controller_index);
+ ring->index = controller_index;
+ ring->dma64 = !!dma64;
+ if (dma64)
+ ring->ops = &dma64_ops;
+ else
+ ring->ops = &dma32_ops;
+ if (for_tx) {
+ ring->tx = 1;
+ ring->current_slot = -1;
+ } else {
+ if (ring->index == 0) {
+ ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE;
+ ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET;
+ } else if (ring->index == 3) {
+ ring->rx_buffersize = B43_DMA3_RX_BUFFERSIZE;
+ ring->frameoffset = B43_DMA3_RX_FRAMEOFFSET;
+ } else
+ B43_WARN_ON(1);
+ }
+ spin_lock_init(&ring->lock);
+#ifdef CONFIG_B43_DEBUG
+ ring->last_injected_overflow = jiffies;
+#endif
+
+ err = alloc_ringmemory(ring);
+ if (err)
+ goto err_kfree_txhdr_cache;
+ err = dmacontroller_setup(ring);
+ if (err)
+ goto err_free_ringmemory;
+
+ out:
+ return ring;
+
+ err_free_ringmemory:
+ free_ringmemory(ring);
+ err_kfree_txhdr_cache:
+ kfree(ring->txhdr_cache);
+ err_kfree_meta:
+ kfree(ring->meta);
+ err_kfree_ring:
+ kfree(ring);
+ ring = NULL;
+ goto out;
+}
+
+/* Main cleanup function. */
+static void b43_destroy_dmaring(struct b43_dmaring *ring)
+{
+ if (!ring)
+ return;
+
+ b43dbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
+ (ring->dma64) ? "64" : "32",
+ ring->mmio_base,
+ (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots);
+ /* Device IRQs are disabled prior entering this function,
+ * so no need to take care of concurrency with rx handler stuff.
+ */
+ dmacontroller_cleanup(ring);
+ free_all_descbuffers(ring);
+ free_ringmemory(ring);
+
+ kfree(ring->txhdr_cache);
+ kfree(ring->meta);
+ kfree(ring);
+}
+
+void b43_dma_free(struct b43_wldev *dev)
+{
+ struct b43_dma *dma;
+
+ if (b43_using_pio(dev))
+ return;
+ dma = &dev->dma;
+
+ b43_destroy_dmaring(dma->rx_ring3);
+ dma->rx_ring3 = NULL;
+ b43_destroy_dmaring(dma->rx_ring0);
+ dma->rx_ring0 = NULL;
+
+ b43_destroy_dmaring(dma->tx_ring5);
+ dma->tx_ring5 = NULL;
+ b43_destroy_dmaring(dma->tx_ring4);
+ dma->tx_ring4 = NULL;
+ b43_destroy_dmaring(dma->tx_ring3);
+ dma->tx_ring3 = NULL;
+ b43_destroy_dmaring(dma->tx_ring2);
+ dma->tx_ring2 = NULL;
+ b43_destroy_dmaring(dma->tx_ring1);
+ dma->tx_ring1 = NULL;
+ b43_destroy_dmaring(dma->tx_ring0);
+ dma->tx_ring0 = NULL;
+}
+
+int b43_dma_init(struct b43_wldev *dev)
+{
+ struct b43_dma *dma = &dev->dma;
+ struct b43_dmaring *ring;
+ int err;
+ u64 dmamask;
+ int dma64 = 0;
+
+ dmamask = supported_dma_mask(dev);
+ if (dmamask == DMA_64BIT_MASK)
+ dma64 = 1;
+
+ err = ssb_dma_set_mask(dev->dev, dmamask);
+ if (err) {
+#ifdef B43_PIO
+ b43warn(dev->wl, "DMA for this device not supported. "
+ "Falling back to PIO\n");
+ dev->__using_pio = 1;
+ return -EAGAIN;
+#else
+ b43err(dev->wl, "DMA for this device not supported and "
+ "no PIO support compiled in\n");
+ return -EOPNOTSUPP;
+#endif
+ }
+
+ err = -ENOMEM;
+ /* setup TX DMA channels. */
+ ring = b43_setup_dmaring(dev, 0, 1, dma64);
+ if (!ring)
+ goto out;
+ dma->tx_ring0 = ring;
+
+ ring = b43_setup_dmaring(dev, 1, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx0;
+ dma->tx_ring1 = ring;
+
+ ring = b43_setup_dmaring(dev, 2, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx1;
+ dma->tx_ring2 = ring;
+
+ ring = b43_setup_dmaring(dev, 3, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx2;
+ dma->tx_ring3 = ring;
+
+ ring = b43_setup_dmaring(dev, 4, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx3;
+ dma->tx_ring4 = ring;
+
+ ring = b43_setup_dmaring(dev, 5, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx4;
+ dma->tx_ring5 = ring;
+
+ /* setup RX DMA channels. */
+ ring = b43_setup_dmaring(dev, 0, 0, dma64);
+ if (!ring)
+ goto err_destroy_tx5;
+ dma->rx_ring0 = ring;
+
+ if (dev->dev->id.revision < 5) {
+ ring = b43_setup_dmaring(dev, 3, 0, dma64);
+ if (!ring)
+ goto err_destroy_rx0;
+ dma->rx_ring3 = ring;
+ }
+
+ b43dbg(dev->wl, "%d-bit DMA initialized\n",
+ (dmamask == DMA_64BIT_MASK) ? 64 :
+ (dmamask == DMA_32BIT_MASK) ? 32 : 30);
+ err = 0;
+ out:
+ return err;
+
+ err_destroy_rx0:
+ b43_destroy_dmaring(dma->rx_ring0);
+ dma->rx_ring0 = NULL;
+ err_destroy_tx5:
+ b43_destroy_dmaring(dma->tx_ring5);
+ dma->tx_ring5 = NULL;
+ err_destroy_tx4:
+ b43_destroy_dmaring(dma->tx_ring4);
+ dma->tx_ring4 = NULL;
+ err_destroy_tx3:
+ b43_destroy_dmaring(dma->tx_ring3);
+ dma->tx_ring3 = NULL;
+ err_destroy_tx2:
+ b43_destroy_dmaring(dma->tx_ring2);
+ dma->tx_ring2 = NULL;
+ err_destroy_tx1:
+ b43_destroy_dmaring(dma->tx_ring1);
+ dma->tx_ring1 = NULL;
+ err_destroy_tx0:
+ b43_destroy_dmaring(dma->tx_ring0);
+ dma->tx_ring0 = NULL;
+ goto out;
+}
+
+/* Generate a cookie for the TX header. */
+static u16 generate_cookie(struct b43_dmaring *ring, int slot)
+{
+ u16 cookie = 0x1000;
+
+ /* Use the upper 4 bits of the cookie as
+ * DMA controller ID and store the slot number
+ * in the lower 12 bits.
+ * Note that the cookie must never be 0, as this
+ * is a special value used in RX path.
+ */
+ switch (ring->index) {
+ case 0:
+ cookie = 0xA000;
+ break;
+ case 1:
+ cookie = 0xB000;
+ break;
+ case 2:
+ cookie = 0xC000;
+ break;
+ case 3:
+ cookie = 0xD000;
+ break;
+ case 4:
+ cookie = 0xE000;
+ break;
+ case 5:
+ cookie = 0xF000;
+ break;
+ }
+ B43_WARN_ON(slot & ~0x0FFF);
+ cookie |= (u16) slot;
+
+ return cookie;
+}
+
+/* Inspect a cookie and find out to which controller/slot it belongs. */
+static
+struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
+{
+ struct b43_dma *dma = &dev->dma;
+ struct b43_dmaring *ring = NULL;
+
+ switch (cookie & 0xF000) {
+ case 0xA000:
+ ring = dma->tx_ring0;
+ break;
+ case 0xB000:
+ ring = dma->tx_ring1;
+ break;
+ case 0xC000:
+ ring = dma->tx_ring2;
+ break;
+ case 0xD000:
+ ring = dma->tx_ring3;
+ break;
+ case 0xE000:
+ ring = dma->tx_ring4;
+ break;
+ case 0xF000:
+ ring = dma->tx_ring5;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ *slot = (cookie & 0x0FFF);
+ B43_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots));
+
+ return ring;
+}
+
+static int dma_tx_fragment(struct b43_dmaring *ring,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ const struct b43_dma_ops *ops = ring->ops;
+ u8 *header;
+ int slot;
+ int err;
+ struct b43_dmadesc_generic *desc;
+ struct b43_dmadesc_meta *meta;
+ struct b43_dmadesc_meta *meta_hdr;
+ struct sk_buff *bounce_skb;
+
+#define SLOTS_PER_PACKET 2
+ B43_WARN_ON(skb_shinfo(skb)->nr_frags);
+
+ /* Get a slot for the header. */
+ slot = request_slot(ring);
+ desc = ops->idx2desc(ring, slot, &meta_hdr);
+ memset(meta_hdr, 0, sizeof(*meta_hdr));
+
+ header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]);
+ b43_generate_txhdr(ring->dev, header,
+ skb->data, skb->len, ctl,
+ generate_cookie(ring, slot));
+
+ meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
+ sizeof(struct b43_txhdr_fw4), 1);
+ if (dma_mapping_error(meta_hdr->dmaaddr))
+ return -EIO;
+ ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
+ sizeof(struct b43_txhdr_fw4), 1, 0, 0);
+
+ /* Get a slot for the payload. */
+ slot = request_slot(ring);
+ desc = ops->idx2desc(ring, slot, &meta);
+ memset(meta, 0, sizeof(*meta));
+
+ memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
+ meta->skb = skb;
+ meta->is_last_fragment = 1;
+
+ meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+ /* create a bounce buffer in zone_dma on mapping failure. */
+ if (dma_mapping_error(meta->dmaaddr)) {
+ bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
+ if (!bounce_skb) {
+ err = -ENOMEM;
+ goto out_unmap_hdr;
+ }
+
+ memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+ dev_kfree_skb_any(skb);
+ skb = bounce_skb;
+ meta->skb = skb;
+ meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+ if (dma_mapping_error(meta->dmaaddr)) {
+ err = -EIO;
+ goto out_free_bounce;
+ }
+ }
+
+ ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1);
+
+ /* Now transfer the whole frame. */
+ wmb();
+ ops->poke_tx(ring, next_slot(ring, slot));
+ return 0;
+
+ out_free_bounce:
+ dev_kfree_skb_any(skb);
+ out_unmap_hdr:
+ unmap_descbuffer(ring, meta_hdr->dmaaddr,
+ sizeof(struct b43_txhdr_fw4), 1);
+ return err;
+}
+
+static inline int should_inject_overflow(struct b43_dmaring *ring)
+{
+#ifdef CONFIG_B43_DEBUG
+ if (unlikely(b43_debug(ring->dev, B43_DBG_DMAOVERFLOW))) {
+ /* Check if we should inject another ringbuffer overflow
+ * to test handling of this situation in the stack. */
+ unsigned long next_overflow;
+
+ next_overflow = ring->last_injected_overflow + HZ;
+ if (time_after(jiffies, next_overflow)) {
+ ring->last_injected_overflow = jiffies;
+ b43dbg(ring->dev->wl,
+ "Injecting TX ring overflow on "
+ "DMA controller %d\n", ring->index);
+ return 1;
+ }
+ }
+#endif /* CONFIG_B43_DEBUG */
+ return 0;
+}
+
+int b43_dma_tx(struct b43_wldev *dev,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ struct b43_dmaring *ring;
+ int err = 0;
+ unsigned long flags;
+
+ ring = priority_to_txring(dev, ctl->queue);
+ spin_lock_irqsave(&ring->lock, flags);
+ B43_WARN_ON(!ring->tx);
+ if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
+ b43warn(dev->wl, "DMA queue overflow\n");
+ err = -ENOSPC;
+ goto out_unlock;
+ }
+ /* Check if the queue was stopped in mac80211,
+ * but we got called nevertheless.
+ * That would be a mac80211 bug. */
+ B43_WARN_ON(ring->stopped);
+
+ err = dma_tx_fragment(ring, skb, ctl);
+ if (unlikely(err)) {
+ b43err(dev->wl, "DMA tx mapping failure\n");
+ goto out_unlock;
+ }
+ ring->nr_tx_packets++;
+ if ((free_slots(ring) < SLOTS_PER_PACKET) ||
+ should_inject_overflow(ring)) {
+ /* This TX ring is full. */
+ ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
+ ring->stopped = 1;
+ if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
+ b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
+ }
+ }
+ out_unlock:
+ spin_unlock_irqrestore(&ring->lock, flags);
+
+ return err;
+}
+
+void b43_dma_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+ const struct b43_dma_ops *ops;
+ struct b43_dmaring *ring;
+ struct b43_dmadesc_generic *desc;
+ struct b43_dmadesc_meta *meta;
+ int slot;
+
+ ring = parse_cookie(dev, status->cookie, &slot);
+ if (unlikely(!ring))
+ return;
+ B43_WARN_ON(!irqs_disabled());
+ spin_lock(&ring->lock);
+
+ B43_WARN_ON(!ring->tx);
+ ops = ring->ops;
+ while (1) {
+ B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+ desc = ops->idx2desc(ring, slot, &meta);
+
+ if (meta->skb)
+ unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len,
+ 1);
+ else
+ unmap_descbuffer(ring, meta->dmaaddr,
+ sizeof(struct b43_txhdr_fw4), 1);
+
+ if (meta->is_last_fragment) {
+ B43_WARN_ON(!meta->skb);
+ /* Call back to inform the ieee80211 subsystem about the
+ * status of the transmission.
+ * Some fields of txstat are already filled in dma_tx().
+ */
+ if (status->acked) {
+ meta->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+ } else {
+ if (!(meta->txstat.control.flags
+ & IEEE80211_TXCTL_NO_ACK))
+ meta->txstat.excessive_retries = 1;
+ }
+ if (status->frame_count == 0) {
+ /* The frame was not transmitted at all. */
+ meta->txstat.retry_count = 0;
+ } else
+ meta->txstat.retry_count = status->frame_count - 1;
+ ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
+ &(meta->txstat));
+ /* skb is freed by ieee80211_tx_status_irqsafe() */
+ meta->skb = NULL;
+ } else {
+ /* No need to call free_descriptor_buffer here, as
+ * this is only the txhdr, which is not allocated.
+ */
+ B43_WARN_ON(meta->skb);
+ }
+
+ /* Everything unmapped and free'd. So it's not used anymore. */
+ ring->used_slots--;
+
+ if (meta->is_last_fragment)
+ break;
+ slot = next_slot(ring, slot);
+ }
+ dev->stats.last_tx = jiffies;
+ if (ring->stopped) {
+ B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
+ ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
+ ring->stopped = 0;
+ if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
+ b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index);
+ }
+ }
+
+ spin_unlock(&ring->lock);
+}
+
+void b43_dma_get_tx_stats(struct b43_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ const int nr_queues = dev->wl->hw->queues;
+ struct b43_dmaring *ring;
+ struct ieee80211_tx_queue_stats_data *data;
+ unsigned long flags;
+ int i;
+
+ for (i = 0; i < nr_queues; i++) {
+ data = &(stats->data[i]);
+ ring = priority_to_txring(dev, i);
+
+ spin_lock_irqsave(&ring->lock, flags);
+ data->len = ring->used_slots / SLOTS_PER_PACKET;
+ data->limit = ring->nr_slots / SLOTS_PER_PACKET;
+ data->count = ring->nr_tx_packets;
+ spin_unlock_irqrestore(&ring->lock, flags);
+ }
+}
+
+static void dma_rx(struct b43_dmaring *ring, int *slot)
+{
+ const struct b43_dma_ops *ops = ring->ops;
+ struct b43_dmadesc_generic *desc;
+ struct b43_dmadesc_meta *meta;
+ struct b43_rxhdr_fw4 *rxhdr;
+ struct sk_buff *skb;
+ u16 len;
+ int err;
+ dma_addr_t dmaaddr;
+
+ desc = ops->idx2desc(ring, *slot, &meta);
+
+ sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
+ skb = meta->skb;
+
+ if (ring->index == 3) {
+ /* We received an xmit status. */
+ struct b43_hwtxstatus *hw = (struct b43_hwtxstatus *)skb->data;
+ int i = 0;
+
+ while (hw->cookie == 0) {
+ if (i > 100)
+ break;
+ i++;
+ udelay(2);
+ barrier();
+ }
+ b43_handle_hwtxstatus(ring->dev, hw);
+ /* recycle the descriptor buffer. */
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
+ ring->rx_buffersize);
+
+ return;
+ }
+ rxhdr = (struct b43_rxhdr_fw4 *)skb->data;
+ len = le16_to_cpu(rxhdr->frame_len);
+ if (len == 0) {
+ int i = 0;
+
+ do {
+ udelay(2);
+ barrier();
+ len = le16_to_cpu(rxhdr->frame_len);
+ } while (len == 0 && i++ < 5);
+ if (unlikely(len == 0)) {
+ /* recycle the descriptor buffer. */
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
+ ring->rx_buffersize);
+ goto drop;
+ }
+ }
+ if (unlikely(len > ring->rx_buffersize)) {
+ /* The data did not fit into one descriptor buffer
+ * and is split over multiple buffers.
+ * This should never happen, as we try to allocate buffers
+ * big enough. So simply ignore this packet.
+ */
+ int cnt = 0;
+ s32 tmp = len;
+
+ while (1) {
+ desc = ops->idx2desc(ring, *slot, &meta);
+ /* recycle the descriptor buffer. */
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
+ ring->rx_buffersize);
+ *slot = next_slot(ring, *slot);
+ cnt++;
+ tmp -= ring->rx_buffersize;
+ if (tmp <= 0)
+ break;
+ }
+ b43err(ring->dev->wl, "DMA RX buffer too small "
+ "(len: %u, buffer: %u, nr-dropped: %d)\n",
+ len, ring->rx_buffersize, cnt);
+ goto drop;
+ }
+
+ dmaaddr = meta->dmaaddr;
+ err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
+ if (unlikely(err)) {
+ b43dbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer() failed\n");
+ sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize);
+ goto drop;
+ }
+
+ unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
+ skb_put(skb, len + ring->frameoffset);
+ skb_pull(skb, ring->frameoffset);
+
+ b43_rx(ring->dev, skb, rxhdr);
+ drop:
+ return;
+}
+
+void b43_dma_rx(struct b43_dmaring *ring)
+{
+ const struct b43_dma_ops *ops = ring->ops;
+ int slot, current_slot;
+ int used_slots = 0;
+
+ B43_WARN_ON(ring->tx);
+ current_slot = ops->get_current_rxslot(ring);
+ B43_WARN_ON(!(current_slot >= 0 && current_slot < ring->nr_slots));
+
+ slot = ring->current_slot;
+ for (; slot != current_slot; slot = next_slot(ring, slot)) {
+ dma_rx(ring, &slot);
+ update_max_used_slots(ring, ++used_slots);
+ }
+ ops->set_current_rxslot(ring, slot);
+ ring->current_slot = slot;
+}
+
+static void b43_dma_tx_suspend_ring(struct b43_dmaring *ring)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ring->lock, flags);
+ B43_WARN_ON(!ring->tx);
+ ring->ops->tx_suspend(ring);
+ spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+static void b43_dma_tx_resume_ring(struct b43_dmaring *ring)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ring->lock, flags);
+ B43_WARN_ON(!ring->tx);
+ ring->ops->tx_resume(ring);
+ spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+void b43_dma_tx_suspend(struct b43_wldev *dev)
+{
+ b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring0);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring1);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring2);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring3);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring4);
+ b43_dma_tx_suspend_ring(dev->dma.tx_ring5);
+}
+
+void b43_dma_tx_resume(struct b43_wldev *dev)
+{
+ b43_dma_tx_resume_ring(dev->dma.tx_ring5);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring4);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring3);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring2);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring1);
+ b43_dma_tx_resume_ring(dev->dma.tx_ring0);
+ b43_power_saving_ctl_bits(dev, 0);
+}
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
new file mode 100644
index 00000000000..3eed185be72
--- /dev/null
+++ b/drivers/net/wireless/b43/dma.h
@@ -0,0 +1,337 @@
+#ifndef B43_DMA_H_
+#define B43_DMA_H_
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/linkage.h>
+#include <asm/atomic.h>
+
+#include "b43.h"
+
+/* DMA-Interrupt reasons. */
+#define B43_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \
+ | (1 << 14) | (1 << 15))
+#define B43_DMAIRQ_NONFATALMASK (1 << 13)
+#define B43_DMAIRQ_RX_DONE (1 << 16)
+
+/*** 32-bit DMA Engine. ***/
+
+/* 32-bit DMA controller registers. */
+#define B43_DMA32_TXCTL 0x00
+#define B43_DMA32_TXENABLE 0x00000001
+#define B43_DMA32_TXSUSPEND 0x00000002
+#define B43_DMA32_TXLOOPBACK 0x00000004
+#define B43_DMA32_TXFLUSH 0x00000010
+#define B43_DMA32_TXADDREXT_MASK 0x00030000
+#define B43_DMA32_TXADDREXT_SHIFT 16
+#define B43_DMA32_TXRING 0x04
+#define B43_DMA32_TXINDEX 0x08
+#define B43_DMA32_TXSTATUS 0x0C
+#define B43_DMA32_TXDPTR 0x00000FFF
+#define B43_DMA32_TXSTATE 0x0000F000
+#define B43_DMA32_TXSTAT_DISABLED 0x00000000
+#define B43_DMA32_TXSTAT_ACTIVE 0x00001000
+#define B43_DMA32_TXSTAT_IDLEWAIT 0x00002000
+#define B43_DMA32_TXSTAT_STOPPED 0x00003000
+#define B43_DMA32_TXSTAT_SUSP 0x00004000
+#define B43_DMA32_TXERROR 0x000F0000
+#define B43_DMA32_TXERR_NOERR 0x00000000
+#define B43_DMA32_TXERR_PROT 0x00010000
+#define B43_DMA32_TXERR_UNDERRUN 0x00020000
+#define B43_DMA32_TXERR_BUFREAD 0x00030000
+#define B43_DMA32_TXERR_DESCREAD 0x00040000
+#define B43_DMA32_TXACTIVE 0xFFF00000
+#define B43_DMA32_RXCTL 0x10
+#define B43_DMA32_RXENABLE 0x00000001
+#define B43_DMA32_RXFROFF_MASK 0x000000FE
+#define B43_DMA32_RXFROFF_SHIFT 1
+#define B43_DMA32_RXDIRECTFIFO 0x00000100
+#define B43_DMA32_RXADDREXT_MASK 0x00030000
+#define B43_DMA32_RXADDREXT_SHIFT 16
+#define B43_DMA32_RXRING 0x14
+#define B43_DMA32_RXINDEX 0x18
+#define B43_DMA32_RXSTATUS 0x1C
+#define B43_DMA32_RXDPTR 0x00000FFF
+#define B43_DMA32_RXSTATE 0x0000F000
+#define B43_DMA32_RXSTAT_DISABLED 0x00000000
+#define B43_DMA32_RXSTAT_ACTIVE 0x00001000
+#define B43_DMA32_RXSTAT_IDLEWAIT 0x00002000
+#define B43_DMA32_RXSTAT_STOPPED 0x00003000
+#define B43_DMA32_RXERROR 0x000F0000
+#define B43_DMA32_RXERR_NOERR 0x00000000
+#define B43_DMA32_RXERR_PROT 0x00010000
+#define B43_DMA32_RXERR_OVERFLOW 0x00020000
+#define B43_DMA32_RXERR_BUFWRITE 0x00030000
+#define B43_DMA32_RXERR_DESCREAD 0x00040000
+#define B43_DMA32_RXACTIVE 0xFFF00000
+
+/* 32-bit DMA descriptor. */
+struct b43_dmadesc32 {
+ __le32 control;
+ __le32 address;
+} __attribute__ ((__packed__));
+#define B43_DMA32_DCTL_BYTECNT 0x00001FFF
+#define B43_DMA32_DCTL_ADDREXT_MASK 0x00030000
+#define B43_DMA32_DCTL_ADDREXT_SHIFT 16
+#define B43_DMA32_DCTL_DTABLEEND 0x10000000
+#define B43_DMA32_DCTL_IRQ 0x20000000
+#define B43_DMA32_DCTL_FRAMEEND 0x40000000
+#define B43_DMA32_DCTL_FRAMESTART 0x80000000
+
+/*** 64-bit DMA Engine. ***/
+
+/* 64-bit DMA controller registers. */
+#define B43_DMA64_TXCTL 0x00
+#define B43_DMA64_TXENABLE 0x00000001
+#define B43_DMA64_TXSUSPEND 0x00000002
+#define B43_DMA64_TXLOOPBACK 0x00000004
+#define B43_DMA64_TXFLUSH 0x00000010
+#define B43_DMA64_TXADDREXT_MASK 0x00030000
+#define B43_DMA64_TXADDREXT_SHIFT 16
+#define B43_DMA64_TXINDEX 0x04
+#define B43_DMA64_TXRINGLO 0x08
+#define B43_DMA64_TXRINGHI 0x0C
+#define B43_DMA64_TXSTATUS 0x10
+#define B43_DMA64_TXSTATDPTR 0x00001FFF
+#define B43_DMA64_TXSTAT 0xF0000000
+#define B43_DMA64_TXSTAT_DISABLED 0x00000000
+#define B43_DMA64_TXSTAT_ACTIVE 0x10000000
+#define B43_DMA64_TXSTAT_IDLEWAIT 0x20000000
+#define B43_DMA64_TXSTAT_STOPPED 0x30000000
+#define B43_DMA64_TXSTAT_SUSP 0x40000000
+#define B43_DMA64_TXERROR 0x14
+#define B43_DMA64_TXERRDPTR 0x0001FFFF
+#define B43_DMA64_TXERR 0xF0000000
+#define B43_DMA64_TXERR_NOERR 0x00000000
+#define B43_DMA64_TXERR_PROT 0x10000000
+#define B43_DMA64_TXERR_UNDERRUN 0x20000000
+#define B43_DMA64_TXERR_TRANSFER 0x30000000
+#define B43_DMA64_TXERR_DESCREAD 0x40000000
+#define B43_DMA64_TXERR_CORE 0x50000000
+#define B43_DMA64_RXCTL 0x20
+#define B43_DMA64_RXENABLE 0x00000001
+#define B43_DMA64_RXFROFF_MASK 0x000000FE
+#define B43_DMA64_RXFROFF_SHIFT 1
+#define B43_DMA64_RXDIRECTFIFO 0x00000100
+#define B43_DMA64_RXADDREXT_MASK 0x00030000
+#define B43_DMA64_RXADDREXT_SHIFT 16
+#define B43_DMA64_RXINDEX 0x24
+#define B43_DMA64_RXRINGLO 0x28
+#define B43_DMA64_RXRINGHI 0x2C
+#define B43_DMA64_RXSTATUS 0x30
+#define B43_DMA64_RXSTATDPTR 0x00001FFF
+#define B43_DMA64_RXSTAT 0xF0000000
+#define B43_DMA64_RXSTAT_DISABLED 0x00000000
+#define B43_DMA64_RXSTAT_ACTIVE 0x10000000
+#define B43_DMA64_RXSTAT_IDLEWAIT 0x20000000
+#define B43_DMA64_RXSTAT_STOPPED 0x30000000
+#define B43_DMA64_RXSTAT_SUSP 0x40000000
+#define B43_DMA64_RXERROR 0x34
+#define B43_DMA64_RXERRDPTR 0x0001FFFF
+#define B43_DMA64_RXERR 0xF0000000
+#define B43_DMA64_RXERR_NOERR 0x00000000
+#define B43_DMA64_RXERR_PROT 0x10000000
+#define B43_DMA64_RXERR_UNDERRUN 0x20000000
+#define B43_DMA64_RXERR_TRANSFER 0x30000000
+#define B43_DMA64_RXERR_DESCREAD 0x40000000
+#define B43_DMA64_RXERR_CORE 0x50000000
+
+/* 64-bit DMA descriptor. */
+struct b43_dmadesc64 {
+ __le32 control0;
+ __le32 control1;
+ __le32 address_low;
+ __le32 address_high;
+} __attribute__ ((__packed__));
+#define B43_DMA64_DCTL0_DTABLEEND 0x10000000
+#define B43_DMA64_DCTL0_IRQ 0x20000000
+#define B43_DMA64_DCTL0_FRAMEEND 0x40000000
+#define B43_DMA64_DCTL0_FRAMESTART 0x80000000
+#define B43_DMA64_DCTL1_BYTECNT 0x00001FFF
+#define B43_DMA64_DCTL1_ADDREXT_MASK 0x00030000
+#define B43_DMA64_DCTL1_ADDREXT_SHIFT 16
+
+struct b43_dmadesc_generic {
+ union {
+ struct b43_dmadesc32 dma32;
+ struct b43_dmadesc64 dma64;
+ } __attribute__ ((__packed__));
+} __attribute__ ((__packed__));
+
+/* Misc DMA constants */
+#define B43_DMA_RINGMEMSIZE PAGE_SIZE
+#define B43_DMA0_RX_FRAMEOFFSET 30
+#define B43_DMA3_RX_FRAMEOFFSET 0
+
+/* DMA engine tuning knobs */
+#define B43_TXRING_SLOTS 128
+#define B43_RXRING_SLOTS 64
+#define B43_DMA0_RX_BUFFERSIZE (2304 + 100)
+#define B43_DMA3_RX_BUFFERSIZE 16
+
+#ifdef CONFIG_B43_DMA
+
+struct sk_buff;
+struct b43_private;
+struct b43_txstatus;
+
+struct b43_dmadesc_meta {
+ /* The kernel DMA-able buffer. */
+ struct sk_buff *skb;
+ /* DMA base bus-address of the descriptor buffer. */
+ dma_addr_t dmaaddr;
+ /* ieee80211 TX status. Only used once per 802.11 frag. */
+ bool is_last_fragment;
+ struct ieee80211_tx_status txstat;
+};
+
+struct b43_dmaring;
+
+/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */
+struct b43_dma_ops {
+ struct b43_dmadesc_generic *(*idx2desc) (struct b43_dmaring * ring,
+ int slot,
+ struct b43_dmadesc_meta **
+ meta);
+ void (*fill_descriptor) (struct b43_dmaring * ring,
+ struct b43_dmadesc_generic * desc,
+ dma_addr_t dmaaddr, u16 bufsize, int start,
+ int end, int irq);
+ void (*poke_tx) (struct b43_dmaring * ring, int slot);
+ void (*tx_suspend) (struct b43_dmaring * ring);
+ void (*tx_resume) (struct b43_dmaring * ring);
+ int (*get_current_rxslot) (struct b43_dmaring * ring);
+ void (*set_current_rxslot) (struct b43_dmaring * ring, int slot);
+};
+
+struct b43_dmaring {
+ /* Lowlevel DMA ops. */
+ const struct b43_dma_ops *ops;
+ /* Kernel virtual base address of the ring memory. */
+ void *descbase;
+ /* Meta data about all descriptors. */
+ struct b43_dmadesc_meta *meta;
+ /* Cache of TX headers for each slot.
+ * This is to avoid an allocation on each TX.
+ * This is NULL for an RX ring.
+ */
+ u8 *txhdr_cache;
+ /* (Unadjusted) DMA base bus-address of the ring memory. */
+ dma_addr_t dmabase;
+ /* Number of descriptor slots in the ring. */
+ int nr_slots;
+ /* Number of used descriptor slots. */
+ int used_slots;
+ /* Currently used slot in the ring. */
+ int current_slot;
+ /* Total number of packets sent. Statistics only. */
+ unsigned int nr_tx_packets;
+ /* Frameoffset in octets. */
+ u32 frameoffset;
+ /* Descriptor buffer size. */
+ u16 rx_buffersize;
+ /* The MMIO base register of the DMA controller. */
+ u16 mmio_base;
+ /* DMA controller index number (0-5). */
+ int index;
+ /* Boolean. Is this a TX ring? */
+ bool tx;
+ /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
+ bool dma64;
+ /* Boolean. Is this ring stopped at ieee80211 level? */
+ bool stopped;
+ /* Lock, only used for TX. */
+ spinlock_t lock;
+ struct b43_wldev *dev;
+#ifdef CONFIG_B43_DEBUG
+ /* Maximum number of used slots. */
+ int max_used_slots;
+ /* Last time we injected a ring overflow. */
+ unsigned long last_injected_overflow;
+#endif /* CONFIG_B43_DEBUG */
+};
+
+static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset)
+{
+ return b43_read32(ring->dev, ring->mmio_base + offset);
+}
+
+static inline
+ void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
+{
+ b43_write32(ring->dev, ring->mmio_base + offset, value);
+}
+
+int b43_dma_init(struct b43_wldev *dev);
+void b43_dma_free(struct b43_wldev *dev);
+
+int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
+ u16 dmacontroller_mmio_base, int dma64);
+int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
+ u16 dmacontroller_mmio_base, int dma64);
+
+u16 b43_dmacontroller_base(int dma64bit, int dmacontroller_idx);
+
+void b43_dma_tx_suspend(struct b43_wldev *dev);
+void b43_dma_tx_resume(struct b43_wldev *dev);
+
+void b43_dma_get_tx_stats(struct b43_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats);
+
+int b43_dma_tx(struct b43_wldev *dev,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl);
+void b43_dma_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status);
+
+void b43_dma_rx(struct b43_dmaring *ring);
+
+#else /* CONFIG_B43_DMA */
+
+static inline int b43_dma_init(struct b43_wldev *dev)
+{
+ return 0;
+}
+static inline void b43_dma_free(struct b43_wldev *dev)
+{
+}
+static inline
+ int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
+ u16 dmacontroller_mmio_base, int dma64)
+{
+ return 0;
+}
+static inline
+ int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
+ u16 dmacontroller_mmio_base, int dma64)
+{
+ return 0;
+}
+static inline
+ void b43_dma_get_tx_stats(struct b43_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+}
+static inline
+ int b43_dma_tx(struct b43_wldev *dev,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ return 0;
+}
+static inline
+ void b43_dma_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+}
+static inline void b43_dma_rx(struct b43_dmaring *ring)
+{
+}
+static inline void b43_dma_tx_suspend(struct b43_wldev *dev)
+{
+}
+static inline void b43_dma_tx_resume(struct b43_wldev *dev)
+{
+}
+
+#endif /* CONFIG_B43_DMA */
+#endif /* B43_DMA_H_ */
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c
new file mode 100644
index 00000000000..19e588582c7
--- /dev/null
+++ b/drivers/net/wireless/b43/leds.c
@@ -0,0 +1,235 @@
+/*
+
+ Broadcom B43 wireless driver
+ LED control
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "leds.h"
+
+
+static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index,
+ bool activelow)
+{
+ struct b43_wl *wl = dev->wl;
+ unsigned long flags;
+ u16 ctl;
+
+ spin_lock_irqsave(&wl->leds_lock, flags);
+ ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
+ if (activelow)
+ ctl &= ~(1 << led_index);
+ else
+ ctl |= (1 << led_index);
+ b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
+ spin_unlock_irqrestore(&wl->leds_lock, flags);
+}
+
+static void b43_led_turn_off(struct b43_wldev *dev, u8 led_index,
+ bool activelow)
+{
+ struct b43_wl *wl = dev->wl;
+ unsigned long flags;
+ u16 ctl;
+
+ spin_lock_irqsave(&wl->leds_lock, flags);
+ ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
+ if (activelow)
+ ctl |= (1 << led_index);
+ else
+ ctl &= ~(1 << led_index);
+ b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
+ spin_unlock_irqrestore(&wl->leds_lock, flags);
+}
+
+/* Callback from the LED subsystem. */
+static void b43_led_brightness_set(struct led_classdev *led_dev,
+ enum led_brightness brightness)
+{
+ struct b43_led *led = container_of(led_dev, struct b43_led, led_dev);
+ struct b43_wldev *dev = led->dev;
+ bool radio_enabled;
+
+ /* Checking the radio-enabled status here is slightly racy,
+ * but we want to avoid the locking overhead and we don't care
+ * whether the LED has the wrong state for a second. */
+ radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable);
+
+ if (brightness == LED_OFF || !radio_enabled)
+ b43_led_turn_off(dev, led->index, led->activelow);
+ else
+ b43_led_turn_on(dev, led->index, led->activelow);
+}
+
+static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
+ const char *name, char *default_trigger,
+ u8 led_index, bool activelow)
+{
+ int err;
+
+ b43_led_turn_off(dev, led_index, activelow);
+ if (led->dev)
+ return -EEXIST;
+ if (!default_trigger)
+ return -EINVAL;
+ led->dev = dev;
+ led->index = led_index;
+ led->activelow = activelow;
+ strncpy(led->name, name, sizeof(led->name));
+
+ led->led_dev.name = led->name;
+ led->led_dev.default_trigger = default_trigger;
+ led->led_dev.brightness_set = b43_led_brightness_set;
+
+ err = led_classdev_register(dev->dev->dev, &led->led_dev);
+ if (err) {
+ b43warn(dev->wl, "LEDs: Failed to register %s\n", name);
+ led->dev = NULL;
+ return err;
+ }
+ return 0;
+}
+
+static void b43_unregister_led(struct b43_led *led)
+{
+ if (!led->dev)
+ return;
+ led_classdev_unregister(&led->led_dev);
+ b43_led_turn_off(led->dev, led->index, led->activelow);
+ led->dev = NULL;
+}
+
+static void b43_map_led(struct b43_wldev *dev,
+ u8 led_index,
+ enum b43_led_behaviour behaviour,
+ bool activelow)
+{
+ struct ieee80211_hw *hw = dev->wl->hw;
+ char name[B43_LED_MAX_NAME_LEN + 1];
+
+ /* Map the b43 specific LED behaviour value to the
+ * generic LED triggers. */
+ switch (behaviour) {
+ case B43_LED_INACTIVE:
+ break;
+ case B43_LED_OFF:
+ b43_led_turn_off(dev, led_index, activelow);
+ break;
+ case B43_LED_ON:
+ b43_led_turn_on(dev, led_index, activelow);
+ break;
+ case B43_LED_ACTIVITY:
+ case B43_LED_TRANSFER:
+ case B43_LED_APTRANSFER:
+ snprintf(name, sizeof(name),
+ "b43-%s:tx", wiphy_name(hw->wiphy));
+ b43_register_led(dev, &dev->led_tx, name,
+ ieee80211_get_tx_led_name(hw),
+ led_index, activelow);
+ snprintf(name, sizeof(name),
+ "b43-%s:rx", wiphy_name(hw->wiphy));
+ b43_register_led(dev, &dev->led_rx, name,
+ ieee80211_get_rx_led_name(hw),
+ led_index, activelow);
+ break;
+ case B43_LED_RADIO_ALL:
+ case B43_LED_RADIO_A:
+ case B43_LED_RADIO_B:
+ case B43_LED_MODE_BG:
+ snprintf(name, sizeof(name),
+ "b43-%s:radio", wiphy_name(hw->wiphy));
+ b43_register_led(dev, &dev->led_radio, name,
+ b43_rfkill_led_name(dev),
+ led_index, activelow);
+ break;
+ case B43_LED_WEIRD:
+ case B43_LED_ASSOC:
+ snprintf(name, sizeof(name),
+ "b43-%s:assoc", wiphy_name(hw->wiphy));
+ b43_register_led(dev, &dev->led_assoc, name,
+ ieee80211_get_assoc_led_name(hw),
+ led_index, activelow);
+ break;
+ default:
+ b43warn(dev->wl, "LEDs: Unknown behaviour 0x%02X\n",
+ behaviour);
+ break;
+ }
+}
+
+void b43_leds_init(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ u8 sprom[4];
+ int i;
+ enum b43_led_behaviour behaviour;
+ bool activelow;
+
+ sprom[0] = bus->sprom.r1.gpio0;
+ sprom[1] = bus->sprom.r1.gpio1;
+ sprom[2] = bus->sprom.r1.gpio2;
+ sprom[3] = bus->sprom.r1.gpio3;
+
+ for (i = 0; i < 4; i++) {
+ if (sprom[i] == 0xFF) {
+ /* There is no LED information in the SPROM
+ * for this LED. Hardcode it here. */
+ activelow = 0;
+ switch (i) {
+ case 0:
+ behaviour = B43_LED_ACTIVITY;
+ activelow = 1;
+ if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
+ behaviour = B43_LED_RADIO_ALL;
+ break;
+ case 1:
+ behaviour = B43_LED_RADIO_B;
+ if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
+ behaviour = B43_LED_ASSOC;
+ break;
+ case 2:
+ behaviour = B43_LED_RADIO_A;
+ break;
+ case 3:
+ behaviour = B43_LED_OFF;
+ break;
+ default:
+ B43_WARN_ON(1);
+ return;
+ }
+ } else {
+ behaviour = sprom[i] & B43_LED_BEHAVIOUR;
+ activelow = !!(sprom[i] & B43_LED_ACTIVELOW);
+ }
+ b43_map_led(dev, i, behaviour, activelow);
+ }
+}
+
+void b43_leds_exit(struct b43_wldev *dev)
+{
+ b43_unregister_led(&dev->led_tx);
+ b43_unregister_led(&dev->led_rx);
+ b43_unregister_led(&dev->led_assoc);
+}
diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h
new file mode 100644
index 00000000000..b8b1dd52124
--- /dev/null
+++ b/drivers/net/wireless/b43/leds.h
@@ -0,0 +1,64 @@
+#ifndef B43_LEDS_H_
+#define B43_LEDS_H_
+
+struct b43_wldev;
+
+#ifdef CONFIG_B43_LEDS
+
+#include <linux/types.h>
+#include <linux/leds.h>
+
+
+#define B43_LED_MAX_NAME_LEN 31
+
+struct b43_led {
+ struct b43_wldev *dev;
+ /* The LED class device */
+ struct led_classdev led_dev;
+ /* The index number of the LED. */
+ u8 index;
+ /* If activelow is true, the LED is ON if the
+ * bit is switched off. */
+ bool activelow;
+ /* The unique name string for this LED device. */
+ char name[B43_LED_MAX_NAME_LEN + 1];
+};
+
+#define B43_LED_BEHAVIOUR 0x7F
+#define B43_LED_ACTIVELOW 0x80
+/* LED behaviour values */
+enum b43_led_behaviour {
+ B43_LED_OFF,
+ B43_LED_ON,
+ B43_LED_ACTIVITY,
+ B43_LED_RADIO_ALL,
+ B43_LED_RADIO_A,
+ B43_LED_RADIO_B,
+ B43_LED_MODE_BG,
+ B43_LED_TRANSFER,
+ B43_LED_APTRANSFER,
+ B43_LED_WEIRD, //FIXME
+ B43_LED_ASSOC,
+ B43_LED_INACTIVE,
+};
+
+void b43_leds_init(struct b43_wldev *dev);
+void b43_leds_exit(struct b43_wldev *dev);
+
+
+#else /* CONFIG_B43_LEDS */
+/* LED support disabled */
+
+struct b43_led {
+ /* empty */
+};
+
+static inline void b43_leds_init(struct b43_wldev *dev)
+{
+}
+static inline void b43_leds_exit(struct b43_wldev *dev)
+{
+}
+#endif /* CONFIG_B43_LEDS */
+
+#endif /* B43_LEDS_H_ */
diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c
new file mode 100644
index 00000000000..b14a1753a0d
--- /dev/null
+++ b/drivers/net/wireless/b43/lo.c
@@ -0,0 +1,1261 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ G PHY LO (LocalOscillator) Measuring and Control routines
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
+ Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "lo.h"
+#include "phy.h"
+#include "main.h"
+
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+
+/* Define to 1 to always calibrate all possible LO control pairs.
+ * This is a workaround until we fix the partial LO calibration optimization. */
+#define B43_CALIB_ALL_LOCTLS 1
+
+
+/* Write the LocalOscillator Control (adjust) value-pair. */
+static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 value;
+ u16 reg;
+
+ if (B43_DEBUG) {
+ if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) {
+ b43dbg(dev->wl, "Invalid LO control pair "
+ "(I: %d, Q: %d)\n", control->i, control->q);
+ dump_stack();
+ return;
+ }
+ }
+
+ value = (u8) (control->q);
+ value |= ((u8) (control->i)) << 8;
+
+ reg = (phy->type == B43_PHYTYPE_B) ? 0x002F : B43_PHY_LO_CTL;
+ b43_phy_write(dev, reg, value);
+}
+
+static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt,
+ const struct b43_bbatt *bbatt,
+ struct b43_wldev *dev)
+{
+ int err = 0;
+
+ /* Check the attenuation values against the LO control array sizes. */
+ if (unlikely(rfatt->att >= B43_NR_RF)) {
+ b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att);
+ err = -EINVAL;
+ }
+ if (unlikely(bbatt->att >= B43_NR_BB)) {
+ b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att);
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+#if !B43_CALIB_ALL_LOCTLS
+static
+struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev,
+ const struct b43_rfatt *rfatt,
+ const struct b43_bbatt *bbatt)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+
+ if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
+ return &(lo->no_padmix[0][0]); /* Just prevent a crash */
+ return &(lo->no_padmix[bbatt->att][rfatt->att]);
+}
+#endif /* !B43_CALIB_ALL_LOCTLS */
+
+struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev,
+ const struct b43_rfatt *rfatt,
+ const struct b43_bbatt *bbatt)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+
+ if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
+ return &(lo->no_padmix[0][0]); /* Just prevent a crash */
+ if (rfatt->with_padmix)
+ return &(lo->with_padmix[bbatt->att][rfatt->att]);
+ return &(lo->no_padmix[bbatt->att][rfatt->att]);
+}
+
+/* Call a function for every possible LO control value-pair. */
+static void b43_call_for_each_loctl(struct b43_wldev *dev,
+ void (*func) (struct b43_wldev *,
+ struct b43_loctl *))
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *ctl = phy->lo_control;
+ int i, j;
+
+ for (i = 0; i < B43_NR_BB; i++) {
+ for (j = 0; j < B43_NR_RF; j++)
+ func(dev, &(ctl->with_padmix[i][j]));
+ }
+ for (i = 0; i < B43_NR_BB; i++) {
+ for (j = 0; j < B43_NR_RF; j++)
+ func(dev, &(ctl->no_padmix[i][j]));
+ }
+}
+
+static u16 lo_b_r15_loop(struct b43_wldev *dev)
+{
+ int i;
+ u16 ret = 0;
+
+ for (i = 0; i < 10; i++) {
+ b43_phy_write(dev, 0x0015, 0xAFA0);
+ udelay(1);
+ b43_phy_write(dev, 0x0015, 0xEFA0);
+ udelay(10);
+ b43_phy_write(dev, 0x0015, 0xFFA0);
+ udelay(40);
+ ret += b43_phy_read(dev, 0x002C);
+ }
+
+ return ret;
+}
+
+void b43_lo_b_measure(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 regstack[12] = { 0 };
+ u16 mls;
+ u16 fval;
+ int i, j;
+
+ regstack[0] = b43_phy_read(dev, 0x0015);
+ regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0;
+
+ if (phy->radio_ver == 0x2053) {
+ regstack[2] = b43_phy_read(dev, 0x000A);
+ regstack[3] = b43_phy_read(dev, 0x002A);
+ regstack[4] = b43_phy_read(dev, 0x0035);
+ regstack[5] = b43_phy_read(dev, 0x0003);
+ regstack[6] = b43_phy_read(dev, 0x0001);
+ regstack[7] = b43_phy_read(dev, 0x0030);
+
+ regstack[8] = b43_radio_read16(dev, 0x0043);
+ regstack[9] = b43_radio_read16(dev, 0x007A);
+ regstack[10] = b43_read16(dev, 0x03EC);
+ regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0;
+
+ b43_phy_write(dev, 0x0030, 0x00FF);
+ b43_write16(dev, 0x03EC, 0x3F3F);
+ b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
+ b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
+ }
+ b43_phy_write(dev, 0x0015, 0xB000);
+ b43_phy_write(dev, 0x002B, 0x0004);
+
+ if (phy->radio_ver == 0x2053) {
+ b43_phy_write(dev, 0x002B, 0x0203);
+ b43_phy_write(dev, 0x002A, 0x08A3);
+ }
+
+ phy->minlowsig[0] = 0xFFFF;
+
+ for (i = 0; i < 4; i++) {
+ b43_radio_write16(dev, 0x0052, regstack[1] | i);
+ lo_b_r15_loop(dev);
+ }
+ for (i = 0; i < 10; i++) {
+ b43_radio_write16(dev, 0x0052, regstack[1] | i);
+ mls = lo_b_r15_loop(dev) / 10;
+ if (mls < phy->minlowsig[0]) {
+ phy->minlowsig[0] = mls;
+ phy->minlowsigpos[0] = i;
+ }
+ }
+ b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]);
+
+ phy->minlowsig[1] = 0xFFFF;
+
+ for (i = -4; i < 5; i += 2) {
+ for (j = -4; j < 5; j += 2) {
+ if (j < 0)
+ fval = (0x0100 * i) + j + 0x0100;
+ else
+ fval = (0x0100 * i) + j;
+ b43_phy_write(dev, 0x002F, fval);
+ mls = lo_b_r15_loop(dev) / 10;
+ if (mls < phy->minlowsig[1]) {
+ phy->minlowsig[1] = mls;
+ phy->minlowsigpos[1] = fval;
+ }
+ }
+ }
+ phy->minlowsigpos[1] += 0x0101;
+
+ b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
+ if (phy->radio_ver == 0x2053) {
+ b43_phy_write(dev, 0x000A, regstack[2]);
+ b43_phy_write(dev, 0x002A, regstack[3]);
+ b43_phy_write(dev, 0x0035, regstack[4]);
+ b43_phy_write(dev, 0x0003, regstack[5]);
+ b43_phy_write(dev, 0x0001, regstack[6]);
+ b43_phy_write(dev, 0x0030, regstack[7]);
+
+ b43_radio_write16(dev, 0x0043, regstack[8]);
+ b43_radio_write16(dev, 0x007A, regstack[9]);
+
+ b43_radio_write16(dev, 0x0052,
+ (b43_radio_read16(dev, 0x0052) & 0x000F)
+ | regstack[11]);
+
+ b43_write16(dev, 0x03EC, regstack[10]);
+ }
+ b43_phy_write(dev, 0x0015, regstack[0]);
+}
+
+static u16 lo_measure_feedthrough(struct b43_wldev *dev,
+ u16 lna, u16 pga, u16 trsw_rx)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 rfover;
+ u16 feedthrough;
+
+ if (phy->gmode) {
+ lna <<= B43_PHY_RFOVERVAL_LNA_SHIFT;
+ pga <<= B43_PHY_RFOVERVAL_PGA_SHIFT;
+
+ B43_WARN_ON(lna & ~B43_PHY_RFOVERVAL_LNA);
+ B43_WARN_ON(pga & ~B43_PHY_RFOVERVAL_PGA);
+/*FIXME This assertion fails B43_WARN_ON(trsw_rx & ~(B43_PHY_RFOVERVAL_TRSWRX |
+ B43_PHY_RFOVERVAL_BW));
+*/
+ trsw_rx &= (B43_PHY_RFOVERVAL_TRSWRX | B43_PHY_RFOVERVAL_BW);
+
+ /* Construct the RF Override Value */
+ rfover = B43_PHY_RFOVERVAL_UNK;
+ rfover |= pga;
+ rfover |= lna;
+ rfover |= trsw_rx;
+ if ((dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) &&
+ phy->rev > 6)
+ rfover |= B43_PHY_RFOVERVAL_EXTLNA;
+
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);
+ udelay(10);
+ rfover |= B43_PHY_RFOVERVAL_BW_LBW;
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);
+ udelay(10);
+ rfover |= B43_PHY_RFOVERVAL_BW_LPF;
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);
+ udelay(10);
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xF300);
+ } else {
+ pga |= B43_PHY_PGACTL_UNKNOWN;
+ b43_phy_write(dev, B43_PHY_PGACTL, pga);
+ udelay(10);
+ pga |= B43_PHY_PGACTL_LOWBANDW;
+ b43_phy_write(dev, B43_PHY_PGACTL, pga);
+ udelay(10);
+ pga |= B43_PHY_PGACTL_LPF;
+ b43_phy_write(dev, B43_PHY_PGACTL, pga);
+ }
+ udelay(21);
+ feedthrough = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+
+ /* This is a good place to check if we need to relax a bit,
+ * as this is the main function called regularly
+ * in the LO calibration. */
+ cond_resched();
+
+ return feedthrough;
+}
+
+/* TXCTL Register and Value Table.
+ * Returns the "TXCTL Register".
+ * "value" is the "TXCTL Value".
+ * "pad_mix_gain" is the PAD Mixer Gain.
+ */
+static u16 lo_txctl_register_table(struct b43_wldev *dev,
+ u16 * value, u16 * pad_mix_gain)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 reg, v, padmix;
+
+ if (phy->type == B43_PHYTYPE_B) {
+ v = 0x30;
+ if (phy->radio_rev <= 5) {
+ reg = 0x43;
+ padmix = 0;
+ } else {
+ reg = 0x52;
+ padmix = 5;
+ }
+ } else {
+ if (phy->rev >= 2 && phy->radio_rev == 8) {
+ reg = 0x43;
+ v = 0x10;
+ padmix = 2;
+ } else {
+ reg = 0x52;
+ v = 0x30;
+ padmix = 5;
+ }
+ }
+ if (value)
+ *value = v;
+ if (pad_mix_gain)
+ *pad_mix_gain = padmix;
+
+ return reg;
+}
+
+static void lo_measure_txctl_values(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ u16 reg, mask;
+ u16 trsw_rx, pga;
+ u16 radio_pctl_reg;
+
+ static const u8 tx_bias_values[] = {
+ 0x09, 0x08, 0x0A, 0x01, 0x00,
+ 0x02, 0x05, 0x04, 0x06,
+ };
+ static const u8 tx_magn_values[] = {
+ 0x70, 0x40,
+ };
+
+ if (!has_loopback_gain(phy)) {
+ radio_pctl_reg = 6;
+ trsw_rx = 2;
+ pga = 0;
+ } else {
+ int lb_gain; /* Loopback gain (in dB) */
+
+ trsw_rx = 0;
+ lb_gain = phy->max_lb_gain / 2;
+ if (lb_gain > 10) {
+ radio_pctl_reg = 0;
+ pga = abs(10 - lb_gain) / 6;
+ pga = limit_value(pga, 0, 15);
+ } else {
+ int cmp_val;
+ int tmp;
+
+ pga = 0;
+ cmp_val = 0x24;
+ if ((phy->rev >= 2) &&
+ (phy->radio_ver == 0x2050) && (phy->radio_rev == 8))
+ cmp_val = 0x3C;
+ tmp = lb_gain;
+ if ((10 - lb_gain) < cmp_val)
+ tmp = (10 - lb_gain);
+ if (tmp < 0)
+ tmp += 6;
+ else
+ tmp += 3;
+ cmp_val /= 4;
+ tmp /= 4;
+ if (tmp >= cmp_val)
+ radio_pctl_reg = cmp_val;
+ else
+ radio_pctl_reg = tmp;
+ }
+ }
+ b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+ & 0xFFF0) | radio_pctl_reg);
+ b43_phy_set_baseband_attenuation(dev, 2);
+
+ reg = lo_txctl_register_table(dev, &mask, NULL);
+ mask = ~mask;
+ b43_radio_write16(dev, reg, b43_radio_read16(dev, reg)
+ & mask);
+
+ if (has_tx_magnification(phy)) {
+ int i, j;
+ int feedthrough;
+ int min_feedth = 0xFFFF;
+ u8 tx_magn, tx_bias;
+
+ for (i = 0; i < ARRAY_SIZE(tx_magn_values); i++) {
+ tx_magn = tx_magn_values[i];
+ b43_radio_write16(dev, 0x52,
+ (b43_radio_read16(dev, 0x52)
+ & 0xFF0F) | tx_magn);
+ for (j = 0; j < ARRAY_SIZE(tx_bias_values); j++) {
+ tx_bias = tx_bias_values[j];
+ b43_radio_write16(dev, 0x52,
+ (b43_radio_read16(dev, 0x52)
+ & 0xFFF0) | tx_bias);
+ feedthrough =
+ lo_measure_feedthrough(dev, 0, pga,
+ trsw_rx);
+ if (feedthrough < min_feedth) {
+ lo->tx_bias = tx_bias;
+ lo->tx_magn = tx_magn;
+ min_feedth = feedthrough;
+ }
+ if (lo->tx_bias == 0)
+ break;
+ }
+ b43_radio_write16(dev, 0x52,
+ (b43_radio_read16(dev, 0x52)
+ & 0xFF00) | lo->tx_bias | lo->
+ tx_magn);
+ }
+ } else {
+ lo->tx_magn = 0;
+ lo->tx_bias = 0;
+ b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52)
+ & 0xFFF0); /* TX bias == 0 */
+ }
+}
+
+static void lo_read_power_vector(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ u16 i;
+ u64 tmp;
+ u64 power_vector = 0;
+ int rf_offset, bb_offset;
+ struct b43_loctl *loctl;
+
+ for (i = 0; i < 8; i += 2) {
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i);
+ /* Clear the top byte. We get holes in the bitmap... */
+ tmp &= 0xFF;
+ power_vector |= (tmp << (i * 8));
+ /* Clear the vector on the device. */
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0);
+ }
+
+ if (power_vector)
+ lo->power_vector = power_vector;
+ power_vector = lo->power_vector;
+
+ for (i = 0; i < 64; i++) {
+ if (power_vector & ((u64) 1ULL << i)) {
+ /* Now figure out which b43_loctl corresponds
+ * to this bit.
+ */
+ rf_offset = i / lo->rfatt_list.len;
+ bb_offset = i % lo->rfatt_list.len; //FIXME?
+ loctl =
+ b43_get_lo_g_ctl(dev,
+ &lo->rfatt_list.list[rf_offset],
+ &lo->bbatt_list.list[bb_offset]);
+ /* And mark it as "used", as the device told us
+ * through the bitmap it is using it.
+ */
+ loctl->used = 1;
+ }
+ }
+}
+
+/* 802.11/LO/GPHY/MeasuringGains */
+static void lo_measure_gain_values(struct b43_wldev *dev,
+ s16 max_rx_gain, int use_trsw_rx)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 tmp;
+
+ if (max_rx_gain < 0)
+ max_rx_gain = 0;
+
+ if (has_loopback_gain(phy)) {
+ int trsw_rx = 0;
+ int trsw_rx_gain;
+
+ if (use_trsw_rx) {
+ trsw_rx_gain = phy->trsw_rx_gain / 2;
+ if (max_rx_gain >= trsw_rx_gain) {
+ trsw_rx_gain = max_rx_gain - trsw_rx_gain;
+ trsw_rx = 0x20;
+ }
+ } else
+ trsw_rx_gain = max_rx_gain;
+ if (trsw_rx_gain < 9) {
+ phy->lna_lod_gain = 0;
+ } else {
+ phy->lna_lod_gain = 1;
+ trsw_rx_gain -= 8;
+ }
+ trsw_rx_gain = limit_value(trsw_rx_gain, 0, 0x2D);
+ phy->pga_gain = trsw_rx_gain / 3;
+ if (phy->pga_gain >= 5) {
+ phy->pga_gain -= 5;
+ phy->lna_gain = 2;
+ } else
+ phy->lna_gain = 0;
+ } else {
+ phy->lna_gain = 0;
+ phy->trsw_rx_gain = 0x20;
+ if (max_rx_gain >= 0x14) {
+ phy->lna_lod_gain = 1;
+ phy->pga_gain = 2;
+ } else if (max_rx_gain >= 0x12) {
+ phy->lna_lod_gain = 1;
+ phy->pga_gain = 1;
+ } else if (max_rx_gain >= 0xF) {
+ phy->lna_lod_gain = 1;
+ phy->pga_gain = 0;
+ } else {
+ phy->lna_lod_gain = 0;
+ phy->pga_gain = 0;
+ }
+ }
+
+ tmp = b43_radio_read16(dev, 0x7A);
+ if (phy->lna_lod_gain == 0)
+ tmp &= ~0x0008;
+ else
+ tmp |= 0x0008;
+ b43_radio_write16(dev, 0x7A, tmp);
+}
+
+struct lo_g_saved_values {
+ u8 old_channel;
+
+ /* Core registers */
+ u16 reg_3F4;
+ u16 reg_3E2;
+
+ /* PHY registers */
+ u16 phy_lo_mask;
+ u16 phy_extg_01;
+ u16 phy_dacctl_hwpctl;
+ u16 phy_dacctl;
+ u16 phy_base_14;
+ u16 phy_hpwr_tssictl;
+ u16 phy_analogover;
+ u16 phy_analogoverval;
+ u16 phy_rfover;
+ u16 phy_rfoverval;
+ u16 phy_classctl;
+ u16 phy_base_3E;
+ u16 phy_crs0;
+ u16 phy_pgactl;
+ u16 phy_base_2A;
+ u16 phy_syncctl;
+ u16 phy_base_30;
+ u16 phy_base_06;
+
+ /* Radio registers */
+ u16 radio_43;
+ u16 radio_7A;
+ u16 radio_52;
+};
+
+static void lo_measure_setup(struct b43_wldev *dev,
+ struct lo_g_saved_values *sav)
+{
+ struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ u16 tmp;
+
+ if (b43_has_hardware_pctl(phy)) {
+ sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
+ sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01));
+ sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL);
+ sav->phy_base_14 = b43_phy_read(dev, B43_PHY_BASE(0x14));
+ sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL);
+
+ b43_phy_write(dev, B43_PHY_HPWR_TSSICTL,
+ b43_phy_read(dev, B43_PHY_HPWR_TSSICTL)
+ | 0x100);
+ b43_phy_write(dev, B43_PHY_EXTG(0x01),
+ b43_phy_read(dev, B43_PHY_EXTG(0x01))
+ | 0x40);
+ b43_phy_write(dev, B43_PHY_DACCTL,
+ b43_phy_read(dev, B43_PHY_DACCTL)
+ | 0x40);
+ b43_phy_write(dev, B43_PHY_BASE(0x14),
+ b43_phy_read(dev, B43_PHY_BASE(0x14))
+ | 0x200);
+ }
+ if (phy->type == B43_PHYTYPE_B &&
+ phy->radio_ver == 0x2050 && phy->radio_rev < 6) {
+ b43_phy_write(dev, B43_PHY_BASE(0x16), 0x410);
+ b43_phy_write(dev, B43_PHY_BASE(0x17), 0x820);
+ }
+ if (!lo->rebuild && b43_has_hardware_pctl(phy))
+ lo_read_power_vector(dev);
+ if (phy->rev >= 2) {
+ sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
+ sav->phy_analogoverval =
+ b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
+ sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
+ sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+ sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
+ sav->phy_base_3E = b43_phy_read(dev, B43_PHY_BASE(0x3E));
+ sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
+
+ b43_phy_write(dev, B43_PHY_CLASSCTL,
+ b43_phy_read(dev, B43_PHY_CLASSCTL)
+ & 0xFFFC);
+ b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
+ & 0x7FFF);
+ b43_phy_write(dev, B43_PHY_ANALOGOVER,
+ b43_phy_read(dev, B43_PHY_ANALOGOVER)
+ | 0x0003);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ b43_phy_read(dev, B43_PHY_ANALOGOVERVAL)
+ & 0xFFFC);
+ if (phy->type == B43_PHYTYPE_G) {
+ if ((phy->rev >= 7) &&
+ (sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+ b43_phy_write(dev, B43_PHY_RFOVER, 0x933);
+ } else {
+ b43_phy_write(dev, B43_PHY_RFOVER, 0x133);
+ }
+ } else {
+ b43_phy_write(dev, B43_PHY_RFOVER, 0);
+ }
+ b43_phy_write(dev, B43_PHY_BASE(0x3E), 0);
+ }
+ sav->reg_3F4 = b43_read16(dev, 0x3F4);
+ sav->reg_3E2 = b43_read16(dev, 0x3E2);
+ sav->radio_43 = b43_radio_read16(dev, 0x43);
+ sav->radio_7A = b43_radio_read16(dev, 0x7A);
+ sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
+ sav->phy_base_2A = b43_phy_read(dev, B43_PHY_BASE(0x2A));
+ sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
+ sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL);
+
+ if (!has_tx_magnification(phy)) {
+ sav->radio_52 = b43_radio_read16(dev, 0x52);
+ sav->radio_52 &= 0x00F0;
+ }
+ if (phy->type == B43_PHYTYPE_B) {
+ sav->phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
+ sav->phy_base_06 = b43_phy_read(dev, B43_PHY_BASE(0x06));
+ b43_phy_write(dev, B43_PHY_BASE(0x30), 0x00FF);
+ b43_phy_write(dev, B43_PHY_BASE(0x06), 0x3F3F);
+ } else {
+ b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2)
+ | 0x8000);
+ }
+ b43_write16(dev, 0x3F4, b43_read16(dev, 0x3F4)
+ & 0xF000);
+
+ tmp =
+ (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_BASE(0x2E);
+ b43_phy_write(dev, tmp, 0x007F);
+
+ tmp = sav->phy_syncctl;
+ b43_phy_write(dev, B43_PHY_SYNCCTL, tmp & 0xFF7F);
+ tmp = sav->radio_7A;
+ b43_radio_write16(dev, 0x007A, tmp & 0xFFF0);
+
+ b43_phy_write(dev, B43_PHY_BASE(0x2A), 0x8A3);
+ if (phy->type == B43_PHYTYPE_G ||
+ (phy->type == B43_PHYTYPE_B &&
+ phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) {
+ b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1003);
+ } else
+ b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x0802);
+ if (phy->rev >= 2)
+ b43_dummy_transmission(dev);
+ b43_radio_selectchannel(dev, 6, 0);
+ b43_radio_read16(dev, 0x51); /* dummy read */
+ if (phy->type == B43_PHYTYPE_G)
+ b43_phy_write(dev, B43_PHY_BASE(0x2F), 0);
+ if (lo->rebuild)
+ lo_measure_txctl_values(dev);
+ if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) {
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078);
+ } else {
+ if (phy->type == B43_PHYTYPE_B)
+ b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
+ else
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
+ }
+}
+
+static void lo_measure_restore(struct b43_wldev *dev,
+ struct lo_g_saved_values *sav)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ u16 tmp;
+
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
+ tmp = (phy->pga_gain << 8);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0);
+ udelay(5);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2);
+ udelay(2);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3);
+ } else {
+ tmp = (phy->pga_gain | 0xEFA0);
+ b43_phy_write(dev, B43_PHY_PGACTL, tmp);
+ }
+ if (b43_has_hardware_pctl(phy)) {
+ b43_gphy_dc_lt_init(dev);
+ } else {
+ if (lo->rebuild)
+ b43_lo_g_adjust_to(dev, 3, 2, 0);
+ else
+ b43_lo_g_adjust(dev);
+ }
+ if (phy->type == B43_PHYTYPE_G) {
+ if (phy->rev >= 3)
+ b43_phy_write(dev, B43_PHY_BASE(0x2E), 0xC078);
+ else
+ b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
+ if (phy->rev >= 2)
+ b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0202);
+ else
+ b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0101);
+ }
+ b43_write16(dev, 0x3F4, sav->reg_3F4);
+ b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl);
+ b43_phy_write(dev, B43_PHY_BASE(0x2A), sav->phy_base_2A);
+ b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl);
+ b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl);
+ b43_radio_write16(dev, 0x43, sav->radio_43);
+ b43_radio_write16(dev, 0x7A, sav->radio_7A);
+ if (!has_tx_magnification(phy)) {
+ tmp = sav->radio_52;
+ b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
+ & 0xFF0F) | tmp);
+ }
+ b43_write16(dev, 0x3E2, sav->reg_3E2);
+ if (phy->type == B43_PHYTYPE_B &&
+ phy->radio_ver == 0x2050 && phy->radio_rev <= 5) {
+ b43_phy_write(dev, B43_PHY_BASE(0x30), sav->phy_base_30);
+ b43_phy_write(dev, B43_PHY_BASE(0x06), sav->phy_base_06);
+ }
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ sav->phy_analogoverval);
+ b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl);
+ b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval);
+ b43_phy_write(dev, B43_PHY_BASE(0x3E), sav->phy_base_3E);
+ b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0);
+ }
+ if (b43_has_hardware_pctl(phy)) {
+ tmp = (sav->phy_lo_mask & 0xBFFF);
+ b43_phy_write(dev, B43_PHY_LO_MASK, tmp);
+ b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01);
+ b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl);
+ b43_phy_write(dev, B43_PHY_BASE(0x14), sav->phy_base_14);
+ b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
+ }
+ b43_radio_selectchannel(dev, sav->old_channel, 1);
+}
+
+struct b43_lo_g_statemachine {
+ int current_state;
+ int nr_measured;
+ int state_val_multiplier;
+ u16 lowest_feedth;
+ struct b43_loctl min_loctl;
+};
+
+/* Loop over each possible value in this state. */
+static int lo_probe_possible_loctls(struct b43_wldev *dev,
+ struct b43_loctl *probe_loctl,
+ struct b43_lo_g_statemachine *d)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ struct b43_loctl test_loctl;
+ struct b43_loctl orig_loctl;
+ struct b43_loctl prev_loctl = {
+ .i = -100,
+ .q = -100,
+ };
+ int i;
+ int begin, end;
+ int found_lower = 0;
+ u16 feedth;
+
+ static const struct b43_loctl modifiers[] = {
+ {.i = 1,.q = 1,},
+ {.i = 1,.q = 0,},
+ {.i = 1,.q = -1,},
+ {.i = 0,.q = -1,},
+ {.i = -1,.q = -1,},
+ {.i = -1,.q = 0,},
+ {.i = -1,.q = 1,},
+ {.i = 0,.q = 1,},
+ };
+
+ if (d->current_state == 0) {
+ begin = 1;
+ end = 8;
+ } else if (d->current_state % 2 == 0) {
+ begin = d->current_state - 1;
+ end = d->current_state + 1;
+ } else {
+ begin = d->current_state - 2;
+ end = d->current_state + 2;
+ }
+ if (begin < 1)
+ begin += 8;
+ if (end > 8)
+ end -= 8;
+
+ memcpy(&orig_loctl, probe_loctl, sizeof(struct b43_loctl));
+ i = begin;
+ d->current_state = i;
+ while (1) {
+ B43_WARN_ON(!(i >= 1 && i <= 8));
+ memcpy(&test_loctl, &orig_loctl, sizeof(struct b43_loctl));
+ test_loctl.i += modifiers[i - 1].i * d->state_val_multiplier;
+ test_loctl.q += modifiers[i - 1].q * d->state_val_multiplier;
+ if ((test_loctl.i != prev_loctl.i ||
+ test_loctl.q != prev_loctl.q) &&
+ (abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) {
+ b43_lo_write(dev, &test_loctl);
+ feedth = lo_measure_feedthrough(dev, phy->lna_gain,
+ phy->pga_gain,
+ phy->trsw_rx_gain);
+ if (feedth < d->lowest_feedth) {
+ memcpy(probe_loctl, &test_loctl,
+ sizeof(struct b43_loctl));
+ found_lower = 1;
+ d->lowest_feedth = feedth;
+ if ((d->nr_measured < 2) &&
+ (!has_loopback_gain(phy) || lo->rebuild))
+ break;
+ }
+ }
+ memcpy(&prev_loctl, &test_loctl, sizeof(prev_loctl));
+ if (i == end)
+ break;
+ if (i == 8)
+ i = 1;
+ else
+ i++;
+ d->current_state = i;
+ }
+
+ return found_lower;
+}
+
+static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
+ struct b43_loctl *loctl,
+ int *max_rx_gain)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ struct b43_lo_g_statemachine d;
+ u16 feedth;
+ int found_lower;
+ struct b43_loctl probe_loctl;
+ int max_repeat = 1, repeat_cnt = 0;
+
+ d.nr_measured = 0;
+ d.state_val_multiplier = 1;
+ if (has_loopback_gain(phy) && !lo->rebuild)
+ d.state_val_multiplier = 3;
+
+ memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl));
+ if (has_loopback_gain(phy) && lo->rebuild)
+ max_repeat = 4;
+ do {
+ b43_lo_write(dev, &d.min_loctl);
+ feedth = lo_measure_feedthrough(dev, phy->lna_gain,
+ phy->pga_gain,
+ phy->trsw_rx_gain);
+ if (!lo->rebuild && feedth < 0x258) {
+ if (feedth >= 0x12C)
+ *max_rx_gain += 6;
+ else
+ *max_rx_gain += 3;
+ feedth = lo_measure_feedthrough(dev, phy->lna_gain,
+ phy->pga_gain,
+ phy->trsw_rx_gain);
+ }
+ d.lowest_feedth = feedth;
+
+ d.current_state = 0;
+ do {
+ B43_WARN_ON(!
+ (d.current_state >= 0
+ && d.current_state <= 8));
+ memcpy(&probe_loctl, &d.min_loctl,
+ sizeof(struct b43_loctl));
+ found_lower =
+ lo_probe_possible_loctls(dev, &probe_loctl, &d);
+ if (!found_lower)
+ break;
+ if ((probe_loctl.i == d.min_loctl.i) &&
+ (probe_loctl.q == d.min_loctl.q))
+ break;
+ memcpy(&d.min_loctl, &probe_loctl,
+ sizeof(struct b43_loctl));
+ d.nr_measured++;
+ } while (d.nr_measured < 24);
+ memcpy(loctl, &d.min_loctl, sizeof(struct b43_loctl));
+
+ if (has_loopback_gain(phy)) {
+ if (d.lowest_feedth > 0x1194)
+ *max_rx_gain -= 6;
+ else if (d.lowest_feedth < 0x5DC)
+ *max_rx_gain += 3;
+ if (repeat_cnt == 0) {
+ if (d.lowest_feedth <= 0x5DC) {
+ d.state_val_multiplier = 1;
+ repeat_cnt++;
+ } else
+ d.state_val_multiplier = 2;
+ } else if (repeat_cnt == 2)
+ d.state_val_multiplier = 1;
+ }
+ lo_measure_gain_values(dev, *max_rx_gain,
+ has_loopback_gain(phy));
+ } while (++repeat_cnt < max_repeat);
+}
+
+#if B43_CALIB_ALL_LOCTLS
+static const struct b43_rfatt b43_full_rfatt_list_items[] = {
+ { .att = 0, .with_padmix = 0, },
+ { .att = 1, .with_padmix = 0, },
+ { .att = 2, .with_padmix = 0, },
+ { .att = 3, .with_padmix = 0, },
+ { .att = 4, .with_padmix = 0, },
+ { .att = 5, .with_padmix = 0, },
+ { .att = 6, .with_padmix = 0, },
+ { .att = 7, .with_padmix = 0, },
+ { .att = 8, .with_padmix = 0, },
+ { .att = 9, .with_padmix = 0, },
+ { .att = 10, .with_padmix = 0, },
+ { .att = 11, .with_padmix = 0, },
+ { .att = 12, .with_padmix = 0, },
+ { .att = 13, .with_padmix = 0, },
+ { .att = 14, .with_padmix = 0, },
+ { .att = 15, .with_padmix = 0, },
+ { .att = 0, .with_padmix = 1, },
+ { .att = 1, .with_padmix = 1, },
+ { .att = 2, .with_padmix = 1, },
+ { .att = 3, .with_padmix = 1, },
+ { .att = 4, .with_padmix = 1, },
+ { .att = 5, .with_padmix = 1, },
+ { .att = 6, .with_padmix = 1, },
+ { .att = 7, .with_padmix = 1, },
+ { .att = 8, .with_padmix = 1, },
+ { .att = 9, .with_padmix = 1, },
+ { .att = 10, .with_padmix = 1, },
+ { .att = 11, .with_padmix = 1, },
+ { .att = 12, .with_padmix = 1, },
+ { .att = 13, .with_padmix = 1, },
+ { .att = 14, .with_padmix = 1, },
+ { .att = 15, .with_padmix = 1, },
+};
+static const struct b43_rfatt_list b43_full_rfatt_list = {
+ .list = b43_full_rfatt_list_items,
+ .len = ARRAY_SIZE(b43_full_rfatt_list_items),
+};
+
+static const struct b43_bbatt b43_full_bbatt_list_items[] = {
+ { .att = 0, },
+ { .att = 1, },
+ { .att = 2, },
+ { .att = 3, },
+ { .att = 4, },
+ { .att = 5, },
+ { .att = 6, },
+ { .att = 7, },
+ { .att = 8, },
+ { .att = 9, },
+ { .att = 10, },
+ { .att = 11, },
+};
+static const struct b43_bbatt_list b43_full_bbatt_list = {
+ .list = b43_full_bbatt_list_items,
+ .len = ARRAY_SIZE(b43_full_bbatt_list_items),
+};
+#endif /* B43_CALIB_ALL_LOCTLS */
+
+static void lo_measure(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ struct b43_loctl loctl = {
+ .i = 0,
+ .q = 0,
+ };
+ struct b43_loctl *ploctl;
+ int max_rx_gain;
+ int rfidx, bbidx;
+ const struct b43_bbatt_list *bbatt_list;
+ const struct b43_rfatt_list *rfatt_list;
+
+ /* Values from the "TXCTL Register and Value Table" */
+ u16 txctl_reg;
+ u16 txctl_value;
+ u16 pad_mix_gain;
+
+ bbatt_list = &lo->bbatt_list;
+ rfatt_list = &lo->rfatt_list;
+#if B43_CALIB_ALL_LOCTLS
+ bbatt_list = &b43_full_bbatt_list;
+ rfatt_list = &b43_full_rfatt_list;
+#endif
+
+ txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain);
+
+ for (rfidx = 0; rfidx < rfatt_list->len; rfidx++) {
+
+ b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+ & 0xFFF0) |
+ rfatt_list->list[rfidx].att);
+ b43_radio_write16(dev, txctl_reg,
+ (b43_radio_read16(dev, txctl_reg)
+ & ~txctl_value)
+ | (rfatt_list->list[rfidx].with_padmix ?
+ txctl_value : 0));
+
+ for (bbidx = 0; bbidx < bbatt_list->len; bbidx++) {
+ if (lo->rebuild) {
+#if B43_CALIB_ALL_LOCTLS
+ ploctl = b43_get_lo_g_ctl(dev,
+ &rfatt_list->list[rfidx],
+ &bbatt_list->list[bbidx]);
+#else
+ ploctl = b43_get_lo_g_ctl_nopadmix(dev,
+ &rfatt_list->
+ list[rfidx],
+ &bbatt_list->
+ list[bbidx]);
+#endif
+ } else {
+ ploctl = b43_get_lo_g_ctl(dev,
+ &rfatt_list->list[rfidx],
+ &bbatt_list->list[bbidx]);
+ if (!ploctl->used)
+ continue;
+ }
+ memcpy(&loctl, ploctl, sizeof(loctl));
+ loctl.i = 0;
+ loctl.q = 0;
+
+ max_rx_gain = rfatt_list->list[rfidx].att * 2;
+ max_rx_gain += bbatt_list->list[bbidx].att / 2;
+ if (rfatt_list->list[rfidx].with_padmix)
+ max_rx_gain -= pad_mix_gain;
+ if (has_loopback_gain(phy))
+ max_rx_gain += phy->max_lb_gain;
+ lo_measure_gain_values(dev, max_rx_gain,
+ has_loopback_gain(phy));
+
+ b43_phy_set_baseband_attenuation(dev,
+ bbatt_list->list[bbidx].att);
+ lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
+ if (phy->type == B43_PHYTYPE_B) {
+ loctl.i++;
+ loctl.q++;
+ }
+ b43_loctl_set_calibrated(&loctl, 1);
+ memcpy(ploctl, &loctl, sizeof(loctl));
+ }
+ }
+}
+
+#if B43_DEBUG
+static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control)
+{
+ const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT);
+ int i = control->i;
+ int q = control->q;
+
+ if (b43_loctl_is_calibrated(control)) {
+ if ((abs(i) > 16) || (abs(q) > 16))
+ goto error;
+ } else {
+ if (control->used)
+ goto error;
+ if (dev->phy.lo_control->rebuild) {
+ control->i = 0;
+ control->q = 0;
+ if ((i != B43_LOCTL_POISON) ||
+ (q != B43_LOCTL_POISON))
+ goto error;
+ }
+ }
+ if (is_initializing && control->used)
+ goto error;
+
+ return;
+error:
+ b43err(dev->wl, "LO control pair validation failed "
+ "(I: %d, Q: %d, used %u, calib: %u, initing: %d)\n",
+ i, q, control->used,
+ b43_loctl_is_calibrated(control),
+ is_initializing);
+}
+
+static void validate_all_loctls(struct b43_wldev *dev)
+{
+ b43_call_for_each_loctl(dev, do_validate_loctl);
+}
+
+static void do_reset_calib(struct b43_wldev *dev, struct b43_loctl *control)
+{
+ if (dev->phy.lo_control->rebuild ||
+ control->used) {
+ b43_loctl_set_calibrated(control, 0);
+ control->i = B43_LOCTL_POISON;
+ control->q = B43_LOCTL_POISON;
+ }
+}
+
+static void reset_all_loctl_calibration_states(struct b43_wldev *dev)
+{
+ b43_call_for_each_loctl(dev, do_reset_calib);
+}
+
+#else /* B43_DEBUG */
+static inline void validate_all_loctls(struct b43_wldev *dev) { }
+static inline void reset_all_loctl_calibration_states(struct b43_wldev *dev) { }
+#endif /* B43_DEBUG */
+
+void b43_lo_g_measure(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct lo_g_saved_values uninitialized_var(sav);
+
+ B43_WARN_ON((phy->type != B43_PHYTYPE_B) &&
+ (phy->type != B43_PHYTYPE_G));
+
+ sav.old_channel = phy->channel;
+ lo_measure_setup(dev, &sav);
+ reset_all_loctl_calibration_states(dev);
+ lo_measure(dev);
+ lo_measure_restore(dev, &sav);
+
+ validate_all_loctls(dev);
+
+ phy->lo_control->lo_measured = 1;
+ phy->lo_control->rebuild = 0;
+}
+
+#if B43_DEBUG
+static void validate_loctl_calibration(struct b43_wldev *dev,
+ struct b43_loctl *loctl,
+ struct b43_rfatt *rfatt,
+ struct b43_bbatt *bbatt)
+{
+ if (b43_loctl_is_calibrated(loctl))
+ return;
+ if (!dev->phy.lo_control->lo_measured) {
+ /* On init we set the attenuation values before we
+ * calibrated the LO. I guess that's OK. */
+ return;
+ }
+ b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated "
+ "control pair: rfatt=%u,%spadmix bbatt=%u\n",
+ rfatt->att,
+ (rfatt->with_padmix) ? "" : "no-",
+ bbatt->att);
+}
+#else
+static inline void validate_loctl_calibration(struct b43_wldev *dev,
+ struct b43_loctl *loctl,
+ struct b43_rfatt *rfatt,
+ struct b43_bbatt *bbatt)
+{
+}
+#endif
+
+static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf,
+ u8 tx_control)
+{
+ if (tx_control & B43_TXCTL_TXMIX) {
+ if (rf->att < 5)
+ rf->att = 4;
+ }
+}
+
+void b43_lo_g_adjust(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_rfatt rf;
+ struct b43_loctl *loctl;
+
+ memcpy(&rf, &phy->rfatt, sizeof(rf));
+ fixup_rfatt_for_txcontrol(&rf, phy->tx_control);
+
+ loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt);
+ validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt);
+ b43_lo_write(dev, loctl);
+}
+
+void b43_lo_g_adjust_to(struct b43_wldev *dev,
+ u16 rfatt, u16 bbatt, u16 tx_control)
+{
+ struct b43_rfatt rf;
+ struct b43_bbatt bb;
+ struct b43_loctl *loctl;
+
+ memset(&rf, 0, sizeof(rf));
+ memset(&bb, 0, sizeof(bb));
+ rf.att = rfatt;
+ bb.att = bbatt;
+ fixup_rfatt_for_txcontrol(&rf, tx_control);
+ loctl = b43_get_lo_g_ctl(dev, &rf, &bb);
+ validate_loctl_calibration(dev, loctl, &rf, &bb);
+ b43_lo_write(dev, loctl);
+}
+
+static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control)
+{
+ control->used = 0;
+}
+
+void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+
+ b43_call_for_each_loctl(dev, do_mark_unused);
+ lo->rebuild = 1;
+}
+
+void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_rfatt rf;
+
+ memcpy(&rf, &phy->rfatt, sizeof(rf));
+ fixup_rfatt_for_txcontrol(&rf, phy->tx_control);
+
+ b43_get_lo_g_ctl(dev, &rf, &phy->bbatt)->used = 1;
+}
diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h
new file mode 100644
index 00000000000..455615d1f8c
--- /dev/null
+++ b/drivers/net/wireless/b43/lo.h
@@ -0,0 +1,112 @@
+#ifndef B43_LO_H_
+#define B43_LO_H_
+
+#include "phy.h"
+
+struct b43_wldev;
+
+/* Local Oscillator control value-pair. */
+struct b43_loctl {
+ /* Control values. */
+ s8 i;
+ s8 q;
+ /* "Used by hardware" flag. */
+ bool used;
+#ifdef CONFIG_B43_DEBUG
+ /* Is this lo-control-array entry calibrated? */
+ bool calibrated;
+#endif
+};
+
+/* Debugging: Poison value for i and q values. */
+#define B43_LOCTL_POISON 111
+
+/* loctl->calibrated debugging mechanism */
+#ifdef CONFIG_B43_DEBUG
+static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl,
+ bool calibrated)
+{
+ loctl->calibrated = calibrated;
+}
+static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl)
+{
+ return loctl->calibrated;
+}
+#else
+static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl,
+ bool calibrated)
+{
+}
+static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl)
+{
+ return 1;
+}
+#endif
+
+/* TX Power LO Control Array.
+ * Value-pairs to adjust the LocalOscillator are stored
+ * in this structure.
+ * There are two different set of values. One for "Flag is Set"
+ * and one for "Flag is Unset".
+ * By "Flag" the flag in struct b43_rfatt is meant.
+ * The Value arrays are two-dimensional. The first index
+ * is the baseband attenuation and the second index
+ * is the radio attenuation.
+ * Use b43_get_lo_g_ctl() to retrieve a value from the lists.
+ */
+struct b43_txpower_lo_control {
+#define B43_NR_BB 12
+#define B43_NR_RF 16
+ /* LO Control values, with PAD Mixer */
+ struct b43_loctl with_padmix[B43_NR_BB][B43_NR_RF];
+ /* LO Control values, without PAD Mixer */
+ struct b43_loctl no_padmix[B43_NR_BB][B43_NR_RF];
+
+ /* Flag to indicate a complete rebuild of the two tables above
+ * to the LO measuring code. */
+ bool rebuild;
+
+ /* Lists of valid RF and BB attenuation values for this device. */
+ struct b43_rfatt_list rfatt_list;
+ struct b43_bbatt_list bbatt_list;
+
+ /* Current TX Bias value */
+ u8 tx_bias;
+ /* Current TX Magnification Value (if used by the device) */
+ u8 tx_magn;
+
+ /* GPHY LO is measured. */
+ bool lo_measured;
+
+ /* Saved device PowerVector */
+ u64 power_vector;
+};
+
+/* Measure the BPHY Local Oscillator. */
+void b43_lo_b_measure(struct b43_wldev *dev);
+/* Measure the BPHY/GPHY Local Oscillator. */
+void b43_lo_g_measure(struct b43_wldev *dev);
+
+/* Adjust the Local Oscillator to the saved attenuation
+ * and txctl values.
+ */
+void b43_lo_g_adjust(struct b43_wldev *dev);
+/* Adjust to specific values. */
+void b43_lo_g_adjust_to(struct b43_wldev *dev,
+ u16 rfatt, u16 bbatt, u16 tx_control);
+
+/* Mark all possible b43_lo_g_ctl as "unused" */
+void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev);
+/* Mark the b43_lo_g_ctl corresponding to the current
+ * attenuation values as used.
+ */
+void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev);
+
+/* Get a reference to a LO Control value pair in the
+ * TX Power LO Control Array.
+ */
+struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev,
+ const struct b43_rfatt *rfatt,
+ const struct b43_bbatt *bbatt);
+
+#endif /* B43_LO_H_ */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
new file mode 100644
index 00000000000..2b17c1dc46f
--- /dev/null
+++ b/drivers/net/wireless/b43/main.c
@@ -0,0 +1,4070 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
+ Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/version.h>
+#include <linux/firmware.h>
+#include <linux/wireless.h>
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <asm/unaligned.h>
+
+#include "b43.h"
+#include "main.h"
+#include "debugfs.h"
+#include "phy.h"
+#include "dma.h"
+#include "pio.h"
+#include "sysfs.h"
+#include "xmit.h"
+#include "lo.h"
+#include "pcmcia.h"
+
+MODULE_DESCRIPTION("Broadcom B43 wireless driver");
+MODULE_AUTHOR("Martin Langer");
+MODULE_AUTHOR("Stefano Brivio");
+MODULE_AUTHOR("Michael Buesch");
+MODULE_LICENSE("GPL");
+
+extern char *nvram_get(char *name);
+
+#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
+static int modparam_pio;
+module_param_named(pio, modparam_pio, int, 0444);
+MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
+#elif defined(CONFIG_B43_DMA)
+# define modparam_pio 0
+#elif defined(CONFIG_B43_PIO)
+# define modparam_pio 1
+#endif
+
+static int modparam_bad_frames_preempt;
+module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
+MODULE_PARM_DESC(bad_frames_preempt,
+ "enable(1) / disable(0) Bad Frames Preemption");
+
+static int modparam_short_retry = B43_DEFAULT_SHORT_RETRY_LIMIT;
+module_param_named(short_retry, modparam_short_retry, int, 0444);
+MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
+
+static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT;
+module_param_named(long_retry, modparam_long_retry, int, 0444);
+MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
+
+static char modparam_fwpostfix[16];
+module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
+MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load.");
+
+static int modparam_hwpctl;
+module_param_named(hwpctl, modparam_hwpctl, int, 0444);
+MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)");
+
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+
+static const struct ssb_device_id b43_ssb_tbl[] = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
+ SSB_DEVTABLE_END
+};
+
+MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl);
+
+/* Channel and ratetables are shared for all devices.
+ * They can't be const, because ieee80211 puts some precalculated
+ * data in there. This data is the same for all devices, so we don't
+ * get concurrency issues */
+#define RATETAB_ENT(_rateid, _flags) \
+ { \
+ .rate = B43_RATE_TO_BASE100KBPS(_rateid), \
+ .val = (_rateid), \
+ .val2 = (_rateid), \
+ .flags = (_flags), \
+ }
+static struct ieee80211_rate __b43_ratetable[] = {
+ RATETAB_ENT(B43_CCK_RATE_1MB, IEEE80211_RATE_CCK),
+ RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
+ RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
+ RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
+ RATETAB_ENT(B43_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
+};
+
+#define b43_a_ratetable (__b43_ratetable + 4)
+#define b43_a_ratetable_size 8
+#define b43_b_ratetable (__b43_ratetable + 0)
+#define b43_b_ratetable_size 4
+#define b43_g_ratetable (__b43_ratetable + 0)
+#define b43_g_ratetable_size 12
+
+#define CHANTAB_ENT(_chanid, _freq) \
+ { \
+ .chan = (_chanid), \
+ .freq = (_freq), \
+ .val = (_chanid), \
+ .flag = IEEE80211_CHAN_W_SCAN | \
+ IEEE80211_CHAN_W_ACTIVE_SCAN | \
+ IEEE80211_CHAN_W_IBSS, \
+ .power_level = 0xFF, \
+ .antenna_max = 0xFF, \
+ }
+static struct ieee80211_channel b43_bg_chantable[] = {
+ CHANTAB_ENT(1, 2412),
+ CHANTAB_ENT(2, 2417),
+ CHANTAB_ENT(3, 2422),
+ CHANTAB_ENT(4, 2427),
+ CHANTAB_ENT(5, 2432),
+ CHANTAB_ENT(6, 2437),
+ CHANTAB_ENT(7, 2442),
+ CHANTAB_ENT(8, 2447),
+ CHANTAB_ENT(9, 2452),
+ CHANTAB_ENT(10, 2457),
+ CHANTAB_ENT(11, 2462),
+ CHANTAB_ENT(12, 2467),
+ CHANTAB_ENT(13, 2472),
+ CHANTAB_ENT(14, 2484),
+};
+
+#define b43_bg_chantable_size ARRAY_SIZE(b43_bg_chantable)
+static struct ieee80211_channel b43_a_chantable[] = {
+ CHANTAB_ENT(36, 5180),
+ CHANTAB_ENT(40, 5200),
+ CHANTAB_ENT(44, 5220),
+ CHANTAB_ENT(48, 5240),
+ CHANTAB_ENT(52, 5260),
+ CHANTAB_ENT(56, 5280),
+ CHANTAB_ENT(60, 5300),
+ CHANTAB_ENT(64, 5320),
+ CHANTAB_ENT(149, 5745),
+ CHANTAB_ENT(153, 5765),
+ CHANTAB_ENT(157, 5785),
+ CHANTAB_ENT(161, 5805),
+ CHANTAB_ENT(165, 5825),
+};
+
+#define b43_a_chantable_size ARRAY_SIZE(b43_a_chantable)
+
+static void b43_wireless_core_exit(struct b43_wldev *dev);
+static int b43_wireless_core_init(struct b43_wldev *dev);
+static void b43_wireless_core_stop(struct b43_wldev *dev);
+static int b43_wireless_core_start(struct b43_wldev *dev);
+
+static int b43_ratelimit(struct b43_wl *wl)
+{
+ if (!wl || !wl->current_dev)
+ return 1;
+ if (b43_status(wl->current_dev) < B43_STAT_STARTED)
+ return 1;
+ /* We are up and running.
+ * Ratelimit the messages to avoid DoS over the net. */
+ return net_ratelimit();
+}
+
+void b43info(struct b43_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ if (!b43_ratelimit(wl))
+ return;
+ va_start(args, fmt);
+ printk(KERN_INFO "b43-%s: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+void b43err(struct b43_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ if (!b43_ratelimit(wl))
+ return;
+ va_start(args, fmt);
+ printk(KERN_ERR "b43-%s ERROR: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+void b43warn(struct b43_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ if (!b43_ratelimit(wl))
+ return;
+ va_start(args, fmt);
+ printk(KERN_WARNING "b43-%s warning: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+#if B43_DEBUG
+void b43dbg(struct b43_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ printk(KERN_DEBUG "b43-%s debug: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+#endif /* DEBUG */
+
+static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val)
+{
+ u32 macctl;
+
+ B43_WARN_ON(offset % 4 != 0);
+
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ if (macctl & B43_MACCTL_BE)
+ val = swab32(val);
+
+ b43_write32(dev, B43_MMIO_RAM_CONTROL, offset);
+ mmiowb();
+ b43_write32(dev, B43_MMIO_RAM_DATA, val);
+}
+
+static inline
+ void b43_shm_control_word(struct b43_wldev *dev, u16 routing, u16 offset)
+{
+ u32 control;
+
+ /* "offset" is the WORD offset. */
+
+ control = routing;
+ control <<= 16;
+ control |= offset;
+ b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
+}
+
+u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
+{
+ u32 ret;
+
+ if (routing == B43_SHM_SHARED) {
+ B43_WARN_ON(offset & 0x0001);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43_shm_control_word(dev, routing, offset >> 2);
+ ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
+ ret <<= 16;
+ b43_shm_control_word(dev, routing, (offset >> 2) + 1);
+ ret |= b43_read16(dev, B43_MMIO_SHM_DATA);
+
+ return ret;
+ }
+ offset >>= 2;
+ }
+ b43_shm_control_word(dev, routing, offset);
+ ret = b43_read32(dev, B43_MMIO_SHM_DATA);
+
+ return ret;
+}
+
+u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
+{
+ u16 ret;
+
+ if (routing == B43_SHM_SHARED) {
+ B43_WARN_ON(offset & 0x0001);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43_shm_control_word(dev, routing, offset >> 2);
+ ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
+
+ return ret;
+ }
+ offset >>= 2;
+ }
+ b43_shm_control_word(dev, routing, offset);
+ ret = b43_read16(dev, B43_MMIO_SHM_DATA);
+
+ return ret;
+}
+
+void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
+{
+ if (routing == B43_SHM_SHARED) {
+ B43_WARN_ON(offset & 0x0001);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43_shm_control_word(dev, routing, offset >> 2);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
+ (value >> 16) & 0xffff);
+ mmiowb();
+ b43_shm_control_word(dev, routing, (offset >> 2) + 1);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
+ return;
+ }
+ offset >>= 2;
+ }
+ b43_shm_control_word(dev, routing, offset);
+ mmiowb();
+ b43_write32(dev, B43_MMIO_SHM_DATA, value);
+}
+
+void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
+{
+ if (routing == B43_SHM_SHARED) {
+ B43_WARN_ON(offset & 0x0001);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43_shm_control_word(dev, routing, offset >> 2);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
+ return;
+ }
+ offset >>= 2;
+ }
+ b43_shm_control_word(dev, routing, offset);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_SHM_DATA, value);
+}
+
+/* Read HostFlags */
+u32 b43_hf_read(struct b43_wldev * dev)
+{
+ u32 ret;
+
+ ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI);
+ ret <<= 16;
+ ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO);
+
+ return ret;
+}
+
+/* Write HostFlags */
+void b43_hf_write(struct b43_wldev *dev, u32 value)
+{
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_HOSTFLO, (value & 0x0000FFFF));
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_HOSTFHI, ((value & 0xFFFF0000) >> 16));
+}
+
+void b43_tsf_read(struct b43_wldev *dev, u64 * tsf)
+{
+ /* We need to be careful. As we read the TSF from multiple
+ * registers, we should take care of register overflows.
+ * In theory, the whole tsf read process should be atomic.
+ * We try to be atomic here, by restaring the read process,
+ * if any of the high registers changed (overflew).
+ */
+ if (dev->dev->id.revision >= 3) {
+ u32 low, high, high2;
+
+ do {
+ high = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH);
+ low = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_LOW);
+ high2 = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH);
+ } while (unlikely(high != high2));
+
+ *tsf = high;
+ *tsf <<= 32;
+ *tsf |= low;
+ } else {
+ u64 tmp;
+ u16 v0, v1, v2, v3;
+ u16 test1, test2, test3;
+
+ do {
+ v3 = b43_read16(dev, B43_MMIO_TSF_3);
+ v2 = b43_read16(dev, B43_MMIO_TSF_2);
+ v1 = b43_read16(dev, B43_MMIO_TSF_1);
+ v0 = b43_read16(dev, B43_MMIO_TSF_0);
+
+ test3 = b43_read16(dev, B43_MMIO_TSF_3);
+ test2 = b43_read16(dev, B43_MMIO_TSF_2);
+ test1 = b43_read16(dev, B43_MMIO_TSF_1);
+ } while (v3 != test3 || v2 != test2 || v1 != test1);
+
+ *tsf = v3;
+ *tsf <<= 48;
+ tmp = v2;
+ tmp <<= 32;
+ *tsf |= tmp;
+ tmp = v1;
+ tmp <<= 16;
+ *tsf |= tmp;
+ *tsf |= v0;
+ }
+}
+
+static void b43_time_lock(struct b43_wldev *dev)
+{
+ u32 macctl;
+
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ macctl |= B43_MACCTL_TBTTHOLD;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+ /* Commit the write */
+ b43_read32(dev, B43_MMIO_MACCTL);
+}
+
+static void b43_time_unlock(struct b43_wldev *dev)
+{
+ u32 macctl;
+
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ macctl &= ~B43_MACCTL_TBTTHOLD;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+ /* Commit the write */
+ b43_read32(dev, B43_MMIO_MACCTL);
+}
+
+static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf)
+{
+ /* Be careful with the in-progress timer.
+ * First zero out the low register, so we have a full
+ * register-overflow duration to complete the operation.
+ */
+ if (dev->dev->id.revision >= 3) {
+ u32 lo = (tsf & 0x00000000FFFFFFFFULL);
+ u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
+
+ b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, 0);
+ mmiowb();
+ b43_write32(dev, B43_MMIO_REV3PLUS_TSF_HIGH, hi);
+ mmiowb();
+ b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, lo);
+ } else {
+ u16 v0 = (tsf & 0x000000000000FFFFULL);
+ u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
+ u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
+ u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
+
+ b43_write16(dev, B43_MMIO_TSF_0, 0);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_TSF_3, v3);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_TSF_2, v2);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_TSF_1, v1);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_TSF_0, v0);
+ }
+}
+
+void b43_tsf_write(struct b43_wldev *dev, u64 tsf)
+{
+ b43_time_lock(dev);
+ b43_tsf_write_locked(dev, tsf);
+ b43_time_unlock(dev);
+}
+
+static
+void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 * mac)
+{
+ static const u8 zero_addr[ETH_ALEN] = { 0 };
+ u16 data;
+
+ if (!mac)
+ mac = zero_addr;
+
+ offset |= 0x0020;
+ b43_write16(dev, B43_MMIO_MACFILTER_CONTROL, offset);
+
+ data = mac[0];
+ data |= mac[1] << 8;
+ b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
+ data = mac[2];
+ data |= mac[3] << 8;
+ b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
+ data = mac[4];
+ data |= mac[5] << 8;
+ b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
+}
+
+static void b43_write_mac_bssid_templates(struct b43_wldev *dev)
+{
+ const u8 *mac;
+ const u8 *bssid;
+ u8 mac_bssid[ETH_ALEN * 2];
+ int i;
+ u32 tmp;
+
+ bssid = dev->wl->bssid;
+ mac = dev->wl->mac_addr;
+
+ b43_macfilter_set(dev, B43_MACFILTER_BSSID, bssid);
+
+ memcpy(mac_bssid, mac, ETH_ALEN);
+ memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
+
+ /* Write our MAC address and BSSID to template ram */
+ for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) {
+ tmp = (u32) (mac_bssid[i + 0]);
+ tmp |= (u32) (mac_bssid[i + 1]) << 8;
+ tmp |= (u32) (mac_bssid[i + 2]) << 16;
+ tmp |= (u32) (mac_bssid[i + 3]) << 24;
+ b43_ram_write(dev, 0x20 + i, tmp);
+ }
+}
+
+static void b43_upload_card_macaddress(struct b43_wldev *dev)
+{
+ b43_write_mac_bssid_templates(dev);
+ b43_macfilter_set(dev, B43_MACFILTER_SELF, dev->wl->mac_addr);
+}
+
+static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
+{
+ /* slot_time is in usec. */
+ if (dev->phy.type != B43_PHYTYPE_G)
+ return;
+ b43_write16(dev, 0x684, 510 + slot_time);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
+}
+
+static void b43_short_slot_timing_enable(struct b43_wldev *dev)
+{
+ b43_set_slot_time(dev, 9);
+ dev->short_slot = 1;
+}
+
+static void b43_short_slot_timing_disable(struct b43_wldev *dev)
+{
+ b43_set_slot_time(dev, 20);
+ dev->short_slot = 0;
+}
+
+/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 b43_interrupt_enable(struct b43_wldev *dev, u32 mask)
+{
+ u32 old_mask;
+
+ old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask | mask);
+
+ return old_mask;
+}
+
+/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 b43_interrupt_disable(struct b43_wldev *dev, u32 mask)
+{
+ u32 old_mask;
+
+ old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
+
+ return old_mask;
+}
+
+/* Synchronize IRQ top- and bottom-half.
+ * IRQs must be masked before calling this.
+ * This must not be called with the irq_lock held.
+ */
+static void b43_synchronize_irq(struct b43_wldev *dev)
+{
+ synchronize_irq(dev->dev->irq);
+ tasklet_kill(&dev->isr_tasklet);
+}
+
+/* DummyTransmission function, as documented on
+ * http://bcm-specs.sipsolutions.net/DummyTransmission
+ */
+void b43_dummy_transmission(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ unsigned int i, max_loop;
+ u16 value;
+ u32 buffer[5] = {
+ 0x00000000,
+ 0x00D40000,
+ 0x00000000,
+ 0x01000000,
+ 0x00000000,
+ };
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ max_loop = 0x1E;
+ buffer[0] = 0x000201CC;
+ break;
+ case B43_PHYTYPE_B:
+ case B43_PHYTYPE_G:
+ max_loop = 0xFA;
+ buffer[0] = 0x000B846E;
+ break;
+ default:
+ B43_WARN_ON(1);
+ return;
+ }
+
+ for (i = 0; i < 5; i++)
+ b43_ram_write(dev, i * 4, buffer[i]);
+
+ /* Commit writes */
+ b43_read32(dev, B43_MMIO_MACCTL);
+
+ b43_write16(dev, 0x0568, 0x0000);
+ b43_write16(dev, 0x07C0, 0x0000);
+ value = ((phy->type == B43_PHYTYPE_A) ? 1 : 0);
+ b43_write16(dev, 0x050C, value);
+ b43_write16(dev, 0x0508, 0x0000);
+ b43_write16(dev, 0x050A, 0x0000);
+ b43_write16(dev, 0x054C, 0x0000);
+ b43_write16(dev, 0x056A, 0x0014);
+ b43_write16(dev, 0x0568, 0x0826);
+ b43_write16(dev, 0x0500, 0x0000);
+ b43_write16(dev, 0x0502, 0x0030);
+
+ if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
+ b43_radio_write16(dev, 0x0051, 0x0017);
+ for (i = 0x00; i < max_loop; i++) {
+ value = b43_read16(dev, 0x050E);
+ if (value & 0x0080)
+ break;
+ udelay(10);
+ }
+ for (i = 0x00; i < 0x0A; i++) {
+ value = b43_read16(dev, 0x050E);
+ if (value & 0x0400)
+ break;
+ udelay(10);
+ }
+ for (i = 0x00; i < 0x0A; i++) {
+ value = b43_read16(dev, 0x0690);
+ if (!(value & 0x0100))
+ break;
+ udelay(10);
+ }
+ if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
+ b43_radio_write16(dev, 0x0051, 0x0037);
+}
+
+static void key_write(struct b43_wldev *dev,
+ u8 index, u8 algorithm, const u8 * key)
+{
+ unsigned int i;
+ u32 offset;
+ u16 value;
+ u16 kidx;
+
+ /* Key index/algo block */
+ kidx = b43_kidx_to_fw(dev, index);
+ value = ((kidx << 4) | algorithm);
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_KEYIDXBLOCK + (kidx * 2), value);
+
+ /* Write the key to the Key Table Pointer offset */
+ offset = dev->ktp + (index * B43_SEC_KEYSIZE);
+ for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
+ value = key[i];
+ value |= (u16) (key[i + 1]) << 8;
+ b43_shm_write16(dev, B43_SHM_SHARED, offset + i, value);
+ }
+}
+
+static void keymac_write(struct b43_wldev *dev, u8 index, const u8 * addr)
+{
+ u32 addrtmp[2] = { 0, 0, };
+ u8 per_sta_keys_start = 8;
+
+ if (b43_new_kidx_api(dev))
+ per_sta_keys_start = 4;
+
+ B43_WARN_ON(index < per_sta_keys_start);
+ /* We have two default TX keys and possibly two default RX keys.
+ * Physical mac 0 is mapped to physical key 4 or 8, depending
+ * on the firmware version.
+ * So we must adjust the index here.
+ */
+ index -= per_sta_keys_start;
+
+ if (addr) {
+ addrtmp[0] = addr[0];
+ addrtmp[0] |= ((u32) (addr[1]) << 8);
+ addrtmp[0] |= ((u32) (addr[2]) << 16);
+ addrtmp[0] |= ((u32) (addr[3]) << 24);
+ addrtmp[1] = addr[4];
+ addrtmp[1] |= ((u32) (addr[5]) << 8);
+ }
+
+ if (dev->dev->id.revision >= 5) {
+ /* Receive match transmitter address mechanism */
+ b43_shm_write32(dev, B43_SHM_RCMTA,
+ (index * 2) + 0, addrtmp[0]);
+ b43_shm_write16(dev, B43_SHM_RCMTA,
+ (index * 2) + 1, addrtmp[1]);
+ } else {
+ /* RXE (Receive Engine) and
+ * PSM (Programmable State Machine) mechanism
+ */
+ if (index < 8) {
+ /* TODO write to RCM 16, 19, 22 and 25 */
+ } else {
+ b43_shm_write32(dev, B43_SHM_SHARED,
+ B43_SHM_SH_PSM + (index * 6) + 0,
+ addrtmp[0]);
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_PSM + (index * 6) + 4,
+ addrtmp[1]);
+ }
+ }
+}
+
+static void do_key_write(struct b43_wldev *dev,
+ u8 index, u8 algorithm,
+ const u8 * key, size_t key_len, const u8 * mac_addr)
+{
+ u8 buf[B43_SEC_KEYSIZE] = { 0, };
+ u8 per_sta_keys_start = 8;
+
+ if (b43_new_kidx_api(dev))
+ per_sta_keys_start = 4;
+
+ B43_WARN_ON(index >= dev->max_nr_keys);
+ B43_WARN_ON(key_len > B43_SEC_KEYSIZE);
+
+ if (index >= per_sta_keys_start)
+ keymac_write(dev, index, NULL); /* First zero out mac. */
+ if (key)
+ memcpy(buf, key, key_len);
+ key_write(dev, index, algorithm, buf);
+ if (index >= per_sta_keys_start)
+ keymac_write(dev, index, mac_addr);
+
+ dev->key[index].algorithm = algorithm;
+}
+
+static int b43_key_write(struct b43_wldev *dev,
+ int index, u8 algorithm,
+ const u8 * key, size_t key_len,
+ const u8 * mac_addr,
+ struct ieee80211_key_conf *keyconf)
+{
+ int i;
+ int sta_keys_start;
+
+ if (key_len > B43_SEC_KEYSIZE)
+ return -EINVAL;
+ for (i = 0; i < dev->max_nr_keys; i++) {
+ /* Check that we don't already have this key. */
+ B43_WARN_ON(dev->key[i].keyconf == keyconf);
+ }
+ if (index < 0) {
+ /* Either pairwise key or address is 00:00:00:00:00:00
+ * for transmit-only keys. Search the index. */
+ if (b43_new_kidx_api(dev))
+ sta_keys_start = 4;
+ else
+ sta_keys_start = 8;
+ for (i = sta_keys_start; i < dev->max_nr_keys; i++) {
+ if (!dev->key[i].keyconf) {
+ /* found empty */
+ index = i;
+ break;
+ }
+ }
+ if (index < 0) {
+ b43err(dev->wl, "Out of hardware key memory\n");
+ return -ENOSPC;
+ }
+ } else
+ B43_WARN_ON(index > 3);
+
+ do_key_write(dev, index, algorithm, key, key_len, mac_addr);
+ if ((index <= 3) && !b43_new_kidx_api(dev)) {
+ /* Default RX key */
+ B43_WARN_ON(mac_addr);
+ do_key_write(dev, index + 4, algorithm, key, key_len, NULL);
+ }
+ keyconf->hw_key_idx = index;
+ dev->key[index].keyconf = keyconf;
+
+ return 0;
+}
+
+static int b43_key_clear(struct b43_wldev *dev, int index)
+{
+ if (B43_WARN_ON((index < 0) || (index >= dev->max_nr_keys)))
+ return -EINVAL;
+ do_key_write(dev, index, B43_SEC_ALGO_NONE,
+ NULL, B43_SEC_KEYSIZE, NULL);
+ if ((index <= 3) && !b43_new_kidx_api(dev)) {
+ do_key_write(dev, index + 4, B43_SEC_ALGO_NONE,
+ NULL, B43_SEC_KEYSIZE, NULL);
+ }
+ dev->key[index].keyconf = NULL;
+
+ return 0;
+}
+
+static void b43_clear_keys(struct b43_wldev *dev)
+{
+ int i;
+
+ for (i = 0; i < dev->max_nr_keys; i++)
+ b43_key_clear(dev, i);
+}
+
+void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
+{
+ u32 macctl;
+ u16 ucstat;
+ bool hwps;
+ bool awake;
+ int i;
+
+ B43_WARN_ON((ps_flags & B43_PS_ENABLED) &&
+ (ps_flags & B43_PS_DISABLED));
+ B43_WARN_ON((ps_flags & B43_PS_AWAKE) && (ps_flags & B43_PS_ASLEEP));
+
+ if (ps_flags & B43_PS_ENABLED) {
+ hwps = 1;
+ } else if (ps_flags & B43_PS_DISABLED) {
+ hwps = 0;
+ } else {
+ //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
+ // and thus is not an AP and we are associated, set bit 25
+ }
+ if (ps_flags & B43_PS_AWAKE) {
+ awake = 1;
+ } else if (ps_flags & B43_PS_ASLEEP) {
+ awake = 0;
+ } else {
+ //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
+ // or we are associated, or FIXME, or the latest PS-Poll packet sent was
+ // successful, set bit26
+ }
+
+/* FIXME: For now we force awake-on and hwps-off */
+ hwps = 0;
+ awake = 1;
+
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ if (hwps)
+ macctl |= B43_MACCTL_HWPS;
+ else
+ macctl &= ~B43_MACCTL_HWPS;
+ if (awake)
+ macctl |= B43_MACCTL_AWAKE;
+ else
+ macctl &= ~B43_MACCTL_AWAKE;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+ /* Commit write */
+ b43_read32(dev, B43_MMIO_MACCTL);
+ if (awake && dev->dev->id.revision >= 5) {
+ /* Wait for the microcode to wake up. */
+ for (i = 0; i < 100; i++) {
+ ucstat = b43_shm_read16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_UCODESTAT);
+ if (ucstat != B43_SHM_SH_UCODESTAT_SLEEP)
+ break;
+ udelay(10);
+ }
+ }
+}
+
+/* Turn the Analog ON/OFF */
+static void b43_switch_analog(struct b43_wldev *dev, int on)
+{
+ b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
+}
+
+void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+{
+ u32 tmslow;
+ u32 macctl;
+
+ flags |= B43_TMSLOW_PHYCLKEN;
+ flags |= B43_TMSLOW_PHYRESET;
+ ssb_device_enable(dev->dev, flags);
+ msleep(2); /* Wait for the PLL to turn on. */
+
+ /* Now take the PHY out of Reset again */
+ tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+ tmslow |= SSB_TMSLOW_FGC;
+ tmslow &= ~B43_TMSLOW_PHYRESET;
+ ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+ ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
+ msleep(1);
+ tmslow &= ~SSB_TMSLOW_FGC;
+ ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+ ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
+ msleep(1);
+
+ /* Turn Analog ON */
+ b43_switch_analog(dev, 1);
+
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ macctl &= ~B43_MACCTL_GMODE;
+ if (flags & B43_TMSLOW_GMODE)
+ macctl |= B43_MACCTL_GMODE;
+ macctl |= B43_MACCTL_IHR_ENABLED;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+}
+
+static void handle_irq_transmit_status(struct b43_wldev *dev)
+{
+ u32 v0, v1;
+ u16 tmp;
+ struct b43_txstatus stat;
+
+ while (1) {
+ v0 = b43_read32(dev, B43_MMIO_XMITSTAT_0);
+ if (!(v0 & 0x00000001))
+ break;
+ v1 = b43_read32(dev, B43_MMIO_XMITSTAT_1);
+
+ stat.cookie = (v0 >> 16);
+ stat.seq = (v1 & 0x0000FFFF);
+ stat.phy_stat = ((v1 & 0x00FF0000) >> 16);
+ tmp = (v0 & 0x0000FFFF);
+ stat.frame_count = ((tmp & 0xF000) >> 12);
+ stat.rts_count = ((tmp & 0x0F00) >> 8);
+ stat.supp_reason = ((tmp & 0x001C) >> 2);
+ stat.pm_indicated = !!(tmp & 0x0080);
+ stat.intermediate = !!(tmp & 0x0040);
+ stat.for_ampdu = !!(tmp & 0x0020);
+ stat.acked = !!(tmp & 0x0002);
+
+ b43_handle_txstatus(dev, &stat);
+ }
+}
+
+static void drain_txstatus_queue(struct b43_wldev *dev)
+{
+ u32 dummy;
+
+ if (dev->dev->id.revision < 5)
+ return;
+ /* Read all entries from the microcode TXstatus FIFO
+ * and throw them away.
+ */
+ while (1) {
+ dummy = b43_read32(dev, B43_MMIO_XMITSTAT_0);
+ if (!(dummy & 0x00000001))
+ break;
+ dummy = b43_read32(dev, B43_MMIO_XMITSTAT_1);
+ }
+}
+
+static u32 b43_jssi_read(struct b43_wldev *dev)
+{
+ u32 val = 0;
+
+ val = b43_shm_read16(dev, B43_SHM_SHARED, 0x08A);
+ val <<= 16;
+ val |= b43_shm_read16(dev, B43_SHM_SHARED, 0x088);
+
+ return val;
+}
+
+static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
+{
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x088, (jssi & 0x0000FFFF));
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x08A, (jssi & 0xFFFF0000) >> 16);
+}
+
+static void b43_generate_noise_sample(struct b43_wldev *dev)
+{
+ b43_jssi_write(dev, 0x7F7F7F7F);
+ b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
+ b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
+ | (1 << 4));
+ B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel);
+}
+
+static void b43_calculate_link_quality(struct b43_wldev *dev)
+{
+ /* Top half of Link Quality calculation. */
+
+ if (dev->noisecalc.calculation_running)
+ return;
+ dev->noisecalc.channel_at_start = dev->phy.channel;
+ dev->noisecalc.calculation_running = 1;
+ dev->noisecalc.nr_samples = 0;
+
+ b43_generate_noise_sample(dev);
+}
+
+static void handle_irq_noise(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 tmp;
+ u8 noise[4];
+ u8 i, j;
+ s32 average;
+
+ /* Bottom half of Link Quality calculation. */
+
+ B43_WARN_ON(!dev->noisecalc.calculation_running);
+ if (dev->noisecalc.channel_at_start != phy->channel)
+ goto drop_calculation;
+ *((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev));
+ if (noise[0] == 0x7F || noise[1] == 0x7F ||
+ noise[2] == 0x7F || noise[3] == 0x7F)
+ goto generate_new;
+
+ /* Get the noise samples. */
+ B43_WARN_ON(dev->noisecalc.nr_samples >= 8);
+ i = dev->noisecalc.nr_samples;
+ noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
+ dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
+ dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
+ dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]];
+ dev->noisecalc.nr_samples++;
+ if (dev->noisecalc.nr_samples == 8) {
+ /* Calculate the Link Quality by the noise samples. */
+ average = 0;
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 4; j++)
+ average += dev->noisecalc.samples[i][j];
+ }
+ average /= (8 * 4);
+ average *= 125;
+ average += 64;
+ average /= 128;
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x40C);
+ tmp = (tmp / 128) & 0x1F;
+ if (tmp >= 8)
+ average += 2;
+ else
+ average -= 25;
+ if (tmp == 8)
+ average -= 72;
+ else
+ average -= 48;
+
+ dev->stats.link_noise = average;
+ drop_calculation:
+ dev->noisecalc.calculation_running = 0;
+ return;
+ }
+ generate_new:
+ b43_generate_noise_sample(dev);
+}
+
+static void handle_irq_tbtt_indication(struct b43_wldev *dev)
+{
+ if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
+ ///TODO: PS TBTT
+ } else {
+ if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
+ b43_power_saving_ctl_bits(dev, 0);
+ }
+ dev->reg124_set_0x4 = 0;
+ if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
+ dev->reg124_set_0x4 = 1;
+}
+
+static void handle_irq_atim_end(struct b43_wldev *dev)
+{
+ if (!dev->reg124_set_0x4 /*FIXME rename this variable */ )
+ return;
+ b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
+ b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
+ | 0x4);
+}
+
+static void handle_irq_pmq(struct b43_wldev *dev)
+{
+ u32 tmp;
+
+ //TODO: AP mode.
+
+ while (1) {
+ tmp = b43_read32(dev, B43_MMIO_PS_STATUS);
+ if (!(tmp & 0x00000008))
+ break;
+ }
+ /* 16bit write is odd, but correct. */
+ b43_write16(dev, B43_MMIO_PS_STATUS, 0x0002);
+}
+
+static void b43_write_template_common(struct b43_wldev *dev,
+ const u8 * data, u16 size,
+ u16 ram_offset,
+ u16 shm_size_offset, u8 rate)
+{
+ u32 i, tmp;
+ struct b43_plcp_hdr4 plcp;
+
+ plcp.data = 0;
+ b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+ b43_ram_write(dev, ram_offset, le32_to_cpu(plcp.data));
+ ram_offset += sizeof(u32);
+ /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet.
+ * So leave the first two bytes of the next write blank.
+ */
+ tmp = (u32) (data[0]) << 16;
+ tmp |= (u32) (data[1]) << 24;
+ b43_ram_write(dev, ram_offset, tmp);
+ ram_offset += sizeof(u32);
+ for (i = 2; i < size; i += sizeof(u32)) {
+ tmp = (u32) (data[i + 0]);
+ if (i + 1 < size)
+ tmp |= (u32) (data[i + 1]) << 8;
+ if (i + 2 < size)
+ tmp |= (u32) (data[i + 2]) << 16;
+ if (i + 3 < size)
+ tmp |= (u32) (data[i + 3]) << 24;
+ b43_ram_write(dev, ram_offset + i - 2, tmp);
+ }
+ b43_shm_write16(dev, B43_SHM_SHARED, shm_size_offset,
+ size + sizeof(struct b43_plcp_hdr6));
+}
+
+static void b43_write_beacon_template(struct b43_wldev *dev,
+ u16 ram_offset,
+ u16 shm_size_offset, u8 rate)
+{
+ int len;
+ const u8 *data;
+
+ B43_WARN_ON(!dev->cached_beacon);
+ len = min((size_t) dev->cached_beacon->len,
+ 0x200 - sizeof(struct b43_plcp_hdr6));
+ data = (const u8 *)(dev->cached_beacon->data);
+ b43_write_template_common(dev, data,
+ len, ram_offset, shm_size_offset, rate);
+}
+
+static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
+ u16 shm_offset, u16 size, u8 rate)
+{
+ struct b43_plcp_hdr4 plcp;
+ u32 tmp;
+ __le16 dur;
+
+ plcp.data = 0;
+ b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+ dur = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->if_id, size,
+ B43_RATE_TO_BASE100KBPS(rate));
+ /* Write PLCP in two parts and timing for packet transfer */
+ tmp = le32_to_cpu(plcp.data);
+ b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF);
+ b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 2, tmp >> 16);
+ b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 6, le16_to_cpu(dur));
+}
+
+/* Instead of using custom probe response template, this function
+ * just patches custom beacon template by:
+ * 1) Changing packet type
+ * 2) Patching duration field
+ * 3) Stripping TIM
+ */
+static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
+ u16 * dest_size, u8 rate)
+{
+ const u8 *src_data;
+ u8 *dest_data;
+ u16 src_size, elem_size, src_pos, dest_pos;
+ __le16 dur;
+ struct ieee80211_hdr *hdr;
+
+ B43_WARN_ON(!dev->cached_beacon);
+ src_size = dev->cached_beacon->len;
+ src_data = (const u8 *)dev->cached_beacon->data;
+
+ if (unlikely(src_size < 0x24)) {
+ b43dbg(dev->wl, "b43_generate_probe_resp: " "invalid beacon\n");
+ return NULL;
+ }
+
+ dest_data = kmalloc(src_size, GFP_ATOMIC);
+ if (unlikely(!dest_data))
+ return NULL;
+
+ /* 0x24 is offset of first variable-len Information-Element
+ * in beacon frame.
+ */
+ memcpy(dest_data, src_data, 0x24);
+ src_pos = dest_pos = 0x24;
+ for (; src_pos < src_size - 2; src_pos += elem_size) {
+ elem_size = src_data[src_pos + 1] + 2;
+ if (src_data[src_pos] != 0x05) { /* TIM */
+ memcpy(dest_data + dest_pos, src_data + src_pos,
+ elem_size);
+ dest_pos += elem_size;
+ }
+ }
+ *dest_size = dest_pos;
+ hdr = (struct ieee80211_hdr *)dest_data;
+
+ /* Set the frame control. */
+ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_PROBE_RESP);
+ dur = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->if_id, *dest_size,
+ B43_RATE_TO_BASE100KBPS(rate));
+ hdr->duration_id = dur;
+
+ return dest_data;
+}
+
+static void b43_write_probe_resp_template(struct b43_wldev *dev,
+ u16 ram_offset,
+ u16 shm_size_offset, u8 rate)
+{
+ u8 *probe_resp_data;
+ u16 size;
+
+ B43_WARN_ON(!dev->cached_beacon);
+ size = dev->cached_beacon->len;
+ probe_resp_data = b43_generate_probe_resp(dev, &size, rate);
+ if (unlikely(!probe_resp_data))
+ return;
+
+ /* Looks like PLCP headers plus packet timings are stored for
+ * all possible basic rates
+ */
+ b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB);
+ b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB);
+ b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB);
+ b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB);
+
+ size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6));
+ b43_write_template_common(dev, probe_resp_data,
+ size, ram_offset, shm_size_offset, rate);
+ kfree(probe_resp_data);
+}
+
+static int b43_refresh_cached_beacon(struct b43_wldev *dev,
+ struct sk_buff *beacon)
+{
+ if (dev->cached_beacon)
+ kfree_skb(dev->cached_beacon);
+ dev->cached_beacon = beacon;
+
+ return 0;
+}
+
+static void b43_update_templates(struct b43_wldev *dev)
+{
+ u32 status;
+
+ B43_WARN_ON(!dev->cached_beacon);
+
+ b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
+ b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
+ b43_write_probe_resp_template(dev, 0x268, 0x4A, B43_CCK_RATE_11MB);
+
+ status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
+ status |= 0x03;
+ b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+}
+
+static void b43_refresh_templates(struct b43_wldev *dev, struct sk_buff *beacon)
+{
+ int err;
+
+ err = b43_refresh_cached_beacon(dev, beacon);
+ if (unlikely(err))
+ return;
+ b43_update_templates(dev);
+}
+
+static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len)
+{
+ u32 tmp;
+ u16 i, len;
+
+ len = min((u16) ssid_len, (u16) 0x100);
+ for (i = 0; i < len; i += sizeof(u32)) {
+ tmp = (u32) (ssid[i + 0]);
+ if (i + 1 < len)
+ tmp |= (u32) (ssid[i + 1]) << 8;
+ if (i + 2 < len)
+ tmp |= (u32) (ssid[i + 2]) << 16;
+ if (i + 3 < len)
+ tmp |= (u32) (ssid[i + 3]) << 24;
+ b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp);
+ }
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len);
+}
+
+static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
+{
+ b43_time_lock(dev);
+ if (dev->dev->id.revision >= 3) {
+ b43_write32(dev, 0x188, (beacon_int << 16));
+ } else {
+ b43_write16(dev, 0x606, (beacon_int >> 6));
+ b43_write16(dev, 0x610, beacon_int);
+ }
+ b43_time_unlock(dev);
+}
+
+static void handle_irq_beacon(struct b43_wldev *dev)
+{
+ u32 status;
+
+ if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ return;
+
+ dev->irq_savedstate &= ~B43_IRQ_BEACON;
+ status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
+
+ if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
+ /* ACK beacon IRQ. */
+ b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
+ dev->irq_savedstate |= B43_IRQ_BEACON;
+ if (dev->cached_beacon)
+ kfree_skb(dev->cached_beacon);
+ dev->cached_beacon = NULL;
+ return;
+ }
+ if (!(status & 0x1)) {
+ b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
+ status |= 0x1;
+ b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+ }
+ if (!(status & 0x2)) {
+ b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
+ status |= 0x2;
+ b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+ }
+}
+
+static void handle_irq_ucode_debug(struct b43_wldev *dev)
+{
+ //TODO
+}
+
+/* Interrupt handler bottom-half */
+static void b43_interrupt_tasklet(struct b43_wldev *dev)
+{
+ u32 reason;
+ u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
+ u32 merged_dma_reason = 0;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+
+ B43_WARN_ON(b43_status(dev) != B43_STAT_STARTED);
+
+ reason = dev->irq_reason;
+ for (i = 0; i < ARRAY_SIZE(dma_reason); i++) {
+ dma_reason[i] = dev->dma_reason[i];
+ merged_dma_reason |= dma_reason[i];
+ }
+
+ if (unlikely(reason & B43_IRQ_MAC_TXERR))
+ b43err(dev->wl, "MAC transmission error\n");
+
+ if (unlikely(reason & B43_IRQ_PHY_TXERR))
+ b43err(dev->wl, "PHY transmission error\n");
+
+ if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK |
+ B43_DMAIRQ_NONFATALMASK))) {
+ if (merged_dma_reason & B43_DMAIRQ_FATALMASK) {
+ b43err(dev->wl, "Fatal DMA error: "
+ "0x%08X, 0x%08X, 0x%08X, "
+ "0x%08X, 0x%08X, 0x%08X\n",
+ dma_reason[0], dma_reason[1],
+ dma_reason[2], dma_reason[3],
+ dma_reason[4], dma_reason[5]);
+ b43_controller_restart(dev, "DMA error");
+ mmiowb();
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+ return;
+ }
+ if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
+ b43err(dev->wl, "DMA error: "
+ "0x%08X, 0x%08X, 0x%08X, "
+ "0x%08X, 0x%08X, 0x%08X\n",
+ dma_reason[0], dma_reason[1],
+ dma_reason[2], dma_reason[3],
+ dma_reason[4], dma_reason[5]);
+ }
+ }
+
+ if (unlikely(reason & B43_IRQ_UCODE_DEBUG))
+ handle_irq_ucode_debug(dev);
+ if (reason & B43_IRQ_TBTT_INDI)
+ handle_irq_tbtt_indication(dev);
+ if (reason & B43_IRQ_ATIM_END)
+ handle_irq_atim_end(dev);
+ if (reason & B43_IRQ_BEACON)
+ handle_irq_beacon(dev);
+ if (reason & B43_IRQ_PMQ)
+ handle_irq_pmq(dev);
+ if (reason & B43_IRQ_TXFIFO_FLUSH_OK)
+ ;/* TODO */
+ if (reason & B43_IRQ_NOISESAMPLE_OK)
+ handle_irq_noise(dev);
+
+ /* Check the DMA reason registers for received data. */
+ if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
+ if (b43_using_pio(dev))
+ b43_pio_rx(dev->pio.queue0);
+ else
+ b43_dma_rx(dev->dma.rx_ring0);
+ }
+ B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
+ B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
+ if (dma_reason[3] & B43_DMAIRQ_RX_DONE) {
+ if (b43_using_pio(dev))
+ b43_pio_rx(dev->pio.queue3);
+ else
+ b43_dma_rx(dev->dma.rx_ring3);
+ }
+ B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
+ B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
+
+ if (reason & B43_IRQ_TX_OK)
+ handle_irq_transmit_status(dev);
+
+ b43_interrupt_enable(dev, dev->irq_savedstate);
+ mmiowb();
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+}
+
+static void pio_irq_workaround(struct b43_wldev *dev, u16 base, int queueidx)
+{
+ u16 rxctl;
+
+ rxctl = b43_read16(dev, base + B43_PIO_RXCTL);
+ if (rxctl & B43_PIO_RXCTL_DATAAVAILABLE)
+ dev->dma_reason[queueidx] |= B43_DMAIRQ_RX_DONE;
+ else
+ dev->dma_reason[queueidx] &= ~B43_DMAIRQ_RX_DONE;
+}
+
+static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason)
+{
+ if (b43_using_pio(dev) &&
+ (dev->dev->id.revision < 3) &&
+ (!(reason & B43_IRQ_PIO_WORKAROUND))) {
+ /* Apply a PIO specific workaround to the dma_reasons */
+ pio_irq_workaround(dev, B43_MMIO_PIO1_BASE, 0);
+ pio_irq_workaround(dev, B43_MMIO_PIO2_BASE, 1);
+ pio_irq_workaround(dev, B43_MMIO_PIO3_BASE, 2);
+ pio_irq_workaround(dev, B43_MMIO_PIO4_BASE, 3);
+ }
+
+ b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
+
+ b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
+ b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]);
+ b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]);
+ b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]);
+ b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]);
+ b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]);
+}
+
+/* Interrupt handler top-half */
+static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
+{
+ irqreturn_t ret = IRQ_NONE;
+ struct b43_wldev *dev = dev_id;
+ u32 reason;
+
+ if (!dev)
+ return IRQ_NONE;
+
+ spin_lock(&dev->wl->irq_lock);
+
+ if (b43_status(dev) < B43_STAT_STARTED)
+ goto out;
+ reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+ if (reason == 0xffffffff) /* shared IRQ */
+ goto out;
+ ret = IRQ_HANDLED;
+ reason &= b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
+ if (!reason)
+ goto out;
+
+ dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
+ & 0x0001DC00;
+ dev->dma_reason[1] = b43_read32(dev, B43_MMIO_DMA1_REASON)
+ & 0x0000DC00;
+ dev->dma_reason[2] = b43_read32(dev, B43_MMIO_DMA2_REASON)
+ & 0x0000DC00;
+ dev->dma_reason[3] = b43_read32(dev, B43_MMIO_DMA3_REASON)
+ & 0x0001DC00;
+ dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON)
+ & 0x0000DC00;
+ dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON)
+ & 0x0000DC00;
+
+ b43_interrupt_ack(dev, reason);
+ /* disable all IRQs. They are enabled again in the bottom half. */
+ dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
+ /* save the reason code and call our bottom half. */
+ dev->irq_reason = reason;
+ tasklet_schedule(&dev->isr_tasklet);
+ out:
+ mmiowb();
+ spin_unlock(&dev->wl->irq_lock);
+
+ return ret;
+}
+
+static void b43_release_firmware(struct b43_wldev *dev)
+{
+ release_firmware(dev->fw.ucode);
+ dev->fw.ucode = NULL;
+ release_firmware(dev->fw.pcm);
+ dev->fw.pcm = NULL;
+ release_firmware(dev->fw.initvals);
+ dev->fw.initvals = NULL;
+ release_firmware(dev->fw.initvals_band);
+ dev->fw.initvals_band = NULL;
+}
+
+static void b43_print_fw_helptext(struct b43_wl *wl)
+{
+ b43err(wl, "You must go to "
+ "http://linuxwireless.org/en/users/Drivers/bcm43xx#devicefirmware "
+ "and download the correct firmware (version 4).\n");
+}
+
+static int do_request_fw(struct b43_wldev *dev,
+ const char *name,
+ const struct firmware **fw)
+{
+ char path[sizeof(modparam_fwpostfix) + 32];
+ struct b43_fw_header *hdr;
+ u32 size;
+ int err;
+
+ if (!name)
+ return 0;
+
+ snprintf(path, ARRAY_SIZE(path),
+ "b43%s/%s.fw",
+ modparam_fwpostfix, name);
+ err = request_firmware(fw, path, dev->dev->dev);
+ if (err) {
+ b43err(dev->wl, "Firmware file \"%s\" not found "
+ "or load failed.\n", path);
+ return err;
+ }
+ if ((*fw)->size < sizeof(struct b43_fw_header))
+ goto err_format;
+ hdr = (struct b43_fw_header *)((*fw)->data);
+ switch (hdr->type) {
+ case B43_FW_TYPE_UCODE:
+ case B43_FW_TYPE_PCM:
+ size = be32_to_cpu(hdr->size);
+ if (size != (*fw)->size - sizeof(struct b43_fw_header))
+ goto err_format;
+ /* fallthrough */
+ case B43_FW_TYPE_IV:
+ if (hdr->ver != 1)
+ goto err_format;
+ break;
+ default:
+ goto err_format;
+ }
+
+ return err;
+
+err_format:
+ b43err(dev->wl, "Firmware file \"%s\" format error.\n", path);
+ return -EPROTO;
+}
+
+static int b43_request_firmware(struct b43_wldev *dev)
+{
+ struct b43_firmware *fw = &dev->fw;
+ const u8 rev = dev->dev->id.revision;
+ const char *filename;
+ u32 tmshigh;
+ int err;
+
+ tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+ if (!fw->ucode) {
+ if ((rev >= 5) && (rev <= 10))
+ filename = "ucode5";
+ else if ((rev >= 11) && (rev <= 12))
+ filename = "ucode11";
+ else if (rev >= 13)
+ filename = "ucode13";
+ else
+ goto err_no_ucode;
+ err = do_request_fw(dev, filename, &fw->ucode);
+ if (err)
+ goto err_load;
+ }
+ if (!fw->pcm) {
+ if ((rev >= 5) && (rev <= 10))
+ filename = "pcm5";
+ else if (rev >= 11)
+ filename = NULL;
+ else
+ goto err_no_pcm;
+ err = do_request_fw(dev, filename, &fw->pcm);
+ if (err)
+ goto err_load;
+ }
+ if (!fw->initvals) {
+ switch (dev->phy.type) {
+ case B43_PHYTYPE_A:
+ if ((rev >= 5) && (rev <= 10)) {
+ if (tmshigh & B43_TMSHIGH_GPHY)
+ filename = "a0g1initvals5";
+ else
+ filename = "a0g0initvals5";
+ } else
+ goto err_no_initvals;
+ break;
+ case B43_PHYTYPE_G:
+ if ((rev >= 5) && (rev <= 10))
+ filename = "b0g0initvals5";
+ else if (rev >= 13)
+ filename = "lp0initvals13";
+ else
+ goto err_no_initvals;
+ break;
+ default:
+ goto err_no_initvals;
+ }
+ err = do_request_fw(dev, filename, &fw->initvals);
+ if (err)
+ goto err_load;
+ }
+ if (!fw->initvals_band) {
+ switch (dev->phy.type) {
+ case B43_PHYTYPE_A:
+ if ((rev >= 5) && (rev <= 10)) {
+ if (tmshigh & B43_TMSHIGH_GPHY)
+ filename = "a0g1bsinitvals5";
+ else
+ filename = "a0g0bsinitvals5";
+ } else if (rev >= 11)
+ filename = NULL;
+ else
+ goto err_no_initvals;
+ break;
+ case B43_PHYTYPE_G:
+ if ((rev >= 5) && (rev <= 10))
+ filename = "b0g0bsinitvals5";
+ else if (rev >= 11)
+ filename = NULL;
+ else
+ goto err_no_initvals;
+ break;
+ default:
+ goto err_no_initvals;
+ }
+ err = do_request_fw(dev, filename, &fw->initvals_band);
+ if (err)
+ goto err_load;
+ }
+
+ return 0;
+
+err_load:
+ b43_print_fw_helptext(dev->wl);
+ goto error;
+
+err_no_ucode:
+ err = -ENODEV;
+ b43err(dev->wl, "No microcode available for core rev %u\n", rev);
+ goto error;
+
+err_no_pcm:
+ err = -ENODEV;
+ b43err(dev->wl, "No PCM available for core rev %u\n", rev);
+ goto error;
+
+err_no_initvals:
+ err = -ENODEV;
+ b43err(dev->wl, "No Initial Values firmware file for PHY %u, "
+ "core rev %u\n", dev->phy.type, rev);
+ goto error;
+
+error:
+ b43_release_firmware(dev);
+ return err;
+}
+
+static int b43_upload_microcode(struct b43_wldev *dev)
+{
+ const size_t hdr_len = sizeof(struct b43_fw_header);
+ const __be32 *data;
+ unsigned int i, len;
+ u16 fwrev, fwpatch, fwdate, fwtime;
+ u32 tmp;
+ int err = 0;
+
+ /* Upload Microcode. */
+ data = (__be32 *) (dev->fw.ucode->data + hdr_len);
+ len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
+ b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
+ for (i = 0; i < len; i++) {
+ b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
+ udelay(10);
+ }
+
+ if (dev->fw.pcm) {
+ /* Upload PCM data. */
+ data = (__be32 *) (dev->fw.pcm->data + hdr_len);
+ len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32);
+ b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
+ b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
+ /* No need for autoinc bit in SHM_HW */
+ b43_shm_control_word(dev, B43_SHM_HW, 0x01EB);
+ for (i = 0; i < len; i++) {
+ b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
+ udelay(10);
+ }
+ }
+
+ b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL);
+ b43_write32(dev, B43_MMIO_MACCTL,
+ B43_MACCTL_PSM_RUN |
+ B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA);
+
+ /* Wait for the microcode to load and respond */
+ i = 0;
+ while (1) {
+ tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+ if (tmp == B43_IRQ_MAC_SUSPENDED)
+ break;
+ i++;
+ if (i >= 50) {
+ b43err(dev->wl, "Microcode not responding\n");
+ b43_print_fw_helptext(dev->wl);
+ err = -ENODEV;
+ goto out;
+ }
+ udelay(10);
+ }
+ b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); /* dummy read */
+
+ /* Get and check the revisions. */
+ fwrev = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEREV);
+ fwpatch = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEPATCH);
+ fwdate = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEDATE);
+ fwtime = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODETIME);
+
+ if (fwrev <= 0x128) {
+ b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from "
+ "binary drivers older than version 4.x is unsupported. "
+ "You must upgrade your firmware files.\n");
+ b43_print_fw_helptext(dev->wl);
+ b43_write32(dev, B43_MMIO_MACCTL, 0);
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+ b43dbg(dev->wl, "Loading firmware version %u.%u "
+ "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
+ fwrev, fwpatch,
+ (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
+ (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
+
+ dev->fw.rev = fwrev;
+ dev->fw.patch = fwpatch;
+
+ out:
+ return err;
+}
+
+static int b43_write_initvals(struct b43_wldev *dev,
+ const struct b43_iv *ivals,
+ size_t count,
+ size_t array_size)
+{
+ const struct b43_iv *iv;
+ u16 offset;
+ size_t i;
+ bool bit32;
+
+ BUILD_BUG_ON(sizeof(struct b43_iv) != 6);
+ iv = ivals;
+ for (i = 0; i < count; i++) {
+ if (array_size < sizeof(iv->offset_size))
+ goto err_format;
+ array_size -= sizeof(iv->offset_size);
+ offset = be16_to_cpu(iv->offset_size);
+ bit32 = !!(offset & B43_IV_32BIT);
+ offset &= B43_IV_OFFSET_MASK;
+ if (offset >= 0x1000)
+ goto err_format;
+ if (bit32) {
+ u32 value;
+
+ if (array_size < sizeof(iv->data.d32))
+ goto err_format;
+ array_size -= sizeof(iv->data.d32);
+
+ value = be32_to_cpu(get_unaligned(&iv->data.d32));
+ b43_write32(dev, offset, value);
+
+ iv = (const struct b43_iv *)((const uint8_t *)iv +
+ sizeof(__be16) +
+ sizeof(__be32));
+ } else {
+ u16 value;
+
+ if (array_size < sizeof(iv->data.d16))
+ goto err_format;
+ array_size -= sizeof(iv->data.d16);
+
+ value = be16_to_cpu(iv->data.d16);
+ b43_write16(dev, offset, value);
+
+ iv = (const struct b43_iv *)((const uint8_t *)iv +
+ sizeof(__be16) +
+ sizeof(__be16));
+ }
+ }
+ if (array_size)
+ goto err_format;
+
+ return 0;
+
+err_format:
+ b43err(dev->wl, "Initial Values Firmware file-format error.\n");
+ b43_print_fw_helptext(dev->wl);
+
+ return -EPROTO;
+}
+
+static int b43_upload_initvals(struct b43_wldev *dev)
+{
+ const size_t hdr_len = sizeof(struct b43_fw_header);
+ const struct b43_fw_header *hdr;
+ struct b43_firmware *fw = &dev->fw;
+ const struct b43_iv *ivals;
+ size_t count;
+ int err;
+
+ hdr = (const struct b43_fw_header *)(fw->initvals->data);
+ ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len);
+ count = be32_to_cpu(hdr->size);
+ err = b43_write_initvals(dev, ivals, count,
+ fw->initvals->size - hdr_len);
+ if (err)
+ goto out;
+ if (fw->initvals_band) {
+ hdr = (const struct b43_fw_header *)(fw->initvals_band->data);
+ ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len);
+ count = be32_to_cpu(hdr->size);
+ err = b43_write_initvals(dev, ivals, count,
+ fw->initvals_band->size - hdr_len);
+ if (err)
+ goto out;
+ }
+out:
+
+ return err;
+}
+
+/* Initialize the GPIOs
+ * http://bcm-specs.sipsolutions.net/GPIO
+ */
+static int b43_gpio_init(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_device *gpiodev, *pcidev = NULL;
+ u32 mask, set;
+
+ b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
+ & ~B43_MACCTL_GPOUTSMSK);
+
+ b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK)
+ | 0x000F);
+
+ mask = 0x0000001F;
+ set = 0x0000000F;
+ if (dev->dev->bus->chip_id == 0x4301) {
+ mask |= 0x0060;
+ set |= 0x0060;
+ }
+ if (0 /* FIXME: conditional unknown */ ) {
+ b43_write16(dev, B43_MMIO_GPIO_MASK,
+ b43_read16(dev, B43_MMIO_GPIO_MASK)
+ | 0x0100);
+ mask |= 0x0180;
+ set |= 0x0180;
+ }
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) {
+ b43_write16(dev, B43_MMIO_GPIO_MASK,
+ b43_read16(dev, B43_MMIO_GPIO_MASK)
+ | 0x0200);
+ mask |= 0x0200;
+ set |= 0x0200;
+ }
+ if (dev->dev->id.revision >= 2)
+ mask |= 0x0010; /* FIXME: This is redundant. */
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ pcidev = bus->pcicore.dev;
+#endif
+ gpiodev = bus->chipco.dev ? : pcidev;
+ if (!gpiodev)
+ return 0;
+ ssb_write32(gpiodev, B43_GPIO_CONTROL,
+ (ssb_read32(gpiodev, B43_GPIO_CONTROL)
+ & mask) | set);
+
+ return 0;
+}
+
+/* Turn off all GPIO stuff. Call this on module unload, for example. */
+static void b43_gpio_cleanup(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_device *gpiodev, *pcidev = NULL;
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ pcidev = bus->pcicore.dev;
+#endif
+ gpiodev = bus->chipco.dev ? : pcidev;
+ if (!gpiodev)
+ return;
+ ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
+}
+
+/* http://bcm-specs.sipsolutions.net/EnableMac */
+void b43_mac_enable(struct b43_wldev *dev)
+{
+ dev->mac_suspended--;
+ B43_WARN_ON(dev->mac_suspended < 0);
+ B43_WARN_ON(irqs_disabled());
+ if (dev->mac_suspended == 0) {
+ b43_write32(dev, B43_MMIO_MACCTL,
+ b43_read32(dev, B43_MMIO_MACCTL)
+ | B43_MACCTL_ENABLED);
+ b43_write32(dev, B43_MMIO_GEN_IRQ_REASON,
+ B43_IRQ_MAC_SUSPENDED);
+ /* Commit writes */
+ b43_read32(dev, B43_MMIO_MACCTL);
+ b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+ b43_power_saving_ctl_bits(dev, 0);
+
+ /* Re-enable IRQs. */
+ spin_lock_irq(&dev->wl->irq_lock);
+ b43_interrupt_enable(dev, dev->irq_savedstate);
+ spin_unlock_irq(&dev->wl->irq_lock);
+ }
+}
+
+/* http://bcm-specs.sipsolutions.net/SuspendMAC */
+void b43_mac_suspend(struct b43_wldev *dev)
+{
+ int i;
+ u32 tmp;
+
+ might_sleep();
+ B43_WARN_ON(irqs_disabled());
+ B43_WARN_ON(dev->mac_suspended < 0);
+
+ if (dev->mac_suspended == 0) {
+ /* Mask IRQs before suspending MAC. Otherwise
+ * the MAC stays busy and won't suspend. */
+ spin_lock_irq(&dev->wl->irq_lock);
+ tmp = b43_interrupt_disable(dev, B43_IRQ_ALL);
+ spin_unlock_irq(&dev->wl->irq_lock);
+ b43_synchronize_irq(dev);
+ dev->irq_savedstate = tmp;
+
+ b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
+ b43_write32(dev, B43_MMIO_MACCTL,
+ b43_read32(dev, B43_MMIO_MACCTL)
+ & ~B43_MACCTL_ENABLED);
+ /* force pci to flush the write */
+ b43_read32(dev, B43_MMIO_MACCTL);
+ for (i = 40; i; i--) {
+ tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+ if (tmp & B43_IRQ_MAC_SUSPENDED)
+ goto out;
+ msleep(1);
+ }
+ b43err(dev->wl, "MAC suspend failed\n");
+ }
+out:
+ dev->mac_suspended++;
+}
+
+static void b43_adjust_opmode(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ u32 ctl;
+ u16 cfp_pretbtt;
+
+ ctl = b43_read32(dev, B43_MMIO_MACCTL);
+ /* Reset status to STA infrastructure mode. */
+ ctl &= ~B43_MACCTL_AP;
+ ctl &= ~B43_MACCTL_KEEP_CTL;
+ ctl &= ~B43_MACCTL_KEEP_BADPLCP;
+ ctl &= ~B43_MACCTL_KEEP_BAD;
+ ctl &= ~B43_MACCTL_PROMISC;
+ ctl &= ~B43_MACCTL_BEACPROMISC;
+ ctl |= B43_MACCTL_INFRA;
+
+ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ ctl |= B43_MACCTL_AP;
+ else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+ ctl &= ~B43_MACCTL_INFRA;
+
+ if (wl->filter_flags & FIF_CONTROL)
+ ctl |= B43_MACCTL_KEEP_CTL;
+ if (wl->filter_flags & FIF_FCSFAIL)
+ ctl |= B43_MACCTL_KEEP_BAD;
+ if (wl->filter_flags & FIF_PLCPFAIL)
+ ctl |= B43_MACCTL_KEEP_BADPLCP;
+ if (wl->filter_flags & FIF_PROMISC_IN_BSS)
+ ctl |= B43_MACCTL_PROMISC;
+ if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
+ ctl |= B43_MACCTL_BEACPROMISC;
+
+ /* Workaround: On old hardware the HW-MAC-address-filter
+ * doesn't work properly, so always run promisc in filter
+ * it in software. */
+ if (dev->dev->id.revision <= 4)
+ ctl |= B43_MACCTL_PROMISC;
+
+ b43_write32(dev, B43_MMIO_MACCTL, ctl);
+
+ cfp_pretbtt = 2;
+ if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) {
+ if (dev->dev->bus->chip_id == 0x4306 &&
+ dev->dev->bus->chip_rev == 3)
+ cfp_pretbtt = 100;
+ else
+ cfp_pretbtt = 50;
+ }
+ b43_write16(dev, 0x612, cfp_pretbtt);
+}
+
+static void b43_rate_memory_write(struct b43_wldev *dev, u16 rate, int is_ofdm)
+{
+ u16 offset;
+
+ if (is_ofdm) {
+ offset = 0x480;
+ offset += (b43_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
+ } else {
+ offset = 0x4C0;
+ offset += (b43_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
+ }
+ b43_shm_write16(dev, B43_SHM_SHARED, offset + 0x20,
+ b43_shm_read16(dev, B43_SHM_SHARED, offset));
+}
+
+static void b43_rate_memory_init(struct b43_wldev *dev)
+{
+ switch (dev->phy.type) {
+ case B43_PHYTYPE_A:
+ case B43_PHYTYPE_G:
+ b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
+ b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
+ b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
+ b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1);
+ b43_rate_memory_write(dev, B43_OFDM_RATE_36MB, 1);
+ b43_rate_memory_write(dev, B43_OFDM_RATE_48MB, 1);
+ b43_rate_memory_write(dev, B43_OFDM_RATE_54MB, 1);
+ if (dev->phy.type == B43_PHYTYPE_A)
+ break;
+ /* fallthrough */
+ case B43_PHYTYPE_B:
+ b43_rate_memory_write(dev, B43_CCK_RATE_1MB, 0);
+ b43_rate_memory_write(dev, B43_CCK_RATE_2MB, 0);
+ b43_rate_memory_write(dev, B43_CCK_RATE_5MB, 0);
+ b43_rate_memory_write(dev, B43_CCK_RATE_11MB, 0);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+/* Set the TX-Antenna for management frames sent by firmware. */
+static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
+{
+ u16 ant = 0;
+ u16 tmp;
+
+ switch (antenna) {
+ case B43_ANTENNA0:
+ ant |= B43_TX4_PHY_ANT0;
+ break;
+ case B43_ANTENNA1:
+ ant |= B43_TX4_PHY_ANT1;
+ break;
+ case B43_ANTENNA_AUTO:
+ ant |= B43_TX4_PHY_ANTLAST;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+
+ /* FIXME We also need to set the other flags of the PHY control field somewhere. */
+
+ /* For Beacons */
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
+ tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp);
+ /* For ACK/CTS */
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL);
+ tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp);
+ /* For Probe Resposes */
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL);
+ tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp);
+}
+
+/* This is the opposite of b43_chip_init() */
+static void b43_chip_exit(struct b43_wldev *dev)
+{
+ b43_radio_turn_off(dev, 1);
+ b43_leds_exit(dev);
+ b43_gpio_cleanup(dev);
+ /* firmware is released later */
+}
+
+/* Initialize the chip
+ * http://bcm-specs.sipsolutions.net/ChipInit
+ */
+static int b43_chip_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ int err, tmp;
+ u32 value32;
+ u16 value16;
+
+ b43_write32(dev, B43_MMIO_MACCTL,
+ B43_MACCTL_PSM_JMP0 | B43_MACCTL_IHR_ENABLED);
+
+ err = b43_request_firmware(dev);
+ if (err)
+ goto out;
+ err = b43_upload_microcode(dev);
+ if (err)
+ goto out; /* firmware is released later */
+
+ err = b43_gpio_init(dev);
+ if (err)
+ goto out; /* firmware is released later */
+ b43_leds_init(dev);
+
+ err = b43_upload_initvals(dev);
+ if (err)
+ goto err_leds_exit;
+ b43_radio_turn_on(dev);
+
+ b43_write16(dev, 0x03E6, 0x0000);
+ err = b43_phy_init(dev);
+ if (err)
+ goto err_radio_off;
+
+ /* Select initial Interference Mitigation. */
+ tmp = phy->interfmode;
+ phy->interfmode = B43_INTERFMODE_NONE;
+ b43_radio_set_interference_mitigation(dev, tmp);
+
+ b43_set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
+ b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT);
+
+ if (phy->type == B43_PHYTYPE_B) {
+ value16 = b43_read16(dev, 0x005E);
+ value16 |= 0x0004;
+ b43_write16(dev, 0x005E, value16);
+ }
+ b43_write32(dev, 0x0100, 0x01000000);
+ if (dev->dev->id.revision < 5)
+ b43_write32(dev, 0x010C, 0x01000000);
+
+ b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
+ & ~B43_MACCTL_INFRA);
+ b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
+ | B43_MACCTL_INFRA);
+
+ if (b43_using_pio(dev)) {
+ b43_write32(dev, 0x0210, 0x00000100);
+ b43_write32(dev, 0x0230, 0x00000100);
+ b43_write32(dev, 0x0250, 0x00000100);
+ b43_write32(dev, 0x0270, 0x00000100);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0034, 0x0000);
+ }
+
+ /* Probe Response Timeout value */
+ /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000);
+
+ /* Initially set the wireless operation mode. */
+ b43_adjust_opmode(dev);
+
+ if (dev->dev->id.revision < 3) {
+ b43_write16(dev, 0x060E, 0x0000);
+ b43_write16(dev, 0x0610, 0x8000);
+ b43_write16(dev, 0x0604, 0x0000);
+ b43_write16(dev, 0x0606, 0x0200);
+ } else {
+ b43_write32(dev, 0x0188, 0x80000000);
+ b43_write32(dev, 0x018C, 0x02000000);
+ }
+ b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, 0x00004000);
+ b43_write32(dev, B43_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
+ b43_write32(dev, B43_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
+ b43_write32(dev, B43_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
+ b43_write32(dev, B43_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
+ b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
+ b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
+
+ value32 = ssb_read32(dev->dev, SSB_TMSLOW);
+ value32 |= 0x00100000;
+ ssb_write32(dev->dev, SSB_TMSLOW, value32);
+
+ b43_write16(dev, B43_MMIO_POWERUP_DELAY,
+ dev->dev->bus->chipco.fast_pwrup_delay);
+
+ err = 0;
+ b43dbg(dev->wl, "Chip initialized\n");
+out:
+ return err;
+
+err_radio_off:
+ b43_radio_turn_off(dev, 1);
+err_leds_exit:
+ b43_leds_exit(dev);
+ b43_gpio_cleanup(dev);
+ return err;
+}
+
+static void b43_periodic_every120sec(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (phy->type != B43_PHYTYPE_G || phy->rev < 2)
+ return;
+
+ b43_mac_suspend(dev);
+ b43_lo_g_measure(dev);
+ b43_mac_enable(dev);
+ if (b43_has_hardware_pctl(phy))
+ b43_lo_g_ctl_mark_all_unused(dev);
+}
+
+static void b43_periodic_every60sec(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (!b43_has_hardware_pctl(phy))
+ b43_lo_g_ctl_mark_all_unused(dev);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+ b43_mac_suspend(dev);
+ b43_calc_nrssi_slope(dev);
+ if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
+ u8 old_chan = phy->channel;
+
+ /* VCO Calibration */
+ if (old_chan >= 8)
+ b43_radio_selectchannel(dev, 1, 0);
+ else
+ b43_radio_selectchannel(dev, 13, 0);
+ b43_radio_selectchannel(dev, old_chan, 0);
+ }
+ b43_mac_enable(dev);
+ }
+}
+
+static void b43_periodic_every30sec(struct b43_wldev *dev)
+{
+ /* Update device statistics. */
+ b43_calculate_link_quality(dev);
+}
+
+static void b43_periodic_every15sec(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (phy->type == B43_PHYTYPE_G) {
+ //TODO: update_aci_moving_average
+ if (phy->aci_enable && phy->aci_wlan_automatic) {
+ b43_mac_suspend(dev);
+ if (!phy->aci_enable && 1 /*TODO: not scanning? */ ) {
+ if (0 /*TODO: bunch of conditions */ ) {
+ b43_radio_set_interference_mitigation
+ (dev, B43_INTERFMODE_MANUALWLAN);
+ }
+ } else if (1 /*TODO*/) {
+ /*
+ if ((aci_average > 1000) && !(b43_radio_aci_scan(dev))) {
+ b43_radio_set_interference_mitigation(dev,
+ B43_INTERFMODE_NONE);
+ }
+ */
+ }
+ b43_mac_enable(dev);
+ } else if (phy->interfmode == B43_INTERFMODE_NONWLAN &&
+ phy->rev == 1) {
+ //TODO: implement rev1 workaround
+ }
+ }
+ b43_phy_xmitpower(dev); //FIXME: unless scanning?
+ //TODO for APHY (temperature?)
+}
+
+static void do_periodic_work(struct b43_wldev *dev)
+{
+ unsigned int state;
+
+ state = dev->periodic_state;
+ if (state % 8 == 0)
+ b43_periodic_every120sec(dev);
+ if (state % 4 == 0)
+ b43_periodic_every60sec(dev);
+ if (state % 2 == 0)
+ b43_periodic_every30sec(dev);
+ b43_periodic_every15sec(dev);
+}
+
+/* Periodic work locking policy:
+ * The whole periodic work handler is protected by
+ * wl->mutex. If another lock is needed somewhere in the
+ * pwork callchain, it's aquired in-place, where it's needed.
+ */
+static void b43_periodic_work_handler(struct work_struct *work)
+{
+ struct b43_wldev *dev = container_of(work, struct b43_wldev,
+ periodic_work.work);
+ struct b43_wl *wl = dev->wl;
+ unsigned long delay;
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(b43_status(dev) != B43_STAT_STARTED))
+ goto out;
+ if (b43_debug(dev, B43_DBG_PWORK_STOP))
+ goto out_requeue;
+
+ do_periodic_work(dev);
+
+ dev->periodic_state++;
+out_requeue:
+ if (b43_debug(dev, B43_DBG_PWORK_FAST))
+ delay = msecs_to_jiffies(50);
+ else
+ delay = round_jiffies_relative(HZ * 15);
+ queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+static void b43_periodic_tasks_setup(struct b43_wldev *dev)
+{
+ struct delayed_work *work = &dev->periodic_work;
+
+ dev->periodic_state = 0;
+ INIT_DELAYED_WORK(work, b43_periodic_work_handler);
+ queue_delayed_work(dev->wl->hw->workqueue, work, 0);
+}
+
+/* Validate access to the chip (SHM) */
+static int b43_validate_chipaccess(struct b43_wldev *dev)
+{
+ u32 value;
+ u32 shm_backup;
+
+ shm_backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
+ b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
+ if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
+ goto error;
+ b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55);
+ if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55)
+ goto error;
+ b43_shm_write32(dev, B43_SHM_SHARED, 0, shm_backup);
+
+ value = b43_read32(dev, B43_MMIO_MACCTL);
+ if ((value | B43_MACCTL_GMODE) !=
+ (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
+ goto error;
+
+ value = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+ if (value)
+ goto error;
+
+ return 0;
+ error:
+ b43err(dev->wl, "Failed to validate the chipaccess\n");
+ return -ENODEV;
+}
+
+static void b43_security_init(struct b43_wldev *dev)
+{
+ dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20;
+ B43_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key));
+ dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP);
+ /* KTP is a word address, but we address SHM bytewise.
+ * So multiply by two.
+ */
+ dev->ktp *= 2;
+ if (dev->dev->id.revision >= 5) {
+ /* Number of RCMTA address slots */
+ b43_write16(dev, B43_MMIO_RCMTA_COUNT, dev->max_nr_keys - 8);
+ }
+ b43_clear_keys(dev);
+}
+
+static int b43_rng_read(struct hwrng *rng, u32 * data)
+{
+ struct b43_wl *wl = (struct b43_wl *)rng->priv;
+ unsigned long flags;
+
+ /* Don't take wl->mutex here, as it could deadlock with
+ * hwrng internal locking. It's not needed to take
+ * wl->mutex here, anyway. */
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ *data = b43_read16(wl->current_dev, B43_MMIO_RNG);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ return (sizeof(u16));
+}
+
+static void b43_rng_exit(struct b43_wl *wl)
+{
+ if (wl->rng_initialized)
+ hwrng_unregister(&wl->rng);
+}
+
+static int b43_rng_init(struct b43_wl *wl)
+{
+ int err;
+
+ snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
+ "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
+ wl->rng.name = wl->rng_name;
+ wl->rng.data_read = b43_rng_read;
+ wl->rng.priv = (unsigned long)wl;
+ wl->rng_initialized = 1;
+ err = hwrng_register(&wl->rng);
+ if (err) {
+ wl->rng_initialized = 0;
+ b43err(wl, "Failed to register the random "
+ "number generator (%d)\n", err);
+ }
+
+ return err;
+}
+
+static int b43_tx(struct ieee80211_hw *hw,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ int err = -ENODEV;
+ unsigned long flags;
+
+ if (unlikely(!dev))
+ goto out;
+ if (unlikely(b43_status(dev) < B43_STAT_STARTED))
+ goto out;
+ /* DMA-TX is done without a global lock. */
+ if (b43_using_pio(dev)) {
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ err = b43_pio_tx(dev, skb, ctl);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ } else
+ err = b43_dma_tx(dev, skb, ctl);
+ out:
+ if (unlikely(err))
+ return NETDEV_TX_BUSY;
+ return NETDEV_TX_OK;
+}
+
+static int b43_conf_tx(struct ieee80211_hw *hw,
+ int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ return 0;
+}
+
+static int b43_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ unsigned long flags;
+ int err = -ENODEV;
+
+ if (!dev)
+ goto out;
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
+ if (b43_using_pio(dev))
+ b43_pio_get_tx_stats(dev, stats);
+ else
+ b43_dma_get_tx_stats(dev, stats);
+ err = 0;
+ }
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ out:
+ return err;
+}
+
+static int b43_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ memcpy(stats, &wl->ieee_stats, sizeof(*stats));
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ return 0;
+}
+
+static const char *phymode_to_string(unsigned int phymode)
+{
+ switch (phymode) {
+ case B43_PHYMODE_A:
+ return "A";
+ case B43_PHYMODE_B:
+ return "B";
+ case B43_PHYMODE_G:
+ return "G";
+ default:
+ B43_WARN_ON(1);
+ }
+ return "";
+}
+
+static int find_wldev_for_phymode(struct b43_wl *wl,
+ unsigned int phymode,
+ struct b43_wldev **dev, bool * gmode)
+{
+ struct b43_wldev *d;
+
+ list_for_each_entry(d, &wl->devlist, list) {
+ if (d->phy.possible_phymodes & phymode) {
+ /* Ok, this device supports the PHY-mode.
+ * Now figure out how the gmode bit has to be
+ * set to support it. */
+ if (phymode == B43_PHYMODE_A)
+ *gmode = 0;
+ else
+ *gmode = 1;
+ *dev = d;
+
+ return 0;
+ }
+ }
+
+ return -ESRCH;
+}
+
+static void b43_put_phy_into_reset(struct b43_wldev *dev)
+{
+ struct ssb_device *sdev = dev->dev;
+ u32 tmslow;
+
+ tmslow = ssb_read32(sdev, SSB_TMSLOW);
+ tmslow &= ~B43_TMSLOW_GMODE;
+ tmslow |= B43_TMSLOW_PHYRESET;
+ tmslow |= SSB_TMSLOW_FGC;
+ ssb_write32(sdev, SSB_TMSLOW, tmslow);
+ msleep(1);
+
+ tmslow = ssb_read32(sdev, SSB_TMSLOW);
+ tmslow &= ~SSB_TMSLOW_FGC;
+ tmslow |= B43_TMSLOW_PHYRESET;
+ ssb_write32(sdev, SSB_TMSLOW, tmslow);
+ msleep(1);
+}
+
+/* Expects wl->mutex locked */
+static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode)
+{
+ struct b43_wldev *up_dev;
+ struct b43_wldev *down_dev;
+ int err;
+ bool gmode = 0;
+ int prev_status;
+
+ err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode);
+ if (err) {
+ b43err(wl, "Could not find a device for %s-PHY mode\n",
+ phymode_to_string(new_mode));
+ return err;
+ }
+ if ((up_dev == wl->current_dev) &&
+ (!!wl->current_dev->phy.gmode == !!gmode)) {
+ /* This device is already running. */
+ return 0;
+ }
+ b43dbg(wl, "Reconfiguring PHYmode to %s-PHY\n",
+ phymode_to_string(new_mode));
+ down_dev = wl->current_dev;
+
+ prev_status = b43_status(down_dev);
+ /* Shutdown the currently running core. */
+ if (prev_status >= B43_STAT_STARTED)
+ b43_wireless_core_stop(down_dev);
+ if (prev_status >= B43_STAT_INITIALIZED)
+ b43_wireless_core_exit(down_dev);
+
+ if (down_dev != up_dev) {
+ /* We switch to a different core, so we put PHY into
+ * RESET on the old core. */
+ b43_put_phy_into_reset(down_dev);
+ }
+
+ /* Now start the new core. */
+ up_dev->phy.gmode = gmode;
+ if (prev_status >= B43_STAT_INITIALIZED) {
+ err = b43_wireless_core_init(up_dev);
+ if (err) {
+ b43err(wl, "Fatal: Could not initialize device for "
+ "newly selected %s-PHY mode\n",
+ phymode_to_string(new_mode));
+ goto init_failure;
+ }
+ }
+ if (prev_status >= B43_STAT_STARTED) {
+ err = b43_wireless_core_start(up_dev);
+ if (err) {
+ b43err(wl, "Fatal: Coult not start device for "
+ "newly selected %s-PHY mode\n",
+ phymode_to_string(new_mode));
+ b43_wireless_core_exit(up_dev);
+ goto init_failure;
+ }
+ }
+ B43_WARN_ON(b43_status(up_dev) != prev_status);
+
+ wl->current_dev = up_dev;
+
+ return 0;
+ init_failure:
+ /* Whoops, failed to init the new core. No core is operating now. */
+ wl->current_dev = NULL;
+ return err;
+}
+
+static int b43_antenna_from_ieee80211(u8 antenna)
+{
+ switch (antenna) {
+ case 0: /* default/diversity */
+ return B43_ANTENNA_DEFAULT;
+ case 1: /* Antenna 0 */
+ return B43_ANTENNA0;
+ case 2: /* Antenna 1 */
+ return B43_ANTENNA1;
+ default:
+ return B43_ANTENNA_DEFAULT;
+ }
+}
+
+static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev;
+ struct b43_phy *phy;
+ unsigned long flags;
+ unsigned int new_phymode = 0xFFFF;
+ int antenna_tx;
+ int antenna_rx;
+ int err = 0;
+ u32 savedirqs;
+
+ antenna_tx = b43_antenna_from_ieee80211(conf->antenna_sel_tx);
+ antenna_rx = b43_antenna_from_ieee80211(conf->antenna_sel_rx);
+
+ mutex_lock(&wl->mutex);
+
+ /* Switch the PHY mode (if necessary). */
+ switch (conf->phymode) {
+ case MODE_IEEE80211A:
+ new_phymode = B43_PHYMODE_A;
+ break;
+ case MODE_IEEE80211B:
+ new_phymode = B43_PHYMODE_B;
+ break;
+ case MODE_IEEE80211G:
+ new_phymode = B43_PHYMODE_G;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ err = b43_switch_phymode(wl, new_phymode);
+ if (err)
+ goto out_unlock_mutex;
+ dev = wl->current_dev;
+ phy = &dev->phy;
+
+ /* Disable IRQs while reconfiguring the device.
+ * This makes it possible to drop the spinlock throughout
+ * the reconfiguration process. */
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ if (b43_status(dev) < B43_STAT_STARTED) {
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ goto out_unlock_mutex;
+ }
+ savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ b43_synchronize_irq(dev);
+
+ /* Switch to the requested channel.
+ * The firmware takes care of races with the TX handler. */
+ if (conf->channel_val != phy->channel)
+ b43_radio_selectchannel(dev, conf->channel_val, 0);
+
+ /* Enable/Disable ShortSlot timing. */
+ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
+ dev->short_slot) {
+ B43_WARN_ON(phy->type != B43_PHYTYPE_G);
+ if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
+ b43_short_slot_timing_enable(dev);
+ else
+ b43_short_slot_timing_disable(dev);
+ }
+
+ /* Adjust the desired TX power level. */
+ if (conf->power_level != 0) {
+ if (conf->power_level != phy->power_level) {
+ phy->power_level = conf->power_level;
+ b43_phy_xmitpower(dev);
+ }
+ }
+
+ /* Antennas for RX and management frame TX. */
+ b43_mgmtframe_txantenna(dev, antenna_tx);
+ b43_set_rx_antenna(dev, antenna_rx);
+
+ /* Update templates for AP mode. */
+ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ b43_set_beacon_int(dev, conf->beacon_int);
+
+ if (!!conf->radio_enabled != phy->radio_on) {
+ if (conf->radio_enabled) {
+ b43_radio_turn_on(dev);
+ b43info(dev->wl, "Radio turned on by software\n");
+ if (!dev->radio_hw_enable) {
+ b43info(dev->wl, "The hardware RF-kill button "
+ "still turns the radio physically off. "
+ "Press the button to turn it on.\n");
+ }
+ } else {
+ b43_radio_turn_off(dev, 0);
+ b43info(dev->wl, "Radio turned off by software\n");
+ }
+ }
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43_interrupt_enable(dev, savedirqs);
+ mmiowb();
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ out_unlock_mutex:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ const u8 *local_addr, const u8 *addr,
+ struct ieee80211_key_conf *key)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ unsigned long flags;
+ u8 algorithm;
+ u8 index;
+ int err = -EINVAL;
+ DECLARE_MAC_BUF(mac);
+
+ if (modparam_nohwcrypt)
+ return -ENOSPC; /* User disabled HW-crypto */
+
+ if (!dev)
+ return -ENODEV;
+ switch (key->alg) {
+ case ALG_WEP:
+ if (key->keylen == 5)
+ algorithm = B43_SEC_ALGO_WEP40;
+ else
+ algorithm = B43_SEC_ALGO_WEP104;
+ break;
+ case ALG_TKIP:
+ algorithm = B43_SEC_ALGO_TKIP;
+ break;
+ case ALG_CCMP:
+ algorithm = B43_SEC_ALGO_AES;
+ break;
+ default:
+ B43_WARN_ON(1);
+ goto out;
+ }
+
+ index = (u8) (key->keyidx);
+ if (index > 3)
+ goto out;
+
+ mutex_lock(&wl->mutex);
+ spin_lock_irqsave(&wl->irq_lock, flags);
+
+ if (b43_status(dev) < B43_STAT_INITIALIZED) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
+ switch (cmd) {
+ case SET_KEY:
+ if (algorithm == B43_SEC_ALGO_TKIP) {
+ /* FIXME: No TKIP hardware encryption for now. */
+ err = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+
+ if (is_broadcast_ether_addr(addr)) {
+ /* addr is FF:FF:FF:FF:FF:FF for default keys */
+ err = b43_key_write(dev, index, algorithm,
+ key->key, key->keylen, NULL, key);
+ } else {
+ /*
+ * either pairwise key or address is 00:00:00:00:00:00
+ * for transmit-only keys
+ */
+ err = b43_key_write(dev, -1, algorithm,
+ key->key, key->keylen, addr, key);
+ }
+ if (err)
+ goto out_unlock;
+
+ if (algorithm == B43_SEC_ALGO_WEP40 ||
+ algorithm == B43_SEC_ALGO_WEP104) {
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_USEDEFKEYS);
+ } else {
+ b43_hf_write(dev,
+ b43_hf_read(dev) & ~B43_HF_USEDEFKEYS);
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ break;
+ case DISABLE_KEY: {
+ err = b43_key_clear(dev, key->hw_key_idx);
+ if (err)
+ goto out_unlock;
+ break;
+ }
+ default:
+ B43_WARN_ON(1);
+ }
+out_unlock:
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ mutex_unlock(&wl->mutex);
+out:
+ if (!err) {
+ b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
+ "mac: %s\n",
+ cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
+ print_mac(mac, addr));
+ }
+ return err;
+}
+
+static void b43_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed, unsigned int *fflags,
+ int mc_count, struct dev_addr_list *mc_list)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ unsigned long flags;
+
+ if (!dev) {
+ *fflags = 0;
+ return;
+ }
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ *fflags &= FIF_PROMISC_IN_BSS |
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_BCN_PRBRESP_PROMISC;
+
+ changed &= FIF_PROMISC_IN_BSS |
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_BCN_PRBRESP_PROMISC;
+
+ wl->filter_flags = *fflags;
+
+ if (changed && b43_status(dev) >= B43_STAT_INITIALIZED)
+ b43_adjust_opmode(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+}
+
+static int b43_config_interface(struct ieee80211_hw *hw,
+ int if_id, struct ieee80211_if_conf *conf)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ unsigned long flags;
+
+ if (!dev)
+ return -ENODEV;
+ mutex_lock(&wl->mutex);
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ B43_WARN_ON(wl->if_id != if_id);
+ if (conf->bssid)
+ memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+ else
+ memset(wl->bssid, 0, ETH_ALEN);
+ if (b43_status(dev) >= B43_STAT_INITIALIZED) {
+ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
+ B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+ b43_set_ssid(dev, conf->ssid, conf->ssid_len);
+ if (conf->beacon)
+ b43_refresh_templates(dev, conf->beacon);
+ }
+ b43_write_mac_bssid_templates(dev);
+ }
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ mutex_unlock(&wl->mutex);
+
+ return 0;
+}
+
+/* Locking: wl->mutex */
+static void b43_wireless_core_stop(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ unsigned long flags;
+
+ if (b43_status(dev) < B43_STAT_STARTED)
+ return;
+
+ /* Disable and sync interrupts. We must do this before than
+ * setting the status to INITIALIZED, as the interrupt handler
+ * won't care about IRQs then. */
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
+ b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* flush */
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ b43_synchronize_irq(dev);
+
+ b43_set_status(dev, B43_STAT_INITIALIZED);
+
+ mutex_unlock(&wl->mutex);
+ /* Must unlock as it would otherwise deadlock. No races here.
+ * Cancel the possibly running self-rearming periodic work. */
+ cancel_delayed_work_sync(&dev->periodic_work);
+ mutex_lock(&wl->mutex);
+
+ ieee80211_stop_queues(wl->hw); //FIXME this could cause a deadlock, as mac80211 seems buggy.
+
+ b43_mac_suspend(dev);
+ free_irq(dev->dev->irq, dev);
+ b43dbg(wl, "Wireless interface stopped\n");
+}
+
+/* Locking: wl->mutex */
+static int b43_wireless_core_start(struct b43_wldev *dev)
+{
+ int err;
+
+ B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
+
+ drain_txstatus_queue(dev);
+ err = request_irq(dev->dev->irq, b43_interrupt_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+ if (err) {
+ b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
+ goto out;
+ }
+
+ /* We are ready to run. */
+ b43_set_status(dev, B43_STAT_STARTED);
+
+ /* Start data flow (TX/RX). */
+ b43_mac_enable(dev);
+ b43_interrupt_enable(dev, dev->irq_savedstate);
+ ieee80211_start_queues(dev->wl->hw);
+
+ /* Start maintainance work */
+ b43_periodic_tasks_setup(dev);
+
+ b43dbg(dev->wl, "Wireless interface started\n");
+ out:
+ return err;
+}
+
+/* Get PHY and RADIO versioning numbers */
+static int b43_phy_versioning(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u32 tmp;
+ u8 analog_type;
+ u8 phy_type;
+ u8 phy_rev;
+ u16 radio_manuf;
+ u16 radio_ver;
+ u16 radio_rev;
+ int unsupported = 0;
+
+ /* Get PHY versioning */
+ tmp = b43_read16(dev, B43_MMIO_PHY_VER);
+ analog_type = (tmp & B43_PHYVER_ANALOG) >> B43_PHYVER_ANALOG_SHIFT;
+ phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT;
+ phy_rev = (tmp & B43_PHYVER_VERSION);
+ switch (phy_type) {
+ case B43_PHYTYPE_A:
+ if (phy_rev >= 4)
+ unsupported = 1;
+ break;
+ case B43_PHYTYPE_B:
+ if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6
+ && phy_rev != 7)
+ unsupported = 1;
+ break;
+ case B43_PHYTYPE_G:
+ if (phy_rev > 8)
+ unsupported = 1;
+ break;
+ default:
+ unsupported = 1;
+ };
+ if (unsupported) {
+ b43err(dev->wl, "FOUND UNSUPPORTED PHY "
+ "(Analog %u, Type %u, Revision %u)\n",
+ analog_type, phy_type, phy_rev);
+ return -EOPNOTSUPP;
+ }
+ b43dbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n",
+ analog_type, phy_type, phy_rev);
+
+ /* Get RADIO versioning */
+ if (dev->dev->bus->chip_id == 0x4317) {
+ if (dev->dev->bus->chip_rev == 0)
+ tmp = 0x3205017F;
+ else if (dev->dev->bus->chip_rev == 1)
+ tmp = 0x4205017F;
+ else
+ tmp = 0x5205017F;
+ } else {
+ b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
+ tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH);
+ tmp <<= 16;
+ b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
+ tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+ }
+ radio_manuf = (tmp & 0x00000FFF);
+ radio_ver = (tmp & 0x0FFFF000) >> 12;
+ radio_rev = (tmp & 0xF0000000) >> 28;
+ switch (phy_type) {
+ case B43_PHYTYPE_A:
+ if (radio_ver != 0x2060)
+ unsupported = 1;
+ if (radio_rev != 1)
+ unsupported = 1;
+ if (radio_manuf != 0x17F)
+ unsupported = 1;
+ break;
+ case B43_PHYTYPE_B:
+ if ((radio_ver & 0xFFF0) != 0x2050)
+ unsupported = 1;
+ break;
+ case B43_PHYTYPE_G:
+ if (radio_ver != 0x2050)
+ unsupported = 1;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ if (unsupported) {
+ b43err(dev->wl, "FOUND UNSUPPORTED RADIO "
+ "(Manuf 0x%X, Version 0x%X, Revision %u)\n",
+ radio_manuf, radio_ver, radio_rev);
+ return -EOPNOTSUPP;
+ }
+ b43dbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X, Revision %u\n",
+ radio_manuf, radio_ver, radio_rev);
+
+ phy->radio_manuf = radio_manuf;
+ phy->radio_ver = radio_ver;
+ phy->radio_rev = radio_rev;
+
+ phy->analog = analog_type;
+ phy->type = phy_type;
+ phy->rev = phy_rev;
+
+ return 0;
+}
+
+static void setup_struct_phy_for_init(struct b43_wldev *dev,
+ struct b43_phy *phy)
+{
+ struct b43_txpower_lo_control *lo;
+ int i;
+
+ memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
+ memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
+
+ /* Flags */
+ phy->locked = 0;
+
+ phy->aci_enable = 0;
+ phy->aci_wlan_automatic = 0;
+ phy->aci_hw_rssi = 0;
+
+ phy->radio_off_context.valid = 0;
+
+ lo = phy->lo_control;
+ if (lo) {
+ memset(lo, 0, sizeof(*(phy->lo_control)));
+ lo->rebuild = 1;
+ lo->tx_bias = 0xFF;
+ }
+ phy->max_lb_gain = 0;
+ phy->trsw_rx_gain = 0;
+ phy->txpwr_offset = 0;
+
+ /* NRSSI */
+ phy->nrssislope = 0;
+ for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
+ phy->nrssi[i] = -1000;
+ for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
+ phy->nrssi_lt[i] = i;
+
+ phy->lofcal = 0xFFFF;
+ phy->initval = 0xFFFF;
+
+ spin_lock_init(&phy->lock);
+ phy->interfmode = B43_INTERFMODE_NONE;
+ phy->channel = 0xFF;
+
+ phy->hardware_power_control = !!modparam_hwpctl;
+}
+
+static void setup_struct_wldev_for_init(struct b43_wldev *dev)
+{
+ /* Flags */
+ dev->reg124_set_0x4 = 0;
+ /* Assume the radio is enabled. If it's not enabled, the state will
+ * immediately get fixed on the first periodic work run. */
+ dev->radio_hw_enable = 1;
+
+ /* Stats */
+ memset(&dev->stats, 0, sizeof(dev->stats));
+
+ setup_struct_phy_for_init(dev, &dev->phy);
+
+ /* IRQ related flags */
+ dev->irq_reason = 0;
+ memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
+ dev->irq_savedstate = B43_IRQ_MASKTEMPLATE;
+
+ dev->mac_suspended = 1;
+
+ /* Noise calculation context */
+ memset(&dev->noisecalc, 0, sizeof(dev->noisecalc));
+}
+
+static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
+{
+ struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+ u32 hf;
+
+ if (!(sprom->r1.boardflags_lo & B43_BFL_BTCOEXIST))
+ return;
+ if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode)
+ return;
+
+ hf = b43_hf_read(dev);
+ if (sprom->r1.boardflags_lo & B43_BFL_BTCMOD)
+ hf |= B43_HF_BTCOEXALT;
+ else
+ hf |= B43_HF_BTCOEX;
+ b43_hf_write(dev, hf);
+ //TODO
+}
+
+static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
+{ //TODO
+}
+
+static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
+{
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ struct ssb_bus *bus = dev->dev->bus;
+ u32 tmp;
+
+ if (bus->pcicore.dev &&
+ bus->pcicore.dev->id.coreid == SSB_DEV_PCI &&
+ bus->pcicore.dev->id.revision <= 5) {
+ /* IMCFGLO timeouts workaround. */
+ tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
+ tmp &= ~SSB_IMCFGLO_REQTO;
+ tmp &= ~SSB_IMCFGLO_SERTO;
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_PCI:
+ case SSB_BUSTYPE_PCMCIA:
+ tmp |= 0x32;
+ break;
+ case SSB_BUSTYPE_SSB:
+ tmp |= 0x53;
+ break;
+ }
+ ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
+ }
+#endif /* CONFIG_SSB_DRIVER_PCICORE */
+}
+
+/* Shutdown a wireless core */
+/* Locking: wl->mutex */
+static void b43_wireless_core_exit(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
+ if (b43_status(dev) != B43_STAT_INITIALIZED)
+ return;
+ b43_set_status(dev, B43_STAT_UNINIT);
+
+ mutex_unlock(&dev->wl->mutex);
+ b43_rfkill_exit(dev);
+ mutex_lock(&dev->wl->mutex);
+
+ b43_rng_exit(dev->wl);
+ b43_pio_free(dev);
+ b43_dma_free(dev);
+ b43_chip_exit(dev);
+ b43_radio_turn_off(dev, 1);
+ b43_switch_analog(dev, 0);
+ if (phy->dyn_tssi_tbl)
+ kfree(phy->tssi2dbm);
+ kfree(phy->lo_control);
+ phy->lo_control = NULL;
+ ssb_device_disable(dev->dev, 0);
+ ssb_bus_may_powerdown(dev->dev->bus);
+}
+
+/* Initialize a wireless core */
+static int b43_wireless_core_init(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_sprom *sprom = &bus->sprom;
+ struct b43_phy *phy = &dev->phy;
+ int err;
+ u32 hf, tmp;
+
+ B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
+
+ err = ssb_bus_powerup(bus, 0);
+ if (err)
+ goto out;
+ if (!ssb_device_is_enabled(dev->dev)) {
+ tmp = phy->gmode ? B43_TMSLOW_GMODE : 0;
+ b43_wireless_core_reset(dev, tmp);
+ }
+
+ if ((phy->type == B43_PHYTYPE_B) || (phy->type == B43_PHYTYPE_G)) {
+ phy->lo_control =
+ kzalloc(sizeof(*(phy->lo_control)), GFP_KERNEL);
+ if (!phy->lo_control) {
+ err = -ENOMEM;
+ goto err_busdown;
+ }
+ }
+ setup_struct_wldev_for_init(dev);
+
+ err = b43_phy_init_tssi2dbm_table(dev);
+ if (err)
+ goto err_kfree_lo_control;
+
+ /* Enable IRQ routing to this device. */
+ ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
+
+ b43_imcfglo_timeouts_workaround(dev);
+ b43_bluetooth_coext_disable(dev);
+ b43_phy_early_init(dev);
+ err = b43_chip_init(dev);
+ if (err)
+ goto err_kfree_tssitbl;
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
+ hf = b43_hf_read(dev);
+ if (phy->type == B43_PHYTYPE_G) {
+ hf |= B43_HF_SYMW;
+ if (phy->rev == 1)
+ hf |= B43_HF_GDCW;
+ if (sprom->r1.boardflags_lo & B43_BFL_PACTRL)
+ hf |= B43_HF_OFDMPABOOST;
+ } else if (phy->type == B43_PHYTYPE_B) {
+ hf |= B43_HF_SYMW;
+ if (phy->rev >= 2 && phy->radio_ver == 0x2050)
+ hf &= ~B43_HF_GDCW;
+ }
+ b43_hf_write(dev, hf);
+
+ /* Short/Long Retry Limit.
+ * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
+ * the chip-internal counter.
+ */
+ tmp = limit_value(modparam_short_retry, 0, 0xF);
+ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, tmp);
+ tmp = limit_value(modparam_long_retry, 0, 0xF);
+ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, tmp);
+
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2);
+
+ /* Disable sending probe responses from firmware.
+ * Setting the MaxTime to one usec will always trigger
+ * a timeout, so we never send any probe resp.
+ * A timeout of zero is infinite. */
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1);
+
+ b43_rate_memory_init(dev);
+
+ /* Minimum Contention Window */
+ if (phy->type == B43_PHYTYPE_B) {
+ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0x1F);
+ } else {
+ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0xF);
+ }
+ /* Maximum Contention Window */
+ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
+
+ do {
+ if (b43_using_pio(dev)) {
+ err = b43_pio_init(dev);
+ } else {
+ err = b43_dma_init(dev);
+ if (!err)
+ b43_qos_init(dev);
+ }
+ } while (err == -EAGAIN);
+ if (err)
+ goto err_chip_exit;
+
+//FIXME
+#if 1
+ b43_write16(dev, 0x0612, 0x0050);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0416, 0x0050);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0414, 0x01F4);
+#endif
+
+ b43_bluetooth_coext_enable(dev);
+
+ ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
+ memset(wl->bssid, 0, ETH_ALEN);
+ memset(wl->mac_addr, 0, ETH_ALEN);
+ b43_upload_card_macaddress(dev);
+ b43_security_init(dev);
+ b43_rfkill_init(dev);
+ b43_rng_init(wl);
+
+ b43_set_status(dev, B43_STAT_INITIALIZED);
+
+ out:
+ return err;
+
+ err_chip_exit:
+ b43_chip_exit(dev);
+ err_kfree_tssitbl:
+ if (phy->dyn_tssi_tbl)
+ kfree(phy->tssi2dbm);
+ err_kfree_lo_control:
+ kfree(phy->lo_control);
+ phy->lo_control = NULL;
+ err_busdown:
+ ssb_bus_may_powerdown(bus);
+ B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
+ return err;
+}
+
+static int b43_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev;
+ unsigned long flags;
+ int err = -EOPNOTSUPP;
+
+ /* TODO: allow WDS/AP devices to coexist */
+
+ if (conf->type != IEEE80211_IF_TYPE_AP &&
+ conf->type != IEEE80211_IF_TYPE_STA &&
+ conf->type != IEEE80211_IF_TYPE_WDS &&
+ conf->type != IEEE80211_IF_TYPE_IBSS)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&wl->mutex);
+ if (wl->operating)
+ goto out_mutex_unlock;
+
+ b43dbg(wl, "Adding Interface type %d\n", conf->type);
+
+ dev = wl->current_dev;
+ wl->operating = 1;
+ wl->if_id = conf->if_id;
+ wl->if_type = conf->type;
+ memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43_adjust_opmode(dev);
+ b43_upload_card_macaddress(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ err = 0;
+ out_mutex_unlock:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+static void b43_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ unsigned long flags;
+
+ b43dbg(wl, "Removing Interface type %d\n", conf->type);
+
+ mutex_lock(&wl->mutex);
+
+ B43_WARN_ON(!wl->operating);
+ B43_WARN_ON(wl->if_id != conf->if_id);
+
+ wl->operating = 0;
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43_adjust_opmode(dev);
+ memset(wl->mac_addr, 0, ETH_ALEN);
+ b43_upload_card_macaddress(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ mutex_unlock(&wl->mutex);
+}
+
+static int b43_start(struct ieee80211_hw *hw)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+ int did_init = 0;
+ int err = 0;
+
+ mutex_lock(&wl->mutex);
+
+ if (b43_status(dev) < B43_STAT_INITIALIZED) {
+ err = b43_wireless_core_init(dev);
+ if (err)
+ goto out_mutex_unlock;
+ did_init = 1;
+ }
+
+ if (b43_status(dev) < B43_STAT_STARTED) {
+ err = b43_wireless_core_start(dev);
+ if (err) {
+ if (did_init)
+ b43_wireless_core_exit(dev);
+ goto out_mutex_unlock;
+ }
+ }
+
+ out_mutex_unlock:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+static void b43_stop(struct ieee80211_hw *hw)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+ struct b43_wldev *dev = wl->current_dev;
+
+ mutex_lock(&wl->mutex);
+ if (b43_status(dev) >= B43_STAT_STARTED)
+ b43_wireless_core_stop(dev);
+ b43_wireless_core_exit(dev);
+ mutex_unlock(&wl->mutex);
+}
+
+static const struct ieee80211_ops b43_hw_ops = {
+ .tx = b43_tx,
+ .conf_tx = b43_conf_tx,
+ .add_interface = b43_add_interface,
+ .remove_interface = b43_remove_interface,
+ .config = b43_dev_config,
+ .config_interface = b43_config_interface,
+ .configure_filter = b43_configure_filter,
+ .set_key = b43_dev_set_key,
+ .get_stats = b43_get_stats,
+ .get_tx_stats = b43_get_tx_stats,
+ .start = b43_start,
+ .stop = b43_stop,
+};
+
+/* Hard-reset the chip. Do not call this directly.
+ * Use b43_controller_restart()
+ */
+static void b43_chip_reset(struct work_struct *work)
+{
+ struct b43_wldev *dev =
+ container_of(work, struct b43_wldev, restart_work);
+ struct b43_wl *wl = dev->wl;
+ int err = 0;
+ int prev_status;
+
+ mutex_lock(&wl->mutex);
+
+ prev_status = b43_status(dev);
+ /* Bring the device down... */
+ if (prev_status >= B43_STAT_STARTED)
+ b43_wireless_core_stop(dev);
+ if (prev_status >= B43_STAT_INITIALIZED)
+ b43_wireless_core_exit(dev);
+
+ /* ...and up again. */
+ if (prev_status >= B43_STAT_INITIALIZED) {
+ err = b43_wireless_core_init(dev);
+ if (err)
+ goto out;
+ }
+ if (prev_status >= B43_STAT_STARTED) {
+ err = b43_wireless_core_start(dev);
+ if (err) {
+ b43_wireless_core_exit(dev);
+ goto out;
+ }
+ }
+ out:
+ mutex_unlock(&wl->mutex);
+ if (err)
+ b43err(wl, "Controller restart FAILED\n");
+ else
+ b43info(wl, "Controller restarted\n");
+}
+
+static int b43_setup_modes(struct b43_wldev *dev,
+ int have_aphy, int have_bphy, int have_gphy)
+{
+ struct ieee80211_hw *hw = dev->wl->hw;
+ struct ieee80211_hw_mode *mode;
+ struct b43_phy *phy = &dev->phy;
+ int cnt = 0;
+ int err;
+
+/*FIXME: Don't tell ieee80211 about an A-PHY, because we currently don't support A-PHY. */
+ have_aphy = 0;
+
+ phy->possible_phymodes = 0;
+ for (; 1; cnt++) {
+ if (have_aphy) {
+ B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
+ mode = &phy->hwmodes[cnt];
+
+ mode->mode = MODE_IEEE80211A;
+ mode->num_channels = b43_a_chantable_size;
+ mode->channels = b43_a_chantable;
+ mode->num_rates = b43_a_ratetable_size;
+ mode->rates = b43_a_ratetable;
+ err = ieee80211_register_hwmode(hw, mode);
+ if (err)
+ return err;
+
+ phy->possible_phymodes |= B43_PHYMODE_A;
+ have_aphy = 0;
+ continue;
+ }
+ if (have_bphy) {
+ B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
+ mode = &phy->hwmodes[cnt];
+
+ mode->mode = MODE_IEEE80211B;
+ mode->num_channels = b43_bg_chantable_size;
+ mode->channels = b43_bg_chantable;
+ mode->num_rates = b43_b_ratetable_size;
+ mode->rates = b43_b_ratetable;
+ err = ieee80211_register_hwmode(hw, mode);
+ if (err)
+ return err;
+
+ phy->possible_phymodes |= B43_PHYMODE_B;
+ have_bphy = 0;
+ continue;
+ }
+ if (have_gphy) {
+ B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
+ mode = &phy->hwmodes[cnt];
+
+ mode->mode = MODE_IEEE80211G;
+ mode->num_channels = b43_bg_chantable_size;
+ mode->channels = b43_bg_chantable;
+ mode->num_rates = b43_g_ratetable_size;
+ mode->rates = b43_g_ratetable;
+ err = ieee80211_register_hwmode(hw, mode);
+ if (err)
+ return err;
+
+ phy->possible_phymodes |= B43_PHYMODE_G;
+ have_gphy = 0;
+ continue;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static void b43_wireless_core_detach(struct b43_wldev *dev)
+{
+ /* We release firmware that late to not be required to re-request
+ * is all the time when we reinit the core. */
+ b43_release_firmware(dev);
+}
+
+static int b43_wireless_core_attach(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ struct ssb_bus *bus = dev->dev->bus;
+ struct pci_dev *pdev = bus->host_pci;
+ int err;
+ int have_aphy = 0, have_bphy = 0, have_gphy = 0;
+ u32 tmp;
+
+ /* Do NOT do any device initialization here.
+ * Do it in wireless_core_init() instead.
+ * This function is for gathering basic information about the HW, only.
+ * Also some structs may be set up here. But most likely you want to have
+ * that in core_init(), too.
+ */
+
+ err = ssb_bus_powerup(bus, 0);
+ if (err) {
+ b43err(wl, "Bus powerup failed\n");
+ goto out;
+ }
+ /* Get the PHY type. */
+ if (dev->dev->id.revision >= 5) {
+ u32 tmshigh;
+
+ tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+ have_aphy = !!(tmshigh & B43_TMSHIGH_APHY);
+ have_gphy = !!(tmshigh & B43_TMSHIGH_GPHY);
+ if (!have_aphy && !have_gphy)
+ have_bphy = 1;
+ } else if (dev->dev->id.revision == 4) {
+ have_gphy = 1;
+ have_aphy = 1;
+ } else
+ have_bphy = 1;
+
+ dev->phy.gmode = (have_gphy || have_bphy);
+ tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
+ b43_wireless_core_reset(dev, tmp);
+
+ err = b43_phy_versioning(dev);
+ if (err)
+ goto err_powerdown;
+ /* Check if this device supports multiband. */
+ if (!pdev ||
+ (pdev->device != 0x4312 &&
+ pdev->device != 0x4319 && pdev->device != 0x4324)) {
+ /* No multiband support. */
+ have_aphy = 0;
+ have_bphy = 0;
+ have_gphy = 0;
+ switch (dev->phy.type) {
+ case B43_PHYTYPE_A:
+ have_aphy = 1;
+ break;
+ case B43_PHYTYPE_B:
+ have_bphy = 1;
+ break;
+ case B43_PHYTYPE_G:
+ have_gphy = 1;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ }
+ dev->phy.gmode = (have_gphy || have_bphy);
+ tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
+ b43_wireless_core_reset(dev, tmp);
+
+ err = b43_validate_chipaccess(dev);
+ if (err)
+ goto err_powerdown;
+ err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy);
+ if (err)
+ goto err_powerdown;
+
+ /* Now set some default "current_dev" */
+ if (!wl->current_dev)
+ wl->current_dev = dev;
+ INIT_WORK(&dev->restart_work, b43_chip_reset);
+
+ b43_radio_turn_off(dev, 1);
+ b43_switch_analog(dev, 0);
+ ssb_device_disable(dev->dev, 0);
+ ssb_bus_may_powerdown(bus);
+
+out:
+ return err;
+
+err_powerdown:
+ ssb_bus_may_powerdown(bus);
+ return err;
+}
+
+static void b43_one_core_detach(struct ssb_device *dev)
+{
+ struct b43_wldev *wldev;
+ struct b43_wl *wl;
+
+ wldev = ssb_get_drvdata(dev);
+ wl = wldev->wl;
+ cancel_work_sync(&wldev->restart_work);
+ b43_debugfs_remove_device(wldev);
+ b43_wireless_core_detach(wldev);
+ list_del(&wldev->list);
+ wl->nr_devs--;
+ ssb_set_drvdata(dev, NULL);
+ kfree(wldev);
+}
+
+static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
+{
+ struct b43_wldev *wldev;
+ struct pci_dev *pdev;
+ int err = -ENOMEM;
+
+ if (!list_empty(&wl->devlist)) {
+ /* We are not the first core on this chip. */
+ pdev = dev->bus->host_pci;
+ /* Only special chips support more than one wireless
+ * core, although some of the other chips have more than
+ * one wireless core as well. Check for this and
+ * bail out early.
+ */
+ if (!pdev ||
+ ((pdev->device != 0x4321) &&
+ (pdev->device != 0x4313) && (pdev->device != 0x431A))) {
+ b43dbg(wl, "Ignoring unconnected 802.11 core\n");
+ return -ENODEV;
+ }
+ }
+
+ wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
+ if (!wldev)
+ goto out;
+
+ wldev->dev = dev;
+ wldev->wl = wl;
+ b43_set_status(wldev, B43_STAT_UNINIT);
+ wldev->bad_frames_preempt = modparam_bad_frames_preempt;
+ tasklet_init(&wldev->isr_tasklet,
+ (void (*)(unsigned long))b43_interrupt_tasklet,
+ (unsigned long)wldev);
+ if (modparam_pio)
+ wldev->__using_pio = 1;
+ INIT_LIST_HEAD(&wldev->list);
+
+ err = b43_wireless_core_attach(wldev);
+ if (err)
+ goto err_kfree_wldev;
+
+ list_add(&wldev->list, &wl->devlist);
+ wl->nr_devs++;
+ ssb_set_drvdata(dev, wldev);
+ b43_debugfs_add_device(wldev);
+
+ out:
+ return err;
+
+ err_kfree_wldev:
+ kfree(wldev);
+ return err;
+}
+
+static void b43_sprom_fixup(struct ssb_bus *bus)
+{
+ /* boardflags workarounds */
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
+ bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
+ bus->sprom.r1.boardflags_lo |= B43_BFL_BTCOEXIST;
+ if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
+ bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
+ bus->sprom.r1.boardflags_lo |= B43_BFL_PACTRL;
+
+ /* Handle case when gain is not set in sprom */
+ if (bus->sprom.r1.antenna_gain_a == 0xFF)
+ bus->sprom.r1.antenna_gain_a = 2;
+ if (bus->sprom.r1.antenna_gain_bg == 0xFF)
+ bus->sprom.r1.antenna_gain_bg = 2;
+
+ /* Convert Antennagain values to Q5.2 */
+ bus->sprom.r1.antenna_gain_a <<= 2;
+ bus->sprom.r1.antenna_gain_bg <<= 2;
+}
+
+static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
+{
+ struct ieee80211_hw *hw = wl->hw;
+
+ ssb_set_devtypedata(dev, NULL);
+ ieee80211_free_hw(hw);
+}
+
+static int b43_wireless_init(struct ssb_device *dev)
+{
+ struct ssb_sprom *sprom = &dev->bus->sprom;
+ struct ieee80211_hw *hw;
+ struct b43_wl *wl;
+ int err = -ENOMEM;
+
+ b43_sprom_fixup(dev->bus);
+
+ hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops);
+ if (!hw) {
+ b43err(NULL, "Could not allocate ieee80211 device\n");
+ goto out;
+ }
+
+ /* fill hw info */
+ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+ hw->max_signal = 100;
+ hw->max_rssi = -110;
+ hw->max_noise = -110;
+ hw->queues = 1; /* FIXME: hardware has more queues */
+ SET_IEEE80211_DEV(hw, dev->dev);
+ if (is_valid_ether_addr(sprom->r1.et1mac))
+ SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);
+ else
+ SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac);
+
+ /* Get and initialize struct b43_wl */
+ wl = hw_to_b43_wl(hw);
+ memset(wl, 0, sizeof(*wl));
+ wl->hw = hw;
+ spin_lock_init(&wl->irq_lock);
+ spin_lock_init(&wl->leds_lock);
+ mutex_init(&wl->mutex);
+ INIT_LIST_HEAD(&wl->devlist);
+
+ ssb_set_devtypedata(dev, wl);
+ b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
+ err = 0;
+ out:
+ return err;
+}
+
+static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
+{
+ struct b43_wl *wl;
+ int err;
+ int first = 0;
+
+ wl = ssb_get_devtypedata(dev);
+ if (!wl) {
+ /* Probing the first core. Must setup common struct b43_wl */
+ first = 1;
+ err = b43_wireless_init(dev);
+ if (err)
+ goto out;
+ wl = ssb_get_devtypedata(dev);
+ B43_WARN_ON(!wl);
+ }
+ err = b43_one_core_attach(dev, wl);
+ if (err)
+ goto err_wireless_exit;
+
+ if (first) {
+ err = ieee80211_register_hw(wl->hw);
+ if (err)
+ goto err_one_core_detach;
+ }
+
+ out:
+ return err;
+
+ err_one_core_detach:
+ b43_one_core_detach(dev);
+ err_wireless_exit:
+ if (first)
+ b43_wireless_exit(dev, wl);
+ return err;
+}
+
+static void b43_remove(struct ssb_device *dev)
+{
+ struct b43_wl *wl = ssb_get_devtypedata(dev);
+ struct b43_wldev *wldev = ssb_get_drvdata(dev);
+
+ B43_WARN_ON(!wl);
+ if (wl->current_dev == wldev)
+ ieee80211_unregister_hw(wl->hw);
+
+ b43_one_core_detach(dev);
+
+ if (list_empty(&wl->devlist)) {
+ /* Last core on the chip unregistered.
+ * We can destroy common struct b43_wl.
+ */
+ b43_wireless_exit(dev, wl);
+ }
+}
+
+/* Perform a hardware reset. This can be called from any context. */
+void b43_controller_restart(struct b43_wldev *dev, const char *reason)
+{
+ /* Must avoid requeueing, if we are in shutdown. */
+ if (b43_status(dev) < B43_STAT_INITIALIZED)
+ return;
+ b43info(dev->wl, "Controller RESET (%s) ...\n", reason);
+ queue_work(dev->wl->hw->workqueue, &dev->restart_work);
+}
+
+#ifdef CONFIG_PM
+
+static int b43_suspend(struct ssb_device *dev, pm_message_t state)
+{
+ struct b43_wldev *wldev = ssb_get_drvdata(dev);
+ struct b43_wl *wl = wldev->wl;
+
+ b43dbg(wl, "Suspending...\n");
+
+ mutex_lock(&wl->mutex);
+ wldev->suspend_init_status = b43_status(wldev);
+ if (wldev->suspend_init_status >= B43_STAT_STARTED)
+ b43_wireless_core_stop(wldev);
+ if (wldev->suspend_init_status >= B43_STAT_INITIALIZED)
+ b43_wireless_core_exit(wldev);
+ mutex_unlock(&wl->mutex);
+
+ b43dbg(wl, "Device suspended.\n");
+
+ return 0;
+}
+
+static int b43_resume(struct ssb_device *dev)
+{
+ struct b43_wldev *wldev = ssb_get_drvdata(dev);
+ struct b43_wl *wl = wldev->wl;
+ int err = 0;
+
+ b43dbg(wl, "Resuming...\n");
+
+ mutex_lock(&wl->mutex);
+ if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) {
+ err = b43_wireless_core_init(wldev);
+ if (err) {
+ b43err(wl, "Resume failed at core init\n");
+ goto out;
+ }
+ }
+ if (wldev->suspend_init_status >= B43_STAT_STARTED) {
+ err = b43_wireless_core_start(wldev);
+ if (err) {
+ b43_wireless_core_exit(wldev);
+ b43err(wl, "Resume failed at core start\n");
+ goto out;
+ }
+ }
+ mutex_unlock(&wl->mutex);
+
+ b43dbg(wl, "Device resumed.\n");
+ out:
+ return err;
+}
+
+#else /* CONFIG_PM */
+# define b43_suspend NULL
+# define b43_resume NULL
+#endif /* CONFIG_PM */
+
+static struct ssb_driver b43_ssb_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = b43_ssb_tbl,
+ .probe = b43_probe,
+ .remove = b43_remove,
+ .suspend = b43_suspend,
+ .resume = b43_resume,
+};
+
+static int __init b43_init(void)
+{
+ int err;
+
+ b43_debugfs_init();
+ err = b43_pcmcia_init();
+ if (err)
+ goto err_dfs_exit;
+ err = ssb_driver_register(&b43_ssb_driver);
+ if (err)
+ goto err_pcmcia_exit;
+
+ return err;
+
+err_pcmcia_exit:
+ b43_pcmcia_exit();
+err_dfs_exit:
+ b43_debugfs_exit();
+ return err;
+}
+
+static void __exit b43_exit(void)
+{
+ ssb_driver_unregister(&b43_ssb_driver);
+ b43_pcmcia_exit();
+ b43_debugfs_exit();
+}
+
+module_init(b43_init)
+module_exit(b43_exit)
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
new file mode 100644
index 00000000000..284d17da17d
--- /dev/null
+++ b/drivers/net/wireless/b43/main.h
@@ -0,0 +1,125 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mb@bu3sch.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef B43_MAIN_H_
+#define B43_MAIN_H_
+
+#include "b43.h"
+
+#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes]
+#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes)
+/* Magic helper macro to pad structures. Ignore those above. It's magic. */
+#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes))
+
+/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
+static inline u8 b43_freq_to_channel_a(int freq)
+{
+ return ((freq - 5000) / 5);
+}
+static inline u8 b43_freq_to_channel_bg(int freq)
+{
+ u8 channel;
+
+ if (freq == 2484)
+ channel = 14;
+ else
+ channel = (freq - 2407) / 5;
+
+ return channel;
+}
+static inline u8 b43_freq_to_channel(struct b43_wldev *dev, int freq)
+{
+ if (dev->phy.type == B43_PHYTYPE_A)
+ return b43_freq_to_channel_a(freq);
+ return b43_freq_to_channel_bg(freq);
+}
+
+/* Lightweight function to convert a channel number to a frequency (in Mhz). */
+static inline int b43_channel_to_freq_a(u8 channel)
+{
+ return (5000 + (5 * channel));
+}
+static inline int b43_channel_to_freq_bg(u8 channel)
+{
+ int freq;
+
+ if (channel == 14)
+ freq = 2484;
+ else
+ freq = 2407 + (5 * channel);
+
+ return freq;
+}
+static inline int b43_channel_to_freq(struct b43_wldev *dev, u8 channel)
+{
+ if (dev->phy.type == B43_PHYTYPE_A)
+ return b43_channel_to_freq_a(channel);
+ return b43_channel_to_freq_bg(channel);
+}
+
+static inline int b43_is_cck_rate(int rate)
+{
+ return (rate == B43_CCK_RATE_1MB ||
+ rate == B43_CCK_RATE_2MB ||
+ rate == B43_CCK_RATE_5MB || rate == B43_CCK_RATE_11MB);
+}
+
+static inline int b43_is_ofdm_rate(int rate)
+{
+ return !b43_is_cck_rate(rate);
+}
+
+void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
+void b43_tsf_write(struct b43_wldev *dev, u64 tsf);
+
+u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
+u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
+void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
+void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
+
+u32 b43_hf_read(struct b43_wldev *dev);
+void b43_hf_write(struct b43_wldev *dev, u32 value);
+
+void b43_dummy_transmission(struct b43_wldev *dev);
+
+void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags);
+
+void b43_mac_suspend(struct b43_wldev *dev);
+void b43_mac_enable(struct b43_wldev *dev);
+
+void b43_controller_restart(struct b43_wldev *dev, const char *reason);
+
+#define B43_PS_ENABLED (1 << 0) /* Force enable hardware power saving */
+#define B43_PS_DISABLED (1 << 1) /* Force disable hardware power saving */
+#define B43_PS_AWAKE (1 << 2) /* Force device awake */
+#define B43_PS_ASLEEP (1 << 3) /* Force device asleep */
+void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags);
+
+#endif /* B43_MAIN_H_ */
diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c
new file mode 100644
index 00000000000..b79a6bd5396
--- /dev/null
+++ b/drivers/net/wireless/b43/pcmcia.c
@@ -0,0 +1,174 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ Copyright (c) 2007 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "pcmcia.h"
+
+#include <linux/ssb/ssb.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+
+static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
+ PCMCIA_DEVICE_NULL,
+};
+
+MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl);
+
+#ifdef CONFIG_PM
+static int b43_pcmcia_suspend(struct pcmcia_device *dev)
+{
+ //TODO
+ return 0;
+}
+
+static int b43_pcmcia_resume(struct pcmcia_device *dev)
+{
+ //TODO
+ return 0;
+}
+#else /* CONFIG_PM */
+# define b43_pcmcia_suspend NULL
+# define b43_pcmcia_resume NULL
+#endif /* CONFIG_PM */
+
+static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
+{
+ struct ssb_bus *ssb;
+ win_req_t win;
+ memreq_t mem;
+ tuple_t tuple;
+ cisparse_t parse;
+ int err = -ENOMEM;
+ int res = 0;
+ unsigned char buf[64];
+
+ ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
+ if (!ssb)
+ goto out_error;
+
+ err = -ENODEV;
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+
+ res = pcmcia_get_first_tuple(dev, &tuple);
+ if (res != CS_SUCCESS)
+ goto err_kfree_ssb;
+ res = pcmcia_get_tuple_data(dev, &tuple);
+ if (res != CS_SUCCESS)
+ goto err_kfree_ssb;
+ res = pcmcia_parse_tuple(dev, &tuple, &parse);
+ if (res != CS_SUCCESS)
+ goto err_kfree_ssb;
+
+ dev->conf.ConfigBase = parse.config.base;
+ dev->conf.Present = parse.config.rmask[0];
+
+ dev->io.BasePort2 = 0;
+ dev->io.NumPorts2 = 0;
+ dev->io.Attributes2 = 0;
+
+ win.Attributes = WIN_ADDR_SPACE_MEM | WIN_MEMORY_TYPE_CM |
+ WIN_ENABLE | WIN_DATA_WIDTH_16 |
+ WIN_USE_WAIT;
+ win.Base = 0;
+ win.Size = SSB_CORE_SIZE;
+ win.AccessSpeed = 250;
+ res = pcmcia_request_window(&dev, &win, &dev->win);
+ if (res != CS_SUCCESS)
+ goto err_kfree_ssb;
+
+ mem.CardOffset = 0;
+ mem.Page = 0;
+ res = pcmcia_map_mem_page(dev->win, &mem);
+ if (res != CS_SUCCESS)
+ goto err_disable;
+
+ dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FIRST_SHARED;
+ dev->irq.IRQInfo1 = IRQ_LEVEL_ID | IRQ_SHARE_ID;
+ dev->irq.Handler = NULL; /* The handler is registered later. */
+ dev->irq.Instance = NULL;
+ res = pcmcia_request_irq(dev, &dev->irq);
+ if (res != CS_SUCCESS)
+ goto err_disable;
+
+ res = pcmcia_request_configuration(dev, &dev->conf);
+ if (res != CS_SUCCESS)
+ goto err_disable;
+
+ err = ssb_bus_pcmciabus_register(ssb, dev, win.Base);
+ if (err)
+ goto err_disable;
+ dev->priv = ssb;
+
+ return 0;
+
+err_disable:
+ pcmcia_disable_device(dev);
+err_kfree_ssb:
+ kfree(ssb);
+out_error:
+ printk(KERN_ERR "b43-pcmcia: Initialization failed (%d, %d)\n",
+ res, err);
+ return err;
+}
+
+static void __devexit b43_pcmcia_remove(struct pcmcia_device *dev)
+{
+ struct ssb_bus *ssb = dev->priv;
+
+ ssb_bus_unregister(ssb);
+ pcmcia_disable_device(dev);
+ kfree(ssb);
+ dev->priv = NULL;
+}
+
+static struct pcmcia_driver b43_pcmcia_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "b43-pcmcia",
+ },
+ .id_table = b43_pcmcia_tbl,
+ .probe = b43_pcmcia_probe,
+ .remove = __devexit_p(b43_pcmcia_remove),
+ .suspend = b43_pcmcia_suspend,
+ .resume = b43_pcmcia_resume,
+};
+
+int b43_pcmcia_init(void)
+{
+ return pcmcia_register_driver(&b43_pcmcia_driver);
+}
+
+void b43_pcmcia_exit(void)
+{
+ pcmcia_unregister_driver(&b43_pcmcia_driver);
+}
diff --git a/drivers/net/wireless/b43/pcmcia.h b/drivers/net/wireless/b43/pcmcia.h
new file mode 100644
index 00000000000..85f120a67cb
--- /dev/null
+++ b/drivers/net/wireless/b43/pcmcia.h
@@ -0,0 +1,20 @@
+#ifndef B43_PCMCIA_H_
+#define B43_PCMCIA_H_
+
+#ifdef CONFIG_B43_PCMCIA
+
+int b43_pcmcia_init(void);
+void b43_pcmcia_exit(void);
+
+#else /* CONFIG_B43_PCMCIA */
+
+static inline int b43_pcmcia_init(void)
+{
+ return 0;
+}
+static inline void b43_pcmcia_exit(void)
+{
+}
+
+#endif /* CONFIG_B43_PCMCIA */
+#endif /* B43_PCMCIA_H_ */
diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c
new file mode 100644
index 00000000000..3d4ed647c31
--- /dev/null
+++ b/drivers/net/wireless/b43/phy.c
@@ -0,0 +1,4381 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
+ Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/types.h>
+
+#include "b43.h"
+#include "phy.h"
+#include "main.h"
+#include "tables.h"
+#include "lo.h"
+
+static const s8 b43_tssi2dbm_b_table[] = {
+ 0x4D, 0x4C, 0x4B, 0x4A,
+ 0x4A, 0x49, 0x48, 0x47,
+ 0x47, 0x46, 0x45, 0x45,
+ 0x44, 0x43, 0x42, 0x42,
+ 0x41, 0x40, 0x3F, 0x3E,
+ 0x3D, 0x3C, 0x3B, 0x3A,
+ 0x39, 0x38, 0x37, 0x36,
+ 0x35, 0x34, 0x32, 0x31,
+ 0x30, 0x2F, 0x2D, 0x2C,
+ 0x2B, 0x29, 0x28, 0x26,
+ 0x25, 0x23, 0x21, 0x1F,
+ 0x1D, 0x1A, 0x17, 0x14,
+ 0x10, 0x0C, 0x06, 0x00,
+ -7, -7, -7, -7,
+ -7, -7, -7, -7,
+ -7, -7, -7, -7,
+};
+
+static const s8 b43_tssi2dbm_g_table[] = {
+ 77, 77, 77, 76,
+ 76, 76, 75, 75,
+ 74, 74, 73, 73,
+ 73, 72, 72, 71,
+ 71, 70, 70, 69,
+ 68, 68, 67, 67,
+ 66, 65, 65, 64,
+ 63, 63, 62, 61,
+ 60, 59, 58, 57,
+ 56, 55, 54, 53,
+ 52, 50, 49, 47,
+ 45, 43, 40, 37,
+ 33, 28, 22, 14,
+ 5, -7, -20, -20,
+ -20, -20, -20, -20,
+ -20, -20, -20, -20,
+};
+
+const u8 b43_radio_channel_codes_bg[] = {
+ 12, 17, 22, 27,
+ 32, 37, 42, 47,
+ 52, 57, 62, 67,
+ 72, 84,
+};
+
+static void b43_phy_initg(struct b43_wldev *dev);
+
+/* Reverse the bits of a 4bit value.
+ * Example: 1101 is flipped 1011
+ */
+static u16 flip_4bit(u16 value)
+{
+ u16 flipped = 0x0000;
+
+ B43_WARN_ON(value & ~0x000F);
+
+ flipped |= (value & 0x0001) << 3;
+ flipped |= (value & 0x0002) << 1;
+ flipped |= (value & 0x0004) >> 1;
+ flipped |= (value & 0x0008) >> 3;
+
+ return flipped;
+}
+
+static void generate_rfatt_list(struct b43_wldev *dev,
+ struct b43_rfatt_list *list)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ /* APHY.rev < 5 || GPHY.rev < 6 */
+ static const struct b43_rfatt rfatt_0[] = {
+ {.att = 3,.with_padmix = 0,},
+ {.att = 1,.with_padmix = 0,},
+ {.att = 5,.with_padmix = 0,},
+ {.att = 7,.with_padmix = 0,},
+ {.att = 9,.with_padmix = 0,},
+ {.att = 2,.with_padmix = 0,},
+ {.att = 0,.with_padmix = 0,},
+ {.att = 4,.with_padmix = 0,},
+ {.att = 6,.with_padmix = 0,},
+ {.att = 8,.with_padmix = 0,},
+ {.att = 1,.with_padmix = 1,},
+ {.att = 2,.with_padmix = 1,},
+ {.att = 3,.with_padmix = 1,},
+ {.att = 4,.with_padmix = 1,},
+ };
+ /* Radio.rev == 8 && Radio.version == 0x2050 */
+ static const struct b43_rfatt rfatt_1[] = {
+ {.att = 2,.with_padmix = 1,},
+ {.att = 4,.with_padmix = 1,},
+ {.att = 6,.with_padmix = 1,},
+ {.att = 8,.with_padmix = 1,},
+ {.att = 10,.with_padmix = 1,},
+ {.att = 12,.with_padmix = 1,},
+ {.att = 14,.with_padmix = 1,},
+ };
+ /* Otherwise */
+ static const struct b43_rfatt rfatt_2[] = {
+ {.att = 0,.with_padmix = 1,},
+ {.att = 2,.with_padmix = 1,},
+ {.att = 4,.with_padmix = 1,},
+ {.att = 6,.with_padmix = 1,},
+ {.att = 8,.with_padmix = 1,},
+ {.att = 9,.with_padmix = 1,},
+ {.att = 9,.with_padmix = 1,},
+ };
+
+ if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) ||
+ (phy->type == B43_PHYTYPE_G && phy->rev < 6)) {
+ /* Software pctl */
+ list->list = rfatt_0;
+ list->len = ARRAY_SIZE(rfatt_0);
+ list->min_val = 0;
+ list->max_val = 9;
+ return;
+ }
+ if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+ /* Hardware pctl */
+ list->list = rfatt_1;
+ list->len = ARRAY_SIZE(rfatt_1);
+ list->min_val = 2;
+ list->max_val = 14;
+ return;
+ }
+ /* Hardware pctl */
+ list->list = rfatt_2;
+ list->len = ARRAY_SIZE(rfatt_2);
+ list->min_val = 0;
+ list->max_val = 9;
+}
+
+static void generate_bbatt_list(struct b43_wldev *dev,
+ struct b43_bbatt_list *list)
+{
+ static const struct b43_bbatt bbatt_0[] = {
+ {.att = 0,},
+ {.att = 1,},
+ {.att = 2,},
+ {.att = 3,},
+ {.att = 4,},
+ {.att = 5,},
+ {.att = 6,},
+ {.att = 7,},
+ {.att = 8,},
+ };
+
+ list->list = bbatt_0;
+ list->len = ARRAY_SIZE(bbatt_0);
+ list->min_val = 0;
+ list->max_val = 8;
+}
+
+bool b43_has_hardware_pctl(struct b43_phy *phy)
+{
+ if (!phy->hardware_power_control)
+ return 0;
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ if (phy->rev >= 5)
+ return 1;
+ break;
+ case B43_PHYTYPE_G:
+ if (phy->rev >= 6)
+ return 1;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ return 0;
+}
+
+static void b43_shm_clear_tssi(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0068, 0x7F7F);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x006a, 0x7F7F);
+ break;
+ case B43_PHYTYPE_B:
+ case B43_PHYTYPE_G:
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F);
+ b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F);
+ break;
+ }
+}
+
+void b43_raw_phy_lock(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ B43_WARN_ON(!irqs_disabled());
+
+ /* We had a check for MACCTL==0 here, but I think that doesn't
+ * make sense, as MACCTL is never 0 when this is called.
+ * --mb */
+ B43_WARN_ON(b43_read32(dev, B43_MMIO_MACCTL) == 0);
+
+ if (dev->dev->id.revision < 3) {
+ b43_mac_suspend(dev);
+ spin_lock(&phy->lock);
+ } else {
+ if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
+ }
+ phy->locked = 1;
+}
+
+void b43_raw_phy_unlock(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ B43_WARN_ON(!irqs_disabled());
+ if (dev->dev->id.revision < 3) {
+ if (phy->locked) {
+ spin_unlock(&phy->lock);
+ b43_mac_enable(dev);
+ }
+ } else {
+ if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ b43_power_saving_ctl_bits(dev, 0);
+ }
+ phy->locked = 0;
+}
+
+/* Different PHYs require different register routing flags.
+ * This adjusts (and does sanity checks on) the routing flags.
+ */
+static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy,
+ u16 offset, struct b43_wldev *dev)
+{
+ if (phy->type == B43_PHYTYPE_A) {
+ /* OFDM registers are base-registers for the A-PHY. */
+ offset &= ~B43_PHYROUTE_OFDM_GPHY;
+ }
+ if (offset & B43_PHYROUTE_EXT_GPHY) {
+ /* Ext-G registers are only available on G-PHYs */
+ if (phy->type != B43_PHYTYPE_G) {
+ b43dbg(dev->wl, "EXT-G PHY access at "
+ "0x%04X on %u type PHY\n", offset, phy->type);
+ }
+ }
+
+ return offset;
+}
+
+u16 b43_phy_read(struct b43_wldev * dev, u16 offset)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ offset = adjust_phyreg_for_phytype(phy, offset, dev);
+ b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
+ return b43_read16(dev, B43_MMIO_PHY_DATA);
+}
+
+void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ offset = adjust_phyreg_for_phytype(phy, offset, dev);
+ b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_PHY_DATA, val);
+}
+
+static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower);
+
+/* Adjust the transmission power output (G-PHY) */
+void b43_set_txpower_g(struct b43_wldev *dev,
+ const struct b43_bbatt *bbatt,
+ const struct b43_rfatt *rfatt, u8 tx_control)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ u16 bb, rf;
+ u16 tx_bias, tx_magn;
+
+ bb = bbatt->att;
+ rf = rfatt->att;
+ tx_bias = lo->tx_bias;
+ tx_magn = lo->tx_magn;
+ if (unlikely(tx_bias == 0xFF))
+ tx_bias = 0;
+
+ /* Save the values for later */
+ phy->tx_control = tx_control;
+ memcpy(&phy->rfatt, rfatt, sizeof(*rfatt));
+ memcpy(&phy->bbatt, bbatt, sizeof(*bbatt));
+
+ if (b43_debug(dev, B43_DBG_XMITPOWER)) {
+ b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), "
+ "rfatt(%u), tx_control(0x%02X), "
+ "tx_bias(0x%02X), tx_magn(0x%02X)\n",
+ bb, rf, tx_control, tx_bias, tx_magn);
+ }
+
+ b43_phy_set_baseband_attenuation(dev, bb);
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf);
+ if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+ b43_radio_write16(dev, 0x43,
+ (rf & 0x000F) | (tx_control & 0x0070));
+ } else {
+ b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+ & 0xFFF0) | (rf & 0x000F));
+ b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
+ & ~0x0070) | (tx_control &
+ 0x0070));
+ }
+ if (has_tx_magnification(phy)) {
+ b43_radio_write16(dev, 0x52, tx_magn | tx_bias);
+ } else {
+ b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
+ & 0xFFF0) | (tx_bias & 0x000F));
+ }
+ if (phy->type == B43_PHYTYPE_G)
+ b43_lo_g_adjust(dev);
+}
+
+static void default_baseband_attenuation(struct b43_wldev *dev,
+ struct b43_bbatt *bb)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
+ bb->att = 0;
+ else
+ bb->att = 2;
+}
+
+static void default_radio_attenuation(struct b43_wldev *dev,
+ struct b43_rfatt *rf)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy *phy = &dev->phy;
+
+ rf->with_padmix = 0;
+
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+ bus->boardinfo.type == SSB_BOARD_BCM4309G) {
+ if (bus->boardinfo.rev < 0x43) {
+ rf->att = 2;
+ return;
+ } else if (bus->boardinfo.rev < 0x51) {
+ rf->att = 3;
+ return;
+ }
+ }
+
+ if (phy->type == B43_PHYTYPE_A) {
+ rf->att = 0x60;
+ return;
+ }
+
+ switch (phy->radio_ver) {
+ case 0x2053:
+ switch (phy->radio_rev) {
+ case 1:
+ rf->att = 6;
+ return;
+ }
+ break;
+ case 0x2050:
+ switch (phy->radio_rev) {
+ case 0:
+ rf->att = 5;
+ return;
+ case 1:
+ if (phy->type == B43_PHYTYPE_G) {
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
+ && bus->boardinfo.type == SSB_BOARD_BCM4309G
+ && bus->boardinfo.rev >= 30)
+ rf->att = 3;
+ else if (bus->boardinfo.vendor ==
+ SSB_BOARDVENDOR_BCM
+ && bus->boardinfo.type ==
+ SSB_BOARD_BU4306)
+ rf->att = 3;
+ else
+ rf->att = 1;
+ } else {
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
+ && bus->boardinfo.type == SSB_BOARD_BCM4309G
+ && bus->boardinfo.rev >= 30)
+ rf->att = 7;
+ else
+ rf->att = 6;
+ }
+ return;
+ case 2:
+ if (phy->type == B43_PHYTYPE_G) {
+ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
+ && bus->boardinfo.type == SSB_BOARD_BCM4309G
+ && bus->boardinfo.rev >= 30)
+ rf->att = 3;
+ else if (bus->boardinfo.vendor ==
+ SSB_BOARDVENDOR_BCM
+ && bus->boardinfo.type ==
+ SSB_BOARD_BU4306)
+ rf->att = 5;
+ else if (bus->chip_id == 0x4320)
+ rf->att = 4;
+ else
+ rf->att = 3;
+ } else
+ rf->att = 6;
+ return;
+ case 3:
+ rf->att = 5;
+ return;
+ case 4:
+ case 5:
+ rf->att = 1;
+ return;
+ case 6:
+ case 7:
+ rf->att = 5;
+ return;
+ case 8:
+ rf->att = 0xA;
+ rf->with_padmix = 1;
+ return;
+ case 9:
+ default:
+ rf->att = 5;
+ return;
+ }
+ }
+ rf->att = 5;
+}
+
+static u16 default_tx_control(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (phy->radio_ver != 0x2050)
+ return 0;
+ if (phy->radio_rev == 1)
+ return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX;
+ if (phy->radio_rev < 6)
+ return B43_TXCTL_PA2DB;
+ if (phy->radio_rev == 8)
+ return B43_TXCTL_TXMIX;
+ return 0;
+}
+
+/* This func is called "PHY calibrate" in the specs... */
+void b43_phy_early_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+
+ default_baseband_attenuation(dev, &phy->bbatt);
+ default_radio_attenuation(dev, &phy->rfatt);
+ phy->tx_control = (default_tx_control(dev) << 4);
+
+ /* Commit previous writes */
+ b43_read32(dev, B43_MMIO_MACCTL);
+
+ if (phy->type == B43_PHYTYPE_B || phy->type == B43_PHYTYPE_G) {
+ generate_rfatt_list(dev, &lo->rfatt_list);
+ generate_bbatt_list(dev, &lo->bbatt_list);
+ }
+ if (phy->type == B43_PHYTYPE_G && phy->rev == 1) {
+ /* Workaround: Temporarly disable gmode through the early init
+ * phase, as the gmode stuff is not needed for phy rev 1 */
+ phy->gmode = 0;
+ b43_wireless_core_reset(dev, 0);
+ b43_phy_initg(dev);
+ phy->gmode = 1;
+ b43_wireless_core_reset(dev, B43_TMSLOW_GMODE);
+ }
+}
+
+/* GPHY_TSSI_Power_Lookup_Table_Init */
+static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ int i;
+ u16 value;
+
+ for (i = 0; i < 32; i++)
+ b43_ofdmtab_write16(dev, 0x3C20, i, phy->tssi2dbm[i]);
+ for (i = 32; i < 64; i++)
+ b43_ofdmtab_write16(dev, 0x3C00, i - 32, phy->tssi2dbm[i]);
+ for (i = 0; i < 64; i += 2) {
+ value = (u16) phy->tssi2dbm[i];
+ value |= ((u16) phy->tssi2dbm[i + 1]) << 8;
+ b43_phy_write(dev, 0x380 + (i / 2), value);
+ }
+}
+
+/* GPHY_Gain_Lookup_Table_Init */
+static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ u16 nr_written = 0;
+ u16 tmp;
+ u8 rf, bb;
+
+ if (!lo->lo_measured) {
+ b43_phy_write(dev, 0x3FF, 0);
+ return;
+ }
+
+ for (rf = 0; rf < lo->rfatt_list.len; rf++) {
+ for (bb = 0; bb < lo->bbatt_list.len; bb++) {
+ if (nr_written >= 0x40)
+ return;
+ tmp = lo->bbatt_list.list[bb].att;
+ tmp <<= 8;
+ if (phy->radio_rev == 8)
+ tmp |= 0x50;
+ else
+ tmp |= 0x40;
+ tmp |= lo->rfatt_list.list[rf].att;
+ b43_phy_write(dev, 0x3C0 + nr_written, tmp);
+ nr_written++;
+ }
+ }
+}
+
+/* GPHY_DC_Lookup_Table */
+void b43_gphy_dc_lt_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_txpower_lo_control *lo = phy->lo_control;
+ struct b43_loctl *loctl0;
+ struct b43_loctl *loctl1;
+ int i;
+ int rf_offset, bb_offset;
+ u16 tmp;
+
+ for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) {
+ rf_offset = i / lo->rfatt_list.len;
+ bb_offset = i % lo->rfatt_list.len;
+
+ loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset],
+ &lo->bbatt_list.list[bb_offset]);
+ if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) {
+ rf_offset = (i + 1) / lo->rfatt_list.len;
+ bb_offset = (i + 1) % lo->rfatt_list.len;
+
+ loctl1 =
+ b43_get_lo_g_ctl(dev,
+ &lo->rfatt_list.list[rf_offset],
+ &lo->bbatt_list.list[bb_offset]);
+ } else
+ loctl1 = loctl0;
+
+ tmp = ((u16) loctl0->q & 0xF);
+ tmp |= ((u16) loctl0->i & 0xF) << 4;
+ tmp |= ((u16) loctl1->q & 0xF) << 8;
+ tmp |= ((u16) loctl1->i & 0xF) << 12; //FIXME?
+ b43_phy_write(dev, 0x3A0 + (i / 2), tmp);
+ }
+}
+
+static void hardware_pctl_init_aphy(struct b43_wldev *dev)
+{
+ //TODO
+}
+
+static void hardware_pctl_init_gphy(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0)
+ | (phy->tgt_idle_tssi - phy->cur_idle_tssi));
+ b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00)
+ | (phy->tgt_idle_tssi - phy->cur_idle_tssi));
+ b43_gphy_tssi_power_lt_init(dev);
+ b43_gphy_gain_lt_init(dev);
+ b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF);
+ b43_phy_write(dev, 0x0014, 0x0000);
+
+ B43_WARN_ON(phy->rev < 6);
+ b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
+ | 0x0800);
+ b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
+ & 0xFEFF);
+ b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801)
+ & 0xFFBF);
+
+ b43_gphy_dc_lt_init(dev);
+}
+
+/* HardwarePowerControl init for A and G PHY */
+static void b43_hardware_pctl_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (!b43_has_hardware_pctl(phy)) {
+ /* No hardware power control */
+ b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL);
+ return;
+ }
+ /* Init the hwpctl related hardware */
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ hardware_pctl_init_aphy(dev);
+ break;
+ case B43_PHYTYPE_G:
+ hardware_pctl_init_gphy(dev);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ /* Enable hardware pctl in firmware. */
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL);
+}
+
+static void b43_hardware_pctl_early_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (!b43_has_hardware_pctl(phy)) {
+ b43_phy_write(dev, 0x047A, 0xC111);
+ return;
+ }
+
+ b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF);
+ b43_phy_write(dev, 0x002F, 0x0202);
+ b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002);
+ b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000);
+ if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+ b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
+ & 0xFF0F) | 0x0010);
+ b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
+ | 0x8000);
+ b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
+ & 0xFFC0) | 0x0010);
+ b43_phy_write(dev, 0x002E, 0xC07F);
+ b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
+ | 0x0400);
+ } else {
+ b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
+ | 0x0200);
+ b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
+ | 0x0400);
+ b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
+ & 0x7FFF);
+ b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F)
+ & 0xFFFE);
+ b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
+ & 0xFFC0) | 0x0010);
+ b43_phy_write(dev, 0x002E, 0xC07F);
+ b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
+ & 0xFF0F) | 0x0010);
+ }
+}
+
+/* Intialize B/G PHY power control
+ * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
+ */
+static void b43_phy_init_pctl(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy *phy = &dev->phy;
+ struct b43_rfatt old_rfatt;
+ struct b43_bbatt old_bbatt;
+ u8 old_tx_control = 0;
+
+ if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+ (bus->boardinfo.type == SSB_BOARD_BU4306))
+ return;
+
+ b43_phy_write(dev, 0x0028, 0x8018);
+
+ /* This does something with the Analog... */
+ b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0)
+ & 0xFFDF);
+
+ if (phy->type == B43_PHYTYPE_G && !phy->gmode)
+ return;
+ b43_hardware_pctl_early_init(dev);
+ if (phy->cur_idle_tssi == 0) {
+ if (phy->radio_ver == 0x2050 && phy->analog == 0) {
+ b43_radio_write16(dev, 0x0076,
+ (b43_radio_read16(dev, 0x0076)
+ & 0x00F7) | 0x0084);
+ } else {
+ struct b43_rfatt rfatt;
+ struct b43_bbatt bbatt;
+
+ memcpy(&old_rfatt, &phy->rfatt, sizeof(old_rfatt));
+ memcpy(&old_bbatt, &phy->bbatt, sizeof(old_bbatt));
+ old_tx_control = phy->tx_control;
+
+ bbatt.att = 11;
+ if (phy->radio_rev == 8) {
+ rfatt.att = 15;
+ rfatt.with_padmix = 1;
+ } else {
+ rfatt.att = 9;
+ rfatt.with_padmix = 0;
+ }
+ b43_set_txpower_g(dev, &bbatt, &rfatt, 0);
+ }
+ b43_dummy_transmission(dev);
+ phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI);
+ if (B43_DEBUG) {
+ /* Current-Idle-TSSI sanity check. */
+ if (abs(phy->cur_idle_tssi - phy->tgt_idle_tssi) >= 20) {
+ b43dbg(dev->wl,
+ "!WARNING! Idle-TSSI phy->cur_idle_tssi "
+ "measuring failed. (cur=%d, tgt=%d). Disabling TX power "
+ "adjustment.\n", phy->cur_idle_tssi,
+ phy->tgt_idle_tssi);
+ phy->cur_idle_tssi = 0;
+ }
+ }
+ if (phy->radio_ver == 0x2050 && phy->analog == 0) {
+ b43_radio_write16(dev, 0x0076,
+ b43_radio_read16(dev, 0x0076)
+ & 0xFF7B);
+ } else {
+ b43_set_txpower_g(dev, &old_bbatt,
+ &old_rfatt, old_tx_control);
+ }
+ }
+ b43_hardware_pctl_init(dev);
+ b43_shm_clear_tssi(dev);
+}
+
+static void b43_phy_agcsetup(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 offset = 0x0000;
+
+ if (phy->rev == 1)
+ offset = 0x4C00;
+
+ b43_ofdmtab_write16(dev, offset, 0, 0x00FE);
+ b43_ofdmtab_write16(dev, offset, 1, 0x000D);
+ b43_ofdmtab_write16(dev, offset, 2, 0x0013);
+ b43_ofdmtab_write16(dev, offset, 3, 0x0019);
+
+ if (phy->rev == 1) {
+ b43_ofdmtab_write16(dev, 0x1800, 0, 0x2710);
+ b43_ofdmtab_write16(dev, 0x1801, 0, 0x9B83);
+ b43_ofdmtab_write16(dev, 0x1802, 0, 0x9B83);
+ b43_ofdmtab_write16(dev, 0x1803, 0, 0x0F8D);
+ b43_phy_write(dev, 0x0455, 0x0004);
+ }
+
+ b43_phy_write(dev, 0x04A5, (b43_phy_read(dev, 0x04A5)
+ & 0x00FF) | 0x5700);
+ b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A)
+ & 0xFF80) | 0x000F);
+ b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A)
+ & 0xC07F) | 0x2B80);
+ b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
+ & 0xF0FF) | 0x0300);
+
+ b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A)
+ | 0x0008);
+
+ b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+ & 0xFFF0) | 0x0008);
+ b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
+ & 0xF0FF) | 0x0600);
+ b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+ & 0xF0FF) | 0x0700);
+ b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+ & 0xF0FF) | 0x0100);
+
+ if (phy->rev == 1) {
+ b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+ & 0xFFF0) | 0x0007);
+ }
+
+ b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488)
+ & 0xFF00) | 0x001C);
+ b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488)
+ & 0xC0FF) | 0x0200);
+ b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496)
+ & 0xFF00) | 0x001C);
+ b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489)
+ & 0xFF00) | 0x0020);
+ b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489)
+ & 0xC0FF) | 0x0200);
+ b43_phy_write(dev, 0x0482, (b43_phy_read(dev, 0x0482)
+ & 0xFF00) | 0x002E);
+ b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496)
+ & 0x00FF) | 0x1A00);
+ b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481)
+ & 0xFF00) | 0x0028);
+ b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481)
+ & 0x00FF) | 0x2C00);
+
+ if (phy->rev == 1) {
+ b43_phy_write(dev, 0x0430, 0x092B);
+ b43_phy_write(dev, 0x041B, (b43_phy_read(dev, 0x041B)
+ & 0xFFE1) | 0x0002);
+ } else {
+ b43_phy_write(dev, 0x041B, b43_phy_read(dev, 0x041B)
+ & 0xFFE1);
+ b43_phy_write(dev, 0x041F, 0x287A);
+ b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420)
+ & 0xFFF0) | 0x0004);
+ }
+
+ if (phy->rev >= 6) {
+ b43_phy_write(dev, 0x0422, 0x287A);
+ b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420)
+ & 0x0FFF) | 0x3000);
+ }
+
+ b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+ & 0x8080) | 0x7874);
+ b43_phy_write(dev, 0x048E, 0x1C00);
+
+ offset = 0x0800;
+ if (phy->rev == 1) {
+ offset = 0x5400;
+ b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+ & 0xF0FF) | 0x0600);
+ b43_phy_write(dev, 0x048B, 0x005E);
+ b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
+ & 0xFF00) | 0x001E);
+ b43_phy_write(dev, 0x048D, 0x0002);
+ }
+ b43_ofdmtab_write16(dev, offset, 0, 0x00);
+ b43_ofdmtab_write16(dev, offset, 1, 0x07);
+ b43_ofdmtab_write16(dev, offset, 2, 0x10);
+ b43_ofdmtab_write16(dev, offset, 3, 0x1C);
+
+ if (phy->rev >= 6) {
+ b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426)
+ & 0xFFFC);
+ b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426)
+ & 0xEFFF);
+ }
+}
+
+static void b43_phy_setupg(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy *phy = &dev->phy;
+ u16 i;
+
+ B43_WARN_ON(phy->type != B43_PHYTYPE_G);
+ if (phy->rev == 1) {
+ b43_phy_write(dev, 0x0406, 0x4F19);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ (b43_phy_read(dev, B43_PHY_G_CRS) & 0xFC3F) |
+ 0x0340);
+ b43_phy_write(dev, 0x042C, 0x005A);
+ b43_phy_write(dev, 0x0427, 0x001A);
+
+ for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x5800, i,
+ b43_tab_finefreqg[i]);
+ for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg1[i]);
+ for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x2000, i, b43_tab_rotor[i]);
+ } else {
+ /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */
+ b43_nrssi_hw_write(dev, 0xBA98, (s16) 0x7654);
+
+ if (phy->rev == 2) {
+ b43_phy_write(dev, 0x04C0, 0x1861);
+ b43_phy_write(dev, 0x04C1, 0x0271);
+ } else if (phy->rev > 2) {
+ b43_phy_write(dev, 0x04C0, 0x0098);
+ b43_phy_write(dev, 0x04C1, 0x0070);
+ b43_phy_write(dev, 0x04C9, 0x0080);
+ }
+ b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x800);
+
+ for (i = 0; i < 64; i++)
+ b43_ofdmtab_write16(dev, 0x4000, i, i);
+ for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg2[i]);
+ }
+
+ if (phy->rev <= 2)
+ for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x1400, i,
+ b43_tab_noisescaleg1[i]);
+ else if ((phy->rev >= 7) && (b43_phy_read(dev, 0x0449) & 0x0200))
+ for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x1400, i,
+ b43_tab_noisescaleg3[i]);
+ else
+ for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x1400, i,
+ b43_tab_noisescaleg2[i]);
+
+ if (phy->rev == 2)
+ for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x5000, i,
+ b43_tab_sigmasqr1[i]);
+ else if ((phy->rev > 2) && (phy->rev <= 8))
+ for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x5000, i,
+ b43_tab_sigmasqr2[i]);
+
+ if (phy->rev == 1) {
+ for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
+ b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]);
+ for (i = 4; i < 20; i++)
+ b43_ofdmtab_write16(dev, 0x5400, i, 0x0020);
+ b43_phy_agcsetup(dev);
+
+ if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+ (bus->boardinfo.type == SSB_BOARD_BU4306) &&
+ (bus->boardinfo.rev == 0x17))
+ return;
+
+ b43_ofdmtab_write16(dev, 0x5001, 0, 0x0002);
+ b43_ofdmtab_write16(dev, 0x5002, 0, 0x0001);
+ } else {
+ for (i = 0; i < 0x20; i++)
+ b43_ofdmtab_write16(dev, 0x1000, i, 0x0820);
+ b43_phy_agcsetup(dev);
+ b43_phy_read(dev, 0x0400); /* dummy read */
+ b43_phy_write(dev, 0x0403, 0x1000);
+ b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F);
+ b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
+
+ if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+ (bus->boardinfo.type == SSB_BOARD_BU4306) &&
+ (bus->boardinfo.rev == 0x17))
+ return;
+
+ b43_ofdmtab_write16(dev, 0x0401, 0, 0x0002);
+ b43_ofdmtab_write16(dev, 0x0402, 0, 0x0001);
+ }
+}
+
+/* Initialize the noisescaletable for APHY */
+static void b43_phy_init_noisescaletbl(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ int i;
+
+ for (i = 0; i < 12; i++) {
+ if (phy->rev == 2)
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x6767);
+ else
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x2323);
+ }
+ if (phy->rev == 2)
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x6700);
+ else
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x2300);
+ for (i = 0; i < 11; i++) {
+ if (phy->rev == 2)
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x6767);
+ else
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x2323);
+ }
+ if (phy->rev == 2)
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x0067);
+ else
+ b43_ofdmtab_write16(dev, 0x1400, i, 0x0023);
+}
+
+static void b43_phy_setupa(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 i;
+
+ B43_WARN_ON(phy->type != B43_PHYTYPE_A);
+ switch (phy->rev) {
+ case 2:
+ b43_phy_write(dev, 0x008E, 0x3800);
+ b43_phy_write(dev, 0x0035, 0x03FF);
+ b43_phy_write(dev, 0x0036, 0x0400);
+
+ b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051);
+
+ b43_phy_write(dev, 0x001C, 0x0FF9);
+ b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F);
+ b43_ofdmtab_write16(dev, 0x3C0C, 0, 0x07BF);
+ b43_radio_write16(dev, 0x0002, 0x07BF);
+
+ b43_phy_write(dev, 0x0024, 0x4680);
+ b43_phy_write(dev, 0x0020, 0x0003);
+ b43_phy_write(dev, 0x001D, 0x0F40);
+ b43_phy_write(dev, 0x001F, 0x1C00);
+
+ b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A)
+ & 0x00FF) | 0x0400);
+ b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B)
+ & 0xFBFF);
+ b43_phy_write(dev, 0x008E, 0x58C1);
+
+ b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F);
+ b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F);
+ b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A);
+ b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030);
+ b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A);
+
+ b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0000, 1, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0000, 2, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0000, 3, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0000, 4, 0x0015);
+ b43_ofdmtab_write16(dev, 0x0000, 5, 0x0015);
+ b43_ofdmtab_write16(dev, 0x0000, 6, 0x0019);
+
+ b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003);
+ b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003);
+ b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007);
+
+ for (i = 0; i < 16; i++)
+ b43_ofdmtab_write16(dev, 0x4000, i, (0x8 + i) & 0x000F);
+
+ b43_ofdmtab_write16(dev, 0x3003, 0, 0x1044);
+ b43_ofdmtab_write16(dev, 0x3004, 0, 0x7201);
+ b43_ofdmtab_write16(dev, 0x3006, 0, 0x0040);
+ b43_ofdmtab_write16(dev, 0x3001, 0,
+ (b43_ofdmtab_read16(dev, 0x3001, 0) &
+ 0x0010) | 0x0008);
+
+ for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x5800, i,
+ b43_tab_finefreqa[i]);
+ for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++)
+ b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea2[i]);
+ for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
+ b43_ofdmtab_write32(dev, 0x2000, i, b43_tab_rotor[i]);
+ b43_phy_init_noisescaletbl(dev);
+ for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
+ b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]);
+ break;
+ case 3:
+ for (i = 0; i < 64; i++)
+ b43_ofdmtab_write16(dev, 0x4000, i, i);
+
+ b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051);
+
+ b43_phy_write(dev, 0x001C, 0x0FF9);
+ b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F);
+ b43_radio_write16(dev, 0x0002, 0x07BF);
+
+ b43_phy_write(dev, 0x0024, 0x4680);
+ b43_phy_write(dev, 0x0020, 0x0003);
+ b43_phy_write(dev, 0x001D, 0x0F40);
+ b43_phy_write(dev, 0x001F, 0x1C00);
+ b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A)
+ & 0x00FF) | 0x0400);
+
+ b43_ofdmtab_write16(dev, 0x3000, 1,
+ (b43_ofdmtab_read16(dev, 0x3000, 1)
+ & 0x0010) | 0x0008);
+ for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++) {
+ b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea3[i]);
+ }
+ b43_phy_init_noisescaletbl(dev);
+ for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) {
+ b43_ofdmtab_write16(dev, 0x5000, i,
+ b43_tab_sigmasqr1[i]);
+ }
+
+ b43_phy_write(dev, 0x0003, 0x1808);
+
+ b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F);
+ b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F);
+ b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A);
+ b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030);
+ b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A);
+
+ b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0001, 0, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0002, 0, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0003, 0, 0x0013);
+ b43_ofdmtab_write16(dev, 0x0004, 0, 0x0015);
+ b43_ofdmtab_write16(dev, 0x0005, 0, 0x0015);
+ b43_ofdmtab_write16(dev, 0x0006, 0, 0x0019);
+
+ b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003);
+ b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003);
+ b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007);
+
+ b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F);
+ b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+/* Initialize APHY. This is also called for the GPHY in some cases. */
+static void b43_phy_inita(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy *phy = &dev->phy;
+ u16 tval;
+
+ might_sleep();
+
+ if (phy->type == B43_PHYTYPE_A) {
+ b43_phy_setupa(dev);
+ } else {
+ b43_phy_setupg(dev);
+ if (phy->gmode &&
+ (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL))
+ b43_phy_write(dev, 0x046E, 0x03CF);
+ return;
+ }
+
+ b43_phy_write(dev, B43_PHY_A_CRS,
+ (b43_phy_read(dev, B43_PHY_A_CRS) & 0xF83C) | 0x0340);
+ b43_phy_write(dev, 0x0034, 0x0001);
+
+ //TODO: RSSI AGC
+ b43_phy_write(dev, B43_PHY_A_CRS,
+ b43_phy_read(dev, B43_PHY_A_CRS) | (1 << 14));
+ b43_radio_init2060(dev);
+
+ if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+ ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
+ (bus->boardinfo.type == SSB_BOARD_BU4309))) {
+ if (phy->lofcal == 0xFFFF) {
+ //TODO: LOF Cal
+ b43_radio_set_tx_iq(dev);
+ } else
+ b43_radio_write16(dev, 0x001E, phy->lofcal);
+ }
+
+ b43_phy_write(dev, 0x007A, 0xF111);
+
+ if (phy->cur_idle_tssi == 0) {
+ b43_radio_write16(dev, 0x0019, 0x0000);
+ b43_radio_write16(dev, 0x0017, 0x0020);
+
+ tval = b43_ofdmtab_read16(dev, 0x3001, 0);
+ if (phy->rev == 1) {
+ b43_ofdmtab_write16(dev, 0x3001, 0,
+ (b43_ofdmtab_read16(dev, 0x3001, 0)
+ & 0xFF87)
+ | 0x0058);
+ } else {
+ b43_ofdmtab_write16(dev, 0x3001, 0,
+ (b43_ofdmtab_read16(dev, 0x3001, 0)
+ & 0xFFC3)
+ | 0x002C);
+ }
+ b43_dummy_transmission(dev);
+ phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_A_PCTL);
+ b43_ofdmtab_write16(dev, 0x3001, 0, tval);
+
+ b43_radio_set_txpower_a(dev, 0x0018);
+ }
+ b43_shm_clear_tssi(dev);
+}
+
+static void b43_phy_initb2(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 offset, val;
+
+ b43_write16(dev, 0x03EC, 0x3F22);
+ b43_phy_write(dev, 0x0020, 0x301C);
+ b43_phy_write(dev, 0x0026, 0x0000);
+ b43_phy_write(dev, 0x0030, 0x00C6);
+ b43_phy_write(dev, 0x0088, 0x3E00);
+ val = 0x3C3D;
+ for (offset = 0x0089; offset < 0x00A7; offset++) {
+ b43_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ b43_phy_write(dev, 0x03E4, 0x3000);
+ b43_radio_selectchannel(dev, phy->channel, 0);
+ if (phy->radio_ver != 0x2050) {
+ b43_radio_write16(dev, 0x0075, 0x0080);
+ b43_radio_write16(dev, 0x0079, 0x0081);
+ }
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x0050, 0x0023);
+ if (phy->radio_ver == 0x2050) {
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x005A, 0x0070);
+ b43_radio_write16(dev, 0x005B, 0x007B);
+ b43_radio_write16(dev, 0x005C, 0x00B0);
+ b43_radio_write16(dev, 0x007A, 0x000F);
+ b43_phy_write(dev, 0x0038, 0x0677);
+ b43_radio_init2050(dev);
+ }
+ b43_phy_write(dev, 0x0014, 0x0080);
+ b43_phy_write(dev, 0x0032, 0x00CA);
+ b43_phy_write(dev, 0x0032, 0x00CC);
+ b43_phy_write(dev, 0x0035, 0x07C2);
+ b43_lo_b_measure(dev);
+ b43_phy_write(dev, 0x0026, 0xCC00);
+ if (phy->radio_ver != 0x2050)
+ b43_phy_write(dev, 0x0026, 0xCE00);
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000);
+ b43_phy_write(dev, 0x002A, 0x88A3);
+ if (phy->radio_ver != 0x2050)
+ b43_phy_write(dev, 0x002A, 0x88C2);
+ b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
+ b43_phy_init_pctl(dev);
+}
+
+static void b43_phy_initb4(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 offset, val;
+
+ b43_write16(dev, 0x03EC, 0x3F22);
+ b43_phy_write(dev, 0x0020, 0x301C);
+ b43_phy_write(dev, 0x0026, 0x0000);
+ b43_phy_write(dev, 0x0030, 0x00C6);
+ b43_phy_write(dev, 0x0088, 0x3E00);
+ val = 0x3C3D;
+ for (offset = 0x0089; offset < 0x00A7; offset++) {
+ b43_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ b43_phy_write(dev, 0x03E4, 0x3000);
+ b43_radio_selectchannel(dev, phy->channel, 0);
+ if (phy->radio_ver != 0x2050) {
+ b43_radio_write16(dev, 0x0075, 0x0080);
+ b43_radio_write16(dev, 0x0079, 0x0081);
+ }
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x0050, 0x0023);
+ if (phy->radio_ver == 0x2050) {
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x005A, 0x0070);
+ b43_radio_write16(dev, 0x005B, 0x007B);
+ b43_radio_write16(dev, 0x005C, 0x00B0);
+ b43_radio_write16(dev, 0x007A, 0x000F);
+ b43_phy_write(dev, 0x0038, 0x0677);
+ b43_radio_init2050(dev);
+ }
+ b43_phy_write(dev, 0x0014, 0x0080);
+ b43_phy_write(dev, 0x0032, 0x00CA);
+ if (phy->radio_ver == 0x2050)
+ b43_phy_write(dev, 0x0032, 0x00E0);
+ b43_phy_write(dev, 0x0035, 0x07C2);
+
+ b43_lo_b_measure(dev);
+
+ b43_phy_write(dev, 0x0026, 0xCC00);
+ if (phy->radio_ver == 0x2050)
+ b43_phy_write(dev, 0x0026, 0xCE00);
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100);
+ b43_phy_write(dev, 0x002A, 0x88A3);
+ if (phy->radio_ver == 0x2050)
+ b43_phy_write(dev, 0x002A, 0x88C2);
+ b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+ b43_calc_nrssi_slope(dev);
+ b43_calc_nrssi_threshold(dev);
+ }
+ b43_phy_init_pctl(dev);
+}
+
+static void b43_phy_initb5(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy *phy = &dev->phy;
+ u16 offset, value;
+ u8 old_channel;
+
+ if (phy->analog == 1) {
+ b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A)
+ | 0x0050);
+ }
+ if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) &&
+ (bus->boardinfo.type != SSB_BOARD_BU4306)) {
+ value = 0x2120;
+ for (offset = 0x00A8; offset < 0x00C7; offset++) {
+ b43_phy_write(dev, offset, value);
+ value += 0x202;
+ }
+ }
+ b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF)
+ | 0x0700);
+ if (phy->radio_ver == 0x2050)
+ b43_phy_write(dev, 0x0038, 0x0667);
+
+ if (phy->gmode || phy->rev >= 2) {
+ if (phy->radio_ver == 0x2050) {
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A)
+ | 0x0020);
+ b43_radio_write16(dev, 0x0051,
+ b43_radio_read16(dev, 0x0051)
+ | 0x0004);
+ }
+ b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000);
+
+ b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
+ b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
+
+ b43_phy_write(dev, 0x001C, 0x186A);
+
+ b43_phy_write(dev, 0x0013,
+ (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900);
+ b43_phy_write(dev, 0x0035,
+ (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064);
+ b43_phy_write(dev, 0x005D,
+ (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A);
+ }
+
+ if (dev->bad_frames_preempt) {
+ b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+ b43_phy_read(dev,
+ B43_PHY_RADIO_BITFIELD) | (1 << 11));
+ }
+
+ if (phy->analog == 1) {
+ b43_phy_write(dev, 0x0026, 0xCE00);
+ b43_phy_write(dev, 0x0021, 0x3763);
+ b43_phy_write(dev, 0x0022, 0x1BC3);
+ b43_phy_write(dev, 0x0023, 0x06F9);
+ b43_phy_write(dev, 0x0024, 0x037E);
+ } else
+ b43_phy_write(dev, 0x0026, 0xCC00);
+ b43_phy_write(dev, 0x0030, 0x00C6);
+ b43_write16(dev, 0x03EC, 0x3F22);
+
+ if (phy->analog == 1)
+ b43_phy_write(dev, 0x0020, 0x3E1C);
+ else
+ b43_phy_write(dev, 0x0020, 0x301C);
+
+ if (phy->analog == 0)
+ b43_write16(dev, 0x03E4, 0x3000);
+
+ old_channel = phy->channel;
+ /* Force to channel 7, even if not supported. */
+ b43_radio_selectchannel(dev, 7, 0);
+
+ if (phy->radio_ver != 0x2050) {
+ b43_radio_write16(dev, 0x0075, 0x0080);
+ b43_radio_write16(dev, 0x0079, 0x0081);
+ }
+
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x0050, 0x0023);
+
+ if (phy->radio_ver == 0x2050) {
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x005A, 0x0070);
+ }
+
+ b43_radio_write16(dev, 0x005B, 0x007B);
+ b43_radio_write16(dev, 0x005C, 0x00B0);
+
+ b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007);
+
+ b43_radio_selectchannel(dev, old_channel, 0);
+
+ b43_phy_write(dev, 0x0014, 0x0080);
+ b43_phy_write(dev, 0x0032, 0x00CA);
+ b43_phy_write(dev, 0x002A, 0x88A3);
+
+ b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
+
+ if (phy->radio_ver == 0x2050)
+ b43_radio_write16(dev, 0x005D, 0x000D);
+
+ b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004);
+}
+
+static void b43_phy_initb6(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 offset, val;
+ u8 old_channel;
+
+ b43_phy_write(dev, 0x003E, 0x817A);
+ b43_radio_write16(dev, 0x007A,
+ (b43_radio_read16(dev, 0x007A) | 0x0058));
+ if (phy->radio_rev == 4 || phy->radio_rev == 5) {
+ b43_radio_write16(dev, 0x51, 0x37);
+ b43_radio_write16(dev, 0x52, 0x70);
+ b43_radio_write16(dev, 0x53, 0xB3);
+ b43_radio_write16(dev, 0x54, 0x9B);
+ b43_radio_write16(dev, 0x5A, 0x88);
+ b43_radio_write16(dev, 0x5B, 0x88);
+ b43_radio_write16(dev, 0x5D, 0x88);
+ b43_radio_write16(dev, 0x5E, 0x88);
+ b43_radio_write16(dev, 0x7D, 0x88);
+ b43_hf_write(dev, b43_hf_read(dev)
+ | B43_HF_TSSIRPSMW);
+ }
+ B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7); /* We had code for these revs here... */
+ if (phy->radio_rev == 8) {
+ b43_radio_write16(dev, 0x51, 0);
+ b43_radio_write16(dev, 0x52, 0x40);
+ b43_radio_write16(dev, 0x53, 0xB7);
+ b43_radio_write16(dev, 0x54, 0x98);
+ b43_radio_write16(dev, 0x5A, 0x88);
+ b43_radio_write16(dev, 0x5B, 0x6B);
+ b43_radio_write16(dev, 0x5C, 0x0F);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_ALTIQ) {
+ b43_radio_write16(dev, 0x5D, 0xFA);
+ b43_radio_write16(dev, 0x5E, 0xD8);
+ } else {
+ b43_radio_write16(dev, 0x5D, 0xF5);
+ b43_radio_write16(dev, 0x5E, 0xB8);
+ }
+ b43_radio_write16(dev, 0x0073, 0x0003);
+ b43_radio_write16(dev, 0x007D, 0x00A8);
+ b43_radio_write16(dev, 0x007C, 0x0001);
+ b43_radio_write16(dev, 0x007E, 0x0008);
+ }
+ val = 0x1E1F;
+ for (offset = 0x0088; offset < 0x0098; offset++) {
+ b43_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ val = 0x3E3F;
+ for (offset = 0x0098; offset < 0x00A8; offset++) {
+ b43_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ val = 0x2120;
+ for (offset = 0x00A8; offset < 0x00C8; offset++) {
+ b43_phy_write(dev, offset, (val & 0x3F3F));
+ val += 0x0202;
+ }
+ if (phy->type == B43_PHYTYPE_G) {
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) | 0x0020);
+ b43_radio_write16(dev, 0x0051,
+ b43_radio_read16(dev, 0x0051) | 0x0004);
+ b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
+ b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
+ b43_phy_write(dev, 0x5B, 0);
+ b43_phy_write(dev, 0x5C, 0);
+ }
+
+ old_channel = phy->channel;
+ if (old_channel >= 8)
+ b43_radio_selectchannel(dev, 1, 0);
+ else
+ b43_radio_selectchannel(dev, 13, 0);
+
+ b43_radio_write16(dev, 0x0050, 0x0020);
+ b43_radio_write16(dev, 0x0050, 0x0023);
+ udelay(40);
+ if (phy->radio_rev < 6 || phy->radio_rev == 8) {
+ b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C)
+ | 0x0002));
+ b43_radio_write16(dev, 0x50, 0x20);
+ }
+ if (phy->radio_rev <= 2) {
+ b43_radio_write16(dev, 0x7C, 0x20);
+ b43_radio_write16(dev, 0x5A, 0x70);
+ b43_radio_write16(dev, 0x5B, 0x7B);
+ b43_radio_write16(dev, 0x5C, 0xB0);
+ }
+ b43_radio_write16(dev, 0x007A,
+ (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007);
+
+ b43_radio_selectchannel(dev, old_channel, 0);
+
+ b43_phy_write(dev, 0x0014, 0x0200);
+ if (phy->radio_rev >= 6)
+ b43_phy_write(dev, 0x2A, 0x88C2);
+ else
+ b43_phy_write(dev, 0x2A, 0x8AC0);
+ b43_phy_write(dev, 0x0038, 0x0668);
+ b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
+ if (phy->radio_rev <= 5) {
+ b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D)
+ & 0xFF80) | 0x0003);
+ }
+ if (phy->radio_rev <= 2)
+ b43_radio_write16(dev, 0x005D, 0x000D);
+
+ if (phy->analog == 4) {
+ b43_write16(dev, 0x3E4, 9);
+ b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61)
+ & 0x0FFF);
+ } else {
+ b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0)
+ | 0x0004);
+ }
+ if (phy->type == B43_PHYTYPE_B) {
+ b43_write16(dev, 0x03E6, 0x8140);
+ b43_phy_write(dev, 0x0016, 0x0410);
+ b43_phy_write(dev, 0x0017, 0x0820);
+ b43_phy_write(dev, 0x0062, 0x0007);
+ b43_radio_init2050(dev);
+ b43_lo_g_measure(dev);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+ b43_calc_nrssi_slope(dev);
+ b43_calc_nrssi_threshold(dev);
+ }
+ b43_phy_init_pctl(dev);
+ } else if (phy->type == B43_PHYTYPE_G)
+ b43_write16(dev, 0x03E6, 0x0);
+}
+
+static void b43_calc_loopback_gain(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 backup_phy[16] = { 0 };
+ u16 backup_radio[3];
+ u16 backup_bband;
+ u16 i, j, loop_i_max;
+ u16 trsw_rx;
+ u16 loop1_outer_done, loop1_inner_done;
+
+ backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0);
+ backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG);
+ backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER);
+ backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER);
+ backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
+ }
+ backup_phy[6] = b43_phy_read(dev, B43_PHY_BASE(0x5A));
+ backup_phy[7] = b43_phy_read(dev, B43_PHY_BASE(0x59));
+ backup_phy[8] = b43_phy_read(dev, B43_PHY_BASE(0x58));
+ backup_phy[9] = b43_phy_read(dev, B43_PHY_BASE(0x0A));
+ backup_phy[10] = b43_phy_read(dev, B43_PHY_BASE(0x03));
+ backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK);
+ backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL);
+ backup_phy[13] = b43_phy_read(dev, B43_PHY_BASE(0x2B));
+ backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL);
+ backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+ backup_bband = phy->bbatt.att;
+ backup_radio[0] = b43_radio_read16(dev, 0x52);
+ backup_radio[1] = b43_radio_read16(dev, 0x43);
+ backup_radio[2] = b43_radio_read16(dev, 0x7A);
+
+ b43_phy_write(dev, B43_PHY_CRS0,
+ b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF);
+ b43_phy_write(dev, B43_PHY_CCKBBANDCFG,
+ b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000);
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD);
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE);
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ b43_phy_write(dev, B43_PHY_ANALOGOVER,
+ b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ b43_phy_read(dev,
+ B43_PHY_ANALOGOVERVAL) & 0xFFFE);
+ b43_phy_write(dev, B43_PHY_ANALOGOVER,
+ b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ b43_phy_read(dev,
+ B43_PHY_ANALOGOVERVAL) & 0xFFFD);
+ }
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C);
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ (b43_phy_read(dev, B43_PHY_RFOVERVAL)
+ & 0xFFCF) | 0x10);
+
+ b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0780);
+ b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+
+ b43_phy_write(dev, B43_PHY_BASE(0x0A),
+ b43_phy_read(dev, B43_PHY_BASE(0x0A)) | 0x2000);
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ b43_phy_write(dev, B43_PHY_ANALOGOVER,
+ b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ b43_phy_read(dev,
+ B43_PHY_ANALOGOVERVAL) & 0xFFFB);
+ }
+ b43_phy_write(dev, B43_PHY_BASE(0x03),
+ (b43_phy_read(dev, B43_PHY_BASE(0x03))
+ & 0xFF9F) | 0x40);
+
+ if (phy->radio_rev == 8) {
+ b43_radio_write16(dev, 0x43, 0x000F);
+ } else {
+ b43_radio_write16(dev, 0x52, 0);
+ b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+ & 0xFFF0) | 0x9);
+ }
+ b43_phy_set_baseband_attenuation(dev, 11);
+
+ if (phy->rev >= 3)
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
+ else
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
+ b43_phy_write(dev, B43_PHY_LO_CTL, 0);
+
+ b43_phy_write(dev, B43_PHY_BASE(0x2B),
+ (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+ & 0xFFC0) | 0x01);
+ b43_phy_write(dev, B43_PHY_BASE(0x2B),
+ (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+ & 0xC0FF) | 0x800);
+
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF);
+
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) {
+ if (phy->rev >= 7) {
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ b43_phy_read(dev, B43_PHY_RFOVER)
+ | 0x0800);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ b43_phy_read(dev, B43_PHY_RFOVERVAL)
+ | 0x8000);
+ }
+ }
+ b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A)
+ & 0x00F7);
+
+ j = 0;
+ loop_i_max = (phy->radio_rev == 8) ? 15 : 9;
+ for (i = 0; i < loop_i_max; i++) {
+ for (j = 0; j < 16; j++) {
+ b43_radio_write16(dev, 0x43, i);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ (b43_phy_read(dev, B43_PHY_RFOVERVAL)
+ & 0xF0FF) | (j << 8));
+ b43_phy_write(dev, B43_PHY_PGACTL,
+ (b43_phy_read(dev, B43_PHY_PGACTL)
+ & 0x0FFF) | 0xA000);
+ b43_phy_write(dev, B43_PHY_PGACTL,
+ b43_phy_read(dev, B43_PHY_PGACTL)
+ | 0xF000);
+ udelay(20);
+ if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
+ goto exit_loop1;
+ }
+ }
+ exit_loop1:
+ loop1_outer_done = i;
+ loop1_inner_done = j;
+ if (j >= 8) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ b43_phy_read(dev, B43_PHY_RFOVERVAL)
+ | 0x30);
+ trsw_rx = 0x1B;
+ for (j = j - 8; j < 16; j++) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ (b43_phy_read(dev, B43_PHY_RFOVERVAL)
+ & 0xF0FF) | (j << 8));
+ b43_phy_write(dev, B43_PHY_PGACTL,
+ (b43_phy_read(dev, B43_PHY_PGACTL)
+ & 0x0FFF) | 0xA000);
+ b43_phy_write(dev, B43_PHY_PGACTL,
+ b43_phy_read(dev, B43_PHY_PGACTL)
+ | 0xF000);
+ udelay(20);
+ trsw_rx -= 3;
+ if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
+ goto exit_loop2;
+ }
+ } else
+ trsw_rx = 0x18;
+ exit_loop2:
+
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]);
+ }
+ b43_phy_write(dev, B43_PHY_BASE(0x5A), backup_phy[6]);
+ b43_phy_write(dev, B43_PHY_BASE(0x59), backup_phy[7]);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), backup_phy[8]);
+ b43_phy_write(dev, B43_PHY_BASE(0x0A), backup_phy[9]);
+ b43_phy_write(dev, B43_PHY_BASE(0x03), backup_phy[10]);
+ b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]);
+ b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]);
+ b43_phy_write(dev, B43_PHY_BASE(0x2B), backup_phy[13]);
+ b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]);
+
+ b43_phy_set_baseband_attenuation(dev, backup_bband);
+
+ b43_radio_write16(dev, 0x52, backup_radio[0]);
+ b43_radio_write16(dev, 0x43, backup_radio[1]);
+ b43_radio_write16(dev, 0x7A, backup_radio[2]);
+
+ b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003);
+ udelay(10);
+ b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]);
+ b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]);
+ b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]);
+
+ phy->max_lb_gain =
+ ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
+ phy->trsw_rx_gain = trsw_rx * 2;
+}
+
+static void b43_phy_initg(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 tmp;
+
+ if (phy->rev == 1)
+ b43_phy_initb5(dev);
+ else
+ b43_phy_initb6(dev);
+
+ if (phy->rev >= 2 || phy->gmode)
+ b43_phy_inita(dev);
+
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_ANALOGOVER, 0);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0);
+ }
+ if (phy->rev == 2) {
+ b43_phy_write(dev, B43_PHY_RFOVER, 0);
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
+ }
+ if (phy->rev > 5) {
+ b43_phy_write(dev, B43_PHY_RFOVER, 0x400);
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
+ }
+ if (phy->gmode || phy->rev >= 2) {
+ tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM);
+ tmp &= B43_PHYVER_VERSION;
+ if (tmp == 3 || tmp == 5) {
+ b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816);
+ b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006);
+ }
+ if (tmp == 5) {
+ b43_phy_write(dev, B43_PHY_OFDM(0xCC),
+ (b43_phy_read(dev, B43_PHY_OFDM(0xCC))
+ & 0x00FF) | 0x1F00);
+ }
+ }
+ if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
+ b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78);
+ if (phy->radio_rev == 8) {
+ b43_phy_write(dev, B43_PHY_EXTG(0x01),
+ b43_phy_read(dev, B43_PHY_EXTG(0x01))
+ | 0x80);
+ b43_phy_write(dev, B43_PHY_OFDM(0x3E),
+ b43_phy_read(dev, B43_PHY_OFDM(0x3E))
+ | 0x4);
+ }
+ if (has_loopback_gain(phy))
+ b43_calc_loopback_gain(dev);
+
+ if (phy->radio_rev != 8) {
+ if (phy->initval == 0xFFFF)
+ phy->initval = b43_radio_init2050(dev);
+ else
+ b43_radio_write16(dev, 0x0078, phy->initval);
+ }
+ if (phy->lo_control->tx_bias == 0xFF) {
+ b43_lo_g_measure(dev);
+ } else {
+ if (has_tx_magnification(phy)) {
+ b43_radio_write16(dev, 0x52,
+ (b43_radio_read16(dev, 0x52) & 0xFF00)
+ | phy->lo_control->tx_bias | phy->
+ lo_control->tx_magn);
+ } else {
+ b43_radio_write16(dev, 0x52,
+ (b43_radio_read16(dev, 0x52) & 0xFFF0)
+ | phy->lo_control->tx_bias);
+ }
+ if (phy->rev >= 6) {
+ b43_phy_write(dev, B43_PHY_BASE(0x36),
+ (b43_phy_read(dev, B43_PHY_BASE(0x36))
+ & 0x0FFF) | (phy->lo_control->
+ tx_bias << 12));
+ }
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL)
+ b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8075);
+ else
+ b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x807F);
+ if (phy->rev < 2)
+ b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x101);
+ else
+ b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x202);
+ }
+ if (phy->gmode || phy->rev >= 2) {
+ b43_lo_g_adjust(dev);
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
+ }
+
+ if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) {
+ /* The specs state to update the NRSSI LT with
+ * the value 0x7FFFFFFF here. I think that is some weird
+ * compiler optimization in the original driver.
+ * Essentially, what we do here is resetting all NRSSI LT
+ * entries to -32 (see the limit_value() in nrssi_hw_update())
+ */
+ b43_nrssi_hw_update(dev, 0xFFFF); //FIXME?
+ b43_calc_nrssi_threshold(dev);
+ } else if (phy->gmode || phy->rev >= 2) {
+ if (phy->nrssi[0] == -1000) {
+ B43_WARN_ON(phy->nrssi[1] != -1000);
+ b43_calc_nrssi_slope(dev);
+ } else
+ b43_calc_nrssi_threshold(dev);
+ }
+ if (phy->radio_rev == 8)
+ b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230);
+ b43_phy_init_pctl(dev);
+ /* FIXME: The spec says in the following if, the 0 should be replaced
+ 'if OFDM may not be used in the current locale'
+ but OFDM is legal everywhere */
+ if ((dev->dev->bus->chip_id == 0x4306
+ && dev->dev->bus->chip_package == 2) || 0) {
+ b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
+ & 0xBFFF);
+ b43_phy_write(dev, B43_PHY_OFDM(0xC3),
+ b43_phy_read(dev, B43_PHY_OFDM(0xC3))
+ & 0x7FFF);
+ }
+}
+
+/* Set the baseband attenuation value on chip. */
+void b43_phy_set_baseband_attenuation(struct b43_wldev *dev,
+ u16 baseband_attenuation)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (phy->analog == 0) {
+ b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0)
+ & 0xFFF0) |
+ baseband_attenuation);
+ } else if (phy->analog > 1) {
+ b43_phy_write(dev, B43_PHY_DACCTL,
+ (b43_phy_read(dev, B43_PHY_DACCTL)
+ & 0xFFC3) | (baseband_attenuation << 2));
+ } else {
+ b43_phy_write(dev, B43_PHY_DACCTL,
+ (b43_phy_read(dev, B43_PHY_DACCTL)
+ & 0xFF87) | (baseband_attenuation << 3));
+ }
+}
+
+/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
+ * This function converts a TSSI value to dBm in Q5.2
+ */
+static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
+{
+ struct b43_phy *phy = &dev->phy;
+ s8 dbm = 0;
+ s32 tmp;
+
+ tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi);
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ tmp += 0x80;
+ tmp = limit_value(tmp, 0x00, 0xFF);
+ dbm = phy->tssi2dbm[tmp];
+ //TODO: There's a FIXME on the specs
+ break;
+ case B43_PHYTYPE_B:
+ case B43_PHYTYPE_G:
+ tmp = limit_value(tmp, 0x00, 0x3F);
+ dbm = phy->tssi2dbm[tmp];
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+
+ return dbm;
+}
+
+void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
+ int *_bbatt, int *_rfatt)
+{
+ int rfatt = *_rfatt;
+ int bbatt = *_bbatt;
+ struct b43_txpower_lo_control *lo = dev->phy.lo_control;
+
+ /* Get baseband and radio attenuation values into their permitted ranges.
+ * Radio attenuation affects power level 4 times as much as baseband. */
+
+ /* Range constants */
+ const int rf_min = lo->rfatt_list.min_val;
+ const int rf_max = lo->rfatt_list.max_val;
+ const int bb_min = lo->bbatt_list.min_val;
+ const int bb_max = lo->bbatt_list.max_val;
+
+ while (1) {
+ if (rfatt > rf_max && bbatt > bb_max - 4)
+ break; /* Can not get it into ranges */
+ if (rfatt < rf_min && bbatt < bb_min + 4)
+ break; /* Can not get it into ranges */
+ if (bbatt > bb_max && rfatt > rf_max - 1)
+ break; /* Can not get it into ranges */
+ if (bbatt < bb_min && rfatt < rf_min + 1)
+ break; /* Can not get it into ranges */
+
+ if (bbatt > bb_max) {
+ bbatt -= 4;
+ rfatt += 1;
+ continue;
+ }
+ if (bbatt < bb_min) {
+ bbatt += 4;
+ rfatt -= 1;
+ continue;
+ }
+ if (rfatt > rf_max) {
+ rfatt -= 1;
+ bbatt += 4;
+ continue;
+ }
+ if (rfatt < rf_min) {
+ rfatt += 1;
+ bbatt -= 4;
+ continue;
+ }
+ break;
+ }
+
+ *_rfatt = limit_value(rfatt, rf_min, rf_max);
+ *_bbatt = limit_value(bbatt, bb_min, bb_max);
+}
+
+/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
+void b43_phy_xmitpower(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43_phy *phy = &dev->phy;
+
+ if (phy->cur_idle_tssi == 0)
+ return;
+ if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+ (bus->boardinfo.type == SSB_BOARD_BU4306))
+ return;
+#ifdef CONFIG_B43_DEBUG
+ if (phy->manual_txpower_control)
+ return;
+#endif
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:{
+
+ //TODO: Nothing for A PHYs yet :-/
+
+ break;
+ }
+ case B43_PHYTYPE_B:
+ case B43_PHYTYPE_G:{
+ u16 tmp;
+ s8 v0, v1, v2, v3;
+ s8 average;
+ int max_pwr;
+ int desired_pwr, estimated_pwr, pwr_adjust;
+ int rfatt_delta, bbatt_delta;
+ int rfatt, bbatt;
+ u8 tx_control;
+ unsigned long phylock_flags;
+
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058);
+ v0 = (s8) (tmp & 0x00FF);
+ v1 = (s8) ((tmp & 0xFF00) >> 8);
+ tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A);
+ v2 = (s8) (tmp & 0x00FF);
+ v3 = (s8) ((tmp & 0xFF00) >> 8);
+ tmp = 0;
+
+ if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
+ || v3 == 0x7F) {
+ tmp =
+ b43_shm_read16(dev, B43_SHM_SHARED, 0x0070);
+ v0 = (s8) (tmp & 0x00FF);
+ v1 = (s8) ((tmp & 0xFF00) >> 8);
+ tmp =
+ b43_shm_read16(dev, B43_SHM_SHARED, 0x0072);
+ v2 = (s8) (tmp & 0x00FF);
+ v3 = (s8) ((tmp & 0xFF00) >> 8);
+ if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
+ || v3 == 0x7F)
+ return;
+ v0 = (v0 + 0x20) & 0x3F;
+ v1 = (v1 + 0x20) & 0x3F;
+ v2 = (v2 + 0x20) & 0x3F;
+ v3 = (v3 + 0x20) & 0x3F;
+ tmp = 1;
+ }
+ b43_shm_clear_tssi(dev);
+
+ average = (v0 + v1 + v2 + v3 + 2) / 4;
+
+ if (tmp
+ && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) &
+ 0x8))
+ average -= 13;
+
+ estimated_pwr =
+ b43_phy_estimate_power_out(dev, average);
+
+ max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
+ if ((dev->dev->bus->sprom.r1.
+ boardflags_lo & B43_BFL_PACTRL)
+ && (phy->type == B43_PHYTYPE_G))
+ max_pwr -= 0x3;
+ if (unlikely(max_pwr <= 0)) {
+ b43warn(dev->wl,
+ "Invalid max-TX-power value in SPROM.\n");
+ max_pwr = 60; /* fake it */
+ dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr;
+ }
+
+ /*TODO:
+ max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr)
+ where REG is the max power as per the regulatory domain
+ */
+
+ /* Get desired power (in Q5.2) */
+ desired_pwr = INT_TO_Q52(phy->power_level);
+ /* And limit it. max_pwr already is Q5.2 */
+ desired_pwr = limit_value(desired_pwr, 0, max_pwr);
+ if (b43_debug(dev, B43_DBG_XMITPOWER)) {
+ b43dbg(dev->wl,
+ "Current TX power output: " Q52_FMT
+ " dBm, " "Desired TX power output: "
+ Q52_FMT " dBm\n", Q52_ARG(estimated_pwr),
+ Q52_ARG(desired_pwr));
+ }
+
+ /* Calculate the adjustment delta. */
+ pwr_adjust = desired_pwr - estimated_pwr;
+
+ /* RF attenuation delta. */
+ rfatt_delta = ((pwr_adjust + 7) / 8);
+ /* Lower attenuation => Bigger power output. Negate it. */
+ rfatt_delta = -rfatt_delta;
+
+ /* Baseband attenuation delta. */
+ bbatt_delta = pwr_adjust / 2;
+ /* Lower attenuation => Bigger power output. Negate it. */
+ bbatt_delta = -bbatt_delta;
+ /* RF att affects power level 4 times as much as
+ * Baseband attennuation. Subtract it. */
+ bbatt_delta -= 4 * rfatt_delta;
+
+ /* So do we finally need to adjust something? */
+ if ((rfatt_delta == 0) && (bbatt_delta == 0)) {
+ b43_lo_g_ctl_mark_cur_used(dev);
+ return;
+ }
+
+ /* Calculate the new attenuation values. */
+ bbatt = phy->bbatt.att;
+ bbatt += bbatt_delta;
+ rfatt = phy->rfatt.att;
+ rfatt += rfatt_delta;
+
+ b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
+ tx_control = phy->tx_control;
+ if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
+ if (rfatt <= 1) {
+ if (tx_control == 0) {
+ tx_control =
+ B43_TXCTL_PA2DB |
+ B43_TXCTL_TXMIX;
+ rfatt += 2;
+ bbatt += 2;
+ } else if (dev->dev->bus->sprom.r1.
+ boardflags_lo &
+ B43_BFL_PACTRL) {
+ bbatt += 4 * (rfatt - 2);
+ rfatt = 2;
+ }
+ } else if (rfatt > 4 && tx_control) {
+ tx_control = 0;
+ if (bbatt < 3) {
+ rfatt -= 3;
+ bbatt += 2;
+ } else {
+ rfatt -= 2;
+ bbatt -= 2;
+ }
+ }
+ }
+ /* Save the control values */
+ phy->tx_control = tx_control;
+ b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
+ phy->rfatt.att = rfatt;
+ phy->bbatt.att = bbatt;
+
+ /* Adjust the hardware */
+ b43_phy_lock(dev, phylock_flags);
+ b43_radio_lock(dev);
+ b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
+ phy->tx_control);
+ b43_lo_g_ctl_mark_cur_used(dev);
+ b43_radio_unlock(dev);
+ b43_phy_unlock(dev, phylock_flags);
+ break;
+ }
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+static inline s32 b43_tssi2dbm_ad(s32 num, s32 den)
+{
+ if (num < 0)
+ return num / den;
+ else
+ return (num + den / 2) / den;
+}
+
+static inline
+ s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2)
+{
+ s32 m1, m2, f = 256, q, delta;
+ s8 i = 0;
+
+ m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
+ m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1);
+ do {
+ if (i > 15)
+ return -EINVAL;
+ q = b43_tssi2dbm_ad(f * 4096 -
+ b43_tssi2dbm_ad(m2 * f, 16) * f, 2048);
+ delta = abs(q - f);
+ f = q;
+ i++;
+ } while (delta >= 2);
+ entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
+ return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
+int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ s16 pab0, pab1, pab2;
+ u8 idx;
+ s8 *dyn_tssi2dbm;
+
+ if (phy->type == B43_PHYTYPE_A) {
+ pab0 = (s16) (dev->dev->bus->sprom.r1.pa1b0);
+ pab1 = (s16) (dev->dev->bus->sprom.r1.pa1b1);
+ pab2 = (s16) (dev->dev->bus->sprom.r1.pa1b2);
+ } else {
+ pab0 = (s16) (dev->dev->bus->sprom.r1.pa0b0);
+ pab1 = (s16) (dev->dev->bus->sprom.r1.pa0b1);
+ pab2 = (s16) (dev->dev->bus->sprom.r1.pa0b2);
+ }
+
+ if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
+ phy->tgt_idle_tssi = 0x34;
+ phy->tssi2dbm = b43_tssi2dbm_b_table;
+ return 0;
+ }
+
+ if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
+ pab0 != -1 && pab1 != -1 && pab2 != -1) {
+ /* The pabX values are set in SPROM. Use them. */
+ if (phy->type == B43_PHYTYPE_A) {
+ if ((s8) dev->dev->bus->sprom.r1.itssi_a != 0 &&
+ (s8) dev->dev->bus->sprom.r1.itssi_a != -1)
+ phy->tgt_idle_tssi =
+ (s8) (dev->dev->bus->sprom.r1.itssi_a);
+ else
+ phy->tgt_idle_tssi = 62;
+ } else {
+ if ((s8) dev->dev->bus->sprom.r1.itssi_bg != 0 &&
+ (s8) dev->dev->bus->sprom.r1.itssi_bg != -1)
+ phy->tgt_idle_tssi =
+ (s8) (dev->dev->bus->sprom.r1.itssi_bg);
+ else
+ phy->tgt_idle_tssi = 62;
+ }
+ dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
+ if (dyn_tssi2dbm == NULL) {
+ b43err(dev->wl, "Could not allocate memory"
+ "for tssi2dbm table\n");
+ return -ENOMEM;
+ }
+ for (idx = 0; idx < 64; idx++)
+ if (b43_tssi2dbm_entry
+ (dyn_tssi2dbm, idx, pab0, pab1, pab2)) {
+ phy->tssi2dbm = NULL;
+ b43err(dev->wl, "Could not generate "
+ "tssi2dBm table\n");
+ kfree(dyn_tssi2dbm);
+ return -ENODEV;
+ }
+ phy->tssi2dbm = dyn_tssi2dbm;
+ phy->dyn_tssi_tbl = 1;
+ } else {
+ /* pabX values not set in SPROM. */
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ /* APHY needs a generated table. */
+ phy->tssi2dbm = NULL;
+ b43err(dev->wl, "Could not generate tssi2dBm "
+ "table (wrong SPROM info)!\n");
+ return -ENODEV;
+ case B43_PHYTYPE_B:
+ phy->tgt_idle_tssi = 0x34;
+ phy->tssi2dbm = b43_tssi2dbm_b_table;
+ break;
+ case B43_PHYTYPE_G:
+ phy->tgt_idle_tssi = 0x34;
+ phy->tssi2dbm = b43_tssi2dbm_g_table;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int b43_phy_init(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ int err = -ENODEV;
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ if (phy->rev == 2 || phy->rev == 3) {
+ b43_phy_inita(dev);
+ err = 0;
+ }
+ break;
+ case B43_PHYTYPE_B:
+ switch (phy->rev) {
+ case 2:
+ b43_phy_initb2(dev);
+ err = 0;
+ break;
+ case 4:
+ b43_phy_initb4(dev);
+ err = 0;
+ break;
+ case 5:
+ b43_phy_initb5(dev);
+ err = 0;
+ break;
+ case 6:
+ b43_phy_initb6(dev);
+ err = 0;
+ break;
+ }
+ break;
+ case B43_PHYTYPE_G:
+ b43_phy_initg(dev);
+ err = 0;
+ break;
+ }
+ if (err)
+ b43err(dev->wl, "Unknown PHYTYPE found\n");
+
+ return err;
+}
+
+void b43_set_rx_antenna(struct b43_wldev *dev, int antenna)
+{
+ struct b43_phy *phy = &dev->phy;
+ u32 hf;
+ u16 tmp;
+ int autodiv = 0;
+
+ if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1)
+ autodiv = 1;
+
+ hf = b43_hf_read(dev);
+ hf &= ~B43_HF_ANTDIVHELP;
+ b43_hf_write(dev, hf);
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ case B43_PHYTYPE_G:
+ tmp = b43_phy_read(dev, B43_PHY_BBANDCFG);
+ tmp &= ~B43_PHY_BBANDCFG_RXANT;
+ tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
+ << B43_PHY_BBANDCFG_RXANT_SHIFT;
+ b43_phy_write(dev, B43_PHY_BBANDCFG, tmp);
+
+ if (autodiv) {
+ tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
+ if (antenna == B43_ANTENNA_AUTO0)
+ tmp &= ~B43_PHY_ANTDWELL_AUTODIV1;
+ else
+ tmp |= B43_PHY_ANTDWELL_AUTODIV1;
+ b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
+ }
+ if (phy->type == B43_PHYTYPE_G) {
+ tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT);
+ if (autodiv)
+ tmp |= B43_PHY_ANTWRSETT_ARXDIV;
+ else
+ tmp &= ~B43_PHY_ANTWRSETT_ARXDIV;
+ b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp);
+ if (phy->rev >= 2) {
+ tmp = b43_phy_read(dev, B43_PHY_OFDM61);
+ tmp |= B43_PHY_OFDM61_10;
+ b43_phy_write(dev, B43_PHY_OFDM61, tmp);
+
+ tmp =
+ b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK);
+ tmp = (tmp & 0xFF00) | 0x15;
+ b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK,
+ tmp);
+
+ if (phy->rev == 2) {
+ b43_phy_write(dev, B43_PHY_ADIVRELATED,
+ 8);
+ } else {
+ tmp =
+ b43_phy_read(dev,
+ B43_PHY_ADIVRELATED);
+ tmp = (tmp & 0xFF00) | 8;
+ b43_phy_write(dev, B43_PHY_ADIVRELATED,
+ tmp);
+ }
+ }
+ if (phy->rev >= 6)
+ b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC);
+ } else {
+ if (phy->rev < 3) {
+ tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
+ tmp = (tmp & 0xFF00) | 0x24;
+ b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
+ } else {
+ tmp = b43_phy_read(dev, B43_PHY_OFDM61);
+ tmp |= 0x10;
+ b43_phy_write(dev, B43_PHY_OFDM61, tmp);
+ if (phy->analog == 3) {
+ b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
+ 0x1D);
+ b43_phy_write(dev, B43_PHY_ADIVRELATED,
+ 8);
+ } else {
+ b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
+ 0x3A);
+ tmp =
+ b43_phy_read(dev,
+ B43_PHY_ADIVRELATED);
+ tmp = (tmp & 0xFF00) | 8;
+ b43_phy_write(dev, B43_PHY_ADIVRELATED,
+ tmp);
+ }
+ }
+ }
+ break;
+ case B43_PHYTYPE_B:
+ tmp = b43_phy_read(dev, B43_PHY_CCKBBANDCFG);
+ tmp &= ~B43_PHY_BBANDCFG_RXANT;
+ tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
+ << B43_PHY_BBANDCFG_RXANT_SHIFT;
+ b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+
+ hf |= B43_HF_ANTDIVHELP;
+ b43_hf_write(dev, hf);
+}
+
+/* Get the freq, as it has to be written to the device. */
+static inline u16 channel2freq_bg(u8 channel)
+{
+ B43_WARN_ON(!(channel >= 1 && channel <= 14));
+
+ return b43_radio_channel_codes_bg[channel - 1];
+}
+
+/* Get the freq, as it has to be written to the device. */
+static inline u16 channel2freq_a(u8 channel)
+{
+ B43_WARN_ON(channel > 200);
+
+ return (5000 + 5 * channel);
+}
+
+void b43_radio_lock(struct b43_wldev *dev)
+{
+ u32 macctl;
+
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ macctl |= B43_MACCTL_RADIOLOCK;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+ /* Commit the write and wait for the device
+ * to exit any radio register access. */
+ b43_read32(dev, B43_MMIO_MACCTL);
+ udelay(10);
+}
+
+void b43_radio_unlock(struct b43_wldev *dev)
+{
+ u32 macctl;
+
+ /* Commit any write */
+ b43_read16(dev, B43_MMIO_PHY_VER);
+ /* unlock */
+ macctl = b43_read32(dev, B43_MMIO_MACCTL);
+ macctl &= ~B43_MACCTL_RADIOLOCK;
+ b43_write32(dev, B43_MMIO_MACCTL, macctl);
+}
+
+u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ offset |= 0x0040;
+ break;
+ case B43_PHYTYPE_B:
+ if (phy->radio_ver == 0x2053) {
+ if (offset < 0x70)
+ offset += 0x80;
+ else if (offset < 0x80)
+ offset += 0x70;
+ } else if (phy->radio_ver == 0x2050) {
+ offset |= 0x80;
+ } else
+ B43_WARN_ON(1);
+ break;
+ case B43_PHYTYPE_G:
+ offset |= 0x80;
+ break;
+ }
+
+ b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
+ return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+}
+
+void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val)
+{
+ b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
+ mmiowb();
+ b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val);
+}
+
+static void b43_set_all_gains(struct b43_wldev *dev,
+ s16 first, s16 second, s16 third)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 i;
+ u16 start = 0x08, end = 0x18;
+ u16 tmp;
+ u16 table;
+
+ if (phy->rev <= 1) {
+ start = 0x10;
+ end = 0x20;
+ }
+
+ table = B43_OFDMTAB_GAINX;
+ if (phy->rev <= 1)
+ table = B43_OFDMTAB_GAINX_R1;
+ for (i = 0; i < 4; i++)
+ b43_ofdmtab_write16(dev, table, i, first);
+
+ for (i = start; i < end; i++)
+ b43_ofdmtab_write16(dev, table, i, second);
+
+ if (third != -1) {
+ tmp = ((u16) third << 14) | ((u16) third << 6);
+ b43_phy_write(dev, 0x04A0,
+ (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp);
+ b43_phy_write(dev, 0x04A1,
+ (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp);
+ b43_phy_write(dev, 0x04A2,
+ (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp);
+ }
+ b43_dummy_transmission(dev);
+}
+
+static void b43_set_original_gains(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 i, tmp;
+ u16 table;
+ u16 start = 0x0008, end = 0x0018;
+
+ if (phy->rev <= 1) {
+ start = 0x0010;
+ end = 0x0020;
+ }
+
+ table = B43_OFDMTAB_GAINX;
+ if (phy->rev <= 1)
+ table = B43_OFDMTAB_GAINX_R1;
+ for (i = 0; i < 4; i++) {
+ tmp = (i & 0xFFFC);
+ tmp |= (i & 0x0001) << 1;
+ tmp |= (i & 0x0002) >> 1;
+
+ b43_ofdmtab_write16(dev, table, i, tmp);
+ }
+
+ for (i = start; i < end; i++)
+ b43_ofdmtab_write16(dev, table, i, i - start);
+
+ b43_phy_write(dev, 0x04A0,
+ (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040);
+ b43_phy_write(dev, 0x04A1,
+ (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040);
+ b43_phy_write(dev, 0x04A2,
+ (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000);
+ b43_dummy_transmission(dev);
+}
+
+/* Synthetic PU workaround */
+static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ might_sleep();
+
+ if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) {
+ /* We do not need the workaround. */
+ return;
+ }
+
+ if (channel <= 10) {
+ b43_write16(dev, B43_MMIO_CHANNEL,
+ channel2freq_bg(channel + 4));
+ } else {
+ b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1));
+ }
+ msleep(1);
+ b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
+}
+
+u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel)
+{
+ struct b43_phy *phy = &dev->phy;
+ u8 ret = 0;
+ u16 saved, rssi, temp;
+ int i, j = 0;
+
+ saved = b43_phy_read(dev, 0x0403);
+ b43_radio_selectchannel(dev, channel, 0);
+ b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
+ if (phy->aci_hw_rssi)
+ rssi = b43_phy_read(dev, 0x048A) & 0x3F;
+ else
+ rssi = saved & 0x3F;
+ /* clamp temp to signed 5bit */
+ if (rssi > 32)
+ rssi -= 64;
+ for (i = 0; i < 100; i++) {
+ temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F;
+ if (temp > 32)
+ temp -= 64;
+ if (temp < rssi)
+ j++;
+ if (j >= 20)
+ ret = 1;
+ }
+ b43_phy_write(dev, 0x0403, saved);
+
+ return ret;
+}
+
+u8 b43_radio_aci_scan(struct b43_wldev * dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u8 ret[13];
+ unsigned int channel = phy->channel;
+ unsigned int i, j, start, end;
+ unsigned long phylock_flags;
+
+ if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0)))
+ return 0;
+
+ b43_phy_lock(dev, phylock_flags);
+ b43_radio_lock(dev);
+ b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
+ b43_set_all_gains(dev, 3, 8, 1);
+
+ start = (channel - 5 > 0) ? channel - 5 : 1;
+ end = (channel + 5 < 14) ? channel + 5 : 13;
+
+ for (i = start; i <= end; i++) {
+ if (abs(channel - i) > 2)
+ ret[i - 1] = b43_radio_aci_detect(dev, i);
+ }
+ b43_radio_selectchannel(dev, channel, 0);
+ b43_phy_write(dev, 0x0802,
+ (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003);
+ b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
+ b43_set_original_gains(dev);
+ for (i = 0; i < 13; i++) {
+ if (!ret[i])
+ continue;
+ end = (i + 5 < 13) ? i + 5 : 13;
+ for (j = i; j < end; j++)
+ ret[j] = 1;
+ }
+ b43_radio_unlock(dev);
+ b43_phy_unlock(dev, phylock_flags);
+
+ return ret[channel - 1];
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val)
+{
+ b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
+ mmiowb();
+ b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val);
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset)
+{
+ u16 val;
+
+ b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
+ val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA);
+
+ return (s16) val;
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
+{
+ u16 i;
+ s16 tmp;
+
+ for (i = 0; i < 64; i++) {
+ tmp = b43_nrssi_hw_read(dev, i);
+ tmp -= val;
+ tmp = limit_value(tmp, -32, 31);
+ b43_nrssi_hw_write(dev, i, tmp);
+ }
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43_nrssi_mem_update(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ s16 i, delta;
+ s32 tmp;
+
+ delta = 0x1F - phy->nrssi[0];
+ for (i = 0; i < 64; i++) {
+ tmp = (i - delta) * phy->nrssislope;
+ tmp /= 0x10000;
+ tmp += 0x3A;
+ tmp = limit_value(tmp, 0, 0x3F);
+ phy->nrssi_lt[i] = tmp;
+ }
+}
+
+static void b43_calc_nrssi_offset(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 backup[20] = { 0 };
+ s16 v47F;
+ u16 i;
+ u16 saved = 0xFFFF;
+
+ backup[0] = b43_phy_read(dev, 0x0001);
+ backup[1] = b43_phy_read(dev, 0x0811);
+ backup[2] = b43_phy_read(dev, 0x0812);
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ backup[3] = b43_phy_read(dev, 0x0814);
+ backup[4] = b43_phy_read(dev, 0x0815);
+ }
+ backup[5] = b43_phy_read(dev, 0x005A);
+ backup[6] = b43_phy_read(dev, 0x0059);
+ backup[7] = b43_phy_read(dev, 0x0058);
+ backup[8] = b43_phy_read(dev, 0x000A);
+ backup[9] = b43_phy_read(dev, 0x0003);
+ backup[10] = b43_radio_read16(dev, 0x007A);
+ backup[11] = b43_radio_read16(dev, 0x0043);
+
+ b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF);
+ b43_phy_write(dev, 0x0001,
+ (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000);
+ b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
+ b43_phy_write(dev, 0x0812,
+ (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004);
+ b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
+ if (phy->rev >= 6) {
+ backup[12] = b43_phy_read(dev, 0x002E);
+ backup[13] = b43_phy_read(dev, 0x002F);
+ backup[14] = b43_phy_read(dev, 0x080F);
+ backup[15] = b43_phy_read(dev, 0x0810);
+ backup[16] = b43_phy_read(dev, 0x0801);
+ backup[17] = b43_phy_read(dev, 0x0060);
+ backup[18] = b43_phy_read(dev, 0x0014);
+ backup[19] = b43_phy_read(dev, 0x0478);
+
+ b43_phy_write(dev, 0x002E, 0);
+ b43_phy_write(dev, 0x002F, 0);
+ b43_phy_write(dev, 0x080F, 0);
+ b43_phy_write(dev, 0x0810, 0);
+ b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100);
+ b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040);
+ b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040);
+ b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200);
+ }
+ b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070);
+ b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080);
+ udelay(30);
+
+ v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F == 31) {
+ for (i = 7; i >= 4; i--) {
+ b43_radio_write16(dev, 0x007B, i);
+ udelay(20);
+ v47F =
+ (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F < 31 && saved == 0xFFFF)
+ saved = i;
+ }
+ if (saved == 0xFFFF)
+ saved = 4;
+ } else {
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) & 0x007F);
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ b43_phy_write(dev, 0x0814,
+ b43_phy_read(dev, 0x0814) | 0x0001);
+ b43_phy_write(dev, 0x0815,
+ b43_phy_read(dev, 0x0815) & 0xFFFE);
+ }
+ b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
+ b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C);
+ b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030);
+ b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030);
+ b43_phy_write(dev, 0x005A, 0x0480);
+ b43_phy_write(dev, 0x0059, 0x0810);
+ b43_phy_write(dev, 0x0058, 0x000D);
+ if (phy->rev == 0) {
+ b43_phy_write(dev, 0x0003, 0x0122);
+ } else {
+ b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A)
+ | 0x2000);
+ }
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ b43_phy_write(dev, 0x0814,
+ b43_phy_read(dev, 0x0814) | 0x0004);
+ b43_phy_write(dev, 0x0815,
+ b43_phy_read(dev, 0x0815) & 0xFFFB);
+ }
+ b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F)
+ | 0x0040);
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) | 0x000F);
+ b43_set_all_gains(dev, 3, 0, 1);
+ b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043)
+ & 0x00F0) | 0x000F);
+ udelay(30);
+ v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F == -32) {
+ for (i = 0; i < 4; i++) {
+ b43_radio_write16(dev, 0x007B, i);
+ udelay(20);
+ v47F =
+ (s16) ((b43_phy_read(dev, 0x047F) >> 8) &
+ 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F > -31 && saved == 0xFFFF)
+ saved = i;
+ }
+ if (saved == 0xFFFF)
+ saved = 3;
+ } else
+ saved = 0;
+ }
+ b43_radio_write16(dev, 0x007B, saved);
+
+ if (phy->rev >= 6) {
+ b43_phy_write(dev, 0x002E, backup[12]);
+ b43_phy_write(dev, 0x002F, backup[13]);
+ b43_phy_write(dev, 0x080F, backup[14]);
+ b43_phy_write(dev, 0x0810, backup[15]);
+ }
+ if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */
+ b43_phy_write(dev, 0x0814, backup[3]);
+ b43_phy_write(dev, 0x0815, backup[4]);
+ }
+ b43_phy_write(dev, 0x005A, backup[5]);
+ b43_phy_write(dev, 0x0059, backup[6]);
+ b43_phy_write(dev, 0x0058, backup[7]);
+ b43_phy_write(dev, 0x000A, backup[8]);
+ b43_phy_write(dev, 0x0003, backup[9]);
+ b43_radio_write16(dev, 0x0043, backup[11]);
+ b43_radio_write16(dev, 0x007A, backup[10]);
+ b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2);
+ b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000);
+ b43_set_original_gains(dev);
+ if (phy->rev >= 6) {
+ b43_phy_write(dev, 0x0801, backup[16]);
+ b43_phy_write(dev, 0x0060, backup[17]);
+ b43_phy_write(dev, 0x0014, backup[18]);
+ b43_phy_write(dev, 0x0478, backup[19]);
+ }
+ b43_phy_write(dev, 0x0001, backup[0]);
+ b43_phy_write(dev, 0x0812, backup[2]);
+ b43_phy_write(dev, 0x0811, backup[1]);
+}
+
+void b43_calc_nrssi_slope(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 backup[18] = { 0 };
+ u16 tmp;
+ s16 nrssi0, nrssi1;
+
+ switch (phy->type) {
+ case B43_PHYTYPE_B:
+ backup[0] = b43_radio_read16(dev, 0x007A);
+ backup[1] = b43_radio_read16(dev, 0x0052);
+ backup[2] = b43_radio_read16(dev, 0x0043);
+ backup[3] = b43_phy_read(dev, 0x0030);
+ backup[4] = b43_phy_read(dev, 0x0026);
+ backup[5] = b43_phy_read(dev, 0x0015);
+ backup[6] = b43_phy_read(dev, 0x002A);
+ backup[7] = b43_phy_read(dev, 0x0020);
+ backup[8] = b43_phy_read(dev, 0x005A);
+ backup[9] = b43_phy_read(dev, 0x0059);
+ backup[10] = b43_phy_read(dev, 0x0058);
+ backup[11] = b43_read16(dev, 0x03E2);
+ backup[12] = b43_read16(dev, 0x03E6);
+ backup[13] = b43_read16(dev, B43_MMIO_CHANNEL_EXT);
+
+ tmp = b43_radio_read16(dev, 0x007A);
+ tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
+ b43_radio_write16(dev, 0x007A, tmp);
+ b43_phy_write(dev, 0x0030, 0x00FF);
+ b43_write16(dev, 0x03EC, 0x7F7F);
+ b43_phy_write(dev, 0x0026, 0x0000);
+ b43_phy_write(dev, 0x0015, b43_phy_read(dev, 0x0015) | 0x0020);
+ b43_phy_write(dev, 0x002A, 0x08A3);
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) | 0x0080);
+
+ nrssi0 = (s16) b43_phy_read(dev, 0x0027);
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) & 0x007F);
+ if (phy->rev >= 2) {
+ b43_write16(dev, 0x03E6, 0x0040);
+ } else if (phy->rev == 0) {
+ b43_write16(dev, 0x03E6, 0x0122);
+ } else {
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+ b43_read16(dev,
+ B43_MMIO_CHANNEL_EXT) & 0x2000);
+ }
+ b43_phy_write(dev, 0x0020, 0x3F3F);
+ b43_phy_write(dev, 0x0015, 0xF330);
+ b43_radio_write16(dev, 0x005A, 0x0060);
+ b43_radio_write16(dev, 0x0043,
+ b43_radio_read16(dev, 0x0043) & 0x00F0);
+ b43_phy_write(dev, 0x005A, 0x0480);
+ b43_phy_write(dev, 0x0059, 0x0810);
+ b43_phy_write(dev, 0x0058, 0x000D);
+ udelay(20);
+
+ nrssi1 = (s16) b43_phy_read(dev, 0x0027);
+ b43_phy_write(dev, 0x0030, backup[3]);
+ b43_radio_write16(dev, 0x007A, backup[0]);
+ b43_write16(dev, 0x03E2, backup[11]);
+ b43_phy_write(dev, 0x0026, backup[4]);
+ b43_phy_write(dev, 0x0015, backup[5]);
+ b43_phy_write(dev, 0x002A, backup[6]);
+ b43_synth_pu_workaround(dev, phy->channel);
+ if (phy->rev != 0)
+ b43_write16(dev, 0x03F4, backup[13]);
+
+ b43_phy_write(dev, 0x0020, backup[7]);
+ b43_phy_write(dev, 0x005A, backup[8]);
+ b43_phy_write(dev, 0x0059, backup[9]);
+ b43_phy_write(dev, 0x0058, backup[10]);
+ b43_radio_write16(dev, 0x0052, backup[1]);
+ b43_radio_write16(dev, 0x0043, backup[2]);
+
+ if (nrssi0 == nrssi1)
+ phy->nrssislope = 0x00010000;
+ else
+ phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+
+ if (nrssi0 <= -4) {
+ phy->nrssi[0] = nrssi0;
+ phy->nrssi[1] = nrssi1;
+ }
+ break;
+ case B43_PHYTYPE_G:
+ if (phy->radio_rev >= 9)
+ return;
+ if (phy->radio_rev == 8)
+ b43_calc_nrssi_offset(dev);
+
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
+ b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
+ backup[7] = b43_read16(dev, 0x03E2);
+ b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000);
+ backup[0] = b43_radio_read16(dev, 0x007A);
+ backup[1] = b43_radio_read16(dev, 0x0052);
+ backup[2] = b43_radio_read16(dev, 0x0043);
+ backup[3] = b43_phy_read(dev, 0x0015);
+ backup[4] = b43_phy_read(dev, 0x005A);
+ backup[5] = b43_phy_read(dev, 0x0059);
+ backup[6] = b43_phy_read(dev, 0x0058);
+ backup[8] = b43_read16(dev, 0x03E6);
+ backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT);
+ if (phy->rev >= 3) {
+ backup[10] = b43_phy_read(dev, 0x002E);
+ backup[11] = b43_phy_read(dev, 0x002F);
+ backup[12] = b43_phy_read(dev, 0x080F);
+ backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL);
+ backup[14] = b43_phy_read(dev, 0x0801);
+ backup[15] = b43_phy_read(dev, 0x0060);
+ backup[16] = b43_phy_read(dev, 0x0014);
+ backup[17] = b43_phy_read(dev, 0x0478);
+ b43_phy_write(dev, 0x002E, 0);
+ b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0);
+ switch (phy->rev) {
+ case 4:
+ case 6:
+ case 7:
+ b43_phy_write(dev, 0x0478,
+ b43_phy_read(dev, 0x0478)
+ | 0x0100);
+ b43_phy_write(dev, 0x0801,
+ b43_phy_read(dev, 0x0801)
+ | 0x0040);
+ break;
+ case 3:
+ case 5:
+ b43_phy_write(dev, 0x0801,
+ b43_phy_read(dev, 0x0801)
+ & 0xFFBF);
+ break;
+ }
+ b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060)
+ | 0x0040);
+ b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014)
+ | 0x0200);
+ }
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) | 0x0070);
+ b43_set_all_gains(dev, 0, 8, 0);
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) & 0x00F7);
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, 0x0811,
+ (b43_phy_read(dev, 0x0811) & 0xFFCF) |
+ 0x0030);
+ b43_phy_write(dev, 0x0812,
+ (b43_phy_read(dev, 0x0812) & 0xFFCF) |
+ 0x0010);
+ }
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) | 0x0080);
+ udelay(20);
+
+ nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (nrssi0 >= 0x0020)
+ nrssi0 -= 0x0040;
+
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) & 0x007F);
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003)
+ & 0xFF9F) | 0x0040);
+ }
+
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+ b43_read16(dev, B43_MMIO_CHANNEL_EXT)
+ | 0x2000);
+ b43_radio_write16(dev, 0x007A,
+ b43_radio_read16(dev, 0x007A) | 0x000F);
+ b43_phy_write(dev, 0x0015, 0xF330);
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, 0x0812,
+ (b43_phy_read(dev, 0x0812) & 0xFFCF) |
+ 0x0020);
+ b43_phy_write(dev, 0x0811,
+ (b43_phy_read(dev, 0x0811) & 0xFFCF) |
+ 0x0020);
+ }
+
+ b43_set_all_gains(dev, 3, 0, 1);
+ if (phy->radio_rev == 8) {
+ b43_radio_write16(dev, 0x0043, 0x001F);
+ } else {
+ tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F;
+ b43_radio_write16(dev, 0x0052, tmp | 0x0060);
+ tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0;
+ b43_radio_write16(dev, 0x0043, tmp | 0x0009);
+ }
+ b43_phy_write(dev, 0x005A, 0x0480);
+ b43_phy_write(dev, 0x0059, 0x0810);
+ b43_phy_write(dev, 0x0058, 0x000D);
+ udelay(20);
+ nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (nrssi1 >= 0x0020)
+ nrssi1 -= 0x0040;
+ if (nrssi0 == nrssi1)
+ phy->nrssislope = 0x00010000;
+ else
+ phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+ if (nrssi0 >= -4) {
+ phy->nrssi[0] = nrssi1;
+ phy->nrssi[1] = nrssi0;
+ }
+ if (phy->rev >= 3) {
+ b43_phy_write(dev, 0x002E, backup[10]);
+ b43_phy_write(dev, 0x002F, backup[11]);
+ b43_phy_write(dev, 0x080F, backup[12]);
+ b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]);
+ }
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, 0x0812,
+ b43_phy_read(dev, 0x0812) & 0xFFCF);
+ b43_phy_write(dev, 0x0811,
+ b43_phy_read(dev, 0x0811) & 0xFFCF);
+ }
+
+ b43_radio_write16(dev, 0x007A, backup[0]);
+ b43_radio_write16(dev, 0x0052, backup[1]);
+ b43_radio_write16(dev, 0x0043, backup[2]);
+ b43_write16(dev, 0x03E2, backup[7]);
+ b43_write16(dev, 0x03E6, backup[8]);
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]);
+ b43_phy_write(dev, 0x0015, backup[3]);
+ b43_phy_write(dev, 0x005A, backup[4]);
+ b43_phy_write(dev, 0x0059, backup[5]);
+ b43_phy_write(dev, 0x0058, backup[6]);
+ b43_synth_pu_workaround(dev, phy->channel);
+ b43_phy_write(dev, 0x0802,
+ b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002));
+ b43_set_original_gains(dev);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
+ if (phy->rev >= 3) {
+ b43_phy_write(dev, 0x0801, backup[14]);
+ b43_phy_write(dev, 0x0060, backup[15]);
+ b43_phy_write(dev, 0x0014, backup[16]);
+ b43_phy_write(dev, 0x0478, backup[17]);
+ }
+ b43_nrssi_mem_update(dev);
+ b43_calc_nrssi_threshold(dev);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+void b43_calc_nrssi_threshold(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ s32 threshold;
+ s32 a, b;
+ s16 tmp16;
+ u16 tmp_u16;
+
+ switch (phy->type) {
+ case B43_PHYTYPE_B:{
+ if (phy->radio_ver != 0x2050)
+ return;
+ if (!
+ (dev->dev->bus->sprom.r1.
+ boardflags_lo & B43_BFL_RSSI))
+ return;
+
+ if (phy->radio_rev >= 6) {
+ threshold =
+ (phy->nrssi[1] - phy->nrssi[0]) * 32;
+ threshold += 20 * (phy->nrssi[0] + 1);
+ threshold /= 40;
+ } else
+ threshold = phy->nrssi[1] - 5;
+
+ threshold = limit_value(threshold, 0, 0x3E);
+ b43_phy_read(dev, 0x0020); /* dummy read */
+ b43_phy_write(dev, 0x0020,
+ (((u16) threshold) << 8) | 0x001C);
+
+ if (phy->radio_rev >= 6) {
+ b43_phy_write(dev, 0x0087, 0x0E0D);
+ b43_phy_write(dev, 0x0086, 0x0C0B);
+ b43_phy_write(dev, 0x0085, 0x0A09);
+ b43_phy_write(dev, 0x0084, 0x0808);
+ b43_phy_write(dev, 0x0083, 0x0808);
+ b43_phy_write(dev, 0x0082, 0x0604);
+ b43_phy_write(dev, 0x0081, 0x0302);
+ b43_phy_write(dev, 0x0080, 0x0100);
+ }
+ break;
+ }
+ case B43_PHYTYPE_G:
+ if (!phy->gmode ||
+ !(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) {
+ tmp16 = b43_nrssi_hw_read(dev, 0x20);
+ if (tmp16 >= 0x20)
+ tmp16 -= 0x40;
+ if (tmp16 < 3) {
+ b43_phy_write(dev, 0x048A,
+ (b43_phy_read(dev, 0x048A)
+ & 0xF000) | 0x09EB);
+ } else {
+ b43_phy_write(dev, 0x048A,
+ (b43_phy_read(dev, 0x048A)
+ & 0xF000) | 0x0AED);
+ }
+ } else {
+ if (phy->interfmode == B43_INTERFMODE_NONWLAN) {
+ a = 0xE;
+ b = 0xA;
+ } else if (!phy->aci_wlan_automatic && phy->aci_enable) {
+ a = 0x13;
+ b = 0x12;
+ } else {
+ a = 0xE;
+ b = 0x11;
+ }
+
+ a = a * (phy->nrssi[1] - phy->nrssi[0]);
+ a += (phy->nrssi[0] << 6);
+ if (a < 32)
+ a += 31;
+ else
+ a += 32;
+ a = a >> 6;
+ a = limit_value(a, -31, 31);
+
+ b = b * (phy->nrssi[1] - phy->nrssi[0]);
+ b += (phy->nrssi[0] << 6);
+ if (b < 32)
+ b += 31;
+ else
+ b += 32;
+ b = b >> 6;
+ b = limit_value(b, -31, 31);
+
+ tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000;
+ tmp_u16 |= ((u32) b & 0x0000003F);
+ tmp_u16 |= (((u32) a & 0x0000003F) << 6);
+ b43_phy_write(dev, 0x048A, tmp_u16);
+ }
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+/* Stack implementation to save/restore values from the
+ * interference mitigation code.
+ * It is save to restore values in random order.
+ */
+static void _stack_save(u32 * _stackptr, size_t * stackidx,
+ u8 id, u16 offset, u16 value)
+{
+ u32 *stackptr = &(_stackptr[*stackidx]);
+
+ B43_WARN_ON(offset & 0xF000);
+ B43_WARN_ON(id & 0xF0);
+ *stackptr = offset;
+ *stackptr |= ((u32) id) << 12;
+ *stackptr |= ((u32) value) << 16;
+ (*stackidx)++;
+ B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE);
+}
+
+static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset)
+{
+ size_t i;
+
+ B43_WARN_ON(offset & 0xF000);
+ B43_WARN_ON(id & 0xF0);
+ for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) {
+ if ((*stackptr & 0x00000FFF) != offset)
+ continue;
+ if (((*stackptr & 0x0000F000) >> 12) != id)
+ continue;
+ return ((*stackptr & 0xFFFF0000) >> 16);
+ }
+ B43_WARN_ON(1);
+
+ return 0;
+}
+
+#define phy_stacksave(offset) \
+ do { \
+ _stack_save(stack, &stackidx, 0x1, (offset), \
+ b43_phy_read(dev, (offset))); \
+ } while (0)
+#define phy_stackrestore(offset) \
+ do { \
+ b43_phy_write(dev, (offset), \
+ _stack_restore(stack, 0x1, \
+ (offset))); \
+ } while (0)
+#define radio_stacksave(offset) \
+ do { \
+ _stack_save(stack, &stackidx, 0x2, (offset), \
+ b43_radio_read16(dev, (offset))); \
+ } while (0)
+#define radio_stackrestore(offset) \
+ do { \
+ b43_radio_write16(dev, (offset), \
+ _stack_restore(stack, 0x2, \
+ (offset))); \
+ } while (0)
+#define ofdmtab_stacksave(table, offset) \
+ do { \
+ _stack_save(stack, &stackidx, 0x3, (offset)|(table), \
+ b43_ofdmtab_read16(dev, (table), (offset))); \
+ } while (0)
+#define ofdmtab_stackrestore(table, offset) \
+ do { \
+ b43_ofdmtab_write16(dev, (table), (offset), \
+ _stack_restore(stack, 0x3, \
+ (offset)|(table))); \
+ } while (0)
+
+static void
+b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 tmp, flipped;
+ size_t stackidx = 0;
+ u32 *stack = phy->interfstack;
+
+ switch (mode) {
+ case B43_INTERFMODE_NONWLAN:
+ if (phy->rev != 1) {
+ b43_phy_write(dev, 0x042B,
+ b43_phy_read(dev, 0x042B) | 0x0800);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev,
+ B43_PHY_G_CRS) & ~0x4000);
+ break;
+ }
+ radio_stacksave(0x0078);
+ tmp = (b43_radio_read16(dev, 0x0078) & 0x001E);
+ flipped = flip_4bit(tmp);
+ if (flipped < 10 && flipped >= 8)
+ flipped = 7;
+ else if (flipped >= 10)
+ flipped -= 3;
+ flipped = flip_4bit(flipped);
+ flipped = (flipped << 1) | 0x0020;
+ b43_radio_write16(dev, 0x0078, flipped);
+
+ b43_calc_nrssi_threshold(dev);
+
+ phy_stacksave(0x0406);
+ b43_phy_write(dev, 0x0406, 0x7E28);
+
+ b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800);
+ b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+ b43_phy_read(dev,
+ B43_PHY_RADIO_BITFIELD) | 0x1000);
+
+ phy_stacksave(0x04A0);
+ b43_phy_write(dev, 0x04A0,
+ (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008);
+ phy_stacksave(0x04A1);
+ b43_phy_write(dev, 0x04A1,
+ (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605);
+ phy_stacksave(0x04A2);
+ b43_phy_write(dev, 0x04A2,
+ (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204);
+ phy_stacksave(0x04A8);
+ b43_phy_write(dev, 0x04A8,
+ (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803);
+ phy_stacksave(0x04AB);
+ b43_phy_write(dev, 0x04AB,
+ (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605);
+
+ phy_stacksave(0x04A7);
+ b43_phy_write(dev, 0x04A7, 0x0002);
+ phy_stacksave(0x04A3);
+ b43_phy_write(dev, 0x04A3, 0x287A);
+ phy_stacksave(0x04A9);
+ b43_phy_write(dev, 0x04A9, 0x2027);
+ phy_stacksave(0x0493);
+ b43_phy_write(dev, 0x0493, 0x32F5);
+ phy_stacksave(0x04AA);
+ b43_phy_write(dev, 0x04AA, 0x2027);
+ phy_stacksave(0x04AC);
+ b43_phy_write(dev, 0x04AC, 0x32F5);
+ break;
+ case B43_INTERFMODE_MANUALWLAN:
+ if (b43_phy_read(dev, 0x0033) & 0x0800)
+ break;
+
+ phy->aci_enable = 1;
+
+ phy_stacksave(B43_PHY_RADIO_BITFIELD);
+ phy_stacksave(B43_PHY_G_CRS);
+ if (phy->rev < 2) {
+ phy_stacksave(0x0406);
+ } else {
+ phy_stacksave(0x04C0);
+ phy_stacksave(0x04C1);
+ }
+ phy_stacksave(0x0033);
+ phy_stacksave(0x04A7);
+ phy_stacksave(0x04A3);
+ phy_stacksave(0x04A9);
+ phy_stacksave(0x04AA);
+ phy_stacksave(0x04AC);
+ phy_stacksave(0x0493);
+ phy_stacksave(0x04A1);
+ phy_stacksave(0x04A0);
+ phy_stacksave(0x04A2);
+ phy_stacksave(0x048A);
+ phy_stacksave(0x04A8);
+ phy_stacksave(0x04AB);
+ if (phy->rev == 2) {
+ phy_stacksave(0x04AD);
+ phy_stacksave(0x04AE);
+ } else if (phy->rev >= 3) {
+ phy_stacksave(0x04AD);
+ phy_stacksave(0x0415);
+ phy_stacksave(0x0416);
+ phy_stacksave(0x0417);
+ ofdmtab_stacksave(0x1A00, 0x2);
+ ofdmtab_stacksave(0x1A00, 0x3);
+ }
+ phy_stacksave(0x042B);
+ phy_stacksave(0x048C);
+
+ b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+ b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
+ & ~0x1000);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ (b43_phy_read(dev, B43_PHY_G_CRS)
+ & 0xFFFC) | 0x0002);
+
+ b43_phy_write(dev, 0x0033, 0x0800);
+ b43_phy_write(dev, 0x04A3, 0x2027);
+ b43_phy_write(dev, 0x04A9, 0x1CA8);
+ b43_phy_write(dev, 0x0493, 0x287A);
+ b43_phy_write(dev, 0x04AA, 0x1CA8);
+ b43_phy_write(dev, 0x04AC, 0x287A);
+
+ b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+ & 0xFFC0) | 0x001A);
+ b43_phy_write(dev, 0x04A7, 0x000D);
+
+ if (phy->rev < 2) {
+ b43_phy_write(dev, 0x0406, 0xFF0D);
+ } else if (phy->rev == 2) {
+ b43_phy_write(dev, 0x04C0, 0xFFFF);
+ b43_phy_write(dev, 0x04C1, 0x00A9);
+ } else {
+ b43_phy_write(dev, 0x04C0, 0x00C1);
+ b43_phy_write(dev, 0x04C1, 0x0059);
+ }
+
+ b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
+ & 0xC0FF) | 0x1800);
+ b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
+ & 0xFFC0) | 0x0015);
+ b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+ & 0xCFFF) | 0x1000);
+ b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+ & 0xF0FF) | 0x0A00);
+ b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+ & 0xCFFF) | 0x1000);
+ b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+ & 0xF0FF) | 0x0800);
+ b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+ & 0xFFCF) | 0x0010);
+ b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+ & 0xFFF0) | 0x0005);
+ b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+ & 0xFFCF) | 0x0010);
+ b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+ & 0xFFF0) | 0x0006);
+ b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+ & 0xF0FF) | 0x0800);
+ b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+ & 0xF0FF) | 0x0500);
+ b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+ & 0xFFF0) | 0x000B);
+
+ if (phy->rev >= 3) {
+ b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
+ & ~0x8000);
+ b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415)
+ & 0x8000) | 0x36D8);
+ b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416)
+ & 0x8000) | 0x36D8);
+ b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417)
+ & 0xFE00) | 0x016D);
+ } else {
+ b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
+ | 0x1000);
+ b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A)
+ & 0x9FFF) | 0x2000);
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW);
+ }
+ if (phy->rev >= 2) {
+ b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B)
+ | 0x0800);
+ }
+ b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
+ & 0xF0FF) | 0x0200);
+ if (phy->rev == 2) {
+ b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE)
+ & 0xFF00) | 0x007F);
+ b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD)
+ & 0x00FF) | 0x1300);
+ } else if (phy->rev >= 6) {
+ b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F);
+ b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F);
+ b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD)
+ & 0x00FF);
+ }
+ b43_calc_nrssi_slope(dev);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+static void
+b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode)
+{
+ struct b43_phy *phy = &dev->phy;
+ u32 *stack = phy->interfstack;
+
+ switch (mode) {
+ case B43_INTERFMODE_NONWLAN:
+ if (phy->rev != 1) {
+ b43_phy_write(dev, 0x042B,
+ b43_phy_read(dev, 0x042B) & ~0x0800);
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev,
+ B43_PHY_G_CRS) | 0x4000);
+ break;
+ }
+ radio_stackrestore(0x0078);
+ b43_calc_nrssi_threshold(dev);
+ phy_stackrestore(0x0406);
+ b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800);
+ if (!dev->bad_frames_preempt) {
+ b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+ b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
+ & ~(1 << 11));
+ }
+ b43_phy_write(dev, B43_PHY_G_CRS,
+ b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000);
+ phy_stackrestore(0x04A0);
+ phy_stackrestore(0x04A1);
+ phy_stackrestore(0x04A2);
+ phy_stackrestore(0x04A8);
+ phy_stackrestore(0x04AB);
+ phy_stackrestore(0x04A7);
+ phy_stackrestore(0x04A3);
+ phy_stackrestore(0x04A9);
+ phy_stackrestore(0x0493);
+ phy_stackrestore(0x04AA);
+ phy_stackrestore(0x04AC);
+ break;
+ case B43_INTERFMODE_MANUALWLAN:
+ if (!(b43_phy_read(dev, 0x0033) & 0x0800))
+ break;
+
+ phy->aci_enable = 0;
+
+ phy_stackrestore(B43_PHY_RADIO_BITFIELD);
+ phy_stackrestore(B43_PHY_G_CRS);
+ phy_stackrestore(0x0033);
+ phy_stackrestore(0x04A3);
+ phy_stackrestore(0x04A9);
+ phy_stackrestore(0x0493);
+ phy_stackrestore(0x04AA);
+ phy_stackrestore(0x04AC);
+ phy_stackrestore(0x04A0);
+ phy_stackrestore(0x04A7);
+ if (phy->rev >= 2) {
+ phy_stackrestore(0x04C0);
+ phy_stackrestore(0x04C1);
+ } else
+ phy_stackrestore(0x0406);
+ phy_stackrestore(0x04A1);
+ phy_stackrestore(0x04AB);
+ phy_stackrestore(0x04A8);
+ if (phy->rev == 2) {
+ phy_stackrestore(0x04AD);
+ phy_stackrestore(0x04AE);
+ } else if (phy->rev >= 3) {
+ phy_stackrestore(0x04AD);
+ phy_stackrestore(0x0415);
+ phy_stackrestore(0x0416);
+ phy_stackrestore(0x0417);
+ ofdmtab_stackrestore(0x1A00, 0x2);
+ ofdmtab_stackrestore(0x1A00, 0x3);
+ }
+ phy_stackrestore(0x04A2);
+ phy_stackrestore(0x048A);
+ phy_stackrestore(0x042B);
+ phy_stackrestore(0x048C);
+ b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW);
+ b43_calc_nrssi_slope(dev);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+}
+
+#undef phy_stacksave
+#undef phy_stackrestore
+#undef radio_stacksave
+#undef radio_stackrestore
+#undef ofdmtab_stacksave
+#undef ofdmtab_stackrestore
+
+int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode)
+{
+ struct b43_phy *phy = &dev->phy;
+ int currentmode;
+
+ if ((phy->type != B43_PHYTYPE_G) || (phy->rev == 0) || (!phy->gmode))
+ return -ENODEV;
+
+ phy->aci_wlan_automatic = 0;
+ switch (mode) {
+ case B43_INTERFMODE_AUTOWLAN:
+ phy->aci_wlan_automatic = 1;
+ if (phy->aci_enable)
+ mode = B43_INTERFMODE_MANUALWLAN;
+ else
+ mode = B43_INTERFMODE_NONE;
+ break;
+ case B43_INTERFMODE_NONE:
+ case B43_INTERFMODE_NONWLAN:
+ case B43_INTERFMODE_MANUALWLAN:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ currentmode = phy->interfmode;
+ if (currentmode == mode)
+ return 0;
+ if (currentmode != B43_INTERFMODE_NONE)
+ b43_radio_interference_mitigation_disable(dev, currentmode);
+
+ if (mode == B43_INTERFMODE_NONE) {
+ phy->aci_enable = 0;
+ phy->aci_hw_rssi = 0;
+ } else
+ b43_radio_interference_mitigation_enable(dev, mode);
+ phy->interfmode = mode;
+
+ return 0;
+}
+
+static u16 b43_radio_core_calibration_value(struct b43_wldev *dev)
+{
+ u16 reg, index, ret;
+
+ static const u8 rcc_table[] = {
+ 0x02, 0x03, 0x01, 0x0F,
+ 0x06, 0x07, 0x05, 0x0F,
+ 0x0A, 0x0B, 0x09, 0x0F,
+ 0x0E, 0x0F, 0x0D, 0x0F,
+ };
+
+ reg = b43_radio_read16(dev, 0x60);
+ index = (reg & 0x001E) >> 1;
+ ret = rcc_table[index] << 1;
+ ret |= (reg & 0x0001);
+ ret |= 0x0020;
+
+ return ret;
+}
+
+#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
+static u16 radio2050_rfover_val(struct b43_wldev *dev,
+ u16 phy_register, unsigned int lpd)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+
+ if (!phy->gmode)
+ return 0;
+
+ if (has_loopback_gain(phy)) {
+ int max_lb_gain = phy->max_lb_gain;
+ u16 extlna;
+ u16 i;
+
+ if (phy->radio_rev == 8)
+ max_lb_gain += 0x3E;
+ else
+ max_lb_gain += 0x26;
+ if (max_lb_gain >= 0x46) {
+ extlna = 0x3000;
+ max_lb_gain -= 0x46;
+ } else if (max_lb_gain >= 0x3A) {
+ extlna = 0x1000;
+ max_lb_gain -= 0x3A;
+ } else if (max_lb_gain >= 0x2E) {
+ extlna = 0x2000;
+ max_lb_gain -= 0x2E;
+ } else {
+ extlna = 0;
+ max_lb_gain -= 0x10;
+ }
+
+ for (i = 0; i < 16; i++) {
+ max_lb_gain -= (i * 6);
+ if (max_lb_gain < 6)
+ break;
+ }
+
+ if ((phy->rev < 7) ||
+ !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+ if (phy_register == B43_PHY_RFOVER) {
+ return 0x1B3;
+ } else if (phy_register == B43_PHY_RFOVERVAL) {
+ extlna |= (i << 8);
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x0F92;
+ case LPD(0, 0, 1):
+ case LPD(1, 0, 1):
+ return (0x0092 | extlna);
+ case LPD(1, 0, 0):
+ return (0x0093 | extlna);
+ }
+ B43_WARN_ON(1);
+ }
+ B43_WARN_ON(1);
+ } else {
+ if (phy_register == B43_PHY_RFOVER) {
+ return 0x9B3;
+ } else if (phy_register == B43_PHY_RFOVERVAL) {
+ if (extlna)
+ extlna |= 0x8000;
+ extlna |= (i << 8);
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x8F92;
+ case LPD(0, 0, 1):
+ return (0x8092 | extlna);
+ case LPD(1, 0, 1):
+ return (0x2092 | extlna);
+ case LPD(1, 0, 0):
+ return (0x2093 | extlna);
+ }
+ B43_WARN_ON(1);
+ }
+ B43_WARN_ON(1);
+ }
+ } else {
+ if ((phy->rev < 7) ||
+ !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+ if (phy_register == B43_PHY_RFOVER) {
+ return 0x1B3;
+ } else if (phy_register == B43_PHY_RFOVERVAL) {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x0FB2;
+ case LPD(0, 0, 1):
+ return 0x00B2;
+ case LPD(1, 0, 1):
+ return 0x30B2;
+ case LPD(1, 0, 0):
+ return 0x30B3;
+ }
+ B43_WARN_ON(1);
+ }
+ B43_WARN_ON(1);
+ } else {
+ if (phy_register == B43_PHY_RFOVER) {
+ return 0x9B3;
+ } else if (phy_register == B43_PHY_RFOVERVAL) {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x8FB2;
+ case LPD(0, 0, 1):
+ return 0x80B2;
+ case LPD(1, 0, 1):
+ return 0x20B2;
+ case LPD(1, 0, 0):
+ return 0x20B3;
+ }
+ B43_WARN_ON(1);
+ }
+ B43_WARN_ON(1);
+ }
+ }
+ return 0;
+}
+
+struct init2050_saved_values {
+ /* Core registers */
+ u16 reg_3EC;
+ u16 reg_3E6;
+ u16 reg_3F4;
+ /* Radio registers */
+ u16 radio_43;
+ u16 radio_51;
+ u16 radio_52;
+ /* PHY registers */
+ u16 phy_pgactl;
+ u16 phy_base_5A;
+ u16 phy_base_59;
+ u16 phy_base_58;
+ u16 phy_base_30;
+ u16 phy_rfover;
+ u16 phy_rfoverval;
+ u16 phy_analogover;
+ u16 phy_analogoverval;
+ u16 phy_crs0;
+ u16 phy_classctl;
+ u16 phy_lo_mask;
+ u16 phy_lo_ctl;
+ u16 phy_syncctl;
+};
+
+u16 b43_radio_init2050(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct init2050_saved_values sav;
+ u16 rcc;
+ u16 radio78;
+ u16 ret;
+ u16 i, j;
+ u32 tmp1 = 0, tmp2 = 0;
+
+ memset(&sav, 0, sizeof(sav)); /* get rid of "may be used uninitialized..." */
+
+ sav.radio_43 = b43_radio_read16(dev, 0x43);
+ sav.radio_51 = b43_radio_read16(dev, 0x51);
+ sav.radio_52 = b43_radio_read16(dev, 0x52);
+ sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
+ sav.phy_base_5A = b43_phy_read(dev, B43_PHY_BASE(0x5A));
+ sav.phy_base_59 = b43_phy_read(dev, B43_PHY_BASE(0x59));
+ sav.phy_base_58 = b43_phy_read(dev, B43_PHY_BASE(0x58));
+
+ if (phy->type == B43_PHYTYPE_B) {
+ sav.phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
+ sav.reg_3EC = b43_read16(dev, 0x3EC);
+
+ b43_phy_write(dev, B43_PHY_BASE(0x30), 0xFF);
+ b43_write16(dev, 0x3EC, 0x3F3F);
+ } else if (phy->gmode || phy->rev >= 2) {
+ sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
+ sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+ sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
+ sav.phy_analogoverval =
+ b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
+ sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
+ sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
+
+ b43_phy_write(dev, B43_PHY_ANALOGOVER,
+ b43_phy_read(dev, B43_PHY_ANALOGOVER)
+ | 0x0003);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ b43_phy_read(dev, B43_PHY_ANALOGOVERVAL)
+ & 0xFFFC);
+ b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
+ & 0x7FFF);
+ b43_phy_write(dev, B43_PHY_CLASSCTL,
+ b43_phy_read(dev, B43_PHY_CLASSCTL)
+ & 0xFFFC);
+ if (has_loopback_gain(phy)) {
+ sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
+ sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL);
+
+ if (phy->rev >= 3)
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
+ else
+ b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
+ b43_phy_write(dev, B43_PHY_LO_CTL, 0);
+ }
+
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
+ LPD(0, 1, 1)));
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ radio2050_rfover_val(dev, B43_PHY_RFOVER, 0));
+ }
+ b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000);
+
+ sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
+ b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL)
+ & 0xFF7F);
+ sav.reg_3E6 = b43_read16(dev, 0x3E6);
+ sav.reg_3F4 = b43_read16(dev, 0x3F4);
+
+ if (phy->analog == 0) {
+ b43_write16(dev, 0x03E6, 0x0122);
+ } else {
+ if (phy->analog >= 2) {
+ b43_phy_write(dev, B43_PHY_BASE(0x03),
+ (b43_phy_read(dev, B43_PHY_BASE(0x03))
+ & 0xFFBF) | 0x40);
+ }
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+ (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000));
+ }
+
+ rcc = b43_radio_core_calibration_value(dev);
+
+ if (phy->type == B43_PHYTYPE_B)
+ b43_radio_write16(dev, 0x78, 0x26);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
+ LPD(0, 1, 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF);
+ b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1403);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
+ LPD(0, 0, 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0);
+ b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51)
+ | 0x0004);
+ if (phy->radio_rev == 8) {
+ b43_radio_write16(dev, 0x43, 0x1F);
+ } else {
+ b43_radio_write16(dev, 0x52, 0);
+ b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+ & 0xFFF0) | 0x0009);
+ }
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+
+ for (i = 0; i < 16; i++) {
+ b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0480);
+ b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0, 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+ udelay(10);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0, 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
+ udelay(10);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0, 0)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
+ udelay(20);
+ tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0, 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+ }
+ udelay(10);
+
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+ tmp1++;
+ tmp1 >>= 9;
+
+ for (i = 0; i < 16; i++) {
+ radio78 = ((flip_4bit(i) << 1) | 0x20);
+ b43_radio_write16(dev, 0x78, radio78);
+ udelay(10);
+ for (j = 0; j < 16; j++) {
+ b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0D80);
+ b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0,
+ 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+ udelay(10);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0,
+ 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
+ udelay(10);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0,
+ 0)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
+ udelay(10);
+ tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+ if (phy->gmode || phy->rev >= 2) {
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ radio2050_rfover_val(dev,
+ B43_PHY_RFOVERVAL,
+ LPD(1, 0,
+ 1)));
+ }
+ b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+ }
+ tmp2++;
+ tmp2 >>= 8;
+ if (tmp1 < tmp2)
+ break;
+ }
+
+ /* Restore the registers */
+ b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl);
+ b43_radio_write16(dev, 0x51, sav.radio_51);
+ b43_radio_write16(dev, 0x52, sav.radio_52);
+ b43_radio_write16(dev, 0x43, sav.radio_43);
+ b43_phy_write(dev, B43_PHY_BASE(0x5A), sav.phy_base_5A);
+ b43_phy_write(dev, B43_PHY_BASE(0x59), sav.phy_base_59);
+ b43_phy_write(dev, B43_PHY_BASE(0x58), sav.phy_base_58);
+ b43_write16(dev, 0x3E6, sav.reg_3E6);
+ if (phy->analog != 0)
+ b43_write16(dev, 0x3F4, sav.reg_3F4);
+ b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl);
+ b43_synth_pu_workaround(dev, phy->channel);
+ if (phy->type == B43_PHYTYPE_B) {
+ b43_phy_write(dev, B43_PHY_BASE(0x30), sav.phy_base_30);
+ b43_write16(dev, 0x3EC, sav.reg_3EC);
+ } else if (phy->gmode) {
+ b43_write16(dev, B43_MMIO_PHY_RADIO,
+ b43_read16(dev, B43_MMIO_PHY_RADIO)
+ & 0x7FFF);
+ b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval);
+ b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover);
+ b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+ sav.phy_analogoverval);
+ b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0);
+ b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl);
+ if (has_loopback_gain(phy)) {
+ b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask);
+ b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl);
+ }
+ }
+ if (i > 15)
+ ret = radio78;
+ else
+ ret = rcc;
+
+ return ret;
+}
+
+void b43_radio_init2060(struct b43_wldev *dev)
+{
+ int err;
+
+ b43_radio_write16(dev, 0x0004, 0x00C0);
+ b43_radio_write16(dev, 0x0005, 0x0008);
+ b43_radio_write16(dev, 0x0009, 0x0040);
+ b43_radio_write16(dev, 0x0005, 0x00AA);
+ b43_radio_write16(dev, 0x0032, 0x008F);
+ b43_radio_write16(dev, 0x0006, 0x008F);
+ b43_radio_write16(dev, 0x0034, 0x008F);
+ b43_radio_write16(dev, 0x002C, 0x0007);
+ b43_radio_write16(dev, 0x0082, 0x0080);
+ b43_radio_write16(dev, 0x0080, 0x0000);
+ b43_radio_write16(dev, 0x003F, 0x00DA);
+ b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
+ b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010);
+ b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
+ b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
+ msleep(1); /* delay 400usec */
+
+ b43_radio_write16(dev, 0x0081,
+ (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010);
+ msleep(1); /* delay 400usec */
+
+ b43_radio_write16(dev, 0x0005,
+ (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008);
+ b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010);
+ b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
+ b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040);
+ b43_radio_write16(dev, 0x0081,
+ (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040);
+ b43_radio_write16(dev, 0x0005,
+ (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008);
+ b43_phy_write(dev, 0x0063, 0xDDC6);
+ b43_phy_write(dev, 0x0069, 0x07BE);
+ b43_phy_write(dev, 0x006A, 0x0000);
+
+ err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_A, 0);
+ B43_WARN_ON(err);
+
+ msleep(1);
+}
+
+static inline u16 freq_r3A_value(u16 frequency)
+{
+ u16 value;
+
+ if (frequency < 5091)
+ value = 0x0040;
+ else if (frequency < 5321)
+ value = 0x0000;
+ else if (frequency < 5806)
+ value = 0x0080;
+ else
+ value = 0x0040;
+
+ return value;
+}
+
+void b43_radio_set_tx_iq(struct b43_wldev *dev)
+{
+ static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
+ static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
+ u16 tmp = b43_radio_read16(dev, 0x001E);
+ int i, j;
+
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 5; j++) {
+ if (tmp == (data_high[i] << 4 | data_low[j])) {
+ b43_phy_write(dev, 0x0069,
+ (i - j) << 8 | 0x00C0);
+ return;
+ }
+ }
+ }
+}
+
+int b43_radio_selectchannel(struct b43_wldev *dev,
+ u8 channel, int synthetic_pu_workaround)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 r8, tmp;
+ u16 freq;
+ u16 channelcookie;
+
+ if (channel == 0xFF) {
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ channel = B43_DEFAULT_CHANNEL_A;
+ break;
+ case B43_PHYTYPE_B:
+ case B43_PHYTYPE_G:
+ channel = B43_DEFAULT_CHANNEL_BG;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ }
+
+ /* First we set the channel radio code to prevent the
+ * firmware from sending ghost packets.
+ */
+ channelcookie = channel;
+ if (phy->type == B43_PHYTYPE_A)
+ channelcookie |= 0x100;
+ b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
+
+ if (phy->type == B43_PHYTYPE_A) {
+ if (channel > 200)
+ return -EINVAL;
+ freq = channel2freq_a(channel);
+
+ r8 = b43_radio_read16(dev, 0x0008);
+ b43_write16(dev, 0x03F0, freq);
+ b43_radio_write16(dev, 0x0008, r8);
+
+ //TODO: write max channel TX power? to Radio 0x2D
+ tmp = b43_radio_read16(dev, 0x002E);
+ tmp &= 0x0080;
+ //TODO: OR tmp with the Power out estimation for this channel?
+ b43_radio_write16(dev, 0x002E, tmp);
+
+ if (freq >= 4920 && freq <= 5500) {
+ /*
+ * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F;
+ * = (freq * 0.025862069
+ */
+ r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */
+ }
+ b43_radio_write16(dev, 0x0007, (r8 << 4) | r8);
+ b43_radio_write16(dev, 0x0020, (r8 << 4) | r8);
+ b43_radio_write16(dev, 0x0021, (r8 << 4) | r8);
+ b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022)
+ & 0x000F) | (r8 << 4));
+ b43_radio_write16(dev, 0x002A, (r8 << 4));
+ b43_radio_write16(dev, 0x002B, (r8 << 4));
+ b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008)
+ & 0x00F0) | (r8 << 4));
+ b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029)
+ & 0xFF0F) | 0x00B0);
+ b43_radio_write16(dev, 0x0035, 0x00AA);
+ b43_radio_write16(dev, 0x0036, 0x0085);
+ b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A)
+ & 0xFF20) |
+ freq_r3A_value(freq));
+ b43_radio_write16(dev, 0x003D,
+ b43_radio_read16(dev, 0x003D) & 0x00FF);
+ b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081)
+ & 0xFF7F) | 0x0080);
+ b43_radio_write16(dev, 0x0035,
+ b43_radio_read16(dev, 0x0035) & 0xFFEF);
+ b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035)
+ & 0xFFEF) | 0x0010);
+ b43_radio_set_tx_iq(dev);
+ //TODO: TSSI2dbm workaround
+ b43_phy_xmitpower(dev); //FIXME correct?
+ } else {
+ if ((channel < 1) || (channel > 14))
+ return -EINVAL;
+
+ if (synthetic_pu_workaround)
+ b43_synth_pu_workaround(dev, channel);
+
+ b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
+
+ if (channel == 14) {
+ if (dev->dev->bus->sprom.r1.country_code ==
+ SSB_SPROM1CCODE_JAPAN)
+ b43_hf_write(dev,
+ b43_hf_read(dev) & ~B43_HF_ACPR);
+ else
+ b43_hf_write(dev,
+ b43_hf_read(dev) | B43_HF_ACPR);
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+ b43_read16(dev, B43_MMIO_CHANNEL_EXT)
+ | (1 << 11));
+ } else {
+ b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+ b43_read16(dev, B43_MMIO_CHANNEL_EXT)
+ & 0xF7BF);
+ }
+ }
+
+ phy->channel = channel;
+ /* Wait for the radio to tune to the channel and stabilize. */
+ msleep(8);
+
+ return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
+static u16 b43_get_txgain_base_band(u16 txpower)
+{
+ u16 ret;
+
+ B43_WARN_ON(txpower > 63);
+
+ if (txpower >= 54)
+ ret = 2;
+ else if (txpower >= 49)
+ ret = 4;
+ else if (txpower >= 44)
+ ret = 5;
+ else
+ ret = 6;
+
+ return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
+static u16 b43_get_txgain_freq_power_amp(u16 txpower)
+{
+ u16 ret;
+
+ B43_WARN_ON(txpower > 63);
+
+ if (txpower >= 32)
+ ret = 0;
+ else if (txpower >= 25)
+ ret = 1;
+ else if (txpower >= 20)
+ ret = 2;
+ else if (txpower >= 12)
+ ret = 3;
+ else
+ ret = 4;
+
+ return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
+static u16 b43_get_txgain_dac(u16 txpower)
+{
+ u16 ret;
+
+ B43_WARN_ON(txpower > 63);
+
+ if (txpower >= 54)
+ ret = txpower - 53;
+ else if (txpower >= 49)
+ ret = txpower - 42;
+ else if (txpower >= 44)
+ ret = txpower - 37;
+ else if (txpower >= 32)
+ ret = txpower - 32;
+ else if (txpower >= 25)
+ ret = txpower - 20;
+ else if (txpower >= 20)
+ ret = txpower - 13;
+ else if (txpower >= 12)
+ ret = txpower - 8;
+ else
+ ret = txpower;
+
+ return ret;
+}
+
+static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower)
+{
+ struct b43_phy *phy = &dev->phy;
+ u16 pamp, base, dac, t;
+
+ txpower = limit_value(txpower, 0, 63);
+
+ pamp = b43_get_txgain_freq_power_amp(txpower);
+ pamp <<= 5;
+ pamp &= 0x00E0;
+ b43_phy_write(dev, 0x0019, pamp);
+
+ base = b43_get_txgain_base_band(txpower);
+ base &= 0x000F;
+ b43_phy_write(dev, 0x0017, base | 0x0020);
+
+ t = b43_ofdmtab_read16(dev, 0x3000, 1);
+ t &= 0x0007;
+
+ dac = b43_get_txgain_dac(txpower);
+ dac <<= 3;
+ dac |= t;
+
+ b43_ofdmtab_write16(dev, 0x3000, 1, dac);
+
+ phy->txpwr_offset = txpower;
+
+ //TODO: FuncPlaceholder (Adjust BB loft cancel)
+}
+
+void b43_radio_turn_on(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ int err;
+ u8 channel;
+
+ might_sleep();
+
+ if (phy->radio_on)
+ return;
+
+ switch (phy->type) {
+ case B43_PHYTYPE_A:
+ b43_radio_write16(dev, 0x0004, 0x00C0);
+ b43_radio_write16(dev, 0x0005, 0x0008);
+ b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7);
+ b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7);
+ b43_radio_init2060(dev);
+ break;
+ case B43_PHYTYPE_B:
+ case B43_PHYTYPE_G:
+ b43_phy_write(dev, 0x0015, 0x8000);
+ b43_phy_write(dev, 0x0015, 0xCC00);
+ b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000));
+ if (phy->radio_off_context.valid) {
+ /* Restore the RFover values. */
+ b43_phy_write(dev, B43_PHY_RFOVER,
+ phy->radio_off_context.rfover);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL,
+ phy->radio_off_context.rfoverval);
+ phy->radio_off_context.valid = 0;
+ }
+ channel = phy->channel;
+ err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1);
+ err |= b43_radio_selectchannel(dev, channel, 0);
+ B43_WARN_ON(err);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ phy->radio_on = 1;
+}
+
+void b43_radio_turn_off(struct b43_wldev *dev, bool force)
+{
+ struct b43_phy *phy = &dev->phy;
+
+ if (!phy->radio_on && !force)
+ return;
+
+ if (phy->type == B43_PHYTYPE_A) {
+ b43_radio_write16(dev, 0x0004, 0x00FF);
+ b43_radio_write16(dev, 0x0005, 0x00FB);
+ b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
+ b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
+ }
+ if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) {
+ u16 rfover, rfoverval;
+
+ rfover = b43_phy_read(dev, B43_PHY_RFOVER);
+ rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+ if (!force) {
+ phy->radio_off_context.rfover = rfover;
+ phy->radio_off_context.rfoverval = rfoverval;
+ phy->radio_off_context.valid = 1;
+ }
+ b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
+ b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
+ } else
+ b43_phy_write(dev, 0x0015, 0xAA00);
+ phy->radio_on = 0;
+}
diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h
new file mode 100644
index 00000000000..c64d74504fc
--- /dev/null
+++ b/drivers/net/wireless/b43/phy.h
@@ -0,0 +1,297 @@
+#ifndef B43_PHY_H_
+#define B43_PHY_H_
+
+#include <linux/types.h>
+
+struct b43_wldev;
+struct b43_phy;
+
+/*** PHY Registers ***/
+
+/* Routing */
+#define B43_PHYROUTE_OFDM_GPHY 0x400
+#define B43_PHYROUTE_EXT_GPHY 0x800
+
+/* Base registers. */
+#define B43_PHY_BASE(reg) (reg)
+/* OFDM (A) registers of a G-PHY */
+#define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY)
+/* Extended G-PHY registers */
+#define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY)
+
+/* OFDM (A) PHY Registers */
+#define B43_PHY_VERSION_OFDM B43_PHY_OFDM(0x00) /* Versioning register for A-PHY */
+#define B43_PHY_BBANDCFG B43_PHY_OFDM(0x01) /* Baseband config */
+#define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */
+#define B43_PHY_BBANDCFG_RXANT_SHIFT 7
+#define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */
+#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 */
+#define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */
+#define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */
+#define B43_PHY_CRS0 B43_PHY_OFDM(0x29)
+#define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */
+#define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */
+#define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */
+#define B43_PHY_ENCORE_EN 0x0200 /* Encore enable */
+#define B43_PHY_LMS B43_PHY_OFDM(0x55)
+#define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */
+#define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */
+#define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */
+#define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */
+#define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */
+#define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */
+#define B43_PHY_OTABLENR_SHIFT 10
+#define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */
+#define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */
+#define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */
+#define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */
+#define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */
+#define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */
+#define B43_PHY_CLIPPWRDOWNT B43_PHY_OFDM(0x93) /* Clip powerdown threshold */
+#define B43_PHY_OFDM9B B43_PHY_OFDM(0x9B) /* FIXME rename */
+#define B43_PHY_N1P1GAIN B43_PHY_OFDM(0xA0)
+#define B43_PHY_P1P2GAIN B43_PHY_OFDM(0xA1)
+#define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2)
+#define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3)
+#define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4)
+#define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */
+#define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9)
+#define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA)
+#define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB)
+#define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */
+#define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */
+#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (rev 1 only) */
+#define B43_PHY_CRSTHRES2_R1 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (rev 1 only) */
+#define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */
+#define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */
+#define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */
+
+/* CCK (B) PHY Registers */
+#define B43_PHY_VERSION_CCK B43_PHY_BASE(0x00) /* Versioning register for B-PHY */
+#define B43_PHY_CCKBBANDCFG B43_PHY_BASE(0x01) /* Contains antenna 0/1 control bit */
+#define B43_PHY_PGACTL B43_PHY_BASE(0x15) /* PGA control */
+#define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */
+#define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */
+#define B43_PHY_PGACTL_UNKNOWN 0xEFA0
+#define B43_PHY_FBCTL1 B43_PHY_BASE(0x18) /* Frequency bandwidth control 1 */
+#define B43_PHY_ITSSI B43_PHY_BASE(0x29) /* Idle TSSI */
+#define B43_PHY_LO_LEAKAGE B43_PHY_BASE(0x2D) /* Measured LO leakage */
+#define B43_PHY_ENERGY B43_PHY_BASE(0x33) /* Energy */
+#define B43_PHY_SYNCCTL B43_PHY_BASE(0x35)
+#define B43_PHY_FBCTL2 B43_PHY_BASE(0x38) /* Frequency bandwidth control 2 */
+#define B43_PHY_DACCTL B43_PHY_BASE(0x60) /* DAC control */
+#define B43_PHY_RCCALOVER B43_PHY_BASE(0x78) /* RC calibration override */
+
+/* Extended G-PHY Registers */
+#define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */
+#define B43_PHY_GTABCTL B43_PHY_EXTG(0x03) /* G-PHY table control (see below) */
+#define B43_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */
+#define B43_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */
+#define B43_PHY_GTABNR_SHIFT 10
+#define B43_PHY_GTABDATA B43_PHY_EXTG(0x04) /* G-PHY table data */
+#define B43_PHY_LO_MASK B43_PHY_EXTG(0x0F) /* Local Oscillator control mask */
+#define B43_PHY_LO_CTL B43_PHY_EXTG(0x10) /* Local Oscillator control */
+#define B43_PHY_RFOVER B43_PHY_EXTG(0x11) /* RF override */
+#define B43_PHY_RFOVERVAL B43_PHY_EXTG(0x12) /* RF override value */
+#define B43_PHY_RFOVERVAL_EXTLNA 0x8000
+#define B43_PHY_RFOVERVAL_LNA 0x7000
+#define B43_PHY_RFOVERVAL_LNA_SHIFT 12
+#define B43_PHY_RFOVERVAL_PGA 0x0F00
+#define B43_PHY_RFOVERVAL_PGA_SHIFT 8
+#define B43_PHY_RFOVERVAL_UNK 0x0010 /* Unknown, always set. */
+#define B43_PHY_RFOVERVAL_TRSWRX 0x00E0
+#define B43_PHY_RFOVERVAL_BW 0x0003 /* Bandwidth flags */
+#define B43_PHY_RFOVERVAL_BW_LPF 0x0001 /* Low Pass Filter */
+#define B43_PHY_RFOVERVAL_BW_LBW 0x0002 /* Low Bandwidth (when set), high when unset */
+#define B43_PHY_ANALOGOVER B43_PHY_EXTG(0x14) /* Analog override */
+#define B43_PHY_ANALOGOVERVAL B43_PHY_EXTG(0x15) /* Analog override value */
+
+/*** OFDM table numbers ***/
+#define B43_OFDMTAB(number, offset) (((number) << B43_PHY_OTABLENR_SHIFT) | (offset))
+#define B43_OFDMTAB_AGC1 B43_OFDMTAB(0x00, 0)
+#define B43_OFDMTAB_GAIN0 B43_OFDMTAB(0x00, 0)
+#define B43_OFDMTAB_GAINX B43_OFDMTAB(0x01, 0) //TODO rename
+#define B43_OFDMTAB_GAIN1 B43_OFDMTAB(0x01, 4)
+#define B43_OFDMTAB_AGC3 B43_OFDMTAB(0x02, 0)
+#define B43_OFDMTAB_GAIN2 B43_OFDMTAB(0x02, 3)
+#define B43_OFDMTAB_LNAHPFGAIN1 B43_OFDMTAB(0x03, 0)
+#define B43_OFDMTAB_WRSSI B43_OFDMTAB(0x04, 0)
+#define B43_OFDMTAB_LNAHPFGAIN2 B43_OFDMTAB(0x04, 0)
+#define B43_OFDMTAB_NOISESCALE B43_OFDMTAB(0x05, 0)
+#define B43_OFDMTAB_AGC2 B43_OFDMTAB(0x06, 0)
+#define B43_OFDMTAB_ROTOR B43_OFDMTAB(0x08, 0)
+#define B43_OFDMTAB_ADVRETARD B43_OFDMTAB(0x09, 0)
+#define B43_OFDMTAB_DAC B43_OFDMTAB(0x0C, 0)
+#define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7)
+#define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12)
+#define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13)
+//TODO
+#define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12)
+#define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0)
+//TODO
+#define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0)
+#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO rename
+#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 1)
+#define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0)
+#define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4)
+#define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0)
+#define B43_OFDMTAB_DACRFPABB B43_OFDMTAB(0x16, 0)
+#define B43_OFDMTAB_DACOFF B43_OFDMTAB(0x17, 0)
+#define B43_OFDMTAB_DCBIAS B43_OFDMTAB(0x18, 0)
+
+u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset);
+void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
+ u16 offset, u16 value);
+u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset);
+void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
+ u16 offset, u32 value);
+
+/*** G-PHY table numbers */
+#define B43_GTAB(number, offset) (((number) << B43_PHY_GTABNR_SHIFT) | (offset))
+#define B43_GTAB_NRSSI B43_GTAB(0x00, 0)
+#define B43_GTAB_TRFEMW B43_GTAB(0x0C, 0x120)
+#define B43_GTAB_ORIGTR B43_GTAB(0x2E, 0x298)
+
+u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset); //TODO implement
+void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value); //TODO implement
+
+#define B43_DEFAULT_CHANNEL_A 36
+#define B43_DEFAULT_CHANNEL_BG 6
+
+enum {
+ B43_ANTENNA0, /* Antenna 0 */
+ B43_ANTENNA1, /* Antenna 0 */
+ B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
+ B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
+
+ B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
+ B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
+};
+
+enum {
+ B43_INTERFMODE_NONE,
+ B43_INTERFMODE_NONWLAN,
+ B43_INTERFMODE_MANUALWLAN,
+ B43_INTERFMODE_AUTOWLAN,
+};
+
+/* Masks for the different PHY versioning registers. */
+#define B43_PHYVER_ANALOG 0xF000
+#define B43_PHYVER_ANALOG_SHIFT 12
+#define B43_PHYVER_TYPE 0x0F00
+#define B43_PHYVER_TYPE_SHIFT 8
+#define B43_PHYVER_VERSION 0x00FF
+
+void b43_raw_phy_lock(struct b43_wldev *dev);
+#define b43_phy_lock(dev, flags) \
+ do { \
+ local_irq_save(flags); \
+ b43_raw_phy_lock(dev); \
+ } while (0)
+void b43_raw_phy_unlock(struct b43_wldev *dev);
+#define b43_phy_unlock(dev, flags) \
+ do { \
+ b43_raw_phy_unlock(dev); \
+ local_irq_restore(flags); \
+ } while (0)
+
+u16 b43_phy_read(struct b43_wldev *dev, u16 offset);
+void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val);
+
+int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev);
+
+void b43_phy_early_init(struct b43_wldev *dev);
+int b43_phy_init(struct b43_wldev *dev);
+
+void b43_set_rx_antenna(struct b43_wldev *dev, int antenna);
+
+void b43_phy_xmitpower(struct b43_wldev *dev);
+void b43_gphy_dc_lt_init(struct b43_wldev *dev);
+
+/* Returns the boolean whether the board has HardwarePowerControl */
+bool b43_has_hardware_pctl(struct b43_phy *phy);
+/* Returns the boolean whether "TX Magnification" is enabled. */
+#define has_tx_magnification(phy) \
+ (((phy)->rev >= 2) && \
+ ((phy)->radio_ver == 0x2050) && \
+ ((phy)->radio_rev == 8))
+/* Card uses the loopback gain stuff */
+#define has_loopback_gain(phy) \
+ (((phy)->rev > 1) || ((phy)->gmode))
+
+/* Radio Attenuation (RF Attenuation) */
+struct b43_rfatt {
+ u8 att; /* Attenuation value */
+ bool with_padmix; /* Flag, PAD Mixer enabled. */
+};
+struct b43_rfatt_list {
+ /* Attenuation values list */
+ const struct b43_rfatt *list;
+ u8 len;
+ /* Minimum/Maximum attenuation values */
+ u8 min_val;
+ u8 max_val;
+};
+
+/* Baseband Attenuation */
+struct b43_bbatt {
+ u8 att; /* Attenuation value */
+};
+struct b43_bbatt_list {
+ /* Attenuation values list */
+ const struct b43_bbatt *list;
+ u8 len;
+ /* Minimum/Maximum attenuation values */
+ u8 min_val;
+ u8 max_val;
+};
+
+/* tx_control bits. */
+#define B43_TXCTL_PA3DB 0x40 /* PA Gain 3dB */
+#define B43_TXCTL_PA2DB 0x20 /* PA Gain 2dB */
+#define B43_TXCTL_TXMIX 0x10 /* TX Mixer Gain */
+
+/* Write BasebandAttenuation value to the device. */
+void b43_phy_set_baseband_attenuation(struct b43_wldev *dev,
+ u16 baseband_attenuation);
+
+extern const u8 b43_radio_channel_codes_bg[];
+
+void b43_radio_lock(struct b43_wldev *dev);
+void b43_radio_unlock(struct b43_wldev *dev);
+
+u16 b43_radio_read16(struct b43_wldev *dev, u16 offset);
+void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val);
+
+u16 b43_radio_init2050(struct b43_wldev *dev);
+void b43_radio_init2060(struct b43_wldev *dev);
+
+void b43_radio_turn_on(struct b43_wldev *dev);
+void b43_radio_turn_off(struct b43_wldev *dev, bool force);
+
+int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel,
+ int synthetic_pu_workaround);
+
+u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel);
+u8 b43_radio_aci_scan(struct b43_wldev *dev);
+
+int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode);
+
+void b43_calc_nrssi_slope(struct b43_wldev *dev);
+void b43_calc_nrssi_threshold(struct b43_wldev *dev);
+s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset);
+void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val);
+void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val);
+void b43_nrssi_mem_update(struct b43_wldev *dev);
+
+void b43_radio_set_tx_iq(struct b43_wldev *dev);
+u16 b43_radio_calibrationvalue(struct b43_wldev *dev);
+
+void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
+ int *_bbatt, int *_rfatt);
+
+void b43_set_txpower_g(struct b43_wldev *dev,
+ const struct b43_bbatt *bbatt,
+ const struct b43_rfatt *rfatt, u8 tx_control);
+
+#endif /* B43_PHY_H_ */
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
new file mode 100644
index 00000000000..67752a28eb9
--- /dev/null
+++ b/drivers/net/wireless/b43/pio.c
@@ -0,0 +1,652 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ PIO Transmission
+
+ Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "pio.h"
+#include "main.h"
+#include "xmit.h"
+
+#include <linux/delay.h>
+
+static void tx_start(struct b43_pioqueue *queue)
+{
+ b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_INIT);
+}
+
+static void tx_octet(struct b43_pioqueue *queue, u8 octet)
+{
+ if (queue->need_workarounds) {
+ b43_pio_write(queue, B43_PIO_TXDATA, octet);
+ b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
+ } else {
+ b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
+ b43_pio_write(queue, B43_PIO_TXDATA, octet);
+ }
+}
+
+static u16 tx_get_next_word(const u8 * txhdr,
+ const u8 * packet,
+ size_t txhdr_size, unsigned int *pos)
+{
+ const u8 *source;
+ unsigned int i = *pos;
+ u16 ret;
+
+ if (i < txhdr_size) {
+ source = txhdr;
+ } else {
+ source = packet;
+ i -= txhdr_size;
+ }
+ ret = le16_to_cpu(*((__le16 *)(source + i)));
+ *pos += 2;
+
+ return ret;
+}
+
+static void tx_data(struct b43_pioqueue *queue,
+ u8 * txhdr, const u8 * packet, unsigned int octets)
+{
+ u16 data;
+ unsigned int i = 0;
+
+ if (queue->need_workarounds) {
+ data = tx_get_next_word(txhdr, packet,
+ sizeof(struct b43_txhdr_fw4), &i);
+ b43_pio_write(queue, B43_PIO_TXDATA, data);
+ }
+ b43_pio_write(queue, B43_PIO_TXCTL,
+ B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI);
+ while (i < octets - 1) {
+ data = tx_get_next_word(txhdr, packet,
+ sizeof(struct b43_txhdr_fw4), &i);
+ b43_pio_write(queue, B43_PIO_TXDATA, data);
+ }
+ if (octets % 2)
+ tx_octet(queue,
+ packet[octets - sizeof(struct b43_txhdr_fw4) - 1]);
+}
+
+static void tx_complete(struct b43_pioqueue *queue, struct sk_buff *skb)
+{
+ if (queue->need_workarounds) {
+ b43_pio_write(queue, B43_PIO_TXDATA, skb->data[skb->len - 1]);
+ b43_pio_write(queue, B43_PIO_TXCTL,
+ B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_COMPLETE);
+ } else {
+ b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_COMPLETE);
+ }
+}
+
+static u16 generate_cookie(struct b43_pioqueue *queue,
+ struct b43_pio_txpacket *packet)
+{
+ u16 cookie = 0x0000;
+ u16 packetindex;
+
+ /* We use the upper 4 bits for the PIO
+ * controller ID and the lower 12 bits
+ * for the packet index (in the cache).
+ */
+ switch (queue->mmio_base) {
+ case B43_MMIO_PIO1_BASE:
+ break;
+ case B43_MMIO_PIO2_BASE:
+ cookie = 0x1000;
+ break;
+ case B43_MMIO_PIO3_BASE:
+ cookie = 0x2000;
+ break;
+ case B43_MMIO_PIO4_BASE:
+ cookie = 0x3000;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ packetindex = packet->index;
+ B43_WARN_ON(packetindex & ~0x0FFF);
+ cookie |= (u16) packetindex;
+
+ return cookie;
+}
+
+static
+struct b43_pioqueue *parse_cookie(struct b43_wldev *dev,
+ u16 cookie, struct b43_pio_txpacket **packet)
+{
+ struct b43_pio *pio = &dev->pio;
+ struct b43_pioqueue *queue = NULL;
+ int packetindex;
+
+ switch (cookie & 0xF000) {
+ case 0x0000:
+ queue = pio->queue0;
+ break;
+ case 0x1000:
+ queue = pio->queue1;
+ break;
+ case 0x2000:
+ queue = pio->queue2;
+ break;
+ case 0x3000:
+ queue = pio->queue3;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+ packetindex = (cookie & 0x0FFF);
+ B43_WARN_ON(!(packetindex >= 0 && packetindex < B43_PIO_MAXTXPACKETS));
+ *packet = &(queue->tx_packets_cache[packetindex]);
+
+ return queue;
+}
+
+union txhdr_union {
+ struct b43_txhdr_fw4 txhdr_fw4;
+};
+
+static void pio_tx_write_fragment(struct b43_pioqueue *queue,
+ struct sk_buff *skb,
+ struct b43_pio_txpacket *packet,
+ size_t txhdr_size)
+{
+ union txhdr_union txhdr_data;
+ u8 *txhdr = NULL;
+ unsigned int octets;
+
+ txhdr = (u8 *) (&txhdr_data.txhdr_fw4);
+
+ B43_WARN_ON(skb_shinfo(skb)->nr_frags);
+ b43_generate_txhdr(queue->dev,
+ txhdr, skb->data, skb->len,
+ &packet->txstat.control,
+ generate_cookie(queue, packet));
+
+ tx_start(queue);
+ octets = skb->len + txhdr_size;
+ if (queue->need_workarounds)
+ octets--;
+ tx_data(queue, txhdr, (u8 *) skb->data, octets);
+ tx_complete(queue, skb);
+}
+
+static void free_txpacket(struct b43_pio_txpacket *packet)
+{
+ struct b43_pioqueue *queue = packet->queue;
+
+ if (packet->skb)
+ dev_kfree_skb_any(packet->skb);
+ list_move(&packet->list, &queue->txfree);
+ queue->nr_txfree++;
+}
+
+static int pio_tx_packet(struct b43_pio_txpacket *packet)
+{
+ struct b43_pioqueue *queue = packet->queue;
+ struct sk_buff *skb = packet->skb;
+ u16 octets;
+
+ octets = (u16) skb->len + sizeof(struct b43_txhdr_fw4);
+ if (queue->tx_devq_size < octets) {
+ b43warn(queue->dev->wl, "PIO queue too small. "
+ "Dropping packet.\n");
+ /* Drop it silently (return success) */
+ free_txpacket(packet);
+ return 0;
+ }
+ B43_WARN_ON(queue->tx_devq_packets > B43_PIO_MAXTXDEVQPACKETS);
+ B43_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
+ /* Check if there is sufficient free space on the device
+ * TX queue. If not, return and let the TX tasklet
+ * retry later.
+ */
+ if (queue->tx_devq_packets == B43_PIO_MAXTXDEVQPACKETS)
+ return -EBUSY;
+ if (queue->tx_devq_used + octets > queue->tx_devq_size)
+ return -EBUSY;
+ /* Now poke the device. */
+ pio_tx_write_fragment(queue, skb, packet, sizeof(struct b43_txhdr_fw4));
+
+ /* Account for the packet size.
+ * (We must not overflow the device TX queue)
+ */
+ queue->tx_devq_packets++;
+ queue->tx_devq_used += octets;
+
+ /* Transmission started, everything ok, move the
+ * packet to the txrunning list.
+ */
+ list_move_tail(&packet->list, &queue->txrunning);
+
+ return 0;
+}
+
+static void tx_tasklet(unsigned long d)
+{
+ struct b43_pioqueue *queue = (struct b43_pioqueue *)d;
+ struct b43_wldev *dev = queue->dev;
+ unsigned long flags;
+ struct b43_pio_txpacket *packet, *tmp_packet;
+ int err;
+ u16 txctl;
+
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+ if (queue->tx_frozen)
+ goto out_unlock;
+ txctl = b43_pio_read(queue, B43_PIO_TXCTL);
+ if (txctl & B43_PIO_TXCTL_SUSPEND)
+ goto out_unlock;
+
+ list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
+ /* Try to transmit the packet. This can fail, if
+ * the device queue is full. In case of failure, the
+ * packet is left in the txqueue.
+ * If transmission succeed, the packet is moved to txrunning.
+ * If it is impossible to transmit the packet, it
+ * is dropped.
+ */
+ err = pio_tx_packet(packet);
+ if (err)
+ break;
+ }
+ out_unlock:
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+}
+
+static void setup_txqueues(struct b43_pioqueue *queue)
+{
+ struct b43_pio_txpacket *packet;
+ int i;
+
+ queue->nr_txfree = B43_PIO_MAXTXPACKETS;
+ for (i = 0; i < B43_PIO_MAXTXPACKETS; i++) {
+ packet = &(queue->tx_packets_cache[i]);
+
+ packet->queue = queue;
+ INIT_LIST_HEAD(&packet->list);
+ packet->index = i;
+
+ list_add(&packet->list, &queue->txfree);
+ }
+}
+
+static
+struct b43_pioqueue *b43_setup_pioqueue(struct b43_wldev *dev,
+ u16 pio_mmio_base)
+{
+ struct b43_pioqueue *queue;
+ u16 qsize;
+
+ queue = kzalloc(sizeof(*queue), GFP_KERNEL);
+ if (!queue)
+ goto out;
+
+ queue->dev = dev;
+ queue->mmio_base = pio_mmio_base;
+ queue->need_workarounds = (dev->dev->id.revision < 3);
+
+ INIT_LIST_HEAD(&queue->txfree);
+ INIT_LIST_HEAD(&queue->txqueue);
+ INIT_LIST_HEAD(&queue->txrunning);
+ tasklet_init(&queue->txtask, tx_tasklet, (unsigned long)queue);
+
+ b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
+ & ~B43_MACCTL_BE);
+
+ qsize = b43_read16(dev, queue->mmio_base + B43_PIO_TXQBUFSIZE);
+ if (qsize == 0) {
+ b43err(dev->wl, "This card does not support PIO "
+ "operation mode. Please use DMA mode "
+ "(module parameter pio=0).\n");
+ goto err_freequeue;
+ }
+ if (qsize <= B43_PIO_TXQADJUST) {
+ b43err(dev->wl, "PIO tx device-queue too small (%u)\n", qsize);
+ goto err_freequeue;
+ }
+ qsize -= B43_PIO_TXQADJUST;
+ queue->tx_devq_size = qsize;
+
+ setup_txqueues(queue);
+
+ out:
+ return queue;
+
+ err_freequeue:
+ kfree(queue);
+ queue = NULL;
+ goto out;
+}
+
+static void cancel_transfers(struct b43_pioqueue *queue)
+{
+ struct b43_pio_txpacket *packet, *tmp_packet;
+
+ tasklet_disable(&queue->txtask);
+
+ list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
+ free_txpacket(packet);
+ list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
+ free_txpacket(packet);
+}
+
+static void b43_destroy_pioqueue(struct b43_pioqueue *queue)
+{
+ if (!queue)
+ return;
+
+ cancel_transfers(queue);
+ kfree(queue);
+}
+
+void b43_pio_free(struct b43_wldev *dev)
+{
+ struct b43_pio *pio;
+
+ if (!b43_using_pio(dev))
+ return;
+ pio = &dev->pio;
+
+ b43_destroy_pioqueue(pio->queue3);
+ pio->queue3 = NULL;
+ b43_destroy_pioqueue(pio->queue2);
+ pio->queue2 = NULL;
+ b43_destroy_pioqueue(pio->queue1);
+ pio->queue1 = NULL;
+ b43_destroy_pioqueue(pio->queue0);
+ pio->queue0 = NULL;
+}
+
+int b43_pio_init(struct b43_wldev *dev)
+{
+ struct b43_pio *pio = &dev->pio;
+ struct b43_pioqueue *queue;
+ int err = -ENOMEM;
+
+ queue = b43_setup_pioqueue(dev, B43_MMIO_PIO1_BASE);
+ if (!queue)
+ goto out;
+ pio->queue0 = queue;
+
+ queue = b43_setup_pioqueue(dev, B43_MMIO_PIO2_BASE);
+ if (!queue)
+ goto err_destroy0;
+ pio->queue1 = queue;
+
+ queue = b43_setup_pioqueue(dev, B43_MMIO_PIO3_BASE);
+ if (!queue)
+ goto err_destroy1;
+ pio->queue2 = queue;
+
+ queue = b43_setup_pioqueue(dev, B43_MMIO_PIO4_BASE);
+ if (!queue)
+ goto err_destroy2;
+ pio->queue3 = queue;
+
+ if (dev->dev->id.revision < 3)
+ dev->irq_savedstate |= B43_IRQ_PIO_WORKAROUND;
+
+ b43dbg(dev->wl, "PIO initialized\n");
+ err = 0;
+ out:
+ return err;
+
+ err_destroy2:
+ b43_destroy_pioqueue(pio->queue2);
+ pio->queue2 = NULL;
+ err_destroy1:
+ b43_destroy_pioqueue(pio->queue1);
+ pio->queue1 = NULL;
+ err_destroy0:
+ b43_destroy_pioqueue(pio->queue0);
+ pio->queue0 = NULL;
+ goto out;
+}
+
+int b43_pio_tx(struct b43_wldev *dev,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ struct b43_pioqueue *queue = dev->pio.queue1;
+ struct b43_pio_txpacket *packet;
+
+ B43_WARN_ON(queue->tx_suspended);
+ B43_WARN_ON(list_empty(&queue->txfree));
+
+ packet = list_entry(queue->txfree.next, struct b43_pio_txpacket, list);
+ packet->skb = skb;
+
+ memset(&packet->txstat, 0, sizeof(packet->txstat));
+ memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
+
+ list_move_tail(&packet->list, &queue->txqueue);
+ queue->nr_txfree--;
+ queue->nr_tx_packets++;
+ B43_WARN_ON(queue->nr_txfree >= B43_PIO_MAXTXPACKETS);
+
+ tasklet_schedule(&queue->txtask);
+
+ return 0;
+}
+
+void b43_pio_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+ struct b43_pioqueue *queue;
+ struct b43_pio_txpacket *packet;
+
+ queue = parse_cookie(dev, status->cookie, &packet);
+ if (B43_WARN_ON(!queue))
+ return;
+
+ queue->tx_devq_packets--;
+ queue->tx_devq_used -=
+ (packet->skb->len + sizeof(struct b43_txhdr_fw4));
+
+ if (status->acked) {
+ packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+ } else {
+ if (!(packet->txstat.control.flags & IEEE80211_TXCTL_NO_ACK))
+ packet->txstat.excessive_retries = 1;
+ }
+ if (status->frame_count == 0) {
+ /* The frame was not transmitted at all. */
+ packet->txstat.retry_count = 0;
+ } else
+ packet->txstat.retry_count = status->frame_count - 1;
+ ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
+ &(packet->txstat));
+ packet->skb = NULL;
+
+ free_txpacket(packet);
+ /* If there are packets on the txqueue, poke the tasklet
+ * to transmit them.
+ */
+ if (!list_empty(&queue->txqueue))
+ tasklet_schedule(&queue->txtask);
+}
+
+void b43_pio_get_tx_stats(struct b43_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct b43_pio *pio = &dev->pio;
+ struct b43_pioqueue *queue;
+ struct ieee80211_tx_queue_stats_data *data;
+
+ queue = pio->queue1;
+ data = &(stats->data[0]);
+ data->len = B43_PIO_MAXTXPACKETS - queue->nr_txfree;
+ data->limit = B43_PIO_MAXTXPACKETS;
+ data->count = queue->nr_tx_packets;
+}
+
+static void pio_rx_error(struct b43_pioqueue *queue,
+ int clear_buffers, const char *error)
+{
+ int i;
+
+ b43err(queue->dev->wl, "PIO RX error: %s\n", error);
+ b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_READY);
+ if (clear_buffers) {
+ B43_WARN_ON(queue->mmio_base != B43_MMIO_PIO1_BASE);
+ for (i = 0; i < 15; i++) {
+ /* Dummy read. */
+ b43_pio_read(queue, B43_PIO_RXDATA);
+ }
+ }
+}
+
+void b43_pio_rx(struct b43_pioqueue *queue)
+{
+ __le16 preamble[21] = { 0 };
+ struct b43_rxhdr_fw4 *rxhdr;
+ u16 tmp, len;
+ u32 macstat;
+ int i, preamble_readwords;
+ struct sk_buff *skb;
+
+ tmp = b43_pio_read(queue, B43_PIO_RXCTL);
+ if (!(tmp & B43_PIO_RXCTL_DATAAVAILABLE))
+ return;
+ b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_DATAAVAILABLE);
+
+ for (i = 0; i < 10; i++) {
+ tmp = b43_pio_read(queue, B43_PIO_RXCTL);
+ if (tmp & B43_PIO_RXCTL_READY)
+ goto data_ready;
+ udelay(10);
+ }
+ b43dbg(queue->dev->wl, "PIO RX timed out\n");
+ return;
+data_ready:
+
+ len = b43_pio_read(queue, B43_PIO_RXDATA);
+ if (unlikely(len > 0x700)) {
+ pio_rx_error(queue, 0, "len > 0x700");
+ return;
+ }
+ if (unlikely(len == 0 && queue->mmio_base != B43_MMIO_PIO4_BASE)) {
+ pio_rx_error(queue, 0, "len == 0");
+ return;
+ }
+ preamble[0] = cpu_to_le16(len);
+ if (queue->mmio_base == B43_MMIO_PIO4_BASE)
+ preamble_readwords = 14 / sizeof(u16);
+ else
+ preamble_readwords = 18 / sizeof(u16);
+ for (i = 0; i < preamble_readwords; i++) {
+ tmp = b43_pio_read(queue, B43_PIO_RXDATA);
+ preamble[i + 1] = cpu_to_le16(tmp);
+ }
+ rxhdr = (struct b43_rxhdr_fw4 *)preamble;
+ macstat = le32_to_cpu(rxhdr->mac_status);
+ if (macstat & B43_RX_MAC_FCSERR) {
+ pio_rx_error(queue,
+ (queue->mmio_base == B43_MMIO_PIO1_BASE),
+ "Frame FCS error");
+ return;
+ }
+ if (queue->mmio_base == B43_MMIO_PIO4_BASE) {
+ /* We received an xmit status. */
+ struct b43_hwtxstatus *hw;
+
+ hw = (struct b43_hwtxstatus *)(preamble + 1);
+ b43_handle_hwtxstatus(queue->dev, hw);
+
+ return;
+ }
+
+ skb = dev_alloc_skb(len);
+ if (unlikely(!skb)) {
+ pio_rx_error(queue, 1, "OOM");
+ return;
+ }
+ skb_put(skb, len);
+ for (i = 0; i < len - 1; i += 2) {
+ tmp = b43_pio_read(queue, B43_PIO_RXDATA);
+ *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
+ }
+ if (len % 2) {
+ tmp = b43_pio_read(queue, B43_PIO_RXDATA);
+ skb->data[len - 1] = (tmp & 0x00FF);
+/* The specs say the following is required, but
+ * it is wrong and corrupts the PLCP. If we don't do
+ * this, the PLCP seems to be correct. So ifdef it out for now.
+ */
+#if 0
+ if (rxflags2 & B43_RXHDR_FLAGS2_TYPE2FRAME)
+ skb->data[2] = (tmp & 0xFF00) >> 8;
+ else
+ skb->data[0] = (tmp & 0xFF00) >> 8;
+#endif
+ }
+ b43_rx(queue->dev, skb, rxhdr);
+}
+
+void b43_pio_tx_suspend(struct b43_pioqueue *queue)
+{
+ b43_power_saving_ctl_bits(queue->dev, B43_PS_AWAKE);
+ b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
+ | B43_PIO_TXCTL_SUSPEND);
+}
+
+void b43_pio_tx_resume(struct b43_pioqueue *queue)
+{
+ b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
+ & ~B43_PIO_TXCTL_SUSPEND);
+ b43_power_saving_ctl_bits(queue->dev, 0);
+ tasklet_schedule(&queue->txtask);
+}
+
+void b43_pio_freeze_txqueues(struct b43_wldev *dev)
+{
+ struct b43_pio *pio;
+
+ B43_WARN_ON(!b43_using_pio(dev));
+ pio = &dev->pio;
+ pio->queue0->tx_frozen = 1;
+ pio->queue1->tx_frozen = 1;
+ pio->queue2->tx_frozen = 1;
+ pio->queue3->tx_frozen = 1;
+}
+
+void b43_pio_thaw_txqueues(struct b43_wldev *dev)
+{
+ struct b43_pio *pio;
+
+ B43_WARN_ON(!b43_using_pio(dev));
+ pio = &dev->pio;
+ pio->queue0->tx_frozen = 0;
+ pio->queue1->tx_frozen = 0;
+ pio->queue2->tx_frozen = 0;
+ pio->queue3->tx_frozen = 0;
+ if (!list_empty(&pio->queue0->txqueue))
+ tasklet_schedule(&pio->queue0->txtask);
+ if (!list_empty(&pio->queue1->txqueue))
+ tasklet_schedule(&pio->queue1->txtask);
+ if (!list_empty(&pio->queue2->txqueue))
+ tasklet_schedule(&pio->queue2->txtask);
+ if (!list_empty(&pio->queue3->txqueue))
+ tasklet_schedule(&pio->queue3->txtask);
+}
diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h
new file mode 100644
index 00000000000..3488f2447bb
--- /dev/null
+++ b/drivers/net/wireless/b43/pio.h
@@ -0,0 +1,153 @@
+#ifndef B43_PIO_H_
+#define B43_PIO_H_
+
+#include "b43.h"
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+#define B43_PIO_TXCTL 0x00
+#define B43_PIO_TXDATA 0x02
+#define B43_PIO_TXQBUFSIZE 0x04
+#define B43_PIO_RXCTL 0x08
+#define B43_PIO_RXDATA 0x0A
+
+#define B43_PIO_TXCTL_WRITELO (1 << 0)
+#define B43_PIO_TXCTL_WRITEHI (1 << 1)
+#define B43_PIO_TXCTL_COMPLETE (1 << 2)
+#define B43_PIO_TXCTL_INIT (1 << 3)
+#define B43_PIO_TXCTL_SUSPEND (1 << 7)
+
+#define B43_PIO_RXCTL_DATAAVAILABLE (1 << 0)
+#define B43_PIO_RXCTL_READY (1 << 1)
+
+/* PIO constants */
+#define B43_PIO_MAXTXDEVQPACKETS 31
+#define B43_PIO_TXQADJUST 80
+
+/* PIO tuning knobs */
+#define B43_PIO_MAXTXPACKETS 256
+
+#ifdef CONFIG_B43_PIO
+
+struct b43_pioqueue;
+struct b43_xmitstatus;
+
+struct b43_pio_txpacket {
+ struct b43_pioqueue *queue;
+ struct sk_buff *skb;
+ struct ieee80211_tx_status txstat;
+ struct list_head list;
+ u16 index; /* Index in the tx_packets_cache */
+};
+
+struct b43_pioqueue {
+ struct b43_wldev *dev;
+ u16 mmio_base;
+
+ bool tx_suspended;
+ bool tx_frozen;
+ bool need_workarounds; /* Workarounds needed for core.rev < 3 */
+
+ /* Adjusted size of the device internal TX buffer. */
+ u16 tx_devq_size;
+ /* Used octets of the device internal TX buffer. */
+ u16 tx_devq_used;
+ /* Used packet slots in the device internal TX buffer. */
+ u8 tx_devq_packets;
+ /* Packets from the txfree list can
+ * be taken on incoming TX requests.
+ */
+ struct list_head txfree;
+ unsigned int nr_txfree;
+ /* Packets on the txqueue are queued,
+ * but not completely written to the chip, yet.
+ */
+ struct list_head txqueue;
+ /* Packets on the txrunning queue are completely
+ * posted to the device. We are waiting for the txstatus.
+ */
+ struct list_head txrunning;
+ /* Total number or packets sent.
+ * (This counter can obviously wrap).
+ */
+ unsigned int nr_tx_packets;
+ struct tasklet_struct txtask;
+ struct b43_pio_txpacket tx_packets_cache[B43_PIO_MAXTXPACKETS];
+};
+
+static inline u16 b43_pio_read(struct b43_pioqueue *queue, u16 offset)
+{
+ return b43_read16(queue->dev, queue->mmio_base + offset);
+}
+
+static inline
+ void b43_pio_write(struct b43_pioqueue *queue, u16 offset, u16 value)
+{
+ b43_write16(queue->dev, queue->mmio_base + offset, value);
+ mmiowb();
+}
+
+int b43_pio_init(struct b43_wldev *dev);
+void b43_pio_free(struct b43_wldev *dev);
+
+int b43_pio_tx(struct b43_wldev *dev,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl);
+void b43_pio_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status);
+void b43_pio_get_tx_stats(struct b43_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats);
+void b43_pio_rx(struct b43_pioqueue *queue);
+
+/* Suspend TX queue in hardware. */
+void b43_pio_tx_suspend(struct b43_pioqueue *queue);
+void b43_pio_tx_resume(struct b43_pioqueue *queue);
+/* Suspend (freeze) the TX tasklet (software level). */
+void b43_pio_freeze_txqueues(struct b43_wldev *dev);
+void b43_pio_thaw_txqueues(struct b43_wldev *dev);
+
+#else /* CONFIG_B43_PIO */
+
+static inline int b43_pio_init(struct b43_wldev *dev)
+{
+ return 0;
+}
+static inline void b43_pio_free(struct b43_wldev *dev)
+{
+}
+static inline
+ int b43_pio_tx(struct b43_wldev *dev,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ return 0;
+}
+static inline
+ void b43_pio_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+}
+static inline
+ void b43_pio_get_tx_stats(struct b43_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+}
+static inline void b43_pio_rx(struct b43_pioqueue *queue)
+{
+}
+static inline void b43_pio_tx_suspend(struct b43_pioqueue *queue)
+{
+}
+static inline void b43_pio_tx_resume(struct b43_pioqueue *queue)
+{
+}
+static inline void b43_pio_freeze_txqueues(struct b43_wldev *dev)
+{
+}
+static inline void b43_pio_thaw_txqueues(struct b43_wldev *dev)
+{
+}
+
+#endif /* CONFIG_B43_PIO */
+#endif /* B43_PIO_H_ */
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
new file mode 100644
index 00000000000..9b1f905ffbf
--- /dev/null
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -0,0 +1,173 @@
+/*
+
+ Broadcom B43 wireless driver
+ RFKILL support
+
+ Copyright (c) 2007 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "rfkill.h"
+#include "b43.h"
+
+
+/* Returns TRUE, if the radio is enabled in hardware. */
+static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
+{
+ if (dev->phy.rev >= 3) {
+ if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI)
+ & B43_MMIO_RADIO_HWENABLED_HI_MASK))
+ return 1;
+ } else {
+ if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO)
+ & B43_MMIO_RADIO_HWENABLED_LO_MASK)
+ return 1;
+ }
+ return 0;
+}
+
+/* The poll callback for the hardware button. */
+static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
+{
+ struct b43_wldev *dev = poll_dev->private;
+ struct b43_wl *wl = dev->wl;
+ bool enabled;
+ bool report_change = 0;
+
+ mutex_lock(&wl->mutex);
+ B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
+ enabled = b43_is_hw_radio_enabled(dev);
+ if (unlikely(enabled != dev->radio_hw_enable)) {
+ dev->radio_hw_enable = enabled;
+ report_change = 1;
+ b43info(wl, "Radio hardware status changed to %s\n",
+ enabled ? "ENABLED" : "DISABLED");
+ }
+ mutex_unlock(&wl->mutex);
+
+ if (unlikely(report_change))
+ input_report_key(poll_dev->input, KEY_WLAN, enabled);
+}
+
+/* Called when the RFKILL toggled in software. */
+static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
+{
+ struct b43_wldev *dev = data;
+ struct b43_wl *wl = dev->wl;
+ int err = 0;
+
+ if (!wl->rfkill.registered)
+ return 0;
+
+ mutex_lock(&wl->mutex);
+ B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
+ switch (state) {
+ case RFKILL_STATE_ON:
+ if (!dev->radio_hw_enable) {
+ /* No luck. We can't toggle the hardware RF-kill
+ * button from software. */
+ err = -EBUSY;
+ goto out_unlock;
+ }
+ if (!dev->phy.radio_on)
+ b43_radio_turn_on(dev);
+ break;
+ case RFKILL_STATE_OFF:
+ if (dev->phy.radio_on)
+ b43_radio_turn_off(dev, 0);
+ break;
+ }
+out_unlock:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+char * b43_rfkill_led_name(struct b43_wldev *dev)
+{
+ struct b43_rfkill *rfk = &(dev->wl->rfkill);
+
+ if (!rfk->registered)
+ return NULL;
+ return rfkill_get_led_name(rfk->rfkill);
+}
+
+void b43_rfkill_init(struct b43_wldev *dev)
+{
+ struct b43_wl *wl = dev->wl;
+ struct b43_rfkill *rfk = &(wl->rfkill);
+ int err;
+
+ rfk->registered = 0;
+
+ rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
+ if (!rfk->rfkill)
+ goto out_error;
+ snprintf(rfk->name, sizeof(rfk->name),
+ "b43-%s", wiphy_name(wl->hw->wiphy));
+ rfk->rfkill->name = rfk->name;
+ rfk->rfkill->state = RFKILL_STATE_ON;
+ rfk->rfkill->data = dev;
+ rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle;
+ rfk->rfkill->user_claim_unsupported = 1;
+
+ rfk->poll_dev = input_allocate_polled_device();
+ if (!rfk->poll_dev)
+ goto err_free_rfk;
+ rfk->poll_dev->private = dev;
+ rfk->poll_dev->poll = b43_rfkill_poll;
+ rfk->poll_dev->poll_interval = 1000; /* msecs */
+
+ err = rfkill_register(rfk->rfkill);
+ if (err)
+ goto err_free_polldev;
+ err = input_register_polled_device(rfk->poll_dev);
+ if (err)
+ goto err_unreg_rfk;
+
+ rfk->registered = 1;
+
+ return;
+err_unreg_rfk:
+ rfkill_unregister(rfk->rfkill);
+err_free_polldev:
+ input_free_polled_device(rfk->poll_dev);
+ rfk->poll_dev = NULL;
+err_free_rfk:
+ rfkill_free(rfk->rfkill);
+ rfk->rfkill = NULL;
+out_error:
+ rfk->registered = 0;
+ b43warn(wl, "RF-kill button init failed\n");
+}
+
+void b43_rfkill_exit(struct b43_wldev *dev)
+{
+ struct b43_rfkill *rfk = &(dev->wl->rfkill);
+
+ if (!rfk->registered)
+ return;
+ rfk->registered = 0;
+
+ input_unregister_polled_device(rfk->poll_dev);
+ rfkill_unregister(rfk->rfkill);
+ input_free_polled_device(rfk->poll_dev);
+ rfk->poll_dev = NULL;
+ rfkill_free(rfk->rfkill);
+ rfk->rfkill = NULL;
+}
diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h
new file mode 100644
index 00000000000..adacf936d81
--- /dev/null
+++ b/drivers/net/wireless/b43/rfkill.h
@@ -0,0 +1,52 @@
+#ifndef B43_RFKILL_H_
+#define B43_RFKILL_H_
+
+struct b43_wldev;
+
+
+#ifdef CONFIG_B43_RFKILL
+
+#include <linux/rfkill.h>
+#include <linux/input-polldev.h>
+
+
+struct b43_rfkill {
+ /* The RFKILL subsystem data structure */
+ struct rfkill *rfkill;
+ /* The poll device for the RFKILL input button */
+ struct input_polled_dev *poll_dev;
+ /* Did initialization succeed? Used for freeing. */
+ bool registered;
+ /* The unique name of this rfkill switch */
+ char name[sizeof("b43-phy4294967295")];
+};
+
+/* The init function returns void, because we are not interested
+ * in failing the b43 init process when rfkill init failed. */
+void b43_rfkill_init(struct b43_wldev *dev);
+void b43_rfkill_exit(struct b43_wldev *dev);
+
+char * b43_rfkill_led_name(struct b43_wldev *dev);
+
+
+#else /* CONFIG_B43_RFKILL */
+/* No RFKILL support. */
+
+struct b43_rfkill {
+ /* empty */
+};
+
+static inline void b43_rfkill_init(struct b43_wldev *dev)
+{
+}
+static inline void b43_rfkill_exit(struct b43_wldev *dev)
+{
+}
+static inline char * b43_rfkill_led_name(struct b43_wldev *dev)
+{
+ return NULL;
+}
+
+#endif /* CONFIG_B43_RFKILL */
+
+#endif /* B43_RFKILL_H_ */
diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c
new file mode 100644
index 00000000000..f4faff6a7d6
--- /dev/null
+++ b/drivers/net/wireless/b43/sysfs.c
@@ -0,0 +1,236 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ SYSFS support routines
+
+ Copyright (c) 2006 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/capability.h>
+#include <linux/io.h>
+
+#include "b43.h"
+#include "sysfs.h"
+#include "main.h"
+#include "phy.h"
+
+#define GENERIC_FILESIZE 64
+
+static int get_integer(const char *buf, size_t count)
+{
+ char tmp[10 + 1] = { 0 };
+ int ret = -EINVAL;
+
+ if (count == 0)
+ goto out;
+ count = min(count, (size_t) 10);
+ memcpy(tmp, buf, count);
+ ret = simple_strtol(tmp, NULL, 10);
+ out:
+ return ret;
+}
+
+static int get_boolean(const char *buf, size_t count)
+{
+ if (count != 0) {
+ if (buf[0] == '1')
+ return 1;
+ if (buf[0] == '0')
+ return 0;
+ if (count >= 4 && memcmp(buf, "true", 4) == 0)
+ return 1;
+ if (count >= 5 && memcmp(buf, "false", 5) == 0)
+ return 0;
+ if (count >= 3 && memcmp(buf, "yes", 3) == 0)
+ return 1;
+ if (count >= 2 && memcmp(buf, "no", 2) == 0)
+ return 0;
+ if (count >= 2 && memcmp(buf, "on", 2) == 0)
+ return 1;
+ if (count >= 3 && memcmp(buf, "off", 3) == 0)
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static ssize_t b43_attr_interfmode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+ ssize_t count = 0;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mutex_lock(&wldev->wl->mutex);
+
+ switch (wldev->phy.interfmode) {
+ case B43_INTERFMODE_NONE:
+ count =
+ snprintf(buf, PAGE_SIZE,
+ "0 (No Interference Mitigation)\n");
+ break;
+ case B43_INTERFMODE_NONWLAN:
+ count =
+ snprintf(buf, PAGE_SIZE,
+ "1 (Non-WLAN Interference Mitigation)\n");
+ break;
+ case B43_INTERFMODE_MANUALWLAN:
+ count =
+ snprintf(buf, PAGE_SIZE,
+ "2 (WLAN Interference Mitigation)\n");
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+
+ mutex_unlock(&wldev->wl->mutex);
+
+ return count;
+}
+
+static ssize_t b43_attr_interfmode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+ unsigned long flags;
+ int err;
+ int mode;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mode = get_integer(buf, count);
+ switch (mode) {
+ case 0:
+ mode = B43_INTERFMODE_NONE;
+ break;
+ case 1:
+ mode = B43_INTERFMODE_NONWLAN;
+ break;
+ case 2:
+ mode = B43_INTERFMODE_MANUALWLAN;
+ break;
+ case 3:
+ mode = B43_INTERFMODE_AUTOWLAN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&wldev->wl->mutex);
+ spin_lock_irqsave(&wldev->wl->irq_lock, flags);
+
+ err = b43_radio_set_interference_mitigation(wldev, mode);
+ if (err) {
+ b43err(wldev->wl, "Interference Mitigation not "
+ "supported by device\n");
+ }
+ mmiowb();
+ spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
+ mutex_unlock(&wldev->wl->mutex);
+
+ return err ? err : count;
+}
+
+static DEVICE_ATTR(interference, 0644,
+ b43_attr_interfmode_show, b43_attr_interfmode_store);
+
+static ssize_t b43_attr_preamble_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+ ssize_t count;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mutex_lock(&wldev->wl->mutex);
+
+ if (wldev->short_preamble)
+ count =
+ snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
+ else
+ count =
+ snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
+
+ mutex_unlock(&wldev->wl->mutex);
+
+ return count;
+}
+
+static ssize_t b43_attr_preamble_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+ unsigned long flags;
+ int value;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ value = get_boolean(buf, count);
+ if (value < 0)
+ return value;
+ mutex_lock(&wldev->wl->mutex);
+ spin_lock_irqsave(&wldev->wl->irq_lock, flags);
+
+ wldev->short_preamble = !!value;
+
+ spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
+ mutex_unlock(&wldev->wl->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(shortpreamble, 0644,
+ b43_attr_preamble_show, b43_attr_preamble_store);
+
+int b43_sysfs_register(struct b43_wldev *wldev)
+{
+ struct device *dev = wldev->dev->dev;
+ int err;
+
+ B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
+
+ err = device_create_file(dev, &dev_attr_interference);
+ if (err)
+ goto out;
+ err = device_create_file(dev, &dev_attr_shortpreamble);
+ if (err)
+ goto err_remove_interfmode;
+
+ out:
+ return err;
+ err_remove_interfmode:
+ device_remove_file(dev, &dev_attr_interference);
+ goto out;
+}
+
+void b43_sysfs_unregister(struct b43_wldev *wldev)
+{
+ struct device *dev = wldev->dev->dev;
+
+ device_remove_file(dev, &dev_attr_shortpreamble);
+ device_remove_file(dev, &dev_attr_interference);
+}
diff --git a/drivers/net/wireless/b43/sysfs.h b/drivers/net/wireless/b43/sysfs.h
new file mode 100644
index 00000000000..12bda9ef1a8
--- /dev/null
+++ b/drivers/net/wireless/b43/sysfs.h
@@ -0,0 +1,9 @@
+#ifndef B43_SYSFS_H_
+#define B43_SYSFS_H_
+
+struct b43_wldev;
+
+int b43_sysfs_register(struct b43_wldev *dev);
+void b43_sysfs_unregister(struct b43_wldev *dev);
+
+#endif /* B43_SYSFS_H_ */
diff --git a/drivers/net/wireless/b43/tables.c b/drivers/net/wireless/b43/tables.c
new file mode 100644
index 00000000000..15a87183a57
--- /dev/null
+++ b/drivers/net/wireless/b43/tables.c
@@ -0,0 +1,375 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ Copyright (c) 2006, 2006 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "tables.h"
+#include "phy.h"
+
+const u32 b43_tab_rotor[] = {
+ 0xFEB93FFD, 0xFEC63FFD, /* 0 */
+ 0xFED23FFD, 0xFEDF3FFD,
+ 0xFEEC3FFE, 0xFEF83FFE,
+ 0xFF053FFE, 0xFF113FFE,
+ 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */
+ 0xFF373FFF, 0xFF443FFF,
+ 0xFF503FFF, 0xFF5D3FFF,
+ 0xFF693FFF, 0xFF763FFF,
+ 0xFF824000, 0xFF8F4000, /* 16 */
+ 0xFF9B4000, 0xFFA84000,
+ 0xFFB54000, 0xFFC14000,
+ 0xFFCE4000, 0xFFDA4000,
+ 0xFFE74000, 0xFFF34000, /* 24 */
+ 0x00004000, 0x000D4000,
+ 0x00194000, 0x00264000,
+ 0x00324000, 0x003F4000,
+ 0x004B4000, 0x00584000, /* 32 */
+ 0x00654000, 0x00714000,
+ 0x007E4000, 0x008A3FFF,
+ 0x00973FFF, 0x00A33FFF,
+ 0x00B03FFF, 0x00BC3FFF, /* 40 */
+ 0x00C93FFF, 0x00D63FFF,
+ 0x00E23FFE, 0x00EF3FFE,
+ 0x00FB3FFE, 0x01083FFE,
+ 0x01143FFE, 0x01213FFD, /* 48 */
+ 0x012E3FFD, 0x013A3FFD,
+ 0x01473FFD,
+};
+
+const u32 b43_tab_retard[] = {
+ 0xDB93CB87, 0xD666CF64, /* 0 */
+ 0xD1FDD358, 0xCDA6D826,
+ 0xCA38DD9F, 0xC729E2B4,
+ 0xC469E88E, 0xC26AEE2B,
+ 0xC0DEF46C, 0xC073FA62, /* 8 */
+ 0xC01D00D5, 0xC0760743,
+ 0xC1560D1E, 0xC2E51369,
+ 0xC4ED18FF, 0xC7AC1ED7,
+ 0xCB2823B2, 0xCEFA28D9, /* 16 */
+ 0xD2F62D3F, 0xD7BB3197,
+ 0xDCE53568, 0xE1FE3875,
+ 0xE7D13B35, 0xED663D35,
+ 0xF39B3EC4, 0xF98E3FA7, /* 24 */
+ 0x00004000, 0x06723FA7,
+ 0x0C653EC4, 0x129A3D35,
+ 0x182F3B35, 0x1E023875,
+ 0x231B3568, 0x28453197, /* 32 */
+ 0x2D0A2D3F, 0x310628D9,
+ 0x34D823B2, 0x38541ED7,
+ 0x3B1318FF, 0x3D1B1369,
+ 0x3EAA0D1E, 0x3F8A0743, /* 40 */
+ 0x3FE300D5, 0x3F8DFA62,
+ 0x3F22F46C, 0x3D96EE2B,
+ 0x3B97E88E, 0x38D7E2B4,
+ 0x35C8DD9F, 0x325AD826, /* 48 */
+ 0x2E03D358, 0x299ACF64,
+ 0x246DCB87,
+};
+
+const u16 b43_tab_finefreqa[] = {
+ 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */
+ 0x0202, 0x0282, 0x0302, 0x0382,
+ 0x0402, 0x0482, 0x0502, 0x0582,
+ 0x05E2, 0x0662, 0x06E2, 0x0762,
+ 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */
+ 0x09C2, 0x0A22, 0x0AA2, 0x0B02,
+ 0x0B82, 0x0BE2, 0x0C62, 0x0CC2,
+ 0x0D42, 0x0DA2, 0x0E02, 0x0E62,
+ 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */
+ 0x1062, 0x10C2, 0x1122, 0x1182,
+ 0x11E2, 0x1242, 0x12A2, 0x12E2,
+ 0x1342, 0x13A2, 0x1402, 0x1442,
+ 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */
+ 0x15E2, 0x1622, 0x1662, 0x16C1,
+ 0x1701, 0x1741, 0x1781, 0x17E1,
+ 0x1821, 0x1861, 0x18A1, 0x18E1,
+ 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */
+ 0x1A21, 0x1A61, 0x1AA1, 0x1AC1,
+ 0x1B01, 0x1B41, 0x1B81, 0x1BA1,
+ 0x1BE1, 0x1C21, 0x1C41, 0x1C81,
+ 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */
+ 0x1D61, 0x1DA1, 0x1DC1, 0x1E01,
+ 0x1E21, 0x1E61, 0x1E81, 0x1EA1,
+ 0x1EE1, 0x1F01, 0x1F21, 0x1F41,
+ 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */
+ 0x2001, 0x2041, 0x2061, 0x2081,
+ 0x20A1, 0x20C1, 0x20E1, 0x2101,
+ 0x2121, 0x2141, 0x2161, 0x2181,
+ 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */
+ 0x2221, 0x2241, 0x2261, 0x2281,
+ 0x22A1, 0x22C1, 0x22C1, 0x22E1,
+ 0x2301, 0x2321, 0x2341, 0x2361,
+ 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */
+ 0x23E1, 0x23E1, 0x2401, 0x2421,
+ 0x2441, 0x2441, 0x2461, 0x2481,
+ 0x2481, 0x24A1, 0x24C1, 0x24C1,
+ 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */
+ 0x2541, 0x2541, 0x2561, 0x2561,
+ 0x2581, 0x25A1, 0x25A1, 0x25C1,
+ 0x25C1, 0x25E1, 0x2601, 0x2601,
+ 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */
+ 0x2661, 0x2661, 0x2681, 0x2681,
+ 0x26A1, 0x26A1, 0x26C1, 0x26C1,
+ 0x26E1, 0x26E1, 0x2701, 0x2701,
+ 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */
+ 0x2760, 0x2760, 0x2780, 0x2780,
+ 0x2780, 0x27A0, 0x27A0, 0x27C0,
+ 0x27C0, 0x27E0, 0x27E0, 0x27E0,
+ 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */
+ 0x2820, 0x2840, 0x2840, 0x2840,
+ 0x2860, 0x2860, 0x2880, 0x2880,
+ 0x2880, 0x28A0, 0x28A0, 0x28A0,
+ 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */
+ 0x28E0, 0x28E0, 0x2900, 0x2900,
+ 0x2900, 0x2920, 0x2920, 0x2920,
+ 0x2940, 0x2940, 0x2940, 0x2960,
+ 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */
+ 0x2980, 0x2980, 0x29A0, 0x29A0,
+ 0x29A0, 0x29A0, 0x29C0, 0x29C0,
+ 0x29C0, 0x29E0, 0x29E0, 0x29E0,
+ 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */
+ 0x2A00, 0x2A20, 0x2A20, 0x2A20,
+ 0x2A20, 0x2A40, 0x2A40, 0x2A40,
+ 0x2A40, 0x2A60, 0x2A60, 0x2A60,
+};
+
+const u16 b43_tab_finefreqg[] = {
+ 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */
+ 0x05A9, 0x0669, 0x0709, 0x0789,
+ 0x0829, 0x08A9, 0x0929, 0x0989,
+ 0x0A09, 0x0A69, 0x0AC9, 0x0B29,
+ 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */
+ 0x0D09, 0x0D69, 0x0DA9, 0x0E09,
+ 0x0E69, 0x0EA9, 0x0F09, 0x0F49,
+ 0x0FA9, 0x0FE9, 0x1029, 0x1089,
+ 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */
+ 0x11E9, 0x1229, 0x1289, 0x12C9,
+ 0x1309, 0x1349, 0x1389, 0x13C9,
+ 0x1409, 0x1449, 0x14A9, 0x14E9,
+ 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */
+ 0x1629, 0x1669, 0x16A9, 0x16E8,
+ 0x1728, 0x1768, 0x17A8, 0x17E8,
+ 0x1828, 0x1868, 0x18A8, 0x18E8,
+ 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */
+ 0x1A28, 0x1A68, 0x1AA8, 0x1AE8,
+ 0x1B28, 0x1B68, 0x1BA8, 0x1BE8,
+ 0x1C28, 0x1C68, 0x1CA8, 0x1CE8,
+ 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */
+ 0x1E48, 0x1E88, 0x1EC8, 0x1F08,
+ 0x1F48, 0x1F88, 0x1FE8, 0x2028,
+ 0x2068, 0x20A8, 0x2108, 0x2148,
+ 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */
+ 0x22C8, 0x2308, 0x2348, 0x23A8,
+ 0x23E8, 0x2448, 0x24A8, 0x24E8,
+ 0x2548, 0x25A8, 0x2608, 0x2668,
+ 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */
+ 0x2847, 0x28C7, 0x2947, 0x29A7,
+ 0x2A27, 0x2AC7, 0x2B47, 0x2BE7,
+ 0x2CA7, 0x2D67, 0x2E47, 0x2F67,
+ 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */
+ 0x3806, 0x38A6, 0x3946, 0x39E6,
+ 0x3A66, 0x3AE6, 0x3B66, 0x3BC6,
+ 0x3C45, 0x3CA5, 0x3D05, 0x3D85,
+ 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */
+ 0x3F45, 0x3FA5, 0x4005, 0x4045,
+ 0x40A5, 0x40E5, 0x4145, 0x4185,
+ 0x41E5, 0x4225, 0x4265, 0x42C5,
+ 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */
+ 0x4424, 0x4464, 0x44C4, 0x4504,
+ 0x4544, 0x4584, 0x45C4, 0x4604,
+ 0x4644, 0x46A4, 0x46E4, 0x4724,
+ 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */
+ 0x4864, 0x48A4, 0x48E4, 0x4924,
+ 0x4964, 0x49A4, 0x49E4, 0x4A24,
+ 0x4A64, 0x4AA4, 0x4AE4, 0x4B23,
+ 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */
+ 0x4C63, 0x4CA3, 0x4CE3, 0x4D23,
+ 0x4D63, 0x4DA3, 0x4DE3, 0x4E23,
+ 0x4E63, 0x4EA3, 0x4EE3, 0x4F23,
+ 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */
+ 0x5083, 0x50C3, 0x5103, 0x5143,
+ 0x5183, 0x51E2, 0x5222, 0x5262,
+ 0x52A2, 0x52E2, 0x5342, 0x5382,
+ 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */
+ 0x5502, 0x5542, 0x55A2, 0x55E2,
+ 0x5642, 0x5682, 0x56E2, 0x5722,
+ 0x5782, 0x57E1, 0x5841, 0x58A1,
+ 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */
+ 0x5AA1, 0x5B01, 0x5B81, 0x5BE1,
+ 0x5C61, 0x5D01, 0x5D80, 0x5E20,
+ 0x5EE0, 0x5FA0, 0x6080, 0x61C0,
+};
+
+const u16 b43_tab_noisea2[] = {
+ 0x0001, 0x0001, 0x0001, 0xFFFE,
+ 0xFFFE, 0x3FFF, 0x1000, 0x0393,
+};
+
+const u16 b43_tab_noisea3[] = {
+ 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+ 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+};
+
+const u16 b43_tab_noiseg1[] = {
+ 0x013C, 0x01F5, 0x031A, 0x0631,
+ 0x0001, 0x0001, 0x0001, 0x0001,
+};
+
+const u16 b43_tab_noiseg2[] = {
+ 0x5484, 0x3C40, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+const u16 b43_tab_noisescaleg1[] = {
+ 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */
+ 0x2F2D, 0x2A2A, 0x2527, 0x1F21,
+ 0x1A1D, 0x1719, 0x1616, 0x1414,
+ 0x1414, 0x1400, 0x1414, 0x1614,
+ 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */
+ 0x2A27, 0x2F2A, 0x332D, 0x3B35,
+ 0x5140, 0x6C62, 0x0077,
+};
+
+const u16 b43_tab_noisescaleg2[] = {
+ 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */
+ 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
+ 0x969B, 0x9195, 0x8F8F, 0x8A8A,
+ 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
+ 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */
+ 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7,
+ 0xCBC0, 0xD8D4, 0x00DD,
+};
+
+const u16 b43_tab_noisescaleg3[] = {
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA400, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA4A4, 0x00A4,
+};
+
+const u16 b43_tab_sigmasqr1[] = {
+ 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */
+ 0x0067, 0x0063, 0x005E, 0x0059,
+ 0x0054, 0x0050, 0x004B, 0x0046,
+ 0x0042, 0x003D, 0x003D, 0x003D,
+ 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */
+ 0x003D, 0x003D, 0x003D, 0x003D,
+ 0x003D, 0x003D, 0x0000, 0x003D,
+ 0x003D, 0x003D, 0x003D, 0x003D,
+ 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */
+ 0x003D, 0x003D, 0x003D, 0x003D,
+ 0x0042, 0x0046, 0x004B, 0x0050,
+ 0x0054, 0x0059, 0x005E, 0x0063,
+ 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */
+ 0x007A,
+};
+
+const u16 b43_tab_sigmasqr2[] = {
+ 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */
+ 0x00D6, 0x00D4, 0x00D2, 0x00CF,
+ 0x00CD, 0x00CA, 0x00C7, 0x00C4,
+ 0x00C1, 0x00BE, 0x00BE, 0x00BE,
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE,
+ 0x00BE, 0x00BE, 0x0000, 0x00BE,
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE,
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE,
+ 0x00C1, 0x00C4, 0x00C7, 0x00CA,
+ 0x00CD, 0x00CF, 0x00D2, 0x00D4,
+ 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */
+ 0x00DE,
+};
+
+static inline void assert_sizes(void)
+{
+ BUILD_BUG_ON(B43_TAB_ROTOR_SIZE != ARRAY_SIZE(b43_tab_rotor));
+ BUILD_BUG_ON(B43_TAB_RETARD_SIZE != ARRAY_SIZE(b43_tab_retard));
+ BUILD_BUG_ON(B43_TAB_FINEFREQA_SIZE != ARRAY_SIZE(b43_tab_finefreqa));
+ BUILD_BUG_ON(B43_TAB_FINEFREQG_SIZE != ARRAY_SIZE(b43_tab_finefreqg));
+ BUILD_BUG_ON(B43_TAB_NOISEA2_SIZE != ARRAY_SIZE(b43_tab_noisea2));
+ BUILD_BUG_ON(B43_TAB_NOISEA3_SIZE != ARRAY_SIZE(b43_tab_noisea3));
+ BUILD_BUG_ON(B43_TAB_NOISEG1_SIZE != ARRAY_SIZE(b43_tab_noiseg1));
+ BUILD_BUG_ON(B43_TAB_NOISEG2_SIZE != ARRAY_SIZE(b43_tab_noiseg2));
+ BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+ ARRAY_SIZE(b43_tab_noisescaleg1));
+ BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+ ARRAY_SIZE(b43_tab_noisescaleg2));
+ BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+ ARRAY_SIZE(b43_tab_noisescaleg3));
+ BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr1));
+ BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr2));
+}
+
+u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset)
+{
+ assert_sizes();
+
+ b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+ return b43_phy_read(dev, B43_PHY_OTABLEI);
+}
+
+void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
+ u16 offset, u16 value)
+{
+ b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+ b43_phy_write(dev, B43_PHY_OTABLEI, value);
+}
+
+u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
+{
+ u32 ret;
+
+ b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+ ret = b43_phy_read(dev, B43_PHY_OTABLEQ);
+ ret <<= 16;
+ ret |= b43_phy_read(dev, B43_PHY_OTABLEI);
+
+ return ret;
+}
+
+void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
+ u16 offset, u32 value)
+{
+ b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+ b43_phy_write(dev, B43_PHY_OTABLEI, value);
+ b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16));
+}
+
+u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset)
+{
+ b43_phy_write(dev, B43_PHY_GTABCTL, table + offset);
+ return b43_phy_read(dev, B43_PHY_GTABDATA);
+}
+
+void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value)
+{
+ b43_phy_write(dev, B43_PHY_GTABCTL, table + offset);
+ b43_phy_write(dev, B43_PHY_GTABDATA, value);
+}
diff --git a/drivers/net/wireless/b43/tables.h b/drivers/net/wireless/b43/tables.h
new file mode 100644
index 00000000000..64635d7b518
--- /dev/null
+++ b/drivers/net/wireless/b43/tables.h
@@ -0,0 +1,28 @@
+#ifndef B43_TABLES_H_
+#define B43_TABLES_H_
+
+#define B43_TAB_ROTOR_SIZE 53
+extern const u32 b43_tab_rotor[];
+#define B43_TAB_RETARD_SIZE 53
+extern const u32 b43_tab_retard[];
+#define B43_TAB_FINEFREQA_SIZE 256
+extern const u16 b43_tab_finefreqa[];
+#define B43_TAB_FINEFREQG_SIZE 256
+extern const u16 b43_tab_finefreqg[];
+#define B43_TAB_NOISEA2_SIZE 8
+extern const u16 b43_tab_noisea2[];
+#define B43_TAB_NOISEA3_SIZE 8
+extern const u16 b43_tab_noisea3[];
+#define B43_TAB_NOISEG1_SIZE 8
+extern const u16 b43_tab_noiseg1[];
+#define B43_TAB_NOISEG2_SIZE 8
+extern const u16 b43_tab_noiseg2[];
+#define B43_TAB_NOISESCALEG_SIZE 27
+extern const u16 b43_tab_noisescaleg1[];
+extern const u16 b43_tab_noisescaleg2[];
+extern const u16 b43_tab_noisescaleg3[];
+#define B43_TAB_SIGMASQR_SIZE 53
+extern const u16 b43_tab_sigmasqr1[];
+extern const u16 b43_tab_sigmasqr2[];
+
+#endif /* B43_TABLES_H_ */
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
new file mode 100644
index 00000000000..0bd6f8a348a
--- /dev/null
+++ b/drivers/net/wireless/b43/xmit.c
@@ -0,0 +1,650 @@
+/*
+
+ Broadcom B43 wireless driver
+
+ Transmission (TX/RX) related functions.
+
+ Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+ Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+ Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "xmit.h"
+#include "phy.h"
+#include "dma.h"
+#include "pio.h"
+
+/* Extract the bitrate out of a CCK PLCP header. */
+static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp)
+{
+ switch (plcp->raw[0]) {
+ case 0x0A:
+ return B43_CCK_RATE_1MB;
+ case 0x14:
+ return B43_CCK_RATE_2MB;
+ case 0x37:
+ return B43_CCK_RATE_5MB;
+ case 0x6E:
+ return B43_CCK_RATE_11MB;
+ }
+ B43_WARN_ON(1);
+ return 0;
+}
+
+/* Extract the bitrate out of an OFDM PLCP header. */
+static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp)
+{
+ switch (plcp->raw[0] & 0xF) {
+ case 0xB:
+ return B43_OFDM_RATE_6MB;
+ case 0xF:
+ return B43_OFDM_RATE_9MB;
+ case 0xA:
+ return B43_OFDM_RATE_12MB;
+ case 0xE:
+ return B43_OFDM_RATE_18MB;
+ case 0x9:
+ return B43_OFDM_RATE_24MB;
+ case 0xD:
+ return B43_OFDM_RATE_36MB;
+ case 0x8:
+ return B43_OFDM_RATE_48MB;
+ case 0xC:
+ return B43_OFDM_RATE_54MB;
+ }
+ B43_WARN_ON(1);
+ return 0;
+}
+
+u8 b43_plcp_get_ratecode_cck(const u8 bitrate)
+{
+ switch (bitrate) {
+ case B43_CCK_RATE_1MB:
+ return 0x0A;
+ case B43_CCK_RATE_2MB:
+ return 0x14;
+ case B43_CCK_RATE_5MB:
+ return 0x37;
+ case B43_CCK_RATE_11MB:
+ return 0x6E;
+ }
+ B43_WARN_ON(1);
+ return 0;
+}
+
+u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate)
+{
+ switch (bitrate) {
+ case B43_OFDM_RATE_6MB:
+ return 0xB;
+ case B43_OFDM_RATE_9MB:
+ return 0xF;
+ case B43_OFDM_RATE_12MB:
+ return 0xA;
+ case B43_OFDM_RATE_18MB:
+ return 0xE;
+ case B43_OFDM_RATE_24MB:
+ return 0x9;
+ case B43_OFDM_RATE_36MB:
+ return 0xD;
+ case B43_OFDM_RATE_48MB:
+ return 0x8;
+ case B43_OFDM_RATE_54MB:
+ return 0xC;
+ }
+ B43_WARN_ON(1);
+ return 0;
+}
+
+void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
+ const u16 octets, const u8 bitrate)
+{
+ __le32 *data = &(plcp->data);
+ __u8 *raw = plcp->raw;
+
+ if (b43_is_ofdm_rate(bitrate)) {
+ u32 d;
+
+ d = b43_plcp_get_ratecode_ofdm(bitrate);
+ B43_WARN_ON(octets & 0xF000);
+ d |= (octets << 5);
+ *data = cpu_to_le32(d);
+ } else {
+ u32 plen;
+
+ plen = octets * 16 / bitrate;
+ if ((octets * 16 % bitrate) > 0) {
+ plen++;
+ if ((bitrate == B43_CCK_RATE_11MB)
+ && ((octets * 8 % 11) < 4)) {
+ raw[1] = 0x84;
+ } else
+ raw[1] = 0x04;
+ } else
+ raw[1] = 0x04;
+ *data |= cpu_to_le32(plen << 16);
+ raw[0] = b43_plcp_get_ratecode_cck(bitrate);
+ }
+}
+
+static u8 b43_calc_fallback_rate(u8 bitrate)
+{
+ switch (bitrate) {
+ case B43_CCK_RATE_1MB:
+ return B43_CCK_RATE_1MB;
+ case B43_CCK_RATE_2MB:
+ return B43_CCK_RATE_1MB;
+ case B43_CCK_RATE_5MB:
+ return B43_CCK_RATE_2MB;
+ case B43_CCK_RATE_11MB:
+ return B43_CCK_RATE_5MB;
+ case B43_OFDM_RATE_6MB:
+ return B43_CCK_RATE_5MB;
+ case B43_OFDM_RATE_9MB:
+ return B43_OFDM_RATE_6MB;
+ case B43_OFDM_RATE_12MB:
+ return B43_OFDM_RATE_9MB;
+ case B43_OFDM_RATE_18MB:
+ return B43_OFDM_RATE_12MB;
+ case B43_OFDM_RATE_24MB:
+ return B43_OFDM_RATE_18MB;
+ case B43_OFDM_RATE_36MB:
+ return B43_OFDM_RATE_24MB;
+ case B43_OFDM_RATE_48MB:
+ return B43_OFDM_RATE_36MB;
+ case B43_OFDM_RATE_54MB:
+ return B43_OFDM_RATE_48MB;
+ }
+ B43_WARN_ON(1);
+ return 0;
+}
+
+static void generate_txhdr_fw4(struct b43_wldev *dev,
+ struct b43_txhdr_fw4 *txhdr,
+ const unsigned char *fragment_data,
+ unsigned int fragment_len,
+ const struct ieee80211_tx_control *txctl,
+ u16 cookie)
+{
+ const struct b43_phy *phy = &dev->phy;
+ const struct ieee80211_hdr *wlhdr =
+ (const struct ieee80211_hdr *)fragment_data;
+ int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
+ u16 fctl = le16_to_cpu(wlhdr->frame_control);
+ u8 rate, rate_fb;
+ int rate_ofdm, rate_fb_ofdm;
+ unsigned int plcp_fragment_len;
+ u32 mac_ctl = 0;
+ u16 phy_ctl = 0;
+ u8 extra_ft = 0;
+
+ memset(txhdr, 0, sizeof(*txhdr));
+
+ rate = txctl->tx_rate;
+ rate_ofdm = b43_is_ofdm_rate(rate);
+ rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
+ rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
+
+ if (rate_ofdm)
+ txhdr->phy_rate = b43_plcp_get_ratecode_ofdm(rate);
+ else
+ txhdr->phy_rate = b43_plcp_get_ratecode_cck(rate);
+ txhdr->mac_frame_ctl = wlhdr->frame_control;
+ memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
+
+ /* Calculate duration for fallback rate */
+ if ((rate_fb == rate) ||
+ (wlhdr->duration_id & cpu_to_le16(0x8000)) ||
+ (wlhdr->duration_id == cpu_to_le16(0))) {
+ /* If the fallback rate equals the normal rate or the
+ * dur_id field contains an AID, CFP magic or 0,
+ * use the original dur_id field. */
+ txhdr->dur_fb = wlhdr->duration_id;
+ } else {
+ int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb);
+ txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->if_id,
+ fragment_len,
+ fbrate_base100kbps);
+ }
+
+ plcp_fragment_len = fragment_len + FCS_LEN;
+ if (use_encryption) {
+ u8 key_idx = (u16) (txctl->key_idx);
+ struct b43_key *key;
+ int wlhdr_len;
+ size_t iv_len;
+
+ B43_WARN_ON(key_idx >= dev->max_nr_keys);
+ key = &(dev->key[key_idx]);
+ B43_WARN_ON(!key->keyconf);
+
+ /* Hardware appends ICV. */
+ plcp_fragment_len += txctl->icv_len;
+
+ key_idx = b43_kidx_to_fw(dev, key_idx);
+ mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) &
+ B43_TX4_MAC_KEYIDX;
+ mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) &
+ B43_TX4_MAC_KEYALG;
+ wlhdr_len = ieee80211_get_hdrlen(fctl);
+ iv_len = min((size_t) txctl->iv_len,
+ ARRAY_SIZE(txhdr->iv));
+ memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
+ }
+ b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp),
+ plcp_fragment_len, rate);
+ b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
+ plcp_fragment_len, rate_fb);
+
+ /* Extra Frame Types */
+ if (rate_fb_ofdm)
+ extra_ft |= B43_TX4_EFT_FBOFDM;
+
+ /* Set channel radio code. Note that the micrcode ORs 0x100 to
+ * this value before comparing it to the value in SHM, if this
+ * is a 5Ghz packet.
+ */
+ txhdr->chan_radio_code = phy->channel;
+
+ /* PHY TX Control word */
+ if (rate_ofdm)
+ phy_ctl |= B43_TX4_PHY_OFDM;
+ if (dev->short_preamble)
+ phy_ctl |= B43_TX4_PHY_SHORTPRMBL;
+ switch (txctl->antenna_sel_tx) {
+ case 0:
+ phy_ctl |= B43_TX4_PHY_ANTLAST;
+ break;
+ case 1:
+ phy_ctl |= B43_TX4_PHY_ANT0;
+ break;
+ case 2:
+ phy_ctl |= B43_TX4_PHY_ANT1;
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+
+ /* MAC control */
+ if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
+ mac_ctl |= B43_TX4_MAC_ACK;
+ if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+ ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
+ mac_ctl |= B43_TX4_MAC_HWSEQ;
+ if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
+ mac_ctl |= B43_TX4_MAC_STMSDU;
+ if (phy->type == B43_PHYTYPE_A)
+ mac_ctl |= B43_TX4_MAC_5GHZ;
+
+ /* Generate the RTS or CTS-to-self frame */
+ if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
+ (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+ unsigned int len;
+ struct ieee80211_hdr *hdr;
+ int rts_rate, rts_rate_fb;
+ int rts_rate_ofdm, rts_rate_fb_ofdm;
+
+ rts_rate = txctl->rts_cts_rate;
+ rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
+ rts_rate_fb = b43_calc_fallback_rate(rts_rate);
+ rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
+
+ if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id,
+ fragment_data, fragment_len,
+ txctl,
+ (struct ieee80211_cts *)(txhdr->
+ rts_frame));
+ mac_ctl |= B43_TX4_MAC_SENDCTS;
+ len = sizeof(struct ieee80211_cts);
+ } else {
+ ieee80211_rts_get(dev->wl->hw, dev->wl->if_id,
+ fragment_data, fragment_len, txctl,
+ (struct ieee80211_rts *)(txhdr->
+ rts_frame));
+ mac_ctl |= B43_TX4_MAC_SENDRTS;
+ len = sizeof(struct ieee80211_rts);
+ }
+ len += FCS_LEN;
+ b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
+ rts_plcp), len,
+ rts_rate);
+ b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
+ rts_plcp_fb),
+ len, rts_rate_fb);
+ hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
+ txhdr->rts_dur_fb = hdr->duration_id;
+ if (rts_rate_ofdm) {
+ extra_ft |= B43_TX4_EFT_RTSOFDM;
+ txhdr->phy_rate_rts =
+ b43_plcp_get_ratecode_ofdm(rts_rate);
+ } else
+ txhdr->phy_rate_rts =
+ b43_plcp_get_ratecode_cck(rts_rate);
+ if (rts_rate_fb_ofdm)
+ extra_ft |= B43_TX4_EFT_RTSFBOFDM;
+ mac_ctl |= B43_TX4_MAC_LONGFRAME;
+ }
+
+ /* Magic cookie */
+ txhdr->cookie = cpu_to_le16(cookie);
+
+ /* Apply the bitfields */
+ txhdr->mac_ctl = cpu_to_le32(mac_ctl);
+ txhdr->phy_ctl = cpu_to_le16(phy_ctl);
+ txhdr->extra_ft = extra_ft;
+}
+
+void b43_generate_txhdr(struct b43_wldev *dev,
+ u8 * txhdr,
+ const unsigned char *fragment_data,
+ unsigned int fragment_len,
+ const struct ieee80211_tx_control *txctl, u16 cookie)
+{
+ generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr,
+ fragment_data, fragment_len, txctl, cookie);
+}
+
+static s8 b43_rssi_postprocess(struct b43_wldev *dev,
+ u8 in_rssi, int ofdm,
+ int adjust_2053, int adjust_2050)
+{
+ struct b43_phy *phy = &dev->phy;
+ s32 tmp;
+
+ switch (phy->radio_ver) {
+ case 0x2050:
+ if (ofdm) {
+ tmp = in_rssi;
+ if (tmp > 127)
+ tmp -= 256;
+ tmp *= 73;
+ tmp /= 64;
+ if (adjust_2050)
+ tmp += 25;
+ else
+ tmp -= 3;
+ } else {
+ if (dev->dev->bus->sprom.r1.
+ boardflags_lo & B43_BFL_RSSI) {
+ if (in_rssi > 63)
+ in_rssi = 63;
+ tmp = phy->nrssi_lt[in_rssi];
+ tmp = 31 - tmp;
+ tmp *= -131;
+ tmp /= 128;
+ tmp -= 57;
+ } else {
+ tmp = in_rssi;
+ tmp = 31 - tmp;
+ tmp *= -149;
+ tmp /= 128;
+ tmp -= 68;
+ }
+ if (phy->type == B43_PHYTYPE_G && adjust_2050)
+ tmp += 25;
+ }
+ break;
+ case 0x2060:
+ if (in_rssi > 127)
+ tmp = in_rssi - 256;
+ else
+ tmp = in_rssi;
+ break;
+ default:
+ tmp = in_rssi;
+ tmp -= 11;
+ tmp *= 103;
+ tmp /= 64;
+ if (adjust_2053)
+ tmp -= 109;
+ else
+ tmp -= 83;
+ }
+
+ return (s8) tmp;
+}
+
+//TODO
+#if 0
+static s8 b43_rssinoise_postprocess(struct b43_wldev *dev, u8 in_rssi)
+{
+ struct b43_phy *phy = &dev->phy;
+ s8 ret;
+
+ if (phy->type == B43_PHYTYPE_A) {
+ //TODO: Incomplete specs.
+ ret = 0;
+ } else
+ ret = b43_rssi_postprocess(dev, in_rssi, 0, 1, 1);
+
+ return ret;
+}
+#endif
+
+void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
+{
+ struct ieee80211_rx_status status;
+ struct b43_plcp_hdr6 *plcp;
+ struct ieee80211_hdr *wlhdr;
+ const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
+ u16 fctl;
+ u16 phystat0, phystat3, chanstat, mactime;
+ u32 macstat;
+ u16 chanid;
+ u8 jssi;
+ int padding;
+
+ memset(&status, 0, sizeof(status));
+
+ /* Get metadata about the frame from the header. */
+ phystat0 = le16_to_cpu(rxhdr->phy_status0);
+ phystat3 = le16_to_cpu(rxhdr->phy_status3);
+ jssi = rxhdr->jssi;
+ macstat = le32_to_cpu(rxhdr->mac_status);
+ mactime = le16_to_cpu(rxhdr->mac_time);
+ chanstat = le16_to_cpu(rxhdr->channel);
+
+ if (macstat & B43_RX_MAC_FCSERR)
+ dev->wl->ieee_stats.dot11FCSErrorCount++;
+ if (macstat & B43_RX_MAC_DECERR) {
+ /* Decryption with the given key failed.
+ * Drop the packet. We also won't be able to decrypt it with
+ * the key in software. */
+ goto drop;
+ }
+
+ /* Skip PLCP and padding */
+ padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0;
+ if (unlikely(skb->len < (sizeof(struct b43_plcp_hdr6) + padding))) {
+ b43dbg(dev->wl, "RX: Packet size underrun (1)\n");
+ goto drop;
+ }
+ plcp = (struct b43_plcp_hdr6 *)(skb->data + padding);
+ skb_pull(skb, sizeof(struct b43_plcp_hdr6) + padding);
+ /* The skb contains the Wireless Header + payload data now */
+ if (unlikely(skb->len < (2 + 2 + 6 /*minimum hdr */ + FCS_LEN))) {
+ b43dbg(dev->wl, "RX: Packet size underrun (2)\n");
+ goto drop;
+ }
+ wlhdr = (struct ieee80211_hdr *)(skb->data);
+ fctl = le16_to_cpu(wlhdr->frame_control);
+ skb_trim(skb, skb->len - FCS_LEN);
+
+ if (macstat & B43_RX_MAC_DEC) {
+ unsigned int keyidx;
+ int wlhdr_len;
+
+ keyidx = ((macstat & B43_RX_MAC_KEYIDX)
+ >> B43_RX_MAC_KEYIDX_SHIFT);
+ /* We must adjust the key index here. We want the "physical"
+ * key index, but the ucode passed it slightly different.
+ */
+ keyidx = b43_kidx_to_raw(dev, keyidx);
+ B43_WARN_ON(keyidx >= dev->max_nr_keys);
+
+ if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) {
+ wlhdr_len = ieee80211_get_hdrlen(fctl);
+ if (unlikely(skb->len < (wlhdr_len + 3))) {
+ b43dbg(dev->wl,
+ "RX: Packet size underrun (3)\n");
+ goto drop;
+ }
+ status.flag |= RX_FLAG_DECRYPTED;
+ }
+ }
+
+ status.ssi = b43_rssi_postprocess(dev, jssi,
+ (phystat0 & B43_RX_PHYST0_OFDM),
+ (phystat0 & B43_RX_PHYST0_GAINCTL),
+ (phystat3 & B43_RX_PHYST3_TRSTATE));
+ status.noise = dev->stats.link_noise;
+ /* the next line looks wrong, but is what mac80211 wants */
+ status.signal = (jssi * 100) / B43_RX_MAX_SSI;
+ if (phystat0 & B43_RX_PHYST0_OFDM)
+ status.rate = b43_plcp_get_bitrate_ofdm(plcp);
+ else
+ status.rate = b43_plcp_get_bitrate_cck(plcp);
+ status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
+ status.mactime = mactime;
+
+ chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
+ switch (chanstat & B43_RX_CHAN_PHYTYPE) {
+ case B43_PHYTYPE_A:
+ status.phymode = MODE_IEEE80211A;
+ status.freq = chanid;
+ status.channel = b43_freq_to_channel_a(chanid);
+ break;
+ case B43_PHYTYPE_B:
+ status.phymode = MODE_IEEE80211B;
+ status.freq = chanid + 2400;
+ status.channel = b43_freq_to_channel_bg(chanid + 2400);
+ break;
+ case B43_PHYTYPE_G:
+ status.phymode = MODE_IEEE80211G;
+ status.freq = chanid + 2400;
+ status.channel = b43_freq_to_channel_bg(chanid + 2400);
+ break;
+ default:
+ B43_WARN_ON(1);
+ }
+
+ dev->stats.last_rx = jiffies;
+ ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+
+ return;
+drop:
+ b43dbg(dev->wl, "RX: Packet dropped\n");
+ dev_kfree_skb_any(skb);
+}
+
+void b43_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status)
+{
+ b43_debugfs_log_txstat(dev, status);
+
+ if (status->intermediate)
+ return;
+ if (status->for_ampdu)
+ return;
+ if (!status->acked)
+ dev->wl->ieee_stats.dot11ACKFailureCount++;
+ if (status->rts_count) {
+ if (status->rts_count == 0xF) //FIXME
+ dev->wl->ieee_stats.dot11RTSFailureCount++;
+ else
+ dev->wl->ieee_stats.dot11RTSSuccessCount++;
+ }
+
+ if (b43_using_pio(dev))
+ b43_pio_handle_txstatus(dev, status);
+ else
+ b43_dma_handle_txstatus(dev, status);
+}
+
+/* Handle TX status report as received through DMA/PIO queues */
+void b43_handle_hwtxstatus(struct b43_wldev *dev,
+ const struct b43_hwtxstatus *hw)
+{
+ struct b43_txstatus status;
+ u8 tmp;
+
+ status.cookie = le16_to_cpu(hw->cookie);
+ status.seq = le16_to_cpu(hw->seq);
+ status.phy_stat = hw->phy_stat;
+ tmp = hw->count;
+ status.frame_count = (tmp >> 4);
+ status.rts_count = (tmp & 0x0F);
+ tmp = hw->flags;
+ status.supp_reason = ((tmp & 0x1C) >> 2);
+ status.pm_indicated = !!(tmp & 0x80);
+ status.intermediate = !!(tmp & 0x40);
+ status.for_ampdu = !!(tmp & 0x20);
+ status.acked = !!(tmp & 0x02);
+
+ b43_handle_txstatus(dev, &status);
+}
+
+/* Stop any TX operation on the device (suspend the hardware queues) */
+void b43_tx_suspend(struct b43_wldev *dev)
+{
+ if (b43_using_pio(dev))
+ b43_pio_freeze_txqueues(dev);
+ else
+ b43_dma_tx_suspend(dev);
+}
+
+/* Resume any TX operation on the device (resume the hardware queues) */
+void b43_tx_resume(struct b43_wldev *dev)
+{
+ if (b43_using_pio(dev))
+ b43_pio_thaw_txqueues(dev);
+ else
+ b43_dma_tx_resume(dev);
+}
+
+#if 0
+static void upload_qos_parms(struct b43_wldev *dev,
+ const u16 * parms, u16 offset)
+{
+ int i;
+
+ for (i = 0; i < B43_NR_QOSPARMS; i++) {
+ b43_shm_write16(dev, B43_SHM_SHARED,
+ offset + (i * 2), parms[i]);
+ }
+}
+#endif
+
+/* Initialize the QoS parameters */
+void b43_qos_init(struct b43_wldev *dev)
+{
+ /* FIXME: This function must probably be called from the mac80211
+ * config callback. */
+ return;
+
+ b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
+ //FIXME kill magic
+ b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4);
+
+ /*TODO: We might need some stack support here to get the values. */
+}
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
new file mode 100644
index 00000000000..03bddd25161
--- /dev/null
+++ b/drivers/net/wireless/b43/xmit.h
@@ -0,0 +1,250 @@
+#ifndef B43_XMIT_H_
+#define B43_XMIT_H_
+
+#include "main.h"
+
+#define _b43_declare_plcp_hdr(size) \
+ struct b43_plcp_hdr##size { \
+ union { \
+ __le32 data; \
+ __u8 raw[size]; \
+ } __attribute__((__packed__)); \
+ } __attribute__((__packed__))
+
+/* struct b43_plcp_hdr4 */
+_b43_declare_plcp_hdr(4);
+/* struct b43_plcp_hdr6 */
+_b43_declare_plcp_hdr(6);
+
+#undef _b43_declare_plcp_hdr
+
+/* TX header for v4 firmware */
+struct b43_txhdr_fw4 {
+ __le32 mac_ctl; /* MAC TX control */
+ __le16 mac_frame_ctl; /* Copy of the FrameControl field */
+ __le16 tx_fes_time_norm; /* TX FES Time Normal */
+ __le16 phy_ctl; /* PHY TX control */
+ __le16 phy_ctl_0; /* Unused */
+ __le16 phy_ctl_1; /* Unused */
+ __le16 phy_ctl_rts_0; /* Unused */
+ __le16 phy_ctl_rts_1; /* Unused */
+ __u8 phy_rate; /* PHY rate */
+ __u8 phy_rate_rts; /* PHY rate for RTS/CTS */
+ __u8 extra_ft; /* Extra Frame Types */
+ __u8 chan_radio_code; /* Channel Radio Code */
+ __u8 iv[16]; /* Encryption IV */
+ __u8 tx_receiver[6]; /* TX Frame Receiver address */
+ __le16 tx_fes_time_fb; /* TX FES Time Fallback */
+ struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP */
+ __le16 rts_dur_fb; /* RTS fallback duration */
+ struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP */
+ __le16 dur_fb; /* Fallback duration */
+ __le16 mm_dur_time; /* Unused */
+ __le16 mm_dur_time_fb; /* Unused */
+ __le32 time_stamp; /* Timestamp */
+ PAD_BYTES(2);
+ __le16 cookie; /* TX frame cookie */
+ __le16 tx_status; /* TX status */
+ struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP */
+ __u8 rts_frame[16]; /* The RTS frame (if used) */
+ PAD_BYTES(2);
+ struct b43_plcp_hdr6 plcp; /* Main PLCP */
+} __attribute__ ((__packed__));
+
+/* MAC TX control */
+#define B43_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */
+#define B43_TX4_MAC_KEYIDX_SHIFT 20
+#define B43_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */
+#define B43_TX4_MAC_KEYALG_SHIFT 16
+#define B43_TX4_MAC_LIFETIME 0x00001000
+#define B43_TX4_MAC_FRAMEBURST 0x00000800
+#define B43_TX4_MAC_SENDCTS 0x00000400
+#define B43_TX4_MAC_AMPDU 0x00000300
+#define B43_TX4_MAC_AMPDU_SHIFT 8
+#define B43_TX4_MAC_5GHZ 0x00000080
+#define B43_TX4_MAC_IGNPMQ 0x00000020
+#define B43_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */
+#define B43_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */
+#define B43_TX4_MAC_SENDRTS 0x00000004
+#define B43_TX4_MAC_LONGFRAME 0x00000002
+#define B43_TX4_MAC_ACK 0x00000001
+
+/* Extra Frame Types */
+#define B43_TX4_EFT_FBOFDM 0x0001 /* Data frame fallback rate type */
+#define B43_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */
+#define B43_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */
+
+/* PHY TX control word */
+#define B43_TX4_PHY_OFDM 0x0001 /* Data frame rate type */
+#define B43_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
+#define B43_TX4_PHY_ANT 0x03C0 /* Antenna selection */
+#define B43_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */
+#define B43_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */
+#define B43_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */
+
+void b43_generate_txhdr(struct b43_wldev *dev,
+ u8 * txhdr,
+ const unsigned char *fragment_data,
+ unsigned int fragment_len,
+ const struct ieee80211_tx_control *txctl, u16 cookie);
+
+/* Transmit Status */
+struct b43_txstatus {
+ u16 cookie; /* The cookie from the txhdr */
+ u16 seq; /* Sequence number */
+ u8 phy_stat; /* PHY TX status */
+ u8 frame_count; /* Frame transmit count */
+ u8 rts_count; /* RTS transmit count */
+ u8 supp_reason; /* Suppression reason */
+ /* flags */
+ u8 pm_indicated; /* PM mode indicated to AP */
+ u8 intermediate; /* Intermediate status notification (not final) */
+ u8 for_ampdu; /* Status is for an AMPDU (afterburner) */
+ u8 acked; /* Wireless ACK received */
+};
+
+/* txstatus supp_reason values */
+enum {
+ B43_TXST_SUPP_NONE, /* Not suppressed */
+ B43_TXST_SUPP_PMQ, /* Suppressed due to PMQ entry */
+ B43_TXST_SUPP_FLUSH, /* Suppressed due to flush request */
+ B43_TXST_SUPP_PREV, /* Previous fragment failed */
+ B43_TXST_SUPP_CHAN, /* Channel mismatch */
+ B43_TXST_SUPP_LIFE, /* Lifetime expired */
+ B43_TXST_SUPP_UNDER, /* Buffer underflow */
+ B43_TXST_SUPP_ABNACK, /* Afterburner NACK */
+};
+
+/* Transmit Status as received through DMA/PIO on old chips */
+struct b43_hwtxstatus {
+ PAD_BYTES(4);
+ __le16 cookie;
+ u8 flags;
+ u8 count;
+ PAD_BYTES(2);
+ __le16 seq;
+ u8 phy_stat;
+ PAD_BYTES(1);
+} __attribute__ ((__packed__));
+
+/* Receive header for v4 firmware. */
+struct b43_rxhdr_fw4 {
+ __le16 frame_len; /* Frame length */
+ PAD_BYTES(2);
+ __le16 phy_status0; /* PHY RX Status 0 */
+ __u8 jssi; /* PHY RX Status 1: JSSI */
+ __u8 sig_qual; /* PHY RX Status 1: Signal Quality */
+ __le16 phy_status2; /* PHY RX Status 2 */
+ __le16 phy_status3; /* PHY RX Status 3 */
+ __le32 mac_status; /* MAC RX status */
+ __le16 mac_time;
+ __le16 channel;
+} __attribute__ ((__packed__));
+
+/* PHY RX Status 0 */
+#define B43_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */
+#define B43_RX_PHYST0_PLCPHCF 0x0200
+#define B43_RX_PHYST0_PLCPFV 0x0100
+#define B43_RX_PHYST0_SHORTPRMBL 0x0080 /* Received with Short Preamble */
+#define B43_RX_PHYST0_LCRS 0x0040
+#define B43_RX_PHYST0_ANT 0x0020 /* Antenna */
+#define B43_RX_PHYST0_UNSRATE 0x0010
+#define B43_RX_PHYST0_CLIP 0x000C
+#define B43_RX_PHYST0_CLIP_SHIFT 2
+#define B43_RX_PHYST0_FTYPE 0x0003 /* Frame type */
+#define B43_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */
+#define B43_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */
+#define B43_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */
+#define B43_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */
+
+/* PHY RX Status 2 */
+#define B43_RX_PHYST2_LNAG 0xC000 /* LNA Gain */
+#define B43_RX_PHYST2_LNAG_SHIFT 14
+#define B43_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */
+#define B43_RX_PHYST2_PNAG_SHIFT 10
+#define B43_RX_PHYST2_FOFF 0x03FF /* F offset */
+
+/* PHY RX Status 3 */
+#define B43_RX_PHYST3_DIGG 0x1800 /* DIG Gain */
+#define B43_RX_PHYST3_DIGG_SHIFT 11
+#define B43_RX_PHYST3_TRSTATE 0x0400 /* TR state */
+
+/* MAC RX Status */
+#define B43_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */
+#define B43_RX_MAC_KEYIDX 0x000007E0 /* Key index */
+#define B43_RX_MAC_KEYIDX_SHIFT 5
+#define B43_RX_MAC_DECERR 0x00000010 /* Decrypt error */
+#define B43_RX_MAC_DEC 0x00000008 /* Decryption attempted */
+#define B43_RX_MAC_PADDING 0x00000004 /* Pad bytes present */
+#define B43_RX_MAC_RESP 0x00000002 /* Response frame transmitted */
+#define B43_RX_MAC_FCSERR 0x00000001 /* FCS error */
+
+/* RX channel */
+#define B43_RX_CHAN_GAIN 0xFC00 /* Gain */
+#define B43_RX_CHAN_GAIN_SHIFT 10
+#define B43_RX_CHAN_ID 0x03FC /* Channel ID */
+#define B43_RX_CHAN_ID_SHIFT 2
+#define B43_RX_CHAN_PHYTYPE 0x0003 /* PHY type */
+
+u8 b43_plcp_get_ratecode_cck(const u8 bitrate);
+u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate);
+
+void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
+ const u16 octets, const u8 bitrate);
+
+void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr);
+
+void b43_handle_txstatus(struct b43_wldev *dev,
+ const struct b43_txstatus *status);
+
+void b43_handle_hwtxstatus(struct b43_wldev *dev,
+ const struct b43_hwtxstatus *hw);
+
+void b43_tx_suspend(struct b43_wldev *dev);
+void b43_tx_resume(struct b43_wldev *dev);
+
+#define B43_NR_QOSPARMS 22
+enum {
+ B43_QOSPARM_TXOP = 0,
+ B43_QOSPARM_CWMIN,
+ B43_QOSPARM_CWMAX,
+ B43_QOSPARM_CWCUR,
+ B43_QOSPARM_AIFS,
+ B43_QOSPARM_BSLOTS,
+ B43_QOSPARM_REGGAP,
+ B43_QOSPARM_STATUS,
+};
+void b43_qos_init(struct b43_wldev *dev);
+
+/* Helper functions for converting the key-table index from "firmware-format"
+ * to "raw-format" and back. The firmware API changed for this at some revision.
+ * We need to account for that here. */
+static inline int b43_new_kidx_api(struct b43_wldev *dev)
+{
+ /* FIXME: Not sure the change was at rev 351 */
+ return (dev->fw.rev >= 351);
+}
+static inline u8 b43_kidx_to_fw(struct b43_wldev *dev, u8 raw_kidx)
+{
+ u8 firmware_kidx;
+ if (b43_new_kidx_api(dev)) {
+ firmware_kidx = raw_kidx;
+ } else {
+ if (raw_kidx >= 4) /* Is per STA key? */
+ firmware_kidx = raw_kidx - 4;
+ else
+ firmware_kidx = raw_kidx; /* TX default key */
+ }
+ return firmware_kidx;
+}
+static inline u8 b43_kidx_to_raw(struct b43_wldev *dev, u8 firmware_kidx)
+{
+ u8 raw_kidx;
+ if (b43_new_kidx_api(dev))
+ raw_kidx = firmware_kidx;
+ else
+ raw_kidx = firmware_kidx + 4; /* RX default keys or per STA keys */
+ return raw_kidx;
+}
+
+#endif /* B43_XMIT_H_ */
diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig
new file mode 100644
index 00000000000..7e23ec23fc9
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/Kconfig
@@ -0,0 +1,89 @@
+config B43LEGACY
+ tristate "Broadcom 43xx-legacy wireless support (mac80211 stack)"
+ depends on SSB_POSSIBLE && MAC80211 && WLAN_80211
+ select SSB
+ select FW_LOADER
+ select HW_RANDOM
+ ---help---
+ b43legacy is a driver for 802.11b devices from Broadcom (BCM4301 and
+ BCM4303) and early model 802.11g chips (BCM4306 Ver. 2) used in the
+ Linksys WPC54G V1 PCMCIA devices.
+
+ Newer 802.11g and 802.11a devices need b43.
+
+ It is safe to include both b43 and b43legacy as the underlying glue
+ layer will automatically load the correct version for your device.
+
+ This driver uses V3 firmware, which must be installed separately using
+ b43-fwcutter.
+
+ This driver can be built as a module (recommended) that will be
+ called "b43legacy". If unsure, say M.
+
+# Auto-select SSB PCI-HOST support, if possible
+config B43LEGACY_PCI_AUTOSELECT
+ bool
+ depends on B43LEGACY && SSB_PCIHOST_POSSIBLE
+ select SSB_PCIHOST
+ default y
+
+# Auto-select SSB PCICORE driver, if possible
+config B43LEGACY_PCICORE_AUTOSELECT
+ bool
+ depends on B43LEGACY && SSB_DRIVER_PCICORE_POSSIBLE
+ select SSB_DRIVER_PCICORE
+ default y
+
+config B43LEGACY_DEBUG
+ bool "Broadcom 43xx-legacy debugging"
+ depends on B43LEGACY
+ default y
+ ---help---
+ Say Y, because this information will help you get the driver running.
+ This option generates a minimum of log output.
+
+config B43LEGACY_DMA
+ bool
+ depends on B43LEGACY
+
+config B43LEGACY_PIO
+ bool
+ depends on B43LEGACY
+
+choice
+ prompt "Broadcom 43xx-legacy data transfer mode"
+ depends on B43LEGACY
+ default B43LEGACY_DMA_AND_PIO_MODE
+
+config B43LEGACY_DMA_AND_PIO_MODE
+ bool "DMA + PIO"
+ select B43LEGACY_DMA
+ select B43LEGACY_PIO
+ ---help---
+ Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
+ data transfer modes. The mode actually used is selectable through
+ the module parameter "pio". With pio=0 as a module parameter, the
+ default DMA is used, otherwise PIO is used.
+
+ If unsure, choose this option.
+
+config B43LEGACY_DMA_MODE
+ bool "DMA (Direct Memory Access) only"
+ select B43LEGACY_DMA
+ ---help---
+ Only include Direct Memory Access (DMA).
+ This reduces the size of the driver module, by omitting the PIO code.
+
+config B43LEGACY_PIO_MODE
+ bool "PIO (Programmed I/O) only"
+ select B43LEGACY_PIO
+ ---help---
+ Only include Programmed I/O (PIO).
+ This reduces the size of the driver module, by omitting the DMA code.
+ Please note that PIO transfers are slow (compared to DMA).
+
+ Also note that not all devices of the b43legacy series support PIO.
+
+ You should use PIO only if DMA does not work for you.
+
+endchoice
diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile
new file mode 100644
index 00000000000..ec3a2482bba
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/Makefile
@@ -0,0 +1,14 @@
+obj-$(CONFIG_B43LEGACY) += b43legacy.o
+b43legacy-obj-$(CONFIG_B43LEGACY_DEBUG) += debugfs.o
+
+b43legacy-obj-$(CONFIG_B43LEGACY_DMA) += dma.o
+b43legacy-obj-$(CONFIG_B43LEGACY_PIO) += pio.o
+
+b43legacy-objs := main.o \
+ ilt.o \
+ leds.o \
+ phy.o \
+ radio.o \
+ sysfs.o \
+ xmit.o \
+ $(b43legacy-obj-y)
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
new file mode 100644
index 00000000000..afe145cec06
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -0,0 +1,832 @@
+#ifndef B43legacy_H_
+#define B43legacy_H_
+
+#include <linux/hw_random.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/stringify.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <asm/atomic.h>
+#include <linux/io.h>
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_driver_chipcommon.h>
+
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+
+#include "debugfs.h"
+#include "leds.h"
+#include "phy.h"
+
+
+#define B43legacy_IRQWAIT_MAX_RETRIES 100
+
+#define B43legacy_RX_MAX_SSI 60 /* best guess at max ssi */
+
+/* MMIO offsets */
+#define B43legacy_MMIO_DMA0_REASON 0x20
+#define B43legacy_MMIO_DMA0_IRQ_MASK 0x24
+#define B43legacy_MMIO_DMA1_REASON 0x28
+#define B43legacy_MMIO_DMA1_IRQ_MASK 0x2C
+#define B43legacy_MMIO_DMA2_REASON 0x30
+#define B43legacy_MMIO_DMA2_IRQ_MASK 0x34
+#define B43legacy_MMIO_DMA3_REASON 0x38
+#define B43legacy_MMIO_DMA3_IRQ_MASK 0x3C
+#define B43legacy_MMIO_DMA4_REASON 0x40
+#define B43legacy_MMIO_DMA4_IRQ_MASK 0x44
+#define B43legacy_MMIO_DMA5_REASON 0x48
+#define B43legacy_MMIO_DMA5_IRQ_MASK 0x4C
+#define B43legacy_MMIO_MACCTL 0x120
+#define B43legacy_MMIO_STATUS_BITFIELD 0x120
+#define B43legacy_MMIO_STATUS2_BITFIELD 0x124
+#define B43legacy_MMIO_GEN_IRQ_REASON 0x128
+#define B43legacy_MMIO_GEN_IRQ_MASK 0x12C
+#define B43legacy_MMIO_RAM_CONTROL 0x130
+#define B43legacy_MMIO_RAM_DATA 0x134
+#define B43legacy_MMIO_PS_STATUS 0x140
+#define B43legacy_MMIO_RADIO_HWENABLED_HI 0x158
+#define B43legacy_MMIO_SHM_CONTROL 0x160
+#define B43legacy_MMIO_SHM_DATA 0x164
+#define B43legacy_MMIO_SHM_DATA_UNALIGNED 0x166
+#define B43legacy_MMIO_XMITSTAT_0 0x170
+#define B43legacy_MMIO_XMITSTAT_1 0x174
+#define B43legacy_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
+#define B43legacy_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
+
+/* 32-bit DMA */
+#define B43legacy_MMIO_DMA32_BASE0 0x200
+#define B43legacy_MMIO_DMA32_BASE1 0x220
+#define B43legacy_MMIO_DMA32_BASE2 0x240
+#define B43legacy_MMIO_DMA32_BASE3 0x260
+#define B43legacy_MMIO_DMA32_BASE4 0x280
+#define B43legacy_MMIO_DMA32_BASE5 0x2A0
+/* 64-bit DMA */
+#define B43legacy_MMIO_DMA64_BASE0 0x200
+#define B43legacy_MMIO_DMA64_BASE1 0x240
+#define B43legacy_MMIO_DMA64_BASE2 0x280
+#define B43legacy_MMIO_DMA64_BASE3 0x2C0
+#define B43legacy_MMIO_DMA64_BASE4 0x300
+#define B43legacy_MMIO_DMA64_BASE5 0x340
+/* PIO */
+#define B43legacy_MMIO_PIO1_BASE 0x300
+#define B43legacy_MMIO_PIO2_BASE 0x310
+#define B43legacy_MMIO_PIO3_BASE 0x320
+#define B43legacy_MMIO_PIO4_BASE 0x330
+
+#define B43legacy_MMIO_PHY_VER 0x3E0
+#define B43legacy_MMIO_PHY_RADIO 0x3E2
+#define B43legacy_MMIO_PHY0 0x3E6
+#define B43legacy_MMIO_ANTENNA 0x3E8
+#define B43legacy_MMIO_CHANNEL 0x3F0
+#define B43legacy_MMIO_CHANNEL_EXT 0x3F4
+#define B43legacy_MMIO_RADIO_CONTROL 0x3F6
+#define B43legacy_MMIO_RADIO_DATA_HIGH 0x3F8
+#define B43legacy_MMIO_RADIO_DATA_LOW 0x3FA
+#define B43legacy_MMIO_PHY_CONTROL 0x3FC
+#define B43legacy_MMIO_PHY_DATA 0x3FE
+#define B43legacy_MMIO_MACFILTER_CONTROL 0x420
+#define B43legacy_MMIO_MACFILTER_DATA 0x422
+#define B43legacy_MMIO_RCMTA_COUNT 0x43C /* Receive Match Transmitter Addr */
+#define B43legacy_MMIO_RADIO_HWENABLED_LO 0x49A
+#define B43legacy_MMIO_GPIO_CONTROL 0x49C
+#define B43legacy_MMIO_GPIO_MASK 0x49E
+#define B43legacy_MMIO_TSF_0 0x632 /* core rev < 3 only */
+#define B43legacy_MMIO_TSF_1 0x634 /* core rev < 3 only */
+#define B43legacy_MMIO_TSF_2 0x636 /* core rev < 3 only */
+#define B43legacy_MMIO_TSF_3 0x638 /* core rev < 3 only */
+#define B43legacy_MMIO_RNG 0x65A
+#define B43legacy_MMIO_POWERUP_DELAY 0x6A8
+
+/* SPROM boardflags_lo values */
+#define B43legacy_BFL_PACTRL 0x0002
+#define B43legacy_BFL_RSSI 0x0008
+#define B43legacy_BFL_EXTLNA 0x1000
+
+/* GPIO register offset, in both ChipCommon and PCI core. */
+#define B43legacy_GPIO_CONTROL 0x6c
+
+/* SHM Routing */
+#define B43legacy_SHM_SHARED 0x0001
+#define B43legacy_SHM_WIRELESS 0x0002
+#define B43legacy_SHM_HW 0x0004
+#define B43legacy_SHM_UCODE 0x0300
+
+/* SHM Routing modifiers */
+#define B43legacy_SHM_AUTOINC_R 0x0200 /* Read Auto-increment */
+#define B43legacy_SHM_AUTOINC_W 0x0100 /* Write Auto-increment */
+#define B43legacy_SHM_AUTOINC_RW (B43legacy_SHM_AUTOINC_R | \
+ B43legacy_SHM_AUTOINC_W)
+
+/* Misc SHM_SHARED offsets */
+#define B43legacy_SHM_SH_WLCOREREV 0x0016 /* 802.11 core revision */
+#define B43legacy_SHM_SH_HOSTFLO 0x005E /* Hostflags ucode opts (low) */
+#define B43legacy_SHM_SH_HOSTFHI 0x0060 /* Hostflags ucode opts (high) */
+/* SHM_SHARED crypto engine */
+#define B43legacy_SHM_SH_KEYIDXBLOCK 0x05D4 /* Key index/algorithm block */
+/* SHM_SHARED beacon variables */
+#define B43legacy_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word */
+/* SHM_SHARED ACK/CTS control */
+#define B43legacy_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word */
+/* SHM_SHARED probe response variables */
+#define B43legacy_SHM_SH_PRPHYCTL 0x0188 /* Probe Resp PHY TX control */
+#define B43legacy_SHM_SH_PRMAXTIME 0x0074 /* Probe Response max time */
+/* SHM_SHARED rate tables */
+/* SHM_SHARED microcode soft registers */
+#define B43legacy_SHM_SH_UCODEREV 0x0000 /* Microcode revision */
+#define B43legacy_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */
+#define B43legacy_SHM_SH_UCODEDATE 0x0004 /* Microcode date */
+#define B43legacy_SHM_SH_UCODETIME 0x0006 /* Microcode time */
+
+#define B43legacy_UCODEFLAGS_OFFSET 0x005E
+
+/* Hardware Radio Enable masks */
+#define B43legacy_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
+#define B43legacy_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
+/* HostFlags. See b43legacy_hf_read/write() */
+#define B43legacy_HF_SYMW 0x00000002 /* G-PHY SYM workaround */
+#define B43legacy_HF_GDCW 0x00000020 /* G-PHY DV cancel filter */
+#define B43legacy_HF_OFDMPABOOST 0x00000040 /* Enable PA boost OFDM */
+#define B43legacy_HF_EDCF 0x00000100 /* on if WME/MAC suspended */
+
+/* MacFilter offsets. */
+#define B43legacy_MACFILTER_SELF 0x0000
+#define B43legacy_MACFILTER_BSSID 0x0003
+#define B43legacy_MACFILTER_MAC 0x0010
+
+/* PHYVersioning */
+#define B43legacy_PHYTYPE_B 0x01
+#define B43legacy_PHYTYPE_G 0x02
+
+/* PHYRegisters */
+#define B43legacy_PHY_G_LO_CONTROL 0x0810
+#define B43legacy_PHY_ILT_G_CTRL 0x0472
+#define B43legacy_PHY_ILT_G_DATA1 0x0473
+#define B43legacy_PHY_ILT_G_DATA2 0x0474
+#define B43legacy_PHY_G_PCTL 0x0029
+#define B43legacy_PHY_RADIO_BITFIELD 0x0401
+#define B43legacy_PHY_G_CRS 0x0429
+#define B43legacy_PHY_NRSSILT_CTRL 0x0803
+#define B43legacy_PHY_NRSSILT_DATA 0x0804
+
+/* RadioRegisters */
+#define B43legacy_RADIOCTL_ID 0x01
+
+/* MAC Control bitfield */
+#define B43legacy_MACCTL_IHR_ENABLED 0x00000400 /* IHR Region Enabled */
+#define B43legacy_MACCTL_INFRA 0x00020000 /* Infrastructure mode */
+#define B43legacy_MACCTL_AP 0x00040000 /* AccessPoint mode */
+#define B43legacy_MACCTL_BEACPROMISC 0x00100000 /* Beacon Promiscuous */
+#define B43legacy_MACCTL_KEEP_BADPLCP 0x00200000 /* Keep bad PLCP frames */
+#define B43legacy_MACCTL_KEEP_CTL 0x00400000 /* Keep control frames */
+#define B43legacy_MACCTL_KEEP_BAD 0x00800000 /* Keep bad frames (FCS) */
+#define B43legacy_MACCTL_PROMISC 0x01000000 /* Promiscuous mode */
+#define B43legacy_MACCTL_GMODE 0x80000000 /* G Mode */
+
+/* StatusBitField */
+#define B43legacy_SBF_MAC_ENABLED 0x00000001
+#define B43legacy_SBF_CORE_READY 0x00000004
+#define B43legacy_SBF_400 0x00000400 /*FIXME: fix name*/
+#define B43legacy_SBF_XFER_REG_BYTESWAP 0x00010000
+#define B43legacy_SBF_MODE_NOTADHOC 0x00020000
+#define B43legacy_SBF_MODE_AP 0x00040000
+#define B43legacy_SBF_RADIOREG_LOCK 0x00080000
+#define B43legacy_SBF_MODE_MONITOR 0x00400000
+#define B43legacy_SBF_MODE_PROMISC 0x01000000
+#define B43legacy_SBF_PS1 0x02000000
+#define B43legacy_SBF_PS2 0x04000000
+#define B43legacy_SBF_NO_SSID_BCAST 0x08000000
+#define B43legacy_SBF_TIME_UPDATE 0x10000000
+
+/* 802.11 core specific TM State Low flags */
+#define B43legacy_TMSLOW_GMODE 0x20000000 /* G Mode Enable */
+#define B43legacy_TMSLOW_PLLREFSEL 0x00200000 /* PLL Freq Ref Select */
+#define B43legacy_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Ctrl Enbl */
+#define B43legacy_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */
+#define B43legacy_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */
+
+/* 802.11 core specific TM State High flags */
+#define B43legacy_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available */
+#define B43legacy_TMSHIGH_GPHY 0x00010000 /* G-PHY avail (rev >= 5) */
+
+#define B43legacy_UCODEFLAG_AUTODIV 0x0001
+
+/* Generic-Interrupt reasons. */
+#define B43legacy_IRQ_MAC_SUSPENDED 0x00000001
+#define B43legacy_IRQ_BEACON 0x00000002
+#define B43legacy_IRQ_TBTT_INDI 0x00000004 /* Target Beacon Transmit Time */
+#define B43legacy_IRQ_BEACON_TX_OK 0x00000008
+#define B43legacy_IRQ_BEACON_CANCEL 0x00000010
+#define B43legacy_IRQ_ATIM_END 0x00000020
+#define B43legacy_IRQ_PMQ 0x00000040
+#define B43legacy_IRQ_PIO_WORKAROUND 0x00000100
+#define B43legacy_IRQ_MAC_TXERR 0x00000200
+#define B43legacy_IRQ_PHY_TXERR 0x00000800
+#define B43legacy_IRQ_PMEVENT 0x00001000
+#define B43legacy_IRQ_TIMER0 0x00002000
+#define B43legacy_IRQ_TIMER1 0x00004000
+#define B43legacy_IRQ_DMA 0x00008000
+#define B43legacy_IRQ_TXFIFO_FLUSH_OK 0x00010000
+#define B43legacy_IRQ_CCA_MEASURE_OK 0x00020000
+#define B43legacy_IRQ_NOISESAMPLE_OK 0x00040000
+#define B43legacy_IRQ_UCODE_DEBUG 0x08000000
+#define B43legacy_IRQ_RFKILL 0x10000000
+#define B43legacy_IRQ_TX_OK 0x20000000
+#define B43legacy_IRQ_PHY_G_CHANGED 0x40000000
+#define B43legacy_IRQ_TIMEOUT 0x80000000
+
+#define B43legacy_IRQ_ALL 0xFFFFFFFF
+#define B43legacy_IRQ_MASKTEMPLATE (B43legacy_IRQ_MAC_SUSPENDED | \
+ B43legacy_IRQ_BEACON | \
+ B43legacy_IRQ_TBTT_INDI | \
+ B43legacy_IRQ_ATIM_END | \
+ B43legacy_IRQ_PMQ | \
+ B43legacy_IRQ_MAC_TXERR | \
+ B43legacy_IRQ_PHY_TXERR | \
+ B43legacy_IRQ_DMA | \
+ B43legacy_IRQ_TXFIFO_FLUSH_OK | \
+ B43legacy_IRQ_NOISESAMPLE_OK | \
+ B43legacy_IRQ_UCODE_DEBUG | \
+ B43legacy_IRQ_RFKILL | \
+ B43legacy_IRQ_TX_OK)
+
+/* Device specific rate values.
+ * The actual values defined here are (rate_in_mbps * 2).
+ * Some code depends on this. Don't change it. */
+#define B43legacy_CCK_RATE_1MB 2
+#define B43legacy_CCK_RATE_2MB 4
+#define B43legacy_CCK_RATE_5MB 11
+#define B43legacy_CCK_RATE_11MB 22
+#define B43legacy_OFDM_RATE_6MB 12
+#define B43legacy_OFDM_RATE_9MB 18
+#define B43legacy_OFDM_RATE_12MB 24
+#define B43legacy_OFDM_RATE_18MB 36
+#define B43legacy_OFDM_RATE_24MB 48
+#define B43legacy_OFDM_RATE_36MB 72
+#define B43legacy_OFDM_RATE_48MB 96
+#define B43legacy_OFDM_RATE_54MB 108
+/* Convert a b43legacy rate value to a rate in 100kbps */
+#define B43legacy_RATE_TO_100KBPS(rate) (((rate) * 10) / 2)
+
+
+#define B43legacy_DEFAULT_SHORT_RETRY_LIMIT 7
+#define B43legacy_DEFAULT_LONG_RETRY_LIMIT 4
+
+/* Max size of a security key */
+#define B43legacy_SEC_KEYSIZE 16
+/* Security algorithms. */
+enum {
+ B43legacy_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
+ B43legacy_SEC_ALGO_WEP40,
+ B43legacy_SEC_ALGO_TKIP,
+ B43legacy_SEC_ALGO_AES,
+ B43legacy_SEC_ALGO_WEP104,
+ B43legacy_SEC_ALGO_AES_LEGACY,
+};
+
+/* Core Information Registers */
+#define B43legacy_CIR_BASE 0xf00
+#define B43legacy_CIR_SBTPSFLAG (B43legacy_CIR_BASE + 0x18)
+#define B43legacy_CIR_SBIMSTATE (B43legacy_CIR_BASE + 0x90)
+#define B43legacy_CIR_SBINTVEC (B43legacy_CIR_BASE + 0x94)
+#define B43legacy_CIR_SBTMSTATELOW (B43legacy_CIR_BASE + 0x98)
+#define B43legacy_CIR_SBTMSTATEHIGH (B43legacy_CIR_BASE + 0x9c)
+#define B43legacy_CIR_SBIMCONFIGLOW (B43legacy_CIR_BASE + 0xa8)
+#define B43legacy_CIR_SB_ID_HI (B43legacy_CIR_BASE + 0xfc)
+
+/* sbtmstatehigh state flags */
+#define B43legacy_SBTMSTATEHIGH_SERROR 0x00000001
+#define B43legacy_SBTMSTATEHIGH_BUSY 0x00000004
+#define B43legacy_SBTMSTATEHIGH_TIMEOUT 0x00000020
+#define B43legacy_SBTMSTATEHIGH_G_PHY_AVAIL 0x00010000
+#define B43legacy_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000
+#define B43legacy_SBTMSTATEHIGH_DMA64BIT 0x10000000
+#define B43legacy_SBTMSTATEHIGH_GATEDCLK 0x20000000
+#define B43legacy_SBTMSTATEHIGH_BISTFAILED 0x40000000
+#define B43legacy_SBTMSTATEHIGH_BISTCOMPLETE 0x80000000
+
+/* sbimstate flags */
+#define B43legacy_SBIMSTATE_IB_ERROR 0x20000
+#define B43legacy_SBIMSTATE_TIMEOUT 0x40000
+
+#define PFX KBUILD_MODNAME ": "
+#ifdef assert
+# undef assert
+#endif
+#ifdef CONFIG_B43LEGACY_DEBUG
+# define B43legacy_WARN_ON(expr) \
+ do { \
+ if (unlikely((expr))) { \
+ printk(KERN_INFO PFX "Test (%s) failed at:" \
+ " %s:%d:%s()\n", \
+ #expr, __FILE__, \
+ __LINE__, __FUNCTION__); \
+ } \
+ } while (0)
+# define B43legacy_BUG_ON(expr) \
+ do { \
+ if (unlikely((expr))) { \
+ printk(KERN_INFO PFX "Test (%s) failed\n", \
+ #expr); \
+ BUG_ON(expr); \
+ } \
+ } while (0)
+# define B43legacy_DEBUG 1
+#else
+# define B43legacy_WARN_ON(x) do { /* nothing */ } while (0)
+# define B43legacy_BUG_ON(x) do { /* nothing */ } while (0)
+# define B43legacy_DEBUG 0
+#endif
+
+
+struct net_device;
+struct pci_dev;
+struct b43legacy_dmaring;
+struct b43legacy_pioqueue;
+
+/* The firmware file header */
+#define B43legacy_FW_TYPE_UCODE 'u'
+#define B43legacy_FW_TYPE_PCM 'p'
+#define B43legacy_FW_TYPE_IV 'i'
+struct b43legacy_fw_header {
+ /* File type */
+ u8 type;
+ /* File format version */
+ u8 ver;
+ u8 __padding[2];
+ /* Size of the data. For ucode and PCM this is in bytes.
+ * For IV this is number-of-ivs. */
+ __be32 size;
+} __attribute__((__packed__));
+
+/* Initial Value file format */
+#define B43legacy_IV_OFFSET_MASK 0x7FFF
+#define B43legacy_IV_32BIT 0x8000
+struct b43legacy_iv {
+ __be16 offset_size;
+ union {
+ __be16 d16;
+ __be32 d32;
+ } data __attribute__((__packed__));
+} __attribute__((__packed__));
+
+#define B43legacy_PHYMODE(phytype) (1 << (phytype))
+#define B43legacy_PHYMODE_B B43legacy_PHYMODE \
+ ((B43legacy_PHYTYPE_B))
+#define B43legacy_PHYMODE_G B43legacy_PHYMODE \
+ ((B43legacy_PHYTYPE_G))
+
+/* Value pair to measure the LocalOscillator. */
+struct b43legacy_lopair {
+ s8 low;
+ s8 high;
+ u8 used:1;
+};
+#define B43legacy_LO_COUNT (14*4)
+
+struct b43legacy_phy {
+ /* Possible PHYMODEs on this PHY */
+ u8 possible_phymodes;
+ /* GMODE bit enabled in MACCTL? */
+ bool gmode;
+ /* Possible ieee80211 subsystem hwmodes for this PHY.
+ * Which mode is selected, depends on thr GMODE enabled bit */
+#define B43legacy_MAX_PHYHWMODES 2
+ struct ieee80211_hw_mode hwmodes[B43legacy_MAX_PHYHWMODES];
+
+ /* Analog Type */
+ u8 analog;
+ /* B43legacy_PHYTYPE_ */
+ u8 type;
+ /* PHY revision number. */
+ u8 rev;
+
+ u16 antenna_diversity;
+ u16 savedpctlreg;
+ /* Radio versioning */
+ u16 radio_manuf; /* Radio manufacturer */
+ u16 radio_ver; /* Radio version */
+ u8 calibrated:1;
+ u8 radio_rev; /* Radio revision */
+
+ bool locked; /* Only used in b43legacy_phy_{un}lock() */
+ bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */
+
+ /* ACI (adjacent channel interference) flags. */
+ bool aci_enable;
+ bool aci_wlan_automatic;
+ bool aci_hw_rssi;
+
+ /* Radio switched on/off */
+ bool radio_on;
+ struct {
+ /* Values saved when turning the radio off.
+ * They are needed when turning it on again. */
+ bool valid;
+ u16 rfover;
+ u16 rfoverval;
+ } radio_off_context;
+
+ u16 minlowsig[2];
+ u16 minlowsigpos[2];
+
+ /* LO Measurement Data.
+ * Use b43legacy_get_lopair() to get a value.
+ */
+ struct b43legacy_lopair *_lo_pairs;
+ /* TSSI to dBm table in use */
+ const s8 *tssi2dbm;
+ /* idle TSSI value */
+ s8 idle_tssi;
+ /* Target idle TSSI */
+ int tgt_idle_tssi;
+ /* Current idle TSSI */
+ int cur_idle_tssi;
+
+ /* LocalOscillator control values. */
+ struct b43legacy_txpower_lo_control *lo_control;
+ /* Values from b43legacy_calc_loopback_gain() */
+ s16 max_lb_gain; /* Maximum Loopback gain in hdB */
+ s16 trsw_rx_gain; /* TRSW RX gain in hdB */
+ s16 lna_lod_gain; /* LNA lod */
+ s16 lna_gain; /* LNA */
+ s16 pga_gain; /* PGA */
+
+ /* PHY lock for core.rev < 3
+ * This lock is only used by b43legacy_phy_{un}lock()
+ */
+ spinlock_t lock;
+
+ /* Desired TX power level (in dBm). This is set by the user and
+ * adjusted in b43legacy_phy_xmitpower(). */
+ u8 power_level;
+
+ /* Values from b43legacy_calc_loopback_gain() */
+ u16 loopback_gain[2];
+
+ /* TX Power control values. */
+ /* B/G PHY */
+ struct {
+ /* Current Radio Attenuation for TXpower recalculation. */
+ u16 rfatt;
+ /* Current Baseband Attenuation for TXpower recalculation. */
+ u16 bbatt;
+ /* Current TXpower control value for TXpower recalculation. */
+ u16 txctl1;
+ u16 txctl2;
+ };
+ /* A PHY */
+ struct {
+ u16 txpwr_offset;
+ };
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+ bool manual_txpower_control; /* Manual TX-power control enabled? */
+#endif
+ /* Current Interference Mitigation mode */
+ int interfmode;
+ /* Stack of saved values from the Interference Mitigation code.
+ * Each value in the stack is layed out as follows:
+ * bit 0-11: offset
+ * bit 12-15: register ID
+ * bit 16-32: value
+ * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
+ */
+#define B43legacy_INTERFSTACK_SIZE 26
+ u32 interfstack[B43legacy_INTERFSTACK_SIZE];
+
+ /* Saved values from the NRSSI Slope calculation */
+ s16 nrssi[2];
+ s32 nrssislope;
+ /* In memory nrssi lookup table. */
+ s8 nrssi_lt[64];
+
+ /* current channel */
+ u8 channel;
+
+ u16 lofcal;
+
+ u16 initval;
+};
+
+/* Data structures for DMA transmission, per 80211 core. */
+struct b43legacy_dma {
+ struct b43legacy_dmaring *tx_ring0;
+ struct b43legacy_dmaring *tx_ring1;
+ struct b43legacy_dmaring *tx_ring2;
+ struct b43legacy_dmaring *tx_ring3;
+ struct b43legacy_dmaring *tx_ring4;
+ struct b43legacy_dmaring *tx_ring5;
+
+ struct b43legacy_dmaring *rx_ring0;
+ struct b43legacy_dmaring *rx_ring3; /* only on core.rev < 5 */
+};
+
+/* Data structures for PIO transmission, per 80211 core. */
+struct b43legacy_pio {
+ struct b43legacy_pioqueue *queue0;
+ struct b43legacy_pioqueue *queue1;
+ struct b43legacy_pioqueue *queue2;
+ struct b43legacy_pioqueue *queue3;
+};
+
+/* Context information for a noise calculation (Link Quality). */
+struct b43legacy_noise_calculation {
+ u8 channel_at_start;
+ bool calculation_running;
+ u8 nr_samples;
+ s8 samples[8][4];
+};
+
+struct b43legacy_stats {
+ u8 link_noise;
+ /* Store the last TX/RX times here for updating the leds. */
+ unsigned long last_tx;
+ unsigned long last_rx;
+};
+
+struct b43legacy_key {
+ void *keyconf;
+ bool enabled;
+ u8 algorithm;
+};
+
+struct b43legacy_wldev;
+
+/* Data structure for the WLAN parts (802.11 cores) of the b43legacy chip. */
+struct b43legacy_wl {
+ /* Pointer to the active wireless device on this chip */
+ struct b43legacy_wldev *current_dev;
+ /* Pointer to the ieee80211 hardware data structure */
+ struct ieee80211_hw *hw;
+
+ spinlock_t irq_lock; /* locks IRQ */
+ struct mutex mutex; /* locks wireless core state */
+ spinlock_t leds_lock; /* lock for leds */
+
+ /* We can only have one operating interface (802.11 core)
+ * at a time. General information about this interface follows.
+ */
+
+ /* Opaque ID of the operating interface from the ieee80211
+ * subsystem. Do not modify.
+ */
+ int if_id;
+ /* MAC address (can be NULL). */
+ u8 mac_addr[ETH_ALEN];
+ /* Current BSSID (can be NULL). */
+ u8 bssid[ETH_ALEN];
+ /* Interface type. (IEEE80211_IF_TYPE_XXX) */
+ int if_type;
+ /* Is the card operating in AP, STA or IBSS mode? */
+ bool operating;
+ /* filter flags */
+ unsigned int filter_flags;
+ /* Stats about the wireless interface */
+ struct ieee80211_low_level_stats ieee_stats;
+
+ struct hwrng rng;
+ u8 rng_initialized;
+ char rng_name[30 + 1];
+
+ /* List of all wireless devices on this chip */
+ struct list_head devlist;
+ u8 nr_devs;
+};
+
+/* Pointers to the firmware data and meta information about it. */
+struct b43legacy_firmware {
+ /* Microcode */
+ const struct firmware *ucode;
+ /* PCM code */
+ const struct firmware *pcm;
+ /* Initial MMIO values for the firmware */
+ const struct firmware *initvals;
+ /* Initial MMIO values for the firmware, band-specific */
+ const struct firmware *initvals_band;
+ /* Firmware revision */
+ u16 rev;
+ /* Firmware patchlevel */
+ u16 patch;
+};
+
+/* Device (802.11 core) initialization status. */
+enum {
+ B43legacy_STAT_UNINIT = 0, /* Uninitialized. */
+ B43legacy_STAT_INITIALIZED = 1, /* Initialized, not yet started. */
+ B43legacy_STAT_STARTED = 2, /* Up and running. */
+};
+#define b43legacy_status(wldev) atomic_read(&(wldev)->__init_status)
+#define b43legacy_set_status(wldev, stat) do { \
+ atomic_set(&(wldev)->__init_status, (stat)); \
+ smp_wmb(); \
+ } while (0)
+
+/* *** --- HOW LOCKING WORKS IN B43legacy --- ***
+ *
+ * You should always acquire both, wl->mutex and wl->irq_lock unless:
+ * - You don't need to acquire wl->irq_lock, if the interface is stopped.
+ * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet
+ * and packet TX path (and _ONLY_ there.)
+ */
+
+/* Data structure for one wireless device (802.11 core) */
+struct b43legacy_wldev {
+ struct ssb_device *dev;
+ struct b43legacy_wl *wl;
+
+ /* The device initialization status.
+ * Use b43legacy_status() to query. */
+ atomic_t __init_status;
+ /* Saved init status for handling suspend. */
+ int suspend_init_status;
+
+ bool __using_pio; /* Using pio rather than dma. */
+ bool bad_frames_preempt;/* Use "Bad Frames Preemption". */
+ bool reg124_set_0x4; /* Variable to keep track of IRQ. */
+ bool short_preamble; /* TRUE if using short preamble. */
+ bool short_slot; /* TRUE if using short slot timing. */
+ bool radio_hw_enable; /* State of radio hardware enable bit. */
+
+ /* PHY/Radio device. */
+ struct b43legacy_phy phy;
+ union {
+ /* DMA engines. */
+ struct b43legacy_dma dma;
+ /* PIO engines. */
+ struct b43legacy_pio pio;
+ };
+
+ /* Various statistics about the physical device. */
+ struct b43legacy_stats stats;
+
+#define B43legacy_NR_LEDS 4
+ struct b43legacy_led leds[B43legacy_NR_LEDS];
+
+ /* Reason code of the last interrupt. */
+ u32 irq_reason;
+ u32 dma_reason[6];
+ /* saved irq enable/disable state bitfield. */
+ u32 irq_savedstate;
+ /* Link Quality calculation context. */
+ struct b43legacy_noise_calculation noisecalc;
+ /* if > 0 MAC is suspended. if == 0 MAC is enabled. */
+ int mac_suspended;
+
+ /* Interrupt Service Routine tasklet (bottom-half) */
+ struct tasklet_struct isr_tasklet;
+
+ /* Periodic tasks */
+ struct delayed_work periodic_work;
+ unsigned int periodic_state;
+
+ struct work_struct restart_work;
+
+ /* encryption/decryption */
+ u16 ktp; /* Key table pointer */
+ u8 max_nr_keys;
+ struct b43legacy_key key[58];
+
+ /* Cached beacon template while uploading the template. */
+ struct sk_buff *cached_beacon;
+
+ /* Firmware data */
+ struct b43legacy_firmware fw;
+
+ /* Devicelist in struct b43legacy_wl (all 802.11 cores) */
+ struct list_head list;
+
+ /* Debugging stuff follows. */
+#ifdef CONFIG_B43LEGACY_DEBUG
+ struct b43legacy_dfsentry *dfsentry;
+#endif
+};
+
+
+static inline
+struct b43legacy_wl *hw_to_b43legacy_wl(struct ieee80211_hw *hw)
+{
+ return hw->priv;
+}
+
+/* Helper function, which returns a boolean.
+ * TRUE, if PIO is used; FALSE, if DMA is used.
+ */
+#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)
+static inline
+int b43legacy_using_pio(struct b43legacy_wldev *dev)
+{
+ return dev->__using_pio;
+}
+#elif defined(CONFIG_B43LEGACY_DMA)
+static inline
+int b43legacy_using_pio(struct b43legacy_wldev *dev)
+{
+ return 0;
+}
+#elif defined(CONFIG_B43LEGACY_PIO)
+static inline
+int b43legacy_using_pio(struct b43legacy_wldev *dev)
+{
+ return 1;
+}
+#else
+# error "Using neither DMA nor PIO? Confused..."
+#endif
+
+
+static inline
+struct b43legacy_wldev *dev_to_b43legacy_wldev(struct device *dev)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ return ssb_get_drvdata(ssb_dev);
+}
+
+/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */
+static inline
+int b43legacy_is_mode(struct b43legacy_wl *wl, int type)
+{
+ return (wl->operating &&
+ wl->if_type == type);
+}
+
+static inline
+bool is_bcm_board_vendor(struct b43legacy_wldev *dev)
+{
+ return (dev->dev->bus->boardinfo.vendor == PCI_VENDOR_ID_BROADCOM);
+}
+
+static inline
+u16 b43legacy_read16(struct b43legacy_wldev *dev, u16 offset)
+{
+ return ssb_read16(dev->dev, offset);
+}
+
+static inline
+void b43legacy_write16(struct b43legacy_wldev *dev, u16 offset, u16 value)
+{
+ ssb_write16(dev->dev, offset, value);
+}
+
+static inline
+u32 b43legacy_read32(struct b43legacy_wldev *dev, u16 offset)
+{
+ return ssb_read32(dev->dev, offset);
+}
+
+static inline
+void b43legacy_write32(struct b43legacy_wldev *dev, u16 offset, u32 value)
+{
+ ssb_write32(dev->dev, offset, value);
+}
+
+static inline
+struct b43legacy_lopair *b43legacy_get_lopair(struct b43legacy_phy *phy,
+ u16 radio_attenuation,
+ u16 baseband_attenuation)
+{
+ return phy->_lo_pairs + (radio_attenuation
+ + 14 * (baseband_attenuation / 2));
+}
+
+
+
+/* Message printing */
+void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+#if B43legacy_DEBUG
+void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+#else /* DEBUG */
+# define b43legacydbg(wl, fmt...) do { /* nothing */ } while (0)
+#endif /* DEBUG */
+
+
+/** Limit a value between two limits */
+#ifdef limit_value
+# undef limit_value
+#endif
+#define limit_value(value, min, max) \
+ ({ \
+ typeof(value) __value = (value); \
+ typeof(value) __min = (min); \
+ typeof(value) __max = (max); \
+ if (__value < __min) \
+ __value = __min; \
+ else if (__value > __max) \
+ __value = __max; \
+ __value; \
+ })
+
+/* Macros for printing a value in Q5.2 format */
+#define Q52_FMT "%u.%u"
+#define Q52_ARG(q52) ((q52) / 4), (((q52) & 3) * 100 / 4)
+
+#endif /* B43legacy_H_ */
diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c
new file mode 100644
index 00000000000..619b4534ef0
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/debugfs.c
@@ -0,0 +1,505 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ debugfs driver debugging code
+
+ Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+
+#include "b43legacy.h"
+#include "main.h"
+#include "debugfs.h"
+#include "dma.h"
+#include "pio.h"
+#include "xmit.h"
+
+
+/* The root directory. */
+static struct dentry *rootdir;
+
+struct b43legacy_debugfs_fops {
+ ssize_t (*read)(struct b43legacy_wldev *dev, char *buf, size_t bufsize);
+ int (*write)(struct b43legacy_wldev *dev, const char *buf, size_t count);
+ struct file_operations fops;
+ /* Offset of struct b43legacy_dfs_file in struct b43legacy_dfsentry */
+ size_t file_struct_offset;
+ /* Take wl->irq_lock before calling read/write? */
+ bool take_irqlock;
+};
+
+static inline
+struct b43legacy_dfs_file * fops_to_dfs_file(struct b43legacy_wldev *dev,
+ const struct b43legacy_debugfs_fops *dfops)
+{
+ void *p;
+
+ p = dev->dfsentry;
+ p += dfops->file_struct_offset;
+
+ return p;
+}
+
+
+#define fappend(fmt, x...) \
+ do { \
+ if (bufsize - count) \
+ count += snprintf(buf + count, \
+ bufsize - count, \
+ fmt , ##x); \
+ else \
+ printk(KERN_ERR "b43legacy: fappend overflow\n"); \
+ } while (0)
+
+
+/* wl->irq_lock is locked */
+static ssize_t tsf_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ u64 tsf;
+
+ b43legacy_tsf_read(dev, &tsf);
+ fappend("0x%08x%08x\n",
+ (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
+ (unsigned int)(tsf & 0xFFFFFFFFULL));
+
+ return count;
+}
+
+/* wl->irq_lock is locked */
+static int tsf_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count)
+{
+ u64 tsf;
+
+ if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1)
+ return -EINVAL;
+ b43legacy_tsf_write(dev, tsf);
+
+ return 0;
+}
+
+/* wl->irq_lock is locked */
+static ssize_t ucode_regs_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ fappend("r%d = 0x%04x\n", i,
+ b43legacy_shm_read16(dev, B43legacy_SHM_WIRELESS, i));
+ }
+
+ return count;
+}
+
+/* wl->irq_lock is locked */
+static ssize_t shm_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
+{
+ ssize_t count = 0;
+ int i;
+ u16 tmp;
+ __le16 *le16buf = (__le16 *)buf;
+
+ for (i = 0; i < 0x1000; i++) {
+ if (bufsize < sizeof(tmp))
+ break;
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 2 * i);
+ le16buf[i] = cpu_to_le16(tmp);
+ count += sizeof(tmp);
+ bufsize -= sizeof(tmp);
+ }
+
+ return count;
+}
+
+static ssize_t txstat_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
+{
+ struct b43legacy_txstatus_log *log = &dev->dfsentry->txstatlog;
+ ssize_t count = 0;
+ unsigned long flags;
+ int i, idx;
+ struct b43legacy_txstatus *stat;
+
+ spin_lock_irqsave(&log->lock, flags);
+ if (log->end < 0) {
+ fappend("Nothing transmitted, yet\n");
+ goto out_unlock;
+ }
+ fappend("b43legacy TX status reports:\n\n"
+ "index | cookie | seq | phy_stat | frame_count | "
+ "rts_count | supp_reason | pm_indicated | "
+ "intermediate | for_ampdu | acked\n" "---\n");
+ i = log->end + 1;
+ idx = 0;
+ while (1) {
+ if (i == B43legacy_NR_LOGGED_TXSTATUS)
+ i = 0;
+ stat = &(log->log[i]);
+ if (stat->cookie) {
+ fappend("%03d | "
+ "0x%04X | 0x%04X | 0x%02X | "
+ "0x%X | 0x%X | "
+ "%u | %u | "
+ "%u | %u | %u\n",
+ idx,
+ stat->cookie, stat->seq, stat->phy_stat,
+ stat->frame_count, stat->rts_count,
+ stat->supp_reason, stat->pm_indicated,
+ stat->intermediate, stat->for_ampdu,
+ stat->acked);
+ idx++;
+ }
+ if (i == log->end)
+ break;
+ i++;
+ }
+out_unlock:
+ spin_unlock_irqrestore(&log->lock, flags);
+
+ return count;
+}
+
+/* wl->irq_lock is locked */
+static int restart_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count)
+{
+ int err = 0;
+
+ if (count > 0 && buf[0] == '1') {
+ b43legacy_controller_restart(dev, "manually restarted");
+ } else
+ err = -EINVAL;
+
+ return err;
+}
+
+#undef fappend
+
+static int b43legacy_debugfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct b43legacy_wldev *dev;
+ struct b43legacy_debugfs_fops *dfops;
+ struct b43legacy_dfs_file *dfile;
+ ssize_t ret = 0;
+ char *buf;
+ const size_t bufsize = 1024 * 128;
+ const size_t buforder = get_order(bufsize);
+ int err = 0;
+
+ if (!count)
+ return 0;
+ dev = file->private_data;
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->wl->mutex);
+ if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
+ dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops);
+ if (!dfops->read) {
+ err = -ENOSYS;
+ goto out_unlock;
+ }
+ dfile = fops_to_dfs_file(dev, dfops);
+
+ if (!dfile->buffer) {
+ buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
+ if (!buf) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+ memset(buf, 0, bufsize);
+ if (dfops->take_irqlock) {
+ spin_lock_irq(&dev->wl->irq_lock);
+ ret = dfops->read(dev, buf, bufsize);
+ spin_unlock_irq(&dev->wl->irq_lock);
+ } else
+ ret = dfops->read(dev, buf, bufsize);
+ if (ret <= 0) {
+ free_pages((unsigned long)buf, buforder);
+ err = ret;
+ goto out_unlock;
+ }
+ dfile->data_len = ret;
+ dfile->buffer = buf;
+ }
+
+ ret = simple_read_from_buffer(userbuf, count, ppos,
+ dfile->buffer,
+ dfile->data_len);
+ if (*ppos >= dfile->data_len) {
+ free_pages((unsigned long)dfile->buffer, buforder);
+ dfile->buffer = NULL;
+ dfile->data_len = 0;
+ }
+out_unlock:
+ mutex_unlock(&dev->wl->mutex);
+
+ return err ? err : ret;
+}
+
+static ssize_t b43legacy_debugfs_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct b43legacy_wldev *dev;
+ struct b43legacy_debugfs_fops *dfops;
+ char *buf;
+ int err = 0;
+
+ if (!count)
+ return 0;
+ if (count > PAGE_SIZE)
+ return -E2BIG;
+ dev = file->private_data;
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->wl->mutex);
+ if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
+ err = -ENODEV;
+ goto out_unlock;
+ }
+
+ dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops);
+ if (!dfops->write) {
+ err = -ENOSYS;
+ goto out_unlock;
+ }
+
+ buf = (char *)get_zeroed_page(GFP_KERNEL);
+ if (!buf) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+ if (copy_from_user(buf, userbuf, count)) {
+ err = -EFAULT;
+ goto out_freepage;
+ }
+ if (dfops->take_irqlock) {
+ spin_lock_irq(&dev->wl->irq_lock);
+ err = dfops->write(dev, buf, count);
+ spin_unlock_irq(&dev->wl->irq_lock);
+ } else
+ err = dfops->write(dev, buf, count);
+ if (err)
+ goto out_freepage;
+
+out_freepage:
+ free_page((unsigned long)buf);
+out_unlock:
+ mutex_unlock(&dev->wl->mutex);
+
+ return err ? err : count;
+}
+
+
+#define B43legacy_DEBUGFS_FOPS(name, _read, _write, _take_irqlock) \
+ static struct b43legacy_debugfs_fops fops_##name = { \
+ .read = _read, \
+ .write = _write, \
+ .fops = { \
+ .open = b43legacy_debugfs_open, \
+ .read = b43legacy_debugfs_read, \
+ .write = b43legacy_debugfs_write, \
+ }, \
+ .file_struct_offset = offsetof(struct b43legacy_dfsentry, \
+ file_##name), \
+ .take_irqlock = _take_irqlock, \
+ }
+
+B43legacy_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
+B43legacy_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1);
+B43legacy_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1);
+B43legacy_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
+B43legacy_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
+
+
+int b43legacy_debug(struct b43legacy_wldev *dev, enum b43legacy_dyndbg feature)
+{
+ return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
+}
+
+static void b43legacy_remove_dynamic_debug(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_dfsentry *e = dev->dfsentry;
+ int i;
+
+ for (i = 0; i < __B43legacy_NR_DYNDBG; i++)
+ debugfs_remove(e->dyn_debug_dentries[i]);
+}
+
+static void b43legacy_add_dynamic_debug(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_dfsentry *e = dev->dfsentry;
+ struct dentry *d;
+
+#define add_dyn_dbg(name, id, initstate) do { \
+ e->dyn_debug[id] = (initstate); \
+ d = debugfs_create_bool(name, 0600, e->subdir, \
+ &(e->dyn_debug[id])); \
+ if (!IS_ERR(d)) \
+ e->dyn_debug_dentries[id] = d; \
+ } while (0)
+
+ add_dyn_dbg("debug_xmitpower", B43legacy_DBG_XMITPOWER, 0);
+ add_dyn_dbg("debug_dmaoverflow", B43legacy_DBG_DMAOVERFLOW, 0);
+ add_dyn_dbg("debug_dmaverbose", B43legacy_DBG_DMAVERBOSE, 0);
+ add_dyn_dbg("debug_pwork_fast", B43legacy_DBG_PWORK_FAST, 0);
+ add_dyn_dbg("debug_pwork_stop", B43legacy_DBG_PWORK_STOP, 0);
+
+#undef add_dyn_dbg
+}
+
+void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_dfsentry *e;
+ struct b43legacy_txstatus_log *log;
+ char devdir[16];
+
+ B43legacy_WARN_ON(!dev);
+ e = kzalloc(sizeof(*e), GFP_KERNEL);
+ if (!e) {
+ b43legacyerr(dev->wl, "debugfs: add device OOM\n");
+ return;
+ }
+ e->dev = dev;
+ log = &e->txstatlog;
+ log->log = kcalloc(B43legacy_NR_LOGGED_TXSTATUS,
+ sizeof(struct b43legacy_txstatus), GFP_KERNEL);
+ if (!log->log) {
+ b43legacyerr(dev->wl, "debugfs: add device txstatus OOM\n");
+ kfree(e);
+ return;
+ }
+ log->end = -1;
+ spin_lock_init(&log->lock);
+
+ dev->dfsentry = e;
+
+ snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
+ e->subdir = debugfs_create_dir(devdir, rootdir);
+ if (!e->subdir || IS_ERR(e->subdir)) {
+ if (e->subdir == ERR_PTR(-ENODEV)) {
+ b43legacydbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
+ "enabled in kernel config\n");
+ } else {
+ b43legacyerr(dev->wl, "debugfs: cannot create %s directory\n",
+ devdir);
+ }
+ dev->dfsentry = NULL;
+ kfree(log->log);
+ kfree(e);
+ return;
+ }
+
+#define ADD_FILE(name, mode) \
+ do { \
+ struct dentry *d; \
+ d = debugfs_create_file(__stringify(name), \
+ mode, e->subdir, dev, \
+ &fops_##name.fops); \
+ e->file_##name.dentry = NULL; \
+ if (!IS_ERR(d)) \
+ e->file_##name.dentry = d; \
+ } while (0)
+
+
+ ADD_FILE(tsf, 0600);
+ ADD_FILE(ucode_regs, 0400);
+ ADD_FILE(shm, 0400);
+ ADD_FILE(txstat, 0400);
+ ADD_FILE(restart, 0200);
+
+#undef ADD_FILE
+
+ b43legacy_add_dynamic_debug(dev);
+}
+
+void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_dfsentry *e;
+
+ if (!dev)
+ return;
+ e = dev->dfsentry;
+ if (!e)
+ return;
+ b43legacy_remove_dynamic_debug(dev);
+
+ debugfs_remove(e->file_tsf.dentry);
+ debugfs_remove(e->file_ucode_regs.dentry);
+ debugfs_remove(e->file_shm.dentry);
+ debugfs_remove(e->file_txstat.dentry);
+ debugfs_remove(e->file_restart.dentry);
+
+ debugfs_remove(e->subdir);
+ kfree(e->txstatlog.log);
+ kfree(e);
+}
+
+void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+{
+ struct b43legacy_dfsentry *e = dev->dfsentry;
+ struct b43legacy_txstatus_log *log;
+ struct b43legacy_txstatus *cur;
+ int i;
+
+ if (!e)
+ return;
+ log = &e->txstatlog;
+ B43legacy_WARN_ON(!irqs_disabled());
+ spin_lock(&log->lock);
+ i = log->end + 1;
+ if (i == B43legacy_NR_LOGGED_TXSTATUS)
+ i = 0;
+ log->end = i;
+ cur = &(log->log[i]);
+ memcpy(cur, status, sizeof(*cur));
+ spin_unlock(&log->lock);
+}
+
+void b43legacy_debugfs_init(void)
+{
+ rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (IS_ERR(rootdir))
+ rootdir = NULL;
+}
+
+void b43legacy_debugfs_exit(void)
+{
+ debugfs_remove(rootdir);
+}
diff --git a/drivers/net/wireless/b43legacy/debugfs.h b/drivers/net/wireless/b43legacy/debugfs.h
new file mode 100644
index 00000000000..ae3b0d0fa84
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/debugfs.h
@@ -0,0 +1,89 @@
+#ifndef B43legacy_DEBUGFS_H_
+#define B43legacy_DEBUGFS_H_
+
+struct b43legacy_wldev;
+struct b43legacy_txstatus;
+
+enum b43legacy_dyndbg { /* Dynamic debugging features */
+ B43legacy_DBG_XMITPOWER,
+ B43legacy_DBG_DMAOVERFLOW,
+ B43legacy_DBG_DMAVERBOSE,
+ B43legacy_DBG_PWORK_FAST,
+ B43legacy_DBG_PWORK_STOP,
+ __B43legacy_NR_DYNDBG,
+};
+
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+
+struct dentry;
+
+#define B43legacy_NR_LOGGED_TXSTATUS 100
+
+struct b43legacy_txstatus_log {
+ struct b43legacy_txstatus *log;
+ int end;
+ spinlock_t lock; /* lock for debugging */
+};
+
+struct b43legacy_dfs_file {
+ struct dentry *dentry;
+ char *buffer;
+ size_t data_len;
+};
+
+struct b43legacy_dfsentry {
+ struct b43legacy_wldev *dev;
+ struct dentry *subdir;
+
+ struct b43legacy_dfs_file file_tsf;
+ struct b43legacy_dfs_file file_ucode_regs;
+ struct b43legacy_dfs_file file_shm;
+ struct b43legacy_dfs_file file_txstat;
+ struct b43legacy_dfs_file file_txpower_g;
+ struct b43legacy_dfs_file file_restart;
+ struct b43legacy_dfs_file file_loctls;
+
+ struct b43legacy_txstatus_log txstatlog;
+
+ /* Enabled/Disabled list for the dynamic debugging features. */
+ u32 dyn_debug[__B43legacy_NR_DYNDBG];
+ /* Dentries for the dynamic debugging entries. */
+ struct dentry *dyn_debug_dentries[__B43legacy_NR_DYNDBG];
+};
+
+int b43legacy_debug(struct b43legacy_wldev *dev,
+ enum b43legacy_dyndbg feature);
+
+void b43legacy_debugfs_init(void);
+void b43legacy_debugfs_exit(void);
+void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev);
+void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev);
+void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status);
+
+#else /* CONFIG_B43LEGACY_DEBUG*/
+
+static inline
+int b43legacy_debug(struct b43legacy_wldev *dev,
+ enum b43legacy_dyndbg feature)
+{
+ return 0;
+}
+
+static inline
+void b43legacy_debugfs_init(void) { }
+static inline
+void b43legacy_debugfs_exit(void) { }
+static inline
+void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev) { }
+static inline
+void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev) { }
+static inline
+void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+ { }
+
+#endif /* CONFIG_B43LEGACY_DEBUG*/
+
+#endif /* B43legacy_DEBUGFS_H_ */
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
new file mode 100644
index 00000000000..8cb3dc4c474
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -0,0 +1,1565 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ DMA ringbuffer and descriptor allocation/management
+
+ Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+
+ Some code in this file is derived from the b44.c driver
+ Copyright (C) 2002 David S. Miller
+ Copyright (C) Pekka Pietikainen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43legacy.h"
+#include "dma.h"
+#include "main.h"
+#include "debugfs.h"
+#include "xmit.h"
+
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <net/dst.h>
+
+/* 32bit DMA ops. */
+static
+struct b43legacy_dmadesc_generic *op32_idx2desc(
+ struct b43legacy_dmaring *ring,
+ int slot,
+ struct b43legacy_dmadesc_meta **meta)
+{
+ struct b43legacy_dmadesc32 *desc;
+
+ *meta = &(ring->meta[slot]);
+ desc = ring->descbase;
+ desc = &(desc[slot]);
+
+ return (struct b43legacy_dmadesc_generic *)desc;
+}
+
+static void op32_fill_descriptor(struct b43legacy_dmaring *ring,
+ struct b43legacy_dmadesc_generic *desc,
+ dma_addr_t dmaaddr, u16 bufsize,
+ int start, int end, int irq)
+{
+ struct b43legacy_dmadesc32 *descbase = ring->descbase;
+ int slot;
+ u32 ctl;
+ u32 addr;
+ u32 addrext;
+
+ slot = (int)(&(desc->dma32) - descbase);
+ B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+
+ addr = (u32)(dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
+ addrext = (u32)(dmaaddr & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ addr |= ssb_dma_translation(ring->dev->dev);
+ ctl = (bufsize - ring->frameoffset)
+ & B43legacy_DMA32_DCTL_BYTECNT;
+ if (slot == ring->nr_slots - 1)
+ ctl |= B43legacy_DMA32_DCTL_DTABLEEND;
+ if (start)
+ ctl |= B43legacy_DMA32_DCTL_FRAMESTART;
+ if (end)
+ ctl |= B43legacy_DMA32_DCTL_FRAMEEND;
+ if (irq)
+ ctl |= B43legacy_DMA32_DCTL_IRQ;
+ ctl |= (addrext << B43legacy_DMA32_DCTL_ADDREXT_SHIFT)
+ & B43legacy_DMA32_DCTL_ADDREXT_MASK;
+
+ desc->dma32.control = cpu_to_le32(ctl);
+ desc->dma32.address = cpu_to_le32(addr);
+}
+
+static void op32_poke_tx(struct b43legacy_dmaring *ring, int slot)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXINDEX,
+ (u32)(slot * sizeof(struct b43legacy_dmadesc32)));
+}
+
+static void op32_tx_suspend(struct b43legacy_dmaring *ring)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
+ b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL)
+ | B43legacy_DMA32_TXSUSPEND);
+}
+
+static void op32_tx_resume(struct b43legacy_dmaring *ring)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
+ b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL)
+ & ~B43legacy_DMA32_TXSUSPEND);
+}
+
+static int op32_get_current_rxslot(struct b43legacy_dmaring *ring)
+{
+ u32 val;
+
+ val = b43legacy_dma_read(ring, B43legacy_DMA32_RXSTATUS);
+ val &= B43legacy_DMA32_RXDPTR;
+
+ return (val / sizeof(struct b43legacy_dmadesc32));
+}
+
+static void op32_set_current_rxslot(struct b43legacy_dmaring *ring,
+ int slot)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX,
+ (u32)(slot * sizeof(struct b43legacy_dmadesc32)));
+}
+
+static const struct b43legacy_dma_ops dma32_ops = {
+ .idx2desc = op32_idx2desc,
+ .fill_descriptor = op32_fill_descriptor,
+ .poke_tx = op32_poke_tx,
+ .tx_suspend = op32_tx_suspend,
+ .tx_resume = op32_tx_resume,
+ .get_current_rxslot = op32_get_current_rxslot,
+ .set_current_rxslot = op32_set_current_rxslot,
+};
+
+/* 64bit DMA ops. */
+static
+struct b43legacy_dmadesc_generic *op64_idx2desc(
+ struct b43legacy_dmaring *ring,
+ int slot,
+ struct b43legacy_dmadesc_meta
+ **meta)
+{
+ struct b43legacy_dmadesc64 *desc;
+
+ *meta = &(ring->meta[slot]);
+ desc = ring->descbase;
+ desc = &(desc[slot]);
+
+ return (struct b43legacy_dmadesc_generic *)desc;
+}
+
+static void op64_fill_descriptor(struct b43legacy_dmaring *ring,
+ struct b43legacy_dmadesc_generic *desc,
+ dma_addr_t dmaaddr, u16 bufsize,
+ int start, int end, int irq)
+{
+ struct b43legacy_dmadesc64 *descbase = ring->descbase;
+ int slot;
+ u32 ctl0 = 0;
+ u32 ctl1 = 0;
+ u32 addrlo;
+ u32 addrhi;
+ u32 addrext;
+
+ slot = (int)(&(desc->dma64) - descbase);
+ B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+
+ addrlo = (u32)(dmaaddr & 0xFFFFFFFF);
+ addrhi = (((u64)dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
+ addrext = (((u64)dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ addrhi |= ssb_dma_translation(ring->dev->dev);
+ if (slot == ring->nr_slots - 1)
+ ctl0 |= B43legacy_DMA64_DCTL0_DTABLEEND;
+ if (start)
+ ctl0 |= B43legacy_DMA64_DCTL0_FRAMESTART;
+ if (end)
+ ctl0 |= B43legacy_DMA64_DCTL0_FRAMEEND;
+ if (irq)
+ ctl0 |= B43legacy_DMA64_DCTL0_IRQ;
+ ctl1 |= (bufsize - ring->frameoffset)
+ & B43legacy_DMA64_DCTL1_BYTECNT;
+ ctl1 |= (addrext << B43legacy_DMA64_DCTL1_ADDREXT_SHIFT)
+ & B43legacy_DMA64_DCTL1_ADDREXT_MASK;
+
+ desc->dma64.control0 = cpu_to_le32(ctl0);
+ desc->dma64.control1 = cpu_to_le32(ctl1);
+ desc->dma64.address_low = cpu_to_le32(addrlo);
+ desc->dma64.address_high = cpu_to_le32(addrhi);
+}
+
+static void op64_poke_tx(struct b43legacy_dmaring *ring, int slot)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXINDEX,
+ (u32)(slot * sizeof(struct b43legacy_dmadesc64)));
+}
+
+static void op64_tx_suspend(struct b43legacy_dmaring *ring)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
+ b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL)
+ | B43legacy_DMA64_TXSUSPEND);
+}
+
+static void op64_tx_resume(struct b43legacy_dmaring *ring)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
+ b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL)
+ & ~B43legacy_DMA64_TXSUSPEND);
+}
+
+static int op64_get_current_rxslot(struct b43legacy_dmaring *ring)
+{
+ u32 val;
+
+ val = b43legacy_dma_read(ring, B43legacy_DMA64_RXSTATUS);
+ val &= B43legacy_DMA64_RXSTATDPTR;
+
+ return (val / sizeof(struct b43legacy_dmadesc64));
+}
+
+static void op64_set_current_rxslot(struct b43legacy_dmaring *ring,
+ int slot)
+{
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX,
+ (u32)(slot * sizeof(struct b43legacy_dmadesc64)));
+}
+
+static const struct b43legacy_dma_ops dma64_ops = {
+ .idx2desc = op64_idx2desc,
+ .fill_descriptor = op64_fill_descriptor,
+ .poke_tx = op64_poke_tx,
+ .tx_suspend = op64_tx_suspend,
+ .tx_resume = op64_tx_resume,
+ .get_current_rxslot = op64_get_current_rxslot,
+ .set_current_rxslot = op64_set_current_rxslot,
+};
+
+
+static inline int free_slots(struct b43legacy_dmaring *ring)
+{
+ return (ring->nr_slots - ring->used_slots);
+}
+
+static inline int next_slot(struct b43legacy_dmaring *ring, int slot)
+{
+ B43legacy_WARN_ON(!(slot >= -1 && slot <= ring->nr_slots - 1));
+ if (slot == ring->nr_slots - 1)
+ return 0;
+ return slot + 1;
+}
+
+static inline int prev_slot(struct b43legacy_dmaring *ring, int slot)
+{
+ B43legacy_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1));
+ if (slot == 0)
+ return ring->nr_slots - 1;
+ return slot - 1;
+}
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+static void update_max_used_slots(struct b43legacy_dmaring *ring,
+ int current_used_slots)
+{
+ if (current_used_slots <= ring->max_used_slots)
+ return;
+ ring->max_used_slots = current_used_slots;
+ if (b43legacy_debug(ring->dev, B43legacy_DBG_DMAVERBOSE))
+ b43legacydbg(ring->dev->wl,
+ "max_used_slots increased to %d on %s ring %d\n",
+ ring->max_used_slots,
+ ring->tx ? "TX" : "RX",
+ ring->index);
+}
+#else
+static inline
+void update_max_used_slots(struct b43legacy_dmaring *ring,
+ int current_used_slots)
+{ }
+#endif /* DEBUG */
+
+/* Request a slot for usage. */
+static inline
+int request_slot(struct b43legacy_dmaring *ring)
+{
+ int slot;
+
+ B43legacy_WARN_ON(!ring->tx);
+ B43legacy_WARN_ON(ring->stopped);
+ B43legacy_WARN_ON(free_slots(ring) == 0);
+
+ slot = next_slot(ring, ring->current_slot);
+ ring->current_slot = slot;
+ ring->used_slots++;
+
+ update_max_used_slots(ring, ring->used_slots);
+
+ return slot;
+}
+
+/* Mac80211-queue to b43legacy-ring mapping */
+static struct b43legacy_dmaring *priority_to_txring(
+ struct b43legacy_wldev *dev,
+ int queue_priority)
+{
+ struct b43legacy_dmaring *ring;
+
+/*FIXME: For now we always run on TX-ring-1 */
+return dev->dma.tx_ring1;
+
+ /* 0 = highest priority */
+ switch (queue_priority) {
+ default:
+ B43legacy_WARN_ON(1);
+ /* fallthrough */
+ case 0:
+ ring = dev->dma.tx_ring3;
+ break;
+ case 1:
+ ring = dev->dma.tx_ring2;
+ break;
+ case 2:
+ ring = dev->dma.tx_ring1;
+ break;
+ case 3:
+ ring = dev->dma.tx_ring0;
+ break;
+ case 4:
+ ring = dev->dma.tx_ring4;
+ break;
+ case 5:
+ ring = dev->dma.tx_ring5;
+ break;
+ }
+
+ return ring;
+}
+
+/* Bcm4301-ring to mac80211-queue mapping */
+static inline int txring_to_priority(struct b43legacy_dmaring *ring)
+{
+ static const u8 idx_to_prio[] =
+ { 3, 2, 1, 0, 4, 5, };
+
+/*FIXME: have only one queue, for now */
+return 0;
+
+ return idx_to_prio[ring->index];
+}
+
+
+u16 b43legacy_dmacontroller_base(int dma64bit, int controller_idx)
+{
+ static const u16 map64[] = {
+ B43legacy_MMIO_DMA64_BASE0,
+ B43legacy_MMIO_DMA64_BASE1,
+ B43legacy_MMIO_DMA64_BASE2,
+ B43legacy_MMIO_DMA64_BASE3,
+ B43legacy_MMIO_DMA64_BASE4,
+ B43legacy_MMIO_DMA64_BASE5,
+ };
+ static const u16 map32[] = {
+ B43legacy_MMIO_DMA32_BASE0,
+ B43legacy_MMIO_DMA32_BASE1,
+ B43legacy_MMIO_DMA32_BASE2,
+ B43legacy_MMIO_DMA32_BASE3,
+ B43legacy_MMIO_DMA32_BASE4,
+ B43legacy_MMIO_DMA32_BASE5,
+ };
+
+ if (dma64bit) {
+ B43legacy_WARN_ON(!(controller_idx >= 0 &&
+ controller_idx < ARRAY_SIZE(map64)));
+ return map64[controller_idx];
+ }
+ B43legacy_WARN_ON(!(controller_idx >= 0 &&
+ controller_idx < ARRAY_SIZE(map32)));
+ return map32[controller_idx];
+}
+
+static inline
+dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring,
+ unsigned char *buf,
+ size_t len,
+ int tx)
+{
+ dma_addr_t dmaaddr;
+
+ if (tx)
+ dmaaddr = dma_map_single(ring->dev->dev->dev,
+ buf, len,
+ DMA_TO_DEVICE);
+ else
+ dmaaddr = dma_map_single(ring->dev->dev->dev,
+ buf, len,
+ DMA_FROM_DEVICE);
+
+ return dmaaddr;
+}
+
+static inline
+void unmap_descbuffer(struct b43legacy_dmaring *ring,
+ dma_addr_t addr,
+ size_t len,
+ int tx)
+{
+ if (tx)
+ dma_unmap_single(ring->dev->dev->dev,
+ addr, len,
+ DMA_TO_DEVICE);
+ else
+ dma_unmap_single(ring->dev->dev->dev,
+ addr, len,
+ DMA_FROM_DEVICE);
+}
+
+static inline
+void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring,
+ dma_addr_t addr,
+ size_t len)
+{
+ B43legacy_WARN_ON(ring->tx);
+
+ dma_sync_single_for_cpu(ring->dev->dev->dev,
+ addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+void sync_descbuffer_for_device(struct b43legacy_dmaring *ring,
+ dma_addr_t addr,
+ size_t len)
+{
+ B43legacy_WARN_ON(ring->tx);
+
+ dma_sync_single_for_device(ring->dev->dev->dev,
+ addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+void free_descriptor_buffer(struct b43legacy_dmaring *ring,
+ struct b43legacy_dmadesc_meta *meta,
+ int irq_context)
+{
+ if (meta->skb) {
+ if (irq_context)
+ dev_kfree_skb_irq(meta->skb);
+ else
+ dev_kfree_skb(meta->skb);
+ meta->skb = NULL;
+ }
+}
+
+static int alloc_ringmemory(struct b43legacy_dmaring *ring)
+{
+ struct device *dev = ring->dev->dev->dev;
+
+ ring->descbase = dma_alloc_coherent(dev, B43legacy_DMA_RINGMEMSIZE,
+ &(ring->dmabase), GFP_KERNEL);
+ if (!ring->descbase) {
+ b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
+ " failed\n");
+ return -ENOMEM;
+ }
+ memset(ring->descbase, 0, B43legacy_DMA_RINGMEMSIZE);
+
+ return 0;
+}
+
+static void free_ringmemory(struct b43legacy_dmaring *ring)
+{
+ struct device *dev = ring->dev->dev->dev;
+
+ dma_free_coherent(dev, B43legacy_DMA_RINGMEMSIZE,
+ ring->descbase, ring->dmabase);
+}
+
+/* Reset the RX DMA channel */
+int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
+ u16 mmio_base, int dma64)
+{
+ int i;
+ u32 value;
+ u16 offset;
+
+ might_sleep();
+
+ offset = dma64 ? B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL;
+ b43legacy_write32(dev, mmio_base + offset, 0);
+ for (i = 0; i < 10; i++) {
+ offset = dma64 ? B43legacy_DMA64_RXSTATUS :
+ B43legacy_DMA32_RXSTATUS;
+ value = b43legacy_read32(dev, mmio_base + offset);
+ if (dma64) {
+ value &= B43legacy_DMA64_RXSTAT;
+ if (value == B43legacy_DMA64_RXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ } else {
+ value &= B43legacy_DMA32_RXSTATE;
+ if (value == B43legacy_DMA32_RXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ }
+ msleep(1);
+ }
+ if (i != -1) {
+ b43legacyerr(dev->wl, "DMA RX reset timed out\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/* Reset the RX DMA channel */
+int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
+ u16 mmio_base, int dma64)
+{
+ int i;
+ u32 value;
+ u16 offset;
+
+ might_sleep();
+
+ for (i = 0; i < 10; i++) {
+ offset = dma64 ? B43legacy_DMA64_TXSTATUS :
+ B43legacy_DMA32_TXSTATUS;
+ value = b43legacy_read32(dev, mmio_base + offset);
+ if (dma64) {
+ value &= B43legacy_DMA64_TXSTAT;
+ if (value == B43legacy_DMA64_TXSTAT_DISABLED ||
+ value == B43legacy_DMA64_TXSTAT_IDLEWAIT ||
+ value == B43legacy_DMA64_TXSTAT_STOPPED)
+ break;
+ } else {
+ value &= B43legacy_DMA32_TXSTATE;
+ if (value == B43legacy_DMA32_TXSTAT_DISABLED ||
+ value == B43legacy_DMA32_TXSTAT_IDLEWAIT ||
+ value == B43legacy_DMA32_TXSTAT_STOPPED)
+ break;
+ }
+ msleep(1);
+ }
+ offset = dma64 ? B43legacy_DMA64_TXCTL : B43legacy_DMA32_TXCTL;
+ b43legacy_write32(dev, mmio_base + offset, 0);
+ for (i = 0; i < 10; i++) {
+ offset = dma64 ? B43legacy_DMA64_TXSTATUS :
+ B43legacy_DMA32_TXSTATUS;
+ value = b43legacy_read32(dev, mmio_base + offset);
+ if (dma64) {
+ value &= B43legacy_DMA64_TXSTAT;
+ if (value == B43legacy_DMA64_TXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ } else {
+ value &= B43legacy_DMA32_TXSTATE;
+ if (value == B43legacy_DMA32_TXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ }
+ msleep(1);
+ }
+ if (i != -1) {
+ b43legacyerr(dev->wl, "DMA TX reset timed out\n");
+ return -ENODEV;
+ }
+ /* ensure the reset is completed. */
+ msleep(1);
+
+ return 0;
+}
+
+static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
+ struct b43legacy_dmadesc_generic *desc,
+ struct b43legacy_dmadesc_meta *meta,
+ gfp_t gfp_flags)
+{
+ struct b43legacy_rxhdr_fw3 *rxhdr;
+ struct b43legacy_hwtxstatus *txstat;
+ dma_addr_t dmaaddr;
+ struct sk_buff *skb;
+
+ B43legacy_WARN_ON(ring->tx);
+
+ skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+ if (unlikely(!skb))
+ return -ENOMEM;
+ dmaaddr = map_descbuffer(ring, skb->data,
+ ring->rx_buffersize, 0);
+ if (dma_mapping_error(dmaaddr)) {
+ /* ugh. try to realloc in zone_dma */
+ gfp_flags |= GFP_DMA;
+
+ dev_kfree_skb_any(skb);
+
+ skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+ if (unlikely(!skb))
+ return -ENOMEM;
+ dmaaddr = map_descbuffer(ring, skb->data,
+ ring->rx_buffersize, 0);
+ }
+
+ if (dma_mapping_error(dmaaddr)) {
+ dev_kfree_skb_any(skb);
+ return -EIO;
+ }
+
+ meta->skb = skb;
+ meta->dmaaddr = dmaaddr;
+ ring->ops->fill_descriptor(ring, desc, dmaaddr,
+ ring->rx_buffersize, 0, 0, 0);
+
+ rxhdr = (struct b43legacy_rxhdr_fw3 *)(skb->data);
+ rxhdr->frame_len = 0;
+ txstat = (struct b43legacy_hwtxstatus *)(skb->data);
+ txstat->cookie = 0;
+
+ return 0;
+}
+
+/* Allocate the initial descbuffers.
+ * This is used for an RX ring only.
+ */
+static int alloc_initial_descbuffers(struct b43legacy_dmaring *ring)
+{
+ int i;
+ int err = -ENOMEM;
+ struct b43legacy_dmadesc_generic *desc;
+ struct b43legacy_dmadesc_meta *meta;
+
+ for (i = 0; i < ring->nr_slots; i++) {
+ desc = ring->ops->idx2desc(ring, i, &meta);
+
+ err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
+ if (err) {
+ b43legacyerr(ring->dev->wl,
+ "Failed to allocate initial descbuffers\n");
+ goto err_unwind;
+ }
+ }
+ mb(); /* all descbuffer setup before next line */
+ ring->used_slots = ring->nr_slots;
+ err = 0;
+out:
+ return err;
+
+err_unwind:
+ for (i--; i >= 0; i--) {
+ desc = ring->ops->idx2desc(ring, i, &meta);
+
+ unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
+ dev_kfree_skb(meta->skb);
+ }
+ goto out;
+}
+
+/* Do initial setup of the DMA controller.
+ * Reset the controller, write the ring busaddress
+ * and switch the "enable" bit on.
+ */
+static int dmacontroller_setup(struct b43legacy_dmaring *ring)
+{
+ int err = 0;
+ u32 value;
+ u32 addrext;
+ u32 trans = ssb_dma_translation(ring->dev->dev);
+
+ if (ring->tx) {
+ if (ring->dma64) {
+ u64 ringbase = (u64)(ring->dmabase);
+
+ addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = B43legacy_DMA64_TXENABLE;
+ value |= (addrext << B43legacy_DMA64_TXADDREXT_SHIFT)
+ & B43legacy_DMA64_TXADDREXT_MASK;
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
+ value);
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO,
+ (ringbase & 0xFFFFFFFF));
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI,
+ ((ringbase >> 32)
+ & ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ } else {
+ u32 ringbase = (u32)(ring->dmabase);
+
+ addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = B43legacy_DMA32_TXENABLE;
+ value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT)
+ & B43legacy_DMA32_TXADDREXT_MASK;
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
+ value);
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXRING,
+ (ringbase &
+ ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ }
+ } else {
+ err = alloc_initial_descbuffers(ring);
+ if (err)
+ goto out;
+ if (ring->dma64) {
+ u64 ringbase = (u64)(ring->dmabase);
+
+ addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = (ring->frameoffset <<
+ B43legacy_DMA64_RXFROFF_SHIFT);
+ value |= B43legacy_DMA64_RXENABLE;
+ value |= (addrext << B43legacy_DMA64_RXADDREXT_SHIFT)
+ & B43legacy_DMA64_RXADDREXT_MASK;
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXCTL,
+ value);
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO,
+ (ringbase & 0xFFFFFFFF));
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI,
+ ((ringbase >> 32) &
+ ~SSB_DMA_TRANSLATION_MASK) |
+ trans);
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX,
+ 200);
+ } else {
+ u32 ringbase = (u32)(ring->dmabase);
+
+ addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+ >> SSB_DMA_TRANSLATION_SHIFT;
+ value = (ring->frameoffset <<
+ B43legacy_DMA32_RXFROFF_SHIFT);
+ value |= B43legacy_DMA32_RXENABLE;
+ value |= (addrext <<
+ B43legacy_DMA32_RXADDREXT_SHIFT)
+ & B43legacy_DMA32_RXADDREXT_MASK;
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL,
+ value);
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXRING,
+ (ringbase &
+ ~SSB_DMA_TRANSLATION_MASK)
+ | trans);
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX,
+ 200);
+ }
+ }
+
+out:
+ return err;
+}
+
+/* Shutdown the DMA controller. */
+static void dmacontroller_cleanup(struct b43legacy_dmaring *ring)
+{
+ if (ring->tx) {
+ b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
+ ring->dma64);
+ if (ring->dma64) {
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, 0);
+ b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, 0);
+ } else
+ b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0);
+ } else {
+ b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
+ ring->dma64);
+ if (ring->dma64) {
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, 0);
+ b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, 0);
+ } else
+ b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0);
+ }
+}
+
+static void free_all_descbuffers(struct b43legacy_dmaring *ring)
+{
+ struct b43legacy_dmadesc_generic *desc;
+ struct b43legacy_dmadesc_meta *meta;
+ int i;
+
+ if (!ring->used_slots)
+ return;
+ for (i = 0; i < ring->nr_slots; i++) {
+ desc = ring->ops->idx2desc(ring, i, &meta);
+
+ if (!meta->skb) {
+ B43legacy_WARN_ON(!ring->tx);
+ continue;
+ }
+ if (ring->tx)
+ unmap_descbuffer(ring, meta->dmaaddr,
+ meta->skb->len, 1);
+ else
+ unmap_descbuffer(ring, meta->dmaaddr,
+ ring->rx_buffersize, 0);
+ free_descriptor_buffer(ring, meta, 0);
+ }
+}
+
+static u64 supported_dma_mask(struct b43legacy_wldev *dev)
+{
+ u32 tmp;
+ u16 mmio_base;
+
+ tmp = b43legacy_read32(dev, SSB_TMSHIGH);
+ if (tmp & SSB_TMSHIGH_DMA64)
+ return DMA_64BIT_MASK;
+ mmio_base = b43legacy_dmacontroller_base(0, 0);
+ b43legacy_write32(dev,
+ mmio_base + B43legacy_DMA32_TXCTL,
+ B43legacy_DMA32_TXADDREXT_MASK);
+ tmp = b43legacy_read32(dev, mmio_base +
+ B43legacy_DMA32_TXCTL);
+ if (tmp & B43legacy_DMA32_TXADDREXT_MASK)
+ return DMA_32BIT_MASK;
+
+ return DMA_30BIT_MASK;
+}
+
+/* Main initialization function. */
+static
+struct b43legacy_dmaring *b43legacy_setup_dmaring(
+ struct b43legacy_wldev *dev,
+ int controller_index,
+ int for_tx,
+ int dma64)
+{
+ struct b43legacy_dmaring *ring;
+ int err;
+ int nr_slots;
+ dma_addr_t dma_test;
+
+ ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+ if (!ring)
+ goto out;
+
+ nr_slots = B43legacy_RXRING_SLOTS;
+ if (for_tx)
+ nr_slots = B43legacy_TXRING_SLOTS;
+
+ ring->meta = kcalloc(nr_slots, sizeof(struct b43legacy_dmadesc_meta),
+ GFP_KERNEL);
+ if (!ring->meta)
+ goto err_kfree_ring;
+ if (for_tx) {
+ ring->txhdr_cache = kcalloc(nr_slots,
+ sizeof(struct b43legacy_txhdr_fw3),
+ GFP_KERNEL);
+ if (!ring->txhdr_cache)
+ goto err_kfree_meta;
+
+ /* test for ability to dma to txhdr_cache */
+ dma_test = dma_map_single(dev->dev->dev,
+ ring->txhdr_cache,
+ sizeof(struct b43legacy_txhdr_fw3),
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dma_test)) {
+ /* ugh realloc */
+ kfree(ring->txhdr_cache);
+ ring->txhdr_cache = kcalloc(nr_slots,
+ sizeof(struct b43legacy_txhdr_fw3),
+ GFP_KERNEL | GFP_DMA);
+ if (!ring->txhdr_cache)
+ goto err_kfree_meta;
+
+ dma_test = dma_map_single(dev->dev->dev,
+ ring->txhdr_cache,
+ sizeof(struct b43legacy_txhdr_fw3),
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dma_test))
+ goto err_kfree_txhdr_cache;
+ }
+
+ dma_unmap_single(dev->dev->dev,
+ dma_test, sizeof(struct b43legacy_txhdr_fw3),
+ DMA_TO_DEVICE);
+ }
+
+ ring->dev = dev;
+ ring->nr_slots = nr_slots;
+ ring->mmio_base = b43legacy_dmacontroller_base(dma64,
+ controller_index);
+ ring->index = controller_index;
+ ring->dma64 = !!dma64;
+ if (dma64)
+ ring->ops = &dma64_ops;
+ else
+ ring->ops = &dma32_ops;
+ if (for_tx) {
+ ring->tx = 1;
+ ring->current_slot = -1;
+ } else {
+ if (ring->index == 0) {
+ ring->rx_buffersize = B43legacy_DMA0_RX_BUFFERSIZE;
+ ring->frameoffset = B43legacy_DMA0_RX_FRAMEOFFSET;
+ } else if (ring->index == 3) {
+ ring->rx_buffersize = B43legacy_DMA3_RX_BUFFERSIZE;
+ ring->frameoffset = B43legacy_DMA3_RX_FRAMEOFFSET;
+ } else
+ B43legacy_WARN_ON(1);
+ }
+ spin_lock_init(&ring->lock);
+#ifdef CONFIG_B43LEGACY_DEBUG
+ ring->last_injected_overflow = jiffies;
+#endif
+
+ err = alloc_ringmemory(ring);
+ if (err)
+ goto err_kfree_txhdr_cache;
+ err = dmacontroller_setup(ring);
+ if (err)
+ goto err_free_ringmemory;
+
+out:
+ return ring;
+
+err_free_ringmemory:
+ free_ringmemory(ring);
+err_kfree_txhdr_cache:
+ kfree(ring->txhdr_cache);
+err_kfree_meta:
+ kfree(ring->meta);
+err_kfree_ring:
+ kfree(ring);
+ ring = NULL;
+ goto out;
+}
+
+/* Main cleanup function. */
+static void b43legacy_destroy_dmaring(struct b43legacy_dmaring *ring)
+{
+ if (!ring)
+ return;
+
+ b43legacydbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots:"
+ " %d/%d\n", (ring->dma64) ? "64" : "32", ring->mmio_base,
+ (ring->tx) ? "TX" : "RX",
+ ring->max_used_slots, ring->nr_slots);
+ /* Device IRQs are disabled prior entering this function,
+ * so no need to take care of concurrency with rx handler stuff.
+ */
+ dmacontroller_cleanup(ring);
+ free_all_descbuffers(ring);
+ free_ringmemory(ring);
+
+ kfree(ring->txhdr_cache);
+ kfree(ring->meta);
+ kfree(ring);
+}
+
+void b43legacy_dma_free(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_dma *dma;
+
+ if (b43legacy_using_pio(dev))
+ return;
+ dma = &dev->dma;
+
+ b43legacy_destroy_dmaring(dma->rx_ring3);
+ dma->rx_ring3 = NULL;
+ b43legacy_destroy_dmaring(dma->rx_ring0);
+ dma->rx_ring0 = NULL;
+
+ b43legacy_destroy_dmaring(dma->tx_ring5);
+ dma->tx_ring5 = NULL;
+ b43legacy_destroy_dmaring(dma->tx_ring4);
+ dma->tx_ring4 = NULL;
+ b43legacy_destroy_dmaring(dma->tx_ring3);
+ dma->tx_ring3 = NULL;
+ b43legacy_destroy_dmaring(dma->tx_ring2);
+ dma->tx_ring2 = NULL;
+ b43legacy_destroy_dmaring(dma->tx_ring1);
+ dma->tx_ring1 = NULL;
+ b43legacy_destroy_dmaring(dma->tx_ring0);
+ dma->tx_ring0 = NULL;
+}
+
+int b43legacy_dma_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_dma *dma = &dev->dma;
+ struct b43legacy_dmaring *ring;
+ int err;
+ u64 dmamask;
+ int dma64 = 0;
+
+ dmamask = supported_dma_mask(dev);
+ if (dmamask == DMA_64BIT_MASK)
+ dma64 = 1;
+
+ err = ssb_dma_set_mask(dev->dev, dmamask);
+ if (err) {
+#ifdef BCM43XX_PIO
+ b43legacywarn(dev->wl, "DMA for this device not supported. "
+ "Falling back to PIO\n");
+ dev->__using_pio = 1;
+ return -EAGAIN;
+#else
+ b43legacyerr(dev->wl, "DMA for this device not supported and "
+ "no PIO support compiled in\n");
+ return -EOPNOTSUPP;
+#endif
+ }
+
+ err = -ENOMEM;
+ /* setup TX DMA channels. */
+ ring = b43legacy_setup_dmaring(dev, 0, 1, dma64);
+ if (!ring)
+ goto out;
+ dma->tx_ring0 = ring;
+
+ ring = b43legacy_setup_dmaring(dev, 1, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx0;
+ dma->tx_ring1 = ring;
+
+ ring = b43legacy_setup_dmaring(dev, 2, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx1;
+ dma->tx_ring2 = ring;
+
+ ring = b43legacy_setup_dmaring(dev, 3, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx2;
+ dma->tx_ring3 = ring;
+
+ ring = b43legacy_setup_dmaring(dev, 4, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx3;
+ dma->tx_ring4 = ring;
+
+ ring = b43legacy_setup_dmaring(dev, 5, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx4;
+ dma->tx_ring5 = ring;
+
+ /* setup RX DMA channels. */
+ ring = b43legacy_setup_dmaring(dev, 0, 0, dma64);
+ if (!ring)
+ goto err_destroy_tx5;
+ dma->rx_ring0 = ring;
+
+ if (dev->dev->id.revision < 5) {
+ ring = b43legacy_setup_dmaring(dev, 3, 0, dma64);
+ if (!ring)
+ goto err_destroy_rx0;
+ dma->rx_ring3 = ring;
+ }
+
+ b43legacydbg(dev->wl, "%d-bit DMA initialized\n",
+ (dmamask == DMA_64BIT_MASK) ? 64 :
+ (dmamask == DMA_32BIT_MASK) ? 32 : 30);
+ err = 0;
+out:
+ return err;
+
+err_destroy_rx0:
+ b43legacy_destroy_dmaring(dma->rx_ring0);
+ dma->rx_ring0 = NULL;
+err_destroy_tx5:
+ b43legacy_destroy_dmaring(dma->tx_ring5);
+ dma->tx_ring5 = NULL;
+err_destroy_tx4:
+ b43legacy_destroy_dmaring(dma->tx_ring4);
+ dma->tx_ring4 = NULL;
+err_destroy_tx3:
+ b43legacy_destroy_dmaring(dma->tx_ring3);
+ dma->tx_ring3 = NULL;
+err_destroy_tx2:
+ b43legacy_destroy_dmaring(dma->tx_ring2);
+ dma->tx_ring2 = NULL;
+err_destroy_tx1:
+ b43legacy_destroy_dmaring(dma->tx_ring1);
+ dma->tx_ring1 = NULL;
+err_destroy_tx0:
+ b43legacy_destroy_dmaring(dma->tx_ring0);
+ dma->tx_ring0 = NULL;
+ goto out;
+}
+
+/* Generate a cookie for the TX header. */
+static u16 generate_cookie(struct b43legacy_dmaring *ring,
+ int slot)
+{
+ u16 cookie = 0x1000;
+
+ /* Use the upper 4 bits of the cookie as
+ * DMA controller ID and store the slot number
+ * in the lower 12 bits.
+ * Note that the cookie must never be 0, as this
+ * is a special value used in RX path.
+ */
+ switch (ring->index) {
+ case 0:
+ cookie = 0xA000;
+ break;
+ case 1:
+ cookie = 0xB000;
+ break;
+ case 2:
+ cookie = 0xC000;
+ break;
+ case 3:
+ cookie = 0xD000;
+ break;
+ case 4:
+ cookie = 0xE000;
+ break;
+ case 5:
+ cookie = 0xF000;
+ break;
+ }
+ B43legacy_WARN_ON(!(((u16)slot & 0xF000) == 0x0000));
+ cookie |= (u16)slot;
+
+ return cookie;
+}
+
+/* Inspect a cookie and find out to which controller/slot it belongs. */
+static
+struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev,
+ u16 cookie, int *slot)
+{
+ struct b43legacy_dma *dma = &dev->dma;
+ struct b43legacy_dmaring *ring = NULL;
+
+ switch (cookie & 0xF000) {
+ case 0xA000:
+ ring = dma->tx_ring0;
+ break;
+ case 0xB000:
+ ring = dma->tx_ring1;
+ break;
+ case 0xC000:
+ ring = dma->tx_ring2;
+ break;
+ case 0xD000:
+ ring = dma->tx_ring3;
+ break;
+ case 0xE000:
+ ring = dma->tx_ring4;
+ break;
+ case 0xF000:
+ ring = dma->tx_ring5;
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+ *slot = (cookie & 0x0FFF);
+ B43legacy_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots));
+
+ return ring;
+}
+
+static int dma_tx_fragment(struct b43legacy_dmaring *ring,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ const struct b43legacy_dma_ops *ops = ring->ops;
+ u8 *header;
+ int slot;
+ int err;
+ struct b43legacy_dmadesc_generic *desc;
+ struct b43legacy_dmadesc_meta *meta;
+ struct b43legacy_dmadesc_meta *meta_hdr;
+ struct sk_buff *bounce_skb;
+
+#define SLOTS_PER_PACKET 2
+ B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
+
+ /* Get a slot for the header. */
+ slot = request_slot(ring);
+ desc = ops->idx2desc(ring, slot, &meta_hdr);
+ memset(meta_hdr, 0, sizeof(*meta_hdr));
+
+ header = &(ring->txhdr_cache[slot * sizeof(
+ struct b43legacy_txhdr_fw3)]);
+ b43legacy_generate_txhdr(ring->dev, header,
+ skb->data, skb->len, ctl,
+ generate_cookie(ring, slot));
+
+ meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
+ sizeof(struct b43legacy_txhdr_fw3), 1);
+ if (dma_mapping_error(meta_hdr->dmaaddr))
+ return -EIO;
+ ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
+ sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0);
+
+ /* Get a slot for the payload. */
+ slot = request_slot(ring);
+ desc = ops->idx2desc(ring, slot, &meta);
+ memset(meta, 0, sizeof(*meta));
+
+ memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
+ meta->skb = skb;
+ meta->is_last_fragment = 1;
+
+ meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+ /* create a bounce buffer in zone_dma on mapping failure. */
+ if (dma_mapping_error(meta->dmaaddr)) {
+ bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
+ if (!bounce_skb) {
+ err = -ENOMEM;
+ goto out_unmap_hdr;
+ }
+
+ memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+ dev_kfree_skb_any(skb);
+ skb = bounce_skb;
+ meta->skb = skb;
+ meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+ if (dma_mapping_error(meta->dmaaddr)) {
+ err = -EIO;
+ goto out_free_bounce;
+ }
+ }
+
+ ops->fill_descriptor(ring, desc, meta->dmaaddr,
+ skb->len, 0, 1, 1);
+
+ wmb(); /* previous stuff MUST be done */
+ /* Now transfer the whole frame. */
+ ops->poke_tx(ring, next_slot(ring, slot));
+ return 0;
+
+out_free_bounce:
+ dev_kfree_skb_any(skb);
+out_unmap_hdr:
+ unmap_descbuffer(ring, meta_hdr->dmaaddr,
+ sizeof(struct b43legacy_txhdr_fw3), 1);
+ return err;
+}
+
+static inline
+int should_inject_overflow(struct b43legacy_dmaring *ring)
+{
+#ifdef CONFIG_B43LEGACY_DEBUG
+ if (unlikely(b43legacy_debug(ring->dev,
+ B43legacy_DBG_DMAOVERFLOW))) {
+ /* Check if we should inject another ringbuffer overflow
+ * to test handling of this situation in the stack. */
+ unsigned long next_overflow;
+
+ next_overflow = ring->last_injected_overflow + HZ;
+ if (time_after(jiffies, next_overflow)) {
+ ring->last_injected_overflow = jiffies;
+ b43legacydbg(ring->dev->wl,
+ "Injecting TX ring overflow on "
+ "DMA controller %d\n", ring->index);
+ return 1;
+ }
+ }
+#endif /* CONFIG_B43LEGACY_DEBUG */
+ return 0;
+}
+
+int b43legacy_dma_tx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ struct b43legacy_dmaring *ring;
+ int err = 0;
+ unsigned long flags;
+
+ ring = priority_to_txring(dev, ctl->queue);
+ spin_lock_irqsave(&ring->lock, flags);
+ B43legacy_WARN_ON(!ring->tx);
+ if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
+ b43legacywarn(dev->wl, "DMA queue overflow\n");
+ err = -ENOSPC;
+ goto out_unlock;
+ }
+ /* Check if the queue was stopped in mac80211,
+ * but we got called nevertheless.
+ * That would be a mac80211 bug. */
+ B43legacy_BUG_ON(ring->stopped);
+
+ err = dma_tx_fragment(ring, skb, ctl);
+ if (unlikely(err)) {
+ b43legacyerr(dev->wl, "DMA tx mapping failure\n");
+ goto out_unlock;
+ }
+ ring->nr_tx_packets++;
+ if ((free_slots(ring) < SLOTS_PER_PACKET) ||
+ should_inject_overflow(ring)) {
+ /* This TX ring is full. */
+ ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
+ ring->stopped = 1;
+ if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
+ b43legacydbg(dev->wl, "Stopped TX ring %d\n",
+ ring->index);
+ }
+out_unlock:
+ spin_unlock_irqrestore(&ring->lock, flags);
+
+ return err;
+}
+
+void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+{
+ const struct b43legacy_dma_ops *ops;
+ struct b43legacy_dmaring *ring;
+ struct b43legacy_dmadesc_generic *desc;
+ struct b43legacy_dmadesc_meta *meta;
+ int slot;
+
+ ring = parse_cookie(dev, status->cookie, &slot);
+ if (unlikely(!ring))
+ return;
+ B43legacy_WARN_ON(!irqs_disabled());
+ spin_lock(&ring->lock);
+
+ B43legacy_WARN_ON(!ring->tx);
+ ops = ring->ops;
+ while (1) {
+ B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+ desc = ops->idx2desc(ring, slot, &meta);
+
+ if (meta->skb)
+ unmap_descbuffer(ring, meta->dmaaddr,
+ meta->skb->len, 1);
+ else
+ unmap_descbuffer(ring, meta->dmaaddr,
+ sizeof(struct b43legacy_txhdr_fw3),
+ 1);
+
+ if (meta->is_last_fragment) {
+ B43legacy_WARN_ON(!meta->skb);
+ /* Call back to inform the ieee80211 subsystem about the
+ * status of the transmission.
+ * Some fields of txstat are already filled in dma_tx().
+ */
+ if (status->acked) {
+ meta->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+ } else {
+ if (!(meta->txstat.control.flags
+ & IEEE80211_TXCTL_NO_ACK))
+ meta->txstat.excessive_retries = 1;
+ }
+ if (status->frame_count == 0) {
+ /* The frame was not transmitted at all. */
+ meta->txstat.retry_count = 0;
+ } else
+ meta->txstat.retry_count = status->frame_count
+ - 1;
+ ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
+ &(meta->txstat));
+ /* skb is freed by ieee80211_tx_status_irqsafe() */
+ meta->skb = NULL;
+ } else {
+ /* No need to call free_descriptor_buffer here, as
+ * this is only the txhdr, which is not allocated.
+ */
+ B43legacy_WARN_ON(meta->skb != NULL);
+ }
+
+ /* Everything unmapped and free'd. So it's not used anymore. */
+ ring->used_slots--;
+
+ if (meta->is_last_fragment)
+ break;
+ slot = next_slot(ring, slot);
+ }
+ dev->stats.last_tx = jiffies;
+ if (ring->stopped) {
+ B43legacy_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
+ ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
+ ring->stopped = 0;
+ if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
+ b43legacydbg(dev->wl, "Woke up TX ring %d\n",
+ ring->index);
+ }
+
+ spin_unlock(&ring->lock);
+}
+
+void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ const int nr_queues = dev->wl->hw->queues;
+ struct b43legacy_dmaring *ring;
+ struct ieee80211_tx_queue_stats_data *data;
+ unsigned long flags;
+ int i;
+
+ for (i = 0; i < nr_queues; i++) {
+ data = &(stats->data[i]);
+ ring = priority_to_txring(dev, i);
+
+ spin_lock_irqsave(&ring->lock, flags);
+ data->len = ring->used_slots / SLOTS_PER_PACKET;
+ data->limit = ring->nr_slots / SLOTS_PER_PACKET;
+ data->count = ring->nr_tx_packets;
+ spin_unlock_irqrestore(&ring->lock, flags);
+ }
+}
+
+static void dma_rx(struct b43legacy_dmaring *ring,
+ int *slot)
+{
+ const struct b43legacy_dma_ops *ops = ring->ops;
+ struct b43legacy_dmadesc_generic *desc;
+ struct b43legacy_dmadesc_meta *meta;
+ struct b43legacy_rxhdr_fw3 *rxhdr;
+ struct sk_buff *skb;
+ u16 len;
+ int err;
+ dma_addr_t dmaaddr;
+
+ desc = ops->idx2desc(ring, *slot, &meta);
+
+ sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
+ skb = meta->skb;
+
+ if (ring->index == 3) {
+ /* We received an xmit status. */
+ struct b43legacy_hwtxstatus *hw =
+ (struct b43legacy_hwtxstatus *)skb->data;
+ int i = 0;
+
+ while (hw->cookie == 0) {
+ if (i > 100)
+ break;
+ i++;
+ udelay(2);
+ barrier();
+ }
+ b43legacy_handle_hwtxstatus(ring->dev, hw);
+ /* recycle the descriptor buffer. */
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
+ ring->rx_buffersize);
+
+ return;
+ }
+ rxhdr = (struct b43legacy_rxhdr_fw3 *)skb->data;
+ len = le16_to_cpu(rxhdr->frame_len);
+ if (len == 0) {
+ int i = 0;
+
+ do {
+ udelay(2);
+ barrier();
+ len = le16_to_cpu(rxhdr->frame_len);
+ } while (len == 0 && i++ < 5);
+ if (unlikely(len == 0)) {
+ /* recycle the descriptor buffer. */
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
+ ring->rx_buffersize);
+ goto drop;
+ }
+ }
+ if (unlikely(len > ring->rx_buffersize)) {
+ /* The data did not fit into one descriptor buffer
+ * and is split over multiple buffers.
+ * This should never happen, as we try to allocate buffers
+ * big enough. So simply ignore this packet.
+ */
+ int cnt = 0;
+ s32 tmp = len;
+
+ while (1) {
+ desc = ops->idx2desc(ring, *slot, &meta);
+ /* recycle the descriptor buffer. */
+ sync_descbuffer_for_device(ring, meta->dmaaddr,
+ ring->rx_buffersize);
+ *slot = next_slot(ring, *slot);
+ cnt++;
+ tmp -= ring->rx_buffersize;
+ if (tmp <= 0)
+ break;
+ }
+ b43legacyerr(ring->dev->wl, "DMA RX buffer too small "
+ "(len: %u, buffer: %u, nr-dropped: %d)\n",
+ len, ring->rx_buffersize, cnt);
+ goto drop;
+ }
+
+ dmaaddr = meta->dmaaddr;
+ err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
+ if (unlikely(err)) {
+ b43legacydbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer()"
+ " failed\n");
+ sync_descbuffer_for_device(ring, dmaaddr,
+ ring->rx_buffersize);
+ goto drop;
+ }
+
+ unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
+ skb_put(skb, len + ring->frameoffset);
+ skb_pull(skb, ring->frameoffset);
+
+ b43legacy_rx(ring->dev, skb, rxhdr);
+drop:
+ return;
+}
+
+void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
+{
+ const struct b43legacy_dma_ops *ops = ring->ops;
+ int slot;
+ int current_slot;
+ int used_slots = 0;
+
+ B43legacy_WARN_ON(ring->tx);
+ current_slot = ops->get_current_rxslot(ring);
+ B43legacy_WARN_ON(!(current_slot >= 0 && current_slot <
+ ring->nr_slots));
+
+ slot = ring->current_slot;
+ for (; slot != current_slot; slot = next_slot(ring, slot)) {
+ dma_rx(ring, &slot);
+ update_max_used_slots(ring, ++used_slots);
+ }
+ ops->set_current_rxslot(ring, slot);
+ ring->current_slot = slot;
+}
+
+static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ring->lock, flags);
+ B43legacy_WARN_ON(!ring->tx);
+ ring->ops->tx_suspend(ring);
+ spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ring->lock, flags);
+ B43legacy_WARN_ON(!ring->tx);
+ ring->ops->tx_resume(ring);
+ spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev)
+{
+ b43legacy_power_saving_ctl_bits(dev, -1, 1);
+ b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring0);
+ b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring1);
+ b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring2);
+ b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring3);
+ b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring4);
+ b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring5);
+}
+
+void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev)
+{
+ b43legacy_dma_tx_resume_ring(dev->dma.tx_ring5);
+ b43legacy_dma_tx_resume_ring(dev->dma.tx_ring4);
+ b43legacy_dma_tx_resume_ring(dev->dma.tx_ring3);
+ b43legacy_dma_tx_resume_ring(dev->dma.tx_ring2);
+ b43legacy_dma_tx_resume_ring(dev->dma.tx_ring1);
+ b43legacy_dma_tx_resume_ring(dev->dma.tx_ring0);
+ b43legacy_power_saving_ctl_bits(dev, -1, -1);
+}
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h
new file mode 100644
index 00000000000..26f6ab08de7
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -0,0 +1,367 @@
+#ifndef B43legacy_DMA_H_
+#define B43legacy_DMA_H_
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/linkage.h>
+#include <asm/atomic.h>
+
+#include "b43legacy.h"
+
+
+/* DMA-Interrupt reasons. */
+#define B43legacy_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \
+ | (1 << 14) | (1 << 15))
+#define B43legacy_DMAIRQ_NONFATALMASK (1 << 13)
+#define B43legacy_DMAIRQ_RX_DONE (1 << 16)
+
+
+/*** 32-bit DMA Engine. ***/
+
+/* 32-bit DMA controller registers. */
+#define B43legacy_DMA32_TXCTL 0x00
+#define B43legacy_DMA32_TXENABLE 0x00000001
+#define B43legacy_DMA32_TXSUSPEND 0x00000002
+#define B43legacy_DMA32_TXLOOPBACK 0x00000004
+#define B43legacy_DMA32_TXFLUSH 0x00000010
+#define B43legacy_DMA32_TXADDREXT_MASK 0x00030000
+#define B43legacy_DMA32_TXADDREXT_SHIFT 16
+#define B43legacy_DMA32_TXRING 0x04
+#define B43legacy_DMA32_TXINDEX 0x08
+#define B43legacy_DMA32_TXSTATUS 0x0C
+#define B43legacy_DMA32_TXDPTR 0x00000FFF
+#define B43legacy_DMA32_TXSTATE 0x0000F000
+#define B43legacy_DMA32_TXSTAT_DISABLED 0x00000000
+#define B43legacy_DMA32_TXSTAT_ACTIVE 0x00001000
+#define B43legacy_DMA32_TXSTAT_IDLEWAIT 0x00002000
+#define B43legacy_DMA32_TXSTAT_STOPPED 0x00003000
+#define B43legacy_DMA32_TXSTAT_SUSP 0x00004000
+#define B43legacy_DMA32_TXERROR 0x000F0000
+#define B43legacy_DMA32_TXERR_NOERR 0x00000000
+#define B43legacy_DMA32_TXERR_PROT 0x00010000
+#define B43legacy_DMA32_TXERR_UNDERRUN 0x00020000
+#define B43legacy_DMA32_TXERR_BUFREAD 0x00030000
+#define B43legacy_DMA32_TXERR_DESCREAD 0x00040000
+#define B43legacy_DMA32_TXACTIVE 0xFFF00000
+#define B43legacy_DMA32_RXCTL 0x10
+#define B43legacy_DMA32_RXENABLE 0x00000001
+#define B43legacy_DMA32_RXFROFF_MASK 0x000000FE
+#define B43legacy_DMA32_RXFROFF_SHIFT 1
+#define B43legacy_DMA32_RXDIRECTFIFO 0x00000100
+#define B43legacy_DMA32_RXADDREXT_MASK 0x00030000
+#define B43legacy_DMA32_RXADDREXT_SHIFT 16
+#define B43legacy_DMA32_RXRING 0x14
+#define B43legacy_DMA32_RXINDEX 0x18
+#define B43legacy_DMA32_RXSTATUS 0x1C
+#define B43legacy_DMA32_RXDPTR 0x00000FFF
+#define B43legacy_DMA32_RXSTATE 0x0000F000
+#define B43legacy_DMA32_RXSTAT_DISABLED 0x00000000
+#define B43legacy_DMA32_RXSTAT_ACTIVE 0x00001000
+#define B43legacy_DMA32_RXSTAT_IDLEWAIT 0x00002000
+#define B43legacy_DMA32_RXSTAT_STOPPED 0x00003000
+#define B43legacy_DMA32_RXERROR 0x000F0000
+#define B43legacy_DMA32_RXERR_NOERR 0x00000000
+#define B43legacy_DMA32_RXERR_PROT 0x00010000
+#define B43legacy_DMA32_RXERR_OVERFLOW 0x00020000
+#define B43legacy_DMA32_RXERR_BUFWRITE 0x00030000
+#define B43legacy_DMA32_RXERR_DESCREAD 0x00040000
+#define B43legacy_DMA32_RXACTIVE 0xFFF00000
+
+/* 32-bit DMA descriptor. */
+struct b43legacy_dmadesc32 {
+ __le32 control;
+ __le32 address;
+} __attribute__((__packed__));
+#define B43legacy_DMA32_DCTL_BYTECNT 0x00001FFF
+#define B43legacy_DMA32_DCTL_ADDREXT_MASK 0x00030000
+#define B43legacy_DMA32_DCTL_ADDREXT_SHIFT 16
+#define B43legacy_DMA32_DCTL_DTABLEEND 0x10000000
+#define B43legacy_DMA32_DCTL_IRQ 0x20000000
+#define B43legacy_DMA32_DCTL_FRAMEEND 0x40000000
+#define B43legacy_DMA32_DCTL_FRAMESTART 0x80000000
+
+
+
+/*** 64-bit DMA Engine. ***/
+
+/* 64-bit DMA controller registers. */
+#define B43legacy_DMA64_TXCTL 0x00
+#define B43legacy_DMA64_TXENABLE 0x00000001
+#define B43legacy_DMA64_TXSUSPEND 0x00000002
+#define B43legacy_DMA64_TXLOOPBACK 0x00000004
+#define B43legacy_DMA64_TXFLUSH 0x00000010
+#define B43legacy_DMA64_TXADDREXT_MASK 0x00030000
+#define B43legacy_DMA64_TXADDREXT_SHIFT 16
+#define B43legacy_DMA64_TXINDEX 0x04
+#define B43legacy_DMA64_TXRINGLO 0x08
+#define B43legacy_DMA64_TXRINGHI 0x0C
+#define B43legacy_DMA64_TXSTATUS 0x10
+#define B43legacy_DMA64_TXSTATDPTR 0x00001FFF
+#define B43legacy_DMA64_TXSTAT 0xF0000000
+#define B43legacy_DMA64_TXSTAT_DISABLED 0x00000000
+#define B43legacy_DMA64_TXSTAT_ACTIVE 0x10000000
+#define B43legacy_DMA64_TXSTAT_IDLEWAIT 0x20000000
+#define B43legacy_DMA64_TXSTAT_STOPPED 0x30000000
+#define B43legacy_DMA64_TXSTAT_SUSP 0x40000000
+#define B43legacy_DMA64_TXERROR 0x14
+#define B43legacy_DMA64_TXERRDPTR 0x0001FFFF
+#define B43legacy_DMA64_TXERR 0xF0000000
+#define B43legacy_DMA64_TXERR_NOERR 0x00000000
+#define B43legacy_DMA64_TXERR_PROT 0x10000000
+#define B43legacy_DMA64_TXERR_UNDERRUN 0x20000000
+#define B43legacy_DMA64_TXERR_TRANSFER 0x30000000
+#define B43legacy_DMA64_TXERR_DESCREAD 0x40000000
+#define B43legacy_DMA64_TXERR_CORE 0x50000000
+#define B43legacy_DMA64_RXCTL 0x20
+#define B43legacy_DMA64_RXENABLE 0x00000001
+#define B43legacy_DMA64_RXFROFF_MASK 0x000000FE
+#define B43legacy_DMA64_RXFROFF_SHIFT 1
+#define B43legacy_DMA64_RXDIRECTFIFO 0x00000100
+#define B43legacy_DMA64_RXADDREXT_MASK 0x00030000
+#define B43legacy_DMA64_RXADDREXT_SHIFT 16
+#define B43legacy_DMA64_RXINDEX 0x24
+#define B43legacy_DMA64_RXRINGLO 0x28
+#define B43legacy_DMA64_RXRINGHI 0x2C
+#define B43legacy_DMA64_RXSTATUS 0x30
+#define B43legacy_DMA64_RXSTATDPTR 0x00001FFF
+#define B43legacy_DMA64_RXSTAT 0xF0000000
+#define B43legacy_DMA64_RXSTAT_DISABLED 0x00000000
+#define B43legacy_DMA64_RXSTAT_ACTIVE 0x10000000
+#define B43legacy_DMA64_RXSTAT_IDLEWAIT 0x20000000
+#define B43legacy_DMA64_RXSTAT_STOPPED 0x30000000
+#define B43legacy_DMA64_RXSTAT_SUSP 0x40000000
+#define B43legacy_DMA64_RXERROR 0x34
+#define B43legacy_DMA64_RXERRDPTR 0x0001FFFF
+#define B43legacy_DMA64_RXERR 0xF0000000
+#define B43legacy_DMA64_RXERR_NOERR 0x00000000
+#define B43legacy_DMA64_RXERR_PROT 0x10000000
+#define B43legacy_DMA64_RXERR_UNDERRUN 0x20000000
+#define B43legacy_DMA64_RXERR_TRANSFER 0x30000000
+#define B43legacy_DMA64_RXERR_DESCREAD 0x40000000
+#define B43legacy_DMA64_RXERR_CORE 0x50000000
+
+/* 64-bit DMA descriptor. */
+struct b43legacy_dmadesc64 {
+ __le32 control0;
+ __le32 control1;
+ __le32 address_low;
+ __le32 address_high;
+} __attribute__((__packed__));
+#define B43legacy_DMA64_DCTL0_DTABLEEND 0x10000000
+#define B43legacy_DMA64_DCTL0_IRQ 0x20000000
+#define B43legacy_DMA64_DCTL0_FRAMEEND 0x40000000
+#define B43legacy_DMA64_DCTL0_FRAMESTART 0x80000000
+#define B43legacy_DMA64_DCTL1_BYTECNT 0x00001FFF
+#define B43legacy_DMA64_DCTL1_ADDREXT_MASK 0x00030000
+#define B43legacy_DMA64_DCTL1_ADDREXT_SHIFT 16
+
+
+
+struct b43legacy_dmadesc_generic {
+ union {
+ struct b43legacy_dmadesc32 dma32;
+ struct b43legacy_dmadesc64 dma64;
+ } __attribute__((__packed__));
+} __attribute__((__packed__));
+
+
+/* Misc DMA constants */
+#define B43legacy_DMA_RINGMEMSIZE PAGE_SIZE
+#define B43legacy_DMA0_RX_FRAMEOFFSET 30
+#define B43legacy_DMA3_RX_FRAMEOFFSET 0
+
+
+/* DMA engine tuning knobs */
+#define B43legacy_TXRING_SLOTS 128
+#define B43legacy_RXRING_SLOTS 64
+#define B43legacy_DMA0_RX_BUFFERSIZE (2304 + 100)
+#define B43legacy_DMA3_RX_BUFFERSIZE 16
+
+
+
+#ifdef CONFIG_B43LEGACY_DMA
+
+
+struct sk_buff;
+struct b43legacy_private;
+struct b43legacy_txstatus;
+
+
+struct b43legacy_dmadesc_meta {
+ /* The kernel DMA-able buffer. */
+ struct sk_buff *skb;
+ /* DMA base bus-address of the descriptor buffer. */
+ dma_addr_t dmaaddr;
+ /* ieee80211 TX status. Only used once per 802.11 frag. */
+ bool is_last_fragment;
+ struct ieee80211_tx_status txstat;
+};
+
+struct b43legacy_dmaring;
+
+/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */
+struct b43legacy_dma_ops {
+ struct b43legacy_dmadesc_generic * (*idx2desc)
+ (struct b43legacy_dmaring *ring,
+ int slot,
+ struct b43legacy_dmadesc_meta
+ **meta);
+ void (*fill_descriptor)(struct b43legacy_dmaring *ring,
+ struct b43legacy_dmadesc_generic *desc,
+ dma_addr_t dmaaddr, u16 bufsize,
+ int start, int end, int irq);
+ void (*poke_tx)(struct b43legacy_dmaring *ring, int slot);
+ void (*tx_suspend)(struct b43legacy_dmaring *ring);
+ void (*tx_resume)(struct b43legacy_dmaring *ring);
+ int (*get_current_rxslot)(struct b43legacy_dmaring *ring);
+ void (*set_current_rxslot)(struct b43legacy_dmaring *ring, int slot);
+};
+
+struct b43legacy_dmaring {
+ /* Lowlevel DMA ops. */
+ const struct b43legacy_dma_ops *ops;
+ /* Kernel virtual base address of the ring memory. */
+ void *descbase;
+ /* Meta data about all descriptors. */
+ struct b43legacy_dmadesc_meta *meta;
+ /* Cache of TX headers for each slot.
+ * This is to avoid an allocation on each TX.
+ * This is NULL for an RX ring.
+ */
+ u8 *txhdr_cache;
+ /* (Unadjusted) DMA base bus-address of the ring memory. */
+ dma_addr_t dmabase;
+ /* Number of descriptor slots in the ring. */
+ int nr_slots;
+ /* Number of used descriptor slots. */
+ int used_slots;
+ /* Currently used slot in the ring. */
+ int current_slot;
+ /* Total number of packets sent. Statistics only. */
+ unsigned int nr_tx_packets;
+ /* Frameoffset in octets. */
+ u32 frameoffset;
+ /* Descriptor buffer size. */
+ u16 rx_buffersize;
+ /* The MMIO base register of the DMA controller. */
+ u16 mmio_base;
+ /* DMA controller index number (0-5). */
+ int index;
+ /* Boolean. Is this a TX ring? */
+ bool tx;
+ /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
+ bool dma64;
+ /* Boolean. Is this ring stopped at ieee80211 level? */
+ bool stopped;
+ /* Lock, only used for TX. */
+ spinlock_t lock;
+ struct b43legacy_wldev *dev;
+#ifdef CONFIG_B43LEGACY_DEBUG
+ /* Maximum number of used slots. */
+ int max_used_slots;
+ /* Last time we injected a ring overflow. */
+ unsigned long last_injected_overflow;
+#endif /* CONFIG_B43LEGACY_DEBUG*/
+};
+
+
+static inline
+u32 b43legacy_dma_read(struct b43legacy_dmaring *ring,
+ u16 offset)
+{
+ return b43legacy_read32(ring->dev, ring->mmio_base + offset);
+}
+
+static inline
+void b43legacy_dma_write(struct b43legacy_dmaring *ring,
+ u16 offset, u32 value)
+{
+ b43legacy_write32(ring->dev, ring->mmio_base + offset, value);
+}
+
+
+int b43legacy_dma_init(struct b43legacy_wldev *dev);
+void b43legacy_dma_free(struct b43legacy_wldev *dev);
+
+int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
+ u16 dmacontroller_mmio_base,
+ int dma64);
+int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
+ u16 dmacontroller_mmio_base,
+ int dma64);
+
+u16 b43legacy_dmacontroller_base(int dma64bit, int dmacontroller_idx);
+
+void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev);
+void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev);
+
+void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats);
+
+int b43legacy_dma_tx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl);
+void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status);
+
+void b43legacy_dma_rx(struct b43legacy_dmaring *ring);
+
+#else /* CONFIG_B43LEGACY_DMA */
+
+
+static inline
+int b43legacy_dma_init(struct b43legacy_wldev *dev)
+{
+ return 0;
+}
+static inline
+void b43legacy_dma_free(struct b43legacy_wldev *dev)
+{
+}
+static inline
+int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
+ u16 dmacontroller_mmio_base,
+ int dma64)
+{
+ return 0;
+}
+static inline
+int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
+ u16 dmacontroller_mmio_base,
+ int dma64)
+{
+ return 0;
+}
+static inline
+void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+}
+static inline
+int b43legacy_dma_tx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ return 0;
+}
+static inline
+void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+{
+}
+static inline
+void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
+{
+}
+static inline
+void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev)
+{
+}
+static inline
+void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev)
+{
+}
+
+#endif /* CONFIG_B43LEGACY_DMA */
+#endif /* B43legacy_DMA_H_ */
diff --git a/drivers/net/wireless/b43legacy/ilt.c b/drivers/net/wireless/b43legacy/ilt.c
new file mode 100644
index 00000000000..247fc780ffd
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/ilt.c
@@ -0,0 +1,336 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mbuesch@freenet.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43legacy.h"
+#include "ilt.h"
+#include "phy.h"
+
+
+/**** Initial Internal Lookup Tables ****/
+
+const u32 b43legacy_ilt_rotor[B43legacy_ILT_ROTOR_SIZE] = {
+ 0xFEB93FFD, 0xFEC63FFD, /* 0 */
+ 0xFED23FFD, 0xFEDF3FFD,
+ 0xFEEC3FFE, 0xFEF83FFE,
+ 0xFF053FFE, 0xFF113FFE,
+ 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */
+ 0xFF373FFF, 0xFF443FFF,
+ 0xFF503FFF, 0xFF5D3FFF,
+ 0xFF693FFF, 0xFF763FFF,
+ 0xFF824000, 0xFF8F4000, /* 16 */
+ 0xFF9B4000, 0xFFA84000,
+ 0xFFB54000, 0xFFC14000,
+ 0xFFCE4000, 0xFFDA4000,
+ 0xFFE74000, 0xFFF34000, /* 24 */
+ 0x00004000, 0x000D4000,
+ 0x00194000, 0x00264000,
+ 0x00324000, 0x003F4000,
+ 0x004B4000, 0x00584000, /* 32 */
+ 0x00654000, 0x00714000,
+ 0x007E4000, 0x008A3FFF,
+ 0x00973FFF, 0x00A33FFF,
+ 0x00B03FFF, 0x00BC3FFF, /* 40 */
+ 0x00C93FFF, 0x00D63FFF,
+ 0x00E23FFE, 0x00EF3FFE,
+ 0x00FB3FFE, 0x01083FFE,
+ 0x01143FFE, 0x01213FFD, /* 48 */
+ 0x012E3FFD, 0x013A3FFD,
+ 0x01473FFD,
+};
+
+const u32 b43legacy_ilt_retard[B43legacy_ILT_RETARD_SIZE] = {
+ 0xDB93CB87, 0xD666CF64, /* 0 */
+ 0xD1FDD358, 0xCDA6D826,
+ 0xCA38DD9F, 0xC729E2B4,
+ 0xC469E88E, 0xC26AEE2B,
+ 0xC0DEF46C, 0xC073FA62, /* 8 */
+ 0xC01D00D5, 0xC0760743,
+ 0xC1560D1E, 0xC2E51369,
+ 0xC4ED18FF, 0xC7AC1ED7,
+ 0xCB2823B2, 0xCEFA28D9, /* 16 */
+ 0xD2F62D3F, 0xD7BB3197,
+ 0xDCE53568, 0xE1FE3875,
+ 0xE7D13B35, 0xED663D35,
+ 0xF39B3EC4, 0xF98E3FA7, /* 24 */
+ 0x00004000, 0x06723FA7,
+ 0x0C653EC4, 0x129A3D35,
+ 0x182F3B35, 0x1E023875,
+ 0x231B3568, 0x28453197, /* 32 */
+ 0x2D0A2D3F, 0x310628D9,
+ 0x34D823B2, 0x38541ED7,
+ 0x3B1318FF, 0x3D1B1369,
+ 0x3EAA0D1E, 0x3F8A0743, /* 40 */
+ 0x3FE300D5, 0x3F8DFA62,
+ 0x3F22F46C, 0x3D96EE2B,
+ 0x3B97E88E, 0x38D7E2B4,
+ 0x35C8DD9F, 0x325AD826, /* 48 */
+ 0x2E03D358, 0x299ACF64,
+ 0x246DCB87,
+};
+
+const u16 b43legacy_ilt_finefreqa[B43legacy_ILT_FINEFREQA_SIZE] = {
+ 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */
+ 0x0202, 0x0282, 0x0302, 0x0382,
+ 0x0402, 0x0482, 0x0502, 0x0582,
+ 0x05E2, 0x0662, 0x06E2, 0x0762,
+ 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */
+ 0x09C2, 0x0A22, 0x0AA2, 0x0B02,
+ 0x0B82, 0x0BE2, 0x0C62, 0x0CC2,
+ 0x0D42, 0x0DA2, 0x0E02, 0x0E62,
+ 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */
+ 0x1062, 0x10C2, 0x1122, 0x1182,
+ 0x11E2, 0x1242, 0x12A2, 0x12E2,
+ 0x1342, 0x13A2, 0x1402, 0x1442,
+ 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */
+ 0x15E2, 0x1622, 0x1662, 0x16C1,
+ 0x1701, 0x1741, 0x1781, 0x17E1,
+ 0x1821, 0x1861, 0x18A1, 0x18E1,
+ 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */
+ 0x1A21, 0x1A61, 0x1AA1, 0x1AC1,
+ 0x1B01, 0x1B41, 0x1B81, 0x1BA1,
+ 0x1BE1, 0x1C21, 0x1C41, 0x1C81,
+ 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */
+ 0x1D61, 0x1DA1, 0x1DC1, 0x1E01,
+ 0x1E21, 0x1E61, 0x1E81, 0x1EA1,
+ 0x1EE1, 0x1F01, 0x1F21, 0x1F41,
+ 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */
+ 0x2001, 0x2041, 0x2061, 0x2081,
+ 0x20A1, 0x20C1, 0x20E1, 0x2101,
+ 0x2121, 0x2141, 0x2161, 0x2181,
+ 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */
+ 0x2221, 0x2241, 0x2261, 0x2281,
+ 0x22A1, 0x22C1, 0x22C1, 0x22E1,
+ 0x2301, 0x2321, 0x2341, 0x2361,
+ 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */
+ 0x23E1, 0x23E1, 0x2401, 0x2421,
+ 0x2441, 0x2441, 0x2461, 0x2481,
+ 0x2481, 0x24A1, 0x24C1, 0x24C1,
+ 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */
+ 0x2541, 0x2541, 0x2561, 0x2561,
+ 0x2581, 0x25A1, 0x25A1, 0x25C1,
+ 0x25C1, 0x25E1, 0x2601, 0x2601,
+ 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */
+ 0x2661, 0x2661, 0x2681, 0x2681,
+ 0x26A1, 0x26A1, 0x26C1, 0x26C1,
+ 0x26E1, 0x26E1, 0x2701, 0x2701,
+ 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */
+ 0x2760, 0x2760, 0x2780, 0x2780,
+ 0x2780, 0x27A0, 0x27A0, 0x27C0,
+ 0x27C0, 0x27E0, 0x27E0, 0x27E0,
+ 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */
+ 0x2820, 0x2840, 0x2840, 0x2840,
+ 0x2860, 0x2860, 0x2880, 0x2880,
+ 0x2880, 0x28A0, 0x28A0, 0x28A0,
+ 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */
+ 0x28E0, 0x28E0, 0x2900, 0x2900,
+ 0x2900, 0x2920, 0x2920, 0x2920,
+ 0x2940, 0x2940, 0x2940, 0x2960,
+ 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */
+ 0x2980, 0x2980, 0x29A0, 0x29A0,
+ 0x29A0, 0x29A0, 0x29C0, 0x29C0,
+ 0x29C0, 0x29E0, 0x29E0, 0x29E0,
+ 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */
+ 0x2A00, 0x2A20, 0x2A20, 0x2A20,
+ 0x2A20, 0x2A40, 0x2A40, 0x2A40,
+ 0x2A40, 0x2A60, 0x2A60, 0x2A60,
+};
+
+const u16 b43legacy_ilt_finefreqg[B43legacy_ILT_FINEFREQG_SIZE] = {
+ 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */
+ 0x05A9, 0x0669, 0x0709, 0x0789,
+ 0x0829, 0x08A9, 0x0929, 0x0989,
+ 0x0A09, 0x0A69, 0x0AC9, 0x0B29,
+ 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */
+ 0x0D09, 0x0D69, 0x0DA9, 0x0E09,
+ 0x0E69, 0x0EA9, 0x0F09, 0x0F49,
+ 0x0FA9, 0x0FE9, 0x1029, 0x1089,
+ 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */
+ 0x11E9, 0x1229, 0x1289, 0x12C9,
+ 0x1309, 0x1349, 0x1389, 0x13C9,
+ 0x1409, 0x1449, 0x14A9, 0x14E9,
+ 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */
+ 0x1629, 0x1669, 0x16A9, 0x16E8,
+ 0x1728, 0x1768, 0x17A8, 0x17E8,
+ 0x1828, 0x1868, 0x18A8, 0x18E8,
+ 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */
+ 0x1A28, 0x1A68, 0x1AA8, 0x1AE8,
+ 0x1B28, 0x1B68, 0x1BA8, 0x1BE8,
+ 0x1C28, 0x1C68, 0x1CA8, 0x1CE8,
+ 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */
+ 0x1E48, 0x1E88, 0x1EC8, 0x1F08,
+ 0x1F48, 0x1F88, 0x1FE8, 0x2028,
+ 0x2068, 0x20A8, 0x2108, 0x2148,
+ 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */
+ 0x22C8, 0x2308, 0x2348, 0x23A8,
+ 0x23E8, 0x2448, 0x24A8, 0x24E8,
+ 0x2548, 0x25A8, 0x2608, 0x2668,
+ 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */
+ 0x2847, 0x28C7, 0x2947, 0x29A7,
+ 0x2A27, 0x2AC7, 0x2B47, 0x2BE7,
+ 0x2CA7, 0x2D67, 0x2E47, 0x2F67,
+ 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */
+ 0x3806, 0x38A6, 0x3946, 0x39E6,
+ 0x3A66, 0x3AE6, 0x3B66, 0x3BC6,
+ 0x3C45, 0x3CA5, 0x3D05, 0x3D85,
+ 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */
+ 0x3F45, 0x3FA5, 0x4005, 0x4045,
+ 0x40A5, 0x40E5, 0x4145, 0x4185,
+ 0x41E5, 0x4225, 0x4265, 0x42C5,
+ 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */
+ 0x4424, 0x4464, 0x44C4, 0x4504,
+ 0x4544, 0x4584, 0x45C4, 0x4604,
+ 0x4644, 0x46A4, 0x46E4, 0x4724,
+ 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */
+ 0x4864, 0x48A4, 0x48E4, 0x4924,
+ 0x4964, 0x49A4, 0x49E4, 0x4A24,
+ 0x4A64, 0x4AA4, 0x4AE4, 0x4B23,
+ 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */
+ 0x4C63, 0x4CA3, 0x4CE3, 0x4D23,
+ 0x4D63, 0x4DA3, 0x4DE3, 0x4E23,
+ 0x4E63, 0x4EA3, 0x4EE3, 0x4F23,
+ 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */
+ 0x5083, 0x50C3, 0x5103, 0x5143,
+ 0x5183, 0x51E2, 0x5222, 0x5262,
+ 0x52A2, 0x52E2, 0x5342, 0x5382,
+ 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */
+ 0x5502, 0x5542, 0x55A2, 0x55E2,
+ 0x5642, 0x5682, 0x56E2, 0x5722,
+ 0x5782, 0x57E1, 0x5841, 0x58A1,
+ 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */
+ 0x5AA1, 0x5B01, 0x5B81, 0x5BE1,
+ 0x5C61, 0x5D01, 0x5D80, 0x5E20,
+ 0x5EE0, 0x5FA0, 0x6080, 0x61C0,
+};
+
+const u16 b43legacy_ilt_noisea2[B43legacy_ILT_NOISEA2_SIZE] = {
+ 0x0001, 0x0001, 0x0001, 0xFFFE,
+ 0xFFFE, 0x3FFF, 0x1000, 0x0393,
+};
+
+const u16 b43legacy_ilt_noisea3[B43legacy_ILT_NOISEA3_SIZE] = {
+ 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+ 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+};
+
+const u16 b43legacy_ilt_noiseg1[B43legacy_ILT_NOISEG1_SIZE] = {
+ 0x013C, 0x01F5, 0x031A, 0x0631,
+ 0x0001, 0x0001, 0x0001, 0x0001,
+};
+
+const u16 b43legacy_ilt_noiseg2[B43legacy_ILT_NOISEG2_SIZE] = {
+ 0x5484, 0x3C40, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+const u16 b43legacy_ilt_noisescaleg1[B43legacy_ILT_NOISESCALEG_SIZE] = {
+ 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */
+ 0x2F2D, 0x2A2A, 0x2527, 0x1F21,
+ 0x1A1D, 0x1719, 0x1616, 0x1414,
+ 0x1414, 0x1400, 0x1414, 0x1614,
+ 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */
+ 0x2A27, 0x2F2A, 0x332D, 0x3B35,
+ 0x5140, 0x6C62, 0x0077,
+};
+
+const u16 b43legacy_ilt_noisescaleg2[B43legacy_ILT_NOISESCALEG_SIZE] = {
+ 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */
+ 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
+ 0x969B, 0x9195, 0x8F8F, 0x8A8A,
+ 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
+ 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */
+ 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7,
+ 0xCBC0, 0xD8D4, 0x00DD,
+};
+
+const u16 b43legacy_ilt_noisescaleg3[B43legacy_ILT_NOISESCALEG_SIZE] = {
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA400, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */
+ 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+ 0xA4A4, 0xA4A4, 0x00A4,
+};
+
+const u16 b43legacy_ilt_sigmasqr1[B43legacy_ILT_SIGMASQR_SIZE] = {
+ 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */
+ 0x0067, 0x0063, 0x005E, 0x0059,
+ 0x0054, 0x0050, 0x004B, 0x0046,
+ 0x0042, 0x003D, 0x003D, 0x003D,
+ 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */
+ 0x003D, 0x003D, 0x003D, 0x003D,
+ 0x003D, 0x003D, 0x0000, 0x003D,
+ 0x003D, 0x003D, 0x003D, 0x003D,
+ 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */
+ 0x003D, 0x003D, 0x003D, 0x003D,
+ 0x0042, 0x0046, 0x004B, 0x0050,
+ 0x0054, 0x0059, 0x005E, 0x0063,
+ 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */
+ 0x007A,
+};
+
+const u16 b43legacy_ilt_sigmasqr2[B43legacy_ILT_SIGMASQR_SIZE] = {
+ 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */
+ 0x00D6, 0x00D4, 0x00D2, 0x00CF,
+ 0x00CD, 0x00CA, 0x00C7, 0x00C4,
+ 0x00C1, 0x00BE, 0x00BE, 0x00BE,
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE,
+ 0x00BE, 0x00BE, 0x0000, 0x00BE,
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE,
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */
+ 0x00BE, 0x00BE, 0x00BE, 0x00BE,
+ 0x00C1, 0x00C4, 0x00C7, 0x00CA,
+ 0x00CD, 0x00CF, 0x00D2, 0x00D4,
+ 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */
+ 0x00DE,
+};
+
+/**** Helper functions to access the device Internal Lookup Tables ****/
+
+void b43legacy_ilt_write(struct b43legacy_wldev *dev, u16 offset, u16 val)
+{
+ b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset);
+ mmiowb();
+ b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA1, val);
+}
+
+void b43legacy_ilt_write32(struct b43legacy_wldev *dev, u16 offset, u32 val)
+{
+ b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset);
+ mmiowb();
+ b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA2,
+ (val & 0xFFFF0000) >> 16);
+ b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA1,
+ val & 0x0000FFFF);
+}
+
+u16 b43legacy_ilt_read(struct b43legacy_wldev *dev, u16 offset)
+{
+ b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset);
+ return b43legacy_phy_read(dev, B43legacy_PHY_ILT_G_DATA1);
+}
diff --git a/drivers/net/wireless/b43legacy/ilt.h b/drivers/net/wireless/b43legacy/ilt.h
new file mode 100644
index 00000000000..48bcf37eccb
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/ilt.h
@@ -0,0 +1,34 @@
+#ifndef B43legacy_ILT_H_
+#define B43legacy_ILT_H_
+
+#define B43legacy_ILT_ROTOR_SIZE 53
+extern const u32 b43legacy_ilt_rotor[B43legacy_ILT_ROTOR_SIZE];
+#define B43legacy_ILT_RETARD_SIZE 53
+extern const u32 b43legacy_ilt_retard[B43legacy_ILT_RETARD_SIZE];
+#define B43legacy_ILT_FINEFREQA_SIZE 256
+extern const u16 b43legacy_ilt_finefreqa[B43legacy_ILT_FINEFREQA_SIZE];
+#define B43legacy_ILT_FINEFREQG_SIZE 256
+extern const u16 b43legacy_ilt_finefreqg[B43legacy_ILT_FINEFREQG_SIZE];
+#define B43legacy_ILT_NOISEA2_SIZE 8
+extern const u16 b43legacy_ilt_noisea2[B43legacy_ILT_NOISEA2_SIZE];
+#define B43legacy_ILT_NOISEA3_SIZE 8
+extern const u16 b43legacy_ilt_noisea3[B43legacy_ILT_NOISEA3_SIZE];
+#define B43legacy_ILT_NOISEG1_SIZE 8
+extern const u16 b43legacy_ilt_noiseg1[B43legacy_ILT_NOISEG1_SIZE];
+#define B43legacy_ILT_NOISEG2_SIZE 8
+extern const u16 b43legacy_ilt_noiseg2[B43legacy_ILT_NOISEG2_SIZE];
+#define B43legacy_ILT_NOISESCALEG_SIZE 27
+extern const u16 b43legacy_ilt_noisescaleg1[B43legacy_ILT_NOISESCALEG_SIZE];
+extern const u16 b43legacy_ilt_noisescaleg2[B43legacy_ILT_NOISESCALEG_SIZE];
+extern const u16 b43legacy_ilt_noisescaleg3[B43legacy_ILT_NOISESCALEG_SIZE];
+#define B43legacy_ILT_SIGMASQR_SIZE 53
+extern const u16 b43legacy_ilt_sigmasqr1[B43legacy_ILT_SIGMASQR_SIZE];
+extern const u16 b43legacy_ilt_sigmasqr2[B43legacy_ILT_SIGMASQR_SIZE];
+
+
+void b43legacy_ilt_write(struct b43legacy_wldev *dev, u16 offset, u16 val);
+void b43legacy_ilt_write32(struct b43legacy_wldev *dev, u16 offset,
+ u32 val);
+u16 b43legacy_ilt_read(struct b43legacy_wldev *dev, u16 offset);
+
+#endif /* B43legacy_ILT_H_ */
diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c
new file mode 100644
index 00000000000..a584ea81050
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/leds.c
@@ -0,0 +1,298 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mb@bu3sch.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "leds.h"
+#include "b43legacy.h"
+#include "main.h"
+
+static void b43legacy_led_changestate(struct b43legacy_led *led)
+{
+ struct b43legacy_wldev *dev = led->dev;
+ const int index = led->index;
+ u16 ledctl;
+
+ B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS));
+ B43legacy_WARN_ON(!led->blink_interval);
+ ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+ ledctl ^= (1 << index);
+ b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
+}
+
+static void b43legacy_led_blink(unsigned long d)
+{
+ struct b43legacy_led *led = (struct b43legacy_led *)d;
+ struct b43legacy_wldev *dev = led->dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->wl->leds_lock, flags);
+ if (led->blink_interval) {
+ b43legacy_led_changestate(led);
+ mod_timer(&led->blink_timer, jiffies + led->blink_interval);
+ }
+ spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
+}
+
+static void b43legacy_led_blink_start(struct b43legacy_led *led,
+ unsigned long interval)
+{
+ if (led->blink_interval)
+ return;
+ led->blink_interval = interval;
+ b43legacy_led_changestate(led);
+ led->blink_timer.expires = jiffies + interval;
+ add_timer(&led->blink_timer);
+}
+
+static void b43legacy_led_blink_stop(struct b43legacy_led *led, int sync)
+{
+ struct b43legacy_wldev *dev = led->dev;
+ const int index = led->index;
+ u16 ledctl;
+
+ if (!led->blink_interval)
+ return;
+ if (unlikely(sync))
+ del_timer_sync(&led->blink_timer);
+ else
+ del_timer(&led->blink_timer);
+ led->blink_interval = 0;
+
+ /* Make sure the LED is turned off. */
+ B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS));
+ ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+ if (led->activelow)
+ ledctl |= (1 << index);
+ else
+ ledctl &= ~(1 << index);
+ b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
+}
+
+static void b43legacy_led_init_hardcoded(struct b43legacy_wldev *dev,
+ struct b43legacy_led *led,
+ int led_index)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+
+ /* This function is called, if the behaviour (and activelow)
+ * information for a LED is missing in the SPROM.
+ * We hardcode the behaviour values for various devices here.
+ * Note that the B43legacy_LED_TEST_XXX behaviour values can
+ * be used to figure out which led is mapped to which index.
+ */
+
+ switch (led_index) {
+ case 0:
+ led->behaviour = B43legacy_LED_ACTIVITY;
+ led->activelow = 1;
+ if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
+ led->behaviour = B43legacy_LED_RADIO_ALL;
+ break;
+ case 1:
+ led->behaviour = B43legacy_LED_RADIO_B;
+ if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
+ led->behaviour = B43legacy_LED_ASSOC;
+ break;
+ case 2:
+ led->behaviour = B43legacy_LED_RADIO_A;
+ break;
+ case 3:
+ led->behaviour = B43legacy_LED_OFF;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+}
+
+int b43legacy_leds_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_led *led;
+ u8 sprom[4];
+ int i;
+
+ sprom[0] = dev->dev->bus->sprom.r1.gpio0;
+ sprom[1] = dev->dev->bus->sprom.r1.gpio1;
+ sprom[2] = dev->dev->bus->sprom.r1.gpio2;
+ sprom[3] = dev->dev->bus->sprom.r1.gpio3;
+
+ for (i = 0; i < B43legacy_NR_LEDS; i++) {
+ led = &(dev->leds[i]);
+ led->index = i;
+ led->dev = dev;
+ setup_timer(&led->blink_timer,
+ b43legacy_led_blink,
+ (unsigned long)led);
+
+ if (sprom[i] == 0xFF)
+ b43legacy_led_init_hardcoded(dev, led, i);
+ else {
+ led->behaviour = sprom[i] & B43legacy_LED_BEHAVIOUR;
+ led->activelow = !!(sprom[i] &
+ B43legacy_LED_ACTIVELOW);
+ }
+ }
+
+ return 0;
+}
+
+void b43legacy_leds_exit(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_led *led;
+ int i;
+
+ for (i = 0; i < B43legacy_NR_LEDS; i++) {
+ led = &(dev->leds[i]);
+ b43legacy_led_blink_stop(led, 1);
+ }
+ b43legacy_leds_switch_all(dev, 0);
+}
+
+void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity)
+{
+ struct b43legacy_led *led;
+ struct b43legacy_phy *phy = &dev->phy;
+ const int transferring = (jiffies - dev->stats.last_tx)
+ < B43legacy_LED_XFER_THRES;
+ int i;
+ int turn_on;
+ unsigned long interval = 0;
+ u16 ledctl;
+ unsigned long flags;
+ bool radio_enabled = (phy->radio_on && dev->radio_hw_enable);
+
+ spin_lock_irqsave(&dev->wl->leds_lock, flags);
+ ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+ for (i = 0; i < B43legacy_NR_LEDS; i++) {
+ led = &(dev->leds[i]);
+
+ turn_on = 0;
+ switch (led->behaviour) {
+ case B43legacy_LED_INACTIVE:
+ continue;
+ case B43legacy_LED_OFF:
+ break;
+ case B43legacy_LED_ON:
+ turn_on = 1;
+ break;
+ case B43legacy_LED_ACTIVITY:
+ turn_on = activity;
+ break;
+ case B43legacy_LED_RADIO_ALL:
+ turn_on = radio_enabled;
+ break;
+ case B43legacy_LED_RADIO_A:
+ break;
+ case B43legacy_LED_RADIO_B:
+ turn_on = radio_enabled;
+ break;
+ case B43legacy_LED_MODE_BG:
+ if (phy->type == B43legacy_PHYTYPE_G && radio_enabled)
+ turn_on = 1;
+ break;
+ case B43legacy_LED_TRANSFER:
+ if (transferring)
+ b43legacy_led_blink_start(led,
+ B43legacy_LEDBLINK_MEDIUM);
+ else
+ b43legacy_led_blink_stop(led, 0);
+ continue;
+ case B43legacy_LED_APTRANSFER:
+ if (b43legacy_is_mode(dev->wl,
+ IEEE80211_IF_TYPE_AP)) {
+ if (transferring) {
+ interval = B43legacy_LEDBLINK_FAST;
+ turn_on = 1;
+ }
+ } else {
+ turn_on = 1;
+ if (transferring)
+ interval = B43legacy_LEDBLINK_FAST;
+ else
+ turn_on = 0;
+ }
+ if (turn_on)
+ b43legacy_led_blink_start(led, interval);
+ else
+ b43legacy_led_blink_stop(led, 0);
+ continue;
+ case B43legacy_LED_WEIRD:
+ break;
+ case B43legacy_LED_ASSOC:
+ turn_on = 1;
+#ifdef CONFIG_B43LEGACY_DEBUG
+ case B43legacy_LED_TEST_BLINKSLOW:
+ b43legacy_led_blink_start(led, B43legacy_LEDBLINK_SLOW);
+ continue;
+ case B43legacy_LED_TEST_BLINKMEDIUM:
+ b43legacy_led_blink_start(led,
+ B43legacy_LEDBLINK_MEDIUM);
+ continue;
+ case B43legacy_LED_TEST_BLINKFAST:
+ b43legacy_led_blink_start(led, B43legacy_LEDBLINK_FAST);
+ continue;
+#endif /* CONFIG_B43LEGACY_DEBUG */
+ default:
+ B43legacy_BUG_ON(1);
+ };
+
+ if (led->activelow)
+ turn_on = !turn_on;
+ if (turn_on)
+ ledctl |= (1 << i);
+ else
+ ledctl &= ~(1 << i);
+ }
+ b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
+ spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
+}
+
+void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on)
+{
+ struct b43legacy_led *led;
+ u16 ledctl;
+ int i;
+ int bit_on;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->wl->leds_lock, flags);
+ ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+ for (i = 0; i < B43legacy_NR_LEDS; i++) {
+ led = &(dev->leds[i]);
+ if (led->behaviour == B43legacy_LED_INACTIVE)
+ continue;
+ if (on)
+ bit_on = led->activelow ? 0 : 1;
+ else
+ bit_on = led->activelow ? 1 : 0;
+ if (bit_on)
+ ledctl |= (1 << i);
+ else
+ ledctl &= ~(1 << i);
+ }
+ b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
+ spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
+}
diff --git a/drivers/net/wireless/b43legacy/leds.h b/drivers/net/wireless/b43legacy/leds.h
new file mode 100644
index 00000000000..b989f503e68
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/leds.h
@@ -0,0 +1,56 @@
+#ifndef B43legacy_LEDS_H_
+#define B43legacy_LEDS_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+
+
+struct b43legacy_led {
+ u8 behaviour;
+ bool activelow;
+ /* Index in the "leds" array in b43legacy_wldev */
+ u8 index;
+ struct b43legacy_wldev *dev;
+ struct timer_list blink_timer;
+ unsigned long blink_interval;
+};
+
+/* Delay between state changes when blinking in jiffies */
+#define B43legacy_LEDBLINK_SLOW (HZ / 1)
+#define B43legacy_LEDBLINK_MEDIUM (HZ / 4)
+#define B43legacy_LEDBLINK_FAST (HZ / 8)
+
+#define B43legacy_LED_XFER_THRES (HZ / 100)
+
+#define B43legacy_LED_BEHAVIOUR 0x7F
+#define B43legacy_LED_ACTIVELOW 0x80
+enum { /* LED behaviour values */
+ B43legacy_LED_OFF,
+ B43legacy_LED_ON,
+ B43legacy_LED_ACTIVITY,
+ B43legacy_LED_RADIO_ALL,
+ B43legacy_LED_RADIO_A,
+ B43legacy_LED_RADIO_B,
+ B43legacy_LED_MODE_BG,
+ B43legacy_LED_TRANSFER,
+ B43legacy_LED_APTRANSFER,
+ B43legacy_LED_WEIRD,
+ B43legacy_LED_ASSOC,
+ B43legacy_LED_INACTIVE,
+
+ /* Behaviour values for testing.
+ * With these values it is easier to figure out
+ * the real behaviour of leds, in case the SPROM
+ * is missing information.
+ */
+ B43legacy_LED_TEST_BLINKSLOW,
+ B43legacy_LED_TEST_BLINKMEDIUM,
+ B43legacy_LED_TEST_BLINKFAST,
+};
+
+int b43legacy_leds_init(struct b43legacy_wldev *dev);
+void b43legacy_leds_exit(struct b43legacy_wldev *dev);
+void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity);
+void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on);
+
+#endif /* B43legacy_LEDS_H_ */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
new file mode 100644
index 00000000000..3bde1e9ab42
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -0,0 +1,3859 @@
+/*
+ *
+ * Broadcom B43legacy wireless driver
+ *
+ * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
+ * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ * Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ * Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ * Some parts of the code in this file are derived from the ipw2200
+ * driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/version.h>
+#include <linux/firmware.h>
+#include <linux/wireless.h>
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <net/dst.h>
+#include <asm/unaligned.h>
+
+#include "b43legacy.h"
+#include "main.h"
+#include "debugfs.h"
+#include "phy.h"
+#include "dma.h"
+#include "pio.h"
+#include "sysfs.h"
+#include "xmit.h"
+#include "radio.h"
+
+
+MODULE_DESCRIPTION("Broadcom B43legacy wireless driver");
+MODULE_AUTHOR("Martin Langer");
+MODULE_AUTHOR("Stefano Brivio");
+MODULE_AUTHOR("Michael Buesch");
+MODULE_LICENSE("GPL");
+
+#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)
+static int modparam_pio;
+module_param_named(pio, modparam_pio, int, 0444);
+MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
+#elif defined(CONFIG_B43LEGACY_DMA)
+# define modparam_pio 0
+#elif defined(CONFIG_B43LEGACY_PIO)
+# define modparam_pio 1
+#endif
+
+static int modparam_bad_frames_preempt;
+module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
+MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames"
+ " Preemption");
+
+static int modparam_short_retry = B43legacy_DEFAULT_SHORT_RETRY_LIMIT;
+module_param_named(short_retry, modparam_short_retry, int, 0444);
+MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
+
+static int modparam_long_retry = B43legacy_DEFAULT_LONG_RETRY_LIMIT;
+module_param_named(long_retry, modparam_long_retry, int, 0444);
+MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
+
+static int modparam_noleds;
+module_param_named(noleds, modparam_noleds, int, 0444);
+MODULE_PARM_DESC(noleds, "Turn off all LED activity");
+
+static char modparam_fwpostfix[16];
+module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
+MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load.");
+
+/* The following table supports BCM4301, BCM4303 and BCM4306/2 devices. */
+static const struct ssb_device_id b43legacy_ssb_tbl[] = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 4),
+ SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, b43legacy_ssb_tbl);
+
+
+/* Channel and ratetables are shared for all devices.
+ * They can't be const, because ieee80211 puts some precalculated
+ * data in there. This data is the same for all devices, so we don't
+ * get concurrency issues */
+#define RATETAB_ENT(_rateid, _flags) \
+ { \
+ .rate = B43legacy_RATE_TO_100KBPS(_rateid), \
+ .val = (_rateid), \
+ .val2 = (_rateid), \
+ .flags = (_flags), \
+ }
+static struct ieee80211_rate __b43legacy_ratetable[] = {
+ RATETAB_ENT(B43legacy_CCK_RATE_1MB, IEEE80211_RATE_CCK),
+ RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
+ RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
+ RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
+ RATETAB_ENT(B43legacy_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
+ RATETAB_ENT(B43legacy_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
+};
+#define b43legacy_a_ratetable (__b43legacy_ratetable + 4)
+#define b43legacy_a_ratetable_size 8
+#define b43legacy_b_ratetable (__b43legacy_ratetable + 0)
+#define b43legacy_b_ratetable_size 4
+#define b43legacy_g_ratetable (__b43legacy_ratetable + 0)
+#define b43legacy_g_ratetable_size 12
+
+#define CHANTAB_ENT(_chanid, _freq) \
+ { \
+ .chan = (_chanid), \
+ .freq = (_freq), \
+ .val = (_chanid), \
+ .flag = IEEE80211_CHAN_W_SCAN | \
+ IEEE80211_CHAN_W_ACTIVE_SCAN | \
+ IEEE80211_CHAN_W_IBSS, \
+ .power_level = 0x0A, \
+ .antenna_max = 0xFF, \
+ }
+static struct ieee80211_channel b43legacy_bg_chantable[] = {
+ CHANTAB_ENT(1, 2412),
+ CHANTAB_ENT(2, 2417),
+ CHANTAB_ENT(3, 2422),
+ CHANTAB_ENT(4, 2427),
+ CHANTAB_ENT(5, 2432),
+ CHANTAB_ENT(6, 2437),
+ CHANTAB_ENT(7, 2442),
+ CHANTAB_ENT(8, 2447),
+ CHANTAB_ENT(9, 2452),
+ CHANTAB_ENT(10, 2457),
+ CHANTAB_ENT(11, 2462),
+ CHANTAB_ENT(12, 2467),
+ CHANTAB_ENT(13, 2472),
+ CHANTAB_ENT(14, 2484),
+};
+#define b43legacy_bg_chantable_size ARRAY_SIZE(b43legacy_bg_chantable)
+
+static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev);
+static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev);
+static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev);
+static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev);
+
+
+static int b43legacy_ratelimit(struct b43legacy_wl *wl)
+{
+ if (!wl || !wl->current_dev)
+ return 1;
+ if (b43legacy_status(wl->current_dev) < B43legacy_STAT_STARTED)
+ return 1;
+ /* We are up and running.
+ * Ratelimit the messages to avoid DoS over the net. */
+ return net_ratelimit();
+}
+
+void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ if (!b43legacy_ratelimit(wl))
+ return;
+ va_start(args, fmt);
+ printk(KERN_INFO "b43legacy-%s: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ if (!b43legacy_ratelimit(wl))
+ return;
+ va_start(args, fmt);
+ printk(KERN_ERR "b43legacy-%s ERROR: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ if (!b43legacy_ratelimit(wl))
+ return;
+ va_start(args, fmt);
+ printk(KERN_WARNING "b43legacy-%s warning: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+#if B43legacy_DEBUG
+void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ printk(KERN_DEBUG "b43legacy-%s debug: ",
+ (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+ vprintk(fmt, args);
+ va_end(args);
+}
+#endif /* DEBUG */
+
+static void b43legacy_ram_write(struct b43legacy_wldev *dev, u16 offset,
+ u32 val)
+{
+ u32 status;
+
+ B43legacy_WARN_ON(offset % 4 != 0);
+
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ if (status & B43legacy_SBF_XFER_REG_BYTESWAP)
+ val = swab32(val);
+
+ b43legacy_write32(dev, B43legacy_MMIO_RAM_CONTROL, offset);
+ mmiowb();
+ b43legacy_write32(dev, B43legacy_MMIO_RAM_DATA, val);
+}
+
+static inline
+void b43legacy_shm_control_word(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset)
+{
+ u32 control;
+
+ /* "offset" is the WORD offset. */
+
+ control = routing;
+ control <<= 16;
+ control |= offset;
+ b43legacy_write32(dev, B43legacy_MMIO_SHM_CONTROL, control);
+}
+
+u32 b43legacy_shm_read32(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset)
+{
+ u32 ret;
+
+ if (routing == B43legacy_SHM_SHARED) {
+ B43legacy_WARN_ON((offset & 0x0001) != 0);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43legacy_shm_control_word(dev, routing, offset >> 2);
+ ret = b43legacy_read16(dev,
+ B43legacy_MMIO_SHM_DATA_UNALIGNED);
+ ret <<= 16;
+ b43legacy_shm_control_word(dev, routing,
+ (offset >> 2) + 1);
+ ret |= b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA);
+
+ return ret;
+ }
+ offset >>= 2;
+ }
+ b43legacy_shm_control_word(dev, routing, offset);
+ ret = b43legacy_read32(dev, B43legacy_MMIO_SHM_DATA);
+
+ return ret;
+}
+
+u16 b43legacy_shm_read16(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset)
+{
+ u16 ret;
+
+ if (routing == B43legacy_SHM_SHARED) {
+ B43legacy_WARN_ON((offset & 0x0001) != 0);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43legacy_shm_control_word(dev, routing, offset >> 2);
+ ret = b43legacy_read16(dev,
+ B43legacy_MMIO_SHM_DATA_UNALIGNED);
+
+ return ret;
+ }
+ offset >>= 2;
+ }
+ b43legacy_shm_control_word(dev, routing, offset);
+ ret = b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA);
+
+ return ret;
+}
+
+void b43legacy_shm_write32(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset,
+ u32 value)
+{
+ if (routing == B43legacy_SHM_SHARED) {
+ B43legacy_WARN_ON((offset & 0x0001) != 0);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43legacy_shm_control_word(dev, routing, offset >> 2);
+ mmiowb();
+ b43legacy_write16(dev,
+ B43legacy_MMIO_SHM_DATA_UNALIGNED,
+ (value >> 16) & 0xffff);
+ mmiowb();
+ b43legacy_shm_control_word(dev, routing,
+ (offset >> 2) + 1);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA,
+ value & 0xffff);
+ return;
+ }
+ offset >>= 2;
+ }
+ b43legacy_shm_control_word(dev, routing, offset);
+ mmiowb();
+ b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, value);
+}
+
+void b43legacy_shm_write16(struct b43legacy_wldev *dev, u16 routing, u16 offset,
+ u16 value)
+{
+ if (routing == B43legacy_SHM_SHARED) {
+ B43legacy_WARN_ON((offset & 0x0001) != 0);
+ if (offset & 0x0003) {
+ /* Unaligned access */
+ b43legacy_shm_control_word(dev, routing, offset >> 2);
+ mmiowb();
+ b43legacy_write16(dev,
+ B43legacy_MMIO_SHM_DATA_UNALIGNED,
+ value);
+ return;
+ }
+ offset >>= 2;
+ }
+ b43legacy_shm_control_word(dev, routing, offset);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA, value);
+}
+
+/* Read HostFlags */
+u32 b43legacy_hf_read(struct b43legacy_wldev *dev)
+{
+ u32 ret;
+
+ ret = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_HOSTFHI);
+ ret <<= 16;
+ ret |= b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_HOSTFLO);
+
+ return ret;
+}
+
+/* Write HostFlags */
+void b43legacy_hf_write(struct b43legacy_wldev *dev, u32 value)
+{
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_HOSTFLO,
+ (value & 0x0000FFFF));
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_HOSTFHI,
+ ((value & 0xFFFF0000) >> 16));
+}
+
+void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf)
+{
+ /* We need to be careful. As we read the TSF from multiple
+ * registers, we should take care of register overflows.
+ * In theory, the whole tsf read process should be atomic.
+ * We try to be atomic here, by restaring the read process,
+ * if any of the high registers changed (overflew).
+ */
+ if (dev->dev->id.revision >= 3) {
+ u32 low;
+ u32 high;
+ u32 high2;
+
+ do {
+ high = b43legacy_read32(dev,
+ B43legacy_MMIO_REV3PLUS_TSF_HIGH);
+ low = b43legacy_read32(dev,
+ B43legacy_MMIO_REV3PLUS_TSF_LOW);
+ high2 = b43legacy_read32(dev,
+ B43legacy_MMIO_REV3PLUS_TSF_HIGH);
+ } while (unlikely(high != high2));
+
+ *tsf = high;
+ *tsf <<= 32;
+ *tsf |= low;
+ } else {
+ u64 tmp;
+ u16 v0;
+ u16 v1;
+ u16 v2;
+ u16 v3;
+ u16 test1;
+ u16 test2;
+ u16 test3;
+
+ do {
+ v3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3);
+ v2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2);
+ v1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1);
+ v0 = b43legacy_read16(dev, B43legacy_MMIO_TSF_0);
+
+ test3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3);
+ test2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2);
+ test1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1);
+ } while (v3 != test3 || v2 != test2 || v1 != test1);
+
+ *tsf = v3;
+ *tsf <<= 48;
+ tmp = v2;
+ tmp <<= 32;
+ *tsf |= tmp;
+ tmp = v1;
+ tmp <<= 16;
+ *tsf |= tmp;
+ *tsf |= v0;
+ }
+}
+
+static void b43legacy_time_lock(struct b43legacy_wldev *dev)
+{
+ u32 status;
+
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ status |= B43legacy_SBF_TIME_UPDATE;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+ mmiowb();
+}
+
+static void b43legacy_time_unlock(struct b43legacy_wldev *dev)
+{
+ u32 status;
+
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ status &= ~B43legacy_SBF_TIME_UPDATE;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+}
+
+static void b43legacy_tsf_write_locked(struct b43legacy_wldev *dev, u64 tsf)
+{
+ /* Be careful with the in-progress timer.
+ * First zero out the low register, so we have a full
+ * register-overflow duration to complete the operation.
+ */
+ if (dev->dev->id.revision >= 3) {
+ u32 lo = (tsf & 0x00000000FFFFFFFFULL);
+ u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
+
+ b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_LOW, 0);
+ mmiowb();
+ b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_HIGH,
+ hi);
+ mmiowb();
+ b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_LOW,
+ lo);
+ } else {
+ u16 v0 = (tsf & 0x000000000000FFFFULL);
+ u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
+ u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
+ u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
+
+ b43legacy_write16(dev, B43legacy_MMIO_TSF_0, 0);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_TSF_3, v3);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_TSF_2, v2);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_TSF_1, v1);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_TSF_0, v0);
+ }
+}
+
+void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf)
+{
+ b43legacy_time_lock(dev);
+ b43legacy_tsf_write_locked(dev, tsf);
+ b43legacy_time_unlock(dev);
+}
+
+static
+void b43legacy_macfilter_set(struct b43legacy_wldev *dev,
+ u16 offset, const u8 *mac)
+{
+ static const u8 zero_addr[ETH_ALEN] = { 0 };
+ u16 data;
+
+ if (!mac)
+ mac = zero_addr;
+
+ offset |= 0x0020;
+ b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_CONTROL, offset);
+
+ data = mac[0];
+ data |= mac[1] << 8;
+ b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data);
+ data = mac[2];
+ data |= mac[3] << 8;
+ b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data);
+ data = mac[4];
+ data |= mac[5] << 8;
+ b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data);
+}
+
+static void b43legacy_write_mac_bssid_templates(struct b43legacy_wldev *dev)
+{
+ static const u8 zero_addr[ETH_ALEN] = { 0 };
+ const u8 *mac = dev->wl->mac_addr;
+ const u8 *bssid = dev->wl->bssid;
+ u8 mac_bssid[ETH_ALEN * 2];
+ int i;
+ u32 tmp;
+
+ if (!bssid)
+ bssid = zero_addr;
+ if (!mac)
+ mac = zero_addr;
+
+ b43legacy_macfilter_set(dev, B43legacy_MACFILTER_BSSID, bssid);
+
+ memcpy(mac_bssid, mac, ETH_ALEN);
+ memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
+
+ /* Write our MAC address and BSSID to template ram */
+ for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) {
+ tmp = (u32)(mac_bssid[i + 0]);
+ tmp |= (u32)(mac_bssid[i + 1]) << 8;
+ tmp |= (u32)(mac_bssid[i + 2]) << 16;
+ tmp |= (u32)(mac_bssid[i + 3]) << 24;
+ b43legacy_ram_write(dev, 0x20 + i, tmp);
+ b43legacy_ram_write(dev, 0x78 + i, tmp);
+ b43legacy_ram_write(dev, 0x478 + i, tmp);
+ }
+}
+
+static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev)
+{
+ b43legacy_write_mac_bssid_templates(dev);
+ b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF,
+ dev->wl->mac_addr);
+}
+
+static void b43legacy_set_slot_time(struct b43legacy_wldev *dev,
+ u16 slot_time)
+{
+ /* slot_time is in usec. */
+ if (dev->phy.type != B43legacy_PHYTYPE_G)
+ return;
+ b43legacy_write16(dev, 0x684, 510 + slot_time);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0010,
+ slot_time);
+}
+
+static void b43legacy_short_slot_timing_enable(struct b43legacy_wldev *dev)
+{
+ b43legacy_set_slot_time(dev, 9);
+ dev->short_slot = 1;
+}
+
+static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev)
+{
+ b43legacy_set_slot_time(dev, 20);
+ dev->short_slot = 0;
+}
+
+/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 b43legacy_interrupt_enable(struct b43legacy_wldev *dev,
+ u32 mask)
+{
+ u32 old_mask;
+
+ old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask |
+ mask);
+
+ return old_mask;
+}
+
+/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 b43legacy_interrupt_disable(struct b43legacy_wldev *dev,
+ u32 mask)
+{
+ u32 old_mask;
+
+ old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
+
+ return old_mask;
+}
+
+/* Synchronize IRQ top- and bottom-half.
+ * IRQs must be masked before calling this.
+ * This must not be called with the irq_lock held.
+ */
+static void b43legacy_synchronize_irq(struct b43legacy_wldev *dev)
+{
+ synchronize_irq(dev->dev->irq);
+ tasklet_kill(&dev->isr_tasklet);
+}
+
+/* DummyTransmission function, as documented on
+ * http://bcm-specs.sipsolutions.net/DummyTransmission
+ */
+void b43legacy_dummy_transmission(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ unsigned int i;
+ unsigned int max_loop;
+ u16 value;
+ u32 buffer[5] = {
+ 0x00000000,
+ 0x00D40000,
+ 0x00000000,
+ 0x01000000,
+ 0x00000000,
+ };
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ case B43legacy_PHYTYPE_G:
+ max_loop = 0xFA;
+ buffer[0] = 0x000B846E;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ return;
+ }
+
+ for (i = 0; i < 5; i++)
+ b43legacy_ram_write(dev, i * 4, buffer[i]);
+
+ /* dummy read follows */
+ b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+
+ b43legacy_write16(dev, 0x0568, 0x0000);
+ b43legacy_write16(dev, 0x07C0, 0x0000);
+ b43legacy_write16(dev, 0x050C, 0x0000);
+ b43legacy_write16(dev, 0x0508, 0x0000);
+ b43legacy_write16(dev, 0x050A, 0x0000);
+ b43legacy_write16(dev, 0x054C, 0x0000);
+ b43legacy_write16(dev, 0x056A, 0x0014);
+ b43legacy_write16(dev, 0x0568, 0x0826);
+ b43legacy_write16(dev, 0x0500, 0x0000);
+ b43legacy_write16(dev, 0x0502, 0x0030);
+
+ if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
+ b43legacy_radio_write16(dev, 0x0051, 0x0017);
+ for (i = 0x00; i < max_loop; i++) {
+ value = b43legacy_read16(dev, 0x050E);
+ if (value & 0x0080)
+ break;
+ udelay(10);
+ }
+ for (i = 0x00; i < 0x0A; i++) {
+ value = b43legacy_read16(dev, 0x050E);
+ if (value & 0x0400)
+ break;
+ udelay(10);
+ }
+ for (i = 0x00; i < 0x0A; i++) {
+ value = b43legacy_read16(dev, 0x0690);
+ if (!(value & 0x0100))
+ break;
+ udelay(10);
+ }
+ if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
+ b43legacy_radio_write16(dev, 0x0051, 0x0037);
+}
+
+/* Turn the Analog ON/OFF */
+static void b43legacy_switch_analog(struct b43legacy_wldev *dev, int on)
+{
+ b43legacy_write16(dev, B43legacy_MMIO_PHY0, on ? 0 : 0xF4);
+}
+
+void b43legacy_wireless_core_reset(struct b43legacy_wldev *dev, u32 flags)
+{
+ u32 tmslow;
+ u32 macctl;
+
+ flags |= B43legacy_TMSLOW_PHYCLKEN;
+ flags |= B43legacy_TMSLOW_PHYRESET;
+ ssb_device_enable(dev->dev, flags);
+ msleep(2); /* Wait for the PLL to turn on. */
+
+ /* Now take the PHY out of Reset again */
+ tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+ tmslow |= SSB_TMSLOW_FGC;
+ tmslow &= ~B43legacy_TMSLOW_PHYRESET;
+ ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+ ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
+ msleep(1);
+ tmslow &= ~SSB_TMSLOW_FGC;
+ ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+ ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
+ msleep(1);
+
+ /* Turn Analog ON */
+ b43legacy_switch_analog(dev, 1);
+
+ macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+ macctl &= ~B43legacy_MACCTL_GMODE;
+ if (flags & B43legacy_TMSLOW_GMODE) {
+ macctl |= B43legacy_MACCTL_GMODE;
+ dev->phy.gmode = 1;
+ } else
+ dev->phy.gmode = 0;
+ macctl |= B43legacy_MACCTL_IHR_ENABLED;
+ b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
+}
+
+static void handle_irq_transmit_status(struct b43legacy_wldev *dev)
+{
+ u32 v0;
+ u32 v1;
+ u16 tmp;
+ struct b43legacy_txstatus stat;
+
+ while (1) {
+ v0 = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_0);
+ if (!(v0 & 0x00000001))
+ break;
+ v1 = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_1);
+
+ stat.cookie = (v0 >> 16);
+ stat.seq = (v1 & 0x0000FFFF);
+ stat.phy_stat = ((v1 & 0x00FF0000) >> 16);
+ tmp = (v0 & 0x0000FFFF);
+ stat.frame_count = ((tmp & 0xF000) >> 12);
+ stat.rts_count = ((tmp & 0x0F00) >> 8);
+ stat.supp_reason = ((tmp & 0x001C) >> 2);
+ stat.pm_indicated = !!(tmp & 0x0080);
+ stat.intermediate = !!(tmp & 0x0040);
+ stat.for_ampdu = !!(tmp & 0x0020);
+ stat.acked = !!(tmp & 0x0002);
+
+ b43legacy_handle_txstatus(dev, &stat);
+ }
+}
+
+static void drain_txstatus_queue(struct b43legacy_wldev *dev)
+{
+ u32 dummy;
+
+ if (dev->dev->id.revision < 5)
+ return;
+ /* Read all entries from the microcode TXstatus FIFO
+ * and throw them away.
+ */
+ while (1) {
+ dummy = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_0);
+ if (!(dummy & 0x00000001))
+ break;
+ dummy = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_1);
+ }
+}
+
+static u32 b43legacy_jssi_read(struct b43legacy_wldev *dev)
+{
+ u32 val = 0;
+
+ val = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x40A);
+ val <<= 16;
+ val |= b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x408);
+
+ return val;
+}
+
+static void b43legacy_jssi_write(struct b43legacy_wldev *dev, u32 jssi)
+{
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x408,
+ (jssi & 0x0000FFFF));
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x40A,
+ (jssi & 0xFFFF0000) >> 16);
+}
+
+static void b43legacy_generate_noise_sample(struct b43legacy_wldev *dev)
+{
+ b43legacy_jssi_write(dev, 0x7F7F7F7F);
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+ b43legacy_read32(dev,
+ B43legacy_MMIO_STATUS2_BITFIELD)
+ | (1 << 4));
+ B43legacy_WARN_ON(dev->noisecalc.channel_at_start !=
+ dev->phy.channel);
+}
+
+static void b43legacy_calculate_link_quality(struct b43legacy_wldev *dev)
+{
+ /* Top half of Link Quality calculation. */
+
+ if (dev->noisecalc.calculation_running)
+ return;
+ dev->noisecalc.channel_at_start = dev->phy.channel;
+ dev->noisecalc.calculation_running = 1;
+ dev->noisecalc.nr_samples = 0;
+
+ b43legacy_generate_noise_sample(dev);
+}
+
+static void handle_irq_noise(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 tmp;
+ u8 noise[4];
+ u8 i;
+ u8 j;
+ s32 average;
+
+ /* Bottom half of Link Quality calculation. */
+
+ B43legacy_WARN_ON(!dev->noisecalc.calculation_running);
+ if (dev->noisecalc.channel_at_start != phy->channel)
+ goto drop_calculation;
+ *((__le32 *)noise) = cpu_to_le32(b43legacy_jssi_read(dev));
+ if (noise[0] == 0x7F || noise[1] == 0x7F ||
+ noise[2] == 0x7F || noise[3] == 0x7F)
+ goto generate_new;
+
+ /* Get the noise samples. */
+ B43legacy_WARN_ON(dev->noisecalc.nr_samples >= 8);
+ i = dev->noisecalc.nr_samples;
+ noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+ dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
+ dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
+ dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
+ dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]];
+ dev->noisecalc.nr_samples++;
+ if (dev->noisecalc.nr_samples == 8) {
+ /* Calculate the Link Quality by the noise samples. */
+ average = 0;
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 4; j++)
+ average += dev->noisecalc.samples[i][j];
+ }
+ average /= (8 * 4);
+ average *= 125;
+ average += 64;
+ average /= 128;
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ 0x40C);
+ tmp = (tmp / 128) & 0x1F;
+ if (tmp >= 8)
+ average += 2;
+ else
+ average -= 25;
+ if (tmp == 8)
+ average -= 72;
+ else
+ average -= 48;
+
+ dev->stats.link_noise = average;
+drop_calculation:
+ dev->noisecalc.calculation_running = 0;
+ return;
+ }
+generate_new:
+ b43legacy_generate_noise_sample(dev);
+}
+
+static void handle_irq_tbtt_indication(struct b43legacy_wldev *dev)
+{
+ if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
+ /* TODO: PS TBTT */
+ } else {
+ if (1/*FIXME: the last PSpoll frame was sent successfully */)
+ b43legacy_power_saving_ctl_bits(dev, -1, -1);
+ }
+ dev->reg124_set_0x4 = 0;
+ if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
+ dev->reg124_set_0x4 = 1;
+}
+
+static void handle_irq_atim_end(struct b43legacy_wldev *dev)
+{
+ if (!dev->reg124_set_0x4) /*FIXME rename this variable*/
+ return;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+ b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD)
+ | 0x4);
+}
+
+static void handle_irq_pmq(struct b43legacy_wldev *dev)
+{
+ u32 tmp;
+
+ /* TODO: AP mode. */
+
+ while (1) {
+ tmp = b43legacy_read32(dev, B43legacy_MMIO_PS_STATUS);
+ if (!(tmp & 0x00000008))
+ break;
+ }
+ /* 16bit write is odd, but correct. */
+ b43legacy_write16(dev, B43legacy_MMIO_PS_STATUS, 0x0002);
+}
+
+static void b43legacy_write_template_common(struct b43legacy_wldev *dev,
+ const u8 *data, u16 size,
+ u16 ram_offset,
+ u16 shm_size_offset, u8 rate)
+{
+ u32 i;
+ u32 tmp;
+ struct b43legacy_plcp_hdr4 plcp;
+
+ plcp.data = 0;
+ b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+ b43legacy_ram_write(dev, ram_offset, le32_to_cpu(plcp.data));
+ ram_offset += sizeof(u32);
+ /* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet.
+ * So leave the first two bytes of the next write blank.
+ */
+ tmp = (u32)(data[0]) << 16;
+ tmp |= (u32)(data[1]) << 24;
+ b43legacy_ram_write(dev, ram_offset, tmp);
+ ram_offset += sizeof(u32);
+ for (i = 2; i < size; i += sizeof(u32)) {
+ tmp = (u32)(data[i + 0]);
+ if (i + 1 < size)
+ tmp |= (u32)(data[i + 1]) << 8;
+ if (i + 2 < size)
+ tmp |= (u32)(data[i + 2]) << 16;
+ if (i + 3 < size)
+ tmp |= (u32)(data[i + 3]) << 24;
+ b43legacy_ram_write(dev, ram_offset + i - 2, tmp);
+ }
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_size_offset,
+ size + sizeof(struct b43legacy_plcp_hdr6));
+}
+
+static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
+ u16 ram_offset,
+ u16 shm_size_offset, u8 rate)
+{
+ int len;
+ const u8 *data;
+
+ B43legacy_WARN_ON(!dev->cached_beacon);
+ len = min((size_t)dev->cached_beacon->len,
+ 0x200 - sizeof(struct b43legacy_plcp_hdr6));
+ data = (const u8 *)(dev->cached_beacon->data);
+ b43legacy_write_template_common(dev, data,
+ len, ram_offset,
+ shm_size_offset, rate);
+}
+
+static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
+ u16 shm_offset, u16 size,
+ u8 rate)
+{
+ struct b43legacy_plcp_hdr4 plcp;
+ u32 tmp;
+ __le16 dur;
+
+ plcp.data = 0;
+ b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+ dur = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->if_id,
+ size,
+ B43legacy_RATE_TO_100KBPS(rate));
+ /* Write PLCP in two parts and timing for packet transfer */
+ tmp = le32_to_cpu(plcp.data);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset,
+ tmp & 0xFFFF);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset + 2,
+ tmp >> 16);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset + 6,
+ le16_to_cpu(dur));
+}
+
+/* Instead of using custom probe response template, this function
+ * just patches custom beacon template by:
+ * 1) Changing packet type
+ * 2) Patching duration field
+ * 3) Stripping TIM
+ */
+static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev,
+ u16 *dest_size, u8 rate)
+{
+ const u8 *src_data;
+ u8 *dest_data;
+ u16 src_size;
+ u16 elem_size;
+ u16 src_pos;
+ u16 dest_pos;
+ __le16 dur;
+ struct ieee80211_hdr *hdr;
+
+ B43legacy_WARN_ON(!dev->cached_beacon);
+ src_size = dev->cached_beacon->len;
+ src_data = (const u8 *)dev->cached_beacon->data;
+
+ if (unlikely(src_size < 0x24)) {
+ b43legacydbg(dev->wl, "b43legacy_generate_probe_resp: "
+ "invalid beacon\n");
+ return NULL;
+ }
+
+ dest_data = kmalloc(src_size, GFP_ATOMIC);
+ if (unlikely(!dest_data))
+ return NULL;
+
+ /* 0x24 is offset of first variable-len Information-Element
+ * in beacon frame.
+ */
+ memcpy(dest_data, src_data, 0x24);
+ src_pos = 0x24;
+ dest_pos = 0x24;
+ for (; src_pos < src_size - 2; src_pos += elem_size) {
+ elem_size = src_data[src_pos + 1] + 2;
+ if (src_data[src_pos] != 0x05) { /* TIM */
+ memcpy(dest_data + dest_pos, src_data + src_pos,
+ elem_size);
+ dest_pos += elem_size;
+ }
+ }
+ *dest_size = dest_pos;
+ hdr = (struct ieee80211_hdr *)dest_data;
+
+ /* Set the frame control. */
+ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_PROBE_RESP);
+ dur = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->if_id,
+ *dest_size,
+ B43legacy_RATE_TO_100KBPS(rate));
+ hdr->duration_id = dur;
+
+ return dest_data;
+}
+
+static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
+ u16 ram_offset,
+ u16 shm_size_offset, u8 rate)
+{
+ u8 *probe_resp_data;
+ u16 size;
+
+ B43legacy_WARN_ON(!dev->cached_beacon);
+ size = dev->cached_beacon->len;
+ probe_resp_data = b43legacy_generate_probe_resp(dev, &size, rate);
+ if (unlikely(!probe_resp_data))
+ return;
+
+ /* Looks like PLCP headers plus packet timings are stored for
+ * all possible basic rates
+ */
+ b43legacy_write_probe_resp_plcp(dev, 0x31A, size,
+ B43legacy_CCK_RATE_1MB);
+ b43legacy_write_probe_resp_plcp(dev, 0x32C, size,
+ B43legacy_CCK_RATE_2MB);
+ b43legacy_write_probe_resp_plcp(dev, 0x33E, size,
+ B43legacy_CCK_RATE_5MB);
+ b43legacy_write_probe_resp_plcp(dev, 0x350, size,
+ B43legacy_CCK_RATE_11MB);
+
+ size = min((size_t)size,
+ 0x200 - sizeof(struct b43legacy_plcp_hdr6));
+ b43legacy_write_template_common(dev, probe_resp_data,
+ size, ram_offset,
+ shm_size_offset, rate);
+ kfree(probe_resp_data);
+}
+
+static int b43legacy_refresh_cached_beacon(struct b43legacy_wldev *dev,
+ struct sk_buff *beacon)
+{
+ if (dev->cached_beacon)
+ kfree_skb(dev->cached_beacon);
+ dev->cached_beacon = beacon;
+
+ return 0;
+}
+
+static void b43legacy_update_templates(struct b43legacy_wldev *dev)
+{
+ u32 status;
+
+ B43legacy_WARN_ON(!dev->cached_beacon);
+
+ b43legacy_write_beacon_template(dev, 0x68, 0x18,
+ B43legacy_CCK_RATE_1MB);
+ b43legacy_write_beacon_template(dev, 0x468, 0x1A,
+ B43legacy_CCK_RATE_1MB);
+ b43legacy_write_probe_resp_template(dev, 0x268, 0x4A,
+ B43legacy_CCK_RATE_11MB);
+
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
+ status |= 0x03;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, status);
+}
+
+static void b43legacy_refresh_templates(struct b43legacy_wldev *dev,
+ struct sk_buff *beacon)
+{
+ int err;
+
+ err = b43legacy_refresh_cached_beacon(dev, beacon);
+ if (unlikely(err))
+ return;
+ b43legacy_update_templates(dev);
+}
+
+static void b43legacy_set_ssid(struct b43legacy_wldev *dev,
+ const u8 *ssid, u8 ssid_len)
+{
+ u32 tmp;
+ u16 i;
+ u16 len;
+
+ len = min((u16)ssid_len, (u16)0x100);
+ for (i = 0; i < len; i += sizeof(u32)) {
+ tmp = (u32)(ssid[i + 0]);
+ if (i + 1 < len)
+ tmp |= (u32)(ssid[i + 1]) << 8;
+ if (i + 2 < len)
+ tmp |= (u32)(ssid[i + 2]) << 16;
+ if (i + 3 < len)
+ tmp |= (u32)(ssid[i + 3]) << 24;
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ 0x380 + i, tmp);
+ }
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ 0x48, len);
+}
+
+static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
+ u16 beacon_int)
+{
+ b43legacy_time_lock(dev);
+ if (dev->dev->id.revision >= 3)
+ b43legacy_write32(dev, 0x188, (beacon_int << 16));
+ else {
+ b43legacy_write16(dev, 0x606, (beacon_int >> 6));
+ b43legacy_write16(dev, 0x610, beacon_int);
+ }
+ b43legacy_time_unlock(dev);
+}
+
+static void handle_irq_beacon(struct b43legacy_wldev *dev)
+{
+ u32 status;
+
+ if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ return;
+
+ dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
+
+ if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
+ /* ACK beacon IRQ. */
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
+ B43legacy_IRQ_BEACON);
+ dev->irq_savedstate |= B43legacy_IRQ_BEACON;
+ if (dev->cached_beacon)
+ kfree_skb(dev->cached_beacon);
+ dev->cached_beacon = NULL;
+ return;
+ }
+ if (!(status & 0x1)) {
+ b43legacy_write_beacon_template(dev, 0x68, 0x18,
+ B43legacy_CCK_RATE_1MB);
+ status |= 0x1;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+ status);
+ }
+ if (!(status & 0x2)) {
+ b43legacy_write_beacon_template(dev, 0x468, 0x1A,
+ B43legacy_CCK_RATE_1MB);
+ status |= 0x2;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+ status);
+ }
+}
+
+static void handle_irq_ucode_debug(struct b43legacy_wldev *dev)
+{
+}
+
+/* Interrupt handler bottom-half */
+static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
+{
+ u32 reason;
+ u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
+ u32 merged_dma_reason = 0;
+ int i;
+ int activity = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+
+ B43legacy_WARN_ON(b43legacy_status(dev) <
+ B43legacy_STAT_INITIALIZED);
+
+ reason = dev->irq_reason;
+ for (i = 0; i < ARRAY_SIZE(dma_reason); i++) {
+ dma_reason[i] = dev->dma_reason[i];
+ merged_dma_reason |= dma_reason[i];
+ }
+
+ if (unlikely(reason & B43legacy_IRQ_MAC_TXERR))
+ b43legacyerr(dev->wl, "MAC transmission error\n");
+
+ if (unlikely(reason & B43legacy_IRQ_PHY_TXERR))
+ b43legacyerr(dev->wl, "PHY transmission error\n");
+
+ if (unlikely(merged_dma_reason & (B43legacy_DMAIRQ_FATALMASK |
+ B43legacy_DMAIRQ_NONFATALMASK))) {
+ if (merged_dma_reason & B43legacy_DMAIRQ_FATALMASK) {
+ b43legacyerr(dev->wl, "Fatal DMA error: "
+ "0x%08X, 0x%08X, 0x%08X, "
+ "0x%08X, 0x%08X, 0x%08X\n",
+ dma_reason[0], dma_reason[1],
+ dma_reason[2], dma_reason[3],
+ dma_reason[4], dma_reason[5]);
+ b43legacy_controller_restart(dev, "DMA error");
+ mmiowb();
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+ return;
+ }
+ if (merged_dma_reason & B43legacy_DMAIRQ_NONFATALMASK)
+ b43legacyerr(dev->wl, "DMA error: "
+ "0x%08X, 0x%08X, 0x%08X, "
+ "0x%08X, 0x%08X, 0x%08X\n",
+ dma_reason[0], dma_reason[1],
+ dma_reason[2], dma_reason[3],
+ dma_reason[4], dma_reason[5]);
+ }
+
+ if (unlikely(reason & B43legacy_IRQ_UCODE_DEBUG))
+ handle_irq_ucode_debug(dev);
+ if (reason & B43legacy_IRQ_TBTT_INDI)
+ handle_irq_tbtt_indication(dev);
+ if (reason & B43legacy_IRQ_ATIM_END)
+ handle_irq_atim_end(dev);
+ if (reason & B43legacy_IRQ_BEACON)
+ handle_irq_beacon(dev);
+ if (reason & B43legacy_IRQ_PMQ)
+ handle_irq_pmq(dev);
+ if (reason & B43legacy_IRQ_TXFIFO_FLUSH_OK)
+ ;/*TODO*/
+ if (reason & B43legacy_IRQ_NOISESAMPLE_OK)
+ handle_irq_noise(dev);
+
+ /* Check the DMA reason registers for received data. */
+ if (dma_reason[0] & B43legacy_DMAIRQ_RX_DONE) {
+ if (b43legacy_using_pio(dev))
+ b43legacy_pio_rx(dev->pio.queue0);
+ else
+ b43legacy_dma_rx(dev->dma.rx_ring0);
+ /* We intentionally don't set "activity" to 1, here. */
+ }
+ B43legacy_WARN_ON(dma_reason[1] & B43legacy_DMAIRQ_RX_DONE);
+ B43legacy_WARN_ON(dma_reason[2] & B43legacy_DMAIRQ_RX_DONE);
+ if (dma_reason[3] & B43legacy_DMAIRQ_RX_DONE) {
+ if (b43legacy_using_pio(dev))
+ b43legacy_pio_rx(dev->pio.queue3);
+ else
+ b43legacy_dma_rx(dev->dma.rx_ring3);
+ activity = 1;
+ }
+ B43legacy_WARN_ON(dma_reason[4] & B43legacy_DMAIRQ_RX_DONE);
+ B43legacy_WARN_ON(dma_reason[5] & B43legacy_DMAIRQ_RX_DONE);
+
+ if (reason & B43legacy_IRQ_TX_OK) {
+ handle_irq_transmit_status(dev);
+ activity = 1;
+ /* TODO: In AP mode, this also causes sending of powersave
+ responses. */
+ }
+
+ if (!modparam_noleds)
+ b43legacy_leds_update(dev, activity);
+ b43legacy_interrupt_enable(dev, dev->irq_savedstate);
+ mmiowb();
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+}
+
+static void pio_irq_workaround(struct b43legacy_wldev *dev,
+ u16 base, int queueidx)
+{
+ u16 rxctl;
+
+ rxctl = b43legacy_read16(dev, base + B43legacy_PIO_RXCTL);
+ if (rxctl & B43legacy_PIO_RXCTL_DATAAVAILABLE)
+ dev->dma_reason[queueidx] |= B43legacy_DMAIRQ_RX_DONE;
+ else
+ dev->dma_reason[queueidx] &= ~B43legacy_DMAIRQ_RX_DONE;
+}
+
+static void b43legacy_interrupt_ack(struct b43legacy_wldev *dev, u32 reason)
+{
+ if (b43legacy_using_pio(dev) &&
+ (dev->dev->id.revision < 3) &&
+ (!(reason & B43legacy_IRQ_PIO_WORKAROUND))) {
+ /* Apply a PIO specific workaround to the dma_reasons */
+ pio_irq_workaround(dev, B43legacy_MMIO_PIO1_BASE, 0);
+ pio_irq_workaround(dev, B43legacy_MMIO_PIO2_BASE, 1);
+ pio_irq_workaround(dev, B43legacy_MMIO_PIO3_BASE, 2);
+ pio_irq_workaround(dev, B43legacy_MMIO_PIO4_BASE, 3);
+ }
+
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, reason);
+
+ b43legacy_write32(dev, B43legacy_MMIO_DMA0_REASON,
+ dev->dma_reason[0]);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA1_REASON,
+ dev->dma_reason[1]);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA2_REASON,
+ dev->dma_reason[2]);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA3_REASON,
+ dev->dma_reason[3]);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA4_REASON,
+ dev->dma_reason[4]);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA5_REASON,
+ dev->dma_reason[5]);
+}
+
+/* Interrupt handler top-half */
+static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id)
+{
+ irqreturn_t ret = IRQ_NONE;
+ struct b43legacy_wldev *dev = dev_id;
+ u32 reason;
+
+ if (!dev)
+ return IRQ_NONE;
+
+ spin_lock(&dev->wl->irq_lock);
+
+ if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
+ goto out;
+ reason = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+ if (reason == 0xffffffff) /* shared IRQ */
+ goto out;
+ ret = IRQ_HANDLED;
+ reason &= b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
+ if (!reason)
+ goto out;
+
+ dev->dma_reason[0] = b43legacy_read32(dev,
+ B43legacy_MMIO_DMA0_REASON)
+ & 0x0001DC00;
+ dev->dma_reason[1] = b43legacy_read32(dev,
+ B43legacy_MMIO_DMA1_REASON)
+ & 0x0000DC00;
+ dev->dma_reason[2] = b43legacy_read32(dev,
+ B43legacy_MMIO_DMA2_REASON)
+ & 0x0000DC00;
+ dev->dma_reason[3] = b43legacy_read32(dev,
+ B43legacy_MMIO_DMA3_REASON)
+ & 0x0001DC00;
+ dev->dma_reason[4] = b43legacy_read32(dev,
+ B43legacy_MMIO_DMA4_REASON)
+ & 0x0000DC00;
+ dev->dma_reason[5] = b43legacy_read32(dev,
+ B43legacy_MMIO_DMA5_REASON)
+ & 0x0000DC00;
+
+ b43legacy_interrupt_ack(dev, reason);
+ /* disable all IRQs. They are enabled again in the bottom half. */
+ dev->irq_savedstate = b43legacy_interrupt_disable(dev,
+ B43legacy_IRQ_ALL);
+ /* save the reason code and call our bottom half. */
+ dev->irq_reason = reason;
+ tasklet_schedule(&dev->isr_tasklet);
+out:
+ mmiowb();
+ spin_unlock(&dev->wl->irq_lock);
+
+ return ret;
+}
+
+static void b43legacy_release_firmware(struct b43legacy_wldev *dev)
+{
+ release_firmware(dev->fw.ucode);
+ dev->fw.ucode = NULL;
+ release_firmware(dev->fw.pcm);
+ dev->fw.pcm = NULL;
+ release_firmware(dev->fw.initvals);
+ dev->fw.initvals = NULL;
+ release_firmware(dev->fw.initvals_band);
+ dev->fw.initvals_band = NULL;
+}
+
+static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl)
+{
+ b43legacyerr(wl, "You must go to http://linuxwireless.org/en/users/"
+ "Drivers/bcm43xx#devicefirmware "
+ "and download the correct firmware (version 3).\n");
+}
+
+static int do_request_fw(struct b43legacy_wldev *dev,
+ const char *name,
+ const struct firmware **fw)
+{
+ char path[sizeof(modparam_fwpostfix) + 32];
+ struct b43legacy_fw_header *hdr;
+ u32 size;
+ int err;
+
+ if (!name)
+ return 0;
+
+ snprintf(path, ARRAY_SIZE(path),
+ "b43legacy%s/%s.fw",
+ modparam_fwpostfix, name);
+ err = request_firmware(fw, path, dev->dev->dev);
+ if (err) {
+ b43legacyerr(dev->wl, "Firmware file \"%s\" not found "
+ "or load failed.\n", path);
+ return err;
+ }
+ if ((*fw)->size < sizeof(struct b43legacy_fw_header))
+ goto err_format;
+ hdr = (struct b43legacy_fw_header *)((*fw)->data);
+ switch (hdr->type) {
+ case B43legacy_FW_TYPE_UCODE:
+ case B43legacy_FW_TYPE_PCM:
+ size = be32_to_cpu(hdr->size);
+ if (size != (*fw)->size - sizeof(struct b43legacy_fw_header))
+ goto err_format;
+ /* fallthrough */
+ case B43legacy_FW_TYPE_IV:
+ if (hdr->ver != 1)
+ goto err_format;
+ break;
+ default:
+ goto err_format;
+ }
+
+ return err;
+
+err_format:
+ b43legacyerr(dev->wl, "Firmware file \"%s\" format error.\n", path);
+ return -EPROTO;
+}
+
+static int b43legacy_request_firmware(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_firmware *fw = &dev->fw;
+ const u8 rev = dev->dev->id.revision;
+ const char *filename;
+ u32 tmshigh;
+ int err;
+
+ tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+ if (!fw->ucode) {
+ if (rev == 2)
+ filename = "ucode2";
+ else if (rev == 4)
+ filename = "ucode4";
+ else
+ filename = "ucode5";
+ err = do_request_fw(dev, filename, &fw->ucode);
+ if (err)
+ goto err_load;
+ }
+ if (!fw->pcm) {
+ if (rev < 5)
+ filename = "pcm4";
+ else
+ filename = "pcm5";
+ err = do_request_fw(dev, filename, &fw->pcm);
+ if (err)
+ goto err_load;
+ }
+ if (!fw->initvals) {
+ switch (dev->phy.type) {
+ case B43legacy_PHYTYPE_G:
+ if ((rev >= 5) && (rev <= 10))
+ filename = "b0g0initvals5";
+ else if (rev == 2 || rev == 4)
+ filename = "b0g0initvals2";
+ else
+ goto err_no_initvals;
+ break;
+ default:
+ goto err_no_initvals;
+ }
+ err = do_request_fw(dev, filename, &fw->initvals);
+ if (err)
+ goto err_load;
+ }
+ if (!fw->initvals_band) {
+ switch (dev->phy.type) {
+ case B43legacy_PHYTYPE_G:
+ if ((rev >= 5) && (rev <= 10))
+ filename = "b0g0bsinitvals5";
+ else if (rev >= 11)
+ filename = NULL;
+ else if (rev == 2 || rev == 4)
+ filename = NULL;
+ else
+ goto err_no_initvals;
+ break;
+ default:
+ goto err_no_initvals;
+ }
+ err = do_request_fw(dev, filename, &fw->initvals_band);
+ if (err)
+ goto err_load;
+ }
+
+ return 0;
+
+err_load:
+ b43legacy_print_fw_helptext(dev->wl);
+ goto error;
+
+err_no_initvals:
+ err = -ENODEV;
+ b43legacyerr(dev->wl, "No Initial Values firmware file for PHY %u, "
+ "core rev %u\n", dev->phy.type, rev);
+ goto error;
+
+error:
+ b43legacy_release_firmware(dev);
+ return err;
+}
+
+static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
+{
+ const size_t hdr_len = sizeof(struct b43legacy_fw_header);
+ const __be32 *data;
+ unsigned int i;
+ unsigned int len;
+ u16 fwrev;
+ u16 fwpatch;
+ u16 fwdate;
+ u16 fwtime;
+ u32 tmp;
+ int err = 0;
+
+ /* Upload Microcode. */
+ data = (__be32 *) (dev->fw.ucode->data + hdr_len);
+ len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
+ b43legacy_shm_control_word(dev,
+ B43legacy_SHM_UCODE |
+ B43legacy_SHM_AUTOINC_W,
+ 0x0000);
+ for (i = 0; i < len; i++) {
+ b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA,
+ be32_to_cpu(data[i]));
+ udelay(10);
+ }
+
+ if (dev->fw.pcm) {
+ /* Upload PCM data. */
+ data = (__be32 *) (dev->fw.pcm->data + hdr_len);
+ len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32);
+ b43legacy_shm_control_word(dev, B43legacy_SHM_HW, 0x01EA);
+ b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, 0x00004000);
+ /* No need for autoinc bit in SHM_HW */
+ b43legacy_shm_control_word(dev, B43legacy_SHM_HW, 0x01EB);
+ for (i = 0; i < len; i++) {
+ b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA,
+ be32_to_cpu(data[i]));
+ udelay(10);
+ }
+ }
+
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
+ B43legacy_IRQ_ALL);
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0x00020402);
+
+ /* Wait for the microcode to load and respond */
+ i = 0;
+ while (1) {
+ tmp = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+ if (tmp == B43legacy_IRQ_MAC_SUSPENDED)
+ break;
+ i++;
+ if (i >= B43legacy_IRQWAIT_MAX_RETRIES) {
+ b43legacyerr(dev->wl, "Microcode not responding\n");
+ b43legacy_print_fw_helptext(dev->wl);
+ err = -ENODEV;
+ goto out;
+ }
+ udelay(10);
+ }
+ /* dummy read follows */
+ b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+
+ /* Get and check the revisions. */
+ fwrev = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_UCODEREV);
+ fwpatch = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_UCODEPATCH);
+ fwdate = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_UCODEDATE);
+ fwtime = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_UCODETIME);
+
+ if (fwrev > 0x128) {
+ b43legacyerr(dev->wl, "YOU ARE TRYING TO LOAD V4 FIRMWARE."
+ " Only firmware from binary drivers version 3.x"
+ " is supported. You must change your firmware"
+ " files.\n");
+ b43legacy_print_fw_helptext(dev->wl);
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0);
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+ b43legacydbg(dev->wl, "Loading firmware version 0x%X, patch level %u "
+ "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch,
+ (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
+ (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
+
+ dev->fw.rev = fwrev;
+ dev->fw.patch = fwpatch;
+
+out:
+ return err;
+}
+
+static int b43legacy_write_initvals(struct b43legacy_wldev *dev,
+ const struct b43legacy_iv *ivals,
+ size_t count,
+ size_t array_size)
+{
+ const struct b43legacy_iv *iv;
+ u16 offset;
+ size_t i;
+ bool bit32;
+
+ BUILD_BUG_ON(sizeof(struct b43legacy_iv) != 6);
+ iv = ivals;
+ for (i = 0; i < count; i++) {
+ if (array_size < sizeof(iv->offset_size))
+ goto err_format;
+ array_size -= sizeof(iv->offset_size);
+ offset = be16_to_cpu(iv->offset_size);
+ bit32 = !!(offset & B43legacy_IV_32BIT);
+ offset &= B43legacy_IV_OFFSET_MASK;
+ if (offset >= 0x1000)
+ goto err_format;
+ if (bit32) {
+ u32 value;
+
+ if (array_size < sizeof(iv->data.d32))
+ goto err_format;
+ array_size -= sizeof(iv->data.d32);
+
+ value = be32_to_cpu(get_unaligned(&iv->data.d32));
+ b43legacy_write32(dev, offset, value);
+
+ iv = (const struct b43legacy_iv *)((const uint8_t *)iv +
+ sizeof(__be16) +
+ sizeof(__be32));
+ } else {
+ u16 value;
+
+ if (array_size < sizeof(iv->data.d16))
+ goto err_format;
+ array_size -= sizeof(iv->data.d16);
+
+ value = be16_to_cpu(iv->data.d16);
+ b43legacy_write16(dev, offset, value);
+
+ iv = (const struct b43legacy_iv *)((const uint8_t *)iv +
+ sizeof(__be16) +
+ sizeof(__be16));
+ }
+ }
+ if (array_size)
+ goto err_format;
+
+ return 0;
+
+err_format:
+ b43legacyerr(dev->wl, "Initial Values Firmware file-format error.\n");
+ b43legacy_print_fw_helptext(dev->wl);
+
+ return -EPROTO;
+}
+
+static int b43legacy_upload_initvals(struct b43legacy_wldev *dev)
+{
+ const size_t hdr_len = sizeof(struct b43legacy_fw_header);
+ const struct b43legacy_fw_header *hdr;
+ struct b43legacy_firmware *fw = &dev->fw;
+ const struct b43legacy_iv *ivals;
+ size_t count;
+ int err;
+
+ hdr = (const struct b43legacy_fw_header *)(fw->initvals->data);
+ ivals = (const struct b43legacy_iv *)(fw->initvals->data + hdr_len);
+ count = be32_to_cpu(hdr->size);
+ err = b43legacy_write_initvals(dev, ivals, count,
+ fw->initvals->size - hdr_len);
+ if (err)
+ goto out;
+ if (fw->initvals_band) {
+ hdr = (const struct b43legacy_fw_header *)
+ (fw->initvals_band->data);
+ ivals = (const struct b43legacy_iv *)(fw->initvals_band->data
+ + hdr_len);
+ count = be32_to_cpu(hdr->size);
+ err = b43legacy_write_initvals(dev, ivals, count,
+ fw->initvals_band->size - hdr_len);
+ if (err)
+ goto out;
+ }
+out:
+
+ return err;
+}
+
+/* Initialize the GPIOs
+ * http://bcm-specs.sipsolutions.net/GPIO
+ */
+static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_device *gpiodev, *pcidev = NULL;
+ u32 mask;
+ u32 set;
+
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+ b43legacy_read32(dev,
+ B43legacy_MMIO_STATUS_BITFIELD)
+ & 0xFFFF3FFF);
+
+ b43legacy_leds_switch_all(dev, 0);
+ b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
+ b43legacy_read16(dev,
+ B43legacy_MMIO_GPIO_MASK)
+ | 0x000F);
+
+ mask = 0x0000001F;
+ set = 0x0000000F;
+ if (dev->dev->bus->chip_id == 0x4301) {
+ mask |= 0x0060;
+ set |= 0x0060;
+ }
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) {
+ b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
+ b43legacy_read16(dev,
+ B43legacy_MMIO_GPIO_MASK)
+ | 0x0200);
+ mask |= 0x0200;
+ set |= 0x0200;
+ }
+ if (dev->dev->id.revision >= 2)
+ mask |= 0x0010; /* FIXME: This is redundant. */
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ pcidev = bus->pcicore.dev;
+#endif
+ gpiodev = bus->chipco.dev ? : pcidev;
+ if (!gpiodev)
+ return 0;
+ ssb_write32(gpiodev, B43legacy_GPIO_CONTROL,
+ (ssb_read32(gpiodev, B43legacy_GPIO_CONTROL)
+ & mask) | set);
+
+ return 0;
+}
+
+/* Turn off all GPIO stuff. Call this on module unload, for example. */
+static void b43legacy_gpio_cleanup(struct b43legacy_wldev *dev)
+{
+ struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_device *gpiodev, *pcidev = NULL;
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ pcidev = bus->pcicore.dev;
+#endif
+ gpiodev = bus->chipco.dev ? : pcidev;
+ if (!gpiodev)
+ return;
+ ssb_write32(gpiodev, B43legacy_GPIO_CONTROL, 0);
+}
+
+/* http://bcm-specs.sipsolutions.net/EnableMac */
+void b43legacy_mac_enable(struct b43legacy_wldev *dev)
+{
+ dev->mac_suspended--;
+ B43legacy_WARN_ON(dev->mac_suspended < 0);
+ if (dev->mac_suspended == 0) {
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+ b43legacy_read32(dev,
+ B43legacy_MMIO_STATUS_BITFIELD)
+ | B43legacy_SBF_MAC_ENABLED);
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
+ B43legacy_IRQ_MAC_SUSPENDED);
+ /* the next two are dummy reads */
+ b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+ b43legacy_power_saving_ctl_bits(dev, -1, -1);
+ }
+}
+
+/* http://bcm-specs.sipsolutions.net/SuspendMAC */
+void b43legacy_mac_suspend(struct b43legacy_wldev *dev)
+{
+ int i;
+ u32 tmp;
+
+ B43legacy_WARN_ON(dev->mac_suspended < 0);
+ if (dev->mac_suspended == 0) {
+ b43legacy_power_saving_ctl_bits(dev, -1, 1);
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+ b43legacy_read32(dev,
+ B43legacy_MMIO_STATUS_BITFIELD)
+ & ~B43legacy_SBF_MAC_ENABLED);
+ b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+ for (i = 10000; i; i--) {
+ tmp = b43legacy_read32(dev,
+ B43legacy_MMIO_GEN_IRQ_REASON);
+ if (tmp & B43legacy_IRQ_MAC_SUSPENDED)
+ goto out;
+ udelay(1);
+ }
+ b43legacyerr(dev->wl, "MAC suspend failed\n");
+ }
+out:
+ dev->mac_suspended++;
+}
+
+static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_wl *wl = dev->wl;
+ u32 ctl;
+ u16 cfp_pretbtt;
+
+ ctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+ /* Reset status to STA infrastructure mode. */
+ ctl &= ~B43legacy_MACCTL_AP;
+ ctl &= ~B43legacy_MACCTL_KEEP_CTL;
+ ctl &= ~B43legacy_MACCTL_KEEP_BADPLCP;
+ ctl &= ~B43legacy_MACCTL_KEEP_BAD;
+ ctl &= ~B43legacy_MACCTL_PROMISC;
+ ctl &= ~B43legacy_MACCTL_BEACPROMISC;
+ ctl |= B43legacy_MACCTL_INFRA;
+
+ if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ ctl |= B43legacy_MACCTL_AP;
+ else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+ ctl &= ~B43legacy_MACCTL_INFRA;
+
+ if (wl->filter_flags & FIF_CONTROL)
+ ctl |= B43legacy_MACCTL_KEEP_CTL;
+ if (wl->filter_flags & FIF_FCSFAIL)
+ ctl |= B43legacy_MACCTL_KEEP_BAD;
+ if (wl->filter_flags & FIF_PLCPFAIL)
+ ctl |= B43legacy_MACCTL_KEEP_BADPLCP;
+ if (wl->filter_flags & FIF_PROMISC_IN_BSS)
+ ctl |= B43legacy_MACCTL_PROMISC;
+ if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
+ ctl |= B43legacy_MACCTL_BEACPROMISC;
+
+ /* Workaround: On old hardware the HW-MAC-address-filter
+ * doesn't work properly, so always run promisc in filter
+ * it in software. */
+ if (dev->dev->id.revision <= 4)
+ ctl |= B43legacy_MACCTL_PROMISC;
+
+ b43legacy_write32(dev, B43legacy_MMIO_MACCTL, ctl);
+
+ cfp_pretbtt = 2;
+ if ((ctl & B43legacy_MACCTL_INFRA) &&
+ !(ctl & B43legacy_MACCTL_AP)) {
+ if (dev->dev->bus->chip_id == 0x4306 &&
+ dev->dev->bus->chip_rev == 3)
+ cfp_pretbtt = 100;
+ else
+ cfp_pretbtt = 50;
+ }
+ b43legacy_write16(dev, 0x612, cfp_pretbtt);
+}
+
+static void b43legacy_rate_memory_write(struct b43legacy_wldev *dev,
+ u16 rate,
+ int is_ofdm)
+{
+ u16 offset;
+
+ if (is_ofdm) {
+ offset = 0x480;
+ offset += (b43legacy_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
+ } else {
+ offset = 0x4C0;
+ offset += (b43legacy_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
+ }
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, offset + 0x20,
+ b43legacy_shm_read16(dev,
+ B43legacy_SHM_SHARED, offset));
+}
+
+static void b43legacy_rate_memory_init(struct b43legacy_wldev *dev)
+{
+ switch (dev->phy.type) {
+ case B43legacy_PHYTYPE_G:
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_6MB, 1);
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_12MB, 1);
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_18MB, 1);
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_24MB, 1);
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_36MB, 1);
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_48MB, 1);
+ b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_54MB, 1);
+ /* fallthrough */
+ case B43legacy_PHYTYPE_B:
+ b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_1MB, 0);
+ b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_2MB, 0);
+ b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_5MB, 0);
+ b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_11MB, 0);
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+}
+
+/* Set the TX-Antenna for management frames sent by firmware. */
+static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev,
+ int antenna)
+{
+ u16 ant = 0;
+ u16 tmp;
+
+ switch (antenna) {
+ case B43legacy_ANTENNA0:
+ ant |= B43legacy_TX4_PHY_ANT0;
+ break;
+ case B43legacy_ANTENNA1:
+ ant |= B43legacy_TX4_PHY_ANT1;
+ break;
+ case B43legacy_ANTENNA_AUTO:
+ ant |= B43legacy_TX4_PHY_ANTLAST;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+
+ /* FIXME We also need to set the other flags of the PHY control
+ * field somewhere. */
+
+ /* For Beacons */
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_BEACPHYCTL);
+ tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_BEACPHYCTL, tmp);
+ /* For ACK/CTS */
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_ACKCTSPHYCTL);
+ tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_ACKCTSPHYCTL, tmp);
+ /* For Probe Resposes */
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_PRPHYCTL);
+ tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_PRPHYCTL, tmp);
+}
+
+/* Returns TRUE, if the radio is enabled in hardware. */
+static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
+{
+ if (dev->phy.rev >= 3) {
+ if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI)
+ & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK))
+ return 1;
+ } else {
+ if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO)
+ & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK)
+ return 1;
+ }
+ return 0;
+}
+
+/* This is the opposite of b43legacy_chip_init() */
+static void b43legacy_chip_exit(struct b43legacy_wldev *dev)
+{
+ b43legacy_radio_turn_off(dev);
+ if (!modparam_noleds)
+ b43legacy_leds_exit(dev);
+ b43legacy_gpio_cleanup(dev);
+ /* firmware is released later */
+}
+
+/* Initialize the chip
+ * http://bcm-specs.sipsolutions.net/ChipInit
+ */
+static int b43legacy_chip_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ int err;
+ int tmp;
+ u32 value32;
+ u16 value16;
+
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+ B43legacy_SBF_CORE_READY
+ | B43legacy_SBF_400);
+
+ err = b43legacy_request_firmware(dev);
+ if (err)
+ goto out;
+ err = b43legacy_upload_microcode(dev);
+ if (err)
+ goto out; /* firmware is released later */
+
+ err = b43legacy_gpio_init(dev);
+ if (err)
+ goto out; /* firmware is released later */
+ err = b43legacy_upload_initvals(dev);
+ if (err)
+ goto err_gpio_cleanup;
+ b43legacy_radio_turn_on(dev);
+
+ b43legacy_write16(dev, 0x03E6, 0x0000);
+ err = b43legacy_phy_init(dev);
+ if (err)
+ goto err_radio_off;
+
+ /* Select initial Interference Mitigation. */
+ tmp = phy->interfmode;
+ phy->interfmode = B43legacy_INTERFMODE_NONE;
+ b43legacy_radio_set_interference_mitigation(dev, tmp);
+
+ b43legacy_phy_set_antenna_diversity(dev);
+ b43legacy_mgmtframe_txantenna(dev, B43legacy_ANTENNA_DEFAULT);
+
+ if (phy->type == B43legacy_PHYTYPE_B) {
+ value16 = b43legacy_read16(dev, 0x005E);
+ value16 |= 0x0004;
+ b43legacy_write16(dev, 0x005E, value16);
+ }
+ b43legacy_write32(dev, 0x0100, 0x01000000);
+ if (dev->dev->id.revision < 5)
+ b43legacy_write32(dev, 0x010C, 0x01000000);
+
+ value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ value32 &= ~B43legacy_SBF_MODE_NOTADHOC;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
+ value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ value32 |= B43legacy_SBF_MODE_NOTADHOC;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
+
+ if (b43legacy_using_pio(dev)) {
+ b43legacy_write32(dev, 0x0210, 0x00000100);
+ b43legacy_write32(dev, 0x0230, 0x00000100);
+ b43legacy_write32(dev, 0x0250, 0x00000100);
+ b43legacy_write32(dev, 0x0270, 0x00000100);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0034,
+ 0x0000);
+ }
+
+ /* Probe Response Timeout value */
+ /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0074, 0x0000);
+
+ /* Initially set the wireless operation mode. */
+ b43legacy_adjust_opmode(dev);
+
+ if (dev->dev->id.revision < 3) {
+ b43legacy_write16(dev, 0x060E, 0x0000);
+ b43legacy_write16(dev, 0x0610, 0x8000);
+ b43legacy_write16(dev, 0x0604, 0x0000);
+ b43legacy_write16(dev, 0x0606, 0x0200);
+ } else {
+ b43legacy_write32(dev, 0x0188, 0x80000000);
+ b43legacy_write32(dev, 0x018C, 0x02000000);
+ }
+ b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, 0x00004000);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
+ b43legacy_write32(dev, B43legacy_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
+
+ value32 = ssb_read32(dev->dev, SSB_TMSLOW);
+ value32 |= 0x00100000;
+ ssb_write32(dev->dev, SSB_TMSLOW, value32);
+
+ b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY,
+ dev->dev->bus->chipco.fast_pwrup_delay);
+
+ B43legacy_WARN_ON(err != 0);
+ b43legacydbg(dev->wl, "Chip initialized\n");
+out:
+ return err;
+
+err_radio_off:
+ b43legacy_radio_turn_off(dev);
+err_gpio_cleanup:
+ b43legacy_gpio_cleanup(dev);
+ goto out;
+}
+
+static void b43legacy_periodic_every120sec(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (phy->type != B43legacy_PHYTYPE_G || phy->rev < 2)
+ return;
+
+ b43legacy_mac_suspend(dev);
+ b43legacy_phy_lo_g_measure(dev);
+ b43legacy_mac_enable(dev);
+}
+
+static void b43legacy_periodic_every60sec(struct b43legacy_wldev *dev)
+{
+ b43legacy_phy_lo_mark_all_unused(dev);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) {
+ b43legacy_mac_suspend(dev);
+ b43legacy_calc_nrssi_slope(dev);
+ b43legacy_mac_enable(dev);
+ }
+}
+
+static void b43legacy_periodic_every30sec(struct b43legacy_wldev *dev)
+{
+ /* Update device statistics. */
+ b43legacy_calculate_link_quality(dev);
+}
+
+static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev)
+{
+ b43legacy_phy_xmitpower(dev); /* FIXME: unless scanning? */
+}
+
+static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev)
+{
+ bool radio_hw_enable;
+
+ /* check if radio hardware enabled status changed */
+ radio_hw_enable = b43legacy_is_hw_radio_enabled(dev);
+ if (unlikely(dev->radio_hw_enable != radio_hw_enable)) {
+ dev->radio_hw_enable = radio_hw_enable;
+ b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n",
+ (radio_hw_enable) ? "enabled" : "disabled");
+ b43legacy_leds_update(dev, 0);
+ }
+}
+
+static void do_periodic_work(struct b43legacy_wldev *dev)
+{
+ unsigned int state;
+
+ state = dev->periodic_state;
+ if (state % 120 == 0)
+ b43legacy_periodic_every120sec(dev);
+ if (state % 60 == 0)
+ b43legacy_periodic_every60sec(dev);
+ if (state % 30 == 0)
+ b43legacy_periodic_every30sec(dev);
+ if (state % 15 == 0)
+ b43legacy_periodic_every15sec(dev);
+ b43legacy_periodic_every1sec(dev);
+}
+
+/* Estimate a "Badness" value based on the periodic work
+ * state-machine state. "Badness" is worse (bigger), if the
+ * periodic work will take longer.
+ */
+static int estimate_periodic_work_badness(unsigned int state)
+{
+ int badness = 0;
+
+ if (state % 120 == 0) /* every 120 sec */
+ badness += 10;
+ if (state % 60 == 0) /* every 60 sec */
+ badness += 5;
+ if (state % 30 == 0) /* every 30 sec */
+ badness += 1;
+ if (state % 15 == 0) /* every 15 sec */
+ badness += 1;
+
+#define BADNESS_LIMIT 4
+ return badness;
+}
+
+static void b43legacy_periodic_work_handler(struct work_struct *work)
+{
+ struct b43legacy_wldev *dev =
+ container_of(work, struct b43legacy_wldev,
+ periodic_work.work);
+ unsigned long flags;
+ unsigned long delay;
+ u32 savedirqs = 0;
+ int badness;
+
+ mutex_lock(&dev->wl->mutex);
+
+ if (unlikely(b43legacy_status(dev) != B43legacy_STAT_STARTED))
+ goto out;
+ if (b43legacy_debug(dev, B43legacy_DBG_PWORK_STOP))
+ goto out_requeue;
+
+ badness = estimate_periodic_work_badness(dev->periodic_state);
+ if (badness > BADNESS_LIMIT) {
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+ /* Suspend TX as we don't want to transmit packets while
+ * we recalibrate the hardware. */
+ b43legacy_tx_suspend(dev);
+ savedirqs = b43legacy_interrupt_disable(dev,
+ B43legacy_IRQ_ALL);
+ /* Periodic work will take a long time, so we want it to
+ * be preemtible and release the spinlock. */
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+ b43legacy_synchronize_irq(dev);
+
+ do_periodic_work(dev);
+
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+ b43legacy_interrupt_enable(dev, savedirqs);
+ b43legacy_tx_resume(dev);
+ mmiowb();
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+ } else {
+ /* Take the global driver lock. This will lock any operation. */
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+
+ do_periodic_work(dev);
+
+ mmiowb();
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+ }
+ dev->periodic_state++;
+out_requeue:
+ if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST))
+ delay = msecs_to_jiffies(50);
+ else
+ delay = round_jiffies_relative(HZ);
+ queue_delayed_work(dev->wl->hw->workqueue,
+ &dev->periodic_work, delay);
+out:
+ mutex_unlock(&dev->wl->mutex);
+}
+
+static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev)
+{
+ struct delayed_work *work = &dev->periodic_work;
+
+ dev->periodic_state = 0;
+ INIT_DELAYED_WORK(work, b43legacy_periodic_work_handler);
+ queue_delayed_work(dev->wl->hw->workqueue, work, 0);
+}
+
+/* Validate access to the chip (SHM) */
+static int b43legacy_validate_chipaccess(struct b43legacy_wldev *dev)
+{
+ u32 value;
+ u32 shm_backup;
+
+ shm_backup = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0);
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, 0xAA5555AA);
+ if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0) !=
+ 0xAA5555AA)
+ goto error;
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, 0x55AAAA55);
+ if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0) !=
+ 0x55AAAA55)
+ goto error;
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, shm_backup);
+
+ value = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+ if ((value | B43legacy_MACCTL_GMODE) !=
+ (B43legacy_MACCTL_GMODE | B43legacy_MACCTL_IHR_ENABLED))
+ goto error;
+
+ value = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+ if (value)
+ goto error;
+
+ return 0;
+error:
+ b43legacyerr(dev->wl, "Failed to validate the chipaccess\n");
+ return -ENODEV;
+}
+
+static void b43legacy_security_init(struct b43legacy_wldev *dev)
+{
+ dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20;
+ B43legacy_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key));
+ dev->ktp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ 0x0056);
+ /* KTP is a word address, but we address SHM bytewise.
+ * So multiply by two.
+ */
+ dev->ktp *= 2;
+ if (dev->dev->id.revision >= 5)
+ /* Number of RCMTA address slots */
+ b43legacy_write16(dev, B43legacy_MMIO_RCMTA_COUNT,
+ dev->max_nr_keys - 8);
+}
+
+static int b43legacy_rng_read(struct hwrng *rng, u32 *data)
+{
+ struct b43legacy_wl *wl = (struct b43legacy_wl *)rng->priv;
+ unsigned long flags;
+
+ /* Don't take wl->mutex here, as it could deadlock with
+ * hwrng internal locking. It's not needed to take
+ * wl->mutex here, anyway. */
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ *data = b43legacy_read16(wl->current_dev, B43legacy_MMIO_RNG);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ return (sizeof(u16));
+}
+
+static void b43legacy_rng_exit(struct b43legacy_wl *wl)
+{
+ if (wl->rng_initialized)
+ hwrng_unregister(&wl->rng);
+}
+
+static int b43legacy_rng_init(struct b43legacy_wl *wl)
+{
+ int err;
+
+ snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
+ "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
+ wl->rng.name = wl->rng_name;
+ wl->rng.data_read = b43legacy_rng_read;
+ wl->rng.priv = (unsigned long)wl;
+ wl->rng_initialized = 1;
+ err = hwrng_register(&wl->rng);
+ if (err) {
+ wl->rng_initialized = 0;
+ b43legacyerr(wl, "Failed to register the random "
+ "number generator (%d)\n", err);
+ }
+
+ return err;
+}
+
+static int b43legacy_tx(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ int err = -ENODEV;
+ unsigned long flags;
+
+ if (unlikely(!dev))
+ goto out;
+ if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED))
+ goto out;
+ /* DMA-TX is done without a global lock. */
+ if (b43legacy_using_pio(dev)) {
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ err = b43legacy_pio_tx(dev, skb, ctl);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ } else
+ err = b43legacy_dma_tx(dev, skb, ctl);
+out:
+ if (unlikely(err))
+ return NETDEV_TX_BUSY;
+ return NETDEV_TX_OK;
+}
+
+static int b43legacy_conf_tx(struct ieee80211_hw *hw,
+ int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ return 0;
+}
+
+static int b43legacy_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ unsigned long flags;
+ int err = -ENODEV;
+
+ if (!dev)
+ goto out;
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ if (likely(b43legacy_status(dev) >= B43legacy_STAT_STARTED)) {
+ if (b43legacy_using_pio(dev))
+ b43legacy_pio_get_tx_stats(dev, stats);
+ else
+ b43legacy_dma_get_tx_stats(dev, stats);
+ err = 0;
+ }
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+out:
+ return err;
+}
+
+static int b43legacy_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ memcpy(stats, &wl->ieee_stats, sizeof(*stats));
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ return 0;
+}
+
+static const char *phymode_to_string(unsigned int phymode)
+{
+ switch (phymode) {
+ case B43legacy_PHYMODE_B:
+ return "B";
+ case B43legacy_PHYMODE_G:
+ return "G";
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ return "";
+}
+
+static int find_wldev_for_phymode(struct b43legacy_wl *wl,
+ unsigned int phymode,
+ struct b43legacy_wldev **dev,
+ bool *gmode)
+{
+ struct b43legacy_wldev *d;
+
+ list_for_each_entry(d, &wl->devlist, list) {
+ if (d->phy.possible_phymodes & phymode) {
+ /* Ok, this device supports the PHY-mode.
+ * Set the gmode bit. */
+ *gmode = 1;
+ *dev = d;
+
+ return 0;
+ }
+ }
+
+ return -ESRCH;
+}
+
+static void b43legacy_put_phy_into_reset(struct b43legacy_wldev *dev)
+{
+ struct ssb_device *sdev = dev->dev;
+ u32 tmslow;
+
+ tmslow = ssb_read32(sdev, SSB_TMSLOW);
+ tmslow &= ~B43legacy_TMSLOW_GMODE;
+ tmslow |= B43legacy_TMSLOW_PHYRESET;
+ tmslow |= SSB_TMSLOW_FGC;
+ ssb_write32(sdev, SSB_TMSLOW, tmslow);
+ msleep(1);
+
+ tmslow = ssb_read32(sdev, SSB_TMSLOW);
+ tmslow &= ~SSB_TMSLOW_FGC;
+ tmslow |= B43legacy_TMSLOW_PHYRESET;
+ ssb_write32(sdev, SSB_TMSLOW, tmslow);
+ msleep(1);
+}
+
+/* Expects wl->mutex locked */
+static int b43legacy_switch_phymode(struct b43legacy_wl *wl,
+ unsigned int new_mode)
+{
+ struct b43legacy_wldev *up_dev;
+ struct b43legacy_wldev *down_dev;
+ int err;
+ bool gmode = 0;
+ int prev_status;
+
+ err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode);
+ if (err) {
+ b43legacyerr(wl, "Could not find a device for %s-PHY mode\n",
+ phymode_to_string(new_mode));
+ return err;
+ }
+ if ((up_dev == wl->current_dev) &&
+ (!!wl->current_dev->phy.gmode == !!gmode))
+ /* This device is already running. */
+ return 0;
+ b43legacydbg(wl, "Reconfiguring PHYmode to %s-PHY\n",
+ phymode_to_string(new_mode));
+ down_dev = wl->current_dev;
+
+ prev_status = b43legacy_status(down_dev);
+ /* Shutdown the currently running core. */
+ if (prev_status >= B43legacy_STAT_STARTED)
+ b43legacy_wireless_core_stop(down_dev);
+ if (prev_status >= B43legacy_STAT_INITIALIZED)
+ b43legacy_wireless_core_exit(down_dev);
+
+ if (down_dev != up_dev)
+ /* We switch to a different core, so we put PHY into
+ * RESET on the old core. */
+ b43legacy_put_phy_into_reset(down_dev);
+
+ /* Now start the new core. */
+ up_dev->phy.gmode = gmode;
+ if (prev_status >= B43legacy_STAT_INITIALIZED) {
+ err = b43legacy_wireless_core_init(up_dev);
+ if (err) {
+ b43legacyerr(wl, "Fatal: Could not initialize device"
+ " for newly selected %s-PHY mode\n",
+ phymode_to_string(new_mode));
+ goto init_failure;
+ }
+ }
+ if (prev_status >= B43legacy_STAT_STARTED) {
+ err = b43legacy_wireless_core_start(up_dev);
+ if (err) {
+ b43legacyerr(wl, "Fatal: Coult not start device for "
+ "newly selected %s-PHY mode\n",
+ phymode_to_string(new_mode));
+ b43legacy_wireless_core_exit(up_dev);
+ goto init_failure;
+ }
+ }
+ B43legacy_WARN_ON(b43legacy_status(up_dev) != prev_status);
+
+ b43legacy_shm_write32(up_dev, B43legacy_SHM_SHARED, 0x003E, 0);
+
+ wl->current_dev = up_dev;
+
+ return 0;
+init_failure:
+ /* Whoops, failed to init the new core. No core is operating now. */
+ wl->current_dev = NULL;
+ return err;
+}
+
+static int b43legacy_antenna_from_ieee80211(u8 antenna)
+{
+ switch (antenna) {
+ case 0: /* default/diversity */
+ return B43legacy_ANTENNA_DEFAULT;
+ case 1: /* Antenna 0 */
+ return B43legacy_ANTENNA0;
+ case 2: /* Antenna 1 */
+ return B43legacy_ANTENNA1;
+ default:
+ return B43legacy_ANTENNA_DEFAULT;
+ }
+}
+
+static int b43legacy_dev_config(struct ieee80211_hw *hw,
+ struct ieee80211_conf *conf)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev;
+ struct b43legacy_phy *phy;
+ unsigned long flags;
+ unsigned int new_phymode = 0xFFFF;
+ int antenna_tx;
+ int antenna_rx;
+ int err = 0;
+ u32 savedirqs;
+
+ antenna_tx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_tx);
+ antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx);
+
+ mutex_lock(&wl->mutex);
+
+ /* Switch the PHY mode (if necessary). */
+ switch (conf->phymode) {
+ case MODE_IEEE80211B:
+ new_phymode = B43legacy_PHYMODE_B;
+ break;
+ case MODE_IEEE80211G:
+ new_phymode = B43legacy_PHYMODE_G;
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+ err = b43legacy_switch_phymode(wl, new_phymode);
+ if (err)
+ goto out_unlock_mutex;
+ dev = wl->current_dev;
+ phy = &dev->phy;
+
+ /* Disable IRQs while reconfiguring the device.
+ * This makes it possible to drop the spinlock throughout
+ * the reconfiguration process. */
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ if (b43legacy_status(dev) < B43legacy_STAT_STARTED) {
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ goto out_unlock_mutex;
+ }
+ savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ b43legacy_synchronize_irq(dev);
+
+ /* Switch to the requested channel.
+ * The firmware takes care of races with the TX handler. */
+ if (conf->channel_val != phy->channel)
+ b43legacy_radio_selectchannel(dev, conf->channel_val, 0);
+
+ /* Enable/Disable ShortSlot timing. */
+ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME))
+ != dev->short_slot) {
+ B43legacy_WARN_ON(phy->type != B43legacy_PHYTYPE_G);
+ if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
+ b43legacy_short_slot_timing_enable(dev);
+ else
+ b43legacy_short_slot_timing_disable(dev);
+ }
+
+ /* Adjust the desired TX power level. */
+ if (conf->power_level != 0) {
+ if (conf->power_level != phy->power_level) {
+ phy->power_level = conf->power_level;
+ b43legacy_phy_xmitpower(dev);
+ }
+ }
+
+ /* Antennas for RX and management frame TX. */
+ b43legacy_mgmtframe_txantenna(dev, antenna_tx);
+
+ /* Update templates for AP mode. */
+ if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+ b43legacy_set_beacon_int(dev, conf->beacon_int);
+
+
+ if (!!conf->radio_enabled != phy->radio_on) {
+ if (conf->radio_enabled) {
+ b43legacy_radio_turn_on(dev);
+ b43legacyinfo(dev->wl, "Radio turned on by software\n");
+ if (!dev->radio_hw_enable)
+ b43legacyinfo(dev->wl, "The hardware RF-kill"
+ " button still turns the radio"
+ " physically off. Press the"
+ " button to turn it on.\n");
+ } else {
+ b43legacy_radio_turn_off(dev);
+ b43legacyinfo(dev->wl, "Radio turned off by"
+ " software\n");
+ }
+ }
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43legacy_interrupt_enable(dev, savedirqs);
+ mmiowb();
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+out_unlock_mutex:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+static int b43legacy_dev_set_key(struct ieee80211_hw *hw,
+ enum set_key_cmd cmd,
+ const u8 *local_addr, const u8 *addr,
+ struct ieee80211_key_conf *key)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ unsigned long flags;
+ int err = -EOPNOTSUPP;
+ DECLARE_MAC_BUF(mac);
+
+ if (!dev)
+ return -ENODEV;
+ mutex_lock(&wl->mutex);
+ spin_lock_irqsave(&wl->irq_lock, flags);
+
+ if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
+ err = -ENODEV;
+ }
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ mutex_unlock(&wl->mutex);
+ b43legacydbg(wl, "Using software based encryption for "
+ "mac: %s\n", print_mac(mac, addr));
+ return err;
+}
+
+static void b43legacy_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed,
+ unsigned int *fflags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ unsigned long flags;
+
+ if (!dev) {
+ *fflags = 0;
+ return;
+ }
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ *fflags &= FIF_PROMISC_IN_BSS |
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_BCN_PRBRESP_PROMISC;
+
+ changed &= FIF_PROMISC_IN_BSS |
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_BCN_PRBRESP_PROMISC;
+
+ wl->filter_flags = *fflags;
+
+ if (changed && b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED)
+ b43legacy_adjust_opmode(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+}
+
+static int b43legacy_config_interface(struct ieee80211_hw *hw,
+ int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ unsigned long flags;
+
+ if (!dev)
+ return -ENODEV;
+ mutex_lock(&wl->mutex);
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ B43legacy_WARN_ON(wl->if_id != if_id);
+ if (conf->bssid)
+ memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+ else
+ memset(wl->bssid, 0, ETH_ALEN);
+ if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
+ if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
+ B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+ b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
+ if (conf->beacon)
+ b43legacy_refresh_templates(dev, conf->beacon);
+ }
+ b43legacy_write_mac_bssid_templates(dev);
+ }
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ mutex_unlock(&wl->mutex);
+
+ return 0;
+}
+
+/* Locking: wl->mutex */
+static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_wl *wl = dev->wl;
+ unsigned long flags;
+
+ if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
+ return;
+
+ /* Disable and sync interrupts. We must do this before than
+ * setting the status to INITIALIZED, as the interrupt handler
+ * won't care about IRQs then. */
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ dev->irq_savedstate = b43legacy_interrupt_disable(dev,
+ B43legacy_IRQ_ALL);
+ b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+ b43legacy_synchronize_irq(dev);
+
+ b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
+
+ mutex_unlock(&wl->mutex);
+ /* Must unlock as it would otherwise deadlock. No races here.
+ * Cancel the possibly running self-rearming periodic work. */
+ cancel_delayed_work_sync(&dev->periodic_work);
+ mutex_lock(&wl->mutex);
+
+ ieee80211_stop_queues(wl->hw); /* FIXME this could cause a deadlock */
+
+ b43legacy_mac_suspend(dev);
+ free_irq(dev->dev->irq, dev);
+ b43legacydbg(wl, "Wireless interface stopped\n");
+}
+
+/* Locking: wl->mutex */
+static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev)
+{
+ int err;
+
+ B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_INITIALIZED);
+
+ drain_txstatus_queue(dev);
+ err = request_irq(dev->dev->irq, b43legacy_interrupt_handler,
+ IRQF_SHARED, KBUILD_MODNAME, dev);
+ if (err) {
+ b43legacyerr(dev->wl, "Cannot request IRQ-%d\n",
+ dev->dev->irq);
+ goto out;
+ }
+ /* We are ready to run. */
+ b43legacy_set_status(dev, B43legacy_STAT_STARTED);
+
+ /* Start data flow (TX/RX) */
+ b43legacy_mac_enable(dev);
+ b43legacy_interrupt_enable(dev, dev->irq_savedstate);
+ ieee80211_start_queues(dev->wl->hw);
+
+ /* Start maintenance work */
+ b43legacy_periodic_tasks_setup(dev);
+
+ b43legacydbg(dev->wl, "Wireless interface started\n");
+out:
+ return err;
+}
+
+/* Get PHY and RADIO versioning numbers */
+static int b43legacy_phy_versioning(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u32 tmp;
+ u8 analog_type;
+ u8 phy_type;
+ u8 phy_rev;
+ u16 radio_manuf;
+ u16 radio_ver;
+ u16 radio_rev;
+ int unsupported = 0;
+
+ /* Get PHY versioning */
+ tmp = b43legacy_read16(dev, B43legacy_MMIO_PHY_VER);
+ analog_type = (tmp & B43legacy_PHYVER_ANALOG)
+ >> B43legacy_PHYVER_ANALOG_SHIFT;
+ phy_type = (tmp & B43legacy_PHYVER_TYPE) >> B43legacy_PHYVER_TYPE_SHIFT;
+ phy_rev = (tmp & B43legacy_PHYVER_VERSION);
+ switch (phy_type) {
+ case B43legacy_PHYTYPE_B:
+ if (phy_rev != 2 && phy_rev != 4
+ && phy_rev != 6 && phy_rev != 7)
+ unsupported = 1;
+ break;
+ case B43legacy_PHYTYPE_G:
+ if (phy_rev > 8)
+ unsupported = 1;
+ break;
+ default:
+ unsupported = 1;
+ };
+ if (unsupported) {
+ b43legacyerr(dev->wl, "FOUND UNSUPPORTED PHY "
+ "(Analog %u, Type %u, Revision %u)\n",
+ analog_type, phy_type, phy_rev);
+ return -EOPNOTSUPP;
+ }
+ b43legacydbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n",
+ analog_type, phy_type, phy_rev);
+
+
+ /* Get RADIO versioning */
+ if (dev->dev->bus->chip_id == 0x4317) {
+ if (dev->dev->bus->chip_rev == 0)
+ tmp = 0x3205017F;
+ else if (dev->dev->bus->chip_rev == 1)
+ tmp = 0x4205017F;
+ else
+ tmp = 0x5205017F;
+ } else {
+ b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL,
+ B43legacy_RADIOCTL_ID);
+ tmp = b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_HIGH);
+ tmp <<= 16;
+ b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL,
+ B43legacy_RADIOCTL_ID);
+ tmp |= b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);
+ }
+ radio_manuf = (tmp & 0x00000FFF);
+ radio_ver = (tmp & 0x0FFFF000) >> 12;
+ radio_rev = (tmp & 0xF0000000) >> 28;
+ switch (phy_type) {
+ case B43legacy_PHYTYPE_B:
+ if ((radio_ver & 0xFFF0) != 0x2050)
+ unsupported = 1;
+ break;
+ case B43legacy_PHYTYPE_G:
+ if (radio_ver != 0x2050)
+ unsupported = 1;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ if (unsupported) {
+ b43legacyerr(dev->wl, "FOUND UNSUPPORTED RADIO "
+ "(Manuf 0x%X, Version 0x%X, Revision %u)\n",
+ radio_manuf, radio_ver, radio_rev);
+ return -EOPNOTSUPP;
+ }
+ b43legacydbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X,"
+ " Revision %u\n", radio_manuf, radio_ver, radio_rev);
+
+
+ phy->radio_manuf = radio_manuf;
+ phy->radio_ver = radio_ver;
+ phy->radio_rev = radio_rev;
+
+ phy->analog = analog_type;
+ phy->type = phy_type;
+ phy->rev = phy_rev;
+
+ return 0;
+}
+
+static void setup_struct_phy_for_init(struct b43legacy_wldev *dev,
+ struct b43legacy_phy *phy)
+{
+ struct b43legacy_lopair *lo;
+ int i;
+
+ memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
+ memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
+
+ /* Flags */
+ phy->locked = 0;
+ /* Assume the radio is enabled. If it's not enabled, the state will
+ * immediately get fixed on the first periodic work run. */
+ dev->radio_hw_enable = 1;
+
+ phy->savedpctlreg = 0xFFFF;
+ phy->aci_enable = 0;
+ phy->aci_wlan_automatic = 0;
+ phy->aci_hw_rssi = 0;
+
+ lo = phy->_lo_pairs;
+ if (lo)
+ memset(lo, 0, sizeof(struct b43legacy_lopair) *
+ B43legacy_LO_COUNT);
+ phy->max_lb_gain = 0;
+ phy->trsw_rx_gain = 0;
+
+ /* Set default attenuation values. */
+ phy->bbatt = b43legacy_default_baseband_attenuation(dev);
+ phy->rfatt = b43legacy_default_radio_attenuation(dev);
+ phy->txctl1 = b43legacy_default_txctl1(dev);
+ phy->txpwr_offset = 0;
+
+ /* NRSSI */
+ phy->nrssislope = 0;
+ for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
+ phy->nrssi[i] = -1000;
+ for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
+ phy->nrssi_lt[i] = i;
+
+ phy->lofcal = 0xFFFF;
+ phy->initval = 0xFFFF;
+
+ spin_lock_init(&phy->lock);
+ phy->interfmode = B43legacy_INTERFMODE_NONE;
+ phy->channel = 0xFF;
+}
+
+static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev)
+{
+ /* Flags */
+ dev->reg124_set_0x4 = 0;
+
+ /* Stats */
+ memset(&dev->stats, 0, sizeof(dev->stats));
+
+ setup_struct_phy_for_init(dev, &dev->phy);
+
+ /* IRQ related flags */
+ dev->irq_reason = 0;
+ memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
+ dev->irq_savedstate = B43legacy_IRQ_MASKTEMPLATE;
+
+ dev->mac_suspended = 1;
+
+ /* Noise calculation context */
+ memset(&dev->noisecalc, 0, sizeof(dev->noisecalc));
+}
+
+static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev)
+{
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ struct ssb_bus *bus = dev->dev->bus;
+ u32 tmp;
+
+ if (bus->pcicore.dev &&
+ bus->pcicore.dev->id.coreid == SSB_DEV_PCI &&
+ bus->pcicore.dev->id.revision <= 5) {
+ /* IMCFGLO timeouts workaround. */
+ tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
+ tmp &= ~SSB_IMCFGLO_REQTO;
+ tmp &= ~SSB_IMCFGLO_SERTO;
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_PCI:
+ case SSB_BUSTYPE_PCMCIA:
+ tmp |= 0x32;
+ break;
+ case SSB_BUSTYPE_SSB:
+ tmp |= 0x53;
+ break;
+ }
+ ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
+ }
+#endif /* CONFIG_SSB_DRIVER_PCICORE */
+}
+
+/* Shutdown a wireless core */
+/* Locking: wl->mutex */
+static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_wl *wl = dev->wl;
+ struct b43legacy_phy *phy = &dev->phy;
+
+ B43legacy_WARN_ON(b43legacy_status(dev) > B43legacy_STAT_INITIALIZED);
+ if (b43legacy_status(dev) != B43legacy_STAT_INITIALIZED)
+ return;
+ b43legacy_set_status(dev, B43legacy_STAT_UNINIT);
+
+ mutex_unlock(&wl->mutex);
+ /* Must unlock as it would otherwise deadlock. No races here.
+ * Cancel possibly pending workqueues. */
+ cancel_work_sync(&dev->restart_work);
+ mutex_lock(&wl->mutex);
+
+ b43legacy_rng_exit(dev->wl);
+ b43legacy_pio_free(dev);
+ b43legacy_dma_free(dev);
+ b43legacy_chip_exit(dev);
+ b43legacy_radio_turn_off(dev);
+ b43legacy_switch_analog(dev, 0);
+ if (phy->dyn_tssi_tbl)
+ kfree(phy->tssi2dbm);
+ kfree(phy->lo_control);
+ phy->lo_control = NULL;
+ ssb_device_disable(dev->dev, 0);
+ ssb_bus_may_powerdown(dev->dev->bus);
+}
+
+static void prepare_phy_data_for_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ int i;
+
+ /* Set default attenuation values. */
+ phy->bbatt = b43legacy_default_baseband_attenuation(dev);
+ phy->rfatt = b43legacy_default_radio_attenuation(dev);
+ phy->txctl1 = b43legacy_default_txctl1(dev);
+ phy->txctl2 = 0xFFFF;
+ phy->txpwr_offset = 0;
+
+ /* NRSSI */
+ phy->nrssislope = 0;
+ for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
+ phy->nrssi[i] = -1000;
+ for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
+ phy->nrssi_lt[i] = i;
+
+ phy->lofcal = 0xFFFF;
+ phy->initval = 0xFFFF;
+
+ phy->aci_enable = 0;
+ phy->aci_wlan_automatic = 0;
+ phy->aci_hw_rssi = 0;
+
+ phy->antenna_diversity = 0xFFFF;
+ memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
+ memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
+
+ /* Flags */
+ phy->calibrated = 0;
+ phy->locked = 0;
+
+ if (phy->_lo_pairs)
+ memset(phy->_lo_pairs, 0,
+ sizeof(struct b43legacy_lopair) * B43legacy_LO_COUNT);
+ memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain));
+}
+
+/* Initialize a wireless core */
+static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_wl *wl = dev->wl;
+ struct ssb_bus *bus = dev->dev->bus;
+ struct b43legacy_phy *phy = &dev->phy;
+ struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+ int err;
+ u32 hf;
+ u32 tmp;
+
+ B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_UNINIT);
+
+ err = ssb_bus_powerup(bus, 0);
+ if (err)
+ goto out;
+ if (!ssb_device_is_enabled(dev->dev)) {
+ tmp = phy->gmode ? B43legacy_TMSLOW_GMODE : 0;
+ b43legacy_wireless_core_reset(dev, tmp);
+ }
+
+ if ((phy->type == B43legacy_PHYTYPE_B) ||
+ (phy->type == B43legacy_PHYTYPE_G)) {
+ phy->_lo_pairs = kzalloc(sizeof(struct b43legacy_lopair)
+ * B43legacy_LO_COUNT,
+ GFP_KERNEL);
+ if (!phy->_lo_pairs)
+ return -ENOMEM;
+ }
+ setup_struct_wldev_for_init(dev);
+
+ err = b43legacy_phy_init_tssi2dbm_table(dev);
+ if (err)
+ goto err_kfree_lo_control;
+
+ /* Enable IRQ routing to this device. */
+ ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
+
+ b43legacy_imcfglo_timeouts_workaround(dev);
+ prepare_phy_data_for_init(dev);
+ b43legacy_phy_calibrate(dev);
+ err = b43legacy_chip_init(dev);
+ if (err)
+ goto err_kfree_tssitbl;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_WLCOREREV,
+ dev->dev->id.revision);
+ hf = b43legacy_hf_read(dev);
+ if (phy->type == B43legacy_PHYTYPE_G) {
+ hf |= B43legacy_HF_SYMW;
+ if (phy->rev == 1)
+ hf |= B43legacy_HF_GDCW;
+ if (sprom->r1.boardflags_lo & B43legacy_BFL_PACTRL)
+ hf |= B43legacy_HF_OFDMPABOOST;
+ } else if (phy->type == B43legacy_PHYTYPE_B) {
+ hf |= B43legacy_HF_SYMW;
+ if (phy->rev >= 2 && phy->radio_ver == 0x2050)
+ hf &= ~B43legacy_HF_GDCW;
+ }
+ b43legacy_hf_write(dev, hf);
+
+ /* Short/Long Retry Limit.
+ * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
+ * the chip-internal counter.
+ */
+ tmp = limit_value(modparam_short_retry, 0, 0xF);
+ b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+ 0x0006, tmp);
+ tmp = limit_value(modparam_long_retry, 0, 0xF);
+ b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+ 0x0007, tmp);
+
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ 0x0044, 3);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ 0x0046, 2);
+
+ /* Disable sending probe responses from firmware.
+ * Setting the MaxTime to one usec will always trigger
+ * a timeout, so we never send any probe resp.
+ * A timeout of zero is infinite. */
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+ B43legacy_SHM_SH_PRMAXTIME, 1);
+
+ b43legacy_rate_memory_init(dev);
+
+ /* Minimum Contention Window */
+ if (phy->type == B43legacy_PHYTYPE_B)
+ b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+ 0x0003, 31);
+ else
+ b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+ 0x0003, 15);
+ /* Maximum Contention Window */
+ b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+ 0x0004, 1023);
+
+ do {
+ if (b43legacy_using_pio(dev))
+ err = b43legacy_pio_init(dev);
+ else {
+ err = b43legacy_dma_init(dev);
+ if (!err)
+ b43legacy_qos_init(dev);
+ }
+ } while (err == -EAGAIN);
+ if (err)
+ goto err_chip_exit;
+
+ b43legacy_write16(dev, 0x0612, 0x0050);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0416, 0x0050);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4);
+
+ ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
+ memset(wl->bssid, 0, ETH_ALEN);
+ memset(wl->mac_addr, 0, ETH_ALEN);
+ b43legacy_upload_card_macaddress(dev);
+ b43legacy_security_init(dev);
+ b43legacy_rng_init(wl);
+
+ b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
+
+out:
+ return err;
+
+err_chip_exit:
+ b43legacy_chip_exit(dev);
+err_kfree_tssitbl:
+ if (phy->dyn_tssi_tbl)
+ kfree(phy->tssi2dbm);
+err_kfree_lo_control:
+ kfree(phy->lo_control);
+ phy->lo_control = NULL;
+ ssb_bus_may_powerdown(bus);
+ B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_UNINIT);
+ return err;
+}
+
+static int b43legacy_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev;
+ unsigned long flags;
+ int err = -EOPNOTSUPP;
+
+ /* TODO: allow WDS/AP devices to coexist */
+
+ if (conf->type != IEEE80211_IF_TYPE_AP &&
+ conf->type != IEEE80211_IF_TYPE_STA &&
+ conf->type != IEEE80211_IF_TYPE_WDS &&
+ conf->type != IEEE80211_IF_TYPE_IBSS)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&wl->mutex);
+ if (wl->operating)
+ goto out_mutex_unlock;
+
+ b43legacydbg(wl, "Adding Interface type %d\n", conf->type);
+
+ dev = wl->current_dev;
+ wl->operating = 1;
+ wl->if_id = conf->if_id;
+ wl->if_type = conf->type;
+ memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43legacy_adjust_opmode(dev);
+ b43legacy_upload_card_macaddress(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ err = 0;
+ out_mutex_unlock:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+static void b43legacy_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ unsigned long flags;
+
+ b43legacydbg(wl, "Removing Interface type %d\n", conf->type);
+
+ mutex_lock(&wl->mutex);
+
+ B43legacy_WARN_ON(!wl->operating);
+ B43legacy_WARN_ON(wl->if_id != conf->if_id);
+
+ wl->operating = 0;
+
+ spin_lock_irqsave(&wl->irq_lock, flags);
+ b43legacy_adjust_opmode(dev);
+ memset(wl->mac_addr, 0, ETH_ALEN);
+ b43legacy_upload_card_macaddress(dev);
+ spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+ mutex_unlock(&wl->mutex);
+}
+
+static int b43legacy_start(struct ieee80211_hw *hw)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+ int did_init = 0;
+ int err = 0;
+
+ mutex_lock(&wl->mutex);
+
+ if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
+ err = b43legacy_wireless_core_init(dev);
+ if (err)
+ goto out_mutex_unlock;
+ did_init = 1;
+ }
+
+ if (b43legacy_status(dev) < B43legacy_STAT_STARTED) {
+ err = b43legacy_wireless_core_start(dev);
+ if (err) {
+ if (did_init)
+ b43legacy_wireless_core_exit(dev);
+ goto out_mutex_unlock;
+ }
+ }
+
+out_mutex_unlock:
+ mutex_unlock(&wl->mutex);
+
+ return err;
+}
+
+static void b43legacy_stop(struct ieee80211_hw *hw)
+{
+ struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+ struct b43legacy_wldev *dev = wl->current_dev;
+
+ mutex_lock(&wl->mutex);
+ if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
+ b43legacy_wireless_core_stop(dev);
+ b43legacy_wireless_core_exit(dev);
+ mutex_unlock(&wl->mutex);
+}
+
+
+static const struct ieee80211_ops b43legacy_hw_ops = {
+ .tx = b43legacy_tx,
+ .conf_tx = b43legacy_conf_tx,
+ .add_interface = b43legacy_add_interface,
+ .remove_interface = b43legacy_remove_interface,
+ .config = b43legacy_dev_config,
+ .config_interface = b43legacy_config_interface,
+ .set_key = b43legacy_dev_set_key,
+ .configure_filter = b43legacy_configure_filter,
+ .get_stats = b43legacy_get_stats,
+ .get_tx_stats = b43legacy_get_tx_stats,
+ .start = b43legacy_start,
+ .stop = b43legacy_stop,
+};
+
+/* Hard-reset the chip. Do not call this directly.
+ * Use b43legacy_controller_restart()
+ */
+static void b43legacy_chip_reset(struct work_struct *work)
+{
+ struct b43legacy_wldev *dev =
+ container_of(work, struct b43legacy_wldev, restart_work);
+ struct b43legacy_wl *wl = dev->wl;
+ int err = 0;
+ int prev_status;
+
+ mutex_lock(&wl->mutex);
+
+ prev_status = b43legacy_status(dev);
+ /* Bring the device down... */
+ if (prev_status >= B43legacy_STAT_STARTED)
+ b43legacy_wireless_core_stop(dev);
+ if (prev_status >= B43legacy_STAT_INITIALIZED)
+ b43legacy_wireless_core_exit(dev);
+
+ /* ...and up again. */
+ if (prev_status >= B43legacy_STAT_INITIALIZED) {
+ err = b43legacy_wireless_core_init(dev);
+ if (err)
+ goto out;
+ }
+ if (prev_status >= B43legacy_STAT_STARTED) {
+ err = b43legacy_wireless_core_start(dev);
+ if (err) {
+ b43legacy_wireless_core_exit(dev);
+ goto out;
+ }
+ }
+out:
+ mutex_unlock(&wl->mutex);
+ if (err)
+ b43legacyerr(wl, "Controller restart FAILED\n");
+ else
+ b43legacyinfo(wl, "Controller restarted\n");
+}
+
+static int b43legacy_setup_modes(struct b43legacy_wldev *dev,
+ int have_bphy,
+ int have_gphy)
+{
+ struct ieee80211_hw *hw = dev->wl->hw;
+ struct ieee80211_hw_mode *mode;
+ struct b43legacy_phy *phy = &dev->phy;
+ int cnt = 0;
+ int err;
+
+ phy->possible_phymodes = 0;
+ for (; 1; cnt++) {
+ if (have_bphy) {
+ B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES);
+ mode = &phy->hwmodes[cnt];
+
+ mode->mode = MODE_IEEE80211B;
+ mode->num_channels = b43legacy_bg_chantable_size;
+ mode->channels = b43legacy_bg_chantable;
+ mode->num_rates = b43legacy_b_ratetable_size;
+ mode->rates = b43legacy_b_ratetable;
+ err = ieee80211_register_hwmode(hw, mode);
+ if (err)
+ return err;
+
+ phy->possible_phymodes |= B43legacy_PHYMODE_B;
+ have_bphy = 0;
+ continue;
+ }
+ if (have_gphy) {
+ B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES);
+ mode = &phy->hwmodes[cnt];
+
+ mode->mode = MODE_IEEE80211G;
+ mode->num_channels = b43legacy_bg_chantable_size;
+ mode->channels = b43legacy_bg_chantable;
+ mode->num_rates = b43legacy_g_ratetable_size;
+ mode->rates = b43legacy_g_ratetable;
+ err = ieee80211_register_hwmode(hw, mode);
+ if (err)
+ return err;
+
+ phy->possible_phymodes |= B43legacy_PHYMODE_G;
+ have_gphy = 0;
+ continue;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static void b43legacy_wireless_core_detach(struct b43legacy_wldev *dev)
+{
+ /* We release firmware that late to not be required to re-request
+ * is all the time when we reinit the core. */
+ b43legacy_release_firmware(dev);
+}
+
+static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_wl *wl = dev->wl;
+ struct ssb_bus *bus = dev->dev->bus;
+ struct pci_dev *pdev = bus->host_pci;
+ int err;
+ int have_bphy = 0;
+ int have_gphy = 0;
+ u32 tmp;
+
+ /* Do NOT do any device initialization here.
+ * Do it in wireless_core_init() instead.
+ * This function is for gathering basic information about the HW, only.
+ * Also some structs may be set up here. But most likely you want to
+ * have that in core_init(), too.
+ */
+
+ err = ssb_bus_powerup(bus, 0);
+ if (err) {
+ b43legacyerr(wl, "Bus powerup failed\n");
+ goto out;
+ }
+ /* Get the PHY type. */
+ if (dev->dev->id.revision >= 5) {
+ u32 tmshigh;
+
+ tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+ have_gphy = !!(tmshigh & B43legacy_TMSHIGH_GPHY);
+ if (!have_gphy)
+ have_bphy = 1;
+ } else if (dev->dev->id.revision == 4)
+ have_gphy = 1;
+ else
+ have_bphy = 1;
+
+ /* Initialize LEDs structs. */
+ err = b43legacy_leds_init(dev);
+ if (err)
+ goto err_powerdown;
+
+ dev->phy.gmode = (have_gphy || have_bphy);
+ tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
+ b43legacy_wireless_core_reset(dev, tmp);
+
+ err = b43legacy_phy_versioning(dev);
+ if (err)
+ goto err_leds_exit;
+ /* Check if this device supports multiband. */
+ if (!pdev ||
+ (pdev->device != 0x4312 &&
+ pdev->device != 0x4319 &&
+ pdev->device != 0x4324)) {
+ /* No multiband support. */
+ have_bphy = 0;
+ have_gphy = 0;
+ switch (dev->phy.type) {
+ case B43legacy_PHYTYPE_B:
+ have_bphy = 1;
+ break;
+ case B43legacy_PHYTYPE_G:
+ have_gphy = 1;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ }
+ dev->phy.gmode = (have_gphy || have_bphy);
+ tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
+ b43legacy_wireless_core_reset(dev, tmp);
+
+ err = b43legacy_validate_chipaccess(dev);
+ if (err)
+ goto err_leds_exit;
+ err = b43legacy_setup_modes(dev, have_bphy, have_gphy);
+ if (err)
+ goto err_leds_exit;
+
+ /* Now set some default "current_dev" */
+ if (!wl->current_dev)
+ wl->current_dev = dev;
+ INIT_WORK(&dev->restart_work, b43legacy_chip_reset);
+
+ b43legacy_radio_turn_off(dev);
+ b43legacy_switch_analog(dev, 0);
+ ssb_device_disable(dev->dev, 0);
+ ssb_bus_may_powerdown(bus);
+
+out:
+ return err;
+
+err_leds_exit:
+ b43legacy_leds_exit(dev);
+err_powerdown:
+ ssb_bus_may_powerdown(bus);
+ return err;
+}
+
+static void b43legacy_one_core_detach(struct ssb_device *dev)
+{
+ struct b43legacy_wldev *wldev;
+ struct b43legacy_wl *wl;
+
+ wldev = ssb_get_drvdata(dev);
+ wl = wldev->wl;
+ cancel_work_sync(&wldev->restart_work);
+ b43legacy_debugfs_remove_device(wldev);
+ b43legacy_wireless_core_detach(wldev);
+ list_del(&wldev->list);
+ wl->nr_devs--;
+ ssb_set_drvdata(dev, NULL);
+ kfree(wldev);
+}
+
+static int b43legacy_one_core_attach(struct ssb_device *dev,
+ struct b43legacy_wl *wl)
+{
+ struct b43legacy_wldev *wldev;
+ struct pci_dev *pdev;
+ int err = -ENOMEM;
+
+ if (!list_empty(&wl->devlist)) {
+ /* We are not the first core on this chip. */
+ pdev = dev->bus->host_pci;
+ /* Only special chips support more than one wireless
+ * core, although some of the other chips have more than
+ * one wireless core as well. Check for this and
+ * bail out early.
+ */
+ if (!pdev ||
+ ((pdev->device != 0x4321) &&
+ (pdev->device != 0x4313) &&
+ (pdev->device != 0x431A))) {
+ b43legacydbg(wl, "Ignoring unconnected 802.11 core\n");
+ return -ENODEV;
+ }
+ }
+
+ wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
+ if (!wldev)
+ goto out;
+
+ wldev->dev = dev;
+ wldev->wl = wl;
+ b43legacy_set_status(wldev, B43legacy_STAT_UNINIT);
+ wldev->bad_frames_preempt = modparam_bad_frames_preempt;
+ tasklet_init(&wldev->isr_tasklet,
+ (void (*)(unsigned long))b43legacy_interrupt_tasklet,
+ (unsigned long)wldev);
+ if (modparam_pio)
+ wldev->__using_pio = 1;
+ INIT_LIST_HEAD(&wldev->list);
+
+ err = b43legacy_wireless_core_attach(wldev);
+ if (err)
+ goto err_kfree_wldev;
+
+ list_add(&wldev->list, &wl->devlist);
+ wl->nr_devs++;
+ ssb_set_drvdata(dev, wldev);
+ b43legacy_debugfs_add_device(wldev);
+out:
+ return err;
+
+err_kfree_wldev:
+ kfree(wldev);
+ return err;
+}
+
+static void b43legacy_sprom_fixup(struct ssb_bus *bus)
+{
+ /* boardflags workarounds */
+ if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
+ bus->boardinfo.type == 0x4E &&
+ bus->boardinfo.rev > 0x40)
+ bus->sprom.r1.boardflags_lo |= B43legacy_BFL_PACTRL;
+
+ /* Convert Antennagain values to Q5.2 */
+ if (bus->sprom.r1.antenna_gain_bg == 0xFF)
+ bus->sprom.r1.antenna_gain_bg = 2; /* if unset, use 2 dBm */
+ bus->sprom.r1.antenna_gain_bg <<= 2;
+}
+
+static void b43legacy_wireless_exit(struct ssb_device *dev,
+ struct b43legacy_wl *wl)
+{
+ struct ieee80211_hw *hw = wl->hw;
+
+ ssb_set_devtypedata(dev, NULL);
+ ieee80211_free_hw(hw);
+}
+
+static int b43legacy_wireless_init(struct ssb_device *dev)
+{
+ struct ssb_sprom *sprom = &dev->bus->sprom;
+ struct ieee80211_hw *hw;
+ struct b43legacy_wl *wl;
+ int err = -ENOMEM;
+
+ b43legacy_sprom_fixup(dev->bus);
+
+ hw = ieee80211_alloc_hw(sizeof(*wl), &b43legacy_hw_ops);
+ if (!hw) {
+ b43legacyerr(NULL, "Could not allocate ieee80211 device\n");
+ goto out;
+ }
+
+ /* fill hw info */
+ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+ IEEE80211_HW_RX_INCLUDES_FCS;
+ hw->max_signal = 100;
+ hw->max_rssi = -110;
+ hw->max_noise = -110;
+ hw->queues = 1; /* FIXME: hardware has more queues */
+ SET_IEEE80211_DEV(hw, dev->dev);
+ if (is_valid_ether_addr(sprom->r1.et1mac))
+ SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);
+ else
+ SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac);
+
+ /* Get and initialize struct b43legacy_wl */
+ wl = hw_to_b43legacy_wl(hw);
+ memset(wl, 0, sizeof(*wl));
+ wl->hw = hw;
+ spin_lock_init(&wl->irq_lock);
+ spin_lock_init(&wl->leds_lock);
+ mutex_init(&wl->mutex);
+ INIT_LIST_HEAD(&wl->devlist);
+
+ ssb_set_devtypedata(dev, wl);
+ b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
+ err = 0;
+out:
+ return err;
+}
+
+static int b43legacy_probe(struct ssb_device *dev,
+ const struct ssb_device_id *id)
+{
+ struct b43legacy_wl *wl;
+ int err;
+ int first = 0;
+
+ wl = ssb_get_devtypedata(dev);
+ if (!wl) {
+ /* Probing the first core - setup common struct b43legacy_wl */
+ first = 1;
+ err = b43legacy_wireless_init(dev);
+ if (err)
+ goto out;
+ wl = ssb_get_devtypedata(dev);
+ B43legacy_WARN_ON(!wl);
+ }
+ err = b43legacy_one_core_attach(dev, wl);
+ if (err)
+ goto err_wireless_exit;
+
+ if (first) {
+ err = ieee80211_register_hw(wl->hw);
+ if (err)
+ goto err_one_core_detach;
+ }
+
+out:
+ return err;
+
+err_one_core_detach:
+ b43legacy_one_core_detach(dev);
+err_wireless_exit:
+ if (first)
+ b43legacy_wireless_exit(dev, wl);
+ return err;
+}
+
+static void b43legacy_remove(struct ssb_device *dev)
+{
+ struct b43legacy_wl *wl = ssb_get_devtypedata(dev);
+ struct b43legacy_wldev *wldev = ssb_get_drvdata(dev);
+
+ B43legacy_WARN_ON(!wl);
+ if (wl->current_dev == wldev)
+ ieee80211_unregister_hw(wl->hw);
+
+ b43legacy_one_core_detach(dev);
+
+ if (list_empty(&wl->devlist))
+ /* Last core on the chip unregistered.
+ * We can destroy common struct b43legacy_wl.
+ */
+ b43legacy_wireless_exit(dev, wl);
+}
+
+/* Perform a hardware reset. This can be called from any context. */
+void b43legacy_controller_restart(struct b43legacy_wldev *dev,
+ const char *reason)
+{
+ /* Must avoid requeueing, if we are in shutdown. */
+ if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
+ return;
+ b43legacyinfo(dev->wl, "Controller RESET (%s) ...\n", reason);
+ queue_work(dev->wl->hw->workqueue, &dev->restart_work);
+}
+
+#ifdef CONFIG_PM
+
+static int b43legacy_suspend(struct ssb_device *dev, pm_message_t state)
+{
+ struct b43legacy_wldev *wldev = ssb_get_drvdata(dev);
+ struct b43legacy_wl *wl = wldev->wl;
+
+ b43legacydbg(wl, "Suspending...\n");
+
+ mutex_lock(&wl->mutex);
+ wldev->suspend_init_status = b43legacy_status(wldev);
+ if (wldev->suspend_init_status >= B43legacy_STAT_STARTED)
+ b43legacy_wireless_core_stop(wldev);
+ if (wldev->suspend_init_status >= B43legacy_STAT_INITIALIZED)
+ b43legacy_wireless_core_exit(wldev);
+ mutex_unlock(&wl->mutex);
+
+ b43legacydbg(wl, "Device suspended.\n");
+
+ return 0;
+}
+
+static int b43legacy_resume(struct ssb_device *dev)
+{
+ struct b43legacy_wldev *wldev = ssb_get_drvdata(dev);
+ struct b43legacy_wl *wl = wldev->wl;
+ int err = 0;
+
+ b43legacydbg(wl, "Resuming...\n");
+
+ mutex_lock(&wl->mutex);
+ if (wldev->suspend_init_status >= B43legacy_STAT_INITIALIZED) {
+ err = b43legacy_wireless_core_init(wldev);
+ if (err) {
+ b43legacyerr(wl, "Resume failed at core init\n");
+ goto out;
+ }
+ }
+ if (wldev->suspend_init_status >= B43legacy_STAT_STARTED) {
+ err = b43legacy_wireless_core_start(wldev);
+ if (err) {
+ b43legacy_wireless_core_exit(wldev);
+ b43legacyerr(wl, "Resume failed at core start\n");
+ goto out;
+ }
+ }
+ mutex_unlock(&wl->mutex);
+
+ b43legacydbg(wl, "Device resumed.\n");
+out:
+ return err;
+}
+
+#else /* CONFIG_PM */
+# define b43legacy_suspend NULL
+# define b43legacy_resume NULL
+#endif /* CONFIG_PM */
+
+static struct ssb_driver b43legacy_ssb_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = b43legacy_ssb_tbl,
+ .probe = b43legacy_probe,
+ .remove = b43legacy_remove,
+ .suspend = b43legacy_suspend,
+ .resume = b43legacy_resume,
+};
+
+static int __init b43legacy_init(void)
+{
+ int err;
+
+ b43legacy_debugfs_init();
+
+ err = ssb_driver_register(&b43legacy_ssb_driver);
+ if (err)
+ goto err_dfs_exit;
+
+ return err;
+
+err_dfs_exit:
+ b43legacy_debugfs_exit();
+ return err;
+}
+
+static void __exit b43legacy_exit(void)
+{
+ ssb_driver_unregister(&b43legacy_ssb_driver);
+ b43legacy_debugfs_exit();
+}
+
+module_init(b43legacy_init)
+module_exit(b43legacy_exit)
diff --git a/drivers/net/wireless/b43legacy/main.h b/drivers/net/wireless/b43legacy/main.h
new file mode 100644
index 00000000000..68435c50d8e
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/main.h
@@ -0,0 +1,127 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef B43legacy_MAIN_H_
+#define B43legacy_MAIN_H_
+
+#include "b43legacy.h"
+
+
+#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes]
+#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes)
+/* Magic helper macro to pad structures. Ignore those above. It's magic. */
+#define PAD_BYTES(nr_bytes) P4D_BYTES(__LINE__ , (nr_bytes))
+
+
+/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
+static inline
+u8 b43legacy_freq_to_channel_bg(int freq)
+{
+ u8 channel;
+
+ if (freq == 2484)
+ channel = 14;
+ else
+ channel = (freq - 2407) / 5;
+
+ return channel;
+}
+static inline
+u8 b43legacy_freq_to_channel(struct b43legacy_wldev *dev,
+ int freq)
+{
+ return b43legacy_freq_to_channel_bg(freq);
+}
+
+/* Lightweight function to convert a channel number to a frequency (in Mhz). */
+static inline
+int b43legacy_channel_to_freq_bg(u8 channel)
+{
+ int freq;
+
+ if (channel == 14)
+ freq = 2484;
+ else
+ freq = 2407 + (5 * channel);
+
+ return freq;
+}
+
+static inline
+int b43legacy_channel_to_freq(struct b43legacy_wldev *dev,
+ u8 channel)
+{
+ return b43legacy_channel_to_freq_bg(channel);
+}
+
+static inline
+int b43legacy_is_cck_rate(int rate)
+{
+ return (rate == B43legacy_CCK_RATE_1MB ||
+ rate == B43legacy_CCK_RATE_2MB ||
+ rate == B43legacy_CCK_RATE_5MB ||
+ rate == B43legacy_CCK_RATE_11MB);
+}
+
+static inline
+int b43legacy_is_ofdm_rate(int rate)
+{
+ return !b43legacy_is_cck_rate(rate);
+}
+
+void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf);
+void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf);
+
+u32 b43legacy_shm_read32(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset);
+u16 b43legacy_shm_read16(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset);
+void b43legacy_shm_write32(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset,
+ u32 value);
+void b43legacy_shm_write16(struct b43legacy_wldev *dev,
+ u16 routing, u16 offset,
+ u16 value);
+
+u32 b43legacy_hf_read(struct b43legacy_wldev *dev);
+void b43legacy_hf_write(struct b43legacy_wldev *dev, u32 value);
+
+void b43legacy_dummy_transmission(struct b43legacy_wldev *dev);
+
+void b43legacy_wireless_core_reset(struct b43legacy_wldev *dev, u32 flags);
+
+void b43legacy_mac_suspend(struct b43legacy_wldev *dev);
+void b43legacy_mac_enable(struct b43legacy_wldev *dev);
+
+void b43legacy_controller_restart(struct b43legacy_wldev *dev,
+ const char *reason);
+
+#endif /* B43legacy_MAIN_H_ */
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
new file mode 100644
index 00000000000..22a4b3d0186
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -0,0 +1,2255 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mbuesch@freenet.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include "b43legacy.h"
+#include "phy.h"
+#include "main.h"
+#include "radio.h"
+#include "ilt.h"
+
+
+static const s8 b43legacy_tssi2dbm_b_table[] = {
+ 0x4D, 0x4C, 0x4B, 0x4A,
+ 0x4A, 0x49, 0x48, 0x47,
+ 0x47, 0x46, 0x45, 0x45,
+ 0x44, 0x43, 0x42, 0x42,
+ 0x41, 0x40, 0x3F, 0x3E,
+ 0x3D, 0x3C, 0x3B, 0x3A,
+ 0x39, 0x38, 0x37, 0x36,
+ 0x35, 0x34, 0x32, 0x31,
+ 0x30, 0x2F, 0x2D, 0x2C,
+ 0x2B, 0x29, 0x28, 0x26,
+ 0x25, 0x23, 0x21, 0x1F,
+ 0x1D, 0x1A, 0x17, 0x14,
+ 0x10, 0x0C, 0x06, 0x00,
+ -7, -7, -7, -7,
+ -7, -7, -7, -7,
+ -7, -7, -7, -7,
+};
+
+static const s8 b43legacy_tssi2dbm_g_table[] = {
+ 77, 77, 77, 76,
+ 76, 76, 75, 75,
+ 74, 74, 73, 73,
+ 73, 72, 72, 71,
+ 71, 70, 70, 69,
+ 68, 68, 67, 67,
+ 66, 65, 65, 64,
+ 63, 63, 62, 61,
+ 60, 59, 58, 57,
+ 56, 55, 54, 53,
+ 52, 50, 49, 47,
+ 45, 43, 40, 37,
+ 33, 28, 22, 14,
+ 5, -7, -20, -20,
+ -20, -20, -20, -20,
+ -20, -20, -20, -20,
+};
+
+static void b43legacy_phy_initg(struct b43legacy_wldev *dev);
+
+
+static inline
+void b43legacy_voluntary_preempt(void)
+{
+ B43legacy_BUG_ON(!(!in_atomic() && !in_irq() &&
+ !in_interrupt() && !irqs_disabled()));
+#ifndef CONFIG_PREEMPT
+ cond_resched();
+#endif /* CONFIG_PREEMPT */
+}
+
+void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ B43legacy_WARN_ON(!irqs_disabled());
+ if (b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD) == 0) {
+ phy->locked = 0;
+ return;
+ }
+ if (dev->dev->id.revision < 3) {
+ b43legacy_mac_suspend(dev);
+ spin_lock(&phy->lock);
+ } else {
+ if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ b43legacy_power_saving_ctl_bits(dev, -1, 1);
+ }
+ phy->locked = 1;
+}
+
+void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ B43legacy_WARN_ON(!irqs_disabled());
+ if (dev->dev->id.revision < 3) {
+ if (phy->locked) {
+ spin_unlock(&phy->lock);
+ b43legacy_mac_enable(dev);
+ }
+ } else {
+ if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+ b43legacy_power_saving_ctl_bits(dev, -1, -1);
+ }
+ phy->locked = 0;
+}
+
+u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset)
+{
+ b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
+ return b43legacy_read16(dev, B43legacy_MMIO_PHY_DATA);
+}
+
+void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val)
+{
+ b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_PHY_DATA, val);
+}
+
+void b43legacy_phy_calibrate(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); /* Dummy read. */
+ if (phy->calibrated)
+ return;
+ if (phy->type == B43legacy_PHYTYPE_G && phy->rev == 1) {
+ b43legacy_wireless_core_reset(dev, 0);
+ b43legacy_phy_initg(dev);
+ b43legacy_wireless_core_reset(dev, B43legacy_TMSLOW_GMODE);
+ }
+ phy->calibrated = 1;
+}
+
+/* intialize B PHY power control
+ * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
+ */
+static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 saved_batt = 0;
+ u16 saved_ratt = 0;
+ u16 saved_txctl1 = 0;
+ int must_reset_txpower = 0;
+
+ B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
+ phy->type == B43legacy_PHYTYPE_G));
+ if (is_bcm_board_vendor(dev) &&
+ (dev->dev->bus->boardinfo.type == 0x0416))
+ return;
+
+ b43legacy_phy_write(dev, 0x0028, 0x8018);
+ b43legacy_write16(dev, 0x03E6, b43legacy_read16(dev, 0x03E6) & 0xFFDF);
+
+ if (phy->type == B43legacy_PHYTYPE_G) {
+ if (!phy->gmode)
+ return;
+ b43legacy_phy_write(dev, 0x047A, 0xC111);
+ }
+ if (phy->savedpctlreg != 0xFFFF)
+ return;
+#ifdef CONFIG_B43LEGACY_DEBUG
+ if (phy->manual_txpower_control)
+ return;
+#endif
+
+ if (phy->type == B43legacy_PHYTYPE_B &&
+ phy->rev >= 2 &&
+ phy->radio_ver == 0x2050)
+ b43legacy_radio_write16(dev, 0x0076,
+ b43legacy_radio_read16(dev, 0x0076)
+ | 0x0084);
+ else {
+ saved_batt = phy->bbatt;
+ saved_ratt = phy->rfatt;
+ saved_txctl1 = phy->txctl1;
+ if ((phy->radio_rev >= 6) && (phy->radio_rev <= 8)
+ && /*FIXME: incomplete specs for 5 < revision < 9 */ 0)
+ b43legacy_radio_set_txpower_bg(dev, 0xB, 0x1F, 0);
+ else
+ b43legacy_radio_set_txpower_bg(dev, 0xB, 9, 0);
+ must_reset_txpower = 1;
+ }
+ b43legacy_dummy_transmission(dev);
+
+ phy->savedpctlreg = b43legacy_phy_read(dev, B43legacy_PHY_G_PCTL);
+
+ if (must_reset_txpower)
+ b43legacy_radio_set_txpower_bg(dev, saved_batt, saved_ratt,
+ saved_txctl1);
+ else
+ b43legacy_radio_write16(dev, 0x0076, b43legacy_radio_read16(dev,
+ 0x0076) & 0xFF7B);
+ b43legacy_radio_clear_tssi(dev);
+}
+
+static void b43legacy_phy_agcsetup(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 offset = 0x0000;
+
+ if (phy->rev == 1)
+ offset = 0x4C00;
+
+ b43legacy_ilt_write(dev, offset, 0x00FE);
+ b43legacy_ilt_write(dev, offset + 1, 0x000D);
+ b43legacy_ilt_write(dev, offset + 2, 0x0013);
+ b43legacy_ilt_write(dev, offset + 3, 0x0019);
+
+ if (phy->rev == 1) {
+ b43legacy_ilt_write(dev, 0x1800, 0x2710);
+ b43legacy_ilt_write(dev, 0x1801, 0x9B83);
+ b43legacy_ilt_write(dev, 0x1802, 0x9B83);
+ b43legacy_ilt_write(dev, 0x1803, 0x0F8D);
+ b43legacy_phy_write(dev, 0x0455, 0x0004);
+ }
+
+ b43legacy_phy_write(dev, 0x04A5, (b43legacy_phy_read(dev, 0x04A5)
+ & 0x00FF) | 0x5700);
+ b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
+ & 0xFF80) | 0x000F);
+ b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
+ & 0xC07F) | 0x2B80);
+ b43legacy_phy_write(dev, 0x048C, (b43legacy_phy_read(dev, 0x048C)
+ & 0xF0FF) | 0x0300);
+
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x0008);
+
+ b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
+ & 0xFFF0) | 0x0008);
+ b43legacy_phy_write(dev, 0x04A1, (b43legacy_phy_read(dev, 0x04A1)
+ & 0xF0FF) | 0x0600);
+ b43legacy_phy_write(dev, 0x04A2, (b43legacy_phy_read(dev, 0x04A2)
+ & 0xF0FF) | 0x0700);
+ b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
+ & 0xF0FF) | 0x0100);
+
+ if (phy->rev == 1)
+ b43legacy_phy_write(dev, 0x04A2,
+ (b43legacy_phy_read(dev, 0x04A2)
+ & 0xFFF0) | 0x0007);
+
+ b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
+ & 0xFF00) | 0x001C);
+ b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
+ & 0xC0FF) | 0x0200);
+ b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
+ & 0xFF00) | 0x001C);
+ b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
+ & 0xFF00) | 0x0020);
+ b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
+ & 0xC0FF) | 0x0200);
+ b43legacy_phy_write(dev, 0x0482, (b43legacy_phy_read(dev, 0x0482)
+ & 0xFF00) | 0x002E);
+ b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
+ & 0x00FF) | 0x1A00);
+ b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
+ & 0xFF00) | 0x0028);
+ b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
+ & 0x00FF) | 0x2C00);
+
+ if (phy->rev == 1) {
+ b43legacy_phy_write(dev, 0x0430, 0x092B);
+ b43legacy_phy_write(dev, 0x041B,
+ (b43legacy_phy_read(dev, 0x041B)
+ & 0xFFE1) | 0x0002);
+ } else {
+ b43legacy_phy_write(dev, 0x041B,
+ b43legacy_phy_read(dev, 0x041B) & 0xFFE1);
+ b43legacy_phy_write(dev, 0x041F, 0x287A);
+ b43legacy_phy_write(dev, 0x0420,
+ (b43legacy_phy_read(dev, 0x0420)
+ & 0xFFF0) | 0x0004);
+ }
+
+ if (phy->rev > 2) {
+ b43legacy_phy_write(dev, 0x0422, 0x287A);
+ b43legacy_phy_write(dev, 0x0420,
+ (b43legacy_phy_read(dev, 0x0420)
+ & 0x0FFF) | 0x3000);
+ }
+
+ b43legacy_phy_write(dev, 0x04A8, (b43legacy_phy_read(dev, 0x04A8)
+ & 0x8080) | 0x7874);
+ b43legacy_phy_write(dev, 0x048E, 0x1C00);
+
+ if (phy->rev == 1) {
+ b43legacy_phy_write(dev, 0x04AB,
+ (b43legacy_phy_read(dev, 0x04AB)
+ & 0xF0FF) | 0x0600);
+ b43legacy_phy_write(dev, 0x048B, 0x005E);
+ b43legacy_phy_write(dev, 0x048C,
+ (b43legacy_phy_read(dev, 0x048C) & 0xFF00)
+ | 0x001E);
+ b43legacy_phy_write(dev, 0x048D, 0x0002);
+ }
+
+ b43legacy_ilt_write(dev, offset + 0x0800, 0);
+ b43legacy_ilt_write(dev, offset + 0x0801, 7);
+ b43legacy_ilt_write(dev, offset + 0x0802, 16);
+ b43legacy_ilt_write(dev, offset + 0x0803, 28);
+
+ if (phy->rev >= 6) {
+ b43legacy_phy_write(dev, 0x0426,
+ (b43legacy_phy_read(dev, 0x0426) & 0xFFFC));
+ b43legacy_phy_write(dev, 0x0426,
+ (b43legacy_phy_read(dev, 0x0426) & 0xEFFF));
+ }
+}
+
+static void b43legacy_phy_setupg(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 i;
+
+ B43legacy_BUG_ON(phy->type != B43legacy_PHYTYPE_G);
+ if (phy->rev == 1) {
+ b43legacy_phy_write(dev, 0x0406, 0x4F19);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ (b43legacy_phy_read(dev,
+ B43legacy_PHY_G_CRS) & 0xFC3F) | 0x0340);
+ b43legacy_phy_write(dev, 0x042C, 0x005A);
+ b43legacy_phy_write(dev, 0x0427, 0x001A);
+
+ for (i = 0; i < B43legacy_ILT_FINEFREQG_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x5800 + i,
+ b43legacy_ilt_finefreqg[i]);
+ for (i = 0; i < B43legacy_ILT_NOISEG1_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x1800 + i,
+ b43legacy_ilt_noiseg1[i]);
+ for (i = 0; i < B43legacy_ILT_ROTOR_SIZE; i++)
+ b43legacy_ilt_write32(dev, 0x2000 + i,
+ b43legacy_ilt_rotor[i]);
+ } else {
+ /* nrssi values are signed 6-bit values. Why 0x7654 here? */
+ b43legacy_nrssi_hw_write(dev, 0xBA98, (s16)0x7654);
+
+ if (phy->rev == 2) {
+ b43legacy_phy_write(dev, 0x04C0, 0x1861);
+ b43legacy_phy_write(dev, 0x04C1, 0x0271);
+ } else if (phy->rev > 2) {
+ b43legacy_phy_write(dev, 0x04C0, 0x0098);
+ b43legacy_phy_write(dev, 0x04C1, 0x0070);
+ b43legacy_phy_write(dev, 0x04C9, 0x0080);
+ }
+ b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev,
+ 0x042B) | 0x800);
+
+ for (i = 0; i < 64; i++)
+ b43legacy_ilt_write(dev, 0x4000 + i, i);
+ for (i = 0; i < B43legacy_ILT_NOISEG2_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x1800 + i,
+ b43legacy_ilt_noiseg2[i]);
+ }
+
+ if (phy->rev <= 2)
+ for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x1400 + i,
+ b43legacy_ilt_noisescaleg1[i]);
+ else if ((phy->rev >= 7) && (b43legacy_phy_read(dev, 0x0449) & 0x0200))
+ for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x1400 + i,
+ b43legacy_ilt_noisescaleg3[i]);
+ else
+ for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x1400 + i,
+ b43legacy_ilt_noisescaleg2[i]);
+
+ if (phy->rev == 2)
+ for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x5000 + i,
+ b43legacy_ilt_sigmasqr1[i]);
+ else if ((phy->rev > 2) && (phy->rev <= 8))
+ for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
+ b43legacy_ilt_write(dev, 0x5000 + i,
+ b43legacy_ilt_sigmasqr2[i]);
+
+ if (phy->rev == 1) {
+ for (i = 0; i < B43legacy_ILT_RETARD_SIZE; i++)
+ b43legacy_ilt_write32(dev, 0x2400 + i,
+ b43legacy_ilt_retard[i]);
+ for (i = 4; i < 20; i++)
+ b43legacy_ilt_write(dev, 0x5400 + i, 0x0020);
+ b43legacy_phy_agcsetup(dev);
+
+ if (is_bcm_board_vendor(dev) &&
+ (dev->dev->bus->boardinfo.type == 0x0416) &&
+ (dev->dev->bus->boardinfo.rev == 0x0017))
+ return;
+
+ b43legacy_ilt_write(dev, 0x5001, 0x0002);
+ b43legacy_ilt_write(dev, 0x5002, 0x0001);
+ } else {
+ for (i = 0; i <= 0x20; i++)
+ b43legacy_ilt_write(dev, 0x1000 + i, 0x0820);
+ b43legacy_phy_agcsetup(dev);
+ b43legacy_phy_read(dev, 0x0400); /* dummy read */
+ b43legacy_phy_write(dev, 0x0403, 0x1000);
+ b43legacy_ilt_write(dev, 0x3C02, 0x000F);
+ b43legacy_ilt_write(dev, 0x3C03, 0x0014);
+
+ if (is_bcm_board_vendor(dev) &&
+ (dev->dev->bus->boardinfo.type == 0x0416) &&
+ (dev->dev->bus->boardinfo.rev == 0x0017))
+ return;
+
+ b43legacy_ilt_write(dev, 0x0401, 0x0002);
+ b43legacy_ilt_write(dev, 0x0402, 0x0001);
+ }
+}
+
+/* Initialize the APHY portion of a GPHY. */
+static void b43legacy_phy_inita(struct b43legacy_wldev *dev)
+{
+
+ might_sleep();
+
+ b43legacy_phy_setupg(dev);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL)
+ b43legacy_phy_write(dev, 0x046E, 0x03CF);
+}
+
+static void b43legacy_phy_initb2(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 offset;
+ int val;
+
+ b43legacy_write16(dev, 0x03EC, 0x3F22);
+ b43legacy_phy_write(dev, 0x0020, 0x301C);
+ b43legacy_phy_write(dev, 0x0026, 0x0000);
+ b43legacy_phy_write(dev, 0x0030, 0x00C6);
+ b43legacy_phy_write(dev, 0x0088, 0x3E00);
+ val = 0x3C3D;
+ for (offset = 0x0089; offset < 0x00A7; offset++) {
+ b43legacy_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ b43legacy_phy_write(dev, 0x03E4, 0x3000);
+ b43legacy_radio_selectchannel(dev, phy->channel, 0);
+ if (phy->radio_ver != 0x2050) {
+ b43legacy_radio_write16(dev, 0x0075, 0x0080);
+ b43legacy_radio_write16(dev, 0x0079, 0x0081);
+ }
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x0050, 0x0023);
+ if (phy->radio_ver == 0x2050) {
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x005A, 0x0070);
+ b43legacy_radio_write16(dev, 0x005B, 0x007B);
+ b43legacy_radio_write16(dev, 0x005C, 0x00B0);
+ b43legacy_radio_write16(dev, 0x007A, 0x000F);
+ b43legacy_phy_write(dev, 0x0038, 0x0677);
+ b43legacy_radio_init2050(dev);
+ }
+ b43legacy_phy_write(dev, 0x0014, 0x0080);
+ b43legacy_phy_write(dev, 0x0032, 0x00CA);
+ b43legacy_phy_write(dev, 0x0032, 0x00CC);
+ b43legacy_phy_write(dev, 0x0035, 0x07C2);
+ b43legacy_phy_lo_b_measure(dev);
+ b43legacy_phy_write(dev, 0x0026, 0xCC00);
+ if (phy->radio_ver != 0x2050)
+ b43legacy_phy_write(dev, 0x0026, 0xCE00);
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1000);
+ b43legacy_phy_write(dev, 0x002A, 0x88A3);
+ if (phy->radio_ver != 0x2050)
+ b43legacy_phy_write(dev, 0x002A, 0x88C2);
+ b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
+ b43legacy_phy_init_pctl(dev);
+}
+
+static void b43legacy_phy_initb4(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 offset;
+ u16 val;
+
+ b43legacy_write16(dev, 0x03EC, 0x3F22);
+ b43legacy_phy_write(dev, 0x0020, 0x301C);
+ b43legacy_phy_write(dev, 0x0026, 0x0000);
+ b43legacy_phy_write(dev, 0x0030, 0x00C6);
+ b43legacy_phy_write(dev, 0x0088, 0x3E00);
+ val = 0x3C3D;
+ for (offset = 0x0089; offset < 0x00A7; offset++) {
+ b43legacy_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ b43legacy_phy_write(dev, 0x03E4, 0x3000);
+ b43legacy_radio_selectchannel(dev, phy->channel, 0);
+ if (phy->radio_ver != 0x2050) {
+ b43legacy_radio_write16(dev, 0x0075, 0x0080);
+ b43legacy_radio_write16(dev, 0x0079, 0x0081);
+ }
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x0050, 0x0023);
+ if (phy->radio_ver == 0x2050) {
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x005A, 0x0070);
+ b43legacy_radio_write16(dev, 0x005B, 0x007B);
+ b43legacy_radio_write16(dev, 0x005C, 0x00B0);
+ b43legacy_radio_write16(dev, 0x007A, 0x000F);
+ b43legacy_phy_write(dev, 0x0038, 0x0677);
+ b43legacy_radio_init2050(dev);
+ }
+ b43legacy_phy_write(dev, 0x0014, 0x0080);
+ b43legacy_phy_write(dev, 0x0032, 0x00CA);
+ if (phy->radio_ver == 0x2050)
+ b43legacy_phy_write(dev, 0x0032, 0x00E0);
+ b43legacy_phy_write(dev, 0x0035, 0x07C2);
+
+ b43legacy_phy_lo_b_measure(dev);
+
+ b43legacy_phy_write(dev, 0x0026, 0xCC00);
+ if (phy->radio_ver == 0x2050)
+ b43legacy_phy_write(dev, 0x0026, 0xCE00);
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1100);
+ b43legacy_phy_write(dev, 0x002A, 0x88A3);
+ if (phy->radio_ver == 0x2050)
+ b43legacy_phy_write(dev, 0x002A, 0x88C2);
+ b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) {
+ b43legacy_calc_nrssi_slope(dev);
+ b43legacy_calc_nrssi_threshold(dev);
+ }
+ b43legacy_phy_init_pctl(dev);
+}
+
+static void b43legacy_phy_initb5(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 offset;
+ u16 value;
+ u8 old_channel;
+
+ if (phy->analog == 1)
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x0050);
+ if (!is_bcm_board_vendor(dev) &&
+ (dev->dev->bus->boardinfo.type != 0x0416)) {
+ value = 0x2120;
+ for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
+ b43legacy_phy_write(dev, offset, value);
+ value += 0x0202;
+ }
+ }
+ b43legacy_phy_write(dev, 0x0035,
+ (b43legacy_phy_read(dev, 0x0035) & 0xF0FF)
+ | 0x0700);
+ if (phy->radio_ver == 0x2050)
+ b43legacy_phy_write(dev, 0x0038, 0x0667);
+
+ if (phy->gmode) {
+ if (phy->radio_ver == 0x2050) {
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x0020);
+ b43legacy_radio_write16(dev, 0x0051,
+ b43legacy_radio_read16(dev, 0x0051)
+ | 0x0004);
+ }
+ b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, 0x0000);
+
+ b43legacy_phy_write(dev, 0x0802, b43legacy_phy_read(dev, 0x0802)
+ | 0x0100);
+ b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, 0x042B)
+ | 0x2000);
+
+ b43legacy_phy_write(dev, 0x001C, 0x186A);
+
+ b43legacy_phy_write(dev, 0x0013, (b43legacy_phy_read(dev,
+ 0x0013) & 0x00FF) | 0x1900);
+ b43legacy_phy_write(dev, 0x0035, (b43legacy_phy_read(dev,
+ 0x0035) & 0xFFC0) | 0x0064);
+ b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
+ 0x005D) & 0xFF80) | 0x000A);
+ }
+
+ if (dev->bad_frames_preempt)
+ b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
+ b43legacy_phy_read(dev,
+ B43legacy_PHY_RADIO_BITFIELD) | (1 << 11));
+
+ if (phy->analog == 1) {
+ b43legacy_phy_write(dev, 0x0026, 0xCE00);
+ b43legacy_phy_write(dev, 0x0021, 0x3763);
+ b43legacy_phy_write(dev, 0x0022, 0x1BC3);
+ b43legacy_phy_write(dev, 0x0023, 0x06F9);
+ b43legacy_phy_write(dev, 0x0024, 0x037E);
+ } else
+ b43legacy_phy_write(dev, 0x0026, 0xCC00);
+ b43legacy_phy_write(dev, 0x0030, 0x00C6);
+ b43legacy_write16(dev, 0x03EC, 0x3F22);
+
+ if (phy->analog == 1)
+ b43legacy_phy_write(dev, 0x0020, 0x3E1C);
+ else
+ b43legacy_phy_write(dev, 0x0020, 0x301C);
+
+ if (phy->analog == 0)
+ b43legacy_write16(dev, 0x03E4, 0x3000);
+
+ old_channel = (phy->channel == 0xFF) ? 1 : phy->channel;
+ /* Force to channel 7, even if not supported. */
+ b43legacy_radio_selectchannel(dev, 7, 0);
+
+ if (phy->radio_ver != 0x2050) {
+ b43legacy_radio_write16(dev, 0x0075, 0x0080);
+ b43legacy_radio_write16(dev, 0x0079, 0x0081);
+ }
+
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x0050, 0x0023);
+
+ if (phy->radio_ver == 0x2050) {
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x005A, 0x0070);
+ }
+
+ b43legacy_radio_write16(dev, 0x005B, 0x007B);
+ b43legacy_radio_write16(dev, 0x005C, 0x00B0);
+
+ b43legacy_radio_write16(dev, 0x007A, b43legacy_radio_read16(dev,
+ 0x007A) | 0x0007);
+
+ b43legacy_radio_selectchannel(dev, old_channel, 0);
+
+ b43legacy_phy_write(dev, 0x0014, 0x0080);
+ b43legacy_phy_write(dev, 0x0032, 0x00CA);
+ b43legacy_phy_write(dev, 0x002A, 0x88A3);
+
+ b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
+
+ if (phy->radio_ver == 0x2050)
+ b43legacy_radio_write16(dev, 0x005D, 0x000D);
+
+ b43legacy_write16(dev, 0x03E4, (b43legacy_read16(dev, 0x03E4) &
+ 0xFFC0) | 0x0004);
+}
+
+static void b43legacy_phy_initb6(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 offset;
+ u16 val;
+ u8 old_channel;
+
+ b43legacy_phy_write(dev, 0x003E, 0x817A);
+ b43legacy_radio_write16(dev, 0x007A,
+ (b43legacy_radio_read16(dev, 0x007A) | 0x0058));
+ if (phy->radio_rev == 4 ||
+ phy->radio_rev == 5) {
+ b43legacy_radio_write16(dev, 0x0051, 0x0037);
+ b43legacy_radio_write16(dev, 0x0052, 0x0070);
+ b43legacy_radio_write16(dev, 0x0053, 0x00B3);
+ b43legacy_radio_write16(dev, 0x0054, 0x009B);
+ b43legacy_radio_write16(dev, 0x005A, 0x0088);
+ b43legacy_radio_write16(dev, 0x005B, 0x0088);
+ b43legacy_radio_write16(dev, 0x005D, 0x0088);
+ b43legacy_radio_write16(dev, 0x005E, 0x0088);
+ b43legacy_radio_write16(dev, 0x007D, 0x0088);
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ (b43legacy_shm_read32(dev,
+ B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET)
+ | 0x00000200));
+ }
+ if (phy->radio_rev == 8) {
+ b43legacy_radio_write16(dev, 0x0051, 0x0000);
+ b43legacy_radio_write16(dev, 0x0052, 0x0040);
+ b43legacy_radio_write16(dev, 0x0053, 0x00B7);
+ b43legacy_radio_write16(dev, 0x0054, 0x0098);
+ b43legacy_radio_write16(dev, 0x005A, 0x0088);
+ b43legacy_radio_write16(dev, 0x005B, 0x006B);
+ b43legacy_radio_write16(dev, 0x005C, 0x000F);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & 0x8000) {
+ b43legacy_radio_write16(dev, 0x005D, 0x00FA);
+ b43legacy_radio_write16(dev, 0x005E, 0x00D8);
+ } else {
+ b43legacy_radio_write16(dev, 0x005D, 0x00F5);
+ b43legacy_radio_write16(dev, 0x005E, 0x00B8);
+ }
+ b43legacy_radio_write16(dev, 0x0073, 0x0003);
+ b43legacy_radio_write16(dev, 0x007D, 0x00A8);
+ b43legacy_radio_write16(dev, 0x007C, 0x0001);
+ b43legacy_radio_write16(dev, 0x007E, 0x0008);
+ }
+ val = 0x1E1F;
+ for (offset = 0x0088; offset < 0x0098; offset++) {
+ b43legacy_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ val = 0x3E3F;
+ for (offset = 0x0098; offset < 0x00A8; offset++) {
+ b43legacy_phy_write(dev, offset, val);
+ val -= 0x0202;
+ }
+ val = 0x2120;
+ for (offset = 0x00A8; offset < 0x00C8; offset++) {
+ b43legacy_phy_write(dev, offset, (val & 0x3F3F));
+ val += 0x0202;
+ }
+ if (phy->type == B43legacy_PHYTYPE_G) {
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A) |
+ 0x0020);
+ b43legacy_radio_write16(dev, 0x0051,
+ b43legacy_radio_read16(dev, 0x0051) |
+ 0x0004);
+ b43legacy_phy_write(dev, 0x0802,
+ b43legacy_phy_read(dev, 0x0802) | 0x0100);
+ b43legacy_phy_write(dev, 0x042B,
+ b43legacy_phy_read(dev, 0x042B) | 0x2000);
+ b43legacy_phy_write(dev, 0x5B, 0x0000);
+ b43legacy_phy_write(dev, 0x5C, 0x0000);
+ }
+
+ old_channel = phy->channel;
+ if (old_channel >= 8)
+ b43legacy_radio_selectchannel(dev, 1, 0);
+ else
+ b43legacy_radio_selectchannel(dev, 13, 0);
+
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ b43legacy_radio_write16(dev, 0x0050, 0x0023);
+ udelay(40);
+ if (phy->radio_rev < 6 || phy->radio_rev == 8) {
+ b43legacy_radio_write16(dev, 0x007C,
+ (b43legacy_radio_read16(dev, 0x007C)
+ | 0x0002));
+ b43legacy_radio_write16(dev, 0x0050, 0x0020);
+ }
+ if (phy->radio_rev <= 2) {
+ b43legacy_radio_write16(dev, 0x007C, 0x0020);
+ b43legacy_radio_write16(dev, 0x005A, 0x0070);
+ b43legacy_radio_write16(dev, 0x005B, 0x007B);
+ b43legacy_radio_write16(dev, 0x005C, 0x00B0);
+ }
+ b43legacy_radio_write16(dev, 0x007A,
+ (b43legacy_radio_read16(dev,
+ 0x007A) & 0x00F8) | 0x0007);
+
+ b43legacy_radio_selectchannel(dev, old_channel, 0);
+
+ b43legacy_phy_write(dev, 0x0014, 0x0200);
+ if (phy->radio_rev >= 6)
+ b43legacy_phy_write(dev, 0x002A, 0x88C2);
+ else
+ b43legacy_phy_write(dev, 0x002A, 0x8AC0);
+ b43legacy_phy_write(dev, 0x0038, 0x0668);
+ b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
+ if (phy->radio_rev <= 5)
+ b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
+ 0x005D) & 0xFF80) | 0x0003);
+ if (phy->radio_rev <= 2)
+ b43legacy_radio_write16(dev, 0x005D, 0x000D);
+
+ if (phy->analog == 4) {
+ b43legacy_write16(dev, 0x03E4, 0x0009);
+ b43legacy_phy_write(dev, 0x61, b43legacy_phy_read(dev, 0x61)
+ & 0xFFF);
+ } else
+ b43legacy_phy_write(dev, 0x0002, (b43legacy_phy_read(dev,
+ 0x0002) & 0xFFC0) | 0x0004);
+ if (phy->type == B43legacy_PHYTYPE_G)
+ b43legacy_write16(dev, 0x03E6, 0x0);
+ if (phy->type == B43legacy_PHYTYPE_B) {
+ b43legacy_write16(dev, 0x03E6, 0x8140);
+ b43legacy_phy_write(dev, 0x0016, 0x0410);
+ b43legacy_phy_write(dev, 0x0017, 0x0820);
+ b43legacy_phy_write(dev, 0x0062, 0x0007);
+ b43legacy_radio_init2050(dev);
+ b43legacy_phy_lo_g_measure(dev);
+ if (dev->dev->bus->sprom.r1.boardflags_lo &
+ B43legacy_BFL_RSSI) {
+ b43legacy_calc_nrssi_slope(dev);
+ b43legacy_calc_nrssi_threshold(dev);
+ }
+ b43legacy_phy_init_pctl(dev);
+ }
+}
+
+static void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 backup_phy[15] = {0};
+ u16 backup_radio[3];
+ u16 backup_bband;
+ u16 i;
+ u16 loop1_cnt;
+ u16 loop1_done;
+ u16 loop1_omitted;
+ u16 loop2_done;
+
+ backup_phy[0] = b43legacy_phy_read(dev, 0x0429);
+ backup_phy[1] = b43legacy_phy_read(dev, 0x0001);
+ backup_phy[2] = b43legacy_phy_read(dev, 0x0811);
+ backup_phy[3] = b43legacy_phy_read(dev, 0x0812);
+ if (phy->rev != 1) {
+ backup_phy[4] = b43legacy_phy_read(dev, 0x0814);
+ backup_phy[5] = b43legacy_phy_read(dev, 0x0815);
+ }
+ backup_phy[6] = b43legacy_phy_read(dev, 0x005A);
+ backup_phy[7] = b43legacy_phy_read(dev, 0x0059);
+ backup_phy[8] = b43legacy_phy_read(dev, 0x0058);
+ backup_phy[9] = b43legacy_phy_read(dev, 0x000A);
+ backup_phy[10] = b43legacy_phy_read(dev, 0x0003);
+ backup_phy[11] = b43legacy_phy_read(dev, 0x080F);
+ backup_phy[12] = b43legacy_phy_read(dev, 0x0810);
+ backup_phy[13] = b43legacy_phy_read(dev, 0x002B);
+ backup_phy[14] = b43legacy_phy_read(dev, 0x0015);
+ b43legacy_phy_read(dev, 0x002D); /* dummy read */
+ backup_bband = phy->bbatt;
+ backup_radio[0] = b43legacy_radio_read16(dev, 0x0052);
+ backup_radio[1] = b43legacy_radio_read16(dev, 0x0043);
+ backup_radio[2] = b43legacy_radio_read16(dev, 0x007A);
+
+ b43legacy_phy_write(dev, 0x0429,
+ b43legacy_phy_read(dev, 0x0429) & 0x3FFF);
+ b43legacy_phy_write(dev, 0x0001,
+ b43legacy_phy_read(dev, 0x0001) & 0x8000);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811) | 0x0002);
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812) & 0xFFFD);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811) | 0x0001);
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812) & 0xFFFE);
+ if (phy->rev != 1) {
+ b43legacy_phy_write(dev, 0x0814,
+ b43legacy_phy_read(dev, 0x0814) | 0x0001);
+ b43legacy_phy_write(dev, 0x0815,
+ b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
+ b43legacy_phy_write(dev, 0x0814,
+ b43legacy_phy_read(dev, 0x0814) | 0x0002);
+ b43legacy_phy_write(dev, 0x0815,
+ b43legacy_phy_read(dev, 0x0815) & 0xFFFD);
+ }
+ b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) |
+ 0x000C);
+ b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) |
+ 0x000C);
+
+ b43legacy_phy_write(dev, 0x0811, (b43legacy_phy_read(dev, 0x0811)
+ & 0xFFCF) | 0x0030);
+ b43legacy_phy_write(dev, 0x0812, (b43legacy_phy_read(dev, 0x0812)
+ & 0xFFCF) | 0x0010);
+
+ b43legacy_phy_write(dev, 0x005A, 0x0780);
+ b43legacy_phy_write(dev, 0x0059, 0xC810);
+ b43legacy_phy_write(dev, 0x0058, 0x000D);
+ if (phy->analog == 0)
+ b43legacy_phy_write(dev, 0x0003, 0x0122);
+ else
+ b43legacy_phy_write(dev, 0x000A,
+ b43legacy_phy_read(dev, 0x000A)
+ | 0x2000);
+ if (phy->rev != 1) {
+ b43legacy_phy_write(dev, 0x0814,
+ b43legacy_phy_read(dev, 0x0814) | 0x0004);
+ b43legacy_phy_write(dev, 0x0815,
+ b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
+ }
+ b43legacy_phy_write(dev, 0x0003,
+ (b43legacy_phy_read(dev, 0x0003)
+ & 0xFF9F) | 0x0040);
+ if (phy->radio_ver == 0x2050 && phy->radio_rev == 2) {
+ b43legacy_radio_write16(dev, 0x0052, 0x0000);
+ b43legacy_radio_write16(dev, 0x0043,
+ (b43legacy_radio_read16(dev, 0x0043)
+ & 0xFFF0) | 0x0009);
+ loop1_cnt = 9;
+ } else if (phy->radio_rev == 8) {
+ b43legacy_radio_write16(dev, 0x0043, 0x000F);
+ loop1_cnt = 15;
+ } else
+ loop1_cnt = 0;
+
+ b43legacy_phy_set_baseband_attenuation(dev, 11);
+
+ if (phy->rev >= 3)
+ b43legacy_phy_write(dev, 0x080F, 0xC020);
+ else
+ b43legacy_phy_write(dev, 0x080F, 0x8020);
+ b43legacy_phy_write(dev, 0x0810, 0x0000);
+
+ b43legacy_phy_write(dev, 0x002B,
+ (b43legacy_phy_read(dev, 0x002B)
+ & 0xFFC0) | 0x0001);
+ b43legacy_phy_write(dev, 0x002B,
+ (b43legacy_phy_read(dev, 0x002B)
+ & 0xC0FF) | 0x0800);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811) | 0x0100);
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812) & 0xCFFF);
+ if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_EXTLNA) {
+ if (phy->rev >= 7) {
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811)
+ | 0x0800);
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812)
+ | 0x8000);
+ }
+ }
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ & 0x00F7);
+
+ for (i = 0; i < loop1_cnt; i++) {
+ b43legacy_radio_write16(dev, 0x0043, loop1_cnt);
+ b43legacy_phy_write(dev, 0x0812,
+ (b43legacy_phy_read(dev, 0x0812)
+ & 0xF0FF) | (i << 8));
+ b43legacy_phy_write(dev, 0x0015,
+ (b43legacy_phy_read(dev, 0x0015)
+ & 0x0FFF) | 0xA000);
+ b43legacy_phy_write(dev, 0x0015,
+ (b43legacy_phy_read(dev, 0x0015)
+ & 0x0FFF) | 0xF000);
+ udelay(20);
+ if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
+ break;
+ }
+ loop1_done = i;
+ loop1_omitted = loop1_cnt - loop1_done;
+
+ loop2_done = 0;
+ if (loop1_done >= 8) {
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812)
+ | 0x0030);
+ for (i = loop1_done - 8; i < 16; i++) {
+ b43legacy_phy_write(dev, 0x0812,
+ (b43legacy_phy_read(dev, 0x0812)
+ & 0xF0FF) | (i << 8));
+ b43legacy_phy_write(dev, 0x0015,
+ (b43legacy_phy_read(dev, 0x0015)
+ & 0x0FFF) | 0xA000);
+ b43legacy_phy_write(dev, 0x0015,
+ (b43legacy_phy_read(dev, 0x0015)
+ & 0x0FFF) | 0xF000);
+ udelay(20);
+ if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
+ break;
+ }
+ }
+
+ if (phy->rev != 1) {
+ b43legacy_phy_write(dev, 0x0814, backup_phy[4]);
+ b43legacy_phy_write(dev, 0x0815, backup_phy[5]);
+ }
+ b43legacy_phy_write(dev, 0x005A, backup_phy[6]);
+ b43legacy_phy_write(dev, 0x0059, backup_phy[7]);
+ b43legacy_phy_write(dev, 0x0058, backup_phy[8]);
+ b43legacy_phy_write(dev, 0x000A, backup_phy[9]);
+ b43legacy_phy_write(dev, 0x0003, backup_phy[10]);
+ b43legacy_phy_write(dev, 0x080F, backup_phy[11]);
+ b43legacy_phy_write(dev, 0x0810, backup_phy[12]);
+ b43legacy_phy_write(dev, 0x002B, backup_phy[13]);
+ b43legacy_phy_write(dev, 0x0015, backup_phy[14]);
+
+ b43legacy_phy_set_baseband_attenuation(dev, backup_bband);
+
+ b43legacy_radio_write16(dev, 0x0052, backup_radio[0]);
+ b43legacy_radio_write16(dev, 0x0043, backup_radio[1]);
+ b43legacy_radio_write16(dev, 0x007A, backup_radio[2]);
+
+ b43legacy_phy_write(dev, 0x0811, backup_phy[2] | 0x0003);
+ udelay(10);
+ b43legacy_phy_write(dev, 0x0811, backup_phy[2]);
+ b43legacy_phy_write(dev, 0x0812, backup_phy[3]);
+ b43legacy_phy_write(dev, 0x0429, backup_phy[0]);
+ b43legacy_phy_write(dev, 0x0001, backup_phy[1]);
+
+ phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11;
+ phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2;
+}
+
+static void b43legacy_phy_initg(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 tmp;
+
+ if (phy->rev == 1)
+ b43legacy_phy_initb5(dev);
+ else
+ b43legacy_phy_initb6(dev);
+ if (phy->rev >= 2 || phy->gmode)
+ b43legacy_phy_inita(dev);
+
+ if (phy->rev >= 2) {
+ b43legacy_phy_write(dev, 0x0814, 0x0000);
+ b43legacy_phy_write(dev, 0x0815, 0x0000);
+ }
+ if (phy->rev == 2) {
+ b43legacy_phy_write(dev, 0x0811, 0x0000);
+ b43legacy_phy_write(dev, 0x0015, 0x00C0);
+ }
+ if (phy->rev > 5) {
+ b43legacy_phy_write(dev, 0x0811, 0x0400);
+ b43legacy_phy_write(dev, 0x0015, 0x00C0);
+ }
+ if (phy->rev >= 2 || phy->gmode) {
+ tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF;
+ if (tmp == 3 || tmp == 5) {
+ b43legacy_phy_write(dev, 0x04C2, 0x1816);
+ b43legacy_phy_write(dev, 0x04C3, 0x8006);
+ if (tmp == 5)
+ b43legacy_phy_write(dev, 0x04CC,
+ (b43legacy_phy_read(dev,
+ 0x04CC) & 0x00FF) |
+ 0x1F00);
+ }
+ b43legacy_phy_write(dev, 0x047E, 0x0078);
+ }
+ if (phy->radio_rev == 8) {
+ b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801)
+ | 0x0080);
+ b43legacy_phy_write(dev, 0x043E, b43legacy_phy_read(dev, 0x043E)
+ | 0x0004);
+ }
+ if (phy->rev >= 2 && phy->gmode)
+ b43legacy_calc_loopback_gain(dev);
+ if (phy->radio_rev != 8) {
+ if (phy->initval == 0xFFFF)
+ phy->initval = b43legacy_radio_init2050(dev);
+ else
+ b43legacy_radio_write16(dev, 0x0078, phy->initval);
+ }
+ if (phy->txctl2 == 0xFFFF)
+ b43legacy_phy_lo_g_measure(dev);
+ else {
+ if (phy->radio_ver == 0x2050 && phy->radio_rev == 8)
+ b43legacy_radio_write16(dev, 0x0052,
+ (phy->txctl1 << 4) |
+ phy->txctl2);
+ else
+ b43legacy_radio_write16(dev, 0x0052,
+ (b43legacy_radio_read16(dev,
+ 0x0052) & 0xFFF0) |
+ phy->txctl1);
+ if (phy->rev >= 6)
+ b43legacy_phy_write(dev, 0x0036,
+ (b43legacy_phy_read(dev, 0x0036)
+ & 0x0FFF) | (phy->txctl2 << 12));
+ if (dev->dev->bus->sprom.r1.boardflags_lo &
+ B43legacy_BFL_PACTRL)
+ b43legacy_phy_write(dev, 0x002E, 0x8075);
+ else
+ b43legacy_phy_write(dev, 0x002E, 0x807F);
+ if (phy->rev < 2)
+ b43legacy_phy_write(dev, 0x002F, 0x0101);
+ else
+ b43legacy_phy_write(dev, 0x002F, 0x0202);
+ }
+ if (phy->gmode || phy->rev >= 2) {
+ b43legacy_phy_lo_adjust(dev, 0);
+ b43legacy_phy_write(dev, 0x080F, 0x8078);
+ }
+
+ if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI)) {
+ /* The specs state to update the NRSSI LT with
+ * the value 0x7FFFFFFF here. I think that is some weird
+ * compiler optimization in the original driver.
+ * Essentially, what we do here is resetting all NRSSI LT
+ * entries to -32 (see the limit_value() in nrssi_hw_update())
+ */
+ b43legacy_nrssi_hw_update(dev, 0xFFFF);
+ b43legacy_calc_nrssi_threshold(dev);
+ } else if (phy->gmode || phy->rev >= 2) {
+ if (phy->nrssi[0] == -1000) {
+ B43legacy_WARN_ON(phy->nrssi[1] != -1000);
+ b43legacy_calc_nrssi_slope(dev);
+ } else {
+ B43legacy_WARN_ON(phy->nrssi[1] == -1000);
+ b43legacy_calc_nrssi_threshold(dev);
+ }
+ }
+ if (phy->radio_rev == 8)
+ b43legacy_phy_write(dev, 0x0805, 0x3230);
+ b43legacy_phy_init_pctl(dev);
+ if (dev->dev->bus->chip_id == 0x4306
+ && dev->dev->bus->chip_package == 2) {
+ b43legacy_phy_write(dev, 0x0429,
+ b43legacy_phy_read(dev, 0x0429) & 0xBFFF);
+ b43legacy_phy_write(dev, 0x04C3,
+ b43legacy_phy_read(dev, 0x04C3) & 0x7FFF);
+ }
+}
+
+static u16 b43legacy_phy_lo_b_r15_loop(struct b43legacy_wldev *dev)
+{
+ int i;
+ u16 ret = 0;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ for (i = 0; i < 10; i++) {
+ b43legacy_phy_write(dev, 0x0015, 0xAFA0);
+ udelay(1);
+ b43legacy_phy_write(dev, 0x0015, 0xEFA0);
+ udelay(10);
+ b43legacy_phy_write(dev, 0x0015, 0xFFA0);
+ udelay(40);
+ ret += b43legacy_phy_read(dev, 0x002C);
+ }
+ local_irq_restore(flags);
+ b43legacy_voluntary_preempt();
+
+ return ret;
+}
+
+void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 regstack[12] = { 0 };
+ u16 mls;
+ u16 fval;
+ int i;
+ int j;
+
+ regstack[0] = b43legacy_phy_read(dev, 0x0015);
+ regstack[1] = b43legacy_radio_read16(dev, 0x0052) & 0xFFF0;
+
+ if (phy->radio_ver == 0x2053) {
+ regstack[2] = b43legacy_phy_read(dev, 0x000A);
+ regstack[3] = b43legacy_phy_read(dev, 0x002A);
+ regstack[4] = b43legacy_phy_read(dev, 0x0035);
+ regstack[5] = b43legacy_phy_read(dev, 0x0003);
+ regstack[6] = b43legacy_phy_read(dev, 0x0001);
+ regstack[7] = b43legacy_phy_read(dev, 0x0030);
+
+ regstack[8] = b43legacy_radio_read16(dev, 0x0043);
+ regstack[9] = b43legacy_radio_read16(dev, 0x007A);
+ regstack[10] = b43legacy_read16(dev, 0x03EC);
+ regstack[11] = b43legacy_radio_read16(dev, 0x0052) & 0x00F0;
+
+ b43legacy_phy_write(dev, 0x0030, 0x00FF);
+ b43legacy_write16(dev, 0x03EC, 0x3F3F);
+ b43legacy_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
+ b43legacy_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
+ }
+ b43legacy_phy_write(dev, 0x0015, 0xB000);
+ b43legacy_phy_write(dev, 0x002B, 0x0004);
+
+ if (phy->radio_ver == 0x2053) {
+ b43legacy_phy_write(dev, 0x002B, 0x0203);
+ b43legacy_phy_write(dev, 0x002A, 0x08A3);
+ }
+
+ phy->minlowsig[0] = 0xFFFF;
+
+ for (i = 0; i < 4; i++) {
+ b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
+ b43legacy_phy_lo_b_r15_loop(dev);
+ }
+ for (i = 0; i < 10; i++) {
+ b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
+ mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
+ if (mls < phy->minlowsig[0]) {
+ phy->minlowsig[0] = mls;
+ phy->minlowsigpos[0] = i;
+ }
+ }
+ b43legacy_radio_write16(dev, 0x0052, regstack[1]
+ | phy->minlowsigpos[0]);
+
+ phy->minlowsig[1] = 0xFFFF;
+
+ for (i = -4; i < 5; i += 2) {
+ for (j = -4; j < 5; j += 2) {
+ if (j < 0)
+ fval = (0x0100 * i) + j + 0x0100;
+ else
+ fval = (0x0100 * i) + j;
+ b43legacy_phy_write(dev, 0x002F, fval);
+ mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
+ if (mls < phy->minlowsig[1]) {
+ phy->minlowsig[1] = mls;
+ phy->minlowsigpos[1] = fval;
+ }
+ }
+ }
+ phy->minlowsigpos[1] += 0x0101;
+
+ b43legacy_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
+ if (phy->radio_ver == 0x2053) {
+ b43legacy_phy_write(dev, 0x000A, regstack[2]);
+ b43legacy_phy_write(dev, 0x002A, regstack[3]);
+ b43legacy_phy_write(dev, 0x0035, regstack[4]);
+ b43legacy_phy_write(dev, 0x0003, regstack[5]);
+ b43legacy_phy_write(dev, 0x0001, regstack[6]);
+ b43legacy_phy_write(dev, 0x0030, regstack[7]);
+
+ b43legacy_radio_write16(dev, 0x0043, regstack[8]);
+ b43legacy_radio_write16(dev, 0x007A, regstack[9]);
+
+ b43legacy_radio_write16(dev, 0x0052,
+ (b43legacy_radio_read16(dev, 0x0052)
+ & 0x000F) | regstack[11]);
+
+ b43legacy_write16(dev, 0x03EC, regstack[10]);
+ }
+ b43legacy_phy_write(dev, 0x0015, regstack[0]);
+}
+
+static inline
+u16 b43legacy_phy_lo_g_deviation_subval(struct b43legacy_wldev *dev,
+ u16 control)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (phy->gmode) {
+ b43legacy_phy_write(dev, 0x15, 0xE300);
+ control <<= 8;
+ b43legacy_phy_write(dev, 0x0812, control | 0x00B0);
+ udelay(5);
+ b43legacy_phy_write(dev, 0x0812, control | 0x00B2);
+ udelay(2);
+ b43legacy_phy_write(dev, 0x0812, control | 0x00B3);
+ udelay(4);
+ b43legacy_phy_write(dev, 0x0015, 0xF300);
+ udelay(8);
+ } else {
+ b43legacy_phy_write(dev, 0x0015, control | 0xEFA0);
+ udelay(2);
+ b43legacy_phy_write(dev, 0x0015, control | 0xEFE0);
+ udelay(4);
+ b43legacy_phy_write(dev, 0x0015, control | 0xFFE0);
+ udelay(8);
+ }
+ ret = b43legacy_phy_read(dev, 0x002D);
+ local_irq_restore(flags);
+ b43legacy_voluntary_preempt();
+
+ return ret;
+}
+
+static u32 b43legacy_phy_lo_g_singledeviation(struct b43legacy_wldev *dev,
+ u16 control)
+{
+ int i;
+ u32 ret = 0;
+
+ for (i = 0; i < 8; i++)
+ ret += b43legacy_phy_lo_g_deviation_subval(dev, control);
+
+ return ret;
+}
+
+/* Write the LocalOscillator CONTROL */
+static inline
+void b43legacy_lo_write(struct b43legacy_wldev *dev,
+ struct b43legacy_lopair *pair)
+{
+ u16 value;
+
+ value = (u8)(pair->low);
+ value |= ((u8)(pair->high)) << 8;
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+ /* Sanity check. */
+ if (pair->low < -8 || pair->low > 8 ||
+ pair->high < -8 || pair->high > 8) {
+ struct b43legacy_phy *phy = &dev->phy;
+ b43legacydbg(dev->wl,
+ "WARNING: Writing invalid LOpair "
+ "(low: %d, high: %d, index: %lu)\n",
+ pair->low, pair->high,
+ (unsigned long)(pair - phy->_lo_pairs));
+ dump_stack();
+ }
+#endif
+
+ b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, value);
+}
+
+static inline
+struct b43legacy_lopair *b43legacy_find_lopair(struct b43legacy_wldev *dev,
+ u16 bbatt,
+ u16 rfatt,
+ u16 tx)
+{
+ static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 };
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (bbatt > 6)
+ bbatt = 6;
+ B43legacy_WARN_ON(rfatt >= 10);
+
+ if (tx == 3)
+ return b43legacy_get_lopair(phy, rfatt, bbatt);
+ return b43legacy_get_lopair(phy, dict[rfatt], bbatt);
+}
+
+static inline
+struct b43legacy_lopair *b43legacy_current_lopair(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ return b43legacy_find_lopair(dev, phy->bbatt,
+ phy->rfatt, phy->txctl1);
+}
+
+/* Adjust B/G LO */
+void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed)
+{
+ struct b43legacy_lopair *pair;
+
+ if (fixed) {
+ /* Use fixed values. Only for initialization. */
+ pair = b43legacy_find_lopair(dev, 2, 3, 0);
+ } else
+ pair = b43legacy_current_lopair(dev);
+ b43legacy_lo_write(dev, pair);
+}
+
+static void b43legacy_phy_lo_g_measure_txctl2(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 txctl2 = 0;
+ u16 i;
+ u32 smallest;
+ u32 tmp;
+
+ b43legacy_radio_write16(dev, 0x0052, 0x0000);
+ udelay(10);
+ smallest = b43legacy_phy_lo_g_singledeviation(dev, 0);
+ for (i = 0; i < 16; i++) {
+ b43legacy_radio_write16(dev, 0x0052, i);
+ udelay(10);
+ tmp = b43legacy_phy_lo_g_singledeviation(dev, 0);
+ if (tmp < smallest) {
+ smallest = tmp;
+ txctl2 = i;
+ }
+ }
+ phy->txctl2 = txctl2;
+}
+
+static
+void b43legacy_phy_lo_g_state(struct b43legacy_wldev *dev,
+ const struct b43legacy_lopair *in_pair,
+ struct b43legacy_lopair *out_pair,
+ u16 r27)
+{
+ static const struct b43legacy_lopair transitions[8] = {
+ { .high = 1, .low = 1, },
+ { .high = 1, .low = 0, },
+ { .high = 1, .low = -1, },
+ { .high = 0, .low = -1, },
+ { .high = -1, .low = -1, },
+ { .high = -1, .low = 0, },
+ { .high = -1, .low = 1, },
+ { .high = 0, .low = 1, },
+ };
+ struct b43legacy_lopair lowest_transition = {
+ .high = in_pair->high,
+ .low = in_pair->low,
+ };
+ struct b43legacy_lopair tmp_pair;
+ struct b43legacy_lopair transition;
+ int i = 12;
+ int state = 0;
+ int found_lower;
+ int j;
+ int begin;
+ int end;
+ u32 lowest_deviation;
+ u32 tmp;
+
+ /* Note that in_pair and out_pair can point to the same pair.
+ * Be careful. */
+
+ b43legacy_lo_write(dev, &lowest_transition);
+ lowest_deviation = b43legacy_phy_lo_g_singledeviation(dev, r27);
+ do {
+ found_lower = 0;
+ B43legacy_WARN_ON(!(state >= 0 && state <= 8));
+ if (state == 0) {
+ begin = 1;
+ end = 8;
+ } else if (state % 2 == 0) {
+ begin = state - 1;
+ end = state + 1;
+ } else {
+ begin = state - 2;
+ end = state + 2;
+ }
+ if (begin < 1)
+ begin += 8;
+ if (end > 8)
+ end -= 8;
+
+ j = begin;
+ tmp_pair.high = lowest_transition.high;
+ tmp_pair.low = lowest_transition.low;
+ while (1) {
+ B43legacy_WARN_ON(!(j >= 1 && j <= 8));
+ transition.high = tmp_pair.high +
+ transitions[j - 1].high;
+ transition.low = tmp_pair.low + transitions[j - 1].low;
+ if ((abs(transition.low) < 9)
+ && (abs(transition.high) < 9)) {
+ b43legacy_lo_write(dev, &transition);
+ tmp = b43legacy_phy_lo_g_singledeviation(dev,
+ r27);
+ if (tmp < lowest_deviation) {
+ lowest_deviation = tmp;
+ state = j;
+ found_lower = 1;
+
+ lowest_transition.high =
+ transition.high;
+ lowest_transition.low = transition.low;
+ }
+ }
+ if (j == end)
+ break;
+ if (j == 8)
+ j = 1;
+ else
+ j++;
+ }
+ } while (i-- && found_lower);
+
+ out_pair->high = lowest_transition.high;
+ out_pair->low = lowest_transition.low;
+}
+
+/* Set the baseband attenuation value on chip. */
+void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev,
+ u16 bbatt)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 value;
+
+ if (phy->analog == 0) {
+ value = (b43legacy_read16(dev, 0x03E6) & 0xFFF0);
+ value |= (bbatt & 0x000F);
+ b43legacy_write16(dev, 0x03E6, value);
+ return;
+ }
+
+ if (phy->analog > 1) {
+ value = b43legacy_phy_read(dev, 0x0060) & 0xFFC3;
+ value |= (bbatt << 2) & 0x003C;
+ } else {
+ value = b43legacy_phy_read(dev, 0x0060) & 0xFF87;
+ value |= (bbatt << 3) & 0x0078;
+ }
+ b43legacy_phy_write(dev, 0x0060, value);
+}
+
+/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */
+void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev)
+{
+ static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
+ const int is_initializing = (b43legacy_status(dev)
+ < B43legacy_STAT_STARTED);
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 h;
+ u16 i;
+ u16 oldi = 0;
+ u16 j;
+ struct b43legacy_lopair control;
+ struct b43legacy_lopair *tmp_control;
+ u16 tmp;
+ u16 regstack[16] = { 0 };
+ u8 oldchannel;
+
+ /* XXX: What are these? */
+ u8 r27 = 0;
+ u16 r31;
+
+ oldchannel = phy->channel;
+ /* Setup */
+ if (phy->gmode) {
+ regstack[0] = b43legacy_phy_read(dev, B43legacy_PHY_G_CRS);
+ regstack[1] = b43legacy_phy_read(dev, 0x0802);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
+ & 0x7FFF);
+ b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
+ }
+ regstack[3] = b43legacy_read16(dev, 0x03E2);
+ b43legacy_write16(dev, 0x03E2, regstack[3] | 0x8000);
+ regstack[4] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
+ regstack[5] = b43legacy_phy_read(dev, 0x15);
+ regstack[6] = b43legacy_phy_read(dev, 0x2A);
+ regstack[7] = b43legacy_phy_read(dev, 0x35);
+ regstack[8] = b43legacy_phy_read(dev, 0x60);
+ regstack[9] = b43legacy_radio_read16(dev, 0x43);
+ regstack[10] = b43legacy_radio_read16(dev, 0x7A);
+ regstack[11] = b43legacy_radio_read16(dev, 0x52);
+ if (phy->gmode) {
+ regstack[12] = b43legacy_phy_read(dev, 0x0811);
+ regstack[13] = b43legacy_phy_read(dev, 0x0812);
+ regstack[14] = b43legacy_phy_read(dev, 0x0814);
+ regstack[15] = b43legacy_phy_read(dev, 0x0815);
+ }
+ b43legacy_radio_selectchannel(dev, 6, 0);
+ if (phy->gmode) {
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
+ & 0x7FFF);
+ b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
+ b43legacy_dummy_transmission(dev);
+ }
+ b43legacy_radio_write16(dev, 0x0043, 0x0006);
+
+ b43legacy_phy_set_baseband_attenuation(dev, 2);
+
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x0000);
+ b43legacy_phy_write(dev, 0x002E, 0x007F);
+ b43legacy_phy_write(dev, 0x080F, 0x0078);
+ b43legacy_phy_write(dev, 0x0035, regstack[7] & ~(1 << 7));
+ b43legacy_radio_write16(dev, 0x007A, regstack[10] & 0xFFF0);
+ b43legacy_phy_write(dev, 0x002B, 0x0203);
+ b43legacy_phy_write(dev, 0x002A, 0x08A3);
+ if (phy->gmode) {
+ b43legacy_phy_write(dev, 0x0814, regstack[14] | 0x0003);
+ b43legacy_phy_write(dev, 0x0815, regstack[15] & 0xFFFC);
+ b43legacy_phy_write(dev, 0x0811, 0x01B3);
+ b43legacy_phy_write(dev, 0x0812, 0x00B2);
+ }
+ if (is_initializing)
+ b43legacy_phy_lo_g_measure_txctl2(dev);
+ b43legacy_phy_write(dev, 0x080F, 0x8078);
+
+ /* Measure */
+ control.low = 0;
+ control.high = 0;
+ for (h = 0; h < 10; h++) {
+ /* Loop over each possible RadioAttenuation (0-9) */
+ i = pairorder[h];
+ if (is_initializing) {
+ if (i == 3) {
+ control.low = 0;
+ control.high = 0;
+ } else if (((i % 2 == 1) && (oldi % 2 == 1)) ||
+ ((i % 2 == 0) && (oldi % 2 == 0))) {
+ tmp_control = b43legacy_get_lopair(phy, oldi,
+ 0);
+ memcpy(&control, tmp_control, sizeof(control));
+ } else {
+ tmp_control = b43legacy_get_lopair(phy, 3, 0);
+ memcpy(&control, tmp_control, sizeof(control));
+ }
+ }
+ /* Loop over each possible BasebandAttenuation/2 */
+ for (j = 0; j < 4; j++) {
+ if (is_initializing) {
+ tmp = i * 2 + j;
+ r27 = 0;
+ r31 = 0;
+ if (tmp > 14) {
+ r31 = 1;
+ if (tmp > 17)
+ r27 = 1;
+ if (tmp > 19)
+ r27 = 2;
+ }
+ } else {
+ tmp_control = b43legacy_get_lopair(phy, i,
+ j * 2);
+ if (!tmp_control->used)
+ continue;
+ memcpy(&control, tmp_control, sizeof(control));
+ r27 = 3;
+ r31 = 0;
+ }
+ b43legacy_radio_write16(dev, 0x43, i);
+ b43legacy_radio_write16(dev, 0x52, phy->txctl2);
+ udelay(10);
+ b43legacy_voluntary_preempt();
+
+ b43legacy_phy_set_baseband_attenuation(dev, j * 2);
+
+ tmp = (regstack[10] & 0xFFF0);
+ if (r31)
+ tmp |= 0x0008;
+ b43legacy_radio_write16(dev, 0x007A, tmp);
+
+ tmp_control = b43legacy_get_lopair(phy, i, j * 2);
+ b43legacy_phy_lo_g_state(dev, &control, tmp_control,
+ r27);
+ }
+ oldi = i;
+ }
+ /* Loop over each possible RadioAttenuation (10-13) */
+ for (i = 10; i < 14; i++) {
+ /* Loop over each possible BasebandAttenuation/2 */
+ for (j = 0; j < 4; j++) {
+ if (is_initializing) {
+ tmp_control = b43legacy_get_lopair(phy, i - 9,
+ j * 2);
+ memcpy(&control, tmp_control, sizeof(control));
+ /* FIXME: The next line is wrong, as the
+ * following if statement can never trigger. */
+ tmp = (i - 9) * 2 + j - 5;
+ r27 = 0;
+ r31 = 0;
+ if (tmp > 14) {
+ r31 = 1;
+ if (tmp > 17)
+ r27 = 1;
+ if (tmp > 19)
+ r27 = 2;
+ }
+ } else {
+ tmp_control = b43legacy_get_lopair(phy, i - 9,
+ j * 2);
+ if (!tmp_control->used)
+ continue;
+ memcpy(&control, tmp_control, sizeof(control));
+ r27 = 3;
+ r31 = 0;
+ }
+ b43legacy_radio_write16(dev, 0x43, i - 9);
+ /* FIXME: shouldn't txctl1 be zero in the next line
+ * and 3 in the loop above? */
+ b43legacy_radio_write16(dev, 0x52,
+ phy->txctl2
+ | (3/*txctl1*/ << 4));
+ udelay(10);
+ b43legacy_voluntary_preempt();
+
+ b43legacy_phy_set_baseband_attenuation(dev, j * 2);
+
+ tmp = (regstack[10] & 0xFFF0);
+ if (r31)
+ tmp |= 0x0008;
+ b43legacy_radio_write16(dev, 0x7A, tmp);
+
+ tmp_control = b43legacy_get_lopair(phy, i, j * 2);
+ b43legacy_phy_lo_g_state(dev, &control, tmp_control,
+ r27);
+ }
+ }
+
+ /* Restoration */
+ if (phy->gmode) {
+ b43legacy_phy_write(dev, 0x0015, 0xE300);
+ b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA0);
+ udelay(5);
+ b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA2);
+ udelay(2);
+ b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA3);
+ b43legacy_voluntary_preempt();
+ } else
+ b43legacy_phy_write(dev, 0x0015, r27 | 0xEFA0);
+ b43legacy_phy_lo_adjust(dev, is_initializing);
+ b43legacy_phy_write(dev, 0x002E, 0x807F);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x002F, 0x0202);
+ else
+ b43legacy_phy_write(dev, 0x002F, 0x0101);
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, regstack[4]);
+ b43legacy_phy_write(dev, 0x0015, regstack[5]);
+ b43legacy_phy_write(dev, 0x002A, regstack[6]);
+ b43legacy_phy_write(dev, 0x0035, regstack[7]);
+ b43legacy_phy_write(dev, 0x0060, regstack[8]);
+ b43legacy_radio_write16(dev, 0x0043, regstack[9]);
+ b43legacy_radio_write16(dev, 0x007A, regstack[10]);
+ regstack[11] &= 0x00F0;
+ regstack[11] |= (b43legacy_radio_read16(dev, 0x52) & 0x000F);
+ b43legacy_radio_write16(dev, 0x52, regstack[11]);
+ b43legacy_write16(dev, 0x03E2, regstack[3]);
+ if (phy->gmode) {
+ b43legacy_phy_write(dev, 0x0811, regstack[12]);
+ b43legacy_phy_write(dev, 0x0812, regstack[13]);
+ b43legacy_phy_write(dev, 0x0814, regstack[14]);
+ b43legacy_phy_write(dev, 0x0815, regstack[15]);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]);
+ b43legacy_phy_write(dev, 0x0802, regstack[1]);
+ }
+ b43legacy_radio_selectchannel(dev, oldchannel, 1);
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+ {
+ /* Sanity check for all lopairs. */
+ for (i = 0; i < B43legacy_LO_COUNT; i++) {
+ tmp_control = phy->_lo_pairs + i;
+ if (tmp_control->low < -8 || tmp_control->low > 8 ||
+ tmp_control->high < -8 || tmp_control->high > 8)
+ b43legacywarn(dev->wl,
+ "WARNING: Invalid LOpair (low: %d, high:"
+ " %d, index: %d)\n",
+ tmp_control->low, tmp_control->high, i);
+ }
+ }
+#endif /* CONFIG_B43LEGACY_DEBUG */
+}
+
+static
+void b43legacy_phy_lo_mark_current_used(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_lopair *pair;
+
+ pair = b43legacy_current_lopair(dev);
+ pair->used = 1;
+}
+
+void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ struct b43legacy_lopair *pair;
+ int i;
+
+ for (i = 0; i < B43legacy_LO_COUNT; i++) {
+ pair = phy->_lo_pairs + i;
+ pair->used = 0;
+ }
+}
+
+/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
+ * This function converts a TSSI value to dBm in Q5.2
+ */
+static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ s8 dbm = 0;
+ s32 tmp;
+
+ tmp = phy->idle_tssi;
+ tmp += tssi;
+ tmp -= phy->savedpctlreg;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ case B43legacy_PHYTYPE_G:
+ tmp = limit_value(tmp, 0x00, 0x3F);
+ dbm = phy->tssi2dbm[tmp];
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+
+ return dbm;
+}
+
+/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
+void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 tmp;
+ u16 txpower;
+ s8 v0;
+ s8 v1;
+ s8 v2;
+ s8 v3;
+ s8 average;
+ int max_pwr;
+ s16 desired_pwr;
+ s16 estimated_pwr;
+ s16 pwr_adjust;
+ s16 radio_att_delta;
+ s16 baseband_att_delta;
+ s16 radio_attenuation;
+ s16 baseband_attenuation;
+ unsigned long phylock_flags;
+
+ if (phy->savedpctlreg == 0xFFFF)
+ return;
+ if ((dev->dev->bus->boardinfo.type == 0x0416) &&
+ is_bcm_board_vendor(dev))
+ return;
+#ifdef CONFIG_B43LEGACY_DEBUG
+ if (phy->manual_txpower_control)
+ return;
+#endif
+
+ B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
+ phy->type == B43legacy_PHYTYPE_G));
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0058);
+ v0 = (s8)(tmp & 0x00FF);
+ v1 = (s8)((tmp & 0xFF00) >> 8);
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005A);
+ v2 = (s8)(tmp & 0x00FF);
+ v3 = (s8)((tmp & 0xFF00) >> 8);
+ tmp = 0;
+
+ if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) {
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ 0x0070);
+ v0 = (s8)(tmp & 0x00FF);
+ v1 = (s8)((tmp & 0xFF00) >> 8);
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+ 0x0072);
+ v2 = (s8)(tmp & 0x00FF);
+ v3 = (s8)((tmp & 0xFF00) >> 8);
+ if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F)
+ return;
+ v0 = (v0 + 0x20) & 0x3F;
+ v1 = (v1 + 0x20) & 0x3F;
+ v2 = (v2 + 0x20) & 0x3F;
+ v3 = (v3 + 0x20) & 0x3F;
+ tmp = 1;
+ }
+ b43legacy_radio_clear_tssi(dev);
+
+ average = (v0 + v1 + v2 + v3 + 2) / 4;
+
+ if (tmp && (b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005E)
+ & 0x8))
+ average -= 13;
+
+ estimated_pwr = b43legacy_phy_estimate_power_out(dev, average);
+
+ max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
+
+ if ((dev->dev->bus->sprom.r1.boardflags_lo
+ & B43legacy_BFL_PACTRL) &&
+ (phy->type == B43legacy_PHYTYPE_G))
+ max_pwr -= 0x3;
+ if (unlikely(max_pwr <= 0)) {
+ b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM."
+ "\n");
+ max_pwr = 74; /* fake it */
+ dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr;
+ }
+
+ /* Use regulatory information to get the maximum power.
+ * In the absence of such data from mac80211, we will use 20 dBm, which
+ * is the value for the EU, US, Canada, and most of the world.
+ * The regulatory maximum is reduced by the antenna gain (from sprom)
+ * and 1.5 dBm (a safety factor??). The result is in Q5.2 format
+ * which accounts for the factor of 4 */
+#define REG_MAX_PWR 20
+ max_pwr = min(REG_MAX_PWR * 4 - dev->dev->bus->sprom.r1.antenna_gain_bg
+ - 0x6, max_pwr);
+
+ /* find the desired power in Q5.2 - power_level is in dBm
+ * and limit it - max_pwr is already in Q5.2 */
+ desired_pwr = limit_value(phy->power_level << 2, 0, max_pwr);
+ if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER))
+ b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT
+ " dBm, Desired TX power output: " Q52_FMT
+ " dBm\n", Q52_ARG(estimated_pwr),
+ Q52_ARG(desired_pwr));
+ /* Check if we need to adjust the current power. The factor of 2 is
+ * for damping */
+ pwr_adjust = (desired_pwr - estimated_pwr) / 2;
+ /* RF attenuation delta
+ * The minus sign is because lower attenuation => more power */
+ radio_att_delta = -(pwr_adjust + 7) >> 3;
+ /* Baseband attenuation delta */
+ baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta);
+ /* Do we need to adjust anything? */
+ if ((radio_att_delta == 0) && (baseband_att_delta == 0)) {
+ b43legacy_phy_lo_mark_current_used(dev);
+ return;
+ }
+
+ /* Calculate the new attenuation values. */
+ baseband_attenuation = phy->bbatt;
+ baseband_attenuation += baseband_att_delta;
+ radio_attenuation = phy->rfatt;
+ radio_attenuation += radio_att_delta;
+
+ /* Get baseband and radio attenuation values into permitted ranges.
+ * baseband 0-11, radio 0-9.
+ * Radio attenuation affects power level 4 times as much as baseband.
+ */
+ if (radio_attenuation < 0) {
+ baseband_attenuation -= (4 * -radio_attenuation);
+ radio_attenuation = 0;
+ } else if (radio_attenuation > 9) {
+ baseband_attenuation += (4 * (radio_attenuation - 9));
+ radio_attenuation = 9;
+ } else {
+ while (baseband_attenuation < 0 && radio_attenuation > 0) {
+ baseband_attenuation += 4;
+ radio_attenuation--;
+ }
+ while (baseband_attenuation > 11 && radio_attenuation < 9) {
+ baseband_attenuation -= 4;
+ radio_attenuation++;
+ }
+ }
+ baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
+
+ txpower = phy->txctl1;
+ if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
+ if (radio_attenuation <= 1) {
+ if (txpower == 0) {
+ txpower = 3;
+ radio_attenuation += 2;
+ baseband_attenuation += 2;
+ } else if (dev->dev->bus->sprom.r1.boardflags_lo
+ & B43legacy_BFL_PACTRL) {
+ baseband_attenuation += 4 *
+ (radio_attenuation - 2);
+ radio_attenuation = 2;
+ }
+ } else if (radio_attenuation > 4 && txpower != 0) {
+ txpower = 0;
+ if (baseband_attenuation < 3) {
+ radio_attenuation -= 3;
+ baseband_attenuation += 2;
+ } else {
+ radio_attenuation -= 2;
+ baseband_attenuation -= 2;
+ }
+ }
+ }
+ /* Save the control values */
+ phy->txctl1 = txpower;
+ baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
+ radio_attenuation = limit_value(radio_attenuation, 0, 9);
+ phy->rfatt = radio_attenuation;
+ phy->bbatt = baseband_attenuation;
+
+ /* Adjust the hardware */
+ b43legacy_phy_lock(dev, phylock_flags);
+ b43legacy_radio_lock(dev);
+ b43legacy_radio_set_txpower_bg(dev, baseband_attenuation,
+ radio_attenuation, txpower);
+ b43legacy_phy_lo_mark_current_used(dev);
+ b43legacy_radio_unlock(dev);
+ b43legacy_phy_unlock(dev, phylock_flags);
+}
+
+static inline
+s32 b43legacy_tssi2dbm_ad(s32 num, s32 den)
+{
+ if (num < 0)
+ return num/den;
+ else
+ return (num+den/2)/den;
+}
+
+static inline
+s8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2)
+{
+ s32 m1;
+ s32 m2;
+ s32 f = 256;
+ s32 q;
+ s32 delta;
+ s8 i = 0;
+
+ m1 = b43legacy_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
+ m2 = max(b43legacy_tssi2dbm_ad(32768 + index * pab2, 256), 1);
+ do {
+ if (i > 15)
+ return -EINVAL;
+ q = b43legacy_tssi2dbm_ad(f * 4096 -
+ b43legacy_tssi2dbm_ad(m2 * f, 16) *
+ f, 2048);
+ delta = abs(q - f);
+ f = q;
+ i++;
+ } while (delta >= 2);
+ entry[index] = limit_value(b43legacy_tssi2dbm_ad(m1 * f, 8192),
+ -127, 128);
+ return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
+int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ s16 pab0;
+ s16 pab1;
+ s16 pab2;
+ u8 idx;
+ s8 *dyn_tssi2dbm;
+
+ B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B ||
+ phy->type == B43legacy_PHYTYPE_G));
+ pab0 = (s16)(dev->dev->bus->sprom.r1.pa0b0);
+ pab1 = (s16)(dev->dev->bus->sprom.r1.pa0b1);
+ pab2 = (s16)(dev->dev->bus->sprom.r1.pa0b2);
+
+ if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
+ phy->idle_tssi = 0x34;
+ phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
+ return 0;
+ }
+
+ if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
+ pab0 != -1 && pab1 != -1 && pab2 != -1) {
+ /* The pabX values are set in SPROM. Use them. */
+ if ((s8)dev->dev->bus->sprom.r1.itssi_bg != 0 &&
+ (s8)dev->dev->bus->sprom.r1.itssi_bg != -1)
+ phy->idle_tssi = (s8)(dev->dev->bus->sprom.r1.itssi_bg);
+ else
+ phy->idle_tssi = 62;
+ dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
+ if (dyn_tssi2dbm == NULL) {
+ b43legacyerr(dev->wl, "Could not allocate memory"
+ "for tssi2dbm table\n");
+ return -ENOMEM;
+ }
+ for (idx = 0; idx < 64; idx++)
+ if (b43legacy_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0,
+ pab1, pab2)) {
+ phy->tssi2dbm = NULL;
+ b43legacyerr(dev->wl, "Could not generate "
+ "tssi2dBm table\n");
+ kfree(dyn_tssi2dbm);
+ return -ENODEV;
+ }
+ phy->tssi2dbm = dyn_tssi2dbm;
+ phy->dyn_tssi_tbl = 1;
+ } else {
+ /* pabX values not set in SPROM. */
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ phy->idle_tssi = 0x34;
+ phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
+ break;
+ case B43legacy_PHYTYPE_G:
+ phy->idle_tssi = 0x34;
+ phy->tssi2dbm = b43legacy_tssi2dbm_g_table;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int b43legacy_phy_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ int err = -ENODEV;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ switch (phy->rev) {
+ case 2:
+ b43legacy_phy_initb2(dev);
+ err = 0;
+ break;
+ case 4:
+ b43legacy_phy_initb4(dev);
+ err = 0;
+ break;
+ case 5:
+ b43legacy_phy_initb5(dev);
+ err = 0;
+ break;
+ case 6:
+ b43legacy_phy_initb6(dev);
+ err = 0;
+ break;
+ }
+ break;
+ case B43legacy_PHYTYPE_G:
+ b43legacy_phy_initg(dev);
+ err = 0;
+ break;
+ }
+ if (err)
+ b43legacyerr(dev->wl, "Unknown PHYTYPE found\n");
+
+ return err;
+}
+
+void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 antennadiv;
+ u16 offset;
+ u16 value;
+ u32 ucodeflags;
+
+ antennadiv = phy->antenna_diversity;
+
+ if (antennadiv == 0xFFFF)
+ antennadiv = 3;
+ B43legacy_WARN_ON(antennadiv > 3);
+
+ ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET);
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ ucodeflags & ~B43legacy_UCODEFLAG_AUTODIV);
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_G:
+ offset = 0x0400;
+
+ if (antennadiv == 2)
+ value = (3/*automatic*/ << 7);
+ else
+ value = (antennadiv << 7);
+ b43legacy_phy_write(dev, offset + 1,
+ (b43legacy_phy_read(dev, offset + 1)
+ & 0x7E7F) | value);
+
+ if (antennadiv >= 2) {
+ if (antennadiv == 2)
+ value = (antennadiv << 7);
+ else
+ value = (0/*force0*/ << 7);
+ b43legacy_phy_write(dev, offset + 0x2B,
+ (b43legacy_phy_read(dev,
+ offset + 0x2B)
+ & 0xFEFF) | value);
+ }
+
+ if (phy->type == B43legacy_PHYTYPE_G) {
+ if (antennadiv >= 2)
+ b43legacy_phy_write(dev, 0x048C,
+ b43legacy_phy_read(dev,
+ 0x048C) | 0x2000);
+ else
+ b43legacy_phy_write(dev, 0x048C,
+ b43legacy_phy_read(dev,
+ 0x048C) & ~0x2000);
+ if (phy->rev >= 2) {
+ b43legacy_phy_write(dev, 0x0461,
+ b43legacy_phy_read(dev,
+ 0x0461) | 0x0010);
+ b43legacy_phy_write(dev, 0x04AD,
+ (b43legacy_phy_read(dev,
+ 0x04AD)
+ & 0x00FF) | 0x0015);
+ if (phy->rev == 2)
+ b43legacy_phy_write(dev, 0x0427,
+ 0x0008);
+ else
+ b43legacy_phy_write(dev, 0x0427,
+ (b43legacy_phy_read(dev, 0x0427)
+ & 0x00FF) | 0x0008);
+ } else if (phy->rev >= 6)
+ b43legacy_phy_write(dev, 0x049B, 0x00DC);
+ } else {
+ if (phy->rev < 3)
+ b43legacy_phy_write(dev, 0x002B,
+ (b43legacy_phy_read(dev,
+ 0x002B) & 0x00FF)
+ | 0x0024);
+ else {
+ b43legacy_phy_write(dev, 0x0061,
+ b43legacy_phy_read(dev,
+ 0x0061) | 0x0010);
+ if (phy->rev == 3) {
+ b43legacy_phy_write(dev, 0x0093,
+ 0x001D);
+ b43legacy_phy_write(dev, 0x0027,
+ 0x0008);
+ } else {
+ b43legacy_phy_write(dev, 0x0093,
+ 0x003A);
+ b43legacy_phy_write(dev, 0x0027,
+ (b43legacy_phy_read(dev, 0x0027)
+ & 0x00FF) | 0x0008);
+ }
+ }
+ }
+ break;
+ case B43legacy_PHYTYPE_B:
+ if (dev->dev->id.revision == 2)
+ value = (3/*automatic*/ << 7);
+ else
+ value = (antennadiv << 7);
+ b43legacy_phy_write(dev, 0x03E2,
+ (b43legacy_phy_read(dev, 0x03E2)
+ & 0xFE7F) | value);
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+
+ if (antennadiv >= 2) {
+ ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET);
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ ucodeflags | B43legacy_UCODEFLAG_AUTODIV);
+ }
+
+ phy->antenna_diversity = antennadiv;
+}
+
+/* Set the PowerSavingControlBits.
+ * Bitvalues:
+ * 0 => unset the bit
+ * 1 => set the bit
+ * -1 => calculate the bit
+ */
+void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev,
+ int bit25, int bit26)
+{
+ int i;
+ u32 status;
+
+/* FIXME: Force 25 to off and 26 to on for now: */
+bit25 = 0;
+bit26 = 1;
+
+ if (bit25 == -1) {
+ /* TODO: If powersave is not off and FIXME is not set and we
+ * are not in adhoc and thus is not an AP and we arei
+ * associated, set bit 25 */
+ }
+ if (bit26 == -1) {
+ /* TODO: If the device is awake or this is an AP, or we are
+ * scanning, or FIXME, or we are associated, or FIXME,
+ * or the latest PS-Poll packet sent was successful,
+ * set bit26 */
+ }
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ if (bit25)
+ status |= B43legacy_SBF_PS1;
+ else
+ status &= ~B43legacy_SBF_PS1;
+ if (bit26)
+ status |= B43legacy_SBF_PS2;
+ else
+ status &= ~B43legacy_SBF_PS2;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+ if (bit26 && dev->dev->id.revision >= 5) {
+ for (i = 0; i < 100; i++) {
+ if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+ 0x0040) != 4)
+ break;
+ udelay(10);
+ }
+ }
+}
diff --git a/drivers/net/wireless/b43legacy/phy.h b/drivers/net/wireless/b43legacy/phy.h
new file mode 100644
index 00000000000..f11b4271714
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/phy.h
@@ -0,0 +1,219 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mbuesch@freenet.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef B43legacy_PHY_H_
+#define B43legacy_PHY_H_
+
+#include <linux/types.h>
+
+enum {
+ B43legacy_ANTENNA0, /* Antenna 0 */
+ B43legacy_ANTENNA1, /* Antenna 0 */
+ B43legacy_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */
+ B43legacy_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */
+
+ B43legacy_ANTENNA_AUTO = B43legacy_ANTENNA_AUTO0,
+ B43legacy_ANTENNA_DEFAULT = B43legacy_ANTENNA_AUTO,
+};
+
+enum {
+ B43legacy_INTERFMODE_NONE,
+ B43legacy_INTERFMODE_NONWLAN,
+ B43legacy_INTERFMODE_MANUALWLAN,
+ B43legacy_INTERFMODE_AUTOWLAN,
+};
+
+/*** PHY Registers ***/
+
+/* Routing */
+#define B43legacy_PHYROUTE_OFDM_GPHY 0x400
+#define B43legacy_PHYROUTE_EXT_GPHY 0x800
+
+/* Base registers. */
+#define B43legacy_PHY_BASE(reg) (reg)
+/* OFDM (A) registers of a G-PHY */
+#define B43legacy_PHY_OFDM(reg) ((reg) | B43legacy_PHYROUTE_OFDM_GPHY)
+/* Extended G-PHY registers */
+#define B43legacy_PHY_EXTG(reg) ((reg) | B43legacy_PHYROUTE_EXT_GPHY)
+
+
+/* Extended G-PHY Registers */
+#define B43legacy_PHY_CLASSCTL B43legacy_PHY_EXTG(0x02) /* Classify control */
+#define B43legacy_PHY_GTABCTL B43legacy_PHY_EXTG(0x03) /* G-PHY table control (see below) */
+#define B43legacy_PHY_GTABOFF 0x03FF /* G-PHY table offset (see below) */
+#define B43legacy_PHY_GTABNR 0xFC00 /* G-PHY table number (see below) */
+#define B43legacy_PHY_GTABNR_SHIFT 10
+#define B43legacy_PHY_GTABDATA B43legacy_PHY_EXTG(0x04) /* G-PHY table data */
+#define B43legacy_PHY_LO_MASK B43legacy_PHY_EXTG(0x0F) /* Local Oscillator control mask */
+#define B43legacy_PHY_LO_CTL B43legacy_PHY_EXTG(0x10) /* Local Oscillator control */
+#define B43legacy_PHY_RFOVER B43legacy_PHY_EXTG(0x11) /* RF override */
+#define B43legacy_PHY_RFOVERVAL B43legacy_PHY_EXTG(0x12) /* RF override value */
+/*** OFDM table numbers ***/
+#define B43legacy_OFDMTAB(number, offset) \
+ (((number) << B43legacy_PHY_OTABLENR_SHIFT) \
+ | (offset))
+#define B43legacy_OFDMTAB_AGC1 B43legacy_OFDMTAB(0x00, 0)
+#define B43legacy_OFDMTAB_GAIN0 B43legacy_OFDMTAB(0x00, 0)
+#define B43legacy_OFDMTAB_GAINX B43legacy_OFDMTAB(0x01, 0)
+#define B43legacy_OFDMTAB_GAIN1 B43legacy_OFDMTAB(0x01, 4)
+#define B43legacy_OFDMTAB_AGC3 B43legacy_OFDMTAB(0x02, 0)
+#define B43legacy_OFDMTAB_GAIN2 B43legacy_OFDMTAB(0x02, 3)
+#define B43legacy_OFDMTAB_LNAHPFGAIN1 B43legacy_OFDMTAB(0x03, 0)
+#define B43legacy_OFDMTAB_WRSSI B43legacy_OFDMTAB(0x04, 0)
+#define B43legacy_OFDMTAB_LNAHPFGAIN2 B43legacy_OFDMTAB(0x04, 0)
+#define B43legacy_OFDMTAB_NOISESCALE B43legacy_OFDMTAB(0x05, 0)
+#define B43legacy_OFDMTAB_AGC2 B43legacy_OFDMTAB(0x06, 0)
+#define B43legacy_OFDMTAB_ROTOR B43legacy_OFDMTAB(0x08, 0)
+#define B43legacy_OFDMTAB_ADVRETARD B43legacy_OFDMTAB(0x09, 0)
+#define B43legacy_OFDMTAB_DAC B43legacy_OFDMTAB(0x0C, 0)
+#define B43legacy_OFDMTAB_DC B43legacy_OFDMTAB(0x0E, 7)
+#define B43legacy_OFDMTAB_PWRDYN2 B43legacy_OFDMTAB(0x0E, 12)
+#define B43legacy_OFDMTAB_LNAGAIN B43legacy_OFDMTAB(0x0E, 13)
+
+#define B43legacy_OFDMTAB_LPFGAIN B43legacy_OFDMTAB(0x0F, 12)
+#define B43legacy_OFDMTAB_RSSI B43legacy_OFDMTAB(0x10, 0)
+
+#define B43legacy_OFDMTAB_AGC1_R1 B43legacy_OFDMTAB(0x13, 0)
+#define B43legacy_OFDMTAB_GAINX_R1 B43legacy_OFDMTAB(0x14, 0)
+#define B43legacy_OFDMTAB_MINSIGSQ B43legacy_OFDMTAB(0x14, 1)
+#define B43legacy_OFDMTAB_AGC3_R1 B43legacy_OFDMTAB(0x15, 0)
+#define B43legacy_OFDMTAB_WRSSI_R1 B43legacy_OFDMTAB(0x15, 4)
+#define B43legacy_OFDMTAB_TSSI B43legacy_OFDMTAB(0x15, 0)
+#define B43legacy_OFDMTAB_DACRFPABB B43legacy_OFDMTAB(0x16, 0)
+#define B43legacy_OFDMTAB_DACOFF B43legacy_OFDMTAB(0x17, 0)
+#define B43legacy_OFDMTAB_DCBIAS B43legacy_OFDMTAB(0x18, 0)
+
+void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt);
+
+/* OFDM (A) PHY Registers */
+#define B43legacy_PHY_VERSION_OFDM B43legacy_PHY_OFDM(0x00) /* Versioning register for A-PHY */
+#define B43legacy_PHY_BBANDCFG B43legacy_PHY_OFDM(0x01) /* Baseband config */
+#define B43legacy_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */
+#define B43legacy_PHY_BBANDCFG_RXANT_SHIFT 7
+#define B43legacy_PHY_PWRDOWN B43legacy_PHY_OFDM(0x03) /* Powerdown */
+#define B43legacy_PHY_CRSTHRES1 B43legacy_PHY_OFDM(0x06) /* CRS Threshold 1 */
+#define B43legacy_PHY_LNAHPFCTL B43legacy_PHY_OFDM(0x1C) /* LNA/HPF control */
+#define B43legacy_PHY_ADIVRELATED B43legacy_PHY_OFDM(0x27) /* FIXME rename */
+#define B43legacy_PHY_CRS0 B43legacy_PHY_OFDM(0x29)
+#define B43legacy_PHY_ANTDWELL B43legacy_PHY_OFDM(0x2B) /* Antenna dwell */
+#define B43legacy_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */
+#define B43legacy_PHY_ENCORE B43legacy_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */
+#define B43legacy_PHY_ENCORE_EN 0x0200 /* Encore enable */
+#define B43legacy_PHY_LMS B43legacy_PHY_OFDM(0x55)
+#define B43legacy_PHY_OFDM61 B43legacy_PHY_OFDM(0x61) /* FIXME rename */
+#define B43legacy_PHY_OFDM61_10 0x0010 /* FIXME rename */
+#define B43legacy_PHY_IQBAL B43legacy_PHY_OFDM(0x69) /* I/Q balance */
+#define B43legacy_PHY_OTABLECTL B43legacy_PHY_OFDM(0x72) /* OFDM table control (see below) */
+#define B43legacy_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */
+#define B43legacy_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */
+#define B43legacy_PHY_OTABLENR_SHIFT 10
+#define B43legacy_PHY_OTABLEI B43legacy_PHY_OFDM(0x73) /* OFDM table data I */
+#define B43legacy_PHY_OTABLEQ B43legacy_PHY_OFDM(0x74) /* OFDM table data Q */
+#define B43legacy_PHY_HPWR_TSSICTL B43legacy_PHY_OFDM(0x78) /* Hardware power TSSI control */
+#define B43legacy_PHY_NRSSITHRES B43legacy_PHY_OFDM(0x8A) /* NRSSI threshold */
+#define B43legacy_PHY_ANTWRSETT B43legacy_PHY_OFDM(0x8C) /* Antenna WR settle */
+#define B43legacy_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */
+#define B43legacy_PHY_CLIPPWRDOWNT B43legacy_PHY_OFDM(0x93) /* Clip powerdown threshold */
+#define B43legacy_PHY_OFDM9B B43legacy_PHY_OFDM(0x9B) /* FIXME rename */
+#define B43legacy_PHY_N1P1GAIN B43legacy_PHY_OFDM(0xA0)
+#define B43legacy_PHY_P1P2GAIN B43legacy_PHY_OFDM(0xA1)
+#define B43legacy_PHY_N1N2GAIN B43legacy_PHY_OFDM(0xA2)
+#define B43legacy_PHY_CLIPTHRES B43legacy_PHY_OFDM(0xA3)
+#define B43legacy_PHY_CLIPN1P2THRES B43legacy_PHY_OFDM(0xA4)
+#define B43legacy_PHY_DIVSRCHIDX B43legacy_PHY_OFDM(0xA8) /* Divider search gain/index */
+#define B43legacy_PHY_CLIPP2THRES B43legacy_PHY_OFDM(0xA9)
+#define B43legacy_PHY_CLIPP3THRES B43legacy_PHY_OFDM(0xAA)
+#define B43legacy_PHY_DIVP1P2GAIN B43legacy_PHY_OFDM(0xAB)
+#define B43legacy_PHY_DIVSRCHGAINBACK B43legacy_PHY_OFDM(0xAD) /* Divider search gain back */
+#define B43legacy_PHY_DIVSRCHGAINCHNG B43legacy_PHY_OFDM(0xAE) /* Divider search gain change */
+#define B43legacy_PHY_CRSTHRES1_R1 B43legacy_PHY_OFDM(0xC0) /* CRS Threshold 1 (rev 1 only) */
+#define B43legacy_PHY_CRSTHRES2_R1 B43legacy_PHY_OFDM(0xC1) /* CRS Threshold 2 (rev 1 only) */
+#define B43legacy_PHY_TSSIP_LTBASE B43legacy_PHY_OFDM(0x380) /* TSSI power lookup table base */
+#define B43legacy_PHY_DC_LTBASE B43legacy_PHY_OFDM(0x3A0) /* DC lookup table base */
+#define B43legacy_PHY_GAIN_LTBASE B43legacy_PHY_OFDM(0x3C0) /* Gain lookup table base */
+
+void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt);
+
+/* Masks for the different PHY versioning registers. */
+#define B43legacy_PHYVER_ANALOG 0xF000
+#define B43legacy_PHYVER_ANALOG_SHIFT 12
+#define B43legacy_PHYVER_TYPE 0x0F00
+#define B43legacy_PHYVER_TYPE_SHIFT 8
+#define B43legacy_PHYVER_VERSION 0x00FF
+
+struct b43legacy_wldev;
+
+void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev);
+#define b43legacy_phy_lock(bcm, flags) \
+ do { \
+ local_irq_save(flags); \
+ b43legacy_raw_phy_lock(bcm); \
+ } while (0)
+void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev);
+#define b43legacy_phy_unlock(bcm, flags) \
+ do { \
+ b43legacy_raw_phy_unlock(bcm); \
+ local_irq_restore(flags); \
+ } while (0)
+
+/* Card uses the loopback gain stuff */
+#define has_loopback_gain(phy) \
+ (((phy)->rev > 1) || ((phy)->gmode))
+
+u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset);
+void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val);
+
+int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev);
+int b43legacy_phy_init(struct b43legacy_wldev *dev);
+
+void b43legacy_set_rx_antenna(struct b43legacy_wldev *dev, int antenna);
+
+void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev);
+void b43legacy_phy_calibrate(struct b43legacy_wldev *dev);
+int b43legacy_phy_connect(struct b43legacy_wldev *dev, int connect);
+
+void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev);
+void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev);
+void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev);
+
+/* Adjust the LocalOscillator to the saved values.
+ * "fixed" is only set to 1 once in initialization. Set to 0 otherwise.
+ */
+void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed);
+void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev);
+
+void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev,
+ u16 baseband_attenuation);
+
+void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev,
+ int bit25, int bit26);
+
+#endif /* B43legacy_PHY_H_ */
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c
new file mode 100644
index 00000000000..de843ac147a
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/pio.c
@@ -0,0 +1,668 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ PIO Transmission
+
+ Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43legacy.h"
+#include "pio.h"
+#include "main.h"
+#include "xmit.h"
+
+#include <linux/delay.h>
+
+
+static void tx_start(struct b43legacy_pioqueue *queue)
+{
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ B43legacy_PIO_TXCTL_INIT);
+}
+
+static void tx_octet(struct b43legacy_pioqueue *queue,
+ u8 octet)
+{
+ if (queue->need_workarounds) {
+ b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ B43legacy_PIO_TXCTL_WRITELO);
+ } else {
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ B43legacy_PIO_TXCTL_WRITELO);
+ b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
+ }
+}
+
+static u16 tx_get_next_word(const u8 *txhdr,
+ const u8 *packet,
+ size_t txhdr_size,
+ unsigned int *pos)
+{
+ const u8 *source;
+ unsigned int i = *pos;
+ u16 ret;
+
+ if (i < txhdr_size)
+ source = txhdr;
+ else {
+ source = packet;
+ i -= txhdr_size;
+ }
+ ret = le16_to_cpu(*((__le16 *)(source + i)));
+ *pos += 2;
+
+ return ret;
+}
+
+static void tx_data(struct b43legacy_pioqueue *queue,
+ u8 *txhdr,
+ const u8 *packet,
+ unsigned int octets)
+{
+ u16 data;
+ unsigned int i = 0;
+
+ if (queue->need_workarounds) {
+ data = tx_get_next_word(txhdr, packet,
+ sizeof(struct b43legacy_txhdr_fw3), &i);
+ b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
+ }
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ B43legacy_PIO_TXCTL_WRITELO |
+ B43legacy_PIO_TXCTL_WRITEHI);
+ while (i < octets - 1) {
+ data = tx_get_next_word(txhdr, packet,
+ sizeof(struct b43legacy_txhdr_fw3), &i);
+ b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
+ }
+ if (octets % 2)
+ tx_octet(queue, packet[octets -
+ sizeof(struct b43legacy_txhdr_fw3) - 1]);
+}
+
+static void tx_complete(struct b43legacy_pioqueue *queue,
+ struct sk_buff *skb)
+{
+ if (queue->need_workarounds) {
+ b43legacy_pio_write(queue, B43legacy_PIO_TXDATA,
+ skb->data[skb->len - 1]);
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ B43legacy_PIO_TXCTL_WRITELO |
+ B43legacy_PIO_TXCTL_COMPLETE);
+ } else
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ B43legacy_PIO_TXCTL_COMPLETE);
+}
+
+static u16 generate_cookie(struct b43legacy_pioqueue *queue,
+ struct b43legacy_pio_txpacket *packet)
+{
+ u16 cookie = 0x0000;
+ int packetindex;
+
+ /* We use the upper 4 bits for the PIO
+ * controller ID and the lower 12 bits
+ * for the packet index (in the cache).
+ */
+ switch (queue->mmio_base) {
+ case B43legacy_MMIO_PIO1_BASE:
+ break;
+ case B43legacy_MMIO_PIO2_BASE:
+ cookie = 0x1000;
+ break;
+ case B43legacy_MMIO_PIO3_BASE:
+ cookie = 0x2000;
+ break;
+ case B43legacy_MMIO_PIO4_BASE:
+ cookie = 0x3000;
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+ packetindex = pio_txpacket_getindex(packet);
+ B43legacy_WARN_ON(!(((u16)packetindex & 0xF000) == 0x0000));
+ cookie |= (u16)packetindex;
+
+ return cookie;
+}
+
+static
+struct b43legacy_pioqueue *parse_cookie(struct b43legacy_wldev *dev,
+ u16 cookie,
+ struct b43legacy_pio_txpacket **packet)
+{
+ struct b43legacy_pio *pio = &dev->pio;
+ struct b43legacy_pioqueue *queue = NULL;
+ int packetindex;
+
+ switch (cookie & 0xF000) {
+ case 0x0000:
+ queue = pio->queue0;
+ break;
+ case 0x1000:
+ queue = pio->queue1;
+ break;
+ case 0x2000:
+ queue = pio->queue2;
+ break;
+ case 0x3000:
+ queue = pio->queue3;
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+ packetindex = (cookie & 0x0FFF);
+ B43legacy_WARN_ON(!(packetindex >= 0 && packetindex
+ < B43legacy_PIO_MAXTXPACKETS));
+ *packet = &(queue->tx_packets_cache[packetindex]);
+
+ return queue;
+}
+
+union txhdr_union {
+ struct b43legacy_txhdr_fw3 txhdr_fw3;
+};
+
+static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
+ struct sk_buff *skb,
+ struct b43legacy_pio_txpacket *packet,
+ size_t txhdr_size)
+{
+ union txhdr_union txhdr_data;
+ u8 *txhdr = NULL;
+ unsigned int octets;
+
+ txhdr = (u8 *)(&txhdr_data.txhdr_fw3);
+
+ B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
+ b43legacy_generate_txhdr(queue->dev,
+ txhdr, skb->data, skb->len,
+ &packet->txstat.control,
+ generate_cookie(queue, packet));
+
+ tx_start(queue);
+ octets = skb->len + txhdr_size;
+ if (queue->need_workarounds)
+ octets--;
+ tx_data(queue, txhdr, (u8 *)skb->data, octets);
+ tx_complete(queue, skb);
+}
+
+static void free_txpacket(struct b43legacy_pio_txpacket *packet,
+ int irq_context)
+{
+ struct b43legacy_pioqueue *queue = packet->queue;
+
+ if (packet->skb) {
+ if (irq_context)
+ dev_kfree_skb_irq(packet->skb);
+ else
+ dev_kfree_skb(packet->skb);
+ }
+ list_move(&packet->list, &queue->txfree);
+ queue->nr_txfree++;
+}
+
+static int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
+{
+ struct b43legacy_pioqueue *queue = packet->queue;
+ struct sk_buff *skb = packet->skb;
+ u16 octets;
+
+ octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3);
+ if (queue->tx_devq_size < octets) {
+ b43legacywarn(queue->dev->wl, "PIO queue too small. "
+ "Dropping packet.\n");
+ /* Drop it silently (return success) */
+ free_txpacket(packet, 1);
+ return 0;
+ }
+ B43legacy_WARN_ON(queue->tx_devq_packets >
+ B43legacy_PIO_MAXTXDEVQPACKETS);
+ B43legacy_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
+ /* Check if there is sufficient free space on the device
+ * TX queue. If not, return and let the TX tasklet
+ * retry later.
+ */
+ if (queue->tx_devq_packets == B43legacy_PIO_MAXTXDEVQPACKETS)
+ return -EBUSY;
+ if (queue->tx_devq_used + octets > queue->tx_devq_size)
+ return -EBUSY;
+ /* Now poke the device. */
+ pio_tx_write_fragment(queue, skb, packet,
+ sizeof(struct b43legacy_txhdr_fw3));
+
+ /* Account for the packet size.
+ * (We must not overflow the device TX queue)
+ */
+ queue->tx_devq_packets++;
+ queue->tx_devq_used += octets;
+
+ /* Transmission started, everything ok, move the
+ * packet to the txrunning list.
+ */
+ list_move_tail(&packet->list, &queue->txrunning);
+
+ return 0;
+}
+
+static void tx_tasklet(unsigned long d)
+{
+ struct b43legacy_pioqueue *queue = (struct b43legacy_pioqueue *)d;
+ struct b43legacy_wldev *dev = queue->dev;
+ unsigned long flags;
+ struct b43legacy_pio_txpacket *packet, *tmp_packet;
+ int err;
+ u16 txctl;
+
+ spin_lock_irqsave(&dev->wl->irq_lock, flags);
+ if (queue->tx_frozen)
+ goto out_unlock;
+ txctl = b43legacy_pio_read(queue, B43legacy_PIO_TXCTL);
+ if (txctl & B43legacy_PIO_TXCTL_SUSPEND)
+ goto out_unlock;
+
+ list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
+ /* Try to transmit the packet. This can fail, if
+ * the device queue is full. In case of failure, the
+ * packet is left in the txqueue.
+ * If transmission succeed, the packet is moved to txrunning.
+ * If it is impossible to transmit the packet, it
+ * is dropped.
+ */
+ err = pio_tx_packet(packet);
+ if (err)
+ break;
+ }
+out_unlock:
+ spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+}
+
+static void setup_txqueues(struct b43legacy_pioqueue *queue)
+{
+ struct b43legacy_pio_txpacket *packet;
+ int i;
+
+ queue->nr_txfree = B43legacy_PIO_MAXTXPACKETS;
+ for (i = 0; i < B43legacy_PIO_MAXTXPACKETS; i++) {
+ packet = &(queue->tx_packets_cache[i]);
+
+ packet->queue = queue;
+ INIT_LIST_HEAD(&packet->list);
+
+ list_add(&packet->list, &queue->txfree);
+ }
+}
+
+static
+struct b43legacy_pioqueue *b43legacy_setup_pioqueue(struct b43legacy_wldev *dev,
+ u16 pio_mmio_base)
+{
+ struct b43legacy_pioqueue *queue;
+ u32 value;
+ u16 qsize;
+
+ queue = kzalloc(sizeof(*queue), GFP_KERNEL);
+ if (!queue)
+ goto out;
+
+ queue->dev = dev;
+ queue->mmio_base = pio_mmio_base;
+ queue->need_workarounds = (dev->dev->id.revision < 3);
+
+ INIT_LIST_HEAD(&queue->txfree);
+ INIT_LIST_HEAD(&queue->txqueue);
+ INIT_LIST_HEAD(&queue->txrunning);
+ tasklet_init(&queue->txtask, tx_tasklet,
+ (unsigned long)queue);
+
+ value = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ value &= ~B43legacy_SBF_XFER_REG_BYTESWAP;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value);
+
+ qsize = b43legacy_read16(dev, queue->mmio_base
+ + B43legacy_PIO_TXQBUFSIZE);
+ if (qsize == 0) {
+ b43legacyerr(dev->wl, "This card does not support PIO "
+ "operation mode. Please use DMA mode "
+ "(module parameter pio=0).\n");
+ goto err_freequeue;
+ }
+ if (qsize <= B43legacy_PIO_TXQADJUST) {
+ b43legacyerr(dev->wl, "PIO tx device-queue too small (%u)\n",
+ qsize);
+ goto err_freequeue;
+ }
+ qsize -= B43legacy_PIO_TXQADJUST;
+ queue->tx_devq_size = qsize;
+
+ setup_txqueues(queue);
+
+out:
+ return queue;
+
+err_freequeue:
+ kfree(queue);
+ queue = NULL;
+ goto out;
+}
+
+static void cancel_transfers(struct b43legacy_pioqueue *queue)
+{
+ struct b43legacy_pio_txpacket *packet, *tmp_packet;
+
+ tasklet_disable(&queue->txtask);
+
+ list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
+ free_txpacket(packet, 0);
+ list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
+ free_txpacket(packet, 0);
+}
+
+static void b43legacy_destroy_pioqueue(struct b43legacy_pioqueue *queue)
+{
+ if (!queue)
+ return;
+
+ cancel_transfers(queue);
+ kfree(queue);
+}
+
+void b43legacy_pio_free(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_pio *pio;
+
+ if (!b43legacy_using_pio(dev))
+ return;
+ pio = &dev->pio;
+
+ b43legacy_destroy_pioqueue(pio->queue3);
+ pio->queue3 = NULL;
+ b43legacy_destroy_pioqueue(pio->queue2);
+ pio->queue2 = NULL;
+ b43legacy_destroy_pioqueue(pio->queue1);
+ pio->queue1 = NULL;
+ b43legacy_destroy_pioqueue(pio->queue0);
+ pio->queue0 = NULL;
+}
+
+int b43legacy_pio_init(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_pio *pio = &dev->pio;
+ struct b43legacy_pioqueue *queue;
+ int err = -ENOMEM;
+
+ queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO1_BASE);
+ if (!queue)
+ goto out;
+ pio->queue0 = queue;
+
+ queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO2_BASE);
+ if (!queue)
+ goto err_destroy0;
+ pio->queue1 = queue;
+
+ queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO3_BASE);
+ if (!queue)
+ goto err_destroy1;
+ pio->queue2 = queue;
+
+ queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO4_BASE);
+ if (!queue)
+ goto err_destroy2;
+ pio->queue3 = queue;
+
+ if (dev->dev->id.revision < 3)
+ dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND;
+
+ b43legacydbg(dev->wl, "PIO initialized\n");
+ err = 0;
+out:
+ return err;
+
+err_destroy2:
+ b43legacy_destroy_pioqueue(pio->queue2);
+ pio->queue2 = NULL;
+err_destroy1:
+ b43legacy_destroy_pioqueue(pio->queue1);
+ pio->queue1 = NULL;
+err_destroy0:
+ b43legacy_destroy_pioqueue(pio->queue0);
+ pio->queue0 = NULL;
+ goto out;
+}
+
+int b43legacy_pio_tx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ struct b43legacy_pioqueue *queue = dev->pio.queue1;
+ struct b43legacy_pio_txpacket *packet;
+
+ B43legacy_WARN_ON(queue->tx_suspended);
+ B43legacy_WARN_ON(list_empty(&queue->txfree));
+
+ packet = list_entry(queue->txfree.next, struct b43legacy_pio_txpacket,
+ list);
+ packet->skb = skb;
+
+ memset(&packet->txstat, 0, sizeof(packet->txstat));
+ memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
+
+ list_move_tail(&packet->list, &queue->txqueue);
+ queue->nr_txfree--;
+ queue->nr_tx_packets++;
+ B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS);
+
+ tasklet_schedule(&queue->txtask);
+
+ return 0;
+}
+
+void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+{
+ struct b43legacy_pioqueue *queue;
+ struct b43legacy_pio_txpacket *packet;
+
+ queue = parse_cookie(dev, status->cookie, &packet);
+ B43legacy_WARN_ON(!queue);
+
+ queue->tx_devq_packets--;
+ queue->tx_devq_used -= (packet->skb->len +
+ sizeof(struct b43legacy_txhdr_fw3));
+
+ if (status->acked)
+ packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+ packet->txstat.retry_count = status->frame_count - 1;
+ ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
+ &(packet->txstat));
+ packet->skb = NULL;
+
+ free_txpacket(packet, 1);
+ /* If there are packets on the txqueue, poke the tasklet
+ * to transmit them.
+ */
+ if (!list_empty(&queue->txqueue))
+ tasklet_schedule(&queue->txtask);
+}
+
+void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct b43legacy_pio *pio = &dev->pio;
+ struct b43legacy_pioqueue *queue;
+ struct ieee80211_tx_queue_stats_data *data;
+
+ queue = pio->queue1;
+ data = &(stats->data[0]);
+ data->len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree;
+ data->limit = B43legacy_PIO_MAXTXPACKETS;
+ data->count = queue->nr_tx_packets;
+}
+
+static void pio_rx_error(struct b43legacy_pioqueue *queue,
+ int clear_buffers,
+ const char *error)
+{
+ int i;
+
+ b43legacyerr(queue->dev->wl, "PIO RX error: %s\n", error);
+ b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
+ B43legacy_PIO_RXCTL_READY);
+ if (clear_buffers) {
+ B43legacy_WARN_ON(queue->mmio_base != B43legacy_MMIO_PIO1_BASE);
+ for (i = 0; i < 15; i++) {
+ /* Dummy read. */
+ b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+ }
+ }
+}
+
+void b43legacy_pio_rx(struct b43legacy_pioqueue *queue)
+{
+ __le16 preamble[21] = { 0 };
+ struct b43legacy_rxhdr_fw3 *rxhdr;
+ u16 tmp;
+ u16 len;
+ u16 macstat;
+ int i;
+ int preamble_readwords;
+ struct sk_buff *skb;
+
+ tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
+ if (!(tmp & B43legacy_PIO_RXCTL_DATAAVAILABLE))
+ return;
+ b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
+ B43legacy_PIO_RXCTL_DATAAVAILABLE);
+
+ for (i = 0; i < 10; i++) {
+ tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
+ if (tmp & B43legacy_PIO_RXCTL_READY)
+ goto data_ready;
+ udelay(10);
+ }
+ b43legacydbg(queue->dev->wl, "PIO RX timed out\n");
+ return;
+data_ready:
+
+ len = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+ if (unlikely(len > 0x700)) {
+ pio_rx_error(queue, 0, "len > 0x700");
+ return;
+ }
+ if (unlikely(len == 0 && queue->mmio_base !=
+ B43legacy_MMIO_PIO4_BASE)) {
+ pio_rx_error(queue, 0, "len == 0");
+ return;
+ }
+ preamble[0] = cpu_to_le16(len);
+ if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE)
+ preamble_readwords = 14 / sizeof(u16);
+ else
+ preamble_readwords = 18 / sizeof(u16);
+ for (i = 0; i < preamble_readwords; i++) {
+ tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+ preamble[i + 1] = cpu_to_le16(tmp);
+ }
+ rxhdr = (struct b43legacy_rxhdr_fw3 *)preamble;
+ macstat = le16_to_cpu(rxhdr->mac_status);
+ if (macstat & B43legacy_RX_MAC_FCSERR) {
+ pio_rx_error(queue,
+ (queue->mmio_base == B43legacy_MMIO_PIO1_BASE),
+ "Frame FCS error");
+ return;
+ }
+ if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) {
+ /* We received an xmit status. */
+ struct b43legacy_hwtxstatus *hw;
+
+ hw = (struct b43legacy_hwtxstatus *)(preamble + 1);
+ b43legacy_handle_hwtxstatus(queue->dev, hw);
+
+ return;
+ }
+
+ skb = dev_alloc_skb(len);
+ if (unlikely(!skb)) {
+ pio_rx_error(queue, 1, "OOM");
+ return;
+ }
+ skb_put(skb, len);
+ for (i = 0; i < len - 1; i += 2) {
+ tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+ *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
+ }
+ if (len % 2) {
+ tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+ skb->data[len - 1] = (tmp & 0x00FF);
+ }
+ b43legacy_rx(queue->dev, skb, rxhdr);
+}
+
+void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue)
+{
+ b43legacy_power_saving_ctl_bits(queue->dev, -1, 1);
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
+ | B43legacy_PIO_TXCTL_SUSPEND);
+}
+
+void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue)
+{
+ b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+ b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
+ & ~B43legacy_PIO_TXCTL_SUSPEND);
+ b43legacy_power_saving_ctl_bits(queue->dev, -1, -1);
+ tasklet_schedule(&queue->txtask);
+}
+
+void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_pio *pio;
+
+ B43legacy_WARN_ON(!b43legacy_using_pio(dev));
+ pio = &dev->pio;
+ pio->queue0->tx_frozen = 1;
+ pio->queue1->tx_frozen = 1;
+ pio->queue2->tx_frozen = 1;
+ pio->queue3->tx_frozen = 1;
+}
+
+void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_pio *pio;
+
+ B43legacy_WARN_ON(!b43legacy_using_pio(dev));
+ pio = &dev->pio;
+ pio->queue0->tx_frozen = 0;
+ pio->queue1->tx_frozen = 0;
+ pio->queue2->tx_frozen = 0;
+ pio->queue3->tx_frozen = 0;
+ if (!list_empty(&pio->queue0->txqueue))
+ tasklet_schedule(&pio->queue0->txtask);
+ if (!list_empty(&pio->queue1->txqueue))
+ tasklet_schedule(&pio->queue1->txtask);
+ if (!list_empty(&pio->queue2->txqueue))
+ tasklet_schedule(&pio->queue2->txtask);
+ if (!list_empty(&pio->queue3->txqueue))
+ tasklet_schedule(&pio->queue3->txtask);
+}
diff --git a/drivers/net/wireless/b43legacy/pio.h b/drivers/net/wireless/b43legacy/pio.h
new file mode 100644
index 00000000000..5bfed0c4003
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/pio.h
@@ -0,0 +1,172 @@
+#ifndef B43legacy_PIO_H_
+#define B43legacy_PIO_H_
+
+#include "b43legacy.h"
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+
+#define B43legacy_PIO_TXCTL 0x00
+#define B43legacy_PIO_TXDATA 0x02
+#define B43legacy_PIO_TXQBUFSIZE 0x04
+#define B43legacy_PIO_RXCTL 0x08
+#define B43legacy_PIO_RXDATA 0x0A
+
+#define B43legacy_PIO_TXCTL_WRITELO (1 << 0)
+#define B43legacy_PIO_TXCTL_WRITEHI (1 << 1)
+#define B43legacy_PIO_TXCTL_COMPLETE (1 << 2)
+#define B43legacy_PIO_TXCTL_INIT (1 << 3)
+#define B43legacy_PIO_TXCTL_SUSPEND (1 << 7)
+
+#define B43legacy_PIO_RXCTL_DATAAVAILABLE (1 << 0)
+#define B43legacy_PIO_RXCTL_READY (1 << 1)
+
+/* PIO constants */
+#define B43legacy_PIO_MAXTXDEVQPACKETS 31
+#define B43legacy_PIO_TXQADJUST 80
+
+/* PIO tuning knobs */
+#define B43legacy_PIO_MAXTXPACKETS 256
+
+
+
+#ifdef CONFIG_B43LEGACY_PIO
+
+
+struct b43legacy_pioqueue;
+struct b43legacy_xmitstatus;
+
+struct b43legacy_pio_txpacket {
+ struct b43legacy_pioqueue *queue;
+ struct sk_buff *skb;
+ struct ieee80211_tx_status txstat;
+ struct list_head list;
+};
+
+#define pio_txpacket_getindex(packet) ((int)((packet) - \
+ (packet)->queue->tx_packets_cache))
+
+struct b43legacy_pioqueue {
+ struct b43legacy_wldev *dev;
+ u16 mmio_base;
+
+ bool tx_suspended;
+ bool tx_frozen;
+ bool need_workarounds; /* Workarounds needed for core.rev < 3 */
+
+ /* Adjusted size of the device internal TX buffer. */
+ u16 tx_devq_size;
+ /* Used octets of the device internal TX buffer. */
+ u16 tx_devq_used;
+ /* Used packet slots in the device internal TX buffer. */
+ u8 tx_devq_packets;
+ /* Packets from the txfree list can
+ * be taken on incoming TX requests.
+ */
+ struct list_head txfree;
+ unsigned int nr_txfree;
+ /* Packets on the txqueue are queued,
+ * but not completely written to the chip, yet.
+ */
+ struct list_head txqueue;
+ /* Packets on the txrunning queue are completely
+ * posted to the device. We are waiting for the txstatus.
+ */
+ struct list_head txrunning;
+ /* Total number or packets sent.
+ * (This counter can obviously wrap).
+ */
+ unsigned int nr_tx_packets;
+ struct tasklet_struct txtask;
+ struct b43legacy_pio_txpacket
+ tx_packets_cache[B43legacy_PIO_MAXTXPACKETS];
+};
+
+static inline
+u16 b43legacy_pio_read(struct b43legacy_pioqueue *queue,
+ u16 offset)
+{
+ return b43legacy_read16(queue->dev, queue->mmio_base + offset);
+}
+
+static inline
+void b43legacy_pio_write(struct b43legacy_pioqueue *queue,
+ u16 offset, u16 value)
+{
+ b43legacy_write16(queue->dev, queue->mmio_base + offset, value);
+ mmiowb();
+}
+
+
+int b43legacy_pio_init(struct b43legacy_wldev *dev);
+void b43legacy_pio_free(struct b43legacy_wldev *dev);
+
+int b43legacy_pio_tx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl);
+void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status);
+void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats);
+void b43legacy_pio_rx(struct b43legacy_pioqueue *queue);
+
+/* Suspend TX queue in hardware. */
+void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue);
+void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue);
+/* Suspend (freeze) the TX tasklet (software level). */
+void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev);
+void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev);
+
+#else /* CONFIG_B43LEGACY_PIO */
+
+static inline
+int b43legacy_pio_init(struct b43legacy_wldev *dev)
+{
+ return 0;
+}
+static inline
+void b43legacy_pio_free(struct b43legacy_wldev *dev)
+{
+}
+static inline
+int b43legacy_pio_tx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ return 0;
+}
+static inline
+void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+{
+}
+static inline
+void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+}
+static inline
+void b43legacy_pio_rx(struct b43legacy_pioqueue *queue)
+{
+}
+static inline
+void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue)
+{
+}
+static inline
+void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue)
+{
+}
+static inline
+void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev)
+{
+}
+static inline
+void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev)
+{
+}
+
+#endif /* CONFIG_B43LEGACY_PIO */
+#endif /* B43legacy_PIO_H_ */
diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c
new file mode 100644
index 00000000000..a361dee664a
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/radio.c
@@ -0,0 +1,2158 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mbuesch@freenet.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+
+#include "b43legacy.h"
+#include "main.h"
+#include "phy.h"
+#include "radio.h"
+#include "ilt.h"
+
+
+/* Table for b43legacy_radio_calibrationvalue() */
+static const u16 rcc_table[16] = {
+ 0x0002, 0x0003, 0x0001, 0x000F,
+ 0x0006, 0x0007, 0x0005, 0x000F,
+ 0x000A, 0x000B, 0x0009, 0x000F,
+ 0x000E, 0x000F, 0x000D, 0x000F,
+};
+
+/* Reverse the bits of a 4bit value.
+ * Example: 1101 is flipped 1011
+ */
+static u16 flip_4bit(u16 value)
+{
+ u16 flipped = 0x0000;
+
+ B43legacy_BUG_ON(!((value & ~0x000F) == 0x0000));
+
+ flipped |= (value & 0x0001) << 3;
+ flipped |= (value & 0x0002) << 1;
+ flipped |= (value & 0x0004) >> 1;
+ flipped |= (value & 0x0008) >> 3;
+
+ return flipped;
+}
+
+/* Get the freq, as it has to be written to the device. */
+static inline
+u16 channel2freq_bg(u8 channel)
+{
+ /* Frequencies are given as frequencies_bg[index] + 2.4GHz
+ * Starting with channel 1
+ */
+ static const u16 frequencies_bg[14] = {
+ 12, 17, 22, 27,
+ 32, 37, 42, 47,
+ 52, 57, 62, 67,
+ 72, 84,
+ };
+
+ if (unlikely(channel < 1 || channel > 14)) {
+ printk(KERN_INFO "b43legacy: Channel %d is out of range\n",
+ channel);
+ dump_stack();
+ return 2412;
+ }
+
+ return frequencies_bg[channel - 1];
+}
+
+void b43legacy_radio_lock(struct b43legacy_wldev *dev)
+{
+ u32 status;
+
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ status |= B43legacy_SBF_RADIOREG_LOCK;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+ mmiowb();
+ udelay(10);
+}
+
+void b43legacy_radio_unlock(struct b43legacy_wldev *dev)
+{
+ u32 status;
+
+ b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */
+ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+ status &= ~B43legacy_SBF_RADIOREG_LOCK;
+ b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+ mmiowb();
+}
+
+u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ if (phy->radio_ver == 0x2053) {
+ if (offset < 0x70)
+ offset += 0x80;
+ else if (offset < 0x80)
+ offset += 0x70;
+ } else if (phy->radio_ver == 0x2050)
+ offset |= 0x80;
+ else
+ B43legacy_WARN_ON(1);
+ break;
+ case B43legacy_PHYTYPE_G:
+ offset |= 0x80;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+
+ b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
+ return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);
+}
+
+void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val)
+{
+ b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
+ mmiowb();
+ b43legacy_write16(dev, B43legacy_MMIO_RADIO_DATA_LOW, val);
+}
+
+static void b43legacy_set_all_gains(struct b43legacy_wldev *dev,
+ s16 first, s16 second, s16 third)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 i;
+ u16 start = 0x08;
+ u16 end = 0x18;
+ u16 offset = 0x0400;
+ u16 tmp;
+
+ if (phy->rev <= 1) {
+ offset = 0x5000;
+ start = 0x10;
+ end = 0x20;
+ }
+
+ for (i = 0; i < 4; i++)
+ b43legacy_ilt_write(dev, offset + i, first);
+
+ for (i = start; i < end; i++)
+ b43legacy_ilt_write(dev, offset + i, second);
+
+ if (third != -1) {
+ tmp = ((u16)third << 14) | ((u16)third << 6);
+ b43legacy_phy_write(dev, 0x04A0,
+ (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
+ | tmp);
+ b43legacy_phy_write(dev, 0x04A1,
+ (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
+ | tmp);
+ b43legacy_phy_write(dev, 0x04A2,
+ (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
+ | tmp);
+ }
+ b43legacy_dummy_transmission(dev);
+}
+
+static void b43legacy_set_original_gains(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 i;
+ u16 tmp;
+ u16 offset = 0x0400;
+ u16 start = 0x0008;
+ u16 end = 0x0018;
+
+ if (phy->rev <= 1) {
+ offset = 0x5000;
+ start = 0x0010;
+ end = 0x0020;
+ }
+
+ for (i = 0; i < 4; i++) {
+ tmp = (i & 0xFFFC);
+ tmp |= (i & 0x0001) << 1;
+ tmp |= (i & 0x0002) >> 1;
+
+ b43legacy_ilt_write(dev, offset + i, tmp);
+ }
+
+ for (i = start; i < end; i++)
+ b43legacy_ilt_write(dev, offset + i, i - start);
+
+ b43legacy_phy_write(dev, 0x04A0,
+ (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
+ | 0x4040);
+ b43legacy_phy_write(dev, 0x04A1,
+ (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
+ | 0x4040);
+ b43legacy_phy_write(dev, 0x04A2,
+ (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
+ | 0x4000);
+ b43legacy_dummy_transmission(dev);
+}
+
+/* Synthetic PU workaround */
+static void b43legacy_synth_pu_workaround(struct b43legacy_wldev *dev,
+ u8 channel)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ might_sleep();
+
+ if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6)
+ /* We do not need the workaround. */
+ return;
+
+ if (channel <= 10)
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
+ channel2freq_bg(channel + 4));
+ else
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
+ channel2freq_bg(channel));
+ msleep(1);
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
+ channel2freq_bg(channel));
+}
+
+u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u8 ret = 0;
+ u16 saved;
+ u16 rssi;
+ u16 temp;
+ int i;
+ int j = 0;
+
+ saved = b43legacy_phy_read(dev, 0x0403);
+ b43legacy_radio_selectchannel(dev, channel, 0);
+ b43legacy_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
+ if (phy->aci_hw_rssi)
+ rssi = b43legacy_phy_read(dev, 0x048A) & 0x3F;
+ else
+ rssi = saved & 0x3F;
+ /* clamp temp to signed 5bit */
+ if (rssi > 32)
+ rssi -= 64;
+ for (i = 0; i < 100; i++) {
+ temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F;
+ if (temp > 32)
+ temp -= 64;
+ if (temp < rssi)
+ j++;
+ if (j >= 20)
+ ret = 1;
+ }
+ b43legacy_phy_write(dev, 0x0403, saved);
+
+ return ret;
+}
+
+u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u8 ret[13];
+ unsigned int channel = phy->channel;
+ unsigned int i;
+ unsigned int j;
+ unsigned int start;
+ unsigned int end;
+ unsigned long phylock_flags;
+
+ if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0)))
+ return 0;
+
+ b43legacy_phy_lock(dev, phylock_flags);
+ b43legacy_radio_lock(dev);
+ b43legacy_phy_write(dev, 0x0802,
+ b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+ & 0x7FFF);
+ b43legacy_set_all_gains(dev, 3, 8, 1);
+
+ start = (channel - 5 > 0) ? channel - 5 : 1;
+ end = (channel + 5 < 14) ? channel + 5 : 13;
+
+ for (i = start; i <= end; i++) {
+ if (abs(channel - i) > 2)
+ ret[i-1] = b43legacy_radio_aci_detect(dev, i);
+ }
+ b43legacy_radio_selectchannel(dev, channel, 0);
+ b43legacy_phy_write(dev, 0x0802,
+ (b43legacy_phy_read(dev, 0x0802) & 0xFFFC)
+ | 0x0003);
+ b43legacy_phy_write(dev, 0x0403,
+ b43legacy_phy_read(dev, 0x0403) & 0xFFF8);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+ | 0x8000);
+ b43legacy_set_original_gains(dev);
+ for (i = 0; i < 13; i++) {
+ if (!ret[i])
+ continue;
+ end = (i + 5 < 13) ? i + 5 : 13;
+ for (j = i; j < end; j++)
+ ret[j] = 1;
+ }
+ b43legacy_radio_unlock(dev);
+ b43legacy_phy_unlock(dev, phylock_flags);
+
+ return ret[channel - 1];
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val)
+{
+ b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
+ mmiowb();
+ b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val);
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset)
+{
+ u16 val;
+
+ b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
+ val = b43legacy_phy_read(dev, B43legacy_PHY_NRSSILT_DATA);
+
+ return (s16)val;
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val)
+{
+ u16 i;
+ s16 tmp;
+
+ for (i = 0; i < 64; i++) {
+ tmp = b43legacy_nrssi_hw_read(dev, i);
+ tmp -= val;
+ tmp = limit_value(tmp, -32, 31);
+ b43legacy_nrssi_hw_write(dev, i, tmp);
+ }
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ s16 i;
+ s16 delta;
+ s32 tmp;
+
+ delta = 0x1F - phy->nrssi[0];
+ for (i = 0; i < 64; i++) {
+ tmp = (i - delta) * phy->nrssislope;
+ tmp /= 0x10000;
+ tmp += 0x3A;
+ tmp = limit_value(tmp, 0, 0x3F);
+ phy->nrssi_lt[i] = tmp;
+ }
+}
+
+static void b43legacy_calc_nrssi_offset(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 backup[20] = { 0 };
+ s16 v47F;
+ u16 i;
+ u16 saved = 0xFFFF;
+
+ backup[0] = b43legacy_phy_read(dev, 0x0001);
+ backup[1] = b43legacy_phy_read(dev, 0x0811);
+ backup[2] = b43legacy_phy_read(dev, 0x0812);
+ backup[3] = b43legacy_phy_read(dev, 0x0814);
+ backup[4] = b43legacy_phy_read(dev, 0x0815);
+ backup[5] = b43legacy_phy_read(dev, 0x005A);
+ backup[6] = b43legacy_phy_read(dev, 0x0059);
+ backup[7] = b43legacy_phy_read(dev, 0x0058);
+ backup[8] = b43legacy_phy_read(dev, 0x000A);
+ backup[9] = b43legacy_phy_read(dev, 0x0003);
+ backup[10] = b43legacy_radio_read16(dev, 0x007A);
+ backup[11] = b43legacy_radio_read16(dev, 0x0043);
+
+ b43legacy_phy_write(dev, 0x0429,
+ b43legacy_phy_read(dev, 0x0429) & 0x7FFF);
+ b43legacy_phy_write(dev, 0x0001,
+ (b43legacy_phy_read(dev, 0x0001) & 0x3FFF)
+ | 0x4000);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811) | 0x000C);
+ b43legacy_phy_write(dev, 0x0812,
+ (b43legacy_phy_read(dev, 0x0812) & 0xFFF3)
+ | 0x0004);
+ b43legacy_phy_write(dev, 0x0802,
+ b43legacy_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
+ if (phy->rev >= 6) {
+ backup[12] = b43legacy_phy_read(dev, 0x002E);
+ backup[13] = b43legacy_phy_read(dev, 0x002F);
+ backup[14] = b43legacy_phy_read(dev, 0x080F);
+ backup[15] = b43legacy_phy_read(dev, 0x0810);
+ backup[16] = b43legacy_phy_read(dev, 0x0801);
+ backup[17] = b43legacy_phy_read(dev, 0x0060);
+ backup[18] = b43legacy_phy_read(dev, 0x0014);
+ backup[19] = b43legacy_phy_read(dev, 0x0478);
+
+ b43legacy_phy_write(dev, 0x002E, 0);
+ b43legacy_phy_write(dev, 0x002F, 0);
+ b43legacy_phy_write(dev, 0x080F, 0);
+ b43legacy_phy_write(dev, 0x0810, 0);
+ b43legacy_phy_write(dev, 0x0478,
+ b43legacy_phy_read(dev, 0x0478) | 0x0100);
+ b43legacy_phy_write(dev, 0x0801,
+ b43legacy_phy_read(dev, 0x0801) | 0x0040);
+ b43legacy_phy_write(dev, 0x0060,
+ b43legacy_phy_read(dev, 0x0060) | 0x0040);
+ b43legacy_phy_write(dev, 0x0014,
+ b43legacy_phy_read(dev, 0x0014) | 0x0200);
+ }
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A) | 0x0070);
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A) | 0x0080);
+ udelay(30);
+
+ v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F == 31) {
+ for (i = 7; i >= 4; i--) {
+ b43legacy_radio_write16(dev, 0x007B, i);
+ udelay(20);
+ v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8)
+ & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F < 31 && saved == 0xFFFF)
+ saved = i;
+ }
+ if (saved == 0xFFFF)
+ saved = 4;
+ } else {
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ & 0x007F);
+ b43legacy_phy_write(dev, 0x0814,
+ b43legacy_phy_read(dev, 0x0814) | 0x0001);
+ b43legacy_phy_write(dev, 0x0815,
+ b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811) | 0x000C);
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812) | 0x000C);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811) | 0x0030);
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812) | 0x0030);
+ b43legacy_phy_write(dev, 0x005A, 0x0480);
+ b43legacy_phy_write(dev, 0x0059, 0x0810);
+ b43legacy_phy_write(dev, 0x0058, 0x000D);
+ if (phy->analog == 0)
+ b43legacy_phy_write(dev, 0x0003, 0x0122);
+ else
+ b43legacy_phy_write(dev, 0x000A,
+ b43legacy_phy_read(dev, 0x000A)
+ | 0x2000);
+ b43legacy_phy_write(dev, 0x0814,
+ b43legacy_phy_read(dev, 0x0814) | 0x0004);
+ b43legacy_phy_write(dev, 0x0815,
+ b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
+ b43legacy_phy_write(dev, 0x0003,
+ (b43legacy_phy_read(dev, 0x0003) & 0xFF9F)
+ | 0x0040);
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x000F);
+ b43legacy_set_all_gains(dev, 3, 0, 1);
+ b43legacy_radio_write16(dev, 0x0043,
+ (b43legacy_radio_read16(dev, 0x0043)
+ & 0x00F0) | 0x000F);
+ udelay(30);
+ v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F == -32) {
+ for (i = 0; i < 4; i++) {
+ b43legacy_radio_write16(dev, 0x007B, i);
+ udelay(20);
+ v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >>
+ 8) & 0x003F);
+ if (v47F >= 0x20)
+ v47F -= 0x40;
+ if (v47F > -31 && saved == 0xFFFF)
+ saved = i;
+ }
+ if (saved == 0xFFFF)
+ saved = 3;
+ } else
+ saved = 0;
+ }
+ b43legacy_radio_write16(dev, 0x007B, saved);
+
+ if (phy->rev >= 6) {
+ b43legacy_phy_write(dev, 0x002E, backup[12]);
+ b43legacy_phy_write(dev, 0x002F, backup[13]);
+ b43legacy_phy_write(dev, 0x080F, backup[14]);
+ b43legacy_phy_write(dev, 0x0810, backup[15]);
+ }
+ b43legacy_phy_write(dev, 0x0814, backup[3]);
+ b43legacy_phy_write(dev, 0x0815, backup[4]);
+ b43legacy_phy_write(dev, 0x005A, backup[5]);
+ b43legacy_phy_write(dev, 0x0059, backup[6]);
+ b43legacy_phy_write(dev, 0x0058, backup[7]);
+ b43legacy_phy_write(dev, 0x000A, backup[8]);
+ b43legacy_phy_write(dev, 0x0003, backup[9]);
+ b43legacy_radio_write16(dev, 0x0043, backup[11]);
+ b43legacy_radio_write16(dev, 0x007A, backup[10]);
+ b43legacy_phy_write(dev, 0x0802,
+ b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2);
+ b43legacy_phy_write(dev, 0x0429,
+ b43legacy_phy_read(dev, 0x0429) | 0x8000);
+ b43legacy_set_original_gains(dev);
+ if (phy->rev >= 6) {
+ b43legacy_phy_write(dev, 0x0801, backup[16]);
+ b43legacy_phy_write(dev, 0x0060, backup[17]);
+ b43legacy_phy_write(dev, 0x0014, backup[18]);
+ b43legacy_phy_write(dev, 0x0478, backup[19]);
+ }
+ b43legacy_phy_write(dev, 0x0001, backup[0]);
+ b43legacy_phy_write(dev, 0x0812, backup[2]);
+ b43legacy_phy_write(dev, 0x0811, backup[1]);
+}
+
+void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 backup[18] = { 0 };
+ u16 tmp;
+ s16 nrssi0;
+ s16 nrssi1;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ backup[0] = b43legacy_radio_read16(dev, 0x007A);
+ backup[1] = b43legacy_radio_read16(dev, 0x0052);
+ backup[2] = b43legacy_radio_read16(dev, 0x0043);
+ backup[3] = b43legacy_phy_read(dev, 0x0030);
+ backup[4] = b43legacy_phy_read(dev, 0x0026);
+ backup[5] = b43legacy_phy_read(dev, 0x0015);
+ backup[6] = b43legacy_phy_read(dev, 0x002A);
+ backup[7] = b43legacy_phy_read(dev, 0x0020);
+ backup[8] = b43legacy_phy_read(dev, 0x005A);
+ backup[9] = b43legacy_phy_read(dev, 0x0059);
+ backup[10] = b43legacy_phy_read(dev, 0x0058);
+ backup[11] = b43legacy_read16(dev, 0x03E2);
+ backup[12] = b43legacy_read16(dev, 0x03E6);
+ backup[13] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
+
+ tmp = b43legacy_radio_read16(dev, 0x007A);
+ tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
+ b43legacy_radio_write16(dev, 0x007A, tmp);
+ b43legacy_phy_write(dev, 0x0030, 0x00FF);
+ b43legacy_write16(dev, 0x03EC, 0x7F7F);
+ b43legacy_phy_write(dev, 0x0026, 0x0000);
+ b43legacy_phy_write(dev, 0x0015,
+ b43legacy_phy_read(dev, 0x0015) | 0x0020);
+ b43legacy_phy_write(dev, 0x002A, 0x08A3);
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x0080);
+
+ nrssi0 = (s16)b43legacy_phy_read(dev, 0x0027);
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ & 0x007F);
+ if (phy->analog >= 2)
+ b43legacy_write16(dev, 0x03E6, 0x0040);
+ else if (phy->analog == 0)
+ b43legacy_write16(dev, 0x03E6, 0x0122);
+ else
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+ b43legacy_read16(dev,
+ B43legacy_MMIO_CHANNEL_EXT) & 0x2000);
+ b43legacy_phy_write(dev, 0x0020, 0x3F3F);
+ b43legacy_phy_write(dev, 0x0015, 0xF330);
+ b43legacy_radio_write16(dev, 0x005A, 0x0060);
+ b43legacy_radio_write16(dev, 0x0043,
+ b43legacy_radio_read16(dev, 0x0043)
+ & 0x00F0);
+ b43legacy_phy_write(dev, 0x005A, 0x0480);
+ b43legacy_phy_write(dev, 0x0059, 0x0810);
+ b43legacy_phy_write(dev, 0x0058, 0x000D);
+ udelay(20);
+
+ nrssi1 = (s16)b43legacy_phy_read(dev, 0x0027);
+ b43legacy_phy_write(dev, 0x0030, backup[3]);
+ b43legacy_radio_write16(dev, 0x007A, backup[0]);
+ b43legacy_write16(dev, 0x03E2, backup[11]);
+ b43legacy_phy_write(dev, 0x0026, backup[4]);
+ b43legacy_phy_write(dev, 0x0015, backup[5]);
+ b43legacy_phy_write(dev, 0x002A, backup[6]);
+ b43legacy_synth_pu_workaround(dev, phy->channel);
+ if (phy->analog != 0)
+ b43legacy_write16(dev, 0x03F4, backup[13]);
+
+ b43legacy_phy_write(dev, 0x0020, backup[7]);
+ b43legacy_phy_write(dev, 0x005A, backup[8]);
+ b43legacy_phy_write(dev, 0x0059, backup[9]);
+ b43legacy_phy_write(dev, 0x0058, backup[10]);
+ b43legacy_radio_write16(dev, 0x0052, backup[1]);
+ b43legacy_radio_write16(dev, 0x0043, backup[2]);
+
+ if (nrssi0 == nrssi1)
+ phy->nrssislope = 0x00010000;
+ else
+ phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+
+ if (nrssi0 <= -4) {
+ phy->nrssi[0] = nrssi0;
+ phy->nrssi[1] = nrssi1;
+ }
+ break;
+ case B43legacy_PHYTYPE_G:
+ if (phy->radio_rev >= 9)
+ return;
+ if (phy->radio_rev == 8)
+ b43legacy_calc_nrssi_offset(dev);
+
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+ & 0x7FFF);
+ b43legacy_phy_write(dev, 0x0802,
+ b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
+ backup[7] = b43legacy_read16(dev, 0x03E2);
+ b43legacy_write16(dev, 0x03E2,
+ b43legacy_read16(dev, 0x03E2) | 0x8000);
+ backup[0] = b43legacy_radio_read16(dev, 0x007A);
+ backup[1] = b43legacy_radio_read16(dev, 0x0052);
+ backup[2] = b43legacy_radio_read16(dev, 0x0043);
+ backup[3] = b43legacy_phy_read(dev, 0x0015);
+ backup[4] = b43legacy_phy_read(dev, 0x005A);
+ backup[5] = b43legacy_phy_read(dev, 0x0059);
+ backup[6] = b43legacy_phy_read(dev, 0x0058);
+ backup[8] = b43legacy_read16(dev, 0x03E6);
+ backup[9] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
+ if (phy->rev >= 3) {
+ backup[10] = b43legacy_phy_read(dev, 0x002E);
+ backup[11] = b43legacy_phy_read(dev, 0x002F);
+ backup[12] = b43legacy_phy_read(dev, 0x080F);
+ backup[13] = b43legacy_phy_read(dev,
+ B43legacy_PHY_G_LO_CONTROL);
+ backup[14] = b43legacy_phy_read(dev, 0x0801);
+ backup[15] = b43legacy_phy_read(dev, 0x0060);
+ backup[16] = b43legacy_phy_read(dev, 0x0014);
+ backup[17] = b43legacy_phy_read(dev, 0x0478);
+ b43legacy_phy_write(dev, 0x002E, 0);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, 0);
+ switch (phy->rev) {
+ case 4: case 6: case 7:
+ b43legacy_phy_write(dev, 0x0478,
+ b43legacy_phy_read(dev,
+ 0x0478) | 0x0100);
+ b43legacy_phy_write(dev, 0x0801,
+ b43legacy_phy_read(dev,
+ 0x0801) | 0x0040);
+ break;
+ case 3: case 5:
+ b43legacy_phy_write(dev, 0x0801,
+ b43legacy_phy_read(dev,
+ 0x0801) & 0xFFBF);
+ break;
+ }
+ b43legacy_phy_write(dev, 0x0060,
+ b43legacy_phy_read(dev, 0x0060)
+ | 0x0040);
+ b43legacy_phy_write(dev, 0x0014,
+ b43legacy_phy_read(dev, 0x0014)
+ | 0x0200);
+ }
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x0070);
+ b43legacy_set_all_gains(dev, 0, 8, 0);
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ & 0x00F7);
+ if (phy->rev >= 2) {
+ b43legacy_phy_write(dev, 0x0811,
+ (b43legacy_phy_read(dev, 0x0811)
+ & 0xFFCF) | 0x0030);
+ b43legacy_phy_write(dev, 0x0812,
+ (b43legacy_phy_read(dev, 0x0812)
+ & 0xFFCF) | 0x0010);
+ }
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x0080);
+ udelay(20);
+
+ nrssi0 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (nrssi0 >= 0x0020)
+ nrssi0 -= 0x0040;
+
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ & 0x007F);
+ if (phy->analog >= 2)
+ b43legacy_phy_write(dev, 0x0003,
+ (b43legacy_phy_read(dev, 0x0003)
+ & 0xFF9F) | 0x0040);
+
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+ b43legacy_read16(dev,
+ B43legacy_MMIO_CHANNEL_EXT) | 0x2000);
+ b43legacy_radio_write16(dev, 0x007A,
+ b43legacy_radio_read16(dev, 0x007A)
+ | 0x000F);
+ b43legacy_phy_write(dev, 0x0015, 0xF330);
+ if (phy->rev >= 2) {
+ b43legacy_phy_write(dev, 0x0812,
+ (b43legacy_phy_read(dev, 0x0812)
+ & 0xFFCF) | 0x0020);
+ b43legacy_phy_write(dev, 0x0811,
+ (b43legacy_phy_read(dev, 0x0811)
+ & 0xFFCF) | 0x0020);
+ }
+
+ b43legacy_set_all_gains(dev, 3, 0, 1);
+ if (phy->radio_rev == 8)
+ b43legacy_radio_write16(dev, 0x0043, 0x001F);
+ else {
+ tmp = b43legacy_radio_read16(dev, 0x0052) & 0xFF0F;
+ b43legacy_radio_write16(dev, 0x0052, tmp | 0x0060);
+ tmp = b43legacy_radio_read16(dev, 0x0043) & 0xFFF0;
+ b43legacy_radio_write16(dev, 0x0043, tmp | 0x0009);
+ }
+ b43legacy_phy_write(dev, 0x005A, 0x0480);
+ b43legacy_phy_write(dev, 0x0059, 0x0810);
+ b43legacy_phy_write(dev, 0x0058, 0x000D);
+ udelay(20);
+ nrssi1 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
+ if (nrssi1 >= 0x0020)
+ nrssi1 -= 0x0040;
+ if (nrssi0 == nrssi1)
+ phy->nrssislope = 0x00010000;
+ else
+ phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+ if (nrssi0 >= -4) {
+ phy->nrssi[0] = nrssi1;
+ phy->nrssi[1] = nrssi0;
+ }
+ if (phy->rev >= 3) {
+ b43legacy_phy_write(dev, 0x002E, backup[10]);
+ b43legacy_phy_write(dev, 0x002F, backup[11]);
+ b43legacy_phy_write(dev, 0x080F, backup[12]);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL,
+ backup[13]);
+ }
+ if (phy->rev >= 2) {
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_phy_read(dev, 0x0812)
+ & 0xFFCF);
+ b43legacy_phy_write(dev, 0x0811,
+ b43legacy_phy_read(dev, 0x0811)
+ & 0xFFCF);
+ }
+
+ b43legacy_radio_write16(dev, 0x007A, backup[0]);
+ b43legacy_radio_write16(dev, 0x0052, backup[1]);
+ b43legacy_radio_write16(dev, 0x0043, backup[2]);
+ b43legacy_write16(dev, 0x03E2, backup[7]);
+ b43legacy_write16(dev, 0x03E6, backup[8]);
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[9]);
+ b43legacy_phy_write(dev, 0x0015, backup[3]);
+ b43legacy_phy_write(dev, 0x005A, backup[4]);
+ b43legacy_phy_write(dev, 0x0059, backup[5]);
+ b43legacy_phy_write(dev, 0x0058, backup[6]);
+ b43legacy_synth_pu_workaround(dev, phy->channel);
+ b43legacy_phy_write(dev, 0x0802,
+ b43legacy_phy_read(dev, 0x0802) | 0x0003);
+ b43legacy_set_original_gains(dev);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+ | 0x8000);
+ if (phy->rev >= 3) {
+ b43legacy_phy_write(dev, 0x0801, backup[14]);
+ b43legacy_phy_write(dev, 0x0060, backup[15]);
+ b43legacy_phy_write(dev, 0x0014, backup[16]);
+ b43legacy_phy_write(dev, 0x0478, backup[17]);
+ }
+ b43legacy_nrssi_mem_update(dev);
+ b43legacy_calc_nrssi_threshold(dev);
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+}
+
+void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ s32 threshold;
+ s32 a;
+ s32 b;
+ s16 tmp16;
+ u16 tmp_u16;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B: {
+ if (phy->radio_ver != 0x2050)
+ return;
+ if (!(dev->dev->bus->sprom.r1.boardflags_lo &
+ B43legacy_BFL_RSSI))
+ return;
+
+ if (phy->radio_rev >= 6) {
+ threshold = (phy->nrssi[1] - phy->nrssi[0]) * 32;
+ threshold += 20 * (phy->nrssi[0] + 1);
+ threshold /= 40;
+ } else
+ threshold = phy->nrssi[1] - 5;
+
+ threshold = limit_value(threshold, 0, 0x3E);
+ b43legacy_phy_read(dev, 0x0020); /* dummy read */
+ b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8)
+ | 0x001C);
+
+ if (phy->radio_rev >= 6) {
+ b43legacy_phy_write(dev, 0x0087, 0x0E0D);
+ b43legacy_phy_write(dev, 0x0086, 0x0C0B);
+ b43legacy_phy_write(dev, 0x0085, 0x0A09);
+ b43legacy_phy_write(dev, 0x0084, 0x0808);
+ b43legacy_phy_write(dev, 0x0083, 0x0808);
+ b43legacy_phy_write(dev, 0x0082, 0x0604);
+ b43legacy_phy_write(dev, 0x0081, 0x0302);
+ b43legacy_phy_write(dev, 0x0080, 0x0100);
+ }
+ break;
+ }
+ case B43legacy_PHYTYPE_G:
+ if (!phy->gmode ||
+ !(dev->dev->bus->sprom.r1.boardflags_lo &
+ B43legacy_BFL_RSSI)) {
+ tmp16 = b43legacy_nrssi_hw_read(dev, 0x20);
+ if (tmp16 >= 0x20)
+ tmp16 -= 0x40;
+ if (tmp16 < 3)
+ b43legacy_phy_write(dev, 0x048A,
+ (b43legacy_phy_read(dev,
+ 0x048A) & 0xF000) | 0x09EB);
+ else
+ b43legacy_phy_write(dev, 0x048A,
+ (b43legacy_phy_read(dev,
+ 0x048A) & 0xF000) | 0x0AED);
+ } else {
+ if (phy->interfmode ==
+ B43legacy_RADIO_INTERFMODE_NONWLAN) {
+ a = 0xE;
+ b = 0xA;
+ } else if (!phy->aci_wlan_automatic &&
+ phy->aci_enable) {
+ a = 0x13;
+ b = 0x12;
+ } else {
+ a = 0xE;
+ b = 0x11;
+ }
+
+ a = a * (phy->nrssi[1] - phy->nrssi[0]);
+ a += (phy->nrssi[0] << 6);
+ if (a < 32)
+ a += 31;
+ else
+ a += 32;
+ a = a >> 6;
+ a = limit_value(a, -31, 31);
+
+ b = b * (phy->nrssi[1] - phy->nrssi[0]);
+ b += (phy->nrssi[0] << 6);
+ if (b < 32)
+ b += 31;
+ else
+ b += 32;
+ b = b >> 6;
+ b = limit_value(b, -31, 31);
+
+ tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000;
+ tmp_u16 |= ((u32)b & 0x0000003F);
+ tmp_u16 |= (((u32)a & 0x0000003F) << 6);
+ b43legacy_phy_write(dev, 0x048A, tmp_u16);
+ }
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+}
+
+/* Stack implementation to save/restore values from the
+ * interference mitigation code.
+ * It is save to restore values in random order.
+ */
+static void _stack_save(u32 *_stackptr, size_t *stackidx,
+ u8 id, u16 offset, u16 value)
+{
+ u32 *stackptr = &(_stackptr[*stackidx]);
+
+ B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
+ B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
+ *stackptr = offset;
+ *stackptr |= ((u32)id) << 13;
+ *stackptr |= ((u32)value) << 16;
+ (*stackidx)++;
+ B43legacy_WARN_ON(!(*stackidx < B43legacy_INTERFSTACK_SIZE));
+}
+
+static u16 _stack_restore(u32 *stackptr,
+ u8 id, u16 offset)
+{
+ size_t i;
+
+ B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
+ B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
+ for (i = 0; i < B43legacy_INTERFSTACK_SIZE; i++, stackptr++) {
+ if ((*stackptr & 0x00001FFF) != offset)
+ continue;
+ if (((*stackptr & 0x00007000) >> 13) != id)
+ continue;
+ return ((*stackptr & 0xFFFF0000) >> 16);
+ }
+ B43legacy_BUG_ON(1);
+
+ return 0;
+}
+
+#define phy_stacksave(offset) \
+ do { \
+ _stack_save(stack, &stackidx, 0x1, (offset), \
+ b43legacy_phy_read(dev, (offset))); \
+ } while (0)
+#define phy_stackrestore(offset) \
+ do { \
+ b43legacy_phy_write(dev, (offset), \
+ _stack_restore(stack, 0x1, \
+ (offset))); \
+ } while (0)
+#define radio_stacksave(offset) \
+ do { \
+ _stack_save(stack, &stackidx, 0x2, (offset), \
+ b43legacy_radio_read16(dev, (offset))); \
+ } while (0)
+#define radio_stackrestore(offset) \
+ do { \
+ b43legacy_radio_write16(dev, (offset), \
+ _stack_restore(stack, 0x2, \
+ (offset))); \
+ } while (0)
+#define ilt_stacksave(offset) \
+ do { \
+ _stack_save(stack, &stackidx, 0x3, (offset), \
+ b43legacy_ilt_read(dev, (offset))); \
+ } while (0)
+#define ilt_stackrestore(offset) \
+ do { \
+ b43legacy_ilt_write(dev, (offset), \
+ _stack_restore(stack, 0x3, \
+ (offset))); \
+ } while (0)
+
+static void
+b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev *dev,
+ int mode)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 tmp;
+ u16 flipped;
+ u32 tmp32;
+ size_t stackidx = 0;
+ u32 *stack = phy->interfstack;
+
+ switch (mode) {
+ case B43legacy_RADIO_INTERFMODE_NONWLAN:
+ if (phy->rev != 1) {
+ b43legacy_phy_write(dev, 0x042B,
+ b43legacy_phy_read(dev, 0x042B)
+ | 0x0800);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev,
+ B43legacy_PHY_G_CRS) & ~0x4000);
+ break;
+ }
+ radio_stacksave(0x0078);
+ tmp = (b43legacy_radio_read16(dev, 0x0078) & 0x001E);
+ flipped = flip_4bit(tmp);
+ if (flipped < 10 && flipped >= 8)
+ flipped = 7;
+ else if (flipped >= 10)
+ flipped -= 3;
+ flipped = flip_4bit(flipped);
+ flipped = (flipped << 1) | 0x0020;
+ b43legacy_radio_write16(dev, 0x0078, flipped);
+
+ b43legacy_calc_nrssi_threshold(dev);
+
+ phy_stacksave(0x0406);
+ b43legacy_phy_write(dev, 0x0406, 0x7E28);
+
+ b43legacy_phy_write(dev, 0x042B,
+ b43legacy_phy_read(dev, 0x042B) | 0x0800);
+ b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
+ b43legacy_phy_read(dev,
+ B43legacy_PHY_RADIO_BITFIELD) | 0x1000);
+
+ phy_stacksave(0x04A0);
+ b43legacy_phy_write(dev, 0x04A0,
+ (b43legacy_phy_read(dev, 0x04A0) & 0xC0C0)
+ | 0x0008);
+ phy_stacksave(0x04A1);
+ b43legacy_phy_write(dev, 0x04A1,
+ (b43legacy_phy_read(dev, 0x04A1) & 0xC0C0)
+ | 0x0605);
+ phy_stacksave(0x04A2);
+ b43legacy_phy_write(dev, 0x04A2,
+ (b43legacy_phy_read(dev, 0x04A2) & 0xC0C0)
+ | 0x0204);
+ phy_stacksave(0x04A8);
+ b43legacy_phy_write(dev, 0x04A8,
+ (b43legacy_phy_read(dev, 0x04A8) & 0xC0C0)
+ | 0x0803);
+ phy_stacksave(0x04AB);
+ b43legacy_phy_write(dev, 0x04AB,
+ (b43legacy_phy_read(dev, 0x04AB) & 0xC0C0)
+ | 0x0605);
+
+ phy_stacksave(0x04A7);
+ b43legacy_phy_write(dev, 0x04A7, 0x0002);
+ phy_stacksave(0x04A3);
+ b43legacy_phy_write(dev, 0x04A3, 0x287A);
+ phy_stacksave(0x04A9);
+ b43legacy_phy_write(dev, 0x04A9, 0x2027);
+ phy_stacksave(0x0493);
+ b43legacy_phy_write(dev, 0x0493, 0x32F5);
+ phy_stacksave(0x04AA);
+ b43legacy_phy_write(dev, 0x04AA, 0x2027);
+ phy_stacksave(0x04AC);
+ b43legacy_phy_write(dev, 0x04AC, 0x32F5);
+ break;
+ case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
+ if (b43legacy_phy_read(dev, 0x0033) & 0x0800)
+ break;
+
+ phy->aci_enable = 1;
+
+ phy_stacksave(B43legacy_PHY_RADIO_BITFIELD);
+ phy_stacksave(B43legacy_PHY_G_CRS);
+ if (phy->rev < 2)
+ phy_stacksave(0x0406);
+ else {
+ phy_stacksave(0x04C0);
+ phy_stacksave(0x04C1);
+ }
+ phy_stacksave(0x0033);
+ phy_stacksave(0x04A7);
+ phy_stacksave(0x04A3);
+ phy_stacksave(0x04A9);
+ phy_stacksave(0x04AA);
+ phy_stacksave(0x04AC);
+ phy_stacksave(0x0493);
+ phy_stacksave(0x04A1);
+ phy_stacksave(0x04A0);
+ phy_stacksave(0x04A2);
+ phy_stacksave(0x048A);
+ phy_stacksave(0x04A8);
+ phy_stacksave(0x04AB);
+ if (phy->rev == 2) {
+ phy_stacksave(0x04AD);
+ phy_stacksave(0x04AE);
+ } else if (phy->rev >= 3) {
+ phy_stacksave(0x04AD);
+ phy_stacksave(0x0415);
+ phy_stacksave(0x0416);
+ phy_stacksave(0x0417);
+ ilt_stacksave(0x1A00 + 0x2);
+ ilt_stacksave(0x1A00 + 0x3);
+ }
+ phy_stacksave(0x042B);
+ phy_stacksave(0x048C);
+
+ b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
+ b43legacy_phy_read(dev,
+ B43legacy_PHY_RADIO_BITFIELD) & ~0x1000);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ (b43legacy_phy_read(dev,
+ B43legacy_PHY_G_CRS)
+ & 0xFFFC) | 0x0002);
+
+ b43legacy_phy_write(dev, 0x0033, 0x0800);
+ b43legacy_phy_write(dev, 0x04A3, 0x2027);
+ b43legacy_phy_write(dev, 0x04A9, 0x1CA8);
+ b43legacy_phy_write(dev, 0x0493, 0x287A);
+ b43legacy_phy_write(dev, 0x04AA, 0x1CA8);
+ b43legacy_phy_write(dev, 0x04AC, 0x287A);
+
+ b43legacy_phy_write(dev, 0x04A0,
+ (b43legacy_phy_read(dev, 0x04A0)
+ & 0xFFC0) | 0x001A);
+ b43legacy_phy_write(dev, 0x04A7, 0x000D);
+
+ if (phy->rev < 2)
+ b43legacy_phy_write(dev, 0x0406, 0xFF0D);
+ else if (phy->rev == 2) {
+ b43legacy_phy_write(dev, 0x04C0, 0xFFFF);
+ b43legacy_phy_write(dev, 0x04C1, 0x00A9);
+ } else {
+ b43legacy_phy_write(dev, 0x04C0, 0x00C1);
+ b43legacy_phy_write(dev, 0x04C1, 0x0059);
+ }
+
+ b43legacy_phy_write(dev, 0x04A1,
+ (b43legacy_phy_read(dev, 0x04A1)
+ & 0xC0FF) | 0x1800);
+ b43legacy_phy_write(dev, 0x04A1,
+ (b43legacy_phy_read(dev, 0x04A1)
+ & 0xFFC0) | 0x0015);
+ b43legacy_phy_write(dev, 0x04A8,
+ (b43legacy_phy_read(dev, 0x04A8)
+ & 0xCFFF) | 0x1000);
+ b43legacy_phy_write(dev, 0x04A8,
+ (b43legacy_phy_read(dev, 0x04A8)
+ & 0xF0FF) | 0x0A00);
+ b43legacy_phy_write(dev, 0x04AB,
+ (b43legacy_phy_read(dev, 0x04AB)
+ & 0xCFFF) | 0x1000);
+ b43legacy_phy_write(dev, 0x04AB,
+ (b43legacy_phy_read(dev, 0x04AB)
+ & 0xF0FF) | 0x0800);
+ b43legacy_phy_write(dev, 0x04AB,
+ (b43legacy_phy_read(dev, 0x04AB)
+ & 0xFFCF) | 0x0010);
+ b43legacy_phy_write(dev, 0x04AB,
+ (b43legacy_phy_read(dev, 0x04AB)
+ & 0xFFF0) | 0x0005);
+ b43legacy_phy_write(dev, 0x04A8,
+ (b43legacy_phy_read(dev, 0x04A8)
+ & 0xFFCF) | 0x0010);
+ b43legacy_phy_write(dev, 0x04A8,
+ (b43legacy_phy_read(dev, 0x04A8)
+ & 0xFFF0) | 0x0006);
+ b43legacy_phy_write(dev, 0x04A2,
+ (b43legacy_phy_read(dev, 0x04A2)
+ & 0xF0FF) | 0x0800);
+ b43legacy_phy_write(dev, 0x04A0,
+ (b43legacy_phy_read(dev, 0x04A0)
+ & 0xF0FF) | 0x0500);
+ b43legacy_phy_write(dev, 0x04A2,
+ (b43legacy_phy_read(dev, 0x04A2)
+ & 0xFFF0) | 0x000B);
+
+ if (phy->rev >= 3) {
+ b43legacy_phy_write(dev, 0x048A,
+ b43legacy_phy_read(dev, 0x048A)
+ & ~0x8000);
+ b43legacy_phy_write(dev, 0x0415,
+ (b43legacy_phy_read(dev, 0x0415)
+ & 0x8000) | 0x36D8);
+ b43legacy_phy_write(dev, 0x0416,
+ (b43legacy_phy_read(dev, 0x0416)
+ & 0x8000) | 0x36D8);
+ b43legacy_phy_write(dev, 0x0417,
+ (b43legacy_phy_read(dev, 0x0417)
+ & 0xFE00) | 0x016D);
+ } else {
+ b43legacy_phy_write(dev, 0x048A,
+ b43legacy_phy_read(dev, 0x048A)
+ | 0x1000);
+ b43legacy_phy_write(dev, 0x048A,
+ (b43legacy_phy_read(dev, 0x048A)
+ & 0x9FFF) | 0x2000);
+ tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET);
+ if (!(tmp32 & 0x800)) {
+ tmp32 |= 0x800;
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ tmp32);
+ }
+ }
+ if (phy->rev >= 2)
+ b43legacy_phy_write(dev, 0x042B,
+ b43legacy_phy_read(dev, 0x042B)
+ | 0x0800);
+ b43legacy_phy_write(dev, 0x048C,
+ (b43legacy_phy_read(dev, 0x048C)
+ & 0xF0FF) | 0x0200);
+ if (phy->rev == 2) {
+ b43legacy_phy_write(dev, 0x04AE,
+ (b43legacy_phy_read(dev, 0x04AE)
+ & 0xFF00) | 0x007F);
+ b43legacy_phy_write(dev, 0x04AD,
+ (b43legacy_phy_read(dev, 0x04AD)
+ & 0x00FF) | 0x1300);
+ } else if (phy->rev >= 6) {
+ b43legacy_ilt_write(dev, 0x1A00 + 0x3, 0x007F);
+ b43legacy_ilt_write(dev, 0x1A00 + 0x2, 0x007F);
+ b43legacy_phy_write(dev, 0x04AD,
+ b43legacy_phy_read(dev, 0x04AD)
+ & 0x00FF);
+ }
+ b43legacy_calc_nrssi_slope(dev);
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+}
+
+static void
+b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev,
+ int mode)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u32 tmp32;
+ u32 *stack = phy->interfstack;
+
+ switch (mode) {
+ case B43legacy_RADIO_INTERFMODE_NONWLAN:
+ if (phy->rev != 1) {
+ b43legacy_phy_write(dev, 0x042B,
+ b43legacy_phy_read(dev, 0x042B)
+ & ~0x0800);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev,
+ B43legacy_PHY_G_CRS) | 0x4000);
+ break;
+ }
+ phy_stackrestore(0x0078);
+ b43legacy_calc_nrssi_threshold(dev);
+ phy_stackrestore(0x0406);
+ b43legacy_phy_write(dev, 0x042B,
+ b43legacy_phy_read(dev, 0x042B) & ~0x0800);
+ if (!dev->bad_frames_preempt)
+ b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
+ b43legacy_phy_read(dev,
+ B43legacy_PHY_RADIO_BITFIELD)
+ & ~(1 << 11));
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+ | 0x4000);
+ phy_stackrestore(0x04A0);
+ phy_stackrestore(0x04A1);
+ phy_stackrestore(0x04A2);
+ phy_stackrestore(0x04A8);
+ phy_stackrestore(0x04AB);
+ phy_stackrestore(0x04A7);
+ phy_stackrestore(0x04A3);
+ phy_stackrestore(0x04A9);
+ phy_stackrestore(0x0493);
+ phy_stackrestore(0x04AA);
+ phy_stackrestore(0x04AC);
+ break;
+ case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
+ if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800))
+ break;
+
+ phy->aci_enable = 0;
+
+ phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD);
+ phy_stackrestore(B43legacy_PHY_G_CRS);
+ phy_stackrestore(0x0033);
+ phy_stackrestore(0x04A3);
+ phy_stackrestore(0x04A9);
+ phy_stackrestore(0x0493);
+ phy_stackrestore(0x04AA);
+ phy_stackrestore(0x04AC);
+ phy_stackrestore(0x04A0);
+ phy_stackrestore(0x04A7);
+ if (phy->rev >= 2) {
+ phy_stackrestore(0x04C0);
+ phy_stackrestore(0x04C1);
+ } else
+ phy_stackrestore(0x0406);
+ phy_stackrestore(0x04A1);
+ phy_stackrestore(0x04AB);
+ phy_stackrestore(0x04A8);
+ if (phy->rev == 2) {
+ phy_stackrestore(0x04AD);
+ phy_stackrestore(0x04AE);
+ } else if (phy->rev >= 3) {
+ phy_stackrestore(0x04AD);
+ phy_stackrestore(0x0415);
+ phy_stackrestore(0x0416);
+ phy_stackrestore(0x0417);
+ ilt_stackrestore(0x1A00 + 0x2);
+ ilt_stackrestore(0x1A00 + 0x3);
+ }
+ phy_stackrestore(0x04A2);
+ phy_stackrestore(0x04A8);
+ phy_stackrestore(0x042B);
+ phy_stackrestore(0x048C);
+ tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET);
+ if (tmp32 & 0x800) {
+ tmp32 &= ~0x800;
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ tmp32);
+ }
+ b43legacy_calc_nrssi_slope(dev);
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+}
+
+#undef phy_stacksave
+#undef phy_stackrestore
+#undef radio_stacksave
+#undef radio_stackrestore
+#undef ilt_stacksave
+#undef ilt_stackrestore
+
+int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev,
+ int mode)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ int currentmode;
+
+ if ((phy->type != B43legacy_PHYTYPE_G) ||
+ (phy->rev == 0) || (!phy->gmode))
+ return -ENODEV;
+
+ phy->aci_wlan_automatic = 0;
+ switch (mode) {
+ case B43legacy_RADIO_INTERFMODE_AUTOWLAN:
+ phy->aci_wlan_automatic = 1;
+ if (phy->aci_enable)
+ mode = B43legacy_RADIO_INTERFMODE_MANUALWLAN;
+ else
+ mode = B43legacy_RADIO_INTERFMODE_NONE;
+ break;
+ case B43legacy_RADIO_INTERFMODE_NONE:
+ case B43legacy_RADIO_INTERFMODE_NONWLAN:
+ case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ currentmode = phy->interfmode;
+ if (currentmode == mode)
+ return 0;
+ if (currentmode != B43legacy_RADIO_INTERFMODE_NONE)
+ b43legacy_radio_interference_mitigation_disable(dev,
+ currentmode);
+
+ if (mode == B43legacy_RADIO_INTERFMODE_NONE) {
+ phy->aci_enable = 0;
+ phy->aci_hw_rssi = 0;
+ } else
+ b43legacy_radio_interference_mitigation_enable(dev, mode);
+ phy->interfmode = mode;
+
+ return 0;
+}
+
+u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev)
+{
+ u16 reg;
+ u16 index;
+ u16 ret;
+
+ reg = b43legacy_radio_read16(dev, 0x0060);
+ index = (reg & 0x001E) >> 1;
+ ret = rcc_table[index] << 1;
+ ret |= (reg & 0x0001);
+ ret |= 0x0020;
+
+ return ret;
+}
+
+#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
+static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 loop_or = 0;
+ u16 adj_loopback_gain = phy->loopback_gain[0];
+ u8 loop;
+ u16 extern_lna_control;
+
+ if (!phy->gmode)
+ return 0;
+ if (!has_loopback_gain(phy)) {
+ if (phy->rev < 7 || !(dev->dev->bus->sprom.r1.boardflags_lo
+ & B43legacy_BFL_EXTLNA)) {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x0FB2;
+ case LPD(0, 0, 1):
+ return 0x00B2;
+ case LPD(1, 0, 1):
+ return 0x30B2;
+ case LPD(1, 0, 0):
+ return 0x30B3;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ } else {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x8FB2;
+ case LPD(0, 0, 1):
+ return 0x80B2;
+ case LPD(1, 0, 1):
+ return 0x20B2;
+ case LPD(1, 0, 0):
+ return 0x20B3;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ }
+ } else {
+ if (phy->radio_rev == 8)
+ adj_loopback_gain += 0x003E;
+ else
+ adj_loopback_gain += 0x0026;
+ if (adj_loopback_gain >= 0x46) {
+ adj_loopback_gain -= 0x46;
+ extern_lna_control = 0x3000;
+ } else if (adj_loopback_gain >= 0x3A) {
+ adj_loopback_gain -= 0x3A;
+ extern_lna_control = 0x2000;
+ } else if (adj_loopback_gain >= 0x2E) {
+ adj_loopback_gain -= 0x2E;
+ extern_lna_control = 0x1000;
+ } else {
+ adj_loopback_gain -= 0x10;
+ extern_lna_control = 0x0000;
+ }
+ for (loop = 0; loop < 16; loop++) {
+ u16 tmp = adj_loopback_gain - 6 * loop;
+ if (tmp < 6)
+ break;
+ }
+
+ loop_or = (loop << 8) | extern_lna_control;
+ if (phy->rev >= 7 && dev->dev->bus->sprom.r1.boardflags_lo
+ & B43legacy_BFL_EXTLNA) {
+ if (extern_lna_control)
+ loop_or |= 0x8000;
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x8F92;
+ case LPD(0, 0, 1):
+ return (0x8092 | loop_or);
+ case LPD(1, 0, 1):
+ return (0x2092 | loop_or);
+ case LPD(1, 0, 0):
+ return (0x2093 | loop_or);
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ } else {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x0F92;
+ case LPD(0, 0, 1):
+ case LPD(1, 0, 1):
+ return (0x0092 | loop_or);
+ case LPD(1, 0, 0):
+ return (0x0093 | loop_or);
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ }
+ }
+ return 0;
+}
+
+u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 backup[21] = { 0 };
+ u16 ret;
+ u16 i;
+ u16 j;
+ u32 tmp1 = 0;
+ u32 tmp2 = 0;
+
+ backup[0] = b43legacy_radio_read16(dev, 0x0043);
+ backup[14] = b43legacy_radio_read16(dev, 0x0051);
+ backup[15] = b43legacy_radio_read16(dev, 0x0052);
+ backup[1] = b43legacy_phy_read(dev, 0x0015);
+ backup[16] = b43legacy_phy_read(dev, 0x005A);
+ backup[17] = b43legacy_phy_read(dev, 0x0059);
+ backup[18] = b43legacy_phy_read(dev, 0x0058);
+ if (phy->type == B43legacy_PHYTYPE_B) {
+ backup[2] = b43legacy_phy_read(dev, 0x0030);
+ backup[3] = b43legacy_read16(dev, 0x03EC);
+ b43legacy_phy_write(dev, 0x0030, 0x00FF);
+ b43legacy_write16(dev, 0x03EC, 0x3F3F);
+ } else {
+ if (phy->gmode) {
+ backup[4] = b43legacy_phy_read(dev, 0x0811);
+ backup[5] = b43legacy_phy_read(dev, 0x0812);
+ backup[6] = b43legacy_phy_read(dev, 0x0814);
+ backup[7] = b43legacy_phy_read(dev, 0x0815);
+ backup[8] = b43legacy_phy_read(dev,
+ B43legacy_PHY_G_CRS);
+ backup[9] = b43legacy_phy_read(dev, 0x0802);
+ b43legacy_phy_write(dev, 0x0814,
+ (b43legacy_phy_read(dev, 0x0814)
+ | 0x0003));
+ b43legacy_phy_write(dev, 0x0815,
+ (b43legacy_phy_read(dev, 0x0815)
+ & 0xFFFC));
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ (b43legacy_phy_read(dev,
+ B43legacy_PHY_G_CRS) & 0x7FFF));
+ b43legacy_phy_write(dev, 0x0802,
+ (b43legacy_phy_read(dev, 0x0802)
+ & 0xFFFC));
+ if (phy->rev > 1) { /* loopback gain enabled */
+ backup[19] = b43legacy_phy_read(dev, 0x080F);
+ backup[20] = b43legacy_phy_read(dev, 0x0810);
+ if (phy->rev >= 3)
+ b43legacy_phy_write(dev, 0x080F,
+ 0xC020);
+ else
+ b43legacy_phy_write(dev, 0x080F,
+ 0x8020);
+ b43legacy_phy_write(dev, 0x0810, 0x0000);
+ }
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(0, 1, 1)));
+ if (phy->rev < 7 ||
+ !(dev->dev->bus->sprom.r1.boardflags_lo
+ & B43legacy_BFL_EXTLNA))
+ b43legacy_phy_write(dev, 0x0811, 0x01B3);
+ else
+ b43legacy_phy_write(dev, 0x0811, 0x09B3);
+ }
+ }
+ b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
+ (b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO)
+ | 0x8000));
+ backup[10] = b43legacy_phy_read(dev, 0x0035);
+ b43legacy_phy_write(dev, 0x0035,
+ (b43legacy_phy_read(dev, 0x0035) & 0xFF7F));
+ backup[11] = b43legacy_read16(dev, 0x03E6);
+ backup[12] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
+
+ /* Initialization */
+ if (phy->analog == 0)
+ b43legacy_write16(dev, 0x03E6, 0x0122);
+ else {
+ if (phy->analog >= 2)
+ b43legacy_phy_write(dev, 0x0003,
+ (b43legacy_phy_read(dev, 0x0003)
+ & 0xFFBF) | 0x0040);
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+ (b43legacy_read16(dev,
+ B43legacy_MMIO_CHANNEL_EXT) | 0x2000));
+ }
+
+ ret = b43legacy_radio_calibrationvalue(dev);
+
+ if (phy->type == B43legacy_PHYTYPE_B)
+ b43legacy_radio_write16(dev, 0x0078, 0x0026);
+
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(0, 1, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xBFAF);
+ b43legacy_phy_write(dev, 0x002B, 0x1403);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(0, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xBFA0);
+ b43legacy_radio_write16(dev, 0x0051,
+ (b43legacy_radio_read16(dev, 0x0051)
+ | 0x0004));
+ if (phy->radio_rev == 8)
+ b43legacy_radio_write16(dev, 0x0043, 0x001F);
+ else {
+ b43legacy_radio_write16(dev, 0x0052, 0x0000);
+ b43legacy_radio_write16(dev, 0x0043,
+ (b43legacy_radio_read16(dev, 0x0043)
+ & 0xFFF0) | 0x0009);
+ }
+ b43legacy_phy_write(dev, 0x0058, 0x0000);
+
+ for (i = 0; i < 16; i++) {
+ b43legacy_phy_write(dev, 0x005A, 0x0480);
+ b43legacy_phy_write(dev, 0x0059, 0xC810);
+ b43legacy_phy_write(dev, 0x0058, 0x000D);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xAFB0);
+ udelay(10);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xEFB0);
+ udelay(10);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 0)));
+ b43legacy_phy_write(dev, 0x0015, 0xFFF0);
+ udelay(20);
+ tmp1 += b43legacy_phy_read(dev, 0x002D);
+ b43legacy_phy_write(dev, 0x0058, 0x0000);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xAFB0);
+ }
+
+ tmp1++;
+ tmp1 >>= 9;
+ udelay(10);
+ b43legacy_phy_write(dev, 0x0058, 0x0000);
+
+ for (i = 0; i < 16; i++) {
+ b43legacy_radio_write16(dev, 0x0078, (flip_4bit(i) << 1)
+ | 0x0020);
+ backup[13] = b43legacy_radio_read16(dev, 0x0078);
+ udelay(10);
+ for (j = 0; j < 16; j++) {
+ b43legacy_phy_write(dev, 0x005A, 0x0D80);
+ b43legacy_phy_write(dev, 0x0059, 0xC810);
+ b43legacy_phy_write(dev, 0x0058, 0x000D);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xAFB0);
+ udelay(10);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xEFB0);
+ udelay(10);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 0)));
+ b43legacy_phy_write(dev, 0x0015, 0xFFF0);
+ udelay(10);
+ tmp2 += b43legacy_phy_read(dev, 0x002D);
+ b43legacy_phy_write(dev, 0x0058, 0x0000);
+ if (phy->gmode)
+ b43legacy_phy_write(dev, 0x0812,
+ b43legacy_get_812_value(dev,
+ LPD(1, 0, 1)));
+ b43legacy_phy_write(dev, 0x0015, 0xAFB0);
+ }
+ tmp2++;
+ tmp2 >>= 8;
+ if (tmp1 < tmp2)
+ break;
+ }
+
+ /* Restore the registers */
+ b43legacy_phy_write(dev, 0x0015, backup[1]);
+ b43legacy_radio_write16(dev, 0x0051, backup[14]);
+ b43legacy_radio_write16(dev, 0x0052, backup[15]);
+ b43legacy_radio_write16(dev, 0x0043, backup[0]);
+ b43legacy_phy_write(dev, 0x005A, backup[16]);
+ b43legacy_phy_write(dev, 0x0059, backup[17]);
+ b43legacy_phy_write(dev, 0x0058, backup[18]);
+ b43legacy_write16(dev, 0x03E6, backup[11]);
+ if (phy->analog != 0)
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[12]);
+ b43legacy_phy_write(dev, 0x0035, backup[10]);
+ b43legacy_radio_selectchannel(dev, phy->channel, 1);
+ if (phy->type == B43legacy_PHYTYPE_B) {
+ b43legacy_phy_write(dev, 0x0030, backup[2]);
+ b43legacy_write16(dev, 0x03EC, backup[3]);
+ } else {
+ if (phy->gmode) {
+ b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
+ (b43legacy_read16(dev,
+ B43legacy_MMIO_PHY_RADIO) & 0x7FFF));
+ b43legacy_phy_write(dev, 0x0811, backup[4]);
+ b43legacy_phy_write(dev, 0x0812, backup[5]);
+ b43legacy_phy_write(dev, 0x0814, backup[6]);
+ b43legacy_phy_write(dev, 0x0815, backup[7]);
+ b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+ backup[8]);
+ b43legacy_phy_write(dev, 0x0802, backup[9]);
+ if (phy->rev > 1) {
+ b43legacy_phy_write(dev, 0x080F, backup[19]);
+ b43legacy_phy_write(dev, 0x0810, backup[20]);
+ }
+ }
+ }
+ if (i >= 15)
+ ret = backup[13];
+
+ return ret;
+}
+
+static inline
+u16 freq_r3A_value(u16 frequency)
+{
+ u16 value;
+
+ if (frequency < 5091)
+ value = 0x0040;
+ else if (frequency < 5321)
+ value = 0x0000;
+ else if (frequency < 5806)
+ value = 0x0080;
+ else
+ value = 0x0040;
+
+ return value;
+}
+
+void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev)
+{
+ static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
+ static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
+ u16 tmp = b43legacy_radio_read16(dev, 0x001E);
+ int i;
+ int j;
+
+ for (i = 0; i < 5; i++) {
+ for (j = 0; j < 5; j++) {
+ if (tmp == (data_high[i] | data_low[j])) {
+ b43legacy_phy_write(dev, 0x0069, (i - j) << 8 |
+ 0x00C0);
+ return;
+ }
+ }
+ }
+}
+
+int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,
+ u8 channel,
+ int synthetic_pu_workaround)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (channel == 0xFF) {
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ case B43legacy_PHYTYPE_G:
+ channel = B43legacy_RADIO_DEFAULT_CHANNEL_BG;
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+ }
+
+/* TODO: Check if channel is valid - return -EINVAL if not */
+ if (synthetic_pu_workaround)
+ b43legacy_synth_pu_workaround(dev, channel);
+
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
+ channel2freq_bg(channel));
+
+ if (channel == 14) {
+ if (dev->dev->bus->sprom.r1.country_code == 5) /* JAPAN) */
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ b43legacy_shm_read32(dev,
+ B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET)
+ & ~(1 << 7));
+ else
+ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET,
+ b43legacy_shm_read32(dev,
+ B43legacy_SHM_SHARED,
+ B43legacy_UCODEFLAGS_OFFSET)
+ | (1 << 7));
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+ b43legacy_read16(dev,
+ B43legacy_MMIO_CHANNEL_EXT) | (1 << 11));
+ } else
+ b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+ b43legacy_read16(dev,
+ B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF);
+
+ phy->channel = channel;
+ /*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
+ * that 2000 usecs might suffice. */
+ msleep(8);
+
+ return 0;
+}
+
+void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val)
+{
+ u16 tmp;
+
+ val <<= 8;
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val);
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val);
+ tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF;
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val);
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
+static u16 b43legacy_get_txgain_base_band(u16 txpower)
+{
+ u16 ret;
+
+ B43legacy_WARN_ON(txpower > 63);
+
+ if (txpower >= 54)
+ ret = 2;
+ else if (txpower >= 49)
+ ret = 4;
+ else if (txpower >= 44)
+ ret = 5;
+ else
+ ret = 6;
+
+ return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
+static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower)
+{
+ u16 ret;
+
+ B43legacy_WARN_ON(txpower > 63);
+
+ if (txpower >= 32)
+ ret = 0;
+ else if (txpower >= 25)
+ ret = 1;
+ else if (txpower >= 20)
+ ret = 2;
+ else if (txpower >= 12)
+ ret = 3;
+ else
+ ret = 4;
+
+ return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
+static u16 b43legacy_get_txgain_dac(u16 txpower)
+{
+ u16 ret;
+
+ B43legacy_WARN_ON(txpower > 63);
+
+ if (txpower >= 54)
+ ret = txpower - 53;
+ else if (txpower >= 49)
+ ret = txpower - 42;
+ else if (txpower >= 44)
+ ret = txpower - 37;
+ else if (txpower >= 32)
+ ret = txpower - 32;
+ else if (txpower >= 25)
+ ret = txpower - 20;
+ else if (txpower >= 20)
+ ret = txpower - 13;
+ else if (txpower >= 12)
+ ret = txpower - 8;
+ else
+ ret = txpower;
+
+ return ret;
+}
+
+void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 pamp;
+ u16 base;
+ u16 dac;
+ u16 ilt;
+
+ txpower = limit_value(txpower, 0, 63);
+
+ pamp = b43legacy_get_txgain_freq_power_amp(txpower);
+ pamp <<= 5;
+ pamp &= 0x00E0;
+ b43legacy_phy_write(dev, 0x0019, pamp);
+
+ base = b43legacy_get_txgain_base_band(txpower);
+ base &= 0x000F;
+ b43legacy_phy_write(dev, 0x0017, base | 0x0020);
+
+ ilt = b43legacy_ilt_read(dev, 0x3001);
+ ilt &= 0x0007;
+
+ dac = b43legacy_get_txgain_dac(txpower);
+ dac <<= 3;
+ dac |= ilt;
+
+ b43legacy_ilt_write(dev, 0x3001, dac);
+
+ phy->txpwr_offset = txpower;
+
+ /* TODO: FuncPlaceholder (Adjust BB loft cancel) */
+}
+
+void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
+ u16 baseband_attenuation,
+ u16 radio_attenuation,
+ u16 txpower)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (baseband_attenuation == 0xFFFF)
+ baseband_attenuation = phy->bbatt;
+ if (radio_attenuation == 0xFFFF)
+ radio_attenuation = phy->rfatt;
+ if (txpower == 0xFFFF)
+ txpower = phy->txctl1;
+ phy->bbatt = baseband_attenuation;
+ phy->rfatt = radio_attenuation;
+ phy->txctl1 = txpower;
+
+ B43legacy_WARN_ON(baseband_attenuation > 11);
+ if (phy->radio_rev < 6)
+ B43legacy_WARN_ON(radio_attenuation > 9);
+ else
+ B43legacy_WARN_ON(radio_attenuation > 31);
+ B43legacy_WARN_ON(txpower > 7);
+
+ b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation);
+ b43legacy_radio_write16(dev, 0x0043, radio_attenuation);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064,
+ radio_attenuation);
+ if (phy->radio_ver == 0x2050)
+ b43legacy_radio_write16(dev, 0x0052,
+ (b43legacy_radio_read16(dev, 0x0052)
+ & ~0x0070) | ((txpower << 4) & 0x0070));
+ /* FIXME: The spec is very weird and unclear here. */
+ if (phy->type == B43legacy_PHYTYPE_G)
+ b43legacy_phy_lo_adjust(dev, 0);
+}
+
+u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
+ return 0;
+ return 2;
+}
+
+u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ u16 att = 0xFFFF;
+
+ switch (phy->radio_ver) {
+ case 0x2053:
+ switch (phy->radio_rev) {
+ case 1:
+ att = 6;
+ break;
+ }
+ break;
+ case 0x2050:
+ switch (phy->radio_rev) {
+ case 0:
+ att = 5;
+ break;
+ case 1:
+ if (phy->type == B43legacy_PHYTYPE_G) {
+ if (is_bcm_board_vendor(dev) &&
+ dev->dev->bus->boardinfo.type == 0x421 &&
+ dev->dev->bus->boardinfo.rev >= 30)
+ att = 3;
+ else if (is_bcm_board_vendor(dev) &&
+ dev->dev->bus->boardinfo.type == 0x416)
+ att = 3;
+ else
+ att = 1;
+ } else {
+ if (is_bcm_board_vendor(dev) &&
+ dev->dev->bus->boardinfo.type == 0x421 &&
+ dev->dev->bus->boardinfo.rev >= 30)
+ att = 7;
+ else
+ att = 6;
+ }
+ break;
+ case 2:
+ if (phy->type == B43legacy_PHYTYPE_G) {
+ if (is_bcm_board_vendor(dev) &&
+ dev->dev->bus->boardinfo.type == 0x421 &&
+ dev->dev->bus->boardinfo.rev >= 30)
+ att = 3;
+ else if (is_bcm_board_vendor(dev) &&
+ dev->dev->bus->boardinfo.type ==
+ 0x416)
+ att = 5;
+ else if (dev->dev->bus->chip_id == 0x4320)
+ att = 4;
+ else
+ att = 3;
+ } else
+ att = 6;
+ break;
+ case 3:
+ att = 5;
+ break;
+ case 4:
+ case 5:
+ att = 1;
+ break;
+ case 6:
+ case 7:
+ att = 5;
+ break;
+ case 8:
+ att = 0x1A;
+ break;
+ case 9:
+ default:
+ att = 5;
+ }
+ }
+ if (is_bcm_board_vendor(dev) &&
+ dev->dev->bus->boardinfo.type == 0x421) {
+ if (dev->dev->bus->boardinfo.rev < 0x43)
+ att = 2;
+ else if (dev->dev->bus->boardinfo.rev < 0x51)
+ att = 3;
+ }
+ if (att == 0xFFFF)
+ att = 5;
+
+ return att;
+}
+
+u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (phy->radio_ver != 0x2050)
+ return 0;
+ if (phy->radio_rev == 1)
+ return 3;
+ if (phy->radio_rev < 6)
+ return 2;
+ if (phy->radio_rev == 8)
+ return 1;
+ return 0;
+}
+
+void b43legacy_radio_turn_on(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ int err;
+ u8 channel;
+
+ might_sleep();
+
+ if (phy->radio_on)
+ return;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ case B43legacy_PHYTYPE_G:
+ b43legacy_phy_write(dev, 0x0015, 0x8000);
+ b43legacy_phy_write(dev, 0x0015, 0xCC00);
+ b43legacy_phy_write(dev, 0x0015,
+ (phy->gmode ? 0x00C0 : 0x0000));
+ if (phy->radio_off_context.valid) {
+ /* Restore the RFover values. */
+ b43legacy_phy_write(dev, B43legacy_PHY_RFOVER,
+ phy->radio_off_context.rfover);
+ b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
+ phy->radio_off_context.rfoverval);
+ phy->radio_off_context.valid = 0;
+ }
+ channel = phy->channel;
+ err = b43legacy_radio_selectchannel(dev,
+ B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1);
+ err |= b43legacy_radio_selectchannel(dev, channel, 0);
+ B43legacy_WARN_ON(err);
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+ phy->radio_on = 1;
+ b43legacy_leds_update(dev, 0);
+}
+
+void b43legacy_radio_turn_off(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) {
+ u16 rfover, rfoverval;
+
+ rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER);
+ rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL);
+ phy->radio_off_context.rfover = rfover;
+ phy->radio_off_context.rfoverval = rfoverval;
+ phy->radio_off_context.valid = 1;
+ b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C);
+ b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
+ rfoverval & 0xFF73);
+ } else
+ b43legacy_phy_write(dev, 0x0015, 0xAA00);
+ phy->radio_on = 0;
+ b43legacydbg(dev->wl, "Radio initialized\n");
+ b43legacy_leds_update(dev, 0);
+}
+
+void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+
+ switch (phy->type) {
+ case B43legacy_PHYTYPE_B:
+ case B43legacy_PHYTYPE_G:
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058,
+ 0x7F7F);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a,
+ 0x7F7F);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070,
+ 0x7F7F);
+ b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072,
+ 0x7F7F);
+ break;
+ }
+}
diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h
new file mode 100644
index 00000000000..6c6a203439e
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/radio.h
@@ -0,0 +1,98 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+ Stefano Brivio <st3@riseup.net>
+ Michael Buesch <mbuesch@freenet.de>
+ Danny van Dyk <kugelfang@gentoo.org>
+ Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+ Some parts of the code in this file are derived from the ipw2200
+ driver Copyright(c) 2003 - 2004 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef B43legacy_RADIO_H_
+#define B43legacy_RADIO_H_
+
+#include "b43legacy.h"
+
+
+#define B43legacy_RADIO_DEFAULT_CHANNEL_BG 6
+
+/* Force antenna 0. */
+#define B43legacy_RADIO_TXANTENNA_0 0
+/* Force antenna 1. */
+#define B43legacy_RADIO_TXANTENNA_1 1
+/* Use the RX antenna, that was selected for the most recently
+ * received good PLCP header.
+ */
+#define B43legacy_RADIO_TXANTENNA_LASTPLCP 3
+#define B43legacy_RADIO_TXANTENNA_DEFAULT B43legacy_RADIO_TXANTENNA_LASTPLCP
+
+#define B43legacy_RADIO_INTERFMODE_NONE 0
+#define B43legacy_RADIO_INTERFMODE_NONWLAN 1
+#define B43legacy_RADIO_INTERFMODE_MANUALWLAN 2
+#define B43legacy_RADIO_INTERFMODE_AUTOWLAN 3
+
+
+void b43legacy_radio_lock(struct b43legacy_wldev *dev);
+void b43legacy_radio_unlock(struct b43legacy_wldev *dev);
+
+u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset);
+void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val);
+
+u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev);
+
+void b43legacy_radio_turn_on(struct b43legacy_wldev *dev);
+void b43legacy_radio_turn_off(struct b43legacy_wldev *dev);
+
+int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, u8 channel,
+ int synthetic_pu_workaround);
+
+void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower);
+void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
+ u16 baseband_attenuation, u16 attenuation,
+ u16 txpower);
+
+u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev);
+u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev);
+u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev);
+
+void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val);
+
+void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev);
+
+u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel);
+u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev);
+
+int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev,
+ int mode);
+
+void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev);
+void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev);
+s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset);
+void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val);
+void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val);
+void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev);
+
+void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev);
+u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev);
+
+#endif /* B43legacy_RADIO_H_ */
diff --git a/drivers/net/wireless/b43legacy/sysfs.c b/drivers/net/wireless/b43legacy/sysfs.c
new file mode 100644
index 00000000000..56c384fa9b1
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/sysfs.c
@@ -0,0 +1,238 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ SYSFS support routines
+
+ Copyright (c) 2006 Michael Buesch <mb@bu3sch.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include "sysfs.h"
+#include "b43legacy.h"
+#include "main.h"
+#include "phy.h"
+#include "radio.h"
+
+#include <linux/capability.h>
+
+
+#define GENERIC_FILESIZE 64
+
+
+static int get_integer(const char *buf, size_t count)
+{
+ char tmp[10 + 1] = { 0 };
+ int ret = -EINVAL;
+
+ if (count == 0)
+ goto out;
+ count = min(count, (size_t)10);
+ memcpy(tmp, buf, count);
+ ret = simple_strtol(tmp, NULL, 10);
+out:
+ return ret;
+}
+
+static int get_boolean(const char *buf, size_t count)
+{
+ if (count != 0) {
+ if (buf[0] == '1')
+ return 1;
+ if (buf[0] == '0')
+ return 0;
+ if (count >= 4 && memcmp(buf, "true", 4) == 0)
+ return 1;
+ if (count >= 5 && memcmp(buf, "false", 5) == 0)
+ return 0;
+ if (count >= 3 && memcmp(buf, "yes", 3) == 0)
+ return 1;
+ if (count >= 2 && memcmp(buf, "no", 2) == 0)
+ return 0;
+ if (count >= 2 && memcmp(buf, "on", 2) == 0)
+ return 1;
+ if (count >= 3 && memcmp(buf, "off", 3) == 0)
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static ssize_t b43legacy_attr_interfmode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
+ ssize_t count = 0;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mutex_lock(&wldev->wl->mutex);
+
+ switch (wldev->phy.interfmode) {
+ case B43legacy_INTERFMODE_NONE:
+ count = snprintf(buf, PAGE_SIZE, "0 (No Interference"
+ " Mitigation)\n");
+ break;
+ case B43legacy_INTERFMODE_NONWLAN:
+ count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference"
+ " Mitigation)\n");
+ break;
+ case B43legacy_INTERFMODE_MANUALWLAN:
+ count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference"
+ " Mitigation)\n");
+ break;
+ default:
+ B43legacy_WARN_ON(1);
+ }
+
+ mutex_unlock(&wldev->wl->mutex);
+
+ return count;
+}
+
+static ssize_t b43legacy_attr_interfmode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
+ unsigned long flags;
+ int err;
+ int mode;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mode = get_integer(buf, count);
+ switch (mode) {
+ case 0:
+ mode = B43legacy_INTERFMODE_NONE;
+ break;
+ case 1:
+ mode = B43legacy_INTERFMODE_NONWLAN;
+ break;
+ case 2:
+ mode = B43legacy_INTERFMODE_MANUALWLAN;
+ break;
+ case 3:
+ mode = B43legacy_INTERFMODE_AUTOWLAN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&wldev->wl->mutex);
+ spin_lock_irqsave(&wldev->wl->irq_lock, flags);
+
+ err = b43legacy_radio_set_interference_mitigation(wldev, mode);
+ if (err)
+ b43legacyerr(wldev->wl, "Interference Mitigation not "
+ "supported by device\n");
+ mmiowb();
+ spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
+ mutex_unlock(&wldev->wl->mutex);
+
+ return err ? err : count;
+}
+
+static DEVICE_ATTR(interference, 0644,
+ b43legacy_attr_interfmode_show,
+ b43legacy_attr_interfmode_store);
+
+static ssize_t b43legacy_attr_preamble_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
+ ssize_t count;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mutex_lock(&wldev->wl->mutex);
+
+ if (wldev->short_preamble)
+ count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble"
+ " enabled)\n");
+ else
+ count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble"
+ " disabled)\n");
+
+ mutex_unlock(&wldev->wl->mutex);
+
+ return count;
+}
+
+static ssize_t b43legacy_attr_preamble_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
+ unsigned long flags;
+ int value;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ value = get_boolean(buf, count);
+ if (value < 0)
+ return value;
+ mutex_lock(&wldev->wl->mutex);
+ spin_lock_irqsave(&wldev->wl->irq_lock, flags);
+
+ wldev->short_preamble = !!value;
+
+ spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
+ mutex_unlock(&wldev->wl->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(shortpreamble, 0644,
+ b43legacy_attr_preamble_show,
+ b43legacy_attr_preamble_store);
+
+int b43legacy_sysfs_register(struct b43legacy_wldev *wldev)
+{
+ struct device *dev = wldev->dev->dev;
+ int err;
+
+ B43legacy_WARN_ON(b43legacy_status(wldev) !=
+ B43legacy_STAT_INITIALIZED);
+
+ err = device_create_file(dev, &dev_attr_interference);
+ if (err)
+ goto out;
+ err = device_create_file(dev, &dev_attr_shortpreamble);
+ if (err)
+ goto err_remove_interfmode;
+
+out:
+ return err;
+err_remove_interfmode:
+ device_remove_file(dev, &dev_attr_interference);
+ goto out;
+}
+
+void b43legacy_sysfs_unregister(struct b43legacy_wldev *wldev)
+{
+ struct device *dev = wldev->dev->dev;
+
+ device_remove_file(dev, &dev_attr_shortpreamble);
+ device_remove_file(dev, &dev_attr_interference);
+}
diff --git a/drivers/net/wireless/b43legacy/sysfs.h b/drivers/net/wireless/b43legacy/sysfs.h
new file mode 100644
index 00000000000..417d509803c
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/sysfs.h
@@ -0,0 +1,9 @@
+#ifndef B43legacy_SYSFS_H_
+#define B43legacy_SYSFS_H_
+
+struct b43legacy_wldev;
+
+int b43legacy_sysfs_register(struct b43legacy_wldev *dev);
+void b43legacy_sysfs_unregister(struct b43legacy_wldev *dev);
+
+#endif /* B43legacy_SYSFS_H_ */
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
new file mode 100644
index 00000000000..fa1e65687a6
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -0,0 +1,642 @@
+/*
+
+ Broadcom B43legacy wireless driver
+
+ Transmission (TX/RX) related functions.
+
+ Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+ Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+ Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ Copyright (C) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <net/dst.h>
+
+#include "xmit.h"
+#include "phy.h"
+#include "dma.h"
+#include "pio.h"
+
+
+/* Extract the bitrate out of a CCK PLCP header. */
+static u8 b43legacy_plcp_get_bitrate_cck(struct b43legacy_plcp_hdr6 *plcp)
+{
+ switch (plcp->raw[0]) {
+ case 0x0A:
+ return B43legacy_CCK_RATE_1MB;
+ case 0x14:
+ return B43legacy_CCK_RATE_2MB;
+ case 0x37:
+ return B43legacy_CCK_RATE_5MB;
+ case 0x6E:
+ return B43legacy_CCK_RATE_11MB;
+ }
+ B43legacy_BUG_ON(1);
+ return 0;
+}
+
+/* Extract the bitrate out of an OFDM PLCP header. */
+static u8 b43legacy_plcp_get_bitrate_ofdm(struct b43legacy_plcp_hdr6 *plcp)
+{
+ switch (plcp->raw[0] & 0xF) {
+ case 0xB:
+ return B43legacy_OFDM_RATE_6MB;
+ case 0xF:
+ return B43legacy_OFDM_RATE_9MB;
+ case 0xA:
+ return B43legacy_OFDM_RATE_12MB;
+ case 0xE:
+ return B43legacy_OFDM_RATE_18MB;
+ case 0x9:
+ return B43legacy_OFDM_RATE_24MB;
+ case 0xD:
+ return B43legacy_OFDM_RATE_36MB;
+ case 0x8:
+ return B43legacy_OFDM_RATE_48MB;
+ case 0xC:
+ return B43legacy_OFDM_RATE_54MB;
+ }
+ B43legacy_BUG_ON(1);
+ return 0;
+}
+
+u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate)
+{
+ switch (bitrate) {
+ case B43legacy_CCK_RATE_1MB:
+ return 0x0A;
+ case B43legacy_CCK_RATE_2MB:
+ return 0x14;
+ case B43legacy_CCK_RATE_5MB:
+ return 0x37;
+ case B43legacy_CCK_RATE_11MB:
+ return 0x6E;
+ }
+ B43legacy_BUG_ON(1);
+ return 0;
+}
+
+u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate)
+{
+ switch (bitrate) {
+ case B43legacy_OFDM_RATE_6MB:
+ return 0xB;
+ case B43legacy_OFDM_RATE_9MB:
+ return 0xF;
+ case B43legacy_OFDM_RATE_12MB:
+ return 0xA;
+ case B43legacy_OFDM_RATE_18MB:
+ return 0xE;
+ case B43legacy_OFDM_RATE_24MB:
+ return 0x9;
+ case B43legacy_OFDM_RATE_36MB:
+ return 0xD;
+ case B43legacy_OFDM_RATE_48MB:
+ return 0x8;
+ case B43legacy_OFDM_RATE_54MB:
+ return 0xC;
+ }
+ B43legacy_BUG_ON(1);
+ return 0;
+}
+
+void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp,
+ const u16 octets, const u8 bitrate)
+{
+ __le32 *data = &(plcp->data);
+ __u8 *raw = plcp->raw;
+
+ if (b43legacy_is_ofdm_rate(bitrate)) {
+ u16 d;
+
+ d = b43legacy_plcp_get_ratecode_ofdm(bitrate);
+ B43legacy_WARN_ON(octets & 0xF000);
+ d |= (octets << 5);
+ *data = cpu_to_le32(d);
+ } else {
+ u32 plen;
+
+ plen = octets * 16 / bitrate;
+ if ((octets * 16 % bitrate) > 0) {
+ plen++;
+ if ((bitrate == B43legacy_CCK_RATE_11MB)
+ && ((octets * 8 % 11) < 4))
+ raw[1] = 0x84;
+ else
+ raw[1] = 0x04;
+ } else
+ raw[1] = 0x04;
+ *data |= cpu_to_le32(plen << 16);
+ raw[0] = b43legacy_plcp_get_ratecode_cck(bitrate);
+ }
+}
+
+static u8 b43legacy_calc_fallback_rate(u8 bitrate)
+{
+ switch (bitrate) {
+ case B43legacy_CCK_RATE_1MB:
+ return B43legacy_CCK_RATE_1MB;
+ case B43legacy_CCK_RATE_2MB:
+ return B43legacy_CCK_RATE_1MB;
+ case B43legacy_CCK_RATE_5MB:
+ return B43legacy_CCK_RATE_2MB;
+ case B43legacy_CCK_RATE_11MB:
+ return B43legacy_CCK_RATE_5MB;
+ case B43legacy_OFDM_RATE_6MB:
+ return B43legacy_CCK_RATE_5MB;
+ case B43legacy_OFDM_RATE_9MB:
+ return B43legacy_OFDM_RATE_6MB;
+ case B43legacy_OFDM_RATE_12MB:
+ return B43legacy_OFDM_RATE_9MB;
+ case B43legacy_OFDM_RATE_18MB:
+ return B43legacy_OFDM_RATE_12MB;
+ case B43legacy_OFDM_RATE_24MB:
+ return B43legacy_OFDM_RATE_18MB;
+ case B43legacy_OFDM_RATE_36MB:
+ return B43legacy_OFDM_RATE_24MB;
+ case B43legacy_OFDM_RATE_48MB:
+ return B43legacy_OFDM_RATE_36MB;
+ case B43legacy_OFDM_RATE_54MB:
+ return B43legacy_OFDM_RATE_48MB;
+ }
+ B43legacy_BUG_ON(1);
+ return 0;
+}
+
+static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
+ struct b43legacy_txhdr_fw3 *txhdr,
+ const unsigned char *fragment_data,
+ unsigned int fragment_len,
+ const struct ieee80211_tx_control *txctl,
+ u16 cookie)
+{
+ const struct ieee80211_hdr *wlhdr;
+ int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
+ u16 fctl;
+ u8 rate;
+ u8 rate_fb;
+ int rate_ofdm;
+ int rate_fb_ofdm;
+ unsigned int plcp_fragment_len;
+ u32 mac_ctl = 0;
+ u16 phy_ctl = 0;
+
+ wlhdr = (const struct ieee80211_hdr *)fragment_data;
+ fctl = le16_to_cpu(wlhdr->frame_control);
+
+ memset(txhdr, 0, sizeof(*txhdr));
+
+ rate = txctl->tx_rate;
+ rate_ofdm = b43legacy_is_ofdm_rate(rate);
+ rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
+ rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb);
+
+ txhdr->mac_frame_ctl = wlhdr->frame_control;
+ memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
+
+ /* Calculate duration for fallback rate */
+ if ((rate_fb == rate) ||
+ (wlhdr->duration_id & cpu_to_le16(0x8000)) ||
+ (wlhdr->duration_id == cpu_to_le16(0))) {
+ /* If the fallback rate equals the normal rate or the
+ * dur_id field contains an AID, CFP magic or 0,
+ * use the original dur_id field. */
+ txhdr->dur_fb = wlhdr->duration_id;
+ } else {
+ int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb);
+ txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
+ dev->wl->if_id,
+ fragment_len,
+ fbrate_base100kbps);
+ }
+
+ plcp_fragment_len = fragment_len + FCS_LEN;
+ if (use_encryption) {
+ u8 key_idx = (u16)(txctl->key_idx);
+ struct b43legacy_key *key;
+ int wlhdr_len;
+ size_t iv_len;
+
+ B43legacy_WARN_ON(key_idx >= dev->max_nr_keys);
+ key = &(dev->key[key_idx]);
+
+ if (key->enabled) {
+ /* Hardware appends ICV. */
+ plcp_fragment_len += txctl->icv_len;
+
+ key_idx = b43legacy_kidx_to_fw(dev, key_idx);
+ mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) &
+ B43legacy_TX4_MAC_KEYIDX;
+ mac_ctl |= (key->algorithm <<
+ B43legacy_TX4_MAC_KEYALG_SHIFT) &
+ B43legacy_TX4_MAC_KEYALG;
+ wlhdr_len = ieee80211_get_hdrlen(fctl);
+ iv_len = min((size_t)txctl->iv_len,
+ ARRAY_SIZE(txhdr->iv));
+ memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
+ }
+ }
+ b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
+ (&txhdr->plcp), plcp_fragment_len,
+ rate);
+ b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
+ (&txhdr->plcp_fb), plcp_fragment_len,
+ rate_fb);
+
+ /* PHY TX Control word */
+ if (rate_ofdm)
+ phy_ctl |= B43legacy_TX4_PHY_OFDM;
+ if (dev->short_preamble)
+ phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
+ switch (txctl->antenna_sel_tx) {
+ case 0:
+ phy_ctl |= B43legacy_TX4_PHY_ANTLAST;
+ break;
+ case 1:
+ phy_ctl |= B43legacy_TX4_PHY_ANT0;
+ break;
+ case 2:
+ phy_ctl |= B43legacy_TX4_PHY_ANT1;
+ break;
+ default:
+ B43legacy_BUG_ON(1);
+ }
+
+ /* MAC control */
+ if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
+ mac_ctl |= B43legacy_TX4_MAC_ACK;
+ if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+ ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
+ mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
+ if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
+ mac_ctl |= B43legacy_TX4_MAC_STMSDU;
+ if (rate_fb_ofdm)
+ mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
+
+ /* Generate the RTS or CTS-to-self frame */
+ if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
+ (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+ unsigned int len;
+ struct ieee80211_hdr *hdr;
+ int rts_rate;
+ int rts_rate_fb;
+ int rts_rate_ofdm;
+ int rts_rate_fb_ofdm;
+
+ rts_rate = txctl->rts_cts_rate;
+ rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate);
+ rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate);
+ rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb);
+ if (rts_rate_fb_ofdm)
+ mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
+
+ if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ ieee80211_ctstoself_get(dev->wl->hw,
+ dev->wl->if_id,
+ fragment_data,
+ fragment_len, txctl,
+ (struct ieee80211_cts *)
+ (txhdr->rts_frame));
+ mac_ctl |= B43legacy_TX4_MAC_SENDCTS;
+ len = sizeof(struct ieee80211_cts);
+ } else {
+ ieee80211_rts_get(dev->wl->hw,
+ dev->wl->if_id,
+ fragment_data, fragment_len, txctl,
+ (struct ieee80211_rts *)
+ (txhdr->rts_frame));
+ mac_ctl |= B43legacy_TX4_MAC_SENDRTS;
+ len = sizeof(struct ieee80211_rts);
+ }
+ len += FCS_LEN;
+ b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
+ (&txhdr->rts_plcp),
+ len, rts_rate);
+ b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
+ (&txhdr->rts_plcp_fb),
+ len, rts_rate_fb);
+ hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
+ txhdr->rts_dur_fb = hdr->duration_id;
+ mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
+ }
+
+ /* Magic cookie */
+ txhdr->cookie = cpu_to_le16(cookie);
+
+ /* Apply the bitfields */
+ txhdr->mac_ctl = cpu_to_le32(mac_ctl);
+ txhdr->phy_ctl = cpu_to_le16(phy_ctl);
+}
+
+void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
+ u8 *txhdr,
+ const unsigned char *fragment_data,
+ unsigned int fragment_len,
+ const struct ieee80211_tx_control *txctl,
+ u16 cookie)
+{
+ generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
+ fragment_data, fragment_len,
+ txctl, cookie);
+}
+
+static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev,
+ u8 in_rssi, int ofdm,
+ int adjust_2053, int adjust_2050)
+{
+ struct b43legacy_phy *phy = &dev->phy;
+ s32 tmp;
+
+ switch (phy->radio_ver) {
+ case 0x2050:
+ if (ofdm) {
+ tmp = in_rssi;
+ if (tmp > 127)
+ tmp -= 256;
+ tmp *= 73;
+ tmp /= 64;
+ if (adjust_2050)
+ tmp += 25;
+ else
+ tmp -= 3;
+ } else {
+ if (dev->dev->bus->sprom.r1.boardflags_lo
+ & B43legacy_BFL_RSSI) {
+ if (in_rssi > 63)
+ in_rssi = 63;
+ tmp = phy->nrssi_lt[in_rssi];
+ tmp = 31 - tmp;
+ tmp *= -131;
+ tmp /= 128;
+ tmp -= 57;
+ } else {
+ tmp = in_rssi;
+ tmp = 31 - tmp;
+ tmp *= -149;
+ tmp /= 128;
+ tmp -= 68;
+ }
+ if (phy->type == B43legacy_PHYTYPE_G &&
+ adjust_2050)
+ tmp += 25;
+ }
+ break;
+ case 0x2060:
+ if (in_rssi > 127)
+ tmp = in_rssi - 256;
+ else
+ tmp = in_rssi;
+ break;
+ default:
+ tmp = in_rssi;
+ tmp -= 11;
+ tmp *= 103;
+ tmp /= 64;
+ if (adjust_2053)
+ tmp -= 109;
+ else
+ tmp -= 83;
+ }
+
+ return (s8)tmp;
+}
+
+void b43legacy_rx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ const void *_rxhdr)
+{
+ struct ieee80211_rx_status status;
+ struct b43legacy_plcp_hdr6 *plcp;
+ struct ieee80211_hdr *wlhdr;
+ const struct b43legacy_rxhdr_fw3 *rxhdr = _rxhdr;
+ u16 fctl;
+ u16 phystat0;
+ u16 phystat3;
+ u16 chanstat;
+ u16 mactime;
+ u32 macstat;
+ u16 chanid;
+ u8 jssi;
+ int padding;
+
+ memset(&status, 0, sizeof(status));
+
+ /* Get metadata about the frame from the header. */
+ phystat0 = le16_to_cpu(rxhdr->phy_status0);
+ phystat3 = le16_to_cpu(rxhdr->phy_status3);
+ jssi = rxhdr->jssi;
+ macstat = le16_to_cpu(rxhdr->mac_status);
+ mactime = le16_to_cpu(rxhdr->mac_time);
+ chanstat = le16_to_cpu(rxhdr->channel);
+
+ if (macstat & B43legacy_RX_MAC_FCSERR)
+ dev->wl->ieee_stats.dot11FCSErrorCount++;
+
+ /* Skip PLCP and padding */
+ padding = (macstat & B43legacy_RX_MAC_PADDING) ? 2 : 0;
+ if (unlikely(skb->len < (sizeof(struct b43legacy_plcp_hdr6) +
+ padding))) {
+ b43legacydbg(dev->wl, "RX: Packet size underrun (1)\n");
+ goto drop;
+ }
+ plcp = (struct b43legacy_plcp_hdr6 *)(skb->data + padding);
+ skb_pull(skb, sizeof(struct b43legacy_plcp_hdr6) + padding);
+ /* The skb contains the Wireless Header + payload data now */
+ if (unlikely(skb->len < (2+2+6/*minimum hdr*/ + FCS_LEN))) {
+ b43legacydbg(dev->wl, "RX: Packet size underrun (2)\n");
+ goto drop;
+ }
+ wlhdr = (struct ieee80211_hdr *)(skb->data);
+ fctl = le16_to_cpu(wlhdr->frame_control);
+
+ if ((macstat & B43legacy_RX_MAC_DEC) &&
+ !(macstat & B43legacy_RX_MAC_DECERR)) {
+ unsigned int keyidx;
+ int wlhdr_len;
+ int iv_len;
+ int icv_len;
+
+ keyidx = ((macstat & B43legacy_RX_MAC_KEYIDX)
+ >> B43legacy_RX_MAC_KEYIDX_SHIFT);
+ /* We must adjust the key index here. We want the "physical"
+ * key index, but the ucode passed it slightly different.
+ */
+ keyidx = b43legacy_kidx_to_raw(dev, keyidx);
+ B43legacy_WARN_ON(keyidx >= dev->max_nr_keys);
+
+ if (dev->key[keyidx].algorithm != B43legacy_SEC_ALGO_NONE) {
+ /* Remove PROTECTED flag to mark it as decrypted. */
+ B43legacy_WARN_ON(!(fctl & IEEE80211_FCTL_PROTECTED));
+ fctl &= ~IEEE80211_FCTL_PROTECTED;
+ wlhdr->frame_control = cpu_to_le16(fctl);
+
+ wlhdr_len = ieee80211_get_hdrlen(fctl);
+ if (unlikely(skb->len < (wlhdr_len + 3))) {
+ b43legacydbg(dev->wl, "RX: Packet size"
+ " underrun3\n");
+ goto drop;
+ }
+ if (skb->data[wlhdr_len + 3] & (1 << 5)) {
+ /* The Ext-IV Bit is set in the "KeyID"
+ * octet of the IV.
+ */
+ iv_len = 8;
+ icv_len = 8;
+ } else {
+ iv_len = 4;
+ icv_len = 4;
+ }
+ if (unlikely(skb->len < (wlhdr_len + iv_len +
+ icv_len))) {
+ b43legacydbg(dev->wl, "RX: Packet size"
+ " underrun4\n");
+ goto drop;
+ }
+ /* Remove the IV */
+ memmove(skb->data + iv_len, skb->data, wlhdr_len);
+ skb_pull(skb, iv_len);
+ /* Remove the ICV */
+ skb_trim(skb, skb->len - icv_len);
+
+ status.flag |= RX_FLAG_DECRYPTED;
+ }
+ }
+
+ status.ssi = b43legacy_rssi_postprocess(dev, jssi,
+ (phystat0 & B43legacy_RX_PHYST0_OFDM),
+ (phystat0 & B43legacy_RX_PHYST0_GAINCTL),
+ (phystat3 & B43legacy_RX_PHYST3_TRSTATE));
+ status.noise = dev->stats.link_noise;
+ status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI;
+ if (phystat0 & B43legacy_RX_PHYST0_OFDM)
+ status.rate = b43legacy_plcp_get_bitrate_ofdm(plcp);
+ else
+ status.rate = b43legacy_plcp_get_bitrate_cck(plcp);
+ status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT);
+ status.mactime = mactime;
+
+ chanid = (chanstat & B43legacy_RX_CHAN_ID) >>
+ B43legacy_RX_CHAN_ID_SHIFT;
+ switch (chanstat & B43legacy_RX_CHAN_PHYTYPE) {
+ case B43legacy_PHYTYPE_B:
+ status.phymode = MODE_IEEE80211B;
+ status.freq = chanid + 2400;
+ status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
+ break;
+ case B43legacy_PHYTYPE_G:
+ status.phymode = MODE_IEEE80211G;
+ status.freq = chanid + 2400;
+ status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
+ break;
+ default:
+ b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n",
+ chanstat);
+ }
+
+ dev->stats.last_rx = jiffies;
+ ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+
+ return;
+drop:
+ b43legacydbg(dev->wl, "RX: Packet dropped\n");
+ dev_kfree_skb_any(skb);
+}
+
+void b43legacy_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status)
+{
+ b43legacy_debugfs_log_txstat(dev, status);
+
+ if (status->intermediate)
+ return;
+ if (status->for_ampdu)
+ return;
+ if (!status->acked)
+ dev->wl->ieee_stats.dot11ACKFailureCount++;
+ if (status->rts_count) {
+ if (status->rts_count == 0xF) /* FIXME */
+ dev->wl->ieee_stats.dot11RTSFailureCount++;
+ else
+ dev->wl->ieee_stats.dot11RTSSuccessCount++;
+ }
+
+ if (b43legacy_using_pio(dev))
+ b43legacy_pio_handle_txstatus(dev, status);
+ else
+ b43legacy_dma_handle_txstatus(dev, status);
+}
+
+/* Handle TX status report as received through DMA/PIO queues */
+void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_hwtxstatus *hw)
+{
+ struct b43legacy_txstatus status;
+ u8 tmp;
+
+ status.cookie = le16_to_cpu(hw->cookie);
+ status.seq = le16_to_cpu(hw->seq);
+ status.phy_stat = hw->phy_stat;
+ tmp = hw->count;
+ status.frame_count = (tmp >> 4);
+ status.rts_count = (tmp & 0x0F);
+ tmp = hw->flags;
+ status.supp_reason = ((tmp & 0x1C) >> 2);
+ status.pm_indicated = !!(tmp & 0x80);
+ status.intermediate = !!(tmp & 0x40);
+ status.for_ampdu = !!(tmp & 0x20);
+ status.acked = !!(tmp & 0x02);
+
+ b43legacy_handle_txstatus(dev, &status);
+}
+
+/* Stop any TX operation on the device (suspend the hardware queues) */
+void b43legacy_tx_suspend(struct b43legacy_wldev *dev)
+{
+ if (b43legacy_using_pio(dev))
+ b43legacy_pio_freeze_txqueues(dev);
+ else
+ b43legacy_dma_tx_suspend(dev);
+}
+
+/* Resume any TX operation on the device (resume the hardware queues) */
+void b43legacy_tx_resume(struct b43legacy_wldev *dev)
+{
+ if (b43legacy_using_pio(dev))
+ b43legacy_pio_thaw_txqueues(dev);
+ else
+ b43legacy_dma_tx_resume(dev);
+}
+
+/* Initialize the QoS parameters */
+void b43legacy_qos_init(struct b43legacy_wldev *dev)
+{
+ /* FIXME: This function must probably be called from the mac80211
+ * config callback. */
+return;
+
+ b43legacy_hf_write(dev, b43legacy_hf_read(dev) | B43legacy_HF_EDCF);
+ /* FIXME kill magic */
+ b43legacy_write16(dev, 0x688,
+ b43legacy_read16(dev, 0x688) | 0x4);
+
+
+ /*TODO: We might need some stack support here to get the values. */
+}
diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h
new file mode 100644
index 00000000000..8a155d0a5d1
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/xmit.h
@@ -0,0 +1,259 @@
+#ifndef B43legacy_XMIT_H_
+#define B43legacy_XMIT_H_
+
+#include "main.h"
+
+
+#define _b43legacy_declare_plcp_hdr(size) \
+ struct b43legacy_plcp_hdr##size { \
+ union { \
+ __le32 data; \
+ __u8 raw[size]; \
+ } __attribute__((__packed__)); \
+ } __attribute__((__packed__))
+
+/* struct b43legacy_plcp_hdr4 */
+_b43legacy_declare_plcp_hdr(4);
+/* struct b43legacy_plcp_hdr6 */
+_b43legacy_declare_plcp_hdr(6);
+
+#undef _b43legacy_declare_plcp_hdr
+
+
+/* TX header for v3 firmware */
+struct b43legacy_txhdr_fw3 {
+ __le32 mac_ctl; /* MAC TX control */
+ __le16 mac_frame_ctl; /* Copy of the FrameControl */
+ __le16 tx_fes_time_norm; /* TX FES Time Normal */
+ __le16 phy_ctl; /* PHY TX control */
+ __u8 iv[16]; /* Encryption IV */
+ __u8 tx_receiver[6]; /* TX Frame Receiver address */
+ __le16 tx_fes_time_fb; /* TX FES Time Fallback */
+ struct b43legacy_plcp_hdr4 rts_plcp_fb; /* RTS fallback PLCP */
+ __le16 rts_dur_fb; /* RTS fallback duration */
+ struct b43legacy_plcp_hdr4 plcp_fb; /* Fallback PLCP */
+ __le16 dur_fb; /* Fallback duration */
+ PAD_BYTES(2);
+ __le16 cookie;
+ __le16 unknown_scb_stuff;
+ struct b43legacy_plcp_hdr6 rts_plcp; /* RTS PLCP */
+ __u8 rts_frame[18]; /* The RTS frame (if used) */
+ struct b43legacy_plcp_hdr6 plcp;
+} __attribute__((__packed__));
+
+/* MAC TX control */
+#define B43legacy_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */
+#define B43legacy_TX4_MAC_KEYIDX_SHIFT 20
+#define B43legacy_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */
+#define B43legacy_TX4_MAC_KEYALG_SHIFT 16
+#define B43legacy_TX4_MAC_LIFETIME 0x00001000
+#define B43legacy_TX4_MAC_FRAMEBURST 0x00000800
+#define B43legacy_TX4_MAC_SENDCTS 0x00000400
+#define B43legacy_TX4_MAC_AMPDU 0x00000300
+#define B43legacy_TX4_MAC_AMPDU_SHIFT 8
+#define B43legacy_TX4_MAC_CTSFALLBACKOFDM 0x00000200
+#define B43legacy_TX4_MAC_FALLBACKOFDM 0x00000100
+#define B43legacy_TX4_MAC_5GHZ 0x00000080
+#define B43legacy_TX4_MAC_IGNPMQ 0x00000020
+#define B43legacy_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Seq No */
+#define B43legacy_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */
+#define B43legacy_TX4_MAC_SENDRTS 0x00000004
+#define B43legacy_TX4_MAC_LONGFRAME 0x00000002
+#define B43legacy_TX4_MAC_ACK 0x00000001
+
+/* Extra Frame Types */
+#define B43legacy_TX4_EFT_FBOFDM 0x0001 /* Data frame fb rate type */
+#define B43legacy_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */
+#define B43legacy_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */
+
+/* PHY TX control word */
+#define B43legacy_TX4_PHY_OFDM 0x0001 /* Data frame rate type */
+#define B43legacy_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */
+#define B43legacy_TX4_PHY_ANT 0x03C0 /* Antenna selection */
+#define B43legacy_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */
+#define B43legacy_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */
+#define B43legacy_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */
+
+
+
+void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
+ u8 *txhdr,
+ const unsigned char *fragment_data,
+ unsigned int fragment_len,
+ const struct ieee80211_tx_control *txctl,
+ u16 cookie);
+
+
+/* Transmit Status */
+struct b43legacy_txstatus {
+ u16 cookie; /* The cookie from the txhdr */
+ u16 seq; /* Sequence number */
+ u8 phy_stat; /* PHY TX status */
+ u8 frame_count; /* Frame transmit count */
+ u8 rts_count; /* RTS transmit count */
+ u8 supp_reason; /* Suppression reason */
+ /* flags */
+ u8 pm_indicated;/* PM mode indicated to AP */
+ u8 intermediate;/* Intermediate status notification */
+ u8 for_ampdu; /* Status is for an AMPDU (afterburner) */
+ u8 acked; /* Wireless ACK received */
+};
+
+/* txstatus supp_reason values */
+enum {
+ B43legacy_TXST_SUPP_NONE, /* Not suppressed */
+ B43legacy_TXST_SUPP_PMQ, /* Suppressed due to PMQ entry */
+ B43legacy_TXST_SUPP_FLUSH, /* Suppressed due to flush request */
+ B43legacy_TXST_SUPP_PREV, /* Previous fragment failed */
+ B43legacy_TXST_SUPP_CHAN, /* Channel mismatch */
+ B43legacy_TXST_SUPP_LIFE, /* Lifetime expired */
+ B43legacy_TXST_SUPP_UNDER, /* Buffer underflow */
+ B43legacy_TXST_SUPP_ABNACK, /* Afterburner NACK */
+};
+
+/* Transmit Status as received through DMA/PIO on old chips */
+struct b43legacy_hwtxstatus {
+ PAD_BYTES(4);
+ __le16 cookie;
+ u8 flags;
+ u8 count;
+ PAD_BYTES(2);
+ __le16 seq;
+ u8 phy_stat;
+ PAD_BYTES(1);
+} __attribute__((__packed__));
+
+
+/* Receive header for v3 firmware. */
+struct b43legacy_rxhdr_fw3 {
+ __le16 frame_len; /* Frame length */
+ PAD_BYTES(2);
+ __le16 phy_status0; /* PHY RX Status 0 */
+ __u8 jssi; /* PHY RX Status 1: JSSI */
+ __u8 sig_qual; /* PHY RX Status 1: Signal Quality */
+ PAD_BYTES(2); /* PHY RX Status 2 */
+ __le16 phy_status3; /* PHY RX Status 3 */
+ __le16 mac_status; /* MAC RX status */
+ __le16 mac_time;
+ __le16 channel;
+} __attribute__((__packed__));
+
+
+/* PHY RX Status 0 */
+#define B43legacy_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */
+#define B43legacy_RX_PHYST0_PLCPHCF 0x0200
+#define B43legacy_RX_PHYST0_PLCPFV 0x0100
+#define B43legacy_RX_PHYST0_SHORTPRMBL 0x0080 /* Recvd with Short Preamble */
+#define B43legacy_RX_PHYST0_LCRS 0x0040
+#define B43legacy_RX_PHYST0_ANT 0x0020 /* Antenna */
+#define B43legacy_RX_PHYST0_UNSRATE 0x0010
+#define B43legacy_RX_PHYST0_CLIP 0x000C
+#define B43legacy_RX_PHYST0_CLIP_SHIFT 2
+#define B43legacy_RX_PHYST0_FTYPE 0x0003 /* Frame type */
+#define B43legacy_RX_PHYST0_CCK 0x0000 /* Frame type: CCK */
+#define B43legacy_RX_PHYST0_OFDM 0x0001 /* Frame type: OFDM */
+#define B43legacy_RX_PHYST0_PRE_N 0x0002 /* Pre-standard N-PHY frame */
+#define B43legacy_RX_PHYST0_STD_N 0x0003 /* Standard N-PHY frame */
+
+/* PHY RX Status 2 */
+#define B43legacy_RX_PHYST2_LNAG 0xC000 /* LNA Gain */
+#define B43legacy_RX_PHYST2_LNAG_SHIFT 14
+#define B43legacy_RX_PHYST2_PNAG 0x3C00 /* PNA Gain */
+#define B43legacy_RX_PHYST2_PNAG_SHIFT 10
+#define B43legacy_RX_PHYST2_FOFF 0x03FF /* F offset */
+
+/* PHY RX Status 3 */
+#define B43legacy_RX_PHYST3_DIGG 0x1800 /* DIG Gain */
+#define B43legacy_RX_PHYST3_DIGG_SHIFT 11
+#define B43legacy_RX_PHYST3_TRSTATE 0x0400 /* TR state */
+
+/* MAC RX Status */
+#define B43legacy_RX_MAC_BEACONSENT 0x00008000 /* Beacon send flag */
+#define B43legacy_RX_MAC_KEYIDX 0x000007E0 /* Key index */
+#define B43legacy_RX_MAC_KEYIDX_SHIFT 5
+#define B43legacy_RX_MAC_DECERR 0x00000010 /* Decrypt error */
+#define B43legacy_RX_MAC_DEC 0x00000008 /* Decryption attempted */
+#define B43legacy_RX_MAC_PADDING 0x00000004 /* Pad bytes present */
+#define B43legacy_RX_MAC_RESP 0x00000002 /* Response frame xmitted */
+#define B43legacy_RX_MAC_FCSERR 0x00000001 /* FCS error */
+
+/* RX channel */
+#define B43legacy_RX_CHAN_GAIN 0xFC00 /* Gain */
+#define B43legacy_RX_CHAN_GAIN_SHIFT 10
+#define B43legacy_RX_CHAN_ID 0x03FC /* Channel ID */
+#define B43legacy_RX_CHAN_ID_SHIFT 2
+#define B43legacy_RX_CHAN_PHYTYPE 0x0003 /* PHY type */
+
+
+
+u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate);
+u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate);
+
+void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp,
+ const u16 octets, const u8 bitrate);
+
+void b43legacy_rx(struct b43legacy_wldev *dev,
+ struct sk_buff *skb,
+ const void *_rxhdr);
+
+void b43legacy_handle_txstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_txstatus *status);
+
+void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev,
+ const struct b43legacy_hwtxstatus *hw);
+
+void b43legacy_tx_suspend(struct b43legacy_wldev *dev);
+void b43legacy_tx_resume(struct b43legacy_wldev *dev);
+
+
+#define B43legacy_NR_QOSPARMS 22
+enum {
+ B43legacy_QOSPARM_TXOP = 0,
+ B43legacy_QOSPARM_CWMIN,
+ B43legacy_QOSPARM_CWMAX,
+ B43legacy_QOSPARM_CWCUR,
+ B43legacy_QOSPARM_AIFS,
+ B43legacy_QOSPARM_BSLOTS,
+ B43legacy_QOSPARM_REGGAP,
+ B43legacy_QOSPARM_STATUS,
+};
+
+void b43legacy_qos_init(struct b43legacy_wldev *dev);
+
+
+/* Helper functions for converting the key-table index from "firmware-format"
+ * to "raw-format" and back. The firmware API changed for this at some revision.
+ * We need to account for that here. */
+static inline
+int b43legacy_new_kidx_api(struct b43legacy_wldev *dev)
+{
+ /* FIXME: Not sure the change was at rev 351 */
+ return (dev->fw.rev >= 351);
+}
+static inline
+u8 b43legacy_kidx_to_fw(struct b43legacy_wldev *dev, u8 raw_kidx)
+{
+ u8 firmware_kidx;
+ if (b43legacy_new_kidx_api(dev))
+ firmware_kidx = raw_kidx;
+ else {
+ if (raw_kidx >= 4) /* Is per STA key? */
+ firmware_kidx = raw_kidx - 4;
+ else
+ firmware_kidx = raw_kidx; /* TX default key */
+ }
+ return firmware_kidx;
+}
+static inline
+u8 b43legacy_kidx_to_raw(struct b43legacy_wldev *dev, u8 firmware_kidx)
+{
+ u8 raw_kidx;
+ if (b43legacy_new_kidx_api(dev))
+ raw_kidx = firmware_kidx;
+ else
+ /* RX default keys or per STA keys */
+ raw_kidx = firmware_kidx + 4;
+ return raw_kidx;
+}
+
+#endif /* B43legacy_XMIT_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 10e07e86542..5fdbf24d244 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -994,10 +994,4 @@ int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 valu
__value; \
})
-/** Helpers to print MAC addresses. */
-#define BCM43xx_MACFMT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define BCM43xx_MACARG(x) ((u8*)(x))[0], ((u8*)(x))[1], \
- ((u8*)(x))[2], ((u8*)(x))[3], \
- ((u8*)(x))[4], ((u8*)(x))[5]
-
#endif /* BCM43xx_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index 8f198befba3..cb51dc51cce 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -29,7 +29,7 @@
#include "bcm43xx_radio.h"
#include "bcm43xx.h"
-#include <asm/bitops.h>
+#include <linux/bitops.h>
static void bcm43xx_led_changestate(struct bcm43xx_led *led)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index dfbd01eaaf3..45683437a98 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -2380,7 +2380,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
goto err_gpio_cleanup;
bcm43xx_radio_turn_on(bcm);
bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
- dprintk(KERN_INFO PFX "Radio %s by hardware\n",
+ printk(KERN_INFO PFX "Radio %s by hardware\n",
(bcm->radio_hw_enable == 0) ? "disabled" : "enabled");
bcm43xx_write16(bcm, 0x03E6, 0x0000);
@@ -3129,7 +3129,7 @@ static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm)
radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) {
bcm->radio_hw_enable = radio_hw_enable;
- dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n",
+ printk(KERN_INFO PFX "Radio hardware status changed to %s\n",
(radio_hw_enable == 0) ? "disabled" : "enabled");
bcm43xx_leds_update(bcm, 0);
}
@@ -4092,7 +4092,6 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev,
goto out;
}
/* initialize the net_device struct */
- SET_MODULE_OWNER(net_dev);
SET_NETDEV_DEV(net_dev, &pdev->dev);
net_dev->open = bcm43xx_net_open;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index 6a109f4a1b7..c605099c9ba 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -2146,7 +2146,7 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
} else
bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
radio->enabled = 0;
- dprintk(KERN_INFO PFX "Radio turned off\n");
+ dprintk(KERN_INFO PFX "Radio initialized\n");
bcm43xx_leds_update(bcm, 0);
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
index 9ecf2bf0d25..47c135a7f4d 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h
@@ -87,7 +87,7 @@ void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
/* RX header as received from the hardware. */
struct bcm43xx_rxhdr {
- /* Frame Length. Must be generated explicitely in PIO mode. */
+ /* Frame Length. Must be generated explicitly in PIO mode. */
__le16 frame_length;
PAD_BYTES(2);
/* Flags field 1 */
diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h
index ef37a75d550..547ba84dc79 100644
--- a/drivers/net/wireless/hostap/hostap.h
+++ b/drivers/net/wireless/hostap/hostap.h
@@ -30,12 +30,11 @@ void hostap_dump_rx_header(const char *name,
const struct hfa384x_rx_frame *rx);
void hostap_dump_tx_header(const char *name,
const struct hfa384x_tx_frame *tx);
-int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr);
-int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr);
+extern const struct header_ops hostap_80211_ops;
int hostap_80211_get_hdrlen(u16 fc);
struct net_device_stats *hostap_get_stats(struct net_device *dev);
void hostap_setup_dev(struct net_device *dev, local_info_t *local,
- int main_dev);
+ int type);
void hostap_set_multicast_list_queue(struct work_struct *work);
int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked);
int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked);
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
index cbedc9ee740..ef084df3d48 100644
--- a/drivers/net/wireless/hostap/hostap_80211_rx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -19,6 +19,7 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
{
struct ieee80211_hdr_4addr *hdr;
u16 fc;
+ DECLARE_MAC_BUF(mac);
hdr = (struct ieee80211_hdr_4addr *) skb->data;
@@ -44,10 +45,11 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
le16_to_cpu(hdr->seq_ctl));
- printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR,
- MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3));
+ printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1));
+ printk(" A2=%s", print_mac(mac, hdr->addr2));
+ printk(" A3=%s", print_mac(mac, hdr->addr3));
if (skb->len >= 30)
- printk(" A4=" MACSTR, MAC2STR(hdr->addr4));
+ printk(" A4=%s", print_mac(mac, hdr->addr4));
printk("\n");
}
@@ -534,6 +536,7 @@ static int
hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
u16 fc, struct net_device **wds)
{
+ DECLARE_MAC_BUF(mac);
/* FIX: is this really supposed to accept WDS frames only in Master
* mode? What about Repeater or Managed with WDS frames? */
if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) !=
@@ -549,10 +552,10 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) {
/* RA (or BSSID) is not ours - drop */
PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with "
- "not own or broadcast %s=" MACSTR "\n",
+ "not own or broadcast %s=%s\n",
local->dev->name,
fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID",
- MAC2STR(hdr->addr1));
+ print_mac(mac, hdr->addr1));
return -1;
}
@@ -565,8 +568,8 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
/* require that WDS link has been registered with TA or the
* frame is from current AP when using 'AP client mode' */
PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame "
- "from unknown TA=" MACSTR "\n",
- local->dev->name, MAC2STR(hdr->addr2));
+ "from unknown TA=%s\n",
+ local->dev->name, print_mac(mac, hdr->addr2));
if (local->ap && local->ap->autom_ap_wds)
hostap_wds_link_oper(local, hdr->addr2, WDS_ADD);
return -1;
@@ -632,6 +635,7 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
{
struct ieee80211_hdr_4addr *hdr;
int res, hdrlen;
+ DECLARE_MAC_BUF(mac);
if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
return 0;
@@ -643,8 +647,8 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
strcmp(crypt->ops->name, "TKIP") == 0) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "received packet from " MACSTR "\n",
- local->dev->name, MAC2STR(hdr->addr2));
+ "received packet from %s\n",
+ local->dev->name, print_mac(mac, hdr->addr2));
}
return -1;
}
@@ -653,9 +657,9 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
atomic_dec(&crypt->refcnt);
if (res < 0) {
- printk(KERN_DEBUG "%s: decryption failed (SA=" MACSTR
+ printk(KERN_DEBUG "%s: decryption failed (SA=%s"
") res=%d\n",
- local->dev->name, MAC2STR(hdr->addr2), res);
+ local->dev->name, print_mac(mac, hdr->addr2), res);
local->comm_tallies.rx_discards_wep_undecryptable++;
return -1;
}
@@ -671,6 +675,7 @@ hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
{
struct ieee80211_hdr_4addr *hdr;
int res, hdrlen;
+ DECLARE_MAC_BUF(mac);
if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
return 0;
@@ -683,8 +688,8 @@ hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
atomic_dec(&crypt->refcnt);
if (res < 0) {
printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
- " (SA=" MACSTR " keyidx=%d)\n",
- local->dev->name, MAC2STR(hdr->addr2), keyidx);
+ " (SA=%s keyidx=%d)\n",
+ local->dev->name, print_mac(mac, hdr->addr2), keyidx);
return -1;
}
@@ -716,6 +721,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
struct ieee80211_crypt_data *crypt = NULL;
void *sta = NULL;
int keyidx = 0;
+ DECLARE_MAC_BUF(mac);
iface = netdev_priv(dev);
local = iface->local;
@@ -792,8 +798,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
* frames silently instead of filling system log with
* these reports. */
printk(KERN_DEBUG "%s: WEP decryption failed (not set)"
- " (SA=" MACSTR ")\n",
- local->dev->name, MAC2STR(hdr->addr2));
+ " (SA=%s)\n",
+ local->dev->name, print_mac(mac, hdr->addr2));
#endif
local->comm_tallies.rx_discards_wep_undecryptable++;
goto rx_dropped;
@@ -807,8 +813,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
(keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
{
printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
- "from " MACSTR "\n", dev->name,
- MAC2STR(hdr->addr2));
+ "from %s\n", dev->name,
+ print_mac(mac, hdr->addr2));
/* TODO: could inform hostapd about this so that it
* could send auth failure report */
goto rx_dropped;
@@ -976,8 +982,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
"unencrypted EAPOL frame\n", local->dev->name);
} else {
printk(KERN_DEBUG "%s: encryption configured, but RX "
- "frame not encrypted (SA=" MACSTR ")\n",
- local->dev->name, MAC2STR(hdr->addr2));
+ "frame not encrypted (SA=%s)\n",
+ local->dev->name, print_mac(mac, hdr->addr2));
goto rx_dropped;
}
}
@@ -986,8 +992,9 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
!hostap_is_eapol_frame(local, skb)) {
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: dropped unencrypted RX data "
- "frame from " MACSTR " (drop_unencrypted=1)\n",
- dev->name, MAC2STR(hdr->addr2));
+ "frame from %s"
+ " (drop_unencrypted=1)\n",
+ dev->name, print_mac(mac, hdr->addr2));
}
goto rx_dropped;
}
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index 3df3c60263d..e7afc3ec3e6 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -17,6 +17,7 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
{
struct ieee80211_hdr_4addr *hdr;
u16 fc;
+ DECLARE_MAC_BUF(mac);
hdr = (struct ieee80211_hdr_4addr *) skb->data;
@@ -40,10 +41,11 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
le16_to_cpu(hdr->seq_ctl));
- printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR,
- MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3));
+ printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1));
+ printk(" A2=%s", print_mac(mac, hdr->addr2));
+ printk(" A3=%s", print_mac(mac, hdr->addr3));
if (skb->len >= 30)
- printk(" A4=" MACSTR, MAC2STR(hdr->addr4));
+ printk(" A4=%s", print_mac(mac, hdr->addr4));
printk("\n");
}
@@ -312,6 +314,7 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
struct ieee80211_hdr_4addr *hdr;
u16 fc;
int prefix_len, postfix_len, hdr_len, res;
+ DECLARE_MAC_BUF(mac);
iface = netdev_priv(skb->dev);
local = iface->local;
@@ -326,8 +329,8 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
hdr = (struct ieee80211_hdr_4addr *) skb->data;
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "TX packet to " MACSTR "\n",
- local->dev->name, MAC2STR(hdr->addr1));
+ "TX packet to %s\n",
+ local->dev->name, print_mac(mac, hdr->addr1));
}
kfree_skb(skb);
return NULL;
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 90900525379..6bbdb76b32d 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -94,6 +94,7 @@ static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta)
static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta)
{
struct sta_info *s;
+ DECLARE_MAC_BUF(mac);
s = ap->sta_hash[STA_HASH(sta->addr)];
if (s == NULL) return;
@@ -108,18 +109,20 @@ static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta)
if (s->hnext != NULL)
s->hnext = s->hnext->hnext;
else
- printk("AP: could not remove STA " MACSTR " from hash table\n",
- MAC2STR(sta->addr));
+ printk("AP: could not remove STA %s"
+ " from hash table\n",
+ print_mac(mac, sta->addr));
}
static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
{
+ DECLARE_MAC_BUF(mac);
if (sta->ap && sta->local)
hostap_event_expired_sta(sta->local->dev, sta);
if (ap->proc != NULL) {
char name[20];
- sprintf(name, MACSTR, MAC2STR(sta->addr));
+ sprintf(name, "%s", print_mac(mac, sta->addr));
remove_proc_entry(name, ap->proc);
}
@@ -182,6 +185,7 @@ static void ap_handle_timer(unsigned long data)
struct ap_data *ap;
unsigned long next_time = 0;
int was_assoc;
+ DECLARE_MAC_BUF(mac);
if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) {
PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n");
@@ -238,8 +242,8 @@ static void ap_handle_timer(unsigned long data)
if (sta->ap) {
if (ap->autom_ap_wds) {
PDEBUG(DEBUG_AP, "%s: removing automatic WDS "
- "connection to AP " MACSTR "\n",
- local->dev->name, MAC2STR(sta->addr));
+ "connection to AP %s\n",
+ local->dev->name, print_mac(mac, sta->addr));
hostap_wds_link_oper(local, sta->addr, WDS_DEL);
}
} else if (sta->timeout_next == STA_NULLFUNC) {
@@ -255,11 +259,11 @@ static void ap_handle_timer(unsigned long data)
} else {
int deauth = sta->timeout_next == STA_DEAUTH;
u16 resp;
- PDEBUG(DEBUG_AP, "%s: sending %s info to STA " MACSTR
+ PDEBUG(DEBUG_AP, "%s: sending %s info to STA %s"
"(last=%lu, jiffies=%lu)\n",
local->dev->name,
deauth ? "deauthentication" : "disassociation",
- MAC2STR(sta->addr), sta->last_rx, jiffies);
+ print_mac(mac, sta->addr), sta->last_rx, jiffies);
resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID :
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
@@ -271,9 +275,10 @@ static void ap_handle_timer(unsigned long data)
if (sta->timeout_next == STA_DEAUTH) {
if (sta->flags & WLAN_STA_PERM) {
- PDEBUG(DEBUG_AP, "%s: STA " MACSTR " would have been "
- "removed, but it has 'perm' flag\n",
- local->dev->name, MAC2STR(sta->addr));
+ PDEBUG(DEBUG_AP, "%s: STA %s"
+ " would have been removed, "
+ "but it has 'perm' flag\n",
+ local->dev->name, print_mac(mac, sta->addr));
} else
ap_free_sta(ap, sta);
return;
@@ -327,6 +332,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off,
struct ap_data *ap = (struct ap_data *) data;
char *policy_txt;
struct mac_entry *entry;
+ DECLARE_MAC_BUF(mac);
if (off != 0) {
*eof = 1;
@@ -357,7 +363,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off,
break;
}
- p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr));
+ p += sprintf(p, "%s\n", print_mac(mac, entry->addr));
}
spin_unlock_bh(&ap->mac_restrictions.lock);
@@ -514,6 +520,7 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off,
struct ap_data *ap = (struct ap_data *) data;
struct sta_info *sta;
int i;
+ DECLARE_MAC_BUF(mac);
if (off > PROC_LIMIT) {
*eof = 1;
@@ -526,7 +533,8 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off,
if (!sta->ap)
continue;
- p += sprintf(p, MACSTR " %d %d %d %d '", MAC2STR(sta->addr),
+ p += sprintf(p, "%s %d %d %d %d '",
+ print_mac(mac, sta->addr),
sta->u.ap.channel, sta->last_rx_signal,
sta->last_rx_silence, sta->last_rx_rate);
for (i = 0; i < sta->u.ap.ssid_len; i++)
@@ -623,6 +631,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
u16 fc, *pos, auth_alg, auth_transaction, status;
struct sta_info *sta = NULL;
char *txt = NULL;
+ DECLARE_MAC_BUF(mac);
if (ap->local->hostapd) {
dev_kfree_skb(skb);
@@ -674,9 +683,9 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
if (sta)
atomic_dec(&sta->users);
if (txt) {
- PDEBUG(DEBUG_AP, "%s: " MACSTR " auth_cb - alg=%d trans#=%d "
- "status=%d - %s\n",
- dev->name, MAC2STR(hdr->addr1), auth_alg,
+ PDEBUG(DEBUG_AP, "%s: %s auth_cb - alg=%d "
+ "trans#=%d status=%d - %s\n",
+ dev->name, print_mac(mac, hdr->addr1), auth_alg,
auth_transaction, status, txt);
}
dev_kfree_skb(skb);
@@ -692,6 +701,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
u16 fc, *pos, status;
struct sta_info *sta = NULL;
char *txt = NULL;
+ DECLARE_MAC_BUF(mac);
if (ap->local->hostapd) {
dev_kfree_skb(skb);
@@ -742,8 +752,8 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
if (sta)
atomic_dec(&sta->users);
if (txt) {
- PDEBUG(DEBUG_AP, "%s: " MACSTR " assoc_cb - %s\n",
- dev->name, MAC2STR(hdr->addr1), txt);
+ PDEBUG(DEBUG_AP, "%s: %s assoc_cb - %s\n",
+ dev->name, print_mac(mac, hdr->addr1), txt);
}
dev_kfree_skb(skb);
}
@@ -755,6 +765,7 @@ static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data)
struct ap_data *ap = data;
struct ieee80211_hdr_4addr *hdr;
struct sta_info *sta;
+ DECLARE_MAC_BUF(mac);
if (skb->len < 24)
goto fail;
@@ -766,9 +777,9 @@ static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data)
sta->flags &= ~WLAN_STA_PENDING_POLL;
spin_unlock(&ap->sta_table_lock);
} else {
- PDEBUG(DEBUG_AP, "%s: STA " MACSTR " did not ACK activity "
- "poll frame\n", ap->local->dev->name,
- MAC2STR(hdr->addr1));
+ PDEBUG(DEBUG_AP, "%s: STA %s"
+ " did not ACK activity poll frame\n",
+ ap->local->dev->name, print_mac(mac, hdr->addr1));
}
fail:
@@ -985,6 +996,7 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off,
char *p = page;
struct sta_info *sta = (struct sta_info *) data;
int i;
+ DECLARE_MAC_BUF(mac);
/* FIX: possible race condition.. the STA data could have just expired,
* but proc entry was still here so that the read could have started;
@@ -995,11 +1007,11 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off,
return 0;
}
- p += sprintf(p, "%s=" MACSTR "\nusers=%d\naid=%d\n"
+ p += sprintf(p, "%s=%s\nusers=%d\naid=%d\n"
"flags=0x%04x%s%s%s%s%s%s%s\n"
"capability=0x%02x\nlisten_interval=%d\nsupported_rates=",
sta->ap ? "AP" : "STA",
- MAC2STR(sta->addr), atomic_read(&sta->users), sta->aid,
+ print_mac(mac, sta->addr), atomic_read(&sta->users), sta->aid,
sta->flags,
sta->flags & WLAN_STA_AUTH ? " AUTH" : "",
sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "",
@@ -1060,6 +1072,7 @@ static void handle_add_proc_queue(struct work_struct *work)
struct sta_info *sta;
char name[20];
struct add_sta_proc_data *entry, *prev;
+ DECLARE_MAC_BUF(mac);
entry = ap->add_sta_proc_entries;
ap->add_sta_proc_entries = NULL;
@@ -1072,7 +1085,7 @@ static void handle_add_proc_queue(struct work_struct *work)
spin_unlock_bh(&ap->sta_table_lock);
if (sta) {
- sprintf(name, MACSTR, MAC2STR(sta->addr));
+ sprintf(name, "%s", print_mac(mac, sta->addr));
sta->proc = create_proc_read_entry(
name, 0, ap->proc,
prism2_sta_proc_read, sta);
@@ -1290,6 +1303,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
struct sta_info *sta = NULL;
struct ieee80211_crypt_data *crypt;
char *txt = "";
+ DECLARE_MAC_BUF(mac);
len = skb->len - IEEE80211_MGMT_HDR_LEN;
@@ -1298,8 +1312,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
if (len < 6) {
PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload "
- "(len=%d) from " MACSTR "\n", dev->name, len,
- MAC2STR(hdr->addr2));
+ "(len=%d) from %s\n", dev->name, len,
+ print_mac(mac, hdr->addr2));
return;
}
@@ -1364,8 +1378,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
if (time_after(jiffies, sta->u.ap.last_beacon +
(10 * sta->listen_interval * HZ) / 1024)) {
PDEBUG(DEBUG_AP, "%s: no beacons received for a while,"
- " assuming AP " MACSTR " is now STA\n",
- dev->name, MAC2STR(sta->addr));
+ " assuming AP %s is now STA\n",
+ dev->name, print_mac(mac, sta->addr));
sta->ap = 0;
sta->flags = 0;
sta->u.sta.challenge = NULL;
@@ -1480,9 +1494,9 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
}
if (resp) {
- PDEBUG(DEBUG_AP, "%s: " MACSTR " auth (alg=%d trans#=%d "
- "stat=%d len=%d fc=%04x) ==> %d (%s)\n",
- dev->name, MAC2STR(hdr->addr2), auth_alg,
+ PDEBUG(DEBUG_AP, "%s: %s auth (alg=%d "
+ "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n",
+ dev->name, print_mac(mac, hdr->addr2), auth_alg,
auth_transaction, status_code, len, fc, resp, txt);
}
}
@@ -1502,13 +1516,14 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
int send_deauth = 0;
char *txt = "";
u8 prev_ap[ETH_ALEN];
+ DECLARE_MAC_BUF(mac);
left = len = skb->len - IEEE80211_MGMT_HDR_LEN;
if (len < (reassoc ? 10 : 4)) {
PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload "
- "(len=%d, reassoc=%d) from " MACSTR "\n",
- dev->name, len, reassoc, MAC2STR(hdr->addr2));
+ "(len=%d, reassoc=%d) from %s\n",
+ dev->name, len, reassoc, print_mac(mac, hdr->addr2));
return;
}
@@ -1585,9 +1600,9 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
}
if (left > 0) {
- PDEBUG(DEBUG_AP, "%s: assoc from " MACSTR " with extra"
- " data (%d bytes) [",
- dev->name, MAC2STR(hdr->addr2), left);
+ PDEBUG(DEBUG_AP, "%s: assoc from %s"
+ " with extra data (%d bytes) [",
+ dev->name, print_mac(mac, hdr->addr2), left);
while (left > 0) {
PDEBUG2(DEBUG_AP, "<%02x>", *u);
u++; left--;
@@ -1687,10 +1702,10 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
}
#if 0
- PDEBUG(DEBUG_AP, "%s: " MACSTR " %sassoc (len=%d prev_ap=" MACSTR
- ") => %d(%d) (%s)\n",
- dev->name, MAC2STR(hdr->addr2), reassoc ? "re" : "", len,
- MAC2STR(prev_ap), resp, send_deauth, txt);
+ PDEBUG(DEBUG_AP, "%s: %s %sassoc (len=%d "
+ "prev_ap=%s) => %d(%d) (%s)\n",
+ dev->name, print_mac(mac, hdr->addr2), reassoc ? "re" : "", len,
+ print_mac(mac, prev_ap), resp, send_deauth, txt);
#endif
}
@@ -1705,6 +1720,7 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb,
int len;
u16 reason_code, *pos;
struct sta_info *sta = NULL;
+ DECLARE_MAC_BUF(mac);
len = skb->len - IEEE80211_MGMT_HDR_LEN;
@@ -1716,8 +1732,8 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb,
pos = (u16 *) body;
reason_code = __le16_to_cpu(*pos);
- PDEBUG(DEBUG_AP, "%s: deauthentication: " MACSTR " len=%d, "
- "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len,
+ PDEBUG(DEBUG_AP, "%s: deauthentication: %s len=%d, "
+ "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len,
reason_code);
spin_lock_bh(&local->ap->sta_table_lock);
@@ -1729,9 +1745,9 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb,
}
spin_unlock_bh(&local->ap->sta_table_lock);
if (sta == NULL) {
- printk("%s: deauthentication from " MACSTR ", "
+ printk("%s: deauthentication from %s, "
"reason_code=%d, but STA not authenticated\n", dev->name,
- MAC2STR(hdr->addr2), reason_code);
+ print_mac(mac, hdr->addr2), reason_code);
}
}
@@ -1746,6 +1762,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
int len;
u16 reason_code, *pos;
struct sta_info *sta = NULL;
+ DECLARE_MAC_BUF(mac);
len = skb->len - IEEE80211_MGMT_HDR_LEN;
@@ -1757,8 +1774,8 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
pos = (u16 *) body;
reason_code = __le16_to_cpu(*pos);
- PDEBUG(DEBUG_AP, "%s: disassociation: " MACSTR " len=%d, "
- "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len,
+ PDEBUG(DEBUG_AP, "%s: disassociation: %s len=%d, "
+ "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len,
reason_code);
spin_lock_bh(&local->ap->sta_table_lock);
@@ -1770,9 +1787,9 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
}
spin_unlock_bh(&local->ap->sta_table_lock);
if (sta == NULL) {
- printk("%s: disassociation from " MACSTR ", "
+ printk("%s: disassociation from %s, "
"reason_code=%d, but STA not authenticated\n",
- dev->name, MAC2STR(hdr->addr2), reason_code);
+ dev->name, print_mac(mac, hdr->addr2), reason_code);
}
}
@@ -1862,15 +1879,16 @@ static void handle_pspoll(local_info_t *local,
struct sta_info *sta;
u16 aid;
struct sk_buff *skb;
+ DECLARE_MAC_BUF(mac);
- PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MACSTR ", TA=" MACSTR
- " PWRMGT=%d\n",
- MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+ PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%s"
+ ", TA=%s PWRMGT=%d\n",
+ print_mac(mac, hdr->addr1), print_mac(mac, hdr->addr2),
!!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM));
if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
- PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MACSTR
- " not own MAC\n", MAC2STR(hdr->addr1));
+ PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=%s"
+ " not own MAC\n", print_mac(mac, hdr->addr1));
return;
}
@@ -1948,6 +1966,7 @@ static void handle_wds_oper_queue(struct work_struct *work)
wds_oper_queue);
local_info_t *local = ap->local;
struct wds_oper_data *entry, *prev;
+ DECLARE_MAC_BUF(mac);
spin_lock_bh(&local->lock);
entry = local->ap->wds_oper_entries;
@@ -1956,10 +1975,10 @@ static void handle_wds_oper_queue(struct work_struct *work)
while (entry) {
PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection "
- "to AP " MACSTR "\n",
+ "to AP %s\n",
local->dev->name,
entry->type == WDS_ADD ? "adding" : "removing",
- MAC2STR(entry->addr));
+ print_mac(mac, entry->addr));
if (entry->type == WDS_ADD)
prism2_wds_add(local, entry->addr, 0);
else if (entry->type == WDS_DEL)
@@ -2135,6 +2154,7 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
u16 fc, type, stype;
struct ieee80211_hdr_4addr *hdr;
+ DECLARE_MAC_BUF(mac);
/* FIX: should give skb->len to handler functions and check that the
* buffer is long enough */
@@ -2163,8 +2183,8 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)="
- MACSTR " not own MAC\n",
- MAC2STR(hdr->addr1));
+ "%s not own MAC\n",
+ print_mac(mac, hdr->addr1));
goto done;
}
@@ -2200,14 +2220,14 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
}
if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
- PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MACSTR
- " not own MAC\n", MAC2STR(hdr->addr1));
+ PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%s"
+ " not own MAC\n", print_mac(mac, hdr->addr1));
goto done;
}
if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) {
- PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MACSTR
- " not own MAC\n", MAC2STR(hdr->addr3));
+ PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%s"
+ " not own MAC\n", print_mac(mac, hdr->addr3));
goto done;
}
@@ -2288,6 +2308,7 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta)
struct sk_buff *skb;
struct ieee80211_hdr_4addr *hdr;
struct hostap_80211_rx_status rx_stats;
+ DECLARE_MAC_BUF(mac);
if (skb_queue_empty(&sta->tx_buf))
return;
@@ -2308,8 +2329,8 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta)
memcpy(hdr->addr2, sta->addr, ETH_ALEN);
hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14));
- PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for "
- "STA " MACSTR "\n", local->dev->name, MAC2STR(sta->addr));
+ PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for STA "
+ "%s\n", local->dev->name, print_mac(mac, sta->addr));
skb->dev = local->dev;
@@ -2636,6 +2657,7 @@ static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev)
int ret = sta->tx_rate;
struct hostap_interface *iface;
local_info_t *local;
+ DECLARE_MAC_BUF(mac);
iface = netdev_priv(dev);
local = iface->local;
@@ -2663,9 +2685,9 @@ static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev)
case 3: sta->tx_rate = 110; break;
default: sta->tx_rate = 0; break;
}
- PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate raised to"
- " %d\n", dev->name, MAC2STR(sta->addr),
- sta->tx_rate);
+ PDEBUG(DEBUG_AP, "%s: STA %s"
+ " TX rate raised to %d\n",
+ dev->name, print_mac(mac, sta->addr), sta->tx_rate);
}
sta->tx_since_last_failure = 0;
}
@@ -2683,6 +2705,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
int set_tim, ret;
struct ieee80211_hdr_4addr *hdr;
struct hostap_skb_tx_data *meta;
+ DECLARE_MAC_BUF(mac);
meta = (struct hostap_skb_tx_data *) skb->cb;
ret = AP_TX_CONTINUE;
@@ -2718,7 +2741,8 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
* print out any errors here. */
if (net_ratelimit()) {
printk(KERN_DEBUG "AP: drop packet to non-associated "
- "STA " MACSTR "\n", MAC2STR(hdr->addr1));
+ "STA %s\n",
+ print_mac(mac, hdr->addr1));
}
#endif
local->ap->tx_drop_nonassoc++;
@@ -2756,8 +2780,9 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
}
if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) {
- PDEBUG(DEBUG_PS, "%s: No more space in STA (" MACSTR ")'s PS "
- "mode buffer\n", local->dev->name, MAC2STR(sta->addr));
+ PDEBUG(DEBUG_PS, "%s: No more space in STA (%s"
+ ")'s PS mode buffer\n",
+ local->dev->name, print_mac(mac, sta->addr));
/* Make sure that TIM is set for the station (it might not be
* after AP wlan hw reset). */
/* FIX: should fix hw reset to restore bits based on STA
@@ -2821,6 +2846,7 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
struct sta_info *sta;
struct ieee80211_hdr_4addr *hdr;
struct hostap_skb_tx_data *meta;
+ DECLARE_MAC_BUF(mac);
hdr = (struct ieee80211_hdr_4addr *) skb->data;
meta = (struct hostap_skb_tx_data *) skb->cb;
@@ -2829,9 +2855,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
sta = ap_get_sta(local->ap, hdr->addr1);
if (!sta) {
spin_unlock(&local->ap->sta_table_lock);
- PDEBUG(DEBUG_AP, "%s: Could not find STA " MACSTR " for this "
- "TX error (@%lu)\n",
- local->dev->name, MAC2STR(hdr->addr1), jiffies);
+ PDEBUG(DEBUG_AP, "%s: Could not find STA %s"
+ " for this TX error (@%lu)\n",
+ local->dev->name, print_mac(mac, hdr->addr1), jiffies);
return;
}
@@ -2858,8 +2884,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
case 3: sta->tx_rate = 110; break;
default: sta->tx_rate = 0; break;
}
- PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate lowered "
- "to %d\n", local->dev->name, MAC2STR(sta->addr),
+ PDEBUG(DEBUG_AP, "%s: STA %s"
+ " TX rate lowered to %d\n",
+ local->dev->name, print_mac(mac, sta->addr),
sta->tx_rate);
}
sta->tx_consecutive_exc = 0;
@@ -2871,16 +2898,17 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta,
int pwrmgt, int type, int stype)
{
+ DECLARE_MAC_BUF(mac);
if (pwrmgt && !(sta->flags & WLAN_STA_PS)) {
sta->flags |= WLAN_STA_PS;
- PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to use PS "
+ PDEBUG(DEBUG_PS2, "STA %s changed to use PS "
"mode (type=0x%02X, stype=0x%02X)\n",
- MAC2STR(sta->addr), type >> 2, stype >> 4);
+ print_mac(mac, sta->addr), type >> 2, stype >> 4);
} else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) {
sta->flags &= ~WLAN_STA_PS;
- PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to not use "
+ PDEBUG(DEBUG_PS2, "STA %s changed to not use "
"PS mode (type=0x%02X, stype=0x%02X)\n",
- MAC2STR(sta->addr), type >> 2, stype >> 4);
+ print_mac(mac, sta->addr), type >> 2, stype >> 4);
if (type != IEEE80211_FTYPE_CTL ||
stype != IEEE80211_STYPE_PSPOLL)
schedule_packet_send(local, sta);
@@ -2924,6 +2952,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
struct sta_info *sta;
u16 fc, type, stype;
struct ieee80211_hdr_4addr *hdr;
+ DECLARE_MAC_BUF(mac);
if (local->ap == NULL)
return AP_RX_CONTINUE;
@@ -2954,9 +2983,10 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
} else {
printk(KERN_DEBUG "%s: dropped received packet"
- " from non-associated STA " MACSTR
+ " from non-associated STA "
+ "%s"
" (type=0x%02x, subtype=0x%02x)\n",
- dev->name, MAC2STR(hdr->addr2),
+ dev->name, print_mac(mac, hdr->addr2),
type >> 2, stype >> 4);
hostap_rx(dev, skb, rx_stats);
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
@@ -2991,8 +3021,8 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
* being associated. */
printk(KERN_DEBUG "%s: rejected received nullfunc "
"frame without ToDS from not associated STA "
- MACSTR "\n",
- dev->name, MAC2STR(hdr->addr2));
+ "%s\n",
+ dev->name, print_mac(mac, hdr->addr2));
hostap_rx(dev, skb, rx_stats);
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
}
@@ -3009,9 +3039,9 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
* If BSSID is own, report the dropping of this frame. */
if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
printk(KERN_DEBUG "%s: dropped received packet from "
- MACSTR " with no ToDS flag (type=0x%02x, "
- "subtype=0x%02x)\n", dev->name,
- MAC2STR(hdr->addr2), type >> 2, stype >> 4);
+ "%s with no ToDS flag "
+ "(type=0x%02x, subtype=0x%02x)\n", dev->name,
+ print_mac(mac, hdr->addr2), type >> 2, stype >> 4);
hostap_dump_rx_80211(dev->name, skb, rx_stats);
}
ret = AP_RX_DROP;
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
index b31e6a05f23..517f8984514 100644
--- a/drivers/net/wireless/hostap/hostap_common.h
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -4,12 +4,6 @@
#include <linux/types.h>
#include <linux/if_ether.h>
-#define BIT(x) (1 << (x))
-
-#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
-#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
-
-
/* IEEE 802.11 defines */
/* Information Element IDs */
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 30e723f6597..877d3bdd37a 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -272,7 +272,7 @@ static int sandisk_enable_wireless(struct net_device *dev)
{
int res, ret = 0;
conf_reg_t reg;
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
tuple_t tuple;
cisparse_t *parse = NULL;
@@ -822,6 +822,7 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000),
PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301),
PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b),
PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612),
@@ -889,6 +890,10 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID123(
"corega", "WL PCCL-11", "ISL37300P",
0xa21501a, 0x59868926, 0xc9049a39),
+ PCMCIA_DEVICE_PROD_ID1234(
+ "The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P",
+ "RevA",
+ 0xa5f472c2, 0x9c05598d, 0xc9049a39, 0x57a66194),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 959887b70ca..c592641e914 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -825,7 +825,7 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
local->hw_downloading)
return -ENODEV;
- res = down_interruptible(&local->rid_bap_sem);
+ res = mutex_lock_interruptible(&local->rid_bap_mtx);
if (res)
return res;
@@ -834,7 +834,7 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed "
"(res=%d, rid=%04x, len=%d)\n",
dev->name, res, rid, len);
- up(&local->rid_bap_sem);
+ mutex_unlock(&local->rid_bap_mtx);
return res;
}
@@ -861,7 +861,7 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
res = hfa384x_from_bap(dev, BAP0, buf, len);
spin_unlock_bh(&local->baplock);
- up(&local->rid_bap_sem);
+ mutex_unlock(&local->rid_bap_mtx);
if (res) {
if (res != -ENODATA)
@@ -902,7 +902,7 @@ static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len)
/* RID len in words and +1 for rec.rid */
rec.len = cpu_to_le16(len / 2 + len % 2 + 1);
- res = down_interruptible(&local->rid_bap_sem);
+ res = mutex_lock_interruptible(&local->rid_bap_mtx);
if (res)
return res;
@@ -917,12 +917,12 @@ static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len)
if (res) {
printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - "
"failed - res=%d\n", dev->name, rid, len, res);
- up(&local->rid_bap_sem);
+ mutex_unlock(&local->rid_bap_mtx);
return res;
}
res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL);
- up(&local->rid_bap_sem);
+ mutex_unlock(&local->rid_bap_mtx);
if (res) {
printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE "
@@ -2335,6 +2335,10 @@ static void prism2_txexc(local_info_t *local)
int show_dump, res;
char *payload = NULL;
struct hfa384x_tx_frame txdesc;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+ DECLARE_MAC_BUF(mac4);
show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR;
local->stats.tx_errors++;
@@ -2400,10 +2404,9 @@ static void prism2_txexc(local_info_t *local)
WLAN_FC_GET_STYPE(fc) >> 4,
fc & IEEE80211_FCTL_TODS ? " ToDS" : "",
fc & IEEE80211_FCTL_FROMDS ? " FromDS" : "");
- PDEBUG(DEBUG_EXTRA, " A1=" MACSTR " A2=" MACSTR " A3="
- MACSTR " A4=" MACSTR "\n",
- MAC2STR(txdesc.addr1), MAC2STR(txdesc.addr2),
- MAC2STR(txdesc.addr3), MAC2STR(txdesc.addr4));
+ PDEBUG(DEBUG_EXTRA, " A1=%s A2=%s A3=%s A4=%s\n",
+ print_mac(mac, txdesc.addr1), print_mac(mac2, txdesc.addr2),
+ print_mac(mac3, txdesc.addr3), print_mac(mac4, txdesc.addr4));
}
@@ -3171,7 +3174,7 @@ prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx,
spin_lock_init(&local->cmdlock);
spin_lock_init(&local->baplock);
spin_lock_init(&local->lock);
- init_MUTEX(&local->rid_bap_sem);
+ mutex_init(&local->rid_bap_mtx);
if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES)
card_idx = 0;
@@ -3254,12 +3257,11 @@ while (0)
INIT_LIST_HEAD(&local->bss_list);
- hostap_setup_dev(dev, local, 1);
- local->saved_eth_header_parse = dev->hard_header_parse;
+ hostap_setup_dev(dev, local, HOSTAP_INTERFACE_MASTER);
dev->hard_start_xmit = hostap_master_start_xmit;
dev->type = ARPHRD_IEEE80211;
- dev->hard_header_parse = hostap_80211_header_parse;
+ dev->header_ops = &hostap_80211_ops;
rtnl_lock();
ret = dev_alloc_name(dev, "wifi%d");
@@ -3424,7 +3426,7 @@ static void prism2_suspend(struct net_device *dev)
struct local_info *local;
union iwreq_data wrqu;
- iface = dev->priv;
+ iface = netdev_priv(dev);
local = iface->local;
/* Send disconnect event, e.g., to trigger reassociation after resume
diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c
index b6a02a02da7..636f4b2382e 100644
--- a/drivers/net/wireless/hostap/hostap_info.c
+++ b/drivers/net/wireless/hostap/hostap_info.c
@@ -166,6 +166,7 @@ static void prism2_host_roaming(local_info_t *local)
struct hfa384x_hostscan_result *selected, *entry;
int i;
unsigned long flags;
+ DECLARE_MAC_BUF(mac);
if (local->last_join_time &&
time_before(jiffies, local->last_join_time + 10 * HZ)) {
@@ -198,8 +199,9 @@ static void prism2_host_roaming(local_info_t *local)
local->preferred_ap[2] || local->preferred_ap[3] ||
local->preferred_ap[4] || local->preferred_ap[5]) {
/* Try to find preferred AP */
- PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " MACSTR "\n",
- dev->name, MAC2STR(local->preferred_ap));
+ PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID "
+ "%s\n",
+ dev->name, print_mac(mac, local->preferred_ap));
for (i = 0; i < local->last_scan_results_count; i++) {
entry = &local->last_scan_results[i];
if (memcmp(local->preferred_ap, entry->bssid, 6) == 0)
@@ -216,8 +218,9 @@ static void prism2_host_roaming(local_info_t *local)
req.channel = selected->chid;
spin_unlock_irqrestore(&local->lock, flags);
- PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=" MACSTR " channel=%d\n",
- dev->name, MAC2STR(req.bssid), le16_to_cpu(req.channel));
+ PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%s"
+ " channel=%d\n",
+ dev->name, print_mac(mac, req.bssid), le16_to_cpu(req.channel));
if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
sizeof(req))) {
printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name);
@@ -409,6 +412,7 @@ static void handle_info_queue_linkstatus(local_info_t *local)
int val = local->prev_link_status;
int connected;
union iwreq_data wrqu;
+ DECLARE_MAC_BUF(mac);
connected =
val == HFA384X_LINKSTATUS_CONNECTED ||
@@ -420,9 +424,10 @@ static void handle_info_queue_linkstatus(local_info_t *local)
printk(KERN_DEBUG "%s: could not read CURRENTBSSID after "
"LinkStatus event\n", local->dev->name);
} else {
- PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" MACSTR "\n",
+ PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID="
+ "%s\n",
local->dev->name,
- MAC2STR((unsigned char *) local->bssid));
+ print_mac(mac, (unsigned char *) local->bssid));
if (local->wds_type & HOSTAP_WDS_AP_CLIENT)
hostap_add_sta(local->ap, local->bssid);
}
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index 8c71077d653..d8f5efcfcab 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -664,6 +664,7 @@ static int hostap_join_ap(struct net_device *dev)
unsigned long flags;
int i;
struct hfa384x_hostscan_result *entry;
+ DECLARE_MAC_BUF(mac);
iface = netdev_priv(dev);
local = iface->local;
@@ -685,14 +686,14 @@ static int hostap_join_ap(struct net_device *dev)
if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
sizeof(req))) {
- printk(KERN_DEBUG "%s: JoinRequest " MACSTR
+ printk(KERN_DEBUG "%s: JoinRequest %s"
" failed\n",
- dev->name, MAC2STR(local->preferred_ap));
+ dev->name, print_mac(mac, local->preferred_ap));
return -1;
}
- printk(KERN_DEBUG "%s: Trying to join BSSID " MACSTR "\n",
- dev->name, MAC2STR(local->preferred_ap));
+ printk(KERN_DEBUG "%s: Trying to join BSSID %s\n",
+ dev->name, print_mac(mac, local->preferred_ap));
return 0;
}
@@ -896,11 +897,8 @@ static void hostap_monitor_set_type(local_info_t *local)
if (local->monitor_type == PRISM2_MONITOR_PRISM ||
local->monitor_type == PRISM2_MONITOR_CAPHDR) {
dev->type = ARPHRD_IEEE80211_PRISM;
- dev->hard_header_parse =
- hostap_80211_prism_header_parse;
} else {
dev->type = ARPHRD_IEEE80211;
- dev->hard_header_parse = hostap_80211_header_parse;
}
}
@@ -1140,7 +1138,7 @@ static int hostap_monitor_mode_disable(local_info_t *local)
printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name);
dev->type = ARPHRD_ETHER;
- dev->hard_header_parse = local->saved_eth_header_parse;
+
if (local->func->cmd(dev, HFA384X_CMDCODE_TEST |
(HFA384X_TEST_STOP << 8),
0, NULL, NULL))
@@ -2922,7 +2920,7 @@ static int prism2_ioctl_priv_monitor(struct net_device *dev, int *i)
printk(KERN_DEBUG "%s: process %d (%s) used deprecated iwpriv monitor "
"- update software to use iwconfig mode monitor\n",
- dev->name, current->pid, current->comm);
+ dev->name, task_pid_nr(current), current->comm);
/* Backward compatibility code - this can be removed at some point */
@@ -3088,7 +3086,7 @@ static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p)
static int prism2_set_genericelement(struct net_device *dev, u8 *elem,
size_t len)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
u8 *buf;
@@ -3116,7 +3114,7 @@ static int prism2_ioctl_siwauth(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *data, char *extra)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
switch (data->flags & IW_AUTH_INDEX) {
@@ -3182,7 +3180,7 @@ static int prism2_ioctl_giwauth(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *data, char *extra)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
switch (data->flags & IW_AUTH_INDEX) {
@@ -3221,7 +3219,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq, char *extra)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
int i, ret = 0;
@@ -3395,7 +3393,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq, char *extra)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
struct ieee80211_crypt_data **crypt;
void *sta_ptr;
@@ -3697,8 +3695,10 @@ static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local,
struct prism2_hostapd_param *param,
int param_len)
{
- printk(KERN_DEBUG "%ssta: associated as client with AP " MACSTR "\n",
- local->dev->name, MAC2STR(param->sta_addr));
+ DECLARE_MAC_BUF(mac);
+ printk(KERN_DEBUG "%ssta: associated as client with AP "
+ "%s\n",
+ local->dev->name, print_mac(mac, param->sta_addr));
memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN);
return 0;
}
@@ -3716,7 +3716,7 @@ static int prism2_ioctl_giwgenie(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
int len = local->generic_elem_len - 2;
@@ -3755,7 +3755,7 @@ static int prism2_ioctl_siwmlme(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
{
- struct hostap_interface *iface = dev->priv;
+ struct hostap_interface *iface = netdev_priv(dev);
local_info_t *local = iface->local;
struct iw_mlme *mlme = (struct iw_mlme *) extra;
u16 reason;
@@ -3976,9 +3976,9 @@ static const iw_handler prism2_private_handler[] =
const struct iw_handler_def hostap_iw_handler_def =
{
- .num_standard = sizeof(prism2_handler) / sizeof(iw_handler),
- .num_private = sizeof(prism2_private_handler) / sizeof(iw_handler),
- .num_private_args = sizeof(prism2_priv) / sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(prism2_handler),
+ .num_private = ARRAY_SIZE(prism2_private_handler),
+ .num_private_args = ARRAY_SIZE(prism2_priv),
.standard = (iw_handler *) prism2_handler,
.private = (iw_handler *) prism2_private_handler,
.private_args = (struct iw_priv_args *) prism2_priv,
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 446de51bab7..17c58e9bdad 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -24,6 +24,7 @@
#include <linux/rtnetlink.h>
#include <linux/wireless.h>
#include <linux/etherdevice.h>
+#include <net/net_namespace.h>
#include <net/iw_handler.h>
#include <net/ieee80211.h>
#include <net/ieee80211_crypt.h>
@@ -72,7 +73,7 @@ struct net_device * hostap_add_interface(struct local_info *local,
dev->mem_start = mdev->mem_start;
dev->mem_end = mdev->mem_end;
- hostap_setup_dev(dev, local, 0);
+ hostap_setup_dev(dev, local, type);
dev->destructor = free_netdev;
sprintf(dev->name, "%s%s", prefix, name);
@@ -529,6 +530,10 @@ int hostap_set_auth_algs(local_info_t *local)
void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
{
u16 status, fc;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+ DECLARE_MAC_BUF(mac4);
status = __le16_to_cpu(rx->status);
@@ -547,13 +552,12 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
- printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4="
- MACSTR "\n",
- MAC2STR(rx->addr1), MAC2STR(rx->addr2), MAC2STR(rx->addr3),
- MAC2STR(rx->addr4));
+ printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n",
+ print_mac(mac, rx->addr1), print_mac(mac2, rx->addr2),
+ print_mac(mac3, rx->addr3), print_mac(mac4, rx->addr4));
- printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n",
- MAC2STR(rx->dst_addr), MAC2STR(rx->src_addr),
+ printk(KERN_DEBUG " dst=%s src=%s len=%d\n",
+ print_mac(mac, rx->dst_addr), print_mac(mac2, rx->src_addr),
__be16_to_cpu(rx->len));
}
@@ -561,6 +565,10 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
{
u16 fc;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+ DECLARE_MAC_BUF(mac4);
printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d "
"tx_control=0x%04x; jiffies=%ld\n",
@@ -576,35 +584,37 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
- printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4="
- MACSTR "\n",
- MAC2STR(tx->addr1), MAC2STR(tx->addr2), MAC2STR(tx->addr3),
- MAC2STR(tx->addr4));
+ printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n",
+ print_mac(mac, tx->addr1), print_mac(mac2, tx->addr2),
+ print_mac(mac3, tx->addr3), print_mac(mac4, tx->addr4));
- printk(KERN_DEBUG " dst=" MACSTR " src=" MACSTR " len=%d\n",
- MAC2STR(tx->dst_addr), MAC2STR(tx->src_addr),
+ printk(KERN_DEBUG " dst=%s src=%s len=%d\n",
+ print_mac(mac, tx->dst_addr), print_mac(mac2, tx->src_addr),
__be16_to_cpu(tx->len));
}
-int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr)
+int hostap_80211_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
- memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
- return ETH_ALEN;
-}
-
+ struct hostap_interface *iface = netdev_priv(skb->dev);
+ local_info_t *local = iface->local;
+
+ if (local->monitor_type == PRISM2_MONITOR_PRISM ||
+ local->monitor_type == PRISM2_MONITOR_CAPHDR) {
+ const unsigned char *mac = skb_mac_header(skb);
+
+ if (*(u32 *)mac == LWNG_CAP_DID_BASE) {
+ memcpy(haddr,
+ mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10,
+ ETH_ALEN); /* addr2 */
+ } else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */
+ memcpy(haddr,
+ mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10,
+ ETH_ALEN); /* addr2 */
+ }
+ } else
+ memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
-int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr)
-{
- const unsigned char *mac = skb_mac_header(skb);
-
- if (*(u32 *)mac == LWNG_CAP_DID_BASE) {
- memcpy(haddr, mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10,
- ETH_ALEN); /* addr2 */
- } else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */
- memcpy(haddr, mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10,
- ETH_ALEN); /* addr2 */
- }
return ETH_ALEN;
}
@@ -836,9 +846,18 @@ static void prism2_tx_timeout(struct net_device *dev)
local->func->schedule_reset(local);
}
+const struct header_ops hostap_80211_ops = {
+ .create = eth_header,
+ .rebuild = eth_rebuild_header,
+ .cache = eth_header_cache,
+ .cache_update = eth_header_cache_update,
+
+ .parse = hostap_80211_header_parse,
+};
+EXPORT_SYMBOL(hostap_80211_ops);
void hostap_setup_dev(struct net_device *dev, local_info_t *local,
- int main_dev)
+ int type)
{
struct hostap_interface *iface;
@@ -858,15 +877,22 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local,
dev->do_ioctl = hostap_ioctl;
dev->open = prism2_open;
dev->stop = prism2_close;
- dev->hard_start_xmit = hostap_data_start_xmit;
dev->set_mac_address = prism2_set_mac_address;
dev->set_multicast_list = hostap_set_multicast_list;
dev->change_mtu = prism2_change_mtu;
dev->tx_timeout = prism2_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
+ if (type == HOSTAP_INTERFACE_AP) {
+ dev->hard_start_xmit = hostap_mgmt_start_xmit;
+ dev->type = ARPHRD_IEEE80211;
+ dev->header_ops = &hostap_80211_ops;
+ } else {
+ dev->hard_start_xmit = hostap_data_start_xmit;
+ }
+
dev->mtu = local->mtu;
- if (!main_dev) {
+ if (type != HOSTAP_INTERFACE_MASTER) {
/* use main radio device queue */
dev->tx_queue_len = 0;
}
@@ -876,7 +902,6 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local,
netif_stop_queue(dev);
}
-
static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked)
{
struct net_device *dev = local->dev;
@@ -892,10 +917,6 @@ static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked)
if (local->apdev == NULL)
return -ENOMEM;
- local->apdev->hard_start_xmit = hostap_mgmt_start_xmit;
- local->apdev->type = ARPHRD_IEEE80211;
- local->apdev->hard_header_parse = hostap_80211_header_parse;
-
return 0;
}
@@ -1093,8 +1114,8 @@ struct proc_dir_entry *hostap_proc;
static int __init hostap_init(void)
{
- if (proc_net != NULL) {
- hostap_proc = proc_mkdir("hostap", proc_net);
+ if (init_net.proc_net != NULL) {
+ hostap_proc = proc_mkdir("hostap", init_net.proc_net);
if (!hostap_proc)
printk(KERN_WARNING "Failed to mkdir "
"/proc/net/hostap\n");
@@ -1109,7 +1130,7 @@ static void __exit hostap_exit(void)
{
if (hostap_proc != NULL) {
hostap_proc = NULL;
- remove_proc_entry("hostap", proc_net);
+ remove_proc_entry("hostap", init_net.proc_net);
}
}
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index 7da3664b851..fc876ba1857 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -444,7 +444,7 @@ static int prism2_pci_resume(struct pci_dev *pdev)
MODULE_DEVICE_TABLE(pci, prism2_pci_id_table);
-static struct pci_driver prism2_pci_drv_id = {
+static struct pci_driver prism2_pci_driver = {
.name = "hostap_pci",
.id_table = prism2_pci_id_table,
.probe = prism2_pci_probe,
@@ -458,13 +458,13 @@ static struct pci_driver prism2_pci_drv_id = {
static int __init init_prism2_pci(void)
{
- return pci_register_driver(&prism2_pci_drv_id);
+ return pci_register_driver(&prism2_pci_driver);
}
static void __exit exit_prism2_pci(void)
{
- pci_unregister_driver(&prism2_pci_drv_id);
+ pci_unregister_driver(&prism2_pci_driver);
}
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c
index d1d8ce022e6..b03536008ad 100644
--- a/drivers/net/wireless/hostap/hostap_proc.c
+++ b/drivers/net/wireless/hostap/hostap_proc.c
@@ -106,6 +106,7 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off,
local_info_t *local = (local_info_t *) data;
struct list_head *ptr;
struct hostap_interface *iface;
+ DECLARE_MAC_BUF(mac);
if (off > PROC_LIMIT) {
*eof = 1;
@@ -117,9 +118,9 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off,
iface = list_entry(ptr, struct hostap_interface, list);
if (iface->type != HOSTAP_INTERFACE_WDS)
continue;
- p += sprintf(p, "%s\t" MACSTR "\n",
+ p += sprintf(p, "%s\t%s\n",
iface->dev->name,
- MAC2STR(iface->u.wds.remote_addr));
+ print_mac(mac, iface->u.wds.remote_addr));
if ((p - page) > PROC_LIMIT) {
printk(KERN_DEBUG "%s: wds proc did not fit\n",
local->dev->name);
@@ -147,6 +148,7 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off,
struct list_head *ptr;
struct hostap_bss_info *bss;
int i;
+ DECLARE_MAC_BUF(mac);
if (off > PROC_LIMIT) {
*eof = 1;
@@ -158,8 +160,8 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off,
spin_lock_bh(&local->lock);
list_for_each(ptr, &local->bss_list) {
bss = list_entry(ptr, struct hostap_bss_info, list);
- p += sprintf(p, MACSTR "\t%lu\t%u\t0x%x\t",
- MAC2STR(bss->bssid), bss->last_update,
+ p += sprintf(p, "%s\t%lu\t%u\t0x%x\t",
+ print_mac(mac, bss->bssid), bss->last_update,
bss->count, bss->capab_info);
for (i = 0; i < bss->ssid_len; i++) {
p += sprintf(p, "%c",
@@ -312,6 +314,7 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off,
int entry, i, len, total = 0;
struct hfa384x_hostscan_result *scanres;
u8 *pos;
+ DECLARE_MAC_BUF(mac);
p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates "
"SSID\n");
@@ -329,14 +332,14 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off,
if ((p - page) > (PAGE_SIZE - 200))
break;
- p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ",
+ p += sprintf(p, "%d %d %d %d 0x%02x %d %s %d ",
le16_to_cpu(scanres->chid),
(s16) le16_to_cpu(scanres->anl),
(s16) le16_to_cpu(scanres->sl),
le16_to_cpu(scanres->beacon_interval),
le16_to_cpu(scanres->capability),
le16_to_cpu(scanres->rate),
- MAC2STR(scanres->bssid),
+ print_mac(mac, scanres->bssid),
le16_to_cpu(scanres->atim));
pos = scanres->sup_rates;
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
index 87a54aa6f4d..e6516a186d0 100644
--- a/drivers/net/wireless/hostap/hostap_wlan.h
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -3,6 +3,7 @@
#include <linux/wireless.h>
#include <linux/netdevice.h>
+#include <linux/mutex.h>
#include <net/iw_handler.h>
#include "hostap_config.h"
@@ -641,7 +642,7 @@ struct local_info {
* when removing entries from the list.
* TX and RX paths can use read lock. */
spinlock_t cmdlock, baplock, lock;
- struct semaphore rid_bap_sem;
+ struct mutex rid_bap_mtx;
u16 infofid; /* MAC buffer id for info frame */
/* txfid, intransmitfid, next_txtid, and next_alloc are protected by
* txfidlock */
@@ -660,7 +661,7 @@ struct local_info {
#define HOSTAP_BITS_TRANSMIT 0
#define HOSTAP_BITS_BAP_TASKLET 1
#define HOSTAP_BITS_BAP_TASKLET2 2
- long bits;
+ unsigned long bits;
struct ap_data *ap;
@@ -735,8 +736,6 @@ struct local_info {
PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1,
PRISM2_MONITOR_CAPHDR = 2
} monitor_type;
- int (*saved_eth_header_parse)(struct sk_buff *skb,
- unsigned char *haddr);
int monitor_allow_fcserr;
int hostapd; /* whether user space daemon, hostapd, is used for AP
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index e8a94b74629..fc6cdd8086c 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -1267,7 +1267,7 @@ static int ipw2100_start_adapter(struct ipw2100_priv *priv)
IPW2100_INTA_FATAL_ERROR |
IPW2100_INTA_PARITY_ERROR);
}
- } while (i--);
+ } while (--i);
/* Clear out any pending INTAs since we aren't supposed to have
* interrupts enabled at this point... */
@@ -1339,7 +1339,7 @@ static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
break;
- } while (i--);
+ } while (--i);
priv->status &= ~STATUS_RESET_PENDING;
@@ -1769,7 +1769,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
if (priv->stop_rf_kill) {
priv->stop_rf_kill = 0;
queue_delayed_work(priv->workqueue, &priv->rf_kill,
- round_jiffies(HZ));
+ round_jiffies_relative(HZ));
}
deferred = 1;
@@ -1914,6 +1914,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
u32 chan;
char *txratename;
u8 bssid[ETH_ALEN];
+ DECLARE_MAC_BUF(mac);
/*
* TBD: BSSID is usually 00:00:00:00:00:00 here and not
@@ -1975,9 +1976,9 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
}
IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID="
- MAC_FMT ")\n",
+ "%s)\n",
priv->net_dev->name, escape_essid(essid, essid_len),
- txratename, chan, MAC_ARG(bssid));
+ txratename, chan, print_mac(mac, bssid));
/* now we copy read ssid into dev */
if (!(priv->config & CFG_STATIC_ESSID)) {
@@ -2045,10 +2046,12 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
{
+ DECLARE_MAC_BUF(mac);
+
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
- "disassociated: '%s' " MAC_FMT " \n",
+ "disassociated: '%s' %s \n",
escape_essid(priv->essid, priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
@@ -2083,7 +2086,30 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
/* Make sure the RF Kill check timer is running */
priv->stop_rf_kill = 0;
cancel_delayed_work(&priv->rf_kill);
- queue_delayed_work(priv->workqueue, &priv->rf_kill, round_jiffies(HZ));
+ queue_delayed_work(priv->workqueue, &priv->rf_kill,
+ round_jiffies_relative(HZ));
+}
+
+static void send_scan_event(void *data)
+{
+ struct ipw2100_priv *priv = data;
+ union iwreq_data wrqu;
+
+ wrqu.data.length = 0;
+ wrqu.data.flags = 0;
+ wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
+}
+
+static void ipw2100_scan_event_later(struct work_struct *work)
+{
+ send_scan_event(container_of(work, struct ipw2100_priv,
+ scan_event_later.work));
+}
+
+static void ipw2100_scan_event_now(struct work_struct *work)
+{
+ send_scan_event(container_of(work, struct ipw2100_priv,
+ scan_event_now));
}
static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
@@ -2092,6 +2118,18 @@ static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
/* Age the scan results... */
priv->ieee->scans++;
priv->status &= ~STATUS_SCANNING;
+
+ /* Only userspace-requested scan completion events go out immediately */
+ if (!priv->user_requested_scan) {
+ if (!delayed_work_pending(&priv->scan_event_later))
+ queue_delayed_work(priv->workqueue,
+ &priv->scan_event_later,
+ round_jiffies_relative(msecs_to_jiffies(4000)));
+ } else {
+ priv->user_requested_scan = 0;
+ cancel_delayed_work(&priv->scan_event_later);
+ queue_work(priv->workqueue, &priv->scan_event_now);
+ }
}
#ifdef CONFIG_IPW2100_DEBUG
@@ -4020,6 +4058,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
char *out = buf;
int length;
int ret;
+ DECLARE_MAC_BUF(mac);
if (priv->status & STATUS_RF_KILL_MASK)
return 0;
@@ -4047,9 +4086,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
__LINE__);
out += sprintf(out, "ESSID: %s\n", essid);
- out += sprintf(out, "BSSID: %02x:%02x:%02x:%02x:%02x:%02x\n",
- bssid[0], bssid[1], bssid[2],
- bssid[3], bssid[4], bssid[5]);
+ out += sprintf(out, "BSSID: %s\n", print_mac(mac, bssid));
out += sprintf(out, "Channel: %d\n", chan);
return out - buf;
@@ -4206,7 +4243,7 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
priv->stop_rf_kill = 0;
cancel_delayed_work(&priv->rf_kill);
queue_delayed_work(priv->workqueue, &priv->rf_kill,
- round_jiffies(HZ));
+ round_jiffies_relative(HZ));
} else
schedule_reset(priv);
}
@@ -4347,6 +4384,7 @@ static void ipw2100_kill_workqueue(struct ipw2100_priv *priv)
cancel_delayed_work(&priv->wx_event_work);
cancel_delayed_work(&priv->hang_check);
cancel_delayed_work(&priv->rf_kill);
+ cancel_delayed_work(&priv->scan_event_later);
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;
}
@@ -4623,19 +4661,20 @@ static void ipw2100_rx_free(struct ipw2100_priv *priv)
static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
{
u32 length = ETH_ALEN;
- u8 mac[ETH_ALEN];
+ u8 addr[ETH_ALEN];
+ DECLARE_MAC_BUF(mac);
int err;
- err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, mac, &length);
+ err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length);
if (err) {
IPW_DEBUG_INFO("MAC address read failed\n");
return -EIO;
}
- IPW_DEBUG_INFO("card MAC is %02X:%02X:%02X:%02X:%02X:%02X\n",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- memcpy(priv->net_dev->dev_addr, mac, ETH_ALEN);
+ memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN);
+ IPW_DEBUG_INFO("card MAC is %s\n",
+ print_mac(mac, priv->net_dev->dev_addr));
return 0;
}
@@ -5014,10 +5053,10 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
int err;
#ifdef CONFIG_IPW2100_DEBUG
+ DECLARE_MAC_BUF(mac);
if (bssid != NULL)
- IPW_DEBUG_HC("MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
- bssid[0], bssid[1], bssid[2], bssid[3], bssid[4],
- bssid[5]);
+ IPW_DEBUG_HC("MANDATORY_BSSID: %s\n",
+ print_mac(mac, bssid));
else
IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
#endif
@@ -5943,7 +5982,7 @@ static void ipw2100_rf_kill(struct work_struct *work)
IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
if (!priv->stop_rf_kill)
queue_delayed_work(priv->workqueue, &priv->rf_kill,
- round_jiffies(HZ));
+ round_jiffies_relative(HZ));
goto exit_unlock;
}
@@ -6009,7 +6048,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
* ends up causing problems. So, we just handle
* the WX extensions through the ipw2100_ioctl interface */
- /* memset() puts everything to 0, so we only have explicitely set
+ /* memset() puts everything to 0, so we only have explicitly set
* those values that need to be something else */
/* If power management is turned on, default to AUTO mode */
@@ -6089,6 +6128,8 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check);
INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
+ INIT_WORK(&priv->scan_event_now, ipw2100_scan_event_now);
+ INIT_DELAYED_WORK(&priv->scan_event_later, ipw2100_scan_event_later);
tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
ipw2100_irq_tasklet, (unsigned long)priv);
@@ -6210,8 +6251,6 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
IPW_DEBUG_INFO("Attempting to register device...\n");
- SET_MODULE_OWNER(dev);
-
printk(KERN_INFO DRV_NAME
": Detected Intel PRO/Wireless 2100 Network Connection\n");
@@ -6865,6 +6904,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev,
static const unsigned char off[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+ DECLARE_MAC_BUF(mac);
// sanity checks
if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
@@ -6890,13 +6930,8 @@ static int ipw2100_wx_set_wap(struct net_device *dev,
err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
- IPW_DEBUG_WX("SET BSSID -> %02X:%02X:%02X:%02X:%02X:%02X\n",
- wrqu->ap_addr.sa_data[0] & 0xff,
- wrqu->ap_addr.sa_data[1] & 0xff,
- wrqu->ap_addr.sa_data[2] & 0xff,
- wrqu->ap_addr.sa_data[3] & 0xff,
- wrqu->ap_addr.sa_data[4] & 0xff,
- wrqu->ap_addr.sa_data[5] & 0xff);
+ IPW_DEBUG_WX("SET BSSID -> %s\n",
+ print_mac(mac, wrqu->ap_addr.sa_data));
done:
mutex_unlock(&priv->action_mutex);
@@ -6912,6 +6947,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev,
*/
struct ipw2100_priv *priv = ieee80211_priv(dev);
+ DECLARE_MAC_BUF(mac);
/* If we are associated, trying to associate, or have a statically
* configured BSSID then return that; otherwise return ANY */
@@ -6921,8 +6957,8 @@ static int ipw2100_wx_get_wap(struct net_device *dev,
} else
memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
- IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
- MAC_ARG(wrqu->ap_addr.sa_data));
+ IPW_DEBUG_WX("Getting WAP BSSID: %s\n",
+ print_mac(mac, wrqu->ap_addr.sa_data));
return 0;
}
@@ -7398,6 +7434,8 @@ static int ipw2100_wx_set_scan(struct net_device *dev,
}
IPW_DEBUG_WX("Initiating scan...\n");
+
+ priv->user_requested_scan = 1;
if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) {
IPW_DEBUG_WX("Start scan failed.\n");
@@ -7472,7 +7510,7 @@ static int ipw2100_wx_set_power(struct net_device *dev,
switch (wrqu->power.flags & IW_POWER_MODE) {
case IW_POWER_ON: /* If not specified */
case IW_POWER_MODE: /* If set all mask */
- case IW_POWER_ALL_R: /* If explicitely state all */
+ case IW_POWER_ALL_R: /* If explicitly state all */
break;
default: /* Otherwise we don't support it */
IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
@@ -8250,10 +8288,9 @@ static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
static struct iw_handler_def ipw2100_wx_handler_def = {
.standard = ipw2100_wx_handlers,
- .num_standard = sizeof(ipw2100_wx_handlers) / sizeof(iw_handler),
- .num_private = sizeof(ipw2100_private_handler) / sizeof(iw_handler),
- .num_private_args = sizeof(ipw2100_private_args) /
- sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(ipw2100_wx_handlers),
+ .num_private = ARRAY_SIZE(ipw2100_private_handler),
+ .num_private_args = ARRAY_SIZE(ipw2100_private_args),
.private = (iw_handler *) ipw2100_private_handler,
.private_args = (struct iw_priv_args *)ipw2100_private_args,
.get_wireless_stats = ipw2100_wx_wireless_stats,
diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h
index 2b8be2418fa..bbf1ddcafba 100644
--- a/drivers/net/wireless/ipw2100.h
+++ b/drivers/net/wireless/ipw2100.h
@@ -586,6 +586,10 @@ struct ipw2100_priv {
struct delayed_work wx_event_work;
struct delayed_work hang_check;
struct delayed_work rf_kill;
+ struct work_struct scan_event_now;
+ struct delayed_work scan_event_later;
+
+ int user_requested_scan;
u32 interrupts;
int tx_interrupts;
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 61497c46746..54f44e5473c 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -1740,8 +1740,10 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
if (disable_radio) {
priv->status |= STATUS_RF_KILL_SW;
- if (priv->workqueue)
+ if (priv->workqueue) {
cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->scan_event);
+ }
queue_work(priv->workqueue, &priv->down);
} else {
priv->status &= ~STATUS_RF_KILL_SW;
@@ -1751,7 +1753,7 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
/* Make sure the RF_KILL check timer is running */
cancel_delayed_work(&priv->rf_kill);
queue_delayed_work(priv->workqueue, &priv->rf_kill,
- round_jiffies(2 * HZ));
+ round_jiffies_relative(2 * HZ));
} else
queue_work(priv->workqueue, &priv->up);
}
@@ -1992,6 +1994,7 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
wake_up_interruptible(&priv->wait_command_queue);
priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->scan_event);
schedule_work(&priv->link_down);
queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
handled |= IPW_INTA_BIT_RF_KILL_DONE;
@@ -2247,8 +2250,8 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac)
return -1;
}
- IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n",
- priv->net_dev->name, MAC_ARG(mac));
+ IPW_DEBUG_INFO("%s: Setting MAC to %s\n",
+ priv->net_dev->name, print_mac(mac, mac));
return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac);
}
@@ -3796,6 +3799,7 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
{
struct ipw_station_entry entry;
int i;
+ DECLARE_MAC_BUF(mac);
for (i = 0; i < priv->num_stations; i++) {
if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) {
@@ -3812,7 +3816,7 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
if (i == MAX_STATIONS)
return IPW_INVALID_STATION;
- IPW_DEBUG_SCAN("Adding AdHoc station: " MAC_FMT "\n", MAC_ARG(bssid));
+ IPW_DEBUG_SCAN("Adding AdHoc station: %s\n", print_mac(mac, bssid));
entry.reserved = 0;
entry.support_mode = 0;
@@ -3839,6 +3843,7 @@ static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid)
static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
{
int err;
+ DECLARE_MAC_BUF(mac);
if (priv->status & STATUS_ASSOCIATING) {
IPW_DEBUG_ASSOC("Disassociating while associating.\n");
@@ -3851,9 +3856,9 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
return;
}
- IPW_DEBUG_ASSOC("Disassocation attempt from " MAC_FMT " "
+ IPW_DEBUG_ASSOC("Disassocation attempt from %s "
"on channel %d.\n",
- MAC_ARG(priv->assoc_request.bssid),
+ print_mac(mac, priv->assoc_request.bssid),
priv->assoc_request.channel);
priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
@@ -4341,6 +4346,37 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv,
IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count);
}
+static void ipw_scan_event(struct work_struct *work)
+{
+ union iwreq_data wrqu;
+
+ struct ipw_priv *priv =
+ container_of(work, struct ipw_priv, scan_event.work);
+
+ wrqu.data.length = 0;
+ wrqu.data.flags = 0;
+ wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
+}
+
+static void handle_scan_event(struct ipw_priv *priv)
+{
+ /* Only userspace-requested scan completion events go out immediately */
+ if (!priv->user_requested_scan) {
+ if (!delayed_work_pending(&priv->scan_event))
+ queue_delayed_work(priv->workqueue, &priv->scan_event,
+ round_jiffies_relative(msecs_to_jiffies(4000)));
+ } else {
+ union iwreq_data wrqu;
+
+ priv->user_requested_scan = 0;
+ cancel_delayed_work(&priv->scan_event);
+
+ wrqu.data.length = 0;
+ wrqu.data.flags = 0;
+ wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
+ }
+}
+
/**
* Handle host notification packet.
* Called from interrupt routine
@@ -4348,6 +4384,7 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv,
static void ipw_rx_notification(struct ipw_priv *priv,
struct ipw_rx_notification *notif)
{
+ DECLARE_MAC_BUF(mac);
notif->size = le16_to_cpu(notif->size);
IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size);
@@ -4360,11 +4397,11 @@ static void ipw_rx_notification(struct ipw_priv *priv,
case CMAS_ASSOCIATED:{
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
- "associated: '%s' " MAC_FMT
+ "associated: '%s' %s"
" \n",
escape_essid(priv->essid,
priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
switch (priv->ieee->iw_mode) {
case IW_MODE_INFRA:
@@ -4444,13 +4481,13 @@ static void ipw_rx_notification(struct ipw_priv *priv,
IPW_DL_STATE |
IPW_DL_ASSOC,
"deauthenticated: '%s' "
- MAC_FMT
+ "%s"
": (0x%04X) - %s \n",
escape_essid(priv->
essid,
priv->
essid_len),
- MAC_ARG(priv->bssid),
+ print_mac(mac, priv->bssid),
ntohs(auth->status),
ipw_get_status_code
(ntohs
@@ -4467,11 +4504,11 @@ static void ipw_rx_notification(struct ipw_priv *priv,
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
- "authenticated: '%s' " MAC_FMT
+ "authenticated: '%s' %s"
"\n",
escape_essid(priv->essid,
priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
break;
}
@@ -4496,11 +4533,11 @@ static void ipw_rx_notification(struct ipw_priv *priv,
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
- "disassociated: '%s' " MAC_FMT
+ "disassociated: '%s' %s"
" \n",
escape_essid(priv->essid,
priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
priv->status &=
~(STATUS_DISASSOCIATING |
@@ -4535,10 +4572,10 @@ static void ipw_rx_notification(struct ipw_priv *priv,
switch (auth->state) {
case CMAS_AUTHENTICATED:
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "authenticated: '%s' " MAC_FMT " \n",
+ "authenticated: '%s' %s \n",
escape_essid(priv->essid,
priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
priv->status |= STATUS_AUTH;
break;
@@ -4554,10 +4591,10 @@ static void ipw_rx_notification(struct ipw_priv *priv,
}
IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
IPW_DL_ASSOC,
- "deauthenticated: '%s' " MAC_FMT "\n",
+ "deauthenticated: '%s' %s\n",
escape_essid(priv->essid,
priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
priv->status &= ~(STATUS_ASSOCIATING |
STATUS_AUTH |
@@ -4691,7 +4728,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
&& priv->status & STATUS_ASSOCIATED)
queue_delayed_work(priv->workqueue,
&priv->request_scan,
- round_jiffies(HZ));
+ round_jiffies_relative(HZ));
/* Send an empty event to user space.
* We don't send the received data on the event because
@@ -4702,14 +4739,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
* on how the scan was initiated. User space can just
* sync on periodic scan to get fresh data...
* Jean II */
- if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) {
- union iwreq_data wrqu;
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(priv->net_dev, SIOCGIWSCAN,
- &wrqu, NULL);
- }
+ if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
+ handle_scan_event(priv);
break;
}
@@ -5383,25 +5414,27 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
int roaming)
{
struct ipw_supported_rates rates;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
/* Verify that this network's capability is compatible with the
* current mode (AdHoc or Infrastructure) */
if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
!(network->capability & WLAN_CAPABILITY_IBSS))) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded due to "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded due to "
"capability mismatch.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
/* If we do not have an ESSID for this AP, we can not associate with
* it */
if (network->flags & NETWORK_EMPTY_ESSID) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of hidden ESSID.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
@@ -5411,11 +5444,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
if ((network->ssid_len != match->network->ssid_len) ||
memcmp(network->ssid, match->network->ssid,
network->ssid_len)) {
- IPW_DEBUG_MERGE("Netowrk '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of non-network ESSID.\n",
escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
} else {
@@ -5430,9 +5463,9 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
strncpy(escaped,
escape_essid(network->ssid, network->ssid_len),
sizeof(escaped));
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of ESSID mismatch: '%s'.\n",
- escaped, MAC_ARG(network->bssid),
+ escaped, print_mac(mac, network->bssid),
escape_essid(priv->essid,
priv->essid_len));
return 0;
@@ -5459,10 +5492,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
/* Now go through and see if the requested network is valid... */
if (priv->ieee->scan_age != 0 &&
time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of age: %ums.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
jiffies_to_msecs(jiffies -
network->last_scanned));
return 0;
@@ -5470,10 +5503,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
if ((priv->config & CFG_STATIC_CHANNEL) &&
(network->channel != priv->channel)) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of channel mismatch: %d != %d.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
network->channel, priv->channel);
return 0;
}
@@ -5481,10 +5514,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
/* Verify privacy compatability */
if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of privacy mismatch: %s != %s.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
priv->
capability & CAP_PRIVACY_ON ? "on" : "off",
network->
@@ -5494,40 +5527,41 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
}
if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
- "because of the same BSSID match: " MAC_FMT
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+ "because of the same BSSID match: %s"
".\n", escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid), MAC_ARG(priv->bssid));
+ print_mac(mac, network->bssid),
+ print_mac(mac2, priv->bssid));
return 0;
}
/* Filter out any incompatible freq / mode combinations */
if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of invalid frequency/mode "
"combination.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
/* Ensure that the rates supported by the driver are compatible with
* this AP, including verification of basic rates (mandatory) */
if (!ipw_compatible_rates(priv, network, &rates)) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because configured rate mask excludes "
"AP mandatory rate.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
if (rates.num_rates == 0) {
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
"because of no compatible rates.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
@@ -5538,9 +5572,9 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv,
/* Set up 'new' AP to this network */
ipw_copy_rates(&match->rates, &rates);
match->network = network;
- IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' is a viable match.\n",
+ IPW_DEBUG_MERGE("Network '%s (%s)' is a viable match.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 1;
}
@@ -5594,6 +5628,7 @@ static int ipw_best_network(struct ipw_priv *priv,
struct ieee80211_network *network, int roaming)
{
struct ipw_supported_rates rates;
+ DECLARE_MAC_BUF(mac);
/* Verify that this network's capability is compatible with the
* current mode (AdHoc or Infrastructure) */
@@ -5601,20 +5636,20 @@ static int ipw_best_network(struct ipw_priv *priv,
!(network->capability & WLAN_CAPABILITY_ESS)) ||
(priv->ieee->iw_mode == IW_MODE_ADHOC &&
!(network->capability & WLAN_CAPABILITY_IBSS))) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded due to "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded due to "
"capability mismatch.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
/* If we do not have an ESSID for this AP, we can not associate with
* it */
if (network->flags & NETWORK_EMPTY_ESSID) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of hidden ESSID.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
@@ -5624,11 +5659,11 @@ static int ipw_best_network(struct ipw_priv *priv,
if ((network->ssid_len != match->network->ssid_len) ||
memcmp(network->ssid, match->network->ssid,
network->ssid_len)) {
- IPW_DEBUG_ASSOC("Netowrk '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of non-network ESSID.\n",
escape_essid(network->ssid,
network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
} else {
@@ -5642,9 +5677,9 @@ static int ipw_best_network(struct ipw_priv *priv,
strncpy(escaped,
escape_essid(network->ssid, network->ssid_len),
sizeof(escaped));
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of ESSID mismatch: '%s'.\n",
- escaped, MAC_ARG(network->bssid),
+ escaped, print_mac(mac, network->bssid),
escape_essid(priv->essid,
priv->essid_len));
return 0;
@@ -5658,12 +5693,12 @@ static int ipw_best_network(struct ipw_priv *priv,
strncpy(escaped,
escape_essid(network->ssid, network->ssid_len),
sizeof(escaped));
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded because "
- "'%s (" MAC_FMT ")' has a stronger signal.\n",
- escaped, MAC_ARG(network->bssid),
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded because "
+ "'%s (%s)' has a stronger signal.\n",
+ escaped, print_mac(mac, network->bssid),
escape_essid(match->network->ssid,
match->network->ssid_len),
- MAC_ARG(match->network->bssid));
+ print_mac(mac, match->network->bssid));
return 0;
}
@@ -5671,11 +5706,11 @@ static int ipw_best_network(struct ipw_priv *priv,
* last 3 seconds, do not try and associate again... */
if (network->last_associate &&
time_after(network->last_associate + (HZ * 3UL), jiffies)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of storming (%ums since last "
"assoc attempt).\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
jiffies_to_msecs(jiffies -
network->last_associate));
return 0;
@@ -5684,10 +5719,10 @@ static int ipw_best_network(struct ipw_priv *priv,
/* Now go through and see if the requested network is valid... */
if (priv->ieee->scan_age != 0 &&
time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of age: %ums.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
jiffies_to_msecs(jiffies -
network->last_scanned));
return 0;
@@ -5695,10 +5730,10 @@ static int ipw_best_network(struct ipw_priv *priv,
if ((priv->config & CFG_STATIC_CHANNEL) &&
(network->channel != priv->channel)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of channel mismatch: %d != %d.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
network->channel, priv->channel);
return 0;
}
@@ -5706,10 +5741,10 @@ static int ipw_best_network(struct ipw_priv *priv,
/* Verify privacy compatability */
if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of privacy mismatch: %s != %s.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid),
+ print_mac(mac, network->bssid),
priv->capability & CAP_PRIVACY_ON ? "on" :
"off",
network->capability &
@@ -5719,48 +5754,48 @@ static int ipw_best_network(struct ipw_priv *priv,
if ((priv->config & CFG_STATIC_BSSID) &&
memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
- "because of BSSID mismatch: " MAC_FMT ".\n",
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+ "because of BSSID mismatch: %s.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid), MAC_ARG(priv->bssid));
+ print_mac(mac, network->bssid), print_mac(mac, priv->bssid));
return 0;
}
/* Filter out any incompatible freq / mode combinations */
if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of invalid frequency/mode "
"combination.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
/* Filter out invalid channel in current GEO */
if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of invalid channel in current GEO\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
/* Ensure that the rates supported by the driver are compatible with
* this AP, including verification of basic rates (mandatory) */
if (!ipw_compatible_rates(priv, network, &rates)) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because configured rate mask excludes "
"AP mandatory rate.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
if (rates.num_rates == 0) {
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+ IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
"because of no compatible rates.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 0;
}
@@ -5772,9 +5807,9 @@ static int ipw_best_network(struct ipw_priv *priv,
ipw_copy_rates(&match->rates, &rates);
match->network = network;
- IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' is a viable match.\n",
+ IPW_DEBUG_ASSOC("Network '%s (%s)' is a viable match.\n",
escape_essid(network->ssid, network->ssid_len),
- MAC_ARG(network->bssid));
+ print_mac(mac, network->bssid));
return 1;
}
@@ -6016,6 +6051,7 @@ static void ipw_bg_adhoc_check(struct work_struct *work)
static void ipw_debug_config(struct ipw_priv *priv)
{
+ DECLARE_MAC_BUF(mac);
IPW_DEBUG_INFO("Scan completed, no valid APs matched "
"[CFG 0x%08X]\n", priv->config);
if (priv->config & CFG_STATIC_CHANNEL)
@@ -6028,8 +6064,8 @@ static void ipw_debug_config(struct ipw_priv *priv)
else
IPW_DEBUG_INFO("ESSID unlocked.\n");
if (priv->config & CFG_STATIC_BSSID)
- IPW_DEBUG_INFO("BSSID locked to " MAC_FMT "\n",
- MAC_ARG(priv->bssid));
+ IPW_DEBUG_INFO("BSSID locked to %s\n",
+ print_mac(mac, priv->bssid));
else
IPW_DEBUG_INFO("BSSID unlocked.\n");
if (priv->capability & CAP_PRIVACY_ON)
@@ -7221,6 +7257,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
struct ipw_supported_rates *rates, int roaming)
{
int err;
+ DECLARE_MAC_BUF(mac);
if (priv->config & CFG_FIXED_RATE)
ipw_set_fixed_rate(priv, network->mode);
@@ -7388,9 +7425,9 @@ static int ipw_associate_network(struct ipw_priv *priv,
return err;
}
- IPW_DEBUG(IPW_DL_STATE, "associating: '%s' " MAC_FMT " \n",
+ IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %s \n",
escape_essid(priv->essid, priv->essid_len),
- MAC_ARG(priv->bssid));
+ print_mac(mac, priv->bssid));
return 0;
}
@@ -8202,6 +8239,9 @@ static void ipw_rx(struct ipw_priv *priv)
struct ieee80211_hdr_4addr *header;
u32 r, w, i;
u8 network_packet;
+ DECLARE_MAC_BUF(mac);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
r = ipw_read32(priv, IPW_RX_READ_INDEX);
w = ipw_read32(priv, IPW_RX_WRITE_INDEX);
@@ -8328,14 +8368,17 @@ static void ipw_rx(struct ipw_priv *priv)
header)))
{
IPW_DEBUG_DROP("Dropping: "
- MAC_FMT ", "
- MAC_FMT ", "
- MAC_FMT "\n",
- MAC_ARG(header->
+ "%s, "
+ "%s, "
+ "%s\n",
+ print_mac(mac,
+ header->
addr1),
- MAC_ARG(header->
+ print_mac(mac2,
+ header->
addr2),
- MAC_ARG(header->
+ print_mac(mac3,
+ header->
addr3));
break;
}
@@ -8867,6 +8910,7 @@ static int ipw_wx_set_wap(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
+ DECLARE_MAC_BUF(mac);
static const unsigned char any[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
@@ -8897,8 +8941,8 @@ static int ipw_wx_set_wap(struct net_device *dev,
return 0;
}
- IPW_DEBUG_WX("Setting mandatory BSSID to " MAC_FMT "\n",
- MAC_ARG(wrqu->ap_addr.sa_data));
+ IPW_DEBUG_WX("Setting mandatory BSSID to %s\n",
+ print_mac(mac, wrqu->ap_addr.sa_data));
memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
@@ -8916,6 +8960,8 @@ static int ipw_wx_get_wap(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
+ DECLARE_MAC_BUF(mac);
+
/* If we are associated, trying to associate, or have a statically
* configured BSSID then return that; otherwise return ANY */
mutex_lock(&priv->mutex);
@@ -8926,8 +8972,8 @@ static int ipw_wx_get_wap(struct net_device *dev,
} else
memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
- IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
- MAC_ARG(wrqu->ap_addr.sa_data));
+ IPW_DEBUG_WX("Getting WAP BSSID: %s\n",
+ print_mac(mac, wrqu->ap_addr.sa_data));
mutex_unlock(&priv->mutex);
return 0;
}
@@ -9472,6 +9518,10 @@ static int ipw_wx_set_scan(struct net_device *dev,
struct ipw_priv *priv = ieee80211_priv(dev);
struct iw_scan_req *req = (struct iw_scan_req *)extra;
+ mutex_lock(&priv->mutex);
+ priv->user_requested_scan = 1;
+ mutex_unlock(&priv->mutex);
+
if (wrqu->data.length == sizeof(struct iw_scan_req)) {
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
ipw_request_direct_scan(priv, req->essid,
@@ -9553,7 +9603,7 @@ static int ipw_wx_set_power(struct net_device *dev,
switch (wrqu->power.flags & IW_POWER_MODE) {
case IW_POWER_ON: /* If not specified */
case IW_POWER_MODE: /* If set all mask */
- case IW_POWER_ALL_R: /* If explicitely state all */
+ case IW_POWER_ALL_R: /* If explicitly state all */
break;
default: /* Otherwise we don't support it */
IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
@@ -10133,6 +10183,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
u8 id, hdr_len, unicast;
u16 remaining_bytes;
int fc;
+ DECLARE_MAC_BUF(mac);
hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
switch (priv->ieee->iw_mode) {
@@ -10143,8 +10194,8 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
id = ipw_add_station(priv, hdr->addr1);
if (id == IPW_INVALID_STATION) {
IPW_WARNING("Attempt to send data to "
- "invalid cell: " MAC_FMT "\n",
- MAC_ARG(hdr->addr1));
+ "invalid cell: %s\n",
+ print_mac(mac, hdr->addr1));
goto drop;
}
}
@@ -10460,13 +10511,15 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p)
{
struct ipw_priv *priv = ieee80211_priv(dev);
struct sockaddr *addr = p;
+ DECLARE_MAC_BUF(mac);
+
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
mutex_lock(&priv->mutex);
priv->config |= CFG_CUSTOM_MAC;
memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
- printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n",
- priv->net_dev->name, MAC_ARG(priv->mac_addr));
+ printk(KERN_INFO "%s: Setting MAC to %s\n",
+ priv->net_dev->name, print_mac(mac, priv->mac_addr));
queue_work(priv->workqueue, &priv->adapter_restart);
mutex_unlock(&priv->mutex);
return 0;
@@ -10647,6 +10700,7 @@ static void ipw_link_up(struct ipw_priv *priv)
}
cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->scan_event);
ipw_reset_stats(priv);
/* Ensure the rate is updated immediately */
priv->last_rate = ipw_get_current_rate(priv);
@@ -10684,7 +10738,8 @@ static void ipw_link_down(struct ipw_priv *priv)
if (!(priv->status & STATUS_EXIT_PENDING)) {
/* Queue up another scan... */
queue_delayed_work(priv->workqueue, &priv->request_scan, 0);
- }
+ } else
+ cancel_delayed_work(&priv->scan_event);
}
static void ipw_bg_link_down(struct work_struct *work)
@@ -10714,6 +10769,7 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv)
INIT_WORK(&priv->up, ipw_bg_up);
INIT_WORK(&priv->down, ipw_bg_down);
INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan);
+ INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event);
INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan);
INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats);
INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan);
@@ -11625,7 +11681,6 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_destroy_workqueue;
}
- SET_MODULE_OWNER(net_dev);
SET_NETDEV_DEV(net_dev, &pdev->dev);
mutex_lock(&priv->mutex);
@@ -11746,6 +11801,7 @@ static void ipw_pci_remove(struct pci_dev *pdev)
cancel_delayed_work(&priv->adhoc_check);
cancel_delayed_work(&priv->gather_stats);
cancel_delayed_work(&priv->request_scan);
+ cancel_delayed_work(&priv->scan_event);
cancel_delayed_work(&priv->rf_kill);
cancel_delayed_work(&priv->scan_check);
destroy_workqueue(priv->workqueue);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index 626a240a87d..bec8e37a173 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -45,7 +45,6 @@
#include <linux/firmware.h>
#include <linux/wireless.h>
-#include <linux/dma-mapping.h>
#include <linux/jiffies.h>
#include <asm/io.h>
@@ -1288,6 +1287,8 @@ struct ipw_priv {
struct iw_public_data wireless_data;
+ int user_requested_scan;
+
struct workqueue_struct *workqueue;
struct delayed_work adhoc_check;
@@ -1296,6 +1297,7 @@ struct ipw_priv {
struct work_struct system_config;
struct work_struct rx_replenish;
struct delayed_work request_scan;
+ struct delayed_work scan_event;
struct work_struct request_passive_scan;
struct work_struct adapter_restart;
struct delayed_work rf_kill;
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
new file mode 100644
index 00000000000..8d52a26c248
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -0,0 +1,128 @@
+config IWLWIFI
+ bool "Intel Wireless WiFi Link Drivers"
+ depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+ select FW_LOADER
+ default n
+ ---help---
+ Select to enable drivers based on the iwlwifi project. This
+ project provides a common foundation for Intel's wireless
+ drivers designed to use the mac80211 subsystem.
+
+ See <file:Documentation/networking/README.iwlwifi> for
+ information on the capabilities currently enabled in this
+ driver and for tips for debugging issues and problems.
+
+config IWLWIFI_DEBUG
+ bool "Enable full debugging output in iwlwifi drivers"
+ depends on IWLWIFI
+ default y
+ ---help---
+ This option will enable debug tracing output for the iwlwifi
+ drivers.
+
+ This will result in the kernel module being ~100k larger. You can
+ control which debug output is sent to the kernel log by setting the
+ value in
+
+ /sys/bus/pci/drivers/${DRIVER}/debug_level
+
+ This entry will only exist if this option is enabled.
+
+ To set a value, simply echo an 8-byte hex value to the same file:
+
+ % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level
+
+ You can find the list of debug mask values in:
+ drivers/net/wireless/mac80211/iwlwifi/iwl-debug.h
+
+ If this is your first time using this driver, you should say Y here
+ as the debug information can assist others in helping you resolve
+ any problems you may encounter.
+
+config IWLWIFI_SENSITIVITY
+ bool "Enable Sensitivity Calibration in iwlwifi drivers"
+ depends on IWLWIFI
+ default y
+ ---help---
+ This option will enable sensitivity calibration for the iwlwifi
+ drivers.
+
+config IWLWIFI_SPECTRUM_MEASUREMENT
+ bool "Enable Spectrum Measurement in iwlwifi drivers"
+ depends on IWLWIFI
+ default y
+ ---help---
+ This option will enable spectrum measurement for the iwlwifi drivers.
+
+config IWLWIFI_QOS
+ bool "Enable Wireless QoS in iwlwifi drivers"
+ depends on IWLWIFI
+ default y
+ ---help---
+ This option will enable wireless quality of service (QoS) for the
+ iwlwifi drivers.
+
+config IWLWIFI_HT
+ bool "Enable 802.11n HT features in iwlwifi drivers"
+ depends on EXPERIMENTAL
+ depends on IWLWIFI && MAC80211_HT
+ default n
+ ---help---
+ This option enables IEEE 802.11n High Throughput features
+ for the iwlwifi drivers.
+
+config IWL4965
+ tristate "Intel Wireless WiFi 4965AGN"
+ depends on m && IWLWIFI && EXPERIMENTAL
+ default m
+ ---help---
+ Select to build the driver supporting the:
+
+ Intel Wireless WiFi Link 4965AGN
+
+ This driver uses the kernel's mac80211 subsystem.
+
+ See <file:Documentation/networking/README.iwlwifi> for
+ information on the capabilities currently enabled in this
+ driver and for tips for debugging any issues or problems.
+
+ In order to use this driver, you will need a microcode (uCode)
+ image for it. You can obtain the microcode from:
+
+ <http://intellinuxwireless.org/>.
+
+ See the above referenced README.iwlwifi for information on where
+ to install the microcode images.
+
+ If you want to compile the driver as a module ( = code which can be
+ inserted in and remvoed from the running kernel whenever you want),
+ say M here and read <file:Documentation/kbuild/modules.txt>. The
+ module will be called iwl4965.ko.
+
+config IWL3945
+ tristate "Intel PRO/Wireless 3945ABG/BG Network Connection"
+ depends on m && IWLWIFI && EXPERIMENTAL
+ default m
+ ---help---
+ Select to build the driver supporting the:
+
+ Intel PRO/Wireless 3945ABG/BG Network Connection
+
+ This driver uses the kernel's mac80211 subsystem.
+
+ See <file:Documentation/networking/README.iwlwifi> for
+ information on the capabilities currently enabled in this
+ driver and for tips for debugging any issues or problems.
+
+ In order to use this driver, you will need a microcode (uCode)
+ image for it. You can obtain the microcode from:
+
+ <http://intellinuxwireless.org/>.
+
+ See the above referenced README.iwlwifi for information on where
+ to install the microcode images.
+
+ If you want to compile the driver as a module ( = code which can be
+ inserted in and remvoed from the running kernel whenever you want),
+ say M here and read <file:Documentation/kbuild/modules.txt>. The
+ module will be called iwl3945.ko.
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
new file mode 100644
index 00000000000..3bbd38358d5
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_IWL3945) += iwl3945.o
+iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o
+
+obj-$(CONFIG_IWL4965) += iwl4965.o
+iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
new file mode 100644
index 00000000000..fb5f0649f4f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_3945_hw__
+#define __iwl_3945_hw__
+
+#define IWL_RX_BUF_SIZE 3000
+/* card static random access memory (SRAM) for processor data and instructs */
+#define ALM_RTC_INST_UPPER_BOUND (0x014000)
+#define ALM_RTC_DATA_UPPER_BOUND (0x808000)
+
+#define ALM_RTC_INST_SIZE (ALM_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
+#define ALM_RTC_DATA_SIZE (ALM_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
+
+#define IWL_MAX_BSM_SIZE ALM_RTC_INST_SIZE
+#define IWL_MAX_INST_SIZE ALM_RTC_INST_SIZE
+#define IWL_MAX_DATA_SIZE ALM_RTC_DATA_SIZE
+#define IWL_MAX_NUM_QUEUES 8
+
+static inline int iwl_hw_valid_rtc_data_addr(u32 addr)
+{
+ return (addr >= RTC_DATA_LOWER_BOUND) &&
+ (addr < ALM_RTC_DATA_UPPER_BOUND);
+}
+
+/* Base physical address of iwl_shared is provided to FH_TSSR_CBB_BASE
+ * and &iwl_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */
+struct iwl_shared {
+ __le32 tx_base_ptr[8];
+ __le32 rx_read_ptr[3];
+} __attribute__ ((packed));
+
+struct iwl_tfd_frame_data {
+ __le32 addr;
+ __le32 len;
+} __attribute__ ((packed));
+
+struct iwl_tfd_frame {
+ __le32 control_flags;
+ struct iwl_tfd_frame_data pa[4];
+ u8 reserved[28];
+} __attribute__ ((packed));
+
+static inline u8 iwl_hw_get_rate(__le16 rate_n_flags)
+{
+ return le16_to_cpu(rate_n_flags) & 0xFF;
+}
+
+static inline u16 iwl_hw_get_rate_n_flags(__le16 rate_n_flags)
+{
+ return le16_to_cpu(rate_n_flags);
+}
+
+static inline __le16 iwl_hw_set_rate_n_flags(u8 rate, u16 flags)
+{
+ return cpu_to_le16((u16)rate|flags);
+}
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
new file mode 100644
index 00000000000..c48b1b537d2
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -0,0 +1,1019 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+#include <net/ieee80211.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#include <linux/workqueue.h>
+
+#define IWL 3945
+
+#include "../net/mac80211/ieee80211_rate.h"
+
+#include "iwlwifi.h"
+
+#define RS_NAME "iwl-3945-rs"
+
+struct iwl_rate_scale_data {
+ u64 data;
+ s32 success_counter;
+ s32 success_ratio;
+ s32 counter;
+ s32 average_tpt;
+ unsigned long stamp;
+};
+
+struct iwl_rate_scale_priv {
+ spinlock_t lock;
+ s32 *expected_tpt;
+ unsigned long last_partial_flush;
+ unsigned long last_flush;
+ u32 flush_time;
+ u32 last_tx_packets;
+ u32 tx_packets;
+ u8 tgg;
+ u8 flush_pending;
+ u8 start_rate;
+ u8 ibss_sta_added;
+ struct timer_list rate_scale_flush;
+ struct iwl_rate_scale_data win[IWL_RATE_COUNT];
+};
+
+static s32 iwl_expected_tpt_g[IWL_RATE_COUNT] = {
+ 7, 13, 35, 58, 0, 0, 76, 104, 130, 168, 191, 202
+};
+
+static s32 iwl_expected_tpt_g_prot[IWL_RATE_COUNT] = {
+ 7, 13, 35, 58, 0, 0, 0, 80, 93, 113, 123, 125
+};
+
+static s32 iwl_expected_tpt_a[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186
+};
+
+static s32 iwl_expected_tpt_b[IWL_RATE_COUNT] = {
+ 7, 13, 35, 58, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+struct iwl_tpt_entry {
+ s8 min_rssi;
+ u8 index;
+};
+
+static struct iwl_tpt_entry iwl_tpt_table_a[] = {
+ {-60, IWL_RATE_54M_INDEX},
+ {-64, IWL_RATE_48M_INDEX},
+ {-72, IWL_RATE_36M_INDEX},
+ {-80, IWL_RATE_24M_INDEX},
+ {-84, IWL_RATE_18M_INDEX},
+ {-85, IWL_RATE_12M_INDEX},
+ {-87, IWL_RATE_9M_INDEX},
+ {-89, IWL_RATE_6M_INDEX}
+};
+
+static struct iwl_tpt_entry iwl_tpt_table_b[] = {
+ {-86, IWL_RATE_11M_INDEX},
+ {-88, IWL_RATE_5M_INDEX},
+ {-90, IWL_RATE_2M_INDEX},
+ {-92, IWL_RATE_1M_INDEX}
+
+};
+
+static struct iwl_tpt_entry iwl_tpt_table_g[] = {
+ {-60, IWL_RATE_54M_INDEX},
+ {-64, IWL_RATE_48M_INDEX},
+ {-68, IWL_RATE_36M_INDEX},
+ {-80, IWL_RATE_24M_INDEX},
+ {-84, IWL_RATE_18M_INDEX},
+ {-85, IWL_RATE_12M_INDEX},
+ {-86, IWL_RATE_11M_INDEX},
+ {-88, IWL_RATE_5M_INDEX},
+ {-90, IWL_RATE_2M_INDEX},
+ {-92, IWL_RATE_1M_INDEX}
+};
+
+#define IWL_RATE_MAX_WINDOW 62
+#define IWL_RATE_FLUSH (3*HZ/10)
+#define IWL_RATE_WIN_FLUSH (HZ/2)
+#define IWL_RATE_HIGH_TH 11520
+#define IWL_RATE_MIN_FAILURE_TH 8
+#define IWL_RATE_MIN_SUCCESS_TH 8
+#define IWL_RATE_DECREASE_TH 1920
+
+static u8 iwl_get_rate_index_by_rssi(s32 rssi, u8 mode)
+{
+ u32 index = 0;
+ u32 table_size = 0;
+ struct iwl_tpt_entry *tpt_table = NULL;
+
+ if ((rssi < IWL_MIN_RSSI_VAL) || (rssi > IWL_MAX_RSSI_VAL))
+ rssi = IWL_MIN_RSSI_VAL;
+
+ switch (mode) {
+ case MODE_IEEE80211G:
+ tpt_table = iwl_tpt_table_g;
+ table_size = ARRAY_SIZE(iwl_tpt_table_g);
+ break;
+
+ case MODE_IEEE80211A:
+ tpt_table = iwl_tpt_table_a;
+ table_size = ARRAY_SIZE(iwl_tpt_table_a);
+ break;
+
+ default:
+ case MODE_IEEE80211B:
+ tpt_table = iwl_tpt_table_b;
+ table_size = ARRAY_SIZE(iwl_tpt_table_b);
+ break;
+ }
+
+ while ((index < table_size) && (rssi < tpt_table[index].min_rssi))
+ index++;
+
+ index = min(index, (table_size - 1));
+
+ return tpt_table[index].index;
+}
+
+static void iwl_clear_window(struct iwl_rate_scale_data *window)
+{
+ window->data = 0;
+ window->success_counter = 0;
+ window->success_ratio = IWL_INVALID_VALUE;
+ window->counter = 0;
+ window->average_tpt = IWL_INVALID_VALUE;
+ window->stamp = 0;
+}
+
+/**
+ * iwl_rate_scale_flush_windows - flush out the rate scale windows
+ *
+ * Returns the number of windows that have gathered data but were
+ * not flushed. If there were any that were not flushed, then
+ * reschedule the rate flushing routine.
+ */
+static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv)
+{
+ int unflushed = 0;
+ int i;
+ unsigned long flags;
+
+ /*
+ * For each rate, if we have collected data on that rate
+ * and it has been more than IWL_RATE_WIN_FLUSH
+ * since we flushed, clear out the gathered statistics
+ */
+ for (i = 0; i < IWL_RATE_COUNT; i++) {
+ if (!rs_priv->win[i].counter)
+ continue;
+
+ spin_lock_irqsave(&rs_priv->lock, flags);
+ if (time_after(jiffies, rs_priv->win[i].stamp +
+ IWL_RATE_WIN_FLUSH)) {
+ IWL_DEBUG_RATE("flushing %d samples of rate "
+ "index %d\n",
+ rs_priv->win[i].counter, i);
+ iwl_clear_window(&rs_priv->win[i]);
+ } else
+ unflushed++;
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+ }
+
+ return unflushed;
+}
+
+#define IWL_RATE_FLUSH_MAX 5000 /* msec */
+#define IWL_RATE_FLUSH_MIN 50 /* msec */
+
+static void iwl_bg_rate_scale_flush(unsigned long data)
+{
+ struct iwl_rate_scale_priv *rs_priv = (void *)data;
+ int unflushed = 0;
+ unsigned long flags;
+ u32 packet_count, duration, pps;
+
+ IWL_DEBUG_RATE("enter\n");
+
+ unflushed = iwl_rate_scale_flush_windows(rs_priv);
+
+ spin_lock_irqsave(&rs_priv->lock, flags);
+
+ rs_priv->flush_pending = 0;
+
+ /* Number of packets Rx'd since last time this timer ran */
+ packet_count = (rs_priv->tx_packets - rs_priv->last_tx_packets) + 1;
+
+ rs_priv->last_tx_packets = rs_priv->tx_packets + 1;
+
+ if (unflushed) {
+ duration =
+ jiffies_to_msecs(jiffies - rs_priv->last_partial_flush);
+/* duration = jiffies_to_msecs(rs_priv->flush_time); */
+
+ IWL_DEBUG_RATE("Tx'd %d packets in %dms\n",
+ packet_count, duration);
+
+ /* Determine packets per second */
+ if (duration)
+ pps = (packet_count * 1000) / duration;
+ else
+ pps = 0;
+
+ if (pps) {
+ duration = IWL_RATE_FLUSH_MAX / pps;
+ if (duration < IWL_RATE_FLUSH_MIN)
+ duration = IWL_RATE_FLUSH_MIN;
+ } else
+ duration = IWL_RATE_FLUSH_MAX;
+
+ rs_priv->flush_time = msecs_to_jiffies(duration);
+
+ IWL_DEBUG_RATE("new flush period: %d msec ave %d\n",
+ duration, packet_count);
+
+ mod_timer(&rs_priv->rate_scale_flush, jiffies +
+ rs_priv->flush_time);
+
+ rs_priv->last_partial_flush = jiffies;
+ }
+
+ /* If there weren't any unflushed entries, we don't schedule the timer
+ * to run again */
+
+ rs_priv->last_flush = jiffies;
+
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+ IWL_DEBUG_RATE("leave\n");
+}
+
+/**
+ * iwl_collect_tx_data - Update the success/failure sliding window
+ *
+ * We keep a sliding window of the last 64 packets transmitted
+ * at this rate. window->data contains the bitmask of successful
+ * packets.
+ */
+static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv,
+ struct iwl_rate_scale_data *window,
+ int success, int retries)
+{
+ unsigned long flags;
+
+ if (!retries) {
+ IWL_DEBUG_RATE("leave: retries == 0 -- should be at least 1\n");
+ return;
+ }
+
+ while (retries--) {
+ spin_lock_irqsave(&rs_priv->lock, flags);
+
+ /* If we have filled up the window then subtract one from the
+ * success counter if the high-bit is counting toward
+ * success */
+ if (window->counter == IWL_RATE_MAX_WINDOW) {
+ if (window->data & (1ULL << (IWL_RATE_MAX_WINDOW - 1)))
+ window->success_counter--;
+ } else
+ window->counter++;
+
+ /* Slide the window to the left one bit */
+ window->data = (window->data << 1);
+
+ /* If this packet was a success then set the low bit high */
+ if (success) {
+ window->success_counter++;
+ window->data |= 1;
+ }
+
+ /* window->counter can't be 0 -- it is either >0 or
+ * IWL_RATE_MAX_WINDOW */
+ window->success_ratio = 12800 * window->success_counter /
+ window->counter;
+
+ /* Tag this window as having been updated */
+ window->stamp = jiffies;
+
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+ }
+}
+
+static void rs_rate_init(void *priv_rate, void *priv_sta,
+ struct ieee80211_local *local, struct sta_info *sta)
+{
+ int i;
+
+ IWL_DEBUG_RATE("enter\n");
+
+ /* TODO: what is a good starting rate for STA? About middle? Maybe not
+ * the lowest or the highest rate.. Could consider using RSSI from
+ * previous packets? Need to have IEEE 802.1X auth succeed immediately
+ * after assoc.. */
+
+ for (i = IWL_RATE_COUNT - 1; i >= 0; i--) {
+ if (sta->supp_rates & (1 << i)) {
+ sta->txrate = i;
+ break;
+ }
+ }
+
+ sta->last_txrate = sta->txrate;
+
+ /* For MODE_IEEE80211A mode it start at IWL_FIRST_OFDM_RATE */
+ if (local->hw.conf.phymode == MODE_IEEE80211A)
+ sta->last_txrate += IWL_FIRST_OFDM_RATE;
+
+ IWL_DEBUG_RATE("leave\n");
+}
+
+static void *rs_alloc(struct ieee80211_local *local)
+{
+ return local->hw.priv;
+}
+
+/* rate scale requires free function to be implmented */
+static void rs_free(void *priv)
+{
+ return;
+}
+static void rs_clear(void *priv)
+{
+ return;
+}
+
+
+static void *rs_alloc_sta(void *priv, gfp_t gfp)
+{
+ struct iwl_rate_scale_priv *rs_priv;
+ int i;
+
+ IWL_DEBUG_RATE("enter\n");
+
+ rs_priv = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp);
+ if (!rs_priv) {
+ IWL_DEBUG_RATE("leave: ENOMEM\n");
+ return NULL;
+ }
+
+ spin_lock_init(&rs_priv->lock);
+
+ rs_priv->start_rate = IWL_RATE_INVALID;
+
+ /* default to just 802.11b */
+ rs_priv->expected_tpt = iwl_expected_tpt_b;
+
+ rs_priv->last_partial_flush = jiffies;
+ rs_priv->last_flush = jiffies;
+ rs_priv->flush_time = IWL_RATE_FLUSH;
+ rs_priv->last_tx_packets = 0;
+ rs_priv->ibss_sta_added = 0;
+
+ init_timer(&rs_priv->rate_scale_flush);
+ rs_priv->rate_scale_flush.data = (unsigned long)rs_priv;
+ rs_priv->rate_scale_flush.function = &iwl_bg_rate_scale_flush;
+
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ iwl_clear_window(&rs_priv->win[i]);
+
+ IWL_DEBUG_RATE("leave\n");
+
+ return rs_priv;
+}
+
+static void rs_free_sta(void *priv, void *priv_sta)
+{
+ struct iwl_rate_scale_priv *rs_priv = priv_sta;
+
+ IWL_DEBUG_RATE("enter\n");
+ del_timer_sync(&rs_priv->rate_scale_flush);
+ kfree(rs_priv);
+ IWL_DEBUG_RATE("leave\n");
+}
+
+
+/*
+ * get ieee prev rate from rate scale table.
+ * for A and B mode we need to overright prev
+ * value
+ */
+static int rs_adjust_next_rate(struct iwl_priv *priv, int rate)
+{
+ int next_rate = iwl_get_prev_ieee_rate(rate);
+
+ switch (priv->phymode) {
+ case MODE_IEEE80211A:
+ if (rate == IWL_RATE_12M_INDEX)
+ next_rate = IWL_RATE_9M_INDEX;
+ else if (rate == IWL_RATE_6M_INDEX)
+ next_rate = IWL_RATE_6M_INDEX;
+ break;
+ case MODE_IEEE80211B:
+ if (rate == IWL_RATE_11M_INDEX_TABLE)
+ next_rate = IWL_RATE_5M_INDEX_TABLE;
+ break;
+ default:
+ break;
+ }
+
+ return next_rate;
+}
+/**
+ * rs_tx_status - Update rate control values based on Tx results
+ *
+ * NOTE: Uses iwl_priv->retry_rate for the # of retries attempted by
+ * the hardware for each rate.
+ */
+static void rs_tx_status(void *priv_rate,
+ struct net_device *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_status *tx_resp)
+{
+ u8 retries, current_count;
+ int scale_rate_index, first_index, last_index;
+ unsigned long flags;
+ struct sta_info *sta;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct iwl_rate_scale_priv *rs_priv;
+
+ IWL_DEBUG_RATE("enter\n");
+
+ retries = tx_resp->retry_count;
+
+ first_index = tx_resp->control.tx_rate;
+ if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
+ IWL_DEBUG_RATE("leave: Rate out of bounds: %0x for %d\n",
+ tx_resp->control.tx_rate, first_index);
+ return;
+ }
+
+ sta = sta_info_get(local, hdr->addr1);
+ if (!sta || !sta->rate_ctrl_priv) {
+ if (sta)
+ sta_info_put(sta);
+ IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
+ return;
+ }
+
+ rs_priv = (void *)sta->rate_ctrl_priv;
+
+ rs_priv->tx_packets++;
+
+ scale_rate_index = first_index;
+ last_index = first_index;
+
+ /*
+ * Update the window for each rate. We determine which rates
+ * were Tx'd based on the total number of retries vs. the number
+ * of retries configured for each rate -- currently set to the
+ * priv value 'retry_rate' vs. rate specific
+ *
+ * On exit from this while loop last_index indicates the rate
+ * at which the frame was finally transmitted (or failed if no
+ * ACK)
+ */
+ while (retries > 0) {
+ if (retries < priv->retry_rate) {
+ current_count = retries;
+ last_index = scale_rate_index;
+ } else {
+ current_count = priv->retry_rate;
+ last_index = rs_adjust_next_rate(priv,
+ scale_rate_index);
+ }
+
+ /* Update this rate accounting for as many retries
+ * as was used for it (per current_count) */
+ iwl_collect_tx_data(rs_priv,
+ &rs_priv->win[scale_rate_index],
+ 0, current_count);
+ IWL_DEBUG_RATE("Update rate %d for %d retries.\n",
+ scale_rate_index, current_count);
+
+ retries -= current_count;
+
+ if (retries)
+ scale_rate_index =
+ rs_adjust_next_rate(priv, scale_rate_index);
+ }
+
+
+ /* Update the last index window with success/failure based on ACK */
+ IWL_DEBUG_RATE("Update rate %d with %s.\n",
+ last_index,
+ (tx_resp->flags & IEEE80211_TX_STATUS_ACK) ?
+ "success" : "failure");
+ iwl_collect_tx_data(rs_priv,
+ &rs_priv->win[last_index],
+ tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1);
+
+ /* We updated the rate scale window -- if its been more than
+ * flush_time since the last run, schedule the flush
+ * again */
+ spin_lock_irqsave(&rs_priv->lock, flags);
+
+ if (!rs_priv->flush_pending &&
+ time_after(jiffies, rs_priv->last_partial_flush +
+ rs_priv->flush_time)) {
+
+ rs_priv->flush_pending = 1;
+ mod_timer(&rs_priv->rate_scale_flush,
+ jiffies + rs_priv->flush_time);
+ }
+
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+ sta_info_put(sta);
+
+ IWL_DEBUG_RATE("leave\n");
+
+ return;
+}
+
+static struct ieee80211_rate *iwl_get_lowest_rate(struct ieee80211_local
+ *local)
+{
+ struct ieee80211_hw_mode *mode = local->oper_hw_mode;
+ int i;
+
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *rate = &mode->rates[i];
+
+ if (rate->flags & IEEE80211_RATE_SUPPORTED)
+ return rate;
+ }
+
+ return &mode->rates[0];
+}
+
+static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
+ u8 index, u16 rate_mask, int phymode)
+{
+ u8 high = IWL_RATE_INVALID;
+ u8 low = IWL_RATE_INVALID;
+
+ /* 802.11A walks to the next literal adjascent rate in
+ * the rate table */
+ if (unlikely(phymode == MODE_IEEE80211A)) {
+ int i;
+ u32 mask;
+
+ /* Find the previous rate that is in the rate mask */
+ i = index - 1;
+ for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
+ if (rate_mask & mask) {
+ low = i;
+ break;
+ }
+ }
+
+ /* Find the next rate that is in the rate mask */
+ i = index + 1;
+ for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {
+ if (rate_mask & mask) {
+ high = i;
+ break;
+ }
+ }
+
+ return (high << 8) | low;
+ }
+
+ low = index;
+ while (low != IWL_RATE_INVALID) {
+ if (rs_priv->tgg)
+ low = iwl_rates[low].prev_rs_tgg;
+ else
+ low = iwl_rates[low].prev_rs;
+ if (low == IWL_RATE_INVALID)
+ break;
+ if (rate_mask & (1 << low))
+ break;
+ IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low);
+ }
+
+ high = index;
+ while (high != IWL_RATE_INVALID) {
+ if (rs_priv->tgg)
+ high = iwl_rates[high].next_rs_tgg;
+ else
+ high = iwl_rates[high].next_rs;
+ if (high == IWL_RATE_INVALID)
+ break;
+ if (rate_mask & (1 << high))
+ break;
+ IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high);
+ }
+
+ return (high << 8) | low;
+}
+
+/**
+ * rs_get_rate - find the rate for the requested packet
+ *
+ * Returns the ieee80211_rate structure allocated by the driver.
+ *
+ * The rate control algorithm has no internal mapping between hw_mode's
+ * rate ordering and the rate ordering used by the rate control algorithm.
+ *
+ * The rate control algorithm uses a single table of rates that goes across
+ * the entire A/B/G spectrum vs. being limited to just one particular
+ * hw_mode.
+ *
+ * As such, we can't convert the index obtained below into the hw_mode's
+ * rate table and must reference the driver allocated rate table
+ *
+ */
+static struct ieee80211_rate *rs_get_rate(void *priv_rate,
+ struct net_device *dev,
+ struct sk_buff *skb,
+ struct rate_control_extra *extra)
+{
+ u8 low = IWL_RATE_INVALID;
+ u8 high = IWL_RATE_INVALID;
+ u16 high_low;
+ int index;
+ struct iwl_rate_scale_priv *rs_priv;
+ struct iwl_rate_scale_data *window = NULL;
+ int current_tpt = IWL_INVALID_VALUE;
+ int low_tpt = IWL_INVALID_VALUE;
+ int high_tpt = IWL_INVALID_VALUE;
+ u32 fail_count;
+ s8 scale_action = 0;
+ unsigned long flags;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct sta_info *sta;
+ u16 fc, rate_mask;
+ struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_RATE("enter\n");
+
+ memset(extra, 0, sizeof(*extra));
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
+ (is_multicast_ether_addr(hdr->addr1))) {
+ /* Send management frames and broadcast/multicast data using
+ * lowest rate. */
+ /* TODO: this could probably be improved.. */
+ IWL_DEBUG_RATE("leave: lowest rate (not data or is "
+ "multicast)\n");
+
+ return iwl_get_lowest_rate(local);
+ }
+
+ sta = sta_info_get(local, hdr->addr1);
+ if (!sta || !sta->rate_ctrl_priv) {
+ IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
+ if (sta)
+ sta_info_put(sta);
+ return NULL;
+ }
+
+ rate_mask = sta->supp_rates;
+ index = min(sta->last_txrate & 0xffff, IWL_RATE_COUNT - 1);
+
+ if (priv->phymode == (u8) MODE_IEEE80211A)
+ rate_mask = rate_mask << IWL_FIRST_OFDM_RATE;
+
+ rs_priv = (void *)sta->rate_ctrl_priv;
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ !rs_priv->ibss_sta_added) {
+ u8 sta_id = iwl_hw_find_station(priv, hdr->addr1);
+
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_RATE("LQ: ADD station %s\n",
+ print_mac(mac, hdr->addr1));
+ sta_id = iwl_add_station(priv,
+ hdr->addr1, 0, CMD_ASYNC);
+ }
+ if (sta_id != IWL_INVALID_STATION)
+ rs_priv->ibss_sta_added = 1;
+ }
+
+ spin_lock_irqsave(&rs_priv->lock, flags);
+
+ if (rs_priv->start_rate != IWL_RATE_INVALID) {
+ index = rs_priv->start_rate;
+ rs_priv->start_rate = IWL_RATE_INVALID;
+ }
+
+ window = &(rs_priv->win[index]);
+
+ fail_count = window->counter - window->success_counter;
+
+ if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) &&
+ (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) {
+ window->average_tpt = IWL_INVALID_VALUE;
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+ IWL_DEBUG_RATE("Invalid average_tpt on rate %d: "
+ "counter: %d, success_counter: %d, "
+ "expected_tpt is %sNULL\n",
+ index,
+ window->counter,
+ window->success_counter,
+ rs_priv->expected_tpt ? "not " : "");
+ goto out;
+
+ }
+
+ window->average_tpt = ((window->success_ratio *
+ rs_priv->expected_tpt[index] + 64) / 128);
+ current_tpt = window->average_tpt;
+
+ high_low = iwl_get_adjacent_rate(rs_priv, index, rate_mask,
+ local->hw.conf.phymode);
+ low = high_low & 0xff;
+ high = (high_low >> 8) & 0xff;
+
+ if (low != IWL_RATE_INVALID)
+ low_tpt = rs_priv->win[low].average_tpt;
+
+ if (high != IWL_RATE_INVALID)
+ high_tpt = rs_priv->win[high].average_tpt;
+
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+ scale_action = 1;
+
+ if ((window->success_ratio < IWL_RATE_DECREASE_TH) || !current_tpt) {
+ IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
+ scale_action = -1;
+ } else if ((low_tpt == IWL_INVALID_VALUE) &&
+ (high_tpt == IWL_INVALID_VALUE))
+ scale_action = 1;
+ else if ((low_tpt != IWL_INVALID_VALUE) &&
+ (high_tpt != IWL_INVALID_VALUE)
+ && (low_tpt < current_tpt)
+ && (high_tpt < current_tpt)) {
+ IWL_DEBUG_RATE("No action -- low [%d] & high [%d] < "
+ "current_tpt [%d]\n",
+ low_tpt, high_tpt, current_tpt);
+ scale_action = 0;
+ } else {
+ if (high_tpt != IWL_INVALID_VALUE) {
+ if (high_tpt > current_tpt)
+ scale_action = 1;
+ else {
+ IWL_DEBUG_RATE
+ ("decrease rate because of high tpt\n");
+ scale_action = -1;
+ }
+ } else if (low_tpt != IWL_INVALID_VALUE) {
+ if (low_tpt > current_tpt) {
+ IWL_DEBUG_RATE
+ ("decrease rate because of low tpt\n");
+ scale_action = -1;
+ } else
+ scale_action = 1;
+ }
+ }
+
+ if ((window->success_ratio > IWL_RATE_HIGH_TH) ||
+ (current_tpt > window->average_tpt)) {
+ IWL_DEBUG_RATE("No action -- success_ratio [%d] > HIGH_TH or "
+ "current_tpt [%d] > average_tpt [%d]\n",
+ window->success_ratio,
+ current_tpt, window->average_tpt);
+ scale_action = 0;
+ }
+
+ switch (scale_action) {
+ case -1:
+ if (low != IWL_RATE_INVALID)
+ index = low;
+ break;
+
+ case 1:
+ if (high != IWL_RATE_INVALID)
+ index = high;
+
+ break;
+
+ case 0:
+ default:
+ break;
+ }
+
+ IWL_DEBUG_RATE("Selected %d (action %d) - low %d high %d\n",
+ index, scale_action, low, high);
+
+ out:
+
+ sta->last_txrate = index;
+ if (priv->phymode == (u8) MODE_IEEE80211A)
+ sta->txrate = sta->last_txrate - IWL_FIRST_OFDM_RATE;
+ else
+ sta->txrate = sta->last_txrate;
+
+ sta_info_put(sta);
+
+ IWL_DEBUG_RATE("leave: %d\n", index);
+
+ return &priv->ieee_rates[index];
+}
+
+static struct rate_control_ops rs_ops = {
+ .module = NULL,
+ .name = RS_NAME,
+ .tx_status = rs_tx_status,
+ .get_rate = rs_get_rate,
+ .rate_init = rs_rate_init,
+ .clear = rs_clear,
+ .alloc = rs_alloc,
+ .free = rs_free,
+ .alloc_sta = rs_alloc_sta,
+ .free_sta = rs_free_sta,
+};
+
+int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_rate_scale_priv *rs_priv;
+ struct sta_info *sta;
+ unsigned long flags;
+ int count = 0, i;
+ u32 samples = 0, success = 0, good = 0;
+ unsigned long now = jiffies;
+ u32 max_time = 0;
+
+ sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
+ if (!sta || !sta->rate_ctrl_priv) {
+ if (sta) {
+ sta_info_put(sta);
+ IWL_DEBUG_RATE("leave - no private rate data!\n");
+ } else
+ IWL_DEBUG_RATE("leave - no station!\n");
+ return sprintf(buf, "station %d not found\n", sta_id);
+ }
+
+ rs_priv = (void *)sta->rate_ctrl_priv;
+ spin_lock_irqsave(&rs_priv->lock, flags);
+ i = IWL_RATE_54M_INDEX;
+ while (1) {
+ u64 mask;
+ int j;
+
+ count +=
+ sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2);
+
+ mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
+ for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
+ buf[count++] =
+ (rs_priv->win[i].data & mask) ? '1' : '0';
+
+ samples += rs_priv->win[i].counter;
+ good += rs_priv->win[i].success_counter;
+ success += rs_priv->win[i].success_counter * iwl_rates[i].ieee;
+
+ if (rs_priv->win[i].stamp) {
+ int delta =
+ jiffies_to_msecs(now - rs_priv->win[i].stamp);
+
+ if (delta > max_time)
+ max_time = delta;
+
+ count += sprintf(&buf[count], "%5dms\n", delta);
+ } else
+ buf[count++] = '\n';
+
+ j = iwl_get_prev_ieee_rate(i);
+ if (j == i)
+ break;
+ i = j;
+ }
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+ sta_info_put(sta);
+
+ /* Display the average rate of all samples taken.
+ *
+ * NOTE: We multiple # of samples by 2 since the IEEE measurement
+ * added from iwl_rates is actually 2X the rate */
+ if (samples)
+ count += sprintf(
+ &buf[count],
+ "\nAverage rate is %3d.%02dMbs over last %4dms\n"
+ "%3d%% success (%d good packets over %d tries)\n",
+ success / (2 * samples), (success * 5 / samples) % 10,
+ max_time, good * 100 / samples, good, samples);
+ else
+ count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n");
+
+ return count;
+}
+
+void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
+{
+ struct iwl_priv *priv = hw->priv;
+ s32 rssi = 0;
+ unsigned long flags;
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct iwl_rate_scale_priv *rs_priv;
+ struct sta_info *sta;
+
+ IWL_DEBUG_RATE("enter\n");
+
+ if (!local->rate_ctrl->ops->name ||
+ strcmp(local->rate_ctrl->ops->name, RS_NAME)) {
+ IWL_WARNING("iwl-3945-rs not selected as rate control algo!\n");
+ IWL_DEBUG_RATE("leave - mac80211 picked the wrong RC algo.\n");
+ return;
+ }
+
+ sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
+ if (!sta || !sta->rate_ctrl_priv) {
+ if (sta)
+ sta_info_put(sta);
+ IWL_DEBUG_RATE("leave - no private rate data!\n");
+ return;
+ }
+
+ rs_priv = (void *)sta->rate_ctrl_priv;
+
+ spin_lock_irqsave(&rs_priv->lock, flags);
+
+ rs_priv->tgg = 0;
+ switch (priv->phymode) {
+ case MODE_IEEE80211G:
+ if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) {
+ rs_priv->tgg = 1;
+ rs_priv->expected_tpt = iwl_expected_tpt_g_prot;
+ } else
+ rs_priv->expected_tpt = iwl_expected_tpt_g;
+ break;
+
+ case MODE_IEEE80211A:
+ rs_priv->expected_tpt = iwl_expected_tpt_a;
+ break;
+
+ default:
+ IWL_WARNING("Invalid phymode. Defaulting to 802.11b\n");
+ case MODE_IEEE80211B:
+ rs_priv->expected_tpt = iwl_expected_tpt_b;
+ break;
+ }
+
+ sta_info_put(sta);
+ spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+ rssi = priv->last_rx_rssi;
+ if (rssi == 0)
+ rssi = IWL_MIN_RSSI_VAL;
+
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_RATE, "Network RSSI: %d\n", rssi);
+
+ rs_priv->start_rate = iwl_get_rate_index_by_rssi(rssi, priv->phymode);
+
+ IWL_DEBUG_RATE("leave: rssi %d assign rate index: "
+ "%d (plcp 0x%x)\n", rssi, rs_priv->start_rate,
+ iwl_rates[rs_priv->start_rate].plcp);
+}
+
+void iwl_rate_control_register(struct ieee80211_hw *hw)
+{
+ ieee80211_rate_control_register(&rs_ops);
+}
+
+void iwl_rate_control_unregister(struct ieee80211_hw *hw)
+{
+ ieee80211_rate_control_unregister(&rs_ops);
+}
+
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
new file mode 100644
index 00000000000..bec4d3ffca1
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
@@ -0,0 +1,210 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_3945_rs_h__
+#define __iwl_3945_rs_h__
+
+struct iwl_rate_info {
+ u8 plcp;
+ u8 ieee;
+ u8 prev_ieee; /* previous rate in IEEE speeds */
+ u8 next_ieee; /* next rate in IEEE speeds */
+ u8 prev_rs; /* previous rate used in rs algo */
+ u8 next_rs; /* next rate used in rs algo */
+ u8 prev_rs_tgg; /* previous rate used in TGG rs algo */
+ u8 next_rs_tgg; /* next rate used in TGG rs algo */
+ u8 table_rs_index; /* index in rate scale table cmd */
+ u8 prev_table_rs; /* prev in rate table cmd */
+
+};
+
+enum {
+ IWL_RATE_1M_INDEX = 0,
+ IWL_RATE_2M_INDEX,
+ IWL_RATE_5M_INDEX,
+ IWL_RATE_11M_INDEX,
+ IWL_RATE_6M_INDEX,
+ IWL_RATE_9M_INDEX,
+ IWL_RATE_12M_INDEX,
+ IWL_RATE_18M_INDEX,
+ IWL_RATE_24M_INDEX,
+ IWL_RATE_36M_INDEX,
+ IWL_RATE_48M_INDEX,
+ IWL_RATE_54M_INDEX,
+ IWL_RATE_COUNT,
+ IWL_RATE_INVM_INDEX,
+ IWL_RATE_INVALID = IWL_RATE_INVM_INDEX
+};
+
+enum {
+ IWL_RATE_6M_INDEX_TABLE = 0,
+ IWL_RATE_9M_INDEX_TABLE,
+ IWL_RATE_12M_INDEX_TABLE,
+ IWL_RATE_18M_INDEX_TABLE,
+ IWL_RATE_24M_INDEX_TABLE,
+ IWL_RATE_36M_INDEX_TABLE,
+ IWL_RATE_48M_INDEX_TABLE,
+ IWL_RATE_54M_INDEX_TABLE,
+ IWL_RATE_1M_INDEX_TABLE,
+ IWL_RATE_2M_INDEX_TABLE,
+ IWL_RATE_5M_INDEX_TABLE,
+ IWL_RATE_11M_INDEX_TABLE,
+ IWL_RATE_INVM_INDEX_TABLE = IWL_RATE_INVM_INDEX,
+};
+
+enum {
+ IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
+ IWL_LAST_OFDM_RATE = IWL_RATE_54M_INDEX,
+ IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
+ IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
+};
+
+/* #define vs. enum to keep from defaulting to 'large integer' */
+#define IWL_RATE_6M_MASK (1<<IWL_RATE_6M_INDEX)
+#define IWL_RATE_9M_MASK (1<<IWL_RATE_9M_INDEX)
+#define IWL_RATE_12M_MASK (1<<IWL_RATE_12M_INDEX)
+#define IWL_RATE_18M_MASK (1<<IWL_RATE_18M_INDEX)
+#define IWL_RATE_24M_MASK (1<<IWL_RATE_24M_INDEX)
+#define IWL_RATE_36M_MASK (1<<IWL_RATE_36M_INDEX)
+#define IWL_RATE_48M_MASK (1<<IWL_RATE_48M_INDEX)
+#define IWL_RATE_54M_MASK (1<<IWL_RATE_54M_INDEX)
+#define IWL_RATE_1M_MASK (1<<IWL_RATE_1M_INDEX)
+#define IWL_RATE_2M_MASK (1<<IWL_RATE_2M_INDEX)
+#define IWL_RATE_5M_MASK (1<<IWL_RATE_5M_INDEX)
+#define IWL_RATE_11M_MASK (1<<IWL_RATE_11M_INDEX)
+
+enum {
+ IWL_RATE_6M_PLCP = 13,
+ IWL_RATE_9M_PLCP = 15,
+ IWL_RATE_12M_PLCP = 5,
+ IWL_RATE_18M_PLCP = 7,
+ IWL_RATE_24M_PLCP = 9,
+ IWL_RATE_36M_PLCP = 11,
+ IWL_RATE_48M_PLCP = 1,
+ IWL_RATE_54M_PLCP = 3,
+ IWL_RATE_1M_PLCP = 10,
+ IWL_RATE_2M_PLCP = 20,
+ IWL_RATE_5M_PLCP = 55,
+ IWL_RATE_11M_PLCP = 110,
+};
+
+enum {
+ IWL_RATE_6M_IEEE = 12,
+ IWL_RATE_9M_IEEE = 18,
+ IWL_RATE_12M_IEEE = 24,
+ IWL_RATE_18M_IEEE = 36,
+ IWL_RATE_24M_IEEE = 48,
+ IWL_RATE_36M_IEEE = 72,
+ IWL_RATE_48M_IEEE = 96,
+ IWL_RATE_54M_IEEE = 108,
+ IWL_RATE_1M_IEEE = 2,
+ IWL_RATE_2M_IEEE = 4,
+ IWL_RATE_5M_IEEE = 11,
+ IWL_RATE_11M_IEEE = 22,
+};
+
+#define IWL_CCK_BASIC_RATES_MASK \
+ (IWL_RATE_1M_MASK | \
+ IWL_RATE_2M_MASK)
+
+#define IWL_CCK_RATES_MASK \
+ (IWL_BASIC_RATES_MASK | \
+ IWL_RATE_5M_MASK | \
+ IWL_RATE_11M_MASK)
+
+#define IWL_OFDM_BASIC_RATES_MASK \
+ (IWL_RATE_6M_MASK | \
+ IWL_RATE_12M_MASK | \
+ IWL_RATE_24M_MASK)
+
+#define IWL_OFDM_RATES_MASK \
+ (IWL_OFDM_BASIC_RATES_MASK | \
+ IWL_RATE_9M_MASK | \
+ IWL_RATE_18M_MASK | \
+ IWL_RATE_36M_MASK | \
+ IWL_RATE_48M_MASK | \
+ IWL_RATE_54M_MASK)
+
+#define IWL_BASIC_RATES_MASK \
+ (IWL_OFDM_BASIC_RATES_MASK | \
+ IWL_CCK_BASIC_RATES_MASK)
+
+#define IWL_RATES_MASK ((1<<IWL_RATE_COUNT)-1)
+
+#define IWL_INVALID_VALUE -1
+
+#define IWL_MIN_RSSI_VAL -100
+#define IWL_MAX_RSSI_VAL 0
+
+extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
+
+static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
+{
+ u8 rate = iwl_rates[rate_index].prev_ieee;
+
+ if (rate == IWL_RATE_INVALID)
+ rate = rate_index;
+ return rate;
+}
+
+/**
+ * iwl_fill_rs_info - Fill an output text buffer with the rate representation
+ *
+ * NOTE: This is provided as a quick mechanism for a user to visualize
+ * the performance of the rate control alogirthm and is not meant to be
+ * parsed software.
+ */
+extern int iwl_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
+
+/**
+ * iwl_rate_scale_init - Initialize the rate scale table based on assoc info
+ *
+ * The specific througput table used is based on the type of network
+ * the associated with, including A, B, G, and G w/ TGG protection
+ */
+extern void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
+
+/**
+ * iwl_rate_control_register - Register the rate control algorithm callbacks
+ *
+ * Since the rate control algorithm is hardware specific, there is no need
+ * or reason to place it as a stand alone module. The driver can call
+ * iwl_rate_control_register in order to register the rate control callbacks
+ * with the mac80211 subsystem. This should be performed prior to calling
+ * ieee80211_register_hw
+ *
+ */
+extern void iwl_rate_control_register(struct ieee80211_hw *hw);
+
+/**
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
+ *
+ * This should be called after calling ieee80211_unregister_hw, but before
+ * the driver is unloaded.
+ */
+extern void iwl_rate_control_unregister(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
new file mode 100644
index 00000000000..3a45fe99a83
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -0,0 +1,2311 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <net/mac80211.h>
+
+#include <linux/etherdevice.h>
+
+#define IWL 3945
+
+#include "iwlwifi.h"
+#include "iwl-helpers.h"
+#include "iwl-3945.h"
+#include "iwl-3945-rs.h"
+
+#define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \
+ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
+ IWL_RATE_##r##M_IEEE, \
+ IWL_RATE_##ip##M_INDEX, \
+ IWL_RATE_##in##M_INDEX, \
+ IWL_RATE_##rp##M_INDEX, \
+ IWL_RATE_##rn##M_INDEX, \
+ IWL_RATE_##pp##M_INDEX, \
+ IWL_RATE_##np##M_INDEX, \
+ IWL_RATE_##r##M_INDEX_TABLE, \
+ IWL_RATE_##ip##M_INDEX_TABLE }
+
+/*
+ * Parameter order:
+ * rate, prev rate, next rate, prev tgg rate, next tgg rate
+ *
+ * If there isn't a valid next or previous rate then INV is used which
+ * maps to IWL_RATE_INVALID
+ *
+ */
+const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+ IWL_DECLARE_RATE_INFO(1, INV, 2, INV, 2, INV, 2), /* 1mbps */
+ IWL_DECLARE_RATE_INFO(2, 1, 5, 1, 5, 1, 5), /* 2mbps */
+ IWL_DECLARE_RATE_INFO(5, 2, 6, 2, 11, 2, 11), /*5.5mbps */
+ IWL_DECLARE_RATE_INFO(11, 9, 12, 5, 12, 5, 18), /* 11mbps */
+ IWL_DECLARE_RATE_INFO(6, 5, 9, 5, 11, 5, 11), /* 6mbps */
+ IWL_DECLARE_RATE_INFO(9, 6, 11, 5, 11, 5, 11), /* 9mbps */
+ IWL_DECLARE_RATE_INFO(12, 11, 18, 11, 18, 11, 18), /* 12mbps */
+ IWL_DECLARE_RATE_INFO(18, 12, 24, 12, 24, 11, 24), /* 18mbps */
+ IWL_DECLARE_RATE_INFO(24, 18, 36, 18, 36, 18, 36), /* 24mbps */
+ IWL_DECLARE_RATE_INFO(36, 24, 48, 24, 48, 24, 48), /* 36mbps */
+ IWL_DECLARE_RATE_INFO(48, 36, 54, 36, 54, 36, 54), /* 48mbps */
+ IWL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */
+};
+
+/* 1 = enable the iwl_disable_events() function */
+#define IWL_EVT_DISABLE (0)
+#define IWL_EVT_DISABLE_SIZE (1532/32)
+
+/**
+ * iwl_disable_events - Disable selected events in uCode event log
+ *
+ * Disable an event by writing "1"s into "disable"
+ * bitmap in SRAM. Bit position corresponds to Event # (id/type).
+ * Default values of 0 enable uCode events to be logged.
+ * Use for only special debugging. This function is just a placeholder as-is,
+ * you'll need to provide the special bits! ...
+ * ... and set IWL_EVT_DISABLE to 1. */
+void iwl_disable_events(struct iwl_priv *priv)
+{
+ int rc;
+ int i;
+ u32 base; /* SRAM address of event log header */
+ u32 disable_ptr; /* SRAM address of event-disable bitmap array */
+ u32 array_size; /* # of u32 entries in array */
+ u32 evt_disable[IWL_EVT_DISABLE_SIZE] = {
+ 0x00000000, /* 31 - 0 Event id numbers */
+ 0x00000000, /* 63 - 32 */
+ 0x00000000, /* 95 - 64 */
+ 0x00000000, /* 127 - 96 */
+ 0x00000000, /* 159 - 128 */
+ 0x00000000, /* 191 - 160 */
+ 0x00000000, /* 223 - 192 */
+ 0x00000000, /* 255 - 224 */
+ 0x00000000, /* 287 - 256 */
+ 0x00000000, /* 319 - 288 */
+ 0x00000000, /* 351 - 320 */
+ 0x00000000, /* 383 - 352 */
+ 0x00000000, /* 415 - 384 */
+ 0x00000000, /* 447 - 416 */
+ 0x00000000, /* 479 - 448 */
+ 0x00000000, /* 511 - 480 */
+ 0x00000000, /* 543 - 512 */
+ 0x00000000, /* 575 - 544 */
+ 0x00000000, /* 607 - 576 */
+ 0x00000000, /* 639 - 608 */
+ 0x00000000, /* 671 - 640 */
+ 0x00000000, /* 703 - 672 */
+ 0x00000000, /* 735 - 704 */
+ 0x00000000, /* 767 - 736 */
+ 0x00000000, /* 799 - 768 */
+ 0x00000000, /* 831 - 800 */
+ 0x00000000, /* 863 - 832 */
+ 0x00000000, /* 895 - 864 */
+ 0x00000000, /* 927 - 896 */
+ 0x00000000, /* 959 - 928 */
+ 0x00000000, /* 991 - 960 */
+ 0x00000000, /* 1023 - 992 */
+ 0x00000000, /* 1055 - 1024 */
+ 0x00000000, /* 1087 - 1056 */
+ 0x00000000, /* 1119 - 1088 */
+ 0x00000000, /* 1151 - 1120 */
+ 0x00000000, /* 1183 - 1152 */
+ 0x00000000, /* 1215 - 1184 */
+ 0x00000000, /* 1247 - 1216 */
+ 0x00000000, /* 1279 - 1248 */
+ 0x00000000, /* 1311 - 1280 */
+ 0x00000000, /* 1343 - 1312 */
+ 0x00000000, /* 1375 - 1344 */
+ 0x00000000, /* 1407 - 1376 */
+ 0x00000000, /* 1439 - 1408 */
+ 0x00000000, /* 1471 - 1440 */
+ 0x00000000, /* 1503 - 1472 */
+ };
+
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ if (!iwl_hw_valid_rtc_data_addr(base)) {
+ IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
+ return;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ IWL_WARNING("Can not read from adapter at this time.\n");
+ return;
+ }
+
+ disable_ptr = iwl_read_restricted_mem(priv, base + (4 * sizeof(u32)));
+ array_size = iwl_read_restricted_mem(priv, base + (5 * sizeof(u32)));
+ iwl_release_restricted_access(priv);
+
+ if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) {
+ IWL_DEBUG_INFO("Disabling selected uCode log events at 0x%x\n",
+ disable_ptr);
+ rc = iwl_grab_restricted_access(priv);
+ for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++)
+ iwl_write_restricted_mem(priv,
+ disable_ptr +
+ (i * sizeof(u32)),
+ evt_disable[i]);
+
+ iwl_release_restricted_access(priv);
+ } else {
+ IWL_DEBUG_INFO("Selected uCode log events may be disabled\n");
+ IWL_DEBUG_INFO(" by writing \"1\"s into disable bitmap\n");
+ IWL_DEBUG_INFO(" in SRAM at 0x%x, size %d u32s\n",
+ disable_ptr, array_size);
+ }
+
+}
+
+/**
+ * iwl3945_get_antenna_flags - Get antenna flags for RXON command
+ * @priv: eeprom and antenna fields are used to determine antenna flags
+ *
+ * priv->eeprom is used to determine if antenna AUX/MAIN are reversed
+ * priv->antenna specifies the antenna diversity mode:
+ *
+ * IWL_ANTENNA_DIVERISTY - NIC selects best antenna by itself
+ * IWL_ANTENNA_MAIN - Force MAIN antenna
+ * IWL_ANTENNA_AUX - Force AUX antenna
+ */
+__le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv)
+{
+ switch (priv->antenna) {
+ case IWL_ANTENNA_DIVERSITY:
+ return 0;
+
+ case IWL_ANTENNA_MAIN:
+ if (priv->eeprom.antenna_switch_type)
+ return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK;
+ return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK;
+
+ case IWL_ANTENNA_AUX:
+ if (priv->eeprom.antenna_switch_type)
+ return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK;
+ return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK;
+ }
+
+ /* bad antenna selector value */
+ IWL_ERROR("Bad antenna selector value (0x%x)\n", priv->antenna);
+ return 0; /* "diversity" is default if error */
+}
+
+/*****************************************************************************
+ *
+ * Intel PRO/Wireless 3945ABG/BG Network Connection
+ *
+ * RX handler implementations
+ *
+ * Used by iwl-base.c
+ *
+ *****************************************************************************/
+
+void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n",
+ (int)sizeof(struct iwl_notif_statistics),
+ le32_to_cpu(pkt->len));
+
+ memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics));
+
+ priv->last_statistics_time = jiffies;
+}
+
+static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data,
+ struct iwl_rx_mem_buffer *rxb,
+ struct ieee80211_rx_status *stats,
+ u16 phy_flags)
+{
+ struct ieee80211_hdr *hdr;
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+ struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+ short len = le16_to_cpu(rx_hdr->len);
+
+ /* We received data from the HW, so stop the watchdog */
+ if (unlikely((len + IWL_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {
+ IWL_DEBUG_DROP("Corruption detected!\n");
+ return;
+ }
+
+ /* We only process data packets if the interface is open */
+ if (unlikely(!priv->is_open)) {
+ IWL_DEBUG_DROP_LIMIT
+ ("Dropping packet while interface is not open.\n");
+ return;
+ }
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+ if (iwl_param_hwcrypto)
+ iwl_set_decrypted_flag(priv, rxb->skb,
+ le32_to_cpu(rx_end->status),
+ stats);
+ iwl_handle_data_packet_monitor(priv, rxb, IWL_RX_DATA(pkt),
+ len, stats, phy_flags);
+ return;
+ }
+
+ skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt);
+ /* Set the size of the skb to the size of the frame */
+ skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));
+
+ hdr = (void *)rxb->skb->data;
+
+ if (iwl_param_hwcrypto)
+ iwl_set_decrypted_flag(priv, rxb->skb,
+ le32_to_cpu(rx_end->status), stats);
+
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ rxb->skb = NULL;
+}
+
+static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+ struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+ struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+ struct ieee80211_hdr *header;
+ u16 phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+ u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg);
+ u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff);
+ struct ieee80211_rx_status stats = {
+ .mactime = le64_to_cpu(rx_end->timestamp),
+ .freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)),
+ .channel = le16_to_cpu(rx_hdr->channel),
+ .phymode = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+ MODE_IEEE80211G : MODE_IEEE80211A,
+ .antenna = 0,
+ .rate = rx_hdr->rate,
+ .flag = 0,
+ };
+ u8 network_packet;
+ int snr;
+
+ if ((unlikely(rx_stats->phy_count > 20))) {
+ IWL_DEBUG_DROP
+ ("dsp size out of range [0,20]: "
+ "%d/n", rx_stats->phy_count);
+ return;
+ }
+
+ if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR)
+ || !(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
+ IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", rx_end->status);
+ return;
+ }
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+ iwl3945_handle_data_packet(priv, 1, rxb, &stats, phy_flags);
+ return;
+ }
+
+ /* Convert 3945's rssi indicator to dBm */
+ stats.ssi = rx_stats->rssi - IWL_RSSI_OFFSET;
+
+ /* Set default noise value to -127 */
+ if (priv->last_rx_noise == 0)
+ priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+ /* 3945 provides noise info for OFDM frames only.
+ * sig_avg and noise_diff are measured by the 3945's digital signal
+ * processor (DSP), and indicate linear levels of signal level and
+ * distortion/noise within the packet preamble after
+ * automatic gain control (AGC). sig_avg should stay fairly
+ * constant if the radio's AGC is working well.
+ * Since these values are linear (not dB or dBm), linear
+ * signal-to-noise ratio (SNR) is (sig_avg / noise_diff).
+ * Convert linear SNR to dB SNR, then subtract that from rssi dBm
+ * to obtain noise level in dBm.
+ * Calculate stats.signal (quality indicator in %) based on SNR. */
+ if (rx_stats_noise_diff) {
+ snr = rx_stats_sig_avg / rx_stats_noise_diff;
+ stats.noise = stats.ssi - iwl_calc_db_from_ratio(snr);
+ stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise);
+
+ /* If noise info not available, calculate signal quality indicator (%)
+ * using just the dBm signal level. */
+ } else {
+ stats.noise = priv->last_rx_noise;
+ stats.signal = iwl_calc_sig_qual(stats.ssi, 0);
+ }
+
+
+ IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n",
+ stats.ssi, stats.noise, stats.signal,
+ rx_stats_sig_avg, rx_stats_noise_diff);
+
+ stats.freq = ieee80211chan2mhz(stats.channel);
+
+ /* can be covered by iwl_report_frame() in most cases */
+/* IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */
+
+ header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
+
+ network_packet = iwl_is_network_packet(priv, header);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & IWL_DL_STATS && net_ratelimit())
+ IWL_DEBUG_STATS
+ ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n",
+ network_packet ? '*' : ' ',
+ stats.channel, stats.ssi, stats.ssi,
+ stats.ssi, stats.rate);
+
+ if (iwl_debug_level & (IWL_DL_RX))
+ /* Set "1" to report good data frames in groups of 100 */
+ iwl_report_frame(priv, pkt, header, 1);
+#endif
+
+ if (network_packet) {
+ priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
+ priv->last_tsf = le64_to_cpu(rx_end->timestamp);
+ priv->last_rx_rssi = stats.ssi;
+ priv->last_rx_noise = stats.noise;
+ }
+
+ switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) {
+ case IEEE80211_FTYPE_MGMT:
+ switch (le16_to_cpu(header->frame_control) &
+ IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PROBE_RESP:
+ case IEEE80211_STYPE_BEACON:{
+ /* If this is a beacon or probe response for
+ * our network then cache the beacon
+ * timestamp */
+ if ((((priv->iw_mode == IEEE80211_IF_TYPE_STA)
+ && !compare_ether_addr(header->addr2,
+ priv->bssid)) ||
+ ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ && !compare_ether_addr(header->addr3,
+ priv->bssid)))) {
+ struct ieee80211_mgmt *mgmt =
+ (struct ieee80211_mgmt *)header;
+ __le32 *pos;
+ pos =
+ (__le32 *) & mgmt->u.beacon.
+ timestamp;
+ priv->timestamp0 = le32_to_cpu(pos[0]);
+ priv->timestamp1 = le32_to_cpu(pos[1]);
+ priv->beacon_int = le16_to_cpu(
+ mgmt->u.beacon.beacon_int);
+ if (priv->call_post_assoc_from_beacon &&
+ (priv->iw_mode ==
+ IEEE80211_IF_TYPE_STA))
+ queue_work(priv->workqueue,
+ &priv->post_associate.work);
+
+ priv->call_post_assoc_from_beacon = 0;
+ }
+
+ break;
+ }
+
+ case IEEE80211_STYPE_ACTION:
+ /* TODO: Parse 802.11h frames for CSA... */
+ break;
+
+ /*
+ * TODO: There is no callback function from upper
+ * stack to inform us when associated status. this
+ * work around to sniff assoc_resp management frame
+ * and finish the association process.
+ */
+ case IEEE80211_STYPE_ASSOC_RESP:
+ case IEEE80211_STYPE_REASSOC_RESP:{
+ struct ieee80211_mgmt *mgnt =
+ (struct ieee80211_mgmt *)header;
+ priv->assoc_id = (~((1 << 15) | (1 << 14)) &
+ le16_to_cpu(mgnt->u.
+ assoc_resp.aid));
+ priv->assoc_capability =
+ le16_to_cpu(mgnt->u.assoc_resp.capab_info);
+ if (priv->beacon_int)
+ queue_work(priv->workqueue,
+ &priv->post_associate.work);
+ else
+ priv->call_post_assoc_from_beacon = 1;
+ break;
+ }
+
+ case IEEE80211_STYPE_PROBE_REQ:{
+ DECLARE_MAC_BUF(mac1);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ IWL_DEBUG_DROP
+ ("Dropping (non network): %s"
+ ", %s, %s\n",
+ print_mac(mac1, header->addr1),
+ print_mac(mac2, header->addr2),
+ print_mac(mac3, header->addr3));
+ return;
+ }
+ }
+
+ iwl3945_handle_data_packet(priv, 0, rxb, &stats, phy_flags);
+ break;
+
+ case IEEE80211_FTYPE_CTL:
+ break;
+
+ case IEEE80211_FTYPE_DATA: {
+ DECLARE_MAC_BUF(mac1);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+
+ if (unlikely(is_duplicate_packet(priv, header)))
+ IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
+ print_mac(mac1, header->addr1),
+ print_mac(mac2, header->addr2),
+ print_mac(mac3, header->addr3));
+ else
+ iwl3945_handle_data_packet(priv, 1, rxb, &stats,
+ phy_flags);
+ break;
+ }
+ }
+}
+
+int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
+ dma_addr_t addr, u16 len)
+{
+ int count;
+ u32 pad;
+ struct iwl_tfd_frame *tfd = (struct iwl_tfd_frame *)ptr;
+
+ count = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags));
+ pad = TFD_CTL_PAD_GET(le32_to_cpu(tfd->control_flags));
+
+ if ((count >= NUM_TFD_CHUNKS) || (count < 0)) {
+ IWL_ERROR("Error can not send more than %d chunks\n",
+ NUM_TFD_CHUNKS);
+ return -EINVAL;
+ }
+
+ tfd->pa[count].addr = cpu_to_le32(addr);
+ tfd->pa[count].len = cpu_to_le32(len);
+
+ count++;
+
+ tfd->control_flags = cpu_to_le32(TFD_CTL_COUNT_SET(count) |
+ TFD_CTL_PAD_SET(pad));
+
+ return 0;
+}
+
+/**
+ * iwl_hw_txq_free_tfd - Free one TFD, those at index [txq->q.last_used]
+ *
+ * Does NOT advance any indexes
+ */
+int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
+ struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used];
+ struct pci_dev *dev = priv->pci_dev;
+ int i;
+ int counter;
+
+ /* classify bd */
+ if (txq->q.id == IWL_CMD_QUEUE_NUM)
+ /* nothing to cleanup after for host commands */
+ return 0;
+
+ /* sanity check */
+ counter = TFD_CTL_COUNT_GET(le32_to_cpu(bd->control_flags));
+ if (counter > NUM_TFD_CHUNKS) {
+ IWL_ERROR("Too many chunks: %i\n", counter);
+ /* @todo issue fatal error, it is quite serious situation */
+ return 0;
+ }
+
+ /* unmap chunks if any */
+
+ for (i = 1; i < counter; i++) {
+ pci_unmap_single(dev, le32_to_cpu(bd->pa[i].addr),
+ le32_to_cpu(bd->pa[i].len), PCI_DMA_TODEVICE);
+ if (txq->txb[txq->q.last_used].skb[0]) {
+ struct sk_buff *skb = txq->txb[txq->q.last_used].skb[0];
+ if (txq->txb[txq->q.last_used].skb[0]) {
+ /* Can be called from interrupt context */
+ dev_kfree_skb_any(skb);
+ txq->txb[txq->q.last_used].skb[0] = NULL;
+ }
+ }
+ }
+ return 0;
+}
+
+u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr)
+{
+ int i;
+ int ret = IWL_INVALID_STATION;
+ unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+ if ((priv->stations[i].used) &&
+ (!compare_ether_addr
+ (priv->stations[i].sta.sta.addr, addr))) {
+ ret = i;
+ goto out;
+ }
+
+ IWL_DEBUG_INFO("can not find STA %s (total %d)\n",
+ print_mac(mac, addr), priv->num_stations);
+ out:
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return ret;
+}
+
+/**
+ * iwl_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
+ *
+*/
+void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct ieee80211_tx_control *ctrl,
+ struct ieee80211_hdr *hdr, int sta_id, int tx_id)
+{
+ unsigned long flags;
+ u16 rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1);
+ u16 rate_mask;
+ int rate;
+ u8 rts_retry_limit;
+ u8 data_retry_limit;
+ __le32 tx_flags;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+
+ rate = iwl_rates[rate_index].plcp;
+ tx_flags = cmd->cmd.tx.tx_flags;
+
+ /* We need to figure out how to get the sta->supp_rates while
+ * in this running context; perhaps encoding into ctrl->tx_rate? */
+ rate_mask = IWL_RATES_MASK;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->stations[sta_id].current_rate.rate_n_flags = rate;
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ (sta_id != IWL3945_BROADCAST_ID) &&
+ (sta_id != IWL_MULTICAST_ID))
+ priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate;
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ if (tx_id >= IWL_CMD_QUEUE_NUM)
+ rts_retry_limit = 3;
+ else
+ rts_retry_limit = 7;
+
+ if (ieee80211_is_probe_response(fc)) {
+ data_retry_limit = 3;
+ if (data_retry_limit < rts_retry_limit)
+ rts_retry_limit = data_retry_limit;
+ } else
+ data_retry_limit = IWL_DEFAULT_TX_RETRY;
+
+ if (priv->data_retry_limit != -1)
+ data_retry_limit = priv->data_retry_limit;
+
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_AUTH:
+ case IEEE80211_STYPE_DEAUTH:
+ case IEEE80211_STYPE_ASSOC_REQ:
+ case IEEE80211_STYPE_REASSOC_REQ:
+ if (tx_flags & TX_CMD_FLG_RTS_MSK) {
+ tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ cmd->cmd.tx.rts_retry_limit = rts_retry_limit;
+ cmd->cmd.tx.data_retry_limit = data_retry_limit;
+ cmd->cmd.tx.rate = rate;
+ cmd->cmd.tx.tx_flags = tx_flags;
+
+ /* OFDM */
+ cmd->cmd.tx.supp_rates[0] =
+ ((rate_mask & IWL_OFDM_RATES_MASK) >> IWL_FIRST_OFDM_RATE) & 0xFF;
+
+ /* CCK */
+ cmd->cmd.tx.supp_rates[1] = (rate_mask & 0xF);
+
+ IWL_DEBUG_RATE("Tx sta id: %d, rate: %d (plcp), flags: 0x%4X "
+ "cck/ofdm mask: 0x%x/0x%x\n", sta_id,
+ cmd->cmd.tx.rate, le32_to_cpu(cmd->cmd.tx.tx_flags),
+ cmd->cmd.tx.supp_rates[1], cmd->cmd.tx.supp_rates[0]);
+}
+
+u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
+{
+ unsigned long flags_spin;
+ struct iwl_station_entry *station;
+
+ if (sta_id == IWL_INVALID_STATION)
+ return IWL_INVALID_STATION;
+
+ spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ station = &priv->stations[sta_id];
+
+ station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
+ station->sta.rate_n_flags = cpu_to_le16(tx_rate);
+ station->current_rate.rate_n_flags = tx_rate;
+ station->sta.mode = STA_CONTROL_MODIFY_MSK;
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+
+ iwl_send_add_station(priv, &station->sta, flags);
+ IWL_DEBUG_RATE("SCALE sync station %d to rate %d\n",
+ sta_id, tx_rate);
+ return sta_id;
+}
+
+void iwl_hw_card_show_info(struct iwl_priv *priv)
+{
+ IWL_DEBUG_INFO("3945ABG HW Version %u.%u.%u\n",
+ ((priv->eeprom.board_revision >> 8) & 0x0F),
+ ((priv->eeprom.board_revision >> 8) >> 4),
+ (priv->eeprom.board_revision & 0x00FF));
+
+ IWL_DEBUG_INFO("3945ABG PBA Number %.*s\n",
+ (int)sizeof(priv->eeprom.board_pba_number),
+ priv->eeprom.board_pba_number);
+
+ IWL_DEBUG_INFO("EEPROM_ANTENNA_SWITCH_TYPE is 0x%02X\n",
+ priv->eeprom.antenna_switch_type);
+}
+
+static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ if (!pwr_max) {
+ u32 val;
+
+ rc = pci_read_config_dword(priv->pci_dev,
+ PCI_POWER_SOURCE, &val);
+ if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) {
+ iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
+ iwl_release_restricted_access(priv);
+
+ iwl_poll_bit(priv, CSR_GPIO_IN,
+ CSR_GPIO_IN_VAL_VAUX_PWR_SRC,
+ CSR_GPIO_IN_BIT_AUX_POWER, 5000);
+ } else
+ iwl_release_restricted_access(priv);
+ } else {
+ iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
+
+ iwl_release_restricted_access(priv);
+ iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
+ CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return rc;
+}
+
+static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ iwl_write_restricted(priv, FH_RCSR_RBD_BASE(0), rxq->dma_addr);
+ iwl_write_restricted(priv, FH_RCSR_RPTR_ADDR(0),
+ priv->hw_setting.shared_phys +
+ offsetof(struct iwl_shared, rx_read_ptr[0]));
+ iwl_write_restricted(priv, FH_RCSR_WPTR(0), 0);
+ iwl_write_restricted(priv, FH_RCSR_CONFIG(0),
+ ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE |
+ ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE |
+ ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN |
+ ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 |
+ (RX_QUEUE_SIZE_LOG << ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE) |
+ ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST |
+ (1 << ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH) |
+ ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH);
+
+ /* fake read to flush all prev I/O */
+ iwl_read_restricted(priv, FH_RSSR_CTRL);
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int iwl3945_tx_reset(struct iwl_priv *priv)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ /* bypass mode */
+ iwl_write_restricted_reg(priv, SCD_MODE_REG, 0x2);
+
+ /* RA 0 is active */
+ iwl_write_restricted_reg(priv, SCD_ARASTAT_REG, 0x01);
+
+ /* all 6 fifo are active */
+ iwl_write_restricted_reg(priv, SCD_TXFACT_REG, 0x3f);
+
+ iwl_write_restricted_reg(priv, SCD_SBYP_MODE_1_REG, 0x010000);
+ iwl_write_restricted_reg(priv, SCD_SBYP_MODE_2_REG, 0x030002);
+ iwl_write_restricted_reg(priv, SCD_TXF4MF_REG, 0x000004);
+ iwl_write_restricted_reg(priv, SCD_TXF5MF_REG, 0x000005);
+
+ iwl_write_restricted(priv, FH_TSSR_CBB_BASE,
+ priv->hw_setting.shared_phys);
+
+ iwl_write_restricted(priv, FH_TSSR_MSG_CONFIG,
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON |
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON |
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B |
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON |
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON |
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH |
+ ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH);
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+/**
+ * iwl3945_txq_ctx_reset - Reset TX queue context
+ *
+ * Destroys all DMA structures and initialize them again
+ */
+static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
+{
+ int rc;
+ int txq_id, slots_num;
+
+ iwl_hw_txq_ctx_free(priv);
+
+ /* Tx CMD queue */
+ rc = iwl3945_tx_reset(priv);
+ if (rc)
+ goto error;
+
+ /* Tx queue(s) */
+ for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) {
+ slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+ TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+ rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
+ txq_id);
+ if (rc) {
+ IWL_ERROR("Tx %d queue init failed\n", txq_id);
+ goto error;
+ }
+ }
+
+ return rc;
+
+ error:
+ iwl_hw_txq_ctx_free(priv);
+ return rc;
+}
+
+int iwl_hw_nic_init(struct iwl_priv *priv)
+{
+ u8 rev_id;
+ int rc;
+ unsigned long flags;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+
+ iwl_power_init_handle(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24));
+ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
+
+ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ if (rc < 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_INFO("Failed to init the card\n");
+ return rc;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+ iwl_write_restricted_reg(priv, APMG_CLK_EN_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT |
+ APMG_CLK_VAL_BSM_CLK_RQT);
+ udelay(20);
+ iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Determine HW type */
+ rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);
+ if (rc)
+ return rc;
+ IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id);
+
+ iwl3945_nic_set_pwr_src(priv, 1);
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (rev_id & PCI_CFG_REV_ID_BIT_RTP)
+ IWL_DEBUG_INFO("RTP type \n");
+ else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
+ IWL_DEBUG_INFO("ALM-MB type\n");
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB);
+ } else {
+ IWL_DEBUG_INFO("ALM-MM type\n");
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Initialize the EEPROM */
+ rc = iwl_eeprom_init(priv);
+ if (rc)
+ return rc;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (EEPROM_SKU_CAP_OP_MODE_MRC == priv->eeprom.sku_cap) {
+ IWL_DEBUG_INFO("SKU OP mode is mrc\n");
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC);
+ } else
+ IWL_DEBUG_INFO("SKU OP mode is basic\n");
+
+ if ((priv->eeprom.board_revision & 0xF0) == 0xD0) {
+ IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
+ priv->eeprom.board_revision);
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
+ } else {
+ IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
+ priv->eeprom.board_revision);
+ iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
+ }
+
+ if (priv->eeprom.almgor_m_version <= 1) {
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A);
+ IWL_DEBUG_INFO("Card M type A version is 0x%X\n",
+ priv->eeprom.almgor_m_version);
+ } else {
+ IWL_DEBUG_INFO("Card M type B version is 0x%X\n",
+ priv->eeprom.almgor_m_version);
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE)
+ IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n");
+
+ if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
+ IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n");
+
+ /* Allocate the RX queue, or reset if it is already allocated */
+ if (!rxq->bd) {
+ rc = iwl_rx_queue_alloc(priv);
+ if (rc) {
+ IWL_ERROR("Unable to initialize Rx queue\n");
+ return -ENOMEM;
+ }
+ } else
+ iwl_rx_queue_reset(priv, rxq);
+
+ iwl_rx_replenish(priv);
+
+ iwl3945_rx_init(priv, rxq);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Look at using this instead:
+ rxq->need_update = 1;
+ iwl_rx_queue_update_write_ptr(priv, rxq);
+ */
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+ iwl_write_restricted(priv, FH_RCSR_WPTR(0), rxq->write & ~7);
+ iwl_release_restricted_access(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ rc = iwl3945_txq_ctx_reset(priv);
+ if (rc)
+ return rc;
+
+ set_bit(STATUS_INIT, &priv->status);
+
+ return 0;
+}
+
+/**
+ * iwl_hw_txq_ctx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
+{
+ int txq_id;
+
+ /* Tx queues */
+ for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++)
+ iwl_tx_queue_free(priv, &priv->txq[txq_id]);
+}
+
+void iwl_hw_txq_ctx_stop(struct iwl_priv *priv)
+{
+ int queue;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (iwl_grab_restricted_access(priv)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ iwl_hw_txq_ctx_free(priv);
+ return;
+ }
+
+ /* stop SCD */
+ iwl_write_restricted_reg(priv, SCD_MODE_REG, 0);
+
+ /* reset TFD queues */
+ for (queue = TFD_QUEUE_MIN; queue < TFD_QUEUE_MAX; queue++) {
+ iwl_write_restricted(priv, FH_TCSR_CONFIG(queue), 0x0);
+ iwl_poll_restricted_bit(priv, FH_TSSR_TX_STATUS,
+ ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(queue),
+ 1000);
+ }
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_hw_txq_ctx_free(priv);
+}
+
+int iwl_hw_nic_stop_master(struct iwl_priv *priv)
+{
+ int rc = 0;
+ u32 reg_val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* set stop master bit */
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+
+ reg_val = iwl_read32(priv, CSR_GP_CNTRL);
+
+ if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE ==
+ (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE))
+ IWL_DEBUG_INFO("Card in power save, master is already "
+ "stopped\n");
+ else {
+ rc = iwl_poll_bit(priv, CSR_RESET,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
+ if (rc < 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_INFO("stop master\n");
+
+ return rc;
+}
+
+int iwl_hw_nic_reset(struct iwl_priv *priv)
+{
+ int rc;
+ unsigned long flags;
+
+ iwl_hw_nic_stop_master(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+ rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (!rc) {
+ iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG,
+ APMG_CLK_VAL_BSM_CLK_RQT);
+
+ udelay(10);
+
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+ iwl_write_restricted_reg(priv, APMG_RTC_INT_MSK_REG, 0x0);
+ iwl_write_restricted_reg(priv, APMG_RTC_INT_STT_REG,
+ 0xFFFFFFFF);
+
+ /* enable DMA */
+ iwl_write_restricted_reg(priv, APMG_CLK_EN_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT |
+ APMG_CLK_VAL_BSM_CLK_RQT);
+ udelay(10);
+
+ iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_RESET_REQ);
+ udelay(5);
+ iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_RESET_REQ);
+ iwl_release_restricted_access(priv);
+ }
+
+ /* Clear the 'host command active' bit... */
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+ wake_up_interruptible(&priv->wait_command_queue);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return rc;
+}
+
+/**
+ * iwl_hw_reg_adjust_power_by_temp - return index delta into power gain settings table
+ */
+static int iwl_hw_reg_adjust_power_by_temp(int new_reading, int old_reading)
+{
+ return (new_reading - old_reading) * (-11) / 100;
+}
+
+/**
+ * iwl_hw_reg_temp_out_of_range - Keep temperature in sane range
+ */
+static inline int iwl_hw_reg_temp_out_of_range(int temperature)
+{
+ return (((temperature < -260) || (temperature > 25)) ? 1 : 0);
+}
+
+int iwl_hw_get_temperature(struct iwl_priv *priv)
+{
+ return iwl_read32(priv, CSR_UCODE_DRV_GP2);
+}
+
+/**
+ * iwl_hw_reg_txpower_get_temperature - get current temperature by reading from NIC
+ */
+static int iwl_hw_reg_txpower_get_temperature(struct iwl_priv *priv)
+{
+ int temperature;
+
+ temperature = iwl_hw_get_temperature(priv);
+
+ /* driver's okay range is -260 to +25.
+ * human readable okay range is 0 to +285 */
+ IWL_DEBUG_INFO("Temperature: %d\n", temperature + IWL_TEMP_CONVERT);
+
+ /* handle insane temp reading */
+ if (iwl_hw_reg_temp_out_of_range(temperature)) {
+ IWL_ERROR("Error bad temperature value %d\n", temperature);
+
+ /* if really really hot(?),
+ * substitute the 3rd band/group's temp measured at factory */
+ if (priv->last_temperature > 100)
+ temperature = priv->eeprom.groups[2].temperature;
+ else /* else use most recent "sane" value from driver */
+ temperature = priv->last_temperature;
+ }
+
+ return temperature; /* raw, not "human readable" */
+}
+
+/* Adjust Txpower only if temperature variance is greater than threshold.
+ *
+ * Both are lower than older versions' 9 degrees */
+#define IWL_TEMPERATURE_LIMIT_TIMER 6
+
+/**
+ * is_temp_calib_needed - determines if new calibration is needed
+ *
+ * records new temperature in tx_mgr->temperature.
+ * replaces tx_mgr->last_temperature *only* if calib needed
+ * (assumes caller will actually do the calibration!). */
+static int is_temp_calib_needed(struct iwl_priv *priv)
+{
+ int temp_diff;
+
+ priv->temperature = iwl_hw_reg_txpower_get_temperature(priv);
+ temp_diff = priv->temperature - priv->last_temperature;
+
+ /* get absolute value */
+ if (temp_diff < 0) {
+ IWL_DEBUG_POWER("Getting cooler, delta %d,\n", temp_diff);
+ temp_diff = -temp_diff;
+ } else if (temp_diff == 0)
+ IWL_DEBUG_POWER("Same temp,\n");
+ else
+ IWL_DEBUG_POWER("Getting warmer, delta %d,\n", temp_diff);
+
+ /* if we don't need calibration, *don't* update last_temperature */
+ if (temp_diff < IWL_TEMPERATURE_LIMIT_TIMER) {
+ IWL_DEBUG_POWER("Timed thermal calib not needed\n");
+ return 0;
+ }
+
+ IWL_DEBUG_POWER("Timed thermal calib needed\n");
+
+ /* assume that caller will actually do calib ...
+ * update the "last temperature" value */
+ priv->last_temperature = priv->temperature;
+ return 1;
+}
+
+#define IWL_MAX_GAIN_ENTRIES 78
+#define IWL_CCK_FROM_OFDM_POWER_DIFF -5
+#define IWL_CCK_FROM_OFDM_INDEX_DIFF (10)
+
+/* radio and DSP power table, each step is 1/2 dB.
+ * 1st number is for RF analog gain, 2nd number is for DSP pre-DAC gain. */
+static struct iwl_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = {
+ {
+ {251, 127}, /* 2.4 GHz, highest power */
+ {251, 127},
+ {251, 127},
+ {251, 127},
+ {251, 125},
+ {251, 110},
+ {251, 105},
+ {251, 98},
+ {187, 125},
+ {187, 115},
+ {187, 108},
+ {187, 99},
+ {243, 119},
+ {243, 111},
+ {243, 105},
+ {243, 97},
+ {243, 92},
+ {211, 106},
+ {211, 100},
+ {179, 120},
+ {179, 113},
+ {179, 107},
+ {147, 125},
+ {147, 119},
+ {147, 112},
+ {147, 106},
+ {147, 101},
+ {147, 97},
+ {147, 91},
+ {115, 107},
+ {235, 121},
+ {235, 115},
+ {235, 109},
+ {203, 127},
+ {203, 121},
+ {203, 115},
+ {203, 108},
+ {203, 102},
+ {203, 96},
+ {203, 92},
+ {171, 110},
+ {171, 104},
+ {171, 98},
+ {139, 116},
+ {227, 125},
+ {227, 119},
+ {227, 113},
+ {227, 107},
+ {227, 101},
+ {227, 96},
+ {195, 113},
+ {195, 106},
+ {195, 102},
+ {195, 95},
+ {163, 113},
+ {163, 106},
+ {163, 102},
+ {163, 95},
+ {131, 113},
+ {131, 106},
+ {131, 102},
+ {131, 95},
+ {99, 113},
+ {99, 106},
+ {99, 102},
+ {99, 95},
+ {67, 113},
+ {67, 106},
+ {67, 102},
+ {67, 95},
+ {35, 113},
+ {35, 106},
+ {35, 102},
+ {35, 95},
+ {3, 113},
+ {3, 106},
+ {3, 102},
+ {3, 95} }, /* 2.4 GHz, lowest power */
+ {
+ {251, 127}, /* 5.x GHz, highest power */
+ {251, 120},
+ {251, 114},
+ {219, 119},
+ {219, 101},
+ {187, 113},
+ {187, 102},
+ {155, 114},
+ {155, 103},
+ {123, 117},
+ {123, 107},
+ {123, 99},
+ {123, 92},
+ {91, 108},
+ {59, 125},
+ {59, 118},
+ {59, 109},
+ {59, 102},
+ {59, 96},
+ {59, 90},
+ {27, 104},
+ {27, 98},
+ {27, 92},
+ {115, 118},
+ {115, 111},
+ {115, 104},
+ {83, 126},
+ {83, 121},
+ {83, 113},
+ {83, 105},
+ {83, 99},
+ {51, 118},
+ {51, 111},
+ {51, 104},
+ {51, 98},
+ {19, 116},
+ {19, 109},
+ {19, 102},
+ {19, 98},
+ {19, 93},
+ {171, 113},
+ {171, 107},
+ {171, 99},
+ {139, 120},
+ {139, 113},
+ {139, 107},
+ {139, 99},
+ {107, 120},
+ {107, 113},
+ {107, 107},
+ {107, 99},
+ {75, 120},
+ {75, 113},
+ {75, 107},
+ {75, 99},
+ {43, 120},
+ {43, 113},
+ {43, 107},
+ {43, 99},
+ {11, 120},
+ {11, 113},
+ {11, 107},
+ {11, 99},
+ {131, 107},
+ {131, 99},
+ {99, 120},
+ {99, 113},
+ {99, 107},
+ {99, 99},
+ {67, 120},
+ {67, 113},
+ {67, 107},
+ {67, 99},
+ {35, 120},
+ {35, 113},
+ {35, 107},
+ {35, 99},
+ {3, 120} } /* 5.x GHz, lowest power */
+};
+
+static inline u8 iwl_hw_reg_fix_power_index(int index)
+{
+ if (index < 0)
+ return 0;
+ if (index >= IWL_MAX_GAIN_ENTRIES)
+ return IWL_MAX_GAIN_ENTRIES - 1;
+ return (u8) index;
+}
+
+/* Kick off thermal recalibration check every 60 seconds */
+#define REG_RECALIB_PERIOD (60)
+
+/**
+ * iwl_hw_reg_set_scan_power - Set Tx power for scan probe requests
+ *
+ * Set (in our channel info database) the direct scan Tx power for 1 Mbit (CCK)
+ * or 6 Mbit (OFDM) rates.
+ */
+static void iwl_hw_reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index,
+ s32 rate_index, const s8 *clip_pwrs,
+ struct iwl_channel_info *ch_info,
+ int band_index)
+{
+ struct iwl_scan_power_info *scan_power_info;
+ s8 power;
+ u8 power_index;
+
+ scan_power_info = &ch_info->scan_pwr_info[scan_tbl_index];
+
+ /* use this channel group's 6Mbit clipping/saturation pwr,
+ * but cap at regulatory scan power restriction (set during init
+ * based on eeprom channel data) for this channel. */
+ power = min(ch_info->scan_power, clip_pwrs[IWL_RATE_6M_INDEX_TABLE]);
+
+ /* further limit to user's max power preference.
+ * FIXME: Other spectrum management power limitations do not
+ * seem to apply?? */
+ power = min(power, priv->user_txpower_limit);
+ scan_power_info->requested_power = power;
+
+ /* find difference between new scan *power* and current "normal"
+ * Tx *power* for 6Mb. Use this difference (x2) to adjust the
+ * current "normal" temperature-compensated Tx power *index* for
+ * this rate (1Mb or 6Mb) to yield new temp-compensated scan power
+ * *index*. */
+ power_index = ch_info->power_info[rate_index].power_table_index
+ - (power - ch_info->power_info
+ [IWL_RATE_6M_INDEX_TABLE].requested_power) * 2;
+
+ /* store reference index that we use when adjusting *all* scan
+ * powers. So we can accommodate user (all channel) or spectrum
+ * management (single channel) power changes "between" temperature
+ * feedback compensation procedures.
+ * don't force fit this reference index into gain table; it may be a
+ * negative number. This will help avoid errors when we're at
+ * the lower bounds (highest gains, for warmest temperatures)
+ * of the table. */
+
+ /* don't exceed table bounds for "real" setting */
+ power_index = iwl_hw_reg_fix_power_index(power_index);
+
+ scan_power_info->power_table_index = power_index;
+ scan_power_info->tpc.tx_gain =
+ power_gain_table[band_index][power_index].tx_gain;
+ scan_power_info->tpc.dsp_atten =
+ power_gain_table[band_index][power_index].dsp_atten;
+}
+
+/**
+ * iwl_hw_reg_send_txpower - fill in Tx Power command with gain settings
+ *
+ * Configures power settings for all rates for the current channel,
+ * using values from channel info struct, and send to NIC
+ */
+int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
+{
+ int rate_idx, i;
+ const struct iwl_channel_info *ch_info = NULL;
+ struct iwl_txpowertable_cmd txpower = {
+ .channel = priv->active_rxon.channel,
+ };
+
+ txpower.band = (priv->phymode == MODE_IEEE80211A) ? 0 : 1;
+ ch_info = iwl_get_channel_info(priv,
+ priv->phymode,
+ le16_to_cpu(priv->active_rxon.channel));
+ if (!ch_info) {
+ IWL_ERROR
+ ("Failed to get channel info for channel %d [%d]\n",
+ le16_to_cpu(priv->active_rxon.channel), priv->phymode);
+ return -EINVAL;
+ }
+
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_POWER("Not calling TX_PWR_TABLE_CMD on "
+ "non-Tx channel.\n");
+ return 0;
+ }
+
+ /* fill cmd with power settings for all rates for current channel */
+ /* Fill OFDM rate */
+ for (rate_idx = IWL_FIRST_OFDM_RATE, i = 0;
+ rate_idx <= IWL_LAST_OFDM_RATE; rate_idx++, i++) {
+
+ txpower.power[i].tpc = ch_info->power_info[i].tpc;
+ txpower.power[i].rate = iwl_rates[rate_idx].plcp;
+
+ IWL_DEBUG_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n",
+ le16_to_cpu(txpower.channel),
+ txpower.band,
+ txpower.power[i].tpc.tx_gain,
+ txpower.power[i].tpc.dsp_atten,
+ txpower.power[i].rate);
+ }
+ /* Fill CCK rates */
+ for (rate_idx = IWL_FIRST_CCK_RATE;
+ rate_idx <= IWL_LAST_CCK_RATE; rate_idx++, i++) {
+ txpower.power[i].tpc = ch_info->power_info[i].tpc;
+ txpower.power[i].rate = iwl_rates[rate_idx].plcp;
+
+ IWL_DEBUG_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n",
+ le16_to_cpu(txpower.channel),
+ txpower.band,
+ txpower.power[i].tpc.tx_gain,
+ txpower.power[i].tpc.dsp_atten,
+ txpower.power[i].rate);
+ }
+
+ return iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD,
+ sizeof(struct iwl_txpowertable_cmd), &txpower);
+
+}
+
+/**
+ * iwl_hw_reg_set_new_power - Configures power tables at new levels
+ * @ch_info: Channel to update. Uses power_info.requested_power.
+ *
+ * Replace requested_power and base_power_index ch_info fields for
+ * one channel.
+ *
+ * Called if user or spectrum management changes power preferences.
+ * Takes into account h/w and modulation limitations (clip power).
+ *
+ * This does *not* send anything to NIC, just sets up ch_info for one channel.
+ *
+ * NOTE: reg_compensate_for_temperature_dif() *must* be run after this to
+ * properly fill out the scan powers, and actual h/w gain settings,
+ * and send changes to NIC
+ */
+static int iwl_hw_reg_set_new_power(struct iwl_priv *priv,
+ struct iwl_channel_info *ch_info)
+{
+ struct iwl_channel_power_info *power_info;
+ int power_changed = 0;
+ int i;
+ const s8 *clip_pwrs;
+ int power;
+
+ /* Get this chnlgrp's rate-to-max/clip-powers table */
+ clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers;
+
+ /* Get this channel's rate-to-current-power settings table */
+ power_info = ch_info->power_info;
+
+ /* update OFDM Txpower settings */
+ for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE;
+ i++, ++power_info) {
+ int delta_idx;
+
+ /* limit new power to be no more than h/w capability */
+ power = min(ch_info->curr_txpow, clip_pwrs[i]);
+ if (power == power_info->requested_power)
+ continue;
+
+ /* find difference between old and new requested powers,
+ * update base (non-temp-compensated) power index */
+ delta_idx = (power - power_info->requested_power) * 2;
+ power_info->base_power_index -= delta_idx;
+
+ /* save new requested power value */
+ power_info->requested_power = power;
+
+ power_changed = 1;
+ }
+
+ /* update CCK Txpower settings, based on OFDM 12M setting ...
+ * ... all CCK power settings for a given channel are the *same*. */
+ if (power_changed) {
+ power =
+ ch_info->power_info[IWL_RATE_12M_INDEX_TABLE].
+ requested_power + IWL_CCK_FROM_OFDM_POWER_DIFF;
+
+ /* do all CCK rates' iwl_channel_power_info structures */
+ for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++) {
+ power_info->requested_power = power;
+ power_info->base_power_index =
+ ch_info->power_info[IWL_RATE_12M_INDEX_TABLE].
+ base_power_index + IWL_CCK_FROM_OFDM_INDEX_DIFF;
+ ++power_info;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * iwl_hw_reg_get_ch_txpower_limit - returns new power limit for channel
+ *
+ * NOTE: Returned power limit may be less (but not more) than requested,
+ * based strictly on regulatory (eeprom and spectrum mgt) limitations
+ * (no consideration for h/w clipping limitations).
+ */
+static int iwl_hw_reg_get_ch_txpower_limit(struct iwl_channel_info *ch_info)
+{
+ s8 max_power;
+
+#if 0
+ /* if we're using TGd limits, use lower of TGd or EEPROM */
+ if (ch_info->tgd_data.max_power != 0)
+ max_power = min(ch_info->tgd_data.max_power,
+ ch_info->eeprom.max_power_avg);
+
+ /* else just use EEPROM limits */
+ else
+#endif
+ max_power = ch_info->eeprom.max_power_avg;
+
+ return min(max_power, ch_info->max_power_avg);
+}
+
+/**
+ * iwl_hw_reg_comp_txpower_temp - Compensate for temperature
+ *
+ * Compensate txpower settings of *all* channels for temperature.
+ * This only accounts for the difference between current temperature
+ * and the factory calibration temperatures, and bases the new settings
+ * on the channel's base_power_index.
+ *
+ * If RxOn is "associated", this sends the new Txpower to NIC!
+ */
+static int iwl_hw_reg_comp_txpower_temp(struct iwl_priv *priv)
+{
+ struct iwl_channel_info *ch_info = NULL;
+ int delta_index;
+ const s8 *clip_pwrs; /* array of h/w max power levels for each rate */
+ u8 a_band;
+ u8 rate_index;
+ u8 scan_tbl_index;
+ u8 i;
+ int ref_temp;
+ int temperature = priv->temperature;
+
+ /* set up new Tx power info for each and every channel, 2.4 and 5.x */
+ for (i = 0; i < priv->channel_count; i++) {
+ ch_info = &priv->channel_info[i];
+ a_band = is_channel_a_band(ch_info);
+
+ /* Get this chnlgrp's factory calibration temperature */
+ ref_temp = (s16)priv->eeprom.groups[ch_info->group_index].
+ temperature;
+
+ /* get power index adjustment based on curr and factory
+ * temps */
+ delta_index = iwl_hw_reg_adjust_power_by_temp(temperature,
+ ref_temp);
+
+ /* set tx power value for all rates, OFDM and CCK */
+ for (rate_index = 0; rate_index < IWL_RATE_COUNT;
+ rate_index++) {
+ int power_idx =
+ ch_info->power_info[rate_index].base_power_index;
+
+ /* temperature compensate */
+ power_idx += delta_index;
+
+ /* stay within table range */
+ power_idx = iwl_hw_reg_fix_power_index(power_idx);
+ ch_info->power_info[rate_index].
+ power_table_index = (u8) power_idx;
+ ch_info->power_info[rate_index].tpc =
+ power_gain_table[a_band][power_idx];
+ }
+
+ /* Get this chnlgrp's rate-to-max/clip-powers table */
+ clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers;
+
+ /* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */
+ for (scan_tbl_index = 0;
+ scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) {
+ s32 actual_index = (scan_tbl_index == 0) ?
+ IWL_RATE_1M_INDEX_TABLE : IWL_RATE_6M_INDEX_TABLE;
+ iwl_hw_reg_set_scan_power(priv, scan_tbl_index,
+ actual_index, clip_pwrs,
+ ch_info, a_band);
+ }
+ }
+
+ /* send Txpower command for current channel to ucode */
+ return iwl_hw_reg_send_txpower(priv);
+}
+
+int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
+{
+ struct iwl_channel_info *ch_info;
+ s8 max_power;
+ u8 a_band;
+ u8 i;
+
+ if (priv->user_txpower_limit == power) {
+ IWL_DEBUG_POWER("Requested Tx power same as current "
+ "limit: %ddBm.\n", power);
+ return 0;
+ }
+
+ IWL_DEBUG_POWER("Setting upper limit clamp to %ddBm.\n", power);
+ priv->user_txpower_limit = power;
+
+ /* set up new Tx powers for each and every channel, 2.4 and 5.x */
+
+ for (i = 0; i < priv->channel_count; i++) {
+ ch_info = &priv->channel_info[i];
+ a_band = is_channel_a_band(ch_info);
+
+ /* find minimum power of all user and regulatory constraints
+ * (does not consider h/w clipping limitations) */
+ max_power = iwl_hw_reg_get_ch_txpower_limit(ch_info);
+ max_power = min(power, max_power);
+ if (max_power != ch_info->curr_txpow) {
+ ch_info->curr_txpow = max_power;
+
+ /* this considers the h/w clipping limitations */
+ iwl_hw_reg_set_new_power(priv, ch_info);
+ }
+ }
+
+ /* update txpower settings for all channels,
+ * send to NIC if associated. */
+ is_temp_calib_needed(priv);
+ iwl_hw_reg_comp_txpower_temp(priv);
+
+ return 0;
+}
+
+/* will add 3945 channel switch cmd handling later */
+int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+{
+ return 0;
+}
+
+/**
+ * iwl3945_reg_txpower_periodic - called when time to check our temperature.
+ *
+ * -- reset periodic timer
+ * -- see if temp has changed enough to warrant re-calibration ... if so:
+ * -- correct coeffs for temp (can reset temp timer)
+ * -- save this temp as "last",
+ * -- send new set of gain settings to NIC
+ * NOTE: This should continue working, even when we're not associated,
+ * so we can keep our internal table of scan powers current. */
+void iwl3945_reg_txpower_periodic(struct iwl_priv *priv)
+{
+ /* This will kick in the "brute force"
+ * iwl_hw_reg_comp_txpower_temp() below */
+ if (!is_temp_calib_needed(priv))
+ goto reschedule;
+
+ /* Set up a new set of temp-adjusted TxPowers, send to NIC.
+ * This is based *only* on current temperature,
+ * ignoring any previous power measurements */
+ iwl_hw_reg_comp_txpower_temp(priv);
+
+ reschedule:
+ queue_delayed_work(priv->workqueue,
+ &priv->thermal_periodic, REG_RECALIB_PERIOD * HZ);
+}
+
+void iwl3945_bg_reg_txpower_periodic(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ thermal_periodic.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl3945_reg_txpower_periodic(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+/**
+ * iwl_hw_reg_get_ch_grp_index - find the channel-group index (0-4)
+ * for the channel.
+ *
+ * This function is used when initializing channel-info structs.
+ *
+ * NOTE: These channel groups do *NOT* match the bands above!
+ * These channel groups are based on factory-tested channels;
+ * on A-band, EEPROM's "group frequency" entries represent the top
+ * channel in each group 1-4. Group 5 All B/G channels are in group 0.
+ */
+static u16 iwl_hw_reg_get_ch_grp_index(struct iwl_priv *priv,
+ const struct iwl_channel_info *ch_info)
+{
+ struct iwl_eeprom_txpower_group *ch_grp = &priv->eeprom.groups[0];
+ u8 group;
+ u16 group_index = 0; /* based on factory calib frequencies */
+ u8 grp_channel;
+
+ /* Find the group index for the channel ... don't use index 1(?) */
+ if (is_channel_a_band(ch_info)) {
+ for (group = 1; group < 5; group++) {
+ grp_channel = ch_grp[group].group_channel;
+ if (ch_info->channel <= grp_channel) {
+ group_index = group;
+ break;
+ }
+ }
+ /* group 4 has a few channels *above* its factory cal freq */
+ if (group == 5)
+ group_index = 4;
+ } else
+ group_index = 0; /* 2.4 GHz, group 0 */
+
+ IWL_DEBUG_POWER("Chnl %d mapped to grp %d\n", ch_info->channel,
+ group_index);
+ return group_index;
+}
+
+/**
+ * iwl_hw_reg_get_matched_power_index - Interpolate to get nominal index
+ *
+ * Interpolate to get nominal (i.e. at factory calibration temperature) index
+ * into radio/DSP gain settings table for requested power.
+ */
+static int iwl_hw_reg_get_matched_power_index(struct iwl_priv *priv,
+ s8 requested_power,
+ s32 setting_index, s32 *new_index)
+{
+ const struct iwl_eeprom_txpower_group *chnl_grp = NULL;
+ s32 index0, index1;
+ s32 power = 2 * requested_power;
+ s32 i;
+ const struct iwl_eeprom_txpower_sample *samples;
+ s32 gains0, gains1;
+ s32 res;
+ s32 denominator;
+
+ chnl_grp = &priv->eeprom.groups[setting_index];
+ samples = chnl_grp->samples;
+ for (i = 0; i < 5; i++) {
+ if (power == samples[i].power) {
+ *new_index = samples[i].gain_index;
+ return 0;
+ }
+ }
+
+ if (power > samples[1].power) {
+ index0 = 0;
+ index1 = 1;
+ } else if (power > samples[2].power) {
+ index0 = 1;
+ index1 = 2;
+ } else if (power > samples[3].power) {
+ index0 = 2;
+ index1 = 3;
+ } else {
+ index0 = 3;
+ index1 = 4;
+ }
+
+ denominator = (s32) samples[index1].power - (s32) samples[index0].power;
+ if (denominator == 0)
+ return -EINVAL;
+ gains0 = (s32) samples[index0].gain_index * (1 << 19);
+ gains1 = (s32) samples[index1].gain_index * (1 << 19);
+ res = gains0 + (gains1 - gains0) *
+ ((s32) power - (s32) samples[index0].power) / denominator +
+ (1 << 18);
+ *new_index = res >> 19;
+ return 0;
+}
+
+static void iwl_hw_reg_init_channel_groups(struct iwl_priv *priv)
+{
+ u32 i;
+ s32 rate_index;
+ const struct iwl_eeprom_txpower_group *group;
+
+ IWL_DEBUG_POWER("Initializing factory calib info from EEPROM\n");
+
+ for (i = 0; i < IWL_NUM_TX_CALIB_GROUPS; i++) {
+ s8 *clip_pwrs; /* table of power levels for each rate */
+ s8 satur_pwr; /* saturation power for each chnl group */
+ group = &priv->eeprom.groups[i];
+
+ /* sanity check on factory saturation power value */
+ if (group->saturation_power < 40) {
+ IWL_WARNING("Error: saturation power is %d, "
+ "less than minimum expected 40\n",
+ group->saturation_power);
+ return;
+ }
+
+ /*
+ * Derive requested power levels for each rate, based on
+ * hardware capabilities (saturation power for band).
+ * Basic value is 3dB down from saturation, with further
+ * power reductions for highest 3 data rates. These
+ * backoffs provide headroom for high rate modulation
+ * power peaks, without too much distortion (clipping).
+ */
+ /* we'll fill in this array with h/w max power levels */
+ clip_pwrs = (s8 *) priv->clip_groups[i].clip_powers;
+
+ /* divide factory saturation power by 2 to find -3dB level */
+ satur_pwr = (s8) (group->saturation_power >> 1);
+
+ /* fill in channel group's nominal powers for each rate */
+ for (rate_index = 0;
+ rate_index < IWL_RATE_COUNT; rate_index++, clip_pwrs++) {
+ switch (rate_index) {
+ case IWL_RATE_36M_INDEX_TABLE:
+ if (i == 0) /* B/G */
+ *clip_pwrs = satur_pwr;
+ else /* A */
+ *clip_pwrs = satur_pwr - 5;
+ break;
+ case IWL_RATE_48M_INDEX_TABLE:
+ if (i == 0)
+ *clip_pwrs = satur_pwr - 7;
+ else
+ *clip_pwrs = satur_pwr - 10;
+ break;
+ case IWL_RATE_54M_INDEX_TABLE:
+ if (i == 0)
+ *clip_pwrs = satur_pwr - 9;
+ else
+ *clip_pwrs = satur_pwr - 12;
+ break;
+ default:
+ *clip_pwrs = satur_pwr;
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * iwl3945_txpower_set_from_eeprom - Set channel power info based on EEPROM
+ *
+ * Second pass (during init) to set up priv->channel_info
+ *
+ * Set up Tx-power settings in our channel info database for each VALID
+ * (for this geo/SKU) channel, at all Tx data rates, based on eeprom values
+ * and current temperature.
+ *
+ * Since this is based on current temperature (at init time), these values may
+ * not be valid for very long, but it gives us a starting/default point,
+ * and allows us to active (i.e. using Tx) scan.
+ *
+ * This does *not* write values to NIC, just sets up our internal table.
+ */
+int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
+{
+ struct iwl_channel_info *ch_info = NULL;
+ struct iwl_channel_power_info *pwr_info;
+ int delta_index;
+ u8 rate_index;
+ u8 scan_tbl_index;
+ const s8 *clip_pwrs; /* array of power levels for each rate */
+ u8 gain, dsp_atten;
+ s8 power;
+ u8 pwr_index, base_pwr_index, a_band;
+ u8 i;
+ int temperature;
+
+ /* save temperature reference,
+ * so we can determine next time to calibrate */
+ temperature = iwl_hw_reg_txpower_get_temperature(priv);
+ priv->last_temperature = temperature;
+
+ iwl_hw_reg_init_channel_groups(priv);
+
+ /* initialize Tx power info for each and every channel, 2.4 and 5.x */
+ for (i = 0, ch_info = priv->channel_info; i < priv->channel_count;
+ i++, ch_info++) {
+ a_band = is_channel_a_band(ch_info);
+ if (!is_channel_valid(ch_info))
+ continue;
+
+ /* find this channel's channel group (*not* "band") index */
+ ch_info->group_index =
+ iwl_hw_reg_get_ch_grp_index(priv, ch_info);
+
+ /* Get this chnlgrp's rate->max/clip-powers table */
+ clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers;
+
+ /* calculate power index *adjustment* value according to
+ * diff between current temperature and factory temperature */
+ delta_index = iwl_hw_reg_adjust_power_by_temp(temperature,
+ priv->eeprom.groups[ch_info->group_index].
+ temperature);
+
+ IWL_DEBUG_POWER("Delta index for channel %d: %d [%d]\n",
+ ch_info->channel, delta_index, temperature +
+ IWL_TEMP_CONVERT);
+
+ /* set tx power value for all OFDM rates */
+ for (rate_index = 0; rate_index < IWL_OFDM_RATES;
+ rate_index++) {
+ s32 power_idx;
+ int rc;
+
+ /* use channel group's clip-power table,
+ * but don't exceed channel's max power */
+ s8 pwr = min(ch_info->max_power_avg,
+ clip_pwrs[rate_index]);
+
+ pwr_info = &ch_info->power_info[rate_index];
+
+ /* get base (i.e. at factory-measured temperature)
+ * power table index for this rate's power */
+ rc = iwl_hw_reg_get_matched_power_index(priv, pwr,
+ ch_info->group_index,
+ &power_idx);
+ if (rc) {
+ IWL_ERROR("Invalid power index\n");
+ return rc;
+ }
+ pwr_info->base_power_index = (u8) power_idx;
+
+ /* temperature compensate */
+ power_idx += delta_index;
+
+ /* stay within range of gain table */
+ power_idx = iwl_hw_reg_fix_power_index(power_idx);
+
+ /* fill 1 OFDM rate's iwl_channel_power_info struct */
+ pwr_info->requested_power = pwr;
+ pwr_info->power_table_index = (u8) power_idx;
+ pwr_info->tpc.tx_gain =
+ power_gain_table[a_band][power_idx].tx_gain;
+ pwr_info->tpc.dsp_atten =
+ power_gain_table[a_band][power_idx].dsp_atten;
+ }
+
+ /* set tx power for CCK rates, based on OFDM 12 Mbit settings*/
+ pwr_info = &ch_info->power_info[IWL_RATE_12M_INDEX_TABLE];
+ power = pwr_info->requested_power +
+ IWL_CCK_FROM_OFDM_POWER_DIFF;
+ pwr_index = pwr_info->power_table_index +
+ IWL_CCK_FROM_OFDM_INDEX_DIFF;
+ base_pwr_index = pwr_info->base_power_index +
+ IWL_CCK_FROM_OFDM_INDEX_DIFF;
+
+ /* stay within table range */
+ pwr_index = iwl_hw_reg_fix_power_index(pwr_index);
+ gain = power_gain_table[a_band][pwr_index].tx_gain;
+ dsp_atten = power_gain_table[a_band][pwr_index].dsp_atten;
+
+ /* fill each CCK rate's iwl_channel_power_info structure
+ * NOTE: All CCK-rate Txpwrs are the same for a given chnl!
+ * NOTE: CCK rates start at end of OFDM rates! */
+ for (rate_index = 0;
+ rate_index < IWL_CCK_RATES; rate_index++) {
+ pwr_info = &ch_info->power_info[rate_index+IWL_OFDM_RATES];
+ pwr_info->requested_power = power;
+ pwr_info->power_table_index = pwr_index;
+ pwr_info->base_power_index = base_pwr_index;
+ pwr_info->tpc.tx_gain = gain;
+ pwr_info->tpc.dsp_atten = dsp_atten;
+ }
+
+ /* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */
+ for (scan_tbl_index = 0;
+ scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) {
+ s32 actual_index = (scan_tbl_index == 0) ?
+ IWL_RATE_1M_INDEX_TABLE : IWL_RATE_6M_INDEX_TABLE;
+ iwl_hw_reg_set_scan_power(priv, scan_tbl_index,
+ actual_index, clip_pwrs, ch_info, a_band);
+ }
+ }
+
+ return 0;
+}
+
+int iwl_hw_rxq_stop(struct iwl_priv *priv)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ iwl_write_restricted(priv, FH_RCSR_CONFIG(0), 0);
+ rc = iwl_poll_restricted_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000);
+ if (rc < 0)
+ IWL_ERROR("Can't stop Rx DMA.\n");
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ int rc;
+ unsigned long flags;
+ int txq_id = txq->q.id;
+
+ struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+
+ shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+ iwl_write_restricted(priv, FH_CBCC_CTRL(txq_id), 0);
+ iwl_write_restricted(priv, FH_CBCC_BASE(txq_id), 0);
+
+ iwl_write_restricted(priv, FH_TCSR_CONFIG(txq_id),
+ ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT |
+ ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF |
+ ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD |
+ ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL |
+ ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE);
+ iwl_release_restricted_access(priv);
+
+ /* fake read to flush all prev. writes */
+ iwl_read32(priv, FH_TSSR_CBB_BASE);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+int iwl_hw_get_rx_read(struct iwl_priv *priv)
+{
+ struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+
+ return le32_to_cpu(shared_data->rx_read_ptr[0]);
+}
+
+/**
+ * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table
+ */
+int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
+{
+ int rc, i, index, prev_index;
+ struct iwl_rate_scaling_cmd rate_cmd = {
+ .reserved = {0, 0, 0},
+ };
+ struct iwl_rate_scaling_info *table = rate_cmd.table;
+
+ for (i = 0; i < ARRAY_SIZE(iwl_rates); i++) {
+ index = iwl_rates[i].table_rs_index;
+
+ table[index].rate_n_flags =
+ iwl_hw_set_rate_n_flags(iwl_rates[i].plcp, 0);
+ table[index].try_cnt = priv->retry_rate;
+ prev_index = iwl_get_prev_ieee_rate(i);
+ table[index].next_rate_index = iwl_rates[prev_index].table_rs_index;
+ }
+
+ switch (priv->phymode) {
+ case MODE_IEEE80211A:
+ IWL_DEBUG_RATE("Select A mode rate scale\n");
+ /* If one of the following CCK rates is used,
+ * have it fall back to the 6M OFDM rate */
+ for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++)
+ table[i].next_rate_index = iwl_rates[IWL_FIRST_OFDM_RATE].table_rs_index;
+
+ /* Don't fall back to CCK rates */
+ table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = IWL_RATE_9M_INDEX_TABLE;
+
+ /* Don't drop out of OFDM rates */
+ table[IWL_RATE_6M_INDEX_TABLE].next_rate_index =
+ iwl_rates[IWL_FIRST_OFDM_RATE].table_rs_index;
+ break;
+
+ case MODE_IEEE80211B:
+ IWL_DEBUG_RATE("Select B mode rate scale\n");
+ /* If an OFDM rate is used, have it fall back to the
+ * 1M CCK rates */
+ for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE; i++)
+ table[i].next_rate_index = iwl_rates[IWL_FIRST_CCK_RATE].table_rs_index;
+
+ /* CCK shouldn't fall back to OFDM... */
+ table[IWL_RATE_11M_INDEX_TABLE].next_rate_index = IWL_RATE_5M_INDEX_TABLE;
+ break;
+
+ default:
+ IWL_DEBUG_RATE("Select G mode rate scale\n");
+ break;
+ }
+
+ /* Update the rate scaling for control frame Tx */
+ rate_cmd.table_id = 0;
+ rc = iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
+ &rate_cmd);
+ if (rc)
+ return rc;
+
+ /* Update the rate scaling for data frame Tx */
+ rate_cmd.table_id = 1;
+ return iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
+ &rate_cmd);
+}
+
+int iwl_hw_set_hw_setting(struct iwl_priv *priv)
+{
+ memset((void *)&priv->hw_setting, 0,
+ sizeof(struct iwl_driver_hw_info));
+
+ priv->hw_setting.shared_virt =
+ pci_alloc_consistent(priv->pci_dev,
+ sizeof(struct iwl_shared),
+ &priv->hw_setting.shared_phys);
+
+ if (!priv->hw_setting.shared_virt) {
+ IWL_ERROR("failed to allocate pci memory\n");
+ mutex_unlock(&priv->mutex);
+ return -ENOMEM;
+ }
+
+ priv->hw_setting.ac_queue_count = AC_NUM;
+ priv->hw_setting.rx_buffer_size = IWL_RX_BUF_SIZE;
+ priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd);
+ priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
+ priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
+ priv->hw_setting.cck_flag = 0;
+ priv->hw_setting.max_stations = IWL3945_STATION_COUNT;
+ priv->hw_setting.bcast_sta_id = IWL3945_BROADCAST_ID;
+ return 0;
+}
+
+unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
+ struct iwl_frame *frame, u8 rate)
+{
+ struct iwl_tx_beacon_cmd *tx_beacon_cmd;
+ unsigned int frame_size;
+
+ tx_beacon_cmd = (struct iwl_tx_beacon_cmd *)&frame->u;
+ memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
+
+ tx_beacon_cmd->tx.sta_id = IWL3945_BROADCAST_ID;
+ tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+ frame_size = iwl_fill_beacon_frame(priv,
+ tx_beacon_cmd->frame,
+ BROADCAST_ADDR,
+ sizeof(frame->u) - sizeof(*tx_beacon_cmd));
+
+ BUG_ON(frame_size > MAX_MPDU_SIZE);
+ tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
+
+ tx_beacon_cmd->tx.rate = rate;
+ tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK |
+ TX_CMD_FLG_TSF_MSK);
+
+ /* supp_rates[0] == OFDM start at IWL_FIRST_OFDM_RATE*/
+ tx_beacon_cmd->tx.supp_rates[0] =
+ (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+
+ tx_beacon_cmd->tx.supp_rates[1] =
+ (IWL_CCK_BASIC_RATES_MASK & 0xF);
+
+ return (sizeof(struct iwl_tx_beacon_cmd) + frame_size);
+}
+
+void iwl_hw_rx_handler_setup(struct iwl_priv *priv)
+{
+ priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx;
+}
+
+void iwl_hw_setup_deferred_work(struct iwl_priv *priv)
+{
+ INIT_DELAYED_WORK(&priv->thermal_periodic,
+ iwl3945_bg_reg_txpower_periodic);
+}
+
+void iwl_hw_cancel_deferred_work(struct iwl_priv *priv)
+{
+ cancel_delayed_work(&priv->thermal_periodic);
+}
+
+struct pci_device_id iwl_hw_card_ids[] = {
+ {0x8086, 0x4222, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x8086, 0x4227, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0}
+};
+
+inline int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv)
+{
+ _iwl_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
+ return 0;
+}
+
+MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
new file mode 100644
index 00000000000..813902e9f8c
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_3945_h__
+#define __iwl_3945_h__
+
+/*
+ * Forward declare iwl-3945.c functions for iwl-base.c
+ */
+extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv);
+extern __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv);
+extern int iwl3945_init_hw_rate_table(struct iwl_priv *priv);
+extern void iwl3945_reg_txpower_periodic(struct iwl_priv *priv);
+extern void iwl3945_bg_reg_txpower_periodic(struct work_struct *work);
+extern int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv);
+extern u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
+ u16 tx_rate, u8 flags);
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
new file mode 100644
index 00000000000..99a19ef4c74
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -0,0 +1,581 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_4965_hw_h__
+#define __iwl_4965_hw_h__
+
+#define IWL_RX_BUF_SIZE (4 * 1024)
+#define IWL_MAX_BSM_SIZE BSM_SRAM_SIZE
+#define KDR_RTC_INST_UPPER_BOUND (0x018000)
+#define KDR_RTC_DATA_UPPER_BOUND (0x80A000)
+#define KDR_RTC_INST_SIZE (KDR_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
+#define KDR_RTC_DATA_SIZE (KDR_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
+
+#define IWL_MAX_INST_SIZE KDR_RTC_INST_SIZE
+#define IWL_MAX_DATA_SIZE KDR_RTC_DATA_SIZE
+
+static inline int iwl_hw_valid_rtc_data_addr(u32 addr)
+{
+ return (addr >= RTC_DATA_LOWER_BOUND) &&
+ (addr < KDR_RTC_DATA_UPPER_BOUND);
+}
+
+/********************* START TXPOWER *****************************************/
+enum {
+ HT_IE_EXT_CHANNEL_NONE = 0,
+ HT_IE_EXT_CHANNEL_ABOVE,
+ HT_IE_EXT_CHANNEL_INVALID,
+ HT_IE_EXT_CHANNEL_BELOW,
+ HT_IE_EXT_CHANNEL_MAX
+};
+
+enum {
+ CALIB_CH_GROUP_1 = 0,
+ CALIB_CH_GROUP_2 = 1,
+ CALIB_CH_GROUP_3 = 2,
+ CALIB_CH_GROUP_4 = 3,
+ CALIB_CH_GROUP_5 = 4,
+ CALIB_CH_GROUP_MAX
+};
+
+/* Temperature calibration offset is 3% 0C in Kelvin */
+#define TEMPERATURE_CALIB_KELVIN_OFFSET 8
+#define TEMPERATURE_CALIB_A_VAL 259
+
+#define IWL_TX_POWER_TEMPERATURE_MIN (263)
+#define IWL_TX_POWER_TEMPERATURE_MAX (410)
+
+#define IWL_TX_POWER_TEMPERATURE_OUT_OF_RANGE(t) \
+ (((t) < IWL_TX_POWER_TEMPERATURE_MIN) || \
+ ((t) > IWL_TX_POWER_TEMPERATURE_MAX))
+
+#define IWL_TX_POWER_ILLEGAL_TEMPERATURE (300)
+
+#define IWL_TX_POWER_TEMPERATURE_DIFFERENCE (2)
+
+#define IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION (6)
+
+#define IWL_TX_POWER_TARGET_POWER_MIN (0) /* 0 dBm = 1 milliwatt */
+#define IWL_TX_POWER_TARGET_POWER_MAX (16) /* 16 dBm */
+
+/* timeout equivalent to 3 minutes */
+#define IWL_TX_POWER_TIMELIMIT_NOCALIB 1800000000
+
+#define IWL_TX_POWER_CCK_COMPENSATION (9)
+
+#define MIN_TX_GAIN_INDEX (0)
+#define MIN_TX_GAIN_INDEX_52GHZ_EXT (-9)
+#define MAX_TX_GAIN_INDEX_52GHZ (98)
+#define MIN_TX_GAIN_52GHZ (98)
+#define MAX_TX_GAIN_INDEX_24GHZ (98)
+#define MIN_TX_GAIN_24GHZ (98)
+#define MAX_TX_GAIN (0)
+#define MAX_TX_GAIN_52GHZ_EXT (-9)
+
+#define IWL_TX_POWER_DEFAULT_REGULATORY_24 (34)
+#define IWL_TX_POWER_DEFAULT_REGULATORY_52 (34)
+#define IWL_TX_POWER_REGULATORY_MIN (0)
+#define IWL_TX_POWER_REGULATORY_MAX (34)
+#define IWL_TX_POWER_DEFAULT_SATURATION_24 (38)
+#define IWL_TX_POWER_DEFAULT_SATURATION_52 (38)
+#define IWL_TX_POWER_SATURATION_MIN (20)
+#define IWL_TX_POWER_SATURATION_MAX (50)
+
+/* dv *0.4 = dt; so that 5 degrees temperature diff equals
+ * 12.5 in voltage diff */
+#define IWL_TX_TEMPERATURE_UPDATE_LIMIT 9
+
+#define IWL_INVALID_CHANNEL (0xffffffff)
+#define IWL_TX_POWER_REGITRY_BIT (2)
+
+#define MIN_IWL_TX_POWER_CALIB_DUR (100)
+#define IWL_CCK_FROM_OFDM_POWER_DIFF (-5)
+#define IWL_CCK_FROM_OFDM_INDEX_DIFF (9)
+
+/* Number of entries in the gain table */
+#define POWER_GAIN_NUM_ENTRIES 78
+#define TX_POW_MAX_SESSION_NUM 5
+/* timeout equivalent to 3 minutes */
+#define TX_IWL_TIMELIMIT_NOCALIB 1800000000
+
+/* Kedron TX_CALIB_STATES */
+#define IWL_TX_CALIB_STATE_SEND_TX 0x00000001
+#define IWL_TX_CALIB_WAIT_TX_RESPONSE 0x00000002
+#define IWL_TX_CALIB_ENABLED 0x00000004
+#define IWL_TX_CALIB_XVT_ON 0x00000008
+#define IWL_TX_CALIB_TEMPERATURE_CORRECT 0x00000010
+#define IWL_TX_CALIB_WORKING_WITH_XVT 0x00000020
+#define IWL_TX_CALIB_XVT_PERIODICAL 0x00000040
+
+#define NUM_IWL_TX_CALIB_SETTINS 5 /* Number of tx correction groups */
+
+#define IWL_MIN_POWER_IN_VP_TABLE 1 /* 0.5dBm multiplied by 2 */
+#define IWL_MAX_POWER_IN_VP_TABLE 40 /* 20dBm - multiplied by 2 (because
+ * entries are for each 0.5dBm) */
+#define IWL_STEP_IN_VP_TABLE 1 /* 0.5dB - multiplied by 2 */
+#define IWL_NUM_POINTS_IN_VPTABLE \
+ (1 + IWL_MAX_POWER_IN_VP_TABLE - IWL_MIN_POWER_IN_VP_TABLE)
+
+#define MIN_TX_GAIN_INDEX (0)
+#define MAX_TX_GAIN_INDEX_52GHZ (98)
+#define MIN_TX_GAIN_52GHZ (98)
+#define MAX_TX_GAIN_INDEX_24GHZ (98)
+#define MIN_TX_GAIN_24GHZ (98)
+#define MAX_TX_GAIN (0)
+
+/* First and last channels of all groups */
+#define CALIB_IWL_TX_ATTEN_GR1_FCH 34
+#define CALIB_IWL_TX_ATTEN_GR1_LCH 43
+#define CALIB_IWL_TX_ATTEN_GR2_FCH 44
+#define CALIB_IWL_TX_ATTEN_GR2_LCH 70
+#define CALIB_IWL_TX_ATTEN_GR3_FCH 71
+#define CALIB_IWL_TX_ATTEN_GR3_LCH 124
+#define CALIB_IWL_TX_ATTEN_GR4_FCH 125
+#define CALIB_IWL_TX_ATTEN_GR4_LCH 200
+#define CALIB_IWL_TX_ATTEN_GR5_FCH 1
+#define CALIB_IWL_TX_ATTEN_GR5_LCH 20
+
+
+union iwl_tx_power_dual_stream {
+ struct {
+ u8 radio_tx_gain[2];
+ u8 dsp_predis_atten[2];
+ } s;
+ u32 dw;
+};
+
+/********************* END TXPOWER *****************************************/
+
+/* HT flags */
+#define RXON_FLG_CTRL_CHANNEL_LOC_POS (22)
+#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK __constant_cpu_to_le32(0x1<<22)
+
+#define RXON_FLG_HT_OPERATING_MODE_POS (23)
+
+#define RXON_FLG_HT_PROT_MSK __constant_cpu_to_le32(0x1<<23)
+#define RXON_FLG_FAT_PROT_MSK __constant_cpu_to_le32(0x2<<23)
+
+#define RXON_FLG_CHANNEL_MODE_POS (25)
+#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3<<25)
+#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1<<25)
+#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2<<25)
+
+#define RXON_RX_CHAIN_DRIVER_FORCE_MSK __constant_cpu_to_le16(0x1<<0)
+#define RXON_RX_CHAIN_VALID_MSK __constant_cpu_to_le16(0x7<<1)
+#define RXON_RX_CHAIN_VALID_POS (1)
+#define RXON_RX_CHAIN_FORCE_SEL_MSK __constant_cpu_to_le16(0x7<<4)
+#define RXON_RX_CHAIN_FORCE_SEL_POS (4)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK __constant_cpu_to_le16(0x7<<7)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS (7)
+#define RXON_RX_CHAIN_CNT_MSK __constant_cpu_to_le16(0x3<<10)
+#define RXON_RX_CHAIN_CNT_POS (10)
+#define RXON_RX_CHAIN_MIMO_CNT_MSK __constant_cpu_to_le16(0x3<<12)
+#define RXON_RX_CHAIN_MIMO_CNT_POS (12)
+#define RXON_RX_CHAIN_MIMO_FORCE_MSK __constant_cpu_to_le16(0x1<<14)
+#define RXON_RX_CHAIN_MIMO_FORCE_POS (14)
+
+
+#define MCS_DUP_6M_PLCP 0x20
+
+/* OFDM HT rate masks */
+/* ***************************************** */
+#define R_MCS_6M_MSK 0x1
+#define R_MCS_12M_MSK 0x2
+#define R_MCS_18M_MSK 0x4
+#define R_MCS_24M_MSK 0x8
+#define R_MCS_36M_MSK 0x10
+#define R_MCS_48M_MSK 0x20
+#define R_MCS_54M_MSK 0x40
+#define R_MCS_60M_MSK 0x80
+#define R_MCS_12M_DUAL_MSK 0x100
+#define R_MCS_24M_DUAL_MSK 0x200
+#define R_MCS_36M_DUAL_MSK 0x400
+#define R_MCS_48M_DUAL_MSK 0x800
+
+#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
+#define is_siso(tbl) (((tbl) == LQ_SISO))
+#define is_mimo(tbl) (((tbl) == LQ_MIMO))
+#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
+#define is_a_band(tbl) (((tbl) == LQ_A))
+#define is_g_and(tbl) (((tbl) == LQ_G))
+
+/* Flow Handler Definitions */
+
+/**********************/
+/* Addresses */
+/**********************/
+
+#define FH_MEM_LOWER_BOUND (0x1000)
+#define FH_MEM_UPPER_BOUND (0x1EF0)
+
+#define IWL_FH_REGS_LOWER_BOUND (0x1000)
+#define IWL_FH_REGS_UPPER_BOUND (0x2000)
+
+#define IWL_FH_KW_MEM_ADDR_REG (FH_MEM_LOWER_BOUND + 0x97C)
+
+/* CBBC Area - Circular buffers base address cache pointers table */
+#define FH_MEM_CBBC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0)
+#define FH_MEM_CBBC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xA10)
+/* queues 0 - 15 */
+#define FH_MEM_CBBC_QUEUE(x) (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4)
+
+/* RSCSR Area */
+#define FH_MEM_RSCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xBC0)
+#define FH_MEM_RSCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00)
+#define FH_MEM_RSCSR_CHNL0 (FH_MEM_RSCSR_LOWER_BOUND)
+
+#define FH_RSCSR_CHNL0_STTS_WPTR_REG (FH_MEM_RSCSR_CHNL0)
+#define FH_RSCSR_CHNL0_RBDCB_BASE_REG (FH_MEM_RSCSR_CHNL0 + 0x004)
+#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008)
+
+/* RCSR Area - Registers address map */
+#define FH_MEM_RCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC00)
+#define FH_MEM_RCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xCC0)
+#define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND)
+
+#define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0)
+
+/* RSSR Area - Rx shared ctrl & status registers */
+#define FH_MEM_RSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC40)
+#define FH_MEM_RSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xD00)
+#define FH_MEM_RSSR_SHARED_CTRL_REG (FH_MEM_RSSR_LOWER_BOUND)
+#define FH_MEM_RSSR_RX_STATUS_REG (FH_MEM_RSSR_LOWER_BOUND + 0x004)
+#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV (FH_MEM_RSSR_LOWER_BOUND + 0x008)
+
+/* TCSR */
+#define IWL_FH_TCSR_LOWER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xD00)
+#define IWL_FH_TCSR_UPPER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xE60)
+
+#define IWL_FH_TCSR_CHNL_NUM (7)
+#define IWL_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
+ (IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
+
+/* TSSR Area - Tx shared status registers */
+/* TSSR */
+#define IWL_FH_TSSR_LOWER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xEA0)
+#define IWL_FH_TSSR_UPPER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xEC0)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG (IWL_FH_TSSR_LOWER_BOUND + 0x008)
+#define IWL_FH_TSSR_TX_STATUS_REG (IWL_FH_TSSR_LOWER_BOUND + 0x010)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON (0xFF000000)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON (0x00FF0000)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_64B (0x00000000)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B (0x00000400)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_256B (0x00000800)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_512B (0x00000C00)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON (0x00000100)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON (0x00000080)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH (0x00000020)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH (0x00000005)
+
+#define IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) \
+ ((1 << (_chnl)) << 24)
+#define IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) \
+ ((1 << (_chnl)) << 16)
+
+#define IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \
+ (IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
+ IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
+
+/* TCSR: tx_config register values */
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER (0x00000001)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_ARC (0x00000002)
+
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008)
+
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000)
+
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD (0x00400000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD (0x00800000)
+
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000)
+
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000)
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000)
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003)
+
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR (0x00000001)
+
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20)
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12)
+
+/* RCSR: channel 0 rx_config register defines */
+#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK (0xC0000000) /* bits 30-31 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK (0x00F00000) /* bits 20-23 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK (0x00030000) /* bits 16-17 */
+#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK (0x00001000) /* bit 12 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK (0x00000FF0) /* bit 4-11 */
+
+#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT (20)
+#define FH_RCSR_RX_CONFIG_RB_SIZE_BITSHIFT (16)
+
+/* RCSR: rx_config register values */
+#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000)
+#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000)
+#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000)
+
+#define IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000)
+
+/* RCSR channel 0 config register values */
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000)
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000)
+
+/* RSCSR: defs used in normal mode */
+#define FH_RSCSR_CHNL0_RBDCB_WPTR_MASK (0x00000FFF) /* bits 0-11 */
+
+#define SCD_WIN_SIZE 64
+#define SCD_FRAME_LIMIT 64
+
+/* memory mapped registers */
+#define SCD_START_OFFSET 0xa02c00
+
+#define SCD_SRAM_BASE_ADDR (SCD_START_OFFSET + 0x0)
+#define SCD_EMPTY_BITS (SCD_START_OFFSET + 0x4)
+#define SCD_DRAM_BASE_ADDR (SCD_START_OFFSET + 0x10)
+#define SCD_AIT (SCD_START_OFFSET + 0x18)
+#define SCD_TXFACT (SCD_START_OFFSET + 0x1c)
+#define SCD_QUEUE_WRPTR(x) (SCD_START_OFFSET + 0x24 + (x) * 4)
+#define SCD_QUEUE_RDPTR(x) (SCD_START_OFFSET + 0x64 + (x) * 4)
+#define SCD_SETQUEUENUM (SCD_START_OFFSET + 0xa4)
+#define SCD_SET_TXSTAT_TXED (SCD_START_OFFSET + 0xa8)
+#define SCD_SET_TXSTAT_DONE (SCD_START_OFFSET + 0xac)
+#define SCD_SET_TXSTAT_NOT_SCHD (SCD_START_OFFSET + 0xb0)
+#define SCD_DECREASE_CREDIT (SCD_START_OFFSET + 0xb4)
+#define SCD_DECREASE_SCREDIT (SCD_START_OFFSET + 0xb8)
+#define SCD_LOAD_CREDIT (SCD_START_OFFSET + 0xbc)
+#define SCD_LOAD_SCREDIT (SCD_START_OFFSET + 0xc0)
+#define SCD_BAR (SCD_START_OFFSET + 0xc4)
+#define SCD_BAR_DW0 (SCD_START_OFFSET + 0xc8)
+#define SCD_BAR_DW1 (SCD_START_OFFSET + 0xcc)
+#define SCD_QUEUECHAIN_SEL (SCD_START_OFFSET + 0xd0)
+#define SCD_QUERY_REQ (SCD_START_OFFSET + 0xd8)
+#define SCD_QUERY_RES (SCD_START_OFFSET + 0xdc)
+#define SCD_PENDING_FRAMES (SCD_START_OFFSET + 0xe0)
+#define SCD_INTERRUPT_MASK (SCD_START_OFFSET + 0xe4)
+#define SCD_INTERRUPT_THRESHOLD (SCD_START_OFFSET + 0xe8)
+#define SCD_QUERY_MIN_FRAME_SIZE (SCD_START_OFFSET + 0x100)
+#define SCD_QUEUE_STATUS_BITS(x) (SCD_START_OFFSET + 0x104 + (x) * 4)
+
+/* SRAM structures */
+#define SCD_CONTEXT_DATA_OFFSET 0x380
+#define SCD_TX_STTS_BITMAP_OFFSET 0x400
+#define SCD_TRANSLATE_TBL_OFFSET 0x500
+#define SCD_CONTEXT_QUEUE_OFFSET(x) (SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
+#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
+ ((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
+
+#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \
+ ((1<<(hi))|((1<<(hi))-(1<<(lo))))
+
+
+#define SCD_MODE_REG_BIT_SEARCH_MODE (1<<0)
+#define SCD_MODE_REG_BIT_SBYP_MODE (1<<1)
+
+#define SCD_TXFIFO_POS_TID (0)
+#define SCD_TXFIFO_POS_RA (4)
+#define SCD_QUEUE_STTS_REG_POS_ACTIVE (0)
+#define SCD_QUEUE_STTS_REG_POS_TXF (1)
+#define SCD_QUEUE_STTS_REG_POS_WSL (5)
+#define SCD_QUEUE_STTS_REG_POS_SCD_ACK (8)
+#define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10)
+#define SCD_QUEUE_STTS_REG_MSK (0x0007FC00)
+
+#define SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF)
+
+#define SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0)
+#define SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F)
+#define SCD_QUEUE_CTX_REG1_CREDIT_POS (8)
+#define SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00)
+#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24)
+#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000)
+#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16)
+#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000)
+
+#define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R (0x00000010)
+#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00)
+#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100)
+#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200)
+
+static inline u8 iwl_hw_get_rate(__le32 rate_n_flags)
+{
+ return le32_to_cpu(rate_n_flags) & 0xFF;
+}
+static inline u16 iwl_hw_get_rate_n_flags(__le32 rate_n_flags)
+{
+ return le32_to_cpu(rate_n_flags) & 0xFFFF;
+}
+static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u16 flags)
+{
+ return cpu_to_le32(flags|(u16)rate);
+}
+
+struct iwl_tfd_frame_data {
+ __le32 tb1_addr;
+
+ __le32 val1;
+ /* __le32 ptb1_32_35:4; */
+#define IWL_tb1_addr_hi_POS 0
+#define IWL_tb1_addr_hi_LEN 4
+#define IWL_tb1_addr_hi_SYM val1
+ /* __le32 tb_len1:12; */
+#define IWL_tb1_len_POS 4
+#define IWL_tb1_len_LEN 12
+#define IWL_tb1_len_SYM val1
+ /* __le32 ptb2_0_15:16; */
+#define IWL_tb2_addr_lo16_POS 16
+#define IWL_tb2_addr_lo16_LEN 16
+#define IWL_tb2_addr_lo16_SYM val1
+
+ __le32 val2;
+ /* __le32 ptb2_16_35:20; */
+#define IWL_tb2_addr_hi20_POS 0
+#define IWL_tb2_addr_hi20_LEN 20
+#define IWL_tb2_addr_hi20_SYM val2
+ /* __le32 tb_len2:12; */
+#define IWL_tb2_len_POS 20
+#define IWL_tb2_len_LEN 12
+#define IWL_tb2_len_SYM val2
+} __attribute__ ((packed));
+
+struct iwl_tfd_frame {
+ __le32 val0;
+ /* __le32 rsvd1:24; */
+ /* __le32 num_tbs:5; */
+#define IWL_num_tbs_POS 24
+#define IWL_num_tbs_LEN 5
+#define IWL_num_tbs_SYM val0
+ /* __le32 rsvd2:1; */
+ /* __le32 padding:2; */
+ struct iwl_tfd_frame_data pa[10];
+ __le32 reserved;
+} __attribute__ ((packed));
+
+#define IWL4965_MAX_WIN_SIZE 64
+#define IWL4965_QUEUE_SIZE 256
+#define IWL4965_NUM_FIFOS 7
+#define IWL_MAX_NUM_QUEUES 16
+
+struct iwl4965_queue_byte_cnt_entry {
+ __le16 val;
+ /* __le16 byte_cnt:12; */
+#define IWL_byte_cnt_POS 0
+#define IWL_byte_cnt_LEN 12
+#define IWL_byte_cnt_SYM val
+ /* __le16 rsvd:4; */
+} __attribute__ ((packed));
+
+struct iwl4965_sched_queue_byte_cnt_tbl {
+ struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL4965_QUEUE_SIZE +
+ IWL4965_MAX_WIN_SIZE];
+ u8 dont_care[1024 -
+ (IWL4965_QUEUE_SIZE + IWL4965_MAX_WIN_SIZE) *
+ sizeof(__le16)];
+} __attribute__ ((packed));
+
+/* Base physical address of iwl_shared is provided to SCD_DRAM_BASE_ADDR
+ * and &iwl_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */
+struct iwl_shared {
+ struct iwl4965_sched_queue_byte_cnt_tbl
+ queues_byte_cnt_tbls[IWL_MAX_NUM_QUEUES];
+ __le32 val0;
+
+ /* __le32 rb_closed_stts_rb_num:12; */
+#define IWL_rb_closed_stts_rb_num_POS 0
+#define IWL_rb_closed_stts_rb_num_LEN 12
+#define IWL_rb_closed_stts_rb_num_SYM val0
+ /* __le32 rsrv1:4; */
+ /* __le32 rb_closed_stts_rx_frame_num:12; */
+#define IWL_rb_closed_stts_rx_frame_num_POS 16
+#define IWL_rb_closed_stts_rx_frame_num_LEN 12
+#define IWL_rb_closed_stts_rx_frame_num_SYM val0
+ /* __le32 rsrv2:4; */
+
+ __le32 val1;
+ /* __le32 frame_finished_stts_rb_num:12; */
+#define IWL_frame_finished_stts_rb_num_POS 0
+#define IWL_frame_finished_stts_rb_num_LEN 12
+#define IWL_frame_finished_stts_rb_num_SYM val1
+ /* __le32 rsrv3:4; */
+ /* __le32 frame_finished_stts_rx_frame_num:12; */
+#define IWL_frame_finished_stts_rx_frame_num_POS 16
+#define IWL_frame_finished_stts_rx_frame_num_LEN 12
+#define IWL_frame_finished_stts_rx_frame_num_SYM val1
+ /* __le32 rsrv4:4; */
+
+ __le32 padding1; /* so that allocation will be aligned to 16B */
+ __le32 padding2;
+} __attribute__ ((packed));
+
+#endif /* __iwl_4965_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
new file mode 100644
index 00000000000..8dc78c0bf1f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -0,0 +1,2298 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+#include <net/ieee80211.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#include <linux/workqueue.h>
+
+#define IWL 4965
+
+#include "../net/mac80211/ieee80211_rate.h"
+
+#include "iwlwifi.h"
+#include "iwl-helpers.h"
+
+#define RS_NAME "iwl-4965-rs"
+
+#define NUM_TRY_BEFORE_ANTENNA_TOGGLE 1
+#define IWL_NUMBER_TRY 1
+#define IWL_HT_NUMBER_TRY 3
+
+#define IWL_RATE_MAX_WINDOW 62
+#define IWL_RATE_HIGH_TH 10880
+#define IWL_RATE_MIN_FAILURE_TH 6
+#define IWL_RATE_MIN_SUCCESS_TH 8
+#define IWL_RATE_DECREASE_TH 1920
+#define IWL_RATE_INCREASE_TH 8960
+#define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ) /*2 seconds */
+
+static u8 rs_ht_to_legacy[] = {
+ IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+ IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+ IWL_RATE_6M_INDEX,
+ IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX,
+ IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX,
+ IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX,
+ IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX
+};
+
+struct iwl_rate {
+ u32 rate_n_flags;
+} __attribute__ ((packed));
+
+struct iwl_rate_scale_data {
+ u64 data;
+ s32 success_counter;
+ s32 success_ratio;
+ s32 counter;
+ s32 average_tpt;
+ unsigned long stamp;
+};
+
+struct iwl_scale_tbl_info {
+ enum iwl_table_type lq_type;
+ enum iwl_antenna_type antenna_type;
+ u8 is_SGI;
+ u8 is_fat;
+ u8 is_dup;
+ u8 action;
+ s32 *expected_tpt;
+ struct iwl_rate current_rate;
+ struct iwl_rate_scale_data win[IWL_RATE_COUNT];
+};
+
+struct iwl_rate_scale_priv {
+ u8 active_tbl;
+ u8 enable_counter;
+ u8 stay_in_tbl;
+ u8 search_better_tbl;
+ s32 last_tpt;
+ u32 table_count_limit;
+ u32 max_failure_limit;
+ u32 max_success_limit;
+ u32 table_count;
+ u32 total_failed;
+ u32 total_success;
+ u32 flush_timer;
+ u8 action_counter;
+ u8 antenna;
+ u8 valid_antenna;
+ u8 is_green;
+ u8 is_dup;
+ u8 phymode;
+ u8 ibss_sta_added;
+ u32 supp_rates;
+ u16 active_rate;
+ u16 active_siso_rate;
+ u16 active_mimo_rate;
+ u16 active_rate_basic;
+ struct iwl_link_quality_cmd lq;
+ struct iwl_scale_tbl_info lq_info[LQ_SIZE];
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct dentry *rs_sta_dbgfs_scale_table_file;
+ struct dentry *rs_sta_dbgfs_stats_table_file;
+ struct iwl_rate dbg_fixed;
+ struct iwl_priv *drv;
+#endif
+};
+
+static void rs_rate_scale_perform(struct iwl_priv *priv,
+ struct net_device *dev,
+ struct ieee80211_hdr *hdr,
+ struct sta_info *sta);
+static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
+ struct iwl_rate *tx_mcs,
+ struct iwl_link_quality_cmd *tbl);
+
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
+ struct iwl_rate *mcs, int index);
+#else
+static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
+ struct iwl_rate *mcs, int index)
+{}
+#endif
+static s32 expected_tpt_A[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
+};
+
+static s32 expected_tpt_G[IWL_RATE_COUNT] = {
+ 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 186
+};
+
+static s32 expected_tpt_siso20MHz[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 42, 42, 76, 102, 124, 159, 183, 193, 202
+};
+
+static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211
+};
+
+static s32 expected_tpt_mimo20MHz[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251
+};
+
+static s32 expected_tpt_mimo20MHzSGI[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257
+};
+
+static s32 expected_tpt_siso40MHz[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257
+};
+
+static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264
+};
+
+static s32 expected_tpt_mimo40MHz[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289
+};
+
+static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = {
+ 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
+};
+
+static int iwl_lq_sync_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+ /*We didn't cache the SKB; let the caller free it */
+ return 1;
+}
+
+static inline u8 iwl_rate_get_rate(u32 rate_n_flags)
+{
+ return (u8)(rate_n_flags & 0xFF);
+}
+
+static int rs_send_lq_cmd(struct iwl_priv *priv,
+ struct iwl_link_quality_cmd *lq, u8 flags)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ int i;
+#endif
+ int rc = -1;
+
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_TX_LINK_QUALITY_CMD,
+ .len = sizeof(struct iwl_link_quality_cmd),
+ .meta.flags = flags,
+ .data = lq,
+ };
+
+ if ((lq->sta_id == 0xFF) &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
+ return rc;
+
+ if (lq->sta_id == 0xFF)
+ lq->sta_id = IWL_AP_ID;
+
+ IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);
+ IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
+ lq->general_params.single_stream_ant_msk,
+ lq->general_params.dual_stream_ant_msk);
+#ifdef CONFIG_IWLWIFI_DEBUG
+ for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+ IWL_DEBUG_RATE("lq index %d 0x%X\n",
+ i, lq->rs_table[i].rate_n_flags);
+#endif
+
+ if (flags & CMD_ASYNC)
+ cmd.meta.u.callback = iwl_lq_sync_callback;
+
+ if (iwl_is_associated(priv) && priv->assoc_station_added &&
+ priv->lq_mngr.lq_ready)
+ rc = iwl_send_cmd(priv, &cmd);
+
+ return rc;
+}
+
+static int rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
+{
+ window->data = 0;
+ window->success_counter = 0;
+ window->success_ratio = IWL_INVALID_VALUE;
+ window->counter = 0;
+ window->average_tpt = IWL_INVALID_VALUE;
+ window->stamp = 0;
+
+ return 0;
+}
+
+static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
+ int scale_index, s32 tpt, u32 status)
+{
+ int rc = 0;
+ struct iwl_rate_scale_data *window = NULL;
+ u64 mask;
+ u8 win_size = IWL_RATE_MAX_WINDOW;
+ s32 fail_count;
+
+ if (scale_index < 0)
+ return -1;
+
+ if (scale_index >= IWL_RATE_COUNT)
+ return -1;
+
+ window = &(windows[scale_index]);
+
+ if (window->counter >= win_size) {
+
+ window->counter = win_size - 1;
+ mask = 1;
+ mask = (mask << (win_size - 1));
+ if ((window->data & mask)) {
+ window->data &= ~mask;
+ window->success_counter = window->success_counter - 1;
+ }
+ }
+
+ window->counter = window->counter + 1;
+ mask = window->data;
+ window->data = (mask << 1);
+ if (status != 0) {
+ window->success_counter = window->success_counter + 1;
+ window->data |= 0x1;
+ }
+
+ if (window->counter > 0)
+ window->success_ratio = 128 * (100 * window->success_counter)
+ / window->counter;
+ else
+ window->success_ratio = IWL_INVALID_VALUE;
+
+ fail_count = window->counter - window->success_counter;
+
+ if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
+ (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
+ window->average_tpt = (window->success_ratio * tpt + 64) / 128;
+ else
+ window->average_tpt = IWL_INVALID_VALUE;
+
+ window->stamp = jiffies;
+
+ return rc;
+}
+
+int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate,
+ struct iwl_scale_tbl_info *tbl,
+ int index, u8 use_green)
+{
+ int rc = 0;
+
+ if (is_legacy(tbl->lq_type)) {
+ mcs_rate->rate_n_flags = iwl_rates[index].plcp;
+ if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
+ mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK;
+
+ } else if (is_siso(tbl->lq_type)) {
+ if (index > IWL_LAST_OFDM_RATE)
+ index = IWL_LAST_OFDM_RATE;
+ mcs_rate->rate_n_flags = iwl_rates[index].plcp_siso |
+ RATE_MCS_HT_MSK;
+ } else {
+ if (index > IWL_LAST_OFDM_RATE)
+ index = IWL_LAST_OFDM_RATE;
+ mcs_rate->rate_n_flags = iwl_rates[index].plcp_mimo |
+ RATE_MCS_HT_MSK;
+ }
+
+ switch (tbl->antenna_type) {
+ case ANT_BOTH:
+ mcs_rate->rate_n_flags |= RATE_MCS_ANT_AB_MSK;
+ break;
+ case ANT_MAIN:
+ mcs_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK;
+ break;
+ case ANT_AUX:
+ mcs_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK;
+ break;
+ case ANT_NONE:
+ break;
+ }
+
+ if (is_legacy(tbl->lq_type))
+ return rc;
+
+ if (tbl->is_fat) {
+ if (tbl->is_dup)
+ mcs_rate->rate_n_flags |= RATE_MCS_DUP_MSK;
+ else
+ mcs_rate->rate_n_flags |= RATE_MCS_FAT_MSK;
+ }
+ if (tbl->is_SGI)
+ mcs_rate->rate_n_flags |= RATE_MCS_SGI_MSK;
+
+ if (use_green) {
+ mcs_rate->rate_n_flags |= RATE_MCS_GF_MSK;
+ if (is_siso(tbl->lq_type))
+ mcs_rate->rate_n_flags &= ~RATE_MCS_SGI_MSK;
+ }
+ return rc;
+}
+
+static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate,
+ int phymode, struct iwl_scale_tbl_info *tbl,
+ int *rate_idx)
+{
+ int index;
+ u32 ant_msk;
+
+ index = iwl_rate_index_from_plcp(mcs_rate->rate_n_flags);
+
+ if (index == IWL_RATE_INVALID) {
+ *rate_idx = -1;
+ return -1;
+ }
+ tbl->is_SGI = 0;
+ tbl->is_fat = 0;
+ tbl->is_dup = 0;
+ tbl->antenna_type = ANT_BOTH;
+
+ if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) {
+ ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);
+
+ if (ant_msk == RATE_MCS_ANT_AB_MSK)
+ tbl->lq_type = LQ_NONE;
+ else {
+
+ if (phymode == MODE_IEEE80211A)
+ tbl->lq_type = LQ_A;
+ else
+ tbl->lq_type = LQ_G;
+
+ if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK)
+ tbl->antenna_type = ANT_MAIN;
+ else
+ tbl->antenna_type = ANT_AUX;
+ }
+ *rate_idx = index;
+
+ } else if (iwl_rate_get_rate(mcs_rate->rate_n_flags)
+ <= IWL_RATE_SISO_60M_PLCP) {
+ tbl->lq_type = LQ_SISO;
+
+ ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);
+ if (ant_msk == RATE_MCS_ANT_AB_MSK)
+ tbl->lq_type = LQ_NONE;
+ else {
+ if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK)
+ tbl->antenna_type = ANT_MAIN;
+ else
+ tbl->antenna_type = ANT_AUX;
+ }
+ if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)
+ tbl->is_SGI = 1;
+
+ if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) ||
+ (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK))
+ tbl->is_fat = 1;
+
+ if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)
+ tbl->is_dup = 1;
+
+ *rate_idx = index;
+ } else {
+ tbl->lq_type = LQ_MIMO;
+ if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)
+ tbl->is_SGI = 1;
+
+ if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) ||
+ (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK))
+ tbl->is_fat = 1;
+
+ if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)
+ tbl->is_dup = 1;
+ *rate_idx = index;
+ }
+ return 0;
+}
+
+static inline void rs_toggle_antenna(struct iwl_rate *new_rate,
+ struct iwl_scale_tbl_info *tbl)
+{
+ if (tbl->antenna_type == ANT_AUX) {
+ tbl->antenna_type = ANT_MAIN;
+ new_rate->rate_n_flags &= ~RATE_MCS_ANT_B_MSK;
+ new_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK;
+ } else {
+ tbl->antenna_type = ANT_AUX;
+ new_rate->rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
+ new_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK;
+ }
+}
+
+static inline s8 rs_use_green(struct iwl_priv *priv)
+{
+ s8 rc = 0;
+#ifdef CONFIG_IWLWIFI_HT
+ if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
+ return 0;
+
+ if ((priv->current_assoc_ht.is_green_field) &&
+ !(priv->current_assoc_ht.operating_mode & 0x4))
+ rc = 1;
+#endif /*CONFIG_IWLWIFI_HT */
+ return rc;
+}
+
+/**
+ * rs_get_supported_rates - get the available rates
+ *
+ * if management frame or broadcast frame only return
+ * basic available rates.
+ *
+ */
+static void rs_get_supported_rates(struct iwl_rate_scale_priv *lq_data,
+ struct ieee80211_hdr *hdr,
+ enum iwl_table_type rate_type,
+ u16 *data_rate)
+{
+ if (is_legacy(rate_type))
+ *data_rate = lq_data->active_rate;
+ else {
+ if (is_siso(rate_type))
+ *data_rate = lq_data->active_siso_rate;
+ else
+ *data_rate = lq_data->active_mimo_rate;
+ }
+
+ if (hdr && is_multicast_ether_addr(hdr->addr1) &&
+ lq_data->active_rate_basic)
+ *data_rate = lq_data->active_rate_basic;
+}
+
+static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
+{
+ u8 high = IWL_RATE_INVALID;
+ u8 low = IWL_RATE_INVALID;
+
+ /* 802.11A or ht walks to the next literal adjascent rate in
+ * the rate table */
+ if (is_a_band(rate_type) || !is_legacy(rate_type)) {
+ int i;
+ u32 mask;
+
+ /* Find the previous rate that is in the rate mask */
+ i = index - 1;
+ for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
+ if (rate_mask & mask) {
+ low = i;
+ break;
+ }
+ }
+
+ /* Find the next rate that is in the rate mask */
+ i = index + 1;
+ for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {
+ if (rate_mask & mask) {
+ high = i;
+ break;
+ }
+ }
+
+ return (high << 8) | low;
+ }
+
+ low = index;
+ while (low != IWL_RATE_INVALID) {
+ low = iwl_rates[low].prev_rs;
+ if (low == IWL_RATE_INVALID)
+ break;
+ if (rate_mask & (1 << low))
+ break;
+ IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low);
+ }
+
+ high = index;
+ while (high != IWL_RATE_INVALID) {
+ high = iwl_rates[high].next_rs;
+ if (high == IWL_RATE_INVALID)
+ break;
+ if (rate_mask & (1 << high))
+ break;
+ IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high);
+ }
+
+ return (high << 8) | low;
+}
+
+static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data,
+ struct iwl_scale_tbl_info *tbl, u8 scale_index,
+ u8 ht_possible, struct iwl_rate *mcs_rate)
+{
+ s32 low;
+ u16 rate_mask;
+ u16 high_low;
+ u8 switch_to_legacy = 0;
+ u8 is_green = lq_data->is_green;
+
+ /* check if we need to switch from HT to legacy rates.
+ * assumption is that mandatory rates (1Mbps or 6Mbps)
+ * are always supported (spec demand) */
+ if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
+ switch_to_legacy = 1;
+ scale_index = rs_ht_to_legacy[scale_index];
+ if (lq_data->phymode == MODE_IEEE80211A)
+ tbl->lq_type = LQ_A;
+ else
+ tbl->lq_type = LQ_G;
+
+ if ((tbl->antenna_type == ANT_BOTH) ||
+ (tbl->antenna_type == ANT_NONE))
+ tbl->antenna_type = ANT_MAIN;
+
+ tbl->is_fat = 0;
+ tbl->is_SGI = 0;
+ }
+
+ rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask);
+
+ /* mask with station rate restriction */
+ if (is_legacy(tbl->lq_type)) {
+ if (lq_data->phymode == (u8) MODE_IEEE80211A)
+ rate_mask = (u16)(rate_mask &
+ (lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
+ else
+ rate_mask = (u16)(rate_mask & lq_data->supp_rates);
+ }
+
+ /* if we did switched from HT to legacy check current rate */
+ if ((switch_to_legacy) &&
+ (rate_mask & (1 << scale_index))) {
+ rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
+ return 0;
+ }
+
+ high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type);
+ low = high_low & 0xff;
+
+ if (low != IWL_RATE_INVALID)
+ rs_mcs_from_tbl(mcs_rate, tbl, low, is_green);
+ else
+ rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
+
+ return 0;
+}
+
+static void rs_tx_status(void *priv_rate,
+ struct net_device *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_status *tx_resp)
+{
+ int status;
+ u8 retries;
+ int rs_index, index = 0;
+ struct iwl_rate_scale_priv *lq;
+ struct iwl_link_quality_cmd *table;
+ struct sta_info *sta;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct iwl_rate_scale_data *window = NULL;
+ struct iwl_rate_scale_data *search_win = NULL;
+ struct iwl_rate tx_mcs;
+ struct iwl_scale_tbl_info tbl_type;
+ struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
+ u8 active_index = 0;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ s32 tpt = 0;
+
+ IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n");
+
+ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
+ return;
+
+ retries = tx_resp->retry_count;
+
+ if (retries > 15)
+ retries = 15;
+
+
+ sta = sta_info_get(local, hdr->addr1);
+
+ if (!sta || !sta->rate_ctrl_priv) {
+ if (sta)
+ sta_info_put(sta);
+ return;
+ }
+
+ lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+
+ if (!priv->lq_mngr.lq_ready)
+ return;
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added)
+ return;
+
+ table = &lq->lq;
+ active_index = lq->active_tbl;
+
+ lq->antenna = (lq->valid_antenna & local->hw.conf.antenna_sel_tx);
+ if (!lq->antenna)
+ lq->antenna = lq->valid_antenna;
+
+ lq->antenna = lq->valid_antenna;
+ curr_tbl = &(lq->lq_info[active_index]);
+ search_tbl = &(lq->lq_info[(1 - active_index)]);
+ window = (struct iwl_rate_scale_data *)
+ &(curr_tbl->win[0]);
+ search_win = (struct iwl_rate_scale_data *)
+ &(search_tbl->win[0]);
+
+ tx_mcs.rate_n_flags = tx_resp->control.tx_rate;
+
+ rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
+ &tbl_type, &rs_index);
+ if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) {
+ IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n",
+ rs_index, tx_mcs.rate_n_flags);
+ sta_info_put(sta);
+ return;
+ }
+
+ if (retries &&
+ (tx_mcs.rate_n_flags !=
+ le32_to_cpu(table->rs_table[0].rate_n_flags))) {
+ IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n",
+ tx_mcs.rate_n_flags,
+ le32_to_cpu(table->rs_table[0].rate_n_flags));
+ sta_info_put(sta);
+ return;
+ }
+
+ while (retries) {
+ tx_mcs.rate_n_flags =
+ le32_to_cpu(table->rs_table[index].rate_n_flags);
+ rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
+ &tbl_type, &rs_index);
+
+ if ((tbl_type.lq_type == search_tbl->lq_type) &&
+ (tbl_type.antenna_type == search_tbl->antenna_type) &&
+ (tbl_type.is_SGI == search_tbl->is_SGI)) {
+ if (search_tbl->expected_tpt)
+ tpt = search_tbl->expected_tpt[rs_index];
+ else
+ tpt = 0;
+ rs_collect_tx_data(search_win,
+ rs_index, tpt, 0);
+ } else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
+ (tbl_type.antenna_type == curr_tbl->antenna_type) &&
+ (tbl_type.is_SGI == curr_tbl->is_SGI)) {
+ if (curr_tbl->expected_tpt)
+ tpt = curr_tbl->expected_tpt[rs_index];
+ else
+ tpt = 0;
+ rs_collect_tx_data(window, rs_index, tpt, 0);
+ }
+ if (lq->stay_in_tbl)
+ lq->total_failed++;
+ --retries;
+ index++;
+
+ }
+
+ if (!tx_resp->retry_count)
+ tx_mcs.rate_n_flags = tx_resp->control.tx_rate;
+ else
+ tx_mcs.rate_n_flags =
+ le32_to_cpu(table->rs_table[index].rate_n_flags);
+
+ rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
+ &tbl_type, &rs_index);
+
+ if (tx_resp->flags & IEEE80211_TX_STATUS_ACK)
+ status = 1;
+ else
+ status = 0;
+
+ if ((tbl_type.lq_type == search_tbl->lq_type) &&
+ (tbl_type.antenna_type == search_tbl->antenna_type) &&
+ (tbl_type.is_SGI == search_tbl->is_SGI)) {
+ if (search_tbl->expected_tpt)
+ tpt = search_tbl->expected_tpt[rs_index];
+ else
+ tpt = 0;
+ rs_collect_tx_data(search_win,
+ rs_index, tpt, status);
+ } else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
+ (tbl_type.antenna_type == curr_tbl->antenna_type) &&
+ (tbl_type.is_SGI == curr_tbl->is_SGI)) {
+ if (curr_tbl->expected_tpt)
+ tpt = curr_tbl->expected_tpt[rs_index];
+ else
+ tpt = 0;
+ rs_collect_tx_data(window, rs_index, tpt, status);
+ }
+
+ if (lq->stay_in_tbl) {
+ if (status)
+ lq->total_success++;
+ else
+ lq->total_failed++;
+ }
+
+ rs_rate_scale_perform(priv, dev, hdr, sta);
+ sta_info_put(sta);
+ return;
+}
+
+static u8 rs_is_ant_connected(u8 valid_antenna,
+ enum iwl_antenna_type antenna_type)
+{
+ if (antenna_type == ANT_AUX)
+ return ((valid_antenna & 0x2) ? 1:0);
+ else if (antenna_type == ANT_MAIN)
+ return ((valid_antenna & 0x1) ? 1:0);
+ else if (antenna_type == ANT_BOTH) {
+ if ((valid_antenna & 0x3) == 0x3)
+ return 1;
+ else
+ return 0;
+ }
+
+ return 1;
+}
+
+static u8 rs_is_other_ant_connected(u8 valid_antenna,
+ enum iwl_antenna_type antenna_type)
+{
+ if (antenna_type == ANT_AUX)
+ return (rs_is_ant_connected(valid_antenna, ANT_MAIN));
+ else
+ return (rs_is_ant_connected(valid_antenna, ANT_AUX));
+
+ return 0;
+}
+
+static void rs_set_stay_in_table(u8 is_legacy,
+ struct iwl_rate_scale_priv *lq_data)
+{
+ IWL_DEBUG_HT("we are staying in the same table\n");
+ lq_data->stay_in_tbl = 1;
+ if (is_legacy) {
+ lq_data->table_count_limit = IWL_LEGACY_TABLE_COUNT;
+ lq_data->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
+ lq_data->max_success_limit = IWL_LEGACY_TABLE_COUNT;
+ } else {
+ lq_data->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
+ lq_data->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
+ lq_data->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
+ }
+ lq_data->table_count = 0;
+ lq_data->total_failed = 0;
+ lq_data->total_success = 0;
+}
+
+static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data,
+ struct iwl_scale_tbl_info *tbl)
+{
+ if (is_legacy(tbl->lq_type)) {
+ if (!is_a_band(tbl->lq_type))
+ tbl->expected_tpt = expected_tpt_G;
+ else
+ tbl->expected_tpt = expected_tpt_A;
+ } else if (is_siso(tbl->lq_type)) {
+ if (tbl->is_fat && !lq_data->is_dup)
+ if (tbl->is_SGI)
+ tbl->expected_tpt = expected_tpt_siso40MHzSGI;
+ else
+ tbl->expected_tpt = expected_tpt_siso40MHz;
+ else if (tbl->is_SGI)
+ tbl->expected_tpt = expected_tpt_siso20MHzSGI;
+ else
+ tbl->expected_tpt = expected_tpt_siso20MHz;
+
+ } else if (is_mimo(tbl->lq_type)) {
+ if (tbl->is_fat && !lq_data->is_dup)
+ if (tbl->is_SGI)
+ tbl->expected_tpt = expected_tpt_mimo40MHzSGI;
+ else
+ tbl->expected_tpt = expected_tpt_mimo40MHz;
+ else if (tbl->is_SGI)
+ tbl->expected_tpt = expected_tpt_mimo20MHzSGI;
+ else
+ tbl->expected_tpt = expected_tpt_mimo20MHz;
+ } else
+ tbl->expected_tpt = expected_tpt_G;
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+static s32 rs_get_best_rate(struct iwl_priv *priv,
+ struct iwl_rate_scale_priv *lq_data,
+ struct iwl_scale_tbl_info *tbl,
+ u16 rate_mask, s8 index, s8 rate)
+{
+ struct iwl_scale_tbl_info *active_tbl =
+ &(lq_data->lq_info[lq_data->active_tbl]);
+ s32 new_rate, high, low, start_hi;
+ s32 active_sr = active_tbl->win[index].success_ratio;
+ s32 *tpt_tbl = tbl->expected_tpt;
+ s32 active_tpt = active_tbl->expected_tpt[index];
+ u16 high_low;
+
+ new_rate = high = low = start_hi = IWL_RATE_INVALID;
+
+ for (; ;) {
+ high_low = rs_get_adjacent_rate(rate, rate_mask, tbl->lq_type);
+
+ low = high_low & 0xff;
+ high = (high_low >> 8) & 0xff;
+
+ if ((((100 * tpt_tbl[rate]) > lq_data->last_tpt) &&
+ ((active_sr > IWL_RATE_DECREASE_TH) &&
+ (active_sr <= IWL_RATE_HIGH_TH) &&
+ (tpt_tbl[rate] <= active_tpt))) ||
+ ((active_sr >= IWL_RATE_SCALE_SWITCH) &&
+ (tpt_tbl[rate] > active_tpt))) {
+
+ if (start_hi != IWL_RATE_INVALID) {
+ new_rate = start_hi;
+ break;
+ }
+ new_rate = rate;
+ if (low != IWL_RATE_INVALID)
+ rate = low;
+ else
+ break;
+ } else {
+ if (new_rate != IWL_RATE_INVALID)
+ break;
+ else if (high != IWL_RATE_INVALID) {
+ start_hi = high;
+ rate = high;
+ } else {
+ new_rate = rate;
+ break;
+ }
+ }
+ }
+
+ return new_rate;
+}
+#endif /* CONFIG_IWLWIFI_HT */
+
+static inline u8 rs_is_both_ant_supp(u8 valid_antenna)
+{
+ return (rs_is_ant_connected(valid_antenna, ANT_BOTH));
+}
+
+static int rs_switch_to_mimo(struct iwl_priv *priv,
+ struct iwl_rate_scale_priv *lq_data,
+ struct iwl_scale_tbl_info *tbl, int index)
+{
+ int rc = -1;
+#ifdef CONFIG_IWLWIFI_HT
+ u16 rate_mask;
+ s32 rate;
+ s8 is_green = lq_data->is_green;
+
+ if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
+ return -1;
+
+ IWL_DEBUG_HT("LQ: try to switch to MIMO\n");
+ tbl->lq_type = LQ_MIMO;
+ rs_get_supported_rates(lq_data, NULL, tbl->lq_type,
+ &rate_mask);
+
+ if (priv->current_assoc_ht.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
+ return -1;
+
+ if (!rs_is_both_ant_supp(lq_data->antenna))
+ return -1;
+
+ rc = 0;
+ tbl->is_dup = lq_data->is_dup;
+ tbl->action = 0;
+ if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ)
+ tbl->is_fat = 1;
+ else
+ tbl->is_fat = 0;
+
+ if (tbl->is_fat) {
+ if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY)
+ tbl->is_SGI = 1;
+ else
+ tbl->is_SGI = 0;
+ } else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY)
+ tbl->is_SGI = 1;
+ else
+ tbl->is_SGI = 0;
+
+ rs_get_expected_tpt_table(lq_data, tbl);
+
+ rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index);
+
+ IWL_DEBUG_HT("LQ: MIMO best rate %d mask %X\n", rate, rate_mask);
+ if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask))
+ return -1;
+ rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green);
+
+ IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
+ tbl->current_rate.rate_n_flags, is_green);
+
+#endif /*CONFIG_IWLWIFI_HT */
+ return rc;
+}
+
+static int rs_switch_to_siso(struct iwl_priv *priv,
+ struct iwl_rate_scale_priv *lq_data,
+ struct iwl_scale_tbl_info *tbl, int index)
+{
+ int rc = -1;
+#ifdef CONFIG_IWLWIFI_HT
+ u16 rate_mask;
+ u8 is_green = lq_data->is_green;
+ s32 rate;
+
+ IWL_DEBUG_HT("LQ: try to switch to SISO\n");
+ if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
+ return -1;
+
+ rc = 0;
+ tbl->is_dup = lq_data->is_dup;
+ tbl->lq_type = LQ_SISO;
+ tbl->action = 0;
+ rs_get_supported_rates(lq_data, NULL, tbl->lq_type,
+ &rate_mask);
+
+ if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ)
+ tbl->is_fat = 1;
+ else
+ tbl->is_fat = 0;
+
+ if (tbl->is_fat) {
+ if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY)
+ tbl->is_SGI = 1;
+ else
+ tbl->is_SGI = 0;
+ } else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY)
+ tbl->is_SGI = 1;
+ else
+ tbl->is_SGI = 0;
+
+ if (is_green)
+ tbl->is_SGI = 0;
+
+ rs_get_expected_tpt_table(lq_data, tbl);
+ rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index);
+
+ IWL_DEBUG_HT("LQ: get best rate %d mask %X\n", rate, rate_mask);
+ if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+ IWL_DEBUG_HT("can not switch with index %d rate mask %x\n",
+ rate, rate_mask);
+ return -1;
+ }
+ rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green);
+ IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
+ tbl->current_rate.rate_n_flags, is_green);
+
+#endif /*CONFIG_IWLWIFI_HT */
+ return rc;
+}
+
+static int rs_move_legacy_other(struct iwl_priv *priv,
+ struct iwl_rate_scale_priv *lq_data,
+ int index)
+{
+ int rc = 0;
+ struct iwl_scale_tbl_info *tbl =
+ &(lq_data->lq_info[lq_data->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
+ struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+ u8 start_action = tbl->action;
+
+ for (; ;) {
+ switch (tbl->action) {
+ case IWL_LEGACY_SWITCH_ANTENNA:
+ IWL_DEBUG_HT("LQ Legacy switch Antenna\n");
+
+ search_tbl->lq_type = LQ_NONE;
+ lq_data->action_counter++;
+ if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+ break;
+ if (!rs_is_other_ant_connected(lq_data->antenna,
+ tbl->antenna_type))
+ break;
+
+ memcpy(search_tbl, tbl, sz);
+
+ rs_toggle_antenna(&(search_tbl->current_rate),
+ search_tbl);
+ rs_get_expected_tpt_table(lq_data, search_tbl);
+ lq_data->search_better_tbl = 1;
+ goto out;
+
+ case IWL_LEGACY_SWITCH_SISO:
+ IWL_DEBUG_HT("LQ: Legacy switch to SISO\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->lq_type = LQ_SISO;
+ search_tbl->is_SGI = 0;
+ search_tbl->is_fat = 0;
+ rc = rs_switch_to_siso(priv, lq_data, search_tbl,
+ index);
+ if (!rc) {
+ lq_data->search_better_tbl = 1;
+ lq_data->action_counter = 0;
+ }
+ if (!rc)
+ goto out;
+
+ break;
+ case IWL_LEGACY_SWITCH_MIMO:
+ IWL_DEBUG_HT("LQ: Legacy switch MIMO\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->lq_type = LQ_MIMO;
+ search_tbl->is_SGI = 0;
+ search_tbl->is_fat = 0;
+ search_tbl->antenna_type = ANT_BOTH;
+ rc = rs_switch_to_mimo(priv, lq_data, search_tbl,
+ index);
+ if (!rc) {
+ lq_data->search_better_tbl = 1;
+ lq_data->action_counter = 0;
+ }
+ if (!rc)
+ goto out;
+ break;
+ }
+ tbl->action++;
+ if (tbl->action > IWL_LEGACY_SWITCH_MIMO)
+ tbl->action = IWL_LEGACY_SWITCH_ANTENNA;
+
+ if (tbl->action == start_action)
+ break;
+
+ }
+ return 0;
+
+ out:
+ tbl->action++;
+ if (tbl->action > IWL_LEGACY_SWITCH_MIMO)
+ tbl->action = IWL_LEGACY_SWITCH_ANTENNA;
+ return 0;
+
+}
+
+static int rs_move_siso_to_other(struct iwl_priv *priv,
+ struct iwl_rate_scale_priv *lq_data,
+ int index)
+{
+ int rc = -1;
+ u8 is_green = lq_data->is_green;
+ struct iwl_scale_tbl_info *tbl =
+ &(lq_data->lq_info[lq_data->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
+ struct iwl_rate_scale_data *window = &(tbl->win[index]);
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+ u8 start_action = tbl->action;
+
+ for (;;) {
+ lq_data->action_counter++;
+ switch (tbl->action) {
+ case IWL_SISO_SWITCH_ANTENNA:
+ IWL_DEBUG_HT("LQ: SISO SWITCH ANTENNA SISO\n");
+ search_tbl->lq_type = LQ_NONE;
+ if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+ break;
+ if (!rs_is_other_ant_connected(lq_data->antenna,
+ tbl->antenna_type))
+ break;
+
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->action = IWL_SISO_SWITCH_MIMO;
+ rs_toggle_antenna(&(search_tbl->current_rate),
+ search_tbl);
+ lq_data->search_better_tbl = 1;
+
+ goto out;
+
+ case IWL_SISO_SWITCH_MIMO:
+ IWL_DEBUG_HT("LQ: SISO SWITCH TO MIMO FROM SISO\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->lq_type = LQ_MIMO;
+ search_tbl->is_SGI = 0;
+ search_tbl->is_fat = 0;
+ search_tbl->antenna_type = ANT_BOTH;
+ rc = rs_switch_to_mimo(priv, lq_data, search_tbl,
+ index);
+ if (!rc)
+ lq_data->search_better_tbl = 1;
+
+ if (!rc)
+ goto out;
+ break;
+ case IWL_SISO_SWITCH_GI:
+ IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->action = 0;
+ if (search_tbl->is_SGI)
+ search_tbl->is_SGI = 0;
+ else if (!is_green)
+ search_tbl->is_SGI = 1;
+ else
+ break;
+ lq_data->search_better_tbl = 1;
+ if ((tbl->lq_type == LQ_SISO) &&
+ (tbl->is_SGI)) {
+ s32 tpt = lq_data->last_tpt / 100;
+ if (((!tbl->is_fat) &&
+ (tpt >= expected_tpt_siso20MHz[index])) ||
+ ((tbl->is_fat) &&
+ (tpt >= expected_tpt_siso40MHz[index])))
+ lq_data->search_better_tbl = 0;
+ }
+ rs_get_expected_tpt_table(lq_data, search_tbl);
+ rs_mcs_from_tbl(&search_tbl->current_rate,
+ search_tbl, index, is_green);
+ goto out;
+ }
+ tbl->action++;
+ if (tbl->action > IWL_SISO_SWITCH_GI)
+ tbl->action = IWL_SISO_SWITCH_ANTENNA;
+
+ if (tbl->action == start_action)
+ break;
+ }
+ return 0;
+
+ out:
+ tbl->action++;
+ if (tbl->action > IWL_SISO_SWITCH_GI)
+ tbl->action = IWL_SISO_SWITCH_ANTENNA;
+ return 0;
+}
+
+static int rs_move_mimo_to_other(struct iwl_priv *priv,
+ struct iwl_rate_scale_priv *lq_data,
+ int index)
+{
+ int rc = -1;
+ s8 is_green = lq_data->is_green;
+ struct iwl_scale_tbl_info *tbl =
+ &(lq_data->lq_info[lq_data->active_tbl]);
+ struct iwl_scale_tbl_info *search_tbl =
+ &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
+ u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+ (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+ u8 start_action = tbl->action;
+
+ for (;;) {
+ lq_data->action_counter++;
+ switch (tbl->action) {
+ case IWL_MIMO_SWITCH_ANTENNA_A:
+ case IWL_MIMO_SWITCH_ANTENNA_B:
+ IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->lq_type = LQ_SISO;
+ search_tbl->is_SGI = 0;
+ search_tbl->is_fat = 0;
+ if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A)
+ search_tbl->antenna_type = ANT_MAIN;
+ else
+ search_tbl->antenna_type = ANT_AUX;
+
+ rc = rs_switch_to_siso(priv, lq_data, search_tbl,
+ index);
+ if (!rc) {
+ lq_data->search_better_tbl = 1;
+ goto out;
+ }
+ break;
+
+ case IWL_MIMO_SWITCH_GI:
+ IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n");
+ memcpy(search_tbl, tbl, sz);
+ search_tbl->lq_type = LQ_MIMO;
+ search_tbl->antenna_type = ANT_BOTH;
+ search_tbl->action = 0;
+ if (search_tbl->is_SGI)
+ search_tbl->is_SGI = 0;
+ else
+ search_tbl->is_SGI = 1;
+ lq_data->search_better_tbl = 1;
+ if ((tbl->lq_type == LQ_MIMO) &&
+ (tbl->is_SGI)) {
+ s32 tpt = lq_data->last_tpt / 100;
+ if (((!tbl->is_fat) &&
+ (tpt >= expected_tpt_mimo20MHz[index])) ||
+ ((tbl->is_fat) &&
+ (tpt >= expected_tpt_mimo40MHz[index])))
+ lq_data->search_better_tbl = 0;
+ }
+ rs_get_expected_tpt_table(lq_data, search_tbl);
+ rs_mcs_from_tbl(&search_tbl->current_rate,
+ search_tbl, index, is_green);
+ goto out;
+
+ }
+ tbl->action++;
+ if (tbl->action > IWL_MIMO_SWITCH_GI)
+ tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;
+
+ if (tbl->action == start_action)
+ break;
+ }
+
+ return 0;
+ out:
+ tbl->action++;
+ if (tbl->action > IWL_MIMO_SWITCH_GI)
+ tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;
+ return 0;
+
+}
+
+static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data)
+{
+ struct iwl_scale_tbl_info *tbl;
+ int i;
+ int active_tbl;
+ int flush_interval_passed = 0;
+
+ active_tbl = lq_data->active_tbl;
+
+ tbl = &(lq_data->lq_info[active_tbl]);
+
+ if (lq_data->stay_in_tbl) {
+
+ if (lq_data->flush_timer)
+ flush_interval_passed =
+ time_after(jiffies,
+ (unsigned long)(lq_data->flush_timer +
+ IWL_RATE_SCALE_FLUSH_INTVL));
+
+ flush_interval_passed = 0;
+ if ((lq_data->total_failed > lq_data->max_failure_limit) ||
+ (lq_data->total_success > lq_data->max_success_limit) ||
+ ((!lq_data->search_better_tbl) && (lq_data->flush_timer)
+ && (flush_interval_passed))) {
+ IWL_DEBUG_HT("LQ: stay is expired %d %d %d\n:",
+ lq_data->total_failed,
+ lq_data->total_success,
+ flush_interval_passed);
+ lq_data->stay_in_tbl = 0;
+ lq_data->total_failed = 0;
+ lq_data->total_success = 0;
+ lq_data->flush_timer = 0;
+ } else if (lq_data->table_count > 0) {
+ lq_data->table_count++;
+ if (lq_data->table_count >=
+ lq_data->table_count_limit) {
+ lq_data->table_count = 0;
+
+ IWL_DEBUG_HT("LQ: stay in table clear win\n");
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(
+ &(tbl->win[i]));
+ }
+ }
+
+ if (!lq_data->stay_in_tbl) {
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(&(tbl->win[i]));
+ }
+ }
+}
+
+static void rs_rate_scale_perform(struct iwl_priv *priv,
+ struct net_device *dev,
+ struct ieee80211_hdr *hdr,
+ struct sta_info *sta)
+{
+ int low = IWL_RATE_INVALID;
+ int high = IWL_RATE_INVALID;
+ int index;
+ int i;
+ struct iwl_rate_scale_data *window = NULL;
+ int current_tpt = IWL_INVALID_VALUE;
+ int low_tpt = IWL_INVALID_VALUE;
+ int high_tpt = IWL_INVALID_VALUE;
+ u32 fail_count;
+ s8 scale_action = 0;
+ u16 fc, rate_mask;
+ u8 update_lq = 0;
+ struct iwl_rate_scale_priv *lq_data;
+ struct iwl_scale_tbl_info *tbl, *tbl1;
+ u16 rate_scale_index_msk = 0;
+ struct iwl_rate mcs_rate;
+ u8 is_green = 0;
+ u8 active_tbl = 0;
+ u8 done_search = 0;
+ u16 high_low;
+
+ IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
+ /* Send management frames and broadcast/multicast data using
+ * lowest rate. */
+ /* TODO: this could probably be improved.. */
+ return;
+ }
+
+ if (!sta || !sta->rate_ctrl_priv)
+ return;
+
+ if (!priv->lq_mngr.lq_ready) {
+ IWL_DEBUG_RATE("still rate scaling not ready\n");
+ return;
+ }
+ lq_data = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+
+ if (!lq_data->search_better_tbl)
+ active_tbl = lq_data->active_tbl;
+ else
+ active_tbl = 1 - lq_data->active_tbl;
+
+ tbl = &(lq_data->lq_info[active_tbl]);
+ is_green = lq_data->is_green;
+
+ index = sta->last_txrate;
+
+ IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index,
+ tbl->lq_type);
+
+ rs_get_supported_rates(lq_data, hdr, tbl->lq_type,
+ &rate_mask);
+
+ IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask);
+
+ /* mask with station rate restriction */
+ if (is_legacy(tbl->lq_type)) {
+ if (lq_data->phymode == (u8) MODE_IEEE80211A)
+ rate_scale_index_msk = (u16) (rate_mask &
+ (lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
+ else
+ rate_scale_index_msk = (u16) (rate_mask &
+ lq_data->supp_rates);
+
+ } else
+ rate_scale_index_msk = rate_mask;
+
+ if (!rate_scale_index_msk)
+ rate_scale_index_msk = rate_mask;
+
+ if (index < 0 || !((1 << index) & rate_scale_index_msk)) {
+ index = IWL_INVALID_VALUE;
+ update_lq = 1;
+
+ /* get the lowest availabe rate */
+ for (i = 0; i <= IWL_RATE_COUNT; i++) {
+ if ((1 << i) & rate_scale_index_msk)
+ index = i;
+ }
+
+ if (index == IWL_INVALID_VALUE) {
+ IWL_WARNING("Can not find a suitable rate\n");
+ return;
+ }
+ }
+
+ if (!tbl->expected_tpt)
+ rs_get_expected_tpt_table(lq_data, tbl);
+
+ window = &(tbl->win[index]);
+
+ fail_count = window->counter - window->success_counter;
+ if (((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
+ (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))
+ || (tbl->expected_tpt == NULL)) {
+ IWL_DEBUG_RATE("LQ: still below TH succ %d total %d "
+ "for index %d\n",
+ window->success_counter, window->counter, index);
+ window->average_tpt = IWL_INVALID_VALUE;
+ rs_stay_in_table(lq_data);
+ if (update_lq) {
+ rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
+ rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);
+ rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
+ }
+ goto out;
+
+ } else
+ window->average_tpt = ((window->success_ratio *
+ tbl->expected_tpt[index] + 64) / 128);
+
+ if (lq_data->search_better_tbl) {
+ int success_limit = IWL_RATE_SCALE_SWITCH;
+
+ if ((window->success_ratio > success_limit) ||
+ (window->average_tpt > lq_data->last_tpt)) {
+ if (!is_legacy(tbl->lq_type)) {
+ IWL_DEBUG_HT("LQ: we are switching to HT"
+ " rate suc %d current tpt %d"
+ " old tpt %d\n",
+ window->success_ratio,
+ window->average_tpt,
+ lq_data->last_tpt);
+ lq_data->enable_counter = 1;
+ }
+ lq_data->active_tbl = active_tbl;
+ current_tpt = window->average_tpt;
+ } else {
+ tbl->lq_type = LQ_NONE;
+ active_tbl = lq_data->active_tbl;
+ tbl = &(lq_data->lq_info[active_tbl]);
+
+ index = iwl_rate_index_from_plcp(
+ tbl->current_rate.rate_n_flags);
+
+ update_lq = 1;
+ current_tpt = lq_data->last_tpt;
+ IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n");
+ }
+ lq_data->search_better_tbl = 0;
+ done_search = 1;
+ goto lq_update;
+ }
+
+ high_low = rs_get_adjacent_rate(index, rate_scale_index_msk,
+ tbl->lq_type);
+ low = high_low & 0xff;
+ high = (high_low >> 8) & 0xff;
+
+ current_tpt = window->average_tpt;
+
+ if (low != IWL_RATE_INVALID)
+ low_tpt = tbl->win[low].average_tpt;
+
+ if (high != IWL_RATE_INVALID)
+ high_tpt = tbl->win[high].average_tpt;
+
+
+ scale_action = 1;
+
+ if ((window->success_ratio <= IWL_RATE_DECREASE_TH) ||
+ (current_tpt == 0)) {
+ IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
+ scale_action = -1;
+ } else if ((low_tpt == IWL_INVALID_VALUE) &&
+ (high_tpt == IWL_INVALID_VALUE))
+ scale_action = 1;
+ else if ((low_tpt != IWL_INVALID_VALUE) &&
+ (high_tpt != IWL_INVALID_VALUE) &&
+ (low_tpt < current_tpt) &&
+ (high_tpt < current_tpt))
+ scale_action = 0;
+ else {
+ if (high_tpt != IWL_INVALID_VALUE) {
+ if (high_tpt > current_tpt)
+ scale_action = 1;
+ else {
+ IWL_DEBUG_RATE
+ ("decrease rate because of high tpt\n");
+ scale_action = -1;
+ }
+ } else if (low_tpt != IWL_INVALID_VALUE) {
+ if (low_tpt > current_tpt) {
+ IWL_DEBUG_RATE
+ ("decrease rate because of low tpt\n");
+ scale_action = -1;
+ } else
+ scale_action = 1;
+ }
+ }
+
+ if (scale_action == -1) {
+ if ((low != IWL_RATE_INVALID) &&
+ ((window->success_ratio > IWL_RATE_HIGH_TH) ||
+ (current_tpt > (100 * tbl->expected_tpt[low]))))
+ scale_action = 0;
+ } else if ((scale_action == 1) &&
+ (window->success_ratio < IWL_RATE_INCREASE_TH))
+ scale_action = 0;
+
+ switch (scale_action) {
+ case -1:
+ if (low != IWL_RATE_INVALID) {
+ update_lq = 1;
+ index = low;
+ }
+ break;
+ case 1:
+ if (high != IWL_RATE_INVALID) {
+ update_lq = 1;
+ index = high;
+ }
+
+ break;
+ case 0:
+ default:
+ break;
+ }
+
+ IWL_DEBUG_HT("choose rate scale index %d action %d low %d "
+ "high %d type %d\n",
+ index, scale_action, low, high, tbl->lq_type);
+
+ lq_update:
+ if (update_lq) {
+ rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
+ rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);
+ rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
+ }
+ rs_stay_in_table(lq_data);
+
+ if (!update_lq && !done_search && !lq_data->stay_in_tbl) {
+ lq_data->last_tpt = current_tpt;
+
+ if (is_legacy(tbl->lq_type))
+ rs_move_legacy_other(priv, lq_data, index);
+ else if (is_siso(tbl->lq_type))
+ rs_move_siso_to_other(priv, lq_data, index);
+ else
+ rs_move_mimo_to_other(priv, lq_data, index);
+
+ if (lq_data->search_better_tbl) {
+ tbl = &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(&(tbl->win[i]));
+
+ index = iwl_rate_index_from_plcp(
+ tbl->current_rate.rate_n_flags);
+
+ IWL_DEBUG_HT("Switch current mcs: %X index: %d\n",
+ tbl->current_rate.rate_n_flags, index);
+ rs_fill_link_cmd(lq_data, &tbl->current_rate,
+ &lq_data->lq);
+ rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
+ }
+ tbl1 = &(lq_data->lq_info[lq_data->active_tbl]);
+
+ if (is_legacy(tbl1->lq_type) &&
+#ifdef CONFIG_IWLWIFI_HT
+ !priv->current_assoc_ht.is_ht &&
+#endif
+ (lq_data->action_counter >= 1)) {
+ lq_data->action_counter = 0;
+ IWL_DEBUG_HT("LQ: STAY in legacy table\n");
+ rs_set_stay_in_table(1, lq_data);
+ }
+
+ if (lq_data->enable_counter &&
+ (lq_data->action_counter >= IWL_ACTION_LIMIT)) {
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ if ((lq_data->last_tpt > TID_AGG_TPT_THREHOLD) &&
+ (priv->lq_mngr.agg_ctrl.auto_agg)) {
+ priv->lq_mngr.agg_ctrl.tid_retry =
+ TID_ALL_SPECIFIED;
+ schedule_work(&priv->agg_work);
+ }
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+ lq_data->action_counter = 0;
+ rs_set_stay_in_table(0, lq_data);
+ }
+ } else {
+ if ((!update_lq) && (!done_search) && (!lq_data->flush_timer))
+ lq_data->flush_timer = jiffies;
+ }
+
+out:
+ rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green);
+ i = index;
+ sta->last_txrate = i;
+
+ /* sta->txrate is an index to A mode rates which start
+ * at IWL_FIRST_OFDM_RATE
+ */
+ if (lq_data->phymode == (u8) MODE_IEEE80211A)
+ sta->txrate = i - IWL_FIRST_OFDM_RATE;
+ else
+ sta->txrate = i;
+
+ return;
+}
+
+
+static void rs_initialize_lq(struct iwl_priv *priv,
+ struct sta_info *sta)
+{
+ int i;
+ struct iwl_rate_scale_priv *lq;
+ struct iwl_scale_tbl_info *tbl;
+ u8 active_tbl = 0;
+ int rate_idx;
+ u8 use_green = rs_use_green(priv);
+ struct iwl_rate mcs_rate;
+
+ if (!sta || !sta->rate_ctrl_priv)
+ goto out;
+
+ lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+ i = sta->last_txrate;
+
+ if ((lq->lq.sta_id == 0xff) &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
+ goto out;
+
+ if (!lq->search_better_tbl)
+ active_tbl = lq->active_tbl;
+ else
+ active_tbl = 1 - lq->active_tbl;
+
+ tbl = &(lq->lq_info[active_tbl]);
+
+ if ((i < 0) || (i >= IWL_RATE_COUNT))
+ i = 0;
+
+ mcs_rate.rate_n_flags = iwl_rates[i].plcp ;
+ mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK;
+ mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
+
+ if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
+ mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK;
+
+ tbl->antenna_type = ANT_AUX;
+ rs_get_tbl_info_from_mcs(&mcs_rate, priv->phymode, tbl, &rate_idx);
+ if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type))
+ rs_toggle_antenna(&mcs_rate, tbl);
+
+ rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green);
+ tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags;
+ rs_get_expected_tpt_table(lq, tbl);
+ rs_fill_link_cmd(lq, &mcs_rate, &lq->lq);
+ rs_send_lq_cmd(priv, &lq->lq, CMD_ASYNC);
+ out:
+ return;
+}
+
+static struct ieee80211_rate *rs_get_lowest_rate(struct ieee80211_local
+ *local)
+{
+ struct ieee80211_hw_mode *mode = local->oper_hw_mode;
+ int i;
+
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *rate = &mode->rates[i];
+
+ if (rate->flags & IEEE80211_RATE_SUPPORTED)
+ return rate;
+ }
+
+ return &mode->rates[0];
+}
+
+static struct ieee80211_rate *rs_get_rate(void *priv_rate,
+ struct net_device *dev,
+ struct sk_buff *skb,
+ struct rate_control_extra
+ *extra)
+{
+
+ int i;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct sta_info *sta;
+ u16 fc;
+ struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+ struct iwl_rate_scale_priv *lq;
+
+ IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
+
+ memset(extra, 0, sizeof(*extra));
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
+ /* Send management frames and broadcast/multicast data using
+ * lowest rate. */
+ /* TODO: this could probably be improved.. */
+ return rs_get_lowest_rate(local);
+ }
+
+ sta = sta_info_get(local, hdr->addr1);
+
+ if (!sta || !sta->rate_ctrl_priv) {
+ if (sta)
+ sta_info_put(sta);
+ return rs_get_lowest_rate(local);
+ }
+
+ lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+ i = sta->last_txrate;
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) {
+ u8 sta_id = iwl_hw_find_station(priv, hdr->addr1);
+ DECLARE_MAC_BUF(mac);
+
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_RATE("LQ: ADD station %s\n",
+ print_mac(mac, hdr->addr1));
+ sta_id = iwl_add_station(priv,
+ hdr->addr1, 0, CMD_ASYNC);
+ }
+ if ((sta_id != IWL_INVALID_STATION)) {
+ lq->lq.sta_id = sta_id;
+ lq->lq.rs_table[0].rate_n_flags = 0;
+ lq->ibss_sta_added = 1;
+ rs_initialize_lq(priv, sta);
+ }
+ if (!lq->ibss_sta_added)
+ goto done;
+ }
+
+ done:
+ sta_info_put(sta);
+ if ((i < 0) || (i > IWL_RATE_COUNT))
+ return rs_get_lowest_rate(local);
+
+ return &priv->ieee_rates[i];
+}
+
+static void *rs_alloc_sta(void *priv, gfp_t gfp)
+{
+ struct iwl_rate_scale_priv *crl;
+ int i, j;
+
+ IWL_DEBUG_RATE("create station rate scale window\n");
+
+ crl = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp);
+
+ if (crl == NULL)
+ return NULL;
+ crl->lq.sta_id = 0xff;
+
+
+ for (j = 0; j < LQ_SIZE; j++)
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(&(crl->lq_info[j].win[i]));
+
+ return crl;
+}
+
+static void rs_rate_init(void *priv_rate, void *priv_sta,
+ struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ int i, j;
+ struct ieee80211_hw_mode *mode = local->oper_hw_mode;
+ struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+ struct iwl_rate_scale_priv *crl = priv_sta;
+
+ crl->flush_timer = 0;
+ crl->supp_rates = sta->supp_rates;
+ sta->txrate = 3;
+ for (j = 0; j < LQ_SIZE; j++)
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ rs_rate_scale_clear_window(&(crl->lq_info[j].win[i]));
+
+ IWL_DEBUG_RATE("rate scale global init\n");
+ /* TODO: what is a good starting rate for STA? About middle? Maybe not
+ * the lowest or the highest rate.. Could consider using RSSI from
+ * previous packets? Need to have IEEE 802.1X auth succeed immediately
+ * after assoc.. */
+
+ crl->ibss_sta_added = 0;
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ u8 sta_id = iwl_hw_find_station(priv, sta->addr);
+ DECLARE_MAC_BUF(mac);
+
+ /* for IBSS the call are from tasklet */
+ IWL_DEBUG_HT("LQ: ADD station %s\n",
+ print_mac(mac, sta->addr));
+
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_RATE("LQ: ADD station %s\n",
+ print_mac(mac, sta->addr));
+ sta_id = iwl_add_station(priv,
+ sta->addr, 0, CMD_ASYNC);
+ }
+ if ((sta_id != IWL_INVALID_STATION)) {
+ crl->lq.sta_id = sta_id;
+ crl->lq.rs_table[0].rate_n_flags = 0;
+ }
+ /* FIXME: this is w/a remove it later */
+ priv->assoc_station_added = 1;
+ }
+
+ for (i = 0; i < mode->num_rates; i++) {
+ if ((sta->supp_rates & BIT(i)) &&
+ (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED))
+ sta->txrate = i;
+ }
+ sta->last_txrate = sta->txrate;
+ /* For MODE_IEEE80211A mode cck rate are at end
+ * rate table
+ */
+ if (local->hw.conf.phymode == MODE_IEEE80211A)
+ sta->last_txrate += IWL_FIRST_OFDM_RATE;
+
+ crl->is_dup = priv->is_dup;
+ crl->valid_antenna = priv->valid_antenna;
+ crl->antenna = priv->antenna;
+ crl->is_green = rs_use_green(priv);
+ crl->active_rate = priv->active_rate;
+ crl->active_rate &= ~(0x1000);
+ crl->active_rate_basic = priv->active_rate_basic;
+ crl->phymode = priv->phymode;
+#ifdef CONFIG_IWLWIFI_HT
+ crl->active_siso_rate = (priv->current_assoc_ht.supp_rates[0] << 1);
+ crl->active_siso_rate |= (priv->current_assoc_ht.supp_rates[0] & 0x1);
+ crl->active_siso_rate &= ~((u16)0x2);
+ crl->active_siso_rate = crl->active_siso_rate << IWL_FIRST_OFDM_RATE;
+
+ crl->active_mimo_rate = (priv->current_assoc_ht.supp_rates[1] << 1);
+ crl->active_mimo_rate |= (priv->current_assoc_ht.supp_rates[1] & 0x1);
+ crl->active_mimo_rate &= ~((u16)0x2);
+ crl->active_mimo_rate = crl->active_mimo_rate << IWL_FIRST_OFDM_RATE;
+ IWL_DEBUG_HT("MIMO RATE 0x%X SISO MASK 0x%X\n", crl->active_siso_rate,
+ crl->active_mimo_rate);
+#endif /*CONFIG_IWLWIFI_HT*/
+#ifdef CONFIG_MAC80211_DEBUGFS
+ crl->drv = priv;
+#endif
+
+ if (priv->assoc_station_added)
+ priv->lq_mngr.lq_ready = 1;
+
+ rs_initialize_lq(priv, sta);
+}
+
+static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
+ struct iwl_rate *tx_mcs,
+ struct iwl_link_quality_cmd *lq_cmd)
+{
+ int index = 0;
+ int rate_idx;
+ int repeat_rate = 0;
+ u8 ant_toggle_count = 0;
+ u8 use_ht_possible = 1;
+ struct iwl_rate new_rate;
+ struct iwl_scale_tbl_info tbl_type = { 0 };
+
+ rs_dbgfs_set_mcs(lq_data, tx_mcs, index);
+
+ rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode,
+ &tbl_type, &rate_idx);
+
+ if (is_legacy(tbl_type.lq_type)) {
+ ant_toggle_count = 1;
+ repeat_rate = IWL_NUMBER_TRY;
+ } else
+ repeat_rate = IWL_HT_NUMBER_TRY;
+
+ lq_cmd->general_params.mimo_delimiter =
+ is_mimo(tbl_type.lq_type) ? 1 : 0;
+ lq_cmd->rs_table[index].rate_n_flags =
+ cpu_to_le32(tx_mcs->rate_n_flags);
+ new_rate.rate_n_flags = tx_mcs->rate_n_flags;
+
+ if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN))
+ lq_cmd->general_params.single_stream_ant_msk = 1;
+ else
+ lq_cmd->general_params.single_stream_ant_msk = 2;
+
+ index++;
+ repeat_rate--;
+
+ while (index < LINK_QUAL_MAX_RETRY_NUM) {
+ while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
+ if (is_legacy(tbl_type.lq_type)) {
+ if (ant_toggle_count <
+ NUM_TRY_BEFORE_ANTENNA_TOGGLE)
+ ant_toggle_count++;
+ else {
+ rs_toggle_antenna(&new_rate, &tbl_type);
+ ant_toggle_count = 1;
+ }
+ }
+
+ rs_dbgfs_set_mcs(lq_data, &new_rate, index);
+ lq_cmd->rs_table[index].rate_n_flags =
+ cpu_to_le32(new_rate.rate_n_flags);
+ repeat_rate--;
+ index++;
+ }
+
+ rs_get_tbl_info_from_mcs(&new_rate, lq_data->phymode, &tbl_type,
+ &rate_idx);
+
+ if (is_mimo(tbl_type.lq_type))
+ lq_cmd->general_params.mimo_delimiter = index;
+
+ rs_get_lower_rate(lq_data, &tbl_type, rate_idx,
+ use_ht_possible, &new_rate);
+
+ if (is_legacy(tbl_type.lq_type)) {
+ if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE)
+ ant_toggle_count++;
+ else {
+ rs_toggle_antenna(&new_rate, &tbl_type);
+ ant_toggle_count = 1;
+ }
+ repeat_rate = IWL_NUMBER_TRY;
+ } else
+ repeat_rate = IWL_HT_NUMBER_TRY;
+
+ use_ht_possible = 0;
+
+ rs_dbgfs_set_mcs(lq_data, &new_rate, index);
+ lq_cmd->rs_table[index].rate_n_flags =
+ cpu_to_le32(new_rate.rate_n_flags);
+
+ index++;
+ repeat_rate--;
+ }
+
+ lq_cmd->general_params.dual_stream_ant_msk = 3;
+ lq_cmd->agg_params.agg_dis_start_th = 3;
+ lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
+}
+
+static void *rs_alloc(struct ieee80211_local *local)
+{
+ return local->hw.priv;
+}
+/* rate scale requires free function to be implemented */
+static void rs_free(void *priv_rate)
+{
+ return;
+}
+
+static void rs_clear(void *priv_rate)
+{
+ struct iwl_priv *priv = (struct iwl_priv *) priv_rate;
+
+ IWL_DEBUG_RATE("enter\n");
+
+ priv->lq_mngr.lq_ready = 0;
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ if (priv->lq_mngr.agg_ctrl.granted_ba)
+ iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+ IWL_DEBUG_RATE("leave\n");
+}
+
+static void rs_free_sta(void *priv, void *priv_sta)
+{
+ struct iwl_rate_scale_priv *rs_priv = priv_sta;
+
+ IWL_DEBUG_RATE("enter\n");
+ kfree(rs_priv);
+ IWL_DEBUG_RATE("leave\n");
+}
+
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
+ struct iwl_rate *mcs, int index)
+{
+ u32 base_rate;
+
+ if (rs_priv->phymode == (u8) MODE_IEEE80211A)
+ base_rate = 0x800D;
+ else
+ base_rate = 0x820A;
+
+ if (rs_priv->dbg_fixed.rate_n_flags) {
+ if (index < 12)
+ mcs->rate_n_flags = rs_priv->dbg_fixed.rate_n_flags;
+ else
+ mcs->rate_n_flags = base_rate;
+ IWL_DEBUG_RATE("Fixed rate ON\n");
+ return;
+ }
+
+ IWL_DEBUG_RATE("Fixed rate OFF\n");
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct iwl_rate_scale_priv *rs_priv = file->private_data;
+ char buf[64];
+ int buf_size;
+ u32 parsed_rate;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ if (sscanf(buf, "%x", &parsed_rate) == 1)
+ rs_priv->dbg_fixed.rate_n_flags = parsed_rate;
+ else
+ rs_priv->dbg_fixed.rate_n_flags = 0;
+
+ rs_priv->active_rate = 0x0FFF;
+ rs_priv->active_siso_rate = 0x1FD0;
+ rs_priv->active_mimo_rate = 0x1FD0;
+
+ IWL_DEBUG_RATE("sta_id %d rate 0x%X\n",
+ rs_priv->lq.sta_id, rs_priv->dbg_fixed.rate_n_flags);
+
+ if (rs_priv->dbg_fixed.rate_n_flags) {
+ rs_fill_link_cmd(rs_priv, &rs_priv->dbg_fixed, &rs_priv->lq);
+ rs_send_lq_cmd(rs_priv->drv, &rs_priv->lq, CMD_ASYNC);
+ }
+
+ return count;
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buff[1024];
+ int desc = 0;
+ int i = 0;
+
+ struct iwl_rate_scale_priv *rs_priv = file->private_data;
+
+ desc += sprintf(buff+desc, "sta_id %d\n", rs_priv->lq.sta_id);
+ desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
+ rs_priv->total_failed, rs_priv->total_success,
+ rs_priv->active_rate);
+ desc += sprintf(buff+desc, "fixed rate 0x%X\n",
+ rs_priv->dbg_fixed.rate_n_flags);
+ desc += sprintf(buff+desc, "general:"
+ "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
+ rs_priv->lq.general_params.flags,
+ rs_priv->lq.general_params.mimo_delimiter,
+ rs_priv->lq.general_params.single_stream_ant_msk,
+ rs_priv->lq.general_params.dual_stream_ant_msk);
+
+ desc += sprintf(buff+desc, "agg:"
+ "time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
+ le16_to_cpu(rs_priv->lq.agg_params.agg_time_limit),
+ rs_priv->lq.agg_params.agg_dis_start_th,
+ rs_priv->lq.agg_params.agg_frame_cnt_limit);
+
+ desc += sprintf(buff+desc,
+ "Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
+ rs_priv->lq.general_params.start_rate_index[0],
+ rs_priv->lq.general_params.start_rate_index[1],
+ rs_priv->lq.general_params.start_rate_index[2],
+ rs_priv->lq.general_params.start_rate_index[3]);
+
+
+ for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+ desc += sprintf(buff+desc, " rate[%d] 0x%X\n",
+ i, le32_to_cpu(rs_priv->lq.rs_table[i].rate_n_flags));
+
+ return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
+ .write = rs_sta_dbgfs_scale_table_write,
+ .read = rs_sta_dbgfs_scale_table_read,
+ .open = open_file_generic,
+};
+static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buff[1024];
+ int desc = 0;
+ int i, j;
+
+ struct iwl_rate_scale_priv *rs_priv = file->private_data;
+ for (i = 0; i < LQ_SIZE; i++) {
+ desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
+ "rate=0x%X\n",
+ rs_priv->active_tbl == i?"*":"x",
+ rs_priv->lq_info[i].lq_type,
+ rs_priv->lq_info[i].is_SGI,
+ rs_priv->lq_info[i].is_fat,
+ rs_priv->lq_info[i].is_dup,
+ rs_priv->lq_info[i].current_rate.rate_n_flags);
+ for (j = 0; j < IWL_RATE_COUNT; j++) {
+ desc += sprintf(buff+desc,
+ "counter=%d success=%d %%=%d\n",
+ rs_priv->lq_info[i].win[j].counter,
+ rs_priv->lq_info[i].win[j].success_counter,
+ rs_priv->lq_info[i].win[j].success_ratio);
+ }
+ }
+ return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
+ .read = rs_sta_dbgfs_stats_table_read,
+ .open = open_file_generic,
+};
+
+static void rs_add_debugfs(void *priv, void *priv_sta,
+ struct dentry *dir)
+{
+ struct iwl_rate_scale_priv *rs_priv = priv_sta;
+ rs_priv->rs_sta_dbgfs_scale_table_file =
+ debugfs_create_file("rate_scale_table", 0600, dir,
+ rs_priv, &rs_sta_dbgfs_scale_table_ops);
+ rs_priv->rs_sta_dbgfs_stats_table_file =
+ debugfs_create_file("rate_stats_table", 0600, dir,
+ rs_priv, &rs_sta_dbgfs_stats_table_ops);
+}
+
+static void rs_remove_debugfs(void *priv, void *priv_sta)
+{
+ struct iwl_rate_scale_priv *rs_priv = priv_sta;
+ debugfs_remove(rs_priv->rs_sta_dbgfs_scale_table_file);
+ debugfs_remove(rs_priv->rs_sta_dbgfs_stats_table_file);
+}
+#endif
+
+static struct rate_control_ops rs_ops = {
+ .module = NULL,
+ .name = RS_NAME,
+ .tx_status = rs_tx_status,
+ .get_rate = rs_get_rate,
+ .rate_init = rs_rate_init,
+ .clear = rs_clear,
+ .alloc = rs_alloc,
+ .free = rs_free,
+ .alloc_sta = rs_alloc_sta,
+ .free_sta = rs_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+ .add_sta_debugfs = rs_add_debugfs,
+ .remove_sta_debugfs = rs_remove_debugfs,
+#endif
+};
+
+int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_rate_scale_priv *rs_priv;
+ struct sta_info *sta;
+ int count = 0, i;
+ u32 samples = 0, success = 0, good = 0;
+ unsigned long now = jiffies;
+ u32 max_time = 0;
+ u8 lq_type, antenna;
+
+ sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
+ if (!sta || !sta->rate_ctrl_priv) {
+ if (sta) {
+ sta_info_put(sta);
+ IWL_DEBUG_RATE("leave - no private rate data!\n");
+ } else
+ IWL_DEBUG_RATE("leave - no station!\n");
+ return sprintf(buf, "station %d not found\n", sta_id);
+ }
+
+ rs_priv = (void *)sta->rate_ctrl_priv;
+
+ lq_type = rs_priv->lq_info[rs_priv->active_tbl].lq_type;
+ antenna = rs_priv->lq_info[rs_priv->active_tbl].antenna_type;
+
+ if (is_legacy(lq_type))
+ i = IWL_RATE_54M_INDEX;
+ else
+ i = IWL_RATE_60M_INDEX;
+ while (1) {
+ u64 mask;
+ int j;
+ int active = rs_priv->active_tbl;
+
+ count +=
+ sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2);
+
+ mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
+ for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
+ buf[count++] =
+ (rs_priv->lq_info[active].win[i].data & mask)
+ ? '1' : '0';
+
+ samples += rs_priv->lq_info[active].win[i].counter;
+ good += rs_priv->lq_info[active].win[i].success_counter;
+ success += rs_priv->lq_info[active].win[i].success_counter *
+ iwl_rates[i].ieee;
+
+ if (rs_priv->lq_info[active].win[i].stamp) {
+ int delta =
+ jiffies_to_msecs(now -
+ rs_priv->lq_info[active].win[i].stamp);
+
+ if (delta > max_time)
+ max_time = delta;
+
+ count += sprintf(&buf[count], "%5dms\n", delta);
+ } else
+ buf[count++] = '\n';
+
+ j = iwl_get_prev_ieee_rate(i);
+ if (j == i)
+ break;
+ i = j;
+ }
+
+ /* Display the average rate of all samples taken.
+ *
+ * NOTE: We multiple # of samples by 2 since the IEEE measurement
+ * added from iwl_rates is actually 2X the rate */
+ if (samples)
+ count += sprintf(&buf[count],
+ "\nAverage rate is %3d.%02dMbs over last %4dms\n"
+ "%3d%% success (%d good packets over %d tries)\n",
+ success / (2 * samples), (success * 5 / samples) % 10,
+ max_time, good * 100 / samples, good, samples);
+ else
+ count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n");
+ count += sprintf(&buf[count], "\nrate scale type %d anntena %d "
+ "active_search %d rate index %d\n", lq_type, antenna,
+ rs_priv->search_better_tbl, sta->last_txrate);
+
+ sta_info_put(sta);
+ return count;
+}
+
+void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ priv->lq_mngr.lq_ready = 1;
+}
+
+void iwl_rate_control_register(struct ieee80211_hw *hw)
+{
+ ieee80211_rate_control_register(&rs_ops);
+}
+
+void iwl_rate_control_unregister(struct ieee80211_hw *hw)
+{
+ ieee80211_rate_control_unregister(&rs_ops);
+}
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
new file mode 100644
index 00000000000..c6325f72df6
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
@@ -0,0 +1,266 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_4965_rs_h__
+#define __iwl_4965_rs_h__
+
+#include "iwl-4965.h"
+
+struct iwl_rate_info {
+ u8 plcp;
+ u8 plcp_siso;
+ u8 plcp_mimo;
+ u8 ieee;
+ u8 prev_ieee; /* previous rate in IEEE speeds */
+ u8 next_ieee; /* next rate in IEEE speeds */
+ u8 prev_rs; /* previous rate used in rs algo */
+ u8 next_rs; /* next rate used in rs algo */
+ u8 prev_rs_tgg; /* previous rate used in TGG rs algo */
+ u8 next_rs_tgg; /* next rate used in TGG rs algo */
+};
+
+enum {
+ IWL_RATE_1M_INDEX = 0,
+ IWL_RATE_2M_INDEX,
+ IWL_RATE_5M_INDEX,
+ IWL_RATE_11M_INDEX,
+ IWL_RATE_6M_INDEX,
+ IWL_RATE_9M_INDEX,
+ IWL_RATE_12M_INDEX,
+ IWL_RATE_18M_INDEX,
+ IWL_RATE_24M_INDEX,
+ IWL_RATE_36M_INDEX,
+ IWL_RATE_48M_INDEX,
+ IWL_RATE_54M_INDEX,
+ IWL_RATE_60M_INDEX,
+ IWL_RATE_COUNT,
+ IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
+ IWL_RATE_INVALID = IWL_RATE_INVM_INDEX
+};
+
+enum {
+ IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
+ IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
+ IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
+ IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
+};
+
+/* #define vs. enum to keep from defaulting to 'large integer' */
+#define IWL_RATE_6M_MASK (1<<IWL_RATE_6M_INDEX)
+#define IWL_RATE_9M_MASK (1<<IWL_RATE_9M_INDEX)
+#define IWL_RATE_12M_MASK (1<<IWL_RATE_12M_INDEX)
+#define IWL_RATE_18M_MASK (1<<IWL_RATE_18M_INDEX)
+#define IWL_RATE_24M_MASK (1<<IWL_RATE_24M_INDEX)
+#define IWL_RATE_36M_MASK (1<<IWL_RATE_36M_INDEX)
+#define IWL_RATE_48M_MASK (1<<IWL_RATE_48M_INDEX)
+#define IWL_RATE_54M_MASK (1<<IWL_RATE_54M_INDEX)
+#define IWL_RATE_60M_MASK (1<<IWL_RATE_60M_INDEX)
+#define IWL_RATE_1M_MASK (1<<IWL_RATE_1M_INDEX)
+#define IWL_RATE_2M_MASK (1<<IWL_RATE_2M_INDEX)
+#define IWL_RATE_5M_MASK (1<<IWL_RATE_5M_INDEX)
+#define IWL_RATE_11M_MASK (1<<IWL_RATE_11M_INDEX)
+
+enum {
+ IWL_RATE_6M_PLCP = 13,
+ IWL_RATE_9M_PLCP = 15,
+ IWL_RATE_12M_PLCP = 5,
+ IWL_RATE_18M_PLCP = 7,
+ IWL_RATE_24M_PLCP = 9,
+ IWL_RATE_36M_PLCP = 11,
+ IWL_RATE_48M_PLCP = 1,
+ IWL_RATE_54M_PLCP = 3,
+ IWL_RATE_60M_PLCP = 3,
+ IWL_RATE_1M_PLCP = 10,
+ IWL_RATE_2M_PLCP = 20,
+ IWL_RATE_5M_PLCP = 55,
+ IWL_RATE_11M_PLCP = 110,
+};
+
+/* OFDM HT rate plcp */
+enum {
+ IWL_RATE_SISO_6M_PLCP = 0,
+ IWL_RATE_SISO_12M_PLCP = 1,
+ IWL_RATE_SISO_18M_PLCP = 2,
+ IWL_RATE_SISO_24M_PLCP = 3,
+ IWL_RATE_SISO_36M_PLCP = 4,
+ IWL_RATE_SISO_48M_PLCP = 5,
+ IWL_RATE_SISO_54M_PLCP = 6,
+ IWL_RATE_SISO_60M_PLCP = 7,
+ IWL_RATE_MIMO_6M_PLCP = 0x8,
+ IWL_RATE_MIMO_12M_PLCP = 0x9,
+ IWL_RATE_MIMO_18M_PLCP = 0xa,
+ IWL_RATE_MIMO_24M_PLCP = 0xb,
+ IWL_RATE_MIMO_36M_PLCP = 0xc,
+ IWL_RATE_MIMO_48M_PLCP = 0xd,
+ IWL_RATE_MIMO_54M_PLCP = 0xe,
+ IWL_RATE_MIMO_60M_PLCP = 0xf,
+ IWL_RATE_SISO_INVM_PLCP,
+ IWL_RATE_MIMO_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
+};
+
+enum {
+ IWL_RATE_6M_IEEE = 12,
+ IWL_RATE_9M_IEEE = 18,
+ IWL_RATE_12M_IEEE = 24,
+ IWL_RATE_18M_IEEE = 36,
+ IWL_RATE_24M_IEEE = 48,
+ IWL_RATE_36M_IEEE = 72,
+ IWL_RATE_48M_IEEE = 96,
+ IWL_RATE_54M_IEEE = 108,
+ IWL_RATE_60M_IEEE = 120,
+ IWL_RATE_1M_IEEE = 2,
+ IWL_RATE_2M_IEEE = 4,
+ IWL_RATE_5M_IEEE = 11,
+ IWL_RATE_11M_IEEE = 22,
+};
+
+#define IWL_CCK_BASIC_RATES_MASK \
+ (IWL_RATE_1M_MASK | \
+ IWL_RATE_2M_MASK)
+
+#define IWL_CCK_RATES_MASK \
+ (IWL_BASIC_RATES_MASK | \
+ IWL_RATE_5M_MASK | \
+ IWL_RATE_11M_MASK)
+
+#define IWL_OFDM_BASIC_RATES_MASK \
+ (IWL_RATE_6M_MASK | \
+ IWL_RATE_12M_MASK | \
+ IWL_RATE_24M_MASK)
+
+#define IWL_OFDM_RATES_MASK \
+ (IWL_OFDM_BASIC_RATES_MASK | \
+ IWL_RATE_9M_MASK | \
+ IWL_RATE_18M_MASK | \
+ IWL_RATE_36M_MASK | \
+ IWL_RATE_48M_MASK | \
+ IWL_RATE_54M_MASK)
+
+#define IWL_BASIC_RATES_MASK \
+ (IWL_OFDM_BASIC_RATES_MASK | \
+ IWL_CCK_BASIC_RATES_MASK)
+
+#define IWL_RATES_MASK ((1<<IWL_RATE_COUNT)-1)
+
+#define IWL_INVALID_VALUE -1
+
+#define IWL_MIN_RSSI_VAL -100
+#define IWL_MAX_RSSI_VAL 0
+
+#define IWL_LEGACY_SWITCH_ANTENNA 0
+#define IWL_LEGACY_SWITCH_SISO 1
+#define IWL_LEGACY_SWITCH_MIMO 2
+
+#define IWL_RS_GOOD_RATIO 12800
+
+#define IWL_ACTION_LIMIT 3
+#define IWL_LEGACY_FAILURE_LIMIT 160
+#define IWL_LEGACY_SUCCESS_LIMIT 480
+#define IWL_LEGACY_TABLE_COUNT 160
+
+#define IWL_NONE_LEGACY_FAILURE_LIMIT 400
+#define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500
+#define IWL_NONE_LEGACY_TABLE_COUNT 1500
+
+#define IWL_RATE_SCALE_SWITCH (10880)
+
+#define IWL_SISO_SWITCH_ANTENNA 0
+#define IWL_SISO_SWITCH_MIMO 1
+#define IWL_SISO_SWITCH_GI 2
+
+#define IWL_MIMO_SWITCH_ANTENNA_A 0
+#define IWL_MIMO_SWITCH_ANTENNA_B 1
+#define IWL_MIMO_SWITCH_GI 2
+
+#define LQ_SIZE 2
+
+extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
+
+enum iwl_table_type {
+ LQ_NONE,
+ LQ_G,
+ LQ_A,
+ LQ_SISO,
+ LQ_MIMO,
+ LQ_MAX,
+};
+
+enum iwl_antenna_type {
+ ANT_NONE,
+ ANT_MAIN,
+ ANT_AUX,
+ ANT_BOTH,
+};
+
+static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
+{
+ u8 rate = iwl_rates[rate_index].prev_ieee;
+
+ if (rate == IWL_RATE_INVALID)
+ rate = rate_index;
+ return rate;
+}
+
+extern int iwl_rate_index_from_plcp(int plcp);
+
+/**
+ * iwl_fill_rs_info - Fill an output text buffer with the rate representation
+ *
+ * NOTE: This is provided as a quick mechanism for a user to visualize
+ * the performance of the rate control alogirthm and is not meant to be
+ * parsed software.
+ */
+extern int iwl_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
+
+/**
+ * iwl_rate_scale_init - Initialize the rate scale table based on assoc info
+ *
+ * The specific througput table used is based on the type of network
+ * the associated with, including A, B, G, and G w/ TGG protection
+ */
+extern void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
+
+/**
+ * iwl_rate_control_register - Register the rate control algorithm callbacks
+ *
+ * Since the rate control algorithm is hardware specific, there is no need
+ * or reason to place it as a stand alone module. The driver can call
+ * iwl_rate_control_register in order to register the rate control callbacks
+ * with the mac80211 subsystem. This should be performed prior to calling
+ * ieee80211_register_hw
+ *
+ */
+extern void iwl_rate_control_register(struct ieee80211_hw *hw);
+
+/**
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
+ *
+ * This should be called after calling ieee80211_unregister_hw, but before
+ * the driver is unloaded.
+ */
+extern void iwl_rate_control_unregister(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
new file mode 100644
index 00000000000..891f90d2f01
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -0,0 +1,4732 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+#include <linux/etherdevice.h>
+
+#define IWL 4965
+
+#include "iwlwifi.h"
+#include "iwl-4965.h"
+#include "iwl-helpers.h"
+
+#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \
+ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \
+ IWL_RATE_SISO_##s##M_PLCP, \
+ IWL_RATE_MIMO_##s##M_PLCP, \
+ IWL_RATE_##r##M_IEEE, \
+ IWL_RATE_##ip##M_INDEX, \
+ IWL_RATE_##in##M_INDEX, \
+ IWL_RATE_##rp##M_INDEX, \
+ IWL_RATE_##rn##M_INDEX, \
+ IWL_RATE_##pp##M_INDEX, \
+ IWL_RATE_##np##M_INDEX }
+
+/*
+ * Parameter order:
+ * rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
+ *
+ * If there isn't a valid next or previous rate then INV is used which
+ * maps to IWL_RATE_INVALID
+ *
+ */
+const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+ IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */
+ IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */
+ IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */
+ IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18), /* 11mbps */
+ IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11), /* 6mbps */
+ IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11), /* 9mbps */
+ IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18), /* 12mbps */
+ IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24), /* 18mbps */
+ IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36), /* 24mbps */
+ IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48), /* 36mbps */
+ IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54), /* 48mbps */
+ IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
+ IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
+};
+
+static int is_fat_channel(__le32 rxon_flags)
+{
+ return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||
+ (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK);
+}
+
+static u8 is_single_stream(struct iwl_priv *priv)
+{
+#ifdef CONFIG_IWLWIFI_HT
+ if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht ||
+ (priv->active_rate_ht[1] == 0) ||
+ (priv->ps_mode == IWL_MIMO_PS_STATIC))
+ return 1;
+#else
+ return 1;
+#endif /*CONFIG_IWLWIFI_HT */
+ return 0;
+}
+
+/*
+ * Determine how many receiver/antenna chains to use.
+ * More provides better reception via diversity. Fewer saves power.
+ * MIMO (dual stream) requires at least 2, but works better with 3.
+ * This does not determine *which* chains to use, just how many.
+ */
+static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv,
+ u8 *idle_state, u8 *rx_state)
+{
+ u8 is_single = is_single_stream(priv);
+ u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;
+
+ /* # of Rx chains to use when expecting MIMO. */
+ if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
+ *rx_state = 2;
+ else
+ *rx_state = 3;
+
+ /* # Rx chains when idling and maybe trying to save power */
+ switch (priv->ps_mode) {
+ case IWL_MIMO_PS_STATIC:
+ case IWL_MIMO_PS_DYNAMIC:
+ *idle_state = (is_cam) ? 2 : 1;
+ break;
+ case IWL_MIMO_PS_NONE:
+ *idle_state = (is_cam) ? *rx_state : 1;
+ break;
+ default:
+ *idle_state = 1;
+ break;
+ }
+
+ return 0;
+}
+
+int iwl_hw_rxq_stop(struct iwl_priv *priv)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ /* stop HW */
+ iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+ rc = iwl_poll_restricted_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
+ (1 << 24), 1000);
+ if (rc < 0)
+ IWL_ERROR("Can't stop Rx DMA.\n");
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr)
+{
+ int i;
+ int start = 0;
+ int ret = IWL_INVALID_STATION;
+ unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
+ (priv->iw_mode == IEEE80211_IF_TYPE_AP))
+ start = IWL_STA_ID;
+
+ if (is_broadcast_ether_addr(addr))
+ return IWL4965_BROADCAST_ID;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ for (i = start; i < priv->hw_setting.max_stations; i++)
+ if ((priv->stations[i].used) &&
+ (!compare_ether_addr
+ (priv->stations[i].sta.sta.addr, addr))) {
+ ret = i;
+ goto out;
+ }
+
+ IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",
+ print_mac(mac, addr), priv->num_stations);
+
+ out:
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return ret;
+}
+
+static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ if (!pwr_max) {
+ u32 val;
+
+ rc = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE,
+ &val);
+
+ if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT)
+ iwl_set_bits_mask_restricted_reg(
+ priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
+ } else
+ iwl_set_bits_mask_restricted_reg(
+ priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+ ~APMG_PS_CTRL_MSK_PWR_SRC);
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return rc;
+}
+
+static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ /* stop HW */
+ iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+
+ iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
+ iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+ rxq->dma_addr >> 8);
+
+ iwl_write_restricted(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
+ (priv->hw_setting.shared_phys +
+ offsetof(struct iwl_shared, val0)) >> 4);
+
+ iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
+ FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
+ FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
+ IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K |
+ /*0x10 << 4 | */
+ (RX_QUEUE_SIZE_LOG <<
+ FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
+
+ /*
+ * iwl_write32(priv,CSR_INT_COAL_REG,0);
+ */
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int iwl4965_kw_init(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ goto out;
+
+ iwl_write_restricted(priv, IWL_FH_KW_MEM_ADDR_REG,
+ priv->kw.dma_addr >> 4);
+ iwl_release_restricted_access(priv);
+out:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+}
+
+static int iwl4965_kw_alloc(struct iwl_priv *priv)
+{
+ struct pci_dev *dev = priv->pci_dev;
+ struct iwl_kw *kw = &priv->kw;
+
+ kw->size = IWL4965_KW_SIZE; /* TBW need set somewhere else */
+ kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
+ if (!kw->v_addr)
+ return -ENOMEM;
+
+ return 0;
+}
+
+#define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \
+ ? # x " " : "")
+
+int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, u16 channel,
+ const struct iwl_eeprom_channel *eeprom_ch,
+ u8 fat_extension_channel)
+{
+ struct iwl_channel_info *ch_info;
+
+ ch_info = (struct iwl_channel_info *)
+ iwl_get_channel_info(priv, phymode, channel);
+
+ if (!is_channel_valid(ch_info))
+ return -1;
+
+ IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+ " %ddBm): Ad-Hoc %ssupported\n",
+ ch_info->channel,
+ is_channel_a_band(ch_info) ?
+ "5.2" : "2.4",
+ CHECK_AND_PRINT(IBSS),
+ CHECK_AND_PRINT(ACTIVE),
+ CHECK_AND_PRINT(RADAR),
+ CHECK_AND_PRINT(WIDE),
+ CHECK_AND_PRINT(NARROW),
+ CHECK_AND_PRINT(DFS),
+ eeprom_ch->flags,
+ eeprom_ch->max_power_avg,
+ ((eeprom_ch->flags & EEPROM_CHANNEL_IBSS)
+ && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ?
+ "" : "not ");
+
+ ch_info->fat_eeprom = *eeprom_ch;
+ ch_info->fat_max_power_avg = eeprom_ch->max_power_avg;
+ ch_info->fat_curr_txpow = eeprom_ch->max_power_avg;
+ ch_info->fat_min_power = 0;
+ ch_info->fat_scan_power = eeprom_ch->max_power_avg;
+ ch_info->fat_flags = eeprom_ch->flags;
+ ch_info->fat_extension_channel = fat_extension_channel;
+
+ return 0;
+}
+
+static void iwl4965_kw_free(struct iwl_priv *priv)
+{
+ struct pci_dev *dev = priv->pci_dev;
+ struct iwl_kw *kw = &priv->kw;
+
+ if (kw->v_addr) {
+ pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
+ memset(kw, 0, sizeof(*kw));
+ }
+}
+
+/**
+ * iwl4965_txq_ctx_reset - Reset TX queue context
+ * Destroys all DMA structures and initialise them again
+ *
+ * @param priv
+ * @return error code
+ */
+static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
+{
+ int rc = 0;
+ int txq_id, slots_num;
+ unsigned long flags;
+
+ iwl4965_kw_free(priv);
+
+ iwl_hw_txq_ctx_free(priv);
+
+ /* Tx CMD queue */
+ rc = iwl4965_kw_alloc(priv);
+ if (rc) {
+ IWL_ERROR("Keep Warm allocation failed");
+ goto error_kw;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (unlikely(rc)) {
+ IWL_ERROR("TX reset failed");
+ spin_unlock_irqrestore(&priv->lock, flags);
+ goto error_reset;
+ }
+
+ iwl_write_restricted_reg(priv, SCD_TXFACT, 0);
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ rc = iwl4965_kw_init(priv);
+ if (rc) {
+ IWL_ERROR("kw_init failed\n");
+ goto error_reset;
+ }
+
+ /* Tx queue(s) */
+ for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
+ slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+ TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+ rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
+ txq_id);
+ if (rc) {
+ IWL_ERROR("Tx %d queue init failed\n", txq_id);
+ goto error;
+ }
+ }
+
+ return rc;
+
+ error:
+ iwl_hw_txq_ctx_free(priv);
+ error_reset:
+ iwl4965_kw_free(priv);
+ error_kw:
+ return rc;
+}
+
+int iwl_hw_nic_init(struct iwl_priv *priv)
+{
+ int rc;
+ unsigned long flags;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ u8 rev_id;
+ u32 val;
+ u8 val_link;
+
+ iwl_power_init_handle(priv);
+
+ /* nic_init */
+ spin_lock_irqsave(&priv->lock, flags);
+
+ iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+ CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ if (rc < 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_INFO("Failed to init the card\n");
+ return rc;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG);
+
+ iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT |
+ APMG_CLK_VAL_BSM_CLK_RQT);
+ iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG);
+
+ udelay(20);
+
+ iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+ iwl_release_restricted_access(priv);
+ iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Determine HW type */
+ rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);
+ if (rc)
+ return rc;
+
+ IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id);
+
+ iwl4965_nic_set_pwr_src(priv, 1);
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if ((rev_id & 0x80) == 0x80 && (rev_id & 0x7f) < 8) {
+ pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val);
+ /* Enable No Snoop field */
+ pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8,
+ val & ~(1 << 11));
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Read the EEPROM */
+ rc = iwl_eeprom_init(priv);
+ if (rc)
+ return rc;
+
+ if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) {
+ IWL_ERROR("Older EEPROM detected! Aborting.\n");
+ return -EINVAL;
+ }
+
+ pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link);
+
+ /* disable L1 entry -- workaround for pre-B1 */
+ pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* set CSR_HW_CONFIG_REG for uCode use */
+
+ iwl_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R |
+ CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+ CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc < 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_INFO("Failed to init the card\n");
+ return rc;
+ }
+
+ iwl_read_restricted_reg(priv, APMG_PS_CTRL_REG);
+ iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_RESET_REQ);
+ udelay(5);
+ iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+ APMG_PS_CTRL_VAL_RESET_REQ);
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_hw_card_show_info(priv);
+
+ /* end nic_init */
+
+ /* Allocate the RX queue, or reset if it is already allocated */
+ if (!rxq->bd) {
+ rc = iwl_rx_queue_alloc(priv);
+ if (rc) {
+ IWL_ERROR("Unable to initialize Rx queue\n");
+ return -ENOMEM;
+ }
+ } else
+ iwl_rx_queue_reset(priv, rxq);
+
+ iwl_rx_replenish(priv);
+
+ iwl4965_rx_init(priv, rxq);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ rxq->need_update = 1;
+ iwl_rx_queue_update_write_ptr(priv, rxq);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ rc = iwl4965_txq_ctx_reset(priv);
+ if (rc)
+ return rc;
+
+ if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE)
+ IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n");
+
+ if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
+ IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n");
+
+ set_bit(STATUS_INIT, &priv->status);
+
+ return 0;
+}
+
+int iwl_hw_nic_stop_master(struct iwl_priv *priv)
+{
+ int rc = 0;
+ u32 reg_val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* set stop master bit */
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+
+ reg_val = iwl_read32(priv, CSR_GP_CNTRL);
+
+ if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE ==
+ (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE))
+ IWL_DEBUG_INFO("Card in power save, master is already "
+ "stopped\n");
+ else {
+ rc = iwl_poll_bit(priv, CSR_RESET,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED,
+ CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
+ if (rc < 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_INFO("stop master\n");
+
+ return rc;
+}
+
+void iwl_hw_txq_ctx_stop(struct iwl_priv *priv)
+{
+
+ int txq_id;
+ unsigned long flags;
+
+ /* reset TFD queues */
+ for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
+ spin_lock_irqsave(&priv->lock, flags);
+ if (iwl_grab_restricted_access(priv)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ continue;
+ }
+
+ iwl_write_restricted(priv,
+ IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
+ 0x0);
+ iwl_poll_restricted_bit(priv, IWL_FH_TSSR_TX_STATUS_REG,
+ IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
+ (txq_id), 200);
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ iwl_hw_txq_ctx_free(priv);
+}
+
+int iwl_hw_nic_reset(struct iwl_priv *priv)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ iwl_hw_nic_stop_master(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+ udelay(10);
+
+ iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ rc = iwl_poll_bit(priv, CSR_RESET,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25);
+
+ udelay(10);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (!rc) {
+ iwl_write_restricted_reg(priv, APMG_CLK_EN_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT |
+ APMG_CLK_VAL_BSM_CLK_RQT);
+
+ udelay(10);
+
+ iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+ iwl_release_restricted_access(priv);
+ }
+
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return rc;
+
+}
+
+#define REG_RECALIB_PERIOD (60)
+
+/**
+ * iwl4965_bg_statistics_periodic - Timer callback to queue statistics
+ *
+ * This callback is provided in order to queue the statistics_work
+ * in work_queue context (v. softirq)
+ *
+ * This timer function is continually reset to execute within
+ * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION
+ * was received. We need to ensure we receive the statistics in order
+ * to update the temperature used for calibrating the TXPOWER. However,
+ * we can't send the statistics command from softirq context (which
+ * is the context which timers run at) so we have to queue off the
+ * statistics_work to actually send the command to the hardware.
+ */
+static void iwl4965_bg_statistics_periodic(unsigned long data)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)data;
+
+ queue_work(priv->workqueue, &priv->statistics_work);
+}
+
+/**
+ * iwl4965_bg_statistics_work - Send the statistics request to the hardware.
+ *
+ * This is queued by iwl_bg_statistics_periodic.
+ */
+static void iwl4965_bg_statistics_work(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ statistics_work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_send_statistics_request(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+#define CT_LIMIT_CONST 259
+#define TM_CT_KILL_THRESHOLD 110
+
+void iwl4965_rf_kill_ct_config(struct iwl_priv *priv)
+{
+ struct iwl_ct_kill_config cmd;
+ u32 R1, R2, R3;
+ u32 temp_th;
+ u32 crit_temperature;
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK) {
+ R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
+ R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
+ R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]);
+ } else {
+ R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]);
+ R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]);
+ R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]);
+ }
+
+ temp_th = CELSIUS_TO_KELVIN(TM_CT_KILL_THRESHOLD);
+
+ crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2;
+ cmd.critical_temperature_R = cpu_to_le32(crit_temperature);
+ rc = iwl_send_cmd_pdu(priv,
+ REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd);
+ if (rc)
+ IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n");
+ else
+ IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n");
+}
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+
+/* "false alarms" are signals that our DSP tries to lock onto,
+ * but then determines that they are either noise, or transmissions
+ * from a distant wireless network (also "noise", really) that get
+ * "stepped on" by stronger transmissions within our own network.
+ * This algorithm attempts to set a sensitivity level that is high
+ * enough to receive all of our own network traffic, but not so
+ * high that our DSP gets too busy trying to lock onto non-network
+ * activity/noise. */
+static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
+ u32 norm_fa,
+ u32 rx_enable_time,
+ struct statistics_general_data *rx_info)
+{
+ u32 max_nrg_cck = 0;
+ int i = 0;
+ u8 max_silence_rssi = 0;
+ u32 silence_ref = 0;
+ u8 silence_rssi_a = 0;
+ u8 silence_rssi_b = 0;
+ u8 silence_rssi_c = 0;
+ u32 val;
+
+ /* "false_alarms" values below are cross-multiplications to assess the
+ * numbers of false alarms within the measured period of actual Rx
+ * (Rx is off when we're txing), vs the min/max expected false alarms
+ * (some should be expected if rx is sensitive enough) in a
+ * hypothetical listening period of 200 time units (TU), 204.8 msec:
+ *
+ * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time
+ *
+ * */
+ u32 false_alarms = norm_fa * 200 * 1024;
+ u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
+ u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
+ struct iwl_sensitivity_data *data = NULL;
+
+ data = &(priv->sensitivity_data);
+
+ data->nrg_auto_corr_silence_diff = 0;
+
+ /* Find max silence rssi among all 3 receivers.
+ * This is background noise, which may include transmissions from other
+ * networks, measured during silence before our network's beacon */
+ silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a &
+ ALL_BAND_FILTER)>>8);
+ silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b &
+ ALL_BAND_FILTER)>>8);
+ silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c &
+ ALL_BAND_FILTER)>>8);
+
+ val = max(silence_rssi_b, silence_rssi_c);
+ max_silence_rssi = max(silence_rssi_a, (u8) val);
+
+ /* Store silence rssi in 20-beacon history table */
+ data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi;
+ data->nrg_silence_idx++;
+ if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L)
+ data->nrg_silence_idx = 0;
+
+ /* Find max silence rssi across 20 beacon history */
+ for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) {
+ val = data->nrg_silence_rssi[i];
+ silence_ref = max(silence_ref, val);
+ }
+ IWL_DEBUG_CALIB("silence a %u, b %u, c %u, 20-bcn max %u\n",
+ silence_rssi_a, silence_rssi_b, silence_rssi_c,
+ silence_ref);
+
+ /* Find max rx energy (min value!) among all 3 receivers,
+ * measured during beacon frame.
+ * Save it in 10-beacon history table. */
+ i = data->nrg_energy_idx;
+ val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c);
+ data->nrg_value[i] = min(rx_info->beacon_energy_a, val);
+
+ data->nrg_energy_idx++;
+ if (data->nrg_energy_idx >= 10)
+ data->nrg_energy_idx = 0;
+
+ /* Find min rx energy (max value) across 10 beacon history.
+ * This is the minimum signal level that we want to receive well.
+ * Add backoff (margin so we don't miss slightly lower energy frames).
+ * This establishes an upper bound (min value) for energy threshold. */
+ max_nrg_cck = data->nrg_value[0];
+ for (i = 1; i < 10; i++)
+ max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i]));
+ max_nrg_cck += 6;
+
+ IWL_DEBUG_CALIB("rx energy a %u, b %u, c %u, 10-bcn max/min %u\n",
+ rx_info->beacon_energy_a, rx_info->beacon_energy_b,
+ rx_info->beacon_energy_c, max_nrg_cck - 6);
+
+ /* Count number of consecutive beacons with fewer-than-desired
+ * false alarms. */
+ if (false_alarms < min_false_alarms)
+ data->num_in_cck_no_fa++;
+ else
+ data->num_in_cck_no_fa = 0;
+ IWL_DEBUG_CALIB("consecutive bcns with few false alarms = %u\n",
+ data->num_in_cck_no_fa);
+
+ /* If we got too many false alarms this time, reduce sensitivity */
+ if (false_alarms > max_false_alarms) {
+ IWL_DEBUG_CALIB("norm FA %u > max FA %u\n",
+ false_alarms, max_false_alarms);
+ IWL_DEBUG_CALIB("... reducing sensitivity\n");
+ data->nrg_curr_state = IWL_FA_TOO_MANY;
+
+ if (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK) {
+ /* Store for "fewer than desired" on later beacon */
+ data->nrg_silence_ref = silence_ref;
+
+ /* increase energy threshold (reduce nrg value)
+ * to decrease sensitivity */
+ if (data->nrg_th_cck > (NRG_MAX_CCK + NRG_STEP_CCK))
+ data->nrg_th_cck = data->nrg_th_cck
+ - NRG_STEP_CCK;
+ }
+
+ /* increase auto_corr values to decrease sensitivity */
+ if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK)
+ data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1;
+ else {
+ val = data->auto_corr_cck + AUTO_CORR_STEP_CCK;
+ data->auto_corr_cck = min((u32)AUTO_CORR_MAX_CCK, val);
+ }
+ val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK;
+ data->auto_corr_cck_mrc = min((u32)AUTO_CORR_MAX_CCK_MRC, val);
+
+ /* Else if we got fewer than desired, increase sensitivity */
+ } else if (false_alarms < min_false_alarms) {
+ data->nrg_curr_state = IWL_FA_TOO_FEW;
+
+ /* Compare silence level with silence level for most recent
+ * healthy number or too many false alarms */
+ data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref -
+ (s32)silence_ref;
+
+ IWL_DEBUG_CALIB("norm FA %u < min FA %u, silence diff %d\n",
+ false_alarms, min_false_alarms,
+ data->nrg_auto_corr_silence_diff);
+
+ /* Increase value to increase sensitivity, but only if:
+ * 1a) previous beacon did *not* have *too many* false alarms
+ * 1b) AND there's a significant difference in Rx levels
+ * from a previous beacon with too many, or healthy # FAs
+ * OR 2) We've seen a lot of beacons (100) with too few
+ * false alarms */
+ if ((data->nrg_prev_state != IWL_FA_TOO_MANY) &&
+ ((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
+ (data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
+
+ IWL_DEBUG_CALIB("... increasing sensitivity\n");
+ /* Increase nrg value to increase sensitivity */
+ val = data->nrg_th_cck + NRG_STEP_CCK;
+ data->nrg_th_cck = min((u32)NRG_MIN_CCK, val);
+
+ /* Decrease auto_corr values to increase sensitivity */
+ val = data->auto_corr_cck - AUTO_CORR_STEP_CCK;
+ data->auto_corr_cck = max((u32)AUTO_CORR_MIN_CCK, val);
+
+ val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK;
+ data->auto_corr_cck_mrc =
+ max((u32)AUTO_CORR_MIN_CCK_MRC, val);
+
+ } else
+ IWL_DEBUG_CALIB("... but not changing sensitivity\n");
+
+ /* Else we got a healthy number of false alarms, keep status quo */
+ } else {
+ IWL_DEBUG_CALIB(" FA in safe zone\n");
+ data->nrg_curr_state = IWL_FA_GOOD_RANGE;
+
+ /* Store for use in "fewer than desired" with later beacon */
+ data->nrg_silence_ref = silence_ref;
+
+ /* If previous beacon had too many false alarms,
+ * give it some extra margin by reducing sensitivity again
+ * (but don't go below measured energy of desired Rx) */
+ if (IWL_FA_TOO_MANY == data->nrg_prev_state) {
+ IWL_DEBUG_CALIB("... increasing margin\n");
+ data->nrg_th_cck -= NRG_MARGIN;
+ }
+ }
+
+ /* Make sure the energy threshold does not go above the measured
+ * energy of the desired Rx signals (reduced by backoff margin),
+ * or else we might start missing Rx frames.
+ * Lower value is higher energy, so we use max()!
+ */
+ data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
+ IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck);
+
+ data->nrg_prev_state = data->nrg_curr_state;
+
+ return 0;
+}
+
+
+static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv,
+ u32 norm_fa,
+ u32 rx_enable_time)
+{
+ u32 val;
+ u32 false_alarms = norm_fa * 200 * 1024;
+ u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
+ u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
+ struct iwl_sensitivity_data *data = NULL;
+
+ data = &(priv->sensitivity_data);
+
+ /* If we got too many false alarms this time, reduce sensitivity */
+ if (false_alarms > max_false_alarms) {
+
+ IWL_DEBUG_CALIB("norm FA %u > max FA %u)\n",
+ false_alarms, max_false_alarms);
+
+ val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm =
+ min((u32)AUTO_CORR_MAX_OFDM, val);
+
+ val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_mrc =
+ min((u32)AUTO_CORR_MAX_OFDM_MRC, val);
+
+ val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_x1 =
+ min((u32)AUTO_CORR_MAX_OFDM_X1, val);
+
+ val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_mrc_x1 =
+ min((u32)AUTO_CORR_MAX_OFDM_MRC_X1, val);
+ }
+
+ /* Else if we got fewer than desired, increase sensitivity */
+ else if (false_alarms < min_false_alarms) {
+
+ IWL_DEBUG_CALIB("norm FA %u < min FA %u\n",
+ false_alarms, min_false_alarms);
+
+ val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm =
+ max((u32)AUTO_CORR_MIN_OFDM, val);
+
+ val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_mrc =
+ max((u32)AUTO_CORR_MIN_OFDM_MRC, val);
+
+ val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_x1 =
+ max((u32)AUTO_CORR_MIN_OFDM_X1, val);
+
+ val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM;
+ data->auto_corr_ofdm_mrc_x1 =
+ max((u32)AUTO_CORR_MIN_OFDM_MRC_X1, val);
+ }
+
+ else
+ IWL_DEBUG_CALIB("min FA %u < norm FA %u < max FA %u OK\n",
+ min_false_alarms, false_alarms, max_false_alarms);
+
+ return 0;
+}
+
+static int iwl_sensitivity_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+ /* We didn't cache the SKB; let the caller free it */
+ return 1;
+}
+
+/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
+static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags)
+{
+ int rc = 0;
+ struct iwl_sensitivity_cmd cmd ;
+ struct iwl_sensitivity_data *data = NULL;
+ struct iwl_host_cmd cmd_out = {
+ .id = SENSITIVITY_CMD,
+ .len = sizeof(struct iwl_sensitivity_cmd),
+ .meta.flags = flags,
+ .data = &cmd,
+ };
+
+ data = &(priv->sensitivity_data);
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_ofdm);
+ cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
+ cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_ofdm_x1);
+ cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
+
+ cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_cck);
+ cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
+ cpu_to_le16((u16)data->auto_corr_cck_mrc);
+
+ cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] =
+ cpu_to_le16((u16)data->nrg_th_cck);
+ cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] =
+ cpu_to_le16((u16)data->nrg_th_ofdm);
+
+ cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
+ __constant_cpu_to_le16(190);
+ cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
+ __constant_cpu_to_le16(390);
+ cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] =
+ __constant_cpu_to_le16(62);
+
+ IWL_DEBUG_CALIB("ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
+ data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
+ data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1,
+ data->nrg_th_ofdm);
+
+ IWL_DEBUG_CALIB("cck: ac %u mrc %u thresh %u\n",
+ data->auto_corr_cck, data->auto_corr_cck_mrc,
+ data->nrg_th_cck);
+
+ cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
+
+ if (flags & CMD_ASYNC)
+ cmd_out.meta.u.callback = iwl_sensitivity_callback;
+
+ /* Don't send command to uCode if nothing has changed */
+ if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]),
+ sizeof(u16)*HD_TABLE_SIZE)) {
+ IWL_DEBUG_CALIB("No change in SENSITIVITY_CMD\n");
+ return 0;
+ }
+
+ /* Copy table for comparison next time */
+ memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
+ sizeof(u16)*HD_TABLE_SIZE);
+
+ rc = iwl_send_cmd(priv, &cmd_out);
+ if (!rc) {
+ IWL_DEBUG_CALIB("SENSITIVITY_CMD succeeded\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force)
+{
+ int rc = 0;
+ int i;
+ struct iwl_sensitivity_data *data = NULL;
+
+ IWL_DEBUG_CALIB("Start iwl4965_init_sensitivity\n");
+
+ if (force)
+ memset(&(priv->sensitivity_tbl[0]), 0,
+ sizeof(u16)*HD_TABLE_SIZE);
+
+ /* Clear driver's sensitivity algo data */
+ data = &(priv->sensitivity_data);
+ memset(data, 0, sizeof(struct iwl_sensitivity_data));
+
+ data->num_in_cck_no_fa = 0;
+ data->nrg_curr_state = IWL_FA_TOO_MANY;
+ data->nrg_prev_state = IWL_FA_TOO_MANY;
+ data->nrg_silence_ref = 0;
+ data->nrg_silence_idx = 0;
+ data->nrg_energy_idx = 0;
+
+ for (i = 0; i < 10; i++)
+ data->nrg_value[i] = 0;
+
+ for (i = 0; i < NRG_NUM_PREV_STAT_L; i++)
+ data->nrg_silence_rssi[i] = 0;
+
+ data->auto_corr_ofdm = 90;
+ data->auto_corr_ofdm_mrc = 170;
+ data->auto_corr_ofdm_x1 = 105;
+ data->auto_corr_ofdm_mrc_x1 = 220;
+ data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF;
+ data->auto_corr_cck_mrc = 200;
+ data->nrg_th_cck = 100;
+ data->nrg_th_ofdm = 100;
+
+ data->last_bad_plcp_cnt_ofdm = 0;
+ data->last_fa_cnt_ofdm = 0;
+ data->last_bad_plcp_cnt_cck = 0;
+ data->last_fa_cnt_cck = 0;
+
+ /* Clear prior Sensitivity command data to force send to uCode */
+ if (force)
+ memset(&(priv->sensitivity_tbl[0]), 0,
+ sizeof(u16)*HD_TABLE_SIZE);
+
+ rc |= iwl4965_sensitivity_write(priv, flags);
+ IWL_DEBUG_CALIB("<<return 0x%X\n", rc);
+
+ return;
+}
+
+
+/* Reset differential Rx gains in NIC to prepare for chain noise calibration.
+ * Called after every association, but this runs only once!
+ * ... once chain noise is calibrated the first time, it's good forever. */
+void iwl4965_chain_noise_reset(struct iwl_priv *priv)
+{
+ struct iwl_chain_noise_data *data = NULL;
+ int rc = 0;
+
+ data = &(priv->chain_noise_data);
+ if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+ struct iwl_calibration_cmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
+ cmd.diff_gain_a = 0;
+ cmd.diff_gain_b = 0;
+ cmd.diff_gain_c = 0;
+ rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+ sizeof(cmd), &cmd);
+ msleep(4);
+ data->state = IWL_CHAIN_NOISE_ACCUMULATE;
+ IWL_DEBUG_CALIB("Run chain_noise_calibrate\n");
+ }
+ return;
+}
+
+/*
+ * Accumulate 20 beacons of signal and noise statistics for each of
+ * 3 receivers/antennas/rx-chains, then figure out:
+ * 1) Which antennas are connected.
+ * 2) Differential rx gain settings to balance the 3 receivers.
+ */
+static void iwl4965_noise_calibration(struct iwl_priv *priv,
+ struct iwl_notif_statistics *stat_resp)
+{
+ struct iwl_chain_noise_data *data = NULL;
+ int rc = 0;
+
+ u32 chain_noise_a;
+ u32 chain_noise_b;
+ u32 chain_noise_c;
+ u32 chain_sig_a;
+ u32 chain_sig_b;
+ u32 chain_sig_c;
+ u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+ u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+ u32 max_average_sig;
+ u16 max_average_sig_antenna_i;
+ u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE;
+ u16 min_average_noise_antenna_i = INITIALIZATION_VALUE;
+ u16 i = 0;
+ u16 chan_num = INITIALIZATION_VALUE;
+ u32 band = INITIALIZATION_VALUE;
+ u32 active_chains = 0;
+ unsigned long flags;
+ struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general);
+
+ data = &(priv->chain_noise_data);
+
+ /* Accumulate just the first 20 beacons after the first association,
+ * then we're done forever. */
+ if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) {
+ if (data->state == IWL_CHAIN_NOISE_ALIVE)
+ IWL_DEBUG_CALIB("Wait for noise calib reset\n");
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+ IWL_DEBUG_CALIB(" << Interference data unavailable\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ band = (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) ? 0 : 1;
+ chan_num = le16_to_cpu(priv->staging_rxon.channel);
+
+ /* Make sure we accumulate data for just the associated channel
+ * (even if scanning). */
+ if ((chan_num != (le32_to_cpu(stat_resp->flag) >> 16)) ||
+ ((STATISTICS_REPLY_FLG_BAND_24G_MSK ==
+ (stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK)) && band)) {
+ IWL_DEBUG_CALIB("Stats not from chan=%d, band=%d\n",
+ chan_num, band);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ /* Accumulate beacon statistics values across 20 beacons */
+ chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) &
+ IN_BAND_FILTER;
+ chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) &
+ IN_BAND_FILTER;
+ chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) &
+ IN_BAND_FILTER;
+
+ chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER;
+ chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER;
+ chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ data->beacon_count++;
+
+ data->chain_noise_a = (chain_noise_a + data->chain_noise_a);
+ data->chain_noise_b = (chain_noise_b + data->chain_noise_b);
+ data->chain_noise_c = (chain_noise_c + data->chain_noise_c);
+
+ data->chain_signal_a = (chain_sig_a + data->chain_signal_a);
+ data->chain_signal_b = (chain_sig_b + data->chain_signal_b);
+ data->chain_signal_c = (chain_sig_c + data->chain_signal_c);
+
+ IWL_DEBUG_CALIB("chan=%d, band=%d, beacon=%d\n", chan_num, band,
+ data->beacon_count);
+ IWL_DEBUG_CALIB("chain_sig: a %d b %d c %d\n",
+ chain_sig_a, chain_sig_b, chain_sig_c);
+ IWL_DEBUG_CALIB("chain_noise: a %d b %d c %d\n",
+ chain_noise_a, chain_noise_b, chain_noise_c);
+
+ /* If this is the 20th beacon, determine:
+ * 1) Disconnected antennas (using signal strengths)
+ * 2) Differential gain (using silence noise) to balance receivers */
+ if (data->beacon_count == CAL_NUM_OF_BEACONS) {
+
+ /* Analyze signal for disconnected antenna */
+ average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS;
+ average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS;
+ average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS;
+
+ if (average_sig[0] >= average_sig[1]) {
+ max_average_sig = average_sig[0];
+ max_average_sig_antenna_i = 0;
+ active_chains = (1 << max_average_sig_antenna_i);
+ } else {
+ max_average_sig = average_sig[1];
+ max_average_sig_antenna_i = 1;
+ active_chains = (1 << max_average_sig_antenna_i);
+ }
+
+ if (average_sig[2] >= max_average_sig) {
+ max_average_sig = average_sig[2];
+ max_average_sig_antenna_i = 2;
+ active_chains = (1 << max_average_sig_antenna_i);
+ }
+
+ IWL_DEBUG_CALIB("average_sig: a %d b %d c %d\n",
+ average_sig[0], average_sig[1], average_sig[2]);
+ IWL_DEBUG_CALIB("max_average_sig = %d, antenna %d\n",
+ max_average_sig, max_average_sig_antenna_i);
+
+ /* Compare signal strengths for all 3 receivers. */
+ for (i = 0; i < NUM_RX_CHAINS; i++) {
+ if (i != max_average_sig_antenna_i) {
+ s32 rssi_delta = (max_average_sig -
+ average_sig[i]);
+
+ /* If signal is very weak, compared with
+ * strongest, mark it as disconnected. */
+ if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
+ data->disconn_array[i] = 1;
+ else
+ active_chains |= (1 << i);
+ IWL_DEBUG_CALIB("i = %d rssiDelta = %d "
+ "disconn_array[i] = %d\n",
+ i, rssi_delta, data->disconn_array[i]);
+ }
+ }
+
+ /*If both chains A & B are disconnected -
+ * connect B and leave A as is */
+ if (data->disconn_array[CHAIN_A] &&
+ data->disconn_array[CHAIN_B]) {
+ data->disconn_array[CHAIN_B] = 0;
+ active_chains |= (1 << CHAIN_B);
+ IWL_DEBUG_CALIB("both A & B chains are disconnected! "
+ "W/A - declare B as connected\n");
+ }
+
+ IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n",
+ active_chains);
+
+ /* Save for use within RXON, TX, SCAN commands, etc. */
+ priv->valid_antenna = active_chains;
+
+ /* Analyze noise for rx balance */
+ average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS);
+ average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS);
+ average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS);
+
+ for (i = 0; i < NUM_RX_CHAINS; i++) {
+ if (!(data->disconn_array[i]) &&
+ (average_noise[i] <= min_average_noise)) {
+ /* This means that chain i is active and has
+ * lower noise values so far: */
+ min_average_noise = average_noise[i];
+ min_average_noise_antenna_i = i;
+ }
+ }
+
+ data->delta_gain_code[min_average_noise_antenna_i] = 0;
+
+ IWL_DEBUG_CALIB("average_noise: a %d b %d c %d\n",
+ average_noise[0], average_noise[1],
+ average_noise[2]);
+
+ IWL_DEBUG_CALIB("min_average_noise = %d, antenna %d\n",
+ min_average_noise, min_average_noise_antenna_i);
+
+ for (i = 0; i < NUM_RX_CHAINS; i++) {
+ s32 delta_g = 0;
+
+ if (!(data->disconn_array[i]) &&
+ (data->delta_gain_code[i] ==
+ CHAIN_NOISE_DELTA_GAIN_INIT_VAL)) {
+ delta_g = average_noise[i] - min_average_noise;
+ data->delta_gain_code[i] = (u8)((delta_g *
+ 10) / 15);
+ if (CHAIN_NOISE_MAX_DELTA_GAIN_CODE <
+ data->delta_gain_code[i])
+ data->delta_gain_code[i] =
+ CHAIN_NOISE_MAX_DELTA_GAIN_CODE;
+
+ data->delta_gain_code[i] =
+ (data->delta_gain_code[i] | (1 << 2));
+ } else
+ data->delta_gain_code[i] = 0;
+ }
+ IWL_DEBUG_CALIB("delta_gain_codes: a %d b %d c %d\n",
+ data->delta_gain_code[0],
+ data->delta_gain_code[1],
+ data->delta_gain_code[2]);
+
+ /* Differential gain gets sent to uCode only once */
+ if (!data->radio_write) {
+ struct iwl_calibration_cmd cmd;
+ data->radio_write = 1;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
+ cmd.diff_gain_a = data->delta_gain_code[0];
+ cmd.diff_gain_b = data->delta_gain_code[1];
+ cmd.diff_gain_c = data->delta_gain_code[2];
+ rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+ sizeof(cmd), &cmd);
+ if (rc)
+ IWL_DEBUG_CALIB("fail sending cmd "
+ "REPLY_PHY_CALIBRATION_CMD \n");
+
+ /* TODO we might want recalculate
+ * rx_chain in rxon cmd */
+
+ /* Mark so we run this algo only once! */
+ data->state = IWL_CHAIN_NOISE_CALIBRATED;
+ }
+ data->chain_noise_a = 0;
+ data->chain_noise_b = 0;
+ data->chain_noise_c = 0;
+ data->chain_signal_a = 0;
+ data->chain_signal_b = 0;
+ data->chain_signal_c = 0;
+ data->beacon_count = 0;
+ }
+ return;
+}
+
+static void iwl4965_sensitivity_calibration(struct iwl_priv *priv,
+ struct iwl_notif_statistics *resp)
+{
+ int rc = 0;
+ u32 rx_enable_time;
+ u32 fa_cck;
+ u32 fa_ofdm;
+ u32 bad_plcp_cck;
+ u32 bad_plcp_ofdm;
+ u32 norm_fa_ofdm;
+ u32 norm_fa_cck;
+ struct iwl_sensitivity_data *data = NULL;
+ struct statistics_rx_non_phy *rx_info = &(resp->rx.general);
+ struct statistics_rx *statistics = &(resp->rx);
+ unsigned long flags;
+ struct statistics_general_data statis;
+
+ data = &(priv->sensitivity_data);
+
+ if (!iwl_is_associated(priv)) {
+ IWL_DEBUG_CALIB("<< - not associated\n");
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+ IWL_DEBUG_CALIB("<< invalid data.\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+
+ /* Extract Statistics: */
+ rx_enable_time = le32_to_cpu(rx_info->channel_load);
+ fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt);
+ fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt);
+ bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err);
+ bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err);
+
+ statis.beacon_silence_rssi_a =
+ le32_to_cpu(statistics->general.beacon_silence_rssi_a);
+ statis.beacon_silence_rssi_b =
+ le32_to_cpu(statistics->general.beacon_silence_rssi_b);
+ statis.beacon_silence_rssi_c =
+ le32_to_cpu(statistics->general.beacon_silence_rssi_c);
+ statis.beacon_energy_a =
+ le32_to_cpu(statistics->general.beacon_energy_a);
+ statis.beacon_energy_b =
+ le32_to_cpu(statistics->general.beacon_energy_b);
+ statis.beacon_energy_c =
+ le32_to_cpu(statistics->general.beacon_energy_c);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_CALIB("rx_enable_time = %u usecs\n", rx_enable_time);
+
+ if (!rx_enable_time) {
+ IWL_DEBUG_CALIB("<< RX Enable Time == 0! \n");
+ return;
+ }
+
+ /* These statistics increase monotonically, and do not reset
+ * at each beacon. Calculate difference from last value, or just
+ * use the new statistics value if it has reset or wrapped around. */
+ if (data->last_bad_plcp_cnt_cck > bad_plcp_cck)
+ data->last_bad_plcp_cnt_cck = bad_plcp_cck;
+ else {
+ bad_plcp_cck -= data->last_bad_plcp_cnt_cck;
+ data->last_bad_plcp_cnt_cck += bad_plcp_cck;
+ }
+
+ if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm)
+ data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm;
+ else {
+ bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm;
+ data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm;
+ }
+
+ if (data->last_fa_cnt_ofdm > fa_ofdm)
+ data->last_fa_cnt_ofdm = fa_ofdm;
+ else {
+ fa_ofdm -= data->last_fa_cnt_ofdm;
+ data->last_fa_cnt_ofdm += fa_ofdm;
+ }
+
+ if (data->last_fa_cnt_cck > fa_cck)
+ data->last_fa_cnt_cck = fa_cck;
+ else {
+ fa_cck -= data->last_fa_cnt_cck;
+ data->last_fa_cnt_cck += fa_cck;
+ }
+
+ /* Total aborted signal locks */
+ norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm;
+ norm_fa_cck = fa_cck + bad_plcp_cck;
+
+ IWL_DEBUG_CALIB("cck: fa %u badp %u ofdm: fa %u badp %u\n", fa_cck,
+ bad_plcp_cck, fa_ofdm, bad_plcp_ofdm);
+
+ iwl4965_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
+ iwl4965_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
+ rc |= iwl4965_sensitivity_write(priv, CMD_ASYNC);
+
+ return;
+}
+
+static void iwl4965_bg_sensitivity_work(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ sensitivity_work);
+
+ mutex_lock(&priv->mutex);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+ test_bit(STATUS_SCANNING, &priv->status)) {
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ if (priv->start_calib) {
+ iwl4965_noise_calibration(priv, &priv->statistics);
+
+ if (priv->sensitivity_data.state ==
+ IWL_SENS_CALIB_NEED_REINIT) {
+ iwl4965_init_sensitivity(priv, CMD_ASYNC, 0);
+ priv->sensitivity_data.state = IWL_SENS_CALIB_ALLOWED;
+ } else
+ iwl4965_sensitivity_calibration(priv,
+ &priv->statistics);
+ }
+
+ mutex_unlock(&priv->mutex);
+ return;
+}
+#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
+
+static void iwl4965_bg_txpower_work(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ txpower_work);
+
+ /* If a scan happened to start before we got here
+ * then just return; the statistics notification will
+ * kick off another scheduled work to compensate for
+ * any temperature delta we missed here. */
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+ test_bit(STATUS_SCANNING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ /* Regardless of if we are assocaited, we must reconfigure the
+ * TX power since frames can be sent on non-radar channels while
+ * not associated */
+ iwl_hw_reg_send_txpower(priv);
+
+ /* Update last_temperature to keep is_calib_needed from running
+ * when it isn't needed... */
+ priv->last_temperature = priv->temperature;
+
+ mutex_unlock(&priv->mutex);
+}
+
+/*
+ * Acquire priv->lock before calling this function !
+ */
+static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index)
+{
+ iwl_write_restricted(priv, HBUS_TARG_WRPTR,
+ (index & 0xff) | (txq_id << 8));
+ iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(txq_id), index);
+}
+
+/*
+ * Acquire priv->lock before calling this function !
+ */
+static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq,
+ int tx_fifo_id, int scd_retry)
+{
+ int txq_id = txq->q.id;
+ int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
+
+ iwl_write_restricted_reg(priv, SCD_QUEUE_STATUS_BITS(txq_id),
+ (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+ (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) |
+ (scd_retry << SCD_QUEUE_STTS_REG_POS_WSL) |
+ (scd_retry << SCD_QUEUE_STTS_REG_POS_SCD_ACK) |
+ SCD_QUEUE_STTS_REG_MSK);
+
+ txq->sched_retry = scd_retry;
+
+ IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n",
+ active ? "Activete" : "Deactivate",
+ scd_retry ? "BA" : "AC", txq_id, tx_fifo_id);
+}
+
+static const u16 default_queue_to_tx_fifo[] = {
+ IWL_TX_FIFO_AC3,
+ IWL_TX_FIFO_AC2,
+ IWL_TX_FIFO_AC1,
+ IWL_TX_FIFO_AC0,
+ IWL_CMD_FIFO_NUM,
+ IWL_TX_FIFO_HCCA_1,
+ IWL_TX_FIFO_HCCA_2
+};
+
+static inline void iwl4965_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
+{
+ set_bit(txq_id, &priv->txq_ctx_active_msk);
+}
+
+static inline void iwl4965_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
+{
+ clear_bit(txq_id, &priv->txq_ctx_active_msk);
+}
+
+int iwl4965_alive_notify(struct iwl_priv *priv)
+{
+ u32 a;
+ int i = 0;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ memset(&(priv->sensitivity_data), 0,
+ sizeof(struct iwl_sensitivity_data));
+ memset(&(priv->chain_noise_data), 0,
+ sizeof(struct iwl_chain_noise_data));
+ for (i = 0; i < NUM_RX_CHAINS; i++)
+ priv->chain_noise_data.delta_gain_code[i] =
+ CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
+#endif /* CONFIG_IWLWIFI_SENSITIVITY*/
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ priv->scd_base_addr = iwl_read_restricted_reg(priv, SCD_SRAM_BASE_ADDR);
+ a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET;
+ for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4)
+ iwl_write_restricted_mem(priv, a, 0);
+ for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4)
+ iwl_write_restricted_mem(priv, a, 0);
+ for (; a < sizeof(u16) * priv->hw_setting.max_txq_num; a += 4)
+ iwl_write_restricted_mem(priv, a, 0);
+
+ iwl_write_restricted_reg(priv, SCD_DRAM_BASE_ADDR,
+ (priv->hw_setting.shared_phys +
+ offsetof(struct iwl_shared, queues_byte_cnt_tbls)) >> 10);
+ iwl_write_restricted_reg(priv, SCD_QUEUECHAIN_SEL, 0);
+
+ /* initiate the queues */
+ for (i = 0; i < priv->hw_setting.max_txq_num; i++) {
+ iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(i), 0);
+ iwl_write_restricted(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
+ iwl_write_restricted_mem(priv, priv->scd_base_addr +
+ SCD_CONTEXT_QUEUE_OFFSET(i),
+ (SCD_WIN_SIZE <<
+ SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
+ SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
+ iwl_write_restricted_mem(priv, priv->scd_base_addr +
+ SCD_CONTEXT_QUEUE_OFFSET(i) +
+ sizeof(u32),
+ (SCD_FRAME_LIMIT <<
+ SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+ SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
+
+ }
+ iwl_write_restricted_reg(priv, SCD_INTERRUPT_MASK,
+ (1 << priv->hw_setting.max_txq_num) - 1);
+
+ iwl_write_restricted_reg(priv, SCD_TXFACT,
+ SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
+
+ iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+ /* map qos queues to fifos one-to-one */
+ for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
+ int ac = default_queue_to_tx_fifo[i];
+ iwl4965_txq_ctx_activate(priv, i);
+ iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
+ }
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+int iwl_hw_set_hw_setting(struct iwl_priv *priv)
+{
+ priv->hw_setting.shared_virt =
+ pci_alloc_consistent(priv->pci_dev,
+ sizeof(struct iwl_shared),
+ &priv->hw_setting.shared_phys);
+
+ if (!priv->hw_setting.shared_virt)
+ return -1;
+
+ memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl_shared));
+
+ priv->hw_setting.max_txq_num = iwl_param_queues_num;
+ priv->hw_setting.ac_queue_count = AC_NUM;
+
+ priv->hw_setting.cck_flag = RATE_MCS_CCK_MSK;
+ priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd);
+ priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
+ priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
+
+ priv->hw_setting.max_stations = IWL4965_STATION_COUNT;
+ priv->hw_setting.bcast_sta_id = IWL4965_BROADCAST_ID;
+ return 0;
+}
+
+/**
+ * iwl_hw_txq_ctx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
+{
+ int txq_id;
+
+ /* Tx queues */
+ for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++)
+ iwl_tx_queue_free(priv, &priv->txq[txq_id]);
+
+ iwl4965_kw_free(priv);
+}
+
+/**
+ * iwl_hw_txq_free_tfd - Free one TFD, those at index [txq->q.last_used]
+ *
+ * Does NOT advance any indexes
+ */
+int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
+ struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used];
+ struct pci_dev *dev = priv->pci_dev;
+ int i;
+ int counter = 0;
+ int index, is_odd;
+
+ /* classify bd */
+ if (txq->q.id == IWL_CMD_QUEUE_NUM)
+ /* nothing to cleanup after for host commands */
+ return 0;
+
+ /* sanity check */
+ counter = IWL_GET_BITS(*bd, num_tbs);
+ if (counter > MAX_NUM_OF_TBS) {
+ IWL_ERROR("Too many chunks: %i\n", counter);
+ /* @todo issue fatal error, it is quite serious situation */
+ return 0;
+ }
+
+ /* unmap chunks if any */
+
+ for (i = 0; i < counter; i++) {
+ index = i / 2;
+ is_odd = i & 0x1;
+
+ if (is_odd)
+ pci_unmap_single(
+ dev,
+ IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
+ (IWL_GET_BITS(bd->pa[index],
+ tb2_addr_hi20) << 16),
+ IWL_GET_BITS(bd->pa[index], tb2_len),
+ PCI_DMA_TODEVICE);
+
+ else if (i > 0)
+ pci_unmap_single(dev,
+ le32_to_cpu(bd->pa[index].tb1_addr),
+ IWL_GET_BITS(bd->pa[index], tb1_len),
+ PCI_DMA_TODEVICE);
+
+ if (txq->txb[txq->q.last_used].skb[i]) {
+ struct sk_buff *skb = txq->txb[txq->q.last_used].skb[i];
+
+ dev_kfree_skb(skb);
+ txq->txb[txq->q.last_used].skb[i] = NULL;
+ }
+ }
+ return 0;
+}
+
+int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
+{
+ IWL_ERROR("TODO: Implement iwl_hw_reg_set_txpower!\n");
+ return -EINVAL;
+}
+
+static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res)
+{
+ s32 sign = 1;
+
+ if (num < 0) {
+ sign = -sign;
+ num = -num;
+ }
+ if (denom < 0) {
+ sign = -sign;
+ denom = -denom;
+ }
+ *res = 1;
+ *res = ((num * 2 + denom) / (denom * 2)) * sign;
+
+ return 1;
+}
+
+static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage,
+ s32 current_voltage)
+{
+ s32 comp = 0;
+
+ if ((TX_POWER_IWL_ILLEGAL_VOLTAGE == eeprom_voltage) ||
+ (TX_POWER_IWL_ILLEGAL_VOLTAGE == current_voltage))
+ return 0;
+
+ iwl4965_math_div_round(current_voltage - eeprom_voltage,
+ TX_POWER_IWL_VOLTAGE_CODES_PER_03V, &comp);
+
+ if (current_voltage > eeprom_voltage)
+ comp *= 2;
+ if ((comp < -2) || (comp > 2))
+ comp = 0;
+
+ return comp;
+}
+
+static const struct iwl_channel_info *
+iwl4965_get_channel_txpower_info(struct iwl_priv *priv, u8 phymode, u16 channel)
+{
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv, phymode, channel);
+
+ if (!is_channel_valid(ch_info))
+ return NULL;
+
+ return ch_info;
+}
+
+static s32 iwl4965_get_tx_atten_grp(u16 channel)
+{
+ if (channel >= CALIB_IWL_TX_ATTEN_GR5_FCH &&
+ channel <= CALIB_IWL_TX_ATTEN_GR5_LCH)
+ return CALIB_CH_GROUP_5;
+
+ if (channel >= CALIB_IWL_TX_ATTEN_GR1_FCH &&
+ channel <= CALIB_IWL_TX_ATTEN_GR1_LCH)
+ return CALIB_CH_GROUP_1;
+
+ if (channel >= CALIB_IWL_TX_ATTEN_GR2_FCH &&
+ channel <= CALIB_IWL_TX_ATTEN_GR2_LCH)
+ return CALIB_CH_GROUP_2;
+
+ if (channel >= CALIB_IWL_TX_ATTEN_GR3_FCH &&
+ channel <= CALIB_IWL_TX_ATTEN_GR3_LCH)
+ return CALIB_CH_GROUP_3;
+
+ if (channel >= CALIB_IWL_TX_ATTEN_GR4_FCH &&
+ channel <= CALIB_IWL_TX_ATTEN_GR4_LCH)
+ return CALIB_CH_GROUP_4;
+
+ IWL_ERROR("Can't find txatten group for channel %d.\n", channel);
+ return -1;
+}
+
+static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel)
+{
+ s32 b = -1;
+
+ for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) {
+ if (priv->eeprom.calib_info.band_info[b].ch_from == 0)
+ continue;
+
+ if ((channel >= priv->eeprom.calib_info.band_info[b].ch_from)
+ && (channel <= priv->eeprom.calib_info.band_info[b].ch_to))
+ break;
+ }
+
+ return b;
+}
+
+static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2)
+{
+ s32 val;
+
+ if (x2 == x1)
+ return y1;
+ else {
+ iwl4965_math_div_round((x2 - x) * (y1 - y2), (x2 - x1), &val);
+ return val + y2;
+ }
+}
+
+static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel,
+ struct iwl_eeprom_calib_ch_info *chan_info)
+{
+ s32 s = -1;
+ u32 c;
+ u32 m;
+ const struct iwl_eeprom_calib_measure *m1;
+ const struct iwl_eeprom_calib_measure *m2;
+ struct iwl_eeprom_calib_measure *omeas;
+ u32 ch_i1;
+ u32 ch_i2;
+
+ s = iwl4965_get_sub_band(priv, channel);
+ if (s >= EEPROM_TX_POWER_BANDS) {
+ IWL_ERROR("Tx Power can not find channel %d ", channel);
+ return -1;
+ }
+
+ ch_i1 = priv->eeprom.calib_info.band_info[s].ch1.ch_num;
+ ch_i2 = priv->eeprom.calib_info.band_info[s].ch2.ch_num;
+ chan_info->ch_num = (u8) channel;
+
+ IWL_DEBUG_TXPOWER("channel %d subband %d factory cal ch %d & %d\n",
+ channel, s, ch_i1, ch_i2);
+
+ for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) {
+ for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) {
+ m1 = &(priv->eeprom.calib_info.band_info[s].ch1.
+ measurements[c][m]);
+ m2 = &(priv->eeprom.calib_info.band_info[s].ch2.
+ measurements[c][m]);
+ omeas = &(chan_info->measurements[c][m]);
+
+ omeas->actual_pow =
+ (u8) iwl4965_interpolate_value(channel, ch_i1,
+ m1->actual_pow,
+ ch_i2,
+ m2->actual_pow);
+ omeas->gain_idx =
+ (u8) iwl4965_interpolate_value(channel, ch_i1,
+ m1->gain_idx, ch_i2,
+ m2->gain_idx);
+ omeas->temperature =
+ (u8) iwl4965_interpolate_value(channel, ch_i1,
+ m1->temperature,
+ ch_i2,
+ m2->temperature);
+ omeas->pa_det =
+ (s8) iwl4965_interpolate_value(channel, ch_i1,
+ m1->pa_det, ch_i2,
+ m2->pa_det);
+
+ IWL_DEBUG_TXPOWER
+ ("chain %d meas %d AP1=%d AP2=%d AP=%d\n", c, m,
+ m1->actual_pow, m2->actual_pow, omeas->actual_pow);
+ IWL_DEBUG_TXPOWER
+ ("chain %d meas %d NI1=%d NI2=%d NI=%d\n", c, m,
+ m1->gain_idx, m2->gain_idx, omeas->gain_idx);
+ IWL_DEBUG_TXPOWER
+ ("chain %d meas %d PA1=%d PA2=%d PA=%d\n", c, m,
+ m1->pa_det, m2->pa_det, omeas->pa_det);
+ IWL_DEBUG_TXPOWER
+ ("chain %d meas %d T1=%d T2=%d T=%d\n", c, m,
+ m1->temperature, m2->temperature,
+ omeas->temperature);
+ }
+ }
+
+ return 0;
+}
+
+/* bit-rate-dependent table to prevent Tx distortion, in half-dB units,
+ * for OFDM 6, 12, 18, 24, 36, 48, 54, 60 MBit, and CCK all rates. */
+static s32 back_off_table[] = {
+ 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 20 MHz */
+ 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 20 MHz */
+ 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM SISO 40 MHz */
+ 10, 10, 10, 10, 10, 15, 17, 20, /* OFDM MIMO 40 MHz */
+ 10 /* CCK */
+};
+
+/* Thermal compensation values for txpower for various frequency ranges ...
+ * ratios from 3:1 to 4.5:1 of degrees (Celsius) per half-dB gain adjust */
+static struct iwl_txpower_comp_entry {
+ s32 degrees_per_05db_a;
+ s32 degrees_per_05db_a_denom;
+} tx_power_cmp_tble[CALIB_CH_GROUP_MAX] = {
+ {9, 2}, /* group 0 5.2, ch 34-43 */
+ {4, 1}, /* group 1 5.2, ch 44-70 */
+ {4, 1}, /* group 2 5.2, ch 71-124 */
+ {4, 1}, /* group 3 5.2, ch 125-200 */
+ {3, 1} /* group 4 2.4, ch all */
+};
+
+static s32 get_min_power_index(s32 rate_power_index, u32 band)
+{
+ if (!band) {
+ if ((rate_power_index & 7) <= 4)
+ return MIN_TX_GAIN_INDEX_52GHZ_EXT;
+ }
+ return MIN_TX_GAIN_INDEX;
+}
+
+struct gain_entry {
+ u8 dsp;
+ u8 radio;
+};
+
+static const struct gain_entry gain_table[2][108] = {
+ /* 5.2GHz power gain index table */
+ {
+ {123, 0x3F}, /* highest txpower */
+ {117, 0x3F},
+ {110, 0x3F},
+ {104, 0x3F},
+ {98, 0x3F},
+ {110, 0x3E},
+ {104, 0x3E},
+ {98, 0x3E},
+ {110, 0x3D},
+ {104, 0x3D},
+ {98, 0x3D},
+ {110, 0x3C},
+ {104, 0x3C},
+ {98, 0x3C},
+ {110, 0x3B},
+ {104, 0x3B},
+ {98, 0x3B},
+ {110, 0x3A},
+ {104, 0x3A},
+ {98, 0x3A},
+ {110, 0x39},
+ {104, 0x39},
+ {98, 0x39},
+ {110, 0x38},
+ {104, 0x38},
+ {98, 0x38},
+ {110, 0x37},
+ {104, 0x37},
+ {98, 0x37},
+ {110, 0x36},
+ {104, 0x36},
+ {98, 0x36},
+ {110, 0x35},
+ {104, 0x35},
+ {98, 0x35},
+ {110, 0x34},
+ {104, 0x34},
+ {98, 0x34},
+ {110, 0x33},
+ {104, 0x33},
+ {98, 0x33},
+ {110, 0x32},
+ {104, 0x32},
+ {98, 0x32},
+ {110, 0x31},
+ {104, 0x31},
+ {98, 0x31},
+ {110, 0x30},
+ {104, 0x30},
+ {98, 0x30},
+ {110, 0x25},
+ {104, 0x25},
+ {98, 0x25},
+ {110, 0x24},
+ {104, 0x24},
+ {98, 0x24},
+ {110, 0x23},
+ {104, 0x23},
+ {98, 0x23},
+ {110, 0x22},
+ {104, 0x18},
+ {98, 0x18},
+ {110, 0x17},
+ {104, 0x17},
+ {98, 0x17},
+ {110, 0x16},
+ {104, 0x16},
+ {98, 0x16},
+ {110, 0x15},
+ {104, 0x15},
+ {98, 0x15},
+ {110, 0x14},
+ {104, 0x14},
+ {98, 0x14},
+ {110, 0x13},
+ {104, 0x13},
+ {98, 0x13},
+ {110, 0x12},
+ {104, 0x08},
+ {98, 0x08},
+ {110, 0x07},
+ {104, 0x07},
+ {98, 0x07},
+ {110, 0x06},
+ {104, 0x06},
+ {98, 0x06},
+ {110, 0x05},
+ {104, 0x05},
+ {98, 0x05},
+ {110, 0x04},
+ {104, 0x04},
+ {98, 0x04},
+ {110, 0x03},
+ {104, 0x03},
+ {98, 0x03},
+ {110, 0x02},
+ {104, 0x02},
+ {98, 0x02},
+ {110, 0x01},
+ {104, 0x01},
+ {98, 0x01},
+ {110, 0x00},
+ {104, 0x00},
+ {98, 0x00},
+ {93, 0x00},
+ {88, 0x00},
+ {83, 0x00},
+ {78, 0x00},
+ },
+ /* 2.4GHz power gain index table */
+ {
+ {110, 0x3f}, /* highest txpower */
+ {104, 0x3f},
+ {98, 0x3f},
+ {110, 0x3e},
+ {104, 0x3e},
+ {98, 0x3e},
+ {110, 0x3d},
+ {104, 0x3d},
+ {98, 0x3d},
+ {110, 0x3c},
+ {104, 0x3c},
+ {98, 0x3c},
+ {110, 0x3b},
+ {104, 0x3b},
+ {98, 0x3b},
+ {110, 0x3a},
+ {104, 0x3a},
+ {98, 0x3a},
+ {110, 0x39},
+ {104, 0x39},
+ {98, 0x39},
+ {110, 0x38},
+ {104, 0x38},
+ {98, 0x38},
+ {110, 0x37},
+ {104, 0x37},
+ {98, 0x37},
+ {110, 0x36},
+ {104, 0x36},
+ {98, 0x36},
+ {110, 0x35},
+ {104, 0x35},
+ {98, 0x35},
+ {110, 0x34},
+ {104, 0x34},
+ {98, 0x34},
+ {110, 0x33},
+ {104, 0x33},
+ {98, 0x33},
+ {110, 0x32},
+ {104, 0x32},
+ {98, 0x32},
+ {110, 0x31},
+ {104, 0x31},
+ {98, 0x31},
+ {110, 0x30},
+ {104, 0x30},
+ {98, 0x30},
+ {110, 0x6},
+ {104, 0x6},
+ {98, 0x6},
+ {110, 0x5},
+ {104, 0x5},
+ {98, 0x5},
+ {110, 0x4},
+ {104, 0x4},
+ {98, 0x4},
+ {110, 0x3},
+ {104, 0x3},
+ {98, 0x3},
+ {110, 0x2},
+ {104, 0x2},
+ {98, 0x2},
+ {110, 0x1},
+ {104, 0x1},
+ {98, 0x1},
+ {110, 0x0},
+ {104, 0x0},
+ {98, 0x0},
+ {97, 0},
+ {96, 0},
+ {95, 0},
+ {94, 0},
+ {93, 0},
+ {92, 0},
+ {91, 0},
+ {90, 0},
+ {89, 0},
+ {88, 0},
+ {87, 0},
+ {86, 0},
+ {85, 0},
+ {84, 0},
+ {83, 0},
+ {82, 0},
+ {81, 0},
+ {80, 0},
+ {79, 0},
+ {78, 0},
+ {77, 0},
+ {76, 0},
+ {75, 0},
+ {74, 0},
+ {73, 0},
+ {72, 0},
+ {71, 0},
+ {70, 0},
+ {69, 0},
+ {68, 0},
+ {67, 0},
+ {66, 0},
+ {65, 0},
+ {64, 0},
+ {63, 0},
+ {62, 0},
+ {61, 0},
+ {60, 0},
+ {59, 0},
+ }
+};
+
+static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
+ u8 is_fat, u8 ctrl_chan_high,
+ struct iwl_tx_power_db *tx_power_tbl)
+{
+ u8 saturation_power;
+ s32 target_power;
+ s32 user_target_power;
+ s32 power_limit;
+ s32 current_temp;
+ s32 reg_limit;
+ s32 current_regulatory;
+ s32 txatten_grp = CALIB_CH_GROUP_MAX;
+ int i;
+ int c;
+ const struct iwl_channel_info *ch_info = NULL;
+ struct iwl_eeprom_calib_ch_info ch_eeprom_info;
+ const struct iwl_eeprom_calib_measure *measurement;
+ s16 voltage;
+ s32 init_voltage;
+ s32 voltage_compensation;
+ s32 degrees_per_05db_num;
+ s32 degrees_per_05db_denom;
+ s32 factory_temp;
+ s32 temperature_comp[2];
+ s32 factory_gain_index[2];
+ s32 factory_actual_pwr[2];
+ s32 power_index;
+
+ /* Sanity check requested level (dBm) */
+ if (priv->user_txpower_limit < IWL_TX_POWER_TARGET_POWER_MIN) {
+ IWL_WARNING("Requested user TXPOWER %d below limit.\n",
+ priv->user_txpower_limit);
+ return -EINVAL;
+ }
+ if (priv->user_txpower_limit > IWL_TX_POWER_TARGET_POWER_MAX) {
+ IWL_WARNING("Requested user TXPOWER %d above limit.\n",
+ priv->user_txpower_limit);
+ return -EINVAL;
+ }
+
+ /* user_txpower_limit is in dBm, convert to half-dBm (half-dB units
+ * are used for indexing into txpower table) */
+ user_target_power = 2 * priv->user_txpower_limit;
+
+ /* Get current (RXON) channel, band, width */
+ ch_info =
+ iwl4965_get_channel_txpower_info(priv, priv->phymode, channel);
+
+ IWL_DEBUG_TXPOWER("chan %d band %d is_fat %d\n", channel, band,
+ is_fat);
+
+ if (!ch_info)
+ return -EINVAL;
+
+ /* get txatten group, used to select 1) thermal txpower adjustment
+ * and 2) mimo txpower balance between Tx chains. */
+ txatten_grp = iwl4965_get_tx_atten_grp(channel);
+ if (txatten_grp < 0)
+ return -EINVAL;
+
+ IWL_DEBUG_TXPOWER("channel %d belongs to txatten group %d\n",
+ channel, txatten_grp);
+
+ if (is_fat) {
+ if (ctrl_chan_high)
+ channel -= 2;
+ else
+ channel += 2;
+ }
+
+ /* hardware txpower limits ...
+ * saturation (clipping distortion) txpowers are in half-dBm */
+ if (band)
+ saturation_power = priv->eeprom.calib_info.saturation_power24;
+ else
+ saturation_power = priv->eeprom.calib_info.saturation_power52;
+
+ if (saturation_power < IWL_TX_POWER_SATURATION_MIN ||
+ saturation_power > IWL_TX_POWER_SATURATION_MAX) {
+ if (band)
+ saturation_power = IWL_TX_POWER_DEFAULT_SATURATION_24;
+ else
+ saturation_power = IWL_TX_POWER_DEFAULT_SATURATION_52;
+ }
+
+ /* regulatory txpower limits ... reg_limit values are in half-dBm,
+ * max_power_avg values are in dBm, convert * 2 */
+ if (is_fat)
+ reg_limit = ch_info->fat_max_power_avg * 2;
+ else
+ reg_limit = ch_info->max_power_avg * 2;
+
+ if ((reg_limit < IWL_TX_POWER_REGULATORY_MIN) ||
+ (reg_limit > IWL_TX_POWER_REGULATORY_MAX)) {
+ if (band)
+ reg_limit = IWL_TX_POWER_DEFAULT_REGULATORY_24;
+ else
+ reg_limit = IWL_TX_POWER_DEFAULT_REGULATORY_52;
+ }
+
+ /* Interpolate txpower calibration values for this channel,
+ * based on factory calibration tests on spaced channels. */
+ iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info);
+
+ /* calculate tx gain adjustment based on power supply voltage */
+ voltage = priv->eeprom.calib_info.voltage;
+ init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage);
+ voltage_compensation =
+ iwl4965_get_voltage_compensation(voltage, init_voltage);
+
+ IWL_DEBUG_TXPOWER("curr volt %d eeprom volt %d volt comp %d\n",
+ init_voltage,
+ voltage, voltage_compensation);
+
+ /* get current temperature (Celsius) */
+ current_temp = max(priv->temperature, IWL_TX_POWER_TEMPERATURE_MIN);
+ current_temp = min(priv->temperature, IWL_TX_POWER_TEMPERATURE_MAX);
+ current_temp = KELVIN_TO_CELSIUS(current_temp);
+
+ /* select thermal txpower adjustment params, based on channel group
+ * (same frequency group used for mimo txatten adjustment) */
+ degrees_per_05db_num =
+ tx_power_cmp_tble[txatten_grp].degrees_per_05db_a;
+ degrees_per_05db_denom =
+ tx_power_cmp_tble[txatten_grp].degrees_per_05db_a_denom;
+
+ /* get per-chain txpower values from factory measurements */
+ for (c = 0; c < 2; c++) {
+ measurement = &ch_eeprom_info.measurements[c][1];
+
+ /* txgain adjustment (in half-dB steps) based on difference
+ * between factory and current temperature */
+ factory_temp = measurement->temperature;
+ iwl4965_math_div_round((current_temp - factory_temp) *
+ degrees_per_05db_denom,
+ degrees_per_05db_num,
+ &temperature_comp[c]);
+
+ factory_gain_index[c] = measurement->gain_idx;
+ factory_actual_pwr[c] = measurement->actual_pow;
+
+ IWL_DEBUG_TXPOWER("chain = %d\n", c);
+ IWL_DEBUG_TXPOWER("fctry tmp %d, "
+ "curr tmp %d, comp %d steps\n",
+ factory_temp, current_temp,
+ temperature_comp[c]);
+
+ IWL_DEBUG_TXPOWER("fctry idx %d, fctry pwr %d\n",
+ factory_gain_index[c],
+ factory_actual_pwr[c]);
+ }
+
+ /* for each of 33 bit-rates (including 1 for CCK) */
+ for (i = 0; i < POWER_TABLE_NUM_ENTRIES; i++) {
+ u8 is_mimo_rate;
+ union iwl_tx_power_dual_stream tx_power;
+
+ /* for mimo, reduce each chain's txpower by half
+ * (3dB, 6 steps), so total output power is regulatory
+ * compliant. */
+ if (i & 0x8) {
+ current_regulatory = reg_limit -
+ IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION;
+ is_mimo_rate = 1;
+ } else {
+ current_regulatory = reg_limit;
+ is_mimo_rate = 0;
+ }
+
+ /* find txpower limit, either hardware or regulatory */
+ power_limit = saturation_power - back_off_table[i];
+ if (power_limit > current_regulatory)
+ power_limit = current_regulatory;
+
+ /* reduce user's txpower request if necessary
+ * for this rate on this channel */
+ target_power = user_target_power;
+ if (target_power > power_limit)
+ target_power = power_limit;
+
+ IWL_DEBUG_TXPOWER("rate %d sat %d reg %d usr %d tgt %d\n",
+ i, saturation_power - back_off_table[i],
+ current_regulatory, user_target_power,
+ target_power);
+
+ /* for each of 2 Tx chains (radio transmitters) */
+ for (c = 0; c < 2; c++) {
+ s32 atten_value;
+
+ if (is_mimo_rate)
+ atten_value =
+ (s32)le32_to_cpu(priv->card_alive_init.
+ tx_atten[txatten_grp][c]);
+ else
+ atten_value = 0;
+
+ /* calculate index; higher index means lower txpower */
+ power_index = (u8) (factory_gain_index[c] -
+ (target_power -
+ factory_actual_pwr[c]) -
+ temperature_comp[c] -
+ voltage_compensation +
+ atten_value);
+
+/* IWL_DEBUG_TXPOWER("calculated txpower index %d\n",
+ power_index); */
+
+ if (power_index < get_min_power_index(i, band))
+ power_index = get_min_power_index(i, band);
+
+ /* adjust 5 GHz index to support negative indexes */
+ if (!band)
+ power_index += 9;
+
+ /* CCK, rate 32, reduce txpower for CCK */
+ if (i == POWER_TABLE_CCK_ENTRY)
+ power_index +=
+ IWL_TX_POWER_CCK_COMPENSATION_C_STEP;
+
+ /* stay within the table! */
+ if (power_index > 107) {
+ IWL_WARNING("txpower index %d > 107\n",
+ power_index);
+ power_index = 107;
+ }
+ if (power_index < 0) {
+ IWL_WARNING("txpower index %d < 0\n",
+ power_index);
+ power_index = 0;
+ }
+
+ /* fill txpower command for this rate/chain */
+ tx_power.s.radio_tx_gain[c] =
+ gain_table[band][power_index].radio;
+ tx_power.s.dsp_predis_atten[c] =
+ gain_table[band][power_index].dsp;
+
+ IWL_DEBUG_TXPOWER("chain %d mimo %d index %d "
+ "gain 0x%02x dsp %d\n",
+ c, atten_value, power_index,
+ tx_power.s.radio_tx_gain[c],
+ tx_power.s.dsp_predis_atten[c]);
+ }/* for each chain */
+
+ tx_power_tbl->power_tbl[i].dw = cpu_to_le32(tx_power.dw);
+
+ }/* for each rate */
+
+ return 0;
+}
+
+/**
+ * iwl_hw_reg_send_txpower - Configure the TXPOWER level user limit
+ *
+ * Uses the active RXON for channel, band, and characteristics (fat, high)
+ * The power limit is taken from priv->user_txpower_limit.
+ */
+int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
+{
+ struct iwl_txpowertable_cmd cmd = { 0 };
+ int rc = 0;
+ u8 band = 0;
+ u8 is_fat = 0;
+ u8 ctrl_chan_high = 0;
+
+ if (test_bit(STATUS_SCANNING, &priv->status)) {
+ /* If this gets hit a lot, switch it to a BUG() and catch
+ * the stack trace to find out who is calling this during
+ * a scan. */
+ IWL_WARNING("TX Power requested while scanning!\n");
+ return -EAGAIN;
+ }
+
+ band = ((priv->phymode == MODE_IEEE80211B) ||
+ (priv->phymode == MODE_IEEE80211G));
+
+ is_fat = is_fat_channel(priv->active_rxon.flags);
+
+ if (is_fat &&
+ (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+ ctrl_chan_high = 1;
+
+ cmd.band = band;
+ cmd.channel = priv->active_rxon.channel;
+
+ rc = iwl4965_fill_txpower_tbl(priv, band,
+ le16_to_cpu(priv->active_rxon.channel),
+ is_fat, ctrl_chan_high, &cmd.tx_power);
+ if (rc)
+ return rc;
+
+ rc = iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd);
+ return rc;
+}
+
+int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+{
+ int rc;
+ u8 band = 0;
+ u8 is_fat = 0;
+ u8 ctrl_chan_high = 0;
+ struct iwl_channel_switch_cmd cmd = { 0 };
+ const struct iwl_channel_info *ch_info;
+
+ band = ((priv->phymode == MODE_IEEE80211B) ||
+ (priv->phymode == MODE_IEEE80211G));
+
+ ch_info = iwl_get_channel_info(priv, priv->phymode, channel);
+
+ is_fat = is_fat_channel(priv->staging_rxon.flags);
+
+ if (is_fat &&
+ (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+ ctrl_chan_high = 1;
+
+ cmd.band = band;
+ cmd.expect_beacon = 0;
+ cmd.channel = cpu_to_le16(channel);
+ cmd.rxon_flags = priv->active_rxon.flags;
+ cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
+ cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ if (ch_info)
+ cmd.expect_beacon = is_channel_radar(ch_info);
+ else
+ cmd.expect_beacon = 1;
+
+ rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_fat,
+ ctrl_chan_high, &cmd.tx_power);
+ if (rc) {
+ IWL_DEBUG_11H("error:%d fill txpower_tbl\n", rc);
+ return rc;
+ }
+
+ rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
+ return rc;
+}
+
+#define RTS_HCCA_RETRY_LIMIT 3
+#define RTS_DFAULT_RETRY_LIMIT 60
+
+void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct ieee80211_tx_control *ctrl,
+ struct ieee80211_hdr *hdr, int sta_id,
+ int is_hcca)
+{
+ u8 rate;
+ u8 rts_retry_limit = 0;
+ u8 data_retry_limit = 0;
+ __le32 tx_flags;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+
+ tx_flags = cmd->cmd.tx.tx_flags;
+
+ rate = iwl_rates[ctrl->tx_rate].plcp;
+
+ rts_retry_limit = (is_hcca) ?
+ RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT;
+
+ if (ieee80211_is_probe_response(fc)) {
+ data_retry_limit = 3;
+ if (data_retry_limit < rts_retry_limit)
+ rts_retry_limit = data_retry_limit;
+ } else
+ data_retry_limit = IWL_DEFAULT_TX_RETRY;
+
+ if (priv->data_retry_limit != -1)
+ data_retry_limit = priv->data_retry_limit;
+
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_AUTH:
+ case IEEE80211_STYPE_DEAUTH:
+ case IEEE80211_STYPE_ASSOC_REQ:
+ case IEEE80211_STYPE_REASSOC_REQ:
+ if (tx_flags & TX_CMD_FLG_RTS_MSK) {
+ tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ cmd->cmd.tx.rts_retry_limit = rts_retry_limit;
+ cmd->cmd.tx.data_retry_limit = data_retry_limit;
+ cmd->cmd.tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, 0);
+ cmd->cmd.tx.tx_flags = tx_flags;
+}
+
+int iwl_hw_get_rx_read(struct iwl_priv *priv)
+{
+ struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+
+ return IWL_GET_BITS(*shared_data, rb_closed_stts_rb_num);
+}
+
+int iwl_hw_get_temperature(struct iwl_priv *priv)
+{
+ return priv->temperature;
+}
+
+unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
+ struct iwl_frame *frame, u8 rate)
+{
+ struct iwl_tx_beacon_cmd *tx_beacon_cmd;
+ unsigned int frame_size;
+
+ tx_beacon_cmd = &frame->u.beacon;
+ memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
+
+ tx_beacon_cmd->tx.sta_id = IWL4965_BROADCAST_ID;
+ tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+ frame_size = iwl_fill_beacon_frame(priv,
+ tx_beacon_cmd->frame,
+ BROADCAST_ADDR,
+ sizeof(frame->u) - sizeof(*tx_beacon_cmd));
+
+ BUG_ON(frame_size > MAX_MPDU_SIZE);
+ tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
+
+ if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP))
+ tx_beacon_cmd->tx.rate_n_flags =
+ iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK);
+ else
+ tx_beacon_cmd->tx.rate_n_flags =
+ iwl_hw_set_rate_n_flags(rate, 0);
+
+ tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK |
+ TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK);
+ return (sizeof(*tx_beacon_cmd) + frame_size);
+}
+
+int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ int rc;
+ unsigned long flags;
+ int txq_id = txq->q.id;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ iwl_write_restricted(priv, FH_MEM_CBBC_QUEUE(txq_id),
+ txq->q.dma_addr >> 8);
+ iwl_write_restricted(
+ priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
+ IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+ IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static inline u8 iwl4965_get_dma_hi_address(dma_addr_t addr)
+{
+ return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0;
+}
+
+int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
+ dma_addr_t addr, u16 len)
+{
+ int index, is_odd;
+ struct iwl_tfd_frame *tfd = ptr;
+ u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
+
+ if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) {
+ IWL_ERROR("Error can not send more than %d chunks\n",
+ MAX_NUM_OF_TBS);
+ return -EINVAL;
+ }
+
+ index = num_tbs / 2;
+ is_odd = num_tbs & 0x1;
+
+ if (!is_odd) {
+ tfd->pa[index].tb1_addr = cpu_to_le32(addr);
+ IWL_SET_BITS(tfd->pa[index], tb1_addr_hi,
+ iwl4965_get_dma_hi_address(addr));
+ IWL_SET_BITS(tfd->pa[index], tb1_len, len);
+ } else {
+ IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16,
+ (u32) (addr & 0xffff));
+ IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16);
+ IWL_SET_BITS(tfd->pa[index], tb2_len, len);
+ }
+
+ IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1);
+
+ return 0;
+}
+
+void iwl_hw_card_show_info(struct iwl_priv *priv)
+{
+ u16 hw_version = priv->eeprom.board_revision_4965;
+
+ IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n",
+ ((hw_version >> 8) & 0x0F),
+ ((hw_version >> 8) >> 4), (hw_version & 0x00FF));
+
+ IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n",
+ priv->eeprom.board_pba_number_4965);
+}
+
+#define IWL_TX_CRC_SIZE 4
+#define IWL_TX_DELIMITER_SIZE 4
+
+int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq, u16 byte_cnt)
+{
+ int len;
+ int txq_id = txq->q.id;
+ struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+
+ if (txq->need_update == 0)
+ return 0;
+
+ len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+
+ IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+ tfd_offset[txq->q.first_empty], byte_cnt, len);
+
+ if (txq->q.first_empty < IWL4965_MAX_WIN_SIZE)
+ IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+ tfd_offset[IWL4965_QUEUE_SIZE + txq->q.first_empty],
+ byte_cnt, len);
+
+ return 0;
+}
+
+/* Set up Rx receiver/antenna/chain usage in "staging" RXON image.
+ * This should not be used for scan command ... it puts data in wrong place. */
+void iwl4965_set_rxon_chain(struct iwl_priv *priv)
+{
+ u8 is_single = is_single_stream(priv);
+ u8 idle_state, rx_state;
+
+ priv->staging_rxon.rx_chain = 0;
+ rx_state = idle_state = 3;
+
+ /* Tell uCode which antennas are actually connected.
+ * Before first association, we assume all antennas are connected.
+ * Just after first association, iwl4965_noise_calibration()
+ * checks which antennas actually *are* connected. */
+ priv->staging_rxon.rx_chain |=
+ cpu_to_le16(priv->valid_antenna << RXON_RX_CHAIN_VALID_POS);
+
+ /* How many receivers should we use? */
+ iwl4965_get_rx_chain_counter(priv, &idle_state, &rx_state);
+ priv->staging_rxon.rx_chain |=
+ cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS);
+ priv->staging_rxon.rx_chain |=
+ cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS);
+
+ if (!is_single && (rx_state >= 2) &&
+ !test_bit(STATUS_POWER_PMI, &priv->status))
+ priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
+ else
+ priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
+
+ IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain);
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+/*
+ get the traffic load value for tid
+*/
+static u32 iwl4965_tl_get_load(struct iwl_priv *priv, u8 tid)
+{
+ u32 load = 0;
+ u32 current_time = jiffies_to_msecs(jiffies);
+ u32 time_diff;
+ s32 index;
+ unsigned long flags;
+ struct iwl_traffic_load *tid_ptr = NULL;
+
+ if (tid >= TID_MAX_LOAD_COUNT)
+ return 0;
+
+ tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]);
+
+ current_time -= current_time % TID_ROUND_VALUE;
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ if (!(tid_ptr->queue_count))
+ goto out;
+
+ time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time);
+ index = time_diff / TID_QUEUE_CELL_SPACING;
+
+ if (index >= TID_QUEUE_MAX_SIZE) {
+ u32 oldest_time = current_time - TID_MAX_TIME_DIFF;
+
+ while (tid_ptr->queue_count &&
+ (tid_ptr->time_stamp < oldest_time)) {
+ tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head];
+ tid_ptr->packet_count[tid_ptr->head] = 0;
+ tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING;
+ tid_ptr->queue_count--;
+ tid_ptr->head++;
+ if (tid_ptr->head >= TID_QUEUE_MAX_SIZE)
+ tid_ptr->head = 0;
+ }
+ }
+ load = tid_ptr->total;
+
+ out:
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ return load;
+}
+
+/*
+ increment traffic load value for tid and also remove
+ any old values if passed the certian time period
+*/
+static void iwl4965_tl_add_packet(struct iwl_priv *priv, u8 tid)
+{
+ u32 current_time = jiffies_to_msecs(jiffies);
+ u32 time_diff;
+ s32 index;
+ unsigned long flags;
+ struct iwl_traffic_load *tid_ptr = NULL;
+
+ if (tid >= TID_MAX_LOAD_COUNT)
+ return;
+
+ tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]);
+
+ current_time -= current_time % TID_ROUND_VALUE;
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ if (!(tid_ptr->queue_count)) {
+ tid_ptr->total = 1;
+ tid_ptr->time_stamp = current_time;
+ tid_ptr->queue_count = 1;
+ tid_ptr->head = 0;
+ tid_ptr->packet_count[0] = 1;
+ goto out;
+ }
+
+ time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time);
+ index = time_diff / TID_QUEUE_CELL_SPACING;
+
+ if (index >= TID_QUEUE_MAX_SIZE) {
+ u32 oldest_time = current_time - TID_MAX_TIME_DIFF;
+
+ while (tid_ptr->queue_count &&
+ (tid_ptr->time_stamp < oldest_time)) {
+ tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head];
+ tid_ptr->packet_count[tid_ptr->head] = 0;
+ tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING;
+ tid_ptr->queue_count--;
+ tid_ptr->head++;
+ if (tid_ptr->head >= TID_QUEUE_MAX_SIZE)
+ tid_ptr->head = 0;
+ }
+ }
+
+ index = (tid_ptr->head + index) % TID_QUEUE_MAX_SIZE;
+ tid_ptr->packet_count[index] = tid_ptr->packet_count[index] + 1;
+ tid_ptr->total = tid_ptr->total + 1;
+
+ if ((index + 1) > tid_ptr->queue_count)
+ tid_ptr->queue_count = index + 1;
+ out:
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+
+}
+
+#define MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS 7
+enum HT_STATUS {
+ BA_STATUS_FAILURE = 0,
+ BA_STATUS_INITIATOR_DELBA,
+ BA_STATUS_RECIPIENT_DELBA,
+ BA_STATUS_RENEW_ADDBA_REQUEST,
+ BA_STATUS_ACTIVE,
+};
+
+static u8 iwl4964_tl_ba_avail(struct iwl_priv *priv)
+{
+ int i;
+ struct iwl_lq_mngr *lq;
+ u8 count = 0;
+ u16 msk;
+
+ lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+ for (i = 0; i < TID_MAX_LOAD_COUNT ; i++) {
+ msk = 1 << i;
+ if ((lq->agg_ctrl.granted_ba & msk) ||
+ (lq->agg_ctrl.wait_for_agg_status & msk))
+ count++;
+ }
+
+ if (count < MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS)
+ return 1;
+
+ return 0;
+}
+
+static void iwl4965_ba_status(struct iwl_priv *priv,
+ u8 tid, enum HT_STATUS status);
+
+static int iwl4965_perform_addba(struct iwl_priv *priv, u8 tid, u32 length,
+ u32 ba_timeout)
+{
+ int rc;
+
+ rc = ieee80211_start_BA_session(priv->hw, priv->bssid, tid);
+ if (rc)
+ iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE);
+
+ return rc;
+}
+
+static int iwl4965_perform_delba(struct iwl_priv *priv, u8 tid)
+{
+ int rc;
+
+ rc = ieee80211_stop_BA_session(priv->hw, priv->bssid, tid);
+ if (rc)
+ iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE);
+
+ return rc;
+}
+
+static void iwl4965_turn_on_agg_for_tid(struct iwl_priv *priv,
+ struct iwl_lq_mngr *lq,
+ u8 auto_agg, u8 tid)
+{
+ u32 tid_msk = (1 << tid);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+/*
+ if ((auto_agg) && (!lq->enable_counter)){
+ lq->agg_ctrl.next_retry = 0;
+ lq->agg_ctrl.tid_retry = 0;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ return;
+ }
+*/
+ if (!(lq->agg_ctrl.granted_ba & tid_msk) &&
+ (lq->agg_ctrl.requested_ba & tid_msk)) {
+ u8 available_queues;
+ u32 load;
+
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ available_queues = iwl4964_tl_ba_avail(priv);
+ load = iwl4965_tl_get_load(priv, tid);
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ if (!available_queues) {
+ if (auto_agg)
+ lq->agg_ctrl.tid_retry |= tid_msk;
+ else {
+ lq->agg_ctrl.requested_ba &= ~tid_msk;
+ lq->agg_ctrl.wait_for_agg_status &= ~tid_msk;
+ }
+ } else if ((auto_agg) &&
+ ((load <= lq->agg_ctrl.tid_traffic_load_threshold) ||
+ ((lq->agg_ctrl.wait_for_agg_status & tid_msk))))
+ lq->agg_ctrl.tid_retry |= tid_msk;
+ else {
+ lq->agg_ctrl.wait_for_agg_status |= tid_msk;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ iwl4965_perform_addba(priv, tid, 0x40,
+ lq->agg_ctrl.ba_timeout);
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ }
+ }
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+}
+
+static void iwl4965_turn_on_agg(struct iwl_priv *priv, u8 tid)
+{
+ struct iwl_lq_mngr *lq;
+ unsigned long flags;
+
+ lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+
+ if ((tid < TID_MAX_LOAD_COUNT))
+ iwl4965_turn_on_agg_for_tid(priv, lq, lq->agg_ctrl.auto_agg,
+ tid);
+ else if (tid == TID_ALL_SPECIFIED) {
+ if (lq->agg_ctrl.requested_ba) {
+ for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++)
+ iwl4965_turn_on_agg_for_tid(priv, lq,
+ lq->agg_ctrl.auto_agg, tid);
+ } else {
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ lq->agg_ctrl.tid_retry = 0;
+ lq->agg_ctrl.next_retry = 0;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ }
+ }
+
+}
+
+void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid)
+{
+ u32 tid_msk;
+ struct iwl_lq_mngr *lq;
+ unsigned long flags;
+
+ lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+
+ if ((tid < TID_MAX_LOAD_COUNT)) {
+ tid_msk = 1 << tid;
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ lq->agg_ctrl.wait_for_agg_status |= tid_msk;
+ lq->agg_ctrl.requested_ba &= ~tid_msk;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ iwl4965_perform_delba(priv, tid);
+ } else if (tid == TID_ALL_SPECIFIED) {
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) {
+ tid_msk = 1 << tid;
+ lq->agg_ctrl.wait_for_agg_status |= tid_msk;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ iwl4965_perform_delba(priv, tid);
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ }
+ lq->agg_ctrl.requested_ba = 0;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ }
+}
+
+static void iwl4965_ba_status(struct iwl_priv *priv,
+ u8 tid, enum HT_STATUS status)
+{
+ struct iwl_lq_mngr *lq;
+ u32 tid_msk = (1 << tid);
+ unsigned long flags;
+
+ lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+
+ if ((tid >= TID_MAX_LOAD_COUNT))
+ goto out;
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ switch (status) {
+ case BA_STATUS_ACTIVE:
+ if (!(lq->agg_ctrl.granted_ba & tid_msk))
+ lq->agg_ctrl.granted_ba |= tid_msk;
+ break;
+ default:
+ if ((lq->agg_ctrl.granted_ba & tid_msk))
+ lq->agg_ctrl.granted_ba &= ~tid_msk;
+ break;
+ }
+
+ lq->agg_ctrl.wait_for_agg_status &= ~tid_msk;
+ if (status != BA_STATUS_ACTIVE) {
+ if (lq->agg_ctrl.auto_agg) {
+ lq->agg_ctrl.tid_retry |= tid_msk;
+ lq->agg_ctrl.next_retry =
+ jiffies + msecs_to_jiffies(500);
+ } else
+ lq->agg_ctrl.requested_ba &= ~tid_msk;
+ }
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ out:
+ return;
+}
+
+static void iwl4965_bg_agg_work(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ agg_work);
+
+ u32 tid;
+ u32 retry_tid;
+ u32 tid_msk;
+ unsigned long flags;
+ struct iwl_lq_mngr *lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ retry_tid = lq->agg_ctrl.tid_retry;
+ lq->agg_ctrl.tid_retry = 0;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+
+ if (retry_tid == TID_ALL_SPECIFIED)
+ iwl4965_turn_on_agg(priv, TID_ALL_SPECIFIED);
+ else {
+ for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) {
+ tid_msk = (1 << tid);
+ if (retry_tid & tid_msk)
+ iwl4965_turn_on_agg(priv, tid);
+ }
+ }
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ if (lq->agg_ctrl.tid_retry)
+ lq->agg_ctrl.next_retry = jiffies + msecs_to_jiffies(500);
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ return;
+}
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd,
+ u8 sta_id, dma_addr_t txcmd_phys,
+ struct ieee80211_hdr *hdr, u8 hdr_len,
+ struct ieee80211_tx_control *ctrl, void *sta_in)
+{
+ struct iwl_tx_cmd cmd;
+ struct iwl_tx_cmd *tx = (struct iwl_tx_cmd *)&out_cmd->cmd.payload[0];
+ dma_addr_t scratch_phys;
+ u8 unicast = 0;
+ u8 is_data = 1;
+ u16 fc;
+ u16 rate_flags;
+ int rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1);
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ __le16 *qc;
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+ unicast = !is_multicast_ether_addr(hdr->addr1);
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+ is_data = 0;
+
+ memcpy(&cmd, &(out_cmd->cmd.tx), sizeof(struct iwl_tx_cmd));
+ memset(tx, 0, sizeof(struct iwl_tx_cmd));
+ memcpy(tx->hdr, hdr, hdr_len);
+
+ tx->len = cmd.len;
+ tx->driver_txop = cmd.driver_txop;
+ tx->stop_time.life_time = cmd.stop_time.life_time;
+ tx->tx_flags = cmd.tx_flags;
+ tx->sta_id = cmd.sta_id;
+ tx->tid_tspec = cmd.tid_tspec;
+ tx->timeout.pm_frame_timeout = cmd.timeout.pm_frame_timeout;
+ tx->next_frame_len = cmd.next_frame_len;
+
+ tx->sec_ctl = cmd.sec_ctl;
+ memcpy(&(tx->key[0]), &(cmd.key[0]), 16);
+ tx->tx_flags = cmd.tx_flags;
+
+ tx->rts_retry_limit = cmd.rts_retry_limit;
+ tx->data_retry_limit = cmd.data_retry_limit;
+
+ scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
+ offsetof(struct iwl_tx_cmd, scratch);
+ tx->dram_lsb_ptr = cpu_to_le32(scratch_phys);
+ tx->dram_msb_ptr = iwl4965_get_dma_hi_address(scratch_phys);
+
+ /* Hard coded to start at the highest retry fallback position
+ * until the 4965 specific rate control algorithm is tied in */
+ tx->initial_rate_index = LINK_QUAL_MAX_RETRY_NUM - 1;
+
+ /* Alternate between antenna A and B for successive frames */
+ if (priv->use_ant_b_for_management_frame) {
+ priv->use_ant_b_for_management_frame = 0;
+ rate_flags = RATE_MCS_ANT_B_MSK;
+ } else {
+ priv->use_ant_b_for_management_frame = 1;
+ rate_flags = RATE_MCS_ANT_A_MSK;
+ }
+
+ if (!unicast || !is_data) {
+ if ((rate_index >= IWL_FIRST_CCK_RATE) &&
+ (rate_index <= IWL_LAST_CCK_RATE))
+ rate_flags |= RATE_MCS_CCK_MSK;
+ } else {
+ tx->initial_rate_index = 0;
+ tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
+ }
+
+ tx->rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[rate_index].plcp,
+ rate_flags);
+
+ if (ieee80211_is_back_request(fc))
+ tx->tx_flags |= TX_CMD_FLG_ACK_MSK |
+ TX_CMD_FLG_IMM_BA_RSP_MASK;
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ qc = ieee80211_get_qos_ctrl(hdr);
+ if (qc &&
+ (priv->iw_mode != IEEE80211_IF_TYPE_IBSS)) {
+ u8 tid = 0;
+ tid = (u8) (le16_to_cpu(*qc) & 0xF);
+ if (tid < TID_MAX_LOAD_COUNT)
+ iwl4965_tl_add_packet(priv, tid);
+ }
+
+ if (priv->lq_mngr.agg_ctrl.next_retry &&
+ (time_after(priv->lq_mngr.agg_ctrl.next_retry, jiffies))) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+ priv->lq_mngr.agg_ctrl.next_retry = 0;
+ spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ schedule_work(&priv->agg_work);
+ }
+#endif
+#endif
+ return 0;
+}
+
+/**
+ * sign_extend - Sign extend a value using specified bit as sign-bit
+ *
+ * Example: sign_extend(9, 3) would return -7 as bit3 of 1001b is 1
+ * and bit0..2 is 001b which when sign extended to 1111111111111001b is -7.
+ *
+ * @param oper value to sign extend
+ * @param index 0 based bit index (0<=index<32) to sign bit
+ */
+static s32 sign_extend(u32 oper, int index)
+{
+ u8 shift = 31 - index;
+
+ return (s32)(oper << shift) >> shift;
+}
+
+/**
+ * iwl4965_get_temperature - return the calibrated temperature (in Kelvin)
+ * @statistics: Provides the temperature reading from the uCode
+ *
+ * A return of <0 indicates bogus data in the statistics
+ */
+int iwl4965_get_temperature(const struct iwl_priv *priv)
+{
+ s32 temperature;
+ s32 vt;
+ s32 R1, R2, R3;
+ u32 R4;
+
+ if (test_bit(STATUS_TEMPERATURE, &priv->status) &&
+ (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)) {
+ IWL_DEBUG_TEMP("Running FAT temperature calibration\n");
+ R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
+ R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
+ R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]);
+ R4 = le32_to_cpu(priv->card_alive_init.therm_r4[1]);
+ } else {
+ IWL_DEBUG_TEMP("Running temperature calibration\n");
+ R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]);
+ R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]);
+ R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]);
+ R4 = le32_to_cpu(priv->card_alive_init.therm_r4[0]);
+ }
+
+ /*
+ * Temperature is only 23 bits so sign extend out to 32
+ *
+ * NOTE If we haven't received a statistics notification yet
+ * with an updated temperature, use R4 provided to us in the
+ * ALIVE response. */
+ if (!test_bit(STATUS_TEMPERATURE, &priv->status))
+ vt = sign_extend(R4, 23);
+ else
+ vt = sign_extend(
+ le32_to_cpu(priv->statistics.general.temperature), 23);
+
+ IWL_DEBUG_TEMP("Calib values R[1-3]: %d %d %d R4: %d\n",
+ R1, R2, R3, vt);
+
+ if (R3 == R1) {
+ IWL_ERROR("Calibration conflict R1 == R3\n");
+ return -1;
+ }
+
+ /* Calculate temperature in degrees Kelvin, adjust by 97%.
+ * Add offset to center the adjustment around 0 degrees Centigrade. */
+ temperature = TEMPERATURE_CALIB_A_VAL * (vt - R2);
+ temperature /= (R3 - R1);
+ temperature = (temperature * 97) / 100 +
+ TEMPERATURE_CALIB_KELVIN_OFFSET;
+
+ IWL_DEBUG_TEMP("Calibrated temperature: %dK, %dC\n", temperature,
+ KELVIN_TO_CELSIUS(temperature));
+
+ return temperature;
+}
+
+/* Adjust Txpower only if temperature variance is greater than threshold. */
+#define IWL_TEMPERATURE_THRESHOLD 3
+
+/**
+ * iwl4965_is_temp_calib_needed - determines if new calibration is needed
+ *
+ * If the temperature changed has changed sufficiently, then a recalibration
+ * is needed.
+ *
+ * Assumes caller will replace priv->last_temperature once calibration
+ * executed.
+ */
+static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv)
+{
+ int temp_diff;
+
+ if (!test_bit(STATUS_STATISTICS, &priv->status)) {
+ IWL_DEBUG_TEMP("Temperature not updated -- no statistics.\n");
+ return 0;
+ }
+
+ temp_diff = priv->temperature - priv->last_temperature;
+
+ /* get absolute value */
+ if (temp_diff < 0) {
+ IWL_DEBUG_POWER("Getting cooler, delta %d, \n", temp_diff);
+ temp_diff = -temp_diff;
+ } else if (temp_diff == 0)
+ IWL_DEBUG_POWER("Same temp, \n");
+ else
+ IWL_DEBUG_POWER("Getting warmer, delta %d, \n", temp_diff);
+
+ if (temp_diff < IWL_TEMPERATURE_THRESHOLD) {
+ IWL_DEBUG_POWER("Thermal txpower calib not needed\n");
+ return 0;
+ }
+
+ IWL_DEBUG_POWER("Thermal txpower calib needed\n");
+
+ return 1;
+}
+
+/* Calculate noise level, based on measurements during network silence just
+ * before arriving beacon. This measurement can be done only if we know
+ * exactly when to expect beacons, therefore only when we're associated. */
+static void iwl4965_rx_calc_noise(struct iwl_priv *priv)
+{
+ struct statistics_rx_non_phy *rx_info
+ = &(priv->statistics.rx.general);
+ int num_active_rx = 0;
+ int total_silence = 0;
+ int bcn_silence_a =
+ le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
+ int bcn_silence_b =
+ le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
+ int bcn_silence_c =
+ le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
+
+ if (bcn_silence_a) {
+ total_silence += bcn_silence_a;
+ num_active_rx++;
+ }
+ if (bcn_silence_b) {
+ total_silence += bcn_silence_b;
+ num_active_rx++;
+ }
+ if (bcn_silence_c) {
+ total_silence += bcn_silence_c;
+ num_active_rx++;
+ }
+
+ /* Average among active antennas */
+ if (num_active_rx)
+ priv->last_rx_noise = (total_silence / num_active_rx) - 107;
+ else
+ priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+ IWL_DEBUG_CALIB("inband silence a %u, b %u, c %u, dBm %d\n",
+ bcn_silence_a, bcn_silence_b, bcn_silence_c,
+ priv->last_rx_noise);
+}
+
+void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ int change;
+ s32 temp;
+
+ IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n",
+ (int)sizeof(priv->statistics), pkt->len);
+
+ change = ((priv->statistics.general.temperature !=
+ pkt->u.stats.general.temperature) ||
+ ((priv->statistics.flag &
+ STATISTICS_REPLY_FLG_FAT_MODE_MSK) !=
+ (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)));
+
+ memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
+
+ set_bit(STATUS_STATISTICS, &priv->status);
+
+ /* Reschedule the statistics timer to occur in
+ * REG_RECALIB_PERIOD seconds to ensure we get a
+ * thermal update even if the uCode doesn't give
+ * us one */
+ mod_timer(&priv->statistics_periodic, jiffies +
+ msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
+
+ if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
+ (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
+ iwl4965_rx_calc_noise(priv);
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ queue_work(priv->workqueue, &priv->sensitivity_work);
+#endif
+ }
+
+ /* If the hardware hasn't reported a change in
+ * temperature then don't bother computing a
+ * calibrated temperature value */
+ if (!change)
+ return;
+
+ temp = iwl4965_get_temperature(priv);
+ if (temp < 0)
+ return;
+
+ if (priv->temperature != temp) {
+ if (priv->temperature)
+ IWL_DEBUG_TEMP("Temperature changed "
+ "from %dC to %dC\n",
+ KELVIN_TO_CELSIUS(priv->temperature),
+ KELVIN_TO_CELSIUS(temp));
+ else
+ IWL_DEBUG_TEMP("Temperature "
+ "initialized to %dC\n",
+ KELVIN_TO_CELSIUS(temp));
+ }
+
+ priv->temperature = temp;
+ set_bit(STATUS_TEMPERATURE, &priv->status);
+
+ if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
+ iwl4965_is_temp_calib_needed(priv))
+ queue_work(priv->workqueue, &priv->txpower_work);
+}
+
+static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
+ int include_phy,
+ struct iwl_rx_mem_buffer *rxb,
+ struct ieee80211_rx_status *stats)
+{
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ struct iwl4965_rx_phy_res *rx_start = (include_phy) ?
+ (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL;
+ struct ieee80211_hdr *hdr;
+ u16 len;
+ __le32 *rx_end;
+ unsigned int skblen;
+ u32 ampdu_status;
+
+ if (!include_phy && priv->last_phy_res[0])
+ rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
+
+ if (!rx_start) {
+ IWL_ERROR("MPDU frame without a PHY data\n");
+ return;
+ }
+ if (include_phy) {
+ hdr = (struct ieee80211_hdr *)((u8 *) & rx_start[1] +
+ rx_start->cfg_phy_cnt);
+
+ len = le16_to_cpu(rx_start->byte_count);
+
+ rx_end = (__le32 *) ((u8 *) & pkt->u.raw[0] +
+ sizeof(struct iwl4965_rx_phy_res) +
+ rx_start->cfg_phy_cnt + len);
+
+ } else {
+ struct iwl4965_rx_mpdu_res_start *amsdu =
+ (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
+
+ hdr = (struct ieee80211_hdr *)(pkt->u.raw +
+ sizeof(struct iwl4965_rx_mpdu_res_start));
+ len = le16_to_cpu(amsdu->byte_count);
+ rx_start->byte_count = amsdu->byte_count;
+ rx_end = (__le32 *) (((u8 *) hdr) + len);
+ }
+ if (len > 2342 || len < 16) {
+ IWL_DEBUG_DROP("byte count out of range [16,2342]"
+ " : %d\n", len);
+ return;
+ }
+
+ ampdu_status = le32_to_cpu(*rx_end);
+ skblen = ((u8 *) rx_end - (u8 *) & pkt->u.raw[0]) + sizeof(u32);
+
+ /* start from MAC */
+ skb_reserve(rxb->skb, (void *)hdr - (void *)pkt);
+ skb_put(rxb->skb, len); /* end where data ends */
+
+ /* We only process data packets if the interface is open */
+ if (unlikely(!priv->is_open)) {
+ IWL_DEBUG_DROP_LIMIT
+ ("Dropping packet while interface is not open.\n");
+ return;
+ }
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+ if (iwl_param_hwcrypto)
+ iwl_set_decrypted_flag(priv, rxb->skb,
+ ampdu_status, stats);
+ iwl_handle_data_packet_monitor(priv, rxb, hdr, len, stats, 0);
+ return;
+ }
+
+ stats->flag = 0;
+ hdr = (struct ieee80211_hdr *)rxb->skb->data;
+
+ if (iwl_param_hwcrypto)
+ iwl_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats);
+
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ priv->alloc_rxb_skb--;
+ rxb->skb = NULL;
+#ifdef LED
+ priv->led_packets += len;
+ iwl_setup_activity_timer(priv);
+#endif
+}
+
+/* Calc max signal level (dBm) among 3 possible receivers */
+static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp)
+{
+ /* data from PHY/DSP regarding signal strength, etc.,
+ * contents are always there, not configurable by host. */
+ struct iwl4965_rx_non_cfg_phy *ncphy =
+ (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy;
+ u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK)
+ >> IWL_AGC_DB_POS;
+
+ u32 valid_antennae =
+ (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK)
+ >> RX_PHY_FLAGS_ANTENNAE_OFFSET;
+ u8 max_rssi = 0;
+ u32 i;
+
+ /* Find max rssi among 3 possible receivers.
+ * These values are measured by the digital signal processor (DSP).
+ * They should stay fairly constant even as the signal strength varies,
+ * if the radio's automatic gain control (AGC) is working right.
+ * AGC value (see below) will provide the "interesting" info. */
+ for (i = 0; i < 3; i++)
+ if (valid_antennae & (1 << i))
+ max_rssi = max(ncphy->rssi_info[i << 1], max_rssi);
+
+ IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n",
+ ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4],
+ max_rssi, agc);
+
+ /* dBm = max_rssi dB - agc dB - constant.
+ * Higher AGC (higher radio gain) means lower signal. */
+ return (max_rssi - agc - IWL_RSSI_OFFSET);
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+
+/* Parsed Information Elements */
+struct ieee802_11_elems {
+ u8 *ds_params;
+ u8 ds_params_len;
+ u8 *tim;
+ u8 tim_len;
+ u8 *ibss_params;
+ u8 ibss_params_len;
+ u8 *erp_info;
+ u8 erp_info_len;
+ u8 *ht_cap_param;
+ u8 ht_cap_param_len;
+ u8 *ht_extra_param;
+ u8 ht_extra_param_len;
+};
+
+static int parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems)
+{
+ size_t left = len;
+ u8 *pos = start;
+ int unknown = 0;
+
+ memset(elems, 0, sizeof(*elems));
+
+ while (left >= 2) {
+ u8 id, elen;
+
+ id = *pos++;
+ elen = *pos++;
+ left -= 2;
+
+ if (elen > left)
+ return -1;
+
+ switch (id) {
+ case WLAN_EID_DS_PARAMS:
+ elems->ds_params = pos;
+ elems->ds_params_len = elen;
+ break;
+ case WLAN_EID_TIM:
+ elems->tim = pos;
+ elems->tim_len = elen;
+ break;
+ case WLAN_EID_IBSS_PARAMS:
+ elems->ibss_params = pos;
+ elems->ibss_params_len = elen;
+ break;
+ case WLAN_EID_ERP_INFO:
+ elems->erp_info = pos;
+ elems->erp_info_len = elen;
+ break;
+ case WLAN_EID_HT_CAPABILITY:
+ elems->ht_cap_param = pos;
+ elems->ht_cap_param_len = elen;
+ break;
+ case WLAN_EID_HT_EXTRA_INFO:
+ elems->ht_extra_param = pos;
+ elems->ht_extra_param_len = elen;
+ break;
+ default:
+ unknown++;
+ break;
+ }
+
+ left -= elen;
+ pos += elen;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_IWLWIFI_HT */
+
+static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
+ priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
+ priv->stations[sta_id].sta.sta.modify_mask = 0;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
+{
+ /* FIXME: need locking over ps_status ??? */
+ u8 sta_id = iwl_hw_find_station(priv, addr);
+
+ if (sta_id != IWL_INVALID_STATION) {
+ u8 sta_awake = priv->stations[sta_id].
+ ps_status == STA_PS_STATUS_WAKE;
+
+ if (sta_awake && ps_bit)
+ priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
+ else if (!sta_awake && !ps_bit) {
+ iwl4965_sta_modify_ps_wake(priv, sta_id);
+ priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
+ }
+ }
+}
+
+/* Called for REPLY_4965_RX (legacy ABG frames), or
+ * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
+static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ /* Use phy data (Rx signal strength, etc.) contained within
+ * this rx packet for legacy frames,
+ * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */
+ int include_phy = (pkt->hdr.cmd == REPLY_4965_RX);
+ struct iwl4965_rx_phy_res *rx_start = (include_phy) ?
+ (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) :
+ (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
+ __le32 *rx_end;
+ unsigned int len = 0;
+ struct ieee80211_hdr *header;
+ u16 fc;
+ struct ieee80211_rx_status stats = {
+ .mactime = le64_to_cpu(rx_start->timestamp),
+ .channel = le16_to_cpu(rx_start->channel),
+ .phymode =
+ (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+ MODE_IEEE80211G : MODE_IEEE80211A,
+ .antenna = 0,
+ .rate = iwl_hw_get_rate(rx_start->rate_n_flags),
+ .flag = 0,
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ .ordered = 0
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+ };
+ u8 network_packet;
+
+ if ((unlikely(rx_start->cfg_phy_cnt > 20))) {
+ IWL_DEBUG_DROP
+ ("dsp size out of range [0,20]: "
+ "%d/n", rx_start->cfg_phy_cnt);
+ return;
+ }
+ if (!include_phy) {
+ if (priv->last_phy_res[0])
+ rx_start = (struct iwl4965_rx_phy_res *)
+ &priv->last_phy_res[1];
+ else
+ rx_start = NULL;
+ }
+
+ if (!rx_start) {
+ IWL_ERROR("MPDU frame without a PHY data\n");
+ return;
+ }
+
+ if (include_phy) {
+ header = (struct ieee80211_hdr *)((u8 *) & rx_start[1]
+ + rx_start->cfg_phy_cnt);
+
+ len = le16_to_cpu(rx_start->byte_count);
+ rx_end = (__le32 *) (pkt->u.raw + rx_start->cfg_phy_cnt +
+ sizeof(struct iwl4965_rx_phy_res) + len);
+ } else {
+ struct iwl4965_rx_mpdu_res_start *amsdu =
+ (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
+
+ header = (void *)(pkt->u.raw +
+ sizeof(struct iwl4965_rx_mpdu_res_start));
+ len = le16_to_cpu(amsdu->byte_count);
+ rx_end = (__le32 *) (pkt->u.raw +
+ sizeof(struct iwl4965_rx_mpdu_res_start) + len);
+ }
+
+ if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) ||
+ !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
+ IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n",
+ le32_to_cpu(*rx_end));
+ return;
+ }
+
+ priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp);
+
+ stats.freq = ieee80211chan2mhz(stats.channel);
+
+ /* Find max signal strength (dBm) among 3 antenna/receiver chains */
+ stats.ssi = iwl4965_calc_rssi(rx_start);
+
+ /* Meaningful noise values are available only from beacon statistics,
+ * which are gathered only when associated, and indicate noise
+ * only for the associated network channel ...
+ * Ignore these noise values while scanning (other channels) */
+ if (iwl_is_associated(priv) &&
+ !test_bit(STATUS_SCANNING, &priv->status)) {
+ stats.noise = priv->last_rx_noise;
+ stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise);
+ } else {
+ stats.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+ stats.signal = iwl_calc_sig_qual(stats.ssi, 0);
+ }
+
+ /* Reset beacon noise level if not associated. */
+ if (!iwl_is_associated(priv))
+ priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ /* TODO: Parts of iwl_report_frame are broken for 4965 */
+ if (iwl_debug_level & (IWL_DL_RX))
+ /* Set "1" to report good data frames in groups of 100 */
+ iwl_report_frame(priv, pkt, header, 1);
+
+ if (iwl_debug_level & (IWL_DL_RX | IWL_DL_STATS))
+ IWL_DEBUG_RX("Rssi %d, noise %d, qual %d, TSF %lu\n",
+ stats.ssi, stats.noise, stats.signal,
+ (long unsigned int)le64_to_cpu(rx_start->timestamp));
+#endif
+
+ network_packet = iwl_is_network_packet(priv, header);
+ if (network_packet) {
+ priv->last_rx_rssi = stats.ssi;
+ priv->last_beacon_time = priv->ucode_beacon_time;
+ priv->last_tsf = le64_to_cpu(rx_start->timestamp);
+ }
+
+ fc = le16_to_cpu(header->frame_control);
+ switch (fc & IEEE80211_FCTL_FTYPE) {
+ case IEEE80211_FTYPE_MGMT:
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM,
+ header->addr2);
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PROBE_RESP:
+ case IEEE80211_STYPE_BEACON:
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_STA &&
+ !compare_ether_addr(header->addr2, priv->bssid)) ||
+ (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+ !compare_ether_addr(header->addr3, priv->bssid))) {
+ struct ieee80211_mgmt *mgmt =
+ (struct ieee80211_mgmt *)header;
+ u64 timestamp =
+ le64_to_cpu(mgmt->u.beacon.timestamp);
+
+ priv->timestamp0 = timestamp & 0xFFFFFFFF;
+ priv->timestamp1 =
+ (timestamp >> 32) & 0xFFFFFFFF;
+ priv->beacon_int = le16_to_cpu(
+ mgmt->u.beacon.beacon_int);
+ if (priv->call_post_assoc_from_beacon &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
+ priv->call_post_assoc_from_beacon = 0;
+ queue_work(priv->workqueue,
+ &priv->post_associate.work);
+ }
+ }
+ break;
+
+ case IEEE80211_STYPE_ACTION:
+ break;
+
+ /*
+ * TODO: There is no callback function from upper
+ * stack to inform us when associated status. this
+ * work around to sniff assoc_resp management frame
+ * and finish the association process.
+ */
+ case IEEE80211_STYPE_ASSOC_RESP:
+ case IEEE80211_STYPE_REASSOC_RESP:
+ if (network_packet) {
+#ifdef CONFIG_IWLWIFI_HT
+ u8 *pos = NULL;
+ struct ieee802_11_elems elems;
+#endif /*CONFIG_IWLWIFI_HT */
+ struct ieee80211_mgmt *mgnt =
+ (struct ieee80211_mgmt *)header;
+
+ priv->assoc_id = (~((1 << 15) | (1 << 14))
+ & le16_to_cpu(mgnt->u.assoc_resp.aid));
+ priv->assoc_capability =
+ le16_to_cpu(
+ mgnt->u.assoc_resp.capab_info);
+#ifdef CONFIG_IWLWIFI_HT
+ pos = mgnt->u.assoc_resp.variable;
+ if (!parse_elems(pos,
+ len - (pos - (u8 *) mgnt),
+ &elems)) {
+ if (elems.ht_extra_param &&
+ elems.ht_cap_param)
+ break;
+ }
+#endif /*CONFIG_IWLWIFI_HT */
+ /* assoc_id is 0 no association */
+ if (!priv->assoc_id)
+ break;
+ if (priv->beacon_int)
+ queue_work(priv->workqueue,
+ &priv->post_associate.work);
+ else
+ priv->call_post_assoc_from_beacon = 1;
+ }
+
+ break;
+
+ case IEEE80211_STYPE_PROBE_REQ:
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ !iwl_is_associated(priv)) {
+ DECLARE_MAC_BUF(mac1);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+
+ IWL_DEBUG_DROP("Dropping (non network): "
+ "%s, %s, %s\n",
+ print_mac(mac1, header->addr1),
+ print_mac(mac2, header->addr2),
+ print_mac(mac3, header->addr3));
+ return;
+ }
+ }
+ iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &stats);
+ break;
+
+ case IEEE80211_FTYPE_CTL:
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_BACK_REQ:
+ IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n");
+ iwl4965_handle_data_packet(priv, 0, include_phy,
+ rxb, &stats);
+ break;
+ default:
+ break;
+ }
+#endif
+
+ break;
+
+ case IEEE80211_FTYPE_DATA: {
+ DECLARE_MAC_BUF(mac1);
+ DECLARE_MAC_BUF(mac2);
+ DECLARE_MAC_BUF(mac3);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ iwl4965_update_ps_mode(priv, fc & IEEE80211_FCTL_PM,
+ header->addr2);
+
+ if (unlikely(!network_packet))
+ IWL_DEBUG_DROP("Dropping (non network): "
+ "%s, %s, %s\n",
+ print_mac(mac1, header->addr1),
+ print_mac(mac2, header->addr2),
+ print_mac(mac3, header->addr3));
+ else if (unlikely(is_duplicate_packet(priv, header)))
+ IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
+ print_mac(mac1, header->addr1),
+ print_mac(mac2, header->addr2),
+ print_mac(mac3, header->addr3));
+ else
+ iwl4965_handle_data_packet(priv, 1, include_phy, rxb,
+ &stats);
+ break;
+ }
+ default:
+ break;
+
+ }
+}
+
+/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
+ * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
+static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ priv->last_phy_res[0] = 1;
+ memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
+ sizeof(struct iwl4965_rx_phy_res));
+}
+
+static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+
+{
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_missed_beacon_notif *missed_beacon;
+
+ missed_beacon = &pkt->u.missed_beacon;
+ if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
+ IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n",
+ le32_to_cpu(missed_beacon->consequtive_missed_beacons),
+ le32_to_cpu(missed_beacon->total_missed_becons),
+ le32_to_cpu(missed_beacon->num_recvd_beacons),
+ le32_to_cpu(missed_beacon->num_expected_beacons));
+ priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
+ if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)))
+ queue_work(priv->workqueue, &priv->sensitivity_work);
+ }
+#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+
+static void iwl4965_set_tx_status(struct iwl_priv *priv, int txq_id, int idx,
+ u32 status, u32 retry_count, u32 rate)
+{
+ struct ieee80211_tx_status *tx_status =
+ &(priv->txq[txq_id].txb[idx].status);
+
+ tx_status->flags = status ? IEEE80211_TX_STATUS_ACK : 0;
+ tx_status->retry_count += retry_count;
+ tx_status->control.tx_rate = rate;
+}
+
+
+static void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv,
+ int sta_id, int tid)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
+ priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+
+static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv,
+ struct iwl_ht_agg *agg,
+ struct iwl_compressed_ba_resp*
+ ba_resp)
+
+{
+ int i, sh, ack;
+ u16 ba_seq_ctl = le16_to_cpu(ba_resp->ba_seq_ctl);
+ u32 bitmap0, bitmap1;
+ u32 resp_bitmap0 = le32_to_cpu(ba_resp->ba_bitmap0);
+ u32 resp_bitmap1 = le32_to_cpu(ba_resp->ba_bitmap1);
+
+ if (unlikely(!agg->wait_for_ba)) {
+ IWL_ERROR("Received BA when not expected\n");
+ return -EINVAL;
+ }
+ agg->wait_for_ba = 0;
+ IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->ba_seq_ctl);
+ sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl>>4);
+ if (sh < 0) /* tbw something is wrong with indeces */
+ sh += 0x100;
+
+ /* don't use 64 bits for now */
+ bitmap0 = resp_bitmap0 >> sh;
+ bitmap1 = resp_bitmap1 >> sh;
+ bitmap0 |= (resp_bitmap1 & ((1<<sh)|((1<<sh)-1))) << (32 - sh);
+
+ if (agg->frame_count > (64 - sh)) {
+ IWL_DEBUG_TX_REPLY("more frames than bitmap size");
+ return -1;
+ }
+
+ /* check for success or failure according to the
+ * transmitted bitmap and back bitmap */
+ bitmap0 &= agg->bitmap0;
+ bitmap1 &= agg->bitmap1;
+
+ for (i = 0; i < agg->frame_count ; i++) {
+ int idx = (agg->start_idx + i) & 0xff;
+ ack = bitmap0 & (1 << i);
+ IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n",
+ ack? "ACK":"NACK", i, idx, agg->start_idx + i);
+ iwl4965_set_tx_status(priv, agg->txq_id, idx, ack, 0,
+ agg->rate_n_flags);
+
+ }
+
+ IWL_DEBUG_TX_REPLY("Bitmap %x%x\n", bitmap0, bitmap1);
+
+ return 0;
+}
+
+static inline int iwl_queue_dec_wrap(int index, int n_bd)
+{
+ return (index == 0) ? n_bd - 1 : index - 1;
+}
+
+static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
+ int index;
+ struct iwl_tx_queue *txq = NULL;
+ struct iwl_ht_agg *agg;
+ u16 ba_resp_scd_flow = le16_to_cpu(ba_resp->scd_flow);
+ u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
+
+ if (ba_resp_scd_flow >= ARRAY_SIZE(priv->txq)) {
+ IWL_ERROR("BUG_ON scd_flow is bigger than number of queues");
+ return;
+ }
+
+ txq = &priv->txq[ba_resp_scd_flow];
+ agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg;
+ index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
+
+ /* TODO: Need to get this copy more sefely - now good for debug */
+/*
+ {
+ DECLARE_MAC_BUF(mac);
+ IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, "
+ "sta_id = %d\n",
+ agg->wait_for_ba,
+ print_mac(mac, (u8*) &ba_resp->sta_addr_lo32),
+ ba_resp->sta_id);
+ IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%X%X, scd_flow = "
+ "%d, scd_ssn = %d\n",
+ ba_resp->tid,
+ ba_resp->ba_seq_ctl,
+ ba_resp->ba_bitmap1,
+ ba_resp->ba_bitmap0,
+ ba_resp->scd_flow,
+ ba_resp->scd_ssn);
+ IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%X%X \n",
+ agg->start_idx,
+ agg->bitmap1,
+ agg->bitmap0);
+ }
+*/
+ iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp);
+ /* releases all the TFDs until the SSN */
+ if (txq->q.last_used != (ba_resp_scd_ssn & 0xff))
+ iwl_tx_queue_reclaim(priv, ba_resp_scd_flow, index);
+
+}
+
+
+static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
+{
+ iwl_write_restricted_reg(priv,
+ SCD_QUEUE_STATUS_BITS(txq_id),
+ (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+ (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
+static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
+ u16 txq_id)
+{
+ u32 tbl_dw_addr;
+ u32 tbl_dw;
+ u16 scd_q2ratid;
+
+ scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK;
+
+ tbl_dw_addr = priv->scd_base_addr +
+ SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
+
+ tbl_dw = iwl_read_restricted_mem(priv, tbl_dw_addr);
+
+ if (txq_id & 0x1)
+ tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
+ else
+ tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
+
+ iwl_write_restricted_mem(priv, tbl_dw_addr, tbl_dw);
+
+ return 0;
+}
+
+/**
+ * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
+ */
+static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
+ int tx_fifo, int sta_id, int tid,
+ u16 ssn_idx)
+{
+ unsigned long flags;
+ int rc;
+ u16 ra_tid;
+
+ if (IWL_BACK_QUEUE_FIRST_ID > txq_id)
+ IWL_WARNING("queue number too small: %d, must be > %d\n",
+ txq_id, IWL_BACK_QUEUE_FIRST_ID);
+
+ ra_tid = BUILD_RAxTID(sta_id, tid);
+
+ iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ iwl4965_tx_queue_stop_scheduler(priv, txq_id);
+
+ iwl4965_tx_queue_set_q2ratid(priv, ra_tid, txq_id);
+
+
+ iwl_set_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1<<txq_id));
+
+ priv->txq[txq_id].q.last_used = (ssn_idx & 0xff);
+ priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff);
+
+ /* supposes that ssn_idx is valid (!= 0xFFF) */
+ iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
+
+ iwl_write_restricted_mem(priv,
+ priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id),
+ (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
+ SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
+
+ iwl_write_restricted_mem(priv, priv->scd_base_addr +
+ SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
+ (SCD_FRAME_LIMIT << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS)
+ & SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
+
+ iwl_set_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id));
+
+ iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+/**
+ * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
+ */
+static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id,
+ u16 ssn_idx, u8 tx_fifo)
+{
+ unsigned long flags;
+ int rc;
+
+ if (IWL_BACK_QUEUE_FIRST_ID > txq_id) {
+ IWL_WARNING("queue number too small: %d, must be > %d\n",
+ txq_id, IWL_BACK_QUEUE_FIRST_ID);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ iwl4965_tx_queue_stop_scheduler(priv, txq_id);
+
+ iwl_clear_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1 << txq_id));
+
+ priv->txq[txq_id].q.last_used = (ssn_idx & 0xff);
+ priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff);
+ /* supposes that ssn_idx is valid (!= 0xFFF) */
+ iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
+
+ iwl_clear_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id));
+ iwl4965_txq_ctx_deactivate(priv, txq_id);
+ iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
+
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+#endif/* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+/*
+ * RATE SCALE CODE
+ */
+int iwl4965_init_hw_rates(struct iwl_priv *priv, struct ieee80211_rate *rates)
+{
+ return 0;
+}
+
+
+/**
+ * iwl4965_add_station - Initialize a station's hardware rate table
+ *
+ * The uCode contains a table of fallback rates and retries per rate
+ * for automatic fallback during transmission.
+ *
+ * NOTE: This initializes the table for a single retry per data rate
+ * which is not optimal. Setting up an intelligent retry per rate
+ * requires feedback from transmission, which isn't exposed through
+ * rc80211_simple which is what this driver is currently using.
+ *
+ */
+void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+ int i, r;
+ struct iwl_link_quality_cmd link_cmd = {
+ .reserved1 = 0,
+ };
+ u16 rate_flags;
+
+ /* Set up the rate scaling to start at 54M and fallback
+ * all the way to 1M in IEEE order and then spin on IEEE */
+ if (is_ap)
+ r = IWL_RATE_54M_INDEX;
+ else if (priv->phymode == MODE_IEEE80211A)
+ r = IWL_RATE_6M_INDEX;
+ else
+ r = IWL_RATE_1M_INDEX;
+
+ for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+ rate_flags = 0;
+ if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
+ rate_flags |= RATE_MCS_CCK_MSK;
+
+ rate_flags |= RATE_MCS_ANT_B_MSK;
+ rate_flags &= ~RATE_MCS_ANT_A_MSK;
+ link_cmd.rs_table[i].rate_n_flags =
+ iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
+ r = iwl_get_prev_ieee_rate(r);
+ }
+
+ link_cmd.general_params.single_stream_ant_msk = 2;
+ link_cmd.general_params.dual_stream_ant_msk = 3;
+ link_cmd.agg_params.agg_dis_start_th = 3;
+ link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
+
+ /* Update the rate scaling for control frame Tx to AP */
+ link_cmd.sta_id = is_ap ? IWL_AP_ID : IWL4965_BROADCAST_ID;
+
+ iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd),
+ &link_cmd);
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+
+static u8 iwl_is_channel_extension(struct iwl_priv *priv, int phymode,
+ u16 channel, u8 extension_chan_offset)
+{
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv, phymode, channel);
+ if (!is_channel_valid(ch_info))
+ return 0;
+
+ if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO)
+ return 0;
+
+ if ((ch_info->fat_extension_channel == extension_chan_offset) ||
+ (ch_info->fat_extension_channel == HT_IE_EXT_CHANNEL_MAX))
+ return 1;
+
+ return 0;
+}
+
+static u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
+ const struct sta_ht_info *ht_info)
+{
+
+ if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
+ return 0;
+
+ if (ht_info->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ)
+ return 0;
+
+ if (ht_info->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO)
+ return 0;
+
+ /* no fat tx allowed on 2.4GHZ */
+ if (priv->phymode != MODE_IEEE80211A)
+ return 0;
+ return (iwl_is_channel_extension(priv, priv->phymode,
+ ht_info->control_channel,
+ ht_info->extension_chan_offset));
+}
+
+void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct sta_ht_info *ht_info)
+{
+ struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+ u32 val;
+
+ if (!ht_info->is_ht)
+ return;
+
+ if (iwl_is_fat_tx_allowed(priv, ht_info))
+ rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+ else
+ rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
+ RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
+
+ if (le16_to_cpu(rxon->channel) != ht_info->control_channel) {
+ IWL_DEBUG_ASSOC("control diff than current %d %d\n",
+ le16_to_cpu(rxon->channel),
+ ht_info->control_channel);
+ rxon->channel = cpu_to_le16(ht_info->control_channel);
+ return;
+ }
+
+ /* Note: control channel is oposit to extension channel */
+ switch (ht_info->extension_chan_offset) {
+ case IWL_EXT_CHANNEL_OFFSET_ABOVE:
+ rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
+ break;
+ case IWL_EXT_CHANNEL_OFFSET_BELOW:
+ rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+ break;
+ case IWL_EXT_CHANNEL_OFFSET_AUTO:
+ rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+ break;
+ default:
+ rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+ break;
+ }
+
+ val = ht_info->operating_mode;
+
+ rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
+
+ priv->active_rate_ht[0] = ht_info->supp_rates[0];
+ priv->active_rate_ht[1] = ht_info->supp_rates[1];
+ iwl4965_set_rxon_chain(priv);
+
+ IWL_DEBUG_ASSOC("supported HT rate 0x%X %X "
+ "rxon flags 0x%X operation mode :0x%X "
+ "extension channel offset 0x%x "
+ "control chan %d\n",
+ priv->active_rate_ht[0], priv->active_rate_ht[1],
+ le32_to_cpu(rxon->flags), ht_info->operating_mode,
+ ht_info->extension_chan_offset,
+ ht_info->control_channel);
+ return;
+}
+
+void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index)
+{
+ __le32 sta_flags;
+ struct sta_ht_info *ht_info = &priv->current_assoc_ht;
+
+ priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ;
+ if (!ht_info->is_ht)
+ goto done;
+
+ sta_flags = priv->stations[index].sta.station_flags;
+
+ if (ht_info->tx_mimo_ps_mode == IWL_MIMO_PS_DYNAMIC)
+ sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
+ else
+ sta_flags &= ~STA_FLG_RTS_MIMO_PROT_MSK;
+
+ sta_flags |= cpu_to_le32(
+ (u32)ht_info->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
+
+ sta_flags |= cpu_to_le32(
+ (u32)ht_info->mpdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
+
+ sta_flags &= (~STA_FLG_FAT_EN_MSK);
+ ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_20MHZ;
+ ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_20MHZ;
+
+ if (iwl_is_fat_tx_allowed(priv, ht_info)) {
+ sta_flags |= STA_FLG_FAT_EN_MSK;
+ ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_40MHZ;
+ if (ht_info->supported_chan_width == IWL_CHANNEL_WIDTH_40MHZ)
+ ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_40MHZ;
+ }
+ priv->current_channel_width = ht_info->tx_chan_width;
+ priv->stations[index].sta.station_flags = sta_flags;
+ done:
+ return;
+}
+
+#ifdef CONFIG_IWLWIFI_HT_AGG
+
+static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv,
+ int sta_id, int tid, u16 ssn)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.station_flags_msk = 0;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
+ priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
+ priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv,
+ int sta_id, int tid)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].sta.station_flags_msk = 0;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
+ priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+static const u16 default_tid_to_tx_fifo[] = {
+ IWL_TX_FIFO_AC1,
+ IWL_TX_FIFO_AC0,
+ IWL_TX_FIFO_AC0,
+ IWL_TX_FIFO_AC1,
+ IWL_TX_FIFO_AC2,
+ IWL_TX_FIFO_AC2,
+ IWL_TX_FIFO_AC3,
+ IWL_TX_FIFO_AC3,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_NONE,
+ IWL_TX_FIFO_AC3
+};
+
+static int iwl_txq_ctx_activate_free(struct iwl_priv *priv)
+{
+ int txq_id;
+
+ for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++)
+ if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
+ return txq_id;
+ return -1;
+}
+
+int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid,
+ u16 *start_seq_num)
+{
+
+ struct iwl_priv *priv = hw->priv;
+ int sta_id;
+ int tx_fifo;
+ int txq_id;
+ int ssn = -1;
+ unsigned long flags;
+ struct iwl_tid_data *tid_data;
+ DECLARE_MAC_BUF(mac);
+
+ if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
+ tx_fifo = default_tid_to_tx_fifo[tid];
+ else
+ return -EINVAL;
+
+ IWL_WARNING("iwl-AGG iwl_mac_ht_tx_agg_start on da=%s"
+ " tid=%d\n", print_mac(mac, da), tid);
+
+ sta_id = iwl_hw_find_station(priv, da);
+ if (sta_id == IWL_INVALID_STATION)
+ return -ENXIO;
+
+ txq_id = iwl_txq_ctx_activate_free(priv);
+ if (txq_id == -1)
+ return -ENXIO;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ tid_data = &priv->stations[sta_id].tid[tid];
+ ssn = SEQ_TO_SN(tid_data->seq_number);
+ tid_data->agg.txq_id = txq_id;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ *start_seq_num = ssn;
+ iwl4965_ba_status(priv, tid, BA_STATUS_ACTIVE);
+ return iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo,
+ sta_id, tid, ssn);
+}
+
+
+int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid,
+ int generator)
+{
+
+ struct iwl_priv *priv = hw->priv;
+ int tx_fifo_id, txq_id, sta_id, ssn = -1;
+ struct iwl_tid_data *tid_data;
+ int rc;
+ DECLARE_MAC_BUF(mac);
+
+ if (!da) {
+ IWL_ERROR("%s: da = NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
+ tx_fifo_id = default_tid_to_tx_fifo[tid];
+ else
+ return -EINVAL;
+
+ sta_id = iwl_hw_find_station(priv, da);
+
+ if (sta_id == IWL_INVALID_STATION)
+ return -ENXIO;
+
+ tid_data = &priv->stations[sta_id].tid[tid];
+ ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
+ txq_id = tid_data->agg.txq_id;
+
+ rc = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id);
+ /* FIXME: need more safe way to handle error condition */
+ if (rc)
+ return rc;
+
+ iwl4965_ba_status(priv, tid, BA_STATUS_INITIATOR_DELBA);
+ IWL_DEBUG_INFO("iwl_mac_ht_tx_agg_stop on da=%s tid=%d\n",
+ print_mac(mac, da), tid);
+
+ return 0;
+}
+
+int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da,
+ u16 tid, u16 start_seq_num)
+{
+ struct iwl_priv *priv = hw->priv;
+ int sta_id;
+ DECLARE_MAC_BUF(mac);
+
+ IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_start on da=%s"
+ " tid=%d\n", print_mac(mac, da), tid);
+ sta_id = iwl_hw_find_station(priv, da);
+ iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, start_seq_num);
+ return 0;
+}
+
+int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da,
+ u16 tid, int generator)
+{
+ struct iwl_priv *priv = hw->priv;
+ int sta_id;
+ DECLARE_MAC_BUF(mac);
+
+ IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_stop on da=%s tid=%d\n",
+ print_mac(mac, da), tid);
+ sta_id = iwl_hw_find_station(priv, da);
+ iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid);
+ return 0;
+}
+
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+/* Set up 4965-specific Rx frame reply handlers */
+void iwl_hw_rx_handler_setup(struct iwl_priv *priv)
+{
+ /* Legacy Rx frames */
+ priv->rx_handlers[REPLY_4965_RX] = iwl4965_rx_reply_rx;
+
+ /* High-throughput (HT) Rx frames */
+ priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy;
+ priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx;
+
+ priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
+ iwl4965_rx_missed_beacon_notif;
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba;
+#endif /* CONFIG_IWLWIFI_AGG */
+#endif /* CONFIG_IWLWIFI */
+}
+
+void iwl_hw_setup_deferred_work(struct iwl_priv *priv)
+{
+ INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work);
+ INIT_WORK(&priv->statistics_work, iwl4965_bg_statistics_work);
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work);
+#endif
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ INIT_WORK(&priv->agg_work, iwl4965_bg_agg_work);
+#endif /* CONFIG_IWLWIFI_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+ init_timer(&priv->statistics_periodic);
+ priv->statistics_periodic.data = (unsigned long)priv;
+ priv->statistics_periodic.function = iwl4965_bg_statistics_periodic;
+}
+
+void iwl_hw_cancel_deferred_work(struct iwl_priv *priv)
+{
+ del_timer_sync(&priv->statistics_periodic);
+
+ cancel_delayed_work(&priv->init_alive_start);
+}
+
+struct pci_device_id iwl_hw_card_ids[] = {
+ {0x8086, 0x4229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0x8086, 0x4230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0}
+};
+
+int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv)
+{
+ u16 count;
+ int rc;
+
+ for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+ rc = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+ EEPROM_SEM_TIMEOUT);
+ if (rc >= 0) {
+ IWL_DEBUG_IO("Aqcuired semaphore after %d tries.\n",
+ count+1);
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
+inline void iwl_eeprom_release_semaphore(struct iwl_priv *priv)
+{
+ iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+}
+
+
+MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
new file mode 100644
index 00000000000..4c700812b45
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -0,0 +1,341 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#ifndef __iwl_4965_h__
+#define __iwl_4965_h__
+
+struct iwl_priv;
+struct sta_ht_info;
+
+/*
+ * Forward declare iwl-4965.c functions for iwl-base.c
+ */
+extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv);
+extern void iwl_eeprom_release_semaphore(struct iwl_priv *priv);
+
+extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq,
+ u16 byte_cnt);
+extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr,
+ int is_ap);
+extern void iwl4965_set_rxon_ht(struct iwl_priv *priv,
+ struct sta_ht_info *ht_info);
+
+extern void iwl4965_set_rxon_chain(struct iwl_priv *priv);
+extern int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd,
+ u8 sta_id, dma_addr_t txcmd_phys,
+ struct ieee80211_hdr *hdr, u8 hdr_len,
+ struct ieee80211_tx_control *ctrl, void *sta_in);
+extern int iwl4965_init_hw_rates(struct iwl_priv *priv,
+ struct ieee80211_rate *rates);
+extern int iwl4965_alive_notify(struct iwl_priv *priv);
+extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode);
+extern void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index);
+
+extern void iwl4965_chain_noise_reset(struct iwl_priv *priv);
+extern void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags,
+ u8 force);
+extern int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode,
+ u16 channel,
+ const struct iwl_eeprom_channel *eeprom_ch,
+ u8 fat_extension_channel);
+extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv);
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+extern int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da,
+ u16 tid, u16 *start_seq_num);
+extern int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da,
+ u16 tid, u16 start_seq_num);
+extern int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da,
+ u16 tid, int generator);
+extern int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da,
+ u16 tid, int generator);
+extern void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid);
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /*CONFIG_IWLWIFI_HT */
+/* Structures, enum, and defines specific to the 4965 */
+
+#define IWL4965_KW_SIZE 0x1000 /*4k */
+
+struct iwl_kw {
+ dma_addr_t dma_addr;
+ void *v_addr;
+ size_t size;
+};
+
+#define TID_QUEUE_CELL_SPACING 50 /*mS */
+#define TID_QUEUE_MAX_SIZE 20
+#define TID_ROUND_VALUE 5 /* mS */
+#define TID_MAX_LOAD_COUNT 8
+
+#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
+#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
+
+#define TID_ALL_ENABLED 0x7f
+#define TID_ALL_SPECIFIED 0xff
+#define TID_AGG_TPT_THREHOLD 0x0
+
+#define IWL_CHANNEL_WIDTH_20MHZ 0
+#define IWL_CHANNEL_WIDTH_40MHZ 1
+
+#define IWL_MIMO_PS_STATIC 0
+#define IWL_MIMO_PS_NONE 3
+#define IWL_MIMO_PS_DYNAMIC 1
+#define IWL_MIMO_PS_INVALID 2
+
+#define IWL_OPERATION_MODE_AUTO 0
+#define IWL_OPERATION_MODE_HT_ONLY 1
+#define IWL_OPERATION_MODE_MIXED 2
+#define IWL_OPERATION_MODE_20MHZ 3
+
+#define IWL_EXT_CHANNEL_OFFSET_AUTO 0
+#define IWL_EXT_CHANNEL_OFFSET_ABOVE 1
+#define IWL_EXT_CHANNEL_OFFSET_ 2
+#define IWL_EXT_CHANNEL_OFFSET_BELOW 3
+#define IWL_EXT_CHANNEL_OFFSET_MAX 4
+
+#define NRG_NUM_PREV_STAT_L 20
+#define NUM_RX_CHAINS (3)
+
+#define TX_POWER_IWL_ILLEGAL_VDET -100000
+#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
+#define TX_POWER_IWL_CLOSED_LOOP_MIN_POWER 18
+#define TX_POWER_IWL_CLOSED_LOOP_MAX_POWER 34
+#define TX_POWER_IWL_VDET_SLOPE_BELOW_NOMINAL 17
+#define TX_POWER_IWL_VDET_SLOPE_ABOVE_NOMINAL 20
+#define TX_POWER_IWL_NOMINAL_POWER 26
+#define TX_POWER_IWL_CLOSED_LOOP_ITERATION_LIMIT 1
+#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V 7
+#define TX_POWER_IWL_DEGREES_PER_VDET_CODE 11
+#define IWL_TX_POWER_MAX_NUM_PA_MEASUREMENTS 1
+#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9)
+#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5)
+
+struct iwl_traffic_load {
+ unsigned long time_stamp;
+ u32 packet_count[TID_QUEUE_MAX_SIZE];
+ u8 queue_count;
+ u8 head;
+ u32 total;
+};
+
+#ifdef CONFIG_IWLWIFI_HT_AGG
+struct iwl_agg_control {
+ unsigned long next_retry;
+ u32 wait_for_agg_status;
+ u32 tid_retry;
+ u32 requested_ba;
+ u32 granted_ba;
+ u8 auto_agg;
+ u32 tid_traffic_load_threshold;
+ u32 ba_timeout;
+ struct iwl_traffic_load traffic_load[TID_MAX_LOAD_COUNT];
+};
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+
+struct iwl_lq_mngr {
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ struct iwl_agg_control agg_ctrl;
+#endif
+ spinlock_t lock;
+ s32 max_window_size;
+ s32 *expected_tpt;
+ u8 *next_higher_rate;
+ u8 *next_lower_rate;
+ unsigned long stamp;
+ unsigned long stamp_last;
+ u32 flush_time;
+ u32 tx_packets;
+ u8 lq_ready;
+};
+
+
+/* Sensitivity and chain noise calibration */
+#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1)
+#define INITIALIZATION_VALUE 0xFFFF
+#define CAL_NUM_OF_BEACONS 20
+#define MAXIMUM_ALLOWED_PATHLOSS 15
+
+/* Param table within SENSITIVITY_CMD */
+#define HD_MIN_ENERGY_CCK_DET_INDEX (0)
+#define HD_MIN_ENERGY_OFDM_DET_INDEX (1)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX (2)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX (3)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX (4)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX (5)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX (6)
+#define HD_BARKER_CORR_TH_ADD_MIN_INDEX (7)
+#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX (8)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9)
+#define HD_OFDM_ENERGY_TH_IN_INDEX (10)
+
+#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0)
+#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1)
+
+#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
+
+#define MAX_FA_OFDM 50
+#define MIN_FA_OFDM 5
+#define MAX_FA_CCK 50
+#define MIN_FA_CCK 5
+
+#define NRG_MIN_CCK 97
+#define NRG_MAX_CCK 0
+
+#define AUTO_CORR_MIN_OFDM 85
+#define AUTO_CORR_MIN_OFDM_MRC 170
+#define AUTO_CORR_MIN_OFDM_X1 105
+#define AUTO_CORR_MIN_OFDM_MRC_X1 220
+#define AUTO_CORR_MAX_OFDM 120
+#define AUTO_CORR_MAX_OFDM_MRC 210
+#define AUTO_CORR_MAX_OFDM_X1 140
+#define AUTO_CORR_MAX_OFDM_MRC_X1 270
+#define AUTO_CORR_STEP_OFDM 1
+
+#define AUTO_CORR_MIN_CCK (125)
+#define AUTO_CORR_MAX_CCK (200)
+#define AUTO_CORR_MIN_CCK_MRC 200
+#define AUTO_CORR_MAX_CCK_MRC 400
+#define AUTO_CORR_STEP_CCK 3
+#define AUTO_CORR_MAX_TH_CCK 160
+
+#define NRG_ALG 0
+#define AUTO_CORR_ALG 1
+#define NRG_DIFF 2
+#define NRG_STEP_CCK 2
+#define NRG_MARGIN 8
+#define MAX_NUMBER_CCK_NO_FA 100
+
+#define AUTO_CORR_CCK_MIN_VAL_DEF (125)
+
+#define CHAIN_A 0
+#define CHAIN_B 1
+#define CHAIN_C 2
+#define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4
+#define ALL_BAND_FILTER 0xFF00
+#define IN_BAND_FILTER 0xFF
+#define MIN_AVERAGE_NOISE_MAX_VALUE 0xFFFFFFFF
+
+enum iwl_false_alarm_state {
+ IWL_FA_TOO_MANY = 0,
+ IWL_FA_TOO_FEW = 1,
+ IWL_FA_GOOD_RANGE = 2,
+};
+
+enum iwl_chain_noise_state {
+ IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */
+ IWL_CHAIN_NOISE_ACCUMULATE = 1,
+ IWL_CHAIN_NOISE_CALIBRATED = 2,
+};
+
+enum iwl_sensitivity_state {
+ IWL_SENS_CALIB_ALLOWED = 0,
+ IWL_SENS_CALIB_NEED_REINIT = 1,
+};
+
+enum iwl_calib_enabled_state {
+ IWL_CALIB_DISABLED = 0, /* must be 0 */
+ IWL_CALIB_ENABLED = 1,
+};
+
+struct statistics_general_data {
+ u32 beacon_silence_rssi_a;
+ u32 beacon_silence_rssi_b;
+ u32 beacon_silence_rssi_c;
+ u32 beacon_energy_a;
+ u32 beacon_energy_b;
+ u32 beacon_energy_c;
+};
+
+/* Sensitivity calib data */
+struct iwl_sensitivity_data {
+ u32 auto_corr_ofdm;
+ u32 auto_corr_ofdm_mrc;
+ u32 auto_corr_ofdm_x1;
+ u32 auto_corr_ofdm_mrc_x1;
+ u32 auto_corr_cck;
+ u32 auto_corr_cck_mrc;
+
+ u32 last_bad_plcp_cnt_ofdm;
+ u32 last_fa_cnt_ofdm;
+ u32 last_bad_plcp_cnt_cck;
+ u32 last_fa_cnt_cck;
+
+ u32 nrg_curr_state;
+ u32 nrg_prev_state;
+ u32 nrg_value[10];
+ u8 nrg_silence_rssi[NRG_NUM_PREV_STAT_L];
+ u32 nrg_silence_ref;
+ u32 nrg_energy_idx;
+ u32 nrg_silence_idx;
+ u32 nrg_th_cck;
+ s32 nrg_auto_corr_silence_diff;
+ u32 num_in_cck_no_fa;
+ u32 nrg_th_ofdm;
+
+ u8 state;
+};
+
+/* Chain noise (differential Rx gain) calib data */
+struct iwl_chain_noise_data {
+ u8 state;
+ u16 beacon_count;
+ u32 chain_noise_a;
+ u32 chain_noise_b;
+ u32 chain_noise_c;
+ u32 chain_signal_a;
+ u32 chain_signal_b;
+ u32 chain_signal_c;
+ u8 disconn_array[NUM_RX_CHAINS];
+ u8 delta_gain_code[NUM_RX_CHAINS];
+ u8 radio_write;
+};
+
+/* IWL4965 */
+#define RATE_MCS_CODE_MSK 0x7
+#define RATE_MCS_MIMO_POS 3
+#define RATE_MCS_MIMO_MSK 0x8
+#define RATE_MCS_HT_DUP_POS 5
+#define RATE_MCS_HT_DUP_MSK 0x20
+#define RATE_MCS_FLAGS_POS 8
+#define RATE_MCS_HT_POS 8
+#define RATE_MCS_HT_MSK 0x100
+#define RATE_MCS_CCK_POS 9
+#define RATE_MCS_CCK_MSK 0x200
+#define RATE_MCS_GF_POS 10
+#define RATE_MCS_GF_MSK 0x400
+
+#define RATE_MCS_FAT_POS 11
+#define RATE_MCS_FAT_MSK 0x800
+#define RATE_MCS_DUP_POS 12
+#define RATE_MCS_DUP_MSK 0x1000
+#define RATE_MCS_SGI_POS 13
+#define RATE_MCS_SGI_MSK 0x2000
+
+#define EEPROM_SEM_TIMEOUT 10
+#define EEPROM_SEM_RETRY_LIMIT 1000
+
+#endif /* __iwl_4965_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-channel.h b/drivers/net/wireless/iwlwifi/iwl-channel.h
new file mode 100644
index 00000000000..023c3f240ce
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-channel.h
@@ -0,0 +1,161 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#ifndef __iwl_channel_h__
+#define __iwl_channel_h__
+
+#define IWL_NUM_SCAN_RATES (2)
+
+struct iwl_channel_tgd_info {
+ u8 type;
+ s8 max_power;
+};
+
+struct iwl_channel_tgh_info {
+ s64 last_radar_time;
+};
+
+/* current Tx power values to use, one for each rate for each channel.
+ * requested power is limited by:
+ * -- regulatory EEPROM limits for this channel
+ * -- hardware capabilities (clip-powers)
+ * -- spectrum management
+ * -- user preference (e.g. iwconfig)
+ * when requested power is set, base power index must also be set. */
+struct iwl_channel_power_info {
+ struct iwl_tx_power tpc; /* actual radio and DSP gain settings */
+ s8 power_table_index; /* actual (compenst'd) index into gain table */
+ s8 base_power_index; /* gain index for power at factory temp. */
+ s8 requested_power; /* power (dBm) requested for this chnl/rate */
+};
+
+/* current scan Tx power values to use, one for each scan rate for each
+ * channel. */
+struct iwl_scan_power_info {
+ struct iwl_tx_power tpc; /* actual radio and DSP gain settings */
+ s8 power_table_index; /* actual (compenst'd) index into gain table */
+ s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */
+};
+
+/* Channel unlock period is 15 seconds. If no beacon or probe response
+ * has been received within 15 seconds on a locked channel then the channel
+ * remains locked. */
+#define TX_UNLOCK_PERIOD 15
+
+/* CSA lock period is 15 seconds. If a CSA has been received on a channel in
+ * the last 15 seconds, the channel is locked */
+#define CSA_LOCK_PERIOD 15
+/*
+ * One for each channel, holds all channel setup data
+ * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
+ * with one another!
+ */
+#define IWL4965_MAX_RATE (33)
+
+struct iwl_channel_info {
+ struct iwl_channel_tgd_info tgd;
+ struct iwl_channel_tgh_info tgh;
+ struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */
+ struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for
+ * FAT channel */
+
+ u8 channel; /* channel number */
+ u8 flags; /* flags copied from EEPROM */
+ s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
+ s8 curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */
+ s8 min_power; /* always 0 */
+ s8 scan_power; /* (dBm) regul. eeprom, direct scans, any rate */
+
+ u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */
+ u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */
+ u8 phymode; /* MODE_IEEE80211{A,B,G} */
+
+ /* Radio/DSP gain settings for each "normal" data Tx rate.
+ * These include, in addition to RF and DSP gain, a few fields for
+ * remembering/modifying gain settings (indexes). */
+ struct iwl_channel_power_info power_info[IWL4965_MAX_RATE];
+
+#if IWL == 4965
+ /* FAT channel info */
+ s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
+ s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */
+ s8 fat_min_power; /* always 0 */
+ s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */
+ u8 fat_flags; /* flags copied from EEPROM */
+ u8 fat_extension_channel;
+#endif
+
+ /* Radio/DSP gain settings for each scan rate, for directed scans. */
+ struct iwl_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
+};
+
+struct iwl_clip_group {
+ /* maximum power level to prevent clipping for each rate, derived by
+ * us from this band's saturation power in EEPROM */
+ const s8 clip_powers[IWL_MAX_RATES];
+};
+
+static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
+{
+ if (ch_info == NULL)
+ return 0;
+ return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
+}
+
+static inline int is_channel_narrow(const struct iwl_channel_info *ch_info)
+{
+ return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0;
+}
+
+static inline int is_channel_radar(const struct iwl_channel_info *ch_info)
+{
+ return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
+}
+
+static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info)
+{
+ return ch_info->phymode == MODE_IEEE80211A;
+}
+
+static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info)
+{
+ return ((ch_info->phymode == MODE_IEEE80211B) ||
+ (ch_info->phymode == MODE_IEEE80211G));
+}
+
+static inline int is_channel_passive(const struct iwl_channel_info *ch)
+{
+ return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
+}
+
+static inline int is_channel_ibss(const struct iwl_channel_info *ch)
+{
+ return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
+}
+
+extern const struct iwl_channel_info *iwl_get_channel_info(
+ const struct iwl_priv *priv, int phymode, u16 channel);
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
new file mode 100644
index 00000000000..9de8d7f6efa
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -0,0 +1,1734 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_commands_h__
+#define __iwl_commands_h__
+
+enum {
+ REPLY_ALIVE = 0x1,
+ REPLY_ERROR = 0x2,
+
+ /* RXON and QOS commands */
+ REPLY_RXON = 0x10,
+ REPLY_RXON_ASSOC = 0x11,
+ REPLY_QOS_PARAM = 0x13,
+ REPLY_RXON_TIMING = 0x14,
+
+ /* Multi-Station support */
+ REPLY_ADD_STA = 0x18,
+ REPLY_REMOVE_STA = 0x19, /* not used */
+ REPLY_REMOVE_ALL_STA = 0x1a, /* not used */
+
+ /* RX, TX, LEDs */
+#if IWL == 3945
+ REPLY_3945_RX = 0x1b, /* 3945 only */
+#endif
+ REPLY_TX = 0x1c,
+ REPLY_RATE_SCALE = 0x47, /* 3945 only */
+ REPLY_LEDS_CMD = 0x48,
+ REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
+
+ /* 802.11h related */
+ RADAR_NOTIFICATION = 0x70, /* not used */
+ REPLY_QUIET_CMD = 0x71, /* not used */
+ REPLY_CHANNEL_SWITCH = 0x72,
+ CHANNEL_SWITCH_NOTIFICATION = 0x73,
+ REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74,
+ SPECTRUM_MEASURE_NOTIFICATION = 0x75,
+
+ /* Power Management */
+ POWER_TABLE_CMD = 0x77,
+ PM_SLEEP_NOTIFICATION = 0x7A,
+ PM_DEBUG_STATISTIC_NOTIFIC = 0x7B,
+
+ /* Scan commands and notifications */
+ REPLY_SCAN_CMD = 0x80,
+ REPLY_SCAN_ABORT_CMD = 0x81,
+ SCAN_START_NOTIFICATION = 0x82,
+ SCAN_RESULTS_NOTIFICATION = 0x83,
+ SCAN_COMPLETE_NOTIFICATION = 0x84,
+
+ /* IBSS/AP commands */
+ BEACON_NOTIFICATION = 0x90,
+ REPLY_TX_BEACON = 0x91,
+ WHO_IS_AWAKE_NOTIFICATION = 0x94, /* not used */
+
+ /* Miscellaneous commands */
+ QUIET_NOTIFICATION = 0x96, /* not used */
+ REPLY_TX_PWR_TABLE_CMD = 0x97,
+ MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */
+
+ /* BT config command */
+ REPLY_BT_CONFIG = 0x9b,
+
+ /* 4965 Statistics */
+ REPLY_STATISTICS_CMD = 0x9c,
+ STATISTICS_NOTIFICATION = 0x9d,
+
+ /* RF-KILL commands and notifications */
+ REPLY_CARD_STATE_CMD = 0xa0,
+ CARD_STATE_NOTIFICATION = 0xa1,
+
+ /* Missed beacons notification */
+ MISSED_BEACONS_NOTIFICATION = 0xa2,
+
+#if IWL == 4965
+ REPLY_CT_KILL_CONFIG_CMD = 0xa4,
+ SENSITIVITY_CMD = 0xa8,
+ REPLY_PHY_CALIBRATION_CMD = 0xb0,
+ REPLY_RX_PHY_CMD = 0xc0,
+ REPLY_RX_MPDU_CMD = 0xc1,
+ REPLY_4965_RX = 0xc3,
+ REPLY_COMPRESSED_BA = 0xc5,
+#endif
+ REPLY_MAX = 0xff
+};
+
+/******************************************************************************
+ * (0)
+ * Header
+ *
+ *****************************************************************************/
+
+#define IWL_CMD_FAILED_MSK 0x40
+
+struct iwl_cmd_header {
+ u8 cmd;
+ u8 flags;
+ /* We have 15 LSB to use as we please (MSB indicates
+ * a frame Rx'd from the HW). We encode the following
+ * information into the sequence field:
+ *
+ * 0:7 index in fifo
+ * 8:13 fifo selection
+ * 14:14 bit indicating if this packet references the 'extra'
+ * storage at the end of the memory queue
+ * 15:15 (Rx indication)
+ *
+ */
+ __le16 sequence;
+
+ /* command data follows immediately */
+ u8 data[0];
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (0a)
+ * Alive and Error Commands & Responses:
+ *
+ *****************************************************************************/
+
+#define UCODE_VALID_OK __constant_cpu_to_le32(0x1)
+#define INITIALIZE_SUBTYPE (9)
+
+/*
+ * REPLY_ALIVE = 0x1 (response only, not a command)
+ */
+struct iwl_alive_resp {
+ u8 ucode_minor;
+ u8 ucode_major;
+ __le16 reserved1;
+ u8 sw_rev[8];
+ u8 ver_type;
+ u8 ver_subtype;
+ __le16 reserved2;
+ __le32 log_event_table_ptr;
+ __le32 error_event_table_ptr;
+ __le32 timestamp;
+ __le32 is_valid;
+} __attribute__ ((packed));
+
+struct iwl_init_alive_resp {
+ u8 ucode_minor;
+ u8 ucode_major;
+ __le16 reserved1;
+ u8 sw_rev[8];
+ u8 ver_type;
+ u8 ver_subtype;
+ __le16 reserved2;
+ __le32 log_event_table_ptr;
+ __le32 error_event_table_ptr;
+ __le32 timestamp;
+ __le32 is_valid;
+
+#if IWL == 4965
+ /* calibration values from "initialize" uCode */
+ __le32 voltage; /* signed */
+ __le32 therm_r1[2]; /* signed 1st for normal, 2nd for FAT channel */
+ __le32 therm_r2[2]; /* signed */
+ __le32 therm_r3[2]; /* signed */
+ __le32 therm_r4[2]; /* signed */
+ __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups,
+ * 2 Tx chains */
+#endif
+} __attribute__ ((packed));
+
+union tsf {
+ u8 byte[8];
+ __le16 word[4];
+ __le32 dw[2];
+};
+
+/*
+ * REPLY_ERROR = 0x2 (response only, not a command)
+ */
+struct iwl_error_resp {
+ __le32 error_type;
+ u8 cmd_id;
+ u8 reserved1;
+ __le16 bad_cmd_seq_num;
+#if IWL == 3945
+ __le16 reserved2;
+#endif
+ __le32 error_info;
+ union tsf timestamp;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (1)
+ * RXON Commands & Responses:
+ *
+ *****************************************************************************/
+
+/*
+ * Rx config defines & structure
+ */
+/* rx_config device types */
+enum {
+ RXON_DEV_TYPE_AP = 1,
+ RXON_DEV_TYPE_ESS = 3,
+ RXON_DEV_TYPE_IBSS = 4,
+ RXON_DEV_TYPE_SNIFFER = 6,
+};
+
+/* rx_config flags */
+/* band & modulation selection */
+#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0)
+#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1)
+/* auto detection enable */
+#define RXON_FLG_AUTO_DETECT_MSK __constant_cpu_to_le32(1 << 2)
+/* TGg protection when tx */
+#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3)
+/* cck short slot & preamble */
+#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4)
+#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5)
+/* antenna selection */
+#define RXON_FLG_DIS_DIV_MSK __constant_cpu_to_le32(1 << 7)
+#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00)
+#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
+#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+/* radar detection enable */
+#define RXON_FLG_RADAR_DETECT_MSK __constant_cpu_to_le32(1 << 12)
+#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13)
+/* rx response to host with 8-byte TSF
+* (according to ON_AIR deassertion) */
+#define RXON_FLG_TSF2HOST_MSK __constant_cpu_to_le32(1 << 15)
+
+/* rx_config filter flags */
+/* accept all data frames */
+#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0)
+/* pass control & management to host */
+#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1)
+/* accept multi-cast */
+#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2)
+/* don't decrypt uni-cast frames */
+#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3)
+/* don't decrypt multi-cast frames */
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4)
+/* STA is associated */
+#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5)
+/* transfer to host non bssid beacons in associated state */
+#define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6)
+
+/*
+ * REPLY_RXON = 0x10 (command, has simple generic response)
+ */
+struct iwl_rxon_cmd {
+ u8 node_addr[6];
+ __le16 reserved1;
+ u8 bssid_addr[6];
+ __le16 reserved2;
+ u8 wlap_bssid_addr[6];
+ __le16 reserved3;
+ u8 dev_type;
+ u8 air_propagation;
+#if IWL == 3945
+ __le16 reserved4;
+#elif IWL == 4965
+ __le16 rx_chain;
+#endif
+ u8 ofdm_basic_rates;
+ u8 cck_basic_rates;
+ __le16 assoc_id;
+ __le32 flags;
+ __le32 filter_flags;
+ __le16 channel;
+#if IWL == 3945
+ __le16 reserved5;
+#elif IWL == 4965
+ u8 ofdm_ht_single_stream_basic_rates;
+ u8 ofdm_ht_dual_stream_basic_rates;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
+ */
+struct iwl_rxon_assoc_cmd {
+ __le32 flags;
+ __le32 filter_flags;
+ u8 ofdm_basic_rates;
+ u8 cck_basic_rates;
+#if IWL == 4965
+ u8 ofdm_ht_single_stream_basic_rates;
+ u8 ofdm_ht_dual_stream_basic_rates;
+ __le16 rx_chain_select_flags;
+#endif
+ __le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
+ */
+struct iwl_rxon_time_cmd {
+ union tsf timestamp;
+ __le16 beacon_interval;
+ __le16 atim_window;
+ __le32 beacon_init_val;
+ __le16 listen_interval;
+ __le16 reserved;
+} __attribute__ ((packed));
+
+struct iwl_tx_power {
+ u8 tx_gain; /* gain for analog radio */
+ u8 dsp_atten; /* gain for DSP */
+} __attribute__ ((packed));
+
+#if IWL == 3945
+struct iwl_power_per_rate {
+ u8 rate; /* plcp */
+ struct iwl_tx_power tpc;
+ u8 reserved;
+} __attribute__ ((packed));
+
+#elif IWL == 4965
+#define POWER_TABLE_NUM_ENTRIES 33
+#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32
+#define POWER_TABLE_CCK_ENTRY 32
+struct tx_power_dual_stream {
+ __le32 dw;
+} __attribute__ ((packed));
+
+struct iwl_tx_power_db {
+ struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
+} __attribute__ ((packed));
+#endif
+
+/*
+ * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
+ */
+struct iwl_channel_switch_cmd {
+ u8 band;
+ u8 expect_beacon;
+ __le16 channel;
+ __le32 rxon_flags;
+ __le32 rxon_filter_flags;
+ __le32 switch_time;
+#if IWL == 3945
+ struct iwl_power_per_rate power[IWL_MAX_RATES];
+#elif IWL == 4965
+ struct iwl_tx_power_db tx_power;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
+ */
+struct iwl_csa_notification {
+ __le16 band;
+ __le16 channel;
+ __le32 status; /* 0 - OK, 1 - fail */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (2)
+ * Quality-of-Service (QOS) Commands & Responses:
+ *
+ *****************************************************************************/
+struct iwl_ac_qos {
+ __le16 cw_min;
+ __le16 cw_max;
+ u8 aifsn;
+ u8 reserved1;
+ __le16 edca_txop;
+} __attribute__ ((packed));
+
+/* QoS flags defines */
+#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01)
+#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02)
+#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10)
+
+/*
+ * TXFIFO Queue number defines
+ */
+/* number of Access categories (AC) (EDCA), queues 0..3 */
+#define AC_NUM 4
+
+/*
+ * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
+ */
+struct iwl_qosparam_cmd {
+ __le32 qos_flags;
+ struct iwl_ac_qos ac[AC_NUM];
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (3)
+ * Add/Modify Stations Commands & Responses:
+ *
+ *****************************************************************************/
+/*
+ * Multi station support
+ */
+#define IWL_AP_ID 0
+#define IWL_MULTICAST_ID 1
+#define IWL_STA_ID 2
+
+#define IWL3945_BROADCAST_ID 24
+#define IWL3945_STATION_COUNT 25
+
+#define IWL4965_BROADCAST_ID 31
+#define IWL4965_STATION_COUNT 32
+
+#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/
+#define IWL_INVALID_STATION 255
+
+#if IWL == 3945
+#define STA_FLG_TX_RATE_MSK __constant_cpu_to_le32(1<<2);
+#endif
+#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1<<8);
+
+#define STA_CONTROL_MODIFY_MSK 0x01
+
+/* key flags __le16*/
+#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x7)
+#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0)
+#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x1)
+#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x2)
+#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x3)
+
+#define STA_KEY_FLG_KEYID_POS 8
+#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800)
+
+/* modify flags */
+#define STA_MODIFY_KEY_MASK 0x01
+#define STA_MODIFY_TID_DISABLE_TX 0x02
+#define STA_MODIFY_TX_RATE_MSK 0x04
+#define STA_MODIFY_ADDBA_TID_MSK 0x08
+#define STA_MODIFY_DELBA_TID_MSK 0x10
+#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid))
+
+/*
+ * Antenna masks:
+ * bit14:15 01 B inactive, A active
+ * 10 B active, A inactive
+ * 11 Both active
+ */
+#define RATE_MCS_ANT_A_POS 14
+#define RATE_MCS_ANT_B_POS 15
+#define RATE_MCS_ANT_A_MSK 0x4000
+#define RATE_MCS_ANT_B_MSK 0x8000
+#define RATE_MCS_ANT_AB_MSK 0xc000
+
+struct iwl_keyinfo {
+ __le16 key_flags;
+ u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */
+ u8 reserved1;
+ __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */
+ __le16 reserved2;
+ u8 key[16]; /* 16-byte unicast decryption key */
+} __attribute__ ((packed));
+
+struct sta_id_modify {
+ u8 addr[ETH_ALEN];
+ __le16 reserved1;
+ u8 sta_id;
+ u8 modify_mask;
+ __le16 reserved2;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_ADD_STA = 0x18 (command)
+ */
+struct iwl_addsta_cmd {
+ u8 mode;
+ u8 reserved[3];
+ struct sta_id_modify sta;
+ struct iwl_keyinfo key;
+ __le32 station_flags;
+ __le32 station_flags_msk;
+ __le16 tid_disable_tx;
+#if IWL == 3945
+ __le16 rate_n_flags;
+#else
+ __le16 reserved1;
+#endif
+ u8 add_immediate_ba_tid;
+ u8 remove_immediate_ba_tid;
+ __le16 add_immediate_ba_ssn;
+#if IWL == 4965
+ __le32 reserved2;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * REPLY_ADD_STA = 0x18 (response)
+ */
+struct iwl_add_sta_resp {
+ u8 status;
+} __attribute__ ((packed));
+
+#define ADD_STA_SUCCESS_MSK 0x1
+
+/******************************************************************************
+ * (4)
+ * Rx Responses:
+ *
+ *****************************************************************************/
+
+struct iwl_rx_frame_stats {
+ u8 phy_count;
+ u8 id;
+ u8 rssi;
+ u8 agc;
+ __le16 sig_avg;
+ __le16 noise_diff;
+ u8 payload[0];
+} __attribute__ ((packed));
+
+struct iwl_rx_frame_hdr {
+ __le16 channel;
+ __le16 phy_flags;
+ u8 reserved1;
+ u8 rate;
+ __le16 len;
+ u8 payload[0];
+} __attribute__ ((packed));
+
+#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0)
+#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1)
+
+#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0)
+#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1)
+#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2)
+#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3)
+#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0)
+
+#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8)
+#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8)
+#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8)
+#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8)
+#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8)
+
+#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11)
+#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11)
+#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11)
+#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11)
+#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11)
+
+struct iwl_rx_frame_end {
+ __le32 status;
+ __le64 timestamp;
+ __le32 beacon_timestamp;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_3945_RX = 0x1b (response only, not a command)
+ *
+ * NOTE: DO NOT dereference from casts to this structure
+ * It is provided only for calculating minimum data set size.
+ * The actual offsets of the hdr and end are dynamic based on
+ * stats.phy_count
+ */
+struct iwl_rx_frame {
+ struct iwl_rx_frame_stats stats;
+ struct iwl_rx_frame_hdr hdr;
+ struct iwl_rx_frame_end end;
+} __attribute__ ((packed));
+
+/* Fixed (non-configurable) rx data from phy */
+#define RX_PHY_FLAGS_ANTENNAE_OFFSET (4)
+#define RX_PHY_FLAGS_ANTENNAE_MASK (0x70)
+#define IWL_AGC_DB_MASK (0x3f80) /* MASK(7,13) */
+#define IWL_AGC_DB_POS (7)
+struct iwl4965_rx_non_cfg_phy {
+ __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */
+ __le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */
+ u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */
+ u8 pad[0];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_4965_RX = 0xc3 (response only, not a command)
+ * Used only for legacy (non 11n) frames.
+ */
+#define RX_RES_PHY_CNT 14
+struct iwl4965_rx_phy_res {
+ u8 non_cfg_phy_cnt; /* non configurable DSP phy data byte count */
+ u8 cfg_phy_cnt; /* configurable DSP phy data byte count */
+ u8 stat_id; /* configurable DSP phy data set ID */
+ u8 reserved1;
+ __le64 timestamp; /* TSF at on air rise */
+ __le32 beacon_time_stamp; /* beacon at on-air rise */
+ __le16 phy_flags; /* general phy flags: band, modulation, ... */
+ __le16 channel; /* channel number */
+ __le16 non_cfg_phy[RX_RES_PHY_CNT]; /* upto 14 phy entries */
+ __le32 reserved2;
+ __le32 rate_n_flags;
+ __le16 byte_count; /* frame's byte-count */
+ __le16 reserved3;
+} __attribute__ ((packed));
+
+struct iwl4965_rx_mpdu_res_start {
+ __le16 byte_count;
+ __le16 reserved;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (5)
+ * Tx Commands & Responses:
+ *
+ *****************************************************************************/
+
+/* Tx flags */
+#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
+#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
+#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3)
+#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4)
+#define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6)
+#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
+#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
+#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
+#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+
+/* ucode ignores BT priority for this frame */
+#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
+
+/* ucode overrides sequence control */
+#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13)
+
+/* signal that this frame is non-last MPDU */
+#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14)
+
+/* calculate TSF in outgoing frame */
+#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16)
+
+/* activate TX calibration. */
+#define TX_CMD_FLG_CALIB_MSK __constant_cpu_to_le32(1 << 17)
+
+/* signals that 2 bytes pad was inserted
+ after the MAC header */
+#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20)
+
+/* HCCA-AP - disable duration overwriting. */
+#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25)
+
+/*
+ * TX command security control
+ */
+#define TX_CMD_SEC_WEP 0x01
+#define TX_CMD_SEC_CCM 0x02
+#define TX_CMD_SEC_TKIP 0x03
+#define TX_CMD_SEC_MSK 0x03
+#define TX_CMD_SEC_SHIFT 6
+#define TX_CMD_SEC_KEY128 0x08
+
+/*
+ * TX command Frame life time
+ */
+
+struct iwl_dram_scratch {
+ u8 try_cnt;
+ u8 bt_kill_cnt;
+ __le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX = 0x1c (command)
+ */
+struct iwl_tx_cmd {
+ __le16 len;
+ __le16 next_frame_len;
+ __le32 tx_flags;
+#if IWL == 3945
+ u8 rate;
+ u8 sta_id;
+ u8 tid_tspec;
+#elif IWL == 4965
+ struct iwl_dram_scratch scratch;
+ __le32 rate_n_flags;
+ u8 sta_id;
+#endif
+ u8 sec_ctl;
+#if IWL == 4965
+ u8 initial_rate_index;
+ u8 reserved;
+#endif
+ u8 key[16];
+#if IWL == 3945
+ union {
+ u8 byte[8];
+ __le16 word[4];
+ __le32 dw[2];
+ } tkip_mic;
+ __le32 next_frame_info;
+#elif IWL == 4965
+ __le16 next_frame_flags;
+ __le16 reserved2;
+#endif
+ union {
+ __le32 life_time;
+ __le32 attempt;
+ } stop_time;
+#if IWL == 3945
+ u8 supp_rates[2];
+#elif IWL == 4965
+ __le32 dram_lsb_ptr;
+ u8 dram_msb_ptr;
+#endif
+ u8 rts_retry_limit; /*byte 50 */
+ u8 data_retry_limit; /*byte 51 */
+#if IWL == 4965
+ u8 tid_tspec;
+#endif
+ union {
+ __le16 pm_frame_timeout;
+ __le16 attempt_duration;
+ } timeout;
+ __le16 driver_txop;
+ u8 payload[0];
+ struct ieee80211_hdr hdr[0];
+} __attribute__ ((packed));
+
+/* TX command response is sent after *all* transmission attempts.
+ *
+ * NOTES:
+ *
+ * TX_STATUS_FAIL_NEXT_FRAG
+ *
+ * If the fragment flag in the MAC header for the frame being transmitted
+ * is set and there is insufficient time to transmit the next frame, the
+ * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'.
+ *
+ * TX_STATUS_FIFO_UNDERRUN
+ *
+ * Indicates the host did not provide bytes to the FIFO fast enough while
+ * a TX was in progress.
+ *
+ * TX_STATUS_FAIL_MGMNT_ABORT
+ *
+ * This status is only possible if the ABORT ON MGMT RX parameter was
+ * set to true with the TX command.
+ *
+ * If the MSB of the status parameter is set then an abort sequence is
+ * required. This sequence consists of the host activating the TX Abort
+ * control line, and then waiting for the TX Abort command response. This
+ * indicates that a the device is no longer in a transmit state, and that the
+ * command FIFO has been cleared. The host must then deactivate the TX Abort
+ * control line. Receiving is still allowed in this case.
+ */
+enum {
+ TX_STATUS_SUCCESS = 0x01,
+ TX_STATUS_DIRECT_DONE = 0x02,
+ TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
+ TX_STATUS_FAIL_LONG_LIMIT = 0x83,
+ TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
+ TX_STATUS_FAIL_MGMNT_ABORT = 0x85,
+ TX_STATUS_FAIL_NEXT_FRAG = 0x86,
+ TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
+ TX_STATUS_FAIL_DEST_PS = 0x88,
+ TX_STATUS_FAIL_ABORTED = 0x89,
+ TX_STATUS_FAIL_BT_RETRY = 0x8a,
+ TX_STATUS_FAIL_STA_INVALID = 0x8b,
+ TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
+ TX_STATUS_FAIL_TID_DISABLE = 0x8d,
+ TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
+ TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
+ TX_STATUS_FAIL_TX_LOCKED = 0x90,
+ TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
+};
+
+#define TX_PACKET_MODE_REGULAR 0x0000
+#define TX_PACKET_MODE_BURST_SEQ 0x0100
+#define TX_PACKET_MODE_BURST_FIRST 0x0200
+
+enum {
+ TX_POWER_PA_NOT_ACTIVE = 0x0,
+};
+
+enum {
+ TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */
+ TX_STATUS_DELAY_MSK = 0x00000040,
+ TX_STATUS_ABORT_MSK = 0x00000080,
+ TX_PACKET_MODE_MSK = 0x0000ff00, /* bits 8:15 */
+ TX_FIFO_NUMBER_MSK = 0x00070000, /* bits 16:18 */
+ TX_RESERVED = 0x00780000, /* bits 19:22 */
+ TX_POWER_PA_DETECT_MSK = 0x7f800000, /* bits 23:30 */
+ TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */
+};
+
+/* *******************************
+ * TX aggregation state
+ ******************************* */
+
+enum {
+ AGG_TX_STATE_TRANSMITTED = 0x00,
+ AGG_TX_STATE_UNDERRUN_MSK = 0x01,
+ AGG_TX_STATE_BT_PRIO_MSK = 0x02,
+ AGG_TX_STATE_FEW_BYTES_MSK = 0x04,
+ AGG_TX_STATE_ABORT_MSK = 0x08,
+ AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10,
+ AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20,
+ AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40,
+ AGG_TX_STATE_SCD_QUERY_MSK = 0x80,
+ AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100,
+ AGG_TX_STATE_RESPONSE_MSK = 0x1ff,
+ AGG_TX_STATE_DUMP_TX_MSK = 0x200,
+ AGG_TX_STATE_DELAY_TX_MSK = 0x400
+};
+
+#define AGG_TX_STATE_LAST_SENT_MSK \
+(AGG_TX_STATE_LAST_SENT_TTL_MSK | \
+ AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
+ AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
+
+#define AGG_TX_STATE_TRY_CNT_POS 12
+#define AGG_TX_STATE_TRY_CNT_MSK 0xf000
+
+#define AGG_TX_STATE_SEQ_NUM_POS 16
+#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
+
+/*
+ * REPLY_TX = 0x1c (response)
+ */
+#if IWL == 4965
+struct iwl_tx_resp {
+ u8 frame_count; /* 1 no aggregation, >1 aggregation */
+ u8 bt_kill_count;
+ u8 failure_rts;
+ u8 failure_frame;
+ __le32 rate_n_flags;
+ __le16 wireless_media_time;
+ __le16 reserved;
+ __le32 pa_power1;
+ __le32 pa_power2;
+ __le32 status; /* TX status (for aggregation status of 1st frame) */
+} __attribute__ ((packed));
+
+#elif IWL == 3945
+struct iwl_tx_resp {
+ u8 failure_rts;
+ u8 failure_frame;
+ u8 bt_kill_count;
+ u8 rate;
+ __le32 wireless_media_time;
+ __le32 status; /* TX status (for aggregation status of 1st frame) */
+} __attribute__ ((packed));
+#endif
+
+/*
+ * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
+ */
+struct iwl_compressed_ba_resp {
+ __le32 sta_addr_lo32;
+ __le16 sta_addr_hi16;
+ __le16 reserved;
+ u8 sta_id;
+ u8 tid;
+ __le16 ba_seq_ctl;
+ __le32 ba_bitmap0;
+ __le32 ba_bitmap1;
+ __le16 scd_flow;
+ __le16 scd_ssn;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
+ */
+struct iwl_txpowertable_cmd {
+ u8 band; /* 0: 5 GHz, 1: 2.4 GHz */
+ u8 reserved;
+ __le16 channel;
+#if IWL == 3945
+ struct iwl_power_per_rate power[IWL_MAX_RATES];
+#elif IWL == 4965
+ struct iwl_tx_power_db tx_power;
+#endif
+} __attribute__ ((packed));
+
+#if IWL == 3945
+struct iwl_rate_scaling_info {
+ __le16 rate_n_flags;
+ u8 try_cnt;
+ u8 next_rate_index;
+} __attribute__ ((packed));
+
+/**
+ * struct iwl_rate_scaling_cmd - Rate Scaling Command & Response
+ *
+ * REPLY_RATE_SCALE = 0x47 (command, has simple generic response)
+ *
+ * NOTE: The table of rates passed to the uCode via the
+ * RATE_SCALE command sets up the corresponding order of
+ * rates used for all related commands, including rate
+ * masks, etc.
+ *
+ * For example, if you set 9MB (PLCP 0x0f) as the first
+ * rate in the rate table, the bit mask for that rate
+ * when passed through ofdm_basic_rates on the REPLY_RXON
+ * command would be bit 0 (1<<0)
+ */
+struct iwl_rate_scaling_cmd {
+ u8 table_id;
+ u8 reserved[3];
+ struct iwl_rate_scaling_info table[IWL_MAX_RATES];
+} __attribute__ ((packed));
+
+#elif IWL == 4965
+
+/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
+#define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1<<0)
+
+#define LINK_QUAL_AC_NUM AC_NUM
+#define LINK_QUAL_MAX_RETRY_NUM 16
+
+#define LINK_QUAL_ANT_A_MSK (1<<0)
+#define LINK_QUAL_ANT_B_MSK (1<<1)
+#define LINK_QUAL_ANT_MSK (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
+
+struct iwl_link_qual_general_params {
+ u8 flags;
+ u8 mimo_delimiter;
+ u8 single_stream_ant_msk;
+ u8 dual_stream_ant_msk;
+ u8 start_rate_index[LINK_QUAL_AC_NUM];
+} __attribute__ ((packed));
+
+struct iwl_link_qual_agg_params {
+ __le16 agg_time_limit;
+ u8 agg_dis_start_th;
+ u8 agg_frame_cnt_limit;
+ __le32 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
+ */
+struct iwl_link_quality_cmd {
+ u8 sta_id;
+ u8 reserved1;
+ __le16 control;
+ struct iwl_link_qual_general_params general_params;
+ struct iwl_link_qual_agg_params agg_params;
+ struct {
+ __le32 rate_n_flags;
+ } rs_table[LINK_QUAL_MAX_RETRY_NUM];
+ __le32 reserved2;
+} __attribute__ ((packed));
+#endif
+
+/*
+ * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
+ */
+struct iwl_bt_cmd {
+ u8 flags;
+ u8 lead_time;
+ u8 max_kill;
+ u8 reserved;
+ __le32 kill_ack_mask;
+ __le32 kill_cts_mask;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (6)
+ * Spectrum Management (802.11h) Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * Spectrum Management
+ */
+#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK | \
+ RXON_FILTER_CTL2HOST_MSK | \
+ RXON_FILTER_ACCEPT_GRP_MSK | \
+ RXON_FILTER_DIS_DECRYPT_MSK | \
+ RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
+ RXON_FILTER_ASSOC_MSK | \
+ RXON_FILTER_BCON_AWARE_MSK)
+
+struct iwl_measure_channel {
+ __le32 duration; /* measurement duration in extended beacon
+ * format */
+ u8 channel; /* channel to measure */
+ u8 type; /* see enum iwl_measure_type */
+ __le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
+ */
+struct iwl_spectrum_cmd {
+ __le16 len; /* number of bytes starting from token */
+ u8 token; /* token id */
+ u8 id; /* measurement id -- 0 or 1 */
+ u8 origin; /* 0 = TGh, 1 = other, 2 = TGk */
+ u8 periodic; /* 1 = periodic */
+ __le16 path_loss_timeout;
+ __le32 start_time; /* start time in extended beacon format */
+ __le32 reserved2;
+ __le32 flags; /* rxon flags */
+ __le32 filter_flags; /* rxon filter flags */
+ __le16 channel_count; /* minimum 1, maximum 10 */
+ __le16 reserved3;
+ struct iwl_measure_channel channels[10];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
+ */
+struct iwl_spectrum_resp {
+ u8 token;
+ u8 id; /* id of the prior command replaced, or 0xff */
+ __le16 status; /* 0 - command will be handled
+ * 1 - cannot handle (conflicts with another
+ * measurement) */
+} __attribute__ ((packed));
+
+enum iwl_measurement_state {
+ IWL_MEASUREMENT_START = 0,
+ IWL_MEASUREMENT_STOP = 1,
+};
+
+enum iwl_measurement_status {
+ IWL_MEASUREMENT_OK = 0,
+ IWL_MEASUREMENT_CONCURRENT = 1,
+ IWL_MEASUREMENT_CSA_CONFLICT = 2,
+ IWL_MEASUREMENT_TGH_CONFLICT = 3,
+ /* 4-5 reserved */
+ IWL_MEASUREMENT_STOPPED = 6,
+ IWL_MEASUREMENT_TIMEOUT = 7,
+ IWL_MEASUREMENT_PERIODIC_FAILED = 8,
+};
+
+#define NUM_ELEMENTS_IN_HISTOGRAM 8
+
+struct iwl_measurement_histogram {
+ __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */
+ __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */
+} __attribute__ ((packed));
+
+/* clear channel availability counters */
+struct iwl_measurement_cca_counters {
+ __le32 ofdm;
+ __le32 cck;
+} __attribute__ ((packed));
+
+enum iwl_measure_type {
+ IWL_MEASURE_BASIC = (1 << 0),
+ IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
+ IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
+ IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
+ IWL_MEASURE_FRAME = (1 << 4),
+ /* bits 5:6 are reserved */
+ IWL_MEASURE_IDLE = (1 << 7),
+};
+
+/*
+ * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
+ */
+struct iwl_spectrum_notification {
+ u8 id; /* measurement id -- 0 or 1 */
+ u8 token;
+ u8 channel_index; /* index in measurement channel list */
+ u8 state; /* 0 - start, 1 - stop */
+ __le32 start_time; /* lower 32-bits of TSF */
+ u8 band; /* 0 - 5.2GHz, 1 - 2.4GHz */
+ u8 channel;
+ u8 type; /* see enum iwl_measurement_type */
+ u8 reserved1;
+ /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only
+ * valid if applicable for measurement type requested. */
+ __le32 cca_ofdm; /* cca fraction time in 40Mhz clock periods */
+ __le32 cca_cck; /* cca fraction time in 44Mhz clock periods */
+ __le32 cca_time; /* channel load time in usecs */
+ u8 basic_type; /* 0 - bss, 1 - ofdm preamble, 2 -
+ * unidentified */
+ u8 reserved2[3];
+ struct iwl_measurement_histogram histogram;
+ __le32 stop_time; /* lower 32-bits of TSF */
+ __le32 status; /* see iwl_measurement_status */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (7)
+ * Power Management Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl_powertable_cmd - Power Table Command
+ * @flags: See below:
+ *
+ * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
+ *
+ * PM allow:
+ * bit 0 - '0' Driver not allow power management
+ * '1' Driver allow PM (use rest of parameters)
+ * uCode send sleep notifications:
+ * bit 1 - '0' Don't send sleep notification
+ * '1' send sleep notification (SEND_PM_NOTIFICATION)
+ * Sleep over DTIM
+ * bit 2 - '0' PM have to walk up every DTIM
+ * '1' PM could sleep over DTIM till listen Interval.
+ * PCI power managed
+ * bit 3 - '0' (PCI_LINK_CTRL & 0x1)
+ * '1' !(PCI_LINK_CTRL & 0x1)
+ * Force sleep Modes
+ * bit 31/30- '00' use both mac/xtal sleeps
+ * '01' force Mac sleep
+ * '10' force xtal sleep
+ * '11' Illegal set
+ *
+ * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
+ * ucode assume sleep over DTIM is allowed and we don't need to wakeup
+ * for every DTIM.
+ */
+#define IWL_POWER_VEC_SIZE 5
+
+
+#if IWL == 3945
+
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le32(1<<0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le32(1<<2)
+#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le32(1<<3)
+struct iwl_powertable_cmd {
+ __le32 flags;
+ __le32 rx_data_timeout;
+ __le32 tx_data_timeout;
+ __le32 sleep_interval[IWL_POWER_VEC_SIZE];
+} __attribute__((packed));
+
+#elif IWL == 4965
+
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1<<0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1<<2)
+#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1<<3)
+
+struct iwl_powertable_cmd {
+ __le16 flags;
+ u8 keep_alive_seconds;
+ u8 debug_flags;
+ __le32 rx_data_timeout;
+ __le32 tx_data_timeout;
+ __le32 sleep_interval[IWL_POWER_VEC_SIZE];
+ __le32 keep_alive_beacons;
+} __attribute__ ((packed));
+#endif
+
+/*
+ * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
+ * 3945 and 4965 identical.
+ */
+struct iwl_sleep_notification {
+ u8 pm_sleep_mode;
+ u8 pm_wakeup_src;
+ __le16 reserved;
+ __le32 sleep_time;
+ __le32 tsf_low;
+ __le32 bcon_timer;
+} __attribute__ ((packed));
+
+/* Sleep states. 3945 and 4965 identical. */
+enum {
+ IWL_PM_NO_SLEEP = 0,
+ IWL_PM_SLP_MAC = 1,
+ IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
+ IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
+ IWL_PM_SLP_PHY = 4,
+ IWL_PM_SLP_REPENT = 5,
+ IWL_PM_WAKEUP_BY_TIMER = 6,
+ IWL_PM_WAKEUP_BY_DRIVER = 7,
+ IWL_PM_WAKEUP_BY_RFKILL = 8,
+ /* 3 reserved */
+ IWL_PM_NUM_OF_MODES = 12,
+};
+
+/*
+ * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response)
+ */
+#define CARD_STATE_CMD_DISABLE 0x00 /* Put card to sleep */
+#define CARD_STATE_CMD_ENABLE 0x01 /* Wake up card */
+#define CARD_STATE_CMD_HALT 0x02 /* Power down permanently */
+struct iwl_card_state_cmd {
+ __le32 status; /* CARD_STATE_CMD_* request new power state */
+} __attribute__ ((packed));
+
+/*
+ * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
+ */
+struct iwl_card_state_notif {
+ __le32 flags;
+} __attribute__ ((packed));
+
+#define HW_CARD_DISABLED 0x01
+#define SW_CARD_DISABLED 0x02
+#define RF_CARD_DISABLED 0x04
+#define RXON_CARD_DISABLED 0x10
+
+struct iwl_ct_kill_config {
+ __le32 reserved;
+ __le32 critical_temperature_M;
+ __le32 critical_temperature_R;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (8)
+ * Scan Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+struct iwl_scan_channel {
+ /* type is defined as:
+ * 0:0 active (0 - passive)
+ * 1:4 SSID direct
+ * If 1 is set then corresponding SSID IE is transmitted in probe
+ * 5:7 reserved
+ */
+ u8 type;
+ u8 channel;
+ struct iwl_tx_power tpc;
+ __le16 active_dwell;
+ __le16 passive_dwell;
+} __attribute__ ((packed));
+
+struct iwl_ssid_ie {
+ u8 id;
+ u8 len;
+ u8 ssid[32];
+} __attribute__ ((packed));
+
+#define PROBE_OPTION_MAX 0x4
+#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1)
+#define IWL_MAX_SCAN_SIZE 1024
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (command)
+ */
+struct iwl_scan_cmd {
+ __le16 len;
+ u8 reserved0;
+ u8 channel_count;
+ __le16 quiet_time; /* dwell only this long on quiet chnl
+ * (active scan) */
+ __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */
+ __le16 good_CRC_th; /* passive -> active promotion threshold */
+#if IWL == 3945
+ __le16 reserved1;
+#elif IWL == 4965
+ __le16 rx_chain;
+#endif
+ __le32 max_out_time; /* max usec to be out of associated (service)
+ * chnl */
+ __le32 suspend_time; /* pause scan this long when returning to svc
+ * chnl.
+ * 3945 -- 31:24 # beacons, 19:0 additional usec,
+ * 4965 -- 31:22 # beacons, 21:0 additional usec.
+ */
+ __le32 flags;
+ __le32 filter_flags;
+
+ struct iwl_tx_cmd tx_cmd;
+ struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
+
+ u8 data[0];
+ /*
+ * The channels start after the probe request payload and are of type:
+ *
+ * struct iwl_scan_channel channels[0];
+ *
+ * NOTE: Only one band of channels can be scanned per pass. You
+ * can not mix 2.4GHz channels and 5.2GHz channels and must
+ * request a scan multiple times (not concurrently)
+ *
+ */
+} __attribute__ ((packed));
+
+/* Can abort will notify by complete notification with abort status. */
+#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1)
+/* complete notification statuses */
+#define ABORT_STATUS 0x2
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (response)
+ */
+struct iwl_scanreq_notification {
+ __le32 status; /* 1: okay, 2: cannot fulfill request */
+} __attribute__ ((packed));
+
+/*
+ * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
+ */
+struct iwl_scanstart_notification {
+ __le32 tsf_low;
+ __le32 tsf_high;
+ __le32 beacon_timer;
+ u8 channel;
+ u8 band;
+ u8 reserved[2];
+ __le32 status;
+} __attribute__ ((packed));
+
+#define SCAN_OWNER_STATUS 0x1;
+#define MEASURE_OWNER_STATUS 0x2;
+
+#define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */
+/*
+ * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
+ */
+struct iwl_scanresults_notification {
+ u8 channel;
+ u8 band;
+ u8 reserved[2];
+ __le32 tsf_low;
+ __le32 tsf_high;
+ __le32 statistics[NUMBER_OF_STATISTICS];
+} __attribute__ ((packed));
+
+/*
+ * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
+ */
+struct iwl_scancomplete_notification {
+ u8 scanned_channels;
+ u8 status;
+ u8 reserved;
+ u8 last_channel;
+ __le32 tsf_low;
+ __le32 tsf_high;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (9)
+ * IBSS/AP Commands and Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
+ */
+struct iwl_beacon_notif {
+ struct iwl_tx_resp beacon_notify_hdr;
+ __le32 low_tsf;
+ __le32 high_tsf;
+ __le32 ibss_mgr_status;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
+ */
+struct iwl_tx_beacon_cmd {
+ struct iwl_tx_cmd tx;
+ __le16 tim_idx;
+ u8 tim_size;
+ u8 reserved1;
+ struct ieee80211_hdr frame[0]; /* beacon frame */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (10)
+ * Statistics Commands and Notifications:
+ *
+ *****************************************************************************/
+
+#define IWL_TEMP_CONVERT 260
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
+
+/* Used for passing to driver number of successes and failures per rate */
+struct rate_histogram {
+ union {
+ __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+ __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+ __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+ } success;
+ union {
+ __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+ __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+ __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+ } failed;
+} __attribute__ ((packed));
+
+/* statistics command response */
+
+struct statistics_rx_phy {
+ __le32 ina_cnt;
+ __le32 fina_cnt;
+ __le32 plcp_err;
+ __le32 crc32_err;
+ __le32 overrun_err;
+ __le32 early_overrun_err;
+ __le32 crc32_good;
+ __le32 false_alarm_cnt;
+ __le32 fina_sync_err_cnt;
+ __le32 sfd_timeout;
+ __le32 fina_timeout;
+ __le32 unresponded_rts;
+ __le32 rxe_frame_limit_overrun;
+ __le32 sent_ack_cnt;
+ __le32 sent_cts_cnt;
+#if IWL == 4965
+ __le32 sent_ba_rsp_cnt;
+ __le32 dsp_self_kill;
+ __le32 mh_format_err;
+ __le32 re_acq_main_rssi_sum;
+ __le32 reserved3;
+#endif
+} __attribute__ ((packed));
+
+#if IWL == 4965
+struct statistics_rx_ht_phy {
+ __le32 plcp_err;
+ __le32 overrun_err;
+ __le32 early_overrun_err;
+ __le32 crc32_good;
+ __le32 crc32_err;
+ __le32 mh_format_err;
+ __le32 agg_crc32_good;
+ __le32 agg_mpdu_cnt;
+ __le32 agg_cnt;
+ __le32 reserved2;
+} __attribute__ ((packed));
+#endif
+
+struct statistics_rx_non_phy {
+ __le32 bogus_cts; /* CTS received when not expecting CTS */
+ __le32 bogus_ack; /* ACK received when not expecting ACK */
+ __le32 non_bssid_frames; /* number of frames with BSSID that
+ * doesn't belong to the STA BSSID */
+ __le32 filtered_frames; /* count frames that were dumped in the
+ * filtering process */
+ __le32 non_channel_beacons; /* beacons with our bss id but not on
+ * our serving channel */
+#if IWL == 4965
+ __le32 channel_beacons; /* beacons with our bss id and in our
+ * serving channel */
+ __le32 num_missed_bcon; /* number of missed beacons */
+ __le32 adc_rx_saturation_time; /* count in 0.8us units the time the
+ * ADC was in saturation */
+ __le32 ina_detection_search_time;/* total time (in 0.8us) searched
+ * for INA */
+ __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */
+ __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */
+ __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */
+ __le32 interference_data_flag; /* flag for interference data
+ * availability. 1 when data is
+ * available. */
+ __le32 channel_load; /* counts RX Enable time */
+ __le32 dsp_false_alarms; /* DSP false alarm (both OFDM
+ * and CCK) counter */
+ __le32 beacon_rssi_a;
+ __le32 beacon_rssi_b;
+ __le32 beacon_rssi_c;
+ __le32 beacon_energy_a;
+ __le32 beacon_energy_b;
+ __le32 beacon_energy_c;
+#endif
+} __attribute__ ((packed));
+
+struct statistics_rx {
+ struct statistics_rx_phy ofdm;
+ struct statistics_rx_phy cck;
+ struct statistics_rx_non_phy general;
+#if IWL == 4965
+ struct statistics_rx_ht_phy ofdm_ht;
+#endif
+} __attribute__ ((packed));
+
+#if IWL == 4965
+struct statistics_tx_non_phy_agg {
+ __le32 ba_timeout;
+ __le32 ba_reschedule_frames;
+ __le32 scd_query_agg_frame_cnt;
+ __le32 scd_query_no_agg;
+ __le32 scd_query_agg;
+ __le32 scd_query_mismatch;
+ __le32 frame_not_ready;
+ __le32 underrun;
+ __le32 bt_prio_kill;
+ __le32 rx_ba_rsp_cnt;
+ __le32 reserved2;
+ __le32 reserved3;
+} __attribute__ ((packed));
+#endif
+
+struct statistics_tx {
+ __le32 preamble_cnt;
+ __le32 rx_detected_cnt;
+ __le32 bt_prio_defer_cnt;
+ __le32 bt_prio_kill_cnt;
+ __le32 few_bytes_cnt;
+ __le32 cts_timeout;
+ __le32 ack_timeout;
+ __le32 expected_ack_cnt;
+ __le32 actual_ack_cnt;
+#if IWL == 4965
+ __le32 dump_msdu_cnt;
+ __le32 burst_abort_next_frame_mismatch_cnt;
+ __le32 burst_abort_missing_next_frame_cnt;
+ __le32 cts_timeout_collision;
+ __le32 ack_or_ba_timeout_collision;
+ struct statistics_tx_non_phy_agg agg;
+#endif
+} __attribute__ ((packed));
+
+struct statistics_dbg {
+ __le32 burst_check;
+ __le32 burst_count;
+ __le32 reserved[4];
+} __attribute__ ((packed));
+
+struct statistics_div {
+ __le32 tx_on_a;
+ __le32 tx_on_b;
+ __le32 exec_time;
+ __le32 probe_time;
+#if IWL == 4965
+ __le32 reserved1;
+ __le32 reserved2;
+#endif
+} __attribute__ ((packed));
+
+struct statistics_general {
+ __le32 temperature;
+#if IWL == 4965
+ __le32 temperature_m;
+#endif
+ struct statistics_dbg dbg;
+ __le32 sleep_time;
+ __le32 slots_out;
+ __le32 slots_idle;
+ __le32 ttl_timestamp;
+ struct statistics_div div;
+#if IWL == 4965
+ __le32 rx_enable_counter;
+ __le32 reserved1;
+ __le32 reserved2;
+ __le32 reserved3;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * REPLY_STATISTICS_CMD = 0x9c,
+ * 3945 and 4965 identical.
+ *
+ * This command triggers an immediate response containing uCode statistics.
+ * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
+ *
+ * If the CLEAR_STATS configuration flag is set, uCode will clear its
+ * internal copy of the statistics (counters) after issuing the response.
+ * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below).
+ *
+ * If the DISABLE_NOTIF configuration flag is set, uCode will not issue
+ * STATISTICS_NOTIFICATIONs after received beacons (see below). This flag
+ * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
+ */
+#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */
+#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
+struct iwl_statistics_cmd {
+ __le32 configuration_flags; /* IWL_STATS_CONF_* */
+} __attribute__ ((packed));
+
+/*
+ * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
+ *
+ * By default, uCode issues this notification after receiving a beacon
+ * while associated. To disable this behavior, set DISABLE_NOTIF flag in the
+ * REPLY_STATISTICS_CMD 0x9c, above.
+ *
+ * Statistics counters continue to increment beacon after beacon, but are
+ * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
+ * 0x9c with CLEAR_STATS bit set (see above).
+ *
+ * uCode also issues this notification during scans. uCode clears statistics
+ * appropriately so that each notification contains statistics for only the
+ * one channel that has just been scanned.
+ */
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8)
+struct iwl_notif_statistics {
+ __le32 flag;
+ struct statistics_rx rx;
+ struct statistics_tx tx;
+ struct statistics_general general;
+} __attribute__ ((packed));
+
+
+/*
+ * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
+ */
+/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row,
+ * then this notification will be sent. */
+#define CONSECUTIVE_MISSED_BCONS_TH 20
+
+struct iwl_missed_beacon_notif {
+ __le32 consequtive_missed_beacons;
+ __le32 total_missed_becons;
+ __le32 num_expected_beacons;
+ __le32 num_recvd_beacons;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (11)
+ * Rx Calibration Commands:
+ *
+ *****************************************************************************/
+
+#define PHY_CALIBRATE_DIFF_GAIN_CMD (7)
+#define HD_TABLE_SIZE (11)
+
+struct iwl_sensitivity_cmd {
+ __le16 control;
+ __le16 table[HD_TABLE_SIZE];
+} __attribute__ ((packed));
+
+struct iwl_calibration_cmd {
+ u8 opCode;
+ u8 flags;
+ __le16 reserved;
+ s8 diff_gain_a;
+ s8 diff_gain_b;
+ s8 diff_gain_c;
+ u8 reserved1;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (12)
+ * Miscellaneous Commands:
+ *
+ *****************************************************************************/
+
+/*
+ * LEDs Command & Response
+ * REPLY_LEDS_CMD = 0x48 (command, has simple generic response)
+ *
+ * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
+ * this command turns it on or off, or sets up a periodic blinking cycle.
+ */
+struct iwl_led_cmd {
+ __le32 interval; /* "interval" in uSec */
+ u8 id; /* 1: Activity, 2: Link, 3: Tech */
+ u8 off; /* # intervals off while blinking;
+ * "0", with >0 "on" value, turns LED on */
+ u8 on; /* # intervals on while blinking;
+ * "0", regardless of "off", turns LED off */
+ u8 reserved;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (13)
+ * Union of all expected notifications/responses:
+ *
+ *****************************************************************************/
+
+struct iwl_rx_packet {
+ __le32 len;
+ struct iwl_cmd_header hdr;
+ union {
+ struct iwl_alive_resp alive_frame;
+ struct iwl_rx_frame rx_frame;
+ struct iwl_tx_resp tx_resp;
+ struct iwl_spectrum_notification spectrum_notif;
+ struct iwl_csa_notification csa_notif;
+ struct iwl_error_resp err_resp;
+ struct iwl_card_state_notif card_state_notif;
+ struct iwl_beacon_notif beacon_status;
+ struct iwl_add_sta_resp add_sta;
+ struct iwl_sleep_notification sleep_notif;
+ struct iwl_spectrum_resp spectrum;
+ struct iwl_notif_statistics stats;
+#if IWL == 4965
+ struct iwl_compressed_ba_resp compressed_ba;
+ struct iwl_missed_beacon_notif missed_beacon;
+#endif
+ __le32 status;
+ u8 raw[0];
+ } u;
+} __attribute__ ((packed));
+
+#define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl_rx_frame))
+
+#endif /* __iwl_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
new file mode 100644
index 00000000000..72318d78957
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -0,0 +1,152 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_debug_h__
+#define __iwl_debug_h__
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+extern u32 iwl_debug_level;
+#define IWL_DEBUG(level, fmt, args...) \
+do { if (iwl_debug_level & (level)) \
+ printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+
+#define IWL_DEBUG_LIMIT(level, fmt, args...) \
+do { if ((iwl_debug_level & (level)) && net_ratelimit()) \
+ printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+#else
+static inline void IWL_DEBUG(int level, const char *fmt, ...)
+{
+}
+static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
+{
+}
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IWL_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry. xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IWL_xxxx_DEBUG() macro definition for your
+ * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/iwl/debug_level
+ *
+ * you simply need to add your entry to the iwl_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/iwl then you do not have
+ * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IWL_DL_INFO (1<<0)
+#define IWL_DL_MAC80211 (1<<1)
+#define IWL_DL_HOST_COMMAND (1<<2)
+#define IWL_DL_STATE (1<<3)
+
+#define IWL_DL_RADIO (1<<7)
+#define IWL_DL_POWER (1<<8)
+#define IWL_DL_TEMP (1<<9)
+
+#define IWL_DL_NOTIF (1<<10)
+#define IWL_DL_SCAN (1<<11)
+#define IWL_DL_ASSOC (1<<12)
+#define IWL_DL_DROP (1<<13)
+
+#define IWL_DL_TXPOWER (1<<14)
+
+#define IWL_DL_AP (1<<15)
+
+#define IWL_DL_FW (1<<16)
+#define IWL_DL_RF_KILL (1<<17)
+#define IWL_DL_FW_ERRORS (1<<18)
+
+#define IWL_DL_LED (1<<19)
+
+#define IWL_DL_RATE (1<<20)
+
+#define IWL_DL_CALIB (1<<21)
+#define IWL_DL_WEP (1<<22)
+#define IWL_DL_TX (1<<23)
+#define IWL_DL_RX (1<<24)
+#define IWL_DL_ISR (1<<25)
+#define IWL_DL_HT (1<<26)
+#define IWL_DL_IO (1<<27)
+#define IWL_DL_11H (1<<28)
+
+#define IWL_DL_STATS (1<<29)
+#define IWL_DL_TX_REPLY (1<<30)
+#define IWL_DL_QOS (1<<31)
+
+#define IWL_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
+#define IWL_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
+#define IWL_DEBUG_INFO(f, a...) IWL_DEBUG(IWL_DL_INFO, f, ## a)
+
+#define IWL_DEBUG_MAC80211(f, a...) IWL_DEBUG(IWL_DL_MAC80211, f, ## a)
+#define IWL_DEBUG_TEMP(f, a...) IWL_DEBUG(IWL_DL_TEMP, f, ## a)
+#define IWL_DEBUG_SCAN(f, a...) IWL_DEBUG(IWL_DL_SCAN, f, ## a)
+#define IWL_DEBUG_RX(f, a...) IWL_DEBUG(IWL_DL_RX, f, ## a)
+#define IWL_DEBUG_TX(f, a...) IWL_DEBUG(IWL_DL_TX, f, ## a)
+#define IWL_DEBUG_ISR(f, a...) IWL_DEBUG(IWL_DL_ISR, f, ## a)
+#define IWL_DEBUG_LED(f, a...) IWL_DEBUG(IWL_DL_LED, f, ## a)
+#define IWL_DEBUG_WEP(f, a...) IWL_DEBUG(IWL_DL_WEP, f, ## a)
+#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HOST_COMMAND, f, ## a)
+#define IWL_DEBUG_CALIB(f, a...) IWL_DEBUG(IWL_DL_CALIB, f, ## a)
+#define IWL_DEBUG_FW(f, a...) IWL_DEBUG(IWL_DL_FW, f, ## a)
+#define IWL_DEBUG_RF_KILL(f, a...) IWL_DEBUG(IWL_DL_RF_KILL, f, ## a)
+#define IWL_DEBUG_DROP(f, a...) IWL_DEBUG(IWL_DL_DROP, f, ## a)
+#define IWL_DEBUG_DROP_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_DROP, f, ## a)
+#define IWL_DEBUG_AP(f, a...) IWL_DEBUG(IWL_DL_AP, f, ## a)
+#define IWL_DEBUG_TXPOWER(f, a...) IWL_DEBUG(IWL_DL_TXPOWER, f, ## a)
+#define IWL_DEBUG_IO(f, a...) IWL_DEBUG(IWL_DL_IO, f, ## a)
+#define IWL_DEBUG_RATE(f, a...) IWL_DEBUG(IWL_DL_RATE, f, ## a)
+#define IWL_DEBUG_RATE_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_RATE, f, ## a)
+#define IWL_DEBUG_NOTIF(f, a...) IWL_DEBUG(IWL_DL_NOTIF, f, ## a)
+#define IWL_DEBUG_ASSOC(f, a...) IWL_DEBUG(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
+#define IWL_DEBUG_ASSOC_LIMIT(f, a...) \
+ IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
+#define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a)
+#define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a)
+#define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a)
+#define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a)
+#define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a)
+#define IWL_DEBUG_POWER(f, a...) IWL_DEBUG(IWL_DL_POWER, f, ## a)
+#define IWL_DEBUG_11H(f, a...) IWL_DEBUG(IWL_DL_11H, f, ## a)
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
new file mode 100644
index 00000000000..e473c97e3f4
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -0,0 +1,336 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_eeprom_h__
+#define __iwl_eeprom_h__
+
+/*
+ * This file defines EEPROM related constants, enums, and inline functions.
+ *
+ */
+
+#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */
+#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */
+/* EEPROM field values */
+#define ANTENNA_SWITCH_NORMAL 0
+#define ANTENNA_SWITCH_INVERSE 1
+
+enum {
+ EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */
+ EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */
+ /* Bit 2 Reserved */
+ EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */
+ EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */
+ EEPROM_CHANNEL_WIDE = (1 << 5),
+ EEPROM_CHANNEL_NARROW = (1 << 6),
+ EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */
+};
+
+/* EEPROM field lengths */
+#define EEPROM_BOARD_PBA_NUMBER_LENGTH 11
+
+/* EEPROM field lengths */
+#define EEPROM_BOARD_PBA_NUMBER_LENGTH 11
+#define EEPROM_REGULATORY_SKU_ID_LENGTH 4
+#define EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH 14
+#define EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH 13
+#define EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH 12
+#define EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH 11
+#define EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH 6
+
+#if IWL == 3945
+#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \
+ EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH)
+#elif IWL == 4965
+#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH 7
+#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH 11
+#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \
+ EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH + \
+ EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH)
+#endif
+
+#define EEPROM_REGULATORY_NUMBER_OF_BANDS 5
+
+/* SKU Capabilities */
+#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0)
+#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1)
+#define EEPROM_SKU_CAP_OP_MODE_MRC (1 << 7)
+
+/* *regulatory* channel data from eeprom, one for each channel */
+struct iwl_eeprom_channel {
+ u8 flags; /* flags copied from EEPROM */
+ s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
+} __attribute__ ((packed));
+
+/*
+ * Mapping of a Tx power level, at factory calibration temperature,
+ * to a radio/DSP gain table index.
+ * One for each of 5 "sample" power levels in each band.
+ * v_det is measured at the factory, using the 3945's built-in power amplifier
+ * (PA) output voltage detector. This same detector is used during Tx of
+ * long packets in normal operation to provide feedback as to proper output
+ * level.
+ * Data copied from EEPROM.
+ */
+struct iwl_eeprom_txpower_sample {
+ u8 gain_index; /* index into power (gain) setup table ... */
+ s8 power; /* ... for this pwr level for this chnl group */
+ u16 v_det; /* PA output voltage */
+} __attribute__ ((packed));
+
+/*
+ * Mappings of Tx power levels -> nominal radio/DSP gain table indexes.
+ * One for each channel group (a.k.a. "band") (1 for BG, 4 for A).
+ * Tx power setup code interpolates between the 5 "sample" power levels
+ * to determine the nominal setup for a requested power level.
+ * Data copied from EEPROM.
+ * DO NOT ALTER THIS STRUCTURE!!!
+ */
+struct iwl_eeprom_txpower_group {
+ struct iwl_eeprom_txpower_sample samples[5]; /* 5 power levels */
+ s32 a, b, c, d, e; /* coefficients for voltage->power
+ * formula (signed) */
+ s32 Fa, Fb, Fc, Fd, Fe; /* these modify coeffs based on
+ * frequency (signed) */
+ s8 saturation_power; /* highest power possible by h/w in this
+ * band */
+ u8 group_channel; /* "representative" channel # in this band */
+ s16 temperature; /* h/w temperature at factory calib this band
+ * (signed) */
+} __attribute__ ((packed));
+
+/*
+ * Temperature-based Tx-power compensation data, not band-specific.
+ * These coefficients are use to modify a/b/c/d/e coeffs based on
+ * difference between current temperature and factory calib temperature.
+ * Data copied from EEPROM.
+ */
+struct iwl_eeprom_temperature_corr {
+ u32 Ta;
+ u32 Tb;
+ u32 Tc;
+ u32 Td;
+ u32 Te;
+} __attribute__ ((packed));
+
+#if IWL == 4965
+#define EEPROM_TX_POWER_TX_CHAINS (2)
+#define EEPROM_TX_POWER_BANDS (8)
+#define EEPROM_TX_POWER_MEASUREMENTS (3)
+#define EEPROM_TX_POWER_VERSION (2)
+#define EEPROM_TX_POWER_VERSION_NEW (5)
+
+struct iwl_eeprom_calib_measure {
+ u8 temperature;
+ u8 gain_idx;
+ u8 actual_pow;
+ s8 pa_det;
+} __attribute__ ((packed));
+
+struct iwl_eeprom_calib_ch_info {
+ u8 ch_num;
+ struct iwl_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS]
+ [EEPROM_TX_POWER_MEASUREMENTS];
+} __attribute__ ((packed));
+
+struct iwl_eeprom_calib_subband_info {
+ u8 ch_from;
+ u8 ch_to;
+ struct iwl_eeprom_calib_ch_info ch1;
+ struct iwl_eeprom_calib_ch_info ch2;
+} __attribute__ ((packed));
+
+struct iwl_eeprom_calib_info {
+ u8 saturation_power24;
+ u8 saturation_power52;
+ s16 voltage; /* signed */
+ struct iwl_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS];
+} __attribute__ ((packed));
+
+#endif
+
+struct iwl_eeprom {
+ u8 reserved0[16];
+#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */
+ u16 device_id; /* abs.ofs: 16 */
+ u8 reserved1[2];
+#define EEPROM_PMC (2*0x0A) /* 2 bytes */
+ u16 pmc; /* abs.ofs: 20 */
+ u8 reserved2[20];
+#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */
+ u8 mac_address[6]; /* abs.ofs: 42 */
+ u8 reserved3[58];
+#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */
+ u16 board_revision; /* abs.ofs: 106 */
+ u8 reserved4[11];
+#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */
+ u8 board_pba_number[9]; /* abs.ofs: 119 */
+ u8 reserved5[8];
+#define EEPROM_VERSION (2*0x44) /* 2 bytes */
+ u16 version; /* abs.ofs: 136 */
+#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */
+ u8 sku_cap; /* abs.ofs: 138 */
+#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */
+ u8 leds_mode; /* abs.ofs: 139 */
+#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */
+ u16 oem_mode;
+#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */
+ u16 wowlan_mode; /* abs.ofs: 142 */
+#define EEPROM_LEDS_TIME_INTERVAL (2*0x48) /* 2 bytes */
+ u16 leds_time_interval; /* abs.ofs: 144 */
+#define EEPROM_LEDS_OFF_TIME (2*0x49) /* 1 bytes */
+ u8 leds_off_time; /* abs.ofs: 146 */
+#define EEPROM_LEDS_ON_TIME (2*0x49+1) /* 1 bytes */
+ u8 leds_on_time; /* abs.ofs: 147 */
+#define EEPROM_ALMGOR_M_VERSION (2*0x4A) /* 1 bytes */
+ u8 almgor_m_version; /* abs.ofs: 148 */
+#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */
+ u8 antenna_switch_type; /* abs.ofs: 149 */
+#if IWL == 3945
+ u8 reserved6[42];
+#else
+ u8 reserved6[8];
+#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */
+ u16 board_revision_4965; /* abs.ofs: 158 */
+ u8 reserved7[13];
+#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */
+ u8 board_pba_number_4965[9]; /* abs.ofs: 173 */
+ u8 reserved8[10];
+#endif
+#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */
+ u8 sku_id[4]; /* abs.ofs: 192 */
+#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */
+ u16 band_1_count; /* abs.ofs: 196 */
+#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */
+ struct iwl_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */
+#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */
+ u16 band_2_count; /* abs.ofs: 226 */
+#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */
+ struct iwl_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */
+#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */
+ u16 band_3_count; /* abs.ofs: 254 */
+#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */
+ struct iwl_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */
+#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */
+ u16 band_4_count; /* abs.ofs: 280 */
+#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */
+ struct iwl_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */
+#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */
+ u16 band_5_count; /* abs.ofs: 304 */
+#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */
+ struct iwl_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */
+
+/* From here on out the EEPROM diverges between the 4965 and the 3945 */
+#if IWL == 3945
+
+ u8 reserved9[194];
+
+#define EEPROM_TXPOWER_CALIB_GROUP0 0x200
+#define EEPROM_TXPOWER_CALIB_GROUP1 0x240
+#define EEPROM_TXPOWER_CALIB_GROUP2 0x280
+#define EEPROM_TXPOWER_CALIB_GROUP3 0x2c0
+#define EEPROM_TXPOWER_CALIB_GROUP4 0x300
+#define IWL_NUM_TX_CALIB_GROUPS 5
+ struct iwl_eeprom_txpower_group groups[IWL_NUM_TX_CALIB_GROUPS];
+/* abs.ofs: 512 */
+#define EEPROM_CALIB_TEMPERATURE_CORRECT 0x340
+ struct iwl_eeprom_temperature_corr corrections; /* abs.ofs: 832 */
+ u8 reserved16[172]; /* fill out to full 1024 byte block */
+
+/* 4965AGN adds fat channel support */
+#elif IWL == 4965
+
+ u8 reserved10[2];
+#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */
+ struct iwl_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */
+ u8 reserved11[2];
+#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */
+ struct iwl_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */
+ u8 reserved12[6];
+#define EEPROM_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */
+ u16 calib_version; /* abs.ofs: 364 */
+ u8 reserved13[2];
+#define EEPROM_SATURATION_POWER_OFFSET (2*0xB8) /* 2 bytes */
+ u16 satruation_power; /* abs.ofs: 368 */
+ u8 reserved14[94];
+#define EEPROM_IWL_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */
+ struct iwl_eeprom_calib_info calib_info; /* abs.ofs: 464 */
+
+ u8 reserved16[140]; /* fill out to full 1024 byte block */
+
+#endif
+
+} __attribute__ ((packed));
+
+#define IWL_EEPROM_IMAGE_SIZE 1024
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
new file mode 100644
index 00000000000..e2a8d95ad9c
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -0,0 +1,255 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_helpers_h__
+#define __iwl_helpers_h__
+
+#include <linux/ctype.h>
+
+/*
+ * The structures defined by the hardware/uCode interface
+ * have bit-wise operations. For each bit-field there is
+ * a data symbol in the structure, the start bit position
+ * and the length of the bit-field.
+ *
+ * iwl_get_bits and iwl_set_bits will return or set the
+ * appropriate bits on a 32-bit value.
+ *
+ * IWL_GET_BITS and IWL_SET_BITS use symbol expansion to
+ * expand out to the appropriate call to iwl_get_bits
+ * and iwl_set_bits without having to reference all of the
+ * numerical constants and defines provided in the hardware
+ * definition
+ */
+
+/**
+ * iwl_get_bits - Extract a hardware bit-field value
+ * @src: source hardware value (__le32)
+ * @pos: bit-position (0-based) of first bit of value
+ * @len: length of bit-field
+ *
+ * iwl_get_bits will return the bit-field in cpu endian ordering.
+ *
+ * NOTE: If used from IWL_GET_BITS then pos and len are compile-constants and
+ * will collapse to minimal code by the compiler.
+ */
+static inline u32 iwl_get_bits(__le32 src, u8 pos, u8 len)
+{
+ u32 tmp = le32_to_cpu(src);
+
+ tmp >>= pos;
+ tmp &= (1UL << len) - 1;
+ return tmp;
+}
+
+/**
+ * iwl_set_bits - Set a hardware bit-field value
+ * @dst: Address of __le32 hardware value
+ * @pos: bit-position (0-based) of first bit of value
+ * @len: length of bit-field
+ * @val: cpu endian value to encode into the bit-field
+ *
+ * iwl_set_bits will encode val into dst, masked to be len bits long at bit
+ * position pos.
+ *
+ * NOTE: If used IWL_SET_BITS pos and len will be compile-constants and
+ * will collapse to minimal code by the compiler.
+ */
+static inline void iwl_set_bits(__le32 *dst, u8 pos, u8 len, int val)
+{
+ u32 tmp = le32_to_cpu(*dst);
+
+ tmp &= ~(((1UL << len) - 1) << pos);
+ tmp |= (val & ((1UL << len) - 1)) << pos;
+ *dst = cpu_to_le32(tmp);
+}
+
+static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val)
+{
+ u16 tmp = le16_to_cpu(*dst);
+
+ tmp &= ~((1UL << (pos + len)) - (1UL << pos));
+ tmp |= (val & ((1UL << len) - 1)) << pos;
+ *dst = cpu_to_le16(tmp);
+}
+
+/*
+ * The bit-field definitions in iwl-xxxx-hw.h are in the form of:
+ *
+ * struct example {
+ * __le32 val1;
+ * #define IWL_name_POS 8
+ * #define IWL_name_LEN 4
+ * #define IWL_name_SYM val1
+ * };
+ *
+ * The IWL_SET_BITS and IWL_GET_BITS macros are provided to allow the driver
+ * to call:
+ *
+ * struct example bar;
+ * u32 val = IWL_GET_BITS(bar, name);
+ * val = val * 2;
+ * IWL_SET_BITS(bar, name, val);
+ *
+ * All cpu / host ordering, masking, and shifts are performed by the macros
+ * and iwl_{get,set}_bits.
+ *
+ */
+#define IWL_SET_BITS(s, sym, v) \
+ iwl_set_bits(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
+ IWL_ ## sym ## _LEN, (v))
+
+#define IWL_SET_BITS16(s, sym, v) \
+ iwl_set_bits16(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
+ IWL_ ## sym ## _LEN, (v))
+
+#define IWL_GET_BITS(s, sym) \
+ iwl_get_bits((s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
+ IWL_ ## sym ## _LEN)
+
+
+#define KELVIN_TO_CELSIUS(x) ((x)-273)
+#define CELSIUS_TO_KELVIN(x) ((x)+273)
+
+#define IEEE80211_CHAN_W_RADAR_DETECT 0x00000010
+
+static inline struct ieee80211_conf *ieee80211_get_hw_conf(
+ struct ieee80211_hw *hw)
+{
+ return &hw->conf;
+}
+
+#define QOS_CONTROL_LEN 2
+
+#define IEEE80211_STYPE_BACK_REQ 0x0080
+#define IEEE80211_STYPE_BACK 0x0090
+
+
+static inline int ieee80211_is_management(u16 fc)
+{
+ return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT;
+}
+
+static inline int ieee80211_is_control(u16 fc)
+{
+ return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL;
+}
+
+static inline int ieee80211_is_data(u16 fc)
+{
+ return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA;
+}
+
+static inline int ieee80211_is_back_request(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ);
+}
+
+static inline int ieee80211_is_probe_response(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP);
+}
+
+static inline int ieee80211_is_probe_request(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_REQ);
+}
+
+static inline int ieee80211_is_beacon(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON);
+}
+
+static inline int ieee80211_is_atim(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ATIM);
+}
+
+static inline int ieee80211_is_assoc_request(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
+
+static inline int ieee80211_is_assoc_response(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_RESP);
+}
+
+static inline int ieee80211_is_auth(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
+
+static inline int ieee80211_is_deauth(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
+
+static inline int ieee80211_is_disassoc(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
+
+static inline int ieee80211_is_reassoc_request(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ);
+}
+
+static inline int ieee80211_is_reassoc_response(u16 fc)
+{
+ return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_RESP);
+}
+
+static inline int iwl_check_bits(unsigned long field, unsigned long mask)
+{
+ return ((field & mask) == mask) ? 1 : 0;
+}
+
+static inline unsigned long elapsed_jiffies(unsigned long start,
+ unsigned long end)
+{
+ if (end > start)
+ return end - start;
+
+ return end + (MAX_JIFFY_OFFSET - start);
+}
+
+#endif /* __iwl_helpers_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-hw.h b/drivers/net/wireless/iwlwifi/iwl-hw.h
new file mode 100644
index 00000000000..1aa6fcd39a5
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-hw.h
@@ -0,0 +1,537 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwlwifi_hw_h__
+#define __iwlwifi_hw_h__
+
+/*
+ * This file defines hardware constants common to 3945 and 4965.
+ *
+ * Device-specific constants are defined in iwl-3945-hw.h and iwl-4965-hw.h,
+ * although this file contains a few definitions for which the .c
+ * implementation is the same for 3945 and 4965, except for the value of
+ * a constant.
+ *
+ * uCode API constants are defined in iwl-commands.h.
+ *
+ * NOTE: DO NOT PUT OS IMPLEMENTATION-SPECIFIC DECLARATIONS HERE
+ *
+ * The iwl-*hw.h (and files they include) files should remain OS/driver
+ * implementation independent, declaring only the hardware interface.
+ */
+
+/* uCode queue management definitions */
+#define IWL_CMD_QUEUE_NUM 4
+#define IWL_CMD_FIFO_NUM 4
+#define IWL_BACK_QUEUE_FIRST_ID 7
+
+/* Tx rates */
+#define IWL_CCK_RATES 4
+#define IWL_OFDM_RATES 8
+
+#if IWL == 3945
+#define IWL_HT_RATES 0
+#elif IWL == 4965
+#define IWL_HT_RATES 16
+#endif
+
+#define IWL_MAX_RATES (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES)
+
+/* Time constants */
+#define SHORT_SLOT_TIME 9
+#define LONG_SLOT_TIME 20
+
+/* RSSI to dBm */
+#if IWL == 3945
+#define IWL_RSSI_OFFSET 95
+#elif IWL == 4965
+#define IWL_RSSI_OFFSET 44
+#endif
+
+#include "iwl-eeprom.h"
+#include "iwl-commands.h"
+
+#define PCI_LINK_CTRL 0x0F0
+#define PCI_POWER_SOURCE 0x0C8
+#define PCI_REG_WUM8 0x0E8
+#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000)
+
+/*=== CSR (control and status registers) ===*/
+#define CSR_BASE (0x000)
+
+#define CSR_SW_VER (CSR_BASE+0x000)
+#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */
+#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */
+#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */
+#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */
+#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/
+#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */
+#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
+#define CSR_GP_CNTRL (CSR_BASE+0x024)
+#define CSR_HW_REV (CSR_BASE+0x028)
+#define CSR_EEPROM_REG (CSR_BASE+0x02c)
+#define CSR_EEPROM_GP (CSR_BASE+0x030)
+#define CSR_GP_UCODE (CSR_BASE+0x044)
+#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054)
+#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058)
+#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
+#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
+#define CSR_LED_REG (CSR_BASE+0x094)
+#define CSR_DRAM_INT_TBL_CTL (CSR_BASE+0x0A0)
+#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
+#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c)
+#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C)
+
+/* HW I/F configuration */
+#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB (0x00000100)
+#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM (0x00000200)
+#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400)
+#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800)
+#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000)
+#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000)
+#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
+
+/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
+ * acknowledged (reset) by host writing "1" to flagged bits. */
+#define CSR_INT_BIT_FH_RX (1<<31) /* Rx DMA, cmd responses, FH_INT[17:16] */
+#define CSR_INT_BIT_HW_ERR (1<<29) /* DMA hardware error FH_INT[31] */
+#define CSR_INT_BIT_DNLD (1<<28) /* uCode Download */
+#define CSR_INT_BIT_FH_TX (1<<27) /* Tx DMA FH_INT[1:0] */
+#define CSR_INT_BIT_MAC_CLK_ACTV (1<<26) /* NIC controller's clock toggled on/off */
+#define CSR_INT_BIT_SW_ERR (1<<25) /* uCode error */
+#define CSR_INT_BIT_RF_KILL (1<<7) /* HW RFKILL switch GP_CNTRL[27] toggled */
+#define CSR_INT_BIT_CT_KILL (1<<6) /* Critical temp (chip too hot) rfkill */
+#define CSR_INT_BIT_SW_RX (1<<3) /* Rx, command responses, 3945 */
+#define CSR_INT_BIT_WAKEUP (1<<1) /* NIC controller waking up (pwr mgmt) */
+#define CSR_INT_BIT_ALIVE (1<<0) /* uCode interrupts once it initializes */
+
+#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \
+ CSR_INT_BIT_HW_ERR | \
+ CSR_INT_BIT_FH_TX | \
+ CSR_INT_BIT_SW_ERR | \
+ CSR_INT_BIT_RF_KILL | \
+ CSR_INT_BIT_SW_RX | \
+ CSR_INT_BIT_WAKEUP | \
+ CSR_INT_BIT_ALIVE)
+
+/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
+#define CSR_FH_INT_BIT_ERR (1<<31) /* Error */
+#define CSR_FH_INT_BIT_HI_PRIOR (1<<30) /* High priority Rx, bypass coalescing */
+#define CSR_FH_INT_BIT_RX_CHNL2 (1<<18) /* Rx channel 2 (3945 only) */
+#define CSR_FH_INT_BIT_RX_CHNL1 (1<<17) /* Rx channel 1 */
+#define CSR_FH_INT_BIT_RX_CHNL0 (1<<16) /* Rx channel 0 */
+#define CSR_FH_INT_BIT_TX_CHNL6 (1<<6) /* Tx channel 6 (3945 only) */
+#define CSR_FH_INT_BIT_TX_CHNL1 (1<<1) /* Tx channel 1 */
+#define CSR_FH_INT_BIT_TX_CHNL0 (1<<0) /* Tx channel 0 */
+
+#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \
+ CSR_FH_INT_BIT_RX_CHNL2 | \
+ CSR_FH_INT_BIT_RX_CHNL1 | \
+ CSR_FH_INT_BIT_RX_CHNL0)
+
+#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL6 | \
+ CSR_FH_INT_BIT_TX_CHNL1 | \
+ CSR_FH_INT_BIT_TX_CHNL0 )
+
+
+/* RESET */
+#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001)
+#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002)
+#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080)
+#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100)
+#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200)
+
+/* GP (general purpose) CONTROL */
+#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001)
+#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008)
+#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010)
+
+#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001)
+
+#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000)
+#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000)
+
+
+/* EEPROM REG */
+#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001)
+#define CSR_EEPROM_REG_BIT_CMD (0x00000002)
+
+/* EEPROM GP */
+#define CSR_EEPROM_GP_VALID_MSK (0x00000006)
+#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000)
+#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180)
+
+/* UCODE DRV GP */
+#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001)
+#define CSR_UCODE_SW_BIT_RFKILL (0x00000002)
+#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004)
+#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008)
+
+/* GPIO */
+#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200)
+#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000)
+#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER
+
+/* GI Chicken Bits */
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000)
+
+/* CSR_ANA_PLL_CFG */
+#define CSR_ANA_PLL_CFG_SH (0x00880300)
+
+#define CSR_LED_REG_TRUN_ON (0x00000078)
+#define CSR_LED_REG_TRUN_OFF (0x00000038)
+#define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF)
+
+/* DRAM_INT_TBL_CTRL */
+#define CSR_DRAM_INT_TBL_CTRL_EN (1<<31)
+#define CSR_DRAM_INT_TBL_CTRL_WRAP_CHK (1<<27)
+
+/*=== HBUS (Host-side Bus) ===*/
+#define HBUS_BASE (0x400)
+
+#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c)
+#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010)
+#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018)
+#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c)
+#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044)
+#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048)
+#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c)
+#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050)
+#define HBUS_TARG_WRPTR (HBUS_BASE+0x060)
+
+#define HBUS_TARG_MBX_C (HBUS_BASE+0x030)
+
+
+/* SCD (Scheduler) */
+#define SCD_BASE (CSR_BASE + 0x2E00)
+
+#define SCD_MODE_REG (SCD_BASE + 0x000)
+#define SCD_ARASTAT_REG (SCD_BASE + 0x004)
+#define SCD_TXFACT_REG (SCD_BASE + 0x010)
+#define SCD_TXF4MF_REG (SCD_BASE + 0x014)
+#define SCD_TXF5MF_REG (SCD_BASE + 0x020)
+#define SCD_SBYP_MODE_1_REG (SCD_BASE + 0x02C)
+#define SCD_SBYP_MODE_2_REG (SCD_BASE + 0x030)
+
+/*=== FH (data Flow Handler) ===*/
+#define FH_BASE (0x800)
+
+#define FH_CBCC_TABLE (FH_BASE+0x140)
+#define FH_TFDB_TABLE (FH_BASE+0x180)
+#define FH_RCSR_TABLE (FH_BASE+0x400)
+#define FH_RSSR_TABLE (FH_BASE+0x4c0)
+#define FH_TCSR_TABLE (FH_BASE+0x500)
+#define FH_TSSR_TABLE (FH_BASE+0x680)
+
+/* TFDB (Transmit Frame Buffer Descriptor) */
+#define FH_TFDB(_channel, buf) \
+ (FH_TFDB_TABLE+((_channel)*2+(buf))*0x28)
+#define ALM_FH_TFDB_CHNL_BUF_CTRL_REG(_channel) \
+ (FH_TFDB_TABLE + 0x50 * _channel)
+/* CBCC _channel is [0,2] */
+#define FH_CBCC(_channel) (FH_CBCC_TABLE+(_channel)*0x8)
+#define FH_CBCC_CTRL(_channel) (FH_CBCC(_channel)+0x00)
+#define FH_CBCC_BASE(_channel) (FH_CBCC(_channel)+0x04)
+
+/* RCSR _channel is [0,2] */
+#define FH_RCSR(_channel) (FH_RCSR_TABLE+(_channel)*0x40)
+#define FH_RCSR_CONFIG(_channel) (FH_RCSR(_channel)+0x00)
+#define FH_RCSR_RBD_BASE(_channel) (FH_RCSR(_channel)+0x04)
+#define FH_RCSR_WPTR(_channel) (FH_RCSR(_channel)+0x20)
+#define FH_RCSR_RPTR_ADDR(_channel) (FH_RCSR(_channel)+0x24)
+
+#if IWL == 3945
+#define FH_RSCSR_CHNL0_WPTR (FH_RCSR_WPTR(0))
+#elif IWL == 4965
+#define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)
+#endif
+
+/* RSSR */
+#define FH_RSSR_CTRL (FH_RSSR_TABLE+0x000)
+#define FH_RSSR_STATUS (FH_RSSR_TABLE+0x004)
+/* TCSR */
+#define FH_TCSR(_channel) (FH_TCSR_TABLE+(_channel)*0x20)
+#define FH_TCSR_CONFIG(_channel) (FH_TCSR(_channel)+0x00)
+#define FH_TCSR_CREDIT(_channel) (FH_TCSR(_channel)+0x04)
+#define FH_TCSR_BUFF_STTS(_channel) (FH_TCSR(_channel)+0x08)
+/* TSSR */
+#define FH_TSSR_CBB_BASE (FH_TSSR_TABLE+0x000)
+#define FH_TSSR_MSG_CONFIG (FH_TSSR_TABLE+0x008)
+#define FH_TSSR_TX_STATUS (FH_TSSR_TABLE+0x010)
+/* 18 - reserved */
+
+/* card static random access memory (SRAM) for processor data and instructs */
+#define RTC_INST_LOWER_BOUND (0x000000)
+#define RTC_DATA_LOWER_BOUND (0x800000)
+
+
+/* DBM */
+
+#define ALM_FH_SRVC_CHNL (6)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE (20)
+#define ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH (4)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN (0x08000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE (0x80000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE (0x20000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 (0x01000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST (0x00001000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH (0x00000000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER (0x00000001)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000)
+
+#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00004000)
+
+#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR (0x00000001)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON (0xFF000000)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON (0x00FF0000)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B (0x00000400)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON (0x00000100)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON (0x00000080)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH (0x00000020)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH (0x00000005)
+
+#define ALM_TB_MAX_BYTES_COUNT (0xFFF0)
+
+#define ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) \
+ ((1LU << _channel) << 24)
+#define ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel) \
+ ((1LU << _channel) << 16)
+
+#define ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_channel) \
+ (ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) | \
+ ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel))
+#define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */
+#define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */
+
+#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004)
+
+#define TFD_QUEUE_MIN 0
+#define TFD_QUEUE_MAX 6
+#define TFD_QUEUE_SIZE_MAX (256)
+
+/* spectrum and channel data structures */
+#define IWL_NUM_SCAN_RATES (2)
+
+#define IWL_SCAN_FLAG_24GHZ (1<<0)
+#define IWL_SCAN_FLAG_52GHZ (1<<1)
+#define IWL_SCAN_FLAG_ACTIVE (1<<2)
+#define IWL_SCAN_FLAG_DIRECT (1<<3)
+
+#define IWL_MAX_CMD_SIZE 1024
+
+#define IWL_DEFAULT_TX_RETRY 15
+#define IWL_MAX_TX_RETRY 16
+
+/*********************************************/
+
+#define RFD_SIZE 4
+#define NUM_TFD_CHUNKS 4
+
+#define RX_QUEUE_SIZE 256
+#define RX_QUEUE_MASK 255
+#define RX_QUEUE_SIZE_LOG 8
+
+/* QoS definitions */
+
+#define CW_MIN_OFDM 15
+#define CW_MAX_OFDM 1023
+#define CW_MIN_CCK 31
+#define CW_MAX_CCK 1023
+
+#define QOS_TX0_CW_MIN_OFDM CW_MIN_OFDM
+#define QOS_TX1_CW_MIN_OFDM CW_MIN_OFDM
+#define QOS_TX2_CW_MIN_OFDM ((CW_MIN_OFDM + 1) / 2 - 1)
+#define QOS_TX3_CW_MIN_OFDM ((CW_MIN_OFDM + 1) / 4 - 1)
+
+#define QOS_TX0_CW_MIN_CCK CW_MIN_CCK
+#define QOS_TX1_CW_MIN_CCK CW_MIN_CCK
+#define QOS_TX2_CW_MIN_CCK ((CW_MIN_CCK + 1) / 2 - 1)
+#define QOS_TX3_CW_MIN_CCK ((CW_MIN_CCK + 1) / 4 - 1)
+
+#define QOS_TX0_CW_MAX_OFDM CW_MAX_OFDM
+#define QOS_TX1_CW_MAX_OFDM CW_MAX_OFDM
+#define QOS_TX2_CW_MAX_OFDM CW_MIN_OFDM
+#define QOS_TX3_CW_MAX_OFDM ((CW_MIN_OFDM + 1) / 2 - 1)
+
+#define QOS_TX0_CW_MAX_CCK CW_MAX_CCK
+#define QOS_TX1_CW_MAX_CCK CW_MAX_CCK
+#define QOS_TX2_CW_MAX_CCK CW_MIN_CCK
+#define QOS_TX3_CW_MAX_CCK ((CW_MIN_CCK + 1) / 2 - 1)
+
+#define QOS_TX0_AIFS 3
+#define QOS_TX1_AIFS 7
+#define QOS_TX2_AIFS 2
+#define QOS_TX3_AIFS 2
+
+#define QOS_TX0_ACM 0
+#define QOS_TX1_ACM 0
+#define QOS_TX2_ACM 0
+#define QOS_TX3_ACM 0
+
+#define QOS_TX0_TXOP_LIMIT_CCK 0
+#define QOS_TX1_TXOP_LIMIT_CCK 0
+#define QOS_TX2_TXOP_LIMIT_CCK 6016
+#define QOS_TX3_TXOP_LIMIT_CCK 3264
+
+#define QOS_TX0_TXOP_LIMIT_OFDM 0
+#define QOS_TX1_TXOP_LIMIT_OFDM 0
+#define QOS_TX2_TXOP_LIMIT_OFDM 3008
+#define QOS_TX3_TXOP_LIMIT_OFDM 1504
+
+#define DEF_TX0_CW_MIN_OFDM CW_MIN_OFDM
+#define DEF_TX1_CW_MIN_OFDM CW_MIN_OFDM
+#define DEF_TX2_CW_MIN_OFDM CW_MIN_OFDM
+#define DEF_TX3_CW_MIN_OFDM CW_MIN_OFDM
+
+#define DEF_TX0_CW_MIN_CCK CW_MIN_CCK
+#define DEF_TX1_CW_MIN_CCK CW_MIN_CCK
+#define DEF_TX2_CW_MIN_CCK CW_MIN_CCK
+#define DEF_TX3_CW_MIN_CCK CW_MIN_CCK
+
+#define DEF_TX0_CW_MAX_OFDM CW_MAX_OFDM
+#define DEF_TX1_CW_MAX_OFDM CW_MAX_OFDM
+#define DEF_TX2_CW_MAX_OFDM CW_MAX_OFDM
+#define DEF_TX3_CW_MAX_OFDM CW_MAX_OFDM
+
+#define DEF_TX0_CW_MAX_CCK CW_MAX_CCK
+#define DEF_TX1_CW_MAX_CCK CW_MAX_CCK
+#define DEF_TX2_CW_MAX_CCK CW_MAX_CCK
+#define DEF_TX3_CW_MAX_CCK CW_MAX_CCK
+
+#define DEF_TX0_AIFS (2)
+#define DEF_TX1_AIFS (2)
+#define DEF_TX2_AIFS (2)
+#define DEF_TX3_AIFS (2)
+
+#define DEF_TX0_ACM 0
+#define DEF_TX1_ACM 0
+#define DEF_TX2_ACM 0
+#define DEF_TX3_ACM 0
+
+#define DEF_TX0_TXOP_LIMIT_CCK 0
+#define DEF_TX1_TXOP_LIMIT_CCK 0
+#define DEF_TX2_TXOP_LIMIT_CCK 0
+#define DEF_TX3_TXOP_LIMIT_CCK 0
+
+#define DEF_TX0_TXOP_LIMIT_OFDM 0
+#define DEF_TX1_TXOP_LIMIT_OFDM 0
+#define DEF_TX2_TXOP_LIMIT_OFDM 0
+#define DEF_TX3_TXOP_LIMIT_OFDM 0
+
+#define QOS_QOS_SETS 3
+#define QOS_PARAM_SET_ACTIVE 0
+#define QOS_PARAM_SET_DEF_CCK 1
+#define QOS_PARAM_SET_DEF_OFDM 2
+
+#define CTRL_QOS_NO_ACK (0x0020)
+#define DCT_FLAG_EXT_QOS_ENABLED (0x10)
+
+#define U32_PAD(n) ((4-(n))&0x3)
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues
+ */
+#define TFD_CTL_COUNT_SET(n) (n<<24)
+#define TFD_CTL_COUNT_GET(ctl) ((ctl>>24) & 7)
+#define TFD_CTL_PAD_SET(n) (n<<28)
+#define TFD_CTL_PAD_GET(ctl) (ctl>>28)
+
+#define TFD_TX_CMD_SLOTS 256
+#define TFD_CMD_SLOTS 32
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
+ sizeof(struct iwl_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+#endif /* __iwlwifi_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
new file mode 100644
index 00000000000..8a8b96fcf48
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -0,0 +1,470 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_io_h__
+#define __iwl_io_h__
+
+#include <linux/io.h>
+
+#include "iwl-debug.h"
+
+/*
+ * IO, register, and NIC memory access functions
+ *
+ * NOTE on naming convention and macro usage for these
+ *
+ * A single _ prefix before a an access function means that no state
+ * check or debug information is printed when that function is called.
+ *
+ * A double __ prefix before an access function means that state is checked
+ * (in the case of *restricted calls) and the current line number is printed
+ * in addition to any other debug output.
+ *
+ * The non-prefixed name is the #define that maps the caller into a
+ * #define that provides the caller's __LINE__ to the double prefix version.
+ *
+ * If you wish to call the function without any debug or state checking,
+ * you should use the single _ prefix version (as is used by dependent IO
+ * routines, for example _iwl_read_restricted calls the non-check version of
+ * _iwl_read32.)
+ *
+ * These declarations are *extremely* useful in quickly isolating code deltas
+ * which result in misconfiguring of the hardware I/O. In combination with
+ * git-bisect and the IO debug level you can quickly determine the specific
+ * commit which breaks the IO sequence to the hardware.
+ *
+ */
+
+#define _iwl_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *iwl,
+ u32 ofs, u32 val)
+{
+ IWL_DEBUG_IO("write_direct32(0x%08X, 0x%08X) - %s %d\n",
+ (u32) (ofs), (u32) (val), f, l);
+ _iwl_write32(iwl, ofs, val);
+}
+#define iwl_write32(iwl, ofs, val) \
+ __iwl_write32(__FILE__, __LINE__, iwl, ofs, val)
+#else
+#define iwl_write32(iwl, ofs, val) _iwl_write32(iwl, ofs, val)
+#endif
+
+#define _iwl_read32(iwl, ofs) readl((iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *iwl, u32 ofs)
+{
+ IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l);
+ return _iwl_read32(iwl, ofs);
+}
+#define iwl_read32(iwl, ofs) __iwl_read32(__FILE__, __LINE__, iwl, ofs)
+#else
+#define iwl_read32(p, o) _iwl_read32(p, o)
+#endif
+
+static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr,
+ u32 bits, u32 mask, int timeout)
+{
+ int i = 0;
+
+ do {
+ if ((_iwl_read32(priv, addr) & mask) == (bits & mask))
+ return i;
+ mdelay(10);
+ i += 10;
+ } while (i < timeout);
+
+ return -ETIMEDOUT;
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline int __iwl_poll_bit(const char *f, u32 l,
+ struct iwl_priv *priv, u32 addr,
+ u32 bits, u32 mask, int timeout)
+{
+ int rc = _iwl_poll_bit(priv, addr, bits, mask, timeout);
+ if (unlikely(rc == -ETIMEDOUT))
+ IWL_DEBUG_IO
+ ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n",
+ addr, bits, mask, f, l);
+ else
+ IWL_DEBUG_IO
+ ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n",
+ addr, bits, mask, rc, f, l);
+ return rc;
+}
+#define iwl_poll_bit(iwl, addr, bits, mask, timeout) \
+ __iwl_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout)
+#else
+#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t)
+#endif
+
+static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ _iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_set_bit(const char *f, u32 l,
+ struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ u32 val = _iwl_read32(priv, reg) | mask;
+ IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+ _iwl_write32(priv, reg, val);
+}
+#define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m)
+#endif
+
+static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ _iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_clear_bit(const char *f, u32 l,
+ struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ u32 val = _iwl_read32(priv, reg) & ~mask;
+ IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+ _iwl_write32(priv, reg, val);
+}
+#define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m)
+#endif
+
+static inline int _iwl_grab_restricted_access(struct iwl_priv *priv)
+{
+ int rc;
+ u32 gp_ctl;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (atomic_read(&priv->restrict_refcnt))
+ return 0;
+#endif
+ if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+ test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+ IWL_WARNING("WARNING: Requesting MAC access during RFKILL "
+ "wakes up NIC\n");
+
+ /* 10 msec allows time for NIC to complete its data save */
+ gp_ctl = _iwl_read32(priv, CSR_GP_CNTRL);
+ if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
+ IWL_DEBUG_RF_KILL("Wait for complete power-down, "
+ "gpctl = 0x%08x\n", gp_ctl);
+ mdelay(10);
+ } else
+ IWL_DEBUG_RF_KILL("power-down complete, "
+ "gpctl = 0x%08x\n", gp_ctl);
+ }
+
+ /* this bit wakes up the NIC */
+ _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ rc = _iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
+ (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
+ CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50);
+ if (rc < 0) {
+ IWL_ERROR("MAC is in deep sleep!\n");
+ return -EIO;
+ }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ atomic_inc(&priv->restrict_refcnt);
+#endif
+ return 0;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline int __iwl_grab_restricted_access(const char *f, u32 l,
+ struct iwl_priv *priv)
+{
+ if (atomic_read(&priv->restrict_refcnt))
+ IWL_DEBUG_INFO("Grabbing access while already held at "
+ "line %d.\n", l);
+
+ IWL_DEBUG_IO("grabbing restricted access - %s %d\n", f, l);
+
+ return _iwl_grab_restricted_access(priv);
+}
+#define iwl_grab_restricted_access(priv) \
+ __iwl_grab_restricted_access(__FILE__, __LINE__, priv)
+#else
+#define iwl_grab_restricted_access(priv) \
+ _iwl_grab_restricted_access(priv)
+#endif
+
+static inline void _iwl_release_restricted_access(struct iwl_priv *priv)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (atomic_dec_and_test(&priv->restrict_refcnt))
+#endif
+ _iwl_clear_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_release_restricted_access(const char *f, u32 l,
+ struct iwl_priv *priv)
+{
+ if (atomic_read(&priv->restrict_refcnt) <= 0)
+ IWL_ERROR("Release unheld restricted access at line %d.\n", l);
+
+ IWL_DEBUG_IO("releasing restricted access - %s %d\n", f, l);
+ _iwl_release_restricted_access(priv);
+}
+#define iwl_release_restricted_access(priv) \
+ __iwl_release_restricted_access(__FILE__, __LINE__, priv)
+#else
+#define iwl_release_restricted_access(priv) \
+ _iwl_release_restricted_access(priv)
+#endif
+
+static inline u32 _iwl_read_restricted(struct iwl_priv *priv, u32 reg)
+{
+ return _iwl_read32(priv, reg);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline u32 __iwl_read_restricted(const char *f, u32 l,
+ struct iwl_priv *priv, u32 reg)
+{
+ u32 value = _iwl_read_restricted(priv, reg);
+ if (!atomic_read(&priv->restrict_refcnt))
+ IWL_ERROR("Unrestricted access from %s %d\n", f, l);
+ IWL_DEBUG_IO("read_restricted(0x%4X) = 0x%08x - %s %d \n", reg, value,
+ f, l);
+ return value;
+}
+#define iwl_read_restricted(priv, reg) \
+ __iwl_read_restricted(__FILE__, __LINE__, priv, reg)
+#else
+#define iwl_read_restricted _iwl_read_restricted
+#endif
+
+static inline void _iwl_write_restricted(struct iwl_priv *priv,
+ u32 reg, u32 value)
+{
+ _iwl_write32(priv, reg, value);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void __iwl_write_restricted(u32 line,
+ struct iwl_priv *priv, u32 reg, u32 value)
+{
+ if (!atomic_read(&priv->restrict_refcnt))
+ IWL_ERROR("Unrestricted access from line %d\n", line);
+ _iwl_write_restricted(priv, reg, value);
+}
+#define iwl_write_restricted(priv, reg, value) \
+ __iwl_write_restricted(__LINE__, priv, reg, value)
+#else
+#define iwl_write_restricted _iwl_write_restricted
+#endif
+
+static inline void iwl_write_buffer_restricted(struct iwl_priv *priv,
+ u32 reg, u32 len, u32 *values)
+{
+ u32 count = sizeof(u32);
+
+ if ((priv != NULL) && (values != NULL)) {
+ for (; 0 < len; len -= count, reg += count, values++)
+ _iwl_write_restricted(priv, reg, *values);
+ }
+}
+
+static inline int _iwl_poll_restricted_bit(struct iwl_priv *priv,
+ u32 addr, u32 mask, int timeout)
+{
+ int i = 0;
+
+ do {
+ if ((_iwl_read_restricted(priv, addr) & mask) == mask)
+ return i;
+ mdelay(10);
+ i += 10;
+ } while (i < timeout);
+
+ return -ETIMEDOUT;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline int __iwl_poll_restricted_bit(const char *f, u32 l,
+ struct iwl_priv *priv,
+ u32 addr, u32 mask, int timeout)
+{
+ int rc = _iwl_poll_restricted_bit(priv, addr, mask, timeout);
+
+ if (unlikely(rc == -ETIMEDOUT))
+ IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) - "
+ "timedout - %s %d\n", addr, mask, f, l);
+ else
+ IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) = 0x%08X "
+ "- %s %d\n", addr, mask, rc, f, l);
+ return rc;
+}
+#define iwl_poll_restricted_bit(iwl, addr, mask, timeout) \
+ __iwl_poll_restricted_bit(__FILE__, __LINE__, iwl, addr, mask, timeout)
+#else
+#define iwl_poll_restricted_bit _iwl_poll_restricted_bit
+#endif
+
+static inline u32 _iwl_read_restricted_reg(struct iwl_priv *priv, u32 reg)
+{
+ _iwl_write_restricted(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+ return _iwl_read_restricted(priv, HBUS_TARG_PRPH_RDAT);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline u32 __iwl_read_restricted_reg(u32 line,
+ struct iwl_priv *priv, u32 reg)
+{
+ if (!atomic_read(&priv->restrict_refcnt))
+ IWL_ERROR("Unrestricted access from line %d\n", line);
+ return _iwl_read_restricted_reg(priv, reg);
+}
+
+#define iwl_read_restricted_reg(priv, reg) \
+ __iwl_read_restricted_reg(__LINE__, priv, reg)
+#else
+#define iwl_read_restricted_reg _iwl_read_restricted_reg
+#endif
+
+static inline void _iwl_write_restricted_reg(struct iwl_priv *priv,
+ u32 addr, u32 val)
+{
+ _iwl_write_restricted(priv, HBUS_TARG_PRPH_WADDR,
+ ((addr & 0x0000FFFF) | (3 << 24)));
+ _iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT, val);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_write_restricted_reg(u32 line,
+ struct iwl_priv *priv,
+ u32 addr, u32 val)
+{
+ if (!atomic_read(&priv->restrict_refcnt))
+ IWL_ERROR("Unrestricted access from line %d\n", line);
+ _iwl_write_restricted_reg(priv, addr, val);
+}
+
+#define iwl_write_restricted_reg(priv, addr, val) \
+ __iwl_write_restricted_reg(__LINE__, priv, addr, val);
+#else
+#define iwl_write_restricted_reg _iwl_write_restricted_reg
+#endif
+
+#define _iwl_set_bits_restricted_reg(priv, reg, mask) \
+ _iwl_write_restricted_reg(priv, reg, \
+ (_iwl_read_restricted_reg(priv, reg) | mask))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_set_bits_restricted_reg(u32 line, struct iwl_priv
+ *priv, u32 reg, u32 mask)
+{
+ if (!atomic_read(&priv->restrict_refcnt))
+ IWL_ERROR("Unrestricted access from line %d\n", line);
+ _iwl_set_bits_restricted_reg(priv, reg, mask);
+}
+#define iwl_set_bits_restricted_reg(priv, reg, mask) \
+ __iwl_set_bits_restricted_reg(__LINE__, priv, reg, mask)
+#else
+#define iwl_set_bits_restricted_reg _iwl_set_bits_restricted_reg
+#endif
+
+#define _iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \
+ _iwl_write_restricted_reg( \
+ priv, reg, ((_iwl_read_restricted_reg(priv, reg) & mask) | bits))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_set_bits_mask_restricted_reg(u32 line,
+ struct iwl_priv *priv, u32 reg, u32 bits, u32 mask)
+{
+ if (!atomic_read(&priv->restrict_refcnt))
+ IWL_ERROR("Unrestricted access from line %d\n", line);
+ _iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask);
+}
+
+#define iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \
+ __iwl_set_bits_mask_restricted_reg(__LINE__, priv, reg, bits, mask)
+#else
+#define iwl_set_bits_mask_restricted_reg _iwl_set_bits_mask_restricted_reg
+#endif
+
+static inline void iwl_clear_bits_restricted_reg(struct iwl_priv
+ *priv, u32 reg, u32 mask)
+{
+ u32 val = _iwl_read_restricted_reg(priv, reg);
+ _iwl_write_restricted_reg(priv, reg, (val & ~mask));
+}
+
+static inline u32 iwl_read_restricted_mem(struct iwl_priv *priv, u32 addr)
+{
+ iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, addr);
+ return iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+}
+
+static inline void iwl_write_restricted_mem(struct iwl_priv *priv, u32 addr,
+ u32 val)
+{
+ iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr);
+ iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, val);
+}
+
+static inline void iwl_write_restricted_mems(struct iwl_priv *priv, u32 addr,
+ u32 len, u32 *values)
+{
+ iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr);
+ for (; 0 < len; len -= sizeof(u32), values++)
+ iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, *values);
+}
+
+static inline void iwl_write_restricted_regs(struct iwl_priv *priv, u32 reg,
+ u32 len, u8 *values)
+{
+ u32 reg_offset = reg;
+ u32 aligment = reg & 0x3;
+
+ /* write any non-dword-aligned stuff at the beginning */
+ if (len < sizeof(u32)) {
+ if ((aligment + len) <= sizeof(u32)) {
+ u8 size;
+ u32 value = 0;
+ size = len - 1;
+ memcpy(&value, values, len);
+ reg_offset = (reg_offset & 0x0000FFFF);
+
+ _iwl_write_restricted(priv,
+ HBUS_TARG_PRPH_WADDR,
+ (reg_offset | (size << 24)));
+ _iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT,
+ value);
+ }
+
+ return;
+ }
+
+ /* now write all the dword-aligned stuff */
+ for (; reg_offset < (reg + len);
+ reg_offset += sizeof(u32), values += sizeof(u32))
+ _iwl_write_restricted_reg(priv, reg_offset, *((u32 *) values));
+}
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-priv.h b/drivers/net/wireless/iwlwifi/iwl-priv.h
new file mode 100644
index 00000000000..6b490d08fea
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-priv.h
@@ -0,0 +1,308 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_priv_h__
+#define __iwl_priv_h__
+
+#include <linux/workqueue.h>
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+enum {
+ MEASUREMENT_READY = (1 << 0),
+ MEASUREMENT_ACTIVE = (1 << 1),
+};
+
+#endif
+
+struct iwl_priv {
+
+ /* ieee device used by generic ieee processing code */
+ struct ieee80211_hw *hw;
+ struct ieee80211_channel *ieee_channels;
+ struct ieee80211_rate *ieee_rates;
+
+ /* temporary frame storage list */
+ struct list_head free_frames;
+ int frames_count;
+
+ u8 phymode;
+ int alloc_rxb_skb;
+
+ void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb);
+
+ const struct ieee80211_hw_mode *modes;
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+ /* spectrum measurement report caching */
+ struct iwl_spectrum_notification measure_report;
+ u8 measurement_status;
+#endif
+ /* ucode beacon time */
+ u32 ucode_beacon_time;
+
+ /* we allocate array of iwl_channel_info for NIC's valid channels.
+ * Access via channel # using indirect index array */
+ struct iwl_channel_info *channel_info; /* channel info array */
+ u8 channel_count; /* # of channels */
+
+ /* each calibration channel group in the EEPROM has a derived
+ * clip setting for each rate. */
+ const struct iwl_clip_group clip_groups[5];
+
+ /* thermal calibration */
+ s32 temperature; /* degrees Kelvin */
+ s32 last_temperature;
+
+ /* Scan related variables */
+ unsigned long last_scan_jiffies;
+ unsigned long scan_start;
+ unsigned long scan_pass_start;
+ unsigned long scan_start_tsf;
+ int scan_bands;
+ int one_direct_scan;
+ u8 direct_ssid_len;
+ u8 direct_ssid[IW_ESSID_MAX_SIZE];
+ struct iwl_scan_cmd *scan;
+ u8 only_active_channel;
+
+ /* spinlock */
+ spinlock_t lock; /* protect general shared data */
+ spinlock_t hcmd_lock; /* protect hcmd */
+ struct mutex mutex;
+
+ /* basic pci-network driver stuff */
+ struct pci_dev *pci_dev;
+
+ /* pci hardware address support */
+ void __iomem *hw_base;
+
+ /* uCode images, save to reload in case of failure */
+ struct fw_image_desc ucode_code; /* runtime inst */
+ struct fw_image_desc ucode_data; /* runtime data original */
+ struct fw_image_desc ucode_data_backup; /* runtime data save/restore */
+ struct fw_image_desc ucode_init; /* initialization inst */
+ struct fw_image_desc ucode_init_data; /* initialization data */
+ struct fw_image_desc ucode_boot; /* bootstrap inst */
+
+
+ struct iwl_rxon_time_cmd rxon_timing;
+
+ /* We declare this const so it can only be
+ * changed via explicit cast within the
+ * routines that actually update the physical
+ * hardware */
+ const struct iwl_rxon_cmd active_rxon;
+ struct iwl_rxon_cmd staging_rxon;
+
+ int error_recovering;
+ struct iwl_rxon_cmd recovery_rxon;
+
+ /* 1st responses from initialize and runtime uCode images.
+ * 4965's initialize alive response contains some calibration data. */
+ struct iwl_init_alive_resp card_alive_init;
+ struct iwl_alive_resp card_alive;
+
+#ifdef LED
+ /* LED related variables */
+ struct iwl_activity_blink activity;
+ unsigned long led_packets;
+ int led_state;
+#endif
+
+ u16 active_rate;
+ u16 active_rate_basic;
+
+ u8 call_post_assoc_from_beacon;
+ u8 assoc_station_added;
+#if IWL == 4965
+ u8 use_ant_b_for_management_frame; /* Tx antenna selection */
+ /* HT variables */
+ u8 is_dup;
+ u8 is_ht_enabled;
+ u8 channel_width; /* 0=20MHZ, 1=40MHZ */
+ u8 current_channel_width;
+ u8 valid_antenna; /* Bit mask of antennas actually connected */
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ struct iwl_sensitivity_data sensitivity_data;
+ struct iwl_chain_noise_data chain_noise_data;
+ u8 start_calib;
+ __le16 sensitivity_tbl[HD_TABLE_SIZE];
+#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
+
+#ifdef CONFIG_IWLWIFI_HT
+ struct sta_ht_info current_assoc_ht;
+#endif
+ u8 active_rate_ht[2];
+ u8 last_phy_res[100];
+
+ /* Rate scaling data */
+ struct iwl_lq_mngr lq_mngr;
+#endif
+
+ /* Rate scaling data */
+ s8 data_retry_limit;
+ u8 retry_rate;
+
+ wait_queue_head_t wait_command_queue;
+
+ int activity_timer_active;
+
+ /* Rx and Tx DMA processing queues */
+ struct iwl_rx_queue rxq;
+ struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES];
+#if IWL == 4965
+ unsigned long txq_ctx_active_msk;
+ struct iwl_kw kw; /* keep warm address */
+ u32 scd_base_addr; /* scheduler sram base address */
+#endif
+
+ unsigned long status;
+ u32 config;
+
+ int last_rx_rssi; /* From Rx packet statisitics */
+ int last_rx_noise; /* From beacon statistics */
+
+ struct iwl_power_mgr power_data;
+
+ struct iwl_notif_statistics statistics;
+ unsigned long last_statistics_time;
+
+ /* context information */
+ u8 essid[IW_ESSID_MAX_SIZE];
+ u8 essid_len;
+ u16 rates_mask;
+
+ u32 power_mode;
+ u32 antenna;
+ u8 bssid[ETH_ALEN];
+ u16 rts_threshold;
+ u8 mac_addr[ETH_ALEN];
+
+ /*station table variables */
+ spinlock_t sta_lock;
+ int num_stations;
+ struct iwl_station_entry stations[IWL_STATION_COUNT];
+
+ /* Indication if ieee80211_ops->open has been called */
+ int is_open;
+
+ u8 mac80211_registered;
+ int is_abg;
+
+ u32 notif_missed_beacons;
+
+ /* Rx'd packet timing information */
+ u32 last_beacon_time;
+ u64 last_tsf;
+
+ /* Duplicate packet detection */
+ u16 last_seq_num;
+ u16 last_frag_num;
+ unsigned long last_packet_time;
+ struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
+
+ /* eeprom */
+ struct iwl_eeprom eeprom;
+
+ int iw_mode;
+
+ struct sk_buff *ibss_beacon;
+
+ /* Last Rx'd beacon timestamp */
+ u32 timestamp0;
+ u32 timestamp1;
+ u16 beacon_int;
+ struct iwl_driver_hw_info hw_setting;
+ int interface_id;
+
+ /* Current association information needed to configure the
+ * hardware */
+ u16 assoc_id;
+ u16 assoc_capability;
+ u8 ps_mode;
+
+#ifdef CONFIG_IWLWIFI_QOS
+ struct iwl_qos_info qos_data;
+#endif /*CONFIG_IWLWIFI_QOS */
+
+ struct workqueue_struct *workqueue;
+
+ struct work_struct up;
+ struct work_struct restart;
+ struct work_struct calibrated_work;
+ struct work_struct scan_completed;
+ struct work_struct rx_replenish;
+ struct work_struct rf_kill;
+ struct work_struct abort_scan;
+ struct work_struct update_link_led;
+ struct work_struct auth_work;
+ struct work_struct report_work;
+ struct work_struct request_scan;
+ struct work_struct beacon_update;
+
+ struct tasklet_struct irq_tasklet;
+
+ struct delayed_work init_alive_start;
+ struct delayed_work alive_start;
+ struct delayed_work activity_timer;
+ struct delayed_work thermal_periodic;
+ struct delayed_work gather_stats;
+ struct delayed_work scan_check;
+ struct delayed_work post_associate;
+
+#define IWL_DEFAULT_TX_POWER 0x0F
+ s8 user_txpower_limit;
+ s8 max_channel_txpower_limit;
+ u32 cck_power_index_compensation;
+
+#ifdef CONFIG_PM
+ u32 pm_state[16];
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ /* debugging info */
+ u32 framecnt_to_us;
+ atomic_t restrict_refcnt;
+#endif
+
+#if IWL == 4965
+ struct work_struct txpower_work;
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ struct work_struct sensitivity_work;
+#endif
+ struct work_struct statistics_work;
+ struct timer_list statistics_periodic;
+
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ struct work_struct agg_work;
+#endif
+
+#endif /* 4965 */
+}; /*iwl_priv */
+
+#endif /* __iwl_priv_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
new file mode 100644
index 00000000000..0df41148ead
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -0,0 +1,229 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_prph_h__
+#define __iwl_prph_h__
+
+
+#define PRPH_BASE (0x00000)
+#define PRPH_END (0xFFFFF)
+
+/* APMG (power management) constants */
+#define APMG_BASE (PRPH_BASE + 0x3000)
+#define APMG_CLK_CTRL_REG (APMG_BASE + 0x0000)
+#define APMG_CLK_EN_REG (APMG_BASE + 0x0004)
+#define APMG_CLK_DIS_REG (APMG_BASE + 0x0008)
+#define APMG_PS_CTRL_REG (APMG_BASE + 0x000c)
+#define APMG_PCIDEV_STT_REG (APMG_BASE + 0x0010)
+#define APMG_RFKILL_REG (APMG_BASE + 0x0014)
+#define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c)
+#define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020)
+
+#define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200)
+#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800)
+
+#define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000)
+
+#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
+
+#define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000)
+#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000)
+#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x01000000)
+
+
+/**
+ * BSM (Bootstrap State Machine)
+ *
+ * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
+ * in special SRAM that does not power down when the embedded control
+ * processor is sleeping (e.g. for periodic power-saving shutdowns of radio).
+ *
+ * When powering back up after sleeps (or during initial uCode load), the BSM
+ * internally loads the short bootstrap program from the special SRAM into the
+ * embedded processor's instruction SRAM, and starts the processor so it runs
+ * the bootstrap program.
+ *
+ * This bootstrap program loads (via PCI busmaster DMA) instructions and data
+ * images for a uCode program from host DRAM locations. The host driver
+ * indicates DRAM locations and sizes for instruction and data images via the
+ * four BSM_DRAM_* registers. Once the bootstrap program loads the new program,
+ * the new program starts automatically.
+ *
+ * The uCode used for open-source drivers includes two programs:
+ *
+ * 1) Initialization -- performs hardware calibration and sets up some
+ * internal data, then notifies host via "initialize alive" notification
+ * (struct iwl_init_alive_resp) that it has completed all of its work.
+ * After signal from host, it then loads and starts the runtime program.
+ * The initialization program must be used when initially setting up the
+ * NIC after loading the driver.
+ *
+ * 2) Runtime/Protocol -- performs all normal runtime operations. This
+ * notifies host via "alive" notification (struct iwl_alive_resp) that it
+ * is ready to be used.
+ *
+ * When initializing the NIC, the host driver does the following procedure:
+ *
+ * 1) Load bootstrap program (instructions only, no data image for bootstrap)
+ * into bootstrap memory. Use dword writes starting at BSM_SRAM_LOWER_BOUND
+ *
+ * 2) Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction
+ * images in host DRAM.
+ *
+ * 3) Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked:
+ * BSM_WR_MEM_SRC_REG = 0
+ * BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND
+ * BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image
+ *
+ * 4) Load bootstrap into instruction SRAM:
+ * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START
+ *
+ * 5) Wait for load completion:
+ * Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0
+ *
+ * 6) Enable future boot loads whenever NIC's power management triggers it:
+ * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN
+ *
+ * 7) Start the NIC by removing all reset bits:
+ * CSR_RESET = 0
+ *
+ * The bootstrap uCode (already in instruction SRAM) loads initialization
+ * uCode. Initialization uCode performs data initialization, sends
+ * "initialize alive" notification to host, and waits for a signal from
+ * host to load runtime code.
+ *
+ * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction
+ * images in host DRAM. The last register loaded must be the instruction
+ * bytecount register ("1" in MSbit tells initialization uCode to load
+ * the runtime uCode):
+ * BSM_DRAM_INST_BYTECOUNT_REG = bytecount | BSM_DRAM_INST_LOAD
+ *
+ * 5) Wait for "alive" notification, then issue normal runtime commands.
+ *
+ * Data caching during power-downs:
+ *
+ * Just before the embedded controller powers down (e.g for automatic
+ * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA)
+ * a current snapshot of the embedded processor's data SRAM into host DRAM.
+ * This caches the data while the embedded processor's memory is powered down.
+ * Location and size are controlled by BSM_DRAM_DATA_* registers.
+ *
+ * NOTE: Instruction SRAM does not need to be saved, since that doesn't
+ * change during operation; the original image (from uCode distribution
+ * file) can be used for reload.
+ *
+ * When powering back up, the BSM loads the bootstrap program. Bootstrap looks
+ * at the BSM_DRAM_* registers, which now point to the runtime instruction
+ * image and the cached (modified) runtime data (*not* the initialization
+ * uCode). Bootstrap reloads these runtime images into SRAM, and restarts the
+ * uCode from where it left off before the power-down.
+ *
+ * NOTE: Initialization uCode does *not* run as part of the save/restore
+ * procedure.
+ *
+ * This save/restore method is mostly for autonomous power management during
+ * normal operation (result of POWER_TABLE_CMD). Platform suspend/resume and
+ * RFKILL should use complete restarts (with total re-initialization) of uCode,
+ * allowing total shutdown (including BSM memory).
+ *
+ * Note that, during normal operation, the host DRAM that held the initial
+ * startup data for the runtime code is now being used as a backup data cache
+ * for modified data! If you need to completely re-initialize the NIC, make
+ * sure that you use the runtime data image from the uCode distribution file,
+ * not the modified/saved runtime data. You may want to store a separate
+ * "clean" runtime data image in DRAM to avoid disk reads of distribution file.
+ */
+
+/* BSM bit fields */
+#define BSM_WR_CTRL_REG_BIT_START (0x80000000) /* start boot load now */
+#define BSM_WR_CTRL_REG_BIT_START_EN (0x40000000) /* enable boot after pwrup*/
+#define BSM_DRAM_INST_LOAD (0x80000000) /* start program load now */
+
+/* BSM addresses */
+#define BSM_BASE (PRPH_BASE + 0x3400)
+#define BSM_END (PRPH_BASE + 0x3800)
+
+#define BSM_WR_CTRL_REG (BSM_BASE + 0x000) /* ctl and status */
+#define BSM_WR_MEM_SRC_REG (BSM_BASE + 0x004) /* source in BSM mem */
+#define BSM_WR_MEM_DST_REG (BSM_BASE + 0x008) /* dest in SRAM mem */
+#define BSM_WR_DWCOUNT_REG (BSM_BASE + 0x00C) /* bytes */
+#define BSM_WR_STATUS_REG (BSM_BASE + 0x010) /* bit 0: 1 == done */
+
+/*
+ * Pointers and size regs for bootstrap load and data SRAM save/restore.
+ * NOTE: 3945 pointers use bits 31:0 of DRAM address.
+ * 4965 pointers use bits 35:4 of DRAM address.
+ */
+#define BSM_DRAM_INST_PTR_REG (BSM_BASE + 0x090)
+#define BSM_DRAM_INST_BYTECOUNT_REG (BSM_BASE + 0x094)
+#define BSM_DRAM_DATA_PTR_REG (BSM_BASE + 0x098)
+#define BSM_DRAM_DATA_BYTECOUNT_REG (BSM_BASE + 0x09C)
+
+/*
+ * BSM special memory, stays powered on during power-save sleeps.
+ * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1)
+ */
+#define BSM_SRAM_LOWER_BOUND (PRPH_BASE + 0x3800)
+#define BSM_SRAM_SIZE (1024) /* bytes */
+
+
+#endif /* __iwl_prph_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
new file mode 100644
index 00000000000..b576ff24eb4
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
@@ -0,0 +1,91 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_spectrum_h__
+#define __iwl_spectrum_h__
+enum { /* ieee80211_basic_report.map */
+ IEEE80211_BASIC_MAP_BSS = (1 << 0),
+ IEEE80211_BASIC_MAP_OFDM = (1 << 1),
+ IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2),
+ IEEE80211_BASIC_MAP_RADAR = (1 << 3),
+ IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4),
+ /* Bits 5-7 are reserved */
+
+};
+struct ieee80211_basic_report {
+ u8 channel;
+ __le64 start_time;
+ __le16 duration;
+ u8 map;
+} __attribute__ ((packed));
+
+enum { /* ieee80211_measurement_request.mode */
+ /* Bit 0 is reserved */
+ IEEE80211_MEASUREMENT_ENABLE = (1 << 1),
+ IEEE80211_MEASUREMENT_REQUEST = (1 << 2),
+ IEEE80211_MEASUREMENT_REPORT = (1 << 3),
+ /* Bits 4-7 are reserved */
+};
+
+enum {
+ IEEE80211_REPORT_BASIC = 0, /* required */
+ IEEE80211_REPORT_CCA = 1, /* optional */
+ IEEE80211_REPORT_RPI = 2, /* optional */
+ /* 3-255 reserved */
+};
+
+struct ieee80211_measurement_params {
+ u8 channel;
+ __le64 start_time;
+ __le16 duration;
+} __attribute__ ((packed));
+
+struct ieee80211_info_element {
+ u8 id;
+ u8 len;
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct ieee80211_measurement_request {
+ struct ieee80211_info_element ie;
+ u8 token;
+ u8 mode;
+ u8 type;
+ struct ieee80211_measurement_params params[0];
+} __attribute__ ((packed));
+
+struct ieee80211_measurement_report {
+ struct ieee80211_info_element ie;
+ u8 token;
+ u8 mode;
+ u8 type;
+ union {
+ struct ieee80211_basic_report basic[0];
+ } u;
+} __attribute__ ((packed));
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
new file mode 100644
index 00000000000..465da4f67ce
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -0,0 +1,8797 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+/*
+ * NOTE: This file (iwl-base.c) is used to build to multiple hardware targets
+ * by defining IWL to either 3945 or 4965. The Makefile used when building
+ * the base targets will create base-3945.o and base-4965.o
+ *
+ * The eventual goal is to move as many of the #if IWL / #endif blocks out of
+ * this file and into the hardware specific implementation files (iwl-XXXX.c)
+ * and leave only the common (non #ifdef sprinkled) code in this file
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/ieee80211_radiotap.h>
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#define IWL 3945
+
+#include "iwlwifi.h"
+#include "iwl-3945.h"
+#include "iwl-helpers.h"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+u32 iwl_debug_level;
+#endif
+
+/******************************************************************************
+ *
+ * module boiler plate
+ *
+ ******************************************************************************/
+
+/* module parameters */
+int iwl_param_disable_hw_scan;
+int iwl_param_debug;
+int iwl_param_disable; /* def: enable radio */
+int iwl_param_antenna; /* def: 0 = both antennas (use diversity) */
+int iwl_param_hwcrypto; /* def: using software encryption */
+int iwl_param_qos_enable = 1;
+int iwl_param_queues_num = IWL_MAX_NUM_QUEUES;
+
+/*
+ * module name, copyright, version, etc.
+ * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk
+ */
+
+#define DRV_DESCRIPTION \
+"Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#define VS "s"
+#else
+#define VS
+#endif
+
+#define IWLWIFI_VERSION "1.1.17k" VD VS
+#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation"
+#define DRV_VERSION IWLWIFI_VERSION
+
+/* Change firmware file name, using "-" and incrementing number,
+ * *only* when uCode interface or architecture changes so that it
+ * is not compatible with earlier drivers.
+ * This number will also appear in << 8 position of 1st dword of uCode file */
+#define IWL3945_UCODE_API "-1"
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
+{
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ int hdr_len = ieee80211_get_hdrlen(fc);
+
+ if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
+ return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
+ return NULL;
+}
+
+static const struct ieee80211_hw_mode *iwl_get_hw_mode(
+ struct iwl_priv *priv, int mode)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ if (priv->modes[i].mode == mode)
+ return &priv->modes[i];
+
+ return NULL;
+}
+
+static int iwl_is_empty_essid(const char *essid, int essid_len)
+{
+ /* Single white space is for Linksys APs */
+ if (essid_len == 1 && essid[0] == ' ')
+ return 1;
+
+ /* Otherwise, if the entire essid is 0, we assume it is hidden */
+ while (essid_len) {
+ essid_len--;
+ if (essid[essid_len] != '\0')
+ return 0;
+ }
+
+ return 1;
+}
+
+static const char *iwl_escape_essid(const char *essid, u8 essid_len)
+{
+ static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+ const char *s = essid;
+ char *d = escaped;
+
+ if (iwl_is_empty_essid(essid, essid_len)) {
+ memcpy(escaped, "<hidden>", sizeof("<hidden>"));
+ return escaped;
+ }
+
+ essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
+ while (essid_len--) {
+ if (*s == '\0') {
+ *d++ = '\\';
+ *d++ = '0';
+ s++;
+ } else
+ *d++ = *s++;
+ }
+ *d = '\0';
+ return escaped;
+}
+
+static void iwl_print_hex_dump(int level, void *p, u32 len)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (!(iwl_debug_level & level))
+ return;
+
+ print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
+ p, len, 1);
+#endif
+}
+
+/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A queue is a circular buffers with 'Read' and 'Write' pointers.
+ * 2 empty entries always kept in the buffer to protect from overflow.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ * The IWL operates with six queues, one receive queue in the device's
+ * sram, one transmit queue for sending commands to the device firmware,
+ * and four transmit queues for data.
+ ***************************************************/
+
+static int iwl_queue_space(const struct iwl_queue *q)
+{
+ int s = q->last_used - q->first_empty;
+
+ if (q->last_used > q->first_empty)
+ s -= q->n_bd;
+
+ if (s <= 0)
+ s += q->n_window;
+ /* keep some reserve to not confuse empty and full situations */
+ s -= 2;
+ if (s < 0)
+ s = 0;
+ return s;
+}
+
+/* XXX: n_bd must be power-of-two size */
+static inline int iwl_queue_inc_wrap(int index, int n_bd)
+{
+ return ++index & (n_bd - 1);
+}
+
+/* XXX: n_bd must be power-of-two size */
+static inline int iwl_queue_dec_wrap(int index, int n_bd)
+{
+ return --index & (n_bd - 1);
+}
+
+static inline int x2_queue_used(const struct iwl_queue *q, int i)
+{
+ return q->first_empty > q->last_used ?
+ (i >= q->last_used && i < q->first_empty) :
+ !(i < q->last_used && i >= q->first_empty);
+}
+
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
+{
+ if (is_huge)
+ return q->n_window;
+
+ return index & (q->n_window - 1);
+}
+
+static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
+ int count, int slots_num, u32 id)
+{
+ q->n_bd = count;
+ q->n_window = slots_num;
+ q->id = id;
+
+ /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
+ * and iwl_queue_dec_wrap are broken. */
+ BUG_ON(!is_power_of_2(count));
+
+ /* slots_num must be power-of-two size, otherwise
+ * get_cmd_index is broken. */
+ BUG_ON(!is_power_of_2(slots_num));
+
+ q->low_mark = q->n_window / 4;
+ if (q->low_mark < 4)
+ q->low_mark = 4;
+
+ q->high_mark = q->n_window / 8;
+ if (q->high_mark < 2)
+ q->high_mark = 2;
+
+ q->first_empty = q->last_used = 0;
+
+ return 0;
+}
+
+static int iwl_tx_queue_alloc(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq, u32 id)
+{
+ struct pci_dev *dev = priv->pci_dev;
+
+ if (id != IWL_CMD_QUEUE_NUM) {
+ txq->txb = kmalloc(sizeof(txq->txb[0]) *
+ TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
+ if (!txq->txb) {
+ IWL_ERROR("kmalloc for auxilary BD "
+ "structures failed\n");
+ goto error;
+ }
+ } else
+ txq->txb = NULL;
+
+ txq->bd = pci_alloc_consistent(dev,
+ sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
+ &txq->q.dma_addr);
+
+ if (!txq->bd) {
+ IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
+ sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
+ goto error;
+ }
+ txq->q.id = id;
+
+ return 0;
+
+ error:
+ if (txq->txb) {
+ kfree(txq->txb);
+ txq->txb = NULL;
+ }
+
+ return -ENOMEM;
+}
+
+int iwl_tx_queue_init(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq, int slots_num, u32 txq_id)
+{
+ struct pci_dev *dev = priv->pci_dev;
+ int len;
+ int rc = 0;
+
+ /* alocate command space + one big command for scan since scan
+ * command is very huge the system will not have two scan at the
+ * same time */
+ len = sizeof(struct iwl_cmd) * slots_num;
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ len += IWL_MAX_SCAN_SIZE;
+ txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
+ if (!txq->cmd)
+ return -ENOMEM;
+
+ rc = iwl_tx_queue_alloc(priv, txq, txq_id);
+ if (rc) {
+ pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+ return -ENOMEM;
+ }
+ txq->need_update = 0;
+
+ /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+ * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+ iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+
+ iwl_hw_tx_queue_init(priv, txq);
+
+ return 0;
+}
+
+/**
+ * iwl_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers. txq itself is not freed.
+ *
+ */
+void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ struct iwl_queue *q = &txq->q;
+ struct pci_dev *dev = priv->pci_dev;
+ int len;
+
+ if (q->n_bd == 0)
+ return;
+
+ /* first, empty all BD's */
+ for (; q->first_empty != q->last_used;
+ q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd))
+ iwl_hw_txq_free_tfd(priv, txq);
+
+ len = sizeof(struct iwl_cmd) * q->n_window;
+ if (q->id == IWL_CMD_QUEUE_NUM)
+ len += IWL_MAX_SCAN_SIZE;
+
+ pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+ /* free buffers belonging to queue itself */
+ if (txq->q.n_bd)
+ pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
+ txq->q.n_bd, txq->bd, txq->q.dma_addr);
+
+ if (txq->txb) {
+ kfree(txq->txb);
+ txq->txb = NULL;
+ }
+
+ /* 0 fill whole structure */
+ memset(txq, 0, sizeof(*txq));
+}
+
+const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+/*************** STATION TABLE MANAGEMENT ****
+ *
+ * NOTE: This needs to be overhauled to better synchronize between
+ * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c
+ *
+ * mac80211 should also be examined to determine if sta_info is duplicating
+ * the functionality provided here
+ */
+
+/**************************************************************/
+#if 0 /* temparary disable till we add real remove station */
+static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+ int index = IWL_INVALID_STATION;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ if (is_ap)
+ index = IWL_AP_ID;
+ else if (is_broadcast_ether_addr(addr))
+ index = priv->hw_setting.bcast_sta_id;
+ else
+ for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+ if (priv->stations[i].used &&
+ !compare_ether_addr(priv->stations[i].sta.sta.addr,
+ addr)) {
+ index = i;
+ break;
+ }
+
+ if (unlikely(index == IWL_INVALID_STATION))
+ goto out;
+
+ if (priv->stations[index].used) {
+ priv->stations[index].used = 0;
+ priv->num_stations--;
+ }
+
+ BUG_ON(priv->num_stations < 0);
+
+out:
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+}
+#endif
+static void iwl_clear_stations_table(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->num_stations = 0;
+ memset(priv->stations, 0, sizeof(priv->stations));
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+
+
+u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
+{
+ int i;
+ int index = IWL_INVALID_STATION;
+ struct iwl_station_entry *station;
+ unsigned long flags_spin;
+ DECLARE_MAC_BUF(mac);
+ u8 rate;
+
+ spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ if (is_ap)
+ index = IWL_AP_ID;
+ else if (is_broadcast_ether_addr(addr))
+ index = priv->hw_setting.bcast_sta_id;
+ else
+ for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) {
+ if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+ addr)) {
+ index = i;
+ break;
+ }
+
+ if (!priv->stations[i].used &&
+ index == IWL_INVALID_STATION)
+ index = i;
+ }
+
+ /* These twh conditions has the same outcome but keep them separate
+ since they have different meaning */
+ if (unlikely(index == IWL_INVALID_STATION)) {
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ return index;
+ }
+
+ if (priv->stations[index].used &&
+ !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ return index;
+ }
+
+ IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
+ station = &priv->stations[index];
+ station->used = 1;
+ priv->num_stations++;
+
+ memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
+ memcpy(station->sta.sta.addr, addr, ETH_ALEN);
+ station->sta.mode = 0;
+ station->sta.sta.sta_id = index;
+ station->sta.station_flags = 0;
+
+ rate = (priv->phymode == MODE_IEEE80211A) ? IWL_RATE_6M_PLCP :
+ IWL_RATE_1M_PLCP | priv->hw_setting.cck_flag;
+
+ /* Turn on both antennas for the station... */
+ station->sta.rate_n_flags =
+ iwl_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK);
+ station->current_rate.rate_n_flags =
+ le16_to_cpu(station->sta.rate_n_flags);
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ iwl_send_add_station(priv, &station->sta, flags);
+ return index;
+
+}
+
+/*************** DRIVER STATUS FUNCTIONS *****/
+
+static inline int iwl_is_ready(struct iwl_priv *priv)
+{
+ /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
+ * set but EXIT_PENDING is not */
+ return test_bit(STATUS_READY, &priv->status) &&
+ test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
+ !test_bit(STATUS_EXIT_PENDING, &priv->status);
+}
+
+static inline int iwl_is_alive(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_ALIVE, &priv->status);
+}
+
+static inline int iwl_is_init(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_INIT, &priv->status);
+}
+
+static inline int iwl_is_rfkill(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+ test_bit(STATUS_RF_KILL_SW, &priv->status);
+}
+
+static inline int iwl_is_ready_rf(struct iwl_priv *priv)
+{
+
+ if (iwl_is_rfkill(priv))
+ return 0;
+
+ return iwl_is_ready(priv);
+}
+
+/*************** HOST COMMAND QUEUE FUNCTIONS *****/
+
+#define IWL_CMD(x) case x : return #x
+
+static const char *get_cmd_string(u8 cmd)
+{
+ switch (cmd) {
+ IWL_CMD(REPLY_ALIVE);
+ IWL_CMD(REPLY_ERROR);
+ IWL_CMD(REPLY_RXON);
+ IWL_CMD(REPLY_RXON_ASSOC);
+ IWL_CMD(REPLY_QOS_PARAM);
+ IWL_CMD(REPLY_RXON_TIMING);
+ IWL_CMD(REPLY_ADD_STA);
+ IWL_CMD(REPLY_REMOVE_STA);
+ IWL_CMD(REPLY_REMOVE_ALL_STA);
+ IWL_CMD(REPLY_3945_RX);
+ IWL_CMD(REPLY_TX);
+ IWL_CMD(REPLY_RATE_SCALE);
+ IWL_CMD(REPLY_LEDS_CMD);
+ IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
+ IWL_CMD(RADAR_NOTIFICATION);
+ IWL_CMD(REPLY_QUIET_CMD);
+ IWL_CMD(REPLY_CHANNEL_SWITCH);
+ IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
+ IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
+ IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
+ IWL_CMD(POWER_TABLE_CMD);
+ IWL_CMD(PM_SLEEP_NOTIFICATION);
+ IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
+ IWL_CMD(REPLY_SCAN_CMD);
+ IWL_CMD(REPLY_SCAN_ABORT_CMD);
+ IWL_CMD(SCAN_START_NOTIFICATION);
+ IWL_CMD(SCAN_RESULTS_NOTIFICATION);
+ IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
+ IWL_CMD(BEACON_NOTIFICATION);
+ IWL_CMD(REPLY_TX_BEACON);
+ IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
+ IWL_CMD(QUIET_NOTIFICATION);
+ IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
+ IWL_CMD(MEASURE_ABORT_NOTIFICATION);
+ IWL_CMD(REPLY_BT_CONFIG);
+ IWL_CMD(REPLY_STATISTICS_CMD);
+ IWL_CMD(STATISTICS_NOTIFICATION);
+ IWL_CMD(REPLY_CARD_STATE_CMD);
+ IWL_CMD(CARD_STATE_NOTIFICATION);
+ IWL_CMD(MISSED_BEACONS_NOTIFICATION);
+ default:
+ return "UNKNOWN";
+
+ }
+}
+
+#define HOST_COMPLETE_TIMEOUT (HZ / 2)
+
+/**
+ * iwl_enqueue_hcmd - enqueue a uCode command
+ * @priv: device private data point
+ * @cmd: a point to the ucode command structure
+ *
+ * The function returns < 0 values to indicate the operation is
+ * failed. On success, it turns the index (> 0) of command in the
+ * command queue.
+ */
+static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+ struct iwl_queue *q = &txq->q;
+ struct iwl_tfd_frame *tfd;
+ u32 *control_flags;
+ struct iwl_cmd *out_cmd;
+ u32 idx;
+ u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
+ dma_addr_t phys_addr;
+ int pad;
+ u16 count;
+ int ret;
+ unsigned long flags;
+
+ /* If any of the command structures end up being larger than
+ * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
+ * we will need to increase the size of the TFD entries */
+ BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
+ !(cmd->meta.flags & CMD_SIZE_HUGE));
+
+ if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+ IWL_ERROR("No space for Tx\n");
+ return -ENOSPC;
+ }
+
+ spin_lock_irqsave(&priv->hcmd_lock, flags);
+
+ tfd = &txq->bd[q->first_empty];
+ memset(tfd, 0, sizeof(*tfd));
+
+ control_flags = (u32 *) tfd;
+
+ idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE);
+ out_cmd = &txq->cmd[idx];
+
+ out_cmd->hdr.cmd = cmd->id;
+ memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
+ memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
+
+ /* At this point, the out_cmd now has all of the incoming cmd
+ * information */
+
+ out_cmd->hdr.flags = 0;
+ out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
+ INDEX_TO_SEQ(q->first_empty));
+ if (out_cmd->meta.flags & CMD_SIZE_HUGE)
+ out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
+
+ phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
+ offsetof(struct iwl_cmd, hdr);
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
+
+ pad = U32_PAD(cmd->len);
+ count = TFD_CTL_COUNT_GET(*control_flags);
+ *control_flags = TFD_CTL_COUNT_SET(count) | TFD_CTL_PAD_SET(pad);
+
+ IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
+ "%d bytes at %d[%d]:%d\n",
+ get_cmd_string(out_cmd->hdr.cmd),
+ out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
+ fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM);
+
+ txq->need_update = 1;
+ q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
+ ret = iwl_tx_queue_update_write_ptr(priv, txq);
+
+ spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+ return ret ? ret : idx;
+}
+
+int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ int ret;
+
+ BUG_ON(!(cmd->meta.flags & CMD_ASYNC));
+
+ /* An asynchronous command can not expect an SKB to be set. */
+ BUG_ON(cmd->meta.flags & CMD_WANT_SKB);
+
+ /* An asynchronous command MUST have a callback. */
+ BUG_ON(!cmd->meta.u.callback);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return -EBUSY;
+
+ ret = iwl_enqueue_hcmd(priv, cmd);
+ if (ret < 0) {
+ IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+ get_cmd_string(cmd->id), ret);
+ return ret;
+ }
+ return 0;
+}
+
+int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ int cmd_idx;
+ int ret;
+ static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */
+
+ BUG_ON(cmd->meta.flags & CMD_ASYNC);
+
+ /* A synchronous command can not have a callback set. */
+ BUG_ON(cmd->meta.u.callback != NULL);
+
+ if (atomic_xchg(&entry, 1)) {
+ IWL_ERROR("Error sending %s: Already sending a host command\n",
+ get_cmd_string(cmd->id));
+ return -EBUSY;
+ }
+
+ set_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+ if (cmd->meta.flags & CMD_WANT_SKB)
+ cmd->meta.source = &cmd->meta;
+
+ cmd_idx = iwl_enqueue_hcmd(priv, cmd);
+ if (cmd_idx < 0) {
+ ret = cmd_idx;
+ IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+ get_cmd_string(cmd->id), ret);
+ goto out;
+ }
+
+ ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ !test_bit(STATUS_HCMD_ACTIVE, &priv->status),
+ HOST_COMPLETE_TIMEOUT);
+ if (!ret) {
+ if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) {
+ IWL_ERROR("Error sending %s: time out after %dms.\n",
+ get_cmd_string(cmd->id),
+ jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
+
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ ret = -ETIMEDOUT;
+ goto cancel;
+ }
+ }
+
+ if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+ IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n",
+ get_cmd_string(cmd->id));
+ ret = -ECANCELED;
+ goto fail;
+ }
+ if (test_bit(STATUS_FW_ERROR, &priv->status)) {
+ IWL_DEBUG_INFO("Command %s failed: FW Error\n",
+ get_cmd_string(cmd->id));
+ ret = -EIO;
+ goto fail;
+ }
+ if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {
+ IWL_ERROR("Error: Response NULL in '%s'\n",
+ get_cmd_string(cmd->id));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ goto out;
+
+cancel:
+ if (cmd->meta.flags & CMD_WANT_SKB) {
+ struct iwl_cmd *qcmd;
+
+ /* Cancel the CMD_WANT_SKB flag for the cmd in the
+ * TX cmd queue. Otherwise in case the cmd comes
+ * in later, it will possibly set an invalid
+ * address (cmd->meta.source). */
+ qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
+ qcmd->meta.flags &= ~CMD_WANT_SKB;
+ }
+fail:
+ if (cmd->meta.u.skb) {
+ dev_kfree_skb_any(cmd->meta.u.skb);
+ cmd->meta.u.skb = NULL;
+ }
+out:
+ atomic_set(&entry, 0);
+ return ret;
+}
+
+int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ /* A command can not be asynchronous AND expect an SKB to be set. */
+ BUG_ON((cmd->meta.flags & CMD_ASYNC) &&
+ (cmd->meta.flags & CMD_WANT_SKB));
+
+ if (cmd->meta.flags & CMD_ASYNC)
+ return iwl_send_cmd_async(priv, cmd);
+
+ return iwl_send_cmd_sync(priv, cmd);
+}
+
+int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
+{
+ struct iwl_host_cmd cmd = {
+ .id = id,
+ .len = len,
+ .data = data,
+ };
+
+ return iwl_send_cmd_sync(priv, &cmd);
+}
+
+static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val)
+{
+ struct iwl_host_cmd cmd = {
+ .id = id,
+ .len = sizeof(val),
+ .data = &val,
+ };
+
+ return iwl_send_cmd_sync(priv, &cmd);
+}
+
+int iwl_send_statistics_request(struct iwl_priv *priv)
+{
+ return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
+}
+
+/**
+ * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
+ * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
+ * @channel: Any channel valid for the requested phymode
+
+ * In addition to setting the staging RXON, priv->phymode is also set.
+ *
+ * NOTE: Does not commit to the hardware; it sets appropriate bit fields
+ * in the staging RXON flag structure based on the phymode
+ */
+static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel)
+{
+ if (!iwl_get_channel_info(priv, phymode, channel)) {
+ IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
+ channel, phymode);
+ return -EINVAL;
+ }
+
+ if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
+ (priv->phymode == phymode))
+ return 0;
+
+ priv->staging_rxon.channel = cpu_to_le16(channel);
+ if (phymode == MODE_IEEE80211A)
+ priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
+ else
+ priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+
+ priv->phymode = phymode;
+
+ IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode);
+
+ return 0;
+}
+
+/**
+ * iwl_check_rxon_cmd - validate RXON structure is valid
+ *
+ * NOTE: This is really only useful during development and can eventually
+ * be #ifdef'd out once the driver is stable and folks aren't actively
+ * making changes
+ */
+static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
+{
+ int error = 0;
+ int counter = 1;
+
+ if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
+ error |= le32_to_cpu(rxon->flags &
+ (RXON_FLG_TGJ_NARROW_BAND_MSK |
+ RXON_FLG_RADAR_DETECT_MSK));
+ if (error)
+ IWL_WARNING("check 24G fields %d | %d\n",
+ counter++, error);
+ } else {
+ error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
+ 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
+ if (error)
+ IWL_WARNING("check 52 fields %d | %d\n",
+ counter++, error);
+ error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
+ if (error)
+ IWL_WARNING("check 52 CCK %d | %d\n",
+ counter++, error);
+ }
+ error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
+ if (error)
+ IWL_WARNING("check mac addr %d | %d\n", counter++, error);
+
+ /* make sure basic rates 6Mbps and 1Mbps are supported */
+ error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
+ ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
+ if (error)
+ IWL_WARNING("check basic rate %d | %d\n", counter++, error);
+
+ error |= (le16_to_cpu(rxon->assoc_id) > 2007);
+ if (error)
+ IWL_WARNING("check assoc id %d | %d\n", counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
+ == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
+ if (error)
+ IWL_WARNING("check CCK and short slot %d | %d\n",
+ counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
+ == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
+ if (error)
+ IWL_WARNING("check CCK & auto detect %d | %d\n",
+ counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
+ RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
+ if (error)
+ IWL_WARNING("check TGG and auto detect %d | %d\n",
+ counter++, error);
+
+ if ((rxon->flags & RXON_FLG_DIS_DIV_MSK))
+ error |= ((rxon->flags & (RXON_FLG_ANT_B_MSK |
+ RXON_FLG_ANT_A_MSK)) == 0);
+ if (error)
+ IWL_WARNING("check antenna %d %d\n", counter++, error);
+
+ if (error)
+ IWL_WARNING("Tuning to channel %d\n",
+ le16_to_cpu(rxon->channel));
+
+ if (error) {
+ IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n");
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit
+ * @priv: staging_rxon is comapred to active_rxon
+ *
+ * If the RXON structure is changing sufficient to require a new
+ * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1
+ * to indicate a new tune is required.
+ */
+static int iwl_full_rxon_required(struct iwl_priv *priv)
+{
+
+ /* These items are only settable from the full RXON command */
+ if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ||
+ compare_ether_addr(priv->staging_rxon.bssid_addr,
+ priv->active_rxon.bssid_addr) ||
+ compare_ether_addr(priv->staging_rxon.node_addr,
+ priv->active_rxon.node_addr) ||
+ compare_ether_addr(priv->staging_rxon.wlap_bssid_addr,
+ priv->active_rxon.wlap_bssid_addr) ||
+ (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) ||
+ (priv->staging_rxon.channel != priv->active_rxon.channel) ||
+ (priv->staging_rxon.air_propagation !=
+ priv->active_rxon.air_propagation) ||
+ (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
+ return 1;
+
+ /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
+ * be updated with the RXON_ASSOC command -- however only some
+ * flag transitions are allowed using RXON_ASSOC */
+
+ /* Check if we are not switching bands */
+ if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) !=
+ (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK))
+ return 1;
+
+ /* Check if we are switching association toggle */
+ if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) !=
+ (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK))
+ return 1;
+
+ return 0;
+}
+
+static int iwl_send_rxon_assoc(struct iwl_priv *priv)
+{
+ int rc = 0;
+ struct iwl_rx_packet *res = NULL;
+ struct iwl_rxon_assoc_cmd rxon_assoc;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_RXON_ASSOC,
+ .len = sizeof(rxon_assoc),
+ .meta.flags = CMD_WANT_SKB,
+ .data = &rxon_assoc,
+ };
+ const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
+ const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+
+ if ((rxon1->flags == rxon2->flags) &&
+ (rxon1->filter_flags == rxon2->filter_flags) &&
+ (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+ (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+ IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n");
+ return 0;
+ }
+
+ rxon_assoc.flags = priv->staging_rxon.flags;
+ rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
+ rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
+ rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+ rxon_assoc.reserved = 0;
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n");
+ rc = -EIO;
+ }
+
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+
+/**
+ * iwl_commit_rxon - commit staging_rxon to hardware
+ *
+ * The RXON command in staging_rxon is commited to the hardware and
+ * the active_rxon structure is updated with the new data. This
+ * function correctly transitions out of the RXON_ASSOC_MSK state if
+ * a HW tune is required based on the RXON structure changes.
+ */
+static int iwl_commit_rxon(struct iwl_priv *priv)
+{
+ /* cast away the const for active_rxon in this function */
+ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+ int rc = 0;
+ DECLARE_MAC_BUF(mac);
+
+ if (!iwl_is_alive(priv))
+ return -1;
+
+ /* always get timestamp with Rx frame */
+ priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
+
+ /* select antenna */
+ priv->staging_rxon.flags &=
+ ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
+ priv->staging_rxon.flags |= iwl3945_get_antenna_flags(priv);
+
+ rc = iwl_check_rxon_cmd(&priv->staging_rxon);
+ if (rc) {
+ IWL_ERROR("Invalid RXON configuration. Not committing.\n");
+ return -EINVAL;
+ }
+
+ /* If we don't need to send a full RXON, we can use
+ * iwl_rxon_assoc_cmd which is used to reconfigure filter
+ * and other flags for the current radio configuration. */
+ if (!iwl_full_rxon_required(priv)) {
+ rc = iwl_send_rxon_assoc(priv);
+ if (rc) {
+ IWL_ERROR("Error setting RXON_ASSOC "
+ "configuration (%d).\n", rc);
+ return rc;
+ }
+
+ memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+ return 0;
+ }
+
+ /* If we are currently associated and the new config requires
+ * an RXON_ASSOC and the new config wants the associated mask enabled,
+ * we must clear the associated from the active configuration
+ * before we apply the new config */
+ if (iwl_is_associated(priv) &&
+ (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) {
+ IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
+ active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+ sizeof(struct iwl_rxon_cmd),
+ &priv->active_rxon);
+
+ /* If the mask clearing failed then we set
+ * active_rxon back to what it was previously */
+ if (rc) {
+ active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
+ IWL_ERROR("Error clearing ASSOC_MSK on current "
+ "configuration (%d).\n", rc);
+ return rc;
+ }
+ }
+
+ IWL_DEBUG_INFO("Sending RXON\n"
+ "* with%s RXON_FILTER_ASSOC_MSK\n"
+ "* channel = %d\n"
+ "* bssid = %s\n",
+ ((priv->staging_rxon.filter_flags &
+ RXON_FILTER_ASSOC_MSK) ? "" : "out"),
+ le16_to_cpu(priv->staging_rxon.channel),
+ print_mac(mac, priv->staging_rxon.bssid_addr));
+
+ /* Apply the new configuration */
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+ sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+ if (rc) {
+ IWL_ERROR("Error setting new configuration (%d).\n", rc);
+ return rc;
+ }
+
+ memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+ iwl_clear_stations_table(priv);
+
+ /* If we issue a new RXON command which required a tune then we must
+ * send a new TXPOWER command or we won't be able to Tx any frames */
+ rc = iwl_hw_reg_send_txpower(priv);
+ if (rc) {
+ IWL_ERROR("Error setting Tx power (%d).\n", rc);
+ return rc;
+ }
+
+ /* Add the broadcast address so we can send broadcast frames */
+ if (iwl_add_station(priv, BROADCAST_ADDR, 0, 0) ==
+ IWL_INVALID_STATION) {
+ IWL_ERROR("Error adding BROADCAST address for transmit.\n");
+ return -EIO;
+ }
+
+ /* If we have set the ASSOC_MSK and we are in BSS mode then
+ * add the IWL_AP_ID to the station rate table */
+ if (iwl_is_associated(priv) &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+ if (iwl_add_station(priv, priv->active_rxon.bssid_addr, 1, 0)
+ == IWL_INVALID_STATION) {
+ IWL_ERROR("Error adding AP address for transmit.\n");
+ return -EIO;
+ }
+
+ /* Init the hardware's rate fallback order based on the
+ * phymode */
+ rc = iwl3945_init_hw_rate_table(priv);
+ if (rc) {
+ IWL_ERROR("Error setting HW rate table: %02X\n", rc);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int iwl_send_bt_config(struct iwl_priv *priv)
+{
+ struct iwl_bt_cmd bt_cmd = {
+ .flags = 3,
+ .lead_time = 0xAA,
+ .max_kill = 1,
+ .kill_ack_mask = 0,
+ .kill_cts_mask = 0,
+ };
+
+ return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+ sizeof(struct iwl_bt_cmd), &bt_cmd);
+}
+
+static int iwl_send_scan_abort(struct iwl_priv *priv)
+{
+ int rc = 0;
+ struct iwl_rx_packet *res;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SCAN_ABORT_CMD,
+ .meta.flags = CMD_WANT_SKB,
+ };
+
+ /* If there isn't a scan actively going on in the hardware
+ * then we are in between scan bands and not actually
+ * actively scanning, so don't send the abort command */
+ if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ return 0;
+ }
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc) {
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ return rc;
+ }
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->u.status != CAN_ABORT_STATUS) {
+ /* The scan abort will return 1 for success or
+ * 2 for "failure". A failure condition can be
+ * due to simply not being in an active scan which
+ * can occur if we send the scan abort before we
+ * the microcode has notified us that a scan is
+ * completed. */
+ IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status);
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ clear_bit(STATUS_SCAN_HW, &priv->status);
+ }
+
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+
+static int iwl_card_state_sync_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct sk_buff *skb)
+{
+ return 1;
+}
+
+/*
+ * CARD_STATE_CMD
+ *
+ * Use: Sets the internal card state to enable, disable, or halt
+ *
+ * When in the 'enable' state the card operates as normal.
+ * When in the 'disable' state, the card enters into a low power mode.
+ * When in the 'halt' state, the card is shut down and must be fully
+ * restarted to come back on.
+ */
+static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
+{
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_CARD_STATE_CMD,
+ .len = sizeof(u32),
+ .data = &flags,
+ .meta.flags = meta_flag,
+ };
+
+ if (meta_flag & CMD_ASYNC)
+ cmd.meta.u.callback = iwl_card_state_sync_callback;
+
+ return iwl_send_cmd(priv, &cmd);
+}
+
+static int iwl_add_sta_sync_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+ struct iwl_rx_packet *res = NULL;
+
+ if (!skb) {
+ IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
+ return 1;
+ }
+
+ res = (struct iwl_rx_packet *)skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+ res->hdr.flags);
+ return 1;
+ }
+
+ switch (res->u.add_sta.status) {
+ case ADD_STA_SUCCESS_MSK:
+ break;
+ default:
+ break;
+ }
+
+ /* We didn't cache the SKB; let the caller free it */
+ return 1;
+}
+
+int iwl_send_add_station(struct iwl_priv *priv,
+ struct iwl_addsta_cmd *sta, u8 flags)
+{
+ struct iwl_rx_packet *res = NULL;
+ int rc = 0;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_ADD_STA,
+ .len = sizeof(struct iwl_addsta_cmd),
+ .meta.flags = flags,
+ .data = sta,
+ };
+
+ if (flags & CMD_ASYNC)
+ cmd.meta.u.callback = iwl_add_sta_sync_callback;
+ else
+ cmd.meta.flags |= CMD_WANT_SKB;
+
+ rc = iwl_send_cmd(priv, &cmd);
+
+ if (rc || (flags & CMD_ASYNC))
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+ res->hdr.flags);
+ rc = -EIO;
+ }
+
+ if (rc == 0) {
+ switch (res->u.add_sta.status) {
+ case ADD_STA_SUCCESS_MSK:
+ IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
+ break;
+ default:
+ rc = -EIO;
+ IWL_WARNING("REPLY_ADD_STA failed\n");
+ break;
+ }
+ }
+
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+
+static int iwl_update_sta_key_info(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id)
+{
+ unsigned long flags;
+ __le16 key_flags = 0;
+
+ switch (keyconf->alg) {
+ case ALG_CCMP:
+ key_flags |= STA_KEY_FLG_CCMP;
+ key_flags |= cpu_to_le16(
+ keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags &= ~STA_KEY_FLG_INVALID;
+ break;
+ case ALG_TKIP:
+ case ALG_WEP:
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+ priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
+ memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
+ keyconf->keylen);
+
+ memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
+ keyconf->keylen);
+ priv->stations[sta_id].sta.key.key_flags = key_flags;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+ return 0;
+}
+
+static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
+ memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo));
+ priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+ return 0;
+}
+
+static void iwl_clear_free_frames(struct iwl_priv *priv)
+{
+ struct list_head *element;
+
+ IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n",
+ priv->frames_count);
+
+ while (!list_empty(&priv->free_frames)) {
+ element = priv->free_frames.next;
+ list_del(element);
+ kfree(list_entry(element, struct iwl_frame, list));
+ priv->frames_count--;
+ }
+
+ if (priv->frames_count) {
+ IWL_WARNING("%d frames still in use. Did we lose one?\n",
+ priv->frames_count);
+ priv->frames_count = 0;
+ }
+}
+
+static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
+{
+ struct iwl_frame *frame;
+ struct list_head *element;
+ if (list_empty(&priv->free_frames)) {
+ frame = kzalloc(sizeof(*frame), GFP_KERNEL);
+ if (!frame) {
+ IWL_ERROR("Could not allocate frame!\n");
+ return NULL;
+ }
+
+ priv->frames_count++;
+ return frame;
+ }
+
+ element = priv->free_frames.next;
+ list_del(element);
+ return list_entry(element, struct iwl_frame, list);
+}
+
+static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
+{
+ memset(frame, 0, sizeof(*frame));
+ list_add(&frame->list, &priv->free_frames);
+}
+
+unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+ struct ieee80211_hdr *hdr,
+ const u8 *dest, int left)
+{
+
+ if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
+ ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
+ (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
+ return 0;
+
+ if (priv->ibss_beacon->len > left)
+ return 0;
+
+ memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len);
+
+ return priv->ibss_beacon->len;
+}
+
+static int iwl_rate_index_from_plcp(int plcp)
+{
+ int i = 0;
+
+ for (i = 0; i < IWL_RATE_COUNT; i++)
+ if (iwl_rates[i].plcp == plcp)
+ return i;
+ return -1;
+}
+
+static u8 iwl_rate_get_lowest_plcp(int rate_mask)
+{
+ u8 i;
+
+ for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
+ i = iwl_rates[i].next_ieee) {
+ if (rate_mask & (1 << i))
+ return iwl_rates[i].plcp;
+ }
+
+ return IWL_RATE_INVALID;
+}
+
+static int iwl_send_beacon_cmd(struct iwl_priv *priv)
+{
+ struct iwl_frame *frame;
+ unsigned int frame_size;
+ int rc;
+ u8 rate;
+
+ frame = iwl_get_free_frame(priv);
+
+ if (!frame) {
+ IWL_ERROR("Could not obtain free frame buffer for beacon "
+ "command.\n");
+ return -ENOMEM;
+ }
+
+ if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
+ rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic &
+ 0xFF0);
+ if (rate == IWL_INVALID_RATE)
+ rate = IWL_RATE_6M_PLCP;
+ } else {
+ rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
+ if (rate == IWL_INVALID_RATE)
+ rate = IWL_RATE_1M_PLCP;
+ }
+
+ frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
+
+ rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
+ &frame->u.cmd[0]);
+
+ iwl_free_frame(priv, frame);
+
+ return rc;
+}
+
+/******************************************************************************
+ *
+ * EEPROM related functions
+ *
+ ******************************************************************************/
+
+static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac)
+{
+ memcpy(mac, priv->eeprom.mac_address, 6);
+}
+
+/**
+ * iwl_eeprom_init - read EEPROM contents
+ *
+ * Load the EEPROM from adapter into priv->eeprom
+ *
+ * NOTE: This routine uses the non-debug IO access functions.
+ */
+int iwl_eeprom_init(struct iwl_priv *priv)
+{
+ u16 *e = (u16 *)&priv->eeprom;
+ u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
+ u32 r;
+ int sz = sizeof(priv->eeprom);
+ int rc;
+ int i;
+ u16 addr;
+
+ /* The EEPROM structure has several padding buffers within it
+ * and when adding new EEPROM maps is subject to programmer errors
+ * which may be very difficult to identify without explicitly
+ * checking the resulting size of the eeprom map. */
+ BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
+
+ if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
+ IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
+ return -ENOENT;
+ }
+
+ rc = iwl_eeprom_aqcuire_semaphore(priv);
+ if (rc < 0) {
+ IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n");
+ return -ENOENT;
+ }
+
+ /* eeprom is an array of 16bit values */
+ for (addr = 0; addr < sz; addr += sizeof(u16)) {
+ _iwl_write32(priv, CSR_EEPROM_REG, addr << 1);
+ _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
+
+ for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
+ i += IWL_EEPROM_ACCESS_DELAY) {
+ r = _iwl_read_restricted(priv, CSR_EEPROM_REG);
+ if (r & CSR_EEPROM_REG_READ_VALID_MSK)
+ break;
+ udelay(IWL_EEPROM_ACCESS_DELAY);
+ }
+
+ if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
+ IWL_ERROR("Time out reading EEPROM[%d]", addr);
+ return -ETIMEDOUT;
+ }
+ e[addr / 2] = le16_to_cpu(r >> 16);
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * Misc. internal state and helper functions
+ *
+ ******************************************************************************/
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/**
+ * iwl_report_frame - dump frame to syslog during debug sessions
+ *
+ * hack this function to show different aspects of received frames,
+ * including selective frame dumps.
+ * group100 parameter selects whether to show 1 out of 100 good frames.
+ *
+ * TODO: ieee80211_hdr stuff is common to 3945 and 4965, so frame type
+ * info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats)
+ * is 3945-specific and gives bad output for 4965. Need to split the
+ * functionality, keep common stuff here.
+ */
+void iwl_report_frame(struct iwl_priv *priv,
+ struct iwl_rx_packet *pkt,
+ struct ieee80211_hdr *header, int group100)
+{
+ u32 to_us;
+ u32 print_summary = 0;
+ u32 print_dump = 0; /* set to 1 to dump all frames' contents */
+ u32 hundred = 0;
+ u32 dataframe = 0;
+ u16 fc;
+ u16 seq_ctl;
+ u16 channel;
+ u16 phy_flags;
+ int rate_sym;
+ u16 length;
+ u16 status;
+ u16 bcn_tmr;
+ u32 tsf_low;
+ u64 tsf;
+ u8 rssi;
+ u8 agc;
+ u16 sig_avg;
+ u16 noise_diff;
+ struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+ struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+ struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+ u8 *data = IWL_RX_DATA(pkt);
+
+ /* MAC header */
+ fc = le16_to_cpu(header->frame_control);
+ seq_ctl = le16_to_cpu(header->seq_ctrl);
+
+ /* metadata */
+ channel = le16_to_cpu(rx_hdr->channel);
+ phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+ rate_sym = rx_hdr->rate;
+ length = le16_to_cpu(rx_hdr->len);
+
+ /* end-of-frame status and timestamp */
+ status = le32_to_cpu(rx_end->status);
+ bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
+ tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
+ tsf = le64_to_cpu(rx_end->timestamp);
+
+ /* signal statistics */
+ rssi = rx_stats->rssi;
+ agc = rx_stats->agc;
+ sig_avg = le16_to_cpu(rx_stats->sig_avg);
+ noise_diff = le16_to_cpu(rx_stats->noise_diff);
+
+ to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
+
+ /* if data frame is to us and all is good,
+ * (optionally) print summary for only 1 out of every 100 */
+ if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) ==
+ (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
+ dataframe = 1;
+ if (!group100)
+ print_summary = 1; /* print each frame */
+ else if (priv->framecnt_to_us < 100) {
+ priv->framecnt_to_us++;
+ print_summary = 0;
+ } else {
+ priv->framecnt_to_us = 0;
+ print_summary = 1;
+ hundred = 1;
+ }
+ } else {
+ /* print summary for all other frames */
+ print_summary = 1;
+ }
+
+ if (print_summary) {
+ char *title;
+ u32 rate;
+
+ if (hundred)
+ title = "100Frames";
+ else if (fc & IEEE80211_FCTL_RETRY)
+ title = "Retry";
+ else if (ieee80211_is_assoc_response(fc))
+ title = "AscRsp";
+ else if (ieee80211_is_reassoc_response(fc))
+ title = "RasRsp";
+ else if (ieee80211_is_probe_response(fc)) {
+ title = "PrbRsp";
+ print_dump = 1; /* dump frame contents */
+ } else if (ieee80211_is_beacon(fc)) {
+ title = "Beacon";
+ print_dump = 1; /* dump frame contents */
+ } else if (ieee80211_is_atim(fc))
+ title = "ATIM";
+ else if (ieee80211_is_auth(fc))
+ title = "Auth";
+ else if (ieee80211_is_deauth(fc))
+ title = "DeAuth";
+ else if (ieee80211_is_disassoc(fc))
+ title = "DisAssoc";
+ else
+ title = "Frame";
+
+ rate = iwl_rate_index_from_plcp(rate_sym);
+ if (rate == -1)
+ rate = 0;
+ else
+ rate = iwl_rates[rate].ieee / 2;
+
+ /* print frame summary.
+ * MAC addresses show just the last byte (for brevity),
+ * but you can hack it to show more, if you'd like to. */
+ if (dataframe)
+ IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
+ "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
+ title, fc, header->addr1[5],
+ length, rssi, channel, rate);
+ else {
+ /* src/dst addresses assume managed mode */
+ IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
+ "src=0x%02x, rssi=%u, tim=%lu usec, "
+ "phy=0x%02x, chnl=%d\n",
+ title, fc, header->addr1[5],
+ header->addr3[5], rssi,
+ tsf_low - priv->scan_start_tsf,
+ phy_flags, channel);
+ }
+ }
+ if (print_dump)
+ iwl_print_hex_dump(IWL_DL_RX, data, length);
+}
+#endif
+
+static void iwl_unset_hw_setting(struct iwl_priv *priv)
+{
+ if (priv->hw_setting.shared_virt)
+ pci_free_consistent(priv->pci_dev,
+ sizeof(struct iwl_shared),
+ priv->hw_setting.shared_virt,
+ priv->hw_setting.shared_phys);
+}
+
+/**
+ * iwl_supported_rate_to_ie - fill in the supported rate in IE field
+ *
+ * return : set the bit for each supported rate insert in ie
+ */
+static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+ u16 basic_rate, int *left)
+{
+ u16 ret_rates = 0, bit;
+ int i;
+ u8 *cnt = ie;
+ u8 *rates = ie + 1;
+
+ for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
+ if (bit & supported_rate) {
+ ret_rates |= bit;
+ rates[*cnt] = iwl_rates[i].ieee |
+ ((bit & basic_rate) ? 0x80 : 0x00);
+ (*cnt)++;
+ (*left)--;
+ if ((*left <= 0) ||
+ (*cnt >= IWL_SUPPORTED_RATES_IE_LEN))
+ break;
+ }
+ }
+
+ return ret_rates;
+}
+
+/**
+ * iwl_fill_probe_req - fill in all required fields and IE for probe request
+ */
+static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+ struct ieee80211_mgmt *frame,
+ int left, int is_direct)
+{
+ int len = 0;
+ u8 *pos = NULL;
+ u16 active_rates, ret_rates, cck_rates;
+
+ /* Make sure there is enough space for the probe request,
+ * two mandatory IEs and the data */
+ left -= 24;
+ if (left < 0)
+ return 0;
+ len += 24;
+
+ frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+ memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN);
+ memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
+ memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN);
+ frame->seq_ctrl = 0;
+
+ /* fill in our indirect SSID IE */
+ /* ...next IE... */
+
+ left -= 2;
+ if (left < 0)
+ return 0;
+ len += 2;
+ pos = &(frame->u.probe_req.variable[0]);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = 0;
+
+ /* fill in our direct SSID IE... */
+ if (is_direct) {
+ /* ...next IE... */
+ left -= 2 + priv->essid_len;
+ if (left < 0)
+ return 0;
+ /* ... fill it in... */
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = priv->essid_len;
+ memcpy(pos, priv->essid, priv->essid_len);
+ pos += priv->essid_len;
+ len += 2 + priv->essid_len;
+ }
+
+ /* fill in supported rate */
+ /* ...next IE... */
+ left -= 2;
+ if (left < 0)
+ return 0;
+
+ /* ... fill it in... */
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos = 0;
+
+ priv->active_rate = priv->rates_mask;
+ active_rates = priv->active_rate;
+ priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+ cck_rates = IWL_CCK_RATES_MASK & active_rates;
+ ret_rates = iwl_supported_rate_to_ie(pos, cck_rates,
+ priv->active_rate_basic, &left);
+ active_rates &= ~ret_rates;
+
+ ret_rates = iwl_supported_rate_to_ie(pos, active_rates,
+ priv->active_rate_basic, &left);
+ active_rates &= ~ret_rates;
+
+ len += 2 + *pos;
+ pos += (*pos) + 1;
+ if (active_rates == 0)
+ goto fill_end;
+
+ /* fill in supported extended rate */
+ /* ...next IE... */
+ left -= 2;
+ if (left < 0)
+ return 0;
+ /* ... fill it in... */
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos = 0;
+ iwl_supported_rate_to_ie(pos, active_rates,
+ priv->active_rate_basic, &left);
+ if (*pos > 0)
+ len += 2 + *pos;
+
+ fill_end:
+ return (u16)len;
+}
+
+/*
+ * QoS support
+*/
+#ifdef CONFIG_IWLWIFI_QOS
+static int iwl_send_qos_params_command(struct iwl_priv *priv,
+ struct iwl_qosparam_cmd *qos)
+{
+
+ return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM,
+ sizeof(struct iwl_qosparam_cmd), qos);
+}
+
+static void iwl_reset_qos(struct iwl_priv *priv)
+{
+ u16 cw_min = 15;
+ u16 cw_max = 1023;
+ u8 aifs = 2;
+ u8 is_legacy = 0;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->qos_data.qos_active = 0;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
+ if (priv->qos_data.qos_enable)
+ priv->qos_data.qos_active = 1;
+ if (!(priv->active_rate & 0xfff0)) {
+ cw_min = 31;
+ is_legacy = 1;
+ }
+ } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (priv->qos_data.qos_enable)
+ priv->qos_data.qos_active = 1;
+ } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
+ cw_min = 31;
+ is_legacy = 1;
+ }
+
+ if (priv->qos_data.qos_active)
+ aifs = 3;
+
+ priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
+ priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
+ priv->qos_data.def_qos_parm.ac[0].edca_txop = 0;
+ priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
+
+ if (priv->qos_data.qos_active) {
+ i = 1;
+ priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
+ priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = 7;
+ priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+ i = 2;
+ priv->qos_data.def_qos_parm.ac[i].cw_min =
+ cpu_to_le16((cw_min + 1) / 2 - 1);
+ priv->qos_data.def_qos_parm.ac[i].cw_max =
+ cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+ if (is_legacy)
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(6016);
+ else
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(3008);
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+ i = 3;
+ priv->qos_data.def_qos_parm.ac[i].cw_min =
+ cpu_to_le16((cw_min + 1) / 4 - 1);
+ priv->qos_data.def_qos_parm.ac[i].cw_max =
+ cpu_to_le16((cw_max + 1) / 2 - 1);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+ if (is_legacy)
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(3264);
+ else
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(1504);
+ } else {
+ for (i = 1; i < 4; i++) {
+ priv->qos_data.def_qos_parm.ac[i].cw_min =
+ cpu_to_le16(cw_min);
+ priv->qos_data.def_qos_parm.ac[i].cw_max =
+ cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = aifs;
+ priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+ }
+ }
+ IWL_DEBUG_QOS("set QoS to default \n");
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+{
+ unsigned long flags;
+
+ if (priv == NULL)
+ return;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (!priv->qos_data.qos_enable)
+ return;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->qos_data.def_qos_parm.qos_flags = 0;
+
+ if (priv->qos_data.qos_cap.q_AP.queue_request &&
+ !priv->qos_data.qos_cap.q_AP.txop_request)
+ priv->qos_data.def_qos_parm.qos_flags |=
+ QOS_PARAM_FLG_TXOP_TYPE_MSK;
+
+ if (priv->qos_data.qos_active)
+ priv->qos_data.def_qos_parm.qos_flags |=
+ QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (force || iwl_is_associated(priv)) {
+ IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n",
+ priv->qos_data.qos_active);
+
+ iwl_send_qos_params_command(priv,
+ &(priv->qos_data.def_qos_parm));
+ }
+}
+
+#endif /* CONFIG_IWLWIFI_QOS */
+/*
+ * Power management (not Tx power!) functions
+ */
+#define MSEC_TO_USEC 1024
+
+#define NOSLP __constant_cpu_to_le32(0)
+#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK
+#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
+#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
+ __constant_cpu_to_le32(X1), \
+ __constant_cpu_to_le32(X2), \
+ __constant_cpu_to_le32(X3), \
+ __constant_cpu_to_le32(X4)}
+
+
+/* default power management (not Tx power) table values */
+/* for tim 0-10 */
+static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
+ {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1},
+ {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
+};
+
+/* for tim > 10 */
+static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
+ {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
+ SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300),
+ SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100),
+ SLP_VEC(2, 6, 9, 9, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25),
+ SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
+};
+
+int iwl_power_init_handle(struct iwl_priv *priv)
+{
+ int rc = 0, i;
+ struct iwl_power_mgr *pow_data;
+ int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC;
+ u16 pci_pm;
+
+ IWL_DEBUG_POWER("Initialize power \n");
+
+ pow_data = &(priv->power_data);
+
+ memset(pow_data, 0, sizeof(*pow_data));
+
+ pow_data->active_index = IWL_POWER_RANGE_0;
+ pow_data->dtim_val = 0xffff;
+
+ memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
+ memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
+
+ rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm);
+ if (rc != 0)
+ return 0;
+ else {
+ struct iwl_powertable_cmd *cmd;
+
+ IWL_DEBUG_POWER("adjust power command flags\n");
+
+ for (i = 0; i < IWL_POWER_AC; i++) {
+ cmd = &pow_data->pwr_range_0[i].cmd;
+
+ if (pci_pm & 0x1)
+ cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+ else
+ cmd->flags |= IWL_POWER_PCI_PM_MSK;
+ }
+ }
+ return rc;
+}
+
+static int iwl_update_power_cmd(struct iwl_priv *priv,
+ struct iwl_powertable_cmd *cmd, u32 mode)
+{
+ int rc = 0, i;
+ u8 skip;
+ u32 max_sleep = 0;
+ struct iwl_power_vec_entry *range;
+ u8 period = 0;
+ struct iwl_power_mgr *pow_data;
+
+ if (mode > IWL_POWER_INDEX_5) {
+ IWL_DEBUG_POWER("Error invalid power mode \n");
+ return -1;
+ }
+ pow_data = &(priv->power_data);
+
+ if (pow_data->active_index == IWL_POWER_RANGE_0)
+ range = &pow_data->pwr_range_0[0];
+ else
+ range = &pow_data->pwr_range_1[1];
+
+ memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd));
+
+#ifdef IWL_MAC80211_DISABLE
+ if (priv->assoc_network != NULL) {
+ unsigned long flags;
+
+ period = priv->assoc_network->tim.tim_period;
+ }
+#endif /*IWL_MAC80211_DISABLE */
+ skip = range[mode].no_dtim;
+
+ if (period == 0) {
+ period = 1;
+ skip = 0;
+ }
+
+ if (skip == 0) {
+ max_sleep = period;
+ cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
+ } else {
+ __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
+ max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
+ cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
+ }
+
+ for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
+ if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
+ cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
+ }
+
+ IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
+ IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
+ IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
+ IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
+ le32_to_cpu(cmd->sleep_interval[0]),
+ le32_to_cpu(cmd->sleep_interval[1]),
+ le32_to_cpu(cmd->sleep_interval[2]),
+ le32_to_cpu(cmd->sleep_interval[3]),
+ le32_to_cpu(cmd->sleep_interval[4]));
+
+ return rc;
+}
+
+static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
+{
+ u32 final_mode = mode;
+ int rc;
+ struct iwl_powertable_cmd cmd;
+
+ /* If on battery, set to 3,
+ * if plugged into AC power, set to CAM ("continuosly aware mode"),
+ * else user level */
+ switch (mode) {
+ case IWL_POWER_BATTERY:
+ final_mode = IWL_POWER_INDEX_3;
+ break;
+ case IWL_POWER_AC:
+ final_mode = IWL_POWER_MODE_CAM;
+ break;
+ default:
+ final_mode = mode;
+ break;
+ }
+
+ iwl_update_power_cmd(priv, &cmd, final_mode);
+
+ rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
+
+ if (final_mode == IWL_POWER_MODE_CAM)
+ clear_bit(STATUS_POWER_PMI, &priv->status);
+ else
+ set_bit(STATUS_POWER_PMI, &priv->status);
+
+ return rc;
+}
+
+int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+{
+ /* Filter incoming packets to determine if they are targeted toward
+ * this network, discarding packets coming from ourselves */
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */
+ /* packets from our adapter are dropped (echo) */
+ if (!compare_ether_addr(header->addr2, priv->mac_addr))
+ return 0;
+ /* {broad,multi}cast packets to our IBSS go through */
+ if (is_multicast_ether_addr(header->addr1))
+ return !compare_ether_addr(header->addr3, priv->bssid);
+ /* packets to our adapter go through */
+ return !compare_ether_addr(header->addr1, priv->mac_addr);
+ case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+ /* packets from our adapter are dropped (echo) */
+ if (!compare_ether_addr(header->addr3, priv->mac_addr))
+ return 0;
+ /* {broad,multi}cast packets to our BSS go through */
+ if (is_multicast_ether_addr(header->addr1))
+ return !compare_ether_addr(header->addr2, priv->bssid);
+ /* packets to our adapter go through */
+ return !compare_ether_addr(header->addr1, priv->mac_addr);
+ }
+
+ return 1;
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+const char *iwl_get_tx_fail_reason(u32 status)
+{
+ switch (status & TX_STATUS_MSK) {
+ case TX_STATUS_SUCCESS:
+ return "SUCCESS";
+ TX_STATUS_ENTRY(SHORT_LIMIT);
+ TX_STATUS_ENTRY(LONG_LIMIT);
+ TX_STATUS_ENTRY(FIFO_UNDERRUN);
+ TX_STATUS_ENTRY(MGMNT_ABORT);
+ TX_STATUS_ENTRY(NEXT_FRAG);
+ TX_STATUS_ENTRY(LIFE_EXPIRE);
+ TX_STATUS_ENTRY(DEST_PS);
+ TX_STATUS_ENTRY(ABORTED);
+ TX_STATUS_ENTRY(BT_RETRY);
+ TX_STATUS_ENTRY(STA_INVALID);
+ TX_STATUS_ENTRY(FRAG_DROPPED);
+ TX_STATUS_ENTRY(TID_DISABLE);
+ TX_STATUS_ENTRY(FRAME_FLUSHED);
+ TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
+ TX_STATUS_ENTRY(TX_LOCKED);
+ TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
+ }
+
+ return "UNKNOWN";
+}
+
+/**
+ * iwl_scan_cancel - Cancel any currently executing HW scan
+ *
+ * NOTE: priv->mutex is not required before calling this function
+ */
+static int iwl_scan_cancel(struct iwl_priv *priv)
+{
+ if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+ clear_bit(STATUS_SCANNING, &priv->status);
+ return 0;
+ }
+
+ if (test_bit(STATUS_SCANNING, &priv->status)) {
+ if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_SCAN("Queuing scan abort.\n");
+ set_bit(STATUS_SCAN_ABORTING, &priv->status);
+ queue_work(priv->workqueue, &priv->abort_scan);
+
+ } else
+ IWL_DEBUG_SCAN("Scan abort already in progress.\n");
+
+ return test_bit(STATUS_SCANNING, &priv->status);
+ }
+
+ return 0;
+}
+
+/**
+ * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
+ * @ms: amount of time to wait (in milliseconds) for scan to abort
+ *
+ * NOTE: priv->mutex must be held before calling this function
+ */
+static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+{
+ unsigned long now = jiffies;
+ int ret;
+
+ ret = iwl_scan_cancel(priv);
+ if (ret && ms) {
+ mutex_unlock(&priv->mutex);
+ while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
+ test_bit(STATUS_SCANNING, &priv->status))
+ msleep(1);
+ mutex_lock(&priv->mutex);
+
+ return test_bit(STATUS_SCANNING, &priv->status);
+ }
+
+ return ret;
+}
+
+static void iwl_sequence_reset(struct iwl_priv *priv)
+{
+ /* Reset ieee stats */
+
+ /* We don't reset the net_device_stats (ieee->stats) on
+ * re-association */
+
+ priv->last_seq_num = -1;
+ priv->last_frag_num = -1;
+ priv->last_packet_time = 0;
+
+ iwl_scan_cancel(priv);
+}
+
+#define MAX_UCODE_BEACON_INTERVAL 1024
+#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA)
+
+static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
+{
+ u16 new_val = 0;
+ u16 beacon_factor = 0;
+
+ beacon_factor =
+ (beacon_val + MAX_UCODE_BEACON_INTERVAL)
+ / MAX_UCODE_BEACON_INTERVAL;
+ new_val = beacon_val / beacon_factor;
+
+ return cpu_to_le16(new_val);
+}
+
+static void iwl_setup_rxon_timing(struct iwl_priv *priv)
+{
+ u64 interval_tm_unit;
+ u64 tsf, result;
+ unsigned long flags;
+ struct ieee80211_conf *conf = NULL;
+ u16 beacon_int = 0;
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp1);
+ priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0);
+
+ priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
+
+ tsf = priv->timestamp1;
+ tsf = ((tsf << 32) | priv->timestamp0);
+
+ beacon_int = priv->beacon_int;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+ if (beacon_int == 0) {
+ priv->rxon_timing.beacon_interval = cpu_to_le16(100);
+ priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
+ } else {
+ priv->rxon_timing.beacon_interval =
+ cpu_to_le16(beacon_int);
+ priv->rxon_timing.beacon_interval =
+ iwl_adjust_beacon_interval(
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+ }
+
+ priv->rxon_timing.atim_window = 0;
+ } else {
+ priv->rxon_timing.beacon_interval =
+ iwl_adjust_beacon_interval(conf->beacon_int);
+ /* TODO: we need to get atim_window from upper stack
+ * for now we set to 0 */
+ priv->rxon_timing.atim_window = 0;
+ }
+
+ interval_tm_unit =
+ (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
+ result = do_div(tsf, interval_tm_unit);
+ priv->rxon_timing.beacon_init_val =
+ cpu_to_le32((u32) ((u64) interval_tm_unit - result));
+
+ IWL_DEBUG_ASSOC
+ ("beacon interval %d beacon timer %d beacon tim %d\n",
+ le16_to_cpu(priv->rxon_timing.beacon_interval),
+ le32_to_cpu(priv->rxon_timing.beacon_init_val),
+ le16_to_cpu(priv->rxon_timing.atim_window));
+}
+
+static int iwl_scan_initiate(struct iwl_priv *priv)
+{
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ IWL_ERROR("APs don't scan.\n");
+ return 0;
+ }
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
+ return -EIO;
+ }
+
+ if (test_bit(STATUS_SCANNING, &priv->status)) {
+ IWL_DEBUG_SCAN("Scan already in progress.\n");
+ return -EAGAIN;
+ }
+
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_SCAN("Scan request while abort pending. "
+ "Queuing.\n");
+ return -EAGAIN;
+ }
+
+ IWL_DEBUG_INFO("Starting scan...\n");
+ priv->scan_bands = 2;
+ set_bit(STATUS_SCANNING, &priv->status);
+ priv->scan_start = jiffies;
+ priv->scan_pass_start = priv->scan_start;
+
+ queue_work(priv->workqueue, &priv->request_scan);
+
+ return 0;
+}
+
+static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+{
+ struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+
+ if (hw_decrypt)
+ rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
+ else
+ rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
+
+ return 0;
+}
+
+static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
+{
+ if (phymode == MODE_IEEE80211A) {
+ priv->staging_rxon.flags &=
+ ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
+ | RXON_FLG_CCK_MSK);
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ } else {
+ /* Copied from iwl_bg_post_associate() */
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+ priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
+ priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
+ }
+}
+
+/*
+ * initilize rxon structure with default values fromm eeprom
+ */
+static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+{
+ const struct iwl_channel_info *ch_info;
+
+ memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
+
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_AP:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
+ break;
+
+ case IEEE80211_IF_TYPE_STA:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
+ priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
+ break;
+
+ case IEEE80211_IF_TYPE_IBSS:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
+ priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
+ priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
+ RXON_FILTER_ACCEPT_GRP_MSK;
+ break;
+
+ case IEEE80211_IF_TYPE_MNTR:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
+ priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
+ RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
+ break;
+ }
+
+#if 0
+ /* TODO: Figure out when short_preamble would be set and cache from
+ * that */
+ if (!hw_to_local(priv->hw)->short_preamble)
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+#endif
+
+ ch_info = iwl_get_channel_info(priv, priv->phymode,
+ le16_to_cpu(priv->staging_rxon.channel));
+
+ if (!ch_info)
+ ch_info = &priv->channel_info[0];
+
+ /*
+ * in some case A channels are all non IBSS
+ * in this case force B/G channel
+ */
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ !(is_channel_ibss(ch_info)))
+ ch_info = &priv->channel_info[0];
+
+ priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
+ if (is_channel_a_band(ch_info))
+ priv->phymode = MODE_IEEE80211A;
+ else
+ priv->phymode = MODE_IEEE80211G;
+
+ iwl_set_flags_for_phymode(priv, priv->phymode);
+
+ priv->staging_rxon.ofdm_basic_rates =
+ (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+ priv->staging_rxon.cck_basic_rates =
+ (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+}
+
+static int iwl_set_mode(struct iwl_priv *priv, int mode)
+{
+ if (!iwl_is_ready_rf(priv))
+ return -EAGAIN;
+
+ if (mode == IEEE80211_IF_TYPE_IBSS) {
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv,
+ priv->phymode,
+ le16_to_cpu(priv->staging_rxon.channel));
+
+ if (!ch_info || !is_channel_ibss(ch_info)) {
+ IWL_ERROR("channel %d not IBSS channel\n",
+ le16_to_cpu(priv->staging_rxon.channel));
+ return -EINVAL;
+ }
+ }
+
+ cancel_delayed_work(&priv->scan_check);
+ if (iwl_scan_cancel_timeout(priv, 100)) {
+ IWL_WARNING("Aborted scan still in progress after 100ms\n");
+ IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+ return -EAGAIN;
+ }
+
+ priv->iw_mode = mode;
+
+ iwl_connection_init_rx_config(priv);
+ memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+
+ iwl_clear_stations_table(priv);
+
+ iwl_commit_rxon(priv);
+
+ return 0;
+}
+
+static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
+ struct ieee80211_tx_control *ctl,
+ struct iwl_cmd *cmd,
+ struct sk_buff *skb_frag,
+ int last_frag)
+{
+ struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+
+ switch (keyinfo->alg) {
+ case ALG_CCMP:
+ cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM;
+ memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen);
+ IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
+ break;
+
+ case ALG_TKIP:
+#if 0
+ cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP;
+
+ if (last_frag)
+ memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8,
+ 8);
+ else
+ memset(cmd->cmd.tx.tkip_mic.byte, 0, 8);
+#endif
+ break;
+
+ case ALG_WEP:
+ cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
+ (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
+
+ if (keyinfo->keylen == 13)
+ cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
+
+ memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
+
+ IWL_DEBUG_TX("Configuring packet for WEP encryption "
+ "with key %d\n", ctl->key_idx);
+ break;
+
+ default:
+ printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg);
+ break;
+ }
+}
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct ieee80211_tx_control *ctrl,
+ struct ieee80211_hdr *hdr,
+ int is_unicast, u8 std_id)
+{
+ __le16 *qc;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ __le32 tx_flags = cmd->cmd.tx.tx_flags;
+
+ cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+ if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
+ tx_flags |= TX_CMD_FLG_ACK_MSK;
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ if (ieee80211_is_probe_response(fc) &&
+ !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
+ tx_flags |= TX_CMD_FLG_TSF_MSK;
+ } else {
+ tx_flags &= (~TX_CMD_FLG_ACK_MSK);
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ }
+
+ cmd->cmd.tx.sta_id = std_id;
+ if (ieee80211_get_morefrag(hdr))
+ tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+
+ qc = ieee80211_get_qos_ctrl(hdr);
+ if (qc) {
+ cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf);
+ tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+ } else
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+
+ if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+ tx_flags |= TX_CMD_FLG_RTS_MSK;
+ tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+ } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+
+ if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
+ tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+ tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+ if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
+ (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
+ cmd->cmd.tx.timeout.pm_frame_timeout =
+ cpu_to_le16(3);
+ else
+ cmd->cmd.tx.timeout.pm_frame_timeout =
+ cpu_to_le16(2);
+ } else
+ cmd->cmd.tx.timeout.pm_frame_timeout = 0;
+
+ cmd->cmd.tx.driver_txop = 0;
+ cmd->cmd.tx.tx_flags = tx_flags;
+ cmd->cmd.tx.next_frame_len = 0;
+}
+
+static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+{
+ int sta_id;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+
+ /* If this frame is broadcast or not data then use the broadcast
+ * station id */
+ if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
+ is_multicast_ether_addr(hdr->addr1))
+ return priv->hw_setting.bcast_sta_id;
+
+ switch (priv->iw_mode) {
+
+ /* If this frame is part of a BSS network (we're a station), then
+ * we use the AP's station id */
+ case IEEE80211_IF_TYPE_STA:
+ return IWL_AP_ID;
+
+ /* If we are an AP, then find the station, or use BCAST */
+ case IEEE80211_IF_TYPE_AP:
+ sta_id = iwl_hw_find_station(priv, hdr->addr1);
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+ return priv->hw_setting.bcast_sta_id;
+
+ /* If this frame is part of a IBSS network, then we use the
+ * target specific station id */
+ case IEEE80211_IF_TYPE_IBSS: {
+ DECLARE_MAC_BUF(mac);
+
+ sta_id = iwl_hw_find_station(priv, hdr->addr1);
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+
+ sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC);
+
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+
+ IWL_DEBUG_DROP("Station %s not in station map. "
+ "Defaulting to broadcast...\n",
+ print_mac(mac, hdr->addr1));
+ iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+ return priv->hw_setting.bcast_sta_id;
+ }
+ default:
+ IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode);
+ return priv->hw_setting.bcast_sta_id;
+ }
+}
+
+/*
+ * start REPLY_TX command process
+ */
+static int iwl_tx_skb(struct iwl_priv *priv,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct iwl_tfd_frame *tfd;
+ u32 *control_flags;
+ int txq_id = ctl->queue;
+ struct iwl_tx_queue *txq = NULL;
+ struct iwl_queue *q = NULL;
+ dma_addr_t phys_addr;
+ dma_addr_t txcmd_phys;
+ struct iwl_cmd *out_cmd = NULL;
+ u16 len, idx, len_org;
+ u8 id, hdr_len, unicast;
+ u8 sta_id;
+ u16 seq_number = 0;
+ u16 fc;
+ __le16 *qc;
+ u8 wait_write_ptr = 0;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_DROP("Dropping - RF KILL\n");
+ goto drop_unlock;
+ }
+
+ if (!priv->interface_id) {
+ IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
+ goto drop_unlock;
+ }
+
+ if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) {
+ IWL_ERROR("ERROR: No TX rate available.\n");
+ goto drop_unlock;
+ }
+
+ unicast = !is_multicast_ether_addr(hdr->addr1);
+ id = 0;
+
+ fc = le16_to_cpu(hdr->frame_control);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (ieee80211_is_auth(fc))
+ IWL_DEBUG_TX("Sending AUTH frame\n");
+ else if (ieee80211_is_assoc_request(fc))
+ IWL_DEBUG_TX("Sending ASSOC frame\n");
+ else if (ieee80211_is_reassoc_request(fc))
+ IWL_DEBUG_TX("Sending REASSOC frame\n");
+#endif
+
+ if (!iwl_is_associated(priv) &&
+ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+ IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
+ goto drop_unlock;
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ hdr_len = ieee80211_get_hdrlen(fc);
+ sta_id = iwl_get_sta_id(priv, hdr);
+ if (sta_id == IWL_INVALID_STATION) {
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
+ print_mac(mac, hdr->addr1));
+ goto drop;
+ }
+
+ IWL_DEBUG_RATE("station Id %d\n", sta_id);
+
+ qc = ieee80211_get_qos_ctrl(hdr);
+ if (qc) {
+ u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+ seq_number = priv->stations[sta_id].tid[tid].seq_number &
+ IEEE80211_SCTL_SEQ;
+ hdr->seq_ctrl = cpu_to_le16(seq_number) |
+ (hdr->seq_ctrl &
+ __constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
+ seq_number += 0x10;
+ }
+ txq = &priv->txq[txq_id];
+ q = &txq->q;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ tfd = &txq->bd[q->first_empty];
+ memset(tfd, 0, sizeof(*tfd));
+ control_flags = (u32 *) tfd;
+ idx = get_cmd_index(q, q->first_empty, 0);
+
+ memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info));
+ txq->txb[q->first_empty].skb[0] = skb;
+ memcpy(&(txq->txb[q->first_empty].status.control),
+ ctl, sizeof(struct ieee80211_tx_control));
+ out_cmd = &txq->cmd[idx];
+ memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
+ memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
+ out_cmd->hdr.cmd = REPLY_TX;
+ out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+ INDEX_TO_SEQ(q->first_empty)));
+ /* copy frags header */
+ memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
+
+ /* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */
+ len = priv->hw_setting.tx_cmd_len +
+ sizeof(struct iwl_cmd_header) + hdr_len;
+
+ len_org = len;
+ len = (len + 3) & ~3;
+
+ if (len_org != len)
+ len_org = 1;
+ else
+ len_org = 0;
+
+ txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
+ offsetof(struct iwl_cmd, hdr);
+
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
+
+ if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+ iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+
+ /* 802.11 null functions have no payload... */
+ len = skb->len - hdr_len;
+ if (len) {
+ phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
+ len, PCI_DMA_TODEVICE);
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
+ }
+
+ /* If there is no payload, then only one TFD is used */
+ if (!len)
+ *control_flags = TFD_CTL_COUNT_SET(1);
+ else
+ *control_flags = TFD_CTL_COUNT_SET(2) |
+ TFD_CTL_PAD_SET(U32_PAD(len));
+
+ len = (u16)skb->len;
+ out_cmd->cmd.tx.len = cpu_to_le16(len);
+
+ /* TODO need this for burst mode later on */
+ iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
+
+ /* set is_hcca to 0; it probably will never be implemented */
+ iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+
+ out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
+ out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
+
+ if (!ieee80211_get_morefrag(hdr)) {
+ txq->need_update = 1;
+ if (qc) {
+ u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+ priv->stations[sta_id].tid[tid].seq_number = seq_number;
+ }
+ } else {
+ wait_write_ptr = 1;
+ txq->need_update = 0;
+ }
+
+ iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
+ sizeof(out_cmd->cmd.tx));
+
+ iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
+ ieee80211_get_hdrlen(fc));
+
+ q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
+ rc = iwl_tx_queue_update_write_ptr(priv, txq);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (rc)
+ return rc;
+
+ if ((iwl_queue_space(q) < q->high_mark)
+ && priv->mac80211_registered) {
+ if (wait_write_ptr) {
+ spin_lock_irqsave(&priv->lock, flags);
+ txq->need_update = 1;
+ iwl_tx_queue_update_write_ptr(priv, txq);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ ieee80211_stop_queue(priv->hw, ctl->queue);
+ }
+
+ return 0;
+
+drop_unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+drop:
+ return -1;
+}
+
+static void iwl_set_rate(struct iwl_priv *priv)
+{
+ const struct ieee80211_hw_mode *hw = NULL;
+ struct ieee80211_rate *rate;
+ int i;
+
+ hw = iwl_get_hw_mode(priv, priv->phymode);
+
+ priv->active_rate = 0;
+ priv->active_rate_basic = 0;
+
+ IWL_DEBUG_RATE("Setting rates for 802.11%c\n",
+ hw->mode == MODE_IEEE80211A ?
+ 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g'));
+
+ for (i = 0; i < hw->num_rates; i++) {
+ rate = &(hw->rates[i]);
+ if ((rate->val < IWL_RATE_COUNT) &&
+ (rate->flags & IEEE80211_RATE_SUPPORTED)) {
+ IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
+ rate->val, iwl_rates[rate->val].plcp,
+ (rate->flags & IEEE80211_RATE_BASIC) ?
+ "*" : "");
+ priv->active_rate |= (1 << rate->val);
+ if (rate->flags & IEEE80211_RATE_BASIC)
+ priv->active_rate_basic |= (1 << rate->val);
+ } else
+ IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
+ rate->val, iwl_rates[rate->val].plcp);
+ }
+
+ IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
+ priv->active_rate, priv->active_rate_basic);
+
+ /*
+ * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK)
+ * otherwise set it to the default of all CCK rates and 6, 12, 24 for
+ * OFDM
+ */
+ if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK)
+ priv->staging_rxon.cck_basic_rates =
+ ((priv->active_rate_basic &
+ IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF;
+ else
+ priv->staging_rxon.cck_basic_rates =
+ (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+
+ if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK)
+ priv->staging_rxon.ofdm_basic_rates =
+ ((priv->active_rate_basic &
+ (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >>
+ IWL_FIRST_OFDM_RATE) & 0xFF;
+ else
+ priv->staging_rxon.ofdm_basic_rates =
+ (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+}
+
+static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+{
+ unsigned long flags;
+
+ if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status))
+ return;
+
+ IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n",
+ disable_radio ? "OFF" : "ON");
+
+ if (disable_radio) {
+ iwl_scan_cancel(priv);
+ /* FIXME: This is a workaround for AP */
+ if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ CSR_UCODE_SW_BIT_RFKILL);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ }
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ clear_bit(STATUS_RF_KILL_SW, &priv->status);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* wake up ucode */
+ msleep(10);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_read32(priv, CSR_UCODE_DRV_GP1);
+ if (!iwl_grab_restricted_access(priv))
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+ IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+ "disabled by HW switch\n");
+ return;
+ }
+
+ queue_work(priv->workqueue, &priv->restart);
+ return;
+}
+
+void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
+ u32 decrypt_res, struct ieee80211_rx_status *stats)
+{
+ u16 fc =
+ le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control);
+
+ if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
+ return;
+
+ if (!(fc & IEEE80211_FCTL_PROTECTED))
+ return;
+
+ IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
+ switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
+ case RX_RES_STATUS_SEC_TYPE_TKIP:
+ if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+ RX_RES_STATUS_BAD_ICV_MIC)
+ stats->flag |= RX_FLAG_MMIC_ERROR;
+ case RX_RES_STATUS_SEC_TYPE_WEP:
+ case RX_RES_STATUS_SEC_TYPE_CCMP:
+ if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+ RX_RES_STATUS_DECRYPT_OK) {
+ IWL_DEBUG_RX("hw decrypt successfully!!!\n");
+ stats->flag |= RX_FLAG_DECRYPTED;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void iwl_handle_data_packet_monitor(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ void *data, short len,
+ struct ieee80211_rx_status *stats,
+ u16 phy_flags)
+{
+ struct iwl_rt_rx_hdr *iwl_rt;
+
+ /* First cache any information we need before we overwrite
+ * the information provided in the skb from the hardware */
+ s8 signal = stats->ssi;
+ s8 noise = 0;
+ int rate = stats->rate;
+ u64 tsf = stats->mactime;
+ __le16 phy_flags_hw = cpu_to_le16(phy_flags);
+
+ /* We received data from the HW, so stop the watchdog */
+ if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) {
+ IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
+ return;
+ }
+
+ /* copy the frame data to write after where the radiotap header goes */
+ iwl_rt = (void *)rxb->skb->data;
+ memmove(iwl_rt->payload, data, len);
+
+ iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+ iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */
+
+ /* total header + data */
+ iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt));
+
+ /* Set the size of the skb to the size of the frame */
+ skb_put(rxb->skb, sizeof(*iwl_rt) + len);
+
+ /* Big bitfield of all the fields we provide in radiotap */
+ iwl_rt->rt_hdr.it_present =
+ cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
+ (1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
+ (1 << IEEE80211_RADIOTAP_ANTENNA));
+
+ /* Zero the flags, we'll add to them as we go */
+ iwl_rt->rt_flags = 0;
+
+ iwl_rt->rt_tsf = cpu_to_le64(tsf);
+
+ /* Convert to dBm */
+ iwl_rt->rt_dbmsignal = signal;
+ iwl_rt->rt_dbmnoise = noise;
+
+ /* Convert the channel frequency and set the flags */
+ iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq);
+ if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
+ iwl_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
+ else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
+ iwl_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
+ else /* 802.11g */
+ iwl_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
+
+ rate = iwl_rate_index_from_plcp(rate);
+ if (rate == -1)
+ iwl_rt->rt_rate = 0;
+ else
+ iwl_rt->rt_rate = iwl_rates[rate].ieee;
+
+ /* antenna number */
+ iwl_rt->rt_antenna =
+ le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+
+ /* set the preamble flag if we have it */
+ if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+ iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+ IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
+
+ stats->flag |= RX_FLAG_RADIOTAP;
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ rxb->skb = NULL;
+}
+
+
+#define IWL_PACKET_RETRY_TIME HZ
+
+int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+{
+ u16 sc = le16_to_cpu(header->seq_ctrl);
+ u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
+ u16 frag = sc & IEEE80211_SCTL_FRAG;
+ u16 *last_seq, *last_frag;
+ unsigned long *last_time;
+
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_IBSS:{
+ struct list_head *p;
+ struct iwl_ibss_seq *entry = NULL;
+ u8 *mac = header->addr2;
+ int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
+
+ __list_for_each(p, &priv->ibss_mac_hash[index]) {
+ entry =
+ list_entry(p, struct iwl_ibss_seq, list);
+ if (!compare_ether_addr(entry->mac, mac))
+ break;
+ }
+ if (p == &priv->ibss_mac_hash[index]) {
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry) {
+ IWL_ERROR
+ ("Cannot malloc new mac entry\n");
+ return 0;
+ }
+ memcpy(entry->mac, mac, ETH_ALEN);
+ entry->seq_num = seq;
+ entry->frag_num = frag;
+ entry->packet_time = jiffies;
+ list_add(&entry->list,
+ &priv->ibss_mac_hash[index]);
+ return 0;
+ }
+ last_seq = &entry->seq_num;
+ last_frag = &entry->frag_num;
+ last_time = &entry->packet_time;
+ break;
+ }
+ case IEEE80211_IF_TYPE_STA:
+ last_seq = &priv->last_seq_num;
+ last_frag = &priv->last_frag_num;
+ last_time = &priv->last_packet_time;
+ break;
+ default:
+ return 0;
+ }
+ if ((*last_seq == seq) &&
+ time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) {
+ if (*last_frag == frag)
+ goto drop;
+ if (*last_frag + 1 != frag)
+ /* out-of-order fragment */
+ goto drop;
+ } else
+ *last_seq = seq;
+
+ *last_frag = frag;
+ *last_time = jiffies;
+ return 0;
+
+ drop:
+ return 1;
+}
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+#include "iwl-spectrum.h"
+
+#define BEACON_TIME_MASK_LOW 0x00FFFFFF
+#define BEACON_TIME_MASK_HIGH 0xFF000000
+#define TIME_UNIT 1024
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in 8:24 format
+ * the high 1 byte is the beacon counts
+ * the lower 3 bytes is the time in usec within one beacon interval
+ */
+
+static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
+{
+ u32 quot;
+ u32 rem;
+ u32 interval = beacon_interval * 1024;
+
+ if (!interval || !usec)
+ return 0;
+
+ quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
+ rem = (usec % interval) & BEACON_TIME_MASK_LOW;
+
+ return (quot << 24) + rem;
+}
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+
+static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+{
+ u32 base_low = base & BEACON_TIME_MASK_LOW;
+ u32 addon_low = addon & BEACON_TIME_MASK_LOW;
+ u32 interval = beacon_interval * TIME_UNIT;
+ u32 res = (base & BEACON_TIME_MASK_HIGH) +
+ (addon & BEACON_TIME_MASK_HIGH);
+
+ if (base_low > addon_low)
+ res += base_low - addon_low;
+ else if (base_low < addon_low) {
+ res += interval + base_low - addon_low;
+ res += (1 << 24);
+ } else
+ res += (1 << 24);
+
+ return cpu_to_le32(res);
+}
+
+static int iwl_get_measurement(struct iwl_priv *priv,
+ struct ieee80211_measurement_params *params,
+ u8 type)
+{
+ struct iwl_spectrum_cmd spectrum;
+ struct iwl_rx_packet *res;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SPECTRUM_MEASUREMENT_CMD,
+ .data = (void *)&spectrum,
+ .meta.flags = CMD_WANT_SKB,
+ };
+ u32 add_time = le64_to_cpu(params->start_time);
+ int rc;
+ int spectrum_resp_status;
+ int duration = le16_to_cpu(params->duration);
+
+ if (iwl_is_associated(priv))
+ add_time =
+ iwl_usecs_to_beacons(
+ le64_to_cpu(params->start_time) - priv->last_tsf,
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+
+ memset(&spectrum, 0, sizeof(spectrum));
+
+ spectrum.channel_count = cpu_to_le16(1);
+ spectrum.flags =
+ RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
+ spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
+ cmd.len = sizeof(spectrum);
+ spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
+
+ if (iwl_is_associated(priv))
+ spectrum.start_time =
+ iwl_add_beacon_time(priv->last_beacon_time,
+ add_time,
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+ else
+ spectrum.start_time = 0;
+
+ spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
+ spectrum.channels[0].channel = params->channel;
+ spectrum.channels[0].type = type;
+ if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+ spectrum.flags |= RXON_FLG_BAND_24G_MSK |
+ RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
+ rc = -EIO;
+ }
+
+ spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
+ switch (spectrum_resp_status) {
+ case 0: /* Command will be handled */
+ if (res->u.spectrum.id != 0xff) {
+ IWL_DEBUG_INFO
+ ("Replaced existing measurement: %d\n",
+ res->u.spectrum.id);
+ priv->measurement_status &= ~MEASUREMENT_READY;
+ }
+ priv->measurement_status |= MEASUREMENT_ACTIVE;
+ rc = 0;
+ break;
+
+ case 1: /* Command will not be handled */
+ rc = -EAGAIN;
+ break;
+ }
+
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+#endif
+
+static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
+ struct iwl_tx_info *tx_sta)
+{
+
+ tx_sta->status.ack_signal = 0;
+ tx_sta->status.excessive_retries = 0;
+ tx_sta->status.queue_length = 0;
+ tx_sta->status.queue_number = 0;
+
+ if (in_interrupt())
+ ieee80211_tx_status_irqsafe(priv->hw,
+ tx_sta->skb[0], &(tx_sta->status));
+ else
+ ieee80211_tx_status(priv->hw,
+ tx_sta->skb[0], &(tx_sta->status));
+
+ tx_sta->skb[0] = NULL;
+}
+
+/**
+ * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC.
+ *
+ * When FW advances 'R' index, all entries between old and
+ * new 'R' index need to be reclaimed. As result, some free space
+ * forms. If there is enough free space (> low mark), wake Tx queue.
+ */
+int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+{
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct iwl_queue *q = &txq->q;
+ int nfreed = 0;
+
+ if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
+ "is out of range [0-%d] %d %d.\n", txq_id,
+ index, q->n_bd, q->first_empty, q->last_used);
+ return 0;
+ }
+
+ for (index = iwl_queue_inc_wrap(index, q->n_bd);
+ q->last_used != index;
+ q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) {
+ if (txq_id != IWL_CMD_QUEUE_NUM) {
+ iwl_txstatus_to_ieee(priv,
+ &(txq->txb[txq->q.last_used]));
+ iwl_hw_txq_free_tfd(priv, txq);
+ } else if (nfreed > 1) {
+ IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
+ q->first_empty, q->last_used);
+ queue_work(priv->workqueue, &priv->restart);
+ }
+ nfreed++;
+ }
+
+ if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
+ (txq_id != IWL_CMD_QUEUE_NUM) &&
+ priv->mac80211_registered)
+ ieee80211_wake_queue(priv->hw, txq_id);
+
+
+ return nfreed;
+}
+
+static int iwl_is_tx_success(u32 status)
+{
+ return (status & 0xFF) == 0x1;
+}
+
+/******************************************************************************
+ *
+ * Generic RX handler implementations
+ *
+ ******************************************************************************/
+static void iwl_rx_reply_tx(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ int index = SEQ_TO_INDEX(sequence);
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct ieee80211_tx_status *tx_status;
+ struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+ u32 status = le32_to_cpu(tx_resp->status);
+
+ if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+ "is out of range [0-%d] %d %d\n", txq_id,
+ index, txq->q.n_bd, txq->q.first_empty,
+ txq->q.last_used);
+ return;
+ }
+
+ tx_status = &(txq->txb[txq->q.last_used].status);
+
+ tx_status->retry_count = tx_resp->failure_frame;
+ tx_status->queue_number = status;
+ tx_status->queue_length = tx_resp->bt_kill_count;
+ tx_status->queue_length |= tx_resp->failure_rts;
+
+ tx_status->flags =
+ iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
+
+ tx_status->control.tx_rate = iwl_rate_index_from_plcp(tx_resp->rate);
+
+ IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
+ txq_id, iwl_get_tx_fail_reason(status), status,
+ tx_resp->rate, tx_resp->failure_frame);
+
+ IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+ if (index != -1)
+ iwl_tx_queue_reclaim(priv, txq_id, index);
+
+ if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+ IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
+}
+
+
+static void iwl_rx_reply_alive(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_alive_resp *palive;
+ struct delayed_work *pwork;
+
+ palive = &pkt->u.alive_frame;
+
+ IWL_DEBUG_INFO("Alive ucode status 0x%08X revision "
+ "0x%01X 0x%01X\n",
+ palive->is_valid, palive->ver_type,
+ palive->ver_subtype);
+
+ if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
+ IWL_DEBUG_INFO("Initialization Alive received.\n");
+ memcpy(&priv->card_alive_init,
+ &pkt->u.alive_frame,
+ sizeof(struct iwl_init_alive_resp));
+ pwork = &priv->init_alive_start;
+ } else {
+ IWL_DEBUG_INFO("Runtime Alive received.\n");
+ memcpy(&priv->card_alive, &pkt->u.alive_frame,
+ sizeof(struct iwl_alive_resp));
+ pwork = &priv->alive_start;
+ iwl_disable_events(priv);
+ }
+
+ /* We delay the ALIVE response by 5ms to
+ * give the HW RF Kill time to activate... */
+ if (palive->is_valid == UCODE_VALID_OK)
+ queue_delayed_work(priv->workqueue, pwork,
+ msecs_to_jiffies(5));
+ else
+ IWL_WARNING("uCode did not respond OK.\n");
+}
+
+static void iwl_rx_reply_add_sta(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+
+ IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
+ return;
+}
+
+static void iwl_rx_reply_error(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+
+ IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
+ "seq 0x%04X ser 0x%08X\n",
+ le32_to_cpu(pkt->u.err_resp.error_type),
+ get_cmd_string(pkt->u.err_resp.cmd_id),
+ pkt->u.err_resp.cmd_id,
+ le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
+ le32_to_cpu(pkt->u.err_resp.error_info));
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
+ struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
+ IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
+ le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
+ rxon->channel = csa->channel;
+ priv->staging_rxon.channel = csa->channel;
+}
+
+static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
+
+ if (!report->state) {
+ IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
+ "Spectrum Measure Notification: Start\n");
+ return;
+ }
+
+ memcpy(&priv->measure_report, report, sizeof(*report));
+ priv->measurement_status |= MEASUREMENT_READY;
+#endif
+}
+
+static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
+ IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
+ sleep->pm_sleep_mode, sleep->pm_wakeup_src);
+#endif
+}
+
+static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ IWL_DEBUG_RADIO("Dumping %d bytes of unhandled "
+ "notification for %s:\n",
+ le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
+ iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+}
+
+static void iwl_bg_beacon_update(struct work_struct *work)
+{
+ struct iwl_priv *priv =
+ container_of(work, struct iwl_priv, beacon_update);
+ struct sk_buff *beacon;
+
+ /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
+ beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL);
+
+ if (!beacon) {
+ IWL_ERROR("update beacon failed\n");
+ return;
+ }
+
+ mutex_lock(&priv->mutex);
+ /* new beacon skb is allocated every time; dispose previous.*/
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = beacon;
+ mutex_unlock(&priv->mutex);
+
+ iwl_send_beacon_cmd(priv);
+}
+
+static void iwl_rx_beacon_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status);
+ u8 rate = beacon->beacon_notify_hdr.rate;
+
+ IWL_DEBUG_RX("beacon status %x retries %d iss %d "
+ "tsf %d %d rate %d\n",
+ le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK,
+ beacon->beacon_notify_hdr.failure_frame,
+ le32_to_cpu(beacon->ibss_mgr_status),
+ le32_to_cpu(beacon->high_tsf),
+ le32_to_cpu(beacon->low_tsf), rate);
+#endif
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+ (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
+ queue_work(priv->workqueue, &priv->beacon_update);
+}
+
+/* Service response to REPLY_SCAN_CMD (0x80) */
+static void iwl_rx_reply_scan(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scanreq_notification *notif =
+ (struct iwl_scanreq_notification *)pkt->u.raw;
+
+ IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status);
+#endif
+}
+
+/* Service SCAN_START_NOTIFICATION (0x82) */
+static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scanstart_notification *notif =
+ (struct iwl_scanstart_notification *)pkt->u.raw;
+ priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
+ IWL_DEBUG_SCAN("Scan start: "
+ "%d [802.11%s] "
+ "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
+ notif->channel,
+ notif->band ? "bg" : "a",
+ notif->tsf_high,
+ notif->tsf_low, notif->status, notif->beacon_timer);
+}
+
+/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
+static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scanresults_notification *notif =
+ (struct iwl_scanresults_notification *)pkt->u.raw;
+
+ IWL_DEBUG_SCAN("Scan ch.res: "
+ "%d [802.11%s] "
+ "(TSF: 0x%08X:%08X) - %d "
+ "elapsed=%lu usec (%dms since last)\n",
+ notif->channel,
+ notif->band ? "bg" : "a",
+ le32_to_cpu(notif->tsf_high),
+ le32_to_cpu(notif->tsf_low),
+ le32_to_cpu(notif->statistics[0]),
+ le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf,
+ jiffies_to_msecs(elapsed_jiffies
+ (priv->last_scan_jiffies, jiffies)));
+
+ priv->last_scan_jiffies = jiffies;
+}
+
+/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
+static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
+
+ IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
+ scan_notif->scanned_channels,
+ scan_notif->tsf_low,
+ scan_notif->tsf_high, scan_notif->status);
+
+ /* The HW is no longer scanning */
+ clear_bit(STATUS_SCAN_HW, &priv->status);
+
+ /* The scan completion notification came in, so kill that timer... */
+ cancel_delayed_work(&priv->scan_check);
+
+ IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
+ (priv->scan_bands == 2) ? "2.4" : "5.2",
+ jiffies_to_msecs(elapsed_jiffies
+ (priv->scan_pass_start, jiffies)));
+
+ /* Remove this scanned band from the list
+ * of pending bands to scan */
+ priv->scan_bands--;
+
+ /* If a request to abort was given, or the scan did not succeed
+ * then we reset the scan state machine and terminate,
+ * re-queuing another scan if one has been requested */
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_INFO("Aborted scan completed.\n");
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ } else {
+ /* If there are more bands on this scan pass reschedule */
+ if (priv->scan_bands > 0)
+ goto reschedule;
+ }
+
+ priv->last_scan_jiffies = jiffies;
+ IWL_DEBUG_INFO("Setting scan to off\n");
+
+ clear_bit(STATUS_SCANNING, &priv->status);
+
+ IWL_DEBUG_INFO("Scan took %dms\n",
+ jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies)));
+
+ queue_work(priv->workqueue, &priv->scan_completed);
+
+ return;
+
+reschedule:
+ priv->scan_pass_start = jiffies;
+ queue_work(priv->workqueue, &priv->request_scan);
+}
+
+/* Handle notification from uCode that card's power state is changing
+ * due to software, hardware, or critical temperature RFKILL */
+static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
+ unsigned long status = priv->status;
+
+ IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n",
+ (flags & HW_CARD_DISABLED) ? "Kill" : "On",
+ (flags & SW_CARD_DISABLED) ? "Kill" : "On");
+
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+ if (flags & HW_CARD_DISABLED)
+ set_bit(STATUS_RF_KILL_HW, &priv->status);
+ else
+ clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+
+ if (flags & SW_CARD_DISABLED)
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ else
+ clear_bit(STATUS_RF_KILL_SW, &priv->status);
+
+ iwl_scan_cancel(priv);
+
+ if ((test_bit(STATUS_RF_KILL_HW, &status) !=
+ test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
+ (test_bit(STATUS_RF_KILL_SW, &status) !=
+ test_bit(STATUS_RF_KILL_SW, &priv->status)))
+ queue_work(priv->workqueue, &priv->rf_kill);
+ else
+ wake_up_interruptible(&priv->wait_command_queue);
+}
+
+/**
+ * iwl_setup_rx_handlers - Initialize Rx handler callbacks
+ *
+ * Setup the RX handlers for each of the reply types sent from the uCode
+ * to the host.
+ *
+ * This function chains into the hardware specific files for them to setup
+ * any hardware specific handlers as well.
+ */
+static void iwl_setup_rx_handlers(struct iwl_priv *priv)
+{
+ priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
+ priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta;
+ priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
+ priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+ priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+ iwl_rx_spectrum_measure_notif;
+ priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
+ priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
+ iwl_rx_pm_debug_statistics_notif;
+ priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif;
+
+ /* NOTE: iwl_rx_statistics is different based on whether
+ * the build is for the 3945 or the 4965. See the
+ * corresponding implementation in iwl-XXXX.c
+ *
+ * The same handler is used for both the REPLY to a
+ * discrete statistics request from the host as well as
+ * for the periodic statistics notification from the uCode
+ */
+ priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_hw_rx_statistics;
+ priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics;
+
+ priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
+ priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
+ priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
+ iwl_rx_scan_results_notif;
+ priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
+ iwl_rx_scan_complete_notif;
+ priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif;
+ priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx;
+
+ /* Setup hardware specific Rx handlers */
+ iwl_hw_rx_handler_setup(priv);
+}
+
+/**
+ * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * @rxb: Rx buffer to reclaim
+ *
+ * If an Rx buffer has an async callback associated with it the callback
+ * will be executed. The attached skb (if present) will only be freed
+ * if the callback returns 1
+ */
+static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ int index = SEQ_TO_INDEX(sequence);
+ int huge = sequence & SEQ_HUGE_FRAME;
+ int cmd_index;
+ struct iwl_cmd *cmd;
+
+ /* If a Tx command is being handled and it isn't in the actual
+ * command queue then there a command routing bug has been introduced
+ * in the queue management code. */
+ if (txq_id != IWL_CMD_QUEUE_NUM)
+ IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
+ txq_id, pkt->hdr.cmd);
+ BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
+
+ cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
+ cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+
+ /* Input error checking is done when commands are added to queue. */
+ if (cmd->meta.flags & CMD_WANT_SKB) {
+ cmd->meta.source->u.skb = rxb->skb;
+ rxb->skb = NULL;
+ } else if (cmd->meta.u.callback &&
+ !cmd->meta.u.callback(priv, cmd, rxb->skb))
+ rxb->skb = NULL;
+
+ iwl_tx_queue_reclaim(priv, txq_id, index);
+
+ if (!(cmd->meta.flags & CMD_ASYNC)) {
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
+ }
+}
+
+/************************** RX-FUNCTIONS ****************************/
+/*
+ * Rx theory of operation
+ *
+ * The host allocates 32 DMA target addresses and passes the host address
+ * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
+ * 0 to 31
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer it will advance the READ index
+ * and fire the RX interrupt. The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When
+ * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ * to replensish the iwl->rxq->rx_free.
+ * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ * iwl->rxq is replenished and the READ INDEX is updated (updating the
+ * 'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ * detached from the iwl->rxq. The driver 'processed' index is updated.
+ * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
+ * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
+ * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there
+ * were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * iwl_rx_queue_alloc() Allocates rx_free
+ * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls
+ * iwl_rx_queue_restock
+ * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
+ * queue, updates firmware pointers, and updates
+ * the WRITE index. If insufficient rx_free buffers
+ * are available, schedules iwl_rx_replenish
+ *
+ * -- enable interrupts --
+ * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the
+ * READ INDEX, detaching the SKB from the pool.
+ * Moves the packet buffer from queue to rx_used.
+ * Calls iwl_rx_queue_restock to refill any empty
+ * slots.
+ * ...
+ *
+ */
+
+/**
+ * iwl_rx_queue_space - Return number of free slots available in queue.
+ */
+static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+{
+ int s = q->read - q->write;
+ if (s <= 0)
+ s += RX_QUEUE_SIZE;
+ /* keep some buffer to not confuse full and empty queue */
+ s -= 2;
+ if (s < 0)
+ s = 0;
+ return s;
+}
+
+/**
+ * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ *
+ * NOTE: This function has 3945 and 4965 specific code sections
+ * but is declared in base due to the majority of the
+ * implementation being the same (only a numeric constant is
+ * different)
+ *
+ */
+int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+{
+ u32 reg = 0;
+ int rc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ if (q->need_update == 0)
+ goto exit_unlock;
+
+ if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+ reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ goto exit_unlock;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ goto exit_unlock;
+
+ iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR,
+ q->write & ~0x7);
+ iwl_release_restricted_access(priv);
+ } else
+ iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
+
+
+ q->need_update = 0;
+
+ exit_unlock:
+ spin_unlock_irqrestore(&q->lock, flags);
+ return rc;
+}
+
+/**
+ * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer.
+ *
+ * NOTE: This function has 3945 and 4965 specific code paths in it.
+ */
+static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
+ dma_addr_t dma_addr)
+{
+ return cpu_to_le32((u32)dma_addr);
+}
+
+/**
+ * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+int iwl_rx_queue_restock(struct iwl_priv *priv)
+{
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct list_head *element;
+ struct iwl_rx_mem_buffer *rxb;
+ unsigned long flags;
+ int write, rc;
+
+ spin_lock_irqsave(&rxq->lock, flags);
+ write = rxq->write & ~0x7;
+ while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+ element = rxq->rx_free.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ list_del(element);
+ rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr);
+ rxq->queue[rxq->write] = rxb;
+ rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+ rxq->free_count--;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ /* If the pre-allocated buffer pool is dropping low, schedule to
+ * refill it */
+ if (rxq->free_count <= RX_LOW_WATERMARK)
+ queue_work(priv->workqueue, &priv->rx_replenish);
+
+
+ /* If we've added more space for the firmware to place data, tell it */
+ if ((write != (rxq->write & ~0x7))
+ || (abs(rxq->write - rxq->read) > 7)) {
+ spin_lock_irqsave(&rxq->lock, flags);
+ rxq->need_update = 1;
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ rc = iwl_rx_queue_update_write_ptr(priv, rxq);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * iwl_rx_replensih - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl_rx_queue_restock.
+ * This is called as a scheduled work item (except for during intialization)
+ */
+void iwl_rx_replenish(void *data)
+{
+ struct iwl_priv *priv = data;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct list_head *element;
+ struct iwl_rx_mem_buffer *rxb;
+ unsigned long flags;
+ spin_lock_irqsave(&rxq->lock, flags);
+ while (!list_empty(&rxq->rx_used)) {
+ element = rxq->rx_used.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ rxb->skb =
+ alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
+ if (!rxb->skb) {
+ if (net_ratelimit())
+ printk(KERN_CRIT DRV_NAME
+ ": Can not allocate SKB buffers\n");
+ /* We don't reschedule replenish work here -- we will
+ * call the restock method and if it still needs
+ * more buffers it will schedule replenish */
+ break;
+ }
+ priv->alloc_rxb_skb++;
+ list_del(element);
+ rxb->dma_addr =
+ pci_map_single(priv->pci_dev, rxb->skb->data,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_rx_queue_restock(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ int i;
+ for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+ if (rxq->pool[i].skb != NULL) {
+ pci_unmap_single(priv->pci_dev,
+ rxq->pool[i].dma_addr,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(rxq->pool[i].skb);
+ }
+ }
+
+ pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+ rxq->dma_addr);
+ rxq->bd = NULL;
+}
+
+int iwl_rx_queue_alloc(struct iwl_priv *priv)
+{
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct pci_dev *dev = priv->pci_dev;
+ int i;
+
+ spin_lock_init(&rxq->lock);
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_used);
+ rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
+ if (!rxq->bd)
+ return -ENOMEM;
+ /* Fill the rx_used queue with _all_ of the Rx buffers */
+ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+ list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+ /* Set us so that we have processed and used all buffers, but have
+ * not restocked the Rx queue with fresh buffers */
+ rxq->read = rxq->write = 0;
+ rxq->free_count = 0;
+ rxq->need_update = 0;
+ return 0;
+}
+
+void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ unsigned long flags;
+ int i;
+ spin_lock_irqsave(&rxq->lock, flags);
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_used);
+ /* Fill the rx_used queue with _all_ of the Rx buffers */
+ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+ /* In the reset function, these buffers may have been allocated
+ * to an SKB, so we need to unmap and free potential storage */
+ if (rxq->pool[i].skb != NULL) {
+ pci_unmap_single(priv->pci_dev,
+ rxq->pool[i].dma_addr,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb(rxq->pool[i].skb);
+ rxq->pool[i].skb = NULL;
+ }
+ list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+ }
+
+ /* Set us so that we have processed and used all buffers, but have
+ * not restocked the Rx queue with fresh buffers */
+ rxq->read = rxq->write = 0;
+ rxq->free_count = 0;
+ spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/* Convert linear signal-to-noise ratio into dB */
+static u8 ratio2dB[100] = {
+/* 0 1 2 3 4 5 6 7 8 9 */
+ 0, 0, 6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */
+ 20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */
+ 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */
+ 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */
+ 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */
+ 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */
+ 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */
+ 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */
+ 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */
+ 39, 39, 39, 39, 39, 40, 40, 40, 40, 40 /* 90 - 99 */
+};
+
+/* Calculates a relative dB value from a ratio of linear
+ * (i.e. not dB) signal levels.
+ * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
+int iwl_calc_db_from_ratio(int sig_ratio)
+{
+ /* Anything above 1000:1 just report as 60 dB */
+ if (sig_ratio > 1000)
+ return 60;
+
+ /* Above 100:1, divide by 10 and use table,
+ * add 20 dB to make up for divide by 10 */
+ if (sig_ratio > 100)
+ return (20 + (int)ratio2dB[sig_ratio/10]);
+
+ /* We shouldn't see this */
+ if (sig_ratio < 1)
+ return 0;
+
+ /* Use table for ratios 1:1 - 99:1 */
+ return (int)ratio2dB[sig_ratio];
+}
+
+#define PERFECT_RSSI (-20) /* dBm */
+#define WORST_RSSI (-95) /* dBm */
+#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
+
+/* Calculate an indication of rx signal quality (a percentage, not dBm!).
+ * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
+ * about formulas used below. */
+int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
+{
+ int sig_qual;
+ int degradation = PERFECT_RSSI - rssi_dbm;
+
+ /* If we get a noise measurement, use signal-to-noise ratio (SNR)
+ * as indicator; formula is (signal dbm - noise dbm).
+ * SNR at or above 40 is a great signal (100%).
+ * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
+ * Weakest usable signal is usually 10 - 15 dB SNR. */
+ if (noise_dbm) {
+ if (rssi_dbm - noise_dbm >= 40)
+ return 100;
+ else if (rssi_dbm < noise_dbm)
+ return 0;
+ sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
+
+ /* Else use just the signal level.
+ * This formula is a least squares fit of data points collected and
+ * compared with a reference system that had a percentage (%) display
+ * for signal quality. */
+ } else
+ sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
+ (15 * RSSI_RANGE + 62 * degradation)) /
+ (RSSI_RANGE * RSSI_RANGE);
+
+ if (sig_qual > 100)
+ sig_qual = 100;
+ else if (sig_qual < 1)
+ sig_qual = 0;
+
+ return sig_qual;
+}
+
+/**
+ * iwl_rx_handle - Main entry function for receiving responses from the uCode
+ *
+ * Uses the priv->rx_handlers callback function array to invoke
+ * the appropriate handlers, including command responses,
+ * frame-received notifications, and other notifications.
+ */
+static void iwl_rx_handle(struct iwl_priv *priv)
+{
+ struct iwl_rx_mem_buffer *rxb;
+ struct iwl_rx_packet *pkt;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ u32 r, i;
+ int reclaim;
+ unsigned long flags;
+
+ r = iwl_hw_get_rx_read(priv);
+ i = rxq->read;
+
+ /* Rx interrupt, but nothing sent from uCode */
+ if (i == r)
+ IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
+
+ while (i != r) {
+ rxb = rxq->queue[i];
+
+ /* If an RXB doesn't have a queue slot associated with it
+ * then a bug has been introduced in the queue refilling
+ * routines -- catch it here */
+ BUG_ON(rxb == NULL);
+
+ rxq->queue[i] = NULL;
+
+ pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
+ IWL_RX_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+ pkt = (struct iwl_rx_packet *)rxb->skb->data;
+
+ /* Reclaim a command buffer only if this packet is a response
+ * to a (driver-originated) command.
+ * If the packet (e.g. Rx frame) originated from uCode,
+ * there is no command buffer to reclaim.
+ * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
+ * but apparently a few don't get set; catch them here. */
+ reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
+ (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
+ (pkt->hdr.cmd != REPLY_TX);
+
+ /* Based on type of command response or notification,
+ * handle those that need handling via function in
+ * rx_handlers table. See iwl_setup_rx_handlers() */
+ if (priv->rx_handlers[pkt->hdr.cmd]) {
+ IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+ "r = %d, i = %d, %s, 0x%02x\n", r, i,
+ get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
+ priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+ } else {
+ /* No handling needed */
+ IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+ "r %d i %d No handler needed for %s, 0x%02x\n",
+ r, i, get_cmd_string(pkt->hdr.cmd),
+ pkt->hdr.cmd);
+ }
+
+ if (reclaim) {
+ /* Invoke any callbacks, transfer the skb to caller,
+ * and fire off the (possibly) blocking iwl_send_cmd()
+ * as we reclaim the driver command queue */
+ if (rxb && rxb->skb)
+ iwl_tx_cmd_complete(priv, rxb);
+ else
+ IWL_WARNING("Claim null rxb?\n");
+ }
+
+ /* For now we just don't re-use anything. We can tweak this
+ * later to try and re-use notification packets and SKBs that
+ * fail to Rx correctly */
+ if (rxb->skb != NULL) {
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(rxb->skb);
+ rxb->skb = NULL;
+ }
+
+ pci_unmap_single(priv->pci_dev, rxb->dma_addr,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ spin_lock_irqsave(&rxq->lock, flags);
+ list_add_tail(&rxb->list, &priv->rxq.rx_used);
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ i = (i + 1) & RX_QUEUE_MASK;
+ }
+
+ /* Backtrack one entry */
+ priv->rxq.read = i;
+ iwl_rx_queue_restock(priv);
+}
+
+int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq)
+{
+ u32 reg = 0;
+ int rc = 0;
+ int txq_id = txq->q.id;
+
+ if (txq->need_update == 0)
+ return rc;
+
+ /* if we're trying to save power */
+ if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+ /* wake up nic if it's powered down ...
+ * uCode will wake up, and interrupt us again, so next
+ * time we'll skip this part. */
+ reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg);
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ return rc;
+ }
+
+ /* restore this queue's parameters in nic hardware. */
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+ iwl_write_restricted(priv, HBUS_TARG_WRPTR,
+ txq->q.first_empty | (txq_id << 8));
+ iwl_release_restricted_access(priv);
+
+ /* else not in power-save mode, uCode will never sleep when we're
+ * trying to tx (during RFKILL, we're not trying to tx). */
+ } else
+ iwl_write32(priv, HBUS_TARG_WRPTR,
+ txq->q.first_empty | (txq_id << 8));
+
+ txq->need_update = 0;
+
+ return rc;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
+{
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_RADIO("RX CONFIG:\n");
+ iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+ IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
+ IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
+ IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
+ le32_to_cpu(rxon->filter_flags));
+ IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type);
+ IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
+ rxon->ofdm_basic_rates);
+ IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
+ IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
+ print_mac(mac, rxon->node_addr));
+ IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
+ print_mac(mac, rxon->bssid_addr));
+ IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
+}
+#endif
+
+static void iwl_enable_interrupts(struct iwl_priv *priv)
+{
+ IWL_DEBUG_ISR("Enabling interrupts\n");
+ set_bit(STATUS_INT_ENABLED, &priv->status);
+ iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+}
+
+static inline void iwl_disable_interrupts(struct iwl_priv *priv)
+{
+ clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+ /* disable interrupts from uCode/NIC to host */
+ iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+ /* acknowledge/clear/reset any interrupts still pending
+ * from uCode or flow handler (Rx/Tx DMA) */
+ iwl_write32(priv, CSR_INT, 0xffffffff);
+ iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+ IWL_DEBUG_ISR("Disabled interrupts\n");
+}
+
+static const char *desc_lookup(int i)
+{
+ switch (i) {
+ case 1:
+ return "FAIL";
+ case 2:
+ return "BAD_PARAM";
+ case 3:
+ return "BAD_CHECKSUM";
+ case 4:
+ return "NMI_INTERRUPT";
+ case 5:
+ return "SYSASSERT";
+ case 6:
+ return "FATAL_ERROR";
+ }
+
+ return "UNKNOWN";
+}
+
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+ u32 i;
+ u32 desc, time, count, base, data1;
+ u32 blink1, blink2, ilink1, ilink2;
+ int rc;
+
+ base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+
+ if (!iwl_hw_valid_rtc_data_addr(base)) {
+ IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
+ return;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ IWL_WARNING("Can not read from adapter at this time.\n");
+ return;
+ }
+
+ count = iwl_read_restricted_mem(priv, base);
+
+ if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+ IWL_ERROR("Start IWL Error Log Dump:\n");
+ IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n",
+ priv->status, priv->config, count);
+ }
+
+ IWL_ERROR("Desc Time asrtPC blink2 "
+ "ilink1 nmiPC Line\n");
+ for (i = ERROR_START_OFFSET;
+ i < (count * ERROR_ELEM_SIZE) + ERROR_START_OFFSET;
+ i += ERROR_ELEM_SIZE) {
+ desc = iwl_read_restricted_mem(priv, base + i);
+ time =
+ iwl_read_restricted_mem(priv, base + i + 1 * sizeof(u32));
+ blink1 =
+ iwl_read_restricted_mem(priv, base + i + 2 * sizeof(u32));
+ blink2 =
+ iwl_read_restricted_mem(priv, base + i + 3 * sizeof(u32));
+ ilink1 =
+ iwl_read_restricted_mem(priv, base + i + 4 * sizeof(u32));
+ ilink2 =
+ iwl_read_restricted_mem(priv, base + i + 5 * sizeof(u32));
+ data1 =
+ iwl_read_restricted_mem(priv, base + i + 6 * sizeof(u32));
+
+ IWL_ERROR
+ ("%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
+ desc_lookup(desc), desc, time, blink1, blink2,
+ ilink1, ilink2, data1);
+ }
+
+ iwl_release_restricted_access(priv);
+
+}
+
+#define EVENT_START_OFFSET (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ * NOTE: Must be called with iwl_grab_restricted_access() already obtained!
+ */
+static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+ u32 num_events, u32 mode)
+{
+ u32 i;
+ u32 base; /* SRAM byte address of event log header */
+ u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+ u32 ptr; /* SRAM byte address of log data */
+ u32 ev, time, data; /* event log data */
+
+ if (num_events == 0)
+ return;
+
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+ if (mode == 0)
+ event_size = 2 * sizeof(u32);
+ else
+ event_size = 3 * sizeof(u32);
+
+ ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+ /* "time" is actually "data" for mode 0 (no timestamp).
+ * place event id # at far right for easier visual parsing. */
+ for (i = 0; i < num_events; i++) {
+ ev = iwl_read_restricted_mem(priv, ptr);
+ ptr += sizeof(u32);
+ time = iwl_read_restricted_mem(priv, ptr);
+ ptr += sizeof(u32);
+ if (mode == 0)
+ IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
+ else {
+ data = iwl_read_restricted_mem(priv, ptr);
+ ptr += sizeof(u32);
+ IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
+ }
+ }
+}
+
+static void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+ int rc;
+ u32 base; /* SRAM byte address of event log header */
+ u32 capacity; /* event log capacity in # entries */
+ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
+ u32 num_wraps; /* # times uCode wrapped to top of log */
+ u32 next_entry; /* index of next entry to be written by uCode */
+ u32 size; /* # entries that we'll print */
+
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ if (!iwl_hw_valid_rtc_data_addr(base)) {
+ IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
+ return;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ IWL_WARNING("Can not read from adapter at this time.\n");
+ return;
+ }
+
+ /* event log header */
+ capacity = iwl_read_restricted_mem(priv, base);
+ mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32)));
+ num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32)));
+ next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32)));
+
+ size = num_wraps ? capacity : next_entry;
+
+ /* bail out if nothing in log */
+ if (size == 0) {
+ IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
+ iwl_release_restricted_access(priv);
+ return;
+ }
+
+ IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n",
+ size, num_wraps);
+
+ /* if uCode has wrapped back to top of log, start at the oldest entry,
+ * i.e the next one that uCode would fill. */
+ if (num_wraps)
+ iwl_print_event_log(priv, next_entry,
+ capacity - next_entry, mode);
+
+ /* (then/else) start at top of log */
+ iwl_print_event_log(priv, 0, next_entry, mode);
+
+ iwl_release_restricted_access(priv);
+}
+
+/**
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ */
+static void iwl_irq_handle_error(struct iwl_priv *priv)
+{
+ /* Set the FW error flag -- cleared on iwl_down */
+ set_bit(STATUS_FW_ERROR, &priv->status);
+
+ /* Cancel currently queued command. */
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & IWL_DL_FW_ERRORS) {
+ iwl_dump_nic_error_log(priv);
+ iwl_dump_nic_event_log(priv);
+ iwl_print_rx_config_cmd(&priv->staging_rxon);
+ }
+#endif
+
+ wake_up_interruptible(&priv->wait_command_queue);
+
+ /* Keep the restart process from trying to send host
+ * commands by clearing the INIT status bit */
+ clear_bit(STATUS_READY, &priv->status);
+
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
+ "Restarting adapter due to uCode error.\n");
+
+ if (iwl_is_associated(priv)) {
+ memcpy(&priv->recovery_rxon, &priv->active_rxon,
+ sizeof(priv->recovery_rxon));
+ priv->error_recovering = 1;
+ }
+ queue_work(priv->workqueue, &priv->restart);
+ }
+}
+
+static void iwl_error_recovery(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ memcpy(&priv->staging_rxon, &priv->recovery_rxon,
+ sizeof(priv->staging_rxon));
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ iwl_add_station(priv, priv->bssid, 1, 0);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
+ priv->error_recovering = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl_irq_tasklet(struct iwl_priv *priv)
+{
+ u32 inta, handled = 0;
+ u32 inta_fh;
+ unsigned long flags;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ u32 inta_mask;
+#endif
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Ack/clear/reset pending uCode interrupts.
+ * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
+ * and will clear only when CSR_FH_INT_STATUS gets cleared. */
+ inta = iwl_read32(priv, CSR_INT);
+ iwl_write32(priv, CSR_INT, inta);
+
+ /* Ack/clear/reset pending flow-handler (DMA) interrupts.
+ * Any new interrupts that happen after this, either while we're
+ * in this tasklet, or later, will show up in next ISR/tasklet. */
+ inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+ iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & IWL_DL_ISR) {
+ inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
+ IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+ inta, inta_mask, inta_fh);
+ }
+#endif
+
+ /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
+ * atomic, make sure that inta covers all the interrupts that
+ * we've discovered, even if FH interrupt came in just after
+ * reading CSR_INT. */
+ if (inta_fh & CSR_FH_INT_RX_MASK)
+ inta |= CSR_INT_BIT_FH_RX;
+ if (inta_fh & CSR_FH_INT_TX_MASK)
+ inta |= CSR_INT_BIT_FH_TX;
+
+ /* Now service all interrupt bits discovered above. */
+ if (inta & CSR_INT_BIT_HW_ERR) {
+ IWL_ERROR("Microcode HW error detected. Restarting.\n");
+
+ /* Tell the device to stop sending interrupts */
+ iwl_disable_interrupts(priv);
+
+ iwl_irq_handle_error(priv);
+
+ handled |= CSR_INT_BIT_HW_ERR;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return;
+ }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & (IWL_DL_ISR)) {
+ /* NIC fires this, but we don't use it, redundant with WAKEUP */
+ if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
+ IWL_DEBUG_ISR("Microcode started or stopped.\n");
+
+ /* Alive notification via Rx interrupt will do the real work */
+ if (inta & CSR_INT_BIT_ALIVE)
+ IWL_DEBUG_ISR("Alive interrupt\n");
+ }
+#endif
+ /* Safely ignore these bits for debug checks below */
+ inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+
+ /* HW RF KILL switch toggled (4965 only) */
+ if (inta & CSR_INT_BIT_RF_KILL) {
+ int hw_rf_kill = 0;
+ if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+ CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+ hw_rf_kill = 1;
+
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
+ "RF_KILL bit toggled to %s.\n",
+ hw_rf_kill ? "disable radio":"enable radio");
+
+ /* Queue restart only if RF_KILL switch was set to "kill"
+ * when we loaded driver, and is now set to "enable".
+ * After we're Alive, RF_KILL gets handled by
+ * iwl_rx_card_state_notif() */
+ if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status))
+ queue_work(priv->workqueue, &priv->restart);
+
+ handled |= CSR_INT_BIT_RF_KILL;
+ }
+
+ /* Chip got too hot and stopped itself (4965 only) */
+ if (inta & CSR_INT_BIT_CT_KILL) {
+ IWL_ERROR("Microcode CT kill error detected.\n");
+ handled |= CSR_INT_BIT_CT_KILL;
+ }
+
+ /* Error detected by uCode */
+ if (inta & CSR_INT_BIT_SW_ERR) {
+ IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n",
+ inta);
+ iwl_irq_handle_error(priv);
+ handled |= CSR_INT_BIT_SW_ERR;
+ }
+
+ /* uCode wakes up after power-down sleep */
+ if (inta & CSR_INT_BIT_WAKEUP) {
+ IWL_DEBUG_ISR("Wakeup interrupt\n");
+ iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[0]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]);
+
+ handled |= CSR_INT_BIT_WAKEUP;
+ }
+
+ /* All uCode command responses, including Tx command responses,
+ * Rx "responses" (frame-received notification), and other
+ * notifications from uCode come through here*/
+ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
+ iwl_rx_handle(priv);
+ handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
+ }
+
+ if (inta & CSR_INT_BIT_FH_TX) {
+ IWL_DEBUG_ISR("Tx interrupt\n");
+
+ iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6));
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted(priv,
+ FH_TCSR_CREDIT
+ (ALM_FH_SRVC_CHNL), 0x0);
+ iwl_release_restricted_access(priv);
+ }
+ handled |= CSR_INT_BIT_FH_TX;
+ }
+
+ if (inta & ~handled)
+ IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
+
+ if (inta & ~CSR_INI_SET_MASK) {
+ IWL_WARNING("Disabled INTA bits 0x%08x were pending\n",
+ inta & ~CSR_INI_SET_MASK);
+ IWL_WARNING(" with FH_INT = 0x%08x\n", inta_fh);
+ }
+
+ /* Re-enable all interrupts */
+ iwl_enable_interrupts(priv);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & (IWL_DL_ISR)) {
+ inta = iwl_read32(priv, CSR_INT);
+ inta_mask = iwl_read32(priv, CSR_INT_MASK);
+ inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+ IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
+ "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
+ }
+#endif
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static irqreturn_t iwl_isr(int irq, void *data)
+{
+ struct iwl_priv *priv = data;
+ u32 inta, inta_mask;
+ u32 inta_fh;
+ if (!priv)
+ return IRQ_NONE;
+
+ spin_lock(&priv->lock);
+
+ /* Disable (but don't clear!) interrupts here to avoid
+ * back-to-back ISRs and sporadic interrupts from our NIC.
+ * If we have something to service, the tasklet will re-enable ints.
+ * If we *don't* have something, we'll re-enable before leaving here. */
+ inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
+ iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+ /* Discover which interrupts are active/pending */
+ inta = iwl_read32(priv, CSR_INT);
+ inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+
+ /* Ignore interrupt if there's nothing in NIC to service.
+ * This may be due to IRQ shared with another device,
+ * or due to sporadic interrupts thrown from our NIC. */
+ if (!inta && !inta_fh) {
+ IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n");
+ goto none;
+ }
+
+ if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+ /* Hardware disappeared */
+ IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta);
+ goto unplugged;
+ }
+
+ IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+ inta, inta_mask, inta_fh);
+
+ /* iwl_irq_tasklet() will service interrupts and re-enable them */
+ tasklet_schedule(&priv->irq_tasklet);
+unplugged:
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+
+ none:
+ /* re-enable interrupts here since we don't have anything to service. */
+ iwl_enable_interrupts(priv);
+ spin_unlock(&priv->lock);
+ return IRQ_NONE;
+}
+
+/************************** EEPROM BANDS ****************************
+ *
+ * The iwl_eeprom_band definitions below provide the mapping from the
+ * EEPROM contents to the specific channel number supported for each
+ * band.
+ *
+ * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3
+ * definition below maps to physical channel 42 in the 5.2GHz spectrum.
+ * The specific geography and calibration information for that channel
+ * is contained in the eeprom map itself.
+ *
+ * During init, we copy the eeprom information and channel map
+ * information into priv->channel_info_24/52 and priv->channel_map_24/52
+ *
+ * channel_map_24/52 provides the index in the channel_info array for a
+ * given channel. We have to have two separate maps as there is channel
+ * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and
+ * band_2
+ *
+ * A value of 0xff stored in the channel_map indicates that the channel
+ * is not supported by the hardware at all.
+ *
+ * A value of 0xfe in the channel_map indicates that the channel is not
+ * valid for Tx with the current hardware. This means that
+ * while the system can tune and receive on a given channel, it may not
+ * be able to associate or transmit any frames on that
+ * channel. There is no corresponding channel information for that
+ * entry.
+ *
+ *********************************************************************/
+
+/* 2.4 GHz */
+static const u8 iwl_eeprom_band_1[14] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+};
+
+/* 5.2 GHz bands */
+static const u8 iwl_eeprom_band_2[] = {
+ 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
+};
+
+static const u8 iwl_eeprom_band_3[] = { /* 5205-5320MHz */
+ 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+};
+
+static const u8 iwl_eeprom_band_4[] = { /* 5500-5700MHz */
+ 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+};
+
+static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */
+ 145, 149, 153, 157, 161, 165
+};
+
+static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
+ int *eeprom_ch_count,
+ const struct iwl_eeprom_channel
+ **eeprom_ch_info,
+ const u8 **eeprom_ch_index)
+{
+ switch (band) {
+ case 1: /* 2.4GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
+ *eeprom_ch_info = priv->eeprom.band_1_channels;
+ *eeprom_ch_index = iwl_eeprom_band_1;
+ break;
+ case 2: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
+ *eeprom_ch_info = priv->eeprom.band_2_channels;
+ *eeprom_ch_index = iwl_eeprom_band_2;
+ break;
+ case 3: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
+ *eeprom_ch_info = priv->eeprom.band_3_channels;
+ *eeprom_ch_index = iwl_eeprom_band_3;
+ break;
+ case 4: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
+ *eeprom_ch_info = priv->eeprom.band_4_channels;
+ *eeprom_ch_index = iwl_eeprom_band_4;
+ break;
+ case 5: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
+ *eeprom_ch_info = priv->eeprom.band_5_channels;
+ *eeprom_ch_index = iwl_eeprom_band_5;
+ break;
+ default:
+ BUG();
+ return;
+ }
+}
+
+const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
+ int phymode, u16 channel)
+{
+ int i;
+
+ switch (phymode) {
+ case MODE_IEEE80211A:
+ for (i = 14; i < priv->channel_count; i++) {
+ if (priv->channel_info[i].channel == channel)
+ return &priv->channel_info[i];
+ }
+ break;
+
+ case MODE_IEEE80211B:
+ case MODE_IEEE80211G:
+ if (channel >= 1 && channel <= 14)
+ return &priv->channel_info[channel - 1];
+ break;
+
+ }
+
+ return NULL;
+}
+
+#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
+ ? # x " " : "")
+
+static int iwl_init_channel_map(struct iwl_priv *priv)
+{
+ int eeprom_ch_count = 0;
+ const u8 *eeprom_ch_index = NULL;
+ const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
+ int band, ch;
+ struct iwl_channel_info *ch_info;
+
+ if (priv->channel_count) {
+ IWL_DEBUG_INFO("Channel map already initialized.\n");
+ return 0;
+ }
+
+ if (priv->eeprom.version < 0x2f) {
+ IWL_WARNING("Unsupported EEPROM version: 0x%04X\n",
+ priv->eeprom.version);
+ return -EINVAL;
+ }
+
+ IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
+
+ priv->channel_count =
+ ARRAY_SIZE(iwl_eeprom_band_1) +
+ ARRAY_SIZE(iwl_eeprom_band_2) +
+ ARRAY_SIZE(iwl_eeprom_band_3) +
+ ARRAY_SIZE(iwl_eeprom_band_4) +
+ ARRAY_SIZE(iwl_eeprom_band_5);
+
+ IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count);
+
+ priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
+ priv->channel_count, GFP_KERNEL);
+ if (!priv->channel_info) {
+ IWL_ERROR("Could not allocate channel_info\n");
+ priv->channel_count = 0;
+ return -ENOMEM;
+ }
+
+ ch_info = priv->channel_info;
+
+ /* Loop through the 5 EEPROM bands adding them in order to the
+ * channel map we maintain (that contains additional information than
+ * what just in the EEPROM) */
+ for (band = 1; band <= 5; band++) {
+
+ iwl_init_band_reference(priv, band, &eeprom_ch_count,
+ &eeprom_ch_info, &eeprom_ch_index);
+
+ /* Loop through each band adding each of the channels */
+ for (ch = 0; ch < eeprom_ch_count; ch++) {
+ ch_info->channel = eeprom_ch_index[ch];
+ ch_info->phymode = (band == 1) ? MODE_IEEE80211B :
+ MODE_IEEE80211A;
+
+ /* permanently store EEPROM's channel regulatory flags
+ * and max power in channel info database. */
+ ch_info->eeprom = eeprom_ch_info[ch];
+
+ /* Copy the run-time flags so they are there even on
+ * invalid channels */
+ ch_info->flags = eeprom_ch_info[ch].flags;
+
+ if (!(is_channel_valid(ch_info))) {
+ IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - "
+ "No traffic\n",
+ ch_info->channel,
+ ch_info->flags,
+ is_channel_a_band(ch_info) ?
+ "5.2" : "2.4");
+ ch_info++;
+ continue;
+ }
+
+ /* Initialize regulatory-based run-time data */
+ ch_info->max_power_avg = ch_info->curr_txpow =
+ eeprom_ch_info[ch].max_power_avg;
+ ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
+ ch_info->min_power = 0;
+
+ IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+ " %ddBm): Ad-Hoc %ssupported\n",
+ ch_info->channel,
+ is_channel_a_band(ch_info) ?
+ "5.2" : "2.4",
+ CHECK_AND_PRINT(IBSS),
+ CHECK_AND_PRINT(ACTIVE),
+ CHECK_AND_PRINT(RADAR),
+ CHECK_AND_PRINT(WIDE),
+ CHECK_AND_PRINT(NARROW),
+ CHECK_AND_PRINT(DFS),
+ eeprom_ch_info[ch].flags,
+ eeprom_ch_info[ch].max_power_avg,
+ ((eeprom_ch_info[ch].
+ flags & EEPROM_CHANNEL_IBSS)
+ && !(eeprom_ch_info[ch].
+ flags & EEPROM_CHANNEL_RADAR))
+ ? "" : "not ");
+
+ /* Set the user_txpower_limit to the highest power
+ * supported by any channel */
+ if (eeprom_ch_info[ch].max_power_avg >
+ priv->user_txpower_limit)
+ priv->user_txpower_limit =
+ eeprom_ch_info[ch].max_power_avg;
+
+ ch_info++;
+ }
+ }
+
+ if (iwl3945_txpower_set_from_eeprom(priv))
+ return -EIO;
+
+ return 0;
+}
+
+/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
+ * sending probe req. This should be set long enough to hear probe responses
+ * from more than one AP. */
+#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52 (10)
+
+/* For faster active scanning, scan will move to the next channel if fewer than
+ * PLCP_QUIET_THRESH packets are heard on this channel within
+ * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell
+ * time if it's a quiet channel (nothing responded to our probe, and there's
+ * no other traffic).
+ * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
+#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */
+#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */
+
+/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
+ * Must be set longer than active dwell time.
+ * For the most reliable scan, set > AP beacon interval (typically 100msec). */
+#define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */
+#define IWL_PASSIVE_DWELL_TIME_52 (10)
+#define IWL_PASSIVE_DWELL_BASE (100)
+#define IWL_CHANNEL_TUNE_TIME 5
+
+static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
+{
+ if (phymode == MODE_IEEE80211A)
+ return IWL_ACTIVE_DWELL_TIME_52;
+ else
+ return IWL_ACTIVE_DWELL_TIME_24;
+}
+
+static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
+{
+ u16 active = iwl_get_active_dwell_time(priv, phymode);
+ u16 passive = (phymode != MODE_IEEE80211A) ?
+ IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
+ IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
+
+ if (iwl_is_associated(priv)) {
+ /* If we're associated, we clamp the maximum passive
+ * dwell time to be 98% of the beacon interval (minus
+ * 2 * channel tune time) */
+ passive = priv->beacon_int;
+ if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
+ passive = IWL_PASSIVE_DWELL_BASE;
+ passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+ }
+
+ if (passive <= active)
+ passive = active + 1;
+
+ return passive;
+}
+
+static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+ u8 is_active, u8 direct_mask,
+ struct iwl_scan_channel *scan_ch)
+{
+ const struct ieee80211_channel *channels = NULL;
+ const struct ieee80211_hw_mode *hw_mode;
+ const struct iwl_channel_info *ch_info;
+ u16 passive_dwell = 0;
+ u16 active_dwell = 0;
+ int added, i;
+
+ hw_mode = iwl_get_hw_mode(priv, phymode);
+ if (!hw_mode)
+ return 0;
+
+ channels = hw_mode->channels;
+
+ active_dwell = iwl_get_active_dwell_time(priv, phymode);
+ passive_dwell = iwl_get_passive_dwell_time(priv, phymode);
+
+ for (i = 0, added = 0; i < hw_mode->num_channels; i++) {
+ if (channels[i].chan ==
+ le16_to_cpu(priv->active_rxon.channel)) {
+ if (iwl_is_associated(priv)) {
+ IWL_DEBUG_SCAN
+ ("Skipping current channel %d\n",
+ le16_to_cpu(priv->active_rxon.channel));
+ continue;
+ }
+ } else if (priv->only_active_channel)
+ continue;
+
+ scan_ch->channel = channels[i].chan;
+
+ ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+ scan_ch->channel);
+ continue;
+ }
+
+ if (!is_active || is_channel_passive(ch_info) ||
+ !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN))
+ scan_ch->type = 0; /* passive */
+ else
+ scan_ch->type = 1; /* active */
+
+ if (scan_ch->type & 1)
+ scan_ch->type |= (direct_mask << 1);
+
+ if (is_channel_narrow(ch_info))
+ scan_ch->type |= (1 << 7);
+
+ scan_ch->active_dwell = cpu_to_le16(active_dwell);
+ scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+
+ /* Set power levels to defaults */
+ scan_ch->tpc.dsp_atten = 110;
+ /* scan_pwr_info->tpc.dsp_atten; */
+
+ /*scan_pwr_info->tpc.tx_gain; */
+ if (phymode == MODE_IEEE80211A)
+ scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
+ else {
+ scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
+ /* NOTE: if we were doing 6Mb OFDM for scans we'd use
+ * power level
+ scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
+ */
+ }
+
+ IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
+ scan_ch->channel,
+ (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
+ (scan_ch->type & 1) ?
+ active_dwell : passive_dwell);
+
+ scan_ch++;
+ added++;
+ }
+
+ IWL_DEBUG_SCAN("total channels to scan %d \n", added);
+ return added;
+}
+
+static void iwl_reset_channel_flag(struct iwl_priv *priv)
+{
+ int i, j;
+ for (i = 0; i < 3; i++) {
+ struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i];
+ for (j = 0; j < hw_mode->num_channels; j++)
+ hw_mode->channels[j].flag = hw_mode->channels[j].val;
+ }
+}
+
+static void iwl_init_hw_rates(struct iwl_priv *priv,
+ struct ieee80211_rate *rates)
+{
+ int i;
+
+ for (i = 0; i < IWL_RATE_COUNT; i++) {
+ rates[i].rate = iwl_rates[i].ieee * 5;
+ rates[i].val = i; /* Rate scaling will work on indexes */
+ rates[i].val2 = i;
+ rates[i].flags = IEEE80211_RATE_SUPPORTED;
+ /* Only OFDM have the bits-per-symbol set */
+ if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE))
+ rates[i].flags |= IEEE80211_RATE_OFDM;
+ else {
+ /*
+ * If CCK 1M then set rate flag to CCK else CCK_2
+ * which is CCK | PREAMBLE2
+ */
+ rates[i].flags |= (iwl_rates[i].plcp == 10) ?
+ IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
+ }
+
+ /* Set up which ones are basic rates... */
+ if (IWL_BASIC_RATES_MASK & (1 << i))
+ rates[i].flags |= IEEE80211_RATE_BASIC;
+ }
+}
+
+/**
+ * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ */
+static int iwl_init_geos(struct iwl_priv *priv)
+{
+ struct iwl_channel_info *ch;
+ struct ieee80211_hw_mode *modes;
+ struct ieee80211_channel *channels;
+ struct ieee80211_channel *geo_ch;
+ struct ieee80211_rate *rates;
+ int i = 0;
+ enum {
+ A = 0,
+ B = 1,
+ G = 2,
+ };
+ int mode_count = 3;
+
+ if (priv->modes) {
+ IWL_DEBUG_INFO("Geography modes already initialized.\n");
+ set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+ return 0;
+ }
+
+ modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count,
+ GFP_KERNEL);
+ if (!modes)
+ return -ENOMEM;
+
+ channels = kzalloc(sizeof(struct ieee80211_channel) *
+ priv->channel_count, GFP_KERNEL);
+ if (!channels) {
+ kfree(modes);
+ return -ENOMEM;
+ }
+
+ rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)),
+ GFP_KERNEL);
+ if (!rates) {
+ kfree(modes);
+ kfree(channels);
+ return -ENOMEM;
+ }
+
+ /* 0 = 802.11a
+ * 1 = 802.11b
+ * 2 = 802.11g
+ */
+
+ /* 5.2GHz channels start after the 2.4GHz channels */
+ modes[A].mode = MODE_IEEE80211A;
+ modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+ modes[A].rates = &rates[4];
+ modes[A].num_rates = 8; /* just OFDM */
+ modes[A].num_channels = 0;
+
+ modes[B].mode = MODE_IEEE80211B;
+ modes[B].channels = channels;
+ modes[B].rates = rates;
+ modes[B].num_rates = 4; /* just CCK */
+ modes[B].num_channels = 0;
+
+ modes[G].mode = MODE_IEEE80211G;
+ modes[G].channels = channels;
+ modes[G].rates = rates;
+ modes[G].num_rates = 12; /* OFDM & CCK */
+ modes[G].num_channels = 0;
+
+ priv->ieee_channels = channels;
+ priv->ieee_rates = rates;
+
+ iwl_init_hw_rates(priv, rates);
+
+ for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
+ ch = &priv->channel_info[i];
+
+ if (!is_channel_valid(ch)) {
+ IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- "
+ "skipping.\n",
+ ch->channel, is_channel_a_band(ch) ?
+ "5.2" : "2.4");
+ continue;
+ }
+
+ if (is_channel_a_band(ch))
+ geo_ch = &modes[A].channels[modes[A].num_channels++];
+ else {
+ geo_ch = &modes[B].channels[modes[B].num_channels++];
+ modes[G].num_channels++;
+ }
+
+ geo_ch->freq = ieee80211chan2mhz(ch->channel);
+ geo_ch->chan = ch->channel;
+ geo_ch->power_level = ch->max_power_avg;
+ geo_ch->antenna_max = 0xff;
+
+ if (is_channel_valid(ch)) {
+ geo_ch->flag = IEEE80211_CHAN_W_SCAN;
+ if (ch->flags & EEPROM_CHANNEL_IBSS)
+ geo_ch->flag |= IEEE80211_CHAN_W_IBSS;
+
+ if (ch->flags & EEPROM_CHANNEL_ACTIVE)
+ geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN;
+
+ if (ch->flags & EEPROM_CHANNEL_RADAR)
+ geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT;
+
+ if (ch->max_power_avg > priv->max_channel_txpower_limit)
+ priv->max_channel_txpower_limit =
+ ch->max_power_avg;
+ }
+
+ geo_ch->val = geo_ch->flag;
+ }
+
+ if ((modes[A].num_channels == 0) && priv->is_abg) {
+ printk(KERN_INFO DRV_NAME
+ ": Incorrectly detected BG card as ABG. Please send "
+ "your PCI ID 0x%04X:0x%04X to maintainer.\n",
+ priv->pci_dev->device, priv->pci_dev->subsystem_device);
+ priv->is_abg = 0;
+ }
+
+ printk(KERN_INFO DRV_NAME
+ ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
+ modes[G].num_channels, modes[A].num_channels);
+
+ /*
+ * NOTE: We register these in preference of order -- the
+ * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick
+ * a phymode based on rates or AP capabilities but seems to
+ * configure it purely on if the channel being configured
+ * is supported by a mode -- and the first match is taken
+ */
+
+ if (modes[G].num_channels)
+ ieee80211_register_hwmode(priv->hw, &modes[G]);
+ if (modes[B].num_channels)
+ ieee80211_register_hwmode(priv->hw, &modes[B]);
+ if (modes[A].num_channels)
+ ieee80211_register_hwmode(priv->hw, &modes[A]);
+
+ priv->modes = modes;
+ set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
+
+static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
+{
+ if (priv->ucode_code.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_code.len,
+ priv->ucode_code.v_addr,
+ priv->ucode_code.p_addr);
+ priv->ucode_code.v_addr = NULL;
+ }
+ if (priv->ucode_data.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_data.len,
+ priv->ucode_data.v_addr,
+ priv->ucode_data.p_addr);
+ priv->ucode_data.v_addr = NULL;
+ }
+ if (priv->ucode_data_backup.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_data_backup.len,
+ priv->ucode_data_backup.v_addr,
+ priv->ucode_data_backup.p_addr);
+ priv->ucode_data_backup.v_addr = NULL;
+ }
+ if (priv->ucode_init.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_init.len,
+ priv->ucode_init.v_addr,
+ priv->ucode_init.p_addr);
+ priv->ucode_init.v_addr = NULL;
+ }
+ if (priv->ucode_init_data.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_init_data.len,
+ priv->ucode_init_data.v_addr,
+ priv->ucode_init_data.p_addr);
+ priv->ucode_init_data.v_addr = NULL;
+ }
+ if (priv->ucode_boot.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_boot.len,
+ priv->ucode_boot.v_addr,
+ priv->ucode_boot.p_addr);
+ priv->ucode_boot.v_addr = NULL;
+ }
+}
+
+/**
+ * iwl_verify_inst_full - verify runtime uCode image in card vs. host,
+ * looking at all data.
+ */
+static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
+{
+ u32 val;
+ u32 save_len = len;
+ int rc = 0;
+ u32 errcnt;
+
+ IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+
+ iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
+
+ errcnt = 0;
+ for (; len > 0; len -= sizeof(u32), image++) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+ IWL_ERROR("uCode INST section is invalid at "
+ "offset 0x%x, is 0x%x, s/b 0x%x\n",
+ save_len - len, val, le32_to_cpu(*image));
+ rc = -EIO;
+ errcnt++;
+ if (errcnt >= 20)
+ break;
+ }
+ }
+
+ iwl_release_restricted_access(priv);
+
+ if (!errcnt)
+ IWL_DEBUG_INFO
+ ("ucode image in INSTRUCTION memory is good\n");
+
+ return rc;
+}
+
+
+/**
+ * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ * using sample data 100 bytes apart. If these sample points are good,
+ * it's a pretty good bet that everything between them is good, too.
+ */
+static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+{
+ u32 val;
+ int rc = 0;
+ u32 errcnt = 0;
+ u32 i;
+
+ IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR,
+ i + RTC_INST_LOWER_BOUND);
+ val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+#if 0 /* Enable this if you want to see details */
+ IWL_ERROR("uCode INST section is invalid at "
+ "offset 0x%x, is 0x%x, s/b 0x%x\n",
+ i, val, *image);
+#endif
+ rc = -EIO;
+ errcnt++;
+ if (errcnt >= 3)
+ break;
+ }
+ }
+
+ iwl_release_restricted_access(priv);
+
+ return rc;
+}
+
+
+/**
+ * iwl_verify_ucode - determine which instruction image is in SRAM,
+ * and verify its contents
+ */
+static int iwl_verify_ucode(struct iwl_priv *priv)
+{
+ __le32 *image;
+ u32 len;
+ int rc = 0;
+
+ /* Try bootstrap */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ rc = iwl_verify_inst_sparse(priv, image, len);
+ if (rc == 0) {
+ IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try initialize */
+ image = (__le32 *)priv->ucode_init.v_addr;
+ len = priv->ucode_init.len;
+ rc = iwl_verify_inst_sparse(priv, image, len);
+ if (rc == 0) {
+ IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try runtime/protocol */
+ image = (__le32 *)priv->ucode_code.v_addr;
+ len = priv->ucode_code.len;
+ rc = iwl_verify_inst_sparse(priv, image, len);
+ if (rc == 0) {
+ IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+
+ /* Show first several data entries in instruction SRAM.
+ * Selection of bootstrap image is arbitrary. */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ rc = iwl_verify_inst_full(priv, image, len);
+
+ return rc;
+}
+
+
+/* check contents of special bootstrap uCode SRAM */
+static int iwl_verify_bsm(struct iwl_priv *priv)
+{
+ __le32 *image = priv->ucode_boot.v_addr;
+ u32 len = priv->ucode_boot.len;
+ u32 reg;
+ u32 val;
+
+ IWL_DEBUG_INFO("Begin verify bsm\n");
+
+ /* verify BSM SRAM contents */
+ val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG);
+ for (reg = BSM_SRAM_LOWER_BOUND;
+ reg < BSM_SRAM_LOWER_BOUND + len;
+ reg += sizeof(u32), image ++) {
+ val = iwl_read_restricted_reg(priv, reg);
+ if (val != le32_to_cpu(*image)) {
+ IWL_ERROR("BSM uCode verification failed at "
+ "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
+ BSM_SRAM_LOWER_BOUND,
+ reg - BSM_SRAM_LOWER_BOUND, len,
+ val, le32_to_cpu(*image));
+ return -EIO;
+ }
+ }
+
+ IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");
+
+ return 0;
+}
+
+/**
+ * iwl_load_bsm - Load bootstrap instructions
+ *
+ * BSM operation:
+ *
+ * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
+ * in special SRAM that does not power down during RFKILL. When powering back
+ * up after power-saving sleeps (or during initial uCode load), the BSM loads
+ * the bootstrap program into the on-board processor, and starts it.
+ *
+ * The bootstrap program loads (via DMA) instructions and data for a new
+ * program from host DRAM locations indicated by the host driver in the
+ * BSM_DRAM_* registers. Once the new program is loaded, it starts
+ * automatically.
+ *
+ * When initializing the NIC, the host driver points the BSM to the
+ * "initialize" uCode image. This uCode sets up some internal data, then
+ * notifies host via "initialize alive" that it is complete.
+ *
+ * The host then replaces the BSM_DRAM_* pointer values to point to the
+ * normal runtime uCode instructions and a backup uCode data cache buffer
+ * (filled initially with starting data values for the on-board processor),
+ * then triggers the "initialize" uCode to load and launch the runtime uCode,
+ * which begins normal operation.
+ *
+ * When doing a power-save shutdown, runtime uCode saves data SRAM into
+ * the backup data cache in DRAM before SRAM is powered down.
+ *
+ * When powering back up, the BSM loads the bootstrap program. This reloads
+ * the runtime uCode instructions and the backup data cache into SRAM,
+ * and re-launches the runtime uCode from where it left off.
+ */
+static int iwl_load_bsm(struct iwl_priv *priv)
+{
+ __le32 *image = priv->ucode_boot.v_addr;
+ u32 len = priv->ucode_boot.len;
+ dma_addr_t pinst;
+ dma_addr_t pdata;
+ u32 inst_len;
+ u32 data_len;
+ int rc;
+ int i;
+ u32 done;
+ u32 reg_offset;
+
+ IWL_DEBUG_INFO("Begin load bsm\n");
+
+ /* make sure bootstrap program is no larger than BSM's SRAM size */
+ if (len > IWL_MAX_BSM_SIZE)
+ return -EINVAL;
+
+ /* Tell bootstrap uCode where to find the "Initialize" uCode
+ * in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965.
+ * NOTE: iwl_initialize_alive_start() will replace these values,
+ * after the "initialize" uCode has run, to point to
+ * runtime/protocol instructions and backup data cache. */
+ pinst = priv->ucode_init.p_addr;
+ pdata = priv->ucode_init_data.p_addr;
+ inst_len = priv->ucode_init.len;
+ data_len = priv->ucode_init_data.len;
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
+
+ /* Fill BSM memory with bootstrap instructions */
+ for (reg_offset = BSM_SRAM_LOWER_BOUND;
+ reg_offset < BSM_SRAM_LOWER_BOUND + len;
+ reg_offset += sizeof(u32), image++)
+ _iwl_write_restricted_reg(priv, reg_offset,
+ le32_to_cpu(*image));
+
+ rc = iwl_verify_bsm(priv);
+ if (rc) {
+ iwl_release_restricted_access(priv);
+ return rc;
+ }
+
+ /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
+ iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0);
+ iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG,
+ RTC_INST_LOWER_BOUND);
+ iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
+
+ /* Load bootstrap code into instruction SRAM now,
+ * to prepare to load "initialize" uCode */
+ iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+ BSM_WR_CTRL_REG_BIT_START);
+
+ /* Wait for load of bootstrap uCode to finish */
+ for (i = 0; i < 100; i++) {
+ done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG);
+ if (!(done & BSM_WR_CTRL_REG_BIT_START))
+ break;
+ udelay(10);
+ }
+ if (i < 100)
+ IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
+ else {
+ IWL_ERROR("BSM write did not complete!\n");
+ return -EIO;
+ }
+
+ /* Enable future boot loads whenever power management unit triggers it
+ * (e.g. when powering back up after power-save shutdown) */
+ iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+ BSM_WR_CTRL_REG_BIT_START_EN);
+
+ iwl_release_restricted_access(priv);
+
+ return 0;
+}
+
+static void iwl_nic_start(struct iwl_priv *priv)
+{
+ /* Remove all resets to allow NIC to operate */
+ iwl_write32(priv, CSR_RESET, 0);
+}
+
+/**
+ * iwl_read_ucode - Read uCode images from disk file.
+ *
+ * Copy into buffers for card to fetch via bus-mastering
+ */
+static int iwl_read_ucode(struct iwl_priv *priv)
+{
+ struct iwl_ucode *ucode;
+ int rc = 0;
+ const struct firmware *ucode_raw;
+ /* firmware file name contains uCode/driver compatibility version */
+ const char *name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode";
+ u8 *src;
+ size_t len;
+ u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
+
+ /* Ask kernel firmware_class module to get the boot firmware off disk.
+ * request_firmware() is synchronous, file is in memory on return. */
+ rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
+ if (rc < 0) {
+ IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc);
+ goto error;
+ }
+
+ IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
+ name, ucode_raw->size);
+
+ /* Make sure that we got at least our header! */
+ if (ucode_raw->size < sizeof(*ucode)) {
+ IWL_ERROR("File size way too small!\n");
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ /* Data from ucode file: header followed by uCode images */
+ ucode = (void *)ucode_raw->data;
+
+ ver = le32_to_cpu(ucode->ver);
+ inst_size = le32_to_cpu(ucode->inst_size);
+ data_size = le32_to_cpu(ucode->data_size);
+ init_size = le32_to_cpu(ucode->init_size);
+ init_data_size = le32_to_cpu(ucode->init_data_size);
+ boot_size = le32_to_cpu(ucode->boot_size);
+
+ IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
+ IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n",
+ inst_size);
+ IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n",
+ data_size);
+ IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n",
+ init_size);
+ IWL_DEBUG_INFO("f/w package hdr init data size = %u\n",
+ init_data_size);
+ IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n",
+ boot_size);
+
+ /* Verify size of file vs. image size info in file's header */
+ if (ucode_raw->size < sizeof(*ucode) +
+ inst_size + data_size + init_size +
+ init_data_size + boot_size) {
+
+ IWL_DEBUG_INFO("uCode file size %d too small\n",
+ (int)ucode_raw->size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ /* Verify that uCode images will fit in card's SRAM */
+ if (inst_size > IWL_MAX_INST_SIZE) {
+ IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n",
+ (int)inst_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ if (data_size > IWL_MAX_DATA_SIZE) {
+ IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n",
+ (int)data_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+ if (init_size > IWL_MAX_INST_SIZE) {
+ IWL_DEBUG_INFO
+ ("uCode init instr len %d too large to fit in card\n",
+ (int)init_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+ if (init_data_size > IWL_MAX_DATA_SIZE) {
+ IWL_DEBUG_INFO
+ ("uCode init data len %d too large to fit in card\n",
+ (int)init_data_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+ if (boot_size > IWL_MAX_BSM_SIZE) {
+ IWL_DEBUG_INFO
+ ("uCode boot instr len %d too large to fit in bsm\n",
+ (int)boot_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ /* Allocate ucode buffers for card's bus-master loading ... */
+
+ /* Runtime instructions and 2 copies of data:
+ * 1) unmodified from disk
+ * 2) backup cache for save/restore during power-downs */
+ priv->ucode_code.len = inst_size;
+ priv->ucode_code.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_code.len,
+ &(priv->ucode_code.p_addr));
+
+ priv->ucode_data.len = data_size;
+ priv->ucode_data.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_data.len,
+ &(priv->ucode_data.p_addr));
+
+ priv->ucode_data_backup.len = data_size;
+ priv->ucode_data_backup.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_data_backup.len,
+ &(priv->ucode_data_backup.p_addr));
+
+
+ /* Initialization instructions and data */
+ priv->ucode_init.len = init_size;
+ priv->ucode_init.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_init.len,
+ &(priv->ucode_init.p_addr));
+
+ priv->ucode_init_data.len = init_data_size;
+ priv->ucode_init_data.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_init_data.len,
+ &(priv->ucode_init_data.p_addr));
+
+ /* Bootstrap (instructions only, no data) */
+ priv->ucode_boot.len = boot_size;
+ priv->ucode_boot.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_boot.len,
+ &(priv->ucode_boot.p_addr));
+
+ if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
+ !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr ||
+ !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr)
+ goto err_pci_alloc;
+
+ /* Copy images into buffers for card's bus-master reads ... */
+
+ /* Runtime instructions (first block of data in file) */
+ src = &ucode->data[0];
+ len = priv->ucode_code.len;
+ IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n",
+ (int)len);
+ memcpy(priv->ucode_code.v_addr, src, len);
+ IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
+ priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
+
+ /* Runtime data (2nd block)
+ * NOTE: Copy into backup buffer will be done in iwl_up() */
+ src = &ucode->data[inst_size];
+ len = priv->ucode_data.len;
+ IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n",
+ (int)len);
+ memcpy(priv->ucode_data.v_addr, src, len);
+ memcpy(priv->ucode_data_backup.v_addr, src, len);
+
+ /* Initialization instructions (3rd block) */
+ if (init_size) {
+ src = &ucode->data[inst_size + data_size];
+ len = priv->ucode_init.len;
+ IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n",
+ (int)len);
+ memcpy(priv->ucode_init.v_addr, src, len);
+ }
+
+ /* Initialization data (4th block) */
+ if (init_data_size) {
+ src = &ucode->data[inst_size + data_size + init_size];
+ len = priv->ucode_init_data.len;
+ IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n",
+ (int)len);
+ memcpy(priv->ucode_init_data.v_addr, src, len);
+ }
+
+ /* Bootstrap instructions (5th block) */
+ src = &ucode->data[inst_size + data_size + init_size + init_data_size];
+ len = priv->ucode_boot.len;
+ IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n",
+ (int)len);
+ memcpy(priv->ucode_boot.v_addr, src, len);
+
+ /* We have our copies now, allow OS release its copies */
+ release_firmware(ucode_raw);
+ return 0;
+
+ err_pci_alloc:
+ IWL_ERROR("failed to allocate pci memory\n");
+ rc = -ENOMEM;
+ iwl_dealloc_ucode_pci(priv);
+
+ err_release:
+ release_firmware(ucode_raw);
+
+ error:
+ return rc;
+}
+
+
+/**
+ * iwl_set_ucode_ptrs - Set uCode address location
+ *
+ * Tell initialization uCode where to find runtime uCode.
+ *
+ * BSM registers initially contain pointers to initialization uCode.
+ * We need to replace them to load runtime uCode inst and data,
+ * and to save runtime data when powering down.
+ */
+static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
+{
+ dma_addr_t pinst;
+ dma_addr_t pdata;
+ int rc = 0;
+ unsigned long flags;
+
+ /* bits 31:0 for 3945 */
+ pinst = priv->ucode_code.p_addr;
+ pdata = priv->ucode_data_backup.p_addr;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ /* Tell bootstrap uCode where to find image to load */
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
+ priv->ucode_data.len);
+
+ /* Inst bytecount must be last to set up, bit 31 signals uCode
+ * that all new ptr/size info is in place */
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG,
+ priv->ucode_code.len | BSM_DRAM_INST_LOAD);
+
+ iwl_release_restricted_access(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
+
+ return rc;
+}
+
+/**
+ * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved
+ *
+ * Called after REPLY_ALIVE notification received from "initialize" uCode.
+ *
+ * The 4965 "initialize" ALIVE reply contains calibration data for:
+ * Voltage, temperature, and MIMO tx gain correction, now stored in priv
+ * (3945 does not contain this data).
+ *
+ * Tell "initialize" uCode to go ahead and load the runtime uCode.
+*/
+static void iwl_init_alive_start(struct iwl_priv *priv)
+{
+ /* Check alive response for "valid" sign from uCode */
+ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+ /* We had an error bringing up the hardware, so take it
+ * all the way back down so we can try again */
+ IWL_DEBUG_INFO("Initialize Alive failed.\n");
+ goto restart;
+ }
+
+ /* Bootstrap uCode has loaded initialize uCode ... verify inst image.
+ * This is a paranoid check, because we would not have gotten the
+ * "initialize" alive if code weren't properly loaded. */
+ if (iwl_verify_ucode(priv)) {
+ /* Runtime instruction load was bad;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
+ goto restart;
+ }
+
+ /* Send pointers to protocol/runtime uCode image ... init code will
+ * load and launch runtime uCode, which will send us another "Alive"
+ * notification. */
+ IWL_DEBUG_INFO("Initialization Alive received.\n");
+ if (iwl_set_ucode_ptrs(priv)) {
+ /* Runtime instruction load won't happen;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
+ goto restart;
+ }
+ return;
+
+ restart:
+ queue_work(priv->workqueue, &priv->restart);
+}
+
+
+/**
+ * iwl_alive_start - called after REPLY_ALIVE notification received
+ * from protocol/runtime uCode (initialization uCode's
+ * Alive gets handled by iwl_init_alive_start()).
+ */
+static void iwl_alive_start(struct iwl_priv *priv)
+{
+ int rc = 0;
+ int thermal_spin = 0;
+ u32 rfkill;
+
+ IWL_DEBUG_INFO("Runtime Alive received.\n");
+
+ if (priv->card_alive.is_valid != UCODE_VALID_OK) {
+ /* We had an error bringing up the hardware, so take it
+ * all the way back down so we can try again */
+ IWL_DEBUG_INFO("Alive failed.\n");
+ goto restart;
+ }
+
+ /* Initialize uCode has loaded Runtime uCode ... verify inst image.
+ * This is a paranoid check, because we would not have gotten the
+ * "runtime" alive if code weren't properly loaded. */
+ if (iwl_verify_ucode(priv)) {
+ /* Runtime instruction load was bad;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Bad runtime uCode load.\n");
+ goto restart;
+ }
+
+ iwl_clear_stations_table(priv);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ IWL_WARNING("Can not read rfkill status from adapter\n");
+ return;
+ }
+
+ rfkill = iwl_read_restricted_reg(priv, APMG_RFKILL_REG);
+ IWL_DEBUG_INFO("RFKILL status: 0x%x\n", rfkill);
+ iwl_release_restricted_access(priv);
+
+ if (rfkill & 0x1) {
+ clear_bit(STATUS_RF_KILL_HW, &priv->status);
+ /* if rfkill is not on, then wait for thermal
+ * sensor in adapter to kick in */
+ while (iwl_hw_get_temperature(priv) == 0) {
+ thermal_spin++;
+ udelay(10);
+ }
+
+ if (thermal_spin)
+ IWL_DEBUG_INFO("Thermal calibration took %dus\n",
+ thermal_spin * 10);
+ } else
+ set_bit(STATUS_RF_KILL_HW, &priv->status);
+
+ /* After the ALIVE response, we can process host commands */
+ set_bit(STATUS_ALIVE, &priv->status);
+
+ /* Clear out the uCode error bit if it is set */
+ clear_bit(STATUS_FW_ERROR, &priv->status);
+
+ rc = iwl_init_channel_map(priv);
+ if (rc) {
+ IWL_ERROR("initializing regulatory failed: %d\n", rc);
+ return;
+ }
+
+ iwl_init_geos(priv);
+
+ if (iwl_is_rfkill(priv))
+ return;
+
+ if (!priv->mac80211_registered) {
+ /* Unlock so any user space entry points can call back into
+ * the driver without a deadlock... */
+ mutex_unlock(&priv->mutex);
+ iwl_rate_control_register(priv->hw);
+ rc = ieee80211_register_hw(priv->hw);
+ priv->hw->conf.beacon_int = 100;
+ mutex_lock(&priv->mutex);
+
+ if (rc) {
+ IWL_ERROR("Failed to register network "
+ "device (error %d)\n", rc);
+ return;
+ }
+
+ priv->mac80211_registered = 1;
+
+ iwl_reset_channel_flag(priv);
+ } else
+ ieee80211_start_queues(priv->hw);
+
+ priv->active_rate = priv->rates_mask;
+ priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+ iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
+
+ if (iwl_is_associated(priv)) {
+ struct iwl_rxon_cmd *active_rxon =
+ (struct iwl_rxon_cmd *)(&priv->active_rxon);
+
+ memcpy(&priv->staging_rxon, &priv->active_rxon,
+ sizeof(priv->staging_rxon));
+ active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ } else {
+ /* Initialize our rx_config data */
+ iwl_connection_init_rx_config(priv);
+ memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+ }
+
+ /* Configure BT coexistence */
+ iwl_send_bt_config(priv);
+
+ /* Configure the adapter for unassociated operation */
+ iwl_commit_rxon(priv);
+
+ /* At this point, the NIC is initialized and operational */
+ priv->notif_missed_beacons = 0;
+ set_bit(STATUS_READY, &priv->status);
+
+ iwl3945_reg_txpower_periodic(priv);
+
+ IWL_DEBUG_INFO("ALIVE processing complete.\n");
+
+ if (priv->error_recovering)
+ iwl_error_recovery(priv);
+
+ return;
+
+ restart:
+ queue_work(priv->workqueue, &priv->restart);
+}
+
+static void iwl_cancel_deferred_work(struct iwl_priv *priv);
+
+static void __iwl_down(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
+ struct ieee80211_conf *conf = NULL;
+
+ IWL_DEBUG_INFO(DRV_NAME " is going down\n");
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ if (!exit_pending)
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
+
+ iwl_clear_stations_table(priv);
+
+ /* Unblock any waiting calls */
+ wake_up_interruptible_all(&priv->wait_command_queue);
+
+ iwl_cancel_deferred_work(priv);
+
+ /* Wipe out the EXIT_PENDING status bit if we are not actually
+ * exiting the module */
+ if (!exit_pending)
+ clear_bit(STATUS_EXIT_PENDING, &priv->status);
+
+ /* stop and reset the on-board processor */
+ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
+ /* tell the device to stop sending interrupts */
+ iwl_disable_interrupts(priv);
+
+ if (priv->mac80211_registered)
+ ieee80211_stop_queues(priv->hw);
+
+ /* If we have not previously called iwl_init() then
+ * clear all bits but the RF Kill and SUSPEND bits and return */
+ if (!iwl_is_init(priv)) {
+ priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+ STATUS_RF_KILL_HW |
+ test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+ STATUS_RF_KILL_SW |
+ test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+ STATUS_IN_SUSPEND;
+ goto exit;
+ }
+
+ /* ...otherwise clear out all the status bits but the RF Kill and
+ * SUSPEND bits and continue taking the NIC down. */
+ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+ STATUS_RF_KILL_HW |
+ test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+ STATUS_RF_KILL_SW |
+ test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+ STATUS_IN_SUSPEND |
+ test_bit(STATUS_FW_ERROR, &priv->status) <<
+ STATUS_FW_ERROR;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_hw_txq_ctx_stop(priv);
+ iwl_hw_rxq_stop(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT);
+ iwl_release_restricted_access(priv);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ udelay(5);
+
+ iwl_hw_nic_stop_master(priv);
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+ iwl_hw_nic_reset(priv);
+
+ exit:
+ memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+ priv->ibss_beacon = NULL;
+
+ /* clear out any free frames */
+ iwl_clear_free_frames(priv);
+}
+
+static void iwl_down(struct iwl_priv *priv)
+{
+ mutex_lock(&priv->mutex);
+ __iwl_down(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+#define MAX_HW_RESTARTS 5
+
+static int __iwl_up(struct iwl_priv *priv)
+{
+ DECLARE_MAC_BUF(mac);
+ int rc, i;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ IWL_WARNING("Exit pending; will not bring the NIC up\n");
+ return -EIO;
+ }
+
+ if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+ IWL_WARNING("Radio disabled by SW RF kill (module "
+ "parameter)\n");
+ return 0;
+ }
+
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+ rc = iwl_hw_nic_init(priv);
+ if (rc) {
+ IWL_ERROR("Unable to int nic\n");
+ return rc;
+ }
+
+ /* make sure rfkill handshake bits are cleared */
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+ /* clear (again), then enable host interrupts */
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+ iwl_enable_interrupts(priv);
+
+ /* really make sure rfkill handshake bits are cleared */
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ /* Copy original ucode data image from disk into backup cache.
+ * This will be used to initialize the on-board processor's
+ * data SRAM for a clean start when the runtime program first loads. */
+ memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
+ priv->ucode_data.len);
+
+ for (i = 0; i < MAX_HW_RESTARTS; i++) {
+
+ iwl_clear_stations_table(priv);
+
+ /* load bootstrap state machine,
+ * load bootstrap program into processor's memory,
+ * prepare to load the "initialize" uCode */
+ rc = iwl_load_bsm(priv);
+
+ if (rc) {
+ IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
+ continue;
+ }
+
+ /* start card; "initialize" will load runtime ucode */
+ iwl_nic_start(priv);
+
+ /* MAC Address location in EEPROM same for 3945/4965 */
+ get_eeprom_mac(priv, priv->mac_addr);
+ IWL_DEBUG_INFO("MAC address: %s\n",
+ print_mac(mac, priv->mac_addr));
+
+ SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+
+ IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
+
+ return 0;
+ }
+
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
+ __iwl_down(priv);
+
+ /* tried to restart and config the device for as long as our
+ * patience could withstand */
+ IWL_ERROR("Unable to initialize device after %d attempts.\n", i);
+ return -EIO;
+}
+
+
+/*****************************************************************************
+ *
+ * Workqueue callbacks
+ *
+ *****************************************************************************/
+
+static void iwl_bg_init_alive_start(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, init_alive_start.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_init_alive_start(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_alive_start(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, alive_start.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_alive_start(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_rf_kill(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
+
+ wake_up_interruptible(&priv->wait_command_queue);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ if (!iwl_is_rfkill(priv)) {
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
+ "HW and/or SW RF Kill no longer active, restarting "
+ "device\n");
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+ queue_work(priv->workqueue, &priv->restart);
+ } else {
+
+ if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
+ IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+ "disabled by SW switch\n");
+ else
+ IWL_WARNING("Radio Frequency Kill Switch is On:\n"
+ "Kill switch must be turned off for "
+ "wireless networking to work.\n");
+ }
+ mutex_unlock(&priv->mutex);
+}
+
+#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
+
+static void iwl_bg_scan_check(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, scan_check.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ if (test_bit(STATUS_SCANNING, &priv->status) ||
+ test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN,
+ "Scan completion watchdog resetting adapter (%dms)\n",
+ jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
+
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+ iwl_send_scan_abort(priv);
+ }
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_request_scan(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, request_scan);
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SCAN_CMD,
+ .len = sizeof(struct iwl_scan_cmd),
+ .meta.flags = CMD_SIZE_HUGE,
+ };
+ int rc = 0;
+ struct iwl_scan_cmd *scan;
+ struct ieee80211_conf *conf = NULL;
+ u8 direct_mask;
+ int phymode;
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ mutex_lock(&priv->mutex);
+
+ if (!iwl_is_ready(priv)) {
+ IWL_WARNING("request scan called when driver not ready.\n");
+ goto done;
+ }
+
+ /* Make sure the scan wasn't cancelled before this queued work
+ * was given the chance to run... */
+ if (!test_bit(STATUS_SCANNING, &priv->status))
+ goto done;
+
+ /* This should never be called or scheduled if there is currently
+ * a scan active in the hardware. */
+ if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+ IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. "
+ "Ignoring second request.\n");
+ rc = -EIO;
+ goto done;
+ }
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n");
+ goto done;
+ }
+
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_HC("Scan request while abort pending. Queuing.\n");
+ goto done;
+ }
+
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
+ goto done;
+ }
+
+ if (!test_bit(STATUS_READY, &priv->status)) {
+ IWL_DEBUG_HC("Scan request while uninitialized. Queuing.\n");
+ goto done;
+ }
+
+ if (!priv->scan_bands) {
+ IWL_DEBUG_HC("Aborting scan due to no requested bands\n");
+ goto done;
+ }
+
+ if (!priv->scan) {
+ priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) +
+ IWL_MAX_SCAN_SIZE, GFP_KERNEL);
+ if (!priv->scan) {
+ rc = -ENOMEM;
+ goto done;
+ }
+ }
+ scan = priv->scan;
+ memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
+
+ scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
+ scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+
+ if (iwl_is_associated(priv)) {
+ u16 interval = 0;
+ u32 extra;
+ u32 suspend_time = 100;
+ u32 scan_suspend_time = 100;
+ unsigned long flags;
+
+ IWL_DEBUG_INFO("Scanning while associated...\n");
+
+ spin_lock_irqsave(&priv->lock, flags);
+ interval = priv->beacon_int;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ scan->suspend_time = 0;
+ scan->max_out_time = cpu_to_le32(200 * 1024);
+ if (!interval)
+ interval = suspend_time;
+ /*
+ * suspend time format:
+ * 0-19: beacon interval in usec (time before exec.)
+ * 20-23: 0
+ * 24-31: number of beacons (suspend between channels)
+ */
+
+ extra = (suspend_time / interval) << 24;
+ scan_suspend_time = 0xFF0FFFFF &
+ (extra | ((suspend_time % interval) * 1024));
+
+ scan->suspend_time = cpu_to_le32(scan_suspend_time);
+ IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n",
+ scan_suspend_time, interval);
+ }
+
+ /* We should add the ability for user to lock to PASSIVE ONLY */
+ if (priv->one_direct_scan) {
+ IWL_DEBUG_SCAN
+ ("Kicking off one direct scan for '%s'\n",
+ iwl_escape_essid(priv->direct_ssid,
+ priv->direct_ssid_len));
+ scan->direct_scan[0].id = WLAN_EID_SSID;
+ scan->direct_scan[0].len = priv->direct_ssid_len;
+ memcpy(scan->direct_scan[0].ssid,
+ priv->direct_ssid, priv->direct_ssid_len);
+ direct_mask = 1;
+ } else if (!iwl_is_associated(priv) && priv->essid_len) {
+ scan->direct_scan[0].id = WLAN_EID_SSID;
+ scan->direct_scan[0].len = priv->essid_len;
+ memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
+ direct_mask = 1;
+ } else
+ direct_mask = 0;
+
+ /* We don't build a direct scan probe request; the uCode will do
+ * that based on the direct_mask added to each channel entry */
+ scan->tx_cmd.len = cpu_to_le16(
+ iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
+ IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
+ scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
+ scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
+ scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+ /* flags + rate selection */
+
+ switch (priv->scan_bands) {
+ case 2:
+ scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
+ scan->tx_cmd.rate = IWL_RATE_1M_PLCP;
+ scan->good_CRC_th = 0;
+ phymode = MODE_IEEE80211G;
+ break;
+
+ case 1:
+ scan->tx_cmd.rate = IWL_RATE_6M_PLCP;
+ scan->good_CRC_th = IWL_GOOD_CRC_TH;
+ phymode = MODE_IEEE80211A;
+ break;
+
+ default:
+ IWL_WARNING("Invalid scan band count\n");
+ goto done;
+ }
+
+ /* select Rx antennas */
+ scan->flags |= iwl3945_get_antenna_flags(priv);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
+ scan->filter_flags = RXON_FILTER_PROMISC_MSK;
+
+ if (direct_mask)
+ IWL_DEBUG_SCAN
+ ("Initiating direct scan for %s.\n",
+ iwl_escape_essid(priv->essid, priv->essid_len));
+ else
+ IWL_DEBUG_SCAN("Initiating indirect scan.\n");
+
+ scan->channel_count =
+ iwl_get_channels_for_scan(
+ priv, phymode, 1, /* active */
+ direct_mask,
+ (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+
+ cmd.len += le16_to_cpu(scan->tx_cmd.len) +
+ scan->channel_count * sizeof(struct iwl_scan_channel);
+ cmd.data = scan;
+ scan->len = cpu_to_le16(cmd.len);
+
+ set_bit(STATUS_SCAN_HW, &priv->status);
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ goto done;
+
+ queue_delayed_work(priv->workqueue, &priv->scan_check,
+ IWL_SCAN_CHECK_WATCHDOG);
+
+ mutex_unlock(&priv->mutex);
+ return;
+
+ done:
+ /* inform mac80211 sacn aborted */
+ queue_work(priv->workqueue, &priv->scan_completed);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_up(struct work_struct *data)
+{
+ struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ __iwl_up(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_restart(struct work_struct *data)
+{
+ struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ iwl_down(priv);
+ queue_work(priv->workqueue, &priv->up);
+}
+
+static void iwl_bg_rx_replenish(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, rx_replenish);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_rx_replenish(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_post_associate(struct work_struct *data)
+{
+ struct iwl_priv *priv = container_of(data, struct iwl_priv,
+ post_associate.work);
+
+ int rc = 0;
+ struct ieee80211_conf *conf = NULL;
+ DECLARE_MAC_BUF(mac);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
+ return;
+ }
+
+
+ IWL_DEBUG_ASSOC("Associated as %d to: %s\n",
+ priv->assoc_id,
+ print_mac(mac, priv->active_rxon.bssid_addr));
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ if (!priv->interface_id || !priv->is_open) {
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+ iwl_scan_cancel_timeout(priv, 200);
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
+ iwl_setup_rxon_timing(priv);
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+ sizeof(priv->rxon_timing), &priv->rxon_timing);
+ if (rc)
+ IWL_WARNING("REPLY_RXON_TIMING failed - "
+ "Attempting to continue.\n");
+
+ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+
+ priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+
+ IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n",
+ priv->assoc_id, priv->beacon_int);
+
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ }
+
+ iwl_commit_rxon(priv);
+
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_STA:
+ iwl_rate_scale_init(priv->hw, IWL_AP_ID);
+ break;
+
+ case IEEE80211_IF_TYPE_IBSS:
+
+ /* clear out the station table */
+ iwl_clear_stations_table(priv);
+
+ iwl_add_station(priv, BROADCAST_ADDR, 0, 0);
+ iwl_add_station(priv, priv->bssid, 0, 0);
+ iwl3945_sync_sta(priv, IWL_STA_ID,
+ (priv->phymode == MODE_IEEE80211A)?
+ IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
+ CMD_ASYNC);
+ iwl_rate_scale_init(priv->hw, IWL_STA_ID);
+ iwl_send_beacon_cmd(priv);
+
+ break;
+
+ default:
+ IWL_ERROR("%s Should not be called in %d mode\n",
+ __FUNCTION__, priv->iw_mode);
+ break;
+ }
+
+ iwl_sequence_reset(priv);
+
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_activate_qos(priv, 0);
+#endif /* CONFIG_IWLWIFI_QOS */
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_abort_scan(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ abort_scan);
+
+ if (!iwl_is_ready(priv))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ set_bit(STATUS_SCAN_ABORTING, &priv->status);
+ iwl_send_scan_abort(priv);
+
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_scan_completed(struct work_struct *work)
+{
+ struct iwl_priv *priv =
+ container_of(work, struct iwl_priv, scan_completed);
+
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n");
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ ieee80211_scan_completed(priv->hw);
+
+ /* Since setting the TXPOWER may have been deferred while
+ * performing the scan, fire one off */
+ mutex_lock(&priv->mutex);
+ iwl_hw_reg_send_txpower(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+/*****************************************************************************
+ *
+ * mac80211 entry point functions
+ *
+ *****************************************************************************/
+
+static int iwl_mac_start(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ /* we should be verifying the device is ready to be opened */
+ mutex_lock(&priv->mutex);
+
+ priv->is_open = 1;
+
+ if (!iwl_is_rfkill(priv))
+ ieee80211_start_queues(priv->hw);
+
+ mutex_unlock(&priv->mutex);
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static void iwl_mac_stop(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+
+ mutex_lock(&priv->mutex);
+ /* stop mac, cancel any scan request and clear
+ * RXON_FILTER_ASSOC_MSK BIT
+ */
+ priv->is_open = 0;
+ iwl_scan_cancel_timeout(priv, 100);
+ cancel_delayed_work(&priv->post_associate);
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("leave\n");
+}
+
+static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+ IWL_DEBUG_MAC80211("leave - monitor\n");
+ return -1;
+ }
+
+ IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
+ ctl->tx_rate);
+
+ if (iwl_tx_skb(priv, skb, ctl))
+ dev_kfree_skb_any(skb);
+
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static int iwl_mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type);
+ if (conf->mac_addr)
+ IWL_DEBUG_MAC80211("enter: MAC %s\n",
+ print_mac(mac, conf->mac_addr));
+
+ if (priv->interface_id) {
+ IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
+ return 0;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->interface_id = conf->if_id;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ mutex_lock(&priv->mutex);
+ iwl_set_mode(priv, conf->type);
+
+ IWL_DEBUG_MAC80211("leave\n");
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+/**
+ * iwl_mac_config - mac80211 config callback
+ *
+ * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
+ * be set inappropriately and the driver currently sets the hardware up to
+ * use it whenever needed.
+ */
+static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ const struct iwl_channel_info *ch_info;
+ unsigned long flags;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
+
+ if (!iwl_is_ready(priv)) {
+ IWL_DEBUG_MAC80211("leave - not ready\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
+ * what is exposed through include/ declrations */
+ if (unlikely(!iwl_param_disable_hw_scan &&
+ test_bit(STATUS_SCANNING, &priv->status))) {
+ IWL_DEBUG_MAC80211("leave - scanning\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
+ conf->channel, conf->phymode);
+ IWL_DEBUG_MAC80211("leave - invalid channel\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+ mutex_unlock(&priv->mutex);
+ return -EINVAL;
+ }
+
+ iwl_set_rxon_channel(priv, conf->phymode, conf->channel);
+
+ iwl_set_flags_for_phymode(priv, conf->phymode);
+
+ /* The list of supported rates and rate mask can be different
+ * for each phymode; since the phymode may have changed, reset
+ * the rate mask to what mac80211 lists */
+ iwl_set_rate(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef IEEE80211_CONF_CHANNEL_SWITCH
+ if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
+ iwl_hw_channel_switch(priv, conf->channel);
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+#endif
+
+ iwl_radio_kill_sw(priv, !conf->radio_enabled);
+
+ if (!conf->radio_enabled) {
+ IWL_DEBUG_MAC80211("leave - radio disabled\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF kill\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ iwl_set_rate(priv);
+
+ if (memcmp(&priv->active_rxon,
+ &priv->staging_rxon, sizeof(priv->staging_rxon)))
+ iwl_commit_rxon(priv);
+ else
+ IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void iwl_config_ap(struct iwl_priv *priv)
+{
+ int rc = 0;
+
+ if (priv->status & STATUS_EXIT_PENDING)
+ return;
+
+ /* The following should be done only at AP bring up */
+ if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) {
+
+ /* RXON - unassoc (to set timing command) */
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ /* RXON Timing */
+ memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
+ iwl_setup_rxon_timing(priv);
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+ sizeof(priv->rxon_timing), &priv->rxon_timing);
+ if (rc)
+ IWL_WARNING("REPLY_RXON_TIMING failed - "
+ "Attempting to continue.\n");
+
+ /* FIXME: what should be the assoc_id for AP? */
+ priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ priv->staging_rxon.flags |=
+ RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ priv->staging_rxon.flags &=
+ ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+ if (priv->assoc_capability &
+ WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ priv->staging_rxon.flags |=
+ RXON_FLG_SHORT_SLOT_MSK;
+ else
+ priv->staging_rxon.flags &=
+ ~RXON_FLG_SHORT_SLOT_MSK;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->staging_rxon.flags &=
+ ~RXON_FLG_SHORT_SLOT_MSK;
+ }
+ /* restore RXON assoc */
+ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+ iwl_add_station(priv, BROADCAST_ADDR, 0, 0);
+ }
+ iwl_send_beacon_cmd(priv);
+
+ /* FIXME - we need to add code here to detect a totally new
+ * configuration, reset the AP, unassoc, rxon timing, assoc,
+ * clear sta table, add BCAST sta... */
+}
+
+static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ DECLARE_MAC_BUF(mac);
+ unsigned long flags;
+ int rc;
+
+ if (conf == NULL)
+ return -EIO;
+
+ /* XXX: this MUST use conf->mac_addr */
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+ (!conf->beacon || !conf->ssid_len)) {
+ IWL_DEBUG_MAC80211
+ ("Leaving in AP mode because HostAPD is not ready.\n");
+ return 0;
+ }
+
+ mutex_lock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
+ if (conf->bssid)
+ IWL_DEBUG_MAC80211("bssid: %s\n",
+ print_mac(mac, conf->bssid));
+
+/*
+ * very dubious code was here; the probe filtering flag is never set:
+ *
+ if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
+ !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
+ */
+ if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
+ IWL_DEBUG_MAC80211("leave - scanning\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ if (priv->interface_id != if_id) {
+ IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (!conf->bssid) {
+ conf->bssid = priv->mac_addr;
+ memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
+ IWL_DEBUG_MAC80211("bssid was set to: %s\n",
+ print_mac(mac, conf->bssid));
+ }
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = conf->beacon;
+ }
+
+ if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
+ !is_multicast_ether_addr(conf->bssid)) {
+ /* If there is currently a HW scan going on in the background
+ * then we need to cancel it else the RXON below will fail. */
+ if (iwl_scan_cancel_timeout(priv, 100)) {
+ IWL_WARNING("Aborted scan still in progress "
+ "after 100ms\n");
+ IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+ mutex_unlock(&priv->mutex);
+ return -EAGAIN;
+ }
+ memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN);
+
+ /* TODO: Audit driver for usage of these members and see
+ * if mac80211 deprecates them (priv->bssid looks like it
+ * shouldn't be there, but I haven't scanned the IBSS code
+ * to verify) - jpk */
+ memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ iwl_config_ap(priv);
+ else {
+ rc = iwl_commit_rxon(priv);
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
+ iwl_add_station(priv,
+ priv->active_rxon.bssid_addr, 1, 0);
+ }
+
+ } else {
+ iwl_scan_cancel_timeout(priv, 100);
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!conf->ssid_len)
+ memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+ else
+ memcpy(priv->essid, conf->ssid, conf->ssid_len);
+
+ priv->essid_len = conf->ssid_len;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_MAC80211("leave\n");
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void iwl_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_addr_list *mc_list)
+{
+ /*
+ * XXX: dummy
+ * see also iwl_connection_init_rx_config
+ */
+ *total_flags = 0;
+}
+
+static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ mutex_lock(&priv->mutex);
+
+ iwl_scan_cancel_timeout(priv, 100);
+ cancel_delayed_work(&priv->post_associate);
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ if (priv->interface_id == conf->if_id) {
+ priv->interface_id = 0;
+ memset(priv->bssid, 0, ETH_ALEN);
+ memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+ priv->essid_len = 0;
+ }
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+#define IWL_DELAY_NEXT_SCAN (HZ*2)
+static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ mutex_lock(&priv->mutex);
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (!iwl_is_ready_rf(priv)) {
+ rc = -EIO;
+ IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
+ goto out_unlock;
+ }
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */
+ rc = -EIO;
+ IWL_ERROR("ERROR: APs don't scan\n");
+ goto out_unlock;
+ }
+
+ /* if we just finished scan ask for delay */
+ if (priv->last_scan_jiffies &&
+ time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
+ jiffies)) {
+ rc = -EAGAIN;
+ goto out_unlock;
+ }
+ if (len) {
+ IWL_DEBUG_SCAN("direct scan for "
+ "%s [%d]\n ",
+ iwl_escape_essid(ssid, len), (int)len);
+
+ priv->one_direct_scan = 1;
+ priv->direct_ssid_len = (u8)
+ min((u8) len, (u8) IW_ESSID_MAX_SIZE);
+ memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
+ } else
+ priv->one_direct_scan = 0;
+
+ rc = iwl_scan_initiate(priv);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+out_unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ mutex_unlock(&priv->mutex);
+
+ return rc;
+}
+
+static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ const u8 *local_addr, const u8 *addr,
+ struct ieee80211_key_conf *key)
+{
+ struct iwl_priv *priv = hw->priv;
+ int rc = 0;
+ u8 sta_id;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_param_hwcrypto) {
+ IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (is_zero_ether_addr(addr))
+ /* only support pairwise keys */
+ return -EOPNOTSUPP;
+
+ sta_id = iwl_hw_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION) {
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
+ print_mac(mac, addr));
+ return -EINVAL;
+ }
+
+ mutex_lock(&priv->mutex);
+
+ iwl_scan_cancel_timeout(priv, 100);
+
+ switch (cmd) {
+ case SET_KEY:
+ rc = iwl_update_sta_key_info(priv, key, sta_id);
+ if (!rc) {
+ iwl_set_rxon_hwcrypto(priv, 1);
+ iwl_commit_rxon(priv);
+ key->hw_key_idx = sta_id;
+ IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n");
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ }
+ break;
+ case DISABLE_KEY:
+ rc = iwl_clear_sta_key_info(priv, sta_id);
+ if (!rc) {
+ iwl_set_rxon_hwcrypto(priv, 0);
+ iwl_commit_rxon(priv);
+ IWL_DEBUG_MAC80211("disable hwcrypto key\n");
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ }
+
+ IWL_DEBUG_MAC80211("leave\n");
+ mutex_unlock(&priv->mutex);
+
+ return rc;
+}
+
+static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct iwl_priv *priv = hw->priv;
+#ifdef CONFIG_IWLWIFI_QOS
+ unsigned long flags;
+ int q;
+#endif /* CONFIG_IWL_QOS */
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF not ready\n");
+ return -EIO;
+ }
+
+ if (queue >= AC_NUM) {
+ IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue);
+ return 0;
+ }
+
+#ifdef CONFIG_IWLWIFI_QOS
+ if (!priv->qos_data.qos_enable) {
+ priv->qos_data.qos_active = 0;
+ IWL_DEBUG_MAC80211("leave - qos not enabled\n");
+ return 0;
+ }
+ q = AC_NUM - 1 - queue;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
+ priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
+ priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+ priv->qos_data.def_qos_parm.ac[q].edca_txop =
+ cpu_to_le16((params->burst_time * 100));
+
+ priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+ priv->qos_data.qos_active = 1;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ mutex_lock(&priv->mutex);
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ iwl_activate_qos(priv, 1);
+ else if (priv->assoc_id && iwl_is_associated(priv))
+ iwl_activate_qos(priv, 0);
+
+ mutex_unlock(&priv->mutex);
+
+#endif /*CONFIG_IWLWIFI_QOS */
+
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct iwl_priv *priv = hw->priv;
+ int i, avail;
+ struct iwl_tx_queue *txq;
+ struct iwl_queue *q;
+ unsigned long flags;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF not ready\n");
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ for (i = 0; i < AC_NUM; i++) {
+ txq = &priv->txq[i];
+ q = &txq->q;
+ avail = iwl_queue_space(q);
+
+ stats->data[i].len = q->n_window - avail;
+ stats->data[i].limit = q->n_window - q->high_mark;
+ stats->data[i].count = q->n_window;
+
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+ return 0;
+}
+
+static int iwl_mac_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ IWL_DEBUG_MAC80211("enter\n");
+ IWL_DEBUG_MAC80211("leave\n");
+
+ return 0;
+}
+
+static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
+{
+ IWL_DEBUG_MAC80211("enter\n");
+ IWL_DEBUG_MAC80211("leave\n");
+
+ return 0;
+}
+
+static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211("enter\n");
+
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_reset_qos(priv);
+#endif
+ cancel_delayed_work(&priv->post_associate);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->assoc_id = 0;
+ priv->assoc_capability = 0;
+ priv->call_post_assoc_from_beacon = 0;
+
+ /* new association get rid of ibss beacon skb */
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = NULL;
+
+ priv->beacon_int = priv->hw->conf.beacon_int;
+ priv->timestamp1 = 0;
+ priv->timestamp0 = 0;
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
+ priv->beacon_int = 0;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* we are restarting association process
+ * clear RXON_FILTER_ASSOC_MSK bit
+ */
+ if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+ iwl_scan_cancel_timeout(priv, 100);
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+ }
+
+ /* Per mac80211.h: This is only used in IBSS mode... */
+ if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+
+ IWL_DEBUG_MAC80211("leave - not in IBSS\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - not ready\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ priv->only_active_channel = 0;
+
+ iwl_set_rate(priv);
+
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF not ready\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+ IWL_DEBUG_MAC80211("leave - not IBSS\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = skb;
+
+ priv->assoc_id = 0;
+
+ IWL_DEBUG_MAC80211("leave\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_reset_qos(priv);
+#endif
+
+ queue_work(priv->workqueue, &priv->post_associate.work);
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * sysfs attributes
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/*
+ * The following adds a new attribute to the sysfs representation
+ * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/)
+ * used for controlling the debug level.
+ *
+ * See the level definitions in iwl for details.
+ */
+
+static ssize_t show_debug_level(struct device_driver *d, char *buf)
+{
+ return sprintf(buf, "0x%08X\n", iwl_debug_level);
+}
+static ssize_t store_debug_level(struct device_driver *d,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+ u32 val;
+
+ val = simple_strtoul(p, &p, 0);
+ if (p == buf)
+ printk(KERN_INFO DRV_NAME
+ ": %s is not in hex or decimal form.\n", buf);
+ else
+ iwl_debug_level = val;
+
+ return strnlen(buf, count);
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+ show_debug_level, store_debug_level);
+
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+static ssize_t show_rf_kill(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ /*
+ * 0 - RF kill not enabled
+ * 1 - SW based RF kill active (sysfs)
+ * 2 - HW based RF kill active
+ * 3 - Both HW and SW based RF kill active
+ */
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
+ (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);
+
+ return sprintf(buf, "%i\n", val);
+}
+
+static ssize_t store_rf_kill(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ mutex_lock(&priv->mutex);
+ iwl_radio_kill_sw(priv, buf[0] == '1');
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
+
+static ssize_t show_temperature(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv));
+}
+
+static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
+
+static ssize_t show_rs_window(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iwl_priv *priv = d->driver_data;
+ return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID);
+}
+static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
+
+static ssize_t show_tx_power(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ return sprintf(buf, "%d\n", priv->user_txpower_limit);
+}
+
+static ssize_t store_tx_power(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ char *p = (char *)buf;
+ u32 val;
+
+ val = simple_strtoul(p, &p, 10);
+ if (p == buf)
+ printk(KERN_INFO DRV_NAME
+ ": %s is not in decimal form.\n", buf);
+ else
+ iwl_hw_reg_set_txpower(priv, val);
+
+ return count;
+}
+
+static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
+
+static ssize_t show_flags(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
+}
+
+static ssize_t store_flags(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ u32 flags = simple_strtoul(buf, NULL, 0);
+
+ mutex_lock(&priv->mutex);
+ if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
+ /* Cancel any currently running scans... */
+ if (iwl_scan_cancel_timeout(priv, 100))
+ IWL_WARNING("Could not cancel scan.\n");
+ else {
+ IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n",
+ flags);
+ priv->staging_rxon.flags = cpu_to_le32(flags);
+ iwl_commit_rxon(priv);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
+
+static ssize_t show_filter_flags(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ return sprintf(buf, "0x%04X\n",
+ le32_to_cpu(priv->active_rxon.filter_flags));
+}
+
+static ssize_t store_filter_flags(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ u32 filter_flags = simple_strtoul(buf, NULL, 0);
+
+ mutex_lock(&priv->mutex);
+ if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
+ /* Cancel any currently running scans... */
+ if (iwl_scan_cancel_timeout(priv, 100))
+ IWL_WARNING("Could not cancel scan.\n");
+ else {
+ IWL_DEBUG_INFO("Committing rxon.filter_flags = "
+ "0x%04X\n", filter_flags);
+ priv->staging_rxon.filter_flags =
+ cpu_to_le32(filter_flags);
+ iwl_commit_rxon(priv);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
+ store_filter_flags);
+
+static ssize_t show_tune(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ return sprintf(buf, "0x%04X\n",
+ (priv->phymode << 8) |
+ le16_to_cpu(priv->active_rxon.channel));
+}
+
+static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode);
+
+static ssize_t store_tune(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ char *p = (char *)buf;
+ u16 tune = simple_strtoul(p, &p, 0);
+ u8 phymode = (tune >> 8) & 0xff;
+ u16 channel = tune & 0xff;
+
+ IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel);
+
+ mutex_lock(&priv->mutex);
+ if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
+ (priv->phymode != phymode)) {
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv, phymode, channel);
+ if (!ch_info) {
+ IWL_WARNING("Requested invalid phymode/channel "
+ "combination: %d %d\n", phymode, channel);
+ mutex_unlock(&priv->mutex);
+ return -EINVAL;
+ }
+
+ /* Cancel any currently running scans... */
+ if (iwl_scan_cancel_timeout(priv, 100))
+ IWL_WARNING("Could not cancel scan.\n");
+ else {
+ IWL_DEBUG_INFO("Committing phymode and "
+ "rxon.channel = %d %d\n",
+ phymode, channel);
+
+ iwl_set_rxon_channel(priv, phymode, channel);
+ iwl_set_flags_for_phymode(priv, phymode);
+
+ iwl_set_rate(priv);
+ iwl_commit_rxon(priv);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+static ssize_t show_measurement(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ struct iwl_spectrum_notification measure_report;
+ u32 size = sizeof(measure_report), len = 0, ofs = 0;
+ u8 *data = (u8 *) & measure_report;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!(priv->measurement_status & MEASUREMENT_READY)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
+ }
+ memcpy(&measure_report, &priv->measure_report, size);
+ priv->measurement_status = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while (size && (PAGE_SIZE - len)) {
+ hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+ PAGE_SIZE - len, 1);
+ len = strlen(buf);
+ if (PAGE_SIZE - len)
+ buf[len++] = '\n';
+
+ ofs += 16;
+ size -= min(size, 16U);
+ }
+
+ return len;
+}
+
+static ssize_t store_measurement(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ struct ieee80211_measurement_params params = {
+ .channel = le16_to_cpu(priv->active_rxon.channel),
+ .start_time = cpu_to_le64(priv->last_tsf),
+ .duration = cpu_to_le16(1),
+ };
+ u8 type = IWL_MEASURE_BASIC;
+ u8 buffer[32];
+ u8 channel;
+
+ if (count) {
+ char *p = buffer;
+ strncpy(buffer, buf, min(sizeof(buffer), count));
+ channel = simple_strtoul(p, NULL, 0);
+ if (channel)
+ params.channel = channel;
+
+ p = buffer;
+ while (*p && *p != ' ')
+ p++;
+ if (*p)
+ type = simple_strtoul(p + 1, NULL, 0);
+ }
+
+ IWL_DEBUG_INFO("Invoking measurement of type %d on "
+ "channel %d (for '%s')\n", type, params.channel, buf);
+ iwl_get_measurement(priv, &params, type);
+
+ return count;
+}
+
+static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
+ show_measurement, store_measurement);
+#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */
+
+static ssize_t show_rate(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ if (priv->iw_mode == IEEE80211_IF_TYPE_STA)
+ i = priv->stations[IWL_AP_ID].current_rate.s.rate;
+ else
+ i = priv->stations[IWL_STA_ID].current_rate.s.rate;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ i = iwl_rate_index_from_plcp(i);
+ if (i == -1)
+ return sprintf(buf, "0\n");
+
+ return sprintf(buf, "%d%s\n",
+ (iwl_rates[i].ieee >> 1),
+ (iwl_rates[i].ieee & 0x1) ? ".5" : "");
+}
+
+static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL);
+
+static ssize_t store_retry_rate(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ priv->retry_rate = simple_strtoul(buf, NULL, 0);
+ if (priv->retry_rate <= 0)
+ priv->retry_rate = 1;
+
+ return count;
+}
+
+static ssize_t show_retry_rate(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ return sprintf(buf, "%d", priv->retry_rate);
+}
+
+static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate,
+ store_retry_rate);
+
+static ssize_t store_power_level(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ int rc;
+ int mode;
+
+ mode = simple_strtoul(buf, NULL, 0);
+ mutex_lock(&priv->mutex);
+
+ if (!iwl_is_ready(priv)) {
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC))
+ mode = IWL_POWER_AC;
+ else
+ mode |= IWL_POWER_ENABLED;
+
+ if (mode != priv->power_mode) {
+ rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode));
+ if (rc) {
+ IWL_DEBUG_MAC80211("failed setting power mode.\n");
+ goto out;
+ }
+ priv->power_mode = mode;
+ }
+
+ rc = count;
+
+ out:
+ mutex_unlock(&priv->mutex);
+ return rc;
+}
+
+#define MAX_WX_STRING 80
+
+/* Values are in microsecond */
+static const s32 timeout_duration[] = {
+ 350000,
+ 250000,
+ 75000,
+ 37000,
+ 25000,
+};
+static const s32 period_duration[] = {
+ 400000,
+ 700000,
+ 1000000,
+ 1000000,
+ 1000000
+};
+
+static ssize_t show_power_level(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ int level = IWL_POWER_LEVEL(priv->power_mode);
+ char *p = buf;
+
+ p += sprintf(p, "%d ", level);
+ switch (level) {
+ case IWL_POWER_MODE_CAM:
+ case IWL_POWER_AC:
+ p += sprintf(p, "(AC)");
+ break;
+ case IWL_POWER_BATTERY:
+ p += sprintf(p, "(BATTERY)");
+ break;
+ default:
+ p += sprintf(p,
+ "(Timeout %dms, Period %dms)",
+ timeout_duration[level - 1] / 1000,
+ period_duration[level - 1] / 1000);
+ }
+
+ if (!(priv->power_mode & IWL_POWER_ENABLED))
+ p += sprintf(p, " OFF\n");
+ else
+ p += sprintf(p, " \n");
+
+ return (p - buf + 1);
+
+}
+
+static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
+ store_power_level);
+
+static ssize_t show_channels(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ int len = 0, i;
+ struct ieee80211_channel *channels = NULL;
+ const struct ieee80211_hw_mode *hw_mode = NULL;
+ int count = 0;
+
+ if (!iwl_is_ready(priv))
+ return -EAGAIN;
+
+ hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G);
+ if (!hw_mode)
+ hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B);
+ if (hw_mode) {
+ channels = hw_mode->channels;
+ count = hw_mode->num_channels;
+ }
+
+ len +=
+ sprintf(&buf[len],
+ "Displaying %d channels in 2.4GHz band "
+ "(802.11bg):\n", count);
+
+ for (i = 0; i < count; i++)
+ len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+ channels[i].chan,
+ channels[i].power_level,
+ channels[i].
+ flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+ " (IEEE 802.11h required)" : "",
+ (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+ || (channels[i].
+ flag &
+ IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+ ", IBSS",
+ channels[i].
+ flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+ "active/passive" : "passive only");
+
+ hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A);
+ if (hw_mode) {
+ channels = hw_mode->channels;
+ count = hw_mode->num_channels;
+ } else {
+ channels = NULL;
+ count = 0;
+ }
+
+ len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band "
+ "(802.11a):\n", count);
+
+ for (i = 0; i < count; i++)
+ len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+ channels[i].chan,
+ channels[i].power_level,
+ channels[i].
+ flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+ " (IEEE 802.11h required)" : "",
+ (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+ || (channels[i].
+ flag &
+ IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+ ", IBSS",
+ channels[i].
+ flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+ "active/passive" : "passive only");
+
+ return len;
+}
+
+static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+
+static ssize_t show_statistics(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ u32 size = sizeof(struct iwl_notif_statistics);
+ u32 len = 0, ofs = 0;
+ u8 *data = (u8 *) & priv->statistics;
+ int rc = 0;
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ mutex_lock(&priv->mutex);
+ rc = iwl_send_statistics_request(priv);
+ mutex_unlock(&priv->mutex);
+
+ if (rc) {
+ len = sprintf(buf,
+ "Error sending statistics request: 0x%08X\n", rc);
+ return len;
+ }
+
+ while (size && (PAGE_SIZE - len)) {
+ hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+ PAGE_SIZE - len, 1);
+ len = strlen(buf);
+ if (PAGE_SIZE - len)
+ buf[len++] = '\n';
+
+ ofs += 16;
+ size -= min(size, 16U);
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
+
+static ssize_t show_antenna(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ return sprintf(buf, "%d\n", priv->antenna);
+}
+
+static ssize_t store_antenna(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ant;
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ if (count == 0)
+ return 0;
+
+ if (sscanf(buf, "%1i", &ant) != 1) {
+ IWL_DEBUG_INFO("not in hex or decimal form.\n");
+ return count;
+ }
+
+ if ((ant >= 0) && (ant <= 2)) {
+ IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
+ priv->antenna = (enum iwl_antenna)ant;
+ } else
+ IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
+
+
+ return count;
+}
+
+static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
+
+static ssize_t show_status(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+ return sprintf(buf, "0x%08x\n", (int)priv->status);
+}
+
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t dump_error_log(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+
+ if (p[0] == '1')
+ iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data);
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
+
+static ssize_t dump_event_log(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+
+ if (p[0] == '1')
+ iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data);
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
+
+/*****************************************************************************
+ *
+ * driver setup and teardown
+ *
+ *****************************************************************************/
+
+static void iwl_setup_deferred_work(struct iwl_priv *priv)
+{
+ priv->workqueue = create_workqueue(DRV_NAME);
+
+ init_waitqueue_head(&priv->wait_command_queue);
+
+ INIT_WORK(&priv->up, iwl_bg_up);
+ INIT_WORK(&priv->restart, iwl_bg_restart);
+ INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
+ INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
+ INIT_WORK(&priv->request_scan, iwl_bg_request_scan);
+ INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
+ INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
+ INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
+ INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate);
+ INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
+ INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
+ INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
+
+ iwl_hw_setup_deferred_work(priv);
+
+ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+ iwl_irq_tasklet, (unsigned long)priv);
+}
+
+static void iwl_cancel_deferred_work(struct iwl_priv *priv)
+{
+ iwl_hw_cancel_deferred_work(priv);
+
+ cancel_delayed_work(&priv->scan_check);
+ cancel_delayed_work(&priv->alive_start);
+ cancel_delayed_work(&priv->post_associate);
+ cancel_work_sync(&priv->beacon_update);
+}
+
+static struct attribute *iwl_sysfs_entries[] = {
+ &dev_attr_antenna.attr,
+ &dev_attr_channels.attr,
+ &dev_attr_dump_errors.attr,
+ &dev_attr_dump_events.attr,
+ &dev_attr_flags.attr,
+ &dev_attr_filter_flags.attr,
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+ &dev_attr_measurement.attr,
+#endif
+ &dev_attr_power_level.attr,
+ &dev_attr_rate.attr,
+ &dev_attr_retry_rate.attr,
+ &dev_attr_rf_kill.attr,
+ &dev_attr_rs_window.attr,
+ &dev_attr_statistics.attr,
+ &dev_attr_status.attr,
+ &dev_attr_temperature.attr,
+ &dev_attr_tune.attr,
+ &dev_attr_tx_power.attr,
+
+ NULL
+};
+
+static struct attribute_group iwl_attribute_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = iwl_sysfs_entries,
+};
+
+static struct ieee80211_ops iwl_hw_ops = {
+ .tx = iwl_mac_tx,
+ .start = iwl_mac_start,
+ .stop = iwl_mac_stop,
+ .add_interface = iwl_mac_add_interface,
+ .remove_interface = iwl_mac_remove_interface,
+ .config = iwl_mac_config,
+ .config_interface = iwl_mac_config_interface,
+ .configure_filter = iwl_configure_filter,
+ .set_key = iwl_mac_set_key,
+ .get_stats = iwl_mac_get_stats,
+ .get_tx_stats = iwl_mac_get_tx_stats,
+ .conf_tx = iwl_mac_conf_tx,
+ .get_tsf = iwl_mac_get_tsf,
+ .reset_tsf = iwl_mac_reset_tsf,
+ .beacon_update = iwl_mac_beacon_update,
+ .hw_scan = iwl_mac_hw_scan
+};
+
+static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = 0;
+ u32 pci_id;
+ struct iwl_priv *priv;
+ struct ieee80211_hw *hw;
+ int i;
+
+ if (iwl_param_disable_hw_scan) {
+ IWL_DEBUG_INFO("Disabling hw_scan\n");
+ iwl_hw_ops.hw_scan = NULL;
+ }
+
+ if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) ||
+ (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) {
+ IWL_ERROR("invalid queues_num, should be between %d and %d\n",
+ IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
+ err = -EINVAL;
+ goto out;
+ }
+
+ /* mac80211 allocates memory for this device instance, including
+ * space for this driver's private structure */
+ hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops);
+ if (hw == NULL) {
+ IWL_ERROR("Can not allocate network device\n");
+ err = -ENOMEM;
+ goto out;
+ }
+ SET_IEEE80211_DEV(hw, &pdev->dev);
+
+ hw->rate_control_algorithm = "iwl-3945-rs";
+
+ IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
+ priv = hw->priv;
+ priv->hw = hw;
+
+ priv->pci_dev = pdev;
+ priv->antenna = (enum iwl_antenna)iwl_param_antenna;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ iwl_debug_level = iwl_param_debug;
+ atomic_set(&priv->restrict_refcnt, 0);
+#endif
+ priv->retry_rate = 1;
+
+ priv->ibss_beacon = NULL;
+
+ /* Tell mac80211 and its clients (e.g. Wireless Extensions)
+ * the range of signal quality values that we'll provide.
+ * Negative values for level/noise indicate that we'll provide dBm.
+ * For WE, at least, non-0 values here *enable* display of values
+ * in app (iwconfig). */
+ hw->max_rssi = -20; /* signal level, negative indicates dBm */
+ hw->max_noise = -20; /* noise level, negative indicates dBm */
+ hw->max_signal = 100; /* link quality indication (%) */
+
+ /* Tell mac80211 our Tx characteristics */
+ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+
+ hw->queues = 4;
+
+ spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->power_data.lock);
+ spin_lock_init(&priv->sta_lock);
+ spin_lock_init(&priv->hcmd_lock);
+
+ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
+ INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
+
+ INIT_LIST_HEAD(&priv->free_frames);
+
+ mutex_init(&priv->mutex);
+ if (pci_enable_device(pdev)) {
+ err = -ENODEV;
+ goto out_ieee80211_free_hw;
+ }
+
+ pci_set_master(pdev);
+
+ iwl_clear_stations_table(priv);
+
+ priv->data_retry_limit = -1;
+ priv->ieee_channels = NULL;
+ priv->ieee_rates = NULL;
+ priv->phymode = -1;
+
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (!err)
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
+ goto out_pci_disable_device;
+ }
+
+ pci_set_drvdata(pdev, priv);
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err)
+ goto out_pci_disable_device;
+ /* We disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state */
+ pci_write_config_byte(pdev, 0x41, 0x00);
+ priv->hw_base = pci_iomap(pdev, 0, 0);
+ if (!priv->hw_base) {
+ err = -ENODEV;
+ goto out_pci_release_regions;
+ }
+
+ IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n",
+ (unsigned long long) pci_resource_len(pdev, 0));
+ IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base);
+
+ /* Initialize module parameter values here */
+
+ if (iwl_param_disable) {
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ IWL_DEBUG_INFO("Radio disabled.\n");
+ }
+
+ priv->iw_mode = IEEE80211_IF_TYPE_STA;
+
+ pci_id =
+ (priv->pci_dev->device << 16) | priv->pci_dev->subsystem_device;
+
+ switch (pci_id) {
+ case 0x42221005: /* 0x4222 0x8086 0x1005 is BG SKU */
+ case 0x42221034: /* 0x4222 0x8086 0x1034 is BG SKU */
+ case 0x42271014: /* 0x4227 0x8086 0x1014 is BG SKU */
+ case 0x42221044: /* 0x4222 0x8086 0x1044 is BG SKU */
+ priv->is_abg = 0;
+ break;
+
+ /*
+ * Rest are assumed ABG SKU -- if this is not the
+ * case then the card will get the wrong 'Detected'
+ * line in the kernel log however the code that
+ * initializes the GEO table will detect no A-band
+ * channels and remove the is_abg mask.
+ */
+ default:
+ priv->is_abg = 1;
+ break;
+ }
+
+ printk(KERN_INFO DRV_NAME
+ ": Detected Intel PRO/Wireless 3945%sBG Network Connection\n",
+ priv->is_abg ? "A" : "");
+
+ /* Device-specific setup */
+ if (iwl_hw_set_hw_setting(priv)) {
+ IWL_ERROR("failed to set hw settings\n");
+ mutex_unlock(&priv->mutex);
+ goto out_iounmap;
+ }
+
+#ifdef CONFIG_IWLWIFI_QOS
+ if (iwl_param_qos_enable)
+ priv->qos_data.qos_enable = 1;
+
+ iwl_reset_qos(priv);
+
+ priv->qos_data.qos_active = 0;
+ priv->qos_data.qos_cap.val = 0;
+#endif /* CONFIG_IWLWIFI_QOS */
+
+ iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6);
+ iwl_setup_deferred_work(priv);
+ iwl_setup_rx_handlers(priv);
+
+ priv->rates_mask = IWL_RATES_MASK;
+ /* If power management is turned on, default to AC mode */
+ priv->power_mode = IWL_POWER_AC;
+ priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
+
+ pci_enable_msi(pdev);
+
+ err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv);
+ if (err) {
+ IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
+ goto out_disable_msi;
+ }
+
+ mutex_lock(&priv->mutex);
+
+ err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
+ if (err) {
+ IWL_ERROR("failed to create sysfs device attributes\n");
+ mutex_unlock(&priv->mutex);
+ goto out_release_irq;
+ }
+
+ /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+ * ucode filename and max sizes are card-specific. */
+ err = iwl_read_ucode(priv);
+ if (err) {
+ IWL_ERROR("Could not read microcode: %d\n", err);
+ mutex_unlock(&priv->mutex);
+ goto out_pci_alloc;
+ }
+
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_INFO("Queing UP work.\n");
+
+ queue_work(priv->workqueue, &priv->up);
+
+ return 0;
+
+ out_pci_alloc:
+ iwl_dealloc_ucode_pci(priv);
+
+ sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+
+ out_release_irq:
+ free_irq(pdev->irq, priv);
+
+ out_disable_msi:
+ pci_disable_msi(pdev);
+ destroy_workqueue(priv->workqueue);
+ priv->workqueue = NULL;
+ iwl_unset_hw_setting(priv);
+
+ out_iounmap:
+ pci_iounmap(pdev, priv->hw_base);
+ out_pci_release_regions:
+ pci_release_regions(pdev);
+ out_pci_disable_device:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ out_ieee80211_free_hw:
+ ieee80211_free_hw(priv->hw);
+ out:
+ return err;
+}
+
+static void iwl_pci_remove(struct pci_dev *pdev)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+ struct list_head *p, *q;
+ int i;
+
+ if (!priv)
+ return;
+
+ IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
+
+ mutex_lock(&priv->mutex);
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
+ __iwl_down(priv);
+ mutex_unlock(&priv->mutex);
+
+ /* Free MAC hash list for ADHOC */
+ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
+ list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
+ list_del(p);
+ kfree(list_entry(p, struct iwl_ibss_seq, list));
+ }
+ }
+
+ sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+
+ iwl_dealloc_ucode_pci(priv);
+
+ if (priv->rxq.bd)
+ iwl_rx_queue_free(priv, &priv->rxq);
+ iwl_hw_txq_ctx_free(priv);
+
+ iwl_unset_hw_setting(priv);
+ iwl_clear_stations_table(priv);
+
+ if (priv->mac80211_registered) {
+ ieee80211_unregister_hw(priv->hw);
+ iwl_rate_control_unregister(priv->hw);
+ }
+
+ /*netif_stop_queue(dev); */
+ flush_workqueue(priv->workqueue);
+
+ /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes
+ * priv->workqueue... so we can't take down the workqueue
+ * until now... */
+ destroy_workqueue(priv->workqueue);
+ priv->workqueue = NULL;
+
+ free_irq(pdev->irq, priv);
+ pci_disable_msi(pdev);
+ pci_iounmap(pdev, priv->hw_base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ kfree(priv->channel_info);
+
+ kfree(priv->ieee_channels);
+ kfree(priv->ieee_rates);
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ ieee80211_free_hw(priv->hw);
+}
+
+#ifdef CONFIG_PM
+
+static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+
+ mutex_lock(&priv->mutex);
+
+ set_bit(STATUS_IN_SUSPEND, &priv->status);
+
+ /* Take down the device; powers it off, etc. */
+ __iwl_down(priv);
+
+ if (priv->mac80211_registered)
+ ieee80211_stop_queues(priv->hw);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void iwl_resume(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ /* The following it a temporary work around due to the
+ * suspend / resume not fully initializing the NIC correctly.
+ * Without all of the following, resume will not attempt to take
+ * down the NIC (it shouldn't really need to) and will just try
+ * and bring the NIC back up. However that fails during the
+ * ucode verification process. This then causes iwl_down to be
+ * called *after* iwl_hw_nic_init() has succeeded -- which
+ * then lets the next init sequence succeed. So, we've
+ * replicated all of that NIC init code here... */
+
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+ iwl_hw_nic_init(priv);
+
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ /* tell the device to stop sending interrupts */
+ iwl_disable_interrupts(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT);
+ iwl_release_restricted_access(priv);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ udelay(5);
+
+ iwl_hw_nic_reset(priv);
+
+ /* Bring the device back up */
+ clear_bit(STATUS_IN_SUSPEND, &priv->status);
+ queue_work(priv->workqueue, &priv->up);
+}
+
+static int iwl_pci_resume(struct pci_dev *pdev)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+ int err;
+
+ printk(KERN_INFO "Coming out of suspend...\n");
+
+ mutex_lock(&priv->mutex);
+
+ pci_set_power_state(pdev, PCI_D0);
+ err = pci_enable_device(pdev);
+ pci_restore_state(pdev);
+
+ /*
+ * Suspend/Resume resets the PCI configuration space, so we have to
+ * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+ * from interfering with C3 CPU state. pci_restore_state won't help
+ * here since it only restores the first 64 bytes pci config header.
+ */
+ pci_write_config_byte(pdev, 0x41, 0x00);
+
+ iwl_resume(priv);
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+/*****************************************************************************
+ *
+ * driver and module entry point
+ *
+ *****************************************************************************/
+
+static struct pci_driver iwl_driver = {
+ .name = DRV_NAME,
+ .id_table = iwl_hw_card_ids,
+ .probe = iwl_pci_probe,
+ .remove = __devexit_p(iwl_pci_remove),
+#ifdef CONFIG_PM
+ .suspend = iwl_pci_suspend,
+ .resume = iwl_pci_resume,
+#endif
+};
+
+static int __init iwl_init(void)
+{
+
+ int ret;
+ printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
+ printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+ ret = pci_register_driver(&iwl_driver);
+ if (ret) {
+ IWL_ERROR("Unable to initialize PCI module\n");
+ return ret;
+ }
+#ifdef CONFIG_IWLWIFI_DEBUG
+ ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
+ if (ret) {
+ IWL_ERROR("Unable to create driver sysfs file\n");
+ pci_unregister_driver(&iwl_driver);
+ return ret;
+ }
+#endif
+
+ return ret;
+}
+
+static void __exit iwl_exit(void)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
+#endif
+ pci_unregister_driver(&iwl_driver);
+}
+
+module_param_named(antenna, iwl_param_antenna, int, 0444);
+MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
+module_param_named(disable, iwl_param_disable, int, 0444);
+MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
+module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444);
+MODULE_PARM_DESC(hwcrypto,
+ "using hardware crypto engine (default 0 [software])\n");
+module_param_named(debug, iwl_param_debug, int, 0444);
+MODULE_PARM_DESC(debug, "debug output mask");
+module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444);
+MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+
+module_param_named(queues_num, iwl_param_queues_num, int, 0444);
+MODULE_PARM_DESC(queues_num, "number of hw queues.");
+
+/* QoS */
+module_param_named(qos_enable, iwl_param_qos_enable, int, 0444);
+MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
+
+module_exit(iwl_exit);
+module_init(iwl_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
new file mode 100644
index 00000000000..9918780f5e8
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -0,0 +1,9392 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+/*
+ * NOTE: This file (iwl-base.c) is used to build to multiple hardware targets
+ * by defining IWL to either 3945 or 4965. The Makefile used when building
+ * the base targets will create base-3945.o and base-4965.o
+ *
+ * The eventual goal is to move as many of the #if IWL / #endif blocks out of
+ * this file and into the hardware specific implementation files (iwl-XXXX.c)
+ * and leave only the common (non #ifdef sprinkled) code in this file
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/ieee80211_radiotap.h>
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#define IWL 4965
+
+#include "iwlwifi.h"
+#include "iwl-4965.h"
+#include "iwl-helpers.h"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+u32 iwl_debug_level;
+#endif
+
+/******************************************************************************
+ *
+ * module boiler plate
+ *
+ ******************************************************************************/
+
+/* module parameters */
+int iwl_param_disable_hw_scan;
+int iwl_param_debug;
+int iwl_param_disable; /* def: enable radio */
+int iwl_param_antenna; /* def: 0 = both antennas (use diversity) */
+int iwl_param_hwcrypto; /* def: using software encryption */
+int iwl_param_qos_enable = 1;
+int iwl_param_queues_num = IWL_MAX_NUM_QUEUES;
+
+/*
+ * module name, copyright, version, etc.
+ * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk
+ */
+
+#define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link 4965AGN driver for Linux"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#define VS "s"
+#else
+#define VS
+#endif
+
+#define IWLWIFI_VERSION "1.1.17k" VD VS
+#define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation"
+#define DRV_VERSION IWLWIFI_VERSION
+
+/* Change firmware file name, using "-" and incrementing number,
+ * *only* when uCode interface or architecture changes so that it
+ * is not compatible with earlier drivers.
+ * This number will also appear in << 8 position of 1st dword of uCode file */
+#define IWL4965_UCODE_API "-1"
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
+{
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ int hdr_len = ieee80211_get_hdrlen(fc);
+
+ if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
+ return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
+ return NULL;
+}
+
+static const struct ieee80211_hw_mode *iwl_get_hw_mode(
+ struct iwl_priv *priv, int mode)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ if (priv->modes[i].mode == mode)
+ return &priv->modes[i];
+
+ return NULL;
+}
+
+static int iwl_is_empty_essid(const char *essid, int essid_len)
+{
+ /* Single white space is for Linksys APs */
+ if (essid_len == 1 && essid[0] == ' ')
+ return 1;
+
+ /* Otherwise, if the entire essid is 0, we assume it is hidden */
+ while (essid_len) {
+ essid_len--;
+ if (essid[essid_len] != '\0')
+ return 0;
+ }
+
+ return 1;
+}
+
+static const char *iwl_escape_essid(const char *essid, u8 essid_len)
+{
+ static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+ const char *s = essid;
+ char *d = escaped;
+
+ if (iwl_is_empty_essid(essid, essid_len)) {
+ memcpy(escaped, "<hidden>", sizeof("<hidden>"));
+ return escaped;
+ }
+
+ essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE);
+ while (essid_len--) {
+ if (*s == '\0') {
+ *d++ = '\\';
+ *d++ = '0';
+ s++;
+ } else
+ *d++ = *s++;
+ }
+ *d = '\0';
+ return escaped;
+}
+
+static void iwl_print_hex_dump(int level, void *p, u32 len)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (!(iwl_debug_level & level))
+ return;
+
+ print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
+ p, len, 1);
+#endif
+}
+
+/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A queue is a circular buffers with 'Read' and 'Write' pointers.
+ * 2 empty entries always kept in the buffer to protect from overflow.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ * The IWL operates with six queues, one receive queue in the device's
+ * sram, one transmit queue for sending commands to the device firmware,
+ * and four transmit queues for data.
+ ***************************************************/
+
+static int iwl_queue_space(const struct iwl_queue *q)
+{
+ int s = q->last_used - q->first_empty;
+
+ if (q->last_used > q->first_empty)
+ s -= q->n_bd;
+
+ if (s <= 0)
+ s += q->n_window;
+ /* keep some reserve to not confuse empty and full situations */
+ s -= 2;
+ if (s < 0)
+ s = 0;
+ return s;
+}
+
+/* XXX: n_bd must be power-of-two size */
+static inline int iwl_queue_inc_wrap(int index, int n_bd)
+{
+ return ++index & (n_bd - 1);
+}
+
+/* XXX: n_bd must be power-of-two size */
+static inline int iwl_queue_dec_wrap(int index, int n_bd)
+{
+ return --index & (n_bd - 1);
+}
+
+static inline int x2_queue_used(const struct iwl_queue *q, int i)
+{
+ return q->first_empty > q->last_used ?
+ (i >= q->last_used && i < q->first_empty) :
+ !(i < q->last_used && i >= q->first_empty);
+}
+
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
+{
+ if (is_huge)
+ return q->n_window;
+
+ return index & (q->n_window - 1);
+}
+
+static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
+ int count, int slots_num, u32 id)
+{
+ q->n_bd = count;
+ q->n_window = slots_num;
+ q->id = id;
+
+ /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
+ * and iwl_queue_dec_wrap are broken. */
+ BUG_ON(!is_power_of_2(count));
+
+ /* slots_num must be power-of-two size, otherwise
+ * get_cmd_index is broken. */
+ BUG_ON(!is_power_of_2(slots_num));
+
+ q->low_mark = q->n_window / 4;
+ if (q->low_mark < 4)
+ q->low_mark = 4;
+
+ q->high_mark = q->n_window / 8;
+ if (q->high_mark < 2)
+ q->high_mark = 2;
+
+ q->first_empty = q->last_used = 0;
+
+ return 0;
+}
+
+static int iwl_tx_queue_alloc(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq, u32 id)
+{
+ struct pci_dev *dev = priv->pci_dev;
+
+ if (id != IWL_CMD_QUEUE_NUM) {
+ txq->txb = kmalloc(sizeof(txq->txb[0]) *
+ TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
+ if (!txq->txb) {
+ IWL_ERROR("kmalloc for auxilary BD "
+ "structures failed\n");
+ goto error;
+ }
+ } else
+ txq->txb = NULL;
+
+ txq->bd = pci_alloc_consistent(dev,
+ sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
+ &txq->q.dma_addr);
+
+ if (!txq->bd) {
+ IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
+ sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
+ goto error;
+ }
+ txq->q.id = id;
+
+ return 0;
+
+ error:
+ if (txq->txb) {
+ kfree(txq->txb);
+ txq->txb = NULL;
+ }
+
+ return -ENOMEM;
+}
+
+int iwl_tx_queue_init(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq, int slots_num, u32 txq_id)
+{
+ struct pci_dev *dev = priv->pci_dev;
+ int len;
+ int rc = 0;
+
+ /* alocate command space + one big command for scan since scan
+ * command is very huge the system will not have two scan at the
+ * same time */
+ len = sizeof(struct iwl_cmd) * slots_num;
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ len += IWL_MAX_SCAN_SIZE;
+ txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
+ if (!txq->cmd)
+ return -ENOMEM;
+
+ rc = iwl_tx_queue_alloc(priv, txq, txq_id);
+ if (rc) {
+ pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+ return -ENOMEM;
+ }
+ txq->need_update = 0;
+
+ /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+ * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+ iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+
+ iwl_hw_tx_queue_init(priv, txq);
+
+ return 0;
+}
+
+/**
+ * iwl_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers. txq itself is not freed.
+ *
+ */
+void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ struct iwl_queue *q = &txq->q;
+ struct pci_dev *dev = priv->pci_dev;
+ int len;
+
+ if (q->n_bd == 0)
+ return;
+
+ /* first, empty all BD's */
+ for (; q->first_empty != q->last_used;
+ q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd))
+ iwl_hw_txq_free_tfd(priv, txq);
+
+ len = sizeof(struct iwl_cmd) * q->n_window;
+ if (q->id == IWL_CMD_QUEUE_NUM)
+ len += IWL_MAX_SCAN_SIZE;
+
+ pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+ /* free buffers belonging to queue itself */
+ if (txq->q.n_bd)
+ pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
+ txq->q.n_bd, txq->bd, txq->q.dma_addr);
+
+ if (txq->txb) {
+ kfree(txq->txb);
+ txq->txb = NULL;
+ }
+
+ /* 0 fill whole structure */
+ memset(txq, 0, sizeof(*txq));
+}
+
+const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+/*************** STATION TABLE MANAGEMENT ****
+ *
+ * NOTE: This needs to be overhauled to better synchronize between
+ * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c
+ *
+ * mac80211 should also be examined to determine if sta_info is duplicating
+ * the functionality provided here
+ */
+
+/**************************************************************/
+
+#if 0 /* temparary disable till we add real remove station */
+static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+ int index = IWL_INVALID_STATION;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ if (is_ap)
+ index = IWL_AP_ID;
+ else if (is_broadcast_ether_addr(addr))
+ index = priv->hw_setting.bcast_sta_id;
+ else
+ for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+ if (priv->stations[i].used &&
+ !compare_ether_addr(priv->stations[i].sta.sta.addr,
+ addr)) {
+ index = i;
+ break;
+ }
+
+ if (unlikely(index == IWL_INVALID_STATION))
+ goto out;
+
+ if (priv->stations[index].used) {
+ priv->stations[index].used = 0;
+ priv->num_stations--;
+ }
+
+ BUG_ON(priv->num_stations < 0);
+
+out:
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+}
+#endif
+
+static void iwl_clear_stations_table(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->num_stations = 0;
+ memset(priv->stations, 0, sizeof(priv->stations));
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+
+u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
+{
+ int i;
+ int index = IWL_INVALID_STATION;
+ struct iwl_station_entry *station;
+ unsigned long flags_spin;
+ DECLARE_MAC_BUF(mac);
+
+ spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ if (is_ap)
+ index = IWL_AP_ID;
+ else if (is_broadcast_ether_addr(addr))
+ index = priv->hw_setting.bcast_sta_id;
+ else
+ for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) {
+ if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+ addr)) {
+ index = i;
+ break;
+ }
+
+ if (!priv->stations[i].used &&
+ index == IWL_INVALID_STATION)
+ index = i;
+ }
+
+
+ /* These twh conditions has the same outcome but keep them separate
+ since they have different meaning */
+ if (unlikely(index == IWL_INVALID_STATION)) {
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ return index;
+ }
+
+ if (priv->stations[index].used &&
+ !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ return index;
+ }
+
+
+ IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
+ station = &priv->stations[index];
+ station->used = 1;
+ priv->num_stations++;
+
+ memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
+ memcpy(station->sta.sta.addr, addr, ETH_ALEN);
+ station->sta.mode = 0;
+ station->sta.sta.sta_id = index;
+ station->sta.station_flags = 0;
+
+#ifdef CONFIG_IWLWIFI_HT
+ /* BCAST station and IBSS stations do not work in HT mode */
+ if (index != priv->hw_setting.bcast_sta_id &&
+ priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
+ iwl4965_set_ht_add_station(priv, index);
+#endif /*CONFIG_IWLWIFI_HT*/
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+ iwl_send_add_station(priv, &station->sta, flags);
+ return index;
+
+}
+
+/*************** DRIVER STATUS FUNCTIONS *****/
+
+static inline int iwl_is_ready(struct iwl_priv *priv)
+{
+ /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
+ * set but EXIT_PENDING is not */
+ return test_bit(STATUS_READY, &priv->status) &&
+ test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
+ !test_bit(STATUS_EXIT_PENDING, &priv->status);
+}
+
+static inline int iwl_is_alive(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_ALIVE, &priv->status);
+}
+
+static inline int iwl_is_init(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_INIT, &priv->status);
+}
+
+static inline int iwl_is_rfkill(struct iwl_priv *priv)
+{
+ return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+ test_bit(STATUS_RF_KILL_SW, &priv->status);
+}
+
+static inline int iwl_is_ready_rf(struct iwl_priv *priv)
+{
+
+ if (iwl_is_rfkill(priv))
+ return 0;
+
+ return iwl_is_ready(priv);
+}
+
+/*************** HOST COMMAND QUEUE FUNCTIONS *****/
+
+#define IWL_CMD(x) case x : return #x
+
+static const char *get_cmd_string(u8 cmd)
+{
+ switch (cmd) {
+ IWL_CMD(REPLY_ALIVE);
+ IWL_CMD(REPLY_ERROR);
+ IWL_CMD(REPLY_RXON);
+ IWL_CMD(REPLY_RXON_ASSOC);
+ IWL_CMD(REPLY_QOS_PARAM);
+ IWL_CMD(REPLY_RXON_TIMING);
+ IWL_CMD(REPLY_ADD_STA);
+ IWL_CMD(REPLY_REMOVE_STA);
+ IWL_CMD(REPLY_REMOVE_ALL_STA);
+ IWL_CMD(REPLY_TX);
+ IWL_CMD(REPLY_RATE_SCALE);
+ IWL_CMD(REPLY_LEDS_CMD);
+ IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
+ IWL_CMD(RADAR_NOTIFICATION);
+ IWL_CMD(REPLY_QUIET_CMD);
+ IWL_CMD(REPLY_CHANNEL_SWITCH);
+ IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
+ IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
+ IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
+ IWL_CMD(POWER_TABLE_CMD);
+ IWL_CMD(PM_SLEEP_NOTIFICATION);
+ IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
+ IWL_CMD(REPLY_SCAN_CMD);
+ IWL_CMD(REPLY_SCAN_ABORT_CMD);
+ IWL_CMD(SCAN_START_NOTIFICATION);
+ IWL_CMD(SCAN_RESULTS_NOTIFICATION);
+ IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
+ IWL_CMD(BEACON_NOTIFICATION);
+ IWL_CMD(REPLY_TX_BEACON);
+ IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
+ IWL_CMD(QUIET_NOTIFICATION);
+ IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
+ IWL_CMD(MEASURE_ABORT_NOTIFICATION);
+ IWL_CMD(REPLY_BT_CONFIG);
+ IWL_CMD(REPLY_STATISTICS_CMD);
+ IWL_CMD(STATISTICS_NOTIFICATION);
+ IWL_CMD(REPLY_CARD_STATE_CMD);
+ IWL_CMD(CARD_STATE_NOTIFICATION);
+ IWL_CMD(MISSED_BEACONS_NOTIFICATION);
+ IWL_CMD(REPLY_CT_KILL_CONFIG_CMD);
+ IWL_CMD(SENSITIVITY_CMD);
+ IWL_CMD(REPLY_PHY_CALIBRATION_CMD);
+ IWL_CMD(REPLY_RX_PHY_CMD);
+ IWL_CMD(REPLY_RX_MPDU_CMD);
+ IWL_CMD(REPLY_4965_RX);
+ IWL_CMD(REPLY_COMPRESSED_BA);
+ default:
+ return "UNKNOWN";
+
+ }
+}
+
+#define HOST_COMPLETE_TIMEOUT (HZ / 2)
+
+/**
+ * iwl_enqueue_hcmd - enqueue a uCode command
+ * @priv: device private data point
+ * @cmd: a point to the ucode command structure
+ *
+ * The function returns < 0 values to indicate the operation is
+ * failed. On success, it turns the index (> 0) of command in the
+ * command queue.
+ */
+static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+ struct iwl_queue *q = &txq->q;
+ struct iwl_tfd_frame *tfd;
+ u32 *control_flags;
+ struct iwl_cmd *out_cmd;
+ u32 idx;
+ u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
+ dma_addr_t phys_addr;
+ int ret;
+ unsigned long flags;
+
+ /* If any of the command structures end up being larger than
+ * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
+ * we will need to increase the size of the TFD entries */
+ BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
+ !(cmd->meta.flags & CMD_SIZE_HUGE));
+
+ if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+ IWL_ERROR("No space for Tx\n");
+ return -ENOSPC;
+ }
+
+ spin_lock_irqsave(&priv->hcmd_lock, flags);
+
+ tfd = &txq->bd[q->first_empty];
+ memset(tfd, 0, sizeof(*tfd));
+
+ control_flags = (u32 *) tfd;
+
+ idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE);
+ out_cmd = &txq->cmd[idx];
+
+ out_cmd->hdr.cmd = cmd->id;
+ memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
+ memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
+
+ /* At this point, the out_cmd now has all of the incoming cmd
+ * information */
+
+ out_cmd->hdr.flags = 0;
+ out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
+ INDEX_TO_SEQ(q->first_empty));
+ if (out_cmd->meta.flags & CMD_SIZE_HUGE)
+ out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
+
+ phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
+ offsetof(struct iwl_cmd, hdr);
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
+
+ IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
+ "%d bytes at %d[%d]:%d\n",
+ get_cmd_string(out_cmd->hdr.cmd),
+ out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
+ fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM);
+
+ txq->need_update = 1;
+ ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0);
+ q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
+ iwl_tx_queue_update_write_ptr(priv, txq);
+
+ spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+ return ret ? ret : idx;
+}
+
+int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ int ret;
+
+ BUG_ON(!(cmd->meta.flags & CMD_ASYNC));
+
+ /* An asynchronous command can not expect an SKB to be set. */
+ BUG_ON(cmd->meta.flags & CMD_WANT_SKB);
+
+ /* An asynchronous command MUST have a callback. */
+ BUG_ON(!cmd->meta.u.callback);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return -EBUSY;
+
+ ret = iwl_enqueue_hcmd(priv, cmd);
+ if (ret < 0) {
+ IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+ get_cmd_string(cmd->id), ret);
+ return ret;
+ }
+ return 0;
+}
+
+int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ int cmd_idx;
+ int ret;
+ static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */
+
+ BUG_ON(cmd->meta.flags & CMD_ASYNC);
+
+ /* A synchronous command can not have a callback set. */
+ BUG_ON(cmd->meta.u.callback != NULL);
+
+ if (atomic_xchg(&entry, 1)) {
+ IWL_ERROR("Error sending %s: Already sending a host command\n",
+ get_cmd_string(cmd->id));
+ return -EBUSY;
+ }
+
+ set_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+ if (cmd->meta.flags & CMD_WANT_SKB)
+ cmd->meta.source = &cmd->meta;
+
+ cmd_idx = iwl_enqueue_hcmd(priv, cmd);
+ if (cmd_idx < 0) {
+ ret = cmd_idx;
+ IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+ get_cmd_string(cmd->id), ret);
+ goto out;
+ }
+
+ ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+ !test_bit(STATUS_HCMD_ACTIVE, &priv->status),
+ HOST_COMPLETE_TIMEOUT);
+ if (!ret) {
+ if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) {
+ IWL_ERROR("Error sending %s: time out after %dms.\n",
+ get_cmd_string(cmd->id),
+ jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
+
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ ret = -ETIMEDOUT;
+ goto cancel;
+ }
+ }
+
+ if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+ IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n",
+ get_cmd_string(cmd->id));
+ ret = -ECANCELED;
+ goto fail;
+ }
+ if (test_bit(STATUS_FW_ERROR, &priv->status)) {
+ IWL_DEBUG_INFO("Command %s failed: FW Error\n",
+ get_cmd_string(cmd->id));
+ ret = -EIO;
+ goto fail;
+ }
+ if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {
+ IWL_ERROR("Error: Response NULL in '%s'\n",
+ get_cmd_string(cmd->id));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ goto out;
+
+cancel:
+ if (cmd->meta.flags & CMD_WANT_SKB) {
+ struct iwl_cmd *qcmd;
+
+ /* Cancel the CMD_WANT_SKB flag for the cmd in the
+ * TX cmd queue. Otherwise in case the cmd comes
+ * in later, it will possibly set an invalid
+ * address (cmd->meta.source). */
+ qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
+ qcmd->meta.flags &= ~CMD_WANT_SKB;
+ }
+fail:
+ if (cmd->meta.u.skb) {
+ dev_kfree_skb_any(cmd->meta.u.skb);
+ cmd->meta.u.skb = NULL;
+ }
+out:
+ atomic_set(&entry, 0);
+ return ret;
+}
+
+int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+ /* A command can not be asynchronous AND expect an SKB to be set. */
+ BUG_ON((cmd->meta.flags & CMD_ASYNC) &&
+ (cmd->meta.flags & CMD_WANT_SKB));
+
+ if (cmd->meta.flags & CMD_ASYNC)
+ return iwl_send_cmd_async(priv, cmd);
+
+ return iwl_send_cmd_sync(priv, cmd);
+}
+
+int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
+{
+ struct iwl_host_cmd cmd = {
+ .id = id,
+ .len = len,
+ .data = data,
+ };
+
+ return iwl_send_cmd_sync(priv, &cmd);
+}
+
+static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val)
+{
+ struct iwl_host_cmd cmd = {
+ .id = id,
+ .len = sizeof(val),
+ .data = &val,
+ };
+
+ return iwl_send_cmd_sync(priv, &cmd);
+}
+
+int iwl_send_statistics_request(struct iwl_priv *priv)
+{
+ return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
+}
+
+/**
+ * iwl_rxon_add_station - add station into station table.
+ *
+ * there is only one AP station with id= IWL_AP_ID
+ * NOTE: mutex must be held before calling the this fnction
+*/
+static int iwl_rxon_add_station(struct iwl_priv *priv,
+ const u8 *addr, int is_ap)
+{
+ u8 sta_id;
+
+ sta_id = iwl_add_station(priv, addr, is_ap, 0);
+ iwl4965_add_station(priv, addr, is_ap);
+
+ return sta_id;
+}
+
+/**
+ * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
+ * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
+ * @channel: Any channel valid for the requested phymode
+
+ * In addition to setting the staging RXON, priv->phymode is also set.
+ *
+ * NOTE: Does not commit to the hardware; it sets appropriate bit fields
+ * in the staging RXON flag structure based on the phymode
+ */
+static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel)
+{
+ if (!iwl_get_channel_info(priv, phymode, channel)) {
+ IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
+ channel, phymode);
+ return -EINVAL;
+ }
+
+ if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
+ (priv->phymode == phymode))
+ return 0;
+
+ priv->staging_rxon.channel = cpu_to_le16(channel);
+ if (phymode == MODE_IEEE80211A)
+ priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
+ else
+ priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+
+ priv->phymode = phymode;
+
+ IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode);
+
+ return 0;
+}
+
+/**
+ * iwl_check_rxon_cmd - validate RXON structure is valid
+ *
+ * NOTE: This is really only useful during development and can eventually
+ * be #ifdef'd out once the driver is stable and folks aren't actively
+ * making changes
+ */
+static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
+{
+ int error = 0;
+ int counter = 1;
+
+ if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
+ error |= le32_to_cpu(rxon->flags &
+ (RXON_FLG_TGJ_NARROW_BAND_MSK |
+ RXON_FLG_RADAR_DETECT_MSK));
+ if (error)
+ IWL_WARNING("check 24G fields %d | %d\n",
+ counter++, error);
+ } else {
+ error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
+ 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
+ if (error)
+ IWL_WARNING("check 52 fields %d | %d\n",
+ counter++, error);
+ error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
+ if (error)
+ IWL_WARNING("check 52 CCK %d | %d\n",
+ counter++, error);
+ }
+ error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
+ if (error)
+ IWL_WARNING("check mac addr %d | %d\n", counter++, error);
+
+ /* make sure basic rates 6Mbps and 1Mbps are supported */
+ error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
+ ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
+ if (error)
+ IWL_WARNING("check basic rate %d | %d\n", counter++, error);
+
+ error |= (le16_to_cpu(rxon->assoc_id) > 2007);
+ if (error)
+ IWL_WARNING("check assoc id %d | %d\n", counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
+ == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
+ if (error)
+ IWL_WARNING("check CCK and short slot %d | %d\n",
+ counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
+ == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
+ if (error)
+ IWL_WARNING("check CCK & auto detect %d | %d\n",
+ counter++, error);
+
+ error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
+ RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
+ if (error)
+ IWL_WARNING("check TGG and auto detect %d | %d\n",
+ counter++, error);
+
+ if (error)
+ IWL_WARNING("Tuning to channel %d\n",
+ le16_to_cpu(rxon->channel));
+
+ if (error) {
+ IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n");
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit
+ * @priv: staging_rxon is comapred to active_rxon
+ *
+ * If the RXON structure is changing sufficient to require a new
+ * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1
+ * to indicate a new tune is required.
+ */
+static int iwl_full_rxon_required(struct iwl_priv *priv)
+{
+
+ /* These items are only settable from the full RXON command */
+ if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ||
+ compare_ether_addr(priv->staging_rxon.bssid_addr,
+ priv->active_rxon.bssid_addr) ||
+ compare_ether_addr(priv->staging_rxon.node_addr,
+ priv->active_rxon.node_addr) ||
+ compare_ether_addr(priv->staging_rxon.wlap_bssid_addr,
+ priv->active_rxon.wlap_bssid_addr) ||
+ (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) ||
+ (priv->staging_rxon.channel != priv->active_rxon.channel) ||
+ (priv->staging_rxon.air_propagation !=
+ priv->active_rxon.air_propagation) ||
+ (priv->staging_rxon.ofdm_ht_single_stream_basic_rates !=
+ priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
+ (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
+ priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
+ (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) ||
+ (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
+ return 1;
+
+ /* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
+ * be updated with the RXON_ASSOC command -- however only some
+ * flag transitions are allowed using RXON_ASSOC */
+
+ /* Check if we are not switching bands */
+ if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) !=
+ (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK))
+ return 1;
+
+ /* Check if we are switching association toggle */
+ if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) !=
+ (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK))
+ return 1;
+
+ return 0;
+}
+
+static int iwl_send_rxon_assoc(struct iwl_priv *priv)
+{
+ int rc = 0;
+ struct iwl_rx_packet *res = NULL;
+ struct iwl_rxon_assoc_cmd rxon_assoc;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_RXON_ASSOC,
+ .len = sizeof(rxon_assoc),
+ .meta.flags = CMD_WANT_SKB,
+ .data = &rxon_assoc,
+ };
+ const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
+ const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+
+ if ((rxon1->flags == rxon2->flags) &&
+ (rxon1->filter_flags == rxon2->filter_flags) &&
+ (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+ (rxon1->ofdm_ht_single_stream_basic_rates ==
+ rxon2->ofdm_ht_single_stream_basic_rates) &&
+ (rxon1->ofdm_ht_dual_stream_basic_rates ==
+ rxon2->ofdm_ht_dual_stream_basic_rates) &&
+ (rxon1->rx_chain == rxon2->rx_chain) &&
+ (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+ IWL_DEBUG_INFO("Using current RXON_ASSOC. Not resending.\n");
+ return 0;
+ }
+
+ rxon_assoc.flags = priv->staging_rxon.flags;
+ rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
+ rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
+ rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+ rxon_assoc.reserved = 0;
+ rxon_assoc.ofdm_ht_single_stream_basic_rates =
+ priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+ rxon_assoc.ofdm_ht_dual_stream_basic_rates =
+ priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
+ rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n");
+ rc = -EIO;
+ }
+
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+
+/**
+ * iwl_commit_rxon - commit staging_rxon to hardware
+ *
+ * The RXON command in staging_rxon is commited to the hardware and
+ * the active_rxon structure is updated with the new data. This
+ * function correctly transitions out of the RXON_ASSOC_MSK state if
+ * a HW tune is required based on the RXON structure changes.
+ */
+static int iwl_commit_rxon(struct iwl_priv *priv)
+{
+ /* cast away the const for active_rxon in this function */
+ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+ DECLARE_MAC_BUF(mac);
+ int rc = 0;
+
+ if (!iwl_is_alive(priv))
+ return -1;
+
+ /* always get timestamp with Rx frame */
+ priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
+
+ rc = iwl_check_rxon_cmd(&priv->staging_rxon);
+ if (rc) {
+ IWL_ERROR("Invalid RXON configuration. Not committing.\n");
+ return -EINVAL;
+ }
+
+ /* If we don't need to send a full RXON, we can use
+ * iwl_rxon_assoc_cmd which is used to reconfigure filter
+ * and other flags for the current radio configuration. */
+ if (!iwl_full_rxon_required(priv)) {
+ rc = iwl_send_rxon_assoc(priv);
+ if (rc) {
+ IWL_ERROR("Error setting RXON_ASSOC "
+ "configuration (%d).\n", rc);
+ return rc;
+ }
+
+ memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+ return 0;
+ }
+
+ /* station table will be cleared */
+ priv->assoc_station_added = 0;
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
+ if (!priv->error_recovering)
+ priv->start_calib = 0;
+
+ iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
+#endif /* CONFIG_IWLWIFI_SENSITIVITY */
+
+ /* If we are currently associated and the new config requires
+ * an RXON_ASSOC and the new config wants the associated mask enabled,
+ * we must clear the associated from the active configuration
+ * before we apply the new config */
+ if (iwl_is_associated(priv) &&
+ (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) {
+ IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
+ active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+ sizeof(struct iwl_rxon_cmd),
+ &priv->active_rxon);
+
+ /* If the mask clearing failed then we set
+ * active_rxon back to what it was previously */
+ if (rc) {
+ active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
+ IWL_ERROR("Error clearing ASSOC_MSK on current "
+ "configuration (%d).\n", rc);
+ return rc;
+ }
+ }
+
+ IWL_DEBUG_INFO("Sending RXON\n"
+ "* with%s RXON_FILTER_ASSOC_MSK\n"
+ "* channel = %d\n"
+ "* bssid = %s\n",
+ ((priv->staging_rxon.filter_flags &
+ RXON_FILTER_ASSOC_MSK) ? "" : "out"),
+ le16_to_cpu(priv->staging_rxon.channel),
+ print_mac(mac, priv->staging_rxon.bssid_addr));
+
+ /* Apply the new configuration */
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+ sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+ if (rc) {
+ IWL_ERROR("Error setting new configuration (%d).\n", rc);
+ return rc;
+ }
+
+ iwl_clear_stations_table(priv);
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ if (!priv->error_recovering)
+ priv->start_calib = 0;
+
+ priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
+ iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
+#endif /* CONFIG_IWLWIFI_SENSITIVITY */
+
+ memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+ /* If we issue a new RXON command which required a tune then we must
+ * send a new TXPOWER command or we won't be able to Tx any frames */
+ rc = iwl_hw_reg_send_txpower(priv);
+ if (rc) {
+ IWL_ERROR("Error setting Tx power (%d).\n", rc);
+ return rc;
+ }
+
+ /* Add the broadcast address so we can send broadcast frames */
+ if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) ==
+ IWL_INVALID_STATION) {
+ IWL_ERROR("Error adding BROADCAST address for transmit.\n");
+ return -EIO;
+ }
+
+ /* If we have set the ASSOC_MSK and we are in BSS mode then
+ * add the IWL_AP_ID to the station rate table */
+ if (iwl_is_associated(priv) &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
+ if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1)
+ == IWL_INVALID_STATION) {
+ IWL_ERROR("Error adding AP address for transmit.\n");
+ return -EIO;
+ }
+ priv->assoc_station_added = 1;
+ }
+
+ return 0;
+}
+
+static int iwl_send_bt_config(struct iwl_priv *priv)
+{
+ struct iwl_bt_cmd bt_cmd = {
+ .flags = 3,
+ .lead_time = 0xAA,
+ .max_kill = 1,
+ .kill_ack_mask = 0,
+ .kill_cts_mask = 0,
+ };
+
+ return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+ sizeof(struct iwl_bt_cmd), &bt_cmd);
+}
+
+static int iwl_send_scan_abort(struct iwl_priv *priv)
+{
+ int rc = 0;
+ struct iwl_rx_packet *res;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SCAN_ABORT_CMD,
+ .meta.flags = CMD_WANT_SKB,
+ };
+
+ /* If there isn't a scan actively going on in the hardware
+ * then we are in between scan bands and not actually
+ * actively scanning, so don't send the abort command */
+ if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ return 0;
+ }
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc) {
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ return rc;
+ }
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->u.status != CAN_ABORT_STATUS) {
+ /* The scan abort will return 1 for success or
+ * 2 for "failure". A failure condition can be
+ * due to simply not being in an active scan which
+ * can occur if we send the scan abort before we
+ * the microcode has notified us that a scan is
+ * completed. */
+ IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status);
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ clear_bit(STATUS_SCAN_HW, &priv->status);
+ }
+
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+
+static int iwl_card_state_sync_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct sk_buff *skb)
+{
+ return 1;
+}
+
+/*
+ * CARD_STATE_CMD
+ *
+ * Use: Sets the internal card state to enable, disable, or halt
+ *
+ * When in the 'enable' state the card operates as normal.
+ * When in the 'disable' state, the card enters into a low power mode.
+ * When in the 'halt' state, the card is shut down and must be fully
+ * restarted to come back on.
+ */
+static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
+{
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_CARD_STATE_CMD,
+ .len = sizeof(u32),
+ .data = &flags,
+ .meta.flags = meta_flag,
+ };
+
+ if (meta_flag & CMD_ASYNC)
+ cmd.meta.u.callback = iwl_card_state_sync_callback;
+
+ return iwl_send_cmd(priv, &cmd);
+}
+
+static int iwl_add_sta_sync_callback(struct iwl_priv *priv,
+ struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+ struct iwl_rx_packet *res = NULL;
+
+ if (!skb) {
+ IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
+ return 1;
+ }
+
+ res = (struct iwl_rx_packet *)skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+ res->hdr.flags);
+ return 1;
+ }
+
+ switch (res->u.add_sta.status) {
+ case ADD_STA_SUCCESS_MSK:
+ break;
+ default:
+ break;
+ }
+
+ /* We didn't cache the SKB; let the caller free it */
+ return 1;
+}
+
+int iwl_send_add_station(struct iwl_priv *priv,
+ struct iwl_addsta_cmd *sta, u8 flags)
+{
+ struct iwl_rx_packet *res = NULL;
+ int rc = 0;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_ADD_STA,
+ .len = sizeof(struct iwl_addsta_cmd),
+ .meta.flags = flags,
+ .data = sta,
+ };
+
+ if (flags & CMD_ASYNC)
+ cmd.meta.u.callback = iwl_add_sta_sync_callback;
+ else
+ cmd.meta.flags |= CMD_WANT_SKB;
+
+ rc = iwl_send_cmd(priv, &cmd);
+
+ if (rc || (flags & CMD_ASYNC))
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+ res->hdr.flags);
+ rc = -EIO;
+ }
+
+ if (rc == 0) {
+ switch (res->u.add_sta.status) {
+ case ADD_STA_SUCCESS_MSK:
+ IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
+ break;
+ default:
+ rc = -EIO;
+ IWL_WARNING("REPLY_ADD_STA failed\n");
+ break;
+ }
+ }
+
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+
+static int iwl_update_sta_key_info(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id)
+{
+ unsigned long flags;
+ __le16 key_flags = 0;
+
+ switch (keyconf->alg) {
+ case ALG_CCMP:
+ key_flags |= STA_KEY_FLG_CCMP;
+ key_flags |= cpu_to_le16(
+ keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags &= ~STA_KEY_FLG_INVALID;
+ break;
+ case ALG_TKIP:
+ case ALG_WEP:
+ return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+ priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
+ memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
+ keyconf->keylen);
+
+ memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
+ keyconf->keylen);
+ priv->stations[sta_id].sta.key.key_flags = key_flags;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+ return 0;
+}
+
+static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
+ memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo));
+ priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
+ iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+ return 0;
+}
+
+static void iwl_clear_free_frames(struct iwl_priv *priv)
+{
+ struct list_head *element;
+
+ IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n",
+ priv->frames_count);
+
+ while (!list_empty(&priv->free_frames)) {
+ element = priv->free_frames.next;
+ list_del(element);
+ kfree(list_entry(element, struct iwl_frame, list));
+ priv->frames_count--;
+ }
+
+ if (priv->frames_count) {
+ IWL_WARNING("%d frames still in use. Did we lose one?\n",
+ priv->frames_count);
+ priv->frames_count = 0;
+ }
+}
+
+static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
+{
+ struct iwl_frame *frame;
+ struct list_head *element;
+ if (list_empty(&priv->free_frames)) {
+ frame = kzalloc(sizeof(*frame), GFP_KERNEL);
+ if (!frame) {
+ IWL_ERROR("Could not allocate frame!\n");
+ return NULL;
+ }
+
+ priv->frames_count++;
+ return frame;
+ }
+
+ element = priv->free_frames.next;
+ list_del(element);
+ return list_entry(element, struct iwl_frame, list);
+}
+
+static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
+{
+ memset(frame, 0, sizeof(*frame));
+ list_add(&frame->list, &priv->free_frames);
+}
+
+unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+ struct ieee80211_hdr *hdr,
+ const u8 *dest, int left)
+{
+
+ if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
+ ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
+ (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
+ return 0;
+
+ if (priv->ibss_beacon->len > left)
+ return 0;
+
+ memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len);
+
+ return priv->ibss_beacon->len;
+}
+
+int iwl_rate_index_from_plcp(int plcp)
+{
+ int i = 0;
+
+ if (plcp & RATE_MCS_HT_MSK) {
+ i = (plcp & 0xff);
+
+ if (i >= IWL_RATE_MIMO_6M_PLCP)
+ i = i - IWL_RATE_MIMO_6M_PLCP;
+
+ i += IWL_FIRST_OFDM_RATE;
+ /* skip 9M not supported in ht*/
+ if (i >= IWL_RATE_9M_INDEX)
+ i += 1;
+ if ((i >= IWL_FIRST_OFDM_RATE) &&
+ (i <= IWL_LAST_OFDM_RATE))
+ return i;
+ } else {
+ for (i = 0; i < ARRAY_SIZE(iwl_rates); i++)
+ if (iwl_rates[i].plcp == (plcp &0xFF))
+ return i;
+ }
+ return -1;
+}
+
+static u8 iwl_rate_get_lowest_plcp(int rate_mask)
+{
+ u8 i;
+
+ for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
+ i = iwl_rates[i].next_ieee) {
+ if (rate_mask & (1 << i))
+ return iwl_rates[i].plcp;
+ }
+
+ return IWL_RATE_INVALID;
+}
+
+static int iwl_send_beacon_cmd(struct iwl_priv *priv)
+{
+ struct iwl_frame *frame;
+ unsigned int frame_size;
+ int rc;
+ u8 rate;
+
+ frame = iwl_get_free_frame(priv);
+
+ if (!frame) {
+ IWL_ERROR("Could not obtain free frame buffer for beacon "
+ "command.\n");
+ return -ENOMEM;
+ }
+
+ if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
+ rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic &
+ 0xFF0);
+ if (rate == IWL_INVALID_RATE)
+ rate = IWL_RATE_6M_PLCP;
+ } else {
+ rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
+ if (rate == IWL_INVALID_RATE)
+ rate = IWL_RATE_1M_PLCP;
+ }
+
+ frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
+
+ rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
+ &frame->u.cmd[0]);
+
+ iwl_free_frame(priv, frame);
+
+ return rc;
+}
+
+/******************************************************************************
+ *
+ * EEPROM related functions
+ *
+ ******************************************************************************/
+
+static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac)
+{
+ memcpy(mac, priv->eeprom.mac_address, 6);
+}
+
+/**
+ * iwl_eeprom_init - read EEPROM contents
+ *
+ * Load the EEPROM from adapter into priv->eeprom
+ *
+ * NOTE: This routine uses the non-debug IO access functions.
+ */
+int iwl_eeprom_init(struct iwl_priv *priv)
+{
+ u16 *e = (u16 *)&priv->eeprom;
+ u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
+ u32 r;
+ int sz = sizeof(priv->eeprom);
+ int rc;
+ int i;
+ u16 addr;
+
+ /* The EEPROM structure has several padding buffers within it
+ * and when adding new EEPROM maps is subject to programmer errors
+ * which may be very difficult to identify without explicitly
+ * checking the resulting size of the eeprom map. */
+ BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
+
+ if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
+ IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
+ return -ENOENT;
+ }
+
+ rc = iwl_eeprom_aqcuire_semaphore(priv);
+ if (rc < 0) {
+ IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n");
+ return -ENOENT;
+ }
+
+ /* eeprom is an array of 16bit values */
+ for (addr = 0; addr < sz; addr += sizeof(u16)) {
+ _iwl_write32(priv, CSR_EEPROM_REG, addr << 1);
+ _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
+
+ for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
+ i += IWL_EEPROM_ACCESS_DELAY) {
+ r = _iwl_read_restricted(priv, CSR_EEPROM_REG);
+ if (r & CSR_EEPROM_REG_READ_VALID_MSK)
+ break;
+ udelay(IWL_EEPROM_ACCESS_DELAY);
+ }
+
+ if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
+ IWL_ERROR("Time out reading EEPROM[%d]", addr);
+ rc = -ETIMEDOUT;
+ goto done;
+ }
+ e[addr / 2] = le16_to_cpu(r >> 16);
+ }
+ rc = 0;
+
+done:
+ iwl_eeprom_release_semaphore(priv);
+ return rc;
+}
+
+/******************************************************************************
+ *
+ * Misc. internal state and helper functions
+ *
+ ******************************************************************************/
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/**
+ * iwl_report_frame - dump frame to syslog during debug sessions
+ *
+ * hack this function to show different aspects of received frames,
+ * including selective frame dumps.
+ * group100 parameter selects whether to show 1 out of 100 good frames.
+ *
+ * TODO: ieee80211_hdr stuff is common to 3945 and 4965, so frame type
+ * info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats)
+ * is 3945-specific and gives bad output for 4965. Need to split the
+ * functionality, keep common stuff here.
+ */
+void iwl_report_frame(struct iwl_priv *priv,
+ struct iwl_rx_packet *pkt,
+ struct ieee80211_hdr *header, int group100)
+{
+ u32 to_us;
+ u32 print_summary = 0;
+ u32 print_dump = 0; /* set to 1 to dump all frames' contents */
+ u32 hundred = 0;
+ u32 dataframe = 0;
+ u16 fc;
+ u16 seq_ctl;
+ u16 channel;
+ u16 phy_flags;
+ int rate_sym;
+ u16 length;
+ u16 status;
+ u16 bcn_tmr;
+ u32 tsf_low;
+ u64 tsf;
+ u8 rssi;
+ u8 agc;
+ u16 sig_avg;
+ u16 noise_diff;
+ struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+ struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+ struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+ u8 *data = IWL_RX_DATA(pkt);
+
+ /* MAC header */
+ fc = le16_to_cpu(header->frame_control);
+ seq_ctl = le16_to_cpu(header->seq_ctrl);
+
+ /* metadata */
+ channel = le16_to_cpu(rx_hdr->channel);
+ phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+ rate_sym = rx_hdr->rate;
+ length = le16_to_cpu(rx_hdr->len);
+
+ /* end-of-frame status and timestamp */
+ status = le32_to_cpu(rx_end->status);
+ bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
+ tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
+ tsf = le64_to_cpu(rx_end->timestamp);
+
+ /* signal statistics */
+ rssi = rx_stats->rssi;
+ agc = rx_stats->agc;
+ sig_avg = le16_to_cpu(rx_stats->sig_avg);
+ noise_diff = le16_to_cpu(rx_stats->noise_diff);
+
+ to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
+
+ /* if data frame is to us and all is good,
+ * (optionally) print summary for only 1 out of every 100 */
+ if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) ==
+ (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
+ dataframe = 1;
+ if (!group100)
+ print_summary = 1; /* print each frame */
+ else if (priv->framecnt_to_us < 100) {
+ priv->framecnt_to_us++;
+ print_summary = 0;
+ } else {
+ priv->framecnt_to_us = 0;
+ print_summary = 1;
+ hundred = 1;
+ }
+ } else {
+ /* print summary for all other frames */
+ print_summary = 1;
+ }
+
+ if (print_summary) {
+ char *title;
+ u32 rate;
+
+ if (hundred)
+ title = "100Frames";
+ else if (fc & IEEE80211_FCTL_RETRY)
+ title = "Retry";
+ else if (ieee80211_is_assoc_response(fc))
+ title = "AscRsp";
+ else if (ieee80211_is_reassoc_response(fc))
+ title = "RasRsp";
+ else if (ieee80211_is_probe_response(fc)) {
+ title = "PrbRsp";
+ print_dump = 1; /* dump frame contents */
+ } else if (ieee80211_is_beacon(fc)) {
+ title = "Beacon";
+ print_dump = 1; /* dump frame contents */
+ } else if (ieee80211_is_atim(fc))
+ title = "ATIM";
+ else if (ieee80211_is_auth(fc))
+ title = "Auth";
+ else if (ieee80211_is_deauth(fc))
+ title = "DeAuth";
+ else if (ieee80211_is_disassoc(fc))
+ title = "DisAssoc";
+ else
+ title = "Frame";
+
+ rate = iwl_rate_index_from_plcp(rate_sym);
+ if (rate == -1)
+ rate = 0;
+ else
+ rate = iwl_rates[rate].ieee / 2;
+
+ /* print frame summary.
+ * MAC addresses show just the last byte (for brevity),
+ * but you can hack it to show more, if you'd like to. */
+ if (dataframe)
+ IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
+ "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
+ title, fc, header->addr1[5],
+ length, rssi, channel, rate);
+ else {
+ /* src/dst addresses assume managed mode */
+ IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
+ "src=0x%02x, rssi=%u, tim=%lu usec, "
+ "phy=0x%02x, chnl=%d\n",
+ title, fc, header->addr1[5],
+ header->addr3[5], rssi,
+ tsf_low - priv->scan_start_tsf,
+ phy_flags, channel);
+ }
+ }
+ if (print_dump)
+ iwl_print_hex_dump(IWL_DL_RX, data, length);
+}
+#endif
+
+static void iwl_unset_hw_setting(struct iwl_priv *priv)
+{
+ if (priv->hw_setting.shared_virt)
+ pci_free_consistent(priv->pci_dev,
+ sizeof(struct iwl_shared),
+ priv->hw_setting.shared_virt,
+ priv->hw_setting.shared_phys);
+}
+
+/**
+ * iwl_supported_rate_to_ie - fill in the supported rate in IE field
+ *
+ * return : set the bit for each supported rate insert in ie
+ */
+static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+ u16 basic_rate, int *left)
+{
+ u16 ret_rates = 0, bit;
+ int i;
+ u8 *cnt = ie;
+ u8 *rates = ie + 1;
+
+ for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
+ if (bit & supported_rate) {
+ ret_rates |= bit;
+ rates[*cnt] = iwl_rates[i].ieee |
+ ((bit & basic_rate) ? 0x80 : 0x00);
+ (*cnt)++;
+ (*left)--;
+ if ((*left <= 0) ||
+ (*cnt >= IWL_SUPPORTED_RATES_IE_LEN))
+ break;
+ }
+ }
+
+ return ret_rates;
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+void static iwl_set_ht_capab(struct ieee80211_hw *hw,
+ struct ieee80211_ht_capability *ht_cap,
+ u8 use_wide_chan);
+#endif
+
+/**
+ * iwl_fill_probe_req - fill in all required fields and IE for probe request
+ */
+static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+ struct ieee80211_mgmt *frame,
+ int left, int is_direct)
+{
+ int len = 0;
+ u8 *pos = NULL;
+ u16 active_rates, ret_rates, cck_rates;
+
+ /* Make sure there is enough space for the probe request,
+ * two mandatory IEs and the data */
+ left -= 24;
+ if (left < 0)
+ return 0;
+ len += 24;
+
+ frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+ memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN);
+ memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
+ memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN);
+ frame->seq_ctrl = 0;
+
+ /* fill in our indirect SSID IE */
+ /* ...next IE... */
+
+ left -= 2;
+ if (left < 0)
+ return 0;
+ len += 2;
+ pos = &(frame->u.probe_req.variable[0]);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = 0;
+
+ /* fill in our direct SSID IE... */
+ if (is_direct) {
+ /* ...next IE... */
+ left -= 2 + priv->essid_len;
+ if (left < 0)
+ return 0;
+ /* ... fill it in... */
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = priv->essid_len;
+ memcpy(pos, priv->essid, priv->essid_len);
+ pos += priv->essid_len;
+ len += 2 + priv->essid_len;
+ }
+
+ /* fill in supported rate */
+ /* ...next IE... */
+ left -= 2;
+ if (left < 0)
+ return 0;
+
+ /* ... fill it in... */
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos = 0;
+
+ priv->active_rate = priv->rates_mask;
+ active_rates = priv->active_rate;
+ priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+ cck_rates = IWL_CCK_RATES_MASK & active_rates;
+ ret_rates = iwl_supported_rate_to_ie(pos, cck_rates,
+ priv->active_rate_basic, &left);
+ active_rates &= ~ret_rates;
+
+ ret_rates = iwl_supported_rate_to_ie(pos, active_rates,
+ priv->active_rate_basic, &left);
+ active_rates &= ~ret_rates;
+
+ len += 2 + *pos;
+ pos += (*pos) + 1;
+ if (active_rates == 0)
+ goto fill_end;
+
+ /* fill in supported extended rate */
+ /* ...next IE... */
+ left -= 2;
+ if (left < 0)
+ return 0;
+ /* ... fill it in... */
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos = 0;
+ iwl_supported_rate_to_ie(pos, active_rates,
+ priv->active_rate_basic, &left);
+ if (*pos > 0)
+ len += 2 + *pos;
+
+#ifdef CONFIG_IWLWIFI_HT
+ if (is_direct && priv->is_ht_enabled) {
+ u8 use_wide_chan = 1;
+
+ if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
+ use_wide_chan = 0;
+ pos += (*pos) + 1;
+ *pos++ = WLAN_EID_HT_CAPABILITY;
+ *pos++ = sizeof(struct ieee80211_ht_capability);
+ iwl_set_ht_capab(NULL, (struct ieee80211_ht_capability *)pos,
+ use_wide_chan);
+ len += 2 + sizeof(struct ieee80211_ht_capability);
+ }
+#endif /*CONFIG_IWLWIFI_HT */
+
+ fill_end:
+ return (u16)len;
+}
+
+/*
+ * QoS support
+*/
+#ifdef CONFIG_IWLWIFI_QOS
+static int iwl_send_qos_params_command(struct iwl_priv *priv,
+ struct iwl_qosparam_cmd *qos)
+{
+
+ return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM,
+ sizeof(struct iwl_qosparam_cmd), qos);
+}
+
+static void iwl_reset_qos(struct iwl_priv *priv)
+{
+ u16 cw_min = 15;
+ u16 cw_max = 1023;
+ u8 aifs = 2;
+ u8 is_legacy = 0;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->qos_data.qos_active = 0;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
+ if (priv->qos_data.qos_enable)
+ priv->qos_data.qos_active = 1;
+ if (!(priv->active_rate & 0xfff0)) {
+ cw_min = 31;
+ is_legacy = 1;
+ }
+ } else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (priv->qos_data.qos_enable)
+ priv->qos_data.qos_active = 1;
+ } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
+ cw_min = 31;
+ is_legacy = 1;
+ }
+
+ if (priv->qos_data.qos_active)
+ aifs = 3;
+
+ priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
+ priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
+ priv->qos_data.def_qos_parm.ac[0].edca_txop = 0;
+ priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
+
+ if (priv->qos_data.qos_active) {
+ i = 1;
+ priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
+ priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = 7;
+ priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+ i = 2;
+ priv->qos_data.def_qos_parm.ac[i].cw_min =
+ cpu_to_le16((cw_min + 1) / 2 - 1);
+ priv->qos_data.def_qos_parm.ac[i].cw_max =
+ cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+ if (is_legacy)
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(6016);
+ else
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(3008);
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+ i = 3;
+ priv->qos_data.def_qos_parm.ac[i].cw_min =
+ cpu_to_le16((cw_min + 1) / 4 - 1);
+ priv->qos_data.def_qos_parm.ac[i].cw_max =
+ cpu_to_le16((cw_max + 1) / 2 - 1);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+ if (is_legacy)
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(3264);
+ else
+ priv->qos_data.def_qos_parm.ac[i].edca_txop =
+ cpu_to_le16(1504);
+ } else {
+ for (i = 1; i < 4; i++) {
+ priv->qos_data.def_qos_parm.ac[i].cw_min =
+ cpu_to_le16(cw_min);
+ priv->qos_data.def_qos_parm.ac[i].cw_max =
+ cpu_to_le16(cw_max);
+ priv->qos_data.def_qos_parm.ac[i].aifsn = aifs;
+ priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+ priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+ }
+ }
+ IWL_DEBUG_QOS("set QoS to default \n");
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+{
+ unsigned long flags;
+
+ if (priv == NULL)
+ return;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (!priv->qos_data.qos_enable)
+ return;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->qos_data.def_qos_parm.qos_flags = 0;
+
+ if (priv->qos_data.qos_cap.q_AP.queue_request &&
+ !priv->qos_data.qos_cap.q_AP.txop_request)
+ priv->qos_data.def_qos_parm.qos_flags |=
+ QOS_PARAM_FLG_TXOP_TYPE_MSK;
+
+ if (priv->qos_data.qos_active)
+ priv->qos_data.def_qos_parm.qos_flags |=
+ QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (force || iwl_is_associated(priv)) {
+ IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n",
+ priv->qos_data.qos_active);
+
+ iwl_send_qos_params_command(priv,
+ &(priv->qos_data.def_qos_parm));
+ }
+}
+
+#endif /* CONFIG_IWLWIFI_QOS */
+/*
+ * Power management (not Tx power!) functions
+ */
+#define MSEC_TO_USEC 1024
+
+#define NOSLP __constant_cpu_to_le16(0), 0, 0
+#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
+#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
+#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
+ __constant_cpu_to_le32(X1), \
+ __constant_cpu_to_le32(X2), \
+ __constant_cpu_to_le32(X3), \
+ __constant_cpu_to_le32(X4)}
+
+
+/* default power management (not Tx power) table values */
+/* for tim 0-10 */
+static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
+ {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1},
+ {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
+};
+
+/* for tim > 10 */
+static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
+ {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
+ SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300),
+ SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100),
+ SLP_VEC(2, 6, 9, 9, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+ {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25),
+ SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
+};
+
+int iwl_power_init_handle(struct iwl_priv *priv)
+{
+ int rc = 0, i;
+ struct iwl_power_mgr *pow_data;
+ int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC;
+ u16 pci_pm;
+
+ IWL_DEBUG_POWER("Initialize power \n");
+
+ pow_data = &(priv->power_data);
+
+ memset(pow_data, 0, sizeof(*pow_data));
+
+ pow_data->active_index = IWL_POWER_RANGE_0;
+ pow_data->dtim_val = 0xffff;
+
+ memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
+ memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
+
+ rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm);
+ if (rc != 0)
+ return 0;
+ else {
+ struct iwl_powertable_cmd *cmd;
+
+ IWL_DEBUG_POWER("adjust power command flags\n");
+
+ for (i = 0; i < IWL_POWER_AC; i++) {
+ cmd = &pow_data->pwr_range_0[i].cmd;
+
+ if (pci_pm & 0x1)
+ cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+ else
+ cmd->flags |= IWL_POWER_PCI_PM_MSK;
+ }
+ }
+ return rc;
+}
+
+static int iwl_update_power_cmd(struct iwl_priv *priv,
+ struct iwl_powertable_cmd *cmd, u32 mode)
+{
+ int rc = 0, i;
+ u8 skip;
+ u32 max_sleep = 0;
+ struct iwl_power_vec_entry *range;
+ u8 period = 0;
+ struct iwl_power_mgr *pow_data;
+
+ if (mode > IWL_POWER_INDEX_5) {
+ IWL_DEBUG_POWER("Error invalid power mode \n");
+ return -1;
+ }
+ pow_data = &(priv->power_data);
+
+ if (pow_data->active_index == IWL_POWER_RANGE_0)
+ range = &pow_data->pwr_range_0[0];
+ else
+ range = &pow_data->pwr_range_1[1];
+
+ memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd));
+
+#ifdef IWL_MAC80211_DISABLE
+ if (priv->assoc_network != NULL) {
+ unsigned long flags;
+
+ period = priv->assoc_network->tim.tim_period;
+ }
+#endif /*IWL_MAC80211_DISABLE */
+ skip = range[mode].no_dtim;
+
+ if (period == 0) {
+ period = 1;
+ skip = 0;
+ }
+
+ if (skip == 0) {
+ max_sleep = period;
+ cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
+ } else {
+ __le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
+ max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
+ cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
+ }
+
+ for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
+ if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
+ cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
+ }
+
+ IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
+ IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
+ IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
+ IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
+ le32_to_cpu(cmd->sleep_interval[0]),
+ le32_to_cpu(cmd->sleep_interval[1]),
+ le32_to_cpu(cmd->sleep_interval[2]),
+ le32_to_cpu(cmd->sleep_interval[3]),
+ le32_to_cpu(cmd->sleep_interval[4]));
+
+ return rc;
+}
+
+static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
+{
+ u32 final_mode = mode;
+ int rc;
+ struct iwl_powertable_cmd cmd;
+
+ /* If on battery, set to 3,
+ * if plugged into AC power, set to CAM ("continuosly aware mode"),
+ * else user level */
+ switch (mode) {
+ case IWL_POWER_BATTERY:
+ final_mode = IWL_POWER_INDEX_3;
+ break;
+ case IWL_POWER_AC:
+ final_mode = IWL_POWER_MODE_CAM;
+ break;
+ default:
+ final_mode = mode;
+ break;
+ }
+
+ cmd.keep_alive_beacons = 0;
+
+ iwl_update_power_cmd(priv, &cmd, final_mode);
+
+ rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
+
+ if (final_mode == IWL_POWER_MODE_CAM)
+ clear_bit(STATUS_POWER_PMI, &priv->status);
+ else
+ set_bit(STATUS_POWER_PMI, &priv->status);
+
+ return rc;
+}
+
+int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+{
+ /* Filter incoming packets to determine if they are targeted toward
+ * this network, discarding packets coming from ourselves */
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */
+ /* packets from our adapter are dropped (echo) */
+ if (!compare_ether_addr(header->addr2, priv->mac_addr))
+ return 0;
+ /* {broad,multi}cast packets to our IBSS go through */
+ if (is_multicast_ether_addr(header->addr1))
+ return !compare_ether_addr(header->addr3, priv->bssid);
+ /* packets to our adapter go through */
+ return !compare_ether_addr(header->addr1, priv->mac_addr);
+ case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+ /* packets from our adapter are dropped (echo) */
+ if (!compare_ether_addr(header->addr3, priv->mac_addr))
+ return 0;
+ /* {broad,multi}cast packets to our BSS go through */
+ if (is_multicast_ether_addr(header->addr1))
+ return !compare_ether_addr(header->addr2, priv->bssid);
+ /* packets to our adapter go through */
+ return !compare_ether_addr(header->addr1, priv->mac_addr);
+ }
+
+ return 1;
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+const char *iwl_get_tx_fail_reason(u32 status)
+{
+ switch (status & TX_STATUS_MSK) {
+ case TX_STATUS_SUCCESS:
+ return "SUCCESS";
+ TX_STATUS_ENTRY(SHORT_LIMIT);
+ TX_STATUS_ENTRY(LONG_LIMIT);
+ TX_STATUS_ENTRY(FIFO_UNDERRUN);
+ TX_STATUS_ENTRY(MGMNT_ABORT);
+ TX_STATUS_ENTRY(NEXT_FRAG);
+ TX_STATUS_ENTRY(LIFE_EXPIRE);
+ TX_STATUS_ENTRY(DEST_PS);
+ TX_STATUS_ENTRY(ABORTED);
+ TX_STATUS_ENTRY(BT_RETRY);
+ TX_STATUS_ENTRY(STA_INVALID);
+ TX_STATUS_ENTRY(FRAG_DROPPED);
+ TX_STATUS_ENTRY(TID_DISABLE);
+ TX_STATUS_ENTRY(FRAME_FLUSHED);
+ TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
+ TX_STATUS_ENTRY(TX_LOCKED);
+ TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
+ }
+
+ return "UNKNOWN";
+}
+
+/**
+ * iwl_scan_cancel - Cancel any currently executing HW scan
+ *
+ * NOTE: priv->mutex is not required before calling this function
+ */
+static int iwl_scan_cancel(struct iwl_priv *priv)
+{
+ if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+ clear_bit(STATUS_SCANNING, &priv->status);
+ return 0;
+ }
+
+ if (test_bit(STATUS_SCANNING, &priv->status)) {
+ if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_SCAN("Queuing scan abort.\n");
+ set_bit(STATUS_SCAN_ABORTING, &priv->status);
+ queue_work(priv->workqueue, &priv->abort_scan);
+
+ } else
+ IWL_DEBUG_SCAN("Scan abort already in progress.\n");
+
+ return test_bit(STATUS_SCANNING, &priv->status);
+ }
+
+ return 0;
+}
+
+/**
+ * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
+ * @ms: amount of time to wait (in milliseconds) for scan to abort
+ *
+ * NOTE: priv->mutex must be held before calling this function
+ */
+static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+{
+ unsigned long now = jiffies;
+ int ret;
+
+ ret = iwl_scan_cancel(priv);
+ if (ret && ms) {
+ mutex_unlock(&priv->mutex);
+ while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
+ test_bit(STATUS_SCANNING, &priv->status))
+ msleep(1);
+ mutex_lock(&priv->mutex);
+
+ return test_bit(STATUS_SCANNING, &priv->status);
+ }
+
+ return ret;
+}
+
+static void iwl_sequence_reset(struct iwl_priv *priv)
+{
+ /* Reset ieee stats */
+
+ /* We don't reset the net_device_stats (ieee->stats) on
+ * re-association */
+
+ priv->last_seq_num = -1;
+ priv->last_frag_num = -1;
+ priv->last_packet_time = 0;
+
+ iwl_scan_cancel(priv);
+}
+
+#define MAX_UCODE_BEACON_INTERVAL 4096
+#define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA)
+
+static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
+{
+ u16 new_val = 0;
+ u16 beacon_factor = 0;
+
+ beacon_factor =
+ (beacon_val + MAX_UCODE_BEACON_INTERVAL)
+ / MAX_UCODE_BEACON_INTERVAL;
+ new_val = beacon_val / beacon_factor;
+
+ return cpu_to_le16(new_val);
+}
+
+static void iwl_setup_rxon_timing(struct iwl_priv *priv)
+{
+ u64 interval_tm_unit;
+ u64 tsf, result;
+ unsigned long flags;
+ struct ieee80211_conf *conf = NULL;
+ u16 beacon_int = 0;
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp1);
+ priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0);
+
+ priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
+
+ tsf = priv->timestamp1;
+ tsf = ((tsf << 32) | priv->timestamp0);
+
+ beacon_int = priv->beacon_int;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+ if (beacon_int == 0) {
+ priv->rxon_timing.beacon_interval = cpu_to_le16(100);
+ priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
+ } else {
+ priv->rxon_timing.beacon_interval =
+ cpu_to_le16(beacon_int);
+ priv->rxon_timing.beacon_interval =
+ iwl_adjust_beacon_interval(
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+ }
+
+ priv->rxon_timing.atim_window = 0;
+ } else {
+ priv->rxon_timing.beacon_interval =
+ iwl_adjust_beacon_interval(conf->beacon_int);
+ /* TODO: we need to get atim_window from upper stack
+ * for now we set to 0 */
+ priv->rxon_timing.atim_window = 0;
+ }
+
+ interval_tm_unit =
+ (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
+ result = do_div(tsf, interval_tm_unit);
+ priv->rxon_timing.beacon_init_val =
+ cpu_to_le32((u32) ((u64) interval_tm_unit - result));
+
+ IWL_DEBUG_ASSOC
+ ("beacon interval %d beacon timer %d beacon tim %d\n",
+ le16_to_cpu(priv->rxon_timing.beacon_interval),
+ le32_to_cpu(priv->rxon_timing.beacon_init_val),
+ le16_to_cpu(priv->rxon_timing.atim_window));
+}
+
+static int iwl_scan_initiate(struct iwl_priv *priv)
+{
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ IWL_ERROR("APs don't scan.\n");
+ return 0;
+ }
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
+ return -EIO;
+ }
+
+ if (test_bit(STATUS_SCANNING, &priv->status)) {
+ IWL_DEBUG_SCAN("Scan already in progress.\n");
+ return -EAGAIN;
+ }
+
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_SCAN("Scan request while abort pending. "
+ "Queuing.\n");
+ return -EAGAIN;
+ }
+
+ IWL_DEBUG_INFO("Starting scan...\n");
+ priv->scan_bands = 2;
+ set_bit(STATUS_SCANNING, &priv->status);
+ priv->scan_start = jiffies;
+ priv->scan_pass_start = priv->scan_start;
+
+ queue_work(priv->workqueue, &priv->request_scan);
+
+ return 0;
+}
+
+static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+{
+ struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+
+ if (hw_decrypt)
+ rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
+ else
+ rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
+
+ return 0;
+}
+
+static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
+{
+ if (phymode == MODE_IEEE80211A) {
+ priv->staging_rxon.flags &=
+ ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
+ | RXON_FLG_CCK_MSK);
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ } else {
+ /* Copied from iwl_bg_post_associate() */
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+ priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
+ priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
+ }
+}
+
+/*
+ * initilize rxon structure with default values fromm eeprom
+ */
+static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+{
+ const struct iwl_channel_info *ch_info;
+
+ memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
+
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_AP:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
+ break;
+
+ case IEEE80211_IF_TYPE_STA:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
+ priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
+ break;
+
+ case IEEE80211_IF_TYPE_IBSS:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
+ priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
+ priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
+ RXON_FILTER_ACCEPT_GRP_MSK;
+ break;
+
+ case IEEE80211_IF_TYPE_MNTR:
+ priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
+ priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
+ RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
+ break;
+ }
+
+#if 0
+ /* TODO: Figure out when short_preamble would be set and cache from
+ * that */
+ if (!hw_to_local(priv->hw)->short_preamble)
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+#endif
+
+ ch_info = iwl_get_channel_info(priv, priv->phymode,
+ le16_to_cpu(priv->staging_rxon.channel));
+
+ if (!ch_info)
+ ch_info = &priv->channel_info[0];
+
+ /*
+ * in some case A channels are all non IBSS
+ * in this case force B/G channel
+ */
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+ !(is_channel_ibss(ch_info)))
+ ch_info = &priv->channel_info[0];
+
+ priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
+ if (is_channel_a_band(ch_info))
+ priv->phymode = MODE_IEEE80211A;
+ else
+ priv->phymode = MODE_IEEE80211G;
+
+ iwl_set_flags_for_phymode(priv, priv->phymode);
+
+ priv->staging_rxon.ofdm_basic_rates =
+ (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+ priv->staging_rxon.cck_basic_rates =
+ (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+
+ priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
+ RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
+ memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+ memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
+ priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
+ priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
+ iwl4965_set_rxon_chain(priv);
+}
+
+static int iwl_set_mode(struct iwl_priv *priv, int mode)
+{
+ if (!iwl_is_ready_rf(priv))
+ return -EAGAIN;
+
+ if (mode == IEEE80211_IF_TYPE_IBSS) {
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv,
+ priv->phymode,
+ le16_to_cpu(priv->staging_rxon.channel));
+
+ if (!ch_info || !is_channel_ibss(ch_info)) {
+ IWL_ERROR("channel %d not IBSS channel\n",
+ le16_to_cpu(priv->staging_rxon.channel));
+ return -EINVAL;
+ }
+ }
+
+ cancel_delayed_work(&priv->scan_check);
+ if (iwl_scan_cancel_timeout(priv, 100)) {
+ IWL_WARNING("Aborted scan still in progress after 100ms\n");
+ IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+ return -EAGAIN;
+ }
+
+ priv->iw_mode = mode;
+
+ iwl_connection_init_rx_config(priv);
+ memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+
+ iwl_clear_stations_table(priv);
+
+ iwl_commit_rxon(priv);
+
+ return 0;
+}
+
+static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
+ struct ieee80211_tx_control *ctl,
+ struct iwl_cmd *cmd,
+ struct sk_buff *skb_frag,
+ int last_frag)
+{
+ struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+
+ switch (keyinfo->alg) {
+ case ALG_CCMP:
+ cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM;
+ memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen);
+ IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
+ break;
+
+ case ALG_TKIP:
+#if 0
+ cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP;
+
+ if (last_frag)
+ memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8,
+ 8);
+ else
+ memset(cmd->cmd.tx.tkip_mic.byte, 0, 8);
+#endif
+ break;
+
+ case ALG_WEP:
+ cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
+ (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
+
+ if (keyinfo->keylen == 13)
+ cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
+
+ memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
+
+ IWL_DEBUG_TX("Configuring packet for WEP encryption "
+ "with key %d\n", ctl->key_idx);
+ break;
+
+ default:
+ printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg);
+ break;
+ }
+}
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct ieee80211_tx_control *ctrl,
+ struct ieee80211_hdr *hdr,
+ int is_unicast, u8 std_id)
+{
+ __le16 *qc;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ __le32 tx_flags = cmd->cmd.tx.tx_flags;
+
+ cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+ if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
+ tx_flags |= TX_CMD_FLG_ACK_MSK;
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ if (ieee80211_is_probe_response(fc) &&
+ !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
+ tx_flags |= TX_CMD_FLG_TSF_MSK;
+ } else {
+ tx_flags &= (~TX_CMD_FLG_ACK_MSK);
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+ }
+
+ cmd->cmd.tx.sta_id = std_id;
+ if (ieee80211_get_morefrag(hdr))
+ tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+
+ qc = ieee80211_get_qos_ctrl(hdr);
+ if (qc) {
+ cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf);
+ tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+ } else
+ tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+
+ if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+ tx_flags |= TX_CMD_FLG_RTS_MSK;
+ tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+ } else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+ tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+ tx_flags |= TX_CMD_FLG_CTS_MSK;
+ }
+
+ if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
+ tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+ tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+ if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
+ (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
+ cmd->cmd.tx.timeout.pm_frame_timeout =
+ cpu_to_le16(3);
+ else
+ cmd->cmd.tx.timeout.pm_frame_timeout =
+ cpu_to_le16(2);
+ } else
+ cmd->cmd.tx.timeout.pm_frame_timeout = 0;
+
+ cmd->cmd.tx.driver_txop = 0;
+ cmd->cmd.tx.tx_flags = tx_flags;
+ cmd->cmd.tx.next_frame_len = 0;
+}
+
+static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+{
+ int sta_id;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ DECLARE_MAC_BUF(mac);
+
+ /* If this frame is broadcast or not data then use the broadcast
+ * station id */
+ if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
+ is_multicast_ether_addr(hdr->addr1))
+ return priv->hw_setting.bcast_sta_id;
+
+ switch (priv->iw_mode) {
+
+ /* If this frame is part of a BSS network (we're a station), then
+ * we use the AP's station id */
+ case IEEE80211_IF_TYPE_STA:
+ return IWL_AP_ID;
+
+ /* If we are an AP, then find the station, or use BCAST */
+ case IEEE80211_IF_TYPE_AP:
+ sta_id = iwl_hw_find_station(priv, hdr->addr1);
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+ return priv->hw_setting.bcast_sta_id;
+
+ /* If this frame is part of a IBSS network, then we use the
+ * target specific station id */
+ case IEEE80211_IF_TYPE_IBSS:
+ sta_id = iwl_hw_find_station(priv, hdr->addr1);
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+
+ sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC);
+
+ if (sta_id != IWL_INVALID_STATION)
+ return sta_id;
+
+ IWL_DEBUG_DROP("Station %s not in station map. "
+ "Defaulting to broadcast...\n",
+ print_mac(mac, hdr->addr1));
+ iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+ return priv->hw_setting.bcast_sta_id;
+
+ default:
+ IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode);
+ return priv->hw_setting.bcast_sta_id;
+ }
+}
+
+/*
+ * start REPLY_TX command process
+ */
+static int iwl_tx_skb(struct iwl_priv *priv,
+ struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct iwl_tfd_frame *tfd;
+ u32 *control_flags;
+ int txq_id = ctl->queue;
+ struct iwl_tx_queue *txq = NULL;
+ struct iwl_queue *q = NULL;
+ dma_addr_t phys_addr;
+ dma_addr_t txcmd_phys;
+ struct iwl_cmd *out_cmd = NULL;
+ u16 len, idx, len_org;
+ u8 id, hdr_len, unicast;
+ u8 sta_id;
+ u16 seq_number = 0;
+ u16 fc;
+ __le16 *qc;
+ u8 wait_write_ptr = 0;
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_DROP("Dropping - RF KILL\n");
+ goto drop_unlock;
+ }
+
+ if (!priv->interface_id) {
+ IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
+ goto drop_unlock;
+ }
+
+ if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) {
+ IWL_ERROR("ERROR: No TX rate available.\n");
+ goto drop_unlock;
+ }
+
+ unicast = !is_multicast_ether_addr(hdr->addr1);
+ id = 0;
+
+ fc = le16_to_cpu(hdr->frame_control);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (ieee80211_is_auth(fc))
+ IWL_DEBUG_TX("Sending AUTH frame\n");
+ else if (ieee80211_is_assoc_request(fc))
+ IWL_DEBUG_TX("Sending ASSOC frame\n");
+ else if (ieee80211_is_reassoc_request(fc))
+ IWL_DEBUG_TX("Sending REASSOC frame\n");
+#endif
+
+ if (!iwl_is_associated(priv) &&
+ ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+ IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
+ goto drop_unlock;
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ hdr_len = ieee80211_get_hdrlen(fc);
+ sta_id = iwl_get_sta_id(priv, hdr);
+ if (sta_id == IWL_INVALID_STATION) {
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
+ print_mac(mac, hdr->addr1));
+ goto drop;
+ }
+
+ IWL_DEBUG_RATE("station Id %d\n", sta_id);
+
+ qc = ieee80211_get_qos_ctrl(hdr);
+ if (qc) {
+ u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+ seq_number = priv->stations[sta_id].tid[tid].seq_number &
+ IEEE80211_SCTL_SEQ;
+ hdr->seq_ctrl = cpu_to_le16(seq_number) |
+ (hdr->seq_ctrl &
+ __constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
+ seq_number += 0x10;
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ /* aggregation is on for this <sta,tid> */
+ if (ctl->flags & IEEE80211_TXCTL_HT_MPDU_AGG)
+ txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+ }
+ txq = &priv->txq[txq_id];
+ q = &txq->q;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ tfd = &txq->bd[q->first_empty];
+ memset(tfd, 0, sizeof(*tfd));
+ control_flags = (u32 *) tfd;
+ idx = get_cmd_index(q, q->first_empty, 0);
+
+ memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info));
+ txq->txb[q->first_empty].skb[0] = skb;
+ memcpy(&(txq->txb[q->first_empty].status.control),
+ ctl, sizeof(struct ieee80211_tx_control));
+ out_cmd = &txq->cmd[idx];
+ memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
+ memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
+ out_cmd->hdr.cmd = REPLY_TX;
+ out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+ INDEX_TO_SEQ(q->first_empty)));
+ /* copy frags header */
+ memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
+
+ /* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */
+ len = priv->hw_setting.tx_cmd_len +
+ sizeof(struct iwl_cmd_header) + hdr_len;
+
+ len_org = len;
+ len = (len + 3) & ~3;
+
+ if (len_org != len)
+ len_org = 1;
+ else
+ len_org = 0;
+
+ txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
+ offsetof(struct iwl_cmd, hdr);
+
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
+
+ if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+ iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+
+ /* 802.11 null functions have no payload... */
+ len = skb->len - hdr_len;
+ if (len) {
+ phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
+ len, PCI_DMA_TODEVICE);
+ iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
+ }
+
+ if (len_org)
+ out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+
+ len = (u16)skb->len;
+ out_cmd->cmd.tx.len = cpu_to_le16(len);
+
+ /* TODO need this for burst mode later on */
+ iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
+
+ /* set is_hcca to 0; it probably will never be implemented */
+ iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+
+ iwl4965_tx_cmd(priv, out_cmd, sta_id, txcmd_phys,
+ hdr, hdr_len, ctl, NULL);
+
+ if (!ieee80211_get_morefrag(hdr)) {
+ txq->need_update = 1;
+ if (qc) {
+ u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+ priv->stations[sta_id].tid[tid].seq_number = seq_number;
+ }
+ } else {
+ wait_write_ptr = 1;
+ txq->need_update = 0;
+ }
+
+ iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
+ sizeof(out_cmd->cmd.tx));
+
+ iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
+ ieee80211_get_hdrlen(fc));
+
+ iwl4965_tx_queue_update_wr_ptr(priv, txq, len);
+
+ q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
+ rc = iwl_tx_queue_update_write_ptr(priv, txq);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (rc)
+ return rc;
+
+ if ((iwl_queue_space(q) < q->high_mark)
+ && priv->mac80211_registered) {
+ if (wait_write_ptr) {
+ spin_lock_irqsave(&priv->lock, flags);
+ txq->need_update = 1;
+ iwl_tx_queue_update_write_ptr(priv, txq);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ ieee80211_stop_queue(priv->hw, ctl->queue);
+ }
+
+ return 0;
+
+drop_unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+drop:
+ return -1;
+}
+
+static void iwl_set_rate(struct iwl_priv *priv)
+{
+ const struct ieee80211_hw_mode *hw = NULL;
+ struct ieee80211_rate *rate;
+ int i;
+
+ hw = iwl_get_hw_mode(priv, priv->phymode);
+
+ priv->active_rate = 0;
+ priv->active_rate_basic = 0;
+
+ IWL_DEBUG_RATE("Setting rates for 802.11%c\n",
+ hw->mode == MODE_IEEE80211A ?
+ 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g'));
+
+ for (i = 0; i < hw->num_rates; i++) {
+ rate = &(hw->rates[i]);
+ if ((rate->val < IWL_RATE_COUNT) &&
+ (rate->flags & IEEE80211_RATE_SUPPORTED)) {
+ IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
+ rate->val, iwl_rates[rate->val].plcp,
+ (rate->flags & IEEE80211_RATE_BASIC) ?
+ "*" : "");
+ priv->active_rate |= (1 << rate->val);
+ if (rate->flags & IEEE80211_RATE_BASIC)
+ priv->active_rate_basic |= (1 << rate->val);
+ } else
+ IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
+ rate->val, iwl_rates[rate->val].plcp);
+ }
+
+ IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
+ priv->active_rate, priv->active_rate_basic);
+
+ /*
+ * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK)
+ * otherwise set it to the default of all CCK rates and 6, 12, 24 for
+ * OFDM
+ */
+ if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK)
+ priv->staging_rxon.cck_basic_rates =
+ ((priv->active_rate_basic &
+ IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF;
+ else
+ priv->staging_rxon.cck_basic_rates =
+ (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+
+ if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK)
+ priv->staging_rxon.ofdm_basic_rates =
+ ((priv->active_rate_basic &
+ (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >>
+ IWL_FIRST_OFDM_RATE) & 0xFF;
+ else
+ priv->staging_rxon.ofdm_basic_rates =
+ (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+}
+
+static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+{
+ unsigned long flags;
+
+ if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status))
+ return;
+
+ IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n",
+ disable_radio ? "OFF" : "ON");
+
+ if (disable_radio) {
+ iwl_scan_cancel(priv);
+ /* FIXME: This is a workaround for AP */
+ if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ CSR_UCODE_SW_BIT_RFKILL);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ }
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ clear_bit(STATUS_RF_KILL_SW, &priv->status);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* wake up ucode */
+ msleep(10);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_read32(priv, CSR_UCODE_DRV_GP1);
+ if (!iwl_grab_restricted_access(priv))
+ iwl_release_restricted_access(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+ IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+ "disabled by HW switch\n");
+ return;
+ }
+
+ queue_work(priv->workqueue, &priv->restart);
+ return;
+}
+
+void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
+ u32 decrypt_res, struct ieee80211_rx_status *stats)
+{
+ u16 fc =
+ le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control);
+
+ if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
+ return;
+
+ if (!(fc & IEEE80211_FCTL_PROTECTED))
+ return;
+
+ IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
+ switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
+ case RX_RES_STATUS_SEC_TYPE_TKIP:
+ if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+ RX_RES_STATUS_BAD_ICV_MIC)
+ stats->flag |= RX_FLAG_MMIC_ERROR;
+ case RX_RES_STATUS_SEC_TYPE_WEP:
+ case RX_RES_STATUS_SEC_TYPE_CCMP:
+ if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+ RX_RES_STATUS_DECRYPT_OK) {
+ IWL_DEBUG_RX("hw decrypt successfully!!!\n");
+ stats->flag |= RX_FLAG_DECRYPTED;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void iwl_handle_data_packet_monitor(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ void *data, short len,
+ struct ieee80211_rx_status *stats,
+ u16 phy_flags)
+{
+ struct iwl_rt_rx_hdr *iwl_rt;
+
+ /* First cache any information we need before we overwrite
+ * the information provided in the skb from the hardware */
+ s8 signal = stats->ssi;
+ s8 noise = 0;
+ int rate = stats->rate;
+ u64 tsf = stats->mactime;
+ __le16 phy_flags_hw = cpu_to_le16(phy_flags);
+
+ /* We received data from the HW, so stop the watchdog */
+ if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) {
+ IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
+ return;
+ }
+
+ /* copy the frame data to write after where the radiotap header goes */
+ iwl_rt = (void *)rxb->skb->data;
+ memmove(iwl_rt->payload, data, len);
+
+ iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+ iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */
+
+ /* total header + data */
+ iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt));
+
+ /* Set the size of the skb to the size of the frame */
+ skb_put(rxb->skb, sizeof(*iwl_rt) + len);
+
+ /* Big bitfield of all the fields we provide in radiotap */
+ iwl_rt->rt_hdr.it_present =
+ cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
+ (1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
+ (1 << IEEE80211_RADIOTAP_ANTENNA));
+
+ /* Zero the flags, we'll add to them as we go */
+ iwl_rt->rt_flags = 0;
+
+ iwl_rt->rt_tsf = cpu_to_le64(tsf);
+
+ /* Convert to dBm */
+ iwl_rt->rt_dbmsignal = signal;
+ iwl_rt->rt_dbmnoise = noise;
+
+ /* Convert the channel frequency and set the flags */
+ iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq);
+ if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
+ iwl_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
+ else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
+ iwl_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
+ else /* 802.11g */
+ iwl_rt->rt_chbitmask =
+ cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
+
+ rate = iwl_rate_index_from_plcp(rate);
+ if (rate == -1)
+ iwl_rt->rt_rate = 0;
+ else
+ iwl_rt->rt_rate = iwl_rates[rate].ieee;
+
+ /* antenna number */
+ iwl_rt->rt_antenna =
+ le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+
+ /* set the preamble flag if we have it */
+ if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+ iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+ IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
+
+ stats->flag |= RX_FLAG_RADIOTAP;
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ rxb->skb = NULL;
+}
+
+
+#define IWL_PACKET_RETRY_TIME HZ
+
+int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+{
+ u16 sc = le16_to_cpu(header->seq_ctrl);
+ u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
+ u16 frag = sc & IEEE80211_SCTL_FRAG;
+ u16 *last_seq, *last_frag;
+ unsigned long *last_time;
+
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_IBSS:{
+ struct list_head *p;
+ struct iwl_ibss_seq *entry = NULL;
+ u8 *mac = header->addr2;
+ int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
+
+ __list_for_each(p, &priv->ibss_mac_hash[index]) {
+ entry =
+ list_entry(p, struct iwl_ibss_seq, list);
+ if (!compare_ether_addr(entry->mac, mac))
+ break;
+ }
+ if (p == &priv->ibss_mac_hash[index]) {
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry) {
+ IWL_ERROR
+ ("Cannot malloc new mac entry\n");
+ return 0;
+ }
+ memcpy(entry->mac, mac, ETH_ALEN);
+ entry->seq_num = seq;
+ entry->frag_num = frag;
+ entry->packet_time = jiffies;
+ list_add(&entry->list,
+ &priv->ibss_mac_hash[index]);
+ return 0;
+ }
+ last_seq = &entry->seq_num;
+ last_frag = &entry->frag_num;
+ last_time = &entry->packet_time;
+ break;
+ }
+ case IEEE80211_IF_TYPE_STA:
+ last_seq = &priv->last_seq_num;
+ last_frag = &priv->last_frag_num;
+ last_time = &priv->last_packet_time;
+ break;
+ default:
+ return 0;
+ }
+ if ((*last_seq == seq) &&
+ time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) {
+ if (*last_frag == frag)
+ goto drop;
+ if (*last_frag + 1 != frag)
+ /* out-of-order fragment */
+ goto drop;
+ } else
+ *last_seq = seq;
+
+ *last_frag = frag;
+ *last_time = jiffies;
+ return 0;
+
+ drop:
+ return 1;
+}
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+#include "iwl-spectrum.h"
+
+#define BEACON_TIME_MASK_LOW 0x00FFFFFF
+#define BEACON_TIME_MASK_HIGH 0xFF000000
+#define TIME_UNIT 1024
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in 8:24 format
+ * the high 1 byte is the beacon counts
+ * the lower 3 bytes is the time in usec within one beacon interval
+ */
+
+static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
+{
+ u32 quot;
+ u32 rem;
+ u32 interval = beacon_interval * 1024;
+
+ if (!interval || !usec)
+ return 0;
+
+ quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
+ rem = (usec % interval) & BEACON_TIME_MASK_LOW;
+
+ return (quot << 24) + rem;
+}
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+
+static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+{
+ u32 base_low = base & BEACON_TIME_MASK_LOW;
+ u32 addon_low = addon & BEACON_TIME_MASK_LOW;
+ u32 interval = beacon_interval * TIME_UNIT;
+ u32 res = (base & BEACON_TIME_MASK_HIGH) +
+ (addon & BEACON_TIME_MASK_HIGH);
+
+ if (base_low > addon_low)
+ res += base_low - addon_low;
+ else if (base_low < addon_low) {
+ res += interval + base_low - addon_low;
+ res += (1 << 24);
+ } else
+ res += (1 << 24);
+
+ return cpu_to_le32(res);
+}
+
+static int iwl_get_measurement(struct iwl_priv *priv,
+ struct ieee80211_measurement_params *params,
+ u8 type)
+{
+ struct iwl_spectrum_cmd spectrum;
+ struct iwl_rx_packet *res;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SPECTRUM_MEASUREMENT_CMD,
+ .data = (void *)&spectrum,
+ .meta.flags = CMD_WANT_SKB,
+ };
+ u32 add_time = le64_to_cpu(params->start_time);
+ int rc;
+ int spectrum_resp_status;
+ int duration = le16_to_cpu(params->duration);
+
+ if (iwl_is_associated(priv))
+ add_time =
+ iwl_usecs_to_beacons(
+ le64_to_cpu(params->start_time) - priv->last_tsf,
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+
+ memset(&spectrum, 0, sizeof(spectrum));
+
+ spectrum.channel_count = cpu_to_le16(1);
+ spectrum.flags =
+ RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
+ spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
+ cmd.len = sizeof(spectrum);
+ spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
+
+ if (iwl_is_associated(priv))
+ spectrum.start_time =
+ iwl_add_beacon_time(priv->last_beacon_time,
+ add_time,
+ le16_to_cpu(priv->rxon_timing.beacon_interval));
+ else
+ spectrum.start_time = 0;
+
+ spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
+ spectrum.channels[0].channel = params->channel;
+ spectrum.channels[0].type = type;
+ if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+ spectrum.flags |= RXON_FLG_BAND_24G_MSK |
+ RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
+
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ return rc;
+
+ res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+ if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
+ rc = -EIO;
+ }
+
+ spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
+ switch (spectrum_resp_status) {
+ case 0: /* Command will be handled */
+ if (res->u.spectrum.id != 0xff) {
+ IWL_DEBUG_INFO
+ ("Replaced existing measurement: %d\n",
+ res->u.spectrum.id);
+ priv->measurement_status &= ~MEASUREMENT_READY;
+ }
+ priv->measurement_status |= MEASUREMENT_ACTIVE;
+ rc = 0;
+ break;
+
+ case 1: /* Command will not be handled */
+ rc = -EAGAIN;
+ break;
+ }
+
+ dev_kfree_skb_any(cmd.meta.u.skb);
+
+ return rc;
+}
+#endif
+
+static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
+ struct iwl_tx_info *tx_sta)
+{
+
+ tx_sta->status.ack_signal = 0;
+ tx_sta->status.excessive_retries = 0;
+ tx_sta->status.queue_length = 0;
+ tx_sta->status.queue_number = 0;
+
+ if (in_interrupt())
+ ieee80211_tx_status_irqsafe(priv->hw,
+ tx_sta->skb[0], &(tx_sta->status));
+ else
+ ieee80211_tx_status(priv->hw,
+ tx_sta->skb[0], &(tx_sta->status));
+
+ tx_sta->skb[0] = NULL;
+}
+
+/**
+ * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC.
+ *
+ * When FW advances 'R' index, all entries between old and
+ * new 'R' index need to be reclaimed. As result, some free space
+ * forms. If there is enough free space (> low mark), wake Tx queue.
+ */
+int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+{
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct iwl_queue *q = &txq->q;
+ int nfreed = 0;
+
+ if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
+ "is out of range [0-%d] %d %d.\n", txq_id,
+ index, q->n_bd, q->first_empty, q->last_used);
+ return 0;
+ }
+
+ for (index = iwl_queue_inc_wrap(index, q->n_bd);
+ q->last_used != index;
+ q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) {
+ if (txq_id != IWL_CMD_QUEUE_NUM) {
+ iwl_txstatus_to_ieee(priv,
+ &(txq->txb[txq->q.last_used]));
+ iwl_hw_txq_free_tfd(priv, txq);
+ } else if (nfreed > 1) {
+ IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
+ q->first_empty, q->last_used);
+ queue_work(priv->workqueue, &priv->restart);
+ }
+ nfreed++;
+ }
+
+ if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
+ (txq_id != IWL_CMD_QUEUE_NUM) &&
+ priv->mac80211_registered)
+ ieee80211_wake_queue(priv->hw, txq_id);
+
+
+ return nfreed;
+}
+
+static int iwl_is_tx_success(u32 status)
+{
+ status &= TX_STATUS_MSK;
+ return (status == TX_STATUS_SUCCESS)
+ || (status == TX_STATUS_DIRECT_DONE);
+}
+
+/******************************************************************************
+ *
+ * Generic RX handler implementations
+ *
+ ******************************************************************************/
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+
+static inline int iwl_get_ra_sta_id(struct iwl_priv *priv,
+ struct ieee80211_hdr *hdr)
+{
+ if (priv->iw_mode == IEEE80211_IF_TYPE_STA)
+ return IWL_AP_ID;
+ else {
+ u8 *da = ieee80211_get_DA(hdr);
+ return iwl_hw_find_station(priv, da);
+ }
+}
+
+static struct ieee80211_hdr *iwl_tx_queue_get_hdr(
+ struct iwl_priv *priv, int txq_id, int idx)
+{
+ if (priv->txq[txq_id].txb[idx].skb[0])
+ return (struct ieee80211_hdr *)priv->txq[txq_id].
+ txb[idx].skb[0]->data;
+ return NULL;
+}
+
+static inline u32 iwl_get_scd_ssn(struct iwl_tx_resp *tx_resp)
+{
+ __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status +
+ tx_resp->frame_count);
+ return le32_to_cpu(*scd_ssn) & MAX_SN;
+
+}
+static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
+ struct iwl_ht_agg *agg,
+ struct iwl_tx_resp *tx_resp,
+ u16 start_idx)
+{
+ u32 status;
+ __le32 *frame_status = &tx_resp->status;
+ struct ieee80211_tx_status *tx_status = NULL;
+ struct ieee80211_hdr *hdr = NULL;
+ int i, sh;
+ int txq_id, idx;
+ u16 seq;
+
+ if (agg->wait_for_ba)
+ IWL_DEBUG_TX_REPLY("got tx repsons w/o back\n");
+
+ agg->frame_count = tx_resp->frame_count;
+ agg->start_idx = start_idx;
+ agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+ agg->bitmap0 = agg->bitmap1 = 0;
+
+ if (agg->frame_count == 1) {
+ struct iwl_tx_queue *txq ;
+ status = le32_to_cpu(frame_status[0]);
+
+ txq_id = agg->txq_id;
+ txq = &priv->txq[txq_id];
+ /* FIXME: code repetition */
+ IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d \n",
+ agg->frame_count, agg->start_idx);
+
+ tx_status = &(priv->txq[txq_id].txb[txq->q.last_used].status);
+ tx_status->retry_count = tx_resp->failure_frame;
+ tx_status->queue_number = status & 0xff;
+ tx_status->queue_length = tx_resp->bt_kill_count;
+ tx_status->queue_length |= tx_resp->failure_rts;
+
+ tx_status->flags = iwl_is_tx_success(status)?
+ IEEE80211_TX_STATUS_ACK : 0;
+ tx_status->control.tx_rate =
+ iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags);
+ /* FIXME: code repetition end */
+
+ IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
+ status & 0xff, tx_resp->failure_frame);
+ IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n",
+ iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags));
+
+ agg->wait_for_ba = 0;
+ } else {
+ u64 bitmap = 0;
+ int start = agg->start_idx;
+
+ for (i = 0; i < agg->frame_count; i++) {
+ u16 sc;
+ status = le32_to_cpu(frame_status[i]);
+ seq = status >> 16;
+ idx = SEQ_TO_INDEX(seq);
+ txq_id = SEQ_TO_QUEUE(seq);
+
+ if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
+ AGG_TX_STATE_ABORT_MSK))
+ continue;
+
+ IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
+ agg->frame_count, txq_id, idx);
+
+ hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
+
+ sc = le16_to_cpu(hdr->seq_ctrl);
+ if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+ IWL_ERROR("BUG_ON idx doesn't match seq control"
+ " idx=%d, seq_idx=%d, seq=%d\n",
+ idx, SEQ_TO_SN(sc),
+ hdr->seq_ctrl);
+ return -1;
+ }
+
+ IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n",
+ i, idx, SEQ_TO_SN(sc));
+
+ sh = idx - start;
+ if (sh > 64) {
+ sh = (start - idx) + 0xff;
+ bitmap = bitmap << sh;
+ sh = 0;
+ start = idx;
+ } else if (sh < -64)
+ sh = 0xff - (start - idx);
+ else if (sh < 0) {
+ sh = start - idx;
+ start = idx;
+ bitmap = bitmap << sh;
+ sh = 0;
+ }
+ bitmap |= (1 << sh);
+ IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
+ start, (u32)(bitmap & 0xFFFFFFFF));
+ }
+
+ agg->bitmap0 = bitmap & 0xFFFFFFFF;
+ agg->bitmap1 = bitmap >> 32;
+ agg->start_idx = start;
+ agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+ IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%x\n",
+ agg->frame_count, agg->start_idx,
+ agg->bitmap0);
+
+ if (bitmap)
+ agg->wait_for_ba = 1;
+ }
+ return 0;
+}
+#endif
+#endif
+
+static void iwl_rx_reply_tx(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ int index = SEQ_TO_INDEX(sequence);
+ struct iwl_tx_queue *txq = &priv->txq[txq_id];
+ struct ieee80211_tx_status *tx_status;
+ struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+ u32 status = le32_to_cpu(tx_resp->status);
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ int tid, sta_id;
+#endif
+#endif
+
+ if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
+ IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+ "is out of range [0-%d] %d %d\n", txq_id,
+ index, txq->q.n_bd, txq->q.first_empty,
+ txq->q.last_used);
+ return;
+ }
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ if (txq->sched_retry) {
+ const u32 scd_ssn = iwl_get_scd_ssn(tx_resp);
+ struct ieee80211_hdr *hdr =
+ iwl_tx_queue_get_hdr(priv, txq_id, index);
+ struct iwl_ht_agg *agg = NULL;
+ __le16 *qc = ieee80211_get_qos_ctrl(hdr);
+
+ if (qc == NULL) {
+ IWL_ERROR("BUG_ON qc is null!!!!\n");
+ return;
+ }
+
+ tid = le16_to_cpu(*qc) & 0xf;
+
+ sta_id = iwl_get_ra_sta_id(priv, hdr);
+ if (unlikely(sta_id == IWL_INVALID_STATION)) {
+ IWL_ERROR("Station not known for\n");
+ return;
+ }
+
+ agg = &priv->stations[sta_id].tid[tid].agg;
+
+ iwl4965_tx_status_reply_tx(priv, agg, tx_resp, index);
+
+ if ((tx_resp->frame_count == 1) &&
+ !iwl_is_tx_success(status)) {
+ /* TODO: send BAR */
+ }
+
+ if ((txq->q.last_used != (scd_ssn & 0xff))) {
+ index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+ IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
+ "%d index %d\n", scd_ssn , index);
+ iwl_tx_queue_reclaim(priv, txq_id, index);
+ }
+ } else {
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+ tx_status = &(txq->txb[txq->q.last_used].status);
+
+ tx_status->retry_count = tx_resp->failure_frame;
+ tx_status->queue_number = status;
+ tx_status->queue_length = tx_resp->bt_kill_count;
+ tx_status->queue_length |= tx_resp->failure_rts;
+
+ tx_status->flags =
+ iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
+
+ tx_status->control.tx_rate =
+ iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags);
+
+ IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
+ "retries %d\n", txq_id, iwl_get_tx_fail_reason(status),
+ status, le32_to_cpu(tx_resp->rate_n_flags),
+ tx_resp->failure_frame);
+
+ IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+ if (index != -1)
+ iwl_tx_queue_reclaim(priv, txq_id, index);
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ }
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+ if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+ IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n");
+}
+
+
+static void iwl_rx_reply_alive(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_alive_resp *palive;
+ struct delayed_work *pwork;
+
+ palive = &pkt->u.alive_frame;
+
+ IWL_DEBUG_INFO("Alive ucode status 0x%08X revision "
+ "0x%01X 0x%01X\n",
+ palive->is_valid, palive->ver_type,
+ palive->ver_subtype);
+
+ if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
+ IWL_DEBUG_INFO("Initialization Alive received.\n");
+ memcpy(&priv->card_alive_init,
+ &pkt->u.alive_frame,
+ sizeof(struct iwl_init_alive_resp));
+ pwork = &priv->init_alive_start;
+ } else {
+ IWL_DEBUG_INFO("Runtime Alive received.\n");
+ memcpy(&priv->card_alive, &pkt->u.alive_frame,
+ sizeof(struct iwl_alive_resp));
+ pwork = &priv->alive_start;
+ }
+
+ /* We delay the ALIVE response by 5ms to
+ * give the HW RF Kill time to activate... */
+ if (palive->is_valid == UCODE_VALID_OK)
+ queue_delayed_work(priv->workqueue, pwork,
+ msecs_to_jiffies(5));
+ else
+ IWL_WARNING("uCode did not respond OK.\n");
+}
+
+static void iwl_rx_reply_add_sta(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+
+ IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
+ return;
+}
+
+static void iwl_rx_reply_error(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+
+ IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
+ "seq 0x%04X ser 0x%08X\n",
+ le32_to_cpu(pkt->u.err_resp.error_type),
+ get_cmd_string(pkt->u.err_resp.cmd_id),
+ pkt->u.err_resp.cmd_id,
+ le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
+ le32_to_cpu(pkt->u.err_resp.error_info));
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
+ struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
+ IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
+ le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
+ rxon->channel = csa->channel;
+ priv->staging_rxon.channel = csa->channel;
+}
+
+static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
+
+ if (!report->state) {
+ IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
+ "Spectrum Measure Notification: Start\n");
+ return;
+ }
+
+ memcpy(&priv->measure_report, report, sizeof(*report));
+ priv->measurement_status |= MEASUREMENT_READY;
+#endif
+}
+
+static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
+ IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
+ sleep->pm_sleep_mode, sleep->pm_wakeup_src);
+#endif
+}
+
+static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ IWL_DEBUG_RADIO("Dumping %d bytes of unhandled "
+ "notification for %s:\n",
+ le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
+ iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+}
+
+static void iwl_bg_beacon_update(struct work_struct *work)
+{
+ struct iwl_priv *priv =
+ container_of(work, struct iwl_priv, beacon_update);
+ struct sk_buff *beacon;
+
+ /* Pull updated AP beacon from mac80211. will fail if not in AP mode */
+ beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL);
+
+ if (!beacon) {
+ IWL_ERROR("update beacon failed\n");
+ return;
+ }
+
+ mutex_lock(&priv->mutex);
+ /* new beacon skb is allocated every time; dispose previous.*/
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = beacon;
+ mutex_unlock(&priv->mutex);
+
+ iwl_send_beacon_cmd(priv);
+}
+
+static void iwl_rx_beacon_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status);
+ u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
+
+ IWL_DEBUG_RX("beacon status %x retries %d iss %d "
+ "tsf %d %d rate %d\n",
+ le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK,
+ beacon->beacon_notify_hdr.failure_frame,
+ le32_to_cpu(beacon->ibss_mgr_status),
+ le32_to_cpu(beacon->high_tsf),
+ le32_to_cpu(beacon->low_tsf), rate);
+#endif
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+ (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
+ queue_work(priv->workqueue, &priv->beacon_update);
+}
+
+/* Service response to REPLY_SCAN_CMD (0x80) */
+static void iwl_rx_reply_scan(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scanreq_notification *notif =
+ (struct iwl_scanreq_notification *)pkt->u.raw;
+
+ IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status);
+#endif
+}
+
+/* Service SCAN_START_NOTIFICATION (0x82) */
+static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scanstart_notification *notif =
+ (struct iwl_scanstart_notification *)pkt->u.raw;
+ priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
+ IWL_DEBUG_SCAN("Scan start: "
+ "%d [802.11%s] "
+ "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
+ notif->channel,
+ notif->band ? "bg" : "a",
+ notif->tsf_high,
+ notif->tsf_low, notif->status, notif->beacon_timer);
+}
+
+/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
+static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scanresults_notification *notif =
+ (struct iwl_scanresults_notification *)pkt->u.raw;
+
+ IWL_DEBUG_SCAN("Scan ch.res: "
+ "%d [802.11%s] "
+ "(TSF: 0x%08X:%08X) - %d "
+ "elapsed=%lu usec (%dms since last)\n",
+ notif->channel,
+ notif->band ? "bg" : "a",
+ le32_to_cpu(notif->tsf_high),
+ le32_to_cpu(notif->tsf_low),
+ le32_to_cpu(notif->statistics[0]),
+ le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf,
+ jiffies_to_msecs(elapsed_jiffies
+ (priv->last_scan_jiffies, jiffies)));
+
+ priv->last_scan_jiffies = jiffies;
+}
+
+/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
+static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
+
+ IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
+ scan_notif->scanned_channels,
+ scan_notif->tsf_low,
+ scan_notif->tsf_high, scan_notif->status);
+
+ /* The HW is no longer scanning */
+ clear_bit(STATUS_SCAN_HW, &priv->status);
+
+ /* The scan completion notification came in, so kill that timer... */
+ cancel_delayed_work(&priv->scan_check);
+
+ IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
+ (priv->scan_bands == 2) ? "2.4" : "5.2",
+ jiffies_to_msecs(elapsed_jiffies
+ (priv->scan_pass_start, jiffies)));
+
+ /* Remove this scanned band from the list
+ * of pending bands to scan */
+ priv->scan_bands--;
+
+ /* If a request to abort was given, or the scan did not succeed
+ * then we reset the scan state machine and terminate,
+ * re-queuing another scan if one has been requested */
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_INFO("Aborted scan completed.\n");
+ clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+ } else {
+ /* If there are more bands on this scan pass reschedule */
+ if (priv->scan_bands > 0)
+ goto reschedule;
+ }
+
+ priv->last_scan_jiffies = jiffies;
+ IWL_DEBUG_INFO("Setting scan to off\n");
+
+ clear_bit(STATUS_SCANNING, &priv->status);
+
+ IWL_DEBUG_INFO("Scan took %dms\n",
+ jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies)));
+
+ queue_work(priv->workqueue, &priv->scan_completed);
+
+ return;
+
+reschedule:
+ priv->scan_pass_start = jiffies;
+ queue_work(priv->workqueue, &priv->request_scan);
+}
+
+/* Handle notification from uCode that card's power state is changing
+ * due to software, hardware, or critical temperature RFKILL */
+static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+ u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
+ unsigned long status = priv->status;
+
+ IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n",
+ (flags & HW_CARD_DISABLED) ? "Kill" : "On",
+ (flags & SW_CARD_DISABLED) ? "Kill" : "On");
+
+ if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
+ RF_CARD_DISABLED)) {
+
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted(
+ priv, HBUS_TARG_MBX_C,
+ HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
+
+ iwl_release_restricted_access(priv);
+ }
+
+ if (!(flags & RXON_CARD_DISABLED)) {
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted(
+ priv, HBUS_TARG_MBX_C,
+ HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
+
+ iwl_release_restricted_access(priv);
+ }
+ }
+
+ if (flags & RF_CARD_DISABLED) {
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+ CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+ iwl_read32(priv, CSR_UCODE_DRV_GP1);
+ if (!iwl_grab_restricted_access(priv))
+ iwl_release_restricted_access(priv);
+ }
+ }
+
+ if (flags & HW_CARD_DISABLED)
+ set_bit(STATUS_RF_KILL_HW, &priv->status);
+ else
+ clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+
+ if (flags & SW_CARD_DISABLED)
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ else
+ clear_bit(STATUS_RF_KILL_SW, &priv->status);
+
+ if (!(flags & RXON_CARD_DISABLED))
+ iwl_scan_cancel(priv);
+
+ if ((test_bit(STATUS_RF_KILL_HW, &status) !=
+ test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
+ (test_bit(STATUS_RF_KILL_SW, &status) !=
+ test_bit(STATUS_RF_KILL_SW, &priv->status)))
+ queue_work(priv->workqueue, &priv->rf_kill);
+ else
+ wake_up_interruptible(&priv->wait_command_queue);
+}
+
+/**
+ * iwl_setup_rx_handlers - Initialize Rx handler callbacks
+ *
+ * Setup the RX handlers for each of the reply types sent from the uCode
+ * to the host.
+ *
+ * This function chains into the hardware specific files for them to setup
+ * any hardware specific handlers as well.
+ */
+static void iwl_setup_rx_handlers(struct iwl_priv *priv)
+{
+ priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
+ priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta;
+ priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
+ priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+ priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+ iwl_rx_spectrum_measure_notif;
+ priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
+ priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
+ iwl_rx_pm_debug_statistics_notif;
+ priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif;
+
+ /* NOTE: iwl_rx_statistics is different based on whether
+ * the build is for the 3945 or the 4965. See the
+ * corresponding implementation in iwl-XXXX.c
+ *
+ * The same handler is used for both the REPLY to a
+ * discrete statistics request from the host as well as
+ * for the periodic statistics notification from the uCode
+ */
+ priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_hw_rx_statistics;
+ priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics;
+
+ priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
+ priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
+ priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
+ iwl_rx_scan_results_notif;
+ priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
+ iwl_rx_scan_complete_notif;
+ priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif;
+ priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx;
+
+ /* Setup hardware specific Rx handlers */
+ iwl_hw_rx_handler_setup(priv);
+}
+
+/**
+ * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * @rxb: Rx buffer to reclaim
+ *
+ * If an Rx buffer has an async callback associated with it the callback
+ * will be executed. The attached skb (if present) will only be freed
+ * if the callback returns 1
+ */
+static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+ u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+ int txq_id = SEQ_TO_QUEUE(sequence);
+ int index = SEQ_TO_INDEX(sequence);
+ int huge = sequence & SEQ_HUGE_FRAME;
+ int cmd_index;
+ struct iwl_cmd *cmd;
+
+ /* If a Tx command is being handled and it isn't in the actual
+ * command queue then there a command routing bug has been introduced
+ * in the queue management code. */
+ if (txq_id != IWL_CMD_QUEUE_NUM)
+ IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
+ txq_id, pkt->hdr.cmd);
+ BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
+
+ cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
+ cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+
+ /* Input error checking is done when commands are added to queue. */
+ if (cmd->meta.flags & CMD_WANT_SKB) {
+ cmd->meta.source->u.skb = rxb->skb;
+ rxb->skb = NULL;
+ } else if (cmd->meta.u.callback &&
+ !cmd->meta.u.callback(priv, cmd, rxb->skb))
+ rxb->skb = NULL;
+
+ iwl_tx_queue_reclaim(priv, txq_id, index);
+
+ if (!(cmd->meta.flags & CMD_ASYNC)) {
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
+ }
+}
+
+/************************** RX-FUNCTIONS ****************************/
+/*
+ * Rx theory of operation
+ *
+ * The host allocates 32 DMA target addresses and passes the host address
+ * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
+ * 0 to 31
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer it will advance the READ index
+ * and fire the RX interrupt. The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When
+ * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ * to replensish the iwl->rxq->rx_free.
+ * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ * iwl->rxq is replenished and the READ INDEX is updated (updating the
+ * 'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ * detached from the iwl->rxq. The driver 'processed' index is updated.
+ * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
+ * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
+ * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there
+ * were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * iwl_rx_queue_alloc() Allocates rx_free
+ * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls
+ * iwl_rx_queue_restock
+ * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
+ * queue, updates firmware pointers, and updates
+ * the WRITE index. If insufficient rx_free buffers
+ * are available, schedules iwl_rx_replenish
+ *
+ * -- enable interrupts --
+ * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the
+ * READ INDEX, detaching the SKB from the pool.
+ * Moves the packet buffer from queue to rx_used.
+ * Calls iwl_rx_queue_restock to refill any empty
+ * slots.
+ * ...
+ *
+ */
+
+/**
+ * iwl_rx_queue_space - Return number of free slots available in queue.
+ */
+static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+{
+ int s = q->read - q->write;
+ if (s <= 0)
+ s += RX_QUEUE_SIZE;
+ /* keep some buffer to not confuse full and empty queue */
+ s -= 2;
+ if (s < 0)
+ s = 0;
+ return s;
+}
+
+/**
+ * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ *
+ * NOTE: This function has 3945 and 4965 specific code sections
+ * but is declared in base due to the majority of the
+ * implementation being the same (only a numeric constant is
+ * different)
+ *
+ */
+int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+{
+ u32 reg = 0;
+ int rc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ if (q->need_update == 0)
+ goto exit_unlock;
+
+ if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+ reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ goto exit_unlock;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ goto exit_unlock;
+
+ iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR,
+ q->write & ~0x7);
+ iwl_release_restricted_access(priv);
+ } else
+ iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
+
+
+ q->need_update = 0;
+
+ exit_unlock:
+ spin_unlock_irqrestore(&q->lock, flags);
+ return rc;
+}
+
+/**
+ * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer.
+ *
+ * NOTE: This function has 3945 and 4965 specific code paths in it.
+ */
+static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
+ dma_addr_t dma_addr)
+{
+ return cpu_to_le32((u32)(dma_addr >> 8));
+}
+
+
+/**
+ * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+int iwl_rx_queue_restock(struct iwl_priv *priv)
+{
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct list_head *element;
+ struct iwl_rx_mem_buffer *rxb;
+ unsigned long flags;
+ int write, rc;
+
+ spin_lock_irqsave(&rxq->lock, flags);
+ write = rxq->write & ~0x7;
+ while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+ element = rxq->rx_free.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ list_del(element);
+ rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr);
+ rxq->queue[rxq->write] = rxb;
+ rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+ rxq->free_count--;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ /* If the pre-allocated buffer pool is dropping low, schedule to
+ * refill it */
+ if (rxq->free_count <= RX_LOW_WATERMARK)
+ queue_work(priv->workqueue, &priv->rx_replenish);
+
+
+ /* If we've added more space for the firmware to place data, tell it */
+ if ((write != (rxq->write & ~0x7))
+ || (abs(rxq->write - rxq->read) > 7)) {
+ spin_lock_irqsave(&rxq->lock, flags);
+ rxq->need_update = 1;
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ rc = iwl_rx_queue_update_write_ptr(priv, rxq);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * iwl_rx_replensih - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl_rx_queue_restock.
+ * This is called as a scheduled work item (except for during intialization)
+ */
+void iwl_rx_replenish(void *data)
+{
+ struct iwl_priv *priv = data;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct list_head *element;
+ struct iwl_rx_mem_buffer *rxb;
+ unsigned long flags;
+ spin_lock_irqsave(&rxq->lock, flags);
+ while (!list_empty(&rxq->rx_used)) {
+ element = rxq->rx_used.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ rxb->skb =
+ alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
+ if (!rxb->skb) {
+ if (net_ratelimit())
+ printk(KERN_CRIT DRV_NAME
+ ": Can not allocate SKB buffers\n");
+ /* We don't reschedule replenish work here -- we will
+ * call the restock method and if it still needs
+ * more buffers it will schedule replenish */
+ break;
+ }
+ priv->alloc_rxb_skb++;
+ list_del(element);
+ rxb->dma_addr =
+ pci_map_single(priv->pci_dev, rxb->skb->data,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+ }
+ spin_unlock_irqrestore(&rxq->lock, flags);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_rx_queue_restock(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ int i;
+ for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+ if (rxq->pool[i].skb != NULL) {
+ pci_unmap_single(priv->pci_dev,
+ rxq->pool[i].dma_addr,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(rxq->pool[i].skb);
+ }
+ }
+
+ pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+ rxq->dma_addr);
+ rxq->bd = NULL;
+}
+
+int iwl_rx_queue_alloc(struct iwl_priv *priv)
+{
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ struct pci_dev *dev = priv->pci_dev;
+ int i;
+
+ spin_lock_init(&rxq->lock);
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_used);
+ rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
+ if (!rxq->bd)
+ return -ENOMEM;
+ /* Fill the rx_used queue with _all_ of the Rx buffers */
+ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+ list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+ /* Set us so that we have processed and used all buffers, but have
+ * not restocked the Rx queue with fresh buffers */
+ rxq->read = rxq->write = 0;
+ rxq->free_count = 0;
+ rxq->need_update = 0;
+ return 0;
+}
+
+void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+ unsigned long flags;
+ int i;
+ spin_lock_irqsave(&rxq->lock, flags);
+ INIT_LIST_HEAD(&rxq->rx_free);
+ INIT_LIST_HEAD(&rxq->rx_used);
+ /* Fill the rx_used queue with _all_ of the Rx buffers */
+ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+ /* In the reset function, these buffers may have been allocated
+ * to an SKB, so we need to unmap and free potential storage */
+ if (rxq->pool[i].skb != NULL) {
+ pci_unmap_single(priv->pci_dev,
+ rxq->pool[i].dma_addr,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb(rxq->pool[i].skb);
+ rxq->pool[i].skb = NULL;
+ }
+ list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+ }
+
+ /* Set us so that we have processed and used all buffers, but have
+ * not restocked the Rx queue with fresh buffers */
+ rxq->read = rxq->write = 0;
+ rxq->free_count = 0;
+ spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/* Convert linear signal-to-noise ratio into dB */
+static u8 ratio2dB[100] = {
+/* 0 1 2 3 4 5 6 7 8 9 */
+ 0, 0, 6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */
+ 20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */
+ 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */
+ 29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */
+ 32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */
+ 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */
+ 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */
+ 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */
+ 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */
+ 39, 39, 39, 39, 39, 40, 40, 40, 40, 40 /* 90 - 99 */
+};
+
+/* Calculates a relative dB value from a ratio of linear
+ * (i.e. not dB) signal levels.
+ * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
+int iwl_calc_db_from_ratio(int sig_ratio)
+{
+ /* 1000:1 or higher just report as 60 dB */
+ if (sig_ratio >= 1000)
+ return 60;
+
+ /* 100:1 or higher, divide by 10 and use table,
+ * add 20 dB to make up for divide by 10 */
+ if (sig_ratio >= 100)
+ return (20 + (int)ratio2dB[sig_ratio/10]);
+
+ /* We shouldn't see this */
+ if (sig_ratio < 1)
+ return 0;
+
+ /* Use table for ratios 1:1 - 99:1 */
+ return (int)ratio2dB[sig_ratio];
+}
+
+#define PERFECT_RSSI (-20) /* dBm */
+#define WORST_RSSI (-95) /* dBm */
+#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
+
+/* Calculate an indication of rx signal quality (a percentage, not dBm!).
+ * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
+ * about formulas used below. */
+int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
+{
+ int sig_qual;
+ int degradation = PERFECT_RSSI - rssi_dbm;
+
+ /* If we get a noise measurement, use signal-to-noise ratio (SNR)
+ * as indicator; formula is (signal dbm - noise dbm).
+ * SNR at or above 40 is a great signal (100%).
+ * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
+ * Weakest usable signal is usually 10 - 15 dB SNR. */
+ if (noise_dbm) {
+ if (rssi_dbm - noise_dbm >= 40)
+ return 100;
+ else if (rssi_dbm < noise_dbm)
+ return 0;
+ sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
+
+ /* Else use just the signal level.
+ * This formula is a least squares fit of data points collected and
+ * compared with a reference system that had a percentage (%) display
+ * for signal quality. */
+ } else
+ sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
+ (15 * RSSI_RANGE + 62 * degradation)) /
+ (RSSI_RANGE * RSSI_RANGE);
+
+ if (sig_qual > 100)
+ sig_qual = 100;
+ else if (sig_qual < 1)
+ sig_qual = 0;
+
+ return sig_qual;
+}
+
+/**
+ * iwl_rx_handle - Main entry function for receiving responses from the uCode
+ *
+ * Uses the priv->rx_handlers callback function array to invoke
+ * the appropriate handlers, including command responses,
+ * frame-received notifications, and other notifications.
+ */
+static void iwl_rx_handle(struct iwl_priv *priv)
+{
+ struct iwl_rx_mem_buffer *rxb;
+ struct iwl_rx_packet *pkt;
+ struct iwl_rx_queue *rxq = &priv->rxq;
+ u32 r, i;
+ int reclaim;
+ unsigned long flags;
+
+ r = iwl_hw_get_rx_read(priv);
+ i = rxq->read;
+
+ /* Rx interrupt, but nothing sent from uCode */
+ if (i == r)
+ IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
+
+ while (i != r) {
+ rxb = rxq->queue[i];
+
+ /* If an RXB doesn't have a queue slot associated with it
+ * then a bug has been introduced in the queue refilling
+ * routines -- catch it here */
+ BUG_ON(rxb == NULL);
+
+ rxq->queue[i] = NULL;
+
+ pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
+ IWL_RX_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+ pkt = (struct iwl_rx_packet *)rxb->skb->data;
+
+ /* Reclaim a command buffer only if this packet is a response
+ * to a (driver-originated) command.
+ * If the packet (e.g. Rx frame) originated from uCode,
+ * there is no command buffer to reclaim.
+ * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
+ * but apparently a few don't get set; catch them here. */
+ reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
+ (pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
+ (pkt->hdr.cmd != REPLY_4965_RX) &&
+ (pkt->hdr.cmd != REPLY_COMPRESSED_BA) &&
+ (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
+ (pkt->hdr.cmd != REPLY_TX);
+
+ /* Based on type of command response or notification,
+ * handle those that need handling via function in
+ * rx_handlers table. See iwl_setup_rx_handlers() */
+ if (priv->rx_handlers[pkt->hdr.cmd]) {
+ IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+ "r = %d, i = %d, %s, 0x%02x\n", r, i,
+ get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
+ priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+ } else {
+ /* No handling needed */
+ IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+ "r %d i %d No handler needed for %s, 0x%02x\n",
+ r, i, get_cmd_string(pkt->hdr.cmd),
+ pkt->hdr.cmd);
+ }
+
+ if (reclaim) {
+ /* Invoke any callbacks, transfer the skb to caller,
+ * and fire off the (possibly) blocking iwl_send_cmd()
+ * as we reclaim the driver command queue */
+ if (rxb && rxb->skb)
+ iwl_tx_cmd_complete(priv, rxb);
+ else
+ IWL_WARNING("Claim null rxb?\n");
+ }
+
+ /* For now we just don't re-use anything. We can tweak this
+ * later to try and re-use notification packets and SKBs that
+ * fail to Rx correctly */
+ if (rxb->skb != NULL) {
+ priv->alloc_rxb_skb--;
+ dev_kfree_skb_any(rxb->skb);
+ rxb->skb = NULL;
+ }
+
+ pci_unmap_single(priv->pci_dev, rxb->dma_addr,
+ IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ spin_lock_irqsave(&rxq->lock, flags);
+ list_add_tail(&rxb->list, &priv->rxq.rx_used);
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ i = (i + 1) & RX_QUEUE_MASK;
+ }
+
+ /* Backtrack one entry */
+ priv->rxq.read = i;
+ iwl_rx_queue_restock(priv);
+}
+
+int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq)
+{
+ u32 reg = 0;
+ int rc = 0;
+ int txq_id = txq->q.id;
+
+ if (txq->need_update == 0)
+ return rc;
+
+ /* if we're trying to save power */
+ if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+ /* wake up nic if it's powered down ...
+ * uCode will wake up, and interrupt us again, so next
+ * time we'll skip this part. */
+ reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+ if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+ IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg);
+ iwl_set_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ return rc;
+ }
+
+ /* restore this queue's parameters in nic hardware. */
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+ iwl_write_restricted(priv, HBUS_TARG_WRPTR,
+ txq->q.first_empty | (txq_id << 8));
+ iwl_release_restricted_access(priv);
+
+ /* else not in power-save mode, uCode will never sleep when we're
+ * trying to tx (during RFKILL, we're not trying to tx). */
+ } else
+ iwl_write32(priv, HBUS_TARG_WRPTR,
+ txq->q.first_empty | (txq_id << 8));
+
+ txq->need_update = 0;
+
+ return rc;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
+{
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_RADIO("RX CONFIG:\n");
+ iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+ IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
+ IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
+ IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
+ le32_to_cpu(rxon->filter_flags));
+ IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type);
+ IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
+ rxon->ofdm_basic_rates);
+ IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
+ IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
+ print_mac(mac, rxon->node_addr));
+ IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
+ print_mac(mac, rxon->bssid_addr));
+ IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
+}
+#endif
+
+static void iwl_enable_interrupts(struct iwl_priv *priv)
+{
+ IWL_DEBUG_ISR("Enabling interrupts\n");
+ set_bit(STATUS_INT_ENABLED, &priv->status);
+ iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+}
+
+static inline void iwl_disable_interrupts(struct iwl_priv *priv)
+{
+ clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+ /* disable interrupts from uCode/NIC to host */
+ iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+ /* acknowledge/clear/reset any interrupts still pending
+ * from uCode or flow handler (Rx/Tx DMA) */
+ iwl_write32(priv, CSR_INT, 0xffffffff);
+ iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+ IWL_DEBUG_ISR("Disabled interrupts\n");
+}
+
+static const char *desc_lookup(int i)
+{
+ switch (i) {
+ case 1:
+ return "FAIL";
+ case 2:
+ return "BAD_PARAM";
+ case 3:
+ return "BAD_CHECKSUM";
+ case 4:
+ return "NMI_INTERRUPT";
+ case 5:
+ return "SYSASSERT";
+ case 6:
+ return "FATAL_ERROR";
+ }
+
+ return "UNKNOWN";
+}
+
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+ u32 data2, line;
+ u32 desc, time, count, base, data1;
+ u32 blink1, blink2, ilink1, ilink2;
+ int rc;
+
+ base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+
+ if (!iwl_hw_valid_rtc_data_addr(base)) {
+ IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
+ return;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ IWL_WARNING("Can not read from adapter at this time.\n");
+ return;
+ }
+
+ count = iwl_read_restricted_mem(priv, base);
+
+ if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+ IWL_ERROR("Start IWL Error Log Dump:\n");
+ IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n",
+ priv->status, priv->config, count);
+ }
+
+ desc = iwl_read_restricted_mem(priv, base + 1 * sizeof(u32));
+ blink1 = iwl_read_restricted_mem(priv, base + 3 * sizeof(u32));
+ blink2 = iwl_read_restricted_mem(priv, base + 4 * sizeof(u32));
+ ilink1 = iwl_read_restricted_mem(priv, base + 5 * sizeof(u32));
+ ilink2 = iwl_read_restricted_mem(priv, base + 6 * sizeof(u32));
+ data1 = iwl_read_restricted_mem(priv, base + 7 * sizeof(u32));
+ data2 = iwl_read_restricted_mem(priv, base + 8 * sizeof(u32));
+ line = iwl_read_restricted_mem(priv, base + 9 * sizeof(u32));
+ time = iwl_read_restricted_mem(priv, base + 11 * sizeof(u32));
+
+ IWL_ERROR("Desc Time "
+ "data1 data2 line\n");
+ IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n",
+ desc_lookup(desc), desc, time, data1, data2, line);
+ IWL_ERROR("blink1 blink2 ilink1 ilink2\n");
+ IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
+ ilink1, ilink2);
+
+ iwl_release_restricted_access(priv);
+}
+
+#define EVENT_START_OFFSET (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ * NOTE: Must be called with iwl_grab_restricted_access() already obtained!
+ */
+static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+ u32 num_events, u32 mode)
+{
+ u32 i;
+ u32 base; /* SRAM byte address of event log header */
+ u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+ u32 ptr; /* SRAM byte address of log data */
+ u32 ev, time, data; /* event log data */
+
+ if (num_events == 0)
+ return;
+
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+ if (mode == 0)
+ event_size = 2 * sizeof(u32);
+ else
+ event_size = 3 * sizeof(u32);
+
+ ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+ /* "time" is actually "data" for mode 0 (no timestamp).
+ * place event id # at far right for easier visual parsing. */
+ for (i = 0; i < num_events; i++) {
+ ev = iwl_read_restricted_mem(priv, ptr);
+ ptr += sizeof(u32);
+ time = iwl_read_restricted_mem(priv, ptr);
+ ptr += sizeof(u32);
+ if (mode == 0)
+ IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
+ else {
+ data = iwl_read_restricted_mem(priv, ptr);
+ ptr += sizeof(u32);
+ IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
+ }
+ }
+}
+
+static void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+ int rc;
+ u32 base; /* SRAM byte address of event log header */
+ u32 capacity; /* event log capacity in # entries */
+ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
+ u32 num_wraps; /* # times uCode wrapped to top of log */
+ u32 next_entry; /* index of next entry to be written by uCode */
+ u32 size; /* # entries that we'll print */
+
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ if (!iwl_hw_valid_rtc_data_addr(base)) {
+ IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
+ return;
+ }
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ IWL_WARNING("Can not read from adapter at this time.\n");
+ return;
+ }
+
+ /* event log header */
+ capacity = iwl_read_restricted_mem(priv, base);
+ mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32)));
+ num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32)));
+ next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32)));
+
+ size = num_wraps ? capacity : next_entry;
+
+ /* bail out if nothing in log */
+ if (size == 0) {
+ IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
+ iwl_release_restricted_access(priv);
+ return;
+ }
+
+ IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n",
+ size, num_wraps);
+
+ /* if uCode has wrapped back to top of log, start at the oldest entry,
+ * i.e the next one that uCode would fill. */
+ if (num_wraps)
+ iwl_print_event_log(priv, next_entry,
+ capacity - next_entry, mode);
+
+ /* (then/else) start at top of log */
+ iwl_print_event_log(priv, 0, next_entry, mode);
+
+ iwl_release_restricted_access(priv);
+}
+
+/**
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ */
+static void iwl_irq_handle_error(struct iwl_priv *priv)
+{
+ /* Set the FW error flag -- cleared on iwl_down */
+ set_bit(STATUS_FW_ERROR, &priv->status);
+
+ /* Cancel currently queued command. */
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & IWL_DL_FW_ERRORS) {
+ iwl_dump_nic_error_log(priv);
+ iwl_dump_nic_event_log(priv);
+ iwl_print_rx_config_cmd(&priv->staging_rxon);
+ }
+#endif
+
+ wake_up_interruptible(&priv->wait_command_queue);
+
+ /* Keep the restart process from trying to send host
+ * commands by clearing the INIT status bit */
+ clear_bit(STATUS_READY, &priv->status);
+
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
+ "Restarting adapter due to uCode error.\n");
+
+ if (iwl_is_associated(priv)) {
+ memcpy(&priv->recovery_rxon, &priv->active_rxon,
+ sizeof(priv->recovery_rxon));
+ priv->error_recovering = 1;
+ }
+ queue_work(priv->workqueue, &priv->restart);
+ }
+}
+
+static void iwl_error_recovery(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ memcpy(&priv->staging_rxon, &priv->recovery_rxon,
+ sizeof(priv->staging_rxon));
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ iwl_rxon_add_station(priv, priv->bssid, 1);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
+ priv->error_recovering = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl_irq_tasklet(struct iwl_priv *priv)
+{
+ u32 inta, handled = 0;
+ u32 inta_fh;
+ unsigned long flags;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ u32 inta_mask;
+#endif
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Ack/clear/reset pending uCode interrupts.
+ * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
+ * and will clear only when CSR_FH_INT_STATUS gets cleared. */
+ inta = iwl_read32(priv, CSR_INT);
+ iwl_write32(priv, CSR_INT, inta);
+
+ /* Ack/clear/reset pending flow-handler (DMA) interrupts.
+ * Any new interrupts that happen after this, either while we're
+ * in this tasklet, or later, will show up in next ISR/tasklet. */
+ inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+ iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & IWL_DL_ISR) {
+ inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
+ IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+ inta, inta_mask, inta_fh);
+ }
+#endif
+
+ /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
+ * atomic, make sure that inta covers all the interrupts that
+ * we've discovered, even if FH interrupt came in just after
+ * reading CSR_INT. */
+ if (inta_fh & CSR_FH_INT_RX_MASK)
+ inta |= CSR_INT_BIT_FH_RX;
+ if (inta_fh & CSR_FH_INT_TX_MASK)
+ inta |= CSR_INT_BIT_FH_TX;
+
+ /* Now service all interrupt bits discovered above. */
+ if (inta & CSR_INT_BIT_HW_ERR) {
+ IWL_ERROR("Microcode HW error detected. Restarting.\n");
+
+ /* Tell the device to stop sending interrupts */
+ iwl_disable_interrupts(priv);
+
+ iwl_irq_handle_error(priv);
+
+ handled |= CSR_INT_BIT_HW_ERR;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return;
+ }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & (IWL_DL_ISR)) {
+ /* NIC fires this, but we don't use it, redundant with WAKEUP */
+ if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
+ IWL_DEBUG_ISR("Microcode started or stopped.\n");
+
+ /* Alive notification via Rx interrupt will do the real work */
+ if (inta & CSR_INT_BIT_ALIVE)
+ IWL_DEBUG_ISR("Alive interrupt\n");
+ }
+#endif
+ /* Safely ignore these bits for debug checks below */
+ inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+
+ /* HW RF KILL switch toggled (4965 only) */
+ if (inta & CSR_INT_BIT_RF_KILL) {
+ int hw_rf_kill = 0;
+ if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+ CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+ hw_rf_kill = 1;
+
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
+ "RF_KILL bit toggled to %s.\n",
+ hw_rf_kill ? "disable radio":"enable radio");
+
+ /* Queue restart only if RF_KILL switch was set to "kill"
+ * when we loaded driver, and is now set to "enable".
+ * After we're Alive, RF_KILL gets handled by
+ * iwl_rx_card_state_notif() */
+ if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status))
+ queue_work(priv->workqueue, &priv->restart);
+
+ handled |= CSR_INT_BIT_RF_KILL;
+ }
+
+ /* Chip got too hot and stopped itself (4965 only) */
+ if (inta & CSR_INT_BIT_CT_KILL) {
+ IWL_ERROR("Microcode CT kill error detected.\n");
+ handled |= CSR_INT_BIT_CT_KILL;
+ }
+
+ /* Error detected by uCode */
+ if (inta & CSR_INT_BIT_SW_ERR) {
+ IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n",
+ inta);
+ iwl_irq_handle_error(priv);
+ handled |= CSR_INT_BIT_SW_ERR;
+ }
+
+ /* uCode wakes up after power-down sleep */
+ if (inta & CSR_INT_BIT_WAKEUP) {
+ IWL_DEBUG_ISR("Wakeup interrupt\n");
+ iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[0]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]);
+ iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]);
+
+ handled |= CSR_INT_BIT_WAKEUP;
+ }
+
+ /* All uCode command responses, including Tx command responses,
+ * Rx "responses" (frame-received notification), and other
+ * notifications from uCode come through here*/
+ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
+ iwl_rx_handle(priv);
+ handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
+ }
+
+ if (inta & CSR_INT_BIT_FH_TX) {
+ IWL_DEBUG_ISR("Tx interrupt\n");
+ handled |= CSR_INT_BIT_FH_TX;
+ }
+
+ if (inta & ~handled)
+ IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
+
+ if (inta & ~CSR_INI_SET_MASK) {
+ IWL_WARNING("Disabled INTA bits 0x%08x were pending\n",
+ inta & ~CSR_INI_SET_MASK);
+ IWL_WARNING(" with FH_INT = 0x%08x\n", inta_fh);
+ }
+
+ /* Re-enable all interrupts */
+ iwl_enable_interrupts(priv);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+ if (iwl_debug_level & (IWL_DL_ISR)) {
+ inta = iwl_read32(priv, CSR_INT);
+ inta_mask = iwl_read32(priv, CSR_INT_MASK);
+ inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+ IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
+ "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
+ }
+#endif
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static irqreturn_t iwl_isr(int irq, void *data)
+{
+ struct iwl_priv *priv = data;
+ u32 inta, inta_mask;
+ u32 inta_fh;
+ if (!priv)
+ return IRQ_NONE;
+
+ spin_lock(&priv->lock);
+
+ /* Disable (but don't clear!) interrupts here to avoid
+ * back-to-back ISRs and sporadic interrupts from our NIC.
+ * If we have something to service, the tasklet will re-enable ints.
+ * If we *don't* have something, we'll re-enable before leaving here. */
+ inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
+ iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+ /* Discover which interrupts are active/pending */
+ inta = iwl_read32(priv, CSR_INT);
+ inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+
+ /* Ignore interrupt if there's nothing in NIC to service.
+ * This may be due to IRQ shared with another device,
+ * or due to sporadic interrupts thrown from our NIC. */
+ if (!inta && !inta_fh) {
+ IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n");
+ goto none;
+ }
+
+ if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+ /* Hardware disappeared. It might have already raised
+ * an interrupt */
+ IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta);
+ goto unplugged;
+ }
+
+ IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+ inta, inta_mask, inta_fh);
+
+ /* iwl_irq_tasklet() will service interrupts and re-enable them */
+ tasklet_schedule(&priv->irq_tasklet);
+
+ unplugged:
+ spin_unlock(&priv->lock);
+ return IRQ_HANDLED;
+
+ none:
+ /* re-enable interrupts here since we don't have anything to service. */
+ iwl_enable_interrupts(priv);
+ spin_unlock(&priv->lock);
+ return IRQ_NONE;
+}
+
+/************************** EEPROM BANDS ****************************
+ *
+ * The iwl_eeprom_band definitions below provide the mapping from the
+ * EEPROM contents to the specific channel number supported for each
+ * band.
+ *
+ * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3
+ * definition below maps to physical channel 42 in the 5.2GHz spectrum.
+ * The specific geography and calibration information for that channel
+ * is contained in the eeprom map itself.
+ *
+ * During init, we copy the eeprom information and channel map
+ * information into priv->channel_info_24/52 and priv->channel_map_24/52
+ *
+ * channel_map_24/52 provides the index in the channel_info array for a
+ * given channel. We have to have two separate maps as there is channel
+ * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and
+ * band_2
+ *
+ * A value of 0xff stored in the channel_map indicates that the channel
+ * is not supported by the hardware at all.
+ *
+ * A value of 0xfe in the channel_map indicates that the channel is not
+ * valid for Tx with the current hardware. This means that
+ * while the system can tune and receive on a given channel, it may not
+ * be able to associate or transmit any frames on that
+ * channel. There is no corresponding channel information for that
+ * entry.
+ *
+ *********************************************************************/
+
+/* 2.4 GHz */
+static const u8 iwl_eeprom_band_1[14] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+};
+
+/* 5.2 GHz bands */
+static const u8 iwl_eeprom_band_2[] = {
+ 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
+};
+
+static const u8 iwl_eeprom_band_3[] = { /* 5205-5320MHz */
+ 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+};
+
+static const u8 iwl_eeprom_band_4[] = { /* 5500-5700MHz */
+ 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+};
+
+static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */
+ 145, 149, 153, 157, 161, 165
+};
+
+static u8 iwl_eeprom_band_6[] = { /* 2.4 FAT channel */
+ 1, 2, 3, 4, 5, 6, 7
+};
+
+static u8 iwl_eeprom_band_7[] = { /* 5.2 FAT channel */
+ 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
+};
+
+static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
+ int *eeprom_ch_count,
+ const struct iwl_eeprom_channel
+ **eeprom_ch_info,
+ const u8 **eeprom_ch_index)
+{
+ switch (band) {
+ case 1: /* 2.4GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
+ *eeprom_ch_info = priv->eeprom.band_1_channels;
+ *eeprom_ch_index = iwl_eeprom_band_1;
+ break;
+ case 2: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
+ *eeprom_ch_info = priv->eeprom.band_2_channels;
+ *eeprom_ch_index = iwl_eeprom_band_2;
+ break;
+ case 3: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
+ *eeprom_ch_info = priv->eeprom.band_3_channels;
+ *eeprom_ch_index = iwl_eeprom_band_3;
+ break;
+ case 4: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
+ *eeprom_ch_info = priv->eeprom.band_4_channels;
+ *eeprom_ch_index = iwl_eeprom_band_4;
+ break;
+ case 5: /* 5.2GHz band */
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
+ *eeprom_ch_info = priv->eeprom.band_5_channels;
+ *eeprom_ch_index = iwl_eeprom_band_5;
+ break;
+ case 6:
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
+ *eeprom_ch_info = priv->eeprom.band_24_channels;
+ *eeprom_ch_index = iwl_eeprom_band_6;
+ break;
+ case 7:
+ *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
+ *eeprom_ch_info = priv->eeprom.band_52_channels;
+ *eeprom_ch_index = iwl_eeprom_band_7;
+ break;
+ default:
+ BUG();
+ return;
+ }
+}
+
+const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
+ int phymode, u16 channel)
+{
+ int i;
+
+ switch (phymode) {
+ case MODE_IEEE80211A:
+ for (i = 14; i < priv->channel_count; i++) {
+ if (priv->channel_info[i].channel == channel)
+ return &priv->channel_info[i];
+ }
+ break;
+
+ case MODE_IEEE80211B:
+ case MODE_IEEE80211G:
+ if (channel >= 1 && channel <= 14)
+ return &priv->channel_info[channel - 1];
+ break;
+
+ }
+
+ return NULL;
+}
+
+#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
+ ? # x " " : "")
+
+static int iwl_init_channel_map(struct iwl_priv *priv)
+{
+ int eeprom_ch_count = 0;
+ const u8 *eeprom_ch_index = NULL;
+ const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
+ int band, ch;
+ struct iwl_channel_info *ch_info;
+
+ if (priv->channel_count) {
+ IWL_DEBUG_INFO("Channel map already initialized.\n");
+ return 0;
+ }
+
+ if (priv->eeprom.version < 0x2f) {
+ IWL_WARNING("Unsupported EEPROM version: 0x%04X\n",
+ priv->eeprom.version);
+ return -EINVAL;
+ }
+
+ IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
+
+ priv->channel_count =
+ ARRAY_SIZE(iwl_eeprom_band_1) +
+ ARRAY_SIZE(iwl_eeprom_band_2) +
+ ARRAY_SIZE(iwl_eeprom_band_3) +
+ ARRAY_SIZE(iwl_eeprom_band_4) +
+ ARRAY_SIZE(iwl_eeprom_band_5);
+
+ IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count);
+
+ priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
+ priv->channel_count, GFP_KERNEL);
+ if (!priv->channel_info) {
+ IWL_ERROR("Could not allocate channel_info\n");
+ priv->channel_count = 0;
+ return -ENOMEM;
+ }
+
+ ch_info = priv->channel_info;
+
+ /* Loop through the 5 EEPROM bands adding them in order to the
+ * channel map we maintain (that contains additional information than
+ * what just in the EEPROM) */
+ for (band = 1; band <= 5; band++) {
+
+ iwl_init_band_reference(priv, band, &eeprom_ch_count,
+ &eeprom_ch_info, &eeprom_ch_index);
+
+ /* Loop through each band adding each of the channels */
+ for (ch = 0; ch < eeprom_ch_count; ch++) {
+ ch_info->channel = eeprom_ch_index[ch];
+ ch_info->phymode = (band == 1) ? MODE_IEEE80211B :
+ MODE_IEEE80211A;
+
+ /* permanently store EEPROM's channel regulatory flags
+ * and max power in channel info database. */
+ ch_info->eeprom = eeprom_ch_info[ch];
+
+ /* Copy the run-time flags so they are there even on
+ * invalid channels */
+ ch_info->flags = eeprom_ch_info[ch].flags;
+
+ if (!(is_channel_valid(ch_info))) {
+ IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - "
+ "No traffic\n",
+ ch_info->channel,
+ ch_info->flags,
+ is_channel_a_band(ch_info) ?
+ "5.2" : "2.4");
+ ch_info++;
+ continue;
+ }
+
+ /* Initialize regulatory-based run-time data */
+ ch_info->max_power_avg = ch_info->curr_txpow =
+ eeprom_ch_info[ch].max_power_avg;
+ ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
+ ch_info->min_power = 0;
+
+ IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+ " %ddBm): Ad-Hoc %ssupported\n",
+ ch_info->channel,
+ is_channel_a_band(ch_info) ?
+ "5.2" : "2.4",
+ CHECK_AND_PRINT(IBSS),
+ CHECK_AND_PRINT(ACTIVE),
+ CHECK_AND_PRINT(RADAR),
+ CHECK_AND_PRINT(WIDE),
+ CHECK_AND_PRINT(NARROW),
+ CHECK_AND_PRINT(DFS),
+ eeprom_ch_info[ch].flags,
+ eeprom_ch_info[ch].max_power_avg,
+ ((eeprom_ch_info[ch].
+ flags & EEPROM_CHANNEL_IBSS)
+ && !(eeprom_ch_info[ch].
+ flags & EEPROM_CHANNEL_RADAR))
+ ? "" : "not ");
+
+ /* Set the user_txpower_limit to the highest power
+ * supported by any channel */
+ if (eeprom_ch_info[ch].max_power_avg >
+ priv->user_txpower_limit)
+ priv->user_txpower_limit =
+ eeprom_ch_info[ch].max_power_avg;
+
+ ch_info++;
+ }
+ }
+
+ for (band = 6; band <= 7; band++) {
+ int phymode;
+ u8 fat_extension_chan;
+
+ iwl_init_band_reference(priv, band, &eeprom_ch_count,
+ &eeprom_ch_info, &eeprom_ch_index);
+
+ phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A;
+ /* Loop through each band adding each of the channels */
+ for (ch = 0; ch < eeprom_ch_count; ch++) {
+
+ if ((band == 6) &&
+ ((eeprom_ch_index[ch] == 5) ||
+ (eeprom_ch_index[ch] == 6) ||
+ (eeprom_ch_index[ch] == 7)))
+ fat_extension_chan = HT_IE_EXT_CHANNEL_MAX;
+ else
+ fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE;
+
+ iwl4965_set_fat_chan_info(priv, phymode,
+ eeprom_ch_index[ch],
+ &(eeprom_ch_info[ch]),
+ fat_extension_chan);
+
+ iwl4965_set_fat_chan_info(priv, phymode,
+ (eeprom_ch_index[ch] + 4),
+ &(eeprom_ch_info[ch]),
+ HT_IE_EXT_CHANNEL_BELOW);
+ }
+ }
+
+ return 0;
+}
+
+/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
+ * sending probe req. This should be set long enough to hear probe responses
+ * from more than one AP. */
+#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52 (10)
+
+/* For faster active scanning, scan will move to the next channel if fewer than
+ * PLCP_QUIET_THRESH packets are heard on this channel within
+ * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell
+ * time if it's a quiet channel (nothing responded to our probe, and there's
+ * no other traffic).
+ * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
+#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */
+#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */
+
+/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
+ * Must be set longer than active dwell time.
+ * For the most reliable scan, set > AP beacon interval (typically 100msec). */
+#define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */
+#define IWL_PASSIVE_DWELL_TIME_52 (10)
+#define IWL_PASSIVE_DWELL_BASE (100)
+#define IWL_CHANNEL_TUNE_TIME 5
+
+static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
+{
+ if (phymode == MODE_IEEE80211A)
+ return IWL_ACTIVE_DWELL_TIME_52;
+ else
+ return IWL_ACTIVE_DWELL_TIME_24;
+}
+
+static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
+{
+ u16 active = iwl_get_active_dwell_time(priv, phymode);
+ u16 passive = (phymode != MODE_IEEE80211A) ?
+ IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
+ IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
+
+ if (iwl_is_associated(priv)) {
+ /* If we're associated, we clamp the maximum passive
+ * dwell time to be 98% of the beacon interval (minus
+ * 2 * channel tune time) */
+ passive = priv->beacon_int;
+ if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
+ passive = IWL_PASSIVE_DWELL_BASE;
+ passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+ }
+
+ if (passive <= active)
+ passive = active + 1;
+
+ return passive;
+}
+
+static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+ u8 is_active, u8 direct_mask,
+ struct iwl_scan_channel *scan_ch)
+{
+ const struct ieee80211_channel *channels = NULL;
+ const struct ieee80211_hw_mode *hw_mode;
+ const struct iwl_channel_info *ch_info;
+ u16 passive_dwell = 0;
+ u16 active_dwell = 0;
+ int added, i;
+
+ hw_mode = iwl_get_hw_mode(priv, phymode);
+ if (!hw_mode)
+ return 0;
+
+ channels = hw_mode->channels;
+
+ active_dwell = iwl_get_active_dwell_time(priv, phymode);
+ passive_dwell = iwl_get_passive_dwell_time(priv, phymode);
+
+ for (i = 0, added = 0; i < hw_mode->num_channels; i++) {
+ if (channels[i].chan ==
+ le16_to_cpu(priv->active_rxon.channel)) {
+ if (iwl_is_associated(priv)) {
+ IWL_DEBUG_SCAN
+ ("Skipping current channel %d\n",
+ le16_to_cpu(priv->active_rxon.channel));
+ continue;
+ }
+ } else if (priv->only_active_channel)
+ continue;
+
+ scan_ch->channel = channels[i].chan;
+
+ ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+ scan_ch->channel);
+ continue;
+ }
+
+ if (!is_active || is_channel_passive(ch_info) ||
+ !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN))
+ scan_ch->type = 0; /* passive */
+ else
+ scan_ch->type = 1; /* active */
+
+ if (scan_ch->type & 1)
+ scan_ch->type |= (direct_mask << 1);
+
+ if (is_channel_narrow(ch_info))
+ scan_ch->type |= (1 << 7);
+
+ scan_ch->active_dwell = cpu_to_le16(active_dwell);
+ scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+
+ /* Set power levels to defaults */
+ scan_ch->tpc.dsp_atten = 110;
+ /* scan_pwr_info->tpc.dsp_atten; */
+
+ /*scan_pwr_info->tpc.tx_gain; */
+ if (phymode == MODE_IEEE80211A)
+ scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
+ else {
+ scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
+ /* NOTE: if we were doing 6Mb OFDM for scans we'd use
+ * power level
+ scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
+ */
+ }
+
+ IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
+ scan_ch->channel,
+ (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
+ (scan_ch->type & 1) ?
+ active_dwell : passive_dwell);
+
+ scan_ch++;
+ added++;
+ }
+
+ IWL_DEBUG_SCAN("total channels to scan %d \n", added);
+ return added;
+}
+
+static void iwl_reset_channel_flag(struct iwl_priv *priv)
+{
+ int i, j;
+ for (i = 0; i < 3; i++) {
+ struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i];
+ for (j = 0; j < hw_mode->num_channels; j++)
+ hw_mode->channels[j].flag = hw_mode->channels[j].val;
+ }
+}
+
+static void iwl_init_hw_rates(struct iwl_priv *priv,
+ struct ieee80211_rate *rates)
+{
+ int i;
+
+ for (i = 0; i < IWL_RATE_COUNT; i++) {
+ rates[i].rate = iwl_rates[i].ieee * 5;
+ rates[i].val = i; /* Rate scaling will work on indexes */
+ rates[i].val2 = i;
+ rates[i].flags = IEEE80211_RATE_SUPPORTED;
+ /* Only OFDM have the bits-per-symbol set */
+ if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE))
+ rates[i].flags |= IEEE80211_RATE_OFDM;
+ else {
+ /*
+ * If CCK 1M then set rate flag to CCK else CCK_2
+ * which is CCK | PREAMBLE2
+ */
+ rates[i].flags |= (iwl_rates[i].plcp == 10) ?
+ IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
+ }
+
+ /* Set up which ones are basic rates... */
+ if (IWL_BASIC_RATES_MASK & (1 << i))
+ rates[i].flags |= IEEE80211_RATE_BASIC;
+ }
+
+ iwl4965_init_hw_rates(priv, rates);
+}
+
+/**
+ * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ */
+static int iwl_init_geos(struct iwl_priv *priv)
+{
+ struct iwl_channel_info *ch;
+ struct ieee80211_hw_mode *modes;
+ struct ieee80211_channel *channels;
+ struct ieee80211_channel *geo_ch;
+ struct ieee80211_rate *rates;
+ int i = 0;
+ enum {
+ A = 0,
+ B = 1,
+ G = 2,
+ A_11N = 3,
+ G_11N = 4,
+ };
+ int mode_count = 5;
+
+ if (priv->modes) {
+ IWL_DEBUG_INFO("Geography modes already initialized.\n");
+ set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+ return 0;
+ }
+
+ modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count,
+ GFP_KERNEL);
+ if (!modes)
+ return -ENOMEM;
+
+ channels = kzalloc(sizeof(struct ieee80211_channel) *
+ priv->channel_count, GFP_KERNEL);
+ if (!channels) {
+ kfree(modes);
+ return -ENOMEM;
+ }
+
+ rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)),
+ GFP_KERNEL);
+ if (!rates) {
+ kfree(modes);
+ kfree(channels);
+ return -ENOMEM;
+ }
+
+ /* 0 = 802.11a
+ * 1 = 802.11b
+ * 2 = 802.11g
+ */
+
+ /* 5.2GHz channels start after the 2.4GHz channels */
+ modes[A].mode = MODE_IEEE80211A;
+ modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+ modes[A].rates = rates;
+ modes[A].num_rates = 8; /* just OFDM */
+ modes[A].rates = &rates[4];
+ modes[A].num_channels = 0;
+
+ modes[B].mode = MODE_IEEE80211B;
+ modes[B].channels = channels;
+ modes[B].rates = rates;
+ modes[B].num_rates = 4; /* just CCK */
+ modes[B].num_channels = 0;
+
+ modes[G].mode = MODE_IEEE80211G;
+ modes[G].channels = channels;
+ modes[G].rates = rates;
+ modes[G].num_rates = 12; /* OFDM & CCK */
+ modes[G].num_channels = 0;
+
+ modes[G_11N].mode = MODE_IEEE80211G;
+ modes[G_11N].channels = channels;
+ modes[G_11N].num_rates = 13; /* OFDM & CCK */
+ modes[G_11N].rates = rates;
+ modes[G_11N].num_channels = 0;
+
+ modes[A_11N].mode = MODE_IEEE80211A;
+ modes[A_11N].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+ modes[A_11N].rates = &rates[4];
+ modes[A_11N].num_rates = 9; /* just OFDM */
+ modes[A_11N].num_channels = 0;
+
+ priv->ieee_channels = channels;
+ priv->ieee_rates = rates;
+
+ iwl_init_hw_rates(priv, rates);
+
+ for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
+ ch = &priv->channel_info[i];
+
+ if (!is_channel_valid(ch)) {
+ IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- "
+ "skipping.\n",
+ ch->channel, is_channel_a_band(ch) ?
+ "5.2" : "2.4");
+ continue;
+ }
+
+ if (is_channel_a_band(ch)) {
+ geo_ch = &modes[A].channels[modes[A].num_channels++];
+ modes[A_11N].num_channels++;
+ } else {
+ geo_ch = &modes[B].channels[modes[B].num_channels++];
+ modes[G].num_channels++;
+ modes[G_11N].num_channels++;
+ }
+
+ geo_ch->freq = ieee80211chan2mhz(ch->channel);
+ geo_ch->chan = ch->channel;
+ geo_ch->power_level = ch->max_power_avg;
+ geo_ch->antenna_max = 0xff;
+
+ if (is_channel_valid(ch)) {
+ geo_ch->flag = IEEE80211_CHAN_W_SCAN;
+ if (ch->flags & EEPROM_CHANNEL_IBSS)
+ geo_ch->flag |= IEEE80211_CHAN_W_IBSS;
+
+ if (ch->flags & EEPROM_CHANNEL_ACTIVE)
+ geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN;
+
+ if (ch->flags & EEPROM_CHANNEL_RADAR)
+ geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT;
+
+ if (ch->max_power_avg > priv->max_channel_txpower_limit)
+ priv->max_channel_txpower_limit =
+ ch->max_power_avg;
+ }
+
+ geo_ch->val = geo_ch->flag;
+ }
+
+ if ((modes[A].num_channels == 0) && priv->is_abg) {
+ printk(KERN_INFO DRV_NAME
+ ": Incorrectly detected BG card as ABG. Please send "
+ "your PCI ID 0x%04X:0x%04X to maintainer.\n",
+ priv->pci_dev->device, priv->pci_dev->subsystem_device);
+ priv->is_abg = 0;
+ }
+
+ printk(KERN_INFO DRV_NAME
+ ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
+ modes[G].num_channels, modes[A].num_channels);
+
+ /*
+ * NOTE: We register these in preference of order -- the
+ * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick
+ * a phymode based on rates or AP capabilities but seems to
+ * configure it purely on if the channel being configured
+ * is supported by a mode -- and the first match is taken
+ */
+
+ if (modes[G].num_channels)
+ ieee80211_register_hwmode(priv->hw, &modes[G]);
+ if (modes[B].num_channels)
+ ieee80211_register_hwmode(priv->hw, &modes[B]);
+ if (modes[A].num_channels)
+ ieee80211_register_hwmode(priv->hw, &modes[A]);
+
+ priv->modes = modes;
+ set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+
+ return 0;
+}
+
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
+
+static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
+{
+ if (priv->ucode_code.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_code.len,
+ priv->ucode_code.v_addr,
+ priv->ucode_code.p_addr);
+ priv->ucode_code.v_addr = NULL;
+ }
+ if (priv->ucode_data.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_data.len,
+ priv->ucode_data.v_addr,
+ priv->ucode_data.p_addr);
+ priv->ucode_data.v_addr = NULL;
+ }
+ if (priv->ucode_data_backup.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_data_backup.len,
+ priv->ucode_data_backup.v_addr,
+ priv->ucode_data_backup.p_addr);
+ priv->ucode_data_backup.v_addr = NULL;
+ }
+ if (priv->ucode_init.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_init.len,
+ priv->ucode_init.v_addr,
+ priv->ucode_init.p_addr);
+ priv->ucode_init.v_addr = NULL;
+ }
+ if (priv->ucode_init_data.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_init_data.len,
+ priv->ucode_init_data.v_addr,
+ priv->ucode_init_data.p_addr);
+ priv->ucode_init_data.v_addr = NULL;
+ }
+ if (priv->ucode_boot.v_addr != NULL) {
+ pci_free_consistent(priv->pci_dev,
+ priv->ucode_boot.len,
+ priv->ucode_boot.v_addr,
+ priv->ucode_boot.p_addr);
+ priv->ucode_boot.v_addr = NULL;
+ }
+}
+
+/**
+ * iwl_verify_inst_full - verify runtime uCode image in card vs. host,
+ * looking at all data.
+ */
+static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
+{
+ u32 val;
+ u32 save_len = len;
+ int rc = 0;
+ u32 errcnt;
+
+ IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+
+ iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
+
+ errcnt = 0;
+ for (; len > 0; len -= sizeof(u32), image++) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+ IWL_ERROR("uCode INST section is invalid at "
+ "offset 0x%x, is 0x%x, s/b 0x%x\n",
+ save_len - len, val, le32_to_cpu(*image));
+ rc = -EIO;
+ errcnt++;
+ if (errcnt >= 20)
+ break;
+ }
+ }
+
+ iwl_release_restricted_access(priv);
+
+ if (!errcnt)
+ IWL_DEBUG_INFO
+ ("ucode image in INSTRUCTION memory is good\n");
+
+ return rc;
+}
+
+
+/**
+ * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ * using sample data 100 bytes apart. If these sample points are good,
+ * it's a pretty good bet that everything between them is good, too.
+ */
+static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+{
+ u32 val;
+ int rc = 0;
+ u32 errcnt = 0;
+ u32 i;
+
+ IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR,
+ i + RTC_INST_LOWER_BOUND);
+ val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+#if 0 /* Enable this if you want to see details */
+ IWL_ERROR("uCode INST section is invalid at "
+ "offset 0x%x, is 0x%x, s/b 0x%x\n",
+ i, val, *image);
+#endif
+ rc = -EIO;
+ errcnt++;
+ if (errcnt >= 3)
+ break;
+ }
+ }
+
+ iwl_release_restricted_access(priv);
+
+ return rc;
+}
+
+
+/**
+ * iwl_verify_ucode - determine which instruction image is in SRAM,
+ * and verify its contents
+ */
+static int iwl_verify_ucode(struct iwl_priv *priv)
+{
+ __le32 *image;
+ u32 len;
+ int rc = 0;
+
+ /* Try bootstrap */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ rc = iwl_verify_inst_sparse(priv, image, len);
+ if (rc == 0) {
+ IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try initialize */
+ image = (__le32 *)priv->ucode_init.v_addr;
+ len = priv->ucode_init.len;
+ rc = iwl_verify_inst_sparse(priv, image, len);
+ if (rc == 0) {
+ IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try runtime/protocol */
+ image = (__le32 *)priv->ucode_code.v_addr;
+ len = priv->ucode_code.len;
+ rc = iwl_verify_inst_sparse(priv, image, len);
+ if (rc == 0) {
+ IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+
+ /* Show first several data entries in instruction SRAM.
+ * Selection of bootstrap image is arbitrary. */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ rc = iwl_verify_inst_full(priv, image, len);
+
+ return rc;
+}
+
+
+/* check contents of special bootstrap uCode SRAM */
+static int iwl_verify_bsm(struct iwl_priv *priv)
+{
+ __le32 *image = priv->ucode_boot.v_addr;
+ u32 len = priv->ucode_boot.len;
+ u32 reg;
+ u32 val;
+
+ IWL_DEBUG_INFO("Begin verify bsm\n");
+
+ /* verify BSM SRAM contents */
+ val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG);
+ for (reg = BSM_SRAM_LOWER_BOUND;
+ reg < BSM_SRAM_LOWER_BOUND + len;
+ reg += sizeof(u32), image ++) {
+ val = iwl_read_restricted_reg(priv, reg);
+ if (val != le32_to_cpu(*image)) {
+ IWL_ERROR("BSM uCode verification failed at "
+ "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
+ BSM_SRAM_LOWER_BOUND,
+ reg - BSM_SRAM_LOWER_BOUND, len,
+ val, le32_to_cpu(*image));
+ return -EIO;
+ }
+ }
+
+ IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");
+
+ return 0;
+}
+
+/**
+ * iwl_load_bsm - Load bootstrap instructions
+ *
+ * BSM operation:
+ *
+ * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
+ * in special SRAM that does not power down during RFKILL. When powering back
+ * up after power-saving sleeps (or during initial uCode load), the BSM loads
+ * the bootstrap program into the on-board processor, and starts it.
+ *
+ * The bootstrap program loads (via DMA) instructions and data for a new
+ * program from host DRAM locations indicated by the host driver in the
+ * BSM_DRAM_* registers. Once the new program is loaded, it starts
+ * automatically.
+ *
+ * When initializing the NIC, the host driver points the BSM to the
+ * "initialize" uCode image. This uCode sets up some internal data, then
+ * notifies host via "initialize alive" that it is complete.
+ *
+ * The host then replaces the BSM_DRAM_* pointer values to point to the
+ * normal runtime uCode instructions and a backup uCode data cache buffer
+ * (filled initially with starting data values for the on-board processor),
+ * then triggers the "initialize" uCode to load and launch the runtime uCode,
+ * which begins normal operation.
+ *
+ * When doing a power-save shutdown, runtime uCode saves data SRAM into
+ * the backup data cache in DRAM before SRAM is powered down.
+ *
+ * When powering back up, the BSM loads the bootstrap program. This reloads
+ * the runtime uCode instructions and the backup data cache into SRAM,
+ * and re-launches the runtime uCode from where it left off.
+ */
+static int iwl_load_bsm(struct iwl_priv *priv)
+{
+ __le32 *image = priv->ucode_boot.v_addr;
+ u32 len = priv->ucode_boot.len;
+ dma_addr_t pinst;
+ dma_addr_t pdata;
+ u32 inst_len;
+ u32 data_len;
+ int rc;
+ int i;
+ u32 done;
+ u32 reg_offset;
+
+ IWL_DEBUG_INFO("Begin load bsm\n");
+
+ /* make sure bootstrap program is no larger than BSM's SRAM size */
+ if (len > IWL_MAX_BSM_SIZE)
+ return -EINVAL;
+
+ /* Tell bootstrap uCode where to find the "Initialize" uCode
+ * in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965.
+ * NOTE: iwl_initialize_alive_start() will replace these values,
+ * after the "initialize" uCode has run, to point to
+ * runtime/protocol instructions and backup data cache. */
+ pinst = priv->ucode_init.p_addr >> 4;
+ pdata = priv->ucode_init_data.p_addr >> 4;
+ inst_len = priv->ucode_init.len;
+ data_len = priv->ucode_init_data.len;
+
+ rc = iwl_grab_restricted_access(priv);
+ if (rc)
+ return rc;
+
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
+
+ /* Fill BSM memory with bootstrap instructions */
+ for (reg_offset = BSM_SRAM_LOWER_BOUND;
+ reg_offset < BSM_SRAM_LOWER_BOUND + len;
+ reg_offset += sizeof(u32), image++)
+ _iwl_write_restricted_reg(priv, reg_offset,
+ le32_to_cpu(*image));
+
+ rc = iwl_verify_bsm(priv);
+ if (rc) {
+ iwl_release_restricted_access(priv);
+ return rc;
+ }
+
+ /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
+ iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0);
+ iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG,
+ RTC_INST_LOWER_BOUND);
+ iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
+
+ /* Load bootstrap code into instruction SRAM now,
+ * to prepare to load "initialize" uCode */
+ iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+ BSM_WR_CTRL_REG_BIT_START);
+
+ /* Wait for load of bootstrap uCode to finish */
+ for (i = 0; i < 100; i++) {
+ done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG);
+ if (!(done & BSM_WR_CTRL_REG_BIT_START))
+ break;
+ udelay(10);
+ }
+ if (i < 100)
+ IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
+ else {
+ IWL_ERROR("BSM write did not complete!\n");
+ return -EIO;
+ }
+
+ /* Enable future boot loads whenever power management unit triggers it
+ * (e.g. when powering back up after power-save shutdown) */
+ iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+ BSM_WR_CTRL_REG_BIT_START_EN);
+
+ iwl_release_restricted_access(priv);
+
+ return 0;
+}
+
+static void iwl_nic_start(struct iwl_priv *priv)
+{
+ /* Remove all resets to allow NIC to operate */
+ iwl_write32(priv, CSR_RESET, 0);
+}
+
+/**
+ * iwl_read_ucode - Read uCode images from disk file.
+ *
+ * Copy into buffers for card to fetch via bus-mastering
+ */
+static int iwl_read_ucode(struct iwl_priv *priv)
+{
+ struct iwl_ucode *ucode;
+ int rc = 0;
+ const struct firmware *ucode_raw;
+ const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode";
+ u8 *src;
+ size_t len;
+ u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
+
+ /* Ask kernel firmware_class module to get the boot firmware off disk.
+ * request_firmware() is synchronous, file is in memory on return. */
+ rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
+ if (rc < 0) {
+ IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc);
+ goto error;
+ }
+
+ IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
+ name, ucode_raw->size);
+
+ /* Make sure that we got at least our header! */
+ if (ucode_raw->size < sizeof(*ucode)) {
+ IWL_ERROR("File size way too small!\n");
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ /* Data from ucode file: header followed by uCode images */
+ ucode = (void *)ucode_raw->data;
+
+ ver = le32_to_cpu(ucode->ver);
+ inst_size = le32_to_cpu(ucode->inst_size);
+ data_size = le32_to_cpu(ucode->data_size);
+ init_size = le32_to_cpu(ucode->init_size);
+ init_data_size = le32_to_cpu(ucode->init_data_size);
+ boot_size = le32_to_cpu(ucode->boot_size);
+
+ IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
+ IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n",
+ inst_size);
+ IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n",
+ data_size);
+ IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n",
+ init_size);
+ IWL_DEBUG_INFO("f/w package hdr init data size = %u\n",
+ init_data_size);
+ IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n",
+ boot_size);
+
+ /* Verify size of file vs. image size info in file's header */
+ if (ucode_raw->size < sizeof(*ucode) +
+ inst_size + data_size + init_size +
+ init_data_size + boot_size) {
+
+ IWL_DEBUG_INFO("uCode file size %d too small\n",
+ (int)ucode_raw->size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ /* Verify that uCode images will fit in card's SRAM */
+ if (inst_size > IWL_MAX_INST_SIZE) {
+ IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n",
+ (int)inst_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ if (data_size > IWL_MAX_DATA_SIZE) {
+ IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n",
+ (int)data_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+ if (init_size > IWL_MAX_INST_SIZE) {
+ IWL_DEBUG_INFO
+ ("uCode init instr len %d too large to fit in card\n",
+ (int)init_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+ if (init_data_size > IWL_MAX_DATA_SIZE) {
+ IWL_DEBUG_INFO
+ ("uCode init data len %d too large to fit in card\n",
+ (int)init_data_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+ if (boot_size > IWL_MAX_BSM_SIZE) {
+ IWL_DEBUG_INFO
+ ("uCode boot instr len %d too large to fit in bsm\n",
+ (int)boot_size);
+ rc = -EINVAL;
+ goto err_release;
+ }
+
+ /* Allocate ucode buffers for card's bus-master loading ... */
+
+ /* Runtime instructions and 2 copies of data:
+ * 1) unmodified from disk
+ * 2) backup cache for save/restore during power-downs */
+ priv->ucode_code.len = inst_size;
+ priv->ucode_code.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_code.len,
+ &(priv->ucode_code.p_addr));
+
+ priv->ucode_data.len = data_size;
+ priv->ucode_data.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_data.len,
+ &(priv->ucode_data.p_addr));
+
+ priv->ucode_data_backup.len = data_size;
+ priv->ucode_data_backup.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_data_backup.len,
+ &(priv->ucode_data_backup.p_addr));
+
+
+ /* Initialization instructions and data */
+ priv->ucode_init.len = init_size;
+ priv->ucode_init.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_init.len,
+ &(priv->ucode_init.p_addr));
+
+ priv->ucode_init_data.len = init_data_size;
+ priv->ucode_init_data.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_init_data.len,
+ &(priv->ucode_init_data.p_addr));
+
+ /* Bootstrap (instructions only, no data) */
+ priv->ucode_boot.len = boot_size;
+ priv->ucode_boot.v_addr =
+ pci_alloc_consistent(priv->pci_dev,
+ priv->ucode_boot.len,
+ &(priv->ucode_boot.p_addr));
+
+ if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
+ !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr ||
+ !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr)
+ goto err_pci_alloc;
+
+ /* Copy images into buffers for card's bus-master reads ... */
+
+ /* Runtime instructions (first block of data in file) */
+ src = &ucode->data[0];
+ len = priv->ucode_code.len;
+ IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n",
+ (int)len);
+ memcpy(priv->ucode_code.v_addr, src, len);
+ IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
+ priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
+
+ /* Runtime data (2nd block)
+ * NOTE: Copy into backup buffer will be done in iwl_up() */
+ src = &ucode->data[inst_size];
+ len = priv->ucode_data.len;
+ IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n",
+ (int)len);
+ memcpy(priv->ucode_data.v_addr, src, len);
+ memcpy(priv->ucode_data_backup.v_addr, src, len);
+
+ /* Initialization instructions (3rd block) */
+ if (init_size) {
+ src = &ucode->data[inst_size + data_size];
+ len = priv->ucode_init.len;
+ IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n",
+ (int)len);
+ memcpy(priv->ucode_init.v_addr, src, len);
+ }
+
+ /* Initialization data (4th block) */
+ if (init_data_size) {
+ src = &ucode->data[inst_size + data_size + init_size];
+ len = priv->ucode_init_data.len;
+ IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n",
+ (int)len);
+ memcpy(priv->ucode_init_data.v_addr, src, len);
+ }
+
+ /* Bootstrap instructions (5th block) */
+ src = &ucode->data[inst_size + data_size + init_size + init_data_size];
+ len = priv->ucode_boot.len;
+ IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n",
+ (int)len);
+ memcpy(priv->ucode_boot.v_addr, src, len);
+
+ /* We have our copies now, allow OS release its copies */
+ release_firmware(ucode_raw);
+ return 0;
+
+ err_pci_alloc:
+ IWL_ERROR("failed to allocate pci memory\n");
+ rc = -ENOMEM;
+ iwl_dealloc_ucode_pci(priv);
+
+ err_release:
+ release_firmware(ucode_raw);
+
+ error:
+ return rc;
+}
+
+
+/**
+ * iwl_set_ucode_ptrs - Set uCode address location
+ *
+ * Tell initialization uCode where to find runtime uCode.
+ *
+ * BSM registers initially contain pointers to initialization uCode.
+ * We need to replace them to load runtime uCode inst and data,
+ * and to save runtime data when powering down.
+ */
+static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
+{
+ dma_addr_t pinst;
+ dma_addr_t pdata;
+ int rc = 0;
+ unsigned long flags;
+
+ /* bits 35:4 for 4965 */
+ pinst = priv->ucode_code.p_addr >> 4;
+ pdata = priv->ucode_data_backup.p_addr >> 4;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ rc = iwl_grab_restricted_access(priv);
+ if (rc) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+ }
+
+ /* Tell bootstrap uCode where to find image to load */
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+ iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
+ priv->ucode_data.len);
+
+ /* Inst bytecount must be last to set up, bit 31 signals uCode
+ * that all new ptr/size info is in place */
+ iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG,
+ priv->ucode_code.len | BSM_DRAM_INST_LOAD);
+
+ iwl_release_restricted_access(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
+
+ return rc;
+}
+
+/**
+ * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved
+ *
+ * Called after REPLY_ALIVE notification received from "initialize" uCode.
+ *
+ * The 4965 "initialize" ALIVE reply contains calibration data for:
+ * Voltage, temperature, and MIMO tx gain correction, now stored in priv
+ * (3945 does not contain this data).
+ *
+ * Tell "initialize" uCode to go ahead and load the runtime uCode.
+*/
+static void iwl_init_alive_start(struct iwl_priv *priv)
+{
+ /* Check alive response for "valid" sign from uCode */
+ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+ /* We had an error bringing up the hardware, so take it
+ * all the way back down so we can try again */
+ IWL_DEBUG_INFO("Initialize Alive failed.\n");
+ goto restart;
+ }
+
+ /* Bootstrap uCode has loaded initialize uCode ... verify inst image.
+ * This is a paranoid check, because we would not have gotten the
+ * "initialize" alive if code weren't properly loaded. */
+ if (iwl_verify_ucode(priv)) {
+ /* Runtime instruction load was bad;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
+ goto restart;
+ }
+
+ /* Calculate temperature */
+ priv->temperature = iwl4965_get_temperature(priv);
+
+ /* Send pointers to protocol/runtime uCode image ... init code will
+ * load and launch runtime uCode, which will send us another "Alive"
+ * notification. */
+ IWL_DEBUG_INFO("Initialization Alive received.\n");
+ if (iwl_set_ucode_ptrs(priv)) {
+ /* Runtime instruction load won't happen;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
+ goto restart;
+ }
+ return;
+
+ restart:
+ queue_work(priv->workqueue, &priv->restart);
+}
+
+
+/**
+ * iwl_alive_start - called after REPLY_ALIVE notification received
+ * from protocol/runtime uCode (initialization uCode's
+ * Alive gets handled by iwl_init_alive_start()).
+ */
+static void iwl_alive_start(struct iwl_priv *priv)
+{
+ int rc = 0;
+
+ IWL_DEBUG_INFO("Runtime Alive received.\n");
+
+ if (priv->card_alive.is_valid != UCODE_VALID_OK) {
+ /* We had an error bringing up the hardware, so take it
+ * all the way back down so we can try again */
+ IWL_DEBUG_INFO("Alive failed.\n");
+ goto restart;
+ }
+
+ /* Initialize uCode has loaded Runtime uCode ... verify inst image.
+ * This is a paranoid check, because we would not have gotten the
+ * "runtime" alive if code weren't properly loaded. */
+ if (iwl_verify_ucode(priv)) {
+ /* Runtime instruction load was bad;
+ * take it all the way back down so we can try again */
+ IWL_DEBUG_INFO("Bad runtime uCode load.\n");
+ goto restart;
+ }
+
+ iwl_clear_stations_table(priv);
+
+ rc = iwl4965_alive_notify(priv);
+ if (rc) {
+ IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n",
+ rc);
+ goto restart;
+ }
+
+ /* After the ALIVE response, we can process host commands */
+ set_bit(STATUS_ALIVE, &priv->status);
+
+ /* Clear out the uCode error bit if it is set */
+ clear_bit(STATUS_FW_ERROR, &priv->status);
+
+ rc = iwl_init_channel_map(priv);
+ if (rc) {
+ IWL_ERROR("initializing regulatory failed: %d\n", rc);
+ return;
+ }
+
+ iwl_init_geos(priv);
+
+ if (iwl_is_rfkill(priv))
+ return;
+
+ if (!priv->mac80211_registered) {
+ /* Unlock so any user space entry points can call back into
+ * the driver without a deadlock... */
+ mutex_unlock(&priv->mutex);
+ iwl_rate_control_register(priv->hw);
+ rc = ieee80211_register_hw(priv->hw);
+ priv->hw->conf.beacon_int = 100;
+ mutex_lock(&priv->mutex);
+
+ if (rc) {
+ IWL_ERROR("Failed to register network "
+ "device (error %d)\n", rc);
+ return;
+ }
+
+ priv->mac80211_registered = 1;
+
+ iwl_reset_channel_flag(priv);
+ } else
+ ieee80211_start_queues(priv->hw);
+
+ priv->active_rate = priv->rates_mask;
+ priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+ iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
+
+ if (iwl_is_associated(priv)) {
+ struct iwl_rxon_cmd *active_rxon =
+ (struct iwl_rxon_cmd *)(&priv->active_rxon);
+
+ memcpy(&priv->staging_rxon, &priv->active_rxon,
+ sizeof(priv->staging_rxon));
+ active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ } else {
+ /* Initialize our rx_config data */
+ iwl_connection_init_rx_config(priv);
+ memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+ }
+
+ /* Configure BT coexistence */
+ iwl_send_bt_config(priv);
+
+ /* Configure the adapter for unassociated operation */
+ iwl_commit_rxon(priv);
+
+ /* At this point, the NIC is initialized and operational */
+ priv->notif_missed_beacons = 0;
+ set_bit(STATUS_READY, &priv->status);
+
+ iwl4965_rf_kill_ct_config(priv);
+ IWL_DEBUG_INFO("ALIVE processing complete.\n");
+
+ if (priv->error_recovering)
+ iwl_error_recovery(priv);
+
+ return;
+
+ restart:
+ queue_work(priv->workqueue, &priv->restart);
+}
+
+static void iwl_cancel_deferred_work(struct iwl_priv *priv);
+
+static void __iwl_down(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
+ struct ieee80211_conf *conf = NULL;
+
+ IWL_DEBUG_INFO(DRV_NAME " is going down\n");
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ if (!exit_pending)
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
+
+ iwl_clear_stations_table(priv);
+
+ /* Unblock any waiting calls */
+ wake_up_interruptible_all(&priv->wait_command_queue);
+
+ iwl_cancel_deferred_work(priv);
+
+ /* Wipe out the EXIT_PENDING status bit if we are not actually
+ * exiting the module */
+ if (!exit_pending)
+ clear_bit(STATUS_EXIT_PENDING, &priv->status);
+
+ /* stop and reset the on-board processor */
+ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
+ /* tell the device to stop sending interrupts */
+ iwl_disable_interrupts(priv);
+
+ if (priv->mac80211_registered)
+ ieee80211_stop_queues(priv->hw);
+
+ /* If we have not previously called iwl_init() then
+ * clear all bits but the RF Kill and SUSPEND bits and return */
+ if (!iwl_is_init(priv)) {
+ priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+ STATUS_RF_KILL_HW |
+ test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+ STATUS_RF_KILL_SW |
+ test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+ STATUS_IN_SUSPEND;
+ goto exit;
+ }
+
+ /* ...otherwise clear out all the status bits but the RF Kill and
+ * SUSPEND bits and continue taking the NIC down. */
+ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+ STATUS_RF_KILL_HW |
+ test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+ STATUS_RF_KILL_SW |
+ test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+ STATUS_IN_SUSPEND |
+ test_bit(STATUS_FW_ERROR, &priv->status) <<
+ STATUS_FW_ERROR;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_hw_txq_ctx_stop(priv);
+ iwl_hw_rxq_stop(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT);
+ iwl_release_restricted_access(priv);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ udelay(5);
+
+ iwl_hw_nic_stop_master(priv);
+ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+ iwl_hw_nic_reset(priv);
+
+ exit:
+ memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+ priv->ibss_beacon = NULL;
+
+ /* clear out any free frames */
+ iwl_clear_free_frames(priv);
+}
+
+static void iwl_down(struct iwl_priv *priv)
+{
+ mutex_lock(&priv->mutex);
+ __iwl_down(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+#define MAX_HW_RESTARTS 5
+
+static int __iwl_up(struct iwl_priv *priv)
+{
+ DECLARE_MAC_BUF(mac);
+ int rc, i;
+ u32 hw_rf_kill = 0;
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ IWL_WARNING("Exit pending; will not bring the NIC up\n");
+ return -EIO;
+ }
+
+ if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+ IWL_WARNING("Radio disabled by SW RF kill (module "
+ "parameter)\n");
+ return 0;
+ }
+
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+ rc = iwl_hw_nic_init(priv);
+ if (rc) {
+ IWL_ERROR("Unable to int nic\n");
+ return rc;
+ }
+
+ /* make sure rfkill handshake bits are cleared */
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+ /* clear (again), then enable host interrupts */
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+ iwl_enable_interrupts(priv);
+
+ /* really make sure rfkill handshake bits are cleared */
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ /* Copy original ucode data image from disk into backup cache.
+ * This will be used to initialize the on-board processor's
+ * data SRAM for a clean start when the runtime program first loads. */
+ memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
+ priv->ucode_data.len);
+
+ /* If platform's RF_KILL switch is set to KILL,
+ * wait for BIT_INT_RF_KILL interrupt before loading uCode
+ * and getting things started */
+ if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+ CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+ hw_rf_kill = 1;
+
+ if (test_bit(STATUS_RF_KILL_HW, &priv->status) || hw_rf_kill) {
+ IWL_WARNING("Radio disabled by HW RF Kill switch\n");
+ return 0;
+ }
+
+ for (i = 0; i < MAX_HW_RESTARTS; i++) {
+
+ iwl_clear_stations_table(priv);
+
+ /* load bootstrap state machine,
+ * load bootstrap program into processor's memory,
+ * prepare to load the "initialize" uCode */
+ rc = iwl_load_bsm(priv);
+
+ if (rc) {
+ IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
+ continue;
+ }
+
+ /* start card; "initialize" will load runtime ucode */
+ iwl_nic_start(priv);
+
+ /* MAC Address location in EEPROM same for 3945/4965 */
+ get_eeprom_mac(priv, priv->mac_addr);
+ IWL_DEBUG_INFO("MAC address: %s\n",
+ print_mac(mac, priv->mac_addr));
+
+ SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+
+ IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
+
+ return 0;
+ }
+
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
+ __iwl_down(priv);
+
+ /* tried to restart and config the device for as long as our
+ * patience could withstand */
+ IWL_ERROR("Unable to initialize device after %d attempts.\n", i);
+ return -EIO;
+}
+
+
+/*****************************************************************************
+ *
+ * Workqueue callbacks
+ *
+ *****************************************************************************/
+
+static void iwl_bg_init_alive_start(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, init_alive_start.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_init_alive_start(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_alive_start(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, alive_start.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_alive_start(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_rf_kill(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
+
+ wake_up_interruptible(&priv->wait_command_queue);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ if (!iwl_is_rfkill(priv)) {
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
+ "HW and/or SW RF Kill no longer active, restarting "
+ "device\n");
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+ queue_work(priv->workqueue, &priv->restart);
+ } else {
+
+ if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
+ IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+ "disabled by SW switch\n");
+ else
+ IWL_WARNING("Radio Frequency Kill Switch is On:\n"
+ "Kill switch must be turned off for "
+ "wireless networking to work.\n");
+ }
+ mutex_unlock(&priv->mutex);
+}
+
+#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
+
+static void iwl_bg_scan_check(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, scan_check.work);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ if (test_bit(STATUS_SCANNING, &priv->status) ||
+ test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN,
+ "Scan completion watchdog resetting adapter (%dms)\n",
+ jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
+
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+ iwl_send_scan_abort(priv);
+ }
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_request_scan(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, request_scan);
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_SCAN_CMD,
+ .len = sizeof(struct iwl_scan_cmd),
+ .meta.flags = CMD_SIZE_HUGE,
+ };
+ int rc = 0;
+ struct iwl_scan_cmd *scan;
+ struct ieee80211_conf *conf = NULL;
+ u8 direct_mask;
+ int phymode;
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ mutex_lock(&priv->mutex);
+
+ if (!iwl_is_ready(priv)) {
+ IWL_WARNING("request scan called when driver not ready.\n");
+ goto done;
+ }
+
+ /* Make sure the scan wasn't cancelled before this queued work
+ * was given the chance to run... */
+ if (!test_bit(STATUS_SCANNING, &priv->status))
+ goto done;
+
+ /* This should never be called or scheduled if there is currently
+ * a scan active in the hardware. */
+ if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+ IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. "
+ "Ignoring second request.\n");
+ rc = -EIO;
+ goto done;
+ }
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n");
+ goto done;
+ }
+
+ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+ IWL_DEBUG_HC("Scan request while abort pending. Queuing.\n");
+ goto done;
+ }
+
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
+ goto done;
+ }
+
+ if (!test_bit(STATUS_READY, &priv->status)) {
+ IWL_DEBUG_HC("Scan request while uninitialized. Queuing.\n");
+ goto done;
+ }
+
+ if (!priv->scan_bands) {
+ IWL_DEBUG_HC("Aborting scan due to no requested bands\n");
+ goto done;
+ }
+
+ if (!priv->scan) {
+ priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) +
+ IWL_MAX_SCAN_SIZE, GFP_KERNEL);
+ if (!priv->scan) {
+ rc = -ENOMEM;
+ goto done;
+ }
+ }
+ scan = priv->scan;
+ memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
+
+ scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
+ scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+
+ if (iwl_is_associated(priv)) {
+ u16 interval = 0;
+ u32 extra;
+ u32 suspend_time = 100;
+ u32 scan_suspend_time = 100;
+ unsigned long flags;
+
+ IWL_DEBUG_INFO("Scanning while associated...\n");
+
+ spin_lock_irqsave(&priv->lock, flags);
+ interval = priv->beacon_int;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ scan->suspend_time = 0;
+ scan->max_out_time = cpu_to_le32(200 * 1024);
+ if (!interval)
+ interval = suspend_time;
+
+ extra = (suspend_time / interval) << 22;
+ scan_suspend_time = (extra |
+ ((suspend_time % interval) * 1024));
+ scan->suspend_time = cpu_to_le32(scan_suspend_time);
+ IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n",
+ scan_suspend_time, interval);
+ }
+
+ /* We should add the ability for user to lock to PASSIVE ONLY */
+ if (priv->one_direct_scan) {
+ IWL_DEBUG_SCAN
+ ("Kicking off one direct scan for '%s'\n",
+ iwl_escape_essid(priv->direct_ssid,
+ priv->direct_ssid_len));
+ scan->direct_scan[0].id = WLAN_EID_SSID;
+ scan->direct_scan[0].len = priv->direct_ssid_len;
+ memcpy(scan->direct_scan[0].ssid,
+ priv->direct_ssid, priv->direct_ssid_len);
+ direct_mask = 1;
+ } else if (!iwl_is_associated(priv) && priv->essid_len) {
+ scan->direct_scan[0].id = WLAN_EID_SSID;
+ scan->direct_scan[0].len = priv->essid_len;
+ memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
+ direct_mask = 1;
+ } else
+ direct_mask = 0;
+
+ /* We don't build a direct scan probe request; the uCode will do
+ * that based on the direct_mask added to each channel entry */
+ scan->tx_cmd.len = cpu_to_le16(
+ iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
+ IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
+ scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
+ scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
+ scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+ /* flags + rate selection */
+
+ scan->tx_cmd.tx_flags |= cpu_to_le32(0x200);
+
+ switch (priv->scan_bands) {
+ case 2:
+ scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
+ scan->tx_cmd.rate_n_flags =
+ iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP,
+ RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK);
+
+ scan->good_CRC_th = 0;
+ phymode = MODE_IEEE80211G;
+ break;
+
+ case 1:
+ scan->tx_cmd.rate_n_flags =
+ iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
+ RATE_MCS_ANT_B_MSK);
+ scan->good_CRC_th = IWL_GOOD_CRC_TH;
+ phymode = MODE_IEEE80211A;
+ break;
+
+ default:
+ IWL_WARNING("Invalid scan band count\n");
+ goto done;
+ }
+
+ /* select Rx chains */
+
+ /* Force use of chains B and C (0x6) for scan Rx.
+ * Avoid A (0x1) because of its off-channel reception on A-band.
+ * MIMO is not used here, but value is required to make uCode happy. */
+ scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
+ cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) |
+ (0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) |
+ (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
+ scan->filter_flags = RXON_FILTER_PROMISC_MSK;
+
+ if (direct_mask)
+ IWL_DEBUG_SCAN
+ ("Initiating direct scan for %s.\n",
+ iwl_escape_essid(priv->essid, priv->essid_len));
+ else
+ IWL_DEBUG_SCAN("Initiating indirect scan.\n");
+
+ scan->channel_count =
+ iwl_get_channels_for_scan(
+ priv, phymode, 1, /* active */
+ direct_mask,
+ (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+
+ cmd.len += le16_to_cpu(scan->tx_cmd.len) +
+ scan->channel_count * sizeof(struct iwl_scan_channel);
+ cmd.data = scan;
+ scan->len = cpu_to_le16(cmd.len);
+
+ set_bit(STATUS_SCAN_HW, &priv->status);
+ rc = iwl_send_cmd_sync(priv, &cmd);
+ if (rc)
+ goto done;
+
+ queue_delayed_work(priv->workqueue, &priv->scan_check,
+ IWL_SCAN_CHECK_WATCHDOG);
+
+ mutex_unlock(&priv->mutex);
+ return;
+
+ done:
+ /* inform mac80211 sacn aborted */
+ queue_work(priv->workqueue, &priv->scan_completed);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_up(struct work_struct *data)
+{
+ struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ __iwl_up(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_restart(struct work_struct *data)
+{
+ struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ iwl_down(priv);
+ queue_work(priv->workqueue, &priv->up);
+}
+
+static void iwl_bg_rx_replenish(struct work_struct *data)
+{
+ struct iwl_priv *priv =
+ container_of(data, struct iwl_priv, rx_replenish);
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+ iwl_rx_replenish(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_post_associate(struct work_struct *data)
+{
+ struct iwl_priv *priv = container_of(data, struct iwl_priv,
+ post_associate.work);
+
+ int rc = 0;
+ struct ieee80211_conf *conf = NULL;
+ DECLARE_MAC_BUF(mac);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
+ return;
+ }
+
+ IWL_DEBUG_ASSOC("Associated as %d to: %s\n",
+ priv->assoc_id,
+ print_mac(mac, priv->active_rxon.bssid_addr));
+
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ if (!priv->interface_id || !priv->is_open) {
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+ iwl_scan_cancel_timeout(priv, 200);
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
+ iwl_setup_rxon_timing(priv);
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+ sizeof(priv->rxon_timing), &priv->rxon_timing);
+ if (rc)
+ IWL_WARNING("REPLY_RXON_TIMING failed - "
+ "Attempting to continue.\n");
+
+ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+
+#ifdef CONFIG_IWLWIFI_HT
+ if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht)
+ iwl4965_set_rxon_ht(priv, &priv->current_assoc_ht);
+ else {
+ priv->active_rate_ht[0] = 0;
+ priv->active_rate_ht[1] = 0;
+ priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ;
+ }
+#endif /* CONFIG_IWLWIFI_HT*/
+ iwl4965_set_rxon_chain(priv);
+ priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+
+ IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n",
+ priv->assoc_id, priv->beacon_int);
+
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+ else
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+ }
+
+ iwl_commit_rxon(priv);
+
+ switch (priv->iw_mode) {
+ case IEEE80211_IF_TYPE_STA:
+ iwl_rate_scale_init(priv->hw, IWL_AP_ID);
+ break;
+
+ case IEEE80211_IF_TYPE_IBSS:
+
+ /* clear out the station table */
+ iwl_clear_stations_table(priv);
+
+ iwl_rxon_add_station(priv, BROADCAST_ADDR, 0);
+ iwl_rxon_add_station(priv, priv->bssid, 0);
+ iwl_rate_scale_init(priv->hw, IWL_STA_ID);
+ iwl_send_beacon_cmd(priv);
+
+ break;
+
+ default:
+ IWL_ERROR("%s Should not be called in %d mode\n",
+ __FUNCTION__, priv->iw_mode);
+ break;
+ }
+
+ iwl_sequence_reset(priv);
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+ /* Enable Rx differential gain and sensitivity calibrations */
+ iwl4965_chain_noise_reset(priv);
+ priv->start_calib = 1;
+#endif /* CONFIG_IWLWIFI_SENSITIVITY */
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->assoc_station_added = 1;
+
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_activate_qos(priv, 0);
+#endif /* CONFIG_IWLWIFI_QOS */
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_abort_scan(struct work_struct *work)
+{
+ struct iwl_priv *priv = container_of(work, struct iwl_priv,
+ abort_scan);
+
+ if (!iwl_is_ready(priv))
+ return;
+
+ mutex_lock(&priv->mutex);
+
+ set_bit(STATUS_SCAN_ABORTING, &priv->status);
+ iwl_send_scan_abort(priv);
+
+ mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_scan_completed(struct work_struct *work)
+{
+ struct iwl_priv *priv =
+ container_of(work, struct iwl_priv, scan_completed);
+
+ IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n");
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ ieee80211_scan_completed(priv->hw);
+
+ /* Since setting the TXPOWER may have been deferred while
+ * performing the scan, fire one off */
+ mutex_lock(&priv->mutex);
+ iwl_hw_reg_send_txpower(priv);
+ mutex_unlock(&priv->mutex);
+}
+
+/*****************************************************************************
+ *
+ * mac80211 entry point functions
+ *
+ *****************************************************************************/
+
+static int iwl_mac_start(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ /* we should be verifying the device is ready to be opened */
+ mutex_lock(&priv->mutex);
+
+ priv->is_open = 1;
+
+ if (!iwl_is_rfkill(priv))
+ ieee80211_start_queues(priv->hw);
+
+ mutex_unlock(&priv->mutex);
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static void iwl_mac_stop(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+
+ mutex_lock(&priv->mutex);
+ /* stop mac, cancel any scan request and clear
+ * RXON_FILTER_ASSOC_MSK BIT
+ */
+ priv->is_open = 0;
+ iwl_scan_cancel_timeout(priv, 100);
+ cancel_delayed_work(&priv->post_associate);
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("leave\n");
+}
+
+static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *ctl)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+ IWL_DEBUG_MAC80211("leave - monitor\n");
+ return -1;
+ }
+
+ IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
+ ctl->tx_rate);
+
+ if (iwl_tx_skb(priv, skb, ctl))
+ dev_kfree_skb_any(skb);
+
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static int iwl_mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type);
+ if (conf->mac_addr)
+ IWL_DEBUG_MAC80211("enter: MAC %s\n",
+ print_mac(mac, conf->mac_addr));
+
+ if (priv->interface_id) {
+ IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
+ return 0;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->interface_id = conf->if_id;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ mutex_lock(&priv->mutex);
+ iwl_set_mode(priv, conf->type);
+
+ IWL_DEBUG_MAC80211("leave\n");
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+/**
+ * iwl_mac_config - mac80211 config callback
+ *
+ * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
+ * be set inappropriately and the driver currently sets the hardware up to
+ * use it whenever needed.
+ */
+static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ const struct iwl_channel_info *ch_info;
+ unsigned long flags;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
+
+ if (!iwl_is_ready(priv)) {
+ IWL_DEBUG_MAC80211("leave - not ready\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
+ * what is exposed through include/ declrations */
+ if (unlikely(!iwl_param_disable_hw_scan &&
+ test_bit(STATUS_SCANNING, &priv->status))) {
+ IWL_DEBUG_MAC80211("leave - scanning\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
+ conf->channel, conf->phymode);
+ IWL_DEBUG_MAC80211("leave - invalid channel\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+ mutex_unlock(&priv->mutex);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_IWLWIFI_HT
+ /* if we are switching fron ht to 2.4 clear flags
+ * from any ht related info since 2.4 does not
+ * support ht */
+ if ((le16_to_cpu(priv->staging_rxon.channel) != conf->channel)
+#ifdef IEEE80211_CONF_CHANNEL_SWITCH
+ && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH)
+#endif
+ )
+ priv->staging_rxon.flags = 0;
+#endif /* CONFIG_IWLWIFI_HT */
+
+ iwl_set_rxon_channel(priv, conf->phymode, conf->channel);
+
+ iwl_set_flags_for_phymode(priv, conf->phymode);
+
+ /* The list of supported rates and rate mask can be different
+ * for each phymode; since the phymode may have changed, reset
+ * the rate mask to what mac80211 lists */
+ iwl_set_rate(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef IEEE80211_CONF_CHANNEL_SWITCH
+ if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
+ iwl_hw_channel_switch(priv, conf->channel);
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+#endif
+
+ iwl_radio_kill_sw(priv, !conf->radio_enabled);
+
+ if (!conf->radio_enabled) {
+ IWL_DEBUG_MAC80211("leave - radio disabled\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF kill\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ iwl_set_rate(priv);
+
+ if (memcmp(&priv->active_rxon,
+ &priv->staging_rxon, sizeof(priv->staging_rxon)))
+ iwl_commit_rxon(priv);
+ else
+ IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void iwl_config_ap(struct iwl_priv *priv)
+{
+ int rc = 0;
+
+ if (priv->status & STATUS_EXIT_PENDING)
+ return;
+
+ /* The following should be done only at AP bring up */
+ if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) {
+
+ /* RXON - unassoc (to set timing command) */
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ /* RXON Timing */
+ memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
+ iwl_setup_rxon_timing(priv);
+ rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+ sizeof(priv->rxon_timing), &priv->rxon_timing);
+ if (rc)
+ IWL_WARNING("REPLY_RXON_TIMING failed - "
+ "Attempting to continue.\n");
+
+ iwl4965_set_rxon_chain(priv);
+
+ /* FIXME: what should be the assoc_id for AP? */
+ priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ priv->staging_rxon.flags |=
+ RXON_FLG_SHORT_PREAMBLE_MSK;
+ else
+ priv->staging_rxon.flags &=
+ ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+ if (priv->assoc_capability &
+ WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ priv->staging_rxon.flags |=
+ RXON_FLG_SHORT_SLOT_MSK;
+ else
+ priv->staging_rxon.flags &=
+ ~RXON_FLG_SHORT_SLOT_MSK;
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+ priv->staging_rxon.flags &=
+ ~RXON_FLG_SHORT_SLOT_MSK;
+ }
+ /* restore RXON assoc */
+ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_activate_qos(priv, 1);
+#endif
+ iwl_rxon_add_station(priv, BROADCAST_ADDR, 0);
+ }
+ iwl_send_beacon_cmd(priv);
+
+ /* FIXME - we need to add code here to detect a totally new
+ * configuration, reset the AP, unassoc, rxon timing, assoc,
+ * clear sta table, add BCAST sta... */
+}
+
+static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+ DECLARE_MAC_BUF(mac);
+ unsigned long flags;
+ int rc;
+
+ if (conf == NULL)
+ return -EIO;
+
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+ (!conf->beacon || !conf->ssid_len)) {
+ IWL_DEBUG_MAC80211
+ ("Leaving in AP mode because HostAPD is not ready.\n");
+ return 0;
+ }
+
+ mutex_lock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
+ if (conf->bssid)
+ IWL_DEBUG_MAC80211("bssid: %s\n",
+ print_mac(mac, conf->bssid));
+
+/*
+ * very dubious code was here; the probe filtering flag is never set:
+ *
+ if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
+ !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
+ */
+ if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
+ IWL_DEBUG_MAC80211("leave - scanning\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ if (priv->interface_id != if_id) {
+ IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+ if (!conf->bssid) {
+ conf->bssid = priv->mac_addr;
+ memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
+ IWL_DEBUG_MAC80211("bssid was set to: %s\n",
+ print_mac(mac, conf->bssid));
+ }
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = conf->beacon;
+ }
+
+ if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
+ !is_multicast_ether_addr(conf->bssid)) {
+ /* If there is currently a HW scan going on in the background
+ * then we need to cancel it else the RXON below will fail. */
+ if (iwl_scan_cancel_timeout(priv, 100)) {
+ IWL_WARNING("Aborted scan still in progress "
+ "after 100ms\n");
+ IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+ mutex_unlock(&priv->mutex);
+ return -EAGAIN;
+ }
+ memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN);
+
+ /* TODO: Audit driver for usage of these members and see
+ * if mac80211 deprecates them (priv->bssid looks like it
+ * shouldn't be there, but I haven't scanned the IBSS code
+ * to verify) - jpk */
+ memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ iwl_config_ap(priv);
+ else {
+ rc = iwl_commit_rxon(priv);
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
+ iwl_rxon_add_station(
+ priv, priv->active_rxon.bssid_addr, 1);
+ }
+
+ } else {
+ iwl_scan_cancel_timeout(priv, 100);
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!conf->ssid_len)
+ memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+ else
+ memcpy(priv->essid, conf->ssid, conf->ssid_len);
+
+ priv->essid_len = conf->ssid_len;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_MAC80211("leave\n");
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void iwl_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_addr_list *mc_list)
+{
+ /*
+ * XXX: dummy
+ * see also iwl_connection_init_rx_config
+ */
+ *total_flags = 0;
+}
+
+static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ mutex_lock(&priv->mutex);
+
+ iwl_scan_cancel_timeout(priv, 100);
+ cancel_delayed_work(&priv->post_associate);
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+
+ if (priv->interface_id == conf->if_id) {
+ priv->interface_id = 0;
+ memset(priv->bssid, 0, ETH_ALEN);
+ memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+ priv->essid_len = 0;
+ }
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+#define IWL_DELAY_NEXT_SCAN (HZ*2)
+static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ mutex_lock(&priv->mutex);
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (!iwl_is_ready_rf(priv)) {
+ rc = -EIO;
+ IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
+ goto out_unlock;
+ }
+
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { /* APs don't scan */
+ rc = -EIO;
+ IWL_ERROR("ERROR: APs don't scan\n");
+ goto out_unlock;
+ }
+
+ /* if we just finished scan ask for delay */
+ if (priv->last_scan_jiffies &&
+ time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
+ jiffies)) {
+ rc = -EAGAIN;
+ goto out_unlock;
+ }
+ if (len) {
+ IWL_DEBUG_SCAN("direct scan for "
+ "%s [%d]\n ",
+ iwl_escape_essid(ssid, len), (int)len);
+
+ priv->one_direct_scan = 1;
+ priv->direct_ssid_len = (u8)
+ min((u8) len, (u8) IW_ESSID_MAX_SIZE);
+ memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
+ } else
+ priv->one_direct_scan = 0;
+
+ rc = iwl_scan_initiate(priv);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+out_unlock:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ mutex_unlock(&priv->mutex);
+
+ return rc;
+}
+
+static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ const u8 *local_addr, const u8 *addr,
+ struct ieee80211_key_conf *key)
+{
+ struct iwl_priv *priv = hw->priv;
+ DECLARE_MAC_BUF(mac);
+ int rc = 0;
+ u8 sta_id;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_param_hwcrypto) {
+ IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (is_zero_ether_addr(addr))
+ /* only support pairwise keys */
+ return -EOPNOTSUPP;
+
+ sta_id = iwl_hw_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
+ print_mac(mac, addr));
+ return -EINVAL;
+ }
+
+ mutex_lock(&priv->mutex);
+
+ iwl_scan_cancel_timeout(priv, 100);
+
+ switch (cmd) {
+ case SET_KEY:
+ rc = iwl_update_sta_key_info(priv, key, sta_id);
+ if (!rc) {
+ iwl_set_rxon_hwcrypto(priv, 1);
+ iwl_commit_rxon(priv);
+ key->hw_key_idx = sta_id;
+ IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n");
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ }
+ break;
+ case DISABLE_KEY:
+ rc = iwl_clear_sta_key_info(priv, sta_id);
+ if (!rc) {
+ iwl_set_rxon_hwcrypto(priv, 0);
+ iwl_commit_rxon(priv);
+ IWL_DEBUG_MAC80211("disable hwcrypto key\n");
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ }
+
+ IWL_DEBUG_MAC80211("leave\n");
+ mutex_unlock(&priv->mutex);
+
+ return rc;
+}
+
+static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct iwl_priv *priv = hw->priv;
+#ifdef CONFIG_IWLWIFI_QOS
+ unsigned long flags;
+ int q;
+#endif /* CONFIG_IWL_QOS */
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF not ready\n");
+ return -EIO;
+ }
+
+ if (queue >= AC_NUM) {
+ IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue);
+ return 0;
+ }
+
+#ifdef CONFIG_IWLWIFI_QOS
+ if (!priv->qos_data.qos_enable) {
+ priv->qos_data.qos_active = 0;
+ IWL_DEBUG_MAC80211("leave - qos not enabled\n");
+ return 0;
+ }
+ q = AC_NUM - 1 - queue;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
+ priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
+ priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+ priv->qos_data.def_qos_parm.ac[q].edca_txop =
+ cpu_to_le16((params->burst_time * 100));
+
+ priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+ priv->qos_data.qos_active = 1;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ mutex_lock(&priv->mutex);
+ if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+ iwl_activate_qos(priv, 1);
+ else if (priv->assoc_id && iwl_is_associated(priv))
+ iwl_activate_qos(priv, 0);
+
+ mutex_unlock(&priv->mutex);
+
+#endif /*CONFIG_IWLWIFI_QOS */
+
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct iwl_priv *priv = hw->priv;
+ int i, avail;
+ struct iwl_tx_queue *txq;
+ struct iwl_queue *q;
+ unsigned long flags;
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF not ready\n");
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ for (i = 0; i < AC_NUM; i++) {
+ txq = &priv->txq[i];
+ q = &txq->q;
+ avail = iwl_queue_space(q);
+
+ stats->data[i].len = q->n_window - avail;
+ stats->data[i].limit = q->n_window - q->high_mark;
+ stats->data[i].count = q->n_window;
+
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+ return 0;
+}
+
+static int iwl_mac_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ IWL_DEBUG_MAC80211("enter\n");
+ IWL_DEBUG_MAC80211("leave\n");
+
+ return 0;
+}
+
+static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
+{
+ IWL_DEBUG_MAC80211("enter\n");
+ IWL_DEBUG_MAC80211("leave\n");
+
+ return 0;
+}
+
+static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211("enter\n");
+
+ priv->lq_mngr.lq_ready = 0;
+#ifdef CONFIG_IWLWIFI_HT
+ spin_lock_irqsave(&priv->lock, flags);
+ memset(&priv->current_assoc_ht, 0, sizeof(struct sta_ht_info));
+ spin_unlock_irqrestore(&priv->lock, flags);
+#ifdef CONFIG_IWLWIFI_HT_AGG
+/* if (priv->lq_mngr.agg_ctrl.granted_ba)
+ iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);*/
+
+ memset(&(priv->lq_mngr.agg_ctrl), 0, sizeof(struct iwl_agg_control));
+ priv->lq_mngr.agg_ctrl.tid_traffic_load_threshold = 10;
+ priv->lq_mngr.agg_ctrl.ba_timeout = 5000;
+ priv->lq_mngr.agg_ctrl.auto_agg = 1;
+
+ if (priv->lq_mngr.agg_ctrl.auto_agg)
+ priv->lq_mngr.agg_ctrl.requested_ba = TID_ALL_ENABLED;
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_reset_qos(priv);
+#endif
+
+ cancel_delayed_work(&priv->post_associate);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->assoc_id = 0;
+ priv->assoc_capability = 0;
+ priv->call_post_assoc_from_beacon = 0;
+ priv->assoc_station_added = 0;
+
+ /* new association get rid of ibss beacon skb */
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = NULL;
+
+ priv->beacon_int = priv->hw->conf.beacon_int;
+ priv->timestamp1 = 0;
+ priv->timestamp0 = 0;
+ if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
+ priv->beacon_int = 0;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* we are restarting association process
+ * clear RXON_FILTER_ASSOC_MSK bit
+ */
+ if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+ iwl_scan_cancel_timeout(priv, 100);
+ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+ iwl_commit_rxon(priv);
+ }
+
+ /* Per mac80211.h: This is only used in IBSS mode... */
+ if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+
+ IWL_DEBUG_MAC80211("leave - not in IBSS\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - not ready\n");
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
+ priv->only_active_channel = 0;
+
+ iwl_set_rate(priv);
+
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct iwl_priv *priv = hw->priv;
+ unsigned long flags;
+
+ mutex_lock(&priv->mutex);
+ IWL_DEBUG_MAC80211("enter\n");
+
+ if (!iwl_is_ready_rf(priv)) {
+ IWL_DEBUG_MAC80211("leave - RF not ready\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+ IWL_DEBUG_MAC80211("leave - not IBSS\n");
+ mutex_unlock(&priv->mutex);
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ priv->ibss_beacon = skb;
+
+ priv->assoc_id = 0;
+
+ IWL_DEBUG_MAC80211("leave\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef CONFIG_IWLWIFI_QOS
+ iwl_reset_qos(priv);
+#endif
+
+ queue_work(priv->workqueue, &priv->post_associate.work);
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+union ht_cap_info {
+ struct {
+ u16 advanced_coding_cap :1;
+ u16 supported_chan_width_set :1;
+ u16 mimo_power_save_mode :2;
+ u16 green_field :1;
+ u16 short_GI20 :1;
+ u16 short_GI40 :1;
+ u16 tx_stbc :1;
+ u16 rx_stbc :1;
+ u16 beam_forming :1;
+ u16 delayed_ba :1;
+ u16 maximal_amsdu_size :1;
+ u16 cck_mode_at_40MHz :1;
+ u16 psmp_support :1;
+ u16 stbc_ctrl_frame_support :1;
+ u16 sig_txop_protection_support :1;
+ };
+ u16 val;
+} __attribute__ ((packed));
+
+union ht_param_info{
+ struct {
+ u8 max_rx_ampdu_factor :2;
+ u8 mpdu_density :3;
+ u8 reserved :3;
+ };
+ u8 val;
+} __attribute__ ((packed));
+
+union ht_exra_param_info {
+ struct {
+ u8 ext_chan_offset :2;
+ u8 tx_chan_width :1;
+ u8 rifs_mode :1;
+ u8 controlled_access_only :1;
+ u8 service_interval_granularity :3;
+ };
+ u8 val;
+} __attribute__ ((packed));
+
+union ht_operation_mode{
+ struct {
+ u16 op_mode :2;
+ u16 non_GF :1;
+ u16 reserved :13;
+ };
+ u16 val;
+} __attribute__ ((packed));
+
+
+static int sta_ht_info_init(struct ieee80211_ht_capability *ht_cap,
+ struct ieee80211_ht_additional_info *ht_extra,
+ struct sta_ht_info *ht_info_ap,
+ struct sta_ht_info *ht_info)
+{
+ union ht_cap_info cap;
+ union ht_operation_mode op_mode;
+ union ht_param_info param_info;
+ union ht_exra_param_info extra_param_info;
+
+ IWL_DEBUG_MAC80211("enter: \n");
+
+ if (!ht_info) {
+ IWL_DEBUG_MAC80211("leave: ht_info is NULL\n");
+ return -1;
+ }
+
+ if (ht_cap) {
+ cap.val = (u16) le16_to_cpu(ht_cap->capabilities_info);
+ param_info.val = ht_cap->mac_ht_params_info;
+ ht_info->is_ht = 1;
+ if (cap.short_GI20)
+ ht_info->sgf |= 0x1;
+ if (cap.short_GI40)
+ ht_info->sgf |= 0x2;
+ ht_info->is_green_field = cap.green_field;
+ ht_info->max_amsdu_size = cap.maximal_amsdu_size;
+ ht_info->supported_chan_width = cap.supported_chan_width_set;
+ ht_info->tx_mimo_ps_mode = cap.mimo_power_save_mode;
+ memcpy(ht_info->supp_rates, ht_cap->supported_mcs_set, 16);
+
+ ht_info->ampdu_factor = param_info.max_rx_ampdu_factor;
+ ht_info->mpdu_density = param_info.mpdu_density;
+
+ IWL_DEBUG_MAC80211("SISO mask 0x%X MIMO mask 0x%X \n",
+ ht_cap->supported_mcs_set[0],
+ ht_cap->supported_mcs_set[1]);
+
+ if (ht_info_ap) {
+ ht_info->control_channel = ht_info_ap->control_channel;
+ ht_info->extension_chan_offset =
+ ht_info_ap->extension_chan_offset;
+ ht_info->tx_chan_width = ht_info_ap->tx_chan_width;
+ ht_info->operating_mode = ht_info_ap->operating_mode;
+ }
+
+ if (ht_extra) {
+ extra_param_info.val = ht_extra->ht_param;
+ ht_info->control_channel = ht_extra->control_chan;
+ ht_info->extension_chan_offset =
+ extra_param_info.ext_chan_offset;
+ ht_info->tx_chan_width = extra_param_info.tx_chan_width;
+ op_mode.val = (u16)
+ le16_to_cpu(ht_extra->operation_mode);
+ ht_info->operating_mode = op_mode.op_mode;
+ IWL_DEBUG_MAC80211("control channel %d\n",
+ ht_extra->control_chan);
+ }
+ } else
+ ht_info->is_ht = 0;
+
+ IWL_DEBUG_MAC80211("leave\n");
+ return 0;
+}
+
+static int iwl_mac_conf_ht(struct ieee80211_hw *hw,
+ struct ieee80211_ht_capability *ht_cap,
+ struct ieee80211_ht_additional_info *ht_extra)
+{
+ struct iwl_priv *priv = hw->priv;
+ int rs;
+
+ IWL_DEBUG_MAC80211("enter: \n");
+
+ rs = sta_ht_info_init(ht_cap, ht_extra, NULL, &priv->current_assoc_ht);
+ iwl4965_set_rxon_chain(priv);
+
+ if (priv && priv->assoc_id &&
+ (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->beacon_int)
+ queue_work(priv->workqueue, &priv->post_associate.work);
+ else
+ priv->call_post_assoc_from_beacon = 1;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ IWL_DEBUG_MAC80211("leave: control channel %d\n",
+ ht_extra->control_chan);
+ return rs;
+
+}
+
+static void iwl_set_ht_capab(struct ieee80211_hw *hw,
+ struct ieee80211_ht_capability *ht_cap,
+ u8 use_wide_chan)
+{
+ union ht_cap_info cap;
+ union ht_param_info param_info;
+
+ memset(&cap, 0, sizeof(union ht_cap_info));
+ memset(&param_info, 0, sizeof(union ht_param_info));
+
+ cap.maximal_amsdu_size = HT_IE_MAX_AMSDU_SIZE_4K;
+ cap.green_field = 1;
+ cap.short_GI20 = 1;
+ cap.short_GI40 = 1;
+ cap.supported_chan_width_set = use_wide_chan;
+ cap.mimo_power_save_mode = 0x3;
+
+ param_info.max_rx_ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
+ param_info.mpdu_density = CFG_HT_MPDU_DENSITY_DEF;
+ ht_cap->capabilities_info = (__le16) cpu_to_le16(cap.val);
+ ht_cap->mac_ht_params_info = (u8) param_info.val;
+
+ ht_cap->supported_mcs_set[0] = 0xff;
+ ht_cap->supported_mcs_set[1] = 0xff;
+ ht_cap->supported_mcs_set[4] =
+ (cap.supported_chan_width_set) ? 0x1: 0x0;
+}
+
+static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw,
+ struct ieee80211_ht_capability *ht_cap)
+{
+ u8 use_wide_channel = 1;
+ struct iwl_priv *priv = hw->priv;
+
+ IWL_DEBUG_MAC80211("enter: \n");
+ if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
+ use_wide_channel = 0;
+
+ /* no fat tx allowed on 2.4GHZ */
+ if (priv->phymode != MODE_IEEE80211A)
+ use_wide_channel = 0;
+
+ iwl_set_ht_capab(hw, ht_cap, use_wide_channel);
+ IWL_DEBUG_MAC80211("leave: \n");
+}
+#endif /*CONFIG_IWLWIFI_HT*/
+
+/*****************************************************************************
+ *
+ * sysfs attributes
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/*
+ * The following adds a new attribute to the sysfs representation
+ * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/)
+ * used for controlling the debug level.
+ *
+ * See the level definitions in iwl for details.
+ */
+
+static ssize_t show_debug_level(struct device_driver *d, char *buf)
+{
+ return sprintf(buf, "0x%08X\n", iwl_debug_level);
+}
+static ssize_t store_debug_level(struct device_driver *d,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+ u32 val;
+
+ val = simple_strtoul(p, &p, 0);
+ if (p == buf)
+ printk(KERN_INFO DRV_NAME
+ ": %s is not in hex or decimal form.\n", buf);
+ else
+ iwl_debug_level = val;
+
+ return strnlen(buf, count);
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+ show_debug_level, store_debug_level);
+
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+static ssize_t show_rf_kill(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ /*
+ * 0 - RF kill not enabled
+ * 1 - SW based RF kill active (sysfs)
+ * 2 - HW based RF kill active
+ * 3 - Both HW and SW based RF kill active
+ */
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
+ (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);
+
+ return sprintf(buf, "%i\n", val);
+}
+
+static ssize_t store_rf_kill(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ mutex_lock(&priv->mutex);
+ iwl_radio_kill_sw(priv, buf[0] == '1');
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
+
+static ssize_t show_temperature(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv));
+}
+
+static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
+
+static ssize_t show_rs_window(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iwl_priv *priv = d->driver_data;
+ return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID);
+}
+static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
+
+static ssize_t show_tx_power(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ return sprintf(buf, "%d\n", priv->user_txpower_limit);
+}
+
+static ssize_t store_tx_power(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ char *p = (char *)buf;
+ u32 val;
+
+ val = simple_strtoul(p, &p, 10);
+ if (p == buf)
+ printk(KERN_INFO DRV_NAME
+ ": %s is not in decimal form.\n", buf);
+ else
+ iwl_hw_reg_set_txpower(priv, val);
+
+ return count;
+}
+
+static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
+
+static ssize_t show_flags(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
+}
+
+static ssize_t store_flags(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ u32 flags = simple_strtoul(buf, NULL, 0);
+
+ mutex_lock(&priv->mutex);
+ if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
+ /* Cancel any currently running scans... */
+ if (iwl_scan_cancel_timeout(priv, 100))
+ IWL_WARNING("Could not cancel scan.\n");
+ else {
+ IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n",
+ flags);
+ priv->staging_rxon.flags = cpu_to_le32(flags);
+ iwl_commit_rxon(priv);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
+
+static ssize_t show_filter_flags(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ return sprintf(buf, "0x%04X\n",
+ le32_to_cpu(priv->active_rxon.filter_flags));
+}
+
+static ssize_t store_filter_flags(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ u32 filter_flags = simple_strtoul(buf, NULL, 0);
+
+ mutex_lock(&priv->mutex);
+ if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
+ /* Cancel any currently running scans... */
+ if (iwl_scan_cancel_timeout(priv, 100))
+ IWL_WARNING("Could not cancel scan.\n");
+ else {
+ IWL_DEBUG_INFO("Committing rxon.filter_flags = "
+ "0x%04X\n", filter_flags);
+ priv->staging_rxon.filter_flags =
+ cpu_to_le32(filter_flags);
+ iwl_commit_rxon(priv);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
+ store_filter_flags);
+
+static ssize_t show_tune(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+ return sprintf(buf, "0x%04X\n",
+ (priv->phymode << 8) |
+ le16_to_cpu(priv->active_rxon.channel));
+}
+
+static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode);
+
+static ssize_t store_tune(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ char *p = (char *)buf;
+ u16 tune = simple_strtoul(p, &p, 0);
+ u8 phymode = (tune >> 8) & 0xff;
+ u16 channel = tune & 0xff;
+
+ IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel);
+
+ mutex_lock(&priv->mutex);
+ if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
+ (priv->phymode != phymode)) {
+ const struct iwl_channel_info *ch_info;
+
+ ch_info = iwl_get_channel_info(priv, phymode, channel);
+ if (!ch_info) {
+ IWL_WARNING("Requested invalid phymode/channel "
+ "combination: %d %d\n", phymode, channel);
+ mutex_unlock(&priv->mutex);
+ return -EINVAL;
+ }
+
+ /* Cancel any currently running scans... */
+ if (iwl_scan_cancel_timeout(priv, 100))
+ IWL_WARNING("Could not cancel scan.\n");
+ else {
+ IWL_DEBUG_INFO("Committing phymode and "
+ "rxon.channel = %d %d\n",
+ phymode, channel);
+
+ iwl_set_rxon_channel(priv, phymode, channel);
+ iwl_set_flags_for_phymode(priv, phymode);
+
+ iwl_set_rate(priv);
+ iwl_commit_rxon(priv);
+ }
+ }
+ mutex_unlock(&priv->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+static ssize_t show_measurement(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ struct iwl_spectrum_notification measure_report;
+ u32 size = sizeof(measure_report), len = 0, ofs = 0;
+ u8 *data = (u8 *) & measure_report;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!(priv->measurement_status & MEASUREMENT_READY)) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
+ }
+ memcpy(&measure_report, &priv->measure_report, size);
+ priv->measurement_status = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while (size && (PAGE_SIZE - len)) {
+ hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+ PAGE_SIZE - len, 1);
+ len = strlen(buf);
+ if (PAGE_SIZE - len)
+ buf[len++] = '\n';
+
+ ofs += 16;
+ size -= min(size, 16U);
+ }
+
+ return len;
+}
+
+static ssize_t store_measurement(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ struct ieee80211_measurement_params params = {
+ .channel = le16_to_cpu(priv->active_rxon.channel),
+ .start_time = cpu_to_le64(priv->last_tsf),
+ .duration = cpu_to_le16(1),
+ };
+ u8 type = IWL_MEASURE_BASIC;
+ u8 buffer[32];
+ u8 channel;
+
+ if (count) {
+ char *p = buffer;
+ strncpy(buffer, buf, min(sizeof(buffer), count));
+ channel = simple_strtoul(p, NULL, 0);
+ if (channel)
+ params.channel = channel;
+
+ p = buffer;
+ while (*p && *p != ' ')
+ p++;
+ if (*p)
+ type = simple_strtoul(p + 1, NULL, 0);
+ }
+
+ IWL_DEBUG_INFO("Invoking measurement of type %d on "
+ "channel %d (for '%s')\n", type, params.channel, buf);
+ iwl_get_measurement(priv, &params, type);
+
+ return count;
+}
+
+static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
+ show_measurement, store_measurement);
+#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */
+
+static ssize_t store_retry_rate(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ priv->retry_rate = simple_strtoul(buf, NULL, 0);
+ if (priv->retry_rate <= 0)
+ priv->retry_rate = 1;
+
+ return count;
+}
+
+static ssize_t show_retry_rate(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ return sprintf(buf, "%d", priv->retry_rate);
+}
+
+static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate,
+ store_retry_rate);
+
+static ssize_t store_power_level(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ int rc;
+ int mode;
+
+ mode = simple_strtoul(buf, NULL, 0);
+ mutex_lock(&priv->mutex);
+
+ if (!iwl_is_ready(priv)) {
+ rc = -EAGAIN;
+ goto out;
+ }
+
+ if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC))
+ mode = IWL_POWER_AC;
+ else
+ mode |= IWL_POWER_ENABLED;
+
+ if (mode != priv->power_mode) {
+ rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode));
+ if (rc) {
+ IWL_DEBUG_MAC80211("failed setting power mode.\n");
+ goto out;
+ }
+ priv->power_mode = mode;
+ }
+
+ rc = count;
+
+ out:
+ mutex_unlock(&priv->mutex);
+ return rc;
+}
+
+#define MAX_WX_STRING 80
+
+/* Values are in microsecond */
+static const s32 timeout_duration[] = {
+ 350000,
+ 250000,
+ 75000,
+ 37000,
+ 25000,
+};
+static const s32 period_duration[] = {
+ 400000,
+ 700000,
+ 1000000,
+ 1000000,
+ 1000000
+};
+
+static ssize_t show_power_level(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ int level = IWL_POWER_LEVEL(priv->power_mode);
+ char *p = buf;
+
+ p += sprintf(p, "%d ", level);
+ switch (level) {
+ case IWL_POWER_MODE_CAM:
+ case IWL_POWER_AC:
+ p += sprintf(p, "(AC)");
+ break;
+ case IWL_POWER_BATTERY:
+ p += sprintf(p, "(BATTERY)");
+ break;
+ default:
+ p += sprintf(p,
+ "(Timeout %dms, Period %dms)",
+ timeout_duration[level - 1] / 1000,
+ period_duration[level - 1] / 1000);
+ }
+
+ if (!(priv->power_mode & IWL_POWER_ENABLED))
+ p += sprintf(p, " OFF\n");
+ else
+ p += sprintf(p, " \n");
+
+ return (p - buf + 1);
+
+}
+
+static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
+ store_power_level);
+
+static ssize_t show_channels(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ int len = 0, i;
+ struct ieee80211_channel *channels = NULL;
+ const struct ieee80211_hw_mode *hw_mode = NULL;
+ int count = 0;
+
+ if (!iwl_is_ready(priv))
+ return -EAGAIN;
+
+ hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G);
+ if (!hw_mode)
+ hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B);
+ if (hw_mode) {
+ channels = hw_mode->channels;
+ count = hw_mode->num_channels;
+ }
+
+ len +=
+ sprintf(&buf[len],
+ "Displaying %d channels in 2.4GHz band "
+ "(802.11bg):\n", count);
+
+ for (i = 0; i < count; i++)
+ len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+ channels[i].chan,
+ channels[i].power_level,
+ channels[i].
+ flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+ " (IEEE 802.11h required)" : "",
+ (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+ || (channels[i].
+ flag &
+ IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+ ", IBSS",
+ channels[i].
+ flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+ "active/passive" : "passive only");
+
+ hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A);
+ if (hw_mode) {
+ channels = hw_mode->channels;
+ count = hw_mode->num_channels;
+ } else {
+ channels = NULL;
+ count = 0;
+ }
+
+ len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band "
+ "(802.11a):\n", count);
+
+ for (i = 0; i < count; i++)
+ len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+ channels[i].chan,
+ channels[i].power_level,
+ channels[i].
+ flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+ " (IEEE 802.11h required)" : "",
+ (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+ || (channels[i].
+ flag &
+ IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+ ", IBSS",
+ channels[i].
+ flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+ "active/passive" : "passive only");
+
+ return len;
+}
+
+static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+
+static ssize_t show_statistics(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ u32 size = sizeof(struct iwl_notif_statistics);
+ u32 len = 0, ofs = 0;
+ u8 *data = (u8 *) & priv->statistics;
+ int rc = 0;
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ mutex_lock(&priv->mutex);
+ rc = iwl_send_statistics_request(priv);
+ mutex_unlock(&priv->mutex);
+
+ if (rc) {
+ len = sprintf(buf,
+ "Error sending statistics request: 0x%08X\n", rc);
+ return len;
+ }
+
+ while (size && (PAGE_SIZE - len)) {
+ hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+ PAGE_SIZE - len, 1);
+ len = strlen(buf);
+ if (PAGE_SIZE - len)
+ buf[len++] = '\n';
+
+ ofs += 16;
+ size -= min(size, 16U);
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
+
+static ssize_t show_antenna(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ return sprintf(buf, "%d\n", priv->antenna);
+}
+
+static ssize_t store_antenna(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ant;
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ if (count == 0)
+ return 0;
+
+ if (sscanf(buf, "%1i", &ant) != 1) {
+ IWL_DEBUG_INFO("not in hex or decimal form.\n");
+ return count;
+ }
+
+ if ((ant >= 0) && (ant <= 2)) {
+ IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
+ priv->antenna = (enum iwl_antenna)ant;
+ } else
+ IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
+
+
+ return count;
+}
+
+static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
+
+static ssize_t show_status(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+ return sprintf(buf, "0x%08x\n", (int)priv->status);
+}
+
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t dump_error_log(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+
+ if (p[0] == '1')
+ iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data);
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
+
+static ssize_t dump_event_log(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char *p = (char *)buf;
+
+ if (p[0] == '1')
+ iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data);
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
+
+/*****************************************************************************
+ *
+ * driver setup and teardown
+ *
+ *****************************************************************************/
+
+static void iwl_setup_deferred_work(struct iwl_priv *priv)
+{
+ priv->workqueue = create_workqueue(DRV_NAME);
+
+ init_waitqueue_head(&priv->wait_command_queue);
+
+ INIT_WORK(&priv->up, iwl_bg_up);
+ INIT_WORK(&priv->restart, iwl_bg_restart);
+ INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
+ INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
+ INIT_WORK(&priv->request_scan, iwl_bg_request_scan);
+ INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
+ INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
+ INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
+ INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate);
+ INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
+ INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
+ INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
+
+ iwl_hw_setup_deferred_work(priv);
+
+ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+ iwl_irq_tasklet, (unsigned long)priv);
+}
+
+static void iwl_cancel_deferred_work(struct iwl_priv *priv)
+{
+ iwl_hw_cancel_deferred_work(priv);
+
+ cancel_delayed_work(&priv->scan_check);
+ cancel_delayed_work(&priv->alive_start);
+ cancel_delayed_work(&priv->post_associate);
+ cancel_work_sync(&priv->beacon_update);
+}
+
+static struct attribute *iwl_sysfs_entries[] = {
+ &dev_attr_antenna.attr,
+ &dev_attr_channels.attr,
+ &dev_attr_dump_errors.attr,
+ &dev_attr_dump_events.attr,
+ &dev_attr_flags.attr,
+ &dev_attr_filter_flags.attr,
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+ &dev_attr_measurement.attr,
+#endif
+ &dev_attr_power_level.attr,
+ &dev_attr_retry_rate.attr,
+ &dev_attr_rf_kill.attr,
+ &dev_attr_rs_window.attr,
+ &dev_attr_statistics.attr,
+ &dev_attr_status.attr,
+ &dev_attr_temperature.attr,
+ &dev_attr_tune.attr,
+ &dev_attr_tx_power.attr,
+
+ NULL
+};
+
+static struct attribute_group iwl_attribute_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = iwl_sysfs_entries,
+};
+
+static struct ieee80211_ops iwl_hw_ops = {
+ .tx = iwl_mac_tx,
+ .start = iwl_mac_start,
+ .stop = iwl_mac_stop,
+ .add_interface = iwl_mac_add_interface,
+ .remove_interface = iwl_mac_remove_interface,
+ .config = iwl_mac_config,
+ .config_interface = iwl_mac_config_interface,
+ .configure_filter = iwl_configure_filter,
+ .set_key = iwl_mac_set_key,
+ .get_stats = iwl_mac_get_stats,
+ .get_tx_stats = iwl_mac_get_tx_stats,
+ .conf_tx = iwl_mac_conf_tx,
+ .get_tsf = iwl_mac_get_tsf,
+ .reset_tsf = iwl_mac_reset_tsf,
+ .beacon_update = iwl_mac_beacon_update,
+#ifdef CONFIG_IWLWIFI_HT
+ .conf_ht = iwl_mac_conf_ht,
+ .get_ht_capab = iwl_mac_get_ht_capab,
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ .ht_tx_agg_start = iwl_mac_ht_tx_agg_start,
+ .ht_tx_agg_stop = iwl_mac_ht_tx_agg_stop,
+ .ht_rx_agg_start = iwl_mac_ht_rx_agg_start,
+ .ht_rx_agg_stop = iwl_mac_ht_rx_agg_stop,
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+ .hw_scan = iwl_mac_hw_scan
+};
+
+static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = 0;
+ struct iwl_priv *priv;
+ struct ieee80211_hw *hw;
+ int i;
+
+ if (iwl_param_disable_hw_scan) {
+ IWL_DEBUG_INFO("Disabling hw_scan\n");
+ iwl_hw_ops.hw_scan = NULL;
+ }
+
+ if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) ||
+ (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) {
+ IWL_ERROR("invalid queues_num, should be between %d and %d\n",
+ IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
+ err = -EINVAL;
+ goto out;
+ }
+
+ /* mac80211 allocates memory for this device instance, including
+ * space for this driver's private structure */
+ hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops);
+ if (hw == NULL) {
+ IWL_ERROR("Can not allocate network device\n");
+ err = -ENOMEM;
+ goto out;
+ }
+ SET_IEEE80211_DEV(hw, &pdev->dev);
+
+ hw->rate_control_algorithm = "iwl-4965-rs";
+
+ IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
+ priv = hw->priv;
+ priv->hw = hw;
+
+ priv->pci_dev = pdev;
+ priv->antenna = (enum iwl_antenna)iwl_param_antenna;
+#ifdef CONFIG_IWLWIFI_DEBUG
+ iwl_debug_level = iwl_param_debug;
+ atomic_set(&priv->restrict_refcnt, 0);
+#endif
+ priv->retry_rate = 1;
+
+ priv->ibss_beacon = NULL;
+
+ /* Tell mac80211 and its clients (e.g. Wireless Extensions)
+ * the range of signal quality values that we'll provide.
+ * Negative values for level/noise indicate that we'll provide dBm.
+ * For WE, at least, non-0 values here *enable* display of values
+ * in app (iwconfig). */
+ hw->max_rssi = -20; /* signal level, negative indicates dBm */
+ hw->max_noise = -20; /* noise level, negative indicates dBm */
+ hw->max_signal = 100; /* link quality indication (%) */
+
+ /* Tell mac80211 our Tx characteristics */
+ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+
+ hw->queues = 4;
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ hw->queues = 16;
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+ spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->power_data.lock);
+ spin_lock_init(&priv->sta_lock);
+ spin_lock_init(&priv->hcmd_lock);
+ spin_lock_init(&priv->lq_mngr.lock);
+
+ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
+ INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
+
+ INIT_LIST_HEAD(&priv->free_frames);
+
+ mutex_init(&priv->mutex);
+ if (pci_enable_device(pdev)) {
+ err = -ENODEV;
+ goto out_ieee80211_free_hw;
+ }
+
+ pci_set_master(pdev);
+
+ iwl_clear_stations_table(priv);
+
+ priv->data_retry_limit = -1;
+ priv->ieee_channels = NULL;
+ priv->ieee_rates = NULL;
+ priv->phymode = -1;
+
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (!err)
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (err) {
+ printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
+ goto out_pci_disable_device;
+ }
+
+ pci_set_drvdata(pdev, priv);
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err)
+ goto out_pci_disable_device;
+ /* We disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state */
+ pci_write_config_byte(pdev, 0x41, 0x00);
+ priv->hw_base = pci_iomap(pdev, 0, 0);
+ if (!priv->hw_base) {
+ err = -ENODEV;
+ goto out_pci_release_regions;
+ }
+
+ IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n",
+ (unsigned long long) pci_resource_len(pdev, 0));
+ IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base);
+
+ /* Initialize module parameter values here */
+
+ if (iwl_param_disable) {
+ set_bit(STATUS_RF_KILL_SW, &priv->status);
+ IWL_DEBUG_INFO("Radio disabled.\n");
+ }
+
+ priv->iw_mode = IEEE80211_IF_TYPE_STA;
+
+ priv->ps_mode = 0;
+ priv->use_ant_b_for_management_frame = 1; /* start with ant B */
+ priv->is_ht_enabled = 1;
+ priv->channel_width = IWL_CHANNEL_WIDTH_40MHZ;
+ priv->valid_antenna = 0x7; /* assume all 3 connected */
+ priv->ps_mode = IWL_MIMO_PS_NONE;
+ priv->cck_power_index_compensation = iwl_read32(
+ priv, CSR_HW_REV_WA_REG);
+
+ iwl4965_set_rxon_chain(priv);
+
+ printk(KERN_INFO DRV_NAME
+ ": Detected Intel Wireless WiFi Link 4965AGN\n");
+
+ /* Device-specific setup */
+ if (iwl_hw_set_hw_setting(priv)) {
+ IWL_ERROR("failed to set hw settings\n");
+ mutex_unlock(&priv->mutex);
+ goto out_iounmap;
+ }
+
+#ifdef CONFIG_IWLWIFI_QOS
+ if (iwl_param_qos_enable)
+ priv->qos_data.qos_enable = 1;
+
+ iwl_reset_qos(priv);
+
+ priv->qos_data.qos_active = 0;
+ priv->qos_data.qos_cap.val = 0;
+#endif /* CONFIG_IWLWIFI_QOS */
+
+ iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6);
+ iwl_setup_deferred_work(priv);
+ iwl_setup_rx_handlers(priv);
+
+ priv->rates_mask = IWL_RATES_MASK;
+ /* If power management is turned on, default to AC mode */
+ priv->power_mode = IWL_POWER_AC;
+ priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
+
+ pci_enable_msi(pdev);
+
+ err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv);
+ if (err) {
+ IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
+ goto out_disable_msi;
+ }
+
+ mutex_lock(&priv->mutex);
+
+ err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
+ if (err) {
+ IWL_ERROR("failed to create sysfs device attributes\n");
+ mutex_unlock(&priv->mutex);
+ goto out_release_irq;
+ }
+
+ /* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+ * ucode filename and max sizes are card-specific. */
+ err = iwl_read_ucode(priv);
+ if (err) {
+ IWL_ERROR("Could not read microcode: %d\n", err);
+ mutex_unlock(&priv->mutex);
+ goto out_pci_alloc;
+ }
+
+ mutex_unlock(&priv->mutex);
+
+ IWL_DEBUG_INFO("Queing UP work.\n");
+
+ queue_work(priv->workqueue, &priv->up);
+
+ return 0;
+
+ out_pci_alloc:
+ iwl_dealloc_ucode_pci(priv);
+
+ sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+
+ out_release_irq:
+ free_irq(pdev->irq, priv);
+
+ out_disable_msi:
+ pci_disable_msi(pdev);
+ destroy_workqueue(priv->workqueue);
+ priv->workqueue = NULL;
+ iwl_unset_hw_setting(priv);
+
+ out_iounmap:
+ pci_iounmap(pdev, priv->hw_base);
+ out_pci_release_regions:
+ pci_release_regions(pdev);
+ out_pci_disable_device:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ out_ieee80211_free_hw:
+ ieee80211_free_hw(priv->hw);
+ out:
+ return err;
+}
+
+static void iwl_pci_remove(struct pci_dev *pdev)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+ struct list_head *p, *q;
+ int i;
+
+ if (!priv)
+ return;
+
+ IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
+
+ mutex_lock(&priv->mutex);
+ set_bit(STATUS_EXIT_PENDING, &priv->status);
+ __iwl_down(priv);
+ mutex_unlock(&priv->mutex);
+
+ /* Free MAC hash list for ADHOC */
+ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
+ list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
+ list_del(p);
+ kfree(list_entry(p, struct iwl_ibss_seq, list));
+ }
+ }
+
+ sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+
+ iwl_dealloc_ucode_pci(priv);
+
+ if (priv->rxq.bd)
+ iwl_rx_queue_free(priv, &priv->rxq);
+ iwl_hw_txq_ctx_free(priv);
+
+ iwl_unset_hw_setting(priv);
+ iwl_clear_stations_table(priv);
+
+ if (priv->mac80211_registered) {
+ ieee80211_unregister_hw(priv->hw);
+ iwl_rate_control_unregister(priv->hw);
+ }
+
+ /*netif_stop_queue(dev); */
+ flush_workqueue(priv->workqueue);
+
+ /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes
+ * priv->workqueue... so we can't take down the workqueue
+ * until now... */
+ destroy_workqueue(priv->workqueue);
+ priv->workqueue = NULL;
+
+ free_irq(pdev->irq, priv);
+ pci_disable_msi(pdev);
+ pci_iounmap(pdev, priv->hw_base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ kfree(priv->channel_info);
+
+ kfree(priv->ieee_channels);
+ kfree(priv->ieee_rates);
+
+ if (priv->ibss_beacon)
+ dev_kfree_skb(priv->ibss_beacon);
+
+ ieee80211_free_hw(priv->hw);
+}
+
+#ifdef CONFIG_PM
+
+static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+
+ mutex_lock(&priv->mutex);
+
+ set_bit(STATUS_IN_SUSPEND, &priv->status);
+
+ /* Take down the device; powers it off, etc. */
+ __iwl_down(priv);
+
+ if (priv->mac80211_registered)
+ ieee80211_stop_queues(priv->hw);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void iwl_resume(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ /* The following it a temporary work around due to the
+ * suspend / resume not fully initializing the NIC correctly.
+ * Without all of the following, resume will not attempt to take
+ * down the NIC (it shouldn't really need to) and will just try
+ * and bring the NIC back up. However that fails during the
+ * ucode verification process. This then causes iwl_down to be
+ * called *after* iwl_hw_nic_init() has succeeded -- which
+ * then lets the next init sequence succeed. So, we've
+ * replicated all of that NIC init code here... */
+
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+ iwl_hw_nic_init(priv);
+
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ /* tell the device to stop sending interrupts */
+ iwl_disable_interrupts(priv);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+ if (!iwl_grab_restricted_access(priv)) {
+ iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+ APMG_CLK_VAL_DMA_CLK_RQT);
+ iwl_release_restricted_access(priv);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ udelay(5);
+
+ iwl_hw_nic_reset(priv);
+
+ /* Bring the device back up */
+ clear_bit(STATUS_IN_SUSPEND, &priv->status);
+ queue_work(priv->workqueue, &priv->up);
+}
+
+static int iwl_pci_resume(struct pci_dev *pdev)
+{
+ struct iwl_priv *priv = pci_get_drvdata(pdev);
+ int err;
+
+ printk(KERN_INFO "Coming out of suspend...\n");
+
+ mutex_lock(&priv->mutex);
+
+ pci_set_power_state(pdev, PCI_D0);
+ err = pci_enable_device(pdev);
+ pci_restore_state(pdev);
+
+ /*
+ * Suspend/Resume resets the PCI configuration space, so we have to
+ * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+ * from interfering with C3 CPU state. pci_restore_state won't help
+ * here since it only restores the first 64 bytes pci config header.
+ */
+ pci_write_config_byte(pdev, 0x41, 0x00);
+
+ iwl_resume(priv);
+ mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+/*****************************************************************************
+ *
+ * driver and module entry point
+ *
+ *****************************************************************************/
+
+static struct pci_driver iwl_driver = {
+ .name = DRV_NAME,
+ .id_table = iwl_hw_card_ids,
+ .probe = iwl_pci_probe,
+ .remove = __devexit_p(iwl_pci_remove),
+#ifdef CONFIG_PM
+ .suspend = iwl_pci_suspend,
+ .resume = iwl_pci_resume,
+#endif
+};
+
+static int __init iwl_init(void)
+{
+
+ int ret;
+ printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
+ printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+ ret = pci_register_driver(&iwl_driver);
+ if (ret) {
+ IWL_ERROR("Unable to initialize PCI module\n");
+ return ret;
+ }
+#ifdef CONFIG_IWLWIFI_DEBUG
+ ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
+ if (ret) {
+ IWL_ERROR("Unable to create driver sysfs file\n");
+ pci_unregister_driver(&iwl_driver);
+ return ret;
+ }
+#endif
+
+ return ret;
+}
+
+static void __exit iwl_exit(void)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+ driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
+#endif
+ pci_unregister_driver(&iwl_driver);
+}
+
+module_param_named(antenna, iwl_param_antenna, int, 0444);
+MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
+module_param_named(disable, iwl_param_disable, int, 0444);
+MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
+module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444);
+MODULE_PARM_DESC(hwcrypto,
+ "using hardware crypto engine (default 0 [software])\n");
+module_param_named(debug, iwl_param_debug, int, 0444);
+MODULE_PARM_DESC(debug, "debug output mask");
+module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444);
+MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+
+module_param_named(queues_num, iwl_param_queues_num, int, 0444);
+MODULE_PARM_DESC(queues_num, "number of hw queues.");
+
+/* QoS */
+module_param_named(qos_enable, iwl_param_qos_enable, int, 0444);
+MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
+
+module_exit(iwl_exit);
+module_init(iwl_init);
diff --git a/drivers/net/wireless/iwlwifi/iwlwifi.h b/drivers/net/wireless/iwlwifi/iwlwifi.h
new file mode 100644
index 00000000000..432ce887807
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwlwifi.h
@@ -0,0 +1,708 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwlwifi_h__
+#define __iwlwifi_h__
+
+#include <linux/pci.h> /* for struct pci_device_id */
+#include <linux/kernel.h>
+#include <net/ieee80211_radiotap.h>
+
+struct iwl_priv;
+
+/* Hardware specific file defines the PCI IDs table for that hardware module */
+extern struct pci_device_id iwl_hw_card_ids[];
+
+#include "iwl-hw.h"
+#if IWL == 3945
+#define DRV_NAME "iwl3945"
+#include "iwl-3945-hw.h"
+#elif IWL == 4965
+#define DRV_NAME "iwl4965"
+#include "iwl-4965-hw.h"
+#endif
+
+#include "iwl-prph.h"
+
+/*
+ * Driver implementation data structures, constants, inline
+ * functions
+ *
+ * NOTE: DO NOT PUT HARDWARE/UCODE SPECIFIC DECLRATIONS HERE
+ *
+ * Hardware specific declrations go into iwl-*hw.h
+ *
+ */
+
+#include "iwl-debug.h"
+
+/* Default noise level to report when noise measurement is not available.
+ * This may be because we're:
+ * 1) Not associated (4965, no beacon statistics being sent to driver)
+ * 2) Scanning (noise measurement does not apply to associated channel)
+ * 3) Receiving CCK (3945 delivers noise info only for OFDM frames)
+ * Use default noise value of -127 ... this is below the range of measurable
+ * Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user.
+ * Also, -127 works better than 0 when averaging frames with/without
+ * noise info (e.g. averaging might be done in app); measured dBm values are
+ * always negative ... using a negative value as the default keeps all
+ * averages within an s8's (used in some apps) range of negative values. */
+#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
+
+/* Module parameters accessible from iwl-*.c */
+extern int iwl_param_disable_hw_scan;
+extern int iwl_param_debug;
+extern int iwl_param_mode;
+extern int iwl_param_disable;
+extern int iwl_param_antenna;
+extern int iwl_param_hwcrypto;
+extern int iwl_param_qos_enable;
+extern int iwl_param_queues_num;
+
+enum iwl_antenna {
+ IWL_ANTENNA_DIVERSITY,
+ IWL_ANTENNA_MAIN,
+ IWL_ANTENNA_AUX
+};
+
+/*
+ * RTS threshold here is total size [2347] minus 4 FCS bytes
+ * Per spec:
+ * a value of 0 means RTS on all data/management packets
+ * a value > max MSDU size means no RTS
+ * else RTS for data/management frames where MPDU is larger
+ * than RTS value.
+ */
+#define DEFAULT_RTS_THRESHOLD 2347U
+#define MIN_RTS_THRESHOLD 0U
+#define MAX_RTS_THRESHOLD 2347U
+#define MAX_MSDU_SIZE 2304U
+#define MAX_MPDU_SIZE 2346U
+#define DEFAULT_BEACON_INTERVAL 100U
+#define DEFAULT_SHORT_RETRY_LIMIT 7U
+#define DEFAULT_LONG_RETRY_LIMIT 4U
+
+struct iwl_rx_mem_buffer {
+ dma_addr_t dma_addr;
+ struct sk_buff *skb;
+ struct list_head list;
+};
+
+struct iwl_rt_rx_hdr {
+ struct ieee80211_radiotap_header rt_hdr;
+ __le64 rt_tsf; /* TSF */
+ u8 rt_flags; /* radiotap packet flags */
+ u8 rt_rate; /* rate in 500kb/s */
+ __le16 rt_channelMHz; /* channel in MHz */
+ __le16 rt_chbitmask; /* channel bitfield */
+ s8 rt_dbmsignal; /* signal in dBm, kluged to signed */
+ s8 rt_dbmnoise;
+ u8 rt_antenna; /* antenna number */
+ u8 payload[0]; /* payload... */
+} __attribute__ ((packed));
+
+struct iwl_rt_tx_hdr {
+ struct ieee80211_radiotap_header rt_hdr;
+ u8 rt_rate; /* rate in 500kb/s */
+ __le16 rt_channel; /* channel in mHz */
+ __le16 rt_chbitmask; /* channel bitfield */
+ s8 rt_dbmsignal; /* signal in dBm, kluged to signed */
+ u8 rt_antenna; /* antenna number */
+ u8 payload[0]; /* payload... */
+} __attribute__ ((packed));
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues
+ */
+struct iwl_queue {
+ int n_bd; /* number of BDs in this queue */
+ int first_empty; /* 1-st empty entry (index) host_w*/
+ int last_used; /* last used entry (index) host_r*/
+ dma_addr_t dma_addr; /* physical addr for BD's */
+ int n_window; /* safe queue window */
+ u32 id;
+ int low_mark; /* low watermark, resume queue if free
+ * space more than this */
+ int high_mark; /* high watermark, stop queue if free
+ * space less than this */
+} __attribute__ ((packed));
+
+#define MAX_NUM_OF_TBS (20)
+
+struct iwl_tx_info {
+ struct ieee80211_tx_status status;
+ struct sk_buff *skb[MAX_NUM_OF_TBS];
+};
+
+/**
+ * struct iwl_tx_queue - Tx Queue for DMA
+ * @need_update: need to update read/write index
+ * @shed_retry: queue is HT AGG enabled
+ *
+ * Queue consists of circular buffer of BD's and required locking structures.
+ */
+struct iwl_tx_queue {
+ struct iwl_queue q;
+ struct iwl_tfd_frame *bd;
+ struct iwl_cmd *cmd;
+ dma_addr_t dma_addr_cmd;
+ struct iwl_tx_info *txb;
+ int need_update;
+ int sched_retry;
+ int active;
+};
+
+#include "iwl-channel.h"
+
+#if IWL == 3945
+#include "iwl-3945-rs.h"
+#else
+#include "iwl-4965-rs.h"
+#endif
+
+#define IWL_TX_FIFO_AC0 0
+#define IWL_TX_FIFO_AC1 1
+#define IWL_TX_FIFO_AC2 2
+#define IWL_TX_FIFO_AC3 3
+#define IWL_TX_FIFO_HCCA_1 5
+#define IWL_TX_FIFO_HCCA_2 6
+#define IWL_TX_FIFO_NONE 7
+
+/* Minimum number of queues. MAX_NUM is defined in hw specific files */
+#define IWL_MIN_NUM_QUEUES 4
+
+/* Power management (not Tx power) structures */
+
+struct iwl_power_vec_entry {
+ struct iwl_powertable_cmd cmd;
+ u8 no_dtim;
+};
+#define IWL_POWER_RANGE_0 (0)
+#define IWL_POWER_RANGE_1 (1)
+
+#define IWL_POWER_MODE_CAM 0x00 /* Continuously Aware Mode, always on */
+#define IWL_POWER_INDEX_3 0x03
+#define IWL_POWER_INDEX_5 0x05
+#define IWL_POWER_AC 0x06
+#define IWL_POWER_BATTERY 0x07
+#define IWL_POWER_LIMIT 0x07
+#define IWL_POWER_MASK 0x0F
+#define IWL_POWER_ENABLED 0x10
+#define IWL_POWER_LEVEL(x) ((x) & IWL_POWER_MASK)
+
+struct iwl_power_mgr {
+ spinlock_t lock;
+ struct iwl_power_vec_entry pwr_range_0[IWL_POWER_AC];
+ struct iwl_power_vec_entry pwr_range_1[IWL_POWER_AC];
+ u8 active_index;
+ u32 dtim_val;
+};
+
+#define IEEE80211_DATA_LEN 2304
+#define IEEE80211_4ADDR_LEN 30
+#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)
+#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+struct iwl_frame {
+ union {
+ struct ieee80211_hdr frame;
+ struct iwl_tx_beacon_cmd beacon;
+ u8 raw[IEEE80211_FRAME_LEN];
+ u8 cmd[360];
+ } u;
+ struct list_head list;
+};
+
+#define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf)
+#define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8)
+#define SEQ_TO_INDEX(x) (x & 0xff)
+#define INDEX_TO_SEQ(x) (x & 0xff)
+#define SEQ_HUGE_FRAME (0x4000)
+#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000)
+#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
+#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
+#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
+
+enum {
+ /* CMD_SIZE_NORMAL = 0, */
+ CMD_SIZE_HUGE = (1 << 0),
+ /* CMD_SYNC = 0, */
+ CMD_ASYNC = (1 << 1),
+ /* CMD_NO_SKB = 0, */
+ CMD_WANT_SKB = (1 << 2),
+};
+
+struct iwl_cmd;
+struct iwl_priv;
+
+struct iwl_cmd_meta {
+ struct iwl_cmd_meta *source;
+ union {
+ struct sk_buff *skb;
+ int (*callback)(struct iwl_priv *priv,
+ struct iwl_cmd *cmd, struct sk_buff *skb);
+ } __attribute__ ((packed)) u;
+
+ /* The CMD_SIZE_HUGE flag bit indicates that the command
+ * structure is stored at the end of the shared queue memory. */
+ u32 flags;
+
+} __attribute__ ((packed));
+
+struct iwl_cmd {
+ struct iwl_cmd_meta meta;
+ struct iwl_cmd_header hdr;
+ union {
+ struct iwl_addsta_cmd addsta;
+ struct iwl_led_cmd led;
+ u32 flags;
+ u8 val8;
+ u16 val16;
+ u32 val32;
+ struct iwl_bt_cmd bt;
+ struct iwl_rxon_time_cmd rxon_time;
+ struct iwl_powertable_cmd powertable;
+ struct iwl_qosparam_cmd qosparam;
+ struct iwl_tx_cmd tx;
+ struct iwl_tx_beacon_cmd tx_beacon;
+ struct iwl_rxon_assoc_cmd rxon_assoc;
+ u8 *indirect;
+ u8 payload[360];
+ } __attribute__ ((packed)) cmd;
+} __attribute__ ((packed));
+
+struct iwl_host_cmd {
+ u8 id;
+ u16 len;
+ struct iwl_cmd_meta meta;
+ const void *data;
+};
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
+ sizeof(struct iwl_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
+
+/**
+ * struct iwl_rx_queue - Rx queue
+ * @processed: Internal index to last handled Rx packet
+ * @read: Shared index to newest available Rx buffer
+ * @write: Shared index to oldest written Rx packet
+ * @free_count: Number of pre-allocated buffers in rx_free
+ * @rx_free: list of free SKBs for use
+ * @rx_used: List of Rx buffers with no SKB
+ * @need_update: flag to indicate we need to update read/write index
+ *
+ * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
+ */
+struct iwl_rx_queue {
+ __le32 *bd;
+ dma_addr_t dma_addr;
+ struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+ struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+ u32 processed;
+ u32 read;
+ u32 write;
+ u32 free_count;
+ struct list_head rx_free;
+ struct list_head rx_used;
+ int need_update;
+ spinlock_t lock;
+};
+
+#define IWL_SUPPORTED_RATES_IE_LEN 8
+
+#define SCAN_INTERVAL 100
+
+#define MAX_A_CHANNELS 252
+#define MIN_A_CHANNELS 7
+
+#define MAX_B_CHANNELS 14
+#define MIN_B_CHANNELS 1
+
+#define STATUS_HCMD_ACTIVE 0 /* host command in progress */
+#define STATUS_INT_ENABLED 1
+#define STATUS_RF_KILL_HW 2
+#define STATUS_RF_KILL_SW 3
+#define STATUS_INIT 4
+#define STATUS_ALIVE 5
+#define STATUS_READY 6
+#define STATUS_TEMPERATURE 7
+#define STATUS_GEO_CONFIGURED 8
+#define STATUS_EXIT_PENDING 9
+#define STATUS_IN_SUSPEND 10
+#define STATUS_STATISTICS 11
+#define STATUS_SCANNING 12
+#define STATUS_SCAN_ABORTING 13
+#define STATUS_SCAN_HW 14
+#define STATUS_POWER_PMI 15
+#define STATUS_FW_ERROR 16
+
+#define MAX_TID_COUNT 9
+
+#define IWL_INVALID_RATE 0xFF
+#define IWL_INVALID_VALUE -1
+
+#if IWL == 4965
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+struct iwl_ht_agg {
+ u16 txq_id;
+ u16 frame_count;
+ u16 wait_for_ba;
+ u16 start_idx;
+ u32 bitmap0;
+ u32 bitmap1;
+ u32 rate_n_flags;
+};
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+#endif
+
+struct iwl_tid_data {
+ u16 seq_number;
+#if IWL == 4965
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+ struct iwl_ht_agg agg;
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+#endif
+};
+
+struct iwl_hw_key {
+ enum ieee80211_key_alg alg;
+ int keylen;
+ u8 key[32];
+};
+
+union iwl_ht_rate_supp {
+ u16 rates;
+ struct {
+ u8 siso_rate;
+ u8 mimo_rate;
+ };
+};
+
+#ifdef CONFIG_IWLWIFI_HT
+#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3)
+#define HT_IE_MAX_AMSDU_SIZE_4K (0)
+#define CFG_HT_MPDU_DENSITY_2USEC (0x5)
+#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
+
+struct sta_ht_info {
+ u8 is_ht;
+ u16 rx_mimo_ps_mode;
+ u16 tx_mimo_ps_mode;
+ u16 control_channel;
+ u8 max_amsdu_size;
+ u8 ampdu_factor;
+ u8 mpdu_density;
+ u8 operating_mode;
+ u8 supported_chan_width;
+ u8 extension_chan_offset;
+ u8 is_green_field;
+ u8 sgf;
+ u8 supp_rates[16];
+ u8 tx_chan_width;
+ u8 chan_width_cap;
+};
+#endif /*CONFIG_IWLWIFI_HT */
+
+#ifdef CONFIG_IWLWIFI_QOS
+
+union iwl_qos_capabity {
+ struct {
+ u8 edca_count:4; /* bit 0-3 */
+ u8 q_ack:1; /* bit 4 */
+ u8 queue_request:1; /* bit 5 */
+ u8 txop_request:1; /* bit 6 */
+ u8 reserved:1; /* bit 7 */
+ } q_AP;
+ struct {
+ u8 acvo_APSD:1; /* bit 0 */
+ u8 acvi_APSD:1; /* bit 1 */
+ u8 ac_bk_APSD:1; /* bit 2 */
+ u8 ac_be_APSD:1; /* bit 3 */
+ u8 q_ack:1; /* bit 4 */
+ u8 max_len:2; /* bit 5-6 */
+ u8 more_data_ack:1; /* bit 7 */
+ } q_STA;
+ u8 val;
+};
+
+/* QoS sturctures */
+struct iwl_qos_info {
+ int qos_enable;
+ int qos_active;
+ union iwl_qos_capabity qos_cap;
+ struct iwl_qosparam_cmd def_qos_parm;
+};
+#endif /*CONFIG_IWLWIFI_QOS */
+
+#define STA_PS_STATUS_WAKE 0
+#define STA_PS_STATUS_SLEEP 1
+
+struct iwl_station_entry {
+ struct iwl_addsta_cmd sta;
+ struct iwl_tid_data tid[MAX_TID_COUNT];
+#if IWL == 3945
+ union {
+ struct {
+ u8 rate;
+ u8 flags;
+ } s;
+ u16 rate_n_flags;
+ } current_rate;
+#endif
+ u8 used;
+ u8 ps_status;
+ struct iwl_hw_key keyinfo;
+};
+
+/* one for each uCode image (inst/data, boot/init/runtime) */
+struct fw_image_desc {
+ void *v_addr; /* access by driver */
+ dma_addr_t p_addr; /* access by card's busmaster DMA */
+ u32 len; /* bytes */
+};
+
+/* uCode file layout */
+struct iwl_ucode {
+ __le32 ver; /* major/minor/subminor */
+ __le32 inst_size; /* bytes of runtime instructions */
+ __le32 data_size; /* bytes of runtime data */
+ __le32 init_size; /* bytes of initialization instructions */
+ __le32 init_data_size; /* bytes of initialization data */
+ __le32 boot_size; /* bytes of bootstrap instructions */
+ u8 data[0]; /* data in same order as "size" elements */
+};
+
+#define IWL_IBSS_MAC_HASH_SIZE 32
+
+struct iwl_ibss_seq {
+ u8 mac[ETH_ALEN];
+ u16 seq_num;
+ u16 frag_num;
+ unsigned long packet_time;
+ struct list_head list;
+};
+
+struct iwl_driver_hw_info {
+ u16 max_txq_num;
+ u16 ac_queue_count;
+ u32 rx_buffer_size;
+ u16 tx_cmd_len;
+ u16 max_rxq_size;
+ u16 max_rxq_log;
+ u32 cck_flag;
+ u8 max_stations;
+ u8 bcast_sta_id;
+ void *shared_virt;
+ dma_addr_t shared_phys;
+};
+
+
+#define STA_FLG_RTS_MIMO_PROT_MSK __constant_cpu_to_le32(1 << 17)
+#define STA_FLG_AGG_MPDU_8US_MSK __constant_cpu_to_le32(1 << 18)
+#define STA_FLG_MAX_AGG_SIZE_POS (19)
+#define STA_FLG_MAX_AGG_SIZE_MSK __constant_cpu_to_le32(3 << 19)
+#define STA_FLG_FAT_EN_MSK __constant_cpu_to_le32(1 << 21)
+#define STA_FLG_MIMO_DIS_MSK __constant_cpu_to_le32(1 << 22)
+#define STA_FLG_AGG_MPDU_DENSITY_POS (23)
+#define STA_FLG_AGG_MPDU_DENSITY_MSK __constant_cpu_to_le32(7 << 23)
+#define HT_SHORT_GI_20MHZ_ONLY (1 << 0)
+#define HT_SHORT_GI_40MHZ_ONLY (1 << 1)
+
+
+#include "iwl-priv.h"
+
+/* Requires full declaration of iwl_priv before including */
+#include "iwl-io.h"
+
+#define IWL_RX_HDR(x) ((struct iwl_rx_frame_hdr *)(\
+ x->u.rx_frame.stats.payload + \
+ x->u.rx_frame.stats.phy_count))
+#define IWL_RX_END(x) ((struct iwl_rx_frame_end *)(\
+ IWL_RX_HDR(x)->payload + \
+ le16_to_cpu(IWL_RX_HDR(x)->len)))
+#define IWL_RX_STATS(x) (&x->u.rx_frame.stats)
+#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload)
+
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-base.c which are forward declared here
+ * for use by iwl-*.c
+ *
+ *****************************************************************************/
+struct iwl_addsta_cmd;
+extern int iwl_send_add_station(struct iwl_priv *priv,
+ struct iwl_addsta_cmd *sta, u8 flags);
+extern const char *iwl_get_tx_fail_reason(u32 status);
+extern u8 iwl_add_station(struct iwl_priv *priv, const u8 *bssid,
+ int is_ap, u8 flags);
+extern int iwl_is_network_packet(struct iwl_priv *priv,
+ struct ieee80211_hdr *header);
+extern int iwl_power_init_handle(struct iwl_priv *priv);
+extern int iwl_eeprom_init(struct iwl_priv *priv);
+#ifdef CONFIG_IWLWIFI_DEBUG
+extern void iwl_report_frame(struct iwl_priv *priv,
+ struct iwl_rx_packet *pkt,
+ struct ieee80211_hdr *header, int group100);
+#else
+static inline void iwl_report_frame(struct iwl_priv *priv,
+ struct iwl_rx_packet *pkt,
+ struct ieee80211_hdr *header,
+ int group100) {}
+#endif
+extern int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq);
+extern void iwl_handle_data_packet_monitor(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb,
+ void *data, short len,
+ struct ieee80211_rx_status *stats,
+ u16 phy_flags);
+extern int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr
+ *header);
+extern void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+extern int iwl_rx_queue_alloc(struct iwl_priv *priv);
+extern void iwl_rx_queue_reset(struct iwl_priv *priv,
+ struct iwl_rx_queue *rxq);
+extern int iwl_calc_db_from_ratio(int sig_ratio);
+extern int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm);
+extern int iwl_tx_queue_init(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq, int count, u32 id);
+extern int iwl_rx_queue_restock(struct iwl_priv *priv);
+extern void iwl_rx_replenish(void *data);
+extern void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+extern int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len,
+ const void *data);
+extern int __must_check iwl_send_cmd_async(struct iwl_priv *priv,
+ struct iwl_host_cmd *cmd);
+extern int __must_check iwl_send_cmd_sync(struct iwl_priv *priv,
+ struct iwl_host_cmd *cmd);
+extern int __must_check iwl_send_cmd(struct iwl_priv *priv,
+ struct iwl_host_cmd *cmd);
+extern unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+ struct ieee80211_hdr *hdr,
+ const u8 *dest, int left);
+extern int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
+ struct iwl_rx_queue *q);
+extern int iwl_send_statistics_request(struct iwl_priv *priv);
+extern void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
+ u32 decrypt_res,
+ struct ieee80211_rx_status *stats);
+extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr);
+
+extern const u8 BROADCAST_ADDR[ETH_ALEN];
+
+/*
+ * Currently used by iwl-3945-rs... look at restructuring so that it doesn't
+ * call this... todo... fix that.
+*/
+extern u8 iwl_sync_station(struct iwl_priv *priv, int sta_id,
+ u16 tx_rate, u8 flags);
+
+static inline int iwl_is_associated(struct iwl_priv *priv)
+{
+ return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-[34]*.c which are forward declared here
+ * for use by iwl-base.c
+ *
+ * NOTE: The implementation of these functions are hardware specific
+ * which is why they are in the hardware specific files (vs. iwl-base.c)
+ *
+ * Naming convention --
+ * iwl_ <-- Its part of iwlwifi (should be changed to iwl_)
+ * iwl_hw_ <-- Hardware specific (implemented in iwl-XXXX.c by all HW)
+ * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
+ * iwl_bg_ <-- Called from work queue context
+ * iwl_mac_ <-- mac80211 callback
+ *
+ ****************************************************************************/
+extern void iwl_hw_rx_handler_setup(struct iwl_priv *priv);
+extern void iwl_hw_setup_deferred_work(struct iwl_priv *priv);
+extern void iwl_hw_cancel_deferred_work(struct iwl_priv *priv);
+extern int iwl_hw_rxq_stop(struct iwl_priv *priv);
+extern int iwl_hw_set_hw_setting(struct iwl_priv *priv);
+extern int iwl_hw_nic_init(struct iwl_priv *priv);
+extern void iwl_hw_card_show_info(struct iwl_priv *priv);
+extern int iwl_hw_nic_stop_master(struct iwl_priv *priv);
+extern void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
+extern void iwl_hw_txq_ctx_stop(struct iwl_priv *priv);
+extern int iwl_hw_nic_reset(struct iwl_priv *priv);
+extern int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
+ dma_addr_t addr, u16 len);
+extern int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+extern int iwl_hw_get_temperature(struct iwl_priv *priv);
+extern int iwl_hw_tx_queue_init(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq);
+extern unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
+ struct iwl_frame *frame, u8 rate);
+extern int iwl_hw_get_rx_read(struct iwl_priv *priv);
+extern void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+ struct iwl_cmd *cmd,
+ struct ieee80211_tx_control *ctrl,
+ struct ieee80211_hdr *hdr,
+ int sta_id, int tx_id);
+extern int iwl_hw_reg_send_txpower(struct iwl_priv *priv);
+extern int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
+extern void iwl_hw_rx_statistics(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb);
+extern void iwl_disable_events(struct iwl_priv *priv);
+extern int iwl4965_get_temperature(const struct iwl_priv *priv);
+
+/**
+ * iwl_hw_find_station - Find station id for a given BSSID
+ * @bssid: MAC address of station ID to find
+ *
+ * NOTE: This should not be hardware specific but the code has
+ * not yet been merged into a single common layer for managing the
+ * station tables.
+ */
+extern u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
+
+extern int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel);
+extern int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
+#endif
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
index 4cf0ff7b833..9cf0211de67 100644
--- a/drivers/net/wireless/libertas/11d.c
+++ b/drivers/net/wireless/libertas/11d.c
@@ -124,17 +124,17 @@ static u8 wlan_channel_known_11d(u8 chan,
u8 nr_chan = parsed_region_chan->nr_chan;
u8 i = 0;
- lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr,
+ lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr,
sizeof(struct chan_power_11d) * nr_chan);
for (i = 0; i < nr_chan; i++) {
if (chan == chanpwr[i].chan) {
- lbs_deb_11d("11D: Found Chan:%d\n", chan);
+ lbs_deb_11d("found chan %d\n", chan);
return 1;
}
}
- lbs_deb_11d("11D: Not Find Chan:%d\n", chan);
+ lbs_deb_11d("chan %d not found\n", chan);
return 0;
}
@@ -174,8 +174,8 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d
memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
COUNTRY_CODE_LEN);
- lbs_deb_11d("11D:nrchan=%d\n", nr_chan);
- lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan,
+ lbs_deb_11d("nrchan %d\n", nr_chan);
+ lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan,
sizeof(struct parsed_region_chan_11d));
for (i = 0; i < nr_chan; i++) {
@@ -213,7 +213,7 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d
domaininfo->nr_subband = nr_subband;
lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
- lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo,
+ lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
COUNTRY_CODE_LEN + 1 +
sizeof(struct ieeetypes_subbandset) * nr_subband);
return 0;
@@ -233,13 +233,13 @@ static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_
struct chan_freq_power *cfp;
if (region_chan == NULL) {
- lbs_deb_11d("11D: region_chan is NULL\n");
+ lbs_deb_11d("region_chan is NULL\n");
return;
}
cfp = region_chan->CFP;
if (cfp == NULL) {
- lbs_deb_11d("11D: cfp equal NULL \n");
+ lbs_deb_11d("cfp is NULL \n");
return;
}
@@ -248,19 +248,19 @@ static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_
memcpy(parsed_region_chan->countrycode,
wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
- lbs_deb_11d("11D: region[0x%x] band[%d]\n", parsed_region_chan->region,
+ lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region,
parsed_region_chan->band);
for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
parsed_region_chan->chanpwr[i].chan = cfp->channel;
parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
- lbs_deb_11d("11D: Chan[%d] Pwr[%d]\n",
+ lbs_deb_11d("chan %d, pwr %d\n",
parsed_region_chan->chanpwr[i].chan,
parsed_region_chan->chanpwr[i].pwr);
}
parsed_region_chan->nr_chan = region_chan->nrcfp;
- lbs_deb_11d("11D: nrchan[%d]\n", parsed_region_chan->nr_chan);
+ lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan);
return;
}
@@ -336,7 +336,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
6. Others
*/
- lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30);
+ lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
if ((*(countryinfo->countrycode)) == 0
|| (countryinfo->len <= COUNTRY_CODE_LEN)) {
@@ -349,7 +349,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
wlan_region_2_code(countryinfo->countrycode);
lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
- lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode,
+ lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
COUNTRY_CODE_LEN);
parsed_region_chan->band = band;
@@ -364,7 +364,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
if (countryinfo->subband[j].firstchan <= lastchan) {
/*Step2&3. Check First Chan Num increment and no overlap */
- lbs_deb_11d("11D: Chan[%d>%d] Overlap\n",
+ lbs_deb_11d("chan %d>%d, overlap\n",
countryinfo->subband[j].firstchan, lastchan);
continue;
}
@@ -393,7 +393,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
} else {
/*not supported and ignore the chan */
lbs_deb_11d(
- "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n",
+ "i %d, chan %d unsupported in region %x, band %d\n",
i, curchan, region, band);
}
}
@@ -405,7 +405,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
parsed_region_chan->nr_chan = idx;
lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
- lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan,
+ lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
done:
@@ -422,15 +422,15 @@ done:
u8 libertas_get_scan_type_11d(u8 chan,
struct parsed_region_chan_11d * parsed_region_chan)
{
- u8 scan_type = cmd_scan_type_passive;
+ u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
lbs_deb_enter(LBS_DEB_11D);
if (wlan_channel_known_11d(chan, parsed_region_chan)) {
- lbs_deb_11d("11D: Found and do Active Scan\n");
- scan_type = cmd_scan_type_active;
+ lbs_deb_11d("found, do active scan\n");
+ scan_type = CMD_SCAN_TYPE_ACTIVE;
} else {
- lbs_deb_11d("11D: Not Find and do Passive Scan\n");
+ lbs_deb_11d("not found, do passive scan\n");
}
lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
@@ -446,25 +446,6 @@ void libertas_init_11d(wlan_private * priv)
return;
}
-static int wlan_enable_11d(wlan_private * priv, u8 flag)
-{
- int ret;
-
- priv->adapter->enable11d = flag;
-
- /* send cmd to FW to enable/disable 11D function in FW */
- ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_snmp_mib,
- cmd_act_set,
- cmd_option_waitforrsp,
- OID_802_11D_ENABLE,
- &priv->adapter->enable11d);
- if (ret)
- lbs_deb_11d("11D: Fail to enable 11D \n");
-
- return 0;
-}
-
/**
* @brief This function sets DOMAIN INFO to FW
* @param priv pointer to wlan_private
@@ -475,15 +456,15 @@ static int set_domain_info_11d(wlan_private * priv)
int ret;
if (!priv->adapter->enable11d) {
- lbs_deb_11d("11D: dnld domain Info with 11d disabled\n");
+ lbs_deb_11d("dnld domain Info with 11d disabled\n");
return 0;
}
- ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info,
- cmd_act_set,
- cmd_option_waitforrsp, 0, NULL);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
if (ret)
- lbs_deb_11d("11D: Fail to dnld domain Info\n");
+ lbs_deb_11d("fail to dnld domain info\n");
return ret;
}
@@ -505,7 +486,7 @@ int libertas_set_universaltable(wlan_private * priv, u8 band)
adapter->universal_channel[i].nrcfp =
sizeof(channel_freq_power_UN_BG) / size;
- lbs_deb_11d("11D: BG-band nrcfp=%d\n",
+ lbs_deb_11d("BG-band nrcfp %d\n",
adapter->universal_channel[i].nrcfp);
adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
@@ -541,10 +522,10 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv,
cmd->command = cpu_to_le16(cmdno);
pdomaininfo->action = cpu_to_le16(cmdoption);
- if (cmdoption == cmd_act_get) {
+ if (cmdoption == CMD_ACT_GET) {
cmd->size =
cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
- lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd,
+ lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
(int)(cmd->size));
goto done;
}
@@ -562,7 +543,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv,
nr_subband * sizeof(struct ieeetypes_subbandset));
cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
- domain->header.len +
+ le16_to_cpu(domain->header.len) +
sizeof(struct mrvlietypesheader) +
S_DS_GEN);
} else {
@@ -570,7 +551,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv,
cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
}
- lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, le16_to_cpu(cmd->size));
+ lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
done:
lbs_deb_enter(LBS_DEB_11D);
@@ -578,31 +559,6 @@ done:
}
/**
- * @brief This function implements private cmd: enable/disable 11D
- * @param priv pointer to wlan_private
- * @param wrq pointer to user data
- * @return 0 or -1
- */
-int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
-{
- int data = 0;
- int *val;
-
- lbs_deb_enter(LBS_DEB_11D);
- data = SUBCMD_DATA(wrq);
-
- lbs_deb_11d("enable 11D: %s\n",
- (data == 1) ? "enable" : "Disable");
-
- wlan_enable_11d(priv, data);
- val = (int *)wrq->u.name;
- *val = priv->adapter->enable11d;
-
- lbs_deb_enter(LBS_DEB_11D);
- return 0;
-}
-
-/**
* @brief This function parses countryinfo from AP and download country info to FW
* @param priv pointer to wlan_private
* @param resp pointer to command response buffer
@@ -619,13 +575,13 @@ int libertas_ret_802_11d_domain_info(wlan_private * priv,
lbs_deb_enter(LBS_DEB_11D);
- lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp,
+ lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
(int)le16_to_cpu(resp->size));
nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
sizeof(struct ieeetypes_subbandset);
- lbs_deb_11d("11D Domain Info Resp: nr_subband=%d\n", nr_subband);
+ lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
@@ -633,10 +589,10 @@ int libertas_ret_802_11d_domain_info(wlan_private * priv,
}
switch (action) {
- case cmd_act_set: /*Proc Set action */
+ case CMD_ACT_SET: /*Proc Set action */
break;
- case cmd_act_get:
+ case CMD_ACT_GET:
break;
default:
lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
@@ -667,7 +623,7 @@ int libertas_parse_dnld_countryinfo_11d(wlan_private * priv,
&adapter->parsed_region_chan);
if (ret == -1) {
- lbs_deb_11d("11D: Err Parse domain_info from AP..\n");
+ lbs_deb_11d("error parsing domain_info from AP\n");
goto done;
}
@@ -679,7 +635,7 @@ int libertas_parse_dnld_countryinfo_11d(wlan_private * priv,
ret = set_domain_info_11d(priv);
if (ret) {
- lbs_deb_11d("11D: Err set domainInfo to FW\n");
+ lbs_deb_11d("error setting domain info\n");
goto done;
}
}
@@ -703,7 +659,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
u8 j;
lbs_deb_enter(LBS_DEB_11D);
- lbs_deb_11d("11D:curbssparams.band[%d]\n", adapter->curbssparams.band);
+ lbs_deb_11d("curbssparams.band %d\n", adapter->curbssparams.band);
if (priv->adapter->enable11d) {
/* update parsed_region_chan_11; dnld domaininf to FW */
@@ -712,7 +668,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
sizeof(adapter->region_channel[0]); j++) {
region_chan = &adapter->region_channel[j];
- lbs_deb_11d("11D:[%d] region_chan->band[%d]\n", j,
+ lbs_deb_11d("%d region_chan->band %d\n", j,
region_chan->band);
if (!region_chan || !region_chan->valid
@@ -725,7 +681,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
if (j >= sizeof(adapter->region_channel) /
sizeof(adapter->region_channel[0])) {
- lbs_deb_11d("11D:region_chan not found. band[%d]\n",
+ lbs_deb_11d("region_chan not found, band %d\n",
adapter->curbssparams.band);
ret = -1;
goto done;
@@ -745,7 +701,7 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
ret = set_domain_info_11d(priv);
if (ret) {
- lbs_deb_11d("11D: Err set domainInfo to FW\n");
+ lbs_deb_11d("error setting domain info\n");
goto done;
}
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h
index 73e42e71291..3a6d1f8db78 100644
--- a/drivers/net/wireless/libertas/11d.h
+++ b/drivers/net/wireless/libertas/11d.h
@@ -83,8 +83,6 @@ u8 libertas_get_scan_type_11d(u8 chan,
u32 libertas_chan_2_freq(u8 chan, u8 band);
-enum state_11d libertas_get_state_11d(wlan_private * priv);
-
void libertas_init_11d(wlan_private * priv);
int libertas_set_universaltable(wlan_private * priv, u8 band);
@@ -93,8 +91,6 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv,
struct cmd_ds_command *cmd, u16 cmdno,
u16 cmdOption);
-int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq);
-
int libertas_ret_802_11d_domain_info(wlan_private * priv,
struct cmd_ds_command *resp);
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index 32ed4136b0d..0e2787691f9 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -1,12 +1,15 @@
-libertas-objs := main.o fw.o wext.o \
+libertas-objs := main.o wext.o \
rx.o tx.o cmd.o \
cmdresp.o scan.o \
join.o 11d.o \
debugfs.o \
ethtool.o assoc.o
-usb8xxx-objs += if_bootcmd.o
usb8xxx-objs += if_usb.o
+libertas_cs-objs += if_cs.o
+libertas_sdio-objs += if_sdio.o
obj-$(CONFIG_LIBERTAS) += libertas.o
obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
+obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o
+obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index afd5617dd92..b61b176e9d0 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -16,6 +16,7 @@ static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static void print_assoc_req(const char * extra, struct assoc_request * assoc_req)
{
+ DECLARE_MAC_BUF(mac);
lbs_deb_assoc(
"#### Association Request: %s\n"
" flags: 0x%08lX\n"
@@ -23,13 +24,13 @@ static void print_assoc_req(const char * extra, struct assoc_request * assoc_req
" channel: %d\n"
" band: %d\n"
" mode: %d\n"
- " BSSID: " MAC_FMT "\n"
+ " BSSID: %s\n"
" Encryption:%s%s%s\n"
" auth: %d\n",
extra, assoc_req->flags,
escape_essid(assoc_req->ssid, assoc_req->ssid_len),
assoc_req->channel, assoc_req->band, assoc_req->mode,
- MAC_ARG(assoc_req->bssid),
+ print_mac(mac, assoc_req->bssid),
assoc_req->secinfo.WPAenabled ? " WPA" : "",
assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
assoc_req->secinfo.wep_enabled ? " WEP" : "",
@@ -57,10 +58,8 @@ static int assoc_helper_essid(wlan_private *priv,
lbs_deb_assoc("New SSID requested: '%s'\n",
escape_essid(assoc_req->ssid, assoc_req->ssid_len));
if (assoc_req->mode == IW_MODE_INFRA) {
- if (adapter->prescan) {
- libertas_send_specific_ssid_scan(priv, assoc_req->ssid,
- assoc_req->ssid_len, 0);
- }
+ libertas_send_specific_ssid_scan(priv, assoc_req->ssid,
+ assoc_req->ssid_len, 0);
bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid,
assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
@@ -106,16 +105,17 @@ static int assoc_helper_bssid(wlan_private *priv,
wlan_adapter *adapter = priv->adapter;
int ret = 0;
struct bss_descriptor * bss;
+ DECLARE_MAC_BUF(mac);
- lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID " MAC_FMT,
- MAC_ARG(assoc_req->bssid));
+ lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s",
+ print_mac(mac, assoc_req->bssid));
/* Search for index position in list for requested MAC */
bss = libertas_find_bssid_in_list(adapter, assoc_req->bssid,
assoc_req->mode);
if (bss == NULL) {
- lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, "
- "cannot associate.\n", MAC_ARG(assoc_req->bssid));
+ lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, "
+ "cannot associate.\n", print_mac(mac, assoc_req->bssid));
goto out;
}
@@ -175,14 +175,14 @@ static int assoc_helper_mode(wlan_private *priv,
if (assoc_req->mode == IW_MODE_INFRA) {
if (adapter->psstate != PS_STATE_FULL_POWER)
- libertas_ps_wakeup(priv, cmd_option_waitforrsp);
- adapter->psmode = wlan802_11powermodecam;
+ libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
+ adapter->psmode = WLAN802_11POWERMODECAM;
}
adapter->mode = assoc_req->mode;
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_snmp_mib,
- 0, cmd_option_waitforrsp,
+ CMD_802_11_SNMP_MIB,
+ 0, CMD_OPTION_WAITFORRSP,
OID_802_11_INFRASTRUCTURE_MODE,
/* Shoot me now */ (void *) (size_t) assoc_req->mode);
@@ -195,9 +195,9 @@ done:
static int update_channel(wlan_private * priv)
{
/* the channel in f/w could be out of sync, get the current channel */
- return libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
- cmd_opt_802_11_rf_channel_get,
- cmd_option_waitforrsp, 0, NULL);
+ return libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL,
+ CMD_OPT_802_11_RF_CHANNEL_GET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
}
void libertas_sync_channel(struct work_struct *work)
@@ -227,9 +227,9 @@ static int assoc_helper_channel(wlan_private *priv,
lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
adapter->curbssparams.channel, assoc_req->channel);
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
- cmd_opt_802_11_rf_channel_set,
- cmd_option_waitforrsp, 0, &assoc_req->channel);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL,
+ CMD_OPT_802_11_RF_CHANNEL_SET,
+ CMD_OPTION_WAITFORRSP, 0, &assoc_req->channel);
if (ret < 0) {
lbs_deb_assoc("ASSOC: channel: error setting channel.");
}
@@ -278,15 +278,15 @@ static int assoc_helper_wep_keys(wlan_private *priv,
|| assoc_req->wep_keys[2].len
|| assoc_req->wep_keys[3].len) {
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_set_wep,
- cmd_act_add,
- cmd_option_waitforrsp,
+ CMD_802_11_SET_WEP,
+ CMD_ACT_ADD,
+ CMD_OPTION_WAITFORRSP,
0, assoc_req);
} else {
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_set_wep,
- cmd_act_remove,
- cmd_option_waitforrsp,
+ CMD_802_11_SET_WEP,
+ CMD_ACT_REMOVE,
+ CMD_OPTION_WAITFORRSP,
0, NULL);
}
@@ -295,9 +295,9 @@ static int assoc_helper_wep_keys(wlan_private *priv,
/* enable/disable the MAC's WEP packet filter */
if (assoc_req->secinfo.wep_enabled)
- adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
+ adapter->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE;
else
- adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
+ adapter->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE;
ret = libertas_set_mac_packet_filter(priv);
if (ret)
goto out;
@@ -307,7 +307,7 @@ static int assoc_helper_wep_keys(wlan_private *priv,
/* Copy WEP keys into adapter wep key fields */
for (i = 0; i < 4; i++) {
memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
- sizeof(struct WLAN_802_11_KEY));
+ sizeof(struct enc_key));
}
adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
@@ -342,9 +342,9 @@ static int assoc_helper_secinfo(wlan_private *priv,
/* Get RSN enabled/disabled */
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_enable_rsn,
- cmd_act_set,
- cmd_option_waitforrsp,
+ CMD_802_11_ENABLE_RSN,
+ CMD_ACT_GET,
+ CMD_OPTION_WAITFORRSP,
0, &rsn);
if (ret) {
lbs_deb_assoc("Failed to get RSN status: %d", ret);
@@ -359,9 +359,9 @@ static int assoc_helper_secinfo(wlan_private *priv,
/* Set RSN enabled/disabled */
rsn = do_wpa;
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_enable_rsn,
- cmd_act_set,
- cmd_option_waitforrsp,
+ CMD_802_11_ENABLE_RSN,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP,
0, &rsn);
out:
@@ -374,15 +374,40 @@ static int assoc_helper_wpa_keys(wlan_private *priv,
struct assoc_request * assoc_req)
{
int ret = 0;
+ unsigned int flags = assoc_req->flags;
lbs_deb_enter(LBS_DEB_ASSOC);
- ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_key_material,
- cmd_act_set,
- cmd_option_waitforrsp,
- 0, assoc_req);
+ /* Work around older firmware bug where WPA unicast and multicast
+ * keys must be set independently. Seen in SDIO parts with firmware
+ * version 5.0.11p0.
+ */
+
+ if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+ clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
+ ret = libertas_prepare_and_send_command(priv,
+ CMD_802_11_KEY_MATERIAL,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP,
+ 0, assoc_req);
+ assoc_req->flags = flags;
+ }
+
+ if (ret)
+ goto out;
+ if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
+ clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
+
+ ret = libertas_prepare_and_send_command(priv,
+ CMD_802_11_KEY_MATERIAL,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP,
+ 0, assoc_req);
+ assoc_req->flags = flags;
+ }
+
+out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
return ret;
}
@@ -412,7 +437,7 @@ static int assoc_helper_wpa_ie(wlan_private *priv,
static int should_deauth_infrastructure(wlan_adapter *adapter,
struct assoc_request * assoc_req)
{
- if (adapter->connect_status != libertas_connected)
+ if (adapter->connect_status != LIBERTAS_CONNECTED)
return 0;
if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
@@ -453,7 +478,7 @@ static int should_deauth_infrastructure(wlan_adapter *adapter,
static int should_stop_adhoc(wlan_adapter *adapter,
struct assoc_request * assoc_req)
{
- if (adapter->connect_status != libertas_connected)
+ if (adapter->connect_status != LIBERTAS_CONNECTED)
return 0;
if (libertas_ssid_cmp(adapter->curbssparams.ssid,
@@ -483,6 +508,7 @@ void libertas_association_worker(struct work_struct *work)
struct assoc_request * assoc_req = NULL;
int ret = 0;
int find_any_ssid = 0;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_ASSOC);
@@ -556,7 +582,8 @@ void libertas_association_worker(struct work_struct *work)
if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
ret = assoc_helper_mode(priv, assoc_req);
if (ret) {
-lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
+ lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n",
+ __LINE__, ret);
goto out;
}
}
@@ -574,7 +601,8 @@ lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
|| test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
ret = assoc_helper_wep_keys(priv, assoc_req);
if (ret) {
-lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
+ lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n",
+ __LINE__, ret);
goto out;
}
}
@@ -582,7 +610,8 @@ lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
ret = assoc_helper_secinfo(priv, assoc_req);
if (ret) {
-lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
+ lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n",
+ __LINE__, ret);
goto out;
}
}
@@ -590,7 +619,8 @@ lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
ret = assoc_helper_wpa_ie(priv, assoc_req);
if (ret) {
-lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
+ lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n",
+ __LINE__, ret);
goto out;
}
}
@@ -599,7 +629,8 @@ lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
|| test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
ret = assoc_helper_wpa_keys(priv, assoc_req);
if (ret) {
-lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
+ lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n",
+ __LINE__, ret);
goto out;
}
}
@@ -618,25 +649,25 @@ lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
success = 0;
}
- if (adapter->connect_status != libertas_connected) {
- lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, "
+ if (adapter->connect_status != LIBERTAS_CONNECTED) {
+ lbs_deb_assoc("ASSOC: association attempt unsuccessful, "
"not connected.\n");
success = 0;
}
if (success) {
lbs_deb_assoc("ASSOC: association attempt successful. "
- "Associated to '%s' (" MAC_FMT ")\n",
+ "Associated to '%s' (%s)\n",
escape_essid(adapter->curbssparams.ssid,
adapter->curbssparams.ssid_len),
- MAC_ARG(adapter->curbssparams.bssid));
+ print_mac(mac, adapter->curbssparams.bssid));
libertas_prepare_and_send_command(priv,
- cmd_802_11_rssi,
- 0, cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_RSSI,
+ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
libertas_prepare_and_send_command(priv,
- cmd_802_11_get_log,
- 0, cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_GET_LOG,
+ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
} else {
ret = -1;
}
@@ -703,7 +734,7 @@ struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
int i;
for (i = 0; i < 4; i++) {
memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
- sizeof(struct WLAN_802_11_KEY));
+ sizeof(struct enc_key));
}
}
@@ -712,12 +743,12 @@ struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
- sizeof(struct WLAN_802_11_KEY));
+ sizeof(struct enc_key));
}
if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
- sizeof(struct WLAN_802_11_KEY));
+ sizeof(struct enc_key));
}
if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
index 5e9c31f0932..e09b7490abb 100644
--- a/drivers/net/wireless/libertas/assoc.h
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -17,7 +17,7 @@ static inline void wlan_postpone_association_work(wlan_private *priv)
if (priv->adapter->surpriseremoved)
return;
cancel_delayed_work(&priv->assoc_work);
- queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY);
+ queue_delayed_work(priv->work_thread, &priv->assoc_work, ASSOC_DELAY);
}
static inline void wlan_cancel_association_work(wlan_private *priv)
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 4a8f5dc7023..be5cfd8402c 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -15,7 +15,7 @@
static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
static u16 commands_allowed_in_ps[] = {
- cmd_802_11_rssi,
+ CMD_802_11_RSSI,
};
/**
@@ -43,7 +43,7 @@ static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd)
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_get_hw_spec);
+ cmd->command = cpu_to_le16(CMD_GET_HW_SPEC);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN);
@@ -56,34 +56,29 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv,
u16 cmd_action)
{
struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
- wlan_adapter *adapter = priv->adapter;
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_802_11_ps_mode);
+ cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
S_DS_GEN);
psm->action = cpu_to_le16(cmd_action);
psm->multipledtim = 0;
switch (cmd_action) {
- case cmd_subcmd_enter_ps:
+ case CMD_SUBCMD_ENTER_PS:
lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
- lbs_deb_cmd("locallisteninterval = %d\n",
- adapter->locallisteninterval);
- psm->locallisteninterval =
- cpu_to_le16(adapter->locallisteninterval);
- psm->nullpktinterval =
- cpu_to_le16(adapter->nullpktinterval);
+ psm->locallisteninterval = 0;
+ psm->nullpktinterval = 0;
psm->multipledtim =
- cpu_to_le16(priv->adapter->multipledtim);
+ cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
break;
- case cmd_subcmd_exit_ps:
+ case CMD_SUBCMD_EXIT_PS:
lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
break;
- case cmd_subcmd_sleep_confirmed:
+ case CMD_SUBCMD_SLEEP_CONFIRMED:
lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
break;
@@ -101,7 +96,9 @@ static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
{
u16 *timeout = pdata_buf;
- cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout);
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
+ S_DS_GEN);
@@ -113,6 +110,7 @@ static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
else
cmd->params.inactivity_timeout.timeout = 0;
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -127,13 +125,13 @@ static int wlan_cmd_802_11_sleep_params(wlan_private * priv,
cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
S_DS_GEN);
- cmd->command = cpu_to_le16(cmd_802_11_sleep_params);
+ cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS);
- if (cmd_action == cmd_act_get) {
+ if (cmd_action == CMD_ACT_GET) {
memset(&adapter->sp, 0, sizeof(struct sleep_params));
memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
sp->action = cpu_to_le16(cmd_action);
- } else if (cmd_action == cmd_act_set) {
+ } else if (cmd_action == CMD_ACT_SET) {
sp->action = cpu_to_le16(cmd_action);
sp->error = cpu_to_le16(adapter->sp.sp_error);
sp->offset = cpu_to_le16(adapter->sp.sp_offset);
@@ -159,10 +157,10 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_802_11_set_wep);
+ cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);
- if (cmd_act == cmd_act_add) {
+ if (cmd_act == CMD_ACT_ADD) {
int i;
if (!assoc_req) {
@@ -171,48 +169,47 @@ static int wlan_cmd_802_11_set_wep(wlan_private * priv,
goto done;
}
- wep->action = cpu_to_le16(cmd_act_add);
+ wep->action = cpu_to_le16(CMD_ACT_ADD);
/* default tx key index */
wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
- (u32)cmd_WEP_KEY_INDEX_MASK));
-
- lbs_deb_cmd("Tx key Index: %u\n", le16_to_cpu(wep->keyindex));
+ (u32)CMD_WEP_KEY_INDEX_MASK));
/* Copy key types and material to host command structure */
for (i = 0; i < 4; i++) {
- struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i];
+ struct enc_key * pkey = &assoc_req->wep_keys[i];
switch (pkey->len) {
case KEY_LEN_WEP_40:
- wep->keytype[i] =
- cpu_to_le16(cmd_type_wep_40_bit);
+ wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
memmove(&wep->keymaterial[i], pkey->key,
pkey->len);
+ lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
break;
case KEY_LEN_WEP_104:
- wep->keytype[i] =
- cpu_to_le16(cmd_type_wep_104_bit);
+ wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
memmove(&wep->keymaterial[i], pkey->key,
pkey->len);
+ lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
break;
case 0:
break;
default:
- lbs_deb_cmd("Invalid WEP key %d length of %d\n",
+ lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
i, pkey->len);
ret = -1;
goto done;
break;
}
}
- } else if (cmd_act == cmd_act_remove) {
+ } else if (cmd_act == CMD_ACT_REMOVE) {
/* ACT_REMOVE clears _all_ WEP keys */
- wep->action = cpu_to_le16(cmd_act_remove);
+ wep->action = cpu_to_le16(CMD_ACT_REMOVE);
/* default tx key index */
wep->keyindex = cpu_to_le16((u16)(adapter->wep_tx_keyidx &
- (u32)cmd_WEP_KEY_INDEX_MASK));
+ (u32)CMD_WEP_KEY_INDEX_MASK));
+ lbs_deb_cmd("SET_WEP: remove key %d\n", adapter->wep_tx_keyidx);
}
ret = 0;
@@ -232,15 +229,16 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_802_11_enable_rsn);
+ cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN);
cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
penableRSN->action = cpu_to_le16(cmd_action);
- if (cmd_action == cmd_act_set) {
+ if (cmd_action == CMD_ACT_SET) {
if (*enable)
- penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
+ penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN);
else
- penableRSN->enable = cpu_to_le16(cmd_disable_rsn);
+ penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN);
+ lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
}
lbs_deb_leave(LBS_DEB_CMD);
@@ -249,9 +247,9 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
- struct WLAN_802_11_KEY * pkey)
+ struct enc_key * pkey)
{
- pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
+ lbs_deb_enter(LBS_DEB_CMD);
if (pkey->flags & KEY_INFO_WPA_ENABLED) {
pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
@@ -264,12 +262,14 @@ static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
}
pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
pkeyparamset->keylen = cpu_to_le16(pkey->len);
memcpy(pkeyparamset->key, pkey->key, pkey->len);
pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid)
+ sizeof(pkeyparamset->keyinfo)
+ sizeof(pkeyparamset->keylen)
+ sizeof(pkeyparamset->key));
+ lbs_deb_leave(LBS_DEB_CMD);
}
static int wlan_cmd_802_11_key_material(wlan_private * priv,
@@ -285,10 +285,10 @@ static int wlan_cmd_802_11_key_material(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_802_11_key_material);
+ cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
pkeymaterial->action = cpu_to_le16(cmd_action);
- if (cmd_action == cmd_act_get) {
+ if (cmd_action == CMD_ACT_GET) {
cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
ret = 0;
goto done;
@@ -324,30 +324,37 @@ static int wlan_cmd_802_11_reset(wlan_private * priv,
{
struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
- cmd->command = cpu_to_le16(cmd_802_11_reset);
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ cmd->command = cpu_to_le16(CMD_802_11_RESET);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
reset->action = cpu_to_le16(cmd_action);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int wlan_cmd_802_11_get_log(wlan_private * priv,
struct cmd_ds_command *cmd)
{
- cmd->command = cpu_to_le16(cmd_802_11_get_log);
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_GET_LOG);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
static int wlan_cmd_802_11_get_stat(wlan_private * priv,
struct cmd_ds_command *cmd)
{
- cmd->command = cpu_to_le16(cmd_802_11_get_stat);
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_GET_STAT);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -364,15 +371,15 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
- cmd->command = cpu_to_le16(cmd_802_11_snmp_mib);
+ cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
switch (cmd_oid) {
case OID_802_11_INFRASTRUCTURE_MODE:
{
u8 mode = (u8) (size_t) pdata_buf;
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
- pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i);
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
+ pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
pSNMPMIB->bufsize = sizeof(u8);
if (mode == IW_MODE_ADHOC) {
ucTemp = SNMP_MIB_VALUE_ADHOC;
@@ -390,10 +397,10 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
{
u32 ulTemp;
- pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i);
+ pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
- if (cmd_action == cmd_act_set) {
- pSNMPMIB->querytype = cmd_act_set;
+ if (cmd_action == CMD_ACT_SET) {
+ pSNMPMIB->querytype = CMD_ACT_SET;
pSNMPMIB->bufsize = sizeof(u16);
ulTemp = *(u32 *)pdata_buf;
*((__le16 *)(pSNMPMIB->value)) =
@@ -406,12 +413,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
{
u32 ulTemp;
- pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i);
+ pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
- if (cmd_action == cmd_act_get) {
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_get);
- } else if (cmd_action == cmd_act_set) {
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+ if (cmd_action == CMD_ACT_GET) {
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
+ } else if (cmd_action == CMD_ACT_SET) {
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
ulTemp = *((u32 *) pdata_buf);
*((__le16 *)(pSNMPMIB->value)) =
@@ -426,12 +433,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
{
u32 ulTemp;
- pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i);
+ pSNMPMIB->oid = le16_to_cpu((u16) RTSTHRESH_I);
- if (cmd_action == cmd_act_get) {
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_get);
- } else if (cmd_action == cmd_act_set) {
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+ if (cmd_action == CMD_ACT_GET) {
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
+ } else if (cmd_action == CMD_ACT_SET) {
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
ulTemp = *((u32 *)pdata_buf);
*(__le16 *)(pSNMPMIB->value) =
@@ -441,12 +448,12 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
break;
}
case OID_802_11_TX_RETRYCOUNT:
- pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i);
+ pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I);
- if (cmd_action == cmd_act_get) {
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_get);
- } else if (cmd_action == cmd_act_set) {
- pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+ if (cmd_action == CMD_ACT_GET) {
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
+ } else if (cmd_action == CMD_ACT_SET) {
+ pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
*((__le16 *)(pSNMPMIB->value)) =
cpu_to_le16((u16) adapter->txretrycount);
@@ -463,7 +470,7 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
lbs_deb_cmd(
- "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n",
+ "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
le16_to_cpu(pSNMPMIB->bufsize),
le16_to_cpu(*(__le16 *) pSNMPMIB->value));
@@ -484,20 +491,20 @@ static int wlan_cmd_802_11_radio_control(wlan_private * priv,
cmd->size =
cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
S_DS_GEN);
- cmd->command = cpu_to_le16(cmd_802_11_radio_control);
+ cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL);
pradiocontrol->action = cpu_to_le16(cmd_action);
switch (adapter->preamble) {
- case cmd_type_short_preamble:
+ case CMD_TYPE_SHORT_PREAMBLE:
pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
break;
- case cmd_type_long_preamble:
+ case CMD_TYPE_LONG_PREAMBLE:
pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
break;
- case cmd_type_auto_preamble:
+ case CMD_TYPE_AUTO_PREAMBLE:
default:
pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
break;
@@ -523,7 +530,7 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
cmd->size =
cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
- cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power);
+ cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
prtp->action = cpu_to_le16(cmd_action);
lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n",
@@ -531,23 +538,23 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
le16_to_cpu(prtp->action));
switch (cmd_action) {
- case cmd_act_tx_power_opt_get:
- prtp->action = cpu_to_le16(cmd_act_get);
+ case CMD_ACT_TX_POWER_OPT_GET:
+ prtp->action = cpu_to_le16(CMD_ACT_GET);
prtp->currentlevel = 0;
break;
- case cmd_act_tx_power_opt_set_high:
- prtp->action = cpu_to_le16(cmd_act_set);
- prtp->currentlevel = cpu_to_le16(cmd_act_tx_power_index_high);
+ case CMD_ACT_TX_POWER_OPT_SET_HIGH:
+ prtp->action = cpu_to_le16(CMD_ACT_SET);
+ prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH);
break;
- case cmd_act_tx_power_opt_set_mid:
- prtp->action = cpu_to_le16(cmd_act_set);
- prtp->currentlevel = cpu_to_le16(cmd_act_tx_power_index_mid);
+ case CMD_ACT_TX_POWER_OPT_SET_MID:
+ prtp->action = cpu_to_le16(CMD_ACT_SET);
+ prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID);
break;
- case cmd_act_tx_power_opt_set_low:
- prtp->action = cpu_to_le16(cmd_act_set);
+ case CMD_ACT_TX_POWER_OPT_SET_LOW:
+ prtp->action = cpu_to_le16(CMD_ACT_SET);
prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
break;
}
@@ -556,19 +563,21 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
return 0;
}
-static int wlan_cmd_802_11_rf_antenna(wlan_private * priv,
+static int wlan_cmd_802_11_monitor_mode(wlan_private * priv,
struct cmd_ds_command *cmd,
u16 cmd_action, void *pdata_buf)
{
- struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant;
+ struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;
- cmd->command = cpu_to_le16(cmd_802_11_rf_antenna);
- cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) +
- S_DS_GEN);
+ cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
+ S_DS_GEN);
- rant->action = cpu_to_le16(cmd_action);
- if ((cmd_action == cmd_act_set_rx) || (cmd_action == cmd_act_set_tx)) {
- rant->antennamode = cpu_to_le16((u16) (*(u32 *) pdata_buf));
+ monitor->action = cpu_to_le16(cmd_action);
+ if (cmd_action == CMD_ACT_SET) {
+ monitor->mode =
+ cpu_to_le16((u16) (*(u32 *) pdata_buf));
}
return 0;
@@ -582,12 +591,11 @@ static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
*rateadapt = &cmd->params.rateset;
wlan_adapter *adapter = priv->adapter;
+ lbs_deb_enter(LBS_DEB_CMD);
cmd->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
+ S_DS_GEN);
- cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset);
-
- lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
rateadapt->action = cpu_to_le16(cmd_action);
rateadapt->enablehwauto = cpu_to_le16(adapter->enablehwauto);
@@ -608,19 +616,16 @@ static int wlan_cmd_802_11_data_rate(wlan_private * priv,
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
S_DS_GEN);
-
- cmd->command = cpu_to_le16(cmd_802_11_data_rate);
-
+ cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE);
memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
-
pdatarate->action = cpu_to_le16(cmd_action);
- if (cmd_action == cmd_act_set_tx_fix_rate) {
- pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate);
- lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n",
- adapter->datarate);
- } else if (cmd_action == cmd_act_set_tx_auto) {
- lbs_deb_cmd("Setting FW for AUTO rate\n");
+ if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) {
+ pdatarate->rates[0] = libertas_data_rate_to_fw_index(adapter->cur_rate);
+ lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n",
+ adapter->cur_rate);
+ } else if (cmd_action == CMD_ACT_SET_TX_AUTO) {
+ lbs_deb_cmd("DATA_RATE: setting auto\n");
}
lbs_deb_leave(LBS_DEB_CMD);
@@ -634,16 +639,19 @@ static int wlan_cmd_mac_multicast_adr(wlan_private * priv,
struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
wlan_adapter *adapter = priv->adapter;
+ lbs_deb_enter(LBS_DEB_CMD);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
S_DS_GEN);
- cmd->command = cpu_to_le16(cmd_mac_multicast_adr);
+ cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
+ lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
pMCastAdr->action = cpu_to_le16(cmd_action);
pMCastAdr->nr_of_adrs =
cpu_to_le16((u16) adapter->nr_of_multicastmacaddr);
memcpy(pMCastAdr->maclist, adapter->multicastlist,
adapter->nr_of_multicastmacaddr * ETH_ALEN);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -653,16 +661,18 @@ static int wlan_cmd_802_11_rf_channel(wlan_private * priv,
{
struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;
- cmd->command = cpu_to_le16(cmd_802_11_rf_channel);
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) +
S_DS_GEN);
- if (option == cmd_opt_802_11_rf_channel_set) {
+ if (option == CMD_OPT_802_11_RF_CHANNEL_SET) {
rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
}
rfchan->action = cpu_to_le16(option);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -671,9 +681,10 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv,
{
wlan_adapter *adapter = priv->adapter;
- cmd->command = cpu_to_le16(cmd_802_11_rssi);
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_RSSI);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
- cmd->params.rssi.N = cpu_to_le16(priv->adapter->bcn_avg_factor);
+ cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
/* reset Beacon SNR/NF/RSSI values */
adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
@@ -683,6 +694,7 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv,
adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -697,7 +709,7 @@ static int wlan_cmd_reg_access(wlan_private * priv,
offval = (struct wlan_offset_value *)pdata_buf;
switch (cmdptr->command) {
- case cmd_mac_reg_access:
+ case CMD_MAC_REG_ACCESS:
{
struct cmd_ds_mac_reg_access *macreg;
@@ -715,7 +727,7 @@ static int wlan_cmd_reg_access(wlan_private * priv,
break;
}
- case cmd_bbp_reg_access:
+ case CMD_BBP_REG_ACCESS:
{
struct cmd_ds_bbp_reg_access *bbpreg;
@@ -734,7 +746,7 @@ static int wlan_cmd_reg_access(wlan_private * priv,
break;
}
- case cmd_rf_reg_access:
+ case CMD_RF_REG_ACCESS:
{
struct cmd_ds_rf_reg_access *rfreg;
@@ -767,19 +779,21 @@ static int wlan_cmd_802_11_mac_address(wlan_private * priv,
{
wlan_adapter *adapter = priv->adapter;
- cmd->command = cpu_to_le16(cmd_802_11_mac_address);
+ lbs_deb_enter(LBS_DEB_CMD);
+ cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
S_DS_GEN);
cmd->result = 0;
cmd->params.macadd.action = cpu_to_le16(cmd_action);
- if (cmd_action == cmd_act_set) {
+ if (cmd_action == CMD_ACT_SET) {
memcpy(cmd->params.macadd.macadd,
adapter->current_addr, ETH_ALEN);
- lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6);
+ lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", adapter->current_addr, 6);
}
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -791,7 +805,7 @@ static int wlan_cmd_802_11_eeprom_access(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_802_11_eeprom_access);
+ cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
S_DS_GEN);
cmd->result = 0;
@@ -801,6 +815,7 @@ static int wlan_cmd_802_11_eeprom_access(wlan_private * priv,
cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
cmd->params.rdeeprom.value = 0;
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -809,35 +824,36 @@ static int wlan_cmd_bt_access(wlan_private * priv,
u16 cmd_action, void *pdata_buf)
{
struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
- lbs_deb_cmd("BT CMD(%d)\n", cmd_action);
+ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
- cmd->command = cpu_to_le16(cmd_bt_access);
+ cmd->command = cpu_to_le16(CMD_BT_ACCESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
cmd->result = 0;
bt_access->action = cpu_to_le16(cmd_action);
switch (cmd_action) {
- case cmd_act_bt_access_add:
+ case CMD_ACT_BT_ACCESS_ADD:
memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
- lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6);
+ lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
break;
- case cmd_act_bt_access_del:
+ case CMD_ACT_BT_ACCESS_DEL:
memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
- lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6);
+ lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
break;
- case cmd_act_bt_access_list:
+ case CMD_ACT_BT_ACCESS_LIST:
bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
break;
- case cmd_act_bt_access_reset:
+ case CMD_ACT_BT_ACCESS_RESET:
break;
- case cmd_act_bt_access_set_invert:
+ case CMD_ACT_BT_ACCESS_SET_INVERT:
bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
break;
- case cmd_act_bt_access_get_invert:
+ case CMD_ACT_BT_ACCESS_GET_INVERT:
break;
default:
break;
}
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -846,9 +862,9 @@ static int wlan_cmd_fwt_access(wlan_private * priv,
u16 cmd_action, void *pdata_buf)
{
struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
- lbs_deb_cmd("FWT CMD(%d)\n", cmd_action);
+ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
- cmd->command = cpu_to_le16(cmd_fwt_access);
+ cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
cmd->result = 0;
@@ -859,6 +875,7 @@ static int wlan_cmd_fwt_access(wlan_private * priv,
fwt_access->action = cpu_to_le16(cmd_action);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -867,9 +884,9 @@ static int wlan_cmd_mesh_access(wlan_private * priv,
u16 cmd_action, void *pdata_buf)
{
struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
- lbs_deb_cmd("FWT CMD(%d)\n", cmd_action);
+ lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
- cmd->command = cpu_to_le16(cmd_mesh_access);
+ cmd->command = cpu_to_le16(CMD_MESH_ACCESS);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN);
cmd->result = 0;
@@ -880,31 +897,47 @@ static int wlan_cmd_mesh_access(wlan_private * priv,
mesh_access->action = cpu_to_le16(cmd_action);
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
+static int wlan_cmd_set_boot2_ver(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ struct cmd_ds_set_boot2_ver *boot2_ver = &cmd->params.boot2_ver;
+ cmd->command = cpu_to_le16(CMD_SET_BOOT2_VER);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_set_boot2_ver) + S_DS_GEN);
+ boot2_ver->version = priv->boot2_version;
return 0;
}
+/*
+ * Note: NEVER use libertas_queue_cmd() with addtail==0 other than for
+ * the command timer, because it does not account for queued commands.
+ */
void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail)
{
unsigned long flags;
struct cmd_ds_command *cmdptr;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
if (!cmdnode) {
- lbs_deb_cmd("QUEUE_CMD: cmdnode is NULL\n");
+ lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
goto done;
}
cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
if (!cmdptr) {
- lbs_deb_cmd("QUEUE_CMD: cmdptr is NULL\n");
+ lbs_deb_host("QUEUE_CMD: cmdptr is NULL\n");
goto done;
}
/* Exit_PS command needs to be queued in the header always. */
- if (cmdptr->command == cmd_802_11_ps_mode) {
+ if (cmdptr->command == CMD_802_11_PS_MODE) {
struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
- if (psm->action == cpu_to_le16(cmd_subcmd_exit_ps)) {
+ if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
if (adapter->psstate != PS_STATE_FULL_POWER)
addtail = 0;
}
@@ -912,25 +945,25 @@ void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u
spin_lock_irqsave(&adapter->driver_lock, flags);
- if (addtail)
+ if (addtail) {
list_add_tail((struct list_head *)cmdnode,
&adapter->cmdpendingq);
- else
+ adapter->nr_cmd_pending++;
+ } else
list_add((struct list_head *)cmdnode, &adapter->cmdpendingq);
spin_unlock_irqrestore(&adapter->driver_lock, flags);
- lbs_deb_cmd("QUEUE_CMD: Inserted node=%p, cmd=0x%x in cmdpendingq\n",
- cmdnode,
+ lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
le16_to_cpu(((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command));
done:
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_HOST);
}
/*
* TODO: Fix the issue when DownloadcommandToStation is being called the
- * second time when the command timesout. All the cmdptr->xxx are in little
+ * second time when the command times out. All the cmdptr->xxx are in little
* endian and therefore all the comparissions will fail.
* For now - we are not performing the endian conversion the second time - but
* for PS and DEEP_SLEEP we need to worry
@@ -941,68 +974,59 @@ static int DownloadcommandToStation(wlan_private * priv,
unsigned long flags;
struct cmd_ds_command *cmdptr;
wlan_adapter *adapter = priv->adapter;
- int ret = 0;
+ int ret = -1;
u16 cmdsize;
u16 command;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
if (!adapter || !cmdnode) {
- lbs_deb_cmd("DNLD_CMD: adapter = %p, cmdnode = %p\n",
- adapter, cmdnode);
- if (cmdnode) {
- spin_lock_irqsave(&adapter->driver_lock, flags);
- __libertas_cleanup_and_insert_cmd(priv, cmdnode);
- spin_unlock_irqrestore(&adapter->driver_lock, flags);
- }
- ret = -1;
+ lbs_deb_host("DNLD_CMD: adapter or cmdmode is NULL\n");
goto done;
}
cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
-
spin_lock_irqsave(&adapter->driver_lock, flags);
if (!cmdptr || !cmdptr->size) {
- lbs_deb_cmd("DNLD_CMD: cmdptr is Null or cmd size is Zero, "
- "Not sending\n");
+ lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n");
__libertas_cleanup_and_insert_cmd(priv, cmdnode);
spin_unlock_irqrestore(&adapter->driver_lock, flags);
- ret = -1;
goto done;
}
adapter->cur_cmd = cmdnode;
adapter->cur_cmd_retcode = 0;
spin_unlock_irqrestore(&adapter->driver_lock, flags);
- lbs_deb_cmd("DNLD_CMD:: Before download, size of cmd = %d\n",
- le16_to_cpu(cmdptr->size));
cmdsize = cmdptr->size;
-
command = cpu_to_le16(cmdptr->command);
+ lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n",
+ command, le16_to_cpu(cmdptr->size), jiffies);
+ lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize);
+
cmdnode->cmdwaitqwoken = 0;
cmdsize = cpu_to_le16(cmdsize);
ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
if (ret != 0) {
- lbs_deb_cmd("DNLD_CMD: Host to Card failed\n");
+ lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n");
spin_lock_irqsave(&adapter->driver_lock, flags);
+ adapter->cur_cmd_retcode = ret;
__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+ adapter->nr_cmd_pending--;
adapter->cur_cmd = NULL;
spin_unlock_irqrestore(&adapter->driver_lock, flags);
- ret = -1;
goto done;
}
- lbs_deb_cmd("DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies);
- lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize);
+ lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);
/* Setup the timer after transmit command */
- if (command == cmd_802_11_scan || command == cmd_802_11_authenticate
- || command == cmd_802_11_associate)
+ if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE
+ || command == CMD_802_11_ASSOCIATE)
mod_timer(&adapter->command_timer, jiffies + (10*HZ));
else
mod_timer(&adapter->command_timer, jiffies + (5*HZ));
@@ -1010,7 +1034,7 @@ static int DownloadcommandToStation(wlan_private * priv,
ret = 0;
done:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
return ret;
}
@@ -1021,11 +1045,11 @@ static int wlan_cmd_mac_control(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- cmd->command = cpu_to_le16(cmd_mac_control);
+ cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);
- lbs_deb_cmd("wlan_cmd_mac_control(): action=0x%X size=%d\n",
+ lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
lbs_deb_leave(LBS_DEB_CMD);
@@ -1041,15 +1065,13 @@ void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node
wlan_adapter *adapter = priv->adapter;
if (!ptempcmd)
- goto done;
+ return;
cleanup_cmdnode(ptempcmd);
list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq);
-done:
- return;
}
-void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+static void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
{
unsigned long flags;
@@ -1065,11 +1087,11 @@ int libertas_set_radio_control(wlan_private * priv)
lbs_deb_enter(LBS_DEB_CMD);
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_radio_control,
- cmd_act_set,
- cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_RADIO_CONTROL,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
- lbs_deb_cmd("RADIO_SET: on or off: 0x%X, preamble = 0x%X\n",
+ lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n",
priv->adapter->radioon, priv->adapter->preamble);
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
@@ -1082,12 +1104,9 @@ int libertas_set_mac_packet_filter(wlan_private * priv)
lbs_deb_enter(LBS_DEB_CMD);
- lbs_deb_cmd("libertas_set_mac_packet_filter value = %x\n",
- priv->adapter->currentpacketfilter);
-
/* Send MAC control command to station */
ret = libertas_prepare_and_send_command(priv,
- cmd_mac_control, 0, 0, 0, NULL);
+ CMD_MAC_CONTROL, 0, 0, 0, NULL);
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
@@ -1115,16 +1134,16 @@ int libertas_prepare_and_send_command(wlan_private * priv,
struct cmd_ds_command *cmdptr;
unsigned long flags;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
if (!adapter) {
- lbs_deb_cmd("PREP_CMD: adapter is Null\n");
+ lbs_deb_host("PREP_CMD: adapter is NULL\n");
ret = -1;
goto done;
}
if (adapter->surpriseremoved) {
- lbs_deb_cmd("PREP_CMD: Card is Removed\n");
+ lbs_deb_host("PREP_CMD: card removed\n");
ret = -1;
goto done;
}
@@ -1132,10 +1151,10 @@ int libertas_prepare_and_send_command(wlan_private * priv,
cmdnode = libertas_get_free_cmd_ctrl_node(priv);
if (cmdnode == NULL) {
- lbs_deb_cmd("PREP_CMD: No free cmdnode\n");
+ lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
/* Wake up main thread to execute next command */
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
ret = -1;
goto done;
}
@@ -1144,11 +1163,10 @@ int libertas_prepare_and_send_command(wlan_private * priv,
cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
- lbs_deb_cmd("PREP_CMD: Val of cmd ptr=%p, command=0x%X\n",
- cmdptr, cmd_no);
+ lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
if (!cmdptr) {
- lbs_deb_cmd("PREP_CMD: bufvirtualaddr of cmdnode is NULL\n");
+ lbs_deb_host("PREP_CMD: cmdptr is NULL\n");
libertas_cleanup_and_insert_cmd(priv, cmdnode);
ret = -1;
goto done;
@@ -1162,136 +1180,136 @@ int libertas_prepare_and_send_command(wlan_private * priv,
cmdptr->result = 0;
switch (cmd_no) {
- case cmd_get_hw_spec:
+ case CMD_GET_HW_SPEC:
ret = wlan_cmd_hw_spec(priv, cmdptr);
break;
- case cmd_802_11_ps_mode:
+ case CMD_802_11_PS_MODE:
ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_scan:
+ case CMD_802_11_SCAN:
ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf);
break;
- case cmd_mac_control:
+ case CMD_MAC_CONTROL:
ret = wlan_cmd_mac_control(priv, cmdptr);
break;
- case cmd_802_11_associate:
- case cmd_802_11_reassociate:
+ case CMD_802_11_ASSOCIATE:
+ case CMD_802_11_REASSOCIATE:
ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf);
break;
- case cmd_802_11_deauthenticate:
+ case CMD_802_11_DEAUTHENTICATE:
ret = libertas_cmd_80211_deauthenticate(priv, cmdptr);
break;
- case cmd_802_11_set_wep:
+ case CMD_802_11_SET_WEP:
ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
break;
- case cmd_802_11_ad_hoc_start:
+ case CMD_802_11_AD_HOC_START:
ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
break;
- case cmd_code_dnld:
+ case CMD_CODE_DNLD:
break;
- case cmd_802_11_reset:
+ case CMD_802_11_RESET:
ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_get_log:
+ case CMD_802_11_GET_LOG:
ret = wlan_cmd_802_11_get_log(priv, cmdptr);
break;
- case cmd_802_11_authenticate:
+ case CMD_802_11_AUTHENTICATE:
ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
break;
- case cmd_802_11_get_stat:
+ case CMD_802_11_GET_STAT:
ret = wlan_cmd_802_11_get_stat(priv, cmdptr);
break;
- case cmd_802_11_snmp_mib:
+ case CMD_802_11_SNMP_MIB:
ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr,
cmd_action, cmd_oid, pdata_buf);
break;
- case cmd_mac_reg_access:
- case cmd_bbp_reg_access:
- case cmd_rf_reg_access:
+ case CMD_MAC_REG_ACCESS:
+ case CMD_BBP_REG_ACCESS:
+ case CMD_RF_REG_ACCESS:
ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
break;
- case cmd_802_11_rf_channel:
+ case CMD_802_11_RF_CHANNEL:
ret = wlan_cmd_802_11_rf_channel(priv, cmdptr,
cmd_action, pdata_buf);
break;
- case cmd_802_11_rf_tx_power:
+ case CMD_802_11_RF_TX_POWER:
ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr,
cmd_action, pdata_buf);
break;
- case cmd_802_11_radio_control:
+ case CMD_802_11_RADIO_CONTROL:
ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_rf_antenna:
- ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr,
- cmd_action, pdata_buf);
- break;
-
- case cmd_802_11_data_rate:
+ case CMD_802_11_DATA_RATE:
ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_rate_adapt_rateset:
+ case CMD_802_11_RATE_ADAPT_RATESET:
ret = wlan_cmd_802_11_rate_adapt_rateset(priv,
cmdptr, cmd_action);
break;
- case cmd_mac_multicast_adr:
+ case CMD_MAC_MULTICAST_ADR:
ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_ad_hoc_join:
+ case CMD_802_11_MONITOR_MODE:
+ ret = wlan_cmd_802_11_monitor_mode(priv, cmdptr,
+ cmd_action, pdata_buf);
+ break;
+
+ case CMD_802_11_AD_HOC_JOIN:
ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
break;
- case cmd_802_11_rssi:
+ case CMD_802_11_RSSI:
ret = wlan_cmd_802_11_rssi(priv, cmdptr);
break;
- case cmd_802_11_ad_hoc_stop:
+ case CMD_802_11_AD_HOC_STOP:
ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr);
break;
- case cmd_802_11_enable_rsn:
+ case CMD_802_11_ENABLE_RSN:
ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
pdata_buf);
break;
- case cmd_802_11_key_material:
+ case CMD_802_11_KEY_MATERIAL:
ret = wlan_cmd_802_11_key_material(priv, cmdptr, cmd_action,
cmd_oid, pdata_buf);
break;
- case cmd_802_11_pairwise_tsc:
+ case CMD_802_11_PAIRWISE_TSC:
break;
- case cmd_802_11_group_tsc:
+ case CMD_802_11_GROUP_TSC:
break;
- case cmd_802_11_mac_address:
+ case CMD_802_11_MAC_ADDRESS:
ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_eeprom_access:
+ case CMD_802_11_EEPROM_ACCESS:
ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr,
cmd_action, pdata_buf);
break;
- case cmd_802_11_set_afc:
- case cmd_802_11_get_afc:
+ case CMD_802_11_SET_AFC:
+ case CMD_802_11_GET_AFC:
cmdptr->command = cpu_to_le16(cmd_no);
cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
@@ -1303,22 +1321,22 @@ int libertas_prepare_and_send_command(wlan_private * priv,
ret = 0;
goto done;
- case cmd_802_11d_domain_info:
+ case CMD_802_11D_DOMAIN_INFO:
ret = libertas_cmd_802_11d_domain_info(priv, cmdptr,
cmd_no, cmd_action);
break;
- case cmd_802_11_sleep_params:
+ case CMD_802_11_SLEEP_PARAMS:
ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
break;
- case cmd_802_11_inactivity_timeout:
+ case CMD_802_11_INACTIVITY_TIMEOUT:
ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr,
cmd_action, pdata_buf);
libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf);
break;
- case cmd_802_11_tpc_cfg:
- cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg);
+ case CMD_802_11_TPC_CFG:
+ cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
cmdptr->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
S_DS_GEN);
@@ -1328,7 +1346,7 @@ int libertas_prepare_and_send_command(wlan_private * priv,
ret = 0;
break;
- case cmd_802_11_led_gpio_ctrl:
+ case CMD_802_11_LED_GPIO_CTRL:
{
struct mrvlietypes_ledgpio *gpio =
(struct mrvlietypes_ledgpio*)
@@ -1339,7 +1357,7 @@ int libertas_prepare_and_send_command(wlan_private * priv,
sizeof(struct cmd_ds_802_11_led_ctrl));
cmdptr->command =
- cpu_to_le16(cmd_802_11_led_gpio_ctrl);
+ cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
cmdptr->size =
@@ -1350,8 +1368,8 @@ int libertas_prepare_and_send_command(wlan_private * priv,
ret = 0;
break;
}
- case cmd_802_11_pwr_cfg:
- cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg);
+ case CMD_802_11_PWR_CFG:
+ cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
cmdptr->size =
cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
S_DS_GEN);
@@ -1360,40 +1378,37 @@ int libertas_prepare_and_send_command(wlan_private * priv,
ret = 0;
break;
- case cmd_bt_access:
+ case CMD_BT_ACCESS:
ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
break;
- case cmd_fwt_access:
+ case CMD_FWT_ACCESS:
ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
break;
- case cmd_mesh_access:
+ case CMD_MESH_ACCESS:
ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
break;
- case cmd_get_tsf:
- cmdptr->command = cpu_to_le16(cmd_get_tsf);
- cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
- S_DS_GEN);
- ret = 0;
+ case CMD_SET_BOOT2_VER:
+ ret = wlan_cmd_set_boot2_ver(priv, cmdptr, cmd_action, pdata_buf);
break;
- case cmd_802_11_tx_rate_query:
- cmdptr->command = cpu_to_le16(cmd_802_11_tx_rate_query);
- cmdptr->size = cpu_to_le16(sizeof(struct cmd_tx_rate_query) +
+
+ case CMD_GET_TSF:
+ cmdptr->command = cpu_to_le16(CMD_GET_TSF);
+ cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
S_DS_GEN);
- adapter->txrate = 0;
ret = 0;
break;
default:
- lbs_deb_cmd("PREP_CMD: unknown command- %#x\n", cmd_no);
+ lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
ret = -1;
break;
}
/* return error, since the command preparation failed */
if (ret != 0) {
- lbs_deb_cmd("PREP_CMD: command preparation failed\n");
+ lbs_deb_host("PREP_CMD: command preparation failed\n");
libertas_cleanup_and_insert_cmd(priv, cmdnode);
ret = -1;
goto done;
@@ -1402,11 +1417,10 @@ int libertas_prepare_and_send_command(wlan_private * priv,
cmdnode->cmdwaitqwoken = 0;
libertas_queue_cmd(adapter, cmdnode, 1);
- adapter->nr_cmd_pending++;
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
- if (wait_option & cmd_option_waitforrsp) {
- lbs_deb_cmd("PREP_CMD: Wait for CMD response\n");
+ if (wait_option & CMD_OPTION_WAITFORRSP) {
+ lbs_deb_host("PREP_CMD: wait for response\n");
might_sleep();
wait_event_interruptible(cmdnode->cmdwait_q,
cmdnode->cmdwaitqwoken);
@@ -1414,7 +1428,7 @@ int libertas_prepare_and_send_command(wlan_private * priv,
spin_lock_irqsave(&adapter->driver_lock, flags);
if (adapter->cur_cmd_retcode) {
- lbs_deb_cmd("PREP_CMD: command failed with return code=%d\n",
+ lbs_deb_host("PREP_CMD: command failed with return code %d\n",
adapter->cur_cmd_retcode);
adapter->cur_cmd_retcode = 0;
ret = -1;
@@ -1422,7 +1436,7 @@ int libertas_prepare_and_send_command(wlan_private * priv,
spin_unlock_irqrestore(&adapter->driver_lock, flags);
done:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
return ret;
}
EXPORT_SYMBOL_GPL(libertas_prepare_and_send_command);
@@ -1443,14 +1457,13 @@ int libertas_allocate_cmd_buffer(wlan_private * priv)
u8 *ptempvirtualaddr;
wlan_adapter *adapter = priv->adapter;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
/* Allocate and initialize cmdCtrlNode */
ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
if (!(tempcmd_array = kzalloc(ulbufsize, GFP_KERNEL))) {
- lbs_deb_cmd(
- "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n");
+ lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
ret = -1;
goto done;
}
@@ -1460,8 +1473,7 @@ int libertas_allocate_cmd_buffer(wlan_private * priv)
ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
if (!(ptempvirtualaddr = kzalloc(ulbufsize, GFP_KERNEL))) {
- lbs_deb_cmd(
- "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n");
+ lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
ret = -1;
goto done;
}
@@ -1478,7 +1490,7 @@ int libertas_allocate_cmd_buffer(wlan_private * priv)
ret = 0;
done:
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
return ret;
}
@@ -1495,11 +1507,11 @@ int libertas_free_cmd_buffer(wlan_private * priv)
struct cmd_ctrl_node *tempcmd_array;
wlan_adapter *adapter = priv->adapter;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
/* need to check if cmd array is allocated or not */
if (adapter->cmd_array == NULL) {
- lbs_deb_cmd("FREE_CMD_BUF: cmd_array is Null\n");
+ lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
goto done;
}
@@ -1509,7 +1521,6 @@ int libertas_free_cmd_buffer(wlan_private * priv)
ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
if (tempcmd_array[i].bufvirtualaddr) {
- lbs_deb_cmd("Free all the array\n");
kfree(tempcmd_array[i].bufvirtualaddr);
tempcmd_array[i].bufvirtualaddr = NULL;
}
@@ -1517,13 +1528,12 @@ int libertas_free_cmd_buffer(wlan_private * priv)
/* Release cmd_ctrl_node */
if (adapter->cmd_array) {
- lbs_deb_cmd("Free cmd_array\n");
kfree(adapter->cmd_array);
adapter->cmd_array = NULL;
}
done:
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_HOST);
return 0;
}
@@ -1540,6 +1550,8 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
wlan_adapter *adapter = priv->adapter;
unsigned long flags;
+ lbs_deb_enter(LBS_DEB_HOST);
+
if (!adapter)
return NULL;
@@ -1549,21 +1561,16 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next;
list_del((struct list_head *)tempnode);
} else {
- lbs_deb_cmd("GET_CMD_NODE: cmd_ctrl_node is not available\n");
+ lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
tempnode = NULL;
}
spin_unlock_irqrestore(&adapter->driver_lock, flags);
- if (tempnode) {
- /*
- lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n");
- lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n",
- tempnode);
- */
+ if (tempnode)
cleanup_cmdnode(tempnode);
- }
+ lbs_deb_leave(LBS_DEB_HOST);
return tempnode;
}
@@ -1575,6 +1582,8 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
*/
static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
{
+ lbs_deb_enter(LBS_DEB_HOST);
+
if (!ptempnode)
return;
ptempnode->cmdwaitqwoken = 1;
@@ -1586,7 +1595,8 @@ static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
if (ptempnode->bufvirtualaddr != NULL)
memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
- return;
+
+ lbs_deb_leave(LBS_DEB_HOST);
}
/**
@@ -1603,7 +1613,7 @@ void libertas_set_cmd_ctrl_node(wlan_private * priv,
struct cmd_ctrl_node *ptempnode,
u32 cmd_oid, u16 wait_option, void *pdata_buf)
{
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
if (!ptempnode)
return;
@@ -1612,7 +1622,7 @@ void libertas_set_cmd_ctrl_node(wlan_private * priv,
ptempnode->wait_option = wait_option;
ptempnode->pdata_buf = pdata_buf;
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_HOST);
}
/**
@@ -1631,12 +1641,15 @@ int libertas_execute_next_command(wlan_private * priv)
unsigned long flags;
int ret = 0;
- lbs_deb_enter(LBS_DEB_CMD);
+ // Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
+ // only caller to us is libertas_thread() and we get even when a
+ // data packet is received
+ lbs_deb_enter(LBS_DEB_THREAD);
spin_lock_irqsave(&adapter->driver_lock, flags);
if (adapter->cur_cmd) {
- lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n");
+ lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
spin_unlock_irqrestore(&adapter->driver_lock, flags);
ret = -1;
goto done;
@@ -1650,22 +1663,20 @@ int libertas_execute_next_command(wlan_private * priv)
spin_unlock_irqrestore(&adapter->driver_lock, flags);
if (cmdnode) {
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: Got next command from cmdpendingq\n");
cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
if (is_command_allowed_in_ps(cmdptr->command)) {
if ((adapter->psstate == PS_STATE_SLEEP) ||
(adapter->psstate == PS_STATE_PRE_SLEEP)) {
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n",
+ lbs_deb_host(
+ "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
le16_to_cpu(cmdptr->command),
adapter->psstate);
ret = -1;
goto done;
}
- lbs_deb_cmd("EXEC_NEXT_CMD: OK to send command "
- "0x%x in psstate %d\n",
+ lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
+ "0x%04x in psstate %d\n",
le16_to_cpu(cmdptr->command),
adapter->psstate);
} else if (adapter->psstate != PS_STATE_FULL_POWER) {
@@ -1681,7 +1692,7 @@ int libertas_execute_next_command(wlan_private * priv)
* immediately.
*/
if (cmdptr->command !=
- cpu_to_le16(cmd_802_11_ps_mode)) {
+ cpu_to_le16(CMD_802_11_PS_MODE)) {
/* Prepare to send Exit PS,
* this non PS command will be sent later */
if ((adapter->psstate == PS_STATE_SLEEP)
@@ -1703,13 +1714,13 @@ int libertas_execute_next_command(wlan_private * priv)
struct cmd_ds_802_11_ps_mode *psm =
&cmdptr->params.psmode;
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: PS cmd- action=0x%x\n",
+ lbs_deb_host(
+ "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
psm->action);
if (psm->action !=
- cpu_to_le16(cmd_subcmd_exit_ps)) {
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: Ignore Enter PS cmd\n");
+ cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
+ lbs_deb_host(
+ "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
list_del((struct list_head *)cmdnode);
libertas_cleanup_and_insert_cmd(priv, cmdnode);
@@ -1719,8 +1730,8 @@ int libertas_execute_next_command(wlan_private * priv)
if ((adapter->psstate == PS_STATE_SLEEP) ||
(adapter->psstate == PS_STATE_PRE_SLEEP)) {
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n");
+ lbs_deb_host(
+ "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
list_del((struct list_head *)cmdnode);
libertas_cleanup_and_insert_cmd(priv, cmdnode);
adapter->needtowakeup = 1;
@@ -1729,12 +1740,12 @@ int libertas_execute_next_command(wlan_private * priv)
goto done;
}
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: Sending Exit_PS down...\n");
+ lbs_deb_host(
+ "EXEC_NEXT_CMD: sending EXIT_PS\n");
}
}
list_del((struct list_head *)cmdnode);
- lbs_deb_cmd("EXEC_NEXT_CMD: Sending 0x%04X command\n",
+ lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
le16_to_cpu(cmdptr->command));
DownloadcommandToStation(priv, cmdnode);
} else {
@@ -1742,23 +1753,23 @@ int libertas_execute_next_command(wlan_private * priv)
* check if in power save mode, if yes, put the device back
* to PS mode
*/
- if ((adapter->psmode != wlan802_11powermodecam) &&
+ if ((adapter->psmode != WLAN802_11POWERMODECAM) &&
(adapter->psstate == PS_STATE_FULL_POWER) &&
- (adapter->connect_status == libertas_connected)) {
+ (adapter->connect_status == LIBERTAS_CONNECTED)) {
if (adapter->secinfo.WPAenabled ||
adapter->secinfo.WPA2enabled) {
/* check for valid WPA group keys */
if (adapter->wpa_mcast_key.len ||
adapter->wpa_unicast_key.len) {
- lbs_deb_cmd(
+ lbs_deb_host(
"EXEC_NEXT_CMD: WPA enabled and GTK_SET"
" go back to PS_SLEEP");
libertas_ps_sleep(priv, 0);
}
} else {
- lbs_deb_cmd(
- "EXEC_NEXT_CMD: command PendQ is empty,"
- " go back to PS_SLEEP");
+ lbs_deb_host(
+ "EXEC_NEXT_CMD: cmdpendingq empty, "
+ "go back to PS_SLEEP");
libertas_ps_sleep(priv, 0);
}
}
@@ -1766,7 +1777,7 @@ int libertas_execute_next_command(wlan_private * priv)
ret = 0;
done:
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_THREAD);
return ret;
}
@@ -1775,7 +1786,7 @@ void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str)
union iwreq_data iwrq;
u8 buf[50];
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_WEXT);
memset(&iwrq, 0, sizeof(union iwreq_data));
memset(buf, 0, sizeof(buf));
@@ -1785,13 +1796,13 @@ void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str)
iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
/* Send Event to upper layer */
- lbs_deb_cmd("Event Indication string = %s\n", (char *)buf);
- lbs_deb_cmd("Event Indication String length = %d\n", iwrq.data.length);
+ lbs_deb_wext("event indication string %s\n", (char *)buf);
+ lbs_deb_wext("event indication length %d\n", iwrq.data.length);
+ lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
- lbs_deb_cmd("Sending wireless event IWEVCUSTOM for %s\n", str);
wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_WEXT);
}
static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
@@ -1800,19 +1811,19 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
wlan_adapter *adapter = priv->adapter;
int ret = 0;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
- lbs_deb_cmd("SEND_SLEEPC_CMD: Before download, size of cmd = %d\n",
+ lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
size);
- lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size);
+ lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
priv->dnld_sent = DNLD_RES_RECEIVED;
spin_lock_irqsave(&adapter->driver_lock, flags);
if (adapter->intcounter || adapter->currenttxskb)
- lbs_deb_cmd("SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n",
+ lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
adapter->intcounter, adapter->currenttxskb);
spin_unlock_irqrestore(&adapter->driver_lock, flags);
@@ -1824,36 +1835,35 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
if (!adapter->intcounter) {
adapter->psstate = PS_STATE_SLEEP;
} else {
- lbs_deb_cmd("SEND_SLEEPC_CMD: After sent,IntC=%d\n",
+ lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
adapter->intcounter);
}
spin_unlock_irqrestore(&adapter->driver_lock, flags);
- lbs_deb_cmd("SEND_SLEEPC_CMD: Sent Confirm Sleep command\n");
- lbs_deb_cmd("+");
+ lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
}
- lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
return ret;
}
void libertas_ps_sleep(wlan_private * priv, int wait_option)
{
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
/*
* PS is currently supported only in Infrastructure mode
* Remove this check if it is to be supported in IBSS mode also
*/
- libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
- cmd_subcmd_enter_ps, wait_option, 0, NULL);
+ libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
+ CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_HOST);
}
/**
- * @brief This function sends Eixt_PS command to firmware.
+ * @brief This function sends Exit_PS command to firmware.
*
* @param priv A pointer to wlan_private structure
* @param wait_option wait response or not
@@ -1863,17 +1873,15 @@ void libertas_ps_wakeup(wlan_private * priv, int wait_option)
{
__le32 Localpsmode;
- lbs_deb_enter(LBS_DEB_CMD);
-
- Localpsmode = cpu_to_le32(wlan802_11powermodecam);
+ lbs_deb_enter(LBS_DEB_HOST);
- lbs_deb_cmd("Exit_PS: Localpsmode = %d\n", wlan802_11powermodecam);
+ Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM);
- libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
- cmd_subcmd_exit_ps,
+ libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
+ CMD_SUBCMD_EXIT_PS,
wait_option, 0, &Localpsmode);
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_HOST);
}
/**
@@ -1890,31 +1898,31 @@ void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode)
wlan_adapter *adapter = priv->adapter;
u8 allowed = 1;
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_enter(LBS_DEB_HOST);
if (priv->dnld_sent) {
allowed = 0;
- lbs_deb_cmd("D");
+ lbs_deb_host("dnld_sent was set");
}
spin_lock_irqsave(&adapter->driver_lock, flags);
if (adapter->cur_cmd) {
allowed = 0;
- lbs_deb_cmd("C");
+ lbs_deb_host("cur_cmd was set");
}
if (adapter->intcounter > 0) {
allowed = 0;
- lbs_deb_cmd("I%d", adapter->intcounter);
+ lbs_deb_host("intcounter %d", adapter->intcounter);
}
spin_unlock_irqrestore(&adapter->driver_lock, flags);
if (allowed) {
- lbs_deb_cmd("Sending libertas_ps_confirm_sleep\n");
+ lbs_deb_host("sending libertas_ps_confirm_sleep\n");
sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep,
sizeof(struct PS_CMD_ConfirmSleep));
} else {
- lbs_deb_cmd("Sleep Confirm has been delayed\n");
+ lbs_deb_host("sleep confirm has been delayed\n");
}
- lbs_deb_leave(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_HOST);
}
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 6ac0d4752fa..8f90892ea22 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -28,10 +28,10 @@ void libertas_mac_event_disconnected(wlan_private * priv)
wlan_adapter *adapter = priv->adapter;
union iwreq_data wrqu;
- if (adapter->connect_status != libertas_connected)
+ if (adapter->connect_status != LIBERTAS_CONNECTED)
return;
- lbs_deb_cmd("Handles disconnect event.\n");
+ lbs_deb_enter(LBS_DEB_CMD);
memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@@ -60,22 +60,12 @@ void libertas_mac_event_disconnected(wlan_private * priv)
memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
adapter->nextSNRNF = 0;
adapter->numSNRNF = 0;
- adapter->rxpd_rate = 0;
- lbs_deb_cmd("Current SSID='%s', ssid length=%u\n",
+ lbs_deb_cmd("current SSID '%s', length %u\n",
escape_essid(adapter->curbssparams.ssid,
adapter->curbssparams.ssid_len),
adapter->curbssparams.ssid_len);
- lbs_deb_cmd("Previous SSID='%s', ssid length=%u\n",
- escape_essid(adapter->prev_ssid, adapter->prev_ssid_len),
- adapter->prev_ssid_len);
-
- adapter->connect_status = libertas_disconnected;
- /* Save previous SSID and BSSID for possible reassociation */
- memcpy(&adapter->prev_ssid, &adapter->curbssparams.ssid,
- IW_ESSID_MAX_SIZE);
- adapter->prev_ssid_len = adapter->curbssparams.ssid_len;
- memcpy(adapter->prev_bssid, adapter->curbssparams.bssid, ETH_ALEN);
+ adapter->connect_status = LIBERTAS_DISCONNECTED;
/* Clear out associated SSID and BSSID since connection is
* no longer valid.
@@ -86,9 +76,10 @@ void libertas_mac_event_disconnected(wlan_private * priv)
if (adapter->psstate != PS_STATE_FULL_POWER) {
/* make firmware to exit PS mode */
- lbs_deb_cmd("Disconnected, so exit PS mode.\n");
+ lbs_deb_cmd("disconnected, so exit PS mode\n");
libertas_ps_wakeup(priv, 0);
}
+ lbs_deb_leave(LBS_DEB_CMD);
}
/**
@@ -102,6 +93,7 @@ static void handle_mic_failureevent(wlan_private * priv, u32 event)
{
char buf[50];
+ lbs_deb_enter(LBS_DEB_CMD);
memset(buf, 0, sizeof(buf));
sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
@@ -113,6 +105,7 @@ static void handle_mic_failureevent(wlan_private * priv, u32 event)
}
libertas_send_iwevcustom_event(priv, buf);
+ lbs_deb_leave(LBS_DEB_CMD);
}
static int wlan_ret_reg_access(wlan_private * priv,
@@ -124,7 +117,7 @@ static int wlan_ret_reg_access(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
switch (type) {
- case cmd_ret_mac_reg_access:
+ case CMD_RET(CMD_MAC_REG_ACCESS):
{
struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
@@ -133,7 +126,7 @@ static int wlan_ret_reg_access(wlan_private * priv,
break;
}
- case cmd_ret_bbp_reg_access:
+ case CMD_RET(CMD_BBP_REG_ACCESS):
{
struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
@@ -142,7 +135,7 @@ static int wlan_ret_reg_access(wlan_private * priv,
break;
}
- case cmd_ret_rf_reg_access:
+ case CMD_RET(CMD_RF_REG_ACCESS):
{
struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
@@ -155,7 +148,7 @@ static int wlan_ret_reg_access(wlan_private * priv,
ret = -1;
}
- lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
@@ -166,6 +159,7 @@ static int wlan_ret_get_hw_spec(wlan_private * priv,
struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
wlan_adapter *adapter = priv->adapter;
int ret = 0;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_CMD);
@@ -173,22 +167,23 @@ static int wlan_ret_get_hw_spec(wlan_private * priv,
memcpy(adapter->fwreleasenumber, hwspec->fwreleasenumber, 4);
- lbs_deb_cmd("GET_HW_SPEC: FWReleaseVersion- %u.%u.%u.p%u\n",
+ lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n",
adapter->fwreleasenumber[2], adapter->fwreleasenumber[1],
adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]);
- lbs_deb_cmd("GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
- hwspec->permanentaddr[0], hwspec->permanentaddr[1],
- hwspec->permanentaddr[2], hwspec->permanentaddr[3],
- hwspec->permanentaddr[4], hwspec->permanentaddr[5]);
- lbs_deb_cmd("GET_HW_SPEC: hwifversion=0x%X version=0x%X\n",
+ lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n",
+ print_mac(mac, hwspec->permanentaddr));
+ lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
hwspec->hwifversion, hwspec->version);
- adapter->regioncode = le16_to_cpu(hwspec->regioncode);
+ /* Clamp region code to 8-bit since FW spec indicates that it should
+ * only ever be 8-bit, even though the field size is 16-bit. Some firmware
+ * returns non-zero high 8 bits here.
+ */
+ adapter->regioncode = le16_to_cpu(hwspec->regioncode) & 0xFF;
for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
/* use the region code to search for the index */
if (adapter->regioncode == libertas_region_code_to_index[i]) {
- adapter->regiontableindex = (u16) i;
break;
}
}
@@ -196,7 +191,6 @@ static int wlan_ret_get_hw_spec(wlan_private * priv,
/* if it's unidentified region code, use the default (USA) */
if (i >= MRVDRV_MAX_REGION_CODE) {
adapter->regioncode = 0x10;
- adapter->regiontableindex = 0;
lbs_pr_info("unidentified region code; using the default (USA)\n");
}
@@ -230,8 +224,8 @@ static int wlan_ret_802_11_sleep_params(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- lbs_deb_cmd("error=%x offset=%x stabletime=%x calcontrol=%x\n"
- " extsleepclk=%x\n", le16_to_cpu(sp->error),
+ lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x "
+ "extsleepclk 0x%x\n", le16_to_cpu(sp->error),
le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime),
sp->calcontrol, sp->externalsleepclk);
@@ -249,6 +243,7 @@ static int wlan_ret_802_11_sleep_params(wlan_private * priv,
static int wlan_ret_802_11_stat(wlan_private * priv,
struct cmd_ds_command *resp)
{
+ lbs_deb_enter(LBS_DEB_CMD);
/* currently adapter->wlan802_11Stat is unused
struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
@@ -258,6 +253,7 @@ static int wlan_ret_802_11_stat(wlan_private * priv,
memcpy(&adapter->wlan802_11Stat,
p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
*/
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -270,28 +266,28 @@ static int wlan_ret_802_11_snmp_mib(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- lbs_deb_cmd("SNMP_RESP: value of the oid = %x, querytype=%x\n", oid,
+ lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid,
querytype);
- lbs_deb_cmd("SNMP_RESP: Buf size = %x\n", le16_to_cpu(smib->bufsize));
+ lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize));
- if (querytype == cmd_act_get) {
+ if (querytype == CMD_ACT_GET) {
switch (oid) {
- case fragthresh_i:
+ case FRAGTHRESH_I:
priv->adapter->fragthsd =
le16_to_cpu(*((__le16 *)(smib->value)));
- lbs_deb_cmd("SNMP_RESP: fragthsd =%u\n",
+ lbs_deb_cmd("SNMP_RESP: frag threshold %u\n",
priv->adapter->fragthsd);
break;
- case rtsthresh_i:
+ case RTSTHRESH_I:
priv->adapter->rtsthsd =
le16_to_cpu(*((__le16 *)(smib->value)));
- lbs_deb_cmd("SNMP_RESP: rtsthsd =%u\n",
+ lbs_deb_cmd("SNMP_RESP: rts threshold %u\n",
priv->adapter->rtsthsd);
break;
- case short_retrylim_i:
+ case SHORT_RETRYLIM_I:
priv->adapter->txretrycount =
le16_to_cpu(*((__le16 *)(smib->value)));
- lbs_deb_cmd("SNMP_RESP: txretrycount =%u\n",
+ lbs_deb_cmd("SNMP_RESP: tx retry count %u\n",
priv->adapter->rtsthsd);
break;
default:
@@ -314,18 +310,19 @@ static int wlan_ret_802_11_key_material(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
/* Copy the returned key to driver private data */
- if (action == cmd_act_get) {
+ if (action == CMD_ACT_GET) {
u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
while (buf_ptr < resp_end) {
struct MrvlIEtype_keyParamSet * pkeyparamset =
(struct MrvlIEtype_keyParamSet *) buf_ptr;
- struct WLAN_802_11_KEY * pkey;
- u16 key_info = le16_to_cpu(pkeyparamset->keyinfo);
+ struct enc_key * pkey;
u16 param_set_len = le16_to_cpu(pkeyparamset->length);
- u8 * end;
u16 key_len = le16_to_cpu(pkeyparamset->keylen);
+ u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo);
+ u16 key_type = le16_to_cpu(pkeyparamset->keytypeid);
+ u8 * end;
end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
+ sizeof (pkeyparamset->length)
@@ -334,20 +331,20 @@ static int wlan_ret_802_11_key_material(wlan_private * priv,
if (end > resp_end)
break;
- if (key_info & KEY_INFO_WPA_UNICAST)
+ if (key_flags & KEY_INFO_WPA_UNICAST)
pkey = &adapter->wpa_unicast_key;
- else if (key_info & KEY_INFO_WPA_MCAST)
+ else if (key_flags & KEY_INFO_WPA_MCAST)
pkey = &adapter->wpa_mcast_key;
else
break;
/* Copy returned key into driver */
- memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+ memset(pkey, 0, sizeof(struct enc_key));
if (key_len > sizeof(pkey->key))
break;
- pkey->type = le16_to_cpu(pkeyparamset->keytypeid);
- pkey->flags = le16_to_cpu(pkeyparamset->keyinfo);
- pkey->len = le16_to_cpu(pkeyparamset->keylen);
+ pkey->type = key_type;
+ pkey->flags = key_flags;
+ pkey->len = key_len;
memcpy(pkey->key, pkeyparamset->key, pkey->len);
buf_ptr = end + 1;
@@ -382,28 +379,9 @@ static int wlan_ret_802_11_rf_tx_power(wlan_private * priv,
adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel);
- lbs_deb_cmd("Current TxPower Level = %d\n", adapter->txpowerlevel);
-
- lbs_deb_enter(LBS_DEB_CMD);
- return 0;
-}
-
-static int wlan_ret_802_11_rf_antenna(wlan_private * priv,
- struct cmd_ds_command *resp)
-{
- struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant;
- wlan_adapter *adapter = priv->adapter;
- u16 action = le16_to_cpu(pAntenna->action);
-
- if (action == cmd_act_get_rx)
- adapter->rxantennamode = le16_to_cpu(pAntenna->antennamode);
-
- if (action == cmd_act_get_tx)
- adapter->txantennamode = le16_to_cpu(pAntenna->antennamode);
-
- lbs_deb_cmd("RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n",
- action, le16_to_cpu(pAntenna->antennamode));
+ lbs_deb_cmd("TX power currently %d\n", adapter->txpowerlevel);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -415,12 +393,12 @@ static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- if (rates->action == cmd_act_get) {
+ if (rates->action == CMD_ACT_GET) {
adapter->enablehwauto = le16_to_cpu(rates->enablehwauto);
adapter->ratebitmap = le16_to_cpu(rates->bitmap);
}
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -429,21 +407,19 @@ static int wlan_ret_802_11_data_rate(wlan_private * priv,
{
struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
wlan_adapter *adapter = priv->adapter;
- u8 dot11datarate;
lbs_deb_enter(LBS_DEB_CMD);
- lbs_dbg_hex("DATA_RATE_RESP: data_rate- ",
- (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate));
+ lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate,
+ sizeof(struct cmd_ds_802_11_data_rate));
- dot11datarate = pdatarate->datarate[0];
- if (pdatarate->action == cpu_to_le16(cmd_act_get_tx_rate)) {
- memcpy(adapter->libertas_supported_rates, pdatarate->datarate,
- sizeof(adapter->libertas_supported_rates));
- }
- adapter->datarate = libertas_index_to_data_rate(dot11datarate);
+ /* FIXME: get actual rates FW can do if this command actually returns
+ * all data rates supported.
+ */
+ adapter->cur_rate = libertas_fw_index_to_data_rate(pdatarate->rates[0]);
+ lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", adapter->cur_rate);
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -457,9 +433,9 @@ static int wlan_ret_802_11_rf_channel(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- if (action == cmd_opt_802_11_rf_channel_get
+ if (action == CMD_OPT_802_11_RF_CHANNEL_GET
&& adapter->curbssparams.channel != newchannel) {
- lbs_deb_cmd("channel Switch: %d to %d\n",
+ lbs_deb_cmd("channel switch from %d to %d\n",
adapter->curbssparams.channel, newchannel);
/* Update the channel again */
@@ -476,6 +452,8 @@ static int wlan_ret_802_11_rssi(wlan_private * priv,
struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
wlan_adapter *adapter = priv->adapter;
+ lbs_deb_enter(LBS_DEB_CMD);
+
/* store the non average value */
adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
adapter->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
@@ -491,9 +469,11 @@ static int wlan_ret_802_11_rssi(wlan_private * priv,
CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
- lbs_deb_cmd("Beacon RSSI value = 0x%x\n",
+ lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
+ adapter->RSSI[TYPE_BEACON][TYPE_NOAVG],
adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -504,11 +484,11 @@ static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
struct wlan_ioctl_regrdwr *pbuf;
pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom;
- lbs_deb_cmd("eeprom read len=%x\n",
+ lbs_deb_enter_args(LBS_DEB_CMD, "len %d",
le16_to_cpu(resp->params.rdeeprom.bytecount));
if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
pbuf->NOB = 0;
- lbs_deb_cmd("eeprom read return length is too big\n");
+ lbs_deb_cmd("EEPROM read length too big\n");
return -1;
}
pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
@@ -516,9 +496,10 @@ static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
le16_to_cpu(resp->params.rdeeprom.bytecount));
- lbs_dbg_hex("adapter", (char *)&pbuf->value,
+ lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value,
le16_to_cpu(resp->params.rdeeprom.bytecount));
}
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -533,7 +514,7 @@ static int wlan_ret_get_log(wlan_private * priv,
/* Stored little-endian */
memcpy(&adapter->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -546,12 +527,12 @@ static int libertas_ret_802_11_enable_rsn(wlan_private * priv,
lbs_deb_enter(LBS_DEB_CMD);
- if (enable_rsn->action == cpu_to_le16(cmd_act_get)) {
+ if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) {
if (pdata_buf)
*pdata_buf = (u32) le16_to_cpu(enable_rsn->enable);
}
- lbs_deb_enter(LBS_DEB_CMD);
+ lbs_deb_leave(LBS_DEB_CMD);
return 0;
}
@@ -563,135 +544,134 @@ static inline int handle_cmd_response(u16 respcmd,
unsigned long flags;
wlan_adapter *adapter = priv->adapter;
+ lbs_deb_enter(LBS_DEB_HOST);
+
switch (respcmd) {
- case cmd_ret_mac_reg_access:
- case cmd_ret_bbp_reg_access:
- case cmd_ret_rf_reg_access:
+ case CMD_RET(CMD_MAC_REG_ACCESS):
+ case CMD_RET(CMD_BBP_REG_ACCESS):
+ case CMD_RET(CMD_RF_REG_ACCESS):
ret = wlan_ret_reg_access(priv, respcmd, resp);
break;
- case cmd_ret_hw_spec_info:
+ case CMD_RET(CMD_GET_HW_SPEC):
ret = wlan_ret_get_hw_spec(priv, resp);
break;
- case cmd_ret_802_11_scan:
+ case CMD_RET(CMD_802_11_SCAN):
ret = libertas_ret_80211_scan(priv, resp);
break;
- case cmd_ret_802_11_get_log:
+ case CMD_RET(CMD_802_11_GET_LOG):
ret = wlan_ret_get_log(priv, resp);
break;
- case cmd_ret_802_11_associate:
- case cmd_ret_802_11_reassociate:
+ case CMD_RET_802_11_ASSOCIATE:
+ case CMD_RET(CMD_802_11_ASSOCIATE):
+ case CMD_RET(CMD_802_11_REASSOCIATE):
ret = libertas_ret_80211_associate(priv, resp);
break;
- case cmd_ret_802_11_disassociate:
- case cmd_ret_802_11_deauthenticate:
+ case CMD_RET(CMD_802_11_DISASSOCIATE):
+ case CMD_RET(CMD_802_11_DEAUTHENTICATE):
ret = libertas_ret_80211_disassociate(priv, resp);
break;
- case cmd_ret_802_11_ad_hoc_start:
- case cmd_ret_802_11_ad_hoc_join:
+ case CMD_RET(CMD_802_11_AD_HOC_START):
+ case CMD_RET(CMD_802_11_AD_HOC_JOIN):
ret = libertas_ret_80211_ad_hoc_start(priv, resp);
break;
- case cmd_ret_802_11_stat:
+ case CMD_RET(CMD_802_11_GET_STAT):
ret = wlan_ret_802_11_stat(priv, resp);
break;
- case cmd_ret_802_11_snmp_mib:
+ case CMD_RET(CMD_802_11_SNMP_MIB):
ret = wlan_ret_802_11_snmp_mib(priv, resp);
break;
- case cmd_ret_802_11_rf_tx_power:
+ case CMD_RET(CMD_802_11_RF_TX_POWER):
ret = wlan_ret_802_11_rf_tx_power(priv, resp);
break;
- case cmd_ret_802_11_set_afc:
- case cmd_ret_802_11_get_afc:
+ case CMD_RET(CMD_802_11_SET_AFC):
+ case CMD_RET(CMD_802_11_GET_AFC):
spin_lock_irqsave(&adapter->driver_lock, flags);
memmove(adapter->cur_cmd->pdata_buf, &resp->params.afc,
sizeof(struct cmd_ds_802_11_afc));
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_802_11_rf_antenna:
- ret = wlan_ret_802_11_rf_antenna(priv, resp);
- break;
- case cmd_ret_mac_multicast_adr:
- case cmd_ret_mac_control:
- case cmd_ret_802_11_set_wep:
- case cmd_ret_802_11_reset:
- case cmd_ret_802_11_authenticate:
- case cmd_ret_802_11_radio_control:
- case cmd_ret_802_11_beacon_stop:
+ case CMD_RET(CMD_MAC_MULTICAST_ADR):
+ case CMD_RET(CMD_MAC_CONTROL):
+ case CMD_RET(CMD_802_11_SET_WEP):
+ case CMD_RET(CMD_802_11_RESET):
+ case CMD_RET(CMD_802_11_AUTHENTICATE):
+ case CMD_RET(CMD_802_11_RADIO_CONTROL):
+ case CMD_RET(CMD_802_11_BEACON_STOP):
break;
- case cmd_ret_802_11_enable_rsn:
+ case CMD_RET(CMD_802_11_ENABLE_RSN):
ret = libertas_ret_802_11_enable_rsn(priv, resp);
break;
- case cmd_ret_802_11_data_rate:
+ case CMD_RET(CMD_802_11_DATA_RATE):
ret = wlan_ret_802_11_data_rate(priv, resp);
break;
- case cmd_ret_802_11_rate_adapt_rateset:
+ case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
break;
- case cmd_ret_802_11_rf_channel:
+ case CMD_RET(CMD_802_11_RF_CHANNEL):
ret = wlan_ret_802_11_rf_channel(priv, resp);
break;
- case cmd_ret_802_11_rssi:
+ case CMD_RET(CMD_802_11_RSSI):
ret = wlan_ret_802_11_rssi(priv, resp);
break;
- case cmd_ret_802_11_mac_address:
+ case CMD_RET(CMD_802_11_MAC_ADDRESS):
ret = wlan_ret_802_11_mac_address(priv, resp);
break;
- case cmd_ret_802_11_ad_hoc_stop:
+ case CMD_RET(CMD_802_11_AD_HOC_STOP):
ret = libertas_ret_80211_ad_hoc_stop(priv, resp);
break;
- case cmd_ret_802_11_key_material:
- lbs_deb_cmd("CMD_RESP: KEY_MATERIAL command response\n");
+ case CMD_RET(CMD_802_11_KEY_MATERIAL):
ret = wlan_ret_802_11_key_material(priv, resp);
break;
- case cmd_ret_802_11_eeprom_access:
+ case CMD_RET(CMD_802_11_EEPROM_ACCESS):
ret = wlan_ret_802_11_eeprom_access(priv, resp);
break;
- case cmd_ret_802_11d_domain_info:
+ case CMD_RET(CMD_802_11D_DOMAIN_INFO):
ret = libertas_ret_802_11d_domain_info(priv, resp);
break;
- case cmd_ret_802_11_sleep_params:
+ case CMD_RET(CMD_802_11_SLEEP_PARAMS):
ret = wlan_ret_802_11_sleep_params(priv, resp);
break;
- case cmd_ret_802_11_inactivity_timeout:
+ case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT):
spin_lock_irqsave(&adapter->driver_lock, flags);
*((u16 *) adapter->cur_cmd->pdata_buf) =
le16_to_cpu(resp->params.inactivity_timeout.timeout);
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_802_11_tpc_cfg:
+ case CMD_RET(CMD_802_11_TPC_CFG):
spin_lock_irqsave(&adapter->driver_lock, flags);
memmove(adapter->cur_cmd->pdata_buf, &resp->params.tpccfg,
sizeof(struct cmd_ds_802_11_tpc_cfg));
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_802_11_led_gpio_ctrl:
+ case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
spin_lock_irqsave(&adapter->driver_lock, flags);
memmove(adapter->cur_cmd->pdata_buf, &resp->params.ledgpio,
sizeof(struct cmd_ds_802_11_led_ctrl));
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_802_11_pwr_cfg:
+ case CMD_RET(CMD_802_11_PWR_CFG):
spin_lock_irqsave(&adapter->driver_lock, flags);
memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg,
sizeof(struct cmd_ds_802_11_pwr_cfg));
@@ -699,39 +679,37 @@ static inline int handle_cmd_response(u16 respcmd,
break;
- case cmd_ret_get_tsf:
+ case CMD_RET(CMD_GET_TSF):
spin_lock_irqsave(&adapter->driver_lock, flags);
memcpy(priv->adapter->cur_cmd->pdata_buf,
&resp->params.gettsf.tsfvalue, sizeof(u64));
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_bt_access:
+ case CMD_RET(CMD_BT_ACCESS):
spin_lock_irqsave(&adapter->driver_lock, flags);
if (adapter->cur_cmd->pdata_buf)
memcpy(adapter->cur_cmd->pdata_buf,
&resp->params.bt.addr1, 2 * ETH_ALEN);
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_fwt_access:
+ case CMD_RET(CMD_FWT_ACCESS):
spin_lock_irqsave(&adapter->driver_lock, flags);
if (adapter->cur_cmd->pdata_buf)
memcpy(adapter->cur_cmd->pdata_buf, &resp->params.fwt,
sizeof(resp->params.fwt));
spin_unlock_irqrestore(&adapter->driver_lock, flags);
break;
- case cmd_ret_mesh_access:
+ case CMD_RET(CMD_MESH_ACCESS):
if (adapter->cur_cmd->pdata_buf)
memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh,
sizeof(resp->params.mesh));
break;
- case cmd_rte_802_11_tx_rate_query:
- priv->adapter->txrate = resp->params.txrate.txrate;
- break;
default:
- lbs_deb_cmd("CMD_RESP: Unknown command response %#x\n",
+ lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
resp->command);
break;
}
+ lbs_deb_leave(LBS_DEB_HOST);
return ret;
}
@@ -744,9 +722,7 @@ int libertas_process_rx_command(wlan_private * priv)
ulong flags;
u16 result;
- lbs_deb_enter(LBS_DEB_CMD);
-
- lbs_deb_cmd("CMD_RESP: @ %lu\n", jiffies);
+ lbs_deb_enter(LBS_DEB_HOST);
/* Now we got response from FW, cancel the command timer */
del_timer(&adapter->command_timer);
@@ -755,25 +731,23 @@ int libertas_process_rx_command(wlan_private * priv)
spin_lock_irqsave(&adapter->driver_lock, flags);
if (!adapter->cur_cmd) {
- lbs_deb_cmd("CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd);
+ lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
ret = -1;
spin_unlock_irqrestore(&adapter->driver_lock, flags);
goto done;
}
resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);
- lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr,
- priv->upld_len);
-
respcmd = le16_to_cpu(resp->command);
-
result = le16_to_cpu(resp->result);
- lbs_deb_cmd("CMD_RESP: %x result: %d length: %d\n", respcmd,
- result, priv->upld_len);
+ lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n",
+ respcmd, priv->upld_len, jiffies);
+ lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr,
+ priv->upld_len);
if (!(respcmd & 0x8000)) {
- lbs_deb_cmd("Invalid response to command!");
+ lbs_deb_host("invalid response!\n");
adapter->cur_cmd_retcode = -1;
__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
adapter->nr_cmd_pending--;
@@ -786,16 +760,16 @@ int libertas_process_rx_command(wlan_private * priv)
/* Store the response code to cur_cmd_retcode. */
adapter->cur_cmd_retcode = result;;
- if (respcmd == cmd_ret_802_11_ps_mode) {
+ if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode;
u16 action = le16_to_cpu(psmode->action);
- lbs_deb_cmd(
- "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+ lbs_deb_host(
+ "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
result, action);
if (result) {
- lbs_deb_cmd("CMD_RESP: PS command failed- %#x \n",
+ lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
result);
/*
* We should not re-try enter-ps command in
@@ -803,20 +777,20 @@ int libertas_process_rx_command(wlan_private * priv)
* libertas_execute_next_command().
*/
if (adapter->mode == IW_MODE_ADHOC &&
- action == cmd_subcmd_enter_ps)
- adapter->psmode = wlan802_11powermodecam;
- } else if (action == cmd_subcmd_enter_ps) {
+ action == CMD_SUBCMD_ENTER_PS)
+ adapter->psmode = WLAN802_11POWERMODECAM;
+ } else if (action == CMD_SUBCMD_ENTER_PS) {
adapter->needtowakeup = 0;
adapter->psstate = PS_STATE_AWAKE;
- lbs_deb_cmd("CMD_RESP: Enter_PS command response\n");
- if (adapter->connect_status != libertas_connected) {
+ lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
+ if (adapter->connect_status != LIBERTAS_CONNECTED) {
/*
* When Deauth Event received before Enter_PS command
* response, We need to wake up the firmware.
*/
- lbs_deb_cmd(
- "Disconnected, Going to invoke libertas_ps_wakeup\n");
+ lbs_deb_host(
+ "disconnected, invoking libertas_ps_wakeup\n");
spin_unlock_irqrestore(&adapter->driver_lock, flags);
mutex_unlock(&adapter->lock);
@@ -824,12 +798,12 @@ int libertas_process_rx_command(wlan_private * priv)
mutex_lock(&adapter->lock);
spin_lock_irqsave(&adapter->driver_lock, flags);
}
- } else if (action == cmd_subcmd_exit_ps) {
+ } else if (action == CMD_SUBCMD_EXIT_PS) {
adapter->needtowakeup = 0;
adapter->psstate = PS_STATE_FULL_POWER;
- lbs_deb_cmd("CMD_RESP: Exit_PS command response\n");
+ lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
} else {
- lbs_deb_cmd("CMD_RESP: PS- action=0x%X\n", action);
+ lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
}
__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
@@ -843,22 +817,22 @@ int libertas_process_rx_command(wlan_private * priv)
if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
/* Copy the response back to response buffer */
- memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size);
-
+ memcpy(adapter->cur_cmd->pdata_buf, resp,
+ le16_to_cpu(resp->size));
adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
}
/* If the command is not successful, cleanup and return failure */
if ((result != 0 || !(respcmd & 0x8000))) {
- lbs_deb_cmd("CMD_RESP: command reply %#x result=%#x\n",
- respcmd, result);
+ lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
+ result, respcmd);
/*
* Handling errors here
*/
switch (respcmd) {
- case cmd_ret_hw_spec_info:
- case cmd_ret_802_11_reset:
- lbs_deb_cmd("CMD_RESP: Reset command failed\n");
+ case CMD_RET(CMD_GET_HW_SPEC):
+ case CMD_RET(CMD_802_11_RESET):
+ lbs_deb_host("CMD_RESP: reset failed\n");
break;
}
@@ -888,7 +862,7 @@ int libertas_process_rx_command(wlan_private * priv)
done:
mutex_unlock(&adapter->lock);
- lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
return ret;
}
@@ -898,13 +872,13 @@ int libertas_process_event(wlan_private * priv)
wlan_adapter *adapter = priv->adapter;
u32 eventcause;
+ lbs_deb_enter(LBS_DEB_CMD);
+
spin_lock_irq(&adapter->driver_lock);
eventcause = adapter->eventcause;
spin_unlock_irq(&adapter->driver_lock);
- lbs_deb_enter(LBS_DEB_CMD);
-
- lbs_deb_cmd("EVENT Cause %x\n", eventcause);
+ lbs_deb_cmd("event cause 0x%x\n", eventcause);
switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) {
case MACREG_INT_CODE_LINK_SENSED:
@@ -912,28 +886,27 @@ int libertas_process_event(wlan_private * priv)
break;
case MACREG_INT_CODE_DEAUTHENTICATED:
- lbs_deb_cmd("EVENT: Deauthenticated\n");
+ lbs_deb_cmd("EVENT: deauthenticated\n");
libertas_mac_event_disconnected(priv);
break;
case MACREG_INT_CODE_DISASSOCIATED:
- lbs_deb_cmd("EVENT: Disassociated\n");
+ lbs_deb_cmd("EVENT: disassociated\n");
libertas_mac_event_disconnected(priv);
break;
case MACREG_INT_CODE_LINK_LOSE_NO_SCAN:
- lbs_deb_cmd("EVENT: Link lost\n");
+ lbs_deb_cmd("EVENT: link lost\n");
libertas_mac_event_disconnected(priv);
break;
case MACREG_INT_CODE_PS_SLEEP:
- lbs_deb_cmd("EVENT: SLEEP\n");
- lbs_deb_cmd("_");
+ lbs_deb_cmd("EVENT: sleep\n");
/* handle unexpected PS SLEEP event */
if (adapter->psstate == PS_STATE_FULL_POWER) {
lbs_deb_cmd(
- "EVENT: In FULL POWER mode - ignore PS SLEEP\n");
+ "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
break;
}
adapter->psstate = PS_STATE_PRE_SLEEP;
@@ -943,8 +916,7 @@ int libertas_process_event(wlan_private * priv)
break;
case MACREG_INT_CODE_PS_AWAKE:
- lbs_deb_cmd("EVENT: AWAKE \n");
- lbs_deb_cmd("|");
+ lbs_deb_cmd("EVENT: awake\n");
/* handle unexpected PS AWAKE event */
if (adapter->psstate == PS_STATE_FULL_POWER) {
@@ -962,7 +934,7 @@ int libertas_process_event(wlan_private * priv)
* adapter->needtowakeup will be set to FALSE
* in libertas_ps_wakeup()
*/
- lbs_deb_cmd("Waking up...\n");
+ lbs_deb_cmd("waking up ...\n");
libertas_ps_wakeup(priv, 0);
}
break;
@@ -981,38 +953,43 @@ int libertas_process_event(wlan_private * priv)
break;
case MACREG_INT_CODE_ADHOC_BCN_LOST:
- lbs_deb_cmd("EVENT: HWAC - ADHOC BCN LOST\n");
+ lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
break;
case MACREG_INT_CODE_RSSI_LOW:
- lbs_pr_alert( "EVENT: RSSI_LOW\n");
+ lbs_pr_alert("EVENT: rssi low\n");
break;
case MACREG_INT_CODE_SNR_LOW:
- lbs_pr_alert( "EVENT: SNR_LOW\n");
+ lbs_pr_alert("EVENT: snr low\n");
break;
case MACREG_INT_CODE_MAX_FAIL:
- lbs_pr_alert( "EVENT: MAX_FAIL\n");
+ lbs_pr_alert("EVENT: max fail\n");
break;
case MACREG_INT_CODE_RSSI_HIGH:
- lbs_pr_alert( "EVENT: RSSI_HIGH\n");
+ lbs_pr_alert("EVENT: rssi high\n");
break;
case MACREG_INT_CODE_SNR_HIGH:
- lbs_pr_alert( "EVENT: SNR_HIGH\n");
+ lbs_pr_alert("EVENT: snr high\n");
break;
case MACREG_INT_CODE_MESH_AUTO_STARTED:
- lbs_pr_alert( "EVENT: MESH_AUTO_STARTED\n");
- adapter->connect_status = libertas_connected ;
+ /* Ignore spurious autostart events if autostart is disabled */
+ if (!priv->mesh_autostart_enabled) {
+ lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
+ break;
+ }
+ lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
+ adapter->connect_status = LIBERTAS_CONNECTED;
if (priv->mesh_open == 1) {
- netif_wake_queue(priv->mesh_dev) ;
- netif_carrier_on(priv->mesh_dev) ;
+ netif_wake_queue(priv->mesh_dev);
+ netif_carrier_on(priv->mesh_dev);
}
- adapter->mode = IW_MODE_ADHOC ;
+ adapter->mode = IW_MODE_ADHOC;
schedule_work(&priv->sync_channel);
break;
default:
- lbs_pr_alert( "EVENT: unknown event id: %#x\n",
+ lbs_pr_alert("EVENT: unknown event id 0x%04x\n",
eventcause >> SBI_EVENT_CAUSE_SHIFT);
break;
}
@@ -1021,6 +998,6 @@ int libertas_process_event(wlan_private * priv)
adapter->eventcause = 0;
spin_unlock_irq(&adapter->driver_lock);
- lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
return ret;
}
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 715cbdaa1d4..0bda0b51191 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -3,6 +3,7 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/mm.h>
+#include <linux/string.h>
#include <net/iw_handler.h>
#include "dev.h"
@@ -63,27 +64,27 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
int numscansdone = 0, res;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
+ DECLARE_MAC_BUF(mac);
struct bss_descriptor * iter_bss;
pos += snprintf(buf+pos, len-pos,
- "# | ch | ss | bssid | cap | TSF | Qual | SSID \n");
+ "# | ch | rssi | bssid | cap | Qual | SSID \n");
mutex_lock(&priv->adapter->lock);
list_for_each_entry (iter_bss, &priv->adapter->network_list, list) {
- u16 cap;
+ u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
+ u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
+ u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
- memcpy(&cap, &iter_bss->cap, sizeof(cap));
pos += snprintf(buf+pos, len-pos,
- "%02u| %03d | %03ld | " MAC_FMT " |",
+ "%02u| %03d | %04ld | %s |",
numscansdone, iter_bss->channel, iter_bss->rssi,
- MAC_ARG(iter_bss->bssid));
- pos += snprintf(buf+pos, len-pos, " %04x-", cap);
+ print_mac(mac, iter_bss->bssid));
+ pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
pos += snprintf(buf+pos, len-pos, "%c%c%c |",
- iter_bss->cap.ibss ? 'A' : 'I',
- iter_bss->cap.privacy ? 'P' : ' ',
- iter_bss->cap.spectrummgmt ? 'S' : ' ');
- pos += snprintf(buf+pos, len-pos, " %08llx |", iter_bss->networktsf);
- pos += snprintf(buf+pos, len-pos, " %d |", SCAN_RSSI(iter_bss->rssi));
+ ibss ? 'A' : 'I', privacy ? 'P' : ' ',
+ spectrum_mgmt ? 'S' : ' ');
+ pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
pos += snprintf(buf+pos, len-pos, " %s\n",
escape_essid(iter_bss->ssid, iter_bss->ssid_len));
@@ -125,9 +126,9 @@ static ssize_t libertas_sleepparams_write(struct file *file,
priv->adapter->sp.sp_reserved = p6;
res = libertas_prepare_and_send_command(priv,
- cmd_802_11_sleep_params,
- cmd_act_set,
- cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_SLEEP_PARAMS,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
if (!res)
res = count;
@@ -150,9 +151,9 @@ static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf
char *buf = (char *)addr;
res = libertas_prepare_and_send_command(priv,
- cmd_802_11_sleep_params,
- cmd_act_get,
- cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_SLEEP_PARAMS,
+ CMD_ACT_GET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
if (res) {
res = -EFAULT;
goto out_unlock;
@@ -205,7 +206,7 @@ static int libertas_parse_chan(char *buf, size_t count,
if (!start)
return -EINVAL;
start += 5;
- end = strstr(start, " ");
+ end = strchr(start, ' ');
if (!end)
end = buf + count;
hold = kzalloc((end - start)+1, GFP_KERNEL);
@@ -256,7 +257,7 @@ static void libertas_parse_ssid(char *buf, size_t count,
if (!hold)
return;
hold += 5;
- end = strstr(hold, " ");
+ end = strchr(hold, ' ');
if (!end)
end = buf + count - 1;
@@ -386,7 +387,7 @@ static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
struct cmd_ctrl_node **cmdnode,
struct cmd_ds_command **cmd)
{
- u16 wait_option = cmd_option_waitforrsp;
+ u16 wait_option = CMD_OPTION_WAITFORRSP;
if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
lbs_deb_debugfs("failed libertas_get_free_cmd_ctrl_node\n");
@@ -402,7 +403,7 @@ static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
(*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
(*cmdnode)->cmdwaitqwoken = 0;
*cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
- (*cmd)->command = cpu_to_le16(cmd_802_11_subscribe_event);
+ (*cmd)->command = cpu_to_le16(CMD_802_11_SUBSCRIBE_EVENT);
(*cmd)->seqnum = cpu_to_le16(++priv->adapter->seqnum);
(*cmd)->result = 0;
return 0;
@@ -429,10 +430,10 @@ static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
}
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -447,7 +448,7 @@ static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -493,10 +494,10 @@ static u16 libertas_get_events_bitmap(wlan_private *priv)
return res;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -511,7 +512,7 @@ static u16 libertas_get_events_bitmap(wlan_private *priv)
return 0;
}
- if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ if (le16_to_cpu(pcmdptr->command) != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
return 0;
@@ -559,7 +560,7 @@ static ssize_t libertas_lowrssi_write(struct file *file,
goto out_unlock;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_set);
+ event->action = cpu_to_le16(CMD_ACT_SET);
pcmdptr->size = cpu_to_le16(S_DS_GEN +
sizeof(struct cmd_ds_802_11_subscribe_event) +
sizeof(struct mrvlietypes_rssithreshold));
@@ -575,7 +576,7 @@ static ssize_t libertas_lowrssi_write(struct file *file,
event->events = cpu_to_le16(event_bitmap);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -591,7 +592,7 @@ static ssize_t libertas_lowrssi_write(struct file *file,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -625,10 +626,10 @@ static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
}
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -644,7 +645,7 @@ static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -712,7 +713,7 @@ static ssize_t libertas_lowsnr_write(struct file *file,
goto out_unlock;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_set);
+ event->action = cpu_to_le16(CMD_ACT_SET);
pcmdptr->size = cpu_to_le16(S_DS_GEN +
sizeof(struct cmd_ds_802_11_subscribe_event) +
sizeof(struct mrvlietypes_snrthreshold));
@@ -727,7 +728,7 @@ static ssize_t libertas_lowsnr_write(struct file *file,
event->events = cpu_to_le16(event_bitmap);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -743,7 +744,7 @@ static ssize_t libertas_lowsnr_write(struct file *file,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -778,10 +779,10 @@ static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
}
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -797,7 +798,7 @@ static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -864,7 +865,7 @@ static ssize_t libertas_failcount_write(struct file *file,
goto out_unlock;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_set);
+ event->action = cpu_to_le16(CMD_ACT_SET);
pcmdptr->size = cpu_to_le16(S_DS_GEN +
sizeof(struct cmd_ds_802_11_subscribe_event) +
sizeof(struct mrvlietypes_failurecount));
@@ -879,7 +880,7 @@ static ssize_t libertas_failcount_write(struct file *file,
event->events = cpu_to_le16(event_bitmap);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -895,7 +896,7 @@ static ssize_t libertas_failcount_write(struct file *file,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -929,10 +930,10 @@ static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
}
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -948,7 +949,7 @@ static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
free_page(addr);
kfree(response_buf);
@@ -1015,7 +1016,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file,
goto out_unlock;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_set);
+ event->action = cpu_to_le16(CMD_ACT_SET);
pcmdptr->size = cpu_to_le16(S_DS_GEN +
sizeof(struct cmd_ds_802_11_subscribe_event) +
sizeof(struct mrvlietypes_beaconsmissed));
@@ -1029,7 +1030,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file,
event->events = cpu_to_le16(event_bitmap);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1045,7 +1046,7 @@ static ssize_t libertas_bcnmiss_write(struct file *file,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
free_page(addr);
kfree(response_buf);
@@ -1079,10 +1080,10 @@ static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
}
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1098,7 +1099,7 @@ static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -1166,7 +1167,7 @@ static ssize_t libertas_highrssi_write(struct file *file,
goto out_unlock;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_set);
+ event->action = cpu_to_le16(CMD_ACT_SET);
pcmdptr->size = cpu_to_le16(S_DS_GEN +
sizeof(struct cmd_ds_802_11_subscribe_event) +
sizeof(struct mrvlietypes_rssithreshold));
@@ -1181,7 +1182,7 @@ static ssize_t libertas_highrssi_write(struct file *file,
event->events = cpu_to_le16(event_bitmap);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1196,7 +1197,7 @@ static ssize_t libertas_highrssi_write(struct file *file,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
return 0;
@@ -1229,10 +1230,10 @@ static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
}
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_get);
+ event->action = cpu_to_le16(CMD_ACT_GET);
pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1248,7 +1249,7 @@ static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -1316,7 +1317,7 @@ static ssize_t libertas_highsnr_write(struct file *file,
goto out_unlock;
event = &pcmdptr->params.subscribe_event;
- event->action = cpu_to_le16(cmd_act_set);
+ event->action = cpu_to_le16(CMD_ACT_SET);
pcmdptr->size = cpu_to_le16(S_DS_GEN +
sizeof(struct cmd_ds_802_11_subscribe_event) +
sizeof(struct mrvlietypes_snrthreshold));
@@ -1331,7 +1332,7 @@ static ssize_t libertas_highsnr_write(struct file *file,
event->events = cpu_to_le16(event_bitmap);
libertas_queue_cmd(adapter, pcmdnode, 1);
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
/* Sleep until response is generated by FW */
wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1347,7 +1348,7 @@ static ssize_t libertas_highsnr_write(struct file *file,
return 0;
}
- if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+ if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
lbs_pr_err("command response incorrect!\n");
kfree(response_buf);
free_page(addr);
@@ -1375,8 +1376,8 @@ static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
offval.value = 0;
ret = libertas_prepare_and_send_command(priv,
- cmd_mac_reg_access, 0,
- cmd_option_waitforrsp, 0, &offval);
+ CMD_MAC_REG_ACCESS, 0,
+ CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
priv->mac_offset, adapter->offsetvalue.value);
@@ -1433,8 +1434,8 @@ static ssize_t libertas_wrmac_write(struct file *file,
offval.offset = offset;
offval.value = value;
res = libertas_prepare_and_send_command(priv,
- cmd_mac_reg_access, 1,
- cmd_option_waitforrsp, 0, &offval);
+ CMD_MAC_REG_ACCESS, 1,
+ CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
res = count;
@@ -1458,8 +1459,8 @@ static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
offval.value = 0;
ret = libertas_prepare_and_send_command(priv,
- cmd_bbp_reg_access, 0,
- cmd_option_waitforrsp, 0, &offval);
+ CMD_BBP_REG_ACCESS, 0,
+ CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
priv->bbp_offset, adapter->offsetvalue.value);
@@ -1517,8 +1518,8 @@ static ssize_t libertas_wrbbp_write(struct file *file,
offval.offset = offset;
offval.value = value;
res = libertas_prepare_and_send_command(priv,
- cmd_bbp_reg_access, 1,
- cmd_option_waitforrsp, 0, &offval);
+ CMD_BBP_REG_ACCESS, 1,
+ CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
res = count;
@@ -1542,8 +1543,8 @@ static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
offval.value = 0;
ret = libertas_prepare_and_send_command(priv,
- cmd_rf_reg_access, 0,
- cmd_option_waitforrsp, 0, &offval);
+ CMD_RF_REG_ACCESS, 0,
+ CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
priv->rf_offset, adapter->offsetvalue.value);
@@ -1601,8 +1602,8 @@ static ssize_t libertas_wrrf_write(struct file *file,
offval.offset = offset;
offval.value = value;
res = libertas_prepare_and_send_command(priv,
- cmd_rf_reg_access, 1,
- cmd_option_waitforrsp, 0, &offval);
+ CMD_RF_REG_ACCESS, 1,
+ CMD_OPTION_WAITFORRSP, 0, &offval);
mdelay(10);
res = count;
@@ -1839,7 +1840,7 @@ static ssize_t wlan_debugfs_write(struct file *f, const char __user *buf,
char *p2;
struct debug_data *d = (struct debug_data *)f->private_data;
- pdata = (char *)kmalloc(cnt, GFP_KERNEL);
+ pdata = kmalloc(cnt, GFP_KERNEL);
if (pdata == NULL)
return 0;
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 40f56bb1eac..87fea9d5b90 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -15,14 +15,9 @@ struct wlan_private;
struct sk_buff;
struct net_device;
-extern char *libertas_fw_name;
-
-void libertas_free_adapter(wlan_private * priv);
int libertas_set_mac_packet_filter(wlan_private * priv);
-int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt);
void libertas_send_tx_feedback(wlan_private * priv);
-u8 libertas_check_last_packet_indication(wlan_private * priv);
int libertas_free_cmd_buffer(wlan_private * priv);
struct cmd_ctrl_node;
@@ -44,8 +39,8 @@ int libertas_execute_next_command(wlan_private * priv);
int libertas_process_event(wlan_private * priv);
void libertas_interrupt(struct net_device *);
int libertas_set_radio_control(wlan_private * priv);
-u32 libertas_index_to_data_rate(u8 index);
-u8 libertas_data_rate_to_index(u32 rate);
+u32 libertas_fw_index_to_data_rate(u8 index);
+u8 libertas_data_rate_to_fw_index(u32 rate);
void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen);
void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb);
@@ -53,8 +48,6 @@ void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb);
/** The proc fs interface */
int libertas_process_rx_command(wlan_private * priv);
int libertas_process_tx(wlan_private * priv, struct sk_buff *skb);
-void libertas_cleanup_and_insert_cmd(wlan_private * priv,
- struct cmd_ctrl_node *ptempcmd);
void __libertas_cleanup_and_insert_cmd(wlan_private * priv,
struct cmd_ctrl_node *ptempcmd);
@@ -75,17 +68,15 @@ void libertas_mac_event_disconnected(wlan_private * priv);
void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str);
-/* fw.c */
-int libertas_init_fw(wlan_private * priv, char *fw_name);
-
/* main.c */
struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band,
int *cfp_no);
wlan_private *libertas_add_card(void *card, struct device *dmdev);
-int libertas_activate_card(wlan_private *priv, char *fw_name);
int libertas_remove_card(wlan_private *priv);
+int libertas_start_card(wlan_private *priv);
+int libertas_stop_card(wlan_private *priv);
int libertas_add_mesh(wlan_private *priv, struct device *dev);
void libertas_remove_mesh(wlan_private *priv);
-
+int libertas_reset_device(wlan_private *priv);
#endif /* _WLAN_DECL_H_ */
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 4dd43e59bda..3a0c9beefcf 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -39,47 +39,49 @@
#define LBS_DEB_FW 0x00080000
#define LBS_DEB_THREAD 0x00100000
#define LBS_DEB_HEX 0x00200000
+#define LBS_DEB_SDIO 0x00400000
extern unsigned int libertas_debug;
#ifdef DEBUG
-#define LBS_DEB_LL(grp, fmt, args...) \
+#define LBS_DEB_LL(grp, grpnam, fmt, args...) \
do { if ((libertas_debug & (grp)) == (grp)) \
- printk(KERN_DEBUG DRV_NAME "%s: " fmt, \
+ printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \
in_interrupt() ? " (INT)" : "", ## args); } while (0)
#else
-#define LBS_DEB_LL(grp, fmt, args...) do {} while (0)
+#define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0)
#endif
#define lbs_deb_enter(grp) \
- LBS_DEB_LL(grp | LBS_DEB_ENTER, "%s():%d enter\n", __FUNCTION__, __LINE__);
+ LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s():%d\n", __FUNCTION__, __LINE__);
#define lbs_deb_enter_args(grp, fmt, args...) \
- LBS_DEB_LL(grp | LBS_DEB_ENTER, "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__);
+ LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__);
#define lbs_deb_leave(grp) \
- LBS_DEB_LL(grp | LBS_DEB_LEAVE, "%s():%d leave\n", __FUNCTION__, __LINE__);
+ LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d\n", __FUNCTION__, __LINE__);
#define lbs_deb_leave_args(grp, fmt, args...) \
- LBS_DEB_LL(grp | LBS_DEB_LEAVE, "%s():%d leave, " fmt "\n", \
+ LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d, " fmt "\n", \
__FUNCTION__, __LINE__, ##args);
-#define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, fmt, ##args)
-#define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, fmt, ##args)
-#define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, fmt, ##args)
-#define lbs_deb_wext(fmt, args...) LBS_DEB_LL(LBS_DEB_WEXT, fmt, ##args)
-#define lbs_deb_ioctl(fmt, args...) LBS_DEB_LL(LBS_DEB_IOCTL, fmt, ##args)
-#define lbs_deb_scan(fmt, args...) LBS_DEB_LL(LBS_DEB_SCAN, fmt, ##args)
-#define lbs_deb_assoc(fmt, args...) LBS_DEB_LL(LBS_DEB_ASSOC, fmt, ##args)
-#define lbs_deb_join(fmt, args...) LBS_DEB_LL(LBS_DEB_JOIN, fmt, ##args)
-#define lbs_deb_11d(fmt, args...) LBS_DEB_LL(LBS_DEB_11D, fmt, ##args)
-#define lbs_deb_debugfs(fmt, args...) LBS_DEB_LL(LBS_DEB_DEBUGFS, fmt, ##args)
-#define lbs_deb_ethtool(fmt, args...) LBS_DEB_LL(LBS_DEB_ETHTOOL, fmt, ##args)
-#define lbs_deb_host(fmt, args...) LBS_DEB_LL(LBS_DEB_HOST, fmt, ##args)
-#define lbs_deb_cmd(fmt, args...) LBS_DEB_LL(LBS_DEB_CMD, fmt, ##args)
-#define lbs_deb_rx(fmt, args...) LBS_DEB_LL(LBS_DEB_RX, fmt, ##args)
-#define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, fmt, ##args)
-#define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, fmt, ##args)
-#define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, fmt, ##args)
-#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, "%s:" fmt, (dev)->bus_id, ##args)
-#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, fmt, ##args)
-#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, fmt, ##args)
+#define lbs_deb_main(fmt, args...) LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args)
+#define lbs_deb_net(fmt, args...) LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args)
+#define lbs_deb_mesh(fmt, args...) LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args)
+#define lbs_deb_wext(fmt, args...) LBS_DEB_LL(LBS_DEB_WEXT, " wext", fmt, ##args)
+#define lbs_deb_ioctl(fmt, args...) LBS_DEB_LL(LBS_DEB_IOCTL, " ioctl", fmt, ##args)
+#define lbs_deb_scan(fmt, args...) LBS_DEB_LL(LBS_DEB_SCAN, " scan", fmt, ##args)
+#define lbs_deb_assoc(fmt, args...) LBS_DEB_LL(LBS_DEB_ASSOC, " assoc", fmt, ##args)
+#define lbs_deb_join(fmt, args...) LBS_DEB_LL(LBS_DEB_JOIN, " join", fmt, ##args)
+#define lbs_deb_11d(fmt, args...) LBS_DEB_LL(LBS_DEB_11D, " 11d", fmt, ##args)
+#define lbs_deb_debugfs(fmt, args...) LBS_DEB_LL(LBS_DEB_DEBUGFS, " debugfs", fmt, ##args)
+#define lbs_deb_ethtool(fmt, args...) LBS_DEB_LL(LBS_DEB_ETHTOOL, " ethtool", fmt, ##args)
+#define lbs_deb_host(fmt, args...) LBS_DEB_LL(LBS_DEB_HOST, " host", fmt, ##args)
+#define lbs_deb_cmd(fmt, args...) LBS_DEB_LL(LBS_DEB_CMD, " cmd", fmt, ##args)
+#define lbs_deb_rx(fmt, args...) LBS_DEB_LL(LBS_DEB_RX, " rx", fmt, ##args)
+#define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args)
+#define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args)
+#define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args)
+#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
+#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
+#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
+#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " thread", fmt, ##args)
#define lbs_pr_info(format, args...) \
printk(KERN_INFO DRV_NAME": " format, ## args)
@@ -89,22 +91,28 @@ do { if ((libertas_debug & (grp)) == (grp)) \
printk(KERN_ALERT DRV_NAME": " format, ## args)
#ifdef DEBUG
-static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
+static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
{
int i = 0;
- if (!(libertas_debug & LBS_DEB_HEX))
- return;
-
- printk(KERN_DEBUG "%s: ", prompt);
- for (i = 1; i <= len; i++) {
- printk("%02x ", (u8) * buf);
- buf++;
+ if (len &&
+ (libertas_debug & LBS_DEB_HEX) &&
+ (libertas_debug & grp))
+ {
+ for (i = 1; i <= len; i++) {
+ if ((i & 0xf) == 1) {
+ if (i != 1)
+ printk("\n");
+ printk(DRV_NAME " %s: ", prompt);
+ }
+ printk("%02x ", (u8) * buf);
+ buf++;
+ }
+ printk("\n");
}
- printk("\n");
}
#else
-#define lbs_dbg_hex(x,y,z) do {} while (0)
+#define lbs_deb_hex(grp,prompt,buf,len) do {} while (0)
#endif
@@ -149,17 +157,18 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
#define MRVDRV_CHANNELS_PER_SCAN 4
#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
-#define MRVDRV_DEBUG_RX_PATH 0x00000001
-#define MRVDRV_DEBUG_TX_PATH 0x00000002
-
#define MRVDRV_MIN_BEACON_INTERVAL 20
#define MRVDRV_MAX_BEACON_INTERVAL 1000
#define MRVDRV_BEACON_INTERVAL 100
+#define MARVELL_MESH_IE_LENGTH 9
+
/** INT status Bit Definition*/
-#define his_cmddnldrdy 0x01
-#define his_cardevent 0x02
-#define his_cmdupldrdy 0x04
+#define MRVDRV_TX_DNLD_RDY 0x0001
+#define MRVDRV_RX_UPLD_RDY 0x0002
+#define MRVDRV_CMD_DNLD_RDY 0x0004
+#define MRVDRV_CMD_UPLD_RDY 0x0008
+#define MRVDRV_CARDEVENT 0x0010
#define SBI_EVENT_CAUSE_SHIFT 3
@@ -218,9 +227,6 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
#define CMD_F_HOSTCMD (1 << 0)
#define FW_CAPINFO_WPA (1 << 0)
-/** WPA key LENGTH*/
-#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32
-
#define KEY_LEN_WPA_AES 16
#define KEY_LEN_WPA_TKIP 32
#define KEY_LEN_WEP_104 13
@@ -247,10 +253,7 @@ static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
AVG_SCALE)) / N))
-#define B_SUPPORTED_RATES 8
-#define G_SUPPORTED_RATES 14
-
-#define WLAN_SUPPORTED_RATES 14
+#define MAX_RATES 14
#define MAX_LEDS 8
@@ -264,11 +267,7 @@ typedef struct _wlan_adapter wlan_adapter;
extern const char libertas_driver_version[];
extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE];
-extern u8 libertas_supported_rates[G_SUPPORTED_RATES];
-
-extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES];
-
-extern u8 libertas_adhoc_rates_b[4];
+extern u8 libertas_bg_rates[MAX_RATES];
/** ENUM definition*/
/** SNRNF_TYPE */
@@ -287,11 +286,11 @@ enum SNRNF_DATA {
/** WLAN_802_11_POWER_MODE */
enum WLAN_802_11_POWER_MODE {
- wlan802_11powermodecam,
- wlan802_11powermodemax_psp,
- wlan802_11Powermodefast_psp,
+ WLAN802_11POWERMODECAM,
+ WLAN802_11POWERMODEMAX_PSP,
+ WLAN802_11POWERMODEFAST_PSP,
/*not a real mode, defined as an upper bound */
- wlan802_11powemodemax
+ WLAN802_11POWEMODEMAX
};
/** PS_STATE */
@@ -311,14 +310,14 @@ enum DNLD_STATE {
/** WLAN_MEDIA_STATE */
enum WLAN_MEDIA_STATE {
- libertas_connected,
- libertas_disconnected
+ LIBERTAS_CONNECTED,
+ LIBERTAS_DISCONNECTED
};
/** WLAN_802_11_PRIVACY_FILTER */
enum WLAN_802_11_PRIVACY_FILTER {
- wlan802_11privfilteracceptall,
- wlan802_11privfilter8021xWEP
+ WLAN802_11PRIVFILTERACCEPTALL,
+ WLAN802_11PRIVFILTER8021XWEP
};
/** mv_ms_type */
@@ -331,23 +330,23 @@ enum mv_ms_type {
/** SNMP_MIB_INDEX_e */
enum SNMP_MIB_INDEX_e {
- desired_bsstype_i = 0,
- op_rateset_i,
- bcnperiod_i,
- dtimperiod_i,
- assocrsp_timeout_i,
- rtsthresh_i,
- short_retrylim_i,
- long_retrylim_i,
- fragthresh_i,
- dot11d_i,
- dot11h_i,
- manufid_i,
- prodID_i,
- manuf_oui_i,
- manuf_name_i,
- manuf_prodname_i,
- manuf_prodver_i,
+ DESIRED_BSSTYPE_I = 0,
+ OP_RATESET_I,
+ BCNPERIOD_I,
+ DTIMPERIOD_I,
+ ASSOCRSP_TIMEOUT_I,
+ RTSTHRESH_I,
+ SHORT_RETRYLIM_I,
+ LONG_RETRYLIM_I,
+ FRAGTHRESH_I,
+ DOT11D_I,
+ DOT11H_I,
+ MANUFID_I,
+ PRODID_I,
+ MANUF_OUI_I,
+ MANUF_NAME_I,
+ MANUF_PRODNAME_I,
+ MANUF_PRODVER_I,
};
/** KEY_TYPE_ID */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 785192b884b..1fb807aa91b 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -14,7 +14,6 @@
#include "defs.h"
#include "scan.h"
-#include "thread.h"
extern struct ethtool_ops libertas_ethtool_ops;
@@ -73,10 +72,8 @@ struct current_bss_params {
u8 band;
/** channel */
u8 channel;
- /** number of rates supported */
- int numofrates;
- /** supported rates*/
- u8 datarates[WLAN_SUPPORTED_RATES];
+ /** zero-terminated array of supported data rates */
+ u8 rates[MAX_RATES + 1];
};
/** sleep_params */
@@ -106,6 +103,8 @@ struct _wlan_private {
int open;
int mesh_open;
int infra_open;
+ int mesh_autostart_enabled;
+ __le16 boot2_version;
char name[DEV_NAME_LEN];
@@ -114,7 +113,9 @@ struct _wlan_private {
struct net_device *dev;
struct net_device_stats stats;
- struct net_device *mesh_dev ; /* Virtual device */
+ struct net_device *mesh_dev; /* Virtual device */
+ struct net_device *rtap_net_dev;
+ struct ieee80211_device *ieee;
struct iw_statistics wstats;
struct wlan_mesh_stats mstats;
@@ -142,20 +143,18 @@ struct _wlan_private {
all other bits reserved 0 */
u8 dnld_sent;
- const struct firmware *firmware;
struct device *hotplug_device;
/** thread to service interrupts */
- struct wlan_thread mainthread;
+ struct task_struct *main_thread;
+ wait_queue_head_t waitq;
+ struct workqueue_struct *work_thread;
+ struct delayed_work scan_work;
struct delayed_work assoc_work;
- struct workqueue_struct *assoc_thread;
struct work_struct sync_channel;
/** Hardware access */
- int (*hw_register_dev) (wlan_private * priv);
- int (*hw_unregister_dev) (wlan_private *);
- int (*hw_prog_firmware) (wlan_private *);
int (*hw_host_to_card) (wlan_private * priv, u8 type, u8 * payload, u16 nb);
int (*hw_get_int_status) (wlan_private * priv, u8 *);
int (*hw_read_event_cause) (wlan_private *);
@@ -188,12 +187,12 @@ struct assoc_request {
u8 bssid[ETH_ALEN];
/** WEP keys */
- struct WLAN_802_11_KEY wep_keys[4];
+ struct enc_key wep_keys[4];
u16 wep_tx_keyidx;
/** WPA keys */
- struct WLAN_802_11_KEY wpa_mcast_key;
- struct WLAN_802_11_KEY wpa_unicast_key;
+ struct enc_key wpa_mcast_key;
+ struct enc_key wpa_unicast_key;
struct wlan_802_11_security secinfo;
@@ -259,23 +258,15 @@ struct _wlan_adapter {
/* IW_MODE_* */
u8 mode;
- u8 prev_ssid[IW_ESSID_MAX_SIZE + 1];
- u8 prev_ssid_len;
- u8 prev_bssid[ETH_ALEN];
-
/* Scan results list */
struct list_head network_list;
struct list_head network_free_list;
struct bss_descriptor *networks;
- u8 scantype;
- u32 scanmode;
-
- u16 beaconperiod;
u8 adhoccreate;
/** capability Info used in Association, start, join */
- struct ieeetypes_capinfo capinfo;
+ u16 capability;
/** MAC address information */
u8 current_addr[ETH_ALEN];
@@ -287,20 +278,10 @@ struct _wlan_adapter {
u16 enablehwauto;
u16 ratebitmap;
- /** control G rates */
- u8 adhoc_grate_enabled;
-
- u32 txantenna;
- u32 rxantenna;
u32 fragthsd;
u32 rtsthsd;
- u32 datarate;
- u8 is_datarate_auto;
-
- u16 listeninterval;
- u16 prescan;
u8 txretrycount;
/** Tx-related variables (for single packet tx) */
@@ -311,22 +292,17 @@ struct _wlan_adapter {
u16 currentpacketfilter;
u32 connect_status;
u16 regioncode;
- u16 regiontableindex;
u16 txpowerlevel;
/** POWER MANAGEMENT AND PnP SUPPORT */
u8 surpriseremoved;
- u16 atimwindow;
u16 psmode; /* Wlan802_11PowermodeCAM=disable
Wlan802_11PowermodeMAX_PSP=enable */
- u16 multipledtim;
u32 psstate;
u8 needtowakeup;
struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep;
- u16 locallisteninterval;
- u16 nullpktinterval;
struct assoc_request * pending_assoc_req;
struct assoc_request * in_progress_assoc_req;
@@ -335,23 +311,18 @@ struct _wlan_adapter {
struct wlan_802_11_security secinfo;
/** WEP keys */
- struct WLAN_802_11_KEY wep_keys[4];
+ struct enc_key wep_keys[4];
u16 wep_tx_keyidx;
/** WPA keys */
- struct WLAN_802_11_KEY wpa_mcast_key;
- struct WLAN_802_11_KEY wpa_unicast_key;
+ struct enc_key wpa_mcast_key;
+ struct enc_key wpa_unicast_key;
/** WPA Information Elements*/
u8 wpa_ie[MAX_WPA_IE_LEN];
u8 wpa_ie_len;
- u16 rxantennamode;
- u16 txantennamode;
-
/** Requested Signal Strength*/
- u16 bcn_avg_factor;
- u16 data_avg_factor;
u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
@@ -359,15 +330,13 @@ struct _wlan_adapter {
u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
u16 nextSNRNF;
u16 numSNRNF;
- u16 rxpd_rate;
u8 radioon;
u32 preamble;
- /** Multi bands Parameter*/
- u8 libertas_supported_rates[G_SUPPORTED_RATES];
-
- /** Blue Tooth Co-existence Arbitration */
+ /** data rate stuff */
+ u8 cur_rate;
+ u8 auto_rate;
/** sleep_params */
struct sleep_params sp;
@@ -392,14 +361,8 @@ struct _wlan_adapter {
struct wlan_offset_value offsetvalue;
struct cmd_ds_802_11_get_log logmsg;
- u16 scanprobes;
-
- u32 pkttxctrl;
- u16 txrate;
- u32 linkmode;
- u32 radiomode;
- u32 debugmode;
+ u32 monitormode;
u8 fw_ready;
u8 last_scanned_channel;
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 96f1974685d..3dae15211b6 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -60,8 +60,7 @@ static int libertas_ethtool_get_eeprom(struct net_device *dev,
// mutex_lock(&priv->mutex);
- adapter->prdeeprom =
- (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
+ adapter->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
if (!adapter->prdeeprom)
return -ENOMEM;
memcpy(adapter->prdeeprom, &regctrl, sizeof(regctrl));
@@ -72,9 +71,9 @@ static int libertas_ethtool_get_eeprom(struct net_device *dev,
regctrl.action, regctrl.offset, regctrl.NOB);
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_eeprom_access,
+ CMD_802_11_EEPROM_ACCESS,
regctrl.action,
- cmd_option_waitforrsp, 0,
+ CMD_OPTION_WAITFORRSP, 0,
&regctrl);
if (ret) {
@@ -110,56 +109,48 @@ static void libertas_ethtool_get_stats(struct net_device * dev,
struct ethtool_stats * stats, u64 * data)
{
wlan_private *priv = dev->priv;
+ struct cmd_ds_mesh_access mesh_access;
+ int ret;
lbs_deb_enter(LBS_DEB_ETHTOOL);
- stats->cmd = ETHTOOL_GSTATS;
- BUG_ON(stats->n_stats != MESH_STATS_NUM);
-
- data[0] = priv->mstats.fwd_drop_rbt;
- data[1] = priv->mstats.fwd_drop_ttl;
- data[2] = priv->mstats.fwd_drop_noroute;
- data[3] = priv->mstats.fwd_drop_nobuf;
- data[4] = priv->mstats.fwd_unicast_cnt;
- data[5] = priv->mstats.fwd_bcast_cnt;
- data[6] = priv->mstats.drop_blind;
- data[7] = priv->mstats.tx_failed_cnt;
+ /* Get Mesh Statistics */
+ ret = libertas_prepare_and_send_command(priv,
+ CMD_MESH_ACCESS, CMD_ACT_MESH_GET_STATS,
+ CMD_OPTION_WAITFORRSP, 0, &mesh_access);
+
+ if (ret)
+ return;
+
+ priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
+ priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
+ priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
+ priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
+ priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
+ priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
+ priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
+ priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
+
+ data[0] = priv->mstats.fwd_drop_rbt;
+ data[1] = priv->mstats.fwd_drop_ttl;
+ data[2] = priv->mstats.fwd_drop_noroute;
+ data[3] = priv->mstats.fwd_drop_nobuf;
+ data[4] = priv->mstats.fwd_unicast_cnt;
+ data[5] = priv->mstats.fwd_bcast_cnt;
+ data[6] = priv->mstats.drop_blind;
+ data[7] = priv->mstats.tx_failed_cnt;
lbs_deb_enter(LBS_DEB_ETHTOOL);
}
-static int libertas_ethtool_get_stats_count(struct net_device * dev)
+static int libertas_ethtool_get_sset_count(struct net_device * dev, int sset)
{
- int ret;
- wlan_private *priv = dev->priv;
- struct cmd_ds_mesh_access mesh_access;
-
- lbs_deb_enter(LBS_DEB_ETHTOOL);
-
- /* Get Mesh Statistics */
- ret = libertas_prepare_and_send_command(priv,
- cmd_mesh_access, cmd_act_mesh_get_stats,
- cmd_option_waitforrsp, 0, &mesh_access);
-
- if (ret) {
- ret = 0;
- goto done;
+ switch (sset) {
+ case ETH_SS_STATS:
+ return MESH_STATS_NUM;
+ default:
+ return -EOPNOTSUPP;
}
-
- priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
- priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
- priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
- priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
- priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
- priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
- priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
- priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
-
- ret = MESH_STATS_NUM;
-
-done:
- lbs_deb_enter_args(LBS_DEB_ETHTOOL, "ret %d", ret);
- return ret;
}
static void libertas_ethtool_get_strings (struct net_device * dev,
@@ -186,7 +177,7 @@ struct ethtool_ops libertas_ethtool_ops = {
.get_drvinfo = libertas_ethtool_get_drvinfo,
.get_eeprom = libertas_ethtool_get_eeprom,
.get_eeprom_len = libertas_ethtool_get_eeprom_len,
- .get_stats_count = libertas_ethtool_get_stats_count,
+ .get_sset_count = libertas_ethtool_get_sset_count,
.get_ethtool_stats = libertas_ethtool_get_stats,
.get_strings = libertas_ethtool_get_strings,
};
diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c
deleted file mode 100644
index 2dc84ff7a54..00000000000
--- a/drivers/net/wireless/libertas/fw.c
+++ /dev/null
@@ -1,349 +0,0 @@
-/**
- * This file contains the initialization for FW and HW
- */
-#include <linux/firmware.h>
-
-#include "host.h"
-#include "defs.h"
-#include "decl.h"
-#include "dev.h"
-#include "wext.h"
-#include "if_usb.h"
-
-/**
- * @brief This function checks the validity of Boot2/FW image.
- *
- * @param data pointer to image
- * len image length
- * @return 0 or -1
- */
-static int check_fwfile_format(u8 *data, u32 totlen)
-{
- u32 bincmd, exit;
- u32 blksize, offset, len;
- int ret;
-
- ret = 1;
- exit = len = 0;
-
- do {
- struct fwheader *fwh = (void *)data;
-
- bincmd = le32_to_cpu(fwh->dnldcmd);
- blksize = le32_to_cpu(fwh->datalength);
- switch (bincmd) {
- case FW_HAS_DATA_TO_RECV:
- offset = sizeof(struct fwheader) + blksize;
- data += offset;
- len += offset;
- if (len >= totlen)
- exit = 1;
- break;
- case FW_HAS_LAST_BLOCK:
- exit = 1;
- ret = 0;
- break;
- default:
- exit = 1;
- break;
- }
- } while (!exit);
-
- if (ret)
- lbs_pr_err("firmware file format check FAIL\n");
- else
- lbs_deb_fw("firmware file format check PASS\n");
-
- return ret;
-}
-
-/**
- * @brief This function downloads firmware image, gets
- * HW spec from firmware and set basic parameters to
- * firmware.
- *
- * @param priv A pointer to wlan_private structure
- * @return 0 or -1
- */
-static int wlan_setup_station_hw(wlan_private * priv, char *fw_name)
-{
- int ret = -1;
- wlan_adapter *adapter = priv->adapter;
-
- lbs_deb_enter(LBS_DEB_FW);
-
- if ((ret = request_firmware(&priv->firmware, fw_name,
- priv->hotplug_device)) < 0) {
- lbs_pr_err("request_firmware() failed with %#x\n", ret);
- lbs_pr_err("firmware %s not found\n", fw_name);
- goto done;
- }
-
- if (check_fwfile_format(priv->firmware->data, priv->firmware->size)) {
- release_firmware(priv->firmware);
- goto done;
- }
-
- ret = priv->hw_prog_firmware(priv);
-
- release_firmware(priv->firmware);
-
- if (ret) {
- lbs_deb_fw("bootloader in invalid state\n");
- ret = -1;
- goto done;
- }
-
- /*
- * Read MAC address from HW
- */
- memset(adapter->current_addr, 0xff, ETH_ALEN);
-
- ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec,
- 0, cmd_option_waitforrsp, 0, NULL);
-
- if (ret) {
- ret = -1;
- goto done;
- }
-
- libertas_set_mac_packet_filter(priv);
-
- /* Get the supported Data rates */
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
- cmd_act_get_tx_rate,
- cmd_option_waitforrsp, 0, NULL);
-
- if (ret) {
- ret = -1;
- goto done;
- }
-
- ret = 0;
-done:
- lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
- return ret;
-}
-
-static int wlan_allocate_adapter(wlan_private * priv)
-{
- size_t bufsize;
- wlan_adapter *adapter = priv->adapter;
-
- /* Allocate buffer to store the BSSID list */
- bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
- adapter->networks = kzalloc(bufsize, GFP_KERNEL);
- if (!adapter->networks) {
- lbs_pr_err("Out of memory allocating beacons\n");
- libertas_free_adapter(priv);
- return -ENOMEM;
- }
-
- /* Allocate the command buffers */
- libertas_allocate_cmd_buffer(priv);
-
- memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep));
- adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
- adapter->libertas_ps_confirm_sleep.command =
- cpu_to_le16(cmd_802_11_ps_mode);
- adapter->libertas_ps_confirm_sleep.size =
- cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
- adapter->libertas_ps_confirm_sleep.result = 0;
- adapter->libertas_ps_confirm_sleep.action =
- cpu_to_le16(cmd_subcmd_sleep_confirmed);
-
- return 0;
-}
-
-static void wlan_init_adapter(wlan_private * priv)
-{
- wlan_adapter *adapter = priv->adapter;
- int i;
-
- adapter->scanprobes = 0;
-
- adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
- adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
-
- /* ATIM params */
- adapter->atimwindow = 0;
-
- adapter->connect_status = libertas_disconnected;
- memset(adapter->current_addr, 0xff, ETH_ALEN);
-
- /* scan type */
- adapter->scantype = cmd_scan_type_active;
-
- /* scan mode */
- adapter->scanmode = cmd_bss_type_any;
-
- /* 802.11 specific */
- adapter->secinfo.wep_enabled = 0;
- for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]);
- i++)
- memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY));
- adapter->wep_tx_keyidx = 0;
- adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
- adapter->mode = IW_MODE_INFRA;
-
- adapter->pending_assoc_req = NULL;
- adapter->in_progress_assoc_req = NULL;
-
- /* Initialize scan result lists */
- INIT_LIST_HEAD(&adapter->network_free_list);
- INIT_LIST_HEAD(&adapter->network_list);
- for (i = 0; i < MAX_NETWORK_COUNT; i++) {
- list_add_tail(&adapter->networks[i].list,
- &adapter->network_free_list);
- }
-
- mutex_init(&adapter->lock);
-
- adapter->prescan = 1;
-
- memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
- adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
-
- /* PnP and power profile */
- adapter->surpriseremoved = 0;
-
- adapter->currentpacketfilter =
- cmd_act_mac_rx_on | cmd_act_mac_tx_on;
-
- adapter->radioon = RADIO_ON;
- adapter->txantenna = RF_ANTENNA_2;
- adapter->rxantenna = RF_ANTENNA_AUTO;
-
- adapter->is_datarate_auto = 1;
- adapter->beaconperiod = MRVDRV_BEACON_INTERVAL;
-
- // set default value of capinfo.
-#define SHORT_PREAMBLE_ALLOWED 1
- memset(&adapter->capinfo, 0, sizeof(adapter->capinfo));
- adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED;
-
- adapter->psmode = wlan802_11powermodecam;
- adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
-
- adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
-
- adapter->psstate = PS_STATE_FULL_POWER;
- adapter->needtowakeup = 0;
- adapter->locallisteninterval = 0; /* default value in firmware will be used */
-
- adapter->datarate = 0; // Initially indicate the rate as auto
-
- adapter->adhoc_grate_enabled = 0;
-
- adapter->intcounter = 0;
-
- adapter->currenttxskb = NULL;
- adapter->pkttxctrl = 0;
-
- memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
- adapter->tx_queue_idx = 0;
- spin_lock_init(&adapter->txqueue_lock);
-
- return;
-}
-
-static void command_timer_fn(unsigned long data);
-
-int libertas_init_fw(wlan_private * priv, char *fw_name)
-{
- int ret = -1;
- wlan_adapter *adapter = priv->adapter;
-
- lbs_deb_enter(LBS_DEB_FW);
-
- /* Allocate adapter structure */
- if ((ret = wlan_allocate_adapter(priv)) != 0)
- goto done;
-
- /* init adapter structure */
- wlan_init_adapter(priv);
-
- /* init timer etc. */
- setup_timer(&adapter->command_timer, command_timer_fn,
- (unsigned long)priv);
-
- /* download fimrware etc. */
- if ((ret = wlan_setup_station_hw(priv, fw_name)) != 0) {
- del_timer_sync(&adapter->command_timer);
- goto done;
- }
-
- /* init 802.11d */
- libertas_init_11d(priv);
-
- ret = 0;
-done:
- lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
- return ret;
-}
-
-void libertas_free_adapter(wlan_private * priv)
-{
- wlan_adapter *adapter = priv->adapter;
-
- if (!adapter) {
- lbs_deb_fw("why double free adapter?\n");
- return;
- }
-
- lbs_deb_fw("free command buffer\n");
- libertas_free_cmd_buffer(priv);
-
- lbs_deb_fw("free command_timer\n");
- del_timer(&adapter->command_timer);
-
- lbs_deb_fw("free scan results table\n");
- kfree(adapter->networks);
- adapter->networks = NULL;
-
- /* Free the adapter object itself */
- lbs_deb_fw("free adapter\n");
- kfree(adapter);
- priv->adapter = NULL;
-}
-
-/**
- * This function handles the timeout of command sending.
- * It will re-send the same command again.
- */
-static void command_timer_fn(unsigned long data)
-{
- wlan_private *priv = (wlan_private *)data;
- wlan_adapter *adapter = priv->adapter;
- struct cmd_ctrl_node *ptempnode;
- struct cmd_ds_command *cmd;
- unsigned long flags;
-
- ptempnode = adapter->cur_cmd;
- if (ptempnode == NULL) {
- lbs_deb_fw("ptempnode empty\n");
- return;
- }
-
- cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
- if (!cmd) {
- lbs_deb_fw("cmd is NULL\n");
- return;
- }
-
- lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command);
-
- if (!adapter->fw_ready)
- return;
-
- spin_lock_irqsave(&adapter->driver_lock, flags);
- adapter->cur_cmd = NULL;
- spin_unlock_irqrestore(&adapter->driver_lock, flags);
-
- lbs_deb_fw("re-sending same command because of timeout\n");
- libertas_queue_cmd(adapter, ptempnode, 0);
-
- wake_up_interruptible(&priv->mainthread.waitq);
-
- return;
-}
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 7509cc10af3..b37ddbca969 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -20,224 +20,163 @@
#define OID_802_11_TX_RETRYCOUNT 0x0000801D
#define OID_802_11D_ENABLE 0x00008020
-#define cmd_option_waitforrsp 0x0002
+#define CMD_OPTION_WAITFORRSP 0x0002
-/** Host command ID */
-#define cmd_code_dnld 0x0002
-#define cmd_get_hw_spec 0x0003
-#define cmd_eeprom_update 0x0004
-#define cmd_802_11_reset 0x0005
-#define cmd_802_11_scan 0x0006
-#define cmd_802_11_get_log 0x000b
-#define cmd_mac_multicast_adr 0x0010
-#define cmd_802_11_authenticate 0x0011
-#define cmd_802_11_eeprom_access 0x0059
-#define cmd_802_11_associate 0x0050
-#define cmd_802_11_set_wep 0x0013
-#define cmd_802_11_get_stat 0x0014
-#define cmd_802_3_get_stat 0x0015
-#define cmd_802_11_snmp_mib 0x0016
-#define cmd_mac_reg_map 0x0017
-#define cmd_bbp_reg_map 0x0018
-#define cmd_mac_reg_access 0x0019
-#define cmd_bbp_reg_access 0x001a
-#define cmd_rf_reg_access 0x001b
-#define cmd_802_11_radio_control 0x001c
-#define cmd_802_11_rf_channel 0x001d
-#define cmd_802_11_rf_tx_power 0x001e
-#define cmd_802_11_rssi 0x001f
-#define cmd_802_11_rf_antenna 0x0020
+/** Host command IDs */
-#define cmd_802_11_ps_mode 0x0021
+/* Return command are almost always the same as the host command, but with
+ * bit 15 set high. There are a few exceptions, though...
+ */
+#define CMD_RET(cmd) (0x8000 | cmd)
-#define cmd_802_11_data_rate 0x0022
-#define cmd_rf_reg_map 0x0023
-#define cmd_802_11_deauthenticate 0x0024
-#define cmd_802_11_reassociate 0x0025
-#define cmd_802_11_disassociate 0x0026
-#define cmd_mac_control 0x0028
-#define cmd_802_11_ad_hoc_start 0x002b
-#define cmd_802_11_ad_hoc_join 0x002c
+/* Return command convention exceptions: */
+#define CMD_RET_802_11_ASSOCIATE 0x8012
-#define cmd_802_11_query_tkip_reply_cntrs 0x002e
-#define cmd_802_11_enable_rsn 0x002f
-#define cmd_802_11_pairwise_tsc 0x0036
-#define cmd_802_11_group_tsc 0x0037
-#define cmd_802_11_key_material 0x005e
+/* Command codes */
+#define CMD_CODE_DNLD 0x0002
+#define CMD_GET_HW_SPEC 0x0003
+#define CMD_EEPROM_UPDATE 0x0004
+#define CMD_802_11_RESET 0x0005
+#define CMD_802_11_SCAN 0x0006
+#define CMD_802_11_GET_LOG 0x000b
+#define CMD_MAC_MULTICAST_ADR 0x0010
+#define CMD_802_11_AUTHENTICATE 0x0011
+#define CMD_802_11_EEPROM_ACCESS 0x0059
+#define CMD_802_11_ASSOCIATE 0x0050
+#define CMD_802_11_SET_WEP 0x0013
+#define CMD_802_11_GET_STAT 0x0014
+#define CMD_802_3_GET_STAT 0x0015
+#define CMD_802_11_SNMP_MIB 0x0016
+#define CMD_MAC_REG_MAP 0x0017
+#define CMD_BBP_REG_MAP 0x0018
+#define CMD_MAC_REG_ACCESS 0x0019
+#define CMD_BBP_REG_ACCESS 0x001a
+#define CMD_RF_REG_ACCESS 0x001b
+#define CMD_802_11_RADIO_CONTROL 0x001c
+#define CMD_802_11_RF_CHANNEL 0x001d
+#define CMD_802_11_RF_TX_POWER 0x001e
+#define CMD_802_11_RSSI 0x001f
+#define CMD_802_11_RF_ANTENNA 0x0020
-#define cmd_802_11_set_afc 0x003c
-#define cmd_802_11_get_afc 0x003d
+#define CMD_802_11_PS_MODE 0x0021
-#define cmd_802_11_ad_hoc_stop 0x0040
+#define CMD_802_11_DATA_RATE 0x0022
+#define CMD_RF_REG_MAP 0x0023
+#define CMD_802_11_DEAUTHENTICATE 0x0024
+#define CMD_802_11_REASSOCIATE 0x0025
+#define CMD_802_11_DISASSOCIATE 0x0026
+#define CMD_MAC_CONTROL 0x0028
+#define CMD_802_11_AD_HOC_START 0x002b
+#define CMD_802_11_AD_HOC_JOIN 0x002c
-#define cmd_802_11_beacon_stop 0x0049
+#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e
+#define CMD_802_11_ENABLE_RSN 0x002f
+#define CMD_802_11_PAIRWISE_TSC 0x0036
+#define CMD_802_11_GROUP_TSC 0x0037
+#define CMD_802_11_KEY_MATERIAL 0x005e
-#define cmd_802_11_mac_address 0x004D
-#define cmd_802_11_eeprom_access 0x0059
+#define CMD_802_11_SET_AFC 0x003c
+#define CMD_802_11_GET_AFC 0x003d
-#define cmd_802_11_band_config 0x0058
+#define CMD_802_11_AD_HOC_STOP 0x0040
-#define cmd_802_11d_domain_info 0x005b
+#define CMD_802_11_BEACON_STOP 0x0049
-#define cmd_802_11_sleep_params 0x0066
+#define CMD_802_11_MAC_ADDRESS 0x004D
+#define CMD_802_11_EEPROM_ACCESS 0x0059
-#define cmd_802_11_inactivity_timeout 0x0067
+#define CMD_802_11_BAND_CONFIG 0x0058
-#define cmd_802_11_tpc_cfg 0x0072
-#define cmd_802_11_pwr_cfg 0x0073
+#define CMD_802_11D_DOMAIN_INFO 0x005b
-#define cmd_802_11_led_gpio_ctrl 0x004e
+#define CMD_802_11_SLEEP_PARAMS 0x0066
-#define cmd_802_11_subscribe_event 0x0075
+#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067
-#define cmd_802_11_rate_adapt_rateset 0x0076
+#define CMD_802_11_TPC_CFG 0x0072
+#define CMD_802_11_PWR_CFG 0x0073
-#define cmd_802_11_tx_rate_query 0x007f
+#define CMD_802_11_LED_GPIO_CTRL 0x004e
-#define cmd_get_tsf 0x0080
+#define CMD_802_11_SUBSCRIBE_EVENT 0x0075
-#define cmd_bt_access 0x0087
-#define cmd_ret_bt_access 0x8087
+#define CMD_802_11_RATE_ADAPT_RATESET 0x0076
-#define cmd_fwt_access 0x0095
-#define cmd_ret_fwt_access 0x8095
+#define CMD_802_11_TX_RATE_QUERY 0x007f
-#define cmd_mesh_access 0x009b
-#define cmd_ret_mesh_access 0x809b
+#define CMD_GET_TSF 0x0080
+
+#define CMD_BT_ACCESS 0x0087
+
+#define CMD_FWT_ACCESS 0x0095
+
+#define CMD_802_11_MONITOR_MODE 0x0098
+
+#define CMD_MESH_ACCESS 0x009b
+
+#define CMD_SET_BOOT2_VER 0x00a5
/* For the IEEE Power Save */
-#define cmd_subcmd_enter_ps 0x0030
-#define cmd_subcmd_exit_ps 0x0031
-#define cmd_subcmd_sleep_confirmed 0x0034
-#define cmd_subcmd_full_powerdown 0x0035
-#define cmd_subcmd_full_powerup 0x0036
+#define CMD_SUBCMD_ENTER_PS 0x0030
+#define CMD_SUBCMD_EXIT_PS 0x0031
+#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034
+#define CMD_SUBCMD_FULL_POWERDOWN 0x0035
+#define CMD_SUBCMD_FULL_POWERUP 0x0036
+
+#define CMD_ENABLE_RSN 0x0001
+#define CMD_DISABLE_RSN 0x0000
+
+#define CMD_ACT_SET 0x0001
+#define CMD_ACT_GET 0x0000
+
+#define CMD_ACT_GET_AES (CMD_ACT_GET + 2)
+#define CMD_ACT_SET_AES (CMD_ACT_SET + 2)
+#define CMD_ACT_REMOVE_AES (CMD_ACT_SET + 3)
+
+/* Define action or option for CMD_802_11_SET_WEP */
+#define CMD_ACT_ADD 0x0002
+#define CMD_ACT_REMOVE 0x0004
+#define CMD_ACT_USE_DEFAULT 0x0008
+
+#define CMD_TYPE_WEP_40_BIT 0x01
+#define CMD_TYPE_WEP_104_BIT 0x02
+
+#define CMD_NUM_OF_WEP_KEYS 4
+
+#define CMD_WEP_KEY_INDEX_MASK 0x3fff
-/* command RET code, MSB is set to 1 */
-#define cmd_ret_hw_spec_info 0x8003
-#define cmd_ret_eeprom_update 0x8004
-#define cmd_ret_802_11_reset 0x8005
-#define cmd_ret_802_11_scan 0x8006
-#define cmd_ret_802_11_get_log 0x800b
-#define cmd_ret_mac_control 0x8028
-#define cmd_ret_mac_multicast_adr 0x8010
-#define cmd_ret_802_11_authenticate 0x8011
-#define cmd_ret_802_11_deauthenticate 0x8024
-#define cmd_ret_802_11_associate 0x8012
-#define cmd_ret_802_11_reassociate 0x8025
-#define cmd_ret_802_11_disassociate 0x8026
-#define cmd_ret_802_11_set_wep 0x8013
-#define cmd_ret_802_11_stat 0x8014
-#define cmd_ret_802_3_stat 0x8015
-#define cmd_ret_802_11_snmp_mib 0x8016
-#define cmd_ret_mac_reg_map 0x8017
-#define cmd_ret_bbp_reg_map 0x8018
-#define cmd_ret_rf_reg_map 0x8023
-#define cmd_ret_mac_reg_access 0x8019
-#define cmd_ret_bbp_reg_access 0x801a
-#define cmd_ret_rf_reg_access 0x801b
-#define cmd_ret_802_11_radio_control 0x801c
-#define cmd_ret_802_11_rf_channel 0x801d
-#define cmd_ret_802_11_rssi 0x801f
-#define cmd_ret_802_11_rf_tx_power 0x801e
-#define cmd_ret_802_11_rf_antenna 0x8020
-#define cmd_ret_802_11_ps_mode 0x8021
-#define cmd_ret_802_11_data_rate 0x8022
-
-#define cmd_ret_802_11_ad_hoc_start 0x802B
-#define cmd_ret_802_11_ad_hoc_join 0x802C
-
-#define cmd_ret_802_11_query_tkip_reply_cntrs 0x802e
-#define cmd_ret_802_11_enable_rsn 0x802f
-#define cmd_ret_802_11_pairwise_tsc 0x8036
-#define cmd_ret_802_11_group_tsc 0x8037
-#define cmd_ret_802_11_key_material 0x805e
-
-#define cmd_enable_rsn 0x0001
-#define cmd_disable_rsn 0x0000
-
-#define cmd_act_set 0x0001
-#define cmd_act_get 0x0000
-
-#define cmd_act_get_AES (cmd_act_get + 2)
-#define cmd_act_set_AES (cmd_act_set + 2)
-#define cmd_act_remove_aes (cmd_act_set + 3)
-
-#define cmd_ret_802_11_set_afc 0x803c
-#define cmd_ret_802_11_get_afc 0x803d
-
-#define cmd_ret_802_11_ad_hoc_stop 0x8040
-
-#define cmd_ret_802_11_beacon_stop 0x8049
-
-#define cmd_ret_802_11_mac_address 0x804D
-#define cmd_ret_802_11_eeprom_access 0x8059
-
-#define cmd_ret_802_11_band_config 0x8058
-
-#define cmd_ret_802_11_sleep_params 0x8066
-
-#define cmd_ret_802_11_inactivity_timeout 0x8067
-
-#define cmd_ret_802_11d_domain_info (0x8000 | \
- cmd_802_11d_domain_info)
-
-#define cmd_ret_802_11_tpc_cfg (cmd_802_11_tpc_cfg | 0x8000)
-#define cmd_ret_802_11_pwr_cfg (cmd_802_11_pwr_cfg | 0x8000)
-
-#define cmd_ret_802_11_led_gpio_ctrl 0x804e
-
-#define cmd_ret_802_11_subscribe_event (cmd_802_11_subscribe_event | 0x8000)
-
-#define cmd_ret_802_11_rate_adapt_rateset (cmd_802_11_rate_adapt_rateset | 0x8000)
-
-#define cmd_rte_802_11_tx_rate_query (cmd_802_11_tx_rate_query | 0x8000)
-
-#define cmd_ret_get_tsf 0x8080
-
-/* Define action or option for cmd_802_11_set_wep */
-#define cmd_act_add 0x0002
-#define cmd_act_remove 0x0004
-#define cmd_act_use_default 0x0008
-
-#define cmd_type_wep_40_bit 0x0001
-#define cmd_type_wep_104_bit 0x0002
-
-#define cmd_NUM_OF_WEP_KEYS 4
-
-#define cmd_WEP_KEY_INDEX_MASK 0x3fff
-
-/* Define action or option for cmd_802_11_reset */
-#define cmd_act_halt 0x0003
+/* Define action or option for CMD_802_11_RESET */
+#define CMD_ACT_HALT 0x0003
-/* Define action or option for cmd_802_11_scan */
-#define cmd_bss_type_bss 0x0001
-#define cmd_bss_type_ibss 0x0002
-#define cmd_bss_type_any 0x0003
+/* Define action or option for CMD_802_11_SCAN */
+#define CMD_BSS_TYPE_BSS 0x0001
+#define CMD_BSS_TYPE_IBSS 0x0002
+#define CMD_BSS_TYPE_ANY 0x0003
-/* Define action or option for cmd_802_11_scan */
-#define cmd_scan_type_active 0x0000
-#define cmd_scan_type_passive 0x0001
+/* Define action or option for CMD_802_11_SCAN */
+#define CMD_SCAN_TYPE_ACTIVE 0x0000
+#define CMD_SCAN_TYPE_PASSIVE 0x0001
-#define cmd_scan_radio_type_bg 0
+#define CMD_SCAN_RADIO_TYPE_BG 0
-#define cmd_scan_probe_delay_time 0
+#define CMD_SCAN_PROBE_DELAY_TIME 0
-/* Define action or option for cmd_mac_control */
-#define cmd_act_mac_rx_on 0x0001
-#define cmd_act_mac_tx_on 0x0002
-#define cmd_act_mac_loopback_on 0x0004
-#define cmd_act_mac_wep_enable 0x0008
-#define cmd_act_mac_int_enable 0x0010
-#define cmd_act_mac_multicast_enable 0x0020
-#define cmd_act_mac_broadcast_enable 0x0040
-#define cmd_act_mac_promiscuous_enable 0x0080
-#define cmd_act_mac_all_multicast_enable 0x0100
-#define cmd_act_mac_strict_protection_enable 0x0400
+/* Define action or option for CMD_MAC_CONTROL */
+#define CMD_ACT_MAC_RX_ON 0x0001
+#define CMD_ACT_MAC_TX_ON 0x0002
+#define CMD_ACT_MAC_LOOPBACK_ON 0x0004
+#define CMD_ACT_MAC_WEP_ENABLE 0x0008
+#define CMD_ACT_MAC_INT_ENABLE 0x0010
+#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020
+#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040
+#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
+#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
+#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400
-/* Define action or option for cmd_802_11_radio_control */
-#define cmd_type_auto_preamble 0x0001
-#define cmd_type_short_preamble 0x0002
-#define cmd_type_long_preamble 0x0003
+/* Define action or option for CMD_802_11_RADIO_CONTROL */
+#define CMD_TYPE_AUTO_PREAMBLE 0x0001
+#define CMD_TYPE_SHORT_PREAMBLE 0x0002
+#define CMD_TYPE_LONG_PREAMBLE 0x0003
#define TURN_ON_RF 0x01
#define RADIO_ON 0x01
@@ -248,70 +187,80 @@
#define SET_LONG_PREAMBLE 0x01
/* Define action or option for CMD_802_11_RF_CHANNEL */
-#define cmd_opt_802_11_rf_channel_get 0x00
-#define cmd_opt_802_11_rf_channel_set 0x01
-
-/* Define action or option for cmd_802_11_rf_tx_power */
-#define cmd_act_tx_power_opt_get 0x0000
-#define cmd_act_tx_power_opt_set_high 0x8007
-#define cmd_act_tx_power_opt_set_mid 0x8004
-#define cmd_act_tx_power_opt_set_low 0x8000
-
-#define cmd_act_tx_power_index_high 0x0007
-#define cmd_act_tx_power_index_mid 0x0004
-#define cmd_act_tx_power_index_low 0x0000
-
-/* Define action or option for cmd_802_11_data_rate */
-#define cmd_act_set_tx_auto 0x0000
-#define cmd_act_set_tx_fix_rate 0x0001
-#define cmd_act_get_tx_rate 0x0002
-
-#define cmd_act_set_rx 0x0001
-#define cmd_act_set_tx 0x0002
-#define cmd_act_set_both 0x0003
-#define cmd_act_get_rx 0x0004
-#define cmd_act_get_tx 0x0008
-#define cmd_act_get_both 0x000c
-
-/* Define action or option for cmd_802_11_ps_mode */
-#define cmd_type_cam 0x0000
-#define cmd_type_max_psp 0x0001
-#define cmd_type_fast_psp 0x0002
-
-/* Define action or option for cmd_bt_access */
+#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00
+#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01
+
+/* Define action or option for CMD_802_11_RF_TX_POWER */
+#define CMD_ACT_TX_POWER_OPT_GET 0x0000
+#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007
+#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004
+#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000
+
+#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007
+#define CMD_ACT_TX_POWER_INDEX_MID 0x0004
+#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000
+
+/* Define action or option for CMD_802_11_DATA_RATE */
+#define CMD_ACT_SET_TX_AUTO 0x0000
+#define CMD_ACT_SET_TX_FIX_RATE 0x0001
+#define CMD_ACT_GET_TX_RATE 0x0002
+
+#define CMD_ACT_SET_RX 0x0001
+#define CMD_ACT_SET_TX 0x0002
+#define CMD_ACT_SET_BOTH 0x0003
+#define CMD_ACT_GET_RX 0x0004
+#define CMD_ACT_GET_TX 0x0008
+#define CMD_ACT_GET_BOTH 0x000c
+
+/* Define action or option for CMD_802_11_PS_MODE */
+#define CMD_TYPE_CAM 0x0000
+#define CMD_TYPE_MAX_PSP 0x0001
+#define CMD_TYPE_FAST_PSP 0x0002
+
+/* Define action or option for CMD_BT_ACCESS */
enum cmd_bt_access_opts {
/* The bt commands start at 5 instead of 1 because the old dft commands
* are mapped to 1-4. These old commands are no longer maintained and
* should not be called.
*/
- cmd_act_bt_access_add = 5,
- cmd_act_bt_access_del,
- cmd_act_bt_access_list,
- cmd_act_bt_access_reset,
- cmd_act_bt_access_set_invert,
- cmd_act_bt_access_get_invert
+ CMD_ACT_BT_ACCESS_ADD = 5,
+ CMD_ACT_BT_ACCESS_DEL,
+ CMD_ACT_BT_ACCESS_LIST,
+ CMD_ACT_BT_ACCESS_RESET,
+ CMD_ACT_BT_ACCESS_SET_INVERT,
+ CMD_ACT_BT_ACCESS_GET_INVERT
};
-/* Define action or option for cmd_fwt_access */
+/* Define action or option for CMD_FWT_ACCESS */
enum cmd_fwt_access_opts {
- cmd_act_fwt_access_add = 1,
- cmd_act_fwt_access_del,
- cmd_act_fwt_access_lookup,
- cmd_act_fwt_access_list,
- cmd_act_fwt_access_list_route,
- cmd_act_fwt_access_list_neighbor,
- cmd_act_fwt_access_reset,
- cmd_act_fwt_access_cleanup,
- cmd_act_fwt_access_time,
+ CMD_ACT_FWT_ACCESS_ADD = 1,
+ CMD_ACT_FWT_ACCESS_DEL,
+ CMD_ACT_FWT_ACCESS_LOOKUP,
+ CMD_ACT_FWT_ACCESS_LIST,
+ CMD_ACT_FWT_ACCESS_LIST_route,
+ CMD_ACT_FWT_ACCESS_LIST_neighbor,
+ CMD_ACT_FWT_ACCESS_RESET,
+ CMD_ACT_FWT_ACCESS_CLEANUP,
+ CMD_ACT_FWT_ACCESS_TIME,
};
-/* Define action or option for cmd_mesh_access */
+/* Define action or option for CMD_MESH_ACCESS */
enum cmd_mesh_access_opts {
- cmd_act_mesh_get_ttl = 1,
- cmd_act_mesh_set_ttl,
- cmd_act_mesh_get_stats,
- cmd_act_mesh_get_anycast,
- cmd_act_mesh_set_anycast,
+ CMD_ACT_MESH_GET_TTL = 1,
+ CMD_ACT_MESH_SET_TTL,
+ CMD_ACT_MESH_GET_STATS,
+ CMD_ACT_MESH_GET_ANYCAST,
+ CMD_ACT_MESH_SET_ANYCAST,
+ CMD_ACT_MESH_SET_LINK_COSTS,
+ CMD_ACT_MESH_GET_LINK_COSTS,
+ CMD_ACT_MESH_SET_BCAST_RATE,
+ CMD_ACT_MESH_GET_BCAST_RATE,
+ CMD_ACT_MESH_SET_RREQ_DELAY,
+ CMD_ACT_MESH_GET_RREQ_DELAY,
+ CMD_ACT_MESH_SET_ROUTE_EXP,
+ CMD_ACT_MESH_GET_ROUTE_EXP,
+ CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+ CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
};
/** Card Event definition */
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index 09b898f6719..e1045dc02cc 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -83,23 +83,12 @@ struct cmd_ctrl_node {
wait_queue_head_t cmdwait_q;
};
-/* WLAN_802_11_KEY
- *
- * Generic structure to hold all key types. key type (WEP40, WEP104, TKIP, AES)
- * is determined from the keylength field.
- */
-struct WLAN_802_11_KEY {
- __le32 len;
- __le32 flags; /* KEY_INFO_* from wlan_defs.h */
- u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH];
- __le16 type; /* KEY_TYPE_* from wlan_defs.h */
-};
-
-struct IE_WPA {
- u8 elementid;
- u8 len;
- u8 oui[4];
- __le16 version;
+/* Generic structure to hold all key types. */
+struct enc_key {
+ u16 len;
+ u16 flags; /* KEY_INFO_* from wlan_defs.h */
+ u16 type; /* KEY_TYPE_* from wlan_defs.h */
+ u8 key[32];
};
/* wlan_offset_value */
@@ -108,18 +97,6 @@ struct wlan_offset_value {
u32 value;
};
-struct WLAN_802_11_FIXED_IEs {
- __le64 timestamp;
- __le16 beaconinterval;
- u16 capabilities; /* Actually struct ieeetypes_capinfo */
-};
-
-struct WLAN_802_11_VARIABLE_IEs {
- u8 elementid;
- u8 length;
- u8 data[1];
-};
-
/* Define general data structure */
/* cmd_DS_GEN */
struct cmd_ds_gen {
@@ -131,7 +108,7 @@ struct cmd_ds_gen {
#define S_DS_GEN sizeof(struct cmd_ds_gen)
/*
- * Define data structure for cmd_get_hw_spec
+ * Define data structure for CMD_GET_HW_SPEC
* This structure defines the response for the GET_HW_SPEC command
*/
struct cmd_ds_get_hw_spec {
@@ -178,11 +155,11 @@ struct cmd_ds_802_11_subscribe_event {
/*
* This scan handle Country Information IE(802.11d compliant)
- * Define data structure for cmd_802_11_scan
+ * Define data structure for CMD_802_11_SCAN
*/
struct cmd_ds_802_11_scan {
u8 bsstype;
- u8 BSSID[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
u8 tlvbuffer[1];
#if 0
mrvlietypes_ssidparamset_t ssidParamSet;
@@ -237,7 +214,7 @@ struct cmd_ds_802_11_deauthenticate {
struct cmd_ds_802_11_associate {
u8 peerstaaddr[6];
- struct ieeetypes_capinfo capinfo;
+ __le16 capability;
__le16 listeninterval;
__le16 bcnperiod;
u8 dtimperiod;
@@ -260,8 +237,8 @@ struct cmd_ds_802_11_associate_rsp {
};
struct cmd_ds_802_11_ad_hoc_result {
- u8 PAD[3];
- u8 BSSID[ETH_ALEN];
+ u8 pad[3];
+ u8 bssid[ETH_ALEN];
};
struct cmd_ds_802_11_set_wep {
@@ -428,6 +405,16 @@ struct cmd_ds_802_11_rf_antenna {
};
+struct cmd_ds_802_11_monitor_mode {
+ u16 action;
+ u16 mode;
+};
+
+struct cmd_ds_set_boot2_ver {
+ u16 action;
+ u16 version;
+};
+
struct cmd_ds_802_11_ps_mode {
__le16 action;
__le16 nullpktinterval;
@@ -451,8 +438,8 @@ struct PS_CMD_ConfirmSleep {
struct cmd_ds_802_11_data_rate {
__le16 action;
- __le16 reserverd;
- u8 datarate[G_SUPPORTED_RATES];
+ __le16 reserved;
+ u8 rates[MAX_RATES];
};
struct cmd_ds_802_11_rate_adapt_rateset {
@@ -462,30 +449,30 @@ struct cmd_ds_802_11_rate_adapt_rateset {
};
struct cmd_ds_802_11_ad_hoc_start {
- u8 SSID[IW_ESSID_MAX_SIZE];
+ u8 ssid[IW_ESSID_MAX_SIZE];
u8 bsstype;
__le16 beaconperiod;
u8 dtimperiod;
union IEEEtypes_ssparamset ssparamset;
union ieeetypes_phyparamset phyparamset;
__le16 probedelay;
- struct ieeetypes_capinfo cap;
- u8 datarate[G_SUPPORTED_RATES];
+ __le16 capability;
+ u8 rates[MAX_RATES];
u8 tlv_memory_size_pad[100];
} __attribute__ ((packed));
struct adhoc_bssdesc {
- u8 BSSID[6];
- u8 SSID[32];
- u8 bsstype;
+ u8 bssid[6];
+ u8 ssid[32];
+ u8 type;
__le16 beaconperiod;
u8 dtimperiod;
__le64 timestamp;
__le64 localtime;
union ieeetypes_phyparamset phyparamset;
union IEEEtypes_ssparamset ssparamset;
- struct ieeetypes_capinfo cap;
- u8 datarates[G_SUPPORTED_RATES];
+ __le16 capability;
+ u8 rates[MAX_RATES];
/* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
* Adhoc join command and will cause a binary layout mismatch with
@@ -494,7 +481,7 @@ struct adhoc_bssdesc {
} __attribute__ ((packed));
struct cmd_ds_802_11_ad_hoc_join {
- struct adhoc_bssdesc bssdescriptor;
+ struct adhoc_bssdesc bss;
__le16 failtimeout;
__le16 probedelay;
@@ -646,6 +633,7 @@ struct cmd_ds_command {
struct cmd_ds_802_11_snmp_mib smib;
struct cmd_ds_802_11_rf_tx_power txp;
struct cmd_ds_802_11_rf_antenna rant;
+ struct cmd_ds_802_11_monitor_mode monitor;
struct cmd_ds_802_11_data_rate drate;
struct cmd_ds_802_11_rate_adapt_rateset rateset;
struct cmd_ds_mac_multicast_adr madr;
@@ -677,6 +665,7 @@ struct cmd_ds_command {
struct cmd_ds_bt_access bt;
struct cmd_ds_fwt_access fwt;
struct cmd_ds_mesh_access mesh;
+ struct cmd_ds_set_boot2_ver boot2_ver;
struct cmd_ds_get_tsf gettsf;
struct cmd_ds_802_11_subscribe_event subscribe_event;
} params;
diff --git a/drivers/net/wireless/libertas/if_bootcmd.c b/drivers/net/wireless/libertas/if_bootcmd.c
deleted file mode 100644
index 8bca306ffad..00000000000
--- a/drivers/net/wireless/libertas/if_bootcmd.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * This file contains functions used in USB Boot command
- * and Boot2/FW update
- */
-
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/netdevice.h>
-#include <linux/usb.h>
-
-#define DRV_NAME "usb8xxx"
-
-#include "defs.h"
-#include "dev.h"
-#include "if_usb.h"
-
-/**
- * @brief This function issues Boot command to the Boot2 code
- * @param ivalue 1:Boot from FW by USB-Download
- * 2:Boot from FW in EEPROM
- * @return 0
- */
-int if_usb_issue_boot_command(wlan_private *priv, int ivalue)
-{
- struct usb_card_rec *cardp = priv->card;
- struct bootcmdstr sbootcmd;
- int i;
-
- /* Prepare command */
- sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
- sbootcmd.u8cmd_tag = ivalue;
- for (i=0; i<11; i++)
- sbootcmd.au8dumy[i]=0x00;
- memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
-
- /* Issue command */
- usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
-
- return 0;
-}
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
new file mode 100644
index 00000000000..ec89dabc412
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -0,0 +1,972 @@
+/*
+
+ Driver for the Marvell 8385 based compact flash WLAN cards.
+
+ (C) 2007 by Holger Schurig <hs4233@mail.mn-solutions.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include <linux/io.h>
+
+#define DRV_NAME "libertas_cs"
+
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+
+
+/********************************************************************/
+/* Module stuff */
+/********************************************************************/
+
+MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
+MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
+MODULE_LICENSE("GPL");
+
+
+
+/********************************************************************/
+/* Data structures */
+/********************************************************************/
+
+struct if_cs_card {
+ struct pcmcia_device *p_dev;
+ wlan_private *priv;
+ void __iomem *iobase;
+};
+
+
+
+/********************************************************************/
+/* Hardware access */
+/********************************************************************/
+
+/* This define enables wrapper functions which allow you
+ to dump all register accesses. You normally won't this,
+ except for development */
+/* #define DEBUG_IO */
+
+#ifdef DEBUG_IO
+static int debug_output = 0;
+#else
+/* This way the compiler optimizes the printk's away */
+#define debug_output 0
+#endif
+
+static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
+{
+ unsigned int val = ioread8(card->iobase + reg);
+ if (debug_output)
+ printk(KERN_INFO "##inb %08x<%02x\n", reg, val);
+ return val;
+}
+static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
+{
+ unsigned int val = ioread16(card->iobase + reg);
+ if (debug_output)
+ printk(KERN_INFO "##inw %08x<%04x\n", reg, val);
+ return val;
+}
+static inline void if_cs_read16_rep(
+ struct if_cs_card *card,
+ uint reg,
+ void *buf,
+ unsigned long count)
+{
+ if (debug_output)
+ printk(KERN_INFO "##insw %08x<(0x%lx words)\n",
+ reg, count);
+ ioread16_rep(card->iobase + reg, buf, count);
+}
+
+static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
+{
+ if (debug_output)
+ printk(KERN_INFO "##outb %08x>%02x\n", reg, val);
+ iowrite8(val, card->iobase + reg);
+}
+
+static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
+{
+ if (debug_output)
+ printk(KERN_INFO "##outw %08x>%04x\n", reg, val);
+ iowrite16(val, card->iobase + reg);
+}
+
+static inline void if_cs_write16_rep(
+ struct if_cs_card *card,
+ uint reg,
+ void *buf,
+ unsigned long count)
+{
+ if (debug_output)
+ printk(KERN_INFO "##outsw %08x>(0x%lx words)\n",
+ reg, count);
+ iowrite16_rep(card->iobase + reg, buf, count);
+}
+
+
+/*
+ * I know that polling/delaying is frowned upon. However, this procedure
+ * with polling is needed while downloading the firmware. At this stage,
+ * the hardware does unfortunately not create any interrupts.
+ *
+ * Fortunately, this function is never used once the firmware is in
+ * the card. :-)
+ *
+ * As a reference, see the "Firmware Specification v5.1", page 18
+ * and 19. I did not follow their suggested timing to the word,
+ * but this works nice & fast anyway.
+ */
+static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg)
+{
+ int i;
+
+ for (i = 0; i < 1000; i++) {
+ u8 val = if_cs_read8(card, addr);
+ if (val == reg)
+ return i;
+ udelay(500);
+ }
+ return -ETIME;
+}
+
+
+
+/* Host control registers and their bit definitions */
+
+#define IF_CS_H_STATUS 0x00000000
+#define IF_CS_H_STATUS_TX_OVER 0x0001
+#define IF_CS_H_STATUS_RX_OVER 0x0002
+#define IF_CS_H_STATUS_DNLD_OVER 0x0004
+
+#define IF_CS_H_INT_CAUSE 0x00000002
+#define IF_CS_H_IC_TX_OVER 0x0001
+#define IF_CS_H_IC_RX_OVER 0x0002
+#define IF_CS_H_IC_DNLD_OVER 0x0004
+#define IF_CS_H_IC_HOST_EVENT 0x0008
+#define IF_CS_H_IC_MASK 0x001f
+
+#define IF_CS_H_INT_MASK 0x00000004
+#define IF_CS_H_IM_MASK 0x001f
+
+#define IF_CS_H_WRITE_LEN 0x00000014
+
+#define IF_CS_H_WRITE 0x00000016
+
+#define IF_CS_H_CMD_LEN 0x00000018
+
+#define IF_CS_H_CMD 0x0000001A
+
+#define IF_CS_C_READ_LEN 0x00000024
+
+#define IF_CS_H_READ 0x00000010
+
+/* Card control registers and their bit definitions */
+
+#define IF_CS_C_STATUS 0x00000020
+#define IF_CS_C_S_TX_DNLD_RDY 0x0001
+#define IF_CS_C_S_RX_UPLD_RDY 0x0002
+#define IF_CS_C_S_CMD_DNLD_RDY 0x0004
+#define IF_CS_C_S_CMD_UPLD_RDY 0x0008
+#define IF_CS_C_S_CARDEVENT 0x0010
+#define IF_CS_C_S_MASK 0x001f
+#define IF_CS_C_S_STATUS_MASK 0x7f00
+/* The following definitions should be the same as the MRVDRV_ ones */
+
+#if MRVDRV_CMD_DNLD_RDY != IF_CS_C_S_CMD_DNLD_RDY
+#error MRVDRV_CMD_DNLD_RDY and IF_CS_C_S_CMD_DNLD_RDY not in sync
+#endif
+#if MRVDRV_CMD_UPLD_RDY != IF_CS_C_S_CMD_UPLD_RDY
+#error MRVDRV_CMD_UPLD_RDY and IF_CS_C_S_CMD_UPLD_RDY not in sync
+#endif
+#if MRVDRV_CARDEVENT != IF_CS_C_S_CARDEVENT
+#error MRVDRV_CARDEVENT and IF_CS_C_S_CARDEVENT not in sync
+#endif
+
+#define IF_CS_C_INT_CAUSE 0x00000022
+#define IF_CS_C_IC_MASK 0x001f
+
+#define IF_CS_C_SQ_READ_LOW 0x00000028
+#define IF_CS_C_SQ_HELPER_OK 0x10
+
+#define IF_CS_C_CMD_LEN 0x00000030
+
+#define IF_CS_C_CMD 0x00000012
+
+#define IF_CS_SCRATCH 0x0000003F
+
+
+
+/********************************************************************/
+/* Interrupts */
+/********************************************************************/
+
+static inline void if_cs_enable_ints(struct if_cs_card *card)
+{
+ lbs_deb_enter(LBS_DEB_CS);
+ if_cs_write16(card, IF_CS_H_INT_MASK, 0);
+}
+
+static inline void if_cs_disable_ints(struct if_cs_card *card)
+{
+ lbs_deb_enter(LBS_DEB_CS);
+ if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
+}
+
+static irqreturn_t if_cs_interrupt(int irq, void *data)
+{
+ struct if_cs_card *card = (struct if_cs_card *)data;
+ u16 int_cause;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
+ if(int_cause == 0x0) {
+ /* Not for us */
+ return IRQ_NONE;
+
+ } else if(int_cause == 0xffff) {
+ /* Read in junk, the card has probably been removed */
+ card->priv->adapter->surpriseremoved = 1;
+
+ } else {
+ if(int_cause & IF_CS_H_IC_TX_OVER) {
+ card->priv->dnld_sent = DNLD_RES_RECEIVED;
+ if (!card->priv->adapter->cur_cmd)
+ wake_up_interruptible(&card->priv->waitq);
+
+ if (card->priv->adapter->connect_status == LIBERTAS_CONNECTED)
+ netif_wake_queue(card->priv->dev);
+ }
+
+ /* clear interrupt */
+ if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK);
+ }
+
+ libertas_interrupt(card->priv->dev);
+
+ return IRQ_HANDLED;
+}
+
+
+
+
+/********************************************************************/
+/* I/O */
+/********************************************************************/
+
+/*
+ * Called from if_cs_host_to_card to send a command to the hardware
+ */
+static int if_cs_send_cmd(wlan_private *priv, u8 *buf, u16 nb)
+{
+ struct if_cs_card *card = (struct if_cs_card *)priv->card;
+ int ret = -1;
+ int loops = 0;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ /* Is hardware ready? */
+ while (1) {
+ u16 val = if_cs_read16(card, IF_CS_C_STATUS);
+ if (val & IF_CS_C_S_CMD_DNLD_RDY)
+ break;
+ if (++loops > 100) {
+ lbs_pr_err("card not ready for commands\n");
+ goto done;
+ }
+ mdelay(1);
+ }
+
+ if_cs_write16(card, IF_CS_H_CMD_LEN, nb);
+
+ if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2);
+ /* Are we supposed to transfer an odd amount of bytes? */
+ if (nb & 1)
+ if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]);
+
+ /* "Assert the download over interrupt command in the Host
+ * status register" */
+ if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
+
+ /* "Assert the download over interrupt command in the Card
+ * interrupt case register" */
+ if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+ ret = 0;
+
+done:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+ return ret;
+}
+
+
+/*
+ * Called from if_cs_host_to_card to send a data to the hardware
+ */
+static void if_cs_send_data(wlan_private *priv, u8 *buf, u16 nb)
+{
+ struct if_cs_card *card = (struct if_cs_card *)priv->card;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ if_cs_write16(card, IF_CS_H_WRITE_LEN, nb);
+
+ /* write even number of bytes, then odd byte if necessary */
+ if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2);
+ if (nb & 1)
+ if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]);
+
+ if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER);
+ if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER);
+
+ lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+/*
+ * Get the command result out of the card.
+ */
+static int if_cs_receive_cmdres(wlan_private *priv, u8* data, u32 *len)
+{
+ int ret = -1;
+ u16 val;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ /* is hardware ready? */
+ val = if_cs_read16(priv->card, IF_CS_C_STATUS);
+ if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) {
+ lbs_pr_err("card not ready for CMD\n");
+ goto out;
+ }
+
+ *len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN);
+ if ((*len == 0) || (*len > MRVDRV_SIZE_OF_CMD_BUFFER)) {
+ lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
+ goto out;
+ }
+
+ /* read even number of bytes, then odd byte if necessary */
+ if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16));
+ if (*len & 1)
+ data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD);
+
+ ret = 0;
+out:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
+ return ret;
+}
+
+
+static struct sk_buff *if_cs_receive_data(wlan_private *priv)
+{
+ struct sk_buff *skb = NULL;
+ u16 len;
+ u8 *data;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ len = if_cs_read16(priv->card, IF_CS_C_READ_LEN);
+ if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
+ lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
+ priv->stats.rx_dropped++;
+ printk(KERN_INFO "##HS %s:%d TODO\n", __FUNCTION__, __LINE__);
+ goto dat_err;
+ }
+
+ //TODO: skb = dev_alloc_skb(len+ETH_FRAME_LEN+MRVDRV_SNAP_HEADER_LEN+EXTRA_LEN);
+ skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
+ if (!skb)
+ goto out;
+ skb_put(skb, len);
+ skb_reserve(skb, 2);/* 16 byte align */
+ data = skb->data;
+
+ /* read even number of bytes, then odd byte if necessary */
+ if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16));
+ if (len & 1)
+ data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ);
+
+dat_err:
+ if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER);
+ if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER);
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb);
+ return skb;
+}
+
+
+
+/********************************************************************/
+/* Firmware */
+/********************************************************************/
+
+/*
+ * Tries to program the helper firmware.
+ *
+ * Return 0 on success
+ */
+static int if_cs_prog_helper(struct if_cs_card *card)
+{
+ int ret = 0;
+ int sent = 0;
+ u8 scratch;
+ const struct firmware *fw;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ scratch = if_cs_read8(card, IF_CS_SCRATCH);
+
+ /* "If the value is 0x5a, the firmware is already
+ * downloaded successfully"
+ */
+ if (scratch == 0x5a)
+ goto done;
+
+ /* "If the value is != 00, it is invalid value of register */
+ if (scratch != 0x00) {
+ ret = -ENODEV;
+ goto done;
+ }
+
+ /* TODO: make firmware file configurable */
+ ret = request_firmware(&fw, "libertas_cs_helper.fw",
+ &handle_to_dev(card->p_dev));
+ if (ret) {
+ lbs_pr_err("can't load helper firmware\n");
+ ret = -ENODEV;
+ goto done;
+ }
+ lbs_deb_cs("helper size %td\n", fw->size);
+
+ /* "Set the 5 bytes of the helper image to 0" */
+ /* Not needed, this contains an ARM branch instruction */
+
+ for (;;) {
+ /* "the number of bytes to send is 256" */
+ int count = 256;
+ int remain = fw->size - sent;
+
+ if (remain < count)
+ count = remain;
+ /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
+ __LINE__, sent, fw->size); */
+
+ /* "write the number of bytes to be sent to the I/O Command
+ * write length register" */
+ if_cs_write16(card, IF_CS_H_CMD_LEN, count);
+
+ /* "write this to I/O Command port register as 16 bit writes */
+ if (count)
+ if_cs_write16_rep(card, IF_CS_H_CMD,
+ &fw->data[sent],
+ count >> 1);
+
+ /* "Assert the download over interrupt command in the Host
+ * status register" */
+ if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
+
+ /* "Assert the download over interrupt command in the Card
+ * interrupt case register" */
+ if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+
+ /* "The host polls the Card Status register ... for 50 ms before
+ declaring a failure */
+ ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
+ IF_CS_C_S_CMD_DNLD_RDY);
+ if (ret < 0) {
+ lbs_pr_err("can't download helper at 0x%x, ret %d\n",
+ sent, ret);
+ goto done;
+ }
+
+ if (count == 0)
+ break;
+
+ sent += count;
+ }
+
+ release_firmware(fw);
+ ret = 0;
+
+done:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+ return ret;
+}
+
+
+static int if_cs_prog_real(struct if_cs_card *card)
+{
+ const struct firmware *fw;
+ int ret = 0;
+ int retry = 0;
+ int len = 0;
+ int sent;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ /* TODO: make firmware file configurable */
+ ret = request_firmware(&fw, "libertas_cs.fw",
+ &handle_to_dev(card->p_dev));
+ if (ret) {
+ lbs_pr_err("can't load firmware\n");
+ ret = -ENODEV;
+ goto done;
+ }
+ lbs_deb_cs("fw size %td\n", fw->size);
+
+ ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK);
+ if (ret < 0) {
+ int i;
+ lbs_pr_err("helper firmware doesn't answer\n");
+ for (i = 0; i < 0x50; i += 2)
+ printk(KERN_INFO "## HS %02x: %04x\n",
+ i, if_cs_read16(card, i));
+ goto err_release;
+ }
+
+ for (sent = 0; sent < fw->size; sent += len) {
+ len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW);
+ /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
+ __LINE__, sent, fw->size); */
+ if (len & 1) {
+ retry++;
+ lbs_pr_info("odd, need to retry this firmware block\n");
+ } else {
+ retry = 0;
+ }
+
+ if (retry > 20) {
+ lbs_pr_err("could not download firmware\n");
+ ret = -ENODEV;
+ goto err_release;
+ }
+ if (retry) {
+ sent -= len;
+ }
+
+
+ if_cs_write16(card, IF_CS_H_CMD_LEN, len);
+
+ if_cs_write16_rep(card, IF_CS_H_CMD,
+ &fw->data[sent],
+ (len+1) >> 1);
+ if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
+ if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+
+ ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
+ IF_CS_C_S_CMD_DNLD_RDY);
+ if (ret < 0) {
+ lbs_pr_err("can't download firmware at 0x%x\n", sent);
+ goto err_release;
+ }
+ }
+
+ ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
+ if (ret < 0) {
+ lbs_pr_err("firmware download failed\n");
+ goto err_release;
+ }
+
+ ret = 0;
+ goto done;
+
+
+err_release:
+ release_firmware(fw);
+
+done:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+ return ret;
+}
+
+
+
+/********************************************************************/
+/* Callback functions for libertas.ko */
+/********************************************************************/
+
+/* Send commands or data packets to the card */
+static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb)
+{
+ int ret = -1;
+
+ lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb);
+
+ switch (type) {
+ case MVMS_DAT:
+ priv->dnld_sent = DNLD_DATA_SENT;
+ if_cs_send_data(priv, buf, nb);
+ ret = 0;
+ break;
+ case MVMS_CMD:
+ priv->dnld_sent = DNLD_CMD_SENT;
+ ret = if_cs_send_cmd(priv, buf, nb);
+ break;
+ default:
+ lbs_pr_err("%s: unsupported type %d\n", __FUNCTION__, type);
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+ return ret;
+}
+
+
+static int if_cs_get_int_status(wlan_private *priv, u8 *ireg)
+{
+ struct if_cs_card *card = (struct if_cs_card *)priv->card;
+ //wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ u16 int_cause;
+ u8 *cmdbuf;
+ *ireg = 0;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ if (priv->adapter->surpriseremoved)
+ goto out;
+
+ int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK;
+ if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause);
+
+ *ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
+
+ if (!*ireg)
+ goto sbi_get_int_status_exit;
+
+sbi_get_int_status_exit:
+
+ /* is there a data packet for us? */
+ if (*ireg & IF_CS_C_S_RX_UPLD_RDY) {
+ struct sk_buff *skb = if_cs_receive_data(priv);
+ libertas_process_rxed_packet(priv, skb);
+ *ireg &= ~IF_CS_C_S_RX_UPLD_RDY;
+ }
+
+ if (*ireg & IF_CS_C_S_TX_DNLD_RDY) {
+ priv->dnld_sent = DNLD_RES_RECEIVED;
+ }
+
+ /* Card has a command result for us */
+ if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) {
+ spin_lock(&priv->adapter->driver_lock);
+ if (!priv->adapter->cur_cmd) {
+ cmdbuf = priv->upld_buf;
+ priv->adapter->hisregcpy &= ~IF_CS_C_S_RX_UPLD_RDY;
+ } else {
+ cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
+ }
+
+ ret = if_cs_receive_cmdres(priv, cmdbuf, &priv->upld_len);
+ spin_unlock(&priv->adapter->driver_lock);
+ if (ret < 0)
+ lbs_pr_err("could not receive cmd from card\n");
+ }
+
+out:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->adapter->hisregcpy);
+ return ret;
+}
+
+
+static int if_cs_read_event_cause(wlan_private *priv)
+{
+ lbs_deb_enter(LBS_DEB_CS);
+
+ priv->adapter->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5;
+ if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT);
+
+ return 0;
+}
+
+
+
+/********************************************************************/
+/* Card Services */
+/********************************************************************/
+
+/*
+ * After a card is removed, if_cs_release() will unregister the
+ * device, and release the PCMCIA configuration. If the device is
+ * still open, this will be postponed until it is closed.
+ */
+static void if_cs_release(struct pcmcia_device *p_dev)
+{
+ struct if_cs_card *card = p_dev->priv;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ pcmcia_disable_device(p_dev);
+ free_irq(p_dev->irq.AssignedIRQ, card);
+ if (card->iobase)
+ ioport_unmap(card->iobase);
+
+ lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+/*
+ * This creates an "instance" of the driver, allocating local data
+ * structures for one device. The device is registered with Card
+ * Services.
+ *
+ * The dev_link structure is initialized, but we don't actually
+ * configure the card at this point -- we wait until we receive a card
+ * insertion event.
+ */
+static int if_cs_probe(struct pcmcia_device *p_dev)
+{
+ int ret = -ENOMEM;
+ wlan_private *priv;
+ struct if_cs_card *card;
+ /* CIS parsing */
+ tuple_t tuple;
+ cisparse_t parse;
+ cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
+ cistpl_io_t *io = &cfg->io;
+ u_char buf[64];
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
+ if (!card) {
+ lbs_pr_err("error in kzalloc\n");
+ goto out;
+ }
+ card->p_dev = p_dev;
+ p_dev->priv = card;
+
+ p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
+ p_dev->irq.Handler = NULL;
+ p_dev->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+
+ p_dev->conf.Attributes = 0;
+ p_dev->conf.IntType = INT_MEMORY_AND_IO;
+
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 ||
+ (ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 ||
+ (ret = pcmcia_parse_tuple(p_dev, &tuple, &parse)) != 0)
+ {
+ lbs_pr_err("error in pcmcia_get_first_tuple etc\n");
+ goto out1;
+ }
+
+ p_dev->conf.ConfigIndex = cfg->index;
+
+ /* Do we need to allocate an interrupt? */
+ if (cfg->irq.IRQInfo1) {
+ p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+ }
+
+ /* IO window settings */
+ if (cfg->io.nwin != 1) {
+ lbs_pr_err("wrong CIS (check number of IO windows)\n");
+ ret = -ENODEV;
+ goto out1;
+ }
+ p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ p_dev->io.BasePort1 = io->win[0].base;
+ p_dev->io.NumPorts1 = io->win[0].len;
+
+ /* This reserves IO space but doesn't actually enable it */
+ ret = pcmcia_request_io(p_dev, &p_dev->io);
+ if (ret) {
+ lbs_pr_err("error in pcmcia_request_io\n");
+ goto out1;
+ }
+
+ /*
+ * Allocate an interrupt line. Note that this does not assign
+ * a handler to the interrupt, unless the 'Handler' member of
+ * the irq structure is initialized.
+ */
+ if (p_dev->conf.Attributes & CONF_ENABLE_IRQ) {
+ ret = pcmcia_request_irq(p_dev, &p_dev->irq);
+ if (ret) {
+ lbs_pr_err("error in pcmcia_request_irq\n");
+ goto out1;
+ }
+ }
+
+ /* Initialize io access */
+ card->iobase = ioport_map(p_dev->io.BasePort1, p_dev->io.NumPorts1);
+ if (!card->iobase) {
+ lbs_pr_err("error in ioport_map\n");
+ ret = -EIO;
+ goto out1;
+ }
+
+ /*
+ * This actually configures the PCMCIA socket -- setting up
+ * the I/O windows and the interrupt mapping, and putting the
+ * card and host interface into "Memory and IO" mode.
+ */
+ ret = pcmcia_request_configuration(p_dev, &p_dev->conf);
+ if (ret) {
+ lbs_pr_err("error in pcmcia_request_configuration\n");
+ goto out2;
+ }
+
+ /* Finally, report what we've done */
+ lbs_deb_cs("irq %d, io 0x%04x-0x%04x\n",
+ p_dev->irq.AssignedIRQ, p_dev->io.BasePort1,
+ p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1);
+
+
+ /* Load the firmware early, before calling into libertas.ko */
+ ret = if_cs_prog_helper(card);
+ if (ret == 0)
+ ret = if_cs_prog_real(card);
+ if (ret)
+ goto out2;
+
+ /* Make this card known to the libertas driver */
+ priv = libertas_add_card(card, &p_dev->dev);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto out2;
+ }
+
+ /* Store pointers to our call-back functions */
+ card->priv = priv;
+ priv->card = card;
+ priv->hw_host_to_card = if_cs_host_to_card;
+ priv->hw_get_int_status = if_cs_get_int_status;
+ priv->hw_read_event_cause = if_cs_read_event_cause;
+
+ priv->adapter->fw_ready = 1;
+
+ /* Now actually get the IRQ */
+ ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt,
+ IRQF_SHARED, DRV_NAME, card);
+ if (ret) {
+ lbs_pr_err("error in request_irq\n");
+ goto out3;
+ }
+
+ /* Clear any interrupt cause that happend while sending
+ * firmware/initializing card */
+ if_cs_write16(card, IF_CS_C_INT_CAUSE, IF_CS_C_IC_MASK);
+ if_cs_enable_ints(card);
+
+ /* And finally bring the card up */
+ if (libertas_start_card(priv) != 0) {
+ lbs_pr_err("could not activate card\n");
+ goto out3;
+ }
+
+ ret = 0;
+ goto out;
+
+out3:
+ libertas_remove_card(priv);
+out2:
+ ioport_unmap(card->iobase);
+out1:
+ pcmcia_disable_device(p_dev);
+out:
+ lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+ return ret;
+}
+
+
+/*
+ * This deletes a driver "instance". The device is de-registered with
+ * Card Services. If it has been released, all local data structures
+ * are freed. Otherwise, the structures will be freed when the device
+ * is released.
+ */
+static void if_cs_detach(struct pcmcia_device *p_dev)
+{
+ struct if_cs_card *card = p_dev->priv;
+
+ lbs_deb_enter(LBS_DEB_CS);
+
+ libertas_stop_card(card->priv);
+ libertas_remove_card(card->priv);
+ if_cs_disable_ints(card);
+ if_cs_release(p_dev);
+ kfree(card);
+
+ lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+
+/********************************************************************/
+/* Module initialization */
+/********************************************************************/
+
+static struct pcmcia_device_id if_cs_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x02df, 0x8103),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
+
+
+static struct pcmcia_driver libertas_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = DRV_NAME,
+ },
+ .probe = if_cs_probe,
+ .remove = if_cs_detach,
+ .id_table = if_cs_ids,
+};
+
+
+static int __init if_cs_init(void)
+{
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_CS);
+ ret = pcmcia_register_driver(&libertas_driver);
+ lbs_deb_leave(LBS_DEB_CS);
+ return ret;
+}
+
+
+static void __exit if_cs_exit(void)
+{
+ lbs_deb_enter(LBS_DEB_CS);
+ pcmcia_unregister_driver(&libertas_driver);
+ lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+module_init(if_cs_init);
+module_exit(if_cs_exit);
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
new file mode 100644
index 00000000000..b24425f7488
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -0,0 +1,1081 @@
+/*
+ * linux/drivers/net/wireless/libertas/if_sdio.c
+ *
+ * Copyright 2007 Pierre Ossman
+ *
+ * Inspired by if_cs.c, Copyright 2007 Holger Schurig
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This hardware has more or less no CMD53 support, so all registers
+ * must be accessed using sdio_readb()/sdio_writeb().
+ *
+ * Transfers must be in one transaction or the firmware goes bonkers.
+ * This means that the transfer must either be small enough to do a
+ * byte based transfer or it must be padded to a multiple of the
+ * current block size.
+ *
+ * As SDIO is still new to the kernel, it is unfortunately common with
+ * bugs in the host controllers related to that. One such bug is that
+ * controllers cannot do transfers that aren't a multiple of 4 bytes.
+ * If you don't have time to fix the host controller driver, you can
+ * work around the problem by modifying if_sdio_host_to_card() and
+ * if_sdio_card_to_host() to pad the data.
+ */
+
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+#include "host.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "if_sdio.h"
+
+static char *libertas_helper_name = NULL;
+module_param_named(helper_name, libertas_helper_name, charp, 0644);
+
+static char *libertas_fw_name = NULL;
+module_param_named(fw_name, libertas_fw_name, charp, 0644);
+
+static const struct sdio_device_id if_sdio_ids[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_LIBERTAS) },
+ { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(sdio, if_sdio_ids);
+
+struct if_sdio_model {
+ int model;
+ const char *helper;
+ const char *firmware;
+};
+
+static struct if_sdio_model if_sdio_models[] = {
+ {
+ /* 8385 */
+ .model = 0x04,
+ .helper = "sd8385_helper.bin",
+ .firmware = "sd8385.bin",
+ },
+ {
+ /* 8686 */
+ .model = 0x0B,
+ .helper = "sd8686_helper.bin",
+ .firmware = "sd8686.bin",
+ },
+};
+
+struct if_sdio_packet {
+ struct if_sdio_packet *next;
+ u16 nb;
+ u8 buffer[0] __attribute__((aligned(4)));
+};
+
+struct if_sdio_card {
+ struct sdio_func *func;
+ wlan_private *priv;
+
+ int model;
+ unsigned long ioport;
+
+ const char *helper;
+ const char *firmware;
+
+ u8 buffer[65536];
+ u8 int_cause;
+ u32 event;
+
+ spinlock_t lock;
+ struct if_sdio_packet *packets;
+ struct work_struct packet_worker;
+};
+
+/********************************************************************/
+/* I/O */
+/********************************************************************/
+
+static u16 if_sdio_read_scratch(struct if_sdio_card *card, int *err)
+{
+ int ret, reg;
+ u16 scratch;
+
+ if (card->model == 0x04)
+ reg = IF_SDIO_SCRATCH_OLD;
+ else
+ reg = IF_SDIO_SCRATCH;
+
+ scratch = sdio_readb(card->func, reg, &ret);
+ if (!ret)
+ scratch |= sdio_readb(card->func, reg + 1, &ret) << 8;
+
+ if (err)
+ *err = ret;
+
+ if (ret)
+ return 0xffff;
+
+ return scratch;
+}
+
+static int if_sdio_handle_cmd(struct if_sdio_card *card,
+ u8 *buffer, unsigned size)
+{
+ int ret;
+ unsigned long flags;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ spin_lock_irqsave(&card->priv->adapter->driver_lock, flags);
+
+ if (!card->priv->adapter->cur_cmd) {
+ lbs_deb_sdio("discarding spurious response\n");
+ ret = 0;
+ goto out;
+ }
+
+ if (size > MRVDRV_SIZE_OF_CMD_BUFFER) {
+ lbs_deb_sdio("response packet too large (%d bytes)\n",
+ (int)size);
+ ret = -E2BIG;
+ goto out;
+ }
+
+ memcpy(card->priv->adapter->cur_cmd->bufvirtualaddr, buffer, size);
+ card->priv->upld_len = size;
+
+ card->int_cause |= MRVDRV_CMD_UPLD_RDY;
+
+ libertas_interrupt(card->priv->dev);
+
+ ret = 0;
+
+out:
+ spin_unlock_irqrestore(&card->priv->adapter->driver_lock, flags);
+
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static int if_sdio_handle_data(struct if_sdio_card *card,
+ u8 *buffer, unsigned size)
+{
+ int ret;
+ struct sk_buff *skb;
+ char *data;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ if (size > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
+ lbs_deb_sdio("response packet too large (%d bytes)\n",
+ (int)size);
+ ret = -E2BIG;
+ goto out;
+ }
+
+ skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + NET_IP_ALIGN);
+ if (!skb) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ data = skb_put(skb, size);
+
+ memcpy(data, buffer, size);
+
+ libertas_process_rxed_packet(card->priv, skb);
+
+ ret = 0;
+
+out:
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static int if_sdio_handle_event(struct if_sdio_card *card,
+ u8 *buffer, unsigned size)
+{
+ int ret;
+ unsigned long flags;
+ u32 event;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ if (card->model == 0x04) {
+ event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
+ if (ret)
+ goto out;
+ } else {
+ if (size < 4) {
+ lbs_deb_sdio("event packet too small (%d bytes)\n",
+ (int)size);
+ ret = -EINVAL;
+ goto out;
+ }
+ event = buffer[3] << 24;
+ event |= buffer[2] << 16;
+ event |= buffer[1] << 8;
+ event |= buffer[0] << 0;
+ event <<= SBI_EVENT_CAUSE_SHIFT;
+ }
+
+ spin_lock_irqsave(&card->priv->adapter->driver_lock, flags);
+
+ card->event = event;
+ card->int_cause |= MRVDRV_CARDEVENT;
+
+ libertas_interrupt(card->priv->dev);
+
+ spin_unlock_irqrestore(&card->priv->adapter->driver_lock, flags);
+
+ ret = 0;
+
+out:
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static int if_sdio_card_to_host(struct if_sdio_card *card)
+{
+ int ret;
+ u8 status;
+ u16 size, type, chunk;
+ unsigned long timeout;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ size = if_sdio_read_scratch(card, &ret);
+ if (ret)
+ goto out;
+
+ if (size < 4) {
+ lbs_deb_sdio("invalid packet size (%d bytes) from firmware\n",
+ (int)size);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ timeout = jiffies + HZ;
+ while (1) {
+ status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
+ if (ret)
+ goto out;
+ if (status & IF_SDIO_IO_RDY)
+ break;
+ if (time_after(jiffies, timeout)) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+ mdelay(1);
+ }
+
+ /*
+ * The transfer must be in one transaction or the firmware
+ * goes suicidal.
+ */
+ chunk = size;
+ if ((chunk > card->func->cur_blksize) || (chunk > 512)) {
+ chunk = (chunk + card->func->cur_blksize - 1) /
+ card->func->cur_blksize * card->func->cur_blksize;
+ }
+
+ ret = sdio_readsb(card->func, card->buffer, card->ioport, chunk);
+ if (ret)
+ goto out;
+
+ chunk = card->buffer[0] | (card->buffer[1] << 8);
+ type = card->buffer[2] | (card->buffer[3] << 8);
+
+ lbs_deb_sdio("packet of type %d and size %d bytes\n",
+ (int)type, (int)chunk);
+
+ if (chunk > size) {
+ lbs_deb_sdio("packet fragment (%d > %d)\n",
+ (int)chunk, (int)size);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (chunk < size) {
+ lbs_deb_sdio("packet fragment (%d < %d)\n",
+ (int)chunk, (int)size);
+ }
+
+ switch (type) {
+ case MVMS_CMD:
+ ret = if_sdio_handle_cmd(card, card->buffer + 4, chunk - 4);
+ if (ret)
+ goto out;
+ break;
+ case MVMS_DAT:
+ ret = if_sdio_handle_data(card, card->buffer + 4, chunk - 4);
+ if (ret)
+ goto out;
+ break;
+ case MVMS_EVENT:
+ ret = if_sdio_handle_event(card, card->buffer + 4, chunk - 4);
+ if (ret)
+ goto out;
+ break;
+ default:
+ lbs_deb_sdio("invalid type (%d) from firmware\n",
+ (int)type);
+ ret = -EINVAL;
+ goto out;
+ }
+
+out:
+ if (ret)
+ lbs_pr_err("problem fetching packet from firmware\n");
+
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static void if_sdio_host_to_card_worker(struct work_struct *work)
+{
+ struct if_sdio_card *card;
+ struct if_sdio_packet *packet;
+ unsigned long timeout;
+ u8 status;
+ int ret;
+ unsigned long flags;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ card = container_of(work, struct if_sdio_card, packet_worker);
+
+ while (1) {
+ spin_lock_irqsave(&card->lock, flags);
+ packet = card->packets;
+ if (packet)
+ card->packets = packet->next;
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ if (!packet)
+ break;
+
+ sdio_claim_host(card->func);
+
+ timeout = jiffies + HZ;
+ while (1) {
+ status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
+ if (ret)
+ goto release;
+ if (status & IF_SDIO_IO_RDY)
+ break;
+ if (time_after(jiffies, timeout)) {
+ ret = -ETIMEDOUT;
+ goto release;
+ }
+ mdelay(1);
+ }
+
+ ret = sdio_writesb(card->func, card->ioport,
+ packet->buffer, packet->nb);
+ if (ret)
+ goto release;
+release:
+ sdio_release_host(card->func);
+
+ kfree(packet);
+ }
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+}
+
+/********************************************************************/
+/* Firmware */
+/********************************************************************/
+
+static int if_sdio_prog_helper(struct if_sdio_card *card)
+{
+ int ret;
+ u8 status;
+ const struct firmware *fw;
+ unsigned long timeout;
+ u8 *chunk_buffer;
+ u32 chunk_size;
+ u8 *firmware;
+ size_t size;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ ret = request_firmware(&fw, card->helper, &card->func->dev);
+ if (ret) {
+ lbs_pr_err("can't load helper firmware\n");
+ goto out;
+ }
+
+ chunk_buffer = kzalloc(64, GFP_KERNEL);
+ if (!chunk_buffer) {
+ ret = -ENOMEM;
+ goto release_fw;
+ }
+
+ sdio_claim_host(card->func);
+
+ ret = sdio_set_block_size(card->func, 32);
+ if (ret)
+ goto release;
+
+ firmware = fw->data;
+ size = fw->size;
+
+ while (size) {
+ timeout = jiffies + HZ;
+ while (1) {
+ status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
+ if (ret)
+ goto release;
+ if ((status & IF_SDIO_IO_RDY) &&
+ (status & IF_SDIO_DL_RDY))
+ break;
+ if (time_after(jiffies, timeout)) {
+ ret = -ETIMEDOUT;
+ goto release;
+ }
+ mdelay(1);
+ }
+
+ chunk_size = min(size, (size_t)60);
+
+ *((u32*)chunk_buffer) = cpu_to_le32(chunk_size);
+ memcpy(chunk_buffer + 4, firmware, chunk_size);
+/*
+ lbs_deb_sdio("sending %d bytes chunk\n", chunk_size);
+*/
+ ret = sdio_writesb(card->func, card->ioport,
+ chunk_buffer, 64);
+ if (ret)
+ goto release;
+
+ firmware += chunk_size;
+ size -= chunk_size;
+ }
+
+ /* an empty block marks the end of the transfer */
+ memset(chunk_buffer, 0, 4);
+ ret = sdio_writesb(card->func, card->ioport, chunk_buffer, 64);
+ if (ret)
+ goto release;
+
+ lbs_deb_sdio("waiting for helper to boot...\n");
+
+ /* wait for the helper to boot by looking at the size register */
+ timeout = jiffies + HZ;
+ while (1) {
+ u16 req_size;
+
+ req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
+ if (ret)
+ goto release;
+
+ req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
+ if (ret)
+ goto release;
+
+ if (req_size != 0)
+ break;
+
+ if (time_after(jiffies, timeout)) {
+ ret = -ETIMEDOUT;
+ goto release;
+ }
+
+ msleep(10);
+ }
+
+ ret = 0;
+
+release:
+ sdio_set_block_size(card->func, 0);
+ sdio_release_host(card->func);
+ kfree(chunk_buffer);
+release_fw:
+ release_firmware(fw);
+
+out:
+ if (ret)
+ lbs_pr_err("failed to load helper firmware\n");
+
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static int if_sdio_prog_real(struct if_sdio_card *card)
+{
+ int ret;
+ u8 status;
+ const struct firmware *fw;
+ unsigned long timeout;
+ u8 *chunk_buffer;
+ u32 chunk_size;
+ u8 *firmware;
+ size_t size, req_size;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ ret = request_firmware(&fw, card->firmware, &card->func->dev);
+ if (ret) {
+ lbs_pr_err("can't load firmware\n");
+ goto out;
+ }
+
+ chunk_buffer = kzalloc(512, GFP_KERNEL);
+ if (!chunk_buffer) {
+ ret = -ENOMEM;
+ goto release_fw;
+ }
+
+ sdio_claim_host(card->func);
+
+ ret = sdio_set_block_size(card->func, 32);
+ if (ret)
+ goto release;
+
+ firmware = fw->data;
+ size = fw->size;
+
+ while (size) {
+ timeout = jiffies + HZ;
+ while (1) {
+ status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
+ if (ret)
+ goto release;
+ if ((status & IF_SDIO_IO_RDY) &&
+ (status & IF_SDIO_DL_RDY))
+ break;
+ if (time_after(jiffies, timeout)) {
+ ret = -ETIMEDOUT;
+ goto release;
+ }
+ mdelay(1);
+ }
+
+ req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
+ if (ret)
+ goto release;
+
+ req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
+ if (ret)
+ goto release;
+/*
+ lbs_deb_sdio("firmware wants %d bytes\n", (int)req_size);
+*/
+ if (req_size == 0) {
+ lbs_deb_sdio("firmware helper gave up early\n");
+ ret = -EIO;
+ goto release;
+ }
+
+ if (req_size & 0x01) {
+ lbs_deb_sdio("firmware helper signalled error\n");
+ ret = -EIO;
+ goto release;
+ }
+
+ if (req_size > size)
+ req_size = size;
+
+ while (req_size) {
+ chunk_size = min(req_size, (size_t)512);
+
+ memcpy(chunk_buffer, firmware, chunk_size);
+/*
+ lbs_deb_sdio("sending %d bytes (%d bytes) chunk\n",
+ chunk_size, (chunk_size + 31) / 32 * 32);
+*/
+ ret = sdio_writesb(card->func, card->ioport,
+ chunk_buffer, (chunk_size + 31) / 32 * 32);
+ if (ret)
+ goto release;
+
+ firmware += chunk_size;
+ size -= chunk_size;
+ req_size -= chunk_size;
+ }
+ }
+
+ ret = 0;
+
+ lbs_deb_sdio("waiting for firmware to boot...\n");
+
+ /* wait for the firmware to boot */
+ timeout = jiffies + HZ;
+ while (1) {
+ u16 scratch;
+
+ scratch = if_sdio_read_scratch(card, &ret);
+ if (ret)
+ goto release;
+
+ if (scratch == IF_SDIO_FIRMWARE_OK)
+ break;
+
+ if (time_after(jiffies, timeout)) {
+ ret = -ETIMEDOUT;
+ goto release;
+ }
+
+ msleep(10);
+ }
+
+ ret = 0;
+
+release:
+ sdio_set_block_size(card->func, 0);
+ sdio_release_host(card->func);
+ kfree(chunk_buffer);
+release_fw:
+ release_firmware(fw);
+
+out:
+ if (ret)
+ lbs_pr_err("failed to load firmware\n");
+
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static int if_sdio_prog_firmware(struct if_sdio_card *card)
+{
+ int ret;
+ u16 scratch;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ sdio_claim_host(card->func);
+ scratch = if_sdio_read_scratch(card, &ret);
+ sdio_release_host(card->func);
+
+ if (ret)
+ goto out;
+
+ if (scratch == IF_SDIO_FIRMWARE_OK) {
+ lbs_deb_sdio("firmware already loaded\n");
+ goto success;
+ }
+
+ ret = if_sdio_prog_helper(card);
+ if (ret)
+ goto out;
+
+ ret = if_sdio_prog_real(card);
+ if (ret)
+ goto out;
+
+success:
+ ret = 0;
+
+out:
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+/*******************************************************************/
+/* Libertas callbacks */
+/*******************************************************************/
+
+static int if_sdio_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb)
+{
+ int ret;
+ struct if_sdio_card *card;
+ struct if_sdio_packet *packet, *cur;
+ u16 size;
+ unsigned long flags;
+
+ lbs_deb_enter_args(LBS_DEB_SDIO, "type %d, bytes %d", type, nb);
+
+ card = priv->card;
+
+ if (nb > (65536 - sizeof(struct if_sdio_packet) - 4)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * The transfer must be in one transaction or the firmware
+ * goes suicidal.
+ */
+ size = nb + 4;
+ if ((size > card->func->cur_blksize) || (size > 512)) {
+ size = (size + card->func->cur_blksize - 1) /
+ card->func->cur_blksize * card->func->cur_blksize;
+ }
+
+ packet = kzalloc(sizeof(struct if_sdio_packet) + size,
+ GFP_ATOMIC);
+ if (!packet) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ packet->next = NULL;
+ packet->nb = size;
+
+ /*
+ * SDIO specific header.
+ */
+ packet->buffer[0] = (nb + 4) & 0xff;
+ packet->buffer[1] = ((nb + 4) >> 8) & 0xff;
+ packet->buffer[2] = type;
+ packet->buffer[3] = 0;
+
+ memcpy(packet->buffer + 4, buf, nb);
+
+ spin_lock_irqsave(&card->lock, flags);
+
+ if (!card->packets)
+ card->packets = packet;
+ else {
+ cur = card->packets;
+ while (cur->next)
+ cur = cur->next;
+ cur->next = packet;
+ }
+
+ switch (type) {
+ case MVMS_CMD:
+ priv->dnld_sent = DNLD_CMD_SENT;
+ break;
+ case MVMS_DAT:
+ priv->dnld_sent = DNLD_DATA_SENT;
+ break;
+ default:
+ lbs_deb_sdio("unknown packet type %d\n", (int)type);
+ }
+
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ schedule_work(&card->packet_worker);
+
+ ret = 0;
+
+out:
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static int if_sdio_get_int_status(wlan_private *priv, u8 *ireg)
+{
+ struct if_sdio_card *card;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ card = priv->card;
+
+ *ireg = card->int_cause;
+ card->int_cause = 0;
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+
+ return 0;
+}
+
+static int if_sdio_read_event_cause(wlan_private *priv)
+{
+ struct if_sdio_card *card;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ card = priv->card;
+
+ priv->adapter->eventcause = card->event;
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+
+ return 0;
+}
+
+/*******************************************************************/
+/* SDIO callbacks */
+/*******************************************************************/
+
+static void if_sdio_interrupt(struct sdio_func *func)
+{
+ int ret;
+ struct if_sdio_card *card;
+ u8 cause;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ card = sdio_get_drvdata(func);
+
+ cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
+ if (ret)
+ goto out;
+
+ lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
+
+ sdio_writeb(card->func, ~cause, IF_SDIO_H_INT_STATUS, &ret);
+ if (ret)
+ goto out;
+
+ /*
+ * Ignore the define name, this really means the card has
+ * successfully received the command.
+ */
+ if (cause & IF_SDIO_H_INT_DNLD) {
+ if ((card->priv->dnld_sent == DNLD_DATA_SENT) &&
+ (card->priv->adapter->connect_status == LIBERTAS_CONNECTED))
+ netif_wake_queue(card->priv->dev);
+ card->priv->dnld_sent = DNLD_RES_RECEIVED;
+ }
+
+ if (cause & IF_SDIO_H_INT_UPLD) {
+ ret = if_sdio_card_to_host(card);
+ if (ret)
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+}
+
+static int if_sdio_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ struct if_sdio_card *card;
+ wlan_private *priv;
+ int ret, i;
+ unsigned int model;
+ struct if_sdio_packet *packet;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ for (i = 0;i < func->card->num_info;i++) {
+ if (sscanf(func->card->info[i],
+ "802.11 SDIO ID: %x", &model) == 1)
+ break;
+ if (sscanf(func->card->info[i],
+ "ID: %x", &model) == 1)
+ break;
+ }
+
+ if (i == func->card->num_info) {
+ lbs_pr_err("unable to identify card model\n");
+ return -ENODEV;
+ }
+
+ card = kzalloc(sizeof(struct if_sdio_card), GFP_KERNEL);
+ if (!card)
+ return -ENOMEM;
+
+ card->func = func;
+ card->model = model;
+ spin_lock_init(&card->lock);
+ INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
+
+ for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) {
+ if (card->model == if_sdio_models[i].model)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(if_sdio_models)) {
+ lbs_pr_err("unkown card model 0x%x\n", card->model);
+ ret = -ENODEV;
+ goto free;
+ }
+
+ card->helper = if_sdio_models[i].helper;
+ card->firmware = if_sdio_models[i].firmware;
+
+ if (libertas_helper_name) {
+ lbs_deb_sdio("overriding helper firmware: %s\n",
+ libertas_helper_name);
+ card->helper = libertas_helper_name;
+ }
+
+ if (libertas_fw_name) {
+ lbs_deb_sdio("overriding firmware: %s\n", libertas_fw_name);
+ card->firmware = libertas_fw_name;
+ }
+
+ sdio_claim_host(func);
+
+ ret = sdio_enable_func(func);
+ if (ret)
+ goto release;
+
+ ret = sdio_claim_irq(func, if_sdio_interrupt);
+ if (ret)
+ goto disable;
+
+ card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
+ if (ret)
+ goto release_int;
+
+ card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8;
+ if (ret)
+ goto release_int;
+
+ card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16;
+ if (ret)
+ goto release_int;
+
+ sdio_release_host(func);
+
+ sdio_set_drvdata(func, card);
+
+ lbs_deb_sdio("class = 0x%X, vendor = 0x%X, "
+ "device = 0x%X, model = 0x%X, ioport = 0x%X\n",
+ func->class, func->vendor, func->device,
+ model, (unsigned)card->ioport);
+
+ ret = if_sdio_prog_firmware(card);
+ if (ret)
+ goto reclaim;
+
+ priv = libertas_add_card(card, &func->dev);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto reclaim;
+ }
+
+ card->priv = priv;
+
+ priv->card = card;
+ priv->hw_host_to_card = if_sdio_host_to_card;
+ priv->hw_get_int_status = if_sdio_get_int_status;
+ priv->hw_read_event_cause = if_sdio_read_event_cause;
+
+ priv->adapter->fw_ready = 1;
+
+ /*
+ * Enable interrupts now that everything is set up
+ */
+ sdio_claim_host(func);
+ sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret);
+ sdio_release_host(func);
+ if (ret)
+ goto reclaim;
+
+ ret = libertas_start_card(priv);
+ if (ret)
+ goto err_activate_card;
+
+out:
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+
+err_activate_card:
+ flush_scheduled_work();
+ free_netdev(priv->dev);
+ kfree(priv->adapter);
+reclaim:
+ sdio_claim_host(func);
+release_int:
+ sdio_release_irq(func);
+disable:
+ sdio_disable_func(func);
+release:
+ sdio_release_host(func);
+free:
+ while (card->packets) {
+ packet = card->packets;
+ card->packets = card->packets->next;
+ kfree(packet);
+ }
+
+ kfree(card);
+
+ goto out;
+}
+
+static void if_sdio_remove(struct sdio_func *func)
+{
+ struct if_sdio_card *card;
+ struct if_sdio_packet *packet;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ card = sdio_get_drvdata(func);
+
+ card->priv->adapter->surpriseremoved = 1;
+
+ lbs_deb_sdio("call remove card\n");
+ libertas_stop_card(card->priv);
+ libertas_remove_card(card->priv);
+
+ flush_scheduled_work();
+
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+
+ while (card->packets) {
+ packet = card->packets;
+ card->packets = card->packets->next;
+ kfree(packet);
+ }
+
+ kfree(card);
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+}
+
+static struct sdio_driver if_sdio_driver = {
+ .name = "libertas_sdio",
+ .id_table = if_sdio_ids,
+ .probe = if_sdio_probe,
+ .remove = if_sdio_remove,
+};
+
+/*******************************************************************/
+/* Module functions */
+/*******************************************************************/
+
+static int if_sdio_init_module(void)
+{
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ printk(KERN_INFO "libertas_sdio: Libertas SDIO driver\n");
+ printk(KERN_INFO "libertas_sdio: Copyright Pierre Ossman\n");
+
+ ret = sdio_register_driver(&if_sdio_driver);
+
+ lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
+
+ return ret;
+}
+
+static void if_sdio_exit_module(void)
+{
+ lbs_deb_enter(LBS_DEB_SDIO);
+
+ sdio_unregister_driver(&if_sdio_driver);
+
+ lbs_deb_leave(LBS_DEB_SDIO);
+}
+
+module_init(if_sdio_init_module);
+module_exit(if_sdio_exit_module);
+
+MODULE_DESCRIPTION("Libertas SDIO WLAN Driver");
+MODULE_AUTHOR("Pierre Ossman");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h
new file mode 100644
index 00000000000..dfcaea7b168
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_sdio.h
@@ -0,0 +1,45 @@
+/*
+ * linux/drivers/net/wireless/libertas/if_sdio.h
+ *
+ * Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#ifndef LIBERTAS_IF_SDIO_H
+#define LIBERTAS_IF_SDIO_H
+
+#define IF_SDIO_IOPORT 0x00
+
+#define IF_SDIO_H_INT_MASK 0x04
+#define IF_SDIO_H_INT_OFLOW 0x08
+#define IF_SDIO_H_INT_UFLOW 0x04
+#define IF_SDIO_H_INT_DNLD 0x02
+#define IF_SDIO_H_INT_UPLD 0x01
+
+#define IF_SDIO_H_INT_STATUS 0x05
+#define IF_SDIO_H_INT_RSR 0x06
+#define IF_SDIO_H_INT_STATUS2 0x07
+
+#define IF_SDIO_RD_BASE 0x10
+
+#define IF_SDIO_STATUS 0x20
+#define IF_SDIO_IO_RDY 0x08
+#define IF_SDIO_CIS_RDY 0x04
+#define IF_SDIO_UL_RDY 0x02
+#define IF_SDIO_DL_RDY 0x01
+
+#define IF_SDIO_C_INT_MASK 0x24
+#define IF_SDIO_C_INT_STATUS 0x28
+#define IF_SDIO_C_INT_RSR 0x2C
+
+#define IF_SDIO_SCRATCH 0x34
+#define IF_SDIO_SCRATCH_OLD 0x80fe
+#define IF_SDIO_FIRMWARE_OK 0xfedc
+
+#define IF_SDIO_EVENT 0x80fc
+
+#endif
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 998317571ec..cb59f46ed12 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -21,7 +21,7 @@
static const char usbdriver_name[] = "usb8xxx";
static u8 *default_fw_name = "usb8388.bin";
-char *libertas_fw_name = NULL;
+static char *libertas_fw_name = NULL;
module_param_named(fw_name, libertas_fw_name, charp, 0644);
/*
@@ -44,13 +44,14 @@ MODULE_DEVICE_TABLE(usb, if_usb_table);
static void if_usb_receive(struct urb *urb);
static void if_usb_receive_fwload(struct urb *urb);
-static int if_usb_reset_device(wlan_private *priv);
-static int if_usb_register_dev(wlan_private * priv);
-static int if_usb_unregister_dev(wlan_private *);
-static int if_usb_prog_firmware(wlan_private *);
+static int if_usb_prog_firmware(struct usb_card_rec *cardp);
static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
static int if_usb_get_int_status(wlan_private * priv, u8 *);
static int if_usb_read_event_cause(wlan_private *);
+static int usb_tx_block(struct usb_card_rec *cardp, u8 *payload, u16 nb);
+static void if_usb_free(struct usb_card_rec *cardp);
+static int if_usb_submit_rx_urb(struct usb_card_rec *cardp);
+static int if_usb_reset_device(struct usb_card_rec *cardp);
/**
* @brief call back function to handle the status of the URB
@@ -59,29 +60,40 @@ static int if_usb_read_event_cause(wlan_private *);
*/
static void if_usb_write_bulk_callback(struct urb *urb)
{
- wlan_private *priv = (wlan_private *) (urb->context);
- wlan_adapter *adapter = priv->adapter;
- struct net_device *dev = priv->dev;
+ struct usb_card_rec *cardp = (struct usb_card_rec *) urb->context;
/* handle the transmission complete validations */
- if (urb->status != 0) {
- /* print the failure status number for debug */
- lbs_pr_info("URB in failure status: %d\n", urb->status);
- } else {
+ if (urb->status == 0) {
+ wlan_private *priv = cardp->priv;
+
/*
lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n");
lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n",
urb->actual_length);
*/
- priv->dnld_sent = DNLD_RES_RECEIVED;
- /* Wake main thread if commands are pending */
- if (!adapter->cur_cmd)
- wake_up_interruptible(&priv->mainthread.waitq);
- if ((adapter->connect_status == libertas_connected)) {
- netif_wake_queue(dev);
- netif_wake_queue(priv->mesh_dev);
+
+ /* Used for both firmware TX and regular TX. priv isn't
+ * valid at firmware load time.
+ */
+ if (priv) {
+ wlan_adapter *adapter = priv->adapter;
+ struct net_device *dev = priv->dev;
+
+ priv->dnld_sent = DNLD_RES_RECEIVED;
+
+ /* Wake main thread if commands are pending */
+ if (!adapter->cur_cmd)
+ wake_up_interruptible(&priv->waitq);
+
+ if ((adapter->connect_status == LIBERTAS_CONNECTED)) {
+ netif_wake_queue(dev);
+ netif_wake_queue(priv->mesh_dev);
+ }
}
+ } else {
+ /* print the failure status number for debug */
+ lbs_pr_info("URB in failure status: %d\n", urb->status);
}
return;
@@ -92,7 +104,7 @@ static void if_usb_write_bulk_callback(struct urb *urb)
* @param cardp pointer usb_card_rec
* @return N/A
*/
-void if_usb_free(struct usb_card_rec *cardp)
+static void if_usb_free(struct usb_card_rec *cardp)
{
lbs_deb_enter(LBS_DEB_USB);
@@ -203,21 +215,35 @@ static int if_usb_probe(struct usb_interface *intf,
}
}
+ /* Upload firmware */
+ cardp->rinfo.cardp = cardp;
+ if (if_usb_prog_firmware(cardp)) {
+ lbs_deb_usbd(&udev->dev, "FW upload failed");
+ goto err_prog_firmware;
+ }
+
if (!(priv = libertas_add_card(cardp, &udev->dev)))
- goto dealloc;
+ goto err_prog_firmware;
+
+ cardp->priv = priv;
if (libertas_add_mesh(priv, &udev->dev))
goto err_add_mesh;
- priv->hw_register_dev = if_usb_register_dev;
- priv->hw_unregister_dev = if_usb_unregister_dev;
- priv->hw_prog_firmware = if_usb_prog_firmware;
+ cardp->eth_dev = priv->dev;
+
priv->hw_host_to_card = if_usb_host_to_card;
priv->hw_get_int_status = if_usb_get_int_status;
priv->hw_read_event_cause = if_usb_read_event_cause;
+ priv->boot2_version = udev->descriptor.bcdDevice;
- if (libertas_activate_card(priv, libertas_fw_name))
- goto err_activate_card;
+ /* Delay 200 ms to waiting for the FW ready */
+ if_usb_submit_rx_urb(cardp);
+ msleep_interruptible(200);
+ priv->adapter->fw_ready = 1;
+
+ if (libertas_start_card(priv))
+ goto err_start_card;
list_add_tail(&cardp->list, &usb_devices);
@@ -226,11 +252,12 @@ static int if_usb_probe(struct usb_interface *intf,
return 0;
-err_activate_card:
+err_start_card:
libertas_remove_mesh(priv);
err_add_mesh:
- free_netdev(priv->dev);
- kfree(priv->adapter);
+ libertas_remove_card(priv);
+err_prog_firmware:
+ if_usb_reset_device(cardp);
dealloc:
if_usb_free(cardp);
@@ -247,21 +274,22 @@ static void if_usb_disconnect(struct usb_interface *intf)
{
struct usb_card_rec *cardp = usb_get_intfdata(intf);
wlan_private *priv = (wlan_private *) cardp->priv;
- wlan_adapter *adapter = NULL;
- adapter = priv->adapter;
+ lbs_deb_enter(LBS_DEB_MAIN);
- /*
- * Update Surprise removed to TRUE
- */
- adapter->surpriseremoved = 1;
+ /* Update Surprise removed to TRUE */
+ cardp->surprise_removed = 1;
list_del(&cardp->list);
- /* card is removed and we can call wlan_remove_card */
- lbs_deb_usbd(&cardp->udev->dev, "call remove card\n");
- libertas_remove_mesh(priv);
- libertas_remove_card(priv);
+ if (priv) {
+ wlan_adapter *adapter = priv->adapter;
+
+ adapter->surpriseremoved = 1;
+ libertas_stop_card(priv);
+ libertas_remove_mesh(priv);
+ libertas_remove_card(priv);
+ }
/* Unlink and free urb */
if_usb_free(cardp);
@@ -269,7 +297,7 @@ static void if_usb_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);
usb_put_dev(interface_to_usbdev(intf));
- return;
+ lbs_deb_leave(LBS_DEB_MAIN);
}
/**
@@ -277,12 +305,11 @@ static void if_usb_disconnect(struct usb_interface *intf)
* @param priv pointer to wlan_private
* @return 0
*/
-static int if_prog_firmware(wlan_private * priv)
+static int if_prog_firmware(struct usb_card_rec *cardp)
{
- struct usb_card_rec *cardp = priv->card;
struct FWData *fwdata;
struct fwheader *fwheader;
- u8 *firmware = priv->firmware->data;
+ u8 *firmware = cardp->fw->data;
fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
@@ -330,7 +357,7 @@ static int if_prog_firmware(wlan_private * priv)
cardp->totalbytes);
*/
memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
- usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+ usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
} else if (fwdata->fwheader.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
/*
@@ -340,7 +367,7 @@ static int if_prog_firmware(wlan_private * priv)
"Donwloading FW JUMP BLOCK\n");
*/
memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
- usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+ usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
cardp->fwfinalblk = 1;
}
@@ -355,17 +382,20 @@ static int if_prog_firmware(wlan_private * priv)
return 0;
}
-static int libertas_do_reset(wlan_private *priv)
+static int if_usb_reset_device(struct usb_card_rec *cardp)
{
int ret;
- struct usb_card_rec *cardp = priv->card;
+ wlan_private * priv = cardp->priv;
lbs_deb_enter(LBS_DEB_USB);
+ /* Try a USB port reset first, if that fails send the reset
+ * command to the firmware.
+ */
ret = usb_reset_device(cardp->udev);
- if (!ret) {
+ if (!ret && priv) {
msleep(10);
- if_usb_reset_device(priv);
+ ret = libertas_reset_device(priv);
msleep(10);
}
@@ -381,14 +411,12 @@ static int libertas_do_reset(wlan_private *priv)
* @param nb data length
* @return 0 or -1
*/
-int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb)
+static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 nb)
{
- /* pointer to card structure */
- struct usb_card_rec *cardp = priv->card;
int ret = -1;
/* check if device is removed */
- if (priv->adapter->surpriseremoved) {
+ if (cardp->surprise_removed) {
lbs_deb_usbd(&cardp->udev->dev, "Device removed\n");
goto tx_ret;
}
@@ -396,7 +424,7 @@ int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb)
usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
usb_sndbulkpipe(cardp->udev,
cardp->bulk_out_endpointAddr),
- payload, nb, if_usb_write_bulk_callback, priv);
+ payload, nb, if_usb_write_bulk_callback, cardp);
cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
@@ -413,11 +441,9 @@ tx_ret:
return ret;
}
-static int __if_usb_submit_rx_urb(wlan_private * priv,
- void (*callbackfn)
- (struct urb *urb))
+static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp,
+ void (*callbackfn)(struct urb *urb))
{
- struct usb_card_rec *cardp = priv->card;
struct sk_buff *skb;
struct read_cb_info *rinfo = &cardp->rinfo;
int ret = -1;
@@ -453,22 +479,21 @@ rx_ret:
return ret;
}
-static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv)
+static int if_usb_submit_rx_urb_fwload(struct usb_card_rec *cardp)
{
- return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload);
+ return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);
}
-static inline int if_usb_submit_rx_urb(wlan_private * priv)
+static int if_usb_submit_rx_urb(struct usb_card_rec *cardp)
{
- return __if_usb_submit_rx_urb(priv, &if_usb_receive);
+ return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
}
static void if_usb_receive_fwload(struct urb *urb)
{
struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
- wlan_private *priv = rinfo->priv;
struct sk_buff *skb = rinfo->skb;
- struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+ struct usb_card_rec *cardp = (struct usb_card_rec *)rinfo->cardp;
struct fwsyncheader *syncfwheader;
struct bootcmdrespStr bootcmdresp;
@@ -484,7 +509,7 @@ static void if_usb_receive_fwload(struct urb *urb)
sizeof(bootcmdresp));
if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
kfree_skb(skb);
- if_usb_submit_rx_urb_fwload(priv);
+ if_usb_submit_rx_urb_fwload(cardp);
cardp->bootcmdresp = 1;
lbs_deb_usbd(&cardp->udev->dev,
"Received valid boot command response\n");
@@ -508,7 +533,7 @@ static void if_usb_receive_fwload(struct urb *urb)
"Received valid boot command response\n");
}
kfree_skb(skb);
- if_usb_submit_rx_urb_fwload(priv);
+ if_usb_submit_rx_urb_fwload(cardp);
return;
}
@@ -544,9 +569,9 @@ static void if_usb_receive_fwload(struct urb *urb)
goto exit;
}
- if_prog_firmware(priv);
+ if_prog_firmware(cardp);
- if_usb_submit_rx_urb_fwload(priv);
+ if_usb_submit_rx_urb_fwload(cardp);
exit:
kfree(syncfwheader);
@@ -596,11 +621,11 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
* data to clear the interrupt */
if (!priv->adapter->cur_cmd) {
cmdbuf = priv->upld_buf;
- priv->adapter->hisregcpy &= ~his_cmdupldrdy;
+ priv->adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
} else
cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
- cardp->usb_int_cause |= his_cmdupldrdy;
+ cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY;
priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN,
priv->upld_len);
@@ -625,17 +650,19 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
static void if_usb_receive(struct urb *urb)
{
struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
- wlan_private *priv = rinfo->priv;
struct sk_buff *skb = rinfo->skb;
- struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+ struct usb_card_rec *cardp = (struct usb_card_rec *) rinfo->cardp;
+ wlan_private * priv = cardp->priv;
int recvlength = urb->actual_length;
u8 *recvbuff = NULL;
- u32 recvtype;
+ u32 recvtype = 0;
lbs_deb_enter(LBS_DEB_USB);
if (recvlength) {
+ __le32 tmp;
+
if (urb->status) {
lbs_deb_usbd(&cardp->udev->dev,
"URB status is failed\n");
@@ -644,18 +671,14 @@ static void if_usb_receive(struct urb *urb)
}
recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
- memcpy(&recvtype, recvbuff, sizeof(u32));
- lbs_deb_usbd(&cardp->udev->dev,
- "Recv length = 0x%x\n", recvlength);
- lbs_deb_usbd(&cardp->udev->dev,
- "Receive type = 0x%X\n", recvtype);
- recvtype = le32_to_cpu(recvtype);
+ memcpy(&tmp, recvbuff, sizeof(u32));
+ recvtype = le32_to_cpu(tmp);
lbs_deb_usbd(&cardp->udev->dev,
- "Receive type after = 0x%X\n", recvtype);
+ "Recv length = 0x%x, Recv type = 0x%X\n",
+ recvlength, recvtype);
} else if (urb->status)
goto rx_exit;
-
switch (recvtype) {
case CMD_TYPE_DATA:
process_cmdtypedata(recvlength, skb, cardp, priv);
@@ -677,18 +700,20 @@ static void if_usb_receive(struct urb *urb)
break;
}
cardp->usb_event_cause <<= 3;
- cardp->usb_int_cause |= his_cardevent;
+ cardp->usb_int_cause |= MRVDRV_CARDEVENT;
kfree_skb(skb);
libertas_interrupt(priv->dev);
spin_unlock(&priv->adapter->driver_lock);
goto rx_exit;
default:
+ lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
+ recvtype);
kfree_skb(skb);
break;
}
setup_for_next:
- if_usb_submit_rx_urb(priv);
+ if_usb_submit_rx_urb(cardp);
rx_exit:
lbs_deb_leave(LBS_DEB_USB);
}
@@ -703,21 +728,19 @@ rx_exit:
*/
static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
{
- int ret = -1;
- u32 tmp;
struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type);
lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb);
if (type == MVMS_CMD) {
- tmp = cpu_to_le32(CMD_TYPE_REQUEST);
+ __le32 tmp = cpu_to_le32(CMD_TYPE_REQUEST);
priv->dnld_sent = DNLD_CMD_SENT;
memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
MESSAGE_HEADER_LEN);
} else {
- tmp = cpu_to_le32(CMD_TYPE_DATA);
+ __le32 tmp = cpu_to_le32(CMD_TYPE_DATA);
priv->dnld_sent = DNLD_DATA_SENT;
memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
MESSAGE_HEADER_LEN);
@@ -725,10 +748,8 @@ static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 n
memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb);
- ret =
- usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN);
-
- return ret;
+ return usb_tx_block(cardp, cardp->bulk_out_buffer,
+ nb + MESSAGE_HEADER_LEN);
}
/* called with adapter->driver_lock held */
@@ -747,80 +768,109 @@ static int if_usb_get_int_status(wlan_private * priv, u8 * ireg)
static int if_usb_read_event_cause(wlan_private * priv)
{
struct usb_card_rec *cardp = priv->card;
+
priv->adapter->eventcause = cardp->usb_event_cause;
/* Re-submit rx urb here to avoid event lost issue */
- if_usb_submit_rx_urb(priv);
+ if_usb_submit_rx_urb(cardp);
return 0;
}
-static int if_usb_reset_device(wlan_private *priv)
+/**
+ * @brief This function issues Boot command to the Boot2 code
+ * @param ivalue 1:Boot from FW by USB-Download
+ * 2:Boot from FW in EEPROM
+ * @return 0
+ */
+static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue)
{
- int ret;
-
- lbs_deb_enter(LBS_DEB_USB);
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset,
- cmd_act_halt, 0, 0, NULL);
- msleep_interruptible(10);
-
- lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
- return ret;
-}
+ struct bootcmdstr sbootcmd;
+ int i;
-static int if_usb_unregister_dev(wlan_private * priv)
-{
- int ret = 0;
+ /* Prepare command */
+ sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
+ sbootcmd.u8cmd_tag = ivalue;
+ for (i=0; i<11; i++)
+ sbootcmd.au8dumy[i]=0x00;
+ memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
- /* Need to send a Reset command to device before USB resources freed
- * and wlan_remove_card() called, then device can handle FW download
- * again.
- */
- if (priv)
- if_usb_reset_device(priv);
+ /* Issue command */
+ usb_tx_block(cardp, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
- return ret;
+ return 0;
}
/**
- * @brief This function register usb device and initialize parameter
- * @param priv pointer to wlan_private
- * @return 0 or -1
+ * @brief This function checks the validity of Boot2/FW image.
+ *
+ * @param data pointer to image
+ * len image length
+ * @return 0 or -1
*/
-static int if_usb_register_dev(wlan_private * priv)
+static int check_fwfile_format(u8 *data, u32 totlen)
{
- struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+ u32 bincmd, exit;
+ u32 blksize, offset, len;
+ int ret;
- lbs_deb_enter(LBS_DEB_USB);
+ ret = 1;
+ exit = len = 0;
- cardp->priv = priv;
- cardp->eth_dev = priv->dev;
- priv->hotplug_device = &(cardp->udev->dev);
+ do {
+ struct fwheader *fwh = (void *)data;
+
+ bincmd = le32_to_cpu(fwh->dnldcmd);
+ blksize = le32_to_cpu(fwh->datalength);
+ switch (bincmd) {
+ case FW_HAS_DATA_TO_RECV:
+ offset = sizeof(struct fwheader) + blksize;
+ data += offset;
+ len += offset;
+ if (len >= totlen)
+ exit = 1;
+ break;
+ case FW_HAS_LAST_BLOCK:
+ exit = 1;
+ ret = 0;
+ break;
+ default:
+ exit = 1;
+ break;
+ }
+ } while (!exit);
- lbs_deb_usbd(&cardp->udev->dev, "udev pointer is at %p\n",
- cardp->udev);
+ if (ret)
+ lbs_pr_err("firmware file format check FAIL\n");
+ else
+ lbs_deb_fw("firmware file format check PASS\n");
- lbs_deb_leave(LBS_DEB_USB);
- return 0;
+ return ret;
}
-
-static int if_usb_prog_firmware(wlan_private * priv)
+static int if_usb_prog_firmware(struct usb_card_rec *cardp)
{
- struct usb_card_rec *cardp = priv->card;
int i = 0;
static int reset_count = 10;
int ret = 0;
lbs_deb_enter(LBS_DEB_USB);
- cardp->rinfo.priv = priv;
+ if ((ret = request_firmware(&cardp->fw, libertas_fw_name,
+ &cardp->udev->dev)) < 0) {
+ lbs_pr_err("request_firmware() failed with %#x\n", ret);
+ lbs_pr_err("firmware %s not found\n", libertas_fw_name);
+ goto done;
+ }
+
+ if (check_fwfile_format(cardp->fw->data, cardp->fw->size))
+ goto release_fw;
restart:
- if (if_usb_submit_rx_urb_fwload(priv) < 0) {
+ if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
ret = -1;
- goto done;
+ goto release_fw;
}
cardp->bootcmdresp = 0;
@@ -828,7 +878,7 @@ restart:
int j = 0;
i++;
/* Issue Boot command = 1, Boot from Download-FW */
- if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB);
+ if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
/* wait for command response */
do {
j++;
@@ -838,14 +888,13 @@ restart:
if (cardp->bootcmdresp == 0) {
if (--reset_count >= 0) {
- libertas_do_reset(priv);
+ if_usb_reset_device(cardp);
goto restart;
}
return -1;
}
i = 0;
- priv->adapter->fw_ready = 0;
cardp->totalbytes = 0;
cardp->fwlastblksent = 0;
@@ -855,40 +904,38 @@ restart:
cardp->totalbytes = 0;
cardp->fwfinalblk = 0;
- if_prog_firmware(priv);
+ if_prog_firmware(cardp);
do {
lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n");
i++;
msleep_interruptible(100);
- if (priv->adapter->surpriseremoved || i >= 20)
+ if (cardp->surprise_removed || i >= 20)
break;
} while (!cardp->fwdnldover);
if (!cardp->fwdnldover) {
lbs_pr_info("failed to load fw, resetting device!\n");
if (--reset_count >= 0) {
- libertas_do_reset(priv);
+ if_usb_reset_device(cardp);
goto restart;
}
lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
ret = -1;
- goto done;
+ goto release_fw;
}
- if_usb_submit_rx_urb(priv);
-
- /* Delay 200 ms to waiting for the FW ready */
- msleep_interruptible(200);
-
- priv->adapter->fw_ready = 1;
+release_fw:
+ release_firmware(cardp->fw);
+ cardp->fw = NULL;
done:
lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
return ret;
}
+
#ifdef CONFIG_PM
static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
{
@@ -900,6 +947,19 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
if (priv->adapter->psstate != PS_STATE_FULL_POWER)
return -1;
+ if (priv->mesh_dev && !priv->mesh_autostart_enabled) {
+ /* Mesh autostart must be activated while sleeping
+ * On resume it will go back to the current state
+ */
+ struct cmd_ds_mesh_access mesh_access;
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ mesh_access.data[0] = cpu_to_le32(1);
+ libertas_prepare_and_send_command(priv,
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ }
+
netif_device_detach(cardp->eth_dev);
netif_device_detach(priv->mesh_dev);
@@ -927,6 +987,19 @@ static int if_usb_resume(struct usb_interface *intf)
netif_device_attach(cardp->eth_dev);
netif_device_attach(priv->mesh_dev);
+ if (priv->mesh_dev && !priv->mesh_autostart_enabled) {
+ /* Mesh autostart was activated while sleeping
+ * Disable it if appropriate
+ */
+ struct cmd_ds_mesh_access mesh_access;
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ mesh_access.data[0] = cpu_to_le32(0);
+ libertas_prepare_and_send_command(priv,
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ }
+
lbs_deb_leave(LBS_DEB_USB);
return 0;
}
@@ -970,8 +1043,10 @@ static void if_usb_exit_module(void)
lbs_deb_enter(LBS_DEB_MAIN);
- list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list)
- if_usb_reset_device((wlan_private *) cardp->priv);
+ list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list) {
+ libertas_prepare_and_send_command(cardp->priv, CMD_802_11_RESET,
+ CMD_ACT_HALT, 0, 0, NULL);
+ }
/* API unregisters the driver from USB subsystem */
usb_deregister(&if_usb_driver);
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
index 156bb485e1a..e07a10ed28b 100644
--- a/drivers/net/wireless/libertas/if_usb.h
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -38,7 +38,7 @@ struct bootcmdrespStr
/* read callback private data */
struct read_cb_info {
- wlan_private *priv;
+ struct usb_card_rec *cardp;
struct sk_buff *skb;
};
@@ -58,6 +58,7 @@ struct usb_card_rec {
int bulk_out_size;
u8 bulk_out_endpointAddr;
+ const struct firmware *fw;
u8 CRC_OK;
u32 fwseqnum;
u32 lastseqnum;
@@ -65,6 +66,7 @@ struct usb_card_rec {
u32 fwlastblksent;
u8 fwdnldover;
u8 fwfinalblk;
+ u8 surprise_removed;
u32 usb_event_cause;
u8 usb_int_cause;
@@ -102,8 +104,4 @@ struct fwsyncheader {
#define FW_DATA_XMIT_SIZE \
sizeof(struct fwheader) + le32_to_cpu(fwdata->fwheader.datalength) + sizeof(u32)
-int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb);
-void if_usb_free(struct usb_card_rec *cardp);
-int if_usb_issue_boot_command(wlan_private *priv, int ivalue);
-
#endif
diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c
index 78ac3064a0b..dc24a05c944 100644
--- a/drivers/net/wireless/libertas/join.c
+++ b/drivers/net/wireless/libertas/join.c
@@ -17,10 +17,13 @@
#include "dev.h"
#include "assoc.h"
-#define AD_HOC_CAP_PRIVACY_ON 1
+/* The firmware needs certain bits masked out of the beacon-derviced capability
+ * field when associating/joining to BSSs.
+ */
+#define CAPINFO_MASK (~(0xda00))
/**
- * @brief This function finds out the common rates between rate1 and rate2.
+ * @brief This function finds common rates between rate1 and card rates.
*
* It will fill common rates in rate1 as output if found.
*
@@ -29,75 +32,87 @@
*
* @param adapter A pointer to wlan_adapter structure
* @param rate1 the buffer which keeps input and output
- * @param rate1_size the size of rate1 buffer
- * @param rate2 the buffer which keeps rate2
- * @param rate2_size the size of rate2 buffer.
+ * @param rate1_size the size of rate1 buffer; new size of buffer on return
*
* @return 0 or -1
*/
-static int get_common_rates(wlan_adapter * adapter, u8 * rate1,
- int rate1_size, u8 * rate2, int rate2_size)
+static int get_common_rates(wlan_adapter * adapter, u8 * rates, u16 *rates_size)
{
- u8 *ptr = rate1;
- int ret = 0;
+ u8 *card_rates = libertas_bg_rates;
+ size_t num_card_rates = sizeof(libertas_bg_rates);
+ int ret = 0, i, j;
u8 tmp[30];
- int i;
+ size_t tmp_size = 0;
- memset(&tmp, 0, sizeof(tmp));
- memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp)));
- memset(rate1, 0, rate1_size);
-
- /* Mask the top bit of the original values */
- for (i = 0; tmp[i] && i < sizeof(tmp); i++)
- tmp[i] &= 0x7F;
-
- for (i = 0; rate2[i] && i < rate2_size; i++) {
- /* Check for Card Rate in tmp, excluding the top bit */
- if (strchr(tmp, rate2[i] & 0x7F)) {
- /* values match, so copy the Card Rate to rate1 */
- *rate1++ = rate2[i];
+ /* For each rate in card_rates that exists in rate1, copy to tmp */
+ for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
+ for (j = 0; rates[j] && (j < *rates_size); j++) {
+ if (rates[j] == card_rates[i])
+ tmp[tmp_size++] = card_rates[i];
}
}
- lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp));
- lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size);
- lbs_dbg_hex("Common rates:", ptr, rate1_size);
- lbs_deb_join("Tx datarate is set to 0x%X\n", adapter->datarate);
+ lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
+ lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
+ lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
+ lbs_deb_join("Tx datarate is currently 0x%X\n", adapter->cur_rate);
- if (!adapter->is_datarate_auto) {
- while (*ptr) {
- if ((*ptr & 0x7f) == adapter->datarate) {
- ret = 0;
+ if (!adapter->auto_rate) {
+ for (i = 0; i < tmp_size; i++) {
+ if (tmp[i] == adapter->cur_rate)
goto done;
- }
- ptr++;
}
- lbs_pr_alert( "Previously set fixed data rate %#x isn't "
- "compatible with the network.\n", adapter->datarate);
-
+ lbs_pr_alert("Previously set fixed data rate %#x isn't "
+ "compatible with the network.\n", adapter->cur_rate);
ret = -1;
goto done;
}
-
ret = 0;
+
done:
+ memset(rates, 0, *rates_size);
+ *rates_size = min_t(int, tmp_size, *rates_size);
+ memcpy(rates, tmp, *rates_size);
return ret;
}
-int libertas_send_deauth(wlan_private * priv)
+
+/**
+ * @brief Sets the MSB on basic rates as the firmware requires
+ *
+ * Scan through an array and set the MSB for basic data rates.
+ *
+ * @param rates buffer of data rates
+ * @param len size of buffer
+ */
+static void libertas_set_basic_rate_flags(u8 * rates, size_t len)
{
- wlan_adapter *adapter = priv->adapter;
- int ret = 0;
+ int i;
- if (adapter->mode == IW_MODE_INFRA &&
- adapter->connect_status == libertas_connected)
- ret = libertas_send_deauthentication(priv);
- else
- ret = -ENOTSUPP;
+ for (i = 0; i < len; i++) {
+ if (rates[i] == 0x02 || rates[i] == 0x04 ||
+ rates[i] == 0x0b || rates[i] == 0x16)
+ rates[i] |= 0x80;
+ }
+}
- return ret;
+/**
+ * @brief Unsets the MSB on basic rates
+ *
+ * Scan through an array and unset the MSB for basic data rates.
+ *
+ * @param rates buffer of data rates
+ * @param len size of buffer
+ */
+void libertas_unset_basic_rate_flags(u8 * rates, size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ rates[i] &= 0x7f;
}
+
/**
* @brief Associate to a specific BSS discovered in a scan
*
@@ -113,23 +128,24 @@ int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req)
lbs_deb_enter(LBS_DEB_JOIN);
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate,
- 0, cmd_option_waitforrsp,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
+ 0, CMD_OPTION_WAITFORRSP,
0, assoc_req->bss.bssid);
if (ret)
goto done;
/* set preamble to firmware */
- if (adapter->capinfo.shortpreamble && assoc_req->bss.cap.shortpreamble)
- adapter->preamble = cmd_type_short_preamble;
+ if ( (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
+ adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
else
- adapter->preamble = cmd_type_long_preamble;
+ adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
libertas_set_radio_control(priv);
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate,
- 0, cmd_option_waitforrsp, 0, assoc_req);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
+ 0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
@@ -150,12 +166,12 @@ int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * ass
adapter->adhoccreate = 1;
- if (!adapter->capinfo.shortpreamble) {
- lbs_deb_join("AdhocStart: Long preamble\n");
- adapter->preamble = cmd_type_long_preamble;
- } else {
+ if (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
lbs_deb_join("AdhocStart: Short preamble\n");
- adapter->preamble = cmd_type_short_preamble;
+ adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
+ } else {
+ lbs_deb_join("AdhocStart: Long preamble\n");
+ adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
}
libertas_set_radio_control(priv);
@@ -163,8 +179,8 @@ int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * ass
lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start,
- 0, cmd_option_waitforrsp, 0, assoc_req);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
+ 0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
return ret;
}
@@ -194,25 +210,37 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso
bss->ssid_len);
/* check if the requested SSID is already joined */
- if (adapter->curbssparams.ssid_len
+ if ( adapter->curbssparams.ssid_len
&& !libertas_ssid_cmp(adapter->curbssparams.ssid,
adapter->curbssparams.ssid_len,
bss->ssid, bss->ssid_len)
- && (adapter->mode == IW_MODE_ADHOC)) {
- lbs_deb_join(
- "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
- "not attempting to re-join");
- return -1;
+ && (adapter->mode == IW_MODE_ADHOC)
+ && (adapter->connect_status == LIBERTAS_CONNECTED)) {
+ union iwreq_data wrqu;
+
+ lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
+ "current, not attempting to re-join");
+
+ /* Send the re-association event though, because the association
+ * request really was successful, even if just a null-op.
+ */
+ memset(&wrqu, 0, sizeof(wrqu));
+ memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid,
+ ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+ goto out;
}
- /*Use shortpreamble only when both creator and card supports
+ /* Use shortpreamble only when both creator and card supports
short preamble */
- if (!bss->cap.shortpreamble || !adapter->capinfo.shortpreamble) {
+ if ( !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ || !(adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
lbs_deb_join("AdhocJoin: Long preamble\n");
- adapter->preamble = cmd_type_long_preamble;
+ adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
} else {
lbs_deb_join("AdhocJoin: Short preamble\n");
- adapter->preamble = cmd_type_short_preamble;
+ adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
}
libertas_set_radio_control(priv);
@@ -222,17 +250,18 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso
adapter->adhoccreate = 0;
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join,
- 0, cmd_option_waitforrsp,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN,
+ 0, CMD_OPTION_WAITFORRSP,
OID_802_11_SSID, assoc_req);
+out:
return ret;
}
int libertas_stop_adhoc_network(wlan_private * priv)
{
- return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop,
- 0, cmd_option_waitforrsp, 0, NULL);
+ return libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP,
+ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
}
/**
@@ -243,8 +272,8 @@ int libertas_stop_adhoc_network(wlan_private * priv)
*/
int libertas_send_deauthentication(wlan_private * priv)
{
- return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate,
- 0, cmd_option_waitforrsp, 0, NULL);
+ return libertas_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE,
+ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
}
/**
@@ -264,10 +293,11 @@ int libertas_cmd_80211_authenticate(wlan_private * priv,
struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
int ret = -1;
u8 *bssid = pdata_buf;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
- cmd->command = cpu_to_le16(cmd_802_11_authenticate);
+ cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
+ S_DS_GEN);
@@ -290,8 +320,8 @@ int libertas_cmd_80211_authenticate(wlan_private * priv,
memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
- lbs_deb_join("AUTH_CMD: BSSID is : " MAC_FMT " auth=0x%X\n",
- MAC_ARG(bssid), pauthenticate->authtype);
+ lbs_deb_join("AUTH_CMD: BSSID is : %s auth=0x%X\n",
+ print_mac(mac, bssid), pauthenticate->authtype);
ret = 0;
out:
@@ -307,7 +337,7 @@ int libertas_cmd_80211_deauthenticate(wlan_private * priv,
lbs_deb_enter(LBS_DEB_JOIN);
- cmd->command = cpu_to_le16(cmd_802_11_deauthenticate);
+ cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE);
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
S_DS_GEN);
@@ -330,9 +360,7 @@ int libertas_cmd_80211_associate(wlan_private * priv,
int ret = 0;
struct assoc_request * assoc_req = pdata_buf;
struct bss_descriptor * bss = &assoc_req->bss;
- u8 *card_rates;
u8 *pos;
- int card_rates_size;
u16 tmpcap, tmplen;
struct mrvlietypes_ssidparamset *ssid;
struct mrvlietypes_phyparamset *phy;
@@ -349,15 +377,15 @@ int libertas_cmd_80211_associate(wlan_private * priv,
goto done;
}
- cmd->command = cpu_to_le16(cmd_802_11_associate);
+ cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE);
memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr));
pos += sizeof(passo->peerstaaddr);
/* set the listen interval */
- passo->listeninterval = cpu_to_le16(adapter->listeninterval);
+ passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
- pos += sizeof(passo->capinfo);
+ pos += sizeof(passo->capability);
pos += sizeof(passo->listeninterval);
pos += sizeof(passo->bcnperiod);
pos += sizeof(passo->dtimperiod);
@@ -386,23 +414,24 @@ int libertas_cmd_80211_associate(wlan_private * priv,
rates = (struct mrvlietypes_ratesparamset *) pos;
rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
-
- memcpy(&rates->rates, &bss->libertas_supported_rates, WLAN_SUPPORTED_RATES);
-
- card_rates = libertas_supported_rates;
- card_rates_size = sizeof(libertas_supported_rates);
-
- if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES,
- card_rates, card_rates_size)) {
+ memcpy(&rates->rates, &bss->rates, MAX_RATES);
+ tmplen = MAX_RATES;
+ if (get_common_rates(adapter, rates->rates, &tmplen)) {
ret = -1;
goto done;
}
-
- tmplen = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES);
- adapter->curbssparams.numofrates = tmplen;
-
pos += sizeof(rates->header) + tmplen;
rates->header.len = cpu_to_le16(tmplen);
+ lbs_deb_join("ASSOC_CMD: num rates = %u\n", tmplen);
+
+ /* Copy the infra. association rates into Current BSS state structure */
+ memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
+ memcpy(&adapter->curbssparams.rates, &rates->rates, tmplen);
+
+ /* Set MSB on basic rates as the firmware requires, but _after_
+ * copying to current bss rates.
+ */
+ libertas_set_basic_rate_flags(rates->rates, tmplen);
if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
rsn = (struct mrvlietypes_rsnparamset *) pos;
@@ -411,7 +440,7 @@ int libertas_cmd_80211_associate(wlan_private * priv,
tmplen = (u16) assoc_req->wpa_ie[1];
rsn->header.len = cpu_to_le16(tmplen);
memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
- lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn,
+ lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn,
sizeof(rsn->header) + tmplen);
pos += sizeof(rsn->header) + tmplen;
}
@@ -419,20 +448,6 @@ int libertas_cmd_80211_associate(wlan_private * priv,
/* update curbssparams */
adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
- /* Copy the infra. association rates into Current BSS state structure */
- memcpy(&adapter->curbssparams.datarates, &rates->rates,
- min_t(size_t, sizeof(adapter->curbssparams.datarates),
- cpu_to_le16(rates->header.len)));
-
- lbs_deb_join("ASSOC_CMD: rates->header.len = %d\n",
- cpu_to_le16(rates->header.len));
-
- /* set IBSS field */
- if (bss->mode == IW_MODE_INFRA) {
-#define CAPINFO_ESS_MODE 1
- passo->capinfo.ess = CAPINFO_ESS_MODE;
- }
-
if (libertas_parse_dnld_countryinfo_11d(priv, bss)) {
ret = -1;
goto done;
@@ -440,12 +455,13 @@ int libertas_cmd_80211_associate(wlan_private * priv,
cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
- /* set the capability info at last */
- memcpy(&tmpcap, &bss->cap, sizeof(passo->capinfo));
- tmpcap &= CAPINFO_MASK;
- lbs_deb_join("ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+ /* set the capability info */
+ tmpcap = (bss->capability & CAPINFO_MASK);
+ if (bss->mode == IW_MODE_INFRA)
+ tmpcap |= WLAN_CAPABILITY_ESS;
+ passo->capability = cpu_to_le16(tmpcap);
+ lbs_deb_join("ASSOC_CMD: capability=%4X CAPINFO_MASK=%4X\n",
tmpcap, CAPINFO_MASK);
- memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo));
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
@@ -459,8 +475,9 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
int ret = 0;
int cmdappendsize = 0;
- int i;
struct assoc_request * assoc_req = pdata_buf;
+ u16 tmpcap = 0;
+ size_t ratesize = 0;
lbs_deb_enter(LBS_DEB_JOIN);
@@ -469,7 +486,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
goto done;
}
- cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start);
+ cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START);
/*
* Fill in the parameters for 2 data structures:
@@ -483,17 +500,17 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
* and operational rates.
*/
- memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE);
- memcpy(adhs->SSID, assoc_req->ssid, assoc_req->ssid_len);
+ memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE);
+ memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len);
lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
escape_essid(assoc_req->ssid, assoc_req->ssid_len),
assoc_req->ssid_len);
/* set the BSS type */
- adhs->bsstype = cmd_bss_type_ibss;
+ adhs->bsstype = CMD_BSS_TYPE_IBSS;
adapter->mode = IW_MODE_ADHOC;
- adhs->beaconperiod = cpu_to_le16(adapter->beaconperiod);
+ adhs->beaconperiod = cpu_to_le16(MRVDRV_BEACON_INTERVAL);
/* set Physical param set */
#define DS_PARA_IE_ID 3
@@ -515,45 +532,36 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
- adhs->ssparamset.ibssparamset.atimwindow = cpu_to_le16(adapter->atimwindow);
+ adhs->ssparamset.ibssparamset.atimwindow = 0;
/* set capability info */
- adhs->cap.ess = 0;
- adhs->cap.ibss = 1;
-
- /* probedelay */
- adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
-
- /* set up privacy in adapter->scantable[i] */
+ tmpcap = WLAN_CAPABILITY_IBSS;
if (assoc_req->secinfo.wep_enabled) {
lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n");
- adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+ tmpcap |= WLAN_CAPABILITY_PRIVACY;
} else {
lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n");
}
+ adhs->capability = cpu_to_le16(tmpcap);
- memset(adhs->datarate, 0, sizeof(adhs->datarate));
-
- if (adapter->adhoc_grate_enabled) {
- memcpy(adhs->datarate, libertas_adhoc_rates_g,
- min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g)));
- } else {
- memcpy(adhs->datarate, libertas_adhoc_rates_b,
- min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b)));
- }
-
- /* Find the last non zero */
- for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ;
+ /* probedelay */
+ adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
- adapter->curbssparams.numofrates = i;
+ memset(adhs->rates, 0, sizeof(adhs->rates));
+ ratesize = min(sizeof(adhs->rates), sizeof(libertas_bg_rates));
+ memcpy(adhs->rates, libertas_bg_rates, ratesize);
/* Copy the ad-hoc creating rates into Current BSS state structure */
- memcpy(&adapter->curbssparams.datarates,
- &adhs->datarate, adapter->curbssparams.numofrates);
+ memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
+ memcpy(&adapter->curbssparams.rates, &adhs->rates, ratesize);
+
+ /* Set MSB on basic rates as the firmware requires, but _after_
+ * copying to current bss rates.
+ */
+ libertas_set_basic_rate_flags(adhs->rates, ratesize);
lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
- adhs->datarate[0], adhs->datarate[1],
- adhs->datarate[2], adhs->datarate[3]);
+ adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]);
lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
@@ -575,7 +583,7 @@ done:
int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
struct cmd_ds_command *cmd)
{
- cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop);
+ cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP);
cmd->size = cpu_to_le16(S_DS_GEN);
return 0;
@@ -585,101 +593,84 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
struct cmd_ds_command *cmd, void *pdata_buf)
{
wlan_adapter *adapter = priv->adapter;
- struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj;
+ struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj;
struct assoc_request * assoc_req = pdata_buf;
struct bss_descriptor *bss = &assoc_req->bss;
int cmdappendsize = 0;
int ret = 0;
- u8 *card_rates;
- int card_rates_size;
- u16 tmpcap;
- int i;
+ u16 ratesize = 0;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
- cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join);
+ cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN);
- padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss;
+ join_cmd->bss.type = CMD_BSS_TYPE_IBSS;
+ join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
- padhocjoin->bssdescriptor.beaconperiod = cpu_to_le16(bss->beaconperiod);
+ memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN);
+ memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len);
- memcpy(&padhocjoin->bssdescriptor.BSSID, &bss->bssid, ETH_ALEN);
- memcpy(&padhocjoin->bssdescriptor.SSID, &bss->ssid, bss->ssid_len);
+ memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset,
+ sizeof(union ieeetypes_phyparamset));
- memcpy(&padhocjoin->bssdescriptor.phyparamset,
- &bss->phyparamset, sizeof(union ieeetypes_phyparamset));
-
- memcpy(&padhocjoin->bssdescriptor.ssparamset,
- &bss->ssparamset, sizeof(union IEEEtypes_ssparamset));
-
- memcpy(&tmpcap, &bss->cap, sizeof(struct ieeetypes_capinfo));
- tmpcap &= CAPINFO_MASK;
+ memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset,
+ sizeof(union IEEEtypes_ssparamset));
+ join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
- tmpcap, CAPINFO_MASK);
- memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap,
- sizeof(struct ieeetypes_capinfo));
+ bss->capability, CAPINFO_MASK);
/* information on BSSID descriptor passed to FW */
lbs_deb_join(
- "ADHOC_J_CMD: BSSID = " MAC_FMT ", SSID = '%s'\n",
- MAC_ARG(padhocjoin->bssdescriptor.BSSID),
- padhocjoin->bssdescriptor.SSID);
+ "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
+ print_mac(mac, join_cmd->bss.bssid),
+ join_cmd->bss.ssid);
/* failtimeout */
- padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+ join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
/* probedelay */
- padhocjoin->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
-
- /* Copy Data rates from the rates recorded in scan response */
- memset(padhocjoin->bssdescriptor.datarates, 0,
- sizeof(padhocjoin->bssdescriptor.datarates));
- memcpy(padhocjoin->bssdescriptor.datarates, bss->datarates,
- min(sizeof(padhocjoin->bssdescriptor.datarates),
- sizeof(bss->datarates)));
-
- card_rates = libertas_supported_rates;
- card_rates_size = sizeof(libertas_supported_rates);
+ join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
adapter->curbssparams.channel = bss->channel;
- if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates,
- sizeof(padhocjoin->bssdescriptor.datarates),
- card_rates, card_rates_size)) {
+ /* Copy Data rates from the rates recorded in scan response */
+ memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates));
+ ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES);
+ memcpy(join_cmd->bss.rates, bss->rates, ratesize);
+ if (get_common_rates(adapter, join_cmd->bss.rates, &ratesize)) {
lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
ret = -1;
goto done;
}
- /* Find the last non zero */
- for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates)
- && padhocjoin->bssdescriptor.datarates[i]; i++) ;
-
- adapter->curbssparams.numofrates = i;
+ /* Copy the ad-hoc creating rates into Current BSS state structure */
+ memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
+ memcpy(&adapter->curbssparams.rates, join_cmd->bss.rates, ratesize);
- /*
- * Copy the adhoc joining rates to Current BSS State structure
+ /* Set MSB on basic rates as the firmware requires, but _after_
+ * copying to current bss rates.
*/
- memcpy(adapter->curbssparams.datarates,
- padhocjoin->bssdescriptor.datarates,
- adapter->curbssparams.numofrates);
+ libertas_set_basic_rate_flags(join_cmd->bss.rates, ratesize);
- padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow =
+ join_cmd->bss.ssparamset.ibssparamset.atimwindow =
cpu_to_le16(bss->atimwindow);
if (assoc_req->secinfo.wep_enabled) {
- padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+ u16 tmp = le16_to_cpu(join_cmd->bss.capability);
+ tmp |= WLAN_CAPABILITY_PRIVACY;
+ join_cmd->bss.capability = cpu_to_le16(tmp);
}
- if (adapter->psmode == wlan802_11powermodemax_psp) {
+ if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
/* wake up first */
__le32 Localpsmode;
- Localpsmode = cpu_to_le32(wlan802_11powermodecam);
+ Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM);
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_ps_mode,
- cmd_act_set,
+ CMD_802_11_PS_MODE,
+ CMD_ACT_SET,
0, 0, &Localpsmode);
if (ret) {
@@ -709,6 +700,7 @@ int libertas_ret_80211_associate(wlan_private * priv,
union iwreq_data wrqu;
struct ieeetypes_assocrsp *passocrsp;
struct bss_descriptor * bss;
+ u16 status_code;
lbs_deb_enter(LBS_DEB_JOIN);
@@ -721,21 +713,65 @@ int libertas_ret_80211_associate(wlan_private * priv,
passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
- if (le16_to_cpu(passocrsp->statuscode)) {
- libertas_mac_event_disconnected(priv);
+ /*
+ * Older FW versions map the IEEE 802.11 Status Code in the association
+ * response to the following values returned in passocrsp->statuscode:
+ *
+ * IEEE Status Code Marvell Status Code
+ * 0 -> 0x0000 ASSOC_RESULT_SUCCESS
+ * 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
+ * 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
+ * 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
+ * 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
+ * others -> 0x0003 ASSOC_RESULT_REFUSED
+ *
+ * Other response codes:
+ * 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
+ * 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
+ * association response from the AP)
+ */
- lbs_deb_join("ASSOC_RESP: Association failed, status code = %d\n",
- le16_to_cpu(passocrsp->statuscode));
+ status_code = le16_to_cpu(passocrsp->statuscode);
+ switch (status_code) {
+ case 0x00:
+ lbs_deb_join("ASSOC_RESP: Association succeeded\n");
+ break;
+ case 0x01:
+ lbs_deb_join("ASSOC_RESP: Association failed; invalid "
+ "parameters (status code %d)\n", status_code);
+ break;
+ case 0x02:
+ lbs_deb_join("ASSOC_RESP: Association failed; internal timer "
+ "expired while waiting for the AP (status code %d)"
+ "\n", status_code);
+ break;
+ case 0x03:
+ lbs_deb_join("ASSOC_RESP: Association failed; association "
+ "was refused by the AP (status code %d)\n",
+ status_code);
+ break;
+ case 0x04:
+ lbs_deb_join("ASSOC_RESP: Association failed; authentication "
+ "was refused by the AP (status code %d)\n",
+ status_code);
+ break;
+ default:
+ lbs_deb_join("ASSOC_RESP: Association failed; reason unknown "
+ "(status code %d)\n", status_code);
+ break;
+ }
+ if (status_code) {
+ libertas_mac_event_disconnected(priv);
ret = -1;
goto done;
}
- lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params,
+ lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_RESP", (void *)&resp->params,
le16_to_cpu(resp->size) - S_DS_GEN);
/* Send a Media Connected event, according to the Spec */
- adapter->connect_status = libertas_connected;
+ adapter->connect_status = LIBERTAS_CONNECTED;
lbs_deb_join("ASSOC_RESP: assocated to '%s'\n",
escape_essid(bss->ssid, bss->ssid_len));
@@ -759,10 +795,10 @@ int libertas_ret_80211_associate(wlan_private * priv,
netif_carrier_on(priv->dev);
netif_wake_queue(priv->dev);
- netif_carrier_on(priv->mesh_dev);
- netif_wake_queue(priv->mesh_dev);
-
- lbs_deb_join("ASSOC_RESP: Associated \n");
+ if (priv->mesh_dev) {
+ netif_carrier_on(priv->mesh_dev);
+ netif_wake_queue(priv->mesh_dev);
+ }
memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@@ -794,6 +830,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
struct cmd_ds_802_11_ad_hoc_result *padhocresult;
union iwreq_data wrqu;
struct bss_descriptor *bss;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
@@ -815,7 +852,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
*/
if (result) {
lbs_deb_join("ADHOC_RESP: failed\n");
- if (adapter->connect_status == libertas_connected) {
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
libertas_mac_event_disconnected(priv);
}
ret = -1;
@@ -830,11 +867,11 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
escape_essid(bss->ssid, bss->ssid_len));
/* Send a Media Connected event, according to the Spec */
- adapter->connect_status = libertas_connected;
+ adapter->connect_status = LIBERTAS_CONNECTED;
- if (command == cmd_ret_802_11_ad_hoc_start) {
+ if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
/* Update the created network descriptor with the new BSSID */
- memcpy(bss->bssid, padhocresult->BSSID, ETH_ALEN);
+ memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN);
}
/* Set the BSSID from the joined/started descriptor */
@@ -847,8 +884,10 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
netif_carrier_on(priv->dev);
netif_wake_queue(priv->dev);
- netif_carrier_on(priv->mesh_dev);
- netif_wake_queue(priv->mesh_dev);
+ if (priv->mesh_dev) {
+ netif_carrier_on(priv->mesh_dev);
+ netif_wake_queue(priv->mesh_dev);
+ }
memset(&wrqu, 0, sizeof(wrqu));
memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
@@ -857,8 +896,8 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel);
- lbs_deb_join("ADHOC_RESP: BSSID = " MAC_FMT "\n",
- MAC_ARG(padhocresult->BSSID));
+ lbs_deb_join("ADHOC_RESP: BSSID = %s\n",
+ print_mac(mac, padhocresult->bssid));
done:
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h
index d522630ff8c..894a072b9f8 100644
--- a/drivers/net/wireless/libertas/join.h
+++ b/drivers/net/wireless/libertas/join.h
@@ -12,45 +12,42 @@
#include "dev.h"
struct cmd_ds_command;
-extern int libertas_cmd_80211_authenticate(wlan_private * priv,
+int libertas_cmd_80211_authenticate(wlan_private * priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
-extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
-extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
struct cmd_ds_command *cmd);
-extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
-extern int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+int libertas_cmd_80211_deauthenticate(wlan_private * priv,
struct cmd_ds_command *cmd);
-extern int libertas_cmd_80211_associate(wlan_private * priv,
+int libertas_cmd_80211_associate(wlan_private * priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
-extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
struct cmd_ds_command *resp);
-extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
struct cmd_ds_command *resp);
-extern int libertas_ret_80211_disassociate(wlan_private * priv,
+int libertas_ret_80211_disassociate(wlan_private * priv,
struct cmd_ds_command *resp);
-extern int libertas_ret_80211_associate(wlan_private * priv,
+int libertas_ret_80211_associate(wlan_private * priv,
struct cmd_ds_command *resp);
-extern int libertas_reassociation_thread(void *data);
-
-extern int libertas_start_adhoc_network(wlan_private * priv,
+int libertas_start_adhoc_network(wlan_private * priv,
struct assoc_request * assoc_req);
-extern int libertas_join_adhoc_network(wlan_private * priv,
+int libertas_join_adhoc_network(wlan_private * priv,
struct assoc_request * assoc_req);
-extern int libertas_stop_adhoc_network(wlan_private * priv);
-
-extern int libertas_send_deauthentication(wlan_private * priv);
-extern int libertas_send_deauth(wlan_private * priv);
+int libertas_stop_adhoc_network(wlan_private * priv);
-extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
+int libertas_send_deauthentication(wlan_private * priv);
int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req);
+void libertas_unset_basic_rate_flags(u8 * rates, size_t len);
+
#endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 9f366242c39..5ead08312e1 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -10,6 +10,7 @@
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
+#include <linux/kthread.h>
#include <net/iw_handler.h>
#include <net/ieee80211.h>
@@ -20,8 +21,9 @@
#include "wext.h"
#include "debugfs.h"
#include "assoc.h"
+#include "join.h"
-#define DRIVER_RELEASE_VERSION "322.p0"
+#define DRIVER_RELEASE_VERSION "323.p0"
const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
#ifdef DEBUG
"-dbg"
@@ -121,57 +123,88 @@ struct region_cfp_table {
static struct region_cfp_table region_cfp_table[] = {
{0x10, /*US FCC */
channel_freq_power_US_BG,
- sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+ ARRAY_SIZE(channel_freq_power_US_BG),
}
,
{0x20, /*CANADA IC */
channel_freq_power_US_BG,
- sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+ ARRAY_SIZE(channel_freq_power_US_BG),
}
,
{0x30, /*EU*/ channel_freq_power_EU_BG,
- sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power),
+ ARRAY_SIZE(channel_freq_power_EU_BG),
}
,
{0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
- sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power),
+ ARRAY_SIZE(channel_freq_power_SPN_BG),
}
,
{0x32, /*FRANCE*/ channel_freq_power_FR_BG,
- sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power),
+ ARRAY_SIZE(channel_freq_power_FR_BG),
}
,
{0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
- sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power),
+ ARRAY_SIZE(channel_freq_power_JPN_BG),
}
,
/*Add new region here */
};
/**
- * the rates supported
+ * the table to keep region code
*/
-u8 libertas_supported_rates[G_SUPPORTED_RATES] =
- { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0 };
+u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
+ { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
/**
- * the rates supported for ad-hoc G mode
+ * 802.11b/g supported bitrates (in 500Kb/s units)
*/
-u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] =
- { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0 };
+u8 libertas_bg_rates[MAX_RATES] =
+ { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0x00, 0x00 };
/**
- * the rates supported for ad-hoc B mode
+ * FW rate table. FW refers to rates by their index in this table, not by the
+ * rate value itself. Values of 0x00 are
+ * reserved positions.
*/
-u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 };
+static u8 fw_data_rates[MAX_RATES] =
+ { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+ 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
+};
/**
- * the table to keep region code
+ * @brief use index to get the data rate
+ *
+ * @param idx The index of data rate
+ * @return data rate or 0
*/
-u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
- { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
+u32 libertas_fw_index_to_data_rate(u8 idx)
+{
+ if (idx >= sizeof(fw_data_rates))
+ idx = 0;
+ return fw_data_rates[idx];
+}
+
+/**
+ * @brief use rate to get the index
+ *
+ * @param rate data rate
+ * @return index or 0
+ */
+u8 libertas_data_rate_to_fw_index(u32 rate)
+{
+ u8 i;
+
+ if (!rate)
+ return 0;
+
+ for (i = 0; i < sizeof(fw_data_rates); i++) {
+ if (rate == fw_data_rates[i])
+ return i;
+ }
+ return 0;
+}
/**
* Attributes exported through sysfs
@@ -187,9 +220,9 @@ static ssize_t libertas_anycast_get(struct device * dev,
memset(&mesh_access, 0, sizeof(mesh_access));
libertas_prepare_and_send_command(to_net_dev(dev)->priv,
- cmd_mesh_access,
- cmd_act_mesh_get_anycast,
- cmd_option_waitforrsp, 0, (void *)&mesh_access);
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_GET_ANYCAST,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
}
@@ -208,18 +241,127 @@ static ssize_t libertas_anycast_set(struct device * dev,
mesh_access.data[0] = cpu_to_le32(datum);
libertas_prepare_and_send_command((to_net_dev(dev))->priv,
- cmd_mesh_access,
- cmd_act_mesh_set_anycast,
- cmd_option_waitforrsp, 0, (void *)&mesh_access);
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_SET_ANYCAST,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ return strlen(buf);
+}
+
+int libertas_add_rtap(wlan_private *priv);
+void libertas_remove_rtap(wlan_private *priv);
+
+/**
+ * Get function for sysfs attribute rtap
+ */
+static ssize_t libertas_rtap_get(struct device * dev,
+ struct device_attribute *attr, char * buf)
+{
+ wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv;
+ wlan_adapter *adapter = priv->adapter;
+ return snprintf(buf, 5, "0x%X\n", adapter->monitormode);
+}
+
+/**
+ * Set function for sysfs attribute rtap
+ */
+static ssize_t libertas_rtap_set(struct device * dev,
+ struct device_attribute *attr, const char * buf, size_t count)
+{
+ int monitor_mode;
+ wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ sscanf(buf, "%x", &monitor_mode);
+ if (monitor_mode != WLAN_MONITOR_OFF) {
+ if(adapter->monitormode == monitor_mode)
+ return strlen(buf);
+ if (adapter->monitormode == WLAN_MONITOR_OFF) {
+ if (adapter->mode == IW_MODE_INFRA)
+ libertas_send_deauthentication(priv);
+ else if (adapter->mode == IW_MODE_ADHOC)
+ libertas_stop_adhoc_network(priv);
+ libertas_add_rtap(priv);
+ }
+ adapter->monitormode = monitor_mode;
+ }
+
+ else {
+ if(adapter->monitormode == WLAN_MONITOR_OFF)
+ return strlen(buf);
+ adapter->monitormode = WLAN_MONITOR_OFF;
+ libertas_remove_rtap(priv);
+ netif_wake_queue(priv->dev);
+ netif_wake_queue(priv->mesh_dev);
+ }
+
+ libertas_prepare_and_send_command(priv,
+ CMD_802_11_MONITOR_MODE, CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, &adapter->monitormode);
return strlen(buf);
}
/**
+ * libertas_rtap attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/libertas-rtap)
+ */
+static DEVICE_ATTR(libertas_rtap, 0644, libertas_rtap_get,
+ libertas_rtap_set );
+
+/**
* anycast_mask attribute to be exported per mshX interface
* through sysfs (/sys/class/net/mshX/anycast_mask)
*/
static DEVICE_ATTR(anycast_mask, 0644, libertas_anycast_get, libertas_anycast_set);
+static ssize_t libertas_autostart_enabled_get(struct device * dev,
+ struct device_attribute *attr, char * buf)
+{
+ struct cmd_ds_mesh_access mesh_access;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ libertas_prepare_and_send_command(to_net_dev(dev)->priv,
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+
+ return sprintf(buf, "%d\n", le32_to_cpu(mesh_access.data[0]));
+}
+
+static ssize_t libertas_autostart_enabled_set(struct device * dev,
+ struct device_attribute *attr, const char * buf, size_t count)
+{
+ struct cmd_ds_mesh_access mesh_access;
+ uint32_t datum;
+ wlan_private * priv = (to_net_dev(dev))->priv;
+ int ret;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ sscanf(buf, "%d", &datum);
+ mesh_access.data[0] = cpu_to_le32(datum);
+
+ ret = libertas_prepare_and_send_command(priv,
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ if (ret == 0)
+ priv->mesh_autostart_enabled = datum ? 1 : 0;
+
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(autostart_enabled, 0644,
+ libertas_autostart_enabled_get, libertas_autostart_enabled_set);
+
+static struct attribute *libertas_mesh_sysfs_entries[] = {
+ &dev_attr_anycast_mask.attr,
+ &dev_attr_autostart_enabled.attr,
+ NULL,
+};
+
+static struct attribute_group libertas_mesh_attr_group = {
+ .attrs = libertas_mesh_sysfs_entries,
+};
+
/**
* @brief Check if the device can be open and wait if necessary.
*
@@ -255,7 +397,7 @@ static int pre_open_check(struct net_device *dev)
* @param dev A pointer to net_device structure
* @return 0
*/
-static int wlan_dev_open(struct net_device *dev)
+static int libertas_dev_open(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv;
wlan_adapter *adapter = priv->adapter;
@@ -264,12 +406,14 @@ static int wlan_dev_open(struct net_device *dev)
priv->open = 1;
- if (adapter->connect_status == libertas_connected) {
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
netif_carrier_on(priv->dev);
- netif_carrier_on(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_carrier_on(priv->mesh_dev);
} else {
netif_carrier_off(priv->dev);
- netif_carrier_off(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_carrier_off(priv->mesh_dev);
}
lbs_deb_leave(LBS_DEB_NET);
@@ -281,7 +425,7 @@ static int wlan_dev_open(struct net_device *dev)
* @param dev A pointer to net_device structure
* @return 0
*/
-static int mesh_open(struct net_device *dev)
+static int libertas_mesh_open(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv ;
@@ -290,7 +434,7 @@ static int mesh_open(struct net_device *dev)
priv->mesh_open = 1 ;
netif_wake_queue(priv->mesh_dev);
if (priv->infra_open == 0)
- return wlan_dev_open(priv->dev) ;
+ return libertas_dev_open(priv->dev) ;
return 0;
}
@@ -300,7 +444,7 @@ static int mesh_open(struct net_device *dev)
* @param dev A pointer to net_device structure
* @return 0
*/
-static int wlan_open(struct net_device *dev)
+static int libertas_open(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv ;
@@ -309,11 +453,11 @@ static int wlan_open(struct net_device *dev)
priv->infra_open = 1 ;
netif_wake_queue(priv->dev);
if (priv->open == 0)
- return wlan_dev_open(priv->dev) ;
+ return libertas_dev_open(priv->dev) ;
return 0;
}
-static int wlan_dev_close(struct net_device *dev)
+static int libertas_dev_close(struct net_device *dev)
{
wlan_private *priv = dev->priv;
@@ -332,14 +476,14 @@ static int wlan_dev_close(struct net_device *dev)
* @param dev A pointer to net_device structure
* @return 0
*/
-static int mesh_close(struct net_device *dev)
+static int libertas_mesh_close(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) (dev->priv);
priv->mesh_open = 0;
netif_stop_queue(priv->mesh_dev);
if (priv->infra_open == 0)
- return wlan_dev_close(dev);
+ return libertas_dev_close(dev);
else
return 0;
}
@@ -350,20 +494,20 @@ static int mesh_close(struct net_device *dev)
* @param dev A pointer to net_device structure
* @return 0
*/
-static int wlan_close(struct net_device *dev)
+static int libertas_close(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv;
netif_stop_queue(dev);
priv->infra_open = 0;
if (priv->mesh_open == 0)
- return wlan_dev_close(dev);
+ return libertas_dev_close(dev);
else
return 0;
}
-static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int libertas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
int ret = 0;
wlan_private *priv = dev->priv;
@@ -376,7 +520,8 @@ static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
netif_stop_queue(priv->dev);
- netif_stop_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_stop_queue(priv->mesh_dev);
if (libertas_process_tx(priv, skb) == 0)
dev->trans_start = jiffies;
@@ -386,41 +531,52 @@ done:
}
/**
- * @brief Mark mesh packets and handover them to wlan_hard_start_xmit
+ * @brief Mark mesh packets and handover them to libertas_hard_start_xmit
*
*/
-static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int libertas_mesh_pre_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
wlan_private *priv = dev->priv;
int ret;
lbs_deb_enter(LBS_DEB_MESH);
+ if(priv->adapter->monitormode != WLAN_MONITOR_OFF) {
+ netif_stop_queue(dev);
+ return -EOPNOTSUPP;
+ }
SET_MESH_FRAME(skb);
- ret = wlan_hard_start_xmit(skb, priv->dev);
+ ret = libertas_hard_start_xmit(skb, priv->dev);
lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
return ret;
}
/**
- * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit
+ * @brief Mark non-mesh packets and handover them to libertas_hard_start_xmit
*
*/
-static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ wlan_private *priv = dev->priv;
int ret;
lbs_deb_enter(LBS_DEB_NET);
+ if(priv->adapter->monitormode != WLAN_MONITOR_OFF) {
+ netif_stop_queue(dev);
+ return -EOPNOTSUPP;
+ }
+
UNSET_MESH_FRAME(skb);
- ret = wlan_hard_start_xmit(skb, dev);
+ ret = libertas_hard_start_xmit(skb, dev);
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
return ret;
}
-static void wlan_tx_timeout(struct net_device *dev)
+static void libertas_tx_timeout(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv;
@@ -432,16 +588,17 @@ static void wlan_tx_timeout(struct net_device *dev)
dev->trans_start = jiffies;
if (priv->adapter->currenttxskb) {
- if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+ if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
/* If we are here, we have not received feedback from
the previous packet. Assume TX_FAIL and move on. */
priv->adapter->eventcause = 0x01000000;
libertas_send_tx_feedback(priv);
} else
- wake_up_interruptible(&priv->mainthread.waitq);
- } else if (priv->adapter->connect_status == libertas_connected) {
+ wake_up_interruptible(&priv->waitq);
+ } else if (priv->adapter->connect_status == LIBERTAS_CONNECTED) {
netif_wake_queue(priv->dev);
- netif_wake_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_wake_queue(priv->mesh_dev);
}
lbs_deb_leave(LBS_DEB_TX);
@@ -453,14 +610,14 @@ static void wlan_tx_timeout(struct net_device *dev)
* @param dev A pointer to wlan_private structure
* @return A pointer to net_device_stats structure
*/
-static struct net_device_stats *wlan_get_stats(struct net_device *dev)
+static struct net_device_stats *libertas_get_stats(struct net_device *dev)
{
wlan_private *priv = (wlan_private *) dev->priv;
return &priv->stats;
}
-static int wlan_set_mac_address(struct net_device *dev, void *addr)
+static int libertas_set_mac_address(struct net_device *dev, void *addr)
{
int ret = 0;
wlan_private *priv = (wlan_private *) dev->priv;
@@ -475,14 +632,14 @@ static int wlan_set_mac_address(struct net_device *dev, void *addr)
memset(adapter->current_addr, 0, ETH_ALEN);
/* dev->dev_addr is 8 bytes */
- lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+ lbs_deb_hex(LBS_DEB_NET, "dev->dev_addr", dev->dev_addr, ETH_ALEN);
- lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN);
+ lbs_deb_hex(LBS_DEB_NET, "addr", phwaddr->sa_data, ETH_ALEN);
memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN);
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address,
- cmd_act_set,
- cmd_option_waitforrsp, 0, NULL);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
if (ret) {
lbs_deb_net("set MAC address failed\n");
@@ -490,7 +647,7 @@ static int wlan_set_mac_address(struct net_device *dev, void *addr)
goto done;
}
- lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN);
+ lbs_deb_hex(LBS_DEB_NET, "adapter->macaddr", adapter->current_addr, ETH_ALEN);
memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN);
if (priv->mesh_dev)
memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
@@ -500,7 +657,7 @@ done:
return ret;
}
-static int wlan_copy_multicast_address(wlan_adapter * adapter,
+static int libertas_copy_multicast_address(wlan_adapter * adapter,
struct net_device *dev)
{
int i = 0;
@@ -515,11 +672,12 @@ static int wlan_copy_multicast_address(wlan_adapter * adapter,
}
-static void wlan_set_multicast_list(struct net_device *dev)
+static void libertas_set_multicast_list(struct net_device *dev)
{
wlan_private *priv = dev->priv;
wlan_adapter *adapter = priv->adapter;
int oldpacketfilter;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_NET);
@@ -528,57 +686,52 @@ static void wlan_set_multicast_list(struct net_device *dev)
if (dev->flags & IFF_PROMISC) {
lbs_deb_net("enable promiscuous mode\n");
adapter->currentpacketfilter |=
- cmd_act_mac_promiscuous_enable;
+ CMD_ACT_MAC_PROMISCUOUS_ENABLE;
adapter->currentpacketfilter &=
- ~(cmd_act_mac_all_multicast_enable |
- cmd_act_mac_multicast_enable);
+ ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
+ CMD_ACT_MAC_MULTICAST_ENABLE);
} else {
/* Multicast */
adapter->currentpacketfilter &=
- ~cmd_act_mac_promiscuous_enable;
+ ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
if (dev->flags & IFF_ALLMULTI || dev->mc_count >
MRVDRV_MAX_MULTICAST_LIST_SIZE) {
lbs_deb_net( "enabling all multicast\n");
adapter->currentpacketfilter |=
- cmd_act_mac_all_multicast_enable;
+ CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
adapter->currentpacketfilter &=
- ~cmd_act_mac_multicast_enable;
+ ~CMD_ACT_MAC_MULTICAST_ENABLE;
} else {
adapter->currentpacketfilter &=
- ~cmd_act_mac_all_multicast_enable;
+ ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
if (!dev->mc_count) {
lbs_deb_net("no multicast addresses, "
"disabling multicast\n");
adapter->currentpacketfilter &=
- ~cmd_act_mac_multicast_enable;
+ ~CMD_ACT_MAC_MULTICAST_ENABLE;
} else {
int i;
adapter->currentpacketfilter |=
- cmd_act_mac_multicast_enable;
+ CMD_ACT_MAC_MULTICAST_ENABLE;
adapter->nr_of_multicastmacaddr =
- wlan_copy_multicast_address(adapter, dev);
+ libertas_copy_multicast_address(adapter, dev);
lbs_deb_net("multicast addresses: %d\n",
dev->mc_count);
for (i = 0; i < dev->mc_count; i++) {
- lbs_deb_net("Multicast address %d:"
- MAC_FMT "\n", i,
- adapter->multicastlist[i][0],
- adapter->multicastlist[i][1],
- adapter->multicastlist[i][2],
- adapter->multicastlist[i][3],
- adapter->multicastlist[i][4],
- adapter->multicastlist[i][5]);
+ lbs_deb_net("Multicast address %d:%s\n",
+ i, print_mac(mac,
+ adapter->multicastlist[i]));
}
/* send multicast addresses to firmware */
libertas_prepare_and_send_command(priv,
- cmd_mac_multicast_adr,
- cmd_act_set, 0, 0,
+ CMD_MAC_MULTICAST_ADR,
+ CMD_ACT_SET, 0, 0,
NULL);
}
}
@@ -599,18 +752,16 @@ static void wlan_set_multicast_list(struct net_device *dev)
* @param data A pointer to wlan_thread structure
* @return 0
*/
-static int wlan_service_main_thread(void *data)
+static int libertas_thread(void *data)
{
- struct wlan_thread *thread = data;
- wlan_private *priv = thread->priv;
+ struct net_device *dev = data;
+ wlan_private *priv = dev->priv;
wlan_adapter *adapter = priv->adapter;
wait_queue_t wait;
u8 ireg = 0;
lbs_deb_enter(LBS_DEB_THREAD);
- wlan_activate_thread(thread);
-
init_waitqueue_entry(&wait, current);
set_freezable();
@@ -620,7 +771,7 @@ static int wlan_service_main_thread(void *data)
adapter->intcounter,
adapter->currenttxskb, priv->dnld_sent);
- add_wait_queue(&thread->waitq, &wait);
+ add_wait_queue(&priv->waitq, &wait);
set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irq(&adapter->driver_lock);
if ((adapter->psstate == PS_STATE_SLEEP) ||
@@ -636,14 +787,13 @@ static int wlan_service_main_thread(void *data)
} else
spin_unlock_irq(&adapter->driver_lock);
-
lbs_deb_thread(
"main-thread 222 (waking up): intcounter=%d currenttxskb=%p "
"dnld_sent=%d\n", adapter->intcounter,
adapter->currenttxskb, priv->dnld_sent);
set_current_state(TASK_RUNNING);
- remove_wait_queue(&thread->waitq, &wait);
+ remove_wait_queue(&priv->waitq, &wait);
try_to_freeze();
lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p "
@@ -681,20 +831,20 @@ static int wlan_service_main_thread(void *data)
adapter->currenttxskb, priv->dnld_sent);
/* command response? */
- if (adapter->hisregcpy & his_cmdupldrdy) {
+ if (adapter->hisregcpy & MRVDRV_CMD_UPLD_RDY) {
lbs_deb_thread("main-thread: cmd response ready\n");
- adapter->hisregcpy &= ~his_cmdupldrdy;
+ adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
spin_unlock_irq(&adapter->driver_lock);
libertas_process_rx_command(priv);
spin_lock_irq(&adapter->driver_lock);
}
/* Any Card Event */
- if (adapter->hisregcpy & his_cardevent) {
+ if (adapter->hisregcpy & MRVDRV_CARDEVENT) {
lbs_deb_thread("main-thread: Card Event Activity\n");
- adapter->hisregcpy &= ~his_cardevent;
+ adapter->hisregcpy &= ~MRVDRV_CARDEVENT;
if (priv->hw_read_event_cause(priv)) {
lbs_pr_alert(
@@ -711,7 +861,7 @@ static int wlan_service_main_thread(void *data)
if (adapter->psstate == PS_STATE_PRE_SLEEP) {
if (!priv->dnld_sent && !adapter->cur_cmd) {
if (adapter->connect_status ==
- libertas_connected) {
+ LIBERTAS_CONNECTED) {
lbs_deb_thread(
"main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p "
"dnld_sent=%d cur_cmd=%p, confirm now\n",
@@ -758,13 +908,214 @@ static int wlan_service_main_thread(void *data)
del_timer(&adapter->command_timer);
adapter->nr_cmd_pending = 0;
wake_up_all(&adapter->cmd_pending);
- wlan_deactivate_thread(thread);
lbs_deb_leave(LBS_DEB_THREAD);
return 0;
}
/**
+ * @brief This function downloads firmware image, gets
+ * HW spec from firmware and set basic parameters to
+ * firmware.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 or -1
+ */
+static int wlan_setup_firmware(wlan_private * priv)
+{
+ int ret = -1;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_mesh_access mesh_access;
+
+ lbs_deb_enter(LBS_DEB_FW);
+
+ /*
+ * Read MAC address from HW
+ */
+ memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+ ret = libertas_prepare_and_send_command(priv, CMD_GET_HW_SPEC,
+ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
+
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+
+ libertas_set_mac_packet_filter(priv);
+
+ /* Get the supported Data rates */
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE,
+ CMD_ACT_GET_TX_RATE,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
+
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+
+ /* Disable mesh autostart */
+ if (priv->mesh_dev) {
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ mesh_access.data[0] = cpu_to_le32(0);
+ ret = libertas_prepare_and_send_command(priv,
+ CMD_MESH_ACCESS,
+ CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+ priv->mesh_autostart_enabled = 0;
+ }
+
+ /* Set the boot2 version in firmware */
+ ret = libertas_prepare_and_send_command(priv, CMD_SET_BOOT2_VER,
+ 0, CMD_OPTION_WAITFORRSP, 0, NULL);
+
+ ret = 0;
+done:
+ lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+ return ret;
+}
+
+/**
+ * This function handles the timeout of command sending.
+ * It will re-send the same command again.
+ */
+static void command_timer_fn(unsigned long data)
+{
+ wlan_private *priv = (wlan_private *)data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *ptempnode;
+ struct cmd_ds_command *cmd;
+ unsigned long flags;
+
+ ptempnode = adapter->cur_cmd;
+ if (ptempnode == NULL) {
+ lbs_deb_fw("ptempnode empty\n");
+ return;
+ }
+
+ cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
+ if (!cmd) {
+ lbs_deb_fw("cmd is NULL\n");
+ return;
+ }
+
+ lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command);
+
+ if (!adapter->fw_ready)
+ return;
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ adapter->cur_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ lbs_deb_fw("re-sending same command because of timeout\n");
+ libertas_queue_cmd(adapter, ptempnode, 0);
+
+ wake_up_interruptible(&priv->waitq);
+
+ return;
+}
+
+static int libertas_init_adapter(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ size_t bufsize;
+ int i, ret = 0;
+
+ /* Allocate buffer to store the BSSID list */
+ bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
+ adapter->networks = kzalloc(bufsize, GFP_KERNEL);
+ if (!adapter->networks) {
+ lbs_pr_err("Out of memory allocating beacons\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* Initialize scan result lists */
+ INIT_LIST_HEAD(&adapter->network_free_list);
+ INIT_LIST_HEAD(&adapter->network_list);
+ for (i = 0; i < MAX_NETWORK_COUNT; i++) {
+ list_add_tail(&adapter->networks[i].list,
+ &adapter->network_free_list);
+ }
+
+ adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
+ adapter->libertas_ps_confirm_sleep.command =
+ cpu_to_le16(CMD_802_11_PS_MODE);
+ adapter->libertas_ps_confirm_sleep.size =
+ cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
+ adapter->libertas_ps_confirm_sleep.action =
+ cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED);
+
+ memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+ adapter->connect_status = LIBERTAS_DISCONNECTED;
+ adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
+ adapter->mode = IW_MODE_INFRA;
+ adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
+ adapter->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
+ adapter->radioon = RADIO_ON;
+ adapter->auto_rate = 1;
+ adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
+ adapter->psmode = WLAN802_11POWERMODECAM;
+ adapter->psstate = PS_STATE_FULL_POWER;
+
+ mutex_init(&adapter->lock);
+
+ memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
+ adapter->tx_queue_idx = 0;
+ spin_lock_init(&adapter->txqueue_lock);
+
+ setup_timer(&adapter->command_timer, command_timer_fn,
+ (unsigned long)priv);
+
+ INIT_LIST_HEAD(&adapter->cmdfreeq);
+ INIT_LIST_HEAD(&adapter->cmdpendingq);
+
+ spin_lock_init(&adapter->driver_lock);
+ init_waitqueue_head(&adapter->cmd_pending);
+ adapter->nr_cmd_pending = 0;
+
+ /* Allocate the command buffers */
+ if (libertas_allocate_cmd_buffer(priv)) {
+ lbs_pr_err("Out of memory allocating command buffers\n");
+ ret = -1;
+ }
+
+out:
+ return ret;
+}
+
+static void libertas_free_adapter(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ if (!adapter) {
+ lbs_deb_fw("why double free adapter?\n");
+ return;
+ }
+
+ lbs_deb_fw("free command buffer\n");
+ libertas_free_cmd_buffer(priv);
+
+ lbs_deb_fw("free command_timer\n");
+ del_timer(&adapter->command_timer);
+
+ lbs_deb_fw("free scan results table\n");
+ kfree(adapter->networks);
+ adapter->networks = NULL;
+
+ /* Free the adapter object itself */
+ lbs_deb_fw("free adapter\n");
+ kfree(adapter);
+ priv->adapter = NULL;
+}
+
+/**
* @brief This function adds the card. it will probe the
* card, allocate the wlan_priv and initialize the device.
*
@@ -781,7 +1132,7 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
/* Allocate an Ethernet device and register it */
if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
lbs_pr_err("init ethX device failed\n");
- return NULL;
+ goto done;
}
priv = dev->priv;
@@ -791,20 +1142,24 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
goto err_kzalloc;
}
+ if (libertas_init_adapter(priv)) {
+ lbs_pr_err("failed to initialize adapter structure.\n");
+ goto err_init_adapter;
+ }
+
priv->dev = dev;
priv->card = card;
priv->mesh_open = 0;
priv->infra_open = 0;
-
- SET_MODULE_OWNER(dev);
+ priv->hotplug_device = dmdev;
/* Setup the OS Interface to our functions */
- dev->open = wlan_open;
- dev->hard_start_xmit = wlan_pre_start_xmit;
- dev->stop = wlan_close;
- dev->set_mac_address = wlan_set_mac_address;
- dev->tx_timeout = wlan_tx_timeout;
- dev->get_stats = wlan_get_stats;
+ dev->open = libertas_open;
+ dev->hard_start_xmit = libertas_pre_start_xmit;
+ dev->stop = libertas_close;
+ dev->set_mac_address = libertas_set_mac_address;
+ dev->tx_timeout = libertas_tx_timeout;
+ dev->get_stats = libertas_get_stats;
dev->watchdog_timeo = 5 * HZ;
dev->ethtool_ops = &libertas_ethtool_ops;
#ifdef WIRELESS_EXT
@@ -813,84 +1168,148 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev)
#define NETIF_F_DYNALLOC 16
dev->features |= NETIF_F_DYNALLOC;
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
- dev->set_multicast_list = wlan_set_multicast_list;
+ dev->set_multicast_list = libertas_set_multicast_list;
SET_NETDEV_DEV(dev, dmdev);
- INIT_LIST_HEAD(&priv->adapter->cmdfreeq);
- INIT_LIST_HEAD(&priv->adapter->cmdpendingq);
+ priv->rtap_net_dev = NULL;
+ if (device_create_file(dmdev, &dev_attr_libertas_rtap))
+ goto err_init_adapter;
+
+ lbs_deb_thread("Starting main thread...\n");
+ init_waitqueue_head(&priv->waitq);
+ priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main");
+ if (IS_ERR(priv->main_thread)) {
+ lbs_deb_thread("Error creating main thread.\n");
+ goto err_kthread_run;
+ }
+
+ priv->work_thread = create_singlethread_workqueue("libertas_worker");
+ INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
+ INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker);
+ INIT_WORK(&priv->sync_channel, libertas_sync_channel);
- spin_lock_init(&priv->adapter->driver_lock);
- init_waitqueue_head(&priv->adapter->cmd_pending);
- priv->adapter->nr_cmd_pending = 0;
goto done;
+err_kthread_run:
+ device_remove_file(dmdev, &dev_attr_libertas_rtap);
+
+err_init_adapter:
+ libertas_free_adapter(priv);
+
err_kzalloc:
free_netdev(dev);
priv = NULL;
+
done:
lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv);
return priv;
}
EXPORT_SYMBOL_GPL(libertas_add_card);
-int libertas_activate_card(wlan_private *priv, char *fw_name)
+
+int libertas_remove_card(wlan_private *priv)
{
+ wlan_adapter *adapter = priv->adapter;
struct net_device *dev = priv->dev;
- int ret = -1;
+ union iwreq_data wrqu;
lbs_deb_enter(LBS_DEB_MAIN);
- lbs_deb_thread("Starting kthread...\n");
- priv->mainthread.priv = priv;
- wlan_create_thread(wlan_service_main_thread,
- &priv->mainthread, "wlan_main_service");
+ libertas_remove_rtap(priv);
- priv->assoc_thread =
- create_singlethread_workqueue("libertas_assoc");
- INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
- INIT_WORK(&priv->sync_channel, libertas_sync_channel);
+ dev = priv->dev;
+ device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap);
- /*
- * Register the device. Fillup the private data structure with
- * relevant information from the card and request for the required
- * IRQ.
- */
- if (priv->hw_register_dev(priv) < 0) {
- lbs_pr_err("failed to register WLAN device\n");
- goto err_registerdev;
- }
+ cancel_delayed_work(&priv->scan_work);
+ cancel_delayed_work(&priv->assoc_work);
+ destroy_workqueue(priv->work_thread);
- /* init FW and HW */
- if (fw_name && libertas_init_fw(priv, fw_name)) {
- lbs_pr_err("firmware init failed\n");
- goto err_registerdev;
+ if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
+ adapter->psmode = WLAN802_11POWERMODECAM;
+ libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
}
+ memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+
+ /* Stop the thread servicing the interrupts */
+ adapter->surpriseremoved = 1;
+ kthread_stop(priv->main_thread);
+
+ libertas_free_adapter(priv);
+
+ priv->dev = NULL;
+ free_netdev(dev);
+
+ lbs_deb_leave(LBS_DEB_MAIN);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(libertas_remove_card);
+
+
+int libertas_start_card(wlan_private *priv)
+{
+ struct net_device *dev = priv->dev;
+ int ret = -1;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+ /* poke the firmware */
+ ret = wlan_setup_firmware(priv);
+ if (ret)
+ goto done;
+
+ /* init 802.11d */
+ libertas_init_11d(priv);
+
if (register_netdev(dev)) {
lbs_pr_err("cannot register ethX device\n");
- goto err_init_fw;
+ goto done;
}
- lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
-
libertas_debugfs_init_one(priv, dev);
+ lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
+
ret = 0;
- goto done;
-err_init_fw:
- priv->hw_unregister_dev(priv);
-err_registerdev:
- destroy_workqueue(priv->assoc_thread);
- /* Stop the thread servicing the interrupts */
- wake_up_interruptible(&priv->mainthread.waitq);
- wlan_terminate_thread(&priv->mainthread);
done:
- lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
return ret;
}
-EXPORT_SYMBOL_GPL(libertas_activate_card);
+EXPORT_SYMBOL_GPL(libertas_start_card);
+
+
+int libertas_stop_card(wlan_private *priv)
+{
+ struct net_device *dev = priv->dev;
+ int ret = -1;
+ struct cmd_ctrl_node *cmdnode;
+ unsigned long flags;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+
+ netif_stop_queue(priv->dev);
+ netif_carrier_off(priv->dev);
+
+ libertas_debugfs_remove_one(priv);
+
+ /* Flush pending command nodes */
+ spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+ list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
+ cmdnode->cmdwaitqwoken = 1;
+ wake_up_interruptible(&cmdnode->cmdwait_q);
+ }
+ spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+
+ unregister_netdev(dev);
+
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(libertas_stop_card);
/**
@@ -915,13 +1334,11 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev)
mesh_dev->priv = priv;
priv->mesh_dev = mesh_dev;
- SET_MODULE_OWNER(mesh_dev);
-
- mesh_dev->open = mesh_open;
- mesh_dev->hard_start_xmit = mesh_pre_start_xmit;
- mesh_dev->stop = mesh_close;
- mesh_dev->get_stats = wlan_get_stats;
- mesh_dev->set_mac_address = wlan_set_mac_address;
+ mesh_dev->open = libertas_mesh_open;
+ mesh_dev->hard_start_xmit = libertas_mesh_pre_start_xmit;
+ mesh_dev->stop = libertas_mesh_close;
+ mesh_dev->get_stats = libertas_get_stats;
+ mesh_dev->set_mac_address = libertas_set_mac_address;
mesh_dev->ethtool_ops = &libertas_ethtool_ops;
memcpy(mesh_dev->dev_addr, priv->dev->dev_addr,
sizeof(priv->dev->dev_addr));
@@ -940,7 +1357,7 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev)
goto err_free;
}
- ret = device_create_file(&(mesh_dev->dev), &dev_attr_anycast_mask);
+ ret = sysfs_create_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group);
if (ret)
goto err_unregister;
@@ -948,7 +1365,6 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev)
ret = 0;
goto done;
-
err_unregister:
unregister_netdev(mesh_dev);
@@ -961,86 +1377,12 @@ done:
}
EXPORT_SYMBOL_GPL(libertas_add_mesh);
-static void wake_pending_cmdnodes(wlan_private *priv)
-{
- struct cmd_ctrl_node *cmdnode;
- unsigned long flags;
-
- lbs_deb_enter(LBS_DEB_CMD);
-
- spin_lock_irqsave(&priv->adapter->driver_lock, flags);
- list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
- cmdnode->cmdwaitqwoken = 1;
- wake_up_interruptible(&cmdnode->cmdwait_q);
- }
- spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
-}
-
-
-int libertas_remove_card(wlan_private *priv)
-{
- wlan_adapter *adapter;
- struct net_device *dev;
- union iwreq_data wrqu;
-
- lbs_deb_enter(LBS_DEB_NET);
-
- if (!priv)
- goto out;
-
- adapter = priv->adapter;
-
- if (!adapter)
- goto out;
-
- dev = priv->dev;
-
- netif_stop_queue(priv->dev);
- netif_carrier_off(priv->dev);
-
- wake_pending_cmdnodes(priv);
-
- unregister_netdev(dev);
-
- cancel_delayed_work(&priv->assoc_work);
- destroy_workqueue(priv->assoc_thread);
-
- if (adapter->psmode == wlan802_11powermodemax_psp) {
- adapter->psmode = wlan802_11powermodecam;
- libertas_ps_wakeup(priv, cmd_option_waitforrsp);
- }
-
- memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-
- adapter->surpriseremoved = 1;
-
- /* Stop the thread servicing the interrupts */
- wlan_terminate_thread(&priv->mainthread);
-
- libertas_debugfs_remove_one(priv);
-
- lbs_deb_net("free adapter\n");
- libertas_free_adapter(priv);
-
- lbs_deb_net("unregister finish\n");
-
- priv->dev = NULL;
- free_netdev(dev);
-
-out:
- lbs_deb_leave(LBS_DEB_NET);
- return 0;
-}
-EXPORT_SYMBOL_GPL(libertas_remove_card);
-
void libertas_remove_mesh(wlan_private *priv)
{
struct net_device *mesh_dev;
- lbs_deb_enter(LBS_DEB_NET);
+ lbs_deb_enter(LBS_DEB_MAIN);
if (!priv)
goto out;
@@ -1050,14 +1392,14 @@ void libertas_remove_mesh(wlan_private *priv)
netif_stop_queue(mesh_dev);
netif_carrier_off(priv->mesh_dev);
- device_remove_file(&(mesh_dev->dev), &dev_attr_anycast_mask);
+ sysfs_remove_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group);
unregister_netdev(mesh_dev);
priv->mesh_dev = NULL ;
free_netdev(mesh_dev);
out:
- lbs_deb_leave(LBS_DEB_NET);
+ lbs_deb_leave(LBS_DEB_MAIN);
}
EXPORT_SYMBOL_GPL(libertas_remove_mesh);
@@ -1076,7 +1418,7 @@ struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *c
lbs_deb_enter(LBS_DEB_MAIN);
- end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table);
+ end = ARRAY_SIZE(region_cfp_table);
for (i = 0; i < end ; i++) {
lbs_deb_main("region_cfp_table[i].region=%d\n",
@@ -1148,15 +1490,30 @@ void libertas_interrupt(struct net_device *dev)
if (priv->adapter->psstate == PS_STATE_SLEEP) {
priv->adapter->psstate = PS_STATE_AWAKE;
netif_wake_queue(dev);
- netif_wake_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_wake_queue(priv->mesh_dev);
}
- wake_up_interruptible(&priv->mainthread.waitq);
+ wake_up_interruptible(&priv->waitq);
lbs_deb_leave(LBS_DEB_THREAD);
}
EXPORT_SYMBOL_GPL(libertas_interrupt);
+int libertas_reset_device(wlan_private *priv)
+{
+ int ret;
+
+ lbs_deb_enter(LBS_DEB_MAIN);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_RESET,
+ CMD_ACT_HALT, 0, 0, NULL);
+ msleep_interruptible(10);
+
+ lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(libertas_reset_device);
+
static int libertas_init_module(void)
{
lbs_deb_enter(LBS_DEB_MAIN);
@@ -1174,6 +1531,81 @@ static void libertas_exit_module(void)
lbs_deb_leave(LBS_DEB_MAIN);
}
+/*
+ * rtap interface support fuctions
+ */
+
+static int libertas_rtap_open(struct net_device *dev)
+{
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
+ return 0;
+}
+
+static int libertas_rtap_stop(struct net_device *dev)
+{
+ return 0;
+}
+
+static int libertas_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ return -EOPNOTSUPP;
+}
+
+static struct net_device_stats *libertas_rtap_get_stats(struct net_device *dev)
+{
+ wlan_private *priv = dev->priv;
+ return &priv->ieee->stats;
+}
+
+
+void libertas_remove_rtap(wlan_private *priv)
+{
+ if (priv->rtap_net_dev == NULL)
+ return;
+ unregister_netdev(priv->rtap_net_dev);
+ free_ieee80211(priv->rtap_net_dev);
+ priv->rtap_net_dev = NULL;
+}
+
+int libertas_add_rtap(wlan_private *priv)
+{
+ int rc = 0;
+
+ if (priv->rtap_net_dev)
+ return -EPERM;
+
+ priv->rtap_net_dev = alloc_ieee80211(0);
+ if (priv->rtap_net_dev == NULL)
+ return -ENOMEM;
+
+
+ priv->ieee = netdev_priv(priv->rtap_net_dev);
+
+ strcpy(priv->rtap_net_dev->name, "rtap%d");
+
+ priv->rtap_net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+ priv->rtap_net_dev->open = libertas_rtap_open;
+ priv->rtap_net_dev->stop = libertas_rtap_stop;
+ priv->rtap_net_dev->get_stats = libertas_rtap_get_stats;
+ priv->rtap_net_dev->hard_start_xmit = libertas_rtap_hard_start_xmit;
+ priv->rtap_net_dev->set_multicast_list = libertas_set_multicast_list;
+ priv->rtap_net_dev->priv = priv;
+
+ priv->ieee->iw_mode = IW_MODE_MONITOR;
+
+ rc = register_netdev(priv->rtap_net_dev);
+ if (rc) {
+ free_ieee80211(priv->rtap_net_dev);
+ priv->rtap_net_dev = NULL;
+ return rc;
+ }
+
+ return 0;
+}
+
+
module_init(libertas_init_module);
module_exit(libertas_exit_module);
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 769c86fb950..0420e5b9ff9 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -85,12 +85,12 @@ static u8 wlan_getavgnf(wlan_private * priv)
static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd)
{
wlan_adapter *adapter = priv->adapter;
- if (adapter->numSNRNF < adapter->data_avg_factor)
+ if (adapter->numSNRNF < DEFAULT_DATA_AVG_FACTOR)
adapter->numSNRNF++;
adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr;
adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf;
adapter->nextSNRNF++;
- if (adapter->nextSNRNF >= adapter->data_avg_factor)
+ if (adapter->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
adapter->nextSNRNF = 0;
return;
}
@@ -117,8 +117,6 @@ static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd)
adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
wlan_save_rawSNRNF(priv, p_rx_pd);
- adapter->rxpd_rate = p_rx_pd->rx_rate;
-
adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE;
adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE;
lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n",
@@ -140,12 +138,15 @@ void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
{
lbs_deb_rx("skb->data %p\n", skb->data);
- if (priv->mesh_dev && IS_MESH_FRAME(skb))
- skb->protocol = eth_type_trans(skb, priv->mesh_dev);
- else
- skb->protocol = eth_type_trans(skb, priv->dev);
+ if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
+ skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);
+ } else {
+ if (priv->mesh_dev && IS_MESH_FRAME(skb))
+ skb->protocol = eth_type_trans(skb, priv->mesh_dev);
+ else
+ skb->protocol = eth_type_trans(skb, priv->dev);
+ }
skb->ip_summed = CHECKSUM_UNNECESSARY;
-
netif_rx(skb);
}
@@ -172,11 +173,7 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
lbs_deb_enter(LBS_DEB_RX);
- if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH)
- lbs_dbg_hex("RX packet: ", skb->data,
- min_t(unsigned int, skb->len, 100));
-
- if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+ if (priv->adapter->monitormode != WLAN_MONITOR_OFF)
return process_rxed_802_11_packet(priv, skb);
p_rx_pkt = (struct rxpackethdr *) skb->data;
@@ -186,7 +183,7 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
else
UNSET_MESH_FRAME(skb);
- lbs_dbg_hex("RX Data: Before chop rxpd", skb->data,
+ lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data,
min_t(unsigned int, skb->len, 100));
if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
@@ -210,9 +207,9 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
- lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
+ lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
sizeof(p_rx_pkt->eth803_hdr.dest_addr));
- lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
+ lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
sizeof(p_rx_pkt->eth803_hdr.src_addr));
if (memcmp(&p_rx_pkt->rfc1042_hdr,
@@ -244,7 +241,7 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
*/
hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
} else {
- lbs_dbg_hex("RX Data: LLC/SNAP",
+ lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP",
(u8 *) & p_rx_pkt->rfc1042_hdr,
sizeof(p_rx_pkt->rfc1042_hdr));
@@ -260,8 +257,8 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
/* Take the data rate from the rxpd structure
* only if the rate is auto
*/
- if (adapter->is_datarate_auto)
- adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate);
+ if (adapter->auto_rate)
+ adapter->cur_rate = libertas_fw_index_to_data_rate(p_rx_pd->rx_rate);
wlan_compute_rssi(priv, p_rx_pd);
@@ -296,21 +293,22 @@ static u8 convert_mv_rate_to_radiotap(u8 rate)
return 11;
case 3: /* 11 Mbps */
return 22;
- case 4: /* 6 Mbps */
+ /* case 4: reserved */
+ case 5: /* 6 Mbps */
return 12;
- case 5: /* 9 Mbps */
+ case 6: /* 9 Mbps */
return 18;
- case 6: /* 12 Mbps */
+ case 7: /* 12 Mbps */
return 24;
- case 7: /* 18 Mbps */
+ case 8: /* 18 Mbps */
return 36;
- case 8: /* 24 Mbps */
+ case 9: /* 24 Mbps */
return 48;
- case 9: /* 36 Mbps */
+ case 10: /* 36 Mbps */
return 72;
- case 10: /* 48 Mbps */
+ case 11: /* 48 Mbps */
return 96;
- case 11: /* 54 Mbps */
+ case 12: /* 54 Mbps */
return 108;
}
lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate);
@@ -340,7 +338,7 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
p_rx_pkt = (struct rx80211packethdr *) skb->data;
prxpd = &p_rx_pkt->rx_pd;
- // lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
+ // lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
lbs_deb_rx("rx err: frame received wit bad length\n");
@@ -361,20 +359,19 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
/* create the exported radio header */
- switch (priv->adapter->radiomode) {
- case WLAN_RADIOMODE_NONE:
+ if(priv->adapter->monitormode == WLAN_MONITOR_OFF) {
/* no radio header */
/* chop the rxpd */
skb_pull(skb, sizeof(struct rxpd));
- break;
+ }
- case WLAN_RADIOMODE_RADIOTAP:
+ else {
/* radiotap header */
radiotap_hdr.hdr.it_version = 0;
/* XXX must check this value for pad */
radiotap_hdr.hdr.it_pad = 0;
- radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr);
- radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT;
+ radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr));
+ radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT);
/* unknown values */
radiotap_hdr.flags = 0;
radiotap_hdr.chan_freq = 0;
@@ -389,8 +386,6 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
//memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
- // lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100));
-
/* chop the rxpd */
skb_pull(skb, sizeof(struct rxpd));
@@ -408,25 +403,13 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
rx_radiotap_hdr));
memcpy(pradiotap_hdr, &radiotap_hdr,
sizeof(struct rx_radiotap_hdr));
- //lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100));
- break;
-
- default:
- /* unknown header */
- lbs_pr_alert("Unknown radiomode %i\n",
- priv->adapter->radiomode);
- /* don't export any header */
- /* chop the rxpd */
- skb_pull(skb, sizeof(struct rxpd));
- break;
}
/* Take the data rate from the rxpd structure
* only if the rate is auto
*/
- if (adapter->is_datarate_auto) {
- adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate);
- }
+ if (adapter->auto_rate)
+ adapter->cur_rate = libertas_fw_index_to_data_rate(prxpd->rx_rate);
wlan_compute_rssi(priv, prxpd);
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index c3043dcb541..ad1e67d984c 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -13,10 +13,13 @@
#include <net/ieee80211.h>
#include <net/iw_handler.h>
+#include <asm/unaligned.h>
+
#include "host.h"
#include "decl.h"
#include "dev.h"
#include "scan.h"
+#include "join.h"
//! Approximate amount of data needed to pass a scan result back to iwlist
#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
@@ -62,6 +65,15 @@
static const u8 zeromac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const u8 bcastmac[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+
+
+/*********************************************************************/
+/* */
+/* Misc helper functions */
+/* */
+/*********************************************************************/
+
static inline void clear_bss_descriptor (struct bss_descriptor * bss)
{
/* Don't blow away ->list, just BSS data */
@@ -74,9 +86,9 @@ static inline int match_bss_no_security(struct wlan_802_11_security * secinfo,
if ( !secinfo->wep_enabled
&& !secinfo->WPAenabled
&& !secinfo->WPA2enabled
- && match_bss->wpa_ie[0] != WPA_IE
- && match_bss->rsn_ie[0] != WPA2_IE
- && !match_bss->privacy) {
+ && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC
+ && match_bss->rsn_ie[0] != MFIE_TYPE_RSN
+ && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
return 1;
}
return 0;
@@ -88,7 +100,7 @@ static inline int match_bss_static_wep(struct wlan_802_11_security * secinfo,
if ( secinfo->wep_enabled
&& !secinfo->WPAenabled
&& !secinfo->WPA2enabled
- && match_bss->privacy) {
+ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
return 1;
}
return 0;
@@ -99,9 +111,10 @@ static inline int match_bss_wpa(struct wlan_802_11_security * secinfo,
{
if ( !secinfo->wep_enabled
&& secinfo->WPAenabled
- && (match_bss->wpa_ie[0] == WPA_IE)
+ && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC)
/* privacy bit may NOT be set in some APs like LinkSys WRT54G
- && bss->privacy */
+ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
+ */
) {
return 1;
}
@@ -113,9 +126,10 @@ static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo,
{
if ( !secinfo->wep_enabled
&& secinfo->WPA2enabled
- && (match_bss->rsn_ie[0] == WPA2_IE)
+ && (match_bss->rsn_ie[0] == MFIE_TYPE_RSN)
/* privacy bit may NOT be set in some APs like LinkSys WRT54G
- && bss->privacy */
+ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
+ */
) {
return 1;
}
@@ -128,9 +142,9 @@ static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo,
if ( !secinfo->wep_enabled
&& !secinfo->WPAenabled
&& !secinfo->WPA2enabled
- && (match_bss->wpa_ie[0] != WPA_IE)
- && (match_bss->rsn_ie[0] != WPA2_IE)
- && match_bss->privacy) {
+ && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC)
+ && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN)
+ && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
return 1;
}
return 0;
@@ -160,7 +174,7 @@ static int is_network_compatible(wlan_adapter * adapter,
{
int matched = 0;
- lbs_deb_enter(LBS_DEB_ASSOC);
+ lbs_deb_enter(LBS_DEB_SCAN);
if (bss->mode != mode)
goto done;
@@ -177,7 +191,7 @@ static int is_network_compatible(wlan_adapter * adapter,
adapter->secinfo.wep_enabled ? "e" : "d",
adapter->secinfo.WPAenabled ? "e" : "d",
adapter->secinfo.WPA2enabled ? "e" : "d",
- bss->privacy);
+ (bss->capability & WLAN_CAPABILITY_PRIVACY));
goto done;
} else if ((matched = match_bss_wpa2(&adapter->secinfo, bss))) {
lbs_deb_scan(
@@ -187,15 +201,14 @@ static int is_network_compatible(wlan_adapter * adapter,
adapter->secinfo.wep_enabled ? "e" : "d",
adapter->secinfo.WPAenabled ? "e" : "d",
adapter->secinfo.WPA2enabled ? "e" : "d",
- bss->privacy);
+ (bss->capability & WLAN_CAPABILITY_PRIVACY));
goto done;
} else if ((matched = match_bss_dynamic_wep(&adapter->secinfo, bss))) {
lbs_deb_scan(
"is_network_compatible() dynamic WEP: "
"wpa_ie=%#x wpa2_ie=%#x privacy=%#x\n",
- bss->wpa_ie[0],
- bss->rsn_ie[0],
- bss->privacy);
+ bss->wpa_ie[0], bss->rsn_ie[0],
+ (bss->capability & WLAN_CAPABILITY_PRIVACY));
goto done;
}
@@ -207,16 +220,44 @@ static int is_network_compatible(wlan_adapter * adapter,
adapter->secinfo.wep_enabled ? "e" : "d",
adapter->secinfo.WPAenabled ? "e" : "d",
adapter->secinfo.WPA2enabled ? "e" : "d",
- bss->privacy);
+ (bss->capability & WLAN_CAPABILITY_PRIVACY));
done:
- lbs_deb_leave(LBS_DEB_SCAN);
+ lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched);
return matched;
}
/**
+ * @brief Compare two SSIDs
+ *
+ * @param ssid1 A pointer to ssid to compare
+ * @param ssid2 A pointer to ssid to compare
+ *
+ * @return 0--ssid is same, otherwise is different
+ */
+int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
+{
+ if (ssid1_len != ssid2_len)
+ return -1;
+
+ return memcmp(ssid1, ssid2, ssid1_len);
+}
+
+
+
+
+/*********************************************************************/
+/* */
+/* Main scanning support */
+/* */
+/*********************************************************************/
+
+
+/**
* @brief Create a channel list for the driver to scan based on region info
*
+ * Only used from wlan_scan_setup_scan_config()
+ *
* Use the driver region/band information to construct a comprehensive list
* of channels to scan. This routine is used for any scan that is not
* provided a specific channel list to scan.
@@ -244,17 +285,19 @@ static void wlan_scan_create_channel_list(wlan_private * priv,
int nextchan;
u8 scantype;
+ lbs_deb_enter_args(LBS_DEB_SCAN, "filteredscan %d", filteredscan);
+
chanidx = 0;
/* Set the default scan type to the user specified type, will later
* be changed to passive on a per channel basis if restricted by
* regulatory requirements (11d or 11h)
*/
- scantype = adapter->scantype;
+ scantype = CMD_SCAN_TYPE_ACTIVE;
for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) {
if (priv->adapter->enable11d &&
- adapter->connect_status != libertas_connected) {
+ adapter->connect_status != LIBERTAS_CONNECTED) {
/* Scan all the supported chan for the first scan */
if (!adapter->universal_channel[rgnidx].valid)
continue;
@@ -286,11 +329,11 @@ static void wlan_scan_create_channel_list(wlan_private * priv,
case BAND_G:
default:
scanchanlist[chanidx].radiotype =
- cmd_scan_radio_type_bg;
+ CMD_SCAN_RADIO_TYPE_BG;
break;
}
- if (scantype == cmd_scan_type_passive) {
+ if (scantype == CMD_SCAN_TYPE_PASSIVE) {
scanchanlist[chanidx].maxscantime =
cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME);
scanchanlist[chanidx].chanscanmode.passivescan =
@@ -312,6 +355,16 @@ static void wlan_scan_create_channel_list(wlan_private * priv,
}
}
+
+/* Delayed partial scan worker */
+void libertas_scan_worker(struct work_struct *work)
+{
+ wlan_private *priv = container_of(work, wlan_private, scan_work.work);
+
+ wlan_scan_networks(priv, NULL, 0);
+}
+
+
/**
* @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
*
@@ -359,7 +412,6 @@ wlan_scan_setup_scan_config(wlan_private * priv,
u8 * pfilteredscan,
u8 * pscancurrentonly)
{
- wlan_adapter *adapter = priv->adapter;
struct mrvlietypes_numprobes *pnumprobestlv;
struct mrvlietypes_ssidparamset *pssidtlv;
struct wlan_scan_cmd_config * pscancfgout = NULL;
@@ -371,6 +423,8 @@ wlan_scan_setup_scan_config(wlan_private * priv,
int channel;
int radiotype;
+ lbs_deb_enter(LBS_DEB_SCAN);
+
pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
if (pscancfgout == NULL)
goto out;
@@ -407,15 +461,12 @@ wlan_scan_setup_scan_config(wlan_private * priv,
*pscancurrentonly = 0;
if (puserscanin) {
-
/* Set the bss type scan filter, use adapter setting if unset */
pscancfgout->bsstype =
- (puserscanin->bsstype ? puserscanin->bsstype : adapter->
- scanmode);
+ puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY;
/* Set the number of probes to send, use adapter setting if unset */
- numprobes = (puserscanin->numprobes ? puserscanin->numprobes :
- adapter->scanprobes);
+ numprobes = puserscanin->numprobes ? puserscanin->numprobes : 0;
/*
* Set the BSSID filter to the incoming configuration,
@@ -447,8 +498,8 @@ wlan_scan_setup_scan_config(wlan_private * priv,
*pfilteredscan = 1;
}
} else {
- pscancfgout->bsstype = adapter->scanmode;
- numprobes = adapter->scanprobes;
+ pscancfgout->bsstype = CMD_BSS_TYPE_ANY;
+ numprobes = 0;
}
/* If the input config or adapter has the number of Probes set, add tlv */
@@ -469,59 +520,56 @@ wlan_scan_setup_scan_config(wlan_private * priv,
*/
*ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
- if (puserscanin && puserscanin->chanlist[0].channumber) {
-
- lbs_deb_scan("Scan: Using supplied channel list\n");
+ if (!puserscanin || !puserscanin->chanlist[0].channumber) {
+ /* Create a default channel scan list */
+ lbs_deb_scan("creating full region channel list\n");
+ wlan_scan_create_channel_list(priv, pscanchanlist,
+ *pfilteredscan);
+ goto out;
+ }
- for (chanidx = 0;
- chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
- && puserscanin->chanlist[chanidx].channumber; chanidx++) {
+ for (chanidx = 0;
+ chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
+ && puserscanin->chanlist[chanidx].channumber; chanidx++) {
- channel = puserscanin->chanlist[chanidx].channumber;
- (pscanchanlist + chanidx)->channumber = channel;
+ channel = puserscanin->chanlist[chanidx].channumber;
+ (pscanchanlist + chanidx)->channumber = channel;
- radiotype = puserscanin->chanlist[chanidx].radiotype;
- (pscanchanlist + chanidx)->radiotype = radiotype;
+ radiotype = puserscanin->chanlist[chanidx].radiotype;
+ (pscanchanlist + chanidx)->radiotype = radiotype;
- scantype = puserscanin->chanlist[chanidx].scantype;
+ scantype = puserscanin->chanlist[chanidx].scantype;
- if (scantype == cmd_scan_type_passive) {
- (pscanchanlist +
- chanidx)->chanscanmode.passivescan = 1;
- } else {
- (pscanchanlist +
- chanidx)->chanscanmode.passivescan = 0;
- }
+ if (scantype == CMD_SCAN_TYPE_PASSIVE) {
+ (pscanchanlist +
+ chanidx)->chanscanmode.passivescan = 1;
+ } else {
+ (pscanchanlist +
+ chanidx)->chanscanmode.passivescan = 0;
+ }
- if (puserscanin->chanlist[chanidx].scantime) {
- scandur =
- puserscanin->chanlist[chanidx].scantime;
+ if (puserscanin->chanlist[chanidx].scantime) {
+ scandur = puserscanin->chanlist[chanidx].scantime;
+ } else {
+ if (scantype == CMD_SCAN_TYPE_PASSIVE) {
+ scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
} else {
- if (scantype == cmd_scan_type_passive) {
- scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
- } else {
- scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
- }
+ scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
}
-
- (pscanchanlist + chanidx)->minscantime =
- cpu_to_le16(scandur);
- (pscanchanlist + chanidx)->maxscantime =
- cpu_to_le16(scandur);
}
- /* Check if we are only scanning the current channel */
- if ((chanidx == 1) && (puserscanin->chanlist[0].channumber
- ==
- priv->adapter->curbssparams.channel)) {
- *pscancurrentonly = 1;
- lbs_deb_scan("Scan: Scanning current channel only");
- }
+ (pscanchanlist + chanidx)->minscantime =
+ cpu_to_le16(scandur);
+ (pscanchanlist + chanidx)->maxscantime =
+ cpu_to_le16(scandur);
+ }
- } else {
- lbs_deb_scan("Scan: Creating full region channel list\n");
- wlan_scan_create_channel_list(priv, pscanchanlist,
- *pfilteredscan);
+ /* Check if we are only scanning the current channel */
+ if ((chanidx == 1) &&
+ (puserscanin->chanlist[0].channumber ==
+ priv->adapter->curbssparams.channel)) {
+ *pscancurrentonly = 1;
+ lbs_deb_scan("scanning current channel only");
}
out:
@@ -531,6 +579,8 @@ out:
/**
* @brief Construct and send multiple scan config commands to the firmware
*
+ * Only used from wlan_scan_networks()
+ *
* Previous routines have created a wlan_scan_cmd_config with any requested
* TLVs. This function splits the channel TLV into maxchanperscan lists
* and sends the portion of the channel TLV along with the other TLVs
@@ -568,12 +618,14 @@ static int wlan_scan_channel_list(wlan_private * priv,
int scanned = 0;
union iwreq_data wrqu;
- lbs_deb_enter(LBS_DEB_ASSOC);
+ lbs_deb_enter_args(LBS_DEB_SCAN, "maxchanperscan %d, filteredscan %d, "
+ "full_scan %d", maxchanperscan, filteredscan, full_scan);
- if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) {
- lbs_deb_scan("Scan: Null detect: %p, %p, %p\n",
- pscancfgout, pchantlvout, pscanchanlist);
- return -1;
+ if (!pscancfgout || !pchantlvout || !pscanchanlist) {
+ lbs_deb_scan("pscancfgout, pchantlvout or "
+ "pscanchanlist is NULL\n");
+ ret = -1;
+ goto out;
}
pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
@@ -605,12 +657,13 @@ static int wlan_scan_channel_list(wlan_private * priv,
while (tlvidx < maxchanperscan && ptmpchan->channumber
&& !doneearly && scanned < 2) {
- lbs_deb_scan(
- "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n",
- ptmpchan->channumber, ptmpchan->radiotype,
- ptmpchan->chanscanmode.passivescan,
- ptmpchan->chanscanmode.disablechanfilt,
- ptmpchan->maxscantime);
+ lbs_deb_scan("channel %d, radio %d, passive %d, "
+ "dischanflt %d, maxscantime %d\n",
+ ptmpchan->channumber,
+ ptmpchan->radiotype,
+ ptmpchan->chanscanmode.passivescan,
+ ptmpchan->chanscanmode.disablechanfilt,
+ ptmpchan->maxscantime);
/* Copy the current channel TLV to the command being prepared */
memcpy(pchantlvout->chanscanparam + tlvidx,
@@ -667,7 +720,7 @@ static int wlan_scan_channel_list(wlan_private * priv,
}
/* Send the scan command to the firmware with the specified cfg */
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_SCAN, 0,
0, 0, pscancfgout);
if (scanned >= 2 && !full_scan) {
ret = 0;
@@ -679,24 +732,38 @@ static int wlan_scan_channel_list(wlan_private * priv,
done:
priv->adapter->last_scanned_channel = ptmpchan->channumber;
- /* Tell userspace the scan table has been updated */
- memset(&wrqu, 0, sizeof(union iwreq_data));
- wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+ if (priv->adapter->last_scanned_channel) {
+ /* Schedule the next part of the partial scan */
+ if (!full_scan && !priv->adapter->surpriseremoved) {
+ cancel_delayed_work(&priv->scan_work);
+ queue_delayed_work(priv->work_thread, &priv->scan_work,
+ msecs_to_jiffies(300));
+ }
+ } else {
+ /* All done, tell userspace the scan table has been updated */
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+ }
+out:
lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
return ret;
}
-static void
-clear_selected_scan_list_entries(wlan_adapter * adapter,
- const struct wlan_ioctl_user_scan_cfg * scan_cfg)
+/*
+ * Only used from wlan_scan_networks()
+*/
+static void clear_selected_scan_list_entries(wlan_adapter *adapter,
+ const struct wlan_ioctl_user_scan_cfg *scan_cfg)
{
- struct bss_descriptor * bss;
- struct bss_descriptor * safe;
+ struct bss_descriptor *bss;
+ struct bss_descriptor *safe;
u32 clear_ssid_flag = 0, clear_bssid_flag = 0;
+ lbs_deb_enter(LBS_DEB_SCAN);
+
if (!scan_cfg)
- return;
+ goto out;
if (scan_cfg->clear_ssid && scan_cfg->ssid_len)
clear_ssid_flag = 1;
@@ -708,7 +775,7 @@ clear_selected_scan_list_entries(wlan_adapter * adapter,
}
if (!clear_ssid_flag && !clear_bssid_flag)
- return;
+ goto out;
mutex_lock(&adapter->lock);
list_for_each_entry_safe (bss, safe, &adapter->network_list, list) {
@@ -731,12 +798,16 @@ clear_selected_scan_list_entries(wlan_adapter * adapter,
}
}
mutex_unlock(&adapter->lock);
+out:
+ lbs_deb_leave(LBS_DEB_SCAN);
}
/**
* @brief Internal function used to start a scan based on an input config
*
+ * Also used from debugfs
+ *
* Use the input user scan configuration information when provided in
* order to send the appropriate scan commands to firmware to populate or
* update the internal driver scan table
@@ -744,12 +815,13 @@ clear_selected_scan_list_entries(wlan_adapter * adapter,
* @param priv A pointer to wlan_private structure
* @param puserscanin Pointer to the input configuration for the requested
* scan.
+ * @param full_scan ???
*
* @return 0 or < 0 if error
*/
int wlan_scan_networks(wlan_private * priv,
- const struct wlan_ioctl_user_scan_cfg * puserscanin,
- int full_scan)
+ const struct wlan_ioctl_user_scan_cfg * puserscanin,
+ int full_scan)
{
wlan_adapter * adapter = priv->adapter;
struct mrvlietypes_chanlistparamset *pchantlvout;
@@ -762,9 +834,16 @@ int wlan_scan_networks(wlan_private * priv,
#ifdef CONFIG_LIBERTAS_DEBUG
struct bss_descriptor * iter_bss;
int i = 0;
+ DECLARE_MAC_BUF(mac);
#endif
- lbs_deb_enter(LBS_DEB_ASSOC);
+ lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
+
+ /* Cancel any partial outstanding partial scans if this scan
+ * is a full scan.
+ */
+ if (full_scan && delayed_work_pending(&priv->scan_work))
+ cancel_delayed_work(&priv->scan_work);
scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
@@ -791,8 +870,10 @@ int wlan_scan_networks(wlan_private * priv,
if (!scancurrentchanonly) {
netif_stop_queue(priv->dev);
netif_carrier_off(priv->dev);
- netif_stop_queue(priv->mesh_dev);
- netif_carrier_off(priv->mesh_dev);
+ if (priv->mesh_dev) {
+ netif_stop_queue(priv->mesh_dev);
+ netif_carrier_off(priv->mesh_dev);
+ }
}
ret = wlan_scan_channel_list(priv,
@@ -807,19 +888,22 @@ int wlan_scan_networks(wlan_private * priv,
#ifdef CONFIG_LIBERTAS_DEBUG
/* Dump the scan table */
mutex_lock(&adapter->lock);
+ lbs_deb_scan("The scan table contains:\n");
list_for_each_entry (iter_bss, &adapter->network_list, list) {
- lbs_deb_scan("Scan:(%02d) " MAC_FMT ", RSSI[%03d], SSID[%s]\n",
- i++, MAC_ARG(iter_bss->bssid), (s32) iter_bss->rssi,
+ lbs_deb_scan("scan %02d, %s, RSSI, %d, SSID '%s'\n",
+ i++, print_mac(mac, iter_bss->bssid), (s32) iter_bss->rssi,
escape_essid(iter_bss->ssid, iter_bss->ssid_len));
}
mutex_unlock(&adapter->lock);
#endif
- if (priv->adapter->connect_status == libertas_connected) {
+ if (priv->adapter->connect_status == LIBERTAS_CONNECTED) {
netif_carrier_on(priv->dev);
netif_wake_queue(priv->dev);
- netif_carrier_on(priv->mesh_dev);
- netif_wake_queue(priv->mesh_dev);
+ if (priv->mesh_dev) {
+ netif_carrier_on(priv->mesh_dev);
+ netif_wake_queue(priv->mesh_dev);
+ }
}
out:
@@ -834,58 +918,6 @@ out:
}
/**
- * @brief Inspect the scan response buffer for pointers to expected TLVs
- *
- * TLVs can be included at the end of the scan response BSS information.
- * Parse the data in the buffer for pointers to TLVs that can potentially
- * be passed back in the response
- *
- * @param ptlv Pointer to the start of the TLV buffer to parse
- * @param tlvbufsize size of the TLV buffer
- * @param ptsftlv Output parameter: Pointer to the TSF TLV if found
- *
- * @return void
- */
-static
-void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv,
- int tlvbufsize,
- struct mrvlietypes_tsftimestamp ** ptsftlv)
-{
- struct mrvlietypes_data *pcurrenttlv;
- int tlvbufleft;
- u16 tlvtype;
- u16 tlvlen;
-
- pcurrenttlv = ptlv;
- tlvbufleft = tlvbufsize;
- *ptsftlv = NULL;
-
- lbs_deb_scan("SCAN_RESP: tlvbufsize = %d\n", tlvbufsize);
- lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize);
-
- while (tlvbufleft >= sizeof(struct mrvlietypesheader)) {
- tlvtype = le16_to_cpu(pcurrenttlv->header.type);
- tlvlen = le16_to_cpu(pcurrenttlv->header.len);
-
- switch (tlvtype) {
- case TLV_TYPE_TSFTIMESTAMP:
- *ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv;
- break;
-
- default:
- lbs_deb_scan("SCAN_RESP: Unhandled TLV = %d\n",
- tlvtype);
- /* Give up, this seems corrupted */
- return;
- } /* switch */
-
- tlvbufleft -= (sizeof(ptlv->header) + tlvlen);
- pcurrenttlv =
- (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen);
- } /* while */
-}
-
-/**
* @brief Interpret a BSS scan response returned from the firmware
*
* Parse the various fixed fields and IEs passed back for a a BSS probe
@@ -899,67 +931,49 @@ void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv,
static int libertas_process_bss(struct bss_descriptor * bss,
u8 ** pbeaconinfo, int *bytesleft)
{
- enum ieeetypes_elementid elemID;
struct ieeetypes_fhparamset *pFH;
struct ieeetypes_dsparamset *pDS;
struct ieeetypes_cfparamset *pCF;
struct ieeetypes_ibssparamset *pibss;
- struct ieeetypes_capinfo *pcap;
- struct WLAN_802_11_FIXED_IEs fixedie;
- u8 *pcurrentptr;
- u8 *pRate;
- u8 elemlen;
- u8 bytestocopy;
- u8 ratesize;
- u16 beaconsize;
- u8 founddatarateie;
- int bytesleftforcurrentbeacon;
- int ret;
-
- struct IE_WPA *pIe;
- const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 };
-
+ DECLARE_MAC_BUF(mac);
struct ieeetypes_countryinfoset *pcountryinfo;
+ u8 *pos, *end, *p;
+ u8 n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
+ u16 beaconsize = 0;
+ int ret;
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- founddatarateie = 0;
- ratesize = 0;
- beaconsize = 0;
+ lbs_deb_enter(LBS_DEB_SCAN);
if (*bytesleft >= sizeof(beaconsize)) {
/* Extract & convert beacon size from the command buffer */
- beaconsize = le16_to_cpup((void *)*pbeaconinfo);
+ beaconsize = le16_to_cpu(get_unaligned((u16 *)*pbeaconinfo));
*bytesleft -= sizeof(beaconsize);
*pbeaconinfo += sizeof(beaconsize);
}
if (beaconsize == 0 || beaconsize > *bytesleft) {
-
*pbeaconinfo += *bytesleft;
*bytesleft = 0;
-
- return -1;
+ ret = -1;
+ goto done;
}
/* Initialize the current working beacon pointer for this BSS iteration */
- pcurrentptr = *pbeaconinfo;
+ pos = *pbeaconinfo;
+ end = pos + beaconsize;
/* Advance the return beacon pointer past the current beacon */
*pbeaconinfo += beaconsize;
*bytesleft -= beaconsize;
- bytesleftforcurrentbeacon = beaconsize;
-
- memcpy(bss->bssid, pcurrentptr, ETH_ALEN);
- lbs_deb_scan("process_bss: AP BSSID " MAC_FMT "\n", MAC_ARG(bss->bssid));
+ memcpy(bss->bssid, pos, ETH_ALEN);
+ lbs_deb_scan("process_bss: AP BSSID %s\n", print_mac(mac, bss->bssid));
+ pos += ETH_ALEN;
- pcurrentptr += ETH_ALEN;
- bytesleftforcurrentbeacon -= ETH_ALEN;
-
- if (bytesleftforcurrentbeacon < 12) {
+ if ((end - pos) < 12) {
lbs_deb_scan("process_bss: Not enough bytes left\n");
- return -1;
+ ret = -1;
+ goto done;
}
/*
@@ -968,85 +982,61 @@ static int libertas_process_bss(struct bss_descriptor * bss,
*/
/* RSSI is 1 byte long */
- bss->rssi = *pcurrentptr;
- lbs_deb_scan("process_bss: RSSI=%02X\n", *pcurrentptr);
- pcurrentptr += 1;
- bytesleftforcurrentbeacon -= 1;
+ bss->rssi = *pos;
+ lbs_deb_scan("process_bss: RSSI=%02X\n", *pos);
+ pos++;
/* time stamp is 8 bytes long */
- fixedie.timestamp = bss->timestamp = le64_to_cpup((void *)pcurrentptr);
- pcurrentptr += 8;
- bytesleftforcurrentbeacon -= 8;
+ pos += 8;
/* beacon interval is 2 bytes long */
- fixedie.beaconinterval = bss->beaconperiod = le16_to_cpup((void *)pcurrentptr);
- pcurrentptr += 2;
- bytesleftforcurrentbeacon -= 2;
+ bss->beaconperiod = le16_to_cpup((void *) pos);
+ pos += 2;
/* capability information is 2 bytes long */
- memcpy(&fixedie.capabilities, pcurrentptr, 2);
- lbs_deb_scan("process_bss: fixedie.capabilities=0x%X\n",
- fixedie.capabilities);
- pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities;
- memcpy(&bss->cap, pcap, sizeof(struct ieeetypes_capinfo));
- pcurrentptr += 2;
- bytesleftforcurrentbeacon -= 2;
-
- /* rest of the current buffer are IE's */
- lbs_deb_scan("process_bss: IE length for this AP = %d\n",
- bytesleftforcurrentbeacon);
+ bss->capability = le16_to_cpup((void *) pos);
+ lbs_deb_scan("process_bss: capabilities = 0x%4X\n", bss->capability);
+ pos += 2;
- lbs_dbg_hex("process_bss: IE info", (u8 *) pcurrentptr,
- bytesleftforcurrentbeacon);
-
- if (pcap->privacy) {
+ if (bss->capability & WLAN_CAPABILITY_PRIVACY)
lbs_deb_scan("process_bss: AP WEP enabled\n");
- bss->privacy = wlan802_11privfilter8021xWEP;
- } else {
- bss->privacy = wlan802_11privfilteracceptall;
- }
-
- if (pcap->ibss == 1) {
+ if (bss->capability & WLAN_CAPABILITY_IBSS)
bss->mode = IW_MODE_ADHOC;
- } else {
+ else
bss->mode = IW_MODE_INFRA;
- }
+
+ /* rest of the current buffer are IE's */
+ lbs_deb_scan("process_bss: IE length for this AP = %zd\n", end - pos);
+ lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);
/* process variable IE */
- while (bytesleftforcurrentbeacon >= 2) {
- elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr));
- elemlen = *((u8 *) pcurrentptr + 1);
+ while (pos <= end - 2) {
+ struct ieee80211_info_element * elem =
+ (struct ieee80211_info_element *) pos;
- if (bytesleftforcurrentbeacon < elemlen) {
+ if (pos + elem->len > end) {
lbs_deb_scan("process_bss: error in processing IE, "
"bytes left < IE length\n");
- bytesleftforcurrentbeacon = 0;
- continue;
+ break;
}
- switch (elemID) {
- case SSID:
- bss->ssid_len = elemlen;
- memcpy(bss->ssid, (pcurrentptr + 2), elemlen);
+ switch (elem->id) {
+ case MFIE_TYPE_SSID:
+ bss->ssid_len = elem->len;
+ memcpy(bss->ssid, elem->data, elem->len);
lbs_deb_scan("ssid '%s', ssid length %u\n",
escape_essid(bss->ssid, bss->ssid_len),
bss->ssid_len);
break;
- case SUPPORTED_RATES:
- memcpy(bss->datarates, (pcurrentptr + 2), elemlen);
- memmove(bss->libertas_supported_rates, (pcurrentptr + 2),
- elemlen);
- ratesize = elemlen;
- founddatarateie = 1;
+ case MFIE_TYPE_RATES:
+ n_basic_rates = min_t(u8, MAX_RATES, elem->len);
+ memcpy(bss->rates, elem->data, n_basic_rates);
+ got_basic_rates = 1;
break;
- case EXTRA_IE:
- lbs_deb_scan("process_bss: EXTRA_IE Found!\n");
- break;
-
- case FH_PARAM_SET:
- pFH = (struct ieeetypes_fhparamset *) pcurrentptr;
+ case MFIE_TYPE_FH_SET:
+ pFH = (struct ieeetypes_fhparamset *) pos;
memmove(&bss->phyparamset.fhparamset, pFH,
sizeof(struct ieeetypes_fhparamset));
#if 0 /* I think we can store these LE */
@@ -1055,21 +1045,21 @@ static int libertas_process_bss(struct bss_descriptor * bss,
#endif
break;
- case DS_PARAM_SET:
- pDS = (struct ieeetypes_dsparamset *) pcurrentptr;
+ case MFIE_TYPE_DS_SET:
+ pDS = (struct ieeetypes_dsparamset *) pos;
bss->channel = pDS->currentchan;
memcpy(&bss->phyparamset.dsparamset, pDS,
sizeof(struct ieeetypes_dsparamset));
break;
- case CF_PARAM_SET:
- pCF = (struct ieeetypes_cfparamset *) pcurrentptr;
+ case MFIE_TYPE_CF_SET:
+ pCF = (struct ieeetypes_cfparamset *) pos;
memcpy(&bss->ssparamset.cfparamset, pCF,
sizeof(struct ieeetypes_cfparamset));
break;
- case IBSS_PARAM_SET:
- pibss = (struct ieeetypes_ibssparamset *) pcurrentptr;
+ case MFIE_TYPE_IBSS_SET:
+ pibss = (struct ieeetypes_ibssparamset *) pos;
bss->atimwindow = le32_to_cpu(pibss->atimwindow);
memmove(&bss->ssparamset.ibssparamset, pibss,
sizeof(struct ieeetypes_ibssparamset));
@@ -1079,9 +1069,8 @@ static int libertas_process_bss(struct bss_descriptor * bss,
#endif
break;
- /* Handle Country Info IE */
- case COUNTRY_INFO:
- pcountryinfo = (struct ieeetypes_countryinfoset *) pcurrentptr;
+ case MFIE_TYPE_COUNTRY:
+ pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
|| pcountryinfo->len > 254) {
lbs_deb_scan("process_bss: 11D- Err "
@@ -1094,70 +1083,63 @@ static int libertas_process_bss(struct bss_descriptor * bss,
memcpy(&bss->countryinfo,
pcountryinfo, pcountryinfo->len + 2);
- lbs_dbg_hex("process_bss: 11D- CountryInfo:",
+ lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo",
(u8 *) pcountryinfo,
(u32) (pcountryinfo->len + 2));
break;
- case EXTENDED_SUPPORTED_RATES:
- /*
- * only process extended supported rate
- * if data rate is already found.
- * data rate IE should come before
+ case MFIE_TYPE_RATES_EX:
+ /* only process extended supported rate if data rate is
+ * already found. Data rate IE should come before
* extended supported rate IE
*/
- if (founddatarateie) {
- if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) {
- bytestocopy =
- (WLAN_SUPPORTED_RATES - ratesize);
- } else {
- bytestocopy = elemlen;
- }
-
- pRate = (u8 *) bss->datarates;
- pRate += ratesize;
- memmove(pRate, (pcurrentptr + 2), bytestocopy);
- pRate = (u8 *) bss->libertas_supported_rates;
- pRate += ratesize;
- memmove(pRate, (pcurrentptr + 2), bytestocopy);
- }
- break;
-
- case VENDOR_SPECIFIC_221:
-#define IE_ID_LEN_FIELDS_BYTES 2
- pIe = (struct IE_WPA *)pcurrentptr;
-
- if (memcmp(pIe->oui, oui01, sizeof(oui01)))
+ if (!got_basic_rates)
break;
- bss->wpa_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES,
- MAX_WPA_IE_LEN);
- memcpy(bss->wpa_ie, pcurrentptr, bss->wpa_ie_len);
- lbs_dbg_hex("process_bss: WPA IE", bss->wpa_ie, elemlen);
+ n_ex_rates = elem->len;
+ if (n_basic_rates + n_ex_rates > MAX_RATES)
+ n_ex_rates = MAX_RATES - n_basic_rates;
+
+ p = bss->rates + n_basic_rates;
+ memcpy(p, elem->data, n_ex_rates);
break;
- case WPA2_IE:
- pIe = (struct IE_WPA *)pcurrentptr;
- bss->rsn_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES,
- MAX_WPA_IE_LEN);
- memcpy(bss->rsn_ie, pcurrentptr, bss->rsn_ie_len);
- lbs_dbg_hex("process_bss: RSN_IE", bss->rsn_ie, elemlen);
+
+ case MFIE_TYPE_GENERIC:
+ if (elem->len >= 4 &&
+ elem->data[0] == 0x00 &&
+ elem->data[1] == 0x50 &&
+ elem->data[2] == 0xf2 &&
+ elem->data[3] == 0x01) {
+ bss->wpa_ie_len = min(elem->len + 2,
+ MAX_WPA_IE_LEN);
+ memcpy(bss->wpa_ie, elem, bss->wpa_ie_len);
+ lbs_deb_hex(LBS_DEB_SCAN, "process_bss: WPA IE", bss->wpa_ie,
+ elem->len);
+ } else if (elem->len >= MARVELL_MESH_IE_LENGTH &&
+ elem->data[0] == 0x00 &&
+ elem->data[1] == 0x50 &&
+ elem->data[2] == 0x43 &&
+ elem->data[3] == 0x04) {
+ bss->mesh = 1;
+ }
break;
- case TIM:
+
+ case MFIE_TYPE_RSN:
+ bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
+ memcpy(bss->rsn_ie, elem, bss->rsn_ie_len);
+ lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", bss->rsn_ie, elem->len);
break;
- case CHALLENGE_TEXT:
+ default:
break;
}
- pcurrentptr += elemlen + 2;
-
- /* need to account for IE ID and IE len */
- bytesleftforcurrentbeacon -= (elemlen + 2);
-
- } /* while (bytesleftforcurrentbeacon > 2) */
+ pos += elem->len + 2;
+ }
/* Timestamp */
bss->last_scanned = jiffies;
+ libertas_unset_basic_rate_flags(bss->rates, sizeof(bss->rates));
ret = 0;
@@ -1167,40 +1149,28 @@ done:
}
/**
- * @brief Compare two SSIDs
- *
- * @param ssid1 A pointer to ssid to compare
- * @param ssid2 A pointer to ssid to compare
- *
- * @return 0--ssid is same, otherwise is different
- */
-int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
-{
- if (ssid1_len != ssid2_len)
- return -1;
-
- return memcmp(ssid1, ssid2, ssid1_len);
-}
-
-/**
* @brief This function finds a specific compatible BSSID in the scan list
*
+ * Used in association code
+ *
* @param adapter A pointer to wlan_adapter
* @param bssid BSSID to find in the scan list
* @param mode Network mode: Infrastructure or IBSS
*
* @return index in BSSID list, or error return code (< 0)
*/
-struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
+struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter,
u8 * bssid, u8 mode)
{
struct bss_descriptor * iter_bss;
struct bss_descriptor * found_bss = NULL;
+ lbs_deb_enter(LBS_DEB_SCAN);
+
if (!bssid)
- return NULL;
+ goto out;
- lbs_dbg_hex("libertas_find_BSSID_in_list: looking for ",
+ lbs_deb_hex(LBS_DEB_SCAN, "looking for",
bssid, ETH_ALEN);
/* Look through the scan table for a compatible match. The loop will
@@ -1225,12 +1195,16 @@ struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
}
mutex_unlock(&adapter->lock);
+out:
+ lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
return found_bss;
}
/**
* @brief This function finds ssid in ssid list.
*
+ * Used in association code
+ *
* @param adapter A pointer to wlan_adapter
* @param ssid SSID to find in the list
* @param bssid BSSID to qualify the SSID selection (if provided)
@@ -1247,6 +1221,8 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
struct bss_descriptor * found_bss = NULL;
struct bss_descriptor * tmp_oldest = NULL;
+ lbs_deb_enter(LBS_DEB_SCAN);
+
mutex_lock(&adapter->lock);
list_for_each_entry (iter_bss, &adapter->network_list, list) {
@@ -1291,6 +1267,7 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
out:
mutex_unlock(&adapter->lock);
+ lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
return found_bss;
}
@@ -1304,13 +1281,15 @@ out:
*
* @return index in BSSID list
*/
-struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
+static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
u8 mode)
{
u8 bestrssi = 0;
struct bss_descriptor * iter_bss;
struct bss_descriptor * best_bss = NULL;
+ lbs_deb_enter(LBS_DEB_SCAN);
+
mutex_lock(&adapter->lock);
list_for_each_entry (iter_bss, &adapter->network_list, list) {
@@ -1335,12 +1314,15 @@ struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
}
mutex_unlock(&adapter->lock);
+ lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss);
return best_bss;
}
/**
* @brief Find the AP with specific ssid in the scan list
*
+ * Used from association worker.
+ *
* @param priv A pointer to wlan_private structure
* @param pSSID A pointer to AP's ssid
*
@@ -1353,11 +1335,11 @@ int libertas_find_best_network_ssid(wlan_private * priv,
int ret = -1;
struct bss_descriptor * found;
- lbs_deb_enter(LBS_DEB_ASSOC);
+ lbs_deb_enter(LBS_DEB_SCAN);
wlan_scan_networks(priv, NULL, 1);
if (adapter->surpriseremoved)
- return -1;
+ goto out;
wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
@@ -1369,6 +1351,7 @@ int libertas_find_best_network_ssid(wlan_private * priv,
ret = 0;
}
+out:
lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
return ret;
}
@@ -1391,7 +1374,10 @@ int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_SCAN);
- wlan_scan_networks(priv, NULL, 0);
+ if (!delayed_work_pending(&priv->scan_work)) {
+ queue_delayed_work(priv->work_thread, &priv->scan_work,
+ msecs_to_jiffies(50));
+ }
if (adapter->surpriseremoved)
return -1;
@@ -1400,10 +1386,17 @@ int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
return 0;
}
+
/**
* @brief Send a scan command for all available channels filtered on a spec
*
+ * Used in association code and from debugfs
+ *
* @param priv A pointer to wlan_private structure
+ * @param ssid A pointer to the SSID to scan for
+ * @param ssid_len Length of the SSID
+ * @param clear_ssid Should existing scan results with this SSID
+ * be cleared?
* @param prequestedssid A pointer to AP's ssid
* @param keeppreviousscan Flag used to save/clear scan table before scan
*
@@ -1416,7 +1409,8 @@ int libertas_send_specific_ssid_scan(wlan_private * priv,
struct wlan_ioctl_user_scan_cfg scancfg;
int ret = 0;
- lbs_deb_enter(LBS_DEB_ASSOC);
+ lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d",
+ escape_essid(ssid, ssid_len), clear_ssid);
if (!ssid_len)
goto out;
@@ -1427,47 +1421,27 @@ int libertas_send_specific_ssid_scan(wlan_private * priv,
scancfg.clear_ssid = clear_ssid;
wlan_scan_networks(priv, &scancfg, 1);
- if (adapter->surpriseremoved)
- return -1;
+ if (adapter->surpriseremoved) {
+ ret = -1;
+ goto out;
+ }
wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
out:
- lbs_deb_leave(LBS_DEB_ASSOC);
+ lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
return ret;
}
-/**
- * @brief scan an AP with specific BSSID
- *
- * @param priv A pointer to wlan_private structure
- * @param bssid A pointer to AP's bssid
- * @param keeppreviousscan Flag used to save/clear scan table before scan
- *
- * @return 0-success, otherwise fail
- */
-int libertas_send_specific_bssid_scan(wlan_private * priv, u8 * bssid, u8 clear_bssid)
-{
- struct wlan_ioctl_user_scan_cfg scancfg;
-
- lbs_deb_enter(LBS_DEB_ASSOC);
- if (bssid == NULL)
- goto out;
- memset(&scancfg, 0x00, sizeof(scancfg));
- memcpy(scancfg.bssid, bssid, ETH_ALEN);
- scancfg.clear_bssid = clear_bssid;
- wlan_scan_networks(priv, &scancfg, 1);
- if (priv->adapter->surpriseremoved)
- return -1;
- wait_event_interruptible(priv->adapter->cmd_pending,
- !priv->adapter->nr_cmd_pending);
+/*********************************************************************/
+/* */
+/* Support for Wireless Extensions */
+/* */
+/*********************************************************************/
-out:
- lbs_deb_leave(LBS_DEB_ASSOC);
- return 0;
-}
+#define MAX_CUSTOM_LEN 64
static inline char *libertas_translate_scan(wlan_private *priv,
char *start, char *stop,
@@ -1483,10 +1457,13 @@ static inline char *libertas_translate_scan(wlan_private *priv,
#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI))
u8 rssi;
+ lbs_deb_enter(LBS_DEB_SCAN);
+
cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, bss->channel);
if (!cfp) {
lbs_deb_scan("Invalid channel number %d\n", bss->channel);
- return NULL;
+ start = NULL;
+ goto out;
}
/* First entry *MUST* be the AP BSSID */
@@ -1550,7 +1527,7 @@ static inline char *libertas_translate_scan(wlan_private *priv,
/* Add encryption capability */
iwe.cmd = SIOCGIWENCODE;
- if (bss->privacy) {
+ if (bss->capability & WLAN_CAPABILITY_PRIVACY) {
iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
} else {
iwe.u.data.flags = IW_ENCODE_DISABLED;
@@ -1565,12 +1542,9 @@ static inline char *libertas_translate_scan(wlan_private *priv,
iwe.u.bitrate.disabled = 0;
iwe.u.bitrate.value = 0;
- for (j = 0; j < sizeof(bss->libertas_supported_rates); j++) {
- u8 rate = bss->libertas_supported_rates[j];
- if (rate == 0)
- break; /* no more rates */
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value = (rate & 0x7f) * 500000;
+ for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
+ /* Bit rate given in 500 kb/s units */
+ iwe.u.bitrate.value = bss->rates[j] * 500000;
current_val = iwe_stream_add_value(start, current_val,
stop, &iwe, IW_EV_PARAM_LEN);
}
@@ -1605,11 +1579,25 @@ static inline char *libertas_translate_scan(wlan_private *priv,
start = iwe_stream_add_point(start, stop, &iwe, buf);
}
+ if (bss->mesh) {
+ char custom[MAX_CUSTOM_LEN];
+ char *p = custom;
+
+ iwe.cmd = IWEVCUSTOM;
+ p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+ "mesh-type: olpc");
+ iwe.u.data.length = p - custom;
+ if (iwe.u.data.length)
+ start = iwe_stream_add_point(start, stop, &iwe, custom);
+ }
+
+out:
+ lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start);
return start;
}
/**
- * @brief Retrieve the scan table entries via wireless tools IOCTL call
+ * @brief Handle Retrieve scan table ioctl
*
* @param dev A pointer to net_device structure
* @param info A pointer to iw_request_info structure
@@ -1630,16 +1618,12 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
struct bss_descriptor * iter_bss;
struct bss_descriptor * safe;
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- /* If we've got an uncompleted scan, schedule the next part */
- if (!adapter->nr_cmd_pending && adapter->last_scanned_channel)
- wlan_scan_networks(priv, NULL, 0);
+ lbs_deb_enter(LBS_DEB_SCAN);
/* Update RSSI if current BSS is a locally created ad-hoc BSS */
if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) {
- libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
- cmd_option_waitforrsp, 0, NULL);
+ libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
}
mutex_lock(&adapter->lock);
@@ -1652,6 +1636,10 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
break;
}
+ /* For mesh device, list only mesh networks */
+ if (dev == priv->mesh_dev && !iter_bss->mesh)
+ continue;
+
/* Prune old an old scan result */
stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
if (time_after(jiffies, stale_time)) {
@@ -1672,19 +1660,27 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
dwrq->length = (ev - extra);
dwrq->flags = 0;
- lbs_deb_leave(LBS_DEB_ASSOC);
+ lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", err);
return err;
}
+
+
+
+/*********************************************************************/
+/* */
+/* Command execution */
+/* */
+/*********************************************************************/
+
+
/**
* @brief Prepare a scan command to be sent to the firmware
*
- * Use the wlan_scan_cmd_config sent to the command processing module in
- * the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command
- * struct to send to firmware.
+ * Called from libertas_prepare_and_send_command() in cmd.c
*
- * The fixed fields specifying the BSS type and BSSID filters as well as a
- * variable number/length of TLVs are sent in the command to firmware.
+ * Sends a fixed lenght data part (specifying the BSS type and BSSID filters)
+ * as well as a variable number/length of TLVs to the firmware.
*
* @param priv A pointer to wlan_private structure
* @param cmd A pointer to cmd_ds_command structure to be sent to
@@ -1693,36 +1689,31 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
* to set the fields/TLVs for the command sent to firmware
*
* @return 0 or -1
- *
- * @sa wlan_scan_create_channel_list
*/
int libertas_cmd_80211_scan(wlan_private * priv,
struct cmd_ds_command *cmd, void *pdata_buf)
{
struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
- struct wlan_scan_cmd_config *pscancfg;
+ struct wlan_scan_cmd_config *pscancfg = pdata_buf;
- lbs_deb_enter(LBS_DEB_ASSOC);
-
- pscancfg = pdata_buf;
+ lbs_deb_enter(LBS_DEB_SCAN);
/* Set fixed field variables in scan command */
pscan->bsstype = pscancfg->bsstype;
- memcpy(pscan->BSSID, pscancfg->bssid, sizeof(pscan->BSSID));
+ memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN);
memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
- cmd->command = cpu_to_le16(cmd_802_11_scan);
+ cmd->command = cpu_to_le16(CMD_802_11_SCAN);
/* size is equal to the sizeof(fixed portions) + the TLV len + header */
- cmd->size = cpu_to_le16(sizeof(pscan->bsstype)
- + sizeof(pscan->BSSID)
- + pscancfg->tlvbufferlen + S_DS_GEN);
+ cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN
+ + pscancfg->tlvbufferlen + S_DS_GEN);
- lbs_deb_scan("SCAN_CMD: command=%x, size=%x, seqnum=%x\n",
+ lbs_deb_scan("SCAN_CMD: command 0x%04x, size %d, seqnum %d\n",
le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
le16_to_cpu(cmd->seqnum));
- lbs_deb_leave(LBS_DEB_ASSOC);
+ lbs_deb_leave(LBS_DEB_SCAN);
return 0;
}
@@ -1741,6 +1732,8 @@ static inline int is_same_network(struct bss_descriptor *src,
/**
* @brief This function handles the command response of scan
*
+ * Called from handle_cmd_response() in cmdrespc.
+ *
* The response buffer for the scan command has the following
* memory layout:
*
@@ -1766,8 +1759,6 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
{
wlan_adapter *adapter = priv->adapter;
struct cmd_ds_802_11_scan_rsp *pscan;
- struct mrvlietypes_data *ptlv;
- struct mrvlietypes_tsftimestamp *ptsftlv;
struct bss_descriptor * iter_bss;
struct bss_descriptor * safe;
u8 *pbssinfo;
@@ -1777,7 +1768,7 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
int tlvbufsize;
int ret;
- lbs_deb_enter(LBS_DEB_ASSOC);
+ lbs_deb_enter(LBS_DEB_SCAN);
/* Prune old entries from scan table */
list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) {
@@ -1798,10 +1789,10 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
goto done;
}
- bytesleft = le16_to_cpu(pscan->bssdescriptsize);
+ bytesleft = le16_to_cpu(get_unaligned((u16*)&pscan->bssdescriptsize));
lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
- scanrespsize = le16_to_cpu(resp->size);
+ scanrespsize = le16_to_cpu(get_unaligned((u16*)&resp->size));
lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n",
pscan->nr_sets);
@@ -1816,11 +1807,6 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
+ sizeof(pscan->nr_sets)
+ S_DS_GEN);
- ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft);
-
- /* Search the TLV buffer space in the scan response for any valid TLVs */
- wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv);
-
/*
* Process each scan response returned (pscan->nr_sets). Save
* the information in the newbssentry and then insert into the
@@ -1831,6 +1817,7 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
struct bss_descriptor new;
struct bss_descriptor * found = NULL;
struct bss_descriptor * oldest = NULL;
+ DECLARE_MAC_BUF(mac);
/* Process the data fields and IEs returned for this BSS */
memset(&new, 0, sizeof (struct bss_descriptor));
@@ -1869,19 +1856,8 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
continue;
}
- lbs_deb_scan("SCAN_RESP: BSSID = " MAC_FMT "\n",
- new.bssid[0], new.bssid[1], new.bssid[2],
- new.bssid[3], new.bssid[4], new.bssid[5]);
-
- /*
- * If the TSF TLV was appended to the scan results, save the
- * this entries TSF value in the networktsf field. The
- * networktsf is the firmware's TSF value at the time the
- * beacon or probe response was received.
- */
- if (ptsftlv) {
- new.networktsf = le64_to_cpup(&ptsftlv->tsftable[idx]);
- }
+ lbs_deb_scan("SCAN_RESP: BSSID = %s\n",
+ print_mac(mac, new.bssid));
/* Copy the locally created newbssentry to the scan table */
memcpy(found, &new, offsetof(struct bss_descriptor, list));
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
index bd019e5ff1e..c29c031bef8 100644
--- a/drivers/net/wireless/libertas/scan.h
+++ b/drivers/net/wireless/libertas/scan.h
@@ -140,8 +140,7 @@ struct bss_descriptor {
u8 ssid[IW_ESSID_MAX_SIZE + 1];
u8 ssid_len;
- /* WEP encryption requirement */
- u32 privacy;
+ u16 capability;
/* receive signal strength in dBm */
long rssi;
@@ -152,18 +151,16 @@ struct bss_descriptor {
u32 atimwindow;
+ /* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
u8 mode;
- u8 libertas_supported_rates[WLAN_SUPPORTED_RATES];
- __le64 timestamp; //!< TSF value included in the beacon/probe response
+ /* zero-terminated array of supported data rates */
+ u8 rates[MAX_RATES + 1];
+
unsigned long last_scanned;
union ieeetypes_phyparamset phyparamset;
union IEEEtypes_ssparamset ssparamset;
- struct ieeetypes_capinfo cap;
- u8 datarates[WLAN_SUPPORTED_RATES];
-
- u64 networktsf; //!< TSF timestamp from the current firmware TSF
struct ieeetypes_countryinfofullset countryinfo;
@@ -172,34 +169,31 @@ struct bss_descriptor {
u8 rsn_ie[MAX_WPA_IE_LEN];
size_t rsn_ie_len;
+ u8 mesh;
+
struct list_head list;
};
-extern int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
+int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode,
int channel);
-struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
- u8 mode);
-
-extern struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
+struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
u8 * bssid, u8 mode);
int libertas_find_best_network_ssid(wlan_private * priv, u8 *out_ssid,
u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode);
-extern int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid,
+int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid,
u8 ssid_len, u8 clear_ssid);
-extern int libertas_send_specific_bssid_scan(wlan_private * priv,
- u8 * bssid, u8 clear_bssid);
-extern int libertas_cmd_80211_scan(wlan_private * priv,
+int libertas_cmd_80211_scan(wlan_private * priv,
struct cmd_ds_command *cmd,
void *pdata_buf);
-extern int libertas_ret_80211_scan(wlan_private * priv,
+int libertas_ret_80211_scan(wlan_private * priv,
struct cmd_ds_command *resp);
int wlan_scan_networks(wlan_private * priv,
@@ -211,9 +205,11 @@ struct ifreq;
struct iw_point;
struct iw_param;
struct iw_request_info;
-extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
+int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra);
-extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
+int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra);
+void libertas_scan_worker(struct work_struct *work);
+
#endif /* _WLAN_SCAN_H */
diff --git a/drivers/net/wireless/libertas/thread.h b/drivers/net/wireless/libertas/thread.h
deleted file mode 100644
index b1f34d92ff3..00000000000
--- a/drivers/net/wireless/libertas/thread.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef __WLAN_THREAD_H_
-#define __WLAN_THREAD_H_
-
-#include <linux/kthread.h>
-
-struct wlan_thread {
- struct task_struct *task;
- wait_queue_head_t waitq;
- pid_t pid;
- void *priv;
-};
-
-static inline void wlan_activate_thread(struct wlan_thread * thr)
-{
- /** Record the thread pid */
- thr->pid = current->pid;
-
- /** Initialize the wait queue */
- init_waitqueue_head(&thr->waitq);
-}
-
-static inline void wlan_deactivate_thread(struct wlan_thread * thr)
-{
- lbs_deb_enter(LBS_DEB_THREAD);
-
- thr->pid = 0;
-
- lbs_deb_leave(LBS_DEB_THREAD);
-}
-
-static inline void wlan_create_thread(int (*wlanfunc) (void *),
- struct wlan_thread * thr, char *name)
-{
- thr->task = kthread_run(wlanfunc, thr, "%s", name);
-}
-
-static inline int wlan_terminate_thread(struct wlan_thread * thr)
-{
- lbs_deb_enter(LBS_DEB_THREAD);
-
- /* Check if the thread is active or not */
- if (!thr->pid) {
- printk(KERN_ERR "Thread does not exist\n");
- return -1;
- }
- kthread_stop(thr->task);
-
- lbs_deb_leave(LBS_DEB_THREAD);
- return 0;
-}
-
-#endif
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index 17c437635a0..fbec06c10dd 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -58,7 +58,6 @@ static u32 convert_radiotap_rate_to_mv(u8 rate)
*/
static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
{
- wlan_adapter *adapter = priv->adapter;
int ret = 0;
struct txpd localtxpd;
struct txpd *plocaltxpd = &localtxpd;
@@ -72,10 +71,6 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
if (priv->adapter->surpriseremoved)
return -1;
- if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
- lbs_dbg_hex("TX packet: ", skb->data,
- min_t(unsigned int, skb->len, 100));
-
if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
lbs_deb_tx("tx err: skb length %d 0 or > %zd\n",
skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
@@ -90,11 +85,8 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
/* offset of actual data */
plocaltxpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
- /* TxCtrl set by user or default */
- plocaltxpd->tx_control = cpu_to_le32(adapter->pkttxctrl);
-
p802x_hdr = skb->data;
- if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+ if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
/* locate radiotap header */
pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data;
@@ -103,7 +95,6 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate);
if (new_rate != 0) {
/* use new tx_control[4:0] */
- new_rate |= (adapter->pkttxctrl & ~0x1f);
plocaltxpd->tx_control = cpu_to_le32(new_rate);
}
@@ -115,12 +106,12 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
}
/* copy destination address from 802.3 or 802.11 header */
- if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+ if (priv->adapter->monitormode != WLAN_MONITOR_OFF)
memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
else
memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
- lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
+ lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
if (IS_MESH_FRAME(skb)) {
plocaltxpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
@@ -130,7 +121,7 @@ static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
ptr += sizeof(struct txpd);
- lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
+ lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
memcpy(ptr, p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
ret = priv->hw_host_to_card(priv, MVMS_DAT,
priv->adapter->tmptxbuf,
@@ -153,13 +144,14 @@ done:
priv->stats.tx_errors++;
}
- if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+ if (!ret && priv->adapter->monitormode != WLAN_MONITOR_OFF) {
/* Keep the skb to echo it back once Tx feedback is
received from FW */
skb_orphan(skb);
/* stop processing outgoing pkts */
netif_stop_queue(priv->dev);
- netif_stop_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_stop_queue(priv->mesh_dev);
/* freeze any packets already in our queues */
priv->adapter->TxLockFlag = 1;
} else {
@@ -198,10 +190,12 @@ static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb)
adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb;
if (adapter->tx_queue_idx == NR_TX_QUEUE) {
netif_stop_queue(priv->dev);
- netif_stop_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_stop_queue(priv->mesh_dev);
} else {
netif_start_queue(priv->dev);
- netif_start_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_start_queue(priv->mesh_dev);
}
spin_unlock(&adapter->txqueue_lock);
@@ -219,7 +213,7 @@ int libertas_process_tx(wlan_private * priv, struct sk_buff *skb)
int ret = -1;
lbs_deb_enter(LBS_DEB_TX);
- lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100));
+ lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
if (priv->dnld_sent) {
lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n",
@@ -258,16 +252,12 @@ void libertas_send_tx_feedback(wlan_private * priv)
int txfail;
int try_count;
- if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP ||
+ if (adapter->monitormode == WLAN_MONITOR_OFF ||
adapter->currenttxskb == NULL)
return;
radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data;
- if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
- lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr,
- min_t(unsigned int, adapter->currenttxskb->len, 100));
-
txfail = (status >> 24);
#if 0
@@ -283,9 +273,10 @@ void libertas_send_tx_feedback(wlan_private * priv)
libertas_upload_rx_packet(priv, adapter->currenttxskb);
adapter->currenttxskb = NULL;
priv->adapter->TxLockFlag = 0;
- if (priv->adapter->connect_status == libertas_connected) {
+ if (priv->adapter->connect_status == LIBERTAS_CONNECTED) {
netif_wake_queue(priv->dev);
- netif_wake_queue(priv->mesh_dev);
+ if (priv->mesh_dev)
+ netif_wake_queue(priv->mesh_dev);
}
}
EXPORT_SYMBOL_GPL(libertas_send_tx_feedback);
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 028e2f3b53d..a43a5f63c87 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -7,71 +7,6 @@
#include <linux/if_ether.h>
#include <asm/byteorder.h>
-/** IEEE type definitions */
-enum ieeetypes_elementid {
- SSID = 0,
- SUPPORTED_RATES,
- FH_PARAM_SET,
- DS_PARAM_SET,
- CF_PARAM_SET,
- TIM,
- IBSS_PARAM_SET,
- COUNTRY_INFO = 7,
-
- CHALLENGE_TEXT = 16,
-
- EXTENDED_SUPPORTED_RATES = 50,
-
- VENDOR_SPECIFIC_221 = 221,
-
- WPA_IE = 221,
- WPA2_IE = 48,
-
- EXTRA_IE = 133,
-} __attribute__ ((packed));
-
-#ifdef __BIG_ENDIAN
-#define CAPINFO_MASK (~(0xda00))
-#else
-#define CAPINFO_MASK (~(0x00da))
-#endif
-
-struct ieeetypes_capinfo {
-#ifdef __BIG_ENDIAN_BITFIELD
- u8 chanagility:1;
- u8 pbcc:1;
- u8 shortpreamble:1;
- u8 privacy:1;
- u8 cfpollrqst:1;
- u8 cfpollable:1;
- u8 ibss:1;
- u8 ess:1;
- u8 rsrvd1:2;
- u8 dsssofdm:1;
- u8 rsvrd2:1;
- u8 apsd:1;
- u8 shortslottime:1;
- u8 rsrvd3:1;
- u8 spectrummgmt:1;
-#else
- u8 ess:1;
- u8 ibss:1;
- u8 cfpollable:1;
- u8 cfpollrqst:1;
- u8 privacy:1;
- u8 shortpreamble:1;
- u8 pbcc:1;
- u8 chanagility:1;
- u8 spectrummgmt:1;
- u8 rsrvd3:1;
- u8 shortslottime:1;
- u8 apsd:1;
- u8 rsvrd2:1;
- u8 dsssofdm:1;
- u8 rsrvd1:2;
-#endif
-} __attribute__ ((packed));
-
struct ieeetypes_cfparamset {
u8 elementid;
u8 len;
@@ -114,7 +49,7 @@ union ieeetypes_phyparamset {
} __attribute__ ((packed));
struct ieeetypes_assocrsp {
- struct ieeetypes_capinfo capability;
+ __le16 capability;
__le16 statuscode;
__le16 aid;
u8 iebuffer[1];
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 2fcc3bf2108..c6f5aa3cb46 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -22,60 +22,6 @@
/**
- * the rates supported by the card
- */
-static u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
- { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
- 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
-};
-
-/**
- * @brief Convert mw value to dbm value
- *
- * @param mw the value of mw
- * @return the value of dbm
- */
-static int mw_to_dbm(int mw)
-{
- if (mw < 2)
- return 0;
- else if (mw < 3)
- return 3;
- else if (mw < 4)
- return 5;
- else if (mw < 6)
- return 7;
- else if (mw < 7)
- return 8;
- else if (mw < 8)
- return 9;
- else if (mw < 10)
- return 10;
- else if (mw < 13)
- return 11;
- else if (mw < 16)
- return 12;
- else if (mw < 20)
- return 13;
- else if (mw < 25)
- return 14;
- else if (mw < 32)
- return 15;
- else if (mw < 40)
- return 16;
- else if (mw < 50)
- return 17;
- else if (mw < 63)
- return 18;
- else if (mw < 79)
- return 19;
- else if (mw < 100)
- return 20;
- else
- return 21;
-}
-
-/**
* @brief Find the channel frequency power info with specific channel
*
* @param adapter A pointer to wlan_adapter structure
@@ -165,7 +111,7 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
* @option Radio Option
* @return 0 --success, otherwise fail
*/
-int wlan_radio_ioctl(wlan_private * priv, u8 option)
+static int wlan_radio_ioctl(wlan_private * priv, u8 option)
{
int ret = 0;
wlan_adapter *adapter = priv->adapter;
@@ -177,9 +123,9 @@ int wlan_radio_ioctl(wlan_private * priv, u8 option)
adapter->radioon = option;
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_radio_control,
- cmd_act_set,
- cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_RADIO_CONTROL,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
}
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -187,84 +133,31 @@ int wlan_radio_ioctl(wlan_private * priv, u8 option)
}
/**
- * @brief Copy rates
- *
- * @param dest A pointer to Dest Buf
- * @param src A pointer to Src Buf
- * @param len The len of Src Buf
- * @return Number of rates copyed
- */
-static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
-{
- int i;
-
- for (i = 0; i < len && src[i]; i++, pos++) {
- if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
- break;
- dest[pos] = src[i];
- }
-
- return pos;
-}
-
-/**
- * @brief Get active data rates
+ * @brief Copy active data rates based on adapter mode and status
*
* @param adapter A pointer to wlan_adapter structure
* @param rate The buf to return the active rates
- * @return The number of rates
*/
-static int get_active_data_rates(wlan_adapter * adapter,
- u8* rates)
+static void copy_active_data_rates(wlan_adapter * adapter, u8 * rates)
{
- int k = 0;
-
lbs_deb_enter(LBS_DEB_WEXT);
- if (adapter->connect_status != libertas_connected) {
- if (adapter->mode == IW_MODE_INFRA) {
- lbs_deb_wext("infra\n");
- k = copyrates(rates, k, libertas_supported_rates,
- sizeof(libertas_supported_rates));
- } else {
- lbs_deb_wext("Adhoc G\n");
- k = copyrates(rates, k, libertas_adhoc_rates_g,
- sizeof(libertas_adhoc_rates_g));
- }
- } else {
- k = copyrates(rates, 0, adapter->curbssparams.datarates,
- adapter->curbssparams.numofrates);
- }
+ if (adapter->connect_status != LIBERTAS_CONNECTED)
+ memcpy(rates, libertas_bg_rates, MAX_RATES);
+ else
+ memcpy(rates, adapter->curbssparams.rates, MAX_RATES);
- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", k);
- return k;
+ lbs_deb_leave(LBS_DEB_WEXT);
}
static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
char *cwrq, char *extra)
{
- const char *cp;
- char comm[6] = { "COMM-" };
- char mrvl[6] = { "MRVL-" };
- int cnt;
lbs_deb_enter(LBS_DEB_WEXT);
- strcpy(cwrq, mrvl);
-
- cp = strstr(libertas_driver_version, comm);
- if (cp == libertas_driver_version) //skip leading "COMM-"
- cp = libertas_driver_version + strlen(comm);
- else
- cp = libertas_driver_version;
-
- cnt = strlen(mrvl);
- cwrq += cnt;
- while (cnt < 16 && (*cp != '-')) {
- *cwrq++ = toupper(*cp++);
- cnt++;
- }
- *cwrq = '\0';
+ /* We could add support for 802.11n here as needed. Jean II */
+ snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g");
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
@@ -305,7 +198,7 @@ static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
- if (adapter->connect_status == libertas_connected) {
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
} else {
memset(awrq->sa_data, 0, ETH_ALEN);
@@ -349,24 +242,11 @@ static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
- /*
- * Get the Nick Name saved
- */
-
- mutex_lock(&adapter->lock);
- strncpy(extra, adapter->nodename, 16);
- mutex_unlock(&adapter->lock);
-
- extra[16] = '\0';
+ dwrq->length = strlen(adapter->nodename);
+ memcpy(extra, adapter->nodename, dwrq->length);
+ extra[dwrq->length] = '\0';
- /*
- * If none, we may want to get the one that was set
- */
-
- /*
- * Push it out !
- */
- dwrq->length = strlen(extra) + 1;
+ dwrq->flags = 1; /* active */
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
@@ -382,20 +262,21 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
/* Use nickname to indicate that mesh is on */
- if (adapter->connect_status == libertas_connected) {
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
strncpy(extra, "Mesh", 12);
extra[12] = '\0';
- dwrq->length = strlen(extra) + 1;
+ dwrq->length = strlen(extra);
}
else {
extra[0] = '\0';
- dwrq->length = 1 ;
+ dwrq->length = 0;
}
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
}
+
static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
@@ -414,8 +295,8 @@ static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
adapter->rtsthsd = rthr;
}
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
- cmd_act_set, cmd_option_waitforrsp,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+ CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
OID_802_11_RTS_THRESHOLD, &rthr);
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -432,8 +313,8 @@ static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
adapter->rtsthsd = 0;
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
- cmd_act_get, cmd_option_waitforrsp,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+ CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
OID_802_11_RTS_THRESHOLD, NULL);
if (ret)
goto out;
@@ -467,8 +348,8 @@ static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
adapter->fragthsd = fthr;
}
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
- cmd_act_set, cmd_option_waitforrsp,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+ CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -486,8 +367,8 @@ static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
adapter->fragthsd = 0;
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_snmp_mib,
- cmd_act_get, cmd_option_waitforrsp,
+ CMD_802_11_SNMP_MIB,
+ CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
if (ret)
goto out;
@@ -539,9 +420,9 @@ static int wlan_get_txpow(struct net_device *dev,
lbs_deb_enter(LBS_DEB_WEXT);
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_rf_tx_power,
- cmd_act_tx_power_opt_get,
- cmd_option_waitforrsp, 0, NULL);
+ CMD_802_11_RF_TX_POWER,
+ CMD_ACT_TX_POWER_OPT_GET,
+ CMD_OPTION_WAITFORRSP, 0, NULL);
if (ret)
goto out;
@@ -581,9 +462,9 @@ static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
/* Adding 1 to convert retry count to try count */
adapter->txretrycount = vwrq->value + 1;
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
- cmd_act_set,
- cmd_option_waitforrsp,
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+ CMD_ACT_SET,
+ CMD_OPTION_WAITFORRSP,
OID_802_11_TX_RETRYCOUNT, NULL);
if (ret)
@@ -608,8 +489,8 @@ static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
adapter->txretrycount = 0;
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_snmp_mib,
- cmd_act_get, cmd_option_waitforrsp,
+ CMD_802_11_SNMP_MIB,
+ CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
OID_802_11_TX_RETRYCOUNT, NULL);
if (ret)
goto out;
@@ -673,7 +554,7 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
wlan_adapter *adapter = priv->adapter;
struct iw_range *range = (struct iw_range *)extra;
struct chan_freq_power *cfp;
- u8 rates[WLAN_SUPPORTED_RATES];
+ u8 rates[MAX_RATES + 1];
u8 flag = 0;
@@ -686,19 +567,17 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
range->max_nwid = 0;
memset(rates, 0, sizeof(rates));
- range->num_bitrates = get_active_data_rates(adapter, rates);
-
- for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
- i++) {
- range->bitrate[i] = (rates[i] & 0x7f) * 500000;
- }
+ copy_active_data_rates(adapter, rates);
+ range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);
+ for (i = 0; i < range->num_bitrates; i++)
+ range->bitrate[i] = rates[i] * 500000;
range->num_bitrates = i;
lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
range->num_bitrates);
range->num_frequency = 0;
if (priv->adapter->enable11d &&
- adapter->connect_status == libertas_connected) {
+ adapter->connect_status == LIBERTAS_CONNECTED) {
u8 chan_no;
u8 band;
@@ -858,9 +737,9 @@ static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
*/
if (vwrq->disabled) {
- adapter->psmode = wlan802_11powermodecam;
+ adapter->psmode = WLAN802_11POWERMODECAM;
if (adapter->psstate != PS_STATE_FULL_POWER) {
- libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+ libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
}
return 0;
@@ -875,14 +754,14 @@ static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
return -EINVAL;
}
- if (adapter->psmode != wlan802_11powermodecam) {
+ if (adapter->psmode != WLAN802_11POWERMODECAM) {
return 0;
}
- adapter->psmode = wlan802_11powermodemax_psp;
+ adapter->psmode = WLAN802_11POWERMODEMAX_PSP;
- if (adapter->connect_status == libertas_connected) {
- libertas_ps_sleep(priv, cmd_option_waitforrsp);
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
+ libertas_ps_sleep(priv, CMD_OPTION_WAITFORRSP);
}
lbs_deb_leave(LBS_DEB_WEXT);
@@ -900,8 +779,8 @@ static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
mode = adapter->psmode;
- if ((vwrq->disabled = (mode == wlan802_11powermodecam))
- || adapter->connect_status == libertas_disconnected)
+ if ((vwrq->disabled = (mode == WLAN802_11POWERMODECAM))
+ || adapter->connect_status == LIBERTAS_DISCONNECTED)
{
goto out;
}
@@ -937,7 +816,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
priv->wstats.status = adapter->mode;
/* If we're not associated, all quality values are meaningless */
- if (adapter->connect_status != libertas_connected)
+ if (adapter->connect_status != LIBERTAS_CONNECTED)
goto out;
/* Quality by RSSI */
@@ -973,7 +852,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
/* Quality by TX errors */
priv->wstats.discard.retries = priv->stats.tx_errors;
- tx_retries = le16_to_cpu(adapter->logmsg.retry);
+ tx_retries = le32_to_cpu(adapter->logmsg.retry);
if (tx_retries > 75)
tx_qual = (90 - tx_retries) * POOR / 15;
@@ -989,20 +868,20 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
(PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
quality = min(quality, tx_qual);
- priv->wstats.discard.code = le16_to_cpu(adapter->logmsg.wepundecryptable);
- priv->wstats.discard.fragment = le16_to_cpu(adapter->logmsg.rxfrag);
+ priv->wstats.discard.code = le32_to_cpu(adapter->logmsg.wepundecryptable);
+ priv->wstats.discard.fragment = le32_to_cpu(adapter->logmsg.rxfrag);
priv->wstats.discard.retries = tx_retries;
- priv->wstats.discard.misc = le16_to_cpu(adapter->logmsg.ackfailure);
+ priv->wstats.discard.misc = le32_to_cpu(adapter->logmsg.ackfailure);
/* Calculate quality */
- priv->wstats.qual.qual = max(quality, (u32)100);
+ priv->wstats.qual.qual = min_t(u8, quality, 100);
priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
stats_valid = 1;
/* update stats asynchronously for future calls */
- libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
+ libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
0, 0, NULL);
- libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
+ libertas_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0,
0, 0, NULL);
out:
if (!stats_valid) {
@@ -1080,88 +959,46 @@ out:
return ret;
}
-/**
- * @brief use index to get the data rate
- *
- * @param index The index of data rate
- * @return data rate or 0
- */
-u32 libertas_index_to_data_rate(u8 index)
-{
- if (index >= sizeof(libertas_wlan_data_rates))
- index = 0;
-
- return libertas_wlan_data_rates[index];
-}
-
-/**
- * @brief use rate to get the index
- *
- * @param rate data rate
- * @return index or 0
- */
-u8 libertas_data_rate_to_index(u32 rate)
-{
- u8 *ptr;
-
- if (rate)
- if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
- sizeof(libertas_wlan_data_rates))))
- return (ptr - libertas_wlan_data_rates);
-
- return 0;
-}
-
static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
wlan_private *priv = dev->priv;
wlan_adapter *adapter = priv->adapter;
- u32 data_rate;
+ u32 new_rate;
u16 action;
- int ret = 0;
- u8 rates[WLAN_SUPPORTED_RATES];
- u8 *rate;
+ int ret = -EINVAL;
+ u8 rates[MAX_RATES + 1];
lbs_deb_enter(LBS_DEB_WEXT);
-
lbs_deb_wext("vwrq->value %d\n", vwrq->value);
+ /* Auto rate? */
if (vwrq->value == -1) {
- action = cmd_act_set_tx_auto; // Auto
- adapter->is_datarate_auto = 1;
- adapter->datarate = 0;
+ action = CMD_ACT_SET_TX_AUTO;
+ adapter->auto_rate = 1;
+ adapter->cur_rate = 0;
} else {
- if (vwrq->value % 100000) {
- return -EINVAL;
- }
-
- data_rate = vwrq->value / 500000;
+ if (vwrq->value % 100000)
+ goto out;
memset(rates, 0, sizeof(rates));
- get_active_data_rates(adapter, rates);
- rate = rates;
- while (*rate) {
- lbs_deb_wext("rate=0x%X, wanted data_rate 0x%X\n", *rate,
- data_rate);
- if ((*rate & 0x7f) == (data_rate & 0x7f))
- break;
- rate++;
- }
- if (!*rate) {
- lbs_pr_alert("fixed data rate 0x%X out "
- "of range\n", data_rate);
- return -EINVAL;
+ copy_active_data_rates(adapter, rates);
+ new_rate = vwrq->value / 500000;
+ if (!memchr(rates, new_rate, sizeof(rates))) {
+ lbs_pr_alert("fixed data rate 0x%X out of range\n",
+ new_rate);
+ goto out;
}
- adapter->datarate = data_rate;
- action = cmd_act_set_tx_fix_rate;
- adapter->is_datarate_auto = 0;
+ adapter->cur_rate = new_rate;
+ action = CMD_ACT_SET_TX_FIX_RATE;
+ adapter->auto_rate = 0;
}
- ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
- action, cmd_option_waitforrsp, 0, NULL);
+ ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE,
+ action, CMD_OPTION_WAITFORRSP, 0, NULL);
+out:
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
}
@@ -1174,14 +1011,19 @@ static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
- if (adapter->is_datarate_auto) {
- vwrq->fixed = 0;
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
+ vwrq->value = adapter->cur_rate * 500000;
+
+ if (adapter->auto_rate)
+ vwrq->fixed = 0;
+ else
+ vwrq->fixed = 1;
+
} else {
- vwrq->fixed = 1;
+ vwrq->fixed = 0;
+ vwrq->value = 0;
}
- vwrq->value = adapter->datarate * 500000;
-
lbs_deb_leave(LBS_DEB_WEXT);
return 0;
}
@@ -1298,7 +1140,7 @@ static int wlan_get_encode(struct net_device *dev,
dwrq->flags |= IW_ENCODE_NOKEY;
- lbs_deb_wext("key: " MAC_FMT ", keylen %d\n",
+ lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
extra[0], extra[1], extra[2],
extra[3], extra[4], extra[5], dwrq->length);
@@ -1325,7 +1167,7 @@ static int wlan_set_wep_key(struct assoc_request *assoc_req,
int set_tx_key)
{
int ret = 0;
- struct WLAN_802_11_KEY *pkey;
+ struct enc_key *pkey;
lbs_deb_enter(LBS_DEB_WEXT);
@@ -1344,7 +1186,7 @@ static int wlan_set_wep_key(struct assoc_request *assoc_req,
pkey = &assoc_req->wep_keys[index];
if (key_length > 0) {
- memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+ memset(pkey, 0, sizeof(struct enc_key));
pkey->type = KEY_TYPE_ID_WEP;
/* Standardize the key length */
@@ -1412,11 +1254,11 @@ static void disable_wpa(struct assoc_request *assoc_req)
{
lbs_deb_enter(LBS_DEB_WEXT);
- memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct WLAN_802_11_KEY));
+ memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key));
assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
- memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct WLAN_802_11_KEY));
+ memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key));
assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
@@ -1567,7 +1409,7 @@ static int wlan_get_encodeext(struct net_device *dev,
&& (adapter->secinfo.WPAenabled ||
adapter->secinfo.WPA2enabled)) {
/* WPA */
- struct WLAN_802_11_KEY * pkey = NULL;
+ struct enc_key * pkey = NULL;
if ( adapter->wpa_mcast_key.len
&& (adapter->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
@@ -1679,7 +1521,7 @@ static int wlan_set_encodeext(struct net_device *dev,
if (set_tx_key)
set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
} else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
- struct WLAN_802_11_KEY * pkey;
+ struct enc_key * pkey;
/* validate key length */
if (((alg == IW_ENCODE_ALG_TKIP)
@@ -1702,7 +1544,7 @@ static int wlan_set_encodeext(struct net_device *dev,
set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
}
- memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
+ memset(pkey, 0, sizeof (struct enc_key));
memcpy(pkey->key, ext->key, ext->key_len);
pkey->len = ext->key_len;
if (pkey->len)
@@ -1976,12 +1818,14 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
return 0;
}
- adapter->preamble = cmd_type_auto_preamble;
+ adapter->preamble = CMD_TYPE_AUTO_PREAMBLE;
wlan_radio_ioctl(priv, RADIO_ON);
+ /* Userspace check in iwrange if it should use dBm or mW,
+ * therefore this should never happen... Jean II */
if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
- dbm = (u16) mw_to_dbm(vwrq->value);
+ return -EOPNOTSUPP;
} else
dbm = (u16) vwrq->value;
@@ -1993,9 +1837,9 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
lbs_deb_wext("txpower set %d dbm\n", dbm);
ret = libertas_prepare_and_send_command(priv,
- cmd_802_11_rf_tx_power,
- cmd_act_tx_power_opt_set_low,
- cmd_option_waitforrsp, 0, (void *)&dbm);
+ CMD_802_11_RF_TX_POWER,
+ CMD_ACT_TX_POWER_OPT_SET_LOW,
+ CMD_OPTION_WAITFORRSP, 0, (void *)&dbm);
lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
return ret;
@@ -2017,7 +1861,7 @@ static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
/*
* Get the current SSID
*/
- if (adapter->connect_status == libertas_connected) {
+ if (adapter->connect_status == LIBERTAS_CONNECTED) {
memcpy(extra, adapter->curbssparams.ssid,
adapter->curbssparams.ssid_len);
extra[adapter->curbssparams.ssid_len] = '\0';
@@ -2029,12 +1873,7 @@ static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
* If none, we may want to get the one that was set
*/
- /* To make the driver backward compatible with WPA supplicant v0.2.4 */
- if (dwrq->length == 32) /* check with WPA supplicant buffer size */
- dwrq->length = min_t(size_t, adapter->curbssparams.ssid_len,
- IW_ESSID_MAX_SIZE);
- else
- dwrq->length = adapter->curbssparams.ssid_len + 1;
+ dwrq->length = adapter->curbssparams.ssid_len;
dwrq->flags = 1; /* active */
@@ -2055,14 +1894,6 @@ static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
- /*
- * WE-20 and earlier NULL pad the end of the SSID and increment
- * SSID length so it can be used like a string. WE-21 and later don't,
- * but some userspace tools aren't able to cope with the change.
- */
- if ((in_ssid_len > 0) && (extra[in_ssid_len - 1] == '\0'))
- in_ssid_len--;
-
/* Check the size of the string */
if (in_ssid_len > IW_ESSID_MAX_SIZE) {
ret = -E2BIG;
@@ -2129,13 +1960,14 @@ static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
wlan_adapter *adapter = priv->adapter;
struct assoc_request * assoc_req;
int ret = 0;
+ DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_WEXT);
if (awrq->sa_family != ARPHRD_ETHER)
return -EINVAL;
- lbs_deb_wext("ASSOC: WAP: sa_data " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
+ lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data));
mutex_lock(&adapter->lock);
@@ -2298,13 +2130,13 @@ static const iw_handler mesh_wlan_handler[] = {
(iw_handler) NULL, /* SIOCSIWPMKSA */
};
struct iw_handler_def libertas_handler_def = {
- .num_standard = sizeof(wlan_handler) / sizeof(iw_handler),
+ .num_standard = ARRAY_SIZE(wlan_handler),
.standard = (iw_handler *) wlan_handler,
.get_wireless_stats = wlan_get_wireless_stats,
};
struct iw_handler_def mesh_handler_def = {
- .num_standard = sizeof(mesh_wlan_handler) / sizeof(iw_handler),
+ .num_standard = ARRAY_SIZE(mesh_wlan_handler),
.standard = (iw_handler *) mesh_wlan_handler,
.get_wireless_stats = wlan_get_wireless_stats,
};
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
index 3d5196c9553..6aa444c7de8 100644
--- a/drivers/net/wireless/libertas/wext.h
+++ b/drivers/net/wireless/libertas/wext.h
@@ -4,9 +4,6 @@
#ifndef _WLAN_WEXT_H_
#define _WLAN_WEXT_H_
-#define SUBCMD_OFFSET 4
-#define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET))
-
/** wlan_ioctl_regrdwr */
struct wlan_ioctl_regrdwr {
/** Which register to access */
@@ -18,13 +15,9 @@ struct wlan_ioctl_regrdwr {
u32 value;
};
-#define WLAN_LINKMODE_802_3 0
-#define WLAN_LINKMODE_802_11 2
-#define WLAN_RADIOMODE_NONE 0
-#define WLAN_RADIOMODE_RADIOTAP 2
+#define WLAN_MONITOR_OFF 0
extern struct iw_handler_def libertas_handler_def;
extern struct iw_handler_def mesh_handler_def;
-int wlan_radio_ioctl(wlan_private * priv, u8 option);
#endif /* _WLAN_WEXT_H_ */
diff --git a/drivers/net/wireless/net2280.h b/drivers/net/wireless/net2280.h
new file mode 100644
index 00000000000..120eb831b28
--- /dev/null
+++ b/drivers/net/wireless/net2280.h
@@ -0,0 +1,452 @@
+#ifndef NET2280_H
+#define NET2280_H
+/*
+ * NetChip 2280 high/full speed USB device controller.
+ * Unlike many such controllers, this one talks PCI.
+ */
+
+/*
+ * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com)
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* NET2280 MEMORY MAPPED REGISTERS
+ *
+ * The register layout came from the chip documentation, and the bit
+ * number definitions were extracted from chip specification.
+ *
+ * Use the shift operator ('<<') to build bit masks, with readl/writel
+ * to access the registers through PCI.
+ */
+
+/* main registers, BAR0 + 0x0000 */
+struct net2280_regs {
+ // offset 0x0000
+ __le32 devinit;
+#define LOCAL_CLOCK_FREQUENCY 8
+#define FORCE_PCI_RESET 7
+#define PCI_ID 6
+#define PCI_ENABLE 5
+#define FIFO_SOFT_RESET 4
+#define CFG_SOFT_RESET 3
+#define PCI_SOFT_RESET 2
+#define USB_SOFT_RESET 1
+#define M8051_RESET 0
+ __le32 eectl;
+#define EEPROM_ADDRESS_WIDTH 23
+#define EEPROM_CHIP_SELECT_ACTIVE 22
+#define EEPROM_PRESENT 21
+#define EEPROM_VALID 20
+#define EEPROM_BUSY 19
+#define EEPROM_CHIP_SELECT_ENABLE 18
+#define EEPROM_BYTE_READ_START 17
+#define EEPROM_BYTE_WRITE_START 16
+#define EEPROM_READ_DATA 8
+#define EEPROM_WRITE_DATA 0
+ __le32 eeclkfreq;
+ u32 _unused0;
+ // offset 0x0010
+
+ __le32 pciirqenb0; /* interrupt PCI master ... */
+#define SETUP_PACKET_INTERRUPT_ENABLE 7
+#define ENDPOINT_F_INTERRUPT_ENABLE 6
+#define ENDPOINT_E_INTERRUPT_ENABLE 5
+#define ENDPOINT_D_INTERRUPT_ENABLE 4
+#define ENDPOINT_C_INTERRUPT_ENABLE 3
+#define ENDPOINT_B_INTERRUPT_ENABLE 2
+#define ENDPOINT_A_INTERRUPT_ENABLE 1
+#define ENDPOINT_0_INTERRUPT_ENABLE 0
+ __le32 pciirqenb1;
+#define PCI_INTERRUPT_ENABLE 31
+#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27
+#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26
+#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25
+#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20
+#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19
+#define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE 18
+#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17
+#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16
+#define GPIO_INTERRUPT_ENABLE 13
+#define DMA_D_INTERRUPT_ENABLE 12
+#define DMA_C_INTERRUPT_ENABLE 11
+#define DMA_B_INTERRUPT_ENABLE 10
+#define DMA_A_INTERRUPT_ENABLE 9
+#define EEPROM_DONE_INTERRUPT_ENABLE 8
+#define VBUS_INTERRUPT_ENABLE 7
+#define CONTROL_STATUS_INTERRUPT_ENABLE 6
+#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4
+#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3
+#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2
+#define RESUME_INTERRUPT_ENABLE 1
+#define SOF_INTERRUPT_ENABLE 0
+ __le32 cpu_irqenb0; /* ... or onboard 8051 */
+#define SETUP_PACKET_INTERRUPT_ENABLE 7
+#define ENDPOINT_F_INTERRUPT_ENABLE 6
+#define ENDPOINT_E_INTERRUPT_ENABLE 5
+#define ENDPOINT_D_INTERRUPT_ENABLE 4
+#define ENDPOINT_C_INTERRUPT_ENABLE 3
+#define ENDPOINT_B_INTERRUPT_ENABLE 2
+#define ENDPOINT_A_INTERRUPT_ENABLE 1
+#define ENDPOINT_0_INTERRUPT_ENABLE 0
+ __le32 cpu_irqenb1;
+#define CPU_INTERRUPT_ENABLE 31
+#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27
+#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26
+#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25
+#define PCI_INTA_INTERRUPT_ENABLE 24
+#define PCI_PME_INTERRUPT_ENABLE 23
+#define PCI_SERR_INTERRUPT_ENABLE 22
+#define PCI_PERR_INTERRUPT_ENABLE 21
+#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20
+#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19
+#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17
+#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16
+#define GPIO_INTERRUPT_ENABLE 13
+#define DMA_D_INTERRUPT_ENABLE 12
+#define DMA_C_INTERRUPT_ENABLE 11
+#define DMA_B_INTERRUPT_ENABLE 10
+#define DMA_A_INTERRUPT_ENABLE 9
+#define EEPROM_DONE_INTERRUPT_ENABLE 8
+#define VBUS_INTERRUPT_ENABLE 7
+#define CONTROL_STATUS_INTERRUPT_ENABLE 6
+#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4
+#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3
+#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2
+#define RESUME_INTERRUPT_ENABLE 1
+#define SOF_INTERRUPT_ENABLE 0
+
+ // offset 0x0020
+ u32 _unused1;
+ __le32 usbirqenb1;
+#define USB_INTERRUPT_ENABLE 31
+#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27
+#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26
+#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25
+#define PCI_INTA_INTERRUPT_ENABLE 24
+#define PCI_PME_INTERRUPT_ENABLE 23
+#define PCI_SERR_INTERRUPT_ENABLE 22
+#define PCI_PERR_INTERRUPT_ENABLE 21
+#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20
+#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19
+#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17
+#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16
+#define GPIO_INTERRUPT_ENABLE 13
+#define DMA_D_INTERRUPT_ENABLE 12
+#define DMA_C_INTERRUPT_ENABLE 11
+#define DMA_B_INTERRUPT_ENABLE 10
+#define DMA_A_INTERRUPT_ENABLE 9
+#define EEPROM_DONE_INTERRUPT_ENABLE 8
+#define VBUS_INTERRUPT_ENABLE 7
+#define CONTROL_STATUS_INTERRUPT_ENABLE 6
+#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4
+#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3
+#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2
+#define RESUME_INTERRUPT_ENABLE 1
+#define SOF_INTERRUPT_ENABLE 0
+ __le32 irqstat0;
+#define INTA_ASSERTED 12
+#define SETUP_PACKET_INTERRUPT 7
+#define ENDPOINT_F_INTERRUPT 6
+#define ENDPOINT_E_INTERRUPT 5
+#define ENDPOINT_D_INTERRUPT 4
+#define ENDPOINT_C_INTERRUPT 3
+#define ENDPOINT_B_INTERRUPT 2
+#define ENDPOINT_A_INTERRUPT 1
+#define ENDPOINT_0_INTERRUPT 0
+ __le32 irqstat1;
+#define POWER_STATE_CHANGE_INTERRUPT 27
+#define PCI_ARBITER_TIMEOUT_INTERRUPT 26
+#define PCI_PARITY_ERROR_INTERRUPT 25
+#define PCI_INTA_INTERRUPT 24
+#define PCI_PME_INTERRUPT 23
+#define PCI_SERR_INTERRUPT 22
+#define PCI_PERR_INTERRUPT 21
+#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT 20
+#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19
+#define PCI_RETRY_ABORT_INTERRUPT 17
+#define PCI_MASTER_CYCLE_DONE_INTERRUPT 16
+#define GPIO_INTERRUPT 13
+#define DMA_D_INTERRUPT 12
+#define DMA_C_INTERRUPT 11
+#define DMA_B_INTERRUPT 10
+#define DMA_A_INTERRUPT 9
+#define EEPROM_DONE_INTERRUPT 8
+#define VBUS_INTERRUPT 7
+#define CONTROL_STATUS_INTERRUPT 6
+#define ROOT_PORT_RESET_INTERRUPT 4
+#define SUSPEND_REQUEST_INTERRUPT 3
+#define SUSPEND_REQUEST_CHANGE_INTERRUPT 2
+#define RESUME_INTERRUPT 1
+#define SOF_INTERRUPT 0
+ // offset 0x0030
+ __le32 idxaddr;
+ __le32 idxdata;
+ __le32 fifoctl;
+#define PCI_BASE2_RANGE 16
+#define IGNORE_FIFO_AVAILABILITY 3
+#define PCI_BASE2_SELECT 2
+#define FIFO_CONFIGURATION_SELECT 0
+ u32 _unused2;
+ // offset 0x0040
+ __le32 memaddr;
+#define START 28
+#define DIRECTION 27
+#define FIFO_DIAGNOSTIC_SELECT 24
+#define MEMORY_ADDRESS 0
+ __le32 memdata0;
+ __le32 memdata1;
+ u32 _unused3;
+ // offset 0x0050
+ __le32 gpioctl;
+#define GPIO3_LED_SELECT 12
+#define GPIO3_INTERRUPT_ENABLE 11
+#define GPIO2_INTERRUPT_ENABLE 10
+#define GPIO1_INTERRUPT_ENABLE 9
+#define GPIO0_INTERRUPT_ENABLE 8
+#define GPIO3_OUTPUT_ENABLE 7
+#define GPIO2_OUTPUT_ENABLE 6
+#define GPIO1_OUTPUT_ENABLE 5
+#define GPIO0_OUTPUT_ENABLE 4
+#define GPIO3_DATA 3
+#define GPIO2_DATA 2
+#define GPIO1_DATA 1
+#define GPIO0_DATA 0
+ __le32 gpiostat;
+#define GPIO3_INTERRUPT 3
+#define GPIO2_INTERRUPT 2
+#define GPIO1_INTERRUPT 1
+#define GPIO0_INTERRUPT 0
+} __attribute__ ((packed));
+
+/* usb control, BAR0 + 0x0080 */
+struct net2280_usb_regs {
+ // offset 0x0080
+ __le32 stdrsp;
+#define STALL_UNSUPPORTED_REQUESTS 31
+#define SET_TEST_MODE 16
+#define GET_OTHER_SPEED_CONFIGURATION 15
+#define GET_DEVICE_QUALIFIER 14
+#define SET_ADDRESS 13
+#define ENDPOINT_SET_CLEAR_HALT 12
+#define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP 11
+#define GET_STRING_DESCRIPTOR_2 10
+#define GET_STRING_DESCRIPTOR_1 9
+#define GET_STRING_DESCRIPTOR_0 8
+#define GET_SET_INTERFACE 6
+#define GET_SET_CONFIGURATION 5
+#define GET_CONFIGURATION_DESCRIPTOR 4
+#define GET_DEVICE_DESCRIPTOR 3
+#define GET_ENDPOINT_STATUS 2
+#define GET_INTERFACE_STATUS 1
+#define GET_DEVICE_STATUS 0
+ __le32 prodvendid;
+#define PRODUCT_ID 16
+#define VENDOR_ID 0
+ __le32 relnum;
+ __le32 usbctl;
+#define SERIAL_NUMBER_INDEX 16
+#define PRODUCT_ID_STRING_ENABLE 13
+#define VENDOR_ID_STRING_ENABLE 12
+#define USB_ROOT_PORT_WAKEUP_ENABLE 11
+#define VBUS_PIN 10
+#define TIMED_DISCONNECT 9
+#define SUSPEND_IMMEDIATELY 7
+#define SELF_POWERED_USB_DEVICE 6
+#define REMOTE_WAKEUP_SUPPORT 5
+#define PME_POLARITY 4
+#define USB_DETECT_ENABLE 3
+#define PME_WAKEUP_ENABLE 2
+#define DEVICE_REMOTE_WAKEUP_ENABLE 1
+#define SELF_POWERED_STATUS 0
+ // offset 0x0090
+ __le32 usbstat;
+#define HIGH_SPEED 7
+#define FULL_SPEED 6
+#define GENERATE_RESUME 5
+#define GENERATE_DEVICE_REMOTE_WAKEUP 4
+ __le32 xcvrdiag;
+#define FORCE_HIGH_SPEED_MODE 31
+#define FORCE_FULL_SPEED_MODE 30
+#define USB_TEST_MODE 24
+#define LINE_STATE 16
+#define TRANSCEIVER_OPERATION_MODE 2
+#define TRANSCEIVER_SELECT 1
+#define TERMINATION_SELECT 0
+ __le32 setup0123;
+ __le32 setup4567;
+ // offset 0x0090
+ u32 _unused0;
+ __le32 ouraddr;
+#define FORCE_IMMEDIATE 7
+#define OUR_USB_ADDRESS 0
+ __le32 ourconfig;
+} __attribute__ ((packed));
+
+/* pci control, BAR0 + 0x0100 */
+struct net2280_pci_regs {
+ // offset 0x0100
+ __le32 pcimstctl;
+#define PCI_ARBITER_PARK_SELECT 13
+#define PCI_MULTI LEVEL_ARBITER 12
+#define PCI_RETRY_ABORT_ENABLE 11
+#define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE 10
+#define DMA_READ_MULTIPLE_ENABLE 9
+#define DMA_READ_LINE_ENABLE 8
+#define PCI_MASTER_COMMAND_SELECT 6
+#define MEM_READ_OR_WRITE 0
+#define IO_READ_OR_WRITE 1
+#define CFG_READ_OR_WRITE 2
+#define PCI_MASTER_START 5
+#define PCI_MASTER_READ_WRITE 4
+#define PCI_MASTER_WRITE 0
+#define PCI_MASTER_READ 1
+#define PCI_MASTER_BYTE_WRITE_ENABLES 0
+ __le32 pcimstaddr;
+ __le32 pcimstdata;
+ __le32 pcimststat;
+#define PCI_ARBITER_CLEAR 2
+#define PCI_EXTERNAL_ARBITER 1
+#define PCI_HOST_MODE 0
+} __attribute__ ((packed));
+
+/* dma control, BAR0 + 0x0180 ... array of four structs like this,
+ * for channels 0..3. see also struct net2280_dma: descriptor
+ * that can be loaded into some of these registers.
+ */
+struct net2280_dma_regs { /* [11.7] */
+ // offset 0x0180, 0x01a0, 0x01c0, 0x01e0,
+ __le32 dmactl;
+#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25
+#define DMA_CLEAR_COUNT_ENABLE 21
+#define DESCRIPTOR_POLLING_RATE 19
+#define POLL_CONTINUOUS 0
+#define POLL_1_USEC 1
+#define POLL_100_USEC 2
+#define POLL_1_MSEC 3
+#define DMA_VALID_BIT_POLLING_ENABLE 18
+#define DMA_VALID_BIT_ENABLE 17
+#define DMA_SCATTER_GATHER_ENABLE 16
+#define DMA_OUT_AUTO_START_ENABLE 4
+#define DMA_PREEMPT_ENABLE 3
+#define DMA_FIFO_VALIDATE 2
+#define DMA_ENABLE 1
+#define DMA_ADDRESS_HOLD 0
+ __le32 dmastat;
+#define DMA_SCATTER_GATHER_DONE_INTERRUPT 25
+#define DMA_TRANSACTION_DONE_INTERRUPT 24
+#define DMA_ABORT 1
+#define DMA_START 0
+ u32 _unused0[2];
+ // offset 0x0190, 0x01b0, 0x01d0, 0x01f0,
+ __le32 dmacount;
+#define VALID_BIT 31
+#define DMA_DIRECTION 30
+#define DMA_DONE_INTERRUPT_ENABLE 29
+#define END_OF_CHAIN 28
+#define DMA_BYTE_COUNT_MASK ((1<<24)-1)
+#define DMA_BYTE_COUNT 0
+ __le32 dmaaddr;
+ __le32 dmadesc;
+ u32 _unused1;
+} __attribute__ ((packed));
+
+/* dedicated endpoint registers, BAR0 + 0x0200 */
+
+struct net2280_dep_regs { /* [11.8] */
+ // offset 0x0200, 0x0210, 0x220, 0x230, 0x240
+ __le32 dep_cfg;
+ // offset 0x0204, 0x0214, 0x224, 0x234, 0x244
+ __le32 dep_rsp;
+ u32 _unused[2];
+} __attribute__ ((packed));
+
+/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs
+ * like this, for ep0 then the configurable endpoints A..F
+ * ep0 reserved for control; E and F have only 64 bytes of fifo
+ */
+struct net2280_ep_regs { /* [11.9] */
+ // offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0
+ __le32 ep_cfg;
+#define ENDPOINT_BYTE_COUNT 16
+#define ENDPOINT_ENABLE 10
+#define ENDPOINT_TYPE 8
+#define ENDPOINT_DIRECTION 7
+#define ENDPOINT_NUMBER 0
+ __le32 ep_rsp;
+#define SET_NAK_OUT_PACKETS 15
+#define SET_EP_HIDE_STATUS_PHASE 14
+#define SET_EP_FORCE_CRC_ERROR 13
+#define SET_INTERRUPT_MODE 12
+#define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11
+#define SET_NAK_OUT_PACKETS_MODE 10
+#define SET_ENDPOINT_TOGGLE 9
+#define SET_ENDPOINT_HALT 8
+#define CLEAR_NAK_OUT_PACKETS 7
+#define CLEAR_EP_HIDE_STATUS_PHASE 6
+#define CLEAR_EP_FORCE_CRC_ERROR 5
+#define CLEAR_INTERRUPT_MODE 4
+#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3
+#define CLEAR_NAK_OUT_PACKETS_MODE 2
+#define CLEAR_ENDPOINT_TOGGLE 1
+#define CLEAR_ENDPOINT_HALT 0
+ __le32 ep_irqenb;
+#define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE 6
+#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 5
+#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3
+#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2
+#define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE 1
+#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0
+ __le32 ep_stat;
+#define FIFO_VALID_COUNT 24
+#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 22
+#define TIMEOUT 21
+#define USB_STALL_SENT 20
+#define USB_IN_NAK_SENT 19
+#define USB_IN_ACK_RCVD 18
+#define USB_OUT_PING_NAK_SENT 17
+#define USB_OUT_ACK_SENT 16
+#define FIFO_OVERFLOW 13
+#define FIFO_UNDERFLOW 12
+#define FIFO_FULL 11
+#define FIFO_EMPTY 10
+#define FIFO_FLUSH 9
+#define SHORT_PACKET_OUT_DONE_INTERRUPT 6
+#define SHORT_PACKET_TRANSFERRED_INTERRUPT 5
+#define NAK_OUT_PACKETS 4
+#define DATA_PACKET_RECEIVED_INTERRUPT 3
+#define DATA_PACKET_TRANSMITTED_INTERRUPT 2
+#define DATA_OUT_PING_TOKEN_INTERRUPT 1
+#define DATA_IN_TOKEN_INTERRUPT 0
+ // offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0
+ __le32 ep_avail;
+ __le32 ep_data;
+ u32 _unused0[2];
+} __attribute__ ((packed));
+
+struct net2280_reg_write {
+ __le16 port;
+ __le32 addr;
+ __le32 val;
+} __attribute__ ((packed));
+
+struct net2280_reg_read {
+ __le16 port;
+ __le32 addr;
+} __attribute__ ((packed));
+#endif /* NET2280_H */
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index 45b00e13ab2..2402cb8dd32 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -4,18 +4,18 @@
* Version: 0.4.1
* Description: Netwave AirSurfer Wireless LAN PC Card driver
* Status: Experimental.
- * Authors: John Markus Bjørndalen <johnm@cs.uit.no>
+ * Authors: John Markus Bjørndalen <johnm@cs.uit.no>
* Dag Brattli <dagb@cs.uit.no>
* David Hinds <dahinds@users.sourceforge.net>
* Created at: A long time ago!
* Modified at: Mon Nov 10 11:54:37 1997
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1997 University of Tromsø, Norway
+ * Copyright (c) 1997 University of Tromsø, Norway
*
* Revision History:
*
- * 08-Nov-97 15:14:47 John Markus Bjørndalen <johnm@cs.uit.no>
+ * 08-Nov-97 15:14:47 John Markus Bjørndalen <johnm@cs.uit.no>
* - Fixed some bugs in netwave_rx and cleaned it up a bit.
* (One of the bugs would have destroyed packets when receiving
* multiple packets per interrupt).
@@ -158,7 +158,7 @@ static int pc_debug = PCMCIA_DEBUG;
module_param(pc_debug, int, 0);
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
static char *version =
-"netwave_cs.c 0.3.0 Thu Jul 17 14:36:02 1997 (John Markus Bjørndalen)\n";
+"netwave_cs.c 0.3.0 Thu Jul 17 14:36:02 1997 (John Markus Bjørndalen)\n";
#else
#define DEBUG(n, args...)
#endif
@@ -412,7 +412,6 @@ static int netwave_probe(struct pcmcia_device *link)
spin_lock_init(&priv->spinlock);
/* Netwave specific entries in the device structure */
- SET_MODULE_OWNER(dev);
dev->hard_start_xmit = &netwave_start_xmit;
dev->get_stats = &netwave_get_stats;
dev->set_multicast_list = &set_multicast_list;
@@ -710,9 +709,9 @@ static const iw_handler netwave_private_handler[] =
static const struct iw_handler_def netwave_handler_def =
{
- .num_standard = sizeof(netwave_handler)/sizeof(iw_handler),
- .num_private = sizeof(netwave_private_handler)/sizeof(iw_handler),
- .num_private_args = sizeof(netwave_private_args)/sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(netwave_handler),
+ .num_private = ARRAY_SIZE(netwave_private_handler),
+ .num_private_args = ARRAY_SIZE(netwave_private_args),
.standard = (iw_handler *) netwave_handler,
.private = (iw_handler *) netwave_private_handler,
.private_args = (struct iw_priv_args *) netwave_private_args,
@@ -738,6 +737,7 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) {
win_req_t req;
memreq_t mem;
u_char __iomem *ramBase = NULL;
+ DECLARE_MAC_BUF(mac);
DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link);
@@ -806,12 +806,13 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) {
for (i = 0; i < 6; i++)
dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i);
- printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx id "
- "%c%c, hw_addr ", dev->name, dev->base_addr, dev->irq,
- (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI),
- (int) readb(ramBase+NETWAVE_EREG_NI+1));
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx"
+ "id %c%c, hw_addr %s\n",
+ dev->name, dev->base_addr, dev->irq,
+ (u_long) ramBase,
+ (int) readb(ramBase+NETWAVE_EREG_NI),
+ (int) readb(ramBase+NETWAVE_EREG_NI+1),
+ print_mac(mac, dev->dev_addr));
/* get revision words */
printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n",
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 062286dc8e1..ca6c2da7bc5 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -2232,6 +2232,7 @@ static int orinoco_init(struct net_device *dev)
struct hermes_idstring nickbuf;
u16 reclen;
int len;
+ DECLARE_MAC_BUF(mac);
/* No need to lock, the hw_unavailable flag is already set in
* alloc_orinocodev() */
@@ -2274,10 +2275,8 @@ static int orinoco_init(struct net_device *dev)
goto out;
}
- printk(KERN_DEBUG "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
- dev->name, dev->dev_addr[0], dev->dev_addr[1],
- dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4],
- dev->dev_addr[5]);
+ printk(KERN_DEBUG "%s: MAC address %s\n",
+ dev->name, print_mac(mac, dev->dev_addr));
/* Get the station name */
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index d1e502236b2..8b7f5768a10 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -313,7 +313,6 @@ orinoco_cs_config(struct pcmcia_device *link)
/* Ok, we have the configuration, prepare to register the netdev */
dev->base_addr = link->io.BasePort1;
dev->irq = link->irq.AssignedIRQ;
- SET_MODULE_OWNER(dev);
card->node.major = card->node.minor = 0;
SET_NETDEV_DEV(dev, &handle_to_dev(link));
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
index eaf3d13b851..35ec5fcf81a 100644
--- a/drivers/net/wireless/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco_nortel.c
@@ -193,7 +193,6 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
card = priv->card;
card->bridge_io = bridge_io;
card->attr_io = attr_io;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
index 97a8b4ff32b..2547d5dac0d 100644
--- a/drivers/net/wireless/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco_pci.c
@@ -148,7 +148,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
priv = netdev_priv(dev);
card = priv->card;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
index 31162ac25a9..98fe165337d 100644
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco_plx.c
@@ -232,7 +232,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
card = priv->card;
card->bridge_io = bridge_io;
card->attr_io = attr_io;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c
index 7c7b960c91d..df493185a4a 100644
--- a/drivers/net/wireless/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco_tmd.c
@@ -134,7 +134,6 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
@@ -190,7 +189,7 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = dev->priv;
+ struct orinoco_private *priv = netdev_priv(dev);
struct orinoco_pci_card *card = priv->card;
unregister_netdev(dev);
diff --git a/drivers/net/wireless/p54.h b/drivers/net/wireless/p54.h
new file mode 100644
index 00000000000..744c866066c
--- /dev/null
+++ b/drivers/net/wireless/p54.h
@@ -0,0 +1,81 @@
+#ifndef PRISM54_H
+#define PRISM54_H
+
+/*
+ * Shared defines for all mac80211 Prism54 code
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+enum control_frame_types {
+ P54_CONTROL_TYPE_FILTER_SET = 0,
+ P54_CONTROL_TYPE_CHANNEL_CHANGE,
+ P54_CONTROL_TYPE_FREQDONE,
+ P54_CONTROL_TYPE_DCFINIT,
+ P54_CONTROL_TYPE_FREEQUEUE = 7,
+ P54_CONTROL_TYPE_TXDONE,
+ P54_CONTROL_TYPE_PING,
+ P54_CONTROL_TYPE_STAT_READBACK,
+ P54_CONTROL_TYPE_BBP,
+ P54_CONTROL_TYPE_EEPROM_READBACK,
+ P54_CONTROL_TYPE_LED
+};
+
+struct p54_control_hdr {
+ __le16 magic1;
+ __le16 len;
+ __le32 req_id;
+ __le16 type; /* enum control_frame_types */
+ u8 retry1;
+ u8 retry2;
+ u8 data[0];
+} __attribute__ ((packed));
+
+#define EEPROM_READBACK_LEN (sizeof(struct p54_control_hdr) + 4 /* p54_eeprom_lm86 */)
+#define MAX_RX_SIZE (IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct p54_control_hdr) + 20 /* length of struct p54_rx_hdr */ + 16 )
+
+#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
+
+struct p54_common {
+ u32 rx_start;
+ u32 rx_end;
+ struct sk_buff_head tx_queue;
+ void (*tx)(struct ieee80211_hw *dev, struct p54_control_hdr *data,
+ size_t len, int free_on_tx);
+ int (*open)(struct ieee80211_hw *dev);
+ void (*stop)(struct ieee80211_hw *dev);
+ int mode;
+ u8 mac_addr[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ struct pda_iq_autocal_entry *iq_autocal;
+ unsigned int iq_autocal_len;
+ struct pda_channel_output_limit *output_limit;
+ unsigned int output_limit_len;
+ struct pda_pa_curve_data *curve_data;
+ __le16 rxhw;
+ u8 version;
+ unsigned int tx_hdr_len;
+ void *cached_vdcf;
+ unsigned int fw_var;
+ /* FIXME: this channels/modes/rates stuff sucks */
+ struct ieee80211_channel channels[14];
+ struct ieee80211_rate rates[12];
+ struct ieee80211_hw_mode modes[2];
+ struct ieee80211_tx_queue_stats tx_stats;
+};
+
+int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
+void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
+int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
+void p54_fill_eeprom_readback(struct p54_control_hdr *hdr);
+struct ieee80211_hw *p54_init_common(size_t priv_data_len);
+void p54_free_common(struct ieee80211_hw *dev);
+
+#endif /* PRISM54_H */
diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c
new file mode 100644
index 00000000000..1437db0cf4b
--- /dev/null
+++ b/drivers/net/wireless/p54common.c
@@ -0,0 +1,1019 @@
+
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "p54common.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Softmac Prism54 common code");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54common");
+
+void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
+{
+ struct p54_common *priv = dev->priv;
+ struct bootrec_exp_if *exp_if;
+ struct bootrec *bootrec;
+ u32 *data = (u32 *)fw->data;
+ u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
+ u8 *fw_version = NULL;
+ size_t len;
+ int i;
+
+ if (priv->rx_start)
+ return;
+
+ while (data < end_data && *data)
+ data++;
+
+ while (data < end_data && !*data)
+ data++;
+
+ bootrec = (struct bootrec *) data;
+
+ while (bootrec->data <= end_data &&
+ (bootrec->data + (len = le32_to_cpu(bootrec->len))) <= end_data) {
+ u32 code = le32_to_cpu(bootrec->code);
+ switch (code) {
+ case BR_CODE_COMPONENT_ID:
+ switch (be32_to_cpu(*bootrec->data)) {
+ case FW_FMAC:
+ printk(KERN_INFO "p54: FreeMAC firmware\n");
+ break;
+ case FW_LM20:
+ printk(KERN_INFO "p54: LM20 firmware\n");
+ break;
+ case FW_LM86:
+ printk(KERN_INFO "p54: LM86 firmware\n");
+ break;
+ case FW_LM87:
+ printk(KERN_INFO "p54: LM87 firmware - not supported yet!\n");
+ break;
+ default:
+ printk(KERN_INFO "p54: unknown firmware\n");
+ break;
+ }
+ break;
+ case BR_CODE_COMPONENT_VERSION:
+ /* 24 bytes should be enough for all firmwares */
+ if (strnlen((unsigned char*)bootrec->data, 24) < 24)
+ fw_version = (unsigned char*)bootrec->data;
+ break;
+ case BR_CODE_DESCR:
+ priv->rx_start = le32_to_cpu(bootrec->data[1]);
+ /* FIXME add sanity checking */
+ priv->rx_end = le32_to_cpu(bootrec->data[2]) - 0x3500;
+ break;
+ case BR_CODE_EXPOSED_IF:
+ exp_if = (struct bootrec_exp_if *) bootrec->data;
+ for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
+ if (exp_if[i].if_id == 0x1a)
+ priv->fw_var = le16_to_cpu(exp_if[i].variant);
+ break;
+ case BR_CODE_DEPENDENT_IF:
+ break;
+ case BR_CODE_END_OF_BRA:
+ case LEGACY_BR_CODE_END_OF_BRA:
+ end_data = NULL;
+ break;
+ default:
+ break;
+ }
+ bootrec = (struct bootrec *)&bootrec->data[len];
+ }
+
+ if (fw_version)
+ printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n",
+ fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
+
+ if (priv->fw_var >= 0x300) {
+ /* Firmware supports QoS, use it! */
+ priv->tx_stats.data[0].limit = 3;
+ priv->tx_stats.data[1].limit = 4;
+ priv->tx_stats.data[2].limit = 3;
+ priv->tx_stats.data[3].limit = 1;
+ dev->queues = 4;
+ }
+}
+EXPORT_SYMBOL_GPL(p54_parse_firmware);
+
+static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev,
+ struct pda_pa_curve_data *curve_data)
+{
+ struct p54_common *priv = dev->priv;
+ struct pda_pa_curve_data_sample_rev1 *rev1;
+ struct pda_pa_curve_data_sample_rev0 *rev0;
+ size_t cd_len = sizeof(*curve_data) +
+ (curve_data->points_per_channel*sizeof(*rev1) + 2) *
+ curve_data->channels;
+ unsigned int i, j;
+ void *source, *target;
+
+ priv->curve_data = kmalloc(cd_len, GFP_KERNEL);
+ if (!priv->curve_data)
+ return -ENOMEM;
+
+ memcpy(priv->curve_data, curve_data, sizeof(*curve_data));
+ source = curve_data->data;
+ target = priv->curve_data->data;
+ for (i = 0; i < curve_data->channels; i++) {
+ __le16 *freq = source;
+ source += sizeof(__le16);
+ *((__le16 *)target) = *freq;
+ target += sizeof(__le16);
+ for (j = 0; j < curve_data->points_per_channel; j++) {
+ rev1 = target;
+ rev0 = source;
+
+ rev1->rf_power = rev0->rf_power;
+ rev1->pa_detector = rev0->pa_detector;
+ rev1->data_64qam = rev0->pcv;
+ /* "invent" the points for the other modulations */
+#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y)
+ rev1->data_16qam = SUB(rev0->pcv, 12);
+ rev1->data_qpsk = SUB(rev1->data_16qam, 12);
+ rev1->data_bpsk = SUB(rev1->data_qpsk, 12);
+ rev1->data_barker= SUB(rev1->data_bpsk, 14);
+#undef SUB
+ target += sizeof(*rev1);
+ source += sizeof(*rev0);
+ }
+ }
+
+ return 0;
+}
+
+int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
+{
+ struct p54_common *priv = dev->priv;
+ struct eeprom_pda_wrap *wrap = NULL;
+ struct pda_entry *entry;
+ int i = 0;
+ unsigned int data_len, entry_len;
+ void *tmp;
+ int err;
+
+ wrap = (struct eeprom_pda_wrap *) eeprom;
+ entry = (void *)wrap->data + wrap->len;
+ i += 2;
+ i += le16_to_cpu(entry->len)*2;
+ while (i < len) {
+ entry_len = le16_to_cpu(entry->len);
+ data_len = ((entry_len - 1) << 1);
+ switch (le16_to_cpu(entry->code)) {
+ case PDR_MAC_ADDRESS:
+ SET_IEEE80211_PERM_ADDR(dev, entry->data);
+ break;
+ case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
+ if (data_len < 2) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ if (2 + entry->data[1]*sizeof(*priv->output_limit) > data_len) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ priv->output_limit = kmalloc(entry->data[1] *
+ sizeof(*priv->output_limit), GFP_KERNEL);
+
+ if (!priv->output_limit) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(priv->output_limit, &entry->data[2],
+ entry->data[1]*sizeof(*priv->output_limit));
+ priv->output_limit_len = entry->data[1];
+ break;
+ case PDR_PRISM_PA_CAL_CURVE_DATA:
+ if (data_len < sizeof(struct pda_pa_curve_data)) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ if (((struct pda_pa_curve_data *)entry->data)->cal_method_rev) {
+ priv->curve_data = kmalloc(data_len, GFP_KERNEL);
+ if (!priv->curve_data) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(priv->curve_data, entry->data, data_len);
+ } else {
+ err = p54_convert_rev0_to_rev1(dev, (struct pda_pa_curve_data *)entry->data);
+ if (err)
+ goto err;
+ }
+
+ break;
+ case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
+ priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
+ if (!priv->iq_autocal) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(priv->iq_autocal, entry->data, data_len);
+ priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
+ break;
+ case PDR_INTERFACE_LIST:
+ tmp = entry->data;
+ while ((u8 *)tmp < entry->data + data_len) {
+ struct bootrec_exp_if *exp_if = tmp;
+ if (le16_to_cpu(exp_if->if_id) == 0xF)
+ priv->rxhw = exp_if->variant & cpu_to_le16(0x07);
+ tmp += sizeof(struct bootrec_exp_if);
+ }
+ break;
+ case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
+ priv->version = *(u8 *)(entry->data + 1);
+ break;
+ case PDR_END:
+ i = len;
+ break;
+ }
+
+ entry = (void *)entry + (entry_len + 1)*2;
+ i += 2;
+ i += entry_len*2;
+ }
+
+ if (!priv->iq_autocal || !priv->output_limit || !priv->curve_data) {
+ printk(KERN_ERR "p54: not all required entries found in eeprom!\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ return 0;
+
+ err:
+ if (priv->iq_autocal) {
+ kfree(priv->iq_autocal);
+ priv->iq_autocal = NULL;
+ }
+
+ if (priv->output_limit) {
+ kfree(priv->output_limit);
+ priv->output_limit = NULL;
+ }
+
+ if (priv->curve_data) {
+ kfree(priv->curve_data);
+ priv->curve_data = NULL;
+ }
+
+ printk(KERN_ERR "p54: eeprom parse failed!\n");
+ return err;
+}
+EXPORT_SYMBOL_GPL(p54_parse_eeprom);
+
+void p54_fill_eeprom_readback(struct p54_control_hdr *hdr)
+{
+ struct p54_eeprom_lm86 *eeprom_hdr;
+
+ hdr->magic1 = cpu_to_le16(0x8000);
+ hdr->len = cpu_to_le16(sizeof(*eeprom_hdr) + 0x2000);
+ hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK);
+ hdr->retry1 = hdr->retry2 = 0;
+ eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data;
+ eeprom_hdr->offset = 0x0;
+ eeprom_hdr->len = cpu_to_le16(0x2000);
+}
+EXPORT_SYMBOL_GPL(p54_fill_eeprom_readback);
+
+static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data;
+ struct ieee80211_rx_status rx_status = {0};
+ u16 freq = le16_to_cpu(hdr->freq);
+
+ rx_status.ssi = hdr->rssi;
+ rx_status.rate = hdr->rate & 0x1f; /* report short preambles & CCK too */
+ rx_status.channel = freq == 2484 ? 14 : (freq - 2407)/5;
+ rx_status.freq = freq;
+ rx_status.phymode = MODE_IEEE80211G;
+ rx_status.antenna = hdr->antenna;
+ rx_status.mactime = le64_to_cpu(hdr->timestamp);
+
+ skb_pull(skb, sizeof(*hdr));
+ skb_trim(skb, le16_to_cpu(hdr->len));
+
+ ieee80211_rx_irqsafe(dev, skb, &rx_status);
+}
+
+static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int i;
+
+ /* ieee80211_start_queues is great if all queues are really empty.
+ * But, what if some are full? */
+
+ for (i = 0; i < dev->queues; i++)
+ if (priv->tx_stats.data[i].len < priv->tx_stats.data[i].limit)
+ ieee80211_wake_queue(dev, i);
+}
+
+static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+ struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data;
+ struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next;
+ u32 addr = le32_to_cpu(hdr->req_id) - 0x70;
+ struct memrecord *range = NULL;
+ u32 freed = 0;
+ u32 last_addr = priv->rx_start;
+
+ while (entry != (struct sk_buff *)&priv->tx_queue) {
+ range = (struct memrecord *)&entry->cb;
+ if (range->start_addr == addr) {
+ struct ieee80211_tx_status status = {{0}};
+ struct p54_control_hdr *entry_hdr;
+ struct p54_tx_control_allocdata *entry_data;
+ int pad = 0;
+
+ if (entry->next != (struct sk_buff *)&priv->tx_queue)
+ freed = ((struct memrecord *)&entry->next->cb)->start_addr - last_addr;
+ else
+ freed = priv->rx_end - last_addr;
+
+ last_addr = range->end_addr;
+ __skb_unlink(entry, &priv->tx_queue);
+ if (!range->control) {
+ kfree_skb(entry);
+ break;
+ }
+ memcpy(&status.control, range->control,
+ sizeof(status.control));
+ kfree(range->control);
+ priv->tx_stats.data[status.control.queue].len--;
+
+ entry_hdr = (struct p54_control_hdr *) entry->data;
+ entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
+ if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
+ pad = entry_data->align[0];
+
+ if (!status.control.flags & IEEE80211_TXCTL_NO_ACK) {
+ if (!(payload->status & 0x01))
+ status.flags |= IEEE80211_TX_STATUS_ACK;
+ else
+ status.excessive_retries = 1;
+ }
+ status.retry_count = payload->retries - 1;
+ status.ack_signal = le16_to_cpu(payload->ack_rssi);
+ skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
+ ieee80211_tx_status_irqsafe(dev, entry, &status);
+ break;
+ } else
+ last_addr = range->end_addr;
+ entry = entry->next;
+ }
+
+ if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
+ sizeof(struct p54_control_hdr))
+ p54_wake_free_queues(dev);
+}
+
+static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+
+ switch (le16_to_cpu(hdr->type)) {
+ case P54_CONTROL_TYPE_TXDONE:
+ p54_rx_frame_sent(dev, skb);
+ break;
+ case P54_CONTROL_TYPE_BBP:
+ break;
+ default:
+ printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
+ wiphy_name(dev->wiphy), le16_to_cpu(hdr->type));
+ break;
+ }
+}
+
+/* returns zero if skb can be reused */
+int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8;
+ switch (type) {
+ case 0x00:
+ case 0x01:
+ p54_rx_data(dev, skb);
+ return -1;
+ case 0x4d:
+ /* TODO: do something better... but then again, I've never seen this happen */
+ printk(KERN_ERR "%s: Received fault. Probably need to restart hardware now..\n",
+ wiphy_name(dev->wiphy));
+ break;
+ case 0x80:
+ p54_rx_control(dev, skb);
+ break;
+ default:
+ printk(KERN_ERR "%s: unknown frame RXed (0x%02x)\n",
+ wiphy_name(dev->wiphy), type);
+ break;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(p54_rx);
+
+/*
+ * So, the firmware is somewhat stupid and doesn't know what places in its
+ * memory incoming data should go to. By poking around in the firmware, we
+ * can find some unused memory to upload our packets to. However, data that we
+ * want the card to TX needs to stay intact until the card has told us that
+ * it is done with it. This function finds empty places we can upload to and
+ * marks allocated areas as reserved if necessary. p54_rx_frame_sent frees
+ * allocated areas.
+ */
+static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
+ struct p54_control_hdr *data, u32 len,
+ struct ieee80211_tx_control *control)
+{
+ struct p54_common *priv = dev->priv;
+ struct sk_buff *entry = priv->tx_queue.next;
+ struct sk_buff *target_skb = NULL;
+ struct memrecord *range;
+ u32 last_addr = priv->rx_start;
+ u32 largest_hole = 0;
+ u32 target_addr = priv->rx_start;
+ unsigned long flags;
+ unsigned int left;
+ len = (len + 0x170 + 3) & ~0x3; /* 0x70 headroom, 0x100 tailroom */
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ left = skb_queue_len(&priv->tx_queue);
+ while (left--) {
+ u32 hole_size;
+ range = (struct memrecord *)&entry->cb;
+ hole_size = range->start_addr - last_addr;
+ if (!target_skb && hole_size >= len) {
+ target_skb = entry->prev;
+ hole_size -= len;
+ target_addr = last_addr;
+ }
+ largest_hole = max(largest_hole, hole_size);
+ last_addr = range->end_addr;
+ entry = entry->next;
+ }
+ if (!target_skb && priv->rx_end - last_addr >= len) {
+ target_skb = priv->tx_queue.prev;
+ largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
+ if (!skb_queue_empty(&priv->tx_queue)) {
+ range = (struct memrecord *)&target_skb->cb;
+ target_addr = range->end_addr;
+ }
+ } else
+ largest_hole = max(largest_hole, priv->rx_end - last_addr);
+
+ if (skb) {
+ range = (struct memrecord *)&skb->cb;
+ range->start_addr = target_addr;
+ range->end_addr = target_addr + len;
+ range->control = control;
+ __skb_queue_after(&priv->tx_queue, target_skb, skb);
+ if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
+ sizeof(struct p54_control_hdr))
+ ieee80211_stop_queues(dev);
+ }
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+
+ data->req_id = cpu_to_le32(target_addr + 0x70);
+}
+
+static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct ieee80211_tx_queue_stats_data *current_queue;
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_allocdata *txhdr;
+ struct ieee80211_tx_control *control_copy;
+ size_t padding, len;
+ u8 rate;
+
+ current_queue = &priv->tx_stats.data[control->queue];
+ if (unlikely(current_queue->len > current_queue->limit))
+ return NETDEV_TX_BUSY;
+ current_queue->len++;
+ current_queue->count++;
+ if (current_queue->len == current_queue->limit)
+ ieee80211_stop_queue(dev, control->queue);
+
+ padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
+ len = skb->len;
+
+ control_copy = kmalloc(sizeof(*control), GFP_ATOMIC);
+ if (control_copy)
+ memcpy(control_copy, control, sizeof(*control));
+
+ txhdr = (struct p54_tx_control_allocdata *)
+ skb_push(skb, sizeof(*txhdr) + padding);
+ hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr));
+
+ if (padding)
+ hdr->magic1 = cpu_to_le16(0x4010);
+ else
+ hdr->magic1 = cpu_to_le16(0x0010);
+ hdr->len = cpu_to_le16(len);
+ hdr->type = (control->flags & IEEE80211_TXCTL_NO_ACK) ? 0 : cpu_to_le16(1);
+ hdr->retry1 = hdr->retry2 = control->retry_limit;
+ p54_assign_address(dev, skb, hdr, skb->len, control_copy);
+
+ memset(txhdr->wep_key, 0x0, 16);
+ txhdr->padding = 0;
+ txhdr->padding2 = 0;
+
+ /* TODO: add support for alternate retry TX rates */
+ rate = control->tx_rate;
+ if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ rate |= 0x40;
+ else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ rate |= 0x20;
+ memset(txhdr->rateset, rate, 8);
+ txhdr->wep_key_present = 0;
+ txhdr->wep_key_len = 0;
+ txhdr->frame_type = cpu_to_le32(control->queue + 4);
+ txhdr->magic4 = 0;
+ txhdr->antenna = (control->antenna_sel_tx == 0) ?
+ 2 : control->antenna_sel_tx - 1;
+ txhdr->output_power = 0x7f; // HW Maximum
+ txhdr->magic5 = (control->flags & IEEE80211_TXCTL_NO_ACK) ?
+ 0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23));
+ if (padding)
+ txhdr->align[0] = padding;
+
+ priv->tx(dev, hdr, skb->len, 0);
+ return 0;
+}
+
+static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
+ const u8 *dst, const u8 *src, u8 antenna,
+ u32 magic3, u32 magic8, u32 magic9)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_filter *filter;
+
+ hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) +
+ priv->tx_hdr_len, GFP_ATOMIC);
+ if (!hdr)
+ return -ENOMEM;
+
+ hdr = (void *)hdr + priv->tx_hdr_len;
+
+ filter = (struct p54_tx_control_filter *) hdr->data;
+ hdr->magic1 = cpu_to_le16(0x8001);
+ hdr->len = cpu_to_le16(sizeof(*filter));
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter), NULL);
+ hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET);
+
+ filter->filter_type = cpu_to_le16(filter_type);
+ memcpy(filter->dst, dst, ETH_ALEN);
+ if (!src)
+ memset(filter->src, ~0, ETH_ALEN);
+ else
+ memcpy(filter->src, src, ETH_ALEN);
+ filter->antenna = antenna;
+ filter->magic3 = cpu_to_le32(magic3);
+ filter->rx_addr = cpu_to_le32(priv->rx_end);
+ filter->max_rx = cpu_to_le16(0x0620); /* FIXME: for usb ver 1.. maybe */
+ filter->rxhw = priv->rxhw;
+ filter->magic8 = cpu_to_le16(magic8);
+ filter->magic9 = cpu_to_le16(magic9);
+
+ priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*filter), 1);
+ return 0;
+}
+
+static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_channel *chan;
+ unsigned int i;
+ size_t payload_len = sizeof(*chan) + sizeof(u32)*2 +
+ sizeof(*chan->curve_data) *
+ priv->curve_data->points_per_channel;
+ void *entry;
+
+ hdr = kzalloc(sizeof(*hdr) + payload_len +
+ priv->tx_hdr_len, GFP_KERNEL);
+ if (!hdr)
+ return -ENOMEM;
+
+ hdr = (void *)hdr + priv->tx_hdr_len;
+
+ chan = (struct p54_tx_control_channel *) hdr->data;
+
+ hdr->magic1 = cpu_to_le16(0x8001);
+ hdr->len = cpu_to_le16(sizeof(*chan));
+ hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len, NULL);
+
+ chan->magic1 = cpu_to_le16(0x1);
+ chan->magic2 = cpu_to_le16(0x0);
+
+ for (i = 0; i < priv->iq_autocal_len; i++) {
+ if (priv->iq_autocal[i].freq != freq)
+ continue;
+
+ memcpy(&chan->iq_autocal, &priv->iq_autocal[i],
+ sizeof(*priv->iq_autocal));
+ break;
+ }
+ if (i == priv->iq_autocal_len)
+ goto err;
+
+ for (i = 0; i < priv->output_limit_len; i++) {
+ if (priv->output_limit[i].freq != freq)
+ continue;
+
+ chan->val_barker = 0x38;
+ chan->val_bpsk = priv->output_limit[i].val_bpsk;
+ chan->val_qpsk = priv->output_limit[i].val_qpsk;
+ chan->val_16qam = priv->output_limit[i].val_16qam;
+ chan->val_64qam = priv->output_limit[i].val_64qam;
+ break;
+ }
+ if (i == priv->output_limit_len)
+ goto err;
+
+ chan->pa_points_per_curve = priv->curve_data->points_per_channel;
+
+ entry = priv->curve_data->data;
+ for (i = 0; i < priv->curve_data->channels; i++) {
+ if (*((__le16 *)entry) != freq) {
+ entry += sizeof(__le16);
+ entry += sizeof(struct pda_pa_curve_data_sample_rev1) *
+ chan->pa_points_per_curve;
+ continue;
+ }
+
+ entry += sizeof(__le16);
+ memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) *
+ chan->pa_points_per_curve);
+ break;
+ }
+
+ memcpy(hdr->data + payload_len - 4, &chan->val_bpsk, 4);
+
+ priv->tx(dev, hdr, sizeof(*hdr) + payload_len, 1);
+ return 0;
+
+ err:
+ printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy));
+ kfree(hdr);
+ return -EINVAL;
+}
+
+static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_led *led;
+
+ hdr = kzalloc(sizeof(*hdr) + sizeof(*led) +
+ priv->tx_hdr_len, GFP_KERNEL);
+ if (!hdr)
+ return -ENOMEM;
+
+ hdr = (void *)hdr + priv->tx_hdr_len;
+ hdr->magic1 = cpu_to_le16(0x8001);
+ hdr->len = cpu_to_le16(sizeof(*led));
+ hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED);
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led), NULL);
+
+ led = (struct p54_tx_control_led *) hdr->data;
+ led->mode = cpu_to_le16(mode);
+ led->led_permanent = cpu_to_le16(link);
+ led->led_temporary = cpu_to_le16(act);
+ led->duration = cpu_to_le16(1000);
+
+ priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*led), 1);
+
+ return 0;
+}
+
+#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, burst) \
+do { \
+ queue.aifs = cpu_to_le16(ai_fs); \
+ queue.cwmin = cpu_to_le16(cw_min); \
+ queue.cwmax = cpu_to_le16(cw_max); \
+ queue.txop = (burst == 0) ? \
+ 0 : cpu_to_le16((burst * 100) / 32 + 1); \
+} while(0)
+
+static void p54_init_vdcf(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_vdcf *vdcf;
+
+ /* all USB V1 adapters need a extra headroom */
+ hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len;
+ hdr->magic1 = cpu_to_le16(0x8001);
+ hdr->len = cpu_to_le16(sizeof(*vdcf));
+ hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT);
+ hdr->req_id = cpu_to_le32(priv->rx_start);
+
+ vdcf = (struct p54_tx_control_vdcf *) hdr->data;
+
+ P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 0x000f);
+ P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 0x001e);
+ P54_SET_QUEUE(vdcf->queue[2], 0x0002, 0x000f, 0x03ff, 0x0014);
+ P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0x0000);
+}
+
+static void p54_set_vdcf(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_control_hdr *hdr;
+ struct p54_tx_control_vdcf *vdcf;
+
+ hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len;
+
+ p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf), NULL);
+
+ vdcf = (struct p54_tx_control_vdcf *) hdr->data;
+
+ if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
+ vdcf->slottime = 9;
+ vdcf->magic1 = 0x00;
+ vdcf->magic2 = 0x10;
+ } else {
+ vdcf->slottime = 20;
+ vdcf->magic1 = 0x0a;
+ vdcf->magic2 = 0x06;
+ }
+
+ /* (see prism54/isl_oid.h for further details) */
+ vdcf->frameburst = cpu_to_le16(0);
+
+ priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0);
+}
+
+static int p54_start(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int err;
+
+ err = priv->open(dev);
+ if (!err)
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
+
+ return err;
+}
+
+static void p54_stop(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ struct sk_buff *skb;
+ while ((skb = skb_dequeue(&priv->tx_queue))) {
+ struct memrecord *range = (struct memrecord *)&skb->cb;
+ if (range->control)
+ kfree(range->control);
+ kfree_skb(skb);
+ }
+ priv->stop(dev);
+ priv->mode = IEEE80211_IF_TYPE_INVALID;
+}
+
+static int p54_add_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+
+ if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+ return -EOPNOTSUPP;
+
+ switch (conf->type) {
+ case IEEE80211_IF_TYPE_STA:
+ priv->mode = conf->type;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+
+ p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642);
+ p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642);
+
+ switch (conf->type) {
+ case IEEE80211_IF_TYPE_STA:
+ p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0);
+ break;
+ default:
+ BUG(); /* impossible */
+ break;
+ }
+
+ p54_set_leds(dev, 1, 0, 0);
+
+ return 0;
+}
+
+static void p54_remove_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
+ memset(priv->mac_addr, 0, ETH_ALEN);
+ p54_set_filter(dev, 0, priv->mac_addr, NULL, 2, 0, 0, 0);
+}
+
+static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+{
+ int ret;
+
+ ret = p54_set_freq(dev, cpu_to_le16(conf->freq));
+ p54_set_vdcf(dev);
+ return ret;
+}
+
+static int p54_config_interface(struct ieee80211_hw *dev, int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+
+ p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642);
+ p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0);
+ p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
+ memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+ return 0;
+}
+
+static void p54_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_mc_list *mclist)
+{
+ struct p54_common *priv = dev->priv;
+
+ *total_flags &= FIF_BCN_PRBRESP_PROMISC;
+
+ if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+ if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+ p54_set_filter(dev, 0, priv->mac_addr,
+ NULL, 2, 0, 0, 0);
+ else
+ p54_set_filter(dev, 0, priv->mac_addr,
+ priv->bssid, 2, 0, 0, 0);
+ }
+}
+
+static int p54_conf_tx(struct ieee80211_hw *dev, int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_tx_control_vdcf *vdcf;
+
+ vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *)
+ ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data);
+
+ if ((params) && !((queue < 0) || (queue > 4))) {
+ P54_SET_QUEUE(vdcf->queue[queue], params->aifs,
+ params->cw_min, params->cw_max, params->burst_time);
+ } else
+ return -EINVAL;
+
+ p54_set_vdcf(dev);
+
+ return 0;
+}
+
+static int p54_get_stats(struct ieee80211_hw *dev,
+ struct ieee80211_low_level_stats *stats)
+{
+ /* TODO */
+ return 0;
+}
+
+static int p54_get_tx_stats(struct ieee80211_hw *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct p54_common *priv = dev->priv;
+ unsigned int i;
+
+ for (i = 0; i < dev->queues; i++)
+ memcpy(&stats->data[i], &priv->tx_stats.data[i],
+ sizeof(stats->data[i]));
+
+ return 0;
+}
+
+static const struct ieee80211_ops p54_ops = {
+ .tx = p54_tx,
+ .start = p54_start,
+ .stop = p54_stop,
+ .add_interface = p54_add_interface,
+ .remove_interface = p54_remove_interface,
+ .config = p54_config,
+ .config_interface = p54_config_interface,
+ .configure_filter = p54_configure_filter,
+ .conf_tx = p54_conf_tx,
+ .get_stats = p54_get_stats,
+ .get_tx_stats = p54_get_tx_stats
+};
+
+struct ieee80211_hw *p54_init_common(size_t priv_data_len)
+{
+ struct ieee80211_hw *dev;
+ struct p54_common *priv;
+ int i;
+
+ dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
+ if (!dev)
+ return NULL;
+
+ priv = dev->priv;
+ priv->mode = IEEE80211_IF_TYPE_INVALID;
+ skb_queue_head_init(&priv->tx_queue);
+ memcpy(priv->channels, p54_channels, sizeof(p54_channels));
+ memcpy(priv->rates, p54_rates, sizeof(p54_rates));
+ priv->modes[1].mode = MODE_IEEE80211B;
+ priv->modes[1].num_rates = 4;
+ priv->modes[1].rates = priv->rates;
+ priv->modes[1].num_channels = ARRAY_SIZE(p54_channels);
+ priv->modes[1].channels = priv->channels;
+ priv->modes[0].mode = MODE_IEEE80211G;
+ priv->modes[0].num_rates = ARRAY_SIZE(p54_rates);
+ priv->modes[0].rates = priv->rates;
+ priv->modes[0].num_channels = ARRAY_SIZE(p54_channels);
+ priv->modes[0].channels = priv->channels;
+ dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
+ IEEE80211_HW_RX_INCLUDES_FCS;
+ dev->channel_change_time = 1000; /* TODO: find actual value */
+ dev->max_rssi = 127;
+
+ priv->tx_stats.data[0].limit = 5;
+ dev->queues = 1;
+
+ dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +
+ sizeof(struct p54_tx_control_allocdata);
+
+ priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf) +
+ priv->tx_hdr_len + sizeof(struct p54_control_hdr), GFP_KERNEL);
+
+ if (!priv->cached_vdcf) {
+ ieee80211_free_hw(dev);
+ return NULL;
+ }
+
+ p54_init_vdcf(dev);
+
+ for (i = 0; i < 2; i++) {
+ if (ieee80211_register_hwmode(dev, &priv->modes[i])) {
+ kfree(priv->cached_vdcf);
+ ieee80211_free_hw(dev);
+ return NULL;
+ }
+ }
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(p54_init_common);
+
+void p54_free_common(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ kfree(priv->iq_autocal);
+ kfree(priv->output_limit);
+ kfree(priv->curve_data);
+ kfree(priv->cached_vdcf);
+}
+EXPORT_SYMBOL_GPL(p54_free_common);
+
+static int __init p54_init(void)
+{
+ return 0;
+}
+
+static void __exit p54_exit(void)
+{
+}
+
+module_init(p54_init);
+module_exit(p54_exit);
diff --git a/drivers/net/wireless/p54common.h b/drivers/net/wireless/p54common.h
new file mode 100644
index 00000000000..a721334e20d
--- /dev/null
+++ b/drivers/net/wireless/p54common.h
@@ -0,0 +1,329 @@
+#ifndef PRISM54COMMON_H
+#define PRISM54COMMON_H
+
+/*
+ * Common code specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+struct bootrec {
+ __le32 code;
+ __le32 len;
+ u32 data[0];
+} __attribute__((packed));
+
+struct bootrec_exp_if {
+ __le16 role;
+ __le16 if_id;
+ __le16 variant;
+ __le16 btm_compat;
+ __le16 top_compat;
+} __attribute__((packed));
+
+#define BR_CODE_MIN 0x80000000
+#define BR_CODE_COMPONENT_ID 0x80000001
+#define BR_CODE_COMPONENT_VERSION 0x80000002
+#define BR_CODE_DEPENDENT_IF 0x80000003
+#define BR_CODE_EXPOSED_IF 0x80000004
+#define BR_CODE_DESCR 0x80000101
+#define BR_CODE_MAX 0x8FFFFFFF
+#define BR_CODE_END_OF_BRA 0xFF0000FF
+#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
+
+#define FW_FMAC 0x464d4143
+#define FW_LM86 0x4c4d3836
+#define FW_LM87 0x4c4d3837
+#define FW_LM20 0x4c4d3230
+
+/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
+
+struct pda_entry {
+ __le16 len; /* includes both code and data */
+ __le16 code;
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct eeprom_pda_wrap {
+ u32 magic;
+ u16 pad;
+ u16 len;
+ u32 arm_opcode;
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct pda_iq_autocal_entry {
+ __le16 freq;
+ __le16 iq_param[4];
+} __attribute__ ((packed));
+
+struct pda_channel_output_limit {
+ __le16 freq;
+ u8 val_bpsk;
+ u8 val_qpsk;
+ u8 val_16qam;
+ u8 val_64qam;
+ u8 rate_set_mask;
+ u8 rate_set_size;
+} __attribute__ ((packed));
+
+struct pda_pa_curve_data_sample_rev0 {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 pcv;
+} __attribute__ ((packed));
+
+struct pda_pa_curve_data_sample_rev1 {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 data_barker;
+ u8 data_bpsk;
+ u8 data_qpsk;
+ u8 data_16qam;
+ u8 data_64qam;
+ u8 padding;
+} __attribute__ ((packed));
+
+struct pda_pa_curve_data {
+ u8 cal_method_rev;
+ u8 channels;
+ u8 points_per_channel;
+ u8 padding;
+ u8 data[0];
+} __attribute__ ((packed));
+
+/*
+ * this defines the PDR codes used to build PDAs as defined in document
+ * number 553155. The current implementation mirrors version 1.1 of the
+ * document and lists only PDRs supported by the ARM platform.
+ */
+
+/* common and choice range (0x0000 - 0x0fff) */
+#define PDR_END 0x0000
+#define PDR_MANUFACTURING_PART_NUMBER 0x0001
+#define PDR_PDA_VERSION 0x0002
+#define PDR_NIC_SERIAL_NUMBER 0x0003
+
+#define PDR_MAC_ADDRESS 0x0101
+#define PDR_REGULATORY_DOMAIN_LIST 0x0103
+#define PDR_TEMPERATURE_TYPE 0x0107
+
+#define PDR_PRISM_PCI_IDENTIFIER 0x0402
+
+/* ARM range (0x1000 - 0x1fff) */
+#define PDR_COUNTRY_INFORMATION 0x1000
+#define PDR_INTERFACE_LIST 0x1001
+#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002
+#define PDR_OEM_NAME 0x1003
+#define PDR_PRODUCT_NAME 0x1004
+#define PDR_UTF8_OEM_NAME 0x1005
+#define PDR_UTF8_PRODUCT_NAME 0x1006
+#define PDR_COUNTRY_LIST 0x1007
+#define PDR_DEFAULT_COUNTRY 0x1008
+
+#define PDR_ANTENNA_GAIN 0x1100
+
+#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901
+#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903
+#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904
+#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905
+#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906
+#define PDR_REGULATORY_POWER_LIMITS 0x1907
+#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
+#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909
+#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a
+
+/* reserved range (0x2000 - 0x7fff) */
+
+/* customer range (0x8000 - 0xffff) */
+#define PDR_BASEBAND_REGISTERS 0x8000
+#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001
+
+/* stored in skb->cb */
+struct memrecord {
+ u32 start_addr;
+ u32 end_addr;
+ struct ieee80211_tx_control *control;
+};
+
+struct p54_eeprom_lm86 {
+ __le16 offset;
+ __le16 len;
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct p54_rx_hdr {
+ __le16 magic;
+ __le16 len;
+ __le16 freq;
+ u8 antenna;
+ u8 rate;
+ u8 rssi;
+ u8 quality;
+ u16 unknown2;
+ __le64 timestamp;
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct p54_frame_sent_hdr {
+ u8 status;
+ u8 retries;
+ __le16 ack_rssi;
+ __le16 seq;
+ u16 rate;
+} __attribute__ ((packed));
+
+struct p54_tx_control_allocdata {
+ u8 rateset[8];
+ u16 padding;
+ u8 wep_key_present;
+ u8 wep_key_len;
+ u8 wep_key[16];
+ __le32 frame_type;
+ u32 padding2;
+ __le16 magic4;
+ u8 antenna;
+ u8 output_power;
+ __le32 magic5;
+ u8 align[0];
+} __attribute__ ((packed));
+
+struct p54_tx_control_filter {
+ __le16 filter_type;
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ u8 antenna;
+ u8 debug;
+ __le32 magic3;
+ u8 rates[8]; // FIXME: what's this for?
+ __le32 rx_addr;
+ __le16 max_rx;
+ __le16 rxhw;
+ __le16 magic8;
+ __le16 magic9;
+} __attribute__ ((packed));
+
+struct p54_tx_control_channel {
+ __le16 magic1;
+ __le16 magic2;
+ u8 padding1[20];
+ struct pda_iq_autocal_entry iq_autocal;
+ u8 pa_points_per_curve;
+ u8 val_barker;
+ u8 val_bpsk;
+ u8 val_qpsk;
+ u8 val_16qam;
+ u8 val_64qam;
+ struct pda_pa_curve_data_sample_rev1 curve_data[0];
+ /* additional padding/data after curve_data */
+} __attribute__ ((packed));
+
+struct p54_tx_control_led {
+ __le16 mode;
+ __le16 led_temporary;
+ __le16 led_permanent;
+ __le16 duration;
+} __attribute__ ((packed));
+
+struct p54_tx_vdcf_queues {
+ __le16 aifs;
+ __le16 cwmin;
+ __le16 cwmax;
+ __le16 txop;
+} __attribute__ ((packed));
+
+struct p54_tx_control_vdcf {
+ u8 padding;
+ u8 slottime;
+ u8 magic1;
+ u8 magic2;
+ struct p54_tx_vdcf_queues queue[8];
+ u8 pad2[4];
+ __le16 frameburst;
+} __attribute__ ((packed));
+
+static const struct ieee80211_rate p54_rates[] = {
+ { .rate = 10,
+ .val = 0,
+ .val2 = 0x10,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 20,
+ .val = 1,
+ .val2 = 0x11,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 55,
+ .val = 2,
+ .val2 = 0x12,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 110,
+ .val = 3,
+ .val2 = 0x13,
+ .flags = IEEE80211_RATE_CCK_2 },
+ { .rate = 60,
+ .val = 4,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 90,
+ .val = 5,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 120,
+ .val = 6,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 180,
+ .val = 7,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 240,
+ .val = 8,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 360,
+ .val = 9,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 480,
+ .val = 10,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 540,
+ .val = 11,
+ .flags = IEEE80211_RATE_OFDM },
+};
+
+// TODO: just generate this..
+static const struct ieee80211_channel p54_channels[] = {
+ { .chan = 1,
+ .freq = 2412},
+ { .chan = 2,
+ .freq = 2417},
+ { .chan = 3,
+ .freq = 2422},
+ { .chan = 4,
+ .freq = 2427},
+ { .chan = 5,
+ .freq = 2432},
+ { .chan = 6,
+ .freq = 2437},
+ { .chan = 7,
+ .freq = 2442},
+ { .chan = 8,
+ .freq = 2447},
+ { .chan = 9,
+ .freq = 2452},
+ { .chan = 10,
+ .freq = 2457},
+ { .chan = 11,
+ .freq = 2462},
+ { .chan = 12,
+ .freq = 2467},
+ { .chan = 13,
+ .freq = 2472},
+ { .chan = 14,
+ .freq = 2484}
+};
+
+#endif /* PRISM54COMMON_H */
diff --git a/drivers/net/wireless/p54pci.c b/drivers/net/wireless/p54pci.c
new file mode 100644
index 00000000000..410b54387f2
--- /dev/null
+++ b/drivers/net/wireless/p54pci.c
@@ -0,0 +1,692 @@
+
+/*
+ * Linux device driver for PCI based Prism54
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jean-baptiste.note@m4x.org>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "p54pci.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Prism54 PCI wireless driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54pci");
+
+static struct pci_device_id p54p_table[] __devinitdata = {
+ /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
+ { PCI_DEVICE(0x1260, 0x3890) },
+ /* 3COM 3CRWE154G72 Wireless LAN adapter */
+ { PCI_DEVICE(0x10b7, 0x6001) },
+ /* Intersil PRISM Indigo Wireless LAN adapter */
+ { PCI_DEVICE(0x1260, 0x3877) },
+ /* Intersil PRISM Javelin/Xbow Wireless LAN adapter */
+ { PCI_DEVICE(0x1260, 0x3886) },
+ { },
+};
+
+MODULE_DEVICE_TABLE(pci, p54p_table);
+
+static int p54p_upload_firmware(struct ieee80211_hw *dev)
+{
+ struct p54p_priv *priv = dev->priv;
+ const struct firmware *fw_entry = NULL;
+ __le32 reg;
+ int err;
+ u32 *data;
+ u32 remains, left, device_addr;
+
+ P54P_WRITE(int_enable, 0);
+ P54P_READ(int_enable);
+ udelay(10);
+
+ reg = P54P_READ(ctrl_stat);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
+ P54P_WRITE(ctrl_stat, reg);
+ P54P_READ(ctrl_stat);
+ udelay(10);
+
+ reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+ P54P_WRITE(ctrl_stat, reg);
+ wmb();
+ udelay(10);
+
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ P54P_WRITE(ctrl_stat, reg);
+ wmb();
+
+ mdelay(50);
+
+ err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev);
+ if (err) {
+ printk(KERN_ERR "%s (prism54pci): cannot find firmware "
+ "(isl3886)\n", pci_name(priv->pdev));
+ return err;
+ }
+
+ p54_parse_firmware(dev, fw_entry);
+
+ data = (u32 *) fw_entry->data;
+ remains = fw_entry->size;
+ device_addr = ISL38XX_DEV_FIRMWARE_ADDR;
+ while (remains) {
+ u32 i = 0;
+ left = min((u32)0x1000, remains);
+ P54P_WRITE(direct_mem_base, cpu_to_le32(device_addr));
+ P54P_READ(int_enable);
+
+ device_addr += 0x1000;
+ while (i < left) {
+ P54P_WRITE(direct_mem_win[i], *data++);
+ i += sizeof(u32);
+ }
+
+ remains -= left;
+ P54P_READ(int_enable);
+ }
+
+ release_firmware(fw_entry);
+
+ reg = P54P_READ(ctrl_stat);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
+ P54P_WRITE(ctrl_stat, reg);
+ P54P_READ(ctrl_stat);
+ udelay(10);
+
+ reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+ P54P_WRITE(ctrl_stat, reg);
+ wmb();
+ udelay(10);
+
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ P54P_WRITE(ctrl_stat, reg);
+ wmb();
+ udelay(10);
+
+ return 0;
+}
+
+static irqreturn_t p54p_simple_interrupt(int irq, void *dev_id)
+{
+ struct p54p_priv *priv = (struct p54p_priv *) dev_id;
+ __le32 reg;
+
+ reg = P54P_READ(int_ident);
+ P54P_WRITE(int_ack, reg);
+
+ if (reg & P54P_READ(int_enable))
+ complete(&priv->boot_comp);
+
+ return IRQ_HANDLED;
+}
+
+static int p54p_read_eeprom(struct ieee80211_hw *dev)
+{
+ struct p54p_priv *priv = dev->priv;
+ int err;
+ struct p54_control_hdr *hdr;
+ void *eeprom;
+ dma_addr_t rx_mapping, tx_mapping;
+ u16 alen;
+
+ init_completion(&priv->boot_comp);
+ err = request_irq(priv->pdev->irq, &p54p_simple_interrupt,
+ IRQF_SHARED, "prism54pci", priv);
+ if (err) {
+ printk(KERN_ERR "%s (prism54pci): failed to register IRQ handler\n",
+ pci_name(priv->pdev));
+ return err;
+ }
+
+ eeprom = kmalloc(0x2010 + EEPROM_READBACK_LEN, GFP_KERNEL);
+ if (!eeprom) {
+ printk(KERN_ERR "%s (prism54pci): no memory for eeprom!\n",
+ pci_name(priv->pdev));
+ err = -ENOMEM;
+ goto out;
+ }
+
+ memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+ P54P_WRITE(ring_control_base, priv->ring_control_dma);
+ P54P_READ(ring_control_base);
+ udelay(10);
+
+ P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT));
+ P54P_READ(int_enable);
+ udelay(10);
+
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+
+ if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
+ printk(KERN_ERR "%s (prism54pci): Cannot boot firmware!\n",
+ pci_name(priv->pdev));
+ err = -EINVAL;
+ goto out;
+ }
+
+ P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
+ P54P_READ(int_enable);
+
+ hdr = eeprom + 0x2010;
+ p54_fill_eeprom_readback(hdr);
+ hdr->req_id = cpu_to_le32(priv->common.rx_start);
+
+ rx_mapping = pci_map_single(priv->pdev, eeprom,
+ 0x2010, PCI_DMA_FROMDEVICE);
+ tx_mapping = pci_map_single(priv->pdev, (void *)hdr,
+ EEPROM_READBACK_LEN, PCI_DMA_TODEVICE);
+
+ priv->ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping);
+ priv->ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010);
+ priv->ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping);
+ priv->ring_control->tx_data[0].device_addr = hdr->req_id;
+ priv->ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN);
+
+ priv->ring_control->host_idx[2] = cpu_to_le32(1);
+ priv->ring_control->host_idx[1] = cpu_to_le32(1);
+
+ wmb();
+ mdelay(100);
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+
+ wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ);
+ wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ);
+
+ pci_unmap_single(priv->pdev, tx_mapping,
+ EEPROM_READBACK_LEN, PCI_DMA_TODEVICE);
+ pci_unmap_single(priv->pdev, rx_mapping,
+ 0x2010, PCI_DMA_FROMDEVICE);
+
+ alen = le16_to_cpu(priv->ring_control->rx_mgmt[0].len);
+ if (le32_to_cpu(priv->ring_control->device_idx[2]) != 1 ||
+ alen < 0x10) {
+ printk(KERN_ERR "%s (prism54pci): Cannot read eeprom!\n",
+ pci_name(priv->pdev));
+ err = -EINVAL;
+ goto out;
+ }
+
+ p54_parse_eeprom(dev, (u8 *)eeprom + 0x10, alen - 0x10);
+
+ out:
+ kfree(eeprom);
+ P54P_WRITE(int_enable, 0);
+ P54P_READ(int_enable);
+ udelay(10);
+ free_irq(priv->pdev->irq, priv);
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+ return err;
+}
+
+static void p54p_refill_rx_ring(struct ieee80211_hw *dev)
+{
+ struct p54p_priv *priv = dev->priv;
+ u32 limit, host_idx, idx;
+
+ host_idx = le32_to_cpu(priv->ring_control->host_idx[0]);
+ limit = host_idx;
+ limit -= le32_to_cpu(priv->ring_control->device_idx[0]);
+ limit = ARRAY_SIZE(priv->ring_control->rx_data) - limit;
+
+ idx = host_idx % ARRAY_SIZE(priv->ring_control->rx_data);
+ while (limit-- > 1) {
+ struct p54p_desc *desc = &priv->ring_control->rx_data[idx];
+
+ if (!desc->host_addr) {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+ skb = dev_alloc_skb(MAX_RX_SIZE);
+ if (!skb)
+ break;
+
+ mapping = pci_map_single(priv->pdev,
+ skb_tail_pointer(skb),
+ MAX_RX_SIZE,
+ PCI_DMA_FROMDEVICE);
+ desc->host_addr = cpu_to_le32(mapping);
+ desc->device_addr = 0; // FIXME: necessary?
+ desc->len = cpu_to_le16(MAX_RX_SIZE);
+ desc->flags = 0;
+ priv->rx_buf[idx] = skb;
+ }
+
+ idx++;
+ host_idx++;
+ idx %= ARRAY_SIZE(priv->ring_control->rx_data);
+ }
+
+ wmb();
+ priv->ring_control->host_idx[0] = cpu_to_le32(host_idx);
+}
+
+static irqreturn_t p54p_interrupt(int irq, void *dev_id)
+{
+ struct ieee80211_hw *dev = dev_id;
+ struct p54p_priv *priv = dev->priv;
+ __le32 reg;
+
+ spin_lock(&priv->lock);
+ reg = P54P_READ(int_ident);
+ if (unlikely(reg == 0xFFFFFFFF)) {
+ spin_unlock(&priv->lock);
+ return IRQ_HANDLED;
+ }
+
+ P54P_WRITE(int_ack, reg);
+
+ reg &= P54P_READ(int_enable);
+
+ if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) {
+ struct p54p_desc *desc;
+ u32 idx, i;
+ i = priv->tx_idx;
+ i %= ARRAY_SIZE(priv->ring_control->tx_data);
+ priv->tx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[1]);
+ idx %= ARRAY_SIZE(priv->ring_control->tx_data);
+
+ while (i != idx) {
+ desc = &priv->ring_control->tx_data[i];
+ if (priv->tx_buf[i]) {
+ kfree(priv->tx_buf[i]);
+ priv->tx_buf[i] = NULL;
+ }
+
+ pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
+ le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
+
+ desc->host_addr = 0;
+ desc->device_addr = 0;
+ desc->len = 0;
+ desc->flags = 0;
+
+ i++;
+ i %= ARRAY_SIZE(priv->ring_control->tx_data);
+ }
+
+ i = priv->rx_idx;
+ i %= ARRAY_SIZE(priv->ring_control->rx_data);
+ priv->rx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[0]);
+ idx %= ARRAY_SIZE(priv->ring_control->rx_data);
+ while (i != idx) {
+ u16 len;
+ struct sk_buff *skb;
+ desc = &priv->ring_control->rx_data[i];
+ len = le16_to_cpu(desc->len);
+ skb = priv->rx_buf[i];
+
+ skb_put(skb, len);
+
+ if (p54_rx(dev, skb)) {
+ pci_unmap_single(priv->pdev,
+ le32_to_cpu(desc->host_addr),
+ MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+
+ priv->rx_buf[i] = NULL;
+ desc->host_addr = 0;
+ } else {
+ skb_trim(skb, 0);
+ desc->len = cpu_to_le16(MAX_RX_SIZE);
+ }
+
+ i++;
+ i %= ARRAY_SIZE(priv->ring_control->rx_data);
+ }
+
+ p54p_refill_rx_ring(dev);
+
+ wmb();
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+ } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))
+ complete(&priv->boot_comp);
+
+ spin_unlock(&priv->lock);
+
+ return reg ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data,
+ size_t len, int free_on_tx)
+{
+ struct p54p_priv *priv = dev->priv;
+ unsigned long flags;
+ struct p54p_desc *desc;
+ dma_addr_t mapping;
+ u32 device_idx, idx, i;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ device_idx = le32_to_cpu(priv->ring_control->device_idx[1]);
+ idx = le32_to_cpu(priv->ring_control->host_idx[1]);
+ i = idx % ARRAY_SIZE(priv->ring_control->tx_data);
+
+ mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE);
+ desc = &priv->ring_control->tx_data[i];
+ desc->host_addr = cpu_to_le32(mapping);
+ desc->device_addr = data->req_id;
+ desc->len = cpu_to_le16(len);
+ desc->flags = 0;
+
+ wmb();
+ priv->ring_control->host_idx[1] = cpu_to_le32(idx + 1);
+
+ if (free_on_tx)
+ priv->tx_buf[i] = data;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+ P54P_READ(dev_int);
+
+ /* FIXME: unlikely to happen because the device usually runs out of
+ memory before we fill the ring up, but we can make it impossible */
+ if (idx - device_idx > ARRAY_SIZE(priv->ring_control->tx_data) - 2)
+ printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy));
+}
+
+static int p54p_open(struct ieee80211_hw *dev)
+{
+ struct p54p_priv *priv = dev->priv;
+ int err;
+
+ init_completion(&priv->boot_comp);
+ err = request_irq(priv->pdev->irq, &p54p_interrupt,
+ IRQF_SHARED, "prism54pci", dev);
+ if (err) {
+ printk(KERN_ERR "%s: failed to register IRQ handler\n",
+ wiphy_name(dev->wiphy));
+ return err;
+ }
+
+ memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+ priv->rx_idx = priv->tx_idx = 0;
+ p54p_refill_rx_ring(dev);
+
+ p54p_upload_firmware(dev);
+
+ P54P_WRITE(ring_control_base, priv->ring_control_dma);
+ P54P_READ(ring_control_base);
+ wmb();
+ udelay(10);
+
+ P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT));
+ P54P_READ(int_enable);
+ wmb();
+ udelay(10);
+
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+ P54P_READ(dev_int);
+
+ if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
+ printk(KERN_ERR "%s: Cannot boot firmware!\n",
+ wiphy_name(dev->wiphy));
+ free_irq(priv->pdev->irq, dev);
+ return -ETIMEDOUT;
+ }
+
+ P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
+ P54P_READ(int_enable);
+ wmb();
+ udelay(10);
+
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+ P54P_READ(dev_int);
+ wmb();
+ udelay(10);
+
+ return 0;
+}
+
+static void p54p_stop(struct ieee80211_hw *dev)
+{
+ struct p54p_priv *priv = dev->priv;
+ unsigned int i;
+ struct p54p_desc *desc;
+
+ P54P_WRITE(int_enable, 0);
+ P54P_READ(int_enable);
+ udelay(10);
+
+ free_irq(priv->pdev->irq, dev);
+
+ P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+
+ for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) {
+ desc = &priv->ring_control->rx_data[i];
+ if (desc->host_addr)
+ pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
+ MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+ kfree_skb(priv->rx_buf[i]);
+ priv->rx_buf[i] = NULL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) {
+ desc = &priv->ring_control->tx_data[i];
+ if (desc->host_addr)
+ pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
+ le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
+
+ kfree(priv->tx_buf[i]);
+ priv->tx_buf[i] = NULL;
+ }
+
+ memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+}
+
+static int __devinit p54p_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct p54p_priv *priv;
+ struct ieee80211_hw *dev;
+ unsigned long mem_addr, mem_len;
+ int err;
+ DECLARE_MAC_BUF(mac);
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR "%s (prism54pci): Cannot enable new PCI device\n",
+ pci_name(pdev));
+ return err;
+ }
+
+ mem_addr = pci_resource_start(pdev, 0);
+ mem_len = pci_resource_len(pdev, 0);
+ if (mem_len < sizeof(struct p54p_csr)) {
+ printk(KERN_ERR "%s (prism54pci): Too short PCI resources\n",
+ pci_name(pdev));
+ pci_disable_device(pdev);
+ return err;
+ }
+
+ err = pci_request_regions(pdev, "prism54pci");
+ if (err) {
+ printk(KERN_ERR "%s (prism54pci): Cannot obtain PCI resources\n",
+ pci_name(pdev));
+ return err;
+ }
+
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
+ pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+ printk(KERN_ERR "%s (prism54pci): No suitable DMA available\n",
+ pci_name(pdev));
+ goto err_free_reg;
+ }
+
+ pci_set_master(pdev);
+ pci_try_set_mwi(pdev);
+
+ pci_write_config_byte(pdev, 0x40, 0);
+ pci_write_config_byte(pdev, 0x41, 0);
+
+ dev = p54_init_common(sizeof(*priv));
+ if (!dev) {
+ printk(KERN_ERR "%s (prism54pci): ieee80211 alloc failed\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto err_free_reg;
+ }
+
+ priv = dev->priv;
+ priv->pdev = pdev;
+
+ SET_IEEE80211_DEV(dev, &pdev->dev);
+ pci_set_drvdata(pdev, dev);
+
+ priv->map = ioremap(mem_addr, mem_len);
+ if (!priv->map) {
+ printk(KERN_ERR "%s (prism54pci): Cannot map device memory\n",
+ pci_name(pdev));
+ err = -EINVAL; // TODO: use a better error code?
+ goto err_free_dev;
+ }
+
+ priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control),
+ &priv->ring_control_dma);
+ if (!priv->ring_control) {
+ printk(KERN_ERR "%s (prism54pci): Cannot allocate rings\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto err_iounmap;
+ }
+ memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+
+ err = p54p_upload_firmware(dev);
+ if (err)
+ goto err_free_desc;
+
+ err = p54p_read_eeprom(dev);
+ if (err)
+ goto err_free_desc;
+
+ priv->common.open = p54p_open;
+ priv->common.stop = p54p_stop;
+ priv->common.tx = p54p_tx;
+
+ spin_lock_init(&priv->lock);
+
+ err = ieee80211_register_hw(dev);
+ if (err) {
+ printk(KERN_ERR "%s (prism54pci): Cannot register netdevice\n",
+ pci_name(pdev));
+ goto err_free_common;
+ }
+
+ printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n",
+ wiphy_name(dev->wiphy),
+ print_mac(mac, dev->wiphy->perm_addr),
+ priv->common.version);
+
+ return 0;
+
+ err_free_common:
+ p54_free_common(dev);
+
+ err_free_desc:
+ pci_free_consistent(pdev, sizeof(*priv->ring_control),
+ priv->ring_control, priv->ring_control_dma);
+
+ err_iounmap:
+ iounmap(priv->map);
+
+ err_free_dev:
+ pci_set_drvdata(pdev, NULL);
+ ieee80211_free_hw(dev);
+
+ err_free_reg:
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ return err;
+}
+
+static void __devexit p54p_remove(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+ struct p54p_priv *priv;
+
+ if (!dev)
+ return;
+
+ ieee80211_unregister_hw(dev);
+ priv = dev->priv;
+ pci_free_consistent(pdev, sizeof(*priv->ring_control),
+ priv->ring_control, priv->ring_control_dma);
+ p54_free_common(dev);
+ iounmap(priv->map);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ ieee80211_free_hw(dev);
+}
+
+#ifdef CONFIG_PM
+static int p54p_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+ struct p54p_priv *priv = dev->priv;
+
+ if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) {
+ ieee80211_stop_queues(dev);
+ p54p_stop(dev);
+ }
+
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return 0;
+}
+
+static int p54p_resume(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+ struct p54p_priv *priv = dev->priv;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) {
+ p54p_open(dev);
+ ieee80211_start_queues(dev);
+ }
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct pci_driver p54p_driver = {
+ .name = "prism54pci",
+ .id_table = p54p_table,
+ .probe = p54p_probe,
+ .remove = __devexit_p(p54p_remove),
+#ifdef CONFIG_PM
+ .suspend = p54p_suspend,
+ .resume = p54p_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init p54p_init(void)
+{
+ return pci_register_driver(&p54p_driver);
+}
+
+static void __exit p54p_exit(void)
+{
+ pci_unregister_driver(&p54p_driver);
+}
+
+module_init(p54p_init);
+module_exit(p54p_exit);
diff --git a/drivers/net/wireless/p54pci.h b/drivers/net/wireless/p54pci.h
new file mode 100644
index 00000000000..52feb597dc4
--- /dev/null
+++ b/drivers/net/wireless/p54pci.h
@@ -0,0 +1,106 @@
+#ifndef PRISM54PCI_H
+#define PRISM54PCI_H
+
+/*
+ * Defines for PCI based mac80211 Prism54 driver
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Device Interrupt register bits */
+#define ISL38XX_DEV_INT_RESET 0x0001
+#define ISL38XX_DEV_INT_UPDATE 0x0002
+#define ISL38XX_DEV_INT_WAKEUP 0x0008
+#define ISL38XX_DEV_INT_SLEEP 0x0010
+#define ISL38XX_DEV_INT_ABORT 0x0020
+/* these two only used in USB */
+#define ISL38XX_DEV_INT_DATA 0x0040
+#define ISL38XX_DEV_INT_MGMT 0x0080
+
+#define ISL38XX_DEV_INT_PCIUART_CTS 0x4000
+#define ISL38XX_DEV_INT_PCIUART_DR 0x8000
+
+/* Interrupt Identification/Acknowledge/Enable register bits */
+#define ISL38XX_INT_IDENT_UPDATE 0x0002
+#define ISL38XX_INT_IDENT_INIT 0x0004
+#define ISL38XX_INT_IDENT_WAKEUP 0x0008
+#define ISL38XX_INT_IDENT_SLEEP 0x0010
+#define ISL38XX_INT_IDENT_PCIUART_CTS 0x4000
+#define ISL38XX_INT_IDENT_PCIUART_DR 0x8000
+
+/* Control/Status register bits */
+#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200
+#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000
+#define ISL38XX_CTRL_STAT_RESET 0x10000000
+#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000
+#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000
+#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000
+
+struct p54p_csr {
+ __le32 dev_int;
+ u8 unused_1[12];
+ __le32 int_ident;
+ __le32 int_ack;
+ __le32 int_enable;
+ u8 unused_2[4];
+ union {
+ __le32 ring_control_base;
+ __le32 gen_purp_com[2];
+ };
+ u8 unused_3[8];
+ __le32 direct_mem_base;
+ u8 unused_4[44];
+ __le32 dma_addr;
+ __le32 dma_len;
+ __le32 dma_ctrl;
+ u8 unused_5[12];
+ __le32 ctrl_stat;
+ u8 unused_6[1924];
+ u8 cardbus_cis[0x800];
+ u8 direct_mem_win[0x1000];
+} __attribute__ ((packed));
+
+/* usb backend only needs the register defines above */
+#ifndef PRISM54USB_H
+struct p54p_desc {
+ __le32 host_addr;
+ __le32 device_addr;
+ __le16 len;
+ __le16 flags;
+} __attribute__ ((packed));
+
+struct p54p_ring_control {
+ __le32 host_idx[4];
+ __le32 device_idx[4];
+ struct p54p_desc rx_data[8];
+ struct p54p_desc tx_data[32];
+ struct p54p_desc rx_mgmt[4];
+ struct p54p_desc tx_mgmt[4];
+} __attribute__ ((packed));
+
+#define P54P_READ(r) __raw_readl(&priv->map->r)
+#define P54P_WRITE(r, val) __raw_writel((__force u32)(val), &priv->map->r)
+
+struct p54p_priv {
+ struct p54_common common;
+ struct pci_dev *pdev;
+ struct p54p_csr __iomem *map;
+
+ spinlock_t lock;
+ struct p54p_ring_control *ring_control;
+ dma_addr_t ring_control_dma;
+ u32 rx_idx, tx_idx;
+ struct sk_buff *rx_buf[8];
+ void *tx_buf[32];
+ struct completion boot_comp;
+};
+
+#endif /* PRISM54USB_H */
+#endif /* PRISM54PCI_H */
diff --git a/drivers/net/wireless/p54usb.c b/drivers/net/wireless/p54usb.c
new file mode 100644
index 00000000000..755482a5a93
--- /dev/null
+++ b/drivers/net/wireless/p54usb.c
@@ -0,0 +1,907 @@
+
+/*
+ * Linux device driver for USB based Prism54
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/usb.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "p54usb.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Prism54 USB wireless driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54usb");
+
+static struct usb_device_id p54u_table[] __devinitdata = {
+ /* Version 1 devices (pci chip + net2280) */
+ {USB_DEVICE(0x0506, 0x0a11)}, /* 3COM 3CRWE254G72 */
+ {USB_DEVICE(0x0707, 0xee06)}, /* SMC 2862W-G */
+ {USB_DEVICE(0x083a, 0x4501)}, /* Accton 802.11g WN4501 USB */
+ {USB_DEVICE(0x083a, 0x4502)}, /* Siemens Gigaset USB Adapter */
+ {USB_DEVICE(0x0846, 0x4200)}, /* Netgear WG121 */
+ {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */
+ {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */
+ {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */
+ {USB_DEVICE(0x124a, 0x4023)}, /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
+ {USB_DEVICE(0x1915, 0x2234)}, /* Linksys WUSB54G OEM */
+ {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */
+ {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */
+ {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */
+ {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */
+ {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */
+
+ /* Version 2 devices (3887) */
+ {USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
+ {USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
+ {USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
+ {USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
+ {USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
+ {USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
+ {USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
+ {USB_DEVICE(0x0915, 0x2002)}, /* Cohiba Proto board */
+ {USB_DEVICE(0x0baf, 0x0118)}, /* U.S. Robotics U5 802.11g Adapter*/
+ {USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
+ {USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
+ {USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
+ {USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
+ {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */
+ {USB_DEVICE(0x13B1, 0x000C)}, /* Linksys WUSB54AG */
+ {USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
+ {USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
+ {USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
+ {USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, p54u_table);
+
+static void p54u_rx_cb(struct urb *urb)
+{
+ struct sk_buff *skb = (struct sk_buff *) urb->context;
+ struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
+ struct ieee80211_hw *dev = info->dev;
+ struct p54u_priv *priv = dev->priv;
+
+ if (unlikely(urb->status)) {
+ info->urb = NULL;
+ usb_free_urb(urb);
+ return;
+ }
+
+ skb_unlink(skb, &priv->rx_queue);
+ skb_put(skb, urb->actual_length);
+ if (!priv->hw_type)
+ skb_pull(skb, sizeof(struct net2280_tx_hdr));
+
+ if (p54_rx(dev, skb)) {
+ skb = dev_alloc_skb(MAX_RX_SIZE);
+ if (unlikely(!skb)) {
+ usb_free_urb(urb);
+ /* TODO check rx queue length and refill *somewhere* */
+ return;
+ }
+
+ info = (struct p54u_rx_info *) skb->cb;
+ info->urb = urb;
+ info->dev = dev;
+ urb->transfer_buffer = skb_tail_pointer(skb);
+ urb->context = skb;
+ skb_queue_tail(&priv->rx_queue, skb);
+ } else {
+ skb_trim(skb, 0);
+ skb_queue_tail(&priv->rx_queue, skb);
+ }
+
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static void p54u_tx_cb(struct urb *urb)
+{
+ usb_free_urb(urb);
+}
+
+static void p54u_tx_free_cb(struct urb *urb)
+{
+ kfree(urb->transfer_buffer);
+ usb_free_urb(urb);
+}
+
+static int p54u_init_urbs(struct ieee80211_hw *dev)
+{
+ struct p54u_priv *priv = dev->priv;
+ struct urb *entry;
+ struct sk_buff *skb;
+ struct p54u_rx_info *info;
+
+ while (skb_queue_len(&priv->rx_queue) < 32) {
+ skb = __dev_alloc_skb(MAX_RX_SIZE, GFP_KERNEL);
+ if (!skb)
+ break;
+ entry = usb_alloc_urb(0, GFP_KERNEL);
+ if (!entry) {
+ kfree_skb(skb);
+ break;
+ }
+ usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), MAX_RX_SIZE, p54u_rx_cb, skb);
+ info = (struct p54u_rx_info *) skb->cb;
+ info->urb = entry;
+ info->dev = dev;
+ skb_queue_tail(&priv->rx_queue, skb);
+ usb_submit_urb(entry, GFP_KERNEL);
+ }
+
+ return 0;
+}
+
+static void p54u_free_urbs(struct ieee80211_hw *dev)
+{
+ struct p54u_priv *priv = dev->priv;
+ struct p54u_rx_info *info;
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&priv->rx_queue))) {
+ info = (struct p54u_rx_info *) skb->cb;
+ if (!info->urb)
+ continue;
+
+ usb_kill_urb(info->urb);
+ kfree_skb(skb);
+ }
+}
+
+static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data,
+ size_t len, int free_on_tx)
+{
+ struct p54u_priv *priv = dev->priv;
+ struct urb *addr_urb, *data_urb;
+
+ addr_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!addr_urb)
+ return;
+
+ data_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!data_urb) {
+ usb_free_urb(addr_urb);
+ return;
+ }
+
+ usb_fill_bulk_urb(addr_urb, priv->udev,
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id,
+ sizeof(data->req_id), p54u_tx_cb, dev);
+ usb_fill_bulk_urb(data_urb, priv->udev,
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len,
+ free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
+
+ usb_submit_urb(addr_urb, GFP_ATOMIC);
+ usb_submit_urb(data_urb, GFP_ATOMIC);
+}
+
+static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data,
+ size_t len, int free_on_tx)
+{
+ struct p54u_priv *priv = dev->priv;
+ struct urb *int_urb, *data_urb;
+ struct net2280_tx_hdr *hdr;
+ struct net2280_reg_write *reg;
+
+ reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
+ if (!reg)
+ return;
+
+ int_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!int_urb) {
+ kfree(reg);
+ return;
+ }
+
+ data_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!data_urb) {
+ kfree(reg);
+ usb_free_urb(int_urb);
+ return;
+ }
+
+ reg->port = cpu_to_le16(NET2280_DEV_U32);
+ reg->addr = cpu_to_le32(P54U_DEV_BASE);
+ reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
+
+ len += sizeof(*data);
+ hdr = (void *)data - sizeof(*hdr);
+ memset(hdr, 0, sizeof(*hdr));
+ hdr->device_addr = data->req_id;
+ hdr->len = cpu_to_le16(len);
+
+ usb_fill_bulk_urb(int_urb, priv->udev,
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
+ p54u_tx_free_cb, dev);
+ usb_submit_urb(int_urb, GFP_ATOMIC);
+
+ usb_fill_bulk_urb(data_urb, priv->udev,
+ usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr),
+ free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
+ usb_submit_urb(data_urb, GFP_ATOMIC);
+}
+
+static int p54u_write(struct p54u_priv *priv,
+ struct net2280_reg_write *buf,
+ enum net2280_op_type type,
+ __le32 addr, __le32 val)
+{
+ unsigned int ep;
+ int alen;
+
+ if (type & 0x0800)
+ ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
+ else
+ ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
+
+ buf->port = cpu_to_le16(type);
+ buf->addr = addr;
+ buf->val = val;
+
+ return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
+}
+
+static int p54u_read(struct p54u_priv *priv, void *buf,
+ enum net2280_op_type type,
+ __le32 addr, __le32 *val)
+{
+ struct net2280_reg_read *read = buf;
+ __le32 *reg = buf;
+ unsigned int ep;
+ int alen, err;
+
+ if (type & 0x0800)
+ ep = P54U_PIPE_DEV;
+ else
+ ep = P54U_PIPE_BRG;
+
+ read->port = cpu_to_le16(type);
+ read->addr = addr;
+
+ err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
+ read, sizeof(*read), &alen, 1000);
+ if (err)
+ return err;
+
+ err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
+ reg, sizeof(*reg), &alen, 1000);
+ if (err)
+ return err;
+
+ *val = *reg;
+ return 0;
+}
+
+static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
+ void *data, size_t len)
+{
+ int alen;
+ return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
+ data, len, &alen, 2000);
+}
+
+static int p54u_read_eeprom(struct ieee80211_hw *dev)
+{
+ struct p54u_priv *priv = dev->priv;
+ void *buf;
+ struct p54_control_hdr *hdr;
+ int err, alen;
+ size_t offset = priv->hw_type ? 0x10 : 0x20;
+
+ buf = kmalloc(0x2020, GFP_KERNEL);
+ if (!buf) {
+ printk(KERN_ERR "prism54usb: cannot allocate memory for"
+ "eeprom readback!\n");
+ return -ENOMEM;
+ }
+
+ if (priv->hw_type) {
+ *((u32 *) buf) = priv->common.rx_start;
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
+ if (err) {
+ printk(KERN_ERR "prism54usb: addr send failed\n");
+ goto fail;
+ }
+ } else {
+ struct net2280_reg_write *reg = buf;
+ reg->port = cpu_to_le16(NET2280_DEV_U32);
+ reg->addr = cpu_to_le32(P54U_DEV_BASE);
+ reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
+ err = p54u_bulk_msg(priv, P54U_PIPE_DEV, buf, sizeof(*reg));
+ if (err) {
+ printk(KERN_ERR "prism54usb: dev_int send failed\n");
+ goto fail;
+ }
+ }
+
+ hdr = buf + priv->common.tx_hdr_len;
+ p54_fill_eeprom_readback(hdr);
+ hdr->req_id = cpu_to_le32(priv->common.rx_start);
+ if (priv->common.tx_hdr_len) {
+ struct net2280_tx_hdr *tx_hdr = buf;
+ tx_hdr->device_addr = hdr->req_id;
+ tx_hdr->len = cpu_to_le16(EEPROM_READBACK_LEN);
+ }
+
+ /* we can just pretend to send 0x2000 bytes of nothing in the headers */
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf,
+ EEPROM_READBACK_LEN + priv->common.tx_hdr_len);
+ if (err) {
+ printk(KERN_ERR "prism54usb: eeprom req send failed\n");
+ goto fail;
+ }
+
+ err = usb_bulk_msg(priv->udev,
+ usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
+ buf, 0x2020, &alen, 1000);
+ if (!err && alen > offset) {
+ p54_parse_eeprom(dev, (u8 *)buf + offset, alen - offset);
+ } else {
+ printk(KERN_ERR "prism54usb: eeprom read failed!\n");
+ err = -EINVAL;
+ goto fail;
+ }
+
+ fail:
+ kfree(buf);
+ return err;
+}
+
+static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
+{
+ static char start_string[] = "~~~~<\r";
+ struct p54u_priv *priv = dev->priv;
+ const struct firmware *fw_entry = NULL;
+ int err, alen;
+ u8 carry = 0;
+ u8 *buf, *tmp, *data;
+ unsigned int left, remains, block_size;
+ struct x2_header *hdr;
+ unsigned long timeout;
+
+ tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
+ if (!buf) {
+ printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n");
+ err = -ENOMEM;
+ goto err_bufalloc;
+ }
+
+ memcpy(buf, start_string, 4);
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
+ if (err) {
+ printk(KERN_ERR "p54usb: reset failed! (%d)\n", err);
+ goto err_reset;
+ }
+
+ err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev);
+ if (err) {
+ printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n");
+ goto err_req_fw_failed;
+ }
+
+ p54_parse_firmware(dev, fw_entry);
+
+ left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
+ strcpy(buf, start_string);
+ left -= strlen(start_string);
+ tmp += strlen(start_string);
+
+ data = fw_entry->data;
+ remains = fw_entry->size;
+
+ hdr = (struct x2_header *)(buf + strlen(start_string));
+ memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
+ hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
+ hdr->fw_length = cpu_to_le32(fw_entry->size);
+ hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
+ sizeof(u32)*2));
+ left -= sizeof(*hdr);
+ tmp += sizeof(*hdr);
+
+ while (remains) {
+ while (left--) {
+ if (carry) {
+ *tmp++ = carry;
+ carry = 0;
+ remains--;
+ continue;
+ }
+ switch (*data) {
+ case '~':
+ *tmp++ = '}';
+ carry = '^';
+ break;
+ case '}':
+ *tmp++ = '}';
+ carry = ']';
+ break;
+ default:
+ *tmp++ = *data;
+ remains--;
+ break;
+ }
+ data++;
+ }
+
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
+ if (err) {
+ printk(KERN_ERR "prism54usb: firmware upload failed!\n");
+ goto err_upload_failed;
+ }
+
+ tmp = buf;
+ left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
+ }
+
+ *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
+ if (err) {
+ printk(KERN_ERR "prism54usb: firmware upload failed!\n");
+ goto err_upload_failed;
+ }
+
+ timeout = jiffies + msecs_to_jiffies(1000);
+ while (!(err = usb_bulk_msg(priv->udev,
+ usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
+ if (alen > 2 && !memcmp(buf, "OK", 2))
+ break;
+
+ if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
+ printk(KERN_INFO "prism54usb: firmware upload failed!\n");
+ err = -EINVAL;
+ break;
+ }
+
+ if (time_after(jiffies, timeout)) {
+ printk(KERN_ERR "prism54usb: firmware boot timed out!\n");
+ err = -ETIMEDOUT;
+ break;
+ }
+ }
+ if (err)
+ goto err_upload_failed;
+
+ buf[0] = 'g';
+ buf[1] = '\r';
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
+ if (err) {
+ printk(KERN_ERR "prism54usb: firmware boot failed!\n");
+ goto err_upload_failed;
+ }
+
+ timeout = jiffies + msecs_to_jiffies(1000);
+ while (!(err = usb_bulk_msg(priv->udev,
+ usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
+ if (alen > 0 && buf[0] == 'g')
+ break;
+
+ if (time_after(jiffies, timeout)) {
+ err = -ETIMEDOUT;
+ break;
+ }
+ }
+ if (err)
+ goto err_upload_failed;
+
+ err_upload_failed:
+ release_firmware(fw_entry);
+ err_req_fw_failed:
+ err_reset:
+ kfree(buf);
+ err_bufalloc:
+ return err;
+}
+
+static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
+{
+ struct p54u_priv *priv = dev->priv;
+ const struct firmware *fw_entry = NULL;
+ const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
+ int err, alen;
+ void *buf;
+ __le32 reg;
+ unsigned int remains, offset;
+ u8 *data;
+
+ buf = kmalloc(512, GFP_KERNEL);
+ if (!buf) {
+ printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n");
+ return -ENOMEM;
+ }
+
+ err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev);
+ if (err) {
+ printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n");
+ kfree(buf);
+ return err;
+ }
+
+ p54_parse_firmware(dev, fw_entry);
+
+#define P54U_WRITE(type, addr, data) \
+ do {\
+ err = p54u_write(priv, buf, type,\
+ cpu_to_le32((u32)(unsigned long)addr), data);\
+ if (err) \
+ goto fail;\
+ } while (0)
+
+#define P54U_READ(type, addr) \
+ do {\
+ err = p54u_read(priv, buf, type,\
+ cpu_to_le32((u32)(unsigned long)addr), &reg);\
+ if (err)\
+ goto fail;\
+ } while (0)
+
+ /* power down net2280 bridge */
+ P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
+ reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
+ reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
+ P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
+
+ mdelay(100);
+
+ /* power up bridge */
+ reg |= cpu_to_le32(P54U_BRG_POWER_UP);
+ reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
+ P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
+
+ mdelay(100);
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
+ cpu_to_le32(NET2280_CLK_30Mhz |
+ NET2280_PCI_ENABLE |
+ NET2280_PCI_SOFT_RESET));
+
+ mdelay(20);
+
+ P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
+ cpu_to_le32(PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER));
+
+ P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
+ cpu_to_le32(NET2280_BASE));
+
+ P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
+ reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
+ P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
+
+ // TODO: we really need this?
+ P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
+ cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
+ P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
+ cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
+
+ P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
+ cpu_to_le32(NET2280_BASE2));
+
+ /* finally done setting up the bridge */
+
+ P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
+ cpu_to_le32(PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER));
+
+ P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
+ P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
+ cpu_to_le32(P54U_DEV_BASE));
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
+ P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
+ cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
+
+ /* do romboot */
+ P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
+
+ P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+ mdelay(20);
+
+ reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+ mdelay(20);
+
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+ mdelay(100);
+
+ P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
+
+ /* finally, we can upload firmware now! */
+ remains = fw_entry->size;
+ data = fw_entry->data;
+ offset = ISL38XX_DEV_FIRMWARE_ADDR;
+
+ while (remains) {
+ unsigned int block_len = min(remains, (unsigned int)512);
+ memcpy(buf, data, block_len);
+
+ err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
+ if (err) {
+ printk(KERN_ERR "prism54usb: firmware block upload "
+ "failed\n");
+ goto fail;
+ }
+
+ P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
+ cpu_to_le32(0xc0000f00));
+
+ P54U_WRITE(NET2280_DEV_U32,
+ 0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
+ P54U_WRITE(NET2280_DEV_U32,
+ 0x0020 | (unsigned long)&devreg->direct_mem_win,
+ cpu_to_le32(1));
+
+ P54U_WRITE(NET2280_DEV_U32,
+ 0x0024 | (unsigned long)&devreg->direct_mem_win,
+ cpu_to_le32(block_len));
+ P54U_WRITE(NET2280_DEV_U32,
+ 0x0028 | (unsigned long)&devreg->direct_mem_win,
+ cpu_to_le32(offset));
+
+ P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
+ cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
+ P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
+ cpu_to_le32(block_len >> 2));
+ P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
+ cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
+
+ mdelay(10);
+
+ P54U_READ(NET2280_DEV_U32,
+ 0x002C | (unsigned long)&devreg->direct_mem_win);
+ if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
+ !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
+ printk(KERN_ERR "prism54usb: firmware DMA transfer "
+ "failed\n");
+ goto fail;
+ }
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
+ cpu_to_le32(NET2280_FIFO_FLUSH));
+
+ remains -= block_len;
+ data += block_len;
+ offset += block_len;
+ }
+
+ /* do ramboot */
+ P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
+ reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+ mdelay(20);
+
+ reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+ reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+ mdelay(100);
+
+ P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
+
+ /* start up the firmware */
+ P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
+ cpu_to_le32(ISL38XX_INT_IDENT_INIT));
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
+ cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
+ cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
+ NET2280_USB_INTERRUPT_ENABLE));
+
+ P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
+ cpu_to_le32(ISL38XX_DEV_INT_RESET));
+
+ err = usb_interrupt_msg(priv->udev,
+ usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
+ buf, sizeof(__le32), &alen, 1000);
+ if (err || alen != sizeof(__le32))
+ goto fail;
+
+ P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
+ P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
+
+ if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
+ err = -EINVAL;
+
+ P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
+ P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
+ cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
+
+#undef P54U_WRITE
+#undef P54U_READ
+
+ fail:
+ release_firmware(fw_entry);
+ kfree(buf);
+ return err;
+}
+
+static int p54u_open(struct ieee80211_hw *dev)
+{
+ struct p54u_priv *priv = dev->priv;
+ int err;
+
+ err = p54u_init_urbs(dev);
+ if (err) {
+ return err;
+ }
+
+ priv->common.open = p54u_init_urbs;
+
+ return 0;
+}
+
+static void p54u_stop(struct ieee80211_hw *dev)
+{
+ /* TODO: figure out how to reliably stop the 3887 and net2280 so
+ the hardware is still usable next time we want to start it.
+ until then, we just stop listening to the hardware.. */
+ p54u_free_urbs(dev);
+ return;
+}
+
+static int __devinit p54u_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct ieee80211_hw *dev;
+ struct p54u_priv *priv;
+ int err;
+ unsigned int i, recognized_pipes;
+ DECLARE_MAC_BUF(mac);
+
+ dev = p54_init_common(sizeof(*priv));
+ if (!dev) {
+ printk(KERN_ERR "prism54usb: ieee80211 alloc failed\n");
+ return -ENOMEM;
+ }
+
+ priv = dev->priv;
+
+ SET_IEEE80211_DEV(dev, &intf->dev);
+ usb_set_intfdata(intf, dev);
+ priv->udev = udev;
+
+ usb_get_dev(udev);
+
+ /* really lazy and simple way of figuring out if we're a 3887 */
+ /* TODO: should just stick the identification in the device table */
+ i = intf->altsetting->desc.bNumEndpoints;
+ recognized_pipes = 0;
+ while (i--) {
+ switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
+ case P54U_PIPE_DATA:
+ case P54U_PIPE_MGMT:
+ case P54U_PIPE_BRG:
+ case P54U_PIPE_DEV:
+ case P54U_PIPE_DATA | USB_DIR_IN:
+ case P54U_PIPE_MGMT | USB_DIR_IN:
+ case P54U_PIPE_BRG | USB_DIR_IN:
+ case P54U_PIPE_DEV | USB_DIR_IN:
+ case P54U_PIPE_INT | USB_DIR_IN:
+ recognized_pipes++;
+ }
+ }
+ priv->common.open = p54u_open;
+
+ if (recognized_pipes < P54U_PIPE_NUMBER) {
+ priv->hw_type = P54U_3887;
+ priv->common.tx = p54u_tx_3887;
+ } else {
+ dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
+ priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
+ priv->common.tx = p54u_tx_net2280;
+ }
+ priv->common.stop = p54u_stop;
+
+ if (priv->hw_type)
+ err = p54u_upload_firmware_3887(dev);
+ else
+ err = p54u_upload_firmware_net2280(dev);
+ if (err)
+ goto err_free_dev;
+
+ err = p54u_read_eeprom(dev);
+ if (err)
+ goto err_free_dev;
+
+ if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+ u8 perm_addr[ETH_ALEN];
+
+ printk(KERN_WARNING "prism54usb: Invalid hwaddr! Using randomly generated MAC addr\n");
+ random_ether_addr(perm_addr);
+ SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+ }
+
+ skb_queue_head_init(&priv->rx_queue);
+
+ err = ieee80211_register_hw(dev);
+ if (err) {
+ printk(KERN_ERR "prism54usb: Cannot register netdevice\n");
+ goto err_free_dev;
+ }
+
+ printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n",
+ wiphy_name(dev->wiphy),
+ print_mac(mac, dev->wiphy->perm_addr),
+ priv->common.version);
+
+ return 0;
+
+ err_free_dev:
+ ieee80211_free_hw(dev);
+ usb_set_intfdata(intf, NULL);
+ usb_put_dev(udev);
+ return err;
+}
+
+static void __devexit p54u_disconnect(struct usb_interface *intf)
+{
+ struct ieee80211_hw *dev = usb_get_intfdata(intf);
+ struct p54u_priv *priv;
+
+ if (!dev)
+ return;
+
+ ieee80211_unregister_hw(dev);
+
+ priv = dev->priv;
+ usb_put_dev(interface_to_usbdev(intf));
+ p54_free_common(dev);
+ ieee80211_free_hw(dev);
+}
+
+static struct usb_driver p54u_driver = {
+ .name = "prism54usb",
+ .id_table = p54u_table,
+ .probe = p54u_probe,
+ .disconnect = p54u_disconnect,
+};
+
+static int __init p54u_init(void)
+{
+ return usb_register(&p54u_driver);
+}
+
+static void __exit p54u_exit(void)
+{
+ usb_deregister(&p54u_driver);
+}
+
+module_init(p54u_init);
+module_exit(p54u_exit);
diff --git a/drivers/net/wireless/p54usb.h b/drivers/net/wireless/p54usb.h
new file mode 100644
index 00000000000..d1896b396c1
--- /dev/null
+++ b/drivers/net/wireless/p54usb.h
@@ -0,0 +1,133 @@
+#ifndef PRISM54USB_H
+#define PRISM54USB_H
+
+/*
+ * Defines for USB based mac80211 Prism54 driver
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* for isl3886 register definitions used on ver 1 devices */
+#include "p54pci.h"
+#include "net2280.h"
+
+/* pci */
+#define NET2280_BASE 0x10000000
+#define NET2280_BASE2 0x20000000
+
+/* gpio */
+#define P54U_BRG_POWER_UP (1 << GPIO0_DATA)
+#define P54U_BRG_POWER_DOWN (1 << GPIO1_DATA)
+
+/* devinit */
+#define NET2280_CLK_4Mhz (15 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_CLK_30Mhz (2 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_CLK_60Mhz (1 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_CLK_STOP (0 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_PCI_ENABLE (1 << PCI_ENABLE)
+#define NET2280_PCI_SOFT_RESET (1 << PCI_SOFT_RESET)
+
+/* endpoints */
+#define NET2280_CLEAR_NAK_OUT_PACKETS_MODE (1 << CLEAR_NAK_OUT_PACKETS_MODE)
+#define NET2280_FIFO_FLUSH (1 << FIFO_FLUSH)
+
+/* irq */
+#define NET2280_USB_INTERRUPT_ENABLE (1 << USB_INTERRUPT_ENABLE)
+#define NET2280_PCI_INTA_INTERRUPT (1 << PCI_INTA_INTERRUPT)
+#define NET2280_PCI_INTA_INTERRUPT_ENABLE (1 << PCI_INTA_INTERRUPT_ENABLE)
+
+/* registers */
+#define NET2280_DEVINIT 0x00
+#define NET2280_USBIRQENB1 0x24
+#define NET2280_IRQSTAT1 0x2c
+#define NET2280_FIFOCTL 0x38
+#define NET2280_GPIOCTL 0x50
+#define NET2280_RELNUM 0x88
+#define NET2280_EPA_RSP 0x324
+#define NET2280_EPA_STAT 0x32c
+#define NET2280_EPB_STAT 0x34c
+#define NET2280_EPC_RSP 0x364
+#define NET2280_EPC_STAT 0x36c
+#define NET2280_EPD_STAT 0x38c
+
+#define NET2280_EPA_CFG 0x320
+#define NET2280_EPB_CFG 0x340
+#define NET2280_EPC_CFG 0x360
+#define NET2280_EPD_CFG 0x380
+#define NET2280_EPE_CFG 0x3A0
+#define NET2280_EPF_CFG 0x3C0
+#define P54U_DEV_BASE 0x40000000
+
+struct net2280_tx_hdr {
+ __le32 device_addr;
+ __le16 len;
+ __le16 follower; /* ? */
+ u8 padding[8];
+} __attribute__((packed));
+
+/* Some flags for the isl hardware registers controlling DMA inside the
+ * chip */
+#define ISL38XX_DMA_STATUS_DONE 0x00000001
+#define ISL38XX_DMA_STATUS_READY 0x00000002
+#define NET2280_EPA_FIFO_PCI_ADDR 0x20000000
+#define ISL38XX_DMA_MASTER_CONTROL_TRIGGER 0x00000004
+
+enum net2280_op_type {
+ NET2280_BRG_U32 = 0x001F,
+ NET2280_BRG_CFG_U32 = 0x000F,
+ NET2280_BRG_CFG_U16 = 0x0003,
+ NET2280_DEV_U32 = 0x080F,
+ NET2280_DEV_CFG_U32 = 0x088F,
+ NET2280_DEV_CFG_U16 = 0x0883
+};
+
+#define P54U_FW_BLOCK 2048
+
+#define X2_SIGNATURE "x2 "
+#define X2_SIGNATURE_SIZE 4
+
+struct x2_header {
+ u8 signature[X2_SIGNATURE_SIZE];
+ __le32 fw_load_addr;
+ __le32 fw_length;
+ __le32 crc;
+} __attribute__((packed));
+
+/* pipes 3 and 4 are not used by the driver */
+#define P54U_PIPE_NUMBER 9
+
+enum p54u_pipe_addr {
+ P54U_PIPE_DATA = 0x01,
+ P54U_PIPE_MGMT = 0x02,
+ P54U_PIPE_3 = 0x03,
+ P54U_PIPE_4 = 0x04,
+ P54U_PIPE_BRG = 0x0d,
+ P54U_PIPE_DEV = 0x0e,
+ P54U_PIPE_INT = 0x0f
+};
+
+struct p54u_rx_info {
+ struct urb *urb;
+ struct ieee80211_hw *dev;
+};
+
+struct p54u_priv {
+ struct p54_common common;
+ struct usb_device *udev;
+ enum {
+ P54U_NET2280 = 0,
+ P54U_3887
+ } hw_type;
+
+ spinlock_t lock;
+ struct sk_buff_head rx_queue;
+};
+
+#endif /* PRISM54USB_H */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 585f5996d29..6d80ca421cf 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -1753,7 +1753,7 @@ prism54_get_oid(struct net_device *ndev, struct iw_request_info *info,
int rvalue;
enum oid_num_t n = dwrq->flags;
- rvalue = mgt_get_request((islpci_private *) ndev->priv, n, 0, NULL, &r);
+ rvalue = mgt_get_request(netdev_priv(ndev), n, 0, NULL, &r);
dwrq->length = mgt_response_to_str(n, &r, extra);
if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32)
kfree(r.ptr);
@@ -1766,7 +1766,7 @@ prism54_set_u32(struct net_device *ndev, struct iw_request_info *info,
{
u32 oid = uwrq[0], u = uwrq[1];
- return mgt_set_request((islpci_private *) ndev->priv, oid, 0, &u);
+ return mgt_set_request(netdev_priv(ndev), oid, 0, &u);
}
static int
@@ -1775,7 +1775,7 @@ prism54_set_raw(struct net_device *ndev, struct iw_request_info *info,
{
u32 oid = dwrq->flags;
- return mgt_set_request((islpci_private *) ndev->priv, oid, 0, extra);
+ return mgt_set_request(netdev_priv(ndev), oid, 0, extra);
}
void
@@ -2029,12 +2029,12 @@ static void
format_event(islpci_private *priv, char *dest, const char *str,
const struct obj_mlme *mlme, u16 *length, int error)
{
- const u8 *a = mlme->address;
+ DECLARE_MAC_BUF(mac);
int n = snprintf(dest, IW_CUSTOM_MAX,
- "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s (%2.2X)",
+ "%s %s %s %s (%2.2X)",
str,
((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"),
- a[0], a[1], a[2], a[3], a[4], a[5],
+ print_mac(mac, mlme->address),
(error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ")
: ""), mlme->code);
BUG_ON(n > IW_CUSTOM_MAX);
@@ -2105,15 +2105,13 @@ struct ieee80211_beacon_phdr {
#define WLAN_EID_GENERIC 0xdd
static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
-#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
-#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
-
static void
prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
u8 *wpa_ie, size_t wpa_ie_len)
{
struct list_head *ptr;
struct islpci_bss_wpa_ie *bss = NULL;
+ DECLARE_MAC_BUF(mac);
if (wpa_ie_len > MAX_WPA_IE_LEN)
wpa_ie_len = MAX_WPA_IE_LEN;
@@ -2154,8 +2152,8 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
bss->wpa_ie_len = wpa_ie_len;
bss->last_update = jiffies;
} else {
- printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR
- "\n", MAC2STR(bssid));
+ printk(KERN_DEBUG "Failed to add BSS WPA entry for "
+ "%s\n", print_mac(mac, bssid));
}
/* expire old entries from WPA list */
@@ -2221,6 +2219,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
{
struct ieee80211_beacon_phdr *hdr;
u8 *pos, *end;
+ DECLARE_MAC_BUF(mac);
if (!priv->wpa)
return;
@@ -2231,7 +2230,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
while (pos < end) {
if (pos + 2 + pos[1] > end) {
printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed "
- "for " MACSTR "\n", MAC2STR(addr));
+ "for %s\n", print_mac(mac, addr));
return;
}
if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
@@ -2270,6 +2269,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
size_t len = 0; /* u16, better? */
u8 *payload = NULL, *pos = NULL;
int ret;
+ DECLARE_MAC_BUF(mac);
/* I think all trapable objects are listed here.
* Some oids have a EX version. The difference is that they are emitted
@@ -2358,14 +2358,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
break;
memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
- printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
- mlmeex->address[0],
- mlmeex->address[1],
- mlmeex->address[2],
- mlmeex->address[3],
- mlmeex->address[4],
- mlmeex->address[5]
- );
+ printk(KERN_DEBUG "Authenticate from: address:\t%s\n",
+ print_mac(mac, mlmeex->address));
confirm->id = -1; /* or mlmeex->id ? */
confirm->state = 0; /* not used */
confirm->code = 0;
@@ -2410,15 +2404,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
if (!wpa_ie_len) {
- printk(KERN_DEBUG "No WPA IE found from "
- "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
- mlmeex->address[0],
- mlmeex->address[1],
- mlmeex->address[2],
- mlmeex->address[3],
- mlmeex->address[4],
- mlmeex->address[5]
- );
+ printk(KERN_DEBUG "No WPA IE found from address:\t%s\n",
+ print_mac(mac, mlmeex->address));
kfree(confirm);
break;
}
@@ -2454,15 +2441,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
if (!wpa_ie_len) {
- printk(KERN_DEBUG "No WPA IE found from "
- "address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
- mlmeex->address[0],
- mlmeex->address[1],
- mlmeex->address[2],
- mlmeex->address[3],
- mlmeex->address[4],
- mlmeex->address[5]
- );
+ printk(KERN_DEBUG "No WPA IE found from address:\t%s\n",
+ print_mac(mac, mlmeex->address));
kfree(confirm);
break;
}
@@ -3239,10 +3219,9 @@ static const iw_handler prism54_private_handler[] = {
};
const struct iw_handler_def prism54_handler_def = {
- .num_standard = sizeof (prism54_handler) / sizeof (iw_handler),
- .num_private = sizeof (prism54_private_handler) / sizeof (iw_handler),
- .num_private_args =
- sizeof (prism54_private_args) / sizeof (struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(prism54_handler),
+ .num_private = ARRAY_SIZE(prism54_private_handler),
+ .num_private_args = ARRAY_SIZE(prism54_private_args),
.standard = (iw_handler *) prism54_handler,
.private = (iw_handler *) prism54_private_handler,
.private_args = (struct iw_priv_args *) prism54_private_args,
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 084795355b7..219dd651dc4 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -808,7 +808,6 @@ islpci_setup(struct pci_dev *pdev)
if (!ndev)
return ndev;
- SET_MODULE_OWNER(ndev);
pci_set_drvdata(pdev, ndev);
#if defined(SET_NETDEV_DEV)
SET_NETDEV_DEV(ndev, &pdev->dev);
diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c
index 42780320cd5..57a4ac34bed 100644
--- a/drivers/net/wireless/prism54/oid_mgt.c
+++ b/drivers/net/wireless/prism54/oid_mgt.c
@@ -244,13 +244,11 @@ mgt_init(islpci_private *priv)
/* Alloc the cache */
for (i = 0; i < OID_NUM_LAST; i++) {
if (isl_oid[i].flags & OID_FLAG_CACHED) {
- priv->mib[i] = kmalloc(isl_oid[i].size *
+ priv->mib[i] = kzalloc(isl_oid[i].size *
(isl_oid[i].range + 1),
GFP_KERNEL);
if (!priv->mib[i])
return -ENOMEM;
- memset(priv->mib[i], 0,
- isl_oid[i].size * (isl_oid[i].range + 1));
} else
priv->mib[i] = NULL;
}
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 3be624295a1..f87fe10059a 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -314,7 +314,7 @@ static int ray_probe(struct pcmcia_device *p_dev)
if (!dev)
goto fail_alloc_dev;
- local = dev->priv;
+ local = netdev_priv(dev);
local->finder = p_dev;
/* The io structure describes IO port mapping. None used here */
@@ -356,7 +356,6 @@ static int ray_probe(struct pcmcia_device *p_dev)
dev->set_multicast_list = &set_multicast_list;
DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n");
- SET_MODULE_OWNER(dev);
dev->init = &ray_dev_init;
dev->open = &ray_open;
dev->stop = &ray_dev_close;
@@ -388,7 +387,7 @@ static void ray_detach(struct pcmcia_device *link)
ray_release(link);
- local = (ray_dev_t *)dev->priv;
+ local = netdev_priv(dev);
del_timer(&local->timer);
if (link->priv) {
@@ -412,7 +411,8 @@ static int ray_config(struct pcmcia_device *link)
win_req_t req;
memreq_t mem;
struct net_device *dev = (struct net_device *)link->priv;
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
+ DECLARE_MAC_BUF(mac);
DEBUG(1, "ray_config(0x%p)\n", link);
@@ -483,10 +483,8 @@ static int ray_config(struct pcmcia_device *link)
strcpy(local->node.dev_name, dev->name);
link->dev_node = &local->node;
- printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ",
- dev->name, dev->irq);
- for (i = 0; i < 6; i++)
- printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+ printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %s\n",
+ dev->name, dev->irq, print_mac(mac, dev->dev_addr));
return 0;
@@ -520,7 +518,7 @@ static int ray_init(struct net_device *dev)
int i;
UCHAR *p;
struct ccs __iomem *pccs;
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
DEBUG(1, "ray_init(0x%p)\n", dev);
if (!(pcmcia_dev_present(link))) {
@@ -581,7 +579,7 @@ static int ray_init(struct net_device *dev)
static int dl_startup_params(struct net_device *dev)
{
int ccsindex;
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct ccs __iomem *pccs;
struct pcmcia_device *link = local->finder;
@@ -786,7 +784,7 @@ static void join_net(u_long data)
static void ray_release(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- ray_dev_t *local = dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
int i;
DEBUG(1, "ray_release(0x%p)\n", link);
@@ -834,7 +832,7 @@ int ray_dev_init(struct net_device *dev)
#ifdef RAY_IMMEDIATE_INIT
int i;
#endif /* RAY_IMMEDIATE_INIT */
- ray_dev_t *local = dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
DEBUG(1,"ray_dev_init(dev=%p)\n",dev);
@@ -868,7 +866,7 @@ int ray_dev_init(struct net_device *dev)
/*===========================================================================*/
static int ray_dev_config(struct net_device *dev, struct ifmap *map)
{
- ray_dev_t *local = dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
/* Dummy routine to satisfy device structure */
DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map);
@@ -882,7 +880,7 @@ static int ray_dev_config(struct net_device *dev, struct ifmap *map)
/*===========================================================================*/
static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- ray_dev_t *local = dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
short length = skb->len;
@@ -925,7 +923,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev,
UCHAR msg_type)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct ccs __iomem *pccs;
int ccsindex;
int offset;
@@ -1099,7 +1097,7 @@ static int ray_set_freq(struct net_device *dev,
struct iw_freq *fwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
/* Reject if card is already initialised */
@@ -1124,7 +1122,7 @@ static int ray_get_freq(struct net_device *dev,
struct iw_freq *fwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
fwrq->m = local->sparm.b5.a_hop_pattern;
fwrq->e = 0;
@@ -1140,7 +1138,7 @@ static int ray_set_essid(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
/* Reject if card is already initialised */
if(local->card_status != CARD_AWAITING_PARAM)
@@ -1173,7 +1171,7 @@ static int ray_get_essid(struct net_device *dev,
struct iw_point *dwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
/* Get the essid that was set */
memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
@@ -1194,7 +1192,7 @@ static int ray_get_wap(struct net_device *dev,
struct sockaddr *awrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
memcpy(awrq->sa_data, local->bss_id, ETH_ALEN);
awrq->sa_family = ARPHRD_ETHER;
@@ -1211,7 +1209,7 @@ static int ray_set_rate(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
/* Reject if card is already initialised */
if(local->card_status != CARD_AWAITING_PARAM)
@@ -1240,7 +1238,7 @@ static int ray_get_rate(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
if(local->net_default_tx_rate == 3)
vwrq->value = 2000000; /* Hum... */
@@ -1260,7 +1258,7 @@ static int ray_set_rts(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
int rthr = vwrq->value;
/* Reject if card is already initialised */
@@ -1290,7 +1288,7 @@ static int ray_get_rts(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
vwrq->value = (local->sparm.b5.a_rts_threshold[0] << 8)
+ local->sparm.b5.a_rts_threshold[1];
@@ -1309,7 +1307,7 @@ static int ray_set_frag(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
int fthr = vwrq->value;
/* Reject if card is already initialised */
@@ -1338,7 +1336,7 @@ static int ray_get_frag(struct net_device *dev,
struct iw_param *vwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
vwrq->value = (local->sparm.b5.a_frag_threshold[0] << 8)
+ local->sparm.b5.a_frag_threshold[1];
@@ -1357,7 +1355,7 @@ static int ray_set_mode(struct net_device *dev,
__u32 *uwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
char card_mode = 1;
@@ -1389,7 +1387,7 @@ static int ray_get_mode(struct net_device *dev,
__u32 *uwrq,
char *extra)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
if(local->sparm.b5.a_network_type)
*uwrq = IW_MODE_INFRA;
@@ -1492,7 +1490,7 @@ static int ray_commit(struct net_device *dev,
*/
static iw_stats * ray_get_wireless_stats(struct net_device * dev)
{
- ray_dev_t * local = (ray_dev_t *) dev->priv;
+ ray_dev_t * local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
struct status __iomem *p = local->sram + STATUS_BASE;
@@ -1568,9 +1566,9 @@ static const struct iw_priv_args ray_private_args[] = {
static const struct iw_handler_def ray_handler_def =
{
- .num_standard = sizeof(ray_handler)/sizeof(iw_handler),
- .num_private = sizeof(ray_private_handler)/sizeof(iw_handler),
- .num_private_args = sizeof(ray_private_args)/sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(ray_handler),
+ .num_private = ARRAY_SIZE(ray_private_handler),
+ .num_private_args = ARRAY_SIZE(ray_private_args),
.standard = ray_handler,
.private = ray_private_handler,
.private_args = ray_private_args,
@@ -1580,7 +1578,7 @@ static const struct iw_handler_def ray_handler_def =
/*===========================================================================*/
static int ray_open(struct net_device *dev)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link;
link = local->finder;
@@ -1614,7 +1612,7 @@ static int ray_open(struct net_device *dev)
/*===========================================================================*/
static int ray_dev_close(struct net_device *dev)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link;
link = local->finder;
@@ -1773,7 +1771,7 @@ static int parse_addr(char *in_str, UCHAR *out)
/*===========================================================================*/
static struct net_device_stats *ray_get_stats(struct net_device *dev)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
struct status __iomem *p = local->sram + STATUS_BASE;
if (!(pcmcia_dev_present(link))) {
@@ -1803,7 +1801,7 @@ static struct net_device_stats *ray_get_stats(struct net_device *dev)
/*===========================================================================*/
static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
int ccsindex;
int i;
@@ -1840,7 +1838,7 @@ static void ray_update_multi_list(struct net_device *dev, int all)
int ccsindex;
struct ccs __iomem *pccs;
int i = 0;
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
struct pcmcia_device *link = local->finder;
void __iomem *p = local->sram + HOST_TO_ECF_BASE;
@@ -1884,7 +1882,7 @@ static void ray_update_multi_list(struct net_device *dev, int all)
/*===========================================================================*/
static void set_multicast_list(struct net_device *dev)
{
- ray_dev_t *local = (ray_dev_t *)dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
UCHAR promisc;
DEBUG(2,"ray_cs set_multicast_list(%p)\n",dev);
@@ -1935,7 +1933,7 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev);
- local = (ray_dev_t *)dev->priv;
+ local = netdev_priv(dev);
link = (struct pcmcia_device *)local->finder;
if (!pcmcia_dev_present(link)) {
DEBUG(2,"ray_cs interrupt from device not present or suspended.\n");
@@ -2165,7 +2163,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i
{
struct sk_buff *skb = NULL;
struct rcs __iomem *prcslink = prcs;
- ray_dev_t *local = dev->priv;
+ ray_dev_t *local = netdev_priv(dev);
UCHAR *rx_ptr;
int total_len;
int tmp;
@@ -2611,6 +2609,7 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len)
UCHAR *p;
struct freq_hop_element *pfh;
UCHAR c[33];
+ DECLARE_MAC_BUF(mac);
link = this_device;
if (!link)
@@ -2618,7 +2617,7 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len)
dev = (struct net_device *)link->priv;
if (!dev)
return 0;
- local = (ray_dev_t *)dev->priv;
+ local = netdev_priv(dev);
if (!local)
return 0;
@@ -2640,9 +2639,8 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len)
nettype[local->sparm.b5.a_network_type], c);
p = local->bss_id;
- len += sprintf(buf + len,
- "BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
- p[0],p[1],p[2],p[3],p[4],p[5]);
+ len += sprintf(buf + len, "BSSID = %s\n",
+ print_mac(mac, p));
len += sprintf(buf + len, "Country code = %d\n",
local->sparm.b5.a_curr_country_code);
diff --git a/drivers/net/wireless/ray_cs.h b/drivers/net/wireless/ray_cs.h
index bd73ebf0334..1e23b7f4cca 100644
--- a/drivers/net/wireless/ray_cs.h
+++ b/drivers/net/wireless/ray_cs.h
@@ -33,8 +33,8 @@ typedef struct ray_dev_t {
void __iomem *rmem; /* pointer to receive buffer window */
struct pcmcia_device *finder; /* pointer back to struct pcmcia_device for card */
struct timer_list timer;
- long tx_ccs_lock;
- long ccs_lock;
+ unsigned long tx_ccs_lock;
+ unsigned long ccs_lock;
int dl_param_ccs;
union {
struct b4_startup_params b4;
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
new file mode 100644
index 00000000000..da05b1faf60
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -0,0 +1,130 @@
+config RT2X00
+ tristate "Ralink driver support"
+ depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
+ ---help---
+ This will enable the experimental support for the Ralink drivers,
+ developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
+
+ These drivers will make use of the Devicescape ieee80211 stack.
+
+ When building one of the individual drivers, the rt2x00 library
+ will also be created. That library (when the driver is built as
+ a module) will be called "rt2x00lib.ko".
+
+config RT2X00_LIB
+ tristate
+ depends on RT2X00
+
+config RT2X00_LIB_PCI
+ tristate
+ depends on RT2X00
+ select RT2X00_LIB
+
+config RT2X00_LIB_USB
+ tristate
+ depends on RT2X00
+ select RT2X00_LIB
+
+config RT2X00_LIB_FIRMWARE
+ boolean
+ depends on RT2X00_LIB
+ select CRC_ITU_T
+ select FW_LOADER
+
+config RT2X00_LIB_RFKILL
+ boolean
+ depends on RT2X00_LIB
+ select RFKILL
+ select INPUT_POLLDEV
+
+config RT2400PCI
+ tristate "Ralink rt2400 pci/pcmcia support"
+ depends on RT2X00 && PCI
+ select RT2X00_LIB_PCI
+ select EEPROM_93CX6
+ ---help---
+ This is an experimental driver for the Ralink rt2400 wireless chip.
+
+ When compiled as a module, this driver will be called "rt2400pci.ko".
+
+config RT2400PCI_RFKILL
+ bool "RT2400 rfkill support"
+ depends on RT2400PCI
+ select RT2X00_LIB_RFKILL
+ ---help---
+ This adds support for integrated rt2400 devices that feature a
+ hardware button to control the radio state.
+ This feature depends on the RF switch subsystem rfkill.
+
+config RT2500PCI
+ tristate "Ralink rt2500 pci/pcmcia support"
+ depends on RT2X00 && PCI
+ select RT2X00_LIB_PCI
+ select EEPROM_93CX6
+ ---help---
+ This is an experimental driver for the Ralink rt2500 wireless chip.
+
+ When compiled as a module, this driver will be called "rt2500pci.ko".
+
+config RT2500PCI_RFKILL
+ bool "RT2500 rfkill support"
+ depends on RT2500PCI
+ select RT2X00_LIB_RFKILL
+ ---help---
+ This adds support for integrated rt2500 devices that feature a
+ hardware button to control the radio state.
+ This feature depends on the RF switch subsystem rfkill.
+
+config RT61PCI
+ tristate "Ralink rt61 pci/pcmcia support"
+ depends on RT2X00 && PCI
+ select RT2X00_LIB_PCI
+ select RT2X00_LIB_FIRMWARE
+ select EEPROM_93CX6
+ ---help---
+ This is an experimental driver for the Ralink rt61 wireless chip.
+
+ When compiled as a module, this driver will be called "rt61pci.ko".
+
+config RT61PCI_RFKILL
+ bool "RT61 rfkill support"
+ depends on RT61PCI
+ select RT2X00_LIB_RFKILL
+ ---help---
+ This adds support for integrated rt61 devices that feature a
+ hardware button to control the radio state.
+ This feature depends on the RF switch subsystem rfkill.
+
+config RT2500USB
+ tristate "Ralink rt2500 usb support"
+ depends on RT2X00 && USB
+ select RT2X00_LIB_USB
+ ---help---
+ This is an experimental driver for the Ralink rt2500 wireless chip.
+
+ When compiled as a module, this driver will be called "rt2500usb.ko".
+
+config RT73USB
+ tristate "Ralink rt73 usb support"
+ depends on RT2X00 && USB
+ select RT2X00_LIB_USB
+ select RT2X00_LIB_FIRMWARE
+ ---help---
+ This is an experimental driver for the Ralink rt73 wireless chip.
+
+ When compiled as a module, this driver will be called "rt73usb.ko".
+
+config RT2X00_LIB_DEBUGFS
+ bool "Ralink debugfs support"
+ depends on RT2X00_LIB && MAC80211_DEBUGFS
+ ---help---
+ Enable creation of debugfs files for the rt2x00 drivers.
+ These debugfs files support both reading and writing of the
+ most important register types of the rt2x00 devices.
+
+config RT2X00_DEBUG
+ bool "Ralink debug output"
+ depends on RT2X00_LIB
+ ---help---
+ Enable debugging output for all rt2x00 modules
+
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
new file mode 100644
index 00000000000..30d654a42ee
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -0,0 +1,22 @@
+rt2x00lib-objs := rt2x00dev.o rt2x00mac.o rt2x00config.o
+
+ifeq ($(CONFIG_RT2X00_LIB_DEBUGFS),y)
+ rt2x00lib-objs += rt2x00debug.o
+endif
+
+ifeq ($(CONFIG_RT2X00_LIB_RFKILL),y)
+ rt2x00lib-objs += rt2x00rfkill.o
+endif
+
+ifeq ($(CONFIG_RT2X00_LIB_FIRMWARE),y)
+ rt2x00lib-objs += rt2x00firmware.o
+endif
+
+obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
+obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
+obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
+obj-$(CONFIG_RT2400PCI) += rt2400pci.o
+obj-$(CONFIG_RT2500PCI) += rt2500pci.o
+obj-$(CONFIG_RT61PCI) += rt61pci.o
+obj-$(CONFIG_RT2500USB) += rt2500usb.o
+obj-$(CONFIG_RT73USB) += rt73usb.o
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
new file mode 100644
index 00000000000..31c1dd27162
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -0,0 +1,1664 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2400pci
+ Abstract: rt2400pci device specific routines.
+ Supported chipsets: RT2460.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2400pci"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/eeprom_93cx6.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+#include "rt2400pci.h"
+
+/*
+ * Register access.
+ * All access to the CSR registers will go through the methods
+ * rt2x00pci_register_read and rt2x00pci_register_write.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers BBPCSR and RFCSR to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static u32 rt2400pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
+ if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
+ break;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ return reg;
+}
+
+static void rt2400pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2400pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+ ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
+ return;
+ }
+
+ /*
+ * Write the data into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+}
+
+static void rt2400pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2400pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+ ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
+ return;
+ }
+
+ /*
+ * Write the request into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2400pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+ ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
+ *value = 0xff;
+ return;
+ }
+
+ *value = rt2x00_get_field32(reg, BBPCSR_VALUE);
+}
+
+static void rt2400pci_rf_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u32 value)
+{
+ u32 reg;
+ unsigned int i;
+
+ if (!word)
+ return;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
+ if (!rt2x00_get_field32(reg, RFCSR_BUSY))
+ goto rf_write;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
+ return;
+
+rf_write:
+ reg = 0;
+ rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+ rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+ rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+
+ eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN);
+ eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT);
+ eeprom->reg_data_clock =
+ !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_CLOCK);
+ eeprom->reg_chip_select =
+ !!rt2x00_get_field32(reg, CSR21_EEPROM_CHIP_SELECT);
+}
+
+static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg = 0;
+
+ rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_IN, !!eeprom->reg_data_in);
+ rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_OUT, !!eeprom->reg_data_out);
+ rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_CLOCK,
+ !!eeprom->reg_data_clock);
+ rt2x00_set_field32(&reg, CSR21_EEPROM_CHIP_SELECT,
+ !!eeprom->reg_chip_select);
+
+ rt2x00pci_register_write(rt2x00dev, CSR21, reg);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
+
+static void rt2400pci_read_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 *data)
+{
+ rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static void rt2400pci_write_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 data)
+{
+ rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt2400pci_rt2x00debug = {
+ .owner = THIS_MODULE,
+ .csr = {
+ .read = rt2400pci_read_csr,
+ .write = rt2400pci_write_csr,
+ .word_size = sizeof(u32),
+ .word_count = CSR_REG_SIZE / sizeof(u32),
+ },
+ .eeprom = {
+ .read = rt2x00_eeprom_read,
+ .write = rt2x00_eeprom_write,
+ .word_size = sizeof(u16),
+ .word_count = EEPROM_SIZE / sizeof(u16),
+ },
+ .bbp = {
+ .read = rt2400pci_bbp_read,
+ .write = rt2400pci_bbp_write,
+ .word_size = sizeof(u8),
+ .word_count = BBP_SIZE / sizeof(u8),
+ },
+ .rf = {
+ .read = rt2x00_rf_read,
+ .write = rt2400pci_rf_write,
+ .word_size = sizeof(u32),
+ .word_count = RF_SIZE / sizeof(u32),
+ },
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+#ifdef CONFIG_RT2400PCI_RFKILL
+static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
+ return rt2x00_get_field32(reg, GPIOCSR_BIT0);
+}
+#else
+#define rt2400pci_rfkill_poll NULL
+#endif /* CONFIG_RT2400PCI_RFKILL */
+
+/*
+ * Configuration handlers.
+ */
+static void rt2400pci_config_mac_addr(struct rt2x00_dev *rt2x00dev,
+ __le32 *mac)
+{
+ rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac,
+ (2 * sizeof(__le32)));
+}
+
+static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev,
+ __le32 *bssid)
+{
+ rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid,
+ (2 * sizeof(__le32)));
+}
+
+static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+ const int tsf_sync)
+{
+ u32 reg;
+
+ rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+
+ /*
+ * Enable beacon config
+ */
+ rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
+ rt2x00_set_field32(&reg, BCNCSR1_PRELOAD,
+ PREAMBLE + get_duration(IEEE80211_HEADER, 20));
+ rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
+
+ /*
+ * Enable synchronisation.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, CSR14_TSF_SYNC, tsf_sync);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+}
+
+static void rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev,
+ const int short_preamble,
+ const int ack_timeout,
+ const int ack_consume_time)
+{
+ int preamble_mask;
+ u32 reg;
+
+ /*
+ * When short preamble is enabled, we should set bit 0x08
+ */
+ preamble_mask = short_preamble << 3;
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, ack_timeout);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, ack_consume_time);
+ rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
+ rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10));
+ rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
+ rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20));
+ rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
+ rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55));
+ rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
+ rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
+ rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+}
+
+static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev,
+ const int basic_rate_mask)
+{
+ rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+}
+
+static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf)
+{
+ /*
+ * Switch on tuning bits.
+ */
+ rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1);
+ rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1);
+
+ rt2400pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2400pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2400pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+ /*
+ * RF2420 chipset don't need any additional actions.
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2420))
+ return;
+
+ /*
+ * For the RT2421 chipsets we need to write an invalid
+ * reference clock rate to activate auto_tune.
+ * After that we set the value back to the correct channel.
+ */
+ rt2400pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2400pci_rf_write(rt2x00dev, 2, 0x000c2a32);
+ rt2400pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+ msleep(1);
+
+ rt2400pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2400pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2400pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+ msleep(1);
+
+ /*
+ * Switch off tuning bits.
+ */
+ rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0);
+ rt2x00_set_field32(&rf->rf3, RF3_TUNER, 0);
+
+ rt2400pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2400pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+ /*
+ * Clear false CRC during channel switch.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT0, &rf->rf1);
+}
+
+static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower)
+{
+ rt2400pci_bbp_write(rt2x00dev, 3, TXPOWER_TO_DEV(txpower));
+}
+
+static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
+ int antenna_tx, int antenna_rx)
+{
+ u8 r1;
+ u8 r4;
+
+ rt2400pci_bbp_read(rt2x00dev, 4, &r4);
+ rt2400pci_bbp_read(rt2x00dev, 1, &r1);
+
+ /*
+ * Configure the TX antenna.
+ */
+ switch (antenna_tx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
+ break;
+ }
+
+ /*
+ * Configure the RX antenna.
+ */
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ break;
+ }
+
+ rt2400pci_bbp_write(rt2x00dev, 4, r4);
+ rt2400pci_bbp_write(rt2x00dev, 1, r1);
+}
+
+static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+ rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
+ rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
+ rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+ rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
+ rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
+ rt2x00pci_register_write(rt2x00dev, CSR19, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+ rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
+ rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL,
+ libconf->conf->beacon_int * 16);
+ rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION,
+ libconf->conf->beacon_int * 16);
+ rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+}
+
+static void rt2400pci_config(struct rt2x00_dev *rt2x00dev,
+ const unsigned int flags,
+ struct rt2x00lib_conf *libconf)
+{
+ if (flags & CONFIG_UPDATE_PHYMODE)
+ rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates);
+ if (flags & CONFIG_UPDATE_CHANNEL)
+ rt2400pci_config_channel(rt2x00dev, &libconf->rf);
+ if (flags & CONFIG_UPDATE_TXPOWER)
+ rt2400pci_config_txpower(rt2x00dev,
+ libconf->conf->power_level);
+ if (flags & CONFIG_UPDATE_ANTENNA)
+ rt2400pci_config_antenna(rt2x00dev,
+ libconf->conf->antenna_sel_tx,
+ libconf->conf->antenna_sel_rx);
+ if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ rt2400pci_config_duration(rt2x00dev, libconf);
+}
+
+static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_tx_queue_params *params)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_CWMIN, params->cw_min);
+ rt2x00_set_field32(&reg, CSR11_CWMAX, params->cw_max);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+}
+
+/*
+ * LED functions.
+ */
+static void rt2400pci_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
+
+ rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
+ rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
+
+ if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
+ } else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+ } else {
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+ }
+
+ rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+}
+
+static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
+ rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+}
+
+/*
+ * Link tuning
+ */
+static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u8 bbp;
+
+ /*
+ * Update FCS error count from register.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+ rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
+
+ /*
+ * Update False CCA count from register.
+ */
+ rt2400pci_bbp_read(rt2x00dev, 39, &bbp);
+ rt2x00dev->link.false_cca = bbp;
+}
+
+static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ rt2400pci_bbp_write(rt2x00dev, 13, 0x08);
+ rt2x00dev->link.vgc_level = 0x08;
+}
+
+static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ u8 reg;
+
+ /*
+ * The link tuner should not run longer then 60 seconds,
+ * and should run once every 2 seconds.
+ */
+ if (rt2x00dev->link.count > 60 || !(rt2x00dev->link.count & 1))
+ return;
+
+ /*
+ * Base r13 link tuning on the false cca count.
+ */
+ rt2400pci_bbp_read(rt2x00dev, 13, &reg);
+
+ if (rt2x00dev->link.false_cca > 512 && reg < 0x20) {
+ rt2400pci_bbp_write(rt2x00dev, 13, ++reg);
+ rt2x00dev->link.vgc_level = reg;
+ } else if (rt2x00dev->link.false_cca < 100 && reg > 0x08) {
+ rt2400pci_bbp_write(rt2x00dev, 13, --reg);
+ rt2x00dev->link.vgc_level = reg;
+ }
+}
+
+/*
+ * Initialization functions.
+ */
+static void rt2400pci_init_rxring(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring = rt2x00dev->rx;
+ struct data_desc *rxd;
+ unsigned int i;
+ u32 word;
+
+ memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ rxd = ring->entry[i].priv;
+
+ rt2x00_desc_read(rxd, 2, &word);
+ rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
+ ring->data_size);
+ rt2x00_desc_write(rxd, 2, word);
+
+ rt2x00_desc_read(rxd, 1, &word);
+ rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS,
+ ring->entry[i].data_dma);
+ rt2x00_desc_write(rxd, 1, word);
+
+ rt2x00_desc_read(rxd, 0, &word);
+ rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+ rt2x00_desc_write(rxd, 0, word);
+ }
+
+ rt2x00_ring_index_clear(rt2x00dev->rx);
+}
+
+static void rt2400pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+ struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+ struct data_desc *txd;
+ unsigned int i;
+ u32 word;
+
+ memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ txd = ring->entry[i].priv;
+
+ rt2x00_desc_read(txd, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS,
+ ring->entry[i].data_dma);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH,
+ ring->data_size);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+ rt2x00_desc_write(txd, 0, word);
+ }
+
+ rt2x00_ring_index_clear(ring);
+}
+
+static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Initialize rings.
+ */
+ rt2400pci_init_rxring(rt2x00dev);
+ rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+ rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+ rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+ rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+ /*
+ * Initialize registers.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXCSR2, &reg);
+ rt2x00_set_field32(&reg, TXCSR2_TXD_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size);
+ rt2x00_set_field32(&reg, TXCSR2_NUM_TXD,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit);
+ rt2x00_set_field32(&reg, TXCSR2_NUM_ATIM,
+ rt2x00dev->bcn[1].stats.limit);
+ rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit);
+ rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg);
+ rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg);
+ rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg);
+ rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER,
+ rt2x00dev->bcn[1].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg);
+ rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER,
+ rt2x00dev->bcn[0].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg);
+ rt2x00_set_field32(&reg, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size);
+ rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit);
+ rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg);
+ rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER,
+ rt2x00dev->rx->data_dma);
+ rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
+
+ return 0;
+}
+
+static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002);
+ rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002);
+ rt2x00pci_register_write(rt2x00dev, PSCSR2, 0x00023f20);
+ rt2x00pci_register_write(rt2x00dev, PSCSR3, 0x00000002);
+
+ rt2x00pci_register_read(rt2x00dev, TIMECSR, &reg);
+ rt2x00_set_field32(&reg, TIMECSR_US_COUNT, 33);
+ rt2x00_set_field32(&reg, TIMECSR_US_64_COUNT, 63);
+ rt2x00_set_field32(&reg, TIMECSR_BEACON_EXPECT, 0);
+ rt2x00pci_register_write(rt2x00dev, TIMECSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR9, &reg);
+ rt2x00_set_field32(&reg, CSR9_MAX_FRAME_UNIT,
+ (rt2x00dev->rx->data_size / 128));
+ rt2x00pci_register_write(rt2x00dev, CSR9, reg);
+
+ rt2x00pci_register_write(rt2x00dev, CNT3, 0x3f080000);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR0, &reg);
+ rt2x00_set_field32(&reg, ARCSR0_AR_BBP_DATA0, 133);
+ rt2x00_set_field32(&reg, ARCSR0_AR_BBP_ID0, 134);
+ rt2x00_set_field32(&reg, ARCSR0_AR_BBP_DATA1, 136);
+ rt2x00_set_field32(&reg, ARCSR0_AR_BBP_ID1, 135);
+ rt2x00pci_register_write(rt2x00dev, ARCSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR3, &reg);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID0, 3); /* Tx power.*/
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID1, 32); /* Signal */
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID2, 36); /* Rssi */
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID2_VALID, 1);
+ rt2x00pci_register_write(rt2x00dev, RXCSR3, reg);
+
+ rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100);
+
+ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+ return -EBUSY;
+
+ rt2x00pci_register_write(rt2x00dev, MACCSR0, 0x00217223);
+ rt2x00pci_register_write(rt2x00dev, MACCSR1, 0x00235518);
+
+ rt2x00pci_register_read(rt2x00dev, MACCSR2, &reg);
+ rt2x00_set_field32(&reg, MACCSR2_DELAY, 64);
+ rt2x00pci_register_write(rt2x00dev, MACCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RALINKCSR, &reg);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA0, 17);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID0, 154);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA1, 0);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID1, 154);
+ rt2x00pci_register_write(rt2x00dev, RALINKCSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+ rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 1);
+ rt2x00_set_field32(&reg, CSR1_BBP_RESET, 0);
+ rt2x00_set_field32(&reg, CSR1_HOST_READY, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+ rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 0);
+ rt2x00_set_field32(&reg, CSR1_HOST_READY, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+
+ /*
+ * We must clear the FCS and FIFO error count.
+ * These registers are cleared on read,
+ * so we may pass a useless variable to store the value.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+ rt2x00pci_register_read(rt2x00dev, CNT4, &reg);
+
+ return 0;
+}
+
+static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u16 eeprom;
+ u8 reg_id;
+ u8 value;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2400pci_bbp_read(rt2x00dev, 0, &value);
+ if ((value != 0xff) && (value != 0x00))
+ goto continue_csr_init;
+ NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ return -EACCES;
+
+continue_csr_init:
+ rt2400pci_bbp_write(rt2x00dev, 1, 0x00);
+ rt2400pci_bbp_write(rt2x00dev, 3, 0x27);
+ rt2400pci_bbp_write(rt2x00dev, 4, 0x08);
+ rt2400pci_bbp_write(rt2x00dev, 10, 0x0f);
+ rt2400pci_bbp_write(rt2x00dev, 15, 0x72);
+ rt2400pci_bbp_write(rt2x00dev, 16, 0x74);
+ rt2400pci_bbp_write(rt2x00dev, 17, 0x20);
+ rt2400pci_bbp_write(rt2x00dev, 18, 0x72);
+ rt2400pci_bbp_write(rt2x00dev, 19, 0x0b);
+ rt2400pci_bbp_write(rt2x00dev, 20, 0x00);
+ rt2400pci_bbp_write(rt2x00dev, 28, 0x11);
+ rt2400pci_bbp_write(rt2x00dev, 29, 0x04);
+ rt2400pci_bbp_write(rt2x00dev, 30, 0x21);
+ rt2400pci_bbp_write(rt2x00dev, 31, 0x00);
+
+ DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+ for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+ if (eeprom != 0xffff && eeprom != 0x0000) {
+ reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+ DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+ reg_id, value);
+ rt2400pci_bbp_write(rt2x00dev, reg_id, value);
+ }
+ }
+ DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+ return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX,
+ state == STATE_RADIO_RX_OFF);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
+static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int mask = (state == STATE_RADIO_IRQ_OFF);
+ u32 reg;
+
+ /*
+ * When interrupts are being enabled, the interrupt registers
+ * should clear the register to assure a clean state.
+ */
+ if (state == STATE_RADIO_IRQ_ON) {
+ rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+ }
+
+ /*
+ * Only toggle the interrupts bits we are going to use.
+ * Non-checked interrupt bits are disabled by default.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, mask);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, mask);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, mask);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, mask);
+ rt2x00_set_field32(&reg, CSR8_RXDONE, mask);
+ rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+}
+
+static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
+ * Initialize all registers.
+ */
+ if (rt2400pci_init_rings(rt2x00dev) ||
+ rt2400pci_init_registers(rt2x00dev) ||
+ rt2400pci_init_bbp(rt2x00dev)) {
+ ERROR(rt2x00dev, "Register initialization failed.\n");
+ return -EIO;
+ }
+
+ /*
+ * Enable interrupts.
+ */
+ rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON);
+
+ /*
+ * Enable LED
+ */
+ rt2400pci_enable_led(rt2x00dev);
+
+ return 0;
+}
+
+static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Disable LED
+ */
+ rt2400pci_disable_led(rt2x00dev);
+
+ rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0);
+
+ /*
+ * Disable synchronisation.
+ */
+ rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+
+ /*
+ * Cancel RX and TX.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+
+ /*
+ * Disable interrupts.
+ */
+ rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF);
+}
+
+static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+ unsigned int i;
+ char put_to_sleep;
+ char bbp_state;
+ char rf_state;
+
+ put_to_sleep = (state != STATE_AWAKE);
+
+ rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+ rt2x00_set_field32(&reg, PWRCSR1_SET_STATE, 1);
+ rt2x00_set_field32(&reg, PWRCSR1_BBP_DESIRE_STATE, state);
+ rt2x00_set_field32(&reg, PWRCSR1_RF_DESIRE_STATE, state);
+ rt2x00_set_field32(&reg, PWRCSR1_PUT_TO_SLEEP, put_to_sleep);
+ rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg);
+
+ /*
+ * Device is not guaranteed to be in the requested state yet.
+ * We must wait until the register indicates that the
+ * device has entered the correct state.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+ bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE);
+ rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE);
+ if (bbp_state == state && rf_state == state)
+ return 0;
+ msleep(10);
+ }
+
+ NOTICE(rt2x00dev, "Device failed to enter state %d, "
+ "current device state: bbp %d and rf %d.\n",
+ state, bbp_state, rf_state);
+
+ return -EBUSY;
+}
+
+static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int retval = 0;
+
+ switch (state) {
+ case STATE_RADIO_ON:
+ retval = rt2400pci_enable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_OFF:
+ rt2400pci_disable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_OFF:
+ rt2400pci_toggle_rx(rt2x00dev, state);
+ break;
+ case STATE_DEEP_SLEEP:
+ case STATE_SLEEP:
+ case STATE_STANDBY:
+ case STATE_AWAKE:
+ retval = rt2400pci_set_state(rt2x00dev, state);
+ break;
+ default:
+ retval = -ENOTSUPP;
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct txdata_entry_desc *desc,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control)
+{
+ u32 word;
+ u32 signal = 0;
+ u32 service = 0;
+ u32 length_high = 0;
+ u32 length_low = 0;
+
+ /*
+ * The PLCP values should be treated as if they
+ * were BBP values.
+ */
+ rt2x00_set_field32(&signal, BBPCSR_VALUE, desc->signal);
+ rt2x00_set_field32(&signal, BBPCSR_REGNUM, 5);
+ rt2x00_set_field32(&signal, BBPCSR_BUSY, 1);
+
+ rt2x00_set_field32(&service, BBPCSR_VALUE, desc->service);
+ rt2x00_set_field32(&service, BBPCSR_REGNUM, 6);
+ rt2x00_set_field32(&service, BBPCSR_BUSY, 1);
+
+ rt2x00_set_field32(&length_high, BBPCSR_VALUE, desc->length_high);
+ rt2x00_set_field32(&length_high, BBPCSR_REGNUM, 7);
+ rt2x00_set_field32(&length_high, BBPCSR_BUSY, 1);
+
+ rt2x00_set_field32(&length_low, BBPCSR_VALUE, desc->length_low);
+ rt2x00_set_field32(&length_low, BBPCSR_REGNUM, 8);
+ rt2x00_set_field32(&length_low, BBPCSR_BUSY, 1);
+
+ /*
+ * Start writing the descriptor words.
+ */
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, length);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 3, &word);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, signal);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, service);
+ rt2x00_desc_write(txd, 3, word);
+
+ rt2x00_desc_read(txd, 4, &word);
+ rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, length_low);
+ rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, length_high);
+ rt2x00_desc_write(txd, 4, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+ rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+ test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_ACK,
+ !(control->flags & IEEE80211_TXCTL_NO_ACK));
+ rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_RTS,
+ test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+ !!(control->flags &
+ IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+ rt2x00_desc_write(txd, 0, word);
+}
+
+/*
+ * TX data initialization
+ */
+static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ unsigned int queue)
+{
+ u32 reg;
+
+ if (queue == IEEE80211_TX_QUEUE_BEACON) {
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ }
+ return;
+ }
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ if (queue == IEEE80211_TX_QUEUE_DATA0)
+ rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
+ else if (queue == IEEE80211_TX_QUEUE_DATA1)
+ rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
+ else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+ rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+}
+
+/*
+ * RX control handlers
+ */
+static void rt2400pci_fill_rxdone(struct data_entry *entry,
+ struct rxdata_entry_desc *desc)
+{
+ struct data_desc *rxd = entry->priv;
+ u32 word0;
+ u32 word2;
+
+ rt2x00_desc_read(rxd, 0, &word0);
+ rt2x00_desc_read(rxd, 2, &word2);
+
+ desc->flags = 0;
+ if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+ desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+ if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+ desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
+ desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
+ entry->ring->rt2x00dev->rssi_offset;
+ desc->ofdm = 0;
+ desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+ struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+ struct data_entry *entry;
+ struct data_desc *txd;
+ u32 word;
+ int tx_status;
+ int retry;
+
+ while (!rt2x00_ring_empty(ring)) {
+ entry = rt2x00_get_data_entry_done(ring);
+ txd = entry->priv;
+ rt2x00_desc_read(txd, 0, &word);
+
+ if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+ !rt2x00_get_field32(word, TXD_W0_VALID))
+ break;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ tx_status = rt2x00_get_field32(word, TXD_W0_RESULT);
+ retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
+
+ rt2x00lib_txdone(entry, tx_status, retry);
+
+ /*
+ * Make this entry available for reuse.
+ */
+ entry->flags = 0;
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_desc_write(txd, 0, word);
+ rt2x00_ring_index_done_inc(ring);
+ }
+
+ /*
+ * If the data ring was full before the txdone handler
+ * we must make sure the packet queue in the mac80211 stack
+ * is reenabled when the txdone handler has finished.
+ */
+ entry = ring->entry;
+ if (!rt2x00_ring_full(ring))
+ ieee80211_wake_queue(rt2x00dev->hw,
+ entry->tx_status.control.queue);
+}
+
+static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
+{
+ struct rt2x00_dev *rt2x00dev = dev_instance;
+ u32 reg;
+
+ /*
+ * Get the interrupt sources & saved to local variable.
+ * Write register value back to clear pending interrupts.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+
+ if (!reg)
+ return IRQ_NONE;
+
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return IRQ_HANDLED;
+
+ /*
+ * Handle interrupts, walk through all bits
+ * and run the tasks, the bits are checked in order of
+ * priority.
+ */
+
+ /*
+ * 1 - Beacon timer expired interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
+ rt2x00lib_beacondone(rt2x00dev);
+
+ /*
+ * 2 - Rx ring done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_RXDONE))
+ rt2x00pci_rxdone(rt2x00dev);
+
+ /*
+ * 3 - Atim ring transmit done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
+ rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+
+ /*
+ * 4 - Priority ring transmit done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
+ rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+
+ /*
+ * 5 - Tx ring transmit done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
+ rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ struct eeprom_93cx6 eeprom;
+ u32 reg;
+ u16 word;
+ u8 *mac;
+
+ rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+
+ eeprom.data = rt2x00dev;
+ eeprom.register_read = rt2400pci_eepromregister_read;
+ eeprom.register_write = rt2400pci_eepromregister_write;
+ eeprom.width = rt2x00_get_field32(reg, CSR21_TYPE_93C46) ?
+ PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+ eeprom.reg_data_in = 0;
+ eeprom.reg_data_out = 0;
+ eeprom.reg_data_clock = 0;
+ eeprom.reg_chip_select = 0;
+
+ eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
+ EEPROM_SIZE / sizeof(u16));
+
+ /*
+ * Start validation of the data that has been read.
+ */
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ DECLARE_MAC_BUF(macbuf);
+
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ if (word == 0xffff) {
+ ERROR(rt2x00dev, "Invalid EEPROM data detected.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 value;
+ u16 eeprom;
+
+ /*
+ * Read EEPROM word for configuration.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Identify RF chipset.
+ */
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
+ rt2x00_set_chip(rt2x00dev, RT2460, value, reg);
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF2420) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2421)) {
+ ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Identify default antenna configuration.
+ */
+ rt2x00dev->hw->conf.antenna_sel_tx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+ rt2x00dev->hw->conf.antenna_sel_rx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+ /*
+ * Store led mode, for correct led behaviour.
+ */
+ rt2x00dev->led_mode =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+
+ /*
+ * Detect if this device has an hardware controlled radio.
+ */
+#ifdef CONFIG_RT2400PCI_RFKILL
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
+ __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+#endif /* CONFIG_RT2400PCI_RFKILL */
+
+ /*
+ * Check if the BBP tuning should be enabled.
+ */
+ if (!rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING))
+ __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+
+ return 0;
+}
+
+/*
+ * RF value list for RF2420 & RF2421
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg[] = {
+ { 1, 0x00022058, 0x000c1fda, 0x00000101, 0 },
+ { 2, 0x00022058, 0x000c1fee, 0x00000101, 0 },
+ { 3, 0x00022058, 0x000c2002, 0x00000101, 0 },
+ { 4, 0x00022058, 0x000c2016, 0x00000101, 0 },
+ { 5, 0x00022058, 0x000c202a, 0x00000101, 0 },
+ { 6, 0x00022058, 0x000c203e, 0x00000101, 0 },
+ { 7, 0x00022058, 0x000c2052, 0x00000101, 0 },
+ { 8, 0x00022058, 0x000c2066, 0x00000101, 0 },
+ { 9, 0x00022058, 0x000c207a, 0x00000101, 0 },
+ { 10, 0x00022058, 0x000c208e, 0x00000101, 0 },
+ { 11, 0x00022058, 0x000c20a2, 0x00000101, 0 },
+ { 12, 0x00022058, 0x000c20b6, 0x00000101, 0 },
+ { 13, 0x00022058, 0x000c20ca, 0x00000101, 0 },
+ { 14, 0x00022058, 0x000c20fa, 0x00000101, 0 },
+};
+
+static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ u8 *txpower;
+ unsigned int i;
+
+ /*
+ * Initialize all hw fields.
+ */
+ rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ rt2x00dev->hw->extra_tx_headroom = 0;
+ rt2x00dev->hw->max_signal = MAX_SIGNAL;
+ rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+ rt2x00dev->hw->queues = 2;
+
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev,
+ EEPROM_MAC_ADDR_0));
+
+ /*
+ * Convert tx_power array in eeprom.
+ */
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ /*
+ * Initialize hw_mode information.
+ */
+ spec->num_modes = 1;
+ spec->num_rates = 4;
+ spec->tx_power_a = NULL;
+ spec->tx_power_bg = txpower;
+ spec->tx_power_default = DEFAULT_TXPOWER;
+
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg);
+ spec->channels = rf_vals_bg;
+}
+
+static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ /*
+ * Allocate eeprom data.
+ */
+ retval = rt2400pci_validate_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt2400pci_init_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * Initialize hw specifications.
+ */
+ rt2400pci_probe_hw_mode(rt2x00dev);
+
+ /*
+ * This device requires the beacon ring
+ */
+ __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+ return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt2400pci_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+ u32 reg;
+
+ /*
+ * Mask off any flags we are going to ignore from
+ * the total_flags field.
+ */
+ *total_flags &=
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_PROMISC_IN_BSS;
+
+ /*
+ * Apply some rules to the filters:
+ * - Some filters imply different filters to be set.
+ * - Some things we can't filter out at all.
+ * - Some filters are set based on interface type.
+ */
+ *total_flags |= FIF_ALLMULTI;
+ if (*total_flags & FIF_OTHER_BSS ||
+ *total_flags & FIF_PROMISC_IN_BSS)
+ *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+ if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+ *total_flags |= FIF_PROMISC_IN_BSS;
+
+ /*
+ * Check if there is any work left for us.
+ */
+ if (intf->filter == *total_flags)
+ return;
+ intf->filter = *total_flags;
+
+ /*
+ * Start configuration steps.
+ * Note that the version error will always be dropped
+ * since there is no filter for it at this time.
+ */
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DROP_CRC,
+ !(*total_flags & FIF_FCSFAIL));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL,
+ !(*total_flags & FIF_PLCPFAIL));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
+ !(*total_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
+static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw,
+ u32 short_retry, u32 long_retry)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
+ rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+ return 0;
+}
+
+static int rt2400pci_conf_tx(struct ieee80211_hw *hw,
+ int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * We don't support variating cw_min and cw_max variables
+ * per queue. So by default we only configure the TX queue,
+ * and ignore all other configurations.
+ */
+ if (queue != IEEE80211_TX_QUEUE_DATA0)
+ return -EINVAL;
+
+ if (rt2x00mac_conf_tx(hw, queue, params))
+ return -EINVAL;
+
+ /*
+ * Write configuration to register.
+ */
+ rt2400pci_config_cw(rt2x00dev, &rt2x00dev->tx->tx_params);
+
+ return 0;
+}
+
+static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u64 tsf;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR17, &reg);
+ tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32;
+ rt2x00pci_register_read(rt2x00dev, CSR16, &reg);
+ tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER);
+
+ return tsf;
+}
+
+static void rt2400pci_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ rt2x00pci_register_write(rt2x00dev, CSR16, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR17, 0);
+}
+
+static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR15, &reg);
+ return rt2x00_get_field32(reg, CSR15_BEACON_SENT);
+}
+
+static const struct ieee80211_ops rt2400pci_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .config_interface = rt2x00mac_config_interface,
+ .configure_filter = rt2400pci_configure_filter,
+ .get_stats = rt2x00mac_get_stats,
+ .set_retry_limit = rt2400pci_set_retry_limit,
+ .erp_ie_changed = rt2x00mac_erp_ie_changed,
+ .conf_tx = rt2400pci_conf_tx,
+ .get_tx_stats = rt2x00mac_get_tx_stats,
+ .get_tsf = rt2400pci_get_tsf,
+ .reset_tsf = rt2400pci_reset_tsf,
+ .beacon_update = rt2x00pci_beacon_update,
+ .tx_last_beacon = rt2400pci_tx_last_beacon,
+};
+
+static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
+ .irq_handler = rt2400pci_interrupt,
+ .probe_hw = rt2400pci_probe_hw,
+ .initialize = rt2x00pci_initialize,
+ .uninitialize = rt2x00pci_uninitialize,
+ .set_device_state = rt2400pci_set_device_state,
+ .rfkill_poll = rt2400pci_rfkill_poll,
+ .link_stats = rt2400pci_link_stats,
+ .reset_tuner = rt2400pci_reset_tuner,
+ .link_tuner = rt2400pci_link_tuner,
+ .write_tx_desc = rt2400pci_write_tx_desc,
+ .write_tx_data = rt2x00pci_write_tx_data,
+ .kick_tx_queue = rt2400pci_kick_tx_queue,
+ .fill_rxdone = rt2400pci_fill_rxdone,
+ .config_mac_addr = rt2400pci_config_mac_addr,
+ .config_bssid = rt2400pci_config_bssid,
+ .config_type = rt2400pci_config_type,
+ .config_preamble = rt2400pci_config_preamble,
+ .config = rt2400pci_config,
+};
+
+static const struct rt2x00_ops rt2400pci_ops = {
+ .name = DRV_NAME,
+ .rxd_size = RXD_DESC_SIZE,
+ .txd_size = TXD_DESC_SIZE,
+ .eeprom_size = EEPROM_SIZE,
+ .rf_size = RF_SIZE,
+ .lib = &rt2400pci_rt2x00_ops,
+ .hw = &rt2400pci_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ .debugfs = &rt2400pci_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * RT2400pci module information.
+ */
+static struct pci_device_id rt2400pci_device_table[] = {
+ { PCI_DEVICE(0x1814, 0x0101), PCI_DEVICE_DATA(&rt2400pci_ops) },
+ { 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT2400 PCI & PCMCIA Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2460 PCI & PCMCIA chipset based cards");
+MODULE_DEVICE_TABLE(pci, rt2400pci_device_table);
+MODULE_LICENSE("GPL");
+
+static struct pci_driver rt2400pci_driver = {
+ .name = DRV_NAME,
+ .id_table = rt2400pci_device_table,
+ .probe = rt2x00pci_probe,
+ .remove = __devexit_p(rt2x00pci_remove),
+ .suspend = rt2x00pci_suspend,
+ .resume = rt2x00pci_resume,
+};
+
+static int __init rt2400pci_init(void)
+{
+ return pci_register_driver(&rt2400pci_driver);
+}
+
+static void __exit rt2400pci_exit(void)
+{
+ pci_unregister_driver(&rt2400pci_driver);
+}
+
+module_init(rt2400pci_init);
+module_exit(rt2400pci_exit);
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
new file mode 100644
index 00000000000..ae22501f085
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -0,0 +1,943 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2400pci
+ Abstract: Data structures and registers for the rt2400pci module.
+ Supported chipsets: RT2460.
+ */
+
+#ifndef RT2400PCI_H
+#define RT2400PCI_H
+
+/*
+ * RF chip defines.
+ */
+#define RF2420 0x0000
+#define RF2421 0x0001
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL 100
+#define MAX_RX_SSI -1
+#define DEFAULT_RSSI_OFFSET 100
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE 0x0000
+#define CSR_REG_SIZE 0x014c
+#define EEPROM_BASE 0x0000
+#define EEPROM_SIZE 0x0100
+#define BBP_SIZE 0x0020
+#define RF_SIZE 0x0010
+
+/*
+ * Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * CSR0: ASIC revision number.
+ */
+#define CSR0 0x0000
+
+/*
+ * CSR1: System control register.
+ * SOFT_RESET: Software reset, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset, 1: reset, 0, release.
+ * HOST_READY: Host ready after initialization.
+ */
+#define CSR1 0x0004
+#define CSR1_SOFT_RESET FIELD32(0x00000001)
+#define CSR1_BBP_RESET FIELD32(0x00000002)
+#define CSR1_HOST_READY FIELD32(0x00000004)
+
+/*
+ * CSR2: System admin status register (invalid).
+ */
+#define CSR2 0x0008
+
+/*
+ * CSR3: STA MAC address register 0.
+ */
+#define CSR3 0x000c
+#define CSR3_BYTE0 FIELD32(0x000000ff)
+#define CSR3_BYTE1 FIELD32(0x0000ff00)
+#define CSR3_BYTE2 FIELD32(0x00ff0000)
+#define CSR3_BYTE3 FIELD32(0xff000000)
+
+/*
+ * CSR4: STA MAC address register 1.
+ */
+#define CSR4 0x0010
+#define CSR4_BYTE4 FIELD32(0x000000ff)
+#define CSR4_BYTE5 FIELD32(0x0000ff00)
+
+/*
+ * CSR5: BSSID register 0.
+ */
+#define CSR5 0x0014
+#define CSR5_BYTE0 FIELD32(0x000000ff)
+#define CSR5_BYTE1 FIELD32(0x0000ff00)
+#define CSR5_BYTE2 FIELD32(0x00ff0000)
+#define CSR5_BYTE3 FIELD32(0xff000000)
+
+/*
+ * CSR6: BSSID register 1.
+ */
+#define CSR6 0x0018
+#define CSR6_BYTE4 FIELD32(0x000000ff)
+#define CSR6_BYTE5 FIELD32(0x0000ff00)
+
+/*
+ * CSR7: Interrupt source register.
+ * Write 1 to clear interrupt.
+ * TBCN_EXPIRE: Beacon timer expired interrupt.
+ * TWAKE_EXPIRE: Wakeup timer expired interrupt.
+ * TATIMW_EXPIRE: Timer of atim window expired interrupt.
+ * TXDONE_TXRING: Tx ring transmit done interrupt.
+ * TXDONE_ATIMRING: Atim ring transmit done interrupt.
+ * TXDONE_PRIORING: Priority ring transmit done interrupt.
+ * RXDONE: Receive done interrupt.
+ */
+#define CSR7 0x001c
+#define CSR7_TBCN_EXPIRE FIELD32(0x00000001)
+#define CSR7_TWAKE_EXPIRE FIELD32(0x00000002)
+#define CSR7_TATIMW_EXPIRE FIELD32(0x00000004)
+#define CSR7_TXDONE_TXRING FIELD32(0x00000008)
+#define CSR7_TXDONE_ATIMRING FIELD32(0x00000010)
+#define CSR7_TXDONE_PRIORING FIELD32(0x00000020)
+#define CSR7_RXDONE FIELD32(0x00000040)
+
+/*
+ * CSR8: Interrupt mask register.
+ * Write 1 to mask interrupt.
+ * TBCN_EXPIRE: Beacon timer expired interrupt.
+ * TWAKE_EXPIRE: Wakeup timer expired interrupt.
+ * TATIMW_EXPIRE: Timer of atim window expired interrupt.
+ * TXDONE_TXRING: Tx ring transmit done interrupt.
+ * TXDONE_ATIMRING: Atim ring transmit done interrupt.
+ * TXDONE_PRIORING: Priority ring transmit done interrupt.
+ * RXDONE: Receive done interrupt.
+ */
+#define CSR8 0x0020
+#define CSR8_TBCN_EXPIRE FIELD32(0x00000001)
+#define CSR8_TWAKE_EXPIRE FIELD32(0x00000002)
+#define CSR8_TATIMW_EXPIRE FIELD32(0x00000004)
+#define CSR8_TXDONE_TXRING FIELD32(0x00000008)
+#define CSR8_TXDONE_ATIMRING FIELD32(0x00000010)
+#define CSR8_TXDONE_PRIORING FIELD32(0x00000020)
+#define CSR8_RXDONE FIELD32(0x00000040)
+
+/*
+ * CSR9: Maximum frame length register.
+ * MAX_FRAME_UNIT: Maximum frame length in 128b unit, default: 12.
+ */
+#define CSR9 0x0024
+#define CSR9_MAX_FRAME_UNIT FIELD32(0x00000f80)
+
+/*
+ * CSR11: Back-off control register.
+ * CWMIN: CWmin. Default cwmin is 31 (2^5 - 1).
+ * CWMAX: CWmax. Default cwmax is 1023 (2^10 - 1).
+ * SLOT_TIME: Slot time, default is 20us for 802.11b.
+ * LONG_RETRY: Long retry count.
+ * SHORT_RETRY: Short retry count.
+ */
+#define CSR11 0x002c
+#define CSR11_CWMIN FIELD32(0x0000000f)
+#define CSR11_CWMAX FIELD32(0x000000f0)
+#define CSR11_SLOT_TIME FIELD32(0x00001f00)
+#define CSR11_LONG_RETRY FIELD32(0x00ff0000)
+#define CSR11_SHORT_RETRY FIELD32(0xff000000)
+
+/*
+ * CSR12: Synchronization configuration register 0.
+ * All units in 1/16 TU.
+ * BEACON_INTERVAL: Beacon interval, default is 100 TU.
+ * CFPMAX_DURATION: Cfp maximum duration, default is 100 TU.
+ */
+#define CSR12 0x0030
+#define CSR12_BEACON_INTERVAL FIELD32(0x0000ffff)
+#define CSR12_CFP_MAX_DURATION FIELD32(0xffff0000)
+
+/*
+ * CSR13: Synchronization configuration register 1.
+ * All units in 1/16 TU.
+ * ATIMW_DURATION: Atim window duration.
+ * CFP_PERIOD: Cfp period, default is 0 TU.
+ */
+#define CSR13 0x0034
+#define CSR13_ATIMW_DURATION FIELD32(0x0000ffff)
+#define CSR13_CFP_PERIOD FIELD32(0x00ff0000)
+
+/*
+ * CSR14: Synchronization control register.
+ * TSF_COUNT: Enable tsf auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * TBCN: Enable tbcn with reload value.
+ * TCFP: Enable tcfp & cfp / cp switching.
+ * TATIMW: Enable tatimw & atim window switching.
+ * BEACON_GEN: Enable beacon generator.
+ * CFP_COUNT_PRELOAD: Cfp count preload value.
+ * TBCM_PRELOAD: Tbcn preload value in units of 64us.
+ */
+#define CSR14 0x0038
+#define CSR14_TSF_COUNT FIELD32(0x00000001)
+#define CSR14_TSF_SYNC FIELD32(0x00000006)
+#define CSR14_TBCN FIELD32(0x00000008)
+#define CSR14_TCFP FIELD32(0x00000010)
+#define CSR14_TATIMW FIELD32(0x00000020)
+#define CSR14_BEACON_GEN FIELD32(0x00000040)
+#define CSR14_CFP_COUNT_PRELOAD FIELD32(0x0000ff00)
+#define CSR14_TBCM_PRELOAD FIELD32(0xffff0000)
+
+/*
+ * CSR15: Synchronization status register.
+ * CFP: ASIC is in contention-free period.
+ * ATIMW: ASIC is in ATIM window.
+ * BEACON_SENT: Beacon is send.
+ */
+#define CSR15 0x003c
+#define CSR15_CFP FIELD32(0x00000001)
+#define CSR15_ATIMW FIELD32(0x00000002)
+#define CSR15_BEACON_SENT FIELD32(0x00000004)
+
+/*
+ * CSR16: TSF timer register 0.
+ */
+#define CSR16 0x0040
+#define CSR16_LOW_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * CSR17: TSF timer register 1.
+ */
+#define CSR17 0x0044
+#define CSR17_HIGH_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * CSR18: IFS timer register 0.
+ * SIFS: Sifs, default is 10 us.
+ * PIFS: Pifs, default is 30 us.
+ */
+#define CSR18 0x0048
+#define CSR18_SIFS FIELD32(0x0000ffff)
+#define CSR18_PIFS FIELD32(0xffff0000)
+
+/*
+ * CSR19: IFS timer register 1.
+ * DIFS: Difs, default is 50 us.
+ * EIFS: Eifs, default is 364 us.
+ */
+#define CSR19 0x004c
+#define CSR19_DIFS FIELD32(0x0000ffff)
+#define CSR19_EIFS FIELD32(0xffff0000)
+
+/*
+ * CSR20: Wakeup timer register.
+ * DELAY_AFTER_TBCN: Delay after tbcn expired in units of 1/16 TU.
+ * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * AUTOWAKE: Enable auto wakeup / sleep mechanism.
+ */
+#define CSR20 0x0050
+#define CSR20_DELAY_AFTER_TBCN FIELD32(0x0000ffff)
+#define CSR20_TBCN_BEFORE_WAKEUP FIELD32(0x00ff0000)
+#define CSR20_AUTOWAKE FIELD32(0x01000000)
+
+/*
+ * CSR21: EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE_93C46: 1: 93c46, 0:93c66.
+ */
+#define CSR21 0x0054
+#define CSR21_RELOAD FIELD32(0x00000001)
+#define CSR21_EEPROM_DATA_CLOCK FIELD32(0x00000002)
+#define CSR21_EEPROM_CHIP_SELECT FIELD32(0x00000004)
+#define CSR21_EEPROM_DATA_IN FIELD32(0x00000008)
+#define CSR21_EEPROM_DATA_OUT FIELD32(0x00000010)
+#define CSR21_TYPE_93C46 FIELD32(0x00000020)
+
+/*
+ * CSR22: CFP control register.
+ * CFP_DURATION_REMAIN: Cfp duration remain, in units of TU.
+ * RELOAD_CFP_DURATION: Write 1 to reload cfp duration remain.
+ */
+#define CSR22 0x0058
+#define CSR22_CFP_DURATION_REMAIN FIELD32(0x0000ffff)
+#define CSR22_RELOAD_CFP_DURATION FIELD32(0x00010000)
+
+/*
+ * Transmit related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXCSR0: TX Control Register.
+ * KICK_TX: Kick tx ring.
+ * KICK_ATIM: Kick atim ring.
+ * KICK_PRIO: Kick priority ring.
+ * ABORT: Abort all transmit related ring operation.
+ */
+#define TXCSR0 0x0060
+#define TXCSR0_KICK_TX FIELD32(0x00000001)
+#define TXCSR0_KICK_ATIM FIELD32(0x00000002)
+#define TXCSR0_KICK_PRIO FIELD32(0x00000004)
+#define TXCSR0_ABORT FIELD32(0x00000008)
+
+/*
+ * TXCSR1: TX Configuration Register.
+ * ACK_TIMEOUT: Ack timeout, default = sifs + 2*slottime + acktime @ 1mbps.
+ * ACK_CONSUME_TIME: Ack consume time, default = sifs + acktime @ 1mbps.
+ * TSF_OFFSET: Insert tsf offset.
+ * AUTORESPONDER: Enable auto responder which include ack & cts.
+ */
+#define TXCSR1 0x0064
+#define TXCSR1_ACK_TIMEOUT FIELD32(0x000001ff)
+#define TXCSR1_ACK_CONSUME_TIME FIELD32(0x0003fe00)
+#define TXCSR1_TSF_OFFSET FIELD32(0x00fc0000)
+#define TXCSR1_AUTORESPONDER FIELD32(0x01000000)
+
+/*
+ * TXCSR2: Tx descriptor configuration register.
+ * TXD_SIZE: Tx descriptor size, default is 48.
+ * NUM_TXD: Number of tx entries in ring.
+ * NUM_ATIM: Number of atim entries in ring.
+ * NUM_PRIO: Number of priority entries in ring.
+ */
+#define TXCSR2 0x0068
+#define TXCSR2_TXD_SIZE FIELD32(0x000000ff)
+#define TXCSR2_NUM_TXD FIELD32(0x0000ff00)
+#define TXCSR2_NUM_ATIM FIELD32(0x00ff0000)
+#define TXCSR2_NUM_PRIO FIELD32(0xff000000)
+
+/*
+ * TXCSR3: TX Ring Base address register.
+ */
+#define TXCSR3 0x006c
+#define TXCSR3_TX_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR4: TX Atim Ring Base address register.
+ */
+#define TXCSR4 0x0070
+#define TXCSR4_ATIM_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR5: TX Prio Ring Base address register.
+ */
+#define TXCSR5 0x0074
+#define TXCSR5_PRIO_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR6: Beacon Base address register.
+ */
+#define TXCSR6 0x0078
+#define TXCSR6_BEACON_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR7: Auto responder control register.
+ * AR_POWERMANAGEMENT: Auto responder power management bit.
+ */
+#define TXCSR7 0x007c
+#define TXCSR7_AR_POWERMANAGEMENT FIELD32(0x00000001)
+
+/*
+ * Receive related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * RXCSR0: RX Control Register.
+ * DISABLE_RX: Disable rx engine.
+ * DROP_CRC: Drop crc error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TODS: Drop frame tods bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * PASS_CRC: Pass all packets with crc attached.
+ */
+#define RXCSR0 0x0080
+#define RXCSR0_DISABLE_RX FIELD32(0x00000001)
+#define RXCSR0_DROP_CRC FIELD32(0x00000002)
+#define RXCSR0_DROP_PHYSICAL FIELD32(0x00000004)
+#define RXCSR0_DROP_CONTROL FIELD32(0x00000008)
+#define RXCSR0_DROP_NOT_TO_ME FIELD32(0x00000010)
+#define RXCSR0_DROP_TODS FIELD32(0x00000020)
+#define RXCSR0_DROP_VERSION_ERROR FIELD32(0x00000040)
+#define RXCSR0_PASS_CRC FIELD32(0x00000080)
+
+/*
+ * RXCSR1: RX descriptor configuration register.
+ * RXD_SIZE: Rx descriptor size, default is 32b.
+ * NUM_RXD: Number of rx entries in ring.
+ */
+#define RXCSR1 0x0084
+#define RXCSR1_RXD_SIZE FIELD32(0x000000ff)
+#define RXCSR1_NUM_RXD FIELD32(0x0000ff00)
+
+/*
+ * RXCSR2: RX Ring base address register.
+ */
+#define RXCSR2 0x0088
+#define RXCSR2_RX_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * RXCSR3: BBP ID register for Rx operation.
+ * BBP_ID#: BBP register # id.
+ * BBP_ID#_VALID: BBP register # id is valid or not.
+ */
+#define RXCSR3 0x0090
+#define RXCSR3_BBP_ID0 FIELD32(0x0000007f)
+#define RXCSR3_BBP_ID0_VALID FIELD32(0x00000080)
+#define RXCSR3_BBP_ID1 FIELD32(0x00007f00)
+#define RXCSR3_BBP_ID1_VALID FIELD32(0x00008000)
+#define RXCSR3_BBP_ID2 FIELD32(0x007f0000)
+#define RXCSR3_BBP_ID2_VALID FIELD32(0x00800000)
+#define RXCSR3_BBP_ID3 FIELD32(0x7f000000)
+#define RXCSR3_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * RXCSR4: BBP ID register for Rx operation.
+ * BBP_ID#: BBP register # id.
+ * BBP_ID#_VALID: BBP register # id is valid or not.
+ */
+#define RXCSR4 0x0094
+#define RXCSR4_BBP_ID4 FIELD32(0x0000007f)
+#define RXCSR4_BBP_ID4_VALID FIELD32(0x00000080)
+#define RXCSR4_BBP_ID5 FIELD32(0x00007f00)
+#define RXCSR4_BBP_ID5_VALID FIELD32(0x00008000)
+
+/*
+ * ARCSR0: Auto Responder PLCP config register 0.
+ * ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data.
+ * ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id.
+ */
+#define ARCSR0 0x0098
+#define ARCSR0_AR_BBP_DATA0 FIELD32(0x000000ff)
+#define ARCSR0_AR_BBP_ID0 FIELD32(0x0000ff00)
+#define ARCSR0_AR_BBP_DATA1 FIELD32(0x00ff0000)
+#define ARCSR0_AR_BBP_ID1 FIELD32(0xff000000)
+
+/*
+ * ARCSR1: Auto Responder PLCP config register 1.
+ * ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data.
+ * ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id.
+ */
+#define ARCSR1 0x009c
+#define ARCSR1_AR_BBP_DATA2 FIELD32(0x000000ff)
+#define ARCSR1_AR_BBP_ID2 FIELD32(0x0000ff00)
+#define ARCSR1_AR_BBP_DATA3 FIELD32(0x00ff0000)
+#define ARCSR1_AR_BBP_ID3 FIELD32(0xff000000)
+
+/*
+ * Miscellaneous Registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * PCICSR: PCI control register.
+ * BIG_ENDIAN: 1: big endian, 0: little endian.
+ * RX_TRESHOLD: Rx threshold in dw to start pci access
+ * 0: 16dw (default), 1: 8dw, 2: 4dw, 3: 32dw.
+ * TX_TRESHOLD: Tx threshold in dw to start pci access
+ * 0: 0dw (default), 1: 1dw, 2: 4dw, 3: forward.
+ * BURST_LENTH: Pci burst length 0: 4dw (default, 1: 8dw, 2: 16dw, 3:32dw.
+ * ENABLE_CLK: Enable clk_run, pci clock can't going down to non-operational.
+ */
+#define PCICSR 0x008c
+#define PCICSR_BIG_ENDIAN FIELD32(0x00000001)
+#define PCICSR_RX_TRESHOLD FIELD32(0x00000006)
+#define PCICSR_TX_TRESHOLD FIELD32(0x00000018)
+#define PCICSR_BURST_LENTH FIELD32(0x00000060)
+#define PCICSR_ENABLE_CLK FIELD32(0x00000080)
+
+/*
+ * CNT0: FCS error count.
+ * FCS_ERROR: FCS error count, cleared when read.
+ */
+#define CNT0 0x00a0
+#define CNT0_FCS_ERROR FIELD32(0x0000ffff)
+
+/*
+ * Statistic Register.
+ * CNT1: PLCP error count.
+ * CNT2: Long error count.
+ * CNT3: CCA false alarm count.
+ * CNT4: Rx FIFO overflow count.
+ * CNT5: Tx FIFO underrun count.
+ */
+#define TIMECSR2 0x00a8
+#define CNT1 0x00ac
+#define CNT2 0x00b0
+#define TIMECSR3 0x00b4
+#define CNT3 0x00b8
+#define CNT4 0x00bc
+#define CNT5 0x00c0
+
+/*
+ * Baseband Control Register.
+ */
+
+/*
+ * PWRCSR0: Power mode configuration register.
+ */
+#define PWRCSR0 0x00c4
+
+/*
+ * Power state transition time registers.
+ */
+#define PSCSR0 0x00c8
+#define PSCSR1 0x00cc
+#define PSCSR2 0x00d0
+#define PSCSR3 0x00d4
+
+/*
+ * PWRCSR1: Manual power control / status register.
+ * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake.
+ * SET_STATE: Set state. Write 1 to trigger, self cleared.
+ * BBP_DESIRE_STATE: BBP desired state.
+ * RF_DESIRE_STATE: RF desired state.
+ * BBP_CURR_STATE: BBP current state.
+ * RF_CURR_STATE: RF current state.
+ * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared.
+ */
+#define PWRCSR1 0x00d8
+#define PWRCSR1_SET_STATE FIELD32(0x00000001)
+#define PWRCSR1_BBP_DESIRE_STATE FIELD32(0x00000006)
+#define PWRCSR1_RF_DESIRE_STATE FIELD32(0x00000018)
+#define PWRCSR1_BBP_CURR_STATE FIELD32(0x00000060)
+#define PWRCSR1_RF_CURR_STATE FIELD32(0x00000180)
+#define PWRCSR1_PUT_TO_SLEEP FIELD32(0x00000200)
+
+/*
+ * TIMECSR: Timer control register.
+ * US_COUNT: 1 us timer count in units of clock cycles.
+ * US_64_COUNT: 64 us timer count in units of 1 us timer.
+ * BEACON_EXPECT: Beacon expect window.
+ */
+#define TIMECSR 0x00dc
+#define TIMECSR_US_COUNT FIELD32(0x000000ff)
+#define TIMECSR_US_64_COUNT FIELD32(0x0000ff00)
+#define TIMECSR_BEACON_EXPECT FIELD32(0x00070000)
+
+/*
+ * MACCSR0: MAC configuration register 0.
+ */
+#define MACCSR0 0x00e0
+
+/*
+ * MACCSR1: MAC configuration register 1.
+ * KICK_RX: Kick one-shot rx in one-shot rx mode.
+ * ONESHOT_RXMODE: Enable one-shot rx mode for debugging.
+ * BBPRX_RESET_MODE: Ralink bbp rx reset mode.
+ * AUTO_TXBBP: Auto tx logic access bbp control register.
+ * AUTO_RXBBP: Auto rx logic access bbp control register.
+ * LOOPBACK: Loopback mode. 0: normal, 1: internal, 2: external, 3:rsvd.
+ * INTERSIL_IF: Intersil if calibration pin.
+ */
+#define MACCSR1 0x00e4
+#define MACCSR1_KICK_RX FIELD32(0x00000001)
+#define MACCSR1_ONESHOT_RXMODE FIELD32(0x00000002)
+#define MACCSR1_BBPRX_RESET_MODE FIELD32(0x00000004)
+#define MACCSR1_AUTO_TXBBP FIELD32(0x00000008)
+#define MACCSR1_AUTO_RXBBP FIELD32(0x00000010)
+#define MACCSR1_LOOPBACK FIELD32(0x00000060)
+#define MACCSR1_INTERSIL_IF FIELD32(0x00000080)
+
+/*
+ * RALINKCSR: Ralink Rx auto-reset BBCR.
+ * AR_BBP_DATA#: Auto reset BBP register # data.
+ * AR_BBP_ID#: Auto reset BBP register # id.
+ */
+#define RALINKCSR 0x00e8
+#define RALINKCSR_AR_BBP_DATA0 FIELD32(0x000000ff)
+#define RALINKCSR_AR_BBP_ID0 FIELD32(0x0000ff00)
+#define RALINKCSR_AR_BBP_DATA1 FIELD32(0x00ff0000)
+#define RALINKCSR_AR_BBP_ID1 FIELD32(0xff000000)
+
+/*
+ * BCNCSR: Beacon interval control register.
+ * CHANGE: Write one to change beacon interval.
+ * DELTATIME: The delta time value.
+ * NUM_BEACON: Number of beacon according to mode.
+ * MODE: Please refer to asic specs.
+ * PLUS: Plus or minus delta time value.
+ */
+#define BCNCSR 0x00ec
+#define BCNCSR_CHANGE FIELD32(0x00000001)
+#define BCNCSR_DELTATIME FIELD32(0x0000001e)
+#define BCNCSR_NUM_BEACON FIELD32(0x00001fe0)
+#define BCNCSR_MODE FIELD32(0x00006000)
+#define BCNCSR_PLUS FIELD32(0x00008000)
+
+/*
+ * BBP / RF / IF Control Register.
+ */
+
+/*
+ * BBPCSR: BBP serial control register.
+ * VALUE: Register value to program into BBP.
+ * REGNUM: Selected BBP register.
+ * BUSY: 1: asic is busy execute BBP programming.
+ * WRITE_CONTROL: 1: write BBP, 0: read BBP.
+ */
+#define BBPCSR 0x00f0
+#define BBPCSR_VALUE FIELD32(0x000000ff)
+#define BBPCSR_REGNUM FIELD32(0x00007f00)
+#define BBPCSR_BUSY FIELD32(0x00008000)
+#define BBPCSR_WRITE_CONTROL FIELD32(0x00010000)
+
+/*
+ * RFCSR: RF serial control register.
+ * VALUE: Register value + id to program into rf/if.
+ * NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22).
+ * IF_SELECT: Chip to program: 0: rf, 1: if.
+ * PLL_LD: Rf pll_ld status.
+ * BUSY: 1: asic is busy execute rf programming.
+ */
+#define RFCSR 0x00f4
+#define RFCSR_VALUE FIELD32(0x00ffffff)
+#define RFCSR_NUMBER_OF_BITS FIELD32(0x1f000000)
+#define RFCSR_IF_SELECT FIELD32(0x20000000)
+#define RFCSR_PLL_LD FIELD32(0x40000000)
+#define RFCSR_BUSY FIELD32(0x80000000)
+
+/*
+ * LEDCSR: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ * LINK: 0: linkoff, 1: linkup.
+ * ACTIVITY: 0: idle, 1: active.
+ */
+#define LEDCSR 0x00f8
+#define LEDCSR_ON_PERIOD FIELD32(0x000000ff)
+#define LEDCSR_OFF_PERIOD FIELD32(0x0000ff00)
+#define LEDCSR_LINK FIELD32(0x00010000)
+#define LEDCSR_ACTIVITY FIELD32(0x00020000)
+
+/*
+ * ASIC pointer information.
+ * RXPTR: Current RX ring address.
+ * TXPTR: Current Tx ring address.
+ * PRIPTR: Current Priority ring address.
+ * ATIMPTR: Current ATIM ring address.
+ */
+#define RXPTR 0x0100
+#define TXPTR 0x0104
+#define PRIPTR 0x0108
+#define ATIMPTR 0x010c
+
+/*
+ * GPIO and others.
+ */
+
+/*
+ * GPIOCSR: GPIO control register.
+ */
+#define GPIOCSR 0x0120
+#define GPIOCSR_BIT0 FIELD32(0x00000001)
+#define GPIOCSR_BIT1 FIELD32(0x00000002)
+#define GPIOCSR_BIT2 FIELD32(0x00000004)
+#define GPIOCSR_BIT3 FIELD32(0x00000008)
+#define GPIOCSR_BIT4 FIELD32(0x00000010)
+#define GPIOCSR_BIT5 FIELD32(0x00000020)
+#define GPIOCSR_BIT6 FIELD32(0x00000040)
+#define GPIOCSR_BIT7 FIELD32(0x00000080)
+
+/*
+ * BBPPCSR: BBP Pin control register.
+ */
+#define BBPPCSR 0x0124
+
+/*
+ * BCNCSR1: Tx BEACON offset time control register.
+ * PRELOAD: Beacon timer offset in units of usec.
+ */
+#define BCNCSR1 0x0130
+#define BCNCSR1_PRELOAD FIELD32(0x0000ffff)
+
+/*
+ * MACCSR2: TX_PE to RX_PE turn-around time control register
+ * DELAY: RX_PE low width, in units of pci clock cycle.
+ */
+#define MACCSR2 0x0134
+#define MACCSR2_DELAY FIELD32(0x000000ff)
+
+/*
+ * ARCSR2: 1 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR2 0x013c
+#define ARCSR2_SIGNAL FIELD32(0x000000ff)
+#define ARCSR2_SERVICE FIELD32(0x0000ff00)
+#define ARCSR2_LENGTH_LOW FIELD32(0x00ff0000)
+#define ARCSR2_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARCSR3: 2 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR3 0x0140
+#define ARCSR3_SIGNAL FIELD32(0x000000ff)
+#define ARCSR3_SERVICE FIELD32(0x0000ff00)
+#define ARCSR3_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARCSR4: 5.5 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR4 0x0144
+#define ARCSR4_SIGNAL FIELD32(0x000000ff)
+#define ARCSR4_SERVICE FIELD32(0x0000ff00)
+#define ARCSR4_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARCSR5: 11 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR5 0x0148
+#define ARCSR5_SIGNAL FIELD32(0x000000ff)
+#define ARCSR5_SERVICE FIELD32(0x0000ff00)
+#define ARCSR5_LENGTH FIELD32(0xffff0000)
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R1: TX antenna control
+ */
+#define BBP_R1_TX_ANTENNA FIELD8(0x03)
+
+/*
+ * R4: RX antenna control
+ */
+#define BBP_R4_RX_ANTENNA FIELD8(0x06)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 1
+ */
+#define RF1_TUNER FIELD32(0x00020000)
+
+/*
+ * RF 3
+ */
+#define RF3_TUNER FIELD32(0x00000100)
+#define RF3_TXPOWER FIELD32(0x00003e00)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0 0x0002
+#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1 0x0003
+#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2 0x0004
+#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RF_TYPE: Rf_type of this adapter.
+ * LED_MODE: 0: default, 1: TX/RX activity,2: Single (ignore link), 3: rsvd.
+ * RX_AGCVGC: 0: disable, 1:enable BBP R13 tuning.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ */
+#define EEPROM_ANTENNA 0x0b
+#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
+#define EEPROM_ANTENNA_RF_TYPE FIELD16(0x0040)
+#define EEPROM_ANTENNA_LED_MODE FIELD16(0x0180)
+#define EEPROM_ANTENNA_RX_AGCVGC_TUNING FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START 0x0c
+#define EEPROM_BBP_SIZE 7
+#define EEPROM_BBP_VALUE FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER
+ */
+#define EEPROM_TXPOWER_START 0x13
+#define EEPROM_TXPOWER_SIZE 7
+#define EEPROM_TXPOWER_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_2 FIELD16(0xff00)
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE ( 8 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE ( 8 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
+ */
+
+/*
+ * Word0
+ */
+#define TXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define TXD_W0_VALID FIELD32(0x00000002)
+#define TXD_W0_RESULT FIELD32(0x0000001c)
+#define TXD_W0_RETRY_COUNT FIELD32(0x000000e0)
+#define TXD_W0_MORE_FRAG FIELD32(0x00000100)
+#define TXD_W0_ACK FIELD32(0x00000200)
+#define TXD_W0_TIMESTAMP FIELD32(0x00000400)
+#define TXD_W0_RTS FIELD32(0x00000800)
+#define TXD_W0_IFS FIELD32(0x00006000)
+#define TXD_W0_RETRY_MODE FIELD32(0x00008000)
+#define TXD_W0_AGC FIELD32(0x00ff0000)
+#define TXD_W0_R2 FIELD32(0xff000000)
+
+/*
+ * Word1
+ */
+#define TXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff)
+
+/*
+ * Word2
+ */
+#define TXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff)
+#define TXD_W2_DATABYTE_COUNT FIELD32(0xffff0000)
+
+/*
+ * Word3 & 4: PLCP information
+ */
+#define TXD_W3_PLCP_SIGNAL FIELD32(0x0000ffff)
+#define TXD_W3_PLCP_SERVICE FIELD32(0xffff0000)
+#define TXD_W4_PLCP_LENGTH_LOW FIELD32(0x0000ffff)
+#define TXD_W4_PLCP_LENGTH_HIGH FIELD32(0xffff0000)
+
+/*
+ * Word5
+ */
+#define TXD_W5_BBCR4 FIELD32(0x0000ffff)
+#define TXD_W5_AGC_REG FIELD32(0x007f0000)
+#define TXD_W5_AGC_REG_VALID FIELD32(0x00800000)
+#define TXD_W5_XXX_REG FIELD32(0x7f000000)
+#define TXD_W5_XXX_REG_VALID FIELD32(0x80000000)
+
+/*
+ * Word6
+ */
+#define TXD_W6_SK_BUFF FIELD32(0xffffffff)
+
+/*
+ * Word7
+ */
+#define TXD_W7_RESERVED FIELD32(0xffffffff)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ */
+#define RXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002)
+#define RXD_W0_MULTICAST FIELD32(0x00000004)
+#define RXD_W0_BROADCAST FIELD32(0x00000008)
+#define RXD_W0_MY_BSS FIELD32(0x00000010)
+#define RXD_W0_CRC_ERROR FIELD32(0x00000020)
+#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080)
+#define RXD_W0_DATABYTE_COUNT FIELD32(0xffff0000)
+
+/*
+ * Word1
+ */
+#define RXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff)
+
+/*
+ * Word2
+ */
+#define RXD_W2_BUFFER_LENGTH FIELD32(0x0000ffff)
+#define RXD_W2_SIGNAL FIELD32(0x00ff0000)
+#define RXD_W2_RSSI FIELD32(0xff000000)
+
+/*
+ * Word3
+ */
+#define RXD_W3_BBR2 FIELD32(0x000000ff)
+#define RXD_W3_BBR3 FIELD32(0x0000ff00)
+#define RXD_W3_BBR4 FIELD32(0x00ff0000)
+#define RXD_W3_BBR5 FIELD32(0xff000000)
+
+/*
+ * Word4
+ */
+#define RXD_W4_RX_END_TIME FIELD32(0xffffffff)
+
+/*
+ * Word5 & 6 & 7: Reserved
+ */
+#define RXD_W5_RESERVED FIELD32(0xffffffff)
+#define RXD_W6_RESERVED FIELD32(0xffffffff)
+#define RXD_W7_RESERVED FIELD32(0xffffffff)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ * NOTE: Logics in rt2400pci for txpower are reversed
+ * compared to the other rt2x00 drivers. A higher txpower
+ * value means that the txpower must be lowered. This is
+ * important when converting the value coming from the
+ * dscape stack to the rt2400 acceptable value.
+ */
+#define MIN_TXPOWER 31
+#define MAX_TXPOWER 62
+#define DEFAULT_TXPOWER 39
+
+#define TXPOWER_FROM_DEV(__txpower) \
+({ \
+ ((__txpower) > MAX_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \
+ ((__txpower) < MIN_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER : \
+ (((__txpower) - MAX_TXPOWER) + MIN_TXPOWER); \
+})
+
+#define TXPOWER_TO_DEV(__txpower) \
+({ \
+ (__txpower) += MIN_TXPOWER; \
+ ((__txpower) <= MIN_TXPOWER) ? MAX_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MIN_TXPOWER : \
+ (MAX_TXPOWER - ((__txpower) - MIN_TXPOWER))); \
+})
+
+#endif /* RT2400PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
new file mode 100644
index 00000000000..702321c3016
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -0,0 +1,1971 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2500pci
+ Abstract: rt2500pci device specific routines.
+ Supported chipsets: RT2560.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2500pci"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/eeprom_93cx6.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+#include "rt2500pci.h"
+
+/*
+ * Register access.
+ * All access to the CSR registers will go through the methods
+ * rt2x00pci_register_read and rt2x00pci_register_write.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers BBPCSR and RFCSR to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static u32 rt2500pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
+ if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
+ break;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ return reg;
+}
+
+static void rt2500pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2500pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+ ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
+ return;
+ }
+
+ /*
+ * Write the data into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+}
+
+static void rt2500pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2500pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+ ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
+ return;
+ }
+
+ /*
+ * Write the request into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+ rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+ rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2500pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+ ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
+ *value = 0xff;
+ return;
+ }
+
+ *value = rt2x00_get_field32(reg, BBPCSR_VALUE);
+}
+
+static void rt2500pci_rf_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u32 value)
+{
+ u32 reg;
+ unsigned int i;
+
+ if (!word)
+ return;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
+ if (!rt2x00_get_field32(reg, RFCSR_BUSY))
+ goto rf_write;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
+ return;
+
+rf_write:
+ reg = 0;
+ rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+ rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+ rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+
+ eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN);
+ eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT);
+ eeprom->reg_data_clock =
+ !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_CLOCK);
+ eeprom->reg_chip_select =
+ !!rt2x00_get_field32(reg, CSR21_EEPROM_CHIP_SELECT);
+}
+
+static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg = 0;
+
+ rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_IN, !!eeprom->reg_data_in);
+ rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_OUT, !!eeprom->reg_data_out);
+ rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_CLOCK,
+ !!eeprom->reg_data_clock);
+ rt2x00_set_field32(&reg, CSR21_EEPROM_CHIP_SELECT,
+ !!eeprom->reg_chip_select);
+
+ rt2x00pci_register_write(rt2x00dev, CSR21, reg);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
+
+static void rt2500pci_read_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 *data)
+{
+ rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static void rt2500pci_write_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 data)
+{
+ rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt2500pci_rt2x00debug = {
+ .owner = THIS_MODULE,
+ .csr = {
+ .read = rt2500pci_read_csr,
+ .write = rt2500pci_write_csr,
+ .word_size = sizeof(u32),
+ .word_count = CSR_REG_SIZE / sizeof(u32),
+ },
+ .eeprom = {
+ .read = rt2x00_eeprom_read,
+ .write = rt2x00_eeprom_write,
+ .word_size = sizeof(u16),
+ .word_count = EEPROM_SIZE / sizeof(u16),
+ },
+ .bbp = {
+ .read = rt2500pci_bbp_read,
+ .write = rt2500pci_bbp_write,
+ .word_size = sizeof(u8),
+ .word_count = BBP_SIZE / sizeof(u8),
+ },
+ .rf = {
+ .read = rt2x00_rf_read,
+ .write = rt2500pci_rf_write,
+ .word_size = sizeof(u32),
+ .word_count = RF_SIZE / sizeof(u32),
+ },
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+#ifdef CONFIG_RT2500PCI_RFKILL
+static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
+ return rt2x00_get_field32(reg, GPIOCSR_BIT0);
+}
+#else
+#define rt2500pci_rfkill_poll NULL
+#endif /* CONFIG_RT2500PCI_RFKILL */
+
+/*
+ * Configuration handlers.
+ */
+static void rt2500pci_config_mac_addr(struct rt2x00_dev *rt2x00dev,
+ __le32 *mac)
+{
+ rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac,
+ (2 * sizeof(__le32)));
+}
+
+static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev,
+ __le32 *bssid)
+{
+ rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid,
+ (2 * sizeof(__le32)));
+}
+
+static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+ const int tsf_sync)
+{
+ u32 reg;
+
+ rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+
+ /*
+ * Enable beacon config
+ */
+ rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
+ rt2x00_set_field32(&reg, BCNCSR1_PRELOAD,
+ PREAMBLE + get_duration(IEEE80211_HEADER, 20));
+ rt2x00_set_field32(&reg, BCNCSR1_BEACON_CWMIN,
+ rt2x00lib_get_ring(rt2x00dev,
+ IEEE80211_TX_QUEUE_BEACON)
+ ->tx_params.cw_min);
+ rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
+
+ /*
+ * Enable synchronisation.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+ rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, CSR14_TSF_SYNC, tsf_sync);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+}
+
+static void rt2500pci_config_preamble(struct rt2x00_dev *rt2x00dev,
+ const int short_preamble,
+ const int ack_timeout,
+ const int ack_consume_time)
+{
+ int preamble_mask;
+ u32 reg;
+
+ /*
+ * When short preamble is enabled, we should set bit 0x08
+ */
+ preamble_mask = short_preamble << 3;
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, ack_timeout);
+ rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, ack_consume_time);
+ rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
+ rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10));
+ rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
+ rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20));
+ rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
+ rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55));
+ rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
+ rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
+ rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
+ rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
+ rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+}
+
+static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev,
+ const int basic_rate_mask)
+{
+ rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+}
+
+static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf, const int txpower)
+{
+ u8 r70;
+
+ /*
+ * Set TXpower.
+ */
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+
+ /*
+ * Switch on tuning bits.
+ * For RT2523 devices we do not need to update the R1 register.
+ */
+ if (!rt2x00_rf(&rt2x00dev->chip, RF2523))
+ rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1);
+ rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1);
+
+ /*
+ * For RT2525 we should first set the channel to half band higher.
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+ static const u32 vals[] = {
+ 0x00080cbe, 0x00080d02, 0x00080d06, 0x00080d0a,
+ 0x00080d0e, 0x00080d12, 0x00080d16, 0x00080d1a,
+ 0x00080d1e, 0x00080d22, 0x00080d26, 0x00080d2a,
+ 0x00080d2e, 0x00080d3a
+ };
+
+ rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2500pci_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
+ rt2500pci_rf_write(rt2x00dev, 3, rf->rf3);
+ if (rf->rf4)
+ rt2500pci_rf_write(rt2x00dev, 4, rf->rf4);
+ }
+
+ rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2500pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2500pci_rf_write(rt2x00dev, 3, rf->rf3);
+ if (rf->rf4)
+ rt2500pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ /*
+ * Channel 14 requires the Japan filter bit to be set.
+ */
+ r70 = 0x46;
+ rt2x00_set_field8(&r70, BBP_R70_JAPAN_FILTER, rf->channel == 14);
+ rt2500pci_bbp_write(rt2x00dev, 70, r70);
+
+ msleep(1);
+
+ /*
+ * Switch off tuning bits.
+ * For RT2523 devices we do not need to update the R1 register.
+ */
+ if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+ rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0);
+ rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
+ }
+
+ rt2x00_set_field32(&rf->rf3, RF3_TUNER, 0);
+ rt2500pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+ /*
+ * Clear false CRC during channel switch.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT0, &rf->rf1);
+}
+
+static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev,
+ const int txpower)
+{
+ u32 rf3;
+
+ rt2x00_rf_read(rt2x00dev, 3, &rf3);
+ rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+ rt2500pci_rf_write(rt2x00dev, 3, rf3);
+}
+
+static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx, const int antenna_rx)
+{
+ u32 reg;
+ u8 r14;
+ u8 r2;
+
+ rt2x00pci_register_read(rt2x00dev, BBPCSR1, &reg);
+ rt2500pci_bbp_read(rt2x00dev, 14, &r14);
+ rt2500pci_bbp_read(rt2x00dev, 2, &r2);
+
+ /*
+ * Configure the TX antenna.
+ */
+ switch (antenna_tx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
+ rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
+ rt2x00_set_field32(&reg, BBPCSR1_CCK, 0);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM, 0);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
+ rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
+ break;
+ }
+
+ /*
+ * Configure the RX antenna.
+ */
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
+ break;
+ }
+
+ /*
+ * RT2525E and RT5222 need to flip TX I/Q
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
+ rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
+ rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
+
+ /*
+ * RT2525E does not need RX I/Q Flip.
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+ rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
+ } else {
+ rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
+ rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 0);
+ }
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg);
+ rt2500pci_bbp_write(rt2x00dev, 14, r14);
+ rt2500pci_bbp_write(rt2x00dev, 2, r2);
+}
+
+static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+ rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
+ rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
+ rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+ rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
+ rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
+ rt2x00pci_register_write(rt2x00dev, CSR19, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+ rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
+ rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL,
+ libconf->conf->beacon_int * 16);
+ rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION,
+ libconf->conf->beacon_int * 16);
+ rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+}
+
+static void rt2500pci_config(struct rt2x00_dev *rt2x00dev,
+ const unsigned int flags,
+ struct rt2x00lib_conf *libconf)
+{
+ if (flags & CONFIG_UPDATE_PHYMODE)
+ rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates);
+ if (flags & CONFIG_UPDATE_CHANNEL)
+ rt2500pci_config_channel(rt2x00dev, &libconf->rf,
+ libconf->conf->power_level);
+ if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+ rt2500pci_config_txpower(rt2x00dev,
+ libconf->conf->power_level);
+ if (flags & CONFIG_UPDATE_ANTENNA)
+ rt2500pci_config_antenna(rt2x00dev,
+ libconf->conf->antenna_sel_tx,
+ libconf->conf->antenna_sel_rx);
+ if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ rt2500pci_config_duration(rt2x00dev, libconf);
+}
+
+/*
+ * LED functions.
+ */
+static void rt2500pci_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
+
+ rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
+ rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
+
+ if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
+ } else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+ } else {
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+ }
+
+ rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+}
+
+static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
+ rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
+ rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
+ rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+}
+
+/*
+ * Link tuning
+ */
+static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Update FCS error count from register.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+ rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
+
+ /*
+ * Update False CCA count from register.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT3, &reg);
+ rt2x00dev->link.false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA);
+}
+
+static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ rt2500pci_bbp_write(rt2x00dev, 17, 0x48);
+ rt2x00dev->link.vgc_level = 0x48;
+}
+
+static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
+ u8 r17;
+
+ /*
+ * To prevent collisions with MAC ASIC on chipsets
+ * up to version C the link tuning should halt after 20
+ * seconds.
+ */
+ if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D &&
+ rt2x00dev->link.count > 20)
+ return;
+
+ rt2500pci_bbp_read(rt2x00dev, 17, &r17);
+
+ /*
+ * Chipset versions C and lower should directly continue
+ * to the dynamic CCA tuning.
+ */
+ if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D)
+ goto dynamic_cca_tune;
+
+ /*
+ * A too low RSSI will cause too much false CCA which will
+ * then corrupt the R17 tuning. To remidy this the tuning should
+ * be stopped (While making sure the R17 value will not exceed limits)
+ */
+ if (rssi < -80 && rt2x00dev->link.count > 20) {
+ if (r17 >= 0x41) {
+ r17 = rt2x00dev->link.vgc_level;
+ rt2500pci_bbp_write(rt2x00dev, 17, r17);
+ }
+ return;
+ }
+
+ /*
+ * Special big-R17 for short distance
+ */
+ if (rssi >= -58) {
+ if (r17 != 0x50)
+ rt2500pci_bbp_write(rt2x00dev, 17, 0x50);
+ return;
+ }
+
+ /*
+ * Special mid-R17 for middle distance
+ */
+ if (rssi >= -74) {
+ if (r17 != 0x41)
+ rt2500pci_bbp_write(rt2x00dev, 17, 0x41);
+ return;
+ }
+
+ /*
+ * Leave short or middle distance condition, restore r17
+ * to the dynamic tuning range.
+ */
+ if (r17 >= 0x41) {
+ rt2500pci_bbp_write(rt2x00dev, 17, rt2x00dev->link.vgc_level);
+ return;
+ }
+
+dynamic_cca_tune:
+
+ /*
+ * R17 is inside the dynamic tuning range,
+ * start tuning the link based on the false cca counter.
+ */
+ if (rt2x00dev->link.false_cca > 512 && r17 < 0x40) {
+ rt2500pci_bbp_write(rt2x00dev, 17, ++r17);
+ rt2x00dev->link.vgc_level = r17;
+ } else if (rt2x00dev->link.false_cca < 100 && r17 > 0x32) {
+ rt2500pci_bbp_write(rt2x00dev, 17, --r17);
+ rt2x00dev->link.vgc_level = r17;
+ }
+}
+
+/*
+ * Initialization functions.
+ */
+static void rt2500pci_init_rxring(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring = rt2x00dev->rx;
+ struct data_desc *rxd;
+ unsigned int i;
+ u32 word;
+
+ memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ rxd = ring->entry[i].priv;
+
+ rt2x00_desc_read(rxd, 1, &word);
+ rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS,
+ ring->entry[i].data_dma);
+ rt2x00_desc_write(rxd, 1, word);
+
+ rt2x00_desc_read(rxd, 0, &word);
+ rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+ rt2x00_desc_write(rxd, 0, word);
+ }
+
+ rt2x00_ring_index_clear(rt2x00dev->rx);
+}
+
+static void rt2500pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+ struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+ struct data_desc *txd;
+ unsigned int i;
+ u32 word;
+
+ memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ txd = ring->entry[i].priv;
+
+ rt2x00_desc_read(txd, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS,
+ ring->entry[i].data_dma);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+ rt2x00_desc_write(txd, 0, word);
+ }
+
+ rt2x00_ring_index_clear(ring);
+}
+
+static int rt2500pci_init_rings(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Initialize rings.
+ */
+ rt2500pci_init_rxring(rt2x00dev);
+ rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+ rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+ rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+ rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+ /*
+ * Initialize registers.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXCSR2, &reg);
+ rt2x00_set_field32(&reg, TXCSR2_TXD_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size);
+ rt2x00_set_field32(&reg, TXCSR2_NUM_TXD,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit);
+ rt2x00_set_field32(&reg, TXCSR2_NUM_ATIM,
+ rt2x00dev->bcn[1].stats.limit);
+ rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit);
+ rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg);
+ rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg);
+ rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg);
+ rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER,
+ rt2x00dev->bcn[1].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg);
+ rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER,
+ rt2x00dev->bcn[0].data_dma);
+ rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg);
+ rt2x00_set_field32(&reg, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size);
+ rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit);
+ rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg);
+ rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER,
+ rt2x00dev->rx->data_dma);
+ rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
+
+ return 0;
+}
+
+static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002);
+ rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002);
+ rt2x00pci_register_write(rt2x00dev, PSCSR2, 0x00020002);
+ rt2x00pci_register_write(rt2x00dev, PSCSR3, 0x00000002);
+
+ rt2x00pci_register_read(rt2x00dev, TIMECSR, &reg);
+ rt2x00_set_field32(&reg, TIMECSR_US_COUNT, 33);
+ rt2x00_set_field32(&reg, TIMECSR_US_64_COUNT, 63);
+ rt2x00_set_field32(&reg, TIMECSR_BEACON_EXPECT, 0);
+ rt2x00pci_register_write(rt2x00dev, TIMECSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR9, &reg);
+ rt2x00_set_field32(&reg, CSR9_MAX_FRAME_UNIT,
+ rt2x00dev->rx->data_size / 128);
+ rt2x00pci_register_write(rt2x00dev, CSR9, reg);
+
+ /*
+ * Always use CWmin and CWmax set in descriptor.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_CW_SELECT, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+ rt2x00pci_register_write(rt2x00dev, CNT3, 0);
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR8, &reg);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID0, 10);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID1, 11);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID2, 13);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID2_VALID, 1);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID3, 12);
+ rt2x00_set_field32(&reg, TXCSR8_BBP_ID3_VALID, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR8, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARTCSR0, &reg);
+ rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_1MBS, 112);
+ rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_2MBS, 56);
+ rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_5_5MBS, 20);
+ rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_11MBS, 10);
+ rt2x00pci_register_write(rt2x00dev, ARTCSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARTCSR1, &reg);
+ rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_6MBS, 45);
+ rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_9MBS, 37);
+ rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_12MBS, 33);
+ rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_18MBS, 29);
+ rt2x00pci_register_write(rt2x00dev, ARTCSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, ARTCSR2, &reg);
+ rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_24MBS, 29);
+ rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_36MBS, 25);
+ rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_48MBS, 25);
+ rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_54MBS, 25);
+ rt2x00pci_register_write(rt2x00dev, ARTCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR3, &reg);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID0, 47); /* CCK Signal */
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID1, 51); /* Rssi */
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID2, 42); /* OFDM Rate */
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID2_VALID, 1);
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID3, 51); /* RSSI */
+ rt2x00_set_field32(&reg, RXCSR3_BBP_ID3_VALID, 1);
+ rt2x00pci_register_write(rt2x00dev, RXCSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, PCICSR, &reg);
+ rt2x00_set_field32(&reg, PCICSR_BIG_ENDIAN, 0);
+ rt2x00_set_field32(&reg, PCICSR_RX_TRESHOLD, 0);
+ rt2x00_set_field32(&reg, PCICSR_TX_TRESHOLD, 3);
+ rt2x00_set_field32(&reg, PCICSR_BURST_LENTH, 1);
+ rt2x00_set_field32(&reg, PCICSR_ENABLE_CLK, 1);
+ rt2x00_set_field32(&reg, PCICSR_READ_MULTIPLE, 1);
+ rt2x00_set_field32(&reg, PCICSR_WRITE_INVALID, 1);
+ rt2x00pci_register_write(rt2x00dev, PCICSR, reg);
+
+ rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100);
+
+ rt2x00pci_register_write(rt2x00dev, GPIOCSR, 0x0000ff00);
+ rt2x00pci_register_write(rt2x00dev, TESTCSR, 0x000000f0);
+
+ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+ return -EBUSY;
+
+ rt2x00pci_register_write(rt2x00dev, MACCSR0, 0x00213223);
+ rt2x00pci_register_write(rt2x00dev, MACCSR1, 0x00235518);
+
+ rt2x00pci_register_read(rt2x00dev, MACCSR2, &reg);
+ rt2x00_set_field32(&reg, MACCSR2_DELAY, 64);
+ rt2x00pci_register_write(rt2x00dev, MACCSR2, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RALINKCSR, &reg);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA0, 17);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID0, 26);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_VALID0, 1);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA1, 0);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID1, 26);
+ rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_VALID1, 1);
+ rt2x00pci_register_write(rt2x00dev, RALINKCSR, reg);
+
+ rt2x00pci_register_write(rt2x00dev, BBPCSR1, 0x82188200);
+
+ rt2x00pci_register_write(rt2x00dev, TXACKCSR0, 0x00000020);
+
+ rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+ rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 1);
+ rt2x00_set_field32(&reg, CSR1_BBP_RESET, 0);
+ rt2x00_set_field32(&reg, CSR1_HOST_READY, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+ rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 0);
+ rt2x00_set_field32(&reg, CSR1_HOST_READY, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+
+ /*
+ * We must clear the FCS and FIFO error count.
+ * These registers are cleared on read,
+ * so we may pass a useless variable to store the value.
+ */
+ rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+ rt2x00pci_register_read(rt2x00dev, CNT4, &reg);
+
+ return 0;
+}
+
+static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u16 eeprom;
+ u8 reg_id;
+ u8 value;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2500pci_bbp_read(rt2x00dev, 0, &value);
+ if ((value != 0xff) && (value != 0x00))
+ goto continue_csr_init;
+ NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ return -EACCES;
+
+continue_csr_init:
+ rt2500pci_bbp_write(rt2x00dev, 3, 0x02);
+ rt2500pci_bbp_write(rt2x00dev, 4, 0x19);
+ rt2500pci_bbp_write(rt2x00dev, 14, 0x1c);
+ rt2500pci_bbp_write(rt2x00dev, 15, 0x30);
+ rt2500pci_bbp_write(rt2x00dev, 16, 0xac);
+ rt2500pci_bbp_write(rt2x00dev, 18, 0x18);
+ rt2500pci_bbp_write(rt2x00dev, 19, 0xff);
+ rt2500pci_bbp_write(rt2x00dev, 20, 0x1e);
+ rt2500pci_bbp_write(rt2x00dev, 21, 0x08);
+ rt2500pci_bbp_write(rt2x00dev, 22, 0x08);
+ rt2500pci_bbp_write(rt2x00dev, 23, 0x08);
+ rt2500pci_bbp_write(rt2x00dev, 24, 0x70);
+ rt2500pci_bbp_write(rt2x00dev, 25, 0x40);
+ rt2500pci_bbp_write(rt2x00dev, 26, 0x08);
+ rt2500pci_bbp_write(rt2x00dev, 27, 0x23);
+ rt2500pci_bbp_write(rt2x00dev, 30, 0x10);
+ rt2500pci_bbp_write(rt2x00dev, 31, 0x2b);
+ rt2500pci_bbp_write(rt2x00dev, 32, 0xb9);
+ rt2500pci_bbp_write(rt2x00dev, 34, 0x12);
+ rt2500pci_bbp_write(rt2x00dev, 35, 0x50);
+ rt2500pci_bbp_write(rt2x00dev, 39, 0xc4);
+ rt2500pci_bbp_write(rt2x00dev, 40, 0x02);
+ rt2500pci_bbp_write(rt2x00dev, 41, 0x60);
+ rt2500pci_bbp_write(rt2x00dev, 53, 0x10);
+ rt2500pci_bbp_write(rt2x00dev, 54, 0x18);
+ rt2500pci_bbp_write(rt2x00dev, 56, 0x08);
+ rt2500pci_bbp_write(rt2x00dev, 57, 0x10);
+ rt2500pci_bbp_write(rt2x00dev, 58, 0x08);
+ rt2500pci_bbp_write(rt2x00dev, 61, 0x6d);
+ rt2500pci_bbp_write(rt2x00dev, 62, 0x10);
+
+ DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+ for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+ if (eeprom != 0xffff && eeprom != 0x0000) {
+ reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+ DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+ reg_id, value);
+ rt2500pci_bbp_write(rt2x00dev, reg_id, value);
+ }
+ }
+ DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+ return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX,
+ state == STATE_RADIO_RX_OFF);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
+static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int mask = (state == STATE_RADIO_IRQ_OFF);
+ u32 reg;
+
+ /*
+ * When interrupts are being enabled, the interrupt registers
+ * should clear the register to assure a clean state.
+ */
+ if (state == STATE_RADIO_IRQ_ON) {
+ rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+ }
+
+ /*
+ * Only toggle the interrupts bits we are going to use.
+ * Non-checked interrupt bits are disabled by default.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+ rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, mask);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, mask);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, mask);
+ rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, mask);
+ rt2x00_set_field32(&reg, CSR8_RXDONE, mask);
+ rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+}
+
+static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
+ * Initialize all registers.
+ */
+ if (rt2500pci_init_rings(rt2x00dev) ||
+ rt2500pci_init_registers(rt2x00dev) ||
+ rt2500pci_init_bbp(rt2x00dev)) {
+ ERROR(rt2x00dev, "Register initialization failed.\n");
+ return -EIO;
+ }
+
+ /*
+ * Enable interrupts.
+ */
+ rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON);
+
+ /*
+ * Enable LED
+ */
+ rt2500pci_enable_led(rt2x00dev);
+
+ return 0;
+}
+
+static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Disable LED
+ */
+ rt2500pci_disable_led(rt2x00dev);
+
+ rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0);
+
+ /*
+ * Disable synchronisation.
+ */
+ rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+
+ /*
+ * Cancel RX and TX.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+
+ /*
+ * Disable interrupts.
+ */
+ rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF);
+}
+
+static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+ unsigned int i;
+ char put_to_sleep;
+ char bbp_state;
+ char rf_state;
+
+ put_to_sleep = (state != STATE_AWAKE);
+
+ rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+ rt2x00_set_field32(&reg, PWRCSR1_SET_STATE, 1);
+ rt2x00_set_field32(&reg, PWRCSR1_BBP_DESIRE_STATE, state);
+ rt2x00_set_field32(&reg, PWRCSR1_RF_DESIRE_STATE, state);
+ rt2x00_set_field32(&reg, PWRCSR1_PUT_TO_SLEEP, put_to_sleep);
+ rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg);
+
+ /*
+ * Device is not guaranteed to be in the requested state yet.
+ * We must wait until the register indicates that the
+ * device has entered the correct state.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+ bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE);
+ rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE);
+ if (bbp_state == state && rf_state == state)
+ return 0;
+ msleep(10);
+ }
+
+ NOTICE(rt2x00dev, "Device failed to enter state %d, "
+ "current device state: bbp %d and rf %d.\n",
+ state, bbp_state, rf_state);
+
+ return -EBUSY;
+}
+
+static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int retval = 0;
+
+ switch (state) {
+ case STATE_RADIO_ON:
+ retval = rt2500pci_enable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_OFF:
+ rt2500pci_disable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_OFF:
+ rt2500pci_toggle_rx(rt2x00dev, state);
+ break;
+ case STATE_DEEP_SLEEP:
+ case STATE_SLEEP:
+ case STATE_STANDBY:
+ case STATE_AWAKE:
+ retval = rt2500pci_set_state(rt2x00dev, state);
+ break;
+ default:
+ retval = -ENOTSUPP;
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct txdata_entry_desc *desc,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control)
+{
+ u32 word;
+
+ /*
+ * Start writing the descriptor words.
+ */
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&word, TXD_W2_AIFS, desc->aifs);
+ rt2x00_set_field32(&word, TXD_W2_CWMIN, desc->cw_min);
+ rt2x00_set_field32(&word, TXD_W2_CWMAX, desc->cw_max);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 3, &word);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, desc->signal);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, desc->service);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW, desc->length_low);
+ rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH, desc->length_high);
+ rt2x00_desc_write(txd, 3, word);
+
+ rt2x00_desc_read(txd, 10, &word);
+ rt2x00_set_field32(&word, TXD_W10_RTS,
+ test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags));
+ rt2x00_desc_write(txd, 10, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+ rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+ test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_ACK,
+ !(control->flags & IEEE80211_TXCTL_NO_ACK));
+ rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_OFDM,
+ test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1);
+ rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+ !!(control->flags &
+ IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+ rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+ rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
+ rt2x00_desc_write(txd, 0, word);
+}
+
+/*
+ * TX data initialization
+ */
+static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ unsigned int queue)
+{
+ u32 reg;
+
+ if (queue == IEEE80211_TX_QUEUE_BEACON) {
+ rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+ if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
+ rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+ }
+ return;
+ }
+
+ rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+ if (queue == IEEE80211_TX_QUEUE_DATA0)
+ rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
+ else if (queue == IEEE80211_TX_QUEUE_DATA1)
+ rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
+ else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+ rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+ rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+}
+
+/*
+ * RX control handlers
+ */
+static void rt2500pci_fill_rxdone(struct data_entry *entry,
+ struct rxdata_entry_desc *desc)
+{
+ struct data_desc *rxd = entry->priv;
+ u32 word0;
+ u32 word2;
+
+ rt2x00_desc_read(rxd, 0, &word0);
+ rt2x00_desc_read(rxd, 2, &word2);
+
+ desc->flags = 0;
+ if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+ desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+ if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+ desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
+
+ desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
+ desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
+ entry->ring->rt2x00dev->rssi_offset;
+ desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+ struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+ struct data_entry *entry;
+ struct data_desc *txd;
+ u32 word;
+ int tx_status;
+ int retry;
+
+ while (!rt2x00_ring_empty(ring)) {
+ entry = rt2x00_get_data_entry_done(ring);
+ txd = entry->priv;
+ rt2x00_desc_read(txd, 0, &word);
+
+ if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+ !rt2x00_get_field32(word, TXD_W0_VALID))
+ break;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ tx_status = rt2x00_get_field32(word, TXD_W0_RESULT);
+ retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
+
+ rt2x00lib_txdone(entry, tx_status, retry);
+
+ /*
+ * Make this entry available for reuse.
+ */
+ entry->flags = 0;
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_desc_write(txd, 0, word);
+ rt2x00_ring_index_done_inc(ring);
+ }
+
+ /*
+ * If the data ring was full before the txdone handler
+ * we must make sure the packet queue in the mac80211 stack
+ * is reenabled when the txdone handler has finished.
+ */
+ entry = ring->entry;
+ if (!rt2x00_ring_full(ring))
+ ieee80211_wake_queue(rt2x00dev->hw,
+ entry->tx_status.control.queue);
+}
+
+static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
+{
+ struct rt2x00_dev *rt2x00dev = dev_instance;
+ u32 reg;
+
+ /*
+ * Get the interrupt sources & saved to local variable.
+ * Write register value back to clear pending interrupts.
+ */
+ rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+ rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+
+ if (!reg)
+ return IRQ_NONE;
+
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return IRQ_HANDLED;
+
+ /*
+ * Handle interrupts, walk through all bits
+ * and run the tasks, the bits are checked in order of
+ * priority.
+ */
+
+ /*
+ * 1 - Beacon timer expired interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
+ rt2x00lib_beacondone(rt2x00dev);
+
+ /*
+ * 2 - Rx ring done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_RXDONE))
+ rt2x00pci_rxdone(rt2x00dev);
+
+ /*
+ * 3 - Atim ring transmit done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
+ rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+
+ /*
+ * 4 - Priority ring transmit done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
+ rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+
+ /*
+ * 5 - Tx ring transmit done interrupt.
+ */
+ if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
+ rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ struct eeprom_93cx6 eeprom;
+ u32 reg;
+ u16 word;
+ u8 *mac;
+
+ rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+
+ eeprom.data = rt2x00dev;
+ eeprom.register_read = rt2500pci_eepromregister_read;
+ eeprom.register_write = rt2500pci_eepromregister_write;
+ eeprom.width = rt2x00_get_field32(reg, CSR21_TYPE_93C46) ?
+ PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+ eeprom.reg_data_in = 0;
+ eeprom.reg_data_out = 0;
+ eeprom.reg_data_clock = 0;
+ eeprom.reg_chip_select = 0;
+
+ eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
+ EEPROM_SIZE / sizeof(u16));
+
+ /*
+ * Start validation of the data that has been read.
+ */
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ DECLARE_MAC_BUF(macbuf);
+
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: %s\n",
+ print_mac(macbuf, mac));
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CCK_TX_POWER, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+ EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI,
+ DEFAULT_RSSI_OFFSET);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word);
+ EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word);
+ }
+
+ return 0;
+}
+
+static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 value;
+ u16 eeprom;
+
+ /*
+ * Read EEPROM word for configuration.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Identify RF chipset.
+ */
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
+ rt2x00_set_chip(rt2x00dev, RT2560, value, reg);
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2523) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2524) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2525) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Identify default antenna configuration.
+ */
+ rt2x00dev->hw->conf.antenna_sel_tx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+ rt2x00dev->hw->conf.antenna_sel_rx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+ /*
+ * Store led mode, for correct led behaviour.
+ */
+ rt2x00dev->led_mode =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+
+ /*
+ * Detect if this device has an hardware controlled radio.
+ */
+#ifdef CONFIG_RT2500PCI_RFKILL
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
+ __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+#endif /* CONFIG_RT2500PCI_RFKILL */
+
+ /*
+ * Check if the BBP tuning should be enabled.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
+ __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+
+ /*
+ * Read the RSSI <-> dBm offset information.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom);
+ rt2x00dev->rssi_offset =
+ rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI);
+
+ return 0;
+}
+
+/*
+ * RF value list for RF2522
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2522[] = {
+ { 1, 0x00002050, 0x000c1fda, 0x00000101, 0 },
+ { 2, 0x00002050, 0x000c1fee, 0x00000101, 0 },
+ { 3, 0x00002050, 0x000c2002, 0x00000101, 0 },
+ { 4, 0x00002050, 0x000c2016, 0x00000101, 0 },
+ { 5, 0x00002050, 0x000c202a, 0x00000101, 0 },
+ { 6, 0x00002050, 0x000c203e, 0x00000101, 0 },
+ { 7, 0x00002050, 0x000c2052, 0x00000101, 0 },
+ { 8, 0x00002050, 0x000c2066, 0x00000101, 0 },
+ { 9, 0x00002050, 0x000c207a, 0x00000101, 0 },
+ { 10, 0x00002050, 0x000c208e, 0x00000101, 0 },
+ { 11, 0x00002050, 0x000c20a2, 0x00000101, 0 },
+ { 12, 0x00002050, 0x000c20b6, 0x00000101, 0 },
+ { 13, 0x00002050, 0x000c20ca, 0x00000101, 0 },
+ { 14, 0x00002050, 0x000c20fa, 0x00000101, 0 },
+};
+
+/*
+ * RF value list for RF2523
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2523[] = {
+ { 1, 0x00022010, 0x00000c9e, 0x000e0111, 0x00000a1b },
+ { 2, 0x00022010, 0x00000ca2, 0x000e0111, 0x00000a1b },
+ { 3, 0x00022010, 0x00000ca6, 0x000e0111, 0x00000a1b },
+ { 4, 0x00022010, 0x00000caa, 0x000e0111, 0x00000a1b },
+ { 5, 0x00022010, 0x00000cae, 0x000e0111, 0x00000a1b },
+ { 6, 0x00022010, 0x00000cb2, 0x000e0111, 0x00000a1b },
+ { 7, 0x00022010, 0x00000cb6, 0x000e0111, 0x00000a1b },
+ { 8, 0x00022010, 0x00000cba, 0x000e0111, 0x00000a1b },
+ { 9, 0x00022010, 0x00000cbe, 0x000e0111, 0x00000a1b },
+ { 10, 0x00022010, 0x00000d02, 0x000e0111, 0x00000a1b },
+ { 11, 0x00022010, 0x00000d06, 0x000e0111, 0x00000a1b },
+ { 12, 0x00022010, 0x00000d0a, 0x000e0111, 0x00000a1b },
+ { 13, 0x00022010, 0x00000d0e, 0x000e0111, 0x00000a1b },
+ { 14, 0x00022010, 0x00000d1a, 0x000e0111, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2524
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2524[] = {
+ { 1, 0x00032020, 0x00000c9e, 0x00000101, 0x00000a1b },
+ { 2, 0x00032020, 0x00000ca2, 0x00000101, 0x00000a1b },
+ { 3, 0x00032020, 0x00000ca6, 0x00000101, 0x00000a1b },
+ { 4, 0x00032020, 0x00000caa, 0x00000101, 0x00000a1b },
+ { 5, 0x00032020, 0x00000cae, 0x00000101, 0x00000a1b },
+ { 6, 0x00032020, 0x00000cb2, 0x00000101, 0x00000a1b },
+ { 7, 0x00032020, 0x00000cb6, 0x00000101, 0x00000a1b },
+ { 8, 0x00032020, 0x00000cba, 0x00000101, 0x00000a1b },
+ { 9, 0x00032020, 0x00000cbe, 0x00000101, 0x00000a1b },
+ { 10, 0x00032020, 0x00000d02, 0x00000101, 0x00000a1b },
+ { 11, 0x00032020, 0x00000d06, 0x00000101, 0x00000a1b },
+ { 12, 0x00032020, 0x00000d0a, 0x00000101, 0x00000a1b },
+ { 13, 0x00032020, 0x00000d0e, 0x00000101, 0x00000a1b },
+ { 14, 0x00032020, 0x00000d1a, 0x00000101, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2525
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2525[] = {
+ { 1, 0x00022020, 0x00080c9e, 0x00060111, 0x00000a1b },
+ { 2, 0x00022020, 0x00080ca2, 0x00060111, 0x00000a1b },
+ { 3, 0x00022020, 0x00080ca6, 0x00060111, 0x00000a1b },
+ { 4, 0x00022020, 0x00080caa, 0x00060111, 0x00000a1b },
+ { 5, 0x00022020, 0x00080cae, 0x00060111, 0x00000a1b },
+ { 6, 0x00022020, 0x00080cb2, 0x00060111, 0x00000a1b },
+ { 7, 0x00022020, 0x00080cb6, 0x00060111, 0x00000a1b },
+ { 8, 0x00022020, 0x00080cba, 0x00060111, 0x00000a1b },
+ { 9, 0x00022020, 0x00080cbe, 0x00060111, 0x00000a1b },
+ { 10, 0x00022020, 0x00080d02, 0x00060111, 0x00000a1b },
+ { 11, 0x00022020, 0x00080d06, 0x00060111, 0x00000a1b },
+ { 12, 0x00022020, 0x00080d0a, 0x00060111, 0x00000a1b },
+ { 13, 0x00022020, 0x00080d0e, 0x00060111, 0x00000a1b },
+ { 14, 0x00022020, 0x00080d1a, 0x00060111, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2525e
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2525e[] = {
+ { 1, 0x00022020, 0x00081136, 0x00060111, 0x00000a0b },
+ { 2, 0x00022020, 0x0008113a, 0x00060111, 0x00000a0b },
+ { 3, 0x00022020, 0x0008113e, 0x00060111, 0x00000a0b },
+ { 4, 0x00022020, 0x00081182, 0x00060111, 0x00000a0b },
+ { 5, 0x00022020, 0x00081186, 0x00060111, 0x00000a0b },
+ { 6, 0x00022020, 0x0008118a, 0x00060111, 0x00000a0b },
+ { 7, 0x00022020, 0x0008118e, 0x00060111, 0x00000a0b },
+ { 8, 0x00022020, 0x00081192, 0x00060111, 0x00000a0b },
+ { 9, 0x00022020, 0x00081196, 0x00060111, 0x00000a0b },
+ { 10, 0x00022020, 0x0008119a, 0x00060111, 0x00000a0b },
+ { 11, 0x00022020, 0x0008119e, 0x00060111, 0x00000a0b },
+ { 12, 0x00022020, 0x000811a2, 0x00060111, 0x00000a0b },
+ { 13, 0x00022020, 0x000811a6, 0x00060111, 0x00000a0b },
+ { 14, 0x00022020, 0x000811ae, 0x00060111, 0x00000a1b },
+};
+
+/*
+ * RF value list for RF5222
+ * Supports: 2.4 GHz & 5.2 GHz
+ */
+static const struct rf_channel rf_vals_5222[] = {
+ { 1, 0x00022020, 0x00001136, 0x00000101, 0x00000a0b },
+ { 2, 0x00022020, 0x0000113a, 0x00000101, 0x00000a0b },
+ { 3, 0x00022020, 0x0000113e, 0x00000101, 0x00000a0b },
+ { 4, 0x00022020, 0x00001182, 0x00000101, 0x00000a0b },
+ { 5, 0x00022020, 0x00001186, 0x00000101, 0x00000a0b },
+ { 6, 0x00022020, 0x0000118a, 0x00000101, 0x00000a0b },
+ { 7, 0x00022020, 0x0000118e, 0x00000101, 0x00000a0b },
+ { 8, 0x00022020, 0x00001192, 0x00000101, 0x00000a0b },
+ { 9, 0x00022020, 0x00001196, 0x00000101, 0x00000a0b },
+ { 10, 0x00022020, 0x0000119a, 0x00000101, 0x00000a0b },
+ { 11, 0x00022020, 0x0000119e, 0x00000101, 0x00000a0b },
+ { 12, 0x00022020, 0x000011a2, 0x00000101, 0x00000a0b },
+ { 13, 0x00022020, 0x000011a6, 0x00000101, 0x00000a0b },
+ { 14, 0x00022020, 0x000011ae, 0x00000101, 0x00000a1b },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x00022010, 0x00018896, 0x00000101, 0x00000a1f },
+ { 40, 0x00022010, 0x0001889a, 0x00000101, 0x00000a1f },
+ { 44, 0x00022010, 0x0001889e, 0x00000101, 0x00000a1f },
+ { 48, 0x00022010, 0x000188a2, 0x00000101, 0x00000a1f },
+ { 52, 0x00022010, 0x000188a6, 0x00000101, 0x00000a1f },
+ { 66, 0x00022010, 0x000188aa, 0x00000101, 0x00000a1f },
+ { 60, 0x00022010, 0x000188ae, 0x00000101, 0x00000a1f },
+ { 64, 0x00022010, 0x000188b2, 0x00000101, 0x00000a1f },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x00022010, 0x00008802, 0x00000101, 0x00000a0f },
+ { 104, 0x00022010, 0x00008806, 0x00000101, 0x00000a0f },
+ { 108, 0x00022010, 0x0000880a, 0x00000101, 0x00000a0f },
+ { 112, 0x00022010, 0x0000880e, 0x00000101, 0x00000a0f },
+ { 116, 0x00022010, 0x00008812, 0x00000101, 0x00000a0f },
+ { 120, 0x00022010, 0x00008816, 0x00000101, 0x00000a0f },
+ { 124, 0x00022010, 0x0000881a, 0x00000101, 0x00000a0f },
+ { 128, 0x00022010, 0x0000881e, 0x00000101, 0x00000a0f },
+ { 132, 0x00022010, 0x00008822, 0x00000101, 0x00000a0f },
+ { 136, 0x00022010, 0x00008826, 0x00000101, 0x00000a0f },
+
+ /* 802.11 UNII */
+ { 140, 0x00022010, 0x0000882a, 0x00000101, 0x00000a0f },
+ { 149, 0x00022020, 0x000090a6, 0x00000101, 0x00000a07 },
+ { 153, 0x00022020, 0x000090ae, 0x00000101, 0x00000a07 },
+ { 157, 0x00022020, 0x000090b6, 0x00000101, 0x00000a07 },
+ { 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 },
+};
+
+static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ u8 *txpower;
+ unsigned int i;
+
+ /*
+ * Initialize all hw fields.
+ */
+ rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ rt2x00dev->hw->extra_tx_headroom = 0;
+ rt2x00dev->hw->max_signal = MAX_SIGNAL;
+ rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+ rt2x00dev->hw->queues = 2;
+
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev,
+ EEPROM_MAC_ADDR_0));
+
+ /*
+ * Convert tx_power array in eeprom.
+ */
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ /*
+ * Initialize hw_mode information.
+ */
+ spec->num_modes = 2;
+ spec->num_rates = 12;
+ spec->tx_power_a = NULL;
+ spec->tx_power_bg = txpower;
+ spec->tx_power_default = DEFAULT_TXPOWER;
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
+ spec->channels = rf_vals_bg_2522;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
+ spec->channels = rf_vals_bg_2523;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
+ spec->channels = rf_vals_bg_2524;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
+ spec->channels = rf_vals_bg_2525;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
+ spec->channels = rf_vals_bg_2525e;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_5222);
+ spec->channels = rf_vals_5222;
+ spec->num_modes = 3;
+ }
+}
+
+static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ /*
+ * Allocate eeprom data.
+ */
+ retval = rt2500pci_validate_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt2500pci_init_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * Initialize hw specifications.
+ */
+ rt2500pci_probe_hw_mode(rt2x00dev);
+
+ /*
+ * This device requires the beacon ring
+ */
+ __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+ return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt2500pci_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+ u32 reg;
+
+ /*
+ * Mask off any flags we are going to ignore from
+ * the total_flags field.
+ */
+ *total_flags &=
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_PROMISC_IN_BSS;
+
+ /*
+ * Apply some rules to the filters:
+ * - Some filters imply different filters to be set.
+ * - Some things we can't filter out at all.
+ * - Some filters are set based on interface type.
+ */
+ if (mc_count)
+ *total_flags |= FIF_ALLMULTI;
+ if (*total_flags & FIF_OTHER_BSS ||
+ *total_flags & FIF_PROMISC_IN_BSS)
+ *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+ if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+ *total_flags |= FIF_PROMISC_IN_BSS;
+
+ /*
+ * Check if there is any work left for us.
+ */
+ if (intf->filter == *total_flags)
+ return;
+ intf->filter = *total_flags;
+
+ /*
+ * Start configuration steps.
+ * Note that the version error will always be dropped
+ * and broadcast frames will always be accepted since
+ * there is no filter for it at this time.
+ */
+ rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+ rt2x00_set_field32(&reg, RXCSR0_DROP_CRC,
+ !(*total_flags & FIF_FCSFAIL));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL,
+ !(*total_flags & FIF_PLCPFAIL));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
+ !(*total_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
+ rt2x00_set_field32(&reg, RXCSR0_DROP_MCAST,
+ !(*total_flags & FIF_ALLMULTI));
+ rt2x00_set_field32(&reg, RXCSR0_DROP_BCAST, 0);
+ rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
+static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw,
+ u32 short_retry, u32 long_retry)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+ rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
+ rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
+ rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+ return 0;
+}
+
+static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u64 tsf;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR17, &reg);
+ tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32;
+ rt2x00pci_register_read(rt2x00dev, CSR16, &reg);
+ tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER);
+
+ return tsf;
+}
+
+static void rt2500pci_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ rt2x00pci_register_write(rt2x00dev, CSR16, 0);
+ rt2x00pci_register_write(rt2x00dev, CSR17, 0);
+}
+
+static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, CSR15, &reg);
+ return rt2x00_get_field32(reg, CSR15_BEACON_SENT);
+}
+
+static const struct ieee80211_ops rt2500pci_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .config_interface = rt2x00mac_config_interface,
+ .configure_filter = rt2500pci_configure_filter,
+ .get_stats = rt2x00mac_get_stats,
+ .set_retry_limit = rt2500pci_set_retry_limit,
+ .erp_ie_changed = rt2x00mac_erp_ie_changed,
+ .conf_tx = rt2x00mac_conf_tx,
+ .get_tx_stats = rt2x00mac_get_tx_stats,
+ .get_tsf = rt2500pci_get_tsf,
+ .reset_tsf = rt2500pci_reset_tsf,
+ .beacon_update = rt2x00pci_beacon_update,
+ .tx_last_beacon = rt2500pci_tx_last_beacon,
+};
+
+static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
+ .irq_handler = rt2500pci_interrupt,
+ .probe_hw = rt2500pci_probe_hw,
+ .initialize = rt2x00pci_initialize,
+ .uninitialize = rt2x00pci_uninitialize,
+ .set_device_state = rt2500pci_set_device_state,
+ .rfkill_poll = rt2500pci_rfkill_poll,
+ .link_stats = rt2500pci_link_stats,
+ .reset_tuner = rt2500pci_reset_tuner,
+ .link_tuner = rt2500pci_link_tuner,
+ .write_tx_desc = rt2500pci_write_tx_desc,
+ .write_tx_data = rt2x00pci_write_tx_data,
+ .kick_tx_queue = rt2500pci_kick_tx_queue,
+ .fill_rxdone = rt2500pci_fill_rxdone,
+ .config_mac_addr = rt2500pci_config_mac_addr,
+ .config_bssid = rt2500pci_config_bssid,
+ .config_type = rt2500pci_config_type,
+ .config_preamble = rt2500pci_config_preamble,
+ .config = rt2500pci_config,
+};
+
+static const struct rt2x00_ops rt2500pci_ops = {
+ .name = DRV_NAME,
+ .rxd_size = RXD_DESC_SIZE,
+ .txd_size = TXD_DESC_SIZE,
+ .eeprom_size = EEPROM_SIZE,
+ .rf_size = RF_SIZE,
+ .lib = &rt2500pci_rt2x00_ops,
+ .hw = &rt2500pci_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ .debugfs = &rt2500pci_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * RT2500pci module information.
+ */
+static struct pci_device_id rt2500pci_device_table[] = {
+ { PCI_DEVICE(0x1814, 0x0201), PCI_DEVICE_DATA(&rt2500pci_ops) },
+ { 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT2500 PCI & PCMCIA Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2560 PCI & PCMCIA chipset based cards");
+MODULE_DEVICE_TABLE(pci, rt2500pci_device_table);
+MODULE_LICENSE("GPL");
+
+static struct pci_driver rt2500pci_driver = {
+ .name = DRV_NAME,
+ .id_table = rt2500pci_device_table,
+ .probe = rt2x00pci_probe,
+ .remove = __devexit_p(rt2x00pci_remove),
+ .suspend = rt2x00pci_suspend,
+ .resume = rt2x00pci_resume,
+};
+
+static int __init rt2500pci_init(void)
+{
+ return pci_register_driver(&rt2500pci_driver);
+}
+
+static void __exit rt2500pci_exit(void)
+{
+ pci_unregister_driver(&rt2500pci_driver);
+}
+
+module_init(rt2500pci_init);
+module_exit(rt2500pci_exit);
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
new file mode 100644
index 00000000000..d92aa56b2f4
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -0,0 +1,1236 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2500pci
+ Abstract: Data structures and registers for the rt2500pci module.
+ Supported chipsets: RT2560.
+ */
+
+#ifndef RT2500PCI_H
+#define RT2500PCI_H
+
+/*
+ * RF chip defines.
+ */
+#define RF2522 0x0000
+#define RF2523 0x0001
+#define RF2524 0x0002
+#define RF2525 0x0003
+#define RF2525E 0x0004
+#define RF5222 0x0010
+
+/*
+ * RT2560 version
+ */
+#define RT2560_VERSION_B 2
+#define RT2560_VERSION_C 3
+#define RT2560_VERSION_D 4
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL 100
+#define MAX_RX_SSI -1
+#define DEFAULT_RSSI_OFFSET 121
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE 0x0000
+#define CSR_REG_SIZE 0x0174
+#define EEPROM_BASE 0x0000
+#define EEPROM_SIZE 0x0200
+#define BBP_SIZE 0x0040
+#define RF_SIZE 0x0014
+
+/*
+ * Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * CSR0: ASIC revision number.
+ */
+#define CSR0 0x0000
+
+/*
+ * CSR1: System control register.
+ * SOFT_RESET: Software reset, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset, 1: reset, 0, release.
+ * HOST_READY: Host ready after initialization.
+ */
+#define CSR1 0x0004
+#define CSR1_SOFT_RESET FIELD32(0x00000001)
+#define CSR1_BBP_RESET FIELD32(0x00000002)
+#define CSR1_HOST_READY FIELD32(0x00000004)
+
+/*
+ * CSR2: System admin status register (invalid).
+ */
+#define CSR2 0x0008
+
+/*
+ * CSR3: STA MAC address register 0.
+ */
+#define CSR3 0x000c
+#define CSR3_BYTE0 FIELD32(0x000000ff)
+#define CSR3_BYTE1 FIELD32(0x0000ff00)
+#define CSR3_BYTE2 FIELD32(0x00ff0000)
+#define CSR3_BYTE3 FIELD32(0xff000000)
+
+/*
+ * CSR4: STA MAC address register 1.
+ */
+#define CSR4 0x0010
+#define CSR4_BYTE4 FIELD32(0x000000ff)
+#define CSR4_BYTE5 FIELD32(0x0000ff00)
+
+/*
+ * CSR5: BSSID register 0.
+ */
+#define CSR5 0x0014
+#define CSR5_BYTE0 FIELD32(0x000000ff)
+#define CSR5_BYTE1 FIELD32(0x0000ff00)
+#define CSR5_BYTE2 FIELD32(0x00ff0000)
+#define CSR5_BYTE3 FIELD32(0xff000000)
+
+/*
+ * CSR6: BSSID register 1.
+ */
+#define CSR6 0x0018
+#define CSR6_BYTE4 FIELD32(0x000000ff)
+#define CSR6_BYTE5 FIELD32(0x0000ff00)
+
+/*
+ * CSR7: Interrupt source register.
+ * Write 1 to clear.
+ * TBCN_EXPIRE: Beacon timer expired interrupt.
+ * TWAKE_EXPIRE: Wakeup timer expired interrupt.
+ * TATIMW_EXPIRE: Timer of atim window expired interrupt.
+ * TXDONE_TXRING: Tx ring transmit done interrupt.
+ * TXDONE_ATIMRING: Atim ring transmit done interrupt.
+ * TXDONE_PRIORING: Priority ring transmit done interrupt.
+ * RXDONE: Receive done interrupt.
+ * DECRYPTION_DONE: Decryption done interrupt.
+ * ENCRYPTION_DONE: Encryption done interrupt.
+ * UART1_TX_TRESHOLD: UART1 TX reaches threshold.
+ * UART1_RX_TRESHOLD: UART1 RX reaches threshold.
+ * UART1_IDLE_TRESHOLD: UART1 IDLE over threshold.
+ * UART1_TX_BUFF_ERROR: UART1 TX buffer error.
+ * UART1_RX_BUFF_ERROR: UART1 RX buffer error.
+ * UART2_TX_TRESHOLD: UART2 TX reaches threshold.
+ * UART2_RX_TRESHOLD: UART2 RX reaches threshold.
+ * UART2_IDLE_TRESHOLD: UART2 IDLE over threshold.
+ * UART2_TX_BUFF_ERROR: UART2 TX buffer error.
+ * UART2_RX_BUFF_ERROR: UART2 RX buffer error.
+ * TIMER_CSR3_EXPIRE: TIMECSR3 timer expired (802.1H quiet period).
+
+ */
+#define CSR7 0x001c
+#define CSR7_TBCN_EXPIRE FIELD32(0x00000001)
+#define CSR7_TWAKE_EXPIRE FIELD32(0x00000002)
+#define CSR7_TATIMW_EXPIRE FIELD32(0x00000004)
+#define CSR7_TXDONE_TXRING FIELD32(0x00000008)
+#define CSR7_TXDONE_ATIMRING FIELD32(0x00000010)
+#define CSR7_TXDONE_PRIORING FIELD32(0x00000020)
+#define CSR7_RXDONE FIELD32(0x00000040)
+#define CSR7_DECRYPTION_DONE FIELD32(0x00000080)
+#define CSR7_ENCRYPTION_DONE FIELD32(0x00000100)
+#define CSR7_UART1_TX_TRESHOLD FIELD32(0x00000200)
+#define CSR7_UART1_RX_TRESHOLD FIELD32(0x00000400)
+#define CSR7_UART1_IDLE_TRESHOLD FIELD32(0x00000800)
+#define CSR7_UART1_TX_BUFF_ERROR FIELD32(0x00001000)
+#define CSR7_UART1_RX_BUFF_ERROR FIELD32(0x00002000)
+#define CSR7_UART2_TX_TRESHOLD FIELD32(0x00004000)
+#define CSR7_UART2_RX_TRESHOLD FIELD32(0x00008000)
+#define CSR7_UART2_IDLE_TRESHOLD FIELD32(0x00010000)
+#define CSR7_UART2_TX_BUFF_ERROR FIELD32(0x00020000)
+#define CSR7_UART2_RX_BUFF_ERROR FIELD32(0x00040000)
+#define CSR7_TIMER_CSR3_EXPIRE FIELD32(0x00080000)
+
+/*
+ * CSR8: Interrupt mask register.
+ * Write 1 to mask interrupt.
+ * TBCN_EXPIRE: Beacon timer expired interrupt.
+ * TWAKE_EXPIRE: Wakeup timer expired interrupt.
+ * TATIMW_EXPIRE: Timer of atim window expired interrupt.
+ * TXDONE_TXRING: Tx ring transmit done interrupt.
+ * TXDONE_ATIMRING: Atim ring transmit done interrupt.
+ * TXDONE_PRIORING: Priority ring transmit done interrupt.
+ * RXDONE: Receive done interrupt.
+ * DECRYPTION_DONE: Decryption done interrupt.
+ * ENCRYPTION_DONE: Encryption done interrupt.
+ * UART1_TX_TRESHOLD: UART1 TX reaches threshold.
+ * UART1_RX_TRESHOLD: UART1 RX reaches threshold.
+ * UART1_IDLE_TRESHOLD: UART1 IDLE over threshold.
+ * UART1_TX_BUFF_ERROR: UART1 TX buffer error.
+ * UART1_RX_BUFF_ERROR: UART1 RX buffer error.
+ * UART2_TX_TRESHOLD: UART2 TX reaches threshold.
+ * UART2_RX_TRESHOLD: UART2 RX reaches threshold.
+ * UART2_IDLE_TRESHOLD: UART2 IDLE over threshold.
+ * UART2_TX_BUFF_ERROR: UART2 TX buffer error.
+ * UART2_RX_BUFF_ERROR: UART2 RX buffer error.
+ * TIMER_CSR3_EXPIRE: TIMECSR3 timer expired (802.1H quiet period).
+ */
+#define CSR8 0x0020
+#define CSR8_TBCN_EXPIRE FIELD32(0x00000001)
+#define CSR8_TWAKE_EXPIRE FIELD32(0x00000002)
+#define CSR8_TATIMW_EXPIRE FIELD32(0x00000004)
+#define CSR8_TXDONE_TXRING FIELD32(0x00000008)
+#define CSR8_TXDONE_ATIMRING FIELD32(0x00000010)
+#define CSR8_TXDONE_PRIORING FIELD32(0x00000020)
+#define CSR8_RXDONE FIELD32(0x00000040)
+#define CSR8_DECRYPTION_DONE FIELD32(0x00000080)
+#define CSR8_ENCRYPTION_DONE FIELD32(0x00000100)
+#define CSR8_UART1_TX_TRESHOLD FIELD32(0x00000200)
+#define CSR8_UART1_RX_TRESHOLD FIELD32(0x00000400)
+#define CSR8_UART1_IDLE_TRESHOLD FIELD32(0x00000800)
+#define CSR8_UART1_TX_BUFF_ERROR FIELD32(0x00001000)
+#define CSR8_UART1_RX_BUFF_ERROR FIELD32(0x00002000)
+#define CSR8_UART2_TX_TRESHOLD FIELD32(0x00004000)
+#define CSR8_UART2_RX_TRESHOLD FIELD32(0x00008000)
+#define CSR8_UART2_IDLE_TRESHOLD FIELD32(0x00010000)
+#define CSR8_UART2_TX_BUFF_ERROR FIELD32(0x00020000)
+#define CSR8_UART2_RX_BUFF_ERROR FIELD32(0x00040000)
+#define CSR8_TIMER_CSR3_EXPIRE FIELD32(0x00080000)
+
+/*
+ * CSR9: Maximum frame length register.
+ * MAX_FRAME_UNIT: Maximum frame length in 128b unit, default: 12.
+ */
+#define CSR9 0x0024
+#define CSR9_MAX_FRAME_UNIT FIELD32(0x00000f80)
+
+/*
+ * SECCSR0: WEP control register.
+ * KICK_DECRYPT: Kick decryption engine, self-clear.
+ * ONE_SHOT: 0: ring mode, 1: One shot only mode.
+ * DESC_ADDRESS: Descriptor physical address of frame.
+ */
+#define SECCSR0 0x0028
+#define SECCSR0_KICK_DECRYPT FIELD32(0x00000001)
+#define SECCSR0_ONE_SHOT FIELD32(0x00000002)
+#define SECCSR0_DESC_ADDRESS FIELD32(0xfffffffc)
+
+/*
+ * CSR11: Back-off control register.
+ * CWMIN: CWmin. Default cwmin is 31 (2^5 - 1).
+ * CWMAX: CWmax. Default cwmax is 1023 (2^10 - 1).
+ * SLOT_TIME: Slot time, default is 20us for 802.11b
+ * CW_SELECT: CWmin/CWmax selection, 1: Register, 0: TXD.
+ * LONG_RETRY: Long retry count.
+ * SHORT_RETRY: Short retry count.
+ */
+#define CSR11 0x002c
+#define CSR11_CWMIN FIELD32(0x0000000f)
+#define CSR11_CWMAX FIELD32(0x000000f0)
+#define CSR11_SLOT_TIME FIELD32(0x00001f00)
+#define CSR11_CW_SELECT FIELD32(0x00002000)
+#define CSR11_LONG_RETRY FIELD32(0x00ff0000)
+#define CSR11_SHORT_RETRY FIELD32(0xff000000)
+
+/*
+ * CSR12: Synchronization configuration register 0.
+ * All units in 1/16 TU.
+ * BEACON_INTERVAL: Beacon interval, default is 100 TU.
+ * CFP_MAX_DURATION: Cfp maximum duration, default is 100 TU.
+ */
+#define CSR12 0x0030
+#define CSR12_BEACON_INTERVAL FIELD32(0x0000ffff)
+#define CSR12_CFP_MAX_DURATION FIELD32(0xffff0000)
+
+/*
+ * CSR13: Synchronization configuration register 1.
+ * All units in 1/16 TU.
+ * ATIMW_DURATION: Atim window duration.
+ * CFP_PERIOD: Cfp period, default is 0 TU.
+ */
+#define CSR13 0x0034
+#define CSR13_ATIMW_DURATION FIELD32(0x0000ffff)
+#define CSR13_CFP_PERIOD FIELD32(0x00ff0000)
+
+/*
+ * CSR14: Synchronization control register.
+ * TSF_COUNT: Enable tsf auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * TBCN: Enable tbcn with reload value.
+ * TCFP: Enable tcfp & cfp / cp switching.
+ * TATIMW: Enable tatimw & atim window switching.
+ * BEACON_GEN: Enable beacon generator.
+ * CFP_COUNT_PRELOAD: Cfp count preload value.
+ * TBCM_PRELOAD: Tbcn preload value in units of 64us.
+ */
+#define CSR14 0x0038
+#define CSR14_TSF_COUNT FIELD32(0x00000001)
+#define CSR14_TSF_SYNC FIELD32(0x00000006)
+#define CSR14_TBCN FIELD32(0x00000008)
+#define CSR14_TCFP FIELD32(0x00000010)
+#define CSR14_TATIMW FIELD32(0x00000020)
+#define CSR14_BEACON_GEN FIELD32(0x00000040)
+#define CSR14_CFP_COUNT_PRELOAD FIELD32(0x0000ff00)
+#define CSR14_TBCM_PRELOAD FIELD32(0xffff0000)
+
+/*
+ * CSR15: Synchronization status register.
+ * CFP: ASIC is in contention-free period.
+ * ATIMW: ASIC is in ATIM window.
+ * BEACON_SENT: Beacon is send.
+ */
+#define CSR15 0x003c
+#define CSR15_CFP FIELD32(0x00000001)
+#define CSR15_ATIMW FIELD32(0x00000002)
+#define CSR15_BEACON_SENT FIELD32(0x00000004)
+
+/*
+ * CSR16: TSF timer register 0.
+ */
+#define CSR16 0x0040
+#define CSR16_LOW_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * CSR17: TSF timer register 1.
+ */
+#define CSR17 0x0044
+#define CSR17_HIGH_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * CSR18: IFS timer register 0.
+ * SIFS: Sifs, default is 10 us.
+ * PIFS: Pifs, default is 30 us.
+ */
+#define CSR18 0x0048
+#define CSR18_SIFS FIELD32(0x000001ff)
+#define CSR18_PIFS FIELD32(0x001f0000)
+
+/*
+ * CSR19: IFS timer register 1.
+ * DIFS: Difs, default is 50 us.
+ * EIFS: Eifs, default is 364 us.
+ */
+#define CSR19 0x004c
+#define CSR19_DIFS FIELD32(0x0000ffff)
+#define CSR19_EIFS FIELD32(0xffff0000)
+
+/*
+ * CSR20: Wakeup timer register.
+ * DELAY_AFTER_TBCN: Delay after tbcn expired in units of 1/16 TU.
+ * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * AUTOWAKE: Enable auto wakeup / sleep mechanism.
+ */
+#define CSR20 0x0050
+#define CSR20_DELAY_AFTER_TBCN FIELD32(0x0000ffff)
+#define CSR20_TBCN_BEFORE_WAKEUP FIELD32(0x00ff0000)
+#define CSR20_AUTOWAKE FIELD32(0x01000000)
+
+/*
+ * CSR21: EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE_93C46: 1: 93c46, 0:93c66.
+ */
+#define CSR21 0x0054
+#define CSR21_RELOAD FIELD32(0x00000001)
+#define CSR21_EEPROM_DATA_CLOCK FIELD32(0x00000002)
+#define CSR21_EEPROM_CHIP_SELECT FIELD32(0x00000004)
+#define CSR21_EEPROM_DATA_IN FIELD32(0x00000008)
+#define CSR21_EEPROM_DATA_OUT FIELD32(0x00000010)
+#define CSR21_TYPE_93C46 FIELD32(0x00000020)
+
+/*
+ * CSR22: CFP control register.
+ * CFP_DURATION_REMAIN: Cfp duration remain, in units of TU.
+ * RELOAD_CFP_DURATION: Write 1 to reload cfp duration remain.
+ */
+#define CSR22 0x0058
+#define CSR22_CFP_DURATION_REMAIN FIELD32(0x0000ffff)
+#define CSR22_RELOAD_CFP_DURATION FIELD32(0x00010000)
+
+/*
+ * Transmit related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXCSR0: TX Control Register.
+ * KICK_TX: Kick tx ring.
+ * KICK_ATIM: Kick atim ring.
+ * KICK_PRIO: Kick priority ring.
+ * ABORT: Abort all transmit related ring operation.
+ */
+#define TXCSR0 0x0060
+#define TXCSR0_KICK_TX FIELD32(0x00000001)
+#define TXCSR0_KICK_ATIM FIELD32(0x00000002)
+#define TXCSR0_KICK_PRIO FIELD32(0x00000004)
+#define TXCSR0_ABORT FIELD32(0x00000008)
+
+/*
+ * TXCSR1: TX Configuration Register.
+ * ACK_TIMEOUT: Ack timeout, default = sifs + 2*slottime + acktime @ 1mbps.
+ * ACK_CONSUME_TIME: Ack consume time, default = sifs + acktime @ 1mbps.
+ * TSF_OFFSET: Insert tsf offset.
+ * AUTORESPONDER: Enable auto responder which include ack & cts.
+ */
+#define TXCSR1 0x0064
+#define TXCSR1_ACK_TIMEOUT FIELD32(0x000001ff)
+#define TXCSR1_ACK_CONSUME_TIME FIELD32(0x0003fe00)
+#define TXCSR1_TSF_OFFSET FIELD32(0x00fc0000)
+#define TXCSR1_AUTORESPONDER FIELD32(0x01000000)
+
+/*
+ * TXCSR2: Tx descriptor configuration register.
+ * TXD_SIZE: Tx descriptor size, default is 48.
+ * NUM_TXD: Number of tx entries in ring.
+ * NUM_ATIM: Number of atim entries in ring.
+ * NUM_PRIO: Number of priority entries in ring.
+ */
+#define TXCSR2 0x0068
+#define TXCSR2_TXD_SIZE FIELD32(0x000000ff)
+#define TXCSR2_NUM_TXD FIELD32(0x0000ff00)
+#define TXCSR2_NUM_ATIM FIELD32(0x00ff0000)
+#define TXCSR2_NUM_PRIO FIELD32(0xff000000)
+
+/*
+ * TXCSR3: TX Ring Base address register.
+ */
+#define TXCSR3 0x006c
+#define TXCSR3_TX_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR4: TX Atim Ring Base address register.
+ */
+#define TXCSR4 0x0070
+#define TXCSR4_ATIM_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR5: TX Prio Ring Base address register.
+ */
+#define TXCSR5 0x0074
+#define TXCSR5_PRIO_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR6: Beacon Base address register.
+ */
+#define TXCSR6 0x0078
+#define TXCSR6_BEACON_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TXCSR7: Auto responder control register.
+ * AR_POWERMANAGEMENT: Auto responder power management bit.
+ */
+#define TXCSR7 0x007c
+#define TXCSR7_AR_POWERMANAGEMENT FIELD32(0x00000001)
+
+/*
+ * TXCSR8: CCK Tx BBP register.
+ */
+#define TXCSR8 0x0098
+#define TXCSR8_BBP_ID0 FIELD32(0x0000007f)
+#define TXCSR8_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXCSR8_BBP_ID1 FIELD32(0x00007f00)
+#define TXCSR8_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXCSR8_BBP_ID2 FIELD32(0x007f0000)
+#define TXCSR8_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXCSR8_BBP_ID3 FIELD32(0x7f000000)
+#define TXCSR8_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXCSR9: OFDM TX BBP registers
+ * OFDM_SIGNAL: BBP rate field address for OFDM.
+ * OFDM_SERVICE: BBP service field address for OFDM.
+ * OFDM_LENGTH_LOW: BBP length low byte address for OFDM.
+ * OFDM_LENGTH_HIGH: BBP length high byte address for OFDM.
+ */
+#define TXCSR9 0x0094
+#define TXCSR9_OFDM_RATE FIELD32(0x000000ff)
+#define TXCSR9_OFDM_SERVICE FIELD32(0x0000ff00)
+#define TXCSR9_OFDM_LENGTH_LOW FIELD32(0x00ff0000)
+#define TXCSR9_OFDM_LENGTH_HIGH FIELD32(0xff000000)
+
+/*
+ * Receive related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * RXCSR0: RX Control Register.
+ * DISABLE_RX: Disable rx engine.
+ * DROP_CRC: Drop crc error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TODS: Drop frame tods bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * PASS_CRC: Pass all packets with crc attached.
+ * PASS_CRC: Pass all packets with crc attached.
+ * PASS_PLCP: Pass all packets with 4 bytes PLCP attached.
+ * DROP_MCAST: Drop multicast frames.
+ * DROP_BCAST: Drop broadcast frames.
+ * ENABLE_QOS: Accept QOS data frame and parse QOS field.
+ */
+#define RXCSR0 0x0080
+#define RXCSR0_DISABLE_RX FIELD32(0x00000001)
+#define RXCSR0_DROP_CRC FIELD32(0x00000002)
+#define RXCSR0_DROP_PHYSICAL FIELD32(0x00000004)
+#define RXCSR0_DROP_CONTROL FIELD32(0x00000008)
+#define RXCSR0_DROP_NOT_TO_ME FIELD32(0x00000010)
+#define RXCSR0_DROP_TODS FIELD32(0x00000020)
+#define RXCSR0_DROP_VERSION_ERROR FIELD32(0x00000040)
+#define RXCSR0_PASS_CRC FIELD32(0x00000080)
+#define RXCSR0_PASS_PLCP FIELD32(0x00000100)
+#define RXCSR0_DROP_MCAST FIELD32(0x00000200)
+#define RXCSR0_DROP_BCAST FIELD32(0x00000400)
+#define RXCSR0_ENABLE_QOS FIELD32(0x00000800)
+
+/*
+ * RXCSR1: RX descriptor configuration register.
+ * RXD_SIZE: Rx descriptor size, default is 32b.
+ * NUM_RXD: Number of rx entries in ring.
+ */
+#define RXCSR1 0x0084
+#define RXCSR1_RXD_SIZE FIELD32(0x000000ff)
+#define RXCSR1_NUM_RXD FIELD32(0x0000ff00)
+
+/*
+ * RXCSR2: RX Ring base address register.
+ */
+#define RXCSR2 0x0088
+#define RXCSR2_RX_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * RXCSR3: BBP ID register for Rx operation.
+ * BBP_ID#: BBP register # id.
+ * BBP_ID#_VALID: BBP register # id is valid or not.
+ */
+#define RXCSR3 0x0090
+#define RXCSR3_BBP_ID0 FIELD32(0x0000007f)
+#define RXCSR3_BBP_ID0_VALID FIELD32(0x00000080)
+#define RXCSR3_BBP_ID1 FIELD32(0x00007f00)
+#define RXCSR3_BBP_ID1_VALID FIELD32(0x00008000)
+#define RXCSR3_BBP_ID2 FIELD32(0x007f0000)
+#define RXCSR3_BBP_ID2_VALID FIELD32(0x00800000)
+#define RXCSR3_BBP_ID3 FIELD32(0x7f000000)
+#define RXCSR3_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * ARCSR1: Auto Responder PLCP config register 1.
+ * AR_BBP_DATA#: Auto responder BBP register # data.
+ * AR_BBP_ID#: Auto responder BBP register # Id.
+ */
+#define ARCSR1 0x009c
+#define ARCSR1_AR_BBP_DATA2 FIELD32(0x000000ff)
+#define ARCSR1_AR_BBP_ID2 FIELD32(0x0000ff00)
+#define ARCSR1_AR_BBP_DATA3 FIELD32(0x00ff0000)
+#define ARCSR1_AR_BBP_ID3 FIELD32(0xff000000)
+
+/*
+ * Miscellaneous Registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+
+ */
+
+/*
+ * PCICSR: PCI control register.
+ * BIG_ENDIAN: 1: big endian, 0: little endian.
+ * RX_TRESHOLD: Rx threshold in dw to start pci access
+ * 0: 16dw (default), 1: 8dw, 2: 4dw, 3: 32dw.
+ * TX_TRESHOLD: Tx threshold in dw to start pci access
+ * 0: 0dw (default), 1: 1dw, 2: 4dw, 3: forward.
+ * BURST_LENTH: Pci burst length 0: 4dw (default, 1: 8dw, 2: 16dw, 3:32dw.
+ * ENABLE_CLK: Enable clk_run, pci clock can't going down to non-operational.
+ * READ_MULTIPLE: Enable memory read multiple.
+ * WRITE_INVALID: Enable memory write & invalid.
+ */
+#define PCICSR 0x008c
+#define PCICSR_BIG_ENDIAN FIELD32(0x00000001)
+#define PCICSR_RX_TRESHOLD FIELD32(0x00000006)
+#define PCICSR_TX_TRESHOLD FIELD32(0x00000018)
+#define PCICSR_BURST_LENTH FIELD32(0x00000060)
+#define PCICSR_ENABLE_CLK FIELD32(0x00000080)
+#define PCICSR_READ_MULTIPLE FIELD32(0x00000100)
+#define PCICSR_WRITE_INVALID FIELD32(0x00000200)
+
+/*
+ * CNT0: FCS error count.
+ * FCS_ERROR: FCS error count, cleared when read.
+ */
+#define CNT0 0x00a0
+#define CNT0_FCS_ERROR FIELD32(0x0000ffff)
+
+/*
+ * Statistic Register.
+ * CNT1: PLCP error count.
+ * CNT2: Long error count.
+ */
+#define TIMECSR2 0x00a8
+#define CNT1 0x00ac
+#define CNT2 0x00b0
+#define TIMECSR3 0x00b4
+
+/*
+ * CNT3: CCA false alarm count.
+ */
+#define CNT3 0x00b8
+#define CNT3_FALSE_CCA FIELD32(0x0000ffff)
+
+/*
+ * Statistic Register.
+ * CNT4: Rx FIFO overflow count.
+ * CNT5: Tx FIFO underrun count.
+ */
+#define CNT4 0x00bc
+#define CNT5 0x00c0
+
+/*
+ * Baseband Control Register.
+ */
+
+/*
+ * PWRCSR0: Power mode configuration register.
+ */
+#define PWRCSR0 0x00c4
+
+/*
+ * Power state transition time registers.
+ */
+#define PSCSR0 0x00c8
+#define PSCSR1 0x00cc
+#define PSCSR2 0x00d0
+#define PSCSR3 0x00d4
+
+/*
+ * PWRCSR1: Manual power control / status register.
+ * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake.
+ * SET_STATE: Set state. Write 1 to trigger, self cleared.
+ * BBP_DESIRE_STATE: BBP desired state.
+ * RF_DESIRE_STATE: RF desired state.
+ * BBP_CURR_STATE: BBP current state.
+ * RF_CURR_STATE: RF current state.
+ * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared.
+ */
+#define PWRCSR1 0x00d8
+#define PWRCSR1_SET_STATE FIELD32(0x00000001)
+#define PWRCSR1_BBP_DESIRE_STATE FIELD32(0x00000006)
+#define PWRCSR1_RF_DESIRE_STATE FIELD32(0x00000018)
+#define PWRCSR1_BBP_CURR_STATE FIELD32(0x00000060)
+#define PWRCSR1_RF_CURR_STATE FIELD32(0x00000180)
+#define PWRCSR1_PUT_TO_SLEEP FIELD32(0x00000200)
+
+/*
+ * TIMECSR: Timer control register.
+ * US_COUNT: 1 us timer count in units of clock cycles.
+ * US_64_COUNT: 64 us timer count in units of 1 us timer.
+ * BEACON_EXPECT: Beacon expect window.
+ */
+#define TIMECSR 0x00dc
+#define TIMECSR_US_COUNT FIELD32(0x000000ff)
+#define TIMECSR_US_64_COUNT FIELD32(0x0000ff00)
+#define TIMECSR_BEACON_EXPECT FIELD32(0x00070000)
+
+/*
+ * MACCSR0: MAC configuration register 0.
+ */
+#define MACCSR0 0x00e0
+
+/*
+ * MACCSR1: MAC configuration register 1.
+ * KICK_RX: Kick one-shot rx in one-shot rx mode.
+ * ONESHOT_RXMODE: Enable one-shot rx mode for debugging.
+ * BBPRX_RESET_MODE: Ralink bbp rx reset mode.
+ * AUTO_TXBBP: Auto tx logic access bbp control register.
+ * AUTO_RXBBP: Auto rx logic access bbp control register.
+ * LOOPBACK: Loopback mode. 0: normal, 1: internal, 2: external, 3:rsvd.
+ * INTERSIL_IF: Intersil if calibration pin.
+ */
+#define MACCSR1 0x00e4
+#define MACCSR1_KICK_RX FIELD32(0x00000001)
+#define MACCSR1_ONESHOT_RXMODE FIELD32(0x00000002)
+#define MACCSR1_BBPRX_RESET_MODE FIELD32(0x00000004)
+#define MACCSR1_AUTO_TXBBP FIELD32(0x00000008)
+#define MACCSR1_AUTO_RXBBP FIELD32(0x00000010)
+#define MACCSR1_LOOPBACK FIELD32(0x00000060)
+#define MACCSR1_INTERSIL_IF FIELD32(0x00000080)
+
+/*
+ * RALINKCSR: Ralink Rx auto-reset BBCR.
+ * AR_BBP_DATA#: Auto reset BBP register # data.
+ * AR_BBP_ID#: Auto reset BBP register # id.
+ */
+#define RALINKCSR 0x00e8
+#define RALINKCSR_AR_BBP_DATA0 FIELD32(0x000000ff)
+#define RALINKCSR_AR_BBP_ID0 FIELD32(0x00007f00)
+#define RALINKCSR_AR_BBP_VALID0 FIELD32(0x00008000)
+#define RALINKCSR_AR_BBP_DATA1 FIELD32(0x00ff0000)
+#define RALINKCSR_AR_BBP_ID1 FIELD32(0x7f000000)
+#define RALINKCSR_AR_BBP_VALID1 FIELD32(0x80000000)
+
+/*
+ * BCNCSR: Beacon interval control register.
+ * CHANGE: Write one to change beacon interval.
+ * DELTATIME: The delta time value.
+ * NUM_BEACON: Number of beacon according to mode.
+ * MODE: Please refer to asic specs.
+ * PLUS: Plus or minus delta time value.
+ */
+#define BCNCSR 0x00ec
+#define BCNCSR_CHANGE FIELD32(0x00000001)
+#define BCNCSR_DELTATIME FIELD32(0x0000001e)
+#define BCNCSR_NUM_BEACON FIELD32(0x00001fe0)
+#define BCNCSR_MODE FIELD32(0x00006000)
+#define BCNCSR_PLUS FIELD32(0x00008000)
+
+/*
+ * BBP / RF / IF Control Register.
+ */
+
+/*
+ * BBPCSR: BBP serial control register.
+ * VALUE: Register value to program into BBP.
+ * REGNUM: Selected BBP register.
+ * BUSY: 1: asic is busy execute BBP programming.
+ * WRITE_CONTROL: 1: write BBP, 0: read BBP.
+ */
+#define BBPCSR 0x00f0
+#define BBPCSR_VALUE FIELD32(0x000000ff)
+#define BBPCSR_REGNUM FIELD32(0x00007f00)
+#define BBPCSR_BUSY FIELD32(0x00008000)
+#define BBPCSR_WRITE_CONTROL FIELD32(0x00010000)
+
+/*
+ * RFCSR: RF serial control register.
+ * VALUE: Register value + id to program into rf/if.
+ * NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22).
+ * IF_SELECT: Chip to program: 0: rf, 1: if.
+ * PLL_LD: Rf pll_ld status.
+ * BUSY: 1: asic is busy execute rf programming.
+ */
+#define RFCSR 0x00f4
+#define RFCSR_VALUE FIELD32(0x00ffffff)
+#define RFCSR_NUMBER_OF_BITS FIELD32(0x1f000000)
+#define RFCSR_IF_SELECT FIELD32(0x20000000)
+#define RFCSR_PLL_LD FIELD32(0x40000000)
+#define RFCSR_BUSY FIELD32(0x80000000)
+
+/*
+ * LEDCSR: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ * LINK: 0: linkoff, 1: linkup.
+ * ACTIVITY: 0: idle, 1: active.
+ * LINK_POLARITY: 0: active low, 1: active high.
+ * ACTIVITY_POLARITY: 0: active low, 1: active high.
+ * LED_DEFAULT: LED state for "enable" 0: ON, 1: OFF.
+ */
+#define LEDCSR 0x00f8
+#define LEDCSR_ON_PERIOD FIELD32(0x000000ff)
+#define LEDCSR_OFF_PERIOD FIELD32(0x0000ff00)
+#define LEDCSR_LINK FIELD32(0x00010000)
+#define LEDCSR_ACTIVITY FIELD32(0x00020000)
+#define LEDCSR_LINK_POLARITY FIELD32(0x00040000)
+#define LEDCSR_ACTIVITY_POLARITY FIELD32(0x00080000)
+#define LEDCSR_LED_DEFAULT FIELD32(0x00100000)
+
+/*
+ * AES control register.
+ */
+#define SECCSR3 0x00fc
+
+/*
+ * ASIC pointer information.
+ * RXPTR: Current RX ring address.
+ * TXPTR: Current Tx ring address.
+ * PRIPTR: Current Priority ring address.
+ * ATIMPTR: Current ATIM ring address.
+ */
+#define RXPTR 0x0100
+#define TXPTR 0x0104
+#define PRIPTR 0x0108
+#define ATIMPTR 0x010c
+
+/*
+ * TXACKCSR0: TX ACK timeout.
+ */
+#define TXACKCSR0 0x0110
+
+/*
+ * ACK timeout count registers.
+ * ACKCNT0: TX ACK timeout count.
+ * ACKCNT1: RX ACK timeout count.
+ */
+#define ACKCNT0 0x0114
+#define ACKCNT1 0x0118
+
+/*
+ * GPIO and others.
+ */
+
+/*
+ * GPIOCSR: GPIO control register.
+ */
+#define GPIOCSR 0x0120
+#define GPIOCSR_BIT0 FIELD32(0x00000001)
+#define GPIOCSR_BIT1 FIELD32(0x00000002)
+#define GPIOCSR_BIT2 FIELD32(0x00000004)
+#define GPIOCSR_BIT3 FIELD32(0x00000008)
+#define GPIOCSR_BIT4 FIELD32(0x00000010)
+#define GPIOCSR_BIT5 FIELD32(0x00000020)
+#define GPIOCSR_BIT6 FIELD32(0x00000040)
+#define GPIOCSR_BIT7 FIELD32(0x00000080)
+#define GPIOCSR_DIR0 FIELD32(0x00000100)
+#define GPIOCSR_DIR1 FIELD32(0x00000200)
+#define GPIOCSR_DIR2 FIELD32(0x00000400)
+#define GPIOCSR_DIR3 FIELD32(0x00000800)
+#define GPIOCSR_DIR4 FIELD32(0x00001000)
+#define GPIOCSR_DIR5 FIELD32(0x00002000)
+#define GPIOCSR_DIR6 FIELD32(0x00004000)
+#define GPIOCSR_DIR7 FIELD32(0x00008000)
+
+/*
+ * FIFO pointer registers.
+ * FIFOCSR0: TX FIFO pointer.
+ * FIFOCSR1: RX FIFO pointer.
+ */
+#define FIFOCSR0 0x0128
+#define FIFOCSR1 0x012c
+
+/*
+ * BCNCSR1: Tx BEACON offset time control register.
+ * PRELOAD: Beacon timer offset in units of usec.
+ * BEACON_CWMIN: 2^CwMin.
+ */
+#define BCNCSR1 0x0130
+#define BCNCSR1_PRELOAD FIELD32(0x0000ffff)
+#define BCNCSR1_BEACON_CWMIN FIELD32(0x000f0000)
+
+/*
+ * MACCSR2: TX_PE to RX_PE turn-around time control register
+ * DELAY: RX_PE low width, in units of pci clock cycle.
+ */
+#define MACCSR2 0x0134
+#define MACCSR2_DELAY FIELD32(0x000000ff)
+
+/*
+ * TESTCSR: TEST mode selection register.
+ */
+#define TESTCSR 0x0138
+
+/*
+ * ARCSR2: 1 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR2 0x013c
+#define ARCSR2_SIGNAL FIELD32(0x000000ff)
+#define ARCSR2_SERVICE FIELD32(0x0000ff00)
+#define ARCSR2_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARCSR3: 2 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR3 0x0140
+#define ARCSR3_SIGNAL FIELD32(0x000000ff)
+#define ARCSR3_SERVICE FIELD32(0x0000ff00)
+#define ARCSR3_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARCSR4: 5.5 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR4 0x0144
+#define ARCSR4_SIGNAL FIELD32(0x000000ff)
+#define ARCSR4_SERVICE FIELD32(0x0000ff00)
+#define ARCSR4_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARCSR5: 11 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR5 0x0148
+#define ARCSR5_SIGNAL FIELD32(0x000000ff)
+#define ARCSR5_SERVICE FIELD32(0x0000ff00)
+#define ARCSR5_LENGTH FIELD32(0xffff0000)
+
+/*
+ * ARTCSR0: CCK ACK/CTS payload consumed time for 1/2/5.5/11 mbps.
+ */
+#define ARTCSR0 0x014c
+#define ARTCSR0_ACK_CTS_11MBS FIELD32(0x000000ff)
+#define ARTCSR0_ACK_CTS_5_5MBS FIELD32(0x0000ff00)
+#define ARTCSR0_ACK_CTS_2MBS FIELD32(0x00ff0000)
+#define ARTCSR0_ACK_CTS_1MBS FIELD32(0xff000000)
+
+
+/*
+ * ARTCSR1: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps.
+ */
+#define ARTCSR1 0x0150
+#define ARTCSR1_ACK_CTS_6MBS FIELD32(0x000000ff)
+#define ARTCSR1_ACK_CTS_9MBS FIELD32(0x0000ff00)
+#define ARTCSR1_ACK_CTS_12MBS FIELD32(0x00ff0000)
+#define ARTCSR1_ACK_CTS_18MBS FIELD32(0xff000000)
+
+/*
+ * ARTCSR2: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps.
+ */
+#define ARTCSR2 0x0154
+#define ARTCSR2_ACK_CTS_24MBS FIELD32(0x000000ff)
+#define ARTCSR2_ACK_CTS_36MBS FIELD32(0x0000ff00)
+#define ARTCSR2_ACK_CTS_48MBS FIELD32(0x00ff0000)
+#define ARTCSR2_ACK_CTS_54MBS FIELD32(0xff000000)
+
+/*
+ * SECCSR1_RT2509: WEP control register.
+ * KICK_ENCRYPT: Kick encryption engine, self-clear.
+ * ONE_SHOT: 0: ring mode, 1: One shot only mode.
+ * DESC_ADDRESS: Descriptor physical address of frame.
+ */
+#define SECCSR1 0x0158
+#define SECCSR1_KICK_ENCRYPT FIELD32(0x00000001)
+#define SECCSR1_ONE_SHOT FIELD32(0x00000002)
+#define SECCSR1_DESC_ADDRESS FIELD32(0xfffffffc)
+
+/*
+ * BBPCSR1: BBP TX configuration.
+ */
+#define BBPCSR1 0x015c
+#define BBPCSR1_CCK FIELD32(0x00000003)
+#define BBPCSR1_CCK_FLIP FIELD32(0x00000004)
+#define BBPCSR1_OFDM FIELD32(0x00030000)
+#define BBPCSR1_OFDM_FLIP FIELD32(0x00040000)
+
+/*
+ * Dual band configuration registers.
+ * DBANDCSR0: Dual band configuration register 0.
+ * DBANDCSR1: Dual band configuration register 1.
+ */
+#define DBANDCSR0 0x0160
+#define DBANDCSR1 0x0164
+
+/*
+ * BBPPCSR: BBP Pin control register.
+ */
+#define BBPPCSR 0x0168
+
+/*
+ * MAC special debug mode selection registers.
+ * DBGSEL0: MAC special debug mode selection register 0.
+ * DBGSEL1: MAC special debug mode selection register 1.
+ */
+#define DBGSEL0 0x016c
+#define DBGSEL1 0x0170
+
+/*
+ * BISTCSR: BBP BIST register.
+ */
+#define BISTCSR 0x0174
+
+/*
+ * Multicast filter registers.
+ * MCAST0: Multicast filter register 0.
+ * MCAST1: Multicast filter register 1.
+ */
+#define MCAST0 0x0178
+#define MCAST1 0x017c
+
+/*
+ * UART registers.
+ * UARTCSR0: UART1 TX register.
+ * UARTCSR1: UART1 RX register.
+ * UARTCSR3: UART1 frame control register.
+ * UARTCSR4: UART1 buffer control register.
+ * UART2CSR0: UART2 TX register.
+ * UART2CSR1: UART2 RX register.
+ * UART2CSR3: UART2 frame control register.
+ * UART2CSR4: UART2 buffer control register.
+ */
+#define UARTCSR0 0x0180
+#define UARTCSR1 0x0184
+#define UARTCSR3 0x0188
+#define UARTCSR4 0x018c
+#define UART2CSR0 0x0190
+#define UART2CSR1 0x0194
+#define UART2CSR3 0x0198
+#define UART2CSR4 0x019c
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R2: TX antenna control
+ */
+#define BBP_R2_TX_ANTENNA FIELD8(0x03)
+#define BBP_R2_TX_IQ_FLIP FIELD8(0x04)
+
+/*
+ * R14: RX antenna control
+ */
+#define BBP_R14_RX_ANTENNA FIELD8(0x03)
+#define BBP_R14_RX_IQ_FLIP FIELD8(0x04)
+
+/*
+ * BBP_R70
+ */
+#define BBP_R70_JAPAN_FILTER FIELD8(0x08)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 1
+ */
+#define RF1_TUNER FIELD32(0x00020000)
+
+/*
+ * RF 3
+ */
+#define RF3_TUNER FIELD32(0x00000100)
+#define RF3_TXPOWER FIELD32(0x00003e00)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0 0x0002
+#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1 0x0003
+#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2 0x0004
+#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * LED_MODE: 0: default, 1: TX/RX activity,2: Single (ignore link), 3: rsvd.
+ * DYN_TXAGC: Dynamic TX AGC control.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ * RF_TYPE: Rf_type of this adapter.
+ */
+#define EEPROM_ANTENNA 0x10
+#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
+#define EEPROM_ANTENNA_LED_MODE FIELD16(0x01c0)
+#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
+#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800)
+
+/*
+ * EEPROM NIC config.
+ * CARDBUS_ACCEL: 0: enable, 1: disable.
+ * DYN_BBP_TUNE: 0: enable, 1: disable.
+ * CCK_TX_POWER: CCK TX power compensation.
+ */
+#define EEPROM_NIC 0x11
+#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0001)
+#define EEPROM_NIC_DYN_BBP_TUNE FIELD16(0x0002)
+#define EEPROM_NIC_CCK_TX_POWER FIELD16(0x000c)
+
+/*
+ * EEPROM geography.
+ * GEO: Default geography setting for device.
+ */
+#define EEPROM_GEOGRAPHY 0x12
+#define EEPROM_GEOGRAPHY_GEO FIELD16(0x0f00)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START 0x13
+#define EEPROM_BBP_SIZE 16
+#define EEPROM_BBP_VALUE FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER
+ */
+#define EEPROM_TXPOWER_START 0x23
+#define EEPROM_TXPOWER_SIZE 7
+#define EEPROM_TXPOWER_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_2 FIELD16(0xff00)
+
+/*
+ * RSSI <-> dBm offset calibration
+ */
+#define EEPROM_CALIBRATE_OFFSET 0x3e
+#define EEPROM_CALIBRATE_OFFSET_RSSI FIELD16(0x00ff)
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE ( 11 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE ( 11 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
+ */
+
+/*
+ * Word0
+ */
+#define TXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define TXD_W0_VALID FIELD32(0x00000002)
+#define TXD_W0_RESULT FIELD32(0x0000001c)
+#define TXD_W0_RETRY_COUNT FIELD32(0x000000e0)
+#define TXD_W0_MORE_FRAG FIELD32(0x00000100)
+#define TXD_W0_ACK FIELD32(0x00000200)
+#define TXD_W0_TIMESTAMP FIELD32(0x00000400)
+#define TXD_W0_OFDM FIELD32(0x00000800)
+#define TXD_W0_CIPHER_OWNER FIELD32(0x00001000)
+#define TXD_W0_IFS FIELD32(0x00006000)
+#define TXD_W0_RETRY_MODE FIELD32(0x00008000)
+#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define TXD_W0_CIPHER_ALG FIELD32(0xe0000000)
+
+/*
+ * Word1
+ */
+#define TXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff)
+
+/*
+ * Word2
+ */
+#define TXD_W2_IV_OFFSET FIELD32(0x0000003f)
+#define TXD_W2_AIFS FIELD32(0x000000c0)
+#define TXD_W2_CWMIN FIELD32(0x00000f00)
+#define TXD_W2_CWMAX FIELD32(0x0000f000)
+
+/*
+ * Word3: PLCP information
+ */
+#define TXD_W3_PLCP_SIGNAL FIELD32(0x000000ff)
+#define TXD_W3_PLCP_SERVICE FIELD32(0x0000ff00)
+#define TXD_W3_PLCP_LENGTH_LOW FIELD32(0x00ff0000)
+#define TXD_W3_PLCP_LENGTH_HIGH FIELD32(0xff000000)
+
+/*
+ * Word4
+ */
+#define TXD_W4_IV FIELD32(0xffffffff)
+
+/*
+ * Word5
+ */
+#define TXD_W5_EIV FIELD32(0xffffffff)
+
+/*
+ * Word6-9: Key
+ */
+#define TXD_W6_KEY FIELD32(0xffffffff)
+#define TXD_W7_KEY FIELD32(0xffffffff)
+#define TXD_W8_KEY FIELD32(0xffffffff)
+#define TXD_W9_KEY FIELD32(0xffffffff)
+
+/*
+ * Word10
+ */
+#define TXD_W10_RTS FIELD32(0x00000001)
+#define TXD_W10_TX_RATE FIELD32(0x000000fe)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ */
+#define RXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002)
+#define RXD_W0_MULTICAST FIELD32(0x00000004)
+#define RXD_W0_BROADCAST FIELD32(0x00000008)
+#define RXD_W0_MY_BSS FIELD32(0x00000010)
+#define RXD_W0_CRC_ERROR FIELD32(0x00000020)
+#define RXD_W0_OFDM FIELD32(0x00000040)
+#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080)
+#define RXD_W0_CIPHER_OWNER FIELD32(0x00000100)
+#define RXD_W0_ICV_ERROR FIELD32(0x00000200)
+#define RXD_W0_IV_OFFSET FIELD32(0x0000fc00)
+#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define RXD_W0_CIPHER_ALG FIELD32(0xe0000000)
+
+/*
+ * Word1
+ */
+#define RXD_W1_BUFFER_ADDRESS FIELD32(0xffffffff)
+
+/*
+ * Word2
+ */
+#define RXD_W2_SIGNAL FIELD32(0x000000ff)
+#define RXD_W2_RSSI FIELD32(0x0000ff00)
+#define RXD_W2_TA FIELD32(0xffff0000)
+
+/*
+ * Word3
+ */
+#define RXD_W3_TA FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define RXD_W4_IV FIELD32(0xffffffff)
+
+/*
+ * Word5
+ */
+#define RXD_W5_EIV FIELD32(0xffffffff)
+
+/*
+ * Word6-9: Key
+ */
+#define RXD_W6_KEY FIELD32(0xffffffff)
+#define RXD_W7_KEY FIELD32(0xffffffff)
+#define RXD_W8_KEY FIELD32(0xffffffff)
+#define RXD_W9_KEY FIELD32(0xffffffff)
+
+/*
+ * Word10
+ */
+#define RXD_W10_DROP FIELD32(0x00000001)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ */
+#define MIN_TXPOWER 0
+#define MAX_TXPOWER 31
+#define DEFAULT_TXPOWER 24
+
+#define TXPOWER_FROM_DEV(__txpower) \
+({ \
+ ((__txpower) > MAX_TXPOWER) ? \
+ DEFAULT_TXPOWER : (__txpower); \
+})
+
+#define TXPOWER_TO_DEV(__txpower) \
+({ \
+ ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
+ (__txpower)); \
+})
+
+#endif /* RT2500PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
new file mode 100644
index 00000000000..277a020b35e
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -0,0 +1,1832 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2500usb
+ Abstract: rt2500usb device specific routines.
+ Supported chipsets: RT2570.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2500usb"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "rt2x00.h"
+#include "rt2x00usb.h"
+#include "rt2500usb.h"
+
+/*
+ * Register access.
+ * All access to the CSR registers will go through the methods
+ * rt2500usb_register_read and rt2500usb_register_write.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers BBPCSR and RFCSR to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static inline void rt2500usb_register_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u16 *value)
+{
+ __le16 reg;
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ &reg, sizeof(u16), REGISTER_TIMEOUT);
+ *value = le16_to_cpu(reg);
+}
+
+static inline void rt2500usb_register_multiread(const struct rt2x00_dev
+ *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u16 length)
+{
+ int timeout = REGISTER_TIMEOUT * (length / sizeof(u16));
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ value, length, timeout);
+}
+
+static inline void rt2500usb_register_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ u16 value)
+{
+ __le16 reg = cpu_to_le16(value);
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ &reg, sizeof(u16), REGISTER_TIMEOUT);
+}
+
+static inline void rt2500usb_register_multiwrite(const struct rt2x00_dev
+ *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u16 length)
+{
+ int timeout = REGISTER_TIMEOUT * (length / sizeof(u16));
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ value, length, timeout);
+}
+
+static u16 rt2500usb_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+ u16 reg;
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2500usb_register_read(rt2x00dev, PHY_CSR8, &reg);
+ if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+ break;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ return reg;
+}
+
+static void rt2500usb_bbp_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u16 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2500usb_bbp_check(rt2x00dev);
+ if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
+ return;
+ }
+
+ /*
+ * Write the data into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR7_DATA, value);
+ rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+ rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
+
+ rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+}
+
+static void rt2500usb_bbp_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u16 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2500usb_bbp_check(rt2x00dev);
+ if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
+ return;
+ }
+
+ /*
+ * Write the request into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+ rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
+
+ rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt2500usb_bbp_check(rt2x00dev);
+ if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
+ *value = 0xff;
+ return;
+ }
+
+ rt2500usb_register_read(rt2x00dev, PHY_CSR7, &reg);
+ *value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
+}
+
+static void rt2500usb_rf_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u32 value)
+{
+ u16 reg;
+ unsigned int i;
+
+ if (!word)
+ return;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2500usb_register_read(rt2x00dev, PHY_CSR10, &reg);
+ if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY))
+ goto rf_write;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n");
+ return;
+
+rf_write:
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
+ rt2500usb_register_write(rt2x00dev, PHY_CSR9, reg);
+
+ reg = 0;
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_NUMBER_OF_BITS, 20);
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
+ rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
+
+ rt2500usb_register_write(rt2x00dev, PHY_CSR10, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u16)) )
+
+static void rt2500usb_read_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 *data)
+{
+ rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data);
+}
+
+static void rt2500usb_write_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 data)
+{
+ rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt2500usb_rt2x00debug = {
+ .owner = THIS_MODULE,
+ .csr = {
+ .read = rt2500usb_read_csr,
+ .write = rt2500usb_write_csr,
+ .word_size = sizeof(u16),
+ .word_count = CSR_REG_SIZE / sizeof(u16),
+ },
+ .eeprom = {
+ .read = rt2x00_eeprom_read,
+ .write = rt2x00_eeprom_write,
+ .word_size = sizeof(u16),
+ .word_count = EEPROM_SIZE / sizeof(u16),
+ },
+ .bbp = {
+ .read = rt2500usb_bbp_read,
+ .write = rt2500usb_bbp_write,
+ .word_size = sizeof(u8),
+ .word_count = BBP_SIZE / sizeof(u8),
+ },
+ .rf = {
+ .read = rt2x00_rf_read,
+ .write = rt2500usb_rf_write,
+ .word_size = sizeof(u32),
+ .word_count = RF_SIZE / sizeof(u32),
+ },
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
+ * Configuration handlers.
+ */
+static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev,
+ __le32 *mac)
+{
+ rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, &mac,
+ (3 * sizeof(__le16)));
+}
+
+static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev,
+ __le32 *bssid)
+{
+ rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, bssid,
+ (3 * sizeof(__le16)));
+}
+
+static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+ const int tsf_sync)
+{
+ u16 reg;
+
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+
+ /*
+ * Enable beacon config
+ */
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR20, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR20_OFFSET,
+ (PREAMBLE + get_duration(IEEE80211_HEADER, 20)) >> 6);
+ if (type == IEEE80211_IF_TYPE_STA)
+ rt2x00_set_field16(&reg, TXRX_CSR20_BCN_EXPECT_WINDOW, 0);
+ else
+ rt2x00_set_field16(&reg, TXRX_CSR20_BCN_EXPECT_WINDOW, 2);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR20, reg);
+
+ /*
+ * Enable synchronisation.
+ */
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR18_OFFSET, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR19_TSF_SYNC, tsf_sync);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+}
+
+static void rt2500usb_config_preamble(struct rt2x00_dev *rt2x00dev,
+ const int short_preamble,
+ const int ack_timeout,
+ const int ack_consume_time)
+{
+ u16 reg;
+
+ /*
+ * When in atomic context, reschedule and let rt2x00lib
+ * call this function again.
+ */
+ if (in_atomic()) {
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work);
+ return;
+ }
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR1_ACK_TIMEOUT, ack_timeout);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR10, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR10_AUTORESPOND_PREAMBLE,
+ !!short_preamble);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg);
+}
+
+static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev,
+ const int phymode,
+ const int basic_rate_mask)
+{
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask);
+
+ if (phymode == HWMODE_B) {
+ rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x000b);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x0040);
+ } else {
+ rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x0005);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x016c);
+ }
+}
+
+static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf, const int txpower)
+{
+ /*
+ * Set TXpower.
+ */
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+
+ /*
+ * For RT2525E we should first set the channel to half band higher.
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+ static const u32 vals[] = {
+ 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
+ 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
+ 0x000008ba, 0x000008be, 0x000008b7, 0x00000902,
+ 0x00000902, 0x00000906
+ };
+
+ rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
+ if (rf->rf4)
+ rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+ }
+
+ rt2500usb_rf_write(rt2x00dev, 1, rf->rf1);
+ rt2500usb_rf_write(rt2x00dev, 2, rf->rf2);
+ rt2500usb_rf_write(rt2x00dev, 3, rf->rf3);
+ if (rf->rf4)
+ rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+}
+
+static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+ const int txpower)
+{
+ u32 rf3;
+
+ rt2x00_rf_read(rt2x00dev, 3, &rf3);
+ rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+ rt2500usb_rf_write(rt2x00dev, 3, rf3);
+}
+
+static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx, const int antenna_rx)
+{
+ u8 r2;
+ u8 r14;
+ u16 csr5;
+ u16 csr6;
+
+ rt2500usb_bbp_read(rt2x00dev, 2, &r2);
+ rt2500usb_bbp_read(rt2x00dev, 14, &r14);
+ rt2500usb_register_read(rt2x00dev, PHY_CSR5, &csr5);
+ rt2500usb_register_read(rt2x00dev, PHY_CSR6, &csr6);
+
+ /*
+ * Configure the TX antenna.
+ */
+ switch (antenna_tx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 1);
+ rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 1);
+ rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 1);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
+ rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 0);
+ rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 0);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
+ rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 2);
+ rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 2);
+ break;
+ }
+
+ /*
+ * Configure the RX antenna.
+ */
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 1);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
+ break;
+ }
+
+ /*
+ * RT2525E and RT5222 need to flip TX I/Q
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
+ rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
+ rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 1);
+ rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 1);
+
+ /*
+ * RT2525E does not need RX I/Q Flip.
+ */
+ if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+ rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
+ } else {
+ rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 0);
+ rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 0);
+ }
+
+ rt2500usb_bbp_write(rt2x00dev, 2, r2);
+ rt2500usb_bbp_write(rt2x00dev, 14, r14);
+ rt2500usb_register_write(rt2x00dev, PHY_CSR5, csr5);
+ rt2500usb_register_write(rt2x00dev, PHY_CSR6, csr6);
+}
+
+static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u16 reg;
+
+ rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR18_INTERVAL,
+ libconf->conf->beacon_int * 4);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
+}
+
+static void rt2500usb_config(struct rt2x00_dev *rt2x00dev,
+ const unsigned int flags,
+ struct rt2x00lib_conf *libconf)
+{
+ if (flags & CONFIG_UPDATE_PHYMODE)
+ rt2500usb_config_phymode(rt2x00dev, libconf->phymode,
+ libconf->basic_rates);
+ if (flags & CONFIG_UPDATE_CHANNEL)
+ rt2500usb_config_channel(rt2x00dev, &libconf->rf,
+ libconf->conf->power_level);
+ if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+ rt2500usb_config_txpower(rt2x00dev,
+ libconf->conf->power_level);
+ if (flags & CONFIG_UPDATE_ANTENNA)
+ rt2500usb_config_antenna(rt2x00dev,
+ libconf->conf->antenna_sel_tx,
+ libconf->conf->antenna_sel_rx);
+ if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ rt2500usb_config_duration(rt2x00dev, libconf);
+}
+
+/*
+ * LED functions.
+ */
+static void rt2500usb_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u16 reg;
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR21, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR21_ON_PERIOD, 70);
+ rt2x00_set_field16(&reg, MAC_CSR21_OFF_PERIOD, 30);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg);
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR20, &reg);
+
+ if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
+ rt2x00_set_field16(&reg, MAC_CSR20_LINK, 1);
+ rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 0);
+ } else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
+ rt2x00_set_field16(&reg, MAC_CSR20_LINK, 0);
+ rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 1);
+ } else {
+ rt2x00_set_field16(&reg, MAC_CSR20_LINK, 1);
+ rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 1);
+ }
+
+ rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg);
+}
+
+static void rt2500usb_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u16 reg;
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR20, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR20_LINK, 0);
+ rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 0);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg);
+}
+
+/*
+ * Link tuning
+ */
+static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+ u16 reg;
+
+ /*
+ * Update FCS error count from register.
+ */
+ rt2500usb_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00dev->link.rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR);
+
+ /*
+ * Update False CCA count from register.
+ */
+ rt2500usb_register_read(rt2x00dev, STA_CSR3, &reg);
+ rt2x00dev->link.false_cca =
+ rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR);
+}
+
+static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ u16 eeprom;
+ u16 value;
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &eeprom);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R24_LOW);
+ rt2500usb_bbp_write(rt2x00dev, 24, value);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &eeprom);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R25_LOW);
+ rt2500usb_bbp_write(rt2x00dev, 25, value);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &eeprom);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R61_LOW);
+ rt2500usb_bbp_write(rt2x00dev, 61, value);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &eeprom);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_VGCUPPER);
+ rt2500usb_bbp_write(rt2x00dev, 17, value);
+
+ rt2x00dev->link.vgc_level = value;
+}
+
+static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
+ u16 bbp_thresh;
+ u16 vgc_bound;
+ u16 sens;
+ u16 r24;
+ u16 r25;
+ u16 r61;
+ u16 r17_sens;
+ u8 r17;
+ u8 up_bound;
+ u8 low_bound;
+
+ /*
+ * Determine the BBP tuning threshold and correctly
+ * set BBP 24, 25 and 61.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &bbp_thresh);
+ bbp_thresh = rt2x00_get_field16(bbp_thresh, EEPROM_BBPTUNE_THRESHOLD);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &r24);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &r25);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &r61);
+
+ if ((rssi + bbp_thresh) > 0) {
+ r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_HIGH);
+ r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_HIGH);
+ r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_HIGH);
+ } else {
+ r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_LOW);
+ r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_LOW);
+ r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_LOW);
+ }
+
+ rt2500usb_bbp_write(rt2x00dev, 24, r24);
+ rt2500usb_bbp_write(rt2x00dev, 25, r25);
+ rt2500usb_bbp_write(rt2x00dev, 61, r61);
+
+ /*
+ * Read current r17 value, as well as the sensitivity values
+ * for the r17 register.
+ */
+ rt2500usb_bbp_read(rt2x00dev, 17, &r17);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &r17_sens);
+
+ /*
+ * A too low RSSI will cause too much false CCA which will
+ * then corrupt the R17 tuning. To remidy this the tuning should
+ * be stopped (While making sure the R17 value will not exceed limits)
+ */
+ if (rssi >= -40) {
+ if (r17 != 0x60)
+ rt2500usb_bbp_write(rt2x00dev, 17, 0x60);
+ return;
+ }
+
+ /*
+ * Special big-R17 for short distance
+ */
+ if (rssi >= -58) {
+ sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_LOW);
+ if (r17 != sens)
+ rt2500usb_bbp_write(rt2x00dev, 17, sens);
+ return;
+ }
+
+ /*
+ * Special mid-R17 for middle distance
+ */
+ if (rssi >= -74) {
+ sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_HIGH);
+ if (r17 != sens)
+ rt2500usb_bbp_write(rt2x00dev, 17, sens);
+ return;
+ }
+
+ /*
+ * Leave short or middle distance condition, restore r17
+ * to the dynamic tuning range.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &vgc_bound);
+ vgc_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCUPPER);
+
+ low_bound = 0x32;
+ if (rssi >= -77)
+ up_bound = vgc_bound;
+ else
+ up_bound = vgc_bound - (-77 - rssi);
+
+ if (up_bound < low_bound)
+ up_bound = low_bound;
+
+ if (r17 > up_bound) {
+ rt2500usb_bbp_write(rt2x00dev, 17, up_bound);
+ rt2x00dev->link.vgc_level = up_bound;
+ } else if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) {
+ rt2500usb_bbp_write(rt2x00dev, 17, ++r17);
+ rt2x00dev->link.vgc_level = r17;
+ } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
+ rt2500usb_bbp_write(rt2x00dev, 17, --r17);
+ rt2x00dev->link.vgc_level = r17;
+ }
+}
+
+/*
+ * Initialization functions.
+ */
+static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u16 reg;
+
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0x0001,
+ USB_MODE_TEST, REGISTER_TIMEOUT);
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_SINGLE_WRITE, 0x0308,
+ 0x00f0, REGISTER_TIMEOUT);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+
+ rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x1111);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x1e11);
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR1_SOFT_RESET, 1);
+ rt2x00_set_field16(&reg, MAC_CSR1_BBP_RESET, 1);
+ rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 0);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR1_SOFT_RESET, 0);
+ rt2x00_set_field16(&reg, MAC_CSR1_BBP_RESET, 0);
+ rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 0);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR5, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID0, 13);
+ rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID0_VALID, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID1, 12);
+ rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID1_VALID, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR5, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR6, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR6_BBP_ID0, 10);
+ rt2x00_set_field16(&reg, TXRX_CSR6_BBP_ID0_VALID, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR6_BBP_ID1, 11);
+ rt2x00_set_field16(&reg, TXRX_CSR6_BBP_ID1_VALID, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR6, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR7_BBP_ID0, 7);
+ rt2x00_set_field16(&reg, TXRX_CSR7_BBP_ID0_VALID, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR7_BBP_ID1, 6);
+ rt2x00_set_field16(&reg, TXRX_CSR7_BBP_ID1_VALID, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR7, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID0, 5);
+ rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID0_VALID, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID1, 0);
+ rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID1_VALID, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR21, 0xe78f);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR9, 0xff1d);
+
+ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+ return -EBUSY;
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR1_SOFT_RESET, 0);
+ rt2x00_set_field16(&reg, MAC_CSR1_BBP_RESET, 0);
+ rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 1);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) {
+ rt2500usb_register_read(rt2x00dev, PHY_CSR2, &reg);
+ reg &= ~0x0002;
+ } else {
+ reg = 0x3002;
+ }
+ rt2500usb_register_write(rt2x00dev, PHY_CSR2, reg);
+
+ rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x0002);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR22, 0x0053);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR15, 0x01ee);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR16, 0x0000);
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR8, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR8_MAX_FRAME_UNIT,
+ rt2x00dev->rx->data_size);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR8, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, 0xff);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt2500usb_register_read(rt2x00dev, MAC_CSR18, &reg);
+ rt2x00_set_field16(&reg, MAC_CSR18_DELAY_AFTER_BEACON, 90);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg);
+
+ rt2500usb_register_read(rt2x00dev, PHY_CSR4, &reg);
+ rt2x00_set_field16(&reg, PHY_CSR4_LOW_RF_LE, 1);
+ rt2500usb_register_write(rt2x00dev, PHY_CSR4, reg);
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR1_AUTO_SEQUENCE, 1);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg);
+
+ return 0;
+}
+
+static int rt2500usb_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u16 eeprom;
+ u8 value;
+ u8 reg_id;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2500usb_bbp_read(rt2x00dev, 0, &value);
+ if ((value != 0xff) && (value != 0x00))
+ goto continue_csr_init;
+ NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ return -EACCES;
+
+continue_csr_init:
+ rt2500usb_bbp_write(rt2x00dev, 3, 0x02);
+ rt2500usb_bbp_write(rt2x00dev, 4, 0x19);
+ rt2500usb_bbp_write(rt2x00dev, 14, 0x1c);
+ rt2500usb_bbp_write(rt2x00dev, 15, 0x30);
+ rt2500usb_bbp_write(rt2x00dev, 16, 0xac);
+ rt2500usb_bbp_write(rt2x00dev, 18, 0x18);
+ rt2500usb_bbp_write(rt2x00dev, 19, 0xff);
+ rt2500usb_bbp_write(rt2x00dev, 20, 0x1e);
+ rt2500usb_bbp_write(rt2x00dev, 21, 0x08);
+ rt2500usb_bbp_write(rt2x00dev, 22, 0x08);
+ rt2500usb_bbp_write(rt2x00dev, 23, 0x08);
+ rt2500usb_bbp_write(rt2x00dev, 24, 0x80);
+ rt2500usb_bbp_write(rt2x00dev, 25, 0x50);
+ rt2500usb_bbp_write(rt2x00dev, 26, 0x08);
+ rt2500usb_bbp_write(rt2x00dev, 27, 0x23);
+ rt2500usb_bbp_write(rt2x00dev, 30, 0x10);
+ rt2500usb_bbp_write(rt2x00dev, 31, 0x2b);
+ rt2500usb_bbp_write(rt2x00dev, 32, 0xb9);
+ rt2500usb_bbp_write(rt2x00dev, 34, 0x12);
+ rt2500usb_bbp_write(rt2x00dev, 35, 0x50);
+ rt2500usb_bbp_write(rt2x00dev, 39, 0xc4);
+ rt2500usb_bbp_write(rt2x00dev, 40, 0x02);
+ rt2500usb_bbp_write(rt2x00dev, 41, 0x60);
+ rt2500usb_bbp_write(rt2x00dev, 53, 0x10);
+ rt2500usb_bbp_write(rt2x00dev, 54, 0x18);
+ rt2500usb_bbp_write(rt2x00dev, 56, 0x08);
+ rt2500usb_bbp_write(rt2x00dev, 57, 0x10);
+ rt2500usb_bbp_write(rt2x00dev, 58, 0x08);
+ rt2500usb_bbp_write(rt2x00dev, 61, 0x60);
+ rt2500usb_bbp_write(rt2x00dev, 62, 0x10);
+ rt2500usb_bbp_write(rt2x00dev, 75, 0xff);
+
+ DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+ for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+ if (eeprom != 0xffff && eeprom != 0x0000) {
+ reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+ DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+ reg_id, value);
+ rt2500usb_bbp_write(rt2x00dev, reg_id, value);
+ }
+ }
+ DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+ return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt2500usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u16 reg;
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX,
+ state == STATE_RADIO_RX_OFF);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+}
+
+static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
+ * Initialize all registers.
+ */
+ if (rt2500usb_init_registers(rt2x00dev) ||
+ rt2500usb_init_bbp(rt2x00dev)) {
+ ERROR(rt2x00dev, "Register initialization failed.\n");
+ return -EIO;
+ }
+
+ rt2x00usb_enable_radio(rt2x00dev);
+
+ /*
+ * Enable LED
+ */
+ rt2500usb_enable_led(rt2x00dev);
+
+ return 0;
+}
+
+static void rt2500usb_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
+ * Disable LED
+ */
+ rt2500usb_disable_led(rt2x00dev);
+
+ rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x2121);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x2121);
+
+ /*
+ * Disable synchronisation.
+ */
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+
+ rt2x00usb_disable_radio(rt2x00dev);
+}
+
+static int rt2500usb_set_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u16 reg;
+ u16 reg2;
+ unsigned int i;
+ char put_to_sleep;
+ char bbp_state;
+ char rf_state;
+
+ put_to_sleep = (state != STATE_AWAKE);
+
+ reg = 0;
+ rt2x00_set_field16(&reg, MAC_CSR17_BBP_DESIRE_STATE, state);
+ rt2x00_set_field16(&reg, MAC_CSR17_RF_DESIRE_STATE, state);
+ rt2x00_set_field16(&reg, MAC_CSR17_PUT_TO_SLEEP, put_to_sleep);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg);
+ rt2x00_set_field16(&reg, MAC_CSR17_SET_STATE, 1);
+ rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg);
+
+ /*
+ * Device is not guaranteed to be in the requested state yet.
+ * We must wait until the register indicates that the
+ * device has entered the correct state.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2500usb_register_read(rt2x00dev, MAC_CSR17, &reg2);
+ bbp_state = rt2x00_get_field16(reg2, MAC_CSR17_BBP_CURR_STATE);
+ rf_state = rt2x00_get_field16(reg2, MAC_CSR17_RF_CURR_STATE);
+ if (bbp_state == state && rf_state == state)
+ return 0;
+ rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg);
+ msleep(30);
+ }
+
+ NOTICE(rt2x00dev, "Device failed to enter state %d, "
+ "current device state: bbp %d and rf %d.\n",
+ state, bbp_state, rf_state);
+
+ return -EBUSY;
+}
+
+static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int retval = 0;
+
+ switch (state) {
+ case STATE_RADIO_ON:
+ retval = rt2500usb_enable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_OFF:
+ rt2500usb_disable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_OFF:
+ rt2500usb_toggle_rx(rt2x00dev, state);
+ break;
+ case STATE_DEEP_SLEEP:
+ case STATE_SLEEP:
+ case STATE_STANDBY:
+ case STATE_AWAKE:
+ retval = rt2500usb_set_state(rt2x00dev, state);
+ break;
+ default:
+ retval = -ENOTSUPP;
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct txdata_entry_desc *desc,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control)
+{
+ u32 word;
+
+ /*
+ * Start writing the descriptor words.
+ */
+ rt2x00_desc_read(txd, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&word, TXD_W1_AIFS, desc->aifs);
+ rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
+ rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, control->retry_limit);
+ rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+ test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_ACK,
+ !(control->flags & IEEE80211_TXCTL_NO_ACK));
+ rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_OFDM,
+ test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
+ !!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT));
+ rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+ rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
+ rt2x00_desc_write(txd, 0, word);
+}
+
+static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
+ int maxpacket, struct sk_buff *skb)
+{
+ int length;
+
+ /*
+ * The length _must_ be a multiple of 2,
+ * but it must _not_ be a multiple of the USB packet size.
+ */
+ length = roundup(skb->len, 2);
+ length += (2 * !(length % maxpacket));
+
+ return length;
+}
+
+/*
+ * TX data initialization
+ */
+static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ unsigned int queue)
+{
+ u16 reg;
+
+ if (queue != IEEE80211_TX_QUEUE_BEACON)
+ return;
+
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+ if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) {
+ rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 1);
+ /*
+ * Beacon generation will fail initially.
+ * To prevent this we need to register the TXRX_CSR19
+ * register several times.
+ */
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+ }
+}
+
+/*
+ * RX control handlers
+ */
+static void rt2500usb_fill_rxdone(struct data_entry *entry,
+ struct rxdata_entry_desc *desc)
+{
+ struct urb *urb = entry->priv;
+ struct data_desc *rxd = (struct data_desc *)(entry->skb->data +
+ (urb->actual_length -
+ entry->ring->desc_size));
+ u32 word0;
+ u32 word1;
+
+ rt2x00_desc_read(rxd, 0, &word0);
+ rt2x00_desc_read(rxd, 1, &word1);
+
+ desc->flags = 0;
+ if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+ desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+ if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+ desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+ desc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
+ entry->ring->rt2x00dev->rssi_offset;
+ desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+
+ return;
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt2500usb_beacondone(struct urb *urb)
+{
+ struct data_entry *entry = (struct data_entry *)urb->context;
+ struct data_ring *ring = entry->ring;
+
+ if (!test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags))
+ return;
+
+ /*
+ * Check if this was the guardian beacon,
+ * if that was the case we need to send the real beacon now.
+ * Otherwise we should free the sk_buffer, the device
+ * should be doing the rest of the work now.
+ */
+ if (ring->index == 1) {
+ rt2x00_ring_index_done_inc(ring);
+ entry = rt2x00_get_data_entry(ring);
+ usb_submit_urb(entry->priv, GFP_ATOMIC);
+ rt2x00_ring_index_inc(ring);
+ } else if (ring->index_done == 1) {
+ entry = rt2x00_get_data_entry_done(ring);
+ if (entry->skb) {
+ dev_kfree_skb(entry->skb);
+ entry->skb = NULL;
+ }
+ rt2x00_ring_index_done_inc(ring);
+ }
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u16 word;
+ u8 *mac;
+
+ rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE);
+
+ /*
+ * Start validation of the data that has been read.
+ */
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ DECLARE_MAC_BUF(macbuf);
+
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CCK_TX_POWER, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+ EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI,
+ DEFAULT_RSSI_OFFSET);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word);
+ EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_THRESHOLD, 45);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE, word);
+ EEPROM(rt2x00dev, "BBPtune: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCUPPER, 0x40);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
+ EEPROM(rt2x00dev, "BBPtune vgc: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_LOW, 0x48);
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R17, word);
+ EEPROM(rt2x00dev, "BBPtune r17: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_LOW, 0x40);
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_HIGH, 0x80);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R24, word);
+ EEPROM(rt2x00dev, "BBPtune r24: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_LOW, 0x40);
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_HIGH, 0x50);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R25, word);
+ EEPROM(rt2x00dev, "BBPtune r25: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_LOW, 0x60);
+ rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_HIGH, 0x6d);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R61, word);
+ EEPROM(rt2x00dev, "BBPtune r61: 0x%04x\n", word);
+ }
+
+ return 0;
+}
+
+static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u16 reg;
+ u16 value;
+ u16 eeprom;
+
+ /*
+ * Read EEPROM word for configuration.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Identify RF chipset.
+ */
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ rt2500usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
+
+ if (!rt2x00_check_rev(&rt2x00dev->chip, 0)) {
+ ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
+ return -ENODEV;
+ }
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2523) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2524) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2525) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Identify default antenna configuration.
+ */
+ rt2x00dev->hw->conf.antenna_sel_tx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+ rt2x00dev->hw->conf.antenna_sel_rx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+ /*
+ * Store led mode, for correct led behaviour.
+ */
+ rt2x00dev->led_mode =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+
+ /*
+ * Check if the BBP tuning should be disabled.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
+ __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+
+ /*
+ * Read the RSSI <-> dBm offset information.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom);
+ rt2x00dev->rssi_offset =
+ rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI);
+
+ return 0;
+}
+
+/*
+ * RF value list for RF2522
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2522[] = {
+ { 1, 0x00002050, 0x000c1fda, 0x00000101, 0 },
+ { 2, 0x00002050, 0x000c1fee, 0x00000101, 0 },
+ { 3, 0x00002050, 0x000c2002, 0x00000101, 0 },
+ { 4, 0x00002050, 0x000c2016, 0x00000101, 0 },
+ { 5, 0x00002050, 0x000c202a, 0x00000101, 0 },
+ { 6, 0x00002050, 0x000c203e, 0x00000101, 0 },
+ { 7, 0x00002050, 0x000c2052, 0x00000101, 0 },
+ { 8, 0x00002050, 0x000c2066, 0x00000101, 0 },
+ { 9, 0x00002050, 0x000c207a, 0x00000101, 0 },
+ { 10, 0x00002050, 0x000c208e, 0x00000101, 0 },
+ { 11, 0x00002050, 0x000c20a2, 0x00000101, 0 },
+ { 12, 0x00002050, 0x000c20b6, 0x00000101, 0 },
+ { 13, 0x00002050, 0x000c20ca, 0x00000101, 0 },
+ { 14, 0x00002050, 0x000c20fa, 0x00000101, 0 },
+};
+
+/*
+ * RF value list for RF2523
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2523[] = {
+ { 1, 0x00022010, 0x00000c9e, 0x000e0111, 0x00000a1b },
+ { 2, 0x00022010, 0x00000ca2, 0x000e0111, 0x00000a1b },
+ { 3, 0x00022010, 0x00000ca6, 0x000e0111, 0x00000a1b },
+ { 4, 0x00022010, 0x00000caa, 0x000e0111, 0x00000a1b },
+ { 5, 0x00022010, 0x00000cae, 0x000e0111, 0x00000a1b },
+ { 6, 0x00022010, 0x00000cb2, 0x000e0111, 0x00000a1b },
+ { 7, 0x00022010, 0x00000cb6, 0x000e0111, 0x00000a1b },
+ { 8, 0x00022010, 0x00000cba, 0x000e0111, 0x00000a1b },
+ { 9, 0x00022010, 0x00000cbe, 0x000e0111, 0x00000a1b },
+ { 10, 0x00022010, 0x00000d02, 0x000e0111, 0x00000a1b },
+ { 11, 0x00022010, 0x00000d06, 0x000e0111, 0x00000a1b },
+ { 12, 0x00022010, 0x00000d0a, 0x000e0111, 0x00000a1b },
+ { 13, 0x00022010, 0x00000d0e, 0x000e0111, 0x00000a1b },
+ { 14, 0x00022010, 0x00000d1a, 0x000e0111, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2524
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2524[] = {
+ { 1, 0x00032020, 0x00000c9e, 0x00000101, 0x00000a1b },
+ { 2, 0x00032020, 0x00000ca2, 0x00000101, 0x00000a1b },
+ { 3, 0x00032020, 0x00000ca6, 0x00000101, 0x00000a1b },
+ { 4, 0x00032020, 0x00000caa, 0x00000101, 0x00000a1b },
+ { 5, 0x00032020, 0x00000cae, 0x00000101, 0x00000a1b },
+ { 6, 0x00032020, 0x00000cb2, 0x00000101, 0x00000a1b },
+ { 7, 0x00032020, 0x00000cb6, 0x00000101, 0x00000a1b },
+ { 8, 0x00032020, 0x00000cba, 0x00000101, 0x00000a1b },
+ { 9, 0x00032020, 0x00000cbe, 0x00000101, 0x00000a1b },
+ { 10, 0x00032020, 0x00000d02, 0x00000101, 0x00000a1b },
+ { 11, 0x00032020, 0x00000d06, 0x00000101, 0x00000a1b },
+ { 12, 0x00032020, 0x00000d0a, 0x00000101, 0x00000a1b },
+ { 13, 0x00032020, 0x00000d0e, 0x00000101, 0x00000a1b },
+ { 14, 0x00032020, 0x00000d1a, 0x00000101, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2525
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2525[] = {
+ { 1, 0x00022020, 0x00080c9e, 0x00060111, 0x00000a1b },
+ { 2, 0x00022020, 0x00080ca2, 0x00060111, 0x00000a1b },
+ { 3, 0x00022020, 0x00080ca6, 0x00060111, 0x00000a1b },
+ { 4, 0x00022020, 0x00080caa, 0x00060111, 0x00000a1b },
+ { 5, 0x00022020, 0x00080cae, 0x00060111, 0x00000a1b },
+ { 6, 0x00022020, 0x00080cb2, 0x00060111, 0x00000a1b },
+ { 7, 0x00022020, 0x00080cb6, 0x00060111, 0x00000a1b },
+ { 8, 0x00022020, 0x00080cba, 0x00060111, 0x00000a1b },
+ { 9, 0x00022020, 0x00080cbe, 0x00060111, 0x00000a1b },
+ { 10, 0x00022020, 0x00080d02, 0x00060111, 0x00000a1b },
+ { 11, 0x00022020, 0x00080d06, 0x00060111, 0x00000a1b },
+ { 12, 0x00022020, 0x00080d0a, 0x00060111, 0x00000a1b },
+ { 13, 0x00022020, 0x00080d0e, 0x00060111, 0x00000a1b },
+ { 14, 0x00022020, 0x00080d1a, 0x00060111, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2525e
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2525e[] = {
+ { 1, 0x00022010, 0x0000089a, 0x00060111, 0x00000e1b },
+ { 2, 0x00022010, 0x0000089e, 0x00060111, 0x00000e07 },
+ { 3, 0x00022010, 0x0000089e, 0x00060111, 0x00000e1b },
+ { 4, 0x00022010, 0x000008a2, 0x00060111, 0x00000e07 },
+ { 5, 0x00022010, 0x000008a2, 0x00060111, 0x00000e1b },
+ { 6, 0x00022010, 0x000008a6, 0x00060111, 0x00000e07 },
+ { 7, 0x00022010, 0x000008a6, 0x00060111, 0x00000e1b },
+ { 8, 0x00022010, 0x000008aa, 0x00060111, 0x00000e07 },
+ { 9, 0x00022010, 0x000008aa, 0x00060111, 0x00000e1b },
+ { 10, 0x00022010, 0x000008ae, 0x00060111, 0x00000e07 },
+ { 11, 0x00022010, 0x000008ae, 0x00060111, 0x00000e1b },
+ { 12, 0x00022010, 0x000008b2, 0x00060111, 0x00000e07 },
+ { 13, 0x00022010, 0x000008b2, 0x00060111, 0x00000e1b },
+ { 14, 0x00022010, 0x000008b6, 0x00060111, 0x00000e23 },
+};
+
+/*
+ * RF value list for RF5222
+ * Supports: 2.4 GHz & 5.2 GHz
+ */
+static const struct rf_channel rf_vals_5222[] = {
+ { 1, 0x00022020, 0x00001136, 0x00000101, 0x00000a0b },
+ { 2, 0x00022020, 0x0000113a, 0x00000101, 0x00000a0b },
+ { 3, 0x00022020, 0x0000113e, 0x00000101, 0x00000a0b },
+ { 4, 0x00022020, 0x00001182, 0x00000101, 0x00000a0b },
+ { 5, 0x00022020, 0x00001186, 0x00000101, 0x00000a0b },
+ { 6, 0x00022020, 0x0000118a, 0x00000101, 0x00000a0b },
+ { 7, 0x00022020, 0x0000118e, 0x00000101, 0x00000a0b },
+ { 8, 0x00022020, 0x00001192, 0x00000101, 0x00000a0b },
+ { 9, 0x00022020, 0x00001196, 0x00000101, 0x00000a0b },
+ { 10, 0x00022020, 0x0000119a, 0x00000101, 0x00000a0b },
+ { 11, 0x00022020, 0x0000119e, 0x00000101, 0x00000a0b },
+ { 12, 0x00022020, 0x000011a2, 0x00000101, 0x00000a0b },
+ { 13, 0x00022020, 0x000011a6, 0x00000101, 0x00000a0b },
+ { 14, 0x00022020, 0x000011ae, 0x00000101, 0x00000a1b },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x00022010, 0x00018896, 0x00000101, 0x00000a1f },
+ { 40, 0x00022010, 0x0001889a, 0x00000101, 0x00000a1f },
+ { 44, 0x00022010, 0x0001889e, 0x00000101, 0x00000a1f },
+ { 48, 0x00022010, 0x000188a2, 0x00000101, 0x00000a1f },
+ { 52, 0x00022010, 0x000188a6, 0x00000101, 0x00000a1f },
+ { 66, 0x00022010, 0x000188aa, 0x00000101, 0x00000a1f },
+ { 60, 0x00022010, 0x000188ae, 0x00000101, 0x00000a1f },
+ { 64, 0x00022010, 0x000188b2, 0x00000101, 0x00000a1f },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x00022010, 0x00008802, 0x00000101, 0x00000a0f },
+ { 104, 0x00022010, 0x00008806, 0x00000101, 0x00000a0f },
+ { 108, 0x00022010, 0x0000880a, 0x00000101, 0x00000a0f },
+ { 112, 0x00022010, 0x0000880e, 0x00000101, 0x00000a0f },
+ { 116, 0x00022010, 0x00008812, 0x00000101, 0x00000a0f },
+ { 120, 0x00022010, 0x00008816, 0x00000101, 0x00000a0f },
+ { 124, 0x00022010, 0x0000881a, 0x00000101, 0x00000a0f },
+ { 128, 0x00022010, 0x0000881e, 0x00000101, 0x00000a0f },
+ { 132, 0x00022010, 0x00008822, 0x00000101, 0x00000a0f },
+ { 136, 0x00022010, 0x00008826, 0x00000101, 0x00000a0f },
+
+ /* 802.11 UNII */
+ { 140, 0x00022010, 0x0000882a, 0x00000101, 0x00000a0f },
+ { 149, 0x00022020, 0x000090a6, 0x00000101, 0x00000a07 },
+ { 153, 0x00022020, 0x000090ae, 0x00000101, 0x00000a07 },
+ { 157, 0x00022020, 0x000090b6, 0x00000101, 0x00000a07 },
+ { 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 },
+};
+
+static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ u8 *txpower;
+ unsigned int i;
+
+ /*
+ * Initialize all hw fields.
+ */
+ rt2x00dev->hw->flags =
+ IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+ IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
+ rt2x00dev->hw->max_signal = MAX_SIGNAL;
+ rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+ rt2x00dev->hw->queues = 2;
+
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev,
+ EEPROM_MAC_ADDR_0));
+
+ /*
+ * Convert tx_power array in eeprom.
+ */
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ /*
+ * Initialize hw_mode information.
+ */
+ spec->num_modes = 2;
+ spec->num_rates = 12;
+ spec->tx_power_a = NULL;
+ spec->tx_power_bg = txpower;
+ spec->tx_power_default = DEFAULT_TXPOWER;
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
+ spec->channels = rf_vals_bg_2522;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
+ spec->channels = rf_vals_bg_2523;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
+ spec->channels = rf_vals_bg_2524;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
+ spec->channels = rf_vals_bg_2525;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
+ spec->channels = rf_vals_bg_2525e;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_5222);
+ spec->channels = rf_vals_5222;
+ spec->num_modes = 3;
+ }
+}
+
+static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ /*
+ * Allocate eeprom data.
+ */
+ retval = rt2500usb_validate_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt2500usb_init_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * Initialize hw specifications.
+ */
+ rt2500usb_probe_hw_mode(rt2x00dev);
+
+ /*
+ * This device requires the beacon ring
+ */
+ __set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+ return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt2500usb_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+ u16 reg;
+
+ /*
+ * Mask off any flags we are going to ignore from
+ * the total_flags field.
+ */
+ *total_flags &=
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_PROMISC_IN_BSS;
+
+ /*
+ * Apply some rules to the filters:
+ * - Some filters imply different filters to be set.
+ * - Some things we can't filter out at all.
+ * - Some filters are set based on interface type.
+ */
+ if (mc_count)
+ *total_flags |= FIF_ALLMULTI;
+ if (*total_flags & FIF_OTHER_BSS ||
+ *total_flags & FIF_PROMISC_IN_BSS)
+ *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+ if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+ *total_flags |= FIF_PROMISC_IN_BSS;
+
+ /*
+ * Check if there is any work left for us.
+ */
+ if (intf->filter == *total_flags)
+ return;
+ intf->filter = *total_flags;
+
+ /*
+ * When in atomic context, reschedule and let rt2x00lib
+ * call this function again.
+ */
+ if (in_atomic()) {
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+ return;
+ }
+
+ /*
+ * Start configuration steps.
+ * Note that the version error will always be dropped
+ * and broadcast frames will always be accepted since
+ * there is no filter for it at this time.
+ */
+ rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CRC,
+ !(*total_flags & FIF_FCSFAIL));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_PHYSICAL,
+ !(*total_flags & FIF_PLCPFAIL));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CONTROL,
+ !(*total_flags & FIF_CONTROL));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_NOT_TO_ME,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_TODS,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_VERSION_ERROR, 1);
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_MULTICAST,
+ !(*total_flags & FIF_ALLMULTI));
+ rt2x00_set_field16(&reg, TXRX_CSR2_DROP_BROADCAST, 0);
+ rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+}
+
+static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct usb_device *usb_dev =
+ interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+ struct data_ring *ring =
+ rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+ struct data_entry *beacon;
+ struct data_entry *guardian;
+ int pipe = usb_sndbulkpipe(usb_dev, 1);
+ int max_packet = usb_maxpacket(usb_dev, pipe, 1);
+ int length;
+
+ /*
+ * Just in case the ieee80211 doesn't set this,
+ * but we need this queue set for the descriptor
+ * initialization.
+ */
+ control->queue = IEEE80211_TX_QUEUE_BEACON;
+
+ /*
+ * Obtain 2 entries, one for the guardian byte,
+ * the second for the actual beacon.
+ */
+ guardian = rt2x00_get_data_entry(ring);
+ rt2x00_ring_index_inc(ring);
+ beacon = rt2x00_get_data_entry(ring);
+
+ /*
+ * First we create the beacon.
+ */
+ skb_push(skb, ring->desc_size);
+ memset(skb->data, 0, ring->desc_size);
+
+ rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
+ (struct ieee80211_hdr *)(skb->data +
+ ring->desc_size),
+ skb->len - ring->desc_size, control);
+
+ length = rt2500usb_get_tx_data_len(rt2x00dev, max_packet, skb);
+
+ usb_fill_bulk_urb(beacon->priv, usb_dev, pipe,
+ skb->data, length, rt2500usb_beacondone, beacon);
+
+ beacon->skb = skb;
+
+ /*
+ * Second we need to create the guardian byte.
+ * We only need a single byte, so lets recycle
+ * the 'flags' field we are not using for beacons.
+ */
+ guardian->flags = 0;
+ usb_fill_bulk_urb(guardian->priv, usb_dev, pipe,
+ &guardian->flags, 1, rt2500usb_beacondone, guardian);
+
+ /*
+ * Send out the guardian byte.
+ */
+ usb_submit_urb(guardian->priv, GFP_ATOMIC);
+
+ /*
+ * Enable beacon generation.
+ */
+ rt2500usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+ return 0;
+}
+
+static const struct ieee80211_ops rt2500usb_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .config_interface = rt2x00mac_config_interface,
+ .configure_filter = rt2500usb_configure_filter,
+ .get_stats = rt2x00mac_get_stats,
+ .erp_ie_changed = rt2x00mac_erp_ie_changed,
+ .conf_tx = rt2x00mac_conf_tx,
+ .get_tx_stats = rt2x00mac_get_tx_stats,
+ .beacon_update = rt2500usb_beacon_update,
+};
+
+static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
+ .probe_hw = rt2500usb_probe_hw,
+ .initialize = rt2x00usb_initialize,
+ .uninitialize = rt2x00usb_uninitialize,
+ .set_device_state = rt2500usb_set_device_state,
+ .link_stats = rt2500usb_link_stats,
+ .reset_tuner = rt2500usb_reset_tuner,
+ .link_tuner = rt2500usb_link_tuner,
+ .write_tx_desc = rt2500usb_write_tx_desc,
+ .write_tx_data = rt2x00usb_write_tx_data,
+ .get_tx_data_len = rt2500usb_get_tx_data_len,
+ .kick_tx_queue = rt2500usb_kick_tx_queue,
+ .fill_rxdone = rt2500usb_fill_rxdone,
+ .config_mac_addr = rt2500usb_config_mac_addr,
+ .config_bssid = rt2500usb_config_bssid,
+ .config_type = rt2500usb_config_type,
+ .config_preamble = rt2500usb_config_preamble,
+ .config = rt2500usb_config,
+};
+
+static const struct rt2x00_ops rt2500usb_ops = {
+ .name = DRV_NAME,
+ .rxd_size = RXD_DESC_SIZE,
+ .txd_size = TXD_DESC_SIZE,
+ .eeprom_size = EEPROM_SIZE,
+ .rf_size = RF_SIZE,
+ .lib = &rt2500usb_rt2x00_ops,
+ .hw = &rt2500usb_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ .debugfs = &rt2500usb_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * rt2500usb module information.
+ */
+static struct usb_device_id rt2500usb_device_table[] = {
+ /* ASUS */
+ { USB_DEVICE(0x0b05, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0b05, 0x1707), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Belkin */
+ { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Cisco Systems */
+ { USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Conceptronic */
+ { USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* D-LINK */
+ { USB_DEVICE(0x2001, 0x3c00), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Gigabyte */
+ { USB_DEVICE(0x1044, 0x8001), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x1044, 0x8007), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Hercules */
+ { USB_DEVICE(0x06f8, 0xe000), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Melco */
+ { USB_DEVICE(0x0411, 0x0066), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0411, 0x0067), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0411, 0x008b), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0411, 0x0097), USB_DEVICE_DATA(&rt2500usb_ops) },
+
+ /* MSI */
+ { USB_DEVICE(0x0db0, 0x6861), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0db0, 0x6865), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0db0, 0x6869), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Ralink */
+ { USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Siemens */
+ { USB_DEVICE(0x0681, 0x3c06), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* SMC */
+ { USB_DEVICE(0x0707, 0xee13), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Spairon */
+ { USB_DEVICE(0x114b, 0x0110), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Trust */
+ { USB_DEVICE(0x0eb0, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) },
+ /* Zinwell */
+ { USB_DEVICE(0x5a57, 0x0260), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT2500 USB Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2570 USB chipset based cards");
+MODULE_DEVICE_TABLE(usb, rt2500usb_device_table);
+MODULE_LICENSE("GPL");
+
+static struct usb_driver rt2500usb_driver = {
+ .name = DRV_NAME,
+ .id_table = rt2500usb_device_table,
+ .probe = rt2x00usb_probe,
+ .disconnect = rt2x00usb_disconnect,
+ .suspend = rt2x00usb_suspend,
+ .resume = rt2x00usb_resume,
+};
+
+static int __init rt2500usb_init(void)
+{
+ return usb_register(&rt2500usb_driver);
+}
+
+static void __exit rt2500usb_exit(void)
+{
+ usb_deregister(&rt2500usb_driver);
+}
+
+module_init(rt2500usb_init);
+module_exit(rt2500usb_exit);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
new file mode 100644
index 00000000000..b18d56e73cf
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -0,0 +1,798 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2500usb
+ Abstract: Data structures and registers for the rt2500usb module.
+ Supported chipsets: RT2570.
+ */
+
+#ifndef RT2500USB_H
+#define RT2500USB_H
+
+/*
+ * RF chip defines.
+ */
+#define RF2522 0x0000
+#define RF2523 0x0001
+#define RF2524 0x0002
+#define RF2525 0x0003
+#define RF2525E 0x0005
+#define RF5222 0x0010
+
+/*
+ * RT2570 version
+ */
+#define RT2570_VERSION_B 2
+#define RT2570_VERSION_C 3
+#define RT2570_VERSION_D 4
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL 100
+#define MAX_RX_SSI -1
+#define DEFAULT_RSSI_OFFSET 120
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE 0x0400
+#define CSR_REG_SIZE 0x0100
+#define EEPROM_BASE 0x0000
+#define EEPROM_SIZE 0x006a
+#define BBP_SIZE 0x0060
+#define RF_SIZE 0x0014
+
+/*
+ * Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * MAC_CSR0: ASIC revision number.
+ */
+#define MAC_CSR0 0x0400
+
+/*
+ * MAC_CSR1: System control.
+ * SOFT_RESET: Software reset, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset, 1: reset, 0, release.
+ * HOST_READY: Host ready after initialization.
+ */
+#define MAC_CSR1 0x0402
+#define MAC_CSR1_SOFT_RESET FIELD16(0x00000001)
+#define MAC_CSR1_BBP_RESET FIELD16(0x00000002)
+#define MAC_CSR1_HOST_READY FIELD16(0x00000004)
+
+/*
+ * MAC_CSR2: STA MAC register 0.
+ */
+#define MAC_CSR2 0x0404
+#define MAC_CSR2_BYTE0 FIELD16(0x00ff)
+#define MAC_CSR2_BYTE1 FIELD16(0xff00)
+
+/*
+ * MAC_CSR3: STA MAC register 1.
+ */
+#define MAC_CSR3 0x0406
+#define MAC_CSR3_BYTE2 FIELD16(0x00ff)
+#define MAC_CSR3_BYTE3 FIELD16(0xff00)
+
+/*
+ * MAC_CSR4: STA MAC register 2.
+ */
+#define MAC_CSR4 0X0408
+#define MAC_CSR4_BYTE4 FIELD16(0x00ff)
+#define MAC_CSR4_BYTE5 FIELD16(0xff00)
+
+/*
+ * MAC_CSR5: BSSID register 0.
+ */
+#define MAC_CSR5 0x040a
+#define MAC_CSR5_BYTE0 FIELD16(0x00ff)
+#define MAC_CSR5_BYTE1 FIELD16(0xff00)
+
+/*
+ * MAC_CSR6: BSSID register 1.
+ */
+#define MAC_CSR6 0x040c
+#define MAC_CSR6_BYTE2 FIELD16(0x00ff)
+#define MAC_CSR6_BYTE3 FIELD16(0xff00)
+
+/*
+ * MAC_CSR7: BSSID register 2.
+ */
+#define MAC_CSR7 0x040e
+#define MAC_CSR7_BYTE4 FIELD16(0x00ff)
+#define MAC_CSR7_BYTE5 FIELD16(0xff00)
+
+/*
+ * MAC_CSR8: Max frame length.
+ */
+#define MAC_CSR8 0x0410
+#define MAC_CSR8_MAX_FRAME_UNIT FIELD16(0x0fff)
+
+/*
+ * Misc MAC_CSR registers.
+ * MAC_CSR9: Timer control.
+ * MAC_CSR10: Slot time.
+ * MAC_CSR11: IFS.
+ * MAC_CSR12: EIFS.
+ * MAC_CSR13: Power mode0.
+ * MAC_CSR14: Power mode1.
+ * MAC_CSR15: Power saving transition0
+ * MAC_CSR16: Power saving transition1
+ */
+#define MAC_CSR9 0x0412
+#define MAC_CSR10 0x0414
+#define MAC_CSR11 0x0416
+#define MAC_CSR12 0x0418
+#define MAC_CSR13 0x041a
+#define MAC_CSR14 0x041c
+#define MAC_CSR15 0x041e
+#define MAC_CSR16 0x0420
+
+/*
+ * MAC_CSR17: Manual power control / status register.
+ * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake.
+ * SET_STATE: Set state. Write 1 to trigger, self cleared.
+ * BBP_DESIRE_STATE: BBP desired state.
+ * RF_DESIRE_STATE: RF desired state.
+ * BBP_CURRENT_STATE: BBP current state.
+ * RF_CURRENT_STATE: RF current state.
+ * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared.
+ */
+#define MAC_CSR17 0x0422
+#define MAC_CSR17_SET_STATE FIELD16(0x0001)
+#define MAC_CSR17_BBP_DESIRE_STATE FIELD16(0x0006)
+#define MAC_CSR17_RF_DESIRE_STATE FIELD16(0x0018)
+#define MAC_CSR17_BBP_CURR_STATE FIELD16(0x0060)
+#define MAC_CSR17_RF_CURR_STATE FIELD16(0x0180)
+#define MAC_CSR17_PUT_TO_SLEEP FIELD16(0x0200)
+
+/*
+ * MAC_CSR18: Wakeup timer register.
+ * DELAY_AFTER_BEACON: Delay after Tbcn expired in units of 1/16 TU.
+ * BEACONS_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * AUTO_WAKE: Enable auto wakeup / sleep mechanism.
+ */
+#define MAC_CSR18 0x0424
+#define MAC_CSR18_DELAY_AFTER_BEACON FIELD16(0x00ff)
+#define MAC_CSR18_BEACONS_BEFORE_WAKEUP FIELD16(0x7f00)
+#define MAC_CSR18_AUTO_WAKE FIELD16(0x8000)
+
+/*
+ * MAC_CSR19: GPIO control register.
+ */
+#define MAC_CSR19 0x0426
+
+/*
+ * MAC_CSR20: LED control register.
+ * ACTIVITY: 0: idle, 1: active.
+ * LINK: 0: linkoff, 1: linkup.
+ * ACTIVITY_POLARITY: 0: active low, 1: active high.
+ */
+#define MAC_CSR20 0x0428
+#define MAC_CSR20_ACTIVITY FIELD16(0x0001)
+#define MAC_CSR20_LINK FIELD16(0x0002)
+#define MAC_CSR20_ACTIVITY_POLARITY FIELD16(0x0004)
+
+/*
+ * MAC_CSR21: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ */
+#define MAC_CSR21 0x042a
+#define MAC_CSR21_ON_PERIOD FIELD16(0x00ff)
+#define MAC_CSR21_OFF_PERIOD FIELD16(0xff00)
+
+/*
+ * Collision window control register.
+ */
+#define MAC_CSR22 0x042c
+
+/*
+ * Transmit related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXRX_CSR0: Security control register.
+ */
+#define TXRX_CSR0 0x0440
+#define TXRX_CSR0_ALGORITHM FIELD16(0x0007)
+#define TXRX_CSR0_IV_OFFSET FIELD16(0x01f8)
+#define TXRX_CSR0_KEY_ID FIELD16(0x1e00)
+
+/*
+ * TXRX_CSR1: TX configuration.
+ * ACK_TIMEOUT: ACK Timeout in unit of 1-us.
+ * TSF_OFFSET: TSF offset in MAC header.
+ * AUTO_SEQUENCE: Let ASIC control frame sequence number.
+ */
+#define TXRX_CSR1 0x0442
+#define TXRX_CSR1_ACK_TIMEOUT FIELD16(0x00ff)
+#define TXRX_CSR1_TSF_OFFSET FIELD16(0x7f00)
+#define TXRX_CSR1_AUTO_SEQUENCE FIELD16(0x8000)
+
+/*
+ * TXRX_CSR2: RX control.
+ * DISABLE_RX: Disable rx engine.
+ * DROP_CRC: Drop crc error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TODS: Drop frame tods bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * DROP_MCAST: Drop multicast frames.
+ * DROP_BCAST: Drop broadcast frames.
+ */
+#define TXRX_CSR2 0x0444
+#define TXRX_CSR2_DISABLE_RX FIELD16(0x0001)
+#define TXRX_CSR2_DROP_CRC FIELD16(0x0002)
+#define TXRX_CSR2_DROP_PHYSICAL FIELD16(0x0004)
+#define TXRX_CSR2_DROP_CONTROL FIELD16(0x0008)
+#define TXRX_CSR2_DROP_NOT_TO_ME FIELD16(0x0010)
+#define TXRX_CSR2_DROP_TODS FIELD16(0x0020)
+#define TXRX_CSR2_DROP_VERSION_ERROR FIELD16(0x0040)
+#define TXRX_CSR2_DROP_MULTICAST FIELD16(0x0200)
+#define TXRX_CSR2_DROP_BROADCAST FIELD16(0x0400)
+
+/*
+ * RX BBP ID registers
+ * TXRX_CSR3: CCK RX BBP ID.
+ * TXRX_CSR4: OFDM RX BBP ID.
+ */
+#define TXRX_CSR3 0x0446
+#define TXRX_CSR4 0x0448
+
+/*
+ * TXRX_CSR5: CCK TX BBP ID0.
+ */
+#define TXRX_CSR5 0x044a
+#define TXRX_CSR5_BBP_ID0 FIELD16(0x007f)
+#define TXRX_CSR5_BBP_ID0_VALID FIELD16(0x0080)
+#define TXRX_CSR5_BBP_ID1 FIELD16(0x7f00)
+#define TXRX_CSR5_BBP_ID1_VALID FIELD16(0x8000)
+
+/*
+ * TXRX_CSR6: CCK TX BBP ID1.
+ */
+#define TXRX_CSR6 0x044c
+#define TXRX_CSR6_BBP_ID0 FIELD16(0x007f)
+#define TXRX_CSR6_BBP_ID0_VALID FIELD16(0x0080)
+#define TXRX_CSR6_BBP_ID1 FIELD16(0x7f00)
+#define TXRX_CSR6_BBP_ID1_VALID FIELD16(0x8000)
+
+/*
+ * TXRX_CSR7: OFDM TX BBP ID0.
+ */
+#define TXRX_CSR7 0x044e
+#define TXRX_CSR7_BBP_ID0 FIELD16(0x007f)
+#define TXRX_CSR7_BBP_ID0_VALID FIELD16(0x0080)
+#define TXRX_CSR7_BBP_ID1 FIELD16(0x7f00)
+#define TXRX_CSR7_BBP_ID1_VALID FIELD16(0x8000)
+
+/*
+ * TXRX_CSR5: OFDM TX BBP ID1.
+ */
+#define TXRX_CSR8 0x0450
+#define TXRX_CSR8_BBP_ID0 FIELD16(0x007f)
+#define TXRX_CSR8_BBP_ID0_VALID FIELD16(0x0080)
+#define TXRX_CSR8_BBP_ID1 FIELD16(0x7f00)
+#define TXRX_CSR8_BBP_ID1_VALID FIELD16(0x8000)
+
+/*
+ * TXRX_CSR9: TX ACK time-out.
+ */
+#define TXRX_CSR9 0x0452
+
+/*
+ * TXRX_CSR10: Auto responder control.
+ */
+#define TXRX_CSR10 0x0454
+#define TXRX_CSR10_AUTORESPOND_PREAMBLE FIELD16(0x0004)
+
+/*
+ * TXRX_CSR11: Auto responder basic rate.
+ */
+#define TXRX_CSR11 0x0456
+
+/*
+ * ACK/CTS time registers.
+ */
+#define TXRX_CSR12 0x0458
+#define TXRX_CSR13 0x045a
+#define TXRX_CSR14 0x045c
+#define TXRX_CSR15 0x045e
+#define TXRX_CSR16 0x0460
+#define TXRX_CSR17 0x0462
+
+/*
+ * TXRX_CSR18: Synchronization control register.
+ */
+#define TXRX_CSR18 0x0464
+#define TXRX_CSR18_OFFSET FIELD16(0x000f)
+#define TXRX_CSR18_INTERVAL FIELD16(0xfff0)
+
+/*
+ * TXRX_CSR19: Synchronization control register.
+ * TSF_COUNT: Enable TSF auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * TBCN: Enable Tbcn with reload value.
+ * BEACON_GEN: Enable beacon generator.
+ */
+#define TXRX_CSR19 0x0466
+#define TXRX_CSR19_TSF_COUNT FIELD16(0x0001)
+#define TXRX_CSR19_TSF_SYNC FIELD16(0x0006)
+#define TXRX_CSR19_TBCN FIELD16(0x0008)
+#define TXRX_CSR19_BEACON_GEN FIELD16(0x0010)
+
+/*
+ * TXRX_CSR20: Tx BEACON offset time control register.
+ * OFFSET: In units of usec.
+ * BCN_EXPECT_WINDOW: Default: 2^CWmin
+ */
+#define TXRX_CSR20 0x0468
+#define TXRX_CSR20_OFFSET FIELD16(0x1fff)
+#define TXRX_CSR20_BCN_EXPECT_WINDOW FIELD16(0xe000)
+
+/*
+ * TXRX_CSR21
+ */
+#define TXRX_CSR21 0x046a
+
+/*
+ * Encryption related CSRs.
+ *
+ */
+
+/*
+ * SEC_CSR0-SEC_CSR7: Shared key 0, word 0-7
+ */
+#define SEC_CSR0 0x0480
+#define SEC_CSR1 0x0482
+#define SEC_CSR2 0x0484
+#define SEC_CSR3 0x0486
+#define SEC_CSR4 0x0488
+#define SEC_CSR5 0x048a
+#define SEC_CSR6 0x048c
+#define SEC_CSR7 0x048e
+
+/*
+ * SEC_CSR8-SEC_CSR15: Shared key 1, word 0-7
+ */
+#define SEC_CSR8 0x0490
+#define SEC_CSR9 0x0492
+#define SEC_CSR10 0x0494
+#define SEC_CSR11 0x0496
+#define SEC_CSR12 0x0498
+#define SEC_CSR13 0x049a
+#define SEC_CSR14 0x049c
+#define SEC_CSR15 0x049e
+
+/*
+ * SEC_CSR16-SEC_CSR23: Shared key 2, word 0-7
+ */
+#define SEC_CSR16 0x04a0
+#define SEC_CSR17 0x04a2
+#define SEC_CSR18 0X04A4
+#define SEC_CSR19 0x04a6
+#define SEC_CSR20 0x04a8
+#define SEC_CSR21 0x04aa
+#define SEC_CSR22 0x04ac
+#define SEC_CSR23 0x04ae
+
+/*
+ * SEC_CSR24-SEC_CSR31: Shared key 3, word 0-7
+ */
+#define SEC_CSR24 0x04b0
+#define SEC_CSR25 0x04b2
+#define SEC_CSR26 0x04b4
+#define SEC_CSR27 0x04b6
+#define SEC_CSR28 0x04b8
+#define SEC_CSR29 0x04ba
+#define SEC_CSR30 0x04bc
+#define SEC_CSR31 0x04be
+
+/*
+ * PHY control registers.
+ */
+
+/*
+ * PHY_CSR0: RF switching timing control.
+ */
+#define PHY_CSR0 0x04c0
+
+/*
+ * PHY_CSR1: TX PA configuration.
+ */
+#define PHY_CSR1 0x04c2
+
+/*
+ * MAC configuration registers.
+ * PHY_CSR2: TX MAC configuration.
+ * PHY_CSR3: RX MAC configuration.
+ */
+#define PHY_CSR2 0x04c4
+#define PHY_CSR3 0x04c6
+
+/*
+ * PHY_CSR4: Interface configuration.
+ */
+#define PHY_CSR4 0x04c8
+#define PHY_CSR4_LOW_RF_LE FIELD16(0x0001)
+
+/*
+ * BBP pre-TX registers.
+ * PHY_CSR5: BBP pre-TX CCK.
+ */
+#define PHY_CSR5 0x04ca
+#define PHY_CSR5_CCK FIELD16(0x0003)
+#define PHY_CSR5_CCK_FLIP FIELD16(0x0004)
+
+/*
+ * BBP pre-TX registers.
+ * PHY_CSR6: BBP pre-TX OFDM.
+ */
+#define PHY_CSR6 0x04cc
+#define PHY_CSR6_OFDM FIELD16(0x0003)
+#define PHY_CSR6_OFDM_FLIP FIELD16(0x0004)
+
+/*
+ * PHY_CSR7: BBP access register 0.
+ * BBP_DATA: BBP data.
+ * BBP_REG_ID: BBP register ID.
+ * BBP_READ_CONTROL: 0: write, 1: read.
+ */
+#define PHY_CSR7 0x04ce
+#define PHY_CSR7_DATA FIELD16(0x00ff)
+#define PHY_CSR7_REG_ID FIELD16(0x7f00)
+#define PHY_CSR7_READ_CONTROL FIELD16(0x8000)
+
+/*
+ * PHY_CSR8: BBP access register 1.
+ * BBP_BUSY: ASIC is busy execute BBP programming.
+ */
+#define PHY_CSR8 0x04d0
+#define PHY_CSR8_BUSY FIELD16(0x0001)
+
+/*
+ * PHY_CSR9: RF access register.
+ * RF_VALUE: Register value + id to program into rf/if.
+ */
+#define PHY_CSR9 0x04d2
+#define PHY_CSR9_RF_VALUE FIELD16(0xffff)
+
+/*
+ * PHY_CSR10: RF access register.
+ * RF_VALUE: Register value + id to program into rf/if.
+ * RF_NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22).
+ * RF_IF_SELECT: Chip to program: 0: rf, 1: if.
+ * RF_PLL_LD: Rf pll_ld status.
+ * RF_BUSY: 1: asic is busy execute rf programming.
+ */
+#define PHY_CSR10 0x04d4
+#define PHY_CSR10_RF_VALUE FIELD16(0x00ff)
+#define PHY_CSR10_RF_NUMBER_OF_BITS FIELD16(0x1f00)
+#define PHY_CSR10_RF_IF_SELECT FIELD16(0x2000)
+#define PHY_CSR10_RF_PLL_LD FIELD16(0x4000)
+#define PHY_CSR10_RF_BUSY FIELD16(0x8000)
+
+/*
+ * STA_CSR0: FCS error count.
+ * FCS_ERROR: FCS error count, cleared when read.
+ */
+#define STA_CSR0 0x04e0
+#define STA_CSR0_FCS_ERROR FIELD16(0xffff)
+
+/*
+ * STA_CSR1: PLCP error count.
+ */
+#define STA_CSR1 0x04e2
+
+/*
+ * STA_CSR2: LONG error count.
+ */
+#define STA_CSR2 0x04e4
+
+/*
+ * STA_CSR3: CCA false alarm.
+ * FALSE_CCA_ERROR: False CCA error count, cleared when read.
+ */
+#define STA_CSR3 0x04e6
+#define STA_CSR3_FALSE_CCA_ERROR FIELD16(0xffff)
+
+/*
+ * STA_CSR4: RX FIFO overflow.
+ */
+#define STA_CSR4 0x04e8
+
+/*
+ * STA_CSR5: Beacon sent counter.
+ */
+#define STA_CSR5 0x04ea
+
+/*
+ * Statistics registers
+ */
+#define STA_CSR6 0x04ec
+#define STA_CSR7 0x04ee
+#define STA_CSR8 0x04f0
+#define STA_CSR9 0x04f2
+#define STA_CSR10 0x04f4
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R2: TX antenna control
+ */
+#define BBP_R2_TX_ANTENNA FIELD8(0x03)
+#define BBP_R2_TX_IQ_FLIP FIELD8(0x04)
+
+/*
+ * R14: RX antenna control
+ */
+#define BBP_R14_RX_ANTENNA FIELD8(0x03)
+#define BBP_R14_RX_IQ_FLIP FIELD8(0x04)
+
+/*
+ * RF registers.
+ */
+
+/*
+ * RF 1
+ */
+#define RF1_TUNER FIELD32(0x00020000)
+
+/*
+ * RF 3
+ */
+#define RF3_TUNER FIELD32(0x00000100)
+#define RF3_TXPOWER FIELD32(0x00003e00)
+
+/*
+ * EEPROM contents.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0 0x0002
+#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1 0x0003
+#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2 0x0004
+#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * LED_MODE: 0: default, 1: TX/RX activity, 2: Single (ignore link), 3: rsvd.
+ * DYN_TXAGC: Dynamic TX AGC control.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ * RF_TYPE: Rf_type of this adapter.
+ */
+#define EEPROM_ANTENNA 0x000b
+#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
+#define EEPROM_ANTENNA_LED_MODE FIELD16(0x01c0)
+#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
+#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800)
+
+/*
+ * EEPROM NIC config.
+ * CARDBUS_ACCEL: 0: enable, 1: disable.
+ * DYN_BBP_TUNE: 0: enable, 1: disable.
+ * CCK_TX_POWER: CCK TX power compensation.
+ */
+#define EEPROM_NIC 0x000c
+#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0001)
+#define EEPROM_NIC_DYN_BBP_TUNE FIELD16(0x0002)
+#define EEPROM_NIC_CCK_TX_POWER FIELD16(0x000c)
+
+/*
+ * EEPROM geography.
+ * GEO: Default geography setting for device.
+ */
+#define EEPROM_GEOGRAPHY 0x000d
+#define EEPROM_GEOGRAPHY_GEO FIELD16(0x0f00)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START 0x000e
+#define EEPROM_BBP_SIZE 16
+#define EEPROM_BBP_VALUE FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER
+ */
+#define EEPROM_TXPOWER_START 0x001e
+#define EEPROM_TXPOWER_SIZE 7
+#define EEPROM_TXPOWER_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_2 FIELD16(0xff00)
+
+/*
+ * EEPROM Tuning threshold
+ */
+#define EEPROM_BBPTUNE 0x0030
+#define EEPROM_BBPTUNE_THRESHOLD FIELD16(0x00ff)
+
+/*
+ * EEPROM BBP R24 Tuning.
+ */
+#define EEPROM_BBPTUNE_R24 0x0031
+#define EEPROM_BBPTUNE_R24_LOW FIELD16(0x00ff)
+#define EEPROM_BBPTUNE_R24_HIGH FIELD16(0xff00)
+
+/*
+ * EEPROM BBP R25 Tuning.
+ */
+#define EEPROM_BBPTUNE_R25 0x0032
+#define EEPROM_BBPTUNE_R25_LOW FIELD16(0x00ff)
+#define EEPROM_BBPTUNE_R25_HIGH FIELD16(0xff00)
+
+/*
+ * EEPROM BBP R24 Tuning.
+ */
+#define EEPROM_BBPTUNE_R61 0x0033
+#define EEPROM_BBPTUNE_R61_LOW FIELD16(0x00ff)
+#define EEPROM_BBPTUNE_R61_HIGH FIELD16(0xff00)
+
+/*
+ * EEPROM BBP VGC Tuning.
+ */
+#define EEPROM_BBPTUNE_VGC 0x0034
+#define EEPROM_BBPTUNE_VGCUPPER FIELD16(0x00ff)
+
+/*
+ * EEPROM BBP R17 Tuning.
+ */
+#define EEPROM_BBPTUNE_R17 0x0035
+#define EEPROM_BBPTUNE_R17_LOW FIELD16(0x00ff)
+#define EEPROM_BBPTUNE_R17_HIGH FIELD16(0xff00)
+
+/*
+ * RSSI <-> dBm offset calibration
+ */
+#define EEPROM_CALIBRATE_OFFSET 0x0036
+#define EEPROM_CALIBRATE_OFFSET_RSSI FIELD16(0x00ff)
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE ( 5 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE ( 4 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
+ */
+
+/*
+ * Word0
+ */
+#define TXD_W0_PACKET_ID FIELD32(0x0000000f)
+#define TXD_W0_RETRY_LIMIT FIELD32(0x000000f0)
+#define TXD_W0_MORE_FRAG FIELD32(0x00000100)
+#define TXD_W0_ACK FIELD32(0x00000200)
+#define TXD_W0_TIMESTAMP FIELD32(0x00000400)
+#define TXD_W0_OFDM FIELD32(0x00000800)
+#define TXD_W0_NEW_SEQ FIELD32(0x00001000)
+#define TXD_W0_IFS FIELD32(0x00006000)
+#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define TXD_W0_CIPHER FIELD32(0x20000000)
+#define TXD_W0_KEY_ID FIELD32(0xc0000000)
+
+/*
+ * Word1
+ */
+#define TXD_W1_IV_OFFSET FIELD32(0x0000003f)
+#define TXD_W1_AIFS FIELD32(0x000000c0)
+#define TXD_W1_CWMIN FIELD32(0x00000f00)
+#define TXD_W1_CWMAX FIELD32(0x0000f000)
+
+/*
+ * Word2: PLCP information
+ */
+#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff)
+#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00)
+#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000)
+#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000)
+
+/*
+ * Word3
+ */
+#define TXD_W3_IV FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define TXD_W4_EIV FIELD32(0xffffffff)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ */
+#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000002)
+#define RXD_W0_MULTICAST FIELD32(0x00000004)
+#define RXD_W0_BROADCAST FIELD32(0x00000008)
+#define RXD_W0_MY_BSS FIELD32(0x00000010)
+#define RXD_W0_CRC_ERROR FIELD32(0x00000020)
+#define RXD_W0_OFDM FIELD32(0x00000040)
+#define RXD_W0_PHYSICAL_ERROR FIELD32(0x00000080)
+#define RXD_W0_CIPHER FIELD32(0x00000100)
+#define RXD_W0_CIPHER_ERROR FIELD32(0x00000200)
+#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+
+/*
+ * Word1
+ */
+#define RXD_W1_RSSI FIELD32(0x000000ff)
+#define RXD_W1_SIGNAL FIELD32(0x0000ff00)
+
+/*
+ * Word2
+ */
+#define RXD_W2_IV FIELD32(0xffffffff)
+
+/*
+ * Word3
+ */
+#define RXD_W3_EIV FIELD32(0xffffffff)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ */
+#define MIN_TXPOWER 0
+#define MAX_TXPOWER 31
+#define DEFAULT_TXPOWER 24
+
+#define TXPOWER_FROM_DEV(__txpower) \
+({ \
+ ((__txpower) > MAX_TXPOWER) ? \
+ DEFAULT_TXPOWER : (__txpower); \
+})
+
+#define TXPOWER_TO_DEV(__txpower) \
+({ \
+ ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
+ (__txpower)); \
+})
+
+#endif /* RT2500USB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
new file mode 100644
index 00000000000..d1ad5251a77
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -0,0 +1,840 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00
+ Abstract: rt2x00 global information.
+ */
+
+#ifndef RT2X00_H
+#define RT2X00_H
+
+#include <linux/bitops.h>
+#include <linux/prefetch.h>
+#include <linux/skbuff.h>
+#include <linux/workqueue.h>
+#include <linux/firmware.h>
+
+#include <net/mac80211.h>
+
+#include "rt2x00debug.h"
+#include "rt2x00reg.h"
+#include "rt2x00ring.h"
+
+/*
+ * Module information.
+ * DRV_NAME should be set within the individual module source files.
+ */
+#define DRV_VERSION "2.0.10"
+#define DRV_PROJECT "http://rt2x00.serialmonkey.com"
+
+/*
+ * Debug definitions.
+ * Debug output has to be enabled during compile time.
+ */
+#define DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, __args...) \
+ printk(__kernlvl "%s -> %s: %s - " __msg, \
+ wiphy_name((__dev)->hw->wiphy), __FUNCTION__, __lvl, ##__args)
+
+#define DEBUG_PRINTK_PROBE(__kernlvl, __lvl, __msg, __args...) \
+ printk(__kernlvl "%s -> %s: %s - " __msg, \
+ DRV_NAME, __FUNCTION__, __lvl, ##__args)
+
+#ifdef CONFIG_RT2X00_DEBUG
+#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \
+ DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, ##__args);
+#else
+#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \
+ do { } while (0)
+#endif /* CONFIG_RT2X00_DEBUG */
+
+/*
+ * Various debug levels.
+ * The debug levels PANIC and ERROR both indicate serious problems,
+ * for this reason they should never be ignored.
+ * The special ERROR_PROBE message is for messages that are generated
+ * when the rt2x00_dev is not yet initialized.
+ */
+#define PANIC(__dev, __msg, __args...) \
+ DEBUG_PRINTK_MSG(__dev, KERN_CRIT, "Panic", __msg, ##__args)
+#define ERROR(__dev, __msg, __args...) \
+ DEBUG_PRINTK_MSG(__dev, KERN_ERR, "Error", __msg, ##__args)
+#define ERROR_PROBE(__msg, __args...) \
+ DEBUG_PRINTK_PROBE(KERN_ERR, "Error", __msg, ##__args)
+#define WARNING(__dev, __msg, __args...) \
+ DEBUG_PRINTK(__dev, KERN_WARNING, "Warning", __msg, ##__args)
+#define NOTICE(__dev, __msg, __args...) \
+ DEBUG_PRINTK(__dev, KERN_NOTICE, "Notice", __msg, ##__args)
+#define INFO(__dev, __msg, __args...) \
+ DEBUG_PRINTK(__dev, KERN_INFO, "Info", __msg, ##__args)
+#define DEBUG(__dev, __msg, __args...) \
+ DEBUG_PRINTK(__dev, KERN_DEBUG, "Debug", __msg, ##__args)
+#define EEPROM(__dev, __msg, __args...) \
+ DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args)
+
+/*
+ * Ring sizes.
+ * Ralink PCI devices demand the Frame size to be a multiple of 128 bytes.
+ * DATA_FRAME_SIZE is used for TX, RX, ATIM and PRIO rings.
+ * MGMT_FRAME_SIZE is used for the BEACON ring.
+ */
+#define DATA_FRAME_SIZE 2432
+#define MGMT_FRAME_SIZE 256
+
+/*
+ * Number of entries in a packet ring.
+ * PCI devices only need 1 Beacon entry,
+ * but USB devices require a second because they
+ * have to send a Guardian byte first.
+ */
+#define RX_ENTRIES 12
+#define TX_ENTRIES 12
+#define ATIM_ENTRIES 1
+#define BEACON_ENTRIES 2
+
+/*
+ * Standard timing and size defines.
+ * These values should follow the ieee80211 specifications.
+ */
+#define ACK_SIZE 14
+#define IEEE80211_HEADER 24
+#define PLCP 48
+#define BEACON 100
+#define PREAMBLE 144
+#define SHORT_PREAMBLE 72
+#define SLOT_TIME 20
+#define SHORT_SLOT_TIME 9
+#define SIFS 10
+#define PIFS ( SIFS + SLOT_TIME )
+#define SHORT_PIFS ( SIFS + SHORT_SLOT_TIME )
+#define DIFS ( PIFS + SLOT_TIME )
+#define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME )
+#define EIFS ( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) )
+
+/*
+ * IEEE802.11 header defines
+ */
+static inline int is_rts_frame(u16 fc)
+{
+ return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS));
+}
+
+static inline int is_cts_frame(u16 fc)
+{
+ return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS));
+}
+
+static inline int is_probe_resp(u16 fc)
+{
+ return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+ ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP));
+}
+
+/*
+ * Chipset identification
+ * The chipset on the device is composed of a RT and RF chip.
+ * The chipset combination is important for determining device capabilities.
+ */
+struct rt2x00_chip {
+ u16 rt;
+#define RT2460 0x0101
+#define RT2560 0x0201
+#define RT2570 0x1201
+#define RT2561s 0x0301 /* Turbo */
+#define RT2561 0x0302
+#define RT2661 0x0401
+#define RT2571 0x1300
+
+ u16 rf;
+ u32 rev;
+};
+
+/*
+ * RF register values that belong to a particular channel.
+ */
+struct rf_channel {
+ int channel;
+ u32 rf1;
+ u32 rf2;
+ u32 rf3;
+ u32 rf4;
+};
+
+/*
+ * To optimize the quality of the link we need to store
+ * the quality of received frames and periodically
+ * optimize the link.
+ */
+struct link {
+ /*
+ * Link tuner counter
+ * The number of times the link has been tuned
+ * since the radio has been switched on.
+ */
+ u32 count;
+
+ /*
+ * Statistics required for Link tuning.
+ * For the average RSSI value we use the "Walking average" approach.
+ * When adding RSSI to the average value the following calculation
+ * is needed:
+ *
+ * avg_rssi = ((avg_rssi * 7) + rssi) / 8;
+ *
+ * The advantage of this approach is that we only need 1 variable
+ * to store the average in (No need for a count and a total).
+ * But more importantly, normal average values will over time
+ * move less and less towards newly added values this results
+ * that with link tuning, the device can have a very good RSSI
+ * for a few minutes but when the device is moved away from the AP
+ * the average will not decrease fast enough to compensate.
+ * The walking average compensates this and will move towards
+ * the new values correctly allowing a effective link tuning.
+ */
+ int avg_rssi;
+ int vgc_level;
+ int false_cca;
+
+ /*
+ * Statistics required for Signal quality calculation.
+ * For calculating the Signal quality we have to determine
+ * the total number of success and failed RX and TX frames.
+ * After that we also use the average RSSI value to help
+ * determining the signal quality.
+ * For the calculation we will use the following algorithm:
+ *
+ * rssi_percentage = (avg_rssi * 100) / rssi_offset
+ * rx_percentage = (rx_success * 100) / rx_total
+ * tx_percentage = (tx_success * 100) / tx_total
+ * avg_signal = ((WEIGHT_RSSI * avg_rssi) +
+ * (WEIGHT_TX * tx_percentage) +
+ * (WEIGHT_RX * rx_percentage)) / 100
+ *
+ * This value should then be checked to not be greated then 100.
+ */
+ int rx_percentage;
+ int rx_success;
+ int rx_failed;
+ int tx_percentage;
+ int tx_success;
+ int tx_failed;
+#define WEIGHT_RSSI 20
+#define WEIGHT_RX 40
+#define WEIGHT_TX 40
+
+ /*
+ * Work structure for scheduling periodic link tuning.
+ */
+ struct delayed_work work;
+};
+
+/*
+ * Clear all counters inside the link structure.
+ * This can be easiest achieved by memsetting everything
+ * except for the work structure at the end.
+ */
+static inline void rt2x00_clear_link(struct link *link)
+{
+ memset(link, 0x00, sizeof(*link) - sizeof(link->work));
+ link->rx_percentage = 50;
+ link->tx_percentage = 50;
+}
+
+/*
+ * Update the rssi using the walking average approach.
+ */
+static inline void rt2x00_update_link_rssi(struct link *link, int rssi)
+{
+ if (!link->avg_rssi)
+ link->avg_rssi = rssi;
+ else
+ link->avg_rssi = ((link->avg_rssi * 7) + rssi) / 8;
+}
+
+/*
+ * When the avg_rssi is unset or no frames have been received),
+ * we need to return the default value which needs to be less
+ * than -80 so the device will select the maximum sensitivity.
+ */
+static inline int rt2x00_get_link_rssi(struct link *link)
+{
+ return (link->avg_rssi && link->rx_success) ? link->avg_rssi : -128;
+}
+
+/*
+ * Interface structure
+ * Configuration details about the current interface.
+ */
+struct interface {
+ /*
+ * Interface identification. The value is assigned
+ * to us by the 80211 stack, and is used to request
+ * new beacons.
+ */
+ int id;
+
+ /*
+ * Current working type (IEEE80211_IF_TYPE_*).
+ * When set to INVALID_INTERFACE, no interface is configured.
+ */
+ int type;
+#define INVALID_INTERFACE IEEE80211_IF_TYPE_INVALID
+
+ /*
+ * MAC of the device.
+ */
+ u8 mac[ETH_ALEN];
+
+ /*
+ * BBSID of the AP to associate with.
+ */
+ u8 bssid[ETH_ALEN];
+
+ /*
+ * Store the packet filter mode for the current interface.
+ */
+ unsigned int filter;
+};
+
+static inline int is_interface_present(struct interface *intf)
+{
+ return !!intf->id;
+}
+
+static inline int is_interface_type(struct interface *intf, int type)
+{
+ return intf->type == type;
+}
+
+/*
+ * Details about the supported modes, rates and channels
+ * of a particular chipset. This is used by rt2x00lib
+ * to build the ieee80211_hw_mode array for mac80211.
+ */
+struct hw_mode_spec {
+ /*
+ * Number of modes, rates and channels.
+ */
+ int num_modes;
+ int num_rates;
+ int num_channels;
+
+ /*
+ * txpower values.
+ */
+ const u8 *tx_power_a;
+ const u8 *tx_power_bg;
+ u8 tx_power_default;
+
+ /*
+ * Device/chipset specific value.
+ */
+ const struct rf_channel *channels;
+};
+
+/*
+ * Configuration structure wrapper around the
+ * mac80211 configuration structure.
+ * When mac80211 configures the driver, rt2x00lib
+ * can precalculate values which are equal for all
+ * rt2x00 drivers. Those values can be stored in here.
+ */
+struct rt2x00lib_conf {
+ struct ieee80211_conf *conf;
+ struct rf_channel rf;
+
+ int phymode;
+
+ int basic_rates;
+ int slot_time;
+
+ short sifs;
+ short pifs;
+ short difs;
+ short eifs;
+};
+
+/*
+ * rt2x00lib callback functions.
+ */
+struct rt2x00lib_ops {
+ /*
+ * Interrupt handlers.
+ */
+ irq_handler_t irq_handler;
+
+ /*
+ * Device init handlers.
+ */
+ int (*probe_hw) (struct rt2x00_dev *rt2x00dev);
+ char *(*get_firmware_name) (struct rt2x00_dev *rt2x00dev);
+ int (*load_firmware) (struct rt2x00_dev *rt2x00dev, void *data,
+ const size_t len);
+
+ /*
+ * Device initialization/deinitialization handlers.
+ */
+ int (*initialize) (struct rt2x00_dev *rt2x00dev);
+ void (*uninitialize) (struct rt2x00_dev *rt2x00dev);
+
+ /*
+ * Radio control handlers.
+ */
+ int (*set_device_state) (struct rt2x00_dev *rt2x00dev,
+ enum dev_state state);
+ int (*rfkill_poll) (struct rt2x00_dev *rt2x00dev);
+ void (*link_stats) (struct rt2x00_dev *rt2x00dev);
+ void (*reset_tuner) (struct rt2x00_dev *rt2x00dev);
+ void (*link_tuner) (struct rt2x00_dev *rt2x00dev);
+
+ /*
+ * TX control handlers
+ */
+ void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct txdata_entry_desc *desc,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control);
+ int (*write_tx_data) (struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring, struct sk_buff *skb,
+ struct ieee80211_tx_control *control);
+ int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, int maxpacket,
+ struct sk_buff *skb);
+ void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
+ unsigned int queue);
+
+ /*
+ * RX control handlers
+ */
+ void (*fill_rxdone) (struct data_entry *entry,
+ struct rxdata_entry_desc *desc);
+
+ /*
+ * Configuration handlers.
+ */
+ void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, __le32 *mac);
+ void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid);
+ void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type,
+ const int tsf_sync);
+ void (*config_preamble) (struct rt2x00_dev *rt2x00dev,
+ const int short_preamble,
+ const int ack_timeout,
+ const int ack_consume_time);
+ void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags,
+ struct rt2x00lib_conf *libconf);
+#define CONFIG_UPDATE_PHYMODE ( 1 << 1 )
+#define CONFIG_UPDATE_CHANNEL ( 1 << 2 )
+#define CONFIG_UPDATE_TXPOWER ( 1 << 3 )
+#define CONFIG_UPDATE_ANTENNA ( 1 << 4 )
+#define CONFIG_UPDATE_SLOT_TIME ( 1 << 5 )
+#define CONFIG_UPDATE_BEACON_INT ( 1 << 6 )
+#define CONFIG_UPDATE_ALL 0xffff
+};
+
+/*
+ * rt2x00 driver callback operation structure.
+ */
+struct rt2x00_ops {
+ const char *name;
+ const unsigned int rxd_size;
+ const unsigned int txd_size;
+ const unsigned int eeprom_size;
+ const unsigned int rf_size;
+ const struct rt2x00lib_ops *lib;
+ const struct ieee80211_ops *hw;
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ const struct rt2x00debug *debugfs;
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * rt2x00 device flags
+ */
+enum rt2x00_flags {
+ /*
+ * Device state flags
+ */
+ DEVICE_PRESENT,
+ DEVICE_REGISTERED_HW,
+ DEVICE_INITIALIZED,
+ DEVICE_STARTED,
+ DEVICE_STARTED_SUSPEND,
+ DEVICE_ENABLED_RADIO,
+ DEVICE_DISABLED_RADIO_HW,
+
+ /*
+ * Driver features
+ */
+ DRIVER_REQUIRE_FIRMWARE,
+ DRIVER_REQUIRE_BEACON_RING,
+
+ /*
+ * Driver configuration
+ */
+ CONFIG_SUPPORT_HW_BUTTON,
+ CONFIG_FRAME_TYPE,
+ CONFIG_RF_SEQUENCE,
+ CONFIG_EXTERNAL_LNA_A,
+ CONFIG_EXTERNAL_LNA_BG,
+ CONFIG_DOUBLE_ANTENNA,
+ CONFIG_DISABLE_LINK_TUNING,
+ CONFIG_SHORT_PREAMBLE,
+};
+
+/*
+ * rt2x00 device structure.
+ */
+struct rt2x00_dev {
+ /*
+ * Device structure.
+ * The structure stored in here depends on the
+ * system bus (PCI or USB).
+ * When accessing this variable, the rt2x00dev_{pci,usb}
+ * macro's should be used for correct typecasting.
+ */
+ void *dev;
+#define rt2x00dev_pci(__dev) ( (struct pci_dev*)(__dev)->dev )
+#define rt2x00dev_usb(__dev) ( (struct usb_interface*)(__dev)->dev )
+
+ /*
+ * Callback functions.
+ */
+ const struct rt2x00_ops *ops;
+
+ /*
+ * IEEE80211 control structure.
+ */
+ struct ieee80211_hw *hw;
+ struct ieee80211_hw_mode *hwmodes;
+ unsigned int curr_hwmode;
+#define HWMODE_B 0
+#define HWMODE_G 1
+#define HWMODE_A 2
+
+ /*
+ * rfkill structure for RF state switching support.
+ * This will only be compiled in when required.
+ */
+#ifdef CONFIG_RT2X00_LIB_RFKILL
+ struct rfkill *rfkill;
+ struct input_polled_dev *poll_dev;
+#endif /* CONFIG_RT2X00_LIB_RFKILL */
+
+ /*
+ * If enabled, the debugfs interface structures
+ * required for deregistration of debugfs.
+ */
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ const struct rt2x00debug_intf *debugfs_intf;
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+ /*
+ * Device flags.
+ * In these flags the current status and some
+ * of the device capabilities are stored.
+ */
+ unsigned long flags;
+
+ /*
+ * Chipset identification.
+ */
+ struct rt2x00_chip chip;
+
+ /*
+ * hw capability specifications.
+ */
+ struct hw_mode_spec spec;
+
+ /*
+ * Register pointers
+ * csr_addr: Base register address. (PCI)
+ * csr_cache: CSR cache for usb_control_msg. (USB)
+ */
+ void __iomem *csr_addr;
+ void *csr_cache;
+
+ /*
+ * Interface configuration.
+ */
+ struct interface interface;
+
+ /*
+ * Link quality
+ */
+ struct link link;
+
+ /*
+ * EEPROM data.
+ */
+ __le16 *eeprom;
+
+ /*
+ * Active RF register values.
+ * These are stored here so we don't need
+ * to read the rf registers and can directly
+ * use this value instead.
+ * This field should be accessed by using
+ * rt2x00_rf_read() and rt2x00_rf_write().
+ */
+ u32 *rf;
+
+ /*
+ * Current TX power value.
+ */
+ u16 tx_power;
+
+ /*
+ * LED register (for rt61pci & rt73usb).
+ */
+ u16 led_reg;
+
+ /*
+ * Led mode (LED_MODE_*)
+ */
+ u8 led_mode;
+
+ /*
+ * Rssi <-> Dbm offset
+ */
+ u8 rssi_offset;
+
+ /*
+ * Frequency offset (for rt61pci & rt73usb).
+ */
+ u8 freq_offset;
+
+ /*
+ * Low level statistics which will have
+ * to be kept up to date while device is running.
+ */
+ struct ieee80211_low_level_stats low_level_stats;
+
+ /*
+ * RX configuration information.
+ */
+ struct ieee80211_rx_status rx_status;
+
+ /*
+ * Scheduled work.
+ */
+ struct work_struct beacon_work;
+ struct work_struct filter_work;
+ struct work_struct config_work;
+
+ /*
+ * Data ring arrays for RX, TX and Beacon.
+ * The Beacon array also contains the Atim ring
+ * if that is supported by the device.
+ */
+ int data_rings;
+ struct data_ring *rx;
+ struct data_ring *tx;
+ struct data_ring *bcn;
+
+ /*
+ * Firmware image.
+ */
+ const struct firmware *fw;
+};
+
+/*
+ * For-each loop for the ring array.
+ * All rings have been allocated as a single array,
+ * this means we can create a very simply loop macro
+ * that is capable of looping through all rings.
+ * ring_end(), txring_end() and ring_loop() are helper macro's which
+ * should not be used directly. Instead the following should be used:
+ * ring_for_each() - Loops through all rings (RX, TX, Beacon & Atim)
+ * txring_for_each() - Loops through TX data rings (TX only)
+ * txringall_for_each() - Loops through all TX rings (TX, Beacon & Atim)
+ */
+#define ring_end(__dev) \
+ &(__dev)->rx[(__dev)->data_rings]
+
+#define txring_end(__dev) \
+ &(__dev)->tx[(__dev)->hw->queues]
+
+#define ring_loop(__entry, __start, __end) \
+ for ((__entry) = (__start); \
+ prefetch(&(__entry)[1]), (__entry) != (__end); \
+ (__entry) = &(__entry)[1])
+
+#define ring_for_each(__dev, __entry) \
+ ring_loop(__entry, (__dev)->rx, ring_end(__dev))
+
+#define txring_for_each(__dev, __entry) \
+ ring_loop(__entry, (__dev)->tx, txring_end(__dev))
+
+#define txringall_for_each(__dev, __entry) \
+ ring_loop(__entry, (__dev)->tx, ring_end(__dev))
+
+/*
+ * Generic RF access.
+ * The RF is being accessed by word index.
+ */
+static inline void rt2x00_rf_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 *data)
+{
+ *data = rt2x00dev->rf[word];
+}
+
+static inline void rt2x00_rf_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 data)
+{
+ rt2x00dev->rf[word] = data;
+}
+
+/*
+ * Generic EEPROM access.
+ * The EEPROM is being accessed by word index.
+ */
+static inline void *rt2x00_eeprom_addr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word)
+{
+ return (void *)&rt2x00dev->eeprom[word];
+}
+
+static inline void rt2x00_eeprom_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u16 *data)
+{
+ *data = le16_to_cpu(rt2x00dev->eeprom[word]);
+}
+
+static inline void rt2x00_eeprom_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u16 data)
+{
+ rt2x00dev->eeprom[word] = cpu_to_le16(data);
+}
+
+/*
+ * Chipset handlers
+ */
+static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev,
+ const u16 rt, const u16 rf, const u32 rev)
+{
+ INFO(rt2x00dev,
+ "Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n",
+ rt, rf, rev);
+
+ rt2x00dev->chip.rt = rt;
+ rt2x00dev->chip.rf = rf;
+ rt2x00dev->chip.rev = rev;
+}
+
+static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip)
+{
+ return (chipset->rt == chip);
+}
+
+static inline char rt2x00_rf(const struct rt2x00_chip *chipset, const u16 chip)
+{
+ return (chipset->rf == chip);
+}
+
+static inline u16 rt2x00_rev(const struct rt2x00_chip *chipset)
+{
+ return chipset->rev;
+}
+
+static inline u16 rt2x00_check_rev(const struct rt2x00_chip *chipset,
+ const u32 rev)
+{
+ return (((chipset->rev & 0xffff0) == rev) &&
+ !!(chipset->rev & 0x0000f));
+}
+
+/*
+ * Duration calculations
+ * The rate variable passed is: 100kbs.
+ * To convert from bytes to bits we multiply size with 8,
+ * then the size is multiplied with 10 to make the
+ * real rate -> rate argument correction.
+ */
+static inline u16 get_duration(const unsigned int size, const u8 rate)
+{
+ return ((size * 8 * 10) / rate);
+}
+
+static inline u16 get_duration_res(const unsigned int size, const u8 rate)
+{
+ return ((size * 8 * 10) % rate);
+}
+
+/*
+ * Library functions.
+ */
+struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev,
+ const unsigned int queue);
+
+/*
+ * Interrupt context handlers.
+ */
+void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_txdone(struct data_entry *entry,
+ const int status, const int retry);
+void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
+ struct rxdata_entry_desc *desc);
+
+/*
+ * TX descriptor initializer
+ */
+void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control);
+
+/*
+ * mac80211 handlers.
+ */
+int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control);
+int rt2x00mac_start(struct ieee80211_hw *hw);
+void rt2x00mac_stop(struct ieee80211_hw *hw);
+int rt2x00mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf);
+void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf);
+int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id,
+ struct ieee80211_if_conf *conf);
+int rt2x00mac_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats);
+int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats);
+void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes,
+ int cts_protection, int preamble);
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
+ const struct ieee80211_tx_queue_params *params);
+
+/*
+ * Driver allocation handlers.
+ */
+int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev);
+#ifdef CONFIG_PM
+int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state);
+int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev);
+#endif /* CONFIG_PM */
+
+#endif /* RT2X00_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
new file mode 100644
index 00000000000..12914cf7156
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -0,0 +1,205 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 generic configuration routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+
+/*
+ * The MAC and BSSID addressess are simple array of bytes,
+ * these arrays are little endian, so when sending the addressess
+ * to the drivers, copy the it into a endian-signed variable.
+ *
+ * Note that all devices (except rt2500usb) have 32 bits
+ * register word sizes. This means that whatever variable we
+ * pass _must_ be a multiple of 32 bits. Otherwise the device
+ * might not accept what we are sending to it.
+ * This will also make it easier for the driver to write
+ * the data to the device.
+ *
+ * Also note that when NULL is passed as address the
+ * we will send 00:00:00:00:00 to the device to clear the address.
+ * This will prevent the device being confused when it wants
+ * to ACK frames or consideres itself associated.
+ */
+void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac)
+{
+ __le32 reg[2];
+
+ memset(&reg, 0, sizeof(reg));
+ if (mac)
+ memcpy(&reg, mac, ETH_ALEN);
+
+ rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, &reg[0]);
+}
+
+void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid)
+{
+ __le32 reg[2];
+
+ memset(&reg, 0, sizeof(reg));
+ if (bssid)
+ memcpy(&reg, bssid, ETH_ALEN);
+
+ rt2x00dev->ops->lib->config_bssid(rt2x00dev, &reg[0]);
+}
+
+void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type)
+{
+ int tsf_sync;
+
+ switch (type) {
+ case IEEE80211_IF_TYPE_IBSS:
+ case IEEE80211_IF_TYPE_AP:
+ tsf_sync = TSF_SYNC_BEACON;
+ break;
+ case IEEE80211_IF_TYPE_STA:
+ tsf_sync = TSF_SYNC_INFRA;
+ break;
+ default:
+ tsf_sync = TSF_SYNC_NONE;
+ break;
+ }
+
+ rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync);
+}
+
+void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf, const int force_config)
+{
+ struct rt2x00lib_conf libconf;
+ struct ieee80211_hw_mode *mode;
+ struct ieee80211_rate *rate;
+ int flags = 0;
+ int short_slot_time;
+
+ /*
+ * In some situations we want to force all configurations
+ * to be reloaded (When resuming for instance).
+ */
+ if (force_config) {
+ flags = CONFIG_UPDATE_ALL;
+ goto config;
+ }
+
+ /*
+ * Check which configuration options have been
+ * updated and should be send to the device.
+ */
+ if (rt2x00dev->rx_status.phymode != conf->phymode)
+ flags |= CONFIG_UPDATE_PHYMODE;
+ if (rt2x00dev->rx_status.channel != conf->channel)
+ flags |= CONFIG_UPDATE_CHANNEL;
+ if (rt2x00dev->tx_power != conf->power_level)
+ flags |= CONFIG_UPDATE_TXPOWER;
+ if (rt2x00dev->rx_status.antenna == conf->antenna_sel_rx)
+ flags |= CONFIG_UPDATE_ANTENNA;
+
+ /*
+ * The following configuration options are never
+ * stored anywhere and will always be updated.
+ */
+ flags |= CONFIG_UPDATE_SLOT_TIME;
+ flags |= CONFIG_UPDATE_BEACON_INT;
+
+ /*
+ * We have determined what options should be updated,
+ * now precalculate device configuration values depending
+ * on what configuration options need to be updated.
+ */
+config:
+ memset(&libconf, 0, sizeof(libconf));
+
+ if (flags & CONFIG_UPDATE_PHYMODE) {
+ switch (conf->phymode) {
+ case MODE_IEEE80211A:
+ libconf.phymode = HWMODE_A;
+ break;
+ case MODE_IEEE80211B:
+ libconf.phymode = HWMODE_B;
+ break;
+ case MODE_IEEE80211G:
+ libconf.phymode = HWMODE_G;
+ break;
+ default:
+ ERROR(rt2x00dev,
+ "Attempt to configure unsupported mode (%d)"
+ "Defaulting to 802.11b", conf->phymode);
+ libconf.phymode = HWMODE_B;
+ }
+
+ mode = &rt2x00dev->hwmodes[libconf.phymode];
+ rate = &mode->rates[mode->num_rates - 1];
+
+ libconf.basic_rates =
+ DEVICE_GET_RATE_FIELD(rate->val, RATEMASK) & DEV_BASIC_RATEMASK;
+ }
+
+ if (flags & CONFIG_UPDATE_CHANNEL) {
+ memcpy(&libconf.rf,
+ &rt2x00dev->spec.channels[conf->channel_val],
+ sizeof(libconf.rf));
+ }
+
+ if (flags & CONFIG_UPDATE_SLOT_TIME) {
+ short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME;
+
+ libconf.slot_time =
+ short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME;
+ libconf.sifs = SIFS;
+ libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS;
+ libconf.difs = short_slot_time ? SHORT_DIFS : DIFS;
+ libconf.eifs = EIFS;
+ }
+
+ libconf.conf = conf;
+
+ /*
+ * Start configuration.
+ */
+ rt2x00dev->ops->lib->config(rt2x00dev, flags, &libconf);
+
+ /*
+ * Some configuration changes affect the link quality
+ * which means we need to reset the link tuner.
+ */
+ if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA))
+ rt2x00lib_reset_link_tuner(rt2x00dev);
+
+ rt2x00dev->curr_hwmode = libconf.phymode;
+ rt2x00dev->rx_status.phymode = conf->phymode;
+ rt2x00dev->rx_status.freq = conf->freq;
+ rt2x00dev->rx_status.channel = conf->channel;
+ rt2x00dev->tx_power = conf->power_level;
+ rt2x00dev->rx_status.antenna = conf->antenna_sel_rx;
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
new file mode 100644
index 00000000000..9275d6f9517
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -0,0 +1,368 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 debugfs specific routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+#define PRINT_LINE_LEN_MAX 32
+
+struct rt2x00debug_intf {
+ /*
+ * Pointer to driver structure where
+ * this debugfs entry belongs to.
+ */
+ struct rt2x00_dev *rt2x00dev;
+
+ /*
+ * Reference to the rt2x00debug structure
+ * which can be used to communicate with
+ * the registers.
+ */
+ const struct rt2x00debug *debug;
+
+ /*
+ * Debugfs entries for:
+ * - driver folder
+ * - driver file
+ * - chipset file
+ * - device flags file
+ * - register offset/value files
+ * - eeprom offset/value files
+ * - bbp offset/value files
+ * - rf offset/value files
+ */
+ struct dentry *driver_folder;
+ struct dentry *driver_entry;
+ struct dentry *chipset_entry;
+ struct dentry *dev_flags;
+ struct dentry *csr_off_entry;
+ struct dentry *csr_val_entry;
+ struct dentry *eeprom_off_entry;
+ struct dentry *eeprom_val_entry;
+ struct dentry *bbp_off_entry;
+ struct dentry *bbp_val_entry;
+ struct dentry *rf_off_entry;
+ struct dentry *rf_val_entry;
+
+ /*
+ * Driver and chipset files will use a data buffer
+ * that has been created in advance. This will simplify
+ * the code since we can use the debugfs functions.
+ */
+ struct debugfs_blob_wrapper driver_blob;
+ struct debugfs_blob_wrapper chipset_blob;
+
+ /*
+ * Requested offset for each register type.
+ */
+ unsigned int offset_csr;
+ unsigned int offset_eeprom;
+ unsigned int offset_bbp;
+ unsigned int offset_rf;
+};
+
+static int rt2x00debug_file_open(struct inode *inode, struct file *file)
+{
+ struct rt2x00debug_intf *intf = inode->i_private;
+
+ file->private_data = inode->i_private;
+
+ if (!try_module_get(intf->debug->owner))
+ return -EBUSY;
+
+ return 0;
+}
+
+static int rt2x00debug_file_release(struct inode *inode, struct file *file)
+{
+ struct rt2x00debug_intf *intf = file->private_data;
+
+ module_put(intf->debug->owner);
+
+ return 0;
+}
+
+#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \
+static ssize_t rt2x00debug_read_##__name(struct file *file, \
+ char __user *buf, \
+ size_t length, \
+ loff_t *offset) \
+{ \
+ struct rt2x00debug_intf *intf = file->private_data; \
+ const struct rt2x00debug *debug = intf->debug; \
+ char line[16]; \
+ size_t size; \
+ __type value; \
+ \
+ if (*offset) \
+ return 0; \
+ \
+ if (intf->offset_##__name >= debug->__name.word_count) \
+ return -EINVAL; \
+ \
+ debug->__name.read(intf->rt2x00dev, \
+ intf->offset_##__name, &value); \
+ \
+ size = sprintf(line, __format, value); \
+ \
+ if (copy_to_user(buf, line, size)) \
+ return -EFAULT; \
+ \
+ *offset += size; \
+ return size; \
+}
+
+#define RT2X00DEBUGFS_OPS_WRITE(__name, __type) \
+static ssize_t rt2x00debug_write_##__name(struct file *file, \
+ const char __user *buf,\
+ size_t length, \
+ loff_t *offset) \
+{ \
+ struct rt2x00debug_intf *intf = file->private_data; \
+ const struct rt2x00debug *debug = intf->debug; \
+ char line[16]; \
+ size_t size; \
+ __type value; \
+ \
+ if (*offset) \
+ return 0; \
+ \
+ if (!capable(CAP_NET_ADMIN)) \
+ return -EPERM; \
+ \
+ if (intf->offset_##__name >= debug->__name.word_count) \
+ return -EINVAL; \
+ \
+ if (copy_from_user(line, buf, length)) \
+ return -EFAULT; \
+ \
+ size = strlen(line); \
+ value = simple_strtoul(line, NULL, 0); \
+ \
+ debug->__name.write(intf->rt2x00dev, \
+ intf->offset_##__name, value); \
+ \
+ *offset += size; \
+ return size; \
+}
+
+#define RT2X00DEBUGFS_OPS(__name, __format, __type) \
+RT2X00DEBUGFS_OPS_READ(__name, __format, __type); \
+RT2X00DEBUGFS_OPS_WRITE(__name, __type); \
+ \
+static const struct file_operations rt2x00debug_fop_##__name = {\
+ .owner = THIS_MODULE, \
+ .read = rt2x00debug_read_##__name, \
+ .write = rt2x00debug_write_##__name, \
+ .open = rt2x00debug_file_open, \
+ .release = rt2x00debug_file_release, \
+};
+
+RT2X00DEBUGFS_OPS(csr, "0x%.8x\n", u32);
+RT2X00DEBUGFS_OPS(eeprom, "0x%.4x\n", u16);
+RT2X00DEBUGFS_OPS(bbp, "0x%.2x\n", u8);
+RT2X00DEBUGFS_OPS(rf, "0x%.8x\n", u32);
+
+static ssize_t rt2x00debug_read_dev_flags(struct file *file,
+ char __user *buf,
+ size_t length,
+ loff_t *offset)
+{
+ struct rt2x00debug_intf *intf = file->private_data;
+ char line[16];
+ size_t size;
+
+ if (*offset)
+ return 0;
+
+ size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->flags);
+
+ if (copy_to_user(buf, line, size))
+ return -EFAULT;
+
+ *offset += size;
+ return size;
+}
+
+static const struct file_operations rt2x00debug_fop_dev_flags = {
+ .owner = THIS_MODULE,
+ .read = rt2x00debug_read_dev_flags,
+ .open = rt2x00debug_file_open,
+ .release = rt2x00debug_file_release,
+};
+
+static struct dentry *rt2x00debug_create_file_driver(const char *name,
+ struct rt2x00debug_intf
+ *intf,
+ struct debugfs_blob_wrapper
+ *blob)
+{
+ char *data;
+
+ data = kzalloc(3 * PRINT_LINE_LEN_MAX, GFP_KERNEL);
+ if (!data)
+ return NULL;
+
+ blob->data = data;
+ data += sprintf(data, "driver: %s\n", intf->rt2x00dev->ops->name);
+ data += sprintf(data, "version: %s\n", DRV_VERSION);
+ data += sprintf(data, "compiled: %s %s\n", __DATE__, __TIME__);
+ blob->size = strlen(blob->data);
+
+ return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob);
+}
+
+static struct dentry *rt2x00debug_create_file_chipset(const char *name,
+ struct rt2x00debug_intf
+ *intf,
+ struct
+ debugfs_blob_wrapper
+ *blob)
+{
+ const struct rt2x00debug *debug = intf->debug;
+ char *data;
+
+ data = kzalloc(4 * PRINT_LINE_LEN_MAX, GFP_KERNEL);
+ if (!data)
+ return NULL;
+
+ blob->data = data;
+ data += sprintf(data, "csr length: %d\n", debug->csr.word_count);
+ data += sprintf(data, "eeprom length: %d\n", debug->eeprom.word_count);
+ data += sprintf(data, "bbp length: %d\n", debug->bbp.word_count);
+ data += sprintf(data, "rf length: %d\n", debug->rf.word_count);
+ blob->size = strlen(blob->data);
+
+ return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob);
+}
+
+void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
+{
+ const struct rt2x00debug *debug = rt2x00dev->ops->debugfs;
+ struct rt2x00debug_intf *intf;
+
+ intf = kzalloc(sizeof(struct rt2x00debug_intf), GFP_KERNEL);
+ if (!intf) {
+ ERROR(rt2x00dev, "Failed to allocate debug handler.\n");
+ return;
+ }
+
+ intf->debug = debug;
+ intf->rt2x00dev = rt2x00dev;
+ rt2x00dev->debugfs_intf = intf;
+
+ intf->driver_folder =
+ debugfs_create_dir(intf->rt2x00dev->ops->name,
+ rt2x00dev->hw->wiphy->debugfsdir);
+ if (IS_ERR(intf->driver_folder))
+ goto exit;
+
+ intf->driver_entry =
+ rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob);
+ if (IS_ERR(intf->driver_entry))
+ goto exit;
+
+ intf->chipset_entry =
+ rt2x00debug_create_file_chipset("chipset",
+ intf, &intf->chipset_blob);
+ if (IS_ERR(intf->chipset_entry))
+ goto exit;
+
+ intf->dev_flags = debugfs_create_file("dev_flags", S_IRUGO,
+ intf->driver_folder, intf,
+ &rt2x00debug_fop_dev_flags);
+ if (IS_ERR(intf->dev_flags))
+ goto exit;
+
+#define RT2X00DEBUGFS_CREATE_ENTRY(__intf, __name) \
+({ \
+ (__intf)->__name##_off_entry = \
+ debugfs_create_u32(__stringify(__name) "_offset", \
+ S_IRUGO | S_IWUSR, \
+ (__intf)->driver_folder, \
+ &(__intf)->offset_##__name); \
+ if (IS_ERR((__intf)->__name##_off_entry)) \
+ goto exit; \
+ \
+ (__intf)->__name##_val_entry = \
+ debugfs_create_file(__stringify(__name) "_value", \
+ S_IRUGO | S_IWUSR, \
+ (__intf)->driver_folder, \
+ (__intf), &rt2x00debug_fop_##__name);\
+ if (IS_ERR((__intf)->__name##_val_entry)) \
+ goto exit; \
+})
+
+ RT2X00DEBUGFS_CREATE_ENTRY(intf, csr);
+ RT2X00DEBUGFS_CREATE_ENTRY(intf, eeprom);
+ RT2X00DEBUGFS_CREATE_ENTRY(intf, bbp);
+ RT2X00DEBUGFS_CREATE_ENTRY(intf, rf);
+
+#undef RT2X00DEBUGFS_CREATE_ENTRY
+
+ return;
+
+exit:
+ rt2x00debug_deregister(rt2x00dev);
+ ERROR(rt2x00dev, "Failed to register debug handler.\n");
+
+ return;
+}
+
+void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
+{
+ const struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
+
+ if (unlikely(!intf))
+ return;
+
+ debugfs_remove(intf->rf_val_entry);
+ debugfs_remove(intf->rf_off_entry);
+ debugfs_remove(intf->bbp_val_entry);
+ debugfs_remove(intf->bbp_off_entry);
+ debugfs_remove(intf->eeprom_val_entry);
+ debugfs_remove(intf->eeprom_off_entry);
+ debugfs_remove(intf->csr_val_entry);
+ debugfs_remove(intf->csr_off_entry);
+ debugfs_remove(intf->dev_flags);
+ debugfs_remove(intf->chipset_entry);
+ debugfs_remove(intf->driver_entry);
+ debugfs_remove(intf->driver_folder);
+ kfree(intf->chipset_blob.data);
+ kfree(intf->driver_blob.data);
+ kfree(intf);
+
+ rt2x00dev->debugfs_intf = NULL;
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h
new file mode 100644
index 00000000000..860e8fa3a0d
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00debug
+ Abstract: Data structures for the rt2x00debug.
+ */
+
+#ifndef RT2X00DEBUG_H
+#define RT2X00DEBUG_H
+
+struct rt2x00_dev;
+
+#define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \
+struct reg##__name { \
+ void (*read)(const struct rt2x00_dev *rt2x00dev, \
+ const unsigned int word, __type *data); \
+ void (*write)(const struct rt2x00_dev *rt2x00dev, \
+ const unsigned int word, __type data); \
+ \
+ unsigned int word_size; \
+ unsigned int word_count; \
+} __name
+
+struct rt2x00debug {
+ /*
+ * Reference to the modules structure.
+ */
+ struct module *owner;
+
+ /*
+ * Register access entries.
+ */
+ RT2X00DEBUGFS_REGISTER_ENTRY(csr, u32);
+ RT2X00DEBUGFS_REGISTER_ENTRY(eeprom, u16);
+ RT2X00DEBUGFS_REGISTER_ENTRY(bbp, u8);
+ RT2X00DEBUGFS_REGISTER_ENTRY(rf, u32);
+};
+
+#endif /* RT2X00DEBUG_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
new file mode 100644
index 00000000000..ff399f8083e
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -0,0 +1,1202 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 generic device routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+/*
+ * Ring handler.
+ */
+struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev,
+ const unsigned int queue)
+{
+ int beacon = test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+
+ /*
+ * Check if we are requesting a reqular TX ring,
+ * or if we are requesting a Beacon or Atim ring.
+ * For Atim rings, we should check if it is supported.
+ */
+ if (queue < rt2x00dev->hw->queues && rt2x00dev->tx)
+ return &rt2x00dev->tx[queue];
+
+ if (!rt2x00dev->bcn || !beacon)
+ return NULL;
+
+ if (queue == IEEE80211_TX_QUEUE_BEACON)
+ return &rt2x00dev->bcn[0];
+ else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+ return &rt2x00dev->bcn[1];
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_get_ring);
+
+/*
+ * Link tuning handlers
+ */
+static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ rt2x00_clear_link(&rt2x00dev->link);
+
+ /*
+ * Reset the link tuner.
+ */
+ rt2x00dev->ops->lib->reset_tuner(rt2x00dev);
+
+ queue_delayed_work(rt2x00dev->hw->workqueue,
+ &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
+}
+
+static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ cancel_delayed_work_sync(&rt2x00dev->link.work);
+}
+
+void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ rt2x00lib_stop_link_tuner(rt2x00dev);
+ rt2x00lib_start_link_tuner(rt2x00dev);
+}
+
+/*
+ * Radio control handlers.
+ */
+int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ int status;
+
+ /*
+ * Don't enable the radio twice.
+ * And check if the hardware button has been disabled.
+ */
+ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+ test_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * Enable radio.
+ */
+ status = rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+ STATE_RADIO_ON);
+ if (status)
+ return status;
+
+ __set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags);
+
+ /*
+ * Enable RX.
+ */
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+
+ /*
+ * Start the TX queues.
+ */
+ ieee80211_start_queues(rt2x00dev->hw);
+
+ return 0;
+}
+
+void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ /*
+ * Stop all scheduled work.
+ */
+ if (work_pending(&rt2x00dev->beacon_work))
+ cancel_work_sync(&rt2x00dev->beacon_work);
+ if (work_pending(&rt2x00dev->filter_work))
+ cancel_work_sync(&rt2x00dev->filter_work);
+ if (work_pending(&rt2x00dev->config_work))
+ cancel_work_sync(&rt2x00dev->config_work);
+
+ /*
+ * Stop the TX queues.
+ */
+ ieee80211_stop_queues(rt2x00dev->hw);
+
+ /*
+ * Disable RX.
+ */
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
+
+ /*
+ * Disable radio.
+ */
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_OFF);
+}
+
+void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state)
+{
+ /*
+ * When we are disabling the RX, we should also stop the link tuner.
+ */
+ if (state == STATE_RADIO_RX_OFF)
+ rt2x00lib_stop_link_tuner(rt2x00dev);
+
+ rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
+
+ /*
+ * When we are enabling the RX, we should also start the link tuner.
+ */
+ if (state == STATE_RADIO_RX_ON &&
+ is_interface_present(&rt2x00dev->interface))
+ rt2x00lib_start_link_tuner(rt2x00dev);
+}
+
+static void rt2x00lib_precalculate_link_signal(struct link *link)
+{
+ if (link->rx_failed || link->rx_success)
+ link->rx_percentage =
+ (link->rx_success * 100) /
+ (link->rx_failed + link->rx_success);
+ else
+ link->rx_percentage = 50;
+
+ if (link->tx_failed || link->tx_success)
+ link->tx_percentage =
+ (link->tx_success * 100) /
+ (link->tx_failed + link->tx_success);
+ else
+ link->tx_percentage = 50;
+
+ link->rx_success = 0;
+ link->rx_failed = 0;
+ link->tx_success = 0;
+ link->tx_failed = 0;
+}
+
+static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev,
+ int rssi)
+{
+ int rssi_percentage = 0;
+ int signal;
+
+ /*
+ * We need a positive value for the RSSI.
+ */
+ if (rssi < 0)
+ rssi += rt2x00dev->rssi_offset;
+
+ /*
+ * Calculate the different percentages,
+ * which will be used for the signal.
+ */
+ if (rt2x00dev->rssi_offset)
+ rssi_percentage = (rssi * 100) / rt2x00dev->rssi_offset;
+
+ /*
+ * Add the individual percentages and use the WEIGHT
+ * defines to calculate the current link signal.
+ */
+ signal = ((WEIGHT_RSSI * rssi_percentage) +
+ (WEIGHT_TX * rt2x00dev->link.tx_percentage) +
+ (WEIGHT_RX * rt2x00dev->link.rx_percentage)) / 100;
+
+ return (signal > 100) ? 100 : signal;
+}
+
+static void rt2x00lib_link_tuner(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, link.work.work);
+
+ /*
+ * When the radio is shutting down we should
+ * immediately cease all link tuning.
+ */
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ /*
+ * Update statistics.
+ */
+ rt2x00dev->ops->lib->link_stats(rt2x00dev);
+
+ rt2x00dev->low_level_stats.dot11FCSErrorCount +=
+ rt2x00dev->link.rx_failed;
+
+ /*
+ * Only perform the link tuning when Link tuning
+ * has been enabled (This could have been disabled from the EEPROM).
+ */
+ if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
+ rt2x00dev->ops->lib->link_tuner(rt2x00dev);
+
+ /*
+ * Precalculate a portion of the link signal which is
+ * in based on the tx/rx success/failure counters.
+ */
+ rt2x00lib_precalculate_link_signal(&rt2x00dev->link);
+
+ /*
+ * Increase tuner counter, and reschedule the next link tuner run.
+ */
+ rt2x00dev->link.count++;
+ queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work,
+ LINK_TUNE_INTERVAL);
+}
+
+static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, filter_work);
+ unsigned int filter = rt2x00dev->interface.filter;
+
+ /*
+ * Since we had stored the filter inside interface.filter,
+ * we should now clear that field. Otherwise the driver will
+ * assume nothing has changed (*total_flags will be compared
+ * to interface.filter to determine if any action is required).
+ */
+ rt2x00dev->interface.filter = 0;
+
+ rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw,
+ filter, &filter, 0, NULL);
+}
+
+static void rt2x00lib_configuration_scheduled(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, config_work);
+ int preamble = !test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+
+ rt2x00mac_erp_ie_changed(rt2x00dev->hw,
+ IEEE80211_ERP_CHANGE_PREAMBLE, 0, preamble);
+}
+
+/*
+ * Interrupt context handlers.
+ */
+static void rt2x00lib_beacondone_scheduled(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, beacon_work);
+ struct data_ring *ring =
+ rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+ struct data_entry *entry = rt2x00_get_data_entry(ring);
+ struct sk_buff *skb;
+
+ skb = ieee80211_beacon_get(rt2x00dev->hw,
+ rt2x00dev->interface.id,
+ &entry->tx_status.control);
+ if (!skb)
+ return;
+
+ rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb,
+ &entry->tx_status.control);
+
+ dev_kfree_skb(skb);
+}
+
+void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
+{
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return;
+
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->beacon_work);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
+
+void rt2x00lib_txdone(struct data_entry *entry,
+ const int status, const int retry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev;
+ struct ieee80211_tx_status *tx_status = &entry->tx_status;
+ struct ieee80211_low_level_stats *stats = &rt2x00dev->low_level_stats;
+ int success = !!(status == TX_SUCCESS || status == TX_SUCCESS_RETRY);
+ int fail = !!(status == TX_FAIL_RETRY || status == TX_FAIL_INVALID ||
+ status == TX_FAIL_OTHER);
+
+ /*
+ * Update TX statistics.
+ */
+ tx_status->flags = 0;
+ tx_status->ack_signal = 0;
+ tx_status->excessive_retries = (status == TX_FAIL_RETRY);
+ tx_status->retry_count = retry;
+ rt2x00dev->link.tx_success += success;
+ rt2x00dev->link.tx_failed += retry + fail;
+
+ if (!(tx_status->control.flags & IEEE80211_TXCTL_NO_ACK)) {
+ if (success)
+ tx_status->flags |= IEEE80211_TX_STATUS_ACK;
+ else
+ stats->dot11ACKFailureCount++;
+ }
+
+ tx_status->queue_length = entry->ring->stats.limit;
+ tx_status->queue_number = tx_status->control.queue;
+
+ if (tx_status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+ if (success)
+ stats->dot11RTSSuccessCount++;
+ else
+ stats->dot11RTSFailureCount++;
+ }
+
+ /*
+ * Send the tx_status to mac80211,
+ * that method also cleans up the skb structure.
+ */
+ ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, tx_status);
+ entry->skb = NULL;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
+
+void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
+ struct rxdata_entry_desc *desc)
+{
+ struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev;
+ struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
+ struct ieee80211_hw_mode *mode;
+ struct ieee80211_rate *rate;
+ unsigned int i;
+ int val = 0;
+
+ /*
+ * Update RX statistics.
+ */
+ mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode];
+ for (i = 0; i < mode->num_rates; i++) {
+ rate = &mode->rates[i];
+
+ /*
+ * When frame was received with an OFDM bitrate,
+ * the signal is the PLCP value. If it was received with
+ * a CCK bitrate the signal is the rate in 0.5kbit/s.
+ */
+ if (!desc->ofdm)
+ val = DEVICE_GET_RATE_FIELD(rate->val, RATE);
+ else
+ val = DEVICE_GET_RATE_FIELD(rate->val, PLCP);
+
+ if (val == desc->signal) {
+ val = rate->val;
+ break;
+ }
+ }
+
+ rt2x00_update_link_rssi(&rt2x00dev->link, desc->rssi);
+ rt2x00dev->link.rx_success++;
+ rx_status->rate = val;
+ rx_status->signal =
+ rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi);
+ rx_status->ssi = desc->rssi;
+ rx_status->flag = desc->flags;
+
+ /*
+ * Send frame to mac80211
+ */
+ ieee80211_rx_irqsafe(rt2x00dev->hw, skb, rx_status);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
+
+/*
+ * TX descriptor initializer
+ */
+void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control)
+{
+ struct txdata_entry_desc desc;
+ struct data_ring *ring;
+ int tx_rate;
+ int bitrate;
+ int duration;
+ int residual;
+ u16 frame_control;
+ u16 seq_ctrl;
+
+ /*
+ * Make sure the descriptor is properly cleared.
+ */
+ memset(&desc, 0x00, sizeof(desc));
+
+ /*
+ * Get ring pointer, if we fail to obtain the
+ * correct ring, then use the first TX ring.
+ */
+ ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
+ if (!ring)
+ ring = rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+
+ desc.cw_min = ring->tx_params.cw_min;
+ desc.cw_max = ring->tx_params.cw_max;
+ desc.aifs = ring->tx_params.aifs;
+
+ /*
+ * Identify queue
+ */
+ if (control->queue < rt2x00dev->hw->queues)
+ desc.queue = control->queue;
+ else if (control->queue == IEEE80211_TX_QUEUE_BEACON ||
+ control->queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+ desc.queue = QUEUE_MGMT;
+ else
+ desc.queue = QUEUE_OTHER;
+
+ /*
+ * Read required fields from ieee80211 header.
+ */
+ frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+ seq_ctrl = le16_to_cpu(ieee80211hdr->seq_ctrl);
+
+ tx_rate = control->tx_rate;
+
+ /*
+ * Check if this is a RTS/CTS frame
+ */
+ if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
+ __set_bit(ENTRY_TXD_BURST, &desc.flags);
+ if (is_rts_frame(frame_control))
+ __set_bit(ENTRY_TXD_RTS_FRAME, &desc.flags);
+ if (control->rts_cts_rate)
+ tx_rate = control->rts_cts_rate;
+ }
+
+ /*
+ * Check for OFDM
+ */
+ if (DEVICE_GET_RATE_FIELD(tx_rate, RATEMASK) & DEV_OFDM_RATEMASK)
+ __set_bit(ENTRY_TXD_OFDM_RATE, &desc.flags);
+
+ /*
+ * Check if more fragments are pending
+ */
+ if (ieee80211_get_morefrag(ieee80211hdr)) {
+ __set_bit(ENTRY_TXD_BURST, &desc.flags);
+ __set_bit(ENTRY_TXD_MORE_FRAG, &desc.flags);
+ }
+
+ /*
+ * Beacons and probe responses require the tsf timestamp
+ * to be inserted into the frame.
+ */
+ if (control->queue == IEEE80211_TX_QUEUE_BEACON ||
+ is_probe_resp(frame_control))
+ __set_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc.flags);
+
+ /*
+ * Determine with what IFS priority this frame should be send.
+ * Set ifs to IFS_SIFS when the this is not the first fragment,
+ * or this fragment came after RTS/CTS.
+ */
+ if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 ||
+ test_bit(ENTRY_TXD_RTS_FRAME, &desc.flags))
+ desc.ifs = IFS_SIFS;
+ else
+ desc.ifs = IFS_BACKOFF;
+
+ /*
+ * PLCP setup
+ * Length calculation depends on OFDM/CCK rate.
+ */
+ desc.signal = DEVICE_GET_RATE_FIELD(tx_rate, PLCP);
+ desc.service = 0x04;
+
+ if (test_bit(ENTRY_TXD_OFDM_RATE, &desc.flags)) {
+ desc.length_high = ((length + FCS_LEN) >> 6) & 0x3f;
+ desc.length_low = ((length + FCS_LEN) & 0x3f);
+ } else {
+ bitrate = DEVICE_GET_RATE_FIELD(tx_rate, RATE);
+
+ /*
+ * Convert length to microseconds.
+ */
+ residual = get_duration_res(length + FCS_LEN, bitrate);
+ duration = get_duration(length + FCS_LEN, bitrate);
+
+ if (residual != 0) {
+ duration++;
+
+ /*
+ * Check if we need to set the Length Extension
+ */
+ if (bitrate == 110 && residual <= 30)
+ desc.service |= 0x80;
+ }
+
+ desc.length_high = (duration >> 8) & 0xff;
+ desc.length_low = duration & 0xff;
+
+ /*
+ * When preamble is enabled we should set the
+ * preamble bit for the signal.
+ */
+ if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE))
+ desc.signal |= 0x08;
+ }
+
+ rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, txd, &desc,
+ ieee80211hdr, length, control);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc);
+
+/*
+ * Driver initialization handlers.
+ */
+static void rt2x00lib_channel(struct ieee80211_channel *entry,
+ const int channel, const int tx_power,
+ const int value)
+{
+ entry->chan = channel;
+ if (channel <= 14)
+ entry->freq = 2407 + (5 * channel);
+ else
+ entry->freq = 5000 + (5 * channel);
+ entry->val = value;
+ entry->flag =
+ IEEE80211_CHAN_W_IBSS |
+ IEEE80211_CHAN_W_ACTIVE_SCAN |
+ IEEE80211_CHAN_W_SCAN;
+ entry->power_level = tx_power;
+ entry->antenna_max = 0xff;
+}
+
+static void rt2x00lib_rate(struct ieee80211_rate *entry,
+ const int rate, const int mask,
+ const int plcp, const int flags)
+{
+ entry->rate = rate;
+ entry->val =
+ DEVICE_SET_RATE_FIELD(rate, RATE) |
+ DEVICE_SET_RATE_FIELD(mask, RATEMASK) |
+ DEVICE_SET_RATE_FIELD(plcp, PLCP);
+ entry->flags = flags;
+ entry->val2 = entry->val;
+ if (entry->flags & IEEE80211_RATE_PREAMBLE2)
+ entry->val2 |= DEVICE_SET_RATE_FIELD(1, PREAMBLE);
+ entry->min_rssi_ack = 0;
+ entry->min_rssi_ack_delta = 0;
+}
+
+static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
+ struct hw_mode_spec *spec)
+{
+ struct ieee80211_hw *hw = rt2x00dev->hw;
+ struct ieee80211_hw_mode *hwmodes;
+ struct ieee80211_channel *channels;
+ struct ieee80211_rate *rates;
+ unsigned int i;
+ unsigned char tx_power;
+
+ hwmodes = kzalloc(sizeof(*hwmodes) * spec->num_modes, GFP_KERNEL);
+ if (!hwmodes)
+ goto exit;
+
+ channels = kzalloc(sizeof(*channels) * spec->num_channels, GFP_KERNEL);
+ if (!channels)
+ goto exit_free_modes;
+
+ rates = kzalloc(sizeof(*rates) * spec->num_rates, GFP_KERNEL);
+ if (!rates)
+ goto exit_free_channels;
+
+ /*
+ * Initialize Rate list.
+ */
+ rt2x00lib_rate(&rates[0], 10, DEV_RATEMASK_1MB,
+ 0x00, IEEE80211_RATE_CCK);
+ rt2x00lib_rate(&rates[1], 20, DEV_RATEMASK_2MB,
+ 0x01, IEEE80211_RATE_CCK_2);
+ rt2x00lib_rate(&rates[2], 55, DEV_RATEMASK_5_5MB,
+ 0x02, IEEE80211_RATE_CCK_2);
+ rt2x00lib_rate(&rates[3], 110, DEV_RATEMASK_11MB,
+ 0x03, IEEE80211_RATE_CCK_2);
+
+ if (spec->num_rates > 4) {
+ rt2x00lib_rate(&rates[4], 60, DEV_RATEMASK_6MB,
+ 0x0b, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[5], 90, DEV_RATEMASK_9MB,
+ 0x0f, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[6], 120, DEV_RATEMASK_12MB,
+ 0x0a, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[7], 180, DEV_RATEMASK_18MB,
+ 0x0e, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[8], 240, DEV_RATEMASK_24MB,
+ 0x09, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[9], 360, DEV_RATEMASK_36MB,
+ 0x0d, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[10], 480, DEV_RATEMASK_48MB,
+ 0x08, IEEE80211_RATE_OFDM);
+ rt2x00lib_rate(&rates[11], 540, DEV_RATEMASK_54MB,
+ 0x0c, IEEE80211_RATE_OFDM);
+ }
+
+ /*
+ * Initialize Channel list.
+ */
+ for (i = 0; i < spec->num_channels; i++) {
+ if (spec->channels[i].channel <= 14)
+ tx_power = spec->tx_power_bg[i];
+ else if (spec->tx_power_a)
+ tx_power = spec->tx_power_a[i];
+ else
+ tx_power = spec->tx_power_default;
+
+ rt2x00lib_channel(&channels[i],
+ spec->channels[i].channel, tx_power, i);
+ }
+
+ /*
+ * Intitialize 802.11b
+ * Rates: CCK.
+ * Channels: OFDM.
+ */
+ if (spec->num_modes > HWMODE_B) {
+ hwmodes[HWMODE_B].mode = MODE_IEEE80211B;
+ hwmodes[HWMODE_B].num_channels = 14;
+ hwmodes[HWMODE_B].num_rates = 4;
+ hwmodes[HWMODE_B].channels = channels;
+ hwmodes[HWMODE_B].rates = rates;
+ }
+
+ /*
+ * Intitialize 802.11g
+ * Rates: CCK, OFDM.
+ * Channels: OFDM.
+ */
+ if (spec->num_modes > HWMODE_G) {
+ hwmodes[HWMODE_G].mode = MODE_IEEE80211G;
+ hwmodes[HWMODE_G].num_channels = 14;
+ hwmodes[HWMODE_G].num_rates = spec->num_rates;
+ hwmodes[HWMODE_G].channels = channels;
+ hwmodes[HWMODE_G].rates = rates;
+ }
+
+ /*
+ * Intitialize 802.11a
+ * Rates: OFDM.
+ * Channels: OFDM, UNII, HiperLAN2.
+ */
+ if (spec->num_modes > HWMODE_A) {
+ hwmodes[HWMODE_A].mode = MODE_IEEE80211A;
+ hwmodes[HWMODE_A].num_channels = spec->num_channels - 14;
+ hwmodes[HWMODE_A].num_rates = spec->num_rates - 4;
+ hwmodes[HWMODE_A].channels = &channels[14];
+ hwmodes[HWMODE_A].rates = &rates[4];
+ }
+
+ if (spec->num_modes > HWMODE_G &&
+ ieee80211_register_hwmode(hw, &hwmodes[HWMODE_G]))
+ goto exit_free_rates;
+
+ if (spec->num_modes > HWMODE_B &&
+ ieee80211_register_hwmode(hw, &hwmodes[HWMODE_B]))
+ goto exit_free_rates;
+
+ if (spec->num_modes > HWMODE_A &&
+ ieee80211_register_hwmode(hw, &hwmodes[HWMODE_A]))
+ goto exit_free_rates;
+
+ rt2x00dev->hwmodes = hwmodes;
+
+ return 0;
+
+exit_free_rates:
+ kfree(rates);
+
+exit_free_channels:
+ kfree(channels);
+
+exit_free_modes:
+ kfree(hwmodes);
+
+exit:
+ ERROR(rt2x00dev, "Allocation ieee80211 modes failed.\n");
+ return -ENOMEM;
+}
+
+static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev)
+{
+ if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags))
+ ieee80211_unregister_hw(rt2x00dev->hw);
+
+ if (likely(rt2x00dev->hwmodes)) {
+ kfree(rt2x00dev->hwmodes->channels);
+ kfree(rt2x00dev->hwmodes->rates);
+ kfree(rt2x00dev->hwmodes);
+ rt2x00dev->hwmodes = NULL;
+ }
+}
+
+static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ int status;
+
+ /*
+ * Initialize HW modes.
+ */
+ status = rt2x00lib_probe_hw_modes(rt2x00dev, spec);
+ if (status)
+ return status;
+
+ /*
+ * Register HW.
+ */
+ status = ieee80211_register_hw(rt2x00dev->hw);
+ if (status) {
+ rt2x00lib_remove_hw(rt2x00dev);
+ return status;
+ }
+
+ __set_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags);
+
+ return 0;
+}
+
+/*
+ * Initialization/uninitialization handlers.
+ */
+static int rt2x00lib_alloc_entries(struct data_ring *ring,
+ const u16 max_entries, const u16 data_size,
+ const u16 desc_size)
+{
+ struct data_entry *entry;
+ unsigned int i;
+
+ ring->stats.limit = max_entries;
+ ring->data_size = data_size;
+ ring->desc_size = desc_size;
+
+ /*
+ * Allocate all ring entries.
+ */
+ entry = kzalloc(ring->stats.limit * sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ entry[i].flags = 0;
+ entry[i].ring = ring;
+ entry[i].skb = NULL;
+ }
+
+ ring->entry = entry;
+
+ return 0;
+}
+
+static int rt2x00lib_alloc_ring_entries(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+
+ /*
+ * Allocate the RX ring.
+ */
+ if (rt2x00lib_alloc_entries(rt2x00dev->rx, RX_ENTRIES, DATA_FRAME_SIZE,
+ rt2x00dev->ops->rxd_size))
+ return -ENOMEM;
+
+ /*
+ * First allocate the TX rings.
+ */
+ txring_for_each(rt2x00dev, ring) {
+ if (rt2x00lib_alloc_entries(ring, TX_ENTRIES, DATA_FRAME_SIZE,
+ rt2x00dev->ops->txd_size))
+ return -ENOMEM;
+ }
+
+ if (!test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * Allocate the BEACON ring.
+ */
+ if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[0], BEACON_ENTRIES,
+ MGMT_FRAME_SIZE, rt2x00dev->ops->txd_size))
+ return -ENOMEM;
+
+ /*
+ * Allocate the Atim ring.
+ */
+ if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[1], ATIM_ENTRIES,
+ DATA_FRAME_SIZE, rt2x00dev->ops->txd_size))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void rt2x00lib_free_ring_entries(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+
+ ring_for_each(rt2x00dev, ring) {
+ kfree(ring->entry);
+ ring->entry = NULL;
+ }
+}
+
+void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
+{
+ if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
+ return;
+
+ /*
+ * Unregister rfkill.
+ */
+ rt2x00rfkill_unregister(rt2x00dev);
+
+ /*
+ * Allow the HW to uninitialize.
+ */
+ rt2x00dev->ops->lib->uninitialize(rt2x00dev);
+
+ /*
+ * Free allocated ring entries.
+ */
+ rt2x00lib_free_ring_entries(rt2x00dev);
+}
+
+int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
+{
+ int status;
+
+ if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * Allocate all ring entries.
+ */
+ status = rt2x00lib_alloc_ring_entries(rt2x00dev);
+ if (status) {
+ ERROR(rt2x00dev, "Ring entries allocation failed.\n");
+ return status;
+ }
+
+ /*
+ * Initialize the device.
+ */
+ status = rt2x00dev->ops->lib->initialize(rt2x00dev);
+ if (status)
+ goto exit;
+
+ __set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags);
+
+ /*
+ * Register the rfkill handler.
+ */
+ status = rt2x00rfkill_register(rt2x00dev);
+ if (status)
+ goto exit_unitialize;
+
+ return 0;
+
+exit_unitialize:
+ rt2x00lib_uninitialize(rt2x00dev);
+
+exit:
+ rt2x00lib_free_ring_entries(rt2x00dev);
+
+ return status;
+}
+
+/*
+ * driver allocation handlers.
+ */
+static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+
+ /*
+ * We need the following rings:
+ * RX: 1
+ * TX: hw->queues
+ * Beacon: 1 (if required)
+ * Atim: 1 (if required)
+ */
+ rt2x00dev->data_rings = 1 + rt2x00dev->hw->queues +
+ (2 * test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags));
+
+ ring = kzalloc(rt2x00dev->data_rings * sizeof(*ring), GFP_KERNEL);
+ if (!ring) {
+ ERROR(rt2x00dev, "Ring allocation failed.\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * Initialize pointers
+ */
+ rt2x00dev->rx = ring;
+ rt2x00dev->tx = &rt2x00dev->rx[1];
+ if (test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags))
+ rt2x00dev->bcn = &rt2x00dev->tx[rt2x00dev->hw->queues];
+
+ /*
+ * Initialize ring parameters.
+ * cw_min: 2^5 = 32.
+ * cw_max: 2^10 = 1024.
+ */
+ ring_for_each(rt2x00dev, ring) {
+ ring->rt2x00dev = rt2x00dev;
+ ring->tx_params.aifs = 2;
+ ring->tx_params.cw_min = 5;
+ ring->tx_params.cw_max = 10;
+ }
+
+ return 0;
+}
+
+static void rt2x00lib_free_rings(struct rt2x00_dev *rt2x00dev)
+{
+ kfree(rt2x00dev->rx);
+ rt2x00dev->rx = NULL;
+ rt2x00dev->tx = NULL;
+ rt2x00dev->bcn = NULL;
+}
+
+int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
+{
+ int retval = -ENOMEM;
+
+ /*
+ * Let the driver probe the device to detect the capabilities.
+ */
+ retval = rt2x00dev->ops->lib->probe_hw(rt2x00dev);
+ if (retval) {
+ ERROR(rt2x00dev, "Failed to allocate device.\n");
+ goto exit;
+ }
+
+ /*
+ * Initialize configuration work.
+ */
+ INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled);
+ INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
+ INIT_WORK(&rt2x00dev->config_work, rt2x00lib_configuration_scheduled);
+ INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
+
+ /*
+ * Reset current working type.
+ */
+ rt2x00dev->interface.type = INVALID_INTERFACE;
+
+ /*
+ * Allocate ring array.
+ */
+ retval = rt2x00lib_alloc_rings(rt2x00dev);
+ if (retval)
+ goto exit;
+
+ /*
+ * Initialize ieee80211 structure.
+ */
+ retval = rt2x00lib_probe_hw(rt2x00dev);
+ if (retval) {
+ ERROR(rt2x00dev, "Failed to initialize hw.\n");
+ goto exit;
+ }
+
+ /*
+ * Allocatie rfkill.
+ */
+ retval = rt2x00rfkill_allocate(rt2x00dev);
+ if (retval)
+ goto exit;
+
+ /*
+ * Open the debugfs entry.
+ */
+ rt2x00debug_register(rt2x00dev);
+
+ __set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+ return 0;
+
+exit:
+ rt2x00lib_remove_dev(rt2x00dev);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev);
+
+void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
+{
+ __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+ /*
+ * Disable radio.
+ */
+ rt2x00lib_disable_radio(rt2x00dev);
+
+ /*
+ * Uninitialize device.
+ */
+ rt2x00lib_uninitialize(rt2x00dev);
+
+ /*
+ * Close debugfs entry.
+ */
+ rt2x00debug_deregister(rt2x00dev);
+
+ /*
+ * Free rfkill
+ */
+ rt2x00rfkill_free(rt2x00dev);
+
+ /*
+ * Free ieee80211_hw memory.
+ */
+ rt2x00lib_remove_hw(rt2x00dev);
+
+ /*
+ * Free firmware image.
+ */
+ rt2x00lib_free_firmware(rt2x00dev);
+
+ /*
+ * Free ring structures.
+ */
+ rt2x00lib_free_rings(rt2x00dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev);
+
+/*
+ * Device state handlers
+ */
+#ifdef CONFIG_PM
+int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state)
+{
+ int retval;
+
+ NOTICE(rt2x00dev, "Going to sleep.\n");
+ __clear_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+ /*
+ * Only continue if mac80211 has open interfaces.
+ */
+ if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+ goto exit;
+ __set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags);
+
+ /*
+ * Disable radio and unitialize all items
+ * that must be recreated on resume.
+ */
+ rt2x00mac_stop(rt2x00dev->hw);
+ rt2x00lib_uninitialize(rt2x00dev);
+ rt2x00debug_deregister(rt2x00dev);
+
+exit:
+ /*
+ * Set device mode to sleep for power management.
+ */
+ retval = rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_SLEEP);
+ if (retval)
+ return retval;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_suspend);
+
+int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
+{
+ struct interface *intf = &rt2x00dev->interface;
+ int retval;
+
+ NOTICE(rt2x00dev, "Waking up.\n");
+ __set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+ /*
+ * Open the debugfs entry.
+ */
+ rt2x00debug_register(rt2x00dev);
+
+ /*
+ * Only continue if mac80211 had open interfaces.
+ */
+ if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * Reinitialize device and all active interfaces.
+ */
+ retval = rt2x00mac_start(rt2x00dev->hw);
+ if (retval)
+ goto exit;
+
+ /*
+ * Reconfigure device.
+ */
+ rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, 1);
+ if (!rt2x00dev->hw->conf.radio_enabled)
+ rt2x00lib_disable_radio(rt2x00dev);
+
+ rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
+ rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
+ rt2x00lib_config_type(rt2x00dev, intf->type);
+
+ /*
+ * It is possible that during that mac80211 has attempted
+ * to send frames while we were suspending or resuming.
+ * In that case we have disabled the TX queue and should
+ * now enable it again
+ */
+ ieee80211_start_queues(rt2x00dev->hw);
+
+ /*
+ * When in Master or Ad-hoc mode,
+ * restart Beacon transmitting by faking a beacondone event.
+ */
+ if (intf->type == IEEE80211_IF_TYPE_AP ||
+ intf->type == IEEE80211_IF_TYPE_IBSS)
+ rt2x00lib_beacondone(rt2x00dev);
+
+ return 0;
+
+exit:
+ rt2x00lib_disable_radio(rt2x00dev);
+ rt2x00lib_uninitialize(rt2x00dev);
+ rt2x00debug_deregister(rt2x00dev);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_resume);
+#endif /* CONFIG_PM */
+
+/*
+ * rt2x00lib module information.
+ */
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("rt2x00 library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c
new file mode 100644
index 00000000000..236025f8b90
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -0,0 +1,124 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: rt2x00 firmware loading routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/crc-itu-t.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
+{
+ struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
+ const struct firmware *fw;
+ char *fw_name;
+ int retval;
+ u16 crc;
+ u16 tmp;
+
+ /*
+ * Read correct firmware from harddisk.
+ */
+ fw_name = rt2x00dev->ops->lib->get_firmware_name(rt2x00dev);
+ if (!fw_name) {
+ ERROR(rt2x00dev,
+ "Invalid firmware filename.\n"
+ "Please file bug report to %s.\n", DRV_PROJECT);
+ return -EINVAL;
+ }
+
+ INFO(rt2x00dev, "Loading firmware file '%s'.\n", fw_name);
+
+ retval = request_firmware(&fw, fw_name, device);
+ if (retval) {
+ ERROR(rt2x00dev, "Failed to request Firmware.\n");
+ return retval;
+ }
+
+ if (!fw || !fw->size || !fw->data) {
+ ERROR(rt2x00dev, "Failed to read Firmware.\n");
+ return -ENOENT;
+ }
+
+ /*
+ * Validate the firmware using 16 bit CRC.
+ * The last 2 bytes of the firmware are the CRC
+ * so substract those 2 bytes from the CRC checksum,
+ * and set those 2 bytes to 0 when calculating CRC.
+ */
+ tmp = 0;
+ crc = crc_itu_t(0, fw->data, fw->size - 2);
+ crc = crc_itu_t(crc, (u8 *)&tmp, 2);
+
+ if (crc != (fw->data[fw->size - 2] << 8 | fw->data[fw->size - 1])) {
+ ERROR(rt2x00dev, "Firmware CRC error.\n");
+ retval = -ENOENT;
+ goto exit;
+ }
+
+ INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n",
+ fw->data[fw->size - 4], fw->data[fw->size - 3]);
+
+ rt2x00dev->fw = fw;
+
+ return 0;
+
+exit:
+ release_firmware(fw);
+
+ return retval;
+}
+
+int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ if (!rt2x00dev->fw) {
+ retval = rt2x00lib_request_firmware(rt2x00dev);
+ if (retval)
+ return retval;
+ }
+
+ /*
+ * Send firmware to the device.
+ */
+ retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev,
+ rt2x00dev->fw->data,
+ rt2x00dev->fw->size);
+ return retval;
+}
+
+void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
+{
+ release_firmware(rt2x00dev->fw);
+ rt2x00dev->fw = NULL;
+}
+
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
new file mode 100644
index 00000000000..06d9bc0015c
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -0,0 +1,119 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00lib
+ Abstract: Data structures and definitions for the rt2x00lib module.
+ */
+
+#ifndef RT2X00LIB_H
+#define RT2X00LIB_H
+
+/*
+ * Interval defines
+ * Both the link tuner as the rfkill will be called once per second.
+ */
+#define LINK_TUNE_INTERVAL ( round_jiffies_relative(HZ) )
+#define RFKILL_POLL_INTERVAL ( 1000 )
+
+/*
+ * Radio control handlers.
+ */
+int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state);
+void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * Initialization handlers.
+ */
+int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * Configuration handlers.
+ */
+void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac);
+void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid);
+void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type);
+void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf, const int force_config);
+
+/*
+ * Firmware handlers.
+ */
+#ifdef CONFIG_RT2X00_LIB_FIRMWARE
+int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev);
+#else
+static inline int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
+{
+ return 0;
+}
+static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_FIRMWARE */
+
+/*
+ * Debugfs handlers.
+ */
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
+void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
+#else
+static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
+{
+}
+
+static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
+ * RFkill handlers.
+ */
+#ifdef CONFIG_RT2X00_LIB_RFKILL
+int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev);
+void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev);
+int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev);
+void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev);
+#else
+static inline int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
+{
+ return 0;
+}
+
+static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
+{
+}
+
+static inline int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
+{
+ return 0;
+}
+
+static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_RFKILL */
+
+#endif /* RT2X00LIB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
new file mode 100644
index 00000000000..85ea8a8e658
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -0,0 +1,446 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00mac
+ Abstract: rt2x00 generic mac80211 routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring,
+ struct sk_buff *frag_skb,
+ struct ieee80211_tx_control *control)
+{
+ struct sk_buff *skb;
+ int size;
+
+ if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ size = sizeof(struct ieee80211_cts);
+ else
+ size = sizeof(struct ieee80211_rts);
+
+ skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom);
+ if (!skb) {
+ WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom);
+ skb_put(skb, size);
+
+ if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ ieee80211_ctstoself_get(rt2x00dev->hw, rt2x00dev->interface.id,
+ frag_skb->data, frag_skb->len, control,
+ (struct ieee80211_cts *)(skb->data));
+ else
+ ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id,
+ frag_skb->data, frag_skb->len, control,
+ (struct ieee80211_rts *)(skb->data));
+
+ if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) {
+ WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ return NETDEV_TX_OK;
+}
+
+int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+ struct data_ring *ring;
+ u16 frame_control;
+
+ /*
+ * Mac80211 might be calling this function while we are trying
+ * to remove the device or perhaps suspending it.
+ * Note that we can only stop the TX queues inside the TX path
+ * due to possible race conditions in mac80211.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) {
+ ieee80211_stop_queues(hw);
+ return 0;
+ }
+
+ /*
+ * Determine which ring to put packet on.
+ */
+ ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
+ if (unlikely(!ring)) {
+ ERROR(rt2x00dev,
+ "Attempt to send packet over invalid queue %d.\n"
+ "Please file bug report to %s.\n",
+ control->queue, DRV_PROJECT);
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ /*
+ * If CTS/RTS is required. and this frame is not CTS or RTS,
+ * create and queue that frame first. But make sure we have
+ * at least enough entries available to send this CTS/RTS
+ * frame as well as the data frame.
+ */
+ frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+ if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) &&
+ (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS |
+ IEEE80211_TXCTL_USE_CTS_PROTECT))) {
+ if (rt2x00_ring_free(ring) <= 1)
+ return NETDEV_TX_BUSY;
+
+ if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control))
+ return NETDEV_TX_BUSY;
+ }
+
+ if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control))
+ return NETDEV_TX_BUSY;
+
+ if (rt2x00dev->ops->lib->kick_tx_queue)
+ rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+
+ return NETDEV_TX_OK;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_tx);
+
+int rt2x00mac_start(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int status;
+
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+ test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * If this is the first interface which is added,
+ * we should load the firmware now.
+ */
+ if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) {
+ status = rt2x00lib_load_firmware(rt2x00dev);
+ if (status)
+ return status;
+ }
+
+ /*
+ * Initialize the device.
+ */
+ status = rt2x00lib_initialize(rt2x00dev);
+ if (status)
+ return status;
+
+ /*
+ * Enable radio.
+ */
+ status = rt2x00lib_enable_radio(rt2x00dev);
+ if (status) {
+ rt2x00lib_uninitialize(rt2x00dev);
+ return status;
+ }
+
+ __set_bit(DEVICE_STARTED, &rt2x00dev->flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_start);
+
+void rt2x00mac_stop(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+ return;
+
+ /*
+ * Perhaps we can add something smarter here,
+ * but for now just disabling the radio should do.
+ */
+ rt2x00lib_disable_radio(rt2x00dev);
+
+ __clear_bit(DEVICE_STARTED, &rt2x00dev->flags);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_stop);
+
+int rt2x00mac_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+
+ /* FIXME: Beaconing is broken in rt2x00. */
+ if (conf->type == IEEE80211_IF_TYPE_IBSS ||
+ conf->type == IEEE80211_IF_TYPE_AP) {
+ ERROR(rt2x00dev,
+ "rt2x00 does not support Adhoc or Master mode");
+ return -EOPNOTSUPP;
+ }
+
+ /*
+ * Don't allow interfaces to be added while
+ * either the device has disappeared or when
+ * another interface is already present.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+ is_interface_present(intf))
+ return -ENOBUFS;
+
+ intf->id = conf->if_id;
+ intf->type = conf->type;
+ if (conf->type == IEEE80211_IF_TYPE_AP)
+ memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
+ memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
+
+ /*
+ * The MAC adddress must be configured after the device
+ * has been initialized. Otherwise the device can reset
+ * the MAC registers.
+ */
+ rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
+ rt2x00lib_config_type(rt2x00dev, conf->type);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
+
+void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+
+ /*
+ * Don't allow interfaces to be remove while
+ * either the device has disappeared or when
+ * no interface is present.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+ !is_interface_present(intf))
+ return;
+
+ intf->id = 0;
+ intf->type = INVALID_INTERFACE;
+ memset(&intf->bssid, 0x00, ETH_ALEN);
+ memset(&intf->mac, 0x00, ETH_ALEN);
+
+ /*
+ * Make sure the bssid and mac address registers
+ * are cleared to prevent false ACKing of frames.
+ */
+ rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
+ rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
+ rt2x00lib_config_type(rt2x00dev, intf->type);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
+
+int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * Mac80211 might be calling this function while we are trying
+ * to remove the device or perhaps suspending it.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * Check if we need to disable the radio,
+ * if this is not the case, at least the RX must be disabled.
+ */
+ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) {
+ if (!conf->radio_enabled)
+ rt2x00lib_disable_radio(rt2x00dev);
+ else
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
+ }
+
+ rt2x00lib_config(rt2x00dev, conf, 0);
+
+ /*
+ * Reenable RX only if the radio should be on.
+ */
+ if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+ else if (conf->radio_enabled)
+ return rt2x00lib_enable_radio(rt2x00dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_config);
+
+int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+ int status;
+
+ /*
+ * Mac80211 might be calling this function while we are trying
+ * to remove the device or perhaps suspending it.
+ */
+ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+ return 0;
+
+ /*
+ * If the given type does not match the configured type,
+ * there has been a problem.
+ */
+ if (conf->type != intf->type)
+ return -EINVAL;
+
+ /*
+ * If the interface does not work in master mode,
+ * then the bssid value in the interface structure
+ * should now be set.
+ */
+ if (conf->type != IEEE80211_IF_TYPE_AP)
+ memcpy(&intf->bssid, conf->bssid, ETH_ALEN);
+ rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
+
+ /*
+ * We only need to initialize the beacon when master mode is enabled.
+ */
+ if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon)
+ return 0;
+
+ status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
+ conf->beacon,
+ conf->beacon_control);
+ if (status)
+ dev_kfree_skb(conf->beacon);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_config_interface);
+
+int rt2x00mac_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * The dot11ACKFailureCount, dot11RTSFailureCount and
+ * dot11RTSSuccessCount are updated in interrupt time.
+ * dot11FCSErrorCount is updated in the link tuner.
+ */
+ memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_get_stats);
+
+int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ unsigned int i;
+
+ for (i = 0; i < hw->queues; i++)
+ memcpy(&stats->data[i], &rt2x00dev->tx[i].stats,
+ sizeof(rt2x00dev->tx[i].stats));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats);
+
+void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes,
+ int cts_protection, int preamble)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int short_preamble;
+ int ack_timeout;
+ int ack_consume_time;
+ int difs;
+
+ /*
+ * We only support changing preamble mode.
+ */
+ if (!(changes & IEEE80211_ERP_CHANGE_PREAMBLE))
+ return;
+
+ short_preamble = !preamble;
+ preamble = !!(preamble) ? PREAMBLE : SHORT_PREAMBLE;
+
+ difs = (hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) ?
+ SHORT_DIFS : DIFS;
+ ack_timeout = difs + PLCP + preamble + get_duration(ACK_SIZE, 10);
+
+ ack_consume_time = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10);
+
+ if (short_preamble)
+ __set_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+ else
+ __clear_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+
+ rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble,
+ ack_timeout, ack_consume_time);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_erp_ie_changed);
+
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct data_ring *ring;
+
+ ring = rt2x00lib_get_ring(rt2x00dev, queue);
+ if (unlikely(!ring))
+ return -EINVAL;
+
+ /*
+ * The passed variables are stored as real value ((2^n)-1).
+ * Ralink registers require to know the bit number 'n'.
+ */
+ if (params->cw_min)
+ ring->tx_params.cw_min = fls(params->cw_min);
+ else
+ ring->tx_params.cw_min = 5; /* cw_min: 2^5 = 32. */
+
+ if (params->cw_max)
+ ring->tx_params.cw_max = fls(params->cw_max);
+ else
+ ring->tx_params.cw_max = 10; /* cw_min: 2^10 = 1024. */
+
+ if (params->aifs)
+ ring->tx_params.aifs = params->aifs;
+ else
+ ring->tx_params.aifs = 2;
+
+ INFO(rt2x00dev,
+ "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
+ queue, ring->tx_params.cw_min, ring->tx_params.cw_max,
+ ring->tx_params.aifs);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
new file mode 100644
index 00000000000..2780df00623
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -0,0 +1,474 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00pci
+ Abstract: rt2x00 generic pci device routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00pci"
+
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+
+/*
+ * Beacon handlers.
+ */
+int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct data_ring *ring =
+ rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+ struct data_entry *entry = rt2x00_get_data_entry(ring);
+
+ /*
+ * Just in case mac80211 doesn't set this correctly,
+ * but we need this queue set for the descriptor
+ * initialization.
+ */
+ control->queue = IEEE80211_TX_QUEUE_BEACON;
+
+ /*
+ * Update the beacon entry.
+ */
+ memcpy(entry->data_addr, skb->data, skb->len);
+ rt2x00lib_write_tx_desc(rt2x00dev, entry->priv,
+ (struct ieee80211_hdr *)skb->data,
+ skb->len, control);
+
+ /*
+ * Enable beacon generation.
+ */
+ rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_beacon_update);
+
+/*
+ * TX data handlers.
+ */
+int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+ struct data_entry *entry = rt2x00_get_data_entry(ring);
+ struct data_desc *txd = entry->priv;
+ u32 word;
+
+ if (rt2x00_ring_full(ring)) {
+ ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ return -EINVAL;
+ }
+
+ rt2x00_desc_read(txd, 0, &word);
+
+ if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) ||
+ rt2x00_get_field32(word, TXD_ENTRY_VALID)) {
+ ERROR(rt2x00dev,
+ "Arrived at non-free entry in the non-full queue %d.\n"
+ "Please file bug report to %s.\n",
+ control->queue, DRV_PROJECT);
+ ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ return -EINVAL;
+ }
+
+ entry->skb = skb;
+ memcpy(&entry->tx_status.control, control, sizeof(*control));
+ memcpy(entry->data_addr, skb->data, skb->len);
+ rt2x00lib_write_tx_desc(rt2x00dev, txd, ieee80211hdr,
+ skb->len, control);
+
+ rt2x00_ring_index_inc(ring);
+
+ if (rt2x00_ring_full(ring))
+ ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
+
+/*
+ * RX data handlers.
+ */
+void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring = rt2x00dev->rx;
+ struct data_entry *entry;
+ struct data_desc *rxd;
+ struct sk_buff *skb;
+ struct rxdata_entry_desc desc;
+ u32 word;
+
+ while (1) {
+ entry = rt2x00_get_data_entry(ring);
+ rxd = entry->priv;
+ rt2x00_desc_read(rxd, 0, &word);
+
+ if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
+ break;
+
+ memset(&desc, 0x00, sizeof(desc));
+ rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
+
+ /*
+ * Allocate the sk_buffer, initialize it and copy
+ * all data into it.
+ */
+ skb = dev_alloc_skb(desc.size + NET_IP_ALIGN);
+ if (!skb)
+ return;
+
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb_put(skb, desc.size);
+ memcpy(skb->data, entry->data_addr, desc.size);
+
+ /*
+ * Send the frame to rt2x00lib for further processing.
+ */
+ rt2x00lib_rxdone(entry, skb, &desc);
+
+ if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
+ rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
+ rt2x00_desc_write(rxd, 0, word);
+ }
+
+ rt2x00_ring_index_inc(ring);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
+
+/*
+ * Device initialization handlers.
+ */
+#define priv_offset(__ring, __i) \
+({ \
+ ring->data_addr + (i * ring->desc_size); \
+})
+
+#define data_addr_offset(__ring, __i) \
+({ \
+ (__ring)->data_addr + \
+ ((__ring)->stats.limit * (__ring)->desc_size) + \
+ ((__i) * (__ring)->data_size); \
+})
+
+#define data_dma_offset(__ring, __i) \
+({ \
+ (__ring)->data_dma + \
+ ((__ring)->stats.limit * (__ring)->desc_size) + \
+ ((__i) * (__ring)->data_size); \
+})
+
+static int rt2x00pci_alloc_dma(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring)
+{
+ unsigned int i;
+
+ /*
+ * Allocate DMA memory for descriptor and buffer.
+ */
+ ring->data_addr = pci_alloc_consistent(rt2x00dev_pci(rt2x00dev),
+ rt2x00_get_ring_size(ring),
+ &ring->data_dma);
+ if (!ring->data_addr)
+ return -ENOMEM;
+
+ /*
+ * Initialize all ring entries to contain valid
+ * addresses.
+ */
+ for (i = 0; i < ring->stats.limit; i++) {
+ ring->entry[i].priv = priv_offset(ring, i);
+ ring->entry[i].data_addr = data_addr_offset(ring, i);
+ ring->entry[i].data_dma = data_dma_offset(ring, i);
+ }
+
+ return 0;
+}
+
+static void rt2x00pci_free_dma(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring)
+{
+ if (ring->data_addr)
+ pci_free_consistent(rt2x00dev_pci(rt2x00dev),
+ rt2x00_get_ring_size(ring),
+ ring->data_addr, ring->data_dma);
+ ring->data_addr = NULL;
+}
+
+int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
+ struct data_ring *ring;
+ int status;
+
+ /*
+ * Allocate DMA
+ */
+ ring_for_each(rt2x00dev, ring) {
+ status = rt2x00pci_alloc_dma(rt2x00dev, ring);
+ if (status)
+ goto exit;
+ }
+
+ /*
+ * Register interrupt handler.
+ */
+ status = request_irq(pci_dev->irq, rt2x00dev->ops->lib->irq_handler,
+ IRQF_SHARED, pci_name(pci_dev), rt2x00dev);
+ if (status) {
+ ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
+ pci_dev->irq, status);
+ return status;
+ }
+
+ return 0;
+
+exit:
+ rt2x00pci_uninitialize(rt2x00dev);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_initialize);
+
+void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+
+ /*
+ * Free irq line.
+ */
+ free_irq(rt2x00dev_pci(rt2x00dev)->irq, rt2x00dev);
+
+ /*
+ * Free DMA
+ */
+ ring_for_each(rt2x00dev, ring)
+ rt2x00pci_free_dma(rt2x00dev, ring);
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
+
+/*
+ * PCI driver handlers.
+ */
+static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
+{
+ kfree(rt2x00dev->rf);
+ rt2x00dev->rf = NULL;
+
+ kfree(rt2x00dev->eeprom);
+ rt2x00dev->eeprom = NULL;
+
+ if (rt2x00dev->csr_addr) {
+ iounmap(rt2x00dev->csr_addr);
+ rt2x00dev->csr_addr = NULL;
+ }
+}
+
+static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
+{
+ struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
+
+ rt2x00dev->csr_addr = ioremap(pci_resource_start(pci_dev, 0),
+ pci_resource_len(pci_dev, 0));
+ if (!rt2x00dev->csr_addr)
+ goto exit;
+
+ rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
+ if (!rt2x00dev->eeprom)
+ goto exit;
+
+ rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
+ if (!rt2x00dev->rf)
+ goto exit;
+
+ return 0;
+
+exit:
+ ERROR_PROBE("Failed to allocate registers.\n");
+
+ rt2x00pci_free_reg(rt2x00dev);
+
+ return -ENOMEM;
+}
+
+int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
+{
+ struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_data;
+ struct ieee80211_hw *hw;
+ struct rt2x00_dev *rt2x00dev;
+ int retval;
+
+ retval = pci_request_regions(pci_dev, pci_name(pci_dev));
+ if (retval) {
+ ERROR_PROBE("PCI request regions failed.\n");
+ return retval;
+ }
+
+ retval = pci_enable_device(pci_dev);
+ if (retval) {
+ ERROR_PROBE("Enable device failed.\n");
+ goto exit_release_regions;
+ }
+
+ pci_set_master(pci_dev);
+
+ if (pci_set_mwi(pci_dev))
+ ERROR_PROBE("MWI not available.\n");
+
+ if (pci_set_dma_mask(pci_dev, DMA_64BIT_MASK) &&
+ pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
+ ERROR_PROBE("PCI DMA not supported.\n");
+ retval = -EIO;
+ goto exit_disable_device;
+ }
+
+ hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
+ if (!hw) {
+ ERROR_PROBE("Failed to allocate hardware.\n");
+ retval = -ENOMEM;
+ goto exit_disable_device;
+ }
+
+ pci_set_drvdata(pci_dev, hw);
+
+ rt2x00dev = hw->priv;
+ rt2x00dev->dev = pci_dev;
+ rt2x00dev->ops = ops;
+ rt2x00dev->hw = hw;
+
+ retval = rt2x00pci_alloc_reg(rt2x00dev);
+ if (retval)
+ goto exit_free_device;
+
+ retval = rt2x00lib_probe_dev(rt2x00dev);
+ if (retval)
+ goto exit_free_reg;
+
+ return 0;
+
+exit_free_reg:
+ rt2x00pci_free_reg(rt2x00dev);
+
+exit_free_device:
+ ieee80211_free_hw(hw);
+
+exit_disable_device:
+ if (retval != -EBUSY)
+ pci_disable_device(pci_dev);
+
+exit_release_regions:
+ pci_release_regions(pci_dev);
+
+ pci_set_drvdata(pci_dev, NULL);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_probe);
+
+void rt2x00pci_remove(struct pci_dev *pci_dev)
+{
+ struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * Free all allocated data.
+ */
+ rt2x00lib_remove_dev(rt2x00dev);
+ rt2x00pci_free_reg(rt2x00dev);
+ ieee80211_free_hw(hw);
+
+ /*
+ * Free the PCI device data.
+ */
+ pci_set_drvdata(pci_dev, NULL);
+ pci_disable_device(pci_dev);
+ pci_release_regions(pci_dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_remove);
+
+#ifdef CONFIG_PM
+int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+ struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int retval;
+
+ retval = rt2x00lib_suspend(rt2x00dev, state);
+ if (retval)
+ return retval;
+
+ rt2x00pci_free_reg(rt2x00dev);
+
+ pci_save_state(pci_dev);
+ pci_disable_device(pci_dev);
+ return pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_suspend);
+
+int rt2x00pci_resume(struct pci_dev *pci_dev)
+{
+ struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int retval;
+
+ if (pci_set_power_state(pci_dev, PCI_D0) ||
+ pci_enable_device(pci_dev) ||
+ pci_restore_state(pci_dev)) {
+ ERROR(rt2x00dev, "Failed to resume device.\n");
+ return -EIO;
+ }
+
+ retval = rt2x00pci_alloc_reg(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt2x00lib_resume(rt2x00dev);
+ if (retval)
+ goto exit_free_reg;
+
+ return 0;
+
+exit_free_reg:
+ rt2x00pci_free_reg(rt2x00dev);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_resume);
+#endif /* CONFIG_PM */
+
+/*
+ * rt2x00pci module information.
+ */
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("rt2x00 library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
new file mode 100644
index 00000000000..82adeac061d
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -0,0 +1,127 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00pci
+ Abstract: Data structures for the rt2x00pci module.
+ */
+
+#ifndef RT2X00PCI_H
+#define RT2X00PCI_H
+
+#include <linux/io.h>
+
+/*
+ * This variable should be used with the
+ * pci_driver structure initialization.
+ */
+#define PCI_DEVICE_DATA(__ops) .driver_data = (kernel_ulong_t)(__ops)
+
+/*
+ * Register defines.
+ * Some registers require multiple attempts before success,
+ * in those cases REGISTER_BUSY_COUNT attempts should be
+ * taken with a REGISTER_BUSY_DELAY interval.
+ */
+#define REGISTER_BUSY_COUNT 5
+#define REGISTER_BUSY_DELAY 100
+
+/*
+ * Descriptor availability flags.
+ * All PCI device descriptors have these 2 flags
+ * with the exact same definition.
+ * By storing them here we can use them inside rt2x00pci
+ * for some simple entry availability checking.
+ */
+#define TXD_ENTRY_OWNER_NIC FIELD32(0x00000001)
+#define TXD_ENTRY_VALID FIELD32(0x00000002)
+#define RXD_ENTRY_OWNER_NIC FIELD32(0x00000001)
+
+/*
+ * Register access.
+ */
+static inline void rt2x00pci_register_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned long offset,
+ u32 *value)
+{
+ *value = readl(rt2x00dev->csr_addr + offset);
+}
+
+static inline void
+rt2x00pci_register_multiread(const struct rt2x00_dev *rt2x00dev,
+ const unsigned long offset,
+ void *value, const u16 length)
+{
+ memcpy_fromio(value, rt2x00dev->csr_addr + offset, length);
+}
+
+static inline void rt2x00pci_register_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned long offset,
+ u32 value)
+{
+ writel(value, rt2x00dev->csr_addr + offset);
+}
+
+static inline void
+rt2x00pci_register_multiwrite(const struct rt2x00_dev *rt2x00dev,
+ const unsigned long offset,
+ void *value, const u16 length)
+{
+ memcpy_toio(rt2x00dev->csr_addr + offset, value, length);
+}
+
+/*
+ * Beacon handlers.
+ */
+int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control);
+
+/*
+ * TX data handlers.
+ */
+int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring, struct sk_buff *skb,
+ struct ieee80211_tx_control *control);
+
+/*
+ * RX data handlers.
+ */
+void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * Device initialization handlers.
+ */
+int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev);
+void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * PCI driver handlers.
+ */
+int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id);
+void rt2x00pci_remove(struct pci_dev *pci_dev);
+#ifdef CONFIG_PM
+int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state);
+int rt2x00pci_resume(struct pci_dev *pci_dev);
+#else
+#define rt2x00pci_suspend NULL
+#define rt2x00pci_resume NULL
+#endif /* CONFIG_PM */
+
+#endif /* RT2X00PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
new file mode 100644
index 00000000000..838421216da
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -0,0 +1,292 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00
+ Abstract: rt2x00 generic register information.
+ */
+
+#ifndef RT2X00REG_H
+#define RT2X00REG_H
+
+/*
+ * TX result flags.
+ */
+enum TX_STATUS {
+ TX_SUCCESS = 0,
+ TX_SUCCESS_RETRY = 1,
+ TX_FAIL_RETRY = 2,
+ TX_FAIL_INVALID = 3,
+ TX_FAIL_OTHER = 4,
+};
+
+/*
+ * Antenna values
+ */
+enum antenna {
+ ANTENNA_SW_DIVERSITY = 0,
+ ANTENNA_A = 1,
+ ANTENNA_B = 2,
+ ANTENNA_HW_DIVERSITY = 3,
+};
+
+/*
+ * Led mode values.
+ */
+enum led_mode {
+ LED_MODE_DEFAULT = 0,
+ LED_MODE_TXRX_ACTIVITY = 1,
+ LED_MODE_SIGNAL_STRENGTH = 2,
+ LED_MODE_ASUS = 3,
+ LED_MODE_ALPHA = 4,
+};
+
+/*
+ * TSF sync values
+ */
+enum tsf_sync {
+ TSF_SYNC_NONE = 0,
+ TSF_SYNC_INFRA = 1,
+ TSF_SYNC_BEACON = 2,
+};
+
+/*
+ * Device states
+ */
+enum dev_state {
+ STATE_DEEP_SLEEP = 0,
+ STATE_SLEEP = 1,
+ STATE_STANDBY = 2,
+ STATE_AWAKE = 3,
+
+/*
+ * Additional device states, these values are
+ * not strict since they are not directly passed
+ * into the device.
+ */
+ STATE_RADIO_ON,
+ STATE_RADIO_OFF,
+ STATE_RADIO_RX_ON,
+ STATE_RADIO_RX_OFF,
+ STATE_RADIO_IRQ_ON,
+ STATE_RADIO_IRQ_OFF,
+};
+
+/*
+ * IFS backoff values
+ */
+enum ifs {
+ IFS_BACKOFF = 0,
+ IFS_SIFS = 1,
+ IFS_NEW_BACKOFF = 2,
+ IFS_NONE = 3,
+};
+
+/*
+ * Cipher types for hardware encryption
+ */
+enum cipher {
+ CIPHER_NONE = 0,
+ CIPHER_WEP64 = 1,
+ CIPHER_WEP128 = 2,
+ CIPHER_TKIP = 3,
+ CIPHER_AES = 4,
+/*
+ * The following fields were added by rt61pci and rt73usb.
+ */
+ CIPHER_CKIP64 = 5,
+ CIPHER_CKIP128 = 6,
+ CIPHER_TKIP_NO_MIC = 7,
+};
+
+/*
+ * Register handlers.
+ * We store the position of a register field inside a field structure,
+ * This will simplify the process of setting and reading a certain field
+ * inside the register while making sure the process remains byte order safe.
+ */
+struct rt2x00_field8 {
+ u8 bit_offset;
+ u8 bit_mask;
+};
+
+struct rt2x00_field16 {
+ u16 bit_offset;
+ u16 bit_mask;
+};
+
+struct rt2x00_field32 {
+ u32 bit_offset;
+ u32 bit_mask;
+};
+
+/*
+ * Power of two check, this will check
+ * if the mask that has been given contains
+ * and contiguous set of bits.
+ */
+#define is_power_of_two(x) ( !((x) & ((x)-1)) )
+#define low_bit_mask(x) ( ((x)-1) & ~(x) )
+#define is_valid_mask(x) is_power_of_two(1 + (x) + low_bit_mask(x))
+
+#define FIELD8(__mask) \
+({ \
+ BUILD_BUG_ON(!(__mask) || \
+ !is_valid_mask(__mask) || \
+ (__mask) != (u8)(__mask)); \
+ (struct rt2x00_field8) { \
+ __ffs(__mask), (__mask) \
+ }; \
+})
+
+#define FIELD16(__mask) \
+({ \
+ BUILD_BUG_ON(!(__mask) || \
+ !is_valid_mask(__mask) || \
+ (__mask) != (u16)(__mask));\
+ (struct rt2x00_field16) { \
+ __ffs(__mask), (__mask) \
+ }; \
+})
+
+#define FIELD32(__mask) \
+({ \
+ BUILD_BUG_ON(!(__mask) || \
+ !is_valid_mask(__mask) || \
+ (__mask) != (u32)(__mask));\
+ (struct rt2x00_field32) { \
+ __ffs(__mask), (__mask) \
+ }; \
+})
+
+static inline void rt2x00_set_field32(u32 *reg,
+ const struct rt2x00_field32 field,
+ const u32 value)
+{
+ *reg &= ~(field.bit_mask);
+ *reg |= (value << field.bit_offset) & field.bit_mask;
+}
+
+static inline u32 rt2x00_get_field32(const u32 reg,
+ const struct rt2x00_field32 field)
+{
+ return (reg & field.bit_mask) >> field.bit_offset;
+}
+
+static inline void rt2x00_set_field16(u16 *reg,
+ const struct rt2x00_field16 field,
+ const u16 value)
+{
+ *reg &= ~(field.bit_mask);
+ *reg |= (value << field.bit_offset) & field.bit_mask;
+}
+
+static inline u16 rt2x00_get_field16(const u16 reg,
+ const struct rt2x00_field16 field)
+{
+ return (reg & field.bit_mask) >> field.bit_offset;
+}
+
+static inline void rt2x00_set_field8(u8 *reg,
+ const struct rt2x00_field8 field,
+ const u8 value)
+{
+ *reg &= ~(field.bit_mask);
+ *reg |= (value << field.bit_offset) & field.bit_mask;
+}
+
+static inline u8 rt2x00_get_field8(const u8 reg,
+ const struct rt2x00_field8 field)
+{
+ return (reg & field.bit_mask) >> field.bit_offset;
+}
+
+/*
+ * Device specific rate value.
+ * We will have to create the device specific rate value
+ * passed to the ieee80211 kernel. We need to make it a consist of
+ * multiple fields because we want to store more then 1 device specific
+ * values inside the value.
+ * 1 - rate, stored as 100 kbit/s.
+ * 2 - preamble, short_preamble enabled flag.
+ * 3 - MASK_RATE, which rates are enabled in this mode, this mask
+ * corresponds with the TX register format for the current device.
+ * 4 - plcp, 802.11b rates are device specific,
+ * 802.11g rates are set according to the ieee802.11a-1999 p.14.
+ * The bit to enable preamble is set in a seperate define.
+ */
+#define DEV_RATE FIELD32(0x000007ff)
+#define DEV_PREAMBLE FIELD32(0x00000800)
+#define DEV_RATEMASK FIELD32(0x00fff000)
+#define DEV_PLCP FIELD32(0xff000000)
+
+/*
+ * Bitfields
+ */
+#define DEV_RATEBIT_1MB ( 1 << 0 )
+#define DEV_RATEBIT_2MB ( 1 << 1 )
+#define DEV_RATEBIT_5_5MB ( 1 << 2 )
+#define DEV_RATEBIT_11MB ( 1 << 3 )
+#define DEV_RATEBIT_6MB ( 1 << 4 )
+#define DEV_RATEBIT_9MB ( 1 << 5 )
+#define DEV_RATEBIT_12MB ( 1 << 6 )
+#define DEV_RATEBIT_18MB ( 1 << 7 )
+#define DEV_RATEBIT_24MB ( 1 << 8 )
+#define DEV_RATEBIT_36MB ( 1 << 9 )
+#define DEV_RATEBIT_48MB ( 1 << 10 )
+#define DEV_RATEBIT_54MB ( 1 << 11 )
+
+/*
+ * Bitmasks for DEV_RATEMASK
+ */
+#define DEV_RATEMASK_1MB ( (DEV_RATEBIT_1MB << 1) -1 )
+#define DEV_RATEMASK_2MB ( (DEV_RATEBIT_2MB << 1) -1 )
+#define DEV_RATEMASK_5_5MB ( (DEV_RATEBIT_5_5MB << 1) -1 )
+#define DEV_RATEMASK_11MB ( (DEV_RATEBIT_11MB << 1) -1 )
+#define DEV_RATEMASK_6MB ( (DEV_RATEBIT_6MB << 1) -1 )
+#define DEV_RATEMASK_9MB ( (DEV_RATEBIT_9MB << 1) -1 )
+#define DEV_RATEMASK_12MB ( (DEV_RATEBIT_12MB << 1) -1 )
+#define DEV_RATEMASK_18MB ( (DEV_RATEBIT_18MB << 1) -1 )
+#define DEV_RATEMASK_24MB ( (DEV_RATEBIT_24MB << 1) -1 )
+#define DEV_RATEMASK_36MB ( (DEV_RATEBIT_36MB << 1) -1 )
+#define DEV_RATEMASK_48MB ( (DEV_RATEBIT_48MB << 1) -1 )
+#define DEV_RATEMASK_54MB ( (DEV_RATEBIT_54MB << 1) -1 )
+
+/*
+ * Bitmask groups of bitrates
+ */
+#define DEV_BASIC_RATEMASK \
+ ( DEV_RATEMASK_11MB | \
+ DEV_RATEBIT_6MB | DEV_RATEBIT_12MB | DEV_RATEBIT_24MB )
+
+#define DEV_CCK_RATEMASK ( DEV_RATEMASK_11MB )
+#define DEV_OFDM_RATEMASK ( DEV_RATEMASK_54MB & ~DEV_CCK_RATEMASK )
+
+/*
+ * Macro's to set and get specific fields from the device specific val and val2
+ * fields inside the ieee80211_rate entry.
+ */
+#define DEVICE_SET_RATE_FIELD(__value, __mask) \
+ (int)( ((__value) << DEV_##__mask.bit_offset) & DEV_##__mask.bit_mask )
+
+#define DEVICE_GET_RATE_FIELD(__value, __mask) \
+ (int)( ((__value) & DEV_##__mask.bit_mask) >> DEV_##__mask.bit_offset )
+
+#endif /* RT2X00REG_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
new file mode 100644
index 00000000000..a0f8b8e0a24
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
@@ -0,0 +1,146 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00rfkill
+ Abstract: rt2x00 rfkill routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/input-polldev.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rfkill.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state)
+{
+ struct rt2x00_dev *rt2x00dev = data;
+ int retval = 0;
+
+ if (unlikely(!rt2x00dev))
+ return 0;
+
+ /*
+ * Only continue if there are enabled interfaces.
+ */
+ if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+ return 0;
+
+ if (state == RFKILL_STATE_ON) {
+ INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n");
+ __clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
+ retval = rt2x00lib_enable_radio(rt2x00dev);
+ } else if (state == RFKILL_STATE_OFF) {
+ INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n");
+ __set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
+ rt2x00lib_disable_radio(rt2x00dev);
+ }
+
+ return retval;
+}
+
+static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev)
+{
+ struct rt2x00_dev *rt2x00dev = poll_dev->private;
+ int state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
+
+ if (rt2x00dev->rfkill->state != state)
+ input_report_key(poll_dev->input, KEY_WLAN, 1);
+}
+
+int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ return 0;
+
+ retval = rfkill_register(rt2x00dev->rfkill);
+ if (retval) {
+ ERROR(rt2x00dev, "Failed to register rfkill handler.\n");
+ return retval;
+ }
+
+ retval = input_register_polled_device(rt2x00dev->poll_dev);
+ if (retval) {
+ ERROR(rt2x00dev, "Failed to register polled device.\n");
+ rfkill_unregister(rt2x00dev->rfkill);
+ return retval;
+ }
+
+ return 0;
+}
+
+void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
+{
+ if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ return;
+
+ input_unregister_polled_device(rt2x00dev->poll_dev);
+ rfkill_unregister(rt2x00dev->rfkill);
+}
+
+int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
+{
+ struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
+
+ if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ return 0;
+
+ rt2x00dev->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
+ if (!rt2x00dev->rfkill) {
+ ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n");
+ return -ENOMEM;
+ }
+
+ rt2x00dev->rfkill->name = rt2x00dev->ops->name;
+ rt2x00dev->rfkill->data = rt2x00dev;
+ rt2x00dev->rfkill->state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
+ rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio;
+
+ rt2x00dev->poll_dev = input_allocate_polled_device();
+ if (!rt2x00dev->poll_dev) {
+ ERROR(rt2x00dev, "Failed to allocate polled device.\n");
+ rfkill_free(rt2x00dev->rfkill);
+ return -ENOMEM;
+ }
+
+ rt2x00dev->poll_dev->private = rt2x00dev;
+ rt2x00dev->poll_dev->poll = rt2x00rfkill_poll;
+ rt2x00dev->poll_dev->poll_interval = RFKILL_POLL_INTERVAL;
+
+ return 0;
+}
+
+void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
+{
+ if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ return;
+
+ input_free_polled_device(rt2x00dev->poll_dev);
+ rfkill_free(rt2x00dev->rfkill);
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00ring.h b/drivers/net/wireless/rt2x00/rt2x00ring.h
new file mode 100644
index 00000000000..1a864d32cfb
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00ring.h
@@ -0,0 +1,268 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00
+ Abstract: rt2x00 ring datastructures and routines
+ */
+
+#ifndef RT2X00RING_H
+#define RT2X00RING_H
+
+/*
+ * data_desc
+ * Each data entry also contains a descriptor which is used by the
+ * device to determine what should be done with the packet and
+ * what the current status is.
+ * This structure is greatly simplified, but the descriptors
+ * are basically a list of little endian 32 bit values.
+ * Make the array by default 1 word big, this will allow us
+ * to use sizeof() correctly.
+ */
+struct data_desc {
+ __le32 word[1];
+};
+
+/*
+ * rxdata_entry_desc
+ * Summary of information that has been read from the
+ * RX frame descriptor.
+ */
+struct rxdata_entry_desc {
+ int signal;
+ int rssi;
+ int ofdm;
+ int size;
+ int flags;
+};
+
+/*
+ * txdata_entry_desc
+ * Summary of information that should be written into the
+ * descriptor for sending a TX frame.
+ */
+struct txdata_entry_desc {
+ unsigned long flags;
+#define ENTRY_TXDONE 1
+#define ENTRY_TXD_RTS_FRAME 2
+#define ENTRY_TXD_OFDM_RATE 3
+#define ENTRY_TXD_MORE_FRAG 4
+#define ENTRY_TXD_REQ_TIMESTAMP 5
+#define ENTRY_TXD_BURST 6
+
+/*
+ * Queue ID. ID's 0-4 are data TX rings
+ */
+ int queue;
+#define QUEUE_MGMT 13
+#define QUEUE_RX 14
+#define QUEUE_OTHER 15
+
+ /*
+ * PLCP values.
+ */
+ u16 length_high;
+ u16 length_low;
+ u16 signal;
+ u16 service;
+
+ /*
+ * Timing information
+ */
+ int aifs;
+ int ifs;
+ int cw_min;
+ int cw_max;
+};
+
+/*
+ * data_entry
+ * The data ring is a list of data entries.
+ * Each entry holds a reference to the descriptor
+ * and the data buffer. For TX rings the reference to the
+ * sk_buff of the packet being transmitted is also stored here.
+ */
+struct data_entry {
+ /*
+ * Status flags
+ */
+ unsigned long flags;
+#define ENTRY_OWNER_NIC 1
+
+ /*
+ * Ring we belong to.
+ */
+ struct data_ring *ring;
+
+ /*
+ * sk_buff for the packet which is being transmitted
+ * in this entry (Only used with TX related rings).
+ */
+ struct sk_buff *skb;
+
+ /*
+ * Store a ieee80211_tx_status structure in each
+ * ring entry, this will optimize the txdone
+ * handler.
+ */
+ struct ieee80211_tx_status tx_status;
+
+ /*
+ * private pointer specific to driver.
+ */
+ void *priv;
+
+ /*
+ * Data address for this entry.
+ */
+ void *data_addr;
+ dma_addr_t data_dma;
+};
+
+/*
+ * data_ring
+ * Data rings are used by the device to send and receive packets.
+ * The data_addr is the base address of the data memory.
+ * To determine at which point in the ring we are,
+ * have to use the rt2x00_ring_index_*() functions.
+ */
+struct data_ring {
+ /*
+ * Pointer to main rt2x00dev structure where this
+ * ring belongs to.
+ */
+ struct rt2x00_dev *rt2x00dev;
+
+ /*
+ * Base address for the device specific data entries.
+ */
+ struct data_entry *entry;
+
+ /*
+ * TX queue statistic info.
+ */
+ struct ieee80211_tx_queue_stats_data stats;
+
+ /*
+ * TX Queue parameters.
+ */
+ struct ieee80211_tx_queue_params tx_params;
+
+ /*
+ * Base address for data ring.
+ */
+ dma_addr_t data_dma;
+ void *data_addr;
+
+ /*
+ * Index variables.
+ */
+ u16 index;
+ u16 index_done;
+
+ /*
+ * Size of packet and descriptor in bytes.
+ */
+ u16 data_size;
+ u16 desc_size;
+};
+
+/*
+ * Handlers to determine the address of the current device specific
+ * data entry, where either index or index_done points to.
+ */
+static inline struct data_entry *rt2x00_get_data_entry(struct data_ring *ring)
+{
+ return &ring->entry[ring->index];
+}
+
+static inline struct data_entry *rt2x00_get_data_entry_done(struct data_ring
+ *ring)
+{
+ return &ring->entry[ring->index_done];
+}
+
+/*
+ * Total ring memory
+ */
+static inline int rt2x00_get_ring_size(struct data_ring *ring)
+{
+ return ring->stats.limit * (ring->desc_size + ring->data_size);
+}
+
+/*
+ * Ring index manipulation functions.
+ */
+static inline void rt2x00_ring_index_inc(struct data_ring *ring)
+{
+ ring->index++;
+ if (ring->index >= ring->stats.limit)
+ ring->index = 0;
+ ring->stats.len++;
+}
+
+static inline void rt2x00_ring_index_done_inc(struct data_ring *ring)
+{
+ ring->index_done++;
+ if (ring->index_done >= ring->stats.limit)
+ ring->index_done = 0;
+ ring->stats.len--;
+ ring->stats.count++;
+}
+
+static inline void rt2x00_ring_index_clear(struct data_ring *ring)
+{
+ ring->index = 0;
+ ring->index_done = 0;
+ ring->stats.len = 0;
+ ring->stats.count = 0;
+}
+
+static inline int rt2x00_ring_empty(struct data_ring *ring)
+{
+ return ring->stats.len == 0;
+}
+
+static inline int rt2x00_ring_full(struct data_ring *ring)
+{
+ return ring->stats.len == ring->stats.limit;
+}
+
+static inline int rt2x00_ring_free(struct data_ring *ring)
+{
+ return ring->stats.limit - ring->stats.len;
+}
+
+/*
+ * TX/RX Descriptor access functions.
+ */
+static inline void rt2x00_desc_read(struct data_desc *desc,
+ const u8 word, u32 *value)
+{
+ *value = le32_to_cpu(desc->word[word]);
+}
+
+static inline void rt2x00_desc_write(struct data_desc *desc,
+ const u8 word, const u32 value)
+{
+ desc->word[word] = cpu_to_le32(value);
+}
+
+#endif /* RT2X00RING_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
new file mode 100644
index 00000000000..73cc726c404
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -0,0 +1,592 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00usb
+ Abstract: rt2x00 generic usb device routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00usb"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "rt2x00.h"
+#include "rt2x00usb.h"
+
+/*
+ * Interfacing with the HW.
+ */
+int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev,
+ const u8 request, const u8 requesttype,
+ const u16 offset, const u16 value,
+ void *buffer, const u16 buffer_length,
+ const int timeout)
+{
+ struct usb_device *usb_dev =
+ interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+ int status;
+ unsigned int i;
+ unsigned int pipe =
+ (requesttype == USB_VENDOR_REQUEST_IN) ?
+ usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0);
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ status = usb_control_msg(usb_dev, pipe, request, requesttype,
+ value, offset, buffer, buffer_length,
+ timeout);
+ if (status >= 0)
+ return 0;
+
+ /*
+ * Check for errors
+ * -ENODEV: Device has disappeared, no point continuing.
+ * All other errors: Try again.
+ */
+ else if (status == -ENODEV)
+ break;
+ }
+
+ ERROR(rt2x00dev,
+ "Vendor Request 0x%02x failed for offset 0x%04x with error %d.\n",
+ request, offset, status);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request);
+
+int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev,
+ const u8 request, const u8 requesttype,
+ const u16 offset, void *buffer,
+ const u16 buffer_length, const int timeout)
+{
+ int status;
+
+ /*
+ * Check for Cache availability.
+ */
+ if (unlikely(!rt2x00dev->csr_cache || buffer_length > CSR_CACHE_SIZE)) {
+ ERROR(rt2x00dev, "CSR cache not available.\n");
+ return -ENOMEM;
+ }
+
+ if (requesttype == USB_VENDOR_REQUEST_OUT)
+ memcpy(rt2x00dev->csr_cache, buffer, buffer_length);
+
+ status = rt2x00usb_vendor_request(rt2x00dev, request, requesttype,
+ offset, 0, rt2x00dev->csr_cache,
+ buffer_length, timeout);
+
+ if (!status && requesttype == USB_VENDOR_REQUEST_IN)
+ memcpy(buffer, rt2x00dev->csr_cache, buffer_length);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
+
+/*
+ * TX data handlers.
+ */
+static void rt2x00usb_interrupt_txdone(struct urb *urb)
+{
+ struct data_entry *entry = (struct data_entry *)urb->context;
+ struct data_ring *ring = entry->ring;
+ struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
+ struct data_desc *txd = (struct data_desc *)entry->skb->data;
+ u32 word;
+ int tx_status;
+
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+ !__test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags))
+ return;
+
+ rt2x00_desc_read(txd, 0, &word);
+
+ /*
+ * Remove the descriptor data from the buffer.
+ */
+ skb_pull(entry->skb, ring->desc_size);
+
+ /*
+ * Obtain the status about this packet.
+ */
+ tx_status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY;
+
+ rt2x00lib_txdone(entry, tx_status, 0);
+
+ /*
+ * Make this entry available for reuse.
+ */
+ entry->flags = 0;
+ rt2x00_ring_index_done_inc(entry->ring);
+
+ /*
+ * If the data ring was full before the txdone handler
+ * we must make sure the packet queue in the mac80211 stack
+ * is reenabled when the txdone handler has finished.
+ */
+ if (!rt2x00_ring_full(ring))
+ ieee80211_wake_queue(rt2x00dev->hw,
+ entry->tx_status.control.queue);
+}
+
+int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct usb_device *usb_dev =
+ interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+ struct data_entry *entry = rt2x00_get_data_entry(ring);
+ int pipe = usb_sndbulkpipe(usb_dev, 1);
+ int max_packet = usb_maxpacket(usb_dev, pipe, 1);
+ u32 length;
+
+ if (rt2x00_ring_full(ring)) {
+ ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ return -EINVAL;
+ }
+
+ if (test_bit(ENTRY_OWNER_NIC, &entry->flags)) {
+ ERROR(rt2x00dev,
+ "Arrived at non-free entry in the non-full queue %d.\n"
+ "Please file bug report to %s.\n",
+ control->queue, DRV_PROJECT);
+ ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+ return -EINVAL;
+ }
+
+ /*
+ * Add the descriptor in front of the skb.
+ */
+ skb_push(skb, ring->desc_size);
+ memset(skb->data, 0, ring->desc_size);
+
+ rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
+ (struct ieee80211_hdr *)(skb->data +
+ ring->desc_size),
+ skb->len - ring->desc_size, control);
+ memcpy(&entry->tx_status.control, control, sizeof(*control));
+ entry->skb = skb;
+
+ /*
+ * USB devices cannot blindly pass the skb->len as the
+ * length of the data to usb_fill_bulk_urb. Pass the skb
+ * to the driver to determine what the length should be.
+ */
+ length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev,
+ max_packet, skb);
+
+ /*
+ * Initialize URB and send the frame to the device.
+ */
+ __set_bit(ENTRY_OWNER_NIC, &entry->flags);
+ usb_fill_bulk_urb(entry->priv, usb_dev, pipe,
+ skb->data, length, rt2x00usb_interrupt_txdone, entry);
+ usb_submit_urb(entry->priv, GFP_ATOMIC);
+
+ rt2x00_ring_index_inc(ring);
+
+ if (rt2x00_ring_full(ring))
+ ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);
+
+/*
+ * RX data handlers.
+ */
+static void rt2x00usb_interrupt_rxdone(struct urb *urb)
+{
+ struct data_entry *entry = (struct data_entry *)urb->context;
+ struct data_ring *ring = entry->ring;
+ struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
+ struct sk_buff *skb;
+ struct rxdata_entry_desc desc;
+ int frame_size;
+
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+ !test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags))
+ return;
+
+ /*
+ * Check if the received data is simply too small
+ * to be actually valid, or if the urb is signaling
+ * a problem.
+ */
+ if (urb->actual_length < entry->ring->desc_size || urb->status)
+ goto skip_entry;
+
+ memset(&desc, 0x00, sizeof(desc));
+ rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
+
+ /*
+ * Allocate a new sk buffer to replace the current one.
+ * If allocation fails, we should drop the current frame
+ * so we can recycle the existing sk buffer for the new frame.
+ */
+ frame_size = entry->ring->data_size + entry->ring->desc_size;
+ skb = dev_alloc_skb(frame_size + NET_IP_ALIGN);
+ if (!skb)
+ goto skip_entry;
+
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb_put(skb, frame_size);
+
+ /*
+ * Trim the skb_buffer to only contain the valid
+ * frame data (so ignore the device's descriptor).
+ */
+ skb_trim(entry->skb, desc.size);
+
+ /*
+ * Send the frame to rt2x00lib for further processing.
+ */
+ rt2x00lib_rxdone(entry, entry->skb, &desc);
+
+ /*
+ * Replace current entry's skb with the newly allocated one,
+ * and reinitialize the urb.
+ */
+ entry->skb = skb;
+ urb->transfer_buffer = entry->skb->data;
+ urb->transfer_buffer_length = entry->skb->len;
+
+skip_entry:
+ if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
+ __set_bit(ENTRY_OWNER_NIC, &entry->flags);
+ usb_submit_urb(urb, GFP_ATOMIC);
+ }
+
+ rt2x00_ring_index_inc(ring);
+}
+
+/*
+ * Radio handlers
+ */
+void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ struct usb_device *usb_dev =
+ interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+ struct data_ring *ring;
+ struct data_entry *entry;
+ unsigned int i;
+
+ /*
+ * Initialize the TX rings
+ */
+ txringall_for_each(rt2x00dev, ring) {
+ for (i = 0; i < ring->stats.limit; i++)
+ ring->entry[i].flags = 0;
+
+ rt2x00_ring_index_clear(ring);
+ }
+
+ /*
+ * Initialize and start the RX ring.
+ */
+ rt2x00_ring_index_clear(rt2x00dev->rx);
+
+ for (i = 0; i < rt2x00dev->rx->stats.limit; i++) {
+ entry = &rt2x00dev->rx->entry[i];
+
+ usb_fill_bulk_urb(entry->priv, usb_dev,
+ usb_rcvbulkpipe(usb_dev, 1),
+ entry->skb->data, entry->skb->len,
+ rt2x00usb_interrupt_rxdone, entry);
+
+ __set_bit(ENTRY_OWNER_NIC, &entry->flags);
+ usb_submit_urb(entry->priv, GFP_ATOMIC);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_enable_radio);
+
+void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+ unsigned int i;
+
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0x0000, 0x0000,
+ REGISTER_TIMEOUT);
+
+ /*
+ * Cancel all rings.
+ */
+ ring_for_each(rt2x00dev, ring) {
+ for (i = 0; i < ring->stats.limit; i++)
+ usb_kill_urb(ring->entry[i].priv);
+ }
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
+
+/*
+ * Device initialization handlers.
+ */
+static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring)
+{
+ unsigned int i;
+
+ /*
+ * Allocate the URB's
+ */
+ for (i = 0; i < ring->stats.limit; i++) {
+ ring->entry[i].priv = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ring->entry[i].priv)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring)
+{
+ unsigned int i;
+
+ if (!ring->entry)
+ return;
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ usb_kill_urb(ring->entry[i].priv);
+ usb_free_urb(ring->entry[i].priv);
+ if (ring->entry[i].skb)
+ kfree_skb(ring->entry[i].skb);
+ }
+}
+
+int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+ struct sk_buff *skb;
+ unsigned int entry_size;
+ unsigned int i;
+ int status;
+
+ /*
+ * Allocate DMA
+ */
+ ring_for_each(rt2x00dev, ring) {
+ status = rt2x00usb_alloc_urb(rt2x00dev, ring);
+ if (status)
+ goto exit;
+ }
+
+ /*
+ * For the RX ring, skb's should be allocated.
+ */
+ entry_size = rt2x00dev->rx->data_size + rt2x00dev->rx->desc_size;
+ for (i = 0; i < rt2x00dev->rx->stats.limit; i++) {
+ skb = dev_alloc_skb(NET_IP_ALIGN + entry_size);
+ if (!skb)
+ goto exit;
+
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb_put(skb, entry_size);
+
+ rt2x00dev->rx->entry[i].skb = skb;
+ }
+
+ return 0;
+
+exit:
+ rt2x00usb_uninitialize(rt2x00dev);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_initialize);
+
+void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+
+ ring_for_each(rt2x00dev, ring)
+ rt2x00usb_free_urb(rt2x00dev, ring);
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize);
+
+/*
+ * USB driver handlers.
+ */
+static void rt2x00usb_free_reg(struct rt2x00_dev *rt2x00dev)
+{
+ kfree(rt2x00dev->rf);
+ rt2x00dev->rf = NULL;
+
+ kfree(rt2x00dev->eeprom);
+ rt2x00dev->eeprom = NULL;
+
+ kfree(rt2x00dev->csr_cache);
+ rt2x00dev->csr_cache = NULL;
+}
+
+static int rt2x00usb_alloc_reg(struct rt2x00_dev *rt2x00dev)
+{
+ rt2x00dev->csr_cache = kzalloc(CSR_CACHE_SIZE, GFP_KERNEL);
+ if (!rt2x00dev->csr_cache)
+ goto exit;
+
+ rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
+ if (!rt2x00dev->eeprom)
+ goto exit;
+
+ rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
+ if (!rt2x00dev->rf)
+ goto exit;
+
+ return 0;
+
+exit:
+ ERROR_PROBE("Failed to allocate registers.\n");
+
+ rt2x00usb_free_reg(rt2x00dev);
+
+ return -ENOMEM;
+}
+
+int rt2x00usb_probe(struct usb_interface *usb_intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usb_dev = interface_to_usbdev(usb_intf);
+ struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_info;
+ struct ieee80211_hw *hw;
+ struct rt2x00_dev *rt2x00dev;
+ int retval;
+
+ usb_dev = usb_get_dev(usb_dev);
+
+ hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
+ if (!hw) {
+ ERROR_PROBE("Failed to allocate hardware.\n");
+ retval = -ENOMEM;
+ goto exit_put_device;
+ }
+
+ usb_set_intfdata(usb_intf, hw);
+
+ rt2x00dev = hw->priv;
+ rt2x00dev->dev = usb_intf;
+ rt2x00dev->ops = ops;
+ rt2x00dev->hw = hw;
+
+ retval = rt2x00usb_alloc_reg(rt2x00dev);
+ if (retval)
+ goto exit_free_device;
+
+ retval = rt2x00lib_probe_dev(rt2x00dev);
+ if (retval)
+ goto exit_free_reg;
+
+ return 0;
+
+exit_free_reg:
+ rt2x00usb_free_reg(rt2x00dev);
+
+exit_free_device:
+ ieee80211_free_hw(hw);
+
+exit_put_device:
+ usb_put_dev(usb_dev);
+
+ usb_set_intfdata(usb_intf, NULL);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_probe);
+
+void rt2x00usb_disconnect(struct usb_interface *usb_intf)
+{
+ struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * Free all allocated data.
+ */
+ rt2x00lib_remove_dev(rt2x00dev);
+ rt2x00usb_free_reg(rt2x00dev);
+ ieee80211_free_hw(hw);
+
+ /*
+ * Free the USB device data.
+ */
+ usb_set_intfdata(usb_intf, NULL);
+ usb_put_dev(interface_to_usbdev(usb_intf));
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_disconnect);
+
+#ifdef CONFIG_PM
+int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state)
+{
+ struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int retval;
+
+ retval = rt2x00lib_suspend(rt2x00dev, state);
+ if (retval)
+ return retval;
+
+ rt2x00usb_free_reg(rt2x00dev);
+
+ /*
+ * Decrease usbdev refcount.
+ */
+ usb_put_dev(interface_to_usbdev(usb_intf));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_suspend);
+
+int rt2x00usb_resume(struct usb_interface *usb_intf)
+{
+ struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int retval;
+
+ usb_get_dev(interface_to_usbdev(usb_intf));
+
+ retval = rt2x00usb_alloc_reg(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt2x00lib_resume(rt2x00dev);
+ if (retval)
+ goto exit_free_reg;
+
+ return 0;
+
+exit_free_reg:
+ rt2x00usb_free_reg(rt2x00dev);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_resume);
+#endif /* CONFIG_PM */
+
+/*
+ * rt2x00pci module information.
+ */
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("rt2x00 library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
new file mode 100644
index 00000000000..2681abe4d49
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -0,0 +1,180 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt2x00usb
+ Abstract: Data structures for the rt2x00usb module.
+ */
+
+#ifndef RT2X00USB_H
+#define RT2X00USB_H
+
+/*
+ * This variable should be used with the
+ * usb_driver structure initialization.
+ */
+#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops)
+
+/*
+ * Register defines.
+ * Some registers require multiple attempts before success,
+ * in those cases REGISTER_BUSY_COUNT attempts should be
+ * taken with a REGISTER_BUSY_DELAY interval.
+ * For USB vendor requests we need to pass a timeout
+ * time in ms, for this we use the REGISTER_TIMEOUT,
+ * however when loading firmware a higher value is
+ * required. In that case we use the REGISTER_TIMEOUT_FIRMWARE.
+ */
+#define REGISTER_BUSY_COUNT 5
+#define REGISTER_BUSY_DELAY 100
+#define REGISTER_TIMEOUT 500
+#define REGISTER_TIMEOUT_FIRMWARE 1000
+
+/*
+ * Cache size
+ */
+#define CSR_CACHE_SIZE 8
+#define CSR_CACHE_SIZE_FIRMWARE 64
+
+/*
+ * USB request types.
+ */
+#define USB_VENDOR_REQUEST ( USB_TYPE_VENDOR | USB_RECIP_DEVICE )
+#define USB_VENDOR_REQUEST_IN ( USB_DIR_IN | USB_VENDOR_REQUEST )
+#define USB_VENDOR_REQUEST_OUT ( USB_DIR_OUT | USB_VENDOR_REQUEST )
+
+/*
+ * USB vendor commands.
+ */
+#define USB_DEVICE_MODE 0x01
+#define USB_SINGLE_WRITE 0x02
+#define USB_SINGLE_READ 0x03
+#define USB_MULTI_WRITE 0x06
+#define USB_MULTI_READ 0x07
+#define USB_EEPROM_WRITE 0x08
+#define USB_EEPROM_READ 0x09
+#define USB_LED_CONTROL 0x0a /* RT73USB */
+#define USB_RX_CONTROL 0x0c
+
+/*
+ * Device modes offset
+ */
+#define USB_MODE_RESET 0x01
+#define USB_MODE_UNPLUG 0x02
+#define USB_MODE_FUNCTION 0x03
+#define USB_MODE_TEST 0x04
+#define USB_MODE_SLEEP 0x07 /* RT73USB */
+#define USB_MODE_FIRMWARE 0x08 /* RT73USB */
+#define USB_MODE_WAKEUP 0x09 /* RT73USB */
+
+/*
+ * Used to read/write from/to the device.
+ * This is the main function to communicate with the device,
+ * the buffer argument _must_ either be NULL or point to
+ * a buffer allocated by kmalloc. Failure to do so can lead
+ * to unexpected behavior depending on the architecture.
+ */
+int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev,
+ const u8 request, const u8 requesttype,
+ const u16 offset, const u16 value,
+ void *buffer, const u16 buffer_length,
+ const int timeout);
+
+/*
+ * Used to read/write from/to the device.
+ * This function will use a previously with kmalloc allocated cache
+ * to communicate with the device. The contents of the buffer pointer
+ * will be copied to this cache when writing, or read from the cache
+ * when reading.
+ * Buffers send to rt2x00usb_vendor_request _must_ be allocated with
+ * kmalloc. Hence the reason for using a previously allocated cache
+ * which has been allocated properly.
+ */
+int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev,
+ const u8 request, const u8 requesttype,
+ const u16 offset, void *buffer,
+ const u16 buffer_length, const int timeout);
+
+/*
+ * Simple wrapper around rt2x00usb_vendor_request to write a single
+ * command to the device. Since we don't use the buffer argument we
+ * don't have to worry about kmalloc here.
+ */
+static inline int rt2x00usb_vendor_request_sw(const struct rt2x00_dev
+ *rt2x00dev,
+ const u8 request,
+ const u16 offset,
+ const u16 value,
+ const int timeout)
+{
+ return rt2x00usb_vendor_request(rt2x00dev, request,
+ USB_VENDOR_REQUEST_OUT, offset,
+ value, NULL, 0, timeout);
+}
+
+/*
+ * Simple wrapper around rt2x00usb_vendor_request to read the eeprom
+ * from the device. Note that the eeprom argument _must_ be allocated using
+ * kmalloc for correct handling inside the kernel USB layer.
+ */
+static inline int rt2x00usb_eeprom_read(const struct rt2x00_dev *rt2x00dev,
+ __le16 *eeprom, const u16 lenght)
+{
+ int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16));
+
+ return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ,
+ USB_VENDOR_REQUEST_IN, 0x0000,
+ 0x0000, eeprom, lenght, timeout);
+}
+
+/*
+ * Radio handlers
+ */
+void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev);
+void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * TX data handlers.
+ */
+int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
+ struct data_ring *ring, struct sk_buff *skb,
+ struct ieee80211_tx_control *control);
+
+/*
+ * Device initialization handlers.
+ */
+int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev);
+void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * USB driver handlers.
+ */
+int rt2x00usb_probe(struct usb_interface *usb_intf,
+ const struct usb_device_id *id);
+void rt2x00usb_disconnect(struct usb_interface *usb_intf);
+#ifdef CONFIG_PM
+int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state);
+int rt2x00usb_resume(struct usb_interface *usb_intf);
+#else
+#define rt2x00usb_suspend NULL
+#define rt2x00usb_resume NULL
+#endif /* CONFIG_PM */
+
+#endif /* RT2X00USB_H */
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
new file mode 100644
index 00000000000..01dbef19d65
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -0,0 +1,2557 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt61pci
+ Abstract: rt61pci device specific routines.
+ Supported chipsets: RT2561, RT2561s, RT2661.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt61pci"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/eeprom_93cx6.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+#include "rt61pci.h"
+
+/*
+ * Register access.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static u32 rt61pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, PHY_CSR3, &reg);
+ if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+ break;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ return reg;
+}
+
+static void rt61pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt61pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
+ return;
+ }
+
+ /*
+ * Write the data into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
+
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+}
+
+static void rt61pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt61pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+ return;
+ }
+
+ /*
+ * Write the request into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt61pci_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+ *value = 0xff;
+ return;
+ }
+
+ *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
+}
+
+static void rt61pci_rf_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u32 value)
+{
+ u32 reg;
+ unsigned int i;
+
+ if (!word)
+ return;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, PHY_CSR4, &reg);
+ if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
+ goto rf_write;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
+ return;
+
+rf_write:
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+ rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS, 21);
+ rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+static void rt61pci_mcu_request(const struct rt2x00_dev *rt2x00dev,
+ const u8 command, const u8 token,
+ const u8 arg0, const u8 arg1)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, &reg);
+
+ if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) {
+ ERROR(rt2x00dev, "mcu request error. "
+ "Request 0x%02x failed for token 0x%02x.\n",
+ command, token);
+ return;
+ }
+
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
+ rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
+ rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
+ rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
+ rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
+}
+
+static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+
+ eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN);
+ eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT);
+ eeprom->reg_data_clock =
+ !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_CLOCK);
+ eeprom->reg_chip_select =
+ !!rt2x00_get_field32(reg, E2PROM_CSR_CHIP_SELECT);
+}
+
+static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
+{
+ struct rt2x00_dev *rt2x00dev = eeprom->data;
+ u32 reg = 0;
+
+ rt2x00_set_field32(&reg, E2PROM_CSR_DATA_IN, !!eeprom->reg_data_in);
+ rt2x00_set_field32(&reg, E2PROM_CSR_DATA_OUT, !!eeprom->reg_data_out);
+ rt2x00_set_field32(&reg, E2PROM_CSR_DATA_CLOCK,
+ !!eeprom->reg_data_clock);
+ rt2x00_set_field32(&reg, E2PROM_CSR_CHIP_SELECT,
+ !!eeprom->reg_chip_select);
+
+ rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
+
+static void rt61pci_read_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 *data)
+{
+ rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static void rt61pci_write_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 data)
+{
+ rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt61pci_rt2x00debug = {
+ .owner = THIS_MODULE,
+ .csr = {
+ .read = rt61pci_read_csr,
+ .write = rt61pci_write_csr,
+ .word_size = sizeof(u32),
+ .word_count = CSR_REG_SIZE / sizeof(u32),
+ },
+ .eeprom = {
+ .read = rt2x00_eeprom_read,
+ .write = rt2x00_eeprom_write,
+ .word_size = sizeof(u16),
+ .word_count = EEPROM_SIZE / sizeof(u16),
+ },
+ .bbp = {
+ .read = rt61pci_bbp_read,
+ .write = rt61pci_bbp_write,
+ .word_size = sizeof(u8),
+ .word_count = BBP_SIZE / sizeof(u8),
+ },
+ .rf = {
+ .read = rt2x00_rf_read,
+ .write = rt61pci_rf_write,
+ .word_size = sizeof(u32),
+ .word_count = RF_SIZE / sizeof(u32),
+ },
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+#ifdef CONFIG_RT61PCI_RFKILL
+static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
+ return rt2x00_get_field32(reg, MAC_CSR13_BIT5);;
+}
+#else
+#define rt61pci_rfkill_poll NULL
+#endif /* CONFIG_RT61PCI_RFKILL */
+
+/*
+ * Configuration handlers.
+ */
+static void rt61pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac)
+{
+ u32 tmp;
+
+ tmp = le32_to_cpu(mac[1]);
+ rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
+ mac[1] = cpu_to_le32(tmp);
+
+ rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2, mac,
+ (2 * sizeof(__le32)));
+}
+
+static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid)
+{
+ u32 tmp;
+
+ tmp = le32_to_cpu(bssid[1]);
+ rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3);
+ bssid[1] = cpu_to_le32(tmp);
+
+ rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, bssid,
+ (2 * sizeof(__le32)));
+}
+
+static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+ const int tsf_sync)
+{
+ u32 reg;
+
+ /*
+ * Clear current synchronisation setup.
+ * For the Beacon base registers we only need to clear
+ * the first byte since that byte contains the VALID and OWNER
+ * bits which (when set to 0) will invalidate the entire beacon.
+ */
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+ rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+
+ /*
+ * Enable synchronisation.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, tsf_sync);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+}
+
+static void rt61pci_config_preamble(struct rt2x00_dev *rt2x00dev,
+ const int short_preamble,
+ const int ack_timeout,
+ const int ack_consume_time)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
+ !!short_preamble);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
+
+static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev,
+ const int basic_rate_mask)
+{
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
+}
+
+static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf, const int txpower)
+{
+ u8 r3;
+ u8 r94;
+ u8 smart;
+
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+ rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+ smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+ rt61pci_bbp_read(rt2x00dev, 3, &r3);
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+ rt61pci_bbp_write(rt2x00dev, 3, r3);
+
+ r94 = 6;
+ if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+ r94 += txpower - MAX_TXPOWER;
+ else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+ r94 += txpower;
+ rt61pci_bbp_write(rt2x00dev, 94, r94);
+
+ rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ udelay(200);
+
+ rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+ rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ udelay(200);
+
+ rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+ rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+ rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+ msleep(1);
+}
+
+static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev,
+ const int txpower)
+{
+ struct rf_channel rf;
+
+ rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+ rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+ rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+ rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+ rt61pci_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx,
+ const int antenna_rx)
+{
+ u8 r3;
+ u8 r4;
+ u8 r77;
+
+ rt61pci_bbp_read(rt2x00dev, 3, &r3);
+ rt61pci_bbp_read(rt2x00dev, 4, &r4);
+ rt61pci_bbp_read(rt2x00dev, 77, &r77);
+
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
+ !rt2x00_rf(&rt2x00dev->chip, RF5225));
+
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
+ !!(rt2x00dev->curr_hwmode != HWMODE_A));
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+ if (rt2x00dev->curr_hwmode == HWMODE_A)
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ else
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+ if (rt2x00dev->curr_hwmode == HWMODE_A)
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ else
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ break;
+ }
+
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ rt61pci_bbp_write(rt2x00dev, 3, r3);
+ rt61pci_bbp_write(rt2x00dev, 4, r4);
+}
+
+static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx,
+ const int antenna_rx)
+{
+ u8 r3;
+ u8 r4;
+ u8 r77;
+
+ rt61pci_bbp_read(rt2x00dev, 3, &r3);
+ rt61pci_bbp_read(rt2x00dev, 4, &r4);
+ rt61pci_bbp_read(rt2x00dev, 77, &r77);
+
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
+ !rt2x00_rf(&rt2x00dev->chip, RF2527));
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
+ !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
+
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ break;
+ }
+
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ rt61pci_bbp_write(rt2x00dev, 3, r3);
+ rt61pci_bbp_write(rt2x00dev, 4, r4);
+}
+
+static void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev,
+ const int p1, const int p2)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
+
+ if (p1 != 0xff) {
+ rt2x00_set_field32(&reg, MAC_CSR13_BIT4, !!p1);
+ rt2x00_set_field32(&reg, MAC_CSR13_BIT12, 0);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg);
+ }
+ if (p2 != 0xff) {
+ rt2x00_set_field32(&reg, MAC_CSR13_BIT3, !p2);
+ rt2x00_set_field32(&reg, MAC_CSR13_BIT11, 0);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg);
+ }
+}
+
+static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx,
+ const int antenna_rx)
+{
+ u16 eeprom;
+ u8 r3;
+ u8 r4;
+ u8 r77;
+
+ rt61pci_bbp_read(rt2x00dev, 3, &r3);
+ rt61pci_bbp_read(rt2x00dev, 4, &r4);
+ rt61pci_bbp_read(rt2x00dev, 77, &r77);
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
+
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) &&
+ rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) {
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 1);
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1);
+ } else if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY)) {
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED) >= 2) {
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ }
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
+ } else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) &&
+ rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) {
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+ switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) {
+ case 0:
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1);
+ break;
+ case 1:
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0);
+ break;
+ case 2:
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0);
+ break;
+ case 3:
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
+ break;
+ }
+ } else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) &&
+ !rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) {
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+ switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) {
+ case 0:
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1);
+ break;
+ case 1:
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0);
+ break;
+ case 2:
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0);
+ break;
+ case 3:
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ rt61pci_bbp_write(rt2x00dev, 77, r77);
+ rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
+ break;
+ }
+ }
+
+ rt61pci_bbp_write(rt2x00dev, 3, r3);
+ rt61pci_bbp_write(rt2x00dev, 4, r4);
+}
+
+struct antenna_sel {
+ u8 word;
+ /*
+ * value[0] -> non-LNA
+ * value[1] -> LNA
+ */
+ u8 value[2];
+};
+
+static const struct antenna_sel antenna_sel_a[] = {
+ { 96, { 0x58, 0x78 } },
+ { 104, { 0x38, 0x48 } },
+ { 75, { 0xfe, 0x80 } },
+ { 86, { 0xfe, 0x80 } },
+ { 88, { 0xfe, 0x80 } },
+ { 35, { 0x60, 0x60 } },
+ { 97, { 0x58, 0x58 } },
+ { 98, { 0x58, 0x58 } },
+};
+
+static const struct antenna_sel antenna_sel_bg[] = {
+ { 96, { 0x48, 0x68 } },
+ { 104, { 0x2c, 0x3c } },
+ { 75, { 0xfe, 0x80 } },
+ { 86, { 0xfe, 0x80 } },
+ { 88, { 0xfe, 0x80 } },
+ { 35, { 0x50, 0x50 } },
+ { 97, { 0x48, 0x48 } },
+ { 98, { 0x48, 0x48 } },
+};
+
+static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx, const int antenna_rx)
+{
+ const struct antenna_sel *sel;
+ unsigned int lna;
+ unsigned int i;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, PHY_CSR0, &reg);
+
+ if (rt2x00dev->curr_hwmode == HWMODE_A) {
+ sel = antenna_sel_a;
+ lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 0);
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 1);
+ } else {
+ sel = antenna_sel_bg;
+ lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 1);
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 0);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
+ rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
+
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg);
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF5325))
+ rt61pci_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx);
+ else if (rt2x00_rf(&rt2x00dev->chip, RF2527))
+ rt61pci_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx);
+ else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) {
+ if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags))
+ rt61pci_config_antenna_2x(rt2x00dev, antenna_tx,
+ antenna_rx);
+ else
+ rt61pci_config_antenna_2529(rt2x00dev, antenna_tx,
+ antenna_rx);
+ }
+}
+
+static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+ rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
+ libconf->conf->beacon_int * 16);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+}
+
+static void rt61pci_config(struct rt2x00_dev *rt2x00dev,
+ const unsigned int flags,
+ struct rt2x00lib_conf *libconf)
+{
+ if (flags & CONFIG_UPDATE_PHYMODE)
+ rt61pci_config_phymode(rt2x00dev, libconf->basic_rates);
+ if (flags & CONFIG_UPDATE_CHANNEL)
+ rt61pci_config_channel(rt2x00dev, &libconf->rf,
+ libconf->conf->power_level);
+ if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+ rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level);
+ if (flags & CONFIG_UPDATE_ANTENNA)
+ rt61pci_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx,
+ libconf->conf->antenna_sel_rx);
+ if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ rt61pci_config_duration(rt2x00dev, libconf);
+}
+
+/*
+ * LED functions.
+ */
+static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 led_reg;
+ u8 arg0;
+ u8 arg1;
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR14, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR14_ON_PERIOD, 70);
+ rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, 30);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR14, reg);
+
+ led_reg = rt2x00dev->led_reg;
+ rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 1);
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)
+ rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 1);
+ else
+ rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 1);
+
+ arg0 = led_reg & 0xff;
+ arg1 = (led_reg >> 8) & 0xff;
+
+ rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1);
+}
+
+static void rt61pci_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u16 led_reg;
+ u8 arg0;
+ u8 arg1;
+
+ led_reg = rt2x00dev->led_reg;
+ rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 0);
+ rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 0);
+ rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 0);
+
+ arg0 = led_reg & 0xff;
+ arg1 = (led_reg >> 8) & 0xff;
+
+ rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1);
+}
+
+static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, int rssi)
+{
+ u8 led;
+
+ if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH)
+ return;
+
+ /*
+ * Led handling requires a positive value for the rssi,
+ * to do that correctly we need to add the correction.
+ */
+ rssi += rt2x00dev->rssi_offset;
+
+ if (rssi <= 30)
+ led = 0;
+ else if (rssi <= 39)
+ led = 1;
+ else if (rssi <= 49)
+ led = 2;
+ else if (rssi <= 53)
+ led = 3;
+ else if (rssi <= 63)
+ led = 4;
+ else
+ led = 5;
+
+ rt61pci_mcu_request(rt2x00dev, MCU_LED_STRENGTH, 0xff, led, 0);
+}
+
+/*
+ * Link tuning
+ */
+static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Update FCS error count from register.
+ */
+ rt2x00pci_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
+
+ /*
+ * Update False CCA count from register.
+ */
+ rt2x00pci_register_read(rt2x00dev, STA_CSR1, &reg);
+ rt2x00dev->link.false_cca =
+ rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
+}
+
+static void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ rt61pci_bbp_write(rt2x00dev, 17, 0x20);
+ rt2x00dev->link.vgc_level = 0x20;
+}
+
+static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
+ u8 r17;
+ u8 up_bound;
+ u8 low_bound;
+
+ /*
+ * Update Led strength
+ */
+ rt61pci_activity_led(rt2x00dev, rssi);
+
+ rt61pci_bbp_read(rt2x00dev, 17, &r17);
+
+ /*
+ * Determine r17 bounds.
+ */
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ low_bound = 0x28;
+ up_bound = 0x48;
+ if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+ low_bound += 0x10;
+ up_bound += 0x10;
+ }
+ } else {
+ low_bound = 0x20;
+ up_bound = 0x40;
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) {
+ low_bound += 0x10;
+ up_bound += 0x10;
+ }
+ }
+
+ /*
+ * Special big-R17 for very short distance
+ */
+ if (rssi >= -35) {
+ if (r17 != 0x60)
+ rt61pci_bbp_write(rt2x00dev, 17, 0x60);
+ return;
+ }
+
+ /*
+ * Special big-R17 for short distance
+ */
+ if (rssi >= -58) {
+ if (r17 != up_bound)
+ rt61pci_bbp_write(rt2x00dev, 17, up_bound);
+ return;
+ }
+
+ /*
+ * Special big-R17 for middle-short distance
+ */
+ if (rssi >= -66) {
+ low_bound += 0x10;
+ if (r17 != low_bound)
+ rt61pci_bbp_write(rt2x00dev, 17, low_bound);
+ return;
+ }
+
+ /*
+ * Special mid-R17 for middle distance
+ */
+ if (rssi >= -74) {
+ low_bound += 0x08;
+ if (r17 != low_bound)
+ rt61pci_bbp_write(rt2x00dev, 17, low_bound);
+ return;
+ }
+
+ /*
+ * Special case: Change up_bound based on the rssi.
+ * Lower up_bound when rssi is weaker then -74 dBm.
+ */
+ up_bound -= 2 * (-74 - rssi);
+ if (low_bound > up_bound)
+ up_bound = low_bound;
+
+ if (r17 > up_bound) {
+ rt61pci_bbp_write(rt2x00dev, 17, up_bound);
+ return;
+ }
+
+ /*
+ * r17 does not yet exceed upper limit, continue and base
+ * the r17 tuning on the false CCA count.
+ */
+ if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) {
+ if (++r17 > up_bound)
+ r17 = up_bound;
+ rt61pci_bbp_write(rt2x00dev, 17, r17);
+ } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
+ if (--r17 < low_bound)
+ r17 = low_bound;
+ rt61pci_bbp_write(rt2x00dev, 17, r17);
+ }
+}
+
+/*
+ * Firmware name function.
+ */
+static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
+{
+ char *fw_name;
+
+ switch (rt2x00dev->chip.rt) {
+ case RT2561:
+ fw_name = FIRMWARE_RT2561;
+ break;
+ case RT2561s:
+ fw_name = FIRMWARE_RT2561s;
+ break;
+ case RT2661:
+ fw_name = FIRMWARE_RT2661;
+ break;
+ default:
+ fw_name = NULL;
+ break;
+ }
+
+ return fw_name;
+}
+
+/*
+ * Initialization functions.
+ */
+static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
+ const size_t len)
+{
+ int i;
+ u32 reg;
+
+ /*
+ * Wait for stable hardware.
+ */
+ for (i = 0; i < 100; i++) {
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
+ if (reg)
+ break;
+ msleep(1);
+ }
+
+ if (!reg) {
+ ERROR(rt2x00dev, "Unstable hardware.\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Prepare MCU and mailbox for firmware loading.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 1);
+ rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+ rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, 0);
+
+ /*
+ * Write firmware to device.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 1);
+ rt2x00_set_field32(&reg, MCU_CNTL_CSR_SELECT_BANK, 1);
+ rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+
+ rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+ data, len);
+
+ rt2x00_set_field32(&reg, MCU_CNTL_CSR_SELECT_BANK, 0);
+ rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+
+ rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 0);
+ rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+
+ for (i = 0; i < 100; i++) {
+ rt2x00pci_register_read(rt2x00dev, MCU_CNTL_CSR, &reg);
+ if (rt2x00_get_field32(reg, MCU_CNTL_CSR_READY))
+ break;
+ msleep(1);
+ }
+
+ if (i == 100) {
+ ERROR(rt2x00dev, "MCU Control register not ready.\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Reset MAC and BBP registers.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
+ rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
+ rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ return 0;
+}
+
+static void rt61pci_init_rxring(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring = rt2x00dev->rx;
+ struct data_desc *rxd;
+ unsigned int i;
+ u32 word;
+
+ memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ rxd = ring->entry[i].priv;
+
+ rt2x00_desc_read(rxd, 5, &word);
+ rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
+ ring->entry[i].data_dma);
+ rt2x00_desc_write(rxd, 5, word);
+
+ rt2x00_desc_read(rxd, 0, &word);
+ rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+ rt2x00_desc_write(rxd, 0, word);
+ }
+
+ rt2x00_ring_index_clear(rt2x00dev->rx);
+}
+
+static void rt61pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+ struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+ struct data_desc *txd;
+ unsigned int i;
+ u32 word;
+
+ memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+ for (i = 0; i < ring->stats.limit; i++) {
+ txd = ring->entry[i].priv;
+
+ rt2x00_desc_read(txd, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 5, &word);
+ rt2x00_set_field32(&word, TXD_W5_PID_TYPE, queue);
+ rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, i);
+ rt2x00_desc_write(txd, 5, word);
+
+ rt2x00_desc_read(txd, 6, &word);
+ rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
+ ring->entry[i].data_dma);
+ rt2x00_desc_write(txd, 6, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+ rt2x00_desc_write(txd, 0, word);
+ }
+
+ rt2x00_ring_index_clear(ring);
+}
+
+static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Initialize rings.
+ */
+ rt61pci_init_rxring(rt2x00dev);
+ rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+ rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+ rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA2);
+ rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA3);
+ rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA4);
+
+ /*
+ * Initialize registers.
+ */
+ rt2x00pci_register_read(rt2x00dev, TX_RING_CSR0, &reg);
+ rt2x00_set_field32(&reg, TX_RING_CSR0_AC0_RING_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit);
+ rt2x00_set_field32(&reg, TX_RING_CSR0_AC1_RING_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit);
+ rt2x00_set_field32(&reg, TX_RING_CSR0_AC2_RING_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].stats.limit);
+ rt2x00_set_field32(&reg, TX_RING_CSR0_AC3_RING_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].stats.limit);
+ rt2x00pci_register_write(rt2x00dev, TX_RING_CSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_RING_CSR1, &reg);
+ rt2x00_set_field32(&reg, TX_RING_CSR1_MGMT_RING_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].stats.limit);
+ rt2x00_set_field32(&reg, TX_RING_CSR1_TXD_SIZE,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size /
+ 4);
+ rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, &reg);
+ rt2x00_set_field32(&reg, AC0_BASE_CSR_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma);
+ rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, &reg);
+ rt2x00_set_field32(&reg, AC1_BASE_CSR_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma);
+ rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, &reg);
+ rt2x00_set_field32(&reg, AC2_BASE_CSR_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].data_dma);
+ rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, &reg);
+ rt2x00_set_field32(&reg, AC3_BASE_CSR_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].data_dma);
+ rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MGMT_BASE_CSR, &reg);
+ rt2x00_set_field32(&reg, MGMT_BASE_CSR_RING_REGISTER,
+ rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].data_dma);
+ rt2x00pci_register_write(rt2x00dev, MGMT_BASE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, &reg);
+ rt2x00_set_field32(&reg, RX_RING_CSR_RING_SIZE,
+ rt2x00dev->rx->stats.limit);
+ rt2x00_set_field32(&reg, RX_RING_CSR_RXD_SIZE,
+ rt2x00dev->rx->desc_size / 4);
+ rt2x00_set_field32(&reg, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4);
+ rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, &reg);
+ rt2x00_set_field32(&reg, RX_BASE_CSR_RING_REGISTER,
+ rt2x00dev->rx->data_dma);
+ rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC0, 2);
+ rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC1, 2);
+ rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC2, 2);
+ rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC3, 2);
+ rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_MGMT, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DMA_DST_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, LOAD_TX_RING_CSR, &reg);
+ rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC0, 1);
+ rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1);
+ rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1);
+ rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1);
+ rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_MGMT, 1);
+ rt2x00pci_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, RX_CNTL_CSR_LOAD_RXD, 1);
+ rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg);
+
+ return 0;
+}
+
+static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR1, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1, 30); /* Rssi */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2, 42); /* OFDM Rate */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3_VALID, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR1, reg);
+
+ /*
+ * CCK TXD BBP registers
+ */
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0, 13);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1, 12);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2, 11);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3_VALID, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR2, reg);
+
+ /*
+ * OFDM TXD BBP registers
+ */
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR3, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0, 7);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1, 6);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2, 5);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2_VALID, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR3, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR7, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_6MBS, 59);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_9MBS, 53);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_12MBS, 49);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_18MBS, 46);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR7, reg);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR8, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_24MBS, 44);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_36MBS, 42);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_48MBS, 42);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR8, reg);
+
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
+
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR6, 0x00000fff);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
+
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x0000071c);
+
+ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+ return -EBUSY;
+
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR13, 0x0000e000);
+
+ /*
+ * Invalidate all Shared Keys (SEC_CSR0),
+ * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
+ */
+ rt2x00pci_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
+ rt2x00pci_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
+ rt2x00pci_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
+
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR1, 0x000023b0);
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR5, 0x060a100c);
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
+ rt2x00pci_register_write(rt2x00dev, PHY_CSR7, 0x00000a08);
+
+ rt2x00pci_register_write(rt2x00dev, PCI_CFG_CSR, 0x28ca4404);
+
+ rt2x00pci_register_write(rt2x00dev, TEST_MODE_CSR, 0x00000200);
+
+ rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
+
+ rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC0_TX_OP, 0);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC1_TX_OP, 0);
+ rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
+
+ rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC2_TX_OP, 192);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC3_TX_OP, 48);
+ rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
+
+ /*
+ * We must clear the error counters.
+ * These registers are cleared on read,
+ * so we may pass a useless variable to store the value.
+ */
+ rt2x00pci_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00pci_register_read(rt2x00dev, STA_CSR1, &reg);
+ rt2x00pci_register_read(rt2x00dev, STA_CSR2, &reg);
+
+ /*
+ * Reset MAC and BBP registers.
+ */
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
+ rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
+ rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ return 0;
+}
+
+static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u16 eeprom;
+ u8 reg_id;
+ u8 value;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt61pci_bbp_read(rt2x00dev, 0, &value);
+ if ((value != 0xff) && (value != 0x00))
+ goto continue_csr_init;
+ NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ return -EACCES;
+
+continue_csr_init:
+ rt61pci_bbp_write(rt2x00dev, 3, 0x00);
+ rt61pci_bbp_write(rt2x00dev, 15, 0x30);
+ rt61pci_bbp_write(rt2x00dev, 21, 0xc8);
+ rt61pci_bbp_write(rt2x00dev, 22, 0x38);
+ rt61pci_bbp_write(rt2x00dev, 23, 0x06);
+ rt61pci_bbp_write(rt2x00dev, 24, 0xfe);
+ rt61pci_bbp_write(rt2x00dev, 25, 0x0a);
+ rt61pci_bbp_write(rt2x00dev, 26, 0x0d);
+ rt61pci_bbp_write(rt2x00dev, 34, 0x12);
+ rt61pci_bbp_write(rt2x00dev, 37, 0x07);
+ rt61pci_bbp_write(rt2x00dev, 39, 0xf8);
+ rt61pci_bbp_write(rt2x00dev, 41, 0x60);
+ rt61pci_bbp_write(rt2x00dev, 53, 0x10);
+ rt61pci_bbp_write(rt2x00dev, 54, 0x18);
+ rt61pci_bbp_write(rt2x00dev, 60, 0x10);
+ rt61pci_bbp_write(rt2x00dev, 61, 0x04);
+ rt61pci_bbp_write(rt2x00dev, 62, 0x04);
+ rt61pci_bbp_write(rt2x00dev, 75, 0xfe);
+ rt61pci_bbp_write(rt2x00dev, 86, 0xfe);
+ rt61pci_bbp_write(rt2x00dev, 88, 0xfe);
+ rt61pci_bbp_write(rt2x00dev, 90, 0x0f);
+ rt61pci_bbp_write(rt2x00dev, 99, 0x00);
+ rt61pci_bbp_write(rt2x00dev, 102, 0x16);
+ rt61pci_bbp_write(rt2x00dev, 107, 0x04);
+
+ DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+ for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+ if (eeprom != 0xffff && eeprom != 0x0000) {
+ reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+ DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+ reg_id, value);
+ rt61pci_bbp_write(rt2x00dev, reg_id, value);
+ }
+ }
+ DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+ return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
+ state == STATE_RADIO_RX_OFF);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
+static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int mask = (state == STATE_RADIO_IRQ_OFF);
+ u32 reg;
+
+ /*
+ * When interrupts are being enabled, the interrupt registers
+ * should clear the register to assure a clean state.
+ */
+ if (state == STATE_RADIO_IRQ_ON) {
+ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
+ }
+
+ /*
+ * Only toggle the interrupts bits we are going to use.
+ * Non-checked interrupt bits are disabled by default.
+ */
+ rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_TXDONE, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_RXDONE, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_ENABLE_MITIGATION, mask);
+ rt2x00_set_field32(&reg, INT_MASK_CSR_MITIGATION_PERIOD, 0xff);
+ rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
+
+ rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_0, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_1, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_2, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_3, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_4, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_5, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_6, mask);
+ rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_7, mask);
+ rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
+}
+
+static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Initialize all registers.
+ */
+ if (rt61pci_init_rings(rt2x00dev) ||
+ rt61pci_init_registers(rt2x00dev) ||
+ rt61pci_init_bbp(rt2x00dev)) {
+ ERROR(rt2x00dev, "Register initialization failed.\n");
+ return -EIO;
+ }
+
+ /*
+ * Enable interrupts.
+ */
+ rt61pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON);
+
+ /*
+ * Enable RX.
+ */
+ rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, RX_CNTL_CSR_ENABLE_RX_DMA, 1);
+ rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg);
+
+ /*
+ * Enable LED
+ */
+ rt61pci_enable_led(rt2x00dev);
+
+ return 0;
+}
+
+static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Disable LED
+ */
+ rt61pci_disable_led(rt2x00dev);
+
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
+
+ /*
+ * Disable synchronisation.
+ */
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0);
+
+ /*
+ * Cancel RX and TX.
+ */
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, 1);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, 1);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, 1);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, 1);
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_MGMT, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+
+ /*
+ * Disable interrupts.
+ */
+ rt61pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF);
+}
+
+static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
+{
+ u32 reg;
+ unsigned int i;
+ char put_to_sleep;
+ char current_state;
+
+ put_to_sleep = (state != STATE_AWAKE);
+
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR12, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep);
+ rt2x00_set_field32(&reg, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep);
+ rt2x00pci_register_write(rt2x00dev, MAC_CSR12, reg);
+
+ /*
+ * Device is not guaranteed to be in the requested state yet.
+ * We must wait until the register indicates that the
+ * device has entered the correct state.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR12, &reg);
+ current_state =
+ rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE);
+ if (current_state == !put_to_sleep)
+ return 0;
+ msleep(10);
+ }
+
+ NOTICE(rt2x00dev, "Device failed to enter state %d, "
+ "current device state %d.\n", !put_to_sleep, current_state);
+
+ return -EBUSY;
+}
+
+static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int retval = 0;
+
+ switch (state) {
+ case STATE_RADIO_ON:
+ retval = rt61pci_enable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_OFF:
+ rt61pci_disable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_OFF:
+ rt61pci_toggle_rx(rt2x00dev, state);
+ break;
+ case STATE_DEEP_SLEEP:
+ case STATE_SLEEP:
+ case STATE_STANDBY:
+ case STATE_AWAKE:
+ retval = rt61pci_set_state(rt2x00dev, state);
+ break;
+ default:
+ retval = -ENOTSUPP;
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct txdata_entry_desc *desc,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control)
+{
+ u32 word;
+
+ /*
+ * Start writing the descriptor words.
+ */
+ rt2x00_desc_read(txd, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue);
+ rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs);
+ rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
+ rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
+ rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 5, &word);
+ rt2x00_set_field32(&word, TXD_W5_TX_POWER,
+ TXPOWER_TO_DEV(control->power_level));
+ rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
+ rt2x00_desc_write(txd, 5, word);
+
+ rt2x00_desc_read(txd, 11, &word);
+ rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, length);
+ rt2x00_desc_write(txd, 11, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
+ rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+ rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+ test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_ACK,
+ !(control->flags & IEEE80211_TXCTL_NO_ACK));
+ rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_OFDM,
+ test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+ !!(control->flags &
+ IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+ rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
+ rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+ rt2x00_set_field32(&word, TXD_W0_BURST,
+ test_bit(ENTRY_TXD_BURST, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
+ rt2x00_desc_write(txd, 0, word);
+}
+
+/*
+ * TX data initialization
+ */
+static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ unsigned int queue)
+{
+ u32 reg;
+
+ if (queue == IEEE80211_TX_QUEUE_BEACON) {
+ /*
+ * For Wi-Fi faily generated beacons between participating
+ * stations. Set TBTT phase adaptive adjustment step to 8us.
+ */
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+ }
+ return;
+ }
+
+ rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+ if (queue == IEEE80211_TX_QUEUE_DATA0)
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, 1);
+ else if (queue == IEEE80211_TX_QUEUE_DATA1)
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, 1);
+ else if (queue == IEEE80211_TX_QUEUE_DATA2)
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, 1);
+ else if (queue == IEEE80211_TX_QUEUE_DATA3)
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, 1);
+ else if (queue == IEEE80211_TX_QUEUE_DATA4)
+ rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_MGMT, 1);
+ rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+}
+
+/*
+ * RX control handlers
+ */
+static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
+{
+ u16 eeprom;
+ u8 offset;
+ u8 lna;
+
+ lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA);
+ switch (lna) {
+ case 3:
+ offset = 90;
+ break;
+ case 2:
+ offset = 74;
+ break;
+ case 1:
+ offset = 64;
+ break;
+ default:
+ return 0;
+ }
+
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+ offset += 14;
+
+ if (lna == 3 || lna == 2)
+ offset += 10;
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+ offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+ } else {
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+ offset += 14;
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+ offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+ }
+
+ return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
+}
+
+static void rt61pci_fill_rxdone(struct data_entry *entry,
+ struct rxdata_entry_desc *desc)
+{
+ struct data_desc *rxd = entry->priv;
+ u32 word0;
+ u32 word1;
+
+ rt2x00_desc_read(rxd, 0, &word0);
+ rt2x00_desc_read(rxd, 1, &word1);
+
+ desc->flags = 0;
+ if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+ desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+ desc->rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1);
+ desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+
+ return;
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_ring *ring;
+ struct data_entry *entry;
+ struct data_desc *txd;
+ u32 word;
+ u32 reg;
+ u32 old_reg;
+ int type;
+ int index;
+ int tx_status;
+ int retry;
+
+ /*
+ * During each loop we will compare the freshly read
+ * STA_CSR4 register value with the value read from
+ * the previous loop. If the 2 values are equal then
+ * we should stop processing because the chance it
+ * quite big that the device has been unplugged and
+ * we risk going into an endless loop.
+ */
+ old_reg = 0;
+
+ while (1) {
+ rt2x00pci_register_read(rt2x00dev, STA_CSR4, &reg);
+ if (!rt2x00_get_field32(reg, STA_CSR4_VALID))
+ break;
+
+ if (old_reg == reg)
+ break;
+ old_reg = reg;
+
+ /*
+ * Skip this entry when it contains an invalid
+ * ring identication number.
+ */
+ type = rt2x00_get_field32(reg, STA_CSR4_PID_TYPE);
+ ring = rt2x00lib_get_ring(rt2x00dev, type);
+ if (unlikely(!ring))
+ continue;
+
+ /*
+ * Skip this entry when it contains an invalid
+ * index number.
+ */
+ index = rt2x00_get_field32(reg, STA_CSR4_PID_SUBTYPE);
+ if (unlikely(index >= ring->stats.limit))
+ continue;
+
+ entry = &ring->entry[index];
+ txd = entry->priv;
+ rt2x00_desc_read(txd, 0, &word);
+
+ if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+ !rt2x00_get_field32(word, TXD_W0_VALID))
+ return;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ tx_status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT);
+ retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
+
+ rt2x00lib_txdone(entry, tx_status, retry);
+
+ /*
+ * Make this entry available for reuse.
+ */
+ entry->flags = 0;
+ rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+ rt2x00_desc_write(txd, 0, word);
+ rt2x00_ring_index_done_inc(entry->ring);
+
+ /*
+ * If the data ring was full before the txdone handler
+ * we must make sure the packet queue in the mac80211 stack
+ * is reenabled when the txdone handler has finished.
+ */
+ if (!rt2x00_ring_full(ring))
+ ieee80211_wake_queue(rt2x00dev->hw,
+ entry->tx_status.control.queue);
+ }
+}
+
+static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
+{
+ struct rt2x00_dev *rt2x00dev = dev_instance;
+ u32 reg_mcu;
+ u32 reg;
+
+ /*
+ * Get the interrupt sources & saved to local variable.
+ * Write register value back to clear pending interrupts.
+ */
+ rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg_mcu);
+ rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
+
+ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+
+ if (!reg && !reg_mcu)
+ return IRQ_NONE;
+
+ if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+ return IRQ_HANDLED;
+
+ /*
+ * Handle interrupts, walk through all bits
+ * and run the tasks, the bits are checked in order of
+ * priority.
+ */
+
+ /*
+ * 1 - Rx ring done interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE))
+ rt2x00pci_rxdone(rt2x00dev);
+
+ /*
+ * 2 - Tx ring done interrupt.
+ */
+ if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE))
+ rt61pci_txdone(rt2x00dev);
+
+ /*
+ * 3 - Handle MCU command done.
+ */
+ if (reg_mcu)
+ rt2x00pci_register_write(rt2x00dev,
+ M2H_CMD_DONE_CSR, 0xffffffff);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ struct eeprom_93cx6 eeprom;
+ u32 reg;
+ u16 word;
+ u8 *mac;
+ s8 value;
+
+ rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+
+ eeprom.data = rt2x00dev;
+ eeprom.register_read = rt61pci_eepromregister_read;
+ eeprom.register_write = rt61pci_eepromregister_write;
+ eeprom.width = rt2x00_get_field32(reg, E2PROM_CSR_TYPE_93C46) ?
+ PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+ eeprom.reg_data_in = 0;
+ eeprom.reg_data_out = 0;
+ eeprom.reg_data_clock = 0;
+ eeprom.reg_chip_select = 0;
+
+ eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
+ EEPROM_SIZE / sizeof(u16));
+
+ /*
+ * Start validation of the data that has been read.
+ */
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ DECLARE_MAC_BUF(macbuf);
+
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5225);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_NIC_ENABLE_DIVERSITY, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_TX_DIVERSITY, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_TX_RX_FIXED, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
+ rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+ EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_LED_LED_MODE,
+ LED_MODE_DEFAULT);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word);
+ EEPROM(rt2x00dev, "Led: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
+ rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
+ EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+ EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ } else {
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+ EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ } else {
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+ }
+
+ return 0;
+}
+
+static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 value;
+ u16 eeprom;
+ u16 device;
+
+ /*
+ * Read EEPROM word for configuration.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Identify RF chipset.
+ * To determine the RT chip we have to read the
+ * PCI header of the device.
+ */
+ pci_read_config_word(rt2x00dev_pci(rt2x00dev),
+ PCI_CONFIG_HEADER_DEVICE, &device);
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00_set_chip(rt2x00dev, device, value, reg);
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF5225) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF5325) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2527) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2529)) {
+ ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Identify default antenna configuration.
+ */
+ rt2x00dev->hw->conf.antenna_sel_tx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+ rt2x00dev->hw->conf.antenna_sel_rx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+ /*
+ * Read the Frame type.
+ */
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE))
+ __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
+
+ /*
+ * Determine number of antenna's.
+ */
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
+ __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags);
+
+ /*
+ * Detect if this device has an hardware controlled radio.
+ */
+#ifdef CONFIG_RT61PCI_RFKILL
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
+ __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+#endif /* CONFIG_RT61PCI_RFKILL */
+
+ /*
+ * Read frequency offset and RF programming sequence.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
+ if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ))
+ __set_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags);
+
+ rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
+
+ /*
+ * Read external LNA informations.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
+ __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
+ __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+
+ /*
+ * Store led settings, for correct led behaviour.
+ * If the eeprom value is invalid,
+ * switch to default led mode.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom);
+
+ rt2x00dev->led_mode = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE);
+
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE,
+ rt2x00dev->led_mode);
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_0));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_1));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_2));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_3));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_4));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT,
+ rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_RDY_G));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_RDY_A));
+
+ return 0;
+}
+
+/*
+ * RF value list for RF5225 & RF5325
+ * Supports: 2.4 GHz & 5.2 GHz, rf_sequence disabled
+ */
+static const struct rf_channel rf_vals_noseq[] = {
+ { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b },
+ { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f },
+ { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b },
+ { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f },
+ { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b },
+ { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f },
+ { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b },
+ { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f },
+ { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b },
+ { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f },
+ { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b },
+ { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f },
+ { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b },
+ { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa23 },
+ { 40, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa03 },
+ { 44, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa0b },
+ { 48, 0x00002ccc, 0x000049aa, 0x0009be55, 0x000ffa13 },
+ { 52, 0x00002ccc, 0x000049ae, 0x0009ae55, 0x000ffa1b },
+ { 56, 0x00002ccc, 0x000049b2, 0x0009ae55, 0x000ffa23 },
+ { 60, 0x00002ccc, 0x000049ba, 0x0009ae55, 0x000ffa03 },
+ { 64, 0x00002ccc, 0x000049be, 0x0009ae55, 0x000ffa0b },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x00002ccc, 0x00004a2a, 0x000bae55, 0x000ffa03 },
+ { 104, 0x00002ccc, 0x00004a2e, 0x000bae55, 0x000ffa0b },
+ { 108, 0x00002ccc, 0x00004a32, 0x000bae55, 0x000ffa13 },
+ { 112, 0x00002ccc, 0x00004a36, 0x000bae55, 0x000ffa1b },
+ { 116, 0x00002ccc, 0x00004a3a, 0x000bbe55, 0x000ffa23 },
+ { 120, 0x00002ccc, 0x00004a82, 0x000bbe55, 0x000ffa03 },
+ { 124, 0x00002ccc, 0x00004a86, 0x000bbe55, 0x000ffa0b },
+ { 128, 0x00002ccc, 0x00004a8a, 0x000bbe55, 0x000ffa13 },
+ { 132, 0x00002ccc, 0x00004a8e, 0x000bbe55, 0x000ffa1b },
+ { 136, 0x00002ccc, 0x00004a92, 0x000bbe55, 0x000ffa23 },
+
+ /* 802.11 UNII */
+ { 140, 0x00002ccc, 0x00004a9a, 0x000bbe55, 0x000ffa03 },
+ { 149, 0x00002ccc, 0x00004aa2, 0x000bbe55, 0x000ffa1f },
+ { 153, 0x00002ccc, 0x00004aa6, 0x000bbe55, 0x000ffa27 },
+ { 157, 0x00002ccc, 0x00004aae, 0x000bbe55, 0x000ffa07 },
+ { 161, 0x00002ccc, 0x00004ab2, 0x000bbe55, 0x000ffa0f },
+ { 165, 0x00002ccc, 0x00004ab6, 0x000bbe55, 0x000ffa17 },
+
+ /* MMAC(Japan)J52 ch 34,38,42,46 */
+ { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa0b },
+ { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000ffa13 },
+ { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa1b },
+ { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa23 },
+};
+
+/*
+ * RF value list for RF5225 & RF5325
+ * Supports: 2.4 GHz & 5.2 GHz, rf_sequence enabled
+ */
+static const struct rf_channel rf_vals_seq[] = {
+ { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b },
+ { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f },
+ { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b },
+ { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f },
+ { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b },
+ { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f },
+ { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b },
+ { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f },
+ { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b },
+ { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f },
+ { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b },
+ { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f },
+ { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b },
+ { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x00002cd4, 0x0004481a, 0x00098455, 0x000c0a03 },
+ { 40, 0x00002cd0, 0x00044682, 0x00098455, 0x000c0a03 },
+ { 44, 0x00002cd0, 0x00044686, 0x00098455, 0x000c0a1b },
+ { 48, 0x00002cd0, 0x0004468e, 0x00098655, 0x000c0a0b },
+ { 52, 0x00002cd0, 0x00044692, 0x00098855, 0x000c0a23 },
+ { 56, 0x00002cd0, 0x0004469a, 0x00098c55, 0x000c0a13 },
+ { 60, 0x00002cd0, 0x000446a2, 0x00098e55, 0x000c0a03 },
+ { 64, 0x00002cd0, 0x000446a6, 0x00099255, 0x000c0a1b },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x00002cd4, 0x0004489a, 0x000b9855, 0x000c0a03 },
+ { 104, 0x00002cd4, 0x000448a2, 0x000b9855, 0x000c0a03 },
+ { 108, 0x00002cd4, 0x000448aa, 0x000b9855, 0x000c0a03 },
+ { 112, 0x00002cd4, 0x000448b2, 0x000b9a55, 0x000c0a03 },
+ { 116, 0x00002cd4, 0x000448ba, 0x000b9a55, 0x000c0a03 },
+ { 120, 0x00002cd0, 0x00044702, 0x000b9a55, 0x000c0a03 },
+ { 124, 0x00002cd0, 0x00044706, 0x000b9a55, 0x000c0a1b },
+ { 128, 0x00002cd0, 0x0004470e, 0x000b9c55, 0x000c0a0b },
+ { 132, 0x00002cd0, 0x00044712, 0x000b9c55, 0x000c0a23 },
+ { 136, 0x00002cd0, 0x0004471a, 0x000b9e55, 0x000c0a13 },
+
+ /* 802.11 UNII */
+ { 140, 0x00002cd0, 0x00044722, 0x000b9e55, 0x000c0a03 },
+ { 149, 0x00002cd0, 0x0004472e, 0x000ba255, 0x000c0a1b },
+ { 153, 0x00002cd0, 0x00044736, 0x000ba255, 0x000c0a0b },
+ { 157, 0x00002cd4, 0x0004490a, 0x000ba255, 0x000c0a17 },
+ { 161, 0x00002cd4, 0x00044912, 0x000ba255, 0x000c0a17 },
+ { 165, 0x00002cd4, 0x0004491a, 0x000ba255, 0x000c0a17 },
+
+ /* MMAC(Japan)J52 ch 34,38,42,46 */
+ { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000c0a0b },
+ { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000c0a13 },
+ { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000c0a1b },
+ { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000c0a23 },
+};
+
+static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ u8 *txpower;
+ unsigned int i;
+
+ /*
+ * Initialize all hw fields.
+ */
+ rt2x00dev->hw->flags =
+ IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ rt2x00dev->hw->extra_tx_headroom = 0;
+ rt2x00dev->hw->max_signal = MAX_SIGNAL;
+ rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+ rt2x00dev->hw->queues = 5;
+
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev,
+ EEPROM_MAC_ADDR_0));
+
+ /*
+ * Convert tx_power array in eeprom.
+ */
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ /*
+ * Initialize hw_mode information.
+ */
+ spec->num_modes = 2;
+ spec->num_rates = 12;
+ spec->tx_power_a = NULL;
+ spec->tx_power_bg = txpower;
+ spec->tx_power_default = DEFAULT_TXPOWER;
+
+ if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) {
+ spec->num_channels = 14;
+ spec->channels = rf_vals_noseq;
+ } else {
+ spec->num_channels = 14;
+ spec->channels = rf_vals_seq;
+ }
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF5325)) {
+ spec->num_modes = 3;
+ spec->num_channels = ARRAY_SIZE(rf_vals_seq);
+
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ spec->tx_power_a = txpower;
+ }
+}
+
+static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ /*
+ * Allocate eeprom data.
+ */
+ retval = rt61pci_validate_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt61pci_init_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * Initialize hw specifications.
+ */
+ rt61pci_probe_hw_mode(rt2x00dev);
+
+ /*
+ * This device requires firmware
+ */
+ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
+
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+ return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt61pci_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+ u32 reg;
+
+ /*
+ * Mask off any flags we are going to ignore from
+ * the total_flags field.
+ */
+ *total_flags &=
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_PROMISC_IN_BSS;
+
+ /*
+ * Apply some rules to the filters:
+ * - Some filters imply different filters to be set.
+ * - Some things we can't filter out at all.
+ * - Some filters are set based on interface type.
+ */
+ if (mc_count)
+ *total_flags |= FIF_ALLMULTI;
+ if (*total_flags & FIF_OTHER_BSS ||
+ *total_flags & FIF_PROMISC_IN_BSS)
+ *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+ if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+ *total_flags |= FIF_PROMISC_IN_BSS;
+
+ /*
+ * Check if there is any work left for us.
+ */
+ if (intf->filter == *total_flags)
+ return;
+ intf->filter = *total_flags;
+
+ /*
+ * Start configuration steps.
+ * Note that the version error will always be dropped
+ * and broadcast frames will always be accepted since
+ * there is no filter for it at this time.
+ */
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
+ !(*total_flags & FIF_FCSFAIL));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
+ !(*total_flags & FIF_PLCPFAIL));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
+ !(*total_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
+ !(*total_flags & FIF_ALLMULTI));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BORADCAST, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 1);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
+static int rt61pci_set_retry_limit(struct ieee80211_hw *hw,
+ u32 short_retry, u32 long_retry)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
+ rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+ return 0;
+}
+
+static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u64 tsf;
+ u32 reg;
+
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR13, &reg);
+ tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32;
+ rt2x00pci_register_read(rt2x00dev, TXRX_CSR12, &reg);
+ tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER);
+
+ return tsf;
+}
+
+static void rt61pci_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR12, 0);
+ rt2x00pci_register_write(rt2x00dev, TXRX_CSR13, 0);
+}
+
+static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ /*
+ * Just in case the ieee80211 doesn't set this,
+ * but we need this queue set for the descriptor
+ * initialization.
+ */
+ control->queue = IEEE80211_TX_QUEUE_BEACON;
+
+ /*
+ * We need to append the descriptor in front of the
+ * beacon frame.
+ */
+ if (skb_headroom(skb) < TXD_DESC_SIZE) {
+ if (pskb_expand_head(skb, TXD_DESC_SIZE, 0, GFP_ATOMIC)) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
+ }
+
+ /*
+ * First we create the beacon.
+ */
+ skb_push(skb, TXD_DESC_SIZE);
+ memset(skb->data, 0, TXD_DESC_SIZE);
+
+ rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
+ (struct ieee80211_hdr *)(skb->data +
+ TXD_DESC_SIZE),
+ skb->len - TXD_DESC_SIZE, control);
+
+ /*
+ * Write entire beacon with descriptor to register,
+ * and kick the beacon generator.
+ */
+ rt2x00pci_register_multiwrite(rt2x00dev, HW_BEACON_BASE0,
+ skb->data, skb->len);
+ rt61pci_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+ return 0;
+}
+
+static const struct ieee80211_ops rt61pci_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .config_interface = rt2x00mac_config_interface,
+ .configure_filter = rt61pci_configure_filter,
+ .get_stats = rt2x00mac_get_stats,
+ .set_retry_limit = rt61pci_set_retry_limit,
+ .erp_ie_changed = rt2x00mac_erp_ie_changed,
+ .conf_tx = rt2x00mac_conf_tx,
+ .get_tx_stats = rt2x00mac_get_tx_stats,
+ .get_tsf = rt61pci_get_tsf,
+ .reset_tsf = rt61pci_reset_tsf,
+ .beacon_update = rt61pci_beacon_update,
+};
+
+static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
+ .irq_handler = rt61pci_interrupt,
+ .probe_hw = rt61pci_probe_hw,
+ .get_firmware_name = rt61pci_get_firmware_name,
+ .load_firmware = rt61pci_load_firmware,
+ .initialize = rt2x00pci_initialize,
+ .uninitialize = rt2x00pci_uninitialize,
+ .set_device_state = rt61pci_set_device_state,
+ .rfkill_poll = rt61pci_rfkill_poll,
+ .link_stats = rt61pci_link_stats,
+ .reset_tuner = rt61pci_reset_tuner,
+ .link_tuner = rt61pci_link_tuner,
+ .write_tx_desc = rt61pci_write_tx_desc,
+ .write_tx_data = rt2x00pci_write_tx_data,
+ .kick_tx_queue = rt61pci_kick_tx_queue,
+ .fill_rxdone = rt61pci_fill_rxdone,
+ .config_mac_addr = rt61pci_config_mac_addr,
+ .config_bssid = rt61pci_config_bssid,
+ .config_type = rt61pci_config_type,
+ .config_preamble = rt61pci_config_preamble,
+ .config = rt61pci_config,
+};
+
+static const struct rt2x00_ops rt61pci_ops = {
+ .name = DRV_NAME,
+ .rxd_size = RXD_DESC_SIZE,
+ .txd_size = TXD_DESC_SIZE,
+ .eeprom_size = EEPROM_SIZE,
+ .rf_size = RF_SIZE,
+ .lib = &rt61pci_rt2x00_ops,
+ .hw = &rt61pci_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ .debugfs = &rt61pci_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * RT61pci module information.
+ */
+static struct pci_device_id rt61pci_device_table[] = {
+ /* RT2561s */
+ { PCI_DEVICE(0x1814, 0x0301), PCI_DEVICE_DATA(&rt61pci_ops) },
+ /* RT2561 v2 */
+ { PCI_DEVICE(0x1814, 0x0302), PCI_DEVICE_DATA(&rt61pci_ops) },
+ /* RT2661 */
+ { PCI_DEVICE(0x1814, 0x0401), PCI_DEVICE_DATA(&rt61pci_ops) },
+ { 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT61 PCI & PCMCIA Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2561, RT2561s & RT2661 "
+ "PCI & PCMCIA chipset based cards");
+MODULE_DEVICE_TABLE(pci, rt61pci_device_table);
+MODULE_FIRMWARE(FIRMWARE_RT2561);
+MODULE_FIRMWARE(FIRMWARE_RT2561s);
+MODULE_FIRMWARE(FIRMWARE_RT2661);
+MODULE_LICENSE("GPL");
+
+static struct pci_driver rt61pci_driver = {
+ .name = DRV_NAME,
+ .id_table = rt61pci_device_table,
+ .probe = rt2x00pci_probe,
+ .remove = __devexit_p(rt2x00pci_remove),
+ .suspend = rt2x00pci_suspend,
+ .resume = rt2x00pci_resume,
+};
+
+static int __init rt61pci_init(void)
+{
+ return pci_register_driver(&rt61pci_driver);
+}
+
+static void __exit rt61pci_exit(void)
+{
+ pci_unregister_driver(&rt61pci_driver);
+}
+
+module_init(rt61pci_init);
+module_exit(rt61pci_exit);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
new file mode 100644
index 00000000000..6721d7dd32b
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -0,0 +1,1457 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt61pci
+ Abstract: Data structures and registers for the rt61pci module.
+ Supported chipsets: RT2561, RT2561s, RT2661.
+ */
+
+#ifndef RT61PCI_H
+#define RT61PCI_H
+
+/*
+ * RF chip defines.
+ */
+#define RF5225 0x0001
+#define RF5325 0x0002
+#define RF2527 0x0003
+#define RF2529 0x0004
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL 100
+#define MAX_RX_SSI -1
+#define DEFAULT_RSSI_OFFSET 120
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE 0x3000
+#define CSR_REG_SIZE 0x04b0
+#define EEPROM_BASE 0x0000
+#define EEPROM_SIZE 0x0100
+#define BBP_SIZE 0x0080
+#define RF_SIZE 0x0014
+
+/*
+ * PCI registers.
+ */
+
+/*
+ * PCI Configuration Header
+ */
+#define PCI_CONFIG_HEADER_VENDOR 0x0000
+#define PCI_CONFIG_HEADER_DEVICE 0x0002
+
+/*
+ * HOST_CMD_CSR: For HOST to interrupt embedded processor
+ */
+#define HOST_CMD_CSR 0x0008
+#define HOST_CMD_CSR_HOST_COMMAND FIELD32(0x0000007f)
+#define HOST_CMD_CSR_INTERRUPT_MCU FIELD32(0x00000080)
+
+/*
+ * MCU_CNTL_CSR
+ * SELECT_BANK: Select 8051 program bank.
+ * RESET: Enable 8051 reset state.
+ * READY: Ready state for 8051.
+ */
+#define MCU_CNTL_CSR 0x000c
+#define MCU_CNTL_CSR_SELECT_BANK FIELD32(0x00000001)
+#define MCU_CNTL_CSR_RESET FIELD32(0x00000002)
+#define MCU_CNTL_CSR_READY FIELD32(0x00000004)
+
+/*
+ * SOFT_RESET_CSR
+ */
+#define SOFT_RESET_CSR 0x0010
+
+/*
+ * MCU_INT_SOURCE_CSR: MCU interrupt source/mask register.
+ */
+#define MCU_INT_SOURCE_CSR 0x0014
+#define MCU_INT_SOURCE_CSR_0 FIELD32(0x00000001)
+#define MCU_INT_SOURCE_CSR_1 FIELD32(0x00000002)
+#define MCU_INT_SOURCE_CSR_2 FIELD32(0x00000004)
+#define MCU_INT_SOURCE_CSR_3 FIELD32(0x00000008)
+#define MCU_INT_SOURCE_CSR_4 FIELD32(0x00000010)
+#define MCU_INT_SOURCE_CSR_5 FIELD32(0x00000020)
+#define MCU_INT_SOURCE_CSR_6 FIELD32(0x00000040)
+#define MCU_INT_SOURCE_CSR_7 FIELD32(0x00000080)
+#define MCU_INT_SOURCE_CSR_TWAKEUP FIELD32(0x00000100)
+#define MCU_INT_SOURCE_CSR_TBTT_EXPIRE FIELD32(0x00000200)
+
+/*
+ * MCU_INT_MASK_CSR: MCU interrupt source/mask register.
+ */
+#define MCU_INT_MASK_CSR 0x0018
+#define MCU_INT_MASK_CSR_0 FIELD32(0x00000001)
+#define MCU_INT_MASK_CSR_1 FIELD32(0x00000002)
+#define MCU_INT_MASK_CSR_2 FIELD32(0x00000004)
+#define MCU_INT_MASK_CSR_3 FIELD32(0x00000008)
+#define MCU_INT_MASK_CSR_4 FIELD32(0x00000010)
+#define MCU_INT_MASK_CSR_5 FIELD32(0x00000020)
+#define MCU_INT_MASK_CSR_6 FIELD32(0x00000040)
+#define MCU_INT_MASK_CSR_7 FIELD32(0x00000080)
+#define MCU_INT_MASK_CSR_TWAKEUP FIELD32(0x00000100)
+#define MCU_INT_MASK_CSR_TBTT_EXPIRE FIELD32(0x00000200)
+
+/*
+ * PCI_USEC_CSR
+ */
+#define PCI_USEC_CSR 0x001c
+
+/*
+ * Security key table memory.
+ * 16 entries 32-byte for shared key table
+ * 64 entries 32-byte for pairwise key table
+ * 64 entries 8-byte for pairwise ta key table
+ */
+#define SHARED_KEY_TABLE_BASE 0x1000
+#define PAIRWISE_KEY_TABLE_BASE 0x1200
+#define PAIRWISE_TA_TABLE_BASE 0x1a00
+
+struct hw_key_entry {
+ u8 key[16];
+ u8 tx_mic[8];
+ u8 rx_mic[8];
+} __attribute__ ((packed));
+
+struct hw_pairwise_ta_entry {
+ u8 address[6];
+ u8 reserved[2];
+} __attribute__ ((packed));
+
+/*
+ * Other on-chip shared memory space.
+ */
+#define HW_CIS_BASE 0x2000
+#define HW_NULL_BASE 0x2b00
+
+/*
+ * Since NULL frame won't be that long (256 byte),
+ * We steal 16 tail bytes to save debugging settings.
+ */
+#define HW_DEBUG_SETTING_BASE 0x2bf0
+
+/*
+ * On-chip BEACON frame space.
+ */
+#define HW_BEACON_BASE0 0x2c00
+#define HW_BEACON_BASE1 0x2d00
+#define HW_BEACON_BASE2 0x2e00
+#define HW_BEACON_BASE3 0x2f00
+#define HW_BEACON_OFFSET 0x0100
+
+/*
+ * HOST-MCU shared memory.
+ */
+
+/*
+ * H2M_MAILBOX_CSR: Host-to-MCU Mailbox.
+ */
+#define H2M_MAILBOX_CSR 0x2100
+#define H2M_MAILBOX_CSR_ARG0 FIELD32(0x000000ff)
+#define H2M_MAILBOX_CSR_ARG1 FIELD32(0x0000ff00)
+#define H2M_MAILBOX_CSR_CMD_TOKEN FIELD32(0x00ff0000)
+#define H2M_MAILBOX_CSR_OWNER FIELD32(0xff000000)
+
+/*
+ * MCU_LEDCS: LED control for MCU Mailbox.
+ */
+#define MCU_LEDCS_LED_MODE FIELD16(0x001f)
+#define MCU_LEDCS_RADIO_STATUS FIELD16(0x0020)
+#define MCU_LEDCS_LINK_BG_STATUS FIELD16(0x0040)
+#define MCU_LEDCS_LINK_A_STATUS FIELD16(0x0080)
+#define MCU_LEDCS_POLARITY_GPIO_0 FIELD16(0x0100)
+#define MCU_LEDCS_POLARITY_GPIO_1 FIELD16(0x0200)
+#define MCU_LEDCS_POLARITY_GPIO_2 FIELD16(0x0400)
+#define MCU_LEDCS_POLARITY_GPIO_3 FIELD16(0x0800)
+#define MCU_LEDCS_POLARITY_GPIO_4 FIELD16(0x1000)
+#define MCU_LEDCS_POLARITY_ACT FIELD16(0x2000)
+#define MCU_LEDCS_POLARITY_READY_BG FIELD16(0x4000)
+#define MCU_LEDCS_POLARITY_READY_A FIELD16(0x8000)
+
+/*
+ * M2H_CMD_DONE_CSR.
+ */
+#define M2H_CMD_DONE_CSR 0x2104
+
+/*
+ * MCU_TXOP_ARRAY_BASE.
+ */
+#define MCU_TXOP_ARRAY_BASE 0x2110
+
+/*
+ * MAC Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * MAC_CSR0: ASIC revision number.
+ */
+#define MAC_CSR0 0x3000
+
+/*
+ * MAC_CSR1: System control register.
+ * SOFT_RESET: Software reset bit, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset BBP.
+ * HOST_READY: Host is ready after initialization, 1: ready.
+ */
+#define MAC_CSR1 0x3004
+#define MAC_CSR1_SOFT_RESET FIELD32(0x00000001)
+#define MAC_CSR1_BBP_RESET FIELD32(0x00000002)
+#define MAC_CSR1_HOST_READY FIELD32(0x00000004)
+
+/*
+ * MAC_CSR2: STA MAC register 0.
+ */
+#define MAC_CSR2 0x3008
+#define MAC_CSR2_BYTE0 FIELD32(0x000000ff)
+#define MAC_CSR2_BYTE1 FIELD32(0x0000ff00)
+#define MAC_CSR2_BYTE2 FIELD32(0x00ff0000)
+#define MAC_CSR2_BYTE3 FIELD32(0xff000000)
+
+/*
+ * MAC_CSR3: STA MAC register 1.
+ */
+#define MAC_CSR3 0x300c
+#define MAC_CSR3_BYTE4 FIELD32(0x000000ff)
+#define MAC_CSR3_BYTE5 FIELD32(0x0000ff00)
+#define MAC_CSR3_UNICAST_TO_ME_MASK FIELD32(0x00ff0000)
+
+/*
+ * MAC_CSR4: BSSID register 0.
+ */
+#define MAC_CSR4 0x3010
+#define MAC_CSR4_BYTE0 FIELD32(0x000000ff)
+#define MAC_CSR4_BYTE1 FIELD32(0x0000ff00)
+#define MAC_CSR4_BYTE2 FIELD32(0x00ff0000)
+#define MAC_CSR4_BYTE3 FIELD32(0xff000000)
+
+/*
+ * MAC_CSR5: BSSID register 1.
+ * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID.
+ */
+#define MAC_CSR5 0x3014
+#define MAC_CSR5_BYTE4 FIELD32(0x000000ff)
+#define MAC_CSR5_BYTE5 FIELD32(0x0000ff00)
+#define MAC_CSR5_BSS_ID_MASK FIELD32(0x00ff0000)
+
+/*
+ * MAC_CSR6: Maximum frame length register.
+ */
+#define MAC_CSR6 0x3018
+#define MAC_CSR6_MAX_FRAME_UNIT FIELD32(0x00000fff)
+
+/*
+ * MAC_CSR7: Reserved
+ */
+#define MAC_CSR7 0x301c
+
+/*
+ * MAC_CSR8: SIFS/EIFS register.
+ * All units are in US.
+ */
+#define MAC_CSR8 0x3020
+#define MAC_CSR8_SIFS FIELD32(0x000000ff)
+#define MAC_CSR8_SIFS_AFTER_RX_OFDM FIELD32(0x0000ff00)
+#define MAC_CSR8_EIFS FIELD32(0xffff0000)
+
+/*
+ * MAC_CSR9: Back-Off control register.
+ * SLOT_TIME: Slot time, default is 20us for 802.11BG.
+ * CWMIN: Bit for Cwmin. default Cwmin is 31 (2^5 - 1).
+ * CWMAX: Bit for Cwmax, default Cwmax is 1023 (2^10 - 1).
+ * CW_SELECT: 1: CWmin/Cwmax select from register, 0:select from TxD.
+ */
+#define MAC_CSR9 0x3024
+#define MAC_CSR9_SLOT_TIME FIELD32(0x000000ff)
+#define MAC_CSR9_CWMIN FIELD32(0x00000f00)
+#define MAC_CSR9_CWMAX FIELD32(0x0000f000)
+#define MAC_CSR9_CW_SELECT FIELD32(0x00010000)
+
+/*
+ * MAC_CSR10: Power state configuration.
+ */
+#define MAC_CSR10 0x3028
+
+/*
+ * MAC_CSR11: Power saving transition time register.
+ * DELAY_AFTER_TBCN: Delay after Tbcn expired in units of TU.
+ * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * WAKEUP_LATENCY: In unit of TU.
+ */
+#define MAC_CSR11 0x302c
+#define MAC_CSR11_DELAY_AFTER_TBCN FIELD32(0x000000ff)
+#define MAC_CSR11_TBCN_BEFORE_WAKEUP FIELD32(0x00007f00)
+#define MAC_CSR11_AUTOWAKE FIELD32(0x00008000)
+#define MAC_CSR11_WAKEUP_LATENCY FIELD32(0x000f0000)
+
+/*
+ * MAC_CSR12: Manual power control / status register (merge CSR20 & PWRCSR1).
+ * CURRENT_STATE: 0:sleep, 1:awake.
+ * FORCE_WAKEUP: This has higher priority than PUT_TO_SLEEP.
+ * BBP_CURRENT_STATE: 0: BBP sleep, 1: BBP awake.
+ */
+#define MAC_CSR12 0x3030
+#define MAC_CSR12_CURRENT_STATE FIELD32(0x00000001)
+#define MAC_CSR12_PUT_TO_SLEEP FIELD32(0x00000002)
+#define MAC_CSR12_FORCE_WAKEUP FIELD32(0x00000004)
+#define MAC_CSR12_BBP_CURRENT_STATE FIELD32(0x00000008)
+
+/*
+ * MAC_CSR13: GPIO.
+ */
+#define MAC_CSR13 0x3034
+#define MAC_CSR13_BIT0 FIELD32(0x00000001)
+#define MAC_CSR13_BIT1 FIELD32(0x00000002)
+#define MAC_CSR13_BIT2 FIELD32(0x00000004)
+#define MAC_CSR13_BIT3 FIELD32(0x00000008)
+#define MAC_CSR13_BIT4 FIELD32(0x00000010)
+#define MAC_CSR13_BIT5 FIELD32(0x00000020)
+#define MAC_CSR13_BIT6 FIELD32(0x00000040)
+#define MAC_CSR13_BIT7 FIELD32(0x00000080)
+#define MAC_CSR13_BIT8 FIELD32(0x00000100)
+#define MAC_CSR13_BIT9 FIELD32(0x00000200)
+#define MAC_CSR13_BIT10 FIELD32(0x00000400)
+#define MAC_CSR13_BIT11 FIELD32(0x00000800)
+#define MAC_CSR13_BIT12 FIELD32(0x00001000)
+
+/*
+ * MAC_CSR14: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ * HW_LED: HW TX activity, 1: normal OFF, 0: normal ON.
+ * SW_LED: s/w LED, 1: ON, 0: OFF.
+ * HW_LED_POLARITY: 0: active low, 1: active high.
+ */
+#define MAC_CSR14 0x3038
+#define MAC_CSR14_ON_PERIOD FIELD32(0x000000ff)
+#define MAC_CSR14_OFF_PERIOD FIELD32(0x0000ff00)
+#define MAC_CSR14_HW_LED FIELD32(0x00010000)
+#define MAC_CSR14_SW_LED FIELD32(0x00020000)
+#define MAC_CSR14_HW_LED_POLARITY FIELD32(0x00040000)
+#define MAC_CSR14_SW_LED2 FIELD32(0x00080000)
+
+/*
+ * MAC_CSR15: NAV control.
+ */
+#define MAC_CSR15 0x303c
+
+/*
+ * TXRX control registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXRX_CSR0: TX/RX configuration register.
+ * TSF_OFFSET: Default is 24.
+ * AUTO_TX_SEQ: 1: ASIC auto replace sequence nr in outgoing frame.
+ * DISABLE_RX: Disable Rx engine.
+ * DROP_CRC: Drop CRC error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TO_DS: Drop fram ToDs bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * DROP_MULTICAST: Drop multicast frames.
+ * DROP_BORADCAST: Drop broadcast frames.
+ * ROP_ACK_CTS: Drop received ACK and CTS.
+ */
+#define TXRX_CSR0 0x3040
+#define TXRX_CSR0_RX_ACK_TIMEOUT FIELD32(0x000001ff)
+#define TXRX_CSR0_TSF_OFFSET FIELD32(0x00007e00)
+#define TXRX_CSR0_AUTO_TX_SEQ FIELD32(0x00008000)
+#define TXRX_CSR0_DISABLE_RX FIELD32(0x00010000)
+#define TXRX_CSR0_DROP_CRC FIELD32(0x00020000)
+#define TXRX_CSR0_DROP_PHYSICAL FIELD32(0x00040000)
+#define TXRX_CSR0_DROP_CONTROL FIELD32(0x00080000)
+#define TXRX_CSR0_DROP_NOT_TO_ME FIELD32(0x00100000)
+#define TXRX_CSR0_DROP_TO_DS FIELD32(0x00200000)
+#define TXRX_CSR0_DROP_VERSION_ERROR FIELD32(0x00400000)
+#define TXRX_CSR0_DROP_MULTICAST FIELD32(0x00800000)
+#define TXRX_CSR0_DROP_BORADCAST FIELD32(0x01000000)
+#define TXRX_CSR0_DROP_ACK_CTS FIELD32(0x02000000)
+#define TXRX_CSR0_TX_WITHOUT_WAITING FIELD32(0x04000000)
+
+/*
+ * TXRX_CSR1
+ */
+#define TXRX_CSR1 0x3044
+#define TXRX_CSR1_BBP_ID0 FIELD32(0x0000007f)
+#define TXRX_CSR1_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXRX_CSR1_BBP_ID1 FIELD32(0x00007f00)
+#define TXRX_CSR1_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXRX_CSR1_BBP_ID2 FIELD32(0x007f0000)
+#define TXRX_CSR1_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXRX_CSR1_BBP_ID3 FIELD32(0x7f000000)
+#define TXRX_CSR1_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR2
+ */
+#define TXRX_CSR2 0x3048
+#define TXRX_CSR2_BBP_ID0 FIELD32(0x0000007f)
+#define TXRX_CSR2_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXRX_CSR2_BBP_ID1 FIELD32(0x00007f00)
+#define TXRX_CSR2_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXRX_CSR2_BBP_ID2 FIELD32(0x007f0000)
+#define TXRX_CSR2_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXRX_CSR2_BBP_ID3 FIELD32(0x7f000000)
+#define TXRX_CSR2_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR3
+ */
+#define TXRX_CSR3 0x304c
+#define TXRX_CSR3_BBP_ID0 FIELD32(0x0000007f)
+#define TXRX_CSR3_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXRX_CSR3_BBP_ID1 FIELD32(0x00007f00)
+#define TXRX_CSR3_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXRX_CSR3_BBP_ID2 FIELD32(0x007f0000)
+#define TXRX_CSR3_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXRX_CSR3_BBP_ID3 FIELD32(0x7f000000)
+#define TXRX_CSR3_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR4: Auto-Responder/Tx-retry register.
+ * AUTORESPOND_PREAMBLE: 0:long, 1:short preamble.
+ * OFDM_TX_RATE_DOWN: 1:enable.
+ * OFDM_TX_RATE_STEP: 0:1-step, 1: 2-step, 2:3-step, 3:4-step.
+ * OFDM_TX_FALLBACK_CCK: 0: Fallback to OFDM 6M only, 1: Fallback to CCK 1M,2M.
+ */
+#define TXRX_CSR4 0x3050
+#define TXRX_CSR4_TX_ACK_TIMEOUT FIELD32(0x000000ff)
+#define TXRX_CSR4_CNTL_ACK_POLICY FIELD32(0x00000700)
+#define TXRX_CSR4_ACK_CTS_PSM FIELD32(0x00010000)
+#define TXRX_CSR4_AUTORESPOND_ENABLE FIELD32(0x00020000)
+#define TXRX_CSR4_AUTORESPOND_PREAMBLE FIELD32(0x00040000)
+#define TXRX_CSR4_OFDM_TX_RATE_DOWN FIELD32(0x00080000)
+#define TXRX_CSR4_OFDM_TX_RATE_STEP FIELD32(0x00300000)
+#define TXRX_CSR4_OFDM_TX_FALLBACK_CCK FIELD32(0x00400000)
+#define TXRX_CSR4_LONG_RETRY_LIMIT FIELD32(0x0f000000)
+#define TXRX_CSR4_SHORT_RETRY_LIMIT FIELD32(0xf0000000)
+
+/*
+ * TXRX_CSR5
+ */
+#define TXRX_CSR5 0x3054
+
+/*
+ * TXRX_CSR6: ACK/CTS payload consumed time
+ */
+#define TXRX_CSR6 0x3058
+
+/*
+ * TXRX_CSR7: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps.
+ */
+#define TXRX_CSR7 0x305c
+#define TXRX_CSR7_ACK_CTS_6MBS FIELD32(0x000000ff)
+#define TXRX_CSR7_ACK_CTS_9MBS FIELD32(0x0000ff00)
+#define TXRX_CSR7_ACK_CTS_12MBS FIELD32(0x00ff0000)
+#define TXRX_CSR7_ACK_CTS_18MBS FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR8: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps.
+ */
+#define TXRX_CSR8 0x3060
+#define TXRX_CSR8_ACK_CTS_24MBS FIELD32(0x000000ff)
+#define TXRX_CSR8_ACK_CTS_36MBS FIELD32(0x0000ff00)
+#define TXRX_CSR8_ACK_CTS_48MBS FIELD32(0x00ff0000)
+#define TXRX_CSR8_ACK_CTS_54MBS FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR9: Synchronization control register.
+ * BEACON_INTERVAL: In unit of 1/16 TU.
+ * TSF_TICKING: Enable TSF auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * BEACON_GEN: Enable beacon generator.
+ */
+#define TXRX_CSR9 0x3064
+#define TXRX_CSR9_BEACON_INTERVAL FIELD32(0x0000ffff)
+#define TXRX_CSR9_TSF_TICKING FIELD32(0x00010000)
+#define TXRX_CSR9_TSF_SYNC FIELD32(0x00060000)
+#define TXRX_CSR9_TBTT_ENABLE FIELD32(0x00080000)
+#define TXRX_CSR9_BEACON_GEN FIELD32(0x00100000)
+#define TXRX_CSR9_TIMESTAMP_COMPENSATE FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR10: BEACON alignment.
+ */
+#define TXRX_CSR10 0x3068
+
+/*
+ * TXRX_CSR11: AES mask.
+ */
+#define TXRX_CSR11 0x306c
+
+/*
+ * TXRX_CSR12: TSF low 32.
+ */
+#define TXRX_CSR12 0x3070
+#define TXRX_CSR12_LOW_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * TXRX_CSR13: TSF high 32.
+ */
+#define TXRX_CSR13 0x3074
+#define TXRX_CSR13_HIGH_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * TXRX_CSR14: TBTT timer.
+ */
+#define TXRX_CSR14 0x3078
+
+/*
+ * TXRX_CSR15: TKIP MIC priority byte "AND" mask.
+ */
+#define TXRX_CSR15 0x307c
+
+/*
+ * PHY control registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * PHY_CSR0: RF/PS control.
+ */
+#define PHY_CSR0 0x3080
+#define PHY_CSR0_PA_PE_BG FIELD32(0x00010000)
+#define PHY_CSR0_PA_PE_A FIELD32(0x00020000)
+
+/*
+ * PHY_CSR1
+ */
+#define PHY_CSR1 0x3084
+
+/*
+ * PHY_CSR2: Pre-TX BBP control.
+ */
+#define PHY_CSR2 0x3088
+
+/*
+ * PHY_CSR3: BBP serial control register.
+ * VALUE: Register value to program into BBP.
+ * REG_NUM: Selected BBP register.
+ * READ_CONTROL: 0: Write BBP, 1: Read BBP.
+ * BUSY: 1: ASIC is busy execute BBP programming.
+ */
+#define PHY_CSR3 0x308c
+#define PHY_CSR3_VALUE FIELD32(0x000000ff)
+#define PHY_CSR3_REGNUM FIELD32(0x00007f00)
+#define PHY_CSR3_READ_CONTROL FIELD32(0x00008000)
+#define PHY_CSR3_BUSY FIELD32(0x00010000)
+
+/*
+ * PHY_CSR4: RF serial control register
+ * VALUE: Register value (include register id) serial out to RF/IF chip.
+ * NUMBER_OF_BITS: Number of bits used in RFRegValue (I:20, RFMD:22).
+ * IF_SELECT: 1: select IF to program, 0: select RF to program.
+ * PLL_LD: RF PLL_LD status.
+ * BUSY: 1: ASIC is busy execute RF programming.
+ */
+#define PHY_CSR4 0x3090
+#define PHY_CSR4_VALUE FIELD32(0x00ffffff)
+#define PHY_CSR4_NUMBER_OF_BITS FIELD32(0x1f000000)
+#define PHY_CSR4_IF_SELECT FIELD32(0x20000000)
+#define PHY_CSR4_PLL_LD FIELD32(0x40000000)
+#define PHY_CSR4_BUSY FIELD32(0x80000000)
+
+/*
+ * PHY_CSR5: RX to TX signal switch timing control.
+ */
+#define PHY_CSR5 0x3094
+#define PHY_CSR5_IQ_FLIP FIELD32(0x00000004)
+
+/*
+ * PHY_CSR6: TX to RX signal timing control.
+ */
+#define PHY_CSR6 0x3098
+#define PHY_CSR6_IQ_FLIP FIELD32(0x00000004)
+
+/*
+ * PHY_CSR7: TX DAC switching timing control.
+ */
+#define PHY_CSR7 0x309c
+
+/*
+ * Security control register.
+ */
+
+/*
+ * SEC_CSR0: Shared key table control.
+ */
+#define SEC_CSR0 0x30a0
+#define SEC_CSR0_BSS0_KEY0_VALID FIELD32(0x00000001)
+#define SEC_CSR0_BSS0_KEY1_VALID FIELD32(0x00000002)
+#define SEC_CSR0_BSS0_KEY2_VALID FIELD32(0x00000004)
+#define SEC_CSR0_BSS0_KEY3_VALID FIELD32(0x00000008)
+#define SEC_CSR0_BSS1_KEY0_VALID FIELD32(0x00000010)
+#define SEC_CSR0_BSS1_KEY1_VALID FIELD32(0x00000020)
+#define SEC_CSR0_BSS1_KEY2_VALID FIELD32(0x00000040)
+#define SEC_CSR0_BSS1_KEY3_VALID FIELD32(0x00000080)
+#define SEC_CSR0_BSS2_KEY0_VALID FIELD32(0x00000100)
+#define SEC_CSR0_BSS2_KEY1_VALID FIELD32(0x00000200)
+#define SEC_CSR0_BSS2_KEY2_VALID FIELD32(0x00000400)
+#define SEC_CSR0_BSS2_KEY3_VALID FIELD32(0x00000800)
+#define SEC_CSR0_BSS3_KEY0_VALID FIELD32(0x00001000)
+#define SEC_CSR0_BSS3_KEY1_VALID FIELD32(0x00002000)
+#define SEC_CSR0_BSS3_KEY2_VALID FIELD32(0x00004000)
+#define SEC_CSR0_BSS3_KEY3_VALID FIELD32(0x00008000)
+
+/*
+ * SEC_CSR1: Shared key table security mode register.
+ */
+#define SEC_CSR1 0x30a4
+#define SEC_CSR1_BSS0_KEY0_CIPHER_ALG FIELD32(0x00000007)
+#define SEC_CSR1_BSS0_KEY1_CIPHER_ALG FIELD32(0x00000070)
+#define SEC_CSR1_BSS0_KEY2_CIPHER_ALG FIELD32(0x00000700)
+#define SEC_CSR1_BSS0_KEY3_CIPHER_ALG FIELD32(0x00007000)
+#define SEC_CSR1_BSS1_KEY0_CIPHER_ALG FIELD32(0x00070000)
+#define SEC_CSR1_BSS1_KEY1_CIPHER_ALG FIELD32(0x00700000)
+#define SEC_CSR1_BSS1_KEY2_CIPHER_ALG FIELD32(0x07000000)
+#define SEC_CSR1_BSS1_KEY3_CIPHER_ALG FIELD32(0x70000000)
+
+/*
+ * Pairwise key table valid bitmap registers.
+ * SEC_CSR2: pairwise key table valid bitmap 0.
+ * SEC_CSR3: pairwise key table valid bitmap 1.
+ */
+#define SEC_CSR2 0x30a8
+#define SEC_CSR3 0x30ac
+
+/*
+ * SEC_CSR4: Pairwise key table lookup control.
+ */
+#define SEC_CSR4 0x30b0
+
+/*
+ * SEC_CSR5: shared key table security mode register.
+ */
+#define SEC_CSR5 0x30b4
+#define SEC_CSR5_BSS2_KEY0_CIPHER_ALG FIELD32(0x00000007)
+#define SEC_CSR5_BSS2_KEY1_CIPHER_ALG FIELD32(0x00000070)
+#define SEC_CSR5_BSS2_KEY2_CIPHER_ALG FIELD32(0x00000700)
+#define SEC_CSR5_BSS2_KEY3_CIPHER_ALG FIELD32(0x00007000)
+#define SEC_CSR5_BSS3_KEY0_CIPHER_ALG FIELD32(0x00070000)
+#define SEC_CSR5_BSS3_KEY1_CIPHER_ALG FIELD32(0x00700000)
+#define SEC_CSR5_BSS3_KEY2_CIPHER_ALG FIELD32(0x07000000)
+#define SEC_CSR5_BSS3_KEY3_CIPHER_ALG FIELD32(0x70000000)
+
+/*
+ * STA control registers.
+ */
+
+/*
+ * STA_CSR0: RX PLCP error count & RX FCS error count.
+ */
+#define STA_CSR0 0x30c0
+#define STA_CSR0_FCS_ERROR FIELD32(0x0000ffff)
+#define STA_CSR0_PLCP_ERROR FIELD32(0xffff0000)
+
+/*
+ * STA_CSR1: RX False CCA count & RX LONG frame count.
+ */
+#define STA_CSR1 0x30c4
+#define STA_CSR1_PHYSICAL_ERROR FIELD32(0x0000ffff)
+#define STA_CSR1_FALSE_CCA_ERROR FIELD32(0xffff0000)
+
+/*
+ * STA_CSR2: TX Beacon count and RX FIFO overflow count.
+ */
+#define STA_CSR2 0x30c8
+#define STA_CSR2_RX_FIFO_OVERFLOW_COUNT FIELD32(0x0000ffff)
+#define STA_CSR2_RX_OVERFLOW_COUNT FIELD32(0xffff0000)
+
+/*
+ * STA_CSR3: TX Beacon count.
+ */
+#define STA_CSR3 0x30cc
+#define STA_CSR3_TX_BEACON_COUNT FIELD32(0x0000ffff)
+
+/*
+ * STA_CSR4: TX Result status register.
+ * VALID: 1:This register contains a valid TX result.
+ */
+#define STA_CSR4 0x30d0
+#define STA_CSR4_VALID FIELD32(0x00000001)
+#define STA_CSR4_TX_RESULT FIELD32(0x0000000e)
+#define STA_CSR4_RETRY_COUNT FIELD32(0x000000f0)
+#define STA_CSR4_PID_SUBTYPE FIELD32(0x00001f00)
+#define STA_CSR4_PID_TYPE FIELD32(0x0000e000)
+#define STA_CSR4_TXRATE FIELD32(0x000f0000)
+
+/*
+ * QOS control registers.
+ */
+
+/*
+ * QOS_CSR0: TXOP holder MAC address register.
+ */
+#define QOS_CSR0 0x30e0
+#define QOS_CSR0_BYTE0 FIELD32(0x000000ff)
+#define QOS_CSR0_BYTE1 FIELD32(0x0000ff00)
+#define QOS_CSR0_BYTE2 FIELD32(0x00ff0000)
+#define QOS_CSR0_BYTE3 FIELD32(0xff000000)
+
+/*
+ * QOS_CSR1: TXOP holder MAC address register.
+ */
+#define QOS_CSR1 0x30e4
+#define QOS_CSR1_BYTE4 FIELD32(0x000000ff)
+#define QOS_CSR1_BYTE5 FIELD32(0x0000ff00)
+
+/*
+ * QOS_CSR2: TXOP holder timeout register.
+ */
+#define QOS_CSR2 0x30e8
+
+/*
+ * RX QOS-CFPOLL MAC address register.
+ * QOS_CSR3: RX QOS-CFPOLL MAC address 0.
+ * QOS_CSR4: RX QOS-CFPOLL MAC address 1.
+ */
+#define QOS_CSR3 0x30ec
+#define QOS_CSR4 0x30f0
+
+/*
+ * QOS_CSR5: "QosControl" field of the RX QOS-CFPOLL.
+ */
+#define QOS_CSR5 0x30f4
+
+/*
+ * Host DMA registers.
+ */
+
+/*
+ * AC0_BASE_CSR: AC_BK base address.
+ */
+#define AC0_BASE_CSR 0x3400
+#define AC0_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * AC1_BASE_CSR: AC_BE base address.
+ */
+#define AC1_BASE_CSR 0x3404
+#define AC1_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * AC2_BASE_CSR: AC_VI base address.
+ */
+#define AC2_BASE_CSR 0x3408
+#define AC2_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * AC3_BASE_CSR: AC_VO base address.
+ */
+#define AC3_BASE_CSR 0x340c
+#define AC3_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * MGMT_BASE_CSR: MGMT ring base address.
+ */
+#define MGMT_BASE_CSR 0x3410
+#define MGMT_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * TX_RING_CSR0: TX Ring size for AC_BK, AC_BE, AC_VI, AC_VO.
+ */
+#define TX_RING_CSR0 0x3418
+#define TX_RING_CSR0_AC0_RING_SIZE FIELD32(0x000000ff)
+#define TX_RING_CSR0_AC1_RING_SIZE FIELD32(0x0000ff00)
+#define TX_RING_CSR0_AC2_RING_SIZE FIELD32(0x00ff0000)
+#define TX_RING_CSR0_AC3_RING_SIZE FIELD32(0xff000000)
+
+/*
+ * TX_RING_CSR1: TX Ring size for MGMT Ring, HCCA Ring
+ * TXD_SIZE: In unit of 32-bit.
+ */
+#define TX_RING_CSR1 0x341c
+#define TX_RING_CSR1_MGMT_RING_SIZE FIELD32(0x000000ff)
+#define TX_RING_CSR1_HCCA_RING_SIZE FIELD32(0x0000ff00)
+#define TX_RING_CSR1_TXD_SIZE FIELD32(0x003f0000)
+
+/*
+ * AIFSN_CSR: AIFSN for each EDCA AC.
+ * AIFSN0: For AC_BK.
+ * AIFSN1: For AC_BE.
+ * AIFSN2: For AC_VI.
+ * AIFSN3: For AC_VO.
+ */
+#define AIFSN_CSR 0x3420
+#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f)
+#define AIFSN_CSR_AIFSN1 FIELD32(0x000000f0)
+#define AIFSN_CSR_AIFSN2 FIELD32(0x00000f00)
+#define AIFSN_CSR_AIFSN3 FIELD32(0x0000f000)
+
+/*
+ * CWMIN_CSR: CWmin for each EDCA AC.
+ * CWMIN0: For AC_BK.
+ * CWMIN1: For AC_BE.
+ * CWMIN2: For AC_VI.
+ * CWMIN3: For AC_VO.
+ */
+#define CWMIN_CSR 0x3424
+#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f)
+#define CWMIN_CSR_CWMIN1 FIELD32(0x000000f0)
+#define CWMIN_CSR_CWMIN2 FIELD32(0x00000f00)
+#define CWMIN_CSR_CWMIN3 FIELD32(0x0000f000)
+
+/*
+ * CWMAX_CSR: CWmax for each EDCA AC.
+ * CWMAX0: For AC_BK.
+ * CWMAX1: For AC_BE.
+ * CWMAX2: For AC_VI.
+ * CWMAX3: For AC_VO.
+ */
+#define CWMAX_CSR 0x3428
+#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f)
+#define CWMAX_CSR_CWMAX1 FIELD32(0x000000f0)
+#define CWMAX_CSR_CWMAX2 FIELD32(0x00000f00)
+#define CWMAX_CSR_CWMAX3 FIELD32(0x0000f000)
+
+/*
+ * TX_DMA_DST_CSR: TX DMA destination
+ * 0: TX ring0, 1: TX ring1, 2: TX ring2 3: invalid
+ */
+#define TX_DMA_DST_CSR 0x342c
+#define TX_DMA_DST_CSR_DEST_AC0 FIELD32(0x00000003)
+#define TX_DMA_DST_CSR_DEST_AC1 FIELD32(0x0000000c)
+#define TX_DMA_DST_CSR_DEST_AC2 FIELD32(0x00000030)
+#define TX_DMA_DST_CSR_DEST_AC3 FIELD32(0x000000c0)
+#define TX_DMA_DST_CSR_DEST_MGMT FIELD32(0x00000300)
+
+/*
+ * TX_CNTL_CSR: KICK/Abort TX.
+ * KICK_TX_AC0: For AC_BK.
+ * KICK_TX_AC1: For AC_BE.
+ * KICK_TX_AC2: For AC_VI.
+ * KICK_TX_AC3: For AC_VO.
+ * ABORT_TX_AC0: For AC_BK.
+ * ABORT_TX_AC1: For AC_BE.
+ * ABORT_TX_AC2: For AC_VI.
+ * ABORT_TX_AC3: For AC_VO.
+ */
+#define TX_CNTL_CSR 0x3430
+#define TX_CNTL_CSR_KICK_TX_AC0 FIELD32(0x00000001)
+#define TX_CNTL_CSR_KICK_TX_AC1 FIELD32(0x00000002)
+#define TX_CNTL_CSR_KICK_TX_AC2 FIELD32(0x00000004)
+#define TX_CNTL_CSR_KICK_TX_AC3 FIELD32(0x00000008)
+#define TX_CNTL_CSR_KICK_TX_MGMT FIELD32(0x00000010)
+#define TX_CNTL_CSR_ABORT_TX_AC0 FIELD32(0x00010000)
+#define TX_CNTL_CSR_ABORT_TX_AC1 FIELD32(0x00020000)
+#define TX_CNTL_CSR_ABORT_TX_AC2 FIELD32(0x00040000)
+#define TX_CNTL_CSR_ABORT_TX_AC3 FIELD32(0x00080000)
+#define TX_CNTL_CSR_ABORT_TX_MGMT FIELD32(0x00100000)
+
+/*
+ * LOAD_TX_RING_CSR: Load RX de
+ */
+#define LOAD_TX_RING_CSR 0x3434
+#define LOAD_TX_RING_CSR_LOAD_TXD_AC0 FIELD32(0x00000001)
+#define LOAD_TX_RING_CSR_LOAD_TXD_AC1 FIELD32(0x00000002)
+#define LOAD_TX_RING_CSR_LOAD_TXD_AC2 FIELD32(0x00000004)
+#define LOAD_TX_RING_CSR_LOAD_TXD_AC3 FIELD32(0x00000008)
+#define LOAD_TX_RING_CSR_LOAD_TXD_MGMT FIELD32(0x00000010)
+
+/*
+ * Several read-only registers, for debugging.
+ */
+#define AC0_TXPTR_CSR 0x3438
+#define AC1_TXPTR_CSR 0x343c
+#define AC2_TXPTR_CSR 0x3440
+#define AC3_TXPTR_CSR 0x3444
+#define MGMT_TXPTR_CSR 0x3448
+
+/*
+ * RX_BASE_CSR
+ */
+#define RX_BASE_CSR 0x3450
+#define RX_BASE_CSR_RING_REGISTER FIELD32(0xffffffff)
+
+/*
+ * RX_RING_CSR.
+ * RXD_SIZE: In unit of 32-bit.
+ */
+#define RX_RING_CSR 0x3454
+#define RX_RING_CSR_RING_SIZE FIELD32(0x000000ff)
+#define RX_RING_CSR_RXD_SIZE FIELD32(0x00003f00)
+#define RX_RING_CSR_RXD_WRITEBACK_SIZE FIELD32(0x00070000)
+
+/*
+ * RX_CNTL_CSR
+ */
+#define RX_CNTL_CSR 0x3458
+#define RX_CNTL_CSR_ENABLE_RX_DMA FIELD32(0x00000001)
+#define RX_CNTL_CSR_LOAD_RXD FIELD32(0x00000002)
+
+/*
+ * RXPTR_CSR: Read-only, for debugging.
+ */
+#define RXPTR_CSR 0x345c
+
+/*
+ * PCI_CFG_CSR
+ */
+#define PCI_CFG_CSR 0x3460
+
+/*
+ * BUF_FORMAT_CSR
+ */
+#define BUF_FORMAT_CSR 0x3464
+
+/*
+ * INT_SOURCE_CSR: Interrupt source register.
+ * Write one to clear corresponding bit.
+ */
+#define INT_SOURCE_CSR 0x3468
+#define INT_SOURCE_CSR_TXDONE FIELD32(0x00000001)
+#define INT_SOURCE_CSR_RXDONE FIELD32(0x00000002)
+#define INT_SOURCE_CSR_BEACON_DONE FIELD32(0x00000004)
+#define INT_SOURCE_CSR_TX_ABORT_DONE FIELD32(0x00000010)
+#define INT_SOURCE_CSR_AC0_DMA_DONE FIELD32(0x00010000)
+#define INT_SOURCE_CSR_AC1_DMA_DONE FIELD32(0x00020000)
+#define INT_SOURCE_CSR_AC2_DMA_DONE FIELD32(0x00040000)
+#define INT_SOURCE_CSR_AC3_DMA_DONE FIELD32(0x00080000)
+#define INT_SOURCE_CSR_MGMT_DMA_DONE FIELD32(0x00100000)
+#define INT_SOURCE_CSR_HCCA_DMA_DONE FIELD32(0x00200000)
+
+/*
+ * INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF.
+ * MITIGATION_PERIOD: Interrupt mitigation in unit of 32 PCI clock.
+ */
+#define INT_MASK_CSR 0x346c
+#define INT_MASK_CSR_TXDONE FIELD32(0x00000001)
+#define INT_MASK_CSR_RXDONE FIELD32(0x00000002)
+#define INT_MASK_CSR_BEACON_DONE FIELD32(0x00000004)
+#define INT_MASK_CSR_TX_ABORT_DONE FIELD32(0x00000010)
+#define INT_MASK_CSR_ENABLE_MITIGATION FIELD32(0x00000080)
+#define INT_MASK_CSR_MITIGATION_PERIOD FIELD32(0x0000ff00)
+#define INT_MASK_CSR_AC0_DMA_DONE FIELD32(0x00010000)
+#define INT_MASK_CSR_AC1_DMA_DONE FIELD32(0x00020000)
+#define INT_MASK_CSR_AC2_DMA_DONE FIELD32(0x00040000)
+#define INT_MASK_CSR_AC3_DMA_DONE FIELD32(0x00080000)
+#define INT_MASK_CSR_MGMT_DMA_DONE FIELD32(0x00100000)
+#define INT_MASK_CSR_HCCA_DMA_DONE FIELD32(0x00200000)
+
+/*
+ * E2PROM_CSR: EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE_93C46: 1: 93c46, 0:93c66.
+ * LOAD_STATUS: 1:loading, 0:done.
+ */
+#define E2PROM_CSR 0x3470
+#define E2PROM_CSR_RELOAD FIELD32(0x00000001)
+#define E2PROM_CSR_DATA_CLOCK FIELD32(0x00000002)
+#define E2PROM_CSR_CHIP_SELECT FIELD32(0x00000004)
+#define E2PROM_CSR_DATA_IN FIELD32(0x00000008)
+#define E2PROM_CSR_DATA_OUT FIELD32(0x00000010)
+#define E2PROM_CSR_TYPE_93C46 FIELD32(0x00000020)
+#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040)
+
+/*
+ * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register.
+ * AC0_TX_OP: For AC_BK, in unit of 32us.
+ * AC1_TX_OP: For AC_BE, in unit of 32us.
+ */
+#define AC_TXOP_CSR0 0x3474
+#define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff)
+#define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000)
+
+/*
+ * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register.
+ * AC2_TX_OP: For AC_VI, in unit of 32us.
+ * AC3_TX_OP: For AC_VO, in unit of 32us.
+ */
+#define AC_TXOP_CSR1 0x3478
+#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff)
+#define AC_TXOP_CSR1_AC3_TX_OP FIELD32(0xffff0000)
+
+/*
+ * DMA_STATUS_CSR
+ */
+#define DMA_STATUS_CSR 0x3480
+
+/*
+ * TEST_MODE_CSR
+ */
+#define TEST_MODE_CSR 0x3484
+
+/*
+ * UART0_TX_CSR
+ */
+#define UART0_TX_CSR 0x3488
+
+/*
+ * UART0_RX_CSR
+ */
+#define UART0_RX_CSR 0x348c
+
+/*
+ * UART0_FRAME_CSR
+ */
+#define UART0_FRAME_CSR 0x3490
+
+/*
+ * UART0_BUFFER_CSR
+ */
+#define UART0_BUFFER_CSR 0x3494
+
+/*
+ * IO_CNTL_CSR
+ */
+#define IO_CNTL_CSR 0x3498
+
+/*
+ * UART_INT_SOURCE_CSR
+ */
+#define UART_INT_SOURCE_CSR 0x34a8
+
+/*
+ * UART_INT_MASK_CSR
+ */
+#define UART_INT_MASK_CSR 0x34ac
+
+/*
+ * PBF_QUEUE_CSR
+ */
+#define PBF_QUEUE_CSR 0x34b0
+
+/*
+ * Firmware DMA registers.
+ * Firmware DMA registers are dedicated for MCU usage
+ * and should not be touched by host driver.
+ * Therefore we skip the definition of these registers.
+ */
+#define FW_TX_BASE_CSR 0x34c0
+#define FW_TX_START_CSR 0x34c4
+#define FW_TX_LAST_CSR 0x34c8
+#define FW_MODE_CNTL_CSR 0x34cc
+#define FW_TXPTR_CSR 0x34d0
+
+/*
+ * 8051 firmware image.
+ */
+#define FIRMWARE_RT2561 "rt2561.bin"
+#define FIRMWARE_RT2561s "rt2561s.bin"
+#define FIRMWARE_RT2661 "rt2661.bin"
+#define FIRMWARE_IMAGE_BASE 0x4000
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R2
+ */
+#define BBP_R2_BG_MODE FIELD8(0x20)
+
+/*
+ * R3
+ */
+#define BBP_R3_SMART_MODE FIELD8(0x01)
+
+/*
+ * R4: RX antenna control
+ * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529)
+ */
+#define BBP_R4_RX_ANTENNA FIELD8(0x03)
+#define BBP_R4_RX_FRAME_END FIELD8(0x20)
+
+/*
+ * R77
+ */
+#define BBP_R77_PAIR FIELD8(0x03)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 3
+ */
+#define RF3_TXPOWER FIELD32(0x00003e00)
+
+/*
+ * RF 4
+ */
+#define RF4_FREQ_OFFSET FIELD32(0x0003f000)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0 0x0002
+#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1 0x0004
+#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2 0x0006
+#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only.
+ * DYN_TXAGC: Dynamic TX AGC control.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ * RF_TYPE: Rf_type of this adapter.
+ */
+#define EEPROM_ANTENNA 0x0010
+#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
+#define EEPROM_ANTENNA_FRAME_TYPE FIELD16(0x0040)
+#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
+#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800)
+
+/*
+ * EEPROM NIC config.
+ * ENABLE_DIVERSITY: 1:enable, 0:disable.
+ * EXTERNAL_LNA_BG: External LNA enable for 2.4G.
+ * CARDBUS_ACCEL: 0:enable, 1:disable.
+ * EXTERNAL_LNA_A: External LNA enable for 5G.
+ */
+#define EEPROM_NIC 0x0011
+#define EEPROM_NIC_ENABLE_DIVERSITY FIELD16(0x0001)
+#define EEPROM_NIC_TX_DIVERSITY FIELD16(0x0002)
+#define EEPROM_NIC_TX_RX_FIXED FIELD16(0x000c)
+#define EEPROM_NIC_EXTERNAL_LNA_BG FIELD16(0x0010)
+#define EEPROM_NIC_CARDBUS_ACCEL FIELD16(0x0020)
+#define EEPROM_NIC_EXTERNAL_LNA_A FIELD16(0x0040)
+
+/*
+ * EEPROM geography.
+ * GEO_A: Default geographical setting for 5GHz band
+ * GEO: Default geographical setting.
+ */
+#define EEPROM_GEOGRAPHY 0x0012
+#define EEPROM_GEOGRAPHY_GEO_A FIELD16(0x00ff)
+#define EEPROM_GEOGRAPHY_GEO FIELD16(0xff00)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START 0x0013
+#define EEPROM_BBP_SIZE 16
+#define EEPROM_BBP_VALUE FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER 802.11G
+ */
+#define EEPROM_TXPOWER_G_START 0x0023
+#define EEPROM_TXPOWER_G_SIZE 7
+#define EEPROM_TXPOWER_G_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_G_2 FIELD16(0xff00)
+
+/*
+ * EEPROM Frequency
+ */
+#define EEPROM_FREQ 0x002f
+#define EEPROM_FREQ_OFFSET FIELD16(0x00ff)
+#define EEPROM_FREQ_SEQ_MASK FIELD16(0xff00)
+#define EEPROM_FREQ_SEQ FIELD16(0x0300)
+
+/*
+ * EEPROM LED.
+ * POLARITY_RDY_G: Polarity RDY_G setting.
+ * POLARITY_RDY_A: Polarity RDY_A setting.
+ * POLARITY_ACT: Polarity ACT setting.
+ * POLARITY_GPIO_0: Polarity GPIO0 setting.
+ * POLARITY_GPIO_1: Polarity GPIO1 setting.
+ * POLARITY_GPIO_2: Polarity GPIO2 setting.
+ * POLARITY_GPIO_3: Polarity GPIO3 setting.
+ * POLARITY_GPIO_4: Polarity GPIO4 setting.
+ * LED_MODE: Led mode.
+ */
+#define EEPROM_LED 0x0030
+#define EEPROM_LED_POLARITY_RDY_G FIELD16(0x0001)
+#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002)
+#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004)
+#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008)
+#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010)
+#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020)
+#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040)
+#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080)
+#define EEPROM_LED_LED_MODE FIELD16(0x1f00)
+
+/*
+ * EEPROM TXPOWER 802.11A
+ */
+#define EEPROM_TXPOWER_A_START 0x0031
+#define EEPROM_TXPOWER_A_SIZE 12
+#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_A_2 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11BG
+ */
+#define EEPROM_RSSI_OFFSET_BG 0x004d
+#define EEPROM_RSSI_OFFSET_BG_1 FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_BG_2 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11A
+ */
+#define EEPROM_RSSI_OFFSET_A 0x004e
+#define EEPROM_RSSI_OFFSET_A_1 FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_A_2 FIELD16(0xff00)
+
+/*
+ * MCU mailbox commands.
+ */
+#define MCU_SLEEP 0x30
+#define MCU_WAKEUP 0x31
+#define MCU_LED 0x50
+#define MCU_LED_STRENGTH 0x52
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE ( 16 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE ( 16 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO and Beacon Ring.
+ */
+
+/*
+ * Word0
+ * TKIP_MIC: ASIC appends TKIP MIC if TKIP is used.
+ * KEY_TABLE: Use per-client pairwise KEY table.
+ * KEY_INDEX:
+ * Key index (0~31) to the pairwise KEY table.
+ * 0~3 to shared KEY table 0 (BSS0).
+ * 4~7 to shared KEY table 1 (BSS1).
+ * 8~11 to shared KEY table 2 (BSS2).
+ * 12~15 to shared KEY table 3 (BSS3).
+ * BURST: Next frame belongs to same "burst" event.
+ */
+#define TXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define TXD_W0_VALID FIELD32(0x00000002)
+#define TXD_W0_MORE_FRAG FIELD32(0x00000004)
+#define TXD_W0_ACK FIELD32(0x00000008)
+#define TXD_W0_TIMESTAMP FIELD32(0x00000010)
+#define TXD_W0_OFDM FIELD32(0x00000020)
+#define TXD_W0_IFS FIELD32(0x00000040)
+#define TXD_W0_RETRY_MODE FIELD32(0x00000080)
+#define TXD_W0_TKIP_MIC FIELD32(0x00000100)
+#define TXD_W0_KEY_TABLE FIELD32(0x00000200)
+#define TXD_W0_KEY_INDEX FIELD32(0x0000fc00)
+#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define TXD_W0_BURST FIELD32(0x10000000)
+#define TXD_W0_CIPHER_ALG FIELD32(0xe0000000)
+
+/*
+ * Word1
+ * HOST_Q_ID: EDCA/HCCA queue ID.
+ * HW_SEQUENCE: MAC overwrites the frame sequence number.
+ * BUFFER_COUNT: Number of buffers in this TXD.
+ */
+#define TXD_W1_HOST_Q_ID FIELD32(0x0000000f)
+#define TXD_W1_AIFSN FIELD32(0x000000f0)
+#define TXD_W1_CWMIN FIELD32(0x00000f00)
+#define TXD_W1_CWMAX FIELD32(0x0000f000)
+#define TXD_W1_IV_OFFSET FIELD32(0x003f0000)
+#define TXD_W1_PIGGY_BACK FIELD32(0x01000000)
+#define TXD_W1_HW_SEQUENCE FIELD32(0x10000000)
+#define TXD_W1_BUFFER_COUNT FIELD32(0xe0000000)
+
+/*
+ * Word2: PLCP information
+ */
+#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff)
+#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00)
+#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000)
+#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000)
+
+/*
+ * Word3
+ */
+#define TXD_W3_IV FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define TXD_W4_EIV FIELD32(0xffffffff)
+
+/*
+ * Word5
+ * FRAME_OFFSET: Frame start offset inside ASIC TXFIFO (after TXINFO field).
+ * TXD_W5_PID_SUBTYPE: Driver assigned packet ID index for txdone handler.
+ * TXD_W5_PID_TYPE: Driver assigned packet ID type for txdone handler.
+ * WAITING_DMA_DONE_INT: TXD been filled with data
+ * and waiting for TxDoneISR housekeeping.
+ */
+#define TXD_W5_FRAME_OFFSET FIELD32(0x000000ff)
+#define TXD_W5_PID_SUBTYPE FIELD32(0x00001f00)
+#define TXD_W5_PID_TYPE FIELD32(0x0000e000)
+#define TXD_W5_TX_POWER FIELD32(0x00ff0000)
+#define TXD_W5_WAITING_DMA_DONE_INT FIELD32(0x01000000)
+
+/*
+ * the above 24-byte is called TXINFO and will be DMAed to MAC block
+ * through TXFIFO. MAC block use this TXINFO to control the transmission
+ * behavior of this frame.
+ * The following fields are not used by MAC block.
+ * They are used by DMA block and HOST driver only.
+ * Once a frame has been DMA to ASIC, all the following fields are useless
+ * to ASIC.
+ */
+
+/*
+ * Word6-10: Buffer physical address
+ */
+#define TXD_W6_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff)
+#define TXD_W7_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff)
+#define TXD_W8_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff)
+#define TXD_W9_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff)
+#define TXD_W10_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff)
+
+/*
+ * Word11-13: Buffer length
+ */
+#define TXD_W11_BUFFER_LENGTH0 FIELD32(0x00000fff)
+#define TXD_W11_BUFFER_LENGTH1 FIELD32(0x0fff0000)
+#define TXD_W12_BUFFER_LENGTH2 FIELD32(0x00000fff)
+#define TXD_W12_BUFFER_LENGTH3 FIELD32(0x0fff0000)
+#define TXD_W13_BUFFER_LENGTH4 FIELD32(0x00000fff)
+
+/*
+ * Word14
+ */
+#define TXD_W14_SK_BUFFER FIELD32(0xffffffff)
+
+/*
+ * Word15
+ */
+#define TXD_W15_NEXT_SK_BUFFER FIELD32(0xffffffff)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ * CIPHER_ERROR: 1:ICV error, 2:MIC error, 3:invalid key.
+ * KEY_INDEX: Decryption key actually used.
+ */
+#define RXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define RXD_W0_DROP FIELD32(0x00000002)
+#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000004)
+#define RXD_W0_MULTICAST FIELD32(0x00000008)
+#define RXD_W0_BROADCAST FIELD32(0x00000010)
+#define RXD_W0_MY_BSS FIELD32(0x00000020)
+#define RXD_W0_CRC_ERROR FIELD32(0x00000040)
+#define RXD_W0_OFDM FIELD32(0x00000080)
+#define RXD_W0_CIPHER_ERROR FIELD32(0x00000300)
+#define RXD_W0_KEY_INDEX FIELD32(0x0000fc00)
+#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define RXD_W0_CIPHER_ALG FIELD32(0xe0000000)
+
+/*
+ * Word1
+ * SIGNAL: RX raw data rate reported by BBP.
+ */
+#define RXD_W1_SIGNAL FIELD32(0x000000ff)
+#define RXD_W1_RSSI_AGC FIELD32(0x00001f00)
+#define RXD_W1_RSSI_LNA FIELD32(0x00006000)
+#define RXD_W1_FRAME_OFFSET FIELD32(0x7f000000)
+
+/*
+ * Word2
+ * IV: Received IV of originally encrypted.
+ */
+#define RXD_W2_IV FIELD32(0xffffffff)
+
+/*
+ * Word3
+ * EIV: Received EIV of originally encrypted.
+ */
+#define RXD_W3_EIV FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define RXD_W4_RESERVED FIELD32(0xffffffff)
+
+/*
+ * the above 20-byte is called RXINFO and will be DMAed to MAC RX block
+ * and passed to the HOST driver.
+ * The following fields are for DMA block and HOST usage only.
+ * Can't be touched by ASIC MAC block.
+ */
+
+/*
+ * Word5
+ */
+#define RXD_W5_BUFFER_PHYSICAL_ADDRESS FIELD32(0xffffffff)
+
+/*
+ * Word6-15: Reserved
+ */
+#define RXD_W6_RESERVED FIELD32(0xffffffff)
+#define RXD_W7_RESERVED FIELD32(0xffffffff)
+#define RXD_W8_RESERVED FIELD32(0xffffffff)
+#define RXD_W9_RESERVED FIELD32(0xffffffff)
+#define RXD_W10_RESERVED FIELD32(0xffffffff)
+#define RXD_W11_RESERVED FIELD32(0xffffffff)
+#define RXD_W12_RESERVED FIELD32(0xffffffff)
+#define RXD_W13_RESERVED FIELD32(0xffffffff)
+#define RXD_W14_RESERVED FIELD32(0xffffffff)
+#define RXD_W15_RESERVED FIELD32(0xffffffff)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ */
+#define MIN_TXPOWER 0
+#define MAX_TXPOWER 31
+#define DEFAULT_TXPOWER 24
+
+#define TXPOWER_FROM_DEV(__txpower) \
+({ \
+ ((__txpower) > MAX_TXPOWER) ? \
+ DEFAULT_TXPOWER : (__txpower); \
+})
+
+#define TXPOWER_TO_DEV(__txpower) \
+({ \
+ ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
+ (__txpower)); \
+})
+
+#endif /* RT61PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
new file mode 100644
index 00000000000..dc640bf6b5e
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -0,0 +1,2111 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt73usb
+ Abstract: rt73usb device specific routines.
+ Supported chipsets: rt2571W & rt2671.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt73usb"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "rt2x00.h"
+#include "rt2x00usb.h"
+#include "rt73usb.h"
+
+/*
+ * Register access.
+ * All access to the CSR registers will go through the methods
+ * rt73usb_register_read and rt73usb_register_write.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers BBPCSR and RFCSR to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static inline void rt73usb_register_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset, u32 *value)
+{
+ __le32 reg;
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ &reg, sizeof(u32), REGISTER_TIMEOUT);
+ *value = le32_to_cpu(reg);
+}
+
+static inline void rt73usb_register_multiread(const struct rt2x00_dev
+ *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u32 length)
+{
+ int timeout = REGISTER_TIMEOUT * (length / sizeof(u32));
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+ USB_VENDOR_REQUEST_IN, offset,
+ value, length, timeout);
+}
+
+static inline void rt73usb_register_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset, u32 value)
+{
+ __le32 reg = cpu_to_le32(value);
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ &reg, sizeof(u32), REGISTER_TIMEOUT);
+}
+
+static inline void rt73usb_register_multiwrite(const struct rt2x00_dev
+ *rt2x00dev,
+ const unsigned int offset,
+ void *value, const u32 length)
+{
+ int timeout = REGISTER_TIMEOUT * (length / sizeof(u32));
+ rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT, offset,
+ value, length, timeout);
+}
+
+static u32 rt73usb_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ unsigned int i;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt73usb_register_read(rt2x00dev, PHY_CSR3, &reg);
+ if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+ break;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ return reg;
+}
+
+static void rt73usb_bbp_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u8 value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt73usb_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
+ return;
+ }
+
+ /*
+ * Write the data into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
+
+ rt73usb_register_write(rt2x00dev, PHY_CSR3, reg);
+}
+
+static void rt73usb_bbp_read(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u8 *value)
+{
+ u32 reg;
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt73usb_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+ return;
+ }
+
+ /*
+ * Write the request into the BBP.
+ */
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+ rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+ rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+
+ rt73usb_register_write(rt2x00dev, PHY_CSR3, reg);
+
+ /*
+ * Wait until the BBP becomes ready.
+ */
+ reg = rt73usb_bbp_check(rt2x00dev);
+ if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+ ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+ *value = 0xff;
+ return;
+ }
+
+ *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
+}
+
+static void rt73usb_rf_write(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, const u32 value)
+{
+ u32 reg;
+ unsigned int i;
+
+ if (!word)
+ return;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt73usb_register_read(rt2x00dev, PHY_CSR4, &reg);
+ if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
+ goto rf_write;
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
+ return;
+
+rf_write:
+ reg = 0;
+ rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+
+ /*
+ * RF5225 and RF2527 contain 21 bits per RF register value,
+ * all others contain 20 bits.
+ */
+ rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
+ 20 + !!(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527)));
+ rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+ rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+
+ rt73usb_register_write(rt2x00dev, PHY_CSR4, reg);
+ rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) )
+
+static void rt73usb_read_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 *data)
+{
+ rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static void rt73usb_write_csr(const struct rt2x00_dev *rt2x00dev,
+ const unsigned int word, u32 data)
+{
+ rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt73usb_rt2x00debug = {
+ .owner = THIS_MODULE,
+ .csr = {
+ .read = rt73usb_read_csr,
+ .write = rt73usb_write_csr,
+ .word_size = sizeof(u32),
+ .word_count = CSR_REG_SIZE / sizeof(u32),
+ },
+ .eeprom = {
+ .read = rt2x00_eeprom_read,
+ .write = rt2x00_eeprom_write,
+ .word_size = sizeof(u16),
+ .word_count = EEPROM_SIZE / sizeof(u16),
+ },
+ .bbp = {
+ .read = rt73usb_bbp_read,
+ .write = rt73usb_bbp_write,
+ .word_size = sizeof(u8),
+ .word_count = BBP_SIZE / sizeof(u8),
+ },
+ .rf = {
+ .read = rt2x00_rf_read,
+ .write = rt73usb_rf_write,
+ .word_size = sizeof(u32),
+ .word_count = RF_SIZE / sizeof(u32),
+ },
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
+ * Configuration handlers.
+ */
+static void rt73usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac)
+{
+ u32 tmp;
+
+ tmp = le32_to_cpu(mac[1]);
+ rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
+ mac[1] = cpu_to_le32(tmp);
+
+ rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, mac,
+ (2 * sizeof(__le32)));
+}
+
+static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid)
+{
+ u32 tmp;
+
+ tmp = le32_to_cpu(bssid[1]);
+ rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3);
+ bssid[1] = cpu_to_le32(tmp);
+
+ rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, bssid,
+ (2 * sizeof(__le32)));
+}
+
+static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+ const int tsf_sync)
+{
+ u32 reg;
+
+ /*
+ * Clear current synchronisation setup.
+ * For the Beacon base registers we only need to clear
+ * the first byte since that byte contains the VALID and OWNER
+ * bits which (when set to 0) will invalidate the entire beacon.
+ */
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0);
+ rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+ rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+ rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+ rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+
+ /*
+ * Enable synchronisation.
+ */
+ rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, tsf_sync);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+}
+
+static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev,
+ const int short_preamble,
+ const int ack_timeout,
+ const int ack_consume_time)
+{
+ u32 reg;
+
+ /*
+ * When in atomic context, reschedule and let rt2x00lib
+ * call this function again.
+ */
+ if (in_atomic()) {
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work);
+ return;
+ }
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
+ !!short_preamble);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
+
+static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev,
+ const int basic_rate_mask)
+{
+ rt73usb_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
+}
+
+static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
+ struct rf_channel *rf, const int txpower)
+{
+ u8 r3;
+ u8 r94;
+ u8 smart;
+
+ rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+ rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+ smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+ rt73usb_bbp_read(rt2x00dev, 3, &r3);
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+ rt73usb_bbp_write(rt2x00dev, 3, r3);
+
+ r94 = 6;
+ if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+ r94 += txpower - MAX_TXPOWER;
+ else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+ r94 += txpower;
+ rt73usb_bbp_write(rt2x00dev, 94, r94);
+
+ rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+ rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+ rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+ rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+ rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+ rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+ rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+ rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+ rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+ rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+ rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+ udelay(10);
+}
+
+static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+ const int txpower)
+{
+ struct rf_channel rf;
+
+ rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+ rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+ rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+ rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+ rt73usb_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx,
+ const int antenna_rx)
+{
+ u8 r3;
+ u8 r4;
+ u8 r77;
+
+ rt73usb_bbp_read(rt2x00dev, 3, &r3);
+ rt73usb_bbp_read(rt2x00dev, 4, &r4);
+ rt73usb_bbp_read(rt2x00dev, 77, &r77);
+
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
+
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
+ !!(rt2x00dev->curr_hwmode != HWMODE_A));
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+ if (rt2x00dev->curr_hwmode == HWMODE_A)
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ else
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+ if (rt2x00dev->curr_hwmode == HWMODE_A)
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ else
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ break;
+ }
+
+ rt73usb_bbp_write(rt2x00dev, 77, r77);
+ rt73usb_bbp_write(rt2x00dev, 3, r3);
+ rt73usb_bbp_write(rt2x00dev, 4, r4);
+}
+
+static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx,
+ const int antenna_rx)
+{
+ u8 r3;
+ u8 r4;
+ u8 r77;
+
+ rt73usb_bbp_read(rt2x00dev, 3, &r3);
+ rt73usb_bbp_read(rt2x00dev, 4, &r4);
+ rt73usb_bbp_read(rt2x00dev, 77, &r77);
+
+ rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
+ rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
+ !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
+
+ switch (antenna_rx) {
+ case ANTENNA_SW_DIVERSITY:
+ case ANTENNA_HW_DIVERSITY:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+ break;
+ case ANTENNA_A:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+ break;
+ case ANTENNA_B:
+ rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+ rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+ break;
+ }
+
+ rt73usb_bbp_write(rt2x00dev, 77, r77);
+ rt73usb_bbp_write(rt2x00dev, 3, r3);
+ rt73usb_bbp_write(rt2x00dev, 4, r4);
+}
+
+struct antenna_sel {
+ u8 word;
+ /*
+ * value[0] -> non-LNA
+ * value[1] -> LNA
+ */
+ u8 value[2];
+};
+
+static const struct antenna_sel antenna_sel_a[] = {
+ { 96, { 0x58, 0x78 } },
+ { 104, { 0x38, 0x48 } },
+ { 75, { 0xfe, 0x80 } },
+ { 86, { 0xfe, 0x80 } },
+ { 88, { 0xfe, 0x80 } },
+ { 35, { 0x60, 0x60 } },
+ { 97, { 0x58, 0x58 } },
+ { 98, { 0x58, 0x58 } },
+};
+
+static const struct antenna_sel antenna_sel_bg[] = {
+ { 96, { 0x48, 0x68 } },
+ { 104, { 0x2c, 0x3c } },
+ { 75, { 0xfe, 0x80 } },
+ { 86, { 0xfe, 0x80 } },
+ { 88, { 0xfe, 0x80 } },
+ { 35, { 0x50, 0x50 } },
+ { 97, { 0x48, 0x48 } },
+ { 98, { 0x48, 0x48 } },
+};
+
+static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev,
+ const int antenna_tx, const int antenna_rx)
+{
+ const struct antenna_sel *sel;
+ unsigned int lna;
+ unsigned int i;
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, PHY_CSR0, &reg);
+
+ if (rt2x00dev->curr_hwmode == HWMODE_A) {
+ sel = antenna_sel_a;
+ lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 0);
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 1);
+ } else {
+ sel = antenna_sel_bg;
+ lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 1);
+ rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 0);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
+ rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
+
+ rt73usb_register_write(rt2x00dev, PHY_CSR0, reg);
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF5226) ||
+ rt2x00_rf(&rt2x00dev->chip, RF5225))
+ rt73usb_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx);
+ else if (rt2x00_rf(&rt2x00dev->chip, RF2528) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527))
+ rt73usb_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx);
+}
+
+static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00lib_conf *libconf)
+{
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
+ rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR8, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
+ rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+ rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
+ rt73usb_register_write(rt2x00dev, MAC_CSR8, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
+ libconf->conf->beacon_int * 16);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+}
+
+static void rt73usb_config(struct rt2x00_dev *rt2x00dev,
+ const unsigned int flags,
+ struct rt2x00lib_conf *libconf)
+{
+ if (flags & CONFIG_UPDATE_PHYMODE)
+ rt73usb_config_phymode(rt2x00dev, libconf->basic_rates);
+ if (flags & CONFIG_UPDATE_CHANNEL)
+ rt73usb_config_channel(rt2x00dev, &libconf->rf,
+ libconf->conf->power_level);
+ if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+ rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level);
+ if (flags & CONFIG_UPDATE_ANTENNA)
+ rt73usb_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx,
+ libconf->conf->antenna_sel_rx);
+ if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+ rt73usb_config_duration(rt2x00dev, libconf);
+}
+
+/*
+ * LED functions.
+ */
+static void rt73usb_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR14, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR14_ON_PERIOD, 70);
+ rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, 30);
+ rt73usb_register_write(rt2x00dev, MAC_CSR14, reg);
+
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1);
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)
+ rt2x00_set_field16(&rt2x00dev->led_reg,
+ MCU_LEDCS_LINK_A_STATUS, 1);
+ else
+ rt2x00_set_field16(&rt2x00dev->led_reg,
+ MCU_LEDCS_LINK_BG_STATUS, 1);
+
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000,
+ rt2x00dev->led_reg, REGISTER_TIMEOUT);
+}
+
+static void rt73usb_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 0);
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, 0);
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, 0);
+
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000,
+ rt2x00dev->led_reg, REGISTER_TIMEOUT);
+}
+
+static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, int rssi)
+{
+ u32 led;
+
+ if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH)
+ return;
+
+ /*
+ * Led handling requires a positive value for the rssi,
+ * to do that correctly we need to add the correction.
+ */
+ rssi += rt2x00dev->rssi_offset;
+
+ if (rssi <= 30)
+ led = 0;
+ else if (rssi <= 39)
+ led = 1;
+ else if (rssi <= 49)
+ led = 2;
+ else if (rssi <= 53)
+ led = 3;
+ else if (rssi <= 63)
+ led = 4;
+ else
+ led = 5;
+
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, led,
+ rt2x00dev->led_reg, REGISTER_TIMEOUT);
+}
+
+/*
+ * Link tuning
+ */
+static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Update FCS error count from register.
+ */
+ rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
+
+ /*
+ * Update False CCA count from register.
+ */
+ rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
+ reg = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
+ rt2x00dev->link.false_cca =
+ rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
+}
+
+static void rt73usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ rt73usb_bbp_write(rt2x00dev, 17, 0x20);
+ rt2x00dev->link.vgc_level = 0x20;
+}
+
+static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+ int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
+ u8 r17;
+ u8 up_bound;
+ u8 low_bound;
+
+ /*
+ * Update Led strength
+ */
+ rt73usb_activity_led(rt2x00dev, rssi);
+
+ rt73usb_bbp_read(rt2x00dev, 17, &r17);
+
+ /*
+ * Determine r17 bounds.
+ */
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ low_bound = 0x28;
+ up_bound = 0x48;
+
+ if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+ low_bound += 0x10;
+ up_bound += 0x10;
+ }
+ } else {
+ if (rssi > -82) {
+ low_bound = 0x1c;
+ up_bound = 0x40;
+ } else if (rssi > -84) {
+ low_bound = 0x1c;
+ up_bound = 0x20;
+ } else {
+ low_bound = 0x1c;
+ up_bound = 0x1c;
+ }
+
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) {
+ low_bound += 0x14;
+ up_bound += 0x10;
+ }
+ }
+
+ /*
+ * Special big-R17 for very short distance
+ */
+ if (rssi > -35) {
+ if (r17 != 0x60)
+ rt73usb_bbp_write(rt2x00dev, 17, 0x60);
+ return;
+ }
+
+ /*
+ * Special big-R17 for short distance
+ */
+ if (rssi >= -58) {
+ if (r17 != up_bound)
+ rt73usb_bbp_write(rt2x00dev, 17, up_bound);
+ return;
+ }
+
+ /*
+ * Special big-R17 for middle-short distance
+ */
+ if (rssi >= -66) {
+ low_bound += 0x10;
+ if (r17 != low_bound)
+ rt73usb_bbp_write(rt2x00dev, 17, low_bound);
+ return;
+ }
+
+ /*
+ * Special mid-R17 for middle distance
+ */
+ if (rssi >= -74) {
+ if (r17 != (low_bound + 0x10))
+ rt73usb_bbp_write(rt2x00dev, 17, low_bound + 0x08);
+ return;
+ }
+
+ /*
+ * Special case: Change up_bound based on the rssi.
+ * Lower up_bound when rssi is weaker then -74 dBm.
+ */
+ up_bound -= 2 * (-74 - rssi);
+ if (low_bound > up_bound)
+ up_bound = low_bound;
+
+ if (r17 > up_bound) {
+ rt73usb_bbp_write(rt2x00dev, 17, up_bound);
+ return;
+ }
+
+ /*
+ * r17 does not yet exceed upper limit, continue and base
+ * the r17 tuning on the false CCA count.
+ */
+ if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) {
+ r17 += 4;
+ if (r17 > up_bound)
+ r17 = up_bound;
+ rt73usb_bbp_write(rt2x00dev, 17, r17);
+ } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
+ r17 -= 4;
+ if (r17 < low_bound)
+ r17 = low_bound;
+ rt73usb_bbp_write(rt2x00dev, 17, r17);
+ }
+}
+
+/*
+ * Firmware name function.
+ */
+static char *rt73usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
+{
+ return FIRMWARE_RT2571;
+}
+
+/*
+ * Initialization functions.
+ */
+static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
+ const size_t len)
+{
+ unsigned int i;
+ int status;
+ u32 reg;
+ char *ptr = data;
+ char *cache;
+ int buflen;
+ int timeout;
+
+ /*
+ * Wait for stable hardware.
+ */
+ for (i = 0; i < 100; i++) {
+ rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+ if (reg)
+ break;
+ msleep(1);
+ }
+
+ if (!reg) {
+ ERROR(rt2x00dev, "Unstable hardware.\n");
+ return -EBUSY;
+ }
+
+ /*
+ * Write firmware to device.
+ * We setup a seperate cache for this action,
+ * since we are going to write larger chunks of data
+ * then normally used cache size.
+ */
+ cache = kmalloc(CSR_CACHE_SIZE_FIRMWARE, GFP_KERNEL);
+ if (!cache) {
+ ERROR(rt2x00dev, "Failed to allocate firmware cache.\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < len; i += CSR_CACHE_SIZE_FIRMWARE) {
+ buflen = min_t(int, len - i, CSR_CACHE_SIZE_FIRMWARE);
+ timeout = REGISTER_TIMEOUT * (buflen / sizeof(u32));
+
+ memcpy(cache, ptr, buflen);
+
+ rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT,
+ FIRMWARE_IMAGE_BASE + i, 0x0000,
+ cache, buflen, timeout);
+
+ ptr += buflen;
+ }
+
+ kfree(cache);
+
+ /*
+ * Send firmware request to device to load firmware,
+ * we need to specify a long timeout time.
+ */
+ status = rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE,
+ 0x0000, USB_MODE_FIRMWARE,
+ REGISTER_TIMEOUT_FIRMWARE);
+ if (status < 0) {
+ ERROR(rt2x00dev, "Failed to write Firmware to device.\n");
+ return status;
+ }
+
+ rt73usb_disable_led(rt2x00dev);
+
+ return 0;
+}
+
+static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1, 30); /* Rssi */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2, 42); /* OFDM Rate */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */
+ rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3_VALID, 1);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR1, reg);
+
+ /*
+ * CCK TXD BBP registers
+ */
+ rt73usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0, 13);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1, 12);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2, 11);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10);
+ rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3_VALID, 1);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+
+ /*
+ * OFDM TXD BBP registers
+ */
+ rt73usb_register_read(rt2x00dev, TXRX_CSR3, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0, 7);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1, 6);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1_VALID, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2, 5);
+ rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2_VALID, 1);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR3, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_6MBS, 59);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_9MBS, 53);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_12MBS, 49);
+ rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_18MBS, 46);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR7, reg);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_24MBS, 44);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_36MBS, 42);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_48MBS, 42);
+ rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+
+ rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR6, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR6_MAX_FRAME_UNIT, 0xfff);
+ rt73usb_register_write(rt2x00dev, MAC_CSR6, reg);
+
+ rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
+
+ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+ return -EBUSY;
+
+ rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00);
+
+ /*
+ * Invalidate all Shared Keys (SEC_CSR0),
+ * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
+ */
+ rt73usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
+ rt73usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
+ rt73usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
+
+ reg = 0x000023b0;
+ if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF2527))
+ rt2x00_set_field32(&reg, PHY_CSR1_RF_RPI, 1);
+ rt73usb_register_write(rt2x00dev, PHY_CSR1, reg);
+
+ rt73usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06);
+ rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
+ rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408);
+
+ rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC0_TX_OP, 0);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC1_TX_OP, 0);
+ rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
+
+ rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC2_TX_OP, 192);
+ rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC3_TX_OP, 48);
+ rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
+ rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+
+ /*
+ * We must clear the error counters.
+ * These registers are cleared on read,
+ * so we may pass a useless variable to store the value.
+ */
+ rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
+ rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
+ rt73usb_register_read(rt2x00dev, STA_CSR2, &reg);
+
+ /*
+ * Reset MAC and BBP registers.
+ */
+ rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
+ rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
+ rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
+ rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
+ rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
+ rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+ return 0;
+}
+
+static int rt73usb_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+ unsigned int i;
+ u16 eeprom;
+ u8 reg_id;
+ u8 value;
+
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt73usb_bbp_read(rt2x00dev, 0, &value);
+ if ((value != 0xff) && (value != 0x00))
+ goto continue_csr_init;
+ NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+ udelay(REGISTER_BUSY_DELAY);
+ }
+
+ ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+ return -EACCES;
+
+continue_csr_init:
+ rt73usb_bbp_write(rt2x00dev, 3, 0x80);
+ rt73usb_bbp_write(rt2x00dev, 15, 0x30);
+ rt73usb_bbp_write(rt2x00dev, 21, 0xc8);
+ rt73usb_bbp_write(rt2x00dev, 22, 0x38);
+ rt73usb_bbp_write(rt2x00dev, 23, 0x06);
+ rt73usb_bbp_write(rt2x00dev, 24, 0xfe);
+ rt73usb_bbp_write(rt2x00dev, 25, 0x0a);
+ rt73usb_bbp_write(rt2x00dev, 26, 0x0d);
+ rt73usb_bbp_write(rt2x00dev, 32, 0x0b);
+ rt73usb_bbp_write(rt2x00dev, 34, 0x12);
+ rt73usb_bbp_write(rt2x00dev, 37, 0x07);
+ rt73usb_bbp_write(rt2x00dev, 39, 0xf8);
+ rt73usb_bbp_write(rt2x00dev, 41, 0x60);
+ rt73usb_bbp_write(rt2x00dev, 53, 0x10);
+ rt73usb_bbp_write(rt2x00dev, 54, 0x18);
+ rt73usb_bbp_write(rt2x00dev, 60, 0x10);
+ rt73usb_bbp_write(rt2x00dev, 61, 0x04);
+ rt73usb_bbp_write(rt2x00dev, 62, 0x04);
+ rt73usb_bbp_write(rt2x00dev, 75, 0xfe);
+ rt73usb_bbp_write(rt2x00dev, 86, 0xfe);
+ rt73usb_bbp_write(rt2x00dev, 88, 0xfe);
+ rt73usb_bbp_write(rt2x00dev, 90, 0x0f);
+ rt73usb_bbp_write(rt2x00dev, 99, 0x00);
+ rt73usb_bbp_write(rt2x00dev, 102, 0x16);
+ rt73usb_bbp_write(rt2x00dev, 107, 0x04);
+
+ DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+ for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+ if (eeprom != 0xffff && eeprom != 0x0000) {
+ reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+ value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+ DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+ reg_id, value);
+ rt73usb_bbp_write(rt2x00dev, reg_id, value);
+ }
+ }
+ DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+ return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
+ state == STATE_RADIO_RX_OFF);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
+static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
+ * Initialize all registers.
+ */
+ if (rt73usb_init_registers(rt2x00dev) ||
+ rt73usb_init_bbp(rt2x00dev)) {
+ ERROR(rt2x00dev, "Register initialization failed.\n");
+ return -EIO;
+ }
+
+ rt2x00usb_enable_radio(rt2x00dev);
+
+ /*
+ * Enable LED
+ */
+ rt73usb_enable_led(rt2x00dev);
+
+ return 0;
+}
+
+static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+ /*
+ * Disable LED
+ */
+ rt73usb_disable_led(rt2x00dev);
+
+ rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
+
+ /*
+ * Disable synchronisation.
+ */
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0);
+
+ rt2x00usb_disable_radio(rt2x00dev);
+}
+
+static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
+{
+ u32 reg;
+ unsigned int i;
+ char put_to_sleep;
+ char current_state;
+
+ put_to_sleep = (state != STATE_AWAKE);
+
+ rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+ rt2x00_set_field32(&reg, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep);
+ rt2x00_set_field32(&reg, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep);
+ rt73usb_register_write(rt2x00dev, MAC_CSR12, reg);
+
+ /*
+ * Device is not guaranteed to be in the requested state yet.
+ * We must wait until the register indicates that the
+ * device has entered the correct state.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+ current_state =
+ rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE);
+ if (current_state == !put_to_sleep)
+ return 0;
+ msleep(10);
+ }
+
+ NOTICE(rt2x00dev, "Device failed to enter state %d, "
+ "current device state %d.\n", !put_to_sleep, current_state);
+
+ return -EBUSY;
+}
+
+static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
+ enum dev_state state)
+{
+ int retval = 0;
+
+ switch (state) {
+ case STATE_RADIO_ON:
+ retval = rt73usb_enable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_OFF:
+ rt73usb_disable_radio(rt2x00dev);
+ break;
+ case STATE_RADIO_RX_ON:
+ case STATE_RADIO_RX_OFF:
+ rt73usb_toggle_rx(rt2x00dev, state);
+ break;
+ case STATE_DEEP_SLEEP:
+ case STATE_SLEEP:
+ case STATE_STANDBY:
+ case STATE_AWAKE:
+ retval = rt73usb_set_state(rt2x00dev, state);
+ break;
+ default:
+ retval = -ENOTSUPP;
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+ struct data_desc *txd,
+ struct txdata_entry_desc *desc,
+ struct ieee80211_hdr *ieee80211hdr,
+ unsigned int length,
+ struct ieee80211_tx_control *control)
+{
+ u32 word;
+
+ /*
+ * Start writing the descriptor words.
+ */
+ rt2x00_desc_read(txd, 1, &word);
+ rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue);
+ rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs);
+ rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
+ rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
+ rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+ rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+ rt2x00_desc_write(txd, 1, word);
+
+ rt2x00_desc_read(txd, 2, &word);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
+ rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
+ rt2x00_desc_write(txd, 2, word);
+
+ rt2x00_desc_read(txd, 5, &word);
+ rt2x00_set_field32(&word, TXD_W5_TX_POWER,
+ TXPOWER_TO_DEV(control->power_level));
+ rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
+ rt2x00_desc_write(txd, 5, word);
+
+ rt2x00_desc_read(txd, 0, &word);
+ rt2x00_set_field32(&word, TXD_W0_BURST,
+ test_bit(ENTRY_TXD_BURST, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+ rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+ test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_ACK,
+ !(control->flags & IEEE80211_TXCTL_NO_ACK));
+ rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+ test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_OFDM,
+ test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+ rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+ !!(control->flags &
+ IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+ rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
+ rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+ rt2x00_set_field32(&word, TXD_W0_BURST2,
+ test_bit(ENTRY_TXD_BURST, &desc->flags));
+ rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
+ rt2x00_desc_write(txd, 0, word);
+}
+
+static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
+ int maxpacket, struct sk_buff *skb)
+{
+ int length;
+
+ /*
+ * The length _must_ be a multiple of 4,
+ * but it must _not_ be a multiple of the USB packet size.
+ */
+ length = roundup(skb->len, 4);
+ length += (4 * !(length % maxpacket));
+
+ return length;
+}
+
+/*
+ * TX data initialization
+ */
+static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+ unsigned int queue)
+{
+ u32 reg;
+
+ if (queue != IEEE80211_TX_QUEUE_BEACON)
+ return;
+
+ /*
+ * For Wi-Fi faily generated beacons between participating stations.
+ * Set TBTT phase adaptive adjustment step to 8us (default 16us)
+ */
+ rt73usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+ if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
+ rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+ }
+}
+
+/*
+ * RX control handlers
+ */
+static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
+{
+ u16 eeprom;
+ u8 offset;
+ u8 lna;
+
+ lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA);
+ switch (lna) {
+ case 3:
+ offset = 90;
+ break;
+ case 2:
+ offset = 74;
+ break;
+ case 1:
+ offset = 64;
+ break;
+ default:
+ return 0;
+ }
+
+ if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+ if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+ if (lna == 3 || lna == 2)
+ offset += 10;
+ } else {
+ if (lna == 3)
+ offset += 6;
+ else if (lna == 2)
+ offset += 8;
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+ offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+ } else {
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+ offset += 14;
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+ offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+ }
+
+ return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
+}
+
+static void rt73usb_fill_rxdone(struct data_entry *entry,
+ struct rxdata_entry_desc *desc)
+{
+ struct data_desc *rxd = (struct data_desc *)entry->skb->data;
+ u32 word0;
+ u32 word1;
+
+ rt2x00_desc_read(rxd, 0, &word0);
+ rt2x00_desc_read(rxd, 1, &word1);
+
+ desc->flags = 0;
+ if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+ desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+
+ /*
+ * Obtain the status about this packet.
+ */
+ desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+ desc->rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1);
+ desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+ desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+
+ /*
+ * Pull the skb to clear the descriptor area.
+ */
+ skb_pull(entry->skb, entry->ring->desc_size);
+
+ return;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u16 word;
+ u8 *mac;
+ s8 value;
+
+ rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE);
+
+ /*
+ * Start validation of the data that has been read.
+ */
+ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+ if (!is_valid_ether_addr(mac)) {
+ DECLARE_MAC_BUF(macbuf);
+
+ random_ether_addr(mac);
+ EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
+ rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5226);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+ EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+ EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_G, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_A, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_ACT, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_0, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_1, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_2, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_3, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_4, 0);
+ rt2x00_set_field16(&word, EEPROM_LED_LED_MODE,
+ LED_MODE_DEFAULT);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word);
+ EEPROM(rt2x00dev, "Led: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
+ rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
+ EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+ EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ } else {
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+ }
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word);
+ if (word == 0xffff) {
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+ EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+ } else {
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+ value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2);
+ if (value < -10 || value > 10)
+ rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+ rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+ }
+
+ return 0;
+}
+
+static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ u16 value;
+ u16 eeprom;
+
+ /*
+ * Read EEPROM word for configuration.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+ /*
+ * Identify RF chipset.
+ */
+ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+ rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+ rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
+
+ if (!rt2x00_check_rev(&rt2x00dev->chip, 0x25730)) {
+ ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
+ return -ENODEV;
+ }
+
+ if (!rt2x00_rf(&rt2x00dev->chip, RF5226) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2528) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF5225) &&
+ !rt2x00_rf(&rt2x00dev->chip, RF2527)) {
+ ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Identify default antenna configuration.
+ */
+ rt2x00dev->hw->conf.antenna_sel_tx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+ rt2x00dev->hw->conf.antenna_sel_rx =
+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+ /*
+ * Read the Frame type.
+ */
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE))
+ __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
+
+ /*
+ * Read frequency offset.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
+ rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
+
+ /*
+ * Read external LNA informations.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA)) {
+ __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+ __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+ }
+
+ /*
+ * Store led settings, for correct led behaviour.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom);
+
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE,
+ rt2x00dev->led_mode);
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_0));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_1));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_2));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_3));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_GPIO_4));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT,
+ rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_RDY_G));
+ rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A,
+ rt2x00_get_field16(eeprom,
+ EEPROM_LED_POLARITY_RDY_A));
+
+ return 0;
+}
+
+/*
+ * RF value list for RF2528
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2528[] = {
+ { 1, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea0b },
+ { 2, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea1f },
+ { 3, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea0b },
+ { 4, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea1f },
+ { 5, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea0b },
+ { 6, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea1f },
+ { 7, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea0b },
+ { 8, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea1f },
+ { 9, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea0b },
+ { 10, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea1f },
+ { 11, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea0b },
+ { 12, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea1f },
+ { 13, 0x00002c0c, 0x0000079e, 0x00068255, 0x000fea0b },
+ { 14, 0x00002c0c, 0x000007a2, 0x00068255, 0x000fea13 },
+};
+
+/*
+ * RF value list for RF5226
+ * Supports: 2.4 GHz & 5.2 GHz
+ */
+static const struct rf_channel rf_vals_5226[] = {
+ { 1, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea0b },
+ { 2, 0x00002c0c, 0x00000786, 0x00068255, 0x000fea1f },
+ { 3, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea0b },
+ { 4, 0x00002c0c, 0x0000078a, 0x00068255, 0x000fea1f },
+ { 5, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea0b },
+ { 6, 0x00002c0c, 0x0000078e, 0x00068255, 0x000fea1f },
+ { 7, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea0b },
+ { 8, 0x00002c0c, 0x00000792, 0x00068255, 0x000fea1f },
+ { 9, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea0b },
+ { 10, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea1f },
+ { 11, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea0b },
+ { 12, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea1f },
+ { 13, 0x00002c0c, 0x0000079e, 0x00068255, 0x000fea0b },
+ { 14, 0x00002c0c, 0x000007a2, 0x00068255, 0x000fea13 },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x00002c0c, 0x0000099a, 0x00098255, 0x000fea23 },
+ { 40, 0x00002c0c, 0x000009a2, 0x00098255, 0x000fea03 },
+ { 44, 0x00002c0c, 0x000009a6, 0x00098255, 0x000fea0b },
+ { 48, 0x00002c0c, 0x000009aa, 0x00098255, 0x000fea13 },
+ { 52, 0x00002c0c, 0x000009ae, 0x00098255, 0x000fea1b },
+ { 56, 0x00002c0c, 0x000009b2, 0x00098255, 0x000fea23 },
+ { 60, 0x00002c0c, 0x000009ba, 0x00098255, 0x000fea03 },
+ { 64, 0x00002c0c, 0x000009be, 0x00098255, 0x000fea0b },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x00002c0c, 0x00000a2a, 0x000b8255, 0x000fea03 },
+ { 104, 0x00002c0c, 0x00000a2e, 0x000b8255, 0x000fea0b },
+ { 108, 0x00002c0c, 0x00000a32, 0x000b8255, 0x000fea13 },
+ { 112, 0x00002c0c, 0x00000a36, 0x000b8255, 0x000fea1b },
+ { 116, 0x00002c0c, 0x00000a3a, 0x000b8255, 0x000fea23 },
+ { 120, 0x00002c0c, 0x00000a82, 0x000b8255, 0x000fea03 },
+ { 124, 0x00002c0c, 0x00000a86, 0x000b8255, 0x000fea0b },
+ { 128, 0x00002c0c, 0x00000a8a, 0x000b8255, 0x000fea13 },
+ { 132, 0x00002c0c, 0x00000a8e, 0x000b8255, 0x000fea1b },
+ { 136, 0x00002c0c, 0x00000a92, 0x000b8255, 0x000fea23 },
+
+ /* 802.11 UNII */
+ { 140, 0x00002c0c, 0x00000a9a, 0x000b8255, 0x000fea03 },
+ { 149, 0x00002c0c, 0x00000aa2, 0x000b8255, 0x000fea1f },
+ { 153, 0x00002c0c, 0x00000aa6, 0x000b8255, 0x000fea27 },
+ { 157, 0x00002c0c, 0x00000aae, 0x000b8255, 0x000fea07 },
+ { 161, 0x00002c0c, 0x00000ab2, 0x000b8255, 0x000fea0f },
+ { 165, 0x00002c0c, 0x00000ab6, 0x000b8255, 0x000fea17 },
+
+ /* MMAC(Japan)J52 ch 34,38,42,46 */
+ { 34, 0x00002c0c, 0x0008099a, 0x000da255, 0x000d3a0b },
+ { 38, 0x00002c0c, 0x0008099e, 0x000da255, 0x000d3a13 },
+ { 42, 0x00002c0c, 0x000809a2, 0x000da255, 0x000d3a1b },
+ { 46, 0x00002c0c, 0x000809a6, 0x000da255, 0x000d3a23 },
+};
+
+/*
+ * RF value list for RF5225 & RF2527
+ * Supports: 2.4 GHz & 5.2 GHz
+ */
+static const struct rf_channel rf_vals_5225_2527[] = {
+ { 1, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b },
+ { 2, 0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f },
+ { 3, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b },
+ { 4, 0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f },
+ { 5, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b },
+ { 6, 0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f },
+ { 7, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b },
+ { 8, 0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f },
+ { 9, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b },
+ { 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f },
+ { 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b },
+ { 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f },
+ { 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b },
+ { 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 },
+
+ /* 802.11 UNI / HyperLan 2 */
+ { 36, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa23 },
+ { 40, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa03 },
+ { 44, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa0b },
+ { 48, 0x00002ccc, 0x000049aa, 0x0009be55, 0x000ffa13 },
+ { 52, 0x00002ccc, 0x000049ae, 0x0009ae55, 0x000ffa1b },
+ { 56, 0x00002ccc, 0x000049b2, 0x0009ae55, 0x000ffa23 },
+ { 60, 0x00002ccc, 0x000049ba, 0x0009ae55, 0x000ffa03 },
+ { 64, 0x00002ccc, 0x000049be, 0x0009ae55, 0x000ffa0b },
+
+ /* 802.11 HyperLan 2 */
+ { 100, 0x00002ccc, 0x00004a2a, 0x000bae55, 0x000ffa03 },
+ { 104, 0x00002ccc, 0x00004a2e, 0x000bae55, 0x000ffa0b },
+ { 108, 0x00002ccc, 0x00004a32, 0x000bae55, 0x000ffa13 },
+ { 112, 0x00002ccc, 0x00004a36, 0x000bae55, 0x000ffa1b },
+ { 116, 0x00002ccc, 0x00004a3a, 0x000bbe55, 0x000ffa23 },
+ { 120, 0x00002ccc, 0x00004a82, 0x000bbe55, 0x000ffa03 },
+ { 124, 0x00002ccc, 0x00004a86, 0x000bbe55, 0x000ffa0b },
+ { 128, 0x00002ccc, 0x00004a8a, 0x000bbe55, 0x000ffa13 },
+ { 132, 0x00002ccc, 0x00004a8e, 0x000bbe55, 0x000ffa1b },
+ { 136, 0x00002ccc, 0x00004a92, 0x000bbe55, 0x000ffa23 },
+
+ /* 802.11 UNII */
+ { 140, 0x00002ccc, 0x00004a9a, 0x000bbe55, 0x000ffa03 },
+ { 149, 0x00002ccc, 0x00004aa2, 0x000bbe55, 0x000ffa1f },
+ { 153, 0x00002ccc, 0x00004aa6, 0x000bbe55, 0x000ffa27 },
+ { 157, 0x00002ccc, 0x00004aae, 0x000bbe55, 0x000ffa07 },
+ { 161, 0x00002ccc, 0x00004ab2, 0x000bbe55, 0x000ffa0f },
+ { 165, 0x00002ccc, 0x00004ab6, 0x000bbe55, 0x000ffa17 },
+
+ /* MMAC(Japan)J52 ch 34,38,42,46 */
+ { 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa0b },
+ { 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000ffa13 },
+ { 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa1b },
+ { 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa23 },
+};
+
+
+static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ u8 *txpower;
+ unsigned int i;
+
+ /*
+ * Initialize all hw fields.
+ */
+ rt2x00dev->hw->flags =
+ IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+ rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
+ rt2x00dev->hw->max_signal = MAX_SIGNAL;
+ rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+ rt2x00dev->hw->queues = 5;
+
+ SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
+ SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+ rt2x00_eeprom_addr(rt2x00dev,
+ EEPROM_MAC_ADDR_0));
+
+ /*
+ * Convert tx_power array in eeprom.
+ */
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ /*
+ * Initialize hw_mode information.
+ */
+ spec->num_modes = 2;
+ spec->num_rates = 12;
+ spec->tx_power_a = NULL;
+ spec->tx_power_bg = txpower;
+ spec->tx_power_default = DEFAULT_TXPOWER;
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF2528)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528);
+ spec->channels = rf_vals_bg_2528;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_5226);
+ spec->channels = rf_vals_5226;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) {
+ spec->num_channels = 14;
+ spec->channels = rf_vals_5225_2527;
+ } else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) {
+ spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527);
+ spec->channels = rf_vals_5225_2527;
+ }
+
+ if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+ rt2x00_rf(&rt2x00dev->chip, RF5226)) {
+ spec->num_modes = 3;
+
+ txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
+ for (i = 0; i < 14; i++)
+ txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+ spec->tx_power_a = txpower;
+ }
+}
+
+static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+ int retval;
+
+ /*
+ * Allocate eeprom data.
+ */
+ retval = rt73usb_validate_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ retval = rt73usb_init_eeprom(rt2x00dev);
+ if (retval)
+ return retval;
+
+ /*
+ * Initialize hw specifications.
+ */
+ rt73usb_probe_hw_mode(rt2x00dev);
+
+ /*
+ * This device requires firmware
+ */
+ __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
+
+ /*
+ * Set the rssi offset.
+ */
+ rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+ return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt73usb_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct interface *intf = &rt2x00dev->interface;
+ u32 reg;
+
+ /*
+ * Mask off any flags we are going to ignore from
+ * the total_flags field.
+ */
+ *total_flags &=
+ FIF_ALLMULTI |
+ FIF_FCSFAIL |
+ FIF_PLCPFAIL |
+ FIF_CONTROL |
+ FIF_OTHER_BSS |
+ FIF_PROMISC_IN_BSS;
+
+ /*
+ * Apply some rules to the filters:
+ * - Some filters imply different filters to be set.
+ * - Some things we can't filter out at all.
+ * - Some filters are set based on interface type.
+ */
+ if (mc_count)
+ *total_flags |= FIF_ALLMULTI;
+ if (*total_flags & FIF_OTHER_BSS ||
+ *total_flags & FIF_PROMISC_IN_BSS)
+ *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+ if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+ *total_flags |= FIF_PROMISC_IN_BSS;
+
+ /*
+ * Check if there is any work left for us.
+ */
+ if (intf->filter == *total_flags)
+ return;
+ intf->filter = *total_flags;
+
+ /*
+ * When in atomic context, reschedule and let rt2x00lib
+ * call this function again.
+ */
+ if (in_atomic()) {
+ queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+ return;
+ }
+
+ /*
+ * Start configuration steps.
+ * Note that the version error will always be dropped
+ * and broadcast frames will always be accepted since
+ * there is no filter for it at this time.
+ */
+ rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
+ !(*total_flags & FIF_FCSFAIL));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
+ !(*total_flags & FIF_PLCPFAIL));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
+ !(*total_flags & FIF_CONTROL));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
+ !(*total_flags & FIF_PROMISC_IN_BSS));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
+ !(*total_flags & FIF_ALLMULTI));
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BROADCAST, 0);
+ rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 1);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
+static int rt73usb_set_retry_limit(struct ieee80211_hw *hw,
+ u32 short_retry, u32 long_retry)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+ rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
+ rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+ return 0;
+}
+
+#if 0
+/*
+ * Mac80211 demands get_tsf must be atomic.
+ * This is not possible for rt73usb since all register access
+ * functions require sleeping. Untill mac80211 no longer needs
+ * get_tsf to be atomic, this function should be disabled.
+ */
+static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ u64 tsf;
+ u32 reg;
+
+ rt73usb_register_read(rt2x00dev, TXRX_CSR13, &reg);
+ tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32;
+ rt73usb_register_read(rt2x00dev, TXRX_CSR12, &reg);
+ tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER);
+
+ return tsf;
+}
+#else
+#define rt73usb_get_tsf NULL
+#endif
+
+static void rt73usb_reset_tsf(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ rt73usb_register_write(rt2x00dev, TXRX_CSR12, 0);
+ rt73usb_register_write(rt2x00dev, TXRX_CSR13, 0);
+}
+
+static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ int timeout;
+
+ /*
+ * Just in case the ieee80211 doesn't set this,
+ * but we need this queue set for the descriptor
+ * initialization.
+ */
+ control->queue = IEEE80211_TX_QUEUE_BEACON;
+
+ /*
+ * First we create the beacon.
+ */
+ skb_push(skb, TXD_DESC_SIZE);
+ memset(skb->data, 0, TXD_DESC_SIZE);
+
+ rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
+ (struct ieee80211_hdr *)(skb->data +
+ TXD_DESC_SIZE),
+ skb->len - TXD_DESC_SIZE, control);
+
+ /*
+ * Write entire beacon with descriptor to register,
+ * and kick the beacon generator.
+ */
+ timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32));
+ rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
+ USB_VENDOR_REQUEST_OUT,
+ HW_BEACON_BASE0, 0x0000,
+ skb->data, skb->len, timeout);
+ rt73usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+ return 0;
+}
+
+static const struct ieee80211_ops rt73usb_mac80211_ops = {
+ .tx = rt2x00mac_tx,
+ .start = rt2x00mac_start,
+ .stop = rt2x00mac_stop,
+ .add_interface = rt2x00mac_add_interface,
+ .remove_interface = rt2x00mac_remove_interface,
+ .config = rt2x00mac_config,
+ .config_interface = rt2x00mac_config_interface,
+ .configure_filter = rt73usb_configure_filter,
+ .get_stats = rt2x00mac_get_stats,
+ .set_retry_limit = rt73usb_set_retry_limit,
+ .erp_ie_changed = rt2x00mac_erp_ie_changed,
+ .conf_tx = rt2x00mac_conf_tx,
+ .get_tx_stats = rt2x00mac_get_tx_stats,
+ .get_tsf = rt73usb_get_tsf,
+ .reset_tsf = rt73usb_reset_tsf,
+ .beacon_update = rt73usb_beacon_update,
+};
+
+static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
+ .probe_hw = rt73usb_probe_hw,
+ .get_firmware_name = rt73usb_get_firmware_name,
+ .load_firmware = rt73usb_load_firmware,
+ .initialize = rt2x00usb_initialize,
+ .uninitialize = rt2x00usb_uninitialize,
+ .set_device_state = rt73usb_set_device_state,
+ .link_stats = rt73usb_link_stats,
+ .reset_tuner = rt73usb_reset_tuner,
+ .link_tuner = rt73usb_link_tuner,
+ .write_tx_desc = rt73usb_write_tx_desc,
+ .write_tx_data = rt2x00usb_write_tx_data,
+ .get_tx_data_len = rt73usb_get_tx_data_len,
+ .kick_tx_queue = rt73usb_kick_tx_queue,
+ .fill_rxdone = rt73usb_fill_rxdone,
+ .config_mac_addr = rt73usb_config_mac_addr,
+ .config_bssid = rt73usb_config_bssid,
+ .config_type = rt73usb_config_type,
+ .config_preamble = rt73usb_config_preamble,
+ .config = rt73usb_config,
+};
+
+static const struct rt2x00_ops rt73usb_ops = {
+ .name = DRV_NAME,
+ .rxd_size = RXD_DESC_SIZE,
+ .txd_size = TXD_DESC_SIZE,
+ .eeprom_size = EEPROM_SIZE,
+ .rf_size = RF_SIZE,
+ .lib = &rt73usb_rt2x00_ops,
+ .hw = &rt73usb_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+ .debugfs = &rt73usb_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * rt73usb module information.
+ */
+static struct usb_device_id rt73usb_device_table[] = {
+ /* AboCom */
+ { USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Askey */
+ { USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* ASUS */
+ { USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Belkin */
+ { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x050d, 0x905c), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Billionton */
+ { USB_DEVICE(0x1631, 0xc019), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Buffalo */
+ { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* CNet */
+ { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Conceptronic */
+ { USB_DEVICE(0x14b2, 0x3c22), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* D-Link */
+ { USB_DEVICE(0x07d1, 0x3c03), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c04), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Gemtek */
+ { USB_DEVICE(0x15a9, 0x0004), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Gigabyte */
+ { USB_DEVICE(0x1044, 0x8008), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x1044, 0x800a), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Huawei-3Com */
+ { USB_DEVICE(0x1472, 0x0009), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Hercules */
+ { USB_DEVICE(0x06f8, 0xe010), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x06f8, 0xe020), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Linksys */
+ { USB_DEVICE(0x13b1, 0x0020), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x13b1, 0x0023), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* MSI */
+ { USB_DEVICE(0x0db0, 0x6877), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0db0, 0x6874), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Ralink */
+ { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Qcom */
+ { USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x18e8, 0x6238), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Senao */
+ { USB_DEVICE(0x1740, 0x7100), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Sitecom */
+ { USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0df6, 0x90ac), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Surecom */
+ { USB_DEVICE(0x0769, 0x31f3), USB_DEVICE_DATA(&rt73usb_ops) },
+ /* Planex */
+ { USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) },
+ { 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT73 USB Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2571W & RT2671 USB chipset based cards");
+MODULE_DEVICE_TABLE(usb, rt73usb_device_table);
+MODULE_FIRMWARE(FIRMWARE_RT2571);
+MODULE_LICENSE("GPL");
+
+static struct usb_driver rt73usb_driver = {
+ .name = DRV_NAME,
+ .id_table = rt73usb_device_table,
+ .probe = rt2x00usb_probe,
+ .disconnect = rt2x00usb_disconnect,
+ .suspend = rt2x00usb_suspend,
+ .resume = rt2x00usb_resume,
+};
+
+static int __init rt73usb_init(void)
+{
+ return usb_register(&rt73usb_driver);
+}
+
+static void __exit rt73usb_exit(void)
+{
+ usb_deregister(&rt73usb_driver);
+}
+
+module_init(rt73usb_init);
+module_exit(rt73usb_exit);
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
new file mode 100644
index 00000000000..f0951519f74
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -0,0 +1,1024 @@
+/*
+ Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: rt73usb
+ Abstract: Data structures and registers for the rt73usb module.
+ Supported chipsets: rt2571W & rt2671.
+ */
+
+#ifndef RT73USB_H
+#define RT73USB_H
+
+/*
+ * RF chip defines.
+ */
+#define RF5226 0x0001
+#define RF2528 0x0002
+#define RF5225 0x0003
+#define RF2527 0x0004
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL 100
+#define MAX_RX_SSI -1
+#define DEFAULT_RSSI_OFFSET 120
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE 0x3000
+#define CSR_REG_SIZE 0x04b0
+#define EEPROM_BASE 0x0000
+#define EEPROM_SIZE 0x0100
+#define BBP_SIZE 0x0080
+#define RF_SIZE 0x0014
+
+/*
+ * USB registers.
+ */
+
+/*
+ * MCU_LEDCS: LED control for MCU Mailbox.
+ */
+#define MCU_LEDCS_LED_MODE FIELD16(0x001f)
+#define MCU_LEDCS_RADIO_STATUS FIELD16(0x0020)
+#define MCU_LEDCS_LINK_BG_STATUS FIELD16(0x0040)
+#define MCU_LEDCS_LINK_A_STATUS FIELD16(0x0080)
+#define MCU_LEDCS_POLARITY_GPIO_0 FIELD16(0x0100)
+#define MCU_LEDCS_POLARITY_GPIO_1 FIELD16(0x0200)
+#define MCU_LEDCS_POLARITY_GPIO_2 FIELD16(0x0400)
+#define MCU_LEDCS_POLARITY_GPIO_3 FIELD16(0x0800)
+#define MCU_LEDCS_POLARITY_GPIO_4 FIELD16(0x1000)
+#define MCU_LEDCS_POLARITY_ACT FIELD16(0x2000)
+#define MCU_LEDCS_POLARITY_READY_BG FIELD16(0x4000)
+#define MCU_LEDCS_POLARITY_READY_A FIELD16(0x8000)
+
+/*
+ * 8051 firmware image.
+ */
+#define FIRMWARE_RT2571 "rt73.bin"
+#define FIRMWARE_IMAGE_BASE 0x0800
+
+/*
+ * Security key table memory.
+ * 16 entries 32-byte for shared key table
+ * 64 entries 32-byte for pairwise key table
+ * 64 entries 8-byte for pairwise ta key table
+ */
+#define SHARED_KEY_TABLE_BASE 0x1000
+#define PAIRWISE_KEY_TABLE_BASE 0x1200
+#define PAIRWISE_TA_TABLE_BASE 0x1a00
+
+struct hw_key_entry {
+ u8 key[16];
+ u8 tx_mic[8];
+ u8 rx_mic[8];
+} __attribute__ ((packed));
+
+struct hw_pairwise_ta_entry {
+ u8 address[6];
+ u8 reserved[2];
+} __attribute__ ((packed));
+
+/*
+ * Since NULL frame won't be that long (256 byte),
+ * We steal 16 tail bytes to save debugging settings.
+ */
+#define HW_DEBUG_SETTING_BASE 0x2bf0
+
+/*
+ * On-chip BEACON frame space.
+ */
+#define HW_BEACON_BASE0 0x2400
+#define HW_BEACON_BASE1 0x2500
+#define HW_BEACON_BASE2 0x2600
+#define HW_BEACON_BASE3 0x2700
+
+/*
+ * MAC Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * MAC_CSR0: ASIC revision number.
+ */
+#define MAC_CSR0 0x3000
+
+/*
+ * MAC_CSR1: System control register.
+ * SOFT_RESET: Software reset bit, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset BBP.
+ * HOST_READY: Host is ready after initialization, 1: ready.
+ */
+#define MAC_CSR1 0x3004
+#define MAC_CSR1_SOFT_RESET FIELD32(0x00000001)
+#define MAC_CSR1_BBP_RESET FIELD32(0x00000002)
+#define MAC_CSR1_HOST_READY FIELD32(0x00000004)
+
+/*
+ * MAC_CSR2: STA MAC register 0.
+ */
+#define MAC_CSR2 0x3008
+#define MAC_CSR2_BYTE0 FIELD32(0x000000ff)
+#define MAC_CSR2_BYTE1 FIELD32(0x0000ff00)
+#define MAC_CSR2_BYTE2 FIELD32(0x00ff0000)
+#define MAC_CSR2_BYTE3 FIELD32(0xff000000)
+
+/*
+ * MAC_CSR3: STA MAC register 1.
+ */
+#define MAC_CSR3 0x300c
+#define MAC_CSR3_BYTE4 FIELD32(0x000000ff)
+#define MAC_CSR3_BYTE5 FIELD32(0x0000ff00)
+#define MAC_CSR3_UNICAST_TO_ME_MASK FIELD32(0x00ff0000)
+
+/*
+ * MAC_CSR4: BSSID register 0.
+ */
+#define MAC_CSR4 0x3010
+#define MAC_CSR4_BYTE0 FIELD32(0x000000ff)
+#define MAC_CSR4_BYTE1 FIELD32(0x0000ff00)
+#define MAC_CSR4_BYTE2 FIELD32(0x00ff0000)
+#define MAC_CSR4_BYTE3 FIELD32(0xff000000)
+
+/*
+ * MAC_CSR5: BSSID register 1.
+ * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID.
+ */
+#define MAC_CSR5 0x3014
+#define MAC_CSR5_BYTE4 FIELD32(0x000000ff)
+#define MAC_CSR5_BYTE5 FIELD32(0x0000ff00)
+#define MAC_CSR5_BSS_ID_MASK FIELD32(0x00ff0000)
+
+/*
+ * MAC_CSR6: Maximum frame length register.
+ */
+#define MAC_CSR6 0x3018
+#define MAC_CSR6_MAX_FRAME_UNIT FIELD32(0x00000fff)
+
+/*
+ * MAC_CSR7: Reserved
+ */
+#define MAC_CSR7 0x301c
+
+/*
+ * MAC_CSR8: SIFS/EIFS register.
+ * All units are in US.
+ */
+#define MAC_CSR8 0x3020
+#define MAC_CSR8_SIFS FIELD32(0x000000ff)
+#define MAC_CSR8_SIFS_AFTER_RX_OFDM FIELD32(0x0000ff00)
+#define MAC_CSR8_EIFS FIELD32(0xffff0000)
+
+/*
+ * MAC_CSR9: Back-Off control register.
+ * SLOT_TIME: Slot time, default is 20us for 802.11BG.
+ * CWMIN: Bit for Cwmin. default Cwmin is 31 (2^5 - 1).
+ * CWMAX: Bit for Cwmax, default Cwmax is 1023 (2^10 - 1).
+ * CW_SELECT: 1: CWmin/Cwmax select from register, 0:select from TxD.
+ */
+#define MAC_CSR9 0x3024
+#define MAC_CSR9_SLOT_TIME FIELD32(0x000000ff)
+#define MAC_CSR9_CWMIN FIELD32(0x00000f00)
+#define MAC_CSR9_CWMAX FIELD32(0x0000f000)
+#define MAC_CSR9_CW_SELECT FIELD32(0x00010000)
+
+/*
+ * MAC_CSR10: Power state configuration.
+ */
+#define MAC_CSR10 0x3028
+
+/*
+ * MAC_CSR11: Power saving transition time register.
+ * DELAY_AFTER_TBCN: Delay after Tbcn expired in units of TU.
+ * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * WAKEUP_LATENCY: In unit of TU.
+ */
+#define MAC_CSR11 0x302c
+#define MAC_CSR11_DELAY_AFTER_TBCN FIELD32(0x000000ff)
+#define MAC_CSR11_TBCN_BEFORE_WAKEUP FIELD32(0x00007f00)
+#define MAC_CSR11_AUTOWAKE FIELD32(0x00008000)
+#define MAC_CSR11_WAKEUP_LATENCY FIELD32(0x000f0000)
+
+/*
+ * MAC_CSR12: Manual power control / status register (merge CSR20 & PWRCSR1).
+ * CURRENT_STATE: 0:sleep, 1:awake.
+ * FORCE_WAKEUP: This has higher priority than PUT_TO_SLEEP.
+ * BBP_CURRENT_STATE: 0: BBP sleep, 1: BBP awake.
+ */
+#define MAC_CSR12 0x3030
+#define MAC_CSR12_CURRENT_STATE FIELD32(0x00000001)
+#define MAC_CSR12_PUT_TO_SLEEP FIELD32(0x00000002)
+#define MAC_CSR12_FORCE_WAKEUP FIELD32(0x00000004)
+#define MAC_CSR12_BBP_CURRENT_STATE FIELD32(0x00000008)
+
+/*
+ * MAC_CSR13: GPIO.
+ */
+#define MAC_CSR13 0x3034
+
+/*
+ * MAC_CSR14: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ * HW_LED: HW TX activity, 1: normal OFF, 0: normal ON.
+ * SW_LED: s/w LED, 1: ON, 0: OFF.
+ * HW_LED_POLARITY: 0: active low, 1: active high.
+ */
+#define MAC_CSR14 0x3038
+#define MAC_CSR14_ON_PERIOD FIELD32(0x000000ff)
+#define MAC_CSR14_OFF_PERIOD FIELD32(0x0000ff00)
+#define MAC_CSR14_HW_LED FIELD32(0x00010000)
+#define MAC_CSR14_SW_LED FIELD32(0x00020000)
+#define MAC_CSR14_HW_LED_POLARITY FIELD32(0x00040000)
+#define MAC_CSR14_SW_LED2 FIELD32(0x00080000)
+
+/*
+ * MAC_CSR15: NAV control.
+ */
+#define MAC_CSR15 0x303c
+
+/*
+ * TXRX control registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXRX_CSR0: TX/RX configuration register.
+ * TSF_OFFSET: Default is 24.
+ * AUTO_TX_SEQ: 1: ASIC auto replace sequence nr in outgoing frame.
+ * DISABLE_RX: Disable Rx engine.
+ * DROP_CRC: Drop CRC error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TO_DS: Drop fram ToDs bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * DROP_MULTICAST: Drop multicast frames.
+ * DROP_BORADCAST: Drop broadcast frames.
+ * ROP_ACK_CTS: Drop received ACK and CTS.
+ */
+#define TXRX_CSR0 0x3040
+#define TXRX_CSR0_RX_ACK_TIMEOUT FIELD32(0x000001ff)
+#define TXRX_CSR0_TSF_OFFSET FIELD32(0x00007e00)
+#define TXRX_CSR0_AUTO_TX_SEQ FIELD32(0x00008000)
+#define TXRX_CSR0_DISABLE_RX FIELD32(0x00010000)
+#define TXRX_CSR0_DROP_CRC FIELD32(0x00020000)
+#define TXRX_CSR0_DROP_PHYSICAL FIELD32(0x00040000)
+#define TXRX_CSR0_DROP_CONTROL FIELD32(0x00080000)
+#define TXRX_CSR0_DROP_NOT_TO_ME FIELD32(0x00100000)
+#define TXRX_CSR0_DROP_TO_DS FIELD32(0x00200000)
+#define TXRX_CSR0_DROP_VERSION_ERROR FIELD32(0x00400000)
+#define TXRX_CSR0_DROP_MULTICAST FIELD32(0x00800000)
+#define TXRX_CSR0_DROP_BROADCAST FIELD32(0x01000000)
+#define TXRX_CSR0_DROP_ACK_CTS FIELD32(0x02000000)
+#define TXRX_CSR0_TX_WITHOUT_WAITING FIELD32(0x04000000)
+
+/*
+ * TXRX_CSR1
+ */
+#define TXRX_CSR1 0x3044
+#define TXRX_CSR1_BBP_ID0 FIELD32(0x0000007f)
+#define TXRX_CSR1_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXRX_CSR1_BBP_ID1 FIELD32(0x00007f00)
+#define TXRX_CSR1_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXRX_CSR1_BBP_ID2 FIELD32(0x007f0000)
+#define TXRX_CSR1_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXRX_CSR1_BBP_ID3 FIELD32(0x7f000000)
+#define TXRX_CSR1_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR2
+ */
+#define TXRX_CSR2 0x3048
+#define TXRX_CSR2_BBP_ID0 FIELD32(0x0000007f)
+#define TXRX_CSR2_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXRX_CSR2_BBP_ID1 FIELD32(0x00007f00)
+#define TXRX_CSR2_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXRX_CSR2_BBP_ID2 FIELD32(0x007f0000)
+#define TXRX_CSR2_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXRX_CSR2_BBP_ID3 FIELD32(0x7f000000)
+#define TXRX_CSR2_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR3
+ */
+#define TXRX_CSR3 0x304c
+#define TXRX_CSR3_BBP_ID0 FIELD32(0x0000007f)
+#define TXRX_CSR3_BBP_ID0_VALID FIELD32(0x00000080)
+#define TXRX_CSR3_BBP_ID1 FIELD32(0x00007f00)
+#define TXRX_CSR3_BBP_ID1_VALID FIELD32(0x00008000)
+#define TXRX_CSR3_BBP_ID2 FIELD32(0x007f0000)
+#define TXRX_CSR3_BBP_ID2_VALID FIELD32(0x00800000)
+#define TXRX_CSR3_BBP_ID3 FIELD32(0x7f000000)
+#define TXRX_CSR3_BBP_ID3_VALID FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR4: Auto-Responder/Tx-retry register.
+ * AUTORESPOND_PREAMBLE: 0:long, 1:short preamble.
+ * OFDM_TX_RATE_DOWN: 1:enable.
+ * OFDM_TX_RATE_STEP: 0:1-step, 1: 2-step, 2:3-step, 3:4-step.
+ * OFDM_TX_FALLBACK_CCK: 0: Fallback to OFDM 6M only, 1: Fallback to CCK 1M,2M.
+ */
+#define TXRX_CSR4 0x3050
+#define TXRX_CSR4_TX_ACK_TIMEOUT FIELD32(0x000000ff)
+#define TXRX_CSR4_CNTL_ACK_POLICY FIELD32(0x00000700)
+#define TXRX_CSR4_ACK_CTS_PSM FIELD32(0x00010000)
+#define TXRX_CSR4_AUTORESPOND_ENABLE FIELD32(0x00020000)
+#define TXRX_CSR4_AUTORESPOND_PREAMBLE FIELD32(0x00040000)
+#define TXRX_CSR4_OFDM_TX_RATE_DOWN FIELD32(0x00080000)
+#define TXRX_CSR4_OFDM_TX_RATE_STEP FIELD32(0x00300000)
+#define TXRX_CSR4_OFDM_TX_FALLBACK_CCK FIELD32(0x00400000)
+#define TXRX_CSR4_LONG_RETRY_LIMIT FIELD32(0x0f000000)
+#define TXRX_CSR4_SHORT_RETRY_LIMIT FIELD32(0xf0000000)
+
+/*
+ * TXRX_CSR5
+ */
+#define TXRX_CSR5 0x3054
+
+/*
+ * TXRX_CSR6: ACK/CTS payload consumed time
+ */
+#define TXRX_CSR6 0x3058
+
+/*
+ * TXRX_CSR7: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps.
+ */
+#define TXRX_CSR7 0x305c
+#define TXRX_CSR7_ACK_CTS_6MBS FIELD32(0x000000ff)
+#define TXRX_CSR7_ACK_CTS_9MBS FIELD32(0x0000ff00)
+#define TXRX_CSR7_ACK_CTS_12MBS FIELD32(0x00ff0000)
+#define TXRX_CSR7_ACK_CTS_18MBS FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR8: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps.
+ */
+#define TXRX_CSR8 0x3060
+#define TXRX_CSR8_ACK_CTS_24MBS FIELD32(0x000000ff)
+#define TXRX_CSR8_ACK_CTS_36MBS FIELD32(0x0000ff00)
+#define TXRX_CSR8_ACK_CTS_48MBS FIELD32(0x00ff0000)
+#define TXRX_CSR8_ACK_CTS_54MBS FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR9: Synchronization control register.
+ * BEACON_INTERVAL: In unit of 1/16 TU.
+ * TSF_TICKING: Enable TSF auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * BEACON_GEN: Enable beacon generator.
+ */
+#define TXRX_CSR9 0x3064
+#define TXRX_CSR9_BEACON_INTERVAL FIELD32(0x0000ffff)
+#define TXRX_CSR9_TSF_TICKING FIELD32(0x00010000)
+#define TXRX_CSR9_TSF_SYNC FIELD32(0x00060000)
+#define TXRX_CSR9_TBTT_ENABLE FIELD32(0x00080000)
+#define TXRX_CSR9_BEACON_GEN FIELD32(0x00100000)
+#define TXRX_CSR9_TIMESTAMP_COMPENSATE FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR10: BEACON alignment.
+ */
+#define TXRX_CSR10 0x3068
+
+/*
+ * TXRX_CSR11: AES mask.
+ */
+#define TXRX_CSR11 0x306c
+
+/*
+ * TXRX_CSR12: TSF low 32.
+ */
+#define TXRX_CSR12 0x3070
+#define TXRX_CSR12_LOW_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * TXRX_CSR13: TSF high 32.
+ */
+#define TXRX_CSR13 0x3074
+#define TXRX_CSR13_HIGH_TSFTIMER FIELD32(0xffffffff)
+
+/*
+ * TXRX_CSR14: TBTT timer.
+ */
+#define TXRX_CSR14 0x3078
+
+/*
+ * TXRX_CSR15: TKIP MIC priority byte "AND" mask.
+ */
+#define TXRX_CSR15 0x307c
+
+/*
+ * PHY control registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * PHY_CSR0: RF/PS control.
+ */
+#define PHY_CSR0 0x3080
+#define PHY_CSR0_PA_PE_BG FIELD32(0x00010000)
+#define PHY_CSR0_PA_PE_A FIELD32(0x00020000)
+
+/*
+ * PHY_CSR1
+ */
+#define PHY_CSR1 0x3084
+#define PHY_CSR1_RF_RPI FIELD32(0x00010000)
+
+/*
+ * PHY_CSR2: Pre-TX BBP control.
+ */
+#define PHY_CSR2 0x3088
+
+/*
+ * PHY_CSR3: BBP serial control register.
+ * VALUE: Register value to program into BBP.
+ * REG_NUM: Selected BBP register.
+ * READ_CONTROL: 0: Write BBP, 1: Read BBP.
+ * BUSY: 1: ASIC is busy execute BBP programming.
+ */
+#define PHY_CSR3 0x308c
+#define PHY_CSR3_VALUE FIELD32(0x000000ff)
+#define PHY_CSR3_REGNUM FIELD32(0x00007f00)
+#define PHY_CSR3_READ_CONTROL FIELD32(0x00008000)
+#define PHY_CSR3_BUSY FIELD32(0x00010000)
+
+/*
+ * PHY_CSR4: RF serial control register
+ * VALUE: Register value (include register id) serial out to RF/IF chip.
+ * NUMBER_OF_BITS: Number of bits used in RFRegValue (I:20, RFMD:22).
+ * IF_SELECT: 1: select IF to program, 0: select RF to program.
+ * PLL_LD: RF PLL_LD status.
+ * BUSY: 1: ASIC is busy execute RF programming.
+ */
+#define PHY_CSR4 0x3090
+#define PHY_CSR4_VALUE FIELD32(0x00ffffff)
+#define PHY_CSR4_NUMBER_OF_BITS FIELD32(0x1f000000)
+#define PHY_CSR4_IF_SELECT FIELD32(0x20000000)
+#define PHY_CSR4_PLL_LD FIELD32(0x40000000)
+#define PHY_CSR4_BUSY FIELD32(0x80000000)
+
+/*
+ * PHY_CSR5: RX to TX signal switch timing control.
+ */
+#define PHY_CSR5 0x3094
+#define PHY_CSR5_IQ_FLIP FIELD32(0x00000004)
+
+/*
+ * PHY_CSR6: TX to RX signal timing control.
+ */
+#define PHY_CSR6 0x3098
+#define PHY_CSR6_IQ_FLIP FIELD32(0x00000004)
+
+/*
+ * PHY_CSR7: TX DAC switching timing control.
+ */
+#define PHY_CSR7 0x309c
+
+/*
+ * Security control register.
+ */
+
+/*
+ * SEC_CSR0: Shared key table control.
+ */
+#define SEC_CSR0 0x30a0
+#define SEC_CSR0_BSS0_KEY0_VALID FIELD32(0x00000001)
+#define SEC_CSR0_BSS0_KEY1_VALID FIELD32(0x00000002)
+#define SEC_CSR0_BSS0_KEY2_VALID FIELD32(0x00000004)
+#define SEC_CSR0_BSS0_KEY3_VALID FIELD32(0x00000008)
+#define SEC_CSR0_BSS1_KEY0_VALID FIELD32(0x00000010)
+#define SEC_CSR0_BSS1_KEY1_VALID FIELD32(0x00000020)
+#define SEC_CSR0_BSS1_KEY2_VALID FIELD32(0x00000040)
+#define SEC_CSR0_BSS1_KEY3_VALID FIELD32(0x00000080)
+#define SEC_CSR0_BSS2_KEY0_VALID FIELD32(0x00000100)
+#define SEC_CSR0_BSS2_KEY1_VALID FIELD32(0x00000200)
+#define SEC_CSR0_BSS2_KEY2_VALID FIELD32(0x00000400)
+#define SEC_CSR0_BSS2_KEY3_VALID FIELD32(0x00000800)
+#define SEC_CSR0_BSS3_KEY0_VALID FIELD32(0x00001000)
+#define SEC_CSR0_BSS3_KEY1_VALID FIELD32(0x00002000)
+#define SEC_CSR0_BSS3_KEY2_VALID FIELD32(0x00004000)
+#define SEC_CSR0_BSS3_KEY3_VALID FIELD32(0x00008000)
+
+/*
+ * SEC_CSR1: Shared key table security mode register.
+ */
+#define SEC_CSR1 0x30a4
+#define SEC_CSR1_BSS0_KEY0_CIPHER_ALG FIELD32(0x00000007)
+#define SEC_CSR1_BSS0_KEY1_CIPHER_ALG FIELD32(0x00000070)
+#define SEC_CSR1_BSS0_KEY2_CIPHER_ALG FIELD32(0x00000700)
+#define SEC_CSR1_BSS0_KEY3_CIPHER_ALG FIELD32(0x00007000)
+#define SEC_CSR1_BSS1_KEY0_CIPHER_ALG FIELD32(0x00070000)
+#define SEC_CSR1_BSS1_KEY1_CIPHER_ALG FIELD32(0x00700000)
+#define SEC_CSR1_BSS1_KEY2_CIPHER_ALG FIELD32(0x07000000)
+#define SEC_CSR1_BSS1_KEY3_CIPHER_ALG FIELD32(0x70000000)
+
+/*
+ * Pairwise key table valid bitmap registers.
+ * SEC_CSR2: pairwise key table valid bitmap 0.
+ * SEC_CSR3: pairwise key table valid bitmap 1.
+ */
+#define SEC_CSR2 0x30a8
+#define SEC_CSR3 0x30ac
+
+/*
+ * SEC_CSR4: Pairwise key table lookup control.
+ */
+#define SEC_CSR4 0x30b0
+
+/*
+ * SEC_CSR5: shared key table security mode register.
+ */
+#define SEC_CSR5 0x30b4
+#define SEC_CSR5_BSS2_KEY0_CIPHER_ALG FIELD32(0x00000007)
+#define SEC_CSR5_BSS2_KEY1_CIPHER_ALG FIELD32(0x00000070)
+#define SEC_CSR5_BSS2_KEY2_CIPHER_ALG FIELD32(0x00000700)
+#define SEC_CSR5_BSS2_KEY3_CIPHER_ALG FIELD32(0x00007000)
+#define SEC_CSR5_BSS3_KEY0_CIPHER_ALG FIELD32(0x00070000)
+#define SEC_CSR5_BSS3_KEY1_CIPHER_ALG FIELD32(0x00700000)
+#define SEC_CSR5_BSS3_KEY2_CIPHER_ALG FIELD32(0x07000000)
+#define SEC_CSR5_BSS3_KEY3_CIPHER_ALG FIELD32(0x70000000)
+
+/*
+ * STA control registers.
+ */
+
+/*
+ * STA_CSR0: RX PLCP error count & RX FCS error count.
+ */
+#define STA_CSR0 0x30c0
+#define STA_CSR0_FCS_ERROR FIELD32(0x0000ffff)
+#define STA_CSR0_PLCP_ERROR FIELD32(0xffff0000)
+
+/*
+ * STA_CSR1: RX False CCA count & RX LONG frame count.
+ */
+#define STA_CSR1 0x30c4
+#define STA_CSR1_PHYSICAL_ERROR FIELD32(0x0000ffff)
+#define STA_CSR1_FALSE_CCA_ERROR FIELD32(0xffff0000)
+
+/*
+ * STA_CSR2: TX Beacon count and RX FIFO overflow count.
+ */
+#define STA_CSR2 0x30c8
+#define STA_CSR2_RX_FIFO_OVERFLOW_COUNT FIELD32(0x0000ffff)
+#define STA_CSR2_RX_OVERFLOW_COUNT FIELD32(0xffff0000)
+
+/*
+ * STA_CSR3: TX Beacon count.
+ */
+#define STA_CSR3 0x30cc
+#define STA_CSR3_TX_BEACON_COUNT FIELD32(0x0000ffff)
+
+/*
+ * STA_CSR4: TX Retry count.
+ */
+#define STA_CSR4 0x30d0
+#define STA_CSR4_TX_NO_RETRY_COUNT FIELD32(0x0000ffff)
+#define STA_CSR4_TX_ONE_RETRY_COUNT FIELD32(0xffff0000)
+
+/*
+ * STA_CSR5: TX Retry count.
+ */
+#define STA_CSR5 0x30d4
+#define STA_CSR4_TX_MULTI_RETRY_COUNT FIELD32(0x0000ffff)
+#define STA_CSR4_TX_RETRY_FAIL_COUNT FIELD32(0xffff0000)
+
+/*
+ * QOS control registers.
+ */
+
+/*
+ * QOS_CSR1: TXOP holder MAC address register.
+ */
+#define QOS_CSR1 0x30e4
+#define QOS_CSR1_BYTE4 FIELD32(0x000000ff)
+#define QOS_CSR1_BYTE5 FIELD32(0x0000ff00)
+
+/*
+ * QOS_CSR2: TXOP holder timeout register.
+ */
+#define QOS_CSR2 0x30e8
+
+/*
+ * RX QOS-CFPOLL MAC address register.
+ * QOS_CSR3: RX QOS-CFPOLL MAC address 0.
+ * QOS_CSR4: RX QOS-CFPOLL MAC address 1.
+ */
+#define QOS_CSR3 0x30ec
+#define QOS_CSR4 0x30f0
+
+/*
+ * QOS_CSR5: "QosControl" field of the RX QOS-CFPOLL.
+ */
+#define QOS_CSR5 0x30f4
+
+/*
+ * WMM Scheduler Register
+ */
+
+/*
+ * AIFSN_CSR: AIFSN for each EDCA AC.
+ * AIFSN0: For AC_BK.
+ * AIFSN1: For AC_BE.
+ * AIFSN2: For AC_VI.
+ * AIFSN3: For AC_VO.
+ */
+#define AIFSN_CSR 0x0400
+#define AIFSN_CSR_AIFSN0 FIELD32(0x0000000f)
+#define AIFSN_CSR_AIFSN1 FIELD32(0x000000f0)
+#define AIFSN_CSR_AIFSN2 FIELD32(0x00000f00)
+#define AIFSN_CSR_AIFSN3 FIELD32(0x0000f000)
+
+/*
+ * CWMIN_CSR: CWmin for each EDCA AC.
+ * CWMIN0: For AC_BK.
+ * CWMIN1: For AC_BE.
+ * CWMIN2: For AC_VI.
+ * CWMIN3: For AC_VO.
+ */
+#define CWMIN_CSR 0x0404
+#define CWMIN_CSR_CWMIN0 FIELD32(0x0000000f)
+#define CWMIN_CSR_CWMIN1 FIELD32(0x000000f0)
+#define CWMIN_CSR_CWMIN2 FIELD32(0x00000f00)
+#define CWMIN_CSR_CWMIN3 FIELD32(0x0000f000)
+
+/*
+ * CWMAX_CSR: CWmax for each EDCA AC.
+ * CWMAX0: For AC_BK.
+ * CWMAX1: For AC_BE.
+ * CWMAX2: For AC_VI.
+ * CWMAX3: For AC_VO.
+ */
+#define CWMAX_CSR 0x0408
+#define CWMAX_CSR_CWMAX0 FIELD32(0x0000000f)
+#define CWMAX_CSR_CWMAX1 FIELD32(0x000000f0)
+#define CWMAX_CSR_CWMAX2 FIELD32(0x00000f00)
+#define CWMAX_CSR_CWMAX3 FIELD32(0x0000f000)
+
+/*
+ * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register.
+ * AC0_TX_OP: For AC_BK, in unit of 32us.
+ * AC1_TX_OP: For AC_BE, in unit of 32us.
+ */
+#define AC_TXOP_CSR0 0x040c
+#define AC_TXOP_CSR0_AC0_TX_OP FIELD32(0x0000ffff)
+#define AC_TXOP_CSR0_AC1_TX_OP FIELD32(0xffff0000)
+
+/*
+ * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register.
+ * AC2_TX_OP: For AC_VI, in unit of 32us.
+ * AC3_TX_OP: For AC_VO, in unit of 32us.
+ */
+#define AC_TXOP_CSR1 0x0410
+#define AC_TXOP_CSR1_AC2_TX_OP FIELD32(0x0000ffff)
+#define AC_TXOP_CSR1_AC3_TX_OP FIELD32(0xffff0000)
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R2
+ */
+#define BBP_R2_BG_MODE FIELD8(0x20)
+
+/*
+ * R3
+ */
+#define BBP_R3_SMART_MODE FIELD8(0x01)
+
+/*
+ * R4: RX antenna control
+ * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529)
+ */
+#define BBP_R4_RX_ANTENNA FIELD8(0x03)
+#define BBP_R4_RX_FRAME_END FIELD8(0x20)
+
+/*
+ * R77
+ */
+#define BBP_R77_PAIR FIELD8(0x03)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 3
+ */
+#define RF3_TXPOWER FIELD32(0x00003e00)
+
+/*
+ * RF 4
+ */
+#define RF4_FREQ_OFFSET FIELD32(0x0003f000)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0 0x0002
+#define EEPROM_MAC_ADDR_BYTE0 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1 0x0003
+#define EEPROM_MAC_ADDR_BYTE2 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3 FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2 0x0004
+#define EEPROM_MAC_ADDR_BYTE4 FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5 FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only.
+ * DYN_TXAGC: Dynamic TX AGC control.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ * RF_TYPE: Rf_type of this adapter.
+ */
+#define EEPROM_ANTENNA 0x0010
+#define EEPROM_ANTENNA_NUM FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT FIELD16(0x0030)
+#define EEPROM_ANTENNA_FRAME_TYPE FIELD16(0x0040)
+#define EEPROM_ANTENNA_DYN_TXAGC FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO FIELD16(0x0400)
+#define EEPROM_ANTENNA_RF_TYPE FIELD16(0xf800)
+
+/*
+ * EEPROM NIC config.
+ * EXTERNAL_LNA: External LNA.
+ */
+#define EEPROM_NIC 0x0011
+#define EEPROM_NIC_EXTERNAL_LNA FIELD16(0x0010)
+
+/*
+ * EEPROM geography.
+ * GEO_A: Default geographical setting for 5GHz band
+ * GEO: Default geographical setting.
+ */
+#define EEPROM_GEOGRAPHY 0x0012
+#define EEPROM_GEOGRAPHY_GEO_A FIELD16(0x00ff)
+#define EEPROM_GEOGRAPHY_GEO FIELD16(0xff00)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START 0x0013
+#define EEPROM_BBP_SIZE 16
+#define EEPROM_BBP_VALUE FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER 802.11G
+ */
+#define EEPROM_TXPOWER_G_START 0x0023
+#define EEPROM_TXPOWER_G_SIZE 7
+#define EEPROM_TXPOWER_G_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_G_2 FIELD16(0xff00)
+
+/*
+ * EEPROM Frequency
+ */
+#define EEPROM_FREQ 0x002f
+#define EEPROM_FREQ_OFFSET FIELD16(0x00ff)
+#define EEPROM_FREQ_SEQ_MASK FIELD16(0xff00)
+#define EEPROM_FREQ_SEQ FIELD16(0x0300)
+
+/*
+ * EEPROM LED.
+ * POLARITY_RDY_G: Polarity RDY_G setting.
+ * POLARITY_RDY_A: Polarity RDY_A setting.
+ * POLARITY_ACT: Polarity ACT setting.
+ * POLARITY_GPIO_0: Polarity GPIO0 setting.
+ * POLARITY_GPIO_1: Polarity GPIO1 setting.
+ * POLARITY_GPIO_2: Polarity GPIO2 setting.
+ * POLARITY_GPIO_3: Polarity GPIO3 setting.
+ * POLARITY_GPIO_4: Polarity GPIO4 setting.
+ * LED_MODE: Led mode.
+ */
+#define EEPROM_LED 0x0030
+#define EEPROM_LED_POLARITY_RDY_G FIELD16(0x0001)
+#define EEPROM_LED_POLARITY_RDY_A FIELD16(0x0002)
+#define EEPROM_LED_POLARITY_ACT FIELD16(0x0004)
+#define EEPROM_LED_POLARITY_GPIO_0 FIELD16(0x0008)
+#define EEPROM_LED_POLARITY_GPIO_1 FIELD16(0x0010)
+#define EEPROM_LED_POLARITY_GPIO_2 FIELD16(0x0020)
+#define EEPROM_LED_POLARITY_GPIO_3 FIELD16(0x0040)
+#define EEPROM_LED_POLARITY_GPIO_4 FIELD16(0x0080)
+#define EEPROM_LED_LED_MODE FIELD16(0x1f00)
+
+/*
+ * EEPROM TXPOWER 802.11A
+ */
+#define EEPROM_TXPOWER_A_START 0x0031
+#define EEPROM_TXPOWER_A_SIZE 12
+#define EEPROM_TXPOWER_A_1 FIELD16(0x00ff)
+#define EEPROM_TXPOWER_A_2 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11BG
+ */
+#define EEPROM_RSSI_OFFSET_BG 0x004d
+#define EEPROM_RSSI_OFFSET_BG_1 FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_BG_2 FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11A
+ */
+#define EEPROM_RSSI_OFFSET_A 0x004e
+#define EEPROM_RSSI_OFFSET_A_1 FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_A_2 FIELD16(0xff00)
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE ( 6 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE ( 6 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO and Beacon Ring.
+ */
+
+/*
+ * Word0
+ * BURST: Next frame belongs to same "burst" event.
+ * TKIP_MIC: ASIC appends TKIP MIC if TKIP is used.
+ * KEY_TABLE: Use per-client pairwise KEY table.
+ * KEY_INDEX:
+ * Key index (0~31) to the pairwise KEY table.
+ * 0~3 to shared KEY table 0 (BSS0).
+ * 4~7 to shared KEY table 1 (BSS1).
+ * 8~11 to shared KEY table 2 (BSS2).
+ * 12~15 to shared KEY table 3 (BSS3).
+ * BURST2: For backward compatibility, set to same value as BURST.
+ */
+#define TXD_W0_BURST FIELD32(0x00000001)
+#define TXD_W0_VALID FIELD32(0x00000002)
+#define TXD_W0_MORE_FRAG FIELD32(0x00000004)
+#define TXD_W0_ACK FIELD32(0x00000008)
+#define TXD_W0_TIMESTAMP FIELD32(0x00000010)
+#define TXD_W0_OFDM FIELD32(0x00000020)
+#define TXD_W0_IFS FIELD32(0x00000040)
+#define TXD_W0_RETRY_MODE FIELD32(0x00000080)
+#define TXD_W0_TKIP_MIC FIELD32(0x00000100)
+#define TXD_W0_KEY_TABLE FIELD32(0x00000200)
+#define TXD_W0_KEY_INDEX FIELD32(0x0000fc00)
+#define TXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define TXD_W0_BURST2 FIELD32(0x10000000)
+#define TXD_W0_CIPHER_ALG FIELD32(0xe0000000)
+
+/*
+ * Word1
+ * HOST_Q_ID: EDCA/HCCA queue ID.
+ * HW_SEQUENCE: MAC overwrites the frame sequence number.
+ * BUFFER_COUNT: Number of buffers in this TXD.
+ */
+#define TXD_W1_HOST_Q_ID FIELD32(0x0000000f)
+#define TXD_W1_AIFSN FIELD32(0x000000f0)
+#define TXD_W1_CWMIN FIELD32(0x00000f00)
+#define TXD_W1_CWMAX FIELD32(0x0000f000)
+#define TXD_W1_IV_OFFSET FIELD32(0x003f0000)
+#define TXD_W1_HW_SEQUENCE FIELD32(0x10000000)
+#define TXD_W1_BUFFER_COUNT FIELD32(0xe0000000)
+
+/*
+ * Word2: PLCP information
+ */
+#define TXD_W2_PLCP_SIGNAL FIELD32(0x000000ff)
+#define TXD_W2_PLCP_SERVICE FIELD32(0x0000ff00)
+#define TXD_W2_PLCP_LENGTH_LOW FIELD32(0x00ff0000)
+#define TXD_W2_PLCP_LENGTH_HIGH FIELD32(0xff000000)
+
+/*
+ * Word3
+ */
+#define TXD_W3_IV FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define TXD_W4_EIV FIELD32(0xffffffff)
+
+/*
+ * Word5
+ * FRAME_OFFSET: Frame start offset inside ASIC TXFIFO (after TXINFO field).
+ * PACKET_ID: Driver assigned packet ID to categorize TXResult in interrupt.
+ * WAITING_DMA_DONE_INT: TXD been filled with data
+ * and waiting for TxDoneISR housekeeping.
+ */
+#define TXD_W5_FRAME_OFFSET FIELD32(0x000000ff)
+#define TXD_W5_PACKET_ID FIELD32(0x0000ff00)
+#define TXD_W5_TX_POWER FIELD32(0x00ff0000)
+#define TXD_W5_WAITING_DMA_DONE_INT FIELD32(0x01000000)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ * CIPHER_ERROR: 1:ICV error, 2:MIC error, 3:invalid key.
+ * KEY_INDEX: Decryption key actually used.
+ */
+#define RXD_W0_OWNER_NIC FIELD32(0x00000001)
+#define RXD_W0_DROP FIELD32(0x00000002)
+#define RXD_W0_UNICAST_TO_ME FIELD32(0x00000004)
+#define RXD_W0_MULTICAST FIELD32(0x00000008)
+#define RXD_W0_BROADCAST FIELD32(0x00000010)
+#define RXD_W0_MY_BSS FIELD32(0x00000020)
+#define RXD_W0_CRC_ERROR FIELD32(0x00000040)
+#define RXD_W0_OFDM FIELD32(0x00000080)
+#define RXD_W0_CIPHER_ERROR FIELD32(0x00000300)
+#define RXD_W0_KEY_INDEX FIELD32(0x0000fc00)
+#define RXD_W0_DATABYTE_COUNT FIELD32(0x0fff0000)
+#define RXD_W0_CIPHER_ALG FIELD32(0xe0000000)
+
+/*
+ * WORD1
+ * SIGNAL: RX raw data rate reported by BBP.
+ * RSSI: RSSI reported by BBP.
+ */
+#define RXD_W1_SIGNAL FIELD32(0x000000ff)
+#define RXD_W1_RSSI_AGC FIELD32(0x00001f00)
+#define RXD_W1_RSSI_LNA FIELD32(0x00006000)
+#define RXD_W1_FRAME_OFFSET FIELD32(0x7f000000)
+
+/*
+ * Word2
+ * IV: Received IV of originally encrypted.
+ */
+#define RXD_W2_IV FIELD32(0xffffffff)
+
+/*
+ * Word3
+ * EIV: Received EIV of originally encrypted.
+ */
+#define RXD_W3_EIV FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define RXD_W4_RESERVED FIELD32(0xffffffff)
+
+/*
+ * the above 20-byte is called RXINFO and will be DMAed to MAC RX block
+ * and passed to the HOST driver.
+ * The following fields are for DMA block and HOST usage only.
+ * Can't be touched by ASIC MAC block.
+ */
+
+/*
+ * Word5
+ */
+#define RXD_W5_RESERVED FIELD32(0xffffffff)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ */
+#define MIN_TXPOWER 0
+#define MAX_TXPOWER 31
+#define DEFAULT_TXPOWER 24
+
+#define TXPOWER_FROM_DEV(__txpower) \
+({ \
+ ((__txpower) > MAX_TXPOWER) ? \
+ DEFAULT_TXPOWER : (__txpower); \
+})
+
+#define TXPOWER_TO_DEV(__txpower) \
+({ \
+ ((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER : \
+ (((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER : \
+ (__txpower)); \
+})
+
+#endif /* RT73USB_H */
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h
index 6124e467b15..6ad322ef0da 100644
--- a/drivers/net/wireless/rtl8187.h
+++ b/drivers/net/wireless/rtl8187.h
@@ -36,8 +36,7 @@ struct rtl8187_rx_info {
};
struct rtl8187_rx_hdr {
- __le16 len;
- __le16 rate;
+ __le32 flags;
u8 noise;
u8 signal;
u8 agc;
@@ -67,13 +66,14 @@ struct rtl8187_priv {
struct rtl818x_csr *map;
void (*rf_init)(struct ieee80211_hw *);
int mode;
+ int if_id;
/* rtl8187 specific */
struct ieee80211_channel channels[14];
struct ieee80211_rate rates[12];
struct ieee80211_hw_mode modes[2];
struct usb_device *udev;
- u8 *hwaddr;
+ u32 rx_conf;
u16 txpwr_base;
u8 asic_rev;
struct sk_buff_head rx_queue;
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index e61c6d5ba1a..e454ae83e97 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -36,11 +36,64 @@ static struct usb_device_id rtl8187_table[] __devinitdata = {
/* Netgear */
{USB_DEVICE(0x0846, 0x6100)},
{USB_DEVICE(0x0846, 0x6a00)},
+ /* HP */
+ {USB_DEVICE(0x03f0, 0xca02)},
{}
};
MODULE_DEVICE_TABLE(usb, rtl8187_table);
+static void rtl8187_iowrite_async_cb(struct urb *urb)
+{
+ kfree(urb->context);
+ usb_free_urb(urb);
+}
+
+static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr,
+ void *data, u16 len)
+{
+ struct usb_ctrlrequest *dr;
+ struct urb *urb;
+ struct rtl8187_async_write_data {
+ u8 data[4];
+ struct usb_ctrlrequest dr;
+ } *buf;
+
+ buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
+ if (!buf)
+ return;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ kfree(buf);
+ return;
+ }
+
+ dr = &buf->dr;
+
+ dr->bRequestType = RTL8187_REQT_WRITE;
+ dr->bRequest = RTL8187_REQ_SET_REG;
+ dr->wValue = addr;
+ dr->wIndex = 0;
+ dr->wLength = cpu_to_le16(len);
+
+ memcpy(buf, data, len);
+
+ usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0),
+ (unsigned char *)dr, buf, len,
+ rtl8187_iowrite_async_cb, buf);
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv,
+ __le32 *addr, u32 val)
+{
+ __le32 buf = cpu_to_le32(val);
+
+ rtl8187_iowrite_async(priv, cpu_to_le16((unsigned long)addr),
+ &buf, sizeof(buf));
+}
+
void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
{
struct rtl8187_priv *priv = dev->priv;
@@ -78,7 +131,8 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
struct rtl8187_tx_hdr *hdr;
struct rtl8187_tx_info *info;
struct urb *urb;
- u32 tmp;
+ __le16 rts_dur = 0;
+ u32 flags;
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
@@ -86,24 +140,24 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
return 0;
}
- hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
- tmp = skb->len - sizeof(*hdr);
- tmp |= RTL8187_TX_FLAG_NO_ENCRYPT;
- tmp |= control->rts_cts_rate << 19;
- tmp |= control->tx_rate << 24;
- if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb))
- tmp |= RTL8187_TX_FLAG_MORE_FRAG;
+ flags = skb->len;
+ flags |= RTL8187_TX_FLAG_NO_ENCRYPT;
+ flags |= control->rts_cts_rate << 19;
+ flags |= control->tx_rate << 24;
+ if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data))
+ flags |= RTL8187_TX_FLAG_MORE_FRAG;
if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
- tmp |= RTL8187_TX_FLAG_RTS;
- hdr->rts_duration =
- ieee80211_rts_duration(dev, skb->len, control);
+ flags |= RTL8187_TX_FLAG_RTS;
+ rts_dur = ieee80211_rts_duration(dev, priv->if_id, skb->len, control);
}
if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
- tmp |= RTL8187_TX_FLAG_CTS;
- hdr->flags = cpu_to_le32(tmp);
+ flags |= RTL8187_TX_FLAG_CTS;
+
+ hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
+ hdr->flags = cpu_to_le32(flags);
hdr->len = 0;
- tmp = control->retry_limit << 8;
- hdr->retry = cpu_to_le32(tmp);
+ hdr->rts_duration = rts_dur;
+ hdr->retry = cpu_to_le32(control->retry_limit << 8);
info = (struct rtl8187_tx_info *)skb->cb;
info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC);
@@ -125,6 +179,7 @@ static void rtl8187_rx_cb(struct urb *urb)
struct rtl8187_rx_hdr *hdr;
struct ieee80211_rx_status rx_status = { 0 };
int rate, signal;
+ u32 flags;
spin_lock(&priv->rx_queue.lock);
if (skb->next)
@@ -143,10 +198,11 @@ static void rtl8187_rx_cb(struct urb *urb)
skb_put(skb, urb->actual_length);
hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr));
- skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF);
+ flags = le32_to_cpu(hdr->flags);
+ skb_trim(skb, flags & 0x0FFF);
signal = hdr->agc >> 1;
- rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF;
+ rate = (flags >> 20) & 0xF;
if (rate > 3) { /* OFDM rate */
if (signal > 90)
signal = 90;
@@ -169,6 +225,8 @@ static void rtl8187_rx_cb(struct urb *urb)
rx_status.channel = dev->conf.channel;
rx_status.phymode = dev->conf.phymode;
rx_status.mactime = le64_to_cpu(hdr->mac_time);
+ if (flags & (1 << 13))
+ rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
ieee80211_rx_irqsafe(dev, skb, &rx_status);
skb = dev_alloc_skb(RTL8187_MAX_RX);
@@ -293,8 +351,6 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev)
rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
- for (i = 0; i < ETH_ALEN; i++)
- rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]);
rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF);
reg = rtl818x_ioread8(priv, &priv->map->CONFIG1);
@@ -365,7 +421,7 @@ static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel)
rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
}
-static int rtl8187_open(struct ieee80211_hw *dev)
+static int rtl8187_start(struct ieee80211_hw *dev)
{
struct rtl8187_priv *priv = dev->priv;
u32 reg;
@@ -377,22 +433,22 @@ static int rtl8187_open(struct ieee80211_hw *dev)
rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
+ rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0);
+ rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0);
+
rtl8187_init_urbs(dev);
reg = RTL818X_RX_CONF_ONLYERLPKT |
RTL818X_RX_CONF_RX_AUTORESETPHY |
RTL818X_RX_CONF_BSSID |
RTL818X_RX_CONF_MGMT |
- RTL818X_RX_CONF_CTRL |
RTL818X_RX_CONF_DATA |
(7 << 13 /* RX FIFO threshold NONE */) |
(7 << 10 /* MAX RX DMA */) |
RTL818X_RX_CONF_BROADCAST |
- RTL818X_RX_CONF_MULTICAST |
RTL818X_RX_CONF_NICMAC;
- if (priv->mode == IEEE80211_IF_TYPE_MNTR)
- reg |= RTL818X_RX_CONF_MONITOR;
+ priv->rx_conf = reg;
rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
@@ -419,7 +475,7 @@ static int rtl8187_open(struct ieee80211_hw *dev)
return 0;
}
-static int rtl8187_stop(struct ieee80211_hw *dev)
+static void rtl8187_stop(struct ieee80211_hw *dev)
{
struct rtl8187_priv *priv = dev->priv;
struct rtl8187_rx_info *info;
@@ -445,28 +501,31 @@ static int rtl8187_stop(struct ieee80211_hw *dev)
usb_kill_urb(info->urb);
kfree_skb(skb);
}
- return 0;
+ return;
}
static int rtl8187_add_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct rtl8187_priv *priv = dev->priv;
+ int i;
- /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
- if (priv->mode != IEEE80211_IF_TYPE_MGMT)
- return -1;
+ if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+ return -EOPNOTSUPP;
switch (conf->type) {
case IEEE80211_IF_TYPE_STA:
- case IEEE80211_IF_TYPE_MNTR:
priv->mode = conf->type;
break;
default:
return -EOPNOTSUPP;
}
- priv->hwaddr = conf->mac_addr ? conf->mac_addr : dev->wiphy->perm_addr;
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+ for (i = 0; i < ETH_ALEN; i++)
+ rtl818x_iowrite8(priv, &priv->map->MAC[i],
+ ((u8 *)conf->mac_addr)[i]);
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
return 0;
}
@@ -475,7 +534,7 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
struct rtl8187_priv *priv = dev->priv;
- priv->mode = IEEE80211_IF_TYPE_MGMT;
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
}
static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
@@ -510,6 +569,8 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id,
struct rtl8187_priv *priv = dev->priv;
int i;
+ priv->if_id = if_id;
+
for (i = 0; i < ETH_ALEN; i++)
rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
@@ -521,14 +582,47 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id,
return 0;
}
+static void rtl8187_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_addr_list *mclist)
+{
+ struct rtl8187_priv *priv = dev->priv;
+
+ if (changed_flags & FIF_FCSFAIL)
+ priv->rx_conf ^= RTL818X_RX_CONF_FCS;
+ if (changed_flags & FIF_CONTROL)
+ priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
+ if (changed_flags & FIF_OTHER_BSS)
+ priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
+ if (*total_flags & FIF_ALLMULTI || mc_count > 0)
+ priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
+ else
+ priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST;
+
+ *total_flags = 0;
+
+ if (priv->rx_conf & RTL818X_RX_CONF_FCS)
+ *total_flags |= FIF_FCSFAIL;
+ if (priv->rx_conf & RTL818X_RX_CONF_CTRL)
+ *total_flags |= FIF_CONTROL;
+ if (priv->rx_conf & RTL818X_RX_CONF_MONITOR)
+ *total_flags |= FIF_OTHER_BSS;
+ if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST)
+ *total_flags |= FIF_ALLMULTI;
+
+ rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf);
+}
+
static const struct ieee80211_ops rtl8187_ops = {
.tx = rtl8187_tx,
- .open = rtl8187_open,
+ .start = rtl8187_start,
.stop = rtl8187_stop,
.add_interface = rtl8187_add_interface,
.remove_interface = rtl8187_remove_interface,
.config = rtl8187_config,
.config_interface = rtl8187_config_interface,
+ .configure_filter = rtl8187_configure_filter,
};
static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -572,6 +666,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
struct ieee80211_channel *channel;
u16 txpwr, reg;
int err, i;
+ DECLARE_MAC_BUF(mac);
dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
if (!dev) {
@@ -601,11 +696,9 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
priv->modes[1].rates = priv->rates;
priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels);
priv->modes[1].channels = priv->channels;
- priv->mode = IEEE80211_IF_TYPE_MGMT;
+ priv->mode = IEEE80211_IF_TYPE_MNTR;
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_WEP_INCLUDE_IV |
- IEEE80211_HW_DATA_NULLFUNC_ACK;
+ IEEE80211_HW_RX_INCLUDES_FCS;
dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr);
dev->queues = 1;
dev->max_rssi = 65;
@@ -681,8 +774,8 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
goto err_free_dev;
}
- printk(KERN_INFO "%s: hwaddr " MAC_FMT ", rtl8187 V%d + %s\n",
- wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr),
+ printk(KERN_INFO "%s: hwaddr %s, rtl8187 V%d + %s\n",
+ wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
priv->asic_rev, priv->rf_init == rtl8225_rf_init ?
"rtl8225" : "rtl8225z2");
diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h
index 283de30628e..880d4becae3 100644
--- a/drivers/net/wireless/rtl818x.h
+++ b/drivers/net/wireless/rtl818x.h
@@ -71,6 +71,7 @@ struct rtl818x_csr {
#define RTL818X_RX_CONF_NICMAC (1 << 1)
#define RTL818X_RX_CONF_MULTICAST (1 << 2)
#define RTL818X_RX_CONF_BROADCAST (1 << 3)
+#define RTL818X_RX_CONF_FCS (1 << 5)
#define RTL818X_RX_CONF_DATA (1 << 18)
#define RTL818X_RX_CONF_CTRL (1 << 19)
#define RTL818X_RX_CONF_MGMT (1 << 20)
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index af70460f008..98df9bc7836 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -782,7 +782,6 @@ spectrum_cs_config(struct pcmcia_device *link)
/* Ok, we have the configuration, prepare to register the netdev */
dev->base_addr = link->io.BasePort1;
dev->irq = link->irq.AssignedIRQ;
- SET_MODULE_OWNER(dev);
card->node.major = card->node.minor = 0;
/* Reset card and download firmware */
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index ef32a5c1e81..88efe1bae58 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -107,6 +107,7 @@ static const char StripVersion[] = "1.3A-STUART.CHESHIRE";
#include <linux/serialP.h>
#include <linux/rcupdate.h>
#include <net/arp.h>
+#include <net/net_namespace.h>
#include <linux/ip.h>
#include <linux/tcp.h>
@@ -1630,8 +1631,8 @@ static void strip_IdleTask(unsigned long parameter)
*/
static int strip_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned len)
{
struct strip *strip_info = netdev_priv(dev);
STRIP_Header *header = (STRIP_Header *) skb_push(skb, sizeof(STRIP_Header));
@@ -1971,7 +1972,7 @@ static struct net_device *get_strip_dev(struct strip *strip_info)
sizeof(zero_address))) {
struct net_device *dev;
read_lock_bh(&dev_base_lock);
- for_each_netdev(dev) {
+ for_each_netdev(&init_net, dev) {
if (dev->type == strip_info->dev->type &&
!memcmp(dev->dev_addr,
&strip_info->true_dev_addr,
@@ -2496,6 +2497,11 @@ static int strip_close_low(struct net_device *dev)
return 0;
}
+static const struct header_ops strip_header_ops = {
+ .create = strip_header,
+ .rebuild = strip_rebuild_header,
+};
+
/*
* This routine is called by DDI when the
* (dynamically assigned) device is registered
@@ -2507,8 +2513,6 @@ static void strip_dev_setup(struct net_device *dev)
* Finish setting up the DEVICE info.
*/
- SET_MODULE_OWNER(dev);
-
dev->trans_start = 0;
dev->last_rx = 0;
dev->tx_queue_len = 30; /* Drop after 30 frames queued */
@@ -2532,8 +2536,8 @@ static void strip_dev_setup(struct net_device *dev)
dev->open = strip_open_low;
dev->stop = strip_close_low;
dev->hard_start_xmit = strip_xmit;
- dev->hard_header = strip_header;
- dev->rebuild_header = strip_rebuild_header;
+ dev->header_ops = &strip_header_ops;
+
dev->set_mac_address = strip_set_mac_address;
dev->get_stats = strip_get_stats;
dev->change_mtu = strip_change_mtu;
@@ -2571,7 +2575,7 @@ static struct strip *strip_alloc(void)
return NULL; /* If no more memory, return */
- strip_info = dev->priv;
+ strip_info = netdev_priv(dev);
strip_info->dev = dev;
strip_info->magic = STRIP_MAGIC;
@@ -2731,16 +2735,8 @@ static int strip_ioctl(struct tty_struct *tty, struct file *file,
return -EFAULT;
return set_mac_address(strip_info, &addr);
}
- /*
- * Allow stty to read, but not set, the serial port
- */
-
- case TCGETS:
- case TCGETA:
- return n_tty_ioctl(tty, file, cmd, arg);
- break;
default:
- return -ENOIOCTLCMD;
+ return tty_mode_ioctl(tty, file, cmd, arg);
break;
}
return 0;
@@ -2787,7 +2783,7 @@ static int __init strip_init_driver(void)
/*
* Register the status file with /proc
*/
- proc_net_fops_create("strip", S_IFREG | S_IRUGO, &strip_seq_fops);
+ proc_net_fops_create(&init_net, "strip", S_IFREG | S_IRUGO, &strip_seq_fops);
return status;
}
@@ -2809,7 +2805,7 @@ static void __exit strip_exit_driver(void)
}
/* Unregister with the /proc/net file here. */
- proc_net_remove("strip");
+ proc_net_remove(&init_net, "strip");
if ((i = tty_unregister_ldisc(N_STRIP)))
printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i);
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 1cf090d60ed..a1f8a168784 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -880,6 +880,8 @@ static void wv_82586_reconfig(struct net_device * dev)
*/
static void wv_psa_show(psa_t * p)
{
+ DECLARE_MAC_BUF(mac);
+
printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
p->psa_io_base_addr_1,
@@ -891,22 +893,13 @@ static void wv_psa_show(psa_t * p)
printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
printk("psa_int_req_no: %d\n", p->psa_int_req_no);
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG
- "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
- p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2],
- p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5],
- p->psa_unused0[6]);
+ printk(KERN_DEBUG "psa_unused0[]: %s\n",
+ print_mac(mac, p->psa_unused0));
#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG
- "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
- p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1],
- p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3],
- p->psa_univ_mac_addr[4], p->psa_univ_mac_addr[5]);
- printk(KERN_DEBUG
- "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
- p->psa_local_mac_addr[0], p->psa_local_mac_addr[1],
- p->psa_local_mac_addr[2], p->psa_local_mac_addr[3],
- p->psa_local_mac_addr[4], p->psa_local_mac_addr[5]);
+ printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n",
+ print_mac(mac, p->psa_univ_mac_addr));
+ printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n",
+ print_mac(mac, p->psa_local_mac_addr));
printk(KERN_DEBUG "psa_univ_local_sel: %d, ",
p->psa_univ_local_sel);
printk("psa_comp_number: %d, ", p->psa_comp_number);
@@ -1248,14 +1241,14 @@ static inline void wv_packet_info(u8 * p, /* Packet to dump */
{ /* Name of the function */
int i;
int maxi;
+ DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG
- "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
- msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
+ "%s: %s(): dest %s, length %d\n",
+ msg1, msg2, print_mac(mac, p), length);
printk(KERN_DEBUG
- "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
- msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12],
- p[13]);
+ "%s: %s(): src %s, type 0x%02X%02X\n",
+ msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]);
#ifdef DEBUG_PACKET_DUMP
@@ -1286,7 +1279,9 @@ static void wv_init_info(struct net_device * dev)
short ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv;
psa_t psa;
- int i;
+#ifdef DEBUG_BASIC_SHOW
+ DECLARE_MAC_BUF(mac);
+#endif
/* Read the parameter storage area */
psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
@@ -1303,10 +1298,8 @@ static void wv_init_info(struct net_device * dev)
#ifdef DEBUG_BASIC_SHOW
/* Now, let's go for the basic stuff. */
- printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr);
- for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
- printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
- printk(", IRQ %d", dev->irq);
+ printk(KERN_NOTICE "%s: WaveLAN at %#x, %s, IRQ %d",
+ dev->name, ioaddr, print_mac(mac, dev->dev_addr), dev->irq);
/* Print current network ID. */
if (psa.psa_nwid_select)
@@ -2400,9 +2393,9 @@ static const struct iw_priv_args wavelan_private_args[] = {
static const struct iw_handler_def wavelan_handler_def =
{
- .num_standard = sizeof(wavelan_handler)/sizeof(iw_handler),
- .num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler),
- .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(wavelan_handler),
+ .num_private = ARRAY_SIZE(wavelan_private_handler),
+ .num_private_args = ARRAY_SIZE(wavelan_private_args),
.standard = wavelan_handler,
.private = wavelan_private_handler,
.private_args = wavelan_private_args,
@@ -3596,15 +3589,15 @@ static void wv_82586_config(struct net_device * dev)
WAVELAN_ADDR_SIZE >> 1);
#ifdef DEBUG_CONFIG_INFO
+ {
+ DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG
"%s: wv_82586_config(): set %d multicast addresses:\n",
dev->name, lp->mc_count);
for (dmi = dev->mc_list; dmi; dmi = dmi->next)
- printk(KERN_DEBUG
- " %02x:%02x:%02x:%02x:%02x:%02x\n",
- dmi->dmi_addr[0], dmi->dmi_addr[1],
- dmi->dmi_addr[2], dmi->dmi_addr[3],
- dmi->dmi_addr[4], dmi->dmi_addr[5]);
+ printk(KERN_DEBUG " %s\n",
+ print_mac(mac, dmi->dmi_addr));
+ }
#endif
}
@@ -4177,7 +4170,6 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr)
/* Init spinlock */
spin_lock_init(&lp->spinlock);
- SET_MODULE_OWNER(dev);
dev->open = wavelan_open;
dev->stop = wavelan_close;
dev->hard_start_xmit = wavelan_packet_xmit;
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 5740d4d4267..577c647824f 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -1042,6 +1042,7 @@ wv_82593_reconfig(struct net_device * dev)
static void
wv_psa_show(psa_t * p)
{
+ DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "##### wavelan psa contents: #####\n");
printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
p->psa_io_base_addr_1,
@@ -1055,29 +1056,13 @@ wv_psa_show(psa_t * p)
printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
printk("psa_int_req_no: %d\n", p->psa_int_req_no);
#ifdef DEBUG_SHOW_UNUSED
- printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
- p->psa_unused0[0],
- p->psa_unused0[1],
- p->psa_unused0[2],
- p->psa_unused0[3],
- p->psa_unused0[4],
- p->psa_unused0[5],
- p->psa_unused0[6]);
+ printk(KERN_DEBUG "psa_unused0[]: %s\n",
+ print_mac(mac, p->psa_unused0));
#endif /* DEBUG_SHOW_UNUSED */
- printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
- p->psa_univ_mac_addr[0],
- p->psa_univ_mac_addr[1],
- p->psa_univ_mac_addr[2],
- p->psa_univ_mac_addr[3],
- p->psa_univ_mac_addr[4],
- p->psa_univ_mac_addr[5]);
- printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
- p->psa_local_mac_addr[0],
- p->psa_local_mac_addr[1],
- p->psa_local_mac_addr[2],
- p->psa_local_mac_addr[3],
- p->psa_local_mac_addr[4],
- p->psa_local_mac_addr[5]);
+ printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n",
+ print_mac(mac, p->psa_univ_mac_addr));
+ printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n",
+ print_mac(mac, p->psa_local_mac_addr));
printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel);
printk("psa_comp_number: %d, ", p->psa_comp_number);
printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
@@ -1277,11 +1262,12 @@ wv_packet_info(u_char * p, /* Packet to dump */
{
int i;
int maxi;
+ DECLARE_MAC_BUF(mac);
- printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
- msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
- printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
- msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]);
+ printk(KERN_DEBUG "%s: %s(): dest %s, length %d\n",
+ msg1, msg2, print_mac(mac, p), length);
+ printk(KERN_DEBUG "%s: %s(): src %s, type 0x%02X%02X\n",
+ msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]);
#ifdef DEBUG_PACKET_DUMP
@@ -1312,7 +1298,7 @@ wv_init_info(struct net_device * dev)
{
kio_addr_t base = dev->base_addr;
psa_t psa;
- int i;
+ DECLARE_MAC_BUF(mac);
/* Read the parameter storage area */
psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
@@ -1329,10 +1315,10 @@ wv_init_info(struct net_device * dev)
#ifdef DEBUG_BASIC_SHOW
/* Now, let's go for the basic stuff */
- printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, hw_addr",
- dev->name, base, dev->irq);
- for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
- printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
+ printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, "
+ "hw_addr %s",
+ dev->name, base, dev->irq,
+ print_mac(mac, dev->dev_addr));
/* Print current network id */
if(psa.psa_nwid_select)
@@ -2719,9 +2705,9 @@ static const iw_handler wavelan_private_handler[] =
static const struct iw_handler_def wavelan_handler_def =
{
- .num_standard = sizeof(wavelan_handler)/sizeof(iw_handler),
- .num_private = sizeof(wavelan_private_handler)/sizeof(iw_handler),
- .num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
+ .num_standard = ARRAY_SIZE(wavelan_handler),
+ .num_private = ARRAY_SIZE(wavelan_private_handler),
+ .num_private_args = ARRAY_SIZE(wavelan_private_args),
.standard = wavelan_handler,
.private = wavelan_private_handler,
.private_args = wavelan_private_args,
@@ -3691,12 +3677,12 @@ wv_82593_config(struct net_device * dev)
int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count;
#ifdef DEBUG_CONFIG_INFO
+ DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n",
dev->name, lp->mc_count);
for(dmi=dev->mc_list; dmi; dmi=dmi->next)
- printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n",
- dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
- dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] );
+ printk(KERN_DEBUG " %s\n",
+ print_mac(mac, dmi->dmi_addr));
#endif
/* Initialize adapter's ethernet multicast addresses */
@@ -4577,7 +4563,6 @@ wavelan_probe(struct pcmcia_device *p_dev)
lp->dev = dev;
/* wavelan NET3 callbacks */
- SET_MODULE_OWNER(dev);
dev->open = &wavelan_open;
dev->stop = &wavelan_close;
dev->hard_start_xmit = &wavelan_packet_xmit;
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index c8b5c227193..42a36b3f3ff 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -859,12 +859,11 @@ static int wl3501_esbq_confirm(struct wl3501_card *this)
static void wl3501_online(struct net_device *dev)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
+ DECLARE_MAC_BUF(mac);
- printk(KERN_INFO "%s: Wireless LAN online. BSSID: "
- "%02X %02X %02X %02X %02X %02X\n", dev->name,
- this->bssid[0], this->bssid[1], this->bssid[2],
- this->bssid[3], this->bssid[4], this->bssid[5]);
+ printk(KERN_INFO "%s: Wireless LAN online. BSSID: %s\n",
+ dev->name, print_mac(mac, this->bssid));
netif_wake_queue(dev);
}
@@ -907,7 +906,7 @@ static int wl3501_mgmt_association(struct wl3501_card *this)
static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
struct wl3501_join_confirm sig;
dprintk(3, "entry");
@@ -1046,7 +1045,7 @@ static inline void wl3501_start_confirm_interrupt(struct net_device *dev,
static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev,
u16 addr)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
struct wl3501_assoc_confirm sig;
dprintk(3, "entry");
@@ -1075,7 +1074,7 @@ static inline void wl3501_rx_interrupt(struct net_device *dev)
int morepkts;
u16 addr;
u8 sig_id;
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
dprintk(3, "entry");
loop:
@@ -1257,7 +1256,7 @@ fail:
static int wl3501_close(struct net_device *dev)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = -ENODEV;
unsigned long flags;
struct pcmcia_device *link;
@@ -1289,7 +1288,7 @@ static int wl3501_close(struct net_device *dev)
*/
static int wl3501_reset(struct net_device *dev)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = -ENODEV;
wl3501_block_interrupt(this);
@@ -1318,7 +1317,7 @@ out:
static void wl3501_tx_timeout(struct net_device *dev)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
struct net_device_stats *stats = &this->stats;
unsigned long flags;
int rc;
@@ -1344,7 +1343,7 @@ static void wl3501_tx_timeout(struct net_device *dev)
static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
int enabled, rc;
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
unsigned long flags;
spin_lock_irqsave(&this->lock, flags);
@@ -1371,7 +1370,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
static int wl3501_open(struct net_device *dev)
{
int rc = -ENODEV;
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
unsigned long flags;
struct pcmcia_device *link;
link = this->p_dev;
@@ -1410,14 +1409,14 @@ fail:
static struct net_device_stats *wl3501_get_stats(struct net_device *dev)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
return &this->stats;
}
static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
struct iw_statistics *wstats = &this->wstats;
u32 value; /* size checked: it is u32 */
@@ -1497,7 +1496,7 @@ static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info,
static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int channel = wrqu->freq.m;
int rc = -EINVAL;
@@ -1511,7 +1510,7 @@ static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info,
static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
wrqu->freq.m = wl3501_chan2freq[this->chan - 1] * 100000;
wrqu->freq.e = 1;
@@ -1526,7 +1525,7 @@ static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info,
if (wrqu->mode == IW_MODE_INFRA ||
wrqu->mode == IW_MODE_ADHOC ||
wrqu->mode == IW_MODE_AUTO) {
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
this->net_type = wrqu->mode;
rc = wl3501_reset(dev);
@@ -1537,7 +1536,7 @@ static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info,
static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
wrqu->mode = this->net_type;
return 0;
@@ -1546,7 +1545,7 @@ static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info,
static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
wrqu->sens.value = this->rssi;
wrqu->sens.disabled = !wrqu->sens.value;
@@ -1577,7 +1576,7 @@ static int wl3501_get_range(struct net_device *dev,
static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
static const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 };
int rc = -EINVAL;
@@ -1597,7 +1596,7 @@ out:
static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
wrqu->ap_addr.sa_family = ARPHRD_ETHER;
memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN);
@@ -1616,7 +1615,7 @@ static int wl3501_set_scan(struct net_device *dev, struct iw_request_info *info,
static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int i;
char *current_ev = extra;
struct iw_event iwe;
@@ -1666,7 +1665,7 @@ static int wl3501_set_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
if (wrqu->data.flags) {
iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID,
@@ -1683,7 +1682,7 @@ static int wl3501_get_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
unsigned long flags;
spin_lock_irqsave(&this->lock, flags);
@@ -1697,7 +1696,7 @@ static int wl3501_get_essid(struct net_device *dev,
static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
if (wrqu->data.length > sizeof(this->nick))
return -E2BIG;
@@ -1708,7 +1707,7 @@ static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info,
static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
strlcpy(extra, this->nick, 32);
wrqu->data.length = strlen(extra);
@@ -1733,7 +1732,7 @@ static int wl3501_get_rts_threshold(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
u16 threshold; /* size checked: it is u16 */
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD,
&threshold, sizeof(threshold));
if (!rc) {
@@ -1749,7 +1748,7 @@ static int wl3501_get_frag_threshold(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
u16 threshold; /* size checked: it is u16 */
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD,
&threshold, sizeof(threshold));
if (!rc) {
@@ -1765,7 +1764,7 @@ static int wl3501_get_txpow(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
u16 txpow;
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = wl3501_get_mib_value(this,
WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL,
&txpow, sizeof(txpow));
@@ -1787,7 +1786,7 @@ static int wl3501_get_retry(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
u8 retry; /* size checked: it is u8 */
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = wl3501_get_mib_value(this,
WL3501_MIB_ATTR_LONG_RETRY_LIMIT,
&retry, sizeof(retry));
@@ -1814,7 +1813,7 @@ static int wl3501_get_encode(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
u8 implemented, restricted, keys[100], len_keys, tocopy;
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = wl3501_get_mib_value(this,
WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED,
&implemented, sizeof(implemented));
@@ -1841,7 +1840,6 @@ static int wl3501_get_encode(struct net_device *dev,
tocopy = min_t(u8, len_keys, wrqu->encoding.length);
tocopy = min_t(u8, tocopy, 100);
wrqu->encoding.length = tocopy;
- memset(extra, 0, tocopy);
memcpy(extra, keys, tocopy);
out:
return rc;
@@ -1852,7 +1850,7 @@ static int wl3501_get_power(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
u8 pwr_state;
- struct wl3501_card *this = dev->priv;
+ struct wl3501_card *this = netdev_priv(dev);
int rc = wl3501_get_mib_value(this,
WL3501_MIB_ATTR_CURRENT_PWR_STATE,
&pwr_state, sizeof(pwr_state));
@@ -1894,7 +1892,7 @@ static const iw_handler wl3501_handler[] = {
};
static const struct iw_handler_def wl3501_handler_def = {
- .num_standard = sizeof(wl3501_handler) / sizeof(iw_handler),
+ .num_standard = ARRAY_SIZE(wl3501_handler),
.standard = (iw_handler *)wl3501_handler,
.get_wireless_stats = wl3501_get_wireless_stats,
};
@@ -1937,7 +1935,7 @@ static int wl3501_probe(struct pcmcia_device *p_dev)
dev->tx_timeout = wl3501_tx_timeout;
dev->watchdog_timeo = 5 * HZ;
dev->get_stats = wl3501_get_stats;
- this = dev->priv;
+ this = netdev_priv(dev);
this->wireless_data.spy_data = &this->spy_data;
this->p_dev = p_dev;
dev->wireless_data = &this->wireless_data;
@@ -1967,6 +1965,7 @@ static int wl3501_config(struct pcmcia_device *link)
struct net_device *dev = link->priv;
int i = 0, j, last_fn, last_ret;
struct wl3501_card *this;
+ DECLARE_MAC_BUF(mac);
/* Try allocating IO ports. This tries a few fixed addresses. If you
* want, you can also read the card's config table to pick addresses --
@@ -2004,9 +2003,7 @@ static int wl3501_config(struct pcmcia_device *link)
goto failed;
}
- SET_MODULE_OWNER(dev);
-
- this = dev->priv;
+ this = netdev_priv(dev);
/*
* At this point, the dev_node_t structure(s) should be initialized and
* arranged in a linked list at link->dev_node.
@@ -2022,14 +2019,14 @@ static int wl3501_config(struct pcmcia_device *link)
}
strcpy(this->node.dev_name, dev->name);
- /* print probe information */
- printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, MAC addr in flash ROM:",
- dev->name, this->base_addr, (int)dev->irq);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
dev->dev_addr[i] = ((char *)&this->mac_addr)[i];
- printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
- }
- printk("\n");
+
+ /* print probe information */
+ printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, "
+ "MAC addr in flash ROM:%s\n",
+ dev->name, this->base_addr, (int)dev->irq,
+ print_mac(mac, dev->dev_addr));
/*
* Initialize card parameters - added by jss
*/
@@ -2079,7 +2076,7 @@ static int wl3501_suspend(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND);
+ wl3501_pwr_mgmt(netdev_priv(dev), WL3501_SUSPEND);
if (link->open)
netif_device_detach(dev);
@@ -2090,7 +2087,7 @@ static int wl3501_resume(struct pcmcia_device *link)
{
struct net_device *dev = link->priv;
- wl3501_pwr_mgmt(dev->priv, WL3501_RESUME);
+ wl3501_pwr_mgmt(netdev_priv(dev), WL3501_RESUME);
if (link->open) {
wl3501_reset(dev);
netif_device_attach(dev);
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 935b144d9b5..d5c0c66188c 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -327,8 +327,8 @@ static void zd1201_usbrx(struct urb *urb)
memcpy(skb_put(skb, 6), &data[datalen-8], 6);
memcpy(skb_put(skb, 2), &data[datalen-24], 2);
memcpy(skb_put(skb, len), data, len);
- skb->dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, zd->dev);
+ skb->dev->last_rx = jiffies;
zd->stats.rx_packets++;
zd->stats.rx_bytes += skb->len;
netif_rx(skb);
@@ -384,8 +384,8 @@ static void zd1201_usbrx(struct urb *urb)
memcpy(skb_put(skb, 2), &data[6], 2);
memcpy(skb_put(skb, len), data+8, len);
}
- skb->dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, zd->dev);
+ skb->dev->last_rx = jiffies;
zd->stats.rx_packets++;
zd->stats.rx_bytes += skb->len;
netif_rx(skb);
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
index 4d505903352..7a2f2a98eda 100644
--- a/drivers/net/wireless/zd1211rw/Makefile
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -4,7 +4,7 @@ zd1211rw-objs := zd_chip.o zd_ieee80211.o \
zd_mac.o zd_netdev.o \
zd_rf_al2230.o zd_rf_rf2959.o \
zd_rf_al7230b.o zd_rf_uw2453.o \
- zd_rf.o zd_usb.o zd_util.o
+ zd_rf.o zd_usb.o
ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index c39f1984b84..f831b68f1b9 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -28,7 +28,6 @@
#include "zd_ieee80211.h"
#include "zd_mac.h"
#include "zd_rf.h"
-#include "zd_util.h"
void zd_chip_init(struct zd_chip *chip,
struct net_device *netdev,
@@ -106,7 +105,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
{
int r;
int i;
- zd_addr_t *a16 = (zd_addr_t *)NULL;
+ zd_addr_t *a16;
u16 *v16;
unsigned int count16;
@@ -377,6 +376,7 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
[0] = { .addr = CR_MAC_ADDR_P1 },
[1] = { .addr = CR_MAC_ADDR_P2 },
};
+ DECLARE_MAC_BUF(mac);
reqs[0].value = (mac_addr[3] << 24)
| (mac_addr[2] << 16)
@@ -386,7 +386,7 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
| mac_addr[4];
dev_dbg_f(zd_chip_dev(chip),
- "mac addr " MAC_FMT "\n", MAC_ARG(mac_addr));
+ "mac addr %s\n", print_mac(mac, mac_addr));
mutex_lock(&chip->mutex);
r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
@@ -500,8 +500,6 @@ int zd_chip_lock_phy_regs(struct zd_chip *chip)
return r;
}
- dev_dbg_f(zd_chip_dev(chip),
- "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp & ~UNLOCK_PHY_REGS);
tmp &= ~UNLOCK_PHY_REGS;
r = zd_iowrite32_locked(chip, tmp, CR_REG1);
@@ -523,8 +521,6 @@ int zd_chip_unlock_phy_regs(struct zd_chip *chip)
return r;
}
- dev_dbg_f(zd_chip_dev(chip),
- "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp | UNLOCK_PHY_REGS);
tmp |= UNLOCK_PHY_REGS;
r = zd_iowrite32_locked(chip, tmp, CR_REG1);
@@ -841,8 +837,6 @@ static int get_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s)
s->atim_wnd_period = values[0];
s->pre_tbtt = values[1];
s->beacon_interval = values[2];
- dev_dbg_f(zd_chip_dev(chip), "aw %u pt %u bi %u\n",
- s->atim_wnd_period, s->pre_tbtt, s->beacon_interval);
return 0;
}
@@ -864,9 +858,6 @@ static int set_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s)
reqs[2].addr = CR_BCN_INTERVAL;
reqs[2].value = s->beacon_interval;
- dev_dbg_f(zd_chip_dev(chip),
- "aw %u pt %u bi %u\n", s->atim_wnd_period, s->pre_tbtt,
- s->beacon_interval);
return zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
}
@@ -1018,19 +1009,19 @@ int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip,
u32 value = 0;
/* Modulation bit */
- if (ZD_CS_TYPE(rts_rate) == ZD_CS_OFDM)
+ if (ZD_MODULATION_TYPE(rts_rate) == ZD_OFDM)
rts_mod = ZD_RX_OFDM;
dev_dbg_f(zd_chip_dev(chip), "rts_rate=%x preamble=%x\n",
rts_rate, preamble);
- value |= rts_rate << RTSCTS_SH_RTS_RATE;
+ value |= ZD_PURE_RATE(rts_rate) << RTSCTS_SH_RTS_RATE;
value |= rts_mod << RTSCTS_SH_RTS_MOD_TYPE;
value |= preamble << RTSCTS_SH_RTS_PMB_TYPE;
value |= preamble << RTSCTS_SH_CTS_PMB_TYPE;
/* We always send 11M self-CTS messages, like the vendor driver. */
- value |= ZD_CCK_RATE_11M << RTSCTS_SH_CTS_RATE;
+ value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_CTS_RATE;
value |= ZD_RX_CCK << RTSCTS_SH_CTS_MOD_TYPE;
return zd_iowrite32_locked(chip, value, CR_RTS_CTS_RATE);
@@ -1160,16 +1151,12 @@ out:
static int update_pwr_int(struct zd_chip *chip, u8 channel)
{
u8 value = chip->pwr_int_values[channel - 1];
- dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n",
- channel, value);
return zd_iowrite16_locked(chip, value, CR31);
}
static int update_pwr_cal(struct zd_chip *chip, u8 channel)
{
u8 value = chip->pwr_cal_values[channel-1];
- dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n",
- channel, value);
return zd_iowrite16_locked(chip, value, CR68);
}
@@ -1184,9 +1171,6 @@ static int update_ofdm_cal(struct zd_chip *chip, u8 channel)
ioreqs[2].addr = CR65;
ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1];
- dev_dbg_f(zd_chip_dev(chip),
- "channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n",
- channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value);
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
@@ -1344,7 +1328,7 @@ int zd_chip_set_basic_rates_locked(struct zd_chip *chip, u16 cr_rates)
return zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL);
}
-static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
+static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size)
{
static const u16 constants[] = {
715, 655, 585, 540, 470, 410, 360, 315,
@@ -1358,7 +1342,7 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
/* It seems that their quality parameter is somehow per signal
* and is now transferred per bit.
*/
- switch (rate) {
+ switch (zd_rate) {
case ZD_OFDM_RATE_6M:
case ZD_OFDM_RATE_12M:
case ZD_OFDM_RATE_24M:
@@ -1385,7 +1369,7 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
break;
}
- switch (rate) {
+ switch (zd_rate) {
case ZD_OFDM_RATE_6M:
case ZD_OFDM_RATE_9M:
i += 3;
@@ -1409,11 +1393,11 @@ static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
return i;
}
-static int ofdm_qual_percent(u8 status_quality, u8 rate, unsigned int size)
+static int ofdm_qual_percent(u8 status_quality, u8 zd_rate, unsigned int size)
{
int r;
- r = ofdm_qual_db(status_quality, rate, size);
+ r = ofdm_qual_db(status_quality, zd_rate, size);
ZD_ASSERT(r >= 0);
if (r < 0)
r = 0;
@@ -1474,12 +1458,17 @@ static int cck_qual_percent(u8 status_quality)
return r <= 100 ? r : 100;
}
+static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame)
+{
+ return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame);
+}
+
u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
const struct rx_status *status)
{
return (status->frame_status&ZD_RX_OFDM) ?
ofdm_qual_percent(status->signal_quality_ofdm,
- zd_ofdm_plcp_header_rate(rx_frame),
+ zd_rate_from_ofdm_plcp_header(rx_frame),
size) :
cck_qual_percent(status->signal_quality_cck);
}
@@ -1495,32 +1484,32 @@ u8 zd_rx_strength_percent(u8 rssi)
u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status)
{
static const u16 ofdm_rates[] = {
- [ZD_OFDM_RATE_6M] = 60,
- [ZD_OFDM_RATE_9M] = 90,
- [ZD_OFDM_RATE_12M] = 120,
- [ZD_OFDM_RATE_18M] = 180,
- [ZD_OFDM_RATE_24M] = 240,
- [ZD_OFDM_RATE_36M] = 360,
- [ZD_OFDM_RATE_48M] = 480,
- [ZD_OFDM_RATE_54M] = 540,
+ [ZD_OFDM_PLCP_RATE_6M] = 60,
+ [ZD_OFDM_PLCP_RATE_9M] = 90,
+ [ZD_OFDM_PLCP_RATE_12M] = 120,
+ [ZD_OFDM_PLCP_RATE_18M] = 180,
+ [ZD_OFDM_PLCP_RATE_24M] = 240,
+ [ZD_OFDM_PLCP_RATE_36M] = 360,
+ [ZD_OFDM_PLCP_RATE_48M] = 480,
+ [ZD_OFDM_PLCP_RATE_54M] = 540,
};
u16 rate;
if (status->frame_status & ZD_RX_OFDM) {
+ /* Deals with PLCP OFDM rate (not zd_rates) */
u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame);
rate = ofdm_rates[ofdm_rate & 0xf];
} else {
- u8 cck_rate = zd_cck_plcp_header_rate(rx_frame);
- switch (cck_rate) {
- case ZD_CCK_SIGNAL_1M:
+ switch (zd_cck_plcp_header_signal(rx_frame)) {
+ case ZD_CCK_PLCP_SIGNAL_1M:
rate = 10;
break;
- case ZD_CCK_SIGNAL_2M:
+ case ZD_CCK_PLCP_SIGNAL_2M:
rate = 20;
break;
- case ZD_CCK_SIGNAL_5M5:
+ case ZD_CCK_PLCP_SIGNAL_5M5:
rate = 55;
break;
- case ZD_CCK_SIGNAL_11M:
+ case ZD_CCK_PLCP_SIGNAL_11M:
rate = 110;
break;
default:
@@ -1638,7 +1627,5 @@ int zd_chip_set_multicast_hash(struct zd_chip *chip,
{ CR_GROUP_HASH_P2, hash->high },
};
- dev_dbg_f(zd_chip_dev(chip), "hash l 0x%08x h 0x%08x\n",
- ioreqs[0].value, ioreqs[1].value);
return zd_iowrite32a(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index f4698576ab7..8009b70213e 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -871,11 +871,6 @@ static inline int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
return r;
}
-static inline int zd_chip_set_rx_filter(struct zd_chip *chip, u32 filter)
-{
- return zd_iowrite32(chip, CR_RX_FILTER, filter);
-}
-
int zd_chip_lock_phy_regs(struct zd_chip *chip);
int zd_chip_unlock_phy_regs(struct zd_chip *chip);
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
index deb99d1eaa7..505b4d7dd0e 100644
--- a/drivers/net/wireless/zd1211rw/zd_def.h
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -21,7 +21,6 @@
#include <linux/kernel.h>
#include <linux/stringify.h>
#include <linux/device.h>
-#include <linux/kernel.h>
typedef u16 __nocast zd_addr_t;
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
index c4f36d39642..fbf6491dce7 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -43,21 +43,25 @@ struct ofdm_plcp_header {
__le16 service;
} __attribute__((packed));
-static inline u8 zd_ofdm_plcp_header_rate(
- const struct ofdm_plcp_header *header)
+static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header)
{
return header->prefix[0] & 0xf;
}
-/* These are referred to as zd_rates */
-#define ZD_OFDM_RATE_6M 0xb
-#define ZD_OFDM_RATE_9M 0xf
-#define ZD_OFDM_RATE_12M 0xa
-#define ZD_OFDM_RATE_18M 0xe
-#define ZD_OFDM_RATE_24M 0x9
-#define ZD_OFDM_RATE_36M 0xd
-#define ZD_OFDM_RATE_48M 0x8
-#define ZD_OFDM_RATE_54M 0xc
+/* The following defines give the encoding of the 4-bit rate field in the
+ * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to
+ * define the zd-rate values for OFDM.
+ *
+ * See the struct zd_ctrlset definition in zd_mac.h.
+ */
+#define ZD_OFDM_PLCP_RATE_6M 0xb
+#define ZD_OFDM_PLCP_RATE_9M 0xf
+#define ZD_OFDM_PLCP_RATE_12M 0xa
+#define ZD_OFDM_PLCP_RATE_18M 0xe
+#define ZD_OFDM_PLCP_RATE_24M 0x9
+#define ZD_OFDM_PLCP_RATE_36M 0xd
+#define ZD_OFDM_PLCP_RATE_48M 0x8
+#define ZD_OFDM_PLCP_RATE_54M 0xc
struct cck_plcp_header {
u8 signal;
@@ -66,15 +70,22 @@ struct cck_plcp_header {
__le16 crc16;
} __attribute__((packed));
-static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header)
+static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header)
{
return header->signal;
}
-#define ZD_CCK_SIGNAL_1M 0x0a
-#define ZD_CCK_SIGNAL_2M 0x14
-#define ZD_CCK_SIGNAL_5M5 0x37
-#define ZD_CCK_SIGNAL_11M 0x6e
+/* These defines give the encodings of the signal field in the 802.11b PLCP
+ * header. The signal field gives the bit rate of the following packet. Even
+ * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s
+ * rate to stay consistent with Zydas and our use of the term.
+ *
+ * Notify that these values are *not* used in the zd-rates.
+ */
+#define ZD_CCK_PLCP_SIGNAL_1M 0x0a
+#define ZD_CCK_PLCP_SIGNAL_2M 0x14
+#define ZD_CCK_PLCP_SIGNAL_5M5 0x37
+#define ZD_CCK_PLCP_SIGNAL_11M 0x6e
enum ieee80211_std {
IEEE80211B = 0x01,
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 26869d107e5..a903645e157 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -28,7 +28,6 @@
#include "zd_ieee80211.h"
#include "zd_netdev.h"
#include "zd_rf.h"
-#include "zd_util.h"
static void ieee_init(struct ieee80211_device *ieee);
static void softmac_init(struct ieee80211softmac_device *sm);
@@ -161,13 +160,33 @@ void zd_mac_clear(struct zd_mac *mac)
ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
}
-static int reset_mode(struct zd_mac *mac)
+static int set_rx_filter(struct zd_mac *mac)
{
struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER;
return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
}
+static int set_sniffer(struct zd_mac *mac)
+{
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+ return zd_iowrite32(&mac->chip, CR_SNIFFER_ON,
+ ieee->iw_mode == IW_MODE_MONITOR ? 1 : 0);
+ return 0;
+}
+
+static int set_mc_hash(struct zd_mac *mac)
+{
+ struct zd_mc_hash hash;
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+ zd_mc_clear(&hash);
+ if (ieee->iw_mode == IW_MODE_MONITOR)
+ zd_mc_add_all(&hash);
+
+ return zd_chip_set_multicast_hash(&mac->chip, &hash);
+}
+
int zd_mac_open(struct net_device *netdev)
{
struct zd_mac *mac = zd_netdev_mac(netdev);
@@ -194,7 +213,13 @@ int zd_mac_open(struct net_device *netdev)
r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);
if (r < 0)
goto disable_int;
- r = reset_mode(mac);
+ r = set_rx_filter(mac);
+ if (r)
+ goto disable_int;
+ r = set_sniffer(mac);
+ if (r)
+ goto disable_int;
+ r = set_mc_hash(mac);
if (r)
goto disable_int;
r = zd_chip_switch_radio_on(chip);
@@ -263,12 +288,13 @@ int zd_mac_set_mac_address(struct net_device *netdev, void *p)
struct sockaddr *addr = p;
struct zd_mac *mac = zd_netdev_mac(netdev);
struct zd_chip *chip = &mac->chip;
+ DECLARE_MAC_BUF(mac2);
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
dev_dbg_f(zd_mac_dev(mac),
- "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data));
+ "Setting MAC to %s\n", print_mac(mac2, addr->sa_data));
if (netdev->flags & IFF_UP) {
r = zd_write_mac_addr(chip, addr->sa_data);
@@ -298,18 +324,21 @@ static void set_multicast_hash_handler(struct work_struct *work)
void zd_mac_set_multicast_list(struct net_device *dev)
{
- struct zd_mc_hash hash;
struct zd_mac *mac = zd_netdev_mac(dev);
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+ struct zd_mc_hash hash;
struct dev_mc_list *mc;
unsigned long flags;
+ DECLARE_MAC_BUF(mac2);
- if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) {
+ if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI) ||
+ ieee->iw_mode == IW_MODE_MONITOR) {
zd_mc_add_all(&hash);
} else {
zd_mc_clear(&hash);
for (mc = dev->mc_list; mc; mc = mc->next) {
- dev_dbg_f(zd_mac_dev(mac), "mc addr " MAC_FMT "\n",
- MAC_ARG(mc->dmi_addr));
+ dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n",
+ print_mac(mac2, mc->dmi_addr));
zd_mc_add_addr(&hash, mc->dmi_addr);
}
}
@@ -582,28 +611,6 @@ u8 zd_mac_get_channel(struct zd_mac *mac)
return channel;
}
-/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */
-static u8 zd_rate_typed(u8 zd_rate)
-{
- static const u8 typed_rates[16] = {
- [ZD_CCK_RATE_1M] = ZD_CS_CCK|ZD_CCK_RATE_1M,
- [ZD_CCK_RATE_2M] = ZD_CS_CCK|ZD_CCK_RATE_2M,
- [ZD_CCK_RATE_5_5M] = ZD_CS_CCK|ZD_CCK_RATE_5_5M,
- [ZD_CCK_RATE_11M] = ZD_CS_CCK|ZD_CCK_RATE_11M,
- [ZD_OFDM_RATE_6M] = ZD_CS_OFDM|ZD_OFDM_RATE_6M,
- [ZD_OFDM_RATE_9M] = ZD_CS_OFDM|ZD_OFDM_RATE_9M,
- [ZD_OFDM_RATE_12M] = ZD_CS_OFDM|ZD_OFDM_RATE_12M,
- [ZD_OFDM_RATE_18M] = ZD_CS_OFDM|ZD_OFDM_RATE_18M,
- [ZD_OFDM_RATE_24M] = ZD_CS_OFDM|ZD_OFDM_RATE_24M,
- [ZD_OFDM_RATE_36M] = ZD_CS_OFDM|ZD_OFDM_RATE_36M,
- [ZD_OFDM_RATE_48M] = ZD_CS_OFDM|ZD_OFDM_RATE_48M,
- [ZD_OFDM_RATE_54M] = ZD_CS_OFDM|ZD_OFDM_RATE_54M,
- };
-
- ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f);
- return typed_rates[zd_rate & ZD_CS_RATE_MASK];
-}
-
int zd_mac_set_mode(struct zd_mac *mac, u32 mode)
{
struct ieee80211_device *ieee;
@@ -628,8 +635,12 @@ int zd_mac_set_mode(struct zd_mac *mac, u32 mode)
ieee->iw_mode = mode;
spin_unlock_irq(&ieee->lock);
- if (netif_running(mac->netdev))
- return reset_mode(mac);
+ if (netif_running(mac->netdev)) {
+ int r = set_rx_filter(mac);
+ if (r)
+ return r;
+ return set_sniffer(mac);
+ }
return 0;
}
@@ -707,25 +718,30 @@ int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range)
static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
{
+ /* ZD_PURE_RATE() must be used to remove the modulation type flag of
+ * the zd-rate values. */
static const u8 rate_divisor[] = {
- [ZD_CCK_RATE_1M] = 1,
- [ZD_CCK_RATE_2M] = 2,
- [ZD_CCK_RATE_5_5M] = 11, /* bits must be doubled */
- [ZD_CCK_RATE_11M] = 11,
- [ZD_OFDM_RATE_6M] = 6,
- [ZD_OFDM_RATE_9M] = 9,
- [ZD_OFDM_RATE_12M] = 12,
- [ZD_OFDM_RATE_18M] = 18,
- [ZD_OFDM_RATE_24M] = 24,
- [ZD_OFDM_RATE_36M] = 36,
- [ZD_OFDM_RATE_48M] = 48,
- [ZD_OFDM_RATE_54M] = 54,
+ [ZD_PURE_RATE(ZD_CCK_RATE_1M)] = 1,
+ [ZD_PURE_RATE(ZD_CCK_RATE_2M)] = 2,
+
+ /* bits must be doubled */
+ [ZD_PURE_RATE(ZD_CCK_RATE_5_5M)] = 11,
+
+ [ZD_PURE_RATE(ZD_CCK_RATE_11M)] = 11,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_6M)] = 6,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_9M)] = 9,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_12M)] = 12,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_18M)] = 18,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_24M)] = 24,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_36M)] = 36,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_48M)] = 48,
+ [ZD_PURE_RATE(ZD_OFDM_RATE_54M)] = 54,
};
u32 bits = (u32)tx_length * 8;
u32 divisor;
- divisor = rate_divisor[zd_rate];
+ divisor = rate_divisor[ZD_PURE_RATE(zd_rate)];
if (divisor == 0)
return -EINVAL;
@@ -748,52 +764,24 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
return bits/divisor;
}
-enum {
- R2M_SHORT_PREAMBLE = 0x01,
- R2M_11A = 0x02,
-};
-
-static u8 zd_rate_to_modulation(u8 zd_rate, int flags)
-{
- u8 modulation;
-
- modulation = zd_rate_typed(zd_rate);
- if (flags & R2M_SHORT_PREAMBLE) {
- switch (ZD_CS_RATE(modulation)) {
- case ZD_CCK_RATE_2M:
- case ZD_CCK_RATE_5_5M:
- case ZD_CCK_RATE_11M:
- modulation |= ZD_CS_CCK_PREA_SHORT;
- return modulation;
- }
- }
- if (flags & R2M_11A) {
- if (ZD_CS_TYPE(modulation) == ZD_CS_OFDM)
- modulation |= ZD_CS_OFDM_MODE_11A;
- }
- return modulation;
-}
-
static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs,
struct ieee80211_hdr_4addr *hdr)
{
struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev);
u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl));
- u8 rate, zd_rate;
+ u8 rate;
int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0;
int is_multicast = is_multicast_ether_addr(hdr->addr1);
int short_preamble = ieee80211softmac_short_preamble_ok(softmac,
is_multicast, is_mgt);
- int flags = 0;
- /* FIXME: 802.11a? */
rate = ieee80211softmac_suggest_txrate(softmac, is_multicast, is_mgt);
+ cs->modulation = rate_to_zd_rate(rate);
- if (short_preamble)
- flags |= R2M_SHORT_PREAMBLE;
-
- zd_rate = rate_to_zd_rate(rate);
- cs->modulation = zd_rate_to_modulation(zd_rate, flags);
+ /* Set short preamble bit when appropriate */
+ if (short_preamble && ZD_MODULATION_TYPE(cs->modulation) == ZD_CCK
+ && cs->modulation != ZD_CCK_RATE_1M)
+ cs->modulation |= ZD_CCK_PREA_SHORT;
}
static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
@@ -832,7 +820,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
cs->control |= ZD_CS_RTS;
/* Use CTS-to-self protection if required */
- if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM &&
+ if (ZD_MODULATION_TYPE(cs->modulation) == ZD_OFDM &&
ieee80211softmac_protection_needed(softmac)) {
/* FIXME: avoid sending RTS *and* self-CTS, is that correct? */
cs->control &= ~ZD_CS_RTS;
@@ -893,7 +881,7 @@ static int fill_ctrlset(struct zd_mac *mac,
* - see line 53 of zdinlinef.h
*/
cs->service = 0;
- r = zd_calc_tx_length_us(&cs->service, ZD_CS_RATE(cs->modulation),
+ r = zd_calc_tx_length_us(&cs->service, ZD_RATE(cs->modulation),
le16_to_cpu(cs->tx_length));
if (r < 0)
return r;
@@ -902,7 +890,7 @@ static int fill_ctrlset(struct zd_mac *mac,
if (next_frag_len == 0) {
cs->next_frame_length = 0;
} else {
- r = zd_calc_tx_length_us(NULL, ZD_CS_RATE(cs->modulation),
+ r = zd_calc_tx_length_us(NULL, ZD_RATE(cs->modulation),
next_frag_len);
if (r < 0)
return r;
@@ -1077,7 +1065,8 @@ static int fill_rx_stats(struct ieee80211_rx_stats *stats,
{
const struct rx_status *status;
- *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
+ *pstatus = status = (struct rx_status *)
+ (buffer + (length - sizeof(struct rx_status)));
if (status->frame_status & ZD_RX_ERROR) {
struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
ieee->stats.rx_errors++;
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 9f9344eb50f..1b15bde3ff6 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -40,28 +40,51 @@ struct zd_ctrlset {
#define ZD_CS_RESERVED_SIZE 25
-/* zd_crtlset field modulation */
-#define ZD_CS_RATE_MASK 0x0f
-#define ZD_CS_TYPE_MASK 0x10
-#define ZD_CS_RATE(modulation) ((modulation) & ZD_CS_RATE_MASK)
-#define ZD_CS_TYPE(modulation) ((modulation) & ZD_CS_TYPE_MASK)
-
-#define ZD_CS_CCK 0x00
-#define ZD_CS_OFDM 0x10
-
-/* These are referred to as zd_rates */
-#define ZD_CCK_RATE_1M 0x00
-#define ZD_CCK_RATE_2M 0x01
-#define ZD_CCK_RATE_5_5M 0x02
-#define ZD_CCK_RATE_11M 0x03
-/* The rates for OFDM are encoded as in the PLCP header. Use ZD_OFDM_RATE_*.
+/* The field modulation of struct zd_ctrlset controls the bit rate, the use
+ * of short or long preambles in 802.11b (CCK mode) or the use of 802.11a or
+ * 802.11g in OFDM mode.
+ *
+ * The term zd-rate is used for the combination of the modulation type flag
+ * and the "pure" rate value.
*/
-
-/* bit 5 is preamble (when in CCK mode), or a/g selection (when in OFDM mode) */
-#define ZD_CS_CCK_PREA_LONG 0x00
-#define ZD_CS_CCK_PREA_SHORT 0x20
-#define ZD_CS_OFDM_MODE_11G 0x00
-#define ZD_CS_OFDM_MODE_11A 0x20
+#define ZD_PURE_RATE_MASK 0x0f
+#define ZD_MODULATION_TYPE_MASK 0x10
+#define ZD_RATE_MASK (ZD_PURE_RATE_MASK|ZD_MODULATION_TYPE_MASK)
+#define ZD_PURE_RATE(modulation) ((modulation) & ZD_PURE_RATE_MASK)
+#define ZD_MODULATION_TYPE(modulation) ((modulation) & ZD_MODULATION_TYPE_MASK)
+#define ZD_RATE(modulation) ((modulation) & ZD_RATE_MASK)
+
+/* The two possible modulation types. Notify that 802.11b doesn't use the CCK
+ * codeing for the 1 and 2 MBit/s rate. We stay with the term here to remain
+ * consistent with uses the term at other places.
+ */
+#define ZD_CCK 0x00
+#define ZD_OFDM 0x10
+
+/* The ZD1211 firmware uses proprietary encodings of the 802.11b (CCK) rates.
+ * For OFDM the PLCP rate encodings are used. We combine these "pure" rates
+ * with the modulation type flag and call the resulting values zd-rates.
+ */
+#define ZD_CCK_RATE_1M (ZD_CCK|0x00)
+#define ZD_CCK_RATE_2M (ZD_CCK|0x01)
+#define ZD_CCK_RATE_5_5M (ZD_CCK|0x02)
+#define ZD_CCK_RATE_11M (ZD_CCK|0x03)
+#define ZD_OFDM_RATE_6M (ZD_OFDM|ZD_OFDM_PLCP_RATE_6M)
+#define ZD_OFDM_RATE_9M (ZD_OFDM|ZD_OFDM_PLCP_RATE_9M)
+#define ZD_OFDM_RATE_12M (ZD_OFDM|ZD_OFDM_PLCP_RATE_12M)
+#define ZD_OFDM_RATE_18M (ZD_OFDM|ZD_OFDM_PLCP_RATE_18M)
+#define ZD_OFDM_RATE_24M (ZD_OFDM|ZD_OFDM_PLCP_RATE_24M)
+#define ZD_OFDM_RATE_36M (ZD_OFDM|ZD_OFDM_PLCP_RATE_36M)
+#define ZD_OFDM_RATE_48M (ZD_OFDM|ZD_OFDM_PLCP_RATE_48M)
+#define ZD_OFDM_RATE_54M (ZD_OFDM|ZD_OFDM_PLCP_RATE_54M)
+
+/* The bit 5 of the zd_ctrlset modulation field controls the preamble in CCK
+ * mode or the 802.11a/802.11g selection in OFDM mode.
+ */
+#define ZD_CCK_PREA_LONG 0x00
+#define ZD_CCK_PREA_SHORT 0x20
+#define ZD_OFDM_MODE_11G 0x00
+#define ZD_OFDM_MODE_11A 0x20
/* zd_ctrlset control field */
#define ZD_CS_NEED_RANDOM_BACKOFF 0x01
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
index 8bda48de31e..047cab3d87d 100644
--- a/drivers/net/wireless/zd1211rw/zd_netdev.c
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.c
@@ -233,7 +233,6 @@ struct net_device *zd_netdev_alloc(struct usb_interface *intf)
return NULL;
}
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &intf->dev);
dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index a9c339ef116..c755b692381 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -31,7 +31,6 @@
#include "zd_netdev.h"
#include "zd_mac.h"
#include "zd_usb.h"
-#include "zd_util.h"
static struct usb_device_id usb_ids[] = {
/* ZD1211 */
@@ -55,6 +54,7 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
/* ZD1211B */
{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
@@ -74,6 +74,9 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
@@ -1041,14 +1044,17 @@ error:
static void disconnect(struct usb_interface *intf)
{
struct net_device *netdev = zd_intf_to_netdev(intf);
- struct zd_mac *mac = zd_netdev_mac(netdev);
- struct zd_usb *usb = &mac->chip.usb;
+ struct zd_mac *mac;
+ struct zd_usb *usb;
/* Either something really bad happened, or we're just dealing with
* a DEVICE_INSTALLER. */
if (netdev == NULL)
return;
+ mac = zd_netdev_mac(netdev);
+ usb = &mac->chip.usb;
+
dev_dbg_f(zd_usb_dev(usb), "\n");
zd_netdev_disconnect(netdev);
diff --git a/drivers/net/wireless/zd1211rw/zd_util.c b/drivers/net/wireless/zd1211rw/zd_util.c
deleted file mode 100644
index d20036c15d1..00000000000
--- a/drivers/net/wireless/zd1211rw/zd_util.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/* zd_util.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Utility program
- */
-
-#include "zd_def.h"
-#include "zd_util.h"
-
-#ifdef DEBUG
-static char hex(u8 v)
-{
- v &= 0xf;
- return (v < 10 ? '0' : 'a' - 10) + v;
-}
-
-static char hex_print(u8 c)
-{
- return (0x20 <= c && c < 0x7f) ? c : '.';
-}
-
-static void dump_line(const u8 *bytes, size_t size)
-{
- char c;
- size_t i;
-
- size = size <= 8 ? size : 8;
- printk(KERN_DEBUG "zd1211 %p ", bytes);
- for (i = 0; i < 8; i++) {
- switch (i) {
- case 1:
- case 5:
- c = '.';
- break;
- case 3:
- c = ':';
- break;
- default:
- c = ' ';
- }
- if (i < size) {
- printk("%c%c%c", hex(bytes[i] >> 4), hex(bytes[i]), c);
- } else {
- printk(" %c", c);
- }
- }
-
- for (i = 0; i < size; i++)
- printk("%c", hex_print(bytes[i]));
- printk("\n");
-}
-
-void zd_hexdump(const void *bytes, size_t size)
-{
- size_t i = 0;
-
- do {
- dump_line((u8 *)bytes + i, size-i);
- i += 8;
- } while (i < size);
-}
-#endif /* DEBUG */
-
-void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size)
-{
- if (buffer_size < tail_size)
- return NULL;
- return (u8 *)buffer + (buffer_size - tail_size);
-}
diff --git a/drivers/net/wireless/zd1211rw/zd_util.h b/drivers/net/wireless/zd1211rw/zd_util.h
deleted file mode 100644
index ce26f7adea9..00000000000
--- a/drivers/net/wireless/zd1211rw/zd_util.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* zd_util.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _ZD_UTIL_H
-#define _ZD_UTIL_H
-
-void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size);
-
-#ifdef DEBUG
-void zd_hexdump(const void *bytes, size_t size);
-#else
-#define zd_hexdump(bytes, size)
-#endif /* DEBUG */
-
-#endif /* _ZD_UTIL_H */
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 4445810335a..2a8fc431099 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -72,24 +72,14 @@ struct netfront_info {
struct list_head list;
struct net_device *netdev;
- struct net_device_stats stats;
-
- struct xen_netif_tx_front_ring tx;
- struct xen_netif_rx_front_ring rx;
-
- spinlock_t tx_lock;
- spinlock_t rx_lock;
+ struct napi_struct napi;
unsigned int evtchn;
+ struct xenbus_device *xbdev;
- /* Receive-ring batched refills. */
-#define RX_MIN_TARGET 8
-#define RX_DFL_MIN_TARGET 64
-#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
- unsigned rx_min_target, rx_max_target, rx_target;
- struct sk_buff_head rx_batch;
-
- struct timer_list rx_refill_timer;
+ spinlock_t tx_lock;
+ struct xen_netif_tx_front_ring tx;
+ int tx_ring_ref;
/*
* {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries
@@ -108,14 +98,23 @@ struct netfront_info {
grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
unsigned tx_skb_freelist;
+ spinlock_t rx_lock ____cacheline_aligned_in_smp;
+ struct xen_netif_rx_front_ring rx;
+ int rx_ring_ref;
+
+ /* Receive-ring batched refills. */
+#define RX_MIN_TARGET 8
+#define RX_DFL_MIN_TARGET 64
+#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+ unsigned rx_min_target, rx_max_target, rx_target;
+ struct sk_buff_head rx_batch;
+
+ struct timer_list rx_refill_timer;
+
struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
grant_ref_t gref_rx_head;
grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
- struct xenbus_device *xbdev;
- int tx_ring_ref;
- int rx_ring_ref;
-
unsigned long rx_pfn_array[NET_RX_RING_SIZE];
struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
struct mmu_update rx_mmu[NET_RX_RING_SIZE];
@@ -185,7 +184,8 @@ static int xennet_can_sg(struct net_device *dev)
static void rx_refill_timeout(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
- netif_rx_schedule(dev);
+ struct netfront_info *np = netdev_priv(dev);
+ netif_rx_schedule(dev, &np->napi);
}
static int netfront_tx_slot_available(struct netfront_info *np)
@@ -212,11 +212,9 @@ static void xennet_alloc_rx_buffers(struct net_device *dev)
struct page *page;
int i, batch_target, notify;
RING_IDX req_prod = np->rx.req_prod_pvt;
- struct xen_memory_reservation reservation;
grant_ref_t ref;
unsigned long pfn;
void *vaddr;
- int nr_flips;
struct xen_netif_rx_request *req;
if (unlikely(!netif_carrier_ok(dev)))
@@ -266,7 +264,7 @@ no_skb:
np->rx_target = np->rx_max_target;
refill:
- for (nr_flips = i = 0; ; i++) {
+ for (i = 0; ; i++) {
skb = __skb_dequeue(&np->rx_batch);
if (skb == NULL)
break;
@@ -295,38 +293,7 @@ no_skb:
req->gref = ref;
}
- if (nr_flips != 0) {
- reservation.extent_start = np->rx_pfn_array;
- reservation.nr_extents = nr_flips;
- reservation.extent_order = 0;
- reservation.address_bits = 0;
- reservation.domid = DOMID_SELF;
-
- if (!xen_feature(XENFEAT_auto_translated_physmap)) {
- /* After all PTEs have been zapped, flush the TLB. */
- np->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] =
- UVMF_TLB_FLUSH|UVMF_ALL;
-
- /* Give away a batch of pages. */
- np->rx_mcl[i].op = __HYPERVISOR_memory_op;
- np->rx_mcl[i].args[0] = XENMEM_decrease_reservation;
- np->rx_mcl[i].args[1] = (unsigned long)&reservation;
-
- /* Zap PTEs and give away pages in one big
- * multicall. */
- (void)HYPERVISOR_multicall(np->rx_mcl, i+1);
-
- /* Check return status of HYPERVISOR_memory_op(). */
- if (unlikely(np->rx_mcl[i].result != i))
- panic("Unable to reduce memory reservation\n");
- } else {
- if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
- &reservation) != i)
- panic("Unable to reduce memory reservation\n");
- }
- } else {
- wmb(); /* barrier so backend seens requests */
- }
+ wmb(); /* barrier so backend seens requests */
/* Above is a suitable barrier to ensure backend will see requests. */
np->rx.req_prod_pvt = req_prod + i;
@@ -340,14 +307,14 @@ static int xennet_open(struct net_device *dev)
{
struct netfront_info *np = netdev_priv(dev);
- memset(&np->stats, 0, sizeof(np->stats));
+ napi_enable(&np->napi);
spin_lock_bh(&np->rx_lock);
if (netif_carrier_ok(dev)) {
xennet_alloc_rx_buffers(dev);
np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &np->napi);
}
spin_unlock_bh(&np->rx_lock);
@@ -566,8 +533,8 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (notify)
notify_remote_via_irq(np->netdev->irq);
- np->stats.tx_bytes += skb->len;
- np->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
/* Note: It is not safe to access skb after xennet_tx_buf_gc()! */
xennet_tx_buf_gc(dev);
@@ -580,7 +547,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
drop:
- np->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
dev_kfree_skb(skb);
return 0;
}
@@ -589,15 +556,10 @@ static int xennet_close(struct net_device *dev)
{
struct netfront_info *np = netdev_priv(dev);
netif_stop_queue(np->netdev);
+ napi_disable(&np->napi);
return 0;
}
-static struct net_device_stats *xennet_get_stats(struct net_device *dev)
-{
- struct netfront_info *np = netdev_priv(dev);
- return &np->stats;
-}
-
static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb,
grant_ref_t ref)
{
@@ -832,9 +794,8 @@ out:
}
static int handle_incoming_queue(struct net_device *dev,
- struct sk_buff_head *rxq)
+ struct sk_buff_head *rxq)
{
- struct netfront_info *np = netdev_priv(dev);
int packets_dropped = 0;
struct sk_buff *skb;
@@ -856,13 +817,13 @@ static int handle_incoming_queue(struct net_device *dev,
if (skb_checksum_setup(skb)) {
kfree_skb(skb);
packets_dropped++;
- np->stats.rx_errors++;
+ dev->stats.rx_errors++;
continue;
}
}
- np->stats.rx_packets++;
- np->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
/* Pass it up. */
netif_receive_skb(skb);
@@ -872,15 +833,16 @@ static int handle_incoming_queue(struct net_device *dev,
return packets_dropped;
}
-static int xennet_poll(struct net_device *dev, int *pbudget)
+static int xennet_poll(struct napi_struct *napi, int budget)
{
- struct netfront_info *np = netdev_priv(dev);
+ struct netfront_info *np = container_of(napi, struct netfront_info, napi);
+ struct net_device *dev = np->netdev;
struct sk_buff *skb;
struct netfront_rx_info rinfo;
struct xen_netif_rx_response *rx = &rinfo.rx;
struct xen_netif_extra_info *extras = rinfo.extras;
RING_IDX i, rp;
- int work_done, budget, more_to_do = 1;
+ int work_done;
struct sk_buff_head rxq;
struct sk_buff_head errq;
struct sk_buff_head tmpq;
@@ -899,9 +861,6 @@ static int xennet_poll(struct net_device *dev, int *pbudget)
skb_queue_head_init(&errq);
skb_queue_head_init(&tmpq);
- budget = *pbudget;
- if (budget > dev->quota)
- budget = dev->quota;
rp = np->rx.sring->rsp_prod;
rmb(); /* Ensure we see queued responses up to 'rp'. */
@@ -917,7 +876,7 @@ static int xennet_poll(struct net_device *dev, int *pbudget)
err:
while ((skb = __skb_dequeue(&tmpq)))
__skb_queue_tail(&errq, skb);
- np->stats.rx_errors++;
+ dev->stats.rx_errors++;
i = np->rx.rsp_cons;
continue;
}
@@ -1006,22 +965,21 @@ err:
xennet_alloc_rx_buffers(dev);
- *pbudget -= work_done;
- dev->quota -= work_done;
-
if (work_done < budget) {
+ int more_to_do = 0;
+
local_irq_save(flags);
RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do);
if (!more_to_do)
- __netif_rx_complete(dev);
+ __netif_rx_complete(dev, napi);
local_irq_restore(flags);
}
spin_unlock(&np->rx_lock);
- return more_to_do;
+ return work_done;
}
static int xennet_change_mtu(struct net_device *dev, int mtu)
@@ -1200,15 +1158,12 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev
netdev->open = xennet_open;
netdev->hard_start_xmit = xennet_start_xmit;
netdev->stop = xennet_close;
- netdev->get_stats = xennet_get_stats;
- netdev->poll = xennet_poll;
+ netif_napi_add(netdev, &np->napi, xennet_poll, 64);
netdev->uninit = xennet_uninit;
netdev->change_mtu = xennet_change_mtu;
- netdev->weight = 64;
netdev->features = NETIF_F_IP_CSUM;
SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
- SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &dev->dev);
np->netdev = netdev;
@@ -1349,7 +1304,7 @@ static irqreturn_t xennet_interrupt(int irq, void *dev_id)
xennet_tx_buf_gc(dev);
/* Under tx_lock: protects access to rx shared-ring indexes. */
if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
- netif_rx_schedule(dev);
+ netif_rx_schedule(dev, &np->napi);
}
spin_unlock_irqrestore(&np->tx_lock, flags);
@@ -1571,7 +1526,7 @@ static int xennet_connect(struct net_device *dev)
if (!feature_rx_copy) {
dev_info(&dev->dev,
- "backend does not support copying recieve path");
+ "backend does not support copying receive path\n");
return -ENODEV;
}
@@ -1661,11 +1616,8 @@ static void backend_changed(struct xenbus_device *dev,
static struct ethtool_ops xennet_ethtool_ops =
{
- .get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
.set_sg = xennet_set_sg,
- .get_tso = ethtool_op_get_tso,
.set_tso = xennet_set_tso,
.get_link = ethtool_op_get_link,
};
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 870c5393c21..87f002ade53 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -318,7 +318,6 @@ struct yellowfin_private {
dma_addr_t tx_status_dma;
struct timer_list timer; /* Media selection timer. */
- struct net_device_stats stats;
/* Frequently used and paired value: keep adjacent for cache effect. */
int chip_id, drv_flags;
struct pci_dev *pci_dev;
@@ -353,7 +352,6 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance);
static int yellowfin_rx(struct net_device *dev);
static void yellowfin_error(struct net_device *dev, int intr_status);
static int yellowfin_close(struct net_device *dev);
-static struct net_device_stats *yellowfin_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static const struct ethtool_ops ethtool_ops;
@@ -376,6 +374,7 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
#else
int bar = 1;
#endif
+ DECLARE_MAC_BUF(mac);
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -392,7 +391,6 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
printk (KERN_ERR PFX "cannot allocate ethernet device\n");
return -ENOMEM;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
np = netdev_priv(dev);
@@ -470,7 +468,6 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
dev->open = &yellowfin_open;
dev->hard_start_xmit = &yellowfin_start_xmit;
dev->stop = &yellowfin_close;
- dev->get_stats = &yellowfin_get_stats;
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &netdev_ioctl;
SET_ETHTOOL_OPS(dev, &ethtool_ops);
@@ -484,12 +481,10 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
if (i)
goto err_out_unmap_status;
- printk(KERN_INFO "%s: %s type %8x at %p, ",
+ printk(KERN_INFO "%s: %s type %8x at %p, %s, IRQ %d.\n",
dev->name, pci_id_tbl[chip_idx].name,
- ioread32(ioaddr + ChipRev), ioaddr);
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i]);
- printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+ ioread32(ioaddr + ChipRev), ioaddr,
+ print_mac(mac, dev->dev_addr), irq);
if (np->drv_flags & HasMII) {
int phy, phy_idx = 0;
@@ -718,7 +713,7 @@ static void yellowfin_tx_timeout(struct net_device *dev)
netif_wake_queue (dev); /* Typical path */
dev->trans_start = jiffies;
- yp->stats.tx_errors++;
+ dev->stats.tx_errors++;
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
@@ -924,8 +919,8 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
if (yp->tx_ring[entry].result_status == 0)
break;
skb = yp->tx_skbuff[entry];
- yp->stats.tx_packets++;
- yp->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
/* Free the original skb. */
pci_unmap_single(yp->pci_dev, yp->tx_ring[entry].addr,
skb->len, PCI_DMA_TODEVICE);
@@ -969,20 +964,20 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n",
dev->name, tx_errs);
#endif
- yp->stats.tx_errors++;
- if (tx_errs & 0xF800) yp->stats.tx_aborted_errors++;
- if (tx_errs & 0x0800) yp->stats.tx_carrier_errors++;
- if (tx_errs & 0x2000) yp->stats.tx_window_errors++;
- if (tx_errs & 0x8000) yp->stats.tx_fifo_errors++;
+ dev->stats.tx_errors++;
+ if (tx_errs & 0xF800) dev->stats.tx_aborted_errors++;
+ if (tx_errs & 0x0800) dev->stats.tx_carrier_errors++;
+ if (tx_errs & 0x2000) dev->stats.tx_window_errors++;
+ if (tx_errs & 0x8000) dev->stats.tx_fifo_errors++;
} else {
#ifndef final_version
if (yellowfin_debug > 4)
printk(KERN_DEBUG "%s: Normal transmit, Tx status %4.4x.\n",
dev->name, tx_errs);
#endif
- yp->stats.tx_bytes += skb->len;
- yp->stats.collisions += tx_errs & 15;
- yp->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.collisions += tx_errs & 15;
+ dev->stats.tx_packets++;
}
/* Free the original skb. */
pci_unmap_single(yp->pci_dev,
@@ -1077,26 +1072,26 @@ static int yellowfin_rx(struct net_device *dev)
if (data_size != 0)
printk(KERN_WARNING "%s: Oversized Ethernet frame spanned multiple buffers,"
" status %4.4x, data_size %d!\n", dev->name, desc_status, data_size);
- yp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} else if ((yp->drv_flags & IsGigabit) && (frame_status & 0x0038)) {
/* There was a error. */
if (yellowfin_debug > 3)
printk(KERN_DEBUG " yellowfin_rx() Rx error was %4.4x.\n",
frame_status);
- yp->stats.rx_errors++;
- if (frame_status & 0x0060) yp->stats.rx_length_errors++;
- if (frame_status & 0x0008) yp->stats.rx_frame_errors++;
- if (frame_status & 0x0010) yp->stats.rx_crc_errors++;
- if (frame_status < 0) yp->stats.rx_dropped++;
+ dev->stats.rx_errors++;
+ if (frame_status & 0x0060) dev->stats.rx_length_errors++;
+ if (frame_status & 0x0008) dev->stats.rx_frame_errors++;
+ if (frame_status & 0x0010) dev->stats.rx_crc_errors++;
+ if (frame_status < 0) dev->stats.rx_dropped++;
} else if ( !(yp->drv_flags & IsGigabit) &&
((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) {
u8 status1 = buf_addr[data_size-2];
u8 status2 = buf_addr[data_size-1];
- yp->stats.rx_errors++;
- if (status1 & 0xC0) yp->stats.rx_length_errors++;
- if (status2 & 0x03) yp->stats.rx_frame_errors++;
- if (status2 & 0x04) yp->stats.rx_crc_errors++;
- if (status2 & 0x80) yp->stats.rx_dropped++;
+ dev->stats.rx_errors++;
+ if (status1 & 0xC0) dev->stats.rx_length_errors++;
+ if (status2 & 0x03) dev->stats.rx_frame_errors++;
+ if (status2 & 0x04) dev->stats.rx_crc_errors++;
+ if (status2 & 0x80) dev->stats.rx_dropped++;
#ifdef YF_PROTOTYPE /* Support for prototype hardware errata. */
} else if ((yp->flags & HasMACAddrBug) &&
memcmp(le32_to_cpu(yp->rx_ring_dma +
@@ -1105,11 +1100,11 @@ static int yellowfin_rx(struct net_device *dev)
memcmp(le32_to_cpu(yp->rx_ring_dma +
entry*sizeof(struct yellowfin_desc)),
"\377\377\377\377\377\377", 6) != 0) {
- if (bogus_rx++ == 0)
- printk(KERN_WARNING "%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:"
- "%2.2x:%2.2x.\n",
- dev->name, buf_addr[0], buf_addr[1], buf_addr[2],
- buf_addr[3], buf_addr[4], buf_addr[5]);
+ if (bogus_rx++ == 0) {
+ DECLARE_MAC_BUF(mac);
+ printk(KERN_WARNING "%s: Bad frame to %s\n",
+ dev->name, print_mac(mac, buf_addr));
+ }
#endif
} else {
struct sk_buff *skb;
@@ -1146,8 +1141,8 @@ static int yellowfin_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- yp->stats.rx_packets++;
- yp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
entry = (++yp->cur_rx) % RX_RING_SIZE;
}
@@ -1181,15 +1176,13 @@ static int yellowfin_rx(struct net_device *dev)
static void yellowfin_error(struct net_device *dev, int intr_status)
{
- struct yellowfin_private *yp = netdev_priv(dev);
-
printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
dev->name, intr_status);
/* Hmmmmm, it's not clear what to do here. */
if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))
- yp->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))
- yp->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
static int yellowfin_close(struct net_device *dev)
@@ -1281,12 +1274,6 @@ static int yellowfin_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *yellowfin_get_stats(struct net_device *dev)
-{
- struct yellowfin_private *yp = netdev_priv(dev);
- return &yp->stats;
-}
-
/* Set or clear the multicast filter for this adaptor. */
static void set_rx_mode(struct net_device *dev)
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index 4032e9f6f9b..a86c022d6a9 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -128,7 +128,6 @@ MODULE_LICENSE("GPL");
struct znet_private {
int rx_dma, tx_dma;
- struct net_device_stats stats;
spinlock_t lock;
short sia_base, sia_size, io_size;
struct i82593_conf_block i593_init;
@@ -161,7 +160,6 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t znet_interrupt(int irq, void *dev_id);
static void znet_rx(struct net_device *dev);
static int znet_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
static void hardware_init(struct net_device *dev);
static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
static void znet_tx_timeout (struct net_device *dev);
@@ -372,6 +370,7 @@ static int __init znet_probe (void)
struct net_device *dev;
char *p;
int err = -ENOMEM;
+ DECLARE_MAC_BUF(mac);
/* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++)
@@ -388,22 +387,20 @@ static int __init znet_probe (void)
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER (dev);
-
znet = dev->priv;
netinfo = (struct netidblk *)p;
dev->base_addr = netinfo->iobase1;
dev->irq = netinfo->irq1;
- printk(KERN_INFO "%s: ZNET at %#3lx,", dev->name, dev->base_addr);
-
/* The station address is in the "netidblk" at 0x0f0000. */
for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i] = netinfo->netid[i]);
+ dev->dev_addr[i] = netinfo->netid[i];
- printk(", using IRQ %d DMA %d and %d.\n", dev->irq, netinfo->dma1,
- netinfo->dma2);
+ printk(KERN_INFO "%s: ZNET at %#3lx, %s"
+ ", using IRQ %d DMA %d and %d.\n",
+ dev->name, dev->base_addr, print_mac(mac, dev->dev_addr),
+ dev->irq, netinfo->dma1, netinfo->dma2);
if (znet_debug > 1) {
printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n",
@@ -447,7 +444,6 @@ static int __init znet_probe (void)
dev->open = &znet_open;
dev->hard_start_xmit = &znet_send_packet;
dev->stop = &znet_close;
- dev->get_stats = net_get_stats;
dev->set_multicast_list = &znet_set_multicast_list;
dev->tx_timeout = znet_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
@@ -566,7 +562,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
ushort *tx_link = znet->tx_cur - 1;
ushort rnd_len = (length + 1)>>1;
- znet->stats.tx_bytes+=length;
+ dev->stats.tx_bytes+=length;
if (znet->tx_cur >= znet->tx_end)
znet->tx_cur = znet->tx_start;
@@ -641,20 +637,20 @@ static irqreturn_t znet_interrupt(int irq, void *dev_id)
tx_status = inw(ioaddr);
/* It's undocumented, but tx_status seems to match the i82586. */
if (tx_status & TX_OK) {
- znet->stats.tx_packets++;
- znet->stats.collisions += tx_status & TX_NCOL_MASK;
+ dev->stats.tx_packets++;
+ dev->stats.collisions += tx_status & TX_NCOL_MASK;
} else {
if (tx_status & (TX_LOST_CTS | TX_LOST_CRS))
- znet->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (tx_status & TX_UND_RUN)
- znet->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (!(tx_status & TX_HRT_BEAT))
- znet->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
if (tx_status & TX_MAX_COL)
- znet->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
/* ...and the catch-all. */
if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL))
- znet->stats.tx_errors++;
+ dev->stats.tx_errors++;
/* Transceiver may be stuck if cable
* was removed while emiting a
@@ -750,19 +746,19 @@ static void znet_rx(struct net_device *dev)
this_rfp_ptr[-3]<<1);
/* Once again we must assume that the i82586 docs apply. */
if ( ! (status & RX_RCV_OK)) { /* There was an error. */
- znet->stats.rx_errors++;
- if (status & RX_CRC_ERR) znet->stats.rx_crc_errors++;
- if (status & RX_ALG_ERR) znet->stats.rx_frame_errors++;
+ dev->stats.rx_errors++;
+ if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++;
+ if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++;
#if 0
- if (status & 0x0200) znet->stats.rx_over_errors++; /* Wrong. */
- if (status & 0x0100) znet->stats.rx_fifo_errors++;
+ if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */
+ if (status & 0x0100) dev->stats.rx_fifo_errors++;
#else
/* maz : Wild guess... */
- if (status & RX_OVRRUN) znet->stats.rx_over_errors++;
+ if (status & RX_OVRRUN) dev->stats.rx_over_errors++;
#endif
- if (status & RX_SRT_FRM) znet->stats.rx_length_errors++;
+ if (status & RX_SRT_FRM) dev->stats.rx_length_errors++;
} else if (pkt_len > 1536) {
- znet->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} else {
/* Malloc up new buffer. */
struct sk_buff *skb;
@@ -771,7 +767,7 @@ static void znet_rx(struct net_device *dev)
if (skb == NULL) {
if (znet_debug)
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- znet->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
break;
}
@@ -791,8 +787,8 @@ static void znet_rx(struct net_device *dev)
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- znet->stats.rx_packets++;
- znet->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
}
znet->rx_cur = this_rfp_ptr;
if (znet->rx_cur >= znet->rx_end)
@@ -829,15 +825,6 @@ static int znet_close(struct net_device *dev)
return 0;
}
-/* Get the current statistics. This may be called with the card open or
- closed. */
-static struct net_device_stats *net_get_stats(struct net_device *dev)
-{
- struct znet_private *znet = dev->priv;
-
- return &znet->stats;
-}
-
static void show_dma(struct net_device *dev)
{
short ioaddr = dev->base_addr;
diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c
index d85e2ea0b6a..3926b2aa9cc 100644
--- a/drivers/net/zorro8390.c
+++ b/drivers/net/zorro8390.c
@@ -125,7 +125,6 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z,
dev = ____alloc_ei_netdev(0);
if (!dev)
return -ENOMEM;
- SET_MODULE_OWNER(dev);
if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, DRV_NAME)) {
free_netdev(dev);
return -EBUSY;
@@ -152,6 +151,7 @@ static int __devinit zorro8390_init(struct net_device *dev,
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
};
+ DECLARE_MAC_BUF(mac);
/* Reset card. Who knows what dain-bramaged state it was left in. */
{
@@ -191,7 +191,7 @@ static int __devinit zorro8390_init(struct net_device *dev,
{0x00, NE_EN0_RSARHI},
{E8390_RREAD+E8390_START, NE_CMD},
};
- for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(program_seq); i++) {
z_writeb(program_seq[i].value, ioaddr + program_seq[i].offset);
}
}
@@ -212,12 +212,12 @@ static int __devinit zorro8390_init(struct net_device *dev,
i = request_irq(IRQ_AMIGA_PORTS, __ei_interrupt, IRQF_SHARED, DRV_NAME, dev);
if (i) return i;
- for(i = 0; i < ETHER_ADDR_LEN; i++) {
+ for(i = 0; i < ETHER_ADDR_LEN; i++)
+ dev->dev_addr[i] = SA_prom[i];
+
#ifdef DEBUG
- printk(" %2.2x", SA_prom[i]);
+ printk("%s", print_mac(mac, dev->dev_addr));
#endif
- dev->dev_addr[i] = SA_prom[i];
- }
ei_status.name = name;
ei_status.tx_start_page = start_page;
@@ -244,10 +244,8 @@ static int __devinit zorro8390_init(struct net_device *dev,
return err;
}
- printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address "
- "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, name, board,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address %s\n",
+ dev->name, name, board, print_mac(mac, dev->dev_addr));
return 0;
}
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 864f09fd9f8..b47bb2d7476 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -12,6 +12,7 @@
*
*/
#include <linux/errno.h>
+#include <linux/module.h>
#include <linux/device.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
@@ -94,3 +95,23 @@ int of_bus_type_init(struct bus_type *bus, const char *name)
bus->resume = of_platform_device_resume;
return bus_register(bus);
}
+
+int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
+{
+ /* initialize common driver fields */
+ if (!drv->driver.name)
+ drv->driver.name = drv->name;
+ if (!drv->driver.owner)
+ drv->driver.owner = drv->owner;
+ drv->driver.bus = bus;
+
+ /* register with core */
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL(of_register_driver);
+
+void of_unregister_driver(struct of_platform_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(of_unregister_driver);
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index a83c3db7d18..c93d3d2640a 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -64,6 +64,8 @@ int alloc_cpu_buffers(void)
b->head_pos = 0;
b->sample_received = 0;
b->sample_lost_overflow = 0;
+ b->backtrace_aborted = 0;
+ b->sample_invalid_eip = 0;
b->cpu = i;
INIT_DELAYED_WORK(&b->work, wq_sync_buffer);
}
@@ -175,6 +177,11 @@ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc,
cpu_buf->sample_received++;
+ if (pc == ESCAPE_CODE) {
+ cpu_buf->sample_invalid_eip++;
+ return 0;
+ }
+
if (nr_available_slots(cpu_buf) < 3) {
cpu_buf->sample_lost_overflow++;
return 0;
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h
index 49900d9e323..c66c025abe7 100644
--- a/drivers/oprofile/cpu_buffer.h
+++ b/drivers/oprofile/cpu_buffer.h
@@ -42,6 +42,7 @@ struct oprofile_cpu_buffer {
unsigned long sample_received;
unsigned long sample_lost_overflow;
unsigned long backtrace_aborted;
+ unsigned long sample_invalid_eip;
int cpu;
struct delayed_work work;
} ____cacheline_aligned;
diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c
index f0acb661c25..d1f6d776e9e 100644
--- a/drivers/oprofile/oprofile_stats.c
+++ b/drivers/oprofile/oprofile_stats.c
@@ -26,6 +26,8 @@ void oprofile_reset_stats(void)
cpu_buf = &cpu_buffer[i];
cpu_buf->sample_received = 0;
cpu_buf->sample_lost_overflow = 0;
+ cpu_buf->backtrace_aborted = 0;
+ cpu_buf->sample_invalid_eip = 0;
}
atomic_set(&oprofile_stats.sample_lost_no_mm, 0);
@@ -61,6 +63,8 @@ void oprofile_create_stats_files(struct super_block * sb, struct dentry * root)
&cpu_buf->sample_lost_overflow);
oprofilefs_create_ro_ulong(sb, cpudir, "backtrace_aborted",
&cpu_buf->backtrace_aborted);
+ oprofilefs_create_ro_ulong(sb, cpudir, "sample_invalid_eip",
+ &cpu_buf->sample_invalid_eip);
}
oprofilefs_create_ro_atomic(sb, dir, "sample_lost_no_mm",
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index b3c4dbff26b..7c60cbd85dc 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -42,6 +42,7 @@
#include <linux/reboot.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/scatterlist.h>
#include <asm/byteorder.h>
#include <asm/cache.h> /* for L1_CACHE_BYTES */
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 5b86ee5c1ee..5eace9e66e1 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -557,44 +557,6 @@ lba_bios_init(void)
#ifdef CONFIG_64BIT
/*
-** Determine if a device is already configured.
-** If so, reserve it resources.
-**
-** Read PCI cfg command register and see if I/O or MMIO is enabled.
-** PAT has to enable the devices it's using.
-**
-** Note: resources are fixed up before we try to claim them.
-*/
-static void
-lba_claim_dev_resources(struct pci_dev *dev)
-{
- u16 cmd;
- int i, srch_flags;
-
- (void) pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
- srch_flags = (cmd & PCI_COMMAND_IO) ? IORESOURCE_IO : 0;
- if (cmd & PCI_COMMAND_MEMORY)
- srch_flags |= IORESOURCE_MEM;
-
- if (!srch_flags)
- return;
-
- for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
- if (dev->resource[i].flags & srch_flags) {
- pci_claim_resource(dev, i);
- DBG(" claimed %s %d [%lx,%lx]/%lx\n",
- pci_name(dev), i,
- dev->resource[i].start,
- dev->resource[i].end,
- dev->resource[i].flags
- );
- }
- }
-}
-
-
-/*
* truncate_pat_collision: Deal with overlaps or outright collisions
* between PAT PDC reported ranges.
*
@@ -653,7 +615,6 @@ truncate_pat_collision(struct resource *root, struct resource *new)
}
#else
-#define lba_claim_dev_resources(dev) do { } while (0)
#define truncate_pat_collision(r,n) (0)
#endif
@@ -684,8 +645,12 @@ lba_fixup_bus(struct pci_bus *bus)
** pci_alloc_primary_bus() mangles this.
*/
if (bus->self) {
+ int i;
/* PCI-PCI Bridge */
pci_read_bridge_bases(bus);
+ for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
+ pci_claim_resource(bus->self, i);
+ }
} else {
/* Host-PCI Bridge */
int err, i;
@@ -803,6 +768,9 @@ lba_fixup_bus(struct pci_bus *bus)
DBG("lba_fixup_bus() WTF? 0x%lx [%lx/%lx] XXX",
res->flags, res->start, res->end);
}
+ if ((i != PCI_ROM_RESOURCE) ||
+ (res->flags & IORESOURCE_ROM_ENABLE))
+ pci_claim_resource(dev, i);
}
#ifdef FBB_SUPPORT
@@ -814,11 +782,6 @@ lba_fixup_bus(struct pci_bus *bus)
bus->bridge_ctl &= ~(status & PCI_STATUS_FAST_BACK);
#endif
- if (is_pdc_pat()) {
- /* Claim resources for PDC's devices */
- lba_claim_dev_resources(dev);
- }
-
/*
** P2PB's have no IRQs. ignore them.
*/
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index e5d7ed92d6f..a6d6b2488ff 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -359,7 +359,7 @@ static __inline__ int led_get_net_activity(void)
* for reading should be OK */
read_lock(&dev_base_lock);
rcu_read_lock();
- for_each_netdev(dev) {
+ for_each_netdev(&init_net, dev) {
struct net_device_stats *stats;
struct in_device *in_dev = __in_dev_get_rcu(dev);
if (!in_dev || !in_dev->ifa_list)
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index fc4bde259dc..ebb09e98d21 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -282,6 +282,7 @@ pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t coun
unsigned short i;
char in[count+1], *temp;
struct device *dev;
+ int ret;
if (!entry || !buf || !count)
return -EINVAL;
@@ -333,7 +334,9 @@ pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t coun
/* Update the symlink to the real device */
sysfs_remove_link(&entry->kobj, "device");
- sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
+ ret = sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
+ WARN_ON(ret);
+
write_unlock(&entry->rw_lock);
printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" path to \"%s\"\n",
@@ -1003,8 +1006,10 @@ pdcs_register_pathentries(void)
entry->ready = 2;
/* Add a nice symlink to the real device */
- if (entry->dev)
- sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
+ if (entry->dev) {
+ err = sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
+ WARN_ON(err);
+ }
write_unlock(&entry->rw_lock);
}
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index d044c48323e..e527a0e1d6c 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -28,6 +28,7 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/pci.h>
+#include <linux/scatterlist.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -1909,8 +1910,8 @@ sba_driver_callback(struct parisc_device *dev)
global_ioc_cnt *= 2;
}
- printk(KERN_INFO "%s found %s at 0x%lx\n",
- MODULE_NAME, version, dev->hpa.start);
+ printk(KERN_INFO "%s found %s at 0x%llx\n",
+ MODULE_NAME, version, (unsigned long long)dev->hpa.start);
sba_dev = kzalloc(sizeof(struct sba_device), GFP_KERNEL);
if (!sba_dev) {
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index 38cdf9fa36a..1e8d2d17f04 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -155,6 +155,7 @@ superio_init(struct pci_dev *pcidev)
struct superio_device *sio = &sio_dev;
struct pci_dev *pdev = sio->lio_pdev;
u16 word;
+ int ret;
if (sio->suckyio_irq_enabled)
return;
@@ -200,7 +201,8 @@ superio_init(struct pci_dev *pcidev)
pci_write_config_word (pdev, PCI_COMMAND, word);
pci_set_master (pdev);
- pci_enable_device(pdev);
+ ret = pci_enable_device(pdev);
+ BUG_ON(ret < 0); /* not too much we can do about this... */
/*
* Next project is programming the onboard interrupt controllers.
diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c
index ff9f3445353..3c8f06c3a5a 100644
--- a/drivers/parport/daisy.c
+++ b/drivers/parport/daisy.c
@@ -199,11 +199,6 @@ void parport_daisy_fini(struct parport *port)
* parport_open - find a device by canonical device number
* @devnum: canonical device number
* @name: name to associate with the device
- * @pf: preemption callback
- * @kf: kick callback
- * @irqf: interrupt handler
- * @flags: registration flags
- * @handle: driver data
*
* This function is similar to parport_register_device(), except
* that it locates a device by its number rather than by the port
@@ -214,10 +209,7 @@ void parport_daisy_fini(struct parport *port)
* for parport_register_device().
**/
-struct pardevice *parport_open(int devnum, const char *name,
- int (*pf) (void *), void (*kf) (void *),
- void (*irqf) (int, void *),
- int flags, void *handle)
+struct pardevice *parport_open(int devnum, const char *name)
{
struct daisydev *p = topology;
struct parport *port;
@@ -237,8 +229,7 @@ struct pardevice *parport_open(int devnum, const char *name,
port = parport_get_port(p->port);
spin_unlock(&topology_lock);
- dev = parport_register_device(port, name, pf, kf,
- irqf, flags, handle);
+ dev = parport_register_device(port, name, NULL, NULL, NULL, 0, NULL);
parport_put_port(port);
if (!dev)
return NULL;
@@ -275,35 +266,6 @@ void parport_close(struct pardevice *dev)
parport_unregister_device(dev);
}
-/**
- * parport_device_num - convert device coordinates
- * @parport: parallel port number
- * @mux: multiplexor port number (-1 for no multiplexor)
- * @daisy: daisy chain address (-1 for no daisy chain address)
- *
- * This tries to locate a device on the given parallel port,
- * multiplexor port and daisy chain address, and returns its
- * device number or %-ENXIO if no device with those coordinates
- * exists.
- **/
-
-int parport_device_num(int parport, int mux, int daisy)
-{
- int res = -ENXIO;
- struct daisydev *dev;
-
- spin_lock(&topology_lock);
- dev = topology;
- while (dev && dev->port->portnum != parport &&
- dev->port->muxport != mux && dev->daisy != daisy)
- dev = dev->next;
- if (dev)
- res = dev->devnum;
- spin_unlock(&topology_lock);
-
- return res;
-}
-
/* Send a daisy-chain-style CPP command packet. */
static int cpp_daisy(struct parport *port, int cmd)
{
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
index 5accaa7bde3..54a6ef72906 100644
--- a/drivers/parport/ieee1284.c
+++ b/drivers/parport/ieee1284.c
@@ -571,7 +571,7 @@ static int parport_ieee1284_ack_data_avail (struct parport *port)
#endif /* IEEE1284 support */
/* Handle an interrupt. */
-void parport_ieee1284_interrupt (int which, void *handle)
+void parport_ieee1284_interrupt (void *handle)
{
struct parport *port = handle;
parport_ieee1284_wakeup (port);
diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c
index a0afaee5ebe..1586e1caa2f 100644
--- a/drivers/parport/parport_amiga.c
+++ b/drivers/parport/parport_amiga.c
@@ -137,13 +137,6 @@ static unsigned char amiga_read_status(struct parport *p)
return status;
}
-/* as this ports irq handling is already done, we use a generic funktion */
-static irqreturn_t amiga_interrupt(int irq, void *dev_id)
-{
- parport_generic_irq(irq, (struct parport *) dev_id);
- return IRQ_HANDLED;
-}
-
static void amiga_enable_irq(struct parport *p)
{
enable_irq(IRQ_AMIGA_CIAA_FLG);
@@ -255,7 +248,7 @@ static int __init parport_amiga_init(void)
if (!p)
goto out_port;
- err = request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0, p->name, p);
+ err = request_irq(IRQ_AMIGA_CIAA_FLG, parport_irq_handler, 0, p->name, p);
if (err)
goto out_irq;
diff --git a/drivers/parport/parport_atari.c b/drivers/parport/parport_atari.c
index 6ea9929b8c7..ad4cdd25613 100644
--- a/drivers/parport/parport_atari.c
+++ b/drivers/parport/parport_atari.c
@@ -103,13 +103,6 @@ parport_atari_restore_state(struct parport *p, struct parport_state *s)
{
}
-static irqreturn_t
-parport_atari_interrupt(int irq, void *dev_id)
-{
- parport_generic_irq(irq, (struct parport *) dev_id);
- return IRQ_HANDLED;
-}
-
static void
parport_atari_enable_irq(struct parport *p)
{
@@ -208,7 +201,7 @@ static int __init parport_atari_init(void)
&parport_atari_ops);
if (!p)
return -ENODEV;
- if (request_irq(IRQ_MFP_BUSY, parport_atari_interrupt,
+ if (request_irq(IRQ_MFP_BUSY, parport_irq_handler,
IRQ_TYPE_SLOW, p->name, p)) {
parport_put_port (p);
return -ENODEV;
diff --git a/drivers/parport/parport_ax88796.c b/drivers/parport/parport_ax88796.c
index 74f4e9742c6..4ec220b2eae 100644
--- a/drivers/parport/parport_ax88796.c
+++ b/drivers/parport/parport_ax88796.c
@@ -232,14 +232,6 @@ parport_ax88796_restore_state(struct parport *p, struct parport_state *s)
writeb(s->u.ax88796.cpr, dd->spp_cpr);
}
-static irqreturn_t
-parport_ax88796_interrupt(int irq, void *dev_id)
-{
- parport_generic_irq(irq, dev_id);
- return IRQ_HANDLED;
-}
-
-
static struct parport_operations parport_ax88796_ops = {
.write_data = parport_ax88796_write_data,
.read_data = parport_ax88796_read_data,
@@ -344,7 +336,7 @@ static int parport_ax88796_probe(struct platform_device *pdev)
if (irq >= 0) {
/* request irq */
- ret = request_irq(irq, parport_ax88796_interrupt,
+ ret = request_irq(irq, parport_irq_handler,
IRQF_TRIGGER_FALLING, pdev->name, pp);
if (ret < 0)
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index 43652ba523e..0e77ae2b71a 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -80,12 +80,6 @@ static int clear_epp_timeout(struct parport *pb)
* of these are in parport_gsc.h.
*/
-static irqreturn_t parport_gsc_interrupt(int irq, void *dev_id)
-{
- parport_generic_irq(irq, (struct parport *) dev_id);
- return IRQ_HANDLED;
-}
-
void parport_gsc_init_state(struct pardevice *dev, struct parport_state *s)
{
s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
@@ -324,7 +318,7 @@ struct parport *__devinit parport_gsc_probe_port (unsigned long base,
printk("]\n");
if (p->irq != PARPORT_IRQ_NONE) {
- if (request_irq (p->irq, parport_gsc_interrupt,
+ if (request_irq (p->irq, parport_irq_handler,
0, p->name, p)) {
printk (KERN_WARNING "%s: irq %d in use, "
"resorting to polled operation\n",
diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c
index ec44efdbb84..6d58bf895b1 100644
--- a/drivers/parport/parport_ip32.c
+++ b/drivers/parport/parport_ip32.c
@@ -778,14 +778,16 @@ static irqreturn_t parport_ip32_interrupt(int irq, void *dev_id)
struct parport * const p = dev_id;
struct parport_ip32_private * const priv = p->physport->private_data;
enum parport_ip32_irq_mode irq_mode = priv->irq_mode;
+
switch (irq_mode) {
case PARPORT_IP32_IRQ_FWD:
- parport_generic_irq(irq, p);
- break;
+ return parport_irq_handler(irq, dev_id);
+
case PARPORT_IP32_IRQ_HERE:
parport_ip32_wakeup(p);
break;
}
+
return IRQ_HANDLED;
}
diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c
index 77726fc4976..6dec9ba5ed2 100644
--- a/drivers/parport/parport_mfc3.c
+++ b/drivers/parport/parport_mfc3.c
@@ -219,7 +219,7 @@ static irqreturn_t mfc3_interrupt(int irq, void *dev_id)
if (this_port[i] != NULL)
if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */
dummy = pia(this_port[i])->pprb; /* clear irq bit */
- parport_generic_irq(irq, this_port[i]);
+ parport_generic_irq(this_port[i]);
}
return IRQ_HANDLED;
}
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index e2be8400110..e9743d3efaf 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -272,13 +272,6 @@ static int clear_epp_timeout(struct parport *pb)
* of these are in parport_pc.h.
*/
-static irqreturn_t parport_pc_interrupt(int irq, void *dev_id)
-{
- parport_generic_irq(irq, (struct parport *) dev_id);
- /* FIXME! Was it really ours? */
- return IRQ_HANDLED;
-}
-
static void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
{
s->u.pc.ctr = 0xc;
@@ -2301,7 +2294,7 @@ struct parport *parport_pc_probe_port (unsigned long int base,
EPP_res = NULL;
}
if (p->irq != PARPORT_IRQ_NONE) {
- if (request_irq (p->irq, parport_pc_interrupt,
+ if (request_irq (p->irq, parport_irq_handler,
0, p->name, p)) {
printk (KERN_WARNING "%s: irq %d in use, "
"resorting to polled operation\n",
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index d27019c2f86..9d595aa91e4 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -46,12 +46,6 @@
#define dprintk(x)
#endif
-static irqreturn_t parport_sunbpp_interrupt(int irq, void *dev_id)
-{
- parport_generic_irq(irq, (struct parport *) dev_id);
- return IRQ_HANDLED;
-}
-
static void parport_sunbpp_disable_irq(struct parport *p)
{
struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
@@ -324,7 +318,7 @@ static int __devinit init_one_port(struct sbus_dev *sdev)
p->size = size;
p->dev = &sdev->ofdev.dev;
- if ((err = request_irq(p->irq, parport_sunbpp_interrupt,
+ if ((err = request_irq(p->irq, parport_irq_handler,
IRQF_SHARED, p->name, p)) != 0) {
goto out_put_port;
}
diff --git a/drivers/parport/probe.c b/drivers/parport/probe.c
index ea83b70e0de..853a15f44f8 100644
--- a/drivers/parport/probe.c
+++ b/drivers/parport/probe.c
@@ -255,8 +255,7 @@ static ssize_t parport_read_device_id (struct parport *port, char *buffer,
ssize_t parport_device_id (int devnum, char *buffer, size_t count)
{
ssize_t retval = -ENXIO;
- struct pardevice *dev = parport_open (devnum, "Device ID probe",
- NULL, NULL, NULL, 0, NULL);
+ struct pardevice *dev = parport_open (devnum, "Device ID probe");
if (!dev)
return -ENXIO;
diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c
index bdbdab9285c..ed82e41210d 100644
--- a/drivers/parport/procfs.c
+++ b/drivers/parport/procfs.c
@@ -237,7 +237,7 @@ static int do_hardware_modes (ctl_table *table, int write,
#define PARPORT_PARPORT_DIR(CHILD) { .ctl_name = DEV_PARPORT, .procname = "parport", \
.mode = 0555, .child = CHILD }
#define PARPORT_DEV_DIR(CHILD) { .ctl_name = CTL_DEV, .procname = "dev", .mode = 0555, .child = CHILD }
-#define PARPORT_DEVICES_ROOT_DIR { .ctl_name = DEV_PARPORT_DEVICES, .procname = "devices", \
+#define PARPORT_DEVICES_ROOT_DIR { .procname = "devices", \
.mode = 0555, .child = NULL }
static const unsigned long parport_min_timeslice_value =
@@ -266,7 +266,6 @@ static const struct parport_sysctl_table parport_sysctl_template = {
.sysctl_header = NULL,
{
{
- .ctl_name = DEV_PARPORT_SPINTIME,
.procname = "spintime",
.data = NULL,
.maxlen = sizeof(int),
@@ -276,7 +275,6 @@ static const struct parport_sysctl_table parport_sysctl_template = {
.extra2 = (void*) &parport_max_spintime_value
},
{
- .ctl_name = DEV_PARPORT_BASE_ADDR,
.procname = "base-addr",
.data = NULL,
.maxlen = 0,
@@ -284,7 +282,6 @@ static const struct parport_sysctl_table parport_sysctl_template = {
.proc_handler = &do_hardware_base_addr
},
{
- .ctl_name = DEV_PARPORT_IRQ,
.procname = "irq",
.data = NULL,
.maxlen = 0,
@@ -292,7 +289,6 @@ static const struct parport_sysctl_table parport_sysctl_template = {
.proc_handler = &do_hardware_irq
},
{
- .ctl_name = DEV_PARPORT_DMA,
.procname = "dma",
.data = NULL,
.maxlen = 0,
@@ -300,7 +296,6 @@ static const struct parport_sysctl_table parport_sysctl_template = {
.proc_handler = &do_hardware_dma
},
{
- .ctl_name = DEV_PARPORT_MODES,
.procname = "modes",
.data = NULL,
.maxlen = 0,
@@ -310,7 +305,6 @@ static const struct parport_sysctl_table parport_sysctl_template = {
PARPORT_DEVICES_ROOT_DIR,
#ifdef CONFIG_PARPORT_1284
{
- .ctl_name = DEV_PARPORT_AUTOPROBE,
.procname = "autoprobe",
.data = NULL,
.maxlen = 0,
@@ -318,7 +312,6 @@ static const struct parport_sysctl_table parport_sysctl_template = {
.proc_handler = &do_autoprobe
},
{
- .ctl_name = DEV_PARPORT_AUTOPROBE + 1,
.procname = "autoprobe0",
.data = NULL,
.maxlen = 0,
@@ -326,7 +319,6 @@ static const struct parport_sysctl_table parport_sysctl_template = {
.proc_handler = &do_autoprobe
},
{
- .ctl_name = DEV_PARPORT_AUTOPROBE + 2,
.procname = "autoprobe1",
.data = NULL,
.maxlen = 0,
@@ -334,7 +326,6 @@ static const struct parport_sysctl_table parport_sysctl_template = {
.proc_handler = &do_autoprobe
},
{
- .ctl_name = DEV_PARPORT_AUTOPROBE + 3,
.procname = "autoprobe2",
.data = NULL,
.maxlen = 0,
@@ -342,7 +333,6 @@ static const struct parport_sysctl_table parport_sysctl_template = {
.proc_handler = &do_autoprobe
},
{
- .ctl_name = DEV_PARPORT_AUTOPROBE + 4,
.procname = "autoprobe3",
.data = NULL,
.maxlen = 0,
@@ -354,7 +344,6 @@ static const struct parport_sysctl_table parport_sysctl_template = {
},
{
{
- .ctl_name = DEV_PARPORT_DEVICES_ACTIVE,
.procname = "active",
.data = NULL,
.maxlen = 0,
@@ -393,7 +382,6 @@ parport_device_sysctl_template = {
.sysctl_header = NULL,
{
{
- .ctl_name = DEV_PARPORT_DEVICE_TIMESLICE,
.procname = "timeslice",
.data = NULL,
.maxlen = sizeof(int),
@@ -449,7 +437,6 @@ parport_default_sysctl_table = {
.sysctl_header = NULL,
{
{
- .ctl_name = DEV_PARPORT_DEFAULT_TIMESLICE,
.procname = "timeslice",
.data = &parport_default_timeslice,
.maxlen = sizeof(parport_default_timeslice),
@@ -459,7 +446,6 @@ parport_default_sysctl_table = {
.extra2 = (void*) &parport_max_timeslice_value
},
{
- .ctl_name = DEV_PARPORT_DEFAULT_SPINTIME,
.procname = "spintime",
.data = &parport_default_spintime,
.maxlen = sizeof(parport_default_spintime),
@@ -502,7 +488,7 @@ int parport_proc_register(struct parport *port)
t->device_dir[0].extra1 = port;
- for (i = 0; i < 8; i++)
+ for (i = 0; i < 5; i++)
t->vars[i].extra1 = port;
t->vars[0].data = &port->spintime;
@@ -512,7 +498,7 @@ int parport_proc_register(struct parport *port)
t->vars[6 + i].extra2 = &port->probe_info[i];
t->port_dir[0].procname = port->name;
- t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
+ t->port_dir[0].ctl_name = 0;
t->port_dir[0].child = t->vars;
t->parport_dir[0].child = t->port_dir;
@@ -551,26 +537,12 @@ int parport_device_proc_register(struct pardevice *device)
t->dev_dir[0].child = t->parport_dir;
t->parport_dir[0].child = t->port_dir;
t->port_dir[0].procname = port->name;
- t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
+ t->port_dir[0].ctl_name = 0;
t->port_dir[0].child = t->devices_root_dir;
t->devices_root_dir[0].child = t->device_dir;
-#ifdef CONFIG_PARPORT_1284
-
- t->device_dir[0].ctl_name =
- parport_device_num(port->number, port->muxport,
- device->daisy)
- + 1; /* nb 0 isn't legal here */
-
-#else /* No IEEE 1284 support */
-
- /* parport_device_num isn't available. */
- t->device_dir[0].ctl_name = 1;
-
-#endif /* IEEE 1284 support or not */
-
+ t->device_dir[0].ctl_name = 0;
t->device_dir[0].procname = device->name;
- t->device_dir[0].extra1 = device;
t->device_dir[0].child = t->vars;
t->vars[0].data = &device->timeslice;
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index cd66442acfe..a8a62bbbb57 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -524,7 +524,7 @@ void parport_remove_port(struct parport *port)
struct pardevice *
parport_register_device(struct parport *port, const char *name,
int (*pf)(void *), void (*kf)(void *),
- void (*irq_func)(int, void *),
+ void (*irq_func)(void *),
int flags, void *handle)
{
struct pardevice *tmp;
@@ -995,6 +995,15 @@ void parport_release(struct pardevice *dev)
}
}
+irqreturn_t parport_irq_handler(int irq, void *dev_id)
+{
+ struct parport *port = dev_id;
+
+ parport_generic_irq(port);
+
+ return IRQ_HANDLED;
+}
+
/* Exported symbols for modules. */
EXPORT_SYMBOL(parport_claim);
@@ -1011,5 +1020,6 @@ EXPORT_SYMBOL(parport_get_port);
EXPORT_SYMBOL(parport_put_port);
EXPORT_SYMBOL(parport_find_number);
EXPORT_SYMBOL(parport_find_base);
+EXPORT_SYMBOL(parport_irq_handler);
MODULE_LICENSE("GPL");
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 7a1d6d51283..e1ca42591ac 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -21,6 +21,17 @@ config PCI_MSI
If you don't know what to do here, say N.
+config PCI_LEGACY
+ bool "Enable deprecated pci_find_* API"
+ depends on PCI
+ default y
+ help
+ Say Y here if you want to include support for the deprecated
+ pci_find_slot() and pci_find_device() APIs. Most drivers have
+ been converted over to using the proper hotplug APIs, so this
+ option serves to include/exclude only a few drivers that are
+ still using this API.
+
config PCI_DEBUG
bool "PCI Debugging"
depends on PCI && DEBUG_KERNEL
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 006054a4099..55505565073 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -20,6 +20,9 @@ obj-$(CONFIG_PCI_MSI) += msi.o
# Build the Hypertransport interrupt support
obj-$(CONFIG_HT_IRQ) += htirq.o
+# Build Intel IOMMU support
+obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o
+
#
# Some architectures use the generic PCI setup functions
#
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
new file mode 100644
index 00000000000..5dfdfdac92e
--- /dev/null
+++ b/drivers/pci/dmar.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2006, 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Copyright (C) Ashok Raj <ashok.raj@intel.com>
+ * Copyright (C) Shaohua Li <shaohua.li@intel.com>
+ * Copyright (C) Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ *
+ * This file implements early detection/parsing of DMA Remapping Devices
+ * reported to OS through BIOS via DMA remapping reporting (DMAR) ACPI
+ * tables.
+ */
+
+#include <linux/pci.h>
+#include <linux/dmar.h>
+
+#undef PREFIX
+#define PREFIX "DMAR:"
+
+/* No locks are needed as DMA remapping hardware unit
+ * list is constructed at boot time and hotplug of
+ * these units are not supported by the architecture.
+ */
+LIST_HEAD(dmar_drhd_units);
+LIST_HEAD(dmar_rmrr_units);
+
+static struct acpi_table_header * __initdata dmar_tbl;
+
+static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
+{
+ /*
+ * add INCLUDE_ALL at the tail, so scan the list will find it at
+ * the very end.
+ */
+ if (drhd->include_all)
+ list_add_tail(&drhd->list, &dmar_drhd_units);
+ else
+ list_add(&drhd->list, &dmar_drhd_units);
+}
+
+static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
+{
+ list_add(&rmrr->list, &dmar_rmrr_units);
+}
+
+static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
+ struct pci_dev **dev, u16 segment)
+{
+ struct pci_bus *bus;
+ struct pci_dev *pdev = NULL;
+ struct acpi_dmar_pci_path *path;
+ int count;
+
+ bus = pci_find_bus(segment, scope->bus);
+ path = (struct acpi_dmar_pci_path *)(scope + 1);
+ count = (scope->length - sizeof(struct acpi_dmar_device_scope))
+ / sizeof(struct acpi_dmar_pci_path);
+
+ while (count) {
+ if (pdev)
+ pci_dev_put(pdev);
+ /*
+ * Some BIOSes list non-exist devices in DMAR table, just
+ * ignore it
+ */
+ if (!bus) {
+ printk(KERN_WARNING
+ PREFIX "Device scope bus [%d] not found\n",
+ scope->bus);
+ break;
+ }
+ pdev = pci_get_slot(bus, PCI_DEVFN(path->dev, path->fn));
+ if (!pdev) {
+ printk(KERN_WARNING PREFIX
+ "Device scope device [%04x:%02x:%02x.%02x] not found\n",
+ segment, bus->number, path->dev, path->fn);
+ break;
+ }
+ path ++;
+ count --;
+ bus = pdev->subordinate;
+ }
+ if (!pdev) {
+ printk(KERN_WARNING PREFIX
+ "Device scope device [%04x:%02x:%02x.%02x] not found\n",
+ segment, scope->bus, path->dev, path->fn);
+ *dev = NULL;
+ return 0;
+ }
+ if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && \
+ pdev->subordinate) || (scope->entry_type == \
+ ACPI_DMAR_SCOPE_TYPE_BRIDGE && !pdev->subordinate)) {
+ pci_dev_put(pdev);
+ printk(KERN_WARNING PREFIX
+ "Device scope type does not match for %s\n",
+ pci_name(pdev));
+ return -EINVAL;
+ }
+ *dev = pdev;
+ return 0;
+}
+
+static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
+ struct pci_dev ***devices, u16 segment)
+{
+ struct acpi_dmar_device_scope *scope;
+ void * tmp = start;
+ int index;
+ int ret;
+
+ *cnt = 0;
+ while (start < end) {
+ scope = start;
+ if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
+ scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
+ (*cnt)++;
+ else
+ printk(KERN_WARNING PREFIX
+ "Unsupported device scope\n");
+ start += scope->length;
+ }
+ if (*cnt == 0)
+ return 0;
+
+ *devices = kcalloc(*cnt, sizeof(struct pci_dev *), GFP_KERNEL);
+ if (!*devices)
+ return -ENOMEM;
+
+ start = tmp;
+ index = 0;
+ while (start < end) {
+ scope = start;
+ if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
+ scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) {
+ ret = dmar_parse_one_dev_scope(scope,
+ &(*devices)[index], segment);
+ if (ret) {
+ kfree(*devices);
+ return ret;
+ }
+ index ++;
+ }
+ start += scope->length;
+ }
+
+ return 0;
+}
+
+/**
+ * dmar_parse_one_drhd - parses exactly one DMA remapping hardware definition
+ * structure which uniquely represent one DMA remapping hardware unit
+ * present in the platform
+ */
+static int __init
+dmar_parse_one_drhd(struct acpi_dmar_header *header)
+{
+ struct acpi_dmar_hardware_unit *drhd;
+ struct dmar_drhd_unit *dmaru;
+ int ret = 0;
+ static int include_all;
+
+ dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
+ if (!dmaru)
+ return -ENOMEM;
+
+ drhd = (struct acpi_dmar_hardware_unit *)header;
+ dmaru->reg_base_addr = drhd->address;
+ dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */
+
+ if (!dmaru->include_all)
+ ret = dmar_parse_dev_scope((void *)(drhd + 1),
+ ((void *)drhd) + header->length,
+ &dmaru->devices_cnt, &dmaru->devices,
+ drhd->segment);
+ else {
+ /* Only allow one INCLUDE_ALL */
+ if (include_all) {
+ printk(KERN_WARNING PREFIX "Only one INCLUDE_ALL "
+ "device scope is allowed\n");
+ ret = -EINVAL;
+ }
+ include_all = 1;
+ }
+
+ if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all))
+ kfree(dmaru);
+ else
+ dmar_register_drhd_unit(dmaru);
+ return ret;
+}
+
+static int __init
+dmar_parse_one_rmrr(struct acpi_dmar_header *header)
+{
+ struct acpi_dmar_reserved_memory *rmrr;
+ struct dmar_rmrr_unit *rmrru;
+ int ret = 0;
+
+ rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
+ if (!rmrru)
+ return -ENOMEM;
+
+ rmrr = (struct acpi_dmar_reserved_memory *)header;
+ rmrru->base_address = rmrr->base_address;
+ rmrru->end_address = rmrr->end_address;
+ ret = dmar_parse_dev_scope((void *)(rmrr + 1),
+ ((void *)rmrr) + header->length,
+ &rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
+
+ if (ret || (rmrru->devices_cnt == 0))
+ kfree(rmrru);
+ else
+ dmar_register_rmrr_unit(rmrru);
+ return ret;
+}
+
+static void __init
+dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
+{
+ struct acpi_dmar_hardware_unit *drhd;
+ struct acpi_dmar_reserved_memory *rmrr;
+
+ switch (header->type) {
+ case ACPI_DMAR_TYPE_HARDWARE_UNIT:
+ drhd = (struct acpi_dmar_hardware_unit *)header;
+ printk (KERN_INFO PREFIX
+ "DRHD (flags: 0x%08x)base: 0x%016Lx\n",
+ drhd->flags, drhd->address);
+ break;
+ case ACPI_DMAR_TYPE_RESERVED_MEMORY:
+ rmrr = (struct acpi_dmar_reserved_memory *)header;
+
+ printk (KERN_INFO PREFIX
+ "RMRR base: 0x%016Lx end: 0x%016Lx\n",
+ rmrr->base_address, rmrr->end_address);
+ break;
+ }
+}
+
+/**
+ * parse_dmar_table - parses the DMA reporting table
+ */
+static int __init
+parse_dmar_table(void)
+{
+ struct acpi_table_dmar *dmar;
+ struct acpi_dmar_header *entry_header;
+ int ret = 0;
+
+ dmar = (struct acpi_table_dmar *)dmar_tbl;
+ if (!dmar)
+ return -ENODEV;
+
+ if (!dmar->width) {
+ printk (KERN_WARNING PREFIX "Zero: Invalid DMAR haw\n");
+ return -EINVAL;
+ }
+
+ printk (KERN_INFO PREFIX "Host address width %d\n",
+ dmar->width + 1);
+
+ entry_header = (struct acpi_dmar_header *)(dmar + 1);
+ while (((unsigned long)entry_header) <
+ (((unsigned long)dmar) + dmar_tbl->length)) {
+ dmar_table_print_dmar_entry(entry_header);
+
+ switch (entry_header->type) {
+ case ACPI_DMAR_TYPE_HARDWARE_UNIT:
+ ret = dmar_parse_one_drhd(entry_header);
+ break;
+ case ACPI_DMAR_TYPE_RESERVED_MEMORY:
+ ret = dmar_parse_one_rmrr(entry_header);
+ break;
+ default:
+ printk(KERN_WARNING PREFIX
+ "Unknown DMAR structure type\n");
+ ret = 0; /* for forward compatibility */
+ break;
+ }
+ if (ret)
+ break;
+
+ entry_header = ((void *)entry_header + entry_header->length);
+ }
+ return ret;
+}
+
+
+int __init dmar_table_init(void)
+{
+
+ parse_dmar_table();
+ if (list_empty(&dmar_drhd_units)) {
+ printk(KERN_INFO PREFIX "No DMAR devices found\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/**
+ * early_dmar_detect - checks to see if the platform supports DMAR devices
+ */
+int __init early_dmar_detect(void)
+{
+ acpi_status status = AE_OK;
+
+ /* if we could find DMAR table, then there are DMAR devices */
+ status = acpi_get_table(ACPI_SIG_DMAR, 0,
+ (struct acpi_table_header **)&dmar_tbl);
+
+ if (ACPI_SUCCESS(status) && !dmar_tbl) {
+ printk (KERN_WARNING PREFIX "Unable to map DMAR\n");
+ status = AE_NOT_FOUND;
+ }
+
+ return (ACPI_SUCCESS(status) ? 1 : 0);
+}
diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
index 1c97e7dd130..2b5352a7dff 100644
--- a/drivers/pci/hotplug.c
+++ b/drivers/pci/hotplug.c
@@ -3,12 +3,9 @@
#include <linux/module.h>
#include "pci.h"
-int pci_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct pci_dev *pdev;
- int i = 0;
- int length = 0;
if (!dev)
return -ENODEV;
@@ -17,37 +14,24 @@ int pci_uevent(struct device *dev, char **envp, int num_envp,
if (!pdev)
return -ENODEV;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PCI_CLASS=%04X", pdev->class))
+ if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PCI_ID=%04X:%04X", pdev->vendor, pdev->device))
+ if (add_uevent_var(env, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
+ if (add_uevent_var(env, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
pdev->subsystem_device))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PCI_SLOT_NAME=%s", pci_name(pdev)))
+ if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev)))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
+ if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
pdev->vendor, pdev->device,
pdev->subsystem_vendor, pdev->subsystem_device,
(u8)(pdev->class >> 16), (u8)(pdev->class >> 8),
(u8)(pdev->class)))
return -ENOMEM;
-
- envp[i] = NULL;
-
return 0;
}
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index 63d62752fb9..a64449d489d 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -41,7 +41,7 @@ config HOTPLUG_PCI_FAKE
config HOTPLUG_PCI_COMPAQ
tristate "Compaq PCI Hotplug driver"
- depends on X86 && PCI_BIOS
+ depends on X86 && PCI_BIOS && PCI_LEGACY
help
Say Y here if you have a motherboard with a Compaq PCI Hotplug
controller.
@@ -63,7 +63,7 @@ config HOTPLUG_PCI_COMPAQ_NVRAM
config HOTPLUG_PCI_IBM
tristate "IBM PCI Hotplug driver"
- depends on X86_IO_APIC && X86 && PCI_BIOS
+ depends on X86_IO_APIC && X86 && PCI_BIOS && PCI_LEGACY
help
Say Y here if you have a motherboard with a IBM PCI Hotplug
controller.
@@ -119,7 +119,7 @@ config HOTPLUG_PCI_CPCI_ZT5550
config HOTPLUG_PCI_CPCI_GENERIC
tristate "Generic port I/O CompactPCI Hotplug driver"
- depends on HOTPLUG_PCI_CPCI && X86
+ depends on HOTPLUG_PCI_CPCI && X86 && PCI_LEGACY
help
Say Y here if you have a CompactPCI system card that exposes the #ENUM
hotswap signal as a bit in a system register that can be read through
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index d590a99930f..a96b739b2d3 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -45,7 +45,7 @@
#include "cpqphp.h"
#include "cpqphp_nvram.h"
-#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */
+#include "../../../arch/x86/pci/pci.h" /* horrible hack showing how processor dependent we are... */
/* Global variables */
@@ -549,7 +549,7 @@ get_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot)
* slot. */
bus->number = tbus;
pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0),
- PCI_REVISION_ID, &work);
+ PCI_CLASS_REVISION, &work);
if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
pci_bus_read_config_dword(bus,
diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
index 37d72f123a8..856d57b4d60 100644
--- a/drivers/pci/hotplug/cpqphp_ctrl.c
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c
@@ -37,6 +37,7 @@
#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
+#include <linux/kthread.h>
#include "cpqphp.h"
static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,
@@ -45,34 +46,20 @@ static int configure_new_function(struct controller* ctrl, struct pci_func *func
u8 behind_bridge, struct resource_lists *resources);
static void interrupt_event_handler(struct controller *ctrl);
-static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */
-static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */
-static int event_finished;
-static unsigned long pushbutton_pending; /* = 0 */
-/* things needed for the long_delay function */
-static struct semaphore delay_sem;
-static wait_queue_head_t delay_wait;
+static struct task_struct *cpqhp_event_thread;
+static unsigned long pushbutton_pending; /* = 0 */
/* delay is in jiffies to wait for */
static void long_delay(int delay)
{
- DECLARE_WAITQUEUE(wait, current);
-
- /* only allow 1 customer into the delay queue at once
- * yes this makes some people wait even longer, but who really cares?
- * this is for _huge_ delays to make the hardware happy as the
- * signals bounce around
+ /*
+ * XXX(hch): if someone is bored please convert all callers
+ * to call msleep_interruptible directly. They really want
+ * to specify timeouts in natural units and spend a lot of
+ * effort converting them to jiffies..
*/
- down (&delay_sem);
-
- init_waitqueue_head(&delay_wait);
-
- add_wait_queue(&delay_wait, &wait);
msleep_interruptible(jiffies_to_msecs(delay));
- remove_wait_queue(&delay_wait, &wait);
-
- up(&delay_sem);
}
@@ -955,8 +942,8 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data)
}
if (schedule_flag) {
- up(&event_semaphore);
- dbg("Signal event_semaphore\n");
+ wake_up_process(cpqhp_event_thread);
+ dbg("Waking even thread");
}
return IRQ_HANDLED;
}
@@ -973,16 +960,13 @@ struct pci_func *cpqhp_slot_create(u8 busnumber)
struct pci_func *new_slot;
struct pci_func *next;
- new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);
-
+ new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL);
if (new_slot == NULL) {
/* I'm not dead yet!
* You will be. */
return new_slot;
}
- memset(new_slot, 0, sizeof(struct pci_func));
-
new_slot->next = NULL;
new_slot->configured = 1;
@@ -1738,7 +1722,7 @@ static u32 remove_board(struct pci_func * func, u32 replace_flag, struct control
static void pushbutton_helper_thread(unsigned long data)
{
pushbutton_pending = data;
- up(&event_semaphore);
+ wake_up_process(cpqhp_event_thread);
}
@@ -1747,13 +1731,13 @@ static int event_thread(void* data)
{
struct controller *ctrl;
- daemonize("phpd_event");
-
while (1) {
dbg("!!!!event_thread sleeping\n");
- down_interruptible (&event_semaphore);
- dbg("event_thread woken finished = %d\n", event_finished);
- if (event_finished) break;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+
+ if (kthread_should_stop())
+ break;
/* Do stuff here */
if (pushbutton_pending)
cpqhp_pushbutton_thread(pushbutton_pending);
@@ -1762,38 +1746,24 @@ static int event_thread(void* data)
interrupt_event_handler(ctrl);
}
dbg("event_thread signals exit\n");
- up(&event_exit);
return 0;
}
-
int cpqhp_event_start_thread(void)
{
- int pid;
-
- /* initialize our semaphores */
- init_MUTEX(&delay_sem);
- init_MUTEX_LOCKED(&event_semaphore);
- init_MUTEX_LOCKED(&event_exit);
- event_finished=0;
-
- pid = kernel_thread(event_thread, NULL, 0);
- if (pid < 0) {
+ cpqhp_event_thread = kthread_run(event_thread, NULL, "phpd_event");
+ if (IS_ERR(cpqhp_event_thread)) {
err ("Can't start up our event thread\n");
- return -1;
+ return PTR_ERR(cpqhp_event_thread);
}
- dbg("Our event thread pid = %d\n", pid);
+
return 0;
}
void cpqhp_event_stop_thread(void)
{
- event_finished = 1;
- dbg("event_thread finish command given\n");
- up(&event_semaphore);
- dbg("wait for event_thread to exit\n");
- down(&event_exit);
+ kthread_stop(cpqhp_event_thread);
}
@@ -1961,16 +1931,14 @@ void cpqhp_pushbutton_thread(unsigned long slot)
return ;
}
- if (func != NULL && ctrl != NULL) {
- if (cpqhp_process_SS(ctrl, func) != 0) {
- amber_LED_on (ctrl, hp_slot);
- green_LED_on (ctrl, hp_slot);
-
- set_SOGO(ctrl);
+ if (cpqhp_process_SS(ctrl, func) != 0) {
+ amber_LED_on(ctrl, hp_slot);
+ green_LED_on(ctrl, hp_slot);
- /* Wait for SOBS to be unset */
- wait_for_ctrl_irq (ctrl);
- }
+ set_SOGO(ctrl);
+
+ /* Wait for SOBS to be unset */
+ wait_for_ctrl_irq(ctrl);
}
p_slot->state = STATIC_STATE;
diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
index fc7c74d7259..3f6cd20e95d 100644
--- a/drivers/pci/hotplug/cpqphp_pci.c
+++ b/drivers/pci/hotplug/cpqphp_pci.c
@@ -37,7 +37,7 @@
#include "../pci.h"
#include "cpqphp.h"
#include "cpqphp_nvram.h"
-#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */
+#include "../../../arch/x86/pci/pci.h" /* horrible hack showing how processor dependent we are... */
u8 cpqhp_nic_irq;
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index 0316eeaaeb2..a90c28d0c69 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -35,7 +35,7 @@
#include <linux/delay.h>
#include <linux/wait.h>
#include "../pci.h"
-#include "../../../arch/i386/pci/pci.h" /* for struct irq_routing_table */
+#include "../../../arch/x86/pci/pci.h" /* for struct irq_routing_table */
#include "ibmphp.h"
#define attn_on(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON)
diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c
index d06ccb69e41..c31e7bf3450 100644
--- a/drivers/pci/hotplug/ibmphp_hpc.c
+++ b/drivers/pci/hotplug/ibmphp_hpc.c
@@ -35,7 +35,7 @@
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/sched.h>
-
+#include <linux/kthread.h>
#include "ibmphp.h"
static int to_debug = 0;
@@ -101,12 +101,11 @@ static int to_debug = 0;
//----------------------------------------------------------------------------
// global variables
//----------------------------------------------------------------------------
-static int ibmphp_shutdown;
-static int tid_poll;
static struct mutex sem_hpcaccess; // lock access to HPC
static struct semaphore semOperations; // lock all operations and
// access to data structures
static struct semaphore sem_exit; // make sure polling thread goes away
+static struct task_struct *ibmphp_poll_thread;
//----------------------------------------------------------------------------
// local function prototypes
//----------------------------------------------------------------------------
@@ -116,10 +115,9 @@ static u8 hpc_writecmdtoindex (u8, u8);
static u8 hpc_readcmdtoindex (u8, u8);
static void get_hpc_access (void);
static void free_hpc_access (void);
-static void poll_hpc (void);
+static int poll_hpc(void *data);
static int process_changeinstatus (struct slot *, struct slot *);
static int process_changeinlatch (u8, u8, struct controller *);
-static int hpc_poll_thread (void *);
static int hpc_wait_ctlr_notworking (int, struct controller *, void __iomem *, u8 *);
//----------------------------------------------------------------------------
@@ -137,8 +135,6 @@ void __init ibmphp_hpc_initvars (void)
init_MUTEX (&semOperations);
init_MUTEX_LOCKED (&sem_exit);
to_debug = 0;
- ibmphp_shutdown = 0;
- tid_poll = 0;
debug ("%s - Exit\n", __FUNCTION__);
}
@@ -819,7 +815,7 @@ void ibmphp_unlock_operations (void)
#define POLL_LATCH_REGISTER 0
#define POLL_SLOTS 1
#define POLL_SLEEP 2
-static void poll_hpc (void)
+static int poll_hpc(void *data)
{
struct slot myslot;
struct slot *pslot = NULL;
@@ -833,10 +829,7 @@ static void poll_hpc (void)
debug ("%s - Entry\n", __FUNCTION__);
- while (!ibmphp_shutdown) {
- if (ibmphp_shutdown)
- break;
-
+ while (!kthread_should_stop()) {
/* try to get the lock to do some kind of hardware access */
down (&semOperations);
@@ -896,7 +889,7 @@ static void poll_hpc (void)
up (&semOperations);
msleep(POLL_INTERVAL_SEC * 1000);
- if (ibmphp_shutdown)
+ if (kthread_should_stop())
break;
down (&semOperations);
@@ -915,6 +908,7 @@ static void poll_hpc (void)
}
up (&sem_exit);
debug ("%s - Exit\n", __FUNCTION__);
+ return 0;
}
@@ -1050,47 +1044,20 @@ static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl)
}
/*----------------------------------------------------------------------
-* Name: hpc_poll_thread
-*
-* Action: polling
-*
-* Return 0
-* Value:
-*---------------------------------------------------------------------*/
-static int hpc_poll_thread (void *data)
-{
- debug ("%s - Entry\n", __FUNCTION__);
-
- daemonize("hpc_poll");
- allow_signal(SIGKILL);
-
- poll_hpc ();
-
- tid_poll = 0;
- debug ("%s - Exit\n", __FUNCTION__);
- return 0;
-}
-
-
-/*----------------------------------------------------------------------
* Name: ibmphp_hpc_start_poll_thread
*
* Action: start polling thread
*---------------------------------------------------------------------*/
int __init ibmphp_hpc_start_poll_thread (void)
{
- int rc = 0;
-
debug ("%s - Entry\n", __FUNCTION__);
- tid_poll = kernel_thread (hpc_poll_thread, NULL, 0);
- if (tid_poll < 0) {
+ ibmphp_poll_thread = kthread_run(poll_hpc, NULL, "hpc_poll");
+ if (IS_ERR(ibmphp_poll_thread)) {
err ("%s - Error, thread not started\n", __FUNCTION__);
- rc = -1;
+ return PTR_ERR(ibmphp_poll_thread);
}
-
- debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc);
- return rc;
+ return 0;
}
/*----------------------------------------------------------------------
@@ -1102,7 +1069,7 @@ void __exit ibmphp_hpc_stop_poll_thread (void)
{
debug ("%s - Entry\n", __FUNCTION__);
- ibmphp_shutdown = 1;
+ kthread_stop(ibmphp_poll_thread);
debug ("before locking operations \n");
ibmphp_lock_operations ();
debug ("after locking operations \n");
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index bd433ef6bfc..01c351c176a 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -689,71 +689,9 @@ int pci_hp_deregister (struct hotplug_slot *slot)
int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
struct hotplug_slot_info *info)
{
- int retval;
-
if ((slot == NULL) || (info == NULL))
return -ENODEV;
- /*
- * check all fields in the info structure, and update timestamps
- * for the files referring to the fields that have now changed.
- */
- if ((has_power_file(slot) == 0) &&
- (slot->info->power_status != info->power_status)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_power.attr);
- if (retval)
- return retval;
- }
-
- if ((has_attention_file(slot) == 0) &&
- (slot->info->attention_status != info->attention_status)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_attention.attr);
- if (retval)
- return retval;
- }
-
- if ((has_latch_file(slot) == 0) &&
- (slot->info->latch_status != info->latch_status)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_latch.attr);
- if (retval)
- return retval;
- }
-
- if ((has_adapter_file(slot) == 0) &&
- (slot->info->adapter_status != info->adapter_status)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_presence.attr);
- if (retval)
- return retval;
- }
-
- if ((has_address_file(slot) == 0) &&
- (slot->info->address != info->address)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_address.attr);
- if (retval)
- return retval;
- }
-
- if ((has_max_bus_speed_file(slot) == 0) &&
- (slot->info->max_bus_speed != info->max_bus_speed)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_max_bus_speed.attr);
- if (retval)
- return retval;
- }
-
- if ((has_cur_bus_speed_file(slot) == 0) &&
- (slot->info->cur_bus_speed != info->cur_bus_speed)) {
- retval = sysfs_update_file(&slot->kobj,
- &hotplug_slot_attr_cur_bus_speed.attr);
- if (retval)
- return retval;
- }
-
memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
return 0;
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index e5d3f0b4f45..6462ac3b405 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -304,8 +304,8 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
hotplug_slot->info->attention_status = status;
-
- if (ATTN_LED(slot->ctrl->ctrlcap))
+
+ if (ATTN_LED(slot->ctrl->ctrlcap))
slot->hpc_ops->set_attention_status(slot, status);
return 0;
@@ -405,7 +405,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
-
+
retval = slot->hpc_ops->get_max_bus_speed(slot, value);
if (retval < 0)
*value = PCI_SPEED_UNKNOWN;
@@ -419,7 +419,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
-
+
retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
if (retval < 0)
*value = PCI_SPEED_UNKNOWN;
@@ -434,7 +434,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
struct slot *t_slot;
u8 value;
struct pci_dev *pdev;
-
+
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
if (!ctrl) {
err("%s : out of memory\n", __FUNCTION__);
@@ -502,23 +502,23 @@ static void pciehp_remove (struct pcie_device *dev)
#ifdef CONFIG_PM
static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)
{
- printk("%s ENTRY\n", __FUNCTION__);
+ printk("%s ENTRY\n", __FUNCTION__);
return 0;
}
static int pciehp_resume (struct pcie_device *dev)
{
- printk("%s ENTRY\n", __FUNCTION__);
+ printk("%s ENTRY\n", __FUNCTION__);
return 0;
}
#endif
-static struct pcie_port_service_id port_pci_ids[] = { {
- .vendor = PCI_ANY_ID,
+static struct pcie_port_service_id port_pci_ids[] = { {
+ .vendor = PCI_ANY_ID,
.device = PCI_ANY_ID,
.port_type = PCIE_ANY_PORT,
.service_type = PCIE_PORT_SERVICE_HP,
- .driver_data = 0,
+ .driver_data = 0,
}, { /* end: all zeroes */ }
};
static const char device_name[] = "hpdriver";
@@ -540,10 +540,6 @@ static int __init pcied_init(void)
{
int retval = 0;
-#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
- pciehp_poll_mode = 1;
-#endif
-
retval = pcie_port_service_register(&hpdriver_portdrv);
dbg("pcie_port_service_register = %d\n", retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 98e541ffef3..c8cb49c5a75 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -173,7 +173,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
return 1;
}
-/* The following routines constitute the bulk of the
+/* The following routines constitute the bulk of the
hotplug controller logic
*/
@@ -181,7 +181,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
{
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
if (POWER_CTRL(ctrl->ctrlcap)) {
- if (pslot->hpc_ops->power_off_slot(pslot)) {
+ if (pslot->hpc_ops->power_off_slot(pslot)) {
err("%s: Issue of Slot Power Off command failed\n",
__FUNCTION__);
return;
@@ -189,7 +189,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
}
if (PWR_LED(ctrl->ctrlcap))
- pslot->hpc_ops->green_led_off(pslot);
+ pslot->hpc_ops->green_led_off(pslot);
if (ATTN_LED(ctrl->ctrlcap)) {
if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
@@ -231,7 +231,7 @@ static int board_added(struct slot *p_slot)
if (retval)
return retval;
}
-
+
if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_blink(p_slot);
@@ -548,7 +548,7 @@ int pciehp_enable_slot(struct slot *p_slot)
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
- if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
+ if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: latch open on slot(%s)\n", __FUNCTION__,
@@ -557,8 +557,8 @@ int pciehp_enable_slot(struct slot *p_slot)
return -ENODEV;
}
}
-
- if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
+
+ if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: already enabled on slot(%s)\n", __FUNCTION__,
@@ -593,7 +593,7 @@ int pciehp_disable_slot(struct slot *p_slot)
/* Check to see if (latch closed, card present, power on) */
mutex_lock(&p_slot->ctrl->crit_sect);
- if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {
+ if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: no adapter on slot(%s)\n", __FUNCTION__,
@@ -603,7 +603,7 @@ int pciehp_disable_slot(struct slot *p_slot)
}
}
- if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
+ if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) {
info("%s: latch open on slot(%s)\n", __FUNCTION__,
@@ -613,7 +613,7 @@ int pciehp_disable_slot(struct slot *p_slot)
}
}
- if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
+ if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: already disabled slot(%s)\n", __FUNCTION__,
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 016eea94a8a..06d025b8b13 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -39,37 +39,6 @@
#include "../pci.h"
#include "pciehp.h"
-#ifdef DEBUG
-#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */
-#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */
-#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */
-#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */
-#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
-#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
-/* Redefine this flagword to set debug level */
-#define DEBUG_LEVEL DBG_K_STANDARD
-
-#define DEFINE_DBG_BUFFER char __dbg_str_buf[256];
-
-#define DBG_PRINT( dbg_flags, args... ) \
- do { \
- if ( DEBUG_LEVEL & ( dbg_flags ) ) \
- { \
- int len; \
- len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
- __FILE__, __LINE__, __FUNCTION__ ); \
- sprintf( __dbg_str_buf + len, args ); \
- printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
- } \
- } while (0)
-
-#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
-#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
-#else
-#define DEFINE_DBG_BUFFER
-#define DBG_ENTER_ROUTINE
-#define DBG_LEAVE_ROUTINE
-#endif /* DEBUG */
static atomic_t pciehp_num_controllers = ATOMIC_INIT(0);
@@ -160,10 +129,10 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
/* Link Width Encoding */
#define LNK_X1 0x01
#define LNK_X2 0x02
-#define LNK_X4 0x04
+#define LNK_X4 0x04
#define LNK_X8 0x08
#define LNK_X12 0x0C
-#define LNK_X16 0x10
+#define LNK_X16 0x10
#define LNK_X32 0x20
/*Field definitions of Link Status Register */
@@ -221,8 +190,6 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
#define EMI_STATE 0x0080
#define EMI_STATUS_BIT 7
-DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
-
static irqreturn_t pcie_isr(int irq, void *dev_id);
static void start_int_poll_timer(struct controller *ctrl, int sec);
@@ -231,14 +198,12 @@ static void int_poll_timeout(unsigned long data)
{
struct controller *ctrl = (struct controller *)data;
- DBG_ENTER_ROUTINE
-
/* Poll for interrupt events. regs == NULL => polling */
pcie_isr(0, ctrl);
init_timer(&ctrl->poll_timer);
if (!pciehp_poll_time)
- pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
+ pciehp_poll_time = 2; /* default polling interval is 2 sec */
start_int_poll_timer(ctrl, pciehp_poll_time);
}
@@ -289,8 +254,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
u16 slot_ctrl;
unsigned long flags;
- DBG_ENTER_ROUTINE
-
mutex_lock(&ctrl->ctrl_lock);
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
@@ -299,7 +262,7 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
goto out;
}
- if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
+ if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
/* After 1 sec and CMD_COMPLETED still not set, just
proceed forward to issue the next command according
to spec. Just print out the error message */
@@ -332,7 +295,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
retval = pcie_wait_cmd(ctrl);
out:
mutex_unlock(&ctrl->ctrl_lock);
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -341,8 +303,6 @@ static int hpc_check_lnk_status(struct controller *ctrl)
u16 lnk_status;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
@@ -350,26 +310,22 @@ static int hpc_check_lnk_status(struct controller *ctrl)
}
dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status);
- if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) ||
+ if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) ||
!(lnk_status & NEG_LINK_WD)) {
err("%s : Link Training Error occurs \n", __FUNCTION__);
retval = -1;
return retval;
}
- DBG_LEAVE_ROUTINE
return retval;
}
-
static int hpc_get_attention_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
u16 slot_ctrl;
u8 atten_led_state;
int retval = 0;
-
- DBG_ENTER_ROUTINE
retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
@@ -400,7 +356,6 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
break;
}
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -410,8 +365,6 @@ static int hpc_get_power_status(struct slot *slot, u8 *status)
u16 slot_ctrl;
u8 pwr_state;
int retval = 0;
-
- DBG_ENTER_ROUTINE
retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
@@ -428,35 +381,30 @@ static int hpc_get_power_status(struct slot *slot, u8 *status)
*status = 1;
break;
case 1:
- *status = 0;
+ *status = 0;
break;
default:
*status = 0xFF;
break;
}
- DBG_LEAVE_ROUTINE
return retval;
}
-
static int hpc_get_latch_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
u16 slot_status;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return retval;
}
- *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;
+ *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -467,8 +415,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
u8 card_state;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
@@ -477,7 +423,6 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
card_state = (u8)((slot_status & PRSN_STATE) >> 6);
*status = (card_state == 1) ? 1 : 0;
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -488,16 +433,13 @@ static int hpc_query_power_fault(struct slot *slot)
u8 pwr_fault;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
err("%s: Cannot check for power fault\n", __FUNCTION__);
return retval;
}
pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
-
- DBG_LEAVE_ROUTINE
+
return pwr_fault;
}
@@ -507,8 +449,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status)
u16 slot_status;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
err("%s : Cannot check EMI status\n", __FUNCTION__);
@@ -516,7 +456,6 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status)
}
*status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -526,8 +465,6 @@ static int hpc_toggle_emi(struct slot *slot)
u16 cmd_mask;
int rc;
- DBG_ENTER_ROUTINE
-
slot_cmd = EMI_CTRL;
cmd_mask = EMI_CTRL;
if (!pciehp_poll_mode) {
@@ -537,7 +474,7 @@ static int hpc_toggle_emi(struct slot *slot)
rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
slot->last_emi_toggle = get_seconds();
- DBG_LEAVE_ROUTINE
+
return rc;
}
@@ -548,8 +485,6 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
u16 cmd_mask;
int rc;
- DBG_ENTER_ROUTINE
-
cmd_mask = ATTN_LED_CTRL;
switch (value) {
case 0 : /* turn off */
@@ -572,19 +507,15 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-
- DBG_LEAVE_ROUTINE
+
return rc;
}
-
static void hpc_set_green_led_on(struct slot *slot)
{
struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 cmd_mask;
-
- DBG_ENTER_ROUTINE
slot_cmd = 0x0100;
cmd_mask = PWR_LED_CTRL;
@@ -597,8 +528,6 @@ static void hpc_set_green_led_on(struct slot *slot)
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
- DBG_LEAVE_ROUTINE
- return;
}
static void hpc_set_green_led_off(struct slot *slot)
@@ -607,8 +536,6 @@ static void hpc_set_green_led_off(struct slot *slot)
u16 slot_cmd;
u16 cmd_mask;
- DBG_ENTER_ROUTINE
-
slot_cmd = 0x0300;
cmd_mask = PWR_LED_CTRL;
if (!pciehp_poll_mode) {
@@ -619,9 +546,6 @@ static void hpc_set_green_led_off(struct slot *slot)
pcie_write_cmd(slot, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-
- DBG_LEAVE_ROUTINE
- return;
}
static void hpc_set_green_led_blink(struct slot *slot)
@@ -629,8 +553,6 @@ static void hpc_set_green_led_blink(struct slot *slot)
struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 cmd_mask;
-
- DBG_ENTER_ROUTINE
slot_cmd = 0x0200;
cmd_mask = PWR_LED_CTRL;
@@ -643,14 +565,10 @@ static void hpc_set_green_led_blink(struct slot *slot)
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
- DBG_LEAVE_ROUTINE
- return;
}
static void hpc_release_ctlr(struct controller *ctrl)
{
- DBG_ENTER_ROUTINE
-
if (pciehp_poll_mode)
del_timer(&ctrl->poll_timer);
else
@@ -662,8 +580,6 @@ static void hpc_release_ctlr(struct controller *ctrl)
*/
if (atomic_dec_and_test(&pciehp_num_controllers))
destroy_workqueue(pciehp_wq);
-
- DBG_LEAVE_ROUTINE
}
static int hpc_power_on_slot(struct slot * slot)
@@ -674,8 +590,6 @@ static int hpc_power_on_slot(struct slot * slot)
u16 slot_status;
int retval = 0;
- DBG_ENTER_ROUTINE
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
/* Clear sticky power-fault bit from previous power failures */
@@ -719,8 +633,6 @@ static int hpc_power_on_slot(struct slot * slot)
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
- DBG_LEAVE_ROUTINE
-
return retval;
}
@@ -731,8 +643,6 @@ static int hpc_power_off_slot(struct slot * slot)
u16 cmd_mask;
int retval = 0;
- DBG_ENTER_ROUTINE
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
slot_cmd = POWER_OFF;
@@ -764,8 +674,6 @@ static int hpc_power_off_slot(struct slot * slot)
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
- DBG_LEAVE_ROUTINE
-
return retval;
}
@@ -784,8 +692,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
return IRQ_NONE;
}
- intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED |
- PRSN_DETECT_CHANGED | CMD_COMPLETED );
+ intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED |
+ MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED);
intr_loc = slot_status & intr_detect;
@@ -807,7 +715,8 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
__FUNCTION__, temp_word);
- temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+ temp_word = (temp_word & ~HP_INTR_ENABLE &
+ ~CMD_CMPL_INTR_ENABLE) | 0x00;
rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
err("%s: Cannot write to SLOTCTRL register\n",
@@ -825,7 +734,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
}
dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
__FUNCTION__, slot_status);
-
+
/* Clear command complete interrupt caused by this write */
temp_word = 0x1f;
rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
@@ -835,10 +744,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
return IRQ_NONE;
}
}
-
+
if (intr_loc & CMD_COMPLETED) {
- /*
- * Command Complete Interrupt Pending
+ /*
+ * Command Complete Interrupt Pending
*/
ctrl->cmd_busy = 0;
wake_up_interruptible(&ctrl->queue);
@@ -892,7 +801,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
__FUNCTION__);
return IRQ_NONE;
}
-
+
/* Clear command complete interrupt caused by this write */
temp_word = 0x1F;
rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
@@ -904,19 +813,17 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
__FUNCTION__, temp_word);
}
-
+
return IRQ_HANDLED;
}
-static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
+static int hpc_get_max_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
{
struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed;
u32 lnk_cap;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
@@ -934,19 +841,18 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
*value = lnk_speed;
dbg("Max link speed = %d\n", lnk_speed);
- DBG_LEAVE_ROUTINE
+
return retval;
}
-static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
+static int hpc_get_max_lnk_width(struct slot *slot,
+ enum pcie_link_width *value)
{
struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth;
u32 lnk_cap;
int retval = 0;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
@@ -985,19 +891,17 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value
*value = lnk_wdth;
dbg("Max link width = %d\n", lnk_wdth);
- DBG_LEAVE_ROUTINE
+
return retval;
}
-static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
+static int hpc_get_cur_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
{
struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
int retval = 0;
u16 lnk_status;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
@@ -1015,25 +919,24 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
*value = lnk_speed;
dbg("Current link speed = %d\n", lnk_speed);
- DBG_LEAVE_ROUTINE
+
return retval;
}
-static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
+static int hpc_get_cur_lnk_width(struct slot *slot,
+ enum pcie_link_width *value)
{
struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
int retval = 0;
u16 lnk_status;
- DBG_ENTER_ROUTINE
-
retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
-
+
switch ((lnk_status & 0x03F0) >> 4){
case 0:
lnk_wdth = PCIE_LNK_WIDTH_RESRV;
@@ -1066,7 +969,7 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value
*value = lnk_wdth;
dbg("Current link width = %d\n", lnk_wdth);
- DBG_LEAVE_ROUTINE
+
return retval;
}
@@ -1085,12 +988,12 @@ static struct hpc_ops pciehp_hpc_ops = {
.get_cur_bus_speed = hpc_get_cur_lnk_speed,
.get_max_lnk_width = hpc_get_max_lnk_width,
.get_cur_lnk_width = hpc_get_cur_lnk_width,
-
+
.query_power_fault = hpc_query_power_fault,
.green_led_on = hpc_set_green_led_on,
.green_led_off = hpc_set_green_led_off,
.green_led_blink = hpc_set_green_led_blink,
-
+
.release_ctlr = hpc_release_ctlr,
.check_lnk_status = hpc_check_lnk_status,
};
@@ -1138,6 +1041,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
dbg("Trying to get hotplug control for %s \n",
(char *)string.pointer);
status = pci_osc_control_set(handle,
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL |
OSC_PCI_EXPRESS_NATIVE_HP_CONTROL);
if (status == AE_NOT_FOUND)
status = acpi_run_oshp(handle);
@@ -1163,8 +1067,6 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
}
#endif
-
-
int pcie_init(struct controller * ctrl, struct pcie_device *dev)
{
int rc;
@@ -1176,8 +1078,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
u16 slot_status, slot_ctrl;
struct pci_dev *pdev;
- DBG_ENTER_ROUTINE
-
pdev = dev->port;
ctrl->pci_dev = pdev; /* save pci_dev in context */
@@ -1201,9 +1101,11 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
dbg("%s: CAPREG offset %x cap_reg %x\n",
__FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
- if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
+ if (((cap_reg & SLOT_IMPL) == 0) ||
+ (((cap_reg & DEV_PORT_TYPE) != 0x0040)
&& ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
- dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__);
+ dbg("%s : This is not a root port or the port is not "
+ "connected to a slot\n", __FUNCTION__);
goto abort_free_ctlr;
}
@@ -1236,14 +1138,15 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
- for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
+ for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
if (pci_resource_len(pdev, rc) > 0)
dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
(unsigned long long)pci_resource_start(pdev, rc),
(unsigned long long)pci_resource_len(pdev, rc));
- info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device,
- pdev->subsystem_vendor, pdev->subsystem_device);
+ info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n",
+ pdev->vendor, pdev->device,
+ pdev->subsystem_vendor, pdev->subsystem_device);
mutex_init(&ctrl->crit_sect);
mutex_init(&ctrl->ctrl_lock);
@@ -1267,7 +1170,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
dbg("%s: SLOTCTRL %x value read %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
- temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+ temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
+ 0x00;
rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
@@ -1330,14 +1234,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
if (ATTN_BUTTN(slot_cap))
intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
-
+
if (POWER_CTRL(slot_cap))
intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
-
+
if (MRL_SENS(slot_cap))
intr_enable = intr_enable | MRL_DETECT_ENABLE;
- temp_word = (temp_word & ~intr_enable) | intr_enable;
+ temp_word = (temp_word & ~intr_enable) | intr_enable;
if (pciehp_poll_mode) {
temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
@@ -1345,7 +1249,10 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
}
- /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
+ /*
+ * Unmask Hot-plug Interrupt Enable for the interrupt
+ * notification mechanism case.
+ */
rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
@@ -1356,14 +1263,14 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
-
+
temp_word = 0x1F; /* Clear all events */
rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
-
+
if (pciehp_force) {
dbg("Bypassing BIOS check for pciehp use on %s\n",
pci_name(ctrl->pci_dev));
@@ -1375,10 +1282,9 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
ctrl->hpc_ops = &pciehp_hpc_ops;
- DBG_LEAVE_ROUTINE
return 0;
- /* We end up here for the many possible ways to fail this API. */
+ /* We end up here for the many possible ways to fail this API. */
abort_disable_intr:
rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (!rc) {
@@ -1395,6 +1301,5 @@ abort_free_irq:
free_irq(ctrl->pci_dev->irq, ctrl);
abort_free_ctlr:
- DBG_LEAVE_ROUTINE
return -1;
}
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index 854aaea09e4..c424aded13f 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -243,9 +243,10 @@ int pciehp_configure_device(struct slot *p_slot)
int pciehp_unconfigure_device(struct slot *p_slot)
{
- int rc = 0;
+ int ret, rc = 0;
int j;
u8 bctl = 0;
+ u8 presence = 0;
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus,
@@ -263,23 +264,28 @@ int pciehp_unconfigure_device(struct slot *p_slot)
continue;
}
if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
- pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
- if (bctl & PCI_BRIDGE_CTL_VGA) {
- err("Cannot remove display device %s\n",
+ ret = p_slot->hpc_ops->get_adapter_status(p_slot,
+ &presence);
+ if (!ret && presence) {
+ pci_read_config_byte(temp, PCI_BRIDGE_CONTROL,
+ &bctl);
+ if (bctl & PCI_BRIDGE_CTL_VGA) {
+ err("Cannot remove display device %s\n",
pci_name(temp));
- pci_dev_put(temp);
- continue;
+ pci_dev_put(temp);
+ continue;
+ }
}
}
pci_remove_bus_device(temp);
pci_dev_put(temp);
}
- /*
+ /*
* Some PCI Express root ports require fixup after hot-plug operation.
*/
- if (pcie_mch_quirk)
+ if (pcie_mch_quirk)
pci_fixup_device(pci_fixup_final, p_slot->ctrl->pci_dev);
-
+
return rc;
}
diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
index df076064a3e..a080fedf033 100644
--- a/drivers/pci/hotplug/rpadlpar_sysfs.c
+++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
@@ -129,17 +129,17 @@ struct kobj_type ktype_dlpar_io = {
};
struct kset dlpar_io_kset = {
- .kobj = {.name = DLPAR_KOBJ_NAME,
- .ktype = &ktype_dlpar_io,
+ .kobj = {.ktype = &ktype_dlpar_io,
.parent = &pci_hotplug_slots_subsys.kobj},
.ktype = &ktype_dlpar_io,
};
int dlpar_sysfs_init(void)
{
+ kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME);
if (kset_register(&dlpar_io_kset)) {
printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n",
- dlpar_io_kset.kobj.name);
+ kobject_name(&dlpar_io_kset.kobj));
return -EINVAL;
}
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
new file mode 100644
index 00000000000..e079a5237c9
--- /dev/null
+++ b/drivers/pci/intel-iommu.c
@@ -0,0 +1,2270 @@
+/*
+ * Copyright (c) 2006, 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Copyright (C) Ashok Raj <ashok.raj@intel.com>
+ * Copyright (C) Shaohua Li <shaohua.li@intel.com>
+ * Copyright (C) Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ */
+
+#include <linux/init.h>
+#include <linux/bitmap.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/sysdev.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/dmar.h>
+#include <linux/dma-mapping.h>
+#include <linux/mempool.h>
+#include "iova.h"
+#include "intel-iommu.h"
+#include <asm/proto.h> /* force_iommu in this header in x86-64*/
+#include <asm/cacheflush.h>
+#include <asm/gart.h>
+#include "pci.h"
+
+#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
+#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
+
+#define IOAPIC_RANGE_START (0xfee00000)
+#define IOAPIC_RANGE_END (0xfeefffff)
+#define IOVA_START_ADDR (0x1000)
+
+#define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
+
+#define DMAR_OPERATION_TIMEOUT (HZ*60) /* 1m */
+
+#define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
+
+static void domain_remove_dev_info(struct dmar_domain *domain);
+
+static int dmar_disabled;
+static int __initdata dmar_map_gfx = 1;
+static int dmar_forcedac;
+
+#define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
+static DEFINE_SPINLOCK(device_domain_lock);
+static LIST_HEAD(device_domain_list);
+
+static int __init intel_iommu_setup(char *str)
+{
+ if (!str)
+ return -EINVAL;
+ while (*str) {
+ if (!strncmp(str, "off", 3)) {
+ dmar_disabled = 1;
+ printk(KERN_INFO"Intel-IOMMU: disabled\n");
+ } else if (!strncmp(str, "igfx_off", 8)) {
+ dmar_map_gfx = 0;
+ printk(KERN_INFO
+ "Intel-IOMMU: disable GFX device mapping\n");
+ } else if (!strncmp(str, "forcedac", 8)) {
+ printk (KERN_INFO
+ "Intel-IOMMU: Forcing DAC for PCI devices\n");
+ dmar_forcedac = 1;
+ }
+
+ str += strcspn(str, ",");
+ while (*str == ',')
+ str++;
+ }
+ return 0;
+}
+__setup("intel_iommu=", intel_iommu_setup);
+
+static struct kmem_cache *iommu_domain_cache;
+static struct kmem_cache *iommu_devinfo_cache;
+static struct kmem_cache *iommu_iova_cache;
+
+static inline void *iommu_kmem_cache_alloc(struct kmem_cache *cachep)
+{
+ unsigned int flags;
+ void *vaddr;
+
+ /* trying to avoid low memory issues */
+ flags = current->flags & PF_MEMALLOC;
+ current->flags |= PF_MEMALLOC;
+ vaddr = kmem_cache_alloc(cachep, GFP_ATOMIC);
+ current->flags &= (~PF_MEMALLOC | flags);
+ return vaddr;
+}
+
+
+static inline void *alloc_pgtable_page(void)
+{
+ unsigned int flags;
+ void *vaddr;
+
+ /* trying to avoid low memory issues */
+ flags = current->flags & PF_MEMALLOC;
+ current->flags |= PF_MEMALLOC;
+ vaddr = (void *)get_zeroed_page(GFP_ATOMIC);
+ current->flags &= (~PF_MEMALLOC | flags);
+ return vaddr;
+}
+
+static inline void free_pgtable_page(void *vaddr)
+{
+ free_page((unsigned long)vaddr);
+}
+
+static inline void *alloc_domain_mem(void)
+{
+ return iommu_kmem_cache_alloc(iommu_domain_cache);
+}
+
+static inline void free_domain_mem(void *vaddr)
+{
+ kmem_cache_free(iommu_domain_cache, vaddr);
+}
+
+static inline void * alloc_devinfo_mem(void)
+{
+ return iommu_kmem_cache_alloc(iommu_devinfo_cache);
+}
+
+static inline void free_devinfo_mem(void *vaddr)
+{
+ kmem_cache_free(iommu_devinfo_cache, vaddr);
+}
+
+struct iova *alloc_iova_mem(void)
+{
+ return iommu_kmem_cache_alloc(iommu_iova_cache);
+}
+
+void free_iova_mem(struct iova *iova)
+{
+ kmem_cache_free(iommu_iova_cache, iova);
+}
+
+static inline void __iommu_flush_cache(
+ struct intel_iommu *iommu, void *addr, int size)
+{
+ if (!ecap_coherent(iommu->ecap))
+ clflush_cache_range(addr, size);
+}
+
+/* Gets context entry for a given bus and devfn */
+static struct context_entry * device_to_context_entry(struct intel_iommu *iommu,
+ u8 bus, u8 devfn)
+{
+ struct root_entry *root;
+ struct context_entry *context;
+ unsigned long phy_addr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ root = &iommu->root_entry[bus];
+ context = get_context_addr_from_root(root);
+ if (!context) {
+ context = (struct context_entry *)alloc_pgtable_page();
+ if (!context) {
+ spin_unlock_irqrestore(&iommu->lock, flags);
+ return NULL;
+ }
+ __iommu_flush_cache(iommu, (void *)context, PAGE_SIZE_4K);
+ phy_addr = virt_to_phys((void *)context);
+ set_root_value(root, phy_addr);
+ set_root_present(root);
+ __iommu_flush_cache(iommu, root, sizeof(*root));
+ }
+ spin_unlock_irqrestore(&iommu->lock, flags);
+ return &context[devfn];
+}
+
+static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+ struct root_entry *root;
+ struct context_entry *context;
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ root = &iommu->root_entry[bus];
+ context = get_context_addr_from_root(root);
+ if (!context) {
+ ret = 0;
+ goto out;
+ }
+ ret = context_present(context[devfn]);
+out:
+ spin_unlock_irqrestore(&iommu->lock, flags);
+ return ret;
+}
+
+static void clear_context_table(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+ struct root_entry *root;
+ struct context_entry *context;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ root = &iommu->root_entry[bus];
+ context = get_context_addr_from_root(root);
+ if (context) {
+ context_clear_entry(context[devfn]);
+ __iommu_flush_cache(iommu, &context[devfn], \
+ sizeof(*context));
+ }
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+static void free_context_table(struct intel_iommu *iommu)
+{
+ struct root_entry *root;
+ int i;
+ unsigned long flags;
+ struct context_entry *context;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ if (!iommu->root_entry) {
+ goto out;
+ }
+ for (i = 0; i < ROOT_ENTRY_NR; i++) {
+ root = &iommu->root_entry[i];
+ context = get_context_addr_from_root(root);
+ if (context)
+ free_pgtable_page(context);
+ }
+ free_pgtable_page(iommu->root_entry);
+ iommu->root_entry = NULL;
+out:
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+/* page table handling */
+#define LEVEL_STRIDE (9)
+#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
+
+static inline int agaw_to_level(int agaw)
+{
+ return agaw + 2;
+}
+
+static inline int agaw_to_width(int agaw)
+{
+ return 30 + agaw * LEVEL_STRIDE;
+
+}
+
+static inline int width_to_agaw(int width)
+{
+ return (width - 30) / LEVEL_STRIDE;
+}
+
+static inline unsigned int level_to_offset_bits(int level)
+{
+ return (12 + (level - 1) * LEVEL_STRIDE);
+}
+
+static inline int address_level_offset(u64 addr, int level)
+{
+ return ((addr >> level_to_offset_bits(level)) & LEVEL_MASK);
+}
+
+static inline u64 level_mask(int level)
+{
+ return ((u64)-1 << level_to_offset_bits(level));
+}
+
+static inline u64 level_size(int level)
+{
+ return ((u64)1 << level_to_offset_bits(level));
+}
+
+static inline u64 align_to_level(u64 addr, int level)
+{
+ return ((addr + level_size(level) - 1) & level_mask(level));
+}
+
+static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
+{
+ int addr_width = agaw_to_width(domain->agaw);
+ struct dma_pte *parent, *pte = NULL;
+ int level = agaw_to_level(domain->agaw);
+ int offset;
+ unsigned long flags;
+
+ BUG_ON(!domain->pgd);
+
+ addr &= (((u64)1) << addr_width) - 1;
+ parent = domain->pgd;
+
+ spin_lock_irqsave(&domain->mapping_lock, flags);
+ while (level > 0) {
+ void *tmp_page;
+
+ offset = address_level_offset(addr, level);
+ pte = &parent[offset];
+ if (level == 1)
+ break;
+
+ if (!dma_pte_present(*pte)) {
+ tmp_page = alloc_pgtable_page();
+
+ if (!tmp_page) {
+ spin_unlock_irqrestore(&domain->mapping_lock,
+ flags);
+ return NULL;
+ }
+ __iommu_flush_cache(domain->iommu, tmp_page,
+ PAGE_SIZE_4K);
+ dma_set_pte_addr(*pte, virt_to_phys(tmp_page));
+ /*
+ * high level table always sets r/w, last level page
+ * table control read/write
+ */
+ dma_set_pte_readable(*pte);
+ dma_set_pte_writable(*pte);
+ __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
+ }
+ parent = phys_to_virt(dma_pte_addr(*pte));
+ level--;
+ }
+
+ spin_unlock_irqrestore(&domain->mapping_lock, flags);
+ return pte;
+}
+
+/* return address's pte at specific level */
+static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
+ int level)
+{
+ struct dma_pte *parent, *pte = NULL;
+ int total = agaw_to_level(domain->agaw);
+ int offset;
+
+ parent = domain->pgd;
+ while (level <= total) {
+ offset = address_level_offset(addr, total);
+ pte = &parent[offset];
+ if (level == total)
+ return pte;
+
+ if (!dma_pte_present(*pte))
+ break;
+ parent = phys_to_virt(dma_pte_addr(*pte));
+ total--;
+ }
+ return NULL;
+}
+
+/* clear one page's page table */
+static void dma_pte_clear_one(struct dmar_domain *domain, u64 addr)
+{
+ struct dma_pte *pte = NULL;
+
+ /* get last level pte */
+ pte = dma_addr_level_pte(domain, addr, 1);
+
+ if (pte) {
+ dma_clear_pte(*pte);
+ __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
+ }
+}
+
+/* clear last level pte, a tlb flush should be followed */
+static void dma_pte_clear_range(struct dmar_domain *domain, u64 start, u64 end)
+{
+ int addr_width = agaw_to_width(domain->agaw);
+
+ start &= (((u64)1) << addr_width) - 1;
+ end &= (((u64)1) << addr_width) - 1;
+ /* in case it's partial page */
+ start = PAGE_ALIGN_4K(start);
+ end &= PAGE_MASK_4K;
+
+ /* we don't need lock here, nobody else touches the iova range */
+ while (start < end) {
+ dma_pte_clear_one(domain, start);
+ start += PAGE_SIZE_4K;
+ }
+}
+
+/* free page table pages. last level pte should already be cleared */
+static void dma_pte_free_pagetable(struct dmar_domain *domain,
+ u64 start, u64 end)
+{
+ int addr_width = agaw_to_width(domain->agaw);
+ struct dma_pte *pte;
+ int total = agaw_to_level(domain->agaw);
+ int level;
+ u64 tmp;
+
+ start &= (((u64)1) << addr_width) - 1;
+ end &= (((u64)1) << addr_width) - 1;
+
+ /* we don't need lock here, nobody else touches the iova range */
+ level = 2;
+ while (level <= total) {
+ tmp = align_to_level(start, level);
+ if (tmp >= end || (tmp + level_size(level) > end))
+ return;
+
+ while (tmp < end) {
+ pte = dma_addr_level_pte(domain, tmp, level);
+ if (pte) {
+ free_pgtable_page(
+ phys_to_virt(dma_pte_addr(*pte)));
+ dma_clear_pte(*pte);
+ __iommu_flush_cache(domain->iommu,
+ pte, sizeof(*pte));
+ }
+ tmp += level_size(level);
+ }
+ level++;
+ }
+ /* free pgd */
+ if (start == 0 && end >= ((((u64)1) << addr_width) - 1)) {
+ free_pgtable_page(domain->pgd);
+ domain->pgd = NULL;
+ }
+}
+
+/* iommu handling */
+static int iommu_alloc_root_entry(struct intel_iommu *iommu)
+{
+ struct root_entry *root;
+ unsigned long flags;
+
+ root = (struct root_entry *)alloc_pgtable_page();
+ if (!root)
+ return -ENOMEM;
+
+ __iommu_flush_cache(iommu, root, PAGE_SIZE_4K);
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ iommu->root_entry = root;
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ return 0;
+}
+
+#define IOMMU_WAIT_OP(iommu, offset, op, cond, sts) \
+{\
+ unsigned long start_time = jiffies;\
+ while (1) {\
+ sts = op (iommu->reg + offset);\
+ if (cond)\
+ break;\
+ if (time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT))\
+ panic("DMAR hardware is malfunctioning\n");\
+ cpu_relax();\
+ }\
+}
+
+static void iommu_set_root_entry(struct intel_iommu *iommu)
+{
+ void *addr;
+ u32 cmd, sts;
+ unsigned long flag;
+
+ addr = iommu->root_entry;
+
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
+
+ cmd = iommu->gcmd | DMA_GCMD_SRTP;
+ writel(cmd, iommu->reg + DMAR_GCMD_REG);
+
+ /* Make sure hardware complete it */
+ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+ readl, (sts & DMA_GSTS_RTPS), sts);
+
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+static void iommu_flush_write_buffer(struct intel_iommu *iommu)
+{
+ u32 val;
+ unsigned long flag;
+
+ if (!cap_rwbf(iommu->cap))
+ return;
+ val = iommu->gcmd | DMA_GCMD_WBF;
+
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ writel(val, iommu->reg + DMAR_GCMD_REG);
+
+ /* Make sure hardware complete it */
+ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+ readl, (!(val & DMA_GSTS_WBFS)), val);
+
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+/* return value determine if we need a write buffer flush */
+static int __iommu_flush_context(struct intel_iommu *iommu,
+ u16 did, u16 source_id, u8 function_mask, u64 type,
+ int non_present_entry_flush)
+{
+ u64 val = 0;
+ unsigned long flag;
+
+ /*
+ * In the non-present entry flush case, if hardware doesn't cache
+ * non-present entry we do nothing and if hardware cache non-present
+ * entry, we flush entries of domain 0 (the domain id is used to cache
+ * any non-present entries)
+ */
+ if (non_present_entry_flush) {
+ if (!cap_caching_mode(iommu->cap))
+ return 1;
+ else
+ did = 0;
+ }
+
+ switch (type) {
+ case DMA_CCMD_GLOBAL_INVL:
+ val = DMA_CCMD_GLOBAL_INVL;
+ break;
+ case DMA_CCMD_DOMAIN_INVL:
+ val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
+ break;
+ case DMA_CCMD_DEVICE_INVL:
+ val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
+ | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
+ break;
+ default:
+ BUG();
+ }
+ val |= DMA_CCMD_ICC;
+
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);
+
+ /* Make sure hardware complete it */
+ IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
+ dmar_readq, (!(val & DMA_CCMD_ICC)), val);
+
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+
+ /* flush context entry will implictly flush write buffer */
+ return 0;
+}
+
+static int inline iommu_flush_context_global(struct intel_iommu *iommu,
+ int non_present_entry_flush)
+{
+ return __iommu_flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL,
+ non_present_entry_flush);
+}
+
+static int inline iommu_flush_context_domain(struct intel_iommu *iommu, u16 did,
+ int non_present_entry_flush)
+{
+ return __iommu_flush_context(iommu, did, 0, 0, DMA_CCMD_DOMAIN_INVL,
+ non_present_entry_flush);
+}
+
+static int inline iommu_flush_context_device(struct intel_iommu *iommu,
+ u16 did, u16 source_id, u8 function_mask, int non_present_entry_flush)
+{
+ return __iommu_flush_context(iommu, did, source_id, function_mask,
+ DMA_CCMD_DEVICE_INVL, non_present_entry_flush);
+}
+
+/* return value determine if we need a write buffer flush */
+static int __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did,
+ u64 addr, unsigned int size_order, u64 type,
+ int non_present_entry_flush)
+{
+ int tlb_offset = ecap_iotlb_offset(iommu->ecap);
+ u64 val = 0, val_iva = 0;
+ unsigned long flag;
+
+ /*
+ * In the non-present entry flush case, if hardware doesn't cache
+ * non-present entry we do nothing and if hardware cache non-present
+ * entry, we flush entries of domain 0 (the domain id is used to cache
+ * any non-present entries)
+ */
+ if (non_present_entry_flush) {
+ if (!cap_caching_mode(iommu->cap))
+ return 1;
+ else
+ did = 0;
+ }
+
+ switch (type) {
+ case DMA_TLB_GLOBAL_FLUSH:
+ /* global flush doesn't need set IVA_REG */
+ val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
+ break;
+ case DMA_TLB_DSI_FLUSH:
+ val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
+ break;
+ case DMA_TLB_PSI_FLUSH:
+ val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
+ /* Note: always flush non-leaf currently */
+ val_iva = size_order | addr;
+ break;
+ default:
+ BUG();
+ }
+ /* Note: set drain read/write */
+#if 0
+ /*
+ * This is probably to be super secure.. Looks like we can
+ * ignore it without any impact.
+ */
+ if (cap_read_drain(iommu->cap))
+ val |= DMA_TLB_READ_DRAIN;
+#endif
+ if (cap_write_drain(iommu->cap))
+ val |= DMA_TLB_WRITE_DRAIN;
+
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ /* Note: Only uses first TLB reg currently */
+ if (val_iva)
+ dmar_writeq(iommu->reg + tlb_offset, val_iva);
+ dmar_writeq(iommu->reg + tlb_offset + 8, val);
+
+ /* Make sure hardware complete it */
+ IOMMU_WAIT_OP(iommu, tlb_offset + 8,
+ dmar_readq, (!(val & DMA_TLB_IVT)), val);
+
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+
+ /* check IOTLB invalidation granularity */
+ if (DMA_TLB_IAIG(val) == 0)
+ printk(KERN_ERR"IOMMU: flush IOTLB failed\n");
+ if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
+ pr_debug("IOMMU: tlb flush request %Lx, actual %Lx\n",
+ DMA_TLB_IIRG(type), DMA_TLB_IAIG(val));
+ /* flush context entry will implictly flush write buffer */
+ return 0;
+}
+
+static int inline iommu_flush_iotlb_global(struct intel_iommu *iommu,
+ int non_present_entry_flush)
+{
+ return __iommu_flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH,
+ non_present_entry_flush);
+}
+
+static int inline iommu_flush_iotlb_dsi(struct intel_iommu *iommu, u16 did,
+ int non_present_entry_flush)
+{
+ return __iommu_flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH,
+ non_present_entry_flush);
+}
+
+static int iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
+ u64 addr, unsigned int pages, int non_present_entry_flush)
+{
+ unsigned int mask;
+
+ BUG_ON(addr & (~PAGE_MASK_4K));
+ BUG_ON(pages == 0);
+
+ /* Fallback to domain selective flush if no PSI support */
+ if (!cap_pgsel_inv(iommu->cap))
+ return iommu_flush_iotlb_dsi(iommu, did,
+ non_present_entry_flush);
+
+ /*
+ * PSI requires page size to be 2 ^ x, and the base address is naturally
+ * aligned to the size
+ */
+ mask = ilog2(__roundup_pow_of_two(pages));
+ /* Fallback to domain selective flush if size is too big */
+ if (mask > cap_max_amask_val(iommu->cap))
+ return iommu_flush_iotlb_dsi(iommu, did,
+ non_present_entry_flush);
+
+ return __iommu_flush_iotlb(iommu, did, addr, mask,
+ DMA_TLB_PSI_FLUSH, non_present_entry_flush);
+}
+
+static int iommu_enable_translation(struct intel_iommu *iommu)
+{
+ u32 sts;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iommu->register_lock, flags);
+ writel(iommu->gcmd|DMA_GCMD_TE, iommu->reg + DMAR_GCMD_REG);
+
+ /* Make sure hardware complete it */
+ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+ readl, (sts & DMA_GSTS_TES), sts);
+
+ iommu->gcmd |= DMA_GCMD_TE;
+ spin_unlock_irqrestore(&iommu->register_lock, flags);
+ return 0;
+}
+
+static int iommu_disable_translation(struct intel_iommu *iommu)
+{
+ u32 sts;
+ unsigned long flag;
+
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ iommu->gcmd &= ~DMA_GCMD_TE;
+ writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);
+
+ /* Make sure hardware complete it */
+ IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
+ readl, (!(sts & DMA_GSTS_TES)), sts);
+
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+ return 0;
+}
+
+/* iommu interrupt handling. Most stuff are MSI-like. */
+
+static char *fault_reason_strings[] =
+{
+ "Software",
+ "Present bit in root entry is clear",
+ "Present bit in context entry is clear",
+ "Invalid context entry",
+ "Access beyond MGAW",
+ "PTE Write access is not set",
+ "PTE Read access is not set",
+ "Next page table ptr is invalid",
+ "Root table address invalid",
+ "Context table ptr is invalid",
+ "non-zero reserved fields in RTP",
+ "non-zero reserved fields in CTP",
+ "non-zero reserved fields in PTE",
+ "Unknown"
+};
+#define MAX_FAULT_REASON_IDX ARRAY_SIZE(fault_reason_strings) - 1
+
+char *dmar_get_fault_reason(u8 fault_reason)
+{
+ if (fault_reason >= MAX_FAULT_REASON_IDX)
+ return fault_reason_strings[MAX_FAULT_REASON_IDX - 1];
+ else
+ return fault_reason_strings[fault_reason];
+}
+
+void dmar_msi_unmask(unsigned int irq)
+{
+ struct intel_iommu *iommu = get_irq_data(irq);
+ unsigned long flag;
+
+ /* unmask it */
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ writel(0, iommu->reg + DMAR_FECTL_REG);
+ /* Read a reg to force flush the post write */
+ readl(iommu->reg + DMAR_FECTL_REG);
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+void dmar_msi_mask(unsigned int irq)
+{
+ unsigned long flag;
+ struct intel_iommu *iommu = get_irq_data(irq);
+
+ /* mask it */
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ writel(DMA_FECTL_IM, iommu->reg + DMAR_FECTL_REG);
+ /* Read a reg to force flush the post write */
+ readl(iommu->reg + DMAR_FECTL_REG);
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+void dmar_msi_write(int irq, struct msi_msg *msg)
+{
+ struct intel_iommu *iommu = get_irq_data(irq);
+ unsigned long flag;
+
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ writel(msg->data, iommu->reg + DMAR_FEDATA_REG);
+ writel(msg->address_lo, iommu->reg + DMAR_FEADDR_REG);
+ writel(msg->address_hi, iommu->reg + DMAR_FEUADDR_REG);
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+void dmar_msi_read(int irq, struct msi_msg *msg)
+{
+ struct intel_iommu *iommu = get_irq_data(irq);
+ unsigned long flag;
+
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ msg->data = readl(iommu->reg + DMAR_FEDATA_REG);
+ msg->address_lo = readl(iommu->reg + DMAR_FEADDR_REG);
+ msg->address_hi = readl(iommu->reg + DMAR_FEUADDR_REG);
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+}
+
+static int iommu_page_fault_do_one(struct intel_iommu *iommu, int type,
+ u8 fault_reason, u16 source_id, u64 addr)
+{
+ char *reason;
+
+ reason = dmar_get_fault_reason(fault_reason);
+
+ printk(KERN_ERR
+ "DMAR:[%s] Request device [%02x:%02x.%d] "
+ "fault addr %llx \n"
+ "DMAR:[fault reason %02d] %s\n",
+ (type ? "DMA Read" : "DMA Write"),
+ (source_id >> 8), PCI_SLOT(source_id & 0xFF),
+ PCI_FUNC(source_id & 0xFF), addr, fault_reason, reason);
+ return 0;
+}
+
+#define PRIMARY_FAULT_REG_LEN (16)
+static irqreturn_t iommu_page_fault(int irq, void *dev_id)
+{
+ struct intel_iommu *iommu = dev_id;
+ int reg, fault_index;
+ u32 fault_status;
+ unsigned long flag;
+
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ fault_status = readl(iommu->reg + DMAR_FSTS_REG);
+
+ /* TBD: ignore advanced fault log currently */
+ if (!(fault_status & DMA_FSTS_PPF))
+ goto clear_overflow;
+
+ fault_index = dma_fsts_fault_record_index(fault_status);
+ reg = cap_fault_reg_offset(iommu->cap);
+ while (1) {
+ u8 fault_reason;
+ u16 source_id;
+ u64 guest_addr;
+ int type;
+ u32 data;
+
+ /* highest 32 bits */
+ data = readl(iommu->reg + reg +
+ fault_index * PRIMARY_FAULT_REG_LEN + 12);
+ if (!(data & DMA_FRCD_F))
+ break;
+
+ fault_reason = dma_frcd_fault_reason(data);
+ type = dma_frcd_type(data);
+
+ data = readl(iommu->reg + reg +
+ fault_index * PRIMARY_FAULT_REG_LEN + 8);
+ source_id = dma_frcd_source_id(data);
+
+ guest_addr = dmar_readq(iommu->reg + reg +
+ fault_index * PRIMARY_FAULT_REG_LEN);
+ guest_addr = dma_frcd_page_addr(guest_addr);
+ /* clear the fault */
+ writel(DMA_FRCD_F, iommu->reg + reg +
+ fault_index * PRIMARY_FAULT_REG_LEN + 12);
+
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+
+ iommu_page_fault_do_one(iommu, type, fault_reason,
+ source_id, guest_addr);
+
+ fault_index++;
+ if (fault_index > cap_num_fault_regs(iommu->cap))
+ fault_index = 0;
+ spin_lock_irqsave(&iommu->register_lock, flag);
+ }
+clear_overflow:
+ /* clear primary fault overflow */
+ fault_status = readl(iommu->reg + DMAR_FSTS_REG);
+ if (fault_status & DMA_FSTS_PFO)
+ writel(DMA_FSTS_PFO, iommu->reg + DMAR_FSTS_REG);
+
+ spin_unlock_irqrestore(&iommu->register_lock, flag);
+ return IRQ_HANDLED;
+}
+
+int dmar_set_interrupt(struct intel_iommu *iommu)
+{
+ int irq, ret;
+
+ irq = create_irq();
+ if (!irq) {
+ printk(KERN_ERR "IOMMU: no free vectors\n");
+ return -EINVAL;
+ }
+
+ set_irq_data(irq, iommu);
+ iommu->irq = irq;
+
+ ret = arch_setup_dmar_msi(irq);
+ if (ret) {
+ set_irq_data(irq, NULL);
+ iommu->irq = 0;
+ destroy_irq(irq);
+ return 0;
+ }
+
+ /* Force fault register is cleared */
+ iommu_page_fault(irq, iommu);
+
+ ret = request_irq(irq, iommu_page_fault, 0, iommu->name, iommu);
+ if (ret)
+ printk(KERN_ERR "IOMMU: can't request irq\n");
+ return ret;
+}
+
+static int iommu_init_domains(struct intel_iommu *iommu)
+{
+ unsigned long ndomains;
+ unsigned long nlongs;
+
+ ndomains = cap_ndoms(iommu->cap);
+ pr_debug("Number of Domains supportd <%ld>\n", ndomains);
+ nlongs = BITS_TO_LONGS(ndomains);
+
+ /* TBD: there might be 64K domains,
+ * consider other allocation for future chip
+ */
+ iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
+ if (!iommu->domain_ids) {
+ printk(KERN_ERR "Allocating domain id array failed\n");
+ return -ENOMEM;
+ }
+ iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
+ GFP_KERNEL);
+ if (!iommu->domains) {
+ printk(KERN_ERR "Allocating domain array failed\n");
+ kfree(iommu->domain_ids);
+ return -ENOMEM;
+ }
+
+ /*
+ * if Caching mode is set, then invalid translations are tagged
+ * with domainid 0. Hence we need to pre-allocate it.
+ */
+ if (cap_caching_mode(iommu->cap))
+ set_bit(0, iommu->domain_ids);
+ return 0;
+}
+
+static struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd)
+{
+ struct intel_iommu *iommu;
+ int ret;
+ int map_size;
+ u32 ver;
+
+ iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+ if (!iommu)
+ return NULL;
+ iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K);
+ if (!iommu->reg) {
+ printk(KERN_ERR "IOMMU: can't map the region\n");
+ goto error;
+ }
+ iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
+ iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
+
+ /* the registers might be more than one page */
+ map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap),
+ cap_max_fault_reg_offset(iommu->cap));
+ map_size = PAGE_ALIGN_4K(map_size);
+ if (map_size > PAGE_SIZE_4K) {
+ iounmap(iommu->reg);
+ iommu->reg = ioremap(drhd->reg_base_addr, map_size);
+ if (!iommu->reg) {
+ printk(KERN_ERR "IOMMU: can't map the region\n");
+ goto error;
+ }
+ }
+
+ ver = readl(iommu->reg + DMAR_VER_REG);
+ pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
+ drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
+ iommu->cap, iommu->ecap);
+ ret = iommu_init_domains(iommu);
+ if (ret)
+ goto error_unmap;
+ spin_lock_init(&iommu->lock);
+ spin_lock_init(&iommu->register_lock);
+
+ drhd->iommu = iommu;
+ return iommu;
+error_unmap:
+ iounmap(iommu->reg);
+error:
+ kfree(iommu);
+ return NULL;
+}
+
+static void domain_exit(struct dmar_domain *domain);
+static void free_iommu(struct intel_iommu *iommu)
+{
+ struct dmar_domain *domain;
+ int i;
+
+ if (!iommu)
+ return;
+
+ i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
+ for (; i < cap_ndoms(iommu->cap); ) {
+ domain = iommu->domains[i];
+ clear_bit(i, iommu->domain_ids);
+ domain_exit(domain);
+ i = find_next_bit(iommu->domain_ids,
+ cap_ndoms(iommu->cap), i+1);
+ }
+
+ if (iommu->gcmd & DMA_GCMD_TE)
+ iommu_disable_translation(iommu);
+
+ if (iommu->irq) {
+ set_irq_data(iommu->irq, NULL);
+ /* This will mask the irq */
+ free_irq(iommu->irq, iommu);
+ destroy_irq(iommu->irq);
+ }
+
+ kfree(iommu->domains);
+ kfree(iommu->domain_ids);
+
+ /* free context mapping */
+ free_context_table(iommu);
+
+ if (iommu->reg)
+ iounmap(iommu->reg);
+ kfree(iommu);
+}
+
+static struct dmar_domain * iommu_alloc_domain(struct intel_iommu *iommu)
+{
+ unsigned long num;
+ unsigned long ndomains;
+ struct dmar_domain *domain;
+ unsigned long flags;
+
+ domain = alloc_domain_mem();
+ if (!domain)
+ return NULL;
+
+ ndomains = cap_ndoms(iommu->cap);
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ num = find_first_zero_bit(iommu->domain_ids, ndomains);
+ if (num >= ndomains) {
+ spin_unlock_irqrestore(&iommu->lock, flags);
+ free_domain_mem(domain);
+ printk(KERN_ERR "IOMMU: no free domain ids\n");
+ return NULL;
+ }
+
+ set_bit(num, iommu->domain_ids);
+ domain->id = num;
+ domain->iommu = iommu;
+ iommu->domains[num] = domain;
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ return domain;
+}
+
+static void iommu_free_domain(struct dmar_domain *domain)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&domain->iommu->lock, flags);
+ clear_bit(domain->id, domain->iommu->domain_ids);
+ spin_unlock_irqrestore(&domain->iommu->lock, flags);
+}
+
+static struct iova_domain reserved_iova_list;
+
+static void dmar_init_reserved_ranges(void)
+{
+ struct pci_dev *pdev = NULL;
+ struct iova *iova;
+ int i;
+ u64 addr, size;
+
+ init_iova_domain(&reserved_iova_list);
+
+ /* IOAPIC ranges shouldn't be accessed by DMA */
+ iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START),
+ IOVA_PFN(IOAPIC_RANGE_END));
+ if (!iova)
+ printk(KERN_ERR "Reserve IOAPIC range failed\n");
+
+ /* Reserve all PCI MMIO to avoid peer-to-peer access */
+ for_each_pci_dev(pdev) {
+ struct resource *r;
+
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ r = &pdev->resource[i];
+ if (!r->flags || !(r->flags & IORESOURCE_MEM))
+ continue;
+ addr = r->start;
+ addr &= PAGE_MASK_4K;
+ size = r->end - addr;
+ size = PAGE_ALIGN_4K(size);
+ iova = reserve_iova(&reserved_iova_list, IOVA_PFN(addr),
+ IOVA_PFN(size + addr) - 1);
+ if (!iova)
+ printk(KERN_ERR "Reserve iova failed\n");
+ }
+ }
+
+}
+
+static void domain_reserve_special_ranges(struct dmar_domain *domain)
+{
+ copy_reserved_iova(&reserved_iova_list, &domain->iovad);
+}
+
+static inline int guestwidth_to_adjustwidth(int gaw)
+{
+ int agaw;
+ int r = (gaw - 12) % 9;
+
+ if (r == 0)
+ agaw = gaw;
+ else
+ agaw = gaw + 9 - r;
+ if (agaw > 64)
+ agaw = 64;
+ return agaw;
+}
+
+static int domain_init(struct dmar_domain *domain, int guest_width)
+{
+ struct intel_iommu *iommu;
+ int adjust_width, agaw;
+ unsigned long sagaw;
+
+ init_iova_domain(&domain->iovad);
+ spin_lock_init(&domain->mapping_lock);
+
+ domain_reserve_special_ranges(domain);
+
+ /* calculate AGAW */
+ iommu = domain->iommu;
+ if (guest_width > cap_mgaw(iommu->cap))
+ guest_width = cap_mgaw(iommu->cap);
+ domain->gaw = guest_width;
+ adjust_width = guestwidth_to_adjustwidth(guest_width);
+ agaw = width_to_agaw(adjust_width);
+ sagaw = cap_sagaw(iommu->cap);
+ if (!test_bit(agaw, &sagaw)) {
+ /* hardware doesn't support it, choose a bigger one */
+ pr_debug("IOMMU: hardware doesn't support agaw %d\n", agaw);
+ agaw = find_next_bit(&sagaw, 5, agaw);
+ if (agaw >= 5)
+ return -ENODEV;
+ }
+ domain->agaw = agaw;
+ INIT_LIST_HEAD(&domain->devices);
+
+ /* always allocate the top pgd */
+ domain->pgd = (struct dma_pte *)alloc_pgtable_page();
+ if (!domain->pgd)
+ return -ENOMEM;
+ __iommu_flush_cache(iommu, domain->pgd, PAGE_SIZE_4K);
+ return 0;
+}
+
+static void domain_exit(struct dmar_domain *domain)
+{
+ u64 end;
+
+ /* Domain 0 is reserved, so dont process it */
+ if (!domain)
+ return;
+
+ domain_remove_dev_info(domain);
+ /* destroy iovas */
+ put_iova_domain(&domain->iovad);
+ end = DOMAIN_MAX_ADDR(domain->gaw);
+ end = end & (~PAGE_MASK_4K);
+
+ /* clear ptes */
+ dma_pte_clear_range(domain, 0, end);
+
+ /* free page tables */
+ dma_pte_free_pagetable(domain, 0, end);
+
+ iommu_free_domain(domain);
+ free_domain_mem(domain);
+}
+
+static int domain_context_mapping_one(struct dmar_domain *domain,
+ u8 bus, u8 devfn)
+{
+ struct context_entry *context;
+ struct intel_iommu *iommu = domain->iommu;
+ unsigned long flags;
+
+ pr_debug("Set context mapping for %02x:%02x.%d\n",
+ bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+ BUG_ON(!domain->pgd);
+ context = device_to_context_entry(iommu, bus, devfn);
+ if (!context)
+ return -ENOMEM;
+ spin_lock_irqsave(&iommu->lock, flags);
+ if (context_present(*context)) {
+ spin_unlock_irqrestore(&iommu->lock, flags);
+ return 0;
+ }
+
+ context_set_domain_id(*context, domain->id);
+ context_set_address_width(*context, domain->agaw);
+ context_set_address_root(*context, virt_to_phys(domain->pgd));
+ context_set_translation_type(*context, CONTEXT_TT_MULTI_LEVEL);
+ context_set_fault_enable(*context);
+ context_set_present(*context);
+ __iommu_flush_cache(iommu, context, sizeof(*context));
+
+ /* it's a non-present to present mapping */
+ if (iommu_flush_context_device(iommu, domain->id,
+ (((u16)bus) << 8) | devfn, DMA_CCMD_MASK_NOBIT, 1))
+ iommu_flush_write_buffer(iommu);
+ else
+ iommu_flush_iotlb_dsi(iommu, 0, 0);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+ return 0;
+}
+
+static int
+domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev)
+{
+ int ret;
+ struct pci_dev *tmp, *parent;
+
+ ret = domain_context_mapping_one(domain, pdev->bus->number,
+ pdev->devfn);
+ if (ret)
+ return ret;
+
+ /* dependent device mapping */
+ tmp = pci_find_upstream_pcie_bridge(pdev);
+ if (!tmp)
+ return 0;
+ /* Secondary interface's bus number and devfn 0 */
+ parent = pdev->bus->self;
+ while (parent != tmp) {
+ ret = domain_context_mapping_one(domain, parent->bus->number,
+ parent->devfn);
+ if (ret)
+ return ret;
+ parent = parent->bus->self;
+ }
+ if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */
+ return domain_context_mapping_one(domain,
+ tmp->subordinate->number, 0);
+ else /* this is a legacy PCI bridge */
+ return domain_context_mapping_one(domain,
+ tmp->bus->number, tmp->devfn);
+}
+
+static int domain_context_mapped(struct dmar_domain *domain,
+ struct pci_dev *pdev)
+{
+ int ret;
+ struct pci_dev *tmp, *parent;
+
+ ret = device_context_mapped(domain->iommu,
+ pdev->bus->number, pdev->devfn);
+ if (!ret)
+ return ret;
+ /* dependent device mapping */
+ tmp = pci_find_upstream_pcie_bridge(pdev);
+ if (!tmp)
+ return ret;
+ /* Secondary interface's bus number and devfn 0 */
+ parent = pdev->bus->self;
+ while (parent != tmp) {
+ ret = device_context_mapped(domain->iommu, parent->bus->number,
+ parent->devfn);
+ if (!ret)
+ return ret;
+ parent = parent->bus->self;
+ }
+ if (tmp->is_pcie)
+ return device_context_mapped(domain->iommu,
+ tmp->subordinate->number, 0);
+ else
+ return device_context_mapped(domain->iommu,
+ tmp->bus->number, tmp->devfn);
+}
+
+static int
+domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
+ u64 hpa, size_t size, int prot)
+{
+ u64 start_pfn, end_pfn;
+ struct dma_pte *pte;
+ int index;
+
+ if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
+ return -EINVAL;
+ iova &= PAGE_MASK_4K;
+ start_pfn = ((u64)hpa) >> PAGE_SHIFT_4K;
+ end_pfn = (PAGE_ALIGN_4K(((u64)hpa) + size)) >> PAGE_SHIFT_4K;
+ index = 0;
+ while (start_pfn < end_pfn) {
+ pte = addr_to_dma_pte(domain, iova + PAGE_SIZE_4K * index);
+ if (!pte)
+ return -ENOMEM;
+ /* We don't need lock here, nobody else
+ * touches the iova range
+ */
+ BUG_ON(dma_pte_addr(*pte));
+ dma_set_pte_addr(*pte, start_pfn << PAGE_SHIFT_4K);
+ dma_set_pte_prot(*pte, prot);
+ __iommu_flush_cache(domain->iommu, pte, sizeof(*pte));
+ start_pfn++;
+ index++;
+ }
+ return 0;
+}
+
+static void detach_domain_for_dev(struct dmar_domain *domain, u8 bus, u8 devfn)
+{
+ clear_context_table(domain->iommu, bus, devfn);
+ iommu_flush_context_global(domain->iommu, 0);
+ iommu_flush_iotlb_global(domain->iommu, 0);
+}
+
+static void domain_remove_dev_info(struct dmar_domain *domain)
+{
+ struct device_domain_info *info;
+ unsigned long flags;
+
+ spin_lock_irqsave(&device_domain_lock, flags);
+ while (!list_empty(&domain->devices)) {
+ info = list_entry(domain->devices.next,
+ struct device_domain_info, link);
+ list_del(&info->link);
+ list_del(&info->global);
+ if (info->dev)
+ info->dev->dev.archdata.iommu = NULL;
+ spin_unlock_irqrestore(&device_domain_lock, flags);
+
+ detach_domain_for_dev(info->domain, info->bus, info->devfn);
+ free_devinfo_mem(info);
+
+ spin_lock_irqsave(&device_domain_lock, flags);
+ }
+ spin_unlock_irqrestore(&device_domain_lock, flags);
+}
+
+/*
+ * find_domain
+ * Note: we use struct pci_dev->dev.archdata.iommu stores the info
+ */
+struct dmar_domain *
+find_domain(struct pci_dev *pdev)
+{
+ struct device_domain_info *info;
+
+ /* No lock here, assumes no domain exit in normal case */
+ info = pdev->dev.archdata.iommu;
+ if (info)
+ return info->domain;
+ return NULL;
+}
+
+static int dmar_pci_device_match(struct pci_dev *devices[], int cnt,
+ struct pci_dev *dev)
+{
+ int index;
+
+ while (dev) {
+ for (index = 0; index < cnt; index ++)
+ if (dev == devices[index])
+ return 1;
+
+ /* Check our parent */
+ dev = dev->bus->self;
+ }
+
+ return 0;
+}
+
+static struct dmar_drhd_unit *
+dmar_find_matched_drhd_unit(struct pci_dev *dev)
+{
+ struct dmar_drhd_unit *drhd = NULL;
+
+ list_for_each_entry(drhd, &dmar_drhd_units, list) {
+ if (drhd->include_all || dmar_pci_device_match(drhd->devices,
+ drhd->devices_cnt, dev))
+ return drhd;
+ }
+
+ return NULL;
+}
+
+/* domain is initialized */
+static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
+{
+ struct dmar_domain *domain, *found = NULL;
+ struct intel_iommu *iommu;
+ struct dmar_drhd_unit *drhd;
+ struct device_domain_info *info, *tmp;
+ struct pci_dev *dev_tmp;
+ unsigned long flags;
+ int bus = 0, devfn = 0;
+
+ domain = find_domain(pdev);
+ if (domain)
+ return domain;
+
+ dev_tmp = pci_find_upstream_pcie_bridge(pdev);
+ if (dev_tmp) {
+ if (dev_tmp->is_pcie) {
+ bus = dev_tmp->subordinate->number;
+ devfn = 0;
+ } else {
+ bus = dev_tmp->bus->number;
+ devfn = dev_tmp->devfn;
+ }
+ spin_lock_irqsave(&device_domain_lock, flags);
+ list_for_each_entry(info, &device_domain_list, global) {
+ if (info->bus == bus && info->devfn == devfn) {
+ found = info->domain;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&device_domain_lock, flags);
+ /* pcie-pci bridge already has a domain, uses it */
+ if (found) {
+ domain = found;
+ goto found_domain;
+ }
+ }
+
+ /* Allocate new domain for the device */
+ drhd = dmar_find_matched_drhd_unit(pdev);
+ if (!drhd) {
+ printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
+ pci_name(pdev));
+ return NULL;
+ }
+ iommu = drhd->iommu;
+
+ domain = iommu_alloc_domain(iommu);
+ if (!domain)
+ goto error;
+
+ if (domain_init(domain, gaw)) {
+ domain_exit(domain);
+ goto error;
+ }
+
+ /* register pcie-to-pci device */
+ if (dev_tmp) {
+ info = alloc_devinfo_mem();
+ if (!info) {
+ domain_exit(domain);
+ goto error;
+ }
+ info->bus = bus;
+ info->devfn = devfn;
+ info->dev = NULL;
+ info->domain = domain;
+ /* This domain is shared by devices under p2p bridge */
+ domain->flags |= DOMAIN_FLAG_MULTIPLE_DEVICES;
+
+ /* pcie-to-pci bridge already has a domain, uses it */
+ found = NULL;
+ spin_lock_irqsave(&device_domain_lock, flags);
+ list_for_each_entry(tmp, &device_domain_list, global) {
+ if (tmp->bus == bus && tmp->devfn == devfn) {
+ found = tmp->domain;
+ break;
+ }
+ }
+ if (found) {
+ free_devinfo_mem(info);
+ domain_exit(domain);
+ domain = found;
+ } else {
+ list_add(&info->link, &domain->devices);
+ list_add(&info->global, &device_domain_list);
+ }
+ spin_unlock_irqrestore(&device_domain_lock, flags);
+ }
+
+found_domain:
+ info = alloc_devinfo_mem();
+ if (!info)
+ goto error;
+ info->bus = pdev->bus->number;
+ info->devfn = pdev->devfn;
+ info->dev = pdev;
+ info->domain = domain;
+ spin_lock_irqsave(&device_domain_lock, flags);
+ /* somebody is fast */
+ found = find_domain(pdev);
+ if (found != NULL) {
+ spin_unlock_irqrestore(&device_domain_lock, flags);
+ if (found != domain) {
+ domain_exit(domain);
+ domain = found;
+ }
+ free_devinfo_mem(info);
+ return domain;
+ }
+ list_add(&info->link, &domain->devices);
+ list_add(&info->global, &device_domain_list);
+ pdev->dev.archdata.iommu = info;
+ spin_unlock_irqrestore(&device_domain_lock, flags);
+ return domain;
+error:
+ /* recheck it here, maybe others set it */
+ return find_domain(pdev);
+}
+
+static int iommu_prepare_identity_map(struct pci_dev *pdev, u64 start, u64 end)
+{
+ struct dmar_domain *domain;
+ unsigned long size;
+ u64 base;
+ int ret;
+
+ printk(KERN_INFO
+ "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
+ pci_name(pdev), start, end);
+ /* page table init */
+ domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
+ if (!domain)
+ return -ENOMEM;
+
+ /* The address might not be aligned */
+ base = start & PAGE_MASK_4K;
+ size = end - base;
+ size = PAGE_ALIGN_4K(size);
+ if (!reserve_iova(&domain->iovad, IOVA_PFN(base),
+ IOVA_PFN(base + size) - 1)) {
+ printk(KERN_ERR "IOMMU: reserve iova failed\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ pr_debug("Mapping reserved region %lx@%llx for %s\n",
+ size, base, pci_name(pdev));
+ /*
+ * RMRR range might have overlap with physical memory range,
+ * clear it first
+ */
+ dma_pte_clear_range(domain, base, base + size);
+
+ ret = domain_page_mapping(domain, base, base, size,
+ DMA_PTE_READ|DMA_PTE_WRITE);
+ if (ret)
+ goto error;
+
+ /* context entry init */
+ ret = domain_context_mapping(domain, pdev);
+ if (!ret)
+ return 0;
+error:
+ domain_exit(domain);
+ return ret;
+
+}
+
+static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
+ struct pci_dev *pdev)
+{
+ if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+ return 0;
+ return iommu_prepare_identity_map(pdev, rmrr->base_address,
+ rmrr->end_address + 1);
+}
+
+#ifdef CONFIG_DMAR_GFX_WA
+extern int arch_get_ram_range(int slot, u64 *addr, u64 *size);
+static void __init iommu_prepare_gfx_mapping(void)
+{
+ struct pci_dev *pdev = NULL;
+ u64 base, size;
+ int slot;
+ int ret;
+
+ for_each_pci_dev(pdev) {
+ if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO ||
+ !IS_GFX_DEVICE(pdev))
+ continue;
+ printk(KERN_INFO "IOMMU: gfx device %s 1-1 mapping\n",
+ pci_name(pdev));
+ slot = arch_get_ram_range(0, &base, &size);
+ while (slot >= 0) {
+ ret = iommu_prepare_identity_map(pdev,
+ base, base + size);
+ if (ret)
+ goto error;
+ slot = arch_get_ram_range(slot, &base, &size);
+ }
+ continue;
+error:
+ printk(KERN_ERR "IOMMU: mapping reserved region failed\n");
+ }
+}
+#endif
+
+#ifdef CONFIG_DMAR_FLOPPY_WA
+static inline void iommu_prepare_isa(void)
+{
+ struct pci_dev *pdev;
+ int ret;
+
+ pdev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
+ if (!pdev)
+ return;
+
+ printk(KERN_INFO "IOMMU: Prepare 0-16M unity mapping for LPC\n");
+ ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
+
+ if (ret)
+ printk("IOMMU: Failed to create 0-64M identity map, "
+ "floppy might not work\n");
+
+}
+#else
+static inline void iommu_prepare_isa(void)
+{
+ return;
+}
+#endif /* !CONFIG_DMAR_FLPY_WA */
+
+int __init init_dmars(void)
+{
+ struct dmar_drhd_unit *drhd;
+ struct dmar_rmrr_unit *rmrr;
+ struct pci_dev *pdev;
+ struct intel_iommu *iommu;
+ int ret, unit = 0;
+
+ /*
+ * for each drhd
+ * allocate root
+ * initialize and program root entry to not present
+ * endfor
+ */
+ for_each_drhd_unit(drhd) {
+ if (drhd->ignored)
+ continue;
+ iommu = alloc_iommu(drhd);
+ if (!iommu) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /*
+ * TBD:
+ * we could share the same root & context tables
+ * amoung all IOMMU's. Need to Split it later.
+ */
+ ret = iommu_alloc_root_entry(iommu);
+ if (ret) {
+ printk(KERN_ERR "IOMMU: allocate root entry failed\n");
+ goto error;
+ }
+ }
+
+ /*
+ * For each rmrr
+ * for each dev attached to rmrr
+ * do
+ * locate drhd for dev, alloc domain for dev
+ * allocate free domain
+ * allocate page table entries for rmrr
+ * if context not allocated for bus
+ * allocate and init context
+ * set present in root table for this bus
+ * init context with domain, translation etc
+ * endfor
+ * endfor
+ */
+ for_each_rmrr_units(rmrr) {
+ int i;
+ for (i = 0; i < rmrr->devices_cnt; i++) {
+ pdev = rmrr->devices[i];
+ /* some BIOS lists non-exist devices in DMAR table */
+ if (!pdev)
+ continue;
+ ret = iommu_prepare_rmrr_dev(rmrr, pdev);
+ if (ret)
+ printk(KERN_ERR
+ "IOMMU: mapping reserved region failed\n");
+ }
+ }
+
+ iommu_prepare_gfx_mapping();
+
+ iommu_prepare_isa();
+
+ /*
+ * for each drhd
+ * enable fault log
+ * global invalidate context cache
+ * global invalidate iotlb
+ * enable translation
+ */
+ for_each_drhd_unit(drhd) {
+ if (drhd->ignored)
+ continue;
+ iommu = drhd->iommu;
+ sprintf (iommu->name, "dmar%d", unit++);
+
+ iommu_flush_write_buffer(iommu);
+
+ ret = dmar_set_interrupt(iommu);
+ if (ret)
+ goto error;
+
+ iommu_set_root_entry(iommu);
+
+ iommu_flush_context_global(iommu, 0);
+ iommu_flush_iotlb_global(iommu, 0);
+
+ ret = iommu_enable_translation(iommu);
+ if (ret)
+ goto error;
+ }
+
+ return 0;
+error:
+ for_each_drhd_unit(drhd) {
+ if (drhd->ignored)
+ continue;
+ iommu = drhd->iommu;
+ free_iommu(iommu);
+ }
+ return ret;
+}
+
+static inline u64 aligned_size(u64 host_addr, size_t size)
+{
+ u64 addr;
+ addr = (host_addr & (~PAGE_MASK_4K)) + size;
+ return PAGE_ALIGN_4K(addr);
+}
+
+struct iova *
+iommu_alloc_iova(struct dmar_domain *domain, size_t size, u64 end)
+{
+ struct iova *piova;
+
+ /* Make sure it's in range */
+ end = min_t(u64, DOMAIN_MAX_ADDR(domain->gaw), end);
+ if (!size || (IOVA_START_ADDR + size > end))
+ return NULL;
+
+ piova = alloc_iova(&domain->iovad,
+ size >> PAGE_SHIFT_4K, IOVA_PFN(end), 1);
+ return piova;
+}
+
+static struct iova *
+__intel_alloc_iova(struct device *dev, struct dmar_domain *domain,
+ size_t size)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct iova *iova = NULL;
+
+ if ((pdev->dma_mask <= DMA_32BIT_MASK) || (dmar_forcedac)) {
+ iova = iommu_alloc_iova(domain, size, pdev->dma_mask);
+ } else {
+ /*
+ * First try to allocate an io virtual address in
+ * DMA_32BIT_MASK and if that fails then try allocating
+ * from higer range
+ */
+ iova = iommu_alloc_iova(domain, size, DMA_32BIT_MASK);
+ if (!iova)
+ iova = iommu_alloc_iova(domain, size, pdev->dma_mask);
+ }
+
+ if (!iova) {
+ printk(KERN_ERR"Allocating iova for %s failed", pci_name(pdev));
+ return NULL;
+ }
+
+ return iova;
+}
+
+static struct dmar_domain *
+get_valid_domain_for_dev(struct pci_dev *pdev)
+{
+ struct dmar_domain *domain;
+ int ret;
+
+ domain = get_domain_for_dev(pdev,
+ DEFAULT_DOMAIN_ADDRESS_WIDTH);
+ if (!domain) {
+ printk(KERN_ERR
+ "Allocating domain for %s failed", pci_name(pdev));
+ return NULL;
+ }
+
+ /* make sure context mapping is ok */
+ if (unlikely(!domain_context_mapped(domain, pdev))) {
+ ret = domain_context_mapping(domain, pdev);
+ if (ret) {
+ printk(KERN_ERR
+ "Domain context map for %s failed",
+ pci_name(pdev));
+ return NULL;
+ }
+ }
+
+ return domain;
+}
+
+static dma_addr_t intel_map_single(struct device *hwdev, void *addr,
+ size_t size, int dir)
+{
+ struct pci_dev *pdev = to_pci_dev(hwdev);
+ int ret;
+ struct dmar_domain *domain;
+ unsigned long start_addr;
+ struct iova *iova;
+ int prot = 0;
+
+ BUG_ON(dir == DMA_NONE);
+ if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+ return virt_to_bus(addr);
+
+ domain = get_valid_domain_for_dev(pdev);
+ if (!domain)
+ return 0;
+
+ addr = (void *)virt_to_phys(addr);
+ size = aligned_size((u64)addr, size);
+
+ iova = __intel_alloc_iova(hwdev, domain, size);
+ if (!iova)
+ goto error;
+
+ start_addr = iova->pfn_lo << PAGE_SHIFT_4K;
+
+ /*
+ * Check if DMAR supports zero-length reads on write only
+ * mappings..
+ */
+ if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
+ !cap_zlr(domain->iommu->cap))
+ prot |= DMA_PTE_READ;
+ if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
+ prot |= DMA_PTE_WRITE;
+ /*
+ * addr - (addr + size) might be partial page, we should map the whole
+ * page. Note: if two part of one page are separately mapped, we
+ * might have two guest_addr mapping to the same host addr, but this
+ * is not a big problem
+ */
+ ret = domain_page_mapping(domain, start_addr,
+ ((u64)addr) & PAGE_MASK_4K, size, prot);
+ if (ret)
+ goto error;
+
+ pr_debug("Device %s request: %lx@%llx mapping: %lx@%llx, dir %d\n",
+ pci_name(pdev), size, (u64)addr,
+ size, (u64)start_addr, dir);
+
+ /* it's a non-present to present mapping */
+ ret = iommu_flush_iotlb_psi(domain->iommu, domain->id,
+ start_addr, size >> PAGE_SHIFT_4K, 1);
+ if (ret)
+ iommu_flush_write_buffer(domain->iommu);
+
+ return (start_addr + ((u64)addr & (~PAGE_MASK_4K)));
+
+error:
+ if (iova)
+ __free_iova(&domain->iovad, iova);
+ printk(KERN_ERR"Device %s request: %lx@%llx dir %d --- failed\n",
+ pci_name(pdev), size, (u64)addr, dir);
+ return 0;
+}
+
+static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr,
+ size_t size, int dir)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct dmar_domain *domain;
+ unsigned long start_addr;
+ struct iova *iova;
+
+ if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+ return;
+ domain = find_domain(pdev);
+ BUG_ON(!domain);
+
+ iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
+ if (!iova)
+ return;
+
+ start_addr = iova->pfn_lo << PAGE_SHIFT_4K;
+ size = aligned_size((u64)dev_addr, size);
+
+ pr_debug("Device %s unmapping: %lx@%llx\n",
+ pci_name(pdev), size, (u64)start_addr);
+
+ /* clear the whole page */
+ dma_pte_clear_range(domain, start_addr, start_addr + size);
+ /* free page tables */
+ dma_pte_free_pagetable(domain, start_addr, start_addr + size);
+
+ if (iommu_flush_iotlb_psi(domain->iommu, domain->id, start_addr,
+ size >> PAGE_SHIFT_4K, 0))
+ iommu_flush_write_buffer(domain->iommu);
+
+ /* free iova */
+ __free_iova(&domain->iovad, iova);
+}
+
+static void * intel_alloc_coherent(struct device *hwdev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flags)
+{
+ void *vaddr;
+ int order;
+
+ size = PAGE_ALIGN_4K(size);
+ order = get_order(size);
+ flags &= ~(GFP_DMA | GFP_DMA32);
+
+ vaddr = (void *)__get_free_pages(flags, order);
+ if (!vaddr)
+ return NULL;
+ memset(vaddr, 0, size);
+
+ *dma_handle = intel_map_single(hwdev, vaddr, size, DMA_BIDIRECTIONAL);
+ if (*dma_handle)
+ return vaddr;
+ free_pages((unsigned long)vaddr, order);
+ return NULL;
+}
+
+static void intel_free_coherent(struct device *hwdev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+ int order;
+
+ size = PAGE_ALIGN_4K(size);
+ order = get_order(size);
+
+ intel_unmap_single(hwdev, dma_handle, size, DMA_BIDIRECTIONAL);
+ free_pages((unsigned long)vaddr, order);
+}
+
+#define SG_ENT_VIRT_ADDRESS(sg) (sg_virt((sg)))
+static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
+ int nelems, int dir)
+{
+ int i;
+ struct pci_dev *pdev = to_pci_dev(hwdev);
+ struct dmar_domain *domain;
+ unsigned long start_addr;
+ struct iova *iova;
+ size_t size = 0;
+ void *addr;
+ struct scatterlist *sg;
+
+ if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+ return;
+
+ domain = find_domain(pdev);
+
+ iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
+ if (!iova)
+ return;
+ for_each_sg(sglist, sg, nelems, i) {
+ addr = SG_ENT_VIRT_ADDRESS(sg);
+ size += aligned_size((u64)addr, sg->length);
+ }
+
+ start_addr = iova->pfn_lo << PAGE_SHIFT_4K;
+
+ /* clear the whole page */
+ dma_pte_clear_range(domain, start_addr, start_addr + size);
+ /* free page tables */
+ dma_pte_free_pagetable(domain, start_addr, start_addr + size);
+
+ if (iommu_flush_iotlb_psi(domain->iommu, domain->id, start_addr,
+ size >> PAGE_SHIFT_4K, 0))
+ iommu_flush_write_buffer(domain->iommu);
+
+ /* free iova */
+ __free_iova(&domain->iovad, iova);
+}
+
+static int intel_nontranslate_map_sg(struct device *hddev,
+ struct scatterlist *sglist, int nelems, int dir)
+{
+ int i;
+ struct scatterlist *sg;
+
+ for_each_sg(sglist, sg, nelems, i) {
+ BUG_ON(!sg_page(sg));
+ sg->dma_address = virt_to_bus(SG_ENT_VIRT_ADDRESS(sg));
+ sg->dma_length = sg->length;
+ }
+ return nelems;
+}
+
+static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist,
+ int nelems, int dir)
+{
+ void *addr;
+ int i;
+ struct pci_dev *pdev = to_pci_dev(hwdev);
+ struct dmar_domain *domain;
+ size_t size = 0;
+ int prot = 0;
+ size_t offset = 0;
+ struct iova *iova = NULL;
+ int ret;
+ struct scatterlist *sg;
+ unsigned long start_addr;
+
+ BUG_ON(dir == DMA_NONE);
+ if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
+ return intel_nontranslate_map_sg(hwdev, sglist, nelems, dir);
+
+ domain = get_valid_domain_for_dev(pdev);
+ if (!domain)
+ return 0;
+
+ for_each_sg(sglist, sg, nelems, i) {
+ addr = SG_ENT_VIRT_ADDRESS(sg);
+ addr = (void *)virt_to_phys(addr);
+ size += aligned_size((u64)addr, sg->length);
+ }
+
+ iova = __intel_alloc_iova(hwdev, domain, size);
+ if (!iova) {
+ sglist->dma_length = 0;
+ return 0;
+ }
+
+ /*
+ * Check if DMAR supports zero-length reads on write only
+ * mappings..
+ */
+ if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL || \
+ !cap_zlr(domain->iommu->cap))
+ prot |= DMA_PTE_READ;
+ if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
+ prot |= DMA_PTE_WRITE;
+
+ start_addr = iova->pfn_lo << PAGE_SHIFT_4K;
+ offset = 0;
+ for_each_sg(sglist, sg, nelems, i) {
+ addr = SG_ENT_VIRT_ADDRESS(sg);
+ addr = (void *)virt_to_phys(addr);
+ size = aligned_size((u64)addr, sg->length);
+ ret = domain_page_mapping(domain, start_addr + offset,
+ ((u64)addr) & PAGE_MASK_4K,
+ size, prot);
+ if (ret) {
+ /* clear the page */
+ dma_pte_clear_range(domain, start_addr,
+ start_addr + offset);
+ /* free page tables */
+ dma_pte_free_pagetable(domain, start_addr,
+ start_addr + offset);
+ /* free iova */
+ __free_iova(&domain->iovad, iova);
+ return 0;
+ }
+ sg->dma_address = start_addr + offset +
+ ((u64)addr & (~PAGE_MASK_4K));
+ sg->dma_length = sg->length;
+ offset += size;
+ }
+
+ /* it's a non-present to present mapping */
+ if (iommu_flush_iotlb_psi(domain->iommu, domain->id,
+ start_addr, offset >> PAGE_SHIFT_4K, 1))
+ iommu_flush_write_buffer(domain->iommu);
+ return nelems;
+}
+
+static struct dma_mapping_ops intel_dma_ops = {
+ .alloc_coherent = intel_alloc_coherent,
+ .free_coherent = intel_free_coherent,
+ .map_single = intel_map_single,
+ .unmap_single = intel_unmap_single,
+ .map_sg = intel_map_sg,
+ .unmap_sg = intel_unmap_sg,
+};
+
+static inline int iommu_domain_cache_init(void)
+{
+ int ret = 0;
+
+ iommu_domain_cache = kmem_cache_create("iommu_domain",
+ sizeof(struct dmar_domain),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+
+ NULL);
+ if (!iommu_domain_cache) {
+ printk(KERN_ERR "Couldn't create iommu_domain cache\n");
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+
+static inline int iommu_devinfo_cache_init(void)
+{
+ int ret = 0;
+
+ iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
+ sizeof(struct device_domain_info),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+
+ NULL);
+ if (!iommu_devinfo_cache) {
+ printk(KERN_ERR "Couldn't create devinfo cache\n");
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+
+static inline int iommu_iova_cache_init(void)
+{
+ int ret = 0;
+
+ iommu_iova_cache = kmem_cache_create("iommu_iova",
+ sizeof(struct iova),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+
+ NULL);
+ if (!iommu_iova_cache) {
+ printk(KERN_ERR "Couldn't create iova cache\n");
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+
+static int __init iommu_init_mempool(void)
+{
+ int ret;
+ ret = iommu_iova_cache_init();
+ if (ret)
+ return ret;
+
+ ret = iommu_domain_cache_init();
+ if (ret)
+ goto domain_error;
+
+ ret = iommu_devinfo_cache_init();
+ if (!ret)
+ return ret;
+
+ kmem_cache_destroy(iommu_domain_cache);
+domain_error:
+ kmem_cache_destroy(iommu_iova_cache);
+
+ return -ENOMEM;
+}
+
+static void __init iommu_exit_mempool(void)
+{
+ kmem_cache_destroy(iommu_devinfo_cache);
+ kmem_cache_destroy(iommu_domain_cache);
+ kmem_cache_destroy(iommu_iova_cache);
+
+}
+
+void __init detect_intel_iommu(void)
+{
+ if (swiotlb || no_iommu || iommu_detected || dmar_disabled)
+ return;
+ if (early_dmar_detect()) {
+ iommu_detected = 1;
+ }
+}
+
+static void __init init_no_remapping_devices(void)
+{
+ struct dmar_drhd_unit *drhd;
+
+ for_each_drhd_unit(drhd) {
+ if (!drhd->include_all) {
+ int i;
+ for (i = 0; i < drhd->devices_cnt; i++)
+ if (drhd->devices[i] != NULL)
+ break;
+ /* ignore DMAR unit if no pci devices exist */
+ if (i == drhd->devices_cnt)
+ drhd->ignored = 1;
+ }
+ }
+
+ if (dmar_map_gfx)
+ return;
+
+ for_each_drhd_unit(drhd) {
+ int i;
+ if (drhd->ignored || drhd->include_all)
+ continue;
+
+ for (i = 0; i < drhd->devices_cnt; i++)
+ if (drhd->devices[i] &&
+ !IS_GFX_DEVICE(drhd->devices[i]))
+ break;
+
+ if (i < drhd->devices_cnt)
+ continue;
+
+ /* bypass IOMMU if it is just for gfx devices */
+ drhd->ignored = 1;
+ for (i = 0; i < drhd->devices_cnt; i++) {
+ if (!drhd->devices[i])
+ continue;
+ drhd->devices[i]->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
+ }
+ }
+}
+
+int __init intel_iommu_init(void)
+{
+ int ret = 0;
+
+ if (no_iommu || swiotlb || dmar_disabled)
+ return -ENODEV;
+
+ if (dmar_table_init())
+ return -ENODEV;
+
+ iommu_init_mempool();
+ dmar_init_reserved_ranges();
+
+ init_no_remapping_devices();
+
+ ret = init_dmars();
+ if (ret) {
+ printk(KERN_ERR "IOMMU: dmar init failed\n");
+ put_iova_domain(&reserved_iova_list);
+ iommu_exit_mempool();
+ return ret;
+ }
+ printk(KERN_INFO
+ "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
+
+ force_iommu = 1;
+ dma_ops = &intel_dma_ops;
+ return 0;
+}
+
diff --git a/drivers/pci/intel-iommu.h b/drivers/pci/intel-iommu.h
new file mode 100644
index 00000000000..459ad1f9dc5
--- /dev/null
+++ b/drivers/pci/intel-iommu.h
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2006, 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Copyright (C) Ashok Raj <ashok.raj@intel.com>
+ * Copyright (C) Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ */
+
+#ifndef _INTEL_IOMMU_H_
+#define _INTEL_IOMMU_H_
+
+#include <linux/types.h>
+#include <linux/msi.h>
+#include "iova.h"
+#include <linux/io.h>
+
+/*
+ * Intel IOMMU register specification per version 1.0 public spec.
+ */
+
+#define DMAR_VER_REG 0x0 /* Arch version supported by this IOMMU */
+#define DMAR_CAP_REG 0x8 /* Hardware supported capabilities */
+#define DMAR_ECAP_REG 0x10 /* Extended capabilities supported */
+#define DMAR_GCMD_REG 0x18 /* Global command register */
+#define DMAR_GSTS_REG 0x1c /* Global status register */
+#define DMAR_RTADDR_REG 0x20 /* Root entry table */
+#define DMAR_CCMD_REG 0x28 /* Context command reg */
+#define DMAR_FSTS_REG 0x34 /* Fault Status register */
+#define DMAR_FECTL_REG 0x38 /* Fault control register */
+#define DMAR_FEDATA_REG 0x3c /* Fault event interrupt data register */
+#define DMAR_FEADDR_REG 0x40 /* Fault event interrupt addr register */
+#define DMAR_FEUADDR_REG 0x44 /* Upper address register */
+#define DMAR_AFLOG_REG 0x58 /* Advanced Fault control */
+#define DMAR_PMEN_REG 0x64 /* Enable Protected Memory Region */
+#define DMAR_PLMBASE_REG 0x68 /* PMRR Low addr */
+#define DMAR_PLMLIMIT_REG 0x6c /* PMRR low limit */
+#define DMAR_PHMBASE_REG 0x70 /* pmrr high base addr */
+#define DMAR_PHMLIMIT_REG 0x78 /* pmrr high limit */
+
+#define OFFSET_STRIDE (9)
+/*
+#define dmar_readl(dmar, reg) readl(dmar + reg)
+#define dmar_readq(dmar, reg) ({ \
+ u32 lo, hi; \
+ lo = readl(dmar + reg); \
+ hi = readl(dmar + reg + 4); \
+ (((u64) hi) << 32) + lo; })
+*/
+static inline u64 dmar_readq(void __iomem *addr)
+{
+ u32 lo, hi;
+ lo = readl(addr);
+ hi = readl(addr + 4);
+ return (((u64) hi) << 32) + lo;
+}
+
+static inline void dmar_writeq(void __iomem *addr, u64 val)
+{
+ writel((u32)val, addr);
+ writel((u32)(val >> 32), addr + 4);
+}
+
+#define DMAR_VER_MAJOR(v) (((v) & 0xf0) >> 4)
+#define DMAR_VER_MINOR(v) ((v) & 0x0f)
+
+/*
+ * Decoding Capability Register
+ */
+#define cap_read_drain(c) (((c) >> 55) & 1)
+#define cap_write_drain(c) (((c) >> 54) & 1)
+#define cap_max_amask_val(c) (((c) >> 48) & 0x3f)
+#define cap_num_fault_regs(c) ((((c) >> 40) & 0xff) + 1)
+#define cap_pgsel_inv(c) (((c) >> 39) & 1)
+
+#define cap_super_page_val(c) (((c) >> 34) & 0xf)
+#define cap_super_offset(c) (((find_first_bit(&cap_super_page_val(c), 4)) \
+ * OFFSET_STRIDE) + 21)
+
+#define cap_fault_reg_offset(c) ((((c) >> 24) & 0x3ff) * 16)
+#define cap_max_fault_reg_offset(c) \
+ (cap_fault_reg_offset(c) + cap_num_fault_regs(c) * 16)
+
+#define cap_zlr(c) (((c) >> 22) & 1)
+#define cap_isoch(c) (((c) >> 23) & 1)
+#define cap_mgaw(c) ((((c) >> 16) & 0x3f) + 1)
+#define cap_sagaw(c) (((c) >> 8) & 0x1f)
+#define cap_caching_mode(c) (((c) >> 7) & 1)
+#define cap_phmr(c) (((c) >> 6) & 1)
+#define cap_plmr(c) (((c) >> 5) & 1)
+#define cap_rwbf(c) (((c) >> 4) & 1)
+#define cap_afl(c) (((c) >> 3) & 1)
+#define cap_ndoms(c) (((unsigned long)1) << (4 + 2 * ((c) & 0x7)))
+/*
+ * Extended Capability Register
+ */
+
+#define ecap_niotlb_iunits(e) ((((e) >> 24) & 0xff) + 1)
+#define ecap_iotlb_offset(e) ((((e) >> 8) & 0x3ff) * 16)
+#define ecap_max_iotlb_offset(e) \
+ (ecap_iotlb_offset(e) + ecap_niotlb_iunits(e) * 16)
+#define ecap_coherent(e) ((e) & 0x1)
+
+
+/* IOTLB_REG */
+#define DMA_TLB_GLOBAL_FLUSH (((u64)1) << 60)
+#define DMA_TLB_DSI_FLUSH (((u64)2) << 60)
+#define DMA_TLB_PSI_FLUSH (((u64)3) << 60)
+#define DMA_TLB_IIRG(type) ((type >> 60) & 7)
+#define DMA_TLB_IAIG(val) (((val) >> 57) & 7)
+#define DMA_TLB_READ_DRAIN (((u64)1) << 49)
+#define DMA_TLB_WRITE_DRAIN (((u64)1) << 48)
+#define DMA_TLB_DID(id) (((u64)((id) & 0xffff)) << 32)
+#define DMA_TLB_IVT (((u64)1) << 63)
+#define DMA_TLB_IH_NONLEAF (((u64)1) << 6)
+#define DMA_TLB_MAX_SIZE (0x3f)
+
+/* GCMD_REG */
+#define DMA_GCMD_TE (((u32)1) << 31)
+#define DMA_GCMD_SRTP (((u32)1) << 30)
+#define DMA_GCMD_SFL (((u32)1) << 29)
+#define DMA_GCMD_EAFL (((u32)1) << 28)
+#define DMA_GCMD_WBF (((u32)1) << 27)
+
+/* GSTS_REG */
+#define DMA_GSTS_TES (((u32)1) << 31)
+#define DMA_GSTS_RTPS (((u32)1) << 30)
+#define DMA_GSTS_FLS (((u32)1) << 29)
+#define DMA_GSTS_AFLS (((u32)1) << 28)
+#define DMA_GSTS_WBFS (((u32)1) << 27)
+
+/* CCMD_REG */
+#define DMA_CCMD_ICC (((u64)1) << 63)
+#define DMA_CCMD_GLOBAL_INVL (((u64)1) << 61)
+#define DMA_CCMD_DOMAIN_INVL (((u64)2) << 61)
+#define DMA_CCMD_DEVICE_INVL (((u64)3) << 61)
+#define DMA_CCMD_FM(m) (((u64)((m) & 0x3)) << 32)
+#define DMA_CCMD_MASK_NOBIT 0
+#define DMA_CCMD_MASK_1BIT 1
+#define DMA_CCMD_MASK_2BIT 2
+#define DMA_CCMD_MASK_3BIT 3
+#define DMA_CCMD_SID(s) (((u64)((s) & 0xffff)) << 16)
+#define DMA_CCMD_DID(d) ((u64)((d) & 0xffff))
+
+/* FECTL_REG */
+#define DMA_FECTL_IM (((u32)1) << 31)
+
+/* FSTS_REG */
+#define DMA_FSTS_PPF ((u32)2)
+#define DMA_FSTS_PFO ((u32)1)
+#define dma_fsts_fault_record_index(s) (((s) >> 8) & 0xff)
+
+/* FRCD_REG, 32 bits access */
+#define DMA_FRCD_F (((u32)1) << 31)
+#define dma_frcd_type(d) ((d >> 30) & 1)
+#define dma_frcd_fault_reason(c) (c & 0xff)
+#define dma_frcd_source_id(c) (c & 0xffff)
+#define dma_frcd_page_addr(d) (d & (((u64)-1) << 12)) /* low 64 bit */
+
+/*
+ * 0: Present
+ * 1-11: Reserved
+ * 12-63: Context Ptr (12 - (haw-1))
+ * 64-127: Reserved
+ */
+struct root_entry {
+ u64 val;
+ u64 rsvd1;
+};
+#define ROOT_ENTRY_NR (PAGE_SIZE_4K/sizeof(struct root_entry))
+static inline bool root_present(struct root_entry *root)
+{
+ return (root->val & 1);
+}
+static inline void set_root_present(struct root_entry *root)
+{
+ root->val |= 1;
+}
+static inline void set_root_value(struct root_entry *root, unsigned long value)
+{
+ root->val |= value & PAGE_MASK_4K;
+}
+
+struct context_entry;
+static inline struct context_entry *
+get_context_addr_from_root(struct root_entry *root)
+{
+ return (struct context_entry *)
+ (root_present(root)?phys_to_virt(
+ root->val & PAGE_MASK_4K):
+ NULL);
+}
+
+/*
+ * low 64 bits:
+ * 0: present
+ * 1: fault processing disable
+ * 2-3: translation type
+ * 12-63: address space root
+ * high 64 bits:
+ * 0-2: address width
+ * 3-6: aval
+ * 8-23: domain id
+ */
+struct context_entry {
+ u64 lo;
+ u64 hi;
+};
+#define context_present(c) ((c).lo & 1)
+#define context_fault_disable(c) (((c).lo >> 1) & 1)
+#define context_translation_type(c) (((c).lo >> 2) & 3)
+#define context_address_root(c) ((c).lo & PAGE_MASK_4K)
+#define context_address_width(c) ((c).hi & 7)
+#define context_domain_id(c) (((c).hi >> 8) & ((1 << 16) - 1))
+
+#define context_set_present(c) do {(c).lo |= 1;} while (0)
+#define context_set_fault_enable(c) \
+ do {(c).lo &= (((u64)-1) << 2) | 1;} while (0)
+#define context_set_translation_type(c, val) \
+ do { \
+ (c).lo &= (((u64)-1) << 4) | 3; \
+ (c).lo |= ((val) & 3) << 2; \
+ } while (0)
+#define CONTEXT_TT_MULTI_LEVEL 0
+#define context_set_address_root(c, val) \
+ do {(c).lo |= (val) & PAGE_MASK_4K;} while (0)
+#define context_set_address_width(c, val) do {(c).hi |= (val) & 7;} while (0)
+#define context_set_domain_id(c, val) \
+ do {(c).hi |= ((val) & ((1 << 16) - 1)) << 8;} while (0)
+#define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while (0)
+
+/*
+ * 0: readable
+ * 1: writable
+ * 2-6: reserved
+ * 7: super page
+ * 8-11: available
+ * 12-63: Host physcial address
+ */
+struct dma_pte {
+ u64 val;
+};
+#define dma_clear_pte(p) do {(p).val = 0;} while (0)
+
+#define DMA_PTE_READ (1)
+#define DMA_PTE_WRITE (2)
+
+#define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while (0)
+#define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while (0)
+#define dma_set_pte_prot(p, prot) \
+ do {(p).val = ((p).val & ~3) | ((prot) & 3); } while (0)
+#define dma_pte_addr(p) ((p).val & PAGE_MASK_4K)
+#define dma_set_pte_addr(p, addr) do {\
+ (p).val |= ((addr) & PAGE_MASK_4K); } while (0)
+#define dma_pte_present(p) (((p).val & 3) != 0)
+
+struct intel_iommu;
+
+struct dmar_domain {
+ int id; /* domain id */
+ struct intel_iommu *iommu; /* back pointer to owning iommu */
+
+ struct list_head devices; /* all devices' list */
+ struct iova_domain iovad; /* iova's that belong to this domain */
+
+ struct dma_pte *pgd; /* virtual address */
+ spinlock_t mapping_lock; /* page table lock */
+ int gaw; /* max guest address width */
+
+ /* adjusted guest address width, 0 is level 2 30-bit */
+ int agaw;
+
+#define DOMAIN_FLAG_MULTIPLE_DEVICES 1
+ int flags;
+};
+
+/* PCI domain-device relationship */
+struct device_domain_info {
+ struct list_head link; /* link to domain siblings */
+ struct list_head global; /* link to global list */
+ u8 bus; /* PCI bus numer */
+ u8 devfn; /* PCI devfn number */
+ struct pci_dev *dev; /* it's NULL for PCIE-to-PCI bridge */
+ struct dmar_domain *domain; /* pointer to domain */
+};
+
+extern int init_dmars(void);
+
+struct intel_iommu {
+ void __iomem *reg; /* Pointer to hardware regs, virtual addr */
+ u64 cap;
+ u64 ecap;
+ unsigned long *domain_ids; /* bitmap of domains */
+ struct dmar_domain **domains; /* ptr to domains */
+ int seg;
+ u32 gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
+ spinlock_t lock; /* protect context, domain ids */
+ spinlock_t register_lock; /* protect register handling */
+ struct root_entry *root_entry; /* virtual address */
+
+ unsigned int irq;
+ unsigned char name[7]; /* Device Name */
+ struct msi_msg saved_msg;
+ struct sys_device sysdev;
+};
+
+#ifndef CONFIG_DMAR_GFX_WA
+static inline void iommu_prepare_gfx_mapping(void)
+{
+ return;
+}
+#endif /* !CONFIG_DMAR_GFX_WA */
+
+#endif
diff --git a/drivers/pci/iova.c b/drivers/pci/iova.c
new file mode 100644
index 00000000000..a84571c2936
--- /dev/null
+++ b/drivers/pci/iova.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This file is released under the GPLv2.
+ *
+ * Copyright (C) 2006 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ */
+
+#include "iova.h"
+
+void
+init_iova_domain(struct iova_domain *iovad)
+{
+ spin_lock_init(&iovad->iova_alloc_lock);
+ spin_lock_init(&iovad->iova_rbtree_lock);
+ iovad->rbroot = RB_ROOT;
+ iovad->cached32_node = NULL;
+
+}
+
+static struct rb_node *
+__get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn)
+{
+ if ((*limit_pfn != DMA_32BIT_PFN) ||
+ (iovad->cached32_node == NULL))
+ return rb_last(&iovad->rbroot);
+ else {
+ struct rb_node *prev_node = rb_prev(iovad->cached32_node);
+ struct iova *curr_iova =
+ container_of(iovad->cached32_node, struct iova, node);
+ *limit_pfn = curr_iova->pfn_lo - 1;
+ return prev_node;
+ }
+}
+
+static void
+__cached_rbnode_insert_update(struct iova_domain *iovad,
+ unsigned long limit_pfn, struct iova *new)
+{
+ if (limit_pfn != DMA_32BIT_PFN)
+ return;
+ iovad->cached32_node = &new->node;
+}
+
+static void
+__cached_rbnode_delete_update(struct iova_domain *iovad, struct iova *free)
+{
+ struct iova *cached_iova;
+ struct rb_node *curr;
+
+ if (!iovad->cached32_node)
+ return;
+ curr = iovad->cached32_node;
+ cached_iova = container_of(curr, struct iova, node);
+
+ if (free->pfn_lo >= cached_iova->pfn_lo)
+ iovad->cached32_node = rb_next(&free->node);
+}
+
+/* Computes the padding size required, to make the
+ * the start address naturally aligned on its size
+ */
+static int
+iova_get_pad_size(int size, unsigned int limit_pfn)
+{
+ unsigned int pad_size = 0;
+ unsigned int order = ilog2(size);
+
+ if (order)
+ pad_size = (limit_pfn + 1) % (1 << order);
+
+ return pad_size;
+}
+
+static int __alloc_iova_range(struct iova_domain *iovad, unsigned long size,
+ unsigned long limit_pfn, struct iova *new, bool size_aligned)
+{
+ struct rb_node *curr = NULL;
+ unsigned long flags;
+ unsigned long saved_pfn;
+ unsigned int pad_size = 0;
+
+ /* Walk the tree backwards */
+ spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
+ saved_pfn = limit_pfn;
+ curr = __get_cached_rbnode(iovad, &limit_pfn);
+ while (curr) {
+ struct iova *curr_iova = container_of(curr, struct iova, node);
+ if (limit_pfn < curr_iova->pfn_lo)
+ goto move_left;
+ else if (limit_pfn < curr_iova->pfn_hi)
+ goto adjust_limit_pfn;
+ else {
+ if (size_aligned)
+ pad_size = iova_get_pad_size(size, limit_pfn);
+ if ((curr_iova->pfn_hi + size + pad_size) <= limit_pfn)
+ break; /* found a free slot */
+ }
+adjust_limit_pfn:
+ limit_pfn = curr_iova->pfn_lo - 1;
+move_left:
+ curr = rb_prev(curr);
+ }
+
+ if (!curr) {
+ if (size_aligned)
+ pad_size = iova_get_pad_size(size, limit_pfn);
+ if ((IOVA_START_PFN + size + pad_size) > limit_pfn) {
+ spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+ return -ENOMEM;
+ }
+ }
+
+ /* pfn_lo will point to size aligned address if size_aligned is set */
+ new->pfn_lo = limit_pfn - (size + pad_size) + 1;
+ new->pfn_hi = new->pfn_lo + size - 1;
+
+ spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+ return 0;
+}
+
+static void
+iova_insert_rbtree(struct rb_root *root, struct iova *iova)
+{
+ struct rb_node **new = &(root->rb_node), *parent = NULL;
+ /* Figure out where to put new node */
+ while (*new) {
+ struct iova *this = container_of(*new, struct iova, node);
+ parent = *new;
+
+ if (iova->pfn_lo < this->pfn_lo)
+ new = &((*new)->rb_left);
+ else if (iova->pfn_lo > this->pfn_lo)
+ new = &((*new)->rb_right);
+ else
+ BUG(); /* this should not happen */
+ }
+ /* Add new node and rebalance tree. */
+ rb_link_node(&iova->node, parent, new);
+ rb_insert_color(&iova->node, root);
+}
+
+/**
+ * alloc_iova - allocates an iova
+ * @iovad - iova domain in question
+ * @size - size of page frames to allocate
+ * @limit_pfn - max limit address
+ * @size_aligned - set if size_aligned address range is required
+ * This function allocates an iova in the range limit_pfn to IOVA_START_PFN
+ * looking from limit_pfn instead from IOVA_START_PFN. If the size_aligned
+ * flag is set then the allocated address iova->pfn_lo will be naturally
+ * aligned on roundup_power_of_two(size).
+ */
+struct iova *
+alloc_iova(struct iova_domain *iovad, unsigned long size,
+ unsigned long limit_pfn,
+ bool size_aligned)
+{
+ unsigned long flags;
+ struct iova *new_iova;
+ int ret;
+
+ new_iova = alloc_iova_mem();
+ if (!new_iova)
+ return NULL;
+
+ /* If size aligned is set then round the size to
+ * to next power of two.
+ */
+ if (size_aligned)
+ size = __roundup_pow_of_two(size);
+
+ spin_lock_irqsave(&iovad->iova_alloc_lock, flags);
+ ret = __alloc_iova_range(iovad, size, limit_pfn, new_iova,
+ size_aligned);
+
+ if (ret) {
+ spin_unlock_irqrestore(&iovad->iova_alloc_lock, flags);
+ free_iova_mem(new_iova);
+ return NULL;
+ }
+
+ /* Insert the new_iova into domain rbtree by holding writer lock */
+ spin_lock(&iovad->iova_rbtree_lock);
+ iova_insert_rbtree(&iovad->rbroot, new_iova);
+ __cached_rbnode_insert_update(iovad, limit_pfn, new_iova);
+ spin_unlock(&iovad->iova_rbtree_lock);
+
+ spin_unlock_irqrestore(&iovad->iova_alloc_lock, flags);
+
+ return new_iova;
+}
+
+/**
+ * find_iova - find's an iova for a given pfn
+ * @iovad - iova domain in question.
+ * pfn - page frame number
+ * This function finds and returns an iova belonging to the
+ * given doamin which matches the given pfn.
+ */
+struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn)
+{
+ unsigned long flags;
+ struct rb_node *node;
+
+ /* Take the lock so that no other thread is manipulating the rbtree */
+ spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
+ node = iovad->rbroot.rb_node;
+ while (node) {
+ struct iova *iova = container_of(node, struct iova, node);
+
+ /* If pfn falls within iova's range, return iova */
+ if ((pfn >= iova->pfn_lo) && (pfn <= iova->pfn_hi)) {
+ spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+ /* We are not holding the lock while this iova
+ * is referenced by the caller as the same thread
+ * which called this function also calls __free_iova()
+ * and it is by desing that only one thread can possibly
+ * reference a particular iova and hence no conflict.
+ */
+ return iova;
+ }
+
+ if (pfn < iova->pfn_lo)
+ node = node->rb_left;
+ else if (pfn > iova->pfn_lo)
+ node = node->rb_right;
+ }
+
+ spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+ return NULL;
+}
+
+/**
+ * __free_iova - frees the given iova
+ * @iovad: iova domain in question.
+ * @iova: iova in question.
+ * Frees the given iova belonging to the giving domain
+ */
+void
+__free_iova(struct iova_domain *iovad, struct iova *iova)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
+ __cached_rbnode_delete_update(iovad, iova);
+ rb_erase(&iova->node, &iovad->rbroot);
+ spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+ free_iova_mem(iova);
+}
+
+/**
+ * free_iova - finds and frees the iova for a given pfn
+ * @iovad: - iova domain in question.
+ * @pfn: - pfn that is allocated previously
+ * This functions finds an iova for a given pfn and then
+ * frees the iova from that domain.
+ */
+void
+free_iova(struct iova_domain *iovad, unsigned long pfn)
+{
+ struct iova *iova = find_iova(iovad, pfn);
+ if (iova)
+ __free_iova(iovad, iova);
+
+}
+
+/**
+ * put_iova_domain - destroys the iova doamin
+ * @iovad: - iova domain in question.
+ * All the iova's in that domain are destroyed.
+ */
+void put_iova_domain(struct iova_domain *iovad)
+{
+ struct rb_node *node;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iovad->iova_rbtree_lock, flags);
+ node = rb_first(&iovad->rbroot);
+ while (node) {
+ struct iova *iova = container_of(node, struct iova, node);
+ rb_erase(node, &iovad->rbroot);
+ free_iova_mem(iova);
+ node = rb_first(&iovad->rbroot);
+ }
+ spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
+}
+
+static int
+__is_range_overlap(struct rb_node *node,
+ unsigned long pfn_lo, unsigned long pfn_hi)
+{
+ struct iova *iova = container_of(node, struct iova, node);
+
+ if ((pfn_lo <= iova->pfn_hi) && (pfn_hi >= iova->pfn_lo))
+ return 1;
+ return 0;
+}
+
+static struct iova *
+__insert_new_range(struct iova_domain *iovad,
+ unsigned long pfn_lo, unsigned long pfn_hi)
+{
+ struct iova *iova;
+
+ iova = alloc_iova_mem();
+ if (!iova)
+ return iova;
+
+ iova->pfn_hi = pfn_hi;
+ iova->pfn_lo = pfn_lo;
+ iova_insert_rbtree(&iovad->rbroot, iova);
+ return iova;
+}
+
+static void
+__adjust_overlap_range(struct iova *iova,
+ unsigned long *pfn_lo, unsigned long *pfn_hi)
+{
+ if (*pfn_lo < iova->pfn_lo)
+ iova->pfn_lo = *pfn_lo;
+ if (*pfn_hi > iova->pfn_hi)
+ *pfn_lo = iova->pfn_hi + 1;
+}
+
+/**
+ * reserve_iova - reserves an iova in the given range
+ * @iovad: - iova domain pointer
+ * @pfn_lo: - lower page frame address
+ * @pfn_hi:- higher pfn adderss
+ * This function allocates reserves the address range from pfn_lo to pfn_hi so
+ * that this address is not dished out as part of alloc_iova.
+ */
+struct iova *
+reserve_iova(struct iova_domain *iovad,
+ unsigned long pfn_lo, unsigned long pfn_hi)
+{
+ struct rb_node *node;
+ unsigned long flags;
+ struct iova *iova;
+ unsigned int overlap = 0;
+
+ spin_lock_irqsave(&iovad->iova_alloc_lock, flags);
+ spin_lock(&iovad->iova_rbtree_lock);
+ for (node = rb_first(&iovad->rbroot); node; node = rb_next(node)) {
+ if (__is_range_overlap(node, pfn_lo, pfn_hi)) {
+ iova = container_of(node, struct iova, node);
+ __adjust_overlap_range(iova, &pfn_lo, &pfn_hi);
+ if ((pfn_lo >= iova->pfn_lo) &&
+ (pfn_hi <= iova->pfn_hi))
+ goto finish;
+ overlap = 1;
+
+ } else if (overlap)
+ break;
+ }
+
+ /* We are here either becasue this is the first reserver node
+ * or need to insert remaining non overlap addr range
+ */
+ iova = __insert_new_range(iovad, pfn_lo, pfn_hi);
+finish:
+
+ spin_unlock(&iovad->iova_rbtree_lock);
+ spin_unlock_irqrestore(&iovad->iova_alloc_lock, flags);
+ return iova;
+}
+
+/**
+ * copy_reserved_iova - copies the reserved between domains
+ * @from: - source doamin from where to copy
+ * @to: - destination domin where to copy
+ * This function copies reserved iova's from one doamin to
+ * other.
+ */
+void
+copy_reserved_iova(struct iova_domain *from, struct iova_domain *to)
+{
+ unsigned long flags;
+ struct rb_node *node;
+
+ spin_lock_irqsave(&from->iova_alloc_lock, flags);
+ spin_lock(&from->iova_rbtree_lock);
+ for (node = rb_first(&from->rbroot); node; node = rb_next(node)) {
+ struct iova *iova = container_of(node, struct iova, node);
+ struct iova *new_iova;
+ new_iova = reserve_iova(to, iova->pfn_lo, iova->pfn_hi);
+ if (!new_iova)
+ printk(KERN_ERR "Reserve iova range %lx@%lx failed\n",
+ iova->pfn_lo, iova->pfn_lo);
+ }
+ spin_unlock(&from->iova_rbtree_lock);
+ spin_unlock_irqrestore(&from->iova_alloc_lock, flags);
+}
diff --git a/drivers/pci/iova.h b/drivers/pci/iova.h
new file mode 100644
index 00000000000..ae3028d5a94
--- /dev/null
+++ b/drivers/pci/iova.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2006, Intel Corporation.
+ *
+ * This file is released under the GPLv2.
+ *
+ * Copyright (C) 2006 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ *
+ */
+
+#ifndef _IOVA_H_
+#define _IOVA_H_
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/rbtree.h>
+#include <linux/dma-mapping.h>
+
+/*
+ * We need a fixed PAGE_SIZE of 4K irrespective of
+ * arch PAGE_SIZE for IOMMU page tables.
+ */
+#define PAGE_SHIFT_4K (12)
+#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K)
+#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K)
+#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K)
+
+/* IO virtual address start page frame number */
+#define IOVA_START_PFN (1)
+
+#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT_4K)
+#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK)
+#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK)
+
+/* iova structure */
+struct iova {
+ struct rb_node node;
+ unsigned long pfn_hi; /* IOMMU dish out addr hi */
+ unsigned long pfn_lo; /* IOMMU dish out addr lo */
+};
+
+/* holds all the iova translations for a domain */
+struct iova_domain {
+ spinlock_t iova_alloc_lock;/* Lock to protect iova allocation */
+ spinlock_t iova_rbtree_lock; /* Lock to protect update of rbtree */
+ struct rb_root rbroot; /* iova domain rbtree root */
+ struct rb_node *cached32_node; /* Save last alloced node */
+};
+
+struct iova *alloc_iova_mem(void);
+void free_iova_mem(struct iova *iova);
+void free_iova(struct iova_domain *iovad, unsigned long pfn);
+void __free_iova(struct iova_domain *iovad, struct iova *iova);
+struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size,
+ unsigned long limit_pfn,
+ bool size_aligned);
+struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo,
+ unsigned long pfn_hi);
+void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to);
+void init_iova_domain(struct iova_domain *iovad);
+struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn);
+void put_iova_domain(struct iova_domain *iovad);
+
+#endif
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index be1df85e5e2..07c9f09c856 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -132,7 +132,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
} else {
msg->address_hi = 0;
- pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
+ pci_read_config_word(dev, msi_data_reg(pos, 0), &data);
}
msg->data = data;
break;
@@ -224,6 +224,12 @@ static struct msi_desc* alloc_msi_entry(void)
return entry;
}
+static void pci_intx_for_msi(struct pci_dev *dev, int enable)
+{
+ if (!(dev->dev_flags & PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG))
+ pci_intx(dev, enable);
+}
+
#ifdef CONFIG_PM
static void __pci_restore_msi_state(struct pci_dev *dev)
{
@@ -237,7 +243,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
entry = get_irq_msi(dev->irq);
pos = entry->msi_attrib.pos;
- pci_intx(dev, 0); /* disable intx */
+ pci_intx_for_msi(dev, 0);
msi_set_enable(dev, 0);
write_msi_msg(dev->irq, &entry->msg);
if (entry->msi_attrib.maskbit)
@@ -260,7 +266,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
return;
/* route the table */
- pci_intx(dev, 0); /* disable intx */
+ pci_intx_for_msi(dev, 0);
msix_set_enable(dev, 0);
list_for_each_entry(entry, &dev->msi_list, list) {
@@ -343,7 +349,7 @@ static int msi_capability_init(struct pci_dev *dev)
}
/* Set MSI enabled bits */
- pci_intx(dev, 0); /* disable intx */
+ pci_intx_for_msi(dev, 0);
msi_set_enable(dev, 1);
dev->msi_enabled = 1;
@@ -433,7 +439,7 @@ static int msix_capability_init(struct pci_dev *dev,
i++;
}
/* Set MSI-X enabled bits */
- pci_intx(dev, 0); /* disable intx */
+ pci_intx_for_msi(dev, 0);
msix_set_enable(dev, 1);
dev->msix_enabled = 1;
@@ -528,7 +534,7 @@ void pci_disable_msi(struct pci_dev* dev)
return;
msi_set_enable(dev, 0);
- pci_intx(dev, 1); /* enable intx */
+ pci_intx_for_msi(dev, 1);
dev->msi_enabled = 0;
BUG_ON(list_empty(&dev->msi_list));
@@ -640,7 +646,7 @@ void pci_disable_msix(struct pci_dev* dev)
return;
msix_set_enable(dev, 0);
- pci_intx(dev, 1); /* enable intx */
+ pci_intx_for_msi(dev, 1);
dev->msix_enabled = 0;
msix_free_all_irqs(dev);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 004bc248727..6d1a2161181 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -54,7 +54,6 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
if (!dynid)
return -ENOMEM;
- INIT_LIST_HEAD(&dynid->node);
dynid->id.vendor = vendor;
dynid->id.device = device;
dynid->id.subvendor = subvendor;
@@ -65,7 +64,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
driver_data : 0UL;
spin_lock(&pdrv->dynids.lock);
- list_add_tail(&pdrv->dynids.list, &dynid->node);
+ list_add_tail(&dynid->node, &pdrv->dynids.list);
spin_unlock(&pdrv->dynids.lock);
if (get_driver(&pdrv->driver)) {
@@ -144,8 +143,8 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
* system is in its list of supported devices. Returns the matching
* pci_device_id structure or %NULL if there is no match.
*/
-const struct pci_device_id *pci_match_device(struct pci_driver *drv,
- struct pci_dev *dev)
+static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
+ struct pci_dev *dev)
{
struct pci_dynid *dynid;
@@ -532,8 +531,7 @@ void pci_dev_put(struct pci_dev *dev)
}
#ifndef CONFIG_HOTPLUG
-int pci_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
@@ -561,7 +559,6 @@ static int __init pci_driver_init(void)
postcore_initcall(pci_driver_init);
EXPORT_SYMBOL(pci_match_id);
-EXPORT_SYMBOL(pci_match_device);
EXPORT_SYMBOL(__pci_register_driver);
EXPORT_SYMBOL(pci_unregister_driver);
EXPORT_SYMBOL(pci_dev_driver);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 37c00f6fd80..71d561fda0a 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -17,11 +17,16 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/string.h>
+#include <linux/log2.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h"
unsigned int pci_pm_d3_delay = 10;
+#ifdef CONFIG_PCI_DOMAINS
+int pci_domains_supported = 1;
+#endif
+
#define DEFAULT_CARDBUS_IO_SIZE (256)
#define DEFAULT_CARDBUS_MEM_SIZE (64*1024*1024)
/* pci=cbmemsize=nnM,cbiosize=nn can override this */
@@ -653,7 +658,7 @@ int
pci_restore_state(struct pci_dev *dev)
{
int i;
- int val;
+ u32 val;
/* PCI Express register must be restored first */
pci_restore_pcie_state(dev);
@@ -1454,7 +1459,7 @@ int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc)
int cap, err = -EINVAL;
u32 stat, cmd, v, o;
- if (mmrbc < 512 || mmrbc > 4096 || (mmrbc & (mmrbc-1)))
+ if (mmrbc < 512 || mmrbc > 4096 || !is_power_of_2(mmrbc))
goto out;
v = ffs(mmrbc) - 10;
@@ -1526,7 +1531,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
int cap, err = -EINVAL;
u16 ctl, v;
- if (rq < 128 || rq > 4096 || (rq & (rq-1)))
+ if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
goto out;
v = (ffs(rq) - 8) << 12;
@@ -1566,6 +1571,13 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags)
return bars;
}
+static void __devinit pci_no_domains(void)
+{
+#ifdef CONFIG_PCI_DOMAINS
+ pci_domains_supported = 0;
+#endif
+}
+
static int __devinit pci_init(void)
{
struct pci_dev *dev = NULL;
@@ -1585,6 +1597,10 @@ static int __devinit pci_setup(char *str)
if (*str && (str = pcibios_setup(str)) && *str) {
if (!strcmp(str, "nomsi")) {
pci_no_msi();
+ } else if (!strcmp(str, "noaer")) {
+ pci_no_aer();
+ } else if (!strcmp(str, "nodomains")) {
+ pci_no_domains();
} else if (!strncmp(str, "cbiosize=", 9)) {
pci_cardbus_io_size = memparse(str + 9, &str);
} else if (!strncmp(str, "cbmemsize=", 10)) {
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4c36e80f6d2..fc87e14b50d 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1,7 +1,6 @@
/* Functions internal to the PCI core code */
-extern int pci_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size);
+extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_cleanup_rom(struct pci_dev *dev);
@@ -52,6 +51,12 @@ void pci_restore_msi_state(struct pci_dev *dev);
static inline void pci_restore_msi_state(struct pci_dev *dev) {}
#endif
+#ifdef CONFIG_PCIEAER
+void pci_no_aer(void);
+#else
+static inline void pci_no_aer(void) { }
+#endif
+
static inline int pci_no_d1d2(struct pci_dev *dev)
{
unsigned int parent_dstates = 0;
@@ -85,3 +90,4 @@ pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
return NULL;
}
+struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev);
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 0ad92a8ad8b..287a9311716 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -25,13 +25,4 @@ config HOTPLUG_PCI_PCIE
When in doubt, say N.
-config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
- bool "Use polling mechanism for hot-plug events (for testing purpose)"
- depends on HOTPLUG_PCI_PCIE
- help
- Say Y here if you want to use the polling mechanism for hot-plug
- events for early platform testing.
-
- When in doubt, say N.
-
source "drivers/pci/pcie/aer/Kconfig"
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index ad90a01b0df..7a62f7dd900 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -81,6 +81,13 @@ static struct pcie_port_service_driver aerdriver = {
.reset_link = aer_root_reset,
};
+static int pcie_aer_disable;
+
+void pci_no_aer(void)
+{
+ pcie_aer_disable = 1; /* has priority over 'forceload' */
+}
+
/**
* aer_irq - Root Port's ISR
* @irq: IRQ assigned to Root Port
@@ -327,6 +334,8 @@ static void aer_error_resume(struct pci_dev *dev)
**/
static int __init aer_service_init(void)
{
+ if (pcie_aer_disable)
+ return -ENXIO;
return pcie_port_service_register(&aerdriver);
}
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 171ca712e52..463a5a9d583 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -276,8 +276,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK);
if (sz) {
res->flags = (l & IORESOURCE_ROM_ENABLE) |
- IORESOURCE_MEM | IORESOURCE_PREFETCH |
- IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+ IORESOURCE_MEM | IORESOURCE_READONLY;
res->start = l & PCI_ROM_ADDRESS_MASK;
res->end = res->start + (unsigned long) sz;
}
@@ -597,7 +596,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass
pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
if (!is_cardbus) {
- child->bridge_ctl = bctl | PCI_BRIDGE_CTL_NO_ISA;
+ child->bridge_ctl = bctl;
/*
* Adjust subordinate busnr in parent buses.
* We do this before scanning for children because
@@ -744,22 +743,46 @@ static int pci_setup_device(struct pci_dev * dev)
*/
if (class == PCI_CLASS_STORAGE_IDE) {
u8 progif;
+ struct pci_bus_region region;
+
pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
if ((progif & 1) == 0) {
- dev->resource[0].start = 0x1F0;
- dev->resource[0].end = 0x1F7;
- dev->resource[0].flags = LEGACY_IO_RESOURCE;
- dev->resource[1].start = 0x3F6;
- dev->resource[1].end = 0x3F6;
- dev->resource[1].flags = LEGACY_IO_RESOURCE;
+ struct resource resource = {
+ .start = 0x1F0,
+ .end = 0x1F7,
+ .flags = LEGACY_IO_RESOURCE,
+ };
+
+ pcibios_resource_to_bus(dev, &region, &resource);
+ dev->resource[0].start = region.start;
+ dev->resource[0].end = region.end;
+ dev->resource[0].flags = resource.flags;
+ resource.start = 0x3F6;
+ resource.end = 0x3F6;
+ resource.flags = LEGACY_IO_RESOURCE;
+ pcibios_resource_to_bus(dev, &region, &resource);
+ dev->resource[1].start = region.start;
+ dev->resource[1].end = region.end;
+ dev->resource[1].flags = resource.flags;
}
if ((progif & 4) == 0) {
- dev->resource[2].start = 0x170;
- dev->resource[2].end = 0x177;
- dev->resource[2].flags = LEGACY_IO_RESOURCE;
- dev->resource[3].start = 0x376;
- dev->resource[3].end = 0x376;
- dev->resource[3].flags = LEGACY_IO_RESOURCE;
+ struct resource resource = {
+ .start = 0x170,
+ .end = 0x177,
+ .flags = LEGACY_IO_RESOURCE,
+ };
+
+ pcibios_resource_to_bus(dev, &region, &resource);
+ dev->resource[2].start = region.start;
+ dev->resource[2].end = region.end;
+ dev->resource[2].flags = resource.flags;
+ resource.start = 0x376;
+ resource.end = 0x376;
+ resource.flags = LEGACY_IO_RESOURCE;
+ pcibios_resource_to_bus(dev, &region, &resource);
+ dev->resource[3].start = region.start;
+ dev->resource[3].end = region.end;
+ dev->resource[3].flags = resource.flags;
}
}
break;
@@ -814,6 +837,19 @@ static void pci_release_dev(struct device *dev)
kfree(pci_dev);
}
+static void set_pcie_port_type(struct pci_dev *pdev)
+{
+ int pos;
+ u16 reg16;
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return;
+ pdev->is_pcie = 1;
+ pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
+ pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
+}
+
/**
* pci_cfg_space_size - get the configuration space size of the PCI device.
* @dev: PCI device
@@ -928,6 +964,7 @@ pci_scan_device(struct pci_bus *bus, int devfn)
dev->device = (l >> 16) & 0xffff;
dev->cfg_size = pci_cfg_space_size(dev);
dev->error_state = pci_channel_io_normal;
+ set_pcie_port_type(dev);
/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
set this higher, assuming the system even supports it. */
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 90adc62d07f..716439e25dd 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -60,7 +60,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
*/
if (capable(CAP_SYS_ADMIN))
- size = dev->cfg_size;
+ size = dp->size;
else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
size = 128;
else
@@ -129,11 +129,11 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
static ssize_t
proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos)
{
- const struct inode *ino = file->f_path.dentry->d_inode;
+ struct inode *ino = file->f_path.dentry->d_inode;
const struct proc_dir_entry *dp = PDE(ino);
struct pci_dev *dev = dp->data;
int pos = *ppos;
- int size = dev->cfg_size;
+ int size = dp->size;
int cnt;
if (pos >= size)
@@ -193,6 +193,7 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof
}
*ppos = pos;
+ i_size_write(ino, dp->size);
return nbytes;
}
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 50f2dd9e1bb..26cc4dcf4f0 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -472,11 +472,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_
*/
static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev)
{
- u8 rev;
u32 region;
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
- if (rev & 0x10) {
+ if (dev->revision & 0x10) {
pci_read_config_dword(dev, 0x48, &region);
region &= PCI_BASE_ADDRESS_IO_MASK;
quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI");
@@ -629,12 +627,9 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk
*/
static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev)
{
- unsigned char revid;
-
- pci_read_config_byte(dev, PCI_REVISION_ID, &revid);
- if (dev->subordinate && revid <= 0x12) {
+ if (dev->subordinate && dev->revision <= 0x12) {
printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X "
- "MMRBC\n", revid);
+ "MMRBC\n", dev->revision);
dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC;
}
}
@@ -930,38 +925,6 @@ static void __init quirk_eisa_bridge(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_eisa_bridge );
-/*
- * On the MSI-K8T-Neo2Fir Board, the internal Soundcard is disabled
- * when a PCI-Soundcard is added. The BIOS only gives Options
- * "Disabled" and "AUTO". This Quirk Sets the corresponding
- * Register-Value to enable the Soundcard.
- *
- * FIXME: Presently this quirk will run on anything that has an 8237
- * which isn't correct, we need to check DMI tables or something in
- * order to make sure it only runs on the MSI-K8T-Neo2Fir. Because it
- * runs everywhere at present we suppress the printk output in most
- * irrelevant cases.
- */
-static void k8t_sound_hostbridge(struct pci_dev *dev)
-{
- unsigned char val;
-
- pci_read_config_byte(dev, 0x50, &val);
- if (val == 0xc8) {
- /* Assume it's probably a MSI-K8T-Neo2Fir */
- printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n");
- pci_write_config_byte(dev, 0x50, val & (~0x40));
-
- /* Verify the Change for Status output */
- pci_read_config_byte(dev, 0x50, &val);
- if (val & 0x40)
- printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n");
- else
- printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n");
- }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
/*
* On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge
@@ -1267,7 +1230,7 @@ static void quirk_jmicron_ata(struct pci_dev *pdev)
case PCI_DEVICE_ID_JMICRON_JMB363:
/* Enable dual function mode, AHCI on fn 0, IDE fn1 */
/* Set the class codes correctly and then direct IDE 0 */
- conf1 |= 0x00C2A102; /* Set 1, 8, 13, 15, 17, 22, 23 */
+ conf1 |= 0x00C2A1B3; /* Set 0, 1, 4, 5, 7, 8, 13, 15, 17, 22, 23 */
break;
case PCI_DEVICE_ID_JMICRON_JMB368:
@@ -1658,12 +1621,8 @@ static void __init quirk_disable_all_msi(struct pci_dev *dev)
printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n");
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_disable_all_msi);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000_PCIX, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disable_all_msi);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RD580, quirk_disable_all_msi);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RX790, quirk_disable_all_msi);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS690, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi);
/* Disable MSI on chipsets that are known to not support it */
@@ -1715,6 +1674,9 @@ static void __devinit quirk_msi_ht_cap(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE,
quirk_msi_ht_cap);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB,
+ quirk_msi_ht_cap);
/* The nVidia CK804 chipset may have 2 HT MSI mappings.
* MSI are supported if the MSI capability set in any of these mappings.
@@ -1742,4 +1704,48 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
quirk_nvidia_ck804_msi_ht_cap);
+
+static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev)
+{
+ dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
+ PCI_DEVICE_ID_TIGON3_5780,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
+ PCI_DEVICE_ID_TIGON3_5780S,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
+ PCI_DEVICE_ID_TIGON3_5714,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
+ PCI_DEVICE_ID_TIGON3_5714S,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
+ PCI_DEVICE_ID_TIGON3_5715,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM,
+ PCI_DEVICE_ID_TIGON3_5715S,
+ quirk_msi_intx_disable_bug);
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4390,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4391,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4392,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4393,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4394,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4395,
+ quirk_msi_intx_disable_bug);
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4373,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4374,
+ quirk_msi_intx_disable_bug);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4375,
+ quirk_msi_intx_disable_bug);
+
#endif /* CONFIG_PCI_MSI */
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index c6e79d01ce3..8541034021f 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -14,6 +14,40 @@
#include "pci.h"
DECLARE_RWSEM(pci_bus_sem);
+/*
+ * find the upstream PCIE-to-PCI bridge of a PCI device
+ * if the device is PCIE, return NULL
+ * if the device isn't connected to a PCIE bridge (that is its parent is a
+ * legacy PCI bridge and the bridge is directly connected to bus 0), return its
+ * parent
+ */
+struct pci_dev *
+pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
+{
+ struct pci_dev *tmp = NULL;
+
+ if (pdev->is_pcie)
+ return NULL;
+ while (1) {
+ if (!pdev->bus->self)
+ break;
+ pdev = pdev->bus->self;
+ /* a p2p bridge */
+ if (!pdev->is_pcie) {
+ tmp = pdev;
+ continue;
+ }
+ /* PCI device should connect to a PCIE bridge */
+ if (pdev->pcie_type != PCI_EXP_TYPE_PCI_BRIDGE) {
+ /* Busted hardware? */
+ WARN_ON_ONCE(1);
+ return NULL;
+ }
+ return pdev;
+ }
+
+ return tmp;
+}
static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
{
@@ -79,6 +113,8 @@ pci_find_next_bus(const struct pci_bus *from)
return b;
}
+#ifdef CONFIG_PCI_LEGACY
+
/**
* pci_find_slot - locate PCI device from a given PCI slot
* @bus: number of PCI bus on which desired PCI device resides
@@ -103,6 +139,8 @@ pci_find_slot(unsigned int bus, unsigned int devfn)
return NULL;
}
+#endif /* CONFIG_PCI_LEGACY */
+
/**
* pci_get_slot - locate PCI device for a given PCI slot
* @bus: PCI bus on which desired PCI device resides
@@ -166,6 +204,7 @@ struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn)
return NULL;
}
+#ifdef CONFIG_PCI_LEGACY
/**
* pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
* @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
@@ -244,6 +283,7 @@ pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *
{
return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
}
+#endif /* CONFIG_PCI_LEGACY */
/**
* pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
@@ -434,8 +474,11 @@ int pci_dev_present(const struct pci_device_id *ids)
EXPORT_SYMBOL(pci_dev_present);
EXPORT_SYMBOL(pci_find_present);
+#ifdef CONFIG_PCI_LEGACY
EXPORT_SYMBOL(pci_find_device);
EXPORT_SYMBOL(pci_find_slot);
+#endif /* CONFIG_PCI_LEGACY */
+
/* For boot time work */
EXPORT_SYMBOL(pci_find_bus);
EXPORT_SYMBOL(pci_find_next_bus);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 5e5191ec8de..401e03c920b 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -472,7 +472,12 @@ void pci_bus_size_bridges(struct pci_bus *bus)
break;
case PCI_CLASS_BRIDGE_PCI:
+ /* don't size subtractive decoding (transparent)
+ * PCI-to-PCI bridges */
+ if (bus->self->transparent)
+ break;
pci_bridge_check_ranges(bus);
+ /* fall through */
default:
pbus_size_io(bus);
/* If the bridge supports prefetchable range, size it
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
index 568f1877315..05ca2ed9eb5 100644
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -48,7 +48,7 @@ pdev_fixup_irq(struct pci_dev *dev,
dev->irq = irq;
pr_debug("PCI: fixup irq: (%s) got %d\n",
- dev->dev.kobj.name, dev->irq);
+ kobject_name(&dev->dev.kobj), dev->irq);
/* Always tell the device, so the driver knows what is
the real IRQ to use; the device does not use it. */
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index c0c77f82d05..519b4ff79f7 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -2,9 +2,7 @@
# PCCARD (PCMCIA/CardBus) bus subsystem configuration
#
-menu "PCCARD (PCMCIA/CardBus) support"
-
-config PCCARD
+menuconfig PCCARD
tristate "PCCard (PCMCIA/CardBus) support"
depends on HOTPLUG
---help---
@@ -271,6 +269,13 @@ config AT91_CF
Say Y here to support the CompactFlash controller on AT91 chips.
Or choose M to compile the driver as a module named "at91_cf".
+config ELECTRA_CF
+ tristate "Electra CompactFlash Controller"
+ depends on PCMCIA && PPC_PASEMI
+ help
+ Say Y here to support the CompactFlash controller on the
+ PA Semi Electra eval board.
+
config PCCARD_NONSTATIC
tristate
@@ -278,5 +283,3 @@ config PCCARD_IODYN
bool
endif # PCCARD
-
-endmenu
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 4276965517f..6f6478ba717 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_PCMCIA_VRC4171) += vrc4171_card.o
obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o
obj-$(CONFIG_OMAP_CF) += omap_cf.o
obj-$(CONFIG_AT91_CF) += at91_cf.o
+obj-$(CONFIG_ELECTRA_CF) += electra_cf.o
sa11xx_core-y += soc_common.o sa11xx_base.o
pxa2xx_core-y += soc_common.o pxa2xx_base.o
@@ -69,4 +70,5 @@ sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o
pxa2xx_cs-$(CONFIG_ARCH_LUBBOCK) += pxa2xx_lubbock.o sa1111_generic.o
pxa2xx_cs-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o
pxa2xx_cs-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o
+pxa2xx_cs-$(CONFIG_MACH_ARMCORE) += pxa2xx_cm_x270.o
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
index 01874b0bb03..ce9d5c44a7b 100644
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ b/drivers/pcmcia/au1000_xxs1500.c
@@ -50,7 +50,10 @@
#include <asm/au1000.h>
#include <asm/au1000_pcmcia.h>
-#include <asm/xxs1500.h>
+
+#define PCMCIA_MAX_SOCK 0
+#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
+#define PCMCIA_IRQ AU1000_GPIO_4
#if 0
#define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args)
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index d154dee76e7..06a85d7d5aa 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -25,6 +25,7 @@
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/byteorder.h>
+#include <asm/unaligned.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
@@ -401,6 +402,15 @@ EXPORT_SYMBOL(pcmcia_replace_cis);
======================================================================*/
+static inline u16 cis_get_u16(void *ptr)
+{
+ return le16_to_cpu(get_unaligned((__le16 *) ptr));
+}
+static inline u32 cis_get_u32(void *ptr)
+{
+ return le32_to_cpu(get_unaligned((__le32 *) ptr));
+}
+
typedef struct tuple_flags {
u_int link_space:4;
u_int has_link:1;
@@ -461,7 +471,7 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple)
/* Get indirect link from the MFC tuple */
read_cis_cache(s, LINK_SPACE(tuple->Flags),
tuple->LinkOffset, 5, link);
- ofs = le32_to_cpu(*(__le32 *)(link+1));
+ ofs = cis_get_u32(link + 1);
SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
/* Move to the next indirect link */
tuple->LinkOffset += 5;
@@ -668,10 +678,10 @@ static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
u_char *p;
if (tuple->TupleDataLen < 5)
return CS_BAD_TUPLE;
- p = (u_char *)tuple->TupleData;
- csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(__le16 *)p)-2;
- csum->len = le16_to_cpu(*(__le16 *)(p + 2));
- csum->sum = *(p+4);
+ p = (u_char *) tuple->TupleData;
+ csum->addr = tuple->CISOffset + cis_get_u16(p) - 2;
+ csum->len = cis_get_u16(p + 2);
+ csum->sum = *(p + 4);
return CS_SUCCESS;
}
@@ -681,7 +691,7 @@ static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
{
if (tuple->TupleDataLen < 4)
return CS_BAD_TUPLE;
- link->addr = le32_to_cpu(*(__le32 *)tuple->TupleData);
+ link->addr = cis_get_u32(tuple->TupleData);
return CS_SUCCESS;
}
@@ -700,7 +710,8 @@ static int parse_longlink_mfc(tuple_t *tuple,
return CS_BAD_TUPLE;
for (i = 0; i < link->nfn; i++) {
link->fn[i].space = *p; p++;
- link->fn[i].addr = le32_to_cpu(*(__le32 *)p); p += 4;
+ link->fn[i].addr = cis_get_u32(p);
+ p += 4;
}
return CS_SUCCESS;
}
@@ -787,12 +798,10 @@ static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
{
- __le16 *p;
if (tuple->TupleDataLen < 4)
return CS_BAD_TUPLE;
- p = (__le16 *)tuple->TupleData;
- m->manf = le16_to_cpu(p[0]);
- m->card = le16_to_cpu(p[1]);
+ m->manf = cis_get_u16(tuple->TupleData);
+ m->card = cis_get_u16(tuple->TupleData + 2);
return CS_SUCCESS;
}
@@ -1091,7 +1100,7 @@ static int parse_cftable_entry(tuple_t *tuple,
break;
case 0x20:
entry->mem.nwin = 1;
- entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8;
+ entry->mem.win[0].len = cis_get_u16(p) << 8;
entry->mem.win[0].card_addr = 0;
entry->mem.win[0].host_addr = 0;
p += 2;
@@ -1099,9 +1108,8 @@ static int parse_cftable_entry(tuple_t *tuple,
break;
case 0x40:
entry->mem.nwin = 1;
- entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8;
- entry->mem.win[0].card_addr =
- le16_to_cpu(*(__le16 *)(p+2)) << 8;
+ entry->mem.win[0].len = cis_get_u16(p) << 8;
+ entry->mem.win[0].card_addr = cis_get_u16(p + 2) << 8;
entry->mem.win[0].host_addr = 0;
p += 4;
if (p > q) return CS_BAD_TUPLE;
@@ -1138,7 +1146,7 @@ static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar)
p = (u_char *)tuple->TupleData;
bar->attr = *p;
p += 2;
- bar->size = le32_to_cpu(*(__le32 *)p);
+ bar->size = cis_get_u32(p);
return CS_SUCCESS;
}
@@ -1151,7 +1159,7 @@ static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
return CS_BAD_TUPLE;
config->last_idx = *(++p);
p++;
- config->base = le32_to_cpu(*(__le32 *)p);
+ config->base = cis_get_u32(p);
config->subtuples = tuple->TupleDataLen - 6;
return CS_SUCCESS;
}
@@ -1267,7 +1275,7 @@ static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
v2->vers = p[0];
v2->comply = p[1];
- v2->dindex = le16_to_cpu(*(__le16 *)(p+2));
+ v2->dindex = cis_get_u16(p +2 );
v2->vspec8 = p[6];
v2->vspec9 = p[7];
v2->nhdr = p[8];
@@ -1308,8 +1316,8 @@ static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
fmt->type = p[0];
fmt->edc = p[1];
- fmt->offset = le32_to_cpu(*(__le32 *)(p+2));
- fmt->length = le32_to_cpu(*(__le32 *)(p+6));
+ fmt->offset = cis_get_u32(p + 2);
+ fmt->length = cis_get_u32(p + 6);
return CS_SUCCESS;
}
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index f8b13f0270d..a0aca46ce87 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -907,18 +907,14 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
EXPORT_SYMBOL(pcmcia_insert_card);
-static int pcmcia_socket_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int pcmcia_socket_uevent(struct device *dev,
+ struct kobj_uevent_env *env)
{
struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
- int i = 0, length = 0;
- if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "SOCKET_NO=%u", s->sock))
+ if (add_uevent_var(env, "SOCKET_NO=%u", s->sock))
return -ENOMEM;
- envp[i] = NULL;
-
return 0;
}
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index a99607142fc..7bf78c12789 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -23,6 +23,7 @@
#include <linux/crc32.h>
#include <linux/firmware.h>
#include <linux/kref.h>
+#include <linux/dma-mapping.h>
#define IN_CARD_SERVICES
#include <pcmcia/cs_types.h>
@@ -670,6 +671,9 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
p_dev->dev.bus = &pcmcia_bus_type;
p_dev->dev.parent = s->dev.parent;
p_dev->dev.release = pcmcia_release_dev;
+ /* by default don't allow DMA */
+ p_dev->dma_mask = DMA_MASK_NONE;
+ p_dev->dev.dma_mask = &p_dev->dma_mask;
bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
p_dev->devname = kmalloc(6 + bus_id_len + 1, GFP_KERNEL);
@@ -1064,11 +1068,10 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
#ifdef CONFIG_HOTPLUG
-static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct pcmcia_device *p_dev;
- int i, length = 0;
+ int i;
u32 hash[4] = { 0, 0, 0, 0};
if (!dev)
@@ -1083,23 +1086,13 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
}
- i = 0;
-
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "SOCKET_NO=%u",
- p_dev->socket->sock))
+ if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVICE_NO=%02X",
- p_dev->device_no))
+ if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+ if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
"pa%08Xpb%08Xpc%08Xpd%08X",
p_dev->has_manf_id ? p_dev->manf_id : 0,
p_dev->has_card_id ? p_dev->card_id : 0,
@@ -1112,15 +1105,12 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
hash[3]))
return -ENOMEM;
- envp[i] = NULL;
-
return 0;
}
#else
-static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c
new file mode 100644
index 00000000000..0a6cea1316b
--- /dev/null
+++ b/drivers/pcmcia/electra_cf.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Based on drivers/pcmcia/omap_cf.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+
+#include <pcmcia/ss.h>
+#include <asm/of_platform.h>
+
+static const char driver_name[] = "electra-cf";
+
+struct electra_cf_socket {
+ struct pcmcia_socket socket;
+
+ struct timer_list timer;
+ unsigned present:1;
+ unsigned active:1;
+
+ struct of_device *ofdev;
+ unsigned long mem_phys;
+ void __iomem * mem_base;
+ unsigned long mem_size;
+ void __iomem * io_virt;
+ unsigned int io_base;
+ unsigned int io_size;
+ u_int irq;
+ struct resource iomem;
+ void __iomem * gpio_base;
+ int gpio_detect;
+ int gpio_vsense;
+ int gpio_3v;
+ int gpio_5v;
+};
+
+#define POLL_INTERVAL (2 * HZ)
+
+
+static int electra_cf_present(struct electra_cf_socket *cf)
+{
+ unsigned int gpio;
+
+ gpio = in_le32(cf->gpio_base+0x40);
+ return !(gpio & (1 << cf->gpio_detect));
+}
+
+static int electra_cf_ss_init(struct pcmcia_socket *s)
+{
+ return 0;
+}
+
+/* the timer is primarily to kick this socket's pccardd */
+static void electra_cf_timer(unsigned long _cf)
+{
+ struct electra_cf_socket *cf = (void *) _cf;
+ int present = electra_cf_present(cf);
+
+ if (present != cf->present) {
+ cf->present = present;
+ pcmcia_parse_events(&cf->socket, SS_DETECT);
+ }
+
+ if (cf->active)
+ mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
+}
+
+static irqreturn_t electra_cf_irq(int irq, void *_cf)
+{
+ electra_cf_timer((unsigned long)_cf);
+ return IRQ_HANDLED;
+}
+
+static int electra_cf_get_status(struct pcmcia_socket *s, u_int *sp)
+{
+ struct electra_cf_socket *cf;
+
+ if (!sp)
+ return -EINVAL;
+
+ cf = container_of(s, struct electra_cf_socket, socket);
+
+ /* NOTE CF is always 3VCARD */
+ if (electra_cf_present(cf)) {
+ *sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
+
+ s->pci_irq = cf->irq;
+ } else
+ *sp = 0;
+ return 0;
+}
+
+static int electra_cf_set_socket(struct pcmcia_socket *sock,
+ struct socket_state_t *s)
+{
+ unsigned int gpio;
+ unsigned int vcc;
+ struct electra_cf_socket *cf;
+
+ cf = container_of(sock, struct electra_cf_socket, socket);
+
+ /* "reset" means no power in our case */
+ vcc = (s->flags & SS_RESET) ? 0 : s->Vcc;
+
+ switch (vcc) {
+ case 0:
+ gpio = 0;
+ break;
+ case 33:
+ gpio = (1 << cf->gpio_3v);
+ break;
+ case 5:
+ gpio = (1 << cf->gpio_5v);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ gpio |= 1 << (cf->gpio_3v + 16); /* enwr */
+ gpio |= 1 << (cf->gpio_5v + 16); /* enwr */
+ out_le32(cf->gpio_base+0x90, gpio);
+
+ pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n",
+ driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask);
+
+ return 0;
+}
+
+static int electra_cf_set_io_map(struct pcmcia_socket *s,
+ struct pccard_io_map *io)
+{
+ return 0;
+}
+
+static int electra_cf_set_mem_map(struct pcmcia_socket *s,
+ struct pccard_mem_map *map)
+{
+ struct electra_cf_socket *cf;
+
+ if (map->card_start)
+ return -EINVAL;
+ cf = container_of(s, struct electra_cf_socket, socket);
+ map->static_start = cf->mem_phys;
+ map->flags &= MAP_ACTIVE|MAP_ATTRIB;
+ if (!(map->flags & MAP_ATTRIB))
+ map->static_start += 0x800;
+ return 0;
+}
+
+static struct pccard_operations electra_cf_ops = {
+ .init = electra_cf_ss_init,
+ .get_status = electra_cf_get_status,
+ .set_socket = electra_cf_set_socket,
+ .set_io_map = electra_cf_set_io_map,
+ .set_mem_map = electra_cf_set_mem_map,
+};
+
+static int __devinit electra_cf_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device *device = &ofdev->dev;
+ struct device_node *np = ofdev->node;
+ struct electra_cf_socket *cf;
+ struct resource mem, io;
+ int status;
+ const unsigned int *prop;
+ int err;
+ struct vm_struct *area;
+
+ err = of_address_to_resource(np, 0, &mem);
+ if (err)
+ return -EINVAL;
+
+ err = of_address_to_resource(np, 1, &io);
+ if (err)
+ return -EINVAL;
+
+ cf = kzalloc(sizeof *cf, GFP_KERNEL);
+ if (!cf)
+ return -ENOMEM;
+
+ setup_timer(&cf->timer, electra_cf_timer, (unsigned long)cf);
+ cf->irq = NO_IRQ;
+
+ cf->ofdev = ofdev;
+ cf->mem_phys = mem.start;
+ cf->mem_size = PAGE_ALIGN(mem.end - mem.start);
+ cf->mem_base = ioremap(cf->mem_phys, cf->mem_size);
+ cf->io_size = PAGE_ALIGN(io.end - io.start);
+
+ area = __get_vm_area(cf->io_size, 0, PHB_IO_BASE, PHB_IO_END);
+ if (area == NULL)
+ return -ENOMEM;
+
+ cf->io_virt = (void __iomem *)(area->addr);
+
+ cf->gpio_base = ioremap(0xfc103000, 0x1000);
+ dev_set_drvdata(device, cf);
+
+ if (!cf->mem_base || !cf->io_virt || !cf->gpio_base ||
+ (__ioremap_at(io.start, cf->io_virt, cf->io_size,
+ _PAGE_NO_CACHE | _PAGE_GUARDED) == NULL)) {
+ dev_err(device, "can't ioremap ranges\n");
+ status = -ENOMEM;
+ goto fail1;
+ }
+
+
+ cf->io_base = (unsigned long)cf->io_virt - VMALLOC_END;
+
+ cf->iomem.start = (unsigned long)cf->mem_base;
+ cf->iomem.end = (unsigned long)cf->mem_base + (mem.end - mem.start);
+ cf->iomem.flags = IORESOURCE_MEM;
+
+ cf->irq = irq_of_parse_and_map(np, 0);
+
+ status = request_irq(cf->irq, electra_cf_irq, IRQF_SHARED,
+ driver_name, cf);
+ if (status < 0) {
+ dev_err(device, "request_irq failed\n");
+ goto fail1;
+ }
+
+ cf->socket.pci_irq = cf->irq;
+
+ prop = of_get_property(np, "card-detect-gpio", NULL);
+ if (!prop)
+ goto fail1;
+ cf->gpio_detect = *prop;
+
+ prop = of_get_property(np, "card-vsense-gpio", NULL);
+ if (!prop)
+ goto fail1;
+ cf->gpio_vsense = *prop;
+
+ prop = of_get_property(np, "card-3v-gpio", NULL);
+ if (!prop)
+ goto fail1;
+ cf->gpio_3v = *prop;
+
+ prop = of_get_property(np, "card-5v-gpio", NULL);
+ if (!prop)
+ goto fail1;
+ cf->gpio_5v = *prop;
+
+ cf->socket.io_offset = cf->io_base;
+
+ /* reserve chip-select regions */
+ if (!request_mem_region(cf->mem_phys, cf->mem_size, driver_name)) {
+ status = -ENXIO;
+ dev_err(device, "Can't claim memory region\n");
+ goto fail1;
+ }
+
+ if (!request_region(cf->io_base, cf->io_size, driver_name)) {
+ status = -ENXIO;
+ dev_err(device, "Can't claim I/O region\n");
+ goto fail2;
+ }
+
+ cf->socket.owner = THIS_MODULE;
+ cf->socket.dev.parent = &ofdev->dev;
+ cf->socket.ops = &electra_cf_ops;
+ cf->socket.resource_ops = &pccard_static_ops;
+ cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP |
+ SS_CAP_MEM_ALIGN;
+ cf->socket.map_size = 0x800;
+
+ status = pcmcia_register_socket(&cf->socket);
+ if (status < 0) {
+ dev_err(device, "pcmcia_register_socket failed\n");
+ goto fail3;
+ }
+
+ dev_info(device, "at mem 0x%lx io 0x%lx irq %d\n",
+ cf->mem_phys, io.start, cf->irq);
+
+ cf->active = 1;
+ electra_cf_timer((unsigned long)cf);
+ return 0;
+
+fail3:
+ release_region(cf->io_base, cf->io_size);
+fail2:
+ release_mem_region(cf->mem_phys, cf->mem_size);
+fail1:
+ if (cf->irq != NO_IRQ)
+ free_irq(cf->irq, cf);
+
+ if (cf->io_virt)
+ __iounmap_at(cf->io_virt, cf->io_size);
+ if (cf->mem_base)
+ iounmap(cf->mem_base);
+ if (cf->gpio_base)
+ iounmap(cf->gpio_base);
+ device_init_wakeup(&ofdev->dev, 0);
+ kfree(cf);
+ return status;
+
+}
+
+static int __devexit electra_cf_remove(struct of_device *ofdev)
+{
+ struct device *device = &ofdev->dev;
+ struct electra_cf_socket *cf;
+
+ cf = dev_get_drvdata(device);
+
+ cf->active = 0;
+ pcmcia_unregister_socket(&cf->socket);
+ free_irq(cf->irq, cf);
+ del_timer_sync(&cf->timer);
+
+ __iounmap_at(cf->io_virt, cf->io_size);
+ iounmap(cf->mem_base);
+ iounmap(cf->gpio_base);
+ release_mem_region(cf->mem_phys, cf->mem_size);
+ release_region(cf->io_base, cf->io_size);
+
+ kfree(cf);
+
+ return 0;
+}
+
+static struct of_device_id electra_cf_match[] = {
+ {
+ .compatible = "electra-cf",
+ },
+ {},
+};
+
+static struct of_platform_driver electra_cf_driver = {
+ .name = (char *)driver_name,
+ .match_table = electra_cf_match,
+ .probe = electra_cf_probe,
+ .remove = electra_cf_remove,
+};
+
+static int __init electra_cf_init(void)
+{
+ return of_register_platform_driver(&electra_cf_driver);
+}
+module_init(electra_cf_init);
+
+static void __exit electra_cf_exit(void)
+{
+ of_unregister_platform_driver(&electra_cf_driver);
+}
+module_exit(electra_cf_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi Electra CF driver");
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 71b33707117..839bb1c0db5 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -101,7 +101,7 @@ static int ignore = -1;
/* Bit map or list of interrupts to choose from */
static u_int irq_mask = 0xffff;
static int irq_list[16];
-static int irq_list_count;
+static unsigned int irq_list_count;
/* The card status change interrupt -- 0 means autoselect */
static int cs_irq = 0;
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index 67d28ee80f2..c5e0d89c3ec 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -22,9 +22,9 @@
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+#include <linux/bitops.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/bitops.h>
#include <asm/system.h>
#include <asm/addrspace.h>
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index b0198549846..d182760f035 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -48,9 +48,9 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fsl_devices.h>
+#include <linux/bitops.h>
#include <asm/io.h>
-#include <asm/bitops.h>
#include <asm/system.h>
#include <asm/time.h>
#include <asm/mpc8xx.h>
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index dd0ddf19ee5..abc10fe49bd 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -58,7 +58,7 @@ MODULE_AUTHOR("Jun Komuro <komurojun-mbn@nifty.com>");
static int irq_mode = 1; /* 0 = ISA interrupt, 1 = PCI interrupt */
static int irq_list[16];
-static int irq_list_count = 0;
+static unsigned int irq_list_count = 0;
module_param(irq_mode, int, 0444);
module_param_array(irq_list, int, &irq_list_count, 0444);
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index dca9f8549b3..874923fcb2f 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -58,7 +58,7 @@ static inline u_int pxa2xx_mcxx_asst(u_int pcmcia_cycle_ns,
u_int mem_clk_10khz)
{
u_int code = pcmcia_cycle_ns * mem_clk_10khz;
- return (code / 300000) + ((code % 300000) ? 1 : 0) - 1;
+ return (code / 300000) + ((code % 300000) ? 1 : 0) + 1;
}
static inline u_int pxa2xx_mcxx_setup(u_int pcmcia_cycle_ns,
diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c
new file mode 100644
index 00000000000..fbf2f3a6984
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_cm_x270.c
@@ -0,0 +1,175 @@
+/*
+ * linux/drivers/pcmcia/pxa/pxa_cm_x270.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.
+ *
+ * Compulab Ltd., 2003, 2007
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+
+#include <pcmcia/ss.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/cm-x270.h>
+
+#include "soc_common.h"
+
+static struct pcmcia_irqs irqs[] = {
+ { 0, PCMCIA_S0_CD_VALID, "PCMCIA0 CD" },
+ { 1, PCMCIA_S1_CD_VALID, "PCMCIA1 CD" },
+};
+
+static int cmx270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+ GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
+ GPIO_bit(GPIO49_nPWE) |
+ GPIO_bit(GPIO50_nPIOR) |
+ GPIO_bit(GPIO51_nPIOW) |
+ GPIO_bit(GPIO85_nPCE_1) |
+ GPIO_bit(GPIO54_nPCE_2);
+
+ pxa_gpio_mode(GPIO48_nPOE_MD);
+ pxa_gpio_mode(GPIO49_nPWE_MD);
+ pxa_gpio_mode(GPIO50_nPIOR_MD);
+ pxa_gpio_mode(GPIO51_nPIOW_MD);
+ pxa_gpio_mode(GPIO85_nPCE_1_MD);
+ pxa_gpio_mode(GPIO54_nPCE_2_MD);
+ pxa_gpio_mode(GPIO55_nPREG_MD);
+ pxa_gpio_mode(GPIO56_nPWAIT_MD);
+ pxa_gpio_mode(GPIO57_nIOIS16_MD);
+
+ /* Reset signal */
+ pxa_gpio_mode(GPIO53_nPCE_2 | GPIO_OUT);
+ GPCR(GPIO53_nPCE_2) = GPIO_bit(GPIO53_nPCE_2);
+
+ set_irq_type(PCMCIA_S0_CD_VALID, IRQ_TYPE_EDGE_BOTH);
+ set_irq_type(PCMCIA_S1_CD_VALID, IRQ_TYPE_EDGE_BOTH);
+
+ /* irq's for slots: */
+ set_irq_type(PCMCIA_S0_RDYINT, IRQ_TYPE_EDGE_FALLING);
+ set_irq_type(PCMCIA_S1_RDYINT, IRQ_TYPE_EDGE_FALLING);
+
+ skt->irq = (skt->nr == 0) ? PCMCIA_S0_RDYINT : PCMCIA_S1_RDYINT;
+ return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
+}
+
+static void cmx270_pcmcia_shutdown(struct soc_pcmcia_socket *skt)
+{
+ soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
+
+ set_irq_type(IRQ_TO_GPIO(PCMCIA_S0_CD_VALID), IRQ_TYPE_NONE);
+ set_irq_type(IRQ_TO_GPIO(PCMCIA_S1_CD_VALID), IRQ_TYPE_NONE);
+
+ set_irq_type(IRQ_TO_GPIO(PCMCIA_S0_RDYINT), IRQ_TYPE_NONE);
+ set_irq_type(IRQ_TO_GPIO(PCMCIA_S1_RDYINT), IRQ_TYPE_NONE);
+}
+
+
+static void cmx270_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+ struct pcmcia_state *state)
+{
+ state->detect = (PCC_DETECT(skt->nr) == 0) ? 1 : 0;
+ state->ready = (PCC_READY(skt->nr) == 0) ? 0 : 1;
+ state->bvd1 = 1;
+ state->bvd2 = 1;
+ state->vs_3v = 0;
+ state->vs_Xv = 0;
+ state->wrprot = 0; /* not available */
+}
+
+
+static int cmx270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+ const socket_state_t *state)
+{
+ GPSR(GPIO49_nPWE) = GPIO_bit(GPIO49_nPWE);
+ pxa_gpio_mode(GPIO49_nPWE | GPIO_OUT);
+
+ switch (skt->nr) {
+ case 0:
+ if (state->flags & SS_RESET) {
+ GPCR(GPIO49_nPWE) = GPIO_bit(GPIO49_nPWE);
+ GPSR(GPIO53_nPCE_2) = GPIO_bit(GPIO53_nPCE_2);
+ udelay(10);
+ GPCR(GPIO53_nPCE_2) = GPIO_bit(GPIO53_nPCE_2);
+ GPSR(GPIO49_nPWE) = GPIO_bit(GPIO49_nPWE);
+ }
+ break;
+ case 1:
+ if (state->flags & SS_RESET) {
+ GPCR(GPIO49_nPWE) = GPIO_bit(GPIO49_nPWE);
+ GPSR(GPIO53_nPCE_2) = GPIO_bit(GPIO53_nPCE_2);
+ udelay(10);
+ GPCR(GPIO53_nPCE_2) = GPIO_bit(GPIO53_nPCE_2);
+ GPSR(GPIO49_nPWE) = GPIO_bit(GPIO49_nPWE);
+ }
+ break;
+ }
+
+ pxa_gpio_mode(GPIO49_nPWE_MD);
+
+ return 0;
+}
+
+static void cmx270_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+}
+
+static void cmx270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+}
+
+
+static struct pcmcia_low_level cmx270_pcmcia_ops = {
+ .owner = THIS_MODULE,
+ .hw_init = cmx270_pcmcia_hw_init,
+ .hw_shutdown = cmx270_pcmcia_shutdown,
+ .socket_state = cmx270_pcmcia_socket_state,
+ .configure_socket = cmx270_pcmcia_configure_socket,
+ .socket_init = cmx270_pcmcia_socket_init,
+ .socket_suspend = cmx270_pcmcia_socket_suspend,
+ .nr = 2,
+};
+
+static struct platform_device *cmx270_pcmcia_device;
+
+static int __init cmx270_pcmcia_init(void)
+{
+ int ret;
+
+ cmx270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+
+ if (!cmx270_pcmcia_device)
+ return -ENOMEM;
+
+ cmx270_pcmcia_device->dev.platform_data = &cmx270_pcmcia_ops;
+
+ printk(KERN_INFO "Registering cm-x270 PCMCIA interface.\n");
+ ret = platform_device_add(cmx270_pcmcia_device);
+
+ if (ret)
+ platform_device_put(cmx270_pcmcia_device);
+
+ return ret;
+}
+
+static void __exit cmx270_pcmcia_exit(void)
+{
+ platform_device_unregister(cmx270_pcmcia_device);
+}
+
+module_init(cmx270_pcmcia_init);
+module_exit(cmx270_pcmcia_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("CM-x270 PCMCIA driver");
diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c
index 5e9b9a3fd02..1510d6cde3e 100644
--- a/drivers/pcmcia/pxa2xx_lubbock.c
+++ b/drivers/pcmcia/pxa2xx_lubbock.c
@@ -30,35 +30,6 @@
#include "sa1111_generic.h"
static int
-lubbock_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
-{
- /*
- * Setup default state of GPIO outputs
- * before we enable them as outputs.
- */
- GPSR(GPIO48_nPOE) =
- GPIO_bit(GPIO48_nPOE) |
- GPIO_bit(GPIO49_nPWE) |
- GPIO_bit(GPIO50_nPIOR) |
- GPIO_bit(GPIO51_nPIOW) |
- GPIO_bit(GPIO52_nPCE_1) |
- GPIO_bit(GPIO53_nPCE_2);
-
- pxa_gpio_mode(GPIO48_nPOE_MD);
- pxa_gpio_mode(GPIO49_nPWE_MD);
- pxa_gpio_mode(GPIO50_nPIOR_MD);
- pxa_gpio_mode(GPIO51_nPIOW_MD);
- pxa_gpio_mode(GPIO52_nPCE_1_MD);
- pxa_gpio_mode(GPIO53_nPCE_2_MD);
- pxa_gpio_mode(GPIO54_pSKTSEL_MD);
- pxa_gpio_mode(GPIO55_nPREG_MD);
- pxa_gpio_mode(GPIO56_nPWAIT_MD);
- pxa_gpio_mode(GPIO57_nIOIS16_MD);
-
- return sa1111_pcmcia_hw_init(skt);
-}
-
-static int
lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state)
{
@@ -230,7 +201,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
static struct pcmcia_low_level lubbock_pcmcia_ops = {
.owner = THIS_MODULE,
- .hw_init = lubbock_pcmcia_hw_init,
+ .hw_init = sa1111_pcmcia_hw_init,
.hw_shutdown = sa1111_pcmcia_hw_shutdown,
.socket_state = sa1111_pcmcia_socket_state,
.configure_socket = lubbock_pcmcia_configure_socket,
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c
index 383107ba4bd..6fa5eaaab8a 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -43,24 +43,6 @@ static int mst_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
* Setup default state of GPIO outputs
* before we enable them as outputs.
*/
- GPSR(GPIO48_nPOE) =
- GPIO_bit(GPIO48_nPOE) |
- GPIO_bit(GPIO49_nPWE) |
- GPIO_bit(GPIO50_nPIOR) |
- GPIO_bit(GPIO51_nPIOW) |
- GPIO_bit(GPIO85_nPCE_1) |
- GPIO_bit(GPIO54_nPCE_2);
-
- pxa_gpio_mode(GPIO48_nPOE_MD);
- pxa_gpio_mode(GPIO49_nPWE_MD);
- pxa_gpio_mode(GPIO50_nPIOR_MD);
- pxa_gpio_mode(GPIO51_nPIOW_MD);
- pxa_gpio_mode(GPIO85_nPCE_1_MD);
- pxa_gpio_mode(GPIO54_nPCE_2_MD);
- pxa_gpio_mode(GPIO79_pSKTSEL_MD);
- pxa_gpio_mode(GPIO55_nPREG_MD);
- pxa_gpio_mode(GPIO56_nPWAIT_MD);
- pxa_gpio_mode(GPIO57_nIOIS16_MD);
skt->irq = (skt->nr == 0) ? MAINSTONE_S0_IRQ : MAINSTONE_S1_IRQ;
return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
@@ -175,7 +157,6 @@ static int __init mst_pcmcia_init(void)
if (!mst_pcmcia_device)
return -ENOMEM;
- mst_pcmcia_device->dev.uevent_suppress = 0;
mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops;
ret = platform_device_add(mst_pcmcia_device);
@@ -195,3 +176,4 @@ fs_initcall(mst_pcmcia_init);
module_exit(mst_pcmcia_exit);
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index a2daa3f531b..d5c33bd78d6 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -261,7 +261,6 @@ static int __init sharpsl_pcmcia_init(void)
if (!sharpsl_pcmcia_device)
return -ENOMEM;
- sharpsl_pcmcia_device->dev.uevent_suppress = 0;
sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev;
@@ -284,3 +283,4 @@ module_exit(sharpsl_pcmcia_exit);
MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index c158cf38b9d..749ac371091 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -90,7 +90,7 @@ static int do_scan = 1;
/* Bit map of interrupts to choose from */
static u_int irq_mask = 0xffff;
static int irq_list[16];
-static int irq_list_count;
+static unsigned int irq_list_count;
/* The card status change interrupt -- 0 means autoselect */
static int cs_irq;
diff --git a/drivers/pnp/Makefile b/drivers/pnp/Makefile
index a381a92fd1b..26f5abc9c3f 100644
--- a/drivers/pnp/Makefile
+++ b/drivers/pnp/Makefile
@@ -7,3 +7,7 @@ obj-y := core.o card.o driver.o resource.o manager.o support.o interface.o quir
obj-$(CONFIG_PNPACPI) += pnpacpi/
obj-$(CONFIG_PNPBIOS) += pnpbios/
obj-$(CONFIG_ISAPNP) += isapnp/
+
+ifeq ($(CONFIG_PNP_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index 6c0440c20e3..da1c9909eb4 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -104,10 +104,6 @@ int pnp_add_card_id(struct pnp_id *id, struct pnp_card *card)
{
struct pnp_id *ptr;
- if (!id)
- return -EINVAL;
- if (!card)
- return -EINVAL;
id->next = NULL;
ptr = card->id;
while (ptr && ptr->next)
@@ -124,8 +120,6 @@ static void pnp_free_card_ids(struct pnp_card *card)
struct pnp_id *id;
struct pnp_id *next;
- if (!card)
- return;
id = card->id;
while (id) {
next = id->next;
@@ -197,42 +191,39 @@ int pnp_add_card(struct pnp_card *card)
int error;
struct list_head *pos, *temp;
- if (!card || !card->protocol)
- return -EINVAL;
-
sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number,
card->number);
card->dev.parent = &card->protocol->dev;
card->dev.bus = NULL;
card->dev.release = &pnp_release_card;
error = device_register(&card->dev);
+ if (error) {
+ dev_err(&card->dev, "could not register (err=%d)\n", error);
+ return error;
+ }
- if (error == 0) {
- pnp_interface_attach_card(card);
- spin_lock(&pnp_lock);
- list_add_tail(&card->global_list, &pnp_cards);
- list_add_tail(&card->protocol_list, &card->protocol->cards);
- spin_unlock(&pnp_lock);
-
- /* we wait until now to add devices in order to ensure the drivers
- * will be able to use all of the related devices on the card
- * without waiting any unresonable length of time */
- list_for_each(pos, &card->devices) {
- struct pnp_dev *dev = card_to_pnp_dev(pos);
- __pnp_add_device(dev);
- }
+ pnp_interface_attach_card(card);
+ spin_lock(&pnp_lock);
+ list_add_tail(&card->global_list, &pnp_cards);
+ list_add_tail(&card->protocol_list, &card->protocol->cards);
+ spin_unlock(&pnp_lock);
- /* match with card drivers */
- list_for_each_safe(pos, temp, &pnp_card_drivers) {
- struct pnp_card_driver *drv =
- list_entry(pos, struct pnp_card_driver,
- global_list);
- card_probe(card, drv);
- }
- } else
- pnp_err("sysfs failure, card '%s' will be unavailable",
- card->dev.bus_id);
- return error;
+ /* we wait until now to add devices in order to ensure the drivers
+ * will be able to use all of the related devices on the card
+ * without waiting an unreasonable length of time */
+ list_for_each(pos, &card->devices) {
+ struct pnp_dev *dev = card_to_pnp_dev(pos);
+ __pnp_add_device(dev);
+ }
+
+ /* match with card drivers */
+ list_for_each_safe(pos, temp, &pnp_card_drivers) {
+ struct pnp_card_driver *drv =
+ list_entry(pos, struct pnp_card_driver,
+ global_list);
+ card_probe(card, drv);
+ }
+ return 0;
}
/**
@@ -243,8 +234,6 @@ void pnp_remove_card(struct pnp_card *card)
{
struct list_head *pos, *temp;
- if (!card)
- return;
device_unregister(&card->dev);
spin_lock(&pnp_lock);
list_del(&card->global_list);
@@ -263,8 +252,6 @@ void pnp_remove_card(struct pnp_card *card)
*/
int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev)
{
- if (!card || !dev || !dev->protocol)
- return -EINVAL;
dev->dev.parent = &card->dev;
dev->card_link = NULL;
snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%02x:%02x.%02x",
@@ -304,14 +291,15 @@ struct pnp_dev *pnp_request_card_device(struct pnp_card_link *clink,
struct pnp_card *card;
if (!clink || !id)
- goto done;
+ return NULL;
+
card = clink->card;
drv = clink->driver;
if (!from) {
pos = card->devices.next;
} else {
if (from->card != card)
- goto done;
+ return NULL;
pos = from->card_list.next;
}
while (pos != &card->devices) {
@@ -321,7 +309,6 @@ struct pnp_dev *pnp_request_card_device(struct pnp_card_link *clink,
pos = pos->next;
}
-done:
return NULL;
found:
@@ -348,8 +335,6 @@ void pnp_release_card_device(struct pnp_dev *dev)
{
struct pnp_card_driver *drv = dev->card_link->driver;
- if (!drv)
- return;
drv->link.remove = &card_remove;
device_release_driver(&dev->dev);
drv->link.remove = &card_remove_first;
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index d5964feb14d..7d366ca672d 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -125,9 +125,11 @@ int __pnp_add_device(struct pnp_dev *dev)
spin_unlock(&pnp_lock);
ret = device_register(&dev->dev);
- if (ret == 0)
- pnp_interface_attach_device(dev);
- return ret;
+ if (ret)
+ return ret;
+
+ pnp_interface_attach_device(dev);
+ return 0;
}
/*
@@ -138,12 +140,30 @@ int __pnp_add_device(struct pnp_dev *dev)
*/
int pnp_add_device(struct pnp_dev *dev)
{
+ int ret;
+
if (dev->card)
return -EINVAL;
+
dev->dev.parent = &dev->protocol->dev;
sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number,
dev->number);
- return __pnp_add_device(dev);
+ ret = __pnp_add_device(dev);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_PNP_DEBUG
+ {
+ struct pnp_id *id;
+
+ dev_printk(KERN_DEBUG, &dev->dev, "%s device, IDs",
+ dev->protocol->name);
+ for (id = dev->id; id; id = id->next)
+ printk(" %s", id->id);
+ printk(" (%s)\n", dev->active ? "active" : "disabled");
+ }
+#endif
+ return 0;
}
void __pnp_remove_device(struct pnp_dev *dev)
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index 2fa64a6b25c..a262762c5b8 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -86,9 +86,6 @@ static int pnp_device_probe(struct device *dev)
pnp_dev = to_pnp_dev(dev);
pnp_drv = to_pnp_driver(dev->driver);
- pnp_dbg("match found with the PnP device '%s' and the driver '%s'",
- dev->bus_id, pnp_drv->name);
-
error = pnp_device_attach(pnp_dev);
if (error < 0)
return error;
@@ -116,6 +113,8 @@ static int pnp_device_probe(struct device *dev)
error = 0;
} else
goto fail;
+
+ dev_dbg(dev, "driver attached\n");
return error;
fail:
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index a0cfb75bbb8..31548044fdd 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -1,7 +1,7 @@
/*
* interface.c - contains everything related to the user interface
*
- * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@suse.cz>
+ * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@perex.cz>
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
*/
@@ -327,8 +327,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
if (dev->status & PNP_ATTACHED) {
retval = -EBUSY;
- pnp_info("Device %s cannot be configured because it is in use.",
- dev->dev.bus_id);
+ dev_info(&dev->dev, "in use; can't configure\n");
goto done;
}
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index b035d60a1dc..2c925b7cd93 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -1,6 +1,6 @@
/*
* ISA Plug & Play support
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -53,7 +53,7 @@ static int isapnp_rdp; /* Read Data Port */
static int isapnp_reset = 1; /* reset all PnP cards (deactivate) */
static int isapnp_verbose = 1; /* verbose mode */
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Generic ISA Plug & Play support");
module_param(isapnp_disable, int, 0);
MODULE_PARM_DESC(isapnp_disable, "ISA Plug & Play disable");
diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c
index 560ccb64081..2b8266c3d40 100644
--- a/drivers/pnp/isapnp/proc.c
+++ b/drivers/pnp/isapnp/proc.c
@@ -1,6 +1,6 @@
/*
* ISA Plug & Play support
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.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
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index 0826287eef5..c6b3d4e63cc 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -1,7 +1,7 @@
/*
* manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices
*
- * based on isapnp.c resource management (c) Jaroslav Kysela <perex@suse.cz>
+ * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
*/
@@ -22,8 +22,7 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
unsigned long *flags;
if (idx >= PNP_MAX_PORT) {
- pnp_err
- ("More than 4 ports is incompatible with pnp specifications.");
+ dev_err(&dev->dev, "too many I/O port resources\n");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
@@ -64,8 +63,7 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
unsigned long *flags;
if (idx >= PNP_MAX_MEM) {
- pnp_err
- ("More than 8 mems is incompatible with pnp specifications.");
+ dev_err(&dev->dev, "too many memory resources\n");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
@@ -122,8 +120,7 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
};
if (idx >= PNP_MAX_IRQ) {
- pnp_err
- ("More than 2 irqs is incompatible with pnp specifications.");
+ dev_err(&dev->dev, "too many IRQ resources\n");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
@@ -161,7 +158,7 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
return 0;
}
-static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
+static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
{
resource_size_t *start, *end;
unsigned long *flags;
@@ -173,15 +170,13 @@ static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
};
if (idx >= PNP_MAX_DMA) {
- pnp_err
- ("More than 2 dmas is incompatible with pnp specifications.");
- /* pretend we were successful so at least the manager won't try again */
- return 1;
+ dev_err(&dev->dev, "too many DMA resources\n");
+ return;
}
/* check if this resource has been manually set, if so skip */
if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
- return 1;
+ return;
start = &dev->res.dma_resource[idx].start;
end = &dev->res.dma_resource[idx].end;
@@ -191,19 +186,17 @@ static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
*flags |= rule->flags | IORESOURCE_DMA;
*flags &= ~IORESOURCE_UNSET;
- if (!rule->map) {
- *flags |= IORESOURCE_DISABLED;
- return 1; /* skip disabled resource requests */
- }
-
for (i = 0; i < 8; i++) {
if (rule->map & (1 << xtab[i])) {
*start = *end = xtab[i];
if (pnp_check_dma(dev, idx))
- return 1;
+ return;
}
}
- return 0;
+#ifdef MAX_DMA_CHANNELS
+ *start = *end = MAX_DMA_CHANNELS;
+#endif
+ *flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
}
/**
@@ -330,8 +323,7 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
irq = irq->next;
}
while (dma) {
- if (!pnp_assign_dma(dev, dma, ndma))
- goto fail;
+ pnp_assign_dma(dev, dma, ndma);
ndma++;
dma = dma->next;
}
@@ -367,8 +359,7 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
irq = irq->next;
}
while (dma) {
- if (!pnp_assign_dma(dev, dma, ndma))
- goto fail;
+ pnp_assign_dma(dev, dma, ndma);
ndma++;
dma = dma->next;
}
@@ -447,8 +438,7 @@ int pnp_auto_config_dev(struct pnp_dev *dev)
int i = 1;
if (!pnp_can_configure(dev)) {
- pnp_dbg("Device %s does not support resource configuration.",
- dev->dev.bus_id);
+ dev_dbg(&dev->dev, "configuration not supported\n");
return -ENODEV;
}
@@ -465,7 +455,7 @@ int pnp_auto_config_dev(struct pnp_dev *dev)
} while (dep);
}
- pnp_err("Unable to assign resources to device %s.", dev->dev.bus_id);
+ dev_err(&dev->dev, "unable to assign resources\n");
return -EBUSY;
}
@@ -478,17 +468,16 @@ int pnp_auto_config_dev(struct pnp_dev *dev)
int pnp_start_dev(struct pnp_dev *dev)
{
if (!pnp_can_write(dev)) {
- pnp_dbg("Device %s does not support activation.",
- dev->dev.bus_id);
+ dev_dbg(&dev->dev, "activation not supported\n");
return -EINVAL;
}
if (dev->protocol->set(dev, &dev->res) < 0) {
- pnp_err("Failed to activate device %s.", dev->dev.bus_id);
+ dev_err(&dev->dev, "activation failed\n");
return -EIO;
}
- pnp_info("Device %s activated.", dev->dev.bus_id);
+ dev_info(&dev->dev, "activated\n");
return 0;
}
@@ -501,16 +490,15 @@ int pnp_start_dev(struct pnp_dev *dev)
int pnp_stop_dev(struct pnp_dev *dev)
{
if (!pnp_can_disable(dev)) {
- pnp_dbg("Device %s does not support disabling.",
- dev->dev.bus_id);
+ dev_dbg(&dev->dev, "disabling not supported\n");
return -EINVAL;
}
if (dev->protocol->disable(dev) < 0) {
- pnp_err("Failed to disable device %s.", dev->dev.bus_id);
+ dev_err(&dev->dev, "disable failed\n");
return -EIO;
}
- pnp_info("Device %s disabled.", dev->dev.bus_id);
+ dev_info(&dev->dev, "disabled\n");
return 0;
}
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index a5a372222d6..dada8990631 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -130,11 +130,16 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
#ifdef CONFIG_ACPI_SLEEP
static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
{
- return acpi_bus_set_power((acpi_handle) dev->data,
- acpi_pm_device_sleep_state(&dev->dev,
- device_may_wakeup
- (&dev->dev),
- NULL));
+ int power_state;
+
+ power_state = acpi_pm_device_sleep_state(&dev->dev,
+ device_may_wakeup(&dev->dev),
+ NULL);
+ if (power_state < 0)
+ power_state = (state.event == PM_EVENT_ON) ?
+ ACPI_STATE_D0 : ACPI_STATE_D3;
+
+ return acpi_bus_set_power((acpi_handle) dev->data, power_state);
}
static int pnpacpi_resume(struct pnp_dev *dev)
@@ -166,7 +171,6 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
is_exclusive_device(device))
return 0;
- pnp_dbg("ACPI device : hid %s", acpi_device_hid(device));
dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
if (!dev) {
pnp_err("Out of memory");
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 0e3b8d0ff06..11adab13f2b 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -75,6 +75,7 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res,
{
int i = 0;
int irq;
+ int p, t;
if (!valid_IRQ(gsi))
return;
@@ -85,6 +86,23 @@ static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res,
if (i >= PNP_MAX_IRQ)
return;
+ /*
+ * in IO-APIC mode, use overrided attribute. Two reasons:
+ * 1. BIOS bug in DSDT
+ * 2. BIOS uses IO-APIC mode Interrupt Source Override
+ */
+ if (!acpi_get_override_irq(gsi, &t, &p)) {
+ t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
+ p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
+
+ if (triggering != t || polarity != p) {
+ pnp_warn("IRQ %d override to %s, %s",
+ gsi, t ? "edge":"level", p ? "low":"high");
+ triggering = t;
+ polarity = p;
+ }
+ }
+
res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
res->irq_resource[i].flags |= irq_flags(triggering, polarity);
irq = acpi_register_gsi(gsi, triggering, polarity);
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 0691f473e9d..e33e03f7108 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -315,25 +315,31 @@ struct pnp_protocol pnpbios_protocol = {
.disable = pnpbios_disable_resources,
};
-static int insert_device(struct pnp_dev *dev, struct pnp_bios_node *node)
+static int insert_device(struct pnp_bios_node *node)
{
struct list_head *pos;
- struct pnp_dev *pnp_dev;
+ struct pnp_dev *dev;
struct pnp_id *dev_id;
char id[8];
/* check if the device is already added */
- dev->number = node->handle;
list_for_each(pos, &pnpbios_protocol.devices) {
- pnp_dev = list_entry(pos, struct pnp_dev, protocol_list);
- if (dev->number == pnp_dev->number)
+ dev = list_entry(pos, struct pnp_dev, protocol_list);
+ if (dev->number == node->handle)
return -1;
}
- /* set the initial values for the PnP device */
+ dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
+ if (!dev)
+ return -1;
+
dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
- if (!dev_id)
+ if (!dev_id) {
+ kfree(dev);
return -1;
+ }
+
+ dev->number = node->handle;
pnpid32_to_pnpid(node->eisa_id, id);
memcpy(dev_id->id, id, 7);
pnp_add_id(dev_id, dev);
@@ -367,7 +373,6 @@ static void __init build_devlist(void)
unsigned int nodes_got = 0;
unsigned int devs = 0;
struct pnp_bios_node *node;
- struct pnp_dev *dev;
node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
@@ -388,12 +393,7 @@ static void __init build_devlist(void)
break;
}
nodes_got++;
- dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
- if (!dev)
- break;
- if (insert_device(dev, node) < 0)
- kfree(dev);
- else
+ if (insert_device(node) == 0)
devs++;
if (nodenum <= thisnodenum) {
printk(KERN_ERR
@@ -500,7 +500,7 @@ static int __init pnpbios_probe_system(void)
return 0;
}
-static int __init exploding_pnp_bios(struct dmi_system_id *d)
+static int __init exploding_pnp_bios(const struct dmi_system_id *d)
{
printk(KERN_WARNING "%s detected. Disabling PnPBIOS\n", d->ident);
return 0;
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c
index 9d9841f24a8..bb19bc957ba 100644
--- a/drivers/pnp/pnpbios/proc.c
+++ b/drivers/pnp/pnpbios/proc.c
@@ -94,8 +94,9 @@ static int proc_read_escd(char *buf, char **start, off_t pos,
/* sanity check */
if (escd_size > MAX_SANE_ESCD_SIZE) {
- printk(KERN_ERR
- "PnPBIOS: proc_read_escd: ESCD size reported by BIOS read_escd call is too great\n");
+ printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by"
+ " BIOS read_escd call is too great\n");
+ kfree(tmpbuf);
return -EFBIG;
}
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index 6b0cf0c2a08..e903b8c2b1f 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/pnp.h>
#include <linux/io.h>
+#include <linux/kallsyms.h>
#include "base.h"
static void quirk_awe32_resources(struct pnp_dev *dev)
@@ -133,11 +134,18 @@ static struct pnp_fixup pnp_fixups[] = {
void pnp_fixup_device(struct pnp_dev *dev)
{
int i = 0;
+ void (*quirk)(struct pnp_dev *);
while (*pnp_fixups[i].id) {
if (compare_pnp_id(dev->id, pnp_fixups[i].id)) {
- pnp_dbg("Calling quirk for %s", dev->dev.bus_id);
- pnp_fixups[i].quirk_function(dev);
+ quirk = pnp_fixups[i].quirk_function;
+
+#ifdef DEBUG
+ dev_dbg(&dev->dev, "calling quirk 0x%p", quirk);
+ print_fn_descriptor_symbol(": %s()\n",
+ (unsigned long) *quirk);
+#endif
+ (*quirk)(dev);
}
i++;
}
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index ef1286900db..41d73a5e931 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -1,7 +1,7 @@
/*
* resource.c - Contains functions for registering and analyzing resource information
*
- * based on isapnp.c resource management (c) Jaroslav Kysela <perex@suse.cz>
+ * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
*/
@@ -51,7 +51,7 @@ struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev)
/* this should never happen but if it does we'll try to continue */
if (dev->independent)
- pnp_err("independent resource already registered");
+ dev_err(&dev->dev, "independent resource already registered\n");
dev->independent = option;
return option;
}
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c
index a06f980b3ac..55c4563986b 100644
--- a/drivers/pnp/system.c
+++ b/drivers/pnp/system.c
@@ -22,36 +22,39 @@ static const struct pnp_device_id pnp_dev_table[] = {
{"", 0}
};
-static void reserve_range(const char *pnpid, resource_size_t start,
+static void reserve_range(struct pnp_dev *dev, resource_size_t start,
resource_size_t end, int port)
{
- struct resource *res;
char *regionid;
+ const char *pnpid = dev->dev.bus_id;
+ struct resource *res;
regionid = kmalloc(16, GFP_KERNEL);
- if (regionid == NULL)
+ if (!regionid)
return;
+
snprintf(regionid, 16, "pnp %s", pnpid);
if (port)
res = request_region(start, end - start + 1, regionid);
else
res = request_mem_region(start, end - start + 1, regionid);
- if (res == NULL)
- kfree(regionid);
- else
+ if (res)
res->flags &= ~IORESOURCE_BUSY;
+ else
+ kfree(regionid);
+
/*
* Failures at this point are usually harmless. pci quirks for
* example do reserve stuff they know about too, so we may well
* have double reservations.
*/
- printk(KERN_INFO "pnp: %s: %s range 0x%llx-0x%llx %s reserved\n",
- pnpid, port ? "ioport" : "iomem",
- (unsigned long long)start, (unsigned long long)end,
- NULL != res ? "has been" : "could not be");
+ dev_info(&dev->dev, "%s range 0x%llx-0x%llx %s reserved\n",
+ port ? "ioport" : "iomem",
+ (unsigned long long) start, (unsigned long long) end,
+ res ? "has been" : "could not be");
}
-static void reserve_resources_of_dev(const struct pnp_dev *dev)
+static void reserve_resources_of_dev(struct pnp_dev *dev)
{
int i;
@@ -73,7 +76,7 @@ static void reserve_resources_of_dev(const struct pnp_dev *dev)
if (pnp_port_end(dev, i) < pnp_port_start(dev, i))
continue; /* invalid */
- reserve_range(dev->dev.bus_id, pnp_port_start(dev, i),
+ reserve_range(dev, pnp_port_start(dev, i),
pnp_port_end(dev, i), 1);
}
@@ -81,7 +84,7 @@ static void reserve_resources_of_dev(const struct pnp_dev *dev)
if (!pnp_mem_valid(dev, i))
continue;
- reserve_range(dev->dev.bus_id, pnp_mem_start(dev, i),
+ reserve_range(dev, pnp_mem_start(dev, i),
pnp_mem_end(dev, i), 0);
}
}
diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c
index 39a90a6f0f8..bbf3ee10da0 100644
--- a/drivers/power/apm_power.c
+++ b/drivers/power/apm_power.c
@@ -26,65 +26,124 @@ static struct power_supply *main_battery;
static void find_main_battery(void)
{
struct device *dev;
- struct power_supply *bat, *batm;
+ struct power_supply *bat = NULL;
+ struct power_supply *max_charge_bat = NULL;
+ struct power_supply *max_energy_bat = NULL;
union power_supply_propval full;
int max_charge = 0;
+ int max_energy = 0;
main_battery = NULL;
- batm = NULL;
+
list_for_each_entry(dev, &power_supply_class->devices, node) {
bat = dev_get_drvdata(dev);
- /* If none of battery devices cantains 'use_for_apm' flag,
- choice one with maximum design charge */
- if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full)) {
+
+ if (bat->use_for_apm) {
+ /* nice, we explicitly asked to report this battery. */
+ main_battery = bat;
+ return;
+ }
+
+ if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) ||
+ !PSY_PROP(bat, CHARGE_FULL, &full)) {
if (full.intval > max_charge) {
- batm = bat;
+ max_charge_bat = bat;
max_charge = full.intval;
}
+ } else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) ||
+ !PSY_PROP(bat, ENERGY_FULL, &full)) {
+ if (full.intval > max_energy) {
+ max_energy_bat = bat;
+ max_energy = full.intval;
+ }
}
+ }
- if (bat->use_for_apm)
- main_battery = bat;
+ if ((max_energy_bat && max_charge_bat) &&
+ (max_energy_bat != max_charge_bat)) {
+ /* try guess battery with more capacity */
+ if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) {
+ if (max_energy > max_charge * full.intval)
+ main_battery = max_energy_bat;
+ else
+ main_battery = max_charge_bat;
+ } else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN,
+ &full)) {
+ if (max_charge > max_energy / full.intval)
+ main_battery = max_charge_bat;
+ else
+ main_battery = max_energy_bat;
+ } else {
+ /* give up, choice any */
+ main_battery = max_energy_bat;
+ }
+ } else if (max_charge_bat) {
+ main_battery = max_charge_bat;
+ } else if (max_energy_bat) {
+ main_battery = max_energy_bat;
+ } else {
+ /* give up, try the last if any */
+ main_battery = bat;
}
- if (!main_battery)
- main_battery = batm;
}
-static int calculate_time(int status)
+static int calculate_time(int status, int using_charge)
{
- union power_supply_propval charge_full, charge_empty;
- union power_supply_propval charge, I;
+ union power_supply_propval full;
+ union power_supply_propval empty;
+ union power_supply_propval cur;
+ union power_supply_propval I;
+ enum power_supply_property full_prop;
+ enum power_supply_property full_design_prop;
+ enum power_supply_property empty_prop;
+ enum power_supply_property empty_design_prop;
+ enum power_supply_property cur_avg_prop;
+ enum power_supply_property cur_now_prop;
- if (MPSY_PROP(CHARGE_FULL, &charge_full)) {
- /* if battery can't report this property, use design value */
- if (MPSY_PROP(CHARGE_FULL_DESIGN, &charge_full))
+ if (MPSY_PROP(CURRENT_AVG, &I)) {
+ /* if battery can't report average value, use momentary */
+ if (MPSY_PROP(CURRENT_NOW, &I))
return -1;
}
- if (MPSY_PROP(CHARGE_EMPTY, &charge_empty)) {
- /* if battery can't report this property, use design value */
- if (MPSY_PROP(CHARGE_EMPTY_DESIGN, &charge_empty))
- charge_empty.intval = 0;
+ if (using_charge) {
+ full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
+ full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
+ empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+ empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+ cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
+ cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
+ } else {
+ full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
+ full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
+ empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
+ empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+ cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
+ cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
}
- if (MPSY_PROP(CHARGE_AVG, &charge)) {
- /* if battery can't report average value, use momentary */
- if (MPSY_PROP(CHARGE_NOW, &charge))
+ if (_MPSY_PROP(full_prop, &full)) {
+ /* if battery can't report this property, use design value */
+ if (_MPSY_PROP(full_design_prop, &full))
return -1;
}
- if (MPSY_PROP(CURRENT_AVG, &I)) {
+ if (_MPSY_PROP(empty_prop, &empty)) {
+ /* if battery can't report this property, use design value */
+ if (_MPSY_PROP(empty_design_prop, &empty))
+ empty.intval = 0;
+ }
+
+ if (_MPSY_PROP(cur_avg_prop, &cur)) {
/* if battery can't report average value, use momentary */
- if (MPSY_PROP(CURRENT_NOW, &I))
+ if (_MPSY_PROP(cur_now_prop, &cur))
return -1;
}
if (status == POWER_SUPPLY_STATUS_CHARGING)
- return ((charge.intval - charge_full.intval) * 60L) /
- I.intval;
+ return ((cur.intval - full.intval) * 60L) / I.intval;
else
- return -((charge.intval - charge_empty.intval) * 60L) /
- I.intval;
+ return -((cur.intval - empty.intval) * 60L) / I.intval;
}
static int calculate_capacity(int using_charge)
@@ -200,18 +259,22 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
info->units = APM_UNITS_MINS;
if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
- if (MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full)) {
- if (MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
- info->time = calculate_time(status.intval);
- else
- info->time = time_to_full.intval / 60;
+ if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) ||
+ !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) {
+ info->time = time_to_full.intval / 60;
+ } else {
+ info->time = calculate_time(status.intval, 0);
+ if (info->time == -1)
+ info->time = calculate_time(status.intval, 1);
}
} else {
- if (MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty)) {
- if (MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
- info->time = calculate_time(status.intval);
- else
- info->time = time_to_empty.intval / 60;
+ if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||
+ !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) {
+ info->time = time_to_empty.intval / 60;
+ } else {
+ info->time = calculate_time(status.intval, 0);
+ if (info->time == -1)
+ info->time = calculate_time(status.intval, 1);
}
}
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c
index be7021ee361..bdb9b7285b3 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/ds2760_battery.c
@@ -366,7 +366,7 @@ static int ds2760_battery_probe(struct platform_device *pdev)
retval = power_supply_register(&pdev->dev, &di->bat);
if (retval) {
- dev_err(di->dev, "failed to register battery");
+ dev_err(di->dev, "failed to register battery\n");
goto batt_failed;
}
diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h
index a9880d468ee..f38ba482be7 100644
--- a/drivers/power/power_supply.h
+++ b/drivers/power/power_supply.h
@@ -14,8 +14,7 @@
extern int power_supply_create_attrs(struct power_supply *psy);
extern void power_supply_remove_attrs(struct power_supply *psy);
-extern int power_supply_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size);
+extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env);
#else
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index de3155b2128..249f61bae63 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -195,11 +195,10 @@ static char *kstruprdup(const char *str, gfp_t gfp)
return ret;
}
-int power_supply_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct power_supply *psy = dev_get_drvdata(dev);
- int i = 0, length = 0, ret = 0, j;
+ int ret = 0, j;
char *prop_buf;
char *attrname;
@@ -212,8 +211,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp,
dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "POWER_SUPPLY_NAME=%s", psy->name);
+ ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name);
if (ret)
return ret;
@@ -243,9 +241,7 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp,
dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "POWER_SUPPLY_%s=%s",
- attrname, prop_buf);
+ ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
kfree(attrname);
if (ret)
goto out;
@@ -282,14 +278,11 @@ int power_supply_uevent(struct device *dev, char **envp, int num_envp,
dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
- &length, "POWER_SUPPLY_%s=%s",
- attrname, prop_buf);
+ ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
kfree(attrname);
if (ret)
goto out;
}
- envp[i] = NULL;
out:
free_page((unsigned long)prop_buf);
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index 85e21614f86..87b3493d88e 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/notifier.h>
#include <linux/ioctl.h>
+#include <linux/fb.h>
#include <asm/firmware.h>
#include <asm/ps3av.h>
@@ -33,6 +34,8 @@
#define BUFSIZE 4096 /* vuart buf size */
#define PS3AV_BUF_SIZE 512 /* max packet size */
+static int safe_mode;
+
static int timeout = 5000; /* in msec ( 5 sec ) */
module_param(timeout, int, 0644);
@@ -491,10 +494,10 @@ static int ps3av_set_videomode(void)
return 0;
}
-static void ps3av_set_videomode_cont(u32 id, u32 old_id)
+static void ps3av_set_videomode_packet(u32 id)
{
struct ps3av_pkt_avb_param avb_param;
- int i;
+ unsigned int i;
u32 len = 0, av_video_cs;
const struct avset_video_mode *video_mode;
int res;
@@ -507,24 +510,6 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
ps3av->av_hw_conf.num_of_avmulti;
avb_param.num_of_av_audio_pkt = 0;
- /* video signal off */
- ps3av_set_video_disable_sig();
-
- /* Retail PS3 product doesn't support this */
- if (id & PS3AV_MODE_HDCP_OFF) {
- res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF);
- if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
- dev_dbg(&ps3av->dev->core, "Not supported\n");
- else if (res)
- dev_dbg(&ps3av->dev->core,
- "ps3av_cmd_av_hdmi_mode failed\n");
- } else if (old_id & PS3AV_MODE_HDCP_OFF) {
- res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL);
- if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
- dev_dbg(&ps3av->dev->core,
- "ps3av_cmd_av_hdmi_mode failed\n");
- }
-
/* video_pkt */
for (i = 0; i < avb_param.num_of_video_pkt; i++)
len += ps3av_cmd_set_video_mode(&avb_param.buf[len],
@@ -555,6 +540,42 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
__func__);
else if (res)
dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n");
+}
+
+static void ps3av_set_videomode_cont(u32 id, u32 old_id)
+{
+ static int vesa = 0;
+ int res;
+
+ /* video signal off */
+ ps3av_set_video_disable_sig();
+
+ /*
+ * AV backend needs non-VESA mode setting at least one time
+ * when VESA mode is used.
+ */
+ if (vesa == 0 && (id & PS3AV_MODE_MASK) >= 11) {
+ /* vesa mode */
+ ps3av_set_videomode_packet(2); /* 480P */
+ }
+ vesa = 1;
+
+ /* Retail PS3 product doesn't support this */
+ if (id & PS3AV_MODE_HDCP_OFF) {
+ res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF);
+ if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
+ dev_dbg(&ps3av->dev->core, "Not supported\n");
+ else if (res)
+ dev_dbg(&ps3av->dev->core,
+ "ps3av_cmd_av_hdmi_mode failed\n");
+ } else if (old_id & PS3AV_MODE_HDCP_OFF) {
+ res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL);
+ if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
+ dev_dbg(&ps3av->dev->core,
+ "ps3av_cmd_av_hdmi_mode failed\n");
+ }
+
+ ps3av_set_videomode_packet(id);
msleep(1500);
/* av video mute */
@@ -567,165 +588,247 @@ static void ps3avd(struct work_struct *work)
complete(&ps3av->done);
}
-static int ps3av_vid2table_id(int vid)
-{
- int i;
-
- for (i = 1; i < ARRAY_SIZE(video_mode_table); i++)
- if (video_mode_table[i].vid == vid)
- return i;
- return -1;
-}
+#define SHIFT_50 0
+#define SHIFT_60 4
+#define SHIFT_VESA 8
+
+static const struct {
+ unsigned mask : 19;
+ unsigned id : 4;
+} ps3av_preferred_modes[] = {
+ { .mask = PS3AV_RESBIT_WUXGA << SHIFT_VESA, .id = 13 },
+ { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_60, .id = 5 },
+ { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_50, .id = 10 },
+ { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_60, .id = 4 },
+ { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_50, .id = 9 },
+ { .mask = PS3AV_RESBIT_SXGA << SHIFT_VESA, .id = 12 },
+ { .mask = PS3AV_RESBIT_WXGA << SHIFT_VESA, .id = 11 },
+ { .mask = PS3AV_RESBIT_1280x720P << SHIFT_60, .id = 3 },
+ { .mask = PS3AV_RESBIT_1280x720P << SHIFT_50, .id = 8 },
+ { .mask = PS3AV_RESBIT_720x480P << SHIFT_60, .id = 2 },
+ { .mask = PS3AV_RESBIT_720x576P << SHIFT_50, .id = 7 },
+};
-static int ps3av_resbit2vid(u32 res_50, u32 res_60)
+static int ps3av_resbit2id(u32 res_50, u32 res_60, u32 res_vesa)
{
- int vid = -1;
+ unsigned int i;
+ u32 res_all;
+
+ /*
+ * We mask off the resolution bits we care about and combine the
+ * results in one bitfield, so make sure there's no overlap
+ */
+ BUILD_BUG_ON(PS3AV_RES_MASK_50 << SHIFT_50 &
+ PS3AV_RES_MASK_60 << SHIFT_60);
+ BUILD_BUG_ON(PS3AV_RES_MASK_50 << SHIFT_50 &
+ PS3AV_RES_MASK_VESA << SHIFT_VESA);
+ BUILD_BUG_ON(PS3AV_RES_MASK_60 << SHIFT_60 &
+ PS3AV_RES_MASK_VESA << SHIFT_VESA);
+ res_all = (res_50 & PS3AV_RES_MASK_50) << SHIFT_50 |
+ (res_60 & PS3AV_RES_MASK_60) << SHIFT_60 |
+ (res_vesa & PS3AV_RES_MASK_VESA) << SHIFT_VESA;
+
+ if (!res_all)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(ps3av_preferred_modes); i++)
+ if (res_all & ps3av_preferred_modes[i].mask)
+ return ps3av_preferred_modes[i].id;
- if (res_50 > res_60) { /* if res_50 == res_60, res_60 will be used */
- if (res_50 & PS3AV_RESBIT_1920x1080P)
- vid = PS3AV_CMD_VIDEO_VID_1080P_50HZ;
- else if (res_50 & PS3AV_RESBIT_1920x1080I)
- vid = PS3AV_CMD_VIDEO_VID_1080I_50HZ;
- else if (res_50 & PS3AV_RESBIT_1280x720P)
- vid = PS3AV_CMD_VIDEO_VID_720P_50HZ;
- else if (res_50 & PS3AV_RESBIT_720x576P)
- vid = PS3AV_CMD_VIDEO_VID_576P;
- else
- vid = -1;
- } else {
- if (res_60 & PS3AV_RESBIT_1920x1080P)
- vid = PS3AV_CMD_VIDEO_VID_1080P_60HZ;
- else if (res_60 & PS3AV_RESBIT_1920x1080I)
- vid = PS3AV_CMD_VIDEO_VID_1080I_60HZ;
- else if (res_60 & PS3AV_RESBIT_1280x720P)
- vid = PS3AV_CMD_VIDEO_VID_720P_60HZ;
- else if (res_60 & PS3AV_RESBIT_720x480P)
- vid = PS3AV_CMD_VIDEO_VID_480P;
- else
- vid = -1;
- }
- return vid;
+ return 0;
}
-static int ps3av_hdmi_get_vid(struct ps3av_info_monitor *info)
+static int ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
{
- u32 res_50, res_60;
- int vid = -1;
+ int id;
- if (info->monitor_type != PS3AV_MONITOR_TYPE_HDMI)
- return -1;
+ if (safe_mode)
+ return PS3AV_DEFAULT_HDMI_MODE_ID_REG_60;
/* check native resolution */
- res_50 = info->res_50.native & PS3AV_RES_MASK_50;
- res_60 = info->res_60.native & PS3AV_RES_MASK_60;
- if (res_50 || res_60) {
- vid = ps3av_resbit2vid(res_50, res_60);
- return vid;
+ id = ps3av_resbit2id(info->res_50.native, info->res_60.native,
+ info->res_vesa.native);
+ if (id) {
+ pr_debug("%s: Using native mode %d\n", __func__, id);
+ return id;
}
- /* check resolution */
- res_50 = info->res_50.res_bits & PS3AV_RES_MASK_50;
- res_60 = info->res_60.res_bits & PS3AV_RES_MASK_60;
- if (res_50 || res_60) {
- vid = ps3av_resbit2vid(res_50, res_60);
- return vid;
+ /* check supported resolutions */
+ id = ps3av_resbit2id(info->res_50.res_bits, info->res_60.res_bits,
+ info->res_vesa.res_bits);
+ if (id) {
+ pr_debug("%s: Using supported mode %d\n", __func__, id);
+ return id;
}
if (ps3av->region & PS3AV_REGION_60)
- vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
+ id = PS3AV_DEFAULT_HDMI_MODE_ID_REG_60;
else
- vid = PS3AV_DEFAULT_HDMI_VID_REG_50;
- return vid;
+ id = PS3AV_DEFAULT_HDMI_MODE_ID_REG_50;
+ pr_debug("%s: Using default mode %d\n", __func__, id);
+ return id;
}
-static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf,
- int boot)
+static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info)
{
- int i, res, vid = -1, dvi = 0, rgb = 0;
+ const struct ps3av_info_monitor *info = &monitor_info->info;
+ const struct ps3av_info_audio *audio = info->audio;
+ char id[sizeof(info->monitor_id)*3+1];
+ int i;
+
+ pr_debug("Monitor Info: size %u\n", monitor_info->send_hdr.size);
+
+ pr_debug("avport: %02x\n", info->avport);
+ for (i = 0; i < sizeof(info->monitor_id); i++)
+ sprintf(&id[i*3], " %02x", info->monitor_id[i]);
+ pr_debug("monitor_id: %s\n", id);
+ pr_debug("monitor_type: %02x\n", info->monitor_type);
+ pr_debug("monitor_name: %.*s\n", (int)sizeof(info->monitor_name),
+ info->monitor_name);
+
+ /* resolution */
+ pr_debug("resolution_60: bits: %08x native: %08x\n",
+ info->res_60.res_bits, info->res_60.native);
+ pr_debug("resolution_50: bits: %08x native: %08x\n",
+ info->res_50.res_bits, info->res_50.native);
+ pr_debug("resolution_other: bits: %08x native: %08x\n",
+ info->res_other.res_bits, info->res_other.native);
+ pr_debug("resolution_vesa: bits: %08x native: %08x\n",
+ info->res_vesa.res_bits, info->res_vesa.native);
+
+ /* color space */
+ pr_debug("color space rgb: %02x\n", info->cs.rgb);
+ pr_debug("color space yuv444: %02x\n", info->cs.yuv444);
+ pr_debug("color space yuv422: %02x\n", info->cs.yuv422);
+
+ /* color info */
+ pr_debug("color info red: X %04x Y %04x\n", info->color.red_x,
+ info->color.red_y);
+ pr_debug("color info green: X %04x Y %04x\n", info->color.green_x,
+ info->color.green_y);
+ pr_debug("color info blue: X %04x Y %04x\n", info->color.blue_x,
+ info->color.blue_y);
+ pr_debug("color info white: X %04x Y %04x\n", info->color.white_x,
+ info->color.white_y);
+ pr_debug("color info gamma: %08x\n", info->color.gamma);
+
+ /* other info */
+ pr_debug("supported_AI: %02x\n", info->supported_ai);
+ pr_debug("speaker_info: %02x\n", info->speaker_info);
+ pr_debug("num of audio: %02x\n", info->num_of_audio_block);
+
+ /* audio block */
+ for (i = 0; i < info->num_of_audio_block; i++) {
+ pr_debug("audio[%d] type: %02x max_ch: %02x fs: %02x sbit: "
+ "%02x\n",
+ i, audio->type, audio->max_num_of_ch, audio->fs,
+ audio->sbit);
+ audio++;
+ }
+}
+
+static const struct ps3av_monitor_quirk {
+ const char *monitor_name;
+ u32 clear_60;
+} ps3av_monitor_quirks[] = {
+ {
+ .monitor_name = "DELL 2007WFP",
+ .clear_60 = PS3AV_RESBIT_1920x1080I
+ }, {
+ .monitor_name = "L226WTQ",
+ .clear_60 = PS3AV_RESBIT_1920x1080I |
+ PS3AV_RESBIT_1920x1080P
+ }, {
+ .monitor_name = "SyncMaster",
+ .clear_60 = PS3AV_RESBIT_1920x1080I
+ }
+};
+
+static void ps3av_fixup_monitor_info(struct ps3av_info_monitor *info)
+{
+ unsigned int i;
+ const struct ps3av_monitor_quirk *quirk;
+
+ for (i = 0; i < ARRAY_SIZE(ps3av_monitor_quirks); i++) {
+ quirk = &ps3av_monitor_quirks[i];
+ if (!strncmp(info->monitor_name, quirk->monitor_name,
+ sizeof(info->monitor_name))) {
+ pr_info("%s: Applying quirk for %s\n", __func__,
+ quirk->monitor_name);
+ info->res_60.res_bits &= ~quirk->clear_60;
+ info->res_60.native &= ~quirk->clear_60;
+ break;
+ }
+ }
+}
+
+static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf)
+{
+ int i, res, id = 0, dvi = 0, rgb = 0;
struct ps3av_pkt_av_get_monitor_info monitor_info;
struct ps3av_info_monitor *info;
- /* get vid for hdmi */
- for (i = 0; i < av_hw_conf->num_of_hdmi; i++) {
+ /* get mode id for hdmi */
+ for (i = 0; i < av_hw_conf->num_of_hdmi && !id; i++) {
res = ps3av_cmd_video_get_monitor_info(&monitor_info,
PS3AV_CMD_AVPORT_HDMI_0 +
i);
if (res < 0)
return -1;
- ps3av_cmd_av_monitor_info_dump(&monitor_info);
+ ps3av_monitor_info_dump(&monitor_info);
+
info = &monitor_info.info;
- /* check DVI */
- if (info->monitor_type == PS3AV_MONITOR_TYPE_DVI) {
+ ps3av_fixup_monitor_info(info);
+
+ switch (info->monitor_type) {
+ case PS3AV_MONITOR_TYPE_DVI:
dvi = PS3AV_MODE_DVI;
- break;
- }
- /* check HDMI */
- vid = ps3av_hdmi_get_vid(info);
- if (vid != -1) {
- /* got valid vid */
+ /* fall through */
+ case PS3AV_MONITOR_TYPE_HDMI:
+ id = ps3av_hdmi_get_id(info);
break;
}
}
- if (dvi) {
- /* DVI mode */
- vid = PS3AV_DEFAULT_DVI_VID;
- } else if (vid == -1) {
+ if (!id) {
/* no HDMI interface or HDMI is off */
if (ps3av->region & PS3AV_REGION_60)
- vid = PS3AV_DEFAULT_AVMULTI_VID_REG_60;
+ id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60;
else
- vid = PS3AV_DEFAULT_AVMULTI_VID_REG_50;
+ id = PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50;
if (ps3av->region & PS3AV_REGION_RGB)
rgb = PS3AV_MODE_RGB;
- } else if (boot) {
- /* HDMI: using DEFAULT HDMI_VID while booting up */
- info = &monitor_info.info;
- if (ps3av->region & PS3AV_REGION_60) {
- if (info->res_60.res_bits & PS3AV_RESBIT_720x480P)
- vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
- else if (info->res_50.res_bits & PS3AV_RESBIT_720x576P)
- vid = PS3AV_DEFAULT_HDMI_VID_REG_50;
- else {
- /* default */
- vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
- }
- } else {
- if (info->res_50.res_bits & PS3AV_RESBIT_720x576P)
- vid = PS3AV_DEFAULT_HDMI_VID_REG_50;
- else if (info->res_60.res_bits & PS3AV_RESBIT_720x480P)
- vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
- else {
- /* default */
- vid = PS3AV_DEFAULT_HDMI_VID_REG_50;
- }
- }
+ pr_debug("%s: Using avmulti mode %d\n", __func__, id);
}
- return (ps3av_vid2table_id(vid) | dvi | rgb);
+ return id | dvi | rgb;
}
static int ps3av_get_hw_conf(struct ps3av *ps3av)
{
int i, j, k, res;
+ const struct ps3av_pkt_av_get_hw_conf *hw_conf;
/* get av_hw_conf */
res = ps3av_cmd_av_get_hw_conf(&ps3av->av_hw_conf);
if (res < 0)
return -1;
- ps3av_cmd_av_hw_conf_dump(&ps3av->av_hw_conf);
+ hw_conf = &ps3av->av_hw_conf;
+ pr_debug("av_h_conf: num of hdmi: %u\n", hw_conf->num_of_hdmi);
+ pr_debug("av_h_conf: num of avmulti: %u\n", hw_conf->num_of_avmulti);
+ pr_debug("av_h_conf: num of spdif: %u\n", hw_conf->num_of_spdif);
for (i = 0; i < PS3AV_HEAD_MAX; i++)
ps3av->head[i] = PS3AV_CMD_VIDEO_HEAD_A + i;
for (i = 0; i < PS3AV_OPT_PORT_MAX; i++)
ps3av->opt_port[i] = PS3AV_CMD_AVPORT_SPDIF_0 + i;
- for (i = 0; i < ps3av->av_hw_conf.num_of_hdmi; i++)
+ for (i = 0; i < hw_conf->num_of_hdmi; i++)
ps3av->av_port[i] = PS3AV_CMD_AVPORT_HDMI_0 + i;
- for (j = 0; j < ps3av->av_hw_conf.num_of_avmulti; j++)
+ for (j = 0; j < hw_conf->num_of_avmulti; j++)
ps3av->av_port[i + j] = PS3AV_CMD_AVPORT_AVMULTI_0 + j;
- for (k = 0; k < ps3av->av_hw_conf.num_of_spdif; k++)
+ for (k = 0; k < hw_conf->num_of_spdif; k++)
ps3av->av_port[i + j + k] = PS3AV_CMD_AVPORT_SPDIF_0 + k;
/* set all audio port */
@@ -738,7 +841,7 @@ static int ps3av_get_hw_conf(struct ps3av *ps3av)
}
/* set mode using id */
-int ps3av_set_video_mode(u32 id, int boot)
+int ps3av_set_video_mode(u32 id)
{
int size;
u32 option;
@@ -752,7 +855,7 @@ int ps3av_set_video_mode(u32 id, int boot)
/* auto mode */
option = id & ~PS3AV_MODE_MASK;
if ((id & PS3AV_MODE_MASK) == 0) {
- id = ps3av_auto_videomode(&ps3av->av_hw_conf, boot);
+ id = ps3av_auto_videomode(&ps3av->av_hw_conf);
if (id < 1) {
printk(KERN_ERR "%s: invalid id :%d\n", __func__, id);
return -EINVAL;
@@ -772,34 +875,13 @@ int ps3av_set_video_mode(u32 id, int boot)
EXPORT_SYMBOL_GPL(ps3av_set_video_mode);
-int ps3av_get_auto_mode(int boot)
+int ps3av_get_auto_mode(void)
{
- return ps3av_auto_videomode(&ps3av->av_hw_conf, boot);
+ return ps3av_auto_videomode(&ps3av->av_hw_conf);
}
EXPORT_SYMBOL_GPL(ps3av_get_auto_mode);
-int ps3av_set_mode(u32 id, int boot)
-{
- int res;
-
- res = ps3av_set_video_mode(id, boot);
- if (res)
- return res;
-
- res = ps3av_set_audio_mode(PS3AV_CMD_AUDIO_NUM_OF_CH_2,
- PS3AV_CMD_AUDIO_FS_48K,
- PS3AV_CMD_AUDIO_WORD_BITS_16,
- PS3AV_CMD_AUDIO_FORMAT_PCM,
- PS3AV_CMD_AUDIO_SOURCE_SERIAL);
- if (res)
- return res;
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ps3av_set_mode);
-
int ps3av_get_mode(void)
{
return ps3av ? ps3av->ps3av_mode : 0;
@@ -941,7 +1023,14 @@ static int ps3av_probe(struct ps3_system_bus_device *dev)
res);
ps3av_get_hw_conf(ps3av);
- id = ps3av_auto_videomode(&ps3av->av_hw_conf, 1);
+
+#ifdef CONFIG_FB
+ if (fb_mode_option && !strcmp(fb_mode_option, "safe"))
+ safe_mode = 1;
+#endif /* CONFIG_FB */
+ id = ps3av_auto_videomode(&ps3av->av_hw_conf);
+ safe_mode = 0;
+
mutex_lock(&ps3av->mutex);
ps3av->ps3av_mode = id;
mutex_unlock(&ps3av->mutex);
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c
index f72f5ddf18e..7f880c26122 100644
--- a/drivers/ps3/ps3av_cmd.c
+++ b/drivers/ps3/ps3av_cmd.c
@@ -512,7 +512,6 @@ static const u32 ps3av_ns_table[][5] = {
static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid)
{
u32 av_vid, ns_val;
- u8 *p = ns;
int d;
d = ns_val = 0;
@@ -551,24 +550,22 @@ static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid)
else
ns_val = ps3av_ns_table[PS3AV_CMD_AUDIO_FS_44K-BASE][d];
- *p++ = ns_val & 0x000000FF;
- *p++ = (ns_val & 0x0000FF00) >> 8;
- *p = (ns_val & 0x00FF0000) >> 16;
+ *ns++ = ns_val & 0x000000FF;
+ *ns++ = (ns_val & 0x0000FF00) >> 8;
+ *ns = (ns_val & 0x00FF0000) >> 16;
}
#undef BASE
static u8 ps3av_cnv_enable(u32 source, const u8 *enable)
{
- const u8 *p;
u8 ret = 0;
if (source == PS3AV_CMD_AUDIO_SOURCE_SPDIF) {
ret = 0x03;
} else if (source == PS3AV_CMD_AUDIO_SOURCE_SERIAL) {
- p = enable;
- ret = ((p[0] << 4) + (p[1] << 5) + (p[2] << 6) + (p[3] << 7)) |
- 0x01;
+ ret = ((enable[0] << 4) + (enable[1] << 5) + (enable[2] << 6) +
+ (enable[3] << 7)) | 0x01;
} else
printk(KERN_ERR "%s failed, source:%x\n", __func__, source);
return ret;
@@ -576,11 +573,9 @@ static u8 ps3av_cnv_enable(u32 source, const u8 *enable)
static u8 ps3av_cnv_fifomap(const u8 *map)
{
- const u8 *p;
u8 ret = 0;
- p = map;
- ret = p[0] + (p[1] << 2) + (p[2] << 4) + (p[3] << 6);
+ ret = map[0] + (map[1] << 2) + (map[2] << 4) + (map[3] << 6);
return ret;
}
@@ -927,72 +922,6 @@ int ps3av_cmd_video_get_monitor_info(struct ps3av_pkt_av_get_monitor_info *info,
return res;
}
-#ifdef PS3AV_DEBUG
-void ps3av_cmd_av_hw_conf_dump(const struct ps3av_pkt_av_get_hw_conf *hw_conf)
-{
- printk("av_h_conf:num of hdmi:%d\n", hw_conf->num_of_hdmi);
- printk("av_h_conf:num of avmulti:%d\n", hw_conf->num_of_avmulti);
- printk("av_h_conf:num of spdif:%d\n", hw_conf->num_of_spdif);
-}
-
-void ps3av_cmd_av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info)
-{
- const struct ps3av_info_monitor *info = &monitor_info->info;
- const struct ps3av_info_audio *audio = info->audio;
- int i;
-
- printk("Monitor Info: size%d\n", monitor_info->send_hdr.size);
-
- printk("avport:%02x\n", info->avport);
- printk("monitor_id:");
- for (i = 0; i < 10; i++)
- printk("%02x ", info->monitor_id[i]);
- printk("\nmonitor_type:%02x\n", info->monitor_type);
- printk("monitor_name:");
- for (i = 0; i < 16; i++)
- printk("%c", info->monitor_name[i]);
-
- /* resolution */
- printk("\nresolution_60: bits:%08x native:%08x\n",
- info->res_60.res_bits, info->res_60.native);
- printk("resolution_50: bits:%08x native:%08x\n",
- info->res_50.res_bits, info->res_50.native);
- printk("resolution_other: bits:%08x native:%08x\n",
- info->res_other.res_bits, info->res_other.native);
- printk("resolution_vesa: bits:%08x native:%08x\n",
- info->res_vesa.res_bits, info->res_vesa.native);
-
- /* color space */
- printk("color space rgb:%02x\n", info->cs.rgb);
- printk("color space yuv444:%02x\n", info->cs.yuv444);
- printk("color space yuv422:%02x\n", info->cs.yuv422);
-
- /* color info */
- printk("color info red:X %04x Y %04x\n",
- info->color.red_x, info->color.red_y);
- printk("color info green:X %04x Y %04x\n",
- info->color.green_x, info->color.green_y);
- printk("color info blue:X %04x Y %04x\n",
- info->color.blue_x, info->color.blue_y);
- printk("color info white:X %04x Y %04x\n",
- info->color.white_x, info->color.white_y);
- printk("color info gamma: %08x\n", info->color.gamma);
-
- /* other info */
- printk("supported_AI:%02x\n", info->supported_ai);
- printk("speaker_info:%02x\n", info->speaker_info);
- printk("num of audio:%02x\n", info->num_of_audio_block);
-
- /* audio block */
- for (i = 0; i < info->num_of_audio_block; i++) {
- printk("audio[%d] type:%02x max_ch:%02x fs:%02x sbit:%02x\n",
- i, audio->type, audio->max_num_of_ch, audio->fs,
- audio->sbit);
- audio++;
- }
-}
-#endif /* PS3AV_DEBUG */
-
#define PS3AV_AV_LAYOUT_0 (PS3AV_CMD_AV_LAYOUT_32 \
| PS3AV_CMD_AV_LAYOUT_44 \
| PS3AV_CMD_AV_LAYOUT_48)
diff --git a/drivers/ps3/ps3stor_lib.c b/drivers/ps3/ps3stor_lib.c
index 3a9824e3b25..55955f16ad9 100644
--- a/drivers/ps3/ps3stor_lib.c
+++ b/drivers/ps3/ps3stor_lib.c
@@ -66,7 +66,7 @@ static int ps3stor_probe_access(struct ps3_storage_device *dev)
if (n > 1)
dev_info(&dev->sbd.core,
"%s:%u: %lu accessible regions found. Only the first "
- "one will be used",
+ "one will be used\n",
__func__, __LINE__, n);
dev->region_idx = __ffs(dev->accessible_regions);
dev_info(&dev->sbd.core,
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c
index bea25a1391e..9dea585ef80 100644
--- a/drivers/ps3/vuart.c
+++ b/drivers/ps3/vuart.c
@@ -22,11 +22,11 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
+#include <linux/bitops.h>
#include <asm/ps3.h>
#include <asm/firmware.h>
#include <asm/lv1call.h>
-#include <asm/bitops.h>
#include "vuart.h"
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index ff9e35cb308..e5cdc0294aa 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -36,7 +36,9 @@ config RTC_HCTOSYS_DEVICE
help
The RTC device that will be used to (re)initialize the system
clock, usually rtc0. Initialization is done when the system
- starts up, and when it resumes from a low power state.
+ starts up, and when it resumes from a low power state. This
+ device should record time in UTC, since the kernel won't do
+ timezone correction.
The driver for this RTC device must be loaded before late_initcall
functions run, so it must usually be statically linked.
@@ -133,12 +135,23 @@ config RTC_DRV_DS1307
The first seven registers on these chips hold an RTC, and other
registers may add features such as NVRAM, a trickle charger for
- the RTC/NVRAM backup power, and alarms. This driver may not
- expose all those available chip features.
+ the RTC/NVRAM backup power, and alarms. NVRAM is visible in
+ sysfs, but other chip features may not be available.
This driver can also be built as a module. If so, the module
will be called rtc-ds1307.
+config RTC_DRV_DS1374
+ tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
+ depends on RTC_CLASS && I2C
+ help
+ If you say yes here you get support for Dallas Semiconductor
+ DS1374 real-time clock chips. If an interrupt is associated
+ with the device, the alarm functionality is supported.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1374.
+
config RTC_DRV_DS1672
tristate "Dallas/Maxim DS1672"
help
@@ -229,7 +242,7 @@ config RTC_DRV_TWL92330
depends on MENELAUS
help
If you say yes here you get support for the RTC on the
- TWL92330 "Menelaus" power mangement chip, used with OMAP2
+ TWL92330 "Menelaus" power management chip, used with OMAP2
platforms. The support is integrated with the rest of
the Menelaus driver; it's not separate module.
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index d3a33aa2696..465db4dd50b 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
+obj-$(CONFIG_RTC_DRV_DS1374) += rtc-ds1374.o
obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 10ab3b71ffc..4dfdf019fcc 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -153,6 +153,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
mutex_init(&rtc->ops_lock);
spin_lock_init(&rtc->irq_lock);
spin_lock_init(&rtc->irq_task_lock);
+ init_waitqueue_head(&rtc->irq_queue);
strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id);
diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
index 178527252c6..33c0e98243e 100644
--- a/drivers/rtc/hctosys.c
+++ b/drivers/rtc/hctosys.c
@@ -47,8 +47,8 @@ static int __init rtc_hctosys(void)
do_settimeofday(&tv);
dev_info(rtc->dev.parent,
- "setting the system clock to "
- "%d-%02d-%02d %02d:%02d:%02d (%u)\n",
+ "setting system clock to "
+ "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec,
(unsigned int) tv.tv_sec);
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index ad66c6ecf36..de0da545c7a 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -12,6 +12,7 @@
*/
#include <linux/rtc.h>
+#include <linux/log2.h>
int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
{
@@ -99,7 +100,7 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
}
EXPORT_SYMBOL_GPL(rtc_set_mmss);
-int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
+static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
int err;
@@ -119,6 +120,87 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
mutex_unlock(&rtc->ops_lock);
return err;
}
+
+int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
+{
+ int err;
+ struct rtc_time before, now;
+ int first_time = 1;
+
+ /* The lower level RTC driver may not be capable of filling
+ * in all fields of the rtc_time struct (eg. rtc-cmos),
+ * and so might instead return -1 in some fields.
+ * We deal with that here by grabbing a current RTC timestamp
+ * and using values from that for any missing (-1) values.
+ *
+ * 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)
+ 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;
+
+ /* 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
+ || before.tm_isdst != now.tm_isdst);
+
+ /* Fill in any missing alarm fields using the timestamp */
+ 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;
+ if (alarm->time.tm_mday == -1)
+ alarm->time.tm_mday = now.tm_mday;
+ if (alarm->time.tm_mon == -1)
+ alarm->time.tm_mon = now.tm_mon;
+ if (alarm->time.tm_year == -1)
+ alarm->time.tm_year = now.tm_year;
+ return 0;
+}
EXPORT_SYMBOL_GPL(rtc_read_alarm);
int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
@@ -210,6 +292,10 @@ int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
if (task == NULL || task->func == NULL)
return -EINVAL;
+ /* Cannot register while the char dev is in use */
+ if (!(mutex_trylock(&rtc->char_lock)))
+ return -EBUSY;
+
spin_lock_irq(&rtc->irq_task_lock);
if (rtc->irq_task == NULL) {
rtc->irq_task = task;
@@ -217,13 +303,14 @@ int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
}
spin_unlock_irq(&rtc->irq_task_lock);
+ mutex_unlock(&rtc->char_lock);
+
return retval;
}
EXPORT_SYMBOL_GPL(rtc_irq_register);
void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
{
-
spin_lock_irq(&rtc->irq_task_lock);
if (rtc->irq_task == task)
rtc->irq_task = NULL;
@@ -231,6 +318,16 @@ void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
}
EXPORT_SYMBOL_GPL(rtc_irq_unregister);
+/**
+ * rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs
+ * @rtc: the rtc device
+ * @task: currently registered with rtc_irq_register()
+ * @enabled: true to enable periodic IRQs
+ * Context: any
+ *
+ * Note that rtc_irq_set_freq() should previously have been used to
+ * specify the desired frequency of periodic IRQ task->func() callbacks.
+ */
int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled)
{
int err = 0;
@@ -240,8 +337,10 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled
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 = -ENXIO;
+ err = -EACCES;
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
if (err == 0)
@@ -251,6 +350,16 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled
}
EXPORT_SYMBOL_GPL(rtc_irq_set_state);
+/**
+ * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ
+ * @rtc: the rtc device
+ * @task: currently registered with rtc_irq_register()
+ * @freq: positive frequency with which task->func() will be called
+ * Context: any
+ *
+ * Note that rtc_irq_set_state() is used to enable or disable the
+ * periodic IRQs.
+ */
int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
{
int err = 0;
@@ -259,9 +368,14 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
if (rtc->ops->irq_set_freq == NULL)
return -ENXIO;
+ if (!is_power_of_2(freq))
+ return -EINVAL;
+
spin_lock_irqsave(&rtc->irq_task_lock, flags);
+ if (rtc->irq_task != NULL && task == NULL)
+ err = -EBUSY;
if (rtc->irq_task != task)
- err = -ENXIO;
+ err = -EACCES;
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
if (err == 0) {
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 5d760bb6c2c..29cf1457ca1 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -120,7 +120,8 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
t->time.tm_hour = CMOS_READ(RTC_HOURS_ALARM);
if (cmos->day_alrm) {
- t->time.tm_mday = CMOS_READ(cmos->day_alrm);
+ /* ignore upper bits on readback per ACPI spec */
+ t->time.tm_mday = CMOS_READ(cmos->day_alrm) & 0x3f;
if (!t->time.tm_mday)
t->time.tm_mday = -1;
@@ -246,11 +247,9 @@ static int cmos_irq_set_freq(struct device *dev, int freq)
/* 0 = no irqs; 1 = 2^15 Hz ... 15 = 2^0 Hz */
f = ffs(freq);
- if (f != 0) {
- if (f-- > 16 || freq != (1 << f))
- return -EINVAL;
- f = 16 - f;
- }
+ if (f-- > 16)
+ return -EINVAL;
+ f = 16 - f;
spin_lock_irqsave(&rtc_lock, flags);
CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
@@ -435,6 +434,19 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
if (!ports)
return -ENODEV;
+ /* Claim I/O ports ASAP, minimizing conflict with legacy driver.
+ *
+ * REVISIT non-x86 systems may instead use memory space resources
+ * (needing ioremap etc), not i/o space resources like this ...
+ */
+ ports = request_region(ports->start,
+ ports->end + 1 - ports->start,
+ driver_name);
+ if (!ports) {
+ dev_dbg(dev, "i/o registers already in use\n");
+ return -EBUSY;
+ }
+
cmos_rtc.irq = rtc_irq;
cmos_rtc.iomem = ports;
@@ -456,24 +468,13 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
cmos_rtc.rtc = rtc_device_register(driver_name, dev,
&cmos_rtc_ops, THIS_MODULE);
- if (IS_ERR(cmos_rtc.rtc))
- return PTR_ERR(cmos_rtc.rtc);
+ if (IS_ERR(cmos_rtc.rtc)) {
+ retval = PTR_ERR(cmos_rtc.rtc);
+ goto cleanup0;
+ }
cmos_rtc.dev = dev;
dev_set_drvdata(dev, &cmos_rtc);
-
- /* platform and pnp busses handle resources incompatibly.
- *
- * REVISIT for non-x86 systems we may need to handle io memory
- * resources: ioremap them, and request_mem_region().
- */
- if (is_pnp()) {
- retval = request_resource(&ioport_resource, ports);
- if (retval < 0) {
- dev_dbg(dev, "i/o registers already in use\n");
- goto cleanup0;
- }
- }
rename_region(ports, cmos_rtc.rtc->dev.bus_id);
spin_lock_irq(&rtc_lock);
@@ -536,9 +537,10 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
return 0;
cleanup1:
- rename_region(ports, NULL);
-cleanup0:
+ cmos_rtc.dev = NULL;
rtc_device_unregister(cmos_rtc.rtc);
+cleanup0:
+ release_region(ports->start, ports->end + 1 - ports->start);
return retval;
}
@@ -557,19 +559,21 @@ static void cmos_do_shutdown(void)
static void __exit cmos_do_remove(struct device *dev)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
+ struct resource *ports;
cmos_do_shutdown();
- if (is_pnp())
- release_resource(cmos->iomem);
- rename_region(cmos->iomem, NULL);
-
if (is_valid_irq(cmos->irq))
- free_irq(cmos->irq, cmos_rtc.rtc);
+ free_irq(cmos->irq, cmos->rtc);
- rtc_device_unregister(cmos_rtc.rtc);
+ rtc_device_unregister(cmos->rtc);
+ cmos->rtc = NULL;
- cmos_rtc.dev = NULL;
+ ports = cmos->iomem;
+ release_region(ports->start, ports->end + 1 - ports->start);
+ cmos->iomem = NULL;
+
+ cmos->dev = NULL;
dev_set_drvdata(dev, NULL);
}
@@ -656,7 +660,8 @@ static int cmos_resume(struct device *dev)
/*----------------------------------------------------------------*/
/* The "CMOS" RTC normally lives on the platform_bus. On ACPI systems,
- * the device node will always be created as a PNPACPI device.
+ * the device node will always be created as a PNPACPI device. Plus
+ * pre-ACPI PCs probably list it in the PNPBIOS tables.
*/
#ifdef CONFIG_PNP
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 005fff3a350..814583bd2fe 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -142,7 +142,7 @@ static int set_uie(struct rtc_device *rtc)
static ssize_t
rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- struct rtc_device *rtc = to_rtc_device(file->private_data);
+ struct rtc_device *rtc = file->private_data;
DECLARE_WAITQUEUE(wait, current);
unsigned long data;
@@ -196,7 +196,7 @@ rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
static unsigned int rtc_dev_poll(struct file *file, poll_table *wait)
{
- struct rtc_device *rtc = to_rtc_device(file->private_data);
+ struct rtc_device *rtc = file->private_data;
unsigned long data;
poll_wait(file, &rtc->irq_queue, wait);
@@ -233,22 +233,12 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
break;
case RTC_PIE_ON:
- if (!capable(CAP_SYS_RESOURCE))
+ if (rtc->irq_freq > rtc->max_user_freq &&
+ !capable(CAP_SYS_RESOURCE))
return -EACCES;
break;
}
- /* avoid conflicting IRQ users */
- if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) {
- spin_lock_irq(&rtc->irq_task_lock);
- if (rtc->irq_task)
- err = -EBUSY;
- spin_unlock_irq(&rtc->irq_task_lock);
-
- if (err < 0)
- return err;
- }
-
/* try the driver's ioctl interface */
if (ops->ioctl) {
err = ops->ioctl(rtc->dev.parent, cmd, arg);
@@ -338,18 +328,20 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
err = rtc_set_time(rtc, &tm);
break;
- case RTC_IRQP_READ:
- if (ops->irq_set_freq)
- err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
- else
- err = -ENOTTY;
+ case RTC_PIE_ON:
+ err = rtc_irq_set_state(rtc, NULL, 1);
+ break;
+
+ case RTC_PIE_OFF:
+ err = rtc_irq_set_state(rtc, NULL, 0);
break;
case RTC_IRQP_SET:
- if (ops->irq_set_freq)
- err = rtc_irq_set_freq(rtc, rtc->irq_task, arg);
- else
- err = -ENOTTY;
+ err = rtc_irq_set_freq(rtc, NULL, arg);
+ break;
+
+ case RTC_IRQP_READ:
+ err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
break;
#if 0
@@ -405,7 +397,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
static int rtc_dev_release(struct inode *inode, struct file *file)
{
- struct rtc_device *rtc = to_rtc_device(file->private_data);
+ struct rtc_device *rtc = file->private_data;
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
clear_uie(rtc);
@@ -419,7 +411,7 @@ static int rtc_dev_release(struct inode *inode, struct file *file)
static int rtc_dev_fasync(int fd, struct file *file, int on)
{
- struct rtc_device *rtc = to_rtc_device(file->private_data);
+ struct rtc_device *rtc = file->private_data;
return fasync_helper(fd, file, on, &rtc->async_queue);
}
@@ -449,8 +441,6 @@ void rtc_dev_prepare(struct rtc_device *rtc)
rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
mutex_init(&rtc->char_lock);
- spin_lock_init(&rtc->irq_lock);
- init_waitqueue_head(&rtc->irq_queue);
#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);
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index db6f3f0d898..bc1c7fe94ad 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -89,6 +89,7 @@ enum ds_type {
struct ds1307 {
u8 reg_addr;
+ bool has_nvram;
u8 regs[8];
enum ds_type type;
struct i2c_msg msg[2];
@@ -242,6 +243,87 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
.set_time = ds1307_set_time,
};
+/*----------------------------------------------------------------------*/
+
+#define NVRAM_SIZE 56
+
+static ssize_t
+ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct i2c_client *client;
+ struct ds1307 *ds1307;
+ struct i2c_msg msg[2];
+ int result;
+
+ client = to_i2c_client(container_of(kobj, struct device, kobj));
+ ds1307 = i2c_get_clientdata(client);
+
+ if (unlikely(off >= NVRAM_SIZE))
+ return 0;
+ if ((off + count) > NVRAM_SIZE)
+ count = NVRAM_SIZE - off;
+ if (unlikely(!count))
+ return count;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = buf;
+
+ buf[0] = 8 + off;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = count;
+ msg[1].buf = buf;
+
+ result = i2c_transfer(to_i2c_adapter(client->dev.parent), msg, 2);
+ if (result != 2) {
+ dev_err(&client->dev, "%s error %d\n", "nvram read", result);
+ return -EIO;
+ }
+ return count;
+}
+
+static ssize_t
+ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct i2c_client *client;
+ u8 buffer[NVRAM_SIZE + 1];
+ int ret;
+
+ client = to_i2c_client(container_of(kobj, struct device, kobj));
+
+ if (unlikely(off >= NVRAM_SIZE))
+ return -EFBIG;
+ if ((off + count) > NVRAM_SIZE)
+ count = NVRAM_SIZE - off;
+ if (unlikely(!count))
+ return count;
+
+ buffer[0] = 8 + off;
+ memcpy(buffer + 1, buf, count);
+
+ ret = i2c_master_send(client, buffer, count + 1);
+ return (ret < 0) ? ret : (ret - 1);
+}
+
+static struct bin_attribute nvram = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IRUGO | S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+
+ .read = ds1307_nvram_read,
+ .write = ds1307_nvram_write,
+ .size = NVRAM_SIZE,
+};
+
+/*----------------------------------------------------------------------*/
+
static struct i2c_driver ds1307_driver;
static int __devinit ds1307_probe(struct i2c_client *client)
@@ -413,6 +495,14 @@ read_rtc:
goto exit_free;
}
+ if (chip->nvram56) {
+ err = sysfs_create_bin_file(&client->dev.kobj, &nvram);
+ if (err == 0) {
+ ds1307->has_nvram = true;
+ dev_info(&client->dev, "56 bytes nvram\n");
+ }
+ }
+
return 0;
exit_bad:
@@ -432,6 +522,9 @@ static int __devexit ds1307_remove(struct i2c_client *client)
{
struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ if (ds1307->has_nvram)
+ sysfs_remove_bin_file(&client->dev.kobj, &nvram);
+
rtc_device_unregister(ds1307->rtc);
kfree(ds1307);
return 0;
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
new file mode 100644
index 00000000000..45bda186bef
--- /dev/null
+++ b/drivers/rtc/rtc-ds1374.c
@@ -0,0 +1,449 @@
+/*
+ * RTC client/driver for the Maxim/Dallas DS1374 Real-Time Clock over I2C
+ *
+ * Based on code by Randy Vinson <rvinson@mvista.com>,
+ * which was based on the m41t00.c by Mark Greer <mgreer@mvista.com>.
+ *
+ * Copyright (C) 2006-2007 Freescale Semiconductor
+ *
+ * 2005 (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.
+ */
+/*
+ * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
+ * recommened in .../Documentation/i2c/writing-clients section
+ * "Sending and receiving", using SMBus level communication is preferred.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/workqueue.h>
+
+#define DS1374_REG_TOD0 0x00 /* Time of Day */
+#define DS1374_REG_TOD1 0x01
+#define DS1374_REG_TOD2 0x02
+#define DS1374_REG_TOD3 0x03
+#define DS1374_REG_WDALM0 0x04 /* Watchdog/Alarm */
+#define DS1374_REG_WDALM1 0x05
+#define DS1374_REG_WDALM2 0x06
+#define DS1374_REG_CR 0x07 /* Control */
+#define DS1374_REG_CR_AIE 0x01 /* Alarm Int. Enable */
+#define DS1374_REG_CR_WDALM 0x20 /* 1=Watchdog, 0=Alarm */
+#define DS1374_REG_CR_WACE 0x40 /* WD/Alarm counter enable */
+#define DS1374_REG_SR 0x08 /* Status */
+#define DS1374_REG_SR_OSF 0x80 /* Oscillator Stop Flag */
+#define DS1374_REG_SR_AF 0x01 /* Alarm Flag */
+#define DS1374_REG_TCR 0x09 /* Trickle Charge */
+
+struct ds1374 {
+ struct i2c_client *client;
+ struct rtc_device *rtc;
+ struct work_struct work;
+
+ /* The mutex protects alarm operations, and prevents a race
+ * between the enable_irq() in the workqueue and the free_irq()
+ * in the remove function.
+ */
+ struct mutex mutex;
+ int exiting;
+};
+
+static struct i2c_driver ds1374_driver;
+
+static int ds1374_read_rtc(struct i2c_client *client, u32 *time,
+ int reg, int nbytes)
+{
+ u8 buf[4];
+ int ret;
+ int i;
+
+ if (nbytes > 4) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ ret = i2c_smbus_read_i2c_block_data(client, reg, nbytes, buf);
+
+ if (ret < 0)
+ return ret;
+ if (ret < nbytes)
+ return -EIO;
+
+ for (i = nbytes - 1, *time = 0; i >= 0; i--)
+ *time = (*time << 8) | buf[i];
+
+ return 0;
+}
+
+static int ds1374_write_rtc(struct i2c_client *client, u32 time,
+ int reg, int nbytes)
+{
+ u8 buf[4];
+ int i;
+
+ if (nbytes > 4) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < nbytes; i++) {
+ buf[i] = time & 0xff;
+ time >>= 8;
+ }
+
+ return i2c_smbus_write_i2c_block_data(client, reg, nbytes, buf);
+}
+
+static int ds1374_check_rtc_status(struct i2c_client *client)
+{
+ int ret = 0;
+ int control, stat;
+
+ stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR);
+ if (stat < 0)
+ return stat;
+
+ if (stat & DS1374_REG_SR_OSF)
+ dev_warn(&client->dev,
+ "oscillator discontinuity flagged, "
+ "time unreliable\n");
+
+ stat &= ~(DS1374_REG_SR_OSF | DS1374_REG_SR_AF);
+
+ ret = i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat);
+ if (ret < 0)
+ return ret;
+
+ /* If the alarm is pending, clear it before requesting
+ * the interrupt, so an interrupt event isn't reported
+ * before everything is initialized.
+ */
+
+ control = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
+ if (control < 0)
+ return control;
+
+ control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE);
+ return i2c_smbus_write_byte_data(client, DS1374_REG_CR, control);
+}
+
+static int ds1374_read_time(struct device *dev, struct rtc_time *time)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ u32 itime;
+ int ret;
+
+ ret = ds1374_read_rtc(client, &itime, DS1374_REG_TOD0, 4);
+ if (!ret)
+ rtc_time_to_tm(itime, time);
+
+ return ret;
+}
+
+static int ds1374_set_time(struct device *dev, struct rtc_time *time)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned long itime;
+
+ rtc_tm_to_time(time, &itime);
+ return ds1374_write_rtc(client, itime, DS1374_REG_TOD0, 4);
+}
+
+/* The ds1374 has a decrementer for an alarm, rather than a comparator.
+ * If the time of day is changed, then the alarm will need to be
+ * reset.
+ */
+static int ds1374_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1374 *ds1374 = i2c_get_clientdata(client);
+ u32 now, cur_alarm;
+ int cr, sr;
+ int ret = 0;
+
+ if (client->irq < 0)
+ return -EINVAL;
+
+ mutex_lock(&ds1374->mutex);
+
+ cr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
+ if (ret < 0)
+ goto out;
+
+ sr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_SR);
+ if (ret < 0)
+ goto out;
+
+ ret = ds1374_read_rtc(client, &now, DS1374_REG_TOD0, 4);
+ if (ret)
+ goto out;
+
+ ret = ds1374_read_rtc(client, &cur_alarm, DS1374_REG_WDALM0, 3);
+ if (ret)
+ goto out;
+
+ rtc_time_to_tm(now + cur_alarm, &alarm->time);
+ alarm->enabled = !!(cr & DS1374_REG_CR_WACE);
+ alarm->pending = !!(sr & DS1374_REG_SR_AF);
+
+out:
+ mutex_unlock(&ds1374->mutex);
+ return ret;
+}
+
+static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1374 *ds1374 = i2c_get_clientdata(client);
+ struct rtc_time now;
+ unsigned long new_alarm, itime;
+ int cr;
+ int ret = 0;
+
+ if (client->irq < 0)
+ return -EINVAL;
+
+ ret = ds1374_read_time(dev, &now);
+ if (ret < 0)
+ return ret;
+
+ rtc_tm_to_time(&alarm->time, &new_alarm);
+ rtc_tm_to_time(&now, &itime);
+
+ new_alarm -= itime;
+
+ /* This can happen due to races, in addition to dates that are
+ * truly in the past. To avoid requiring the caller to check for
+ * races, dates in the past are assumed to be in the recent past
+ * (i.e. not something that we'd rather the caller know about via
+ * an error), and the alarm is set to go off as soon as possible.
+ */
+ if (new_alarm <= 0)
+ new_alarm = 1;
+
+ mutex_lock(&ds1374->mutex);
+
+ ret = cr = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
+ if (ret < 0)
+ goto out;
+
+ /* Disable any existing alarm before setting the new one
+ * (or lack thereof). */
+ cr &= ~DS1374_REG_CR_WACE;
+
+ ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr);
+ if (ret < 0)
+ goto out;
+
+ ret = ds1374_write_rtc(client, new_alarm, DS1374_REG_WDALM0, 3);
+ if (ret)
+ goto out;
+
+ if (alarm->enabled) {
+ cr |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE;
+ cr &= ~DS1374_REG_CR_WDALM;
+
+ ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr);
+ }
+
+out:
+ mutex_unlock(&ds1374->mutex);
+ return ret;
+}
+
+static irqreturn_t ds1374_irq(int irq, void *dev_id)
+{
+ struct i2c_client *client = dev_id;
+ struct ds1374 *ds1374 = i2c_get_clientdata(client);
+
+ disable_irq_nosync(irq);
+ schedule_work(&ds1374->work);
+ return IRQ_HANDLED;
+}
+
+static void ds1374_work(struct work_struct *work)
+{
+ struct ds1374 *ds1374 = container_of(work, struct ds1374, work);
+ struct i2c_client *client = ds1374->client;
+ int stat, control;
+
+ mutex_lock(&ds1374->mutex);
+
+ stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR);
+ if (stat < 0)
+ return;
+
+ if (stat & DS1374_REG_SR_AF) {
+ stat &= ~DS1374_REG_SR_AF;
+ i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat);
+
+ control = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
+ if (control < 0)
+ goto out;
+
+ control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE);
+ i2c_smbus_write_byte_data(client, DS1374_REG_CR, control);
+
+ /* rtc_update_irq() assumes that it is called
+ * from IRQ-disabled context.
+ */
+ local_irq_disable();
+ rtc_update_irq(ds1374->rtc, 1, RTC_AF | RTC_IRQF);
+ local_irq_enable();
+ }
+
+out:
+ if (!ds1374->exiting)
+ enable_irq(client->irq);
+
+ mutex_unlock(&ds1374->mutex);
+}
+
+static int ds1374_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1374 *ds1374 = i2c_get_clientdata(client);
+ int ret = -ENOIOCTLCMD;
+
+ mutex_lock(&ds1374->mutex);
+
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
+ if (ret < 0)
+ goto out;
+
+ ret &= ~DS1374_REG_CR_WACE;
+
+ ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret);
+ if (ret < 0)
+ goto out;
+
+ break;
+
+ case RTC_AIE_ON:
+ ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
+ if (ret < 0)
+ goto out;
+
+ ret |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE;
+ ret &= ~DS1374_REG_CR_WDALM;
+
+ ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret);
+ if (ret < 0)
+ goto out;
+
+ break;
+ }
+
+out:
+ mutex_unlock(&ds1374->mutex);
+ return ret;
+}
+
+static const struct rtc_class_ops ds1374_rtc_ops = {
+ .read_time = ds1374_read_time,
+ .set_time = ds1374_set_time,
+ .read_alarm = ds1374_read_alarm,
+ .set_alarm = ds1374_set_alarm,
+ .ioctl = ds1374_ioctl,
+};
+
+static int ds1374_probe(struct i2c_client *client)
+{
+ struct ds1374 *ds1374;
+ int ret;
+
+ ds1374 = kzalloc(sizeof(struct ds1374), GFP_KERNEL);
+ if (!ds1374)
+ return -ENOMEM;
+
+ ds1374->client = client;
+ i2c_set_clientdata(client, ds1374);
+
+ INIT_WORK(&ds1374->work, ds1374_work);
+ mutex_init(&ds1374->mutex);
+
+ ret = ds1374_check_rtc_status(client);
+ if (ret)
+ goto out_free;
+
+ if (client->irq >= 0) {
+ ret = request_irq(client->irq, ds1374_irq, 0,
+ "ds1374", client);
+ if (ret) {
+ dev_err(&client->dev, "unable to request IRQ\n");
+ goto out_free;
+ }
+ }
+
+ ds1374->rtc = rtc_device_register(client->name, &client->dev,
+ &ds1374_rtc_ops, THIS_MODULE);
+ if (IS_ERR(ds1374->rtc)) {
+ ret = PTR_ERR(ds1374->rtc);
+ dev_err(&client->dev, "unable to register the class device\n");
+ goto out_irq;
+ }
+
+ return 0;
+
+out_irq:
+ if (client->irq >= 0)
+ free_irq(client->irq, client);
+
+out_free:
+ i2c_set_clientdata(client, NULL);
+ kfree(ds1374);
+ return ret;
+}
+
+static int __devexit ds1374_remove(struct i2c_client *client)
+{
+ struct ds1374 *ds1374 = i2c_get_clientdata(client);
+
+ if (client->irq >= 0) {
+ mutex_lock(&ds1374->mutex);
+ ds1374->exiting = 1;
+ mutex_unlock(&ds1374->mutex);
+
+ free_irq(client->irq, client);
+ flush_scheduled_work();
+ }
+
+ rtc_device_unregister(ds1374->rtc);
+ i2c_set_clientdata(client, NULL);
+ kfree(ds1374);
+ return 0;
+}
+
+static struct i2c_driver ds1374_driver = {
+ .driver = {
+ .name = "rtc-ds1374",
+ .owner = THIS_MODULE,
+ },
+ .probe = ds1374_probe,
+ .remove = __devexit_p(ds1374_remove),
+};
+
+static int __init ds1374_init(void)
+{
+ return i2c_add_driver(&ds1374_driver);
+}
+
+static void __exit ds1374_exit(void)
+{
+ i2c_del_driver(&ds1374_driver);
+}
+
+module_init(ds1374_init);
+module_exit(ds1374_exit);
+
+MODULE_AUTHOR("Scott Wood <scottwood@freescale.com>");
+MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index 5ab3492817d..d9e848dcd45 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -291,7 +291,7 @@ static ssize_t ds1553_nvram_write(struct kobject *kobj,
static struct bin_attribute ds1553_nvram_attr = {
.attr = {
.name = "nvram",
- .mode = S_IRUGO | S_IWUGO,
+ .mode = S_IRUGO | S_IWUSR,
},
.size = RTC_OFFSET,
.read = ds1553_nvram_read,
@@ -395,7 +395,7 @@ static struct platform_driver ds1553_rtc_driver = {
.probe = ds1553_rtc_probe,
.remove = __devexit_p(ds1553_rtc_remove),
.driver = {
- .name = "ds1553",
+ .name = "rtc-ds1553",
.owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index 67291b0f828..2e73f0b183b 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -160,10 +160,13 @@ static ssize_t ds1742_nvram_write(struct kobject *kobj,
static struct bin_attribute ds1742_nvram_attr = {
.attr = {
.name = "nvram",
- .mode = S_IRUGO | S_IWUGO,
+ .mode = S_IRUGO | S_IWUSR,
},
.read = ds1742_nvram_read,
.write = ds1742_nvram_write,
+ /* REVISIT: size in sysfs won't match actual size... if it's
+ * not a constant, each RTC should have its own attribute.
+ */
};
static int __devinit ds1742_rtc_probe(struct platform_device *pdev)
@@ -251,7 +254,7 @@ static struct platform_driver ds1742_rtc_driver = {
.probe = ds1742_rtc_probe,
.remove = __devexit_p(ds1742_rtc_remove),
.driver = {
- .name = "ds1742",
+ .name = "rtc-ds1742",
.owner = THIS_MODULE,
},
};
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index bf60d35f580..cd0bbc0e803 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -353,11 +353,12 @@ static ssize_t m48t59_nvram_write(struct kobject *kobj,
static struct bin_attribute m48t59_nvram_attr = {
.attr = {
.name = "nvram",
- .mode = S_IRUGO | S_IWUGO,
+ .mode = S_IRUGO | S_IWUSR,
.owner = THIS_MODULE,
},
.read = m48t59_nvram_read,
.write = m48t59_nvram_write,
+ .size = M48T59_NVRAM_SIZE,
};
static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
@@ -464,7 +465,7 @@ static int __devexit m48t59_rtc_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver m48t59_rtc_platdrv = {
+static struct platform_driver m48t59_rtc_driver = {
.driver = {
.name = "rtc-m48t59",
.owner = THIS_MODULE,
@@ -475,12 +476,12 @@ static struct platform_driver m48t59_rtc_platdrv = {
static int __init m48t59_rtc_init(void)
{
- return platform_driver_register(&m48t59_rtc_platdrv);
+ return platform_driver_register(&m48t59_rtc_driver);
}
static void __exit m48t59_rtc_exit(void)
{
- platform_driver_unregister(&m48t59_rtc_platdrv);
+ platform_driver_unregister(&m48t59_rtc_driver);
}
module_init(m48t59_rtc_init);
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index d48b0337458..556d0e7da35 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -332,6 +332,9 @@ static int pcf8583_probe(struct i2c_adapter *adap, int addr, int kind)
}
};
+ if (!i2c_check_functionality(adap, I2C_FUNC_I2C))
+ return 0;
+
pcf = kzalloc(sizeof(*pcf), GFP_KERNEL);
if (!pcf)
return -ENOMEM;
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index e4bf68ca96f..2fd49edcc71 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -21,11 +21,11 @@
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/pm.h>
+#include <linux/bitops.h>
#include <linux/amba/bus.h>
#include <asm/io.h>
-#include <asm/bitops.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/rtc.h>
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 8c1012b432b..e2041b4d0c8 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -542,8 +542,6 @@ static int s3c_rtc_probe(struct platform_device *pdev)
/* RTC Power management control */
-static struct timespec s3c_rtc_delta;
-
static int ticnt_save;
static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 0918b787c4d..6f1e9a9804b 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -29,8 +29,8 @@
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/pm.h>
+#include <linux/bitops.h>
-#include <asm/bitops.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/rtc.h>
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 93ee05eeaeb..8e8c8b8e81e 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -1,7 +1,7 @@
/*
* SuperH On-Chip RTC Support
*
- * Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2006, 2007 Paul Mundt
* Copyright (C) 2006 Jamie Lenehan
*
* Based on the old arch/sh/kernel/cpu/rtc.c by:
@@ -23,16 +23,19 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/io.h>
+#include <asm/rtc.h>
#define DRV_NAME "sh-rtc"
-#define DRV_VERSION "0.1.2"
+#define DRV_VERSION "0.1.3"
#ifdef CONFIG_CPU_SH3
#define rtc_reg_size sizeof(u16)
#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */
+#define RTC_DEF_CAPABILITIES 0UL
#elif defined(CONFIG_CPU_SH4)
#define rtc_reg_size sizeof(u32)
#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */
+#define RTC_DEF_CAPABILITIES RTC_CAP_4_DIGIT_YEAR
#endif
#define RTC_REG(r) ((r) * rtc_reg_size)
@@ -80,6 +83,7 @@ struct sh_rtc {
struct rtc_device *rtc_dev;
spinlock_t lock;
int rearm_aie;
+ unsigned long capabilities; /* See asm-sh/rtc.h for cap bits */
};
static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
@@ -319,14 +323,14 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT));
tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT)) - 1;
-#if defined(CONFIG_CPU_SH4)
- yr = readw(rtc->regbase + RYRCNT);
- yr100 = BCD2BIN(yr >> 8);
- yr &= 0xff;
-#else
- yr = readb(rtc->regbase + RYRCNT);
- yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
-#endif
+ if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {
+ yr = readw(rtc->regbase + RYRCNT);
+ yr100 = BCD2BIN(yr >> 8);
+ yr &= 0xff;
+ } else {
+ yr = readb(rtc->regbase + RYRCNT);
+ yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
+ }
tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900;
@@ -347,8 +351,10 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
- if (rtc_valid_tm(tm) < 0)
+ if (rtc_valid_tm(tm) < 0) {
dev_err(dev, "invalid date\n");
+ rtc_time_to_tm(0, tm);
+ }
return 0;
}
@@ -375,14 +381,14 @@ static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT);
writeb(BIN2BCD(tm->tm_mon + 1), rtc->regbase + RMONCNT);
-#ifdef CONFIG_CPU_SH3
- year = tm->tm_year % 100;
- writeb(BIN2BCD(year), rtc->regbase + RYRCNT);
-#else
- year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
- BIN2BCD(tm->tm_year % 100);
- writew(year, rtc->regbase + RYRCNT);
-#endif
+ if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {
+ year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
+ BIN2BCD(tm->tm_year % 100);
+ writew(year, rtc->regbase + RYRCNT);
+ } else {
+ year = tm->tm_year % 100;
+ writeb(BIN2BCD(year), rtc->regbase + RYRCNT);
+ }
/* Start RTC */
tmp = readb(rtc->regbase + RCR2);
@@ -584,11 +590,22 @@ static int __devinit sh_rtc_probe(struct platform_device *pdev)
rtc->rtc_dev = rtc_device_register("sh", &pdev->dev,
&sh_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
+ if (IS_ERR(rtc->rtc_dev)) {
ret = PTR_ERR(rtc->rtc_dev);
goto err_badmap;
}
+ rtc->capabilities = RTC_DEF_CAPABILITIES;
+ if (pdev->dev.platform_data) {
+ struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data;
+
+ /*
+ * Some CPUs have special capabilities in addition to the
+ * default set. Add those in here.
+ */
+ rtc->capabilities |= pinfo->capabilities;
+ }
+
platform_set_drvdata(pdev, rtc);
return 0;
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index 8288b6b2bf2..a265da7c6ff 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -291,7 +291,7 @@ static ssize_t stk17ta8_nvram_write(struct kobject *kobj,
static struct bin_attribute stk17ta8_nvram_attr = {
.attr = {
.name = "nvram",
- .mode = S_IRUGO | S_IWUGO,
+ .mode = S_IRUGO | S_IWUSR,
.owner = THIS_MODULE,
},
.size = RTC_OFFSET,
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 69df94b4484..2ae0e8304d3 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -73,11 +73,35 @@ rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr,
return retval;
}
+static ssize_t
+rtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq);
+}
+
+static ssize_t
+rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ struct rtc_device *rtc = to_rtc_device(dev);
+ unsigned long val = simple_strtoul(buf, NULL, 0);
+
+ if (val >= 4096 || val == 0)
+ return -EINVAL;
+
+ rtc->max_user_freq = (int)val;
+
+ return n;
+}
+
static struct device_attribute rtc_attrs[] = {
__ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
__ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
__ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
__ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
+ __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,
+ rtc_sysfs_set_max_user_freq),
{ },
};
@@ -176,9 +200,8 @@ void rtc_sysfs_add_device(struct rtc_device *rtc)
err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
if (err)
- dev_err(rtc->dev.parent, "failed to create "
- "alarm attribute, %d",
- err);
+ dev_err(rtc->dev.parent,
+ "failed to create alarm attribute, %d\n", err);
}
void rtc_sysfs_del_device(struct rtc_device *rtc)
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 8b9d68f6e01..5b7385e430e 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -40,7 +40,7 @@ struct DCTL_data {
*
* Each bit configuration leading to an action code 2 (Exit with
* programming error or unusual condition indication)
- * are handled as fatal error´s.
+ * are handled as fatal errors.
*
* All other configurations are handled as recoverable errors.
*
@@ -2001,7 +2001,7 @@ dasd_3990_erp_compound_code(struct dasd_ccw_req * erp, char *sense)
switch (sense[28]) {
case 0x17:
/* issue a Diagnostic Control command with an
- * Inhibit Write subcommand and controler modifier */
+ * Inhibit Write subcommand and controller modifier */
erp = dasd_3990_erp_DCTL(erp, 0x20);
break;
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index d32c60dbdd8..571320ab9e1 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -472,14 +472,13 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
struct dasd_ccw_req *cqr;
struct dasd_diag_req *dreq;
struct dasd_diag_bio *dbio;
- struct bio *bio;
+ struct req_iterator iter;
struct bio_vec *bv;
char *dst;
unsigned int count, datasize;
sector_t recid, first_rec, last_rec;
unsigned int blksize, off;
unsigned char rw_cmd;
- int i;
if (rq_data_dir(req) == READ)
rw_cmd = MDSK_READ_REQ;
@@ -493,13 +492,11 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
/* Check struct bio and count the number of blocks for the request. */
count = 0;
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- if (bv->bv_len & (blksize - 1))
- /* Fba can only do full blocks. */
- return ERR_PTR(-EINVAL);
- count += bv->bv_len >> (device->s2b_shift + 9);
- }
+ rq_for_each_segment(bv, req, iter) {
+ if (bv->bv_len & (blksize - 1))
+ /* Fba can only do full blocks. */
+ return ERR_PTR(-EINVAL);
+ count += bv->bv_len >> (device->s2b_shift + 9);
}
/* Paranoia. */
if (count != last_rec - first_rec + 1)
@@ -516,18 +513,16 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
dreq->block_count = count;
dbio = dreq->bio;
recid = first_rec;
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- dst = page_address(bv->bv_page) + bv->bv_offset;
- for (off = 0; off < bv->bv_len; off += blksize) {
- memset(dbio, 0, sizeof (struct dasd_diag_bio));
- dbio->type = rw_cmd;
- dbio->block_number = recid + 1;
- dbio->buffer = dst;
- dbio++;
- dst += blksize;
- recid++;
- }
+ rq_for_each_segment(bv, req, iter) {
+ dst = page_address(bv->bv_page) + bv->bv_offset;
+ for (off = 0; off < bv->bv_len; off += blksize) {
+ memset(dbio, 0, sizeof (struct dasd_diag_bio));
+ dbio->type = rw_cmd;
+ dbio->block_number = recid + 1;
+ dbio->buffer = dst;
+ dbio++;
+ dst += blksize;
+ recid++;
}
}
cqr->retries = DIAG_MAX_RETRIES;
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index ea63ba7828f..44adf8496bd 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1176,7 +1176,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
struct LO_eckd_data *LO_data;
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
- struct bio *bio;
+ struct req_iterator iter;
struct bio_vec *bv;
char *dst;
unsigned int blksize, blk_per_trk, off;
@@ -1185,7 +1185,6 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
sector_t first_trk, last_trk;
unsigned int first_offs, last_offs;
unsigned char cmd, rcmd;
- int i;
private = (struct dasd_eckd_private *) device->private;
if (rq_data_dir(req) == READ)
@@ -1206,18 +1205,15 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
/* Check struct bio and count the number of blocks for the request. */
count = 0;
cidaw = 0;
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- if (bv->bv_len & (blksize - 1))
- /* Eckd can only do full blocks. */
- return ERR_PTR(-EINVAL);
- count += bv->bv_len >> (device->s2b_shift + 9);
+ rq_for_each_segment(bv, req, iter) {
+ if (bv->bv_len & (blksize - 1))
+ /* Eckd can only do full blocks. */
+ return ERR_PTR(-EINVAL);
+ count += bv->bv_len >> (device->s2b_shift + 9);
#if defined(CONFIG_64BIT)
- if (idal_is_needed (page_address(bv->bv_page),
- bv->bv_len))
- cidaw += bv->bv_len >> (device->s2b_shift + 9);
+ if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
+ cidaw += bv->bv_len >> (device->s2b_shift + 9);
#endif
- }
}
/* Paranoia. */
if (count != last_rec - first_rec + 1)
@@ -1257,7 +1253,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
locate_record(ccw++, LO_data++, first_trk, first_offs + 1,
last_rec - recid + 1, cmd, device, blksize);
}
- rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+ rq_for_each_segment(bv, req, iter) {
dst = page_address(bv->bv_page) + bv->bv_offset;
if (dasd_page_cache) {
char *copy = kmem_cache_alloc(dasd_page_cache,
@@ -1328,12 +1324,12 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
{
struct dasd_eckd_private *private;
struct ccw1 *ccw;
- struct bio *bio;
+ struct req_iterator iter;
struct bio_vec *bv;
char *dst, *cda;
unsigned int blksize, blk_per_trk, off;
sector_t recid;
- int i, status;
+ int status;
if (!dasd_page_cache)
goto out;
@@ -1346,7 +1342,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
ccw++;
if (private->uses_cdl == 0 || recid > 2*blk_per_trk)
ccw++;
- rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+ rq_for_each_segment(bv, req, iter) {
dst = page_address(bv->bv_page) + bv->bv_offset;
for (off = 0; off < bv->bv_len; off += blksize) {
/* Skip locate record. */
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index da16ead8aff..1d95822e0b8 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -234,14 +234,13 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
struct LO_fba_data *LO_data;
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
- struct bio *bio;
+ struct req_iterator iter;
struct bio_vec *bv;
char *dst;
int count, cidaw, cplength, datasize;
sector_t recid, first_rec, last_rec;
unsigned int blksize, off;
unsigned char cmd;
- int i;
private = (struct dasd_fba_private *) device->private;
if (rq_data_dir(req) == READ) {
@@ -257,18 +256,15 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
/* Check struct bio and count the number of blocks for the request. */
count = 0;
cidaw = 0;
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- if (bv->bv_len & (blksize - 1))
- /* Fba can only do full blocks. */
- return ERR_PTR(-EINVAL);
- count += bv->bv_len >> (device->s2b_shift + 9);
+ rq_for_each_segment(bv, req, iter) {
+ if (bv->bv_len & (blksize - 1))
+ /* Fba can only do full blocks. */
+ return ERR_PTR(-EINVAL);
+ count += bv->bv_len >> (device->s2b_shift + 9);
#if defined(CONFIG_64BIT)
- if (idal_is_needed (page_address(bv->bv_page),
- bv->bv_len))
- cidaw += bv->bv_len / blksize;
+ if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
+ cidaw += bv->bv_len / blksize;
#endif
- }
}
/* Paranoia. */
if (count != last_rec - first_rec + 1)
@@ -304,7 +300,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
locate_record(ccw++, LO_data++, rq_data_dir(req), 0, count);
}
recid = first_rec;
- rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+ rq_for_each_segment(bv, req, iter) {
dst = page_address(bv->bv_page) + bv->bv_offset;
if (dasd_page_cache) {
char *copy = kmem_cache_alloc(dasd_page_cache,
@@ -359,11 +355,11 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
{
struct dasd_fba_private *private;
struct ccw1 *ccw;
- struct bio *bio;
+ struct req_iterator iter;
struct bio_vec *bv;
char *dst, *cda;
unsigned int blksize, off;
- int i, status;
+ int status;
if (!dasd_page_cache)
goto out;
@@ -374,7 +370,7 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
ccw++;
if (private->rdc_data.mode.bits.data_chain != 0)
ccw++;
- rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+ rq_for_each_segment(bv, req, iter) {
dst = page_address(bv->bv_page) + bv->bv_offset;
for (off = 0; off < bv->bv_len; off += blksize) {
/* Skip locate record. */
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index aeda5268244..d427daeef51 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -53,6 +53,7 @@
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/interrupt.h>
+#include <linux/log2.h>
#include <asm/ccwdev.h>
#include <linux/workqueue.h>
#include <asm/debug.h>
@@ -456,7 +457,7 @@ dasd_free_chunk(struct list_head *chunk_list, void *mem)
static inline int
dasd_check_blocksize(int bsize)
{
- if (bsize < 512 || bsize > 4096 || (bsize & (bsize - 1)) != 0)
+ if (bsize < 512 || bsize > 4096 || !is_power_of_2(bsize))
return -EMEDIUMTYPE;
return 0;
}
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 4d8798bacf9..5e083d1f57e 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -193,6 +193,12 @@ dcssblk_segment_warn(int rc, char* seg_name)
}
}
+static void dcssblk_unregister_callback(struct device *dev)
+{
+ device_unregister(dev);
+ put_device(dev);
+}
+
/*
* device attribute for switching shared/nonshared (exclusive)
* operation (show + store)
@@ -276,8 +282,7 @@ removeseg:
blk_cleanup_queue(dev_info->dcssblk_queue);
dev_info->gd->queue = NULL;
put_disk(dev_info->gd);
- device_unregister(dev);
- put_device(dev);
+ rc = device_schedule_callback(dev, dcssblk_unregister_callback);
out:
up_write(&dcssblk_devices_sem);
return rc;
@@ -674,10 +679,10 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio)
}
bytes_done += bvec->bv_len;
}
- bio_endio(bio, bytes_done, 0);
+ bio_endio(bio, 0);
return 0;
fail:
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index 354a060e5be..f231bc21b1c 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -230,12 +230,10 @@ static int xpram_make_request(struct request_queue *q, struct bio *bio)
}
}
set_bit(BIO_UPTODATE, &bio->bi_flags);
- bytes = bio->bi_size;
- bio->bi_size = 0;
- bio->bi_end_io(bio, bytes, 0);
+ bio_endio(bio, 0);
return 0;
fail:
- bio_io_error(bio, bio->bi_size);
+ bio_io_error(bio);
return 0;
}
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 6000bdee408..0e1f35c9ed9 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -667,6 +667,9 @@ raw3215_probe (struct ccw_device *cdev)
struct raw3215_info *raw;
int line;
+ /* Console is special. */
+ if (raw3215[0] && (cdev->dev.driver_data == raw3215[0]))
+ return 0;
raw = kmalloc(sizeof(struct raw3215_info) +
RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
if (raw == NULL)
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index fd3479119eb..0b040557db0 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -22,6 +22,7 @@
#include <asm/ebcdic.h>
#include "raw3270.h"
+#include "tty3270.h"
#include "ctrlchar.h"
#define CON3270_OUTPUT_BUFFER_SIZE 1024
@@ -507,8 +508,6 @@ con3270_write(struct console *co, const char *str, unsigned int count)
spin_unlock_irqrestore(&cp->view.lock,flags);
}
-extern struct tty_driver *tty3270_driver;
-
static struct tty_driver *
con3270_device(struct console *c, int *index)
{
diff --git a/drivers/s390/char/defkeymap.c b/drivers/s390/char/defkeymap.c
index 564baca01b7..389346cda6c 100644
--- a/drivers/s390/char/defkeymap.c
+++ b/drivers/s390/char/defkeymap.c
@@ -150,7 +150,7 @@ char *func_table[MAX_NR_FUNC] = {
NULL,
};
-struct kbdiacr accent_table[MAX_DIACR] = {
+struct kbdiacruc accent_table[MAX_DIACR] = {
{'^', 'c', '\003'}, {'^', 'd', '\004'},
{'^', 'z', '\032'}, {'^', '\012', '\000'},
};
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index f62f9a4e895..cee4d4e4242 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -11,6 +11,7 @@
#include <linux/sched.h>
#include <linux/sysrq.h>
+#include <linux/consolemap.h>
#include <linux/kbd_kern.h>
#include <linux/kbd_diacr.h>
#include <asm/uaccess.h>
@@ -82,11 +83,11 @@ kbd_alloc(void) {
if (!kbd->fn_handler)
goto out_func;
kbd->accent_table =
- kmalloc(sizeof(struct kbdiacr)*MAX_DIACR, GFP_KERNEL);
+ kmalloc(sizeof(struct kbdiacruc)*MAX_DIACR, GFP_KERNEL);
if (!kbd->accent_table)
goto out_fn_handler;
memcpy(kbd->accent_table, accent_table,
- sizeof(struct kbdiacr)*MAX_DIACR);
+ sizeof(struct kbdiacruc)*MAX_DIACR);
kbd->accent_table_size = accent_table_size;
return kbd;
@@ -183,8 +184,8 @@ kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc)
* Otherwise, conclude that DIACR was not combining after all,
* queue it and return CH.
*/
-static unsigned char
-handle_diacr(struct kbd_data *kbd, unsigned char ch)
+static unsigned int
+handle_diacr(struct kbd_data *kbd, unsigned int ch)
{
int i, d;
@@ -460,7 +461,6 @@ int
kbd_ioctl(struct kbd_data *kbd, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct kbdiacrs __user *a;
void __user *argp;
int ct, perm;
@@ -481,17 +481,40 @@ kbd_ioctl(struct kbd_data *kbd, struct file *file,
case KDSKBSENT:
return do_kdgkb_ioctl(kbd, argp, cmd, perm);
case KDGKBDIACR:
- a = argp;
+ {
+ struct kbdiacrs __user *a = argp;
+ struct kbdiacr diacr;
+ int i;
if (put_user(kbd->accent_table_size, &a->kb_cnt))
return -EFAULT;
+ for (i = 0; i < kbd->accent_table_size; i++) {
+ diacr.diacr = kbd->accent_table[i].diacr;
+ diacr.base = kbd->accent_table[i].base;
+ diacr.result = kbd->accent_table[i].result;
+ if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr)))
+ return -EFAULT;
+ }
+ return 0;
+ }
+ case KDGKBDIACRUC:
+ {
+ struct kbdiacrsuc __user *a = argp;
+
ct = kbd->accent_table_size;
- if (copy_to_user(a->kbdiacr, kbd->accent_table,
- ct * sizeof(struct kbdiacr)))
+ if (put_user(ct, &a->kb_cnt))
+ return -EFAULT;
+ if (copy_to_user(a->kbdiacruc, kbd->accent_table,
+ ct * sizeof(struct kbdiacruc)))
return -EFAULT;
return 0;
+ }
case KDSKBDIACR:
- a = argp;
+ {
+ struct kbdiacrs __user *a = argp;
+ struct kbdiacr diacr;
+ int i;
+
if (!perm)
return -EPERM;
if (get_user(ct, &a->kb_cnt))
@@ -499,10 +522,31 @@ kbd_ioctl(struct kbd_data *kbd, struct file *file,
if (ct >= MAX_DIACR)
return -EINVAL;
kbd->accent_table_size = ct;
- if (copy_from_user(kbd->accent_table, a->kbdiacr,
- ct * sizeof(struct kbdiacr)))
+ for (i = 0; i < ct; i++) {
+ if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr)))
+ return -EFAULT;
+ kbd->accent_table[i].diacr = diacr.diacr;
+ kbd->accent_table[i].base = diacr.base;
+ kbd->accent_table[i].result = diacr.result;
+ }
+ return 0;
+ }
+ case KDSKBDIACRUC:
+ {
+ struct kbdiacrsuc __user *a = argp;
+
+ if (!perm)
+ return -EPERM;
+ if (get_user(ct, &a->kb_cnt))
+ return -EFAULT;
+ if (ct >= MAX_DIACR)
+ return -EINVAL;
+ kbd->accent_table_size = ct;
+ if (copy_from_user(kbd->accent_table, a->kbdiacruc,
+ ct * sizeof(struct kbdiacruc)))
return -EFAULT;
return 0;
+ }
default:
return -ENOIOCTLCMD;
}
diff --git a/drivers/s390/char/keyboard.h b/drivers/s390/char/keyboard.h
index f7bf45c6bf0..5ccfe9cf126 100644
--- a/drivers/s390/char/keyboard.h
+++ b/drivers/s390/char/keyboard.h
@@ -25,9 +25,9 @@ struct kbd_data {
unsigned short **key_maps;
char **func_table;
fn_handler_fn **fn_handler;
- struct kbdiacr *accent_table;
+ struct kbdiacruc *accent_table;
unsigned int accent_table_size;
- unsigned char diacr;
+ unsigned int diacr;
unsigned short sysrq;
};
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 2edd5fb6d3d..8d1c64a24de 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -48,8 +48,8 @@ struct raw3270 {
struct timer_list timer; /* Device timer. */
unsigned char *ascebc; /* ascii -> ebcdic table */
- struct class_device *clttydev; /* 3270-class tty device ptr */
- struct class_device *cltubdev; /* 3270-class tub device ptr */
+ struct device *clttydev; /* 3270-class tty device ptr */
+ struct device *cltubdev; /* 3270-class tub device ptr */
struct raw3270_request init_request;
unsigned char init_data[256];
@@ -1107,11 +1107,9 @@ raw3270_delete_device(struct raw3270 *rp)
/* Remove from device chain. */
mutex_lock(&raw3270_mutex);
if (rp->clttydev && !IS_ERR(rp->clttydev))
- class_device_destroy(class3270,
- MKDEV(IBM_TTY3270_MAJOR, rp->minor));
+ device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
if (rp->cltubdev && !IS_ERR(rp->cltubdev))
- class_device_destroy(class3270,
- MKDEV(IBM_FS3270_MAJOR, rp->minor));
+ device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, rp->minor));
list_del_init(&rp->list);
mutex_unlock(&raw3270_mutex);
@@ -1181,24 +1179,22 @@ static int raw3270_create_attributes(struct raw3270 *rp)
if (rc)
goto out;
- rp->clttydev = class_device_create(class3270, NULL,
- MKDEV(IBM_TTY3270_MAJOR, rp->minor),
- &rp->cdev->dev, "tty%s",
- rp->cdev->dev.bus_id);
+ rp->clttydev = device_create(class3270, &rp->cdev->dev,
+ MKDEV(IBM_TTY3270_MAJOR, rp->minor),
+ "tty%s", rp->cdev->dev.bus_id);
if (IS_ERR(rp->clttydev)) {
rc = PTR_ERR(rp->clttydev);
goto out_ttydev;
}
- rp->cltubdev = class_device_create(class3270, NULL,
- MKDEV(IBM_FS3270_MAJOR, rp->minor),
- &rp->cdev->dev, "tub%s",
- rp->cdev->dev.bus_id);
+ rp->cltubdev = device_create(class3270, &rp->cdev->dev,
+ MKDEV(IBM_FS3270_MAJOR, rp->minor),
+ "tub%s", rp->cdev->dev.bus_id);
if (!IS_ERR(rp->cltubdev))
goto out;
rc = PTR_ERR(rp->cltubdev);
- class_device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
+ device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
out_ttydev:
sysfs_remove_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index fa62e694405..25629b92dec 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -93,6 +93,7 @@ static volatile enum sclp_mask_state_t {
#define SCLP_RETRY_INTERVAL 30
static void sclp_process_queue(void);
+static void __sclp_make_read_req(void);
static int sclp_init_mask(int calculate);
static int sclp_init(void);
@@ -115,7 +116,6 @@ sclp_service_call(sclp_cmdw_t command, void *sccb)
return 0;
}
-static inline void __sclp_make_read_req(void);
static void
__sclp_queue_read_req(void)
@@ -318,8 +318,7 @@ sclp_read_cb(struct sclp_req *req, void *data)
}
/* Prepare read event data request. Called while sclp_lock is locked. */
-static inline void
-__sclp_make_read_req(void)
+static void __sclp_make_read_req(void)
{
struct sccb_header *sccb;
diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
index 29fe2a5ec2f..82a13d9fdfe 100644
--- a/drivers/s390/char/sclp_cpi.c
+++ b/drivers/s390/char/sclp_cpi.c
@@ -157,7 +157,7 @@ cpi_prepare_req(void)
sclp_ascebc_str(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
EBC_TOUPPER(evb->system_name, CPI_LENGTH_SYSTEM_NAME);
- /* set sytem level */
+ /* set system level */
evb->system_level = LINUX_VERSION_CODE;
/* set sysplex name */
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index 80e7a537e7d..5b47e9cce75 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -1134,21 +1134,18 @@ tape_34xx_bread(struct tape_device *device, struct request *req)
{
struct tape_request *request;
struct ccw1 *ccw;
- int count = 0, i;
+ int count = 0;
unsigned off;
char *dst;
struct bio_vec *bv;
- struct bio *bio;
+ struct req_iterator iter;
struct tape_34xx_block_id * start_block;
DBF_EVENT(6, "xBREDid:");
/* Count the number of blocks for the request. */
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
- }
- }
+ rq_for_each_segment(bv, req, iter)
+ count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
/* Allocate the ccw request. */
request = tape_alloc_request(3+count+1, 8);
@@ -1175,18 +1172,15 @@ tape_34xx_bread(struct tape_device *device, struct request *req)
ccw = tape_ccw_cc(ccw, NOP, 0, NULL);
ccw = tape_ccw_cc(ccw, NOP, 0, NULL);
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- dst = kmap(bv->bv_page) + bv->bv_offset;
- for (off = 0; off < bv->bv_len;
- off += TAPEBLOCK_HSEC_SIZE) {
- ccw->flags = CCW_FLAG_CC;
- ccw->cmd_code = READ_FORWARD;
- ccw->count = TAPEBLOCK_HSEC_SIZE;
- set_normalized_cda(ccw, (void*) __pa(dst));
- ccw++;
- dst += TAPEBLOCK_HSEC_SIZE;
- }
+ rq_for_each_segment(bv, req, iter) {
+ dst = kmap(bv->bv_page) + bv->bv_offset;
+ for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) {
+ ccw->flags = CCW_FLAG_CC;
+ ccw->cmd_code = READ_FORWARD;
+ ccw->count = TAPEBLOCK_HSEC_SIZE;
+ set_normalized_cda(ccw, (void*) __pa(dst));
+ ccw++;
+ dst += TAPEBLOCK_HSEC_SIZE;
}
}
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 7e2b2ab4926..da25f8e2415 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -623,21 +623,19 @@ tape_3590_bread(struct tape_device *device, struct request *req)
{
struct tape_request *request;
struct ccw1 *ccw;
- int count = 0, start_block, i;
+ int count = 0, start_block;
unsigned off;
char *dst;
struct bio_vec *bv;
- struct bio *bio;
+ struct req_iterator iter;
DBF_EVENT(6, "xBREDid:");
start_block = req->sector >> TAPEBLOCK_HSEC_S2B;
DBF_EVENT(6, "start_block = %i\n", start_block);
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
- }
- }
+ rq_for_each_segment(bv, req, iter)
+ count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
+
request = tape_alloc_request(2 + count + 1, 4);
if (IS_ERR(request))
return request;
@@ -653,21 +651,18 @@ tape_3590_bread(struct tape_device *device, struct request *req)
*/
ccw = tape_ccw_cc(ccw, NOP, 0, NULL);
- rq_for_each_bio(bio, req) {
- bio_for_each_segment(bv, bio, i) {
- dst = page_address(bv->bv_page) + bv->bv_offset;
- for (off = 0; off < bv->bv_len;
- off += TAPEBLOCK_HSEC_SIZE) {
- ccw->flags = CCW_FLAG_CC;
- ccw->cmd_code = READ_FORWARD;
- ccw->count = TAPEBLOCK_HSEC_SIZE;
- set_normalized_cda(ccw, (void *) __pa(dst));
- ccw++;
- dst += TAPEBLOCK_HSEC_SIZE;
- }
- if (off > bv->bv_len)
- BUG();
+ rq_for_each_segment(bv, req, iter) {
+ dst = page_address(bv->bv_page) + bv->bv_offset;
+ for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) {
+ ccw->flags = CCW_FLAG_CC;
+ ccw->cmd_code = READ_FORWARD;
+ ccw->count = TAPEBLOCK_HSEC_SIZE;
+ set_normalized_cda(ccw, (void *) __pa(dst));
+ ccw++;
+ dst += TAPEBLOCK_HSEC_SIZE;
}
+ if (off > bv->bv_len)
+ BUG();
}
ccw = tape_ccw_end(ccw, NOP, 0, NULL);
DBF_EVENT(6, "xBREDccwg\n");
@@ -713,16 +708,22 @@ static void tape_3590_med_state_set(struct tape_device *device,
c_info = &TAPE_3590_CRYPT_INFO(device);
- if (sense->masst == MSENSE_UNASSOCIATED) {
+ DBF_EVENT(6, "medium state: %x:%x\n", sense->macst, sense->masst);
+ switch (sense->macst) {
+ case 0x04:
+ case 0x05:
+ case 0x06:
tape_med_state_set(device, MS_UNLOADED);
TAPE_3590_CRYPT_INFO(device).medium_status = 0;
return;
- }
- if (sense->masst != MSENSE_ASSOCIATED_MOUNT) {
- PRINT_ERR("Unknown medium state: %x\n", sense->masst);
+ case 0x08:
+ case 0x09:
+ tape_med_state_set(device, MS_LOADED);
+ break;
+ default:
+ tape_med_state_set(device, MS_UNKNOWN);
return;
}
- tape_med_state_set(device, MS_LOADED);
c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
if (sense->flags & MSENSE_CRYPT_MASK) {
PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags);
@@ -840,15 +841,17 @@ tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb)
/* Probably result of halt ssch */
return TAPE_IO_PENDING;
else if (irb->scsw.dstat == 0x85)
- /* Device Ready -> check medium state */
- tape_3590_schedule_work(device, TO_MSEN);
- else if (irb->scsw.dstat & DEV_STAT_ATTENTION)
+ /* Device Ready */
+ DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id);
+ else if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
tape_3590_schedule_work(device, TO_READ_ATTMSG);
- else {
+ } else {
DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
PRINT_WARN("Unsolicited IRQ (Device End) caught.\n");
tape_dump_sense(device, NULL, irb);
}
+ /* check medium state */
+ tape_3590_schedule_work(device, TO_MSEN);
return TAPE_IO_SUCCESS;
}
diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c
index 2e0d29730b6..aa7f166f403 100644
--- a/drivers/s390/char/tape_class.c
+++ b/drivers/s390/char/tape_class.c
@@ -69,12 +69,9 @@ struct tape_class_device *register_tape_dev(
if (rc)
goto fail_with_cdev;
- tcd->class_device = class_device_create(
- tape_class,
- NULL,
- tcd->char_device->dev,
- device,
- "%s", tcd->device_name
+ tcd->class_device = device_create(tape_class, device,
+ tcd->char_device->dev,
+ "%s", tcd->device_name
);
rc = IS_ERR(tcd->class_device) ? PTR_ERR(tcd->class_device) : 0;
if (rc)
@@ -90,7 +87,7 @@ struct tape_class_device *register_tape_dev(
return tcd;
fail_with_class_device:
- class_device_destroy(tape_class, tcd->char_device->dev);
+ device_destroy(tape_class, tcd->char_device->dev);
fail_with_cdev:
cdev_del(tcd->char_device);
@@ -105,11 +102,9 @@ EXPORT_SYMBOL(register_tape_dev);
void unregister_tape_dev(struct tape_class_device *tcd)
{
if (tcd != NULL && !IS_ERR(tcd)) {
- sysfs_remove_link(
- &tcd->class_device->dev->kobj,
- tcd->mode_name
- );
- class_device_destroy(tape_class, tcd->char_device->dev);
+ sysfs_remove_link(&tcd->class_device->kobj,
+ tcd->mode_name);
+ device_destroy(tape_class, tcd->char_device->dev);
cdev_del(tcd->char_device);
kfree(tcd);
}
diff --git a/drivers/s390/char/tape_class.h b/drivers/s390/char/tape_class.h
index a8bd9b47fad..e2b5ac918ac 100644
--- a/drivers/s390/char/tape_class.h
+++ b/drivers/s390/char/tape_class.h
@@ -24,8 +24,8 @@
#define TAPECLASS_NAME_LEN 32
struct tape_class_device {
- struct cdev * char_device;
- struct class_device * class_device;
+ struct cdev *char_device;
+ struct device *class_device;
char device_name[TAPECLASS_NAME_LEN];
char mode_name[TAPECLASS_NAME_LEN];
};
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index bc33068b9ce..70b1980a08b 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -25,8 +25,8 @@
#include <asm/ebcdic.h>
#include <asm/uaccess.h>
-
#include "raw3270.h"
+#include "tty3270.h"
#include "keyboard.h"
#define TTY3270_CHAR_BUF_SIZE 256
@@ -1338,8 +1338,11 @@ tty3270_getpar(struct tty3270 *tp, int ix)
static void
tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
{
- tp->cx = min_t(int, tp->view.cols - 1, max_t(int, 0, cx));
- cy = min_t(int, tp->view.rows - 3, max_t(int, 0, cy));
+ int max_cx = max(0, cx);
+ int max_cy = max(0, cy);
+
+ tp->cx = min_t(int, tp->view.cols - 1, max_cx);
+ cy = min_t(int, tp->view.rows - 3, max_cy);
if (cy != tp->cy) {
tty3270_convert_line(tp, tp->cy);
tp->cy = cy;
diff --git a/drivers/s390/char/tty3270.h b/drivers/s390/char/tty3270.h
new file mode 100644
index 00000000000..799da57f039
--- /dev/null
+++ b/drivers/s390/char/tty3270.h
@@ -0,0 +1,16 @@
+/*
+ * drivers/s390/char/tty3270.h
+ *
+ * Copyright IBM Corp. 2007
+ *
+ */
+
+#ifndef __DRIVERS_S390_CHAR_TTY3270_H
+#define __DRIVERS_S390_CHAR_TTY3270_H
+
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+
+extern struct tty_driver *tty3270_driver;
+
+#endif /* __DRIVERS_S390_CHAR_TTY3270_H */
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index 12f7a4ce82c..e0c4c508e12 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -74,7 +74,7 @@ struct vmlogrdr_priv_t {
int dev_in_use; /* 1: already opened, 0: not opened*/
spinlock_t priv_lock;
struct device *device;
- struct class_device *class_device;
+ struct device *class_device;
int autorecording;
int autopurge;
};
@@ -762,12 +762,10 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
device_unregister(dev);
return ret;
}
- priv->class_device = class_device_create(
- vmlogrdr_class,
- NULL,
- MKDEV(vmlogrdr_major, priv->minor_num),
- dev,
- "%s", dev->bus_id );
+ priv->class_device = device_create(vmlogrdr_class, dev,
+ MKDEV(vmlogrdr_major,
+ priv->minor_num),
+ "%s", dev->bus_id);
if (IS_ERR(priv->class_device)) {
ret = PTR_ERR(priv->class_device);
priv->class_device=NULL;
@@ -783,8 +781,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv)
{
- class_device_destroy(vmlogrdr_class,
- MKDEV(vmlogrdr_major, priv->minor_num));
+ device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num));
if (priv->device != NULL) {
sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group);
device_unregister(priv->device);
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
index 680b9b58b80..6f40facb1c4 100644
--- a/drivers/s390/char/vmwatchdog.c
+++ b/drivers/s390/char/vmwatchdog.c
@@ -66,8 +66,8 @@ static int __diag288(enum vmwdt_func func, unsigned int timeout,
"0: la %0,0\n"
"1:\n"
EX_TABLE(0b,1b)
- : "=d" (err) : "d"(__func), "d"(__timeout),
- "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc");
+ : "+d" (err) : "d"(__func), "d"(__timeout),
+ "d"(__cmdp), "d"(__cmdl) : "1", "cc");
return err;
}
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 3712ede1672..7073daf7798 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -141,15 +141,16 @@ static int memcpy_real(void *dest, unsigned long src, size_t count)
if (count == 0)
return 0;
- flags = __raw_local_irq_stnsm(0xf8); /* switch to real mode */
+ flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */
asm volatile (
"0: mvcle %1,%2,0x0\n"
"1: jo 0b\n"
" lhi %0,0x0\n"
"2:\n"
EX_TABLE(1b,2b)
- : "+d" (rc)
- : "d" (_dest), "d" (_src), "d" (_len1), "d" (_len2)
+ : "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1),
+ "+d" (_len2), "=m" (*((long*)dest))
+ : "m" (*((long*)src))
: "cc", "memory");
__raw_local_irq_ssm(flags);
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index b0a18f5176a..5baa517c3b6 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -44,8 +44,7 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv)
return 0;
}
static int
-ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer,
- int buffer_size)
+ccwgroup_uevent (struct device *dev, struct kobj_uevent_env *env)
{
/* TODO */
return 0;
@@ -152,16 +151,24 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
return 0;
}
-/*
- * try to add a new ccwgroup device for one driver
- * argc and argv[] are a list of bus_id's of devices
- * belonging to the driver.
+/**
+ * ccwgroup_create() - create and register a ccw group device
+ * @root: parent device for the new device
+ * @creator_id: identifier of creating driver
+ * @cdrv: ccw driver of slave devices
+ * @argc: number of slave devices
+ * @argv: bus ids of slave devices
+ *
+ * Create and register a new ccw group device as a child of @root. Slave
+ * devices are obtained from the list of bus ids given in @argv[] and must all
+ * belong to @cdrv.
+ * Returns:
+ * %0 on success and an error code on failure.
+ * Context:
+ * non-atomic
*/
-int
-ccwgroup_create(struct device *root,
- unsigned int creator_id,
- struct ccw_driver *cdrv,
- int argc, char *argv[])
+int ccwgroup_create(struct device *root, unsigned int creator_id,
+ struct ccw_driver *cdrv, int argc, char *argv[])
{
struct ccwgroup_device *gdev;
int i;
@@ -390,8 +397,13 @@ static struct bus_type ccwgroup_bus_type = {
.remove = ccwgroup_remove,
};
-int
-ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
+/**
+ * ccwgroup_driver_register() - register a ccw group driver
+ * @cdriver: driver to be registered
+ *
+ * This function is mainly a wrapper around driver_register().
+ */
+int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
{
/* register our new driver with the core */
cdriver->driver.bus = &ccwgroup_bus_type;
@@ -406,8 +418,13 @@ __ccwgroup_match_all(struct device *dev, void *data)
return 1;
}
-void
-ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
+/**
+ * ccwgroup_driver_unregister() - deregister a ccw group driver
+ * @cdriver: driver to be deregistered
+ *
+ * This function is mainly a wrapper around driver_unregister().
+ */
+void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
{
struct device *dev;
@@ -427,8 +444,16 @@ ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
driver_unregister(&cdriver->driver);
}
-int
-ccwgroup_probe_ccwdev(struct ccw_device *cdev)
+/**
+ * ccwgroup_probe_ccwdev() - probe function for slave devices
+ * @cdev: ccw device to be probed
+ *
+ * This is a dummy probe function for ccw devices that are slave devices in
+ * a ccw group device.
+ * Returns:
+ * always %0
+ */
+int ccwgroup_probe_ccwdev(struct ccw_device *cdev)
{
return 0;
}
@@ -452,8 +477,15 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
return NULL;
}
-void
-ccwgroup_remove_ccwdev(struct ccw_device *cdev)
+/**
+ * ccwgroup_remove_ccwdev() - remove function for slave devices
+ * @cdev: ccw device to be removed
+ *
+ * This is a remove function for ccw devices that are slave devices in a ccw
+ * group device. It sets the ccw device offline and also deregisters the
+ * embedding ccw group device.
+ */
+void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
{
struct ccwgroup_device *gdev;
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index 920dd71e643..297cdceb0ca 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -14,7 +14,7 @@
#include <linux/jiffies.h>
#include <linux/wait.h>
#include <linux/mutex.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
#include <asm/chpid.h>
#include <asm/sclp.h>
@@ -55,7 +55,7 @@ static wait_queue_head_t cfg_wait_queue;
/* Return channel_path struct for given chpid. */
static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
{
- return css[chpid.cssid]->chps[chpid.id];
+ return channel_subsystems[chpid.cssid]->chps[chpid.id];
}
/* Set vary state for given chpid. */
@@ -86,7 +86,7 @@ u8 chp_get_sch_opm(struct subchannel *sch)
opm = 0;
chp_id_init(&chpid);
- for (i=0; i < 8; i++) {
+ for (i = 0; i < 8; i++) {
opm <<= 1;
chpid.id = sch->schib.pmcw.chpid[i];
if (chp_get_status(chpid) != 0)
@@ -118,7 +118,7 @@ static int s390_vary_chpid(struct chp_id chpid, int on)
sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid,
chpid.id);
- CIO_TRACE_EVENT( 2, dbf_text);
+ CIO_TRACE_EVENT(2, dbf_text);
status = chp_get_status(chpid);
if (!on && !status) {
@@ -140,9 +140,11 @@ static ssize_t chp_measurement_chars_read(struct kobject *kobj,
char *buf, loff_t off, size_t count)
{
struct channel_path *chp;
+ struct device *device;
unsigned int size;
- chp = to_channelpath(container_of(kobj, struct device, kobj));
+ device = container_of(kobj, struct device, kobj);
+ chp = to_channelpath(device);
if (!chp->cmg_chars)
return 0;
@@ -193,9 +195,11 @@ static ssize_t chp_measurement_read(struct kobject *kobj,
{
struct channel_path *chp;
struct channel_subsystem *css;
+ struct device *device;
unsigned int size;
- chp = to_channelpath(container_of(kobj, struct device, kobj));
+ device = container_of(kobj, struct device, kobj);
+ chp = to_channelpath(device);
css = to_css(chp->dev.parent);
size = sizeof(struct cmg_entry);
@@ -242,7 +246,7 @@ int chp_add_cmg_attr(struct channel_path *chp)
static ssize_t chp_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct channel_path *chp = container_of(dev, struct channel_path, dev);
+ struct channel_path *chp = to_channelpath(dev);
if (!chp)
return 0;
@@ -254,7 +258,7 @@ static ssize_t chp_status_write(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct channel_path *cp = container_of(dev, struct channel_path, dev);
+ struct channel_path *cp = to_channelpath(dev);
char cmd[10];
int num_args;
int error;
@@ -282,7 +286,7 @@ static ssize_t chp_configure_show(struct device *dev,
struct channel_path *cp;
int status;
- cp = container_of(dev, struct channel_path, dev);
+ cp = to_channelpath(dev);
status = chp_info_get_status(cp->chpid);
if (status < 0)
return status;
@@ -304,7 +308,7 @@ static ssize_t chp_configure_write(struct device *dev,
return -EINVAL;
if (val != 0 && val != 1)
return -EINVAL;
- cp = container_of(dev, struct channel_path, dev);
+ cp = to_channelpath(dev);
chp_cfg_schedule(cp->chpid, val);
cfg_wait_idle();
@@ -316,7 +320,7 @@ static DEVICE_ATTR(configure, 0644, chp_configure_show, chp_configure_write);
static ssize_t chp_type_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct channel_path *chp = container_of(dev, struct channel_path, dev);
+ struct channel_path *chp = to_channelpath(dev);
if (!chp)
return 0;
@@ -353,7 +357,7 @@ static ssize_t chp_shared_show(struct device *dev,
static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);
-static struct attribute * chp_attrs[] = {
+static struct attribute *chp_attrs[] = {
&dev_attr_status.attr,
&dev_attr_configure.attr,
&dev_attr_type.attr,
@@ -370,7 +374,7 @@ static void chp_release(struct device *dev)
{
struct channel_path *cp;
- cp = container_of(dev, struct channel_path, dev);
+ cp = to_channelpath(dev);
kfree(cp);
}
@@ -395,7 +399,7 @@ int chp_new(struct chp_id chpid)
/* fill in status, etc. */
chp->chpid = chpid;
chp->state = 1;
- chp->dev.parent = &css[chpid.cssid]->device;
+ chp->dev.parent = &channel_subsystems[chpid.cssid]->device;
chp->dev.release = chp_release;
snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid,
chpid.id);
@@ -430,18 +434,18 @@ int chp_new(struct chp_id chpid)
device_unregister(&chp->dev);
goto out_free;
}
- mutex_lock(&css[chpid.cssid]->mutex);
- if (css[chpid.cssid]->cm_enabled) {
+ mutex_lock(&channel_subsystems[chpid.cssid]->mutex);
+ if (channel_subsystems[chpid.cssid]->cm_enabled) {
ret = chp_add_cmg_attr(chp);
if (ret) {
sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
device_unregister(&chp->dev);
- mutex_unlock(&css[chpid.cssid]->mutex);
+ mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
goto out_free;
}
}
- css[chpid.cssid]->chps[chpid.id] = chp;
- mutex_unlock(&css[chpid.cssid]->mutex);
+ channel_subsystems[chpid.cssid]->chps[chpid.id] = chp;
+ mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
return ret;
out_free:
kfree(chp);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index f2708d65be5..46905345159 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -619,6 +619,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
sch->schib.pmcw.ena = 0;
if ((sch->lpm & (sch->lpm - 1)) != 0)
sch->schib.pmcw.mp = 1; /* multipath mode */
+ /* clean up possible residual cmf stuff */
+ sch->schib.pmcw.mme = 0;
+ sch->schib.pmcw.mbfc = 0;
+ sch->schib.pmcw.mbi = 0;
+ sch->schib.mba = 0;
return 0;
out:
if (!cio_is_console(schid))
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 34a796913b0..f4c132ab39e 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -45,7 +45,8 @@
#include "ioasm.h"
#include "chsc.h"
-/* parameter to enable cmf during boot, possible uses are:
+/*
+ * parameter to enable cmf during boot, possible uses are:
* "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be
* used on any subchannel
* "s390cmf=<num>" -- enable cmf and allocate enough memory to measure
@@ -73,18 +74,20 @@ enum cmb_index {
* enum cmb_format - types of supported measurement block formats
*
* @CMF_BASIC: traditional channel measurement blocks supported
- * by all machines that we run on
+ * by all machines that we run on
* @CMF_EXTENDED: improved format that was introduced with the z990
- * machine
- * @CMF_AUTODETECT: default: use extended format when running on a z990
- * or later machine, otherwise fall back to basic format
- **/
+ * machine
+ * @CMF_AUTODETECT: default: use extended format when running on a machine
+ * supporting extended format, otherwise fall back to
+ * basic format
+ */
enum cmb_format {
CMF_BASIC,
CMF_EXTENDED,
CMF_AUTODETECT = -1,
};
-/**
+
+/*
* format - actual format for all measurement blocks
*
* The format module parameter can be set to a value of 0 (zero)
@@ -105,20 +108,21 @@ module_param(format, bool, 0444);
* either with the help of a special pool or with kmalloc
* @free: free memory allocated with @alloc
* @set: enable or disable measurement
+ * @read: read a measurement entry at an index
* @readall: read a measurement block in a common format
* @reset: clear the data in the associated measurement block and
* reset its time stamp
* @align: align an allocated block so that the hardware can use it
*/
struct cmb_operations {
- int (*alloc) (struct ccw_device*);
- void(*free) (struct ccw_device*);
- int (*set) (struct ccw_device*, u32);
- u64 (*read) (struct ccw_device*, int);
- int (*readall)(struct ccw_device*, struct cmbdata *);
- void (*reset) (struct ccw_device*);
- void * (*align) (void *);
-
+ int (*alloc) (struct ccw_device *);
+ void (*free) (struct ccw_device *);
+ int (*set) (struct ccw_device *, u32);
+ u64 (*read) (struct ccw_device *, int);
+ int (*readall)(struct ccw_device *, struct cmbdata *);
+ void (*reset) (struct ccw_device *);
+ void *(*align) (void *);
+/* private: */
struct attribute_group *attr_group;
};
static struct cmb_operations *cmbops;
@@ -130,9 +134,11 @@ struct cmb_data {
unsigned long long last_update; /* when last_block was updated */
};
-/* our user interface is designed in terms of nanoseconds,
+/*
+ * Our user interface is designed in terms of nanoseconds,
* while the hardware measures total times in its own
- * unit.*/
+ * unit.
+ */
static inline u64 time_to_nsec(u32 value)
{
return ((u64)value) * 128000ull;
@@ -152,19 +158,20 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count)
if (count == 0)
return 0;
- /* value comes in units of 128 µsec */
+ /* value comes in units of 128 µsec */
ret = time_to_nsec(value);
do_div(ret, count);
return ret;
}
-/* activate or deactivate the channel monitor. When area is NULL,
+/*
+ * Activate or deactivate the channel monitor. When area is NULL,
* the monitor is deactivated. The channel monitor needs to
* be active in order to measure subchannels, which also need
- * to be enabled. */
-static inline void
-cmf_activate(void *area, unsigned int onoff)
+ * to be enabled.
+ */
+static inline void cmf_activate(void *area, unsigned int onoff)
{
register void * __gpr2 asm("2");
register long __gpr1 asm("1");
@@ -175,8 +182,8 @@ cmf_activate(void *area, unsigned int onoff)
asm("schm" : : "d" (__gpr2), "d" (__gpr1) );
}
-static int
-set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address)
+static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
+ unsigned long address)
{
int ret;
int retry;
@@ -336,10 +343,10 @@ static int cmf_copy_block(struct ccw_device *cdev)
if (sch->schib.scsw.fctl & SCSW_FCTL_START_FUNC) {
/* Don't copy if a start function is in progress. */
- if ((!sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED) &&
+ if ((!(sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED)) &&
(sch->schib.scsw.actl &
(SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) &&
- (!sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS))
+ (!(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)))
return -EBUSY;
}
cmb_data = cdev->private->cmb;
@@ -466,6 +473,7 @@ static void cmf_generic_reset(struct ccw_device *cdev)
*
* @mem: pointer to CMBs (only in basic measurement mode)
* @list: contains a linked list of all subchannels
+ * @num_channels: number of channels to be measured
* @lock: protect concurrent access to @mem and @list
*/
struct cmb_area {
@@ -481,28 +489,36 @@ static struct cmb_area cmb_area = {
.num_channels = 1024,
};
-
/* ****** old style CMB handling ********/
-/** int maxchannels
- *
+/*
* Basic channel measurement blocks are allocated in one contiguous
* block of memory, which can not be moved as long as any channel
* is active. Therefore, a maximum number of subchannels needs to
* be defined somewhere. This is a module parameter, defaulting to
* a resonable value of 1024, or 32 kb of memory.
* Current kernels don't allow kmalloc with more than 128kb, so the
- * maximum is 4096
+ * maximum is 4096.
*/
module_param_named(maxchannels, cmb_area.num_channels, uint, 0444);
/**
* struct cmb - basic channel measurement block
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @reserved: unused in basic measurement mode
+ *
+ * The measurement block as used by the hardware. The fields are described
+ * further in z/Architecture Principles of Operation, chapter 17.
*
- * cmb as used by the hardware the fields are described in z/Architecture
- * Principles of Operation, chapter 17.
- * The area to be a contiguous array and may not be reallocated or freed.
+ * The cmb area made up from these blocks must be a contiguous array and may
+ * not be reallocated or freed.
* Only one cmb area can be present in the system.
*/
struct cmb {
@@ -516,8 +532,9 @@ struct cmb {
u32 reserved[2];
};
-/* insert a single device into the cmb_area list
- * called with cmb_area.lock held from alloc_cmb
+/*
+ * Insert a single device into the cmb_area list.
+ * Called with cmb_area.lock held from alloc_cmb.
*/
static int alloc_cmb_single(struct ccw_device *cdev,
struct cmb_data *cmb_data)
@@ -532,9 +549,11 @@ static int alloc_cmb_single(struct ccw_device *cdev,
goto out;
}
- /* find first unused cmb in cmb_area.mem.
- * this is a little tricky: cmb_area.list
- * remains sorted by ->cmb->hw_data pointers */
+ /*
+ * Find first unused cmb in cmb_area.mem.
+ * This is a little tricky: cmb_area.list
+ * remains sorted by ->cmb->hw_data pointers.
+ */
cmb = cmb_area.mem;
list_for_each_entry(node, &cmb_area.list, cmb_list) {
struct cmb_data *data;
@@ -558,8 +577,7 @@ out:
return ret;
}
-static int
-alloc_cmb (struct ccw_device *cdev)
+static int alloc_cmb(struct ccw_device *cdev)
{
int ret;
struct cmb *mem;
@@ -670,7 +688,7 @@ static int set_cmb(struct ccw_device *cdev, u32 mme)
return set_schib_wait(cdev, mme, 0, offset);
}
-static u64 read_cmb (struct ccw_device *cdev, int index)
+static u64 read_cmb(struct ccw_device *cdev, int index)
{
struct cmb *cmb;
u32 val;
@@ -720,7 +738,7 @@ out:
return ret;
}
-static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data)
{
struct cmb *cmb;
struct cmb_data *cmb_data;
@@ -793,14 +811,25 @@ static struct cmb_operations cmbops_basic = {
.align = align_cmb,
.attr_group = &cmf_attr_group,
};
-
+
/* ******** extended cmb handling ********/
/**
* struct cmbe - extended channel measurement block
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @device_busy_time: time of device busy
+ * @initial_command_response_time: initial command response time
+ * @reserved: unused
*
- * cmb as used by the hardware, may be in any 64 bit physical location,
- * the fields are described in z/Architecture Principles of Operation,
+ * The measurement block as used by the hardware. May be in any 64 bit physical
+ * location.
+ * The fields are described further in z/Architecture Principles of Operation,
* third edition, chapter 17.
*/
struct cmbe {
@@ -816,10 +845,12 @@ struct cmbe {
u32 reserved[7];
};
-/* kmalloc only guarantees 8 byte alignment, but we need cmbe
+/*
+ * kmalloc only guarantees 8 byte alignment, but we need cmbe
* pointers to be naturally aligned. Make sure to allocate
- * enough space for two cmbes */
-static inline struct cmbe* cmbe_align(struct cmbe *c)
+ * enough space for two cmbes.
+ */
+static inline struct cmbe *cmbe_align(struct cmbe *c)
{
unsigned long addr;
addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) &
@@ -827,7 +858,7 @@ static inline struct cmbe* cmbe_align(struct cmbe *c)
return (struct cmbe*)addr;
}
-static int alloc_cmbe (struct ccw_device *cdev)
+static int alloc_cmbe(struct ccw_device *cdev)
{
struct cmbe *cmbe;
struct cmb_data *cmb_data;
@@ -873,7 +904,7 @@ out_free:
return ret;
}
-static void free_cmbe (struct ccw_device *cdev)
+static void free_cmbe(struct ccw_device *cdev)
{
struct cmb_data *cmb_data;
@@ -912,7 +943,7 @@ static int set_cmbe(struct ccw_device *cdev, u32 mme)
}
-static u64 read_cmbe (struct ccw_device *cdev, int index)
+static u64 read_cmbe(struct ccw_device *cdev, int index)
{
struct cmbe *cmb;
struct cmb_data *cmb_data;
@@ -970,7 +1001,7 @@ out:
return ret;
}
-static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data)
{
struct cmbe *cmb;
struct cmb_data *cmb_data;
@@ -1047,17 +1078,16 @@ static struct cmb_operations cmbops_extended = {
.align = align_cmbe,
.attr_group = &cmf_attr_group_ext,
};
-
-static ssize_t
-cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
+static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
{
return sprintf(buf, "%lld\n",
(unsigned long long) cmf_read(to_ccwdev(dev), idx));
}
-static ssize_t
-cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_show_avg_sample_interval(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct ccw_device *cdev;
long interval;
@@ -1079,8 +1109,9 @@ cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%ld\n", interval);
}
-static ssize_t
-cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_show_avg_utilization(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct cmbdata data;
u64 utilization;
@@ -1112,14 +1143,16 @@ cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char
}
#define cmf_attr(name) \
-static ssize_t show_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
-{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
-static DEVICE_ATTR(name, 0444, show_ ## name, NULL);
+static ssize_t show_##name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ return cmb_show_attr((dev), buf, cmb_##name); } \
+static DEVICE_ATTR(name, 0444, show_##name, NULL);
#define cmf_attr_avg(name) \
-static ssize_t show_avg_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
-{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
-static DEVICE_ATTR(avg_ ## name, 0444, show_avg_ ## name, NULL);
+static ssize_t show_avg_##name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ return cmb_show_attr((dev), buf, cmb_##name); } \
+static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL);
cmf_attr(ssch_rsch_count);
cmf_attr(sample_count);
@@ -1131,7 +1164,8 @@ cmf_attr_avg(device_active_only_time);
cmf_attr_avg(device_busy_time);
cmf_attr_avg(initial_command_response_time);
-static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, NULL);
+static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval,
+ NULL);
static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL);
static struct attribute *cmf_attributes[] = {
@@ -1172,12 +1206,16 @@ static struct attribute_group cmf_attr_group_ext = {
.attrs = cmf_attributes_ext,
};
-static ssize_t cmb_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0);
}
-static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t c)
+static ssize_t cmb_enable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t c)
{
struct ccw_device *cdev;
int ret;
@@ -1202,9 +1240,16 @@ static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *att
DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store);
-/* enable_cmf/disable_cmf: module interface for cmf (de)activation */
-int
-enable_cmf(struct ccw_device *cdev)
+/**
+ * enable_cmf() - switch on the channel measurement for a specific device
+ * @cdev: The ccw device to be enabled
+ *
+ * Returns %0 for success or a negative error value.
+ *
+ * Context:
+ * non-atomic
+ */
+int enable_cmf(struct ccw_device *cdev)
{
int ret;
@@ -1225,8 +1270,16 @@ enable_cmf(struct ccw_device *cdev)
return ret;
}
-int
-disable_cmf(struct ccw_device *cdev)
+/**
+ * disable_cmf() - switch off the channel measurement for a specific device
+ * @cdev: The ccw device to be disabled
+ *
+ * Returns %0 for success or a negative error value.
+ *
+ * Context:
+ * non-atomic
+ */
+int disable_cmf(struct ccw_device *cdev)
{
int ret;
@@ -1238,14 +1291,32 @@ disable_cmf(struct ccw_device *cdev)
return ret;
}
-u64
-cmf_read(struct ccw_device *cdev, int index)
+/**
+ * cmf_read() - read one value from the current channel measurement block
+ * @cdev: the channel to be read
+ * @index: the index of the value to be read
+ *
+ * Returns the value read or %0 if the value cannot be read.
+ *
+ * Context:
+ * any
+ */
+u64 cmf_read(struct ccw_device *cdev, int index)
{
return cmbops->read(cdev, index);
}
-int
-cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
+/**
+ * cmf_readall() - read the current channel measurement block
+ * @cdev: the channel to be read
+ * @data: a pointer to a data block that will be filled
+ *
+ * Returns %0 on success, a negative error value otherwise.
+ *
+ * Context:
+ * any
+ */
+int cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
{
return cmbops->readall(cdev, data);
}
@@ -1257,15 +1328,16 @@ int cmf_reenable(struct ccw_device *cdev)
return cmbops->set(cdev, 2);
}
-static int __init
-init_cmf(void)
+static int __init init_cmf(void)
{
char *format_string;
char *detect_string = "parameter";
- /* We cannot really autoprobe this. If the user did not give a parameter,
- see if we are running on z990 or up, otherwise fall back to basic mode. */
-
+ /*
+ * If the user did not give a parameter, see if we are running on a
+ * machine supporting extended measurement blocks, otherwise fall back
+ * to basic mode.
+ */
if (format == CMF_AUTODETECT) {
if (!css_characteristics_avail ||
!css_general_characteristics.ext_mb) {
@@ -1284,7 +1356,7 @@ init_cmf(void)
cmbops = &cmbops_basic;
break;
case CMF_EXTENDED:
- format_string = "extended";
+ format_string = "extended";
cmbops = &cmbops_extended;
break;
default:
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 5635e656c1a..838f7ac0dc3 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/list.h>
+#include <linux/reboot.h>
#include "css.h"
#include "cio.h"
@@ -27,7 +28,7 @@ int css_init_done = 0;
static int need_reprobe = 0;
static int max_ssid = 0;
-struct channel_subsystem *css[__MAX_CSSID + 1];
+struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1];
int css_characteristics_avail = 0;
@@ -177,10 +178,19 @@ static int css_register_subchannel(struct subchannel *sch)
int ret;
/* Initialize the subchannel structure */
- sch->dev.parent = &css[0]->device;
+ sch->dev.parent = &channel_subsystems[0]->device;
sch->dev.bus = &css_bus_type;
sch->dev.release = &css_subchannel_release;
sch->dev.groups = subch_attr_groups;
+ /*
+ * We don't want to generate uevents for I/O subchannels that don't
+ * have a working ccw device behind them since they will be
+ * unregistered before they can be used anyway, so we delay the add
+ * uevent until after device recognition was successful.
+ */
+ if (!cio_is_console(sch->schid))
+ /* Console is special, no need to suppress. */
+ sch->dev.uevent_suppress = 1;
css_update_ssd_info(sch);
/* make it known to the system */
ret = css_sch_device_register(sch);
@@ -606,30 +616,55 @@ static int __init setup_css(int nr)
{
u32 tod_high;
int ret;
+ struct channel_subsystem *css;
- memset(css[nr], 0, sizeof(struct channel_subsystem));
- css[nr]->pseudo_subchannel =
- kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL);
- if (!css[nr]->pseudo_subchannel)
+ css = channel_subsystems[nr];
+ memset(css, 0, sizeof(struct channel_subsystem));
+ css->pseudo_subchannel =
+ kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL);
+ if (!css->pseudo_subchannel)
return -ENOMEM;
- css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device;
- css[nr]->pseudo_subchannel->dev.release = css_subchannel_release;
- sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct");
- ret = cio_create_sch_lock(css[nr]->pseudo_subchannel);
+ css->pseudo_subchannel->dev.parent = &css->device;
+ css->pseudo_subchannel->dev.release = css_subchannel_release;
+ sprintf(css->pseudo_subchannel->dev.bus_id, "defunct");
+ ret = cio_create_sch_lock(css->pseudo_subchannel);
if (ret) {
- kfree(css[nr]->pseudo_subchannel);
+ kfree(css->pseudo_subchannel);
return ret;
}
- mutex_init(&css[nr]->mutex);
- css[nr]->valid = 1;
- css[nr]->cssid = nr;
- sprintf(css[nr]->device.bus_id, "css%x", nr);
- css[nr]->device.release = channel_subsystem_release;
+ mutex_init(&css->mutex);
+ css->valid = 1;
+ css->cssid = nr;
+ sprintf(css->device.bus_id, "css%x", nr);
+ css->device.release = channel_subsystem_release;
tod_high = (u32) (get_clock() >> 32);
- css_generate_pgid(css[nr], tod_high);
+ css_generate_pgid(css, tod_high);
return 0;
}
+static int css_reboot_event(struct notifier_block *this,
+ unsigned long event,
+ void *ptr)
+{
+ int ret, i;
+
+ ret = NOTIFY_DONE;
+ for (i = 0; i <= __MAX_CSSID; i++) {
+ struct channel_subsystem *css;
+
+ css = channel_subsystems[i];
+ if (css->cm_enabled)
+ if (chsc_secm(css, 0))
+ ret = NOTIFY_BAD;
+ }
+
+ return ret;
+}
+
+static struct notifier_block css_reboot_notifier = {
+ .notifier_call = css_reboot_event,
+};
+
/*
* Now that the driver core is running, we can setup our channel subsystem.
* The struct subchannel's are created during probing (except for the
@@ -670,51 +705,63 @@ init_channel_subsystem (void)
}
/* Setup css structure. */
for (i = 0; i <= __MAX_CSSID; i++) {
- css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
- if (!css[i]) {
+ struct channel_subsystem *css;
+
+ css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
+ if (!css) {
ret = -ENOMEM;
goto out_unregister;
}
+ channel_subsystems[i] = css;
ret = setup_css(i);
if (ret)
goto out_free;
- ret = device_register(&css[i]->device);
+ ret = device_register(&css->device);
if (ret)
goto out_free_all;
if (css_characteristics_avail &&
css_chsc_characteristics.secm) {
- ret = device_create_file(&css[i]->device,
+ ret = device_create_file(&css->device,
&dev_attr_cm_enable);
if (ret)
goto out_device;
}
- ret = device_register(&css[i]->pseudo_subchannel->dev);
+ ret = device_register(&css->pseudo_subchannel->dev);
if (ret)
goto out_file;
}
+ ret = register_reboot_notifier(&css_reboot_notifier);
+ if (ret)
+ goto out_pseudo;
css_init_done = 1;
ctl_set_bit(6, 28);
for_each_subchannel(__init_channel_subsystem, NULL);
return 0;
+out_pseudo:
+ device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev);
out_file:
- device_remove_file(&css[i]->device, &dev_attr_cm_enable);
+ device_remove_file(&channel_subsystems[i]->device,
+ &dev_attr_cm_enable);
out_device:
- device_unregister(&css[i]->device);
+ device_unregister(&channel_subsystems[i]->device);
out_free_all:
- kfree(css[i]->pseudo_subchannel->lock);
- kfree(css[i]->pseudo_subchannel);
+ kfree(channel_subsystems[i]->pseudo_subchannel->lock);
+ kfree(channel_subsystems[i]->pseudo_subchannel);
out_free:
- kfree(css[i]);
+ kfree(channel_subsystems[i]);
out_unregister:
while (i > 0) {
+ struct channel_subsystem *css;
+
i--;
- device_unregister(&css[i]->pseudo_subchannel->dev);
+ css = channel_subsystems[i];
+ device_unregister(&css->pseudo_subchannel->dev);
if (css_characteristics_avail && css_chsc_characteristics.secm)
- device_remove_file(&css[i]->device,
+ device_remove_file(&css->device,
&dev_attr_cm_enable);
- device_unregister(&css[i]->device);
+ device_unregister(&css->device);
}
out_bus:
bus_unregister(&css_bus_type);
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 5d65e83ca66..81215ef3243 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -167,7 +167,7 @@ struct channel_subsystem {
#define to_css(dev) container_of(dev, struct channel_subsystem, device)
extern struct bus_type css_bus_type;
-extern struct channel_subsystem *css[];
+extern struct channel_subsystem *channel_subsystems[];
/* Some helper functions for disconnected state. */
int device_is_disconnected(struct subchannel *);
@@ -191,6 +191,5 @@ int sch_is_pseudo_sch(struct subchannel *);
extern struct workqueue_struct *slow_path_wq;
-int subchannel_add_files (struct device *);
extern struct attribute_group *subch_attr_groups[];
#endif
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e44d92eac8e..74f6b539974 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -21,6 +21,7 @@
#include <asm/ccwdev.h>
#include <asm/cio.h>
#include <asm/param.h> /* HZ */
+#include <asm/cmb.h>
#include "cio.h"
#include "cio_debug.h"
@@ -78,49 +79,38 @@ static int snprint_alias(char *buf, size_t size,
/* Set up environment variables for ccw device uevent. Return 0 on success,
* non-zero otherwise. */
-static int ccw_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct ccw_device *cdev = to_ccwdev(dev);
struct ccw_device_id *id = &(cdev->id);
- int i = 0;
- int len = 0;
int ret;
char modalias_buf[30];
/* CU_TYPE= */
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "CU_TYPE=%04X", id->cu_type);
+ ret = add_uevent_var(env, "CU_TYPE=%04X", id->cu_type);
if (ret)
return ret;
/* CU_MODEL= */
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "CU_MODEL=%02X", id->cu_model);
+ ret = add_uevent_var(env, "CU_MODEL=%02X", id->cu_model);
if (ret)
return ret;
/* The next two can be zero, that's ok for us */
/* DEV_TYPE= */
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "DEV_TYPE=%04X", id->dev_type);
+ ret = add_uevent_var(env, "DEV_TYPE=%04X", id->dev_type);
if (ret)
return ret;
/* DEV_MODEL= */
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "DEV_MODEL=%02X", id->dev_model);
+ ret = add_uevent_var(env, "DEV_MODEL=%02X", id->dev_model);
if (ret)
return ret;
/* MODALIAS= */
snprint_alias(modalias_buf, sizeof(modalias_buf), id, "");
- ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "MODALIAS=%s", modalias_buf);
- if (ret)
- return ret;
- envp[i] = NULL;
- return 0;
+ ret = add_uevent_var(env, "MODALIAS=%s", modalias_buf);
+ return ret;
}
struct bus_type ccw_bus_type;
@@ -357,8 +347,18 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
cdev->private->dev_id.devno);
}
-int
-ccw_device_set_offline(struct ccw_device *cdev)
+/**
+ * ccw_device_set_offline() - disable a ccw device for I/O
+ * @cdev: target ccw device
+ *
+ * This function calls the driver's set_offline() function for @cdev, if
+ * given, and then disables @cdev.
+ * Returns:
+ * %0 on success and a negative error value on failure.
+ * Context:
+ * enabled, ccw device lock not held
+ */
+int ccw_device_set_offline(struct ccw_device *cdev)
{
int ret;
@@ -396,8 +396,19 @@ ccw_device_set_offline(struct ccw_device *cdev)
return ret;
}
-int
-ccw_device_set_online(struct ccw_device *cdev)
+/**
+ * ccw_device_set_online() - enable a ccw device for I/O
+ * @cdev: target ccw device
+ *
+ * This function first enables @cdev and then calls the driver's set_online()
+ * function for @cdev, if given. If set_online() returns an error, @cdev is
+ * disabled again.
+ * Returns:
+ * %0 on success and a negative error value on failure.
+ * Context:
+ * enabled, ccw device lock not held
+ */
+int ccw_device_set_online(struct ccw_device *cdev)
{
int ret;
@@ -727,7 +738,7 @@ static int io_subchannel_initialize_dev(struct subchannel *sch,
atomic_set(&cdev->private->onoff, 0);
cdev->dev.parent = &sch->dev;
cdev->dev.release = ccw_device_release;
- INIT_LIST_HEAD(&cdev->private->kick_work.entry);
+ INIT_WORK(&cdev->private->kick_work, NULL);
cdev->dev.groups = ccwdev_attr_groups;
/* Do first half of device_register. */
device_initialize(&cdev->dev);
@@ -947,8 +958,7 @@ out:
wake_up(&ccw_device_init_wq);
}
-void
-ccw_device_call_sch_unregister(struct work_struct *work)
+static void ccw_device_call_sch_unregister(struct work_struct *work)
{
struct ccw_device_private *priv;
struct ccw_device *cdev;
@@ -1101,6 +1111,7 @@ io_subchannel_probe (struct subchannel *sch)
* device, e.g. the console.
*/
cdev = sch->dev.driver_data;
+ cdev->dev.groups = ccwdev_attr_groups;
device_initialize(&cdev->dev);
ccw_device_register(cdev);
/*
@@ -1326,8 +1337,19 @@ __ccwdev_check_busid(struct device *dev, void *id)
}
-struct ccw_device *
-get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id)
+/**
+ * get_ccwdev_by_busid() - obtain device from a bus id
+ * @cdrv: driver the device is owned by
+ * @bus_id: bus id of the device to be searched
+ *
+ * This function searches all devices owned by @cdrv for a device with a bus
+ * id matching @bus_id.
+ * Returns:
+ * If a match is found, its reference count of the found device is increased
+ * and it is returned; else %NULL is returned.
+ */
+struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv,
+ const char *bus_id)
{
struct device *dev;
struct device_driver *drv;
@@ -1401,16 +1423,34 @@ ccw_device_remove (struct device *dev)
return 0;
}
+static void ccw_device_shutdown(struct device *dev)
+{
+ struct ccw_device *cdev;
+
+ cdev = to_ccwdev(dev);
+ if (cdev->drv && cdev->drv->shutdown)
+ cdev->drv->shutdown(cdev);
+ disable_cmf(cdev);
+}
+
struct bus_type ccw_bus_type = {
.name = "ccw",
.match = ccw_bus_match,
.uevent = ccw_uevent,
.probe = ccw_device_probe,
.remove = ccw_device_remove,
+ .shutdown = ccw_device_shutdown,
};
-int
-ccw_driver_register (struct ccw_driver *cdriver)
+/**
+ * ccw_driver_register() - register a ccw driver
+ * @cdriver: driver to be registered
+ *
+ * This function is mainly a wrapper around driver_register().
+ * Returns:
+ * %0 on success and a negative error value on failure.
+ */
+int ccw_driver_register(struct ccw_driver *cdriver)
{
struct device_driver *drv = &cdriver->driver;
@@ -1420,8 +1460,13 @@ ccw_driver_register (struct ccw_driver *cdriver)
return driver_register(drv);
}
-void
-ccw_driver_unregister (struct ccw_driver *cdriver)
+/**
+ * ccw_driver_unregister() - deregister a ccw driver
+ * @cdriver: driver to be deregistered
+ *
+ * This function is mainly a wrapper around driver_unregister().
+ */
+void ccw_driver_unregister(struct ccw_driver *cdriver)
{
driver_unregister(&cdriver->driver);
}
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index b66338b7657..0d408960043 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -80,7 +80,6 @@ void io_subchannel_recog_done(struct ccw_device *cdev);
int ccw_device_cancel_halt_clear(struct ccw_device *);
void ccw_device_do_unreg_rereg(struct work_struct *);
-void ccw_device_call_sch_unregister(struct work_struct *);
void ccw_device_move_to_orphanage(struct work_struct *);
int ccw_device_is_orphan(struct ccw_device *);
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 8633dc53769..8867443b806 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -446,7 +446,8 @@ static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
if (cdev->private->pgid[last].inf.ps.state1 ==
SNID_STATE1_RESET)
/* No previous pgid found */
- memcpy(&cdev->private->pgid[0], &css[0]->global_pgid,
+ memcpy(&cdev->private->pgid[0],
+ &channel_subsystems[0]->global_pgid,
sizeof(struct pgid));
else
/* Use existing pgid */
@@ -543,51 +544,6 @@ ccw_device_recog_timeout(struct ccw_device *cdev, enum dev_event dev_event)
}
-static void
-ccw_device_nopath_notify(struct work_struct *work)
-{
- struct ccw_device_private *priv;
- struct ccw_device *cdev;
- struct subchannel *sch;
- int ret;
- unsigned long flags;
-
- priv = container_of(work, struct ccw_device_private, kick_work);
- cdev = priv->cdev;
- spin_lock_irqsave(cdev->ccwlock, flags);
- sch = to_subchannel(cdev->dev.parent);
- /* Extra sanity. */
- if (sch->lpm)
- goto out_unlock;
- if (sch->driver && sch->driver->notify) {
- spin_unlock_irqrestore(cdev->ccwlock, flags);
- ret = sch->driver->notify(&sch->dev, CIO_NO_PATH);
- spin_lock_irqsave(cdev->ccwlock, flags);
- } else
- ret = 0;
- if (!ret) {
- if (get_device(&sch->dev)) {
- /* Driver doesn't want to keep device. */
- cio_disable_subchannel(sch);
- if (get_device(&cdev->dev)) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister);
- queue_work(ccw_device_work,
- &cdev->private->kick_work);
- } else
- put_device(&sch->dev);
- }
- } else {
- cio_disable_subchannel(sch);
- ccw_device_set_timeout(cdev, 0);
- cdev->private->flags.fake_irb = 0;
- cdev->private->state = DEV_STATE_DISCONNECTED;
- wake_up(&cdev->private->wait_q);
- }
-out_unlock:
- spin_unlock_irqrestore(cdev->ccwlock, flags);
-}
-
void
ccw_device_verify_done(struct ccw_device *cdev, int err)
{
@@ -631,12 +587,9 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
default:
/* Reset oper notify indication after verify error. */
cdev->private->flags.donotify = 0;
- if (cdev->online) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify);
- queue_work(ccw_device_notify_work,
- &cdev->private->kick_work);
- } else
+ if (cdev->online)
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+ else
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
}
@@ -690,11 +643,7 @@ ccw_device_disband_done(struct ccw_device *cdev, int err)
break;
default:
cdev->private->flags.donotify = 0;
- if (get_device(&cdev->dev)) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister);
- queue_work(ccw_device_work, &cdev->private->kick_work);
- }
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
}
@@ -765,59 +714,16 @@ ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event)
}
/*
- * Handle not operational event while offline.
+ * Handle not operational event in non-special state.
*/
-static void
-ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event)
+static void ccw_device_generic_notoper(struct ccw_device *cdev,
+ enum dev_event dev_event)
{
struct subchannel *sch;
cdev->private->state = DEV_STATE_NOT_OPER;
sch = to_subchannel(cdev->dev.parent);
- if (get_device(&cdev->dev)) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister);
- queue_work(ccw_device_work, &cdev->private->kick_work);
- }
- wake_up(&cdev->private->wait_q);
-}
-
-/*
- * Handle not operational event while online.
- */
-static void
-ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
-{
- struct subchannel *sch;
- int ret;
-
- sch = to_subchannel(cdev->dev.parent);
- if (sch->driver->notify) {
- spin_unlock_irq(cdev->ccwlock);
- ret = sch->driver->notify(&sch->dev,
- sch->lpm ? CIO_GONE : CIO_NO_PATH);
- spin_lock_irq(cdev->ccwlock);
- } else
- ret = 0;
- if (ret) {
- ccw_device_set_timeout(cdev, 0);
- cdev->private->flags.fake_irb = 0;
- cdev->private->state = DEV_STATE_DISCONNECTED;
- wake_up(&cdev->private->wait_q);
- return;
- }
- cdev->private->state = DEV_STATE_NOT_OPER;
- cio_disable_subchannel(sch);
- if (sch->schib.scsw.actl != 0) {
- // FIXME: not-oper indication to device driver ?
- ccw_device_call_handler(cdev);
- }
- if (get_device(&cdev->dev)) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister);
- queue_work(ccw_device_work, &cdev->private->kick_work);
- }
- wake_up(&cdev->private->wait_q);
+ css_schedule_eval(sch->schid);
}
/*
@@ -915,18 +821,9 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
cdev->private->state = DEV_STATE_TIMEOUT_KILL;
return;
}
- if (ret == -ENODEV) {
- struct subchannel *sch;
-
- sch = to_subchannel(cdev->dev.parent);
- if (!sch->lpm) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify);
- queue_work(ccw_device_notify_work,
- &cdev->private->kick_work);
- } else
- dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
- } else if (cdev->handler)
+ if (ret == -ENODEV)
+ dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+ else if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
ERR_PTR(-ETIMEDOUT));
}
@@ -1233,7 +1130,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_SENSE_PGID] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_sense_pgid_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
[DEV_EVENT_VERIFY] = ccw_device_nop,
@@ -1245,50 +1142,50 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_OFFLINE] = {
- [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_offline_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_VERIFY] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_verify_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
[DEV_EVENT_VERIFY] = ccw_device_delay_verify,
},
[DEV_STATE_ONLINE] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_online_timeout,
[DEV_EVENT_VERIFY] = ccw_device_online_verify,
},
[DEV_STATE_W4SENSE] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_w4sense,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_online_verify,
},
[DEV_STATE_DISBAND_PGID] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_disband_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_BOXED] = {
- [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_stlck_done,
[DEV_EVENT_TIMEOUT] = ccw_device_stlck_done,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
/* states to wait for i/o completion before doing something */
[DEV_STATE_CLEAR_VERIFY] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_clear_verify,
[DEV_EVENT_TIMEOUT] = ccw_device_nop,
[DEV_EVENT_VERIFY] = ccw_device_nop,
},
[DEV_STATE_TIMEOUT_KILL] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_killing_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout,
[DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 14eba854b15..7fd2dadc329 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -25,6 +25,16 @@
#include "device.h"
#include "chp.h"
+/**
+ * ccw_device_set_options_mask() - set some options and unset the rest
+ * @cdev: device for which the options are to be set
+ * @flags: options to be set
+ *
+ * All flags specified in @flags are set, all flags not specified in @flags
+ * are cleared.
+ * Returns:
+ * %0 on success, -%EINVAL on an invalid flag combination.
+ */
int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
{
/*
@@ -40,6 +50,15 @@ int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
return 0;
}
+/**
+ * ccw_device_set_options() - set some options
+ * @cdev: device for which the options are to be set
+ * @flags: options to be set
+ *
+ * All flags specified in @flags are set, the remainder is left untouched.
+ * Returns:
+ * %0 on success, -%EINVAL if an invalid flag combination would ensue.
+ */
int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
{
/*
@@ -59,6 +78,13 @@ int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
return 0;
}
+/**
+ * ccw_device_clear_options() - clear some options
+ * @cdev: device for which the options are to be cleared
+ * @flags: options to be cleared
+ *
+ * All flags specified in @flags are cleared, the remainder is left untouched.
+ */
void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
{
cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0;
@@ -67,8 +93,22 @@ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0;
}
-int
-ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
+/**
+ * ccw_device_clear() - terminate I/O request processing
+ * @cdev: target ccw device
+ * @intparm: interruption parameter; value is only used if no I/O is
+ * outstanding, otherwise the intparm associated with the I/O request
+ * is returned
+ *
+ * ccw_device_clear() calls csch on @cdev's subchannel.
+ * Returns:
+ * %0 on success,
+ * -%ENODEV on device not operational,
+ * -%EINVAL on invalid device state.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
{
struct subchannel *sch;
int ret;
@@ -89,10 +129,33 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
return ret;
}
-int
-ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, __u8 key,
- unsigned long flags)
+/**
+ * ccw_device_start_key() - start a s390 channel program with key
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ * @cdev's interrupt handler. Allows a device driver to associate
+ * the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ * value of 0 will make cio use the opm.
+ * @key: storage key to be used for the I/O
+ * @flags: additional flags; defines the action to be performed for I/O
+ * processing.
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * Returns:
+ * %0, if the operation was successful;
+ * -%EBUSY, if the device is busy, or status pending;
+ * -%EACCES, if no path specified in @lpm is operational;
+ * -%ENODEV, if the device is not operational.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm, __u8 key,
+ unsigned long flags)
{
struct subchannel *sch;
int ret;
@@ -135,11 +198,38 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
return ret;
}
-
-int
-ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, __u8 key,
- unsigned long flags, int expires)
+/**
+ * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ * @cdev's interrupt handler. Allows a device driver to associate
+ * the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ * value of 0 will make cio use the opm.
+ * @key: storage key to be used for the I/O
+ * @flags: additional flags; defines the action to be performed for I/O
+ * processing.
+ * @expires: timeout value in jiffies
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * This function notifies the device driver if the channel program has not
+ * completed during the time specified by @expires. If a timeout occurs, the
+ * channel program is terminated via xsch, hsch or csch, and the device's
+ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
+ * Returns:
+ * %0, if the operation was successful;
+ * -%EBUSY, if the device is busy, or status pending;
+ * -%EACCES, if no path specified in @lpm is operational;
+ * -%ENODEV, if the device is not operational.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm, __u8 key,
+ unsigned long flags, int expires)
{
int ret;
@@ -152,18 +242,67 @@ ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
return ret;
}
-int
-ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, unsigned long flags)
+/**
+ * ccw_device_start() - start a s390 channel program
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ * @cdev's interrupt handler. Allows a device driver to associate
+ * the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ * value of 0 will make cio use the opm.
+ * @flags: additional flags; defines the action to be performed for I/O
+ * processing.
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * Returns:
+ * %0, if the operation was successful;
+ * -%EBUSY, if the device is busy, or status pending;
+ * -%EACCES, if no path specified in @lpm is operational;
+ * -%ENODEV, if the device is not operational.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm, unsigned long flags)
{
return ccw_device_start_key(cdev, cpa, intparm, lpm,
PAGE_DEFAULT_KEY, flags);
}
-int
-ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
- unsigned long intparm, __u8 lpm, unsigned long flags,
- int expires)
+/**
+ * ccw_device_start_timeout() - start a s390 channel program with timeout
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ * @cdev's interrupt handler. Allows a device driver to associate
+ * the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ * value of 0 will make cio use the opm.
+ * @flags: additional flags; defines the action to be performed for I/O
+ * processing.
+ * @expires: timeout value in jiffies
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * This function notifies the device driver if the channel program has not
+ * completed during the time specified by @expires. If a timeout occurs, the
+ * channel program is terminated via xsch, hsch or csch, and the device's
+ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
+ * Returns:
+ * %0, if the operation was successful;
+ * -%EBUSY, if the device is busy, or status pending;
+ * -%EACCES, if no path specified in @lpm is operational;
+ * -%ENODEV, if the device is not operational.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
+ unsigned long intparm, __u8 lpm,
+ unsigned long flags, int expires)
{
return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm,
PAGE_DEFAULT_KEY, flags,
@@ -171,8 +310,23 @@ ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
}
-int
-ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
+/**
+ * ccw_device_halt() - halt I/O request processing
+ * @cdev: target ccw device
+ * @intparm: interruption parameter; value is only used if no I/O is
+ * outstanding, otherwise the intparm associated with the I/O request
+ * is returned
+ *
+ * ccw_device_halt() calls hsch on @cdev's subchannel.
+ * Returns:
+ * %0 on success,
+ * -%ENODEV on device not operational,
+ * -%EINVAL on invalid device state,
+ * -%EBUSY on device busy or interrupt pending.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
{
struct subchannel *sch;
int ret;
@@ -193,8 +347,20 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
return ret;
}
-int
-ccw_device_resume(struct ccw_device *cdev)
+/**
+ * ccw_device_resume() - resume channel program execution
+ * @cdev: target ccw device
+ *
+ * ccw_device_resume() calls rsch on @cdev's subchannel.
+ * Returns:
+ * %0 on success,
+ * -%ENODEV on device not operational,
+ * -%EINVAL on invalid device state,
+ * -%EBUSY on device busy or interrupt pending.
+ * Context:
+ * Interrupts disabled, ccw device lock held
+ */
+int ccw_device_resume(struct ccw_device *cdev)
{
struct subchannel *sch;
@@ -260,11 +426,21 @@ ccw_device_call_handler(struct ccw_device *cdev)
return 1;
}
-/*
- * Search for CIW command in extended sense data.
+/**
+ * ccw_device_get_ciw() - Search for CIW command in extended sense data.
+ * @cdev: ccw device to inspect
+ * @ct: command type to look for
+ *
+ * During SenseID, command information words (CIWs) describing special
+ * commands available to the device may have been stored in the extended
+ * sense data. This function searches for CIWs of a specified command
+ * type in the extended sense data.
+ * Returns:
+ * %NULL if no extended sense data has been stored or if no CIW of the
+ * specified command type could be found,
+ * else a pointer to the CIW of the specified command type.
*/
-struct ciw *
-ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
+struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
{
int ciw_cnt;
@@ -276,8 +452,14 @@ ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
return NULL;
}
-__u8
-ccw_device_get_path_mask(struct ccw_device *cdev)
+/**
+ * ccw_device_get_path_mask() - get currently available paths
+ * @cdev: ccw device to be queried
+ * Returns:
+ * %0 if no subchannel for the device is available,
+ * else the mask of currently available paths for the ccw device's subchannel.
+ */
+__u8 ccw_device_get_path_mask(struct ccw_device *cdev)
{
struct subchannel *sch;
@@ -357,8 +539,7 @@ out_unlock:
return ret;
}
-void *
-ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
+void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
{
struct subchannel *sch;
struct chp_id chpid;
diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c
index 16ea828e99f..ef7bc0a125e 100644
--- a/drivers/s390/cio/idset.c
+++ b/drivers/s390/cio/idset.c
@@ -6,7 +6,7 @@
*/
#include <linux/slab.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
#include "idset.h"
#include "css.h"
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index d8d479876ec..40a3208c7cf 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -1024,9 +1024,9 @@ __qdio_outbound_processing(struct qdio_q *q)
}
static void
-qdio_outbound_processing(struct qdio_q *q)
+qdio_outbound_processing(unsigned long q)
{
- __qdio_outbound_processing(q);
+ __qdio_outbound_processing((struct qdio_q *) q);
}
/************************* INBOUND ROUTINES *******************************/
@@ -1449,9 +1449,10 @@ out:
}
static void
-tiqdio_inbound_processing(struct qdio_q *q)
+tiqdio_inbound_processing(unsigned long q)
{
- __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount));
+ __tiqdio_inbound_processing((struct qdio_q *) q,
+ atomic_read(&spare_indicator_usecount));
}
static void
@@ -1494,9 +1495,9 @@ again:
}
static void
-qdio_inbound_processing(struct qdio_q *q)
+qdio_inbound_processing(unsigned long q)
{
- __qdio_inbound_processing(q);
+ __qdio_inbound_processing((struct qdio_q *) q);
}
/************************* MAIN ROUTINES *******************************/
@@ -1760,12 +1761,15 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
q->handler=input_handler;
q->dev_st_chg_ind=irq_ptr->dev_st_chg_ind;
- q->tasklet.data=(unsigned long)q;
/* q->is_thinint_q isn't valid at this time, but
- * irq_ptr->is_thinint_irq is */
- q->tasklet.func=(void(*)(unsigned long))
- ((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing:
- &qdio_inbound_processing);
+ * irq_ptr->is_thinint_irq is
+ */
+ if (irq_ptr->is_thinint_irq)
+ tasklet_init(&q->tasklet, tiqdio_inbound_processing,
+ (unsigned long) q);
+ else
+ tasklet_init(&q->tasklet, qdio_inbound_processing,
+ (unsigned long) q);
/* actually this is not used for inbound queues. yet. */
atomic_set(&q->busy_siga_counter,0);
@@ -1836,13 +1840,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
q->last_move_ftc=0;
q->handler=output_handler;
- q->tasklet.data=(unsigned long)q;
- q->tasklet.func=(void(*)(unsigned long))
- &qdio_outbound_processing;
- q->timer.function=(void(*)(unsigned long))
- &qdio_outbound_processing;
- q->timer.data = (long)q;
- init_timer(&q->timer);
+ tasklet_init(&q->tasklet, qdio_outbound_processing,
+ (unsigned long) q);
+ setup_timer(&q->timer, qdio_outbound_processing,
+ (unsigned long) q);
atomic_set(&q->busy_siga_counter,0);
q->timing.busy_start=0;
@@ -3726,7 +3727,7 @@ qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count
#endif /* CONFIG_64BIT */
}
} else {
- QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n");
+ QDIO_PRINT_ERR("QDIO performance_stats: write 0 or 1 to this file!\n");
return -EINVAL;
}
return count;
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 90bd2201451..67aaff3e668 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -458,28 +458,22 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv)
* uevent function for AP devices. It sets up a single environment
* variable DEV_TYPE which contains the hardware device type.
*/
-static int ap_uevent (struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int ap_uevent (struct device *dev, struct kobj_uevent_env *env)
{
struct ap_device *ap_dev = to_ap_dev(dev);
- int retval = 0, length = 0, i = 0;
+ int retval = 0;
if (!ap_dev)
return -ENODEV;
/* Set up DEV_TYPE environment variable. */
- retval = add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEV_TYPE=%04X", ap_dev->device_type);
+ retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
if (retval)
return retval;
/* Add MODALIAS= */
- retval = add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=ap:t%02X", ap_dev->device_type);
+ retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
- envp[i] = NULL;
return retval;
}
@@ -1231,8 +1225,9 @@ static void ap_reset_domain(void)
{
int i;
- for (i = 0; i < AP_DEVICES; i++)
- ap_reset_queue(AP_MKQID(i, ap_domain_index));
+ if (ap_domain_index != -1)
+ for (i = 0; i < AP_DEVICES; i++)
+ ap_reset_queue(AP_MKQID(i, ap_domain_index));
}
static void ap_reset_all(void)
diff --git a/drivers/s390/crypto/zcrypt_mono.c b/drivers/s390/crypto/zcrypt_mono.c
index 2a9349ad68b..44253fdd413 100644
--- a/drivers/s390/crypto/zcrypt_mono.c
+++ b/drivers/s390/crypto/zcrypt_mono.c
@@ -45,7 +45,7 @@
/**
* The module initialization code.
*/
-int __init zcrypt_init(void)
+static int __init zcrypt_init(void)
{
int rc;
@@ -86,7 +86,7 @@ out:
/**
* The module termination code.
*/
-void __exit zcrypt_exit(void)
+static void __exit zcrypt_exit(void)
{
zcrypt_cex2a_exit();
zcrypt_pcixcc_exit();
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index 64948788d30..70b9ddc8cf9 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -277,7 +277,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
};
struct {
struct type6_hdr hdr;
- struct ica_CPRBX cprbx;
+ struct CPRBX cprbx;
} __attribute__((packed)) *msg = ap_msg->message;
int rcblen = CEIL4(xcRB->request_control_blk_length);
@@ -432,14 +432,17 @@ static int convert_type86_ica(struct zcrypt_device *zdev,
}
if (service_rc == 8 && service_rs == 770) {
PDEBUG("Invalid key length on PCIXCC/CEX2C\n");
- zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
- return -EAGAIN;
+ return -EINVAL;
}
if (service_rc == 8 && service_rs == 783) {
PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n");
zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
return -EAGAIN;
}
+ if (service_rc == 12 && service_rs == 769) {
+ PDEBUG("Invalid key on PCIXCC/CEX2C\n");
+ return -EINVAL;
+ }
PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n",
service_rc, service_rs);
zdev->online = 0;
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h
index a78ff307fd1..8cb7d7a6973 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.h
+++ b/drivers/s390/crypto/zcrypt_pcixcc.h
@@ -28,51 +28,6 @@
#ifndef _ZCRYPT_PCIXCC_H_
#define _ZCRYPT_PCIXCC_H_
-/**
- * CPRBX
- * Note that all shorts and ints are big-endian.
- * All pointer fields are 16 bytes long, and mean nothing.
- *
- * A request CPRB is followed by a request_parameter_block.
- *
- * The request (or reply) parameter block is organized thus:
- * function code
- * VUD block
- * key block
- */
-struct CPRBX {
- unsigned short cprb_len; /* CPRB length 220 */
- unsigned char cprb_ver_id; /* CPRB version id. 0x02 */
- unsigned char pad_000[3]; /* Alignment pad bytes */
- unsigned char func_id[2]; /* function id 0x5432 */
- unsigned char cprb_flags[4]; /* Flags */
- unsigned int req_parml; /* request parameter buffer len */
- unsigned int req_datal; /* request data buffer */
- unsigned int rpl_msgbl; /* reply message block length */
- unsigned int rpld_parml; /* replied parameter block len */
- unsigned int rpl_datal; /* reply data block len */
- unsigned int rpld_datal; /* replied data block len */
- unsigned int req_extbl; /* request extension block len */
- unsigned char pad_001[4]; /* reserved */
- unsigned int rpld_extbl; /* replied extension block len */
- unsigned char req_parmb[16]; /* request parm block 'address' */
- unsigned char req_datab[16]; /* request data block 'address' */
- unsigned char rpl_parmb[16]; /* reply parm block 'address' */
- unsigned char rpl_datab[16]; /* reply data block 'address' */
- unsigned char req_extb[16]; /* request extension block 'addr'*/
- unsigned char rpl_extb[16]; /* reply extension block 'addres'*/
- unsigned short ccp_rtcode; /* server return code */
- unsigned short ccp_rscode; /* server reason code */
- unsigned int mac_data_len; /* Mac Data Length */
- unsigned char logon_id[8]; /* Logon Identifier */
- unsigned char mac_value[8]; /* Mac Value */
- unsigned char mac_content_flgs;/* Mac content flag byte */
- unsigned char pad_002; /* Alignment */
- unsigned short domain; /* Domain */
- unsigned char pad_003[12]; /* Domain masks */
- unsigned char pad_004[36]; /* reserved */
-} __attribute__((packed));
-
int zcrypt_pcixcc_init(void);
void zcrypt_pcixcc_exit(void);
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 023455a0b34..3561982749e 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -59,13 +59,13 @@
* 1.15 Changed for 2.6 Kernel No longer compiles on 2.4 or lower
* 1.25 Added Packing support
*/
-#include <asm/bitops.h>
#include <asm/ccwdev.h>
#include <asm/ccwgroup.h>
#include <asm/debug.h>
#include <asm/idals.h>
#include <asm/io.h>
+#include <linux/bitops.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/errno.h>
@@ -3891,7 +3891,6 @@ claw_init_netdevice(struct net_device * dev)
dev->type = ARPHRD_SLIP;
dev->tx_queue_len = 1300;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- SET_MODULE_OWNER(dev);
#ifdef FUNCTRACE
printk(KERN_INFO "%s:%s Exit\n",dev->name,__FUNCTION__);
#endif
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index 92e8a37b502..6bf3ebbe985 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
- * Fixes by : Jochen Röhrig (roehrig@de.ibm.com)
+ * Fixes by : Jochen Röhrig (roehrig@de.ibm.com)
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>
Peter Tiedemann (ptiedem@de.ibm.com)
* Driver Model stuff by : Cornelia Huck <cornelia.huck@de.ibm.com>
@@ -19,7 +19,7 @@
* Dieter Wellerdiek (wel@de.ibm.com)
* Martin Schwidefsky (schwidefsky@de.ibm.com)
* Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- * Jochen Röhrig (roehrig@de.ibm.com)
+ * Jochen Röhrig (roehrig@de.ibm.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -885,7 +885,7 @@ ch_action_firstio(fsm_instance * fi, int event, void *arg)
}
/**
- * Don´t setup a timer for receiving the initial RX frame
+ * Don't setup a timer for receiving the initial RX frame
* if in compatibility mode, since VM TCP delays the initial
* frame until it has some data to send.
*/
@@ -905,10 +905,10 @@ ch_action_firstio(fsm_instance * fi, int event, void *arg)
ccw_check_return_code(ch, rc, "init IO");
}
/**
- * If in compatibility mode since we don´t setup a timer, we
+ * If in compatibility mode since we don't setup a timer, we
* also signal RX channel up immediately. This enables us
* to send packets early which in turn usually triggers some
- * reply from VM TCP which brings up the RX channel to it´s
+ * reply from VM TCP which brings up the RX channel to it's
* final state.
*/
if ((CHANNEL_DIRECTION(ch->flags) == READ) &&
@@ -2823,7 +2823,6 @@ ctc_init_netdevice(struct net_device * dev, int alloc_device,
dev->type = ARPHRD_SLIP;
dev->tx_queue_len = 100;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- SET_MODULE_OWNER(dev);
return dev;
}
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 08a994fdd1a..0fd663b23d7 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1400,11 +1400,14 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n",
cdev->dev.bus_id, dstat, cstat);
if (rc) {
- lcs_schedule_recovery(card);
- wake_up(&card->wait_q);
- return;
+ channel->state = LCS_CH_STATE_ERROR;
}
}
+ if (channel->state == LCS_CH_STATE_ERROR) {
+ lcs_schedule_recovery(card);
+ wake_up(&card->wait_q);
+ return;
+ }
/* How far in the ccw chain have we processed? */
if ((channel->state != LCS_CH_STATE_INIT) &&
(irb->scsw.fctl & SCSW_FCTL_START_FUNC)) {
@@ -1708,6 +1711,8 @@ lcs_stopcard(struct lcs_card *card)
if (card->read.state != LCS_CH_STATE_STOPPED &&
card->write.state != LCS_CH_STATE_STOPPED &&
+ card->read.state != LCS_CH_STATE_ERROR &&
+ card->write.state != LCS_CH_STATE_ERROR &&
card->state == DEV_STATE_UP) {
lcs_clear_multicast_list(card);
rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP);
@@ -2145,7 +2150,6 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
card->dev->stop = lcs_stop_device;
card->dev->hard_start_xmit = lcs_start_xmit;
card->dev->get_stats = lcs_getstats;
- SET_MODULE_OWNER(dev);
memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH);
#ifdef CONFIG_IP_MULTICAST
if (!lcs_check_multicast_support(card))
diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h
index 0e1e4a0a88f..8976fb0b070 100644
--- a/drivers/s390/net/lcs.h
+++ b/drivers/s390/net/lcs.h
@@ -138,6 +138,7 @@ enum lcs_channel_states {
LCS_CH_STATE_RUNNING,
LCS_CH_STATE_SUSPENDED,
LCS_CH_STATE_CLEARED,
+ LCS_CH_STATE_ERROR,
};
/**
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 26888947433..4d18d6419dd 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1904,7 +1904,6 @@ static void netiucv_setup_netdevice(struct net_device *dev)
dev->type = ARPHRD_SLIP;
dev->tx_queue_len = NETIUCV_QUEUELEN_DEFAULT;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- SET_MODULE_OWNER(dev);
}
/**
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index 6d4959807ab..8c6b72d05b1 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -833,8 +833,7 @@ struct qeth_card {
struct qeth_qdio_info qdio;
struct qeth_perf_stats perf_stats;
int use_hard_stop;
- int (*orig_hard_header)(struct sk_buff *,struct net_device *,
- unsigned short,void *,void *,unsigned);
+ const struct header_ops *orig_header_ops;
struct qeth_osn_info osn_info;
atomic_t force_alloc_skb;
};
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 70108fb1690..e3c268cfbff 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -159,13 +159,15 @@ qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue,
buffer = buf->buffer;
/* fill one skb into buffer */
for (i = 0; i < ctx->elements_per_skb; ++i){
- buffer->element[buf->next_element_to_fill].addr =
- ctx->elements[element].addr;
- buffer->element[buf->next_element_to_fill].length =
- ctx->elements[element].length;
- buffer->element[buf->next_element_to_fill].flags =
- ctx->elements[element].flags;
- buf->next_element_to_fill++;
+ if (ctx->elements[element].length != 0) {
+ buffer->element[buf->next_element_to_fill].
+ addr = ctx->elements[element].addr;
+ buffer->element[buf->next_element_to_fill].
+ length = ctx->elements[element].length;
+ buffer->element[buf->next_element_to_fill].
+ flags = ctx->elements[element].flags;
+ buf->next_element_to_fill++;
+ }
element++;
elements--;
}
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index f3e6fbeb212..ff999ff0b62 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -160,6 +160,9 @@ qeth_set_multicast_list(struct net_device *);
static void
qeth_setadp_promisc_mode(struct qeth_card *);
+static int
+qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr);
+
static void
qeth_notify_processes(void)
{
@@ -820,14 +823,15 @@ __qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags)
again:
list_for_each_entry_safe(addr, tmp, &card->ip_list, entry) {
if (addr->is_multicast) {
+ list_del(&addr->entry);
spin_unlock_irqrestore(&card->ip_lock, *flags);
rc = qeth_deregister_addr_entry(card, addr);
spin_lock_irqsave(&card->ip_lock, *flags);
if (!rc) {
- list_del(&addr->entry);
kfree(addr);
goto again;
- }
+ } else
+ list_add(&addr->entry, &card->ip_list);
}
}
}
@@ -2698,10 +2702,15 @@ qeth_process_inbound_buffer(struct qeth_card *card,
qeth_layer2_rebuild_skb(card, skb, hdr);
else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3)
vlan_tag = qeth_rebuild_skb(card, skb, hdr);
- else { /*in case of OSN*/
+ else if (hdr->hdr.osn.id == QETH_HEADER_TYPE_OSN) {
skb_push(skb, sizeof(struct qeth_hdr));
skb_copy_to_linear_data(skb, hdr,
sizeof(struct qeth_hdr));
+ } else { /* unknown header type */
+ dev_kfree_skb_any(skb);
+ QETH_DBF_TEXT(trace, 3, "inbunkno");
+ QETH_DBF_HEX(control, 3, hdr, QETH_DBF_CONTROL_LEN);
+ continue;
}
/* is device UP ? */
if (!(card->dev->flags & IFF_UP)){
@@ -3787,8 +3796,8 @@ qeth_get_netdevice(enum qeth_card_types type, enum qeth_link_types linktype)
/*hard_header fake function; used in case fake_ll is set */
static int
qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, void *daddr, void *saddr,
- unsigned len)
+ unsigned short type, const void *daddr, const void *saddr,
+ unsigned len)
{
if(dev->type == ARPHRD_IEEE802_TR){
struct trh_hdr *hdr;
@@ -3811,6 +3820,11 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
}
}
+static const struct header_ops qeth_fake_ops = {
+ .create = qeth_fake_header,
+ .parse = qeth_hard_header_parse,
+};
+
static int
qeth_send_packet(struct qeth_card *, struct sk_buff *);
@@ -4500,7 +4514,8 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
/* check if we have enough elements (including following
* free buffers) to handle eddp context */
if (qeth_eddp_check_buffers_for_context(queue,ctx) < 0){
- printk("eddp tx_dropped 1\n");
+ if (net_ratelimit())
+ PRINT_WARN("eddp tx_dropped 1\n");
rc = -EBUSY;
goto out;
}
@@ -4649,7 +4664,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
[qeth_get_priority_queue(card, skb, ipv, cast_type)];
if (!card->options.layer2) {
ipv = qeth_get_ip_version(skb);
- if ((card->dev->hard_header == qeth_fake_header) && ipv) {
+ if ((card->dev->header_ops == &qeth_fake_ops) && ipv) {
new_skb = qeth_pskb_unshare(skb, GFP_ATOMIC);
if (!new_skb)
return -ENOMEM;
@@ -4711,8 +4726,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
rc = qeth_do_send_packet(card, queue, new_skb, hdr,
elements_needed, ctx);
else {
- if ((skb->protocol == htons(ETH_P_ARP)) &&
- (card->dev->flags & IFF_NOARP)) {
+ if ((!card->options.layer2) &&
+ (ipv == 0)) {
__qeth_free_new_skb(skb, new_skb);
return -EPERM;
}
@@ -6561,12 +6576,16 @@ static struct ethtool_ops qeth_ethtool_ops = {
};
static int
-qeth_hard_header_parse(struct sk_buff *skb, unsigned char *haddr)
+qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
- struct qeth_card *card;
- struct ethhdr *eth;
+ const struct qeth_card *card;
+ const struct ethhdr *eth;
+ struct net_device *dev = skb->dev;
- card = qeth_get_card_from_dev(skb->dev);
+ if (dev->type != ARPHRD_IEEE802_TR)
+ return 0;
+
+ card = qeth_get_card_from_dev(dev);
if (card->options.layer2)
goto haveheader;
#ifdef CONFIG_QETH_IPV6
@@ -6596,6 +6615,10 @@ haveheader:
return ETH_ALEN;
}
+static const struct header_ops qeth_null_ops = {
+ .parse = qeth_hard_header_parse,
+};
+
static int
qeth_netdev_init(struct net_device *dev)
{
@@ -6620,12 +6643,9 @@ qeth_netdev_init(struct net_device *dev)
dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid;
dev->vlan_rx_add_vid = qeth_vlan_rx_add_vid;
#endif
- if (qeth_get_netdev_flags(card) & IFF_NOARP) {
- dev->rebuild_header = NULL;
- dev->hard_header = NULL;
- dev->header_cache_update = NULL;
- dev->hard_header_cache = NULL;
- }
+ if (qeth_get_netdev_flags(card) & IFF_NOARP)
+ dev->header_ops = &qeth_null_ops;
+
#ifdef CONFIG_QETH_IPV6
/*IPv6 address autoconfiguration stuff*/
if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD))
@@ -6633,11 +6653,8 @@ qeth_netdev_init(struct net_device *dev)
#endif
if (card->options.fake_ll &&
(qeth_get_netdev_flags(card) & IFF_NOARP))
- dev->hard_header = qeth_fake_header;
- if (dev->type == ARPHRD_IEEE802_TR)
- dev->hard_header_parse = NULL;
- else
- dev->hard_header_parse = qeth_hard_header_parse;
+ dev->header_ops = &qeth_fake_ops;
+
dev->set_mac_address = qeth_layer2_set_mac_address;
dev->flags |= qeth_get_netdev_flags(card);
if ((card->options.fake_broadcast) ||
@@ -6649,7 +6666,6 @@ qeth_netdev_init(struct net_device *dev)
dev->mtu = card->info.initial_mtu;
if (card->info.type != QETH_CARD_TYPE_OSN)
SET_ETHTOOL_OPS(dev, &qeth_ethtool_ops);
- SET_MODULE_OWNER(dev);
return 0;
}
@@ -6741,10 +6757,10 @@ retry:
}
/*network device will be recovered*/
if (card->dev) {
- card->dev->hard_header = card->orig_hard_header;
+ card->dev->header_ops = card->orig_header_ops;
if (card->options.fake_ll &&
(qeth_get_netdev_flags(card) & IFF_NOARP))
- card->dev->hard_header = qeth_fake_header;
+ card->dev->header_ops = &qeth_fake_ops;
return 0;
}
/* at first set_online allocate netdev */
@@ -6758,7 +6774,7 @@ retry:
goto out;
}
card->dev->priv = card;
- card->orig_hard_header = card->dev->hard_header;
+ card->orig_header_ops = card->dev->header_ops;
card->dev->type = qeth_get_arphdr_type(card->info.type,
card->info.link_type);
card->dev->init = qeth_netdev_init;
@@ -8309,7 +8325,7 @@ qeth_arp_constructor(struct neighbour *neigh)
if (card == NULL)
goto out;
if((card->options.layer2) ||
- (card->dev->hard_header == qeth_fake_header))
+ (card->dev->header_ops == &qeth_fake_ops))
goto out;
rcu_read_lock();
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index 3ccca5871fd..47bb47b4858 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -148,6 +148,10 @@ static int __init smsg_init(void)
{
int rc;
+ if (!MACHINE_IS_VM) {
+ rc = -EPROTONOSUPPORT;
+ goto out;
+ }
rc = driver_register(&smsg_driver);
if (rc != 0)
goto out;
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 90aa53fc4f3..00118499018 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -559,10 +559,9 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
retval = -ENOMEM;
goto out;
}
+ sg_init_table(sg_list->sg, sg_list->count);
for (i = 0, sg = sg_list->sg; i < sg_list->count; i++, sg++) {
- sg->length = min(size, PAGE_SIZE);
- sg->offset = 0;
address = (void *) get_zeroed_page(GFP_KERNEL);
if (address == NULL) {
sg_list->count = i;
@@ -570,7 +569,7 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
retval = -ENOMEM;
goto out;
}
- zfcp_address_to_sg(address, sg);
+ zfcp_address_to_sg(address, sg, min(size, PAGE_SIZE));
size -= sg->length;
}
@@ -891,7 +890,7 @@ zfcp_unit_dequeue(struct zfcp_unit *unit)
/*
* Allocates a combined QTCB/fsf_req buffer for erp actions and fcp/SCSI
* commands.
- * It also genrates fcp-nameserver request/response buffer and unsolicited
+ * It also genrates fcp-nameserver request/response buffer and unsolicited
* status read fsf_req buffers.
*
* locks: must only be called with zfcp_data.config_sema taken
@@ -982,7 +981,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
struct zfcp_adapter *adapter;
/*
- * Note: It is safe to release the list_lock, as any list changes
+ * Note: It is safe to release the list_lock, as any list changes
* are protected by the config_sema, which must be held to get here
*/
@@ -1038,6 +1037,10 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
spin_lock_init(&adapter->san_dbf_lock);
spin_lock_init(&adapter->scsi_dbf_lock);
+ retval = zfcp_adapter_debug_register(adapter);
+ if (retval)
+ goto debug_register_failed;
+
/* initialize error recovery stuff */
rwlock_init(&adapter->erp_lock);
@@ -1058,7 +1061,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
/* mark adapter unusable as long as sysfs registration is not complete */
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
- adapter->ccw_device = ccw_device;
dev_set_drvdata(&ccw_device->dev, adapter);
if (zfcp_sysfs_adapter_create_files(&ccw_device->dev))
@@ -1085,6 +1087,8 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
generic_services_failed:
zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
sysfs_failed:
+ zfcp_adapter_debug_unregister(adapter);
+ debug_register_failed:
dev_set_drvdata(&ccw_device->dev, NULL);
zfcp_reqlist_free(adapter);
failed_low_mem_buffers:
@@ -1130,6 +1134,8 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
goto out;
}
+ zfcp_adapter_debug_unregister(adapter);
+
/* remove specified adapter data structure from list */
write_lock_irq(&zfcp_data.config_lock);
list_del(&adapter->list);
@@ -1510,13 +1516,13 @@ zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool)
return -ENOMEM;
memset(data, 0, sizeof(*data));
+ sg_init_table(&data->req , 1);
+ sg_init_table(&data->resp , 1);
data->ct.req = &data->req;
data->ct.resp = &data->resp;
data->ct.req_count = data->ct.resp_count = 1;
- zfcp_address_to_sg(&data->ct_iu_req, &data->req);
- zfcp_address_to_sg(&data->ct_iu_resp, &data->resp);
- data->req.length = sizeof(struct ct_iu_gid_pn_req);
- data->resp.length = sizeof(struct ct_iu_gid_pn_resp);
+ zfcp_address_to_sg(&data->ct_iu_req, &data->req, sizeof(struct ct_iu_gid_pn_req));
+ zfcp_address_to_sg(&data->ct_iu_resp, &data->resp, sizeof(struct ct_iu_gid_pn_resp));
*gid_pn = data;
return 0;
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index 1c8f71a5985..e01cbf152a8 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -28,7 +28,7 @@ static void zfcp_ccw_remove(struct ccw_device *);
static int zfcp_ccw_set_online(struct ccw_device *);
static int zfcp_ccw_set_offline(struct ccw_device *);
static int zfcp_ccw_notify(struct ccw_device *, int);
-static void zfcp_ccw_shutdown(struct device *);
+static void zfcp_ccw_shutdown(struct ccw_device *);
static struct ccw_device_id zfcp_ccw_device_id[] = {
{CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
@@ -51,9 +51,7 @@ static struct ccw_driver zfcp_ccw_driver = {
.set_online = zfcp_ccw_set_online,
.set_offline = zfcp_ccw_set_offline,
.notify = zfcp_ccw_notify,
- .driver = {
- .shutdown = zfcp_ccw_shutdown,
- },
+ .shutdown = zfcp_ccw_shutdown,
};
MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
@@ -150,15 +148,12 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
down(&zfcp_data.config_sema);
adapter = dev_get_drvdata(&ccw_device->dev);
- retval = zfcp_adapter_debug_register(adapter);
- if (retval)
- goto out;
retval = zfcp_erp_thread_setup(adapter);
if (retval) {
ZFCP_LOG_INFO("error: start of error recovery thread for "
"adapter %s failed\n",
zfcp_get_busid_by_adapter(adapter));
- goto out_erp_thread;
+ goto out;
}
retval = zfcp_adapter_scsi_register(adapter);
@@ -177,8 +172,6 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
out_scsi_register:
zfcp_erp_thread_kill(adapter);
- out_erp_thread:
- zfcp_adapter_debug_unregister(adapter);
out:
up(&zfcp_data.config_sema);
return retval;
@@ -201,7 +194,6 @@ zfcp_ccw_set_offline(struct ccw_device *ccw_device)
zfcp_erp_adapter_shutdown(adapter, 0);
zfcp_erp_wait(adapter);
zfcp_erp_thread_kill(adapter);
- zfcp_adapter_debug_unregister(adapter);
up(&zfcp_data.config_sema);
return 0;
}
@@ -277,12 +269,12 @@ zfcp_ccw_register(void)
* Makes sure that QDIO queues are down when the system gets stopped.
*/
static void
-zfcp_ccw_shutdown(struct device *dev)
+zfcp_ccw_shutdown(struct ccw_device *cdev)
{
struct zfcp_adapter *adapter;
down(&zfcp_data.config_sema);
- adapter = dev_get_drvdata(dev);
+ adapter = dev_get_drvdata(&cdev->dev);
zfcp_erp_adapter_shutdown(adapter, 0);
zfcp_erp_wait(adapter);
up(&zfcp_data.config_sema);
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 5f3212440f6..ffa3bf75694 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -19,8 +19,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <asm/debug.h>
#include <linux/ctype.h>
+#include <asm/debug.h>
#include "zfcp_ext.h"
static u32 dbfsize = 4;
@@ -35,17 +35,17 @@ static int
zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
{
unsigned long long sec;
- struct timespec xtime;
+ struct timespec dbftime;
int len = 0;
stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
sec = stck >> 12;
do_div(sec, 1000000);
- xtime.tv_sec = sec;
+ dbftime.tv_sec = sec;
stck -= (sec * 1000000) << 12;
- xtime.tv_nsec = ((stck * 1000) >> 12);
+ dbftime.tv_nsec = ((stck * 1000) >> 12);
len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n",
- label, xtime.tv_sec, xtime.tv_nsec);
+ label, dbftime.tv_sec, dbftime.tv_nsec);
return len;
}
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index b36dfc40d9f..e268f79bdbd 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -1,23 +1,23 @@
-/*
+/*
* This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries.
*
* (C) Copyright IBM Corp. 2002, 2006
- *
- * This program is free software; you can redistribute 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.
- */
+ *
+ * This program is free software; you can redistribute 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.
+ */
#ifndef ZFCP_DEF_H
#define ZFCP_DEF_H
@@ -34,6 +34,7 @@
#include <linux/slab.h>
#include <linux/mempool.h>
#include <linux/syscalls.h>
+#include <linux/scatterlist.h>
#include <linux/ioctl.h>
#include <scsi/scsi.h>
#include <scsi/scsi_tcq.h>
@@ -62,19 +63,19 @@
static inline void *
zfcp_sg_to_address(struct scatterlist *list)
{
- return (void *) (page_address(list->page) + list->offset);
+ return sg_virt(list);
}
/**
* zfcp_address_to_sg - set up struct scatterlist from kernel address
* @address: kernel address
* @list: struct scatterlist
+ * @size: buffer size
*/
static inline void
-zfcp_address_to_sg(void *address, struct scatterlist *list)
+zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size)
{
- list->page = virt_to_page(address);
- list->offset = ((unsigned long) address) & (PAGE_SIZE - 1);
+ sg_set_buf(list, address, size);
}
#define REQUEST_LIST_SIZE 128
@@ -90,7 +91,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list)
#define ZFCP_DEVICE_TYPE 0x1732
#define ZFCP_DEVICE_MODEL 0x03
#define ZFCP_DEVICE_MODEL_PRIV 0x04
-
+
/* allow as many chained SBALs as are supported by hardware */
#define ZFCP_MAX_SBALS_PER_REQ FSF_MAX_SBALS_PER_REQ
#define ZFCP_MAX_SBALS_PER_CT_REQ FSF_MAX_SBALS_PER_REQ
@@ -508,7 +509,7 @@ struct zfcp_rc_entry {
/*
* this allows removal of logging code by the preprocessor
- * (the most detailed log level still to be compiled in is specified,
+ * (the most detailed log level still to be compiled in is specified,
* higher log levels are removed)
*/
#define ZFCP_LOG_LEVEL_LIMIT ZFCP_LOG_LEVEL_TRACE
@@ -546,7 +547,7 @@ do { \
if (ZFCP_LOG_CHECK(level)) \
_ZFCP_LOG(fmt, ##args); \
} while (0)
-
+
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL
# define ZFCP_LOG_NORMAL(fmt, args...) do { } while (0)
#else
@@ -583,8 +584,8 @@ do { \
/*************** ADAPTER/PORT/UNIT AND FSF_REQ STATUS FLAGS ******************/
-/*
- * Note, the leftmost status byte is common among adapter, port
+/*
+ * Note, the leftmost status byte is common among adapter, port
* and unit
*/
#define ZFCP_COMMON_FLAGS 0xfff00000
@@ -1007,8 +1008,8 @@ struct zfcp_fsf_req {
u32 fsf_command; /* FSF Command copy */
struct fsf_qtcb *qtcb; /* address of associated QTCB */
u32 seq_no; /* Sequence number of request */
- unsigned long data; /* private data of request */
- struct timer_list timer; /* used for erp or scsi er */
+ unsigned long data; /* private data of request */
+ struct timer_list timer; /* used for erp or scsi er */
struct zfcp_erp_action *erp_action; /* used if this request is
issued on behalf of erp */
mempool_t *pool; /* used if request was alloacted
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index d8cd75ce2d9..5552b755c08 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -1,22 +1,22 @@
-/*
+/*
* This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries.
*
* (C) Copyright IBM Corp. 2002, 2006
- *
- * This program is free software; you can redistribute 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.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_ERP
@@ -54,7 +54,7 @@ static int zfcp_erp_strategy_check_adapter(struct zfcp_adapter *, int);
static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *,
struct zfcp_port *,
struct zfcp_unit *, int);
-static inline int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
+static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *,
struct zfcp_port *,
struct zfcp_unit *, int);
@@ -106,8 +106,8 @@ static void zfcp_erp_action_cleanup(int, struct zfcp_adapter *,
static void zfcp_erp_action_ready(struct zfcp_erp_action *);
static int zfcp_erp_action_exists(struct zfcp_erp_action *);
-static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
-static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *);
+static void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
+static void zfcp_erp_action_to_running(struct zfcp_erp_action *);
static void zfcp_erp_memwait_handler(unsigned long);
@@ -191,7 +191,7 @@ void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
}
/*
- * function:
+ * function:
*
* purpose: called if an adapter failed,
* initiates adapter recovery which is done
@@ -228,7 +228,7 @@ zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: Wrappper for zfcp_erp_adapter_reopen_internal
* used to ensure the correct locking
@@ -308,21 +308,23 @@ zfcp_erp_adisc(struct zfcp_port *port)
if (send_els == NULL)
goto nomem;
- send_els->req = kzalloc(sizeof(struct scatterlist), GFP_ATOMIC);
+ send_els->req = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC);
if (send_els->req == NULL)
goto nomem;
+ sg_init_table(send_els->req, 1);
- send_els->resp = kzalloc(sizeof(struct scatterlist), GFP_ATOMIC);
+ send_els->resp = kmalloc(sizeof(struct scatterlist), GFP_ATOMIC);
if (send_els->resp == NULL)
goto nomem;
+ sg_init_table(send_els->resp, 1);
address = (void *) get_zeroed_page(GFP_ATOMIC);
if (address == NULL)
goto nomem;
- zfcp_address_to_sg(address, send_els->req);
+ zfcp_address_to_sg(address, send_els->req, sizeof(struct zfcp_ls_adisc));
address += PAGE_SIZE >> 1;
- zfcp_address_to_sg(address, send_els->resp);
+ zfcp_address_to_sg(address, send_els->resp, sizeof(struct zfcp_ls_adisc_acc));
send_els->req_count = send_els->resp_count = 1;
send_els->adapter = adapter;
@@ -334,9 +336,6 @@ zfcp_erp_adisc(struct zfcp_port *port)
adisc = zfcp_sg_to_address(send_els->req);
send_els->ls_code = adisc->code = ZFCP_LS_ADISC;
- send_els->req->length = sizeof(struct zfcp_ls_adisc);
- send_els->resp->length = sizeof(struct zfcp_ls_adisc_acc);
-
/* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports
without FC-AL-2 capability, so we don't set it */
adisc->wwpn = fc_host_port_name(adapter->scsi_host);
@@ -363,7 +362,7 @@ zfcp_erp_adisc(struct zfcp_port *port)
retval = -ENOMEM;
freemem:
if (address != NULL)
- __free_pages(send_els->req->page, 0);
+ __free_pages(sg_page(send_els->req), 0);
if (send_els != NULL) {
kfree(send_els->req);
kfree(send_els->resp);
@@ -437,7 +436,7 @@ zfcp_erp_adisc_handler(unsigned long data)
out:
zfcp_port_put(port);
- __free_pages(send_els->req->page, 0);
+ __free_pages(sg_page(send_els->req), 0);
kfree(send_els->req);
kfree(send_els->resp);
kfree(send_els);
@@ -476,7 +475,7 @@ zfcp_test_link(struct zfcp_port *port)
/*
- * function:
+ * function:
*
* purpose: called if a port failed to be opened normally
* initiates Forced Reopen recovery which is done
@@ -517,7 +516,7 @@ zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: Wrappper for zfcp_erp_port_forced_reopen_internal
* used to ensure the correct locking
@@ -543,7 +542,7 @@ zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: called if a port is to be opened
* initiates Reopen recovery which is done
@@ -612,7 +611,7 @@ zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: called if a unit is to be opened
* initiates Reopen recovery which is done
@@ -704,7 +703,7 @@ static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
}
/*
- * function:
+ * function:
*
* purpose: disable I/O,
* return any open requests and clean them up,
@@ -725,7 +724,7 @@ zfcp_erp_port_block(struct zfcp_port *port, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: enable I/O
*
@@ -742,7 +741,7 @@ zfcp_erp_port_unblock(struct zfcp_port *port)
}
/*
- * function:
+ * function:
*
* purpose: disable I/O,
* return any open requests and clean them up,
@@ -763,7 +762,7 @@ zfcp_erp_unit_block(struct zfcp_unit *unit, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: enable I/O
*
@@ -792,7 +791,7 @@ zfcp_erp_action_ready(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
* purpose:
*
@@ -952,7 +951,7 @@ zfcp_erp_memwait_handler(unsigned long data)
* action gets an appropriate flag and will be processed
* accordingly
*/
-void zfcp_erp_timeout_handler(unsigned long data)
+static void zfcp_erp_timeout_handler(unsigned long data)
{
struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data;
struct zfcp_adapter *adapter = erp_action->adapter;
@@ -967,7 +966,7 @@ void zfcp_erp_timeout_handler(unsigned long data)
* zfcp_erp_action_dismiss - dismiss an erp_action
*
* adapter->erp_lock must be held
- *
+ *
* Dismissal of an erp_action is usually required if an erp_action of
* higher priority is generated.
*/
@@ -1005,9 +1004,9 @@ zfcp_erp_thread_setup(struct zfcp_adapter *adapter)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns:
*
@@ -1094,7 +1093,7 @@ zfcp_erp_thread(void *data)
}
/*
- * function:
+ * function:
*
* purpose: drives single error recovery action and schedules higher and
* subordinate actions, if necessary
@@ -1206,7 +1205,7 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
/*
* put this target through the erp mill again if someone has
- * requested to change the status of a target being online
+ * requested to change the status of a target being online
* to offline or the other way around
* (old retval is preserved if nothing has to be done here)
*/
@@ -1228,7 +1227,7 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
unlock:
write_unlock(&adapter->erp_lock);
read_unlock_irqrestore(&zfcp_data.config_lock, flags);
-
+
if (retval != ZFCP_ERP_CONTINUES)
zfcp_erp_action_cleanup(action, adapter, port, unit, retval);
@@ -1250,9 +1249,9 @@ zfcp_erp_strategy(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_DISMISSED - if action has been dismissed
* retval - otherwise
@@ -1322,7 +1321,7 @@ zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
* purpose: triggers retry of this action after a certain amount of time
* by means of timer provided by erp_action
@@ -1346,7 +1345,7 @@ zfcp_erp_strategy_memwait(struct zfcp_erp_action *erp_action)
return retval;
}
-/*
+/*
* function: zfcp_erp_adapter_failed
*
* purpose: sets the adapter and all underlying devices to ERP_FAILED
@@ -1362,7 +1361,7 @@ zfcp_erp_adapter_failed(struct zfcp_adapter *adapter)
debug_text_event(adapter->erp_dbf, 2, "a_afail");
}
-/*
+/*
* function: zfcp_erp_port_failed
*
* purpose: sets the port and all underlying devices to ERP_FAILED
@@ -1386,7 +1385,7 @@ zfcp_erp_port_failed(struct zfcp_port *port)
debug_event(port->adapter->erp_dbf, 2, &port->wwpn, sizeof (wwn_t));
}
-/*
+/*
* function: zfcp_erp_unit_failed
*
* purpose: sets the unit to ERP_FAILED
@@ -1417,7 +1416,7 @@ zfcp_erp_unit_failed(struct zfcp_unit *unit)
* successfully is reset.
*
* returns: ZFCP_ERP_CONTINUES - action continues (not considered)
- * ZFCP_ERP_SUCCEEDED - action finished successfully
+ * ZFCP_ERP_SUCCEEDED - action finished successfully
* ZFCP_ERP_EXIT - action failed and will not continue
*/
static int
@@ -1491,7 +1490,7 @@ zfcp_erp_strategy_statechange(int action,
return retval;
}
-static inline int
+static int
zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status)
{
return
@@ -1646,7 +1645,7 @@ zfcp_erp_schedule_work(struct zfcp_unit *unit)
}
/*
- * function:
+ * function:
*
* purpose: remaining things in good cases,
* escalation in bad cases
@@ -1687,8 +1686,8 @@ zfcp_erp_strategy_followup_actions(int action,
break;
case ZFCP_ERP_ACTION_REOPEN_UNIT:
- if (status == ZFCP_ERP_SUCCEEDED) ; /* no further action */
- else
+ /* Nothing to do if status == ZFCP_ERP_SUCCEEDED */
+ if (status != ZFCP_ERP_SUCCEEDED)
zfcp_erp_port_reopen_internal(unit->port, 0);
break;
}
@@ -1815,7 +1814,7 @@ zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u32 mask, int set_or_clear)
}
/*
- * function:
+ * function:
*
* purpose: Wrappper for zfcp_erp_port_reopen_all_internal
* used to ensure the correct locking
@@ -1852,9 +1851,9 @@ zfcp_erp_port_reopen_all_internal(struct zfcp_adapter *adapter, int clear_mask)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: FIXME
*/
@@ -1871,7 +1870,7 @@ zfcp_erp_unit_reopen_all_internal(struct zfcp_port *port, int clear_mask)
}
/*
- * function:
+ * function:
*
* purpose: this routine executes the 'Reopen Adapter' action
* (the entire action is processed synchronously, since
@@ -1908,9 +1907,9 @@ zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_SUCCEEDED - action finished successfully
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -1930,9 +1929,9 @@ zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_SUCCEEDED - action finished successfully
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -1957,7 +1956,7 @@ zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *erp_action)
* purpose: allocate the irq associated with this devno and register
* the FSF adapter with the SCSI stack
*
- * returns:
+ * returns:
*/
static int
zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close)
@@ -2001,7 +2000,7 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close)
* returns: 0 - successful setup
* !0 - failed setup
*/
-int
+static int
zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
{
int retval;
@@ -2197,7 +2196,7 @@ zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action)
zfcp_erp_action_to_running(erp_action);
write_unlock_irq(&adapter->erp_lock);
- ret = zfcp_fsf_exchange_port_data(erp_action, adapter, NULL);
+ ret = zfcp_fsf_exchange_port_data(erp_action);
if (ret == -EOPNOTSUPP) {
debug_text_event(adapter->erp_dbf, 3, "a_xport_notsupp");
return ZFCP_ERP_SUCCEEDED;
@@ -2249,7 +2248,7 @@ zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action
}
/*
- * function:
+ * function:
*
* purpose: this routine executes the 'Reopen Physical Port' action
*
@@ -2308,7 +2307,7 @@ zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
* purpose: this routine executes the 'Reopen Port' action
*
@@ -2530,7 +2529,7 @@ zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
* purpose: makes the erp thread continue with reopen (physical) port
* actions which have been paused until the name server port
@@ -2570,9 +2569,9 @@ zfcp_erp_port_strategy_open_nameserver_wakeup(struct zfcp_erp_action
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_CONTINUES - action continues (asynchronously)
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -2626,9 +2625,9 @@ zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_CONTINUES - action continues (asynchronously)
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -2663,9 +2662,9 @@ zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_CONTINUES - action continues (asynchronously)
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -2700,9 +2699,9 @@ zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_CONTINUES - action continues (asynchronously)
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -2737,7 +2736,7 @@ zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
* purpose: this routine executes the 'Reopen Unit' action
* currently no retries
@@ -2825,9 +2824,9 @@ zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *unit)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_CONTINUES - action continues (asynchronously)
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -2865,9 +2864,9 @@ zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action)
}
/*
- * function:
+ * function:
*
- * purpose:
+ * purpose:
*
* returns: ZFCP_ERP_CONTINUES - action continues (asynchronously)
* ZFCP_ERP_FAILED - action finished unsuccessfully
@@ -2913,7 +2912,7 @@ void zfcp_erp_start_timer(struct zfcp_fsf_req *fsf_req)
}
/*
- * function:
+ * function:
*
* purpose: enqueue the specified error recovery action, if needed
*
@@ -2992,7 +2991,7 @@ zfcp_erp_action_enqueue(int action,
port->erp_action.action);
debug_text_event(adapter->erp_dbf, 4,
"pf_actenq_drp");
- } else
+ } else
debug_text_event(adapter->erp_dbf, 4,
"pf_actenq_drpcp");
debug_event(adapter->erp_dbf, 4, &port->wwpn,
@@ -3248,8 +3247,7 @@ static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
zfcp_erp_action_dismiss(&unit->erp_action);
}
-static inline void
-zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
@@ -3258,8 +3256,7 @@ zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
}
-static inline void
-zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 991d45667a4..8534cf09546 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -1,22 +1,22 @@
-/*
+/*
* This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries.
*
* (C) Copyright IBM Corp. 2002, 2006
- *
- * This program is free software; you can redistribute 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.
+ *
+ * This program is free software; you can redistribute 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.
*/
#ifndef ZFCP_EXT_H
@@ -82,9 +82,11 @@ extern int zfcp_fsf_open_unit(struct zfcp_erp_action *);
extern int zfcp_fsf_close_unit(struct zfcp_erp_action *);
extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *);
-extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *,
- struct zfcp_adapter *,
- struct fsf_qtcb_bottom_port *);
+extern int zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *,
+ struct fsf_qtcb_bottom_config *);
+extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *);
+extern int zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *,
+ struct fsf_qtcb_bottom_port *);
extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **,
u32, u32, struct zfcp_sg_list *);
extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long);
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 99299976e89..ff866ebd44a 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -80,10 +80,10 @@ static const char zfcp_act_subtable_type[5][8] = {
/*
* function: zfcp_fsf_req_alloc
*
- * purpose: Obtains an fsf_req and potentially a qtcb (for all but
+ * purpose: Obtains an fsf_req and potentially a qtcb (for all but
* unsolicited requests) via helper functions
* Does some initial fsf request set-up.
- *
+ *
* returns: pointer to allocated fsf_req if successfull
* NULL otherwise
*
@@ -192,7 +192,7 @@ void zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
* returns: 0 - success
* !0 - failure
*
- * context:
+ * context:
*/
int
zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
@@ -214,8 +214,8 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
}
/*
- * fsf_req may be deleted due to waking up functions, so
- * cleanup is saved here and used later
+ * fsf_req may be deleted due to waking up functions, so
+ * cleanup is saved here and used later
*/
if (likely(fsf_req->status & ZFCP_STATUS_FSFREQ_CLEANUP))
cleanup = 1;
@@ -259,9 +259,9 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
* and initiates appropriate actions
* (usually calling FSF command specific handlers)
*
- * returns:
+ * returns:
*
- * context:
+ * context:
*
* locks:
*/
@@ -638,7 +638,7 @@ zfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter,
*
* purpose: calls the appropriate command specific handler
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req)
@@ -854,7 +854,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
*
* purpose: is called for finished Open Port command
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
@@ -1088,7 +1088,7 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req)
* returns: address of initiated FSF request
* NULL - request could not be initiated
*
- * FIXME(design): should be watched by a timeout !!!
+ * FIXME(design): should be watched by a timeout !!!
* FIXME(design) shouldn't this be modified to return an int
* also...don't know how though
*/
@@ -1157,7 +1157,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
*
* purpose: is called for finished Abort FCP Command request
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
@@ -1941,25 +1941,28 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
{
volatile struct qdio_buffer_element *sbale;
struct zfcp_fsf_req *fsf_req;
+ struct zfcp_adapter *adapter = erp_action->adapter;
unsigned long lock_flags;
- int retval = 0;
+ int retval;
/* setup new FSF request */
- retval = zfcp_fsf_req_create(erp_action->adapter,
+ retval = zfcp_fsf_req_create(adapter,
FSF_QTCB_EXCHANGE_CONFIG_DATA,
ZFCP_REQ_AUTO_CLEANUP,
- erp_action->adapter->pool.fsf_req_erp,
+ adapter->pool.fsf_req_erp,
&lock_flags, &fsf_req);
- if (retval < 0) {
+ if (retval) {
ZFCP_LOG_INFO("error: Could not create exchange configuration "
"data request for adapter %s.\n",
- zfcp_get_busid_by_adapter(erp_action->adapter));
- goto out;
+ zfcp_get_busid_by_adapter(adapter));
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+ lock_flags);
+ return retval;
}
sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
- sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
- sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
fsf_req->qtcb->bottom.config.feature_selection =
FSF_FEATURE_CFDC |
@@ -1971,23 +1974,71 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
zfcp_erp_start_timer(fsf_req);
retval = zfcp_fsf_req_send(fsf_req);
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+ lock_flags);
if (retval) {
- ZFCP_LOG_INFO
- ("error: Could not send exchange configuration data "
- "command on the adapter %s\n",
- zfcp_get_busid_by_adapter(erp_action->adapter));
+ ZFCP_LOG_INFO("error: Could not send exchange configuration "
+ "data command on the adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
zfcp_fsf_req_free(fsf_req);
erp_action->fsf_req = NULL;
- goto out;
}
+ else
+ ZFCP_LOG_DEBUG("exchange configuration data request initiated "
+ "(adapter %s)\n",
+ zfcp_get_busid_by_adapter(adapter));
- ZFCP_LOG_DEBUG("exchange configuration data request initiated "
- "(adapter %s)\n",
- zfcp_get_busid_by_adapter(erp_action->adapter));
+ return retval;
+}
- out:
- write_unlock_irqrestore(&erp_action->adapter->request_queue.queue_lock,
+int
+zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter,
+ struct fsf_qtcb_bottom_config *data)
+{
+ volatile struct qdio_buffer_element *sbale;
+ struct zfcp_fsf_req *fsf_req;
+ unsigned long lock_flags;
+ int retval;
+
+ /* setup new FSF request */
+ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA,
+ 0, NULL, &lock_flags, &fsf_req);
+ if (retval) {
+ ZFCP_LOG_INFO("error: Could not create exchange configuration "
+ "data request for adapter %s.\n",
+ zfcp_get_busid_by_adapter(adapter));
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
+ lock_flags);
+ return retval;
+ }
+
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+ fsf_req->qtcb->bottom.config.feature_selection =
+ FSF_FEATURE_CFDC |
+ FSF_FEATURE_LUN_SHARING |
+ FSF_FEATURE_NOTIFICATION_LOST |
+ FSF_FEATURE_UPDATE_ALERT;
+
+ if (data)
+ fsf_req->data = (unsigned long) data;
+
+ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+ retval = zfcp_fsf_req_send(fsf_req);
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock,
lock_flags);
+ if (retval)
+ ZFCP_LOG_INFO("error: Could not send exchange configuration "
+ "data command on the adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ else
+ wait_event(fsf_req->completion_wq,
+ fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+
+ zfcp_fsf_req_free(fsf_req);
+
return retval;
}
@@ -2016,11 +2067,17 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
adapter->peer_d_id = 0;
if (xchg_ok) {
+
+ if (fsf_req->data)
+ memcpy((struct fsf_qtcb_bottom_config *) fsf_req->data,
+ bottom, sizeof (struct fsf_qtcb_bottom_config));
+
fc_host_node_name(shost) = bottom->nport_serv_param.wwnn;
fc_host_port_name(shost) = bottom->nport_serv_param.wwpn;
fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK;
fc_host_speed(shost) = bottom->fc_link_speed;
- fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3;
+ fc_host_supported_classes(shost) =
+ FC_COS_CLASS2 | FC_COS_CLASS3;
adapter->hydra_version = bottom->adapter_type;
if (fc_host_permanent_port_name(shost) == -1)
fc_host_permanent_port_name(shost) =
@@ -2053,7 +2110,8 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
min(FC_SERIAL_NUMBER_SIZE, 17));
}
- ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n"
+ ZFCP_LOG_NORMAL("The adapter %s reported the following "
+ "characteristics:\n"
"WWNN 0x%016Lx, "
"WWPN 0x%016Lx, "
"S_ID 0x%06x,\n"
@@ -2090,7 +2148,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
return 0;
}
-/*
+/**
* function: zfcp_fsf_exchange_config_data_handler
*
* purpose: is called for finished Exchange Configuration Data command
@@ -2125,7 +2183,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
adapter->peer_wwpn,
adapter->peer_d_id);
debug_text_event(fsf_req->adapter->erp_dbf, 0,
- "top-p-to-p");
+ "top-p-to-p");
break;
case FC_PORTTYPE_NLPORT:
ZFCP_LOG_NORMAL("error: Arbitrated loop fibrechannel "
@@ -2138,8 +2196,8 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
return -EIO;
case FC_PORTTYPE_NPORT:
ZFCP_LOG_NORMAL("Switched fabric fibrechannel "
- "network detected at adapter %s.\n",
- zfcp_get_busid_by_adapter(adapter));
+ "network detected at adapter %s.\n",
+ zfcp_get_busid_by_adapter(adapter));
break;
default:
ZFCP_LOG_NORMAL("bug: The fibrechannel topology "
@@ -2179,7 +2237,8 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0))
return -EIO;
- atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status);
+ atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
+ &adapter->status);
zfcp_fsf_link_down_info_eval(adapter,
&qtcb->header.fsf_status_qual.link_down_info);
@@ -2187,7 +2246,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
default:
debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng");
debug_event(fsf_req->adapter->erp_dbf, 0,
- &fsf_req->qtcb->header.fsf_status, sizeof (u32));
+ &fsf_req->qtcb->header.fsf_status, sizeof(u32));
zfcp_erp_adapter_shutdown(adapter, 0);
return -EIO;
}
@@ -2197,74 +2256,118 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req)
/**
* zfcp_fsf_exchange_port_data - request information about local port
* @erp_action: ERP action for the adapter for which port data is requested
- * @adapter: for which port data is requested
- * @data: response to exchange port data request
*/
int
-zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
- struct zfcp_adapter *adapter,
- struct fsf_qtcb_bottom_port *data)
+zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action)
{
volatile struct qdio_buffer_element *sbale;
- struct zfcp_fsf_req *fsf_req;
+ struct zfcp_fsf_req *fsf_req;
+ struct zfcp_adapter *adapter = erp_action->adapter;
unsigned long lock_flags;
- int retval = 0;
+ int retval;
if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) {
ZFCP_LOG_INFO("error: exchange port data "
- "command not supported by adapter %s\n",
+ "command not supported by adapter %s\n",
zfcp_get_busid_by_adapter(adapter));
- return -EOPNOTSUPP;
- }
+ return -EOPNOTSUPP;
+ }
/* setup new FSF request */
retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
- erp_action ? ZFCP_REQ_AUTO_CLEANUP : 0,
- NULL, &lock_flags, &fsf_req);
- if (retval < 0) {
+ ZFCP_REQ_AUTO_CLEANUP,
+ adapter->pool.fsf_req_erp,
+ &lock_flags, &fsf_req);
+ if (retval) {
ZFCP_LOG_INFO("error: Out of resources. Could not create an "
- "exchange port data request for"
- "the adapter %s.\n",
+ "exchange port data request for"
+ "the adapter %s.\n",
zfcp_get_busid_by_adapter(adapter));
write_unlock_irqrestore(&adapter->request_queue.queue_lock,
lock_flags);
return retval;
}
- if (data)
- fsf_req->data = (unsigned long) data;
-
sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
- sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
- sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
- if (erp_action) {
- erp_action->fsf_req = fsf_req;
- fsf_req->erp_action = erp_action;
- zfcp_erp_start_timer(fsf_req);
- } else
- zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+ erp_action->fsf_req = fsf_req;
+ fsf_req->erp_action = erp_action;
+ zfcp_erp_start_timer(fsf_req);
retval = zfcp_fsf_req_send(fsf_req);
+ write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
+
if (retval) {
ZFCP_LOG_INFO("error: Could not send an exchange port data "
- "command on the adapter %s\n",
+ "command on the adapter %s\n",
zfcp_get_busid_by_adapter(adapter));
zfcp_fsf_req_free(fsf_req);
- if (erp_action)
- erp_action->fsf_req = NULL;
+ erp_action->fsf_req = NULL;
+ }
+ else
+ ZFCP_LOG_DEBUG("exchange port data request initiated "
+ "(adapter %s)\n",
+ zfcp_get_busid_by_adapter(adapter));
+ return retval;
+}
+
+
+/**
+ * zfcp_fsf_exchange_port_data_sync - request information about local port
+ * and wait until information is ready
+ */
+int
+zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter,
+ struct fsf_qtcb_bottom_port *data)
+{
+ volatile struct qdio_buffer_element *sbale;
+ struct zfcp_fsf_req *fsf_req;
+ unsigned long lock_flags;
+ int retval;
+
+ if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) {
+ ZFCP_LOG_INFO("error: exchange port data "
+ "command not supported by adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ return -EOPNOTSUPP;
+ }
+
+ /* setup new FSF request */
+ retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
+ 0, NULL, &lock_flags, &fsf_req);
+ if (retval) {
+ ZFCP_LOG_INFO("error: Out of resources. Could not create an "
+ "exchange port data request for"
+ "the adapter %s.\n",
+ zfcp_get_busid_by_adapter(adapter));
write_unlock_irqrestore(&adapter->request_queue.queue_lock,
lock_flags);
return retval;
}
+ if (data)
+ fsf_req->data = (unsigned long) data;
+
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
+ sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
+ sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
+
+ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+ retval = zfcp_fsf_req_send(fsf_req);
write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
- if (!erp_action) {
+ if (retval)
+ ZFCP_LOG_INFO("error: Could not send an exchange port data "
+ "command on the adapter %s\n",
+ zfcp_get_busid_by_adapter(adapter));
+ else
wait_event(fsf_req->completion_wq,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
- zfcp_fsf_req_free(fsf_req);
- }
+
+ zfcp_fsf_req_free(fsf_req);
+
return retval;
}
@@ -2277,18 +2380,16 @@ static void
zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
{
struct zfcp_adapter *adapter;
- struct fsf_qtcb *qtcb;
- struct fsf_qtcb_bottom_port *bottom, *data;
+ struct fsf_qtcb_bottom_port *bottom;
struct Scsi_Host *shost;
adapter = fsf_req->adapter;
- qtcb = fsf_req->qtcb;
- bottom = &qtcb->bottom.port;
+ bottom = &fsf_req->qtcb->bottom.port;
shost = adapter->scsi_host;
- data = (struct fsf_qtcb_bottom_port*) fsf_req->data;
- if (data)
- memcpy(data, bottom, sizeof(struct fsf_qtcb_bottom_port));
+ if (fsf_req->data)
+ memcpy((struct fsf_qtcb_bottom_port*) fsf_req->data, bottom,
+ sizeof(struct fsf_qtcb_bottom_port));
if (adapter->connection_features & FSF_FEATURE_NPIV_MODE)
fc_host_permanent_port_name(shost) = bottom->wwpn;
@@ -2336,10 +2437,10 @@ zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req)
/*
* function: zfcp_fsf_open_port
*
- * purpose:
+ * purpose:
*
* returns: address of initiated FSF request
- * NULL - request could not be initiated
+ * NULL - request could not be initiated
*/
int
zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
@@ -2400,7 +2501,7 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
*
* purpose: is called for finished Open Port command
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req)
@@ -3002,7 +3103,7 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
*
* purpose: is called for finished Open LUN command
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
@@ -3265,7 +3366,7 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
* purpose:
*
* returns: address of fsf_req - request successfully initiated
- * NULL -
+ * NULL -
*
* assumptions: This routine does not check whether the associated
* remote port/lun has already been opened. This should be
@@ -3586,17 +3687,17 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
ZFCP_LOG_DEBUG(
"Data did not fit into available buffer(s), "
"waiting for more...\n");
- retval = -EIO;
- } else {
- ZFCP_LOG_NORMAL("error: No truncation implemented but "
- "required. Shutting down unit "
- "(adapter %s, port 0x%016Lx, "
- "unit 0x%016Lx)\n",
- zfcp_get_busid_by_unit(unit),
- unit->port->wwpn,
- unit->fcp_lun);
- zfcp_erp_unit_shutdown(unit, 0);
- retval = -EINVAL;
+ retval = -EIO;
+ } else {
+ ZFCP_LOG_NORMAL("error: No truncation implemented but "
+ "required. Shutting down unit "
+ "(adapter %s, port 0x%016Lx, "
+ "unit 0x%016Lx)\n",
+ zfcp_get_busid_by_unit(unit),
+ unit->port->wwpn,
+ unit->fcp_lun);
+ zfcp_erp_unit_shutdown(unit, 0);
+ retval = -EINVAL;
}
goto no_fit;
}
@@ -3727,7 +3828,7 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
*
* purpose: is called for finished Send FCP Command
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
@@ -3964,7 +4065,7 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req)
*
* purpose: evaluates FCP_RSP IU
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
@@ -4192,7 +4293,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req)
*
* purpose: evaluates FCP_RSP IU
*
- * returns:
+ * returns:
*/
static int
zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req)
@@ -4635,7 +4736,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
INIT_LIST_HEAD(&fsf_req->list);
init_timer(&fsf_req->timer);
- /* initialize waitqueue which may be used to wait on
+ /* initialize waitqueue which may be used to wait on
this request completion */
init_waitqueue_head(&fsf_req->completion_wq);
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
index 71186618947..8cce5cc11d5 100644
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -1,22 +1,22 @@
-/*
+/*
* This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries.
*
* (C) Copyright IBM Corp. 2002, 2006
- *
- * This program is free software; you can redistribute 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.
+ *
+ * This program is free software; you can redistribute 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.
*/
#ifndef FSF_H
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index c6899efdc8f..51d92b196ee 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -174,10 +174,9 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
* That is why we need to clear the link-down flag
* which is set again in case we have missed by a mile.
*/
- zfcp_erp_adapter_reopen(
- adapter,
- ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
- ZFCP_STATUS_COMMON_ERP_FAILED);
+ zfcp_erp_adapter_reopen(adapter,
+ ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
+ ZFCP_STATUS_COMMON_ERP_FAILED);
}
return retval;
}
@@ -591,7 +590,7 @@ zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
*/
int
zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
- struct scatterlist *sg, int sg_count, int max_sbals)
+ struct scatterlist *sgl, int sg_count, int max_sbals)
{
int sg_index;
struct scatterlist *sg_segment;
@@ -607,9 +606,7 @@ zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
sbale->flags |= sbtype;
/* process all segements of scatter-gather list */
- for (sg_index = 0, sg_segment = sg, bytes = 0;
- sg_index < sg_count;
- sg_index++, sg_segment++) {
+ for_each_sg(sgl, sg_segment, sg_count, sg_index) {
retval = zfcp_qdio_sbals_from_segment(
fsf_req,
sbtype,
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index ad7eb4a9261..abae2027f7e 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -1,22 +1,22 @@
-/*
+/*
* This file is part of the zfcp device driver for
* FCP adapters for IBM System z9 and zSeries.
*
* (C) Copyright IBM Corp. 2002, 2006
- *
- * This program is free software; you can redistribute 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.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI
@@ -101,7 +101,7 @@ zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd)
((unsigned char *) fcp_cmd +
sizeof (struct fcp_cmnd_iu) + additional_length);
/*
- * fcp_dl_addr = start address of fcp_cmnd structure +
+ * fcp_dl_addr = start address of fcp_cmnd structure +
* size of fixed part + size of dynamically sized add_dcp_cdb field
* SEE FCP-2 documentation
*/
@@ -189,13 +189,12 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
unit->device = NULL;
zfcp_erp_unit_failed(unit);
zfcp_unit_put(unit);
- } else {
+ } else
ZFCP_LOG_NORMAL("bug: no unit associated with SCSI device at "
"address %p\n", sdpnt);
- }
}
-/*
+/*
* called from scsi midlayer to allow finetuning of a device.
*/
static int
@@ -361,12 +360,11 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id,
list_for_each_entry(port, &adapter->port_list_head, list) {
if (!port->rport || (id != port->rport->scsi_target_id))
continue;
- list_for_each_entry(unit, &port->unit_list_head, list) {
+ list_for_each_entry(unit, &port->unit_list_head, list)
if (lun == unit->scsi_lun) {
retval = unit;
goto out;
}
- }
}
out:
return retval;
@@ -374,7 +372,7 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id,
/**
* zfcp_scsi_eh_abort_handler - abort the specified SCSI command
- * @scpnt: pointer to scsi_cmnd to be aborted
+ * @scpnt: pointer to scsi_cmnd to be aborted
* Return: SUCCESS - command has been aborted and cleaned up in internal
* bookkeeping, SCSI stack won't be called for aborted command
* FAILED - otherwise
@@ -733,7 +731,7 @@ zfcp_get_fc_host_stats(struct Scsi_Host *shost)
if (!data)
return NULL;
- ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
+ ret = zfcp_fsf_exchange_port_data_sync(adapter, data);
if (ret) {
kfree(data);
return NULL; /* XXX return zeroed fc_stats? */
@@ -763,7 +761,7 @@ zfcp_reset_fc_host_stats(struct Scsi_Host *shost)
if (!data)
return;
- ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
+ ret = zfcp_fsf_exchange_port_data_sync(adapter, data);
if (ret) {
kfree(data);
} else {
@@ -802,6 +800,7 @@ struct fc_function_template zfcp_transport_functions = {
.show_host_port_type = 1,
.show_host_speed = 1,
.show_host_port_id = 1,
+ .disable_target_scan = 1,
};
/**
diff --git a/drivers/s390/scsi/zfcp_sysfs_unit.c b/drivers/s390/scsi/zfcp_sysfs_unit.c
index 81a48417586..63f75ee95c3 100644
--- a/drivers/s390/scsi/zfcp_sysfs_unit.c
+++ b/drivers/s390/scsi/zfcp_sysfs_unit.c
@@ -139,7 +139,7 @@ static struct attribute_group zfcp_unit_attr_group = {
.attrs = zfcp_unit_attrs,
};
-/**
+/**
* zfcp_sysfs_create_unit_files - create sysfs unit files
* @dev: pointer to belonging device
*
@@ -151,7 +151,7 @@ zfcp_sysfs_unit_create_files(struct device *dev)
return sysfs_create_group(&dev->kobj, &zfcp_unit_attr_group);
}
-/**
+/**
* zfcp_sysfs_remove_unit_files - remove sysfs unit files
* @dev: pointer to belonging device
*
diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h
index 63941a259b9..f1aa1389ea4 100644
--- a/drivers/sbus/char/vfc.h
+++ b/drivers/sbus/char/vfc.h
@@ -126,7 +126,7 @@ struct vfc_dev {
volatile struct vfc_regs __iomem *regs;
struct vfc_regs *phys_regs;
unsigned int control_reg;
- struct semaphore device_lock_sem;
+ struct mutex device_lock_mtx;
int instance;
int busy;
unsigned long which_io;
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index 9269f7fbd36..d4f8fcded51 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -22,6 +22,7 @@
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/mm.h>
#include <asm/openprom.h>
@@ -54,12 +55,12 @@ static unsigned char saa9051_init_array[VFC_SAA9051_NR] = {
void vfc_lock_device(struct vfc_dev *dev)
{
- down(&dev->device_lock_sem);
+ mutex_lock(&dev->device_lock_mtx);
}
void vfc_unlock_device(struct vfc_dev *dev)
{
- up(&dev->device_lock_sem);
+ mutex_unlock(&dev->device_lock_mtx);
}
@@ -133,7 +134,7 @@ int init_vfc_hw(struct vfc_dev *dev)
int init_vfc_devstruct(struct vfc_dev *dev, int instance)
{
dev->instance=instance;
- init_MUTEX(&dev->device_lock_sem);
+ mutex_init(&dev->device_lock_mtx);
dev->control_reg=0;
dev->busy=0;
return 0;
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index efd9d8d3a89..afb262b4be1 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -1840,7 +1840,7 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
(scsi_bufflen(srb) < TW_MIN_SGL_LENGTH)) {
if (srb->sc_data_direction == DMA_TO_DEVICE || srb->sc_data_direction == DMA_BIDIRECTIONAL) {
struct scatterlist *sg = scsi_sglist(srb);
- char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ char *buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
memcpy(tw_dev->generic_buffer_virt[request_id], buf, sg->length);
kunmap_atomic(buf - sg->offset, KM_IRQ0);
}
@@ -1919,7 +1919,7 @@ static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int re
char *buf;
unsigned long flags = 0;
local_irq_save(flags);
- buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
memcpy(buf, tw_dev->generic_buffer_virt[request_id], sg->length);
kunmap_atomic(buf - sg->offset, KM_IRQ0);
local_irq_restore(flags);
@@ -1990,6 +1990,7 @@ static struct scsi_host_template driver_template = {
.max_sectors = TW_MAX_SECTORS,
.cmd_per_lun = TW_MAX_CMDS_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.shost_attrs = twa_host_attrs,
.emulated = 1
};
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index c7995fc216e..59716ebeb10 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -1469,7 +1469,7 @@ static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id,
struct scatterlist *sg = scsi_sglist(cmd);
local_irq_save(flags);
- buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
transfer_len = min(sg->length, len);
memcpy(buf, data, transfer_len);
@@ -2261,6 +2261,7 @@ static struct scsi_host_template driver_template = {
.max_sectors = TW_MAX_SECTORS,
.cmd_per_lun = TW_MAX_CMDS_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.shost_attrs = tw_host_attrs,
.emulated = 1
};
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 9b206176f71..49e1ffa4b2f 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -3575,6 +3575,7 @@ static struct scsi_host_template Bus_Logic_template = {
.unchecked_isa_dma = 1,
.max_sectors = 128,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
/*
diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c
index a7f916c0c9c..1c9078191d9 100644
--- a/drivers/scsi/FlashPoint.c
+++ b/drivers/scsi/FlashPoint.c
@@ -25,9 +25,6 @@
#define FAILURE 0xFFFFFFFFL
-#define BIT(x) ((unsigned char)(1<<(x))) /* single-bit mask in bit position x */
-#define BITW(x) ((unsigned short)(1<<(x))) /* single-bit mask in bit position x */
-
struct sccb;
typedef void (*CALL_BK_FN) (struct sccb *);
@@ -374,9 +371,9 @@ typedef struct SCCBscam_info {
#define SCAM_ENABLED BIT(2)
#define SCAM_LEVEL2 BIT(3)
-#define RENEGO_ENA BITW(10)
-#define CONNIO_ENA BITW(11)
-#define GREEN_PC_ENA BITW(12)
+#define RENEGO_ENA BIT(10)
+#define CONNIO_ENA BIT(11)
+#define GREEN_PC_ENA BIT(12)
#define AUTO_RATE_00 00
#define AUTO_RATE_05 01
@@ -511,23 +508,23 @@ typedef struct SCCBscam_info {
#define hp_intena 0x40
-#define RESET BITW(7)
-#define PROG_HLT BITW(6)
-#define PARITY BITW(5)
-#define FIFO BITW(4)
-#define SEL BITW(3)
-#define SCAM_SEL BITW(2)
-#define RSEL BITW(1)
-#define TIMEOUT BITW(0)
-#define BUS_FREE BITW(15)
-#define XFER_CNT_0 BITW(14)
-#define PHASE BITW(13)
-#define IUNKWN BITW(12)
-#define ICMD_COMP BITW(11)
-#define ITICKLE BITW(10)
-#define IDO_STRT BITW(9)
-#define ITAR_DISC BITW(8)
-#define AUTO_INT (BITW(12)+BITW(11)+BITW(10)+BITW(9)+BITW(8))
+#define RESET BIT(7)
+#define PROG_HLT BIT(6)
+#define PARITY BIT(5)
+#define FIFO BIT(4)
+#define SEL BIT(3)
+#define SCAM_SEL BIT(2)
+#define RSEL BIT(1)
+#define TIMEOUT BIT(0)
+#define BUS_FREE BIT(15)
+#define XFER_CNT_0 BIT(14)
+#define PHASE BIT(13)
+#define IUNKWN BIT(12)
+#define ICMD_COMP BIT(11)
+#define ITICKLE BIT(10)
+#define IDO_STRT BIT(9)
+#define ITAR_DISC BIT(8)
+#define AUTO_INT (BIT(12)+BIT(11)+BIT(10)+BIT(9)+BIT(8))
#define CLR_ALL_INT 0xFFFF
#define CLR_ALL_INT_1 0xFF00
@@ -674,37 +671,37 @@ typedef struct SCCBscam_info {
#define BIOS_DATA_OFFSET 0x60
#define BIOS_RELATIVE_CARD 0x64
-#define AR3 (BITW(9) + BITW(8))
-#define SDATA BITW(10)
+#define AR3 (BIT(9) + BIT(8))
+#define SDATA BIT(10)
-#define CRD_OP BITW(11) /* Cmp Reg. w/ Data */
+#define CRD_OP BIT(11) /* Cmp Reg. w/ Data */
-#define CRR_OP BITW(12) /* Cmp Reg. w. Reg. */
+#define CRR_OP BIT(12) /* Cmp Reg. w. Reg. */
-#define CPE_OP (BITW(14)+BITW(11)) /* Cmp SCSI phs & Branch EQ */
+#define CPE_OP (BIT(14)+BIT(11)) /* Cmp SCSI phs & Branch EQ */
-#define CPN_OP (BITW(14)+BITW(12)) /* Cmp SCSI phs & Branch NOT EQ */
+#define CPN_OP (BIT(14)+BIT(12)) /* Cmp SCSI phs & Branch NOT EQ */
#define ADATA_OUT 0x00
-#define ADATA_IN BITW(8)
-#define ACOMMAND BITW(10)
-#define ASTATUS (BITW(10)+BITW(8))
-#define AMSG_OUT (BITW(10)+BITW(9))
-#define AMSG_IN (BITW(10)+BITW(9)+BITW(8))
+#define ADATA_IN BIT(8)
+#define ACOMMAND BIT(10)
+#define ASTATUS (BIT(10)+BIT(8))
+#define AMSG_OUT (BIT(10)+BIT(9))
+#define AMSG_IN (BIT(10)+BIT(9)+BIT(8))
-#define BRH_OP BITW(13) /* Branch */
+#define BRH_OP BIT(13) /* Branch */
#define ALWAYS 0x00
-#define EQUAL BITW(8)
-#define NOT_EQ BITW(9)
+#define EQUAL BIT(8)
+#define NOT_EQ BIT(9)
-#define TCB_OP (BITW(13)+BITW(11)) /* Test condition & branch */
+#define TCB_OP (BIT(13)+BIT(11)) /* Test condition & branch */
-#define FIFO_0 BITW(10)
+#define FIFO_0 BIT(10)
-#define MPM_OP BITW(15) /* Match phase and move data */
+#define MPM_OP BIT(15) /* Match phase and move data */
-#define MRR_OP BITW(14) /* Move DReg. to Reg. */
+#define MRR_OP BIT(14) /* Move DReg. to Reg. */
#define S_IDREG (BIT(2)+BIT(1)+BIT(0))
@@ -712,9 +709,9 @@ typedef struct SCCBscam_info {
#define D_AR1 BIT(0)
#define D_BUCKET (BIT(2) + BIT(1) + BIT(0))
-#define RAT_OP (BITW(14)+BITW(13)+BITW(11))
+#define RAT_OP (BIT(14)+BIT(13)+BIT(11))
-#define SSI_OP (BITW(15)+BITW(11))
+#define SSI_OP (BIT(15)+BIT(11))
#define SSI_ITAR_DISC (ITAR_DISC >> 8)
#define SSI_IDO_STRT (IDO_STRT >> 8)
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 6f2c71ef47e..a6676be8784 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -172,12 +172,12 @@ config CHR_DEV_SCH
don't need this for those tiny 6-slot cdrom changers. Media
changers are listed as "Type: Medium Changer" in /proc/scsi/scsi.
If you have such hardware and want to use it with linux, say Y
- here. Check <file:Documentation/scsi-changer.txt> for details.
+ here. Check <file:Documentation/scsi/scsi-changer.txt> for details.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/kbuild/modules.txt> and
- <file:Documentation/scsi.txt>. The module will be called ch.o.
+ <file:Documentation/scsi/scsi.txt>. The module will be called ch.o.
If unsure, say N.
@@ -272,6 +272,13 @@ config SCSI_FC_ATTRS
each attached FiberChannel device to sysfs, say Y.
Otherwise, say N.
+config SCSI_FC_TGT_ATTRS
+ bool "SCSI target support for FiberChannel Transport Attributes"
+ depends on SCSI_FC_ATTRS
+ depends on SCSI_TGT = y || SCSI_TGT = SCSI_FC_ATTRS
+ help
+ If you want to use SCSI target mode drivers enable this option.
+
config SCSI_ISCSI_ATTRS
tristate "iSCSI Transport Attributes"
depends on SCSI && NET
@@ -289,6 +296,20 @@ config SCSI_SAS_ATTRS
source "drivers/scsi/libsas/Kconfig"
+config SCSI_SRP_ATTRS
+ tristate "SRP Transport Attributes"
+ depends on SCSI
+ help
+ If you wish to export transport-specific information about
+ each attached SRP device to sysfs, say Y.
+
+config SCSI_SRP_TGT_ATTRS
+ bool "SCSI target support for SRP Transport Attributes"
+ depends on SCSI_SRP_ATTRS
+ depends on SCSI_TGT = y || SCSI_TGT = SCSI_SRP_ATTRS
+ help
+ If you want to use SCSI target mode drivers enable this option.
+
endmenu
menuconfig SCSI_LOWLEVEL
@@ -500,9 +521,8 @@ config SCSI_DPT_I2O
config SCSI_ADVANSYS
tristate "AdvanSys SCSI support"
- depends on SCSI
+ depends on SCSI && VIRT_TO_BUS
depends on ISA || EISA || PCI
- depends on BROKEN || X86_32
help
This is a driver for all SCSI host adapters manufactured by
AdvanSys. It is documented in the kernel source in
@@ -524,19 +544,32 @@ config SCSI_IN2000
module will be called in2000.
config SCSI_ARCMSR
- tristate "ARECA ARC11X0[PCI-X]/ARC12X0[PCI-EXPRESS] SATA-RAID support"
+ tristate "ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Adapter"
depends on PCI && SCSI
help
- This driver supports all of ARECA's SATA RAID controller cards.
+ This driver supports all of ARECA's SATA/SAS RAID controller cards.
This is an ARECA-maintained driver by Erich Chen.
- If you have any problems, please mail to: < erich@areca.com.tw >
+ If you have any problems, please mail to: <erich@areca.com.tw>.
Areca supports Linux RAID config tools.
-
- < http://www.areca.com.tw >
+ Please link <http://www.areca.com.tw>
To compile this driver as a module, choose M here: the
module will be called arcmsr (modprobe arcmsr).
+config SCSI_ARCMSR_AER
+ bool "Enable PCI Error Recovery Capability in Areca Driver(ARCMSR)"
+ depends on SCSI_ARCMSR && PCIEAER
+ default n
+ help
+ The advanced error reporting(AER) capability is "NOT" provided by
+ ARC1200/1201/1202 SATA RAID controllers cards.
+ If your card is one of ARC1200/1201/1202, please use the default setting, n.
+ If your card is other models, you could pick it
+ on condition that the kernel version is greater than 2.6.19.
+ This function is maintained driver by Nick Cheng. If you have any
+ problems or suggestion, you are welcome to contact with <nick.cheng@areca.com.tw>.
+ To enable this function, choose Y here.
+
source "drivers/scsi/megaraid/Kconfig.megaraid"
config SCSI_HPTIOP
@@ -692,7 +725,7 @@ config SCSI_FD_MCS
config SCSI_GDTH
tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support"
- depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API
+ depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API && PCI_LEGACY
---help---
Formerly called GDT SCSI Disk Array Controller Support.
@@ -836,6 +869,7 @@ config SCSI_IPS
config SCSI_IBMVSCSI
tristate "IBM Virtual SCSI support"
depends on PPC_PSERIES || PPC_ISERIES
+ select SCSI_SRP_ATTRS
help
This is the IBM POWER Virtual SCSI Client
@@ -844,7 +878,7 @@ config SCSI_IBMVSCSI
config SCSI_IBMVSCSIS
tristate "IBM Virtual SCSI Server support"
- depends on PPC_PSERIES && SCSI_TGT && SCSI_SRP
+ depends on PPC_PSERIES && SCSI_SRP && SCSI_SRP_TGT_ATTRS
help
This is the SRP target driver for IBM pSeries virtual environments.
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 86a7ba7bad6..2e6129f13d3 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o
obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/
+obj-$(CONFIG_SCSI_SRP_ATTRS) += scsi_transport_srp.o
obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o
obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
@@ -114,7 +115,6 @@ obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o
obj-$(CONFIG_BLK_DEV_IDESCSI) += ide-scsi.o
obj-$(CONFIG_SCSI_MESH) += mesh.o
obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o
-obj-$(CONFIG_SCSI_PLUTO) += pluto.o
obj-$(CONFIG_SCSI_DECNCR) += NCR53C9x.o dec_esp.o
obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o
obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o
@@ -122,7 +122,6 @@ obj-$(CONFIG_SCSI_PPA) += ppa.o
obj-$(CONFIG_SCSI_IMM) += imm.o
obj-$(CONFIG_JAZZ_ESP) += esp_scsi.o jazz_esp.o
obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o
-obj-$(CONFIG_SCSI_FCAL) += fcal.o
obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o
obj-$(CONFIG_SCSI_SNI_53C710) += 53c700.o sni_53c710.o
obj-$(CONFIG_SCSI_NSP32) += nsp32.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index f8e449a98d2..2597209183d 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -298,8 +298,7 @@ static __inline__ void initialize_SCp(Scsi_Cmnd * cmd)
if (cmd->use_sg) {
cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
- cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
- cmd->SCp.buffer->offset;
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
cmd->SCp.this_residual = cmd->SCp.buffer->length;
} else {
cmd->SCp.buffer = NULL;
@@ -1542,9 +1541,7 @@ part2:
hostdata->connected = cmd;
hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
- if (cmd->SCp.ptr != (char *)cmd->sense_buffer) {
- initialize_SCp(cmd);
- }
+ initialize_SCp(cmd);
return 0;
@@ -2133,7 +2130,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
+ cmd->scsi_done(cmd);
return;
#endif
/*
@@ -2145,8 +2142,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
++cmd->SCp.buffer;
--cmd->SCp.buffers_residual;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
- cmd->SCp.buffer->offset;
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
dprintk(NDEBUG_INFORMATION, ("scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual));
}
/*
@@ -2196,7 +2192,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
+ cmd->scsi_done(cmd);
/* XXX - need to source or sink data here, as appropriate */
} else
cmd->SCp.this_residual -= transfersize - len;
@@ -2280,19 +2276,16 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
#ifdef AUTOSENSE
+ if ((cmd->cmnd[0] == REQUEST_SENSE) &&
+ hostdata->ses.cmd_len) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ hostdata->ses.cmd_len = 0 ;
+ }
+
if ((cmd->cmnd[0] != REQUEST_SENSE) && (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+ scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+
dprintk(NDEBUG_AUTOSENSE, ("scsi%d : performing request sense\n", instance->host_no));
- cmd->cmnd[0] = REQUEST_SENSE;
- cmd->cmnd[1] &= 0xe0;
- cmd->cmnd[2] = 0;
- cmd->cmnd[3] = 0;
- cmd->cmnd[4] = sizeof(cmd->sense_buffer);
- cmd->cmnd[5] = 0;
-
- cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
- cmd->SCp.ptr = (char *) cmd->sense_buffer;
- cmd->SCp.this_residual = sizeof(cmd->sense_buffer);
LIST(cmd, hostdata->issue_queue);
cmd->host_scribble = (unsigned char *)
@@ -2740,7 +2733,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
tmp->host_scribble = NULL;
tmp->result = DID_ABORT << 16;
dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no));
- tmp->done(tmp);
+ tmp->scsi_done(tmp);
return SUCCESS;
}
#if (NDEBUG & NDEBUG_ABORT)
@@ -2805,7 +2798,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
*prev = (Scsi_Cmnd *) tmp->host_scribble;
tmp->host_scribble = NULL;
tmp->result = DID_ABORT << 16;
- tmp->done(tmp);
+ tmp->scsi_done(tmp);
return SUCCESS;
}
}
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index bccf13f7153..bdc468c9e1d 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -30,6 +30,10 @@
#include <linux/interrupt.h>
+#ifdef AUTOSENSE
+#include <scsi/scsi_eh.h>
+#endif
+
#define NCR5380_PUBLIC_RELEASE 7
#define NCR53C400_PUBLIC_RELEASE 2
@@ -281,6 +285,9 @@ struct NCR5380_hostdata {
unsigned pendingr;
unsigned pendingw;
#endif
+#ifdef AUTOSENSE
+ struct scsi_eh_save ses;
+#endif
};
#ifdef __KERNEL__
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 79b4df15814..5b0efc90391 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -927,7 +927,7 @@ static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
esp->dma_mmu_get_scsi_sgl(esp, sp);
else
sp->SCp.ptr =
- (char *) virt_to_phys((page_address(sp->SCp.buffer->page) + sp->SCp.buffer->offset));
+ (char *) virt_to_phys(sg_virt(sp->SCp.buffer));
}
}
@@ -1385,7 +1385,7 @@ int esp_abort(Scsi_Cmnd *SCptr)
this->host_scribble = NULL;
esp_release_dmabufs(esp, this);
this->result = DID_ABORT << 16;
- this->done(this);
+ this->scsi_done(this);
if(don)
esp->dma_ints_on(esp);
return SUCCESS;
@@ -1748,7 +1748,7 @@ static inline void advance_sg(struct NCR_ESP *esp, Scsi_Cmnd *sp)
if (esp->dma_advance_sg)
esp->dma_advance_sg (sp);
else
- sp->SCp.ptr = (char *) virt_to_phys((page_address(sp->SCp.buffer->page) + sp->SCp.buffer->offset));
+ sp->SCp.ptr = (char *) virt_to_phys(sg_virt(sp->SCp.buffer));
}
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index eda8c48f6be..137d065db3d 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -875,8 +875,7 @@ static void NCR53c406a_intr(void *dev_id)
outb(TRANSFER_INFO | DMA_OP, CMD_REG);
#if USE_PIO
scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) {
- NCR53c406a_pio_write(page_address(sg->page) + sg->offset,
- sg->length);
+ NCR53c406a_pio_write(sg_virt(sg), sg->length);
}
REG0;
#endif /* USE_PIO */
@@ -897,8 +896,7 @@ static void NCR53c406a_intr(void *dev_id)
outb(TRANSFER_INFO | DMA_OP, CMD_REG);
#if USE_PIO
scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) {
- NCR53c406a_pio_read(page_address(sg->page) + sg->offset,
- sg->length);
+ NCR53c406a_pio_read(sg_virt(sg), sg->length);
}
REG0;
#endif /* USE_PIO */
@@ -1066,7 +1064,8 @@ static struct scsi_host_template driver_template =
.sg_tablesize = 32 /*SG_ALL*/ /*SG_NONE*/,
.cmd_per_lun = 1 /* commands per lun */,
.unchecked_isa_dma = 1 /* unchecked_isa_dma */,
- .use_clustering = ENABLE_CLUSTERING
+ .use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
#include "scsi_module.c"
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index 3a8089705fe..9e64b21ef63 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -97,7 +97,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mca.h>
-#include <linux/interrupt.h>
#include <asm/io.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
@@ -314,10 +313,10 @@ NCR_D700_probe(struct device *dev)
break;
}
- p = kmalloc(sizeof(*p), GFP_KERNEL);
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
- memset(p, '\0', sizeof(*p));
+
p->dev = dev;
snprintf(p->name, sizeof(p->name), "D700(%s)", dev->bus_id);
if (request_irq(irq, NCR_D700_intr, IRQF_SHARED, p->name, p)) {
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index f608d4a1d6d..d3a6d15fb77 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -1071,6 +1071,7 @@ static struct scsi_host_template inia100_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
static int __devinit inia100_probe_one(struct pci_dev *pdev,
diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c
index 0c758d1452b..d4bda201774 100644
--- a/drivers/scsi/a4000t.c
+++ b/drivers/scsi/a4000t.c
@@ -37,7 +37,7 @@ static struct platform_device *a4000t_scsi_device;
static int __devinit a4000t_probe(struct device *dev)
{
- struct Scsi_Host * host = NULL;
+ struct Scsi_Host *host;
struct NCR_700_Host_Parameters *hostdata;
if (!(MACH_IS_AMIGA && AMIGAHW_PRESENT(A4000_SCSI)))
@@ -47,12 +47,11 @@ static int __devinit a4000t_probe(struct device *dev)
"A4000T builtin SCSI"))
goto out;
- hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
- if (hostdata == NULL) {
+ hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (!hostdata) {
printk(KERN_ERR "a4000t-scsi: Failed to allocate host data\n");
goto out_release;
}
- memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
/* Fill in the required pieces of hostdata */
hostdata->base = (void __iomem *)ZTWO_VADDR(A4000T_SCSI_ADDR);
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 6800e578e4b..a77ab8d693d 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -177,9 +177,9 @@ int check_interval = 24 * 60 * 60;
module_param(check_interval, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health checks.");
-int check_reset = 1;
-module_param(check_reset, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the adapter.");
+int aac_check_reset = 1;
+module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter.");
int expose_physicals = -1;
module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
@@ -356,7 +356,7 @@ static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigne
int transfer_len;
struct scatterlist *sg = scsi_sglist(scsicmd);
- buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
transfer_len = min(sg->length, len + offset);
transfer_len -= offset;
@@ -1305,7 +1305,7 @@ int aac_get_adapter_info(struct aac_dev* dev)
(int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
dev->supplement_adapter_info.VpdInfo.Tsid);
}
- if (!check_reset ||
+ if (!aac_check_reset ||
(dev->supplement_adapter_info.SupportedOptions2 &
le32_to_cpu(AAC_OPTION_IGNORE_RESET))) {
printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 94727b9375e..9abba8b90f7 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -1526,7 +1526,7 @@ struct aac_mntent {
__le32 capacityhigh;
};
-#define FSCS_NOTCLEAN 0x0001 /* fsck is neccessary before mounting */
+#define FSCS_NOTCLEAN 0x0001 /* fsck is necessary before mounting */
#define FSCS_READONLY 0x0002 /* possible result of broken mirror */
#define FSCS_HIDDEN 0x0004 /* should be ignored - set during a clear */
@@ -1871,4 +1871,4 @@ extern int aac_reset_devices;
extern int aac_commit;
extern int update_interval;
extern int check_interval;
-extern int check_reset;
+extern int aac_check_reset;
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index 72b0393b459..1e6d7a9c75b 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -391,7 +391,7 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
/*
* Extract the fibctx from the input parameters
*/
- if (fibctx->unique == (u32)(ptrdiff_t)arg) /* We found a winner */
+ if (fibctx->unique == (u32)(uintptr_t)arg) /* We found a winner */
break;
entry = entry->next;
fibctx = NULL;
@@ -590,7 +590,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
}
addr = (u64)upsg->sg[i].addr[0];
addr += ((u64)upsg->sg[i].addr[1]) << 32;
- sg_user[i] = (void __user *)(ptrdiff_t)addr;
+ sg_user[i] = (void __user *)(uintptr_t)addr;
sg_list[i] = p; // save so we can clean up later
sg_indx = i;
@@ -633,7 +633,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
rcode = -ENOMEM;
goto cleanup;
}
- sg_user[i] = (void __user *)(ptrdiff_t)usg->sg[i].addr;
+ sg_user[i] = (void __user *)(uintptr_t)usg->sg[i].addr;
sg_list[i] = p; // save so we can clean up later
sg_indx = i;
@@ -664,7 +664,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
if (actual_fibsize64 == fibsize) {
struct user_sgmap64* usg = (struct user_sgmap64 *)upsg;
for (i = 0; i < upsg->count; i++) {
- u64 addr;
+ uintptr_t addr;
void* p;
/* Does this really need to be GFP_DMA? */
p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
@@ -676,7 +676,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
}
addr = (u64)usg->sg[i].addr[0];
addr += ((u64)usg->sg[i].addr[1]) << 32;
- sg_user[i] = (void __user *)(ptrdiff_t)addr;
+ sg_user[i] = (void __user *)addr;
sg_list[i] = p; // save so we can clean up later
sg_indx = i;
@@ -704,7 +704,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
rcode = -ENOMEM;
goto cleanup;
}
- sg_user[i] = (void __user *)(ptrdiff_t)upsg->sg[i].addr;
+ sg_user[i] = (void __user *)(uintptr_t)upsg->sg[i].addr;
sg_list[i] = p; // save so we can clean up later
sg_indx = i;
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 3009ad8c407..8736813a029 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -110,7 +110,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
/*
* Align the beginning of Headers to commalign
*/
- align = (commalign - ((ptrdiff_t)(base) & (commalign - 1)));
+ align = (commalign - ((uintptr_t)(base) & (commalign - 1)));
base = base + align;
phys = phys + align;
/*
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index bb870906b4c..240a0bb8986 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1372,8 +1372,9 @@ int aac_check_health(struct aac_dev * aac)
printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
- if (!check_reset || (aac->supplement_adapter_info.SupportedOptions2 &
- le32_to_cpu(AAC_OPTION_IGNORE_RESET)))
+ if (!aac_check_reset ||
+ (aac->supplement_adapter_info.SupportedOptions2 &
+ le32_to_cpu(AAC_OPTION_IGNORE_RESET)))
goto out;
host = aac->scsi_host_ptr;
if (aac->thread->pid != current->pid)
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index fcd25f7d0bc..e6032ffc66a 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -254,7 +254,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
kfree (fib);
return 1;
}
- memcpy(hw_fib, (struct hw_fib *)(((ptrdiff_t)(dev->regs.sa)) +
+ memcpy(hw_fib, (struct hw_fib *)(((uintptr_t)(dev->regs.sa)) +
(index & ~0x00000002L)), sizeof(struct hw_fib));
INIT_LIST_HEAD(&fib->fiblink);
fib->type = FSAFS_NTC_FIB_CONTEXT;
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index a7f42a17b5c..038980be763 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -944,6 +944,7 @@ static struct scsi_host_template aac_driver_template = {
.cmd_per_lun = AAC_NUM_IO_FIB,
#endif
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.emulated = 1,
};
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 79c0b6e37a3..9dd3952516c 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -1,765 +1,27 @@
-#define ASC_VERSION "3.3K" /* AdvanSys Driver Version */
+#define DRV_NAME "advansys"
+#define ASC_VERSION "3.4" /* AdvanSys Driver Version */
/*
* advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
*
* Copyright (c) 1995-2000 Advanced System Products, Inc.
* Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
+ * Copyright (c) 2007 Matthew Wilcox <matthew@wil.cx>
* All Rights Reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that redistributions of source
- * code retain the above copyright notice and this comment without
- * modification.
- *
- * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
- * changed its name to ConnectCom Solutions, Inc.
- *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*/
/*
-
- Documentation for the AdvanSys Driver
-
- A. Linux Kernels Supported by this Driver
- B. Adapters Supported by this Driver
- C. Linux source files modified by AdvanSys Driver
- D. Source Comments
- E. Driver Compile Time Options and Debugging
- F. Driver LILO Option
- G. Tests to run before releasing new driver
- H. Release History
- I. Known Problems/Fix List
- J. Credits (Chronological Order)
-
- A. Linux Kernels Supported by this Driver
-
- This driver has been tested in the following Linux kernels: v2.2.18
- v2.4.0. The driver is supported on v2.2 and v2.4 kernels and on x86,
- alpha, and PowerPC platforms.
-
- B. Adapters Supported by this Driver
-
- AdvanSys (Advanced System Products, Inc.) manufactures the following
- RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow
- (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI
- buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit
- transfer) SCSI Host Adapters for the PCI bus.
-
- The CDB counts below indicate the number of SCSI CDB (Command
- Descriptor Block) requests that can be stored in the RISC chip
- cache and board LRAM. A CDB is a single SCSI command. The driver
- detect routine will display the number of CDBs available for each
- adapter detected. The number of CDBs used by the driver can be
- lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
-
- Laptop Products:
- ABP-480 - Bus-Master CardBus (16 CDB) (2.4 kernel and greater)
-
- Connectivity Products:
- ABP510/5150 - Bus-Master ISA (240 CDB)
- ABP5140 - Bus-Master ISA PnP (16 CDB)
- ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
- ABP902/3902 - Bus-Master PCI (16 CDB)
- ABP3905 - Bus-Master PCI (16 CDB)
- ABP915 - Bus-Master PCI (16 CDB)
- ABP920 - Bus-Master PCI (16 CDB)
- ABP3922 - Bus-Master PCI (16 CDB)
- ABP3925 - Bus-Master PCI (16 CDB)
- ABP930 - Bus-Master PCI (16 CDB)
- ABP930U - Bus-Master PCI Ultra (16 CDB)
- ABP930UA - Bus-Master PCI Ultra (16 CDB)
- ABP960 - Bus-Master PCI MAC/PC (16 CDB)
- ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
-
- Single Channel Products:
- ABP542 - Bus-Master ISA with floppy (240 CDB)
- ABP742 - Bus-Master EISA (240 CDB)
- ABP842 - Bus-Master VL (240 CDB)
- ABP940 - Bus-Master PCI (240 CDB)
- ABP940U - Bus-Master PCI Ultra (240 CDB)
- ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
- ABP970 - Bus-Master PCI MAC/PC (240 CDB)
- ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
- ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB)
- ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
- ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
- ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
-
- Multi-Channel Products:
- ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
- ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
- ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
- ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel)
- ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
- ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
- ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
- ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB)
- ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB)
-
- C. Linux source files modified by AdvanSys Driver
-
- This section for historical purposes documents the changes
- originally made to the Linux kernel source to add the advansys
- driver. As Linux has changed some of these files have also
- been modified.
-
- 1. linux/arch/i386/config.in:
-
- bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y
-
- 2. linux/drivers/scsi/hosts.c:
-
- #ifdef CONFIG_SCSI_ADVANSYS
- #include "advansys.h"
- #endif
-
- and after "static struct scsi_host_template builtin_scsi_hosts[] =":
-
- #ifdef CONFIG_SCSI_ADVANSYS
- ADVANSYS,
- #endif
-
- 3. linux/drivers/scsi/Makefile:
-
- ifdef CONFIG_SCSI_ADVANSYS
- SCSI_SRCS := $(SCSI_SRCS) advansys.c
- SCSI_OBJS := $(SCSI_OBJS) advansys.o
- else
- SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o
- endif
-
- 4. linux/init/main.c:
-
- extern void advansys_setup(char *str, int *ints);
-
- and add the following lines to the bootsetups[] array.
-
- #ifdef CONFIG_SCSI_ADVANSYS
- { "advansys=", advansys_setup },
- #endif
-
- D. Source Comments
-
- 1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
-
- 2. This driver should be maintained in multiple files. But to make
- it easier to include with Linux and to follow Linux conventions,
- the whole driver is maintained in the source files advansys.h and
- advansys.c. In this file logical sections of the driver begin with
- a comment that contains '---'. The following are the logical sections
- of the driver below.
-
- --- Linux Version
- --- Linux Include File
- --- Driver Options
- --- Debugging Header
- --- Asc Library Constants and Macros
- --- Adv Library Constants and Macros
- --- Driver Constants and Macros
- --- Driver Structures
- --- Driver Data
- --- Driver Function Prototypes
- --- Linux 'struct scsi_host_template' and advansys_setup() Functions
- --- Loadable Driver Support
- --- Miscellaneous Driver Functions
- --- Functions Required by the Asc Library
- --- Functions Required by the Adv Library
- --- Tracing and Debugging Functions
- --- Asc Library Functions
- --- Adv Library Functions
-
- 3. The string 'XXX' is used to flag code that needs to be re-written
- or that contains a problem that needs to be addressed.
-
- 4. I have stripped comments from and reformatted the source for the
- Asc Library and Adv Library to reduce the size of this file. This
- source can be found under the following headings. The Asc Library
- is used to support Narrow Boards. The Adv Library is used to
- support Wide Boards.
-
- --- Asc Library Constants and Macros
- --- Adv Library Constants and Macros
- --- Asc Library Functions
- --- Adv Library Functions
-
- E. Driver Compile Time Options and Debugging
-
- In this source file the following constants can be defined. They are
- defined in the source below. Both of these options are enabled by
- default.
-
- 1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled)
-
- Enabling this option adds assertion logic statements to the
- driver. If an assertion fails a message will be displayed to
- the console, but the system will continue to operate. Any
- assertions encountered should be reported to the person
- responsible for the driver. Assertion statements may proactively
- detect problems with the driver and facilitate fixing these
- problems. Enabling assertions will add a small overhead to the
- execution of the driver.
-
- 2. ADVANSYS_DEBUG - Enable driver debugging (Def: Disabled)
-
- Enabling this option adds tracing functions to the driver and
- the ability to set a driver tracing level at boot time. This
- option will also export symbols not required outside the driver to
- the kernel name space. This option is very useful for debugging
- the driver, but it will add to the size of the driver execution
- image and add overhead to the execution of the driver.
-
- The amount of debugging output can be controlled with the global
- variable 'asc_dbglvl'. The higher the number the more output. By
- default the debug level is 0.
-
- If the driver is loaded at boot time and the LILO Driver Option
- is included in the system, the debug level can be changed by
- specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The
- first three hex digits of the pseudo I/O Port must be set to
- 'deb' and the fourth hex digit specifies the debug level: 0 - F.
- The following command line will look for an adapter at 0x330
- and set the debug level to 2.
-
- linux advansys=0x330,0,0,0,0xdeb2
-
- If the driver is built as a loadable module this variable can be
- defined when the driver is loaded. The following insmod command
- will set the debug level to one.
-
- insmod advansys.o asc_dbglvl=1
-
- Debugging Message Levels:
- 0: Errors Only
- 1: High-Level Tracing
- 2-N: Verbose Tracing
-
- To enable debug output to console, please make sure that:
-
- a. System and kernel logging is enabled (syslogd, klogd running).
- b. Kernel messages are routed to console output. Check
- /etc/syslog.conf for an entry similar to this:
-
- kern.* /dev/console
-
- c. klogd is started with the appropriate -c parameter
- (e.g. klogd -c 8)
-
- This will cause printk() messages to be be displayed on the
- current console. Refer to the klogd(8) and syslogd(8) man pages
- for details.
-
- Alternatively you can enable printk() to console with this
- program. However, this is not the 'official' way to do this.
- Debug output is logged in /var/log/messages.
-
- main()
- {
- syscall(103, 7, 0, 0);
- }
-
- Increasing LOG_BUF_LEN in kernel/printk.c to something like
- 40960 allows more debug messages to be buffered in the kernel
- and written to the console or log file.
-
- 3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0)
-
- Enabling this option adds statistics collection and display
- through /proc to the driver. The information is useful for
- monitoring driver and device performance. It will add to the
- size of the driver execution image and add minor overhead to
- the execution of the driver.
-
- Statistics are maintained on a per adapter basis. Driver entry
- point call counts and transfer size counts are maintained.
- Statistics are only available for kernels greater than or equal
- to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured.
-
- AdvanSys SCSI adapter files have the following path name format:
-
- /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
-
- This information can be displayed with cat. For example:
-
- cat /proc/scsi/advansys/0
-
- When ADVANSYS_STATS is not defined the AdvanSys /proc files only
- contain adapter and device configuration information.
-
- F. Driver LILO Option
-
- If init/main.c is modified as described in the 'Directions for Adding
- the AdvanSys Driver to Linux' section (B.4.) above, the driver will
- recognize the 'advansys' LILO command line and /etc/lilo.conf option.
- This option can be used to either disable I/O port scanning or to limit
- scanning to 1 - 4 I/O ports. Regardless of the option setting EISA and
- PCI boards will still be searched for and detected. This option only
- affects searching for ISA and VL boards.
-
- Examples:
- 1. Eliminate I/O port scanning:
- boot: linux advansys=
- or
- boot: linux advansys=0x0
- 2. Limit I/O port scanning to one I/O port:
- boot: linux advansys=0x110
- 3. Limit I/O port scanning to four I/O ports:
- boot: linux advansys=0x110,0x210,0x230,0x330
-
- For a loadable module the same effect can be achieved by setting
- the 'asc_iopflag' variable and 'asc_ioport' array when loading
- the driver, e.g.
-
- insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330
-
- If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1)
- I/O Port may be added to specify the driver debug level. Refer to
- the 'Driver Compile Time Options and Debugging' section above for
- more information.
-
- G. Tests to run before releasing new driver
-
- 1. In the supported kernels verify there are no warning or compile
- errors when the kernel is built as both a driver and as a module
- and with the following options:
-
- ADVANSYS_DEBUG - enabled and disabled
- CONFIG_SMP - enabled and disabled
- CONFIG_PROC_FS - enabled and disabled
-
- 2. Run tests on an x86, alpha, and PowerPC with at least one narrow
- card and one wide card attached to a hard disk and CD-ROM drive:
- fdisk, mkfs, fsck, bonnie, copy/compare test from the
- CD-ROM to the hard drive.
-
- H. Release History
-
- BETA-1.0 (12/23/95):
- First Release
-
- BETA-1.1 (12/28/95):
- 1. Prevent advansys_detect() from being called twice.
- 2. Add LILO 0xdeb[0-f] option to set 'asc_dbglvl'.
-
- 1.2 (1/12/96):
- 1. Prevent re-entrancy in the interrupt handler which
- resulted in the driver hanging Linux.
- 2. Fix problem that prevented ABP-940 cards from being
- recognized on some PCI motherboards.
- 3. Add support for the ABP-5140 PnP ISA card.
- 4. Fix check condition return status.
- 5. Add conditionally compiled code for Linux v1.3.X.
-
- 1.3 (2/23/96):
- 1. Fix problem in advansys_biosparam() that resulted in the
- wrong drive geometry being returned for drives > 1GB with
- extended translation enabled.
- 2. Add additional tracing during device initialization.
- 3. Change code that only applies to ISA PnP adapter.
- 4. Eliminate 'make dep' warning.
- 5. Try to fix problem with handling resets by increasing their
- timeout value.
-
- 1.4 (5/8/96):
- 1. Change definitions to eliminate conflicts with other subsystems.
- 2. Add versioning code for the shared interrupt changes.
- 3. Eliminate problem in asc_rmqueue() with iterating after removing
- a request.
- 4. Remove reset request loop problem from the "Known Problems or
- Issues" section. This problem was isolated and fixed in the
- mid-level SCSI driver.
-
- 1.5 (8/8/96):
- 1. Add support for ABP-940U (PCI Ultra) adapter.
- 2. Add support for IRQ sharing by setting the IRQF_SHARED flag for
- request_irq and supplying a dev_id pointer to both request_irq()
- and free_irq().
- 3. In AscSearchIOPortAddr11() restore a call to check_region() which
- should be used before I/O port probing.
- 4. Fix bug in asc_prt_hex() which resulted in the displaying
- the wrong data.
- 5. Incorporate miscellaneous Asc Library bug fixes and new microcode.
- 6. Change driver versioning to be specific to each Linux sub-level.
- 7. Change statistics gathering to be per adapter instead of global
- to the driver.
- 8. Add more information and statistics to the adapter /proc file:
- /proc/scsi/advansys[0...].
- 9. Remove 'cmd_per_lun' from the "Known Problems or Issues" list.
- This problem has been addressed with the SCSI mid-level changes
- made in v1.3.89. The advansys_select_queue_depths() function
- was added for the v1.3.89 changes.
-
- 1.6 (9/10/96):
- 1. Incorporate miscellaneous Asc Library bug fixes and new microcode.
-
- 1.7 (9/25/96):
- 1. Enable clustering and optimize the setting of the maximum number
- of scatter gather elements for any particular board. Clustering
- increases CPU utilization, but results in a relatively larger
- increase in I/O throughput.
- 2. Improve the performance of the request queuing functions by
- adding a last pointer to the queue structure.
- 3. Correct problems with reset and abort request handling that
- could have hung or crashed Linux.
- 4. Add more information to the adapter /proc file:
- /proc/scsi/advansys[0...].
- 5. Remove the request timeout issue form the driver issues list.
- 6. Miscellaneous documentation additions and changes.
-
- 1.8 (10/4/96):
- 1. Make changes to handle the new v2.1.0 kernel memory mapping
- in which a kernel virtual address may not be equivalent to its
- bus or DMA memory address.
- 2. Change abort and reset request handling to make it yet even
- more robust.
- 3. Try to mitigate request starvation by sending ordered requests
- to heavily loaded, tag queuing enabled devices.
- 4. Maintain statistics on request response time.
- 5. Add request response time statistics and other information to
- the adapter /proc file: /proc/scsi/advansys[0...].
-
- 1.9 (10/21/96):
- 1. Add conditionally compiled code (ASC_QUEUE_FLOW_CONTROL) to
- make use of mid-level SCSI driver device queue depth flow
- control mechanism. This will eliminate aborts caused by a
- device being unable to keep up with requests and eliminate
- repeat busy or QUEUE FULL status returned by a device.
- 2. Incorporate miscellaneous Asc Library bug fixes.
- 3. To allow the driver to work in kernels with broken module
- support set 'cmd_per_lun' if the driver is compiled as a
- module. This change affects kernels v1.3.89 to present.
- 4. Remove PCI BIOS address from the driver banner. The PCI BIOS
- is relocated by the motherboard BIOS and its new address can
- not be determined by the driver.
- 5. Add mid-level SCSI queue depth information to the adapter
- /proc file: /proc/scsi/advansys[0...].
-
- 2.0 (11/14/96):
- 1. Change allocation of global structures used for device
- initialization to guarantee they are in DMA-able memory.
- Previously when the driver was loaded as a module these
- structures might not have been in DMA-able memory, causing
- device initialization to fail.
-
- 2.1 (12/30/96):
- 1. In advansys_reset(), if the request is a synchronous reset
- request, even if the request serial number has changed, then
- complete the request.
- 2. Add Asc Library bug fixes including new microcode.
- 3. Clear inquiry buffer before using it.
- 4. Correct ifdef typo.
-
- 2.2 (1/15/97):
- 1. Add Asc Library bug fixes including new microcode.
- 2. Add synchronous data transfer rate information to the
- adapter /proc file: /proc/scsi/advansys[0...].
- 3. Change ADVANSYS_DEBUG to be disabled by default. This
- will reduce the size of the driver image, eliminate execution
- overhead, and remove unneeded symbols from the kernel symbol
- space that were previously added by the driver.
- 4. Add new compile-time option ADVANSYS_ASSERT for assertion
- code that used to be defined within ADVANSYS_DEBUG. This
- option is enabled by default.
-
- 2.8 (5/26/97):
- 1. Change version number to 2.8 to synchronize the Linux driver
- version numbering with other AdvanSys drivers.
- 2. Reformat source files without tabs to present the same view
- of the file to everyone regardless of the editor tab setting
- being used.
- 3. Add Asc Library bug fixes.
-
- 3.1A (1/8/98):
- 1. Change version number to 3.1 to indicate that support for
- Ultra-Wide adapters (ABP-940UW) is included in this release.
- 2. Add Asc Library (Narrow Board) bug fixes.
- 3. Report an underrun condition with the host status byte set
- to DID_UNDERRUN. Currently DID_UNDERRUN is defined to 0 which
- causes the underrun condition to be ignored. When Linux defines
- its own DID_UNDERRUN the constant defined in this file can be
- removed.
- 4. Add patch to AscWaitTixISRDone().
- 5. Add support for up to 16 different AdvanSys host adapter SCSI
- channels in one system. This allows four cards with four channels
- to be used in one system.
-
- 3.1B (1/9/98):
- 1. Handle that PCI register base addresses are not always page
- aligned even though ioremap() requires that the address argument
- be page aligned.
-
- 3.1C (1/10/98):
- 1. Update latest BIOS version checked for from the /proc file.
- 2. Don't set microcode SDTR variable at initialization. Instead
- wait until device capabilities have been detected from an Inquiry
- command.
-
- 3.1D (1/21/98):
- 1. Improve performance when the driver is compiled as module by
- allowing up to 64 scatter-gather elements instead of 8.
-
- 3.1E (5/1/98):
- 1. Set time delay in AscWaitTixISRDone() to 1000 ms.
- 2. Include SMP locking changes.
- 3. For v2.1.93 and newer kernels use CONFIG_PCI and new PCI BIOS
- access functions.
- 4. Update board serial number printing.
- 5. Try allocating an IRQ both with and without the IRQF_DISABLED
- flag set to allow IRQ sharing with drivers that do not set
- the IRQF_DISABLED flag. Also display a more descriptive error
- message if request_irq() fails.
- 6. Update to latest Asc and Adv Libraries.
-
- 3.2A (7/22/99):
- 1. Update Adv Library to 4.16 which includes support for
- the ASC38C0800 (Ultra2/LVD) IC.
-
- 3.2B (8/23/99):
- 1. Correct PCI compile time option for v2.1.93 and greater
- kernels, advansys_info() string, and debug compile time
- option.
- 2. Correct DvcSleepMilliSecond() for v2.1.0 and greater
- kernels. This caused an LVD detection/BIST problem problem
- among other things.
- 3. Sort PCI cards by PCI Bus, Slot, Function ascending order
- to be consistent with the BIOS.
- 4. Update to Asc Library S121 and Adv Library 5.2.
-
- 3.2C (8/24/99):
- 1. Correct PCI card detection bug introduced in 3.2B that
- prevented PCI cards from being detected in kernels older
- than v2.1.93.
-
- 3.2D (8/26/99):
- 1. Correct /proc device synchronous speed information display.
- Also when re-negotiation is pending for a target device
- note this condition with an * and footnote.
- 2. Correct initialization problem with Ultra-Wide cards that
- have a pre-3.2 BIOS. A microcode variable changed locations
- in 3.2 and greater BIOSes which caused WDTR to be attempted
- erroneously with drives that don't support WDTR.
-
- 3.2E (8/30/99):
- 1. Fix compile error caused by v2.3.13 PCI structure change.
- 2. Remove field from ASCEEP_CONFIG that resulted in an EEPROM
- checksum error for ISA cards.
- 3. Remove ASC_QUEUE_FLOW_CONTROL conditional code. The mid-level
- SCSI changes that it depended on were never included in Linux.
-
- 3.2F (9/3/99):
- 1. Handle new initial function code added in v2.3.16 for all
- driver versions.
-
- 3.2G (9/8/99):
- 1. Fix PCI board detection in v2.3.13 and greater kernels.
- 2. Fix comiple errors in v2.3.X with debugging enabled.
-
- 3.2H (9/13/99):
- 1. Add 64-bit address, long support for Alpha and UltraSPARC.
- The driver has been verified to work on an Alpha system.
- 2. Add partial byte order handling support for Power PC and
- other big-endian platforms. This support has not yet been
- completed or verified.
- 3. For wide boards replace block zeroing of request and
- scatter-gather structures with individual field initialization
- to improve performance.
- 4. Correct and clarify ROM BIOS version detection.
-
- 3.2I (10/8/99):
- 1. Update to Adv Library 5.4.
- 2. Add v2.3.19 underrun reporting to asc_isr_callback() and
- adv_isr_callback(). Remove DID_UNDERRUN constant and other
- no longer needed code that previously documented the lack
- of underrun handling.
-
- 3.2J (10/14/99):
- 1. Eliminate compile errors for v2.0 and earlier kernels.
-
- 3.2K (11/15/99):
- 1. Correct debug compile error in asc_prt_adv_scsi_req_q().
- 2. Update Adv Library to 5.5.
- 3. Add ifdef handling for /proc changes added in v2.3.28.
- 4. Increase Wide board scatter-gather list maximum length to
- 255 when the driver is compiled into the kernel.
-
- 3.2L (11/18/99):
- 1. Fix bug in adv_get_sglist() that caused an assertion failure
- at line 7475. The reqp->sgblkp pointer must be initialized
- to NULL in adv_get_sglist().
-
- 3.2M (11/29/99):
- 1. Really fix bug in adv_get_sglist().
- 2. Incorporate v2.3.29 changes into driver.
-
- 3.2N (4/1/00):
- 1. Add CONFIG_ISA ifdef code.
- 2. Include advansys_interrupts_enabled name change patch.
- 3. For >= v2.3.28 use new SCSI error handling with new function
- advansys_eh_bus_reset(). Don't include an abort function
- because of base library limitations.
- 4. For >= v2.3.28 use per board lock instead of io_request_lock.
- 5. For >= v2.3.28 eliminate advansys_command() and
- advansys_command_done().
- 6. Add some changes for PowerPC (Big Endian) support, but it isn't
- working yet.
- 7. Fix "nonexistent resource free" problem that occurred on a module
- unload for boards with an I/O space >= 255. The 'n_io_port' field
- is only one byte and can not be used to hold an ioport length more
- than 255.
-
- 3.3A (4/4/00):
- 1. Update to Adv Library 5.8.
- 2. For wide cards add support for CDBs up to 16 bytes.
- 3. Eliminate warnings when CONFIG_PROC_FS is not defined.
-
- 3.3B (5/1/00):
- 1. Support for PowerPC (Big Endian) wide cards. Narrow cards
- still need work.
- 2. Change bitfields to shift and mask access for endian
- portability.
-
- 3.3C (10/13/00):
- 1. Update for latest 2.4 kernel.
- 2. Test ABP-480 CardBus support in 2.4 kernel - works!
- 3. Update to Asc Library S123.
- 4. Update to Adv Library 5.12.
-
- 3.3D (11/22/00):
- 1. Update for latest 2.4 kernel.
- 2. Create patches for 2.2 and 2.4 kernels.
-
- 3.3E (1/9/01):
- 1. Now that 2.4 is released remove ifdef code for kernel versions
- less than 2.2. The driver is now only supported in kernels 2.2,
- 2.4, and greater.
- 2. Add code to release and acquire the io_request_lock in
- the driver entrypoint functions: advansys_detect and
- advansys_queuecommand. In kernel 2.4 the SCSI mid-level driver
- still holds the io_request_lock on entry to SCSI low-level drivers.
- This was supposed to be removed before 2.4 was released but never
- happened. When the mid-level SCSI driver is changed all references
- to the io_request_lock should be removed from the driver.
- 3. Simplify error handling by removing advansys_abort(),
- AscAbortSRB(), AscResetDevice(). SCSI bus reset requests are
- now handled by resetting the SCSI bus and fully re-initializing
- the chip. This simple method of error recovery has proven to work
- most reliably after attempts at different methods. Also now only
- support the "new" error handling method and remove the obsolete
- error handling interface.
- 4. Fix debug build errors.
-
- 3.3F (1/24/01):
- 1. Merge with ConnectCom version from Andy Kellner which
- updates Adv Library to 5.14.
- 2. Make PowerPC (Big Endian) work for narrow cards and
- fix problems writing EEPROM for wide cards.
- 3. Remove interrupts_enabled assertion function.
-
- 3.3G (2/16/01):
- 1. Return an error from narrow boards if passed a 16 byte
- CDB. The wide board can already handle 16 byte CDBs.
-
- 3.3GJ (4/15/02):
- 1. hacks for lk 2.5 series (D. Gilbert)
-
- 3.3GJD (10/14/02):
- 1. change select_queue_depths to slave_configure
- 2. make cmd_per_lun be sane again
-
- 3.3K [2004/06/24]:
- 1. continuing cleanup for lk 2.6 series
- 2. Fix problem in lk 2.6.7-bk2 that broke PCI wide cards
- 3. Fix problem that oopsed ISA cards
-
- I. Known Problems/Fix List (XXX)
-
- 1. Need to add memory mapping workaround. Test the memory mapping.
- If it doesn't work revert to I/O port access. Can a test be done
- safely?
- 2. Handle an interrupt not working. Keep an interrupt counter in
- the interrupt handler. In the timeout function if the interrupt
- has not occurred then print a message and run in polled mode.
- 3. Allow bus type scanning order to be changed.
- 4. Need to add support for target mode commands, cf. CAM XPT.
-
- J. Credits (Chronological Order)
-
- Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver
- and maintained it up to 3.3F. He continues to answer questions
- and help maintain the driver.
-
- Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
- basis for the Linux v1.3.X changes which were included in the
- 1.2 release.
-
- Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
- in advansys_biosparam() which was fixed in the 1.3 release.
-
- Erik Ratcliffe <erik@caldera.com> has done testing of the
- AdvanSys driver in the Caldera releases.
-
- Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
- AscWaitTixISRDone() which he found necessary to make the
- driver work with a SCSI-1 disk.
-
- Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
- support in the 3.1A driver.
-
- Doug Gilbert <dgilbert@interlog.com> has made changes and
- suggestions to improve the driver and done a lot of testing.
-
- Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed
- in 3.2K.
-
- Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
- patch and helped with PowerPC wide and narrow board support.
-
- Philip Blundell <philb@gnu.org> provided an
- advansys_interrupts_enabled patch.
-
- Dave Jones <dave@denial.force9.co.uk> reported the compiler
- warnings generated when CONFIG_PROC_FS was not defined in
- the 3.2M driver.
-
- Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian
- problems) for wide cards.
-
- Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow
- card error handling.
-
- Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow
- board support and fixed a bug in AscGetEEPConfig().
-
- Arnaldo Carvalho de Melo <acme@conectiva.com.br> made
- save_flags/restore_flags changes.
-
- Andy Kellner <AKellner@connectcom.net> continues the Advansys SCSI
- driver development for ConnectCom (Version > 3.3F).
-
- K. ConnectCom (AdvanSys) Contact Information
-
- Mail: ConnectCom Solutions, Inc.
- 1150 Ringwood Court
- San Jose, CA 95131
- Operator/Sales: 1-408-383-9400
- FAX: 1-408-383-9612
- Tech Support: 1-408-467-2930
- Tech Support E-Mail: linux@connectcom.net
- FTP Site: ftp.connectcom.net (login: anonymous)
- Web Site: http://www.connectcom.net
-
-*/
-
-/*
- * --- Linux Include Files
+ * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
+ * changed its name to ConnectCom Solutions, Inc.
+ * On June 18, 2001 Initio Corp. acquired ConnectCom's SCSI assets
*/
#include <linux/module.h>
-
-#if defined(CONFIG_X86) && !defined(CONFIG_ISA)
-#define CONFIG_ISA
-#endif /* CONFIG_X86 && !CONFIG_ISA */
-
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -771,7 +33,9 @@
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/blkdev.h>
-#include <linux/stat.h>
+#include <linux/isa.h>
+#include <linux/eisa.h>
+#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
@@ -779,49 +43,38 @@
#include <asm/system.h>
#include <asm/dma.h>
-/* FIXME: (by jejb@steeleye.com) This warning is present for two
- * reasons:
- *
- * 1) This driver badly needs converting to the correct driver model
- * probing API
- *
- * 2) Although all of the necessary command mapping places have the
- * appropriate dma_map.. APIs, the driver still processes its internal
- * queue using bus_to_virt() and virt_to_bus() which are illegal under
- * the API. The entire queue processing structure will need to be
- * altered to fix this.
- */
-#warning this driver is still not properly converted to the DMA API
-
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif /* CONFIG_PCI */
-/*
- * --- Driver Options
+/* FIXME:
+ *
+ * 1. Although all of the necessary command mapping places have the
+ * appropriate dma_map.. APIs, the driver still processes its internal
+ * queue using bus_to_virt() and virt_to_bus() which are illegal under
+ * the API. The entire queue processing structure will need to be
+ * altered to fix this.
+ * 2. Need to add memory mapping workaround. Test the memory mapping.
+ * If it doesn't work revert to I/O port access. Can a test be done
+ * safely?
+ * 3. Handle an interrupt not working. Keep an interrupt counter in
+ * the interrupt handler. In the timeout function if the interrupt
+ * has not occurred then print a message and run in polled mode.
+ * 4. Need to add support for target mode commands, cf. CAM XPT.
+ * 5. check DMA mapping functions for failure
+ * 6. Use scsi_transport_spi
+ * 7. advansys_info is not safe against multiple simultaneous callers
+ * 8. Add module_param to override ISA/VLB ioport array
*/
-
-/* Enable driver assertions. */
-#define ADVANSYS_ASSERT
+#warning this driver is still not properly converted to the DMA API
/* Enable driver /proc statistics. */
#define ADVANSYS_STATS
/* Enable driver tracing. */
-/* #define ADVANSYS_DEBUG */
-
-/*
- * --- Asc Library Constants and Macros
- */
-
-#define ASC_LIB_VERSION_MAJOR 1
-#define ASC_LIB_VERSION_MINOR 24
-#define ASC_LIB_SERIAL_NUMBER 123
+#undef ADVANSYS_DEBUG
/*
* Portable Data Types
@@ -837,17 +90,6 @@
#define ASC_DCNT __u32 /* Unsigned Data count type. */
#define ASC_SDCNT __s32 /* Signed Data count type. */
-/*
- * These macros are used to convert a virtual address to a
- * 32-bit value. This currently can be used on Linux Alpha
- * which uses 64-bit virtual address but a 32-bit bus address.
- * This is likely to break in the future, but doing this now
- * will give us time to change the HW and FW to handle 64-bit
- * addresses.
- */
-#define ASC_VADDR_TO_U32 virt_to_bus
-#define ASC_U32_TO_VADDR bus_to_virt
-
typedef unsigned char uchar;
#ifndef TRUE
@@ -857,29 +99,9 @@ typedef unsigned char uchar;
#define FALSE (0)
#endif
-#define EOF (-1)
#define ERR (-1)
#define UW_ERR (uint)(0xFFFF)
#define isodd_word(val) ((((uint)val) & (uint)0x0001) != 0)
-#define AscPCIConfigVendorIDRegister 0x0000
-#define AscPCIConfigDeviceIDRegister 0x0002
-#define AscPCIConfigCommandRegister 0x0004
-#define AscPCIConfigStatusRegister 0x0006
-#define AscPCIConfigRevisionIDRegister 0x0008
-#define AscPCIConfigCacheSize 0x000C
-#define AscPCIConfigLatencyTimer 0x000D
-#define AscPCIIOBaseRegister 0x0010
-#define AscPCICmdRegBits_IOMemBusMaster 0x0007
-#define ASC_PCI_ID2BUS(id) ((id) & 0xFF)
-#define ASC_PCI_ID2DEV(id) (((id) >> 11) & 0x1F)
-#define ASC_PCI_ID2FUNC(id) (((id) >> 8) & 0x7)
-#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
-#define ASC_PCI_REVISION_3150 0x02
-#define ASC_PCI_REVISION_3050 0x03
-
-#define ASC_DVCLIB_CALL_DONE (1)
-#define ASC_DVCLIB_CALL_FAILED (0)
-#define ASC_DVCLIB_CALL_ERROR (-1)
#define PCI_VENDOR_ID_ASP 0x10cd
#define PCI_DEVICE_ID_ASP_1200A 0x1100
@@ -898,7 +120,7 @@ typedef unsigned char uchar;
#define CC_VERY_LONG_SG_LIST 0
#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
-#define PortAddr unsigned short /* port address size */
+#define PortAddr unsigned int /* port address size */
#define inp(port) inb(port)
#define outp(port, byte) outb((byte), (port))
@@ -918,11 +140,10 @@ typedef unsigned char uchar;
#define ASC_IS_PCMCIA (0x0008)
#define ASC_IS_MCA (0x0020)
#define ASC_IS_VL (0x0040)
-#define ASC_ISA_PNP_PORT_ADDR (0x279)
-#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
#define ASC_IS_WIDESCSI_16 (0x0100)
#define ASC_IS_WIDESCSI_32 (0x0200)
#define ASC_IS_BIG_ENDIAN (0x8000)
+
#define ASC_CHIP_MIN_VER_VL (0x01)
#define ASC_CHIP_MAX_VER_VL (0x07)
#define ASC_CHIP_MIN_VER_PCI (0x09)
@@ -941,16 +162,9 @@ typedef unsigned char uchar;
#define ASC_CHIP_MAX_VER_EISA (0x47)
#define ASC_CHIP_VER_EISA_BIT (0x40)
#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
-#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER 0x21
-#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER 0x0A
-#define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL)
#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL)
-#define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL)
#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL)
-#define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL)
#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
-#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL)
-#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL)
#define ASC_SCSI_ID_BITS 3
#define ASC_SCSI_TIX_TYPE uchar
@@ -961,82 +175,17 @@ typedef unsigned char uchar;
#define ASC_SCSI_WIDTH_BIT_SET 0xFF
#define ASC_MAX_SENSE_LEN 32
#define ASC_MIN_SENSE_LEN 14
-#define ASC_MAX_CDB_LEN 12
#define ASC_SCSI_RESET_HOLD_TIME_US 60
-#define ADV_INQ_CLOCKING_ST_ONLY 0x0
-#define ADV_INQ_CLOCKING_DT_ONLY 0x1
-#define ADV_INQ_CLOCKING_ST_AND_DT 0x3
-
/*
- * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
- * and CmdDt (Command Support Data) field bit definitions.
+ * Narrow boards only support 12-byte commands, while wide boards
+ * extend to 16-byte commands.
*/
-#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3
-#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2
-#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1
-#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0
-
-#define ASC_SCSIDIR_NOCHK 0x00
-#define ASC_SCSIDIR_T2H 0x08
-#define ASC_SCSIDIR_H2T 0x10
-#define ASC_SCSIDIR_NODATA 0x18
-#define SCSI_ASC_NOMEDIA 0x3A
-#define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4))
-#define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F))
-#define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13))
-#define PUT_CDB1(x) ((uchar)((uint)(x) >> 8))
-#define MS_CMD_DONE 0x00
-#define MS_EXTEND 0x01
+#define ASC_MAX_CDB_LEN 12
+#define ADV_MAX_CDB_LEN 16
+
#define MS_SDTR_LEN 0x03
-#define MS_SDTR_CODE 0x01
#define MS_WDTR_LEN 0x02
-#define MS_WDTR_CODE 0x03
-#define MS_MDP_LEN 0x05
-#define MS_MDP_CODE 0x00
-
-/*
- * Inquiry data structure and bitfield macros
- *
- * Only quantities of more than 1 bit are shifted, since the others are
- * just tested for true or false. C bitfields aren't portable between big
- * and little-endian platforms so they are not used.
- */
-
-#define ASC_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f)
-#define ASC_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5)
-#define ASC_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f)
-#define ASC_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80)
-#define ASC_INQ_ANSI_VER(inq) ((inq)->ver & 0x07)
-#define ASC_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3)
-#define ASC_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6)
-#define ASC_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f)
-#define ASC_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40)
-#define ASC_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80)
-#define ASC_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01)
-#define ASC_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02)
-#define ASC_INQ_LINK_CMD(inq) ((inq)->flags & 0x08)
-#define ASC_INQ_SYNC(inq) ((inq)->flags & 0x10)
-#define ASC_INQ_WIDE16(inq) ((inq)->flags & 0x20)
-#define ASC_INQ_WIDE32(inq) ((inq)->flags & 0x40)
-#define ASC_INQ_REL_ADDR(inq) ((inq)->flags & 0x80)
-#define ASC_INQ_INFO_UNIT(inq) ((inq)->info & 0x01)
-#define ASC_INQ_QUICK_ARB(inq) ((inq)->info & 0x02)
-#define ASC_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
-
-typedef struct {
- uchar periph;
- uchar devtype;
- uchar ver;
- uchar byte3;
- uchar add_len;
- uchar res1;
- uchar res2;
- uchar flags;
- uchar vendor_id[8];
- uchar product_id[16];
- uchar product_rev_level[4];
-} ASC_SCSI_INQUIRY;
#define ASC_SG_LIST_PER_Q 7
#define QS_FREE 0x00
@@ -1215,22 +364,9 @@ typedef struct asc_sg_head {
ushort queue_cnt;
ushort entry_to_copy;
ushort res;
- ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
+ ASC_SG_LIST sg_list[0];
} ASC_SG_HEAD;
-#define ASC_MIN_SG_LIST 2
-
-typedef struct asc_min_sg_head {
- ushort entry_cnt;
- ushort queue_cnt;
- ushort entry_to_copy;
- ushort res;
- ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
-} ASC_MIN_SG_HEAD;
-
-#define QCX_SORT (0x0001)
-#define QCX_COALEASE (0x0002)
-
typedef struct asc_scsi_q {
ASC_SCSIQ_1 q1;
ASC_SCSIQ_2 q2;
@@ -1287,45 +423,12 @@ typedef struct asc_risc_sg_list_q {
ASC_SG_LIST sg_list[7];
} ASC_RISC_SG_LIST_Q;
-#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL
-#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024
-#define ASCQ_ERR_NO_ERROR 0
-#define ASCQ_ERR_IO_NOT_FOUND 1
-#define ASCQ_ERR_LOCAL_MEM 2
-#define ASCQ_ERR_CHKSUM 3
-#define ASCQ_ERR_START_CHIP 4
-#define ASCQ_ERR_INT_TARGET_ID 5
-#define ASCQ_ERR_INT_LOCAL_MEM 6
-#define ASCQ_ERR_HALT_RISC 7
-#define ASCQ_ERR_GET_ASPI_ENTRY 8
-#define ASCQ_ERR_CLOSE_ASPI 9
-#define ASCQ_ERR_HOST_INQUIRY 0x0A
-#define ASCQ_ERR_SAVED_SRB_BAD 0x0B
-#define ASCQ_ERR_QCNTL_SG_LIST 0x0C
#define ASCQ_ERR_Q_STATUS 0x0D
-#define ASCQ_ERR_WR_SCSIQ 0x0E
-#define ASCQ_ERR_PC_ADDR 0x0F
-#define ASCQ_ERR_SYN_OFFSET 0x10
-#define ASCQ_ERR_SYN_XFER_TIME 0x11
-#define ASCQ_ERR_LOCK_DMA 0x12
-#define ASCQ_ERR_UNLOCK_DMA 0x13
-#define ASCQ_ERR_VDS_CHK_INSTALL 0x14
-#define ASCQ_ERR_MICRO_CODE_HALT 0x15
-#define ASCQ_ERR_SET_LRAM_ADDR 0x16
#define ASCQ_ERR_CUR_QNG 0x17
#define ASCQ_ERR_SG_Q_LINKS 0x18
-#define ASCQ_ERR_SCSIQ_PTR 0x19
#define ASCQ_ERR_ISR_RE_ENTRY 0x1A
#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B
#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C
-#define ASCQ_ERR_SG_LIST_ODD_ADDRESS 0x1D
-#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
-#define ASCQ_ERR_SCSIQ_NULL_PTR 0x1F
-#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR 0x20
-#define ASCQ_ERR_GET_NUM_OF_FREE_Q 0x21
-#define ASCQ_ERR_SEND_SCSI_Q 0x22
-#define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23
-#define ASCQ_ERR_RESET_SDTR 0x24
/*
* Warning code values are set in ASC_DVC_VAR 'warn_code'.
@@ -1338,84 +441,51 @@ typedef struct asc_risc_sg_list_q {
#define ASC_WARN_CMD_QNG_CONFLICT 0x0010
#define ASC_WARN_EEPROM_RECOVER 0x0020
#define ASC_WARN_CFG_MSW_RECOVER 0x0040
-#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
/*
- * Error code values are set in ASC_DVC_VAR 'err_code'.
+ * Error code values are set in {ASC/ADV}_DVC_VAR 'err_code'.
*/
-#define ASC_IERR_WRITE_EEPROM 0x0001
-#define ASC_IERR_MCODE_CHKSUM 0x0002
-#define ASC_IERR_SET_PC_ADDR 0x0004
-#define ASC_IERR_START_STOP_CHIP 0x0008
-#define ASC_IERR_IRQ_NO 0x0010
-#define ASC_IERR_SET_IRQ_NO 0x0020
-#define ASC_IERR_CHIP_VERSION 0x0040
-#define ASC_IERR_SET_SCSI_ID 0x0080
-#define ASC_IERR_GET_PHY_ADDR 0x0100
-#define ASC_IERR_BAD_SIGNATURE 0x0200
-#define ASC_IERR_NO_BUS_TYPE 0x0400
-#define ASC_IERR_SCAM 0x0800
-#define ASC_IERR_SET_SDTR 0x1000
-#define ASC_IERR_RW_LRAM 0x8000
-
-#define ASC_DEF_IRQ_NO 10
-#define ASC_MAX_IRQ_NO 15
-#define ASC_MIN_IRQ_NO 10
-#define ASC_MIN_REMAIN_Q (0x02)
+#define ASC_IERR_NO_CARRIER 0x0001 /* No more carrier memory */
+#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
+#define ASC_IERR_SET_PC_ADDR 0x0004
+#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
+#define ASC_IERR_ILLEGAL_CONNECTION 0x0010 /* Illegal cable connection */
+#define ASC_IERR_SINGLE_END_DEVICE 0x0020 /* SE device on DIFF bus */
+#define ASC_IERR_REVERSED_CABLE 0x0040 /* Narrow flat cable reversed */
+#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
+#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD device on LVD port */
+#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
+#define ASC_IERR_NO_BUS_TYPE 0x0400
+#define ASC_IERR_BIST_PRE_TEST 0x0800 /* BIST pre-test error */
+#define ASC_IERR_BIST_RAM_TEST 0x1000 /* BIST RAM test error */
+#define ASC_IERR_BAD_CHIPTYPE 0x2000 /* Invalid chip_type setting */
+
#define ASC_DEF_MAX_TOTAL_QNG (0xF0)
#define ASC_MIN_TAG_Q_PER_DVC (0x04)
-#define ASC_DEF_TAG_Q_PER_DVC (0x04)
-#define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q
+#define ASC_MIN_FREE_Q (0x02)
#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
#define ASC_MAX_TOTAL_QNG 240
#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
#define ASC_MAX_INRAM_TAG_QNG 16
-#define ASC_IOADR_TABLE_MAX_IX 11
#define ASC_IOADR_GAP 0x10
-#define ASC_SEARCH_IOP_GAP 0x10
-#define ASC_MIN_IOP_ADDR (PortAddr)0x0100
-#define ASC_MAX_IOP_ADDR (PortAddr)0x3F0
-#define ASC_IOADR_1 (PortAddr)0x0110
-#define ASC_IOADR_2 (PortAddr)0x0130
-#define ASC_IOADR_3 (PortAddr)0x0150
-#define ASC_IOADR_4 (PortAddr)0x0190
-#define ASC_IOADR_5 (PortAddr)0x0210
-#define ASC_IOADR_6 (PortAddr)0x0230
-#define ASC_IOADR_7 (PortAddr)0x0250
-#define ASC_IOADR_8 (PortAddr)0x0330
-#define ASC_IOADR_DEF ASC_IOADR_8
-#define ASC_LIB_SCSIQ_WK_SP 256
-#define ASC_MAX_SYN_XFER_NO 16
#define ASC_SYN_MAX_OFFSET 0x0F
#define ASC_DEF_SDTR_OFFSET 0x0F
-#define ASC_DEF_SDTR_INDEX 0x00
#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02
-#define SYN_XFER_NS_0 25
-#define SYN_XFER_NS_1 30
-#define SYN_XFER_NS_2 35
-#define SYN_XFER_NS_3 40
-#define SYN_XFER_NS_4 50
-#define SYN_XFER_NS_5 60
-#define SYN_XFER_NS_6 70
-#define SYN_XFER_NS_7 85
-#define SYN_ULTRA_XFER_NS_0 12
-#define SYN_ULTRA_XFER_NS_1 19
-#define SYN_ULTRA_XFER_NS_2 25
-#define SYN_ULTRA_XFER_NS_3 32
-#define SYN_ULTRA_XFER_NS_4 38
-#define SYN_ULTRA_XFER_NS_5 44
-#define SYN_ULTRA_XFER_NS_6 50
-#define SYN_ULTRA_XFER_NS_7 57
-#define SYN_ULTRA_XFER_NS_8 63
-#define SYN_ULTRA_XFER_NS_9 69
-#define SYN_ULTRA_XFER_NS_10 75
-#define SYN_ULTRA_XFER_NS_11 82
-#define SYN_ULTRA_XFER_NS_12 88
-#define SYN_ULTRA_XFER_NS_13 94
-#define SYN_ULTRA_XFER_NS_14 100
-#define SYN_ULTRA_XFER_NS_15 107
+#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
+
+/* The narrow chip only supports a limited selection of transfer rates.
+ * These are encoded in the range 0..7 or 0..15 depending whether the chip
+ * is Ultra-capable or not. These tables let us convert from one to the other.
+ */
+static const unsigned char asc_syn_xfer_period[8] = {
+ 25, 30, 35, 40, 50, 60, 70, 85
+};
+
+static const unsigned char asc_syn_ultra_xfer_period[16] = {
+ 12, 19, 25, 32, 38, 44, 50, 57, 63, 69, 75, 82, 88, 94, 100, 107
+};
typedef struct ext_msg {
uchar msg_type;
@@ -1456,22 +526,16 @@ typedef struct asc_dvc_cfg {
uchar isa_dma_speed;
uchar isa_dma_channel;
uchar chip_version;
- ushort lib_serial_no;
- ushort lib_version;
ushort mcode_date;
ushort mcode_version;
uchar max_tag_qng[ASC_MAX_TID + 1];
- uchar *overrun_buf;
uchar sdtr_period_offset[ASC_MAX_TID + 1];
- ushort pci_slot_info;
uchar adapter_info[6];
- struct device *dev;
} ASC_DVC_CFG;
#define ASC_DEF_DVC_CNTL 0xFFFF
#define ASC_DEF_CHIP_SCSI_ID 7
#define ASC_DEF_ISA_DMA_SPEED 4
-#define ASC_INIT_STATE_NULL 0x0000
#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
#define ASC_INIT_STATE_END_GET_CFG 0x0002
#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
@@ -1484,43 +548,39 @@ typedef struct asc_dvc_cfg {
#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
-#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
#define ASC_MIN_TAGGED_CMD 7
#define ASC_MAX_SCSI_RESET_WAIT 30
+#define ASC_OVERRUN_BSIZE 64
struct asc_dvc_var; /* Forward Declaration. */
-typedef void (*ASC_ISR_CALLBACK) (struct asc_dvc_var *, ASC_QDONE_INFO *);
-typedef int (*ASC_EXE_CALLBACK) (struct asc_dvc_var *, ASC_SCSI_Q *);
-
typedef struct asc_dvc_var {
PortAddr iop_base;
ushort err_code;
ushort dvc_cntl;
ushort bug_fix_cntl;
ushort bus_type;
- ASC_ISR_CALLBACK isr_callback;
- ASC_EXE_CALLBACK exe_callback;
ASC_SCSI_BIT_ID_TYPE init_sdtr;
ASC_SCSI_BIT_ID_TYPE sdtr_done;
ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
ASC_SCSI_BIT_ID_TYPE unit_not_ready;
ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
ASC_SCSI_BIT_ID_TYPE start_motor;
+ uchar overrun_buf[ASC_OVERRUN_BSIZE] __aligned(8);
+ dma_addr_t overrun_dma;
uchar scsi_reset_wait;
uchar chip_no;
char is_in_int;
uchar max_total_qng;
uchar cur_total_qng;
uchar in_critical_cnt;
- uchar irq_no;
uchar last_q_shortage;
ushort init_state;
uchar cur_dvc_qng[ASC_MAX_TID + 1];
uchar max_dvc_qng[ASC_MAX_TID + 1];
ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
- uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
+ const uchar *sdtr_period_tbl;
ASC_DVC_CFG *cfg;
ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
char redo_scam;
@@ -1529,9 +589,11 @@ typedef struct asc_dvc_var {
ASC_DCNT max_dma_count;
ASC_SCSI_BIT_ID_TYPE no_scam;
ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
+ uchar min_sdtr_index;
uchar max_sdtr_index;
- uchar host_init_sdtr_index;
struct asc_board *drv_ptr;
+ int ptr_map_count;
+ void **ptr_map;
ASC_DCNT uc_break;
} ASC_DVC_VAR;
@@ -1568,12 +630,7 @@ typedef struct asc_cap_info_array {
#define ASC_EEP_MAX_DVC_ADDR_VL 15
#define ASC_EEP_DVC_CFG_BEG 32
#define ASC_EEP_MAX_DVC_ADDR 45
-#define ASC_EEP_DEFINED_WORDS 10
-#define ASC_EEP_MAX_ADDR 63
-#define ASC_EEP_RES_WORDS 0
#define ASC_EEP_MAX_RETRY 20
-#define ASC_MAX_INIT_BUSY_RETRY 8
-#define ASC_EEP_ISA_PNP_WSIZE 16
/*
* These macros keep the chip SCSI id and ISA DMA speed
@@ -1609,17 +666,10 @@ typedef struct asceep_config {
ushort chksum;
} ASCEEP_CONFIG;
-#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800
-#define ASC_PCI_CFG_LSW_BURST_MODE 0x0080
-#define ASC_PCI_CFG_LSW_INTR_ABLE 0x0020
-
#define ASC_EEP_CMD_READ 0x80
#define ASC_EEP_CMD_WRITE 0x40
#define ASC_EEP_CMD_WRITE_ABLE 0x30
#define ASC_EEP_CMD_WRITE_DISABLE 0x00
-#define ASC_OVERRUN_BSIZE 0x00000048UL
-#define ASC_CTRL_BREAK_ONCE 0x0001
-#define ASC_CTRL_BREAK_STAY_IDLE 0x0002
#define ASCV_MSGOUT_BEG 0x0000
#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
@@ -1796,16 +846,9 @@ typedef struct asceep_config {
#define ASC_1000_ID0W 0x04C1
#define ASC_1000_ID0W_FIX 0x00C1
#define ASC_1000_ID1B 0x25
-#define ASC_EISA_BIG_IOP_GAP (0x1C30-0x0C50)
-#define ASC_EISA_SMALL_IOP_GAP (0x0020)
-#define ASC_EISA_MIN_IOP_ADDR (0x0C30)
-#define ASC_EISA_MAX_IOP_ADDR (0xFC50)
#define ASC_EISA_REV_IOP_MASK (0x0C83)
-#define ASC_EISA_PID_IOP_MASK (0x0C80)
#define ASC_EISA_CFG_IOP_MASK (0x0C86)
#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
-#define ASC_EISA_ID_740 0x01745004UL
-#define ASC_EISA_ID_750 0x01755004UL
#define INS_HALTINT (ushort)0x6281
#define INS_HALT (ushort)0x6280
#define INS_SINT (ushort)0x6200
@@ -1828,11 +871,10 @@ typedef struct asc_mc_saved {
#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
-#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
-#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
-#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
-#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
-#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
+#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data))
+#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id))
+#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data)
+#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id))
#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
@@ -1887,125 +929,6 @@ typedef struct asc_mc_saved {
#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
-static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
-static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
-static void AscWaitEEPRead(void);
-static void AscWaitEEPWrite(void);
-static ushort AscReadEEPWord(PortAddr, uchar);
-static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
-static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
-static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
-static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
-static int AscStartChip(PortAddr);
-static int AscStopChip(PortAddr);
-static void AscSetChipIH(PortAddr, ushort);
-static int AscIsChipHalted(PortAddr);
-static void AscAckInterrupt(PortAddr);
-static void AscDisableInterrupt(PortAddr);
-static void AscEnableInterrupt(PortAddr);
-static void AscSetBank(PortAddr, uchar);
-static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
-#ifdef CONFIG_ISA
-static ushort AscGetIsaDmaChannel(PortAddr);
-static ushort AscSetIsaDmaChannel(PortAddr, ushort);
-static uchar AscSetIsaDmaSpeed(PortAddr, uchar);
-static uchar AscGetIsaDmaSpeed(PortAddr);
-#endif /* CONFIG_ISA */
-static uchar AscReadLramByte(PortAddr, ushort);
-static ushort AscReadLramWord(PortAddr, ushort);
-#if CC_VERY_LONG_SG_LIST
-static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
-#endif /* CC_VERY_LONG_SG_LIST */
-static void AscWriteLramWord(PortAddr, ushort, ushort);
-static void AscWriteLramByte(PortAddr, ushort, uchar);
-static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
-static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
-static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
-static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
-static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
-static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
-static ushort AscInitFromEEP(ASC_DVC_VAR *);
-static ushort AscInitFromAscDvcVar(ASC_DVC_VAR *);
-static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
-static int AscTestExternalLram(ASC_DVC_VAR *);
-static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
-static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
-static void AscSetChipSDTR(PortAddr, uchar, uchar);
-static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
-static uchar AscAllocFreeQueue(PortAddr, uchar);
-static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
-static int AscHostReqRiscHalt(PortAddr);
-static int AscStopQueueExe(PortAddr);
-static int AscSendScsiQueue(ASC_DVC_VAR *,
- ASC_SCSI_Q *scsiq, uchar n_q_required);
-static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
-static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
-static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
-static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
-static ushort AscInitLram(ASC_DVC_VAR *);
-static ushort AscInitQLinkVar(ASC_DVC_VAR *);
-static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
-static int AscIsrChipHalted(ASC_DVC_VAR *);
-static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
- ASC_QDONE_INFO *, ASC_DCNT);
-static int AscIsrQDone(ASC_DVC_VAR *);
-static int AscCompareString(uchar *, uchar *, int);
-#ifdef CONFIG_ISA
-static ushort AscGetEisaChipCfg(PortAddr);
-static ASC_DCNT AscGetEisaProductID(PortAddr);
-static PortAddr AscSearchIOPortAddrEISA(PortAddr);
-static PortAddr AscSearchIOPortAddr11(PortAddr);
-static PortAddr AscSearchIOPortAddr(PortAddr, ushort);
-static void AscSetISAPNPWaitForKey(void);
-#endif /* CONFIG_ISA */
-static uchar AscGetChipScsiCtrl(PortAddr);
-static uchar AscSetChipScsiID(PortAddr, uchar);
-static uchar AscGetChipVersion(PortAddr, ushort);
-static ushort AscGetChipBusType(PortAddr);
-static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
-static int AscFindSignature(PortAddr);
-static void AscToggleIRQAct(PortAddr);
-static uchar AscGetChipIRQ(PortAddr, ushort);
-static uchar AscSetChipIRQ(PortAddr, uchar, ushort);
-static ushort AscGetChipBiosAddress(PortAddr, ushort);
-static inline ulong DvcEnterCritical(void);
-static inline void DvcLeaveCritical(ulong);
-#ifdef CONFIG_PCI
-static uchar DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort);
-static void DvcWritePCIConfigByte(ASC_DVC_VAR *, ushort, uchar);
-#endif /* CONFIG_PCI */
-static ushort AscGetChipBiosAddress(PortAddr, ushort);
-static void DvcSleepMilliSecond(ASC_DCNT);
-static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
-static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
-static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
-static ushort AscInitGetConfig(ASC_DVC_VAR *);
-static ushort AscInitSetConfig(ASC_DVC_VAR *);
-static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
-static void AscAsyncFix(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
-static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
-static void AscInquiryHandling(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
-static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
-static int AscISR(ASC_DVC_VAR *);
-static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
-static int AscSgListToQueue(int);
-#ifdef CONFIG_ISA
-static void AscEnableIsaDma(uchar);
-#endif /* CONFIG_ISA */
-static ASC_DCNT AscGetMaxDmaCount(ushort);
-static const char *advansys_info(struct Scsi_Host *shost);
-
-/*
- * --- Adv Library Constants and Macros
- */
-
-#define ADV_LIB_VERSION_MAJOR 5
-#define ADV_LIB_VERSION_MINOR 14
-
-/*
- * Define Adv Library required special types.
- */
-
/*
* Portable Data Types
*
@@ -2045,12 +968,6 @@ static const char *advansys_info(struct Scsi_Host *shost);
#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
/*
- * For wide boards a CDB length maximum of 16 bytes
- * is supported.
- */
-#define ADV_MAX_CDB_LEN 16
-
-/*
* Define total number of simultaneous maximum element scatter-gather
* request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
* maximum number of outstanding commands per wide host adapter. Each
@@ -2058,28 +975,14 @@ static const char *advansys_info(struct Scsi_Host *shost);
* elements. Allow each command to have at least one ADV_SG_BLOCK structure.
* This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
* structures or 255 scatter-gather elements.
- *
*/
#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
/*
- * Define Adv Library required maximum number of scatter-gather
- * elements per request.
+ * Define maximum number of scatter-gather elements per request.
*/
#define ADV_MAX_SG_LIST 255
-
-/* Number of SG blocks needed. */
-#define ADV_NUM_SG_BLOCK \
- ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
-
-/* Total contiguous memory needed for SG blocks. */
-#define ADV_SG_TOTAL_MEM_SIZE \
- (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
-
-#define ADV_PAGE_SIZE PAGE_SIZE
-
-#define ADV_NUM_PAGE_CROSSING \
- ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
+#define NO_OF_SG_PER_BLOCK 15
#define ADV_EEP_DVC_CFG_BEGIN (0x00)
#define ADV_EEP_DVC_CFG_END (0x15)
@@ -2385,10 +1288,6 @@ typedef struct adveep_38C1600_config {
* EEPROM Commands
*/
#define ASC_EEP_CMD_DONE 0x0200
-#define ASC_EEP_CMD_DONE_ERR 0x0001
-
-/* cfg_word */
-#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
/* bios_ctrl */
#define BIOS_CTRL_BIOS 0x0001
@@ -2405,10 +1304,8 @@ typedef struct adveep_38C1600_config {
#define BIOS_CTRL_AIPP_DIS 0x2000
#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
-#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */
#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
-#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */
/*
* XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
@@ -2418,8 +1315,6 @@ typedef struct adveep_38C1600_config {
* #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
*/
#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
-#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */
-#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */
/*
* Byte I/O register address from base of 'iop_base'.
@@ -2549,8 +1444,6 @@ typedef struct adveep_38C1600_config {
#define ADV_CHIP_ID_BYTE 0x25
#define ADV_CHIP_ID_WORD 0x04C1
-#define ADV_SC_SCSI_BUS_RESET 0x2000
-
#define ADV_INTR_ENABLE_HOST_INTR 0x01
#define ADV_INTR_ENABLE_SEL_INTR 0x02
#define ADV_INTR_ENABLE_DPR_INTR 0x04
@@ -2590,8 +1483,6 @@ typedef struct adveep_38C1600_config {
#define ADV_TICKLE_B 0x02
#define ADV_TICKLE_C 0x03
-#define ADV_SCSI_CTRL_RSTOUT 0x2000
-
#define AdvIsIntPending(port) \
(AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
@@ -2744,14 +1635,11 @@ typedef struct adveep_38C1600_config {
*/
#define INTAB 0x01
-/* a_advlib.h */
-
/*
* Adv Library Status Definitions
*/
#define ADV_TRUE 1
#define ADV_FALSE 0
-#define ADV_NOERROR 1
#define ADV_SUCCESS 1
#define ADV_BUSY 0
#define ADV_ERROR (-1)
@@ -2762,31 +1650,12 @@ typedef struct adveep_38C1600_config {
#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
-#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
#define ADV_MAX_TID 15 /* max. target identifier */
#define ADV_MAX_LUN 7 /* max. logical unit number */
/*
- * Error code values are set in ADV_DVC_VAR 'err_code'.
- */
-#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
-#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
-#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
-#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
-#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
-#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
-#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
-#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
-#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
-#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
-#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
-#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
-#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
-#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
-
-/*
* Fixed locations of microcode operating variables.
*/
#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
@@ -2902,8 +1771,7 @@ typedef struct adv_carr_t {
#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
#define ADV_CARRIER_NUM_PAGE_CROSSING \
- (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
- (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
+ (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + (PAGE_SIZE - 1))/PAGE_SIZE)
#define ADV_CARRIER_BUFSIZE \
((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
@@ -2937,80 +1805,17 @@ typedef struct adv_dvc_cfg {
ushort disc_enable; /* enable disconnection */
uchar chip_version; /* chip version */
uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
- ushort lib_version; /* Adv Library version number */
ushort control_flag; /* Microcode Control Flag */
ushort mcode_date; /* Microcode date */
ushort mcode_version; /* Microcode version */
- ushort pci_slot_info; /* high byte device/function number */
- /* bits 7-3 device num., bits 2-0 function num. */
- /* low byte bus num. */
ushort serial1; /* EEPROM serial number word 1 */
ushort serial2; /* EEPROM serial number word 2 */
ushort serial3; /* EEPROM serial number word 3 */
- struct device *dev; /* pointer to the pci dev structure for this board */
} ADV_DVC_CFG;
struct adv_dvc_var;
struct adv_scsi_req_q;
-typedef void (*ADV_ISR_CALLBACK)
- (struct adv_dvc_var *, struct adv_scsi_req_q *);
-
-typedef void (*ADV_ASYNC_CALLBACK)
- (struct adv_dvc_var *, uchar);
-
-/*
- * Adapter operation variable structure.
- *
- * One structure is required per host adapter.
- *
- * Field naming convention:
- *
- * *_able indicates both whether a feature should be enabled or disabled
- * and whether a device isi capable of the feature. At initialization
- * this field may be set, but later if a device is found to be incapable
- * of the feature, the field is cleared.
- */
-typedef struct adv_dvc_var {
- AdvPortAddr iop_base; /* I/O port address */
- ushort err_code; /* fatal error code */
- ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
- ADV_ISR_CALLBACK isr_callback;
- ADV_ASYNC_CALLBACK async_callback;
- ushort wdtr_able; /* try WDTR for a device */
- ushort sdtr_able; /* try SDTR for a device */
- ushort ultra_able; /* try SDTR Ultra speed for a device */
- ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
- ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
- ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
- ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
- ushort tagqng_able; /* try tagged queuing with a device */
- ushort ppr_able; /* PPR message capable per TID bitmask. */
- uchar max_dvc_qng; /* maximum number of tagged commands per device */
- ushort start_motor; /* start motor command allowed */
- uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
- uchar chip_no; /* should be assigned by caller */
- uchar max_host_qng; /* maximum number of Q'ed command allowed */
- uchar irq_no; /* IRQ number */
- ushort no_scam; /* scam_tolerant of EEPROM */
- struct asc_board *drv_ptr; /* driver pointer to private structure */
- uchar chip_scsi_id; /* chip SCSI target ID */
- uchar chip_type;
- uchar bist_err_code;
- ADV_CARR_T *carrier_buf;
- ADV_CARR_T *carr_freelist; /* Carrier free list. */
- ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
- ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
- ushort carr_pending_cnt; /* Count of pending carriers. */
- /*
- * Note: The following fields will not be used after initialization. The
- * driver may discard the buffer after initialization is done.
- */
- ADV_DVC_CFG *cfg; /* temporary configuration structure */
-} ADV_DVC_VAR;
-
-#define NO_OF_SG_PER_BLOCK 15
-
typedef struct asc_sg_block {
uchar reserved1;
uchar reserved2;
@@ -3069,6 +1874,83 @@ typedef struct adv_scsi_req_q {
} ADV_SCSI_REQ_Q;
/*
+ * The following two structures are used to process Wide Board requests.
+ *
+ * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
+ * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
+ * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
+ * Mid-Level SCSI request structure.
+ *
+ * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
+ * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
+ * up to 255 scatter-gather elements may be used per request or
+ * ADV_SCSI_REQ_Q.
+ *
+ * Both structures must be 32 byte aligned.
+ */
+typedef struct adv_sgblk {
+ ADV_SG_BLOCK sg_block; /* Sgblock structure. */
+ uchar align[32]; /* Sgblock structure padding. */
+ struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
+} adv_sgblk_t;
+
+typedef struct adv_req {
+ ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
+ uchar align[32]; /* Request structure padding. */
+ struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
+ adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
+ struct adv_req *next_reqp; /* Next Request Structure. */
+} adv_req_t;
+
+/*
+ * Adapter operation variable structure.
+ *
+ * One structure is required per host adapter.
+ *
+ * Field naming convention:
+ *
+ * *_able indicates both whether a feature should be enabled or disabled
+ * and whether a device isi capable of the feature. At initialization
+ * this field may be set, but later if a device is found to be incapable
+ * of the feature, the field is cleared.
+ */
+typedef struct adv_dvc_var {
+ AdvPortAddr iop_base; /* I/O port address */
+ ushort err_code; /* fatal error code */
+ ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
+ ushort wdtr_able; /* try WDTR for a device */
+ ushort sdtr_able; /* try SDTR for a device */
+ ushort ultra_able; /* try SDTR Ultra speed for a device */
+ ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
+ ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
+ ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
+ ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
+ ushort tagqng_able; /* try tagged queuing with a device */
+ ushort ppr_able; /* PPR message capable per TID bitmask. */
+ uchar max_dvc_qng; /* maximum number of tagged commands per device */
+ ushort start_motor; /* start motor command allowed */
+ uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
+ uchar chip_no; /* should be assigned by caller */
+ uchar max_host_qng; /* maximum number of Q'ed command allowed */
+ ushort no_scam; /* scam_tolerant of EEPROM */
+ struct asc_board *drv_ptr; /* driver pointer to private structure */
+ uchar chip_scsi_id; /* chip SCSI target ID */
+ uchar chip_type;
+ uchar bist_err_code;
+ ADV_CARR_T *carrier_buf;
+ ADV_CARR_T *carr_freelist; /* Carrier free list. */
+ ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
+ ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
+ ushort carr_pending_cnt; /* Count of pending carriers. */
+ struct adv_req *orig_reqp; /* adv_req_t memory block. */
+ /*
+ * Note: The following fields will not be used after initialization. The
+ * driver may discard the buffer after initialization is done.
+ */
+ ADV_DVC_CFG *cfg; /* temporary configuration structure */
+} ADV_DVC_VAR;
+
+/*
* Microcode idle loop commands
*/
#define IDLE_CMD_COMPLETED 0
@@ -3092,10 +1974,8 @@ typedef struct adv_scsi_req_q {
/*
* Wait loop time out values.
*/
-#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
-#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
#define SCSI_MAX_RETRY 10 /* retry count */
#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
@@ -3105,53 +1985,6 @@ typedef struct adv_scsi_req_q {
#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
-/*
- * Device drivers must define the following functions.
- */
-static inline ulong DvcEnterCritical(void);
-static inline void DvcLeaveCritical(ulong);
-static void DvcSleepMilliSecond(ADV_DCNT);
-static uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
-static void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
-static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
- uchar *, ASC_SDCNT *, int);
-static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
-
-/*
- * Adv Library functions available to drivers.
- */
-static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-static int AdvISR(ADV_DVC_VAR *);
-static int AdvInitGetConfig(ADV_DVC_VAR *);
-static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
-static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
-static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
-static int AdvResetChipAndSB(ADV_DVC_VAR *);
-static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
-
-/*
- * Internal Adv Library functions.
- */
-static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
-static void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
-static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
-static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
-static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
-static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
-static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
-static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
-static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
-static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
-static void AdvWaitEEPCmd(AdvPortAddr);
-static ushort AdvReadEEPWord(AdvPortAddr, int);
-
-/*
- * PCI Bus Definitions
- */
-#define AscPCICmdRegBits_BusMastering 0x0007
-#define AscPCICmdRegBits_ParErrRespCtrl 0x0040
-
/* Read byte from a register. */
#define AdvReadByteRegister(iop_base, reg_off) \
(ADV_MEM_READB((iop_base) + (reg_off)))
@@ -3319,23 +2152,6 @@ do { \
#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
-/*
- * Default EEPROM Configuration structure defined in a_init.c.
- */
-static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
-static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
-static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
-
-/*
- * DvcGetPhyAddr() flag arguments
- */
-#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
-#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
-#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
-#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
-#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
-#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
-
/* Return the address that is aligned at the next doubleword >= to 'addr'. */
#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
@@ -3353,92 +2169,10 @@ static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
(sizeof(ADV_SG_BLOCK) * \
((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
-/*
- * Inquiry data structure and bitfield macros
- *
- * Using bitfields to access the subchar data isn't portable across
- * endianness, so instead mask and shift. Only quantities of more
- * than 1 bit are shifted, since the others are just tested for true
- * or false.
- */
-
-#define ADV_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f)
-#define ADV_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5)
-#define ADV_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f)
-#define ADV_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80)
-#define ADV_INQ_ANSI_VER(inq) ((inq)->ver & 0x07)
-#define ADV_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3)
-#define ADV_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6)
-#define ADV_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f)
-#define ADV_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40)
-#define ADV_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80)
-#define ADV_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01)
-#define ADV_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02)
-#define ADV_INQ_LINK_CMD(inq) ((inq)->flags & 0x08)
-#define ADV_INQ_SYNC(inq) ((inq)->flags & 0x10)
-#define ADV_INQ_WIDE16(inq) ((inq)->flags & 0x20)
-#define ADV_INQ_WIDE32(inq) ((inq)->flags & 0x40)
-#define ADV_INQ_REL_ADDR(inq) ((inq)->flags & 0x80)
-#define ADV_INQ_INFO_UNIT(inq) ((inq)->info & 0x01)
-#define ADV_INQ_QUICK_ARB(inq) ((inq)->info & 0x02)
-#define ADV_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
-
-typedef struct {
- uchar periph; /* peripheral device type [0:4] */
- /* peripheral qualifier [5:7] */
- uchar devtype; /* device type modifier (for SCSI I) [0:6] */
- /* RMB - removable medium bit [7] */
- uchar ver; /* ANSI approved version [0:2] */
- /* ECMA version [3:5] */
- /* ISO version [6:7] */
- uchar byte3; /* response data format [0:3] */
- /* 0 SCSI 1 */
- /* 1 CCS */
- /* 2 SCSI-2 */
- /* 3-F reserved */
- /* reserved [4:5] */
- /* terminate I/O process bit (see 5.6.22) [6] */
- /* asynch. event notification (processor) [7] */
- uchar add_len; /* additional length */
- uchar res1; /* reserved */
- uchar res2; /* reserved */
- uchar flags; /* soft reset implemented [0] */
- /* command queuing [1] */
- /* reserved [2] */
- /* linked command for this logical unit [3] */
- /* synchronous data transfer [4] */
- /* wide bus 16 bit data transfer [5] */
- /* wide bus 32 bit data transfer [6] */
- /* relative addressing mode [7] */
- uchar vendor_id[8]; /* vendor identification */
- uchar product_id[16]; /* product identification */
- uchar product_rev_level[4]; /* product revision level */
- uchar vendor_specific[20]; /* vendor specific */
- uchar info; /* information unit supported [0] */
- /* quick arbitrate supported [1] */
- /* clocking field [2:3] */
- /* reserved [4:7] */
- uchar res3; /* reserved */
-} ADV_SCSI_INQUIRY; /* 58 bytes */
-
-/*
- * --- Driver Constants and Macros
- */
-
-#define ASC_NUM_BOARD_SUPPORTED 16
-#define ASC_NUM_IOPORT_PROBE 4
-#define ASC_NUM_BUS 4
-
-/* Reference Scsi_Host hostdata */
-#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
-
-/* asc_board_t flags */
-#define ASC_HOST_IN_RESET 0x01
+/* struct asc_board flags */
#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
-#define ASC_SELECT_QUEUE_DEPTHS 0x08
#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
-#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
@@ -3473,82 +2207,14 @@ typedef struct {
#define HOST_BYTE(byte) ((byte) << 16)
#define DRIVER_BYTE(byte) ((byte) << 24)
-/*
- * The following definitions and macros are OS independent interfaces to
- * the queue functions:
- * REQ - SCSI request structure
- * REQP - pointer to SCSI request structure
- * REQPTID(reqp) - reqp's target id
- * REQPNEXT(reqp) - reqp's next pointer
- * REQPNEXTP(reqp) - pointer to reqp's next pointer
- * REQPTIME(reqp) - reqp's time stamp value
- * REQTIMESTAMP() - system time stamp value
- */
-typedef struct scsi_cmnd REQ, *REQP;
-#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
-#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
-#define REQPTID(reqp) ((reqp)->device->id)
-#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
-#define REQTIMESTAMP() (jiffies)
-
-#define REQTIMESTAT(function, ascq, reqp, tid) \
-{ \
- /*
- * If the request time stamp is less than the system time stamp, then \
- * maybe the system time stamp wrapped. Set the request time to zero.\
- */ \
- if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
- REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
- } else { \
- /* Indicate an error occurred with the assertion. */ \
- ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
- REQPTIME(reqp) = 0; \
- } \
- /* Handle first minimum time case without external initialization. */ \
- if (((ascq)->q_tot_cnt[tid] == 1) || \
- (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
- (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
- ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
- (function), (tid), (ascq)->q_min_tim[tid]); \
- } \
- if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
- (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
- ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
- (function), tid, (ascq)->q_max_tim[tid]); \
- } \
- (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
- /* Reset the time stamp field. */ \
- REQPTIME(reqp) = 0; \
-}
-
-/* asc_enqueue() flags */
-#define ASC_FRONT 1
-#define ASC_BACK 2
-
-/* asc_dequeue_list() argument */
-#define ASC_TID_ALL (-1)
-
-/* Return non-zero, if the queue is empty. */
-#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
-
-#define PCI_MAX_SLOT 0x1F
-#define PCI_MAX_BUS 0xFF
-#define PCI_IOADDRESS_MASK 0xFFFE
-#define ASC_PCI_DEVICE_ID_CNT 6 /* PCI Device ID count. */
-
+#define ASC_STATS(shost, counter) ASC_STATS_ADD(shost, counter, 1)
#ifndef ADVANSYS_STATS
-#define ASC_STATS(shost, counter)
#define ASC_STATS_ADD(shost, counter, count)
#else /* ADVANSYS_STATS */
-#define ASC_STATS(shost, counter) \
- (ASC_BOARDP(shost)->asc_stats.counter++)
-
#define ASC_STATS_ADD(shost, counter, count) \
- (ASC_BOARDP(shost)->asc_stats.counter += (count))
+ (((struct asc_board *) shost_priv(shost))->asc_stats.counter += (count))
#endif /* ADVANSYS_STATS */
-#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
-
/* If the result wraps when calculating tenths, return 0. */
#define ASC_TENTHS(num, den) \
(((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
@@ -3589,13 +2255,8 @@ typedef struct scsi_cmnd REQ, *REQP;
#ifndef ADVANSYS_DEBUG
-#define ASC_DBG(lvl, s)
-#define ASC_DBG1(lvl, s, a1)
-#define ASC_DBG2(lvl, s, a1, a2)
-#define ASC_DBG3(lvl, s, a1, a2, a3)
-#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
+#define ASC_DBG(lvl, s...)
#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
-#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
@@ -3614,40 +2275,11 @@ typedef struct scsi_cmnd REQ, *REQP;
* 2-N: Verbose Tracing
*/
-#define ASC_DBG(lvl, s) \
- { \
- if (asc_dbglvl >= (lvl)) { \
- printk(s); \
- } \
- }
-
-#define ASC_DBG1(lvl, s, a1) \
- { \
- if (asc_dbglvl >= (lvl)) { \
- printk((s), (a1)); \
- } \
- }
-
-#define ASC_DBG2(lvl, s, a1, a2) \
- { \
- if (asc_dbglvl >= (lvl)) { \
- printk((s), (a1), (a2)); \
- } \
- }
-
-#define ASC_DBG3(lvl, s, a1, a2, a3) \
- { \
- if (asc_dbglvl >= (lvl)) { \
- printk((s), (a1), (a2), (a3)); \
- } \
- }
-
-#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
- { \
- if (asc_dbglvl >= (lvl)) { \
- printk((s), (a1), (a2), (a3), (a4)); \
- } \
- }
+#define ASC_DBG(lvl, format, arg...) { \
+ if (asc_dbglvl >= (lvl)) \
+ printk(KERN_DEBUG "%s: %s: " format, DRV_NAME, \
+ __FUNCTION__ , ## arg); \
+}
#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
{ \
@@ -3656,13 +2288,6 @@ typedef struct scsi_cmnd REQ, *REQP;
} \
}
-#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
- { \
- if (asc_dbglvl >= (lvl)) { \
- asc_prt_scsi_cmnd(s); \
- } \
- }
-
#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
{ \
if (asc_dbglvl >= (lvl)) { \
@@ -3701,24 +2326,6 @@ typedef struct scsi_cmnd REQ, *REQP;
ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
#endif /* ADVANSYS_DEBUG */
-#ifndef ADVANSYS_ASSERT
-#define ASC_ASSERT(a)
-#else /* ADVANSYS_ASSERT */
-
-#define ASC_ASSERT(a) \
- { \
- if (!(a)) { \
- printk("ASC_ASSERT() Failure: file %s, line %d\n", \
- __FILE__, __LINE__); \
- } \
- }
-
-#endif /* ADVANSYS_ASSERT */
-
-/*
- * --- Driver Structures
- */
-
#ifdef ADVANSYS_STATS
/* Per board statistics structure */
@@ -3739,72 +2346,23 @@ struct asc_stats {
ADV_DCNT exe_error; /* # ASC_ERROR returns. */
ADV_DCNT exe_unknown; /* # unknown returns. */
/* Data Transfer Statistics */
- ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
- ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
- ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
- ADV_DCNT sg_elem; /* # scatter-gather elements */
- ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
+ ADV_DCNT xfer_cnt; /* # I/O requests received */
+ ADV_DCNT xfer_elem; /* # scatter-gather elements */
+ ADV_DCNT xfer_sect; /* # 512-byte blocks */
};
#endif /* ADVANSYS_STATS */
/*
- * Request queuing structure
- */
-typedef struct asc_queue {
- ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
- REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
- REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
-#ifdef ADVANSYS_STATS
- short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
- short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
- ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
- ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
- ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
- ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
-#endif /* ADVANSYS_STATS */
-} asc_queue_t;
-
-/*
- * Adv Library Request Structures
- *
- * The following two structures are used to process Wide Board requests.
- *
- * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
- * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
- * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
- * Mid-Level SCSI request structure.
- *
- * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
- * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
- * up to 255 scatter-gather elements may be used per request or
- * ADV_SCSI_REQ_Q.
- *
- * Both structures must be 32 byte aligned.
- */
-typedef struct adv_sgblk {
- ADV_SG_BLOCK sg_block; /* Sgblock structure. */
- uchar align[32]; /* Sgblock structure padding. */
- struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
-} adv_sgblk_t;
-
-typedef struct adv_req {
- ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
- uchar align[32]; /* Request structure padding. */
- struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
- adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
- struct adv_req *next_reqp; /* Next Request Structure. */
-} adv_req_t;
-
-/*
* Structure allocated for each board.
*
- * This structure is allocated by scsi_register() at the end
+ * This structure is allocated by scsi_host_alloc() at the end
* of the 'Scsi_Host' structure starting at the 'hostdata'
* field. It is guaranteed to be allocated from DMA-able memory.
*/
-typedef struct asc_board {
- int id; /* Board Id */
+struct asc_board {
+ struct device *dev;
uint flags; /* Board flags */
+ unsigned int irq;
union {
ASC_DVC_VAR asc_dvc_var; /* Narrow board */
ADV_DVC_VAR adv_dvc_var; /* Wide board */
@@ -3814,11 +2372,7 @@ typedef struct asc_board {
ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
} dvc_cfg;
ushort asc_n_io_port; /* Number I/O ports. */
- asc_queue_t active; /* Active command queue */
- asc_queue_t waiting; /* Waiting command queue */
- asc_queue_t done; /* Done command queue */
ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
- struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
@@ -3829,2409 +2383,529 @@ typedef struct asc_board {
ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
} eep_config;
ulong last_reset; /* Saved last reset time */
- spinlock_t lock; /* Board spinlock */
-#ifdef CONFIG_PROC_FS
/* /proc/scsi/advansys/[0...] */
char *prtbuf; /* /proc print buffer */
-#endif /* CONFIG_PROC_FS */
#ifdef ADVANSYS_STATS
struct asc_stats asc_stats; /* Board statistics */
#endif /* ADVANSYS_STATS */
/*
* The following fields are used only for Narrow Boards.
*/
- /* The following three structures must be in DMA-able memory. */
- ASC_SCSI_REQ_Q scsireqq;
- ASC_CAP_INFO cap_info;
- ASC_SCSI_INQUIRY inquiry;
uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
/*
* The following fields are used only for Wide Boards.
*/
void __iomem *ioremap_addr; /* I/O Memory remap address. */
ushort ioport; /* I/O Port address. */
- ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */
- adv_req_t *orig_reqp; /* adv_req_t memory block. */
adv_req_t *adv_reqp; /* Request structures. */
adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
ushort bios_signature; /* BIOS Signature. */
ushort bios_version; /* BIOS Version. */
ushort bios_codeseg; /* BIOS Code Segment. */
ushort bios_codelen; /* BIOS Code Segment Length. */
-} asc_board_t;
-
-/*
- * PCI configuration structures
- */
-typedef struct _PCI_DATA_ {
- uchar type;
- uchar bus;
- uchar slot;
- uchar func;
- uchar offset;
-} PCI_DATA;
-
-typedef struct _PCI_DEVICE_ {
- ushort vendorID;
- ushort deviceID;
- ushort slotNumber;
- ushort slotFound;
- uchar busNumber;
- uchar maxBusNumber;
- uchar devFunc;
- ushort startSlot;
- ushort endSlot;
- uchar bridge;
- uchar type;
-} PCI_DEVICE;
-
-typedef struct _PCI_CONFIG_SPACE_ {
- ushort vendorID;
- ushort deviceID;
- ushort command;
- ushort status;
- uchar revision;
- uchar classCode[3];
- uchar cacheSize;
- uchar latencyTimer;
- uchar headerType;
- uchar bist;
- ADV_PADDR baseAddress[6];
- ushort reserved[4];
- ADV_PADDR optionRomAddr;
- ushort reserved2[4];
- uchar irqLine;
- uchar irqPin;
- uchar minGnt;
- uchar maxLatency;
-} PCI_CONFIG_SPACE;
-
-/*
- * --- Driver Data
- */
-
-/* Note: All driver global data should be initialized. */
-
-/* Number of boards detected in system. */
-static int asc_board_count = 0;
-static struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
-
-/* Overrun buffer used by all narrow boards. */
-static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
-
-/*
- * Global structures required to issue a command.
- */
-static ASC_SCSI_Q asc_scsi_q = { {0} };
-static ASC_SG_HEAD asc_sg_head = { 0 };
-
-/* List of supported bus types. */
-static ushort asc_bus[ASC_NUM_BUS] __initdata = {
- ASC_IS_ISA,
- ASC_IS_VL,
- ASC_IS_EISA,
- ASC_IS_PCI,
};
-static int asc_iopflag = ASC_FALSE;
-static int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
+#define asc_dvc_to_board(asc_dvc) container_of(asc_dvc, struct asc_board, \
+ dvc_var.asc_dvc_var)
+#define adv_dvc_to_board(adv_dvc) container_of(adv_dvc, struct asc_board, \
+ dvc_var.adv_dvc_var)
+#define adv_dvc_to_pdev(adv_dvc) to_pci_dev(adv_dvc_to_board(adv_dvc)->dev)
#ifdef ADVANSYS_DEBUG
-static char *asc_bus_name[ASC_NUM_BUS] = {
- "ASC_IS_ISA",
- "ASC_IS_VL",
- "ASC_IS_EISA",
- "ASC_IS_PCI",
-};
-
static int asc_dbglvl = 3;
-#endif /* ADVANSYS_DEBUG */
-
-/* Declaration for Asc Library internal data referenced by driver. */
-static PortAddr _asc_def_iop_base[];
-
-/*
- * --- Driver Function Prototypes
- *
- * advansys.h contains function prototypes for functions global to Linux.
- */
-
-static irqreturn_t advansys_interrupt(int, void *);
-static int advansys_slave_configure(struct scsi_device *);
-static void asc_scsi_done_list(struct scsi_cmnd *);
-static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
-static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
-static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
-static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
-static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
-static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-static void adv_async_callback(ADV_DVC_VAR *, uchar);
-static void asc_enqueue(asc_queue_t *, REQP, int);
-static REQP asc_dequeue(asc_queue_t *, int);
-static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
-static int asc_rmqueue(asc_queue_t *, REQP);
-static void asc_execute_queue(asc_queue_t *);
-#ifdef CONFIG_PROC_FS
-static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
-static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
-static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
-static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
-static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
-static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
-static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
-static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
-static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
-static int asc_prt_line(char *, int, char *fmt, ...);
-#endif /* CONFIG_PROC_FS */
-
-/* Declaration for Asc Library internal functions referenced by driver. */
-static int AscFindSignature(PortAddr);
-static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
-
-/* Statistics function prototypes. */
-#ifdef ADVANSYS_STATS
-#ifdef CONFIG_PROC_FS
-static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
-static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
-#endif /* CONFIG_PROC_FS */
-#endif /* ADVANSYS_STATS */
-
-/* Debug function prototypes. */
-#ifdef ADVANSYS_DEBUG
-static void asc_prt_scsi_host(struct Scsi_Host *);
-static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
-static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
-static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
-static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
-static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
-static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
-static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
-static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
-static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
-static void asc_prt_hex(char *f, uchar *, int);
-#endif /* ADVANSYS_DEBUG */
-#ifdef CONFIG_PROC_FS
/*
- * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
- *
- * *buffer: I/O buffer
- * **start: if inout == FALSE pointer into buffer where user read should start
- * offset: current offset into a /proc/scsi/advansys/[0...] file
- * length: length of buffer
- * hostno: Scsi_Host host_no
- * inout: TRUE - user is writing; FALSE - user is reading
- *
- * Return the number of bytes read from or written to a
- * /proc/scsi/advansys/[0...] file.
- *
- * Note: This function uses the per board buffer 'prtbuf' which is
- * allocated when the board is initialized in advansys_detect(). The
- * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
- * used to write to the buffer. The way asc_proc_copy() is written
- * if 'prtbuf' is too small it will not be overwritten. Instead the
- * user just won't get all the available statistics.
+ * asc_prt_asc_dvc_var()
*/
-static int
-advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
- off_t offset, int length, int inout)
+static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
{
- struct Scsi_Host *shp;
- asc_board_t *boardp;
- int i;
- char *cp;
- int cplen;
- int cnt;
- int totcnt;
- int leftlen;
- char *curbuf;
- off_t advoffset;
-#ifdef ADVANSYS_STATS
- int tgt_id;
-#endif /* ADVANSYS_STATS */
-
- ASC_DBG(1, "advansys_proc_info: begin\n");
-
- /*
- * User write not supported.
- */
- if (inout == TRUE) {
- return (-ENOSYS);
- }
-
- /*
- * User read of /proc/scsi/advansys/[0...] file.
- */
-
- /* Find the specified board. */
- for (i = 0; i < asc_board_count; i++) {
- if (asc_host[i]->host_no == shost->host_no) {
- break;
- }
- }
- if (i == asc_board_count) {
- return (-ENOENT);
- }
-
- shp = asc_host[i];
- boardp = ASC_BOARDP(shp);
-
- /* Copy read data starting at the beginning of the buffer. */
- *start = buffer;
- curbuf = buffer;
- advoffset = 0;
- totcnt = 0;
- leftlen = length;
-
- /*
- * Get board configuration information.
- *
- * advansys_info() returns the board string from its own static buffer.
- */
- cp = (char *)advansys_info(shp);
- strcat(cp, "\n");
- cplen = strlen(cp);
- /* Copy board information. */
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
-
- /*
- * Display Wide Board BIOS Information.
- */
- if (ASC_WIDE_BOARD(boardp)) {
- cp = boardp->prtbuf;
- cplen = asc_prt_adv_bios(shp, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt =
- asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
- cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
- }
-
- /*
- * Display driver information for each device attached to the board.
- */
- cp = boardp->prtbuf;
- cplen = asc_prt_board_devices(shp, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
-
- /*
- * Display EEPROM configuration for the board.
- */
- cp = boardp->prtbuf;
- if (ASC_NARROW_BOARD(boardp)) {
- cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
- } else {
- cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
- }
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
-
- /*
- * Display driver configuration and information for the board.
- */
- cp = boardp->prtbuf;
- cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
-#ifdef ADVANSYS_STATS
- /*
- * Display driver statistics for the board.
- */
- cp = boardp->prtbuf;
- cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl "
+ "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
- /*
- * Display driver statistics for each target.
- */
- for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
- cp = boardp->prtbuf;
- cplen = asc_prt_target_stats(shp, tgt_id, cp, ASC_PRTBUF_SIZE);
- ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
- cnt =
- asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
- cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
- }
-#endif /* ADVANSYS_STATS */
+ printk(" bus_type %d, init_sdtr 0x%x,\n", h->bus_type,
+ (unsigned)h->init_sdtr);
- /*
- * Display Asc Library dynamic configuration information
- * for the board.
- */
- cp = boardp->prtbuf;
- if (ASC_NARROW_BOARD(boardp)) {
- cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE);
- } else {
- cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE);
- }
- ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
- cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
- totcnt += cnt;
- leftlen -= cnt;
- if (leftlen == 0) {
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
- return totcnt;
- }
- advoffset += cplen;
- curbuf += cnt;
+ printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, "
+ "chip_no 0x%x,\n", (unsigned)h->sdtr_done,
+ (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready,
+ (unsigned)h->chip_no);
- ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+ printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait "
+ "%u,\n", (unsigned)h->queue_full_or_busy,
+ (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
- return totcnt;
-}
-#endif /* CONFIG_PROC_FS */
+ printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, "
+ "in_critical_cnt %u,\n", (unsigned)h->is_in_int,
+ (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng,
+ (unsigned)h->in_critical_cnt);
-/*
- * advansys_info()
- *
- * Return suitable for printing on the console with the argument
- * adapter's configuration information.
- *
- * Note: The information line should not exceed ASC_INFO_SIZE bytes,
- * otherwise the static 'info' array will be overrun.
- */
-static const char *advansys_info(struct Scsi_Host *shost)
-{
- static char info[ASC_INFO_SIZE];
- asc_board_t *boardp;
- ASC_DVC_VAR *asc_dvc_varp;
- ADV_DVC_VAR *adv_dvc_varp;
- char *busname;
- int iolen;
- char *widename = NULL;
+ printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, "
+ "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage,
+ (unsigned)h->init_state, (unsigned)h->no_scam,
+ (unsigned)h->pci_fix_asyn_xfer);
- boardp = ASC_BOARDP(shost);
- if (ASC_NARROW_BOARD(boardp)) {
- asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
- ASC_DBG(1, "advansys_info: begin\n");
- if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
- if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
- ASC_IS_ISAPNP) {
- busname = "ISA PnP";
- } else {
- busname = "ISA";
- }
- /* Don't reference 'shost->n_io_port'; It may be truncated. */
- sprintf(info,
- "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
- ASC_VERSION, busname,
- (ulong)shost->io_port,
- (ulong)shost->io_port + boardp->asc_n_io_port -
- 1, shost->irq, shost->dma_channel);
- } else {
- if (asc_dvc_varp->bus_type & ASC_IS_VL) {
- busname = "VL";
- } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
- busname = "EISA";
- } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
- if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
- == ASC_IS_PCI_ULTRA) {
- busname = "PCI Ultra";
- } else {
- busname = "PCI";
- }
- } else {
- busname = "?";
- ASC_PRINT2
- ("advansys_info: board %d: unknown bus type %d\n",
- boardp->id, asc_dvc_varp->bus_type);
- }
- /* Don't reference 'shost->n_io_port'; It may be truncated. */
- sprintf(info,
- "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
- ASC_VERSION, busname,
- (ulong)shost->io_port,
- (ulong)shost->io_port + boardp->asc_n_io_port -
- 1, shost->irq);
- }
- } else {
- /*
- * Wide Adapter Information
- *
- * Memory-mapped I/O is used instead of I/O space to access
- * the adapter, but display the I/O Port range. The Memory
- * I/O address is displayed through the driver /proc file.
- */
- adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
- iolen = ADV_3550_IOLEN;
- widename = "Ultra-Wide";
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
- iolen = ADV_38C0800_IOLEN;
- widename = "Ultra2-Wide";
- } else {
- iolen = ADV_38C1600_IOLEN;
- widename = "Ultra3-Wide";
- }
- sprintf(info,
- "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
- ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
- (ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq);
- }
- ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
- ASC_DBG(1, "advansys_info: end\n");
- return info;
+ printk(" cfg 0x%lx\n", (ulong)h->cfg);
}
/*
- * advansys_queuecommand() - interrupt-driven I/O entrypoint.
- *
- * This function always returns 0. Command return status is saved
- * in the 'scp' result field.
+ * asc_prt_asc_dvc_cfg()
*/
-static int
-advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
+static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
{
- struct Scsi_Host *shost;
- asc_board_t *boardp;
- ulong flags;
- struct scsi_cmnd *done_scp;
-
- shost = scp->device->host;
- boardp = ASC_BOARDP(shost);
- ASC_STATS(shost, queuecommand);
-
- /* host_lock taken by mid-level prior to call but need to protect */
- /* against own ISR */
- spin_lock_irqsave(&boardp->lock, flags);
-
- /*
- * Block new commands while handling a reset or abort request.
- */
- if (boardp->flags & ASC_HOST_IN_RESET) {
- ASC_DBG1(1,
- "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
- (ulong)scp);
- scp->result = HOST_BYTE(DID_RESET);
-
- /*
- * Add blocked requests to the board's 'done' queue. The queued
- * requests will be completed at the end of the abort or reset
- * handling.
- */
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- spin_unlock_irqrestore(&boardp->lock, flags);
- return 0;
- }
+ printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
- /*
- * Attempt to execute any waiting commands for the board.
- */
- if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
- ASC_DBG(1,
- "advansys_queuecommand: before asc_execute_queue() waiting\n");
- asc_execute_queue(&boardp->waiting);
- }
+ printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
+ h->can_tagged_qng, h->cmd_qng_enabled);
+ printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
+ h->disc_enable, h->sdtr_enable);
- /*
- * Save the function pointer to Linux mid-level 'done' function
- * and attempt to execute the command.
- *
- * If ASC_NOERROR is returned the request has been added to the
- * board's 'active' queue and will be completed by the interrupt
- * handler.
- *
- * If ASC_BUSY is returned add the request to the board's per
- * target waiting list. This is the first time the request has
- * been tried. Add it to the back of the waiting list. It will be
- * retried later.
- *
- * If an error occurred, the request will have been placed on the
- * board's 'done' queue and must be completed before returning.
- */
- scp->scsi_done = done;
- switch (asc_execute_scsi_cmnd(scp)) {
- case ASC_NOERROR:
- break;
- case ASC_BUSY:
- asc_enqueue(&boardp->waiting, scp, ASC_BACK);
- break;
- case ASC_ERROR:
- default:
- done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
- /* Interrupts could be enabled here. */
- asc_scsi_done_list(done_scp);
- break;
- }
- spin_unlock_irqrestore(&boardp->lock, flags);
+ printk(" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, "
+ "chip_version %d,\n", h->chip_scsi_id, h->isa_dma_speed,
+ h->isa_dma_channel, h->chip_version);
- return 0;
+ printk(" mcode_date 0x%x, mcode_version %d\n",
+ h->mcode_date, h->mcode_version);
}
/*
- * advansys_reset()
- *
- * Reset the bus associated with the command 'scp'.
+ * asc_prt_adv_dvc_var()
*
- * This function runs its own thread. Interrupts must be blocked but
- * sleeping is allowed and no locking other than for host structures is
- * required. Returns SUCCESS or FAILED.
+ * Display an ADV_DVC_VAR structure.
*/
-static int advansys_reset(struct scsi_cmnd *scp)
+static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
{
- struct Scsi_Host *shost;
- asc_board_t *boardp;
- ASC_DVC_VAR *asc_dvc_varp;
- ADV_DVC_VAR *adv_dvc_varp;
- ulong flags;
- struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
- struct scsi_cmnd *tscp, *new_last_scp;
- int status;
- int ret = SUCCESS;
-
- ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
-
-#ifdef ADVANSYS_STATS
- if (scp->device->host != NULL) {
- ASC_STATS(scp->device->host, reset);
- }
-#endif /* ADVANSYS_STATS */
-
- if ((shost = scp->device->host) == NULL) {
- scp->result = HOST_BYTE(DID_ERROR);
- return FAILED;
- }
-
- boardp = ASC_BOARDP(shost);
-
- ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
- boardp->id);
- /*
- * Check for re-entrancy.
- */
- spin_lock_irqsave(&boardp->lock, flags);
- if (boardp->flags & ASC_HOST_IN_RESET) {
- spin_unlock_irqrestore(&boardp->lock, flags);
- return FAILED;
- }
- boardp->flags |= ASC_HOST_IN_RESET;
- spin_unlock_irqrestore(&boardp->lock, flags);
-
- if (ASC_NARROW_BOARD(boardp)) {
- /*
- * Narrow Board
- */
- asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
-
- /*
- * Reset the chip and SCSI bus.
- */
- ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
- status = AscInitAsc1000Driver(asc_dvc_varp);
-
- /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
- if (asc_dvc_varp->err_code) {
- ASC_PRINT2
- ("advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
- boardp->id, asc_dvc_varp->err_code);
- ret = FAILED;
- } else if (status) {
- ASC_PRINT2
- ("advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
- boardp->id, status);
- } else {
- ASC_PRINT1
- ("advansys_reset: board %d: SCSI bus reset successful.\n",
- boardp->id);
- }
-
- ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
- spin_lock_irqsave(&boardp->lock, flags);
-
- } else {
- /*
- * Wide Board
- *
- * If the suggest reset bus flags are set, then reset the bus.
- * Otherwise only reset the device.
- */
- adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-
- /*
- * Reset the target's SCSI bus.
- */
- ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
- switch (AdvResetChipAndSB(adv_dvc_varp)) {
- case ASC_TRUE:
- ASC_PRINT1
- ("advansys_reset: board %d: SCSI bus reset successful.\n",
- boardp->id);
- break;
- case ASC_FALSE:
- default:
- ASC_PRINT1
- ("advansys_reset: board %d: SCSI bus reset error.\n",
- boardp->id);
- ret = FAILED;
- break;
- }
- spin_lock_irqsave(&boardp->lock, flags);
- (void)AdvISR(adv_dvc_varp);
- }
- /* Board lock is held. */
-
- /*
- * Dequeue all board 'done' requests. A pointer to the last request
- * is returned in 'last_scp'.
- */
- done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
-
- /*
- * Dequeue all board 'active' requests for all devices and set
- * the request status to DID_RESET. A pointer to the last request
- * is returned in 'last_scp'.
- */
- if (done_scp == NULL) {
- done_scp =
- asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
- for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- } else {
- /* Append to 'done_scp' at the end with 'last_scp'. */
- ASC_ASSERT(last_scp != NULL);
- last_scp->host_scribble =
- (unsigned char *)asc_dequeue_list(&boardp->active,
- &new_last_scp,
- ASC_TID_ALL);
- if (new_last_scp != NULL) {
- ASC_ASSERT(REQPNEXT(last_scp) != NULL);
- for (tscp = REQPNEXT(last_scp); tscp;
- tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- last_scp = new_last_scp;
- }
- }
-
- /*
- * Dequeue all 'waiting' requests and set the request status
- * to DID_RESET.
- */
- if (done_scp == NULL) {
- done_scp =
- asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
- for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- } else {
- /* Append to 'done_scp' at the end with 'last_scp'. */
- ASC_ASSERT(last_scp != NULL);
- last_scp->host_scribble =
- (unsigned char *)asc_dequeue_list(&boardp->waiting,
- &new_last_scp,
- ASC_TID_ALL);
- if (new_last_scp != NULL) {
- ASC_ASSERT(REQPNEXT(last_scp) != NULL);
- for (tscp = REQPNEXT(last_scp); tscp;
- tscp = REQPNEXT(tscp)) {
- tscp->result = HOST_BYTE(DID_RESET);
- }
- last_scp = new_last_scp;
- }
- }
+ printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
- /* Save the time of the most recently completed reset. */
- boardp->last_reset = jiffies;
+ printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
+ (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
- /* Clear reset flag. */
- boardp->flags &= ~ASC_HOST_IN_RESET;
- spin_unlock_irqrestore(&boardp->lock, flags);
+ printk(" sdtr_able 0x%x, wdtr_able 0x%x\n",
+ (unsigned)h->sdtr_able, (unsigned)h->wdtr_able);
- /*
- * Complete all the 'done_scp' requests.
- */
- if (done_scp != NULL) {
- asc_scsi_done_list(done_scp);
- }
+ printk(" start_motor 0x%x, scsi_reset_wait 0x%x\n",
+ (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
- ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
+ printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
+ (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
+ (ulong)h->carr_freelist);
- return ret;
-}
+ printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
+ (ulong)h->icq_sp, (ulong)h->irq_sp);
-/*
- * advansys_biosparam()
- *
- * Translate disk drive geometry if the "BIOS greater than 1 GB"
- * support is enabled for a drive.
- *
- * ip (information pointer) is an int array with the following definition:
- * ip[0]: heads
- * ip[1]: sectors
- * ip[2]: cylinders
- */
-static int
-advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
- sector_t capacity, int ip[])
-{
- asc_board_t *boardp;
+ printk(" no_scam 0x%x, tagqng_able 0x%x\n",
+ (unsigned)h->no_scam, (unsigned)h->tagqng_able);
- ASC_DBG(1, "advansys_biosparam: begin\n");
- ASC_STATS(sdev->host, biosparam);
- boardp = ASC_BOARDP(sdev->host);
- if (ASC_NARROW_BOARD(boardp)) {
- if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
- ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
- ip[0] = 255;
- ip[1] = 63;
- } else {
- ip[0] = 64;
- ip[1] = 32;
- }
- } else {
- if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
- BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
- ip[0] = 255;
- ip[1] = 63;
- } else {
- ip[0] = 64;
- ip[1] = 32;
- }
- }
- ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
- ASC_DBG(1, "advansys_biosparam: end\n");
- return 0;
+ printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
+ (unsigned)h->chip_scsi_id, (ulong)h->cfg);
}
-static int __init advansys_detect(struct scsi_host_template *tpnt);
-static int advansys_release(struct Scsi_Host *shp);
-
-static struct scsi_host_template driver_template = {
- .proc_name = "advansys",
-#ifdef CONFIG_PROC_FS
- .proc_info = advansys_proc_info,
-#endif
- .name = "advansys",
- .detect = advansys_detect,
- .release = advansys_release,
- .info = advansys_info,
- .queuecommand = advansys_queuecommand,
- .eh_bus_reset_handler = advansys_reset,
- .bios_param = advansys_biosparam,
- .slave_configure = advansys_slave_configure,
- /*
- * Because the driver may control an ISA adapter 'unchecked_isa_dma'
- * must be set. The flag will be cleared in advansys_detect for non-ISA
- * adapters. Refer to the comment in scsi_module.c for more information.
- */
- .unchecked_isa_dma = 1,
- /*
- * All adapters controlled by this driver are capable of large
- * scatter-gather lists. According to the mid-level SCSI documentation
- * this obviates any performance gain provided by setting
- * 'use_clustering'. But empirically while CPU utilization is increased
- * by enabling clustering, I/O throughput increases as well.
- */
- .use_clustering = ENABLE_CLUSTERING,
-};
-
-#include "scsi_module.c"
-
-/*
- * --- Miscellaneous Driver Functions
- */
-
/*
- * First-level interrupt handler.
+ * asc_prt_adv_dvc_cfg()
*
- * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
- * all boards are currently checked for interrupts on each interrupt, 'dev_id'
- * is not referenced. 'dev_id' could be used to identify an interrupt passed
- * to the AdvanSys driver which is for a device sharing an interrupt with
- * an AdvanSys adapter.
+ * Display an ADV_DVC_CFG structure.
*/
-static irqreturn_t advansys_interrupt(int irq, void *dev_id)
+static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
{
- ulong flags;
- int i;
- asc_board_t *boardp;
- struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
- struct scsi_cmnd *new_last_scp;
- struct Scsi_Host *shost;
-
- ASC_DBG(1, "advansys_interrupt: begin\n");
-
- /*
- * Check for interrupts on all boards.
- * AscISR() will call asc_isr_callback().
- */
- for (i = 0; i < asc_board_count; i++) {
- shost = asc_host[i];
- boardp = ASC_BOARDP(shost);
- ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
- i, (ulong)boardp);
- spin_lock_irqsave(&boardp->lock, flags);
- if (ASC_NARROW_BOARD(boardp)) {
- /*
- * Narrow Board
- */
- if (AscIsIntPending(shost->io_port)) {
- ASC_STATS(shost, interrupt);
- ASC_DBG(1,
- "advansys_interrupt: before AscISR()\n");
- AscISR(&boardp->dvc_var.asc_dvc_var);
- }
- } else {
- /*
- * Wide Board
- */
- ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
- if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
- ASC_STATS(shost, interrupt);
- }
- }
-
- /*
- * Start waiting requests and create a list of completed requests.
- *
- * If a reset request is being performed for the board, the reset
- * handler will complete pending requests after it has completed.
- */
- if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
- ASC_DBG2(1,
- "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n",
- (ulong)done_scp, (ulong)last_scp);
-
- /* Start any waiting commands for the board. */
- if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
- ASC_DBG(1,
- "advansys_interrupt: before asc_execute_queue()\n");
- asc_execute_queue(&boardp->waiting);
- }
-
- /*
- * Add to the list of requests that must be completed.
- *
- * 'done_scp' will always be NULL on the first iteration
- * of this loop. 'last_scp' is set at the same time as
- * 'done_scp'.
- */
- if (done_scp == NULL) {
- done_scp =
- asc_dequeue_list(&boardp->done, &last_scp,
- ASC_TID_ALL);
- } else {
- ASC_ASSERT(last_scp != NULL);
- last_scp->host_scribble =
- (unsigned char *)asc_dequeue_list(&boardp->
- done,
- &new_last_scp,
- ASC_TID_ALL);
- if (new_last_scp != NULL) {
- ASC_ASSERT(REQPNEXT(last_scp) != NULL);
- last_scp = new_last_scp;
- }
- }
- }
- spin_unlock_irqrestore(&boardp->lock, flags);
- }
-
- /*
- * If interrupts were enabled on entry, then they
- * are now enabled here.
- *
- * Complete all requests on the done list.
- */
-
- asc_scsi_done_list(done_scp);
+ printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
- ASC_DBG(1, "advansys_interrupt: end\n");
- return IRQ_HANDLED;
-}
+ printk(" disc_enable 0x%x, termination 0x%x\n",
+ h->disc_enable, h->termination);
-/*
- * Set the number of commands to queue per device for the
- * specified host adapter.
- */
-static int advansys_slave_configure(struct scsi_device *device)
-{
- asc_board_t *boardp;
+ printk(" chip_version 0x%x, mcode_date 0x%x\n",
+ h->chip_version, h->mcode_date);
- boardp = ASC_BOARDP(device->host);
- boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
- /*
- * Save a pointer to the device and set its initial/maximum
- * queue depth. Only save the pointer for a lun0 dev though.
- */
- if (device->lun == 0)
- boardp->device[device->id] = device;
- if (device->tagged_supported) {
- if (ASC_NARROW_BOARD(boardp)) {
- scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
- boardp->dvc_var.asc_dvc_var.
- max_dvc_qng[device->id]);
- } else {
- scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
- boardp->dvc_var.adv_dvc_var.
- max_dvc_qng);
- }
- } else {
- scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
- }
- ASC_DBG4(1,
- "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
- (ulong)device, (ulong)boardp, device->id, device->queue_depth);
- return 0;
+ printk(" mcode_version 0x%x, control_flag 0x%x\n",
+ h->mcode_version, h->control_flag);
}
/*
- * Complete all requests on the singly linked list pointed
- * to by 'scp'.
- *
- * Interrupts can be enabled on entry.
+ * asc_prt_scsi_host()
*/
-static void asc_scsi_done_list(struct scsi_cmnd *scp)
+static void asc_prt_scsi_host(struct Scsi_Host *s)
{
- struct scsi_cmnd *tscp;
-
- ASC_DBG(2, "asc_scsi_done_list: begin\n");
- while (scp != NULL) {
- asc_board_t *boardp;
- struct device *dev;
+ struct asc_board *boardp = shost_priv(s);
- ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
- tscp = REQPNEXT(scp);
- scp->host_scribble = NULL;
-
- boardp = ASC_BOARDP(scp->device->host);
-
- if (ASC_NARROW_BOARD(boardp))
- dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
- else
- dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
+ printk("Scsi_Host at addr 0x%p, device %s\n", s, boardp->dev->bus_id);
+ printk(" host_busy %u, host_no %d, last_reset %d,\n",
+ s->host_busy, s->host_no, (unsigned)s->last_reset);
- if (scp->use_sg)
- dma_unmap_sg(dev,
- (struct scatterlist *)scp->request_buffer,
- scp->use_sg, scp->sc_data_direction);
- else if (scp->request_bufflen)
- dma_unmap_single(dev, scp->SCp.dma_handle,
- scp->request_bufflen,
- scp->sc_data_direction);
+ printk(" base 0x%lx, io_port 0x%lx, irq %d,\n",
+ (ulong)s->base, (ulong)s->io_port, boardp->irq);
- ASC_STATS(scp->device->host, done);
- ASC_ASSERT(scp->scsi_done != NULL);
+ printk(" dma_channel %d, this_id %d, can_queue %d,\n",
+ s->dma_channel, s->this_id, s->can_queue);
- scp->scsi_done(scp);
+ printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
+ s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
- scp = tscp;
+ if (ASC_NARROW_BOARD(boardp)) {
+ asc_prt_asc_dvc_var(&boardp->dvc_var.asc_dvc_var);
+ asc_prt_asc_dvc_cfg(&boardp->dvc_cfg.asc_dvc_cfg);
+ } else {
+ asc_prt_adv_dvc_var(&boardp->dvc_var.adv_dvc_var);
+ asc_prt_adv_dvc_cfg(&boardp->dvc_cfg.adv_dvc_cfg);
}
- ASC_DBG(2, "asc_scsi_done_list: done\n");
- return;
}
/*
- * Execute a single 'Scsi_Cmnd'.
- *
- * The function 'done' is called when the request has been completed.
- *
- * Scsi_Cmnd:
- *
- * host - board controlling device
- * device - device to send command
- * target - target of device
- * lun - lun of device
- * cmd_len - length of SCSI CDB
- * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
- * use_sg - if non-zero indicates scatter-gather request with use_sg elements
- *
- * if (use_sg == 0) {
- * request_buffer - buffer address for request
- * request_bufflen - length of request buffer
- * } else {
- * request_buffer - pointer to scatterlist structure
- * }
- *
- * sense_buffer - sense command buffer
- *
- * result (4 bytes of an int):
- * Byte Meaning
- * 0 SCSI Status Byte Code
- * 1 SCSI One Byte Message Code
- * 2 Host Error Code
- * 3 Mid-Level Error Code
- *
- * host driver fields:
- * SCp - Scsi_Pointer used for command processing status
- * scsi_done - used to save caller's done function
- * host_scribble - used for pointer to another struct scsi_cmnd
- *
- * If this function returns ASC_NOERROR the request has been enqueued
- * on the board's 'active' queue and will be completed from the
- * interrupt handler.
- *
- * If this function returns ASC_NOERROR the request has been enqueued
- * on the board's 'done' queue and must be completed by the caller.
+ * asc_prt_hex()
*
- * If ASC_BUSY is returned the request will be enqueued by the
- * caller on the target's waiting queue and re-tried later.
+ * Print hexadecimal output in 4 byte groupings 32 bytes
+ * or 8 double-words per line.
*/
-static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
+static void asc_prt_hex(char *f, uchar *s, int l)
{
- asc_board_t *boardp;
- ASC_DVC_VAR *asc_dvc_varp;
- ADV_DVC_VAR *adv_dvc_varp;
- ADV_SCSI_REQ_Q *adv_scsiqp;
- struct scsi_device *device;
- int ret;
-
- ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
- (ulong)scp, (ulong)scp->scsi_done);
-
- boardp = ASC_BOARDP(scp->device->host);
- device = boardp->device[scp->device->id];
+ int i;
+ int j;
+ int k;
+ int m;
- if (ASC_NARROW_BOARD(boardp)) {
- /*
- * Build and execute Narrow Board request.
- */
+ printk("%s: (%d bytes)\n", f, l);
- asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+ for (i = 0; i < l; i += 32) {
- /*
- * Build Asc Library request structure using the
- * global structures 'asc_scsi_req' and 'asc_sg_head'.
- *
- * If an error is returned, then the request has been
- * queued on the board done queue. It will be completed
- * by the caller.
- *
- * asc_build_req() can not return ASC_BUSY.
- */
- if (asc_build_req(boardp, scp) == ASC_ERROR) {
- ASC_STATS(scp->device->host, build_error);
- return ASC_ERROR;
+ /* Display a maximum of 8 double-words per line. */
+ if ((k = (l - i) / 4) >= 8) {
+ k = 8;
+ m = 0;
+ } else {
+ m = (l - i) % 4;
}
- /*
- * Execute the command. If there is no error, add the command
- * to the active queue.
- */
- switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
- case ASC_NOERROR:
- ASC_STATS(scp->device->host, exe_noerror);
- /*
- * Increment monotonically increasing per device successful
- * request counter. Wrapping doesn't matter.
- */
- boardp->reqcnt[scp->device->id]++;
- asc_enqueue(&boardp->active, scp, ASC_BACK);
- ASC_DBG(1,
- "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
- break;
- case ASC_BUSY:
- /*
- * Caller will enqueue request on the target's waiting queue
- * and retry later.
- */
- ASC_STATS(scp->device->host, exe_busy);
- break;
- case ASC_ERROR:
- ASC_PRINT2
- ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
- boardp->id, asc_dvc_varp->err_code);
- ASC_STATS(scp->device->host, exe_error);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
- default:
- ASC_PRINT2
- ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
- boardp->id, asc_dvc_varp->err_code);
- ASC_STATS(scp->device->host, exe_unknown);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
+ for (j = 0; j < k; j++) {
+ printk(" %2.2X%2.2X%2.2X%2.2X",
+ (unsigned)s[i + (j * 4)],
+ (unsigned)s[i + (j * 4) + 1],
+ (unsigned)s[i + (j * 4) + 2],
+ (unsigned)s[i + (j * 4) + 3]);
}
- } else {
- /*
- * Build and execute Wide Board request.
- */
- adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
- /*
- * Build and get a pointer to an Adv Library request structure.
- *
- * If the request is successfully built then send it below,
- * otherwise return with an error.
- */
- switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
- case ASC_NOERROR:
- ASC_DBG(3,
- "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
- break;
- case ASC_BUSY:
- ASC_DBG(1,
- "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
- /*
- * If busy is returned the request has not been enqueued.
- * It will be enqueued by the caller on the target's waiting
- * queue and retried later.
- *
- * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
- * count wide board busy conditions. They are updated in
- * adv_build_req and adv_get_sglist, respectively.
- */
- return ASC_BUSY;
- case ASC_ERROR:
- /*
- * If an error is returned, then the request has been
- * queued on the board done queue. It will be completed
- * by the caller.
- */
+ switch (m) {
+ case 0:
default:
- ASC_DBG(1,
- "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
- ASC_STATS(scp->device->host, build_error);
- return ASC_ERROR;
- }
-
- /*
- * Execute the command. If there is no error, add the command
- * to the active queue.
- */
- switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
- case ASC_NOERROR:
- ASC_STATS(scp->device->host, exe_noerror);
- /*
- * Increment monotonically increasing per device successful
- * request counter. Wrapping doesn't matter.
- */
- boardp->reqcnt[scp->device->id]++;
- asc_enqueue(&boardp->active, scp, ASC_BACK);
- ASC_DBG(1,
- "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
break;
- case ASC_BUSY:
- /*
- * Caller will enqueue request on the target's waiting queue
- * and retry later.
- */
- ASC_STATS(scp->device->host, exe_busy);
+ case 1:
+ printk(" %2.2X", (unsigned)s[i + (j * 4)]);
break;
- case ASC_ERROR:
- ASC_PRINT2
- ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
- boardp->id, adv_dvc_varp->err_code);
- ASC_STATS(scp->device->host, exe_error);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
+ case 2:
+ printk(" %2.2X%2.2X",
+ (unsigned)s[i + (j * 4)],
+ (unsigned)s[i + (j * 4) + 1]);
break;
- default:
- ASC_PRINT2
- ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
- boardp->id, adv_dvc_varp->err_code);
- ASC_STATS(scp->device->host, exe_unknown);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
+ case 3:
+ printk(" %2.2X%2.2X%2.2X",
+ (unsigned)s[i + (j * 4) + 1],
+ (unsigned)s[i + (j * 4) + 2],
+ (unsigned)s[i + (j * 4) + 3]);
break;
}
- }
-
- ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
- return ret;
-}
-/*
- * Build a request structure for the Asc Library (Narrow Board).
- *
- * The global structures 'asc_scsi_q' and 'asc_sg_head' are
- * used to build the request.
- *
- * If an error occurs, then queue the request on the board done
- * queue and return ASC_ERROR.
- */
-static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
-{
- struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
-
- /*
- * Mutually exclusive access is required to 'asc_scsi_q' and
- * 'asc_sg_head' until after the request is started.
- */
- memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
-
- /*
- * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
- */
- asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
-
- /*
- * Build the ASC_SCSI_Q request.
- *
- * For narrow boards a CDB length maximum of 12 bytes
- * is supported.
- */
- if (scp->cmd_len > ASC_MAX_CDB_LEN) {
- ASC_PRINT3
- ("asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %d\n",
- boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- return ASC_ERROR;
- }
- asc_scsi_q.cdbptr = &scp->cmnd[0];
- asc_scsi_q.q2.cdb_len = scp->cmd_len;
- asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
- asc_scsi_q.q1.target_lun = scp->device->lun;
- asc_scsi_q.q2.target_ix =
- ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
- asc_scsi_q.q1.sense_addr =
- cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
- asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
-
- /*
- * If there are any outstanding requests for the current target,
- * then every 255th request send an ORDERED request. This heuristic
- * tries to retain the benefit of request sorting while preventing
- * request starvation. 255 is the max number of tags or pending commands
- * a device may have outstanding.
- *
- * The request count is incremented below for every successfully
- * started request.
- *
- */
- if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
- (boardp->reqcnt[scp->device->id] % 255) == 0) {
- asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
- } else {
- asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
- }
-
- /*
- * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
- * buffer command.
- */
- if (scp->use_sg == 0) {
- /*
- * CDB request of single contiguous buffer.
- */
- ASC_STATS(scp->device->host, cont_cnt);
- scp->SCp.dma_handle = scp->request_bufflen ?
- dma_map_single(dev, scp->request_buffer,
- scp->request_bufflen,
- scp->sc_data_direction) : 0;
- asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
- asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
- ASC_STATS_ADD(scp->device->host, cont_xfer,
- ASC_CEILING(scp->request_bufflen, 512));
- asc_scsi_q.q1.sg_queue_cnt = 0;
- asc_scsi_q.sg_head = NULL;
- } else {
- /*
- * CDB scatter-gather request list.
- */
- int sgcnt;
- int use_sg;
- struct scatterlist *slp;
-
- slp = (struct scatterlist *)scp->request_buffer;
- use_sg =
- dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
-
- if (use_sg > scp->device->host->sg_tablesize) {
- ASC_PRINT3
- ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
- boardp->id, use_sg,
- scp->device->host->sg_tablesize);
- dma_unmap_sg(dev, slp, scp->use_sg,
- scp->sc_data_direction);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- return ASC_ERROR;
- }
-
- ASC_STATS(scp->device->host, sg_cnt);
-
- /*
- * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
- * structure to point to it.
- */
- memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
-
- asc_scsi_q.q1.cntl |= QC_SG_HEAD;
- asc_scsi_q.sg_head = &asc_sg_head;
- asc_scsi_q.q1.data_cnt = 0;
- asc_scsi_q.q1.data_addr = 0;
- /* This is a byte value, otherwise it would need to be swapped. */
- asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
- ASC_STATS_ADD(scp->device->host, sg_elem,
- asc_sg_head.entry_cnt);
-
- /*
- * Convert scatter-gather list into ASC_SG_HEAD list.
- */
- for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
- asc_sg_head.sg_list[sgcnt].addr =
- cpu_to_le32(sg_dma_address(slp));
- asc_sg_head.sg_list[sgcnt].bytes =
- cpu_to_le32(sg_dma_len(slp));
- ASC_STATS_ADD(scp->device->host, sg_xfer,
- ASC_CEILING(sg_dma_len(slp), 512));
- }
+ printk("\n");
}
-
- ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
- ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
-
- return ASC_NOERROR;
}
/*
- * Build a request structure for the Adv Library (Wide Board).
- *
- * If an adv_req_t can not be allocated to issue the request,
- * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
- *
- * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
- * microcode for DMA addresses or math operations are byte swapped
- * to little-endian order.
+ * asc_prt_asc_scsi_q()
*/
-static int
-adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
- ADV_SCSI_REQ_Q **adv_scsiqpp)
+static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
{
- adv_req_t *reqp;
- ADV_SCSI_REQ_Q *scsiqp;
+ ASC_SG_HEAD *sgp;
int i;
- int ret;
- struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
- /*
- * Allocate an adv_req_t structure from the board to execute
- * the command.
- */
- if (boardp->adv_reqp == NULL) {
- ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
- ASC_STATS(scp->device->host, adv_build_noreq);
- return ASC_BUSY;
- } else {
- reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp->next_reqp;
- reqp->next_reqp = NULL;
- }
-
- /*
- * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
- */
- scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
-
- /*
- * Initialize the structure.
- */
- scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
-
- /*
- * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
- */
- scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
-
- /*
- * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
- */
- reqp->cmndp = scp;
-
- /*
- * Build the ADV_SCSI_REQ_Q request.
- */
-
- /*
- * Set CDB length and copy it to the request structure.
- * For wide boards a CDB length maximum of 16 bytes
- * is supported.
- */
- if (scp->cmd_len > ADV_MAX_CDB_LEN) {
- ASC_PRINT3
- ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
- boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- return ASC_ERROR;
- }
- scsiqp->cdb_len = scp->cmd_len;
- /* Copy first 12 CDB bytes to cdb[]. */
- for (i = 0; i < scp->cmd_len && i < 12; i++) {
- scsiqp->cdb[i] = scp->cmnd[i];
- }
- /* Copy last 4 CDB bytes, if present, to cdb16[]. */
- for (; i < scp->cmd_len; i++) {
- scsiqp->cdb16[i - 12] = scp->cmnd[i];
- }
-
- scsiqp->target_id = scp->device->id;
- scsiqp->target_lun = scp->device->lun;
-
- scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
- scsiqp->sense_len = sizeof(scp->sense_buffer);
-
- /*
- * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
- * buffer command.
- */
-
- scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
- scsiqp->vdata_addr = scp->request_buffer;
- scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
-
- if (scp->use_sg == 0) {
- /*
- * CDB request of single contiguous buffer.
- */
- reqp->sgblkp = NULL;
- scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
- if (scp->request_bufflen) {
- scsiqp->vdata_addr = scp->request_buffer;
- scp->SCp.dma_handle =
- dma_map_single(dev, scp->request_buffer,
- scp->request_bufflen,
- scp->sc_data_direction);
- } else {
- scsiqp->vdata_addr = NULL;
- scp->SCp.dma_handle = 0;
- }
- scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
- scsiqp->sg_list_ptr = NULL;
- scsiqp->sg_real_addr = 0;
- ASC_STATS(scp->device->host, cont_cnt);
- ASC_STATS_ADD(scp->device->host, cont_xfer,
- ASC_CEILING(scp->request_bufflen, 512));
- } else {
- /*
- * CDB scatter-gather request list.
- */
- struct scatterlist *slp;
- int use_sg;
-
- slp = (struct scatterlist *)scp->request_buffer;
- use_sg =
- dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
-
- if (use_sg > ADV_MAX_SG_LIST) {
- ASC_PRINT3
- ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
- boardp->id, use_sg,
- scp->device->host->sg_tablesize);
- dma_unmap_sg(dev, slp, scp->use_sg,
- scp->sc_data_direction);
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
+ printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
- /*
- * Free the 'adv_req_t' structure by adding it back to the
- * board free list.
- */
- reqp->next_reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp;
+ printk
+ (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
+ q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
+ q->q2.tag_code);
- return ASC_ERROR;
- }
+ printk
+ (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+ (ulong)le32_to_cpu(q->q1.data_addr),
+ (ulong)le32_to_cpu(q->q1.data_cnt),
+ (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
- if ((ret =
- adv_get_sglist(boardp, reqp, scp,
- use_sg)) != ADV_SUCCESS) {
- /*
- * Free the adv_req_t structure by adding it back to the
- * board free list.
- */
- reqp->next_reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp;
+ printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
+ (ulong)q->cdbptr, q->q2.cdb_len,
+ (ulong)q->sg_head, q->q1.sg_queue_cnt);
- return ret;
+ if (q->sg_head) {
+ sgp = q->sg_head;
+ printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
+ printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
+ sgp->queue_cnt);
+ for (i = 0; i < sgp->entry_cnt; i++) {
+ printk(" [%u]: addr 0x%lx, bytes %lu\n",
+ i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
+ (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
}
- ASC_STATS(scp->device->host, sg_cnt);
- ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
}
-
- ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
- ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
-
- *adv_scsiqpp = scsiqp;
-
- return ASC_NOERROR;
}
/*
- * Build scatter-gather list for Adv Library (Wide Board).
- *
- * Additional ADV_SG_BLOCK structures will need to be allocated
- * if the total number of scatter-gather elements exceeds
- * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
- * assumed to be physically contiguous.
- *
- * Return:
- * ADV_SUCCESS(1) - SG List successfully created
- * ADV_ERROR(-1) - SG List creation failed
+ * asc_prt_asc_qdone_info()
*/
-static int
-adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
- int use_sg)
+static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
{
- adv_sgblk_t *sgblkp;
- ADV_SCSI_REQ_Q *scsiqp;
- struct scatterlist *slp;
- int sg_elem_cnt;
- ADV_SG_BLOCK *sg_block, *prev_sg_block;
- ADV_PADDR sg_block_paddr;
- int i;
-
- scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
- slp = (struct scatterlist *)scp->request_buffer;
- sg_elem_cnt = use_sg;
- prev_sg_block = NULL;
- reqp->sgblkp = NULL;
-
- do {
- /*
- * Allocate a 'adv_sgblk_t' structure from the board free
- * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
- * (15) scatter-gather elements.
- */
- if ((sgblkp = boardp->adv_sgblkp) == NULL) {
- ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
- ASC_STATS(scp->device->host, adv_build_nosg);
-
- /*
- * Allocation failed. Free 'adv_sgblk_t' structures already
- * allocated for the request.
- */
- while ((sgblkp = reqp->sgblkp) != NULL) {
- /* Remove 'sgblkp' from the request list. */
- reqp->sgblkp = sgblkp->next_sgblkp;
-
- /* Add 'sgblkp' to the board free list. */
- sgblkp->next_sgblkp = boardp->adv_sgblkp;
- boardp->adv_sgblkp = sgblkp;
- }
- return ASC_BUSY;
- } else {
- /* Complete 'adv_sgblk_t' board allocation. */
- boardp->adv_sgblkp = sgblkp->next_sgblkp;
- sgblkp->next_sgblkp = NULL;
-
- /*
- * Get 8 byte aligned virtual and physical addresses for
- * the allocated ADV_SG_BLOCK structure.
- */
- sg_block =
- (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
- sg_block_paddr = virt_to_bus(sg_block);
-
- /*
- * Check if this is the first 'adv_sgblk_t' for the request.
- */
- if (reqp->sgblkp == NULL) {
- /* Request's first scatter-gather block. */
- reqp->sgblkp = sgblkp;
-
- /*
- * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
- * address pointers.
- */
- scsiqp->sg_list_ptr = sg_block;
- scsiqp->sg_real_addr =
- cpu_to_le32(sg_block_paddr);
- } else {
- /* Request's second or later scatter-gather block. */
- sgblkp->next_sgblkp = reqp->sgblkp;
- reqp->sgblkp = sgblkp;
-
- /*
- * Point the previous ADV_SG_BLOCK structure to
- * the newly allocated ADV_SG_BLOCK structure.
- */
- ASC_ASSERT(prev_sg_block != NULL);
- prev_sg_block->sg_ptr =
- cpu_to_le32(sg_block_paddr);
- }
- }
-
- for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
- sg_block->sg_list[i].sg_addr =
- cpu_to_le32(sg_dma_address(slp));
- sg_block->sg_list[i].sg_count =
- cpu_to_le32(sg_dma_len(slp));
- ASC_STATS_ADD(scp->device->host, sg_xfer,
- ASC_CEILING(sg_dma_len(slp), 512));
-
- if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
- sg_block->sg_cnt = i + 1;
- sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
- return ADV_SUCCESS;
- }
- slp++;
- }
- sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
- prev_sg_block = sg_block;
- }
- while (1);
- /* NOTREACHED */
+ printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
+ printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
+ (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
+ q->d2.tag_code);
+ printk
+ (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
+ q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
}
/*
- * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
+ * asc_prt_adv_sgblock()
*
- * Interrupt callback function for the Narrow SCSI Asc Library.
+ * Display an ADV_SG_BLOCK structure.
*/
-static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
+static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
{
- asc_board_t *boardp;
- struct scsi_cmnd *scp;
- struct Scsi_Host *shost;
int i;
- ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
- (ulong)asc_dvc_varp, (ulong)qdonep);
- ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
-
- /*
- * Get the struct scsi_cmnd structure and Scsi_Host structure for the
- * command that has been completed.
- */
- scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
- ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
-
- if (scp == NULL) {
- ASC_PRINT("asc_isr_callback: scp is NULL\n");
- return;
- }
- ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
-
- /*
- * If the request's host pointer is not valid, display a
- * message and return.
- */
- shost = scp->device->host;
- for (i = 0; i < asc_board_count; i++) {
- if (asc_host[i] == shost) {
- break;
- }
- }
- if (i == asc_board_count) {
- ASC_PRINT2
- ("asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
- (ulong)scp, (ulong)shost);
- return;
- }
-
- ASC_STATS(shost, callback);
- ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
-
- /*
- * If the request isn't found on the active queue, it may
- * have been removed to handle a reset request.
- * Display a message and return.
- */
- boardp = ASC_BOARDP(shost);
- ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
- if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
- ASC_PRINT2
- ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
- boardp->id, (ulong)scp);
- return;
- }
-
- /*
- * 'qdonep' contains the command's ending status.
- */
- switch (qdonep->d3.done_stat) {
- case QD_NO_ERROR:
- ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
- scp->result = 0;
-
- /*
- * If an INQUIRY command completed successfully, then call
- * the AscInquiryHandling() function to set-up the device.
- */
- if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
- (scp->request_bufflen - qdonep->remain_bytes) >= 8) {
- AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
- (ASC_SCSI_INQUIRY *)scp->
- request_buffer);
- }
-
- /*
- * Check for an underrun condition.
- *
- * If there was no error and an underrun condition, then
- * then return the number of underrun bytes.
- */
- if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
- qdonep->remain_bytes <= scp->request_bufflen) {
- ASC_DBG1(1,
- "asc_isr_callback: underrun condition %u bytes\n",
- (unsigned)qdonep->remain_bytes);
- scp->resid = qdonep->remain_bytes;
- }
- break;
-
- case QD_WITH_ERROR:
- ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
- switch (qdonep->d3.host_stat) {
- case QHSTA_NO_ERROR:
- if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
- ASC_DBG(2,
- "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
- ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
- sizeof(scp->sense_buffer));
- /*
- * Note: The 'status_byte()' macro used by target drivers
- * defined in scsi.h shifts the status byte returned by
- * host drivers right by 1 bit. This is why target drivers
- * also use right shifted status byte definitions. For
- * instance target drivers use CHECK_CONDITION, defined to
- * 0x1, instead of the SCSI defined check condition value
- * of 0x2. Host drivers are supposed to return the status
- * byte as it is defined by SCSI.
- */
- scp->result = DRIVER_BYTE(DRIVER_SENSE) |
- STATUS_BYTE(qdonep->d3.scsi_stat);
- } else {
- scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
- }
- break;
-
- default:
- /* QHSTA error occurred */
- ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
- qdonep->d3.host_stat);
- scp->result = HOST_BYTE(DID_BAD_TARGET);
- break;
- }
- break;
-
- case QD_ABORTED_BY_HOST:
- ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
- scp->result =
- HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
- scsi_msg) |
- STATUS_BYTE(qdonep->d3.scsi_stat);
- break;
-
- default:
- ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
- qdonep->d3.done_stat);
- scp->result =
- HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
- scsi_msg) |
- STATUS_BYTE(qdonep->d3.scsi_stat);
- break;
- }
-
- /*
- * If the 'init_tidmask' bit isn't already set for the target and the
- * current request finished normally, then set the bit for the target
- * to indicate that a device is present.
- */
- if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
- qdonep->d3.done_stat == QD_NO_ERROR &&
- qdonep->d3.host_stat == QHSTA_NO_ERROR) {
- boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+ printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
+ (ulong)b, sgblockno);
+ printk(" sg_cnt %u, sg_ptr 0x%lx\n",
+ b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
+ BUG_ON(b->sg_cnt > NO_OF_SG_PER_BLOCK);
+ if (b->sg_ptr != 0)
+ BUG_ON(b->sg_cnt != NO_OF_SG_PER_BLOCK);
+ for (i = 0; i < b->sg_cnt; i++) {
+ printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
+ i, (ulong)b->sg_list[i].sg_addr,
+ (ulong)b->sg_list[i].sg_count);
}
-
- /*
- * Because interrupts may be enabled by the 'struct scsi_cmnd' done
- * function, add the command to the end of the board's done queue.
- * The done function for the command will be called from
- * advansys_interrupt().
- */
- asc_enqueue(&boardp->done, scp, ASC_BACK);
-
- return;
}
/*
- * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
+ * asc_prt_adv_scsi_req_q()
*
- * Callback function for the Wide SCSI Adv Library.
+ * Display an ADV_SCSI_REQ_Q structure.
*/
-static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
+static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
{
- asc_board_t *boardp;
- adv_req_t *reqp;
- adv_sgblk_t *sgblkp;
- struct scsi_cmnd *scp;
- struct Scsi_Host *shost;
- int i;
- ADV_DCNT resid_cnt;
-
- ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
- (ulong)adv_dvc_varp, (ulong)scsiqp);
- ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+ int sg_blk_cnt;
+ struct asc_sg_block *sg_ptr;
- /*
- * Get the adv_req_t structure for the command that has been
- * completed. The adv_req_t structure actually contains the
- * completed ADV_SCSI_REQ_Q structure.
- */
- reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
- ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
- if (reqp == NULL) {
- ASC_PRINT("adv_isr_callback: reqp is NULL\n");
- return;
- }
+ printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
- /*
- * Get the struct scsi_cmnd structure and Scsi_Host structure for the
- * command that has been completed.
- *
- * Note: The adv_req_t request structure and adv_sgblk_t structure,
- * if any, are dropped, because a board structure pointer can not be
- * determined.
- */
- scp = reqp->cmndp;
- ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
- if (scp == NULL) {
- ASC_PRINT
- ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
- return;
- }
- ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+ printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
+ q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
- /*
- * If the request's host pointer is not valid, display a message
- * and return.
- */
- shost = scp->device->host;
- for (i = 0; i < asc_board_count; i++) {
- if (asc_host[i] == shost) {
- break;
- }
- }
- /*
- * Note: If the host structure is not found, the adv_req_t request
- * structure and adv_sgblk_t structure, if any, is dropped.
- */
- if (i == asc_board_count) {
- ASC_PRINT2
- ("adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
- (ulong)scp, (ulong)shost);
- return;
- }
+ printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
+ q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
- ASC_STATS(shost, callback);
- ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
+ printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+ (ulong)le32_to_cpu(q->data_cnt),
+ (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
- /*
- * If the request isn't found on the active queue, it may have been
- * removed to handle a reset request. Display a message and return.
- *
- * Note: Because the structure may still be in use don't attempt
- * to free the adv_req_t and adv_sgblk_t, if any, structures.
- */
- boardp = ASC_BOARDP(shost);
- ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
- if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
- ASC_PRINT2
- ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
- boardp->id, (ulong)scp);
- return;
- }
+ printk
+ (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
+ q->cdb_len, q->done_status, q->host_status, q->scsi_status);
- /*
- * 'done_status' contains the command's ending status.
- */
- switch (scsiqp->done_status) {
- case QD_NO_ERROR:
- ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
- scp->result = 0;
+ printk(" sg_working_ix 0x%x, target_cmd %u\n",
+ q->sg_working_ix, q->target_cmd);
- /*
- * Check for an underrun condition.
- *
- * If there was no error and an underrun condition, then
- * then return the number of underrun bytes.
- */
- resid_cnt = le32_to_cpu(scsiqp->data_cnt);
- if (scp->request_bufflen != 0 && resid_cnt != 0 &&
- resid_cnt <= scp->request_bufflen) {
- ASC_DBG1(1,
- "adv_isr_callback: underrun condition %lu bytes\n",
- (ulong)resid_cnt);
- scp->resid = resid_cnt;
- }
- break;
+ printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
+ (ulong)le32_to_cpu(q->scsiq_rptr),
+ (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
- case QD_WITH_ERROR:
- ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
- switch (scsiqp->host_status) {
- case QHSTA_NO_ERROR:
- if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
- ASC_DBG(2,
- "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
- ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
- sizeof(scp->sense_buffer));
- /*
- * Note: The 'status_byte()' macro used by target drivers
- * defined in scsi.h shifts the status byte returned by
- * host drivers right by 1 bit. This is why target drivers
- * also use right shifted status byte definitions. For
- * instance target drivers use CHECK_CONDITION, defined to
- * 0x1, instead of the SCSI defined check condition value
- * of 0x2. Host drivers are supposed to return the status
- * byte as it is defined by SCSI.
- */
- scp->result = DRIVER_BYTE(DRIVER_SENSE) |
- STATUS_BYTE(scsiqp->scsi_status);
- } else {
- scp->result = STATUS_BYTE(scsiqp->scsi_status);
+ /* Display the request's ADV_SG_BLOCK structures. */
+ if (q->sg_list_ptr != NULL) {
+ sg_blk_cnt = 0;
+ while (1) {
+ /*
+ * 'sg_ptr' is a physical address. Convert it to a virtual
+ * address by indexing 'sg_blk_cnt' into the virtual address
+ * array 'sg_list_ptr'.
+ *
+ * XXX - Assumes all SG physical blocks are virtually contiguous.
+ */
+ sg_ptr =
+ &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
+ asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
+ if (sg_ptr->sg_ptr == 0) {
+ break;
}
- break;
-
- default:
- /* Some other QHSTA error occurred. */
- ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
- scsiqp->host_status);
- scp->result = HOST_BYTE(DID_BAD_TARGET);
- break;
+ sg_blk_cnt++;
}
- break;
-
- case QD_ABORTED_BY_HOST:
- ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
- scp->result =
- HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
- break;
-
- default:
- ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
- scsiqp->done_status);
- scp->result =
- HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
- break;
- }
-
- /*
- * If the 'init_tidmask' bit isn't already set for the target and the
- * current request finished normally, then set the bit for the target
- * to indicate that a device is present.
- */
- if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
- scsiqp->done_status == QD_NO_ERROR &&
- scsiqp->host_status == QHSTA_NO_ERROR) {
- boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
- }
-
- /*
- * Because interrupts may be enabled by the 'struct scsi_cmnd' done
- * function, add the command to the end of the board's done queue.
- * The done function for the command will be called from
- * advansys_interrupt().
- */
- asc_enqueue(&boardp->done, scp, ASC_BACK);
-
- /*
- * Free all 'adv_sgblk_t' structures allocated for the request.
- */
- while ((sgblkp = reqp->sgblkp) != NULL) {
- /* Remove 'sgblkp' from the request list. */
- reqp->sgblkp = sgblkp->next_sgblkp;
-
- /* Add 'sgblkp' to the board free list. */
- sgblkp->next_sgblkp = boardp->adv_sgblkp;
- boardp->adv_sgblkp = sgblkp;
}
-
- /*
- * Free the adv_req_t structure used with the command by adding
- * it back to the board free list.
- */
- reqp->next_reqp = boardp->adv_reqp;
- boardp->adv_reqp = reqp;
-
- ASC_DBG(1, "adv_isr_callback: done\n");
-
- return;
}
+#endif /* ADVANSYS_DEBUG */
/*
- * adv_async_callback() - Adv Library asynchronous event callback function.
+ * The advansys chip/microcode contains a 32-bit identifier for each command
+ * known as the 'srb'. I don't know what it stands for. The driver used
+ * to encode the scsi_cmnd pointer by calling virt_to_bus and retrieve it
+ * with bus_to_virt. Now the driver keeps a per-host map of integers to
+ * pointers. It auto-expands when full, unless it can't allocate memory.
+ * Note that an srb of 0 is treated specially by the chip/firmware, hence
+ * the return of i+1 in this routine, and the corresponding subtraction in
+ * the inverse routine.
*/
-static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
+#define BAD_SRB 0
+static u32 advansys_ptr_to_srb(struct asc_dvc_var *asc_dvc, void *ptr)
{
- switch (code) {
- case ADV_ASYNC_SCSI_BUS_RESET_DET:
- /*
- * The firmware detected a SCSI Bus reset.
- */
- ASC_DBG(0,
- "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
- break;
+ int i;
+ void **new_ptr;
- case ADV_ASYNC_RDMA_FAILURE:
- /*
- * Handle RDMA failure by resetting the SCSI Bus and
- * possibly the chip if it is unresponsive. Log the error
- * with a unique code.
- */
- ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
- AdvResetChipAndSB(adv_dvc_varp);
- break;
+ for (i = 0; i < asc_dvc->ptr_map_count; i++) {
+ if (!asc_dvc->ptr_map[i])
+ goto out;
+ }
- case ADV_HOST_SCSI_BUS_RESET:
- /*
- * Host generated SCSI bus reset occurred.
- */
- ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
- break;
+ if (asc_dvc->ptr_map_count == 0)
+ asc_dvc->ptr_map_count = 1;
+ else
+ asc_dvc->ptr_map_count *= 2;
- default:
- ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
- break;
- }
+ new_ptr = krealloc(asc_dvc->ptr_map,
+ asc_dvc->ptr_map_count * sizeof(void *), GFP_ATOMIC);
+ if (!new_ptr)
+ return BAD_SRB;
+ asc_dvc->ptr_map = new_ptr;
+ out:
+ ASC_DBG(3, "Putting ptr %p into array offset %d\n", ptr, i);
+ asc_dvc->ptr_map[i] = ptr;
+ return i + 1;
}
-/*
- * Add a 'REQP' to the end of specified queue. Set 'tidmask'
- * to indicate a command is queued for the device.
- *
- * 'flag' may be either ASC_FRONT or ASC_BACK.
- *
- * 'REQPNEXT(reqp)' returns reqp's next pointer.
- */
-static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
+static void * advansys_srb_to_ptr(struct asc_dvc_var *asc_dvc, u32 srb)
{
- int tid;
-
- ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
- (ulong)ascq, (ulong)reqp, flag);
- ASC_ASSERT(reqp != NULL);
- ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
- tid = REQPTID(reqp);
- ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
- if (flag == ASC_FRONT) {
- reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
- ascq->q_first[tid] = reqp;
- /* If the queue was empty, set the last pointer. */
- if (ascq->q_last[tid] == NULL) {
- ascq->q_last[tid] = reqp;
- }
- } else { /* ASC_BACK */
- if (ascq->q_last[tid] != NULL) {
- ascq->q_last[tid]->host_scribble =
- (unsigned char *)reqp;
- }
- ascq->q_last[tid] = reqp;
- reqp->host_scribble = NULL;
- /* If the queue was empty, set the first pointer. */
- if (ascq->q_first[tid] == NULL) {
- ascq->q_first[tid] = reqp;
- }
- }
- /* The queue has at least one entry, set its bit. */
- ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
-#ifdef ADVANSYS_STATS
- /* Maintain request queue statistics. */
- ascq->q_tot_cnt[tid]++;
- ascq->q_cur_cnt[tid]++;
- if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
- ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
- ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
- tid, ascq->q_max_cnt[tid]);
- }
- REQPTIME(reqp) = REQTIMESTAMP();
-#endif /* ADVANSYS_STATS */
- ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
- return;
-}
+ void *ptr;
-/*
- * Return first queued 'REQP' on the specified queue for
- * the specified target device. Clear the 'tidmask' bit for
- * the device if no more commands are left queued for it.
- *
- * 'REQPNEXT(reqp)' returns reqp's next pointer.
- */
-static REQP asc_dequeue(asc_queue_t *ascq, int tid)
-{
- REQP reqp;
-
- ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
- ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
- if ((reqp = ascq->q_first[tid]) != NULL) {
- ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
- ascq->q_first[tid] = REQPNEXT(reqp);
- /* If the queue is empty, clear its bit and the last pointer. */
- if (ascq->q_first[tid] == NULL) {
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
- ASC_ASSERT(ascq->q_last[tid] == reqp);
- ascq->q_last[tid] = NULL;
- }
-#ifdef ADVANSYS_STATS
- /* Maintain request queue statistics. */
- ascq->q_cur_cnt[tid]--;
- ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
- REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
-#endif /* ADVANSYS_STATS */
+ srb--;
+ if (srb >= asc_dvc->ptr_map_count) {
+ printk("advansys: bad SRB %u, max %u\n", srb,
+ asc_dvc->ptr_map_count);
+ return NULL;
}
- ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
- return reqp;
+ ptr = asc_dvc->ptr_map[srb];
+ asc_dvc->ptr_map[srb] = NULL;
+ ASC_DBG(3, "Returning ptr %p from array offset %d\n", ptr, srb);
+ return ptr;
}
/*
- * Return a pointer to a singly linked list of all the requests queued
- * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
- *
- * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
- * the last request returned in the singly linked list.
- *
- * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
- * then all queued requests are concatenated into one list and
- * returned.
+ * advansys_info()
*
- * Note: If 'lastpp' is used to append a new list to the end of
- * an old list, only change the old list last pointer if '*lastpp'
- * (or the function return value) is not NULL, i.e. use a temporary
- * variable for 'lastpp' and check its value after the function return
- * before assigning it to the list last pointer.
+ * Return suitable for printing on the console with the argument
+ * adapter's configuration information.
*
- * Unfortunately collecting queuing time statistics adds overhead to
- * the function that isn't inherent to the function's algorithm.
+ * Note: The information line should not exceed ASC_INFO_SIZE bytes,
+ * otherwise the static 'info' array will be overrun.
*/
-static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
+static const char *advansys_info(struct Scsi_Host *shost)
{
- REQP firstp, lastp;
- int i;
-
- ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
- ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
+ static char info[ASC_INFO_SIZE];
+ struct asc_board *boardp = shost_priv(shost);
+ ASC_DVC_VAR *asc_dvc_varp;
+ ADV_DVC_VAR *adv_dvc_varp;
+ char *busname;
+ char *widename = NULL;
- /*
- * If 'tid' is not ASC_TID_ALL, return requests only for
- * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
- * requests for all tids.
- */
- if (tid != ASC_TID_ALL) {
- /* Return all requests for the specified 'tid'. */
- if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
- /* List is empty; Set first and last return pointers to NULL. */
- firstp = lastp = NULL;
- } else {
- firstp = ascq->q_first[tid];
- lastp = ascq->q_last[tid];
- ascq->q_first[tid] = ascq->q_last[tid] = NULL;
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
-#ifdef ADVANSYS_STATS
- {
- REQP reqp;
- ascq->q_cur_cnt[tid] = 0;
- for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
- REQTIMESTAT("asc_dequeue_list", ascq,
- reqp, tid);
- }
+ if (ASC_NARROW_BOARD(boardp)) {
+ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+ ASC_DBG(1, "begin\n");
+ if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+ if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
+ ASC_IS_ISAPNP) {
+ busname = "ISA PnP";
+ } else {
+ busname = "ISA";
}
-#endif /* ADVANSYS_STATS */
- }
- } else {
- /* Return all requests for all tids. */
- firstp = lastp = NULL;
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
- if (firstp == NULL) {
- firstp = ascq->q_first[i];
- lastp = ascq->q_last[i];
+ sprintf(info,
+ "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
+ ASC_VERSION, busname,
+ (ulong)shost->io_port,
+ (ulong)shost->io_port + ASC_IOADR_GAP - 1,
+ boardp->irq, shost->dma_channel);
+ } else {
+ if (asc_dvc_varp->bus_type & ASC_IS_VL) {
+ busname = "VL";
+ } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
+ busname = "EISA";
+ } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
+ if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+ == ASC_IS_PCI_ULTRA) {
+ busname = "PCI Ultra";
} else {
- ASC_ASSERT(lastp != NULL);
- lastp->host_scribble =
- (unsigned char *)ascq->q_first[i];
- lastp = ascq->q_last[i];
+ busname = "PCI";
}
- ascq->q_first[i] = ascq->q_last[i] = NULL;
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
-#ifdef ADVANSYS_STATS
- ascq->q_cur_cnt[i] = 0;
-#endif /* ADVANSYS_STATS */
- }
- }
-#ifdef ADVANSYS_STATS
- {
- REQP reqp;
- for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
- REQTIMESTAT("asc_dequeue_list", ascq, reqp,
- reqp->device->id);
+ } else {
+ busname = "?";
+ shost_printk(KERN_ERR, shost, "unknown bus "
+ "type %d\n", asc_dvc_varp->bus_type);
}
+ sprintf(info,
+ "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
+ ASC_VERSION, busname, (ulong)shost->io_port,
+ (ulong)shost->io_port + ASC_IOADR_GAP - 1,
+ boardp->irq);
}
-#endif /* ADVANSYS_STATS */
- }
- if (lastpp) {
- *lastpp = lastp;
- }
- ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
- return firstp;
-}
-
-/*
- * Remove the specified 'REQP' from the specified queue for
- * the specified target device. Clear the 'tidmask' bit for the
- * device if no more commands are left queued for it.
- *
- * 'REQPNEXT(reqp)' returns reqp's the next pointer.
- *
- * Return ASC_TRUE if the command was found and removed,
- * otherwise return ASC_FALSE.
- */
-static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
-{
- REQP currp, prevp;
- int tid;
- int ret = ASC_FALSE;
-
- ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
- (ulong)ascq, (ulong)reqp);
- ASC_ASSERT(reqp != NULL);
-
- tid = REQPTID(reqp);
- ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
-
- /*
- * Handle the common case of 'reqp' being the first
- * entry on the queue.
- */
- if (reqp == ascq->q_first[tid]) {
- ret = ASC_TRUE;
- ascq->q_first[tid] = REQPNEXT(reqp);
- /* If the queue is now empty, clear its bit and the last pointer. */
- if (ascq->q_first[tid] == NULL) {
- ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
- ASC_ASSERT(ascq->q_last[tid] == reqp);
- ascq->q_last[tid] = NULL;
- }
- } else if (ascq->q_first[tid] != NULL) {
- ASC_ASSERT(ascq->q_last[tid] != NULL);
+ } else {
/*
- * Because the case of 'reqp' being the first entry has been
- * handled above and it is known the queue is not empty, if
- * 'reqp' is found on the queue it is guaranteed the queue will
- * not become empty and that 'q_first[tid]' will not be changed.
+ * Wide Adapter Information
*
- * Set 'prevp' to the first entry, 'currp' to the second entry,
- * and search for 'reqp'.
+ * Memory-mapped I/O is used instead of I/O space to access
+ * the adapter, but display the I/O Port range. The Memory
+ * I/O address is displayed through the driver /proc file.
*/
- for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
- currp; prevp = currp, currp = REQPNEXT(currp)) {
- if (currp == reqp) {
- ret = ASC_TRUE;
- prevp->host_scribble =
- (unsigned char *)REQPNEXT(currp);
- reqp->host_scribble = NULL;
- if (ascq->q_last[tid] == reqp) {
- ascq->q_last[tid] = prevp;
- }
- break;
- }
+ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+ if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+ widename = "Ultra-Wide";
+ } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+ widename = "Ultra2-Wide";
+ } else {
+ widename = "Ultra3-Wide";
}
+ sprintf(info,
+ "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
+ ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
+ (ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, boardp->irq);
}
-#ifdef ADVANSYS_STATS
- /* Maintain request queue statistics. */
- if (ret == ASC_TRUE) {
- ascq->q_cur_cnt[tid]--;
- REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
- }
- ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
-#endif /* ADVANSYS_STATS */
- ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
- return ret;
+ BUG_ON(strlen(info) >= ASC_INFO_SIZE);
+ ASC_DBG(1, "end\n");
+ return info;
}
+#ifdef CONFIG_PROC_FS
/*
- * Execute as many queued requests as possible for the specified queue.
+ * asc_prt_line()
+ *
+ * If 'cp' is NULL print to the console, otherwise print to a buffer.
*
- * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
+ * Return 0 if printing to the console, otherwise return the number of
+ * bytes written to the buffer.
+ *
+ * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
+ * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
*/
-static void asc_execute_queue(asc_queue_t *ascq)
+static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
{
- ADV_SCSI_BIT_ID_TYPE scan_tidmask;
- REQP reqp;
- int i;
+ va_list args;
+ int ret;
+ char s[ASC_PRTLINE_SIZE];
- ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
- /*
- * Execute queued commands for devices attached to
- * the current board in round-robin fashion.
- */
- scan_tidmask = ascq->q_tidmask;
- do {
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
- if ((reqp = asc_dequeue(ascq, i)) == NULL) {
- scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
- } else
- if (asc_execute_scsi_cmnd
- ((struct scsi_cmnd *)reqp)
- == ASC_BUSY) {
- scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
- /*
- * The request returned ASC_BUSY. Enqueue at the front of
- * target's waiting list to maintain correct ordering.
- */
- asc_enqueue(ascq, reqp, ASC_FRONT);
- }
- }
- }
- } while (scan_tidmask);
- return;
+ va_start(args, fmt);
+ ret = vsprintf(s, fmt, args);
+ BUG_ON(ret >= ASC_PRTLINE_SIZE);
+ if (buf == NULL) {
+ (void)printk(s);
+ ret = 0;
+ } else {
+ ret = min(buflen, ret);
+ memcpy(buf, s, ret);
+ }
+ va_end(args);
+ return ret;
}
-#ifdef CONFIG_PROC_FS
/*
* asc_prt_board_devices()
*
@@ -6245,14 +2919,13 @@ static void asc_execute_queue(asc_queue_t *ascq)
*/
static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
int leftlen;
int totlen;
int len;
int chip_scsi_id;
int i;
- boardp = ASC_BOARDP(shost);
leftlen = cplen;
totlen = len = 0;
@@ -6286,13 +2959,12 @@ static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
*/
static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
int leftlen;
int totlen;
int len;
ushort major, minor, letter;
- boardp = ASC_BOARDP(shost);
leftlen = cplen;
totlen = len = 0;
@@ -6452,7 +3124,7 @@ static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
*/
static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
ASC_DVC_VAR *asc_dvc_varp;
int leftlen;
int totlen;
@@ -6464,7 +3136,6 @@ static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
#endif /* CONFIG_ISA */
uchar serialstr[13];
- boardp = ASC_BOARDP(shost);
asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
ep = &boardp->eep_config.asc_eep;
@@ -6586,7 +3257,7 @@ static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
*/
static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
ADV_DVC_VAR *adv_dvc_varp;
int leftlen;
int totlen;
@@ -6601,7 +3272,6 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
ushort *wordp;
ushort sdtr_speed = 0;
- boardp = ASC_BOARDP(shost);
adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
ep_3550 = &boardp->eep_config.adv_3550_eep;
@@ -6873,14 +3543,12 @@ static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen
*/
static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
int leftlen;
int totlen;
int len;
int chip_scsi_id;
- boardp = ASC_BOARDP(shost);
-
leftlen = cplen;
totlen = len = 0;
@@ -6912,10 +3580,7 @@ static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
boardp->asc_n_io_port);
ASC_PRT_NEXT();
- /* 'shost->n_io_port' may be truncated because it is only one byte. */
- len = asc_prt_line(cp, leftlen,
- " io_port 0x%x, n_io_port 0x%x\n",
- shost->io_port, shost->n_io_port);
+ len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port);
ASC_PRT_NEXT();
if (ASC_NARROW_BOARD(boardp)) {
@@ -6940,7 +3605,7 @@ static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
*/
static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
int chip_scsi_id;
int leftlen;
int totlen;
@@ -6950,7 +3615,6 @@ static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
int i;
int renegotiate = 0;
- boardp = ASC_BOARDP(shost);
v = &boardp->dvc_var.asc_dvc_var;
c = &boardp->dvc_cfg.asc_dvc_cfg;
chip_scsi_id = c->chip_scsi_id;
@@ -6963,15 +3627,10 @@ static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
shost->host_no);
ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
- c->chip_version, c->lib_version, c->lib_serial_no,
- c->mcode_date);
- ASC_PRT_NEXT();
-
- len = asc_prt_line(cp, leftlen,
- " mcode_version 0x%x, err_code %u\n",
- c->mcode_version, v->err_code);
+ len = asc_prt_line(cp, leftlen, " chip_version %u, mcode_date 0x%x, "
+ "mcode_version 0x%x, err_code %u\n",
+ c->chip_version, c->mcode_date, c->mcode_version,
+ v->err_code);
ASC_PRT_NEXT();
/* Current number of commands waiting for the host. */
@@ -7128,7 +3787,7 @@ static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
*/
static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
{
- asc_board_t *boardp;
+ struct asc_board *boardp = shost_priv(shost);
int leftlen;
int totlen;
int len;
@@ -7145,7 +3804,6 @@ static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
ushort period = 0;
int renegotiate = 0;
- boardp = ASC_BOARDP(shost);
v = &boardp->dvc_var.adv_dvc_var;
c = &boardp->dvc_cfg.adv_dvc_cfg;
iop_base = v->iop_base;
@@ -7167,10 +3825,9 @@ static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
v->err_code);
ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
- " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
- c->chip_version, c->lib_version, c->mcode_date,
- c->mcode_version);
+ len = asc_prt_line(cp, leftlen, " chip_version %u, mcode_date 0x%x, "
+ "mcode_version 0x%x\n", c->chip_version,
+ c->mcode_date, c->mcode_version);
ASC_PRT_NEXT();
AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
@@ -7376,12 +4033,12 @@ asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
{
int cnt = 0;
- ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
+ ASC_DBG(2, "offset %d, advoffset %d, cplen %d\n",
(unsigned)offset, (unsigned)advoffset, cplen);
if (offset <= advoffset) {
/* Read offset below current offset, copy everything. */
cnt = min(cplen, leftlen);
- ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
+ ASC_DBG(2, "curbuf 0x%lx, cp 0x%lx, cnt %d\n",
(ulong)curbuf, (ulong)cp, cnt);
memcpy(curbuf, cp, cnt);
} else if (offset < advoffset + cplen) {
@@ -7389,1125 +4046,4537 @@ asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
cnt = (advoffset + cplen) - offset;
cp = (cp + cplen) - cnt;
cnt = min(cnt, leftlen);
- ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
+ ASC_DBG(2, "curbuf 0x%lx, cp 0x%lx, cnt %d\n",
(ulong)curbuf, (ulong)cp, cnt);
memcpy(curbuf, cp, cnt);
}
return cnt;
}
+#ifdef ADVANSYS_STATS
/*
- * asc_prt_line()
+ * asc_prt_board_stats()
*
- * If 'cp' is NULL print to the console, otherwise print to a buffer.
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
*
- * Return 0 if printing to the console, otherwise return the number of
- * bytes written to the buffer.
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
+{
+ struct asc_board *boardp = shost_priv(shost);
+ struct asc_stats *s = &boardp->asc_stats;
+
+ int leftlen = cplen;
+ int len, totlen = 0;
+
+ len = asc_prt_line(cp, leftlen,
+ "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
+ shost->host_no);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
+ s->queuecommand, s->reset, s->biosparam,
+ s->interrupt);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
+ s->callback, s->done, s->build_error,
+ s->adv_build_noreq, s->adv_build_nosg);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+ " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
+ s->exe_noerror, s->exe_busy, s->exe_error,
+ s->exe_unknown);
+ ASC_PRT_NEXT();
+
+ /*
+ * Display data transfer statistics.
+ */
+ if (s->xfer_cnt > 0) {
+ len = asc_prt_line(cp, leftlen, " xfer_cnt %lu, xfer_elem %lu, ",
+ s->xfer_cnt, s->xfer_elem);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, "xfer_bytes %lu.%01lu kb\n",
+ s->xfer_sect / 2, ASC_TENTHS(s->xfer_sect, 2));
+ ASC_PRT_NEXT();
+
+ /* Scatter gather transfer statistics */
+ len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
+ s->xfer_elem / s->xfer_cnt,
+ ASC_TENTHS(s->xfer_elem, s->xfer_cnt));
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
+ (s->xfer_sect / 2) / s->xfer_elem,
+ ASC_TENTHS((s->xfer_sect / 2), s->xfer_elem));
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
+ (s->xfer_sect / 2) / s->xfer_cnt,
+ ASC_TENTHS((s->xfer_sect / 2), s->xfer_cnt));
+ ASC_PRT_NEXT();
+ }
+
+ return totlen;
+}
+#endif /* ADVANSYS_STATS */
+
+/*
+ * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
*
- * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
- * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset into a /proc/scsi/advansys/[0...] file
+ * length: length of buffer
+ * hostno: Scsi_Host host_no
+ * inout: TRUE - user is writing; FALSE - user is reading
+ *
+ * Return the number of bytes read from or written to a
+ * /proc/scsi/advansys/[0...] file.
+ *
+ * Note: This function uses the per board buffer 'prtbuf' which is
+ * allocated when the board is initialized in advansys_detect(). The
+ * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
+ * used to write to the buffer. The way asc_proc_copy() is written
+ * if 'prtbuf' is too small it will not be overwritten. Instead the
+ * user just won't get all the available statistics.
*/
-static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
+static int
+advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
+ off_t offset, int length, int inout)
{
- va_list args;
- int ret;
- char s[ASC_PRTLINE_SIZE];
+ struct asc_board *boardp = shost_priv(shost);
+ char *cp;
+ int cplen;
+ int cnt;
+ int totcnt;
+ int leftlen;
+ char *curbuf;
+ off_t advoffset;
- va_start(args, fmt);
- ret = vsprintf(s, fmt, args);
- ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
- if (buf == NULL) {
- (void)printk(s);
- ret = 0;
+ ASC_DBG(1, "begin\n");
+
+ /*
+ * User write not supported.
+ */
+ if (inout == TRUE)
+ return -ENOSYS;
+
+ /*
+ * User read of /proc/scsi/advansys/[0...] file.
+ */
+
+ /* Copy read data starting at the beginning of the buffer. */
+ *start = buffer;
+ curbuf = buffer;
+ advoffset = 0;
+ totcnt = 0;
+ leftlen = length;
+
+ /*
+ * Get board configuration information.
+ *
+ * advansys_info() returns the board string from its own static buffer.
+ */
+ cp = (char *)advansys_info(shost);
+ strcat(cp, "\n");
+ cplen = strlen(cp);
+ /* Copy board information. */
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+ /*
+ * Display Wide Board BIOS Information.
+ */
+ if (!ASC_NARROW_BOARD(boardp)) {
+ cp = boardp->prtbuf;
+ cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
+ BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
+ cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+ }
+
+ /*
+ * Display driver information for each device attached to the board.
+ */
+ cp = boardp->prtbuf;
+ cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
+ BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+ /*
+ * Display EEPROM configuration for the board.
+ */
+ cp = boardp->prtbuf;
+ if (ASC_NARROW_BOARD(boardp)) {
+ cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
} else {
- ret = min(buflen, ret);
- memcpy(buf, s, ret);
+ cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
}
- va_end(args);
- return ret;
+ BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+ /*
+ * Display driver configuration and information for the board.
+ */
+ cp = boardp->prtbuf;
+ cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
+ BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+#ifdef ADVANSYS_STATS
+ /*
+ * Display driver statistics for the board.
+ */
+ cp = boardp->prtbuf;
+ cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
+ BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+#endif /* ADVANSYS_STATS */
+
+ /*
+ * Display Asc Library dynamic configuration information
+ * for the board.
+ */
+ cp = boardp->prtbuf;
+ if (ASC_NARROW_BOARD(boardp)) {
+ cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
+ } else {
+ cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
+ }
+ BUG_ON(cplen >= ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+
+ ASC_DBG(1, "totcnt %d\n", totcnt);
+
+ return totcnt;
}
#endif /* CONFIG_PROC_FS */
-/*
- * --- Functions Required by the Asc Library
- */
+static void asc_scsi_done(struct scsi_cmnd *scp)
+{
+ scsi_dma_unmap(scp);
+ ASC_STATS(scp->device->host, done);
+ scp->scsi_done(scp);
+}
-/*
- * Delay for 'n' milliseconds. Don't use the 'jiffies'
- * global variable which is incremented once every 5 ms
- * from a timer interrupt, because this function may be
- * called when interrupts are disabled.
- */
-static void DvcSleepMilliSecond(ADV_DCNT n)
+static void AscSetBank(PortAddr iop_base, uchar bank)
{
- ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
- mdelay(n);
+ uchar val;
+
+ val = AscGetChipControl(iop_base) &
+ (~
+ (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
+ CC_CHIP_RESET));
+ if (bank == 1) {
+ val |= CC_BANK_ONE;
+ } else if (bank == 2) {
+ val |= CC_DIAG | CC_BANK_ONE;
+ } else {
+ val &= ~CC_BANK_ONE;
+ }
+ AscSetChipControl(iop_base, val);
}
-/*
- * Currently and inline noop but leave as a placeholder.
- * Leave DvcEnterCritical() as a noop placeholder.
- */
-static inline ulong DvcEnterCritical(void)
+static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
{
- return 0;
+ AscSetBank(iop_base, 1);
+ AscWriteChipIH(iop_base, ins_code);
+ AscSetBank(iop_base, 0);
}
-/*
- * Critical sections are all protected by the board spinlock.
- * Leave DvcLeaveCritical() as a noop placeholder.
- */
-static inline void DvcLeaveCritical(ulong flags)
+static int AscStartChip(PortAddr iop_base)
+{
+ AscSetChipControl(iop_base, 0);
+ if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+ return (0);
+ }
+ return (1);
+}
+
+static int AscStopChip(PortAddr iop_base)
+{
+ uchar cc_val;
+
+ cc_val =
+ AscGetChipControl(iop_base) &
+ (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
+ AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
+ AscSetChipIH(iop_base, INS_HALT);
+ AscSetChipIH(iop_base, INS_RFLAG_WTM);
+ if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
+ return (0);
+ }
+ return (1);
+}
+
+static int AscIsChipHalted(PortAddr iop_base)
+{
+ if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+ if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
+{
+ PortAddr iop_base;
+ int i = 10;
+
+ iop_base = asc_dvc->iop_base;
+ while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
+ && (i-- > 0)) {
+ mdelay(100);
+ }
+ AscStopChip(iop_base);
+ AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
+ udelay(60);
+ AscSetChipIH(iop_base, INS_RFLAG_WTM);
+ AscSetChipIH(iop_base, INS_HALT);
+ AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
+ AscSetChipControl(iop_base, CC_HALT);
+ mdelay(200);
+ AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+ AscSetChipStatus(iop_base, 0);
+ return (AscIsChipHalted(iop_base));
+}
+
+static int AscFindSignature(PortAddr iop_base)
+{
+ ushort sig_word;
+
+ ASC_DBG(1, "AscGetChipSignatureByte(0x%x) 0x%x\n",
+ iop_base, AscGetChipSignatureByte(iop_base));
+ if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
+ ASC_DBG(1, "AscGetChipSignatureWord(0x%x) 0x%x\n",
+ iop_base, AscGetChipSignatureWord(iop_base));
+ sig_word = AscGetChipSignatureWord(iop_base);
+ if ((sig_word == (ushort)ASC_1000_ID0W) ||
+ (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static void AscEnableInterrupt(PortAddr iop_base)
+{
+ ushort cfg;
+
+ cfg = AscGetChipCfgLsw(iop_base);
+ AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
+}
+
+static void AscDisableInterrupt(PortAddr iop_base)
+{
+ ushort cfg;
+
+ cfg = AscGetChipCfgLsw(iop_base);
+ AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
+}
+
+static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
+{
+ unsigned char byte_data;
+ unsigned short word_data;
+
+ if (isodd_word(addr)) {
+ AscSetChipLramAddr(iop_base, addr - 1);
+ word_data = AscGetChipLramData(iop_base);
+ byte_data = (word_data >> 8) & 0xFF;
+ } else {
+ AscSetChipLramAddr(iop_base, addr);
+ word_data = AscGetChipLramData(iop_base);
+ byte_data = word_data & 0xFF;
+ }
+ return byte_data;
+}
+
+static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
+{
+ ushort word_data;
+
+ AscSetChipLramAddr(iop_base, addr);
+ word_data = AscGetChipLramData(iop_base);
+ return (word_data);
+}
+
+#if CC_VERY_LONG_SG_LIST
+static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
+{
+ ushort val_low, val_high;
+ ASC_DCNT dword_data;
+
+ AscSetChipLramAddr(iop_base, addr);
+ val_low = AscGetChipLramData(iop_base);
+ val_high = AscGetChipLramData(iop_base);
+ dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
+ return (dword_data);
+}
+#endif /* CC_VERY_LONG_SG_LIST */
+
+static void
+AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
+{
+ int i;
+
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < words; i++) {
+ AscSetChipLramData(iop_base, set_wval);
+ }
+}
+
+static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
+{
+ AscSetChipLramAddr(iop_base, addr);
+ AscSetChipLramData(iop_base, word_val);
+}
+
+static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
{
- return;
+ ushort word_data;
+
+ if (isodd_word(addr)) {
+ addr--;
+ word_data = AscReadLramWord(iop_base, addr);
+ word_data &= 0x00FF;
+ word_data |= (((ushort)byte_val << 8) & 0xFF00);
+ } else {
+ word_data = AscReadLramWord(iop_base, addr);
+ word_data &= 0xFF00;
+ word_data |= ((ushort)byte_val & 0x00FF);
+ }
+ AscWriteLramWord(iop_base, addr, word_data);
}
/*
- * void
- * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
- *
- * Calling/Exit State:
- * none
+ * Copy 2 bytes to LRAM.
*
- * Description:
- * Output an ASC_SCSI_Q structure to the chip
+ * The source data is assumed to be in little-endian order in memory
+ * and is maintained in little-endian order when written to LRAM.
*/
static void
-DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
+AscMemWordCopyPtrToLram(PortAddr iop_base,
+ ushort s_addr, uchar *s_buffer, int words)
{
int i;
- ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
AscSetChipLramAddr(iop_base, s_addr);
for (i = 0; i < 2 * words; i += 2) {
- if (i == 4 || i == 20) {
- continue;
- }
+ /*
+ * On a little-endian system the second argument below
+ * produces a little-endian ushort which is written to
+ * LRAM in little-endian order. On a big-endian system
+ * the second argument produces a big-endian ushort which
+ * is "transparently" byte-swapped by outpw() and written
+ * in little-endian order to LRAM.
+ */
outpw(iop_base + IOP_RAM_DATA,
- ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
+ ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
}
}
/*
- * void
- * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
+ * Copy 4 bytes to LRAM.
*
- * Calling/Exit State:
- * none
+ * The source data is assumed to be in little-endian order in memory
+ * and is maintained in little-endian order when writen to LRAM.
+ */
+static void
+AscMemDWordCopyPtrToLram(PortAddr iop_base,
+ ushort s_addr, uchar *s_buffer, int dwords)
+{
+ int i;
+
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < 4 * dwords; i += 4) {
+ outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
+ outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
+ }
+}
+
+/*
+ * Copy 2 bytes from LRAM.
*
- * Description:
- * Input an ASC_QDONE_INFO structure from the chip
+ * The source data is assumed to be in little-endian order in LRAM
+ * and is maintained in little-endian order when written to memory.
*/
static void
-DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
+AscMemWordCopyPtrFromLram(PortAddr iop_base,
+ ushort s_addr, uchar *d_buffer, int words)
{
int i;
ushort word;
AscSetChipLramAddr(iop_base, s_addr);
for (i = 0; i < 2 * words; i += 2) {
- if (i == 10) {
- continue;
- }
word = inpw(iop_base + IOP_RAM_DATA);
- inbuf[i] = word & 0xff;
- inbuf[i + 1] = (word >> 8) & 0xff;
+ d_buffer[i] = word & 0xff;
+ d_buffer[i + 1] = (word >> 8) & 0xff;
}
- ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
}
-/*
- * Read a PCI configuration byte.
- */
-static uchar __init DvcReadPCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset)
+static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
{
-#ifdef CONFIG_PCI
- uchar byte_data;
- pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
- return byte_data;
-#else /* !defined(CONFIG_PCI) */
- return 0;
-#endif /* !defined(CONFIG_PCI) */
+ ASC_DCNT sum;
+ int i;
+
+ sum = 0L;
+ for (i = 0; i < words; i++, s_addr += 2) {
+ sum += AscReadLramWord(iop_base, s_addr);
+ }
+ return (sum);
}
-/*
- * Write a PCI configuration byte.
- */
-static void __init
-DvcWritePCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
+static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
{
-#ifdef CONFIG_PCI
- pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
-#endif /* CONFIG_PCI */
+ uchar i;
+ ushort s_addr;
+ PortAddr iop_base;
+ ushort warn_code;
+
+ iop_base = asc_dvc->iop_base;
+ warn_code = 0;
+ AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
+ (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
+ 64) >> 1));
+ i = ASC_MIN_ACTIVE_QNO;
+ s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+ (uchar)(i + 1));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+ (uchar)(asc_dvc->max_total_qng));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+ (uchar)i);
+ i++;
+ s_addr += ASC_QBLK_SIZE;
+ for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+ (uchar)(i + 1));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+ (uchar)(i - 1));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+ (uchar)i);
+ }
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+ (uchar)ASC_QLINK_END);
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+ (uchar)(asc_dvc->max_total_qng - 1));
+ AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+ (uchar)asc_dvc->max_total_qng);
+ i++;
+ s_addr += ASC_QBLK_SIZE;
+ for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
+ i++, s_addr += ASC_QBLK_SIZE) {
+ AscWriteLramByte(iop_base,
+ (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
+ AscWriteLramByte(iop_base,
+ (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
+ AscWriteLramByte(iop_base,
+ (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
+ }
+ return warn_code;
}
-/*
- * Return the BIOS address of the adapter at the specified
- * I/O port and with the specified bus type.
- */
-static ushort __init AscGetChipBiosAddress(PortAddr iop_base, ushort bus_type)
+static ASC_DCNT
+AscLoadMicroCode(PortAddr iop_base,
+ ushort s_addr, uchar *mcode_buf, ushort mcode_size)
{
- ushort cfg_lsw;
- ushort bios_addr;
+ ASC_DCNT chksum;
+ ushort mcode_word_size;
+ ushort mcode_chksum;
- /*
- * The PCI BIOS is re-located by the motherboard BIOS. Because
- * of this the driver can not determine where a PCI BIOS is
- * loaded and executes.
- */
- if (bus_type & ASC_IS_PCI) {
- return (0);
+ /* Write the microcode buffer starting at LRAM address 0. */
+ mcode_word_size = (ushort)(mcode_size >> 1);
+ AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
+ AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
+
+ chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
+ ASC_DBG(1, "chksum 0x%lx\n", (ulong)chksum);
+ mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
+ (ushort)ASC_CODE_SEC_BEG,
+ (ushort)((mcode_size -
+ s_addr - (ushort)
+ ASC_CODE_SEC_BEG) /
+ 2));
+ ASC_DBG(1, "mcode_chksum 0x%lx\n", (ulong)mcode_chksum);
+ AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
+ AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
+ return chksum;
+}
+
+/* Microcode buffer is kept after initialization for error recovery. */
+static uchar _asc_mcode_buf[] = {
+ 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00, 0x80, 0x73, 0x48, 0x04,
+ 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
+ 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
+ 0xC2, 0x00, 0x92, 0x80, 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98,
+ 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00,
+ 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
+ 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
+ 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23,
+ 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84, 0xD2, 0xC1, 0x80, 0x73, 0xCD, 0x04,
+ 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97, 0xC6, 0x81, 0xC2, 0x88,
+ 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
+ 0x84, 0x97, 0x07, 0xA6, 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88,
+ 0x03, 0x03, 0x01, 0xDE, 0xC2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00,
+ 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01, 0x80, 0x63, 0x07, 0xA6,
+ 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
+ 0x34, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01,
+ 0x04, 0xCA, 0x0D, 0x23, 0x68, 0x98, 0x4D, 0x04, 0x04, 0x85, 0x05, 0xD8,
+ 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23,
+ 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
+ 0x00, 0x33, 0x0A, 0x00, 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01,
+ 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33,
+ 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81, 0x06, 0xAB, 0x82, 0x01,
+ 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
+ 0x3C, 0x01, 0x00, 0x05, 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6,
+ 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xBE, 0x81, 0xFD, 0x23,
+ 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0,
+ 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
+ 0xC2, 0x88, 0x06, 0x23, 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01,
+ 0x00, 0xA2, 0xD4, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xDA, 0x01, 0xE6, 0x84,
+ 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61,
+ 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
+ 0x4F, 0x00, 0x84, 0x97, 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01,
+ 0x4F, 0x00, 0x62, 0x97, 0x48, 0x04, 0x84, 0x80, 0xF0, 0x97, 0x00, 0x46,
+ 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29,
+ 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
+ 0x04, 0x98, 0xF0, 0x80, 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02,
+ 0x7C, 0x95, 0x06, 0xA6, 0x34, 0x02, 0x03, 0xA6, 0x4C, 0x04, 0x46, 0x82,
+ 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96, 0x46, 0x82, 0xFE, 0x95,
+ 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
+ 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02,
+ 0xC2, 0x88, 0x7C, 0x95, 0x48, 0x82, 0x60, 0x96, 0x48, 0x82, 0x04, 0x23,
+ 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84, 0x04, 0x01, 0x0C, 0xDC,
+ 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
+ 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01,
+ 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07, 0xA6, 0x5A, 0x02,
+ 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04, 0x01, 0xA6, 0xB4, 0x02,
+ 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
+ 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01,
+ 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35,
+ 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82,
+ 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
+ 0x00, 0x33, 0x1F, 0x00, 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39,
+ 0x0E, 0x3D, 0x7E, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x14, 0x03, 0x00, 0xA6,
+ 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6,
+ 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
+ 0x7C, 0x95, 0xEE, 0x82, 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42,
+ 0x7E, 0x98, 0x64, 0xE4, 0x04, 0x01, 0x2D, 0xC8, 0x31, 0x05, 0x07, 0x01,
+ 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x86, 0x98,
+ 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
+ 0x3C, 0x04, 0x06, 0xA6, 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33,
+ 0x25, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x32, 0x83, 0x60, 0x96, 0x32, 0x83,
+ 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05, 0xEB, 0x04, 0x00, 0x33,
+ 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
+ 0xFF, 0xA2, 0x7A, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83,
+ 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x9A, 0x03, 0xEC, 0x00, 0x6E, 0x00,
+ 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x96, 0x03,
+ 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
+ 0xA4, 0x03, 0x00, 0xA6, 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42,
+ 0x01, 0xA6, 0xA4, 0x03, 0x07, 0xA6, 0xB2, 0x03, 0xD4, 0x83, 0x7C, 0x95,
+ 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42,
+ 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
+ 0xC0, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32,
+ 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x10, 0x84,
+ 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
+ 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
+ 0x06, 0xA6, 0x0A, 0x04, 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95,
+ 0xF4, 0x83, 0x60, 0x96, 0xF4, 0x83, 0x20, 0x84, 0x07, 0xF0, 0x06, 0xA4,
+ 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63,
+ 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
+ 0x38, 0x04, 0x00, 0x33, 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84,
+ 0x60, 0x96, 0x20, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84,
+ 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63,
+ 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
+ 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2,
+ 0x86, 0x04, 0x0A, 0xA0, 0x76, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00,
+ 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00,
+ 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
+ 0x08, 0x23, 0x22, 0xA3, 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04,
+ 0x02, 0x23, 0x22, 0xA3, 0xC4, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00,
+ 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x04, 0x98,
+ 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
+ 0x81, 0x62, 0xE8, 0x81, 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE,
+ 0x04, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62,
+ 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23,
+ 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
+ 0xF4, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC,
+ 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x04, 0x98, 0x26, 0x95,
+ 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x22, 0x05,
+ 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
+ 0x46, 0x97, 0xCD, 0x04, 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01,
+ 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x34, 0x85, 0x02, 0x23, 0xA0, 0x01,
+ 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05, 0x1D, 0x01, 0x04, 0xD6,
+ 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
+ 0x49, 0x00, 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01,
+ 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05,
+ 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00,
+ 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
+ 0x07, 0xA4, 0xF8, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85,
+ 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xB8, 0x05, 0x80, 0x63,
+ 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xA4, 0x05,
+ 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
+ 0x62, 0x97, 0x04, 0x85, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85,
+ 0x08, 0xA0, 0xBE, 0x05, 0xF4, 0x85, 0x03, 0xA0, 0xC4, 0x05, 0xF4, 0x85,
+ 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63, 0xCC, 0x86, 0x07, 0xA0,
+ 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
+ 0x80, 0x67, 0x80, 0x63, 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23,
+ 0x68, 0x98, 0x48, 0x23, 0xF8, 0x88, 0x07, 0x23, 0x80, 0x00, 0x06, 0x87,
+ 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63, 0x4A, 0x00,
+ 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
+ 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33,
+ 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x01, 0xD6, 0x20, 0x23, 0x63, 0x60,
+ 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00, 0x07, 0xA6, 0x7C, 0x05,
+ 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
+ 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA,
+ 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33,
+ 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63,
+ 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
+ 0xDF, 0x00, 0x06, 0xA6, 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67,
+ 0x80, 0x63, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63,
+ 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x94, 0x06,
+ 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
+ 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6,
+ 0x7C, 0x05, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0xA2, 0x06,
+ 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x40, 0x0E,
+ 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
+ 0x07, 0xA6, 0xD6, 0x06, 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03,
+ 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xE8, 0x06, 0x00, 0x33,
+ 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xF4, 0x06, 0xC0, 0x0E,
+ 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
+ 0x81, 0x62, 0x04, 0x01, 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B,
+ 0x80, 0x63, 0x06, 0xA6, 0x8C, 0x06, 0x00, 0x33, 0x2C, 0x00, 0xC2, 0x88,
+ 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6,
+ 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
+ 0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07,
+ 0x07, 0xA6, 0x7C, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE6, 0x84,
+ 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00,
+ 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
+ 0x80, 0x05, 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04,
+ 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x71, 0x00,
+ 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, 0x80, 0x01,
+ 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
+ 0xF1, 0x00, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01,
+ 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04,
+ 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01,
+ 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
+ 0xC4, 0x07, 0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05,
+ 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23,
+ 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xE4, 0x07,
+ 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
+ 0x05, 0x05, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
+ 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63,
+ 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x00, 0xA0,
+ 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
+ 0x00, 0x63, 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43,
+ 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, 0x44, 0x08, 0x74, 0x04, 0x02, 0x01,
+ 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x24, 0x08, 0x04, 0x98,
+ 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
+ 0x5A, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95,
+ 0x4A, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x64, 0x08, 0x00, 0x05, 0x4E, 0x88,
+ 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x76, 0x08,
+ 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
+ 0x00, 0x63, 0x38, 0x2B, 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09,
+ 0x31, 0x05, 0x92, 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32,
+ 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36,
+ 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
+ 0x40, 0x36, 0x40, 0x3A, 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40,
+ 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73,
+ 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
+ 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
+ 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77,
+ 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, 0x41, 0x23,
+ 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE6, 0x84,
+};
+
+static unsigned short _asc_mcode_size = sizeof(_asc_mcode_buf);
+static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
+
+/* Microcode buffer is kept after initialization for error recovery. */
+static unsigned char _adv_asc3550_buf[] = {
+ 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
+ 0x01, 0x00, 0x48, 0xe4, 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00,
+ 0x00, 0xfa, 0xff, 0xff, 0x28, 0x0e, 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7,
+ 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0, 0x01, 0xf6,
+ 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
+ 0x00, 0xec, 0x85, 0xf0, 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54,
+ 0x00, 0xe6, 0x1e, 0xf0, 0x86, 0xf0, 0xb4, 0x00, 0x98, 0x57, 0xd0, 0x01,
+ 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00, 0xaa, 0x18, 0x02, 0x80,
+ 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
+ 0x00, 0x57, 0x01, 0xea, 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
+ 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
+ 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12, 0x02, 0x4a, 0xb9, 0x54,
+ 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
+ 0x3e, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
+ 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x62, 0x0a,
+ 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13, 0x4c, 0x1c, 0xbb, 0x55,
+ 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
+ 0x03, 0xf7, 0x06, 0xf7, 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00,
+ 0x00, 0x01, 0xb0, 0x08, 0x30, 0x13, 0x64, 0x15, 0x32, 0x1c, 0x38, 0x1c,
+ 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c, 0x04, 0xea, 0x5d, 0xf0,
+ 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
+ 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10,
+ 0x0a, 0x12, 0x04, 0x13, 0x40, 0x13, 0x30, 0x1c, 0x00, 0x4e, 0xbd, 0x56,
+ 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xa7, 0xf0,
+ 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
+ 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00,
+ 0xde, 0x03, 0x56, 0x0a, 0x14, 0x0e, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10,
+ 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13, 0x10, 0x15, 0x14, 0x15,
+ 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
+ 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55,
+ 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0, 0x0c, 0xf0,
+ 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa,
+ 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
+ 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01,
+ 0x26, 0x01, 0x79, 0x01, 0x7a, 0x01, 0xc0, 0x01, 0xc2, 0x01, 0x7c, 0x02,
+ 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08, 0x69, 0x08, 0xba, 0x08,
+ 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
+ 0xf1, 0x10, 0x06, 0x12, 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13,
+ 0x42, 0x14, 0xd6, 0x14, 0x8a, 0x15, 0xc6, 0x17, 0xd2, 0x17, 0x6b, 0x18,
+ 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0x48, 0x47,
+ 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
+ 0x14, 0x56, 0x77, 0x57, 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90,
+ 0x03, 0xa1, 0xfe, 0x9c, 0xf0, 0x29, 0x02, 0xfe, 0xb8, 0x0c, 0xff, 0x10,
+ 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf, 0xfe, 0x80, 0x01, 0xff,
+ 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+ 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00,
+ 0x00, 0x10, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
+ 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+ 0xfe, 0x04, 0xf7, 0xcf, 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe,
+ 0x04, 0xf7, 0xcf, 0x67, 0x0b, 0x3c, 0x2a, 0xfe, 0x3d, 0xf0, 0xfe, 0x02,
+ 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0, 0xfe, 0xf0, 0x01, 0xfe,
+ 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
+ 0x02, 0xfe, 0xd4, 0x0c, 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe,
+ 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x05, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
+ 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48, 0xf0, 0xfe, 0x86, 0x02,
+ 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
+ 0xfe, 0x46, 0xf0, 0xfe, 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02,
+ 0xfe, 0x43, 0xf0, 0xfe, 0x44, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x48, 0x02,
+ 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b, 0xa0, 0x17, 0x06, 0x18,
+ 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
+ 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10,
+ 0xfe, 0x06, 0xfc, 0xc7, 0x0a, 0x6b, 0x01, 0x9e, 0x02, 0x29, 0x14, 0x4d,
+ 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xbd,
+ 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
+ 0x58, 0x1c, 0x17, 0x06, 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0,
+ 0xfe, 0x02, 0x02, 0x21, 0xfe, 0x94, 0x02, 0xfe, 0x5a, 0x1c, 0xea, 0xfe,
+ 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97, 0x01, 0xfe, 0x54, 0x0f,
+ 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
+ 0x69, 0x10, 0x17, 0x06, 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d,
+ 0x12, 0x20, 0xfe, 0x05, 0xf6, 0xc7, 0x01, 0xfe, 0x52, 0x16, 0x09, 0x4a,
+ 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6, 0x02, 0x29, 0x0a, 0x40,
+ 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
+ 0x58, 0x0a, 0x99, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03,
+ 0x01, 0xe6, 0x02, 0x29, 0x2a, 0x46, 0xfe, 0x02, 0xe8, 0x27, 0xf8, 0xfe,
+ 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc, 0x01, 0xfe, 0x07, 0x4b,
+ 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
+ 0xfe, 0x56, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0,
+ 0x9c, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x64, 0x03, 0xeb, 0x0f,
+ 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48, 0x1c, 0xeb, 0x09, 0x04,
+ 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
+ 0x01, 0x0e, 0xac, 0x75, 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2,
+ 0xfe, 0x01, 0xf0, 0xd2, 0xfe, 0x82, 0xf0, 0xfe, 0x92, 0x03, 0xec, 0x11,
+ 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25, 0x32, 0x1f, 0xfe, 0xb4,
+ 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
+ 0x0a, 0xf0, 0xfe, 0x7a, 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe,
+ 0xf6, 0x04, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02, 0xd1,
+ 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8, 0xf7, 0xfe, 0x48, 0x1c,
+ 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
+ 0x0a, 0xca, 0x01, 0x0e, 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28,
+ 0xfe, 0x10, 0x12, 0x14, 0x2c, 0x01, 0x33, 0x8f, 0xfe, 0x66, 0x02, 0x02,
+ 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65, 0xfe, 0x3c, 0x04, 0x1f,
+ 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
+ 0x12, 0x2b, 0xff, 0x02, 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04,
+ 0x2b, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd5, 0xfe, 0x4c, 0x44, 0xfe,
+ 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
+ 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
+ 0xfe, 0x2a, 0x13, 0x2f, 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c,
+ 0xfe, 0x4c, 0x54, 0x64, 0xd3, 0xfa, 0xef, 0x86, 0x09, 0x04, 0x1d, 0xfe,
+ 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04, 0x1d, 0xfe, 0x1c, 0x12,
+ 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
+ 0x70, 0x0c, 0x02, 0x22, 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90,
+ 0xf9, 0x03, 0x14, 0x92, 0x01, 0x33, 0x02, 0x29, 0xfe, 0x42, 0x5b, 0x67,
+ 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4,
+ 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
+ 0xfe, 0x70, 0x12, 0x49, 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2,
+ 0x00, 0x28, 0x16, 0xfe, 0x80, 0x05, 0xfe, 0x31, 0xe4, 0x6a, 0x49, 0x04,
+ 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x42, 0x12,
+ 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
+ 0x11, 0xfe, 0xe3, 0x00, 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05,
+ 0xfe, 0x49, 0xf0, 0xfe, 0x64, 0x05, 0x83, 0x24, 0xfe, 0x21, 0x00, 0xa1,
+ 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe, 0x09, 0x48, 0x01, 0x08,
+ 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
+ 0x86, 0x24, 0x06, 0x12, 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d,
+ 0xfe, 0x22, 0x12, 0x47, 0x01, 0xa7, 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b,
+ 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c, 0x02, 0x22, 0x05, 0xfe,
+ 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
+ 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19,
+ 0xfe, 0x02, 0x12, 0x5f, 0x01, 0xfe, 0xaa, 0x14, 0x1f, 0xfe, 0xfe, 0x05,
+ 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x50, 0xb4, 0x0c,
+ 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
+ 0x13, 0x01, 0xfe, 0x14, 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48,
+ 0xb7, 0x19, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d,
+ 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe, 0x72, 0x06, 0x49, 0x04,
+ 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
+ 0x06, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4,
+ 0x0c, 0x3f, 0x17, 0x06, 0x01, 0xa7, 0xec, 0x72, 0x70, 0x01, 0x6e, 0x87,
+ 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0, 0xfe,
+ 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
+ 0x8d, 0x81, 0x02, 0x22, 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a,
+ 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00,
+ 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15, 0x00, 0x02, 0xfe, 0x32,
+ 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
+ 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
+ 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x06, 0x01, 0x08, 0x15, 0x00, 0x02,
+ 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe, 0x9a, 0x81, 0x4b, 0x1d,
+ 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
+ 0x45, 0xfe, 0x32, 0x12, 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25,
+ 0x32, 0xfe, 0x0a, 0xf0, 0xfe, 0x32, 0x07, 0x8d, 0x81, 0x8c, 0xfe, 0x5c,
+ 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a, 0x06, 0x15, 0x19, 0x02,
+ 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
+ 0x90, 0x77, 0xfe, 0xca, 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a,
+ 0x35, 0x1e, 0x20, 0x07, 0x10, 0xfe, 0x0e, 0x12, 0x74, 0xfe, 0x80, 0x80,
+ 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe, 0x83, 0xe7, 0xc4, 0xa1,
+ 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
+ 0x40, 0x12, 0x58, 0x01, 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
+ 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x83, 0xfb, 0xfe, 0x8a, 0x90, 0x0c, 0x52,
+ 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe,
+ 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
+ 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18,
+ 0x55, 0x09, 0x04, 0x4f, 0x85, 0x01, 0xa8, 0xfe, 0x1f, 0x80, 0x12, 0x58,
+ 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56, 0x18, 0x57, 0xfb, 0xfe,
+ 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
+ 0x0c, 0x39, 0x18, 0x3a, 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35,
+ 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x48, 0x08, 0xfe, 0x9e, 0xf0,
+ 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0xfe, 0x80,
+ 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
+ 0xfe, 0x7a, 0x08, 0x8d, 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10,
+ 0x15, 0x19, 0xfe, 0xc9, 0x10, 0x61, 0x04, 0x06, 0xfe, 0x10, 0x12, 0x61,
+ 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68, 0x12, 0xfe, 0x2e, 0x1c,
+ 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
+ 0x52, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe,
+ 0xac, 0xf0, 0xfe, 0xbe, 0x08, 0xfe, 0x8a, 0x10, 0xaa, 0xfe, 0xf3, 0x10,
+ 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe, 0x24, 0x0a, 0xab, 0xfe,
+ 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
+ 0x1c, 0x12, 0xb5, 0xfe, 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
+ 0x16, 0x9d, 0x05, 0xcb, 0x1c, 0x06, 0x16, 0x9d, 0xb8, 0x6d, 0xb9, 0x6d,
+ 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b, 0x14, 0x92, 0x01, 0x33,
+ 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
+ 0xfe, 0x74, 0x18, 0x1c, 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01,
+ 0xfe, 0x44, 0x0d, 0x3b, 0x01, 0xe6, 0x1e, 0x27, 0x74, 0x67, 0x1a, 0x02,
+ 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a, 0x09, 0x04, 0x6a, 0xfe,
+ 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
+ 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
+ 0xfe, 0x86, 0x91, 0x63, 0x27, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x77,
+ 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18, 0x7c, 0xbe, 0x54, 0xbf,
+ 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
+ 0x79, 0x56, 0x68, 0x57, 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05,
+ 0xfa, 0x4e, 0x01, 0xa5, 0xa2, 0x23, 0x0c, 0x7b, 0x0c, 0x7c, 0x79, 0x56,
+ 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x79, 0x39,
+ 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
+ 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59,
+ 0x02, 0x6d, 0x09, 0x04, 0x19, 0x16, 0xd7, 0x09, 0x04, 0xfe, 0xf7, 0x00,
+ 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f, 0xfe, 0x10, 0x90, 0xfe,
+ 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
+ 0x11, 0x9b, 0x09, 0x04, 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a,
+ 0x77, 0xfe, 0xc6, 0x08, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x6d,
+ 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04, 0x0b, 0xfe, 0x1a, 0x12,
+ 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
+ 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe,
+ 0x6c, 0x19, 0xbe, 0x39, 0xfe, 0xed, 0x19, 0xbf, 0x3a, 0xfe, 0x0c, 0x51,
+ 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff, 0x34, 0xfe, 0x74, 0x10,
+ 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
+ 0x84, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00,
+ 0x02, 0x5a, 0xfe, 0xd1, 0xf0, 0xfe, 0xc4, 0x0a, 0x14, 0x7a, 0x01, 0x33,
+ 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xca,
+ 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
+ 0x22, 0x00, 0x02, 0x5a, 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe,
+ 0x24, 0x00, 0x02, 0x5a, 0xfe, 0xd0, 0xf0, 0xfe, 0xec, 0x0a, 0x0f, 0x93,
+ 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f, 0x4c, 0xfe, 0x10, 0x10,
+ 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
+ 0x2a, 0x13, 0xfe, 0x4e, 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0,
+ 0xfe, 0x20, 0x0b, 0xb1, 0x16, 0x32, 0x2a, 0x73, 0xdd, 0xb8, 0x22, 0xb9,
+ 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25, 0x32, 0x8c, 0xfe, 0x48,
+ 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
+ 0xdb, 0x10, 0x11, 0xfe, 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd,
+ 0x7f, 0xfe, 0x89, 0xf0, 0x22, 0x30, 0x2e, 0xd8, 0xbc, 0x7d, 0xbd, 0x7f,
+ 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1, 0x45, 0x0f, 0xfe, 0x42,
+ 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
+ 0x09, 0x04, 0x0b, 0xfe, 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54,
+ 0x12, 0x4b, 0xfe, 0x28, 0x00, 0x21, 0xfe, 0xa6, 0x0c, 0x0a, 0x40, 0x01,
+ 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01,
+ 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
+ 0x01, 0x6f, 0x02, 0x29, 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e,
+ 0x0b, 0xfe, 0xb4, 0x10, 0x01, 0x86, 0x3e, 0x0b, 0xfe, 0xaa, 0x10, 0x01,
+ 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3, 0x3e, 0x0b, 0x0f, 0xfe,
+ 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
+ 0xe8, 0x59, 0x11, 0x2d, 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02,
+ 0xfe, 0x2a, 0x03, 0x09, 0x04, 0x0b, 0x84, 0x3e, 0x0b, 0x0f, 0x00, 0xfe,
+ 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12, 0x09, 0x04, 0x1b, 0xfe,
+ 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
+ 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35,
+ 0xfe, 0xa9, 0x10, 0x0f, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0b, 0x5f,
+ 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x0f, 0xfe, 0x47, 0x00,
+ 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
+ 0xab, 0x70, 0x05, 0x6b, 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b,
+ 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x59, 0x01, 0xda, 0x02, 0x29, 0xea,
+ 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31, 0x00, 0x37, 0x97, 0x01,
+ 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
+ 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47,
+ 0x4b, 0x89, 0xfe, 0x75, 0x57, 0x05, 0x51, 0xfe, 0x98, 0x56, 0xfe, 0x38,
+ 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48, 0x46, 0x09, 0x04, 0x1d,
+ 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
+ 0x99, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe,
+ 0x2a, 0x03, 0x0a, 0x51, 0xfe, 0xee, 0x14, 0xee, 0x3e, 0x1d, 0xfe, 0xce,
+ 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x29, 0x1e,
+ 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
+ 0xce, 0x1e, 0x2d, 0x47, 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe,
+ 0xec, 0x0d, 0x13, 0x06, 0x12, 0x4d, 0x01, 0xfe, 0xe2, 0x15, 0x05, 0xfe,
+ 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe, 0xf0, 0x0d, 0xfe, 0x02,
+ 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
+ 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4,
+ 0x0d, 0xfe, 0x18, 0x13, 0xaf, 0xfe, 0x02, 0xea, 0xce, 0x62, 0x7a, 0xfe,
+ 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c, 0x05, 0xfe, 0x38, 0x01,
+ 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
+ 0x0c, 0xfe, 0x62, 0x01, 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11,
+ 0x2d, 0x8a, 0x13, 0x06, 0x03, 0x23, 0x03, 0x1e, 0x4d, 0xfe, 0xf7, 0x12,
+ 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe, 0x71, 0x13, 0xfe, 0x24,
+ 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
+ 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc,
+ 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x23,
+ 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6, 0x75, 0x03, 0x09, 0x04,
+ 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
+ 0xfe, 0x1e, 0x80, 0xe1, 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe,
+ 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xa3, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
+ 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82, 0x16, 0x2f, 0x07, 0x2d,
+ 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
+ 0xe8, 0x11, 0xfe, 0xe9, 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01,
+ 0xfe, 0x14, 0x16, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
+ 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01, 0x09, 0x04, 0x4f, 0xfe,
+ 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
+ 0x40, 0x12, 0x20, 0x63, 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76,
+ 0x20, 0x03, 0xfe, 0x08, 0x1c, 0x05, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
+ 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05, 0xfe, 0xb0, 0x00, 0xfe,
+ 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
+ 0x24, 0x69, 0x12, 0xc9, 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48,
+ 0x5f, 0x17, 0x1d, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x21, 0xfe, 0x08,
+ 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c, 0xfe, 0x90, 0x4d, 0xfe,
+ 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
+ 0x46, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0,
+ 0xfe, 0x32, 0x0f, 0xea, 0x70, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
+ 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee, 0xfe, 0x07, 0xe6, 0x1d,
+ 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
+ 0xfa, 0xef, 0xfe, 0x42, 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a,
+ 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x36, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
+ 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10,
+ 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
+ 0x10, 0x07, 0x7e, 0x45, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03,
+ 0xfe, 0x44, 0x58, 0x74, 0xfe, 0x01, 0xec, 0x97, 0xfe, 0x9e, 0x40, 0xfe,
+ 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76, 0x27, 0x01, 0xda, 0xfe,
+ 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
+ 0xfe, 0x48, 0x12, 0x07, 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30,
+ 0x12, 0x07, 0xc2, 0x16, 0xfe, 0x3e, 0x11, 0x07, 0xfe, 0x23, 0x00, 0x16,
+ 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8, 0x11, 0x07, 0x19, 0xfe,
+ 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
+ 0x01, 0x08, 0x8c, 0x43, 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01,
+ 0xfe, 0x32, 0x0e, 0x11, 0x7e, 0x02, 0x29, 0x2b, 0x2f, 0x07, 0x9b, 0xfe,
+ 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe, 0xfc, 0x10, 0x09, 0x04,
+ 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
+ 0xc6, 0x10, 0x1e, 0x58, 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77,
+ 0xfe, 0x82, 0x0c, 0x0c, 0x54, 0x18, 0x55, 0x23, 0x0c, 0x7b, 0x0c, 0x7c,
+ 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01, 0xa5, 0xc0, 0x38, 0xc1,
+ 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
+ 0x05, 0xfa, 0x4e, 0xfe, 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40,
+ 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x56, 0x18, 0x57, 0x83, 0xc0, 0x38, 0xc1,
+ 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
+ 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
+ 0x58, 0xfe, 0x1f, 0x40, 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe,
+ 0xae, 0x50, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x44, 0x50, 0xfe, 0xc6, 0x50,
+ 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x05, 0x39,
+ 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
+ 0x12, 0xcd, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5,
+ 0x07, 0x06, 0x21, 0x44, 0x2f, 0x07, 0x9b, 0x21, 0x5b, 0x01, 0x6e, 0x1c,
+ 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79, 0x39, 0x68, 0x3a, 0xfe,
+ 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
+ 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19,
+ 0x41, 0x02, 0x5b, 0x2b, 0x01, 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e,
+ 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b, 0x3b, 0x02, 0x44, 0x01,
+ 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
+ 0x01, 0x08, 0x1f, 0xa2, 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49,
+ 0x60, 0x05, 0xfe, 0x9c, 0x00, 0x28, 0x84, 0x49, 0x04, 0x19, 0x34, 0x9f,
+ 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06, 0x78, 0x3d, 0xfe, 0xda,
+ 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
+ 0x05, 0xc6, 0x28, 0x84, 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe,
+ 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17, 0x05, 0x50, 0xb4, 0x0c,
+ 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe, 0xaa, 0x14, 0x02,
+ 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
+ 0x21, 0x44, 0x01, 0xfe, 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14,
+ 0xfe, 0xa4, 0x14, 0x87, 0xfe, 0x4a, 0xf4, 0x0b, 0x16, 0x44, 0xfe, 0x4a,
+ 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a, 0x85, 0x02, 0x5b, 0x05,
+ 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
+ 0xd8, 0x14, 0x02, 0x5c, 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe,
+ 0xe0, 0x12, 0x72, 0xf1, 0x01, 0x08, 0x23, 0x72, 0x03, 0x8f, 0xfe, 0xdc,
+ 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca, 0x12, 0x5e, 0x2b, 0x01,
+ 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
+ 0x1c, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13,
+ 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0x1c, 0x3d, 0xfe, 0x30, 0x56,
+ 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
+ 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
+ 0x03, 0x0a, 0x50, 0x01, 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c,
+ 0x10, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x19, 0x48, 0xfe, 0x00,
+ 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x63, 0x27,
+ 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
+ 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01,
+ 0xfe, 0x14, 0x18, 0xfe, 0x42, 0x48, 0x5f, 0x60, 0x89, 0x01, 0x08, 0x1f,
+ 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14,
+ 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
+ 0xcc, 0x12, 0x49, 0x04, 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2,
+ 0x4b, 0xc3, 0x64, 0xfe, 0xe8, 0x13, 0x3b, 0x13, 0x06, 0x17, 0xc3, 0x78,
+ 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xa1, 0xff, 0x02, 0x83,
+ 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
+ 0x13, 0x06, 0xfe, 0x56, 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00,
+ 0x8e, 0xe4, 0x0a, 0xfe, 0x64, 0x00, 0x17, 0x93, 0x13, 0x06, 0xfe, 0x28,
+ 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe, 0xc8, 0x00, 0x8e, 0xe4,
+ 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
+ 0x01, 0xba, 0xfe, 0x4e, 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4,
+ 0x94, 0xfe, 0x56, 0xf0, 0xfe, 0x60, 0x14, 0xfe, 0x04, 0xf4, 0x6c, 0xfe,
+ 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01, 0xfe, 0x22, 0x13, 0x1c,
+ 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
+ 0xfe, 0x9c, 0x14, 0xb7, 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe,
+ 0x4d, 0xe4, 0x19, 0xba, 0xfe, 0x9c, 0x14, 0xb7, 0x19, 0x83, 0x60, 0x23,
+ 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06, 0xfe, 0xb4, 0x56, 0xfe,
+ 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
+ 0xe5, 0x15, 0x0b, 0x01, 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26,
+ 0xe5, 0x72, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x03, 0x15, 0x06, 0x01, 0x08,
+ 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x06, 0x01, 0x08,
+ 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
+ 0x4a, 0x01, 0x08, 0x03, 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44,
+ 0x13, 0xad, 0x12, 0xcc, 0xfe, 0x49, 0xf4, 0x00, 0x3b, 0x72, 0x9f, 0x5e,
+ 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01, 0x08, 0x2f, 0x07, 0xfe,
+ 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
+ 0x01, 0x43, 0x1e, 0xcd, 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03,
+ 0x0a, 0x42, 0x01, 0x0e, 0xed, 0x88, 0x07, 0x10, 0xa4, 0x0a, 0x80, 0x01,
+ 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x80, 0x01, 0x0e, 0x88,
+ 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
+ 0x88, 0x03, 0x0a, 0x42, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03,
+ 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x80, 0x80, 0xf2, 0xfe, 0x49, 0xe4, 0x10,
+ 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51, 0x01, 0x82, 0x03, 0x17,
+ 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
+ 0xfe, 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01,
+ 0xfe, 0xfc, 0x16, 0xe0, 0x91, 0x1d, 0x66, 0xfe, 0x2c, 0x01, 0xfe, 0x2f,
+ 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe, 0xda, 0x10, 0x17, 0x10,
+ 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
+ 0x05, 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90,
+ 0xfe, 0x30, 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x66, 0xfe, 0x38, 0x00, 0xfe,
+ 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe, 0x40, 0x16, 0xfe, 0xb6,
+ 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
+ 0x10, 0x71, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
+ 0x1d, 0xf7, 0x38, 0x90, 0xfe, 0x62, 0x16, 0xfe, 0x94, 0x14, 0xfe, 0x10,
+ 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00,
+ 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
+ 0xfe, 0x30, 0xbc, 0xfe, 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f,
+ 0x79, 0xfe, 0x1c, 0xf7, 0xc5, 0x90, 0xfe, 0x9a, 0x16, 0xfe, 0x5c, 0x14,
+ 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe, 0x42, 0x10, 0xfe, 0x02,
+ 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
+ 0xfe, 0x1d, 0xf7, 0x4f, 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe,
+ 0x1c, 0x13, 0x91, 0x4f, 0x47, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe,
+ 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11, 0xfe, 0xdd, 0x00, 0x63,
+ 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
+ 0x06, 0x37, 0x95, 0xa9, 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17,
+ 0x23, 0x03, 0xfe, 0x7e, 0x18, 0x1c, 0x1a, 0x5d, 0x13, 0x0d, 0x03, 0x71,
+ 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x78, 0x2c,
+ 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
+ 0x13, 0x3c, 0x8a, 0x0a, 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0,
+ 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
+ 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x01, 0x6f,
+ 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
+ 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c,
+ 0xe7, 0x0b, 0x0f, 0xfe, 0x15, 0x00, 0x59, 0x76, 0x27, 0x01, 0xda, 0x17,
+ 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35, 0x11, 0x2d, 0x01, 0x6f,
+ 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
+ 0xc8, 0xfe, 0x48, 0x55, 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73,
+ 0x12, 0x98, 0x03, 0x0a, 0x99, 0x01, 0x0e, 0xf0, 0x0a, 0x40, 0x01, 0x0e,
+ 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73, 0x75, 0x03, 0x0a, 0x42,
+ 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
+ 0x0e, 0x73, 0x75, 0x03, 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18,
+ 0x05, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0x5b, 0xfe, 0x4e, 0xe4, 0xc2,
+ 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1b,
+ 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
+ 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe,
+ 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x2c, 0xfe, 0x4e, 0x45, 0xfe, 0x0c, 0x12,
+ 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69, 0x03, 0x07, 0x7a, 0xfe,
+ 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
+ 0x07, 0x1b, 0xfe, 0x5a, 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26,
+ 0x10, 0x07, 0x1a, 0x5d, 0x24, 0x2c, 0xdc, 0x07, 0x0b, 0x5d, 0x24, 0x93,
+ 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d, 0x9f, 0xad, 0x03, 0x14,
+ 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
+ 0x03, 0x25, 0xfe, 0xca, 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6,
+ 0x18, 0x03, 0xff, 0x1a, 0x00, 0x00,
+};
+
+static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
+static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
+
+/* Microcode buffer is kept after initialization for error recovery. */
+static unsigned char _adv_asc38C0800_buf[] = {
+ 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
+ 0x01, 0x00, 0x48, 0xe4, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19,
+ 0x00, 0xfa, 0xff, 0xff, 0x1c, 0x0f, 0x00, 0xf6, 0x9e, 0xe7, 0xff, 0x00,
+ 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6, 0x09, 0xe7, 0x55, 0xf0,
+ 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
+ 0x18, 0xf4, 0x08, 0x00, 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0,
+ 0x82, 0x0d, 0x00, 0xe6, 0x86, 0xf0, 0xb1, 0xf0, 0x98, 0x57, 0x01, 0xfc,
+ 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x3c, 0x00, 0xbb, 0x00,
+ 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
+ 0xba, 0x13, 0x18, 0x40, 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc,
+ 0x3e, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x74, 0x01, 0x76, 0x01, 0xb9, 0x54,
+ 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00, 0xc0, 0x00, 0x01, 0x01,
+ 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
+ 0x08, 0x12, 0x02, 0x4a, 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80,
+ 0x30, 0xe4, 0x4b, 0xe4, 0x5d, 0xf0, 0x02, 0xfa, 0x20, 0x00, 0x32, 0x00,
+ 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01,
+ 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
+ 0x06, 0x13, 0x4c, 0x1c, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0,
+ 0x03, 0xf7, 0x0c, 0x00, 0x0f, 0x00, 0x47, 0x00, 0xbe, 0x00, 0x00, 0x01,
+ 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44,
+ 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
+ 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01,
+ 0x4e, 0x01, 0x4a, 0x0b, 0x42, 0x0c, 0x12, 0x0f, 0x0c, 0x10, 0x22, 0x11,
+ 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48, 0x00, 0x4e, 0x42, 0x54,
+ 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
+ 0x59, 0xf0, 0xb8, 0xf0, 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc,
+ 0x05, 0xfc, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00, 0xa4, 0x00,
+ 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xe2, 0x03,
+ 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
+ 0x12, 0x13, 0x24, 0x14, 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17,
+ 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44,
+ 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x3a, 0x55, 0x83, 0x55,
+ 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
+ 0x0c, 0xf0, 0x04, 0xf8, 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00,
+ 0x1e, 0x00, 0x9e, 0x00, 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00,
+ 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01, 0xc4, 0x01, 0xc6, 0x01,
+ 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
+ 0x68, 0x08, 0x69, 0x08, 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f,
+ 0x12, 0x10, 0x1a, 0x10, 0xed, 0x10, 0xf1, 0x10, 0x2a, 0x11, 0x06, 0x12,
+ 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x46, 0x14,
+ 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
+ 0xca, 0x18, 0xe6, 0x19, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
+ 0x0e, 0x47, 0xfe, 0x9c, 0xf0, 0x2b, 0x02, 0xfe, 0xac, 0x0d, 0xff, 0x10,
+ 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6, 0xfe, 0x84, 0x01, 0xff,
+ 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+ 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00,
+ 0x00, 0x11, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
+ 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x11,
+ 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+ 0xfe, 0x04, 0xf7, 0xd6, 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe,
+ 0x04, 0xf7, 0xd6, 0x99, 0x0a, 0x42, 0x2c, 0xfe, 0x3d, 0xf0, 0xfe, 0x06,
+ 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0, 0xfe, 0xf4, 0x01, 0xfe,
+ 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
+ 0x02, 0xfe, 0xc8, 0x0d, 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe,
+ 0xfc, 0x10, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd3, 0x12,
+ 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48, 0xf0, 0xfe, 0x8a, 0x02,
+ 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
+ 0xfe, 0x46, 0xf0, 0xfe, 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02,
+ 0xfe, 0x43, 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x4c, 0x02,
+ 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a, 0xaa, 0x18, 0x06, 0x14,
+ 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
+ 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10,
+ 0xfe, 0x06, 0xfc, 0xce, 0x09, 0x70, 0x01, 0xa8, 0x02, 0x2b, 0x15, 0x59,
+ 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xbd,
+ 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
+ 0x58, 0x1c, 0x18, 0x06, 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0,
+ 0xfe, 0x06, 0x02, 0x23, 0xfe, 0x98, 0x02, 0xfe, 0x5a, 0x1c, 0xf8, 0xfe,
+ 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10,
+ 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
+ 0x69, 0x10, 0x18, 0x06, 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43,
+ 0x13, 0x20, 0xfe, 0x05, 0xf6, 0xce, 0x01, 0xfe, 0x4a, 0x17, 0x08, 0x54,
+ 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b,
+ 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
+ 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe,
+ 0x10, 0x03, 0x01, 0xfe, 0x82, 0x16, 0x02, 0x2b, 0x2c, 0x4f, 0xfe, 0x02,
+ 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe,
+ 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
+ 0xfe, 0x40, 0x1c, 0x1c, 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe,
+ 0xa0, 0xf0, 0xfe, 0x48, 0x03, 0xfe, 0x11, 0xf0, 0xa7, 0xfe, 0xef, 0x10,
+ 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10, 0xfe, 0x11, 0x00, 0x02,
+ 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
+ 0x21, 0x22, 0xa3, 0xb7, 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78,
+ 0x01, 0xfe, 0xb4, 0x16, 0x12, 0xd1, 0x1c, 0xd9, 0xfe, 0x01, 0xf0, 0xd9,
+ 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12, 0xfe, 0xe4, 0x00, 0x27,
+ 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
+ 0x06, 0xf0, 0xfe, 0xc8, 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a,
+ 0x06, 0x02, 0x24, 0x03, 0x70, 0x28, 0x17, 0xfe, 0xfa, 0x04, 0x15, 0x6d,
+ 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8, 0xf9, 0x2c, 0x99, 0x19,
+ 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
+ 0x74, 0x01, 0xaf, 0x8c, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda,
+ 0x09, 0xd1, 0x01, 0x0e, 0x8d, 0x51, 0x64, 0x79, 0x2a, 0x03, 0x70, 0x28,
+ 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02,
+ 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
+ 0xfe, 0x3c, 0x04, 0x3b, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
+ 0x12, 0x2d, 0xff, 0x02, 0x00, 0x10, 0x01, 0x0b, 0x1d, 0xfe, 0xe4, 0x04,
+ 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde, 0xfe, 0x4c, 0x44, 0xfe,
+ 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
+ 0xda, 0x4f, 0x79, 0x2a, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62,
+ 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x2a, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x52,
+ 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b, 0xda, 0xfe,
+ 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
+ 0x08, 0x13, 0x32, 0x07, 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe,
+ 0x1c, 0x12, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00,
+ 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x2d, 0x12, 0xfe, 0xe6,
+ 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
+ 0x02, 0x2b, 0xfe, 0x42, 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf,
+ 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x87, 0x80, 0xfe, 0x31, 0xe4, 0x5b, 0x08,
+ 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x19, 0xfe, 0x7c,
+ 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
+ 0x17, 0xfe, 0x90, 0x05, 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe,
+ 0x56, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x28, 0xfe, 0x4e, 0x12, 0x67, 0xff,
+ 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c, 0x34, 0xfe, 0x89, 0x48,
+ 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
+ 0x12, 0xfe, 0xe3, 0x00, 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05,
+ 0xfe, 0x49, 0xf0, 0xfe, 0x70, 0x05, 0x88, 0x25, 0xfe, 0x21, 0x00, 0xab,
+ 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe, 0x09, 0x48, 0xff, 0x02,
+ 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
+ 0x08, 0x53, 0x05, 0xcb, 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39,
+ 0xfe, 0x27, 0x01, 0x08, 0x05, 0x1b, 0xfe, 0x22, 0x12, 0x41, 0x01, 0xb2,
+ 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36,
+ 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
+ 0x03, 0x5c, 0x28, 0xfe, 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18,
+ 0x06, 0x09, 0x06, 0x53, 0x05, 0x1f, 0xfe, 0x02, 0x12, 0x50, 0x01, 0xfe,
+ 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe,
+ 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
+ 0x12, 0x03, 0x45, 0x28, 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01,
+ 0xfe, 0x76, 0x19, 0xfe, 0x43, 0x48, 0xc4, 0xcc, 0x0f, 0x71, 0xff, 0x02,
+ 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4, 0x6e, 0x41, 0x01, 0xb2,
+ 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
+ 0xfe, 0xcc, 0x15, 0x1d, 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12,
+ 0xfe, 0xe5, 0x00, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x18, 0x06, 0x01, 0xb2,
+ 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe, 0xe2, 0x00, 0x27, 0xdb,
+ 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
+ 0xfe, 0x06, 0xf0, 0xfe, 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05,
+ 0x0a, 0xfe, 0x2e, 0x12, 0x16, 0x19, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
+ 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0xfe, 0x99, 0xa4, 0x01,
+ 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
+ 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01,
+ 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
+ 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02, 0xe2, 0x6c, 0x58, 0xbe,
+ 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
+ 0xfe, 0x09, 0x6f, 0xba, 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d,
+ 0x8b, 0x6c, 0x7f, 0x27, 0xfe, 0x54, 0x07, 0x1c, 0x34, 0xfe, 0x0a, 0xf0,
+ 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c, 0x07, 0x02, 0x24, 0x01,
+ 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
+ 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14,
+ 0x61, 0x08, 0x54, 0x5a, 0x37, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x0e, 0x12,
+ 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a, 0xfe, 0x06, 0x10, 0xfe,
+ 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
+ 0x37, 0x01, 0xb3, 0xb8, 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe,
+ 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0x88,
+ 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x0c,
+ 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
+ 0x14, 0x3e, 0xfe, 0x4a, 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe,
+ 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x05, 0x5b,
+ 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62, 0xfe, 0x44, 0x90, 0xfe,
+ 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
+ 0x0c, 0x5e, 0x14, 0x5f, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d,
+ 0x14, 0x3e, 0x0c, 0x2e, 0x14, 0x3c, 0x21, 0x0c, 0x49, 0x0c, 0x63, 0x08,
+ 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27, 0xdd, 0xfe, 0x9e,
+ 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
+ 0x9a, 0x08, 0xc6, 0xfe, 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06,
+ 0xf0, 0xfe, 0x94, 0x08, 0x95, 0x86, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xc9,
+ 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05, 0x06, 0xfe, 0x10, 0x12,
+ 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
+ 0x1c, 0x02, 0xfe, 0x18, 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a,
+ 0xfe, 0x7a, 0x12, 0xfe, 0x2c, 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0xd2, 0x09,
+ 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe, 0xde, 0x09, 0xfe, 0xb7,
+ 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
+ 0xfe, 0xf1, 0x18, 0xfe, 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58,
+ 0xfe, 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x1c, 0x85, 0xfe,
+ 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0, 0xfe, 0xf0, 0x08, 0xb5,
+ 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
+ 0x0b, 0xb6, 0xfe, 0xbf, 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe,
+ 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xc2, 0xfe, 0xd2, 0xf0, 0x85, 0xfe, 0x76,
+ 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e, 0x06, 0x17, 0x85, 0xc5,
+ 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
+ 0x9d, 0x01, 0x36, 0x10, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10,
+ 0x80, 0x02, 0x65, 0xfe, 0x98, 0x80, 0xfe, 0x19, 0xe4, 0x0a, 0xfe, 0x1a,
+ 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18, 0xfe, 0x44, 0x54, 0xbe,
+ 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
+ 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f,
+ 0x14, 0x40, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x6c, 0x18, 0xfe, 0xed, 0x18,
+ 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f, 0x3b, 0x40, 0x03, 0x49,
+ 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
+ 0x8f, 0xfe, 0xe3, 0x54, 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a,
+ 0xfe, 0x37, 0xf0, 0xfe, 0xda, 0x09, 0xfe, 0x8b, 0xf0, 0xfe, 0x60, 0x09,
+ 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa, 0x0a, 0x3a, 0x49, 0x3b,
+ 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
+ 0xad, 0xfe, 0x01, 0x59, 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a,
+ 0xfe, 0x24, 0x0a, 0x3a, 0x49, 0x8f, 0xfe, 0xe3, 0x54, 0x57, 0x49, 0x7d,
+ 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02, 0x4a, 0x3a, 0x49, 0x3b,
+ 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
+ 0x02, 0x4a, 0x08, 0x05, 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe,
+ 0x66, 0x13, 0x22, 0x62, 0xb7, 0xfe, 0x03, 0xa1, 0xfe, 0x83, 0x80, 0xfe,
+ 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x6a,
+ 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
+ 0x61, 0x0c, 0x7f, 0x14, 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8,
+ 0x6a, 0x2a, 0x13, 0x62, 0x9b, 0x2e, 0x9c, 0x3c, 0x3a, 0x3f, 0x3b, 0x40,
+ 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0x01, 0xef,
+ 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
+ 0xe4, 0x08, 0x05, 0x1f, 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05,
+ 0xfe, 0xf7, 0x00, 0x37, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x10, 0x58, 0xfe,
+ 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe, 0xf4, 0x09, 0x08, 0x05,
+ 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
+ 0x81, 0x50, 0xfe, 0x10, 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32,
+ 0x07, 0xa6, 0x17, 0xfe, 0x08, 0x09, 0x12, 0xa6, 0x08, 0x05, 0x0a, 0xfe,
+ 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe, 0x08, 0x09, 0xfe, 0x0c,
+ 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
+ 0x08, 0x05, 0x0a, 0xfe, 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41,
+ 0xf4, 0xc2, 0xfe, 0xd1, 0xf0, 0xe2, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe,
+ 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0x57, 0x3d, 0xfe, 0xed,
+ 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
+ 0x00, 0xff, 0x35, 0xfe, 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6,
+ 0x0b, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x8a, 0x03, 0xd2, 0x1e, 0x06, 0xfe,
+ 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65, 0xfe, 0xd1, 0xf0, 0xfe,
+ 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
+ 0x10, 0xfe, 0xce, 0xf0, 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd,
+ 0xf0, 0xfe, 0xca, 0x0b, 0x10, 0xfe, 0x22, 0x00, 0x02, 0x65, 0xfe, 0xcb,
+ 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00, 0x02, 0x65, 0xfe, 0xd0,
+ 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
+ 0x0b, 0x10, 0x58, 0xfe, 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05,
+ 0x1f, 0x4d, 0x10, 0xfe, 0x12, 0x00, 0x2c, 0x0f, 0xfe, 0x4e, 0x11, 0x27,
+ 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14, 0x0c, 0xbc, 0x17, 0x34,
+ 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
+ 0x0c, 0x1c, 0x34, 0x94, 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6,
+ 0xdc, 0x02, 0x24, 0x01, 0x4b, 0xfe, 0xdb, 0x10, 0x12, 0xfe, 0xe8, 0x00,
+ 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe, 0x89, 0xf0, 0x24, 0x33,
+ 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
+ 0x33, 0x31, 0xdf, 0xbc, 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c,
+ 0x06, 0xfe, 0x81, 0x49, 0x17, 0xfe, 0x2c, 0x0d, 0x08, 0x05, 0x0a, 0xfe,
+ 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54, 0x12, 0x55, 0xfe, 0x28,
+ 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
+ 0x44, 0xfe, 0x28, 0x00, 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09,
+ 0xa4, 0x01, 0xfe, 0x26, 0x0f, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x02, 0x2b,
+ 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44, 0x0a, 0xfe, 0xb4, 0x10,
+ 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
+ 0xfe, 0x34, 0x46, 0xac, 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96,
+ 0x10, 0x08, 0x54, 0x0a, 0x37, 0x01, 0xf5, 0x01, 0xf6, 0x64, 0x12, 0x2f,
+ 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02, 0xfe, 0x2e, 0x03, 0x08,
+ 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
+ 0x1a, 0xfe, 0x58, 0x12, 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c,
+ 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x50, 0x0d, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d,
+ 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37, 0xfe, 0xa9, 0x10, 0x10,
+ 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
+ 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41,
+ 0x00, 0xaa, 0x10, 0xfe, 0x24, 0x00, 0x8c, 0xb5, 0xb6, 0x74, 0x03, 0x70,
+ 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a, 0xfe, 0x9d, 0x41, 0xfe,
+ 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
+ 0xb4, 0x15, 0xfe, 0x31, 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02,
+ 0xd7, 0x42, 0xfe, 0x06, 0xec, 0xd0, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45,
+ 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47, 0x4b, 0x91, 0xfe, 0x75,
+ 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
+ 0x0e, 0xfe, 0x44, 0x48, 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09,
+ 0x46, 0x01, 0x0e, 0x41, 0xfe, 0x41, 0x58, 0x09, 0xa4, 0x01, 0x0e, 0xfe,
+ 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe, 0x2e, 0x03, 0x09, 0x5d,
+ 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
+ 0xce, 0x47, 0xfe, 0xad, 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe,
+ 0x9e, 0x12, 0x21, 0x13, 0x59, 0x13, 0x9f, 0x13, 0xd5, 0x22, 0x2f, 0x41,
+ 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe, 0xe0, 0x0e, 0x0f, 0x06,
+ 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
+ 0x3a, 0x01, 0x56, 0xfe, 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00,
+ 0x66, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
+ 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe, 0x48, 0xf4, 0x0d, 0xfe,
+ 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
+ 0x15, 0x1a, 0x39, 0xa0, 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01,
+ 0x1e, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x03, 0xfe, 0x3a, 0x01,
+ 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25, 0x06, 0x13, 0x2f, 0x12,
+ 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
+ 0x22, 0x9f, 0xb7, 0x13, 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24,
+ 0x1c, 0x15, 0x19, 0x39, 0xa0, 0xb4, 0xfe, 0xd9, 0x10, 0xc3, 0xfe, 0x03,
+ 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xc3, 0xfe, 0x03, 0xdc,
+ 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
+ 0xfe, 0x00, 0xcc, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05,
+ 0x58, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
+ 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae, 0xfe, 0x0c, 0x90, 0xfe,
+ 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
+ 0x0a, 0xfe, 0x3c, 0x50, 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f,
+ 0xad, 0x01, 0xfe, 0xb4, 0x16, 0x08, 0x05, 0x1b, 0x4e, 0x01, 0xf5, 0x01,
+ 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58, 0xfe, 0x2c, 0x13, 0x01,
+ 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
+ 0x0c, 0xfe, 0x64, 0x01, 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe,
+ 0x12, 0x12, 0xfe, 0x03, 0x80, 0x8d, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
+ 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64, 0x22, 0x20, 0xfb, 0x79,
+ 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
+ 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe,
+ 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
+ 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c, 0x45, 0x0f, 0x46, 0x52,
+ 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
+ 0x0f, 0x44, 0x11, 0x0f, 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe,
+ 0x91, 0x54, 0x23, 0xe4, 0x25, 0x11, 0x13, 0x20, 0x7c, 0x6f, 0x4f, 0x22,
+ 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
+ 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
+ 0x18, 0x1c, 0x04, 0x42, 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b,
+ 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x04, 0x01, 0xb0, 0x7c, 0x6f, 0x4f,
+ 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0x32, 0x07, 0x2f,
+ 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
+ 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe,
+ 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe,
+ 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07, 0x82, 0x4e, 0xfe, 0x14,
+ 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
+ 0xfe, 0x01, 0xec, 0xa2, 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe,
+ 0x9c, 0xe7, 0x1a, 0x79, 0x2a, 0x01, 0xe3, 0xfe, 0xdd, 0x10, 0x2c, 0xc7,
+ 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a, 0xfe, 0x48, 0x12, 0x07,
+ 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
+ 0xfe, 0x32, 0x12, 0x07, 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17,
+ 0xfe, 0x9c, 0x12, 0x07, 0x1f, 0xfe, 0x12, 0x12, 0x07, 0x00, 0x17, 0x24,
+ 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b, 0x94, 0x4b, 0x04, 0x2d,
+ 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
+ 0x32, 0x07, 0xa6, 0xfe, 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe,
+ 0xf0, 0x11, 0x08, 0x05, 0x5a, 0xfe, 0x72, 0x12, 0x9b, 0x2e, 0x9c, 0x3c,
+ 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62, 0xfe, 0x26, 0x13, 0x03,
+ 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
+ 0x0c, 0x7f, 0x0c, 0x80, 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01,
+ 0xef, 0x9b, 0x2e, 0x9c, 0x3c, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe,
+ 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe, 0x91, 0x10, 0x03, 0x3f,
+ 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
+ 0x88, 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe,
+ 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x0c, 0x5e, 0x14, 0x5f, 0x08, 0x05, 0x5a,
+ 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40, 0x03, 0x60, 0x29, 0x61,
+ 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
+ 0x50, 0xfe, 0xc6, 0x50, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe,
+ 0x8a, 0x50, 0x03, 0x3d, 0x29, 0x3e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50,
+ 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1d,
+ 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
+ 0x72, 0x01, 0xaf, 0x1e, 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a,
+ 0x3d, 0x3b, 0x3e, 0xfe, 0x0a, 0x55, 0x35, 0xfe, 0x8b, 0x55, 0x57, 0x3d,
+ 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x02, 0x72, 0xfe, 0x19,
+ 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
+ 0x1d, 0xe8, 0x33, 0x31, 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a,
+ 0x4d, 0x02, 0x4c, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0xe8, 0x33, 0x31, 0xdf,
+ 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8, 0x33, 0x31, 0xfe, 0xe8,
+ 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
+ 0x05, 0x1f, 0x35, 0xa9, 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06,
+ 0x7c, 0x43, 0xfe, 0xda, 0x14, 0x01, 0xaf, 0x8c, 0xfe, 0x4b, 0x45, 0xee,
+ 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a, 0x03, 0x45, 0x28, 0x35,
+ 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
+ 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01,
+ 0xfe, 0x9e, 0x15, 0x02, 0x89, 0x01, 0x0b, 0x1c, 0x34, 0x1d, 0x4c, 0x33,
+ 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1, 0xfe, 0x42, 0x58, 0xf1,
+ 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
+ 0xf4, 0x06, 0xea, 0x32, 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1,
+ 0x0c, 0x45, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0xcc, 0x15,
+ 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13, 0x26, 0xfe, 0xd4, 0x13,
+ 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
+ 0x13, 0x1c, 0xfe, 0xd0, 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01,
+ 0x0b, 0xfe, 0xd5, 0x10, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
+ 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x04, 0x0f,
+ 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
+ 0xfe, 0x00, 0x5c, 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93,
+ 0x04, 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0xfe, 0x0b, 0x58,
+ 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01, 0x87, 0x04, 0xfe, 0x03,
+ 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
+ 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c,
+ 0x6a, 0x2a, 0x0c, 0x5e, 0x14, 0x5f, 0x57, 0x3f, 0x7d, 0x40, 0x04, 0xdd,
+ 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x8d, 0x04, 0x01,
+ 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
+ 0xfe, 0x96, 0x15, 0x33, 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15,
+ 0x33, 0x31, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0xcd, 0x28, 0xfe,
+ 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13, 0x21, 0x69, 0x1a, 0xee,
+ 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
+ 0x30, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83,
+ 0x55, 0x69, 0x19, 0xae, 0x98, 0xfe, 0x30, 0x00, 0x96, 0xf2, 0x18, 0x6d,
+ 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed, 0x98, 0xfe, 0x64, 0x00,
+ 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
+ 0x10, 0x69, 0x06, 0xfe, 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2,
+ 0x09, 0xfe, 0xc8, 0x00, 0x18, 0x59, 0x0f, 0x06, 0x88, 0x98, 0xfe, 0x90,
+ 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe, 0x43, 0xf4, 0x9f, 0xfe,
+ 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
+ 0x9e, 0xfe, 0xf3, 0x10, 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e,
+ 0x43, 0xec, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x6e, 0x7a, 0xfe, 0x90,
+ 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4,
+ 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
+ 0xf4, 0x00, 0xe9, 0x91, 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58,
+ 0x04, 0x51, 0x0f, 0x0a, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xf3, 0x16,
+ 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01, 0x0b, 0x26, 0xf3, 0x76,
+ 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
+ 0x16, 0x19, 0x01, 0x0b, 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
+ 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x26, 0xb1, 0x76, 0xfe, 0x89, 0x4a, 0x01,
+ 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06, 0xfe, 0x48, 0x13, 0xb8,
+ 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
+ 0xec, 0xfe, 0x27, 0x01, 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27,
+ 0xfe, 0x2e, 0x16, 0x32, 0x07, 0xfe, 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1d,
+ 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b, 0x22, 0xd4, 0x07, 0x06,
+ 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
+ 0x07, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8,
+ 0x04, 0x09, 0x84, 0x01, 0x0e, 0x8e, 0xfe, 0x80, 0xe7, 0x11, 0x07, 0x11,
+ 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04, 0x09, 0x48, 0x01, 0x0e,
+ 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
+ 0x80, 0xfe, 0x80, 0x4c, 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01,
+ 0x0e, 0xfe, 0x80, 0x4c, 0x09, 0x5d, 0x01, 0x87, 0x04, 0x18, 0x11, 0x75,
+ 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24,
+ 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
+ 0x17, 0xad, 0x9a, 0x1b, 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04,
+ 0xb9, 0x23, 0xfe, 0xde, 0x16, 0xfe, 0xda, 0x10, 0x18, 0x11, 0x75, 0x03,
+ 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe, 0x18, 0x58, 0x03, 0xfe,
+ 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
+ 0xf4, 0x06, 0xfe, 0x3c, 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79,
+ 0xfe, 0x1c, 0xf7, 0x1f, 0x97, 0xfe, 0x38, 0x17, 0xfe, 0xb6, 0x14, 0x35,
+ 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c, 0x10, 0x18, 0x11, 0x75,
+ 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
+ 0x2e, 0x97, 0xfe, 0x5a, 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c,
+ 0x1a, 0xfe, 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x04, 0xb9, 0x23, 0xfe,
+ 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75, 0xfe, 0x30, 0xbc, 0xfe,
+ 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
+ 0xcb, 0x97, 0xfe, 0x92, 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23,
+ 0xfe, 0x7e, 0x17, 0xfe, 0x42, 0x10, 0xfe, 0x02, 0xf6, 0x11, 0x75, 0xfe,
+ 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe, 0x03, 0xa1, 0xfe, 0x1d,
+ 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
+ 0x9a, 0x5b, 0x41, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7,
+ 0x11, 0xfe, 0x81, 0xe7, 0x11, 0x12, 0xfe, 0xdd, 0x00, 0x6a, 0x2a, 0x04,
+ 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8, 0x17, 0x15, 0x06, 0x39,
+ 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
+ 0xfe, 0x7e, 0x18, 0x1e, 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2,
+ 0x1e, 0x06, 0xfe, 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x7c, 0x6f, 0x4f, 0x32,
+ 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42, 0x13, 0x42, 0x92, 0x09,
+ 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
+ 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11,
+ 0xac, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c, 0x01, 0x73, 0xfe, 0x16,
+ 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12, 0xfe, 0x14,
+ 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
+ 0xe7, 0x0a, 0x10, 0xfe, 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18,
+ 0x06, 0x04, 0x42, 0x92, 0x08, 0x54, 0x1b, 0x37, 0x12, 0x2f, 0x01, 0x73,
+ 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x3a, 0xce, 0x3b,
+ 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
+ 0x13, 0xa3, 0x04, 0x09, 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46,
+ 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x17, 0xfe, 0xe8, 0x18, 0x77, 0x78, 0x04,
+ 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09, 0x5d, 0x01, 0xa8, 0x09,
+ 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
+ 0x1c, 0x19, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10,
+ 0xfe, 0x4e, 0xe4, 0xc9, 0x6b, 0xfe, 0x2e, 0x19, 0x03, 0xfe, 0x92, 0x00,
+ 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x6b,
+ 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
+ 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e,
+ 0x45, 0xea, 0xba, 0xff, 0x04, 0x68, 0x54, 0xe7, 0x1e, 0x6e, 0xfe, 0x08,
+ 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe, 0x1a, 0xf4, 0xfe, 0x00,
+ 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
+ 0x04, 0x07, 0x7e, 0xfe, 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09,
+ 0x00, 0xfe, 0x34, 0x10, 0x07, 0x1a, 0xfe, 0x5a, 0xf0, 0xfe, 0x92, 0x19,
+ 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66, 0x25, 0x6d, 0xe5, 0x07,
+ 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
+ 0xa9, 0xb8, 0x04, 0x15, 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe,
+ 0x81, 0x03, 0x83, 0xfe, 0x40, 0x5c, 0x04, 0x1c, 0xf7, 0xfe, 0x14, 0xf0,
+ 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b, 0xf7, 0xfe, 0x82, 0xf0,
+ 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
+};
+
+static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
+static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
+
+/* Microcode buffer is kept after initialization for error recovery. */
+static unsigned char _adv_asc38C1600_buf[] = {
+ 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
+ 0x18, 0xe4, 0x01, 0x00, 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13,
+ 0x2e, 0x1e, 0x02, 0x00, 0x07, 0x17, 0xc0, 0x5f, 0x00, 0xfa, 0xff, 0xff,
+ 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7, 0x85, 0xf0, 0x86, 0xf0,
+ 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
+ 0x98, 0x57, 0x01, 0xe6, 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4,
+ 0x08, 0x00, 0xf0, 0x1d, 0x38, 0x54, 0x32, 0xf0, 0x10, 0x00, 0xc2, 0x0e,
+ 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4, 0x00, 0xe6, 0xb1, 0xf0,
+ 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
+ 0x06, 0x13, 0x0c, 0x1c, 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc,
+ 0xbc, 0x0e, 0xa2, 0x12, 0xb9, 0x54, 0x00, 0x80, 0x62, 0x0a, 0x5a, 0x12,
+ 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56, 0x03, 0xe6, 0x01, 0xea,
+ 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
+ 0x04, 0x13, 0xbb, 0x55, 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4,
+ 0x40, 0x00, 0xb6, 0x00, 0xbb, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x01, 0x01,
+ 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12, 0x4c, 0x1c, 0x4e, 0x1c,
+ 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
+ 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
+ 0x74, 0x01, 0x76, 0x01, 0x78, 0x01, 0x7c, 0x01, 0xc6, 0x0e, 0x0c, 0x10,
+ 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c, 0x6e, 0x1e, 0x02, 0x48,
+ 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
+ 0x03, 0xfc, 0x06, 0x00, 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12,
+ 0x18, 0x1a, 0x70, 0x1a, 0x30, 0x1c, 0x38, 0x1c, 0x10, 0x44, 0x00, 0x4c,
+ 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea, 0x5d, 0xf0, 0xa7, 0xf0,
+ 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
+ 0x33, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00,
+ 0x20, 0x01, 0x4e, 0x01, 0x79, 0x01, 0x3c, 0x09, 0x68, 0x0d, 0x02, 0x10,
+ 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13, 0x40, 0x16, 0x50, 0x16,
+ 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
+ 0x05, 0xf0, 0x09, 0xf0, 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7,
+ 0x0a, 0x00, 0x9b, 0x00, 0x9c, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00,
+ 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08, 0xe9, 0x09, 0x5c, 0x0c,
+ 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
+ 0x42, 0x1d, 0x08, 0x44, 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46,
+ 0x89, 0x48, 0x68, 0x54, 0x83, 0x55, 0x83, 0x59, 0x31, 0xe4, 0x02, 0xe6,
+ 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8,
+ 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
+ 0xa8, 0x00, 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01,
+ 0x26, 0x01, 0x60, 0x01, 0x7a, 0x01, 0x82, 0x01, 0xc8, 0x01, 0xca, 0x01,
+ 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07, 0x68, 0x08, 0x10, 0x0d,
+ 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
+ 0xf3, 0x10, 0x06, 0x12, 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13,
+ 0x10, 0x13, 0xfe, 0x9c, 0xf0, 0x35, 0x05, 0xfe, 0xec, 0x0e, 0xff, 0x10,
+ 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8, 0xfe, 0x88, 0x01, 0xff,
+ 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+ 0x00, 0xfe, 0x57, 0x24, 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00,
+ 0x00, 0x1a, 0xff, 0x09, 0x00, 0x00, 0xff, 0x08, 0x01, 0x01, 0xff, 0x08,
+ 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10, 0xff, 0xff, 0xff, 0x13,
+ 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+ 0xfe, 0x04, 0xf7, 0xe8, 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe,
+ 0x04, 0xf7, 0xe8, 0x7d, 0x0d, 0x51, 0x37, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c,
+ 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0, 0xfe, 0xf8, 0x01, 0xfe,
+ 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
+ 0x05, 0xfe, 0x08, 0x0f, 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05,
+ 0xfe, 0x0e, 0x03, 0xfe, 0x28, 0x1c, 0x03, 0xfe, 0xa6, 0x00, 0xfe, 0xd1,
+ 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe, 0x48, 0xf0, 0xfe, 0x90,
+ 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
+ 0x02, 0xfe, 0x46, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60,
+ 0x02, 0xfe, 0x43, 0xf0, 0xfe, 0x4e, 0x02, 0xfe, 0x44, 0xf0, 0xfe, 0x52,
+ 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c, 0x0d, 0xa2, 0x1c, 0x07,
+ 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
+ 0x1c, 0xf5, 0xfe, 0x1e, 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7,
+ 0x10, 0xfe, 0x06, 0xfc, 0xde, 0x0a, 0x81, 0x01, 0xa3, 0x05, 0x35, 0x1f,
+ 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a, 0x81, 0x01, 0x5c, 0xfe,
+ 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
+ 0xfe, 0x58, 0x1c, 0x1c, 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d,
+ 0xf0, 0xfe, 0x0c, 0x02, 0x2b, 0xfe, 0x9e, 0x02, 0xfe, 0x5a, 0x1c, 0xfe,
+ 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30, 0x00, 0x47, 0xb8, 0x01,
+ 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
+ 0x1a, 0x31, 0xfe, 0x69, 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec,
+ 0x2c, 0x60, 0x01, 0xfe, 0x1e, 0x1e, 0x20, 0x2c, 0xfe, 0x05, 0xf6, 0xde,
+ 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a, 0x44, 0x15, 0x56, 0x51,
+ 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
+ 0x01, 0x18, 0x09, 0x00, 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41,
+ 0x58, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0xc8, 0x54, 0x7b, 0xfe, 0x1c, 0x03,
+ 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60, 0xfe, 0x02, 0xe8, 0x30,
+ 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
+ 0xfe, 0xe4, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40,
+ 0x1c, 0x2a, 0xeb, 0xfe, 0x26, 0xf0, 0xfe, 0x66, 0x03, 0xfe, 0xa0, 0xf0,
+ 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe, 0xef, 0x10, 0xfe, 0x9f,
+ 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
+ 0x70, 0x37, 0xfe, 0x48, 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28,
+ 0xfe, 0x18, 0x13, 0x26, 0x21, 0xb9, 0xc7, 0x20, 0xb9, 0x0a, 0x57, 0x01,
+ 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15, 0xe1, 0x2a, 0xeb, 0xfe,
+ 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
+ 0x15, 0xfe, 0xe4, 0x00, 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe,
+ 0xc6, 0x03, 0x01, 0x41, 0xfe, 0x06, 0xf0, 0xfe, 0xd6, 0x03, 0xaf, 0xa0,
+ 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29, 0x03, 0x81, 0x1e, 0x1b,
+ 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
+ 0xea, 0xfe, 0x46, 0x1c, 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf,
+ 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c, 0x75, 0x01, 0xa6, 0x86, 0x0a,
+ 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a, 0xe1, 0x01, 0x18, 0x77,
+ 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
+ 0x8f, 0xfe, 0x70, 0x02, 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29,
+ 0x2f, 0xfe, 0x4e, 0x04, 0x16, 0xfe, 0x4a, 0x04, 0x7e, 0xfe, 0xa0, 0x00,
+ 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff, 0x02, 0x00, 0x10, 0x01,
+ 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
+ 0xee, 0xfe, 0x4c, 0x44, 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13,
+ 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x60, 0x8d, 0x30, 0x01, 0xfe, 0x4e,
+ 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xfe,
+ 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
+ 0x13, 0x34, 0xfe, 0x4c, 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe,
+ 0x48, 0x47, 0xfe, 0x54, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xa5, 0x01, 0x43,
+ 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06, 0x28, 0xf9, 0x1f, 0x7f,
+ 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
+ 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe,
+ 0x1c, 0x90, 0x04, 0xfe, 0x9c, 0x93, 0x3a, 0x0b, 0x0e, 0x8b, 0x02, 0x1f,
+ 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b, 0x7d, 0x1d, 0xfe, 0x46,
+ 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
+ 0xfe, 0x87, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c,
+ 0x06, 0x0d, 0xfe, 0x98, 0x13, 0x0f, 0xfe, 0x20, 0x80, 0x04, 0xfe, 0xa0,
+ 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84, 0x12, 0x01, 0x38, 0x06,
+ 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
+ 0x05, 0xd0, 0x54, 0x01, 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe,
+ 0xa0, 0x00, 0x1e, 0xfe, 0x50, 0x12, 0x5e, 0xff, 0x02, 0x00, 0x10, 0x2f,
+ 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe,
+ 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
+ 0x38, 0xfe, 0x4a, 0xf0, 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba,
+ 0x05, 0x71, 0x2e, 0xfe, 0x21, 0x00, 0xf1, 0x2e, 0xfe, 0x22, 0x00, 0xa2,
+ 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00, 0x10, 0x2f, 0xfe, 0xd0,
+ 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
+ 0x1c, 0x00, 0x4d, 0x01, 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27,
+ 0x01, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x24, 0x12, 0x3e, 0x01, 0x84, 0x1f,
+ 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42,
+ 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
+ 0x03, 0xb6, 0x1e, 0xfe, 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13,
+ 0x3e, 0x01, 0x84, 0x17, 0xfe, 0x72, 0x06, 0x0a, 0x07, 0x01, 0x38, 0x06,
+ 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56, 0x19, 0x16, 0xfe, 0x68,
+ 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
+ 0x03, 0x9a, 0x1e, 0xfe, 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13,
+ 0x01, 0xc6, 0x09, 0x12, 0x48, 0xfe, 0x92, 0x06, 0x2e, 0x12, 0x01, 0xfe,
+ 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13, 0x58, 0xff, 0x02, 0x00,
+ 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
+ 0xfe, 0xea, 0x06, 0x01, 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01,
+ 0xfe, 0x84, 0x19, 0x16, 0xfe, 0xe0, 0x06, 0x15, 0x82, 0x01, 0x41, 0x15,
+ 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07, 0x01, 0x84, 0xfe, 0xae,
+ 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
+ 0x1e, 0xfe, 0x1a, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01,
+ 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0xf0, 0x45, 0x0a, 0x95,
+ 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24, 0x36, 0xfe, 0x02, 0xf6,
+ 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
+ 0xd0, 0x0d, 0x17, 0xfe, 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe,
+ 0x90, 0x07, 0x26, 0x20, 0x9e, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x21,
+ 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58, 0x57, 0x10, 0xe6, 0x05,
+ 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
+ 0xfe, 0x9c, 0x32, 0x5f, 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00,
+ 0x2f, 0xed, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe, 0xce, 0x07, 0xae, 0xfe,
+ 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08, 0xaf, 0xa0, 0x05, 0x29,
+ 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
+ 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe,
+ 0x99, 0xa4, 0x01, 0x08, 0x14, 0x00, 0x05, 0xfe, 0xc6, 0x09, 0x01, 0x76,
+ 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x30, 0x13,
+ 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
+ 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00,
+ 0x05, 0xef, 0x7c, 0x4a, 0x78, 0x4f, 0x0f, 0xfe, 0x9a, 0x81, 0x04, 0xfe,
+ 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d, 0x28, 0x48, 0xfe, 0x6c,
+ 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
+ 0x12, 0x53, 0x63, 0x4e, 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c,
+ 0xfe, 0x0a, 0xf0, 0xfe, 0x6c, 0x08, 0xaf, 0xa0, 0xae, 0xfe, 0x96, 0x08,
+ 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24, 0x05, 0xed, 0xfe, 0x9c,
+ 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
+ 0x1e, 0xfe, 0x99, 0x58, 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe,
+ 0x16, 0x09, 0x10, 0x6a, 0x22, 0x6b, 0x01, 0x0c, 0x61, 0x54, 0x44, 0x21,
+ 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e, 0x1e, 0x47, 0x2c, 0x7a,
+ 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
+ 0x01, 0x0c, 0x61, 0x65, 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20,
+ 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe,
+ 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10, 0x01, 0xfe, 0xce, 0x1e,
+ 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
+ 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b,
+ 0x22, 0x4c, 0xfe, 0x8a, 0x10, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x50, 0x12,
+ 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e, 0x10, 0x6a, 0x22, 0x6b,
+ 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
+ 0xfe, 0x9f, 0x83, 0x33, 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90,
+ 0x04, 0xfe, 0xc4, 0x93, 0x3a, 0x0b, 0xfe, 0xc6, 0x90, 0x04, 0xfe, 0xc6,
+ 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d, 0x01, 0xfe, 0xce, 0x1e,
+ 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
+ 0x04, 0xfe, 0xc0, 0x93, 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2,
+ 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x4b, 0x22, 0x4c, 0x10, 0x64, 0x22, 0x34,
+ 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe,
+ 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
+ 0x3c, 0x37, 0x88, 0xf5, 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a,
+ 0xd2, 0xfe, 0x1e, 0x0a, 0xd3, 0xfe, 0x42, 0x0a, 0xae, 0xfe, 0x12, 0x0a,
+ 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0, 0x05, 0x29, 0x01, 0x41,
+ 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
+ 0xfe, 0x14, 0x12, 0x01, 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d,
+ 0xfe, 0x74, 0x12, 0xfe, 0x2e, 0x1c, 0x05, 0xfe, 0x1a, 0x0c, 0x01, 0x76,
+ 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41, 0xfe, 0x2c, 0x1c, 0xfe,
+ 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
+ 0x92, 0x10, 0xc4, 0xf6, 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe,
+ 0x1a, 0x0c, 0xc5, 0xfe, 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0xbf, 0xfe, 0x6b,
+ 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12, 0xac, 0xfe, 0xd2, 0xf0,
+ 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
+ 0x1b, 0xbf, 0xd4, 0x5b, 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5,
+ 0xfe, 0xa9, 0x10, 0x75, 0x5e, 0x32, 0x1f, 0x7f, 0x01, 0x42, 0x19, 0xfe,
+ 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98, 0x05, 0x70, 0xfe, 0x74,
+ 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
+ 0x0f, 0x4d, 0x01, 0xfe, 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05,
+ 0x5b, 0x01, 0x0c, 0x06, 0x0d, 0x2b, 0xfe, 0xe2, 0x0b, 0x01, 0x0c, 0x06,
+ 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24, 0xfe, 0x88, 0x13, 0x21,
+ 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
+ 0x83, 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42,
+ 0x13, 0x0f, 0xfe, 0x04, 0x91, 0x04, 0xfe, 0x84, 0x93, 0xfe, 0xca, 0x57,
+ 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93, 0xfe, 0xcb, 0x57, 0x0b,
+ 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
+ 0x6a, 0x3b, 0x6b, 0x10, 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01,
+ 0xc2, 0xc8, 0x7a, 0x30, 0x20, 0x6e, 0xdb, 0x64, 0xdc, 0x34, 0x91, 0x6c,
+ 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xfe, 0x04, 0xfa, 0x64,
+ 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
+ 0x10, 0x98, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06,
+ 0x24, 0x1b, 0x40, 0x91, 0x4b, 0x7e, 0x4c, 0x01, 0x0c, 0x06, 0xfe, 0xf7,
+ 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58,
+ 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
+ 0x1b, 0x40, 0x01, 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe,
+ 0x8e, 0x1e, 0x4f, 0x0f, 0xfe, 0x10, 0x90, 0x04, 0xfe, 0x90, 0x93, 0x3a,
+ 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93, 0x79, 0x0b, 0x0e, 0xfe,
+ 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
+ 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e,
+ 0xfe, 0x6e, 0x0a, 0xfe, 0x0c, 0x58, 0xfe, 0x8d, 0x58, 0x05, 0x5b, 0x26,
+ 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99, 0x83, 0x33, 0x0b, 0x0e,
+ 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
+ 0x19, 0xfe, 0x19, 0x41, 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef,
+ 0x1f, 0x92, 0x01, 0x42, 0x19, 0xfe, 0x44, 0x00, 0xfe, 0x90, 0x10, 0xfe,
+ 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda, 0x4c, 0xfe, 0x0c, 0x51,
+ 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
+ 0x76, 0x10, 0xac, 0xfe, 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18,
+ 0x23, 0x1d, 0x5d, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0x08, 0x13, 0x19, 0xfe,
+ 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe, 0xcc, 0x0c, 0x1f, 0x92,
+ 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
+ 0x0c, 0xfe, 0x3e, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe,
+ 0x22, 0x00, 0x05, 0x70, 0xfe, 0xcb, 0xf0, 0xfe, 0xea, 0x0c, 0x19, 0xfe,
+ 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe, 0xf4, 0x0c, 0x19, 0x94,
+ 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
+ 0xfe, 0xcc, 0xf0, 0xef, 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12,
+ 0x00, 0x37, 0x13, 0xfe, 0x4e, 0x11, 0x2f, 0xfe, 0x16, 0x0d, 0xfe, 0x9e,
+ 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b, 0x3c, 0x37, 0x88, 0xf5,
+ 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
+ 0x2f, 0xfe, 0x3e, 0x0d, 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0,
+ 0xd4, 0x9f, 0xd5, 0x9f, 0xd2, 0x9f, 0xd3, 0x9f, 0x05, 0x29, 0x01, 0x41,
+ 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4, 0xc5, 0x75, 0xd7, 0x99,
+ 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
+ 0x9c, 0x2f, 0xfe, 0x8c, 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01,
+ 0x48, 0xa4, 0x19, 0xfe, 0x42, 0x00, 0x05, 0x70, 0x90, 0x07, 0xfe, 0x81,
+ 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x44, 0x13,
+ 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
+ 0xfe, 0xda, 0x0e, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe,
+ 0x28, 0x00, 0xfe, 0xfa, 0x10, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00,
+ 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40, 0x15, 0x56, 0x01, 0x85,
+ 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
+ 0xcc, 0x10, 0x01, 0xa7, 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f,
+ 0xfe, 0x19, 0x82, 0x04, 0xfe, 0x99, 0x83, 0xfe, 0xcc, 0x47, 0x0b, 0x0e,
+ 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe, 0x43, 0x00, 0xfe, 0xa2,
+ 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
+ 0x00, 0x1d, 0x40, 0x15, 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01,
+ 0xfe, 0x9e, 0x1e, 0x05, 0xfe, 0x3a, 0x03, 0x01, 0x0c, 0x06, 0x0d, 0x5d,
+ 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01, 0x76, 0x06, 0x12, 0xfe,
+ 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
+ 0xfe, 0x9d, 0xf0, 0xfe, 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
+ 0xfe, 0x94, 0x0e, 0x01, 0x0c, 0x61, 0x12, 0x44, 0xfe, 0x9f, 0x10, 0x19,
+ 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f, 0xfe, 0x2e, 0x10, 0x19,
+ 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
+ 0xfe, 0x41, 0x00, 0xa2, 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75,
+ 0x03, 0x81, 0x1e, 0x2b, 0xea, 0x4f, 0xfe, 0x04, 0xe6, 0x12, 0xfe, 0x9d,
+ 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05, 0x35, 0xfe, 0x12, 0x1c,
+ 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
+ 0xfe, 0xd4, 0x11, 0x05, 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e,
+ 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0x06, 0xea, 0xe0,
+ 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03, 0x67, 0xfe, 0x98, 0x56,
+ 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
+ 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe,
+ 0x41, 0x58, 0x0a, 0xba, 0xfe, 0xfa, 0x14, 0xfe, 0x49, 0x54, 0xb0, 0xfe,
+ 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67, 0xfe, 0xe0, 0x14, 0xfe,
+ 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
+ 0xfe, 0xad, 0x13, 0x05, 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12,
+ 0x26, 0x20, 0x96, 0x20, 0xe7, 0xfe, 0x08, 0x1c, 0xfe, 0x7c, 0x19, 0xfe,
+ 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe, 0x48, 0x55, 0xa5, 0x3b,
+ 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
+ 0xf0, 0x1a, 0x03, 0xfe, 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe,
+ 0x1e, 0x10, 0xfe, 0x02, 0xec, 0xe7, 0x53, 0x00, 0x36, 0xfe, 0x04, 0xec,
+ 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x62, 0x1b,
+ 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
+ 0xea, 0xe7, 0x53, 0x92, 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3,
+ 0xfe, 0x2a, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x23, 0xfe, 0xf0, 0xff, 0x10,
+ 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62, 0x01, 0x01, 0xfe, 0x1e,
+ 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
+ 0x26, 0x02, 0x21, 0x96, 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13,
+ 0x1f, 0x1d, 0x47, 0xb5, 0xc3, 0xfe, 0xe1, 0x10, 0xcf, 0xfe, 0x03, 0xdc,
+ 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf, 0xfe, 0x03, 0xdc, 0xfe,
+ 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
+ 0x00, 0xcc, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06,
+ 0x4a, 0xfe, 0x4e, 0x13, 0x0f, 0xfe, 0x1c, 0x80, 0x04, 0xfe, 0x9c, 0x83,
+ 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13, 0x0f, 0xfe, 0x1e, 0x80,
+ 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
+ 0x1d, 0x80, 0x04, 0xfe, 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c,
+ 0x13, 0x01, 0xfe, 0xee, 0x1e, 0xac, 0xfe, 0x14, 0x13, 0x01, 0xfe, 0xfe,
+ 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4,
+ 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
+ 0x56, 0xfb, 0x01, 0xfe, 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01,
+ 0xfe, 0xf4, 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x15, 0xfe, 0xe9, 0x00, 0x01,
+ 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe, 0x22, 0x1b, 0xfe, 0x1e,
+ 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
+ 0x96, 0x90, 0x04, 0xfe, 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64,
+ 0x01, 0x22, 0xfe, 0x66, 0x01, 0x01, 0x0c, 0x06, 0x65, 0xf9, 0x0f, 0xfe,
+ 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x0e, 0x77, 0xfe, 0x01,
+ 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
+ 0x21, 0x2c, 0xfe, 0x00, 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03,
+ 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58, 0x03, 0xfe, 0xae, 0x00, 0xfe, 0x07,
+ 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe, 0xb2, 0x00,
+ 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
+ 0x66, 0x10, 0x55, 0x10, 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe,
+ 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe, 0x88, 0x11, 0x46, 0x1a, 0x13,
+ 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x2b, 0xfe,
+ 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
+ 0x00, 0x40, 0x8d, 0x2c, 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0,
+ 0xfe, 0xb2, 0x11, 0xfe, 0x12, 0x1c, 0x75, 0xfe, 0x14, 0x1c, 0xfe, 0x10,
+ 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c, 0x14, 0xfe, 0x0e, 0x47,
+ 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
+ 0xa7, 0x90, 0x34, 0x60, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
+ 0x13, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x34, 0x13, 0x0a, 0x5a, 0x01,
+ 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
+ 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
+ 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85,
+ 0xf2, 0x09, 0x9b, 0xa4, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xec,
+ 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01, 0xec, 0xb8, 0xfe, 0x9e,
+ 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
+ 0xf4, 0xfe, 0xdd, 0x10, 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee,
+ 0x09, 0x12, 0xfe, 0x48, 0x12, 0x09, 0x0d, 0xfe, 0x56, 0x12, 0x09, 0x1d,
+ 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4, 0x13, 0x09, 0xfe, 0x23,
+ 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
+ 0x24, 0xfe, 0x12, 0x12, 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42,
+ 0xa1, 0x32, 0x01, 0x08, 0xae, 0x41, 0x02, 0x32, 0xfe, 0x62, 0x08, 0x0a,
+ 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05, 0x35, 0x32, 0x01, 0x43,
+ 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
+ 0x13, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34,
+ 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55, 0xb0, 0xfe, 0x4a, 0x13, 0x21, 0x6e,
+ 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e, 0xfe, 0xb6, 0x0e, 0x10,
+ 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
+ 0x88, 0x20, 0x6e, 0x01, 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
+ 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x64, 0xfe, 0x05, 0xfa,
+ 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x40, 0x56, 0xfe,
+ 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
+ 0x44, 0x55, 0xfe, 0xe5, 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56,
+ 0xfe, 0xa1, 0x56, 0x10, 0x68, 0x22, 0x69, 0x01, 0x0c, 0x06, 0x54, 0xf9,
+ 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b, 0x6b, 0xfe, 0x2c, 0x50,
+ 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
+ 0x50, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03,
+ 0x4b, 0x3b, 0x4c, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x05, 0x73, 0x2e,
+ 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08, 0x16, 0x3d, 0x27, 0x25,
+ 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
+ 0xa6, 0x23, 0x3f, 0x1b, 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13,
+ 0x91, 0x4b, 0x7e, 0x4c, 0xfe, 0x0a, 0x55, 0x31, 0xfe, 0x8b, 0x55, 0xd9,
+ 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0x05, 0x72, 0x01,
+ 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
+ 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d,
+ 0x83, 0x2d, 0x7f, 0x1b, 0xfe, 0x66, 0x15, 0x05, 0x3d, 0x01, 0x08, 0x2a,
+ 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d, 0x2b, 0x3d, 0x01, 0x08,
+ 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
+ 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45,
+ 0x2d, 0x00, 0xa4, 0x46, 0x07, 0x90, 0x3f, 0x01, 0xfe, 0xf8, 0x15, 0x01,
+ 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13, 0x01, 0x43, 0x09, 0x82,
+ 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
+ 0x05, 0x72, 0xfe, 0xc0, 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66,
+ 0x8a, 0x10, 0x66, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01, 0xfe, 0x56,
+ 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d, 0x27, 0x25, 0xbd,
+ 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
+ 0xe8, 0x14, 0x01, 0xa6, 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe,
+ 0x4a, 0xf4, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05,
+ 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73,
+ 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
+ 0x27, 0x25, 0xbd, 0x09, 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b,
+ 0xfe, 0xaa, 0x14, 0xfe, 0xb6, 0x14, 0x86, 0xa8, 0xb2, 0x0d, 0x1b, 0x3d,
+ 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09, 0x82, 0x4e, 0x05, 0x72,
+ 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
+ 0xfe, 0xc0, 0x19, 0x05, 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17,
+ 0xfe, 0xe2, 0x15, 0x5f, 0xcc, 0x01, 0x08, 0x26, 0x5f, 0x02, 0x8f, 0xfe,
+ 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe, 0xcc, 0x15, 0x5e, 0x32,
+ 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
+ 0xad, 0x23, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02,
+ 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0x23, 0x3f, 0xfe, 0x30,
+ 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
+ 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
+ 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58,
+ 0x02, 0x0a, 0x66, 0x01, 0x5c, 0x0a, 0x55, 0x01, 0x5c, 0x0a, 0x6f, 0x01,
+ 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a, 0xff, 0x03, 0x00, 0x54,
+ 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
+ 0x7c, 0x3a, 0x0b, 0x0e, 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a,
+ 0x19, 0xfe, 0xfb, 0x19, 0xfe, 0x1a, 0xf7, 0x00, 0xfe, 0x1b, 0xf7, 0x00,
+ 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c, 0xda, 0x6d, 0x02, 0xfe,
+ 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
+ 0x02, 0x01, 0xc6, 0xfe, 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16,
+ 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xbe, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17,
+ 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x03, 0x9a, 0x1e, 0xfe,
+ 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
+ 0x48, 0xfe, 0x08, 0x17, 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d,
+ 0xb4, 0x7b, 0xfe, 0x26, 0x17, 0x4d, 0x13, 0x07, 0x1c, 0xb4, 0x90, 0x04,
+ 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1, 0xff, 0x02, 0x83, 0x55,
+ 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
+ 0x17, 0x1c, 0x63, 0x13, 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16,
+ 0x13, 0xd6, 0xfe, 0x64, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0x64,
+ 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10, 0x53, 0x07, 0xfe, 0x60,
+ 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
+ 0x00, 0x1c, 0x95, 0x13, 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe,
+ 0x8c, 0x17, 0x45, 0xf3, 0xfe, 0x43, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe,
+ 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43, 0xf4, 0x94, 0xf6, 0x8b,
+ 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
+ 0xda, 0x17, 0x62, 0x49, 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe,
+ 0xda, 0x17, 0x62, 0x80, 0x71, 0x50, 0x26, 0xfe, 0x4d, 0xf4, 0x00, 0xf7,
+ 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x02, 0x50, 0x13,
+ 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
+ 0x25, 0xbe, 0xfe, 0x03, 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9,
+ 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe,
+ 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01, 0x01, 0x08, 0x16, 0xa9,
+ 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
+ 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01,
+ 0x03, 0xb6, 0x1e, 0x83, 0x01, 0x38, 0x06, 0x24, 0x31, 0xa2, 0x78, 0xf2,
+ 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1, 0x78, 0x03, 0x9a, 0x1e,
+ 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
+ 0xfe, 0x40, 0x5a, 0x23, 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18,
+ 0x62, 0x49, 0x71, 0x8c, 0x80, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x80, 0xfe,
+ 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
+ 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
+ 0x43, 0x48, 0x2d, 0x93, 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe,
+ 0x40, 0x10, 0x2d, 0xb4, 0x36, 0xfe, 0x34, 0xf4, 0x04, 0xfe, 0x34, 0x10,
+ 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe, 0x28, 0x10, 0xfe, 0xc0,
+ 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
+ 0x18, 0x45, 0xfe, 0x1c, 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe,
+ 0x56, 0xf0, 0xfe, 0x0c, 0x19, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x40, 0xf4,
+ 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d, 0x21, 0xfe, 0x7f, 0x01,
+ 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
+ 0x7e, 0x01, 0xfe, 0xc8, 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01,
+ 0xfe, 0x48, 0x45, 0xfa, 0x21, 0xfe, 0x81, 0x01, 0xfe, 0xc8, 0x44, 0x4e,
+ 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50, 0x13, 0x0d, 0x02, 0x14,
+ 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
+ 0xfe, 0x82, 0x19, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f,
+ 0xfe, 0x89, 0x49, 0x01, 0x08, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
+ 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07, 0x01, 0x08, 0x17, 0xc1,
+ 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
+ 0x08, 0x02, 0x50, 0x02, 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f,
+ 0x01, 0x08, 0x17, 0x74, 0x14, 0x12, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x89,
+ 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01, 0x08, 0x17, 0x74, 0xfe,
+ 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
+ 0x74, 0x5f, 0xcc, 0x01, 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c,
+ 0x13, 0xc8, 0x20, 0xe4, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x5f, 0xa1, 0x5e,
+ 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff, 0x02, 0x00, 0x10, 0x2f,
+ 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
+ 0x16, 0xfe, 0x64, 0x1a, 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09,
+ 0x07, 0x5d, 0x01, 0x0c, 0x61, 0x07, 0x44, 0x02, 0x0a, 0x5a, 0x01, 0x18,
+ 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01,
+ 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
+ 0xfe, 0x80, 0xe7, 0x1a, 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe,
+ 0xb2, 0x16, 0xaa, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0xaa, 0x0a, 0x67, 0x01,
+ 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe, 0x7e, 0x1e, 0xfe, 0x80,
+ 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
+ 0xfe, 0x80, 0x4c, 0x0a, 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c,
+ 0xe5, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x24, 0x1c, 0xfe, 0x1d,
+ 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe, 0x2a, 0x1c, 0xfa, 0xb3,
+ 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
+ 0xf4, 0x1a, 0xfe, 0xfa, 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01,
+ 0xfe, 0x00, 0xf4, 0x24, 0xfe, 0x18, 0x58, 0x03, 0xfe, 0x66, 0x01, 0xfe,
+ 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f, 0xfe, 0x30, 0xf4, 0x07,
+ 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
+ 0xf7, 0x24, 0xb1, 0xfe, 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9,
+ 0x2b, 0xfe, 0x26, 0x1b, 0xfe, 0xba, 0x10, 0x1c, 0x1a, 0x87, 0xfe, 0x83,
+ 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x54, 0xb1,
+ 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
+ 0xaf, 0x19, 0xfe, 0x98, 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b,
+ 0xfe, 0x8a, 0x10, 0x1c, 0x1a, 0x87, 0x8b, 0x0f, 0xfe, 0x30, 0x90, 0x04,
+ 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58, 0xfe, 0x32, 0x90, 0x04,
+ 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
+ 0x7c, 0x12, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6,
+ 0x1b, 0xfe, 0x5e, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x96, 0x1b, 0x5c,
+ 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe, 0x6a, 0xfe, 0x19, 0xfe,
+ 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
+ 0x1b, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83,
+ 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x1a, 0xfe, 0x81, 0xe7, 0x1a,
+ 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a, 0x30, 0xfe, 0x12, 0x45,
+ 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
+ 0x39, 0xf0, 0x75, 0x26, 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13,
+ 0x11, 0x02, 0x87, 0x03, 0xe3, 0x23, 0x07, 0xfe, 0xef, 0x12, 0xfe, 0xe1,
+ 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09, 0x56, 0xfe, 0x3c, 0x13,
+ 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
+ 0x01, 0x18, 0xcb, 0xfe, 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48,
+ 0x01, 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f,
+ 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x4c, 0x01,
+ 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
+ 0x12, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d,
+ 0x02, 0xfe, 0x9c, 0xe7, 0x0d, 0x19, 0xfe, 0x15, 0x00, 0x40, 0x8d, 0x30,
+ 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06, 0x83, 0xfe, 0x18, 0x80,
+ 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
+ 0x90, 0xfe, 0xba, 0x90, 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31,
+ 0xfe, 0xc9, 0x55, 0x02, 0x21, 0xb9, 0x88, 0x20, 0xb9, 0x02, 0x0a, 0xba,
+ 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01, 0x18, 0xfe, 0x49, 0x44,
+ 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
+ 0x1a, 0xa4, 0x0a, 0x67, 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89,
+ 0x02, 0xfe, 0x4e, 0xe4, 0x1d, 0x7b, 0xfe, 0x52, 0x1d, 0x03, 0xfe, 0x90,
+ 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xdd, 0x7b,
+ 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
+ 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe,
+ 0x94, 0x00, 0xd1, 0x24, 0xfe, 0x08, 0x10, 0x03, 0xfe, 0x96, 0x00, 0xd1,
+ 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04, 0x68, 0x54, 0xfe, 0xf1,
+ 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
+ 0xfe, 0x1a, 0xf4, 0xfe, 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa,
+ 0x1d, 0x13, 0x1d, 0x02, 0x09, 0x92, 0xfe, 0x5a, 0xf0, 0xfe, 0xba, 0x1d,
+ 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe, 0x5a, 0xf0, 0xfe, 0xc8,
+ 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
+ 0x1a, 0x10, 0x09, 0x0d, 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e,
+ 0x95, 0xa1, 0xc8, 0x02, 0x1f, 0x93, 0x01, 0x42, 0xfe, 0x04, 0xfe, 0x99,
+ 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e, 0xfe, 0x14, 0xf0, 0x08,
+ 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
+ 0xfe, 0x82, 0xf0, 0xfe, 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80,
+ 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x18, 0x80, 0x04, 0xfe, 0x98,
+ 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02, 0x80, 0x04, 0xfe, 0x82,
+ 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
+ 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b,
+ 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x04, 0x80, 0x04, 0xfe, 0x84,
+ 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80, 0x80, 0x04, 0xfe, 0x80,
+ 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
+ 0xfe, 0x99, 0x83, 0xfe, 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06,
+ 0x83, 0x04, 0xfe, 0x86, 0x83, 0xfe, 0xce, 0x47, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x08, 0x90, 0x04, 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x8a, 0x90, 0x04, 0xfe, 0x8a, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
+ 0xfe, 0x3c, 0x90, 0x04, 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b,
+ 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b, 0x77, 0x0e,
+ 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
+};
+
+static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
+static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
+
+static void AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
+{
+ PortAddr iop_base;
+ int i;
+ ushort lram_addr;
+
+ iop_base = asc_dvc->iop_base;
+ AscPutRiscVarFreeQHead(iop_base, 1);
+ AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+ AscPutVarFreeQHead(iop_base, 1);
+ AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+ AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
+ (uchar)((int)asc_dvc->max_total_qng + 1));
+ AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
+ (uchar)((int)asc_dvc->max_total_qng + 2));
+ AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
+ asc_dvc->max_total_qng);
+ AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+ AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
+ AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
+ AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
+ AscPutQDoneInProgress(iop_base, 0);
+ lram_addr = ASC_QADR_BEG;
+ for (i = 0; i < 32; i++, lram_addr += 2) {
+ AscWriteLramWord(iop_base, lram_addr, 0);
}
-#ifdef CONFIG_ISA
- if ((bus_type & ASC_IS_EISA) != 0) {
- cfg_lsw = AscGetEisaChipCfg(iop_base);
- cfg_lsw &= 0x000F;
- bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
- (cfg_lsw * ASC_BIOS_BANK_SIZE));
- return (bios_addr);
- } /* if */
-#endif /* CONFIG_ISA */
+}
- cfg_lsw = AscGetChipCfgLsw(iop_base);
+static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
+{
+ int i;
+ ushort warn_code;
+ PortAddr iop_base;
+ ASC_PADDR phy_addr;
+ ASC_DCNT phy_size;
+ struct asc_board *board = asc_dvc_to_board(asc_dvc);
- /*
- * ISA PnP uses the top bit as the 32K BIOS flag
- */
- if (bus_type == ASC_IS_ISAPNP) {
- cfg_lsw &= 0x7FFF;
+ iop_base = asc_dvc->iop_base;
+ warn_code = 0;
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ AscPutMCodeInitSDTRAtID(iop_base, i,
+ asc_dvc->cfg->sdtr_period_offset[i]);
}
- /* if */
- bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
- ASC_BIOS_MIN_ADDR);
- return (bios_addr);
+
+ AscInitQLinkVar(asc_dvc);
+ AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
+ asc_dvc->cfg->disc_enable);
+ AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
+ ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
+
+ /* Ensure overrun buffer is aligned on an 8 byte boundary. */
+ BUG_ON((unsigned long)asc_dvc->overrun_buf & 7);
+ asc_dvc->overrun_dma = dma_map_single(board->dev, asc_dvc->overrun_buf,
+ ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
+ phy_addr = cpu_to_le32(asc_dvc->overrun_dma);
+ AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
+ (uchar *)&phy_addr, 1);
+ phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE);
+ AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
+ (uchar *)&phy_size, 1);
+
+ asc_dvc->cfg->mcode_date =
+ AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
+ asc_dvc->cfg->mcode_version =
+ AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
+
+ AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+ if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+ asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+ return warn_code;
+ }
+ if (AscStartChip(iop_base) != 1) {
+ asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+ return warn_code;
+ }
+
+ return warn_code;
}
-/*
- * --- Functions Required by the Adv Library
- */
+static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
+{
+ ushort warn_code;
+ PortAddr iop_base;
+
+ iop_base = asc_dvc->iop_base;
+ warn_code = 0;
+ if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
+ !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
+ AscResetChipAndScsiBus(asc_dvc);
+ mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
+ }
+ asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
+ if (asc_dvc->err_code != 0)
+ return UW_ERR;
+ if (!AscFindSignature(asc_dvc->iop_base)) {
+ asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+ return warn_code;
+ }
+ AscDisableInterrupt(iop_base);
+ warn_code |= AscInitLram(asc_dvc);
+ if (asc_dvc->err_code != 0)
+ return UW_ERR;
+ ASC_DBG(1, "_asc_mcode_chksum 0x%lx\n", (ulong)_asc_mcode_chksum);
+ if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
+ _asc_mcode_size) != _asc_mcode_chksum) {
+ asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+ return warn_code;
+ }
+ warn_code |= AscInitMicroCodeVar(asc_dvc);
+ asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
+ AscEnableInterrupt(iop_base);
+ return warn_code;
+}
/*
- * DvcGetPhyAddr()
+ * Load the Microcode
+ *
+ * Write the microcode image to RISC memory starting at address 0.
+ *
+ * The microcode is stored compressed in the following format:
*
- * Return the physical address of 'vaddr' and set '*lenp' to the
- * number of physically contiguous bytes that follow 'vaddr'.
- * 'flag' indicates the type of structure whose physical address
- * is being translated.
+ * 254 word (508 byte) table indexed by byte code followed
+ * by the following byte codes:
*
- * Note: Because Linux currently doesn't page the kernel and all
- * kernel buffers are physically contiguous, leave '*lenp' unchanged.
+ * 1-Byte Code:
+ * 00: Emit word 0 in table.
+ * 01: Emit word 1 in table.
+ * .
+ * FD: Emit word 253 in table.
+ *
+ * Multi-Byte Code:
+ * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+ * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+ *
+ * Returns 0 or an error if the checksum doesn't match
*/
-ADV_PADDR
-DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
- uchar *vaddr, ADV_SDCNT *lenp, int flag)
+static int AdvLoadMicrocode(AdvPortAddr iop_base, unsigned char *buf, int size,
+ int memsize, int chksum)
{
- ADV_PADDR paddr;
+ int i, j, end, len = 0;
+ ADV_DCNT sum;
+
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
- paddr = virt_to_bus(vaddr);
+ for (i = 253 * 2; i < size; i++) {
+ if (buf[i] == 0xff) {
+ unsigned short word = (buf[i + 3] << 8) | buf[i + 2];
+ for (j = 0; j < buf[i + 1]; j++) {
+ AdvWriteWordAutoIncLram(iop_base, word);
+ len += 2;
+ }
+ i += 3;
+ } else if (buf[i] == 0xfe) {
+ unsigned short word = (buf[i + 2] << 8) | buf[i + 1];
+ AdvWriteWordAutoIncLram(iop_base, word);
+ i += 2;
+ len += 2;
+ } else {
+ unsigned char off = buf[i] * 2;
+ unsigned short word = (buf[off + 1] << 8) | buf[off];
+ AdvWriteWordAutoIncLram(iop_base, word);
+ len += 2;
+ }
+ }
- ASC_DBG4(4,
- "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
- (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
- (ulong)paddr);
+ end = len;
- return paddr;
+ while (len < memsize) {
+ AdvWriteWordAutoIncLram(iop_base, 0);
+ len += 2;
+ }
+
+ /* Verify the microcode checksum. */
+ sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+ for (len = 0; len < end; len += 2) {
+ sum += AdvReadWordAutoIncLram(iop_base);
+ }
+
+ if (sum != chksum)
+ return ASC_IERR_MCODE_CHKSUM;
+
+ return 0;
}
-/*
- * Read a PCI configuration byte.
- */
-static uchar __init DvcAdvReadPCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset)
+static void AdvBuildCarrierFreelist(struct adv_dvc_var *asc_dvc)
{
-#ifdef CONFIG_PCI
- uchar byte_data;
- pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
- return byte_data;
-#else /* CONFIG_PCI */
- return 0;
-#endif /* CONFIG_PCI */
+ ADV_CARR_T *carrp;
+ ADV_SDCNT buf_size;
+ ADV_PADDR carr_paddr;
+
+ carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+ asc_dvc->carr_freelist = NULL;
+ if (carrp == asc_dvc->carrier_buf) {
+ buf_size = ADV_CARRIER_BUFSIZE;
+ } else {
+ buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+ }
+
+ do {
+ /* Get physical address of the carrier 'carrp'. */
+ carr_paddr = cpu_to_le32(virt_to_bus(carrp));
+
+ buf_size -= sizeof(ADV_CARR_T);
+
+ carrp->carr_pa = carr_paddr;
+ carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
+
+ /*
+ * Insert the carrier at the beginning of the freelist.
+ */
+ carrp->next_vpa =
+ cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+ asc_dvc->carr_freelist = carrp;
+
+ carrp++;
+ } while (buf_size > 0);
}
/*
- * Write a PCI configuration byte.
+ * Send an idle command to the chip and wait for completion.
+ *
+ * Command completion is polled for once per microsecond.
+ *
+ * The function can be called from anywhere including an interrupt handler.
+ * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
+ * functions to prevent reentrancy.
+ *
+ * Return Values:
+ * ADV_TRUE - command completed successfully
+ * ADV_FALSE - command failed
+ * ADV_ERROR - command timed out
*/
-static void __init
-DvcAdvWritePCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
+static int
+AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
+ ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
{
-#ifdef CONFIG_PCI
- pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
-#else /* CONFIG_PCI */
- return;
-#endif /* CONFIG_PCI */
+ int result;
+ ADV_DCNT i, j;
+ AdvPortAddr iop_base;
+
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * Clear the idle command status which is set by the microcode
+ * to a non-zero value to indicate when the command is completed.
+ * The non-zero result is one of the IDLE_CMD_STATUS_* values
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
+
+ /*
+ * Write the idle command value after the idle command parameter
+ * has been written to avoid a race condition. If the order is not
+ * followed, the microcode may process the idle command before the
+ * parameters have been written to LRAM.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
+ cpu_to_le32(idle_cmd_parameter));
+ AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
+
+ /*
+ * Tickle the RISC to tell it to process the idle command.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+ /*
+ * Clear the tickle value. In the ASC-3550 the RISC flag
+ * command 'clr_tickle_b' does not work unless the host
+ * value is cleared.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+ }
+
+ /* Wait for up to 100 millisecond for the idle command to timeout. */
+ for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
+ /* Poll once each microsecond for command completion. */
+ for (j = 0; j < SCSI_US_PER_MSEC; j++) {
+ AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
+ result);
+ if (result != 0)
+ return result;
+ udelay(1);
+ }
+ }
+
+ BUG(); /* The idle command should never timeout. */
+ return ADV_ERROR;
}
/*
- * --- Tracing and Debugging Functions
+ * Reset SCSI Bus and purge all outstanding requests.
+ *
+ * Return Value:
+ * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
+ * ADV_FALSE(0) - Microcode command failed.
+ * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
+ * may be hung which requires driver recovery.
*/
+static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
+{
+ int status;
+
+ /*
+ * Send the SCSI Bus Reset idle start idle command which asserts
+ * the SCSI Bus Reset signal.
+ */
+ status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
+ if (status != ADV_TRUE) {
+ return status;
+ }
+
+ /*
+ * Delay for the specified SCSI Bus Reset hold time.
+ *
+ * The hold time delay is done on the host because the RISC has no
+ * microsecond accurate timer.
+ */
+ udelay(ASC_SCSI_RESET_HOLD_TIME_US);
+
+ /*
+ * Send the SCSI Bus Reset end idle command which de-asserts
+ * the SCSI Bus Reset signal and purges any pending requests.
+ */
+ status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
+ if (status != ADV_TRUE) {
+ return status;
+ }
+
+ mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
+
+ return status;
+}
-#ifdef ADVANSYS_STATS
-#ifdef CONFIG_PROC_FS
/*
- * asc_prt_board_stats()
+ * Initialize the ASC-3550.
*
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
*
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Needed after initialization for error recovery.
*/
-static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
+static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
{
- int leftlen;
- int totlen;
- int len;
- struct asc_stats *s;
- asc_board_t *boardp;
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ int begin_addr;
+ int end_addr;
+ ushort code_sum;
+ int word;
+ int i;
+ ushort scsi_cfg1;
+ uchar tid;
+ ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
+ ushort wdtr_able = 0, sdtr_able, tagqng_able;
+ uchar max_cmd[ADV_MAX_TID + 1];
- leftlen = cplen;
- totlen = len = 0;
+ /* If there is already an error, don't continue. */
+ if (asc_dvc->err_code != 0)
+ return ADV_ERROR;
- boardp = ASC_BOARDP(shost);
- s = &boardp->asc_stats;
+ /*
+ * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
+ asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
+ }
- len = asc_prt_line(cp, leftlen,
- "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
- shost->host_no);
- ASC_PRT_NEXT();
+ warn_code = 0;
+ iop_base = asc_dvc->iop_base;
- len = asc_prt_line(cp, leftlen,
- " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
- s->queuecommand, s->reset, s->biosparam,
- s->interrupt);
- ASC_PRT_NEXT();
+ /*
+ * Save the RISC memory BIOS region before writing the microcode.
+ * The BIOS may already be loaded and using its RISC LRAM region
+ * so its region must be saved and restored.
+ *
+ * Note: This code makes the assumption, which is currently true,
+ * that a chip reset does not clear RISC LRAM.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- len = asc_prt_line(cp, leftlen,
- " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
- s->callback, s->done, s->build_error,
- s->adv_build_noreq, s->adv_build_nosg);
- ASC_PRT_NEXT();
+ /*
+ * Save current per TID negotiated values.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
+ ushort bios_version, major, minor;
- len = asc_prt_line(cp, leftlen,
- " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
- s->exe_noerror, s->exe_busy, s->exe_error,
- s->exe_unknown);
- ASC_PRT_NEXT();
+ bios_version =
+ bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
+ major = (bios_version >> 12) & 0xF;
+ minor = (bios_version >> 8) & 0xF;
+ if (major < 3 || (major == 3 && minor == 1)) {
+ /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
+ AdvReadWordLram(iop_base, 0x120, wdtr_able);
+ } else {
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ }
+ }
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+
+ asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc3550_buf,
+ _adv_asc3550_size, ADV_3550_MEMSIZE,
+ _adv_asc3550_chksum);
+ if (asc_dvc->err_code)
+ return ADV_ERROR;
/*
- * Display data transfer statistics.
+ * Restore the RISC memory BIOS region.
*/
- if (s->cont_cnt > 0) {
- len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
- ASC_PRT_NEXT();
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
- s->cont_xfer / 2,
- ASC_TENTHS(s->cont_xfer, 2));
- ASC_PRT_NEXT();
+ /*
+ * Calculate and write the microcode code checksum to the microcode
+ * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+ AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+ code_sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+ for (word = begin_addr; word < end_addr; word += 2) {
+ code_sum += AdvReadWordAutoIncLram(iop_base);
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
- /* Contiguous transfer average size */
- len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
- (s->cont_xfer / 2) / s->cont_cnt,
- ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
- ASC_PRT_NEXT();
+ /*
+ * Read and save microcode version and date.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+ asc_dvc->cfg->mcode_date);
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+ asc_dvc->cfg->mcode_version);
+
+ /*
+ * Set the chip type to indicate the ASC3550.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
+
+ /*
+ * If the PCI Configuration Command Register "Parity Error Response
+ * Control" Bit was clear (0), then set the microcode variable
+ * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+ * to ignore DMA parity errors.
+ */
+ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_IGNORE_PERR;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
}
- if (s->sg_cnt > 0) {
+ /*
+ * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
+ * threshold of 128 bytes. This register is only accessible to the host.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+ START_CTL_EMFU | READ_CMD_MRM);
- len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
- s->sg_cnt, s->sg_elem);
- ASC_PRT_NEXT();
+ /*
+ * Microcode operating variables for WDTR, SDTR, and command tag
+ * queuing will be set in slave_configure() based on what a
+ * device reports it is capable of in Inquiry byte 7.
+ *
+ * If SCSI Bus Resets have been disabled, then directly set
+ * SDTR and WDTR from the EEPROM configuration. This will allow
+ * the BIOS and warm boot to work without a SCSI bus hang on
+ * the Inquiry caused by host and target mismatched DTR values.
+ * Without the SCSI Bus Reset, before an Inquiry a device can't
+ * be assumed to be in Asynchronous, Narrow mode.
+ */
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+ asc_dvc->wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+ asc_dvc->sdtr_able);
+ }
- len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
- s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
- ASC_PRT_NEXT();
+ /*
+ * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
+ * bitmask. These values determine the maximum SDTR speed negotiated
+ * with a device.
+ *
+ * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+ * without determining here whether the device supports SDTR.
+ *
+ * 4-bit speed SDTR speed name
+ * =========== ===============
+ * 0000b (0x0) SDTR disabled
+ * 0001b (0x1) 5 Mhz
+ * 0010b (0x2) 10 Mhz
+ * 0011b (0x3) 20 Mhz (Ultra)
+ * 0100b (0x4) 40 Mhz (LVD/Ultra2)
+ * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
+ * 0110b (0x6) Undefined
+ * .
+ * 1111b (0xF) Undefined
+ */
+ word = 0;
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
+ /* Set Ultra speed for TID 'tid'. */
+ word |= (0x3 << (4 * (tid % 4)));
+ } else {
+ /* Set Fast speed for TID 'tid'. */
+ word |= (0x2 << (4 * (tid % 4)));
+ }
+ if (tid == 3) { /* Check if done with sdtr_speed1. */
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
+ word = 0;
+ } else if (tid == 7) { /* Check if done with sdtr_speed2. */
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
+ word = 0;
+ } else if (tid == 11) { /* Check if done with sdtr_speed3. */
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
+ word = 0;
+ } else if (tid == 15) { /* Check if done with sdtr_speed4. */
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
+ /* End of loop. */
+ }
+ }
- /* Scatter gather transfer statistics */
- len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
- s->sg_elem / s->sg_cnt,
- ASC_TENTHS(s->sg_elem, s->sg_cnt));
- ASC_PRT_NEXT();
+ /*
+ * Set microcode operating variable for the disconnect per TID bitmask.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+ asc_dvc->cfg->disc_enable);
- len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
- (s->sg_xfer / 2) / s->sg_elem,
- ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
- ASC_PRT_NEXT();
+ /*
+ * Set SCSI_CFG0 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG0 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+ PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+ asc_dvc->chip_scsi_id);
- len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
- (s->sg_xfer / 2) / s->sg_cnt,
- ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
- ASC_PRT_NEXT();
+ /*
+ * Determine SCSI_CFG1 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+
+ /* Read current SCSI_CFG1 Register value. */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+ /*
+ * If all three connectors are in use, return an error.
+ */
+ if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
+ (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
+ asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
+ return ADV_ERROR;
}
/*
- * Display request queuing statistics.
+ * If the internal narrow cable is reversed all of the SCSI_CTRL
+ * register signals will be set. Check for and return an error if
+ * this condition is found.
*/
- len = asc_prt_line(cp, leftlen,
- " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
- HZ);
- ASC_PRT_NEXT();
+ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+ asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+ return ADV_ERROR;
+ }
- return totlen;
+ /*
+ * If this is a differential board and a single-ended device
+ * is attached to one of the connectors, return an error.
+ */
+ if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
+ asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
+ return ADV_ERROR;
+ }
+
+ /*
+ * If automatic termination control is enabled, then set the
+ * termination value based on a table listed in a_condor.h.
+ *
+ * If manual termination was specified with an EEPROM setting
+ * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
+ * is ready to be 'ored' into SCSI_CFG1.
+ */
+ if (asc_dvc->cfg->termination == 0) {
+ /*
+ * The software always controls termination by setting TERM_CTL_SEL.
+ * If TERM_CTL_SEL were set to 0, the hardware would set termination.
+ */
+ asc_dvc->cfg->termination |= TERM_CTL_SEL;
+
+ switch (scsi_cfg1 & CABLE_DETECT) {
+ /* TERM_CTL_H: on, TERM_CTL_L: on */
+ case 0x3:
+ case 0x7:
+ case 0xB:
+ case 0xD:
+ case 0xE:
+ case 0xF:
+ asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
+ break;
+
+ /* TERM_CTL_H: on, TERM_CTL_L: off */
+ case 0x1:
+ case 0x5:
+ case 0x9:
+ case 0xA:
+ case 0xC:
+ asc_dvc->cfg->termination |= TERM_CTL_H;
+ break;
+
+ /* TERM_CTL_H: off, TERM_CTL_L: off */
+ case 0x2:
+ case 0x6:
+ break;
+ }
+ }
+
+ /*
+ * Clear any set TERM_CTL_H and TERM_CTL_L bits.
+ */
+ scsi_cfg1 &= ~TERM_CTL;
+
+ /*
+ * Invert the TERM_CTL_H and TERM_CTL_L bits and then
+ * set 'scsi_cfg1'. The TERM_POL bit does not need to be
+ * referenced, because the hardware internally inverts
+ * the Termination High and Low bits if TERM_POL is set.
+ */
+ scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
+
+ /*
+ * Set SCSI_CFG1 Microcode Default Value
+ *
+ * Set filter value and possibly modified termination control
+ * bits in the Microcode SCSI_CFG1 Register Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
+ FLTR_DISABLE | scsi_cfg1);
+
+ /*
+ * Set MEM_CFG Microcode Default Value
+ *
+ * The microcode will set the MEM_CFG register using this value
+ * after it is started below.
+ *
+ * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+ * are defined.
+ *
+ * ASC-3550 has 8KB internal memory.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ BIOS_EN | RAM_SZ_8KB);
+
+ /*
+ * Set SEL_MASK Microcode Default Value
+ *
+ * The microcode will set the SEL_MASK register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+ AdvBuildCarrierFreelist(asc_dvc);
+
+ /*
+ * Set-up the Host->RISC Initiator Command Queue (ICQ).
+ */
+
+ if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+
+ /*
+ * The first command issued will be placed in the stopper carrier.
+ */
+ asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC ICQ physical address start value.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+ /*
+ * Set-up the RISC->Host Initiator Response Queue (IRQ).
+ */
+ if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+ /*
+ * The first command completed by the RISC will be placed in
+ * the stopper.
+ *
+ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+ * completed the RISC will set the ASC_RQ_STOPPER bit.
+ */
+ asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC IRQ physical address start value.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+ asc_dvc->carr_pending_cnt = 0;
+
+ AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+ (ADV_INTR_ENABLE_HOST_INTR |
+ ADV_INTR_ENABLE_GLOBAL_INTR));
+
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+ AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+ /* finally, finally, gentlemen, start your engine */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+ /*
+ * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+ * Resets should be performed. The RISC has to be running
+ * to issue a SCSI Bus Reset.
+ */
+ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+ /*
+ * If the BIOS Signature is present in memory, restore the
+ * BIOS Handshake Configuration Table and do not perform
+ * a SCSI Bus Reset.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+ 0x55AA) {
+ /*
+ * Restore per TID negotiated values.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+ tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvWriteByteLram(iop_base,
+ ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+ } else {
+ if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+ warn_code = ASC_WARN_BUSRESET_ERROR;
+ }
+ }
+ }
+
+ return warn_code;
}
/*
- * asc_prt_target_stats()
+ * Initialize the ASC-38C0800.
*
- * Note: no single line should be greater than ASC_PRTLINE_SIZE,
- * cf. asc_prt_line().
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
*
- * This is separated from asc_prt_board_stats because a full set
- * of targets will overflow ASC_PRTBUF_SIZE.
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
*
- * Return the number of characters copied into 'cp'. No more than
- * 'cplen' characters will be copied to 'cp'.
+ * Needed after initialization for error recovery.
*/
-static int
-asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
+static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
{
- int leftlen;
- int totlen;
- int len;
- struct asc_stats *s;
- ushort chip_scsi_id;
- asc_board_t *boardp;
- asc_queue_t *active;
- asc_queue_t *waiting;
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ int begin_addr;
+ int end_addr;
+ ushort code_sum;
+ int word;
+ int i;
+ ushort scsi_cfg1;
+ uchar byte;
+ uchar tid;
+ ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
+ ushort wdtr_able, sdtr_able, tagqng_able;
+ uchar max_cmd[ADV_MAX_TID + 1];
- leftlen = cplen;
- totlen = len = 0;
+ /* If there is already an error, don't continue. */
+ if (asc_dvc->err_code != 0)
+ return ADV_ERROR;
- boardp = ASC_BOARDP(shost);
- s = &boardp->asc_stats;
+ /*
+ * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
+ asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
+ }
- active = &ASC_BOARDP(shost)->active;
- waiting = &ASC_BOARDP(shost)->waiting;
+ warn_code = 0;
+ iop_base = asc_dvc->iop_base;
- if (ASC_NARROW_BOARD(boardp)) {
- chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
- } else {
- chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+ /*
+ * Save the RISC memory BIOS region before writing the microcode.
+ * The BIOS may already be loaded and using its RISC LRAM region
+ * so its region must be saved and restored.
+ *
+ * Note: This code makes the assumption, which is currently true,
+ * that a chip reset does not clear RISC LRAM.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
}
- if ((chip_scsi_id == tgt_id) ||
- ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
- return 0;
+ /*
+ * Save current per TID negotiated values.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
}
- do {
- if (active->q_tot_cnt[tgt_id] > 0
- || waiting->q_tot_cnt[tgt_id] > 0) {
- len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
- ASC_PRT_NEXT();
+ /*
+ * RAM BIST (RAM Built-In Self Test)
+ *
+ * Address : I/O base + offset 0x38h register (byte).
+ * Function: Bit 7-6(RW) : RAM mode
+ * Normal Mode : 0x00
+ * Pre-test Mode : 0x40
+ * RAM Test Mode : 0x80
+ * Bit 5 : unused
+ * Bit 4(RO) : Done bit
+ * Bit 3-0(RO) : Status
+ * Host Error : 0x08
+ * Int_RAM Error : 0x04
+ * RISC Error : 0x02
+ * SCSI Error : 0x01
+ * No Error : 0x00
+ *
+ * Note: RAM BIST code should be put right here, before loading the
+ * microcode and after saving the RISC memory BIOS region.
+ */
- len = asc_prt_line(cp, leftlen,
- " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
- active->q_cur_cnt[tgt_id],
- active->q_max_cnt[tgt_id],
- active->q_tot_cnt[tgt_id],
- active->q_min_tim[tgt_id],
- active->q_max_tim[tgt_id],
- (active->q_tot_cnt[tgt_id] ==
- 0) ? 0 : (active->
- q_tot_tim[tgt_id] /
- active->
- q_tot_cnt[tgt_id]),
- (active->q_tot_cnt[tgt_id] ==
- 0) ? 0 : ASC_TENTHS(active->
- q_tot_tim
- [tgt_id],
- active->
- q_tot_cnt
- [tgt_id]));
- ASC_PRT_NEXT();
+ /*
+ * LRAM Pre-test
+ *
+ * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+ * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+ * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+ * to NORMAL_MODE, return an error too.
+ */
+ for (i = 0; i < 2; i++) {
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+ mdelay(10); /* Wait for 10ms before reading back. */
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0
+ || (byte & 0x0F) != PRE_TEST_VALUE) {
+ asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
+ }
- len = asc_prt_line(cp, leftlen,
- " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
- waiting->q_cur_cnt[tgt_id],
- waiting->q_max_cnt[tgt_id],
- waiting->q_tot_cnt[tgt_id],
- waiting->q_min_tim[tgt_id],
- waiting->q_max_tim[tgt_id],
- (waiting->q_tot_cnt[tgt_id] ==
- 0) ? 0 : (waiting->
- q_tot_tim[tgt_id] /
- waiting->
- q_tot_cnt[tgt_id]),
- (waiting->q_tot_cnt[tgt_id] ==
- 0) ? 0 : ASC_TENTHS(waiting->
- q_tot_tim
- [tgt_id],
- waiting->
- q_tot_cnt
- [tgt_id]));
- ASC_PRT_NEXT();
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+ mdelay(10); /* Wait for 10ms before reading back. */
+ if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+ != NORMAL_VALUE) {
+ asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
}
- } while (0);
+ }
- return totlen;
-}
-#endif /* CONFIG_PROC_FS */
-#endif /* ADVANSYS_STATS */
+ /*
+ * LRAM Test - It takes about 1.5 ms to run through the test.
+ *
+ * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+ * If Done bit not set or Status not 0, save register byte, set the
+ * err_code, and return an error.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+ mdelay(10); /* Wait for 10ms before checking status. */
-#ifdef ADVANSYS_DEBUG
-/*
- * asc_prt_scsi_host()
- */
-static void asc_prt_scsi_host(struct Scsi_Host *s)
-{
- asc_board_t *boardp;
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
+ /* Get here if Done bit not set or Status not 0. */
+ asc_dvc->bist_err_code = byte; /* for BIOS display message */
+ asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
+ return ADV_ERROR;
+ }
- boardp = ASC_BOARDP(s);
+ /* We need to reset back to normal mode after LRAM test passes. */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
- printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
- printk(" host_busy %u, host_no %d, last_reset %d,\n",
- s->host_busy, s->host_no, (unsigned)s->last_reset);
+ asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C0800_buf,
+ _adv_asc38C0800_size, ADV_38C0800_MEMSIZE,
+ _adv_asc38C0800_chksum);
+ if (asc_dvc->err_code)
+ return ADV_ERROR;
- printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
- (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq);
+ /*
+ * Restore the RISC memory BIOS region.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- printk(" dma_channel %d, this_id %d, can_queue %d,\n",
- s->dma_channel, s->this_id, s->can_queue);
+ /*
+ * Calculate and write the microcode code checksum to the microcode
+ * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+ AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+ code_sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+ for (word = begin_addr; word < end_addr; word += 2) {
+ code_sum += AdvReadWordAutoIncLram(iop_base);
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
- printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
- s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
+ /*
+ * Read microcode version and date.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+ asc_dvc->cfg->mcode_date);
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+ asc_dvc->cfg->mcode_version);
- if (ASC_NARROW_BOARD(boardp)) {
- asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
- asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
- } else {
- asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
- asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
+ /*
+ * Set the chip type to indicate the ASC38C0800.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
+
+ /*
+ * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+ * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+ * cable detection and then we are able to read C_DET[3:0].
+ *
+ * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+ * Microcode Default Value' section below.
+ */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+ AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
+ scsi_cfg1 | DIS_TERM_DRV);
+
+ /*
+ * If the PCI Configuration Command Register "Parity Error Response
+ * Control" Bit was clear (0), then set the microcode variable
+ * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+ * to ignore DMA parity errors.
+ */
+ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_IGNORE_PERR;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
}
-}
-/*
- * asc_prt_scsi_cmnd()
- */
-static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
-{
- printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
+ /*
+ * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
+ * bits for the default FIFO threshold.
+ *
+ * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
+ *
+ * For DMA Errata #4 set the BC_THRESH_ENB bit.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+ BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
+ READ_CMD_MRM);
- printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
- (ulong)s->device->host, (ulong)s->device, s->device->id,
- s->device->lun, s->device->channel);
+ /*
+ * Microcode operating variables for WDTR, SDTR, and command tag
+ * queuing will be set in slave_configure() based on what a
+ * device reports it is capable of in Inquiry byte 7.
+ *
+ * If SCSI Bus Resets have been disabled, then directly set
+ * SDTR and WDTR from the EEPROM configuration. This will allow
+ * the BIOS and warm boot to work without a SCSI bus hang on
+ * the Inquiry caused by host and target mismatched DTR values.
+ * Without the SCSI Bus Reset, before an Inquiry a device can't
+ * be assumed to be in Asynchronous, Narrow mode.
+ */
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+ asc_dvc->wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+ asc_dvc->sdtr_able);
+ }
- asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
+ /*
+ * Set microcode operating variables for DISC and SDTR_SPEED1,
+ * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+ * configuration values.
+ *
+ * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+ * without determining here whether the device supports SDTR.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+ asc_dvc->cfg->disc_enable);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
- printk("sc_data_direction %u, resid %d\n",
- s->sc_data_direction, s->resid);
+ /*
+ * Set SCSI_CFG0 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG0 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+ PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+ asc_dvc->chip_scsi_id);
- printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
+ /*
+ * Determine SCSI_CFG1 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
- printk(" serial_number 0x%x, retries %d, allowed %d\n",
- (unsigned)s->serial_number, s->retries, s->allowed);
+ /* Read current SCSI_CFG1 Register value. */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
- printk(" timeout_per_command %d\n", s->timeout_per_command);
+ /*
+ * If the internal narrow cable is reversed all of the SCSI_CTRL
+ * register signals will be set. Check for and return an error if
+ * this condition is found.
+ */
+ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+ asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+ return ADV_ERROR;
+ }
- printk
- (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
- (ulong)s->scsi_done, (ulong)s->done, (ulong)s->host_scribble,
- s->result);
+ /*
+ * All kind of combinations of devices attached to one of four
+ * connectors are acceptable except HVD device attached. For example,
+ * LVD device can be attached to SE connector while SE device attached
+ * to LVD connector. If LVD device attached to SE connector, it only
+ * runs up to Ultra speed.
+ *
+ * If an HVD device is attached to one of LVD connectors, return an
+ * error. However, there is no way to detect HVD device attached to
+ * SE connectors.
+ */
+ if (scsi_cfg1 & HVD) {
+ asc_dvc->err_code = ASC_IERR_HVD_DEVICE;
+ return ADV_ERROR;
+ }
- printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
-}
+ /*
+ * If either SE or LVD automatic termination control is enabled, then
+ * set the termination value based on a table listed in a_condor.h.
+ *
+ * If manual termination was specified with an EEPROM setting then
+ * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready
+ * to be 'ored' into SCSI_CFG1.
+ */
+ if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
+ /* SE automatic termination control is enabled. */
+ switch (scsi_cfg1 & C_DET_SE) {
+ /* TERM_SE_HI: on, TERM_SE_LO: on */
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ asc_dvc->cfg->termination |= TERM_SE;
+ break;
-/*
- * asc_prt_asc_dvc_var()
- */
-static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
-{
- printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
+ /* TERM_SE_HI: on, TERM_SE_LO: off */
+ case 0x0:
+ asc_dvc->cfg->termination |= TERM_SE_HI;
+ break;
+ }
+ }
- printk
- (" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
- h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
+ if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
+ /* LVD automatic termination control is enabled. */
+ switch (scsi_cfg1 & C_DET_LVD) {
+ /* TERM_LVD_HI: on, TERM_LVD_LO: on */
+ case 0x4:
+ case 0x8:
+ case 0xC:
+ asc_dvc->cfg->termination |= TERM_LVD;
+ break;
- printk
- (" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
- h->bus_type, (ulong)h->isr_callback, (ulong)h->exe_callback,
- (unsigned)h->init_sdtr);
+ /* TERM_LVD_HI: off, TERM_LVD_LO: off */
+ case 0x0:
+ break;
+ }
+ }
- printk
- (" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
- (unsigned)h->sdtr_done, (unsigned)h->use_tagged_qng,
- (unsigned)h->unit_not_ready, (unsigned)h->chip_no);
+ /*
+ * Clear any set TERM_SE and TERM_LVD bits.
+ */
+ scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
- printk
- (" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
- (unsigned)h->queue_full_or_busy, (unsigned)h->start_motor,
- (unsigned)h->scsi_reset_wait);
+ /*
+ * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
+ */
+ scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
- printk
- (" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
- (unsigned)h->is_in_int, (unsigned)h->max_total_qng,
- (unsigned)h->cur_total_qng, (unsigned)h->in_critical_cnt);
+ /*
+ * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE
+ * bits and set possibly modified termination control bits in the
+ * Microcode SCSI_CFG1 Register Value.
+ */
+ scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
- printk
- (" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
- (unsigned)h->last_q_shortage, (unsigned)h->init_state,
- (unsigned)h->no_scam, (unsigned)h->pci_fix_asyn_xfer);
+ /*
+ * Set SCSI_CFG1 Microcode Default Value
+ *
+ * Set possibly modified termination control and reset DIS_TERM_DRV
+ * bits in the Microcode SCSI_CFG1 Register Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
- printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
-}
+ /*
+ * Set MEM_CFG Microcode Default Value
+ *
+ * The microcode will set the MEM_CFG register using this value
+ * after it is started below.
+ *
+ * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+ * are defined.
+ *
+ * ASC-38C0800 has 16KB internal memory.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ BIOS_EN | RAM_SZ_16KB);
-/*
- * asc_prt_asc_dvc_cfg()
- */
-static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
-{
- printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
+ /*
+ * Set SEL_MASK Microcode Default Value
+ *
+ * The microcode will set the SEL_MASK register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
- printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
- h->can_tagged_qng, h->cmd_qng_enabled);
- printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
- h->disc_enable, h->sdtr_enable);
+ AdvBuildCarrierFreelist(asc_dvc);
- printk
- (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
- h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
- h->chip_version);
+ /*
+ * Set-up the Host->RISC Initiator Command Queue (ICQ).
+ */
- printk
- (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
- to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
- h->mcode_date);
+ if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
- printk(" mcode_version %d, overrun_buf 0x%lx\n",
- h->mcode_version, (ulong)h->overrun_buf);
+ /*
+ * The first command issued will be placed in the stopper carrier.
+ */
+ asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC ICQ physical address start value.
+ * carr_pa is LE, must be native before write
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+ /*
+ * Set-up the RISC->Host Initiator Response Queue (IRQ).
+ */
+ if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+ /*
+ * The first command completed by the RISC will be placed in
+ * the stopper.
+ *
+ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+ * completed the RISC will set the ASC_RQ_STOPPER bit.
+ */
+ asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC IRQ physical address start value.
+ *
+ * carr_pa is LE, must be native before write *
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+ asc_dvc->carr_pending_cnt = 0;
+
+ AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+ (ADV_INTR_ENABLE_HOST_INTR |
+ ADV_INTR_ENABLE_GLOBAL_INTR));
+
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+ AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+ /* finally, finally, gentlemen, start your engine */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+ /*
+ * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+ * Resets should be performed. The RISC has to be running
+ * to issue a SCSI Bus Reset.
+ */
+ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+ /*
+ * If the BIOS Signature is present in memory, restore the
+ * BIOS Handshake Configuration Table and do not perform
+ * a SCSI Bus Reset.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+ 0x55AA) {
+ /*
+ * Restore per TID negotiated values.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+ tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvWriteByteLram(iop_base,
+ ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+ } else {
+ if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+ warn_code = ASC_WARN_BUSRESET_ERROR;
+ }
+ }
+ }
+
+ return warn_code;
}
/*
- * asc_prt_asc_scsi_q()
+ * Initialize the ASC-38C1600.
+ *
+ * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Needed after initialization for error recovery.
*/
-static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
+static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
{
- ASC_SG_HEAD *sgp;
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ int begin_addr;
+ int end_addr;
+ ushort code_sum;
+ long word;
int i;
+ ushort scsi_cfg1;
+ uchar byte;
+ uchar tid;
+ ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
+ ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
+ uchar max_cmd[ASC_MAX_TID + 1];
- printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
+ /* If there is already an error, don't continue. */
+ if (asc_dvc->err_code != 0) {
+ return ADV_ERROR;
+ }
- printk
- (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
- q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
- q->q2.tag_code);
+ /*
+ * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
+ asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
+ }
- printk
- (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
- (ulong)le32_to_cpu(q->q1.data_addr),
- (ulong)le32_to_cpu(q->q1.data_cnt),
- (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
+ warn_code = 0;
+ iop_base = asc_dvc->iop_base;
- printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
- (ulong)q->cdbptr, q->q2.cdb_len,
- (ulong)q->sg_head, q->q1.sg_queue_cnt);
+ /*
+ * Save the RISC memory BIOS region before writing the microcode.
+ * The BIOS may already be loaded and using its RISC LRAM region
+ * so its region must be saved and restored.
+ *
+ * Note: This code makes the assumption, which is currently true,
+ * that a chip reset does not clear RISC LRAM.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- if (q->sg_head) {
- sgp = q->sg_head;
- printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
- printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
- sgp->queue_cnt);
- for (i = 0; i < sgp->entry_cnt; i++) {
- printk(" [%u]: addr 0x%lx, bytes %lu\n",
- i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
- (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
+ /*
+ * Save current per TID negotiated values.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+
+ /*
+ * RAM BIST (Built-In Self Test)
+ *
+ * Address : I/O base + offset 0x38h register (byte).
+ * Function: Bit 7-6(RW) : RAM mode
+ * Normal Mode : 0x00
+ * Pre-test Mode : 0x40
+ * RAM Test Mode : 0x80
+ * Bit 5 : unused
+ * Bit 4(RO) : Done bit
+ * Bit 3-0(RO) : Status
+ * Host Error : 0x08
+ * Int_RAM Error : 0x04
+ * RISC Error : 0x02
+ * SCSI Error : 0x01
+ * No Error : 0x00
+ *
+ * Note: RAM BIST code should be put right here, before loading the
+ * microcode and after saving the RISC memory BIOS region.
+ */
+
+ /*
+ * LRAM Pre-test
+ *
+ * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+ * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+ * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+ * to NORMAL_MODE, return an error too.
+ */
+ for (i = 0; i < 2; i++) {
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+ mdelay(10); /* Wait for 10ms before reading back. */
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0
+ || (byte & 0x0F) != PRE_TEST_VALUE) {
+ asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
}
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+ mdelay(10); /* Wait for 10ms before reading back. */
+ if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+ != NORMAL_VALUE) {
+ asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST;
+ return ADV_ERROR;
+ }
}
-}
-/*
- * asc_prt_asc_qdone_info()
- */
-static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
-{
- printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
- printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
- (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
- q->d2.tag_code);
- printk
- (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
- q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
-}
+ /*
+ * LRAM Test - It takes about 1.5 ms to run through the test.
+ *
+ * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+ * If Done bit not set or Status not 0, save register byte, set the
+ * err_code, and return an error.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+ mdelay(10); /* Wait for 10ms before checking status. */
-/*
- * asc_prt_adv_dvc_var()
- *
- * Display an ADV_DVC_VAR structure.
- */
-static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
-{
- printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
+ byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+ if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
+ /* Get here if Done bit not set or Status not 0. */
+ asc_dvc->bist_err_code = byte; /* for BIOS display message */
+ asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST;
+ return ADV_ERROR;
+ }
- printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
- (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
+ /* We need to reset back to normal mode after LRAM test passes. */
+ AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
- printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
- (ulong)h->isr_callback, (unsigned)h->sdtr_able,
- (unsigned)h->wdtr_able);
+ asc_dvc->err_code = AdvLoadMicrocode(iop_base, _adv_asc38C1600_buf,
+ _adv_asc38C1600_size, ADV_38C1600_MEMSIZE,
+ _adv_asc38C1600_chksum);
+ if (asc_dvc->err_code)
+ return ADV_ERROR;
- printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
- (unsigned)h->start_motor,
- (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
+ /*
+ * Restore the RISC memory BIOS region.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+ AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+ bios_mem[i]);
+ }
- printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
- (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
- (ulong)h->carr_freelist);
+ /*
+ * Calculate and write the microcode code checksum to the microcode
+ * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+ AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+ code_sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+ for (word = begin_addr; word < end_addr; word += 2) {
+ code_sum += AdvReadWordAutoIncLram(iop_base);
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
- printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
- (ulong)h->icq_sp, (ulong)h->irq_sp);
+ /*
+ * Read microcode version and date.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+ asc_dvc->cfg->mcode_date);
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+ asc_dvc->cfg->mcode_version);
- printk(" no_scam 0x%x, tagqng_able 0x%x\n",
- (unsigned)h->no_scam, (unsigned)h->tagqng_able);
+ /*
+ * Set the chip type to indicate the ASC38C1600.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
- printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
- (unsigned)h->chip_scsi_id, (ulong)h->cfg);
-}
+ /*
+ * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+ * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+ * cable detection and then we are able to read C_DET[3:0].
+ *
+ * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+ * Microcode Default Value' section below.
+ */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+ AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
+ scsi_cfg1 | DIS_TERM_DRV);
-/*
- * asc_prt_adv_dvc_cfg()
- *
- * Display an ADV_DVC_CFG structure.
- */
-static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
-{
- printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
+ /*
+ * If the PCI Configuration Command Register "Parity Error Response
+ * Control" Bit was clear (0), then set the microcode variable
+ * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+ * to ignore DMA parity errors.
+ */
+ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_IGNORE_PERR;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ }
- printk(" disc_enable 0x%x, termination 0x%x\n",
- h->disc_enable, h->termination);
+ /*
+ * If the BIOS control flag AIPP (Asynchronous Information
+ * Phase Protection) disable bit is not set, then set the firmware
+ * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
+ * AIPP checking and encoding.
+ */
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_ENABLE_AIPP;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ }
- printk(" chip_version 0x%x, mcode_date 0x%x\n",
- h->chip_version, h->mcode_date);
+ /*
+ * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
+ * and START_CTL_TH [3:2].
+ */
+ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+ FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
- printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
- h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
+ /*
+ * Microcode operating variables for WDTR, SDTR, and command tag
+ * queuing will be set in slave_configure() based on what a
+ * device reports it is capable of in Inquiry byte 7.
+ *
+ * If SCSI Bus Resets have been disabled, then directly set
+ * SDTR and WDTR from the EEPROM configuration. This will allow
+ * the BIOS and warm boot to work without a SCSI bus hang on
+ * the Inquiry caused by host and target mismatched DTR values.
+ * Without the SCSI Bus Reset, before an Inquiry a device can't
+ * be assumed to be in Asynchronous, Narrow mode.
+ */
+ if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+ asc_dvc->wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+ asc_dvc->sdtr_able);
+ }
- printk(" control_flag 0x%x, pci_slot_info 0x%x\n",
- h->control_flag, h->pci_slot_info);
-}
+ /*
+ * Set microcode operating variables for DISC and SDTR_SPEED1,
+ * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+ * configuration values.
+ *
+ * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+ * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+ * without determining here whether the device supports SDTR.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+ asc_dvc->cfg->disc_enable);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
-/*
- * asc_prt_adv_scsi_req_q()
- *
- * Display an ADV_SCSI_REQ_Q structure.
- */
-static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
-{
- int sg_blk_cnt;
- struct asc_sg_block *sg_ptr;
+ /*
+ * Set SCSI_CFG0 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG0 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+ PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+ asc_dvc->chip_scsi_id);
- printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
+ /*
+ * Calculate SCSI_CFG1 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ *
+ * Each ASC-38C1600 function has only two cable detect bits.
+ * The bus mode override bits are in IOPB_SOFT_OVER_WR.
+ */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
- printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
- q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
+ /*
+ * If the cable is reversed all of the SCSI_CTRL register signals
+ * will be set. Check for and return an error if this condition is
+ * found.
+ */
+ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+ asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+ return ADV_ERROR;
+ }
- printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
- q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
+ /*
+ * Each ASC-38C1600 function has two connectors. Only an HVD device
+ * can not be connected to either connector. An LVD device or SE device
+ * may be connected to either connecor. If an SE device is connected,
+ * then at most Ultra speed (20 Mhz) can be used on both connectors.
+ *
+ * If an HVD device is attached, return an error.
+ */
+ if (scsi_cfg1 & HVD) {
+ asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
+ return ADV_ERROR;
+ }
- printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
- (ulong)le32_to_cpu(q->data_cnt),
- (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
+ /*
+ * Each function in the ASC-38C1600 uses only the SE cable detect and
+ * termination because there are two connectors for each function. Each
+ * function may use either LVD or SE mode. Corresponding the SE automatic
+ * termination control EEPROM bits are used for each function. Each
+ * function has its own EEPROM. If SE automatic control is enabled for
+ * the function, then set the termination value based on a table listed
+ * in a_condor.h.
+ *
+ * If manual termination is specified in the EEPROM for the function,
+ * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
+ * ready to be 'ored' into SCSI_CFG1.
+ */
+ if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
+ struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
+ /* SE automatic termination control is enabled. */
+ switch (scsi_cfg1 & C_DET_SE) {
+ /* TERM_SE_HI: on, TERM_SE_LO: on */
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ asc_dvc->cfg->termination |= TERM_SE;
+ break;
- printk
- (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
- q->cdb_len, q->done_status, q->host_status, q->scsi_status);
+ case 0x0:
+ if (PCI_FUNC(pdev->devfn) == 0) {
+ /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
+ } else {
+ /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
+ asc_dvc->cfg->termination |= TERM_SE_HI;
+ }
+ break;
+ }
+ }
- printk(" sg_working_ix 0x%x, target_cmd %u\n",
- q->sg_working_ix, q->target_cmd);
+ /*
+ * Clear any set TERM_SE bits.
+ */
+ scsi_cfg1 &= ~TERM_SE;
- printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
- (ulong)le32_to_cpu(q->scsiq_rptr),
- (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
+ /*
+ * Invert the TERM_SE bits and then set 'scsi_cfg1'.
+ */
+ scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
- /* Display the request's ADV_SG_BLOCK structures. */
- if (q->sg_list_ptr != NULL) {
- sg_blk_cnt = 0;
- while (1) {
+ /*
+ * Clear Big Endian and Terminator Polarity bits and set possibly
+ * modified termination control bits in the Microcode SCSI_CFG1
+ * Register Value.
+ *
+ * Big Endian bit is not used even on big endian machines.
+ */
+ scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
+
+ /*
+ * Set SCSI_CFG1 Microcode Default Value
+ *
+ * Set possibly modified termination control bits in the Microcode
+ * SCSI_CFG1 Register Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+
+ /*
+ * Set MEM_CFG Microcode Default Value
+ *
+ * The microcode will set the MEM_CFG register using this value
+ * after it is started below.
+ *
+ * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+ * are defined.
+ *
+ * ASC-38C1600 has 32KB internal memory.
+ *
+ * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
+ * out a special 16K Adv Library and Microcode version. After the issue
+ * resolved, we should turn back to the 32K support. Both a_condor.h and
+ * mcode.sas files also need to be updated.
+ *
+ * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ * BIOS_EN | RAM_SZ_32KB);
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+ BIOS_EN | RAM_SZ_16KB);
+
+ /*
+ * Set SEL_MASK Microcode Default Value
+ *
+ * The microcode will set the SEL_MASK register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+ AdvBuildCarrierFreelist(asc_dvc);
+
+ /*
+ * Set-up the Host->RISC Initiator Command Queue (ICQ).
+ */
+ if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+
+ /*
+ * The first command issued will be placed in the stopper carrier.
+ */
+ asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC ICQ physical address start value. Initialize the
+ * COMMA register to the same value otherwise the RISC will
+ * prematurely detect a command is available.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+ AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+ le32_to_cpu(asc_dvc->icq_sp->carr_pa));
+
+ /*
+ * Set-up the RISC->Host Initiator Response Queue (IRQ).
+ */
+ if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+ asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+ return ADV_ERROR;
+ }
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+ /*
+ * The first command completed by the RISC will be placed in
+ * the stopper.
+ *
+ * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+ * completed the RISC will set the ASC_RQ_STOPPER bit.
+ */
+ asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+ /*
+ * Set RISC IRQ physical address start value.
+ */
+ AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+ asc_dvc->carr_pending_cnt = 0;
+
+ AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+ (ADV_INTR_ENABLE_HOST_INTR |
+ ADV_INTR_ENABLE_GLOBAL_INTR));
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+ AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+ /* finally, finally, gentlemen, start your engine */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+ /*
+ * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+ * Resets should be performed. The RISC has to be running
+ * to issue a SCSI Bus Reset.
+ */
+ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+ /*
+ * If the BIOS Signature is present in memory, restore the
+ * per TID microcode operating variables.
+ */
+ if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+ 0x55AA) {
/*
- * 'sg_ptr' is a physical address. Convert it to a virtual
- * address by indexing 'sg_blk_cnt' into the virtual address
- * array 'sg_list_ptr'.
- *
- * XXX - Assumes all SG physical blocks are virtually contiguous.
+ * Restore per TID negotiated values.
*/
- sg_ptr =
- &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
- asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
- if (sg_ptr->sg_ptr == 0) {
- break;
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+ tagqng_able);
+ for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+ AdvWriteByteLram(iop_base,
+ ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
+ }
+ } else {
+ if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+ warn_code = ASC_WARN_BUSRESET_ERROR;
}
- sg_blk_cnt++;
}
}
+
+ return warn_code;
}
/*
- * asc_prt_adv_sgblock()
+ * Reset chip and SCSI Bus.
*
- * Display an ADV_SG_BLOCK structure.
+ * Return Value:
+ * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
+ * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
*/
-static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
+static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
{
- int i;
+ int status;
+ ushort wdtr_able, sdtr_able, tagqng_able;
+ ushort ppr_able = 0;
+ uchar tid, max_cmd[ADV_MAX_TID + 1];
+ AdvPortAddr iop_base;
+ ushort bios_sig;
- printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
- (ulong)b, sgblockno);
- printk(" sg_cnt %u, sg_ptr 0x%lx\n",
- b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
- ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
- if (b->sg_ptr != 0) {
- ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * Save current per TID negotiated values.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
}
- for (i = 0; i < b->sg_cnt; i++) {
- printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
- i, (ulong)b->sg_list[i].sg_addr,
- (ulong)b->sg_list[i].sg_count);
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
}
-}
-/*
- * asc_prt_hex()
- *
- * Print hexadecimal output in 4 byte groupings 32 bytes
- * or 8 double-words per line.
- */
-static void asc_prt_hex(char *f, uchar *s, int l)
-{
- int i;
- int j;
- int k;
- int m;
-
- printk("%s: (%d bytes)\n", f, l);
+ /*
+ * Force the AdvInitAsc3550/38C0800Driver() function to
+ * perform a SCSI Bus Reset by clearing the BIOS signature word.
+ * The initialization functions assumes a SCSI Bus Reset is not
+ * needed if the BIOS signature word is present.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+ AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
- for (i = 0; i < l; i += 32) {
+ /*
+ * Stop chip and reset it.
+ */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
+ mdelay(100);
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+ ADV_CTRL_REG_CMD_WR_IO_REG);
- /* Display a maximum of 8 double-words per line. */
- if ((k = (l - i) / 4) >= 8) {
- k = 8;
- m = 0;
- } else {
- m = (l - i) % 4;
- }
+ /*
+ * Reset Adv Library error code, if any, and try
+ * re-initializing the chip.
+ */
+ asc_dvc->err_code = 0;
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ status = AdvInitAsc38C1600Driver(asc_dvc);
+ } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ status = AdvInitAsc38C0800Driver(asc_dvc);
+ } else {
+ status = AdvInitAsc3550Driver(asc_dvc);
+ }
- for (j = 0; j < k; j++) {
- printk(" %2.2X%2.2X%2.2X%2.2X",
- (unsigned)s[i + (j * 4)],
- (unsigned)s[i + (j * 4) + 1],
- (unsigned)s[i + (j * 4) + 2],
- (unsigned)s[i + (j * 4) + 3]);
- }
+ /* Translate initialization return value to status value. */
+ if (status == 0) {
+ status = ADV_TRUE;
+ } else {
+ status = ADV_FALSE;
+ }
- switch (m) {
- case 0:
- default:
- break;
- case 1:
- printk(" %2.2X", (unsigned)s[i + (j * 4)]);
- break;
- case 2:
- printk(" %2.2X%2.2X",
- (unsigned)s[i + (j * 4)],
- (unsigned)s[i + (j * 4) + 1]);
- break;
- case 3:
- printk(" %2.2X%2.2X%2.2X",
- (unsigned)s[i + (j * 4) + 1],
- (unsigned)s[i + (j * 4) + 2],
- (unsigned)s[i + (j * 4) + 3]);
- break;
- }
+ /*
+ * Restore the BIOS signature word.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
- printk("\n");
+ /*
+ * Restore per TID negotiated values.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+ for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+ AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ max_cmd[tid]);
}
+
+ return status;
}
-#endif /* ADVANSYS_DEBUG */
/*
- * --- Asc Library Functions
+ * adv_async_callback() - Adv Library asynchronous event callback function.
*/
-
-static ushort __init AscGetEisaChipCfg(PortAddr iop_base)
+static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
{
- PortAddr eisa_cfg_iop;
+ switch (code) {
+ case ADV_ASYNC_SCSI_BUS_RESET_DET:
+ /*
+ * The firmware detected a SCSI Bus reset.
+ */
+ ASC_DBG(0, "ADV_ASYNC_SCSI_BUS_RESET_DET\n");
+ break;
- eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
- (PortAddr) (ASC_EISA_CFG_IOP_MASK);
- return (inpw(eisa_cfg_iop));
-}
+ case ADV_ASYNC_RDMA_FAILURE:
+ /*
+ * Handle RDMA failure by resetting the SCSI Bus and
+ * possibly the chip if it is unresponsive. Log the error
+ * with a unique code.
+ */
+ ASC_DBG(0, "ADV_ASYNC_RDMA_FAILURE\n");
+ AdvResetChipAndSB(adv_dvc_varp);
+ break;
-static uchar __init AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
-{
- ushort cfg_lsw;
+ case ADV_HOST_SCSI_BUS_RESET:
+ /*
+ * Host generated SCSI bus reset occurred.
+ */
+ ASC_DBG(0, "ADV_HOST_SCSI_BUS_RESET\n");
+ break;
- if (AscGetChipScsiID(iop_base) == new_host_id) {
- return (new_host_id);
+ default:
+ ASC_DBG(0, "unknown code 0x%x\n", code);
+ break;
}
- cfg_lsw = AscGetChipCfgLsw(iop_base);
- cfg_lsw &= 0xF8FF;
- cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
- AscSetChipCfgLsw(iop_base, cfg_lsw);
- return (AscGetChipScsiID(iop_base));
}
-static uchar __init AscGetChipScsiCtrl(PortAddr iop_base)
+/*
+ * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
+ *
+ * Callback function for the Wide SCSI Adv Library.
+ */
+static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
{
- uchar sc;
+ struct asc_board *boardp;
+ adv_req_t *reqp;
+ adv_sgblk_t *sgblkp;
+ struct scsi_cmnd *scp;
+ struct Scsi_Host *shost;
+ ADV_DCNT resid_cnt;
- AscSetBank(iop_base, 1);
- sc = inp(iop_base + IOP_REG_SC);
- AscSetBank(iop_base, 0);
- return (sc);
-}
+ ASC_DBG(1, "adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
+ (ulong)adv_dvc_varp, (ulong)scsiqp);
+ ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
-static uchar __init AscGetChipVersion(PortAddr iop_base, ushort bus_type)
-{
- if ((bus_type & ASC_IS_EISA) != 0) {
- PortAddr eisa_iop;
- uchar revision;
- eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
- (PortAddr) ASC_EISA_REV_IOP_MASK;
- revision = inp(eisa_iop);
- return ((uchar)((ASC_CHIP_MIN_VER_EISA - 1) + revision));
+ /*
+ * Get the adv_req_t structure for the command that has been
+ * completed. The adv_req_t structure actually contains the
+ * completed ADV_SCSI_REQ_Q structure.
+ */
+ reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
+ ASC_DBG(1, "reqp 0x%lx\n", (ulong)reqp);
+ if (reqp == NULL) {
+ ASC_PRINT("adv_isr_callback: reqp is NULL\n");
+ return;
}
- return (AscGetChipVerNo(iop_base));
-}
-static ushort __init AscGetChipBusType(PortAddr iop_base)
-{
- ushort chip_ver;
-
- chip_ver = AscGetChipVerNo(iop_base);
- if ((chip_ver >= ASC_CHIP_MIN_VER_VL)
- && (chip_ver <= ASC_CHIP_MAX_VER_VL)
- ) {
- if (((iop_base & 0x0C30) == 0x0C30)
- || ((iop_base & 0x0C50) == 0x0C50)
- ) {
- return (ASC_IS_EISA);
- }
- return (ASC_IS_VL);
+ /*
+ * Get the struct scsi_cmnd structure and Scsi_Host structure for the
+ * command that has been completed.
+ *
+ * Note: The adv_req_t request structure and adv_sgblk_t structure,
+ * if any, are dropped, because a board structure pointer can not be
+ * determined.
+ */
+ scp = reqp->cmndp;
+ ASC_DBG(1, "scp 0x%p\n", scp);
+ if (scp == NULL) {
+ ASC_PRINT
+ ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
+ return;
}
- if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
- (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
- if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
- return (ASC_IS_ISAPNP);
+ ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+
+ shost = scp->device->host;
+ ASC_STATS(shost, callback);
+ ASC_DBG(1, "shost 0x%p\n", shost);
+
+ boardp = shost_priv(shost);
+ BUG_ON(adv_dvc_varp != &boardp->dvc_var.adv_dvc_var);
+
+ /*
+ * 'done_status' contains the command's ending status.
+ */
+ switch (scsiqp->done_status) {
+ case QD_NO_ERROR:
+ ASC_DBG(2, "QD_NO_ERROR\n");
+ scp->result = 0;
+
+ /*
+ * Check for an underrun condition.
+ *
+ * If there was no error and an underrun condition, then
+ * then return the number of underrun bytes.
+ */
+ resid_cnt = le32_to_cpu(scsiqp->data_cnt);
+ if (scsi_bufflen(scp) != 0 && resid_cnt != 0 &&
+ resid_cnt <= scsi_bufflen(scp)) {
+ ASC_DBG(1, "underrun condition %lu bytes\n",
+ (ulong)resid_cnt);
+ scsi_set_resid(scp, resid_cnt);
}
- return (ASC_IS_ISA);
- } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
- (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
- return (ASC_IS_PCI);
+ break;
+
+ case QD_WITH_ERROR:
+ ASC_DBG(2, "QD_WITH_ERROR\n");
+ switch (scsiqp->host_status) {
+ case QHSTA_NO_ERROR:
+ if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
+ ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
+ ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+ sizeof(scp->sense_buffer));
+ /*
+ * Note: The 'status_byte()' macro used by
+ * target drivers defined in scsi.h shifts the
+ * status byte returned by host drivers right
+ * by 1 bit. This is why target drivers also
+ * use right shifted status byte definitions.
+ * For instance target drivers use
+ * CHECK_CONDITION, defined to 0x1, instead of
+ * the SCSI defined check condition value of
+ * 0x2. Host drivers are supposed to return
+ * the status byte as it is defined by SCSI.
+ */
+ scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+ STATUS_BYTE(scsiqp->scsi_status);
+ } else {
+ scp->result = STATUS_BYTE(scsiqp->scsi_status);
+ }
+ break;
+
+ default:
+ /* Some other QHSTA error occurred. */
+ ASC_DBG(1, "host_status 0x%x\n", scsiqp->host_status);
+ scp->result = HOST_BYTE(DID_BAD_TARGET);
+ break;
+ }
+ break;
+
+ case QD_ABORTED_BY_HOST:
+ ASC_DBG(1, "QD_ABORTED_BY_HOST\n");
+ scp->result =
+ HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
+ break;
+
+ default:
+ ASC_DBG(1, "done_status 0x%x\n", scsiqp->done_status);
+ scp->result =
+ HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
+ break;
}
- return (0);
-}
-static ASC_DCNT
-AscLoadMicroCode(PortAddr iop_base,
- ushort s_addr, uchar *mcode_buf, ushort mcode_size)
-{
- ASC_DCNT chksum;
- ushort mcode_word_size;
- ushort mcode_chksum;
+ /*
+ * If the 'init_tidmask' bit isn't already set for the target and the
+ * current request finished normally, then set the bit for the target
+ * to indicate that a device is present.
+ */
+ if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
+ scsiqp->done_status == QD_NO_ERROR &&
+ scsiqp->host_status == QHSTA_NO_ERROR) {
+ boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+ }
- /* Write the microcode buffer starting at LRAM address 0. */
- mcode_word_size = (ushort)(mcode_size >> 1);
- AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
- AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
+ asc_scsi_done(scp);
- chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
- ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
- mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
- (ushort)ASC_CODE_SEC_BEG,
- (ushort)((mcode_size -
- s_addr - (ushort)
- ASC_CODE_SEC_BEG) /
- 2));
- ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
- (ulong)mcode_chksum);
- AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
- AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
- return (chksum);
+ /*
+ * Free all 'adv_sgblk_t' structures allocated for the request.
+ */
+ while ((sgblkp = reqp->sgblkp) != NULL) {
+ /* Remove 'sgblkp' from the request list. */
+ reqp->sgblkp = sgblkp->next_sgblkp;
+
+ /* Add 'sgblkp' to the board free list. */
+ sgblkp->next_sgblkp = boardp->adv_sgblkp;
+ boardp->adv_sgblkp = sgblkp;
+ }
+
+ /*
+ * Free the adv_req_t structure used with the command by adding
+ * it back to the board free list.
+ */
+ reqp->next_reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp;
+
+ ASC_DBG(1, "done\n");
}
-static int AscFindSignature(PortAddr iop_base)
+/*
+ * Adv Library Interrupt Service Routine
+ *
+ * This function is called by a driver's interrupt service routine.
+ * The function disables and re-enables interrupts.
+ *
+ * When a microcode idle command is completed, the ADV_DVC_VAR
+ * 'idle_cmd_done' field is set to ADV_TRUE.
+ *
+ * Note: AdvISR() can be called when interrupts are disabled or even
+ * when there is no hardware interrupt condition present. It will
+ * always check for completed idle commands and microcode requests.
+ * This is an important feature that shouldn't be changed because it
+ * allows commands to be completed from polling mode loops.
+ *
+ * Return:
+ * ADV_TRUE(1) - interrupt was pending
+ * ADV_FALSE(0) - no interrupt was pending
+ */
+static int AdvISR(ADV_DVC_VAR *asc_dvc)
{
- ushort sig_word;
+ AdvPortAddr iop_base;
+ uchar int_stat;
+ ushort target_bit;
+ ADV_CARR_T *free_carrp;
+ ADV_VADDR irq_next_vpa;
+ ADV_SCSI_REQ_Q *scsiq;
- ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
- iop_base, AscGetChipSignatureByte(iop_base));
- if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
- ASC_DBG2(1,
- "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
- iop_base, AscGetChipSignatureWord(iop_base));
- sig_word = AscGetChipSignatureWord(iop_base);
- if ((sig_word == (ushort)ASC_1000_ID0W) ||
- (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
- return (1);
- }
+ iop_base = asc_dvc->iop_base;
+
+ /* Reading the register clears the interrupt. */
+ int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
+
+ if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
+ ADV_INTR_STATUS_INTRC)) == 0) {
+ return ADV_FALSE;
}
- return (0);
-}
-static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata = {
- 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
- ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
-};
+ /*
+ * Notify the driver of an asynchronous microcode condition by
+ * calling the adv_async_callback function. The function
+ * is passed the microcode ASC_MC_INTRB_CODE byte value.
+ */
+ if (int_stat & ADV_INTR_STATUS_INTRB) {
+ uchar intrb_code;
-#ifdef CONFIG_ISA
-static uchar _isa_pnp_inited __initdata = 0;
+ AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
-static PortAddr __init AscSearchIOPortAddr(PortAddr iop_beg, ushort bus_type)
-{
- if (bus_type & ASC_IS_VL) {
- while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
- if (AscGetChipVersion(iop_beg, bus_type) <=
- ASC_CHIP_MAX_VER_VL) {
- return (iop_beg);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+ asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
+ asc_dvc->carr_pending_cnt != 0) {
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE,
+ ADV_TICKLE_A);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+ AdvWriteByteRegister(iop_base,
+ IOPB_TICKLE,
+ ADV_TICKLE_NOP);
+ }
}
}
- return (0);
+
+ adv_async_callback(asc_dvc, intrb_code);
}
- if (bus_type & ASC_IS_ISA) {
- if (_isa_pnp_inited == 0) {
- AscSetISAPNPWaitForKey();
- _isa_pnp_inited++;
- }
- while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
- if ((AscGetChipVersion(iop_beg, bus_type) &
- ASC_CHIP_VER_ISA_BIT) != 0) {
- return (iop_beg);
- }
+
+ /*
+ * Check if the IRQ stopper carrier contains a completed request.
+ */
+ while (((irq_next_vpa =
+ le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
+ /*
+ * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
+ * The RISC will have set 'areq_vpa' to a virtual address.
+ *
+ * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
+ * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
+ * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
+ * in AdvExeScsiQueue().
+ */
+ scsiq = (ADV_SCSI_REQ_Q *)
+ ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
+
+ /*
+ * Request finished with good status and the queue was not
+ * DMAed to host memory by the firmware. Set all status fields
+ * to indicate good status.
+ */
+ if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
+ scsiq->done_status = QD_NO_ERROR;
+ scsiq->host_status = scsiq->scsi_status = 0;
+ scsiq->data_cnt = 0L;
}
- return (0);
+
+ /*
+ * Advance the stopper pointer to the next carrier
+ * ignoring the lower four bits. Free the previous
+ * stopper carrier.
+ */
+ free_carrp = asc_dvc->irq_sp;
+ asc_dvc->irq_sp = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
+
+ free_carrp->next_vpa =
+ cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+ asc_dvc->carr_freelist = free_carrp;
+ asc_dvc->carr_pending_cnt--;
+
+ target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
+
+ /*
+ * Clear request microcode control flag.
+ */
+ scsiq->cntl = 0;
+
+ /*
+ * Notify the driver of the completed request by passing
+ * the ADV_SCSI_REQ_Q pointer to its callback function.
+ */
+ scsiq->a_flag |= ADV_SCSIQ_DONE;
+ adv_isr_callback(asc_dvc, scsiq);
+ /*
+ * Note: After the driver callback function is called, 'scsiq'
+ * can no longer be referenced.
+ *
+ * Fall through and continue processing other completed
+ * requests...
+ */
}
- if (bus_type & ASC_IS_EISA) {
- if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
- return (iop_beg);
- }
- return (0);
+ return ADV_TRUE;
+}
+
+static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
+{
+ if (asc_dvc->err_code == 0) {
+ asc_dvc->err_code = err_code;
+ AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
+ err_code);
}
- return (0);
+ return err_code;
}
-static PortAddr __init AscSearchIOPortAddr11(PortAddr s_addr)
+static void AscAckInterrupt(PortAddr iop_base)
{
- int i;
- PortAddr iop_base;
+ uchar host_flag;
+ uchar risc_flag;
+ ushort loop;
- for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
- if (_asc_def_iop_base[i] > s_addr) {
+ loop = 0;
+ do {
+ risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
+ if (loop++ > 0x7FFF) {
break;
}
- }
- for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
- iop_base = _asc_def_iop_base[i];
- if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
- ASC_DBG1(1,
- "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
- iop_base);
- continue;
- }
- ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n",
- iop_base);
- release_region(iop_base, ASC_IOADR_GAP);
- if (AscFindSignature(iop_base)) {
- return (iop_base);
+ } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
+ host_flag =
+ AscReadLramByte(iop_base,
+ ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
+ AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+ (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
+ AscSetChipStatus(iop_base, CIW_INT_ACK);
+ loop = 0;
+ while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
+ AscSetChipStatus(iop_base, CIW_INT_ACK);
+ if (loop++ > 3) {
+ break;
}
}
- return (0);
+ AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
}
-static void __init AscSetISAPNPWaitForKey(void)
+static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
{
- outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
- outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
- return;
+ const uchar *period_table;
+ int max_index;
+ int min_index;
+ int i;
+
+ period_table = asc_dvc->sdtr_period_tbl;
+ max_index = (int)asc_dvc->max_sdtr_index;
+ min_index = (int)asc_dvc->min_sdtr_index;
+ if ((syn_time <= period_table[max_index])) {
+ for (i = min_index; i < (max_index - 1); i++) {
+ if (syn_time <= period_table[i]) {
+ return (uchar)i;
+ }
+ }
+ return (uchar)max_index;
+ } else {
+ return (uchar)(max_index + 1);
+ }
}
-#endif /* CONFIG_ISA */
-static void __init AscToggleIRQAct(PortAddr iop_base)
+static uchar
+AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
{
- AscSetChipStatus(iop_base, CIW_IRQ_ACT);
- AscSetChipStatus(iop_base, 0);
- return;
+ EXT_MSG sdtr_buf;
+ uchar sdtr_period_index;
+ PortAddr iop_base;
+
+ iop_base = asc_dvc->iop_base;
+ sdtr_buf.msg_type = EXTENDED_MESSAGE;
+ sdtr_buf.msg_len = MS_SDTR_LEN;
+ sdtr_buf.msg_req = EXTENDED_SDTR;
+ sdtr_buf.xfer_period = sdtr_period;
+ sdtr_offset &= ASC_SYN_MAX_OFFSET;
+ sdtr_buf.req_ack_offset = sdtr_offset;
+ sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+ if (sdtr_period_index <= asc_dvc->max_sdtr_index) {
+ AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG,
+ (uchar *)&sdtr_buf,
+ sizeof(EXT_MSG) >> 1);
+ return ((sdtr_period_index << 4) | sdtr_offset);
+ } else {
+ sdtr_buf.req_ack_offset = 0;
+ AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG,
+ (uchar *)&sdtr_buf,
+ sizeof(EXT_MSG) >> 1);
+ return 0;
+ }
}
-static uchar __init AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
+static uchar
+AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
{
- ushort cfg_lsw;
- uchar chip_irq;
+ uchar byte;
+ uchar sdtr_period_ix;
- if ((bus_type & ASC_IS_EISA) != 0) {
- cfg_lsw = AscGetEisaChipCfg(iop_base);
- chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
- if ((chip_irq == 13) || (chip_irq > 15)) {
- return (0);
- }
- return (chip_irq);
- }
- if ((bus_type & ASC_IS_VL) != 0) {
- cfg_lsw = AscGetChipCfgLsw(iop_base);
- chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
- if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
- return (0);
- }
- return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
- }
- cfg_lsw = AscGetChipCfgLsw(iop_base);
- chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
- if (chip_irq == 3)
- chip_irq += (uchar)2;
- return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
+ sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+ if (sdtr_period_ix > asc_dvc->max_sdtr_index)
+ return 0xFF;
+ byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
+ return byte;
}
-static uchar __init
-AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
+static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
{
- ushort cfg_lsw;
+ ASC_SCSI_BIT_ID_TYPE org_id;
+ int i;
+ int sta = TRUE;
- if ((bus_type & ASC_IS_VL) != 0) {
- if (irq_no != 0) {
- if ((irq_no < ASC_MIN_IRQ_NO)
- || (irq_no > ASC_MAX_IRQ_NO)) {
- irq_no = 0;
- } else {
- irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
- }
+ AscSetBank(iop_base, 1);
+ org_id = AscReadChipDvcID(iop_base);
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ if (org_id == (0x01 << i))
+ break;
+ }
+ org_id = (ASC_SCSI_BIT_ID_TYPE) i;
+ AscWriteChipDvcID(iop_base, id);
+ if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
+ AscSetBank(iop_base, 0);
+ AscSetChipSyn(iop_base, sdtr_data);
+ if (AscGetChipSyn(iop_base) != sdtr_data) {
+ sta = FALSE;
}
- cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
- cfg_lsw |= (ushort)0x0010;
- AscSetChipCfgLsw(iop_base, cfg_lsw);
- AscToggleIRQAct(iop_base);
- cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
- cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
- AscSetChipCfgLsw(iop_base, cfg_lsw);
- AscToggleIRQAct(iop_base);
- return (AscGetChipIRQ(iop_base, bus_type));
- }
- if ((bus_type & (ASC_IS_ISA)) != 0) {
- if (irq_no == 15)
- irq_no -= (uchar)2;
- irq_no -= (uchar)ASC_MIN_IRQ_NO;
- cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
- cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
- AscSetChipCfgLsw(iop_base, cfg_lsw);
- return (AscGetChipIRQ(iop_base, bus_type));
+ } else {
+ sta = FALSE;
}
- return (0);
+ AscSetBank(iop_base, 1);
+ AscWriteChipDvcID(iop_base, org_id);
+ AscSetBank(iop_base, 0);
+ return (sta);
}
-#ifdef CONFIG_ISA
-static void __init AscEnableIsaDma(uchar dma_channel)
+static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
{
- if (dma_channel < 4) {
- outp(0x000B, (ushort)(0xC0 | dma_channel));
- outp(0x000A, dma_channel);
- } else if (dma_channel < 8) {
- outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
- outp(0x00D4, (ushort)(dma_channel - 4));
- }
- return;
+ AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+ AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
}
-#endif /* CONFIG_ISA */
static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
{
@@ -8528,9 +8597,9 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
uchar cur_dvc_qng;
uchar asyn_sdtr;
uchar scsi_status;
- asc_board_t *boardp;
+ struct asc_board *boardp;
- ASC_ASSERT(asc_dvc->drv_ptr != NULL);
+ BUG_ON(!asc_dvc->drv_ptr);
boardp = asc_dvc->drv_ptr;
iop_base = asc_dvc->iop_base;
@@ -8541,8 +8610,7 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
target_ix = AscReadLramByte(iop_base,
(ushort)(halt_q_addr +
(ushort)ASC_SCSIQ_B_TARGET_IX));
- q_cntl =
- AscReadLramByte(iop_base,
+ q_cntl = AscReadLramByte(iop_base,
(ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
tid_no = ASC_TIX_TO_TID(target_ix);
target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
@@ -8566,14 +8634,13 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
return (0);
} else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
-
AscMemWordCopyPtrFromLram(iop_base,
ASCV_MSGIN_BEG,
(uchar *)&ext_msg,
sizeof(EXT_MSG) >> 1);
- if (ext_msg.msg_type == MS_EXTEND &&
- ext_msg.msg_req == MS_SDTR_CODE &&
+ if (ext_msg.msg_type == EXTENDED_MESSAGE &&
+ ext_msg.msg_req == EXTENDED_SDTR &&
ext_msg.msg_len == MS_SDTR_LEN) {
sdtr_accept = TRUE;
if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
@@ -8582,15 +8649,14 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
}
if ((ext_msg.xfer_period <
- asc_dvc->sdtr_period_tbl[asc_dvc->
- host_init_sdtr_index])
+ asc_dvc->sdtr_period_tbl[asc_dvc->min_sdtr_index])
|| (ext_msg.xfer_period >
asc_dvc->sdtr_period_tbl[asc_dvc->
max_sdtr_index])) {
sdtr_accept = FALSE;
ext_msg.xfer_period =
asc_dvc->sdtr_period_tbl[asc_dvc->
- host_init_sdtr_index];
+ min_sdtr_index];
}
if (sdtr_accept) {
sdtr_data =
@@ -8614,7 +8680,6 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
} else {
if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
-
q_cntl &= ~QC_MSG_OUT;
asc_dvc->sdtr_done |= target_id;
asc_dvc->init_sdtr |= target_id;
@@ -8629,7 +8694,6 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
tid_no);
boardp->sdtr_data[tid_no] = sdtr_data;
} else {
-
q_cntl |= QC_MSG_OUT;
AscMsgOutSDTR(asc_dvc,
ext_msg.xfer_period,
@@ -8655,8 +8719,8 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
q_cntl);
AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
return (0);
- } else if (ext_msg.msg_type == MS_EXTEND &&
- ext_msg.msg_req == MS_WDTR_CODE &&
+ } else if (ext_msg.msg_type == EXTENDED_MESSAGE &&
+ ext_msg.msg_req == EXTENDED_WDTR &&
ext_msg.msg_len == MS_WDTR_LEN) {
ext_msg.wdtr_width = 0;
@@ -8749,9 +8813,9 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
(uchar *)&out_msg,
sizeof(EXT_MSG) >> 1);
- if ((out_msg.msg_type == MS_EXTEND) &&
+ if ((out_msg.msg_type == EXTENDED_MESSAGE) &&
(out_msg.msg_len == MS_SDTR_LEN) &&
- (out_msg.msg_req == MS_SDTR_CODE)) {
+ (out_msg.msg_req == EXTENDED_SDTR)) {
asc_dvc->init_sdtr &= ~target_id;
asc_dvc->sdtr_done &= ~target_id;
@@ -8797,9 +8861,9 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
cur_dvc_qng);
/*
- * Set the device queue depth to the number of
- * active requests when the QUEUE FULL condition
- * was encountered.
+ * Set the device queue depth to the
+ * number of active requests when the
+ * QUEUE FULL condition was encountered.
*/
boardp->queue_full |= target_id;
boardp->queue_full_cnt[tid_no] =
@@ -8825,9 +8889,8 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
int i;
q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
- if (q_no == ASC_QLINK_END) {
- return (0);
- }
+ if (q_no == ASC_QLINK_END)
+ return 0;
q_addr = ASC_QNO_TO_QADDR(q_no);
@@ -8879,8 +8942,8 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
sg_entry_cnt = ASC_MAX_SG_LIST - 1;
/*
- * Keep track of remaining number of SG elements that will
- * need to be handled on the next interrupt.
+ * Keep track of remaining number of SG elements that
+ * will need to be handled on the next interrupt.
*/
scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
} else {
@@ -8971,6 +9034,34 @@ static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
return (0);
}
+/*
+ * void
+ * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
+ *
+ * Calling/Exit State:
+ * none
+ *
+ * Description:
+ * Input an ASC_QDONE_INFO structure from the chip
+ */
+static void
+DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
+{
+ int i;
+ ushort word;
+
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < 2 * words; i += 2) {
+ if (i == 10) {
+ continue;
+ }
+ word = inpw(iop_base + IOP_RAM_DATA);
+ inbuf[i] = word & 0xff;
+ inbuf[i + 1] = (word >> 8) & 0xff;
+ }
+ ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
+}
+
static uchar
_AscCopyLramScsiDoneQ(PortAddr iop_base,
ushort q_addr,
@@ -9014,7 +9105,124 @@ _AscCopyLramScsiDoneQ(PortAddr iop_base,
ASC_SCSIQ_DW_REMAIN_XFER_CNT));
scsiq->remain_bytes &= max_dma_count;
- return (sg_queue_cnt);
+ return sg_queue_cnt;
+}
+
+/*
+ * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
+ *
+ * Interrupt callback function for the Narrow SCSI Asc Library.
+ */
+static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
+{
+ struct asc_board *boardp;
+ struct scsi_cmnd *scp;
+ struct Scsi_Host *shost;
+
+ ASC_DBG(1, "asc_dvc_varp 0x%p, qdonep 0x%p\n", asc_dvc_varp, qdonep);
+ ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
+
+ scp = advansys_srb_to_ptr(asc_dvc_varp, qdonep->d2.srb_ptr);
+ if (!scp)
+ return;
+
+ ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+
+ shost = scp->device->host;
+ ASC_STATS(shost, callback);
+ ASC_DBG(1, "shost 0x%p\n", shost);
+
+ boardp = shost_priv(shost);
+ BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var);
+
+ dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
+ sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+ /*
+ * 'qdonep' contains the command's ending status.
+ */
+ switch (qdonep->d3.done_stat) {
+ case QD_NO_ERROR:
+ ASC_DBG(2, "QD_NO_ERROR\n");
+ scp->result = 0;
+
+ /*
+ * Check for an underrun condition.
+ *
+ * If there was no error and an underrun condition, then
+ * return the number of underrun bytes.
+ */
+ if (scsi_bufflen(scp) != 0 && qdonep->remain_bytes != 0 &&
+ qdonep->remain_bytes <= scsi_bufflen(scp)) {
+ ASC_DBG(1, "underrun condition %u bytes\n",
+ (unsigned)qdonep->remain_bytes);
+ scsi_set_resid(scp, qdonep->remain_bytes);
+ }
+ break;
+
+ case QD_WITH_ERROR:
+ ASC_DBG(2, "QD_WITH_ERROR\n");
+ switch (qdonep->d3.host_stat) {
+ case QHSTA_NO_ERROR:
+ if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
+ ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n");
+ ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+ sizeof(scp->sense_buffer));
+ /*
+ * Note: The 'status_byte()' macro used by
+ * target drivers defined in scsi.h shifts the
+ * status byte returned by host drivers right
+ * by 1 bit. This is why target drivers also
+ * use right shifted status byte definitions.
+ * For instance target drivers use
+ * CHECK_CONDITION, defined to 0x1, instead of
+ * the SCSI defined check condition value of
+ * 0x2. Host drivers are supposed to return
+ * the status byte as it is defined by SCSI.
+ */
+ scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+ STATUS_BYTE(qdonep->d3.scsi_stat);
+ } else {
+ scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
+ }
+ break;
+
+ default:
+ /* QHSTA error occurred */
+ ASC_DBG(1, "host_stat 0x%x\n", qdonep->d3.host_stat);
+ scp->result = HOST_BYTE(DID_BAD_TARGET);
+ break;
+ }
+ break;
+
+ case QD_ABORTED_BY_HOST:
+ ASC_DBG(1, "QD_ABORTED_BY_HOST\n");
+ scp->result =
+ HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
+ scsi_msg) |
+ STATUS_BYTE(qdonep->d3.scsi_stat);
+ break;
+
+ default:
+ ASC_DBG(1, "done_stat 0x%x\n", qdonep->d3.done_stat);
+ scp->result =
+ HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
+ scsi_msg) |
+ STATUS_BYTE(qdonep->d3.scsi_stat);
+ break;
+ }
+
+ /*
+ * If the 'init_tidmask' bit isn't already set for the target and the
+ * current request finished normally, then set the bit for the target
+ * to indicate that a device is present.
+ */
+ if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
+ qdonep->d3.done_stat == QD_NO_ERROR &&
+ qdonep->d3.host_stat == QHSTA_NO_ERROR) {
+ boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+ }
+
+ asc_scsi_done(scp);
}
static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
@@ -9035,10 +9243,8 @@ static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
ASC_QDONE_INFO scsiq_buf;
ASC_QDONE_INFO *scsiq;
int false_overrun;
- ASC_ISR_CALLBACK asc_isr_callback;
iop_base = asc_dvc->iop_base;
- asc_isr_callback = asc_dvc->isr_callback;
n_q_used = 1;
scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
@@ -9141,7 +9347,7 @@ static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
AscSetChipControl(iop_base,
(uchar)(CC_SCSI_RESET
| CC_HALT));
- DvcDelayNanoSecond(asc_dvc, 60000);
+ udelay(60);
AscSetChipControl(iop_base, CC_HALT);
AscSetChipStatus(iop_base,
CIW_CLR_SCSI_RESET_INT);
@@ -9150,7 +9356,7 @@ static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
}
}
if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
- (*asc_isr_callback) (asc_dvc, scsiq);
+ asc_isr_callback(asc_dvc, scsiq);
} else {
if ((AscReadLramByte(iop_base,
(ushort)(q_addr + (ushort)
@@ -9168,7 +9374,7 @@ static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
FATAL_ERR_QDONE:
if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
- (*asc_isr_callback) (asc_dvc, scsiq);
+ asc_isr_callback(asc_dvc, scsiq);
}
return (0x80);
}
@@ -9190,22 +9396,19 @@ static int AscISR(ASC_DVC_VAR *asc_dvc)
iop_base = asc_dvc->iop_base;
int_pending = FALSE;
- if (AscIsIntPending(iop_base) == 0) {
+ if (AscIsIntPending(iop_base) == 0)
return int_pending;
- }
- if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
- || (asc_dvc->isr_callback == 0)
- ) {
- return (ERR);
+ if ((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) {
+ return ERR;
}
if (asc_dvc->in_critical_cnt != 0) {
AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
- return (ERR);
+ return ERR;
}
if (asc_dvc->is_in_int) {
AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
- return (ERR);
+ return ERR;
}
asc_dvc->is_in_int = TRUE;
ctrl_reg = AscGetChipControl(iop_base);
@@ -9220,7 +9423,7 @@ static int AscISR(ASC_DVC_VAR *asc_dvc)
saved_ctrl_reg &= (uchar)(~CC_HALT);
while ((AscGetChipStatus(iop_base) &
CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
- DvcSleepMilliSecond(100);
+ mdelay(100);
}
AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
AscSetChipControl(iop_base, CC_HALT);
@@ -9235,9 +9438,7 @@ static int AscISR(ASC_DVC_VAR *asc_dvc)
(uchar)(~ASC_HOST_FLAG_IN_ISR);
AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
(uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
- if ((chipstat & CSW_INT_PENDING)
- || (int_pending)
- ) {
+ if ((chipstat & CSW_INT_PENDING) || (int_pending)) {
AscAckInterrupt(iop_base);
int_pending = TRUE;
if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
@@ -9268,615 +9469,767 @@ static int AscISR(ASC_DVC_VAR *asc_dvc)
AscSetChipLramAddr(iop_base, saved_ram_addr);
AscSetChipControl(iop_base, saved_ctrl_reg);
asc_dvc->is_in_int = FALSE;
- return (int_pending);
+ return int_pending;
}
-/* Microcode buffer is kept after initialization for error recovery. */
-static uchar _asc_mcode_buf[] = {
- 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0xFF, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
- 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
- 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
- 0x03, 0x23, 0x36, 0x40,
- 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
- 0xC2, 0x00, 0x92, 0x80,
- 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
- 0xB6, 0x00, 0x92, 0x80,
- 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
- 0x92, 0x80, 0x80, 0x62,
- 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
- 0xCD, 0x04, 0x4D, 0x00,
- 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
- 0xE6, 0x84, 0xD2, 0xC1,
- 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
- 0xC6, 0x81, 0xC2, 0x88,
- 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
- 0x84, 0x97, 0x07, 0xA6,
- 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
- 0xC2, 0x88, 0xCE, 0x00,
- 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
- 0x80, 0x63, 0x07, 0xA6,
- 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
- 0x34, 0x01, 0x00, 0x33,
- 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
- 0x68, 0x98, 0x4D, 0x04,
- 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
- 0xF8, 0x88, 0xFB, 0x23,
- 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
- 0x00, 0x33, 0x0A, 0x00,
- 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
- 0xC2, 0x88, 0xCD, 0x04,
- 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
- 0x06, 0xAB, 0x82, 0x01,
- 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
- 0x3C, 0x01, 0x00, 0x05,
- 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
- 0x15, 0x23, 0xA1, 0x01,
- 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
- 0x06, 0x61, 0x00, 0xA0,
- 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
- 0xC2, 0x88, 0x06, 0x23,
- 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
- 0x57, 0x60, 0x00, 0xA0,
- 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
- 0x4B, 0x00, 0x06, 0x61,
- 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
- 0x4F, 0x00, 0x84, 0x97,
- 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
- 0x48, 0x04, 0x84, 0x80,
- 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
- 0x81, 0x73, 0x06, 0x29,
- 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
- 0x04, 0x98, 0xF0, 0x80,
- 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
- 0x34, 0x02, 0x03, 0xA6,
- 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
- 0x46, 0x82, 0xFE, 0x95,
- 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
- 0x07, 0xA6, 0x5A, 0x02,
- 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
- 0x48, 0x82, 0x60, 0x96,
- 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
- 0x04, 0x01, 0x0C, 0xDC,
- 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
- 0x6F, 0x00, 0xA5, 0x01,
- 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
- 0x02, 0xA6, 0xAA, 0x02,
- 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
- 0x01, 0xA6, 0xB4, 0x02,
- 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
- 0x80, 0x63, 0x00, 0x43,
- 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
- 0x04, 0x61, 0x84, 0x01,
- 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
- 0x00, 0x00, 0xEA, 0x82,
- 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
- 0x00, 0x33, 0x1F, 0x00,
- 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
- 0xB6, 0x2D, 0x01, 0xA6,
- 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
- 0x10, 0x03, 0x03, 0xA6,
- 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
- 0x7C, 0x95, 0xEE, 0x82,
- 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
- 0x04, 0x01, 0x2D, 0xC8,
- 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
- 0x05, 0x05, 0x86, 0x98,
- 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
- 0x3C, 0x04, 0x06, 0xA6,
- 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
- 0x7C, 0x95, 0x32, 0x83,
- 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
- 0xEB, 0x04, 0x00, 0x33,
- 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
- 0xFF, 0xA2, 0x7A, 0x03,
- 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
- 0x00, 0xA2, 0x9A, 0x03,
- 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
- 0x01, 0xA6, 0x96, 0x03,
- 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
- 0xA4, 0x03, 0x00, 0xA6,
- 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
- 0x07, 0xA6, 0xB2, 0x03,
- 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
- 0xA8, 0x98, 0x80, 0x42,
- 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
- 0xC0, 0x83, 0x00, 0x33,
- 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
- 0xA0, 0x01, 0x12, 0x23,
- 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
- 0x80, 0x67, 0x05, 0x23,
- 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
- 0x06, 0xA6, 0x0A, 0x04,
- 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
- 0xF4, 0x83, 0x20, 0x84,
- 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
- 0x83, 0x03, 0x80, 0x63,
- 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
- 0x38, 0x04, 0x00, 0x33,
- 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
- 0x1D, 0x01, 0x06, 0xCC,
- 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
- 0xA2, 0x0D, 0x80, 0x63,
- 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
- 0x80, 0x63, 0xA3, 0x01,
- 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
- 0x76, 0x04, 0xE0, 0x00,
- 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
- 0x00, 0x33, 0x1E, 0x00,
- 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
- 0x08, 0x23, 0x22, 0xA3,
- 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
- 0xC4, 0x04, 0x42, 0x23,
- 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
- 0xF8, 0x88, 0x04, 0x98,
- 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
- 0x81, 0x62, 0xE8, 0x81,
- 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
- 0x00, 0x33, 0x00, 0x81,
- 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
- 0xF8, 0x88, 0x04, 0x23,
- 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
- 0xF4, 0x04, 0x00, 0x33,
- 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
- 0x04, 0x23, 0xA0, 0x01,
- 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
- 0x00, 0xA3, 0x22, 0x05,
- 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
- 0x46, 0x97, 0xCD, 0x04,
- 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
- 0x82, 0x01, 0x34, 0x85,
- 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
- 0x1D, 0x01, 0x04, 0xD6,
- 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
- 0x49, 0x00, 0x81, 0x01,
- 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
- 0x49, 0x04, 0x80, 0x01,
- 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
- 0x01, 0x23, 0xEA, 0x00,
- 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
- 0x07, 0xA4, 0xF8, 0x05,
- 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
- 0xC2, 0x88, 0x04, 0xA0,
- 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
- 0x00, 0xA2, 0xA4, 0x05,
- 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
- 0x62, 0x97, 0x04, 0x85,
- 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
- 0xF4, 0x85, 0x03, 0xA0,
- 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
- 0xCC, 0x86, 0x07, 0xA0,
- 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
- 0x80, 0x67, 0x80, 0x63,
- 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
- 0xF8, 0x88, 0x07, 0x23,
- 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
- 0x00, 0x63, 0x4A, 0x00,
- 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
- 0x07, 0x41, 0x83, 0x03,
- 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
- 0x1D, 0x01, 0x01, 0xD6,
- 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
- 0x07, 0xA6, 0x7C, 0x05,
- 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
- 0x52, 0x00, 0x06, 0x61,
- 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
- 0x00, 0x63, 0x1D, 0x01,
- 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
- 0x07, 0x41, 0x00, 0x63,
- 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
- 0xDF, 0x00, 0x06, 0xA6,
- 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
- 0x00, 0x40, 0xC0, 0x20,
- 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
- 0x06, 0xA6, 0x94, 0x06,
- 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
- 0x40, 0x0E, 0x80, 0x63,
- 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
- 0x80, 0x63, 0x00, 0x43,
- 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
- 0x80, 0x67, 0x40, 0x0E,
- 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
- 0x07, 0xA6, 0xD6, 0x06,
- 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
- 0x0A, 0x2B, 0x07, 0xA6,
- 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
- 0xF4, 0x06, 0xC0, 0x0E,
- 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
- 0x81, 0x62, 0x04, 0x01,
- 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
- 0x8C, 0x06, 0x00, 0x33,
- 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
- 0x80, 0x63, 0x06, 0xA6,
- 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
- 0x00, 0x00, 0x80, 0x67,
- 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
- 0xBF, 0x23, 0x04, 0x61,
- 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
- 0x00, 0x01, 0xF2, 0x00,
- 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
- 0x80, 0x05, 0x81, 0x05,
- 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
- 0x70, 0x00, 0x81, 0x01,
- 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
- 0x70, 0x00, 0x80, 0x01,
- 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
- 0xF1, 0x00, 0x70, 0x00,
- 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
- 0x71, 0x04, 0x70, 0x00,
- 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
- 0xA3, 0x01, 0xA2, 0x01,
- 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
- 0xC4, 0x07, 0x00, 0x33,
- 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
- 0x48, 0x00, 0xB0, 0x01,
- 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
- 0x00, 0xA2, 0xE4, 0x07,
- 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
- 0x05, 0x05, 0x00, 0x63,
- 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
- 0x76, 0x08, 0x80, 0x02,
- 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
- 0x00, 0x02, 0x00, 0xA0,
- 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
- 0x00, 0x63, 0xF3, 0x04,
- 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
- 0x00, 0xA2, 0x44, 0x08,
- 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
- 0x24, 0x08, 0x04, 0x98,
- 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
- 0x5A, 0x88, 0x02, 0x01,
- 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
- 0x00, 0xA3, 0x64, 0x08,
- 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
- 0x06, 0xA6, 0x76, 0x08,
- 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
- 0x00, 0x63, 0x38, 0x2B,
- 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
- 0x05, 0x05, 0xB2, 0x09,
- 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
- 0x80, 0x32, 0x80, 0x36,
- 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
- 0x40, 0x36, 0x40, 0x3A,
- 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
- 0x5D, 0x00, 0xFE, 0xC3,
- 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
- 0xFF, 0xFD, 0x80, 0x73,
- 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
- 0xA1, 0x23, 0xA1, 0x01,
- 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
- 0x80, 0x00, 0x03, 0xC2,
- 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
- 0xA0, 0x01, 0xE6, 0x84,
-};
+/*
+ * advansys_reset()
+ *
+ * Reset the bus associated with the command 'scp'.
+ *
+ * This function runs its own thread. Interrupts must be blocked but
+ * sleeping is allowed and no locking other than for host structures is
+ * required. Returns SUCCESS or FAILED.
+ */
+static int advansys_reset(struct scsi_cmnd *scp)
+{
+ struct Scsi_Host *shost = scp->device->host;
+ struct asc_board *boardp = shost_priv(shost);
+ unsigned long flags;
+ int status;
+ int ret = SUCCESS;
-static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
-static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
+ ASC_DBG(1, "0x%p\n", scp);
-#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
-static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
- INQUIRY,
- REQUEST_SENSE,
- READ_CAPACITY,
- READ_TOC,
- MODE_SELECT,
- MODE_SENSE,
- MODE_SELECT_10,
- MODE_SENSE_10,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF,
- 0xFF
-};
+ ASC_STATS(shost, reset);
-static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
-{
- PortAddr iop_base;
- ulong last_int_level;
- int sta;
- int n_q_required;
- int disable_syn_offset_one_fix;
- int i;
- ASC_PADDR addr;
- ASC_EXE_CALLBACK asc_exe_callback;
- ushort sg_entry_cnt = 0;
- ushort sg_entry_cnt_minus_one = 0;
- uchar target_ix;
- uchar tid_no;
- uchar sdtr_data;
- uchar extra_bytes;
- uchar scsi_cmd;
- uchar disable_cmd;
- ASC_SG_HEAD *sg_head;
- ASC_DCNT data_cnt;
+ scmd_printk(KERN_INFO, scp, "SCSI bus reset started...\n");
- iop_base = asc_dvc->iop_base;
- sg_head = scsiq->sg_head;
- asc_exe_callback = asc_dvc->exe_callback;
- if (asc_dvc->err_code != 0)
- return (ERR);
- if (scsiq == (ASC_SCSI_Q *)0L) {
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
- return (ERR);
- }
- scsiq->q1.q_no = 0;
- if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
- scsiq->q1.extra_bytes = 0;
- }
- sta = 0;
- target_ix = scsiq->q2.target_ix;
- tid_no = ASC_TIX_TO_TID(target_ix);
- n_q_required = 1;
- if (scsiq->cdbptr[0] == REQUEST_SENSE) {
- if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
- asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
- sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
- AscMsgOutSDTR(asc_dvc,
- asc_dvc->
- sdtr_period_tbl[(sdtr_data >> 4) &
- (uchar)(asc_dvc->
- max_sdtr_index -
- 1)],
- (uchar)(sdtr_data & (uchar)
- ASC_SYN_MAX_OFFSET));
- scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
+ if (ASC_NARROW_BOARD(boardp)) {
+ ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
+
+ /* Reset the chip and SCSI bus. */
+ ASC_DBG(1, "before AscInitAsc1000Driver()\n");
+ status = AscInitAsc1000Driver(asc_dvc);
+
+ /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
+ if (asc_dvc->err_code) {
+ scmd_printk(KERN_INFO, scp, "SCSI bus reset error: "
+ "0x%x\n", asc_dvc->err_code);
+ ret = FAILED;
+ } else if (status) {
+ scmd_printk(KERN_INFO, scp, "SCSI bus reset warning: "
+ "0x%x\n", status);
+ } else {
+ scmd_printk(KERN_INFO, scp, "SCSI bus reset "
+ "successful\n");
+ }
+
+ ASC_DBG(1, "after AscInitAsc1000Driver()\n");
+ spin_lock_irqsave(shost->host_lock, flags);
+ } else {
+ /*
+ * If the suggest reset bus flags are set, then reset the bus.
+ * Otherwise only reset the device.
+ */
+ ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var;
+
+ /*
+ * Reset the target's SCSI bus.
+ */
+ ASC_DBG(1, "before AdvResetChipAndSB()\n");
+ switch (AdvResetChipAndSB(adv_dvc)) {
+ case ASC_TRUE:
+ scmd_printk(KERN_INFO, scp, "SCSI bus reset "
+ "successful\n");
+ break;
+ case ASC_FALSE:
+ default:
+ scmd_printk(KERN_INFO, scp, "SCSI bus reset error\n");
+ ret = FAILED;
+ break;
}
+ spin_lock_irqsave(shost->host_lock, flags);
+ AdvISR(adv_dvc);
}
- last_int_level = DvcEnterCritical();
- if (asc_dvc->in_critical_cnt != 0) {
- DvcLeaveCritical(last_int_level);
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
- return (ERR);
+
+ /* Save the time of the most recently completed reset. */
+ boardp->last_reset = jiffies;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ ASC_DBG(1, "ret %d\n", ret);
+
+ return ret;
+}
+
+/*
+ * advansys_biosparam()
+ *
+ * Translate disk drive geometry if the "BIOS greater than 1 GB"
+ * support is enabled for a drive.
+ *
+ * ip (information pointer) is an int array with the following definition:
+ * ip[0]: heads
+ * ip[1]: sectors
+ * ip[2]: cylinders
+ */
+static int
+advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+ sector_t capacity, int ip[])
+{
+ struct asc_board *boardp = shost_priv(sdev->host);
+
+ ASC_DBG(1, "begin\n");
+ ASC_STATS(sdev->host, biosparam);
+ if (ASC_NARROW_BOARD(boardp)) {
+ if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
+ ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
+ ip[0] = 255;
+ ip[1] = 63;
+ } else {
+ ip[0] = 64;
+ ip[1] = 32;
+ }
+ } else {
+ if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
+ BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
+ ip[0] = 255;
+ ip[1] = 63;
+ } else {
+ ip[0] = 64;
+ ip[1] = 32;
+ }
}
- asc_dvc->in_critical_cnt++;
- if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
- if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
- asc_dvc->in_critical_cnt--;
- DvcLeaveCritical(last_int_level);
- return (ERR);
+ ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
+ ASC_DBG(1, "end\n");
+ return 0;
+}
+
+/*
+ * First-level interrupt handler.
+ *
+ * 'dev_id' is a pointer to the interrupting adapter's Scsi_Host.
+ */
+static irqreturn_t advansys_interrupt(int irq, void *dev_id)
+{
+ struct Scsi_Host *shost = dev_id;
+ struct asc_board *boardp = shost_priv(shost);
+ irqreturn_t result = IRQ_NONE;
+
+ ASC_DBG(2, "boardp 0x%p\n", boardp);
+ spin_lock(shost->host_lock);
+ if (ASC_NARROW_BOARD(boardp)) {
+ if (AscIsIntPending(shost->io_port)) {
+ result = IRQ_HANDLED;
+ ASC_STATS(shost, interrupt);
+ ASC_DBG(1, "before AscISR()\n");
+ AscISR(&boardp->dvc_var.asc_dvc_var);
}
-#if !CC_VERY_LONG_SG_LIST
- if (sg_entry_cnt > ASC_MAX_SG_LIST) {
- asc_dvc->in_critical_cnt--;
- DvcLeaveCritical(last_int_level);
- return (ERR);
+ } else {
+ ASC_DBG(1, "before AdvISR()\n");
+ if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
+ result = IRQ_HANDLED;
+ ASC_STATS(shost, interrupt);
}
-#endif /* !CC_VERY_LONG_SG_LIST */
- if (sg_entry_cnt == 1) {
- scsiq->q1.data_addr =
- (ADV_PADDR)sg_head->sg_list[0].addr;
- scsiq->q1.data_cnt =
- (ADV_DCNT)sg_head->sg_list[0].bytes;
- scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
+ }
+ spin_unlock(shost->host_lock);
+
+ ASC_DBG(1, "end\n");
+ return result;
+}
+
+static int AscHostReqRiscHalt(PortAddr iop_base)
+{
+ int count = 0;
+ int sta = 0;
+ uchar saved_stop_code;
+
+ if (AscIsChipHalted(iop_base))
+ return (1);
+ saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
+ AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+ ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
+ do {
+ if (AscIsChipHalted(iop_base)) {
+ sta = 1;
+ break;
}
- sg_entry_cnt_minus_one = sg_entry_cnt - 1;
+ mdelay(100);
+ } while (count++ < 20);
+ AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
+ return (sta);
+}
+
+static int
+AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
+{
+ int sta = FALSE;
+
+ if (AscHostReqRiscHalt(iop_base)) {
+ sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+ AscStartChip(iop_base);
}
- scsi_cmd = scsiq->cdbptr[0];
- disable_syn_offset_one_fix = FALSE;
- if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
- !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
- if (scsiq->q1.cntl & QC_SG_HEAD) {
- data_cnt = 0;
- for (i = 0; i < sg_entry_cnt; i++) {
- data_cnt +=
- (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
- bytes);
- }
+ return sta;
+}
+
+static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev)
+{
+ char type = sdev->type;
+ ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id;
+
+ if (!(asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN))
+ return;
+ if (asc_dvc->init_sdtr & tid_bits)
+ return;
+
+ if ((type == TYPE_ROM) && (strncmp(sdev->vendor, "HP ", 3) == 0))
+ asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
+
+ asc_dvc->pci_fix_asyn_xfer |= tid_bits;
+ if ((type == TYPE_PROCESSOR) || (type == TYPE_SCANNER) ||
+ (type == TYPE_ROM) || (type == TYPE_TAPE))
+ asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
+
+ if (asc_dvc->pci_fix_asyn_xfer & tid_bits)
+ AscSetRunChipSynRegAtID(asc_dvc->iop_base, sdev->id,
+ ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+}
+
+static void
+advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
+{
+ ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id;
+ ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng;
+
+ if (sdev->lun == 0) {
+ ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr;
+ if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) {
+ asc_dvc->init_sdtr |= tid_bit;
} else {
- data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
+ asc_dvc->init_sdtr &= ~tid_bit;
}
- if (data_cnt != 0UL) {
- if (data_cnt < 512UL) {
- disable_syn_offset_one_fix = TRUE;
- } else {
- for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
- i++) {
- disable_cmd =
- _syn_offset_one_disable_cmd[i];
- if (disable_cmd == 0xFF) {
- break;
- }
- if (scsi_cmd == disable_cmd) {
- disable_syn_offset_one_fix =
- TRUE;
- break;
- }
- }
+
+ if (orig_init_sdtr != asc_dvc->init_sdtr)
+ AscAsyncFix(asc_dvc, sdev);
+ }
+
+ if (sdev->tagged_supported) {
+ if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) {
+ if (sdev->lun == 0) {
+ asc_dvc->cfg->can_tagged_qng |= tid_bit;
+ asc_dvc->use_tagged_qng |= tid_bit;
}
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+ asc_dvc->max_dvc_qng[sdev->id]);
+ }
+ } else {
+ if (sdev->lun == 0) {
+ asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
+ asc_dvc->use_tagged_qng &= ~tid_bit;
}
+ scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
}
- if (disable_syn_offset_one_fix) {
- scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
- scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
- ASC_TAG_FLAG_DISABLE_DISCONNECT);
+
+ if ((sdev->lun == 0) &&
+ (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) {
+ AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
+ asc_dvc->cfg->disc_enable);
+ AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
+ asc_dvc->use_tagged_qng);
+ AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
+ asc_dvc->cfg->can_tagged_qng);
+
+ asc_dvc->max_dvc_qng[sdev->id] =
+ asc_dvc->cfg->max_tag_qng[sdev->id];
+ AscWriteLramByte(asc_dvc->iop_base,
+ (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id),
+ asc_dvc->max_dvc_qng[sdev->id]);
+ }
+}
+
+/*
+ * Wide Transfers
+ *
+ * If the EEPROM enabled WDTR for the device and the device supports wide
+ * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and
+ * write the new value to the microcode.
+ */
+static void
+advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask)
+{
+ unsigned short cfg_word;
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+ if ((cfg_word & tidmask) != 0)
+ return;
+
+ cfg_word |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+
+ /*
+ * Clear the microcode SDTR and WDTR negotiation done indicators for
+ * the target to cause it to negotiate with the new setting set above.
+ * WDTR when accepted causes the target to enter asynchronous mode, so
+ * SDTR must be negotiated.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+ cfg_word &= ~tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
+ cfg_word &= ~tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
+}
+
+/*
+ * Synchronous Transfers
+ *
+ * If the EEPROM enabled SDTR for the device and the device
+ * supports synchronous transfers, then turn on the device's
+ * 'sdtr_able' bit. Write the new value to the microcode.
+ */
+static void
+advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask)
+{
+ unsigned short cfg_word;
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+ if ((cfg_word & tidmask) != 0)
+ return;
+
+ cfg_word |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+
+ /*
+ * Clear the microcode "SDTR negotiation" done indicator for the
+ * target to cause it to negotiate with the new setting set above.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+ cfg_word &= ~tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+}
+
+/*
+ * PPR (Parallel Protocol Request) Capable
+ *
+ * If the device supports DT mode, then it must be PPR capable.
+ * The PPR message will be used in place of the SDTR and WDTR
+ * messages to negotiate synchronous speed and offset, transfer
+ * width, and protocol options.
+ */
+static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
+ AdvPortAddr iop_base, unsigned short tidmask)
+{
+ AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
+ adv_dvc->ppr_able |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
+}
+
+static void
+advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
+{
+ AdvPortAddr iop_base = adv_dvc->iop_base;
+ unsigned short tidmask = 1 << sdev->id;
+
+ if (sdev->lun == 0) {
+ /*
+ * Handle WDTR, SDTR, and Tag Queuing. If the feature
+ * is enabled in the EEPROM and the device supports the
+ * feature, then enable it in the microcode.
+ */
+
+ if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
+ advansys_wide_enable_wdtr(iop_base, tidmask);
+ if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
+ advansys_wide_enable_sdtr(iop_base, tidmask);
+ if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
+ advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
+
+ /*
+ * Tag Queuing is disabled for the BIOS which runs in polled
+ * mode and would see no benefit from Tag Queuing. Also by
+ * disabling Tag Queuing in the BIOS devices with Tag Queuing
+ * bugs will at least work with the BIOS.
+ */
+ if ((adv_dvc->tagqng_able & tidmask) &&
+ sdev->tagged_supported) {
+ unsigned short cfg_word;
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+ cfg_word |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+ cfg_word);
+ AdvWriteByteLram(iop_base,
+ ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
+ adv_dvc->max_dvc_qng);
+ }
+ }
+
+ if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+ adv_dvc->max_dvc_qng);
} else {
- scsiq->q2.tag_code &= 0x27;
+ scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
}
- if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
- if (asc_dvc->bug_fix_cntl) {
- if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
- if ((scsi_cmd == READ_6) ||
- (scsi_cmd == READ_10)) {
- addr =
- (ADV_PADDR)le32_to_cpu(sg_head->
- sg_list
- [sg_entry_cnt_minus_one].
- addr) +
- (ADV_DCNT)le32_to_cpu(sg_head->
- sg_list
- [sg_entry_cnt_minus_one].
- bytes);
- extra_bytes =
- (uchar)((ushort)addr & 0x0003);
- if ((extra_bytes != 0)
- &&
- ((scsiq->q2.
- tag_code &
- ASC_TAG_FLAG_EXTRA_BYTES)
- == 0)) {
- scsiq->q2.tag_code |=
- ASC_TAG_FLAG_EXTRA_BYTES;
- scsiq->q1.extra_bytes =
- extra_bytes;
- data_cnt =
- le32_to_cpu(sg_head->
- sg_list
- [sg_entry_cnt_minus_one].
- bytes);
- data_cnt -=
- (ASC_DCNT) extra_bytes;
- sg_head->
- sg_list
- [sg_entry_cnt_minus_one].
- bytes =
- cpu_to_le32(data_cnt);
- }
- }
- }
+}
+
+/*
+ * Set the number of commands to queue per device for the
+ * specified host adapter.
+ */
+static int advansys_slave_configure(struct scsi_device *sdev)
+{
+ struct asc_board *boardp = shost_priv(sdev->host);
+
+ if (ASC_NARROW_BOARD(boardp))
+ advansys_narrow_slave_configure(sdev,
+ &boardp->dvc_var.asc_dvc_var);
+ else
+ advansys_wide_slave_configure(sdev,
+ &boardp->dvc_var.adv_dvc_var);
+
+ return 0;
+}
+
+static __le32 advansys_get_sense_buffer_dma(struct scsi_cmnd *scp)
+{
+ struct asc_board *board = shost_priv(scp->device->host);
+ scp->SCp.dma_handle = dma_map_single(board->dev, scp->sense_buffer,
+ sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+ dma_cache_sync(board->dev, scp->sense_buffer,
+ sizeof(scp->sense_buffer), DMA_FROM_DEVICE);
+ return cpu_to_le32(scp->SCp.dma_handle);
+}
+
+static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
+ struct asc_scsi_q *asc_scsi_q)
+{
+ struct asc_dvc_var *asc_dvc = &boardp->dvc_var.asc_dvc_var;
+ int use_sg;
+
+ memset(asc_scsi_q, 0, sizeof(*asc_scsi_q));
+
+ /*
+ * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
+ */
+ asc_scsi_q->q2.srb_ptr = advansys_ptr_to_srb(asc_dvc, scp);
+ if (asc_scsi_q->q2.srb_ptr == BAD_SRB) {
+ scp->result = HOST_BYTE(DID_SOFT_ERROR);
+ return ASC_ERROR;
+ }
+
+ /*
+ * Build the ASC_SCSI_Q request.
+ */
+ asc_scsi_q->cdbptr = &scp->cmnd[0];
+ asc_scsi_q->q2.cdb_len = scp->cmd_len;
+ asc_scsi_q->q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
+ asc_scsi_q->q1.target_lun = scp->device->lun;
+ asc_scsi_q->q2.target_ix =
+ ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
+ asc_scsi_q->q1.sense_addr = advansys_get_sense_buffer_dma(scp);
+ asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer);
+
+ /*
+ * If there are any outstanding requests for the current target,
+ * then every 255th request send an ORDERED request. This heuristic
+ * tries to retain the benefit of request sorting while preventing
+ * request starvation. 255 is the max number of tags or pending commands
+ * a device may have outstanding.
+ *
+ * The request count is incremented below for every successfully
+ * started request.
+ *
+ */
+ if ((asc_dvc->cur_dvc_qng[scp->device->id] > 0) &&
+ (boardp->reqcnt[scp->device->id] % 255) == 0) {
+ asc_scsi_q->q2.tag_code = MSG_ORDERED_TAG;
+ } else {
+ asc_scsi_q->q2.tag_code = MSG_SIMPLE_TAG;
+ }
+
+ /* Build ASC_SCSI_Q */
+ use_sg = scsi_dma_map(scp);
+ if (use_sg != 0) {
+ int sgcnt;
+ struct scatterlist *slp;
+ struct asc_sg_head *asc_sg_head;
+
+ if (use_sg > scp->device->host->sg_tablesize) {
+ scmd_printk(KERN_ERR, scp, "use_sg %d > "
+ "sg_tablesize %d\n", use_sg,
+ scp->device->host->sg_tablesize);
+ scsi_dma_unmap(scp);
+ scp->result = HOST_BYTE(DID_ERROR);
+ return ASC_ERROR;
}
- sg_head->entry_to_copy = sg_head->entry_cnt;
-#if CC_VERY_LONG_SG_LIST
+
+ asc_sg_head = kzalloc(sizeof(asc_scsi_q->sg_head) +
+ use_sg * sizeof(struct asc_sg_list), GFP_ATOMIC);
+ if (!asc_sg_head) {
+ scsi_dma_unmap(scp);
+ scp->result = HOST_BYTE(DID_SOFT_ERROR);
+ return ASC_ERROR;
+ }
+
+ asc_scsi_q->q1.cntl |= QC_SG_HEAD;
+ asc_scsi_q->sg_head = asc_sg_head;
+ asc_scsi_q->q1.data_cnt = 0;
+ asc_scsi_q->q1.data_addr = 0;
+ /* This is a byte value, otherwise it would need to be swapped. */
+ asc_sg_head->entry_cnt = asc_scsi_q->q1.sg_queue_cnt = use_sg;
+ ASC_STATS_ADD(scp->device->host, xfer_elem,
+ asc_sg_head->entry_cnt);
+
/*
- * Set the sg_entry_cnt to the maximum possible. The rest of
- * the SG elements will be copied when the RISC completes the
- * SG elements that fit and halts.
+ * Convert scatter-gather list into ASC_SG_HEAD list.
*/
- if (sg_entry_cnt > ASC_MAX_SG_LIST) {
- sg_entry_cnt = ASC_MAX_SG_LIST;
+ scsi_for_each_sg(scp, slp, use_sg, sgcnt) {
+ asc_sg_head->sg_list[sgcnt].addr =
+ cpu_to_le32(sg_dma_address(slp));
+ asc_sg_head->sg_list[sgcnt].bytes =
+ cpu_to_le32(sg_dma_len(slp));
+ ASC_STATS_ADD(scp->device->host, xfer_sect,
+ DIV_ROUND_UP(sg_dma_len(slp), 512));
}
-#endif /* CC_VERY_LONG_SG_LIST */
- n_q_required = AscSgListToQueue(sg_entry_cnt);
- if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
- (uint) n_q_required)
- || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
- if ((sta =
- AscSendScsiQueue(asc_dvc, scsiq,
- n_q_required)) == 1) {
- asc_dvc->in_critical_cnt--;
- if (asc_exe_callback != 0) {
- (*asc_exe_callback) (asc_dvc, scsiq);
- }
- DvcLeaveCritical(last_int_level);
- return (sta);
+ }
+
+ ASC_STATS(scp->device->host, xfer_cnt);
+
+ ASC_DBG_PRT_ASC_SCSI_Q(2, asc_scsi_q);
+ ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+
+ return ASC_NOERROR;
+}
+
+/*
+ * Build scatter-gather list for Adv Library (Wide Board).
+ *
+ * Additional ADV_SG_BLOCK structures will need to be allocated
+ * if the total number of scatter-gather elements exceeds
+ * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
+ * assumed to be physically contiguous.
+ *
+ * Return:
+ * ADV_SUCCESS(1) - SG List successfully created
+ * ADV_ERROR(-1) - SG List creation failed
+ */
+static int
+adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
+ int use_sg)
+{
+ adv_sgblk_t *sgblkp;
+ ADV_SCSI_REQ_Q *scsiqp;
+ struct scatterlist *slp;
+ int sg_elem_cnt;
+ ADV_SG_BLOCK *sg_block, *prev_sg_block;
+ ADV_PADDR sg_block_paddr;
+ int i;
+
+ scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
+ slp = scsi_sglist(scp);
+ sg_elem_cnt = use_sg;
+ prev_sg_block = NULL;
+ reqp->sgblkp = NULL;
+
+ for (;;) {
+ /*
+ * Allocate a 'adv_sgblk_t' structure from the board free
+ * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
+ * (15) scatter-gather elements.
+ */
+ if ((sgblkp = boardp->adv_sgblkp) == NULL) {
+ ASC_DBG(1, "no free adv_sgblk_t\n");
+ ASC_STATS(scp->device->host, adv_build_nosg);
+
+ /*
+ * Allocation failed. Free 'adv_sgblk_t' structures
+ * already allocated for the request.
+ */
+ while ((sgblkp = reqp->sgblkp) != NULL) {
+ /* Remove 'sgblkp' from the request list. */
+ reqp->sgblkp = sgblkp->next_sgblkp;
+
+ /* Add 'sgblkp' to the board free list. */
+ sgblkp->next_sgblkp = boardp->adv_sgblkp;
+ boardp->adv_sgblkp = sgblkp;
}
+ return ASC_BUSY;
}
- } else {
- if (asc_dvc->bug_fix_cntl) {
- if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
- if ((scsi_cmd == READ_6) ||
- (scsi_cmd == READ_10)) {
- addr =
- le32_to_cpu(scsiq->q1.data_addr) +
- le32_to_cpu(scsiq->q1.data_cnt);
- extra_bytes =
- (uchar)((ushort)addr & 0x0003);
- if ((extra_bytes != 0)
- &&
- ((scsiq->q2.
- tag_code &
- ASC_TAG_FLAG_EXTRA_BYTES)
- == 0)) {
- data_cnt =
- le32_to_cpu(scsiq->q1.
- data_cnt);
- if (((ushort)data_cnt & 0x01FF)
- == 0) {
- scsiq->q2.tag_code |=
- ASC_TAG_FLAG_EXTRA_BYTES;
- data_cnt -= (ASC_DCNT)
- extra_bytes;
- scsiq->q1.data_cnt =
- cpu_to_le32
- (data_cnt);
- scsiq->q1.extra_bytes =
- extra_bytes;
- }
- }
- }
- }
+
+ /* Complete 'adv_sgblk_t' board allocation. */
+ boardp->adv_sgblkp = sgblkp->next_sgblkp;
+ sgblkp->next_sgblkp = NULL;
+
+ /*
+ * Get 8 byte aligned virtual and physical addresses
+ * for the allocated ADV_SG_BLOCK structure.
+ */
+ sg_block = (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
+ sg_block_paddr = virt_to_bus(sg_block);
+
+ /*
+ * Check if this is the first 'adv_sgblk_t' for the
+ * request.
+ */
+ if (reqp->sgblkp == NULL) {
+ /* Request's first scatter-gather block. */
+ reqp->sgblkp = sgblkp;
+
+ /*
+ * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
+ * address pointers.
+ */
+ scsiqp->sg_list_ptr = sg_block;
+ scsiqp->sg_real_addr = cpu_to_le32(sg_block_paddr);
+ } else {
+ /* Request's second or later scatter-gather block. */
+ sgblkp->next_sgblkp = reqp->sgblkp;
+ reqp->sgblkp = sgblkp;
+
+ /*
+ * Point the previous ADV_SG_BLOCK structure to
+ * the newly allocated ADV_SG_BLOCK structure.
+ */
+ prev_sg_block->sg_ptr = cpu_to_le32(sg_block_paddr);
}
- n_q_required = 1;
- if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
- ((scsiq->q1.cntl & QC_URGENT) != 0)) {
- if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
- n_q_required)) == 1) {
- asc_dvc->in_critical_cnt--;
- if (asc_exe_callback != 0) {
- (*asc_exe_callback) (asc_dvc, scsiq);
- }
- DvcLeaveCritical(last_int_level);
- return (sta);
+
+ for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
+ sg_block->sg_list[i].sg_addr =
+ cpu_to_le32(sg_dma_address(slp));
+ sg_block->sg_list[i].sg_count =
+ cpu_to_le32(sg_dma_len(slp));
+ ASC_STATS_ADD(scp->device->host, xfer_sect,
+ DIV_ROUND_UP(sg_dma_len(slp), 512));
+
+ if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
+ sg_block->sg_cnt = i + 1;
+ sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
+ return ADV_SUCCESS;
}
+ slp++;
}
+ sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
+ prev_sg_block = sg_block;
}
- asc_dvc->in_critical_cnt--;
- DvcLeaveCritical(last_int_level);
- return (sta);
}
+/*
+ * Build a request structure for the Adv Library (Wide Board).
+ *
+ * If an adv_req_t can not be allocated to issue the request,
+ * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
+ *
+ * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
+ * microcode for DMA addresses or math operations are byte swapped
+ * to little-endian order.
+ */
static int
-AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
+adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
+ ADV_SCSI_REQ_Q **adv_scsiqpp)
{
- PortAddr iop_base;
- uchar free_q_head;
- uchar next_qp;
- uchar tid_no;
- uchar target_ix;
- int sta;
+ adv_req_t *reqp;
+ ADV_SCSI_REQ_Q *scsiqp;
+ int i;
+ int ret;
+ int use_sg;
- iop_base = asc_dvc->iop_base;
- target_ix = scsiq->q2.target_ix;
- tid_no = ASC_TIX_TO_TID(target_ix);
- sta = 0;
- free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
- if (n_q_required > 1) {
- if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
- free_q_head, (uchar)
- (n_q_required)))
- != (uchar)ASC_QLINK_END) {
- asc_dvc->last_q_shortage = 0;
- scsiq->sg_head->queue_cnt = n_q_required - 1;
- scsiq->q1.q_no = free_q_head;
- if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
- free_q_head)) == 1) {
- AscPutVarFreeQHead(iop_base, next_qp);
- asc_dvc->cur_total_qng += (uchar)(n_q_required);
- asc_dvc->cur_dvc_qng[tid_no]++;
- }
- return (sta);
+ /*
+ * Allocate an adv_req_t structure from the board to execute
+ * the command.
+ */
+ if (boardp->adv_reqp == NULL) {
+ ASC_DBG(1, "no free adv_req_t\n");
+ ASC_STATS(scp->device->host, adv_build_noreq);
+ return ASC_BUSY;
+ } else {
+ reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp->next_reqp;
+ reqp->next_reqp = NULL;
+ }
+
+ /*
+ * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
+ */
+ scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
+
+ /*
+ * Initialize the structure.
+ */
+ scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
+
+ /*
+ * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
+ */
+ scsiqp->srb_ptr = ADV_VADDR_TO_U32(reqp);
+
+ /*
+ * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
+ */
+ reqp->cmndp = scp;
+
+ /*
+ * Build the ADV_SCSI_REQ_Q request.
+ */
+
+ /* Set CDB length and copy it to the request structure. */
+ scsiqp->cdb_len = scp->cmd_len;
+ /* Copy first 12 CDB bytes to cdb[]. */
+ for (i = 0; i < scp->cmd_len && i < 12; i++) {
+ scsiqp->cdb[i] = scp->cmnd[i];
+ }
+ /* Copy last 4 CDB bytes, if present, to cdb16[]. */
+ for (; i < scp->cmd_len; i++) {
+ scsiqp->cdb16[i - 12] = scp->cmnd[i];
+ }
+
+ scsiqp->target_id = scp->device->id;
+ scsiqp->target_lun = scp->device->lun;
+
+ scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
+ scsiqp->sense_len = sizeof(scp->sense_buffer);
+
+ /* Build ADV_SCSI_REQ_Q */
+
+ use_sg = scsi_dma_map(scp);
+ if (use_sg == 0) {
+ /* Zero-length transfer */
+ reqp->sgblkp = NULL;
+ scsiqp->data_cnt = 0;
+ scsiqp->vdata_addr = NULL;
+
+ scsiqp->data_addr = 0;
+ scsiqp->sg_list_ptr = NULL;
+ scsiqp->sg_real_addr = 0;
+ } else {
+ if (use_sg > ADV_MAX_SG_LIST) {
+ scmd_printk(KERN_ERR, scp, "use_sg %d > "
+ "ADV_MAX_SG_LIST %d\n", use_sg,
+ scp->device->host->sg_tablesize);
+ scsi_dma_unmap(scp);
+ scp->result = HOST_BYTE(DID_ERROR);
+
+ /*
+ * Free the 'adv_req_t' structure by adding it back
+ * to the board free list.
+ */
+ reqp->next_reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp;
+
+ return ASC_ERROR;
}
- } else if (n_q_required == 1) {
- if ((next_qp = AscAllocFreeQueue(iop_base,
- free_q_head)) !=
- ASC_QLINK_END) {
- scsiq->q1.q_no = free_q_head;
- if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
- free_q_head)) == 1) {
- AscPutVarFreeQHead(iop_base, next_qp);
- asc_dvc->cur_total_qng++;
- asc_dvc->cur_dvc_qng[tid_no]++;
- }
- return (sta);
+
+ scsiqp->data_cnt = cpu_to_le32(scsi_bufflen(scp));
+
+ ret = adv_get_sglist(boardp, reqp, scp, use_sg);
+ if (ret != ADV_SUCCESS) {
+ /*
+ * Free the adv_req_t structure by adding it back to
+ * the board free list.
+ */
+ reqp->next_reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp;
+
+ return ret;
}
+
+ ASC_STATS_ADD(scp->device->host, xfer_elem, use_sg);
}
- return (sta);
+
+ ASC_STATS(scp->device->host, xfer_cnt);
+
+ ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+ ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+
+ *adv_scsiqpp = scsiqp;
+
+ return ASC_NOERROR;
}
static int AscSgListToQueue(int sg_list)
@@ -9886,7 +10239,7 @@ static int AscSgListToQueue(int sg_list)
n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
n_sg_list_qs++;
- return (n_sg_list_qs + 1);
+ return n_sg_list_qs + 1;
}
static uint
@@ -9901,7 +10254,7 @@ AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
tid_no = ASC_TIX_TO_TID(target_ix);
if ((asc_dvc->unit_not_ready & target_id) ||
(asc_dvc->queue_full_or_busy & target_id)) {
- return (0);
+ return 0;
}
if (n_qs == 1) {
cur_used_qs = (uint) asc_dvc->cur_total_qng +
@@ -9914,9 +10267,9 @@ AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
if (asc_dvc->cur_dvc_qng[tid_no] >=
asc_dvc->max_dvc_qng[tid_no]) {
- return (0);
+ return 0;
}
- return (cur_free_qs);
+ return cur_free_qs;
}
if (n_qs > 1) {
if ((n_qs > asc_dvc->last_q_shortage)
@@ -9924,7 +10277,62 @@ AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
asc_dvc->last_q_shortage = n_qs;
}
}
- return (0);
+ return 0;
+}
+
+static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
+{
+ ushort q_addr;
+ uchar next_qp;
+ uchar q_status;
+
+ q_addr = ASC_QNO_TO_QADDR(free_q_head);
+ q_status = (uchar)AscReadLramByte(iop_base,
+ (ushort)(q_addr +
+ ASC_SCSIQ_B_STATUS));
+ next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
+ if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END))
+ return next_qp;
+ return ASC_QLINK_END;
+}
+
+static uchar
+AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
+{
+ uchar i;
+
+ for (i = 0; i < n_free_q; i++) {
+ free_q_head = AscAllocFreeQueue(iop_base, free_q_head);
+ if (free_q_head == ASC_QLINK_END)
+ break;
+ }
+ return free_q_head;
+}
+
+/*
+ * void
+ * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
+ *
+ * Calling/Exit State:
+ * none
+ *
+ * Description:
+ * Output an ASC_SCSI_Q structure to the chip
+ */
+static void
+DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
+{
+ int i;
+
+ ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
+ AscSetChipLramAddr(iop_base, s_addr);
+ for (i = 0; i < 2 * words; i += 2) {
+ if (i == 4 || i == 20) {
+ continue;
+ }
+ outpw(iop_base + IOP_RAM_DATA,
+ ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
+ }
}
static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
@@ -9966,7 +10374,7 @@ static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
(ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
(ushort)(((ushort)scsiq->q1.
q_no << 8) | (ushort)QS_READY));
- return (1);
+ return 1;
}
static int
@@ -10104,491 +10512,651 @@ AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
}
static int
-AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
+AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
{
- int sta = FALSE;
+ PortAddr iop_base;
+ uchar free_q_head;
+ uchar next_qp;
+ uchar tid_no;
+ uchar target_ix;
+ int sta;
- if (AscHostReqRiscHalt(iop_base)) {
- sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
- AscStartChip(iop_base);
- return (sta);
+ iop_base = asc_dvc->iop_base;
+ target_ix = scsiq->q2.target_ix;
+ tid_no = ASC_TIX_TO_TID(target_ix);
+ sta = 0;
+ free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
+ if (n_q_required > 1) {
+ next_qp = AscAllocMultipleFreeQueue(iop_base, free_q_head,
+ (uchar)n_q_required);
+ if (next_qp != ASC_QLINK_END) {
+ asc_dvc->last_q_shortage = 0;
+ scsiq->sg_head->queue_cnt = n_q_required - 1;
+ scsiq->q1.q_no = free_q_head;
+ sta = AscPutReadySgListQueue(asc_dvc, scsiq,
+ free_q_head);
+ }
+ } else if (n_q_required == 1) {
+ next_qp = AscAllocFreeQueue(iop_base, free_q_head);
+ if (next_qp != ASC_QLINK_END) {
+ scsiq->q1.q_no = free_q_head;
+ sta = AscPutReadyQueue(asc_dvc, scsiq, free_q_head);
+ }
}
- return (sta);
+ if (sta == 1) {
+ AscPutVarFreeQHead(iop_base, next_qp);
+ asc_dvc->cur_total_qng += n_q_required;
+ asc_dvc->cur_dvc_qng[tid_no]++;
+ }
+ return sta;
}
-static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
+#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
+static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
+ INQUIRY,
+ REQUEST_SENSE,
+ READ_CAPACITY,
+ READ_TOC,
+ MODE_SELECT,
+ MODE_SENSE,
+ MODE_SELECT_10,
+ MODE_SENSE_10,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF
+};
+
+static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
{
- ASC_SCSI_BIT_ID_TYPE org_id;
+ PortAddr iop_base;
+ int sta;
+ int n_q_required;
+ int disable_syn_offset_one_fix;
int i;
- int sta = TRUE;
+ ASC_PADDR addr;
+ ushort sg_entry_cnt = 0;
+ ushort sg_entry_cnt_minus_one = 0;
+ uchar target_ix;
+ uchar tid_no;
+ uchar sdtr_data;
+ uchar extra_bytes;
+ uchar scsi_cmd;
+ uchar disable_cmd;
+ ASC_SG_HEAD *sg_head;
+ ASC_DCNT data_cnt;
- AscSetBank(iop_base, 1);
- org_id = AscReadChipDvcID(iop_base);
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if (org_id == (0x01 << i))
- break;
+ iop_base = asc_dvc->iop_base;
+ sg_head = scsiq->sg_head;
+ if (asc_dvc->err_code != 0)
+ return (ERR);
+ scsiq->q1.q_no = 0;
+ if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
+ scsiq->q1.extra_bytes = 0;
}
- org_id = (ASC_SCSI_BIT_ID_TYPE) i;
- AscWriteChipDvcID(iop_base, id);
- if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
- AscSetBank(iop_base, 0);
- AscSetChipSyn(iop_base, sdtr_data);
- if (AscGetChipSyn(iop_base) != sdtr_data) {
- sta = FALSE;
+ sta = 0;
+ target_ix = scsiq->q2.target_ix;
+ tid_no = ASC_TIX_TO_TID(target_ix);
+ n_q_required = 1;
+ if (scsiq->cdbptr[0] == REQUEST_SENSE) {
+ if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
+ asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
+ sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+ AscMsgOutSDTR(asc_dvc,
+ asc_dvc->
+ sdtr_period_tbl[(sdtr_data >> 4) &
+ (uchar)(asc_dvc->
+ max_sdtr_index -
+ 1)],
+ (uchar)(sdtr_data & (uchar)
+ ASC_SYN_MAX_OFFSET));
+ scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
}
+ }
+ if (asc_dvc->in_critical_cnt != 0) {
+ AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
+ return (ERR);
+ }
+ asc_dvc->in_critical_cnt++;
+ if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+ if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
+ asc_dvc->in_critical_cnt--;
+ return (ERR);
+ }
+#if !CC_VERY_LONG_SG_LIST
+ if (sg_entry_cnt > ASC_MAX_SG_LIST) {
+ asc_dvc->in_critical_cnt--;
+ return (ERR);
+ }
+#endif /* !CC_VERY_LONG_SG_LIST */
+ if (sg_entry_cnt == 1) {
+ scsiq->q1.data_addr =
+ (ADV_PADDR)sg_head->sg_list[0].addr;
+ scsiq->q1.data_cnt =
+ (ADV_DCNT)sg_head->sg_list[0].bytes;
+ scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
+ }
+ sg_entry_cnt_minus_one = sg_entry_cnt - 1;
+ }
+ scsi_cmd = scsiq->cdbptr[0];
+ disable_syn_offset_one_fix = FALSE;
+ if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
+ !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
+ if (scsiq->q1.cntl & QC_SG_HEAD) {
+ data_cnt = 0;
+ for (i = 0; i < sg_entry_cnt; i++) {
+ data_cnt +=
+ (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
+ bytes);
+ }
+ } else {
+ data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
+ }
+ if (data_cnt != 0UL) {
+ if (data_cnt < 512UL) {
+ disable_syn_offset_one_fix = TRUE;
+ } else {
+ for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
+ i++) {
+ disable_cmd =
+ _syn_offset_one_disable_cmd[i];
+ if (disable_cmd == 0xFF) {
+ break;
+ }
+ if (scsi_cmd == disable_cmd) {
+ disable_syn_offset_one_fix =
+ TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (disable_syn_offset_one_fix) {
+ scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
+ scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
+ ASC_TAG_FLAG_DISABLE_DISCONNECT);
} else {
- sta = FALSE;
+ scsiq->q2.tag_code &= 0x27;
}
- AscSetBank(iop_base, 1);
- AscWriteChipDvcID(iop_base, org_id);
- AscSetBank(iop_base, 0);
+ if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+ if (asc_dvc->bug_fix_cntl) {
+ if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+ if ((scsi_cmd == READ_6) ||
+ (scsi_cmd == READ_10)) {
+ addr =
+ (ADV_PADDR)le32_to_cpu(sg_head->
+ sg_list
+ [sg_entry_cnt_minus_one].
+ addr) +
+ (ADV_DCNT)le32_to_cpu(sg_head->
+ sg_list
+ [sg_entry_cnt_minus_one].
+ bytes);
+ extra_bytes =
+ (uchar)((ushort)addr & 0x0003);
+ if ((extra_bytes != 0)
+ &&
+ ((scsiq->q2.
+ tag_code &
+ ASC_TAG_FLAG_EXTRA_BYTES)
+ == 0)) {
+ scsiq->q2.tag_code |=
+ ASC_TAG_FLAG_EXTRA_BYTES;
+ scsiq->q1.extra_bytes =
+ extra_bytes;
+ data_cnt =
+ le32_to_cpu(sg_head->
+ sg_list
+ [sg_entry_cnt_minus_one].
+ bytes);
+ data_cnt -=
+ (ASC_DCNT) extra_bytes;
+ sg_head->
+ sg_list
+ [sg_entry_cnt_minus_one].
+ bytes =
+ cpu_to_le32(data_cnt);
+ }
+ }
+ }
+ }
+ sg_head->entry_to_copy = sg_head->entry_cnt;
+#if CC_VERY_LONG_SG_LIST
+ /*
+ * Set the sg_entry_cnt to the maximum possible. The rest of
+ * the SG elements will be copied when the RISC completes the
+ * SG elements that fit and halts.
+ */
+ if (sg_entry_cnt > ASC_MAX_SG_LIST) {
+ sg_entry_cnt = ASC_MAX_SG_LIST;
+ }
+#endif /* CC_VERY_LONG_SG_LIST */
+ n_q_required = AscSgListToQueue(sg_entry_cnt);
+ if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
+ (uint) n_q_required)
+ || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+ if ((sta =
+ AscSendScsiQueue(asc_dvc, scsiq,
+ n_q_required)) == 1) {
+ asc_dvc->in_critical_cnt--;
+ return (sta);
+ }
+ }
+ } else {
+ if (asc_dvc->bug_fix_cntl) {
+ if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+ if ((scsi_cmd == READ_6) ||
+ (scsi_cmd == READ_10)) {
+ addr =
+ le32_to_cpu(scsiq->q1.data_addr) +
+ le32_to_cpu(scsiq->q1.data_cnt);
+ extra_bytes =
+ (uchar)((ushort)addr & 0x0003);
+ if ((extra_bytes != 0)
+ &&
+ ((scsiq->q2.
+ tag_code &
+ ASC_TAG_FLAG_EXTRA_BYTES)
+ == 0)) {
+ data_cnt =
+ le32_to_cpu(scsiq->q1.
+ data_cnt);
+ if (((ushort)data_cnt & 0x01FF)
+ == 0) {
+ scsiq->q2.tag_code |=
+ ASC_TAG_FLAG_EXTRA_BYTES;
+ data_cnt -= (ASC_DCNT)
+ extra_bytes;
+ scsiq->q1.data_cnt =
+ cpu_to_le32
+ (data_cnt);
+ scsiq->q1.extra_bytes =
+ extra_bytes;
+ }
+ }
+ }
+ }
+ }
+ n_q_required = 1;
+ if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
+ ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+ if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
+ n_q_required)) == 1) {
+ asc_dvc->in_critical_cnt--;
+ return (sta);
+ }
+ }
+ }
+ asc_dvc->in_critical_cnt--;
return (sta);
}
-static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
+/*
+ * AdvExeScsiQueue() - Send a request to the RISC microcode program.
+ *
+ * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
+ * add the carrier to the ICQ (Initiator Command Queue), and tickle the
+ * RISC to notify it a new command is ready to be executed.
+ *
+ * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
+ * set to SCSI_MAX_RETRY.
+ *
+ * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
+ * for DMA addresses or math operations are byte swapped to little-endian
+ * order.
+ *
+ * Return:
+ * ADV_SUCCESS(1) - The request was successfully queued.
+ * ADV_BUSY(0) - Resource unavailable; Retry again after pending
+ * request completes.
+ * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
+ * host IC error.
+ */
+static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
{
- uchar i;
- ushort s_addr;
- PortAddr iop_base;
- ushort warn_code;
+ AdvPortAddr iop_base;
+ ADV_PADDR req_paddr;
+ ADV_CARR_T *new_carrp;
- iop_base = asc_dvc->iop_base;
- warn_code = 0;
- AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
- (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
- 64) >> 1)
- );
- i = ASC_MIN_ACTIVE_QNO;
- s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
- (uchar)(i + 1));
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
- (uchar)(asc_dvc->max_total_qng));
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
- (uchar)i);
- i++;
- s_addr += ASC_QBLK_SIZE;
- for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
- (uchar)(i + 1));
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
- (uchar)(i - 1));
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
- (uchar)i);
- }
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
- (uchar)ASC_QLINK_END);
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
- (uchar)(asc_dvc->max_total_qng - 1));
- AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
- (uchar)asc_dvc->max_total_qng);
- i++;
- s_addr += ASC_QBLK_SIZE;
- for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
- i++, s_addr += ASC_QBLK_SIZE) {
- AscWriteLramByte(iop_base,
- (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
- AscWriteLramByte(iop_base,
- (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
- AscWriteLramByte(iop_base,
- (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
+ /*
+ * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
+ */
+ if (scsiq->target_id > ADV_MAX_TID) {
+ scsiq->host_status = QHSTA_M_INVALID_DEVICE;
+ scsiq->done_status = QD_WITH_ERROR;
+ return ADV_ERROR;
}
- return (warn_code);
-}
-
-static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
-{
- PortAddr iop_base;
- int i;
- ushort lram_addr;
iop_base = asc_dvc->iop_base;
- AscPutRiscVarFreeQHead(iop_base, 1);
- AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
- AscPutVarFreeQHead(iop_base, 1);
- AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
- AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
- (uchar)((int)asc_dvc->max_total_qng + 1));
- AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
- (uchar)((int)asc_dvc->max_total_qng + 2));
- AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
- asc_dvc->max_total_qng);
- AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
- AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
- AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
- AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
- AscPutQDoneInProgress(iop_base, 0);
- lram_addr = ASC_QADR_BEG;
- for (i = 0; i < 32; i++, lram_addr += 2) {
- AscWriteLramWord(iop_base, lram_addr, 0);
- }
- return (0);
-}
-static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
-{
- if (asc_dvc->err_code == 0) {
- asc_dvc->err_code = err_code;
- AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
- err_code);
+ /*
+ * Allocate a carrier ensuring at least one carrier always
+ * remains on the freelist and initialize fields.
+ */
+ if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
+ return ADV_BUSY;
}
- return (err_code);
-}
+ asc_dvc->carr_freelist = (ADV_CARR_T *)
+ ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
+ asc_dvc->carr_pending_cnt++;
-static uchar
-AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
-{
- EXT_MSG sdtr_buf;
- uchar sdtr_period_index;
- PortAddr iop_base;
+ /*
+ * Set the carrier to be a stopper by setting 'next_vpa'
+ * to the stopper value. The current stopper will be changed
+ * below to point to the new stopper.
+ */
+ new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
- iop_base = asc_dvc->iop_base;
- sdtr_buf.msg_type = MS_EXTEND;
- sdtr_buf.msg_len = MS_SDTR_LEN;
- sdtr_buf.msg_req = MS_SDTR_CODE;
- sdtr_buf.xfer_period = sdtr_period;
- sdtr_offset &= ASC_SYN_MAX_OFFSET;
- sdtr_buf.req_ack_offset = sdtr_offset;
- if ((sdtr_period_index =
- AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
- asc_dvc->max_sdtr_index) {
- AscMemWordCopyPtrToLram(iop_base,
- ASCV_MSGOUT_BEG,
- (uchar *)&sdtr_buf,
- sizeof(EXT_MSG) >> 1);
- return ((sdtr_period_index << 4) | sdtr_offset);
- } else {
+ /*
+ * Clear the ADV_SCSI_REQ_Q done flag.
+ */
+ scsiq->a_flag &= ~ADV_SCSIQ_DONE;
- sdtr_buf.req_ack_offset = 0;
- AscMemWordCopyPtrToLram(iop_base,
- ASCV_MSGOUT_BEG,
- (uchar *)&sdtr_buf,
- sizeof(EXT_MSG) >> 1);
- return (0);
- }
-}
+ req_paddr = virt_to_bus(scsiq);
+ BUG_ON(req_paddr & 31);
+ /* Wait for assertion before making little-endian */
+ req_paddr = cpu_to_le32(req_paddr);
-static uchar
-AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
-{
- uchar byte;
- uchar sdtr_period_ix;
+ /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
+ scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
+ scsiq->scsiq_rptr = req_paddr;
- sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
- if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
- ) {
- return (0xFF);
- }
- byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
- return (byte);
-}
+ scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
+ /*
+ * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
+ * order during initialization.
+ */
+ scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
-static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
-{
- AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
- AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
- return;
-}
+ /*
+ * Use the current stopper to send the ADV_SCSI_REQ_Q command to
+ * the microcode. The newly allocated stopper will become the new
+ * stopper.
+ */
+ asc_dvc->icq_sp->areq_vpa = req_paddr;
-static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
-{
- uchar *period_table;
- int max_index;
- int min_index;
- int i;
+ /*
+ * Set the 'next_vpa' pointer for the old stopper to be the
+ * physical address of the new stopper. The RISC can only
+ * follow physical addresses.
+ */
+ asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
- period_table = asc_dvc->sdtr_period_tbl;
- max_index = (int)asc_dvc->max_sdtr_index;
- min_index = (int)asc_dvc->host_init_sdtr_index;
- if ((syn_time <= period_table[max_index])) {
- for (i = min_index; i < (max_index - 1); i++) {
- if (syn_time <= period_table[i]) {
- return ((uchar)i);
- }
+ /*
+ * Set the host adapter stopper pointer to point to the new carrier.
+ */
+ asc_dvc->icq_sp = new_carrp;
+
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+ asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ /*
+ * Tickle the RISC to tell it to read its Command Queue Head pointer.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+ /*
+ * Clear the tickle value. In the ASC-3550 the RISC flag
+ * command 'clr_tickle_a' does not work unless the host
+ * value is cleared.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_TICKLE,
+ ADV_TICKLE_NOP);
}
- return ((uchar)max_index);
- } else {
- return ((uchar)(max_index + 1));
+ } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ /*
+ * Notify the RISC a carrier is ready by writing the physical
+ * address of the new carrier stopper to the COMMA register.
+ */
+ AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+ le32_to_cpu(new_carrp->carr_pa));
}
+
+ return ADV_SUCCESS;
}
-static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
+/*
+ * Execute a single 'Scsi_Cmnd'.
+ */
+static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
{
- ushort q_addr;
- uchar next_qp;
- uchar q_status;
+ int ret, err_code;
+ struct asc_board *boardp = shost_priv(scp->device->host);
- q_addr = ASC_QNO_TO_QADDR(free_q_head);
- q_status = (uchar)AscReadLramByte(iop_base,
- (ushort)(q_addr +
- ASC_SCSIQ_B_STATUS));
- next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
- if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
- return (next_qp);
- }
- return (ASC_QLINK_END);
-}
+ ASC_DBG(1, "scp 0x%p\n", scp);
-static uchar
-AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
-{
- uchar i;
+ if (ASC_NARROW_BOARD(boardp)) {
+ ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var;
+ struct asc_scsi_q asc_scsi_q;
- for (i = 0; i < n_free_q; i++) {
- if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
- == ASC_QLINK_END) {
- return (ASC_QLINK_END);
+ /* asc_build_req() can not return ASC_BUSY. */
+ ret = asc_build_req(boardp, scp, &asc_scsi_q);
+ if (ret == ASC_ERROR) {
+ ASC_STATS(scp->device->host, build_error);
+ return ASC_ERROR;
}
- }
- return (free_q_head);
-}
-static int AscHostReqRiscHalt(PortAddr iop_base)
-{
- int count = 0;
- int sta = 0;
- uchar saved_stop_code;
+ ret = AscExeScsiQueue(asc_dvc, &asc_scsi_q);
+ kfree(asc_scsi_q.sg_head);
+ err_code = asc_dvc->err_code;
+ } else {
+ ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var;
+ ADV_SCSI_REQ_Q *adv_scsiqp;
- if (AscIsChipHalted(iop_base))
- return (1);
- saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
- AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
- ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
- do {
- if (AscIsChipHalted(iop_base)) {
- sta = 1;
+ switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
+ case ASC_NOERROR:
+ ASC_DBG(3, "adv_build_req ASC_NOERROR\n");
break;
+ case ASC_BUSY:
+ ASC_DBG(1, "adv_build_req ASC_BUSY\n");
+ /*
+ * The asc_stats fields 'adv_build_noreq' and
+ * 'adv_build_nosg' count wide board busy conditions.
+ * They are updated in adv_build_req and
+ * adv_get_sglist, respectively.
+ */
+ return ASC_BUSY;
+ case ASC_ERROR:
+ default:
+ ASC_DBG(1, "adv_build_req ASC_ERROR\n");
+ ASC_STATS(scp->device->host, build_error);
+ return ASC_ERROR;
}
- DvcSleepMilliSecond(100);
- } while (count++ < 20);
- AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
- return (sta);
-}
-static int AscStopQueueExe(PortAddr iop_base)
-{
- int count = 0;
+ ret = AdvExeScsiQueue(adv_dvc, adv_scsiqp);
+ err_code = adv_dvc->err_code;
+ }
- if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
- AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
- ASC_STOP_REQ_RISC_STOP);
- do {
- if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
- ASC_STOP_ACK_RISC_STOP) {
- return (1);
- }
- DvcSleepMilliSecond(100);
- } while (count++ < 20);
+ switch (ret) {
+ case ASC_NOERROR:
+ ASC_STATS(scp->device->host, exe_noerror);
+ /*
+ * Increment monotonically increasing per device
+ * successful request counter. Wrapping doesn't matter.
+ */
+ boardp->reqcnt[scp->device->id]++;
+ ASC_DBG(1, "ExeScsiQueue() ASC_NOERROR\n");
+ break;
+ case ASC_BUSY:
+ ASC_STATS(scp->device->host, exe_busy);
+ break;
+ case ASC_ERROR:
+ scmd_printk(KERN_ERR, scp, "ExeScsiQueue() ASC_ERROR, "
+ "err_code 0x%x\n", err_code);
+ ASC_STATS(scp->device->host, exe_error);
+ scp->result = HOST_BYTE(DID_ERROR);
+ break;
+ default:
+ scmd_printk(KERN_ERR, scp, "ExeScsiQueue() unknown, "
+ "err_code 0x%x\n", err_code);
+ ASC_STATS(scp->device->host, exe_unknown);
+ scp->result = HOST_BYTE(DID_ERROR);
+ break;
}
- return (0);
-}
-static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
-{
- udelay(micro_sec);
+ ASC_DBG(1, "end\n");
+ return ret;
}
-static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
+/*
+ * advansys_queuecommand() - interrupt-driven I/O entrypoint.
+ *
+ * This function always returns 0. Command return status is saved
+ * in the 'scp' result field.
+ */
+static int
+advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
{
- udelay((nano_sec + 999) / 1000);
-}
+ struct Scsi_Host *shost = scp->device->host;
+ int asc_res, result = 0;
-#ifdef CONFIG_ISA
-static ASC_DCNT __init AscGetEisaProductID(PortAddr iop_base)
-{
- PortAddr eisa_iop;
- ushort product_id_high, product_id_low;
- ASC_DCNT product_id;
-
- eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
- product_id_low = inpw(eisa_iop);
- product_id_high = inpw(eisa_iop + 2);
- product_id = ((ASC_DCNT) product_id_high << 16) |
- (ASC_DCNT) product_id_low;
- return (product_id);
-}
+ ASC_STATS(shost, queuecommand);
+ scp->scsi_done = done;
-static PortAddr __init AscSearchIOPortAddrEISA(PortAddr iop_base)
-{
- ASC_DCNT eisa_product_id;
+ asc_res = asc_execute_scsi_cmnd(scp);
- if (iop_base == 0) {
- iop_base = ASC_EISA_MIN_IOP_ADDR;
- } else {
- if (iop_base == ASC_EISA_MAX_IOP_ADDR)
- return (0);
- if ((iop_base & 0x0050) == 0x0050) {
- iop_base += ASC_EISA_BIG_IOP_GAP;
- } else {
- iop_base += ASC_EISA_SMALL_IOP_GAP;
- }
- }
- while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
- eisa_product_id = AscGetEisaProductID(iop_base);
- if ((eisa_product_id == ASC_EISA_ID_740) ||
- (eisa_product_id == ASC_EISA_ID_750)) {
- if (AscFindSignature(iop_base)) {
- inpw(iop_base + 4);
- return (iop_base);
- }
- }
- if (iop_base == ASC_EISA_MAX_IOP_ADDR)
- return (0);
- if ((iop_base & 0x0050) == 0x0050) {
- iop_base += ASC_EISA_BIG_IOP_GAP;
- } else {
- iop_base += ASC_EISA_SMALL_IOP_GAP;
- }
+ switch (asc_res) {
+ case ASC_NOERROR:
+ break;
+ case ASC_BUSY:
+ result = SCSI_MLQUEUE_HOST_BUSY;
+ break;
+ case ASC_ERROR:
+ default:
+ asc_scsi_done(scp);
+ break;
}
- return (0);
+
+ return result;
}
-#endif /* CONFIG_ISA */
-static int AscStartChip(PortAddr iop_base)
+static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
{
- AscSetChipControl(iop_base, 0);
- if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
- return (0);
- }
- return (1);
+ PortAddr eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+ (PortAddr) (ASC_EISA_CFG_IOP_MASK);
+ return inpw(eisa_cfg_iop);
}
-static int AscStopChip(PortAddr iop_base)
+/*
+ * Return the BIOS address of the adapter at the specified
+ * I/O port and with the specified bus type.
+ */
+static unsigned short __devinit
+AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
{
- uchar cc_val;
+ unsigned short cfg_lsw;
+ unsigned short bios_addr;
- cc_val =
- AscGetChipControl(iop_base) &
- (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
- AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
- AscSetChipIH(iop_base, INS_HALT);
- AscSetChipIH(iop_base, INS_RFLAG_WTM);
- if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
- return (0);
- }
- return (1);
-}
+ /*
+ * The PCI BIOS is re-located by the motherboard BIOS. Because
+ * of this the driver can not determine where a PCI BIOS is
+ * loaded and executes.
+ */
+ if (bus_type & ASC_IS_PCI)
+ return 0;
-static int AscIsChipHalted(PortAddr iop_base)
-{
- if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
- if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
- return (1);
- }
+ if ((bus_type & ASC_IS_EISA) != 0) {
+ cfg_lsw = AscGetEisaChipCfg(iop_base);
+ cfg_lsw &= 0x000F;
+ bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE;
+ return bios_addr;
}
- return (0);
-}
-static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
-{
- AscSetBank(iop_base, 1);
- AscWriteChipIH(iop_base, ins_code);
- AscSetBank(iop_base, 0);
- return;
+ cfg_lsw = AscGetChipCfgLsw(iop_base);
+
+ /*
+ * ISA PnP uses the top bit as the 32K BIOS flag
+ */
+ if (bus_type == ASC_IS_ISAPNP)
+ cfg_lsw &= 0x7FFF;
+ bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE;
+ return bios_addr;
}
-static void AscAckInterrupt(PortAddr iop_base)
+static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
{
- uchar host_flag;
- uchar risc_flag;
- ushort loop;
+ ushort cfg_lsw;
- loop = 0;
- do {
- risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
- if (loop++ > 0x7FFF) {
- break;
- }
- } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
- host_flag =
- AscReadLramByte(iop_base,
- ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
- AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
- (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
- AscSetChipStatus(iop_base, CIW_INT_ACK);
- loop = 0;
- while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
- AscSetChipStatus(iop_base, CIW_INT_ACK);
- if (loop++ > 3) {
- break;
- }
+ if (AscGetChipScsiID(iop_base) == new_host_id) {
+ return (new_host_id);
}
- AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
- return;
+ cfg_lsw = AscGetChipCfgLsw(iop_base);
+ cfg_lsw &= 0xF8FF;
+ cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
+ AscSetChipCfgLsw(iop_base, cfg_lsw);
+ return (AscGetChipScsiID(iop_base));
}
-static void AscDisableInterrupt(PortAddr iop_base)
+static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
{
- ushort cfg;
+ unsigned char sc;
- cfg = AscGetChipCfgLsw(iop_base);
- AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
- return;
+ AscSetBank(iop_base, 1);
+ sc = inp(iop_base + IOP_REG_SC);
+ AscSetBank(iop_base, 0);
+ return sc;
}
-static void AscEnableInterrupt(PortAddr iop_base)
+static unsigned char __devinit
+AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
{
- ushort cfg;
-
- cfg = AscGetChipCfgLsw(iop_base);
- AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
- return;
+ if (bus_type & ASC_IS_EISA) {
+ PortAddr eisa_iop;
+ unsigned char revision;
+ eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+ (PortAddr) ASC_EISA_REV_IOP_MASK;
+ revision = inp(eisa_iop);
+ return ASC_CHIP_MIN_VER_EISA - 1 + revision;
+ }
+ return AscGetChipVerNo(iop_base);
}
-static void AscSetBank(PortAddr iop_base, uchar bank)
+#ifdef CONFIG_ISA
+static void __devinit AscEnableIsaDma(uchar dma_channel)
{
- uchar val;
-
- val = AscGetChipControl(iop_base) &
- (~
- (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
- CC_CHIP_RESET));
- if (bank == 1) {
- val |= CC_BANK_ONE;
- } else if (bank == 2) {
- val |= CC_DIAG | CC_BANK_ONE;
- } else {
- val &= ~CC_BANK_ONE;
+ if (dma_channel < 4) {
+ outp(0x000B, (ushort)(0xC0 | dma_channel));
+ outp(0x000A, dma_channel);
+ } else if (dma_channel < 8) {
+ outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
+ outp(0x00D4, (ushort)(dma_channel - 4));
}
- AscSetChipControl(iop_base, val);
- return;
}
+#endif /* CONFIG_ISA */
-static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
+static int AscStopQueueExe(PortAddr iop_base)
{
- PortAddr iop_base;
- int i = 10;
+ int count = 0;
- iop_base = asc_dvc->iop_base;
- while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
- && (i-- > 0)) {
- DvcSleepMilliSecond(100);
+ if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
+ AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+ ASC_STOP_REQ_RISC_STOP);
+ do {
+ if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
+ ASC_STOP_ACK_RISC_STOP) {
+ return (1);
+ }
+ mdelay(100);
+ } while (count++ < 20);
}
- AscStopChip(iop_base);
- AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
- DvcDelayNanoSecond(asc_dvc, 60000);
- AscSetChipIH(iop_base, INS_RFLAG_WTM);
- AscSetChipIH(iop_base, INS_HALT);
- AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
- AscSetChipControl(iop_base, CC_HALT);
- DvcSleepMilliSecond(200);
- AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
- AscSetChipStatus(iop_base, 0);
- return (AscIsChipHalted(iop_base));
+ return (0);
}
-static ASC_DCNT __init AscGetMaxDmaCount(ushort bus_type)
+static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
{
if (bus_type & ASC_IS_ISA)
- return (ASC_MAX_ISA_DMA_COUNT);
+ return ASC_MAX_ISA_DMA_COUNT;
else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
- return (ASC_MAX_VL_DMA_COUNT);
- return (ASC_MAX_PCI_DMA_COUNT);
+ return ASC_MAX_VL_DMA_COUNT;
+ return ASC_MAX_PCI_DMA_COUNT;
}
#ifdef CONFIG_ISA
-static ushort __init AscGetIsaDmaChannel(PortAddr iop_base)
+static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
{
ushort channel;
@@ -10600,7 +11168,7 @@ static ushort __init AscGetIsaDmaChannel(PortAddr iop_base)
return (channel + 4);
}
-static ushort __init AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
+static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
{
ushort cfg_lsw;
uchar value;
@@ -10615,19 +11183,10 @@ static ushort __init AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
AscSetChipCfgLsw(iop_base, cfg_lsw);
return (AscGetIsaDmaChannel(iop_base));
}
- return (0);
-}
-
-static uchar __init AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
-{
- speed_value &= 0x07;
- AscSetBank(iop_base, 1);
- AscWriteChipDmaSpeed(iop_base, speed_value);
- AscSetBank(iop_base, 0);
- return (AscGetIsaDmaSpeed(iop_base));
+ return 0;
}
-static uchar __init AscGetIsaDmaSpeed(PortAddr iop_base)
+static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
{
uchar speed_value;
@@ -10635,223 +11194,20 @@ static uchar __init AscGetIsaDmaSpeed(PortAddr iop_base)
speed_value = AscReadChipDmaSpeed(iop_base);
speed_value &= 0x07;
AscSetBank(iop_base, 0);
- return (speed_value);
+ return speed_value;
}
-#endif /* CONFIG_ISA */
-static ushort __init
-AscReadPCIConfigWord(ASC_DVC_VAR *asc_dvc, ushort pci_config_offset)
+static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
{
- uchar lsb, msb;
-
- lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset);
- msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1);
- return ((ushort)((msb << 8) | lsb));
-}
-
-static ushort __init AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
-{
- ushort warn_code;
- PortAddr iop_base;
- ushort PCIDeviceID;
- ushort PCIVendorID;
- uchar PCIRevisionID;
- uchar prevCmdRegBits;
-
- warn_code = 0;
- iop_base = asc_dvc->iop_base;
- asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
- if (asc_dvc->err_code != 0) {
- return (UW_ERR);
- }
- if (asc_dvc->bus_type == ASC_IS_PCI) {
- PCIVendorID = AscReadPCIConfigWord(asc_dvc,
- AscPCIConfigVendorIDRegister);
-
- PCIDeviceID = AscReadPCIConfigWord(asc_dvc,
- AscPCIConfigDeviceIDRegister);
-
- PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigRevisionIDRegister);
-
- if (PCIVendorID != PCI_VENDOR_ID_ASP) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister);
-
- if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) !=
- AscPCICmdRegBits_IOMemBusMaster) {
- DvcWritePCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister,
- (prevCmdRegBits |
- AscPCICmdRegBits_IOMemBusMaster));
-
- if ((DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister)
- & AscPCICmdRegBits_IOMemBusMaster)
- != AscPCICmdRegBits_IOMemBusMaster) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- }
- if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
- (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
- DvcWritePCIConfigByte(asc_dvc,
- AscPCIConfigLatencyTimer, 0x00);
- if (DvcReadPCIConfigByte
- (asc_dvc, AscPCIConfigLatencyTimer)
- != 0x00) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
- if (DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigLatencyTimer) <
- 0x20) {
- DvcWritePCIConfigByte(asc_dvc,
- AscPCIConfigLatencyTimer,
- 0x20);
-
- if (DvcReadPCIConfigByte(asc_dvc,
- AscPCIConfigLatencyTimer)
- < 0x20) {
- warn_code |=
- ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- }
- }
- }
-
- if (AscFindSignature(iop_base)) {
- warn_code |= AscInitAscDvcVar(asc_dvc);
- warn_code |= AscInitFromEEP(asc_dvc);
- asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
- if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
- asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
- }
- } else {
- asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
- }
- return (warn_code);
-}
-
-static ushort __init AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
-{
- ushort warn_code = 0;
-
- asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
- if (asc_dvc->err_code != 0)
- return (UW_ERR);
- if (AscFindSignature(asc_dvc->iop_base)) {
- warn_code |= AscInitFromAscDvcVar(asc_dvc);
- asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
- } else {
- asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
- }
- return (warn_code);
+ speed_value &= 0x07;
+ AscSetBank(iop_base, 1);
+ AscWriteChipDmaSpeed(iop_base, speed_value);
+ AscSetBank(iop_base, 0);
+ return AscGetIsaDmaSpeed(iop_base);
}
-
-static ushort __init AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
-{
- PortAddr iop_base;
- ushort cfg_msw;
- ushort warn_code;
- ushort pci_device_id = 0;
-
- iop_base = asc_dvc->iop_base;
-#ifdef CONFIG_PCI
- if (asc_dvc->cfg->dev)
- pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device;
-#endif
- warn_code = 0;
- cfg_msw = AscGetChipCfgMsw(iop_base);
- if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
- cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
- warn_code |= ASC_WARN_CFG_MSW_RECOVER;
- AscSetChipCfgMsw(iop_base, cfg_msw);
- }
- if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
- asc_dvc->cfg->cmd_qng_enabled) {
- asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
- warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
- }
- if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
- warn_code |= ASC_WARN_AUTO_CONFIG;
- }
- if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
- if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
- != asc_dvc->irq_no) {
- asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
- }
- }
- if (asc_dvc->bus_type & ASC_IS_PCI) {
- cfg_msw &= 0xFFC0;
- AscSetChipCfgMsw(iop_base, cfg_msw);
- if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
- } else {
- if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
- (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
- asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
- asc_dvc->bug_fix_cntl |=
- ASC_BUG_FIX_ASYN_USE_SYN;
- }
- }
- } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
- if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
- == ASC_CHIP_VER_ASYN_BUG) {
- asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
- }
- }
- if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
- asc_dvc->cfg->chip_scsi_id) {
- asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
- }
-#ifdef CONFIG_ISA
- if (asc_dvc->bus_type & ASC_IS_ISA) {
- AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
- AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
- }
#endif /* CONFIG_ISA */
- return (warn_code);
-}
-
-static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
-{
- ushort warn_code;
- PortAddr iop_base;
-
- iop_base = asc_dvc->iop_base;
- warn_code = 0;
- if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
- !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
- AscResetChipAndScsiBus(asc_dvc);
- DvcSleepMilliSecond((ASC_DCNT)
- ((ushort)asc_dvc->scsi_reset_wait * 1000));
- }
- asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
- if (asc_dvc->err_code != 0)
- return (UW_ERR);
- if (!AscFindSignature(asc_dvc->iop_base)) {
- asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
- return (warn_code);
- }
- AscDisableInterrupt(iop_base);
- warn_code |= AscInitLram(asc_dvc);
- if (asc_dvc->err_code != 0)
- return (UW_ERR);
- ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
- (ulong)_asc_mcode_chksum);
- if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
- _asc_mcode_size) != _asc_mcode_chksum) {
- asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
- return (warn_code);
- }
- warn_code |= AscInitMicroCodeVar(asc_dvc);
- asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
- AscEnableInterrupt(iop_base);
- return (warn_code);
-}
-static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
+static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
{
int i;
PortAddr iop_base;
@@ -10882,7 +11238,7 @@ static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
asc_dvc->queue_full_or_busy = 0;
asc_dvc->redo_scam = 0;
asc_dvc->res2 = 0;
- asc_dvc->host_init_sdtr_index = 0;
+ asc_dvc->min_sdtr_index = 0;
asc_dvc->cfg->can_tagged_qng = 0;
asc_dvc->cfg->cmd_qng_enabled = 0;
asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
@@ -10894,39 +11250,14 @@ static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
- asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
- asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
- ASC_LIB_VERSION_MINOR;
chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
asc_dvc->cfg->chip_version = chip_version;
- asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
- asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
- asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
- asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
- asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
- asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
- asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
- asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
+ asc_dvc->sdtr_period_tbl = asc_syn_xfer_period;
asc_dvc->max_sdtr_index = 7;
if ((asc_dvc->bus_type & ASC_IS_PCI) &&
(chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
- asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
- asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
- asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
- asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
- asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
- asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
- asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
- asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
- asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
- asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
- asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
- asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
- asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
- asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
- asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
- asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
+ asc_dvc->sdtr_period_tbl = asc_syn_ultra_xfer_period;
asc_dvc->max_sdtr_index = 15;
if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
AscSetExtraControl(iop_base,
@@ -10943,12 +11274,12 @@ static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
}
asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
- if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
- AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
- asc_dvc->bus_type = ASC_IS_ISAPNP;
- }
#ifdef CONFIG_ISA
if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
+ if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) {
+ AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
+ asc_dvc->bus_type = ASC_IS_ISAPNP;
+ }
asc_dvc->cfg->isa_dma_channel =
(uchar)AscGetIsaDmaChannel(iop_base);
}
@@ -10960,231 +11291,92 @@ static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
}
- return (warn_code);
+ return warn_code;
}
-static ushort __init AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
+static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
{
- ASCEEP_CONFIG eep_config_buf;
- ASCEEP_CONFIG *eep_config;
- PortAddr iop_base;
- ushort chksum;
- ushort warn_code;
- ushort cfg_msw, cfg_lsw;
- int i;
- int write_eep = 0;
-
- iop_base = asc_dvc->iop_base;
- warn_code = 0;
- AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
- AscStopQueueExe(iop_base);
- if ((AscStopChip(iop_base) == FALSE) ||
- (AscGetChipScsiCtrl(iop_base) != 0)) {
- asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
- AscResetChipAndScsiBus(asc_dvc);
- DvcSleepMilliSecond((ASC_DCNT)
- ((ushort)asc_dvc->scsi_reset_wait * 1000));
- }
- if (AscIsChipHalted(iop_base) == FALSE) {
- asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
- return (warn_code);
- }
- AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
- if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
- asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
- return (warn_code);
- }
- eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
- cfg_msw = AscGetChipCfgMsw(iop_base);
- cfg_lsw = AscGetChipCfgLsw(iop_base);
- if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
- cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
- warn_code |= ASC_WARN_CFG_MSW_RECOVER;
- AscSetChipCfgMsw(iop_base, cfg_msw);
- }
- chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
- ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
- if (chksum == 0) {
- chksum = 0xaa55;
- }
- if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
- warn_code |= ASC_WARN_AUTO_CONFIG;
- if (asc_dvc->cfg->chip_version == 3) {
- if (eep_config->cfg_lsw != cfg_lsw) {
- warn_code |= ASC_WARN_EEPROM_RECOVER;
- eep_config->cfg_lsw =
- AscGetChipCfgLsw(iop_base);
- }
- if (eep_config->cfg_msw != cfg_msw) {
- warn_code |= ASC_WARN_EEPROM_RECOVER;
- eep_config->cfg_msw =
- AscGetChipCfgMsw(iop_base);
- }
- }
- }
- eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
- eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
- ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
- eep_config->chksum);
- if (chksum != eep_config->chksum) {
- if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
- ASC_CHIP_VER_PCI_ULTRA_3050) {
- ASC_DBG(1,
- "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
- eep_config->init_sdtr = 0xFF;
- eep_config->disc_enable = 0xFF;
- eep_config->start_motor = 0xFF;
- eep_config->use_cmd_qng = 0;
- eep_config->max_total_qng = 0xF0;
- eep_config->max_tag_qng = 0x20;
- eep_config->cntl = 0xBFFF;
- ASC_EEP_SET_CHIP_ID(eep_config, 7);
- eep_config->no_scam = 0;
- eep_config->adapter_info[0] = 0;
- eep_config->adapter_info[1] = 0;
- eep_config->adapter_info[2] = 0;
- eep_config->adapter_info[3] = 0;
- eep_config->adapter_info[4] = 0;
- /* Indicate EEPROM-less board. */
- eep_config->adapter_info[5] = 0xBB;
- } else {
- ASC_PRINT
- ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
- write_eep = 1;
- warn_code |= ASC_WARN_EEPROM_CHKSUM;
- }
- }
- asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
- asc_dvc->cfg->disc_enable = eep_config->disc_enable;
- asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
- asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
- asc_dvc->start_motor = eep_config->start_motor;
- asc_dvc->dvc_cntl = eep_config->cntl;
- asc_dvc->no_scam = eep_config->no_scam;
- asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
- asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
- asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
- asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
- asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
- asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
- if (!AscTestExternalLram(asc_dvc)) {
- if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
- ASC_IS_PCI_ULTRA)) {
- eep_config->max_total_qng =
- ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
- eep_config->max_tag_qng =
- ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
- } else {
- eep_config->cfg_msw |= 0x0800;
- cfg_msw |= 0x0800;
- AscSetChipCfgMsw(iop_base, cfg_msw);
- eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
- eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
- }
- } else {
- }
- if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
- eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
- }
- if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
- eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
- }
- if (eep_config->max_tag_qng > eep_config->max_total_qng) {
- eep_config->max_tag_qng = eep_config->max_total_qng;
- }
- if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
- eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
- }
- asc_dvc->max_total_qng = eep_config->max_total_qng;
- if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
- eep_config->use_cmd_qng) {
- eep_config->disc_enable = eep_config->use_cmd_qng;
- warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
- }
- if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
- asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
- }
- ASC_EEP_SET_CHIP_ID(eep_config,
- ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
- asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
- if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
- !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
- asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
- }
+ int retry;
- for (i = 0; i <= ASC_MAX_TID; i++) {
- asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
- asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
- asc_dvc->cfg->sdtr_period_offset[i] =
- (uchar)(ASC_DEF_SDTR_OFFSET |
- (asc_dvc->host_init_sdtr_index << 4));
- }
- eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
- if (write_eep) {
- if ((i =
- AscSetEEPConfig(iop_base, eep_config,
- asc_dvc->bus_type)) != 0) {
- ASC_PRINT1
- ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
- i);
- } else {
- ASC_PRINT
- ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
- }
+ for (retry = 0; retry < ASC_EEP_MAX_RETRY; retry++) {
+ unsigned char read_back;
+ AscSetChipEEPCmd(iop_base, cmd_reg);
+ mdelay(1);
+ read_back = AscGetChipEEPCmd(iop_base);
+ if (read_back == cmd_reg)
+ return 1;
}
- return (warn_code);
+ return 0;
}
-static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
+static void __devinit AscWaitEEPRead(void)
{
- int i;
- ushort warn_code;
- PortAddr iop_base;
- ASC_PADDR phy_addr;
- ASC_DCNT phy_size;
-
- iop_base = asc_dvc->iop_base;
- warn_code = 0;
- for (i = 0; i <= ASC_MAX_TID; i++) {
- AscPutMCodeInitSDTRAtID(iop_base, i,
- asc_dvc->cfg->sdtr_period_offset[i]
- );
- }
+ mdelay(1);
+}
- AscInitQLinkVar(asc_dvc);
- AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
- asc_dvc->cfg->disc_enable);
- AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
- ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
+static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
+{
+ ushort read_wval;
+ uchar cmd_reg;
- /* Align overrun buffer on an 8 byte boundary. */
- phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
- phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
- AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
- (uchar *)&phy_addr, 1);
- phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
- AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
- (uchar *)&phy_size, 1);
+ AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+ AscWaitEEPRead();
+ cmd_reg = addr | ASC_EEP_CMD_READ;
+ AscWriteEEPCmdReg(iop_base, cmd_reg);
+ AscWaitEEPRead();
+ read_wval = AscGetChipEEPData(iop_base);
+ AscWaitEEPRead();
+ return read_wval;
+}
- asc_dvc->cfg->mcode_date =
- AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
- asc_dvc->cfg->mcode_version =
- AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
+static ushort __devinit
+AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
+{
+ ushort wval;
+ ushort sum;
+ ushort *wbuf;
+ int cfg_beg;
+ int cfg_end;
+ int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
+ int s_addr;
- AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
- if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
- asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
- return (warn_code);
+ wbuf = (ushort *)cfg_buf;
+ sum = 0;
+ /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
+ for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+ *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
+ sum += *wbuf;
}
- if (AscStartChip(iop_base) != 1) {
- asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
- return (warn_code);
+ if (bus_type & ASC_IS_VL) {
+ cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+ cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+ } else {
+ cfg_beg = ASC_EEP_DVC_CFG_BEG;
+ cfg_end = ASC_EEP_MAX_DVC_ADDR;
}
-
- return (warn_code);
+ for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+ wval = AscReadEEPWord(iop_base, (uchar)s_addr);
+ if (s_addr <= uchar_end_in_config) {
+ /*
+ * Swap all char fields - must unswap bytes already swapped
+ * by AscReadEEPWord().
+ */
+ *wbuf = le16_to_cpu(wval);
+ } else {
+ /* Don't swap word field at the end - cntl field. */
+ *wbuf = wval;
+ }
+ sum += wval; /* Checksum treats all EEPROM data as words. */
+ }
+ /*
+ * Read the checksum word which will be compared against 'sum'
+ * by the caller. Word field already swapped.
+ */
+ *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
+ return sum;
}
-static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
+static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
{
PortAddr iop_base;
ushort q_addr;
@@ -11197,7 +11389,7 @@ static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
saved_word = AscReadLramWord(iop_base, q_addr);
AscSetChipLramAddr(iop_base, q_addr);
AscSetChipLramData(iop_base, 0x55AA);
- DvcSleepMilliSecond(10);
+ mdelay(10);
AscSetChipLramAddr(iop_base, q_addr);
if (AscGetChipLramData(iop_base) == 0x55AA) {
sta = 1;
@@ -11206,26 +11398,12 @@ static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
return (sta);
}
-static int __init AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
+static void __devinit AscWaitEEPWrite(void)
{
- uchar read_back;
- int retry;
-
- retry = 0;
- while (TRUE) {
- AscSetChipEEPCmd(iop_base, cmd_reg);
- DvcSleepMilliSecond(1);
- read_back = AscGetChipEEPCmd(iop_base);
- if (read_back == cmd_reg) {
- return (1);
- }
- if (retry++ > ASC_EEP_MAX_RETRY) {
- return (0);
- }
- }
+ mdelay(20);
}
-static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
+static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
{
ushort read_back;
int retry;
@@ -11233,7 +11411,7 @@ static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
retry = 0;
while (TRUE) {
AscSetChipEEPData(iop_base, data_reg);
- DvcSleepMilliSecond(1);
+ mdelay(1);
read_back = AscGetChipEEPData(iop_base);
if (read_back == data_reg) {
return (1);
@@ -11244,34 +11422,7 @@ static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
}
}
-static void __init AscWaitEEPRead(void)
-{
- DvcSleepMilliSecond(1);
- return;
-}
-
-static void __init AscWaitEEPWrite(void)
-{
- DvcSleepMilliSecond(20);
- return;
-}
-
-static ushort __init AscReadEEPWord(PortAddr iop_base, uchar addr)
-{
- ushort read_wval;
- uchar cmd_reg;
-
- AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
- AscWaitEEPRead();
- cmd_reg = addr | ASC_EEP_CMD_READ;
- AscWriteEEPCmdReg(iop_base, cmd_reg);
- AscWaitEEPRead();
- read_wval = AscGetChipEEPData(iop_base);
- AscWaitEEPRead();
- return (read_wval);
-}
-
-static ushort __init
+static ushort __devinit
AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
{
ushort read_wval;
@@ -11292,54 +11443,7 @@ AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
return (read_wval);
}
-static ushort __init
-AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
-{
- ushort wval;
- ushort sum;
- ushort *wbuf;
- int cfg_beg;
- int cfg_end;
- int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
- int s_addr;
-
- wbuf = (ushort *)cfg_buf;
- sum = 0;
- /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
- for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
- *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
- sum += *wbuf;
- }
- if (bus_type & ASC_IS_VL) {
- cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
- cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
- } else {
- cfg_beg = ASC_EEP_DVC_CFG_BEG;
- cfg_end = ASC_EEP_MAX_DVC_ADDR;
- }
- for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
- wval = AscReadEEPWord(iop_base, (uchar)s_addr);
- if (s_addr <= uchar_end_in_config) {
- /*
- * Swap all char fields - must unswap bytes already swapped
- * by AscReadEEPWord().
- */
- *wbuf = le16_to_cpu(wval);
- } else {
- /* Don't swap word field at the end - cntl field. */
- *wbuf = wval;
- }
- sum += wval; /* Checksum treats all EEPROM data as words. */
- }
- /*
- * Read the checksum word which will be compared against 'sum'
- * by the caller. Word field already swapped.
- */
- *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
- return (sum);
-}
-
-static int __init
+static int __devinit
AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
{
int n_error;
@@ -11432,10 +11536,10 @@ AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
n_error++;
}
- return (n_error);
+ return n_error;
}
-static int __init
+static int __devinit
AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
{
int retry;
@@ -11451,2386 +11555,326 @@ AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
break;
}
}
- return (n_error);
+ return n_error;
}
-static void
-AscAsyncFix(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
+static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
{
- uchar dvc_type;
- ASC_SCSI_BIT_ID_TYPE tid_bits;
-
- dvc_type = ASC_INQ_DVC_TYPE(inq);
- tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
-
- if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
- if (!(asc_dvc->init_sdtr & tid_bits)) {
- if ((dvc_type == TYPE_ROM) &&
- (AscCompareString((uchar *)inq->vendor_id,
- (uchar *)"HP ", 3) == 0)) {
- asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
- }
- asc_dvc->pci_fix_asyn_xfer |= tid_bits;
- if ((dvc_type == TYPE_PROCESSOR) ||
- (dvc_type == TYPE_SCANNER) ||
- (dvc_type == TYPE_ROM) || (dvc_type == TYPE_TAPE)) {
- asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
- }
+ ASCEEP_CONFIG eep_config_buf;
+ ASCEEP_CONFIG *eep_config;
+ PortAddr iop_base;
+ ushort chksum;
+ ushort warn_code;
+ ushort cfg_msw, cfg_lsw;
+ int i;
+ int write_eep = 0;
- if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
- AscSetRunChipSynRegAtID(asc_dvc->iop_base,
- tid_no,
- ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+ iop_base = asc_dvc->iop_base;
+ warn_code = 0;
+ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
+ AscStopQueueExe(iop_base);
+ if ((AscStopChip(iop_base) == FALSE) ||
+ (AscGetChipScsiCtrl(iop_base) != 0)) {
+ asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
+ AscResetChipAndScsiBus(asc_dvc);
+ mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */
+ }
+ if (AscIsChipHalted(iop_base) == FALSE) {
+ asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+ return (warn_code);
+ }
+ AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+ if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+ asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+ return (warn_code);
+ }
+ eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
+ cfg_msw = AscGetChipCfgMsw(iop_base);
+ cfg_lsw = AscGetChipCfgLsw(iop_base);
+ if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+ cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
+ warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+ AscSetChipCfgMsw(iop_base, cfg_msw);
+ }
+ chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
+ ASC_DBG(1, "chksum 0x%x\n", chksum);
+ if (chksum == 0) {
+ chksum = 0xaa55;
+ }
+ if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+ warn_code |= ASC_WARN_AUTO_CONFIG;
+ if (asc_dvc->cfg->chip_version == 3) {
+ if (eep_config->cfg_lsw != cfg_lsw) {
+ warn_code |= ASC_WARN_EEPROM_RECOVER;
+ eep_config->cfg_lsw =
+ AscGetChipCfgLsw(iop_base);
+ }
+ if (eep_config->cfg_msw != cfg_msw) {
+ warn_code |= ASC_WARN_EEPROM_RECOVER;
+ eep_config->cfg_msw =
+ AscGetChipCfgMsw(iop_base);
}
}
}
- return;
-}
-
-static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
-{
- if ((inq->add_len >= 32) &&
- (AscCompareString((uchar *)inq->vendor_id,
- (uchar *)"QUANTUM XP34301", 15) == 0) &&
- (AscCompareString((uchar *)inq->product_rev_level,
- (uchar *)"1071", 4) == 0)) {
- return 0;
- }
- return 1;
-}
-
-static void
-AscInquiryHandling(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
-{
- ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
- ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
-
- orig_init_sdtr = asc_dvc->init_sdtr;
- orig_use_tagged_qng = asc_dvc->use_tagged_qng;
-
- asc_dvc->init_sdtr &= ~tid_bit;
- asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
- asc_dvc->use_tagged_qng &= ~tid_bit;
-
- if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
- if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
- asc_dvc->init_sdtr |= tid_bit;
+ eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
+ eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
+ ASC_DBG(1, "eep_config->chksum 0x%x\n", eep_config->chksum);
+ if (chksum != eep_config->chksum) {
+ if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
+ ASC_CHIP_VER_PCI_ULTRA_3050) {
+ ASC_DBG(1, "chksum error ignored; EEPROM-less board\n");
+ eep_config->init_sdtr = 0xFF;
+ eep_config->disc_enable = 0xFF;
+ eep_config->start_motor = 0xFF;
+ eep_config->use_cmd_qng = 0;
+ eep_config->max_total_qng = 0xF0;
+ eep_config->max_tag_qng = 0x20;
+ eep_config->cntl = 0xBFFF;
+ ASC_EEP_SET_CHIP_ID(eep_config, 7);
+ eep_config->no_scam = 0;
+ eep_config->adapter_info[0] = 0;
+ eep_config->adapter_info[1] = 0;
+ eep_config->adapter_info[2] = 0;
+ eep_config->adapter_info[3] = 0;
+ eep_config->adapter_info[4] = 0;
+ /* Indicate EEPROM-less board. */
+ eep_config->adapter_info[5] = 0xBB;
+ } else {
+ ASC_PRINT
+ ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
+ write_eep = 1;
+ warn_code |= ASC_WARN_EEPROM_CHKSUM;
}
- if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
- ASC_INQ_CMD_QUEUE(inq)) {
- if (AscTagQueuingSafe(inq)) {
- asc_dvc->use_tagged_qng |= tid_bit;
- asc_dvc->cfg->can_tagged_qng |= tid_bit;
- }
+ }
+ asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
+ asc_dvc->cfg->disc_enable = eep_config->disc_enable;
+ asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
+ asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
+ asc_dvc->start_motor = eep_config->start_motor;
+ asc_dvc->dvc_cntl = eep_config->cntl;
+ asc_dvc->no_scam = eep_config->no_scam;
+ asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
+ asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
+ asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
+ asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
+ asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
+ asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
+ if (!AscTestExternalLram(asc_dvc)) {
+ if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
+ ASC_IS_PCI_ULTRA)) {
+ eep_config->max_total_qng =
+ ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
+ eep_config->max_tag_qng =
+ ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
+ } else {
+ eep_config->cfg_msw |= 0x0800;
+ cfg_msw |= 0x0800;
+ AscSetChipCfgMsw(iop_base, cfg_msw);
+ eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
+ eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
}
+ } else {
}
- if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
- AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
- asc_dvc->cfg->disc_enable);
- AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
- asc_dvc->use_tagged_qng);
- AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
- asc_dvc->cfg->can_tagged_qng);
-
- asc_dvc->max_dvc_qng[tid_no] =
- asc_dvc->cfg->max_tag_qng[tid_no];
- AscWriteLramByte(asc_dvc->iop_base,
- (ushort)(ASCV_MAX_DVC_QNG_BEG + tid_no),
- asc_dvc->max_dvc_qng[tid_no]);
+ if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
+ eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
}
- if (orig_init_sdtr != asc_dvc->init_sdtr) {
- AscAsyncFix(asc_dvc, tid_no, inq);
+ if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
+ eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
}
- return;
-}
-
-static int AscCompareString(uchar *str1, uchar *str2, int len)
-{
- int i;
- int diff;
-
- for (i = 0; i < len; i++) {
- diff = (int)(str1[i] - str2[i]);
- if (diff != 0)
- return (diff);
+ if (eep_config->max_tag_qng > eep_config->max_total_qng) {
+ eep_config->max_tag_qng = eep_config->max_total_qng;
}
- return (0);
-}
-
-static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
-{
- uchar byte_data;
- ushort word_data;
-
- if (isodd_word(addr)) {
- AscSetChipLramAddr(iop_base, addr - 1);
- word_data = AscGetChipLramData(iop_base);
- byte_data = (uchar)((word_data >> 8) & 0xFF);
- } else {
- AscSetChipLramAddr(iop_base, addr);
- word_data = AscGetChipLramData(iop_base);
- byte_data = (uchar)(word_data & 0xFF);
+ if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
+ eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
+ }
+ asc_dvc->max_total_qng = eep_config->max_total_qng;
+ if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
+ eep_config->use_cmd_qng) {
+ eep_config->disc_enable = eep_config->use_cmd_qng;
+ warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+ }
+ ASC_EEP_SET_CHIP_ID(eep_config,
+ ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
+ asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
+ if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
+ !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
+ asc_dvc->min_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
}
- return (byte_data);
-}
-
-static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
-{
- ushort word_data;
-
- AscSetChipLramAddr(iop_base, addr);
- word_data = AscGetChipLramData(iop_base);
- return (word_data);
-}
-
-#if CC_VERY_LONG_SG_LIST
-static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
-{
- ushort val_low, val_high;
- ASC_DCNT dword_data;
- AscSetChipLramAddr(iop_base, addr);
- val_low = AscGetChipLramData(iop_base);
- val_high = AscGetChipLramData(iop_base);
- dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
- return (dword_data);
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
+ asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
+ asc_dvc->cfg->sdtr_period_offset[i] =
+ (uchar)(ASC_DEF_SDTR_OFFSET |
+ (asc_dvc->min_sdtr_index << 4));
+ }
+ eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
+ if (write_eep) {
+ if ((i = AscSetEEPConfig(iop_base, eep_config,
+ asc_dvc->bus_type)) != 0) {
+ ASC_PRINT1
+ ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
+ i);
+ } else {
+ ASC_PRINT
+ ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
+ }
+ }
+ return (warn_code);
}
-#endif /* CC_VERY_LONG_SG_LIST */
-static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
+static int __devinit AscInitGetConfig(struct Scsi_Host *shost)
{
- AscSetChipLramAddr(iop_base, addr);
- AscSetChipLramData(iop_base, word_val);
- return;
-}
+ struct asc_board *board = shost_priv(shost);
+ ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var;
+ unsigned short warn_code = 0;
-static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
-{
- ushort word_data;
+ asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
+ if (asc_dvc->err_code != 0)
+ return asc_dvc->err_code;
- if (isodd_word(addr)) {
- addr--;
- word_data = AscReadLramWord(iop_base, addr);
- word_data &= 0x00FF;
- word_data |= (((ushort)byte_val << 8) & 0xFF00);
+ if (AscFindSignature(asc_dvc->iop_base)) {
+ warn_code |= AscInitAscDvcVar(asc_dvc);
+ warn_code |= AscInitFromEEP(asc_dvc);
+ asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
+ if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
+ asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
} else {
- word_data = AscReadLramWord(iop_base, addr);
- word_data &= 0xFF00;
- word_data |= ((ushort)byte_val & 0x00FF);
+ asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
}
- AscWriteLramWord(iop_base, addr, word_data);
- return;
-}
-/*
- * Copy 2 bytes to LRAM.
- *
- * The source data is assumed to be in little-endian order in memory
- * and is maintained in little-endian order when written to LRAM.
- */
-static void
-AscMemWordCopyPtrToLram(PortAddr iop_base,
- ushort s_addr, uchar *s_buffer, int words)
-{
- int i;
-
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < 2 * words; i += 2) {
- /*
- * On a little-endian system the second argument below
- * produces a little-endian ushort which is written to
- * LRAM in little-endian order. On a big-endian system
- * the second argument produces a big-endian ushort which
- * is "transparently" byte-swapped by outpw() and written
- * in little-endian order to LRAM.
- */
- outpw(iop_base + IOP_RAM_DATA,
- ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
+ switch (warn_code) {
+ case 0: /* No error */
+ break;
+ case ASC_WARN_IO_PORT_ROTATE:
+ shost_printk(KERN_WARNING, shost, "I/O port address "
+ "modified\n");
+ break;
+ case ASC_WARN_AUTO_CONFIG:
+ shost_printk(KERN_WARNING, shost, "I/O port increment switch "
+ "enabled\n");
+ break;
+ case ASC_WARN_EEPROM_CHKSUM:
+ shost_printk(KERN_WARNING, shost, "EEPROM checksum error\n");
+ break;
+ case ASC_WARN_IRQ_MODIFIED:
+ shost_printk(KERN_WARNING, shost, "IRQ modified\n");
+ break;
+ case ASC_WARN_CMD_QNG_CONFLICT:
+ shost_printk(KERN_WARNING, shost, "tag queuing enabled w/o "
+ "disconnects\n");
+ break;
+ default:
+ shost_printk(KERN_WARNING, shost, "unknown warning: 0x%x\n",
+ warn_code);
+ break;
}
- return;
-}
-/*
- * Copy 4 bytes to LRAM.
- *
- * The source data is assumed to be in little-endian order in memory
- * and is maintained in little-endian order when writen to LRAM.
- */
-static void
-AscMemDWordCopyPtrToLram(PortAddr iop_base,
- ushort s_addr, uchar *s_buffer, int dwords)
-{
- int i;
+ if (asc_dvc->err_code != 0)
+ shost_printk(KERN_ERR, shost, "error 0x%x at init_state "
+ "0x%x\n", asc_dvc->err_code, asc_dvc->init_state);
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < 4 * dwords; i += 4) {
- outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
- outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
- }
- return;
+ return asc_dvc->err_code;
}
-/*
- * Copy 2 bytes from LRAM.
- *
- * The source data is assumed to be in little-endian order in LRAM
- * and is maintained in little-endian order when written to memory.
- */
-static void
-AscMemWordCopyPtrFromLram(PortAddr iop_base,
- ushort s_addr, uchar *d_buffer, int words)
+static int __devinit AscInitSetConfig(struct pci_dev *pdev, struct Scsi_Host *shost)
{
- int i;
- ushort word;
+ struct asc_board *board = shost_priv(shost);
+ ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var;
+ PortAddr iop_base = asc_dvc->iop_base;
+ unsigned short cfg_msw;
+ unsigned short warn_code = 0;
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < 2 * words; i += 2) {
- word = inpw(iop_base + IOP_RAM_DATA);
- d_buffer[i] = word & 0xff;
- d_buffer[i + 1] = (word >> 8) & 0xff;
+ asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
+ if (asc_dvc->err_code != 0)
+ return asc_dvc->err_code;
+ if (!AscFindSignature(asc_dvc->iop_base)) {
+ asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+ return asc_dvc->err_code;
}
- return;
-}
-
-static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
-{
- ASC_DCNT sum;
- int i;
- sum = 0L;
- for (i = 0; i < words; i++, s_addr += 2) {
- sum += AscReadLramWord(iop_base, s_addr);
+ cfg_msw = AscGetChipCfgMsw(iop_base);
+ if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+ cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
+ warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+ AscSetChipCfgMsw(iop_base, cfg_msw);
}
- return (sum);
-}
-
-static void
-AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
-{
- int i;
-
- AscSetChipLramAddr(iop_base, s_addr);
- for (i = 0; i < words; i++) {
- AscSetChipLramData(iop_base, set_wval);
+ if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
+ asc_dvc->cfg->cmd_qng_enabled) {
+ asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
+ warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
}
- return;
-}
-
-/*
- * --- Adv Library Functions
- */
-
-/* a_mcode.h */
-
-/* Microcode buffer is kept after initialization for error recovery. */
-static unsigned char _adv_asc3550_buf[] = {
- 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
- 0x01, 0x00, 0x48, 0xe4,
- 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
- 0x28, 0x0e, 0x9e, 0xe7,
- 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
- 0x55, 0xf0, 0x01, 0xf6,
- 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
- 0x00, 0xec, 0x85, 0xf0,
- 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
- 0x86, 0xf0, 0xb4, 0x00,
- 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
- 0xaa, 0x18, 0x02, 0x80,
- 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
- 0x00, 0x57, 0x01, 0xea,
- 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
- 0x03, 0xe6, 0xb6, 0x00,
- 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
- 0x02, 0x4a, 0xb9, 0x54,
- 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
- 0x3e, 0x00, 0x80, 0x00,
- 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
- 0x74, 0x01, 0x76, 0x01,
- 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
- 0x4c, 0x1c, 0xbb, 0x55,
- 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
- 0x03, 0xf7, 0x06, 0xf7,
- 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
- 0x30, 0x13, 0x64, 0x15,
- 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
- 0x04, 0xea, 0x5d, 0xf0,
- 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
- 0xcc, 0x00, 0x20, 0x01,
- 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
- 0x40, 0x13, 0x30, 0x1c,
- 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
- 0x59, 0xf0, 0xa7, 0xf0,
- 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
- 0xa4, 0x00, 0xb5, 0x00,
- 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
- 0x14, 0x0e, 0x02, 0x10,
- 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
- 0x10, 0x15, 0x14, 0x15,
- 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
- 0x91, 0x44, 0x0a, 0x45,
- 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
- 0x83, 0x59, 0x05, 0xe6,
- 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
- 0x02, 0xfa, 0x03, 0xfa,
- 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
- 0x9e, 0x00, 0xa8, 0x00,
- 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
- 0x7a, 0x01, 0xc0, 0x01,
- 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
- 0x69, 0x08, 0xba, 0x08,
- 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
- 0xf1, 0x10, 0x06, 0x12,
- 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
- 0x8a, 0x15, 0xc6, 0x17,
- 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
- 0x0e, 0x47, 0x48, 0x47,
- 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
- 0x14, 0x56, 0x77, 0x57,
- 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
- 0xf0, 0x29, 0x02, 0xfe,
- 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
- 0xfe, 0x80, 0x01, 0xff,
- 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
- 0x00, 0xfe, 0x57, 0x24,
- 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
- 0x00, 0x00, 0xff, 0x08,
- 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
- 0xff, 0xff, 0xff, 0x0f,
- 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
- 0xfe, 0x04, 0xf7, 0xcf,
- 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
- 0x0b, 0x3c, 0x2a, 0xfe,
- 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
- 0xfe, 0xf0, 0x01, 0xfe,
- 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
- 0x02, 0xfe, 0xd4, 0x0c,
- 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
- 0x1c, 0x05, 0xfe, 0xa6,
- 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
- 0xf0, 0xfe, 0x86, 0x02,
- 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
- 0xfe, 0x46, 0xf0, 0xfe,
- 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
- 0x44, 0x02, 0xfe, 0x44,
- 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
- 0xa0, 0x17, 0x06, 0x18,
- 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
- 0x1e, 0x1c, 0xfe, 0xe9,
- 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
- 0x0a, 0x6b, 0x01, 0x9e,
- 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
- 0x01, 0x82, 0xfe, 0xbd,
- 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
- 0x58, 0x1c, 0x17, 0x06,
- 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
- 0xfe, 0x94, 0x02, 0xfe,
- 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
- 0x01, 0xfe, 0x54, 0x0f,
- 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
- 0x69, 0x10, 0x17, 0x06,
- 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
- 0xf6, 0xc7, 0x01, 0xfe,
- 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
- 0x02, 0x29, 0x0a, 0x40,
- 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
- 0x58, 0x0a, 0x99, 0x01,
- 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
- 0x2a, 0x46, 0xfe, 0x02,
- 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
- 0x01, 0xfe, 0x07, 0x4b,
- 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
- 0xfe, 0x56, 0x03, 0xfe,
- 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
- 0xfe, 0x9f, 0xf0, 0xfe,
- 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
- 0x1c, 0xeb, 0x09, 0x04,
- 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
- 0x01, 0x0e, 0xac, 0x75,
- 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
- 0xfe, 0x82, 0xf0, 0xfe,
- 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
- 0x32, 0x1f, 0xfe, 0xb4,
- 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
- 0x0a, 0xf0, 0xfe, 0x7a,
- 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
- 0x01, 0x33, 0x8f, 0xfe,
- 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
- 0xf7, 0xfe, 0x48, 0x1c,
- 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
- 0x0a, 0xca, 0x01, 0x0e,
- 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
- 0x2c, 0x01, 0x33, 0x8f,
- 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
- 0xfe, 0x3c, 0x04, 0x1f,
- 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
- 0x12, 0x2b, 0xff, 0x02,
- 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
- 0x22, 0x30, 0x2e, 0xd5,
- 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
- 0xfe, 0x4c, 0x54, 0x64,
- 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
- 0xfe, 0x2a, 0x13, 0x2f,
- 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
- 0xd3, 0xfa, 0xef, 0x86,
- 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
- 0x1d, 0xfe, 0x1c, 0x12,
- 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
- 0x70, 0x0c, 0x02, 0x22,
- 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
- 0x01, 0x33, 0x02, 0x29,
- 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
- 0x80, 0xfe, 0x31, 0xe4,
- 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
- 0xfe, 0x70, 0x12, 0x49,
- 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
- 0x80, 0x05, 0xfe, 0x31,
- 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
- 0x28, 0xfe, 0x42, 0x12,
- 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
- 0x11, 0xfe, 0xe3, 0x00,
- 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
- 0x64, 0x05, 0x83, 0x24,
- 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
- 0x09, 0x48, 0x01, 0x08,
- 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
- 0x86, 0x24, 0x06, 0x12,
- 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
- 0x01, 0xa7, 0x14, 0x92,
- 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
- 0x02, 0x22, 0x05, 0xfe,
- 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
- 0x47, 0x01, 0xa7, 0x26,
- 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
- 0x01, 0xfe, 0xaa, 0x14,
- 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
- 0x05, 0x50, 0xb4, 0x0c,
- 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
- 0x13, 0x01, 0xfe, 0x14,
- 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
- 0xff, 0x02, 0x00, 0x57,
- 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
- 0x72, 0x06, 0x49, 0x04,
- 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
- 0x06, 0x11, 0x9a, 0x01,
- 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
- 0x01, 0xa7, 0xec, 0x72,
- 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
- 0xfe, 0x0a, 0xf0, 0xfe,
- 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
- 0x8d, 0x81, 0x02, 0x22,
- 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
- 0x01, 0x08, 0x15, 0x00,
- 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
- 0x00, 0x02, 0xfe, 0x32,
- 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
- 0xfe, 0x1b, 0x00, 0x01,
- 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
- 0x08, 0x15, 0x06, 0x01,
- 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
- 0x9a, 0x81, 0x4b, 0x1d,
- 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
- 0x45, 0xfe, 0x32, 0x12,
- 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
- 0xfe, 0x32, 0x07, 0x8d,
- 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
- 0x06, 0x15, 0x19, 0x02,
- 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
- 0x90, 0x77, 0xfe, 0xca,
- 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
- 0x10, 0xfe, 0x0e, 0x12,
- 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
- 0x83, 0xe7, 0xc4, 0xa1,
- 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
- 0x40, 0x12, 0x58, 0x01,
- 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
- 0x51, 0x83, 0xfb, 0xfe,
- 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
- 0xfe, 0x40, 0x50, 0xfe,
- 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
- 0xfe, 0x2a, 0x12, 0xfe,
- 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
- 0x85, 0x01, 0xa8, 0xfe,
- 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
- 0x18, 0x57, 0xfb, 0xfe,
- 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
- 0x0c, 0x39, 0x18, 0x3a,
- 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
- 0x11, 0x65, 0xfe, 0x48,
- 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
- 0xdd, 0xb8, 0xfe, 0x80,
- 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
- 0xfe, 0x7a, 0x08, 0x8d,
- 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
- 0x10, 0x61, 0x04, 0x06,
- 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
- 0x12, 0xfe, 0x2e, 0x1c,
- 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
- 0x52, 0x12, 0xfe, 0x2c,
- 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
- 0x08, 0xfe, 0x8a, 0x10,
- 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
- 0x24, 0x0a, 0xab, 0xfe,
- 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
- 0x1c, 0x12, 0xb5, 0xfe,
- 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
- 0x1c, 0x06, 0x16, 0x9d,
- 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
- 0x14, 0x92, 0x01, 0x33,
- 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
- 0xfe, 0x74, 0x18, 0x1c,
- 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
- 0x01, 0xe6, 0x1e, 0x27,
- 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
- 0x09, 0x04, 0x6a, 0xfe,
- 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
- 0xfe, 0x83, 0x80, 0xfe,
- 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
- 0x27, 0xfe, 0x40, 0x59,
- 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
- 0x7c, 0xbe, 0x54, 0xbf,
- 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
- 0x79, 0x56, 0x68, 0x57,
- 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
- 0xa2, 0x23, 0x0c, 0x7b,
- 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
- 0x16, 0xd7, 0x79, 0x39,
- 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
- 0xfe, 0x10, 0x58, 0xfe,
- 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
- 0x19, 0x16, 0xd7, 0x09,
- 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
- 0xfe, 0x10, 0x90, 0xfe,
- 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
- 0x11, 0x9b, 0x09, 0x04,
- 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
- 0xfe, 0x0c, 0x58, 0xfe,
- 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
- 0x0b, 0xfe, 0x1a, 0x12,
- 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
- 0x14, 0x7a, 0x01, 0x33,
- 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
- 0xfe, 0xed, 0x19, 0xbf,
- 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
- 0x34, 0xfe, 0x74, 0x10,
- 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
- 0x84, 0x05, 0xcb, 0x1c,
- 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
- 0xf0, 0xfe, 0xc4, 0x0a,
- 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
- 0xce, 0xf0, 0xfe, 0xca,
- 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
- 0x22, 0x00, 0x02, 0x5a,
- 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
- 0xfe, 0xd0, 0xf0, 0xfe,
- 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
- 0x4c, 0xfe, 0x10, 0x10,
- 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
- 0x2a, 0x13, 0xfe, 0x4e,
- 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
- 0x16, 0x32, 0x2a, 0x73,
- 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
- 0x32, 0x8c, 0xfe, 0x48,
- 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
- 0xdb, 0x10, 0x11, 0xfe,
- 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
- 0x22, 0x30, 0x2e, 0xd8,
- 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
- 0x45, 0x0f, 0xfe, 0x42,
- 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
- 0x09, 0x04, 0x0b, 0xfe,
- 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
- 0x00, 0x21, 0xfe, 0xa6,
- 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
- 0xfe, 0xe2, 0x10, 0x01,
- 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
- 0x01, 0x6f, 0x02, 0x29,
- 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
- 0x01, 0x86, 0x3e, 0x0b,
- 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
- 0x3e, 0x0b, 0x0f, 0xfe,
- 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
- 0xe8, 0x59, 0x11, 0x2d,
- 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
- 0x04, 0x0b, 0x84, 0x3e,
- 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
- 0x09, 0x04, 0x1b, 0xfe,
- 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
- 0x1c, 0x1c, 0xfe, 0x9d,
- 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
- 0xfe, 0x15, 0x00, 0xfe,
- 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
- 0x0f, 0xfe, 0x47, 0x00,
- 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
- 0xab, 0x70, 0x05, 0x6b,
- 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
- 0x1c, 0x42, 0x59, 0x01,
- 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
- 0x00, 0x37, 0x97, 0x01,
- 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
- 0x1d, 0xfe, 0xce, 0x45,
- 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
- 0x57, 0x05, 0x51, 0xfe,
- 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
- 0x46, 0x09, 0x04, 0x1d,
- 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
- 0x99, 0x01, 0x0e, 0xfe,
- 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
- 0xfe, 0xee, 0x14, 0xee,
- 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
- 0x13, 0x02, 0x29, 0x1e,
- 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
- 0xce, 0x1e, 0x2d, 0x47,
- 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
- 0x12, 0x4d, 0x01, 0xfe,
- 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
- 0xf0, 0x0d, 0xfe, 0x02,
- 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
- 0xf6, 0xfe, 0x34, 0x01,
- 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
- 0xaf, 0xfe, 0x02, 0xea,
- 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
- 0x05, 0xfe, 0x38, 0x01,
- 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
- 0x0c, 0xfe, 0x62, 0x01,
- 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
- 0x03, 0x23, 0x03, 0x1e,
- 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
- 0x71, 0x13, 0xfe, 0x24,
- 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
- 0xdc, 0xfe, 0x73, 0x57,
- 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
- 0x80, 0x5d, 0x03, 0xfe,
- 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
- 0x75, 0x03, 0x09, 0x04,
- 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
- 0xfe, 0x1e, 0x80, 0xe1,
- 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
- 0x90, 0xa3, 0xfe, 0x3c,
- 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
- 0x16, 0x2f, 0x07, 0x2d,
- 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
- 0xe8, 0x11, 0xfe, 0xe9,
- 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
- 0x1e, 0x1c, 0xfe, 0x14,
- 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
- 0x09, 0x04, 0x4f, 0xfe,
- 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
- 0x40, 0x12, 0x20, 0x63,
- 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
- 0x1c, 0x05, 0xfe, 0xac,
- 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
- 0xfe, 0xb0, 0x00, 0xfe,
- 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
- 0x24, 0x69, 0x12, 0xc9,
- 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
- 0x90, 0x4d, 0xfe, 0x91,
- 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
- 0xfe, 0x90, 0x4d, 0xfe,
- 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
- 0x46, 0x1e, 0x20, 0xed,
- 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
- 0x70, 0xfe, 0x14, 0x1c,
- 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
- 0xfe, 0x07, 0xe6, 0x1d,
- 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
- 0xfa, 0xef, 0xfe, 0x42,
- 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
- 0xfe, 0x36, 0x12, 0xf0,
- 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
- 0x3d, 0x75, 0x07, 0x10,
- 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
- 0x10, 0x07, 0x7e, 0x45,
- 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
- 0xfe, 0x01, 0xec, 0x97,
- 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
- 0x27, 0x01, 0xda, 0xfe,
- 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
- 0xfe, 0x48, 0x12, 0x07,
- 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
- 0xfe, 0x3e, 0x11, 0x07,
- 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
- 0x11, 0x07, 0x19, 0xfe,
- 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
- 0x01, 0x08, 0x8c, 0x43,
- 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
- 0x7e, 0x02, 0x29, 0x2b,
- 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
- 0xfc, 0x10, 0x09, 0x04,
- 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
- 0xc6, 0x10, 0x1e, 0x58,
- 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
- 0x54, 0x18, 0x55, 0x23,
- 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
- 0xa5, 0xc0, 0x38, 0xc1,
- 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
- 0x05, 0xfa, 0x4e, 0xfe,
- 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
- 0x0c, 0x56, 0x18, 0x57,
- 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
- 0x00, 0x56, 0xfe, 0xa1,
- 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
- 0x58, 0xfe, 0x1f, 0x40,
- 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
- 0x31, 0x57, 0xfe, 0x44,
- 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
- 0x8a, 0x50, 0x05, 0x39,
- 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
- 0x12, 0xcd, 0x02, 0x5b,
- 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
- 0x2f, 0x07, 0x9b, 0x21,
- 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
- 0x39, 0x68, 0x3a, 0xfe,
- 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
- 0x51, 0xfe, 0x8e, 0x51,
- 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
- 0x01, 0x08, 0x25, 0x32,
- 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
- 0x3b, 0x02, 0x44, 0x01,
- 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
- 0x01, 0x08, 0x1f, 0xa2,
- 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
- 0x00, 0x28, 0x84, 0x49,
- 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
- 0x78, 0x3d, 0xfe, 0xda,
- 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
- 0x05, 0xc6, 0x28, 0x84,
- 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
- 0x14, 0xfe, 0x03, 0x17,
- 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
- 0xfe, 0xaa, 0x14, 0x02,
- 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
- 0x21, 0x44, 0x01, 0xfe,
- 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
- 0xfe, 0x4a, 0xf4, 0x0b,
- 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
- 0x85, 0x02, 0x5b, 0x05,
- 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
- 0xd8, 0x14, 0x02, 0x5c,
- 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
- 0x01, 0x08, 0x23, 0x72,
- 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
- 0x12, 0x5e, 0x2b, 0x01,
- 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
- 0x1c, 0xfe, 0xff, 0x7f,
- 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
- 0x57, 0x48, 0x8b, 0x1c,
- 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
- 0x00, 0x57, 0x48, 0x8b,
- 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
- 0x03, 0x0a, 0x50, 0x01,
- 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
- 0x54, 0xfe, 0x00, 0xf4,
- 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
- 0x03, 0x7c, 0x63, 0x27,
- 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
- 0xfe, 0x82, 0x4a, 0xfe,
- 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
- 0x42, 0x48, 0x5f, 0x60,
- 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
- 0x1f, 0xfe, 0xa2, 0x14,
- 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
- 0xcc, 0x12, 0x49, 0x04,
- 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
- 0xe8, 0x13, 0x3b, 0x13,
- 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
- 0xa1, 0xff, 0x02, 0x83,
- 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
- 0x13, 0x06, 0xfe, 0x56,
- 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
- 0x64, 0x00, 0x17, 0x93,
- 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
- 0xc8, 0x00, 0x8e, 0xe4,
- 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
- 0x01, 0xba, 0xfe, 0x4e,
- 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
- 0xfe, 0x60, 0x14, 0xfe,
- 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
- 0xfe, 0x22, 0x13, 0x1c,
- 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
- 0xfe, 0x9c, 0x14, 0xb7,
- 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
- 0xfe, 0x9c, 0x14, 0xb7,
- 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
- 0xfe, 0xb4, 0x56, 0xfe,
- 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
- 0xe5, 0x15, 0x0b, 0x01,
- 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
- 0x49, 0x01, 0x08, 0x03,
- 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
- 0x15, 0x06, 0x01, 0x08,
- 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
- 0x4a, 0x01, 0x08, 0x03,
- 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
- 0xfe, 0x49, 0xf4, 0x00,
- 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
- 0x08, 0x2f, 0x07, 0xfe,
- 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
- 0x01, 0x43, 0x1e, 0xcd,
- 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
- 0xed, 0x88, 0x07, 0x10,
- 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
- 0x80, 0x01, 0x0e, 0x88,
- 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
- 0x88, 0x03, 0x0a, 0x42,
- 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
- 0xfe, 0x80, 0x80, 0xf2,
- 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
- 0x01, 0x82, 0x03, 0x17,
- 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
- 0xfe, 0x24, 0x1c, 0xfe,
- 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
- 0x91, 0x1d, 0x66, 0xfe,
- 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
- 0xda, 0x10, 0x17, 0x10,
- 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
- 0x05, 0xfe, 0x66, 0x01,
- 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
- 0xfe, 0x3c, 0x50, 0x66,
- 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
- 0x40, 0x16, 0xfe, 0xb6,
- 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
- 0x10, 0x71, 0xfe, 0x83,
- 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
- 0xfe, 0x62, 0x16, 0xfe,
- 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
- 0xfe, 0x98, 0xe7, 0x00,
- 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
- 0xfe, 0x30, 0xbc, 0xfe,
- 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
- 0xc5, 0x90, 0xfe, 0x9a,
- 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
- 0x42, 0x10, 0xfe, 0x02,
- 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
- 0xfe, 0x1d, 0xf7, 0x4f,
- 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
- 0x47, 0xfe, 0x83, 0x58,
- 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
- 0xfe, 0xdd, 0x00, 0x63,
- 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
- 0x06, 0x37, 0x95, 0xa9,
- 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
- 0x18, 0x1c, 0x1a, 0x5d,
- 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
- 0xe1, 0x10, 0x78, 0x2c,
- 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
- 0x13, 0x3c, 0x8a, 0x0a,
- 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
- 0xe3, 0xfe, 0x00, 0xcc,
- 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
- 0x0e, 0xf2, 0x01, 0x6f,
- 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
- 0xf6, 0xfe, 0xd6, 0xf0,
- 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
- 0x15, 0x00, 0x59, 0x76,
- 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
- 0x11, 0x2d, 0x01, 0x6f,
- 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
- 0xc8, 0xfe, 0x48, 0x55,
- 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
- 0x99, 0x01, 0x0e, 0xf0,
- 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
- 0x75, 0x03, 0x0a, 0x42,
- 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
- 0x0e, 0x73, 0x75, 0x03,
- 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
- 0xfe, 0x3a, 0x45, 0x5b,
- 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
- 0xfe, 0x02, 0xe6, 0x1b,
- 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
- 0xfe, 0x94, 0x00, 0xfe,
- 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
- 0xe6, 0x2c, 0xfe, 0x4e,
- 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
- 0x03, 0x07, 0x7a, 0xfe,
- 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
- 0x07, 0x1b, 0xfe, 0x5a,
- 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
- 0x24, 0x2c, 0xdc, 0x07,
- 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
- 0x9f, 0xad, 0x03, 0x14,
- 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
- 0x03, 0x25, 0xfe, 0xca,
- 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
- 0x00, 0x00,
-};
-
-static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
-static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
-
-/* Microcode buffer is kept after initialization for error recovery. */
-static unsigned char _adv_asc38C0800_buf[] = {
- 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
- 0x01, 0x00, 0x48, 0xe4,
- 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
- 0x1c, 0x0f, 0x00, 0xf6,
- 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
- 0x09, 0xe7, 0x55, 0xf0,
- 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
- 0x18, 0xf4, 0x08, 0x00,
- 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
- 0x86, 0xf0, 0xb1, 0xf0,
- 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
- 0x3c, 0x00, 0xbb, 0x00,
- 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
- 0xba, 0x13, 0x18, 0x40,
- 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
- 0x6e, 0x01, 0x74, 0x01,
- 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
- 0xc0, 0x00, 0x01, 0x01,
- 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
- 0x08, 0x12, 0x02, 0x4a,
- 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
- 0x5d, 0xf0, 0x02, 0xfa,
- 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
- 0x68, 0x01, 0x6a, 0x01,
- 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
- 0x06, 0x13, 0x4c, 0x1c,
- 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
- 0x0f, 0x00, 0x47, 0x00,
- 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
- 0x4e, 0x1c, 0x10, 0x44,
- 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
- 0x05, 0x00, 0x34, 0x00,
- 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
- 0x42, 0x0c, 0x12, 0x0f,
- 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
- 0x00, 0x4e, 0x42, 0x54,
- 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
- 0x59, 0xf0, 0xb8, 0xf0,
- 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
- 0x19, 0x00, 0x33, 0x00,
- 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
- 0xe7, 0x00, 0xe2, 0x03,
- 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
- 0x12, 0x13, 0x24, 0x14,
- 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
- 0x36, 0x1c, 0x08, 0x44,
- 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
- 0x3a, 0x55, 0x83, 0x55,
- 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
- 0x0c, 0xf0, 0x04, 0xf8,
- 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
- 0xa8, 0x00, 0xaa, 0x00,
- 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
- 0xc4, 0x01, 0xc6, 0x01,
- 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
- 0x68, 0x08, 0x69, 0x08,
- 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
- 0xed, 0x10, 0xf1, 0x10,
- 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
- 0x1e, 0x13, 0x46, 0x14,
- 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
- 0xca, 0x18, 0xe6, 0x19,
- 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
- 0xf0, 0x2b, 0x02, 0xfe,
- 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
- 0xfe, 0x84, 0x01, 0xff,
- 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
- 0x00, 0xfe, 0x57, 0x24,
- 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
- 0x00, 0x00, 0xff, 0x08,
- 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
- 0xff, 0xff, 0xff, 0x11,
- 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
- 0xfe, 0x04, 0xf7, 0xd6,
- 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
- 0x0a, 0x42, 0x2c, 0xfe,
- 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
- 0xfe, 0xf4, 0x01, 0xfe,
- 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
- 0x02, 0xfe, 0xc8, 0x0d,
- 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
- 0x1c, 0x03, 0xfe, 0xa6,
- 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
- 0xf0, 0xfe, 0x8a, 0x02,
- 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
- 0xfe, 0x46, 0xf0, 0xfe,
- 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
- 0x48, 0x02, 0xfe, 0x44,
- 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
- 0xaa, 0x18, 0x06, 0x14,
- 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
- 0x1e, 0x1c, 0xfe, 0xe9,
- 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
- 0x09, 0x70, 0x01, 0xa8,
- 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
- 0x01, 0x87, 0xfe, 0xbd,
- 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
- 0x58, 0x1c, 0x18, 0x06,
- 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
- 0xfe, 0x98, 0x02, 0xfe,
- 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
- 0x01, 0xfe, 0x48, 0x10,
- 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
- 0x69, 0x10, 0x18, 0x06,
- 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
- 0xf6, 0xce, 0x01, 0xfe,
- 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
- 0x82, 0x16, 0x02, 0x2b,
- 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
- 0xfe, 0x41, 0x58, 0x09,
- 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
- 0x82, 0x16, 0x02, 0x2b,
- 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
- 0xfe, 0x77, 0x57, 0xfe,
- 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
- 0xfe, 0x40, 0x1c, 0x1c,
- 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
- 0x03, 0xfe, 0x11, 0xf0,
- 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
- 0xfe, 0x11, 0x00, 0x02,
- 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
- 0x21, 0x22, 0xa3, 0xb7,
- 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
- 0x12, 0xd1, 0x1c, 0xd9,
- 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
- 0xfe, 0xe4, 0x00, 0x27,
- 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
- 0x06, 0xf0, 0xfe, 0xc8,
- 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
- 0x70, 0x28, 0x17, 0xfe,
- 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
- 0xf9, 0x2c, 0x99, 0x19,
- 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
- 0x74, 0x01, 0xaf, 0x8c,
- 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
- 0x8d, 0x51, 0x64, 0x79,
- 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
- 0xfe, 0x6a, 0x02, 0x02,
- 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
- 0xfe, 0x3c, 0x04, 0x3b,
- 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
- 0x00, 0x10, 0x01, 0x0b,
- 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
- 0xfe, 0x4c, 0x44, 0xfe,
- 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
- 0xda, 0x4f, 0x79, 0x2a,
- 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
- 0xfe, 0x2a, 0x13, 0x32,
- 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
- 0x54, 0x6b, 0xda, 0xfe,
- 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
- 0x08, 0x13, 0x32, 0x07,
- 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
- 0x08, 0x05, 0x06, 0x4d,
- 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
- 0x2d, 0x12, 0xfe, 0xe6,
- 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
- 0x02, 0x2b, 0xfe, 0x42,
- 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
- 0xfe, 0x87, 0x80, 0xfe,
- 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
- 0x07, 0x19, 0xfe, 0x7c,
- 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
- 0x17, 0xfe, 0x90, 0x05,
- 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
- 0xa0, 0x00, 0x28, 0xfe,
- 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
- 0x34, 0xfe, 0x89, 0x48,
- 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
- 0x12, 0xfe, 0xe3, 0x00,
- 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
- 0x70, 0x05, 0x88, 0x25,
- 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
- 0x09, 0x48, 0xff, 0x02,
- 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
- 0x08, 0x53, 0x05, 0xcb,
- 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
- 0x05, 0x1b, 0xfe, 0x22,
- 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
- 0x0d, 0x00, 0x01, 0x36,
- 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
- 0x03, 0x5c, 0x28, 0xfe,
- 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
- 0x05, 0x1f, 0xfe, 0x02,
- 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
- 0x01, 0x4b, 0x12, 0xfe,
- 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
- 0x12, 0x03, 0x45, 0x28,
- 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
- 0x43, 0x48, 0xc4, 0xcc,
- 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
- 0x6e, 0x41, 0x01, 0xb2,
- 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
- 0xfe, 0xcc, 0x15, 0x1d,
- 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
- 0x45, 0xc1, 0x0c, 0x45,
- 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
- 0xe2, 0x00, 0x27, 0xdb,
- 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
- 0xfe, 0x06, 0xf0, 0xfe,
- 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
- 0x16, 0x19, 0x01, 0x0b,
- 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
- 0xfe, 0x99, 0xa4, 0x01,
- 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
- 0x12, 0x08, 0x05, 0x1a,
- 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
- 0x0b, 0x16, 0x00, 0x01,
- 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
- 0xe2, 0x6c, 0x58, 0xbe,
- 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
- 0xfe, 0x09, 0x6f, 0xba,
- 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
- 0xfe, 0x54, 0x07, 0x1c,
- 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
- 0x07, 0x02, 0x24, 0x01,
- 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
- 0x2c, 0x90, 0xfe, 0xae,
- 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
- 0x37, 0x22, 0x20, 0x07,
- 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
- 0xfe, 0x06, 0x10, 0xfe,
- 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
- 0x37, 0x01, 0xb3, 0xb8,
- 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
- 0x50, 0xfe, 0x44, 0x51,
- 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
- 0x14, 0x5f, 0xfe, 0x0c,
- 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
- 0x14, 0x3e, 0xfe, 0x4a,
- 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
- 0x90, 0x0c, 0x60, 0x14,
- 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
- 0xfe, 0x44, 0x90, 0xfe,
- 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
- 0x0c, 0x5e, 0x14, 0x5f,
- 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
- 0x14, 0x3c, 0x21, 0x0c,
- 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
- 0x27, 0xdd, 0xfe, 0x9e,
- 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
- 0x9a, 0x08, 0xc6, 0xfe,
- 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
- 0x95, 0x86, 0x02, 0x24,
- 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
- 0x06, 0xfe, 0x10, 0x12,
- 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
- 0x1c, 0x02, 0xfe, 0x18,
- 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
- 0x2c, 0x1c, 0xfe, 0xaa,
- 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
- 0xde, 0x09, 0xfe, 0xb7,
- 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
- 0xfe, 0xf1, 0x18, 0xfe,
- 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
- 0x14, 0x59, 0xfe, 0x95,
- 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
- 0xfe, 0xf0, 0x08, 0xb5,
- 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
- 0x0b, 0xb6, 0xfe, 0xbf,
- 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
- 0x12, 0xc2, 0xfe, 0xd2,
- 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
- 0x06, 0x17, 0x85, 0xc5,
- 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
- 0x9d, 0x01, 0x36, 0x10,
- 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
- 0x98, 0x80, 0xfe, 0x19,
- 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
- 0xfe, 0x44, 0x54, 0xbe,
- 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
- 0x02, 0x4a, 0x08, 0x05,
- 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
- 0x9c, 0x3c, 0xfe, 0x6c,
- 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
- 0x3b, 0x40, 0x03, 0x49,
- 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
- 0x8f, 0xfe, 0xe3, 0x54,
- 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
- 0xda, 0x09, 0xfe, 0x8b,
- 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
- 0x0a, 0x3a, 0x49, 0x3b,
- 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
- 0xad, 0xfe, 0x01, 0x59,
- 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
- 0x49, 0x8f, 0xfe, 0xe3,
- 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
- 0x4a, 0x3a, 0x49, 0x3b,
- 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
- 0x02, 0x4a, 0x08, 0x05,
- 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
- 0xb7, 0xfe, 0x03, 0xa1,
- 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
- 0xfe, 0x86, 0x91, 0x6a,
- 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
- 0x61, 0x0c, 0x7f, 0x14,
- 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
- 0x9b, 0x2e, 0x9c, 0x3c,
- 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
- 0xfa, 0x3c, 0x01, 0xef,
- 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
- 0xe4, 0x08, 0x05, 0x1f,
- 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
- 0x03, 0x5e, 0x29, 0x5f,
- 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
- 0xf4, 0x09, 0x08, 0x05,
- 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
- 0x81, 0x50, 0xfe, 0x10,
- 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
- 0x08, 0x09, 0x12, 0xa6,
- 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
- 0x08, 0x09, 0xfe, 0x0c,
- 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
- 0x08, 0x05, 0x0a, 0xfe,
- 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
- 0xf0, 0xe2, 0x15, 0x7e,
- 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
- 0x57, 0x3d, 0xfe, 0xed,
- 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
- 0x00, 0xff, 0x35, 0xfe,
- 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
- 0x1e, 0x19, 0x8a, 0x03,
- 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
- 0xfe, 0xd1, 0xf0, 0xfe,
- 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
- 0x10, 0xfe, 0xce, 0xf0,
- 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
- 0x10, 0xfe, 0x22, 0x00,
- 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
- 0x02, 0x65, 0xfe, 0xd0,
- 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
- 0x0b, 0x10, 0x58, 0xfe,
- 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
- 0x12, 0x00, 0x2c, 0x0f,
- 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
- 0x0c, 0xbc, 0x17, 0x34,
- 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
- 0x0c, 0x1c, 0x34, 0x94,
- 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
- 0x4b, 0xfe, 0xdb, 0x10,
- 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
- 0x89, 0xf0, 0x24, 0x33,
- 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
- 0x33, 0x31, 0xdf, 0xbc,
- 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
- 0x17, 0xfe, 0x2c, 0x0d,
- 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
- 0x12, 0x55, 0xfe, 0x28,
- 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
- 0x44, 0xfe, 0x28, 0x00,
- 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
- 0x0f, 0x64, 0x12, 0x2f,
- 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
- 0x0a, 0xfe, 0xb4, 0x10,
- 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
- 0xfe, 0x34, 0x46, 0xac,
- 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
- 0x37, 0x01, 0xf5, 0x01,
- 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
- 0xfe, 0x2e, 0x03, 0x08,
- 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
- 0x1a, 0xfe, 0x58, 0x12,
- 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
- 0xfe, 0x50, 0x0d, 0xfe,
- 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
- 0xfe, 0xa9, 0x10, 0x10,
- 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
- 0xfe, 0x13, 0x00, 0xfe,
- 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
- 0x24, 0x00, 0x8c, 0xb5,
- 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
- 0xfe, 0x9d, 0x41, 0xfe,
- 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
- 0xb4, 0x15, 0xfe, 0x31,
- 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
- 0xec, 0xd0, 0xfc, 0x44,
- 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
- 0x4b, 0x91, 0xfe, 0x75,
- 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
- 0x0e, 0xfe, 0x44, 0x48,
- 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
- 0xfe, 0x41, 0x58, 0x09,
- 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
- 0x2e, 0x03, 0x09, 0x5d,
- 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
- 0xce, 0x47, 0xfe, 0xad,
- 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
- 0x59, 0x13, 0x9f, 0x13,
- 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
- 0xe0, 0x0e, 0x0f, 0x06,
- 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
- 0x3a, 0x01, 0x56, 0xfe,
- 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
- 0x20, 0x4f, 0xfe, 0x05,
- 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
- 0x48, 0xf4, 0x0d, 0xfe,
- 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
- 0x15, 0x1a, 0x39, 0xa0,
- 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
- 0x0c, 0xfe, 0x60, 0x01,
- 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
- 0x06, 0x13, 0x2f, 0x12,
- 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
- 0x22, 0x9f, 0xb7, 0x13,
- 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
- 0xa0, 0xb4, 0xfe, 0xd9,
- 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
- 0xc3, 0xfe, 0x03, 0xdc,
- 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
- 0xfe, 0x00, 0xcc, 0x04,
- 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
- 0xfe, 0x1c, 0x80, 0x07,
- 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
- 0xfe, 0x0c, 0x90, 0xfe,
- 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
- 0x0a, 0xfe, 0x3c, 0x50,
- 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
- 0x16, 0x08, 0x05, 0x1b,
- 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
- 0xfe, 0x2c, 0x13, 0x01,
- 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
- 0x0c, 0xfe, 0x64, 0x01,
- 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
- 0x80, 0x8d, 0xfe, 0x01,
- 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
- 0x22, 0x20, 0xfb, 0x79,
- 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
- 0x03, 0xfe, 0xae, 0x00,
+ if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+ warn_code |= ASC_WARN_AUTO_CONFIG;
+ }
+#ifdef CONFIG_PCI
+ if (asc_dvc->bus_type & ASC_IS_PCI) {
+ cfg_msw &= 0xFFC0;
+ AscSetChipCfgMsw(iop_base, cfg_msw);
+ if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
+ } else {
+ if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
+ (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
+ asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
+ asc_dvc->bug_fix_cntl |=
+ ASC_BUG_FIX_ASYN_USE_SYN;
+ }
+ }
+ } else
+#endif /* CONFIG_PCI */
+ if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
+ if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
+ == ASC_CHIP_VER_ASYN_BUG) {
+ asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
+ }
+ }
+ if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
+ asc_dvc->cfg->chip_scsi_id) {
+ asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
+ }
+#ifdef CONFIG_ISA
+ if (asc_dvc->bus_type & ASC_IS_ISA) {
+ AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
+ AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
+ }
+#endif /* CONFIG_ISA */
- 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
- 0xb2, 0x00, 0xfe, 0x09,
- 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
- 0x45, 0x0f, 0x46, 0x52,
- 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
- 0x0f, 0x44, 0x11, 0x0f,
- 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
- 0x25, 0x11, 0x13, 0x20,
- 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
- 0x56, 0xfe, 0xd6, 0xf0,
- 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
- 0x18, 0x1c, 0x04, 0x42,
- 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
- 0xf5, 0x13, 0x04, 0x01,
- 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
- 0x13, 0x32, 0x07, 0x2f,
- 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
- 0x41, 0x48, 0xfe, 0x45,
- 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
- 0x07, 0x11, 0xac, 0x09,
- 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
- 0x82, 0x4e, 0xfe, 0x14,
- 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
- 0xfe, 0x01, 0xec, 0xa2,
- 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
- 0x2a, 0x01, 0xe3, 0xfe,
- 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
- 0xfe, 0x48, 0x12, 0x07,
- 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
- 0xfe, 0x32, 0x12, 0x07,
- 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
- 0x1f, 0xfe, 0x12, 0x12,
- 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
- 0x94, 0x4b, 0x04, 0x2d,
- 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
- 0x32, 0x07, 0xa6, 0xfe,
- 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
- 0x5a, 0xfe, 0x72, 0x12,
- 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
- 0xfe, 0x26, 0x13, 0x03,
- 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
- 0x0c, 0x7f, 0x0c, 0x80,
- 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
- 0x3c, 0xfe, 0x04, 0x55,
- 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
- 0x91, 0x10, 0x03, 0x3f,
- 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
- 0x88, 0x9b, 0x2e, 0x9c,
- 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
- 0x56, 0x0c, 0x5e, 0x14,
- 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
- 0x03, 0x60, 0x29, 0x61,
- 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
- 0x50, 0xfe, 0xc6, 0x50,
- 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
- 0x29, 0x3e, 0xfe, 0x40,
- 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
- 0x2d, 0x01, 0x0b, 0x1d,
- 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
- 0x72, 0x01, 0xaf, 0x1e,
- 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
- 0x0a, 0x55, 0x35, 0xfe,
- 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
- 0x02, 0x72, 0xfe, 0x19,
- 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
- 0x1d, 0xe8, 0x33, 0x31,
- 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
- 0x0b, 0x1c, 0x34, 0x1d,
- 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
- 0x33, 0x31, 0xfe, 0xe8,
- 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
- 0x05, 0x1f, 0x35, 0xa9,
- 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
- 0x14, 0x01, 0xaf, 0x8c,
- 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
- 0x03, 0x45, 0x28, 0x35,
- 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
- 0x03, 0x5c, 0xc1, 0x0c,
- 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
- 0x89, 0x01, 0x0b, 0x1c,
- 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
- 0xfe, 0x42, 0x58, 0xf1,
- 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
- 0xf4, 0x06, 0xea, 0x32,
- 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
- 0x01, 0x0b, 0x26, 0x89,
- 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
- 0x26, 0xfe, 0xd4, 0x13,
- 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
- 0x13, 0x1c, 0xfe, 0xd0,
- 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
- 0x0f, 0x71, 0xff, 0x02,
- 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
- 0x00, 0x5c, 0x04, 0x0f,
- 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
- 0xfe, 0x00, 0x5c, 0x04,
- 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
- 0x02, 0x00, 0x57, 0x52,
- 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
- 0x87, 0x04, 0xfe, 0x03,
- 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
- 0xfe, 0x00, 0x7d, 0xfe,
- 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
- 0x14, 0x5f, 0x57, 0x3f,
- 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
- 0x5a, 0x8d, 0x04, 0x01,
- 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
- 0xfe, 0x96, 0x15, 0x33,
- 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
- 0x0a, 0xfe, 0xc1, 0x59,
- 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
- 0x21, 0x69, 0x1a, 0xee,
- 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
- 0x30, 0xfe, 0x78, 0x10,
- 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
- 0x98, 0xfe, 0x30, 0x00,
- 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
- 0x98, 0xfe, 0x64, 0x00,
- 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
- 0x10, 0x69, 0x06, 0xfe,
- 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
- 0x18, 0x59, 0x0f, 0x06,
- 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
- 0x43, 0xf4, 0x9f, 0xfe,
- 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
- 0x9e, 0xfe, 0xf3, 0x10,
- 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
- 0x17, 0xfe, 0x4d, 0xe4,
- 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
- 0x17, 0xfe, 0x4d, 0xe4,
- 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
- 0xf4, 0x00, 0xe9, 0x91,
- 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
- 0x04, 0x16, 0x06, 0x01,
- 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
- 0x0b, 0x26, 0xf3, 0x76,
- 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
- 0x16, 0x19, 0x01, 0x0b,
- 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
- 0x0b, 0x26, 0xb1, 0x76,
- 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
- 0xfe, 0x48, 0x13, 0xb8,
- 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
- 0xec, 0xfe, 0x27, 0x01,
- 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
- 0x07, 0xfe, 0xe3, 0x00,
- 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
- 0x22, 0xd4, 0x07, 0x06,
- 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
- 0x07, 0x11, 0xae, 0x09,
- 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
- 0x0e, 0x8e, 0xfe, 0x80,
- 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
- 0x09, 0x48, 0x01, 0x0e,
- 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
- 0x80, 0xfe, 0x80, 0x4c,
- 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
- 0x09, 0x5d, 0x01, 0x87,
- 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
- 0x19, 0xde, 0xfe, 0x24,
- 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
- 0x17, 0xad, 0x9a, 0x1b,
- 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
- 0x16, 0xfe, 0xda, 0x10,
- 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
- 0x18, 0x58, 0x03, 0xfe,
- 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
- 0xf4, 0x06, 0xfe, 0x3c,
- 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
- 0x97, 0xfe, 0x38, 0x17,
- 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
- 0x10, 0x18, 0x11, 0x75,
- 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
- 0x2e, 0x97, 0xfe, 0x5a,
- 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
- 0xfe, 0x98, 0xe7, 0x00,
- 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
- 0xfe, 0x30, 0xbc, 0xfe,
- 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
- 0xcb, 0x97, 0xfe, 0x92,
- 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
- 0x42, 0x10, 0xfe, 0x02,
- 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
- 0x03, 0xa1, 0xfe, 0x1d,
- 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
- 0x9a, 0x5b, 0x41, 0xfe,
- 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
- 0x11, 0x12, 0xfe, 0xdd,
- 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
- 0x17, 0x15, 0x06, 0x39,
- 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
- 0xfe, 0x7e, 0x18, 0x1e,
- 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
- 0x12, 0xfe, 0xe1, 0x10,
- 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
- 0x13, 0x42, 0x92, 0x09,
- 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
- 0xf0, 0xfe, 0x00, 0xcc,
- 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
- 0x0e, 0xfe, 0x80, 0x4c,
- 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
- 0x24, 0x12, 0xfe, 0x14,
- 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
- 0xe7, 0x0a, 0x10, 0xfe,
- 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
- 0x08, 0x54, 0x1b, 0x37,
- 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
- 0x90, 0x3a, 0xce, 0x3b,
- 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
- 0x13, 0xa3, 0x04, 0x09,
- 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
- 0x44, 0x17, 0xfe, 0xe8,
- 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
- 0x5d, 0x01, 0xa8, 0x09,
- 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
- 0x1c, 0x19, 0x03, 0xfe,
- 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
- 0x6b, 0xfe, 0x2e, 0x19,
- 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
- 0xfe, 0x0b, 0x00, 0x6b,
- 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
- 0x08, 0x10, 0x03, 0xfe,
- 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
- 0x04, 0x68, 0x54, 0xe7,
- 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
- 0x1a, 0xf4, 0xfe, 0x00,
- 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
- 0x04, 0x07, 0x7e, 0xfe,
- 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
- 0x07, 0x1a, 0xfe, 0x5a,
- 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
- 0x25, 0x6d, 0xe5, 0x07,
- 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
- 0xa9, 0xb8, 0x04, 0x15,
- 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
- 0x40, 0x5c, 0x04, 0x1c,
- 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
- 0xf7, 0xfe, 0x82, 0xf0,
- 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
-};
+ asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
-static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
-static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
+ switch (warn_code) {
+ case 0: /* No error. */
+ break;
+ case ASC_WARN_IO_PORT_ROTATE:
+ shost_printk(KERN_WARNING, shost, "I/O port address "
+ "modified\n");
+ break;
+ case ASC_WARN_AUTO_CONFIG:
+ shost_printk(KERN_WARNING, shost, "I/O port increment switch "
+ "enabled\n");
+ break;
+ case ASC_WARN_EEPROM_CHKSUM:
+ shost_printk(KERN_WARNING, shost, "EEPROM checksum error\n");
+ break;
+ case ASC_WARN_IRQ_MODIFIED:
+ shost_printk(KERN_WARNING, shost, "IRQ modified\n");
+ break;
+ case ASC_WARN_CMD_QNG_CONFLICT:
+ shost_printk(KERN_WARNING, shost, "tag queuing w/o "
+ "disconnects\n");
+ break;
+ default:
+ shost_printk(KERN_WARNING, shost, "unknown warning: 0x%x\n",
+ warn_code);
+ break;
+ }
-/* Microcode buffer is kept after initialization for error recovery. */
-static unsigned char _adv_asc38C1600_buf[] = {
- 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
- 0x18, 0xe4, 0x01, 0x00,
- 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
- 0x07, 0x17, 0xc0, 0x5f,
- 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
- 0x85, 0xf0, 0x86, 0xf0,
- 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
- 0x98, 0x57, 0x01, 0xe6,
- 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
- 0x38, 0x54, 0x32, 0xf0,
- 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
- 0x00, 0xe6, 0xb1, 0xf0,
- 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
- 0x06, 0x13, 0x0c, 0x1c,
- 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
- 0xb9, 0x54, 0x00, 0x80,
- 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
- 0x03, 0xe6, 0x01, 0xea,
- 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
- 0x04, 0x13, 0xbb, 0x55,
- 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
- 0xbb, 0x00, 0xc0, 0x00,
- 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
- 0x4c, 0x1c, 0x4e, 0x1c,
- 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
- 0x24, 0x01, 0x3c, 0x01,
- 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
- 0x78, 0x01, 0x7c, 0x01,
- 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
- 0x6e, 0x1e, 0x02, 0x48,
- 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
- 0x03, 0xfc, 0x06, 0x00,
- 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
- 0x30, 0x1c, 0x38, 0x1c,
- 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
- 0x5d, 0xf0, 0xa7, 0xf0,
- 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
- 0x33, 0x00, 0x34, 0x00,
- 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
- 0x79, 0x01, 0x3c, 0x09,
- 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
- 0x40, 0x16, 0x50, 0x16,
- 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
- 0x05, 0xf0, 0x09, 0xf0,
- 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
- 0x9c, 0x00, 0xa4, 0x00,
- 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
- 0xe9, 0x09, 0x5c, 0x0c,
- 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
- 0x42, 0x1d, 0x08, 0x44,
- 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
- 0x83, 0x55, 0x83, 0x59,
- 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
- 0x4b, 0xf4, 0x04, 0xf8,
- 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
- 0xa8, 0x00, 0xaa, 0x00,
- 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
- 0x7a, 0x01, 0x82, 0x01,
- 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
- 0x68, 0x08, 0x10, 0x0d,
- 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
- 0xf3, 0x10, 0x06, 0x12,
- 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
- 0xf0, 0x35, 0x05, 0xfe,
- 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
- 0xfe, 0x88, 0x01, 0xff,
- 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
- 0x00, 0xfe, 0x57, 0x24,
- 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
- 0x00, 0x00, 0xff, 0x08,
- 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
- 0xff, 0xff, 0xff, 0x13,
- 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
- 0xfe, 0x04, 0xf7, 0xe8,
- 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
- 0x0d, 0x51, 0x37, 0xfe,
- 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
- 0xfe, 0xf8, 0x01, 0xfe,
- 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
- 0x05, 0xfe, 0x08, 0x0f,
- 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
- 0x28, 0x1c, 0x03, 0xfe,
- 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
- 0x48, 0xf0, 0xfe, 0x90,
- 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
- 0x02, 0xfe, 0x46, 0xf0,
- 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
- 0xfe, 0x4e, 0x02, 0xfe,
- 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
- 0x0d, 0xa2, 0x1c, 0x07,
- 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
- 0x1c, 0xf5, 0xfe, 0x1e,
- 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
- 0xde, 0x0a, 0x81, 0x01,
- 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
- 0x81, 0x01, 0x5c, 0xfe,
- 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
- 0xfe, 0x58, 0x1c, 0x1c,
- 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
- 0x2b, 0xfe, 0x9e, 0x02,
- 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
- 0x00, 0x47, 0xb8, 0x01,
- 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
- 0x1a, 0x31, 0xfe, 0x69,
- 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
- 0x1e, 0x1e, 0x20, 0x2c,
- 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
- 0x44, 0x15, 0x56, 0x51,
- 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
- 0x01, 0x18, 0x09, 0x00,
- 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
- 0x18, 0xfe, 0xc8, 0x54,
- 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
- 0xfe, 0x02, 0xe8, 0x30,
- 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
- 0xfe, 0xe4, 0x01, 0xfe,
- 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
- 0x26, 0xf0, 0xfe, 0x66,
- 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
- 0xef, 0x10, 0xfe, 0x9f,
- 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
- 0x70, 0x37, 0xfe, 0x48,
- 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
- 0x21, 0xb9, 0xc7, 0x20,
- 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
- 0xe1, 0x2a, 0xeb, 0xfe,
- 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
- 0x15, 0xfe, 0xe4, 0x00,
- 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
- 0xfe, 0x06, 0xf0, 0xfe,
- 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
- 0x03, 0x81, 0x1e, 0x1b,
- 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
- 0xea, 0xfe, 0x46, 0x1c,
- 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
- 0xfe, 0x48, 0x1c, 0x75,
- 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
- 0xe1, 0x01, 0x18, 0x77,
- 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
- 0x8f, 0xfe, 0x70, 0x02,
- 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
- 0x16, 0xfe, 0x4a, 0x04,
- 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
- 0x02, 0x00, 0x10, 0x01,
- 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
- 0xee, 0xfe, 0x4c, 0x44,
- 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
- 0x7b, 0xec, 0x60, 0x8d,
- 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
- 0x0c, 0x06, 0x28, 0xfe,
- 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
- 0x13, 0x34, 0xfe, 0x4c,
- 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
- 0x13, 0x01, 0x0c, 0x06,
- 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
- 0x28, 0xf9, 0x1f, 0x7f,
- 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
- 0xfe, 0xa4, 0x0e, 0x05,
- 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
- 0x9c, 0x93, 0x3a, 0x0b,
- 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
- 0x7d, 0x1d, 0xfe, 0x46,
- 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
- 0xfe, 0x87, 0x83, 0xfe,
- 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
- 0x13, 0x0f, 0xfe, 0x20,
- 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
- 0x12, 0x01, 0x38, 0x06,
- 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
- 0x05, 0xd0, 0x54, 0x01,
- 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
- 0x50, 0x12, 0x5e, 0xff,
- 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
- 0x00, 0x10, 0x2f, 0xfe,
- 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
- 0x38, 0xfe, 0x4a, 0xf0,
- 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
- 0x21, 0x00, 0xf1, 0x2e,
- 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
- 0x10, 0x2f, 0xfe, 0xd0,
- 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
- 0x1c, 0x00, 0x4d, 0x01,
- 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
- 0x28, 0xfe, 0x24, 0x12,
- 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
- 0x0d, 0x00, 0x01, 0x42,
- 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
- 0x03, 0xb6, 0x1e, 0xfe,
- 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
- 0xfe, 0x72, 0x06, 0x0a,
- 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
- 0x19, 0x16, 0xfe, 0x68,
- 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
- 0x03, 0x9a, 0x1e, 0xfe,
- 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
- 0x48, 0xfe, 0x92, 0x06,
- 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
- 0x58, 0xff, 0x02, 0x00,
- 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
- 0xfe, 0xea, 0x06, 0x01,
- 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
- 0xfe, 0xe0, 0x06, 0x15,
- 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
- 0x01, 0x84, 0xfe, 0xae,
- 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
- 0x1e, 0xfe, 0x1a, 0x12,
- 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
- 0x43, 0x48, 0x62, 0x80,
- 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
- 0x36, 0xfe, 0x02, 0xf6,
- 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
- 0xd0, 0x0d, 0x17, 0xfe,
- 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
- 0x9e, 0x15, 0x82, 0x01,
- 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
- 0x57, 0x10, 0xe6, 0x05,
- 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
- 0xfe, 0x9c, 0x32, 0x5f,
- 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
- 0xfe, 0x0a, 0xf0, 0xfe,
- 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
- 0xaf, 0xa0, 0x05, 0x29,
- 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
- 0x00, 0x01, 0x08, 0x14,
- 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
- 0x14, 0x00, 0x05, 0xfe,
- 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
- 0x12, 0xfe, 0x30, 0x13,
- 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
- 0x01, 0x08, 0x14, 0x00,
- 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
- 0x78, 0x4f, 0x0f, 0xfe,
- 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
- 0x28, 0x48, 0xfe, 0x6c,
- 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
- 0x12, 0x53, 0x63, 0x4e,
- 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
- 0x6c, 0x08, 0xaf, 0xa0,
- 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
- 0x05, 0xed, 0xfe, 0x9c,
- 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
- 0x1e, 0xfe, 0x99, 0x58,
- 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
- 0x22, 0x6b, 0x01, 0x0c,
- 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
- 0x1e, 0x47, 0x2c, 0x7a,
- 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
- 0x01, 0x0c, 0x61, 0x65,
- 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
- 0x16, 0xfe, 0x08, 0x50,
- 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
- 0x01, 0xfe, 0xce, 0x1e,
- 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
- 0x01, 0xfe, 0xfe, 0x1e,
- 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
- 0x10, 0x01, 0x0c, 0x06,
- 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
- 0x10, 0x6a, 0x22, 0x6b,
- 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
- 0xfe, 0x9f, 0x83, 0x33,
- 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
- 0x3a, 0x0b, 0xfe, 0xc6,
- 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
- 0x01, 0xfe, 0xce, 0x1e,
- 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
- 0x04, 0xfe, 0xc0, 0x93,
- 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
- 0x10, 0x4b, 0x22, 0x4c,
- 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
- 0x4e, 0x11, 0x2f, 0xfe,
- 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
- 0x3c, 0x37, 0x88, 0xf5,
- 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
- 0xd3, 0xfe, 0x42, 0x0a,
- 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
- 0x05, 0x29, 0x01, 0x41,
- 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
- 0xfe, 0x14, 0x12, 0x01,
- 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
- 0x2e, 0x1c, 0x05, 0xfe,
- 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
- 0xfe, 0x2c, 0x1c, 0xfe,
- 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
- 0x92, 0x10, 0xc4, 0xf6,
- 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
- 0xe7, 0x10, 0xfe, 0x2b,
- 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
- 0xac, 0xfe, 0xd2, 0xf0,
- 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
- 0x1b, 0xbf, 0xd4, 0x5b,
- 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
- 0x5e, 0x32, 0x1f, 0x7f,
- 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
- 0x05, 0x70, 0xfe, 0x74,
- 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
- 0x0f, 0x4d, 0x01, 0xfe,
- 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
- 0x0d, 0x2b, 0xfe, 0xe2,
- 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
- 0xfe, 0x88, 0x13, 0x21,
- 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
- 0x83, 0x83, 0xfe, 0xc9,
- 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
- 0x91, 0x04, 0xfe, 0x84,
- 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
- 0xfe, 0xcb, 0x57, 0x0b,
- 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
- 0x6a, 0x3b, 0x6b, 0x10,
- 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
- 0x20, 0x6e, 0xdb, 0x64,
- 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
- 0xfe, 0x04, 0xfa, 0x64,
- 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
- 0x10, 0x98, 0x91, 0x6c,
- 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
- 0x4b, 0x7e, 0x4c, 0x01,
- 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
- 0x58, 0xfe, 0x91, 0x58,
- 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
- 0x1b, 0x40, 0x01, 0x0c,
- 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
- 0xfe, 0x10, 0x90, 0x04,
- 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
- 0x79, 0x0b, 0x0e, 0xfe,
- 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
- 0x01, 0x0c, 0x06, 0x0d,
- 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
- 0x0c, 0x58, 0xfe, 0x8d,
- 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
- 0x83, 0x33, 0x0b, 0x0e,
- 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
- 0x19, 0xfe, 0x19, 0x41,
- 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
- 0x19, 0xfe, 0x44, 0x00,
- 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
- 0x4c, 0xfe, 0x0c, 0x51,
- 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
- 0x76, 0x10, 0xac, 0xfe,
- 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
- 0xe3, 0x23, 0x07, 0xfe,
- 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
- 0xcc, 0x0c, 0x1f, 0x92,
- 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
- 0x0c, 0xfe, 0x3e, 0x10,
- 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
- 0xfe, 0xcb, 0xf0, 0xfe,
- 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
- 0xf4, 0x0c, 0x19, 0x94,
- 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
- 0xfe, 0xcc, 0xf0, 0xef,
- 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
- 0x4e, 0x11, 0x2f, 0xfe,
- 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
- 0x3c, 0x37, 0x88, 0xf5,
- 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
- 0x2f, 0xfe, 0x3e, 0x0d,
- 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
- 0xd2, 0x9f, 0xd3, 0x9f,
- 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
- 0xc5, 0x75, 0xd7, 0x99,
- 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
- 0x9c, 0x2f, 0xfe, 0x8c,
- 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
- 0x42, 0x00, 0x05, 0x70,
- 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
- 0x0d, 0xfe, 0x44, 0x13,
- 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
- 0xfe, 0xda, 0x0e, 0x0a,
- 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
- 0x10, 0x01, 0xfe, 0xf4,
- 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
- 0x15, 0x56, 0x01, 0x85,
- 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
- 0xcc, 0x10, 0x01, 0xa7,
- 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
- 0xfe, 0x99, 0x83, 0xfe,
- 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
- 0x43, 0x00, 0xfe, 0xa2,
- 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
- 0x00, 0x1d, 0x40, 0x15,
- 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
- 0xfe, 0x3a, 0x03, 0x01,
- 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
- 0x76, 0x06, 0x12, 0xfe,
- 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
- 0xfe, 0x9d, 0xf0, 0xfe,
- 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
- 0x0c, 0x61, 0x12, 0x44,
- 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
- 0xfe, 0x2e, 0x10, 0x19,
- 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
- 0xfe, 0x41, 0x00, 0xa2,
- 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
- 0xea, 0x4f, 0xfe, 0x04,
- 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
- 0x35, 0xfe, 0x12, 0x1c,
- 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
- 0xfe, 0xd4, 0x11, 0x05,
- 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
- 0xce, 0x45, 0x31, 0x51,
- 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
- 0x67, 0xfe, 0x98, 0x56,
- 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
- 0x0c, 0x06, 0x28, 0xfe,
- 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
- 0xfe, 0xfa, 0x14, 0xfe,
- 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
- 0xfe, 0xe0, 0x14, 0xfe,
- 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
- 0xfe, 0xad, 0x13, 0x05,
- 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
- 0xe7, 0xfe, 0x08, 0x1c,
- 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
- 0x48, 0x55, 0xa5, 0x3b,
- 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
- 0xf0, 0x1a, 0x03, 0xfe,
- 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
- 0xec, 0xe7, 0x53, 0x00,
- 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
- 0x01, 0xfe, 0x62, 0x1b,
- 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
- 0xea, 0xe7, 0x53, 0x92,
- 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
- 0xfe, 0x38, 0x01, 0x23,
- 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
- 0x01, 0x01, 0xfe, 0x1e,
- 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
- 0x26, 0x02, 0x21, 0x96,
- 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
- 0xc3, 0xfe, 0xe1, 0x10,
- 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
- 0xfe, 0x03, 0xdc, 0xfe,
- 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
- 0x00, 0xcc, 0x02, 0xfe,
- 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
- 0x0f, 0xfe, 0x1c, 0x80,
- 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
- 0x0f, 0xfe, 0x1e, 0x80,
- 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
- 0x1d, 0x80, 0x04, 0xfe,
- 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
- 0x1e, 0xac, 0xfe, 0x14,
- 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
- 0x1f, 0xfe, 0x30, 0xf4,
- 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
- 0x56, 0xfb, 0x01, 0xfe,
- 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
- 0xfe, 0x00, 0x1d, 0x15,
- 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
- 0x22, 0x1b, 0xfe, 0x1e,
- 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
- 0x96, 0x90, 0x04, 0xfe,
- 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
- 0x01, 0x01, 0x0c, 0x06,
- 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
- 0x0e, 0x77, 0xfe, 0x01,
- 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
- 0x21, 0x2c, 0xfe, 0x00,
- 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
- 0x06, 0x58, 0x03, 0xfe,
- 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
- 0x03, 0xfe, 0xb2, 0x00,
- 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
- 0x66, 0x10, 0x55, 0x10,
- 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
- 0x54, 0x2b, 0xfe, 0x88,
- 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
- 0x91, 0x54, 0x2b, 0xfe,
- 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
- 0x00, 0x40, 0x8d, 0x2c,
- 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
- 0x12, 0x1c, 0x75, 0xfe,
- 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
- 0x14, 0xfe, 0x0e, 0x47,
- 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
- 0xa7, 0x90, 0x34, 0x60,
- 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
- 0x09, 0x56, 0xfe, 0x34,
- 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
- 0xfe, 0x45, 0x48, 0x01,
- 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
- 0x09, 0x1a, 0xa5, 0x0a,
- 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
- 0xfe, 0x14, 0x56, 0xfe,
- 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
- 0xec, 0xb8, 0xfe, 0x9e,
- 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
- 0xf4, 0xfe, 0xdd, 0x10,
- 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
- 0x12, 0x09, 0x0d, 0xfe,
- 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
- 0x13, 0x09, 0xfe, 0x23,
- 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
- 0x24, 0xfe, 0x12, 0x12,
- 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
- 0xae, 0x41, 0x02, 0x32,
- 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
- 0x35, 0x32, 0x01, 0x43,
- 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
- 0x13, 0x01, 0x0c, 0x06,
- 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
- 0xe5, 0x55, 0xb0, 0xfe,
- 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
- 0xfe, 0xb6, 0x0e, 0x10,
- 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
- 0x88, 0x20, 0x6e, 0x01,
- 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
- 0x55, 0xfe, 0x04, 0xfa,
- 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
- 0xfe, 0x40, 0x56, 0xfe,
- 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
- 0x44, 0x55, 0xfe, 0xe5,
- 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
- 0x68, 0x22, 0x69, 0x01,
- 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
- 0x6b, 0xfe, 0x2c, 0x50,
- 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
- 0x50, 0x03, 0x68, 0x3b,
- 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
- 0x40, 0x50, 0xfe, 0xc2,
- 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
- 0x16, 0x3d, 0x27, 0x25,
- 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
- 0xa6, 0x23, 0x3f, 0x1b,
- 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
- 0xfe, 0x0a, 0x55, 0x31,
- 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
- 0x51, 0x05, 0x72, 0x01,
- 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
- 0x2a, 0x3c, 0x16, 0xc0,
- 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
- 0xfe, 0x66, 0x15, 0x05,
- 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
- 0x2b, 0x3d, 0x01, 0x08,
- 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
- 0xb6, 0x1e, 0x83, 0x01,
- 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
- 0x07, 0x90, 0x3f, 0x01,
- 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
- 0x01, 0x43, 0x09, 0x82,
- 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
- 0x05, 0x72, 0xfe, 0xc0,
- 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
- 0x32, 0x01, 0x08, 0x17,
- 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
- 0x3d, 0x27, 0x25, 0xbd,
- 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
- 0xe8, 0x14, 0x01, 0xa6,
- 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
- 0x0e, 0x12, 0x01, 0x43,
- 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
- 0x01, 0x08, 0x17, 0x73,
- 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
- 0x27, 0x25, 0xbd, 0x09,
- 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
- 0xb6, 0x14, 0x86, 0xa8,
- 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
- 0x82, 0x4e, 0x05, 0x72,
- 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
- 0xfe, 0xc0, 0x19, 0x05,
- 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
- 0xcc, 0x01, 0x08, 0x26,
- 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
- 0xcc, 0x15, 0x5e, 0x32,
- 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
- 0xad, 0x23, 0xfe, 0xff,
- 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
- 0x00, 0x57, 0x52, 0xad,
- 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
- 0x02, 0x00, 0x57, 0x52,
- 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
- 0x02, 0x13, 0x58, 0xff,
- 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
- 0x5c, 0x0a, 0x55, 0x01,
- 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
- 0xff, 0x03, 0x00, 0x54,
- 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
- 0x7c, 0x3a, 0x0b, 0x0e,
- 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
- 0xfe, 0x1a, 0xf7, 0x00,
- 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
- 0xda, 0x6d, 0x02, 0xfe,
- 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
- 0x02, 0x01, 0xc6, 0xfe,
- 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
- 0x25, 0xbe, 0x01, 0x08,
- 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
- 0x03, 0x9a, 0x1e, 0xfe,
- 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
- 0x48, 0xfe, 0x08, 0x17,
- 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
- 0x17, 0x4d, 0x13, 0x07,
- 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
- 0xff, 0x02, 0x83, 0x55,
- 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
- 0x17, 0x1c, 0x63, 0x13,
- 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
- 0x00, 0xb0, 0xfe, 0x80,
- 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
- 0x53, 0x07, 0xfe, 0x60,
- 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
- 0x00, 0x1c, 0x95, 0x13,
- 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
- 0xfe, 0x43, 0xf4, 0x96,
- 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
- 0xf4, 0x94, 0xf6, 0x8b,
- 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
- 0xda, 0x17, 0x62, 0x49,
- 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
- 0x71, 0x50, 0x26, 0xfe,
- 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
- 0x58, 0x02, 0x50, 0x13,
- 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
- 0x25, 0xbe, 0xfe, 0x03,
- 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
- 0x0a, 0x01, 0x08, 0x16,
- 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
- 0x01, 0x08, 0x16, 0xa9,
- 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
- 0x08, 0x16, 0xa9, 0x27,
- 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
- 0x01, 0x38, 0x06, 0x24,
- 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
- 0x78, 0x03, 0x9a, 0x1e,
- 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
- 0xfe, 0x40, 0x5a, 0x23,
- 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
- 0x80, 0x48, 0xfe, 0xaa,
- 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
- 0xfe, 0xac, 0x1d, 0xfe,
- 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
- 0x43, 0x48, 0x2d, 0x93,
- 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
- 0x36, 0xfe, 0x34, 0xf4,
- 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
- 0x28, 0x10, 0xfe, 0xc0,
- 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
- 0x18, 0x45, 0xfe, 0x1c,
- 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
- 0x19, 0xfe, 0x04, 0xf4,
- 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
- 0x21, 0xfe, 0x7f, 0x01,
- 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
- 0x7e, 0x01, 0xfe, 0xc8,
- 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
- 0x21, 0xfe, 0x81, 0x01,
- 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
- 0x13, 0x0d, 0x02, 0x14,
- 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
- 0xfe, 0x82, 0x19, 0x14,
- 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
- 0x08, 0x02, 0x14, 0x07,
- 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
- 0x01, 0x08, 0x17, 0xc1,
- 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
- 0x08, 0x02, 0x50, 0x02,
- 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
- 0x14, 0x12, 0x01, 0x08,
- 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
- 0x08, 0x17, 0x74, 0xfe,
- 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
- 0x74, 0x5f, 0xcc, 0x01,
- 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
- 0xfe, 0x49, 0xf4, 0x00,
- 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
- 0x02, 0x00, 0x10, 0x2f,
- 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
- 0x16, 0xfe, 0x64, 0x1a,
- 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
- 0x61, 0x07, 0x44, 0x02,
- 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
- 0x13, 0x0a, 0x9d, 0x01,
- 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
- 0xfe, 0x80, 0xe7, 0x1a,
- 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
- 0x0a, 0x5a, 0x01, 0x18,
- 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
- 0x7e, 0x1e, 0xfe, 0x80,
- 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
- 0xfe, 0x80, 0x4c, 0x0a,
- 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
- 0xfe, 0x19, 0xde, 0xfe,
- 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
- 0x2a, 0x1c, 0xfa, 0xb3,
- 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
- 0xf4, 0x1a, 0xfe, 0xfa,
- 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
- 0xfe, 0x18, 0x58, 0x03,
- 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
- 0xfe, 0x30, 0xf4, 0x07,
- 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
- 0xf7, 0x24, 0xb1, 0xfe,
- 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
- 0xfe, 0xba, 0x10, 0x1c,
- 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
- 0x1d, 0xf7, 0x54, 0xb1,
- 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
- 0xaf, 0x19, 0xfe, 0x98,
- 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
- 0x1a, 0x87, 0x8b, 0x0f,
- 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
- 0xfe, 0x32, 0x90, 0x04,
- 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
- 0x7c, 0x12, 0xfe, 0x0f,
- 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
- 0x31, 0x02, 0xc9, 0x2b,
- 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
- 0x6a, 0xfe, 0x19, 0xfe,
- 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
- 0x1b, 0xfe, 0x36, 0x14,
- 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
- 0xfe, 0x80, 0xe7, 0x1a,
- 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
- 0x30, 0xfe, 0x12, 0x45,
- 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
- 0x39, 0xf0, 0x75, 0x26,
- 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
- 0xe3, 0x23, 0x07, 0xfe,
- 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
- 0x56, 0xfe, 0x3c, 0x13,
- 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
- 0x01, 0x18, 0xcb, 0xfe,
- 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
- 0xfe, 0x00, 0xcc, 0xcb,
- 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
- 0xfe, 0x80, 0x4c, 0x01,
- 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
- 0x12, 0xfe, 0x14, 0x56,
- 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
- 0x0d, 0x19, 0xfe, 0x15,
- 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
- 0x83, 0xfe, 0x18, 0x80,
- 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
- 0x90, 0xfe, 0xba, 0x90,
- 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
- 0x21, 0xb9, 0x88, 0x20,
- 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
- 0x18, 0xfe, 0x49, 0x44,
- 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
- 0x1a, 0xa4, 0x0a, 0x67,
- 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
- 0x1d, 0x7b, 0xfe, 0x52,
- 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
- 0x4e, 0xe4, 0xdd, 0x7b,
- 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
- 0xfe, 0x4e, 0xe4, 0xfe,
- 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
- 0xfe, 0x08, 0x10, 0x03,
- 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
- 0x68, 0x54, 0xfe, 0xf1,
- 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
- 0xfe, 0x1a, 0xf4, 0xfe,
- 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
- 0x09, 0x92, 0xfe, 0x5a,
- 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
- 0x5a, 0xf0, 0xfe, 0xc8,
- 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
- 0x1a, 0x10, 0x09, 0x0d,
- 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
- 0x1f, 0x93, 0x01, 0x42,
- 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
- 0xfe, 0x14, 0xf0, 0x08,
- 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
- 0xfe, 0x82, 0xf0, 0xfe,
- 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
- 0x02, 0x0f, 0xfe, 0x18,
- 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
- 0x80, 0x04, 0xfe, 0x82,
- 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
- 0x83, 0x33, 0x0b, 0x0e,
- 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
- 0x02, 0x0f, 0xfe, 0x04,
- 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
- 0x80, 0x04, 0xfe, 0x80,
- 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
- 0xfe, 0x99, 0x83, 0xfe,
- 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
- 0x83, 0xfe, 0xce, 0x47,
- 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
- 0x0b, 0x0e, 0x02, 0x0f,
- 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
- 0xfe, 0x08, 0x90, 0x04,
- 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
- 0xfe, 0x8a, 0x93, 0x79,
- 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
- 0x0b, 0x0e, 0x02, 0x0f,
- 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
- 0xfe, 0x3c, 0x90, 0x04,
- 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
- 0x04, 0xfe, 0x83, 0x83,
- 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
-};
+ if (asc_dvc->err_code != 0)
+ shost_printk(KERN_ERR, shost, "error 0x%x at init_state "
+ "0x%x\n", asc_dvc->err_code, asc_dvc->init_state);
-static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
-static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
+ return asc_dvc->err_code;
+}
-/* a_init.c */
/*
* EEPROM Configuration.
*
@@ -13847,7 +11891,7 @@ static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian
* on big-endian platforms so char fields read as words are actually being
* unswapped on big-endian platforms.
*/
-static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __initdata = {
+static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
0x0000, /* cfg_msw */
0xFFFF, /* disc_enable */
@@ -13885,7 +11929,7 @@ static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __initdata = {
0 /* num_of_err */
};
-static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __initdata = {
+static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
0, /* cfg_lsw */
0, /* cfg_msw */
0, /* -disc_enable */
@@ -13923,7 +11967,7 @@ static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __initdata = {
0 /* num_of_err */
};
-static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __initdata = {
+static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
0x0000, /* 01 cfg_msw */
0xFFFF, /* 02 disc_enable */
@@ -13988,7 +12032,7 @@ static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __initdata = {
0 /* 63 reserved */
};
-static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __initdata = {
+static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
0, /* 00 cfg_lsw */
0, /* 01 cfg_msw */
0, /* 02 disc_enable */
@@ -14053,7 +12097,7 @@ static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __initdata = {
0 /* 63 reserved */
};
-static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __initdata = {
+static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
0x0000, /* 01 cfg_msw */
0xFFFF, /* 02 disc_enable */
@@ -14118,7 +12162,7 @@ static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __initdata = {
0 /* 63 reserved */
};
-static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __initdata = {
+static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
0, /* 00 cfg_lsw */
0, /* 01 cfg_msw */
0, /* 02 disc_enable */
@@ -14183,1944 +12227,365 @@ static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __initdata = {
0 /* 63 reserved */
};
+#ifdef CONFIG_PCI
/*
- * Initialize the ADV_DVC_VAR structure.
- *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
- *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
+ * Wait for EEPROM command to complete
*/
-static int __init AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
+static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
{
- ushort warn_code;
- AdvPortAddr iop_base;
- uchar pci_cmd_reg;
- int status;
-
- warn_code = 0;
- asc_dvc->err_code = 0;
- iop_base = asc_dvc->iop_base;
-
- /*
- * PCI Command Register
- *
- * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes
- * I/O Space Control, Memory Space Control and Bus Master Control bits.
- */
-
- if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister))
- & AscPCICmdRegBits_BusMastering)
- != AscPCICmdRegBits_BusMastering) {
- pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
-
- DvcAdvWritePCIConfigByte(asc_dvc,
- AscPCIConfigCommandRegister,
- pci_cmd_reg);
-
- if (((DvcAdvReadPCIConfigByte
- (asc_dvc, AscPCIConfigCommandRegister))
- & AscPCICmdRegBits_BusMastering)
- != AscPCICmdRegBits_BusMastering) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- }
-
- /*
- * PCI Latency Timer
- *
- * If the "latency timer" register is 0x20 or above, then we don't need
- * to change it. Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
- * comes up less than 0x20).
- */
- if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
- DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer,
- 0x20);
- if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) <
- 0x20) {
- warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
- }
- }
-
- /*
- * Save the state of the PCI Configuration Command Register
- * "Parity Error Response Control" Bit. If the bit is clear (0),
- * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
- * DMA parity errors.
- */
- asc_dvc->cfg->control_flag = 0;
- if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
- & AscPCICmdRegBits_ParErrRespCtrl)) == 0) {
- asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
- }
-
- asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
- ADV_LIB_VERSION_MINOR;
- asc_dvc->cfg->chip_version =
- AdvGetChipVersion(iop_base, asc_dvc->bus_type);
-
- ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
- (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
- (ushort)ADV_CHIP_ID_BYTE);
-
- ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
- (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
- (ushort)ADV_CHIP_ID_WORD);
-
- /*
- * Reset the chip to start and allow register writes.
- */
- if (AdvFindSignature(iop_base) == 0) {
- asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
- return ADV_ERROR;
- } else {
- /*
- * The caller must set 'chip_type' to a valid setting.
- */
- if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
- asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
- asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
- asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
- return ADV_ERROR;
- }
-
- /*
- * Reset Chip.
- */
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
- ADV_CTRL_REG_CMD_RESET);
- DvcSleepMilliSecond(100);
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
- ADV_CTRL_REG_CMD_WR_IO_REG);
+ int eep_delay_ms;
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
- if ((status =
- AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR) {
- return ADV_ERROR;
- }
- } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
- if ((status =
- AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR) {
- return ADV_ERROR;
- }
- } else {
- if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR) {
- return ADV_ERROR;
- }
+ for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
+ if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
+ ASC_EEP_CMD_DONE) {
+ break;
}
- warn_code |= status;
+ mdelay(1);
}
-
- return warn_code;
+ if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
+ 0)
+ BUG();
}
/*
- * Initialize the ASC-3550.
- *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
- *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
- *
- * Needed after initialization for error recovery.
+ * Read the EEPROM from specified location
*/
-static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
+static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
{
- AdvPortAddr iop_base;
- ushort warn_code;
- ADV_DCNT sum;
- int begin_addr;
- int end_addr;
- ushort code_sum;
- int word;
- int j;
- int adv_asc3550_expanded_size;
- ADV_CARR_T *carrp;
- ADV_DCNT contig_len;
- ADV_SDCNT buf_size;
- ADV_PADDR carr_paddr;
- int i;
- ushort scsi_cfg1;
- uchar tid;
- ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
- ushort wdtr_able = 0, sdtr_able, tagqng_able;
- uchar max_cmd[ADV_MAX_TID + 1];
-
- /* If there is already an error, don't continue. */
- if (asc_dvc->err_code != 0) {
- return ADV_ERROR;
- }
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_READ | eep_word_addr);
+ AdvWaitEEPCmd(iop_base);
+ return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
+}
- /*
- * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
- */
- if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
- asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
- return ADV_ERROR;
- }
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+void __devinit
+AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+{
+ ushort *wbuf;
+ ushort addr, chksum;
+ ushort *charfields;
- warn_code = 0;
- iop_base = asc_dvc->iop_base;
+ wbuf = (ushort *)cfg_buf;
+ charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
+ chksum = 0;
- /*
- * Save the RISC memory BIOS region before writing the microcode.
- * The BIOS may already be loaded and using its RISC LRAM region
- * so its region must be saved and restored.
- *
- * Note: This code makes the assumption, which is currently true,
- * that a chip reset does not clear RISC LRAM.
- */
- for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
- AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
- bios_mem[i]);
- }
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+ AdvWaitEEPCmd(iop_base);
/*
- * Save current per TID negotiated values.
+ * Write EEPROM from word 0 to word 20.
*/
- if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
- ushort bios_version, major, minor;
-
- bios_version =
- bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
- major = (bios_version >> 12) & 0xF;
- minor = (bios_version >> 8) & 0xF;
- if (major < 3 || (major == 3 && minor == 1)) {
- /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
- AdvReadWordLram(iop_base, 0x120, wdtr_able);
- } else {
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- }
- }
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
+ for (addr = ADV_EEP_DVC_CFG_BEGIN;
+ addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
+ ushort word;
- /*
- * Load the Microcode
- *
- * Write the microcode image to RISC memory starting at address 0.
- */
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
- /* Assume the following compressed format of the microcode buffer:
- *
- * 254 word (508 byte) table indexed by byte code followed
- * by the following byte codes:
- *
- * 1-Byte Code:
- * 00: Emit word 0 in table.
- * 01: Emit word 1 in table.
- * .
- * FD: Emit word 253 in table.
- *
- * Multi-Byte Code:
- * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
- * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
- */
- word = 0;
- for (i = 253 * 2; i < _adv_asc3550_size; i++) {
- if (_adv_asc3550_buf[i] == 0xff) {
- for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc3550_buf
- [i +
- 3] << 8) |
- _adv_asc3550_buf
- [i + 2]));
- word++;
- }
- i += 3;
- } else if (_adv_asc3550_buf[i] == 0xfe) {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc3550_buf[i +
- 2]
- << 8) |
- _adv_asc3550_buf[i +
- 1]));
- i += 2;
- word++;
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
} else {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
- word++;
+ word = *wbuf;
}
+ chksum += *wbuf; /* Checksum is calculated from word values. */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ mdelay(ADV_EEP_DELAY_MS);
}
/*
- * Set 'word' for later use to clear the rest of memory and save
- * the expanded mcode size.
- */
- word *= 2;
- adv_asc3550_expanded_size = word;
-
- /*
- * Clear the rest of ASC-3550 Internal RAM (8KB).
- */
- for (; word < ADV_3550_MEMSIZE; word += 2) {
- AdvWriteWordAutoIncLram(iop_base, 0);
- }
-
- /*
- * Verify the microcode checksum.
- */
- sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
- for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
- sum += AdvReadWordAutoIncLram(iop_base);
- }
-
- if (sum != _adv_asc3550_chksum) {
- asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
- return ADV_ERROR;
- }
-
- /*
- * Restore the RISC memory BIOS region.
- */
- for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
- AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
- bios_mem[i]);
- }
-
- /*
- * Calculate and write the microcode code checksum to the microcode
- * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
- */
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
- AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
- code_sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
- for (word = begin_addr; word < end_addr; word += 2) {
- code_sum += AdvReadWordAutoIncLram(iop_base);
- }
- AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
-
- /*
- * Read and save microcode version and date.
- */
- AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
- asc_dvc->cfg->mcode_date);
- AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
- asc_dvc->cfg->mcode_version);
-
- /*
- * Set the chip type to indicate the ASC3550.
- */
- AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
-
- /*
- * If the PCI Configuration Command Register "Parity Error Response
- * Control" Bit was clear (0), then set the microcode variable
- * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
- * to ignore DMA parity errors.
- */
- if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
- AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- word |= CONTROL_FLAG_IGNORE_PERR;
- AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- }
-
- /*
- * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
- * threshold of 128 bytes. This register is only accessible to the host.
+ * Write EEPROM checksum at word 21.
*/
- AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
- START_CTL_EMFU | READ_CMD_MRM);
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ wbuf++;
+ charfields++;
/*
- * Microcode operating variables for WDTR, SDTR, and command tag
- * queuing will be set in AdvInquiryHandling() based on what a
- * device reports it is capable of in Inquiry byte 7.
- *
- * If SCSI Bus Resets have been disabled, then directly set
- * SDTR and WDTR from the EEPROM configuration. This will allow
- * the BIOS and warm boot to work without a SCSI bus hang on
- * the Inquiry caused by host and target mismatched DTR values.
- * Without the SCSI Bus Reset, before an Inquiry a device can't
- * be assumed to be in Asynchronous, Narrow mode.
+ * Write EEPROM OEM name at words 22 to 29.
*/
- if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
- asc_dvc->wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
- asc_dvc->sdtr_able);
- }
+ for (addr = ADV_EEP_DVC_CTL_BEGIN;
+ addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+ ushort word;
- /*
- * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
- * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
- * bitmask. These values determine the maximum SDTR speed negotiated
- * with a device.
- *
- * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
- * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
- * without determining here whether the device supports SDTR.
- *
- * 4-bit speed SDTR speed name
- * =========== ===============
- * 0000b (0x0) SDTR disabled
- * 0001b (0x1) 5 Mhz
- * 0010b (0x2) 10 Mhz
- * 0011b (0x3) 20 Mhz (Ultra)
- * 0100b (0x4) 40 Mhz (LVD/Ultra2)
- * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
- * 0110b (0x6) Undefined
- * .
- * 1111b (0xF) Undefined
- */
- word = 0;
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
- /* Set Ultra speed for TID 'tid'. */
- word |= (0x3 << (4 * (tid % 4)));
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
} else {
- /* Set Fast speed for TID 'tid'. */
- word |= (0x2 << (4 * (tid % 4)));
- }
- if (tid == 3) { /* Check if done with sdtr_speed1. */
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
- word = 0;
- } else if (tid == 7) { /* Check if done with sdtr_speed2. */
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
- word = 0;
- } else if (tid == 11) { /* Check if done with sdtr_speed3. */
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
- word = 0;
- } else if (tid == 15) { /* Check if done with sdtr_speed4. */
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
- /* End of loop. */
- }
- }
-
- /*
- * Set microcode operating variable for the disconnect per TID bitmask.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
- asc_dvc->cfg->disc_enable);
-
- /*
- * Set SCSI_CFG0 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG0 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
- PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
- asc_dvc->chip_scsi_id);
-
- /*
- * Determine SCSI_CFG1 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
-
- /* Read current SCSI_CFG1 Register value. */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
-
- /*
- * If all three connectors are in use, return an error.
- */
- if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
- (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
- asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
- return ADV_ERROR;
- }
-
- /*
- * If the internal narrow cable is reversed all of the SCSI_CTRL
- * register signals will be set. Check for and return an error if
- * this condition is found.
- */
- if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
- asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
- return ADV_ERROR;
- }
-
- /*
- * If this is a differential board and a single-ended device
- * is attached to one of the connectors, return an error.
- */
- if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
- asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
- return ADV_ERROR;
- }
-
- /*
- * If automatic termination control is enabled, then set the
- * termination value based on a table listed in a_condor.h.
- *
- * If manual termination was specified with an EEPROM setting
- * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
- * is ready to be 'ored' into SCSI_CFG1.
- */
- if (asc_dvc->cfg->termination == 0) {
- /*
- * The software always controls termination by setting TERM_CTL_SEL.
- * If TERM_CTL_SEL were set to 0, the hardware would set termination.
- */
- asc_dvc->cfg->termination |= TERM_CTL_SEL;
-
- switch (scsi_cfg1 & CABLE_DETECT) {
- /* TERM_CTL_H: on, TERM_CTL_L: on */
- case 0x3:
- case 0x7:
- case 0xB:
- case 0xD:
- case 0xE:
- case 0xF:
- asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
- break;
-
- /* TERM_CTL_H: on, TERM_CTL_L: off */
- case 0x1:
- case 0x5:
- case 0x9:
- case 0xA:
- case 0xC:
- asc_dvc->cfg->termination |= TERM_CTL_H;
- break;
-
- /* TERM_CTL_H: off, TERM_CTL_L: off */
- case 0x2:
- case 0x6:
- break;
+ word = *wbuf;
}
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
}
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+ AdvWaitEEPCmd(iop_base);
+}
- /*
- * Clear any set TERM_CTL_H and TERM_CTL_L bits.
- */
- scsi_cfg1 &= ~TERM_CTL;
-
- /*
- * Invert the TERM_CTL_H and TERM_CTL_L bits and then
- * set 'scsi_cfg1'. The TERM_POL bit does not need to be
- * referenced, because the hardware internally inverts
- * the Termination High and Low bits if TERM_POL is set.
- */
- scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
-
- /*
- * Set SCSI_CFG1 Microcode Default Value
- *
- * Set filter value and possibly modified termination control
- * bits in the Microcode SCSI_CFG1 Register Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
- FLTR_DISABLE | scsi_cfg1);
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+void __devinit
+AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
+{
+ ushort *wbuf;
+ ushort *charfields;
+ ushort addr, chksum;
- /*
- * Set MEM_CFG Microcode Default Value
- *
- * The microcode will set the MEM_CFG register using this value
- * after it is started below.
- *
- * MEM_CFG may be accessed as a word or byte, but only bits 0-7
- * are defined.
- *
- * ASC-3550 has 8KB internal memory.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
- BIOS_EN | RAM_SZ_8KB);
+ wbuf = (ushort *)cfg_buf;
+ charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
+ chksum = 0;
- /*
- * Set SEL_MASK Microcode Default Value
- *
- * The microcode will set the SEL_MASK register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
- ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+ AdvWaitEEPCmd(iop_base);
/*
- * Build carrier freelist.
- *
- * Driver must have already allocated memory and set 'carrier_buf'.
+ * Write EEPROM from word 0 to word 20.
*/
- ASC_ASSERT(asc_dvc->carrier_buf != NULL);
-
- carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
- asc_dvc->carr_freelist = NULL;
- if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
- buf_size = ADV_CARRIER_BUFSIZE;
- } else {
- buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
- }
-
- do {
- /*
- * Get physical address of the carrier 'carrp'.
- */
- contig_len = sizeof(ADV_CARR_T);
- carr_paddr =
- cpu_to_le32(DvcGetPhyAddr
- (asc_dvc, NULL, (uchar *)carrp,
- (ADV_SDCNT *)&contig_len,
- ADV_IS_CARRIER_FLAG));
-
- buf_size -= sizeof(ADV_CARR_T);
+ for (addr = ADV_EEP_DVC_CFG_BEGIN;
+ addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
+ ushort word;
- /*
- * If the current carrier is not physically contiguous, then
- * maybe there was a page crossing. Try the next carrier aligned
- * start address.
- */
- if (contig_len < sizeof(ADV_CARR_T)) {
- carrp++;
- continue;
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
+ } else {
+ word = *wbuf;
}
-
- carrp->carr_pa = carr_paddr;
- carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
-
- /*
- * Insert the carrier at the beginning of the freelist.
- */
- carrp->next_vpa =
- cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
- asc_dvc->carr_freelist = carrp;
-
- carrp++;
- }
- while (buf_size > 0);
-
- /*
- * Set-up the Host->RISC Initiator Command Queue (ICQ).
- */
-
- if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
-
- /*
- * The first command issued will be placed in the stopper carrier.
- */
- asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
- /*
- * Set RISC ICQ physical address start value.
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
-
- /*
- * Set-up the RISC->Host Initiator Response Queue (IRQ).
- */
- if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
+ chksum += *wbuf; /* Checksum is calculated from word values. */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ mdelay(ADV_EEP_DELAY_MS);
}
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
/*
- * The first command completed by the RISC will be placed in
- * the stopper.
- *
- * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
- * completed the RISC will set the ASC_RQ_STOPPER bit.
+ * Write EEPROM checksum at word 21.
*/
- asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ wbuf++;
+ charfields++;
/*
- * Set RISC IRQ physical address start value.
+ * Write EEPROM OEM name at words 22 to 29.
*/
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
- asc_dvc->carr_pending_cnt = 0;
-
- AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
- (ADV_INTR_ENABLE_HOST_INTR |
- ADV_INTR_ENABLE_GLOBAL_INTR));
-
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
- AdvWriteWordRegister(iop_base, IOPW_PC, word);
-
- /* finally, finally, gentlemen, start your engine */
- AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+ for (addr = ADV_EEP_DVC_CTL_BEGIN;
+ addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+ ushort word;
- /*
- * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
- * Resets should be performed. The RISC has to be running
- * to issue a SCSI Bus Reset.
- */
- if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
- /*
- * If the BIOS Signature is present in memory, restore the
- * BIOS Handshake Configuration Table and do not perform
- * a SCSI Bus Reset.
- */
- if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
- 0x55AA) {
- /*
- * Restore per TID negotiated values.
- */
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
- tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- AdvWriteByteLram(iop_base,
- ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
} else {
- if (AdvResetSB(asc_dvc) != ADV_TRUE) {
- warn_code = ASC_WARN_BUSRESET_ERROR;
- }
+ word = *wbuf;
}
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
}
-
- return warn_code;
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+ AdvWaitEEPCmd(iop_base);
}
/*
- * Initialize the ASC-38C0800.
- *
- * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
- *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
- *
- * Needed after initialization for error recovery.
+ * Write the EEPROM from 'cfg_buf'.
*/
-static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
+void __devinit
+AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
{
- AdvPortAddr iop_base;
- ushort warn_code;
- ADV_DCNT sum;
- int begin_addr;
- int end_addr;
- ushort code_sum;
- int word;
- int j;
- int adv_asc38C0800_expanded_size;
- ADV_CARR_T *carrp;
- ADV_DCNT contig_len;
- ADV_SDCNT buf_size;
- ADV_PADDR carr_paddr;
- int i;
- ushort scsi_cfg1;
- uchar byte;
- uchar tid;
- ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
- ushort wdtr_able, sdtr_able, tagqng_able;
- uchar max_cmd[ADV_MAX_TID + 1];
-
- /* If there is already an error, don't continue. */
- if (asc_dvc->err_code != 0) {
- return ADV_ERROR;
- }
-
- /*
- * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
- */
- if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
- asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
- return ADV_ERROR;
- }
-
- warn_code = 0;
- iop_base = asc_dvc->iop_base;
-
- /*
- * Save the RISC memory BIOS region before writing the microcode.
- * The BIOS may already be loaded and using its RISC LRAM region
- * so its region must be saved and restored.
- *
- * Note: This code makes the assumption, which is currently true,
- * that a chip reset does not clear RISC LRAM.
- */
- for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
- AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
- bios_mem[i]);
- }
-
- /*
- * Save current per TID negotiated values.
- */
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
-
- /*
- * RAM BIST (RAM Built-In Self Test)
- *
- * Address : I/O base + offset 0x38h register (byte).
- * Function: Bit 7-6(RW) : RAM mode
- * Normal Mode : 0x00
- * Pre-test Mode : 0x40
- * RAM Test Mode : 0x80
- * Bit 5 : unused
- * Bit 4(RO) : Done bit
- * Bit 3-0(RO) : Status
- * Host Error : 0x08
- * Int_RAM Error : 0x04
- * RISC Error : 0x02
- * SCSI Error : 0x01
- * No Error : 0x00
- *
- * Note: RAM BIST code should be put right here, before loading the
- * microcode and after saving the RISC memory BIOS region.
- */
-
- /*
- * LRAM Pre-test
- *
- * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
- * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
- * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
- * to NORMAL_MODE, return an error too.
- */
- for (i = 0; i < 2; i++) {
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
- byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
- if ((byte & RAM_TEST_DONE) == 0
- || (byte & 0x0F) != PRE_TEST_VALUE) {
- asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
- return ADV_ERROR;
- }
-
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
- if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
- != NORMAL_VALUE) {
- asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
- return ADV_ERROR;
- }
- }
-
- /*
- * LRAM Test - It takes about 1.5 ms to run through the test.
- *
- * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
- * If Done bit not set or Status not 0, save register byte, set the
- * err_code, and return an error.
- */
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
+ ushort *wbuf;
+ ushort *charfields;
+ ushort addr, chksum;
- byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
- if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
- /* Get here if Done bit not set or Status not 0. */
- asc_dvc->bist_err_code = byte; /* for BIOS display message */
- asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
- return ADV_ERROR;
- }
+ wbuf = (ushort *)cfg_buf;
+ charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
+ chksum = 0;
- /* We need to reset back to normal mode after LRAM test passes. */
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+ AdvWaitEEPCmd(iop_base);
/*
- * Load the Microcode
- *
- * Write the microcode image to RISC memory starting at address 0.
- *
+ * Write EEPROM from word 0 to word 20.
*/
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+ for (addr = ADV_EEP_DVC_CFG_BEGIN;
+ addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
+ ushort word;
- /* Assume the following compressed format of the microcode buffer:
- *
- * 254 word (508 byte) table indexed by byte code followed
- * by the following byte codes:
- *
- * 1-Byte Code:
- * 00: Emit word 0 in table.
- * 01: Emit word 1 in table.
- * .
- * FD: Emit word 253 in table.
- *
- * Multi-Byte Code:
- * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
- * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
- */
- word = 0;
- for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
- if (_adv_asc38C0800_buf[i] == 0xff) {
- for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C0800_buf
- [i +
- 3] << 8) |
- _adv_asc38C0800_buf
- [i + 2]));
- word++;
- }
- i += 3;
- } else if (_adv_asc38C0800_buf[i] == 0xfe) {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C0800_buf
- [i +
- 2] << 8) |
- _adv_asc38C0800_buf[i
- +
- 1]));
- i += 2;
- word++;
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
} else {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
- word++;
- }
- }
-
- /*
- * Set 'word' for later use to clear the rest of memory and save
- * the expanded mcode size.
- */
- word *= 2;
- adv_asc38C0800_expanded_size = word;
-
- /*
- * Clear the rest of ASC-38C0800 Internal RAM (16KB).
- */
- for (; word < ADV_38C0800_MEMSIZE; word += 2) {
- AdvWriteWordAutoIncLram(iop_base, 0);
- }
-
- /*
- * Verify the microcode checksum.
- */
- sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
- for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
- sum += AdvReadWordAutoIncLram(iop_base);
- }
- ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
-
- ASC_DBG2(1,
- "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
- (ulong)sum, (ulong)_adv_asc38C0800_chksum);
-
- if (sum != _adv_asc38C0800_chksum) {
- asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
- return ADV_ERROR;
- }
-
- /*
- * Restore the RISC memory BIOS region.
- */
- for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
- AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
- bios_mem[i]);
- }
-
- /*
- * Calculate and write the microcode code checksum to the microcode
- * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
- */
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
- AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
- code_sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
- for (word = begin_addr; word < end_addr; word += 2) {
- code_sum += AdvReadWordAutoIncLram(iop_base);
- }
- AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
-
- /*
- * Read microcode version and date.
- */
- AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
- asc_dvc->cfg->mcode_date);
- AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
- asc_dvc->cfg->mcode_version);
-
- /*
- * Set the chip type to indicate the ASC38C0800.
- */
- AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
-
- /*
- * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
- * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
- * cable detection and then we are able to read C_DET[3:0].
- *
- * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
- * Microcode Default Value' section below.
- */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
- AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
- scsi_cfg1 | DIS_TERM_DRV);
-
- /*
- * If the PCI Configuration Command Register "Parity Error Response
- * Control" Bit was clear (0), then set the microcode variable
- * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
- * to ignore DMA parity errors.
- */
- if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
- AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- word |= CONTROL_FLAG_IGNORE_PERR;
- AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- }
-
- /*
- * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
- * bits for the default FIFO threshold.
- *
- * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
- *
- * For DMA Errata #4 set the BC_THRESH_ENB bit.
- */
- AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
- BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
- READ_CMD_MRM);
-
- /*
- * Microcode operating variables for WDTR, SDTR, and command tag
- * queuing will be set in AdvInquiryHandling() based on what a
- * device reports it is capable of in Inquiry byte 7.
- *
- * If SCSI Bus Resets have been disabled, then directly set
- * SDTR and WDTR from the EEPROM configuration. This will allow
- * the BIOS and warm boot to work without a SCSI bus hang on
- * the Inquiry caused by host and target mismatched DTR values.
- * Without the SCSI Bus Reset, before an Inquiry a device can't
- * be assumed to be in Asynchronous, Narrow mode.
- */
- if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
- asc_dvc->wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
- asc_dvc->sdtr_able);
- }
-
- /*
- * Set microcode operating variables for DISC and SDTR_SPEED1,
- * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
- * configuration values.
- *
- * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
- * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
- * without determining here whether the device supports SDTR.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
- asc_dvc->cfg->disc_enable);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
-
- /*
- * Set SCSI_CFG0 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG0 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
- PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
- asc_dvc->chip_scsi_id);
-
- /*
- * Determine SCSI_CFG1 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
-
- /* Read current SCSI_CFG1 Register value. */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
-
- /*
- * If the internal narrow cable is reversed all of the SCSI_CTRL
- * register signals will be set. Check for and return an error if
- * this condition is found.
- */
- if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
- asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
- return ADV_ERROR;
- }
-
- /*
- * All kind of combinations of devices attached to one of four connectors
- * are acceptable except HVD device attached. For example, LVD device can
- * be attached to SE connector while SE device attached to LVD connector.
- * If LVD device attached to SE connector, it only runs up to Ultra speed.
- *
- * If an HVD device is attached to one of LVD connectors, return an error.
- * However, there is no way to detect HVD device attached to SE connectors.
- */
- if (scsi_cfg1 & HVD) {
- asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
- return ADV_ERROR;
- }
-
- /*
- * If either SE or LVD automatic termination control is enabled, then
- * set the termination value based on a table listed in a_condor.h.
- *
- * If manual termination was specified with an EEPROM setting then
- * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
- * be 'ored' into SCSI_CFG1.
- */
- if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
- /* SE automatic termination control is enabled. */
- switch (scsi_cfg1 & C_DET_SE) {
- /* TERM_SE_HI: on, TERM_SE_LO: on */
- case 0x1:
- case 0x2:
- case 0x3:
- asc_dvc->cfg->termination |= TERM_SE;
- break;
-
- /* TERM_SE_HI: on, TERM_SE_LO: off */
- case 0x0:
- asc_dvc->cfg->termination |= TERM_SE_HI;
- break;
- }
- }
-
- if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
- /* LVD automatic termination control is enabled. */
- switch (scsi_cfg1 & C_DET_LVD) {
- /* TERM_LVD_HI: on, TERM_LVD_LO: on */
- case 0x4:
- case 0x8:
- case 0xC:
- asc_dvc->cfg->termination |= TERM_LVD;
- break;
-
- /* TERM_LVD_HI: off, TERM_LVD_LO: off */
- case 0x0:
- break;
- }
- }
-
- /*
- * Clear any set TERM_SE and TERM_LVD bits.
- */
- scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
-
- /*
- * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
- */
- scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
-
- /*
- * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
- * and set possibly modified termination control bits in the Microcode
- * SCSI_CFG1 Register Value.
- */
- scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
-
- /*
- * Set SCSI_CFG1 Microcode Default Value
- *
- * Set possibly modified termination control and reset DIS_TERM_DRV
- * bits in the Microcode SCSI_CFG1 Register Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
-
- /*
- * Set MEM_CFG Microcode Default Value
- *
- * The microcode will set the MEM_CFG register using this value
- * after it is started below.
- *
- * MEM_CFG may be accessed as a word or byte, but only bits 0-7
- * are defined.
- *
- * ASC-38C0800 has 16KB internal memory.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
- BIOS_EN | RAM_SZ_16KB);
-
- /*
- * Set SEL_MASK Microcode Default Value
- *
- * The microcode will set the SEL_MASK register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
- ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
-
- /*
- * Build the carrier freelist.
- *
- * Driver must have already allocated memory and set 'carrier_buf'.
- */
- ASC_ASSERT(asc_dvc->carrier_buf != NULL);
-
- carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
- asc_dvc->carr_freelist = NULL;
- if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
- buf_size = ADV_CARRIER_BUFSIZE;
- } else {
- buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
- }
-
- do {
- /*
- * Get physical address for the carrier 'carrp'.
- */
- contig_len = sizeof(ADV_CARR_T);
- carr_paddr =
- cpu_to_le32(DvcGetPhyAddr
- (asc_dvc, NULL, (uchar *)carrp,
- (ADV_SDCNT *)&contig_len,
- ADV_IS_CARRIER_FLAG));
-
- buf_size -= sizeof(ADV_CARR_T);
-
- /*
- * If the current carrier is not physically contiguous, then
- * maybe there was a page crossing. Try the next carrier aligned
- * start address.
- */
- if (contig_len < sizeof(ADV_CARR_T)) {
- carrp++;
- continue;
+ word = *wbuf;
}
-
- carrp->carr_pa = carr_paddr;
- carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
-
- /*
- * Insert the carrier at the beginning of the freelist.
- */
- carrp->next_vpa =
- cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
- asc_dvc->carr_freelist = carrp;
-
- carrp++;
- }
- while (buf_size > 0);
-
- /*
- * Set-up the Host->RISC Initiator Command Queue (ICQ).
- */
-
- if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
-
- /*
- * The first command issued will be placed in the stopper carrier.
- */
- asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
- /*
- * Set RISC ICQ physical address start value.
- * carr_pa is LE, must be native before write
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
-
- /*
- * Set-up the RISC->Host Initiator Response Queue (IRQ).
- */
- if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
+ chksum += *wbuf; /* Checksum is calculated from word values. */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ mdelay(ADV_EEP_DELAY_MS);
}
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
/*
- * The first command completed by the RISC will be placed in
- * the stopper.
- *
- * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
- * completed the RISC will set the ASC_RQ_STOPPER bit.
+ * Write EEPROM checksum at word 21.
*/
- asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ wbuf++;
+ charfields++;
/*
- * Set RISC IRQ physical address start value.
- *
- * carr_pa is LE, must be native before write *
+ * Write EEPROM OEM name at words 22 to 29.
*/
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
- asc_dvc->carr_pending_cnt = 0;
-
- AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
- (ADV_INTR_ENABLE_HOST_INTR |
- ADV_INTR_ENABLE_GLOBAL_INTR));
-
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
- AdvWriteWordRegister(iop_base, IOPW_PC, word);
-
- /* finally, finally, gentlemen, start your engine */
- AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+ for (addr = ADV_EEP_DVC_CTL_BEGIN;
+ addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+ ushort word;
- /*
- * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
- * Resets should be performed. The RISC has to be running
- * to issue a SCSI Bus Reset.
- */
- if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
- /*
- * If the BIOS Signature is present in memory, restore the
- * BIOS Handshake Configuration Table and do not perform
- * a SCSI Bus Reset.
- */
- if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
- 0x55AA) {
- /*
- * Restore per TID negotiated values.
- */
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
- tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- AdvWriteByteLram(iop_base,
- ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
+ if (*charfields++) {
+ word = cpu_to_le16(*wbuf);
} else {
- if (AdvResetSB(asc_dvc) != ADV_TRUE) {
- warn_code = ASC_WARN_BUSRESET_ERROR;
- }
+ word = *wbuf;
}
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
}
-
- return warn_code;
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+ AdvWaitEEPCmd(iop_base);
}
/*
- * Initialize the ASC-38C1600.
- *
- * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
- *
- * For a non-fatal error return a warning code. If there are no warnings
- * then 0 is returned.
+ * Read EEPROM configuration into the specified buffer.
*
- * Needed after initialization for error recovery.
+ * Return a checksum based on the EEPROM configuration read.
*/
-static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
+static ushort __devinit
+AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
{
- AdvPortAddr iop_base;
- ushort warn_code;
- ADV_DCNT sum;
- int begin_addr;
- int end_addr;
- ushort code_sum;
- long word;
- int j;
- int adv_asc38C1600_expanded_size;
- ADV_CARR_T *carrp;
- ADV_DCNT contig_len;
- ADV_SDCNT buf_size;
- ADV_PADDR carr_paddr;
- int i;
- ushort scsi_cfg1;
- uchar byte;
- uchar tid;
- ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
- ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
- uchar max_cmd[ASC_MAX_TID + 1];
-
- /* If there is already an error, don't continue. */
- if (asc_dvc->err_code != 0) {
- return ADV_ERROR;
- }
-
- /*
- * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
- */
- if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
- asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
- return ADV_ERROR;
- }
-
- warn_code = 0;
- iop_base = asc_dvc->iop_base;
-
- /*
- * Save the RISC memory BIOS region before writing the microcode.
- * The BIOS may already be loaded and using its RISC LRAM region
- * so its region must be saved and restored.
- *
- * Note: This code makes the assumption, which is currently true,
- * that a chip reset does not clear RISC LRAM.
- */
- for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
- AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
- bios_mem[i]);
- }
-
- /*
- * Save current per TID negotiated values.
- */
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ASC_MAX_TID; tid++) {
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
-
- /*
- * RAM BIST (Built-In Self Test)
- *
- * Address : I/O base + offset 0x38h register (byte).
- * Function: Bit 7-6(RW) : RAM mode
- * Normal Mode : 0x00
- * Pre-test Mode : 0x40
- * RAM Test Mode : 0x80
- * Bit 5 : unused
- * Bit 4(RO) : Done bit
- * Bit 3-0(RO) : Status
- * Host Error : 0x08
- * Int_RAM Error : 0x04
- * RISC Error : 0x02
- * SCSI Error : 0x01
- * No Error : 0x00
- *
- * Note: RAM BIST code should be put right here, before loading the
- * microcode and after saving the RISC memory BIOS region.
- */
+ ushort wval, chksum;
+ ushort *wbuf;
+ int eep_addr;
+ ushort *charfields;
- /*
- * LRAM Pre-test
- *
- * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
- * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
- * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
- * to NORMAL_MODE, return an error too.
- */
- for (i = 0; i < 2; i++) {
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
- byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
- if ((byte & RAM_TEST_DONE) == 0
- || (byte & 0x0F) != PRE_TEST_VALUE) {
- asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
- return ADV_ERROR;
- }
+ charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
+ wbuf = (ushort *)cfg_buf;
+ chksum = 0;
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
- if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
- != NORMAL_VALUE) {
- asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
- return ADV_ERROR;
+ for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+ eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+ wval = AdvReadEEPWord(iop_base, eep_addr);
+ chksum += wval; /* Checksum is calculated from word values. */
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(wval);
+ } else {
+ *wbuf = wval;
}
}
+ /* Read checksum word. */
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ wbuf++;
+ charfields++;
- /*
- * LRAM Test - It takes about 1.5 ms to run through the test.
- *
- * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
- * If Done bit not set or Status not 0, save register byte, set the
- * err_code, and return an error.
- */
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
- DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
-
- byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
- if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
- /* Get here if Done bit not set or Status not 0. */
- asc_dvc->bist_err_code = byte; /* for BIOS display message */
- asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
- return ADV_ERROR;
+ /* Read rest of EEPROM not covered by the checksum. */
+ for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+ eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(*wbuf);
+ }
}
+ return chksum;
+}
- /* We need to reset back to normal mode after LRAM test passes. */
- AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+static ushort __devinit
+AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
+{
+ ushort wval, chksum;
+ ushort *wbuf;
+ int eep_addr;
+ ushort *charfields;
- /*
- * Load the Microcode
- *
- * Write the microcode image to RISC memory starting at address 0.
- *
- */
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+ charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
+ wbuf = (ushort *)cfg_buf;
+ chksum = 0;
- /*
- * Assume the following compressed format of the microcode buffer:
- *
- * 254 word (508 byte) table indexed by byte code followed
- * by the following byte codes:
- *
- * 1-Byte Code:
- * 00: Emit word 0 in table.
- * 01: Emit word 1 in table.
- * .
- * FD: Emit word 253 in table.
- *
- * Multi-Byte Code:
- * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
- * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
- */
- word = 0;
- for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
- if (_adv_asc38C1600_buf[i] == 0xff) {
- for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C1600_buf
- [i +
- 3] << 8) |
- _adv_asc38C1600_buf
- [i + 2]));
- word++;
- }
- i += 3;
- } else if (_adv_asc38C1600_buf[i] == 0xfe) {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C1600_buf
- [i +
- 2] << 8) |
- _adv_asc38C1600_buf[i
- +
- 1]));
- i += 2;
- word++;
+ for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+ eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+ wval = AdvReadEEPWord(iop_base, eep_addr);
+ chksum += wval; /* Checksum is calculated from word values. */
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(wval);
} else {
- AdvWriteWordAutoIncLram(iop_base, (((ushort)
- _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
- word++;
+ *wbuf = wval;
}
}
+ /* Read checksum word. */
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ wbuf++;
+ charfields++;
- /*
- * Set 'word' for later use to clear the rest of memory and save
- * the expanded mcode size.
- */
- word *= 2;
- adv_asc38C1600_expanded_size = word;
-
- /*
- * Clear the rest of ASC-38C1600 Internal RAM (32KB).
- */
- for (; word < ADV_38C1600_MEMSIZE; word += 2) {
- AdvWriteWordAutoIncLram(iop_base, 0);
- }
-
- /*
- * Verify the microcode checksum.
- */
- sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-
- for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
- sum += AdvReadWordAutoIncLram(iop_base);
- }
-
- if (sum != _adv_asc38C1600_chksum) {
- asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
- return ADV_ERROR;
- }
-
- /*
- * Restore the RISC memory BIOS region.
- */
- for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
- AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
- bios_mem[i]);
- }
-
- /*
- * Calculate and write the microcode code checksum to the microcode
- * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
- */
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
- AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
- code_sum = 0;
- AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
- for (word = begin_addr; word < end_addr; word += 2) {
- code_sum += AdvReadWordAutoIncLram(iop_base);
- }
- AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
-
- /*
- * Read microcode version and date.
- */
- AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
- asc_dvc->cfg->mcode_date);
- AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
- asc_dvc->cfg->mcode_version);
-
- /*
- * Set the chip type to indicate the ASC38C1600.
- */
- AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
-
- /*
- * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
- * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
- * cable detection and then we are able to read C_DET[3:0].
- *
- * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
- * Microcode Default Value' section below.
- */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
- AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
- scsi_cfg1 | DIS_TERM_DRV);
-
- /*
- * If the PCI Configuration Command Register "Parity Error Response
- * Control" Bit was clear (0), then set the microcode variable
- * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
- * to ignore DMA parity errors.
- */
- if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
- AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- word |= CONTROL_FLAG_IGNORE_PERR;
- AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- }
-
- /*
- * If the BIOS control flag AIPP (Asynchronous Information
- * Phase Protection) disable bit is not set, then set the firmware
- * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
- * AIPP checking and encoding.
- */
- if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
- AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- word |= CONTROL_FLAG_ENABLE_AIPP;
- AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
- }
-
- /*
- * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
- * and START_CTL_TH [3:2].
- */
- AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
- FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
-
- /*
- * Microcode operating variables for WDTR, SDTR, and command tag
- * queuing will be set in AdvInquiryHandling() based on what a
- * device reports it is capable of in Inquiry byte 7.
- *
- * If SCSI Bus Resets have been disabled, then directly set
- * SDTR and WDTR from the EEPROM configuration. This will allow
- * the BIOS and warm boot to work without a SCSI bus hang on
- * the Inquiry caused by host and target mismatched DTR values.
- * Without the SCSI Bus Reset, before an Inquiry a device can't
- * be assumed to be in Asynchronous, Narrow mode.
- */
- if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
- asc_dvc->wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
- asc_dvc->sdtr_able);
- }
-
- /*
- * Set microcode operating variables for DISC and SDTR_SPEED1,
- * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
- * configuration values.
- *
- * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
- * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
- * without determining here whether the device supports SDTR.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
- asc_dvc->cfg->disc_enable);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
-
- /*
- * Set SCSI_CFG0 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG0 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
- PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
- asc_dvc->chip_scsi_id);
-
- /*
- * Calculate SCSI_CFG1 Microcode Default Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- *
- * Each ASC-38C1600 function has only two cable detect bits.
- * The bus mode override bits are in IOPB_SOFT_OVER_WR.
- */
- scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
-
- /*
- * If the cable is reversed all of the SCSI_CTRL register signals
- * will be set. Check for and return an error if this condition is
- * found.
- */
- if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
- asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
- return ADV_ERROR;
- }
-
- /*
- * Each ASC-38C1600 function has two connectors. Only an HVD device
- * can not be connected to either connector. An LVD device or SE device
- * may be connected to either connecor. If an SE device is connected,
- * then at most Ultra speed (20 Mhz) can be used on both connectors.
- *
- * If an HVD device is attached, return an error.
- */
- if (scsi_cfg1 & HVD) {
- asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
- return ADV_ERROR;
- }
-
- /*
- * Each function in the ASC-38C1600 uses only the SE cable detect and
- * termination because there are two connectors for each function. Each
- * function may use either LVD or SE mode. Corresponding the SE automatic
- * termination control EEPROM bits are used for each function. Each
- * function has its own EEPROM. If SE automatic control is enabled for
- * the function, then set the termination value based on a table listed
- * in a_condor.h.
- *
- * If manual termination is specified in the EEPROM for the function,
- * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
- * ready to be 'ored' into SCSI_CFG1.
- */
- if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
- /* SE automatic termination control is enabled. */
- switch (scsi_cfg1 & C_DET_SE) {
- /* TERM_SE_HI: on, TERM_SE_LO: on */
- case 0x1:
- case 0x2:
- case 0x3:
- asc_dvc->cfg->termination |= TERM_SE;
- break;
-
- case 0x0:
- if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
- /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
- } else {
- /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
- asc_dvc->cfg->termination |= TERM_SE_HI;
- }
- break;
+ /* Read rest of EEPROM not covered by the checksum. */
+ for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+ eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(*wbuf);
}
}
+ return chksum;
+}
- /*
- * Clear any set TERM_SE bits.
- */
- scsi_cfg1 &= ~TERM_SE;
-
- /*
- * Invert the TERM_SE bits and then set 'scsi_cfg1'.
- */
- scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
-
- /*
- * Clear Big Endian and Terminator Polarity bits and set possibly
- * modified termination control bits in the Microcode SCSI_CFG1
- * Register Value.
- *
- * Big Endian bit is not used even on big endian machines.
- */
- scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
-
- /*
- * Set SCSI_CFG1 Microcode Default Value
- *
- * Set possibly modified termination control bits in the Microcode
- * SCSI_CFG1 Register Value.
- *
- * The microcode will set the SCSI_CFG1 register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
-
- /*
- * Set MEM_CFG Microcode Default Value
- *
- * The microcode will set the MEM_CFG register using this value
- * after it is started below.
- *
- * MEM_CFG may be accessed as a word or byte, but only bits 0-7
- * are defined.
- *
- * ASC-38C1600 has 32KB internal memory.
- *
- * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
- * out a special 16K Adv Library and Microcode version. After the issue
- * resolved, we should turn back to the 32K support. Both a_condor.h and
- * mcode.sas files also need to be updated.
- *
- * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
- * BIOS_EN | RAM_SZ_32KB);
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
- BIOS_EN | RAM_SZ_16KB);
-
- /*
- * Set SEL_MASK Microcode Default Value
- *
- * The microcode will set the SEL_MASK register using this value
- * after it is started below.
- */
- AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
- ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
-
- /*
- * Build the carrier freelist.
- *
- * Driver must have already allocated memory and set 'carrier_buf'.
- */
-
- ASC_ASSERT(asc_dvc->carrier_buf != NULL);
-
- carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
- asc_dvc->carr_freelist = NULL;
- if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
- buf_size = ADV_CARRIER_BUFSIZE;
- } else {
- buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
- }
-
- do {
- /*
- * Get physical address for the carrier 'carrp'.
- */
- contig_len = sizeof(ADV_CARR_T);
- carr_paddr =
- cpu_to_le32(DvcGetPhyAddr
- (asc_dvc, NULL, (uchar *)carrp,
- (ADV_SDCNT *)&contig_len,
- ADV_IS_CARRIER_FLAG));
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+static ushort __devinit
+AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
+{
+ ushort wval, chksum;
+ ushort *wbuf;
+ int eep_addr;
+ ushort *charfields;
- buf_size -= sizeof(ADV_CARR_T);
+ charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
+ wbuf = (ushort *)cfg_buf;
+ chksum = 0;
- /*
- * If the current carrier is not physically contiguous, then
- * maybe there was a page crossing. Try the next carrier aligned
- * start address.
- */
- if (contig_len < sizeof(ADV_CARR_T)) {
- carrp++;
- continue;
+ for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+ eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+ wval = AdvReadEEPWord(iop_base, eep_addr);
+ chksum += wval; /* Checksum is calculated from word values. */
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(wval);
+ } else {
+ *wbuf = wval;
}
-
- carrp->carr_pa = carr_paddr;
- carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
-
- /*
- * Insert the carrier at the beginning of the freelist.
- */
- carrp->next_vpa =
- cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
- asc_dvc->carr_freelist = carrp;
-
- carrp++;
- }
- while (buf_size > 0);
-
- /*
- * Set-up the Host->RISC Initiator Command Queue (ICQ).
- */
- if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
}
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
-
- /*
- * The first command issued will be placed in the stopper carrier.
- */
- asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
- /*
- * Set RISC ICQ physical address start value. Initialize the
- * COMMA register to the same value otherwise the RISC will
- * prematurely detect a command is available.
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
- AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
- le32_to_cpu(asc_dvc->icq_sp->carr_pa));
-
- /*
- * Set-up the RISC->Host Initiator Response Queue (IRQ).
- */
- if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
- asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
- return ADV_ERROR;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
-
- /*
- * The first command completed by the RISC will be placed in
- * the stopper.
- *
- * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
- * completed the RISC will set the ASC_RQ_STOPPER bit.
- */
- asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
- /*
- * Set RISC IRQ physical address start value.
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
- asc_dvc->carr_pending_cnt = 0;
-
- AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
- (ADV_INTR_ENABLE_HOST_INTR |
- ADV_INTR_ENABLE_GLOBAL_INTR));
- AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
- AdvWriteWordRegister(iop_base, IOPW_PC, word);
-
- /* finally, finally, gentlemen, start your engine */
- AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+ /* Read checksum word. */
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ wbuf++;
+ charfields++;
- /*
- * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
- * Resets should be performed. The RISC has to be running
- * to issue a SCSI Bus Reset.
- */
- if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
- /*
- * If the BIOS Signature is present in memory, restore the
- * per TID microcode operating variables.
- */
- if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
- 0x55AA) {
- /*
- * Restore per TID negotiated values.
- */
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
- tagqng_able);
- for (tid = 0; tid <= ASC_MAX_TID; tid++) {
- AdvWriteByteLram(iop_base,
- ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
- } else {
- if (AdvResetSB(asc_dvc) != ADV_TRUE) {
- warn_code = ASC_WARN_BUSRESET_ERROR;
- }
+ /* Read rest of EEPROM not covered by the checksum. */
+ for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+ eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ if (*charfields++) {
+ *wbuf = le16_to_cpu(*wbuf);
}
}
-
- return warn_code;
+ return chksum;
}
/*
@@ -16135,12 +12600,11 @@ static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
*
* Note: Chip is stopped on entry.
*/
-static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
+static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
{
AdvPortAddr iop_base;
ushort warn_code;
ADVEEP_3550_CONFIG eep_config;
- int i;
iop_base = asc_dvc->iop_base;
@@ -16157,15 +12621,12 @@ static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
/*
* Set EEPROM default values.
*/
- for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
- *((uchar *)&eep_config + i) =
- *((uchar *)&Default_3550_EEPROM_Config + i);
- }
+ memcpy(&eep_config, &Default_3550_EEPROM_Config,
+ sizeof(ADVEEP_3550_CONFIG));
/*
- * Assume the 6 byte board serial number that was read
- * from EEPROM is correct even if the EEPROM checksum
- * failed.
+ * Assume the 6 byte board serial number that was read from
+ * EEPROM is correct even if the EEPROM checksum failed.
*/
eep_config.serial_number_word3 =
AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
@@ -16289,12 +12750,11 @@ static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
*
* Note: Chip is stopped on entry.
*/
-static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
+static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
{
AdvPortAddr iop_base;
ushort warn_code;
ADVEEP_38C0800_CONFIG eep_config;
- int i;
uchar tid, termination;
ushort sdtr_speed = 0;
@@ -16314,15 +12774,12 @@ static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
/*
* Set EEPROM default values.
*/
- for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
- *((uchar *)&eep_config + i) =
- *((uchar *)&Default_38C0800_EEPROM_Config + i);
- }
+ memcpy(&eep_config, &Default_38C0800_EEPROM_Config,
+ sizeof(ADVEEP_38C0800_CONFIG));
/*
- * Assume the 6 byte board serial number that was read
- * from EEPROM is correct even if the EEPROM checksum
- * failed.
+ * Assume the 6 byte board serial number that was read from
+ * EEPROM is correct even if the EEPROM checksum failed.
*/
eep_config.serial_number_word3 =
AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
@@ -16492,12 +12949,11 @@ static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
*
* Note: Chip is stopped on entry.
*/
-static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
+static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
{
AdvPortAddr iop_base;
ushort warn_code;
ADVEEP_38C1600_CONFIG eep_config;
- int i;
uchar tid, termination;
ushort sdtr_speed = 0;
@@ -16512,75 +12968,52 @@ static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
*/
if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
eep_config.check_sum) {
+ struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
warn_code |= ASC_WARN_EEPROM_CHKSUM;
/*
* Set EEPROM default values.
*/
- for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
- if (i == 1
- && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
- 0) {
- /*
- * Set Function 1 EEPROM Word 0 MSB
- *
- * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
- * EEPROM bits.
- *
- * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
- * old Mac system booting problem. The Expansion ROM must
- * be disabled in Function 1 for these systems.
- *
- */
- *((uchar *)&eep_config + i) =
- ((*
- ((uchar *)&Default_38C1600_EEPROM_Config
- +
- i)) &
- (~
- (((ADV_EEPROM_BIOS_ENABLE |
- ADV_EEPROM_INTAB) >> 8) & 0xFF)));
+ memcpy(&eep_config, &Default_38C1600_EEPROM_Config,
+ sizeof(ADVEEP_38C1600_CONFIG));
- /*
- * Set the INTAB (bit 11) if the GPIO 0 input indicates
- * the Function 1 interrupt line is wired to INTA.
- *
- * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
- * 1 - Function 1 interrupt line wired to INT A.
- * 0 - Function 1 interrupt line wired to INT B.
- *
- * Note: Adapter boards always have Function 0 wired to INTA.
- * Put all 5 GPIO bits in input mode and then read
- * their input values.
- */
- AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
- 0);
- if (AdvReadByteRegister
- (iop_base, IOPB_GPIO_DATA) & 0x01) {
- /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
- *((uchar *)&eep_config + i) |=
- ((ADV_EEPROM_INTAB >> 8) & 0xFF);
- }
- } else {
- *((uchar *)&eep_config + i) =
- *((uchar *)&Default_38C1600_EEPROM_Config
- + i);
- }
+ if (PCI_FUNC(pdev->devfn) != 0) {
+ u8 ints;
+ /*
+ * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60
+ * and old Mac system booting problem. The Expansion
+ * ROM must be disabled in Function 1 for these systems
+ */
+ eep_config.cfg_lsw &= ~ADV_EEPROM_BIOS_ENABLE;
+ /*
+ * Clear the INTAB (bit 11) if the GPIO 0 input
+ * indicates the Function 1 interrupt line is wired
+ * to INTB.
+ *
+ * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
+ * 1 - Function 1 interrupt line wired to INT A.
+ * 0 - Function 1 interrupt line wired to INT B.
+ *
+ * Note: Function 0 is always wired to INTA.
+ * Put all 5 GPIO bits in input mode and then read
+ * their input values.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0);
+ ints = AdvReadByteRegister(iop_base, IOPB_GPIO_DATA);
+ if ((ints & 0x01) == 0)
+ eep_config.cfg_lsw &= ~ADV_EEPROM_INTAB;
}
/*
- * Assume the 6 byte board serial number that was read
- * from EEPROM is correct even if the EEPROM checksum
- * failed.
+ * Assume the 6 byte board serial number that was read from
+ * EEPROM is correct even if the EEPROM checksum failed.
*/
eep_config.serial_number_word3 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
-
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
eep_config.serial_number_word2 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
-
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
eep_config.serial_number_word1 =
- AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
+ AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
AdvSet38C1600EEPConfig(iop_base, &eep_config);
}
@@ -16729,1176 +13162,281 @@ static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
}
/*
- * Read EEPROM configuration into the specified buffer.
- *
- * Return a checksum based on the EEPROM configuration read.
- */
-static ushort __init
-AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
-{
- ushort wval, chksum;
- ushort *wbuf;
- int eep_addr;
- ushort *charfields;
-
- charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
- wbuf = (ushort *)cfg_buf;
- chksum = 0;
-
- for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
- eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
- wval = AdvReadEEPWord(iop_base, eep_addr);
- chksum += wval; /* Checksum is calculated from word values. */
- if (*charfields++) {
- *wbuf = le16_to_cpu(wval);
- } else {
- *wbuf = wval;
- }
- }
- /* Read checksum word. */
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- wbuf++;
- charfields++;
-
- /* Read rest of EEPROM not covered by the checksum. */
- for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
- eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- if (*charfields++) {
- *wbuf = le16_to_cpu(*wbuf);
- }
- }
- return chksum;
-}
-
-/*
- * Read EEPROM configuration into the specified buffer.
+ * Initialize the ADV_DVC_VAR structure.
*
- * Return a checksum based on the EEPROM configuration read.
- */
-static ushort __init
-AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
-{
- ushort wval, chksum;
- ushort *wbuf;
- int eep_addr;
- ushort *charfields;
-
- charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
- wbuf = (ushort *)cfg_buf;
- chksum = 0;
-
- for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
- eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
- wval = AdvReadEEPWord(iop_base, eep_addr);
- chksum += wval; /* Checksum is calculated from word values. */
- if (*charfields++) {
- *wbuf = le16_to_cpu(wval);
- } else {
- *wbuf = wval;
- }
- }
- /* Read checksum word. */
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- wbuf++;
- charfields++;
-
- /* Read rest of EEPROM not covered by the checksum. */
- for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
- eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- if (*charfields++) {
- *wbuf = le16_to_cpu(*wbuf);
- }
- }
- return chksum;
-}
-
-/*
- * Read EEPROM configuration into the specified buffer.
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
*
- * Return a checksum based on the EEPROM configuration read.
- */
-static ushort __init
-AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
-{
- ushort wval, chksum;
- ushort *wbuf;
- int eep_addr;
- ushort *charfields;
-
- charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
- wbuf = (ushort *)cfg_buf;
- chksum = 0;
-
- for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
- eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
- wval = AdvReadEEPWord(iop_base, eep_addr);
- chksum += wval; /* Checksum is calculated from word values. */
- if (*charfields++) {
- *wbuf = le16_to_cpu(wval);
- } else {
- *wbuf = wval;
- }
- }
- /* Read checksum word. */
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- wbuf++;
- charfields++;
-
- /* Read rest of EEPROM not covered by the checksum. */
- for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
- eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
- *wbuf = AdvReadEEPWord(iop_base, eep_addr);
- if (*charfields++) {
- *wbuf = le16_to_cpu(*wbuf);
- }
- }
- return chksum;
-}
-
-/*
- * Read the EEPROM from specified location
- */
-static ushort __init AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
-{
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_READ | eep_word_addr);
- AdvWaitEEPCmd(iop_base);
- return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
-}
-
-/*
- * Wait for EEPROM command to complete
- */
-static void __init AdvWaitEEPCmd(AdvPortAddr iop_base)
-{
- int eep_delay_ms;
-
- for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
- if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
- ASC_EEP_CMD_DONE) {
- break;
- }
- DvcSleepMilliSecond(1);
- }
- if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
- 0) {
- ASC_ASSERT(0);
- }
- return;
-}
-
-/*
- * Write the EEPROM from 'cfg_buf'.
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
*/
-void __init
-AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+static int __devinit
+AdvInitGetConfig(struct pci_dev *pdev, struct Scsi_Host *shost)
{
- ushort *wbuf;
- ushort addr, chksum;
- ushort *charfields;
-
- wbuf = (ushort *)cfg_buf;
- charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
- chksum = 0;
-
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
- AdvWaitEEPCmd(iop_base);
-
- /*
- * Write EEPROM from word 0 to word 20.
- */
- for (addr = ADV_EEP_DVC_CFG_BEGIN;
- addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
- ushort word;
-
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- chksum += *wbuf; /* Checksum is calculated from word values. */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
- }
+ struct asc_board *board = shost_priv(shost);
+ ADV_DVC_VAR *asc_dvc = &board->dvc_var.adv_dvc_var;
+ unsigned short warn_code = 0;
+ AdvPortAddr iop_base = asc_dvc->iop_base;
+ u16 cmd;
+ int status;
- /*
- * Write EEPROM checksum at word 21.
- */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- wbuf++;
- charfields++;
+ asc_dvc->err_code = 0;
/*
- * Write EEPROM OEM name at words 22 to 29.
+ * Save the state of the PCI Configuration Command Register
+ * "Parity Error Response Control" Bit. If the bit is clear (0),
+ * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
+ * DMA parity errors.
*/
- for (addr = ADV_EEP_DVC_CTL_BEGIN;
- addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
- ushort word;
-
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
- AdvWaitEEPCmd(iop_base);
- return;
-}
-
-/*
- * Write the EEPROM from 'cfg_buf'.
- */
-void __init
-AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
-{
- ushort *wbuf;
- ushort *charfields;
- ushort addr, chksum;
-
- wbuf = (ushort *)cfg_buf;
- charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
- chksum = 0;
-
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
- AdvWaitEEPCmd(iop_base);
+ asc_dvc->cfg->control_flag = 0;
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ if ((cmd & PCI_COMMAND_PARITY) == 0)
+ asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
- /*
- * Write EEPROM from word 0 to word 20.
- */
- for (addr = ADV_EEP_DVC_CFG_BEGIN;
- addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
- ushort word;
+ asc_dvc->cfg->chip_version =
+ AdvGetChipVersion(iop_base, asc_dvc->bus_type);
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- chksum += *wbuf; /* Checksum is calculated from word values. */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
- }
+ ASC_DBG(1, "iopb_chip_id_1: 0x%x 0x%x\n",
+ (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
+ (ushort)ADV_CHIP_ID_BYTE);
- /*
- * Write EEPROM checksum at word 21.
- */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- wbuf++;
- charfields++;
+ ASC_DBG(1, "iopw_chip_id_0: 0x%x 0x%x\n",
+ (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
+ (ushort)ADV_CHIP_ID_WORD);
/*
- * Write EEPROM OEM name at words 22 to 29.
+ * Reset the chip to start and allow register writes.
*/
- for (addr = ADV_EEP_DVC_CTL_BEGIN;
- addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
- ushort word;
-
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
+ if (AdvFindSignature(iop_base) == 0) {
+ asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+ return ADV_ERROR;
+ } else {
+ /*
+ * The caller must set 'chip_type' to a valid setting.
+ */
+ if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
+ asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
+ asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
+ asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
+ return ADV_ERROR;
}
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
- AdvWaitEEPCmd(iop_base);
- return;
-}
-/*
- * Write the EEPROM from 'cfg_buf'.
- */
-void __init
-AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
-{
- ushort *wbuf;
- ushort *charfields;
- ushort addr, chksum;
-
- wbuf = (ushort *)cfg_buf;
- charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
- chksum = 0;
-
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
- AdvWaitEEPCmd(iop_base);
-
- /*
- * Write EEPROM from word 0 to word 20.
- */
- for (addr = ADV_EEP_DVC_CFG_BEGIN;
- addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
- ushort word;
+ /*
+ * Reset Chip.
+ */
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+ ADV_CTRL_REG_CMD_RESET);
+ mdelay(100);
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+ ADV_CTRL_REG_CMD_WR_IO_REG);
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
+ if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+ status = AdvInitFrom38C1600EEP(asc_dvc);
+ } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ status = AdvInitFrom38C0800EEP(asc_dvc);
} else {
- word = *wbuf;
+ status = AdvInitFrom3550EEP(asc_dvc);
}
- chksum += *wbuf; /* Checksum is calculated from word values. */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+ warn_code |= status;
}
- /*
- * Write EEPROM checksum at word 21.
- */
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- wbuf++;
- charfields++;
+ if (warn_code != 0)
+ shost_printk(KERN_WARNING, shost, "warning: 0x%x\n", warn_code);
- /*
- * Write EEPROM OEM name at words 22 to 29.
- */
- for (addr = ADV_EEP_DVC_CTL_BEGIN;
- addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
- ushort word;
+ if (asc_dvc->err_code)
+ shost_printk(KERN_ERR, shost, "error code 0x%x\n",
+ asc_dvc->err_code);
- if (*charfields++) {
- word = cpu_to_le16(*wbuf);
- } else {
- word = *wbuf;
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
- ASC_EEP_CMD_WRITE | addr);
- AdvWaitEEPCmd(iop_base);
- }
- AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
- AdvWaitEEPCmd(iop_base);
- return;
+ return asc_dvc->err_code;
}
+#endif
-/* a_advlib.c */
-/*
- * AdvExeScsiQueue() - Send a request to the RISC microcode program.
- *
- * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
- * add the carrier to the ICQ (Initiator Command Queue), and tickle the
- * RISC to notify it a new command is ready to be executed.
- *
- * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
- * set to SCSI_MAX_RETRY.
- *
- * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
- * for DMA addresses or math operations are byte swapped to little-endian
- * order.
- *
- * Return:
- * ADV_SUCCESS(1) - The request was successfully queued.
- * ADV_BUSY(0) - Resource unavailable; Retry again after pending
- * request completes.
- * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
- * host IC error.
- */
-static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
-{
- ulong last_int_level;
- AdvPortAddr iop_base;
- ADV_DCNT req_size;
- ADV_PADDR req_paddr;
- ADV_CARR_T *new_carrp;
-
- ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
-
- /*
- * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
- */
- if (scsiq->target_id > ADV_MAX_TID) {
- scsiq->host_status = QHSTA_M_INVALID_DEVICE;
- scsiq->done_status = QD_WITH_ERROR;
- return ADV_ERROR;
- }
-
- iop_base = asc_dvc->iop_base;
-
- last_int_level = DvcEnterCritical();
-
- /*
- * Allocate a carrier ensuring at least one carrier always
- * remains on the freelist and initialize fields.
- */
- if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
- DvcLeaveCritical(last_int_level);
- return ADV_BUSY;
- }
- asc_dvc->carr_freelist = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
- asc_dvc->carr_pending_cnt++;
-
- /*
- * Set the carrier to be a stopper by setting 'next_vpa'
- * to the stopper value. The current stopper will be changed
- * below to point to the new stopper.
- */
- new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
-
- /*
- * Clear the ADV_SCSI_REQ_Q done flag.
- */
- scsiq->a_flag &= ~ADV_SCSIQ_DONE;
-
- req_size = sizeof(ADV_SCSI_REQ_Q);
- req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
- (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
-
- ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
- ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
-
- /* Wait for assertion before making little-endian */
- req_paddr = cpu_to_le32(req_paddr);
-
- /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
- scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
- scsiq->scsiq_rptr = req_paddr;
-
- scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
- /*
- * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
- * order during initialization.
- */
- scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
-
- /*
- * Use the current stopper to send the ADV_SCSI_REQ_Q command to
- * the microcode. The newly allocated stopper will become the new
- * stopper.
- */
- asc_dvc->icq_sp->areq_vpa = req_paddr;
-
+static struct scsi_host_template advansys_template = {
+ .proc_name = DRV_NAME,
+#ifdef CONFIG_PROC_FS
+ .proc_info = advansys_proc_info,
+#endif
+ .name = DRV_NAME,
+ .info = advansys_info,
+ .queuecommand = advansys_queuecommand,
+ .eh_bus_reset_handler = advansys_reset,
+ .bios_param = advansys_biosparam,
+ .slave_configure = advansys_slave_configure,
/*
- * Set the 'next_vpa' pointer for the old stopper to be the
- * physical address of the new stopper. The RISC can only
- * follow physical addresses.
+ * Because the driver may control an ISA adapter 'unchecked_isa_dma'
+ * must be set. The flag will be cleared in advansys_board_found
+ * for non-ISA adapters.
*/
- asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
-
+ .unchecked_isa_dma = 1,
/*
- * Set the host adapter stopper pointer to point to the new carrier.
+ * All adapters controlled by this driver are capable of large
+ * scatter-gather lists. According to the mid-level SCSI documentation
+ * this obviates any performance gain provided by setting
+ * 'use_clustering'. But empirically while CPU utilization is increased
+ * by enabling clustering, I/O throughput increases as well.
*/
- asc_dvc->icq_sp = new_carrp;
-
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
- asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
- /*
- * Tickle the RISC to tell it to read its Command Queue Head pointer.
- */
- AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
- /*
- * Clear the tickle value. In the ASC-3550 the RISC flag
- * command 'clr_tickle_a' does not work unless the host
- * value is cleared.
- */
- AdvWriteByteRegister(iop_base, IOPB_TICKLE,
- ADV_TICKLE_NOP);
- }
- } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
- /*
- * Notify the RISC a carrier is ready by writing the physical
- * address of the new carrier stopper to the COMMA register.
- */
- AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
- le32_to_cpu(new_carrp->carr_pa));
- }
-
- DvcLeaveCritical(last_int_level);
-
- return ADV_SUCCESS;
-}
+ .use_clustering = ENABLE_CLUSTERING,
+};
-/*
- * Reset SCSI Bus and purge all outstanding requests.
- *
- * Return Value:
- * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
- * ADV_FALSE(0) - Microcode command failed.
- * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
- * may be hung which requires driver recovery.
- */
-static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
+static int __devinit advansys_wide_init_chip(struct Scsi_Host *shost)
{
- int status;
+ struct asc_board *board = shost_priv(shost);
+ struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var;
+ int req_cnt = 0;
+ adv_req_t *reqp = NULL;
+ int sg_cnt = 0;
+ adv_sgblk_t *sgp;
+ int warn_code, err_code;
/*
- * Send the SCSI Bus Reset idle start idle command which asserts
- * the SCSI Bus Reset signal.
+ * Allocate buffer carrier structures. The total size
+ * is about 4 KB, so allocate all at once.
*/
- status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
- if (status != ADV_TRUE) {
- return status;
- }
+ adv_dvc->carrier_buf = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
+ ASC_DBG(1, "carrier_buf 0x%p\n", adv_dvc->carrier_buf);
- /*
- * Delay for the specified SCSI Bus Reset hold time.
- *
- * The hold time delay is done on the host because the RISC has no
- * microsecond accurate timer.
- */
- DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
+ if (!adv_dvc->carrier_buf)
+ goto kmalloc_failed;
/*
- * Send the SCSI Bus Reset end idle command which de-asserts
- * the SCSI Bus Reset signal and purges any pending requests.
+ * Allocate up to 'max_host_qng' request structures for the Wide
+ * board. The total size is about 16 KB, so allocate all at once.
+ * If the allocation fails decrement and try again.
*/
- status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
- if (status != ADV_TRUE) {
- return status;
- }
-
- DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
-
- return status;
-}
-
-/*
- * Reset chip and SCSI Bus.
- *
- * Return Value:
- * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
- * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
- */
-static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
-{
- int status;
- ushort wdtr_able, sdtr_able, tagqng_able;
- ushort ppr_able = 0;
- uchar tid, max_cmd[ADV_MAX_TID + 1];
- AdvPortAddr iop_base;
- ushort bios_sig;
+ for (req_cnt = adv_dvc->max_host_qng; req_cnt > 0; req_cnt--) {
+ reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
- iop_base = asc_dvc->iop_base;
+ ASC_DBG(1, "reqp 0x%p, req_cnt %d, bytes %lu\n", reqp, req_cnt,
+ (ulong)sizeof(adv_req_t) * req_cnt);
- /*
- * Save current per TID negotiated values.
- */
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
- AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
- }
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
+ if (reqp)
+ break;
}
- /*
- * Force the AdvInitAsc3550/38C0800Driver() function to
- * perform a SCSI Bus Reset by clearing the BIOS signature word.
- * The initialization functions assumes a SCSI Bus Reset is not
- * needed if the BIOS signature word is present.
- */
- AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
- AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
+ if (!reqp)
+ goto kmalloc_failed;
- /*
- * Stop chip and reset it.
- */
- AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
- DvcSleepMilliSecond(100);
- AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
- ADV_CTRL_REG_CMD_WR_IO_REG);
+ adv_dvc->orig_reqp = reqp;
/*
- * Reset Adv Library error code, if any, and try
- * re-initializing the chip.
+ * Allocate up to ADV_TOT_SG_BLOCK request structures for
+ * the Wide board. Each structure is about 136 bytes.
*/
- asc_dvc->err_code = 0;
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
- status = AdvInitAsc38C1600Driver(asc_dvc);
- } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
- status = AdvInitAsc38C0800Driver(asc_dvc);
- } else {
- status = AdvInitAsc3550Driver(asc_dvc);
- }
+ board->adv_sgblkp = NULL;
+ for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
+ sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
- /* Translate initialization return value to status value. */
- if (status == 0) {
- status = ADV_TRUE;
- } else {
- status = ADV_FALSE;
- }
+ if (!sgp)
+ break;
- /*
- * Restore the BIOS signature word.
- */
- AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+ sgp->next_sgblkp = board->adv_sgblkp;
+ board->adv_sgblkp = sgp;
- /*
- * Restore per TID negotiated values.
- */
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
- AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
}
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- for (tid = 0; tid <= ADV_MAX_TID; tid++) {
- AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
- max_cmd[tid]);
- }
-
- return status;
-}
-
-/*
- * Adv Library Interrupt Service Routine
- *
- * This function is called by a driver's interrupt service routine.
- * The function disables and re-enables interrupts.
- *
- * When a microcode idle command is completed, the ADV_DVC_VAR
- * 'idle_cmd_done' field is set to ADV_TRUE.
- *
- * Note: AdvISR() can be called when interrupts are disabled or even
- * when there is no hardware interrupt condition present. It will
- * always check for completed idle commands and microcode requests.
- * This is an important feature that shouldn't be changed because it
- * allows commands to be completed from polling mode loops.
- *
- * Return:
- * ADV_TRUE(1) - interrupt was pending
- * ADV_FALSE(0) - no interrupt was pending
- */
-static int AdvISR(ADV_DVC_VAR *asc_dvc)
-{
- AdvPortAddr iop_base;
- uchar int_stat;
- ushort target_bit;
- ADV_CARR_T *free_carrp;
- ADV_VADDR irq_next_vpa;
- int flags;
- ADV_SCSI_REQ_Q *scsiq;
-
- flags = DvcEnterCritical();
-
- iop_base = asc_dvc->iop_base;
- /* Reading the register clears the interrupt. */
- int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
+ ASC_DBG(1, "sg_cnt %d * %lu = %lu bytes\n", sg_cnt, sizeof(adv_sgblk_t),
+ sizeof(adv_sgblk_t) * sg_cnt);
- if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
- ADV_INTR_STATUS_INTRC)) == 0) {
- DvcLeaveCritical(flags);
- return ADV_FALSE;
- }
+ if (!board->adv_sgblkp)
+ goto kmalloc_failed;
/*
- * Notify the driver of an asynchronous microcode condition by
- * calling the ADV_DVC_VAR.async_callback function. The function
- * is passed the microcode ASC_MC_INTRB_CODE byte value.
+ * Point 'adv_reqp' to the request structures and
+ * link them together.
*/
- if (int_stat & ADV_INTR_STATUS_INTRB) {
- uchar intrb_code;
-
- AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
-
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
- asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
- if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
- asc_dvc->carr_pending_cnt != 0) {
- AdvWriteByteRegister(iop_base, IOPB_TICKLE,
- ADV_TICKLE_A);
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
- AdvWriteByteRegister(iop_base,
- IOPB_TICKLE,
- ADV_TICKLE_NOP);
- }
- }
- }
-
- if (asc_dvc->async_callback != 0) {
- (*asc_dvc->async_callback) (asc_dvc, intrb_code);
- }
+ req_cnt--;
+ reqp[req_cnt].next_reqp = NULL;
+ for (; req_cnt > 0; req_cnt--) {
+ reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
}
+ board->adv_reqp = &reqp[0];
- /*
- * Check if the IRQ stopper carrier contains a completed request.
- */
- while (((irq_next_vpa =
- le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
- /*
- * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
- * The RISC will have set 'areq_vpa' to a virtual address.
- *
- * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
- * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
- * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
- * in AdvExeScsiQueue().
- */
- scsiq = (ADV_SCSI_REQ_Q *)
- ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
-
- /*
- * Request finished with good status and the queue was not
- * DMAed to host memory by the firmware. Set all status fields
- * to indicate good status.
- */
- if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
- scsiq->done_status = QD_NO_ERROR;
- scsiq->host_status = scsiq->scsi_status = 0;
- scsiq->data_cnt = 0L;
- }
-
- /*
- * Advance the stopper pointer to the next carrier
- * ignoring the lower four bits. Free the previous
- * stopper carrier.
- */
- free_carrp = asc_dvc->irq_sp;
- asc_dvc->irq_sp = (ADV_CARR_T *)
- ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
-
- free_carrp->next_vpa =
- cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
- asc_dvc->carr_freelist = free_carrp;
- asc_dvc->carr_pending_cnt--;
-
- ASC_ASSERT(scsiq != NULL);
- target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
-
- /*
- * Clear request microcode control flag.
- */
- scsiq->cntl = 0;
-
- /*
- * If the command that completed was a SCSI INQUIRY and
- * LUN 0 was sent the command, then process the INQUIRY
- * command information for the device.
- *
- * Note: If data returned were either VPD or CmdDt data,
- * don't process the INQUIRY command information for
- * the device, otherwise may erroneously set *_able bits.
- */
- if (scsiq->done_status == QD_NO_ERROR &&
- scsiq->cdb[0] == INQUIRY &&
- scsiq->target_lun == 0 &&
- (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
- == ADV_INQ_RTN_STD_INQUIRY_DATA) {
- AdvInquiryHandling(asc_dvc, scsiq);
- }
-
- /*
- * Notify the driver of the completed request by passing
- * the ADV_SCSI_REQ_Q pointer to its callback function.
- */
- scsiq->a_flag |= ADV_SCSIQ_DONE;
- (*asc_dvc->isr_callback) (asc_dvc, scsiq);
- /*
- * Note: After the driver callback function is called, 'scsiq'
- * can no longer be referenced.
- *
- * Fall through and continue processing other completed
- * requests...
- */
-
- /*
- * Disable interrupts again in case the driver inadvertently
- * enabled interrupts in its callback function.
- *
- * The DvcEnterCritical() return value is ignored, because
- * the 'flags' saved when AdvISR() was first entered will be
- * used to restore the interrupt flag on exit.
- */
- (void)DvcEnterCritical();
+ if (adv_dvc->chip_type == ADV_CHIP_ASC3550) {
+ ASC_DBG(2, "AdvInitAsc3550Driver()\n");
+ warn_code = AdvInitAsc3550Driver(adv_dvc);
+ } else if (adv_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+ ASC_DBG(2, "AdvInitAsc38C0800Driver()\n");
+ warn_code = AdvInitAsc38C0800Driver(adv_dvc);
+ } else {
+ ASC_DBG(2, "AdvInitAsc38C1600Driver()\n");
+ warn_code = AdvInitAsc38C1600Driver(adv_dvc);
}
- DvcLeaveCritical(flags);
- return ADV_TRUE;
-}
+ err_code = adv_dvc->err_code;
-/*
- * Send an idle command to the chip and wait for completion.
- *
- * Command completion is polled for once per microsecond.
- *
- * The function can be called from anywhere including an interrupt handler.
- * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
- * functions to prevent reentrancy.
- *
- * Return Values:
- * ADV_TRUE - command completed successfully
- * ADV_FALSE - command failed
- * ADV_ERROR - command timed out
- */
-static int
-AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
- ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
-{
- ulong last_int_level;
- int result;
- ADV_DCNT i, j;
- AdvPortAddr iop_base;
-
- last_int_level = DvcEnterCritical();
-
- iop_base = asc_dvc->iop_base;
-
- /*
- * Clear the idle command status which is set by the microcode
- * to a non-zero value to indicate when the command is completed.
- * The non-zero result is one of the IDLE_CMD_STATUS_* values
- * defined in a_advlib.h.
- */
- AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
-
- /*
- * Write the idle command value after the idle command parameter
- * has been written to avoid a race condition. If the order is not
- * followed, the microcode may process the idle command before the
- * parameters have been written to LRAM.
- */
- AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
- cpu_to_le32(idle_cmd_parameter));
- AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
-
- /*
- * Tickle the RISC to tell it to process the idle command.
- */
- AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
- if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
- /*
- * Clear the tickle value. In the ASC-3550 the RISC flag
- * command 'clr_tickle_b' does not work unless the host
- * value is cleared.
- */
- AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+ if (warn_code || err_code) {
+ shost_printk(KERN_WARNING, shost, "error: warn 0x%x, error "
+ "0x%x\n", warn_code, err_code);
}
- /* Wait for up to 100 millisecond for the idle command to timeout. */
- for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
- /* Poll once each microsecond for command completion. */
- for (j = 0; j < SCSI_US_PER_MSEC; j++) {
- AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
- result);
- if (result != 0) {
- DvcLeaveCritical(last_int_level);
- return result;
- }
- DvcDelayMicroSecond(asc_dvc, (ushort)1);
- }
- }
+ goto exit;
- ASC_ASSERT(0); /* The idle command should never timeout. */
- DvcLeaveCritical(last_int_level);
- return ADV_ERROR;
+ kmalloc_failed:
+ shost_printk(KERN_ERR, shost, "error: kmalloc() failed\n");
+ err_code = ADV_ERROR;
+ exit:
+ return err_code;
}
-/*
- * Inquiry Information Byte 7 Handling
- *
- * Handle SCSI Inquiry Command information for a device by setting
- * microcode operating variables that affect WDTR, SDTR, and Tag
- * Queuing.
- */
-static void AdvInquiryHandling(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
+static void advansys_wide_free_mem(struct asc_board *board)
{
- AdvPortAddr iop_base;
- uchar tid;
- ADV_SCSI_INQUIRY *inq;
- ushort tidmask;
- ushort cfg_word;
-
- /*
- * AdvInquiryHandling() requires up to INQUIRY information Byte 7
- * to be available.
- *
- * If less than 8 bytes of INQUIRY information were requested or less
- * than 8 bytes were transferred, then return. cdb[4] is the request
- * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
- * microcode to the transfer residual count.
- */
-
- if (scsiq->cdb[4] < 8 ||
- (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) {
- return;
- }
-
- iop_base = asc_dvc->iop_base;
- tid = scsiq->target_id;
-
- inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
-
- /*
- * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
- */
- if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) {
- return;
- } else {
- /*
- * INQUIRY Byte 7 Handling
- *
- * Use a device's INQUIRY byte 7 to determine whether it
- * supports WDTR, SDTR, and Tag Queuing. If the feature
- * is enabled in the EEPROM and the device supports the
- * feature, then enable it in the microcode.
- */
-
- tidmask = ADV_TID_TO_TIDMASK(tid);
-
- /*
- * Wide Transfers
- *
- * If the EEPROM enabled WDTR for the device and the device
- * supports wide bus (16 bit) transfers, then turn on the
- * device's 'wdtr_able' bit and write the new value to the
- * microcode.
- */
- if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) {
- AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
- if ((cfg_word & tidmask) == 0) {
- cfg_word |= tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
- cfg_word);
-
- /*
- * Clear the microcode "SDTR negotiation" and "WDTR
- * negotiation" done indicators for the target to cause
- * it to negotiate with the new setting set above.
- * WDTR when accepted causes the target to enter
- * asynchronous mode, so SDTR must be negotiated.
- */
- AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
- cfg_word);
- cfg_word &= ~tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
- cfg_word);
- AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE,
- cfg_word);
- cfg_word &= ~tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE,
- cfg_word);
- }
- }
-
- /*
- * Synchronous Transfers
- *
- * If the EEPROM enabled SDTR for the device and the device
- * supports synchronous transfers, then turn on the device's
- * 'sdtr_able' bit. Write the new value to the microcode.
- */
- if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) {
- AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
- if ((cfg_word & tidmask) == 0) {
- cfg_word |= tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
- cfg_word);
-
- /*
- * Clear the microcode "SDTR negotiation" done indicator
- * for the target to cause it to negotiate with the new
- * setting set above.
- */
- AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
- cfg_word);
- cfg_word &= ~tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
- cfg_word);
- }
- }
- /*
- * If the Inquiry data included enough space for the SPI-3
- * Clocking field, then check if DT mode is supported.
- */
- if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
- (scsiq->cdb[4] >= 57 ||
- (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) {
- /*
- * PPR (Parallel Protocol Request) Capable
- *
- * If the device supports DT mode, then it must be PPR capable.
- * The PPR message will be used in place of the SDTR and WDTR
- * messages to negotiate synchronous speed and offset, transfer
- * width, and protocol options.
- */
- if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) {
- AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE,
- asc_dvc->ppr_able);
- asc_dvc->ppr_able |= tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE,
- asc_dvc->ppr_able);
- }
- }
-
- /*
- * If the EEPROM enabled Tag Queuing for the device and the
- * device supports Tag Queueing, then turn on the device's
- * 'tagqng_enable' bit in the microcode and set the microcode
- * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
- * value.
- *
- * Tag Queuing is disabled for the BIOS which runs in polled
- * mode and would see no benefit from Tag Queuing. Also by
- * disabling Tag Queuing in the BIOS devices with Tag Queuing
- * bugs will at least work with the BIOS.
- */
- if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) {
- AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
- cfg_word |= tidmask;
- AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
- cfg_word);
-
- AdvWriteByteLram(iop_base,
- ASC_MC_NUMBER_OF_MAX_CMD + tid,
- asc_dvc->max_dvc_qng);
- }
+ struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var;
+ kfree(adv_dvc->carrier_buf);
+ adv_dvc->carrier_buf = NULL;
+ kfree(adv_dvc->orig_reqp);
+ adv_dvc->orig_reqp = board->adv_reqp = NULL;
+ while (board->adv_sgblkp) {
+ adv_sgblk_t *sgp = board->adv_sgblkp;
+ board->adv_sgblkp = sgp->next_sgblkp;
+ kfree(sgp);
}
}
-MODULE_LICENSE("Dual BSD/GPL");
-
-static struct Scsi_Host *__devinit
-advansys_board_found(int iop, struct device *dev, int bus_type)
+static int __devinit advansys_board_found(struct Scsi_Host *shost,
+ unsigned int iop, int bus_type)
{
- struct Scsi_Host *shost;
- struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
- asc_board_t *boardp;
+ struct pci_dev *pdev;
+ struct asc_board *boardp = shost_priv(shost);
ASC_DVC_VAR *asc_dvc_varp = NULL;
ADV_DVC_VAR *adv_dvc_varp = NULL;
- adv_sgblk_t *sgp = NULL;
- int share_irq = FALSE;
- int iolen = 0;
- ADV_PADDR pci_memory_address;
- int warn_code, err_code;
- int ret;
+ int share_irq, warn_code, ret;
- /*
- * Adapter found.
- *
- * Register the adapter, get its configuration, and
- * initialize it.
- */
- ASC_DBG(2, "advansys_board_found: scsi_register()\n");
- shost = scsi_register(&driver_template, sizeof(asc_board_t));
-
- if (!shost)
- return NULL;
-
- /* Save a pointer to the Scsi_Host of each board found. */
- asc_host[asc_board_count++] = shost;
-
- /* Initialize private per board data */
- boardp = ASC_BOARDP(shost);
- memset(boardp, 0, sizeof(asc_board_t));
- boardp->id = asc_board_count - 1;
-
- /* Initialize spinlock. */
- spin_lock_init(&boardp->lock);
-
- /*
- * Handle both narrow and wide boards.
- *
- * If a Wide board was detected, set the board structure
- * wide board flag. Set-up the board structure based on
- * the board type.
- */
-#ifdef CONFIG_PCI
- if (bus_type == ASC_IS_PCI &&
- (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
- pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
- pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
- boardp->flags |= ASC_IS_WIDE_BOARD;
- }
-#endif /* CONFIG_PCI */
+ pdev = (bus_type == ASC_IS_PCI) ? to_pci_dev(boardp->dev) : NULL;
if (ASC_NARROW_BOARD(boardp)) {
- ASC_DBG(1, "advansys_board_found: narrow board\n");
+ ASC_DBG(1, "narrow board\n");
asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
asc_dvc_varp->bus_type = bus_type;
asc_dvc_varp->drv_ptr = boardp;
asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
- asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
asc_dvc_varp->iop_base = iop;
- asc_dvc_varp->isr_callback = asc_isr_callback;
} else {
- ASC_DBG(1, "advansys_board_found: wide board\n");
+#ifdef CONFIG_PCI
adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
adv_dvc_varp->drv_ptr = boardp;
adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
- adv_dvc_varp->isr_callback = adv_isr_callback;
- adv_dvc_varp->async_callback = adv_async_callback;
-#ifdef CONFIG_PCI
if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
- ASC_DBG(1, "advansys_board_found: ASC-3550\n");
+ ASC_DBG(1, "wide board ASC-3550\n");
adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
} else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
- ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
+ ASC_DBG(1, "wide board ASC-38C0800\n");
adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
} else {
- ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
+ ASC_DBG(1, "wide board ASC-38C1600\n");
adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
}
-#endif /* CONFIG_PCI */
- /*
- * Map the board's registers into virtual memory for
- * PCI slave access. Only memory accesses are used to
- * access the board's registers.
- *
- * Note: The PCI register base address is not always
- * page aligned, but the address passed to ioremap()
- * must be page aligned. It is guaranteed that the
- * PCI register base address will not cross a page
- * boundary.
- */
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
- iolen = ADV_3550_IOLEN;
- } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
- iolen = ADV_38C0800_IOLEN;
- } else {
- iolen = ADV_38C1600_IOLEN;
- }
-#ifdef CONFIG_PCI
- pci_memory_address = pci_resource_start(pdev, 1);
- ASC_DBG1(1,
- "advansys_board_found: pci_memory_address: 0x%lx\n",
- (ulong)pci_memory_address);
- if ((boardp->ioremap_addr =
- ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) {
- ASC_PRINT3
- ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
- boardp->id, pci_memory_address, iolen);
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
+ boardp->asc_n_io_port = pci_resource_len(pdev, 1);
+ boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1),
+ boardp->asc_n_io_port);
+ if (!boardp->ioremap_addr) {
+ shost_printk(KERN_ERR, shost, "ioremap(%lx, %d) "
+ "returned NULL\n",
+ (long)pci_resource_start(pdev, 1),
+ boardp->asc_n_io_port);
+ ret = -ENODEV;
+ goto err_shost;
}
- ASC_DBG1(1,
- "advansys_board_found: ioremap_addr: 0x%lx\n",
- (ulong)boardp->ioremap_addr);
- adv_dvc_varp->iop_base = (AdvPortAddr)
- (boardp->ioremap_addr +
- (pci_memory_address - (pci_memory_address & PAGE_MASK)));
- ASC_DBG1(1,
- "advansys_board_found: iop_base: 0x%lx\n",
- adv_dvc_varp->iop_base);
-#endif /* CONFIG_PCI */
+ adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr;
+ ASC_DBG(1, "iop_base: 0x%p\n", adv_dvc_varp->iop_base);
/*
* Even though it isn't used to access wide boards, other
@@ -17907,9 +13445,9 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
*/
boardp->ioport = iop;
- ASC_DBG2(1,
- "advansys_board_found: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
- (ushort)inp(iop + 1), (ushort)inpw(iop));
+ ASC_DBG(1, "iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
+ (ushort)inp(iop + 1), (ushort)inpw(iop));
+#endif /* CONFIG_PCI */
}
#ifdef CONFIG_PROC_FS
@@ -17917,18 +13455,16 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
* Allocate buffer for printing information from
* /proc/scsi/advansys/[0...].
*/
- if ((boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
- ASC_PRINT3
- ("advansys_board_found: board %d: kmalloc(%d, %d) returned NULL\n",
- boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
+ boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
+ if (!boardp->prtbuf) {
+ shost_printk(KERN_ERR, shost, "kmalloc(%d) returned NULL\n",
+ ASC_PRTBUF_SIZE);
+ ret = -ENOMEM;
+ goto err_unmap;
}
#endif /* CONFIG_PROC_FS */
if (ASC_NARROW_BOARD(boardp)) {
- asc_dvc_varp->cfg->dev = dev;
/*
* Set the board bus type and PCI IRQ before
* calling AscInitGetConfig().
@@ -17937,127 +13473,56 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
#ifdef CONFIG_ISA
case ASC_IS_ISA:
shost->unchecked_isa_dma = TRUE;
- share_irq = FALSE;
+ share_irq = 0;
break;
case ASC_IS_VL:
shost->unchecked_isa_dma = FALSE;
- share_irq = FALSE;
+ share_irq = 0;
break;
case ASC_IS_EISA:
shost->unchecked_isa_dma = FALSE;
- share_irq = TRUE;
+ share_irq = IRQF_SHARED;
break;
#endif /* CONFIG_ISA */
#ifdef CONFIG_PCI
case ASC_IS_PCI:
- shost->irq = asc_dvc_varp->irq_no = pdev->irq;
- asc_dvc_varp->cfg->pci_slot_info =
- ASC_PCI_MKID(pdev->bus->number,
- PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn));
shost->unchecked_isa_dma = FALSE;
- share_irq = TRUE;
+ share_irq = IRQF_SHARED;
break;
#endif /* CONFIG_PCI */
default:
- ASC_PRINT2
- ("advansys_board_found: board %d: unknown adapter type: %d\n",
- boardp->id, asc_dvc_varp->bus_type);
+ shost_printk(KERN_ERR, shost, "unknown adapter type: "
+ "%d\n", asc_dvc_varp->bus_type);
shost->unchecked_isa_dma = TRUE;
- share_irq = FALSE;
+ share_irq = 0;
break;
}
- } else {
- adv_dvc_varp->cfg->dev = dev;
- /*
- * For Wide boards set PCI information before calling
- * AdvInitGetConfig().
- */
-#ifdef CONFIG_PCI
- shost->irq = adv_dvc_varp->irq_no = pdev->irq;
- adv_dvc_varp->cfg->pci_slot_info =
- ASC_PCI_MKID(pdev->bus->number,
- PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn));
- shost->unchecked_isa_dma = FALSE;
- share_irq = TRUE;
-#endif /* CONFIG_PCI */
- }
- /*
- * Read the board configuration.
- */
- if (ASC_NARROW_BOARD(boardp)) {
/*
* NOTE: AscInitGetConfig() may change the board's
* bus_type value. The bus_type value should no
* longer be used. If the bus_type field must be
* referenced only use the bit-wise AND operator "&".
*/
- ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
- switch (ret = AscInitGetConfig(asc_dvc_varp)) {
- case 0: /* No error */
- break;
- case ASC_WARN_IO_PORT_ROTATE:
- ASC_PRINT1
- ("AscInitGetConfig: board %d: I/O port address modified\n",
- boardp->id);
- break;
- case ASC_WARN_AUTO_CONFIG:
- ASC_PRINT1
- ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
- boardp->id);
- break;
- case ASC_WARN_EEPROM_CHKSUM:
- ASC_PRINT1
- ("AscInitGetConfig: board %d: EEPROM checksum error\n",
- boardp->id);
- break;
- case ASC_WARN_IRQ_MODIFIED:
- ASC_PRINT1
- ("AscInitGetConfig: board %d: IRQ modified\n",
- boardp->id);
- break;
- case ASC_WARN_CMD_QNG_CONFLICT:
- ASC_PRINT1
- ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
- boardp->id);
- break;
- default:
- ASC_PRINT2
- ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
- boardp->id, ret);
- break;
- }
- if ((err_code = asc_dvc_varp->err_code) != 0) {
- ASC_PRINT3
- ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
- boardp->id,
- asc_dvc_varp->init_state, asc_dvc_varp->err_code);
- }
+ ASC_DBG(2, "AscInitGetConfig()\n");
+ ret = AscInitGetConfig(shost) ? -ENODEV : 0;
} else {
- ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
- if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
- ASC_PRINT2
- ("AdvInitGetConfig: board %d: warning: 0x%x\n",
- boardp->id, ret);
- }
- if ((err_code = adv_dvc_varp->err_code) != 0) {
- ASC_PRINT2
- ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
- boardp->id, adv_dvc_varp->err_code);
- }
- }
+#ifdef CONFIG_PCI
+ /*
+ * For Wide boards set PCI information before calling
+ * AdvInitGetConfig().
+ */
+ shost->unchecked_isa_dma = FALSE;
+ share_irq = IRQF_SHARED;
+ ASC_DBG(2, "AdvInitGetConfig()\n");
- if (err_code != 0) {
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
+ ret = AdvInitGetConfig(pdev, shost) ? -ENODEV : 0;
+#endif /* CONFIG_PCI */
}
+ if (ret)
+ goto err_free_proc;
+
/*
* Save the EEPROM configuration so that it can be displayed
* from /proc/scsi/advansys/[0...].
@@ -18098,61 +13563,10 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
/*
* Modify board configuration.
*/
- ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
- switch (ret = AscInitSetConfig(asc_dvc_varp)) {
- case 0: /* No error. */
- break;
- case ASC_WARN_IO_PORT_ROTATE:
- ASC_PRINT1
- ("AscInitSetConfig: board %d: I/O port address modified\n",
- boardp->id);
- break;
- case ASC_WARN_AUTO_CONFIG:
- ASC_PRINT1
- ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
- boardp->id);
- break;
- case ASC_WARN_EEPROM_CHKSUM:
- ASC_PRINT1
- ("AscInitSetConfig: board %d: EEPROM checksum error\n",
- boardp->id);
- break;
- case ASC_WARN_IRQ_MODIFIED:
- ASC_PRINT1
- ("AscInitSetConfig: board %d: IRQ modified\n",
- boardp->id);
- break;
- case ASC_WARN_CMD_QNG_CONFLICT:
- ASC_PRINT1
- ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
- boardp->id);
- break;
- default:
- ASC_PRINT2
- ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
- boardp->id, ret);
- break;
- }
- if (asc_dvc_varp->err_code != 0) {
- ASC_PRINT3
- ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
- boardp->id,
- asc_dvc_varp->init_state, asc_dvc_varp->err_code);
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
- }
-
- /*
- * Finish initializing the 'Scsi_Host' structure.
- */
- /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
- if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
- shost->irq = asc_dvc_varp->irq_no;
- }
+ ASC_DBG(2, "AscInitSetConfig()\n");
+ ret = AscInitSetConfig(pdev, shost) ? -ENODEV : 0;
+ if (ret)
+ goto err_free_proc;
} else {
ADVEEP_3550_CONFIG *ep_3550;
ADVEEP_38C0800_CONFIG *ep_38C0800;
@@ -18246,11 +13660,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
*/
boardp->init_tidmask |=
ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
-
- /*
- * Finish initializing the 'Scsi_Host' structure.
- */
- shost->irq = adv_dvc_varp->irq_no;
}
/*
@@ -18262,6 +13671,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
if (ASC_NARROW_BOARD(boardp)) {
shost->max_id = ASC_MAX_TID + 1;
shost->max_lun = ASC_MAX_LUN + 1;
+ shost->max_cmd_len = ASC_MAX_CDB_LEN;
shost->io_port = asc_dvc_varp->iop_base;
boardp->asc_n_io_port = ASC_IOADR_GAP;
@@ -18272,6 +13682,7 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
} else {
shost->max_id = ADV_MAX_TID + 1;
shost->max_lun = ADV_MAX_LUN + 1;
+ shost->max_cmd_len = ADV_MAX_CDB_LEN;
/*
* Save the I/O Port address and length even though
@@ -18280,7 +13691,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
* PCI Memory Mapped I/O.
*/
shost->io_port = iop;
- boardp->asc_n_io_port = iolen;
shost->this_id = adv_dvc_varp->chip_scsi_id;
@@ -18289,15 +13699,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
}
/*
- * 'n_io_port' currently is one byte.
- *
- * Set a value to 'n_io_port', but never referenced it because
- * it may be truncated.
- */
- shost->n_io_port = boardp->asc_n_io_port <= 255 ?
- boardp->asc_n_io_port : 255;
-
- /*
* Following v1.3.89, 'cmd_per_lun' is no longer needed
* and should be set to zero.
*
@@ -18343,14 +13744,12 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
shost->sg_tablesize = SG_ALL;
}
- ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
+ ASC_DBG(1, "sg_tablesize: %d\n", shost->sg_tablesize);
/* BIOS start address. */
if (ASC_NARROW_BOARD(boardp)) {
- shost->base = ((ulong)
- AscGetChipBiosAddress(asc_dvc_varp->
- iop_base,
- asc_dvc_varp->bus_type));
+ shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
+ asc_dvc_varp->bus_type);
} else {
/*
* Fill-in BIOS board variables. The Wide BIOS saves
@@ -18365,12 +13764,10 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
AdvReadWordLram(adv_dvc_varp->iop_base,
BIOS_CODELEN, boardp->bios_codelen);
- ASC_DBG2(1,
- "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
+ ASC_DBG(1, "bios_signature 0x%x, bios_version 0x%x\n",
boardp->bios_signature, boardp->bios_version);
- ASC_DBG2(1,
- "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
+ ASC_DBG(1, "bios_codeseg 0x%x, bios_codelen 0x%x\n",
boardp->bios_codeseg, boardp->bios_codelen);
/*
@@ -18392,30 +13789,6 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
* Register Board Resources - I/O Port, DMA, IRQ
*/
- /*
- * Register I/O port range.
- *
- * For Wide boards the I/O ports are not used to access
- * the board, but request the region anyway.
- *
- * 'shost->n_io_port' is not referenced, because it may be truncated.
- */
- ASC_DBG2(2,
- "advansys_board_found: request_region port 0x%lx, len 0x%x\n",
- (ulong)shost->io_port, boardp->asc_n_io_port);
- if (request_region(shost->io_port, boardp->asc_n_io_port,
- "advansys") == NULL) {
- ASC_PRINT3
- ("advansys_board_found: board %d: request_region() failed, port 0x%lx, len 0x%x\n",
- boardp->id, (ulong)shost->io_port, boardp->asc_n_io_port);
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
- }
-
/* Register DMA Channel for Narrow boards. */
shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
#ifdef CONFIG_ISA
@@ -18423,19 +13796,12 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
/* Register DMA channel for ISA bus. */
if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
- if ((ret =
- request_dma(shost->dma_channel, "advansys")) != 0) {
- ASC_PRINT3
- ("advansys_board_found: board %d: request_dma() %d failed %d\n",
- boardp->id, shost->dma_channel, ret);
- release_region(shost->io_port,
- boardp->asc_n_io_port);
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
+ ret = request_dma(shost->dma_channel, DRV_NAME);
+ if (ret) {
+ shost_printk(KERN_ERR, shost, "request_dma() "
+ "%d failed %d\n",
+ shost->dma_channel, ret);
+ goto err_free_proc;
}
AscEnableIsaDma(shost->dma_channel);
}
@@ -18443,573 +13809,392 @@ advansys_board_found(int iop, struct device *dev, int bus_type)
#endif /* CONFIG_ISA */
/* Register IRQ Number. */
- ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
- /*
- * If request_irq() fails with the IRQF_DISABLED flag set,
- * then try again without the IRQF_DISABLED flag set. This
- * allows IRQ sharing to work even with other drivers that
- * do not set the IRQF_DISABLED flag.
- *
- * If IRQF_DISABLED is not set, then interrupts are enabled
- * before the driver interrupt function is called.
- */
- if (((ret = request_irq(shost->irq, advansys_interrupt,
- IRQF_DISABLED | (share_irq ==
- TRUE ?
- IRQF_SHARED :
- 0), "advansys", boardp)) != 0)
- &&
- ((ret =
- request_irq(shost->irq, advansys_interrupt,
- (share_irq == TRUE ? IRQF_SHARED : 0),
- "advansys", boardp)) != 0)) {
+ ASC_DBG(2, "request_irq(%d, %p)\n", boardp->irq, shost);
+
+ ret = request_irq(boardp->irq, advansys_interrupt, share_irq,
+ DRV_NAME, shost);
+
+ if (ret) {
if (ret == -EBUSY) {
- ASC_PRINT2
- ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
- boardp->id, shost->irq);
+ shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x "
+ "already in use\n", boardp->irq);
} else if (ret == -EINVAL) {
- ASC_PRINT2
- ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
- boardp->id, shost->irq);
+ shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x "
+ "not valid\n", boardp->irq);
} else {
- ASC_PRINT3
- ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
- boardp->id, shost->irq, ret);
+ shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x "
+ "failed with %d\n", boardp->irq, ret);
}
- release_region(shost->io_port, boardp->asc_n_io_port);
- iounmap(boardp->ioremap_addr);
- if (shost->dma_channel != NO_ISA_DMA) {
- free_dma(shost->dma_channel);
- }
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
+ goto err_free_dma;
}
/*
* Initialize board RISC chip and enable interrupts.
*/
if (ASC_NARROW_BOARD(boardp)) {
- ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
+ ASC_DBG(2, "AscInitAsc1000Driver()\n");
warn_code = AscInitAsc1000Driver(asc_dvc_varp);
- err_code = asc_dvc_varp->err_code;
- if (warn_code || err_code) {
- ASC_PRINT4
- ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
- boardp->id,
- asc_dvc_varp->init_state, warn_code, err_code);
+ if (warn_code || asc_dvc_varp->err_code) {
+ shost_printk(KERN_ERR, shost, "error: init_state 0x%x, "
+ "warn 0x%x, error 0x%x\n",
+ asc_dvc_varp->init_state, warn_code,
+ asc_dvc_varp->err_code);
+ if (asc_dvc_varp->err_code)
+ ret = -ENODEV;
}
} else {
- ADV_CARR_T *carrp;
- int req_cnt = 0;
- adv_req_t *reqp = NULL;
- int sg_cnt = 0;
-
- /*
- * Allocate buffer carrier structures. The total size
- * is about 4 KB, so allocate all at once.
- */
- carrp = (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
- ASC_DBG1(1, "advansys_board_found: carrp 0x%lx\n", (ulong)carrp);
-
- if (carrp == NULL) {
- goto kmalloc_error;
- }
+ if (advansys_wide_init_chip(shost))
+ ret = -ENODEV;
+ }
- /*
- * Allocate up to 'max_host_qng' request structures for
- * the Wide board. The total size is about 16 KB, so
- * allocate all at once. If the allocation fails decrement
- * and try again.
- */
- for (req_cnt = adv_dvc_varp->max_host_qng;
- req_cnt > 0; req_cnt--) {
+ if (ret)
+ goto err_free_wide_mem;
- reqp = (adv_req_t *)
- kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
+ ASC_DBG_PRT_SCSI_HOST(2, shost);
- ASC_DBG3(1,
- "advansys_board_found: reqp 0x%lx, req_cnt %d, bytes %lu\n",
- (ulong)reqp, req_cnt,
- (ulong)sizeof(adv_req_t) * req_cnt);
+ ret = scsi_add_host(shost, boardp->dev);
+ if (ret)
+ goto err_free_wide_mem;
- if (reqp != NULL) {
- break;
- }
- }
- if (reqp == NULL) {
- goto kmalloc_error;
- }
+ scsi_scan_host(shost);
+ return 0;
- /*
- * Allocate up to ADV_TOT_SG_BLOCK request structures for
- * the Wide board. Each structure is about 136 bytes.
- */
- boardp->adv_sgblkp = NULL;
- for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
+ err_free_wide_mem:
+ advansys_wide_free_mem(boardp);
+ free_irq(boardp->irq, shost);
+ err_free_dma:
+ if (shost->dma_channel != NO_ISA_DMA)
+ free_dma(shost->dma_channel);
+ err_free_proc:
+ kfree(boardp->prtbuf);
+ err_unmap:
+ if (boardp->ioremap_addr)
+ iounmap(boardp->ioremap_addr);
+ err_shost:
+ return ret;
+}
- sgp = (adv_sgblk_t *)
- kmalloc(sizeof(adv_sgblk_t), GFP_ATOMIC);
+/*
+ * advansys_release()
+ *
+ * Release resources allocated for a single AdvanSys adapter.
+ */
+static int advansys_release(struct Scsi_Host *shost)
+{
+ struct asc_board *board = shost_priv(shost);
+ ASC_DBG(1, "begin\n");
+ scsi_remove_host(shost);
+ free_irq(board->irq, shost);
+ if (shost->dma_channel != NO_ISA_DMA) {
+ ASC_DBG(1, "free_dma()\n");
+ free_dma(shost->dma_channel);
+ }
+ if (ASC_NARROW_BOARD(board)) {
+ dma_unmap_single(board->dev,
+ board->dvc_var.asc_dvc_var.overrun_dma,
+ ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE);
+ } else {
+ iounmap(board->ioremap_addr);
+ advansys_wide_free_mem(board);
+ }
+ kfree(board->prtbuf);
+ scsi_host_put(shost);
+ ASC_DBG(1, "end\n");
+ return 0;
+}
- if (sgp == NULL) {
- break;
- }
+#define ASC_IOADR_TABLE_MAX_IX 11
- sgp->next_sgblkp = boardp->adv_sgblkp;
- boardp->adv_sgblkp = sgp;
+static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
+ 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
+ 0x0210, 0x0230, 0x0250, 0x0330
+};
- }
- ASC_DBG3(1,
- "advansys_board_found: sg_cnt %d * %u = %u bytes\n",
- sg_cnt, sizeof(adv_sgblk_t),
- (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
+/*
+ * The ISA IRQ number is found in bits 2 and 3 of the CfgLsw. It decodes as:
+ * 00: 10
+ * 01: 11
+ * 10: 12
+ * 11: 15
+ */
+static unsigned int __devinit advansys_isa_irq_no(PortAddr iop_base)
+{
+ unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base);
+ unsigned int chip_irq = ((cfg_lsw >> 2) & 0x03) + 10;
+ if (chip_irq == 13)
+ chip_irq = 15;
+ return chip_irq;
+}
- /*
- * If no request structures or scatter-gather structures could
- * be allocated, then return an error. Otherwise continue with
- * initialization.
- */
- kmalloc_error:
- if (carrp == NULL) {
- ASC_PRINT1
- ("advansys_board_found: board %d error: failed to kmalloc() carrier buffer.\n",
- boardp->id);
- err_code = ADV_ERROR;
- } else if (reqp == NULL) {
- kfree(carrp);
- ASC_PRINT1
- ("advansys_board_found: board %d error: failed to kmalloc() adv_req_t buffer.\n",
- boardp->id);
- err_code = ADV_ERROR;
- } else if (boardp->adv_sgblkp == NULL) {
- kfree(carrp);
- kfree(reqp);
- ASC_PRINT1
- ("advansys_board_found: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n",
- boardp->id);
- err_code = ADV_ERROR;
- } else {
+static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
+{
+ int err = -ENODEV;
+ PortAddr iop_base = _asc_def_iop_base[id];
+ struct Scsi_Host *shost;
+ struct asc_board *board;
- /* Save carrier buffer pointer. */
- boardp->orig_carrp = carrp;
+ if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) {
+ ASC_DBG(1, "I/O port 0x%x busy\n", iop_base);
+ return -ENODEV;
+ }
+ ASC_DBG(1, "probing I/O port 0x%x\n", iop_base);
+ if (!AscFindSignature(iop_base))
+ goto release_region;
+ if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
+ goto release_region;
- /*
- * Save original pointer for kfree() in case the
- * driver is built as a module and can be unloaded.
- */
- boardp->orig_reqp = reqp;
+ err = -ENOMEM;
+ shost = scsi_host_alloc(&advansys_template, sizeof(*board));
+ if (!shost)
+ goto release_region;
- adv_dvc_varp->carrier_buf = carrp;
+ board = shost_priv(shost);
+ board->irq = advansys_isa_irq_no(iop_base);
+ board->dev = dev;
- /*
- * Point 'adv_reqp' to the request structures and
- * link them together.
- */
- req_cnt--;
- reqp[req_cnt].next_reqp = NULL;
- for (; req_cnt > 0; req_cnt--) {
- reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
- }
- boardp->adv_reqp = &reqp[0];
-
- if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
- ASC_DBG(2,
- "advansys_board_found: AdvInitAsc3550Driver()\n");
- warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
- } else if (adv_dvc_varp->chip_type ==
- ADV_CHIP_ASC38C0800) {
- ASC_DBG(2,
- "advansys_board_found: AdvInitAsc38C0800Driver()\n");
- warn_code =
- AdvInitAsc38C0800Driver(adv_dvc_varp);
- } else {
- ASC_DBG(2,
- "advansys_board_found: AdvInitAsc38C1600Driver()\n");
- warn_code =
- AdvInitAsc38C1600Driver(adv_dvc_varp);
- }
- err_code = adv_dvc_varp->err_code;
+ err = advansys_board_found(shost, iop_base, ASC_IS_ISA);
+ if (err)
+ goto free_host;
- if (warn_code || err_code) {
- ASC_PRINT3
- ("advansys_board_found: board %d error: warn 0x%x, error 0x%x\n",
- boardp->id, warn_code, err_code);
- }
- }
- }
+ dev_set_drvdata(dev, shost);
+ return 0;
- if (err_code != 0) {
- release_region(shost->io_port, boardp->asc_n_io_port);
- if (ASC_WIDE_BOARD(boardp)) {
- iounmap(boardp->ioremap_addr);
- kfree(boardp->orig_carrp);
- boardp->orig_carrp = NULL;
- if (boardp->orig_reqp) {
- kfree(boardp->orig_reqp);
- boardp->orig_reqp = boardp->adv_reqp = NULL;
- }
- while ((sgp = boardp->adv_sgblkp) != NULL) {
- boardp->adv_sgblkp = sgp->next_sgblkp;
- kfree(sgp);
- }
- }
- if (shost->dma_channel != NO_ISA_DMA) {
- free_dma(shost->dma_channel);
- }
-#ifdef CONFIG_PROC_FS
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- free_irq(shost->irq, boardp);
- scsi_unregister(shost);
- asc_board_count--;
- return NULL;
- }
- ASC_DBG_PRT_SCSI_HOST(2, shost);
+ free_host:
+ scsi_host_put(shost);
+ release_region:
+ release_region(iop_base, ASC_IOADR_GAP);
+ return err;
+}
- return shost;
+static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
+{
+ int ioport = _asc_def_iop_base[id];
+ advansys_release(dev_get_drvdata(dev));
+ release_region(ioport, ASC_IOADR_GAP);
+ return 0;
}
+static struct isa_driver advansys_isa_driver = {
+ .probe = advansys_isa_probe,
+ .remove = __devexit_p(advansys_isa_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ },
+};
+
/*
- * advansys_detect()
- *
- * Detect function for AdvanSys adapters.
- *
- * Argument is a pointer to the host driver's scsi_hosts entry.
- *
- * Return number of adapters found.
- *
- * Note: Because this function is called during system initialization
- * it must not call SCSI mid-level functions including scsi_malloc()
- * and scsi_free().
+ * The VLB IRQ number is found in bits 2 to 4 of the CfgLsw. It decodes as:
+ * 000: invalid
+ * 001: 10
+ * 010: 11
+ * 011: 12
+ * 100: invalid
+ * 101: 14
+ * 110: 15
+ * 111: invalid
*/
-static int __init advansys_detect(struct scsi_host_template *tpnt)
+static unsigned int __devinit advansys_vlb_irq_no(PortAddr iop_base)
{
- static int detect_called = ASC_FALSE;
- int iop;
- int bus;
- int ioport = 0;
- struct device *dev = NULL;
-#ifdef CONFIG_PCI
- int pci_init_search = 0;
- struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
- int pci_card_cnt_max = 0;
- int pci_card_cnt = 0;
- struct pci_dev *pdev = NULL;
- int pci_device_id_cnt = 0;
- unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
- PCI_DEVICE_ID_ASP_1200A,
- PCI_DEVICE_ID_ASP_ABP940,
- PCI_DEVICE_ID_ASP_ABP940U,
- PCI_DEVICE_ID_ASP_ABP940UW,
- PCI_DEVICE_ID_38C0800_REV1,
- PCI_DEVICE_ID_38C1600_REV1
- };
-#endif /* CONFIG_PCI */
-
- if (detect_called == ASC_FALSE) {
- detect_called = ASC_TRUE;
- } else {
- printk
- ("AdvanSys SCSI: advansys_detect() multiple calls ignored\n");
+ unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base);
+ unsigned int chip_irq = ((cfg_lsw >> 2) & 0x07) + 9;
+ if ((chip_irq < 10) || (chip_irq == 13) || (chip_irq > 15))
return 0;
- }
-
- ASC_DBG(1, "advansys_detect: begin\n");
+ return chip_irq;
+}
- asc_board_count = 0;
+static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
+{
+ int err = -ENODEV;
+ PortAddr iop_base = _asc_def_iop_base[id];
+ struct Scsi_Host *shost;
+ struct asc_board *board;
+ if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) {
+ ASC_DBG(1, "I/O port 0x%x busy\n", iop_base);
+ return -ENODEV;
+ }
+ ASC_DBG(1, "probing I/O port 0x%x\n", iop_base);
+ if (!AscFindSignature(iop_base))
+ goto release_region;
/*
- * If I/O port probing has been modified, then verify and
- * clean-up the 'asc_ioport' list.
+ * I don't think this condition can actually happen, but the old
+ * driver did it, and the chances of finding a VLB setup in 2007
+ * to do testing with is slight to none.
*/
- if (asc_iopflag == ASC_TRUE) {
- for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
- ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n",
- ioport, asc_ioport[ioport]);
- if (asc_ioport[ioport] != 0) {
- for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX;
- iop++) {
- if (_asc_def_iop_base[iop] ==
- asc_ioport[ioport]) {
- break;
- }
- }
- if (iop == ASC_IOADR_TABLE_MAX_IX) {
- printk
- ("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
- asc_ioport[ioport]);
- asc_ioport[ioport] = 0;
- }
- }
- }
- ioport = 0;
- }
+ if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
+ goto release_region;
- for (bus = 0; bus < ASC_NUM_BUS; bus++) {
+ err = -ENOMEM;
+ shost = scsi_host_alloc(&advansys_template, sizeof(*board));
+ if (!shost)
+ goto release_region;
- ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
- bus, asc_bus_name[bus]);
- iop = 0;
+ board = shost_priv(shost);
+ board->irq = advansys_vlb_irq_no(iop_base);
+ board->dev = dev;
- while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
+ err = advansys_board_found(shost, iop_base, ASC_IS_VL);
+ if (err)
+ goto free_host;
- ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
- asc_board_count);
+ dev_set_drvdata(dev, shost);
+ return 0;
- switch (asc_bus[bus]) {
- case ASC_IS_ISA:
- case ASC_IS_VL:
-#ifdef CONFIG_ISA
- if (asc_iopflag == ASC_FALSE) {
- iop =
- AscSearchIOPortAddr(iop,
- asc_bus[bus]);
- } else {
- /*
- * ISA and VL I/O port scanning has either been
- * eliminated or limited to selected ports on
- * the LILO command line, /etc/lilo.conf, or
- * by setting variables when the module was loaded.
- */
- ASC_DBG(1,
- "advansys_detect: I/O port scanning modified\n");
- ioport_try_again:
- iop = 0;
- for (; ioport < ASC_NUM_IOPORT_PROBE;
- ioport++) {
- if ((iop =
- asc_ioport[ioport]) != 0) {
- break;
- }
- }
- if (iop) {
- ASC_DBG1(1,
- "advansys_detect: probing I/O port 0x%x...\n",
- iop);
- if (!request_region
- (iop, ASC_IOADR_GAP,
- "advansys")) {
- printk
- ("AdvanSys SCSI: specified I/O Port 0x%X is busy\n",
- iop);
- /* Don't try this I/O port twice. */
- asc_ioport[ioport] = 0;
- goto ioport_try_again;
- } else if (AscFindSignature(iop)
- == ASC_FALSE) {
- printk
- ("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n",
- iop);
- /* Don't try this I/O port twice. */
- release_region(iop,
- ASC_IOADR_GAP);
- asc_ioport[ioport] = 0;
- goto ioport_try_again;
- } else {
- /*
- * If this isn't an ISA board, then it must be
- * a VL board. If currently looking an ISA
- * board is being looked for then try for
- * another ISA board in 'asc_ioport'.
- */
- if (asc_bus[bus] ==
- ASC_IS_ISA
- &&
- (AscGetChipVersion
- (iop,
- ASC_IS_ISA) &
- ASC_CHIP_VER_ISA_BIT)
- == 0) {
- /*
- * Don't clear 'asc_ioport[ioport]'. Try
- * this board again for VL. Increment
- * 'ioport' past this board.
- */
- ioport++;
- release_region
- (iop,
- ASC_IOADR_GAP);
- goto ioport_try_again;
- }
- }
- /*
- * This board appears good, don't try the I/O port
- * again by clearing its value. Increment 'ioport'
- * for the next iteration.
- */
- asc_ioport[ioport++] = 0;
- }
- }
-#endif /* CONFIG_ISA */
- break;
+ free_host:
+ scsi_host_put(shost);
+ release_region:
+ release_region(iop_base, ASC_IOADR_GAP);
+ return -ENODEV;
+}
- case ASC_IS_EISA:
-#ifdef CONFIG_ISA
- iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
-#endif /* CONFIG_ISA */
- break;
+static struct isa_driver advansys_vlb_driver = {
+ .probe = advansys_vlb_probe,
+ .remove = __devexit_p(advansys_isa_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "advansys_vlb",
+ },
+};
- case ASC_IS_PCI:
-#ifdef CONFIG_PCI
- if (pci_init_search == 0) {
- int i, j;
-
- pci_init_search = 1;
-
- /* Find all PCI cards. */
- while (pci_device_id_cnt <
- ASC_PCI_DEVICE_ID_CNT) {
- if ((pdev =
- pci_find_device
- (PCI_VENDOR_ID_ASP,
- pci_device_id
- [pci_device_id_cnt],
- pdev)) == NULL) {
- pci_device_id_cnt++;
- } else {
- if (pci_enable_device
- (pdev) == 0) {
- pci_devicep
- [pci_card_cnt_max++]
- = pdev;
- }
- }
- }
+static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
+ { "ABP7401" },
+ { "ABP7501" },
+ { "" }
+};
- /*
- * Sort PCI cards in ascending order by PCI Bus, Slot,
- * and Device Number.
- */
- for (i = 0; i < pci_card_cnt_max - 1;
- i++) {
- for (j = i + 1;
- j < pci_card_cnt_max;
- j++) {
- if ((pci_devicep[j]->
- bus->number <
- pci_devicep[i]->
- bus->number)
- ||
- ((pci_devicep[j]->
- bus->number ==
- pci_devicep[i]->
- bus->number)
- &&
- (pci_devicep[j]->
- devfn <
- pci_devicep[i]->
- devfn))) {
- pdev =
- pci_devicep
- [i];
- pci_devicep[i] =
- pci_devicep
- [j];
- pci_devicep[j] =
- pdev;
- }
- }
- }
+MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
- pci_card_cnt = 0;
- } else {
- pci_card_cnt++;
- }
+/*
+ * EISA is a little more tricky than PCI; each EISA device may have two
+ * channels, and this driver is written to make each channel its own Scsi_Host
+ */
+struct eisa_scsi_data {
+ struct Scsi_Host *host[2];
+};
- if (pci_card_cnt == pci_card_cnt_max) {
- iop = 0;
- } else {
- pdev = pci_devicep[pci_card_cnt];
-
- ASC_DBG2(2,
- "advansys_detect: devfn %d, bus number %d\n",
- pdev->devfn,
- pdev->bus->number);
- iop = pci_resource_start(pdev, 0);
- ASC_DBG2(1,
- "advansys_detect: vendorID %X, deviceID %X\n",
- pdev->vendor,
- pdev->device);
- ASC_DBG2(2,
- "advansys_detect: iop %X, irqLine %d\n",
- iop, pdev->irq);
- }
- if (pdev)
- dev = &pdev->dev;
+/*
+ * The EISA IRQ number is found in bits 8 to 10 of the CfgLsw. It decodes as:
+ * 000: 10
+ * 001: 11
+ * 010: 12
+ * 011: invalid
+ * 100: 14
+ * 101: 15
+ * 110: invalid
+ * 111: invalid
+ */
+static unsigned int __devinit advansys_eisa_irq_no(struct eisa_device *edev)
+{
+ unsigned short cfg_lsw = inw(edev->base_addr + 0xc86);
+ unsigned int chip_irq = ((cfg_lsw >> 8) & 0x07) + 10;
+ if ((chip_irq == 13) || (chip_irq > 15))
+ return 0;
+ return chip_irq;
+}
-#endif /* CONFIG_PCI */
- break;
+static int __devinit advansys_eisa_probe(struct device *dev)
+{
+ int i, ioport, irq = 0;
+ int err;
+ struct eisa_device *edev = to_eisa_device(dev);
+ struct eisa_scsi_data *data;
- default:
- ASC_PRINT1
- ("advansys_detect: unknown bus type: %d\n",
- asc_bus[bus]);
- break;
- }
- ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop);
+ err = -ENOMEM;
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ goto fail;
+ ioport = edev->base_addr + 0xc30;
- /*
- * Adapter not found, try next bus type.
- */
- if (iop == 0) {
- break;
- }
+ err = -ENODEV;
+ for (i = 0; i < 2; i++, ioport += 0x20) {
+ struct asc_board *board;
+ struct Scsi_Host *shost;
+ if (!request_region(ioport, ASC_IOADR_GAP, DRV_NAME)) {
+ printk(KERN_WARNING "Region %x-%x busy\n", ioport,
+ ioport + ASC_IOADR_GAP - 1);
+ continue;
+ }
+ if (!AscFindSignature(ioport)) {
+ release_region(ioport, ASC_IOADR_GAP);
+ continue;
+ }
- advansys_board_found(iop, dev, asc_bus[bus]);
+ /*
+ * I don't know why we need to do this for EISA chips, but
+ * not for any others. It looks to be equivalent to
+ * AscGetChipCfgMsw, but I may have overlooked something,
+ * so I'm not converting it until I get an EISA board to
+ * test with.
+ */
+ inw(ioport + 4);
+
+ if (!irq)
+ irq = advansys_eisa_irq_no(edev);
+
+ err = -ENOMEM;
+ shost = scsi_host_alloc(&advansys_template, sizeof(*board));
+ if (!shost)
+ goto release_region;
+
+ board = shost_priv(shost);
+ board->irq = irq;
+ board->dev = dev;
+
+ err = advansys_board_found(shost, ioport, ASC_IS_EISA);
+ if (!err) {
+ data->host[i] = shost;
+ continue;
}
+
+ scsi_host_put(shost);
+ release_region:
+ release_region(ioport, ASC_IOADR_GAP);
+ break;
}
- ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n",
- asc_board_count);
- return asc_board_count;
+ if (err)
+ goto free_data;
+ dev_set_drvdata(dev, data);
+ return 0;
+
+ free_data:
+ kfree(data->host[0]);
+ kfree(data->host[1]);
+ kfree(data);
+ fail:
+ return err;
}
-/*
- * advansys_release()
- *
- * Release resources allocated for a single AdvanSys adapter.
- */
-static int advansys_release(struct Scsi_Host *shost)
+static __devexit int advansys_eisa_remove(struct device *dev)
{
- asc_board_t *boardp;
+ int i;
+ struct eisa_scsi_data *data = dev_get_drvdata(dev);
- ASC_DBG(1, "advansys_release: begin\n");
- boardp = ASC_BOARDP(shost);
- free_irq(shost->irq, boardp);
- if (shost->dma_channel != NO_ISA_DMA) {
- ASC_DBG(1, "advansys_release: free_dma()\n");
- free_dma(shost->dma_channel);
+ for (i = 0; i < 2; i++) {
+ int ioport;
+ struct Scsi_Host *shost = data->host[i];
+ if (!shost)
+ continue;
+ ioport = shost->io_port;
+ advansys_release(shost);
+ release_region(ioport, ASC_IOADR_GAP);
}
- release_region(shost->io_port, boardp->asc_n_io_port);
- if (ASC_WIDE_BOARD(boardp)) {
- adv_sgblk_t *sgp = NULL;
- iounmap(boardp->ioremap_addr);
- kfree(boardp->orig_carrp);
- boardp->orig_carrp = NULL;
- if (boardp->orig_reqp) {
- kfree(boardp->orig_reqp);
- boardp->orig_reqp = boardp->adv_reqp = NULL;
- }
- while ((sgp = boardp->adv_sgblkp) != NULL) {
- boardp->adv_sgblkp = sgp->next_sgblkp;
- kfree(sgp);
- }
- }
-#ifdef CONFIG_PROC_FS
- ASC_ASSERT(boardp->prtbuf != NULL);
- kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
- scsi_unregister(shost);
- ASC_DBG(1, "advansys_release: end\n");
+ kfree(data);
return 0;
}
-#ifdef CONFIG_PCI
+static struct eisa_driver advansys_eisa_driver = {
+ .id_table = advansys_eisa_table,
+ .driver = {
+ .name = DRV_NAME,
+ .probe = advansys_eisa_probe,
+ .remove = __devexit_p(advansys_eisa_remove),
+ }
+};
+
/* PCI Devices supported by this driver */
static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
{PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
@@ -19028,4 +14213,131 @@ static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
};
MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
-#endif /* CONFIG_PCI */
+
+static void __devinit advansys_set_latency(struct pci_dev *pdev)
+{
+ if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
+ (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
+ } else {
+ u8 latency;
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
+ if (latency < 0x20)
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
+ }
+}
+
+static int __devinit
+advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err, ioport;
+ struct Scsi_Host *shost;
+ struct asc_board *board;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ goto fail;
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err)
+ goto disable_device;
+ pci_set_master(pdev);
+ advansys_set_latency(pdev);
+
+ err = -ENODEV;
+ if (pci_resource_len(pdev, 0) == 0)
+ goto release_region;
+
+ ioport = pci_resource_start(pdev, 0);
+
+ err = -ENOMEM;
+ shost = scsi_host_alloc(&advansys_template, sizeof(*board));
+ if (!shost)
+ goto release_region;
+
+ board = shost_priv(shost);
+ board->irq = pdev->irq;
+ board->dev = &pdev->dev;
+
+ if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
+ pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
+ pdev->device == PCI_DEVICE_ID_38C1600_REV1) {
+ board->flags |= ASC_IS_WIDE_BOARD;
+ }
+
+ err = advansys_board_found(shost, ioport, ASC_IS_PCI);
+ if (err)
+ goto free_host;
+
+ pci_set_drvdata(pdev, shost);
+ return 0;
+
+ free_host:
+ scsi_host_put(shost);
+ release_region:
+ pci_release_regions(pdev);
+ disable_device:
+ pci_disable_device(pdev);
+ fail:
+ return err;
+}
+
+static void __devexit advansys_pci_remove(struct pci_dev *pdev)
+{
+ advansys_release(pci_get_drvdata(pdev));
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static struct pci_driver advansys_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = advansys_pci_tbl,
+ .probe = advansys_pci_probe,
+ .remove = __devexit_p(advansys_pci_remove),
+};
+
+static int __init advansys_init(void)
+{
+ int error;
+
+ error = isa_register_driver(&advansys_isa_driver,
+ ASC_IOADR_TABLE_MAX_IX);
+ if (error)
+ goto fail;
+
+ error = isa_register_driver(&advansys_vlb_driver,
+ ASC_IOADR_TABLE_MAX_IX);
+ if (error)
+ goto unregister_isa;
+
+ error = eisa_driver_register(&advansys_eisa_driver);
+ if (error)
+ goto unregister_vlb;
+
+ error = pci_register_driver(&advansys_pci_driver);
+ if (error)
+ goto unregister_eisa;
+
+ return 0;
+
+ unregister_eisa:
+ eisa_driver_unregister(&advansys_eisa_driver);
+ unregister_vlb:
+ isa_unregister_driver(&advansys_vlb_driver);
+ unregister_isa:
+ isa_unregister_driver(&advansys_isa_driver);
+ fail:
+ return error;
+}
+
+static void __exit advansys_exit(void)
+{
+ pci_unregister_driver(&advansys_pci_driver);
+ eisa_driver_unregister(&advansys_eisa_driver);
+ isa_unregister_driver(&advansys_vlb_driver);
+ isa_unregister_driver(&advansys_isa_driver);
+}
+
+module_init(advansys_init);
+module_exit(advansys_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index d30a30786dd..ea8c6994764 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -1,6 +1,6 @@
/* aha152x.c -- Adaptec AHA-152x driver
- * Author: Jürgen E. Fischer, fischer@norbit.de
- * Copyright 1993-2004 Jürgen E. Fischer
+ * Author: Jürgen E. Fischer, fischer@norbit.de
+ * Copyright 1993-2004 Jürgen E. Fischer
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -357,7 +357,7 @@ enum {
check_condition = 0x0800, /* requesting sense after CHECK CONDITION */
};
-MODULE_AUTHOR("Jürgen Fischer");
+MODULE_AUTHOR("Jürgen Fischer");
MODULE_DESCRIPTION(AHA152X_REVID);
MODULE_LICENSE("GPL");
@@ -613,7 +613,7 @@ struct aha152x_scdata {
#define SCNEXT(SCpnt) SCDATA(SCpnt)->next
#define SCSEM(SCpnt) SCDATA(SCpnt)->done
-#define SG_ADDRESS(buffer) ((char *) (page_address((buffer)->page)+(buffer)->offset))
+#define SG_ADDRESS(buffer) ((char *) sg_virt((buffer)))
/* state handling */
static void seldi_run(struct Scsi_Host *shpnt);
@@ -907,9 +907,10 @@ out_host_put:
void aha152x_release(struct Scsi_Host *shpnt)
{
- if(!shpnt)
+ if (!shpnt)
return;
+ scsi_remove_host(shpnt);
if (shpnt->irq)
free_irq(shpnt->irq, shpnt);
@@ -923,7 +924,6 @@ void aha152x_release(struct Scsi_Host *shpnt)
pnp_device_detach(HOSTDATA(shpnt)->pnpdev);
#endif
- scsi_remove_host(shpnt);
list_del(&HOSTDATA(shpnt)->host_list);
scsi_host_put(shpnt);
}
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index cbbfbc9f3e0..bbcc2c52d79 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -49,7 +49,7 @@
#include "aha1542.h"
#define SCSI_BUF_PA(address) isa_virt_to_bus(address)
-#define SCSI_SG_PA(sgent) (isa_page_to_bus((sgent)->page) + (sgent)->offset)
+#define SCSI_SG_PA(sgent) (isa_page_to_bus(sg_page((sgent))) + (sgent)->offset)
static void BAD_DMA(void *address, unsigned int length)
{
@@ -61,15 +61,14 @@ static void BAD_DMA(void *address, unsigned int length)
}
static void BAD_SG_DMA(Scsi_Cmnd * SCpnt,
- struct scatterlist *sgpnt,
+ struct scatterlist *sgp,
int nseg,
int badseg)
{
printk(KERN_CRIT "sgpnt[%d:%d] page %p/0x%llx length %u\n",
- badseg, nseg,
- page_address(sgpnt[badseg].page) + sgpnt[badseg].offset,
- (unsigned long long)SCSI_SG_PA(&sgpnt[badseg]),
- sgpnt[badseg].length);
+ badseg, nseg, sg_virt(sgp),
+ (unsigned long long)SCSI_SG_PA(sgp),
+ sgp->length);
/*
* Not safe to continue.
@@ -691,7 +690,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen);
if (SCpnt->use_sg) {
- struct scatterlist *sgpnt;
+ struct scatterlist *sg;
struct chain *cptr;
#ifdef DEBUG
unsigned char *ptr;
@@ -699,23 +698,20 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
int i;
ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */
SCpnt->host_scribble = kmalloc(512, GFP_KERNEL | GFP_DMA);
- sgpnt = (struct scatterlist *) SCpnt->request_buffer;
cptr = (struct chain *) SCpnt->host_scribble;
if (cptr == NULL) {
/* free the claimed mailbox slot */
HOSTDATA(SCpnt->device->host)->SCint[mbo] = NULL;
return SCSI_MLQUEUE_HOST_BUSY;
}
- for (i = 0; i < SCpnt->use_sg; i++) {
- if (sgpnt[i].length == 0 || SCpnt->use_sg > 16 ||
- (((int) sgpnt[i].offset) & 1) || (sgpnt[i].length & 1)) {
+ scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) {
+ if (sg->length == 0 || SCpnt->use_sg > 16 ||
+ (((int) sg->offset) & 1) || (sg->length & 1)) {
unsigned char *ptr;
printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i);
- for (i = 0; i < SCpnt->use_sg; i++) {
+ scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) {
printk(KERN_CRIT "%d: %p %d\n", i,
- (page_address(sgpnt[i].page) +
- sgpnt[i].offset),
- sgpnt[i].length);
+ sg_virt(sg), sg->length);
};
printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr);
ptr = (unsigned char *) &cptr[i];
@@ -723,10 +719,10 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
printk("%02x ", ptr[i]);
panic("Foooooooood fight!");
};
- any2scsi(cptr[i].dataptr, SCSI_SG_PA(&sgpnt[i]));
- if (SCSI_SG_PA(&sgpnt[i]) + sgpnt[i].length - 1 > ISA_DMA_THRESHOLD)
- BAD_SG_DMA(SCpnt, sgpnt, SCpnt->use_sg, i);
- any2scsi(cptr[i].datalen, sgpnt[i].length);
+ any2scsi(cptr[i].dataptr, SCSI_SG_PA(sg));
+ if (SCSI_SG_PA(sg) + sg->length - 1 > ISA_DMA_THRESHOLD)
+ BAD_SG_DMA(SCpnt, sg, SCpnt->use_sg, i);
+ any2scsi(cptr[i].datalen, sg->length);
};
any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(cptr));
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index e4a4f3a965d..f6722fd4600 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -563,6 +563,7 @@ static struct scsi_host_template aha1740_template = {
.sg_tablesize = AHA1740_SCATTER,
.cmd_per_lun = AHA1740_CMDLUN,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.eh_abort_handler = aha1740_eh_abort_handler,
};
diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c
index c4d17231c82..6d86a9be538 100644
--- a/drivers/scsi/aic7xxx/aic7770.c
+++ b/drivers/scsi/aic7xxx/aic7770.c
@@ -60,8 +60,6 @@
#define ID_OLV_274xD 0x04907783 /* Olivetti OEM (Differential) */
static int aic7770_chip_init(struct ahc_softc *ahc);
-static int aic7770_suspend(struct ahc_softc *ahc);
-static int aic7770_resume(struct ahc_softc *ahc);
static int aha2840_load_seeprom(struct ahc_softc *ahc);
static ahc_device_setup_t ahc_aic7770_VL_setup;
static ahc_device_setup_t ahc_aic7770_EISA_setup;
@@ -155,8 +153,6 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
return (error);
ahc->bus_chip_init = aic7770_chip_init;
- ahc->bus_suspend = aic7770_suspend;
- ahc->bus_resume = aic7770_resume;
error = ahc_reset(ahc, /*reinit*/FALSE);
if (error != 0)
@@ -272,18 +268,6 @@ aic7770_chip_init(struct ahc_softc *ahc)
return (ahc_chip_init(ahc));
}
-static int
-aic7770_suspend(struct ahc_softc *ahc)
-{
- return (ahc_suspend(ahc));
-}
-
-static int
-aic7770_resume(struct ahc_softc *ahc)
-{
- return (ahc_resume(ahc));
-}
-
/*
* Read the 284x SEEPROM.
*/
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index 27adbb294ac..ce638aa6005 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -1003,8 +1003,15 @@ struct ahd_suspend_channel_state {
uint8_t seqctl;
};
+struct ahd_suspend_pci_state {
+ uint32_t devconfig;
+ uint8_t command;
+ uint8_t csize_lattime;
+};
+
struct ahd_suspend_state {
struct ahd_suspend_channel_state channel[2];
+ struct ahd_suspend_pci_state pci_state;
uint8_t optionmode;
uint8_t dscommand0;
uint8_t dspcistatus;
@@ -1333,6 +1340,8 @@ struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t);
int ahd_pci_config(struct ahd_softc *,
struct ahd_pci_identity *);
int ahd_pci_test_register_access(struct ahd_softc *);
+void ahd_pci_suspend(struct ahd_softc *);
+void ahd_pci_resume(struct ahd_softc *);
/************************** SCB and SCB queue management **********************/
void ahd_qinfifo_requeue_tail(struct ahd_softc *ahd,
@@ -1343,6 +1352,8 @@ struct ahd_softc *ahd_alloc(void *platform_arg, char *name);
int ahd_softc_init(struct ahd_softc *);
void ahd_controller_info(struct ahd_softc *ahd, char *buf);
int ahd_init(struct ahd_softc *ahd);
+int ahd_suspend(struct ahd_softc *ahd);
+void ahd_resume(struct ahd_softc *ahd);
int ahd_default_config(struct ahd_softc *ahd);
int ahd_parse_vpddata(struct ahd_softc *ahd,
struct vpd_config *vpd);
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 05f692bd0ad..a7dd8cdda47 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -7175,7 +7175,6 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd)
ahd->flags &= ~AHD_ALL_INTERRUPTS;
}
-#if 0
int
ahd_suspend(struct ahd_softc *ahd)
{
@@ -7189,19 +7188,15 @@ ahd_suspend(struct ahd_softc *ahd)
ahd_shutdown(ahd);
return (0);
}
-#endif /* 0 */
-#if 0
-int
+void
ahd_resume(struct ahd_softc *ahd)
{
ahd_reset(ahd, /*reinit*/TRUE);
ahd_intr_enable(ahd, TRUE);
ahd_restart(ahd);
- return (0);
}
-#endif /* 0 */
/************************** Busy Target Table *********************************/
/*
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index a055a96e3ad..2d020405480 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -315,8 +315,8 @@ uint32_t aic79xx_slowcrc;
*/
static char *aic79xx = NULL;
-MODULE_AUTHOR("Maintainer: Justin T. Gibbs <gibbs@scsiguy.com>");
-MODULE_DESCRIPTION("Adaptec Aic790X U320 SCSI Host Bus Adapter driver");
+MODULE_AUTHOR("Maintainer: Hannes Reinecke <hare@suse.de>");
+MODULE_DESCRIPTION("Adaptec AIC790X U320 SCSI Host Bus Adapter driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(AIC79XX_DRIVER_VERSION);
module_param(aic79xx, charp, 0444);
@@ -766,6 +766,7 @@ struct scsi_host_template aic79xx_driver_template = {
.max_sectors = 8192,
.cmd_per_lun = 2,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.slave_alloc = ahd_linux_slave_alloc,
.slave_configure = ahd_linux_slave_configure,
.target_alloc = ahd_linux_target_alloc,
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index c62ce41f279..66f0259edb6 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -50,6 +50,8 @@ static int ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd,
static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
u_long *bus_addr,
uint8_t __iomem **maddr);
+static int ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg);
+static int ahd_linux_pci_dev_resume(struct pci_dev *pdev);
static void ahd_linux_pci_dev_remove(struct pci_dev *pdev);
/* Define the macro locally since it's different for different class of chips.
@@ -86,10 +88,58 @@ MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table);
static struct pci_driver aic79xx_pci_driver = {
.name = "aic79xx",
.probe = ahd_linux_pci_dev_probe,
+#ifdef CONFIG_PM
+ .suspend = ahd_linux_pci_dev_suspend,
+ .resume = ahd_linux_pci_dev_resume,
+#endif
.remove = ahd_linux_pci_dev_remove,
.id_table = ahd_linux_pci_id_table
};
+static int
+ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ahd_softc *ahd = pci_get_drvdata(pdev);
+ int rc;
+
+ if ((rc = ahd_suspend(ahd)))
+ return rc;
+
+ ahd_pci_suspend(ahd);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ if (mesg.event == PM_EVENT_SUSPEND)
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return rc;
+}
+
+static int
+ahd_linux_pci_dev_resume(struct pci_dev *pdev)
+{
+ struct ahd_softc *ahd = pci_get_drvdata(pdev);
+ int rc;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ if ((rc = pci_enable_device(pdev))) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to enable device after resume (%d)\n", rc);
+ return rc;
+ }
+
+ pci_set_master(pdev);
+
+ ahd_pci_resume(ahd);
+
+ ahd_resume(ahd);
+
+ return rc;
+}
+
static void
ahd_linux_pci_dev_remove(struct pci_dev *pdev)
{
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 0bada0028aa..7a203a90601 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -389,6 +389,33 @@ ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
return error;
}
+void
+ahd_pci_suspend(struct ahd_softc *ahd)
+{
+ /*
+ * Save chip register configuration data for chip resets
+ * that occur during runtime and resume events.
+ */
+ ahd->suspend_state.pci_state.devconfig =
+ ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4);
+ ahd->suspend_state.pci_state.command =
+ ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/1);
+ ahd->suspend_state.pci_state.csize_lattime =
+ ahd_pci_read_config(ahd->dev_softc, CSIZE_LATTIME, /*bytes*/1);
+
+}
+
+void
+ahd_pci_resume(struct ahd_softc *ahd)
+{
+ ahd_pci_write_config(ahd->dev_softc, DEVCONFIG,
+ ahd->suspend_state.pci_state.devconfig, /*bytes*/4);
+ ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
+ ahd->suspend_state.pci_state.command, /*bytes*/1);
+ ahd_pci_write_config(ahd->dev_softc, CSIZE_LATTIME,
+ ahd->suspend_state.pci_state.csize_lattime, /*bytes*/1);
+}
+
/*
* Perform some simple tests that should catch situations where
* our registers are invalidly mapped.
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index e1bd57b9f23..3d4e42d9045 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -962,16 +962,6 @@ struct ahc_softc {
ahc_bus_chip_init_t bus_chip_init;
/*
- * Bus specific suspend routine.
- */
- ahc_bus_suspend_t bus_suspend;
-
- /*
- * Bus specific resume routine.
- */
- ahc_bus_resume_t bus_resume;
-
- /*
* Target mode related state kept on a per enabled lun basis.
* Targets that are not enabled will have null entries.
* As an initiator, we keep one target entry for our initiator
@@ -1153,6 +1143,7 @@ struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t);
int ahc_pci_config(struct ahc_softc *,
struct ahc_pci_identity *);
int ahc_pci_test_register_access(struct ahc_softc *);
+void ahc_pci_resume(struct ahc_softc *ahc);
/*************************** EISA/VL Front End ********************************/
struct aic7770_identity *aic7770_find_device(uint32_t);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 2e9c38f2e8a..390b0fc991c 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -335,8 +335,8 @@ static uint32_t aic7xxx_periodic_otag;
*/
static char *aic7xxx = NULL;
-MODULE_AUTHOR("Maintainer: Justin T. Gibbs <gibbs@scsiguy.com>");
-MODULE_DESCRIPTION("Adaptec Aic77XX/78XX SCSI Host Bus Adapter driver");
+MODULE_AUTHOR("Maintainer: Hannes Reinecke <hare@suse.de>");
+MODULE_DESCRIPTION("Adaptec AIC77XX/78XX SCSI Host Bus Adapter driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(AIC7XXX_DRIVER_VERSION);
module_param(aic7xxx, charp, 0444);
@@ -747,6 +747,7 @@ struct scsi_host_template aic7xxx_driver_template = {
.max_sectors = 8192,
.cmd_per_lun = 2,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.slave_alloc = ahc_linux_slave_alloc,
.slave_configure = ahc_linux_slave_configure,
.target_alloc = ahc_linux_target_alloc,
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index ea5687df732..4488946cff2 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -49,6 +49,8 @@ static int ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc,
static int ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
u_long *bus_addr,
uint8_t __iomem **maddr);
+static int ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg);
+static int ahc_linux_pci_dev_resume(struct pci_dev *pdev);
static void ahc_linux_pci_dev_remove(struct pci_dev *pdev);
/* Define the macro locally since it's different for different class of chips.
@@ -133,10 +135,54 @@ MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
static struct pci_driver aic7xxx_pci_driver = {
.name = "aic7xxx",
.probe = ahc_linux_pci_dev_probe,
+#ifdef CONFIG_PM
+ .suspend = ahc_linux_pci_dev_suspend,
+ .resume = ahc_linux_pci_dev_resume,
+#endif
.remove = ahc_linux_pci_dev_remove,
.id_table = ahc_linux_pci_id_table
};
+static int
+ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ahc_softc *ahc = pci_get_drvdata(pdev);
+ int rc;
+
+ if ((rc = ahc_suspend(ahc)))
+ return rc;
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ if (mesg.event == PM_EVENT_SUSPEND)
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return rc;
+}
+
+static int
+ahc_linux_pci_dev_resume(struct pci_dev *pdev)
+{
+ struct ahc_softc *ahc = pci_get_drvdata(pdev);
+ int rc;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ if ((rc = pci_enable_device(pdev))) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to enable device after resume (%d)\n", rc);
+ return rc;
+ }
+
+ pci_set_master(pdev);
+
+ ahc_pci_resume(ahc);
+
+ return (ahc_resume(ahc));
+}
+
static void
ahc_linux_pci_dev_remove(struct pci_dev *pdev)
{
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index 09c8172c9e5..ae35937b805 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -633,8 +633,6 @@ static void write_brdctl(struct ahc_softc *ahc, uint8_t value);
static uint8_t read_brdctl(struct ahc_softc *ahc);
static void ahc_pci_intr(struct ahc_softc *ahc);
static int ahc_pci_chip_init(struct ahc_softc *ahc);
-static int ahc_pci_suspend(struct ahc_softc *ahc);
-static int ahc_pci_resume(struct ahc_softc *ahc);
static int
ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor,
@@ -791,8 +789,6 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
ahc->bus_intr = ahc_pci_intr;
ahc->bus_chip_init = ahc_pci_chip_init;
- ahc->bus_suspend = ahc_pci_suspend;
- ahc->bus_resume = ahc_pci_resume;
/* Remeber how the card was setup in case there is no SEEPROM */
if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
@@ -2024,18 +2020,9 @@ ahc_pci_chip_init(struct ahc_softc *ahc)
return (ahc_chip_init(ahc));
}
-static int
-ahc_pci_suspend(struct ahc_softc *ahc)
-{
- return (ahc_suspend(ahc));
-}
-
-static int
+void
ahc_pci_resume(struct ahc_softc *ahc)
{
-
- pci_set_power_state(ahc->dev_softc, AHC_POWER_STATE_D0);
-
/*
* We assume that the OS has restored our register
* mappings, etc. Just update the config space registers
@@ -2063,7 +2050,6 @@ ahc_pci_resume(struct ahc_softc *ahc)
&sxfrctl1);
ahc_release_seeprom(&sd);
}
- return (ahc_resume(ahc));
}
static int
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l
index f06e7035cb3..c0457b8c3b7 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l
@@ -66,6 +66,7 @@ static char string_buf[MAX_STR_CONST];
static char *string_buf_ptr;
static int parren_count;
static char buf[255];
+int mmlineno;
%}
WORD [A-Za-z_][-A-Za-z_0-9]*
@@ -76,7 +77,7 @@ MCARG [^(), \t]+
%%
\n {
- ++yylineno;
+ ++mmlineno;
}
\r ;
<ARGLIST>{SPACE} ;
diff --git a/drivers/scsi/aic7xxx/cam.h b/drivers/scsi/aic7xxx/cam.h
index 26f17e3fc45..687aef6ef18 100644
--- a/drivers/scsi/aic7xxx/cam.h
+++ b/drivers/scsi/aic7xxx/cam.h
@@ -48,7 +48,7 @@ typedef enum {
CAM_REQ_ABORTED, /* CCB request aborted by the host */
CAM_UA_ABORT, /* Unable to abort CCB request */
CAM_REQ_CMP_ERR, /* CCB request completed with an error */
- CAM_BUSY, /* CAM subsytem is busy */
+ CAM_BUSY, /* CAM subsystem is busy */
CAM_REQ_INVALID, /* CCB request was invalid */
CAM_PATH_INVALID, /* Supplied Path ID is invalid */
CAM_SEL_TIMEOUT, /* Target Selection Timeout */
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 4998bb850c4..8f8db5f0aef 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -8416,10 +8416,9 @@ aic7xxx_alloc(struct scsi_host_template *sht, struct aic7xxx_host *temp)
*p = *temp;
p->host = host;
- p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
- if (p->scb_data != NULL)
+ p->scb_data = kzalloc(sizeof(scb_data_type), GFP_ATOMIC);
+ if (p->scb_data)
{
- memset(p->scb_data, 0, sizeof(scb_data_type));
scbq_init (&p->scb_data->free_scbs);
}
else
@@ -9196,10 +9195,9 @@ aic7xxx_detect(struct scsi_host_template *template)
printk(KERN_INFO " this driver, we are ignoring it.\n");
}
}
- else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host),
+ else if ( (temp_p = kzalloc(sizeof(struct aic7xxx_host),
GFP_ATOMIC)) != NULL )
{
- memset(temp_p, 0, sizeof(struct aic7xxx_host));
temp_p->chip = aic_pdevs[i].chip | AHC_PCI;
temp_p->flags = aic_pdevs[i].flags;
temp_p->features = aic_pdevs[i].features;
@@ -11144,6 +11142,7 @@ static struct scsi_host_template driver_template = {
.max_sectors = 2048,
.cmd_per_lun = 3,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
#include "scsi_module.c"
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h
index c6c3d18222f..491e5d8a98b 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.h
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.h
@@ -40,18 +40,6 @@
#define ASD_MAX_PHYS 8
#define ASD_PCBA_SN_SIZE 12
-/* Those are to be further named properly, the "RAZORx" part, and
- * subsequently included in include/linux/pci_ids.h.
- */
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR10 0x410
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR12 0x412
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1E 0x41E
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1F 0x41F
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR30 0x430
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR32 0x432
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3E 0x43E
-#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3F 0x43F
-
struct asd_ha_addrspace {
void __iomem *addr;
unsigned long start; /* pci resource start */
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 63bcde24644..b70d6e7f96e 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -583,7 +583,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL);
if (!asd_ha) {
asd_printk("out of memory\n");
- goto Err;
+ goto Err_put;
}
asd_ha->pcidev = dev;
asd_ha->sas_ha.dev = &asd_ha->pcidev->dev;
@@ -600,14 +600,12 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
shost->max_cmd_len = 16;
err = scsi_add_host(shost, &dev->dev);
- if (err) {
- scsi_host_put(shost);
+ if (err)
goto Err_free;
- }
err = asd_dev->setup(asd_ha);
if (err)
- goto Err_free;
+ goto Err_remove;
err = -ENODEV;
if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)
@@ -618,14 +616,14 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
;
else {
asd_printk("no suitable DMA mask for %s\n", pci_name(dev));
- goto Err_free;
+ goto Err_remove;
}
pci_set_drvdata(dev, asd_ha);
err = asd_map_ha(asd_ha);
if (err)
- goto Err_free;
+ goto Err_remove;
err = asd_create_ha_caches(asd_ha);
if (err)
@@ -692,9 +690,12 @@ Err_free_cache:
asd_destroy_ha_caches(asd_ha);
Err_unmap:
asd_unmap_ha(asd_ha);
+Err_remove:
+ scsi_remove_host(shost);
Err_free:
kfree(asd_ha);
- scsi_remove_host(shost);
+Err_put:
+ scsi_host_put(shost);
Err:
pci_disable_device(dev);
return err;
@@ -829,22 +830,15 @@ static struct sas_domain_function_template aic94xx_transport_functions = {
};
static const struct pci_device_id aic94xx_pci_table[] __devinitdata = {
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR10),
- 0, 0, 1},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR12),
- 0, 0, 1},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1E),
- 0, 0, 1},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1F),
- 0, 0, 1},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR30),
- 0, 0, 2},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32),
- 0, 0, 2},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3E),
- 0, 0, 2},
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3F),
- 0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x410),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x412),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x416),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41E),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41F),0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x430),0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x432),0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43E),0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43F),0, 0, 2},
{}
};
diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c
index 5b0932f6147..06509bff71f 100644
--- a/drivers/scsi/aic94xx/aic94xx_sds.c
+++ b/drivers/scsi/aic94xx/aic94xx_sds.c
@@ -377,7 +377,7 @@ out:
#define FLASH_RESET 0xF0
-#define FLASH_SIZE 0x200000
+#define ASD_FLASH_SIZE 0x200000
#define FLASH_DIR_COOKIE "*** ADAPTEC FLASH DIRECTORY *** "
#define FLASH_NEXT_ENTRY_OFFS 0x2000
#define FLASH_MAX_DIR_ENTRIES 32
@@ -609,7 +609,7 @@ static int asd_find_flash_dir(struct asd_ha_struct *asd_ha,
struct asd_flash_dir *flash_dir)
{
u32 v;
- for (v = 0; v < FLASH_SIZE; v += FLASH_NEXT_ENTRY_OFFS) {
+ for (v = 0; v < ASD_FLASH_SIZE; v += FLASH_NEXT_ENTRY_OFFS) {
asd_read_flash_seg(asd_ha, flash_dir, v,
sizeof(FLASH_DIR_COOKIE)-1);
if (memcmp(flash_dir->cookie, FLASH_DIR_COOKIE,
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index ab13824df85..ee0a98bffcd 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -94,7 +94,7 @@ static inline int asd_map_scatterlist(struct sas_task *task,
res = -ENOMEM;
goto err_unmap;
}
- for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) {
+ for_each_sg(task->scatter, sc, num_sg, i) {
struct sg_el *sg =
&((struct sg_el *)ascb->sg_arr->vaddr)[i];
sg->bus_addr = cpu_to_le64((u64)sg_dma_address(sc));
@@ -103,7 +103,7 @@ static inline int asd_map_scatterlist(struct sas_task *task,
sg->flags |= ASD_SG_EL_LIST_EOL;
}
- for (sc = task->scatter, i = 0; i < 2; i++, sc++) {
+ for_each_sg(task->scatter, sc, 2, i) {
sg_arr[i].bus_addr =
cpu_to_le64((u64)sg_dma_address(sc));
sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc));
@@ -115,7 +115,7 @@ static inline int asd_map_scatterlist(struct sas_task *task,
sg_arr[2].bus_addr=cpu_to_le64((u64)ascb->sg_arr->dma_handle);
} else {
int i;
- for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) {
+ for_each_sg(task->scatter, sc, num_sg, i) {
sg_arr[i].bus_addr =
cpu_to_le64((u64)sg_dma_address(sc));
sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc));
@@ -207,7 +207,7 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb,
"stat(0x%x) is not CHECK_CONDITION"
"\n",
SAS_ADDR(task->dev->sas_addr),
- ts->stat);
+ iu->status);
}
}
} else {
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index f0b8bf4534f..a67e29f83ae 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -9,7 +9,7 @@
** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved.
**
** Web site: www.areca.com.tw
-** E-mail: erich@areca.com.tw
+** E-mail: support@areca.com.tw
**
** 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
@@ -45,19 +45,26 @@
#include <linux/interrupt.h>
struct class_device_attribute;
-
-#define ARCMSR_MAX_OUTSTANDING_CMD 256
-#define ARCMSR_MAX_FREECCB_NUM 288
-#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.14"
+/*The limit of outstanding scsi command that firmware can handle*/
+#define ARCMSR_MAX_OUTSTANDING_CMD 256
+#define ARCMSR_MAX_FREECCB_NUM 320
+#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/08/30"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
-#define ARCMSR_MAX_XFER_SECTORS_B 4096
-#define ARCMSR_MAX_TARGETID 17
-#define ARCMSR_MAX_TARGETLUN 8
-#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD
-#define ARCMSR_MAX_QBUFFER 4096
-#define ARCMSR_MAX_SG_ENTRIES 38
-
+#define ARCMSR_MAX_XFER_SECTORS_B 4096
+#define ARCMSR_MAX_TARGETID 17
+#define ARCMSR_MAX_TARGETLUN 8
+#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD
+#define ARCMSR_MAX_QBUFFER 4096
+#define ARCMSR_MAX_SG_ENTRIES 38
+#define ARCMSR_MAX_HBB_POSTQUEUE 264
+/*
+**********************************************************************************
+**
+**********************************************************************************
+*/
+#define ARC_SUCCESS 0
+#define ARC_FAILURE 1
/*
*******************************************************************************
** split 64bits dma addressing
@@ -90,7 +97,7 @@ struct CMD_MESSAGE_FIELD
uint8_t messagedatabuffer[1032];
};
/* IOP message transfer */
-#define ARCMSR_MESSAGE_FAIL 0x0001
+#define ARCMSR_MESSAGE_FAIL 0x0001
/* DeviceType */
#define ARECA_SATA_RAID 0x90000000
/* FunctionCode */
@@ -134,14 +141,14 @@ struct CMD_MESSAGE_FIELD
#define IS_SG64_ADDR 0x01000000 /* bit24 */
struct SG32ENTRY
{
- uint32_t length;
- uint32_t address;
+ __le32 length;
+ __le32 address;
};
struct SG64ENTRY
{
- uint32_t length;
- uint32_t address;
- uint32_t addresshigh;
+ __le32 length;
+ __le32 address;
+ __le32 addresshigh;
};
struct SGENTRY_UNION
{
@@ -163,27 +170,27 @@ struct QBUFFER
};
/*
*******************************************************************************
-** FIRMWARE INFO
+** FIRMWARE INFO for Intel IOP R 80331 processor (Type A)
*******************************************************************************
*/
struct FIRMWARE_INFO
{
- uint32_t signature; /*0, 00-03*/
- uint32_t request_len; /*1, 04-07*/
- uint32_t numbers_queue; /*2, 08-11*/
+ uint32_t signature; /*0, 00-03*/
+ uint32_t request_len; /*1, 04-07*/
+ uint32_t numbers_queue; /*2, 08-11*/
uint32_t sdram_size; /*3, 12-15*/
- uint32_t ide_channels; /*4, 16-19*/
- char vendor[40]; /*5, 20-59*/
- char model[8]; /*15, 60-67*/
- char firmware_ver[16]; /*17, 68-83*/
- char device_map[16]; /*21, 84-99*/
+ uint32_t ide_channels; /*4, 16-19*/
+ char vendor[40]; /*5, 20-59*/
+ char model[8]; /*15, 60-67*/
+ char firmware_ver[16]; /*17, 68-83*/
+ char device_map[16]; /*21, 84-99*/
};
/* signature of set and get firmware config */
-#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060
-#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063
+#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060
+#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063
/* message code of inbound message register */
-#define ARCMSR_INBOUND_MESG0_NOP 0x00000000
-#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001
+#define ARCMSR_INBOUND_MESG0_NOP 0x00000000
+#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001
#define ARCMSR_INBOUND_MESG0_SET_CONFIG 0x00000002
#define ARCMSR_INBOUND_MESG0_ABORT_CMD 0x00000003
#define ARCMSR_INBOUND_MESG0_STOP_BGRB 0x00000004
@@ -203,6 +210,60 @@ struct FIRMWARE_INFO
#define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000
/* outbound firmware ok */
#define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000
+
+/*
+************************************************************************
+** SPEC. for Areca Type B adapter
+************************************************************************
+*/
+/* ARECA HBB COMMAND for its FIRMWARE */
+/* window of "instruction flags" from driver to iop */
+#define ARCMSR_DRV2IOP_DOORBELL 0x00020400
+#define ARCMSR_DRV2IOP_DOORBELL_MASK 0x00020404
+/* window of "instruction flags" from iop to driver */
+#define ARCMSR_IOP2DRV_DOORBELL 0x00020408
+#define ARCMSR_IOP2DRV_DOORBELL_MASK 0x0002040C
+/* ARECA FLAG LANGUAGE */
+/* ioctl transfer */
+#define ARCMSR_IOP2DRV_DATA_WRITE_OK 0x00000001
+/* ioctl transfer */
+#define ARCMSR_IOP2DRV_DATA_READ_OK 0x00000002
+#define ARCMSR_IOP2DRV_CDB_DONE 0x00000004
+#define ARCMSR_IOP2DRV_MESSAGE_CMD_DONE 0x00000008
+
+#define ARCMSR_DOORBELL_HANDLE_INT 0x0000000F
+#define ARCMSR_DOORBELL_INT_CLEAR_PATTERN 0xFF00FFF0
+#define ARCMSR_MESSAGE_INT_CLEAR_PATTERN 0xFF00FFF7
+/* (ARCMSR_INBOUND_MESG0_GET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_GET_CONFIG 0x00010008
+/* (ARCMSR_INBOUND_MESG0_SET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_SET_CONFIG 0x00020008
+/* (ARCMSR_INBOUND_MESG0_ABORT_CMD<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_ABORT_CMD 0x00030008
+/* (ARCMSR_INBOUND_MESG0_STOP_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_STOP_BGRB 0x00040008
+/* (ARCMSR_INBOUND_MESG0_FLUSH_CACHE<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_FLUSH_CACHE 0x00050008
+/* (ARCMSR_INBOUND_MESG0_START_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_START_BGRB 0x00060008
+#define ARCMSR_MESSAGE_START_DRIVER_MODE 0x000E0008
+#define ARCMSR_MESSAGE_SET_POST_WINDOW 0x000F0008
+/* ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK */
+#define ARCMSR_MESSAGE_FIRMWARE_OK 0x80000000
+/* ioctl transfer */
+#define ARCMSR_DRV2IOP_DATA_WRITE_OK 0x00000001
+/* ioctl transfer */
+#define ARCMSR_DRV2IOP_DATA_READ_OK 0x00000002
+#define ARCMSR_DRV2IOP_CDB_POSTED 0x00000004
+#define ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED 0x00000008
+
+/* data tunnel buffer between user space program and its firmware */
+/* user space data to iop 128bytes */
+#define ARCMSR_IOCTL_WBUFFER 0x0000fe00
+/* iop data to user space 128bytes */
+#define ARCMSR_IOCTL_RBUFFER 0x0000ff00
+/* iop message_rwbuffer for message command */
+#define ARCMSR_MSGCODE_RWBUFFER 0x0000fa00
/*
*******************************************************************************
** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
@@ -214,7 +275,6 @@ struct ARCMSR_CDB
uint8_t TargetID;
uint8_t LUN;
uint8_t Function;
-
uint8_t CdbLength;
uint8_t sgcount;
uint8_t Flags;
@@ -224,20 +284,18 @@ struct ARCMSR_CDB
#define ARCMSR_CDB_FLAG_SIMPLEQ 0x00
#define ARCMSR_CDB_FLAG_HEADQ 0x08
#define ARCMSR_CDB_FLAG_ORDEREDQ 0x10
- uint8_t Reserved1;
+ uint8_t Reserved1;
uint32_t Context;
uint32_t DataLength;
-
uint8_t Cdb[16];
-
uint8_t DeviceStatus;
-#define ARCMSR_DEV_CHECK_CONDITION 0x02
-#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0
-#define ARCMSR_DEV_ABORTED 0xF1
-#define ARCMSR_DEV_INIT_FAIL 0xF2
- uint8_t SenseData[15];
+#define ARCMSR_DEV_CHECK_CONDITION 0x02
+#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0
+#define ARCMSR_DEV_ABORTED 0xF1
+#define ARCMSR_DEV_INIT_FAIL 0xF2
+ uint8_t SenseData[15];
union
{
struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES];
@@ -246,10 +304,10 @@ struct ARCMSR_CDB
};
/*
*******************************************************************************
-** Messaging Unit (MU) of the Intel R 80331 I/O processor (80331)
+** Messaging Unit (MU) of the Intel R 80331 I/O processor(Type A) and Type B processor
*******************************************************************************
*/
-struct MessageUnit
+struct MessageUnit_A
{
uint32_t resrved0[4]; /*0000 000F*/
uint32_t inbound_msgaddr0; /*0010 0013*/
@@ -274,6 +332,22 @@ struct MessageUnit
uint32_t message_rbuffer[32]; /*0F00 0F7F 32*/
uint32_t reserved6[32]; /*0F80 0FFF 32*/
};
+
+struct MessageUnit_B
+{
+ uint32_t post_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
+ uint32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
+ uint32_t postq_index;
+ uint32_t doneq_index;
+ uint32_t __iomem *drv2iop_doorbell_reg;
+ uint32_t __iomem *drv2iop_doorbell_mask_reg;
+ uint32_t __iomem *iop2drv_doorbell_reg;
+ uint32_t __iomem *iop2drv_doorbell_mask_reg;
+ uint32_t __iomem *msgcode_rwbuffer_reg;
+ uint32_t __iomem *ioctl_wbuffer_reg;
+ uint32_t __iomem *ioctl_rbuffer_reg;
+};
+
/*
*******************************************************************************
** Adapter Control Block
@@ -281,37 +355,48 @@ struct MessageUnit
*/
struct AdapterControlBlock
{
+ uint32_t adapter_type; /* adapter A,B..... */
+ #define ACB_ADAPTER_TYPE_A 0x00000001 /* hba I IOP */
+ #define ACB_ADAPTER_TYPE_B 0x00000002 /* hbb M IOP */
+ #define ACB_ADAPTER_TYPE_C 0x00000004 /* hbc P IOP */
+ #define ACB_ADAPTER_TYPE_D 0x00000008 /* hbd A IOP */
struct pci_dev * pdev;
struct Scsi_Host * host;
unsigned long vir2phy_offset;
/* Offset is used in making arc cdb physical to virtual calculations */
uint32_t outbound_int_enable;
- struct MessageUnit __iomem * pmu;
+ union {
+ struct MessageUnit_A __iomem * pmuA;
+ struct MessageUnit_B * pmuB;
+ };
/* message unit ATU inbound base address0 */
uint32_t acb_flags;
-#define ACB_F_SCSISTOPADAPTER 0x0001
-#define ACB_F_MSG_STOP_BGRB 0x0002
+ #define ACB_F_SCSISTOPADAPTER 0x0001
+ #define ACB_F_MSG_STOP_BGRB 0x0002
/* stop RAID background rebuild */
-#define ACB_F_MSG_START_BGRB 0x0004
+ #define ACB_F_MSG_START_BGRB 0x0004
/* stop RAID background rebuild */
-#define ACB_F_IOPDATA_OVERFLOW 0x0008
+ #define ACB_F_IOPDATA_OVERFLOW 0x0008
/* iop message data rqbuffer overflow */
-#define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010
+ #define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010
/* message clear wqbuffer */
-#define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020
+ #define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020
/* message clear rqbuffer */
-#define ACB_F_MESSAGE_WQBUFFER_READED 0x0040
-#define ACB_F_BUS_RESET 0x0080
-#define ACB_F_IOP_INITED 0x0100
+ #define ACB_F_MESSAGE_WQBUFFER_READED 0x0040
+ #define ACB_F_BUS_RESET 0x0080
+ #define ACB_F_IOP_INITED 0x0100
/* iop init */
struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM];
/* used for memory free */
struct list_head ccb_free_list;
/* head of free ccb list */
+
atomic_t ccboutstandingcount;
+ /*The present outstanding command number that in the IOP that
+ waiting for being handled by FW*/
void * dma_coherent;
/* dma_coherent used for memory free */
@@ -353,7 +438,7 @@ struct CommandControlBlock
{
struct ARCMSR_CDB arcmsr_cdb;
/*
- ** 0-503 (size of CDB=504):
+ ** 0-503 (size of CDB = 504):
** arcmsr messenger scsi command descriptor size 504 bytes
*/
uint32_t cdb_shifted_phyaddr;
@@ -466,7 +551,9 @@ struct SENSE_DATA
#define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE 0x01
#define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE 0x1F
-extern void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb);
+extern void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *);
+extern void arcmsr_iop_message_read(struct AdapterControlBlock *);
+extern struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *);
extern struct class_device_attribute *arcmsr_host_attrs[];
-extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb);
+extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *);
void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb);
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
index 06c0dce3b83..7d7b0a55427 100644
--- a/drivers/scsi/arcmsr/arcmsr_attr.c
+++ b/drivers/scsi/arcmsr/arcmsr_attr.c
@@ -8,7 +8,7 @@
** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
**
** Web site: www.areca.com.tw
-** E-mail: erich@areca.com.tw
+** E-mail: support@areca.com.tw
**
** 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
@@ -49,6 +49,7 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/delay.h>
+#include <linux/pci.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
@@ -58,15 +59,14 @@
struct class_device_attribute *arcmsr_host_attrs[];
-static ssize_t
-arcmsr_sysfs_iop_message_read(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj,
+ struct bin_attribute *bin,
+ char *buf, loff_t off,
+ size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *host = class_to_shost(cdev);
struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
- struct MessageUnit __iomem *reg = acb->pmu;
uint8_t *pQbuffer,*ptmpQbuffer;
int32_t allxfer_len = 0;
@@ -85,12 +85,13 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj,
allxfer_len++;
}
if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
- struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
- &reg->message_rbuffer;
- uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
+ struct QBUFFER __iomem *prbuffer;
+ uint8_t __iomem *iop_data;
int32_t iop_len;
acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ prbuffer = arcmsr_get_iop_rqbuffer(acb);
+ iop_data = prbuffer->data;
iop_len = readl(&prbuffer->data_len);
while (iop_len > 0) {
acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
@@ -99,16 +100,15 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj,
iop_data++;
iop_len--;
}
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
- &reg->inbound_doorbell);
+ arcmsr_iop_message_read(acb);
}
return (allxfer_len);
}
-static ssize_t
-arcmsr_sysfs_iop_message_write(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj,
+ struct bin_attribute *bin,
+ char *buf, loff_t off,
+ size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *host = class_to_shost(cdev);
@@ -126,7 +126,7 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj,
wqbuf_lastindex = acb->wqbuf_lastindex;
wqbuf_firstindex = acb->wqbuf_firstindex;
if (wqbuf_lastindex != wqbuf_firstindex) {
- arcmsr_post_Qbuffer(acb);
+ arcmsr_post_ioctldata2iop(acb);
return 0; /*need retry*/
} else {
my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
@@ -144,7 +144,7 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj,
if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
acb->acb_flags &=
~ACB_F_MESSAGE_WQBUFFER_CLEARED;
- arcmsr_post_Qbuffer(acb);
+ arcmsr_post_ioctldata2iop(acb);
}
return count;
} else {
@@ -153,15 +153,14 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj,
}
}
-static ssize_t
-arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
+ struct bin_attribute *bin,
+ char *buf, loff_t off,
+ size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *host = class_to_shost(cdev);
struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
- struct MessageUnit __iomem *reg = acb->pmu;
uint8_t *pQbuffer;
if (!capable(CAP_SYS_ADMIN))
@@ -169,8 +168,7 @@ arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
- , &reg->inbound_doorbell);
+ arcmsr_iop_message_read(acb);
}
acb->acb_flags |=
(ACB_F_MESSAGE_WQBUFFER_CLEARED
@@ -191,6 +189,7 @@ static struct bin_attribute arcmsr_sysfs_message_read_attr = {
.attr = {
.name = "mu_read",
.mode = S_IRUSR ,
+ .owner = THIS_MODULE,
},
.size = 1032,
.read = arcmsr_sysfs_iop_message_read,
@@ -200,6 +199,7 @@ static struct bin_attribute arcmsr_sysfs_message_write_attr = {
.attr = {
.name = "mu_write",
.mode = S_IWUSR,
+ .owner = THIS_MODULE,
},
.size = 1032,
.write = arcmsr_sysfs_iop_message_write,
@@ -209,6 +209,7 @@ static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
.attr = {
.name = "mu_clear",
.mode = S_IWUSR,
+ .owner = THIS_MODULE,
},
.size = 1,
.write = arcmsr_sysfs_iop_message_clear,
@@ -219,31 +220,26 @@ int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb)
struct Scsi_Host *host = acb->host;
int error;
- error = sysfs_create_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_read_attr);
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
if (error) {
printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n");
goto error_bin_file_message_read;
}
- error = sysfs_create_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_write_attr);
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
if (error) {
printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n");
goto error_bin_file_message_write;
}
- error = sysfs_create_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_clear_attr);
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr);
if (error) {
printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n");
goto error_bin_file_message_clear;
}
return 0;
error_bin_file_message_clear:
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_write_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
error_bin_file_message_write:
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_read_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
error_bin_file_message_read:
return error;
}
@@ -252,12 +248,9 @@ void
arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb) {
struct Scsi_Host *host = acb->host;
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_clear_attr);
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_write_attr);
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_read_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
}
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 0ddfc21e9f7..d466a2dac1d 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -9,7 +9,7 @@
** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
**
** Web site: www.areca.com.tw
-** E-mail: erich@areca.com.tw
+** E-mail: support@areca.com.tw
**
** 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
@@ -71,33 +71,34 @@
#include <scsi/scsicam.h>
#include "arcmsr.h"
-MODULE_AUTHOR("Erich Chen <erich@areca.com.tw>");
+MODULE_AUTHOR("Erich Chen <support@areca.com.tw>");
MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID HOST Adapter");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(ARCMSR_DRIVER_VERSION);
-static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd);
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
+ struct scsi_cmnd *cmd);
+static int arcmsr_iop_confirm(struct AdapterControlBlock *acb);
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 *));
+ 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_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
static void arcmsr_remove(struct pci_dev *pdev);
static void arcmsr_shutdown(struct pci_dev *pdev);
static void arcmsr_iop_init(struct AdapterControlBlock *acb);
static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb);
+static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb);
static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);
-static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb);
-static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb);
+static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb);
+static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
-static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
- pci_channel_state_t state);
-static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev);
-static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
+static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
+ int queue_depth)
{
if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
queue_depth = ARCMSR_MAX_CMD_PERLUN;
@@ -121,19 +122,28 @@ static struct scsi_host_template arcmsr_scsi_host_template = {
.max_sectors = ARCMSR_MAX_XFER_SECTORS,
.cmd_per_lun = ARCMSR_MAX_CMD_PERLUN,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.shost_attrs = arcmsr_host_attrs,
};
+#ifdef CONFIG_SCSI_ARCMSR_AER
+static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev);
+static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state);
+
static struct pci_error_handlers arcmsr_pci_error_handlers = {
.error_detected = arcmsr_pci_error_detected,
.slot_reset = arcmsr_pci_slot_reset,
};
-
+#endif
static struct pci_device_id arcmsr_device_id_table[] = {
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)},
@@ -153,20 +163,20 @@ static struct pci_driver arcmsr_pci_driver = {
.probe = arcmsr_probe,
.remove = arcmsr_remove,
.shutdown = arcmsr_shutdown,
+ #ifdef CONFIG_SCSI_ARCMSR_AER
.err_handler = &arcmsr_pci_error_handlers,
+ #endif
};
static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
{
irqreturn_t handle_state;
- struct AdapterControlBlock *acb;
- unsigned long flags;
+ struct AdapterControlBlock *acb = dev_id;
- acb = (struct AdapterControlBlock *)dev_id;
-
- spin_lock_irqsave(acb->host->host_lock, flags);
+ spin_lock(acb->host->host_lock);
handle_state = arcmsr_interrupt(acb);
- spin_unlock_irqrestore(acb->host->host_lock, flags);
+ spin_unlock(acb->host->host_lock);
+
return handle_state;
}
@@ -198,69 +208,173 @@ static int arcmsr_bios_param(struct scsi_device *sdev,
return 0;
}
-static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
+static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb)
{
struct pci_dev *pdev = acb->pdev;
- struct MessageUnit __iomem *reg = acb->pmu;
- u32 ccb_phyaddr_hi32;
- void *dma_coherent;
- dma_addr_t dma_coherent_handle, dma_addr;
- struct CommandControlBlock *ccb_tmp;
- int i, j;
+ u16 dev_id;
+ pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
+ switch (dev_id) {
+ case 0x1201 : {
+ acb->adapter_type = ACB_ADAPTER_TYPE_B;
+ }
+ break;
- dma_coherent = dma_alloc_coherent(&pdev->dev,
+ default : acb->adapter_type = ACB_ADAPTER_TYPE_A;
+ }
+}
+
+static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
+{
+
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ struct pci_dev *pdev = acb->pdev;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle, dma_addr;
+ struct CommandControlBlock *ccb_tmp;
+ uint32_t intmask_org;
+ int i, j;
+
+ acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+ if (!acb->pmuA) {
+ printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n",
+ acb->host->host_no);
+ return -ENOMEM;
+ }
+
+ dma_coherent = dma_alloc_coherent(&pdev->dev,
ARCMSR_MAX_FREECCB_NUM *
sizeof (struct CommandControlBlock) + 0x20,
&dma_coherent_handle, GFP_KERNEL);
- if (!dma_coherent)
- return -ENOMEM;
- acb->dma_coherent = dma_coherent;
- acb->dma_coherent_handle = dma_coherent_handle;
+ if (!dma_coherent) {
+ iounmap(acb->pmuA);
+ return -ENOMEM;
+ }
- if (((unsigned long)dma_coherent & 0x1F)) {
- dma_coherent = dma_coherent +
- (0x20 - ((unsigned long)dma_coherent & 0x1F));
- dma_coherent_handle = dma_coherent_handle +
- (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
- }
+ acb->dma_coherent = dma_coherent;
+ acb->dma_coherent_handle = dma_coherent_handle;
- dma_addr = dma_coherent_handle;
- ccb_tmp = (struct CommandControlBlock *)dma_coherent;
- for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
- ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
- ccb_tmp->acb = acb;
- acb->pccb_pool[i] = ccb_tmp;
- list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
- dma_addr = dma_addr + sizeof (struct CommandControlBlock);
- ccb_tmp++;
- }
+ if (((unsigned long)dma_coherent & 0x1F)) {
+ dma_coherent = dma_coherent +
+ (0x20 - ((unsigned long)dma_coherent & 0x1F));
+ dma_coherent_handle = dma_coherent_handle +
+ (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
+ }
- acb->vir2phy_offset = (unsigned long)ccb_tmp -
- (unsigned long)dma_addr;
- for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
- for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
- acb->devstate[i][j] = ARECA_RAID_GOOD;
+ dma_addr = dma_coherent_handle;
+ ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
+ ccb_tmp->acb = acb;
+ acb->pccb_pool[i] = ccb_tmp;
+ list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
+ dma_addr = dma_addr + sizeof(struct CommandControlBlock);
+ ccb_tmp++;
+ }
- /*
- ** here we need to tell iop 331 our ccb_tmp.HighPart
- ** if ccb_tmp.HighPart is not zero
- */
- ccb_phyaddr_hi32 = (uint32_t) ((dma_coherent_handle >> 16) >> 16);
- if (ccb_phyaddr_hi32 != 0) {
- writel(ARCMSR_SIGNATURE_SET_CONFIG, &reg->message_rwbuffer[0]);
- writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);
- writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb))
- printk(KERN_NOTICE "arcmsr%d: "
- "'set ccb high part physical address' timeout\n",
- acb->host->host_no);
- }
+ acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;
+ for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+ for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+ acb->devstate[i][j] = ARECA_RAID_GONE;
+
+ /*
+ ** here we need to tell iop 331 our ccb_tmp.HighPart
+ ** if ccb_tmp.HighPart is not zero
+ */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+
+ struct pci_dev *pdev = acb->pdev;
+ struct MessageUnit_B *reg;
+ void __iomem *mem_base0, *mem_base1;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle, dma_addr;
+ uint32_t intmask_org;
+ struct CommandControlBlock *ccb_tmp;
+ int i, j;
+
+ dma_coherent = dma_alloc_coherent(&pdev->dev,
+ ((ARCMSR_MAX_FREECCB_NUM *
+ sizeof(struct CommandControlBlock) + 0x20) +
+ sizeof(struct MessageUnit_B)),
+ &dma_coherent_handle, GFP_KERNEL);
+ if (!dma_coherent)
+ return -ENOMEM;
+
+ acb->dma_coherent = dma_coherent;
+ acb->dma_coherent_handle = dma_coherent_handle;
+
+ if (((unsigned long)dma_coherent & 0x1F)) {
+ dma_coherent = dma_coherent +
+ (0x20 - ((unsigned long)dma_coherent & 0x1F));
+ dma_coherent_handle = dma_coherent_handle +
+ (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
+ }
+
+ reg = (struct MessageUnit_B *)(dma_coherent +
+ ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));
+
+ dma_addr = dma_coherent_handle;
+ ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
+ ccb_tmp->acb = acb;
+ acb->pccb_pool[i] = ccb_tmp;
+ list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
+ dma_addr = dma_addr + sizeof(struct CommandControlBlock);
+ ccb_tmp++;
+ }
+
+ reg = (struct MessageUnit_B *)(dma_coherent +
+ ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));
+ acb->pmuB = reg;
+ mem_base0 = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (!mem_base0)
+ goto out;
+
+ mem_base1 = ioremap(pci_resource_start(pdev, 2),
+ pci_resource_len(pdev, 2));
+ if (!mem_base1) {
+ iounmap(mem_base0);
+ goto out;
+ }
+
+ reg->drv2iop_doorbell_reg = mem_base0 + ARCMSR_DRV2IOP_DOORBELL;
+ reg->drv2iop_doorbell_mask_reg = mem_base0 +
+ ARCMSR_DRV2IOP_DOORBELL_MASK;
+ reg->iop2drv_doorbell_reg = mem_base0 + ARCMSR_IOP2DRV_DOORBELL;
+ reg->iop2drv_doorbell_mask_reg = mem_base0 +
+ ARCMSR_IOP2DRV_DOORBELL_MASK;
+ reg->ioctl_wbuffer_reg = mem_base1 + ARCMSR_IOCTL_WBUFFER;
+ reg->ioctl_rbuffer_reg = mem_base1 + ARCMSR_IOCTL_RBUFFER;
+ reg->msgcode_rwbuffer_reg = mem_base1 + ARCMSR_MSGCODE_RWBUFFER;
+
+ acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;
+ for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+ for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+ acb->devstate[i][j] = ARECA_RAID_GOOD;
- writel(readl(&reg->outbound_intmask) |
- ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
- &reg->outbound_intmask);
+ /*
+ ** here we need to tell iop 331 our ccb_tmp.HighPart
+ ** if ccb_tmp.HighPart is not zero
+ */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ }
+ break;
+ }
return 0;
+
+out:
+ dma_free_coherent(&acb->pdev->dev,
+ ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20,
+ acb->dma_coherent, acb->dma_coherent_handle);
+ return -ENOMEM;
}
static int arcmsr_probe(struct pci_dev *pdev,
@@ -310,16 +424,11 @@ static int arcmsr_probe(struct pci_dev *pdev,
host->unique_id = (bus << 8) | dev_fun;
host->irq = pdev->irq;
error = pci_request_regions(pdev, "arcmsr");
- if (error)
+ if (error) {
goto out_host_put;
-
- acb->pmu = ioremap(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- if (!acb->pmu) {
- printk(KERN_NOTICE "arcmsr%d: memory"
- " mapping region fail \n", acb->host->host_no);
- goto out_release_regions;
}
+ arcmsr_define_adapter_type(acb);
+
acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
ACB_F_MESSAGE_RQBUFFER_CLEARED |
ACB_F_MESSAGE_WQBUFFER_READED);
@@ -328,10 +437,10 @@ static int arcmsr_probe(struct pci_dev *pdev,
error = arcmsr_alloc_ccb_pool(acb);
if (error)
- goto out_iounmap;
+ goto out_release_regions;
error = request_irq(pdev->irq, arcmsr_do_interrupt,
- IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb);
+ IRQF_SHARED, "arcmsr", acb);
if (error)
goto out_free_ccb_pool;
@@ -349,15 +458,15 @@ static int arcmsr_probe(struct pci_dev *pdev,
goto out_free_sysfs;
scsi_scan_host(host);
+ #ifdef CONFIG_SCSI_ARCMSR_AER
pci_enable_pcie_error_reporting(pdev);
+ #endif
return 0;
out_free_sysfs:
out_free_irq:
free_irq(pdev->irq, acb);
out_free_ccb_pool:
arcmsr_free_ccb_pool(acb);
- out_iounmap:
- iounmap(acb->pmu);
out_release_regions:
pci_release_regions(pdev);
out_host_put:
@@ -368,17 +477,84 @@ static int arcmsr_probe(struct pci_dev *pdev,
return error;
}
-static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
+static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ uint32_t Index;
+ uint8_t Retries = 0x00;
+
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(&reg->outbound_intstatus) &
+ ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
+ writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
+ &reg->outbound_intstatus);
+ return 0x00;
+ }
+ msleep(10);
+ }/*max 1 seconds*/
+
+ } while (Retries++ < 20);/*max 20 sec*/
+ return 0xff;
+}
+
+static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = acb->pmuB;
+ uint32_t Index;
+ uint8_t Retries = 0x00;
+
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(reg->iop2drv_doorbell_reg)
+ & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
+ , reg->iop2drv_doorbell_reg);
+ return 0x00;
+ }
+ msleep(10);
+ }/*max 1 seconds*/
+
+ } while (Retries++ < 20);/*max 20 sec*/
+ return 0xff;
+}
+
+static void arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb))
+ if (arcmsr_hba_wait_msgint_ready(acb))
printk(KERN_NOTICE
"arcmsr%d: wait 'abort all outstanding command' timeout \n"
, acb->host->host_no);
}
+static void arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = acb->pmuB;
+
+ writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg);
+ if (arcmsr_hbb_wait_msgint_ready(acb))
+ printk(KERN_NOTICE
+ "arcmsr%d: wait 'abort all outstanding command' timeout \n"
+ , acb->host->host_no);
+}
+
+static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ arcmsr_abort_hba_allcmd(acb);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ arcmsr_abort_hbb_allcmd(acb);
+ }
+ }
+}
+
static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
{
struct scsi_cmnd *pcmd = ccb->pcmd;
@@ -400,28 +576,238 @@ static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag)
pcmd->scsi_done(pcmd);
}
+static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ int retry_count = 30;
+
+ writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
+ do {
+ if (!arcmsr_hba_wait_msgint_ready(acb))
+ break;
+ else {
+ retry_count--;
+ printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+ timeout, retry count down = %d \n", acb->host->host_no, retry_count);
+ }
+ } while (retry_count != 0);
+}
+
+static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = acb->pmuB;
+ int retry_count = 30;
+
+ writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell_reg);
+ do {
+ if (!arcmsr_hbb_wait_msgint_ready(acb))
+ break;
+ else {
+ retry_count--;
+ printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+ timeout,retry count down = %d \n", acb->host->host_no, retry_count);
+ }
+ } while (retry_count != 0);
+}
+
+static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ arcmsr_flush_hba_cache(acb);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ arcmsr_flush_hbb_cache(acb);
+ }
+ }
+}
+
+static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
+{
+
+ struct scsi_cmnd *pcmd = ccb->pcmd;
+ struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
+
+ pcmd->result = DID_OK << 16;
+ if (sensebuffer) {
+ int sense_data_length =
+ sizeof(struct SENSE_DATA) < sizeof(pcmd->sense_buffer)
+ ? sizeof(struct SENSE_DATA) : sizeof(pcmd->sense_buffer);
+ memset(sensebuffer, 0, sizeof(pcmd->sense_buffer));
+ memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
+ sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
+ sensebuffer->Valid = 1;
+ }
+}
+
+static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
+{
+ u32 orig_mask = 0;
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A : {
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ orig_mask = readl(&reg->outbound_intmask)|\
+ ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE;
+ writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \
+ &reg->outbound_intmask);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B : {
+ struct MessageUnit_B *reg = acb->pmuB;
+ orig_mask = readl(reg->iop2drv_doorbell_mask_reg) & \
+ (~ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
+ writel(0, reg->iop2drv_doorbell_mask_reg);
+ }
+ break;
+ }
+ return orig_mask;
+}
+
+static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \
+ struct CommandControlBlock *ccb, uint32_t flag_ccb)
+{
+
+ uint8_t id, lun;
+ id = ccb->pcmd->device->id;
+ lun = ccb->pcmd->device->lun;
+ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (acb->devstate[id][lun] == ARECA_RAID_GONE)
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ ccb->pcmd->result = DID_OK << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ } else {
+ switch (ccb->arcmsr_cdb.DeviceStatus) {
+ case ARCMSR_DEV_SELECT_TIMEOUT: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_NO_CONNECT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_ABORTED:
+
+ case ARCMSR_DEV_INIT_FAIL: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_CHECK_CONDITION: {
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ arcmsr_report_sense_info(ccb);
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ default:
+ printk(KERN_NOTICE
+ "arcmsr%d: scsi id = %d lun = %d"
+ " isr get command error done, "
+ "but got unknown DeviceStatus = 0x%x \n"
+ , acb->host->host_no
+ , id
+ , lun
+ , ccb->arcmsr_cdb.DeviceStatus);
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_NO_CONNECT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ break;
+ }
+ }
+}
+
+static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t flag_ccb)
+
+{
+ struct CommandControlBlock *ccb;
+
+ ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5));
+ if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
+ if (ccb->startdone == ARCMSR_CCB_ABORTED) {
+ struct scsi_cmnd *abortcmd = ccb->pcmd;
+ if (abortcmd) {
+ abortcmd->result |= DID_ABORT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \
+ isr got aborted command \n", acb->host->host_no, ccb);
+ }
+ }
+ printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \
+ done acb = '0x%p'"
+ "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x"
+ " ccboutstandingcount = %d \n"
+ , acb->host->host_no
+ , acb
+ , ccb
+ , ccb->acb
+ , ccb->startdone
+ , atomic_read(&acb->ccboutstandingcount));
+ }
+ arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+}
+
+static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
+{
+ int i = 0;
+ uint32_t flag_ccb;
+
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ uint32_t outbound_intstatus;
+ outbound_intstatus = readl(&reg->outbound_intstatus) &
+ acb->outbound_int_enable;
+ /*clear and abort all outbound posted Q*/
+ writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
+ while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF)
+ && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
+ arcmsr_drain_donequeue(acb, flag_ccb);
+ }
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = acb->pmuB;
+ /*clear all outbound posted Q*/
+ for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
+ if ((flag_ccb = readl(&reg->done_qbuffer[i])) != 0) {
+ writel(0, &reg->done_qbuffer[i]);
+ arcmsr_drain_donequeue(acb, flag_ccb);
+ }
+ writel(0, &reg->post_qbuffer[i]);
+ }
+ reg->doneq_index = 0;
+ reg->postq_index = 0;
+ }
+ break;
+ }
+}
static void arcmsr_remove(struct pci_dev *pdev)
{
struct Scsi_Host *host = pci_get_drvdata(pdev);
struct AdapterControlBlock *acb =
(struct AdapterControlBlock *) host->hostdata;
- struct MessageUnit __iomem *reg = acb->pmu;
int poll_count = 0;
arcmsr_free_sysfs_attr(acb);
scsi_remove_host(host);
arcmsr_stop_adapter_bgrb(acb);
arcmsr_flush_adapter_cache(acb);
- writel(readl(&reg->outbound_intmask) |
- ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
- &reg->outbound_intmask);
+ arcmsr_disable_outbound_ints(acb);
acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
acb->acb_flags &= ~ACB_F_IOP_INITED;
- for (poll_count = 0; poll_count < 256; poll_count++) {
+ for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++) {
if (!atomic_read(&acb->ccboutstandingcount))
break;
- arcmsr_interrupt(acb);
+ arcmsr_interrupt(acb);/* FIXME: need spinlock */
msleep(25);
}
@@ -429,8 +815,7 @@ static void arcmsr_remove(struct pci_dev *pdev)
int i;
arcmsr_abort_allcmd(acb);
- for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++)
- readl(&reg->outbound_queueport);
+ arcmsr_done4abort_postqueue(acb);
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
struct CommandControlBlock *ccb = acb->pccb_pool[i];
if (ccb->startdone == ARCMSR_CCB_START) {
@@ -442,7 +827,6 @@ static void arcmsr_remove(struct pci_dev *pdev)
}
free_irq(pdev->irq, acb);
- iounmap(acb->pmu);
arcmsr_free_ccb_pool(acb);
pci_release_regions(pdev);
@@ -477,86 +861,43 @@ static void arcmsr_module_exit(void)
module_init(arcmsr_module_init);
module_exit(arcmsr_module_exit);
-static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
+static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \
+ u32 intmask_org)
{
- struct MessageUnit __iomem *reg = acb->pmu;
- u32 orig_mask = readl(&reg->outbound_intmask);
-
- writel(orig_mask | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
- &reg->outbound_intmask);
- return orig_mask;
-}
-
-static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
- u32 orig_mask)
-{
- struct MessageUnit __iomem *reg = acb->pmu;
u32 mask;
- mask = orig_mask & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
- ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
- writel(mask, &reg->outbound_intmask);
-}
-
-static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
-{
- struct MessageUnit __iomem *reg = acb->pmu;
+ switch (acb->adapter_type) {
- writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb))
- printk(KERN_NOTICE
- "arcmsr%d: wait 'flush adapter cache' timeout \n"
- , acb->host->host_no);
-}
-
-static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
-{
- struct scsi_cmnd *pcmd = ccb->pcmd;
- struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
+ case ACB_ADAPTER_TYPE_A : {
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
+ ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
+ writel(mask, &reg->outbound_intmask);
+ acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
+ }
+ break;
- pcmd->result = DID_OK << 16;
- if (sensebuffer) {
- int sense_data_length =
- sizeof (struct SENSE_DATA) < sizeof (pcmd->sense_buffer)
- ? sizeof (struct SENSE_DATA) : sizeof (pcmd->sense_buffer);
- memset(sensebuffer, 0, sizeof (pcmd->sense_buffer));
- memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
- sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
- sensebuffer->Valid = 1;
+ case ACB_ADAPTER_TYPE_B : {
+ struct MessageUnit_B *reg = acb->pmuB;
+ mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK | \
+ ARCMSR_IOP2DRV_DATA_READ_OK | ARCMSR_IOP2DRV_CDB_DONE);
+ writel(mask, reg->iop2drv_doorbell_mask_reg);
+ acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
+ }
}
}
-static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb)
-{
- struct MessageUnit __iomem *reg = acb->pmu;
- uint32_t Index;
- uint8_t Retries = 0x00;
-
- do {
- for (Index = 0; Index < 100; Index++) {
- if (readl(&reg->outbound_intstatus)
- & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
- writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT
- , &reg->outbound_intstatus);
- return 0x00;
- }
- msleep_interruptible(10);
- }/*max 1 seconds*/
- } while (Retries++ < 20);/*max 20 sec*/
- return 0xff;
-}
-
static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd)
{
struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
int8_t *psge = (int8_t *)&arcmsr_cdb->u;
- uint32_t address_lo, address_hi;
+ __le32 address_lo, address_hi;
int arccdbsize = 0x30;
int nseg;
ccb->pcmd = pcmd;
- memset(arcmsr_cdb, 0, sizeof (struct ARCMSR_CDB));
+ memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB));
arcmsr_cdb->Bus = 0;
arcmsr_cdb->TargetID = pcmd->device->id;
arcmsr_cdb->LUN = pcmd->device->lun;
@@ -569,7 +910,8 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
BUG_ON(nseg < 0);
if (nseg) {
- int length, i, cdb_sgcount = 0;
+ __le32 length;
+ int i, cdb_sgcount = 0;
struct scatterlist *sg;
/* map stor port SG list to our iop SG List. */
@@ -590,7 +932,7 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
pdma_sg->addresshigh = address_hi;
pdma_sg->address = address_lo;
- pdma_sg->length = length|IS_SG64_ADDR;
+ pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR);
psge += sizeof (struct SG64ENTRY);
arccdbsize += sizeof (struct SG64ENTRY);
}
@@ -609,207 +951,360 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr;
struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
-
atomic_inc(&acb->ccboutstandingcount);
ccb->startdone = ARCMSR_CCB_START;
- if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
- writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+
+ if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
+ writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
&reg->inbound_queueport);
- else
- writel(cdb_shifted_phyaddr, &reg->inbound_queueport);
-}
+ else {
+ writel(cdb_shifted_phyaddr, &reg->inbound_queueport);
+ }
+ }
+ break;
-void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb)
-{
- struct MessageUnit __iomem *reg = acb->pmu;
- struct QBUFFER __iomem *pwbuffer = (struct QBUFFER __iomem *) &reg->message_wbuffer;
- uint8_t __iomem *iop_data = (uint8_t __iomem *) pwbuffer->data;
- int32_t allxfer_len = 0;
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = acb->pmuB;
+ uint32_t ending_index, index = reg->postq_index;
- if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
- acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
- while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
- && (allxfer_len < 124)) {
- writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data);
- acb->wqbuf_firstindex++;
- acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
- iop_data++;
- allxfer_len++;
+ ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE);
+ writel(0, &reg->post_qbuffer[ending_index]);
+ if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
+ writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\
+ &reg->post_qbuffer[index]);
+ }
+ else {
+ writel(cdb_shifted_phyaddr, &reg->post_qbuffer[index]);
}
- writel(allxfer_len, &pwbuffer->data_len);
- writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK
- , &reg->inbound_doorbell);
+ index++;
+ index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */
+ reg->postq_index = index;
+ writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell_reg);
+ }
+ break;
}
}
-static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
+static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
-
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb))
+
+ if (arcmsr_hba_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
, acb->host->host_no);
+ }
+}
+
+static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = acb->pmuB;
+ acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell_reg);
+
+ if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE
+ "arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
+ , acb->host->host_no);
+ }
+}
+
+static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ arcmsr_stop_hba_bgrb(acb);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ arcmsr_stop_hbb_bgrb(acb);
+ }
+ break;
+ }
}
static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ iounmap(acb->pmuA);
+ break;
+ }
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = acb->pmuB;
+ iounmap(reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL);
+ iounmap(reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER);
+ }
+ }
dma_free_coherent(&acb->pdev->dev,
ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20,
acb->dma_coherent,
acb->dma_coherent_handle);
}
-static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
+void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
- struct CommandControlBlock *ccb;
- uint32_t flag_ccb, outbound_intstatus, outbound_doorbell;
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+ }
+ break;
- outbound_intstatus = readl(&reg->outbound_intstatus)
- & acb->outbound_int_enable;
- writel(outbound_intstatus, &reg->outbound_intstatus);
- if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) {
- outbound_doorbell = readl(&reg->outbound_doorbell);
- writel(outbound_doorbell, &reg->outbound_doorbell);
- if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
- struct QBUFFER __iomem * prbuffer =
- (struct QBUFFER __iomem *) &reg->message_rbuffer;
- uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
- int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
-
- rqbuf_lastindex = acb->rqbuf_lastindex;
- rqbuf_firstindex = acb->rqbuf_firstindex;
- iop_len = readl(&prbuffer->data_len);
- my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1)
- &(ARCMSR_MAX_QBUFFER - 1);
- if (my_empty_len >= iop_len) {
- while (iop_len > 0) {
- acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
- acb->rqbuf_lastindex++;
- acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
- iop_data++;
- iop_len--;
- }
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
- &reg->inbound_doorbell);
- } else
- acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
- }
- if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
- acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
- if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
- struct QBUFFER __iomem * pwbuffer =
- (struct QBUFFER __iomem *) &reg->message_wbuffer;
- uint8_t __iomem * iop_data = (uint8_t __iomem *) pwbuffer->data;
- int32_t allxfer_len = 0;
-
- acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
- while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
- && (allxfer_len < 124)) {
- writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data);
- acb->wqbuf_firstindex++;
- acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
- iop_data++;
- allxfer_len++;
- }
- writel(allxfer_len, &pwbuffer->data_len);
- writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK,
- &reg->inbound_doorbell);
- }
- if (acb->wqbuf_firstindex == acb->wqbuf_lastindex)
- acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = acb->pmuB;
+ writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg);
}
+ break;
}
- if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
- int id, lun;
+}
+
+static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
/*
- ****************************************************************
- ** areca cdb command done
- ****************************************************************
+ ** push inbound doorbell tell iop, driver data write ok
+ ** and wait reply on next hwinterrupt for next Qbuffer post
*/
- while (1) {
- if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF)
- break;/*chip FIFO no ccb for completion already*/
- /* check if command done with no error*/
- ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
- (flag_ccb << 5));
- if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
- if (ccb->startdone == ARCMSR_CCB_ABORTED) {
- struct scsi_cmnd *abortcmd = ccb->pcmd;
- if (abortcmd) {
- abortcmd->result |= DID_ABORT >> 16;
- arcmsr_ccb_complete(ccb, 1);
- printk(KERN_NOTICE
- "arcmsr%d: ccb ='0x%p' isr got aborted command \n"
- , acb->host->host_no, ccb);
- }
- continue;
- }
- printk(KERN_NOTICE
- "arcmsr%d: isr get an illegal ccb command done acb = '0x%p'"
- "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x"
- " ccboutstandingcount = %d \n"
- , acb->host->host_no
- , acb
- , ccb
- , ccb->acb
- , ccb->startdone
- , atomic_read(&acb->ccboutstandingcount));
- continue;
- }
- id = ccb->pcmd->device->id;
- lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
- if (acb->devstate[id][lun] == ARECA_RAID_GONE)
- acb->devstate[id][lun] = ARECA_RAID_GOOD;
- ccb->pcmd->result = DID_OK << 16;
- arcmsr_ccb_complete(ccb, 1);
- } else {
- switch(ccb->arcmsr_cdb.DeviceStatus) {
- case ARCMSR_DEV_SELECT_TIMEOUT: {
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
- case ARCMSR_DEV_ABORTED:
- case ARCMSR_DEV_INIT_FAIL: {
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
- case ARCMSR_DEV_CHECK_CONDITION: {
- acb->devstate[id][lun] = ARECA_RAID_GOOD;
- arcmsr_report_sense_info(ccb);
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
- default:
- printk(KERN_NOTICE
- "arcmsr%d: scsi id = %d lun = %d"
- " isr get command error done, "
- "but got unknown DeviceStatus = 0x%x \n"
- , acb->host->host_no
- , id
- , lun
- , ccb->arcmsr_cdb.DeviceStatus);
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
- break;
- }
- }
- }/*drain reply FIFO*/
+ writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, &reg->inbound_doorbell);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = acb->pmuB;
+ /*
+ ** push inbound doorbell tell iop, driver data write ok
+ ** and wait reply on next hwinterrupt for next Qbuffer post
+ */
+ writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell_reg);
+ }
+ break;
+ }
+}
+
+struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
+{
+ struct QBUFFER __iomem *qbuffer = NULL;
+
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ qbuffer = (struct QBUFFER __iomem *)&reg->message_rbuffer;
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = acb->pmuB;
+ qbuffer = (struct QBUFFER __iomem *)reg->ioctl_rbuffer_reg;
+ }
+ break;
+ }
+ return qbuffer;
+}
+
+static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb)
+{
+ struct QBUFFER __iomem *pqbuffer = NULL;
+
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ pqbuffer = (struct QBUFFER __iomem *) &reg->message_wbuffer;
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = acb->pmuB;
+ pqbuffer = (struct QBUFFER __iomem *)reg->ioctl_wbuffer_reg;
+ }
+ break;
+ }
+ return pqbuffer;
+}
+
+static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
+{
+ struct QBUFFER __iomem *prbuffer;
+ struct QBUFFER *pQbuffer;
+ uint8_t __iomem *iop_data;
+ int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
+
+ rqbuf_lastindex = acb->rqbuf_lastindex;
+ rqbuf_firstindex = acb->rqbuf_firstindex;
+ prbuffer = arcmsr_get_iop_rqbuffer(acb);
+ iop_data = (uint8_t __iomem *)prbuffer->data;
+ iop_len = prbuffer->data_len;
+ my_empty_len = (rqbuf_firstindex - rqbuf_lastindex -1)&(ARCMSR_MAX_QBUFFER -1);
+
+ if (my_empty_len >= iop_len)
+ {
+ while (iop_len > 0) {
+ pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex];
+ memcpy(pQbuffer, iop_data,1);
+ rqbuf_lastindex++;
+ rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ iop_len--;
+ }
+ acb->rqbuf_lastindex = rqbuf_lastindex;
+ arcmsr_iop_message_read(acb);
+ }
+
+ else {
+ acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
+ }
+}
+
+static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb)
+{
+ acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
+ if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
+ uint8_t *pQbuffer;
+ struct QBUFFER __iomem *pwbuffer;
+ uint8_t __iomem *iop_data;
+ int32_t allxfer_len = 0;
+
+ acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
+ pwbuffer = arcmsr_get_iop_wqbuffer(acb);
+ iop_data = (uint8_t __iomem *)pwbuffer->data;
+
+ while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) && \
+ (allxfer_len < 124)) {
+ pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex];
+ memcpy(iop_data, pQbuffer, 1);
+ acb->wqbuf_firstindex++;
+ acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ allxfer_len++;
+ }
+ pwbuffer->data_len = allxfer_len;
+
+ arcmsr_iop_message_wrote(acb);
+ }
+
+ if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) {
+ acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
+ }
+}
+
+static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb)
+{
+ uint32_t outbound_doorbell;
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+
+ outbound_doorbell = readl(&reg->outbound_doorbell);
+ writel(outbound_doorbell, &reg->outbound_doorbell);
+ if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
+ arcmsr_iop2drv_data_wrote_handle(acb);
+ }
+
+ if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
+ arcmsr_iop2drv_data_read_handle(acb);
+ }
+}
+
+static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
+{
+ uint32_t flag_ccb;
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+
+ while ((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) {
+ arcmsr_drain_donequeue(acb, flag_ccb);
+ }
+}
+
+static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb)
+{
+ uint32_t index;
+ uint32_t flag_ccb;
+ struct MessageUnit_B *reg = acb->pmuB;
+
+ index = reg->doneq_index;
+
+ while ((flag_ccb = readl(&reg->done_qbuffer[index])) != 0) {
+ writel(0, &reg->done_qbuffer[index]);
+ arcmsr_drain_donequeue(acb, flag_ccb);
+ index++;
+ index %= ARCMSR_MAX_HBB_POSTQUEUE;
+ reg->doneq_index = index;
+ }
+}
+
+static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
+{
+ uint32_t outbound_intstatus;
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+
+ outbound_intstatus = readl(&reg->outbound_intstatus) & \
+ acb->outbound_int_enable;
+ if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) {
+ return 1;
+ }
+ writel(outbound_intstatus, &reg->outbound_intstatus);
+ if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) {
+ arcmsr_hba_doorbell_isr(acb);
+ }
+ if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
+ arcmsr_hba_postqueue_isr(acb);
+ }
+ return 0;
+}
+
+static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
+{
+ uint32_t outbound_doorbell;
+ struct MessageUnit_B *reg = acb->pmuB;
+
+ outbound_doorbell = readl(reg->iop2drv_doorbell_reg) & \
+ acb->outbound_int_enable;
+ if (!outbound_doorbell)
+ return 1;
+
+ writel(~outbound_doorbell, reg->iop2drv_doorbell_reg);
+
+ if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) {
+ arcmsr_iop2drv_data_wrote_handle(acb);
+ }
+ if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) {
+ arcmsr_iop2drv_data_read_handle(acb);
+ }
+ if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) {
+ arcmsr_hbb_postqueue_isr(acb);
+ }
+
+ return 0;
+}
+
+static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ if (arcmsr_handle_hba_isr(acb)) {
+ return IRQ_NONE;
+ }
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ if (arcmsr_handle_hbb_isr(acb)) {
+ return IRQ_NONE;
+ }
+ }
+ break;
}
- if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))
- return IRQ_NONE;
return IRQ_HANDLED;
}
@@ -818,16 +1313,47 @@ static void arcmsr_iop_parking(struct AdapterControlBlock *acb)
if (acb) {
/* stop adapter background rebuild */
if (acb->acb_flags & ACB_F_MSG_START_BGRB) {
+ uint32_t intmask_org;
acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
+ intmask_org = arcmsr_disable_outbound_ints(acb);
arcmsr_stop_adapter_bgrb(acb);
arcmsr_flush_adapter_cache(acb);
+ arcmsr_enable_outbound_ints(acb, intmask_org);
+ }
+ }
+}
+
+void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb)
+{
+ int32_t wqbuf_firstindex, wqbuf_lastindex;
+ uint8_t *pQbuffer;
+ struct QBUFFER __iomem *pwbuffer;
+ uint8_t __iomem *iop_data;
+ int32_t allxfer_len = 0;
+
+ pwbuffer = arcmsr_get_iop_wqbuffer(acb);
+ iop_data = (uint8_t __iomem *)pwbuffer->data;
+ if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
+ acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
+ wqbuf_firstindex = acb->wqbuf_firstindex;
+ wqbuf_lastindex = acb->wqbuf_lastindex;
+ while ((wqbuf_firstindex != wqbuf_lastindex) && (allxfer_len < 124)) {
+ pQbuffer = &acb->wqbuffer[wqbuf_firstindex];
+ memcpy(iop_data, pQbuffer, 1);
+ wqbuf_firstindex++;
+ wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ allxfer_len++;
}
+ acb->wqbuf_firstindex = wqbuf_firstindex;
+ pwbuffer->data_len = allxfer_len;
+ arcmsr_iop_message_wrote(acb);
}
}
-static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd)
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
+ struct scsi_cmnd *cmd)
{
- struct MessageUnit __iomem *reg = acb->pmu;
struct CMD_MESSAGE_FIELD *pcmdmessagefld;
int retvalue = 0, transfer_len = 0;
char *buffer;
@@ -836,10 +1362,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_
(uint32_t ) cmd->cmnd[6] << 16 |
(uint32_t ) cmd->cmnd[7] << 8 |
(uint32_t ) cmd->cmnd[8];
- /* 4 bytes: Areca io control code */
+ /* 4 bytes: Areca io control code */
sg = scsi_sglist(cmd);
- buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
if (scsi_sg_count(cmd) > 1) {
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
@@ -852,194 +1378,199 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_
}
pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer;
switch(controlcode) {
+
case ARCMSR_MESSAGE_READ_RQBUFFER: {
- unsigned long *ver_addr;
- dma_addr_t buf_handle;
- uint8_t *pQbuffer, *ptmpQbuffer;
- int32_t allxfer_len = 0;
+ unsigned long *ver_addr;
+ dma_addr_t buf_handle;
+ uint8_t *pQbuffer, *ptmpQbuffer;
+ int32_t allxfer_len = 0;
+
+ ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
+ if (!ver_addr) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
+ }
+ ptmpQbuffer = (uint8_t *) ver_addr;
+ while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
+ && (allxfer_len < 1031)) {
+ pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
+ memcpy(ptmpQbuffer, pQbuffer, 1);
+ acb->rqbuf_firstindex++;
+ acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ ptmpQbuffer++;
+ allxfer_len++;
+ }
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
- ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
- if (!ver_addr) {
- retvalue = ARCMSR_MESSAGE_FAIL;
- goto message_out;
- }
- ptmpQbuffer = (uint8_t *) ver_addr;
- while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
- && (allxfer_len < 1031)) {
- pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
- memcpy(ptmpQbuffer, pQbuffer, 1);
- acb->rqbuf_firstindex++;
- acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
- ptmpQbuffer++;
- allxfer_len++;
- }
- if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
- struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
- &reg->message_rbuffer;
- uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
- int32_t iop_len;
-
- acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
- iop_len = readl(&prbuffer->data_len);
- while (iop_len > 0) {
- acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
- acb->rqbuf_lastindex++;
- acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
- iop_data++;
- iop_len--;
- }
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
- &reg->inbound_doorbell);
+ struct QBUFFER __iomem *prbuffer;
+ uint8_t __iomem *iop_data;
+ int32_t iop_len;
+
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ prbuffer = arcmsr_get_iop_rqbuffer(acb);
+ iop_data = prbuffer->data;
+ iop_len = readl(&prbuffer->data_len);
+ while (iop_len > 0) {
+ acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
+ acb->rqbuf_lastindex++;
+ acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ iop_len--;
}
- memcpy(pcmdmessagefld->messagedatabuffer,
- (uint8_t *)ver_addr, allxfer_len);
- pcmdmessagefld->cmdmessage.Length = allxfer_len;
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
- pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
+ arcmsr_iop_message_read(acb);
+ }
+ memcpy(pcmdmessagefld->messagedatabuffer, (uint8_t *)ver_addr, allxfer_len);
+ pcmdmessagefld->cmdmessage.Length = allxfer_len;
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
}
break;
- case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
- unsigned long *ver_addr;
- dma_addr_t buf_handle;
- int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
- uint8_t *pQbuffer, *ptmpuserbuffer;
- ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
- if (!ver_addr) {
- retvalue = ARCMSR_MESSAGE_FAIL;
- goto message_out;
- }
- ptmpuserbuffer = (uint8_t *)ver_addr;
- user_len = pcmdmessagefld->cmdmessage.Length;
- memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
- wqbuf_lastindex = acb->wqbuf_lastindex;
- wqbuf_firstindex = acb->wqbuf_firstindex;
- if (wqbuf_lastindex != wqbuf_firstindex) {
+ case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
+ unsigned long *ver_addr;
+ dma_addr_t buf_handle;
+ int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
+ uint8_t *pQbuffer, *ptmpuserbuffer;
+
+ ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
+ if (!ver_addr) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
+ }
+ ptmpuserbuffer = (uint8_t *)ver_addr;
+ user_len = pcmdmessagefld->cmdmessage.Length;
+ memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
+ wqbuf_lastindex = acb->wqbuf_lastindex;
+ wqbuf_firstindex = acb->wqbuf_firstindex;
+ if (wqbuf_lastindex != wqbuf_firstindex) {
+ struct SENSE_DATA *sensebuffer =
+ (struct SENSE_DATA *)cmd->sense_buffer;
+ arcmsr_post_ioctldata2iop(acb);
+ /* has error report sensedata */
+ sensebuffer->ErrorCode = 0x70;
+ sensebuffer->SenseKey = ILLEGAL_REQUEST;
+ sensebuffer->AdditionalSenseLength = 0x0A;
+ sensebuffer->AdditionalSenseCode = 0x20;
+ sensebuffer->Valid = 1;
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ } else {
+ my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
+ &(ARCMSR_MAX_QBUFFER - 1);
+ if (my_empty_len >= user_len) {
+ while (user_len > 0) {
+ pQbuffer =
+ &acb->wqbuffer[acb->wqbuf_lastindex];
+ memcpy(pQbuffer, ptmpuserbuffer, 1);
+ acb->wqbuf_lastindex++;
+ acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ ptmpuserbuffer++;
+ user_len--;
+ }
+ if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
+ acb->acb_flags &=
+ ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
+ arcmsr_post_ioctldata2iop(acb);
+ }
+ } else {
+ /* has error report sensedata */
struct SENSE_DATA *sensebuffer =
(struct SENSE_DATA *)cmd->sense_buffer;
- arcmsr_post_Qbuffer(acb);
- /* has error report sensedata */
sensebuffer->ErrorCode = 0x70;
sensebuffer->SenseKey = ILLEGAL_REQUEST;
sensebuffer->AdditionalSenseLength = 0x0A;
sensebuffer->AdditionalSenseCode = 0x20;
sensebuffer->Valid = 1;
retvalue = ARCMSR_MESSAGE_FAIL;
- } else {
- my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
- &(ARCMSR_MAX_QBUFFER - 1);
- if (my_empty_len >= user_len) {
- while (user_len > 0) {
- pQbuffer =
- &acb->wqbuffer[acb->wqbuf_lastindex];
- memcpy(pQbuffer, ptmpuserbuffer, 1);
- acb->wqbuf_lastindex++;
- acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
- ptmpuserbuffer++;
- user_len--;
- }
- if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
- acb->acb_flags &=
- ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
- arcmsr_post_Qbuffer(acb);
- }
- } else {
- /* has error report sensedata */
- struct SENSE_DATA *sensebuffer =
- (struct SENSE_DATA *)cmd->sense_buffer;
- sensebuffer->ErrorCode = 0x70;
- sensebuffer->SenseKey = ILLEGAL_REQUEST;
- sensebuffer->AdditionalSenseLength = 0x0A;
- sensebuffer->AdditionalSenseCode = 0x20;
- sensebuffer->Valid = 1;
- retvalue = ARCMSR_MESSAGE_FAIL;
- }
+ }
}
pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
}
break;
+
case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
- uint8_t *pQbuffer = acb->rqbuffer;
+ uint8_t *pQbuffer = acb->rqbuffer;
- if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
- acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
- &reg->inbound_doorbell);
- }
- acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
- acb->rqbuf_firstindex = 0;
- acb->rqbuf_lastindex = 0;
- memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
- pcmdmessagefld->cmdmessage.ReturnCode =
- ARCMSR_MESSAGE_RETURNCODE_OK;
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ arcmsr_iop_message_read(acb);
+ }
+ acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
+ acb->rqbuf_firstindex = 0;
+ acb->rqbuf_lastindex = 0;
+ memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
}
break;
+
case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
- uint8_t *pQbuffer = acb->wqbuffer;
+ uint8_t *pQbuffer = acb->wqbuffer;
- if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
- acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
- , &reg->inbound_doorbell);
- }
- acb->acb_flags |=
- (ACB_F_MESSAGE_WQBUFFER_CLEARED |
- ACB_F_MESSAGE_WQBUFFER_READED);
- acb->wqbuf_firstindex = 0;
- acb->wqbuf_lastindex = 0;
- memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
- pcmdmessagefld->cmdmessage.ReturnCode =
- ARCMSR_MESSAGE_RETURNCODE_OK;
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ arcmsr_iop_message_read(acb);
+ }
+ acb->acb_flags |=
+ (ACB_F_MESSAGE_WQBUFFER_CLEARED |
+ ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->wqbuf_firstindex = 0;
+ acb->wqbuf_lastindex = 0;
+ memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
}
break;
+
case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
- uint8_t *pQbuffer;
+ uint8_t *pQbuffer;
- if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
- acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
- , &reg->inbound_doorbell);
- }
- acb->acb_flags |=
- (ACB_F_MESSAGE_WQBUFFER_CLEARED
- | ACB_F_MESSAGE_RQBUFFER_CLEARED
- | ACB_F_MESSAGE_WQBUFFER_READED);
- acb->rqbuf_firstindex = 0;
- acb->rqbuf_lastindex = 0;
- acb->wqbuf_firstindex = 0;
- acb->wqbuf_lastindex = 0;
- pQbuffer = acb->rqbuffer;
- memset(pQbuffer, 0, sizeof (struct QBUFFER));
- pQbuffer = acb->wqbuffer;
- memset(pQbuffer, 0, sizeof (struct QBUFFER));
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ arcmsr_iop_message_read(acb);
+ }
+ acb->acb_flags |=
+ (ACB_F_MESSAGE_WQBUFFER_CLEARED
+ | ACB_F_MESSAGE_RQBUFFER_CLEARED
+ | ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->rqbuf_firstindex = 0;
+ acb->rqbuf_lastindex = 0;
+ acb->wqbuf_firstindex = 0;
+ acb->wqbuf_lastindex = 0;
+ pQbuffer = acb->rqbuffer;
+ memset(pQbuffer, 0, sizeof(struct QBUFFER));
+ pQbuffer = acb->wqbuffer;
+ memset(pQbuffer, 0, sizeof(struct QBUFFER));
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
}
break;
+
case ARCMSR_MESSAGE_RETURN_CODE_3F: {
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
}
break;
+
case ARCMSR_MESSAGE_SAY_HELLO: {
- int8_t * hello_string = "Hello! I am ARCMSR";
+ int8_t *hello_string = "Hello! I am ARCMSR";
- memcpy(pcmdmessagefld->messagedatabuffer, hello_string
- , (int16_t)strlen(hello_string));
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ memcpy(pcmdmessagefld->messagedatabuffer, hello_string
+ , (int16_t)strlen(hello_string));
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
}
break;
+
case ARCMSR_MESSAGE_SAY_GOODBYE:
arcmsr_iop_parking(acb);
break;
+
case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
arcmsr_flush_adapter_cache(acb);
break;
+
default:
retvalue = ARCMSR_MESSAGE_FAIL;
}
- message_out:
+ message_out:
sg = scsi_sglist(cmd);
kunmap_atomic(buffer - sg->offset, KM_IRQ0);
-
return retvalue;
}
@@ -1084,7 +1615,7 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
strncpy(&inqdata[32], "R001", 4); /* Product Revision */
sg = scsi_sglist(cmd);
- buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
memcpy(buffer, inqdata, sizeof(inqdata));
sg = scsi_sglist(cmd);
@@ -1109,8 +1640,7 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
void (* done)(struct scsi_cmnd *))
{
struct Scsi_Host *host = cmd->device->host;
- struct AdapterControlBlock *acb =
- (struct AdapterControlBlock *) host->hostdata;
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
struct CommandControlBlock *ccb;
int target = cmd->device->id;
int lun = cmd->device->lun;
@@ -1153,26 +1683,27 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
ccb = arcmsr_get_freeccb(acb);
if (!ccb)
return SCSI_MLQUEUE_HOST_BUSY;
+
arcmsr_build_ccb(acb, ccb, cmd);
arcmsr_post_ccb(acb, ccb);
return 0;
}
-static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
+static void arcmsr_get_hba_config(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
char *acb_firm_model = acb->firm_model;
char *acb_firm_version = acb->firm_version;
- char __iomem *iop_firm_model = (char __iomem *) &reg->message_rwbuffer[15];
- char __iomem *iop_firm_version = (char __iomem *) &reg->message_rwbuffer[17];
+ char __iomem *iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]);
+ char __iomem *iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]);
int count;
writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb))
- printk(KERN_NOTICE
- "arcmsr%d: wait "
- "'get adapter firmware miscellaneous data' timeout \n"
- , acb->host->host_no);
+ if (arcmsr_hba_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
+ miscellaneous data' timeout \n", acb->host->host_no);
+ }
+
count = 8;
while (count) {
*acb_firm_model = readb(iop_firm_model);
@@ -1180,6 +1711,7 @@ static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
iop_firm_model++;
count--;
}
+
count = 16;
while (count) {
*acb_firm_version = readb(iop_firm_version);
@@ -1187,28 +1719,93 @@ static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
iop_firm_version++;
count--;
}
- printk(KERN_INFO
- "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
+
+ printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
, acb->host->host_no
, acb->firm_version);
+
acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
}
-static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
+static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = acb->pmuB;
+ uint32_t __iomem *lrwbuffer = reg->msgcode_rwbuffer_reg;
+ char *acb_firm_model = acb->firm_model;
+ char *acb_firm_version = acb->firm_version;
+ char __iomem *iop_firm_model = (char __iomem *)(&lrwbuffer[15]);
+ /*firm_model,15,60-67*/
+ char __iomem *iop_firm_version = (char __iomem *)(&lrwbuffer[17]);
+ /*firm_version,17,68-83*/
+ int count;
+
+ writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg);
+ if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
+ miscellaneous data' timeout \n", acb->host->host_no);
+ }
+
+ count = 8;
+ while (count)
+ {
+ *acb_firm_model = readb(iop_firm_model);
+ acb_firm_model++;
+ iop_firm_model++;
+ count--;
+ }
+
+ count = 16;
+ while (count)
+ {
+ *acb_firm_version = readb(iop_firm_version);
+ acb_firm_version++;
+ iop_firm_version++;
+ count--;
+ }
+
+ printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n",
+ acb->host->host_no,
+ acb->firm_version);
+
+ lrwbuffer++;
+ acb->firm_request_len = readl(lrwbuffer++);
+ /*firm_request_len,1,04-07*/
+ acb->firm_numbers_queue = readl(lrwbuffer++);
+ /*firm_numbers_queue,2,08-11*/
+ acb->firm_sdram_size = readl(lrwbuffer++);
+ /*firm_sdram_size,3,12-15*/
+ acb->firm_hd_channels = readl(lrwbuffer);
+ /*firm_ide_channels,4,16-19*/
+}
+
+static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ arcmsr_get_hba_config(acb);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ arcmsr_get_hbb_config(acb);
+ }
+ break;
+ }
+}
+
+static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
struct CommandControlBlock *ccb;
uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
- int id, lun;
- polling_ccb_retry:
+ polling_hba_ccb_retry:
poll_count++;
- outbound_intstatus = readl(&reg->outbound_intstatus)
- & acb->outbound_int_enable;
+ outbound_intstatus = readl(&reg->outbound_intstatus) & acb->outbound_int_enable;
writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
while (1) {
if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF) {
@@ -1218,17 +1815,14 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
msleep(25);
if (poll_count > 100)
break;
- goto polling_ccb_retry;
+ goto polling_hba_ccb_retry;
}
}
- ccb = (struct CommandControlBlock *)
- (acb->vir2phy_offset + (flag_ccb << 5));
- if ((ccb->acb != acb) ||
- (ccb->startdone != ARCMSR_CCB_START)) {
- if ((ccb->startdone == ARCMSR_CCB_ABORTED) ||
- (ccb == poll_ccb)) {
- printk(KERN_NOTICE
- "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
+ ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5));
+ poll_ccb_done = (ccb == poll_ccb) ? 1:0;
+ if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
+ if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
+ printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
" poll command abort successfully \n"
, acb->host->host_no
, ccb->pcmd->device->id
@@ -1239,176 +1833,279 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
poll_ccb_done = 1;
continue;
}
- printk(KERN_NOTICE
- "arcmsr%d: polling get an illegal ccb"
- " command done ccb ='0x%p'"
+ printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
+ " command done ccb = '0x%p'"
"ccboutstandingcount = %d \n"
, acb->host->host_no
, ccb
, atomic_read(&acb->ccboutstandingcount));
continue;
}
- id = ccb->pcmd->device->id;
- lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
- if (acb->devstate[id][lun] == ARECA_RAID_GONE)
- acb->devstate[id][lun] = ARECA_RAID_GOOD;
- ccb->pcmd->result = DID_OK << 16;
- arcmsr_ccb_complete(ccb, 1);
- } else {
- switch(ccb->arcmsr_cdb.DeviceStatus) {
- case ARCMSR_DEV_SELECT_TIMEOUT: {
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
- case ARCMSR_DEV_ABORTED:
- case ARCMSR_DEV_INIT_FAIL: {
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+ }
+}
+
+static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, \
+ struct CommandControlBlock *poll_ccb)
+{
+ struct MessageUnit_B *reg = acb->pmuB;
+ struct CommandControlBlock *ccb;
+ uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
+ int index;
+
+ polling_hbb_ccb_retry:
+ poll_count++;
+ /* clear doorbell interrupt */
+ writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
+ while (1) {
+ index = reg->doneq_index;
+ if ((flag_ccb = readl(&reg->done_qbuffer[index])) == 0) {
+ if (poll_ccb_done)
+ break;
+ else {
+ msleep(25);
+ if (poll_count > 100)
+ break;
+ goto polling_hbb_ccb_retry;
}
- break;
- case ARCMSR_DEV_CHECK_CONDITION: {
- acb->devstate[id][lun] = ARECA_RAID_GOOD;
- arcmsr_report_sense_info(ccb);
+ }
+ writel(0, &reg->done_qbuffer[index]);
+ index++;
+ /*if last index number set it to 0 */
+ index %= ARCMSR_MAX_HBB_POSTQUEUE;
+ reg->doneq_index = index;
+ /* check ifcommand done with no error*/
+ ccb = (struct CommandControlBlock *)\
+ (acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/
+ poll_ccb_done = (ccb == poll_ccb) ? 1:0;
+ if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
+ if (ccb->startdone == ARCMSR_CCB_ABORTED) {
+ printk(KERN_NOTICE "arcmsr%d: \
+ scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n"
+ ,acb->host->host_no
+ ,ccb->pcmd->device->id
+ ,ccb->pcmd->device->lun
+ ,ccb);
+ ccb->pcmd->result = DID_ABORT << 16;
arcmsr_ccb_complete(ccb, 1);
+ continue;
}
- break;
- default:
- printk(KERN_NOTICE
- "arcmsr%d: scsi id = %d lun = %d"
- " polling and getting command error done"
- "but got unknown DeviceStatus = 0x%x \n"
+ printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
+ " command done ccb = '0x%p'"
+ "ccboutstandingcount = %d \n"
, acb->host->host_no
- , id
- , lun
- , ccb->arcmsr_cdb.DeviceStatus);
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- break;
+ , ccb
+ , atomic_read(&acb->ccboutstandingcount));
+ continue;
}
+ arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+ } /*drain reply FIFO*/
+}
+
+static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, \
+ struct CommandControlBlock *poll_ccb)
+{
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ arcmsr_polling_hba_ccbdone(acb,poll_ccb);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ arcmsr_polling_hbb_ccbdone(acb,poll_ccb);
}
}
}
-static void arcmsr_done4_abort_postqueue(struct AdapterControlBlock *acb)
+
+static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
{
- int i = 0, found = 0;
- int id, lun;
- uint32_t flag_ccb, outbound_intstatus;
- struct MessageUnit __iomem *reg = acb->pmu;
- struct CommandControlBlock *ccb;
- /*clear and abort all outbound posted Q*/
-
- while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) &&
-(i++ < 256)){
- ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
-(flag_ccb << 5));
- if (ccb){
- if ((ccb->acb != acb)||(ccb->startdone != \
-ARCMSR_CCB_START)){
- printk(KERN_NOTICE "arcmsr%d: polling get \
-an illegal ccb" "command done ccb = '0x%p'""ccboutstandingcount = %d \n",
- acb->host->host_no, ccb,
- atomic_read(&acb->ccboutstandingcount));
- continue;
+ uint32_t cdb_phyaddr, ccb_phyaddr_hi32;
+ dma_addr_t dma_coherent_handle;
+ /*
+ ********************************************************************
+ ** here we need to tell iop 331 our freeccb.HighPart
+ ** if freeccb.HighPart is not zero
+ ********************************************************************
+ */
+ dma_coherent_handle = acb->dma_coherent_handle;
+ cdb_phyaddr = (uint32_t)(dma_coherent_handle);
+ ccb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+ /*
+ ***********************************************************************
+ ** if adapter type B, set window of "post command Q"
+ ***********************************************************************
+ */
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ if (ccb_phyaddr_hi32 != 0) {
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ uint32_t intmask_org;
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ writel(ARCMSR_SIGNATURE_SET_CONFIG, \
+ &reg->message_rwbuffer[0]);
+ writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);
+ writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \
+ &reg->inbound_msgaddr0);
+ if (arcmsr_hba_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: ""set ccb high \
+ part physical address timeout\n",
+ acb->host->host_no);
+ return 1;
}
+ arcmsr_enable_outbound_ints(acb, intmask_org);
+ }
+ }
+ break;
- id = ccb->pcmd->device->id;
- lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)){
- if (acb->devstate[id][lun] == ARECA_RAID_GONE)
- acb->devstate[id][lun] = ARECA_RAID_GOOD;
- ccb->pcmd->result = DID_OK << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- else {
- switch(ccb->arcmsr_cdb.DeviceStatus) {
- case ARCMSR_DEV_SELECT_TIMEOUT: {
- acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
+ case ACB_ADAPTER_TYPE_B: {
+ unsigned long post_queue_phyaddr;
+ uint32_t __iomem *rwbuffer;
- case ARCMSR_DEV_ABORTED:
+ struct MessageUnit_B *reg = acb->pmuB;
+ uint32_t intmask_org;
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ reg->postq_index = 0;
+ reg->doneq_index = 0;
+ writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell_reg);
+ if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \
+ acb->host->host_no);
+ return 1;
+ }
+ post_queue_phyaddr = cdb_phyaddr + ARCMSR_MAX_FREECCB_NUM * \
+ sizeof(struct CommandControlBlock) + offsetof(struct MessageUnit_B, post_qbuffer) ;
+ rwbuffer = reg->msgcode_rwbuffer_reg;
+ /* driver "set config" signature */
+ writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
+ /* normal should be zero */
+ writel(ccb_phyaddr_hi32, rwbuffer++);
+ /* postQ size (256 + 8)*4 */
+ writel(post_queue_phyaddr, rwbuffer++);
+ /* doneQ size (256 + 8)*4 */
+ writel(post_queue_phyaddr + 1056, rwbuffer++);
+ /* ccb maxQ size must be --> [(256 + 8)*4]*/
+ writel(1056, rwbuffer);
+
+ writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell_reg);
+ if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
+ timeout \n",acb->host->host_no);
+ return 1;
+ }
- case ARCMSR_DEV_INIT_FAIL: {
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
+ writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell_reg);
+ if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: 'can not set diver mode \n"\
+ ,acb->host->host_no);
+ return 1;
+ }
+ arcmsr_enable_outbound_ints(acb, intmask_org);
+ }
+ break;
+ }
+ return 0;
+}
- case ARCMSR_DEV_CHECK_CONDITION: {
- acb->devstate[id][lun] =
- ARECA_RAID_GOOD;
- arcmsr_report_sense_info(ccb);
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
+static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
+{
+ uint32_t firmware_state = 0;
- default:
- printk(KERN_NOTICE
- "arcmsr%d: scsi id = %d \
- lun = %d""polling and \
- getting command error \
- done""but got unknown \
- DeviceStatus = 0x%x \n",
- acb->host->host_no, id,
- lun, ccb->arcmsr_cdb.DeviceStatus);
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- break;
- }
- }
- found = 1;
- }
+ switch (acb->adapter_type) {
+
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ do {
+ firmware_state = readl(&reg->outbound_msgaddr1);
+ } while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = acb->pmuB;
+ do {
+ firmware_state = readl(reg->iop2drv_doorbell_reg);
+ } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
+ }
+ break;
}
- if (found){
- outbound_intstatus = readl(&reg->outbound_intstatus) & \
- acb->outbound_int_enable;
- writel(outbound_intstatus, &reg->outbound_intstatus);
- /*clear interrupt*/
+}
+
+static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ acb->acb_flags |= ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
+ if (arcmsr_hba_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
+ rebulid' timeout \n", acb->host->host_no);
}
- return;
}
+static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = acb->pmuB;
+ acb->acb_flags |= ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell_reg);
+ if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
+ rebulid' timeout \n",acb->host->host_no);
+ }
+}
-static void arcmsr_iop_init(struct AdapterControlBlock *acb)
+static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
- uint32_t intmask_org, mask, outbound_doorbell, firmware_state = 0;
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A:
+ arcmsr_start_hba_bgrb(acb);
+ break;
+ case ACB_ADAPTER_TYPE_B:
+ arcmsr_start_hbb_bgrb(acb);
+ break;
+ }
+}
- do {
- firmware_state = readl(&reg->outbound_msgaddr1);
- } while (!(firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK));
- intmask_org = readl(&reg->outbound_intmask)
- | ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE;
- arcmsr_get_firmware_spec(acb);
+static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ uint32_t outbound_doorbell;
+ /* empty doorbell Qbuffer if door bell ringed */
+ outbound_doorbell = readl(&reg->outbound_doorbell);
+ /*clear doorbell interrupt */
+ writel(outbound_doorbell, &reg->outbound_doorbell);
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+ }
+ break;
- acb->acb_flags |= ACB_F_MSG_START_BGRB;
- writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb)) {
- printk(KERN_NOTICE "arcmsr%d: "
- "wait 'start adapter background rebulid' timeout\n",
- acb->host->host_no);
+ case ACB_ADAPTER_TYPE_B: {
+ struct MessageUnit_B *reg = acb->pmuB;
+ /*clear interrupt and message state*/
+ writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
+ writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg);
+ /* let IOP know data has been read */
+ }
+ break;
}
+}
- outbound_doorbell = readl(&reg->outbound_doorbell);
- writel(outbound_doorbell, &reg->outbound_doorbell);
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
- mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE
- | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
- writel(intmask_org & mask, &reg->outbound_intmask);
- acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
+static void arcmsr_iop_init(struct AdapterControlBlock *acb)
+{
+ uint32_t intmask_org;
+
+ arcmsr_wait_firmware_ready(acb);
+ arcmsr_iop_confirm(acb);
+ /* disable all outbound interrupt */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ arcmsr_get_firmware_spec(acb);
+ /*start background rebuild*/
+ arcmsr_start_adapter_bgrb(acb);
+ /* empty doorbell Qbuffer if door bell ringed */
+ arcmsr_clear_doorbell_queue_buffer(acb);
+ /* enable outbound Post Queue,outbound doorbell Interrupt */
+ arcmsr_enable_outbound_ints(acb, intmask_org);
acb->acb_flags |= ACB_F_IOP_INITED;
}
@@ -1421,22 +2118,24 @@ static void arcmsr_iop_reset(struct AdapterControlBlock *acb)
if (atomic_read(&acb->ccboutstandingcount) != 0) {
/* talk to iop 331 outstanding command aborted */
arcmsr_abort_allcmd(acb);
+
/* wait for 3 sec for all command aborted*/
- msleep_interruptible(3000);
+ ssleep(3);
+
/* disable all outbound interrupt */
intmask_org = arcmsr_disable_outbound_ints(acb);
/* clear all outbound posted Q */
- arcmsr_done4_abort_postqueue(acb);
+ arcmsr_done4abort_postqueue(acb);
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
ccb = acb->pccb_pool[i];
if (ccb->startdone == ARCMSR_CCB_START) {
ccb->startdone = ARCMSR_CCB_ABORTED;
+ arcmsr_ccb_complete(ccb, 1);
}
}
/* enable all outbound interrupt */
arcmsr_enable_outbound_ints(acb, intmask_org);
}
-
}
static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
@@ -1450,7 +2149,7 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
for (i = 0; i < 400; i++) {
if (!atomic_read(&acb->ccboutstandingcount))
break;
- arcmsr_interrupt(acb);
+ arcmsr_interrupt(acb);/* FIXME: need spinlock */
msleep(25);
}
arcmsr_iop_reset(acb);
@@ -1468,7 +2167,7 @@ static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
/*
** Wait for 3 sec for all command done.
*/
- msleep_interruptible(3000);
+ ssleep(3);
intmask = arcmsr_disable_outbound_ints(acb);
arcmsr_polling_ccbdone(acb, ccb);
@@ -1515,6 +2214,8 @@ static const char *arcmsr_info(struct Scsi_Host *host)
switch (acb->pdev->device) {
case PCI_DEVICE_ID_ARECA_1110:
+ case PCI_DEVICE_ID_ARECA_1200:
+ case PCI_DEVICE_ID_ARECA_1202:
case PCI_DEVICE_ID_ARECA_1210:
raid6 = 0;
/*FALLTHRU*/
@@ -1522,6 +2223,7 @@ static const char *arcmsr_info(struct Scsi_Host *host)
case PCI_DEVICE_ID_ARECA_1130:
case PCI_DEVICE_ID_ARECA_1160:
case PCI_DEVICE_ID_ARECA_1170:
+ case PCI_DEVICE_ID_ARECA_1201:
case PCI_DEVICE_ID_ARECA_1220:
case PCI_DEVICE_ID_ARECA_1230:
case PCI_DEVICE_ID_ARECA_1260:
@@ -1544,287 +2246,82 @@ static const char *arcmsr_info(struct Scsi_Host *host)
ARCMSR_DRIVER_VERSION);
return buf;
}
-
+#ifdef CONFIG_SCSI_ARCMSR_AER
static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev)
{
- struct Scsi_Host *host;
- struct AdapterControlBlock *acb;
- uint8_t bus, dev_fun;
- int error;
-
- error = pci_enable_device(pdev);
- if (error)
- return PCI_ERS_RESULT_DISCONNECT;
- pci_set_master(pdev);
-
- host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof \
-(struct AdapterControlBlock));
- if (!host)
- return PCI_ERS_RESULT_DISCONNECT;
- acb = (struct AdapterControlBlock *)host->hostdata;
- memset(acb, 0, sizeof (struct AdapterControlBlock));
-
- error = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
- if (error) {
- error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (error) {
- printk(KERN_WARNING
- "scsi%d: No suitable DMA mask available\n",
- host->host_no);
- return PCI_ERS_RESULT_DISCONNECT;
- }
- }
- bus = pdev->bus->number;
- dev_fun = pdev->devfn;
- acb = (struct AdapterControlBlock *) host->hostdata;
- memset(acb, 0, sizeof(struct AdapterControlBlock));
- acb->pdev = pdev;
- acb->host = host;
- host->max_sectors = ARCMSR_MAX_XFER_SECTORS;
- host->max_lun = ARCMSR_MAX_TARGETLUN;
- host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/
- host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/
- host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES;
- host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */
- host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;
- host->this_id = ARCMSR_SCSI_INITIATOR_ID;
- host->unique_id = (bus << 8) | dev_fun;
- host->irq = pdev->irq;
- error = pci_request_regions(pdev, "arcmsr");
- if (error)
- return PCI_ERS_RESULT_DISCONNECT;
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *) host->hostdata;
+ uint32_t intmask_org;
+ int i, j;
- acb->pmu = ioremap(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- if (!acb->pmu) {
- printk(KERN_NOTICE "arcmsr%d: memory"
- " mapping region fail \n", acb->host->host_no);
+ if (pci_enable_device(pdev)) {
return PCI_ERS_RESULT_DISCONNECT;
}
+ pci_set_master(pdev);
+ intmask_org = arcmsr_disable_outbound_ints(acb);
acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
ACB_F_MESSAGE_RQBUFFER_CLEARED |
ACB_F_MESSAGE_WQBUFFER_READED);
acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
- INIT_LIST_HEAD(&acb->ccb_free_list);
-
- error = arcmsr_alloc_ccb_pool(acb);
- if (error)
- return PCI_ERS_RESULT_DISCONNECT;
-
- error = request_irq(pdev->irq, arcmsr_do_interrupt,
- IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb);
- if (error)
- return PCI_ERS_RESULT_DISCONNECT;
-
- arcmsr_iop_init(acb);
- if (strncmp(acb->firm_version, "V1.42", 5) >= 0)
- host->max_sectors = ARCMSR_MAX_XFER_SECTORS_B;
-
- pci_set_drvdata(pdev, host);
-
- error = scsi_add_host(host, &pdev->dev);
- if (error)
- return PCI_ERS_RESULT_DISCONNECT;
+ for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+ for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+ acb->devstate[i][j] = ARECA_RAID_GONE;
- error = arcmsr_alloc_sysfs_attr(acb);
- if (error)
- return PCI_ERS_RESULT_DISCONNECT;
+ arcmsr_wait_firmware_ready(acb);
+ arcmsr_iop_confirm(acb);
+ /* disable all outbound interrupt */
+ arcmsr_get_firmware_spec(acb);
+ /*start background rebuild*/
+ arcmsr_start_adapter_bgrb(acb);
+ /* empty doorbell Qbuffer if door bell ringed */
+ arcmsr_clear_doorbell_queue_buffer(acb);
+ /* enable outbound Post Queue,outbound doorbell Interrupt */
+ arcmsr_enable_outbound_ints(acb, intmask_org);
+ acb->acb_flags |= ACB_F_IOP_INITED;
- scsi_scan_host(host);
+ pci_enable_pcie_error_reporting(pdev);
return PCI_ERS_RESULT_RECOVERED;
}
static void arcmsr_pci_ers_need_reset_forepart(struct pci_dev *pdev)
{
struct Scsi_Host *host = pci_get_drvdata(pdev);
- struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
- struct MessageUnit __iomem *reg = acb->pmu;
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *)host->hostdata;
struct CommandControlBlock *ccb;
- /*clear and abort all outbound posted Q*/
- int i = 0, found = 0;
- int id, lun;
- uint32_t flag_ccb, outbound_intstatus;
-
- while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) &&
- (i++ < 256)){
- ccb = (struct CommandControlBlock *)(acb->vir2phy_offset
- + (flag_ccb << 5));
- if (ccb){
- if ((ccb->acb != acb)||(ccb->startdone !=
- ARCMSR_CCB_START)){
- printk(KERN_NOTICE "arcmsr%d: polling \
- get an illegal ccb"" command done ccb = '0x%p'"
- "ccboutstandingcount = %d \n",
- acb->host->host_no, ccb,
- atomic_read(&acb->ccboutstandingcount));
- continue;
- }
-
- id = ccb->pcmd->device->id;
- lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
- if (acb->devstate[id][lun] ==
- ARECA_RAID_GONE)
- acb->devstate[id][lun] =
- ARECA_RAID_GOOD;
- ccb->pcmd->result = DID_OK << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- else {
- switch(ccb->arcmsr_cdb.DeviceStatus) {
- case ARCMSR_DEV_SELECT_TIMEOUT: {
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
-
- case ARCMSR_DEV_ABORTED:
-
- case ARCMSR_DEV_INIT_FAIL: {
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
-
- case ARCMSR_DEV_CHECK_CONDITION: {
- acb->devstate[id][lun] =
- ARECA_RAID_GOOD;
- arcmsr_report_sense_info(ccb);
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
+ uint32_t intmask_org;
+ int i = 0;
- default:
- printk(KERN_NOTICE
- "arcmsr%d: scsi \
- id = %d lun = %d"
- " polling and \
- getting command \
- error done"
- "but got unknown \
- DeviceStatus = 0x%x \n"
- , acb->host->host_no,
- id, lun,
- ccb->arcmsr_cdb.DeviceStatus);
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- break;
- }
- }
- found = 1;
+ if (atomic_read(&acb->ccboutstandingcount) != 0) {
+ /* talk to iop 331 outstanding command aborted */
+ arcmsr_abort_allcmd(acb);
+ /* wait for 3 sec for all command aborted*/
+ ssleep(3);
+ /* disable all outbound interrupt */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ /* clear all outbound posted Q */
+ arcmsr_done4abort_postqueue(acb);
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ ccb = acb->pccb_pool[i];
+ if (ccb->startdone == ARCMSR_CCB_START) {
+ ccb->startdone = ARCMSR_CCB_ABORTED;
+ arcmsr_ccb_complete(ccb, 1);
}
}
- if (found){
- outbound_intstatus = readl(&reg->outbound_intstatus) &
- acb->outbound_int_enable;
- writel(outbound_intstatus, &reg->outbound_intstatus);
- /*clear interrupt*/
- }
- return;
+ /* enable all outbound interrupt */
+ arcmsr_enable_outbound_ints(acb, intmask_org);
+ }
+ pci_disable_device(pdev);
}
-
static void arcmsr_pci_ers_disconnect_forepart(struct pci_dev *pdev)
{
- struct Scsi_Host *host = pci_get_drvdata(pdev);
- struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
- struct MessageUnit __iomem *reg = acb->pmu;
- struct CommandControlBlock *ccb;
- /*clear and abort all outbound posted Q*/
- int i = 0, found = 0;
- int id, lun;
- uint32_t flag_ccb, outbound_intstatus;
-
- while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) &&
- (i++ < 256)){
- ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
- (flag_ccb << 5));
- if (ccb){
- if ((ccb->acb != acb)||(ccb->startdone !=
- ARCMSR_CCB_START)){
- printk(KERN_NOTICE
- "arcmsr%d: polling get an illegal ccb"
- " command done ccb = '0x%p'"
- "ccboutstandingcount = %d \n",
- acb->host->host_no, ccb,
- atomic_read(&acb->ccboutstandingcount));
- continue;
- }
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct AdapterControlBlock *acb = \
+ (struct AdapterControlBlock *)host->hostdata;
- id = ccb->pcmd->device->id;
- lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
- if (acb->devstate[id][lun] == ARECA_RAID_GONE)
- acb->devstate[id][lun] = ARECA_RAID_GOOD;
- ccb->pcmd->result = DID_OK << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- else {
- switch(ccb->arcmsr_cdb.DeviceStatus) {
- case ARCMSR_DEV_SELECT_TIMEOUT: {
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
-
- case ARCMSR_DEV_ABORTED:
-
- case ARCMSR_DEV_INIT_FAIL: {
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
-
- case ARCMSR_DEV_CHECK_CONDITION: {
- acb->devstate[id][lun] =
- ARECA_RAID_GOOD;
- arcmsr_report_sense_info(ccb);
- arcmsr_ccb_complete(ccb, 1);
- }
- break;
-
- default:
- printk(KERN_NOTICE "arcmsr%d: \
- scsi id = %d lun = %d"
- " polling and \
- getting command error done"
- "but got unknown \
- DeviceStatus = 0x%x \n"
- , acb->host->host_no,
- id, lun, ccb->arcmsr_cdb.DeviceStatus);
- acb->devstate[id][lun] =
- ARECA_RAID_GONE;
- ccb->pcmd->result =
- DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
- break;
- }
- }
- found = 1;
- }
- }
- if (found){
- outbound_intstatus = readl(&reg->outbound_intstatus) &
- acb->outbound_int_enable;
- writel(outbound_intstatus, &reg->outbound_intstatus);
- /*clear interrupt*/
- }
- return;
+ arcmsr_stop_adapter_bgrb(acb);
+ arcmsr_flush_adapter_cache(acb);
}
static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
@@ -1840,5 +2337,6 @@ static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
break;
default:
return PCI_ERS_RESULT_NEED_RESET;
- }
+ }
}
+#endif
diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
index 21ba57155be..bb6550e3192 100644
--- a/drivers/scsi/arm/scsi.h
+++ b/drivers/scsi/arm/scsi.h
@@ -38,9 +38,7 @@ static inline int next_SCp(struct scsi_pointer *SCp)
if (ret) {
SCp->buffer++;
SCp->buffers_residual--;
- SCp->ptr = (char *)
- (page_address(SCp->buffer->page) +
- SCp->buffer->offset);
+ SCp->ptr = sg_virt(SCp->buffer);
SCp->this_residual = SCp->buffer->length;
} else {
SCp->ptr = NULL;
@@ -76,9 +74,7 @@ static inline void init_SCp(struct scsi_cmnd *SCpnt)
SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
- SCpnt->SCp.ptr = (char *)
- (page_address(SCpnt->SCp.buffer->page) +
- SCpnt->SCp.buffer->offset);
+ SCpnt->SCp.ptr = sg_virt(SCpnt->SCp.buffer);
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
SCpnt->SCp.phase = SCpnt->request_bufflen;
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 03dbe60c264..a9680b5e8ac 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -477,10 +477,9 @@ static void merge_contiguous_buffers(Scsi_Cmnd *cmd)
for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
cmd->SCp.buffers_residual &&
- virt_to_phys(page_address(cmd->SCp.buffer[1].page) +
- cmd->SCp.buffer[1].offset) == endaddr;) {
+ virt_to_phys(sg_virt(&cmd->SCp.buffer[1])) == endaddr;) {
MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
- page_address(cmd->SCp.buffer[1].page), endaddr);
+ page_address(sg_page(&cmd->SCp.buffer[1])), endaddr);
#if (NDEBUG & NDEBUG_MERGING)
++cnt;
#endif
@@ -515,8 +514,7 @@ static inline void initialize_SCp(Scsi_Cmnd *cmd)
if (cmd->use_sg) {
cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
- cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page) +
- cmd->SCp.buffer->offset;
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
cmd->SCp.this_residual = cmd->SCp.buffer->length;
/* ++roman: Try to merge some scatter-buffers if they are at
* contiguous physical addresses.
@@ -2041,7 +2039,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
+ cmd->scsi_done(cmd);
return;
#endif
case PHASE_DATAIN:
@@ -2054,8 +2052,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
++cmd->SCp.buffer;
--cmd->SCp.buffers_residual;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
- cmd->SCp.buffer->offset;
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
/* ++roman: Try to merge some scatter-buffers if
* they are at contiguous physical addresses.
*/
@@ -2100,7 +2097,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
+ cmd->scsi_done(cmd);
/* XXX - need to source or sink data here, as appropriate */
} else {
#ifdef REAL_DMA
@@ -2235,24 +2232,17 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
#ifdef AUTOSENSE
+ if ((cmd->cmnd[0] == REQUEST_SENSE) &&
+ hostdata->ses.cmd_len) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ hostdata->ses.cmd_len = 0 ;
+ }
+
if ((cmd->cmnd[0] != REQUEST_SENSE) &&
(status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+ scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
+
ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO);
- cmd->cmnd[0] = REQUEST_SENSE;
- cmd->cmnd[1] &= 0xe0;
- cmd->cmnd[2] = 0;
- cmd->cmnd[3] = 0;
- cmd->cmnd[4] = sizeof(cmd->sense_buffer);
- cmd->cmnd[5] = 0;
- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
- cmd->use_sg = 0;
- /* this is initialized from initialize_SCp
- cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
- */
- cmd->request_buffer = (char *) cmd->sense_buffer;
- cmd->request_bufflen = sizeof(cmd->sense_buffer);
local_irq_save(flags);
LIST(cmd,hostdata->issue_queue);
diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c
index cac35408673..d858f3d4127 100644
--- a/drivers/scsi/bvme6000_scsi.c
+++ b/drivers/scsi/bvme6000_scsi.c
@@ -36,19 +36,18 @@ static struct platform_device *bvme6000_scsi_device;
static __devinit int
bvme6000_probe(struct device *dev)
{
- struct Scsi_Host * host = NULL;
+ struct Scsi_Host *host;
struct NCR_700_Host_Parameters *hostdata;
if (!MACH_IS_BVME6000)
goto out;
- hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
- if (hostdata == NULL) {
+ hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (!hostdata) {
printk(KERN_ERR "bvme6000-scsi: "
"Failed to allocate host data\n");
goto out;
}
- memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
/* Fill in the required pieces of hostdata */
hostdata->base = (void __iomem *)BVME_NCR53C710_BASE;
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 2a458d66b6f..024553f9c24 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -1235,7 +1235,21 @@ scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr)
}
EXPORT_SYMBOL(scsi_print_sense_hdr);
+/*
+ * Print normalized SCSI sense header with device information and a prefix.
+ */
void
+scsi_cmd_print_sense_hdr(struct scsi_cmnd *scmd, const char *desc,
+ struct scsi_sense_hdr *sshdr)
+{
+ scmd_printk(KERN_INFO, scmd, "%s: ", desc);
+ scsi_show_sense_hdr(sshdr);
+ scmd_printk(KERN_INFO, scmd, "%s: ", desc);
+ scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+}
+EXPORT_SYMBOL(scsi_cmd_print_sense_hdr);
+
+static void
scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
struct scsi_sense_hdr *sshdr)
{
@@ -1258,7 +1272,7 @@ scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
}
}
-void
+static void
scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len,
struct scsi_sense_hdr *sshdr)
{
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 7b8a3457b69..a9def6e1d30 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -778,7 +778,7 @@ static void srb_waiting_insert(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0, "srb_waiting_insert: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_add(&srb->list, &dcb->srb_waiting_list);
}
@@ -787,7 +787,7 @@ static void srb_waiting_append(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0, "srb_waiting_append: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_add_tail(&srb->list, &dcb->srb_waiting_list);
}
@@ -795,7 +795,7 @@ static void srb_waiting_append(struct DeviceCtlBlk *dcb,
static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0, "srb_going_append: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_add_tail(&srb->list, &dcb->srb_going_list);
}
@@ -805,7 +805,7 @@ static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
struct ScsiReqBlk *i;
struct ScsiReqBlk *tmp;
dprintkdbg(DBG_0, "srb_going_remove: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list)
if (i == srb) {
@@ -821,7 +821,7 @@ static void srb_waiting_remove(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *i;
struct ScsiReqBlk *tmp;
dprintkdbg(DBG_0, "srb_waiting_remove: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list)
if (i == srb) {
@@ -836,7 +836,7 @@ static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb,
{
dprintkdbg(DBG_0,
"srb_going_to_waiting_move: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_move(&srb->list, &dcb->srb_waiting_list);
}
@@ -846,7 +846,7 @@ static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb,
{
dprintkdbg(DBG_0,
"srb_waiting_to_going_move: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
list_move(&srb->list, &dcb->srb_going_list);
}
@@ -982,7 +982,7 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
int nseg;
enum dma_data_direction dir = cmd->sc_data_direction;
dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n",
- cmd->pid, dcb->target_id, dcb->target_lun);
+ cmd->serial_number, dcb->target_id, dcb->target_lun);
srb->dcb = dcb;
srb->cmd = cmd;
@@ -1086,7 +1086,7 @@ static int dc395x_queue_command(struct scsi_cmnd *cmd, void (*done)(struct scsi_
struct AdapterCtlBlk *acb =
(struct AdapterCtlBlk *)cmd->device->host->hostdata;
dprintkdbg(DBG_0, "queue_command: (pid#%li) <%02i-%i> cmnd=0x%02x\n",
- cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
/* Assume BAD_TARGET; will be cleared later */
cmd->result = DID_BAD_TARGET << 16;
@@ -1139,7 +1139,7 @@ static int dc395x_queue_command(struct scsi_cmnd *cmd, void (*done)(struct scsi_
/* process immediately */
send_srb(acb, srb);
}
- dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->pid);
+ dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->serial_number);
return 0;
complete:
@@ -1203,7 +1203,7 @@ static void dump_register_info(struct AdapterCtlBlk *acb,
else
dprintkl(KERN_INFO, "dump: srb=%p cmd=%p (pid#%li) "
"cmnd=0x%02x <%02i-%i>\n",
- srb, srb->cmd, srb->cmd->pid,
+ srb, srb->cmd, srb->cmd->serial_number,
srb->cmd->cmnd[0], srb->cmd->device->id,
srb->cmd->device->lun);
printk(" sglist=%p cnt=%i idx=%i len=%zu\n",
@@ -1300,7 +1300,7 @@ static int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
(struct AdapterCtlBlk *)cmd->device->host->hostdata;
dprintkl(KERN_INFO,
"eh_bus_reset: (pid#%li) target=<%02i-%i> cmd=%p\n",
- cmd->pid, cmd->device->id, cmd->device->lun, cmd);
+ cmd->serial_number, cmd->device->id, cmd->device->lun, cmd);
if (timer_pending(&acb->waiting_timer))
del_timer(&acb->waiting_timer);
@@ -1367,7 +1367,7 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd)
struct DeviceCtlBlk *dcb;
struct ScsiReqBlk *srb;
dprintkl(KERN_INFO, "eh_abort: (pid#%li) target=<%02i-%i> cmd=%p\n",
- cmd->pid, cmd->device->id, cmd->device->lun, cmd);
+ cmd->serial_number, cmd->device->id, cmd->device->lun, cmd);
dcb = find_dcb(acb, cmd->device->id, cmd->device->lun);
if (!dcb) {
@@ -1494,7 +1494,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
u8 s_stat, scsicommand, i, identify_message;
u8 *ptr;
dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
srb->tag_number = TAG_NONE; /* acb->tag_max_num: had error read in eeprom */
@@ -1504,7 +1504,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
#if 1
if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) {
dprintkdbg(DBG_KG, "start_scsi: (pid#%li) BUSY %02x %04x\n",
- srb->cmd->pid, s_stat, s_stat2);
+ srb->cmd->serial_number, s_stat, s_stat2);
/*
* Try anyway?
*
@@ -1522,14 +1522,14 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
if (acb->active_dcb) {
dprintkl(KERN_DEBUG, "start_scsi: (pid#%li) Attempt to start a"
"command while another command (pid#%li) is active.",
- srb->cmd->pid,
+ srb->cmd->serial_number,
acb->active_dcb->active_srb ?
- acb->active_dcb->active_srb->cmd->pid : 0);
+ acb->active_dcb->active_srb->cmd->serial_number : 0);
return 1;
}
if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) {
dprintkdbg(DBG_KG, "start_scsi: (pid#%li) Failed (busy)\n",
- srb->cmd->pid);
+ srb->cmd->serial_number);
return 1;
}
/* Allow starting of SCSI commands half a second before we allow the mid-level
@@ -1603,7 +1603,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
if (tag_number >= dcb->max_command) {
dprintkl(KERN_WARNING, "start_scsi: (pid#%li) "
"Out of tags target=<%02i-%i>)\n",
- srb->cmd->pid, srb->cmd->device->id,
+ srb->cmd->serial_number, srb->cmd->device->id,
srb->cmd->device->lun);
srb->state = SRB_READY;
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
@@ -1622,7 +1622,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
/*polling:*/
/* Send CDB ..command block ......... */
dprintkdbg(DBG_KG, "start_scsi: (pid#%li) <%02i-%i> cmnd=0x%02x tag=%i\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun,
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun,
srb->cmd->cmnd[0], srb->tag_number);
if (srb->flag & AUTO_REQSENSE) {
DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE);
@@ -1647,7 +1647,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
* : Let's process it first!
*/
dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> Failed - busy\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun);
srb->state = SRB_READY;
free_tag(dcb, srb);
srb->msg_count = 0;
@@ -1808,12 +1808,12 @@ static irqreturn_t dc395x_interrupt(int irq, void *dev_id)
irqreturn_t handled = IRQ_NONE;
/*
- * Check for pending interupt
+ * Check for pending interrupt
*/
scsi_status = DC395x_read16(acb, TRM_S1040_SCSI_STATUS);
dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS);
if (scsi_status & SCSIINTERRUPT) {
- /* interupt pending - let's process it! */
+ /* interrupt pending - let's process it! */
dc395x_handle_interrupt(acb, scsi_status);
handled = IRQ_HANDLED;
}
@@ -1842,7 +1842,7 @@ static irqreturn_t dc395x_interrupt(int irq, void *dev_id)
static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
- dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->serial_number);
if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT))
*pscsi_status = PH_BUS_FREE; /*.. initial phase */
@@ -1856,18 +1856,18 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
{
u16 i;
u8 *ptr;
- dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->serial_number);
clear_fifo(acb, "msgout_phase1");
if (!(srb->state & SRB_MSGOUT)) {
srb->state |= SRB_MSGOUT;
dprintkl(KERN_DEBUG,
"msgout_phase1: (pid#%li) Phase unexpected\n",
- srb->cmd->pid); /* So what ? */
+ srb->cmd->serial_number); /* So what ? */
}
if (!srb->msg_count) {
dprintkdbg(DBG_0, "msgout_phase1: (pid#%li) NOP msg\n",
- srb->cmd->pid);
+ srb->cmd->serial_number);
DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP);
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */
DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
@@ -1887,7 +1887,7 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
- dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->serial_number);
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
}
@@ -1898,7 +1898,7 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
struct DeviceCtlBlk *dcb;
u8 *ptr;
u16 i;
- dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->serial_number);
clear_fifo(acb, "command_phase1");
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN);
@@ -2042,7 +2042,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 scsi_status = *pscsi_status;
u32 d_left_counter = 0;
dprintkdbg(DBG_0, "data_out_phase0: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
/*
* KG: We need to drain the buffers before we draw any conclusions!
@@ -2172,7 +2172,7 @@ static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "data_out_phase1: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
clear_fifo(acb, "data_out_phase1");
/* do prepare before transfer when data out phase */
data_io_transfer(acb, srb, XFERDATAOUT);
@@ -2184,7 +2184,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 scsi_status = *pscsi_status;
dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
/*
* KG: DataIn is much more tricky than DataOut. When the device is finished
@@ -2205,7 +2205,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
if (scsi_status & PARITYERROR) {
dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) "
- "Parity Error\n", srb->cmd->pid);
+ "Parity Error\n", srb->cmd->serial_number);
srb->status |= PARITY_ERROR;
}
/*
@@ -2395,7 +2395,7 @@ static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "data_in_phase1: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
data_io_transfer(acb, srb, XFERDATAIN);
}
@@ -2407,7 +2407,7 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
u8 bval;
dprintkdbg(DBG_0,
"data_io_transfer: (pid#%li) <%02i-%i> %c len=%i, sg=(%i/%i)\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun,
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun,
((io_dir & DMACMD_DIR) ? 'r' : 'w'),
srb->total_xfer_length, srb->sg_index, srb->sg_count);
if (srb == acb->tmp_srb)
@@ -2580,7 +2580,7 @@ static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "status_phase0: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); /* get message */
srb->state = SRB_COMPLETED;
@@ -2594,7 +2594,7 @@ static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
dprintkdbg(DBG_0, "status_phase1: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+ srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
srb->state = SRB_STATUS;
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */
DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP);
@@ -2636,7 +2636,7 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
struct ScsiReqBlk *srb = NULL;
struct ScsiReqBlk *i;
dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) tag=%i srb=%p\n",
- srb->cmd->pid, tag, srb);
+ srb->cmd->serial_number, tag, srb);
if (!(dcb->tag_mask & (1 << tag)))
dprintkl(KERN_DEBUG,
@@ -2655,7 +2655,7 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
goto mingx0;
dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) <%02i-%i>\n",
- srb->cmd->pid, srb->dcb->target_id, srb->dcb->target_lun);
+ srb->cmd->serial_number, srb->dcb->target_id, srb->dcb->target_lun);
if (dcb->flag & ABORT_DEV_) {
/*srb->state = SRB_ABORT_SENT; */
enable_msgout_abort(acb, srb);
@@ -2865,7 +2865,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
struct DeviceCtlBlk *dcb = acb->active_dcb;
- dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->serial_number);
srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
if (msgin_completed(srb->msgin_buf, acb->msg_len)) {
@@ -2933,7 +2933,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
*/
dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) "
"SAVE POINTER rem=%i Ignore\n",
- srb->cmd->pid, srb->total_xfer_length);
+ srb->cmd->serial_number, srb->total_xfer_length);
break;
case RESTORE_POINTERS:
@@ -2943,7 +2943,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
case ABORT:
dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) "
"<%02i-%i> ABORT msg\n",
- srb->cmd->pid, dcb->target_id,
+ srb->cmd->serial_number, dcb->target_id,
dcb->target_lun);
dcb->flag |= ABORT_DEV_;
enable_msgout_abort(acb, srb);
@@ -2975,7 +2975,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
- dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->serial_number);
clear_fifo(acb, "msgin_phase1");
DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
if (!(srb->state & SRB_MSGIN)) {
@@ -3041,7 +3041,7 @@ static void disconnect(struct AdapterCtlBlk *acb)
}
srb = dcb->active_srb;
acb->active_dcb = NULL;
- dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->pid);
+ dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->serial_number);
srb->scsi_phase = PH_BUS_FREE; /* initial phase */
clear_fifo(acb, "disconnect");
@@ -3072,13 +3072,13 @@ static void disconnect(struct AdapterCtlBlk *acb)
srb->state = SRB_READY;
dprintkl(KERN_DEBUG,
"disconnect: (pid#%li) Unexpected\n",
- srb->cmd->pid);
+ srb->cmd->serial_number);
srb->target_status = SCSI_STAT_SEL_TIMEOUT;
goto disc1;
} else {
/* Normal selection timeout */
dprintkdbg(DBG_KG, "disconnect: (pid#%li) "
- "<%02i-%i> SelTO\n", srb->cmd->pid,
+ "<%02i-%i> SelTO\n", srb->cmd->serial_number,
dcb->target_id, dcb->target_lun);
if (srb->retry_count++ > DC395x_MAX_RETRIES
|| acb->scan_devices) {
@@ -3090,7 +3090,7 @@ static void disconnect(struct AdapterCtlBlk *acb)
srb_going_to_waiting_move(dcb, srb);
dprintkdbg(DBG_KG,
"disconnect: (pid#%li) Retry\n",
- srb->cmd->pid);
+ srb->cmd->serial_number);
waiting_set_timer(acb, HZ / 20);
}
} else if (srb->state & SRB_DISCONNECT) {
@@ -3144,7 +3144,7 @@ static void reselect(struct AdapterCtlBlk *acb)
if (!acb->scan_devices) {
dprintkdbg(DBG_KG, "reselect: (pid#%li) <%02i-%i> "
"Arb lost but Resel win rsel=%i stat=0x%04x\n",
- srb->cmd->pid, dcb->target_id,
+ srb->cmd->serial_number, dcb->target_id,
dcb->target_lun, rsel_tar_lun_id,
DC395x_read16(acb, TRM_S1040_SCSI_STATUS));
arblostflag = 1;
@@ -3318,7 +3318,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
enum dma_data_direction dir = cmd->sc_data_direction;
int ckc_only = 1;
- dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->pid,
+ dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->serial_number,
srb->cmd->device->id, srb->cmd->device->lun);
dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n",
srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count,
@@ -3499,7 +3499,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
if (srb->total_xfer_length)
dprintkdbg(DBG_KG, "srb_done: (pid#%li) <%02i-%i> "
"cmnd=0x%02x Missed %i bytes\n",
- cmd->pid, cmd->device->id, cmd->device->lun,
+ cmd->serial_number, cmd->device->id, cmd->device->lun,
cmd->cmnd[0], srb->total_xfer_length);
}
@@ -3509,7 +3509,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n");
else {
dprintkdbg(DBG_0, "srb_done: (pid#%li) done result=0x%08x\n",
- cmd->pid, cmd->result);
+ cmd->serial_number, cmd->result);
srb_free_insert(acb, srb);
}
pci_unmap_srb(acb, srb);
@@ -3538,7 +3538,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
p = srb->cmd;
dir = p->sc_data_direction;
result = MK_RES(0, did_flag, 0, 0);
- printk("G:%li(%02i-%i) ", p->pid,
+ printk("G:%li(%02i-%i) ", p->serial_number,
p->device->id, p->device->lun);
srb_going_remove(dcb, srb);
free_tag(dcb, srb);
@@ -3568,7 +3568,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
p = srb->cmd;
result = MK_RES(0, did_flag, 0, 0);
- printk("W:%li<%02i-%i>", p->pid, p->device->id,
+ printk("W:%li<%02i-%i>", p->serial_number, p->device->id,
p->device->lun);
srb_waiting_remove(dcb, srb);
srb_free_insert(acb, srb);
@@ -3678,7 +3678,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
{
struct scsi_cmnd *cmd = srb->cmd;
dprintkdbg(DBG_1, "request_sense: (pid#%li) <%02i-%i>\n",
- cmd->pid, cmd->device->id, cmd->device->lun);
+ cmd->serial_number, cmd->device->id, cmd->device->lun);
srb->flag |= AUTO_REQSENSE;
srb->adapter_status = 0;
@@ -3709,7 +3709,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
if (start_scsi(acb, dcb, srb)) { /* Should only happen, if sb. else grabs the bus */
dprintkl(KERN_DEBUG,
"request_sense: (pid#%li) failed <%02i-%i>\n",
- srb->cmd->pid, dcb->target_id, dcb->target_lun);
+ srb->cmd->serial_number, dcb->target_id, dcb->target_lun);
srb_going_to_waiting_move(dcb, srb);
waiting_set_timer(acb, HZ / 100);
}
@@ -4579,7 +4579,7 @@ static void adapter_uninit_chip(struct AdapterCtlBlk *acb)
if (acb->config & HCC_SCSI_RESET)
reset_scsi_bus(acb);
- /* clear any pending interupt state */
+ /* clear any pending interrupt state */
DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
}
@@ -4717,13 +4717,13 @@ static int dc395x_proc_info(struct Scsi_Host *host, char *buffer,
dcb->target_id, dcb->target_lun,
list_size(&dcb->srb_waiting_list));
list_for_each_entry(srb, &dcb->srb_waiting_list, list)
- SPRINTF(" %li", srb->cmd->pid);
+ SPRINTF(" %li", srb->cmd->serial_number);
if (!list_empty(&dcb->srb_going_list))
SPRINTF("\nDCB (%02i-%i): Going : %i:",
dcb->target_id, dcb->target_lun,
list_size(&dcb->srb_going_list));
list_for_each_entry(srb, &dcb->srb_going_list, list)
- SPRINTF(" %li", srb->cmd->pid);
+ SPRINTF(" %li", srb->cmd->serial_number);
if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list))
SPRINTF("\n");
}
@@ -4765,6 +4765,7 @@ static struct scsi_host_template dc395x_driver_template = {
.eh_bus_reset_handler = dc395x_eh_bus_reset,
.unchecked_isa_dma = 0,
.use_clustering = DISABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 502732ac270..8258506ba7d 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -949,16 +949,14 @@ static int adpt_install_hba(struct pci_dev* pDev)
}
// Allocate and zero the data structure
- pHba = kmalloc(sizeof(adpt_hba), GFP_KERNEL);
- if( pHba == NULL) {
- if(msg_addr_virt != base_addr_virt){
+ pHba = kzalloc(sizeof(adpt_hba), GFP_KERNEL);
+ if (!pHba) {
+ if (msg_addr_virt != base_addr_virt)
iounmap(msg_addr_virt);
- }
iounmap(base_addr_virt);
pci_release_regions(pDev);
return -ENOMEM;
}
- memset(pHba, 0, sizeof(adpt_hba));
mutex_lock(&adpt_configuration_lock);
@@ -2622,14 +2620,13 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
msg=(u32 __iomem *)(pHba->msg_addr_virt+m);
- status = kmalloc(4,GFP_KERNEL|ADDR32);
- if (status==NULL) {
+ status = kzalloc(4, GFP_KERNEL|ADDR32);
+ if (!status) {
adpt_send_nop(pHba, m);
printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n",
pHba->name);
return -ENOMEM;
}
- memset(status, 0, 4);
writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]);
writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]);
@@ -2668,12 +2665,11 @@ static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
kfree(pHba->reply_pool);
- pHba->reply_pool = kmalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32);
- if(!pHba->reply_pool){
- printk(KERN_ERR"%s: Could not allocate reply pool\n",pHba->name);
- return -1;
+ pHba->reply_pool = kzalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32);
+ if (!pHba->reply_pool) {
+ printk(KERN_ERR "%s: Could not allocate reply pool\n", pHba->name);
+ return -ENOMEM;
}
- memset(pHba->reply_pool, 0 , pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4);
ptr = pHba->reply_pool;
for(i = 0; i < pHba->reply_fifo_size; i++) {
@@ -2884,12 +2880,11 @@ static int adpt_i2o_build_sys_table(void)
kfree(sys_tbl);
- sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL|ADDR32);
- if(!sys_tbl) {
+ sys_tbl = kzalloc(sys_tbl_len, GFP_KERNEL|ADDR32);
+ if (!sys_tbl) {
printk(KERN_WARNING "SysTab Set failed. Out of memory.\n");
return -ENOMEM;
}
- memset(sys_tbl, 0, sys_tbl_len);
sys_tbl->num_entries = hba_count;
sys_tbl->version = I2OVERSION;
@@ -3300,6 +3295,7 @@ static struct scsi_host_template adpt_template = {
.this_id = 7,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
static s32 adpt_scsi_register(adpt_hba* pHba)
@@ -3351,7 +3347,7 @@ static int __init adpt_init(void)
return count > 0 ? 0 : -ENODEV;
}
-static void __exit adpt_exit(void)
+static void adpt_exit(void)
{
while (hba_chain)
adpt_release(hba_chain);
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index 9d52e45c7d3..2596165096d 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -137,11 +137,9 @@ static struct override {
#ifdef OVERRIDE
[] __initdata = OVERRIDE;
#else
-[4] __initdata = { {
-0, IRQ_AUTO}, {
-0, IRQ_AUTO}, {
-0, IRQ_AUTO}, {
-0, IRQ_AUTO}};
+[4] __initdata = {
+ { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO }
+};
#endif
#define NO_OVERRIDES ARRAY_SIZE(overrides)
@@ -176,7 +174,7 @@ static const struct signature {
* Inputs : str - unused, ints - array of integer parameters with ints[0]
* equal to the number of ints.
*
-*/
+ */
static void __init dtc_setup(char *str, int *ints)
{
@@ -233,7 +231,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
} else
for (; !addr && (current_base < NO_BASES); ++current_base) {
#if (DTCDEBUG & DTCDEBUG_INIT)
- printk("scsi-dtc : probing address %08x\n", bases[current_base].address);
+ printk(KERN_DEBUG "scsi-dtc : probing address %08x\n", bases[current_base].address);
#endif
if (bases[current_base].noauto)
continue;
@@ -244,7 +242,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
if (check_signature(base + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) {
addr = bases[current_base].address;
#if (DTCDEBUG & DTCDEBUG_INIT)
- printk("scsi-dtc : detected board.\n");
+ printk(KERN_DEBUG "scsi-dtc : detected board.\n");
#endif
goto found;
}
@@ -253,7 +251,7 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
}
#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
- printk("scsi-dtc : base = %08x\n", addr);
+ printk(KERN_DEBUG "scsi-dtc : base = %08x\n", addr);
#endif
if (!addr)
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index a83e9f150b9..7ead5210de9 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -523,7 +523,8 @@ static struct scsi_host_template driver_template = {
.slave_configure = eata2x_slave_configure,
.this_id = 7,
.unchecked_isa_dma = 1,
- .use_clustering = ENABLE_CLUSTERING
+ .use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD)
@@ -1758,7 +1759,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
if (SCpnt->host_scribble)
panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
- ha->board_name, SCpnt->pid, SCpnt);
+ ha->board_name, SCpnt->serial_number, SCpnt);
/* i is the mailbox number, look for the first free mailbox
starting from last_cp_used */
@@ -1792,7 +1793,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
if (do_trace)
scmd_printk(KERN_INFO, SCpnt,
- "qcomm, mbox %d, pid %ld.\n", i, SCpnt->pid);
+ "qcomm, mbox %d, pid %ld.\n", i, SCpnt->serial_number);
cpp->reqsen = 1;
cpp->dispri = 1;
@@ -1825,7 +1826,7 @@ static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
unmap_dma(i, ha);
SCpnt->host_scribble = NULL;
scmd_printk(KERN_INFO, SCpnt,
- "qcomm, pid %ld, adapter busy.\n", SCpnt->pid);
+ "qcomm, pid %ld, adapter busy.\n", SCpnt->serial_number);
return 1;
}
@@ -1841,13 +1842,13 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg)
if (SCarg->host_scribble == NULL) {
scmd_printk(KERN_INFO, SCarg,
- "abort, pid %ld inactive.\n", SCarg->pid);
+ "abort, pid %ld inactive.\n", SCarg->serial_number);
return SUCCESS;
}
i = *(unsigned int *)SCarg->host_scribble;
scmd_printk(KERN_WARNING, SCarg,
- "abort, mbox %d, pid %ld.\n", i, SCarg->pid);
+ "abort, mbox %d, pid %ld.\n", i, SCarg->serial_number);
if (i >= shost->can_queue)
panic("%s: abort, invalid SCarg->host_scribble.\n", ha->board_name);
@@ -1892,7 +1893,7 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg)
SCarg->host_scribble = NULL;
ha->cp_stat[i] = FREE;
printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
- ha->board_name, i, SCarg->pid);
+ ha->board_name, i, SCarg->serial_number);
SCarg->scsi_done(SCarg);
return SUCCESS;
}
@@ -1909,12 +1910,12 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
struct hostdata *ha = (struct hostdata *)shost->hostdata;
scmd_printk(KERN_INFO, SCarg,
- "reset, enter, pid %ld.\n", SCarg->pid);
+ "reset, enter, pid %ld.\n", SCarg->serial_number);
spin_lock_irq(shost->host_lock);
if (SCarg->host_scribble == NULL)
- printk("%s: reset, pid %ld inactive.\n", ha->board_name, SCarg->pid);
+ printk("%s: reset, pid %ld inactive.\n", ha->board_name, SCarg->serial_number);
if (ha->in_reset) {
printk("%s: reset, exit, already in reset.\n", ha->board_name);
@@ -1954,13 +1955,13 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) {
ha->cp_stat[i] = ABORTING;
printk("%s: reset, mbox %d aborting, pid %ld.\n",
- ha->board_name, i, SCpnt->pid);
+ ha->board_name, i, SCpnt->serial_number);
}
else {
ha->cp_stat[i] = IN_RESET;
printk("%s: reset, mbox %d in reset, pid %ld.\n",
- ha->board_name, i, SCpnt->pid);
+ ha->board_name, i, SCpnt->serial_number);
}
if (SCpnt->host_scribble == NULL)
@@ -2015,7 +2016,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
printk
("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
- ha->board_name, i, SCpnt->pid);
+ ha->board_name, i, SCpnt->serial_number);
}
else if (ha->cp_stat[i] == ABORTING) {
@@ -2029,7 +2030,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
printk
("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
- ha->board_name, i, SCpnt->pid);
+ ha->board_name, i, SCpnt->serial_number);
}
else
@@ -2043,7 +2044,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
do_trace = 0;
if (arg_done)
- printk("%s: reset, exit, pid %ld done.\n", ha->board_name, SCarg->pid);
+ printk("%s: reset, exit, pid %ld done.\n", ha->board_name, SCarg->serial_number);
else
printk("%s: reset, exit.\n", ha->board_name);
@@ -2182,7 +2183,7 @@ static int reorder(struct hostdata *ha, unsigned long cursec,
cpp = &ha->cp[k];
SCpnt = cpp->SCpnt;
ll[n] = SCpnt->request->nr_sectors;
- pl[n] = SCpnt->pid;
+ pl[n] = SCpnt->serial_number;
if (!n)
continue;
@@ -2230,7 +2231,7 @@ static int reorder(struct hostdata *ha, unsigned long cursec,
"%s pid %ld mb %d fc %d nr %d sec %ld ns %ld"
" cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
(ihdlr ? "ihdlr" : "qcomm"),
- SCpnt->pid, k, flushcount,
+ SCpnt->serial_number, k, flushcount,
n_ready, SCpnt->request->sector,
SCpnt->request->nr_sectors, cursec, YESNO(s),
YESNO(r), YESNO(rev), YESNO(input_only),
@@ -2277,7 +2278,7 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec,
"%s, pid %ld, mbox %d, adapter"
" busy, will abort.\n",
(ihdlr ? "ihdlr" : "qcomm"),
- SCpnt->pid, k);
+ SCpnt->serial_number, k);
ha->cp_stat[k] = ABORTING;
continue;
}
@@ -2391,11 +2392,11 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
if (SCpnt->host_scribble == NULL)
panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", ha->board_name,
- i, SCpnt->pid, SCpnt);
+ i, SCpnt->serial_number, SCpnt);
if (*(unsigned int *)SCpnt->host_scribble != i)
panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
- ha->board_name, i, SCpnt->pid,
+ ha->board_name, i, SCpnt->serial_number,
*(unsigned int *)SCpnt->host_scribble);
sync_dma(i, ha);
@@ -2445,12 +2446,12 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
"target_status 0x%x, sense key 0x%x.\n",
ha->board_name,
SCpnt->device->channel, SCpnt->device->id,
- SCpnt->device->lun, SCpnt->pid,
+ SCpnt->device->lun, SCpnt->serial_number,
spp->target_status, SCpnt->sense_buffer[2]);
ha->target_to[SCpnt->device->id][SCpnt->device->channel] = 0;
- if (ha->last_retried_pid == SCpnt->pid)
+ if (ha->last_retried_pid == SCpnt->serial_number)
ha->retries = 0;
break;
@@ -2485,7 +2486,7 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
#endif
ha->retries++;
- ha->last_retried_pid = SCpnt->pid;
+ ha->last_retried_pid = SCpnt->serial_number;
} else
status = DID_ERROR << 16;
@@ -2516,7 +2517,7 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"
" pid %ld, reg 0x%x, count %d.\n",
i, spp->adapter_status, spp->target_status,
- SCpnt->pid, reg, ha->iocount);
+ SCpnt->serial_number, reg, ha->iocount);
unmap_dma(i, ha);
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index f33ad01064a..982c5092be1 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -107,59 +107,44 @@ static struct scsi_host_template driver_template;
static int eata_pio_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset,
int length, int rw)
{
- static u8 buff[512];
- int size, len = 0;
- off_t begin = 0, pos = 0;
+ int len = 0;
+ off_t begin = 0, pos = 0;
- if (rw)
- return -ENOSYS;
- if (offset == 0)
- memset(buff, 0, sizeof(buff));
+ if (rw)
+ return -ENOSYS;
- size = sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: "
+ len += sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: "
"%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
- len += size; pos = begin + len;
- size = sprintf(buffer + len, "queued commands: %10ld\n"
+ len += sprintf(buffer + len, "queued commands: %10ld\n"
"processed interrupts:%10ld\n", queue_counter, int_counter);
- len += size; pos = begin + len;
-
- size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
+ len += sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
shost->host_no, SD(shost)->name);
- len += size;
- pos = begin + len;
- size = sprintf(buffer + len, "Firmware revision: v%s\n",
+ len += sprintf(buffer + len, "Firmware revision: v%s\n",
SD(shost)->revision);
- len += size;
- pos = begin + len;
- size = sprintf(buffer + len, "IO: PIO\n");
- len += size;
- pos = begin + len;
- size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) shost->base);
- len += size;
- pos = begin + len;
- size = sprintf(buffer + len, "Host Bus: %s\n",
+ len += sprintf(buffer + len, "IO: PIO\n");
+ len += sprintf(buffer + len, "Base IO : %#.4x\n", (u32) shost->base);
+ len += sprintf(buffer + len, "Host Bus: %s\n",
(SD(shost)->bustype == 'P')?"PCI ":
(SD(shost)->bustype == 'E')?"EISA":"ISA ");
- len += size;
- pos = begin + len;
+ pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
- stop_output:
- DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
- *start=buffer+(offset-begin); /* Start of wanted data */
- len-=(offset-begin); /* Start slop */
- if(len>length)
- len = length; /* Ending slop */
- DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
+stop_output:
+ DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin); /* Start slop */
+ if (len > length)
+ len = length; /* Ending slop */
+ DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
- return (len);
+ return len;
}
static int eata_pio_release(struct Scsi_Host *sh)
@@ -187,7 +172,7 @@ static void IncStat(struct scsi_pointer *SCp, unsigned int Increment)
SCp->Status = 0;
else {
SCp->buffer++;
- SCp->ptr = page_address(SCp->buffer->page) + SCp->buffer->offset;
+ SCp->ptr = sg_virt(SCp->buffer);
SCp->this_residual = SCp->buffer->length;
}
}
@@ -390,7 +375,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd,
"eata_pio_queue pid %ld, y %d\n",
- cmd->pid, y));
+ cmd->serial_number, y));
cmd->scsi_done = (void *) done;
@@ -425,7 +410,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
} else {
cmd->SCp.buffer = cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg;
- cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
cmd->SCp.this_residual = cmd->SCp.buffer->length;
}
cmd->SCp.Status = (cmd->SCp.this_residual != 0); /* TRUE as long as bytes
@@ -435,10 +420,10 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
cmd->result = DID_BUS_BUSY << 16;
scmd_printk(KERN_NOTICE, cmd,
"eata_pio_queue pid %ld, HBA busy, "
- "returning DID_BUS_BUSY, done.\n", cmd->pid);
+ "returning DID_BUS_BUSY, done.\n", cmd->serial_number);
done(cmd);
cp->status = FREE;
- return (0);
+ return 0;
}
/* FIXME: timeout */
while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
@@ -450,9 +435,9 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd,
"Queued base %#.4lx pid: %ld "
- "slot %d irq %d\n", sh->base, cmd->pid, y, sh->irq));
+ "slot %d irq %d\n", sh->base, cmd->serial_number, y, sh->irq));
- return (0);
+ return 0;
}
static int eata_pio_abort(struct scsi_cmnd *cmd)
@@ -461,7 +446,7 @@ static int eata_pio_abort(struct scsi_cmnd *cmd)
DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd,
"eata_pio_abort called pid: %ld\n",
- cmd->pid));
+ cmd->serial_number));
while (inb(cmd->device->host->base + HA_RAUXSTAT) & HA_ABUSY)
if (--loop == 0) {
@@ -497,7 +482,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd)
DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd,
"eata_pio_reset called pid:%ld\n",
- cmd->pid));
+ cmd->serial_number));
spin_lock_irq(host->host_lock);
@@ -516,7 +501,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd)
sp = HD(cmd)->ccb[x].cmd;
HD(cmd)->ccb[x].status = RESET;
- printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
+ printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->serial_number);
if (sp == NULL)
panic("eata_pio_reset: slot %d, sp==NULL.\n", x);
@@ -589,23 +574,28 @@ static char *get_pio_board_data(unsigned long base, unsigned int irq, unsigned i
cp.cp_cdb[5] = 0;
if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP))
- return (NULL);
- while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
+ return NULL;
+
+ while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
+ cpu_relax();
+
outsw(base + HA_RDATA, &cp, cplen);
outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
for (z = 0; z < cppadlen; z++)
outw(0, base + HA_RDATA);
- while (inb(base + HA_RSTATUS) & HA_SBUSY);
+ while (inb(base + HA_RSTATUS) & HA_SBUSY)
+ cpu_relax();
+
if (inb(base + HA_RSTATUS) & HA_SERROR)
- return (NULL);
+ return NULL;
else if (!(inb(base + HA_RSTATUS) & HA_SDRQ))
- return (NULL);
+ return NULL;
else {
insw(base + HA_RDATA, &buff, 127);
while (inb(base + HA_RSTATUS) & HA_SDRQ)
inw(base + HA_RDATA);
- return (buff);
+ return buff;
}
}
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 95cf7b6cd62..4ed3a529706 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -2138,7 +2138,7 @@ irqreturn_t scsi_esp_intr(int irq, void *dev_id)
}
EXPORT_SYMBOL(scsi_esp_intr);
-static void __devinit esp_get_revision(struct esp *esp)
+static void esp_get_revision(struct esp *esp)
{
u8 val;
@@ -2187,7 +2187,7 @@ static void __devinit esp_get_revision(struct esp *esp)
}
}
-static void __devinit esp_init_swstate(struct esp *esp)
+static void esp_init_swstate(struct esp *esp)
{
int i;
@@ -2233,7 +2233,7 @@ static void esp_bootup_reset(struct esp *esp)
esp_read8(ESP_INTRPT);
}
-static void __devinit esp_set_clock_params(struct esp *esp)
+static void esp_set_clock_params(struct esp *esp)
{
int fmhz;
u8 ccf;
@@ -2306,7 +2306,7 @@ static const char *esp_chip_names[] = {
static struct scsi_transport_template *esp_transport_template;
-int __devinit scsi_esp_register(struct esp *esp, struct device *dev)
+int scsi_esp_register(struct esp *esp, struct device *dev)
{
static int instance;
int err;
@@ -2346,7 +2346,7 @@ int __devinit scsi_esp_register(struct esp *esp, struct device *dev)
}
EXPORT_SYMBOL(scsi_esp_register);
-void __devexit scsi_esp_unregister(struct esp *esp)
+void scsi_esp_unregister(struct esp *esp)
{
scsi_remove_host(esp->host);
}
diff --git a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c
deleted file mode 100644
index c4e16c0775d..00000000000
--- a/drivers/scsi/fcal.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/* fcal.c: Fibre Channel Arbitrated Loop SCSI host adapter driver.
- *
- * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-#ifdef CONFIG_KMOD
-#include <linux/kmod.h>
-#endif
-
-#include <asm/irq.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "../fc4/fcp_impl.h"
-#include "fcal.h"
-
-#include <linux/module.h>
-
-/* #define FCAL_DEBUG */
-
-#define fcal_printk printk ("FCAL %s: ", fc->name); printk
-
-#ifdef FCAL_DEBUG
-#define FCALD(x) fcal_printk x;
-#define FCALND(x) printk ("FCAL: "); printk x;
-#else
-#define FCALD(x)
-#define FCALND(x)
-#endif
-
-static unsigned char alpa2target[] = {
-0x7e, 0x7d, 0x7c, 0xff, 0x7b, 0xff, 0xff, 0xff, 0x7a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79,
-0x78, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x76, 0xff, 0xff, 0x75, 0xff, 0x74, 0x73, 0x72,
-0xff, 0xff, 0xff, 0x71, 0xff, 0x70, 0x6f, 0x6e, 0xff, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0xff,
-0xff, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0xff, 0xff, 0x61, 0x60, 0xff, 0x5f, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0x5e, 0xff, 0x5d, 0x5c, 0x5b, 0xff, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0xff,
-0xff, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0xff, 0xff, 0x4e, 0x4d, 0xff, 0x4c, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0x4b, 0xff, 0x4a, 0x49, 0x48, 0xff, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0xff,
-0xff, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0xff, 0xff, 0x3b, 0x3a, 0xff, 0x39, 0xff, 0xff, 0xff,
-0x38, 0x37, 0x36, 0xff, 0x35, 0xff, 0xff, 0xff, 0x34, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x33,
-0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x30, 0xff, 0xff, 0x2f, 0xff, 0x2e, 0x2d, 0x2c,
-0xff, 0xff, 0xff, 0x2b, 0xff, 0x2a, 0x29, 0x28, 0xff, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0xff,
-0xff, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0xff, 0xff, 0x1b, 0x1a, 0xff, 0x19, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0x18, 0xff, 0x17, 0x16, 0x15, 0xff, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0xff,
-0xff, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0xff, 0xff, 0x08, 0x07, 0xff, 0x06, 0xff, 0xff, 0xff,
-0x05, 0x04, 0x03, 0xff, 0x02, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
-};
-
-static unsigned char target2alpa[] = {
-0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce,
-0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5, 0xb4, 0xb3,
-0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b,
-0x98, 0x97, 0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79, 0x76, 0x75, 0x74, 0x73,
-0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
-0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x47, 0x46, 0x45, 0x43, 0x3c,
-0x3a, 0x39, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x27, 0x26,
-0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17, 0x10, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x00
-};
-
-static int fcal_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd);
-
-int fcal_slave_configure(struct scsi_device *device)
-{
- int depth_to_use;
-
- if (device->tagged_supported)
- depth_to_use = /* 254 */ 8;
- else
- depth_to_use = 2;
-
- scsi_adjust_queue_depth(device,
- (device->tagged_supported ?
- MSG_SIMPLE_TAG : 0),
- depth_to_use);
-
- return 0;
-}
-
-/* Detect all FC Arbitrated Loops attached to the machine.
- fc4 module has done all the work for us... */
-int __init fcal_detect(struct scsi_host_template *tpnt)
-{
- int nfcals = 0;
- fc_channel *fc;
- int fcalcount;
- int i;
-
- tpnt->proc_name = "fcal";
- fcalcount = 0;
- for_each_online_fc_channel(fc)
- if (fc->posmap)
- fcalcount++;
- FCALND(("%d channels online\n", fcalcount))
- if (!fcalcount) {
-#if defined(MODULE) && defined(CONFIG_FC4_SOCAL_MODULE) && defined(CONFIG_KMOD)
- request_module("socal");
-
- for_each_online_fc_channel(fc)
- if (fc->posmap)
- fcalcount++;
- if (!fcalcount)
-#endif
- return 0;
- }
- for_each_online_fc_channel(fc) {
- struct Scsi_Host *host;
- long *ages;
- struct fcal *fcal;
-
- if (!fc->posmap) continue;
-
- /* Strange, this is already registered to some other SCSI host, then it cannot be fcal */
- if (fc->scsi_name[0]) continue;
- memcpy (fc->scsi_name, "FCAL", 4);
-
- fc->can_queue = FCAL_CAN_QUEUE;
- fc->rsp_size = 64;
- fc->encode_addr = fcal_encode_addr;
-
- ages = kmalloc (128 * sizeof(long), GFP_KERNEL);
- if (!ages) continue;
-
- host = scsi_register (tpnt, sizeof (struct fcal));
- if (!host)
- {
- kfree(ages);
- continue;
- }
-
- if (!try_module_get(fc->module)) {
- kfree(ages);
- scsi_unregister(host);
- continue;
- }
-
- nfcals++;
-
- fcal = (struct fcal *)host->hostdata;
-
- fc->fcp_register(fc, TYPE_SCSI_FCP, 0);
-
- for (i = 0; i < fc->posmap->len; i++) {
- int status, target, alpa;
-
- alpa = fc->posmap->list[i];
- FCALD(("Sending PLOGI to %02x\n", alpa))
- target = alpa2target[alpa];
- status = fc_do_plogi(fc, alpa, fcal->node_wwn + target,
- fcal->nport_wwn + target);
- FCALD(("PLOGI returned with status %d\n", status))
- if (status != FC_STATUS_OK)
- continue;
- FCALD(("Sending PRLI to %02x\n", alpa))
- status = fc_do_prli(fc, alpa);
- FCALD(("PRLI returned with status %d\n", status))
- if (status == FC_STATUS_OK)
- fcal->map[target] = 1;
- }
-
- host->max_id = 127;
- host->irq = fc->irq;
-#ifdef __sparc_v9__
- host->unchecked_isa_dma = 1;
-#endif
-
- fc->channels = 1;
- fc->targets = 127;
- fc->ages = ages;
- memset (ages, 0, 128 * sizeof(long));
-
- fcal->fc = fc;
-
- FCALD(("Found FCAL\n"))
- }
- if (nfcals)
-#ifdef __sparc__
- printk ("FCAL: Total of %d Sun Enterprise Network Array (A5000 or EX500) channels found\n", nfcals);
-#else
- printk ("FCAL: Total of %d Fibre Channel Arbitrated Loops found\n", nfcals);
-#endif
- return nfcals;
-}
-
-int fcal_release(struct Scsi_Host *host)
-{
- struct fcal *fcal = (struct fcal *)host->hostdata;
- fc_channel *fc = fcal->fc;
-
- module_put(fc->module);
-
- fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
- FCALND((" releasing fcal.\n"));
- kfree (fc->ages);
- FCALND(("released fcal!\n"));
- return 0;
-}
-
-#undef SPRINTF
-#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }
-
-int fcal_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout)
-{
- struct fcal *fcal;
- fc_channel *fc;
- char *pos = buffer;
- int i, j;
-
- if (inout) return length;
-
- fcal = (struct fcal *)host->hostdata;
- fc = fcal->fc;
-
-#ifdef __sparc__
- SPRINTF ("Sun Enterprise Network Array (A5000 or E?500) on %s PROM node %x\n", fc->name, fc->dev->prom_node);
-#else
- SPRINTF ("Fibre Channel Arbitrated Loop on %s\n", fc->name);
-#endif
- SPRINTF ("Initiator AL-PA: %02x\n", fc->sid);
-
- SPRINTF ("\nAttached devices:\n");
-
- for (i = 0; i < fc->posmap->len; i++) {
- unsigned char alpa = fc->posmap->list[i];
- unsigned char target;
- u32 *u1, *u2;
-
- target = alpa2target[alpa];
- u1 = (u32 *)&fcal->nport_wwn[target];
- u2 = (u32 *)&fcal->node_wwn[target];
- if (!u1[0] && !u1[1]) {
- SPRINTF (" [AL-PA: %02x] Not responded to PLOGI\n", alpa);
- } else if (!fcal->map[target]) {
- SPRINTF (" [AL-PA: %02x, Port WWN: %08x%08x, Node WWN: %08x%08x] Not responded to PRLI\n",
- alpa, u1[0], u1[1], u2[0], u2[1]);
- } else {
- struct scsi_device *scd;
- shost_for_each_device(scd, host)
- if (scd->id == target) {
- SPRINTF (" [AL-PA: %02x, Id: %02d, Port WWN: %08x%08x, Node WWN: %08x%08x] ",
- alpa, target, u1[0], u1[1], u2[0], u2[1]);
- SPRINTF ("%s ", scsi_device_type(scd->type));
-
- for (j = 0; (j < 8) && (scd->vendor[j] >= 0x20); j++)
- SPRINTF ("%c", scd->vendor[j]);
- SPRINTF (" ");
-
- for (j = 0; (j < 16) && (scd->model[j] >= 0x20); j++)
- SPRINTF ("%c", scd->model[j]);
-
- SPRINTF ("\n");
- }
- }
- }
- SPRINTF ("\n");
-
- *start = buffer + offset;
-
- if ((pos - buffer) < offset)
- return 0;
- else if (pos - buffer - offset < length)
- return pos - buffer - offset;
- else
- return length;
-}
-
-/*
- For FC-AL, we use a simple addressing: we have just one channel 0,
- and all AL-PAs are mapped to targets 0..0x7e
- */
-static int fcal_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd)
-{
- struct fcal *f;
-
- /* We don't support LUNs yet - I'm not sure if LUN should be in SCSI fcp_cdb, or in second byte of addr[0] */
- if (SCpnt->cmnd[1] & 0xe0) return -EINVAL;
- /* FC-PLDA tells us... */
- memset(addr, 0, 8);
- f = (struct fcal *)SCpnt->device->host->hostdata;
- if (!f->map[SCpnt->device->id])
- return -EINVAL;
- /* Now, determine DID: It will be Native Identifier, so we zero upper
- 2 bytes of the 3 byte DID, lowest byte will be AL-PA */
- fcmd->did = target2alpa[SCpnt->device->id];
- FCALD(("trying DID %06x\n", fcmd->did))
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .name = "Fibre Channel Arbitrated Loop",
- .detect = fcal_detect,
- .release = fcal_release,
- .proc_info = fcal_proc_info,
- .queuecommand = fcp_scsi_queuecommand,
- .slave_configure = fcal_slave_configure,
- .can_queue = FCAL_CAN_QUEUE,
- .this_id = -1,
- .sg_tablesize = 1,
- .cmd_per_lun = 1,
- .use_clustering = ENABLE_CLUSTERING,
- .eh_abort_handler = fcp_scsi_abort,
- .eh_device_reset_handler = fcp_scsi_dev_reset,
- .eh_host_reset_handler = fcp_scsi_host_reset,
-};
-#include "scsi_module.c"
-
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/scsi/fcal.h b/drivers/scsi/fcal.h
deleted file mode 100644
index 7ff2c3494f9..00000000000
--- a/drivers/scsi/fcal.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* fcal.h: Generic Fibre Channel Arbitrated Loop SCSI host adapter driver definitions.
- *
- * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
- */
-
-#ifndef _FCAL_H
-#define _FCAL_H
-
-#include "../fc4/fcp_impl.h"
-
-struct fcal {
- /* fc must be first */
- fc_channel *fc;
- unsigned char map[128];
- fc_wwn nport_wwn[128];
- fc_wwn node_wwn[128];
-};
-
-/* Arbitrary constant. Cannot be too large, as fc4 layer has limitations
- for a particular channel */
-#define FCAL_CAN_QUEUE 512
-
-int fcal_detect(struct scsi_host_template *);
-int fcal_release(struct Scsi_Host *);
-int fcal_slave_configure(struct scsi_device *);
-
-#endif /* !(_FCAL_H) */
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
index 668569e8856..8335b608e57 100644
--- a/drivers/scsi/fd_mcs.c
+++ b/drivers/scsi/fd_mcs.c
@@ -973,7 +973,7 @@ static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
if (current_SC->SCp.buffers_residual) {
--current_SC->SCp.buffers_residual;
++current_SC->SCp.buffer;
- current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+ current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
} else
break;
@@ -1006,7 +1006,7 @@ static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
if (!current_SC->SCp.this_residual && current_SC->SCp.buffers_residual) {
--current_SC->SCp.buffers_residual;
++current_SC->SCp.buffer;
- current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+ current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
}
}
@@ -1109,7 +1109,7 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
if (current_SC->use_sg) {
current_SC->SCp.buffer = (struct scatterlist *) current_SC->request_buffer;
- current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+ current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
} else {
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 36169d597e9..2cd6b4959eb 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -387,7 +387,9 @@ static void __iomem * bios_mem;
static int bios_major;
static int bios_minor;
static int PCI_bus;
+#ifdef CONFIG_PCI
static struct pci_dev *PCI_dev;
+#endif
static int Quantum; /* Quantum board variant */
static int interrupt_level;
static volatile int in_command;
@@ -1319,7 +1321,7 @@ static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id)
if (current_SC->SCp.buffers_residual) {
--current_SC->SCp.buffers_residual;
++current_SC->SCp.buffer;
- current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+ current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
} else
break;
@@ -1352,7 +1354,7 @@ static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id)
&& current_SC->SCp.buffers_residual) {
--current_SC->SCp.buffers_residual;
++current_SC->SCp.buffer;
- current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+ current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
}
}
@@ -1437,8 +1439,7 @@ static int fdomain_16x0_queue(struct scsi_cmnd *SCpnt,
if (scsi_sg_count(current_SC)) {
current_SC->SCp.buffer = scsi_sglist(current_SC);
- current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page)
- + current_SC->SCp.buffer->offset;
+ current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1;
} else {
@@ -1764,6 +1765,7 @@ struct scsi_host_template fdomain_driver_template = {
};
#ifndef PCMCIA
+#ifdef CONFIG_PCI
static struct pci_device_id fdomain_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70,
@@ -1771,7 +1773,7 @@ static struct pci_device_id fdomain_pci_tbl[] __devinitdata = {
{ }
};
MODULE_DEVICE_TABLE(pci, fdomain_pci_tbl);
-
+#endif
#define driver_template fdomain_driver_template
#include "scsi_module.c"
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 880f70d24e6..607336f56d5 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -556,7 +556,7 @@ generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev,
}
#endif
-#if NCR53C400_PSEUDO_DMA
+#ifdef NCR53C400_PSEUDO_DMA
/**
* NCR5380_pread - pseudo DMA read
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 55e4d2dc2bb..b253b8c718d 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -27,280 +27,8 @@
* along with this kernel; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
- * Linux kernel 2.4.x, 2.6.x supported *
+ * Linux kernel 2.6.x supported *
* *
- * $Log: gdth.c,v $
- * Revision 1.74 2006/04/10 13:44:47 achim
- * Community changes for 2.6.x
- * Kernel 2.2.x no longer supported
- * scsi_request interface removed, thanks to Christoph Hellwig
- *
- * Revision 1.73 2004/03/31 13:33:03 achim
- * Special command 0xfd implemented to detect 64-bit DMA support
- *
- * Revision 1.72 2004/03/17 08:56:04 achim
- * 64-bit DMA only enabled if FW >= x.43
- *
- * Revision 1.71 2004/03/05 15:51:29 achim
- * Screen service: separate message buffer, bugfixes
- *
- * Revision 1.70 2004/02/27 12:19:07 achim
- * Bugfix: Reset bit in config (0xfe) call removed
- *
- * Revision 1.69 2004/02/20 09:50:24 achim
- * Compatibility changes for kernels < 2.4.20
- * Bugfix screen service command size
- * pci_set_dma_mask() error handling added
- *
- * Revision 1.68 2004/02/19 15:46:54 achim
- * 64-bit DMA bugfixes
- * Drive size bugfix for drives > 1TB
- *
- * Revision 1.67 2004/01/14 13:11:57 achim
- * Tool access over /proc no longer supported
- * Bugfixes IOCTLs
- *
- * Revision 1.66 2003/12/19 15:04:06 achim
- * Bugfixes support for drives > 2TB
- *
- * Revision 1.65 2003/12/15 11:21:56 achim
- * 64-bit DMA support added
- * Support for drives > 2 TB implemented
- * Kernels 2.2.x, 2.4.x, 2.6.x supported
- *
- * Revision 1.64 2003/09/17 08:30:26 achim
- * EISA/ISA controller scan disabled
- * Command line switch probe_eisa_isa added
- *
- * Revision 1.63 2003/07/12 14:01:00 Daniele Bellucci <bellucda@tiscali.it>
- * Minor cleanups in gdth_ioctl.
- *
- * Revision 1.62 2003/02/27 15:01:59 achim
- * Dynamic DMA mapping implemented
- * New (character device) IOCTL interface added
- * Other controller related changes made
- *
- * Revision 1.61 2002/11/08 13:09:52 boji
- * Added support for XSCALE based RAID Controllers
- * Fixed SCREENSERVICE initialization in SMP cases
- * Added checks for gdth_polling before GDTH_HA_LOCK
- *
- * Revision 1.60 2002/02/05 09:35:22 achim
- * MODULE_LICENSE only if kernel >= 2.4.11
- *
- * Revision 1.59 2002/01/30 09:46:33 achim
- * Small changes
- *
- * Revision 1.58 2002/01/29 15:30:02 achim
- * Set default value of shared_access to Y
- * New status S_CACHE_RESERV for clustering added
- *
- * Revision 1.57 2001/08/21 11:16:35 achim
- * Bugfix free_irq()
- *
- * Revision 1.56 2001/08/09 11:19:39 achim
- * Scsi_Host_Template changes
- *
- * Revision 1.55 2001/08/09 10:11:28 achim
- * Command HOST_UNFREEZE_IO before cache service init.
- *
- * Revision 1.54 2001/07/20 13:48:12 achim
- * Expand: gdth_analyse_hdrive() removed
- *
- * Revision 1.53 2001/07/17 09:52:49 achim
- * Small OEM related change
- *
- * Revision 1.52 2001/06/19 15:06:20 achim
- * New host command GDT_UNFREEZE_IO added
- *
- * Revision 1.51 2001/05/22 06:42:37 achim
- * PCI: Subdevice ID added
- *
- * Revision 1.50 2001/05/17 13:42:16 achim
- * Support for Intel Storage RAID Controllers added
- *
- * Revision 1.50 2001/05/17 12:12:34 achim
- * Support for Intel Storage RAID Controllers added
- *
- * Revision 1.49 2001/03/15 15:07:17 achim
- * New __setup interface for boot command line options added
- *
- * Revision 1.48 2001/02/06 12:36:28 achim
- * Bugfix Cluster protocol
- *
- * Revision 1.47 2001/01/10 14:42:06 achim
- * New switch shared_access added
- *
- * Revision 1.46 2001/01/09 08:11:35 achim
- * gdth_command() removed
- * meaning of Scsi_Pointer members changed
- *
- * Revision 1.45 2000/11/16 12:02:24 achim
- * Changes for kernel 2.4
- *
- * Revision 1.44 2000/10/11 08:44:10 achim
- * Clustering changes: New flag media_changed added
- *
- * Revision 1.43 2000/09/20 12:59:01 achim
- * DPMEM remap functions for all PCI controller types implemented
- * Small changes for ia64 platform
- *
- * Revision 1.42 2000/07/20 09:04:50 achim
- * Small changes for kernel 2.4
- *
- * Revision 1.41 2000/07/04 14:11:11 achim
- * gdth_analyse_hdrive() added to rescan drives after online expansion
- *
- * Revision 1.40 2000/06/27 11:24:16 achim
- * Changes Clustering, Screenservice
- *
- * Revision 1.39 2000/06/15 13:09:04 achim
- * Changes for gdth_do_cmd()
- *
- * Revision 1.38 2000/06/15 12:08:43 achim
- * Bugfix gdth_sync_event(), service SCREENSERVICE
- * Data direction for command 0xc2 changed to DOU
- *
- * Revision 1.37 2000/05/25 13:50:10 achim
- * New driver parameter virt_ctr added
- *
- * Revision 1.36 2000/05/04 08:50:46 achim
- * Event buffer now in gdth_ha_str
- *
- * Revision 1.35 2000/03/03 10:44:08 achim
- * New event_string only valid for the RP controller family
- *
- * Revision 1.34 2000/03/02 14:55:29 achim
- * New mechanism for async. event handling implemented
- *
- * Revision 1.33 2000/02/21 15:37:37 achim
- * Bugfix Alpha platform + DPMEM above 4GB
- *
- * Revision 1.32 2000/02/14 16:17:37 achim
- * Bugfix sense_buffer[] + raw devices
- *
- * Revision 1.31 2000/02/10 10:29:00 achim
- * Delete sense_buffer[0], if command OK
- *
- * Revision 1.30 1999/11/02 13:42:39 achim
- * ARRAY_DRV_LIST2 implemented
- * Now 255 log. and 100 host drives supported
- *
- * Revision 1.29 1999/10/05 13:28:47 achim
- * GDT_CLUST_RESET added
- *
- * Revision 1.28 1999/08/12 13:44:54 achim
- * MOUNTALL removed
- * Cluster drives -> removeable drives
- *
- * Revision 1.27 1999/06/22 07:22:38 achim
- * Small changes
- *
- * Revision 1.26 1999/06/10 16:09:12 achim
- * Cluster Host Drive support: Bugfixes
- *
- * Revision 1.25 1999/06/01 16:03:56 achim
- * gdth_init_pci(): Manipulate config. space to start RP controller
- *
- * Revision 1.24 1999/05/26 11:53:06 achim
- * Cluster Host Drive support added
- *
- * Revision 1.23 1999/03/26 09:12:31 achim
- * Default value for hdr_channel set to 0
- *
- * Revision 1.22 1999/03/22 16:27:16 achim
- * Bugfix: gdth_store_event() must not be locked with GDTH_LOCK_HA()
- *
- * Revision 1.21 1999/03/16 13:40:34 achim
- * Problems with reserved drives solved
- * gdth_eh_bus_reset() implemented
- *
- * Revision 1.20 1999/03/10 09:08:13 achim
- * Bugfix: Corrections in gdth_direction_tab[] made
- * Bugfix: Increase command timeout (gdth_update_timeout()) NOT in gdth_putq()
- *
- * Revision 1.19 1999/03/05 14:38:16 achim
- * Bugfix: Heads/Sectors mapping for reserved devices possibly wrong
- * -> gdth_eval_mapping() implemented, changes in gdth_bios_param()
- * INIT_RETRIES set to 100s to avoid DEINIT-Timeout for controllers
- * with BIOS disabled and memory test set to Intensive
- * Enhanced /proc support
- *
- * Revision 1.18 1999/02/24 09:54:33 achim
- * Command line parameter hdr_channel implemented
- * Bugfix for EISA controllers + Linux 2.2.x
- *
- * Revision 1.17 1998/12/17 15:58:11 achim
- * Command line parameters implemented
- * Changes for Alpha platforms
- * PCI controller scan changed
- * SMP support improved (spin_lock_irqsave(),...)
- * New async. events, new scan/reserve commands included
- *
- * Revision 1.16 1998/09/28 16:08:46 achim
- * GDT_PCIMPR: DPMEM remapping, if required
- * mdelay() added
- *
- * Revision 1.15 1998/06/03 14:54:06 achim
- * gdth_delay(), gdth_flush() implemented
- * Bugfix: gdth_release() changed
- *
- * Revision 1.14 1998/05/22 10:01:17 achim
- * mj: pcibios_strerror() removed
- * Improved SMP support (if version >= 2.1.95)
- * gdth_halt(): halt_called flag added (if version < 2.1)
- *
- * Revision 1.13 1998/04/16 09:14:57 achim
- * Reserve drives (for raw service) implemented
- * New error handling code enabled
- * Get controller name from board_info() IOCTL
- * Final round of PCI device driver patches by Martin Mares
- *
- * Revision 1.12 1998/03/03 09:32:37 achim
- * Fibre channel controller support added
- *
- * Revision 1.11 1998/01/27 16:19:14 achim
- * SA_SHIRQ added
- * add_timer()/del_timer() instead of GDTH_TIMER
- * scsi_add_timer()/scsi_del_timer() instead of SCSI_TIMER
- * New error handling included
- *
- * Revision 1.10 1997/10/31 12:29:57 achim
- * Read heads/sectors from host drive
- *
- * Revision 1.9 1997/09/04 10:07:25 achim
- * IO-mapping with virt_to_bus(), gdth_readb(), gdth_writeb(), ...
- * register_reboot_notifier() to get a notify on shutown used
- *
- * Revision 1.8 1997/04/02 12:14:30 achim
- * Version 1.00 (see gdth.h), tested with kernel 2.0.29
- *
- * Revision 1.7 1997/03/12 13:33:37 achim
- * gdth_reset() changed, new async. events
- *
- * Revision 1.6 1997/03/04 14:01:11 achim
- * Shutdown routine gdth_halt() implemented
- *
- * Revision 1.5 1997/02/21 09:08:36 achim
- * New controller included (RP, RP1, RP2 series)
- * IOCTL interface implemented
- *
- * Revision 1.4 1996/07/05 12:48:55 achim
- * Function gdth_bios_param() implemented
- * New constant GDTH_MAXC_P_L inserted
- * GDT_WRITE_THR, GDT_EXT_INFO implemented
- * Function gdth_reset() changed
- *
- * Revision 1.3 1996/05/10 09:04:41 achim
- * Small changes for Linux 1.2.13
- *
- * Revision 1.2 1996/05/09 12:45:27 achim
- * Loadable module support implemented
- * /proc support corrections made
- *
- * Revision 1.1 1996/04/11 07:35:57 achim
- * Initial revision
- *
************************************************************************/
/* All GDT Disk Array Controllers are fully supported by this driver.
@@ -328,8 +56,6 @@
* max_ids:x x - target ID count per channel (1..MAXID)
* rescan:Y rescan all channels/IDs
* rescan:N use all devices found until now
- * virt_ctr:Y map every channel to a virtual controller
- * virt_ctr:N use multi channel support
* hdr_channel:x x - number of virtual bus for host drives
* shared_access:Y disable driver reserve/release protocol to
* access a shared resource from several nodes,
@@ -341,7 +67,7 @@
* force_dma32:N use 64 bit DMA mode, if supported
*
* The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
- * max_ids:127,rescan:N,virt_ctr:N,hdr_channel:0,
+ * max_ids:127,rescan:N,hdr_channel:0,
* shared_access:Y,probe_eisa_isa:N,force_dma32:N".
* Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y".
*
@@ -352,22 +78,22 @@
* '1' in place of 'Y' and '0' in place of 'N'.
*
* Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0
- * max_ids=127 rescan=0 virt_ctr=0 hdr_channel=0 shared_access=0
+ * max_ids=127 rescan=0 hdr_channel=0 shared_access=0
* probe_eisa_isa=0 force_dma32=0"
* The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1".
*/
/* The meaning of the Scsi_Pointer members in this driver is as follows:
* ptr: Chaining
- * this_residual: Command priority
- * buffer: phys. DMA sense buffer
- * dma_handle: phys. DMA buffer (kernel >= 2.4.0)
- * buffers_residual: Timeout value
- * Status: Command status (gdth_do_cmd()), DMA mem. mappings
- * Message: Additional info (gdth_do_cmd()), DMA direction
- * have_data_in: Flag for gdth_wait_completion()
- * sent_command: Opcode special command
- * phase: Service/parameter/return code special command
+ * this_residual: gdth_bufflen
+ * buffer: gdth_sglist
+ * dma_handle: unused
+ * buffers_residual: gdth_sg_count
+ * Status: unused
+ * Message: unused
+ * have_data_in: unused
+ * sent_command: unused
+ * phase: unused
*/
@@ -392,12 +118,8 @@
#include <linux/proc_fs.h>
#include <linux/time.h>
#include <linux/timer.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6)
#include <linux/dma-mapping.h>
-#else
-#define DMA_32BIT_MASK 0x00000000ffffffffULL
-#define DMA_64BIT_MASK 0xffffffffffffffffULL
-#endif
+#include <linux/list.h>
#ifdef GDTH_RTC
#include <linux/mc146818rtc.h>
@@ -409,29 +131,27 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/spinlock.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
#include <linux/blkdev.h>
-#else
-#include <linux/blk.h>
-#include "sd.h"
-#endif
+#include <linux/scatterlist.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
-#include "gdth_kcompat.h"
#include "gdth.h"
static void gdth_delay(int milliseconds);
static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
static irqreturn_t gdth_interrupt(int irq, void *dev_id);
-static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
-static int gdth_async_event(int hanum);
+static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
+ int gdth_from_wait, int* pIndex);
+static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
+ Scsi_Cmnd *scp);
+static int gdth_async_event(gdth_ha_str *ha);
static void gdth_log_event(gdth_evt_data *dvr, char *buffer);
-static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority);
-static void gdth_next(int hanum);
-static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b);
-static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp);
+static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority);
+static void gdth_next(gdth_ha_str *ha);
+static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b);
+static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source,
ushort idx, gdth_evt_data *evt);
static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr);
@@ -439,42 +159,34 @@ static void gdth_readapp_event(gdth_ha_str *ha, unchar application,
gdth_evt_str *estr);
static void gdth_clear_events(void);
-static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp,
- char *buffer,ushort count);
-static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp);
-static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive);
+static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
+ char *buffer, ushort count, int to_buffer);
+static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp);
+static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive);
-static int gdth_search_eisa(ushort eisa_adr);
-static int gdth_search_isa(ulong32 bios_adr);
-static int gdth_search_pci(gdth_pci_str *pcistr);
-static void gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt,
- ushort vendor, ushort dev);
-static void gdth_sort_pci(gdth_pci_str *pcistr, int cnt);
-static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha);
-static int gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha);
-static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha);
-
-static void gdth_enable_int(int hanum);
-static int gdth_get_status(unchar *pIStatus,int irq);
-static int gdth_test_busy(int hanum);
-static int gdth_get_cmd_index(int hanum);
-static void gdth_release_event(int hanum);
-static int gdth_wait(int hanum,int index,ulong32 time);
-static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
- ulong64 p2,ulong64 p3);
-static int gdth_search_drives(int hanum);
-static int gdth_analyse_hdrive(int hanum, ushort hdrive);
-
-static const char *gdth_ctr_name(int hanum);
+static void gdth_enable_int(gdth_ha_str *ha);
+static unchar gdth_get_status(gdth_ha_str *ha, int irq);
+static int gdth_test_busy(gdth_ha_str *ha);
+static int gdth_get_cmd_index(gdth_ha_str *ha);
+static void gdth_release_event(gdth_ha_str *ha);
+static int gdth_wait(gdth_ha_str *ha, int index,ulong32 time);
+static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode,
+ ulong32 p1, ulong64 p2,ulong64 p3);
+static int gdth_search_drives(gdth_ha_str *ha);
+static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive);
+
+static const char *gdth_ctr_name(gdth_ha_str *ha);
static int gdth_open(struct inode *inode, struct file *filep);
static int gdth_close(struct inode *inode, struct file *filep);
static int gdth_ioctl(struct inode *inode, struct file *filep,
unsigned int cmd, unsigned long arg);
-static void gdth_flush(int hanum);
+static void gdth_flush(gdth_ha_str *ha);
static int gdth_halt(struct notifier_block *nb, ulong event, void *buf);
static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *));
+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);
#ifdef DEBUG_GDTH
@@ -571,29 +283,17 @@ static struct timer_list gdth_timer;
#define GDTOFFSOF(a,b) (size_t)&(((a*)0)->b)
#define INDEX_OK(i,t) ((i)<ARRAY_SIZE(t))
-#define NUMDATA(a) ( (gdth_num_str *)((a)->hostdata))
-#define HADATA(a) (&((gdth_ext_str *)((a)->hostdata))->haext)
-#define CMDDATA(a) (&((gdth_ext_str *)((a)->hostdata))->cmdext)
-
#define BUS_L2P(a,b) ((b)>(a)->virt_bus ? (b-1):(b))
-#define gdth_readb(addr) readb(addr)
-#define gdth_readw(addr) readw(addr)
-#define gdth_readl(addr) readl(addr)
-#define gdth_writeb(b,addr) writeb((b),(addr))
-#define gdth_writew(b,addr) writew((b),(addr))
-#define gdth_writel(b,addr) writel((b),(addr))
-
+#ifdef CONFIG_ISA
static unchar gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */
+#endif
+#if defined(CONFIG_EISA) || defined(CONFIG_ISA)
static unchar gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */
+#endif
static unchar gdth_polling; /* polling if TRUE */
-static unchar gdth_from_wait = FALSE; /* gdth_wait() */
-static int wait_index,wait_hanum; /* gdth_wait() */
static int gdth_ctr_count = 0; /* controller count */
-static int gdth_ctr_vcount = 0; /* virt. ctr. count */
-static int gdth_ctr_released = 0; /* gdth_release() */
-static struct Scsi_Host *gdth_ctr_tab[MAXHA]; /* controller table */
-static struct Scsi_Host *gdth_ctr_vtab[MAXHA*MAXBUS]; /* virt. ctr. table */
+static LIST_HEAD(gdth_instances); /* controller list */
static unchar gdth_write_through = FALSE; /* write through */
static gdth_evt_str ebuffer[MAX_EVENTS]; /* event buffer */
static int elastidx;
@@ -645,8 +345,6 @@ static int hdr_channel = 0;
static int max_ids = MAXID;
/* rescan all IDs */
static int rescan = 0;
-/* map channels to virtual controllers */
-static int virt_ctr = 0;
/* shared access */
static int shared_access = 1;
/* enable support for EISA and ISA controllers */
@@ -655,7 +353,6 @@ static int probe_eisa_isa = 0;
static int force_dma32 = 0;
/* parameters for modprobe/insmod */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
module_param_array(irq, int, NULL, 0);
module_param(disable, int, 0);
module_param(reserve_mode, int, 0);
@@ -664,24 +361,9 @@ module_param(reverse_scan, int, 0);
module_param(hdr_channel, int, 0);
module_param(max_ids, int, 0);
module_param(rescan, int, 0);
-module_param(virt_ctr, int, 0);
module_param(shared_access, int, 0);
module_param(probe_eisa_isa, int, 0);
module_param(force_dma32, int, 0);
-#else
-MODULE_PARM(irq, "i");
-MODULE_PARM(disable, "i");
-MODULE_PARM(reserve_mode, "i");
-MODULE_PARM(reserve_list, "4-" __MODULE_STRING(MAX_RES_ARGS) "i");
-MODULE_PARM(reverse_scan, "i");
-MODULE_PARM(hdr_channel, "i");
-MODULE_PARM(max_ids, "i");
-MODULE_PARM(rescan, "i");
-MODULE_PARM(virt_ctr, "i");
-MODULE_PARM(shared_access, "i");
-MODULE_PARM(probe_eisa_isa, "i");
-MODULE_PARM(force_dma32, "i");
-#endif
MODULE_AUTHOR("Achim Leubner");
MODULE_LICENSE("GPL");
@@ -692,6 +374,47 @@ static const struct file_operations gdth_fops = {
.release = gdth_close,
};
+/*
+ * gdth scsi_command access wrappers.
+ * below 6 functions are used throughout the driver to access scsi_command's
+ * io parameters. The reason we do not use the regular accessors from
+ * scsi_cmnd.h is because of gdth_execute(). Since it is unrecommended for
+ * llds to directly set scsi_cmnd's IO members. This driver will use SCp
+ * members for IO parameters, and will copy scsi_cmnd's members to Scp
+ * members in queuecommand. For internal commands through gdth_execute()
+ * SCp's members will be set directly.
+ */
+static inline unsigned gdth_bufflen(struct scsi_cmnd *cmd)
+{
+ return (unsigned)cmd->SCp.this_residual;
+}
+
+static inline void gdth_set_bufflen(struct scsi_cmnd *cmd, unsigned bufflen)
+{
+ cmd->SCp.this_residual = bufflen;
+}
+
+static inline unsigned gdth_sg_count(struct scsi_cmnd *cmd)
+{
+ return (unsigned)cmd->SCp.buffers_residual;
+}
+
+static inline void gdth_set_sg_count(struct scsi_cmnd *cmd, unsigned sg_count)
+{
+ cmd->SCp.buffers_residual = sg_count;
+}
+
+static inline struct scatterlist *gdth_sglist(struct scsi_cmnd *cmd)
+{
+ return cmd->SCp.buffer;
+}
+
+static inline void gdth_set_sglist(struct scsi_cmnd *cmd,
+ struct scatterlist *sglist)
+{
+ cmd->SCp.buffer = sglist;
+}
+
#include "gdth_proc.h"
#include "gdth_proc.c"
@@ -701,6 +424,45 @@ static struct notifier_block gdth_notifier = {
};
static int notifier_disabled = 0;
+static gdth_ha_str *gdth_find_ha(int hanum)
+{
+ gdth_ha_str *ha;
+
+ list_for_each_entry(ha, &gdth_instances, list)
+ if (hanum == ha->hanum)
+ return ha;
+
+ return NULL;
+}
+
+static struct gdth_cmndinfo *gdth_get_cmndinfo(gdth_ha_str *ha)
+{
+ struct gdth_cmndinfo *priv = NULL;
+ ulong flags;
+ int i;
+
+ spin_lock_irqsave(&ha->smp_lock, flags);
+
+ for (i=0; i<GDTH_MAXCMDS; ++i) {
+ if (ha->cmndinfo[i].index == 0) {
+ priv = &ha->cmndinfo[i];
+ priv->index = i+1;
+ memset(priv, 0, sizeof(*priv));
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
+
+ return priv;
+}
+
+static void gdth_put_cmndinfo(struct gdth_cmndinfo *priv)
+{
+ BUG_ON(!priv);
+ priv->index = 0;
+}
+
static void gdth_delay(int milliseconds)
{
if (milliseconds == 0) {
@@ -710,80 +472,62 @@ static void gdth_delay(int milliseconds)
}
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
static void gdth_scsi_done(struct scsi_cmnd *scp)
{
- TRACE2(("gdth_scsi_done()\n"));
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
+ int internal_command = cmndinfo->internal_command;
+
+ TRACE2(("gdth_scsi_done()\n"));
- if (scp->request)
- complete((struct completion *)scp->request);
+ gdth_put_cmndinfo(cmndinfo);
+ scp->host_scribble = NULL;
+
+ if (internal_command)
+ complete((struct completion *)scp->request);
+ else
+ scp->scsi_done(scp);
}
int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
int timeout, u32 *info)
{
+ gdth_ha_str *ha = shost_priv(sdev->host);
Scsi_Cmnd *scp;
+ struct gdth_cmndinfo cmndinfo;
+ struct scatterlist one_sg;
DECLARE_COMPLETION_ONSTACK(wait);
int rval;
- scp = kmalloc(sizeof(*scp), GFP_KERNEL);
+ scp = kzalloc(sizeof(*scp), GFP_KERNEL);
if (!scp)
return -ENOMEM;
- memset(scp, 0, sizeof(*scp));
+
scp->device = sdev;
+ memset(&cmndinfo, 0, sizeof(cmndinfo));
+
/* use request field to save the ptr. to completion struct. */
scp->request = (struct request *)&wait;
scp->timeout_per_command = timeout*HZ;
- scp->request_buffer = gdtcmd;
+ sg_init_one(&one_sg, gdtcmd, sizeof(*gdtcmd));
+ gdth_set_sglist(scp, &one_sg);
+ gdth_set_sg_count(scp, 1);
+ gdth_set_bufflen(scp, sizeof(*gdtcmd));
scp->cmd_len = 12;
memcpy(scp->cmnd, cmnd, 12);
- scp->SCp.this_residual = IOCTL_PRI; /* priority */
- scp->done = gdth_scsi_done; /* some fn. test this */
- gdth_queuecommand(scp, gdth_scsi_done);
- wait_for_completion(&wait);
-
- rval = scp->SCp.Status;
- if (info)
- *info = scp->SCp.Message;
- kfree(scp);
- return rval;
-}
-#else
-static void gdth_scsi_done(Scsi_Cmnd *scp)
-{
- TRACE2(("gdth_scsi_done()\n"));
-
- scp->request.rq_status = RQ_SCSI_DONE;
- if (scp->request.waiting)
- complete(scp->request.waiting);
-}
+ cmndinfo.priority = IOCTL_PRI;
+ cmndinfo.internal_command = 1;
-int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
- int timeout, u32 *info)
-{
- Scsi_Cmnd *scp = scsi_allocate_device(sdev, 1, FALSE);
- unsigned bufflen = gdtcmd ? sizeof(gdth_cmd_str) : 0;
- DECLARE_COMPLETION_ONSTACK(wait);
- int rval;
+ TRACE(("__gdth_execute() cmd 0x%x\n", scp->cmnd[0]));
+ __gdth_queuecommand(ha, scp, &cmndinfo);
- if (!scp)
- return -ENOMEM;
- scp->cmd_len = 12;
- scp->use_sg = 0;
- scp->SCp.this_residual = IOCTL_PRI; /* priority */
- scp->request.rq_status = RQ_SCSI_BUSY;
- scp->request.waiting = &wait;
- scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
wait_for_completion(&wait);
- rval = scp->SCp.Status;
+ rval = cmndinfo.status;
if (info)
- *info = scp->SCp.Message;
-
- scsi_release_command(scp);
+ *info = cmndinfo.info;
+ kfree(scp);
return rval;
}
-#endif
int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd,
int timeout, u32 *info)
@@ -815,7 +559,7 @@ static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs
}
/* controller search and initialization functions */
-
+#ifdef CONFIG_EISA
static int __init gdth_search_eisa(ushort eisa_adr)
{
ulong32 id;
@@ -832,8 +576,9 @@ static int __init gdth_search_eisa(ushort eisa_adr)
return 0;
}
+#endif /* CONFIG_EISA */
-
+#ifdef CONFIG_ISA
static int __init gdth_search_isa(ulong32 bios_adr)
{
void __iomem *addr;
@@ -841,14 +586,18 @@ static int __init gdth_search_isa(ulong32 bios_adr)
TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr));
if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) {
- id = gdth_readl(addr);
+ id = readl(addr);
iounmap(addr);
if (id == GDT2_ID) /* GDT2000 */
return 1;
}
return 0;
}
+#endif /* CONFIG_ISA */
+#ifdef CONFIG_PCI
+static void gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt,
+ ushort vendor, ushort dev);
static int __init gdth_search_pci(gdth_pci_str *pcistr)
{
@@ -928,7 +677,6 @@ static void __init gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt,
}
}
-
static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt)
{
gdth_pci_str temp;
@@ -965,8 +713,9 @@ static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt)
}
} while (changed);
}
+#endif /* CONFIG_PCI */
-
+#ifdef CONFIG_EISA
static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)
{
ulong32 retries,id;
@@ -1058,8 +807,9 @@ static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)
ha->dma64_support = 0;
return 1;
}
+#endif /* CONFIG_EISA */
-
+#ifdef CONFIG_ISA
static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
{
register gdt2_dpram_str __iomem *dp2_ptr;
@@ -1075,22 +825,22 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
return 0;
}
dp2_ptr = ha->brd;
- gdth_writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */
+ writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */
/* reset interface area */
memset_io(&dp2_ptr->u, 0, sizeof(dp2_ptr->u));
- if (gdth_readl(&dp2_ptr->u) != 0) {
+ if (readl(&dp2_ptr->u) != 0) {
printk("GDT-ISA: Initialization error (DPMEM write error)\n");
iounmap(ha->brd);
return 0;
}
/* disable board interrupts, read DRQ and IRQ */
- gdth_writeb(0xff, &dp2_ptr->io.irqdel);
- gdth_writeb(0x00, &dp2_ptr->io.irqen);
- gdth_writeb(0x00, &dp2_ptr->u.ic.S_Status);
- gdth_writeb(0x00, &dp2_ptr->u.ic.Cmd_Index);
+ writeb(0xff, &dp2_ptr->io.irqdel);
+ writeb(0x00, &dp2_ptr->io.irqen);
+ writeb(0x00, &dp2_ptr->u.ic.S_Status);
+ writeb(0x00, &dp2_ptr->u.ic.Cmd_Index);
- irq_drq = gdth_readb(&dp2_ptr->io.rq);
+ irq_drq = readb(&dp2_ptr->io.rq);
for (i=0; i<3; ++i) {
if ((irq_drq & 1)==0)
break;
@@ -1098,7 +848,7 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
}
ha->drq = gdth_drq_tab[i];
- irq_drq = gdth_readb(&dp2_ptr->io.rq) >> 3;
+ irq_drq = readb(&dp2_ptr->io.rq) >> 3;
for (i=1; i<5; ++i) {
if ((irq_drq & 1)==0)
break;
@@ -1107,12 +857,12 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
ha->irq = gdth_irq_tab[i];
/* deinitialize services */
- gdth_writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]);
- gdth_writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(0, &dp2_ptr->io.event);
+ writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]);
+ writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx);
+ writeb(0, &dp2_ptr->io.event);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xff) {
+ while (readb(&dp2_ptr->u.ic.S_Status) != 0xff) {
if (--retries == 0) {
printk("GDT-ISA: Initialization error (DEINIT failed)\n");
iounmap(ha->brd);
@@ -1120,9 +870,9 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- prot_ver = (unchar)gdth_readl(&dp2_ptr->u.ic.S_Info[0]);
- gdth_writeb(0, &dp2_ptr->u.ic.Status);
- gdth_writeb(0xff, &dp2_ptr->io.irqdel);
+ prot_ver = (unchar)readl(&dp2_ptr->u.ic.S_Info[0]);
+ writeb(0, &dp2_ptr->u.ic.Status);
+ writeb(0xff, &dp2_ptr->io.irqdel);
if (prot_ver != PROTOCOL_VERSION) {
printk("GDT-ISA: Illegal protocol version\n");
iounmap(ha->brd);
@@ -1136,15 +886,15 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
ha->brd_phys = bios_adr >> 4;
/* special request to controller BIOS */
- gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[0]);
- gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[1]);
- gdth_writel(0x01, &dp2_ptr->u.ic.S_Info[2]);
- gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[3]);
- gdth_writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(0, &dp2_ptr->io.event);
+ writel(0x00, &dp2_ptr->u.ic.S_Info[0]);
+ writel(0x00, &dp2_ptr->u.ic.S_Info[1]);
+ writel(0x01, &dp2_ptr->u.ic.S_Info[2]);
+ writel(0x00, &dp2_ptr->u.ic.S_Info[3]);
+ writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx);
+ writeb(0, &dp2_ptr->io.event);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xfe) {
+ while (readb(&dp2_ptr->u.ic.S_Status) != 0xfe) {
if (--retries == 0) {
printk("GDT-ISA: Initialization error\n");
iounmap(ha->brd);
@@ -1152,14 +902,15 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- gdth_writeb(0, &dp2_ptr->u.ic.Status);
- gdth_writeb(0xff, &dp2_ptr->io.irqdel);
+ writeb(0, &dp2_ptr->u.ic.Status);
+ writeb(0xff, &dp2_ptr->io.irqdel);
ha->dma64_support = 0;
return 1;
}
+#endif /* CONFIG_ISA */
-
+#ifdef CONFIG_PCI
static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
{
register gdt6_dpram_str __iomem *dp6_ptr;
@@ -1190,8 +941,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
/* check and reset interface area */
dp6_ptr = ha->brd;
- gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
- if (gdth_readl(&dp6_ptr->u) != DPMEM_MAGIC) {
+ writel(DPMEM_MAGIC, &dp6_ptr->u);
+ if (readl(&dp6_ptr->u) != DPMEM_MAGIC) {
printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n",
pcistr->dpmem);
found = FALSE;
@@ -1202,7 +953,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
return 0;
}
- if (gdth_readw(ha->brd) != 0xffff) {
+ if (readw(ha->brd) != 0xffff) {
TRACE2(("init_pci_old() address 0x%x busy\n", i));
continue;
}
@@ -1215,8 +966,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
return 0;
}
dp6_ptr = ha->brd;
- gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
- if (gdth_readl(&dp6_ptr->u) == DPMEM_MAGIC) {
+ writel(DPMEM_MAGIC, &dp6_ptr->u);
+ if (readl(&dp6_ptr->u) == DPMEM_MAGIC) {
printk("GDT-PCI: Use free address at 0x%x\n", i);
found = TRUE;
break;
@@ -1229,24 +980,24 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
}
memset_io(&dp6_ptr->u, 0, sizeof(dp6_ptr->u));
- if (gdth_readl(&dp6_ptr->u) != 0) {
+ if (readl(&dp6_ptr->u) != 0) {
printk("GDT-PCI: Initialization error (DPMEM write error)\n");
iounmap(ha->brd);
return 0;
}
/* disable board interrupts, deinit services */
- gdth_writeb(0xff, &dp6_ptr->io.irqdel);
- gdth_writeb(0x00, &dp6_ptr->io.irqen);
- gdth_writeb(0x00, &dp6_ptr->u.ic.S_Status);
- gdth_writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);
-
- gdth_writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]);
- gdth_writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(0, &dp6_ptr->io.event);
+ writeb(0xff, &dp6_ptr->io.irqdel);
+ writeb(0x00, &dp6_ptr->io.irqen);
+ writeb(0x00, &dp6_ptr->u.ic.S_Status);
+ writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);
+
+ writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]);
+ writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx);
+ writeb(0, &dp6_ptr->io.event);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
+ while (readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error (DEINIT failed)\n");
iounmap(ha->brd);
@@ -1254,9 +1005,9 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- prot_ver = (unchar)gdth_readl(&dp6_ptr->u.ic.S_Info[0]);
- gdth_writeb(0, &dp6_ptr->u.ic.S_Status);
- gdth_writeb(0xff, &dp6_ptr->io.irqdel);
+ prot_ver = (unchar)readl(&dp6_ptr->u.ic.S_Info[0]);
+ writeb(0, &dp6_ptr->u.ic.S_Status);
+ writeb(0xff, &dp6_ptr->io.irqdel);
if (prot_ver != PROTOCOL_VERSION) {
printk("GDT-PCI: Illegal protocol version\n");
iounmap(ha->brd);
@@ -1267,15 +1018,15 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
ha->ic_all_size = sizeof(dp6_ptr->u);
/* special command to controller BIOS */
- gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
- gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
- gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[2]);
- gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
- gdth_writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(0, &dp6_ptr->io.event);
+ writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
+ writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
+ writel(0x00, &dp6_ptr->u.ic.S_Info[2]);
+ writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
+ writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
+ writeb(0, &dp6_ptr->io.event);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
+ while (readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error\n");
iounmap(ha->brd);
@@ -1283,8 +1034,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- gdth_writeb(0, &dp6_ptr->u.ic.S_Status);
- gdth_writeb(0xff, &dp6_ptr->io.irqdel);
+ writeb(0, &dp6_ptr->u.ic.S_Status);
+ writeb(0xff, &dp6_ptr->io.irqdel);
ha->dma64_support = 0;
@@ -1300,8 +1051,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
/* check and reset interface area */
dp6c_ptr = ha->brd;
- gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
- if (gdth_readl(&dp6c_ptr->u) != DPMEM_MAGIC) {
+ writel(DPMEM_MAGIC, &dp6c_ptr->u);
+ if (readl(&dp6c_ptr->u) != DPMEM_MAGIC) {
printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n",
pcistr->dpmem);
found = FALSE;
@@ -1312,7 +1063,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
return 0;
}
- if (gdth_readw(ha->brd) != 0xffff) {
+ if (readw(ha->brd) != 0xffff) {
TRACE2(("init_pci_plx() address 0x%x busy\n", i));
continue;
}
@@ -1325,8 +1076,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
return 0;
}
dp6c_ptr = ha->brd;
- gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
- if (gdth_readl(&dp6c_ptr->u) == DPMEM_MAGIC) {
+ writel(DPMEM_MAGIC, &dp6c_ptr->u);
+ if (readl(&dp6c_ptr->u) == DPMEM_MAGIC) {
printk("GDT-PCI: Use free address at 0x%x\n", i);
found = TRUE;
break;
@@ -1339,7 +1090,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
}
memset_io(&dp6c_ptr->u, 0, sizeof(dp6c_ptr->u));
- if (gdth_readl(&dp6c_ptr->u) != 0) {
+ if (readl(&dp6c_ptr->u) != 0) {
printk("GDT-PCI: Initialization error (DPMEM write error)\n");
iounmap(ha->brd);
return 0;
@@ -1349,17 +1100,17 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
outb(0x00,PTR2USHORT(&ha->plx->control1));
outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
- gdth_writeb(0x00, &dp6c_ptr->u.ic.S_Status);
- gdth_writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index);
+ writeb(0x00, &dp6c_ptr->u.ic.S_Status);
+ writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index);
- gdth_writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]);
- gdth_writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx);
+ writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]);
+ writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx);
outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
+ while (readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error (DEINIT failed)\n");
iounmap(ha->brd);
@@ -1367,8 +1118,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- prot_ver = (unchar)gdth_readl(&dp6c_ptr->u.ic.S_Info[0]);
- gdth_writeb(0, &dp6c_ptr->u.ic.Status);
+ prot_ver = (unchar)readl(&dp6c_ptr->u.ic.S_Info[0]);
+ writeb(0, &dp6c_ptr->u.ic.Status);
if (prot_ver != PROTOCOL_VERSION) {
printk("GDT-PCI: Illegal protocol version\n");
iounmap(ha->brd);
@@ -1379,17 +1130,17 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
ha->ic_all_size = sizeof(dp6c_ptr->u);
/* special command to controller BIOS */
- gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
- gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
- gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[2]);
- gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
- gdth_writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
+ writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
+ writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
+ writel(0x00, &dp6c_ptr->u.ic.S_Info[2]);
+ writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
+ writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
+ while (readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error\n");
iounmap(ha->brd);
@@ -1397,7 +1148,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- gdth_writeb(0, &dp6c_ptr->u.ic.S_Status);
+ writeb(0, &dp6c_ptr->u.ic.S_Status);
ha->dma64_support = 0;
@@ -1425,12 +1176,12 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
/* Ensure that it is safe to access the non HW portions of DPMEM.
* Aditional check needed for Xscale based RAID controllers */
- while( ((int)gdth_readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 )
+ while( ((int)readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 )
gdth_delay(1);
/* check and reset interface area */
- gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u);
- if (gdth_readl(&dp6m_ptr->u) != DPMEM_MAGIC) {
+ writel(DPMEM_MAGIC, &dp6m_ptr->u);
+ if (readl(&dp6m_ptr->u) != DPMEM_MAGIC) {
printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n",
pcistr->dpmem);
found = FALSE;
@@ -1441,7 +1192,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
return 0;
}
- if (gdth_readw(ha->brd) != 0xffff) {
+ if (readw(ha->brd) != 0xffff) {
TRACE2(("init_pci_mpr() address 0x%x busy\n", i));
continue;
}
@@ -1454,8 +1205,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
return 0;
}
dp6m_ptr = ha->brd;
- gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u);
- if (gdth_readl(&dp6m_ptr->u) == DPMEM_MAGIC) {
+ writel(DPMEM_MAGIC, &dp6m_ptr->u);
+ if (readl(&dp6m_ptr->u) == DPMEM_MAGIC) {
printk("GDT-PCI: Use free address at 0x%x\n", i);
found = TRUE;
break;
@@ -1470,18 +1221,18 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
memset_io(&dp6m_ptr->u, 0, sizeof(dp6m_ptr->u));
/* disable board interrupts, deinit services */
- gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) | 4,
+ writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) | 4,
&dp6m_ptr->i960r.edoor_en_reg);
- gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
- gdth_writeb(0x00, &dp6m_ptr->u.ic.S_Status);
- gdth_writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index);
+ writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+ writeb(0x00, &dp6m_ptr->u.ic.S_Status);
+ writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index);
- gdth_writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]);
- gdth_writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+ writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]);
+ writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx);
+ writeb(1, &dp6m_ptr->i960r.ldoor_reg);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xff) {
+ while (readb(&dp6m_ptr->u.ic.S_Status) != 0xff) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error (DEINIT failed)\n");
iounmap(ha->brd);
@@ -1489,8 +1240,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- prot_ver = (unchar)gdth_readl(&dp6m_ptr->u.ic.S_Info[0]);
- gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+ prot_ver = (unchar)readl(&dp6m_ptr->u.ic.S_Info[0]);
+ writeb(0, &dp6m_ptr->u.ic.S_Status);
if (prot_ver != PROTOCOL_VERSION) {
printk("GDT-PCI: Illegal protocol version\n");
iounmap(ha->brd);
@@ -1501,15 +1252,15 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
ha->ic_all_size = sizeof(dp6m_ptr->u);
/* special command to controller BIOS */
- gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[0]);
- gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[1]);
- gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[2]);
- gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[3]);
- gdth_writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+ writel(0x00, &dp6m_ptr->u.ic.S_Info[0]);
+ writel(0x00, &dp6m_ptr->u.ic.S_Info[1]);
+ writel(0x00, &dp6m_ptr->u.ic.S_Info[2]);
+ writel(0x00, &dp6m_ptr->u.ic.S_Info[3]);
+ writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx);
+ writeb(1, &dp6m_ptr->i960r.ldoor_reg);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) {
+ while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error\n");
iounmap(ha->brd);
@@ -1517,14 +1268,14 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+ writeb(0, &dp6m_ptr->u.ic.S_Status);
/* read FW version to detect 64-bit DMA support */
- gdth_writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx);
- gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+ writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx);
+ writeb(1, &dp6m_ptr->i960r.ldoor_reg);
retries = INIT_RETRIES;
gdth_delay(20);
- while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) {
+ while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) {
if (--retries == 0) {
printk("GDT-PCI: Initialization error (DEINIT failed)\n");
iounmap(ha->brd);
@@ -1532,8 +1283,8 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
}
gdth_delay(1);
}
- prot_ver = (unchar)(gdth_readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16);
- gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+ prot_ver = (unchar)(readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16);
+ writeb(0, &dp6m_ptr->u.ic.S_Status);
if (prot_ver < 0x2b) /* FW < x.43: no 64-bit DMA support */
ha->dma64_support = 0;
else
@@ -1542,20 +1293,18 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
return 1;
}
-
+#endif /* CONFIG_PCI */
/* controller protocol functions */
-static void __init gdth_enable_int(int hanum)
+static void __init gdth_enable_int(gdth_ha_str *ha)
{
- gdth_ha_str *ha;
ulong flags;
gdt2_dpram_str __iomem *dp2_ptr;
gdt6_dpram_str __iomem *dp6_ptr;
gdt6m_dpram_str __iomem *dp6m_ptr;
- TRACE(("gdth_enable_int() hanum %d\n",hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE(("gdth_enable_int() hanum %d\n",ha->hanum));
spin_lock_irqsave(&ha->smp_lock, flags);
if (ha->type == GDT_EISA) {
@@ -1564,93 +1313,80 @@ static void __init gdth_enable_int(int hanum)
outb(0x01, ha->bmic + EINTENABREG);
} else if (ha->type == GDT_ISA) {
dp2_ptr = ha->brd;
- gdth_writeb(1, &dp2_ptr->io.irqdel);
- gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);
- gdth_writeb(1, &dp2_ptr->io.irqen);
+ writeb(1, &dp2_ptr->io.irqdel);
+ writeb(0, &dp2_ptr->u.ic.Cmd_Index);
+ writeb(1, &dp2_ptr->io.irqen);
} else if (ha->type == GDT_PCI) {
dp6_ptr = ha->brd;
- gdth_writeb(1, &dp6_ptr->io.irqdel);
- gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);
- gdth_writeb(1, &dp6_ptr->io.irqen);
+ writeb(1, &dp6_ptr->io.irqdel);
+ writeb(0, &dp6_ptr->u.ic.Cmd_Index);
+ writeb(1, &dp6_ptr->io.irqen);
} else if (ha->type == GDT_PCINEW) {
outb(0xff, PTR2USHORT(&ha->plx->edoor_reg));
outb(0x03, PTR2USHORT(&ha->plx->control1));
} else if (ha->type == GDT_PCIMPR) {
dp6m_ptr = ha->brd;
- gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
- gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4,
+ writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+ writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4,
&dp6m_ptr->i960r.edoor_en_reg);
}
spin_unlock_irqrestore(&ha->smp_lock, flags);
}
-
-static int gdth_get_status(unchar *pIStatus,int irq)
+/* return IStatus if interrupt was from this card else 0 */
+static unchar gdth_get_status(gdth_ha_str *ha, int irq)
{
- register gdth_ha_str *ha;
- int i;
+ unchar IStatus = 0;
+
+ TRACE(("gdth_get_status() irq %d ctr_count %d\n", irq, gdth_ctr_count));
- TRACE(("gdth_get_status() irq %d ctr_count %d\n",
- irq,gdth_ctr_count));
-
- *pIStatus = 0;
- for (i=0; i<gdth_ctr_count; ++i) {
- ha = HADATA(gdth_ctr_tab[i]);
if (ha->irq != (unchar)irq) /* check IRQ */
- continue;
+ return false;
if (ha->type == GDT_EISA)
- *pIStatus = inb((ushort)ha->bmic + EDOORREG);
+ IStatus = inb((ushort)ha->bmic + EDOORREG);
else if (ha->type == GDT_ISA)
- *pIStatus =
- gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
+ IStatus =
+ readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
else if (ha->type == GDT_PCI)
- *pIStatus =
- gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
+ IStatus =
+ readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
else if (ha->type == GDT_PCINEW)
- *pIStatus = inb(PTR2USHORT(&ha->plx->edoor_reg));
+ IStatus = inb(PTR2USHORT(&ha->plx->edoor_reg));
else if (ha->type == GDT_PCIMPR)
- *pIStatus =
- gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg);
-
- if (*pIStatus)
- return i; /* board found */
- }
- return -1;
+ IStatus =
+ readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg);
+
+ return IStatus;
}
-
-
-static int gdth_test_busy(int hanum)
+
+static int gdth_test_busy(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
register int gdtsema0 = 0;
- TRACE(("gdth_test_busy() hanum %d\n",hanum));
-
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE(("gdth_test_busy() hanum %d\n", ha->hanum));
+
if (ha->type == GDT_EISA)
gdtsema0 = (int)inb(ha->bmic + SEMA0REG);
else if (ha->type == GDT_ISA)
- gdtsema0 = (int)gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+ gdtsema0 = (int)readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
else if (ha->type == GDT_PCI)
- gdtsema0 = (int)gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+ gdtsema0 = (int)readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
else if (ha->type == GDT_PCINEW)
gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg));
else if (ha->type == GDT_PCIMPR)
gdtsema0 =
- (int)gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
+ (int)readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
return (gdtsema0 & 1);
}
-static int gdth_get_cmd_index(int hanum)
+static int gdth_get_cmd_index(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
int i;
- TRACE(("gdth_get_cmd_index() hanum %d\n",hanum));
+ TRACE(("gdth_get_cmd_index() hanum %d\n", ha->hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
for (i=0; i<GDTH_MAXCMDS; ++i) {
if (ha->cmd_tab[i].cmnd == UNUSED_CMND) {
ha->cmd_tab[i].cmnd = ha->pccb->RequestBuffer;
@@ -1663,30 +1399,26 @@ static int gdth_get_cmd_index(int hanum)
}
-static void gdth_set_sema0(int hanum)
+static void gdth_set_sema0(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
-
- TRACE(("gdth_set_sema0() hanum %d\n",hanum));
+ TRACE(("gdth_set_sema0() hanum %d\n", ha->hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
if (ha->type == GDT_EISA) {
outb(1, ha->bmic + SEMA0REG);
} else if (ha->type == GDT_ISA) {
- gdth_writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+ writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
} else if (ha->type == GDT_PCI) {
- gdth_writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+ writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
} else if (ha->type == GDT_PCINEW) {
outb(1, PTR2USHORT(&ha->plx->sema0_reg));
} else if (ha->type == GDT_PCIMPR) {
- gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
+ writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
}
}
-static void gdth_copy_command(int hanum)
+static void gdth_copy_command(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
register gdth_cmd_str *cmd_ptr;
register gdt6m_dpram_str __iomem *dp6m_ptr;
register gdt6c_dpram_str __iomem *dp6c_ptr;
@@ -1694,9 +1426,8 @@ static void gdth_copy_command(int hanum)
gdt2_dpram_str __iomem *dp2_ptr;
ushort cp_count,dp_offset,cmd_no;
- TRACE(("gdth_copy_command() hanum %d\n",hanum));
+ TRACE(("gdth_copy_command() hanum %d\n", ha->hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
cp_count = ha->cmd_len;
dp_offset= ha->cmd_offs_dpmem;
cmd_no = ha->cmd_cnt;
@@ -1715,42 +1446,39 @@ static void gdth_copy_command(int hanum)
/* set offset and service, copy command to DPMEM */
if (ha->type == GDT_ISA) {
dp2_ptr = ha->brd;
- gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET,
+ writew(dp_offset + DPMEM_COMMAND_OFFSET,
&dp2_ptr->u.ic.comm_queue[cmd_no].offset);
- gdth_writew((ushort)cmd_ptr->Service,
+ writew((ushort)cmd_ptr->Service,
&dp2_ptr->u.ic.comm_queue[cmd_no].serv_id);
memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
} else if (ha->type == GDT_PCI) {
dp6_ptr = ha->brd;
- gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET,
+ writew(dp_offset + DPMEM_COMMAND_OFFSET,
&dp6_ptr->u.ic.comm_queue[cmd_no].offset);
- gdth_writew((ushort)cmd_ptr->Service,
+ writew((ushort)cmd_ptr->Service,
&dp6_ptr->u.ic.comm_queue[cmd_no].serv_id);
memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
} else if (ha->type == GDT_PCINEW) {
dp6c_ptr = ha->brd;
- gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET,
+ writew(dp_offset + DPMEM_COMMAND_OFFSET,
&dp6c_ptr->u.ic.comm_queue[cmd_no].offset);
- gdth_writew((ushort)cmd_ptr->Service,
+ writew((ushort)cmd_ptr->Service,
&dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id);
memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
} else if (ha->type == GDT_PCIMPR) {
dp6m_ptr = ha->brd;
- gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET,
+ writew(dp_offset + DPMEM_COMMAND_OFFSET,
&dp6m_ptr->u.ic.comm_queue[cmd_no].offset);
- gdth_writew((ushort)cmd_ptr->Service,
+ writew((ushort)cmd_ptr->Service,
&dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id);
memcpy_toio(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
}
}
-static void gdth_release_event(int hanum)
+static void gdth_release_event(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
-
- TRACE(("gdth_release_event() hanum %d\n",hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE(("gdth_release_event() hanum %d\n", ha->hanum));
#ifdef GDTH_STATISTICS
{
@@ -1774,56 +1502,50 @@ static void gdth_release_event(int hanum)
outl(ha->ccb_phys, ha->bmic + MAILBOXREG);
outb(ha->pccb->Service, ha->bmic + LDOORREG);
} else if (ha->type == GDT_ISA) {
- gdth_writeb(0, &((gdt2_dpram_str __iomem *)ha->brd)->io.event);
+ writeb(0, &((gdt2_dpram_str __iomem *)ha->brd)->io.event);
} else if (ha->type == GDT_PCI) {
- gdth_writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event);
+ writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event);
} else if (ha->type == GDT_PCINEW) {
outb(1, PTR2USHORT(&ha->plx->ldoor_reg));
} else if (ha->type == GDT_PCIMPR) {
- gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.ldoor_reg);
+ writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.ldoor_reg);
}
}
-
-static int gdth_wait(int hanum,int index,ulong32 time)
+static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time)
{
- gdth_ha_str *ha;
int answer_found = FALSE;
+ int wait_index = 0;
- TRACE(("gdth_wait() hanum %d index %d time %d\n",hanum,index,time));
+ TRACE(("gdth_wait() hanum %d index %d time %d\n", ha->hanum, index, time));
- ha = HADATA(gdth_ctr_tab[hanum]);
if (index == 0)
return 1; /* no wait required */
- gdth_from_wait = TRUE;
do {
- gdth_interrupt((int)ha->irq,ha);
- if (wait_hanum==hanum && wait_index==index) {
+ __gdth_interrupt(ha, (int)ha->irq, true, &wait_index);
+ if (wait_index == index) {
answer_found = TRUE;
break;
}
gdth_delay(1);
} while (--time);
- gdth_from_wait = FALSE;
-
- while (gdth_test_busy(hanum))
+
+ while (gdth_test_busy(ha))
gdth_delay(0);
return (answer_found);
}
-static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
- ulong64 p2,ulong64 p3)
+static int gdth_internal_cmd(gdth_ha_str *ha, unchar service, ushort opcode,
+ ulong32 p1, ulong64 p2, ulong64 p3)
{
- register gdth_ha_str *ha;
register gdth_cmd_str *cmd_ptr;
int retries,index;
TRACE2(("gdth_internal_cmd() service %d opcode %d\n",service,opcode));
- ha = HADATA(gdth_ctr_tab[hanum]);
cmd_ptr = ha->pccb;
memset((char*)cmd_ptr,0,sizeof(gdth_cmd_str));
@@ -1831,11 +1553,11 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
for (retries = INIT_RETRIES;;) {
cmd_ptr->Service = service;
cmd_ptr->RequestBuffer = INTERNAL_CMND;
- if (!(index=gdth_get_cmd_index(hanum))) {
+ if (!(index=gdth_get_cmd_index(ha))) {
TRACE(("GDT: No free command index found\n"));
return 0;
}
- gdth_set_sema0(hanum);
+ gdth_set_sema0(ha);
cmd_ptr->OpCode = opcode;
cmd_ptr->BoardNode = LOCALBOARD;
if (service == CACHESERVICE) {
@@ -1875,10 +1597,10 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
ha->cmd_len = sizeof(gdth_cmd_str);
ha->cmd_offs_dpmem = 0;
ha->cmd_cnt = 0;
- gdth_copy_command(hanum);
- gdth_release_event(hanum);
+ gdth_copy_command(ha);
+ gdth_release_event(ha);
gdth_delay(20);
- if (!gdth_wait(hanum,index,INIT_TIMEOUT)) {
+ if (!gdth_wait(ha, index, INIT_TIMEOUT)) {
printk("GDT: Initialization error (timeout service %d)\n",service);
return 0;
}
@@ -1893,9 +1615,8 @@ static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
/* search for devices */
-static int __init gdth_search_drives(int hanum)
+static int __init gdth_search_drives(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
ushort cdev_cnt, i;
int ok;
ulong32 bus_no, drv_cnt, drv_no, j;
@@ -1915,22 +1636,21 @@ static int __init gdth_search_drives(int hanum)
ulong flags;
#endif
- TRACE(("gdth_search_drives() hanum %d\n",hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE(("gdth_search_drives() hanum %d\n", ha->hanum));
ok = 0;
/* initialize controller services, at first: screen service */
ha->screen_feat = 0;
if (!force_dma32) {
- ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_X_INIT_SCR,0,0,0);
+ ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_X_INIT_SCR, 0, 0, 0);
if (ok)
ha->screen_feat = GDT_64BIT;
}
if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
- ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0);
+ ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_INIT, 0, 0, 0);
if (!ok) {
printk("GDT-HA %d: Initialization error screen service (code %d)\n",
- hanum, ha->status);
+ ha->hanum, ha->status);
return 0;
}
TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n"));
@@ -1954,25 +1674,26 @@ static int __init gdth_search_drives(int hanum)
TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0],
*(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]));
/* 3. send to controller firmware */
- gdth_internal_cmd(hanum,SCREENSERVICE,GDT_REALTIME, *(ulong32 *)&rtc[0],
+ gdth_internal_cmd(ha, SCREENSERVICE, GDT_REALTIME, *(ulong32 *)&rtc[0],
*(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]);
#endif
/* unfreeze all IOs */
- gdth_internal_cmd(hanum,CACHESERVICE,GDT_UNFREEZE_IO,0,0,0);
+ gdth_internal_cmd(ha, CACHESERVICE, GDT_UNFREEZE_IO, 0, 0, 0);
/* initialize cache service */
ha->cache_feat = 0;
if (!force_dma32) {
- ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INIT_HOST,LINUX_OS,0,0);
+ ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INIT_HOST, LINUX_OS,
+ 0, 0);
if (ok)
ha->cache_feat = GDT_64BIT;
}
if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
- ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0);
+ ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_INIT, LINUX_OS, 0, 0);
if (!ok) {
printk("GDT-HA %d: Initialization error cache service (code %d)\n",
- hanum, ha->status);
+ ha->hanum, ha->status);
return 0;
}
TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
@@ -2001,9 +1722,9 @@ static int __init gdth_search_drives(int hanum)
pmod->cmd_buff_size = 0;
pmod->reserved1 = 0;
pmod->reserved2 = 0;
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,SET_PERF_MODES,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, SET_PERF_MODES,
INVALID_CHANNEL,sizeof(gdth_perf_modes))) {
- printk("GDT-HA %d: Interrupt coalescing activated\n", hanum);
+ printk("GDT-HA %d: Interrupt coalescing activated\n", ha->hanum);
}
}
#endif
@@ -2015,7 +1736,7 @@ static int __init gdth_search_drives(int hanum)
iocr->hdr.first_chan = 0;
iocr->hdr.last_chan = MAXBUS-1;
iocr->hdr.list_offset = GDTOFFSOF(gdth_raw_iochan_str, list[0]);
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_RAW_DESC,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, IOCHAN_RAW_DESC,
INVALID_CHANNEL,sizeof(gdth_raw_iochan_str))) {
TRACE2(("IOCHAN_RAW_DESC supported!\n"));
ha->bus_cnt = iocr->hdr.chan_count;
@@ -2030,13 +1751,13 @@ static int __init gdth_search_drives(int hanum)
chn = (gdth_getch_str *)ha->pscratch;
for (bus_no = 0; bus_no < MAXBUS; ++bus_no) {
chn->channel_no = bus_no;
- if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
SCSI_CHAN_CNT | L_CTRL_PATTERN,
IO_CHANNEL | INVALID_CHANNEL,
sizeof(gdth_getch_str))) {
if (bus_no == 0) {
printk("GDT-HA %d: Error detecting channel count (0x%x)\n",
- hanum, ha->status);
+ ha->hanum, ha->status);
return 0;
}
break;
@@ -2051,10 +1772,10 @@ static int __init gdth_search_drives(int hanum)
TRACE2(("gdth_search_drives() %d channels\n",ha->bus_cnt));
/* read cache configuration */
- if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_INFO,
+ if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_INFO,
INVALID_CHANNEL,sizeof(gdth_cinfo_str))) {
printk("GDT-HA %d: Initialization error cache service (code %d)\n",
- hanum, ha->status);
+ ha->hanum, ha->status);
return 0;
}
ha->cpar = ((gdth_cinfo_str *)ha->pscratch)->cpar;
@@ -2064,11 +1785,11 @@ static int __init gdth_search_drives(int hanum)
/* read board info and features */
ha->more_proc = FALSE;
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_INFO,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, BOARD_INFO,
INVALID_CHANNEL,sizeof(gdth_binfo_str))) {
memcpy(&ha->binfo, (gdth_binfo_str *)ha->pscratch,
sizeof(gdth_binfo_str));
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_FEATURES,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, BOARD_FEATURES,
INVALID_CHANNEL,sizeof(gdth_bfeat_str))) {
TRACE2(("BOARD_INFO/BOARD_FEATURES supported\n"));
ha->bfeat = *(gdth_bfeat_str *)ha->pscratch;
@@ -2076,7 +1797,7 @@ static int __init gdth_search_drives(int hanum)
}
} else {
TRACE2(("BOARD_INFO requires firmware >= 1.10/2.08\n"));
- strcpy(ha->binfo.type_string, gdth_ctr_name(hanum));
+ strcpy(ha->binfo.type_string, gdth_ctr_name(ha));
}
TRACE2(("Controller name: %s\n",ha->binfo.type_string));
@@ -2089,7 +1810,7 @@ static int __init gdth_search_drives(int hanum)
ioc->hdr.first_chan = 0;
ioc->hdr.last_chan = MAXBUS-1;
ioc->hdr.list_offset = GDTOFFSOF(gdth_iochan_str, list[0]);
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_DESC,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, IOCHAN_DESC,
INVALID_CHANNEL,sizeof(gdth_iochan_str))) {
for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
ha->raw[bus_no].address = ioc->list[bus_no].address;
@@ -2104,7 +1825,7 @@ static int __init gdth_search_drives(int hanum)
for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
chn = (gdth_getch_str *)ha->pscratch;
chn->channel_no = ha->raw[bus_no].local_no;
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
SCSI_CHAN_CNT | L_CTRL_PATTERN,
ha->raw[bus_no].address | INVALID_CHANNEL,
sizeof(gdth_getch_str))) {
@@ -2116,7 +1837,7 @@ static int __init gdth_search_drives(int hanum)
drl = (gdth_drlist_str *)ha->pscratch;
drl->sc_no = ha->raw[bus_no].local_no;
drl->sc_cnt = ha->raw[bus_no].pdev_cnt;
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
SCSI_DR_LIST | L_CTRL_PATTERN,
ha->raw[bus_no].address | INVALID_CHANNEL,
sizeof(gdth_drlist_str))) {
@@ -2129,10 +1850,10 @@ static int __init gdth_search_drives(int hanum)
}
/* logical drives */
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_CNT,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_CNT,
INVALID_CHANNEL,sizeof(ulong32))) {
drv_cnt = *(ulong32 *)ha->pscratch;
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_LIST,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_LIST,
INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) {
for (j = 0; j < drv_cnt; ++j) {
drv_no = ((ulong32 *)ha->pscratch)[j];
@@ -2146,7 +1867,7 @@ static int __init gdth_search_drives(int hanum)
alst->entries_avail = MAX_LDRIVES;
alst->first_entry = 0;
alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]);
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
ARRAY_DRV_LIST2 | LA_CTRL_PATTERN,
INVALID_CHANNEL, sizeof(gdth_arcdl_str) +
(alst->entries_avail-1) * sizeof(gdth_alist_str))) {
@@ -2157,7 +1878,7 @@ static int __init gdth_search_drives(int hanum)
ha->hdr[j].is_hotfix = alst->list[j].is_hotfix;
ha->hdr[j].master_no = alst->list[j].cd_handle;
}
- } else if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ } else if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
ARRAY_DRV_LIST | LA_CTRL_PATTERN,
0, 35 * sizeof(gdth_alist_str))) {
for (j = 0; j < 35; ++j) {
@@ -2175,24 +1896,24 @@ static int __init gdth_search_drives(int hanum)
/* initialize raw service */
ha->raw_feat = 0;
if (!force_dma32) {
- ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_X_INIT_RAW,0,0,0);
+ ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_X_INIT_RAW, 0, 0, 0);
if (ok)
ha->raw_feat = GDT_64BIT;
}
if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
- ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0);
+ ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_INIT, 0, 0, 0);
if (!ok) {
printk("GDT-HA %d: Initialization error raw service (code %d)\n",
- hanum, ha->status);
+ ha->hanum, ha->status);
return 0;
}
TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n"));
/* set/get features raw service (scatter/gather) */
- if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER,
- 0,0)) {
+ if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_SET_FEAT, SCATTER_GATHER,
+ 0, 0)) {
TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n"));
- if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_GET_FEAT,0,0,0)) {
+ if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_GET_FEAT, 0, 0, 0)) {
TRACE2(("gdth_search_dr(): get feat RAWSERVICE %d\n",
ha->info));
ha->raw_feat |= (ushort)ha->info;
@@ -2200,10 +1921,10 @@ static int __init gdth_search_drives(int hanum)
}
/* set/get features cache service (equal to raw service) */
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_SET_FEAT,0,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_SET_FEAT, 0,
SCATTER_GATHER,0)) {
TRACE2(("gdth_search_drives(): set features CACHESERVICE OK\n"));
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_GET_FEAT,0,0,0)) {
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_GET_FEAT, 0, 0, 0)) {
TRACE2(("gdth_search_dr(): get feat CACHESERV. %d\n",
ha->info));
ha->cache_feat |= (ushort)ha->info;
@@ -2212,22 +1933,22 @@ static int __init gdth_search_drives(int hanum)
/* reserve drives for raw service */
if (reserve_mode != 0) {
- gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE_ALL,
+ gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESERVE_ALL,
reserve_mode == 1 ? 1 : 3, 0, 0);
TRACE2(("gdth_search_drives(): RESERVE_ALL code %d\n",
ha->status));
}
for (i = 0; i < MAX_RES_ARGS; i += 4) {
- if (reserve_list[i] == hanum && reserve_list[i+1] < ha->bus_cnt &&
+ if (reserve_list[i] == ha->hanum && reserve_list[i+1] < ha->bus_cnt &&
reserve_list[i+2] < ha->tid_cnt && reserve_list[i+3] < MAXLUN) {
TRACE2(("gdth_search_drives(): reserve ha %d bus %d id %d lun %d\n",
reserve_list[i], reserve_list[i+1],
reserve_list[i+2], reserve_list[i+3]));
- if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE,0,
+ if (!gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESERVE, 0,
reserve_list[i+1], reserve_list[i+2] |
(reserve_list[i+3] << 8))) {
printk("GDT-HA %d: Error raw service (RESERVE, code %d)\n",
- hanum, ha->status);
+ ha->hanum, ha->status);
}
}
}
@@ -2236,58 +1957,44 @@ static int __init gdth_search_drives(int hanum)
oemstr = (gdth_oem_str_ioctl *)ha->pscratch;
oemstr->params.ctl_version = 0x01;
oemstr->params.buffer_size = sizeof(oemstr->text);
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL,
CACHE_READ_OEM_STRING_RECORD,INVALID_CHANNEL,
sizeof(gdth_oem_str_ioctl))) {
TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD OK\n"));
printk("GDT-HA %d: Vendor: %s Name: %s\n",
- hanum,oemstr->text.oem_company_name,ha->binfo.type_string);
+ ha->hanum, oemstr->text.oem_company_name, ha->binfo.type_string);
/* Save the Host Drive inquiry data */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
strlcpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,
sizeof(ha->oem_name));
-#else
- strncpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,7);
- ha->oem_name[7] = '\0';
-#endif
} else {
/* Old method, based on PCI ID */
TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD failed\n"));
printk("GDT-HA %d: Name: %s\n",
- hanum,ha->binfo.type_string);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+ ha->hanum, ha->binfo.type_string);
if (ha->oem_id == OEM_ID_INTEL)
strlcpy(ha->oem_name,"Intel ", sizeof(ha->oem_name));
else
strlcpy(ha->oem_name,"ICP ", sizeof(ha->oem_name));
-#else
- if (ha->oem_id == OEM_ID_INTEL)
- strcpy(ha->oem_name,"Intel ");
- else
- strcpy(ha->oem_name,"ICP ");
-#endif
}
/* scanning for host drives */
for (i = 0; i < cdev_cnt; ++i)
- gdth_analyse_hdrive(hanum,i);
+ gdth_analyse_hdrive(ha, i);
TRACE(("gdth_search_drives() OK\n"));
return 1;
}
-static int gdth_analyse_hdrive(int hanum,ushort hdrive)
+static int gdth_analyse_hdrive(gdth_ha_str *ha, ushort hdrive)
{
- register gdth_ha_str *ha;
ulong32 drv_cyls;
int drv_hds, drv_secs;
- TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n",hanum,hdrive));
+ TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n", ha->hanum, hdrive));
if (hdrive >= MAX_HDRIVES)
return 0;
- ha = HADATA(gdth_ctr_tab[hanum]);
- if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,hdrive,0,0))
+ if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_INFO, hdrive, 0, 0))
return 0;
ha->hdr[hdrive].present = TRUE;
ha->hdr[hdrive].size = ha->info;
@@ -2307,7 +2014,7 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive)
ha->hdr[hdrive].size = drv_cyls * drv_hds * drv_secs;
if (ha->cache_feat & GDT_64BIT) {
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INFO,hdrive,0,0)
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INFO, hdrive, 0, 0)
&& ha->info2 != 0) {
ha->hdr[hdrive].size = ((ulong64)ha->info2 << 32) | ha->info;
}
@@ -2316,14 +2023,14 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive)
hdrive,ha->hdr[hdrive].size,drv_hds,drv_secs));
/* get informations about device */
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,hdrive,0,0)) {
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_DEVTYPE, hdrive, 0, 0)) {
TRACE2(("gdth_search_dr() cache drive %d devtype %d\n",
hdrive,ha->info));
ha->hdr[hdrive].devtype = (ushort)ha->info;
}
/* cluster info */
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_CLUST_INFO,hdrive,0,0)) {
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_CLUST_INFO, hdrive, 0, 0)) {
TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n",
hdrive,ha->info));
if (!shared_access)
@@ -2331,7 +2038,7 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive)
}
/* R/W attributes */
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,hdrive,0,0)) {
+ if (gdth_internal_cmd(ha, CACHESERVICE, GDT_RW_ATTRIBS, hdrive, 0, 0)) {
TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n",
hdrive,ha->info));
ha->hdr[hdrive].rw_attribs = (unchar)ha->info;
@@ -2343,27 +2050,26 @@ static int gdth_analyse_hdrive(int hanum,ushort hdrive)
/* command queueing/sending functions */
-static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
+static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar priority)
{
- register gdth_ha_str *ha;
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
register Scsi_Cmnd *pscp;
register Scsi_Cmnd *nscp;
ulong flags;
unchar b, t;
TRACE(("gdth_putq() priority %d\n",priority));
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
- if (scp->done != gdth_scsi_done) {
- scp->SCp.this_residual = (int)priority;
- b = virt_ctr ? NUMDATA(scp->device->host)->busnum:scp->device->channel;
+ if (!cmndinfo->internal_command) {
+ cmndinfo->priority = priority;
+ b = scp->device->channel;
t = scp->device->id;
if (priority >= DEFAULT_PRI) {
if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
(b==ha->virt_bus && t<MAX_HDRIVES && ha->hdr[t].lock)) {
TRACE2(("gdth_putq(): locked IO ->update_timeout()\n"));
- scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
+ cmndinfo->timeout = gdth_update_timeout(scp, 0);
}
}
}
@@ -2375,7 +2081,7 @@ static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
pscp = ha->req_first;
nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
/* priority: 0-highest,..,0xff-lowest */
- while (nscp && (unchar)nscp->SCp.this_residual <= priority) {
+ while (nscp && gdth_cmnd_priv(nscp)->priority <= priority) {
pscp = nscp;
nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
}
@@ -2395,9 +2101,8 @@ static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
#endif
}
-static void gdth_next(int hanum)
+static void gdth_next(gdth_ha_str *ha)
{
- register gdth_ha_str *ha;
register Scsi_Cmnd *pscp;
register Scsi_Cmnd *nscp;
unchar b, t, l, firsttime;
@@ -2405,8 +2110,7 @@ static void gdth_next(int hanum)
ulong flags = 0;
int cmd_index;
- TRACE(("gdth_next() hanum %d\n",hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE(("gdth_next() hanum %d\n", ha->hanum));
if (!gdth_polling)
spin_lock_irqsave(&ha->smp_lock, flags);
@@ -2416,14 +2120,14 @@ static void gdth_next(int hanum)
cmd_index = 0;
for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) {
+ struct gdth_cmndinfo *nscp_cmndinfo = gdth_cmnd_priv(nscp);
if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr)
pscp = (Scsi_Cmnd *)pscp->SCp.ptr;
- if (nscp->done != gdth_scsi_done) {
- b = virt_ctr ?
- NUMDATA(nscp->device->host)->busnum : nscp->device->channel;
+ if (!nscp_cmndinfo->internal_command) {
+ b = nscp->device->channel;
t = nscp->device->id;
l = nscp->device->lun;
- if (nscp->SCp.this_residual >= DEFAULT_PRI) {
+ if (nscp_cmndinfo->priority >= DEFAULT_PRI) {
if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
(b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock))
continue;
@@ -2432,21 +2136,21 @@ static void gdth_next(int hanum)
b = t = l = 0;
if (firsttime) {
- if (gdth_test_busy(hanum)) { /* controller busy ? */
- TRACE(("gdth_next() controller %d busy !\n",hanum));
+ if (gdth_test_busy(ha)) { /* controller busy ? */
+ TRACE(("gdth_next() controller %d busy !\n", ha->hanum));
if (!gdth_polling) {
spin_unlock_irqrestore(&ha->smp_lock, flags);
return;
}
- while (gdth_test_busy(hanum))
+ while (gdth_test_busy(ha))
gdth_delay(1);
}
firsttime = FALSE;
}
- if (nscp->done != gdth_scsi_done) {
- if (nscp->SCp.phase == -1) {
- nscp->SCp.phase = CACHESERVICE; /* default: cache svc. */
+ if (!nscp_cmndinfo->internal_command) {
+ if (nscp_cmndinfo->phase == -1) {
+ nscp_cmndinfo->phase = CACHESERVICE; /* default: cache svc. */
if (nscp->cmnd[0] == TEST_UNIT_READY) {
TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n",
b, t, l));
@@ -2459,8 +2163,8 @@ static void gdth_next(int hanum)
} else if ((ha->scan_mode & 0x0f) == 1) {
if (b == 0 && ((t == 0 && l == 1) ||
(t == 1 && l == 0))) {
- nscp->SCp.sent_command = GDT_SCAN_START;
- nscp->SCp.phase = ((ha->scan_mode & 0x10 ? 1:0) << 8)
+ nscp_cmndinfo->OpCode = GDT_SCAN_START;
+ nscp_cmndinfo->phase = ((ha->scan_mode & 0x10 ? 1:0) << 8)
| SCSIRAWSERVICE;
ha->scan_mode = 0x12;
TRACE2(("Scan mode: 0x%x (SCAN_START)\n",
@@ -2471,8 +2175,8 @@ static void gdth_next(int hanum)
}
} else if (ha->scan_mode == 0x12) {
if (b == ha->bus_cnt && t == ha->tid_cnt-1) {
- nscp->SCp.phase = SCSIRAWSERVICE;
- nscp->SCp.sent_command = GDT_SCAN_END;
+ nscp_cmndinfo->phase = SCSIRAWSERVICE;
+ nscp_cmndinfo->OpCode = GDT_SCAN_END;
ha->scan_mode &= 0x10;
TRACE2(("Scan mode: 0x%x (SCAN_END)\n",
ha->scan_mode));
@@ -2483,18 +2187,18 @@ static void gdth_next(int hanum)
nscp->cmnd[0] != READ_CAPACITY && nscp->cmnd[0] != MODE_SENSE &&
(ha->hdr[t].cluster_type & CLUSTER_DRIVE)) {
/* always GDT_CLUST_INFO! */
- nscp->SCp.sent_command = GDT_CLUST_INFO;
+ nscp_cmndinfo->OpCode = GDT_CLUST_INFO;
}
}
}
- if (nscp->SCp.sent_command != -1) {
- if ((nscp->SCp.phase & 0xff) == CACHESERVICE) {
- if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+ if (nscp_cmndinfo->OpCode != -1) {
+ if ((nscp_cmndinfo->phase & 0xff) == CACHESERVICE) {
+ if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t)))
this_cmd = FALSE;
next_cmd = FALSE;
- } else if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) {
- if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b))))
+ } else if ((nscp_cmndinfo->phase & 0xff) == SCSIRAWSERVICE) {
+ if (!(cmd_index=gdth_fill_raw_cmd(ha, nscp, BUS_L2P(ha, b))))
this_cmd = FALSE;
next_cmd = FALSE;
} else {
@@ -2502,18 +2206,18 @@ static void gdth_next(int hanum)
nscp->sense_buffer[0] = 0x70;
nscp->sense_buffer[2] = NOT_READY;
nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
- if (!nscp->SCp.have_data_in)
- nscp->SCp.have_data_in++;
+ if (!nscp_cmndinfo->wait_for_completion)
+ nscp_cmndinfo->wait_for_completion++;
else
- nscp->scsi_done(nscp);
+ gdth_scsi_done(nscp);
}
- } else if (nscp->done == gdth_scsi_done) {
- if (!(cmd_index=gdth_special_cmd(hanum,nscp)))
+ } else if (gdth_cmnd_priv(nscp)->internal_command) {
+ if (!(cmd_index=gdth_special_cmd(ha, nscp)))
this_cmd = FALSE;
next_cmd = FALSE;
} else if (b != ha->virt_bus) {
if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW ||
- !(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b))))
+ !(cmd_index=gdth_fill_raw_cmd(ha, nscp, BUS_L2P(ha, b))))
this_cmd = FALSE;
else
ha->raw[BUS_L2P(ha,b)].io_cnt[t]++;
@@ -2521,10 +2225,10 @@ static void gdth_next(int hanum)
TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n",
nscp->cmnd[0], b, t, l));
nscp->result = DID_BAD_TARGET << 16;
- if (!nscp->SCp.have_data_in)
- nscp->SCp.have_data_in++;
+ if (!nscp_cmndinfo->wait_for_completion)
+ nscp_cmndinfo->wait_for_completion++;
else
- nscp->scsi_done(nscp);
+ gdth_scsi_done(nscp);
} else {
switch (nscp->cmnd[0]) {
case TEST_UNIT_READY:
@@ -2547,12 +2251,12 @@ static void gdth_next(int hanum)
nscp->sense_buffer[0] = 0x70;
nscp->sense_buffer[2] = UNIT_ATTENTION;
nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
- if (!nscp->SCp.have_data_in)
- nscp->SCp.have_data_in++;
+ if (!nscp_cmndinfo->wait_for_completion)
+ nscp_cmndinfo->wait_for_completion++;
else
- nscp->scsi_done(nscp);
- } else if (gdth_internal_cache_cmd(hanum,nscp))
- nscp->scsi_done(nscp);
+ gdth_scsi_done(nscp);
+ } else if (gdth_internal_cache_cmd(ha, nscp))
+ gdth_scsi_done(nscp);
break;
case ALLOW_MEDIUM_REMOVAL:
@@ -2563,15 +2267,15 @@ static void gdth_next(int hanum)
TRACE(("Prevent r. nonremov. drive->do nothing\n"));
nscp->result = DID_OK << 16;
nscp->sense_buffer[0] = 0;
- if (!nscp->SCp.have_data_in)
- nscp->SCp.have_data_in++;
+ if (!nscp_cmndinfo->wait_for_completion)
+ nscp_cmndinfo->wait_for_completion++;
else
- nscp->scsi_done(nscp);
+ gdth_scsi_done(nscp);
} else {
nscp->cmnd[3] = (ha->hdr[t].devtype&1) ? 1:0;
TRACE(("Prevent/allow r. %d rem. drive %d\n",
nscp->cmnd[4],nscp->cmnd[3]));
- if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+ if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t)))
this_cmd = FALSE;
}
break;
@@ -2580,7 +2284,7 @@ static void gdth_next(int hanum)
case RELEASE:
TRACE2(("cache cmd %s\n",nscp->cmnd[0] == RESERVE ?
"RESERVE" : "RELEASE"));
- if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+ if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t)))
this_cmd = FALSE;
break;
@@ -2599,11 +2303,11 @@ static void gdth_next(int hanum)
nscp->sense_buffer[0] = 0x70;
nscp->sense_buffer[2] = UNIT_ATTENTION;
nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
- if (!nscp->SCp.have_data_in)
- nscp->SCp.have_data_in++;
+ if (!nscp_cmndinfo->wait_for_completion)
+ nscp_cmndinfo->wait_for_completion++;
else
- nscp->scsi_done(nscp);
- } else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+ gdth_scsi_done(nscp);
+ } else if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t)))
this_cmd = FALSE;
break;
@@ -2612,12 +2316,12 @@ static void gdth_next(int hanum)
nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
nscp->cmnd[4],nscp->cmnd[5]));
printk("GDT-HA %d: Unknown SCSI command 0x%x to cache service !\n",
- hanum, nscp->cmnd[0]);
+ ha->hanum, nscp->cmnd[0]);
nscp->result = DID_ABORT << 16;
- if (!nscp->SCp.have_data_in)
- nscp->SCp.have_data_in++;
+ if (!nscp_cmndinfo->wait_for_completion)
+ nscp_cmndinfo->wait_for_completion++;
else
- nscp->scsi_done(nscp);
+ gdth_scsi_done(nscp);
break;
}
}
@@ -2633,79 +2337,77 @@ static void gdth_next(int hanum)
}
if (ha->cmd_cnt > 0) {
- gdth_release_event(hanum);
+ gdth_release_event(ha);
}
if (!gdth_polling)
spin_unlock_irqrestore(&ha->smp_lock, flags);
if (gdth_polling && ha->cmd_cnt > 0) {
- if (!gdth_wait(hanum,cmd_index,POLL_TIMEOUT))
+ if (!gdth_wait(ha, cmd_index, POLL_TIMEOUT))
printk("GDT-HA %d: Command %d timed out !\n",
- hanum,cmd_index);
+ ha->hanum, cmd_index);
}
}
-
-static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp,
- char *buffer,ushort count)
+
+/*
+ * gdth_copy_internal_data() - copy to/from a buffer onto a scsi_cmnd's
+ * buffers, kmap_atomic() as needed.
+ */
+static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp,
+ char *buffer, ushort count, int to_buffer)
{
- ushort cpcount,i;
+ ushort cpcount,i, max_sg = gdth_sg_count(scp);
ushort cpsum,cpnow;
struct scatterlist *sl;
- gdth_ha_str *ha;
char *address;
- cpcount = count<=(ushort)scp->request_bufflen ? count:(ushort)scp->request_bufflen;
- ha = HADATA(gdth_ctr_tab[hanum]);
+ cpcount = min_t(ushort, count, gdth_bufflen(scp));
- if (scp->use_sg) {
- sl = (struct scatterlist *)scp->request_buffer;
- for (i=0,cpsum=0; i<scp->use_sg; ++i,++sl) {
+ if (cpcount) {
+ cpsum=0;
+ scsi_for_each_sg(scp, sl, max_sg, i) {
unsigned long flags;
cpnow = (ushort)sl->length;
TRACE(("copy_internal() now %d sum %d count %d %d\n",
- cpnow,cpsum,cpcount,(ushort)scp->bufflen));
+ cpnow, cpsum, cpcount, gdth_bufflen(scp)));
if (cpsum+cpnow > cpcount)
cpnow = cpcount - cpsum;
cpsum += cpnow;
- if (!sl->page) {
+ if (!sg_page(sl)) {
printk("GDT-HA %d: invalid sc/gt element in gdth_copy_internal_data()\n",
- hanum);
+ ha->hanum);
return;
}
local_irq_save(flags);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
- address = kmap_atomic(sl->page, KM_BIO_SRC_IRQ) + sl->offset;
- memcpy(address,buffer,cpnow);
- flush_dcache_page(sl->page);
+ address = kmap_atomic(sg_page(sl), KM_BIO_SRC_IRQ) + sl->offset;
+ if (to_buffer)
+ memcpy(buffer, address, cpnow);
+ else
+ memcpy(address, buffer, cpnow);
+ flush_dcache_page(sg_page(sl));
kunmap_atomic(address, KM_BIO_SRC_IRQ);
-#else
- address = kmap_atomic(sl->page, KM_BH_IRQ) + sl->offset;
- memcpy(address,buffer,cpnow);
- flush_dcache_page(sl->page);
- kunmap_atomic(address, KM_BH_IRQ);
-#endif
local_irq_restore(flags);
if (cpsum == cpcount)
break;
buffer += cpnow;
}
- } else {
- TRACE(("copy_internal() count %d\n",cpcount));
- memcpy((char*)scp->request_buffer,buffer,cpcount);
+ } else if (count) {
+ printk("GDT-HA %d: SCSI command with no buffers but data transfer expected!\n",
+ ha->hanum);
+ WARN_ON(1);
}
}
-static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
+static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
{
- register gdth_ha_str *ha;
unchar t;
gdth_inq_data inq;
gdth_rdcap_data rdc;
gdth_sense_data sd;
gdth_modep_data mpd;
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
- ha = HADATA(gdth_ctr_tab[hanum]);
t = scp->device->id;
TRACE(("gdth_internal_cache_cmd() cmd 0x%x hdrive %d\n",
scp->cmnd[0],t));
@@ -2736,7 +2438,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
strcpy(inq.vendor,ha->oem_name);
sprintf(inq.product,"Host Drive #%02d",t);
strcpy(inq.revision," ");
- gdth_copy_internal_data(hanum,scp,(char*)&inq,sizeof(gdth_inq_data));
+ gdth_copy_internal_data(ha, scp, (char*)&inq, sizeof(gdth_inq_data), 0);
break;
case REQUEST_SENSE:
@@ -2746,7 +2448,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
sd.key = NO_SENSE;
sd.info = 0;
sd.add_length= 0;
- gdth_copy_internal_data(hanum,scp,(char*)&sd,sizeof(gdth_sense_data));
+ gdth_copy_internal_data(ha, scp, (char*)&sd, sizeof(gdth_sense_data), 0);
break;
case MODE_SENSE:
@@ -2758,7 +2460,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16;
mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8;
mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff);
- gdth_copy_internal_data(hanum,scp,(char*)&mpd,sizeof(gdth_modep_data));
+ gdth_copy_internal_data(ha, scp, (char*)&mpd, sizeof(gdth_modep_data), 0);
break;
case READ_CAPACITY:
@@ -2768,7 +2470,7 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
else
rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1);
rdc.block_length = cpu_to_be32(SECTOR_SIZE);
- gdth_copy_internal_data(hanum,scp,(char*)&rdc,sizeof(gdth_rdcap_data));
+ gdth_copy_internal_data(ha, scp, (char*)&rdc, sizeof(gdth_rdcap_data), 0);
break;
case SERVICE_ACTION_IN:
@@ -2779,7 +2481,8 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
TRACE2(("Read capacity (16) hdrive %d\n",t));
rdc16.last_block_no = cpu_to_be64(ha->hdr[t].size-1);
rdc16.block_length = cpu_to_be32(SECTOR_SIZE);
- gdth_copy_internal_data(hanum,scp,(char*)&rdc16,sizeof(gdth_rdcap16_data));
+ gdth_copy_internal_data(ha, scp, (char*)&rdc16,
+ sizeof(gdth_rdcap16_data), 0);
} else {
scp->result = DID_ABORT << 16;
}
@@ -2790,27 +2493,22 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
break;
}
- if (!scp->SCp.have_data_in)
- scp->SCp.have_data_in++;
+ if (!cmndinfo->wait_for_completion)
+ cmndinfo->wait_for_completion++;
else
return 1;
return 0;
}
-
-static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
+
+static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive)
{
- register gdth_ha_str *ha;
register gdth_cmd_str *cmdp;
- struct scatterlist *sl;
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
ulong32 cnt, blockcnt;
ulong64 no, blockno;
- dma_addr_t phys_addr;
int i, cmd_index, read_write, sgcnt, mode64;
- struct page *page;
- ulong offset;
- ha = HADATA(gdth_ctr_tab[hanum]);
cmdp = ha->pccb;
TRACE(("gdth_fill_cache_cmd() cmd 0x%x cmdsize %d hdrive %d\n",
scp->cmnd[0],scp->cmd_len,hdrive));
@@ -2826,18 +2524,18 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
cmdp->Service = CACHESERVICE;
cmdp->RequestBuffer = scp;
/* search free command index */
- if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+ if (!(cmd_index=gdth_get_cmd_index(ha))) {
TRACE(("GDT: No free command index found\n"));
return 0;
}
/* if it's the first command, set command semaphore */
if (ha->cmd_cnt == 0)
- gdth_set_sema0(hanum);
+ gdth_set_sema0(ha);
/* fill command */
read_write = 0;
- if (scp->SCp.sent_command != -1)
- cmdp->OpCode = scp->SCp.sent_command; /* special cache cmd. */
+ if (cmndinfo->OpCode != -1)
+ cmdp->OpCode = cmndinfo->OpCode; /* special cache cmd. */
else if (scp->cmnd[0] == RESERVE)
cmdp->OpCode = GDT_RESERVE_DRV;
else if (scp->cmnd[0] == RELEASE)
@@ -2898,17 +2596,17 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
cmdp->u.cache.BlockCnt = blockcnt;
}
- if (scp->use_sg) {
- sl = (struct scatterlist *)scp->request_buffer;
- sgcnt = scp->use_sg;
- scp->SCp.Status = GDTH_MAP_SG;
- scp->SCp.Message = (read_write == 1 ?
+ if (gdth_bufflen(scp)) {
+ cmndinfo->dma_dir = (read_write == 1 ?
PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
- sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message);
+ sgcnt = pci_map_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp),
+ cmndinfo->dma_dir);
if (mode64) {
+ struct scatterlist *sl;
+
cmdp->u.cache64.DestAddr= (ulong64)-1;
cmdp->u.cache64.sg_canz = sgcnt;
- for (i=0; i<sgcnt; ++i,++sl) {
+ scsi_for_each_sg(scp, sl, sgcnt, i) {
cmdp->u.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl);
#ifdef GDTH_DMA_STATISTICS
if (cmdp->u.cache64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
@@ -2919,9 +2617,11 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
cmdp->u.cache64.sg_lst[i].sg_len = sg_dma_len(sl);
}
} else {
+ struct scatterlist *sl;
+
cmdp->u.cache.DestAddr= 0xffffffff;
cmdp->u.cache.sg_canz = sgcnt;
- for (i=0; i<sgcnt; ++i,++sl) {
+ scsi_for_each_sg(scp, sl, sgcnt, i) {
cmdp->u.cache.sg_lst[i].sg_ptr = sg_dma_address(sl);
#ifdef GDTH_DMA_STATISTICS
ha->dma32_cnt++;
@@ -2937,38 +2637,6 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
}
#endif
- } else if (scp->request_bufflen) {
- scp->SCp.Status = GDTH_MAP_SINGLE;
- scp->SCp.Message = (read_write == 1 ?
- PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
- page = virt_to_page(scp->request_buffer);
- offset = (ulong)scp->request_buffer & ~PAGE_MASK;
- phys_addr = pci_map_page(ha->pdev,page,offset,
- scp->request_bufflen,scp->SCp.Message);
- scp->SCp.dma_handle = phys_addr;
- if (mode64) {
- if (ha->cache_feat & SCATTER_GATHER) {
- cmdp->u.cache64.DestAddr = (ulong64)-1;
- cmdp->u.cache64.sg_canz = 1;
- cmdp->u.cache64.sg_lst[0].sg_ptr = phys_addr;
- cmdp->u.cache64.sg_lst[0].sg_len = scp->request_bufflen;
- cmdp->u.cache64.sg_lst[1].sg_len = 0;
- } else {
- cmdp->u.cache64.DestAddr = phys_addr;
- cmdp->u.cache64.sg_canz= 0;
- }
- } else {
- if (ha->cache_feat & SCATTER_GATHER) {
- cmdp->u.cache.DestAddr = 0xffffffff;
- cmdp->u.cache.sg_canz = 1;
- cmdp->u.cache.sg_lst[0].sg_ptr = phys_addr;
- cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen;
- cmdp->u.cache.sg_lst[1].sg_len = 0;
- } else {
- cmdp->u.cache.DestAddr = phys_addr;
- cmdp->u.cache.sg_canz= 0;
- }
- }
}
}
/* evaluate command size, check space */
@@ -3004,23 +2672,21 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
}
/* copy command */
- gdth_copy_command(hanum);
+ gdth_copy_command(ha);
return cmd_index;
}
-static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
+static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b)
{
- register gdth_ha_str *ha;
register gdth_cmd_str *cmdp;
- struct scatterlist *sl;
ushort i;
- dma_addr_t phys_addr, sense_paddr;
+ dma_addr_t sense_paddr;
int cmd_index, sgcnt, mode64;
unchar t,l;
struct page *page;
ulong offset;
+ struct gdth_cmndinfo *cmndinfo;
- ha = HADATA(gdth_ctr_tab[hanum]);
t = scp->device->id;
l = scp->device->lun;
cmdp = ha->pccb;
@@ -3035,26 +2701,27 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
cmdp->Service = SCSIRAWSERVICE;
cmdp->RequestBuffer = scp;
/* search free command index */
- if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+ if (!(cmd_index=gdth_get_cmd_index(ha))) {
TRACE(("GDT: No free command index found\n"));
return 0;
}
/* if it's the first command, set command semaphore */
if (ha->cmd_cnt == 0)
- gdth_set_sema0(hanum);
+ gdth_set_sema0(ha);
+ cmndinfo = gdth_cmnd_priv(scp);
/* fill command */
- if (scp->SCp.sent_command != -1) {
- cmdp->OpCode = scp->SCp.sent_command; /* special raw cmd. */
+ if (cmndinfo->OpCode != -1) {
+ cmdp->OpCode = cmndinfo->OpCode; /* special raw cmd. */
cmdp->BoardNode = LOCALBOARD;
if (mode64) {
- cmdp->u.raw64.direction = (scp->SCp.phase >> 8);
+ cmdp->u.raw64.direction = (cmndinfo->phase >> 8);
TRACE2(("special raw cmd 0x%x param 0x%x\n",
cmdp->OpCode, cmdp->u.raw64.direction));
/* evaluate command size */
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst);
} else {
- cmdp->u.raw.direction = (scp->SCp.phase >> 8);
+ cmdp->u.raw.direction = (cmndinfo->phase >> 8);
TRACE2(("special raw cmd 0x%x param 0x%x\n",
cmdp->OpCode, cmdp->u.raw.direction));
/* evaluate command size */
@@ -3066,9 +2733,8 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
offset = (ulong)scp->sense_buffer & ~PAGE_MASK;
sense_paddr = pci_map_page(ha->pdev,page,offset,
16,PCI_DMA_FROMDEVICE);
- *(ulong32 *)&scp->SCp.buffer = (ulong32)sense_paddr;
- /* high part, if 64bit */
- *(ulong32 *)&scp->host_scribble = (ulong32)((ulong64)sense_paddr >> 32);
+
+ cmndinfo->sense_paddr = sense_paddr;
cmdp->OpCode = GDT_WRITE; /* always */
cmdp->BoardNode = LOCALBOARD;
if (mode64) {
@@ -3080,7 +2746,7 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
cmdp->u.raw64.lun = l;
cmdp->u.raw64.bus = b;
cmdp->u.raw64.priority = 0;
- cmdp->u.raw64.sdlen = scp->request_bufflen;
+ cmdp->u.raw64.sdlen = gdth_bufflen(scp);
cmdp->u.raw64.sense_len = 16;
cmdp->u.raw64.sense_data = sense_paddr;
cmdp->u.raw64.direction =
@@ -3097,7 +2763,7 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
cmdp->u.raw.bus = b;
cmdp->u.raw.priority = 0;
cmdp->u.raw.link_p = 0;
- cmdp->u.raw.sdlen = scp->request_bufflen;
+ cmdp->u.raw.sdlen = gdth_bufflen(scp);
cmdp->u.raw.sense_len = 16;
cmdp->u.raw.sense_data = sense_paddr;
cmdp->u.raw.direction =
@@ -3106,16 +2772,16 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
cmdp->u.raw.sg_ranz = 0;
}
- if (scp->use_sg) {
- sl = (struct scatterlist *)scp->request_buffer;
- sgcnt = scp->use_sg;
- scp->SCp.Status = GDTH_MAP_SG;
- scp->SCp.Message = PCI_DMA_BIDIRECTIONAL;
- sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message);
+ if (gdth_bufflen(scp)) {
+ cmndinfo->dma_dir = PCI_DMA_BIDIRECTIONAL;
+ sgcnt = pci_map_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp),
+ cmndinfo->dma_dir);
if (mode64) {
+ struct scatterlist *sl;
+
cmdp->u.raw64.sdata = (ulong64)-1;
cmdp->u.raw64.sg_ranz = sgcnt;
- for (i=0; i<sgcnt; ++i,++sl) {
+ scsi_for_each_sg(scp, sl, sgcnt, i) {
cmdp->u.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl);
#ifdef GDTH_DMA_STATISTICS
if (cmdp->u.raw64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
@@ -3126,9 +2792,11 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
cmdp->u.raw64.sg_lst[i].sg_len = sg_dma_len(sl);
}
} else {
+ struct scatterlist *sl;
+
cmdp->u.raw.sdata = 0xffffffff;
cmdp->u.raw.sg_ranz = sgcnt;
- for (i=0; i<sgcnt; ++i,++sl) {
+ scsi_for_each_sg(scp, sl, sgcnt, i) {
cmdp->u.raw.sg_lst[i].sg_ptr = sg_dma_address(sl);
#ifdef GDTH_DMA_STATISTICS
ha->dma32_cnt++;
@@ -3144,38 +2812,6 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
}
#endif
- } else if (scp->request_bufflen) {
- scp->SCp.Status = GDTH_MAP_SINGLE;
- scp->SCp.Message = PCI_DMA_BIDIRECTIONAL;
- page = virt_to_page(scp->request_buffer);
- offset = (ulong)scp->request_buffer & ~PAGE_MASK;
- phys_addr = pci_map_page(ha->pdev,page,offset,
- scp->request_bufflen,scp->SCp.Message);
- scp->SCp.dma_handle = phys_addr;
-
- if (mode64) {
- if (ha->raw_feat & SCATTER_GATHER) {
- cmdp->u.raw64.sdata = (ulong64)-1;
- cmdp->u.raw64.sg_ranz= 1;
- cmdp->u.raw64.sg_lst[0].sg_ptr = phys_addr;
- cmdp->u.raw64.sg_lst[0].sg_len = scp->request_bufflen;
- cmdp->u.raw64.sg_lst[1].sg_len = 0;
- } else {
- cmdp->u.raw64.sdata = phys_addr;
- cmdp->u.raw64.sg_ranz= 0;
- }
- } else {
- if (ha->raw_feat & SCATTER_GATHER) {
- cmdp->u.raw.sdata = 0xffffffff;
- cmdp->u.raw.sg_ranz= 1;
- cmdp->u.raw.sg_lst[0].sg_ptr = phys_addr;
- cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen;
- cmdp->u.raw.sg_lst[1].sg_len = 0;
- } else {
- cmdp->u.raw.sdata = phys_addr;
- cmdp->u.raw.sg_ranz= 0;
- }
- }
}
if (mode64) {
TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
@@ -3209,35 +2845,33 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
}
/* copy command */
- gdth_copy_command(hanum);
+ gdth_copy_command(ha);
return cmd_index;
}
-static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp)
+static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
{
- register gdth_ha_str *ha;
register gdth_cmd_str *cmdp;
int cmd_index;
- ha = HADATA(gdth_ctr_tab[hanum]);
cmdp= ha->pccb;
TRACE2(("gdth_special_cmd(): "));
if (ha->type==GDT_EISA && ha->cmd_cnt>0)
return 0;
- memcpy( cmdp, scp->request_buffer, sizeof(gdth_cmd_str));
+ gdth_copy_internal_data(ha, scp, (char *)cmdp, sizeof(gdth_cmd_str), 1);
cmdp->RequestBuffer = scp;
/* search free command index */
- if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+ if (!(cmd_index=gdth_get_cmd_index(ha))) {
TRACE(("GDT: No free command index found\n"));
return 0;
}
/* if it's the first command, set command semaphore */
if (ha->cmd_cnt == 0)
- gdth_set_sema0(hanum);
+ gdth_set_sema0(ha);
/* evaluate command size, check space */
if (cmdp->OpCode == GDT_IOCTL) {
@@ -3275,7 +2909,7 @@ static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp)
}
/* copy command */
- gdth_copy_command(hanum);
+ gdth_copy_command(ha);
return cmd_index;
}
@@ -3402,15 +3036,14 @@ static void gdth_clear_events(void)
/* SCSI interface functions */
-static irqreturn_t gdth_interrupt(int irq,void *dev_id)
+static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq,
+ int gdth_from_wait, int* pIndex)
{
- gdth_ha_str *ha2 = (gdth_ha_str *)dev_id;
- register gdth_ha_str *ha;
gdt6m_dpram_str __iomem *dp6m_ptr = NULL;
gdt6_dpram_str __iomem *dp6_ptr;
gdt2_dpram_str __iomem *dp2_ptr;
Scsi_Cmnd *scp;
- int hanum, rval, i;
+ int rval, i;
unchar IStatus;
ushort Service;
ulong flags = 0;
@@ -3431,17 +3064,15 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
}
if (!gdth_polling)
- spin_lock_irqsave(&ha2->smp_lock, flags);
- wait_index = 0;
+ spin_lock_irqsave(&ha->smp_lock, flags);
/* search controller */
- if ((hanum = gdth_get_status(&IStatus,irq)) == -1) {
+ if (0 == (IStatus = gdth_get_status(ha, irq))) {
/* spurious interrupt */
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
- return IRQ_HANDLED;
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
+ return IRQ_HANDLED;
}
- ha = HADATA(gdth_ctr_tab[hanum]);
#ifdef GDTH_STATISTICS
++act_ints;
@@ -3482,32 +3113,32 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
dp2_ptr = ha->brd;
if (IStatus & 0x80) { /* error flag */
IStatus &= ~0x80;
- ha->status = gdth_readw(&dp2_ptr->u.ic.Status);
+ ha->status = readw(&dp2_ptr->u.ic.Status);
TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
} else /* no error */
ha->status = S_OK;
- ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]);
- ha->service = gdth_readw(&dp2_ptr->u.ic.Service);
- ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
+ ha->info = readl(&dp2_ptr->u.ic.Info[0]);
+ ha->service = readw(&dp2_ptr->u.ic.Service);
+ ha->info2 = readl(&dp2_ptr->u.ic.Info[1]);
- gdth_writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */
- gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */
- gdth_writeb(0, &dp2_ptr->io.Sema1); /* reset status semaphore */
+ writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */
+ writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */
+ writeb(0, &dp2_ptr->io.Sema1); /* reset status semaphore */
} else if (ha->type == GDT_PCI) {
dp6_ptr = ha->brd;
if (IStatus & 0x80) { /* error flag */
IStatus &= ~0x80;
- ha->status = gdth_readw(&dp6_ptr->u.ic.Status);
+ ha->status = readw(&dp6_ptr->u.ic.Status);
TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
} else /* no error */
ha->status = S_OK;
- ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]);
- ha->service = gdth_readw(&dp6_ptr->u.ic.Service);
- ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
+ ha->info = readl(&dp6_ptr->u.ic.Info[0]);
+ ha->service = readw(&dp6_ptr->u.ic.Service);
+ ha->info2 = readl(&dp6_ptr->u.ic.Info[1]);
- gdth_writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */
- gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */
- gdth_writeb(0, &dp6_ptr->io.Sema1); /* reset status semaphore */
+ writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */
+ writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */
+ writeb(0, &dp6_ptr->io.Sema1); /* reset status semaphore */
} else if (ha->type == GDT_PCINEW) {
if (IStatus & 0x80) { /* error flag */
IStatus &= ~0x80;
@@ -3530,7 +3161,7 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
ha->status = pcs->ext_status & 0xffff;
else
#endif
- ha->status = gdth_readw(&dp6m_ptr->i960r.status);
+ ha->status = readw(&dp6m_ptr->i960r.status);
TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
} else /* no error */
ha->status = S_OK;
@@ -3543,18 +3174,18 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
} else
#endif
{
- ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]);
- ha->service = gdth_readw(&dp6m_ptr->i960r.service);
- ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
+ ha->info = readl(&dp6m_ptr->i960r.info[0]);
+ ha->service = readw(&dp6m_ptr->i960r.service);
+ ha->info2 = readl(&dp6m_ptr->i960r.info[1]);
}
/* event string */
if (IStatus == ASYNCINDEX) {
if (ha->service != SCREENSERVICE &&
(ha->fw_vers & 0xff) >= 0x1a) {
- ha->dvr.severity = gdth_readb
+ ha->dvr.severity = readb
(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.severity);
for (i = 0; i < 256; ++i) {
- ha->dvr.event_string[i] = gdth_readb
+ ha->dvr.event_string[i] = readb
(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.evt_str[i]);
if (ha->dvr.event_string[i] == 0)
break;
@@ -3567,13 +3198,13 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
if (!coalesced)
#endif
{
- gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
- gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
+ writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+ writeb(0, &dp6m_ptr->i960r.sema1_reg);
}
} else {
TRACE2(("gdth_interrupt() unknown controller type\n"));
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
return IRQ_HANDLED;
}
@@ -3581,26 +3212,25 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
IStatus,ha->status,ha->info));
if (gdth_from_wait) {
- wait_hanum = hanum;
- wait_index = (int)IStatus;
+ *pIndex = (int)IStatus;
}
if (IStatus == ASYNCINDEX) {
TRACE2(("gdth_interrupt() async. event\n"));
- gdth_async_event(hanum);
+ gdth_async_event(ha);
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
- gdth_next(hanum);
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
+ gdth_next(ha);
return IRQ_HANDLED;
}
if (IStatus == SPEZINDEX) {
TRACE2(("Service unknown or not initialized !\n"));
ha->dvr.size = sizeof(ha->dvr.eu.driver);
- ha->dvr.eu.driver.ionode = hanum;
+ ha->dvr.eu.driver.ionode = ha->hanum;
gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr);
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
return IRQ_HANDLED;
}
scp = ha->cmd_tab[IStatus-2].cmnd;
@@ -3609,28 +3239,28 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
if (scp == UNUSED_CMND) {
TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus));
ha->dvr.size = sizeof(ha->dvr.eu.driver);
- ha->dvr.eu.driver.ionode = hanum;
+ ha->dvr.eu.driver.ionode = ha->hanum;
ha->dvr.eu.driver.index = IStatus;
gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr);
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
return IRQ_HANDLED;
}
if (scp == INTERNAL_CMND) {
TRACE(("gdth_interrupt() answer to internal command\n"));
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
return IRQ_HANDLED;
}
TRACE(("gdth_interrupt() sync. status\n"));
- rval = gdth_sync_event(hanum,Service,IStatus,scp);
+ rval = gdth_sync_event(ha,Service,IStatus,scp);
if (!gdth_polling)
- spin_unlock_irqrestore(&ha2->smp_lock, flags);
+ spin_unlock_irqrestore(&ha->smp_lock, flags);
if (rval == 2) {
- gdth_putq(hanum,scp,scp->SCp.this_residual);
+ gdth_putq(ha, scp, gdth_cmnd_priv(scp)->priority);
} else if (rval == 1) {
- scp->scsi_done(scp);
+ gdth_scsi_done(scp);
}
#ifdef INT_COAL
@@ -3653,23 +3283,30 @@ static irqreturn_t gdth_interrupt(int irq,void *dev_id)
/* coalescing only for new GDT_PCIMPR controllers available */
if (ha->type == GDT_PCIMPR && coalesced) {
- gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
- gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
+ writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+ writeb(0, &dp6m_ptr->i960r.sema1_reg);
}
#endif
- gdth_next(hanum);
+ gdth_next(ha);
return IRQ_HANDLED;
}
-static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
+static irqreturn_t gdth_interrupt(int irq, void *dev_id)
+{
+ gdth_ha_str *ha = (gdth_ha_str *)dev_id;
+
+ return __gdth_interrupt(ha, irq, false, NULL);
+}
+
+static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index,
+ Scsi_Cmnd *scp)
{
- register gdth_ha_str *ha;
gdth_msg_str *msg;
gdth_cmd_str *cmdp;
unchar b, t;
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
- ha = HADATA(gdth_ctr_tab[hanum]);
cmdp = ha->pccb;
TRACE(("gdth_sync_event() serv %d status %d\n",
service,ha->status));
@@ -3687,12 +3324,12 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
}
if (msg->msg_ext && !msg->msg_answer) {
- while (gdth_test_busy(hanum))
+ while (gdth_test_busy(ha))
gdth_delay(0);
cmdp->Service = SCREENSERVICE;
cmdp->RequestBuffer = SCREEN_CMND;
- gdth_get_cmd_index(hanum);
- gdth_set_sema0(hanum);
+ gdth_get_cmd_index(ha);
+ gdth_set_sema0(ha);
cmdp->OpCode = GDT_READ;
cmdp->BoardNode = LOCALBOARD;
cmdp->u.screen.reserved = 0;
@@ -3702,8 +3339,8 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr)
+ sizeof(ulong64);
ha->cmd_cnt = 0;
- gdth_copy_command(hanum);
- gdth_release_event(hanum);
+ gdth_copy_command(ha);
+ gdth_release_event(ha);
return 0;
}
@@ -3721,12 +3358,12 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
}
msg->msg_ext = 0;
msg->msg_answer = 0;
- while (gdth_test_busy(hanum))
+ while (gdth_test_busy(ha))
gdth_delay(0);
cmdp->Service = SCREENSERVICE;
cmdp->RequestBuffer = SCREEN_CMND;
- gdth_get_cmd_index(hanum);
- gdth_set_sema0(hanum);
+ gdth_get_cmd_index(ha);
+ gdth_set_sema0(ha);
cmdp->OpCode = GDT_WRITE;
cmdp->BoardNode = LOCALBOARD;
cmdp->u.screen.reserved = 0;
@@ -3736,74 +3373,67 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr)
+ sizeof(ulong64);
ha->cmd_cnt = 0;
- gdth_copy_command(hanum);
- gdth_release_event(hanum);
+ gdth_copy_command(ha);
+ gdth_release_event(ha);
return 0;
}
printk("\n");
} else {
- b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+ b = scp->device->channel;
t = scp->device->id;
- if (scp->SCp.sent_command == -1 && b != ha->virt_bus) {
+ if (cmndinfo->OpCode == -1 && b != ha->virt_bus) {
ha->raw[BUS_L2P(ha,b)].io_cnt[t]--;
}
/* cache or raw service */
if (ha->status == S_BSY) {
TRACE2(("Controller busy -> retry !\n"));
- if (scp->SCp.sent_command == GDT_MOUNT)
- scp->SCp.sent_command = GDT_CLUST_INFO;
+ if (cmndinfo->OpCode == GDT_MOUNT)
+ cmndinfo->OpCode = GDT_CLUST_INFO;
/* retry */
return 2;
}
- if (scp->SCp.Status == GDTH_MAP_SG)
- pci_unmap_sg(ha->pdev,scp->request_buffer,
- scp->use_sg,scp->SCp.Message);
- else if (scp->SCp.Status == GDTH_MAP_SINGLE)
- pci_unmap_page(ha->pdev,scp->SCp.dma_handle,
- scp->request_bufflen,scp->SCp.Message);
- if (scp->SCp.buffer) {
- dma_addr_t addr;
- addr = (dma_addr_t)*(ulong32 *)&scp->SCp.buffer;
- if (scp->host_scribble)
- addr += (dma_addr_t)
- ((ulong64)(*(ulong32 *)&scp->host_scribble) << 32);
- pci_unmap_page(ha->pdev,addr,16,PCI_DMA_FROMDEVICE);
- }
+ if (gdth_bufflen(scp))
+ pci_unmap_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp),
+ cmndinfo->dma_dir);
+
+ if (cmndinfo->sense_paddr)
+ pci_unmap_page(ha->pdev, cmndinfo->sense_paddr, 16,
+ PCI_DMA_FROMDEVICE);
if (ha->status == S_OK) {
- scp->SCp.Status = S_OK;
- scp->SCp.Message = ha->info;
- if (scp->SCp.sent_command != -1) {
+ cmndinfo->status = S_OK;
+ cmndinfo->info = ha->info;
+ if (cmndinfo->OpCode != -1) {
TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n",
- scp->SCp.sent_command));
+ cmndinfo->OpCode));
/* special commands GDT_CLUST_INFO/GDT_MOUNT ? */
- if (scp->SCp.sent_command == GDT_CLUST_INFO) {
+ if (cmndinfo->OpCode == GDT_CLUST_INFO) {
ha->hdr[t].cluster_type = (unchar)ha->info;
if (!(ha->hdr[t].cluster_type &
CLUSTER_MOUNTED)) {
/* NOT MOUNTED -> MOUNT */
- scp->SCp.sent_command = GDT_MOUNT;
+ cmndinfo->OpCode = GDT_MOUNT;
if (ha->hdr[t].cluster_type &
CLUSTER_RESERVED) {
/* cluster drive RESERVED (on the other node) */
- scp->SCp.phase = -2; /* reservation conflict */
+ cmndinfo->phase = -2; /* reservation conflict */
}
} else {
- scp->SCp.sent_command = -1;
+ cmndinfo->OpCode = -1;
}
} else {
- if (scp->SCp.sent_command == GDT_MOUNT) {
+ if (cmndinfo->OpCode == GDT_MOUNT) {
ha->hdr[t].cluster_type |= CLUSTER_MOUNTED;
ha->hdr[t].media_changed = TRUE;
- } else if (scp->SCp.sent_command == GDT_UNMOUNT) {
+ } else if (cmndinfo->OpCode == GDT_UNMOUNT) {
ha->hdr[t].cluster_type &= ~CLUSTER_MOUNTED;
ha->hdr[t].media_changed = TRUE;
}
- scp->SCp.sent_command = -1;
+ cmndinfo->OpCode = -1;
}
/* retry */
- scp->SCp.this_residual = HIGH_PRI;
+ cmndinfo->priority = HIGH_PRI;
return 2;
} else {
/* RESERVE/RELEASE ? */
@@ -3816,17 +3446,17 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
scp->sense_buffer[0] = 0;
}
} else {
- scp->SCp.Status = ha->status;
- scp->SCp.Message = ha->info;
+ cmndinfo->status = ha->status;
+ cmndinfo->info = ha->info;
- if (scp->SCp.sent_command != -1) {
+ if (cmndinfo->OpCode != -1) {
TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n",
- scp->SCp.sent_command, ha->status));
- if (scp->SCp.sent_command == GDT_SCAN_START ||
- scp->SCp.sent_command == GDT_SCAN_END) {
- scp->SCp.sent_command = -1;
+ cmndinfo->OpCode, ha->status));
+ if (cmndinfo->OpCode == GDT_SCAN_START ||
+ cmndinfo->OpCode == GDT_SCAN_END) {
+ cmndinfo->OpCode = -1;
/* retry */
- scp->SCp.this_residual = HIGH_PRI;
+ cmndinfo->priority = HIGH_PRI;
return 2;
}
memset((char*)scp->sense_buffer,0,16);
@@ -3848,9 +3478,9 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
scp->sense_buffer[2] = NOT_READY;
scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
}
- if (scp->done != gdth_scsi_done) {
+ if (!cmndinfo->internal_command) {
ha->dvr.size = sizeof(ha->dvr.eu.sync);
- ha->dvr.eu.sync.ionode = hanum;
+ ha->dvr.eu.sync.ionode = ha->hanum;
ha->dvr.eu.sync.service = service;
ha->dvr.eu.sync.status = ha->status;
ha->dvr.eu.sync.info = ha->info;
@@ -3869,8 +3499,8 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
}
}
}
- if (!scp->SCp.have_data_in)
- scp->SCp.have_data_in++;
+ if (!cmndinfo->wait_for_completion)
+ cmndinfo->wait_for_completion++;
else
return 1;
}
@@ -4034,25 +3664,23 @@ static char *async_cache_tab[] = {
};
-static int gdth_async_event(int hanum)
+static int gdth_async_event(gdth_ha_str *ha)
{
- gdth_ha_str *ha;
gdth_cmd_str *cmdp;
int cmd_index;
- ha = HADATA(gdth_ctr_tab[hanum]);
cmdp= ha->pccb;
TRACE2(("gdth_async_event() ha %d serv %d\n",
- hanum,ha->service));
+ ha->hanum, ha->service));
if (ha->service == SCREENSERVICE) {
if (ha->status == MSG_REQUEST) {
- while (gdth_test_busy(hanum))
+ while (gdth_test_busy(ha))
gdth_delay(0);
cmdp->Service = SCREENSERVICE;
cmdp->RequestBuffer = SCREEN_CMND;
- cmd_index = gdth_get_cmd_index(hanum);
- gdth_set_sema0(hanum);
+ cmd_index = gdth_get_cmd_index(ha);
+ gdth_set_sema0(ha);
cmdp->OpCode = GDT_READ;
cmdp->BoardNode = LOCALBOARD;
cmdp->u.screen.reserved = 0;
@@ -4062,7 +3690,7 @@ static int gdth_async_event(int hanum)
ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr)
+ sizeof(ulong64);
ha->cmd_cnt = 0;
- gdth_copy_command(hanum);
+ gdth_copy_command(ha);
if (ha->type == GDT_EISA)
printk("[EISA slot %d] ",(ushort)ha->brd_phys);
else if (ha->type == GDT_ISA)
@@ -4070,19 +3698,19 @@ static int gdth_async_event(int hanum)
else
printk("[PCI %d/%d] ",(ushort)(ha->brd_phys>>8),
(ushort)((ha->brd_phys>>3)&0x1f));
- gdth_release_event(hanum);
+ gdth_release_event(ha);
}
} else {
if (ha->type == GDT_PCIMPR &&
(ha->fw_vers & 0xff) >= 0x1a) {
ha->dvr.size = 0;
- ha->dvr.eu.async.ionode = hanum;
+ ha->dvr.eu.async.ionode = ha->hanum;
ha->dvr.eu.async.status = ha->status;
/* severity and event_string already set! */
} else {
ha->dvr.size = sizeof(ha->dvr.eu.async);
- ha->dvr.eu.async.ionode = hanum;
+ ha->dvr.eu.async.ionode = ha->hanum;
ha->dvr.eu.async.service = ha->service;
ha->dvr.eu.async.status = ha->status;
ha->dvr.eu.async.info = ha->info;
@@ -4164,9 +3792,8 @@ static void gdth_timeout(ulong data)
Scsi_Cmnd *nscp;
gdth_ha_str *ha;
ulong flags;
- int hanum = 0;
- ha = HADATA(gdth_ctr_tab[hanum]);
+ ha = list_first_entry(&gdth_instances, gdth_ha_str, list);
spin_lock_irqsave(&ha->smp_lock, flags);
for (act_stats=0,i=0; i<GDTH_MAXCMDS; ++i)
@@ -4229,8 +3856,6 @@ static void __init internal_setup(char *str,int *ints)
max_ids = val;
else if (!strncmp(argv, "rescan:", 7))
rescan = val;
- else if (!strncmp(argv, "virt_ctr:", 9))
- virt_ctr = val;
else if (!strncmp(argv, "shared_access:", 14))
shared_access = val;
else if (!strncmp(argv, "probe_eisa_isa:", 15))
@@ -4277,523 +3902,10 @@ int __init option_setup(char *str)
return 1;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-static int __init gdth_detect(struct scsi_host_template *shtp)
-#else
-static int __init gdth_detect(Scsi_Host_Template *shtp)
-#endif
-{
- struct Scsi_Host *shp;
- gdth_pci_str pcistr[MAXHA];
- gdth_ha_str *ha;
- ulong32 isa_bios;
- ushort eisa_slot;
- int i,hanum,cnt,ctr,err;
- unchar b;
-
-
-#ifdef DEBUG_GDTH
- printk("GDT: This driver contains debugging information !! Trace level = %d\n",
- DebugState);
- printk(" Destination of debugging information: ");
-#ifdef __SERIAL__
-#ifdef __COM2__
- printk("Serial port COM2\n");
-#else
- printk("Serial port COM1\n");
-#endif
-#else
- printk("Console\n");
-#endif
- gdth_delay(3000);
-#endif
-
- TRACE(("gdth_detect()\n"));
-
- if (disable) {
- printk("GDT-HA: Controller driver disabled from command line !\n");
- return 0;
- }
-
- printk("GDT-HA: Storage RAID Controller Driver. Version: %s\n",GDTH_VERSION_STR);
- /* initializations */
- gdth_polling = TRUE; b = 0;
- gdth_clear_events();
-
- /* As default we do not probe for EISA or ISA controllers */
- if (probe_eisa_isa) {
- /* scanning for controllers, at first: ISA controller */
- for (isa_bios=0xc8000UL; isa_bios<=0xd8000UL; isa_bios+=0x8000UL) {
- dma_addr_t scratch_dma_handle;
- scratch_dma_handle = 0;
-
- if (gdth_ctr_count >= MAXHA)
- break;
- if (gdth_search_isa(isa_bios)) { /* controller found */
- shp = scsi_register(shtp,sizeof(gdth_ext_str));
- if (shp == NULL)
- continue;
-
- ha = HADATA(shp);
- if (!gdth_init_isa(isa_bios,ha)) {
- scsi_unregister(shp);
- continue;
- }
-#ifdef __ia64__
- break;
-#else
- /* controller found and initialized */
- printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
- isa_bios,ha->irq,ha->drq);
-
- if (request_irq(ha->irq,gdth_interrupt,IRQF_DISABLED,"gdth",ha)) {
- printk("GDT-ISA: Unable to allocate IRQ\n");
- scsi_unregister(shp);
- continue;
- }
- if (request_dma(ha->drq,"gdth")) {
- printk("GDT-ISA: Unable to allocate DMA channel\n");
- free_irq(ha->irq,ha);
- scsi_unregister(shp);
- continue;
- }
- set_dma_mode(ha->drq,DMA_MODE_CASCADE);
- enable_dma(ha->drq);
- shp->unchecked_isa_dma = 1;
- shp->irq = ha->irq;
- shp->dma_channel = ha->drq;
- hanum = gdth_ctr_count;
- gdth_ctr_tab[gdth_ctr_count++] = shp;
- gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-
- NUMDATA(shp)->hanum = (ushort)hanum;
- NUMDATA(shp)->busnum= 0;
-
- ha->pccb = CMDDATA(shp);
- ha->ccb_phys = 0L;
- ha->pdev = NULL;
- ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
- &scratch_dma_handle);
- ha->scratch_phys = scratch_dma_handle;
- ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
- &scratch_dma_handle);
- ha->msg_phys = scratch_dma_handle;
-#ifdef INT_COAL
- ha->coal_stat = (gdth_coal_status *)
- pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, &scratch_dma_handle);
- ha->coal_stat_phys = scratch_dma_handle;
-#endif
-
- ha->scratch_busy = FALSE;
- ha->req_first = NULL;
- ha->tid_cnt = MAX_HDRIVES;
- if (max_ids > 0 && max_ids < ha->tid_cnt)
- ha->tid_cnt = max_ids;
- for (i=0; i<GDTH_MAXCMDS; ++i)
- ha->cmd_tab[i].cmnd = UNUSED_CMND;
- ha->scan_mode = rescan ? 0x10 : 0;
-
- if (ha->pscratch == NULL || ha->pmsg == NULL ||
- !gdth_search_drives(hanum)) {
- printk("GDT-ISA: Error during device scan\n");
- --gdth_ctr_count;
- --gdth_ctr_vcount;
-
-#ifdef INT_COAL
- if (ha->coal_stat)
- pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, ha->coal_stat,
- ha->coal_stat_phys);
-#endif
- if (ha->pscratch)
- pci_free_consistent(ha->pdev, GDTH_SCRATCH,
- ha->pscratch, ha->scratch_phys);
- if (ha->pmsg)
- pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
- ha->pmsg, ha->msg_phys);
-
- free_irq(ha->irq,ha);
- scsi_unregister(shp);
- continue;
- }
- if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
- hdr_channel = ha->bus_cnt;
- ha->virt_bus = hdr_channel;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \
- LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- shp->highmem_io = 0;
-#endif
- if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT)
- shp->max_cmd_len = 16;
-
- shp->max_id = ha->tid_cnt;
- shp->max_lun = MAXLUN;
- shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
- if (virt_ctr) {
- virt_ctr = 1;
- /* register addit. SCSI channels as virtual controllers */
- for (b = 1; b < ha->bus_cnt + 1; ++b) {
- shp = scsi_register(shtp,sizeof(gdth_num_str));
- shp->unchecked_isa_dma = 1;
- shp->irq = ha->irq;
- shp->dma_channel = ha->drq;
- gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
- NUMDATA(shp)->hanum = (ushort)hanum;
- NUMDATA(shp)->busnum = b;
- }
- }
-
- spin_lock_init(&ha->smp_lock);
- gdth_enable_int(hanum);
-#endif /* !__ia64__ */
- }
- }
-
- /* scanning for EISA controllers */
- for (eisa_slot=0x1000; eisa_slot<=0x8000; eisa_slot+=0x1000) {
- dma_addr_t scratch_dma_handle;
- scratch_dma_handle = 0;
-
- if (gdth_ctr_count >= MAXHA)
- break;
- if (gdth_search_eisa(eisa_slot)) { /* controller found */
- shp = scsi_register(shtp,sizeof(gdth_ext_str));
- if (shp == NULL)
- continue;
-
- ha = HADATA(shp);
- if (!gdth_init_eisa(eisa_slot,ha)) {
- scsi_unregister(shp);
- continue;
- }
- /* controller found and initialized */
- printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
- eisa_slot>>12,ha->irq);
-
- if (request_irq(ha->irq,gdth_interrupt,IRQF_DISABLED,"gdth",ha)) {
- printk("GDT-EISA: Unable to allocate IRQ\n");
- scsi_unregister(shp);
- continue;
- }
- shp->unchecked_isa_dma = 0;
- shp->irq = ha->irq;
- shp->dma_channel = 0xff;
- hanum = gdth_ctr_count;
- gdth_ctr_tab[gdth_ctr_count++] = shp;
- gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-
- NUMDATA(shp)->hanum = (ushort)hanum;
- NUMDATA(shp)->busnum= 0;
- TRACE2(("EISA detect Bus 0: hanum %d\n",
- NUMDATA(shp)->hanum));
-
- ha->pccb = CMDDATA(shp);
- ha->ccb_phys = 0L;
-
- ha->pdev = NULL;
- ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
- &scratch_dma_handle);
- ha->scratch_phys = scratch_dma_handle;
- ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
- &scratch_dma_handle);
- ha->msg_phys = scratch_dma_handle;
-#ifdef INT_COAL
- ha->coal_stat = (gdth_coal_status *)
- pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, &scratch_dma_handle);
- ha->coal_stat_phys = scratch_dma_handle;
-#endif
- ha->ccb_phys =
- pci_map_single(ha->pdev,ha->pccb,
- sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
- ha->scratch_busy = FALSE;
- ha->req_first = NULL;
- ha->tid_cnt = MAX_HDRIVES;
- if (max_ids > 0 && max_ids < ha->tid_cnt)
- ha->tid_cnt = max_ids;
- for (i=0; i<GDTH_MAXCMDS; ++i)
- ha->cmd_tab[i].cmnd = UNUSED_CMND;
- ha->scan_mode = rescan ? 0x10 : 0;
-
- if (ha->pscratch == NULL || ha->pmsg == NULL ||
- !gdth_search_drives(hanum)) {
- printk("GDT-EISA: Error during device scan\n");
- --gdth_ctr_count;
- --gdth_ctr_vcount;
-#ifdef INT_COAL
- if (ha->coal_stat)
- pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, ha->coal_stat,
- ha->coal_stat_phys);
-#endif
- if (ha->pscratch)
- pci_free_consistent(ha->pdev, GDTH_SCRATCH,
- ha->pscratch, ha->scratch_phys);
- if (ha->pmsg)
- pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
- ha->pmsg, ha->msg_phys);
- if (ha->ccb_phys)
- pci_unmap_single(ha->pdev,ha->ccb_phys,
- sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
- free_irq(ha->irq,ha);
- scsi_unregister(shp);
- continue;
- }
- if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
- hdr_channel = ha->bus_cnt;
- ha->virt_bus = hdr_channel;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \
- LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- shp->highmem_io = 0;
-#endif
- if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT)
- shp->max_cmd_len = 16;
-
- shp->max_id = ha->tid_cnt;
- shp->max_lun = MAXLUN;
- shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
- if (virt_ctr) {
- virt_ctr = 1;
- /* register addit. SCSI channels as virtual controllers */
- for (b = 1; b < ha->bus_cnt + 1; ++b) {
- shp = scsi_register(shtp,sizeof(gdth_num_str));
- shp->unchecked_isa_dma = 0;
- shp->irq = ha->irq;
- shp->dma_channel = 0xff;
- gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
- NUMDATA(shp)->hanum = (ushort)hanum;
- NUMDATA(shp)->busnum = b;
- }
- }
-
- spin_lock_init(&ha->smp_lock);
- gdth_enable_int(hanum);
- }
- }
- }
-
- /* scanning for PCI controllers */
- cnt = gdth_search_pci(pcistr);
- printk("GDT-HA: Found %d PCI Storage RAID Controllers\n",cnt);
- gdth_sort_pci(pcistr,cnt);
- for (ctr = 0; ctr < cnt; ++ctr) {
- dma_addr_t scratch_dma_handle;
- scratch_dma_handle = 0;
-
- if (gdth_ctr_count >= MAXHA)
- break;
- shp = scsi_register(shtp,sizeof(gdth_ext_str));
- if (shp == NULL)
- continue;
-
- ha = HADATA(shp);
- if (!gdth_init_pci(&pcistr[ctr],ha)) {
- scsi_unregister(shp);
- continue;
- }
- /* controller found and initialized */
- printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
- pcistr[ctr].pdev->bus->number,
- PCI_SLOT(pcistr[ctr].pdev->devfn), ha->irq);
-
- if (request_irq(ha->irq, gdth_interrupt,
- IRQF_DISABLED|IRQF_SHARED, "gdth", ha))
- {
- printk("GDT-PCI: Unable to allocate IRQ\n");
- scsi_unregister(shp);
- continue;
- }
- shp->unchecked_isa_dma = 0;
- shp->irq = ha->irq;
- shp->dma_channel = 0xff;
- hanum = gdth_ctr_count;
- gdth_ctr_tab[gdth_ctr_count++] = shp;
- gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-
- NUMDATA(shp)->hanum = (ushort)hanum;
- NUMDATA(shp)->busnum= 0;
-
- ha->pccb = CMDDATA(shp);
- ha->ccb_phys = 0L;
-
- ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
- &scratch_dma_handle);
- ha->scratch_phys = scratch_dma_handle;
- ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
- &scratch_dma_handle);
- ha->msg_phys = scratch_dma_handle;
-#ifdef INT_COAL
- ha->coal_stat = (gdth_coal_status *)
- pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, &scratch_dma_handle);
- ha->coal_stat_phys = scratch_dma_handle;
-#endif
- ha->scratch_busy = FALSE;
- ha->req_first = NULL;
- ha->tid_cnt = pcistr[ctr].pdev->device >= 0x200 ? MAXID : MAX_HDRIVES;
- if (max_ids > 0 && max_ids < ha->tid_cnt)
- ha->tid_cnt = max_ids;
- for (i=0; i<GDTH_MAXCMDS; ++i)
- ha->cmd_tab[i].cmnd = UNUSED_CMND;
- ha->scan_mode = rescan ? 0x10 : 0;
-
- err = FALSE;
- if (ha->pscratch == NULL || ha->pmsg == NULL ||
- !gdth_search_drives(hanum)) {
- err = TRUE;
- } else {
- if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
- hdr_channel = ha->bus_cnt;
- ha->virt_bus = hdr_channel;
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- scsi_set_pci_device(shp, pcistr[ctr].pdev);
-#endif
- if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat &GDT_64BIT)||
- /* 64-bit DMA only supported from FW >= x.43 */
- (!ha->dma64_support)) {
- if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING "GDT-PCI %d: Unable to set 32-bit DMA\n", hanum);
- err = TRUE;
- }
- } else {
- shp->max_cmd_len = 16;
- if (!pci_set_dma_mask(pcistr[ctr].pdev, DMA_64BIT_MASK)) {
- printk("GDT-PCI %d: 64-bit DMA enabled\n", hanum);
- } else if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING "GDT-PCI %d: Unable to set 64/32-bit DMA\n", hanum);
- err = TRUE;
- }
- }
- }
-
- if (err) {
- printk("GDT-PCI %d: Error during device scan\n", hanum);
- --gdth_ctr_count;
- --gdth_ctr_vcount;
-#ifdef INT_COAL
- if (ha->coal_stat)
- pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, ha->coal_stat,
- ha->coal_stat_phys);
-#endif
- if (ha->pscratch)
- pci_free_consistent(ha->pdev, GDTH_SCRATCH,
- ha->pscratch, ha->scratch_phys);
- if (ha->pmsg)
- pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
- ha->pmsg, ha->msg_phys);
- free_irq(ha->irq,ha);
- scsi_unregister(shp);
- continue;
- }
-
- shp->max_id = ha->tid_cnt;
- shp->max_lun = MAXLUN;
- shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
- if (virt_ctr) {
- virt_ctr = 1;
- /* register addit. SCSI channels as virtual controllers */
- for (b = 1; b < ha->bus_cnt + 1; ++b) {
- shp = scsi_register(shtp,sizeof(gdth_num_str));
- shp->unchecked_isa_dma = 0;
- shp->irq = ha->irq;
- shp->dma_channel = 0xff;
- gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
- NUMDATA(shp)->hanum = (ushort)hanum;
- NUMDATA(shp)->busnum = b;
- }
- }
-
- spin_lock_init(&ha->smp_lock);
- gdth_enable_int(hanum);
- }
-
- TRACE2(("gdth_detect() %d controller detected\n",gdth_ctr_count));
- if (gdth_ctr_count > 0) {
-#ifdef GDTH_STATISTICS
- TRACE2(("gdth_detect(): Initializing timer !\n"));
- init_timer(&gdth_timer);
- gdth_timer.expires = jiffies + HZ;
- gdth_timer.data = 0L;
- gdth_timer.function = gdth_timeout;
- add_timer(&gdth_timer);
-#endif
- major = register_chrdev(0,"gdth",&gdth_fops);
- notifier_disabled = 0;
- register_reboot_notifier(&gdth_notifier);
- }
- gdth_polling = FALSE;
- return gdth_ctr_vcount;
-}
-
-static int gdth_release(struct Scsi_Host *shp)
-{
- int hanum;
- gdth_ha_str *ha;
-
- TRACE2(("gdth_release()\n"));
- if (NUMDATA(shp)->busnum == 0) {
- hanum = NUMDATA(shp)->hanum;
- ha = HADATA(gdth_ctr_tab[hanum]);
- if (ha->sdev) {
- scsi_free_host_dev(ha->sdev);
- ha->sdev = NULL;
- }
- gdth_flush(hanum);
-
- if (shp->irq) {
- free_irq(shp->irq,ha);
- }
-#ifndef __ia64__
- if (shp->dma_channel != 0xff) {
- free_dma(shp->dma_channel);
- }
-#endif
-#ifdef INT_COAL
- if (ha->coal_stat)
- pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
- MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys);
-#endif
- if (ha->pscratch)
- pci_free_consistent(ha->pdev, GDTH_SCRATCH,
- ha->pscratch, ha->scratch_phys);
- if (ha->pmsg)
- pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
- ha->pmsg, ha->msg_phys);
- if (ha->ccb_phys)
- pci_unmap_single(ha->pdev,ha->ccb_phys,
- sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
- gdth_ctr_released++;
- TRACE2(("gdth_release(): HA %d of %d\n",
- gdth_ctr_released, gdth_ctr_count));
-
- if (gdth_ctr_released == gdth_ctr_count) {
-#ifdef GDTH_STATISTICS
- del_timer(&gdth_timer);
-#endif
- unregister_chrdev(major,"gdth");
- unregister_reboot_notifier(&gdth_notifier);
- }
- }
-
- scsi_unregister(shp);
- return 0;
-}
-
-
-static const char *gdth_ctr_name(int hanum)
+static const char *gdth_ctr_name(gdth_ha_str *ha)
{
- gdth_ha_str *ha;
-
TRACE2(("gdth_ctr_name()\n"));
- ha = HADATA(gdth_ctr_tab[hanum]);
-
if (ha->type == GDT_EISA) {
switch (ha->stype) {
case GDT3_ID:
@@ -4820,29 +3932,23 @@ static const char *gdth_ctr_name(int hanum)
static const char *gdth_info(struct Scsi_Host *shp)
{
- int hanum;
- gdth_ha_str *ha;
+ gdth_ha_str *ha = shost_priv(shp);
TRACE2(("gdth_info()\n"));
- hanum = NUMDATA(shp)->hanum;
- ha = HADATA(gdth_ctr_tab[hanum]);
-
return ((const char *)ha->binfo.type_string);
}
static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
{
- int i, hanum;
- gdth_ha_str *ha;
+ gdth_ha_str *ha = shost_priv(scp->device->host);
+ int i;
ulong flags;
Scsi_Cmnd *cmnd;
unchar b;
TRACE2(("gdth_eh_bus_reset()\n"));
- hanum = NUMDATA(scp->device->host)->hanum;
- b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
- ha = HADATA(gdth_ctr_tab[hanum]);
+ b = scp->device->channel;
/* clear command tab */
spin_lock_irqsave(&ha->smp_lock, flags);
@@ -4859,9 +3965,9 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
if (ha->hdr[i].present) {
spin_lock_irqsave(&ha->smp_lock, flags);
gdth_polling = TRUE;
- while (gdth_test_busy(hanum))
+ while (gdth_test_busy(ha))
gdth_delay(0);
- if (gdth_internal_cmd(hanum, CACHESERVICE,
+ if (gdth_internal_cmd(ha, CACHESERVICE,
GDT_CLUST_RESET, i, 0, 0))
ha->hdr[i].cluster_type &= ~CLUSTER_RESERVED;
gdth_polling = FALSE;
@@ -4874,9 +3980,9 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
for (i = 0; i < MAXID; ++i)
ha->raw[BUS_L2P(ha,b)].io_cnt[i] = 0;
gdth_polling = TRUE;
- while (gdth_test_busy(hanum))
+ while (gdth_test_busy(ha))
gdth_delay(0);
- gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS,
+ gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESET_BUS,
BUS_L2P(ha,b), 0, 0);
gdth_polling = FALSE;
spin_unlock_irqrestore(&ha->smp_lock, flags);
@@ -4884,30 +3990,18 @@ static int gdth_eh_bus_reset(Scsi_Cmnd *scp)
return SUCCESS;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
static int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip)
-#else
-static int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
-#endif
{
unchar b, t;
- int hanum;
- gdth_ha_str *ha;
+ gdth_ha_str *ha = shost_priv(sdev->host);
struct scsi_device *sd;
unsigned capacity;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
sd = sdev;
capacity = cap;
-#else
- sd = disk->device;
- capacity = disk->capacity;
-#endif
- hanum = NUMDATA(sd->host)->hanum;
- b = virt_ctr ? NUMDATA(sd->host)->busnum : sd->channel;
+ b = sd->channel;
t = sd->id;
- TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", hanum, b, t));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", ha->hanum, b, t));
if (b != ha->virt_bus || ha->hdr[t].heads == 0) {
/* raw device or host drive without mapping information */
@@ -4925,33 +4019,42 @@ static int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
}
-static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
+static int gdth_queuecommand(struct scsi_cmnd *scp,
+ void (*done)(struct scsi_cmnd *))
{
- int hanum;
- int priority;
+ gdth_ha_str *ha = shost_priv(scp->device->host);
+ struct gdth_cmndinfo *cmndinfo;
TRACE(("gdth_queuecommand() cmd 0x%x\n", scp->cmnd[0]));
-
- scp->scsi_done = (void *)done;
- scp->SCp.have_data_in = 1;
- scp->SCp.phase = -1;
- scp->SCp.sent_command = -1;
- scp->SCp.Status = GDTH_MAP_NONE;
- scp->SCp.buffer = (struct scatterlist *)NULL;
-
- hanum = NUMDATA(scp->device->host)->hanum;
+
+ cmndinfo = gdth_get_cmndinfo(ha);
+ BUG_ON(!cmndinfo);
+
+ scp->scsi_done = done;
+ gdth_update_timeout(scp, scp->timeout_per_command * 6);
+ cmndinfo->priority = DEFAULT_PRI;
+
+ gdth_set_bufflen(scp, scsi_bufflen(scp));
+ gdth_set_sg_count(scp, scsi_sg_count(scp));
+ gdth_set_sglist(scp, scsi_sglist(scp));
+
+ return __gdth_queuecommand(ha, scp, cmndinfo);
+}
+
+static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp,
+ struct gdth_cmndinfo *cmndinfo)
+{
+ scp->host_scribble = (unsigned char *)cmndinfo;
+ cmndinfo->wait_for_completion = 1;
+ cmndinfo->phase = -1;
+ cmndinfo->OpCode = -1;
+
#ifdef GDTH_STATISTICS
++act_ios;
#endif
- priority = DEFAULT_PRI;
- if (scp->done == gdth_scsi_done)
- priority = scp->SCp.this_residual;
- else
- gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
-
- gdth_putq( hanum, scp, priority );
- gdth_next( hanum );
+ gdth_putq(ha, scp, cmndinfo->priority);
+ gdth_next(ha);
return 0;
}
@@ -4959,12 +4062,10 @@ static int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
static int gdth_open(struct inode *inode, struct file *filep)
{
gdth_ha_str *ha;
- int i;
- for (i = 0; i < gdth_ctr_count; i++) {
- ha = HADATA(gdth_ctr_tab[i]);
+ list_for_each_entry(ha, &gdth_instances, list) {
if (!ha->sdev)
- ha->sdev = scsi_get_host_dev(gdth_ctr_tab[i]);
+ ha->sdev = scsi_get_host_dev(ha->shost);
}
TRACE(("gdth_open()\n"));
@@ -4983,10 +4084,11 @@ static int ioc_event(void __user *arg)
gdth_ha_str *ha;
ulong flags;
- if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event)) ||
- evt.ionode >= gdth_ctr_count)
+ if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event)))
+ return -EFAULT;
+ ha = gdth_find_ha(evt.ionode);
+ if (!ha)
return -EFAULT;
- ha = HADATA(gdth_ctr_tab[evt.ionode]);
if (evt.erase == 0xff) {
if (evt.event.event_source == ES_TEST)
@@ -5020,11 +4122,12 @@ static int ioc_lockdrv(void __user *arg)
ulong flags;
gdth_ha_str *ha;
- if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv)) ||
- ldrv.ionode >= gdth_ctr_count)
+ if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv)))
return -EFAULT;
- ha = HADATA(gdth_ctr_tab[ldrv.ionode]);
-
+ ha = gdth_find_ha(ldrv.ionode);
+ if (!ha)
+ return -EFAULT;
+
for (i = 0; i < ldrv.drive_cnt && i < MAX_HDRIVES; ++i) {
j = ldrv.drives[i];
if (j >= MAX_HDRIVES || !ha->hdr[j].present)
@@ -5033,14 +4136,14 @@ static int ioc_lockdrv(void __user *arg)
spin_lock_irqsave(&ha->smp_lock, flags);
ha->hdr[j].lock = 1;
spin_unlock_irqrestore(&ha->smp_lock, flags);
- gdth_wait_completion(ldrv.ionode, ha->bus_cnt, j);
- gdth_stop_timeout(ldrv.ionode, ha->bus_cnt, j);
+ gdth_wait_completion(ha, ha->bus_cnt, j);
+ gdth_stop_timeout(ha, ha->bus_cnt, j);
} else {
spin_lock_irqsave(&ha->smp_lock, flags);
ha->hdr[j].lock = 0;
spin_unlock_irqrestore(&ha->smp_lock, flags);
- gdth_start_timeout(ldrv.ionode, ha->bus_cnt, j);
- gdth_next(ldrv.ionode);
+ gdth_start_timeout(ha, ha->bus_cnt, j);
+ gdth_next(ha);
}
}
return 0;
@@ -5050,16 +4153,16 @@ static int ioc_resetdrv(void __user *arg, char *cmnd)
{
gdth_ioctl_reset res;
gdth_cmd_str cmd;
- int hanum;
gdth_ha_str *ha;
int rval;
if (copy_from_user(&res, arg, sizeof(gdth_ioctl_reset)) ||
- res.ionode >= gdth_ctr_count || res.number >= MAX_HDRIVES)
+ res.number >= MAX_HDRIVES)
return -EFAULT;
- hanum = res.ionode;
- ha = HADATA(gdth_ctr_tab[hanum]);
-
+ ha = gdth_find_ha(res.ionode);
+ if (!ha)
+ return -EFAULT;
+
if (!ha->hdr[res.number].present)
return 0;
memset(&cmd, 0, sizeof(gdth_cmd_str));
@@ -5085,22 +4188,21 @@ static int ioc_general(void __user *arg, char *cmnd)
gdth_ioctl_general gen;
char *buf = NULL;
ulong64 paddr;
- int hanum;
gdth_ha_str *ha;
int rval;
-
- if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general)) ||
- gen.ionode >= gdth_ctr_count)
+
+ if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general)))
+ return -EFAULT;
+ ha = gdth_find_ha(gen.ionode);
+ if (!ha)
return -EFAULT;
- hanum = gen.ionode;
- ha = HADATA(gdth_ctr_tab[hanum]);
if (gen.data_len + gen.sense_len != 0) {
- if (!(buf = gdth_ioctl_alloc(hanum, gen.data_len + gen.sense_len,
+ if (!(buf = gdth_ioctl_alloc(ha, gen.data_len + gen.sense_len,
FALSE, &paddr)))
return -EFAULT;
if (copy_from_user(buf, arg + sizeof(gdth_ioctl_general),
gen.data_len + gen.sense_len)) {
- gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+ gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return -EFAULT;
}
@@ -5174,7 +4276,7 @@ static int ioc_general(void __user *arg, char *cmnd)
gen.command.u.raw.sense_data = (ulong32)paddr + gen.data_len;
}
} else {
- gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+ gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return -EFAULT;
}
}
@@ -5186,15 +4288,15 @@ static int ioc_general(void __user *arg, char *cmnd)
if (copy_to_user(arg + sizeof(gdth_ioctl_general), buf,
gen.data_len + gen.sense_len)) {
- gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+ gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return -EFAULT;
}
if (copy_to_user(arg, &gen,
sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) {
- gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+ gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return -EFAULT;
}
- gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+ gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr);
return 0;
}
@@ -5204,7 +4306,7 @@ static int ioc_hdrlist(void __user *arg, char *cmnd)
gdth_cmd_str *cmd;
gdth_ha_str *ha;
unchar i;
- int hanum, rc = -ENOMEM;
+ int rc = -ENOMEM;
u32 cluster_type = 0;
rsc = kmalloc(sizeof(*rsc), GFP_KERNEL);
@@ -5213,12 +4315,10 @@ static int ioc_hdrlist(void __user *arg, char *cmnd)
goto free_fail;
if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) ||
- rsc->ionode >= gdth_ctr_count) {
+ (NULL == (ha = gdth_find_ha(rsc->ionode)))) {
rc = -EFAULT;
goto free_fail;
}
- hanum = rsc->ionode;
- ha = HADATA(gdth_ctr_tab[hanum]);
memset(cmd, 0, sizeof(gdth_cmd_str));
for (i = 0; i < MAX_HDRIVES; ++i) {
@@ -5259,7 +4359,7 @@ static int ioc_rescan(void __user *arg, char *cmnd)
gdth_cmd_str *cmd;
ushort i, status, hdr_cnt;
ulong32 info;
- int hanum, cyls, hds, secs;
+ int cyls, hds, secs;
int rc = -ENOMEM;
ulong flags;
gdth_ha_str *ha;
@@ -5270,12 +4370,10 @@ static int ioc_rescan(void __user *arg, char *cmnd)
goto free_fail;
if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) ||
- rsc->ionode >= gdth_ctr_count) {
+ (NULL == (ha = gdth_find_ha(rsc->ionode)))) {
rc = -EFAULT;
goto free_fail;
}
- hanum = rsc->ionode;
- ha = HADATA(gdth_ctr_tab[hanum]);
memset(cmd, 0, sizeof(gdth_cmd_str));
if (rsc->flag == 0) {
@@ -5432,9 +4530,9 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
gdth_ioctl_ctrtype ctrt;
if (copy_from_user(&ctrt, argp, sizeof(gdth_ioctl_ctrtype)) ||
- ctrt.ionode >= gdth_ctr_count)
+ (NULL == (ha = gdth_find_ha(ctrt.ionode))))
return -EFAULT;
- ha = HADATA(gdth_ctr_tab[ctrt.ionode]);
+
if (ha->type == GDT_ISA || ha->type == GDT_EISA) {
ctrt.type = (unchar)((ha->stype>>20) - 0x10);
} else {
@@ -5473,10 +4571,9 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
unchar i, j;
if (copy_from_user(&lchn, argp, sizeof(gdth_ioctl_lockchn)) ||
- lchn.ionode >= gdth_ctr_count)
+ (NULL == (ha = gdth_find_ha(lchn.ionode))))
return -EFAULT;
- ha = HADATA(gdth_ctr_tab[lchn.ionode]);
-
+
i = lchn.channel;
if (i < ha->bus_cnt) {
if (lchn.lock) {
@@ -5484,16 +4581,16 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
ha->raw[i].lock = 1;
spin_unlock_irqrestore(&ha->smp_lock, flags);
for (j = 0; j < ha->tid_cnt; ++j) {
- gdth_wait_completion(lchn.ionode, i, j);
- gdth_stop_timeout(lchn.ionode, i, j);
+ gdth_wait_completion(ha, i, j);
+ gdth_stop_timeout(ha, i, j);
}
} else {
spin_lock_irqsave(&ha->smp_lock, flags);
ha->raw[i].lock = 0;
spin_unlock_irqrestore(&ha->smp_lock, flags);
for (j = 0; j < ha->tid_cnt; ++j) {
- gdth_start_timeout(lchn.ionode, i, j);
- gdth_next(lchn.ionode);
+ gdth_start_timeout(ha, i, j);
+ gdth_next(ha);
}
}
}
@@ -5509,37 +4606,22 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
case GDTIOCTL_RESET_BUS:
{
gdth_ioctl_reset res;
- int hanum, rval;
+ int rval;
if (copy_from_user(&res, argp, sizeof(gdth_ioctl_reset)) ||
- res.ionode >= gdth_ctr_count)
+ (NULL == (ha = gdth_find_ha(res.ionode))))
return -EFAULT;
- hanum = res.ionode;
- ha = HADATA(gdth_ctr_tab[hanum]);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
- scp = kmalloc(sizeof(*scp), GFP_KERNEL);
+ scp = kzalloc(sizeof(*scp), GFP_KERNEL);
if (!scp)
return -ENOMEM;
- memset(scp, 0, sizeof(*scp));
scp->device = ha->sdev;
scp->cmd_len = 12;
- scp->use_sg = 0;
- scp->device->channel = virt_ctr ? 0 : res.number;
+ scp->device->channel = res.number;
rval = gdth_eh_bus_reset(scp);
res.status = (rval == SUCCESS ? S_OK : S_GENERR);
kfree(scp);
-#else
- scp = scsi_allocate_device(ha->sdev, 1, FALSE);
- if (!scp)
- return -ENOMEM;
- scp->cmd_len = 12;
- scp->use_sg = 0;
- scp->channel = virt_ctr ? 0 : res.number;
- rval = gdth_eh_bus_reset(scp);
- res.status = (rval == SUCCESS ? S_OK : S_GENERR);
- scsi_release_command(scp);
-#endif
+
if (copy_to_user(argp, &res, sizeof(gdth_ioctl_reset)))
return -EFAULT;
break;
@@ -5556,16 +4638,14 @@ static int gdth_ioctl(struct inode *inode, struct file *filep,
/* flush routine */
-static void gdth_flush(int hanum)
+static void gdth_flush(gdth_ha_str *ha)
{
int i;
- gdth_ha_str *ha;
gdth_cmd_str gdtcmd;
char cmnd[MAX_COMMAND_SIZE];
memset(cmnd, 0xff, MAX_COMMAND_SIZE);
- TRACE2(("gdth_flush() hanum %d\n",hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE2(("gdth_flush() hanum %d\n", ha->hanum));
for (i = 0; i < MAX_HDRIVES; ++i) {
if (ha->hdr[i].present) {
@@ -5581,9 +4661,9 @@ static void gdth_flush(int hanum)
gdtcmd.u.cache.BlockNo = 1;
gdtcmd.u.cache.sg_canz = 0;
}
- TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
+ TRACE2(("gdth_flush(): flush ha %d drive %d\n", ha->hanum, i));
- gdth_execute(gdth_ctr_tab[hanum], &gdtcmd, cmnd, 30, NULL);
+ gdth_execute(ha->shost, &gdtcmd, cmnd, 30, NULL);
}
}
}
@@ -5591,7 +4671,7 @@ static void gdth_flush(int hanum)
/* shutdown routine */
static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
{
- int hanum;
+ gdth_ha_str *ha;
#ifndef __alpha__
gdth_cmd_str gdtcmd;
char cmnd[MAX_COMMAND_SIZE];
@@ -5606,8 +4686,8 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
notifier_disabled = 1;
printk("GDT-HA: Flushing all host drives .. ");
- for (hanum = 0; hanum < gdth_ctr_count; ++hanum) {
- gdth_flush(hanum);
+ list_for_each_entry(ha, &gdth_instances, list) {
+ gdth_flush(ha);
#ifndef __alpha__
/* controller reset */
@@ -5615,8 +4695,8 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
gdtcmd.BoardNode = LOCALBOARD;
gdtcmd.Service = CACHESERVICE;
gdtcmd.OpCode = GDT_RESET;
- TRACE2(("gdth_halt(): reset controller %d\n", hanum));
- gdth_execute(gdth_ctr_tab[hanum], &gdtcmd, cmnd, 10, NULL);
+ TRACE2(("gdth_halt(): reset controller %d\n", ha->hanum));
+ gdth_execute(ha->shost, &gdtcmd, cmnd, 10, NULL);
#endif
}
printk("Done.\n");
@@ -5627,7 +4707,6 @@ static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
return NOTIFY_OK;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
/* configure lun */
static int gdth_slave_configure(struct scsi_device *sdev)
{
@@ -5636,40 +4715,540 @@ static int gdth_slave_configure(struct scsi_device *sdev)
sdev->skip_ms_page_8 = 1;
return 0;
}
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-static struct scsi_host_template driver_template = {
-#else
-static Scsi_Host_Template driver_template = {
-#endif
- .proc_name = "gdth",
- .proc_info = gdth_proc_info,
+static struct scsi_host_template gdth_template = {
.name = "GDT SCSI Disk Array Controller",
- .detect = gdth_detect,
- .release = gdth_release,
.info = gdth_info,
.queuecommand = gdth_queuecommand,
.eh_bus_reset_handler = gdth_eh_bus_reset,
+ .slave_configure = gdth_slave_configure,
.bios_param = gdth_bios_param,
+ .proc_info = gdth_proc_info,
+ .proc_name = "gdth",
.can_queue = GDTH_MAXCMDS,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
- .slave_configure = gdth_slave_configure,
-#endif
.this_id = -1,
.sg_tablesize = GDTH_MAXSG,
.cmd_per_lun = GDTH_MAXC_P_L,
.unchecked_isa_dma = 1,
.use_clustering = ENABLE_CLUSTERING,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
- .use_new_eh_code = 1,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)
- .highmem_io = 1,
+};
+
+#ifdef CONFIG_ISA
+static int __init gdth_isa_probe_one(ulong32 isa_bios)
+{
+ struct Scsi_Host *shp;
+ gdth_ha_str *ha;
+ dma_addr_t scratch_dma_handle = 0;
+ int error, i;
+
+ if (!gdth_search_isa(isa_bios))
+ return -ENXIO;
+
+ shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str));
+ if (!shp)
+ return -ENOMEM;
+ ha = shost_priv(shp);
+
+ error = -ENODEV;
+ if (!gdth_init_isa(isa_bios,ha))
+ goto out_host_put;
+
+ /* controller found and initialized */
+ printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
+ isa_bios, ha->irq, ha->drq);
+
+ error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha);
+ if (error) {
+ printk("GDT-ISA: Unable to allocate IRQ\n");
+ goto out_host_put;
+ }
+
+ error = request_dma(ha->drq, "gdth");
+ if (error) {
+ printk("GDT-ISA: Unable to allocate DMA channel\n");
+ goto out_free_irq;
+ }
+
+ set_dma_mode(ha->drq,DMA_MODE_CASCADE);
+ enable_dma(ha->drq);
+ shp->unchecked_isa_dma = 1;
+ shp->irq = ha->irq;
+ shp->dma_channel = ha->drq;
+
+ ha->hanum = gdth_ctr_count++;
+ ha->shost = shp;
+
+ ha->pccb = &ha->cmdext;
+ ha->ccb_phys = 0L;
+ ha->pdev = NULL;
+
+ error = -ENOMEM;
+
+ ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
+ &scratch_dma_handle);
+ if (!ha->pscratch)
+ goto out_dec_counters;
+ ha->scratch_phys = scratch_dma_handle;
+
+ ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
+ &scratch_dma_handle);
+ if (!ha->pmsg)
+ goto out_free_pscratch;
+ ha->msg_phys = scratch_dma_handle;
+
+#ifdef INT_COAL
+ ha->coal_stat = pci_alloc_consistent(ha->pdev,
+ sizeof(gdth_coal_status) * MAXOFFSETS,
+ &scratch_dma_handle);
+ if (!ha->coal_stat)
+ goto out_free_pmsg;
+ ha->coal_stat_phys = scratch_dma_handle;
#endif
+
+ ha->scratch_busy = FALSE;
+ ha->req_first = NULL;
+ ha->tid_cnt = MAX_HDRIVES;
+ if (max_ids > 0 && max_ids < ha->tid_cnt)
+ ha->tid_cnt = max_ids;
+ for (i = 0; i < GDTH_MAXCMDS; ++i)
+ ha->cmd_tab[i].cmnd = UNUSED_CMND;
+ ha->scan_mode = rescan ? 0x10 : 0;
+
+ error = -ENODEV;
+ if (!gdth_search_drives(ha)) {
+ printk("GDT-ISA: Error during device scan\n");
+ goto out_free_coal_stat;
+ }
+
+ if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+ hdr_channel = ha->bus_cnt;
+ ha->virt_bus = hdr_channel;
+
+ if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT)
+ shp->max_cmd_len = 16;
+
+ shp->max_id = ha->tid_cnt;
+ shp->max_lun = MAXLUN;
+ shp->max_channel = ha->bus_cnt;
+
+ spin_lock_init(&ha->smp_lock);
+ gdth_enable_int(ha);
+
+ error = scsi_add_host(shp, NULL);
+ if (error)
+ goto out_free_coal_stat;
+ list_add_tail(&ha->list, &gdth_instances);
+ return 0;
+
+ out_free_coal_stat:
+#ifdef INT_COAL
+ pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS,
+ ha->coal_stat, ha->coal_stat_phys);
+ out_free_pmsg:
#endif
-};
+ pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
+ ha->pmsg, ha->msg_phys);
+ out_free_pscratch:
+ pci_free_consistent(ha->pdev, GDTH_SCRATCH,
+ ha->pscratch, ha->scratch_phys);
+ out_dec_counters:
+ gdth_ctr_count--;
+ out_free_irq:
+ free_irq(ha->irq, ha);
+ out_host_put:
+ scsi_host_put(shp);
+ return error;
+}
+#endif /* CONFIG_ISA */
+
+#ifdef CONFIG_EISA
+static int __init gdth_eisa_probe_one(ushort eisa_slot)
+{
+ struct Scsi_Host *shp;
+ gdth_ha_str *ha;
+ dma_addr_t scratch_dma_handle = 0;
+ int error, i;
+
+ if (!gdth_search_eisa(eisa_slot))
+ return -ENXIO;
+
+ shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str));
+ if (!shp)
+ return -ENOMEM;
+ ha = shost_priv(shp);
+
+ error = -ENODEV;
+ if (!gdth_init_eisa(eisa_slot,ha))
+ goto out_host_put;
+
+ /* controller found and initialized */
+ printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
+ eisa_slot >> 12, ha->irq);
+
+ error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha);
+ if (error) {
+ printk("GDT-EISA: Unable to allocate IRQ\n");
+ goto out_host_put;
+ }
+
+ shp->unchecked_isa_dma = 0;
+ shp->irq = ha->irq;
+ shp->dma_channel = 0xff;
+
+ ha->hanum = gdth_ctr_count++;
+ ha->shost = shp;
+
+ TRACE2(("EISA detect Bus 0: hanum %d\n", ha->hanum));
+
+ ha->pccb = &ha->cmdext;
+ ha->ccb_phys = 0L;
+
+ error = -ENOMEM;
+
+ ha->pdev = NULL;
+ ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
+ &scratch_dma_handle);
+ if (!ha->pscratch)
+ goto out_free_irq;
+ ha->scratch_phys = scratch_dma_handle;
+
+ ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
+ &scratch_dma_handle);
+ if (!ha->pmsg)
+ goto out_free_pscratch;
+ ha->msg_phys = scratch_dma_handle;
+
+#ifdef INT_COAL
+ ha->coal_stat = pci_alloc_consistent(ha->pdev,
+ sizeof(gdth_coal_status) * MAXOFFSETS,
+ &scratch_dma_handle);
+ if (!ha->coal_stat)
+ goto out_free_pmsg;
+ ha->coal_stat_phys = scratch_dma_handle;
+#endif
+
+ ha->ccb_phys = pci_map_single(ha->pdev,ha->pccb,
+ sizeof(gdth_cmd_str), PCI_DMA_BIDIRECTIONAL);
+ if (!ha->ccb_phys)
+ goto out_free_coal_stat;
+
+ ha->scratch_busy = FALSE;
+ ha->req_first = NULL;
+ ha->tid_cnt = MAX_HDRIVES;
+ if (max_ids > 0 && max_ids < ha->tid_cnt)
+ ha->tid_cnt = max_ids;
+ for (i = 0; i < GDTH_MAXCMDS; ++i)
+ ha->cmd_tab[i].cmnd = UNUSED_CMND;
+ ha->scan_mode = rescan ? 0x10 : 0;
+
+ if (!gdth_search_drives(ha)) {
+ printk("GDT-EISA: Error during device scan\n");
+ error = -ENODEV;
+ goto out_free_ccb_phys;
+ }
+
+ if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+ hdr_channel = ha->bus_cnt;
+ ha->virt_bus = hdr_channel;
+
+ if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT)
+ shp->max_cmd_len = 16;
+
+ shp->max_id = ha->tid_cnt;
+ shp->max_lun = MAXLUN;
+ shp->max_channel = ha->bus_cnt;
+
+ spin_lock_init(&ha->smp_lock);
+ gdth_enable_int(ha);
+
+ error = scsi_add_host(shp, NULL);
+ if (error)
+ goto out_free_coal_stat;
+ list_add_tail(&ha->list, &gdth_instances);
+ return 0;
+
+ out_free_ccb_phys:
+ pci_unmap_single(ha->pdev,ha->ccb_phys, sizeof(gdth_cmd_str),
+ PCI_DMA_BIDIRECTIONAL);
+ out_free_coal_stat:
+#ifdef INT_COAL
+ pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS,
+ ha->coal_stat, ha->coal_stat_phys);
+ out_free_pmsg:
+#endif
+ pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
+ ha->pmsg, ha->msg_phys);
+ out_free_pscratch:
+ pci_free_consistent(ha->pdev, GDTH_SCRATCH,
+ ha->pscratch, ha->scratch_phys);
+ out_free_irq:
+ free_irq(ha->irq, ha);
+ gdth_ctr_count--;
+ out_host_put:
+ scsi_host_put(shp);
+ return error;
+}
+#endif /* CONFIG_EISA */
+
+#ifdef CONFIG_PCI
+static int __init gdth_pci_probe_one(gdth_pci_str *pcistr, int ctr)
+{
+ struct Scsi_Host *shp;
+ gdth_ha_str *ha;
+ dma_addr_t scratch_dma_handle = 0;
+ int error, i;
+
+ shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str));
+ if (!shp)
+ return -ENOMEM;
+ ha = shost_priv(shp);
+
+ error = -ENODEV;
+ if (!gdth_init_pci(&pcistr[ctr],ha))
+ goto out_host_put;
+
+ /* controller found and initialized */
+ printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
+ pcistr[ctr].pdev->bus->number,
+ PCI_SLOT(pcistr[ctr].pdev->devfn),
+ ha->irq);
+
+ error = request_irq(ha->irq, gdth_interrupt,
+ IRQF_DISABLED|IRQF_SHARED, "gdth", ha);
+ if (error) {
+ printk("GDT-PCI: Unable to allocate IRQ\n");
+ goto out_host_put;
+ }
+
+ shp->unchecked_isa_dma = 0;
+ shp->irq = ha->irq;
+ shp->dma_channel = 0xff;
+
+ ha->hanum = gdth_ctr_count++;
+ ha->shost = shp;
+
+ ha->pccb = &ha->cmdext;
+ ha->ccb_phys = 0L;
+
+ error = -ENOMEM;
+
+ ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH,
+ &scratch_dma_handle);
+ if (!ha->pscratch)
+ goto out_free_irq;
+ ha->scratch_phys = scratch_dma_handle;
+
+ ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str),
+ &scratch_dma_handle);
+ if (!ha->pmsg)
+ goto out_free_pscratch;
+ ha->msg_phys = scratch_dma_handle;
+
+#ifdef INT_COAL
+ ha->coal_stat = pci_alloc_consistent(ha->pdev,
+ sizeof(gdth_coal_status) * MAXOFFSETS,
+ &scratch_dma_handle);
+ if (!ha->coal_stat)
+ goto out_free_pmsg;
+ ha->coal_stat_phys = scratch_dma_handle;
+#endif
+
+ ha->scratch_busy = FALSE;
+ ha->req_first = NULL;
+ ha->tid_cnt = pcistr[ctr].pdev->device >= 0x200 ? MAXID : MAX_HDRIVES;
+ if (max_ids > 0 && max_ids < ha->tid_cnt)
+ ha->tid_cnt = max_ids;
+ for (i = 0; i < GDTH_MAXCMDS; ++i)
+ ha->cmd_tab[i].cmnd = UNUSED_CMND;
+ ha->scan_mode = rescan ? 0x10 : 0;
+
+ error = -ENODEV;
+ if (!gdth_search_drives(ha)) {
+ printk("GDT-PCI %d: Error during device scan\n", ha->hanum);
+ goto out_free_coal_stat;
+ }
+
+ if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+ hdr_channel = ha->bus_cnt;
+ ha->virt_bus = hdr_channel;
+
+ /* 64-bit DMA only supported from FW >= x.43 */
+ if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) ||
+ !ha->dma64_support) {
+ if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
+ printk(KERN_WARNING "GDT-PCI %d: "
+ "Unable to set 32-bit DMA\n", ha->hanum);
+ goto out_free_coal_stat;
+ }
+ } else {
+ shp->max_cmd_len = 16;
+ if (!pci_set_dma_mask(pcistr[ctr].pdev, DMA_64BIT_MASK)) {
+ printk("GDT-PCI %d: 64-bit DMA enabled\n", ha->hanum);
+ } else if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) {
+ printk(KERN_WARNING "GDT-PCI %d: "
+ "Unable to set 64/32-bit DMA\n", ha->hanum);
+ goto out_free_coal_stat;
+ }
+ }
+
+ shp->max_id = ha->tid_cnt;
+ shp->max_lun = MAXLUN;
+ shp->max_channel = ha->bus_cnt;
+
+ spin_lock_init(&ha->smp_lock);
+ gdth_enable_int(ha);
+
+ error = scsi_add_host(shp, &pcistr[ctr].pdev->dev);
+ if (error)
+ goto out_free_coal_stat;
+ list_add_tail(&ha->list, &gdth_instances);
+ return 0;
+
+ out_free_coal_stat:
+#ifdef INT_COAL
+ pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS,
+ ha->coal_stat, ha->coal_stat_phys);
+ out_free_pmsg:
+#endif
+ pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
+ ha->pmsg, ha->msg_phys);
+ out_free_pscratch:
+ pci_free_consistent(ha->pdev, GDTH_SCRATCH,
+ ha->pscratch, ha->scratch_phys);
+ out_free_irq:
+ free_irq(ha->irq, ha);
+ gdth_ctr_count--;
+ out_host_put:
+ scsi_host_put(shp);
+ return error;
+}
+#endif /* CONFIG_PCI */
+
+static void gdth_remove_one(gdth_ha_str *ha)
+{
+ struct Scsi_Host *shp = ha->shost;
+
+ TRACE2(("gdth_remove_one()\n"));
+
+ scsi_remove_host(shp);
+
+ if (ha->sdev) {
+ scsi_free_host_dev(ha->sdev);
+ ha->sdev = NULL;
+ }
+
+ gdth_flush(ha);
+
+ if (shp->irq)
+ free_irq(shp->irq,ha);
+
+#ifdef CONFIG_ISA
+ if (shp->dma_channel != 0xff)
+ free_dma(shp->dma_channel);
+#endif
+#ifdef INT_COAL
+ if (ha->coal_stat)
+ pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+ MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys);
+#endif
+ if (ha->pscratch)
+ pci_free_consistent(ha->pdev, GDTH_SCRATCH,
+ ha->pscratch, ha->scratch_phys);
+ if (ha->pmsg)
+ pci_free_consistent(ha->pdev, sizeof(gdth_msg_str),
+ ha->pmsg, ha->msg_phys);
+ if (ha->ccb_phys)
+ pci_unmap_single(ha->pdev,ha->ccb_phys,
+ sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
+
+ scsi_host_put(shp);
+}
+
+static int __init gdth_init(void)
+{
+ if (disable) {
+ printk("GDT-HA: Controller driver disabled from"
+ " command line !\n");
+ return 0;
+ }
+
+ printk("GDT-HA: Storage RAID Controller Driver. Version: %s\n",
+ GDTH_VERSION_STR);
+
+ /* initializations */
+ gdth_polling = TRUE;
+ gdth_clear_events();
+
+ /* As default we do not probe for EISA or ISA controllers */
+ if (probe_eisa_isa) {
+ /* scanning for controllers, at first: ISA controller */
+#ifdef CONFIG_ISA
+ ulong32 isa_bios;
+ for (isa_bios = 0xc8000UL; isa_bios <= 0xd8000UL;
+ isa_bios += 0x8000UL)
+ gdth_isa_probe_one(isa_bios);
+#endif
+#ifdef CONFIG_EISA
+ {
+ ushort eisa_slot;
+ for (eisa_slot = 0x1000; eisa_slot <= 0x8000;
+ eisa_slot += 0x1000)
+ gdth_eisa_probe_one(eisa_slot);
+ }
+#endif
+ }
+
+#ifdef CONFIG_PCI
+ /* scanning for PCI controllers */
+ {
+ gdth_pci_str pcistr[MAXHA];
+ int cnt,ctr;
+
+ cnt = gdth_search_pci(pcistr);
+ printk("GDT-HA: Found %d PCI Storage RAID Controllers\n", cnt);
+ gdth_sort_pci(pcistr,cnt);
+ for (ctr = 0; ctr < cnt; ++ctr)
+ gdth_pci_probe_one(pcistr, ctr);
+ }
+#endif /* CONFIG_PCI */
+
+ TRACE2(("gdth_detect() %d controller detected\n", gdth_ctr_count));
+
+ if (list_empty(&gdth_instances))
+ return -ENODEV;
+
+#ifdef GDTH_STATISTICS
+ TRACE2(("gdth_detect(): Initializing timer !\n"));
+ init_timer(&gdth_timer);
+ gdth_timer.expires = jiffies + HZ;
+ gdth_timer.data = 0L;
+ gdth_timer.function = gdth_timeout;
+ add_timer(&gdth_timer);
+#endif
+ major = register_chrdev(0,"gdth", &gdth_fops);
+ notifier_disabled = 0;
+ register_reboot_notifier(&gdth_notifier);
+ gdth_polling = FALSE;
+ return 0;
+}
+
+static void __exit gdth_exit(void)
+{
+ gdth_ha_str *ha;
+
+ list_for_each_entry(ha, &gdth_instances, list)
+ gdth_remove_one(ha);
+
+#ifdef GDTH_STATISTICS
+ del_timer(&gdth_timer);
+#endif
+ unregister_chrdev(major,"gdth");
+ unregister_reboot_notifier(&gdth_notifier);
+}
+
+module_init(gdth_init);
+module_exit(gdth_exit);
-#include "scsi_module.c"
#ifndef MODULE
__setup("gdth=", option_setup);
#endif
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index 37423300592..1434c6b0297 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -13,7 +13,6 @@
* $Id: gdth.h,v 1.58 2006/01/11 16:14:09 achim Exp $
*/
-#include <linux/version.h>
#include <linux/types.h>
#ifndef TRUE
@@ -304,15 +303,8 @@
#define MAILBOXREG 0x0c90 /* mailbox reg. (16 bytes) */
#define EISAREG 0x0cc0 /* EISA configuration */
-/* DMA memory mappings */
-#define GDTH_MAP_NONE 0
-#define GDTH_MAP_SINGLE 1
-#define GDTH_MAP_SG 2
-#define GDTH_MAP_IOCTL 3
-
/* other defines */
#define LINUX_OS 8 /* used for cache optim. */
-#define SCATTER_GATHER 1 /* s/g feature */
#define SECS32 0x1f /* round capacity */
#define BIOS_ID_OFFS 0x10 /* offset contr-ID in ISABIOS */
#define LOCALBOARD 0 /* board node always 0 */
@@ -854,6 +846,9 @@ typedef struct {
/* controller information structure */
typedef struct {
+ struct Scsi_Host *shost;
+ struct list_head list;
+ ushort hanum;
ushort oem_id; /* OEM */
ushort type; /* controller class */
ulong32 stype; /* subtype (PCI: device ID) */
@@ -865,6 +860,7 @@ typedef struct {
void __iomem *brd; /* DPRAM address */
ulong32 brd_phys; /* slot number/BIOS address */
gdt6c_plx_regs *plx; /* PLX regs (new PCI contr.) */
+ gdth_cmd_str cmdext;
gdth_cmd_str *pccb; /* address command structure */
ulong32 ccb_phys; /* phys. address */
#ifdef INT_COAL
@@ -916,6 +912,19 @@ typedef struct {
Scsi_Cmnd *cmnd; /* pending request */
ushort service; /* service */
} cmd_tab[GDTH_MAXCMDS]; /* table of pend. requests */
+ struct gdth_cmndinfo { /* per-command private info */
+ int index;
+ int internal_command; /* don't call scsi_done */
+ dma_addr_t sense_paddr; /* sense dma-addr */
+ unchar priority;
+ int timeout;
+ volatile int wait_for_completion;
+ ushort status;
+ ulong32 info;
+ enum dma_data_direction dma_dir;
+ int phase; /* ???? */
+ int OpCode;
+ } cmndinfo[GDTH_MAXCMDS]; /* index==0 is free */
unchar bus_cnt; /* SCSI bus count */
unchar tid_cnt; /* Target ID count */
unchar bus_id[MAXBUS]; /* IOP IDs */
@@ -938,19 +947,10 @@ typedef struct {
struct scsi_device *sdev;
} gdth_ha_str;
-/* structure for scsi_register(), SCSI bus != 0 */
-typedef struct {
- ushort hanum;
- ushort busnum;
-} gdth_num_str;
-
-/* structure for scsi_register() */
-typedef struct {
- gdth_num_str numext; /* must be the first element */
- gdth_ha_str haext;
- gdth_cmd_str cmdext;
-} gdth_ext_str;
-
+static inline struct gdth_cmndinfo *gdth_cmnd_priv(struct scsi_cmnd* cmd)
+{
+ return (struct gdth_cmndinfo *)cmd->host_scribble;
+}
/* INQUIRY data format */
typedef struct {
diff --git a/drivers/scsi/gdth_kcompat.h b/drivers/scsi/gdth_kcompat.h
deleted file mode 100644
index 2a302eee669..00000000000
--- a/drivers/scsi/gdth_kcompat.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef IRQ_HANDLED
-typedef void irqreturn_t;
-#define IRQ_NONE
-#define IRQ_HANDLED
-#endif
-
-#ifndef MODULE_LICENSE
-#define MODULE_LICENSE(x)
-#endif
-
-#ifndef __iomem
-#define __iomem
-#endif
-
-#ifndef __attribute_used__
-#define __attribute_used__ __devinitdata
-#endif
-
-#ifndef __user
-#define __user
-#endif
-
-#ifndef SERVICE_ACTION_IN
-#define SERVICE_ACTION_IN 0x9e
-#endif
-#ifndef READ_16
-#define READ_16 0x88
-#endif
-#ifndef WRITE_16
-#define WRITE_16 0x8a
-#endif
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index 32982eb75c8..de5773443c6 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -4,62 +4,32 @@
#include <linux/completion.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length,
int inout)
{
- int hanum,busnum;
+ gdth_ha_str *ha = shost_priv(host);
TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
length,(int)offset,inout));
- hanum = NUMDATA(host)->hanum;
- busnum= NUMDATA(host)->busnum;
-
- if (inout)
- return(gdth_set_info(buffer,length,host,hanum,busnum));
- else
- return(gdth_get_info(buffer,start,offset,length,host,hanum,busnum));
-}
-#else
-int gdth_proc_info(char *buffer,char **start,off_t offset,int length,int hostno,
- int inout)
-{
- int hanum,busnum,i;
-
- TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
- length,(int)offset,inout));
-
- for (i = 0; i < gdth_ctr_vcount; ++i) {
- if (gdth_ctr_vtab[i]->host_no == hostno)
- break;
- }
- if (i == gdth_ctr_vcount)
- return(-EINVAL);
-
- hanum = NUMDATA(gdth_ctr_vtab[i])->hanum;
- busnum= NUMDATA(gdth_ctr_vtab[i])->busnum;
-
if (inout)
- return(gdth_set_info(buffer,length,gdth_ctr_vtab[i],hanum,busnum));
+ return(gdth_set_info(buffer,length,host,ha));
else
- return(gdth_get_info(buffer,start,offset,length,
- gdth_ctr_vtab[i],hanum,busnum));
+ return(gdth_get_info(buffer,start,offset,length,host,ha));
}
-#endif
static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
- int hanum,int busnum)
+ gdth_ha_str *ha)
{
int ret_val = -EINVAL;
- TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
+ TRACE2(("gdth_set_info() ha %d\n",ha->hanum,));
if (length >= 4) {
if (strncmp(buffer,"gdth",4) == 0) {
buffer += 5;
length -= 5;
- ret_val = gdth_set_asc_info(host, buffer, length, hanum);
+ ret_val = gdth_set_asc_info(host, buffer, length, ha);
}
}
@@ -67,11 +37,10 @@ static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
}
static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
- int length,int hanum)
+ int length, gdth_ha_str *ha)
{
int orig_length, drive, wb_mode;
int i, found;
- gdth_ha_str *ha;
gdth_cmd_str gdtcmd;
gdth_cpar_str *pcpar;
ulong64 paddr;
@@ -80,8 +49,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
memset(cmnd, 0xff, 12);
memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
- TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE2(("gdth_set_asc_info() ha %d\n",ha->hanum));
orig_length = length + 5;
drive = -1;
wb_mode = 0;
@@ -157,7 +125,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
}
if (wb_mode) {
- if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str), TRUE, &paddr))
+ if (!gdth_ioctl_alloc(ha, sizeof(gdth_cpar_str), TRUE, &paddr))
return(-EBUSY);
pcpar = (gdth_cpar_str *)ha->pscratch;
memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
@@ -171,7 +139,7 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
gdth_execute(host, &gdtcmd, cmnd, 30, NULL);
- gdth_ioctl_free(hanum, GDTH_SCRATCH, ha->pscratch, paddr);
+ gdth_ioctl_free(ha, GDTH_SCRATCH, ha->pscratch, paddr);
printk("Done.\n");
return(orig_length);
}
@@ -181,11 +149,10 @@ static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
}
static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
- struct Scsi_Host *host,int hanum,int busnum)
+ struct Scsi_Host *host, gdth_ha_str *ha)
{
int size = 0,len = 0;
off_t begin = 0,pos = 0;
- gdth_ha_str *ha;
int id, i, j, k, sec, flag;
int no_mdrv = 0, drv_no, is_mirr;
ulong32 cnt;
@@ -214,8 +181,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
memset(cmnd, 0xff, 12);
memset(gdtcmd, 0, sizeof(gdth_cmd_str));
- TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
- ha = HADATA(gdth_ctr_tab[hanum]);
+ TRACE2(("gdth_get_info() ha %d\n",ha->hanum));
/* request is i.e. "cat /proc/scsi/gdth/0" */
@@ -245,13 +211,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
/* controller information */
size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
len += size; pos = begin + len;
- if (virt_ctr)
- sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
- else
- strcpy(hrec, ha->binfo.type_string);
+ strcpy(hrec, ha->binfo.type_string);
size = sprintf(buffer+len,
" Number: \t%d \tName: \t%s\n",
- hanum, hrec);
+ ha->hanum, hrec);
len += size; pos = begin + len;
if (ha->more_proc)
@@ -301,7 +264,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
len += size; pos = begin + len;
flag = FALSE;
- buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+ buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
if (!buf)
goto stop_output;
for (i = 0; i < ha->bus_cnt; ++i) {
@@ -404,7 +367,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
goto stop_output;
}
}
- gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+ gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
if (!flag) {
size = sprintf(buffer+len, "\n --\n");
@@ -416,7 +379,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
len += size; pos = begin + len;
flag = FALSE;
- buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+ buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
if (!buf)
goto stop_output;
for (i = 0; i < MAX_LDRIVES; ++i) {
@@ -510,7 +473,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
if (pos > offset + length)
goto stop_output;
}
- gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+ gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
if (!flag) {
size = sprintf(buffer+len, "\n --\n");
@@ -522,7 +485,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
len += size; pos = begin + len;
flag = FALSE;
- buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+ buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
if (!buf)
goto stop_output;
for (i = 0; i < MAX_LDRIVES; ++i) {
@@ -581,7 +544,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
goto stop_output;
}
}
- gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+ gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
if (!flag) {
size = sprintf(buffer+len, "\n --\n");
@@ -593,7 +556,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
len += size; pos = begin + len;
flag = FALSE;
- buf = gdth_ioctl_alloc(hanum, sizeof(gdth_hget_str), FALSE, &paddr);
+ buf = gdth_ioctl_alloc(ha, sizeof(gdth_hget_str), FALSE, &paddr);
if (!buf)
goto stop_output;
for (i = 0; i < MAX_LDRIVES; ++i) {
@@ -626,7 +589,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
}
}
}
- gdth_ioctl_free(hanum, sizeof(gdth_hget_str), buf, paddr);
+ gdth_ioctl_free(ha, sizeof(gdth_hget_str), buf, paddr);
for (i = 0; i < MAX_HDRIVES; ++i) {
if (!(ha->hdr[i].present))
@@ -664,7 +627,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
id = gdth_read_event(ha, id, estr);
if (estr->event_source == 0)
break;
- if (estr->event_data.eu.driver.ionode == hanum &&
+ if (estr->event_data.eu.driver.ionode == ha->hanum &&
estr->event_source == ES_ASYNC) {
gdth_log_event(&estr->event_data, hrec);
do_gettimeofday(&tv);
@@ -699,17 +662,15 @@ free_fail:
return rc;
}
-static char *gdth_ioctl_alloc(int hanum, int size, int scratch,
+static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch,
ulong64 *paddr)
{
- gdth_ha_str *ha;
ulong flags;
char *ret_val;
if (size == 0)
return NULL;
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
if (!ha->scratch_busy && size <= GDTH_SCRATCH) {
@@ -729,12 +690,10 @@ static char *gdth_ioctl_alloc(int hanum, int size, int scratch,
return ret_val;
}
-static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr)
+static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr)
{
- gdth_ha_str *ha;
ulong flags;
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
if (buf == ha->pscratch) {
@@ -747,13 +706,11 @@ static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr)
}
#ifdef GDTH_IOCTL_PROC
-static int gdth_ioctl_check_bin(int hanum, ushort size)
+static int gdth_ioctl_check_bin(gdth_ha_str *ha, ushort size)
{
- gdth_ha_str *ha;
ulong flags;
int ret_val;
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
ret_val = FALSE;
@@ -766,27 +723,27 @@ static int gdth_ioctl_check_bin(int hanum, ushort size)
}
#endif
-static void gdth_wait_completion(int hanum, int busnum, int id)
+static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id)
{
- gdth_ha_str *ha;
ulong flags;
int i;
Scsi_Cmnd *scp;
+ struct gdth_cmndinfo *cmndinfo;
unchar b, t;
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
for (i = 0; i < GDTH_MAXCMDS; ++i) {
scp = ha->cmd_tab[i].cmnd;
+ cmndinfo = gdth_cmnd_priv(scp);
- b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+ b = scp->device->channel;
t = scp->device->id;
if (!SPECIAL_SCP(scp) && t == (unchar)id &&
b == (unchar)busnum) {
- scp->SCp.have_data_in = 0;
+ cmndinfo->wait_for_completion = 0;
spin_unlock_irqrestore(&ha->smp_lock, flags);
- while (!scp->SCp.have_data_in)
+ while (!cmndinfo->wait_for_completion)
barrier();
spin_lock_irqsave(&ha->smp_lock, flags);
}
@@ -794,55 +751,51 @@ static void gdth_wait_completion(int hanum, int busnum, int id)
spin_unlock_irqrestore(&ha->smp_lock, flags);
}
-static void gdth_stop_timeout(int hanum, int busnum, int id)
+static void gdth_stop_timeout(gdth_ha_str *ha, int busnum, int id)
{
- gdth_ha_str *ha;
ulong flags;
Scsi_Cmnd *scp;
unchar b, t;
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
- if (scp->done != gdth_scsi_done) {
- b = virt_ctr ?
- NUMDATA(scp->device->host)->busnum : scp->device->channel;
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
+ if (!cmndinfo->internal_command) {
+ b = scp->device->channel;
t = scp->device->id;
if (t == (unchar)id && b == (unchar)busnum) {
TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
- scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
+ cmndinfo->timeout = gdth_update_timeout(scp, 0);
}
}
}
spin_unlock_irqrestore(&ha->smp_lock, flags);
}
-static void gdth_start_timeout(int hanum, int busnum, int id)
+static void gdth_start_timeout(gdth_ha_str *ha, int busnum, int id)
{
- gdth_ha_str *ha;
ulong flags;
Scsi_Cmnd *scp;
unchar b, t;
- ha = HADATA(gdth_ctr_tab[hanum]);
spin_lock_irqsave(&ha->smp_lock, flags);
for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
- if (scp->done != gdth_scsi_done) {
- b = virt_ctr ?
- NUMDATA(scp->device->host)->busnum : scp->device->channel;
+ struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp);
+ if (!cmndinfo->internal_command) {
+ b = scp->device->channel;
t = scp->device->id;
if (t == (unchar)id && b == (unchar)busnum) {
TRACE2(("gdth_start_timeout(): update_timeout()\n"));
- gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual);
+ gdth_update_timeout(scp, cmndinfo->timeout);
}
}
}
spin_unlock_irqrestore(&ha->smp_lock, flags);
}
-static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
+static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout)
{
int oldto;
diff --git a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h
index a679eeb6820..45e6fdacf36 100644
--- a/drivers/scsi/gdth_proc.h
+++ b/drivers/scsi/gdth_proc.h
@@ -9,20 +9,20 @@ int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd,
int timeout, u32 *info);
static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
- int hanum,int busnum);
+ gdth_ha_str *ha);
static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
- struct Scsi_Host *host,int hanum,int busnum);
+ struct Scsi_Host *host, gdth_ha_str *ha);
static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
- int length, int hanum);
+ int length, gdth_ha_str *ha);
-static char *gdth_ioctl_alloc(int hanum, int size, int scratch,
- ulong64 *paddr);
-static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr);
-static void gdth_wait_completion(int hanum, int busnum, int id);
-static void gdth_stop_timeout(int hanum, int busnum, int id);
-static void gdth_start_timeout(int hanum, int busnum, int id);
-static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout);
+static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch,
+ ulong64 *paddr);
+static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, ulong64 paddr);
+static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id);
+static void gdth_stop_timeout(gdth_ha_str *ha, int busnum, int id);
+static void gdth_start_timeout(gdth_ha_str *ha, int busnum, int id);
+static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout);
#endif
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 96bc31266c9..24271a871b8 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -342,6 +342,14 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost->unchecked_isa_dma = sht->unchecked_isa_dma;
shost->use_clustering = sht->use_clustering;
shost->ordered_tag = sht->ordered_tag;
+ shost->active_mode = sht->supported_mode;
+ shost->use_sg_chaining = sht->use_sg_chaining;
+
+ if (sht->supported_mode == MODE_UNKNOWN)
+ /* means we didn't set it ... default to INITIATOR */
+ shost->active_mode = MODE_INITIATOR;
+ else
+ shost->active_mode = sht->supported_mode;
if (sht->max_host_blocked)
shost->max_host_blocked = sht->max_host_blocked;
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 0e579ca4581..0844331abb8 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -1,6 +1,6 @@
/*
* HighPoint RR3xxx controller driver for Linux
- * Copyright (C) 2006 HighPoint Technologies, Inc. All Rights Reserved.
+ * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -42,7 +42,7 @@ MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx SATA Controller Driver");
static char driver_name[] = "hptiop";
static const char driver_name_long[] = "RocketRAID 3xxx SATA Controller driver";
-static const char driver_ver[] = "v1.0 (060426)";
+static const char driver_ver[] = "v1.2 (070830)";
static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag);
static void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag);
@@ -76,7 +76,7 @@ static int iop_wait_ready(struct hpt_iopmu __iomem *iop, u32 millisec)
static void hptiop_request_callback(struct hptiop_hba *hba, u32 tag)
{
- if ((tag & IOPMU_QUEUE_MASK_HOST_BITS) == IOPMU_QUEUE_ADDR_HOST_BIT)
+ if (tag & IOPMU_QUEUE_ADDR_HOST_BIT)
return hptiop_host_request_callback(hba,
tag & ~IOPMU_QUEUE_ADDR_HOST_BIT);
else
@@ -323,12 +323,22 @@ static inline void free_req(struct hptiop_hba *hba, struct hptiop_request *req)
hba->req_list = req;
}
-static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag)
+static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag)
{
struct hpt_iop_request_scsi_command *req;
struct scsi_cmnd *scp;
+ u32 tag;
+
+ if (hba->iopintf_v2) {
+ tag = _tag & ~ IOPMU_QUEUE_REQUEST_RESULT_BIT;
+ req = hba->reqs[tag].req_virt;
+ if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT))
+ req->header.result = IOP_RESULT_SUCCESS;
+ } else {
+ tag = _tag;
+ req = hba->reqs[tag].req_virt;
+ }
- req = (struct hpt_iop_request_scsi_command *)hba->reqs[tag].req_virt;
dprintk("hptiop_host_request_callback: req=%p, type=%d, "
"result=%d, context=0x%x tag=%d\n",
req, req->header.type, req->header.result,
@@ -365,8 +375,9 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag)
scp->result = SAM_STAT_CHECK_CONDITION;
memset(&scp->sense_buffer,
0, sizeof(scp->sense_buffer));
- memcpy(&scp->sense_buffer,
- &req->sg_list, le32_to_cpu(req->dataxfer_length));
+ memcpy(&scp->sense_buffer, &req->sg_list,
+ min(sizeof(scp->sense_buffer),
+ le32_to_cpu(req->dataxfer_length)));
break;
default:
@@ -497,7 +508,7 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
goto cmd_done;
}
- req = (struct hpt_iop_request_scsi_command *)_req->req_virt;
+ req = _req->req_virt;
/* build S/G table */
sg_count = hptiop_buildsgl(scp, req->sg_list);
@@ -521,8 +532,19 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
memcpy(req->cdb, scp->cmnd, sizeof(req->cdb));
- writel(IOPMU_QUEUE_ADDR_HOST_BIT | _req->req_shifted_phy,
- &hba->iop->inbound_queue);
+ if (hba->iopintf_v2) {
+ u32 size_bits;
+ if (req->header.size < 256)
+ size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
+ else if (req->header.size < 512)
+ size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
+ else
+ size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT |
+ IOPMU_QUEUE_ADDR_HOST_BIT;
+ writel(_req->req_shifted_phy | size_bits, &hba->iop->inbound_queue);
+ } else
+ writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT,
+ &hba->iop->inbound_queue);
return 0;
@@ -634,6 +656,7 @@ static struct scsi_host_template driver_template = {
.unchecked_isa_dma = 0,
.emulated = 0,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.proc_name = driver_name,
.shost_attrs = hptiop_attrs,
.this_id = -1,
@@ -688,6 +711,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
hba->pcidev = pcidev;
hba->host = host;
hba->initialized = 0;
+ hba->iopintf_v2 = 0;
atomic_set(&hba->resetting, 0);
atomic_set(&hba->reset_count, 0);
@@ -722,8 +746,13 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
hba->max_request_size = le32_to_cpu(iop_config.request_size);
hba->max_sg_descriptors = le32_to_cpu(iop_config.max_sg_count);
hba->firmware_version = le32_to_cpu(iop_config.firmware_version);
+ hba->interface_version = le32_to_cpu(iop_config.interface_version);
hba->sdram_size = le32_to_cpu(iop_config.sdram_size);
+ if (hba->firmware_version > 0x01020000 ||
+ hba->interface_version > 0x01020000)
+ hba->iopintf_v2 = 1;
+
host->max_sectors = le32_to_cpu(iop_config.data_transfer_length) >> 9;
host->max_id = le32_to_cpu(iop_config.max_devices);
host->sg_tablesize = le32_to_cpu(iop_config.max_sg_count);
@@ -731,8 +760,15 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
host->cmd_per_lun = le32_to_cpu(iop_config.max_requests);
host->max_cmd_len = 16;
- set_config.vbus_id = cpu_to_le32(host->host_no);
+ req_size = sizeof(struct hpt_iop_request_scsi_command)
+ + sizeof(struct hpt_iopsg) * (hba->max_sg_descriptors - 1);
+ if ((req_size & 0x1f) != 0)
+ req_size = (req_size + 0x1f) & ~0x1f;
+
+ memset(&set_config, 0, sizeof(struct hpt_iop_request_set_config));
set_config.iop_id = cpu_to_le32(host->host_no);
+ set_config.vbus_id = cpu_to_le16(host->host_no);
+ set_config.max_host_request_size = cpu_to_le16(req_size);
if (iop_set_config(hba, &set_config)) {
printk(KERN_ERR "scsi%d: set config failed\n",
@@ -750,10 +786,6 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
}
/* Allocate request mem */
- req_size = sizeof(struct hpt_iop_request_scsi_command)
- + sizeof(struct hpt_iopsg) * (hba->max_sg_descriptors - 1);
- if ((req_size& 0x1f) != 0)
- req_size = (req_size + 0x1f) & ~0x1f;
dprintk("req_size=%d, max_requests=%d\n", req_size, hba->max_requests);
@@ -879,8 +911,10 @@ static void hptiop_remove(struct pci_dev *pcidev)
}
static struct pci_device_id hptiop_id_table[] = {
- { PCI_DEVICE(0x1103, 0x3220) },
- { PCI_DEVICE(0x1103, 0x3320) },
+ { PCI_VDEVICE(TTI, 0x3220) },
+ { PCI_VDEVICE(TTI, 0x3320) },
+ { PCI_VDEVICE(TTI, 0x3520) },
+ { PCI_VDEVICE(TTI, 0x4320) },
{},
};
@@ -910,3 +944,4 @@ module_init(hptiop_module_init);
module_exit(hptiop_module_exit);
MODULE_LICENSE("GPL");
+
diff --git a/drivers/scsi/hptiop.h b/drivers/scsi/hptiop.h
index f04f7e81d1a..2a5e46e001c 100644
--- a/drivers/scsi/hptiop.h
+++ b/drivers/scsi/hptiop.h
@@ -1,6 +1,6 @@
/*
* HighPoint RR3xxx controller driver for Linux
- * Copyright (C) 2006 HighPoint Technologies, Inc. All Rights Reserved.
+ * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,219 +18,6 @@
#ifndef _HPTIOP_H_
#define _HPTIOP_H_
-/*
- * logical device type.
- * Identify array (logical device) and physical device.
- */
-#define LDT_ARRAY 1
-#define LDT_DEVICE 2
-
-/*
- * Array types
- */
-#define AT_UNKNOWN 0
-#define AT_RAID0 1
-#define AT_RAID1 2
-#define AT_RAID5 3
-#define AT_RAID6 4
-#define AT_JBOD 7
-
-#define MAX_NAME_LENGTH 36
-#define MAX_ARRAYNAME_LEN 16
-
-#define MAX_ARRAY_MEMBERS_V1 8
-#define MAX_ARRAY_MEMBERS_V2 16
-
-/* keep definition for source code compatiblity */
-#define MAX_ARRAY_MEMBERS MAX_ARRAY_MEMBERS_V1
-
-/*
- * array flags
- */
-#define ARRAY_FLAG_DISABLED 0x00000001 /* The array is disabled */
-#define ARRAY_FLAG_NEEDBUILDING 0x00000002 /* need to be rebuilt */
-#define ARRAY_FLAG_REBUILDING 0x00000004 /* in rebuilding process */
-#define ARRAY_FLAG_BROKEN 0x00000008 /* broken but still working */
-#define ARRAY_FLAG_BOOTDISK 0x00000010 /* has a active partition */
-#define ARRAY_FLAG_BOOTMARK 0x00000040 /* array has boot mark set */
-#define ARRAY_FLAG_NEED_AUTOREBUILD 0x00000080 /* auto-rebuild should start */
-#define ARRAY_FLAG_VERIFYING 0x00000100 /* is being verified */
-#define ARRAY_FLAG_INITIALIZING 0x00000200 /* is being initialized */
-#define ARRAY_FLAG_TRANSFORMING 0x00000400 /* tranform in progress */
-#define ARRAY_FLAG_NEEDTRANSFORM 0x00000800 /* array need tranform */
-#define ARRAY_FLAG_NEEDINITIALIZING 0x00001000 /* initialization not done */
-#define ARRAY_FLAG_BROKEN_REDUNDANT 0x00002000 /* broken but redundant */
-
-/*
- * device flags
- */
-#define DEVICE_FLAG_DISABLED 0x00000001 /* device is disabled */
-#define DEVICE_FLAG_UNINITIALIZED 0x00010000 /* device is not initialized */
-#define DEVICE_FLAG_LEGACY 0x00020000 /* lagacy drive */
-#define DEVICE_FLAG_IS_SPARE 0x80000000 /* is a spare disk */
-
-/*
- * ioctl codes
- */
-#define HPT_CTL_CODE(x) (x+0xFF00)
-#define HPT_CTL_CODE_LINUX_TO_IOP(x) ((x)-0xff00)
-
-#define HPT_IOCTL_GET_CONTROLLER_INFO HPT_CTL_CODE(2)
-#define HPT_IOCTL_GET_CHANNEL_INFO HPT_CTL_CODE(3)
-#define HPT_IOCTL_GET_LOGICAL_DEVICES HPT_CTL_CODE(4)
-#define HPT_IOCTL_GET_DRIVER_CAPABILITIES HPT_CTL_CODE(19)
-#define HPT_IOCTL_GET_DEVICE_INFO_V3 HPT_CTL_CODE(46)
-#define HPT_IOCTL_GET_CONTROLLER_INFO_V2 HPT_CTL_CODE(47)
-
-/*
- * Controller information.
- */
-struct hpt_controller_info {
- u8 chip_type; /* chip type */
- u8 interrupt_level; /* IRQ level */
- u8 num_buses; /* bus count */
- u8 chip_flags;
-
- u8 product_id[MAX_NAME_LENGTH];/* product name */
- u8 vendor_id[MAX_NAME_LENGTH]; /* vendor name */
-}
-__attribute__((packed));
-
-/*
- * Channel information.
- */
-struct hpt_channel_info {
- __le32 io_port; /* IDE Base Port Address */
- __le32 control_port; /* IDE Control Port Address */
- __le32 devices[2]; /* device connected to this channel */
-}
-__attribute__((packed));
-
-/*
- * Array information.
- */
-struct hpt_array_info_v3 {
- u8 name[MAX_ARRAYNAME_LEN]; /* array name */
- u8 description[64]; /* array description */
- u8 create_manager[16]; /* who created it */
- __le32 create_time; /* when created it */
-
- u8 array_type; /* array type */
- u8 block_size_shift; /* stripe size */
- u8 ndisk; /* Number of ID in Members[] */
- u8 reserved;
-
- __le32 flags; /* working flags, see ARRAY_FLAG_XXX */
- __le32 members[MAX_ARRAY_MEMBERS_V2]; /* member array/disks */
-
- __le32 rebuilding_progress;
- __le64 rebuilt_sectors; /* rebuilding point (LBA) for single member */
-
- __le32 transform_source;
- __le32 transform_target; /* destination device ID */
- __le32 transforming_progress;
- __le32 signature; /* persistent identification*/
- __le16 critical_members; /* bit mask of critical members */
- __le16 reserve2;
- __le32 reserve;
-}
-__attribute__((packed));
-
-/*
- * physical device information.
- */
-#define MAX_PARENTS_PER_DISK 8
-
-struct hpt_device_info_v2 {
- u8 ctlr_id; /* controller id */
- u8 path_id; /* bus */
- u8 target_id; /* id */
- u8 device_mode_setting; /* Current Data Transfer mode: 0-4 PIO0-4 */
- /* 5-7 MW DMA0-2, 8-13 UDMA0-5 */
- u8 device_type; /* device type */
- u8 usable_mode; /* highest usable mode */
-
-#ifdef __BIG_ENDIAN_BITFIELD
- u8 NCQ_enabled: 1;
- u8 NCQ_supported: 1;
- u8 TCQ_enabled: 1;
- u8 TCQ_supported: 1;
- u8 write_cache_enabled: 1;
- u8 write_cache_supported: 1;
- u8 read_ahead_enabled: 1;
- u8 read_ahead_supported: 1;
- u8 reserved6: 6;
- u8 spin_up_mode: 2;
-#else
- u8 read_ahead_supported: 1;
- u8 read_ahead_enabled: 1;
- u8 write_cache_supported: 1;
- u8 write_cache_enabled: 1;
- u8 TCQ_supported: 1;
- u8 TCQ_enabled: 1;
- u8 NCQ_supported: 1;
- u8 NCQ_enabled: 1;
- u8 spin_up_mode: 2;
- u8 reserved6: 6;
-#endif
-
- __le32 flags; /* working flags, see DEVICE_FLAG_XXX */
- u8 ident[150]; /* (partitial) Identify Data of this device */
-
- __le64 total_free;
- __le64 max_free;
- __le64 bad_sectors;
- __le32 parent_arrays[MAX_PARENTS_PER_DISK];
-}
-__attribute__((packed));
-
-/*
- * Logical device information.
- */
-#define INVALID_TARGET_ID 0xFF
-#define INVALID_BUS_ID 0xFF
-
-struct hpt_logical_device_info_v3 {
- u8 type; /* LDT_ARRAY or LDT_DEVICE */
- u8 cache_policy; /* refer to CACHE_POLICY_xxx */
- u8 vbus_id; /* vbus sequence in vbus_list */
- u8 target_id; /* OS target id. 0xFF is invalid */
- /* OS name: DISK $VBusId_$TargetId */
- __le64 capacity; /* array capacity */
- __le32 parent_array; /* don't use this field for physical
- device. use ParentArrays field in
- hpt_device_info_v2 */
- /* reserved statistic fields */
- __le32 stat1;
- __le32 stat2;
- __le32 stat3;
- __le32 stat4;
-
- union {
- struct hpt_array_info_v3 array;
- struct hpt_device_info_v2 device;
- } __attribute__((packed)) u;
-
-}
-__attribute__((packed));
-
-/*
- * ioctl structure
- */
-#define HPT_IOCTL_MAGIC 0xA1B2C3D4
-
-struct hpt_ioctl_u {
- u32 magic; /* used to check if it's a valid ioctl packet */
- u32 ioctl_code; /* operation control code */
- void __user *inbuf; /* input data buffer */
- u32 inbuf_size; /* size of input data buffer */
- void __user *outbuf; /* output data buffer */
- u32 outbuf_size; /* size of output data buffer */
- void __user *bytes_returned; /* count of bytes returned */
-}
-__attribute__((packed));
-
-
struct hpt_iopmu
{
__le32 resrved0[4];
@@ -252,6 +39,8 @@ struct hpt_iopmu
#define IOPMU_QUEUE_EMPTY 0xffffffff
#define IOPMU_QUEUE_MASK_HOST_BITS 0xf0000000
#define IOPMU_QUEUE_ADDR_HOST_BIT 0x80000000
+#define IOPMU_QUEUE_REQUEST_SIZE_BIT 0x40000000
+#define IOPMU_QUEUE_REQUEST_RESULT_BIT 0x40000000
#define IOPMU_OUTBOUND_INT_MSG0 1
#define IOPMU_OUTBOUND_INT_MSG1 2
@@ -336,7 +125,8 @@ struct hpt_iop_request_set_config
{
struct hpt_iop_request_header header;
__le32 iop_id;
- __le32 vbus_id;
+ __le16 vbus_id;
+ __le16 max_host_request_size;
__le32 reserve[6];
};
@@ -412,9 +202,8 @@ struct hptiop_hba {
struct Scsi_Host * host;
struct pci_dev * pcidev;
- struct list_head link;
-
/* IOP config info */
+ u32 interface_version;
u32 firmware_version;
u32 sdram_size;
u32 max_devices;
@@ -423,8 +212,10 @@ struct hptiop_hba {
u32 max_sg_descriptors;
u32 req_size; /* host-allocated request buffer size */
- int initialized;
- int msg_done;
+
+ int iopintf_v2: 1;
+ int initialized: 1;
+ int msg_done: 1;
struct hptiop_request * req_list;
struct hptiop_request reqs[HPTIOP_MAX_REQUESTS];
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 4275d1b04ce..db004a45073 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -460,13 +460,6 @@ module_param(boot_options, charp, 0);
module_param_array(io_port, int, NULL, 0);
module_param_array(scsi_id, int, NULL, 0);
-#if 0 /* FIXME: No longer exist? --RR */
-MODULE_PARM(display, "1i");
-MODULE_PARM(adisplay, "1i");
-MODULE_PARM(normal, "1i");
-MODULE_PARM(ansi, "1i");
-#endif
-
MODULE_LICENSE("GPL");
#endif
/*counter of concurrent disk read/writes, to turn on/off disk led */
@@ -1508,6 +1501,7 @@ static struct scsi_host_template ibmmca_driver_template = {
.sg_tablesize = 16,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
static int ibmmca_probe(struct device *dev)
@@ -1693,6 +1687,7 @@ static int __devexit ibmmca_remove(struct device *dev)
scsi_remove_host(shpnt);
release_region(shpnt->io_port, shpnt->n_io_port);
free_irq(shpnt->irq, dev);
+ scsi_host_put(shpnt);
return 0;
}
@@ -1833,7 +1828,7 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
BUG_ON(scsi_sg_count(cmd) > 16);
scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
- ld(shpnt)[ldn].sge[i].address = (void *) (isa_page_to_bus(sg->page) + sg->offset);
+ ld(shpnt)[ldn].sge[i].address = (void *) (isa_page_to_bus(sg_page(sg)) + sg->offset);
ld(shpnt)[ldn].sge[i].byte_length = sg->length;
}
scb->enable |= IM_POINTER_TO_LIST;
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
index f67d9efc7a9..6ac0633d545 100644
--- a/drivers/scsi/ibmvscsi/Makefile
+++ b/drivers/scsi/ibmvscsi/Makefile
@@ -1,9 +1,7 @@
obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o
ibmvscsic-y += ibmvscsi.o
-ifndef CONFIG_PPC_PSERIES
ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o
-endif
ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o
obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 5ecc63d1b43..5f2396c0395 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -70,11 +70,13 @@
#include <linux/moduleparam.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
+#include <asm/firmware.h>
#include <asm/vio.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport_srp.h>
#include "ibmvscsi.h"
/* The values below are somewhat arbitrary default values, but
@@ -87,8 +89,12 @@ static int max_channel = 3;
static int init_timeout = 5;
static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
+static struct scsi_transport_template *ibmvscsi_transport_template;
+
#define IBMVSCSI_VERSION "1.5.8"
+static struct ibmvscsi_ops *ibmvscsi_ops;
+
MODULE_DESCRIPTION("IBM Virtual SCSI");
MODULE_AUTHOR("Dave Boutcher");
MODULE_LICENSE("GPL");
@@ -506,8 +512,8 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
atomic_set(&hostdata->request_limit, 0);
purge_requests(hostdata, DID_ERROR);
- if ((ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata)) ||
- (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0)) ||
+ if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata)) ||
+ (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0)) ||
(vio_enable_interrupts(to_vio_dev(hostdata->dev)))) {
atomic_set(&hostdata->request_limit, -1);
dev_err(hostdata->dev, "error after reset\n");
@@ -550,7 +556,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
unsigned long timeout)
{
u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
- int request_status;
+ int request_status = 0;
int rc;
/* If we have exhausted our request limit, just fail this request,
@@ -568,6 +574,13 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
if (request_status < -1)
goto send_error;
/* Otherwise, we may have run out of requests. */
+ /* If request limit was 0 when we started the adapter is in the
+ * process of performing a login with the server adapter, or
+ * we may have run out of requests.
+ */
+ else if (request_status == -1 &&
+ evt_struct->iu.srp.login_req.opcode != SRP_LOGIN_REQ)
+ goto send_busy;
/* Abort and reset calls should make it through.
* Nothing except abort and reset should use the last two
* slots unless we had two or less to begin with.
@@ -612,7 +625,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
}
if ((rc =
- ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
+ ibmvscsi_ops->send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
list_del(&evt_struct->list);
del_timer(&evt_struct->timer);
@@ -627,7 +640,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
free_event_struct(&hostdata->pool, evt_struct);
- atomic_inc(&hostdata->request_limit);
+ if (request_status != -1)
+ atomic_inc(&hostdata->request_limit);
return SCSI_MLQUEUE_HOST_BUSY;
send_error:
@@ -921,10 +935,11 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata)
login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT;
spin_lock_irqsave(hostdata->host->host_lock, flags);
- /* Start out with a request limit of 1, since this is negotiated in
- * the login request we are just sending
+ /* Start out with a request limit of 0, since this is negotiated in
+ * the login request we are just sending and login requests always
+ * get sent by the driver regardless of request_limit.
*/
- atomic_set(&hostdata->request_limit, 1);
+ atomic_set(&hostdata->request_limit, 0);
rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
@@ -1211,8 +1226,8 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
case 0x01: /* Initialization message */
dev_info(hostdata->dev, "partner initialized\n");
/* Send back a response */
- if ((rc = ibmvscsi_send_crq(hostdata,
- 0xC002000000000000LL, 0)) == 0) {
+ if ((rc = ibmvscsi_ops->send_crq(hostdata,
+ 0xC002000000000000LL, 0)) == 0) {
/* Now login */
send_srp_login(hostdata);
} else {
@@ -1237,10 +1252,10 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
/* We need to re-setup the interpartition connection */
dev_info(hostdata->dev, "Re-enabling adapter!\n");
purge_requests(hostdata, DID_REQUEUE);
- if ((ibmvscsi_reenable_crq_queue(&hostdata->queue,
- hostdata)) ||
- (ibmvscsi_send_crq(hostdata,
- 0xC001000000000000LL, 0))) {
+ if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue,
+ hostdata)) ||
+ (ibmvscsi_ops->send_crq(hostdata,
+ 0xC001000000000000LL, 0))) {
atomic_set(&hostdata->request_limit,
-1);
dev_err(hostdata->dev, "error after enable\n");
@@ -1250,10 +1265,10 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
crq->format);
purge_requests(hostdata, DID_ERROR);
- if ((ibmvscsi_reset_crq_queue(&hostdata->queue,
- hostdata)) ||
- (ibmvscsi_send_crq(hostdata,
- 0xC001000000000000LL, 0))) {
+ if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue,
+ hostdata)) ||
+ (ibmvscsi_ops->send_crq(hostdata,
+ 0xC001000000000000LL, 0))) {
atomic_set(&hostdata->request_limit,
-1);
dev_err(hostdata->dev, "error after reset\n");
@@ -1542,6 +1557,7 @@ static struct scsi_host_template driver_template = {
.this_id = -1,
.sg_tablesize = SG_ALL,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.shost_attrs = ibmvscsi_attrs,
};
@@ -1553,6 +1569,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
struct ibmvscsi_host_data *hostdata;
struct Scsi_Host *host;
struct device *dev = &vdev->dev;
+ struct srp_rport_identifiers ids;
+ struct srp_rport *rport;
unsigned long wait_switch = 0;
int rc;
@@ -1565,6 +1583,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
goto scsi_host_alloc_failed;
}
+ host->transportt = ibmvscsi_transport_template;
hostdata = shost_priv(host);
memset(hostdata, 0x00, sizeof(*hostdata));
INIT_LIST_HEAD(&hostdata->sent);
@@ -1573,7 +1592,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
atomic_set(&hostdata->request_limit, -1);
hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */
- rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests);
+ rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_requests);
if (rc != 0 && rc != H_RESOURCE) {
dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
goto init_crq_failed;
@@ -1590,11 +1609,19 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
if (scsi_add_host(hostdata->host, hostdata->dev))
goto add_host_failed;
+ /* we don't have a proper target_port_id so let's use the fake one */
+ memcpy(ids.port_id, hostdata->madapter_info.partition_name,
+ sizeof(ids.port_id));
+ ids.roles = SRP_RPORT_ROLE_TARGET;
+ rport = srp_rport_add(host, &ids);
+ if (IS_ERR(rport))
+ goto add_srp_port_failed;
+
/* Try to send an initialization message. Note that this is allowed
* to fail if the other end is not acive. In that case we don't
* want to scan
*/
- if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0
+ if (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0) == 0
|| rc == H_RESOURCE) {
/*
* Wait around max init_timeout secs for the adapter to finish
@@ -1617,10 +1644,12 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
vdev->dev.driver_data = hostdata;
return 0;
+ add_srp_port_failed:
+ scsi_remove_host(hostdata->host);
add_host_failed:
release_event_pool(&hostdata->pool, hostdata);
init_pool_failed:
- ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_requests);
+ ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_requests);
init_crq_failed:
scsi_host_put(host);
scsi_host_alloc_failed:
@@ -1631,9 +1660,10 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
{
struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
release_event_pool(&hostdata->pool, hostdata);
- ibmvscsi_release_crq_queue(&hostdata->queue, hostdata,
- max_requests);
-
+ ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
+ max_requests);
+
+ srp_remove_host(hostdata->host);
scsi_remove_host(hostdata->host);
scsi_host_put(hostdata->host);
@@ -1660,14 +1690,35 @@ static struct vio_driver ibmvscsi_driver = {
}
};
+static struct srp_function_template ibmvscsi_transport_functions = {
+};
+
int __init ibmvscsi_module_init(void)
{
- return vio_register_driver(&ibmvscsi_driver);
+ int ret;
+
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ ibmvscsi_ops = &iseriesvscsi_ops;
+ else if (firmware_has_feature(FW_FEATURE_VIO))
+ ibmvscsi_ops = &rpavscsi_ops;
+ else
+ return -ENODEV;
+
+ ibmvscsi_transport_template =
+ srp_attach_transport(&ibmvscsi_transport_functions);
+ if (!ibmvscsi_transport_template)
+ return -ENOMEM;
+
+ ret = vio_register_driver(&ibmvscsi_driver);
+ if (ret)
+ srp_release_transport(ibmvscsi_transport_template);
+ return ret;
}
void __exit ibmvscsi_module_exit(void)
{
vio_unregister_driver(&ibmvscsi_driver);
+ srp_release_transport(ibmvscsi_transport_template);
}
module_init(ibmvscsi_module_init);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index b19c2e26c2a..46e850e302c 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -98,21 +98,25 @@ struct ibmvscsi_host_data {
};
/* routines for managing a command/response queue */
-int ibmvscsi_init_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata,
- int max_requests);
-void ibmvscsi_release_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata,
- int max_requests);
-int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata);
-
-int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata);
-
void ibmvscsi_handle_crq(struct viosrp_crq *crq,
struct ibmvscsi_host_data *hostdata);
-int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
- u64 word1, u64 word2);
+
+struct ibmvscsi_ops {
+ int (*init_crq_queue)(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata,
+ int max_requests);
+ void (*release_crq_queue)(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata,
+ int max_requests);
+ int (*reset_crq_queue)(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata);
+ int (*reenable_crq_queue)(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata);
+ int (*send_crq)(struct ibmvscsi_host_data *hostdata,
+ u64 word1, u64 word2);
+};
+
+extern struct ibmvscsi_ops iseriesvscsi_ops;
+extern struct ibmvscsi_ops rpavscsi_ops;
#endif /* IBMVSCSI_H */
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index 8ba7dd09d01..82bcab688b4 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_srp.h>
#include <scsi/scsi_tgt.h>
#include <scsi/libsrp.h>
#include <asm/hvcall.h>
@@ -68,9 +69,12 @@ struct vio_port {
unsigned long liobn;
unsigned long riobn;
struct srp_target *target;
+
+ struct srp_rport *rport;
};
static struct workqueue_struct *vtgtd;
+static struct scsi_transport_template *ibmvstgt_transport_template;
/*
* These are fixed for the system and come from the Open Firmware device tree.
@@ -188,6 +192,7 @@ static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc,
static void handle_cmd_queue(struct srp_target *target)
{
struct Scsi_Host *shost = target->shost;
+ struct srp_rport *rport = target_to_port(target)->rport;
struct iu_entry *iue;
struct srp_cmd *cmd;
unsigned long flags;
@@ -200,7 +205,8 @@ retry:
if (!test_and_set_bit(V_FLYING, &iue->flags)) {
spin_unlock_irqrestore(&target->lock, flags);
cmd = iue->sbuf->buf;
- err = srp_cmd_queue(shost, cmd, iue, 0);
+ err = srp_cmd_queue(shost, cmd, iue,
+ (unsigned long)rport, 0);
if (err) {
eprintk("cannot queue cmd %p %d\n", cmd, err);
srp_iu_put(iue);
@@ -359,6 +365,16 @@ static void process_login(struct iu_entry *iue)
union viosrp_iu *iu = vio_iu(iue);
struct srp_login_rsp *rsp = &iu->srp.login_rsp;
uint64_t tag = iu->srp.rsp.tag;
+ struct Scsi_Host *shost = iue->target->shost;
+ struct srp_target *target = host_to_srp_target(shost);
+ struct vio_port *vport = target_to_port(target);
+ struct srp_rport_identifiers ids;
+
+ memset(&ids, 0, sizeof(ids));
+ sprintf(ids.port_id, "%x", vport->dma_dev->unit_address);
+ ids.roles = SRP_RPORT_ROLE_INITIATOR;
+ if (!vport->rport)
+ vport->rport = srp_rport_add(shost, &ids);
/* TODO handle case that requested size is wrong and
* buffer format is wrong
@@ -412,7 +428,9 @@ static int process_tsk_mgmt(struct iu_entry *iue)
fn = 0;
}
if (fn)
- scsi_tgt_tsk_mgmt_request(iue->target->shost, fn,
+ scsi_tgt_tsk_mgmt_request(iue->target->shost,
+ (unsigned long)iue->target->shost,
+ fn,
iu->srp.tsk_mgmt.task_tag,
(struct scsi_lun *) &iu->srp.tsk_mgmt.lun,
iue);
@@ -721,7 +739,8 @@ static int ibmvstgt_eh_abort_handler(struct scsi_cmnd *sc)
return 0;
}
-static int ibmvstgt_tsk_mgmt_response(u64 mid, int result)
+static int ibmvstgt_tsk_mgmt_response(struct Scsi_Host *shost,
+ u64 itn_id, u64 mid, int result)
{
struct iu_entry *iue = (struct iu_entry *) ((void *) mid);
union viosrp_iu *iu = vio_iu(iue);
@@ -747,6 +766,20 @@ static int ibmvstgt_tsk_mgmt_response(u64 mid, int result)
return 0;
}
+static int ibmvstgt_it_nexus_response(struct Scsi_Host *shost, u64 itn_id,
+ int result)
+{
+ struct srp_target *target = host_to_srp_target(shost);
+ struct vio_port *vport = target_to_port(target);
+
+ if (result) {
+ eprintk("%p %d\n", shost, result);
+ srp_rport_del(vport->rport);
+ vport->rport = NULL;
+ }
+ return 0;
+}
+
static ssize_t system_id_show(struct class_device *cdev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", system_id);
@@ -785,9 +818,9 @@ static struct scsi_host_template ibmvstgt_sht = {
.max_sectors = DEFAULT_MAX_SECTORS,
.transfer_response = ibmvstgt_cmd_done,
.eh_abort_handler = ibmvstgt_eh_abort_handler,
- .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response,
.shost_attrs = ibmvstgt_attrs,
.proc_name = TGT_NAME,
+ .supported_mode = MODE_TARGET,
};
static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
@@ -804,6 +837,7 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
shost = scsi_host_alloc(&ibmvstgt_sht, sizeof(struct srp_target));
if (!shost)
goto free_vport;
+ shost->transportt = ibmvstgt_transport_template;
err = scsi_tgt_alloc_queue(shost);
if (err)
goto put_host;
@@ -837,8 +871,8 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id)
err = scsi_add_host(shost, target->dev);
if (err)
goto destroy_queue;
- return 0;
+ return 0;
destroy_queue:
crq_queue_destroy(target);
free_srp_target:
@@ -857,6 +891,7 @@ static int ibmvstgt_remove(struct vio_dev *dev)
struct vio_port *vport = target->ldata;
crq_queue_destroy(target);
+ srp_remove_host(shost);
scsi_remove_host(shost);
scsi_tgt_free_queue(shost);
srp_target_free(target);
@@ -909,15 +944,25 @@ static int get_system_info(void)
return 0;
}
+static struct srp_function_template ibmvstgt_transport_functions = {
+ .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response,
+ .it_nexus_response = ibmvstgt_it_nexus_response,
+};
+
static int ibmvstgt_init(void)
{
int err = -ENOMEM;
printk("IBM eServer i/pSeries Virtual SCSI Target Driver\n");
+ ibmvstgt_transport_template =
+ srp_attach_transport(&ibmvstgt_transport_functions);
+ if (!ibmvstgt_transport_template)
+ return err;
+
vtgtd = create_workqueue("ibmvtgtd");
if (!vtgtd)
- return err;
+ goto release_transport;
err = get_system_info();
if (err)
@@ -928,9 +973,10 @@ static int ibmvstgt_init(void)
goto destroy_wq;
return 0;
-
destroy_wq:
destroy_workqueue(vtgtd);
+release_transport:
+ srp_release_transport(ibmvstgt_transport_template);
return err;
}
@@ -940,6 +986,7 @@ static void ibmvstgt_exit(void)
destroy_workqueue(vtgtd);
vio_unregister_driver(&ibmvstgt_driver);
+ srp_release_transport(ibmvstgt_transport_template);
}
MODULE_DESCRIPTION("IBM Virtual SCSI Target");
diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c
index 6aeb5f003c3..0775fdee5fa 100644
--- a/drivers/scsi/ibmvscsi/iseries_vscsi.c
+++ b/drivers/scsi/ibmvscsi/iseries_vscsi.c
@@ -53,7 +53,7 @@ struct srp_lp_event {
/**
* standard interface for handling logical partition events.
*/
-static void ibmvscsi_handle_event(struct HvLpEvent *lpevt)
+static void iseriesvscsi_handle_event(struct HvLpEvent *lpevt)
{
struct srp_lp_event *evt = (struct srp_lp_event *)lpevt;
@@ -74,9 +74,9 @@ static void ibmvscsi_handle_event(struct HvLpEvent *lpevt)
/* ------------------------------------------------------------
* Routines for driver initialization
*/
-int ibmvscsi_init_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata,
- int max_requests)
+static int iseriesvscsi_init_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata,
+ int max_requests)
{
int rc;
@@ -88,7 +88,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
goto viopath_open_failed;
}
- rc = vio_setHandler(viomajorsubtype_scsi, ibmvscsi_handle_event);
+ rc = vio_setHandler(viomajorsubtype_scsi, iseriesvscsi_handle_event);
if (rc < 0) {
printk("vio_setHandler failed with rc %d in open_event_path\n",
rc);
@@ -102,9 +102,9 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
return -1;
}
-void ibmvscsi_release_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata,
- int max_requests)
+static void iseriesvscsi_release_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata,
+ int max_requests)
{
vio_clearHandler(viomajorsubtype_scsi);
viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests);
@@ -117,8 +117,8 @@ void ibmvscsi_release_crq_queue(struct crq_queue *queue,
*
* no-op for iSeries
*/
-int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata)
+static int iseriesvscsi_reset_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata)
{
return 0;
}
@@ -130,19 +130,20 @@ int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
*
* no-op for iSeries
*/
-int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata)
+static int iseriesvscsi_reenable_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata)
{
return 0;
}
/**
- * ibmvscsi_send_crq: - Send a CRQ
+ * iseriesvscsi_send_crq: - Send a CRQ
* @hostdata: the adapter
* @word1: the first 64 bits of the data
* @word2: the second 64 bits of the data
*/
-int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
+static int iseriesvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
+ u64 word1, u64 word2)
{
single_host_data = hostdata;
return HvCallEvent_signalLpEventFast(viopath_hostLp,
@@ -156,3 +157,11 @@ int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
VIOVERSION << 16, word1, word2, 0,
0);
}
+
+struct ibmvscsi_ops iseriesvscsi_ops = {
+ .init_crq_queue = iseriesvscsi_init_crq_queue,
+ .release_crq_queue = iseriesvscsi_release_crq_queue,
+ .reset_crq_queue = iseriesvscsi_reset_crq_queue,
+ .reenable_crq_queue = iseriesvscsi_reenable_crq_queue,
+ .send_crq = iseriesvscsi_send_crq,
+};
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 9c14e789df5..182146100dc 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -42,14 +42,14 @@ static unsigned int partition_number = -1;
* Routines for managing the command/response queue
*/
/**
- * ibmvscsi_handle_event: - Interrupt handler for crq events
+ * rpavscsi_handle_event: - Interrupt handler for crq events
* @irq: number of irq to handle, not used
* @dev_instance: ibmvscsi_host_data of host that received interrupt
*
* Disables interrupts and schedules srp_task
* Always returns IRQ_HANDLED
*/
-static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
+static irqreturn_t rpavscsi_handle_event(int irq, void *dev_instance)
{
struct ibmvscsi_host_data *hostdata =
(struct ibmvscsi_host_data *)dev_instance;
@@ -66,9 +66,9 @@ static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
* Frees irq, deallocates a page for messages, unmaps dma, and unregisters
* the crq with the hypervisor.
*/
-void ibmvscsi_release_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata,
- int max_requests)
+static void rpavscsi_release_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata,
+ int max_requests)
{
long rc;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -108,12 +108,13 @@ static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue)
}
/**
- * ibmvscsi_send_crq: - Send a CRQ
+ * rpavscsi_send_crq: - Send a CRQ
* @hostdata: the adapter
* @word1: the first 64 bits of the data
* @word2: the second 64 bits of the data
*/
-int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
+static int rpavscsi_send_crq(struct ibmvscsi_host_data *hostdata,
+ u64 word1, u64 word2)
{
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -121,10 +122,10 @@ int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
}
/**
- * ibmvscsi_task: - Process srps asynchronously
+ * rpavscsi_task: - Process srps asynchronously
* @data: ibmvscsi_host_data of host
*/
-static void ibmvscsi_task(void *data)
+static void rpavscsi_task(void *data)
{
struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -190,6 +191,42 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
}
/**
+ * reset_crq_queue: - resets a crq after a failure
+ * @queue: crq_queue to initialize and register
+ * @hostdata: ibmvscsi_host_data of host
+ *
+ */
+static int rpavscsi_reset_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata)
+{
+ int rc;
+ struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+
+ /* Close the CRQ */
+ do {
+ rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+ } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
+
+ /* Clean out the queue */
+ memset(queue->msgs, 0x00, PAGE_SIZE);
+ queue->cur = 0;
+
+ set_adapter_info(hostdata);
+
+ /* And re-open it again */
+ rc = plpar_hcall_norets(H_REG_CRQ,
+ vdev->unit_address,
+ queue->msg_token, PAGE_SIZE);
+ if (rc == 2) {
+ /* Adapter is good, but other end is not ready */
+ dev_warn(hostdata->dev, "Partner adapter not ready\n");
+ } else if (rc != 0) {
+ dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
+ }
+ return rc;
+}
+
+/**
* initialize_crq_queue: - Initializes and registers CRQ with hypervisor
* @queue: crq_queue to initialize and register
* @hostdata: ibmvscsi_host_data of host
@@ -198,9 +235,9 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
* the crq with the hypervisor.
* Returns zero on success.
*/
-int ibmvscsi_init_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata,
- int max_requests)
+static int rpavscsi_init_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata,
+ int max_requests)
{
int rc;
int retrc;
@@ -227,7 +264,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
queue->msg_token, PAGE_SIZE);
if (rc == H_RESOURCE)
/* maybe kexecing and resource is busy. try a reset */
- rc = ibmvscsi_reset_crq_queue(queue,
+ rc = rpavscsi_reset_crq_queue(queue,
hostdata);
if (rc == 2) {
@@ -240,7 +277,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
}
if (request_irq(vdev->irq,
- ibmvscsi_handle_event,
+ rpavscsi_handle_event,
0, "ibmvscsi", (void *)hostdata) != 0) {
dev_err(hostdata->dev, "couldn't register irq 0x%x\n",
vdev->irq);
@@ -256,7 +293,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
queue->cur = 0;
spin_lock_init(&queue->lock);
- tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task,
+ tasklet_init(&hostdata->srp_task, (void *)rpavscsi_task,
(unsigned long)hostdata);
return retrc;
@@ -281,8 +318,8 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
* @hostdata: ibmvscsi_host_data of host
*
*/
-int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata)
+static int rpavscsi_reenable_crq_queue(struct crq_queue *queue,
+ struct ibmvscsi_host_data *hostdata)
{
int rc;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
@@ -297,38 +334,10 @@ int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
return rc;
}
-/**
- * reset_crq_queue: - resets a crq after a failure
- * @queue: crq_queue to initialize and register
- * @hostdata: ibmvscsi_host_data of host
- *
- */
-int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
- struct ibmvscsi_host_data *hostdata)
-{
- int rc;
- struct vio_dev *vdev = to_vio_dev(hostdata->dev);
-
- /* Close the CRQ */
- do {
- rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
- } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
-
- /* Clean out the queue */
- memset(queue->msgs, 0x00, PAGE_SIZE);
- queue->cur = 0;
-
- set_adapter_info(hostdata);
-
- /* And re-open it again */
- rc = plpar_hcall_norets(H_REG_CRQ,
- vdev->unit_address,
- queue->msg_token, PAGE_SIZE);
- if (rc == 2) {
- /* Adapter is good, but other end is not ready */
- dev_warn(hostdata->dev, "Partner adapter not ready\n");
- } else if (rc != 0) {
- dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
- }
- return rc;
-}
+struct ibmvscsi_ops rpavscsi_ops = {
+ .init_crq_queue = rpavscsi_init_crq_queue,
+ .release_crq_queue = rpavscsi_release_crq_queue,
+ .reset_crq_queue = rpavscsi_reset_crq_queue,
+ .reenable_crq_queue = rpavscsi_reenable_crq_queue,
+ .send_crq = rpavscsi_send_crq,
+};
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 1cc01acc280..8d0244c2e7d 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -47,9 +47,9 @@
#include <linux/scatterlist.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/bitops.h>
#include <asm/io.h>
-#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <scsi/scsi.h>
@@ -70,6 +70,7 @@ typedef struct idescsi_pc_s {
u8 *buffer; /* Data buffer */
u8 *current_position; /* Pointer into the above buffer */
struct scatterlist *sg; /* Scatter gather table */
+ unsigned int sg_cnt; /* Number of entries in sg */
int b_count; /* Bytes transferred from current entry */
struct scsi_cmnd *scsi_cmd; /* SCSI command */
void (*done)(struct scsi_cmnd *); /* Scsi completion routine */
@@ -82,14 +83,12 @@ typedef struct idescsi_pc_s {
*/
#define PC_DMA_IN_PROGRESS 0 /* 1 while DMA in progress */
#define PC_WRITING 1 /* Data direction */
-#define PC_TRANSFORM 2 /* transform SCSI commands */
#define PC_TIMEDOUT 3 /* command timed out */
#define PC_DMA_OK 4 /* Use DMA */
/*
* SCSI command transformation layer
*/
-#define IDESCSI_TRANSFORM 0 /* Enable/Disable transformation */
#define IDESCSI_SG_TRANSFORM 1 /* /dev/sg transformation */
/*
@@ -175,33 +174,35 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne
char *buf;
while (bcount) {
- if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
- printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n");
- idescsi_discard_data (drive, bcount);
- return;
- }
count = min(pc->sg->length - pc->b_count, bcount);
- if (PageHighMem(pc->sg->page)) {
+ if (PageHighMem(sg_page(pc->sg))) {
unsigned long flags;
local_irq_save(flags);
- buf = kmap_atomic(pc->sg->page, KM_IRQ0) +
+ buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) +
pc->sg->offset;
drive->hwif->atapi_input_bytes(drive,
buf + pc->b_count, count);
kunmap_atomic(buf - pc->sg->offset, KM_IRQ0);
local_irq_restore(flags);
} else {
- buf = page_address(pc->sg->page) + pc->sg->offset;
+ buf = sg_virt(pc->sg);
drive->hwif->atapi_input_bytes(drive,
buf + pc->b_count, count);
}
bcount -= count; pc->b_count += count;
if (pc->b_count == pc->sg->length) {
- pc->sg++;
+ if (!--pc->sg_cnt)
+ break;
+ pc->sg = sg_next(pc->sg);
pc->b_count = 0;
}
}
+
+ if (bcount) {
+ printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n");
+ idescsi_discard_data (drive, bcount);
+ }
}
static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount)
@@ -210,104 +211,35 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign
char *buf;
while (bcount) {
- if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
- printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n");
- idescsi_output_zeros (drive, bcount);
- return;
- }
count = min(pc->sg->length - pc->b_count, bcount);
- if (PageHighMem(pc->sg->page)) {
+ if (PageHighMem(sg_page(pc->sg))) {
unsigned long flags;
local_irq_save(flags);
- buf = kmap_atomic(pc->sg->page, KM_IRQ0) +
+ buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) +
pc->sg->offset;
drive->hwif->atapi_output_bytes(drive,
buf + pc->b_count, count);
kunmap_atomic(buf - pc->sg->offset, KM_IRQ0);
local_irq_restore(flags);
} else {
- buf = page_address(pc->sg->page) + pc->sg->offset;
+ buf = sg_virt(pc->sg);
drive->hwif->atapi_output_bytes(drive,
buf + pc->b_count, count);
}
bcount -= count; pc->b_count += count;
if (pc->b_count == pc->sg->length) {
- pc->sg++;
+ if (!--pc->sg_cnt)
+ break;
+ pc->sg = sg_next(pc->sg);
pc->b_count = 0;
}
}
-}
-/*
- * Most of the SCSI commands are supported directly by ATAPI devices.
- * idescsi_transform_pc handles the few exceptions.
- */
-static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
-{
- u8 *c = pc->c, *scsi_buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
- char *atapi_buf;
-
- if (!test_bit(PC_TRANSFORM, &pc->flags))
- return;
- if (drive->media == ide_cdrom || drive->media == ide_optical) {
- if (c[0] == READ_6 || c[0] == WRITE_6) {
- c[8] = c[4]; c[5] = c[3]; c[4] = c[2];
- c[3] = c[1] & 0x1f; c[2] = 0; c[1] &= 0xe0;
- c[0] += (READ_10 - READ_6);
- }
- if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
- unsigned short new_len;
- if (!scsi_buf)
- return;
- if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL)
- return;
- memset(atapi_buf, 0, pc->buffer_size + 4);
- memset (c, 0, 12);
- c[0] = sc[0] | 0x40;
- c[1] = sc[1];
- c[2] = sc[2];
- new_len = sc[4] + 4;
- c[8] = new_len;
- c[7] = new_len >> 8;
- c[9] = sc[5];
- if (c[0] == MODE_SELECT_10) {
- atapi_buf[1] = scsi_buf[0]; /* Mode data length */
- atapi_buf[2] = scsi_buf[1]; /* Medium type */
- atapi_buf[3] = scsi_buf[2]; /* Device specific parameter */
- atapi_buf[7] = scsi_buf[3]; /* Block descriptor length */
- memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4);
- }
- pc->buffer = atapi_buf;
- pc->request_transfer += 4;
- pc->buffer_size += 4;
- }
- }
-}
-
-static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc)
-{
- u8 *atapi_buf = pc->buffer;
- u8 *sc = pc->scsi_cmd->cmnd;
- u8 *scsi_buf = pc->scsi_cmd->request_buffer;
-
- if (!test_bit(PC_TRANSFORM, &pc->flags))
- return;
- if (drive->media == ide_cdrom || drive->media == ide_optical) {
- if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
- scsi_buf[0] = atapi_buf[1]; /* Mode data length */
- scsi_buf[1] = atapi_buf[2]; /* Medium type */
- scsi_buf[2] = atapi_buf[3]; /* Device specific parameter */
- scsi_buf[3] = atapi_buf[7]; /* Block descriptor length */
- memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8);
- }
- if (pc->c[0] == INQUIRY) {
- scsi_buf[2] |= 2; /* ansi_revision */
- scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2; /* response data format */
- }
+ if (bcount) {
+ printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n");
+ idescsi_output_zeros (drive, bcount);
}
- if (atapi_buf && atapi_buf != scsi_buf)
- kfree(atapi_buf);
}
static void hexdump(u8 *x, int len)
@@ -393,7 +325,6 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
idescsi_pc_t *pc = (idescsi_pc_t *) rq->special;
int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
struct Scsi_Host *host;
- u8 *scsi_buf;
int errors = rq->errors;
unsigned long flags;
@@ -434,15 +365,6 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
} else {
pc->scsi_cmd->result = DID_OK << 16;
- idescsi_transform_pc2 (drive, pc);
- if (log) {
- printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);
- if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
- printk(", rst = ");
- scsi_buf = pc->scsi_cmd->request_buffer;
- hexdump(scsi_buf, min_t(unsigned, 16, pc->scsi_cmd->request_bufflen));
- } else printk("\n");
- }
}
host = pc->scsi_cmd->device->host;
spin_lock_irqsave(host->host_lock, flags);
@@ -637,19 +559,14 @@ static int idescsi_map_sg(ide_drive_t *drive, idescsi_pc_t *pc)
return 1;
sg = hwif->sg_table;
- scsi_sg = pc->scsi_cmd->request_buffer;
- segments = pc->scsi_cmd->use_sg;
+ scsi_sg = scsi_sglist(pc->scsi_cmd);
+ segments = scsi_sg_count(pc->scsi_cmd);
if (segments > hwif->sg_max_nents)
return 1;
- if (!segments) {
- hwif->sg_nents = 1;
- sg_init_one(sg, pc->scsi_cmd->request_buffer, pc->request_transfer);
- } else {
- hwif->sg_nents = segments;
- memcpy(sg, scsi_sg, sizeof(*sg) * segments);
- }
+ hwif->sg_nents = segments;
+ memcpy(sg, scsi_sg, sizeof(*sg) * segments);
return 0;
}
@@ -744,7 +661,6 @@ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi)
{
if (drive->id && (drive->id->config & 0x0060) == 0x20)
set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
- set_bit(IDESCSI_TRANSFORM, &scsi->transform);
clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
#if IDESCSI_DEBUG_LOG
set_bit(IDESCSI_LOG_CMD, &scsi->log);
@@ -758,6 +674,7 @@ static void ide_scsi_remove(ide_drive_t *drive)
struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost);
struct gendisk *g = scsi->disk;
+ scsi_remove_host(scsihost);
ide_proc_unregister_driver(drive, scsi->driver);
ide_unregister_region(g);
@@ -766,7 +683,6 @@ static void ide_scsi_remove(ide_drive_t *drive)
g->private_data = NULL;
put_disk(g);
- scsi_remove_host(scsihost);
ide_scsi_put(scsi);
}
@@ -838,6 +754,8 @@ static struct block_device_operations idescsi_ops = {
static int idescsi_slave_configure(struct scsi_device * sdp)
{
/* Configure detected device */
+ sdp->use_10_for_rw = 1;
+ sdp->use_10_for_ms = 1;
scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, sdp->host->cmd_per_lun);
return 0;
}
@@ -862,24 +780,6 @@ static int idescsi_ioctl (struct scsi_device *dev, int cmd, void __user *arg)
return -EINVAL;
}
-static inline int should_transform(ide_drive_t *drive, struct scsi_cmnd *cmd)
-{
- idescsi_scsi_t *scsi = drive_to_idescsi(drive);
-
- /* this was a layering violation and we can't support it
- anymore, sorry. */
-#if 0
- struct gendisk *disk = cmd->request->rq_disk;
-
- if (disk) {
- struct struct scsi_device_Template **p = disk->private_data;
- if (strcmp((*p)->scsi_driverfs_driver.name, "sg") == 0)
- return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
- }
-#endif
- return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
-}
-
static int idescsi_queue (struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
@@ -905,23 +805,15 @@ static int idescsi_queue (struct scsi_cmnd *cmd,
pc->flags = 0;
pc->rq = rq;
memcpy (pc->c, cmd->cmnd, cmd->cmd_len);
- if (cmd->use_sg) {
- pc->buffer = NULL;
- pc->sg = cmd->request_buffer;
- } else {
- pc->buffer = cmd->request_buffer;
- pc->sg = NULL;
- }
+ pc->buffer = NULL;
+ pc->sg = scsi_sglist(cmd);
+ pc->sg_cnt = scsi_sg_count(cmd);
pc->b_count = 0;
- pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
+ pc->request_transfer = pc->buffer_size = scsi_bufflen(cmd);
pc->scsi_cmd = cmd;
pc->done = done;
pc->timeout = jiffies + cmd->timeout_per_command;
- if (should_transform(drive, cmd))
- set_bit(PC_TRANSFORM, &pc->flags);
- idescsi_transform_pc1 (drive, pc);
-
if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
hexdump(cmd->cmnd, cmd->cmd_len);
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 005d2b05f32..a3d0c6b1495 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -705,9 +705,7 @@ static int imm_completion(struct scsi_cmnd *cmd)
cmd->SCp.buffer++;
cmd->SCp.this_residual =
cmd->SCp.buffer->length;
- cmd->SCp.ptr =
- page_address(cmd->SCp.buffer->page) +
- cmd->SCp.buffer->offset;
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
/*
* Make sure that we transfer even number of bytes
@@ -740,10 +738,6 @@ static void imm_interrupt(struct work_struct *work)
struct Scsi_Host *host = cmd->device->host;
unsigned long flags;
- if (!cmd) {
- printk("IMM: bug in imm_interrupt\n");
- return;
- }
if (imm_engine(dev, cmd)) {
schedule_delayed_work(&dev->imm_tq, 1);
return;
@@ -848,9 +842,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
cmd->SCp.buffer =
(struct scatterlist *) cmd->request_buffer;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr =
- page_address(cmd->SCp.buffer->page) +
- cmd->SCp.buffer->offset;
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
} else {
/* else fill the only available buffer */
cmd->SCp.buffer = NULL;
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index 312190a6938..c8b452f2878 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -343,7 +343,7 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
instance = cmd->device->host;
hostdata = (struct IN2000_hostdata *) instance->hostdata;
- DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x-%ld(", cmd->cmnd[0], cmd->pid))
+ DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x-%ld(", cmd->cmnd[0], cmd->serial_number))
/* Set up a few fields in the Scsi_Cmnd structure for our own use:
* - host_scribble is the pointer to the next cmd in the input queue
@@ -372,7 +372,7 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
if (cmd->use_sg) {
cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
- cmd->SCp.ptr = (char *) page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
cmd->SCp.this_residual = cmd->SCp.buffer->length;
} else {
cmd->SCp.buffer = NULL;
@@ -427,7 +427,7 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
in2000_execute(cmd->device->host);
- DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->pid))
+ DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->serial_number))
return 0;
}
@@ -703,7 +703,7 @@ static void in2000_execute(struct Scsi_Host *instance)
* to search the input_Q again...
*/
- DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->pid))
+ DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->serial_number))
}
@@ -764,7 +764,7 @@ static void transfer_bytes(Scsi_Cmnd * cmd, int data_in_dir)
++cmd->SCp.buffer;
--cmd->SCp.buffers_residual;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
}
/* Set up hardware registers */
@@ -1147,7 +1147,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
case CSR_XFER_DONE | PHS_COMMAND:
case CSR_UNEXP | PHS_COMMAND:
case CSR_SRV_REQ | PHS_COMMAND:
- DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid))
+ DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number))
transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata);
hostdata->state = S_CONNECTED;
break;
@@ -1189,7 +1189,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
switch (msg) {
case COMMAND_COMPLETE:
- DB(DB_INTR, printk("CCMP-%ld", cmd->pid))
+ DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number))
write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
hostdata->state = S_PRE_CMP_DISC;
break;
@@ -1327,7 +1327,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
if (phs == 0x60) {
- DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid))
+ DB(DB_INTR, printk("SX-DONE-%ld", cmd->serial_number))
cmd->SCp.Message = COMMAND_COMPLETE;
lun = read_3393(hostdata, WD_TARGET_LUN);
DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))
@@ -1348,7 +1348,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
in2000_execute(instance);
} else {
- printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs, cmd->pid);
+ printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs, cmd->serial_number);
}
break;
@@ -1415,7 +1415,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
spin_unlock_irqrestore(instance->host_lock, flags);
return IRQ_HANDLED;
}
- DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid))
+ DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->serial_number))
hostdata->connected = NULL;
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
hostdata->state = S_UNCONNECTED;
@@ -1440,7 +1440,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
*/
write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
- DB(DB_INTR, printk("DISC-%ld", cmd->pid))
+ DB(DB_INTR, printk("DISC-%ld", cmd->serial_number))
if (cmd == NULL) {
printk(" - Already disconnected! ");
hostdata->state = S_UNCONNECTED;
@@ -1573,7 +1573,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
} else
hostdata->state = S_CONNECTED;
- DB(DB_INTR, printk("-%ld", cmd->pid))
+ DB(DB_INTR, printk("-%ld", cmd->serial_number))
break;
default:
@@ -1702,7 +1702,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd)
prev->host_scribble = cmd->host_scribble;
cmd->host_scribble = NULL;
cmd->result = DID_ABORT << 16;
- printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->pid);
+ printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->serial_number);
cmd->scsi_done(cmd);
return SUCCESS;
}
@@ -1723,7 +1723,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd)
if (hostdata->connected == cmd) {
- printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->pid);
+ printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->serial_number);
printk("sending wd33c93 ABORT command - ");
write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
@@ -2268,7 +2268,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
strcat(bp, "\nconnected: ");
if (hd->connected) {
cmd = (Scsi_Cmnd *) hd->connected;
- sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
}
}
@@ -2276,7 +2276,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
strcat(bp, "\ninput_Q: ");
cmd = (Scsi_Cmnd *) hd->input_Q;
while (cmd) {
- sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
cmd = (Scsi_Cmnd *) cmd->host_scribble;
}
@@ -2285,7 +2285,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
strcat(bp, "\ndisconnected_Q:");
cmd = (Scsi_Cmnd *) hd->disconnected_Q;
while (cmd) {
- sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
cmd = (Scsi_Cmnd *) cmd->host_scribble;
}
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index d9dfb69ae03..4c4465d39a1 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -665,7 +665,7 @@ static void initio_init(struct initio_host * host, u8 *bios_addr)
host->max_tags[i] = 0xFF;
} /* for */
printk("i91u: PCI Base=0x%04X, IRQ=%d, BIOS=0x%04X0, SCSI ID=%d\n",
- host->addr, host->irq,
+ host->addr, host->pci_dev->irq,
host->bios_addr, host->scsi_id);
/* Reset SCSI Bus */
if (host->config & HCC_SCSI_RESET) {
@@ -2831,6 +2831,7 @@ static struct scsi_host_template initio_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
static int initio_probe_one(struct pci_dev *pdev,
@@ -2890,6 +2891,8 @@ static int initio_probe_one(struct pci_dev *pdev,
goto out_release_region;
}
+ host->pci_dev = pdev;
+
host->num_scbs = num_scb;
host->scb = scb;
host->next_pending = scb;
@@ -2904,6 +2907,7 @@ static int initio_probe_one(struct pci_dev *pdev,
host->scb_end = tmp;
host->first_avail = scb;
host->last_avail = prev;
+ spin_lock_init(&host->avail_lock);
initio_init(host, phys_to_virt(bios_seg << 4));
@@ -2927,7 +2931,6 @@ static int initio_probe_one(struct pci_dev *pdev,
}
pci_set_drvdata(pdev, shost);
- host->pci_dev = pdev;
error = scsi_add_host(shost, &pdev->dev);
if (error)
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index f142eafb6fc..0841df01bc1 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -2872,6 +2872,7 @@ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len)
}
scatterlist = sglist->scatterlist;
+ sg_init_table(scatterlist, num_elem);
sglist->order = order;
sglist->num_sg = num_elem;
@@ -2884,12 +2885,12 @@ static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len)
/* Free up what we already allocated */
for (j = i - 1; j >= 0; j--)
- __free_pages(scatterlist[j].page, order);
+ __free_pages(sg_page(&scatterlist[j]), order);
kfree(sglist);
return NULL;
}
- scatterlist[i].page = page;
+ sg_set_page(&scatterlist[i], page, 0, 0);
}
return sglist;
@@ -2910,7 +2911,7 @@ static void ipr_free_ucode_buffer(struct ipr_sglist *sglist)
int i;
for (i = 0; i < sglist->num_sg; i++)
- __free_pages(sglist->scatterlist[i].page, sglist->order);
+ __free_pages(sg_page(&sglist->scatterlist[i]), sglist->order);
kfree(sglist);
}
@@ -2940,9 +2941,11 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
scatterlist = sglist->scatterlist;
for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) {
- kaddr = kmap(scatterlist[i].page);
+ struct page *page = sg_page(&scatterlist[i]);
+
+ kaddr = kmap(page);
memcpy(kaddr, buffer, bsize_elem);
- kunmap(scatterlist[i].page);
+ kunmap(page);
scatterlist[i].length = bsize_elem;
@@ -2953,9 +2956,11 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
}
if (len % bsize_elem) {
- kaddr = kmap(scatterlist[i].page);
+ struct page *page = sg_page(&scatterlist[i]);
+
+ kaddr = kmap(page);
memcpy(kaddr, buffer, len % bsize_elem);
- kunmap(scatterlist[i].page);
+ kunmap(page);
scatterlist[i].length = len % bsize_elem;
}
@@ -3829,18 +3834,18 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg,
/**
* ipr_sata_reset - Reset the SATA port
- * @ap: SATA port to reset
+ * @link: SATA link to reset
* @classes: class of the attached device
*
- * This function issues a SATA phy reset to the affected ATA port.
+ * This function issues a SATA phy reset to the affected ATA link.
*
* Return value:
* 0 on success / non-zero on failure
**/
-static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes,
+static int ipr_sata_reset(struct ata_link *link, unsigned int *classes,
unsigned long deadline)
{
- struct ipr_sata_port *sata_port = ap->private_data;
+ struct ipr_sata_port *sata_port = link->ap->private_data;
struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
struct ipr_resource_entry *res;
unsigned long lock_flags = 0;
@@ -4981,22 +4986,22 @@ static void ipr_ata_phy_reset(struct ata_port *ap)
rc = ipr_device_reset(ioa_cfg, res);
if (rc) {
- ap->ops->port_disable(ap);
+ ata_port_disable(ap);
goto out_unlock;
}
switch(res->cfgte.proto) {
case IPR_PROTO_SATA:
case IPR_PROTO_SAS_STP:
- ap->device[0].class = ATA_DEV_ATA;
+ ap->link.device[0].class = ATA_DEV_ATA;
break;
case IPR_PROTO_SATA_ATAPI:
case IPR_PROTO_SAS_STP_ATAPI:
- ap->device[0].class = ATA_DEV_ATAPI;
+ ap->link.device[0].class = ATA_DEV_ATAPI;
break;
default:
- ap->device[0].class = ATA_DEV_UNKNOWN;
- ap->ops->port_disable(ap);
+ ap->link.device[0].class = ATA_DEV_UNKNOWN;
+ ata_port_disable(ap);
break;
};
@@ -5134,6 +5139,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
u32 ioadl_flags = 0;
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+ struct ipr_ioadl_desc *last_ioadl = NULL;
int len = qc->nbytes + qc->pad_len;
struct scatterlist *sg;
@@ -5156,11 +5162,13 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
ata_for_each_sg(sg, qc) {
ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg));
ioadl->address = cpu_to_be32(sg_dma_address(sg));
- if (ata_sg_is_last(sg, qc))
- ioadl->flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
- else
- ioadl++;
+
+ last_ioadl = ioadl;
+ ioadl++;
}
+
+ if (likely(last_ioadl))
+ last_ioadl->flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
}
/**
@@ -5262,7 +5270,6 @@ static u8 ipr_ata_check_altstatus(struct ata_port *ap)
}
static struct ata_port_operations ipr_sata_ops = {
- .port_disable = ata_port_disable,
.check_status = ipr_ata_check_status,
.check_altstatus = ipr_ata_check_altstatus,
.dev_select = ata_noop_dev_select,
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 492a51bd6aa..5c5a9b2628f 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -204,8 +204,8 @@ module_param(ips, charp, 0);
/*
* DRIVER_VER
*/
-#define IPS_VERSION_HIGH "7.12"
-#define IPS_VERSION_LOW ".05 "
+#define IPS_VERSION_HIGH IPS_VER_MAJOR_STRING "." IPS_VER_MINOR_STRING
+#define IPS_VERSION_LOW "." IPS_VER_BUILD_STRING " "
#if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__)
#warning "This driver has only been tested on the x86/ia64/x86_64 platforms"
@@ -656,6 +656,8 @@ ips_release(struct Scsi_Host *sh)
METHOD_TRACE("ips_release", 1);
+ scsi_remove_host(sh);
+
for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ;
if (i == IPS_MAX_ADAPTERS) {
@@ -707,7 +709,6 @@ ips_release(struct Scsi_Host *sh)
/* free IRQ */
free_irq(ha->irq, ha);
- scsi_remove_host(sh);
scsi_host_put(sh);
ips_released_controllers++;
@@ -1514,7 +1515,7 @@ static int ips_is_passthru(struct scsi_cmnd *SC)
/* kmap_atomic() ensures addressability of the user buffer.*/
/* local_irq_save() protects the KM_IRQ0 address slot. */
local_irq_save(flags);
- buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
buffer[2] == 'P' && buffer[3] == 'P') {
kunmap_atomic(buffer - sg->offset, KM_IRQ0);
@@ -3251,7 +3252,7 @@ ips_done(ips_ha_t * ha, ips_scb_t * scb)
*/
if ((scb->breakup) || (scb->sg_break)) {
struct scatterlist *sg;
- int sg_dma_index, ips_sg_index = 0;
+ int i, sg_dma_index, ips_sg_index = 0;
/* we had a data breakup */
scb->data_len = 0;
@@ -3260,20 +3261,22 @@ ips_done(ips_ha_t * ha, ips_scb_t * scb)
/* Spin forward to last dma chunk */
sg_dma_index = scb->breakup;
+ for (i = 0; i < scb->breakup; i++)
+ sg = sg_next(sg);
/* Take care of possible partial on last chunk */
ips_fill_scb_sg_single(ha,
- sg_dma_address(&sg[sg_dma_index]),
+ sg_dma_address(sg),
scb, ips_sg_index++,
- sg_dma_len(&sg[sg_dma_index]));
+ sg_dma_len(sg));
for (; sg_dma_index < scsi_sg_count(scb->scsi_cmd);
- sg_dma_index++) {
+ sg_dma_index++, sg = sg_next(sg)) {
if (ips_fill_scb_sg_single
(ha,
- sg_dma_address(&sg[sg_dma_index]),
+ sg_dma_address(sg),
scb, ips_sg_index++,
- sg_dma_len(&sg[sg_dma_index])) < 0)
+ sg_dma_len(sg)) < 0)
break;
}
@@ -3520,7 +3523,7 @@ ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count)
/* kmap_atomic() ensures addressability of the data buffer.*/
/* local_irq_save() protects the KM_IRQ0 address slot. */
local_irq_save(flags);
- buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
+ buffer = kmap_atomic(sg_page(&sg[i]), KM_IRQ0) + sg[i].offset;
memcpy(buffer, &cdata[xfer_cnt], min_cnt);
kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
local_irq_restore(flags);
@@ -3553,7 +3556,7 @@ ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count)
/* kmap_atomic() ensures addressability of the data buffer.*/
/* local_irq_save() protects the KM_IRQ0 address slot. */
local_irq_save(flags);
- buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
+ buffer = kmap_atomic(sg_page(&sg[i]), KM_IRQ0) + sg[i].offset;
memcpy(&cdata[xfer_cnt], buffer, min_cnt);
kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
local_irq_restore(flags);
@@ -6946,7 +6949,7 @@ module_exit(ips_module_exit);
static int __devinit
ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
{
- int index;
+ int uninitialized_var(index);
int rc;
METHOD_TRACE("ips_insert_device", 1);
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index 24123d537c5..3bcbd9ff056 100644
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -1172,12 +1172,13 @@ typedef struct {
*************************************************************************/
#define IPS_VER_MAJOR 7
-#define IPS_VER_MAJOR_STRING "7"
+#define IPS_VER_MAJOR_STRING __stringify(IPS_VER_MAJOR)
#define IPS_VER_MINOR 12
-#define IPS_VER_MINOR_STRING "12"
-#define IPS_VER_BUILD 02
-#define IPS_VER_BUILD_STRING "02"
-#define IPS_VER_STRING "7.12.02"
+#define IPS_VER_MINOR_STRING __stringify(IPS_VER_MINOR)
+#define IPS_VER_BUILD 05
+#define IPS_VER_BUILD_STRING __stringify(IPS_VER_BUILD)
+#define IPS_VER_STRING IPS_VER_MAJOR_STRING "." \
+ IPS_VER_MINOR_STRING "." IPS_VER_BUILD_STRING
#define IPS_RELEASE_ID 0x00020000
#define IPS_BUILD_IDENT 761
#define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002. All Rights Reserved."
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index a21455d0274..4bcf916c21a 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -70,9 +70,7 @@ module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
static inline void
iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
{
- ibuf->sg.page = virt_to_page(vbuf);
- ibuf->sg.offset = offset_in_page(vbuf);
- ibuf->sg.length = size;
+ sg_init_one(&ibuf->sg, vbuf, size);
ibuf->sent = 0;
ibuf->use_sendmsg = 1;
}
@@ -80,13 +78,12 @@ iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size)
static inline void
iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg)
{
- ibuf->sg.page = sg->page;
- ibuf->sg.offset = sg->offset;
- ibuf->sg.length = sg->length;
+ sg_init_table(&ibuf->sg, 1);
+ sg_set_page(&ibuf->sg, sg_page(sg), sg->length, sg->offset);
/*
* Fastpath: sg element fits into single page
*/
- if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg->page))
+ if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg_page(sg)))
ibuf->use_sendmsg = 0;
else
ibuf->use_sendmsg = 1;
@@ -677,9 +674,8 @@ partial_sg_digest_update(struct hash_desc *desc, struct scatterlist *sg,
{
struct scatterlist temp;
- memcpy(&temp, sg, sizeof(struct scatterlist));
- temp.offset = offset;
- temp.length = length;
+ sg_init_table(&temp, 1);
+ sg_set_page(&temp, sg_page(sg), length, offset);
crypto_hash_update(desc, &temp, length);
}
@@ -716,7 +712,7 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
for (i = tcp_ctask->sg_count; i < scsi_sg_count(sc); i++) {
char *dest;
- dest = kmap_atomic(sg[i].page, KM_SOFTIRQ0);
+ dest = kmap_atomic(sg_page(&sg[i]), KM_SOFTIRQ0);
rc = iscsi_ctask_copy(tcp_conn, ctask, dest + sg[i].offset,
sg[i].length, offset);
kunmap_atomic(dest, KM_SOFTIRQ0);
@@ -1103,9 +1099,9 @@ iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags)
* slab case.
*/
if (buf->use_sendmsg)
- res = sock_no_sendpage(sk, buf->sg.page, offset, size, flags);
+ res = sock_no_sendpage(sk, sg_page(&buf->sg), offset, size, flags);
else
- res = tcp_conn->sendpage(sk, buf->sg.page, offset, size, flags);
+ res = tcp_conn->sendpage(sk, sg_page(&buf->sg), offset, size, flags);
if (res >= 0) {
conn->txdata_octets += res;
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 5e573efcf0a..0829b55c64d 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -249,17 +249,17 @@ static void sas_ata_phy_reset(struct ata_port *ap)
switch (dev->sata_dev.command_set) {
case ATA_COMMAND_SET:
SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__);
- ap->device[0].class = ATA_DEV_ATA;
+ ap->link.device[0].class = ATA_DEV_ATA;
break;
case ATAPI_COMMAND_SET:
SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__);
- ap->device[0].class = ATA_DEV_ATAPI;
+ ap->link.device[0].class = ATA_DEV_ATAPI;
break;
default:
SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
__FUNCTION__,
dev->sata_dev.command_set);
- ap->device[0].class = ATA_DEV_UNKNOWN;
+ ap->link.device[0].class = ATA_DEV_UNKNOWN;
break;
}
@@ -317,7 +317,7 @@ static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
dev->sata_dev.serror = val;
break;
case SCR_ACTIVE:
- dev->sata_dev.ap->sactive = val;
+ dev->sata_dev.ap->link.sactive = val;
break;
default:
return -EINVAL;
@@ -342,7 +342,7 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
*val = dev->sata_dev.serror;
return 0;
case SCR_ACTIVE:
- *val = dev->sata_dev.ap->sactive;
+ *val = dev->sata_dev.ap->link.sactive;
return 0;
default:
return -EINVAL;
@@ -350,7 +350,6 @@ static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
}
static struct ata_port_operations sas_sata_ops = {
- .port_disable = ata_port_disable,
.check_status = sas_ata_check_status,
.check_altstatus = sas_ata_check_status,
.dev_select = ata_noop_dev_select,
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 7ef0afc3cd6..5f3a0d7b18d 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -285,7 +285,7 @@ static void sas_discover_domain(struct work_struct *work)
dev = port->port_dev;
SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id,
- current->pid);
+ task_pid_nr(current));
switch (dev->dev_type) {
case SAS_END_DEV:
@@ -320,7 +320,7 @@ static void sas_discover_domain(struct work_struct *work)
}
SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id,
- current->pid, error);
+ task_pid_nr(current), error);
}
static void sas_revalidate_domain(struct work_struct *work)
@@ -334,12 +334,12 @@ static void sas_revalidate_domain(struct work_struct *work)
&port->disc.pending);
SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
- current->pid);
+ task_pid_nr(current));
if (port->port_dev)
res = sas_ex_revalidate_domain(port->port_dev);
SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
- port->id, current->pid, res);
+ port->id, task_pid_nr(current), res);
}
/* ---------- Events ---------- */
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
index 732446e6396..2ad0a27dbaa 100644
--- a/drivers/scsi/libsrp.c
+++ b/drivers/scsi/libsrp.c
@@ -392,7 +392,7 @@ static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir)
}
int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info,
- u64 addr)
+ u64 itn_id, u64 addr)
{
enum dma_data_direction dir;
struct scsi_cmnd *sc;
@@ -428,7 +428,8 @@ int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info,
sc->request_bufflen = len;
sc->request_buffer = (void *) (unsigned long) addr;
sc->tag = tag;
- err = scsi_tgt_queue_command(sc, (struct scsi_lun *) &cmd->lun, cmd->tag);
+ err = scsi_tgt_queue_command(sc, itn_id, (struct scsi_lun *)&cmd->lun,
+ cmd->tag);
if (err)
scsi_host_put_command(shost, sc);
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 2e3c01bebed..d6a98bc970f 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -43,7 +43,6 @@
#include "lpfc_crtn.h"
#include "lpfc_vport.h"
#include "lpfc_version.h"
-#include "lpfc_vport.h"
#include "lpfc_debugfs.h"
#ifdef CONFIG_LPFC_DEBUG_FS
@@ -902,7 +901,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
}
}
- vport->disc_trc = kmalloc(
+ vport->disc_trc = kzalloc(
(sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc),
GFP_KERNEL);
@@ -913,8 +912,6 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
goto debug_failed;
}
atomic_set(&vport->disc_trc_cnt, 0);
- memset(vport->disc_trc, 0,
- (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc));
snprintf(name, sizeof(name), "discovery_trace");
vport->debug_disc_trc =
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 414350ab584..ecebdfa0047 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -43,7 +43,6 @@
#include "lpfc_crtn.h"
#include "lpfc_vport.h"
#include "lpfc_version.h"
-#include "lpfc_vport.h"
static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
@@ -1266,11 +1265,10 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
uint32_t *HashWorking;
uint32_t *pwwnn = (uint32_t *) phba->wwnn;
- HashWorking = kmalloc(80 * sizeof(uint32_t), GFP_KERNEL);
+ HashWorking = kcalloc(80, sizeof(uint32_t), GFP_KERNEL);
if (!HashWorking)
return;
- memset(HashWorking, 0, (80 * sizeof(uint32_t)));
HashWorking[0] = HashWorking[78] = *pwwnn++;
HashWorking[1] = HashWorking[79] = *pwwnn;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 17d7dc05149..4e46045dea6 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -202,10 +202,9 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport)
dma_addr_t pdma_phys;
uint16_t iotag;
- psb = kmalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
+ psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
if (!psb)
return NULL;
- memset(psb, 0, sizeof (struct lpfc_scsi_buf));
/*
* Get memory from the pci pool to map the virt space to pci bus space
@@ -683,6 +682,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq);
int datadir = scsi_cmnd->sc_data_direction;
+ char tag[2];
lpfc_cmd->fcp_rsp->rspSnsLen = 0;
/* clear task management bits */
@@ -693,8 +693,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, 16);
- if (scsi_cmnd->device->tagged_supported) {
- switch (scsi_cmnd->tag) {
+ if (scsi_populate_tag_msg(scsi_cmnd, tag)) {
+ switch (tag[0]) {
case HEAD_OF_QUEUE_TAG:
fcp_cmnd->fcpCntl1 = HEAD_OF_Q;
break;
@@ -1439,6 +1439,7 @@ struct scsi_host_template lpfc_template = {
.scan_finished = lpfc_scan_finished,
.this_id = -1,
.sg_tablesize = LPFC_SG_SEG_CNT,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.cmd_per_lun = LPFC_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = lpfc_hba_attrs,
@@ -1461,6 +1462,7 @@ struct scsi_host_template lpfc_vport_template = {
.sg_tablesize = LPFC_SG_SEG_CNT,
.cmd_per_lun = LPFC_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.shost_attrs = lpfc_vport_attrs,
.max_sectors = 0xFFFF,
};
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index ce5ff2bccba..ce348c5c706 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -675,7 +675,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
uint32_t hbqno;
hbqno = tag >> 16;
- if (hbqno > LPFC_MAX_HBQS)
+ if (hbqno >= LPFC_MAX_HBQS)
return NULL;
list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) {
@@ -1243,7 +1243,8 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
memset(adaptermsg, 0, LPFC_MAX_ADPTMSG);
memcpy(&adaptermsg[0], (uint8_t *) irsp,
MAX_MSG_DATA);
- dev_warn(&((phba->pcidev)->dev), "lpfc%d: %s",
+ dev_warn(&((phba->pcidev)->dev),
+ "lpfc%d: %s\n",
phba->brd_no, adaptermsg);
} else {
/* Unknown IOCB command */
@@ -1430,7 +1431,8 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
memset(adaptermsg, 0, LPFC_MAX_ADPTMSG);
memcpy(&adaptermsg[0], (uint8_t *) irsp,
MAX_MSG_DATA);
- dev_warn(&((phba->pcidev)->dev), "lpfc%d: %s",
+ dev_warn(&((phba->pcidev)->dev),
+ "lpfc%d: %s\n",
phba->brd_no, adaptermsg);
} else {
/* Unknown IOCB command */
@@ -1681,7 +1683,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
memcpy(&adaptermsg[0], (uint8_t *) irsp,
MAX_MSG_DATA);
dev_warn(&((phba->pcidev)->dev),
- "lpfc%d: %s",
+ "lpfc%d: %s\n",
phba->brd_no, adaptermsg);
} else {
/* Unknown IOCB command */
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index b12ad7c7c67..a035001f443 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -402,6 +402,7 @@ static struct scsi_host_template mac53c94_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = DISABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *match)
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index cdbcaa5ad6c..abe2bda6ac3 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -53,6 +53,11 @@
#include "scsi.h"
#include <scsi/scsi_host.h>
#include "mac_scsi.h"
+
+/* These control the behaviour of the generic 5380 core */
+#define AUTOSENSE
+#define PSEUDO_DMA
+
#include "NCR5380.h"
#if 0
@@ -571,10 +576,6 @@ static int macscsi_pwrite (struct Scsi_Host *instance,
}
-/* These control the behaviour of the generic 5380 core */
-#define AUTOSENSE
-#define PSEUDO_DMA
-
#include "NCR5380.c"
static struct scsi_host_template driver_template = {
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index da56163c30a..66c65203573 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -658,7 +658,7 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy)
struct scatterlist *sg;
sg = scsi_sglist(cmd);
- buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
memset(buf, 0, cmd->cmnd[4]);
kunmap_atomic(buf - sg->offset, KM_IRQ0);
@@ -1542,10 +1542,8 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
if( cmd->cmnd[0] == INQUIRY && !islogical ) {
sgl = scsi_sglist(cmd);
- if( sgl->page ) {
- c = *(unsigned char *)
- page_address((&sgl[0])->page) +
- (&sgl[0])->offset;
+ if( sg_page(sgl) ) {
+ c = *(unsigned char *) sg_virt(&sgl[0]);
} else {
printk(KERN_WARNING
"megaraid: invalid sg.\n");
@@ -4416,8 +4414,7 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
scmd = &adapter->int_scmd;
memset(scmd, 0, sizeof(Scsi_Cmnd));
- sdev = kmalloc(sizeof(struct scsi_device), GFP_KERNEL);
- memset(sdev, 0, sizeof(struct scsi_device));
+ sdev = kzalloc(sizeof(struct scsi_device), GFP_KERNEL);
scmd->device = sdev;
scmd->device->host = adapter->host;
@@ -4493,6 +4490,7 @@ static struct scsi_host_template megaraid_template = {
.sg_tablesize = MAX_SGLIST,
.cmd_per_lun = DEF_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.eh_abort_handler = megaraid_abort,
.eh_device_reset_handler = megaraid_reset,
.eh_bus_reset_handler = megaraid_reset,
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index c6a53dccc16..c8923108183 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -361,6 +361,7 @@ static struct scsi_host_template megaraid_template_g = {
.eh_host_reset_handler = megaraid_reset_handler,
.change_queue_depth = megaraid_change_queue_depth,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.sdev_attrs = megaraid_sdev_attrs,
.shost_attrs = megaraid_shost_attrs,
};
@@ -426,7 +427,7 @@ megaraid_exit(void)
* @id : pci device id of the class of controllers
*
* This routine should be called whenever a new adapter is detected by the
- * PCI hotplug susbsytem.
+ * PCI hotplug susbsystem.
*/
static int __devinit
megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -1583,10 +1584,8 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
caddr_t vaddr;
sgl = scsi_sglist(scp);
- if (sgl->page) {
- vaddr = (caddr_t)
- (page_address((&sgl[0])->page)
- + (&sgl[0])->offset);
+ if (sg_page(sgl)) {
+ vaddr = (caddr_t) sg_virt(&sgl[0]);
memset(vaddr, 0, scp->cmnd[4]);
}
@@ -2327,10 +2326,8 @@ megaraid_mbox_dpc(unsigned long devp)
&& IS_RAID_CH(raid_dev, scb->dev_channel)) {
sgl = scsi_sglist(scp);
- if (sgl->page) {
- c = *(unsigned char *)
- (page_address((&sgl[0])->page) +
- (&sgl[0])->offset);
+ if (sg_page(sgl)) {
+ c = *(unsigned char *) sg_virt(&sgl[0]);
} else {
con_log(CL_ANN, (KERN_WARNING
"megaraid mailbox: invalid sg:%d\n",
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index ebb948c016b..e3c5c528220 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -1110,6 +1110,7 @@ static struct scsi_host_template megasas_template = {
.eh_timed_out = megasas_reset_timer,
.bios_param = megasas_bios_param,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
/**
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 651d09b08f2..7470ff39ab2 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1843,6 +1843,7 @@ static struct scsi_host_template mesh_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 2,
.use_clustering = DISABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
diff --git a/drivers/scsi/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c
index 1bdddad4857..b264b499d98 100644
--- a/drivers/scsi/mvme16x_scsi.c
+++ b/drivers/scsi/mvme16x_scsi.c
@@ -48,13 +48,12 @@ mvme16x_probe(struct device *dev)
goto out;
}
- hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
if (hostdata == NULL) {
printk(KERN_ERR "mvme16x-scsi: "
"Failed to allocate host data\n");
goto out;
}
- memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
/* Fill in the required pieces of hostdata */
hostdata->base = (void __iomem *)0xfff47000UL;
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 030ba49f33f..016c462bc77 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -8143,12 +8143,7 @@ static int ncr53c8xx_abort(struct scsi_cmnd *cmd)
unsigned long flags;
struct scsi_cmnd *done_list;
-#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
- printk("ncr53c8xx_abort: pid=%lu serial_number=%ld\n",
- cmd->pid, cmd->serial_number);
-#else
- printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid);
-#endif
+ printk("ncr53c8xx_abort: command pid %lu\n", cmd->serial_number);
NCR_LOCK_NCB(np, flags);
@@ -8528,18 +8523,15 @@ struct Scsi_Host * __init ncr_attach(struct scsi_host_template *tpnt,
}
-int ncr53c8xx_release(struct Scsi_Host *host)
+void ncr53c8xx_release(struct Scsi_Host *host)
{
- struct host_data *host_data;
+ struct host_data *host_data = shost_priv(host);
#ifdef DEBUG_NCR53C8XX
printk("ncr53c8xx: release\n");
#endif
- if (!host)
- return 1;
- host_data = (struct host_data *)host->hostdata;
- if (host_data && host_data->ncb)
+ if (host_data->ncb)
ncr_detach(host_data->ncb);
- return 1;
+ scsi_host_put(host);
}
static void ncr53c8xx_set_period(struct scsi_target *starget, int period)
diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
index b39357d9af8..0e008dacf67 100644
--- a/drivers/scsi/ncr53c8xx.h
+++ b/drivers/scsi/ncr53c8xx.h
@@ -1321,7 +1321,7 @@ struct ncr_device {
};
extern struct Scsi_Host *ncr_attach(struct scsi_host_template *tpnt, int unit, struct ncr_device *device);
-extern int ncr53c8xx_release(struct Scsi_Host *host);
+extern void ncr53c8xx_release(struct Scsi_Host *host);
irqreturn_t ncr53c8xx_intr(int irq, void *dev_id);
extern int ncr53c8xx_init(void);
extern void ncr53c8xx_exit(void);
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 7fed3537215..28161dc95e0 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -281,6 +281,7 @@ static struct scsi_host_template nsp32_template = {
.cmd_per_lun = 1,
.this_id = NSP32_HOST_SCSIID,
.use_clustering = DISABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.eh_abort_handler = nsp32_eh_abort,
.eh_bus_reset_handler = nsp32_eh_bus_reset,
.eh_host_reset_handler = nsp32_eh_host_reset,
diff --git a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h
index a976e8193d1..6715ecb3bfc 100644
--- a/drivers/scsi/nsp32.h
+++ b/drivers/scsi/nsp32.h
@@ -69,11 +69,6 @@ typedef u32 u32_le;
typedef u16 u16_le;
/*
- * MACRO
- */
-#define BIT(x) (1UL << (x))
-
-/*
* BASIC Definitions
*/
#ifndef TRUE
diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
index 26a6d55faf3..8e5eadbd5c5 100644
--- a/drivers/scsi/oktagon_esp.c
+++ b/drivers/scsi/oktagon_esp.c
@@ -550,8 +550,7 @@ void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp)
void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp)
{
- sp->SCp.ptr = page_address(sp->SCp.buffer->page)+
- sp->SCp.buffer->offset;
+ sp->SCp.ptr = sg_virt(sp->SCp.buffer);
}
void dma_mmu_release_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp)
@@ -564,8 +563,7 @@ void dma_mmu_release_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp)
void dma_advance_sg(Scsi_Cmnd *sp)
{
- sp->SCp.ptr = page_address(sp->SCp.buffer->page)+
- sp->SCp.buffer->offset;
+ sp->SCp.ptr = sg_virt(sp->SCp.buffer);
}
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 08060fb478b..abef7048f25 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -542,7 +542,7 @@ static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int q
if (STp->raw) {
if (STp->buffer->syscall_result) {
for (i=0; i < STp->buffer->sg_segs; i++)
- memset(page_address(STp->buffer->sg[i].page),
+ memset(page_address(sg_page(&STp->buffer->sg[i])),
0, STp->buffer->sg[i].length);
strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
} else
@@ -593,10 +593,11 @@ static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int q
if (aux->frame_type != OS_FRAME_TYPE_DATA &&
aux->frame_type != OS_FRAME_TYPE_EOD &&
aux->frame_type != OS_FRAME_TYPE_MARKER) {
- if (!quiet)
+ if (!quiet) {
#if DEBUG
printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type);
#endif
+ }
goto err_out;
}
if (aux->frame_type == OS_FRAME_TYPE_EOD &&
@@ -606,11 +607,12 @@ static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int q
goto err_out;
}
if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
- if (!quiet)
+ if (!quiet) {
#if DEBUG
printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n",
name, ntohl(aux->frame_seq_num), frame_seq_number);
#endif
+ }
goto err_out;
}
if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
@@ -3298,7 +3300,7 @@ static ssize_t osst_write(struct file * filp, const char __user * buf, size_t co
char * name = tape_name(STp);
- if (down_interruptible(&STp->lock))
+ if (mutex_lock_interruptible(&STp->lock))
return (-ERESTARTSYS);
/*
@@ -3600,7 +3602,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name
out:
if (SRpnt != NULL) osst_release_request(SRpnt);
- up(&STp->lock);
+ mutex_unlock(&STp->lock);
return retval;
}
@@ -3619,7 +3621,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo
char * name = tape_name(STp);
- if (down_interruptible(&STp->lock))
+ if (mutex_lock_interruptible(&STp->lock))
return (-ERESTARTSYS);
/*
@@ -3785,7 +3787,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo
out:
if (SRpnt != NULL) osst_release_request(SRpnt);
- up(&STp->lock);
+ mutex_unlock(&STp->lock);
return retval;
}
@@ -4437,7 +4439,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
for (i = 0, b_size = 0;
(i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE);
b_size += STp->buffer->sg[i++].length);
- STp->buffer->aux = (os_aux_t *) (page_address(STp->buffer->sg[i].page) + OS_DATA_SIZE - b_size);
+ STp->buffer->aux = (os_aux_t *) (page_address(sg_page(&STp->buffer->sg[i])) + OS_DATA_SIZE - b_size);
#if DEBUG
printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name,
STp->buffer->b_data, page_address(STp->buffer->sg[0].page));
@@ -4852,7 +4854,7 @@ static int osst_ioctl(struct inode * inode,struct file * file,
char * name = tape_name(STp);
void __user * p = (void __user *)arg;
- if (down_interruptible(&STp->lock))
+ if (mutex_lock_interruptible(&STp->lock))
return -ERESTARTSYS;
#if DEBUG
@@ -5163,14 +5165,14 @@ static int osst_ioctl(struct inode * inode,struct file * file,
}
if (SRpnt) osst_release_request(SRpnt);
- up(&STp->lock);
+ mutex_unlock(&STp->lock);
return scsi_ioctl(STp->device, cmd_in, p);
out:
if (SRpnt) osst_release_request(SRpnt);
- up(&STp->lock);
+ mutex_unlock(&STp->lock);
return retval;
}
@@ -5252,25 +5254,25 @@ static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
/* Try to allocate the first segment up to OS_DATA_SIZE and the others
big enough to reach the goal (code assumes no segments in place) */
for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) {
- STbuffer->sg[0].page = alloc_pages(priority, order);
+ struct page *page = alloc_pages(priority, order);
+
STbuffer->sg[0].offset = 0;
- if (STbuffer->sg[0].page != NULL) {
- STbuffer->sg[0].length = b_size;
- STbuffer->b_data = page_address(STbuffer->sg[0].page);
+ if (page != NULL) {
+ sg_set_page(&STbuffer->sg[0], page, b_size, 0);
+ STbuffer->b_data = page_address(page);
break;
}
}
- if (STbuffer->sg[0].page == NULL) {
+ if (sg_page(&STbuffer->sg[0]) == NULL) {
printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
return 0;
}
/* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
for (segs=STbuffer->sg_segs=1, got=b_size;
segs < max_segs && got < OS_FRAME_SIZE; ) {
- STbuffer->sg[segs].page =
- alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
+ struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
STbuffer->sg[segs].offset = 0;
- if (STbuffer->sg[segs].page == NULL) {
+ if (page == NULL) {
if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) {
b_size /= 2; /* Large enough for the rest of the buffers */
order--;
@@ -5284,7 +5286,7 @@ static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
normalize_buffer(STbuffer);
return 0;
}
- STbuffer->sg[segs].length = (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size;
+ sg_set_page(&STbuffer->sg[segs], page, (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size, 0);
got += STbuffer->sg[segs].length;
STbuffer->buffer_size = got;
STbuffer->sg_segs = ++segs;
@@ -5316,7 +5318,7 @@ static void normalize_buffer(struct osst_buffer *STbuffer)
b_size < STbuffer->sg[i].length;
b_size *= 2, order++);
- __free_pages(STbuffer->sg[i].page, order);
+ __free_pages(sg_page(&STbuffer->sg[i]), order);
STbuffer->buffer_size -= STbuffer->sg[i].length;
}
#if DEBUG
@@ -5344,7 +5346,7 @@ static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, i
for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
cnt = st_bp->sg[i].length - offset < do_count ?
st_bp->sg[i].length - offset : do_count;
- res = copy_from_user(page_address(st_bp->sg[i].page) + offset, ubp, cnt);
+ res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt);
if (res)
return (-EFAULT);
do_count -= cnt;
@@ -5377,7 +5379,7 @@ static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count
for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
cnt = st_bp->sg[i].length - offset < do_count ?
st_bp->sg[i].length - offset : do_count;
- res = copy_to_user(ubp, page_address(st_bp->sg[i].page) + offset, cnt);
+ res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt);
if (res)
return (-EFAULT);
do_count -= cnt;
@@ -5410,7 +5412,7 @@ static int osst_zero_buffer_tail(struct osst_buffer *st_bp)
i < st_bp->sg_segs && do_count > 0; i++) {
cnt = st_bp->sg[i].length - offset < do_count ?
st_bp->sg[i].length - offset : do_count ;
- memset(page_address(st_bp->sg[i].page) + offset, 0, cnt);
+ memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt);
do_count -= cnt;
offset = 0;
}
@@ -5430,7 +5432,7 @@ static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
cnt = st_bp->sg[i].length < do_count ?
st_bp->sg[i].length : do_count ;
- memcpy(page_address(st_bp->sg[i].page), ptr, cnt);
+ memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt);
do_count -= cnt;
ptr += cnt;
}
@@ -5451,7 +5453,7 @@ static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
cnt = st_bp->sg[i].length < do_count ?
st_bp->sg[i].length : do_count ;
- memcpy(ptr, page_address(st_bp->sg[i].page), cnt);
+ memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt);
do_count -= cnt;
ptr += cnt;
}
@@ -5778,13 +5780,12 @@ static int osst_probe(struct device *dev)
dev_num = i;
/* allocate a struct osst_tape for this device */
- tpnt = kmalloc(sizeof(struct osst_tape), GFP_ATOMIC);
- if (tpnt == NULL) {
+ tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC);
+ if (!tpnt) {
write_unlock(&os_scsi_tapes_lock);
printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
goto out_put_disk;
}
- memset(tpnt, 0, sizeof(struct osst_tape));
/* allocate a buffer for this device */
i = SDp->host->sg_tablesize;
@@ -5866,7 +5867,7 @@ static int osst_probe(struct device *dev)
tpnt->modes[2].defined = 1;
tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0;
- init_MUTEX(&tpnt->lock);
+ mutex_init(&tpnt->lock);
osst_nr_dev++;
write_unlock(&os_scsi_tapes_lock);
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h
index 2cc7b5a1606..5aa22740b5d 100644
--- a/drivers/scsi/osst.h
+++ b/drivers/scsi/osst.h
@@ -4,6 +4,7 @@
#include <asm/byteorder.h>
#include <linux/completion.h>
+#include <linux/mutex.h>
/* FIXME - rename and use the following two types or delete them!
* and the types really should go to st.h anyway...
@@ -532,7 +533,7 @@ struct osst_tape {
struct scsi_driver *driver;
unsigned capacity;
struct scsi_device *device;
- struct semaphore lock; /* for serialization */
+ struct mutex lock; /* for serialization */
struct completion wait; /* for SCSI commands */
struct osst_buffer * buffer;
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 445cfbbca9b..a45d89b1414 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -25,8 +25,6 @@
***********************************************************************/
-/* $Id: nsp_cs.c,v 1.23 2003/08/18 11:09:19 elca Exp $ */
-
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -59,7 +57,7 @@
#include "nsp_cs.h"
MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
-MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module $Revision: 1.23 $");
+MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module");
MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
@@ -83,10 +81,6 @@ static struct scsi_host_template nsp_driver_template = {
.proc_name = "nsp_cs",
.proc_info = nsp_proc_info,
.name = "WorkBit NinjaSCSI-3/32Bi(16bit)",
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
- .detect = nsp_detect_old,
- .release = nsp_release_old,
-#endif
.info = nsp_info,
.queuecommand = nsp_queuecommand,
/* .eh_abort_handler = nsp_eh_abort,*/
@@ -97,9 +91,6 @@ static struct scsi_host_template nsp_driver_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = DISABLE_CLUSTERING,
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
- .use_new_eh_code = 1,
-#endif
};
static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
@@ -1313,11 +1304,7 @@ static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
nsp_hw_data *data_b = &nsp_data_base, *data;
nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
-#else
- host = scsi_register(sht, sizeof(nsp_hw_data));
-#endif
if (host == NULL) {
nsp_dbg(NSP_DEBUG_INIT, "host failed");
return NULL;
@@ -1354,37 +1341,6 @@ static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht)
return host; /* detect done. */
}
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-static int nsp_detect_old(struct scsi_host_template *sht)
-{
- if (nsp_detect(sht) == NULL) {
- return 0;
- } else {
- //MOD_INC_USE_COUNT;
- return 1;
- }
-}
-
-
-static int nsp_release_old(struct Scsi_Host *shpnt)
-{
- //nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
-
- /* PCMCIA Card Service dose same things below. */
- /* So we do nothing. */
- //if (shpnt->irq) {
- // free_irq(shpnt->irq, data->ScsiInfo);
- //}
- //if (shpnt->io_port) {
- // release_region(shpnt->io_port, shpnt->n_io_port);
- //}
-
- //MOD_DEC_USE_COUNT;
-
- return 0;
-}
-#endif
-
/*----------------------------------------------------------------*/
/* return info string */
/*----------------------------------------------------------------*/
@@ -1403,19 +1359,9 @@ static const char *nsp_info(struct Scsi_Host *shpnt)
nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\
} \
} while(0)
-static int
-nsp_proc_info(
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- struct Scsi_Host *host,
-#endif
- char *buffer,
- char **start,
- off_t offset,
- int length,
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- int hostno,
-#endif
- int inout)
+
+static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start,
+ off_t offset, int length, int inout)
{
int id;
char *pos = buffer;
@@ -1423,24 +1369,13 @@ nsp_proc_info(
int speed;
unsigned long flags;
nsp_hw_data *data;
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- struct Scsi_Host *host;
-#else
int hostno;
-#endif
+
if (inout) {
return -EINVAL;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
hostno = host->host_no;
-#else
- /* search this HBA host */
- host = scsi_host_hn_get(hostno);
- if (host == NULL) {
- return -ESRCH;
- }
-#endif
data = (nsp_hw_data *)host->hostdata;
@@ -1675,10 +1610,6 @@ static int nsp_cs_config(struct pcmcia_device *link)
cistpl_cftable_entry_t dflt = { 0 };
struct Scsi_Host *host;
nsp_hw_data *data = &nsp_data_base;
-#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
- struct scsi_device *dev;
- dev_node_t **tail, *node;
-#endif
nsp_dbg(NSP_DEBUG_INIT, "in");
@@ -1811,17 +1742,7 @@ static int nsp_cs_config(struct pcmcia_device *link)
goto cs_failed;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
host = nsp_detect(&nsp_driver_template);
-#else
- scsi_register_host(&nsp_driver_template);
- for (host = scsi_host_get_next(NULL); host != NULL;
- host = scsi_host_get_next(host)) {
- if (host->hostt == &nsp_driver_template) {
- break;
- }
- }
-#endif
if (host == NULL) {
nsp_dbg(NSP_DEBUG_INIT, "detect failed");
@@ -1829,7 +1750,6 @@ static int nsp_cs_config(struct pcmcia_device *link)
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
ret = scsi_add_host (host, NULL);
if (ret)
goto cs_failed;
@@ -1840,52 +1760,6 @@ static int nsp_cs_config(struct pcmcia_device *link)
link->dev_node = &info->node;
info->host = host;
-#else
- nsp_dbg(NSP_DEBUG_INIT, "GET_SCSI_INFO");
- tail = &link->dev_node;
- info->ndev = 0;
-
- nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);
-
- for (dev = host->host_queue; dev != NULL; dev = dev->next) {
- unsigned long id;
- id = (dev->id & 0x0f) + ((dev->lun & 0x0f) << 4) +
- ((dev->channel & 0x0f) << 8) +
- ((dev->host->host_no & 0x0f) << 12);
- node = &info->node[info->ndev];
- node->minor = 0;
- switch (dev->type) {
- case TYPE_TAPE:
- node->major = SCSI_TAPE_MAJOR;
- snprintf(node->dev_name, sizeof(node->dev_name), "st#%04lx", id);
- break;
- case TYPE_DISK:
- case TYPE_MOD:
- node->major = SCSI_DISK0_MAJOR;
- snprintf(node->dev_name, sizeof(node->dev_name), "sd#%04lx", id);
- break;
- case TYPE_ROM:
- case TYPE_WORM:
- node->major = SCSI_CDROM_MAJOR;
- snprintf(node->dev_name, sizeof(node->dev_name), "sr#%04lx", id);
- break;
- default:
- node->major = SCSI_GENERIC_MAJOR;
- snprintf(node->dev_name, sizeof(node->dev_name), "sg#%04lx", id);
- break;
- }
- *tail = node; tail = &node->next;
- info->ndev++;
- info->host = dev->host;
- }
-
- *tail = NULL;
- if (info->ndev == 0) {
- nsp_msg(KERN_INFO, "no SCSI devices found");
- }
- nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);
-#endif
-
/* Finally, report what we've done */
printk(KERN_INFO "nsp_cs: index 0x%02x: ",
link->conf.ConfigIndex);
@@ -1938,13 +1812,9 @@ static void nsp_cs_release(struct pcmcia_device *link)
nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
/* Unlink the device chain */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2))
if (info->host != NULL) {
scsi_remove_host(info->host);
}
-#else
- scsi_unregister_host(&nsp_driver_template);
-#endif
link->dev_node = NULL;
if (link->win) {
@@ -1954,11 +1824,9 @@ static void nsp_cs_release(struct pcmcia_device *link)
}
pcmcia_disable_device(link);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2))
if (info->host != NULL) {
scsi_host_put(info->host);
}
-#endif
} /* nsp_cs_release */
static int nsp_cs_suspend(struct pcmcia_device *link)
@@ -2005,7 +1873,6 @@ static int nsp_cs_resume(struct pcmcia_device *link)
/*======================================================================*
* module entry point
*====================================================================*/
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
static struct pcmcia_device_id nsp_cs_ids[] = {
PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
@@ -2029,28 +1896,12 @@ static struct pcmcia_driver nsp_driver = {
.suspend = nsp_cs_suspend,
.resume = nsp_cs_resume,
};
-#endif
static int __init nsp_cs_init(void)
{
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
nsp_msg(KERN_INFO, "loading...");
return pcmcia_register_driver(&nsp_driver);
-#else
- servinfo_t serv;
-
- nsp_msg(KERN_INFO, "loading...");
- pcmcia_get_card_services_info(&serv);
- if (serv.Revision != CS_RELEASE_CODE) {
- nsp_msg(KERN_DEBUG, "Card Services release does not match!");
- return -EINVAL;
- }
- register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach);
-
- nsp_dbg(NSP_DEBUG_INIT, "out");
- return 0;
-#endif
}
static void __exit nsp_cs_exit(void)
diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
index 9102cbdf135..7db28cd4944 100644
--- a/drivers/scsi/pcmcia/nsp_cs.h
+++ b/drivers/scsi/pcmcia/nsp_cs.h
@@ -10,8 +10,6 @@
=========================================================*/
-/* $Id: nsp_cs.h,v 1.19 2003/08/18 11:09:19 elca Exp $ */
-
#ifndef __nsp_cs__
#define __nsp_cs__
@@ -26,7 +24,6 @@
/************************************
* Some useful macros...
*/
-#define BIT(x) (1L << (x))
/* SCSI initiator must be ID 7 */
#define NSP_INITIATOR_ID 7
@@ -227,13 +224,7 @@
typedef struct scsi_info_t {
struct pcmcia_device *p_dev;
struct Scsi_Host *host;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
dev_node_t node;
-#else
- int ndev;
- dev_node_t node[8];
- struct bus_operations *bus;
-#endif
int stop;
} scsi_info_t;
@@ -402,7 +393,7 @@ enum _burst_mode {
#define MSG_EXT_SDTR 0x01
/* scatter-gather table */
-# define BUFFER_ADDR ((char *)((unsigned int)(SCpnt->SCp.buffer->page) + SCpnt->SCp.buffer->offset))
+# define BUFFER_ADDR ((char *)((sg_virt(SCpnt->SCp.buffer))))
#endif /*__nsp_cs__*/
/* end */
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 961839ecfe8..969b9387a0c 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -443,8 +443,7 @@ SYM53C500_intr(int irq, void *dev_id)
scsi_for_each_sg(curSC, sg, scsi_sg_count(curSC), i) {
SYM53C500_pio_write(fast_pio, port_base,
- page_address(sg->page) + sg->offset,
- sg->length);
+ sg_virt(sg), sg->length);
}
REG0(port_base);
}
@@ -463,8 +462,7 @@ SYM53C500_intr(int irq, void *dev_id)
scsi_for_each_sg(curSC, sg, scsi_sg_count(curSC), i) {
SYM53C500_pio_read(fast_pio, port_base,
- page_address(sg->page) + sg->offset,
- sg->length);
+ sg_virt(sg), sg->length);
}
REG0(port_base);
}
@@ -694,6 +692,7 @@ static struct scsi_host_template sym53c500_driver_template = {
.sg_tablesize = 32,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.shost_attrs = SYM53C500_shost_attrs
};
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
deleted file mode 100644
index d953d43fe2e..00000000000
--- a/drivers/scsi/pluto.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/* pluto.c: SparcSTORAGE Array SCSI host adapter driver.
- *
- * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- *
- */
-
-#include <linux/completion.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-#ifdef CONFIG_KMOD
-#include <linux/kmod.h>
-#endif
-
-#include <asm/irq.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "../fc4/fcp_impl.h"
-#include "pluto.h"
-
-#include <linux/module.h>
-
-#define RQ_SCSI_BUSY 0xffff
-#define RQ_SCSI_DONE 0xfffe
-
-/* #define PLUTO_DEBUG */
-
-#define pluto_printk printk ("PLUTO %s: ", fc->name); printk
-
-#ifdef PLUTO_DEBUG
-#define PLD(x) pluto_printk x;
-#define PLND(x) printk ("PLUTO: "); printk x;
-#else
-#define PLD(x)
-#define PLND(x)
-#endif
-
-static struct ctrl_inquiry {
- struct Scsi_Host host;
- struct pluto pluto;
- Scsi_Cmnd cmd;
- char inquiry[256];
- fc_channel *fc;
-} *fcs __initdata;
-static int fcscount __initdata = 0;
-static atomic_t fcss __initdata = ATOMIC_INIT(0);
-static DECLARE_COMPLETION(fc_detect_complete);
-
-static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd);
-
-static void __init pluto_detect_done(Scsi_Cmnd *SCpnt)
-{
- /* Do nothing */
-}
-
-static void __init pluto_detect_scsi_done(Scsi_Cmnd *SCpnt)
-{
- PLND(("Detect done %08lx\n", (long)SCpnt))
- if (atomic_dec_and_test (&fcss))
- complete(&fc_detect_complete);
-}
-
-int pluto_slave_configure(struct scsi_device *device)
-{
- int depth_to_use;
-
- if (device->tagged_supported)
- depth_to_use = /* 254 */ 8;
- else
- depth_to_use = 2;
-
- scsi_adjust_queue_depth(device,
- (device->tagged_supported ?
- MSG_SIMPLE_TAG : 0),
- depth_to_use);
-
- return 0;
-}
-
-/* Detect all SSAs attached to the machine.
- To be fast, do it on all online FC channels at the same time. */
-int __init pluto_detect(struct scsi_host_template *tpnt)
-{
- int i, retry, nplutos;
- fc_channel *fc;
- struct scsi_device dev;
-
- tpnt->proc_name = "pluto";
- fcscount = 0;
- for_each_online_fc_channel(fc) {
- if (!fc->posmap)
- fcscount++;
- }
- PLND(("%d channels online\n", fcscount))
- if (!fcscount) {
-#if defined(MODULE) && defined(CONFIG_FC4_SOC_MODULE) && defined(CONFIG_KMOD)
- request_module("soc");
-
- for_each_online_fc_channel(fc) {
- if (!fc->posmap)
- fcscount++;
- }
- if (!fcscount)
-#endif
- return 0;
- }
- fcs = kmalloc(sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA);
- if (!fcs) {
- printk ("PLUTO: Not enough memory to probe\n");
- return 0;
- }
-
- memset (fcs, 0, sizeof (struct ctrl_inquiry) * fcscount);
- memset (&dev, 0, sizeof(dev));
- atomic_set (&fcss, fcscount);
-
- i = 0;
- for_each_online_fc_channel(fc) {
- Scsi_Cmnd *SCpnt;
- struct Scsi_Host *host;
- struct pluto *pluto;
-
- if (i == fcscount) break;
- if (fc->posmap) continue;
-
- PLD(("trying to find SSA\n"))
-
- /* If this is already registered to some other SCSI host, then it cannot be pluto */
- if (fc->scsi_name[0]) continue;
- memcpy (fc->scsi_name, "SSA", 4);
-
- fcs[i].fc = fc;
-
- fc->can_queue = PLUTO_CAN_QUEUE;
- fc->rsp_size = 64;
- fc->encode_addr = pluto_encode_addr;
-
- fc->fcp_register(fc, TYPE_SCSI_FCP, 0);
-
- SCpnt = &(fcs[i].cmd);
- host = &(fcs[i].host);
- pluto = (struct pluto *)host->hostdata;
-
- pluto->fc = fc;
-
- SCpnt->cmnd[0] = INQUIRY;
- SCpnt->cmnd[4] = 255;
-
- /* FC layer requires this, so that SCpnt->device->tagged_supported is initially 0 */
- SCpnt->device = &dev;
- dev.host = host;
-
- SCpnt->cmd_len = COMMAND_SIZE(INQUIRY);
-
- SCpnt->request->cmd_flags &= ~REQ_STARTED;
-
- SCpnt->done = pluto_detect_done;
- SCpnt->request_bufflen = 256;
- SCpnt->request_buffer = fcs[i].inquiry;
- PLD(("set up %d %08lx\n", i, (long)SCpnt))
- i++;
- }
-
- for (retry = 0; retry < 5; retry++) {
- for (i = 0; i < fcscount; i++) {
- if (!fcs[i].fc) break;
- if (!(fcs[i].cmd.request->cmd_flags & REQ_STARTED)) {
- fcs[i].cmd.request->cmd_flags |= REQ_STARTED;
- disable_irq(fcs[i].fc->irq);
- PLND(("queuecommand %d %d\n", retry, i))
- fcp_scsi_queuecommand (&(fcs[i].cmd),
- pluto_detect_scsi_done);
- enable_irq(fcs[i].fc->irq);
- }
- }
-
- wait_for_completion_timeout(&fc_detect_complete, 10 * HZ);
- PLND(("Woken up\n"))
- if (!atomic_read(&fcss))
- break; /* All fc channels have answered us */
- }
-
- PLND(("Finished search\n"))
- for (i = 0, nplutos = 0; i < fcscount; i++) {
- Scsi_Cmnd *SCpnt;
-
- if (!(fc = fcs[i].fc)) break;
-
- SCpnt = &(fcs[i].cmd);
-
- /* Let FC mid-level free allocated resources */
- SCpnt->done (SCpnt);
-
- if (!SCpnt->result) {
- struct pluto_inquiry *inq;
- struct pluto *pluto;
- struct Scsi_Host *host;
-
- inq = (struct pluto_inquiry *)fcs[i].inquiry;
-
- if ((inq->dtype & 0x1f) == TYPE_PROCESSOR &&
- !strncmp (inq->vendor_id, "SUN", 3) &&
- !strncmp (inq->product_id, "SSA", 3)) {
- char *p;
- long *ages;
-
- ages = kmalloc (((inq->channels + 1) * inq->targets) * sizeof(long), GFP_KERNEL);
- if (!ages) continue;
-
- host = scsi_register (tpnt, sizeof (struct pluto));
- if(!host)
- {
- kfree(ages);
- continue;
- }
-
- if (!try_module_get(fc->module)) {
- kfree(ages);
- scsi_unregister(host);
- continue;
- }
-
- nplutos++;
-
- pluto = (struct pluto *)host->hostdata;
-
- host->max_id = inq->targets;
- host->max_channel = inq->channels;
- host->irq = fc->irq;
-
- fc->channels = inq->channels + 1;
- fc->targets = inq->targets;
- fc->ages = ages;
- memset (ages, 0, ((inq->channels + 1) * inq->targets) * sizeof(long));
-
- pluto->fc = fc;
- memcpy (pluto->rev_str, inq->revision, 4);
- pluto->rev_str[4] = 0;
- p = strchr (pluto->rev_str, ' ');
- if (p) *p = 0;
- memcpy (pluto->fw_rev_str, inq->fw_revision, 4);
- pluto->fw_rev_str[4] = 0;
- p = strchr (pluto->fw_rev_str, ' ');
- if (p) *p = 0;
- memcpy (pluto->serial_str, inq->serial, 12);
- pluto->serial_str[12] = 0;
- p = strchr (pluto->serial_str, ' ');
- if (p) *p = 0;
-
- PLD(("Found SSA rev %s fw rev %s serial %s %dx%d\n", pluto->rev_str, pluto->fw_rev_str, pluto->serial_str, host->max_channel, host->max_id))
- } else
- fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
- } else
- fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
- }
- kfree((char *)fcs);
- if (nplutos)
- printk ("PLUTO: Total of %d SparcSTORAGE Arrays found\n", nplutos);
- return nplutos;
-}
-
-int pluto_release(struct Scsi_Host *host)
-{
- struct pluto *pluto = (struct pluto *)host->hostdata;
- fc_channel *fc = pluto->fc;
-
- module_put(fc->module);
-
- fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
- PLND((" releasing pluto.\n"));
- kfree (fc->ages);
- PLND(("released pluto!\n"));
- return 0;
-}
-
-const char *pluto_info(struct Scsi_Host *host)
-{
- static char buf[128], *p;
- struct pluto *pluto = (struct pluto *) host->hostdata;
-
- sprintf(buf, "SUN SparcSTORAGE Array %s fw %s serial %s %dx%d on %s",
- pluto->rev_str, pluto->fw_rev_str, pluto->serial_str,
- host->max_channel, host->max_id, pluto->fc->name);
-#ifdef __sparc__
- p = strchr(buf, 0);
- sprintf(p, " PROM node %x", pluto->fc->dev->prom_node);
-#endif
- return buf;
-}
-
-/* SSA uses this FC4S addressing:
- switch (addr[0])
- {
- case 0: CONTROLLER - All of addr[1]..addr[3] has to be 0
- case 1: SINGLE DISK - addr[1] channel, addr[2] id, addr[3] 0
- case 2: DISK GROUP - ???
- }
-
- So that SCSI mid-layer can access to these, we reserve
- channel 0 id 0 lun 0 for CONTROLLER
- and channels 1 .. max_channel are normal single disks.
- */
-static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd)
-{
- PLND(("encode addr %d %d %d\n", SCpnt->device->channel, SCpnt->device->id, SCpnt->cmnd[1] & 0xe0))
- /* We don't support LUNs - neither does SSA :) */
- if (SCpnt->cmnd[1] & 0xe0)
- return -EINVAL;
- if (!SCpnt->device->channel) {
- if (SCpnt->device->id)
- return -EINVAL;
- memset (addr, 0, 4 * sizeof(u16));
- } else {
- addr[0] = 1;
- addr[1] = SCpnt->device->channel - 1;
- addr[2] = SCpnt->device->id;
- addr[3] = 0;
- }
- /* We're Point-to-Point, so target it to the default DID */
- fcmd->did = fc->did;
- PLND(("trying %04x%04x%04x%04x\n", addr[0], addr[1], addr[2], addr[3]))
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .name = "Sparc Storage Array 100/200",
- .detect = pluto_detect,
- .release = pluto_release,
- .info = pluto_info,
- .queuecommand = fcp_scsi_queuecommand,
- .slave_configure = pluto_slave_configure,
- .can_queue = PLUTO_CAN_QUEUE,
- .this_id = -1,
- .sg_tablesize = 1,
- .cmd_per_lun = 1,
- .use_clustering = ENABLE_CLUSTERING,
- .eh_abort_handler = fcp_scsi_abort,
- .eh_device_reset_handler = fcp_scsi_dev_reset,
- .eh_host_reset_handler = fcp_scsi_host_reset,
-};
-
-#include "scsi_module.c"
-
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/scsi/pluto.h b/drivers/scsi/pluto.h
deleted file mode 100644
index 5da20616ac3..00000000000
--- a/drivers/scsi/pluto.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* pluto.h: SparcSTORAGE Array SCSI host adapter driver definitions.
- *
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#ifndef _PLUTO_H
-#define _PLUTO_H
-
-#include "../fc4/fcp_impl.h"
-
-struct pluto {
- /* This must be first */
- fc_channel *fc;
- char rev_str[5];
- char fw_rev_str[5];
- char serial_str[13];
-};
-
-struct pluto_inquiry {
- u8 dtype;
- u8 removable:1, qualifier:7;
- u8 iso:2, ecma:3, ansi:3;
- u8 aenc:1, trmiop:1, :2, rdf:4;
- u8 len;
- u8 xxx1;
- u8 xxx2;
- u8 reladdr:1, wbus32:1, wbus16:1, sync:1, linked:1, :1, cmdque:1, softreset:1;
- u8 vendor_id[8];
- u8 product_id[16];
- u8 revision[4];
- u8 fw_revision[4];
- u8 serial[12];
- u8 xxx3[2];
- u8 channels;
- u8 targets;
-};
-
-/* This is the max number of outstanding SCSI commands per pluto */
-#define PLUTO_CAN_QUEUE 254
-
-int pluto_detect(struct scsi_host_template *);
-int pluto_release(struct Scsi_Host *);
-const char * pluto_info(struct Scsi_Host *);
-int pluto_slave_configure(struct scsi_device *);
-
-#endif /* !(_PLUTO_H) */
-
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 67b6d76a6c8..67ee51a3d7e 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -608,9 +608,7 @@ static int ppa_completion(struct scsi_cmnd *cmd)
cmd->SCp.buffer++;
cmd->SCp.this_residual =
cmd->SCp.buffer->length;
- cmd->SCp.ptr =
- page_address(cmd->SCp.buffer->page) +
- cmd->SCp.buffer->offset;
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
}
}
/* Now check to see if the drive is ready to comunicate */
@@ -756,8 +754,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
/* if many buffers are available, start filling the first */
cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
- cmd->SCp.buffer->offset;
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
} else {
/* else fill the only available buffer */
cmd->SCp.buffer = NULL;
diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c
index b50f1e14f2a..17b4a7c4618 100644
--- a/drivers/scsi/ps3rom.c
+++ b/drivers/scsi/ps3rom.c
@@ -100,31 +100,31 @@ static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf)
struct scatterlist *sgpnt;
unsigned int buflen;
- buflen = cmd->request_bufflen;
+ buflen = scsi_bufflen(cmd);
if (!buflen)
return 0;
- if (!cmd->request_buffer)
+ if (!scsi_sglist(cmd))
return -1;
- sgpnt = cmd->request_buffer;
active = 1;
- for (k = 0, req_len = 0, act_len = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+ req_len = act_len = 0;
+ scsi_for_each_sg(cmd, sgpnt, scsi_sg_count(cmd), k) {
if (active) {
- kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+ kaddr = kmap_atomic(sg_page(sgpnt), KM_IRQ0);
len = sgpnt->length;
if ((req_len + len) > buflen) {
active = 0;
len = buflen - req_len;
}
memcpy(kaddr + sgpnt->offset, buf + req_len, len);
- flush_kernel_dcache_page(sgpnt->page);
+ flush_kernel_dcache_page(sg_page(sgpnt));
kunmap_atomic(kaddr, KM_IRQ0);
act_len += len;
}
req_len += sgpnt->length;
}
- cmd->resid = req_len - act_len;
+ scsi_set_resid(cmd, req_len - act_len);
return 0;
}
@@ -138,16 +138,16 @@ static int fetch_to_dev_buffer(struct scsi_cmnd *cmd, void *buf)
struct scatterlist *sgpnt;
unsigned int buflen;
- buflen = cmd->request_bufflen;
+ buflen = scsi_bufflen(cmd);
if (!buflen)
return 0;
- if (!cmd->request_buffer)
+ if (!scsi_sglist(cmd))
return -1;
- sgpnt = cmd->request_buffer;
- for (k = 0, req_len = 0, fin = 0; k < cmd->use_sg; ++k, ++sgpnt) {
- kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+ req_len = fin = 0;
+ scsi_for_each_sg(cmd, sgpnt, scsi_sg_count(cmd), k) {
+ kaddr = kmap_atomic(sg_page(sgpnt), KM_IRQ0);
len = sgpnt->length;
if ((req_len + len) > buflen) {
len = buflen - req_len;
@@ -177,12 +177,12 @@ static int ps3rom_atapi_request(struct ps3_storage_device *dev,
memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12);
atapi_cmnd.pktlen = 12;
atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */
- atapi_cmnd.blocks = atapi_cmnd.arglen = cmd->request_bufflen;
+ atapi_cmnd.blocks = atapi_cmnd.arglen = scsi_bufflen(cmd);
atapi_cmnd.buffer = dev->bounce_lpar;
switch (cmd->sc_data_direction) {
case DMA_FROM_DEVICE:
- if (cmd->request_bufflen >= CD_FRAMESIZE)
+ if (scsi_bufflen(cmd) >= CD_FRAMESIZE)
atapi_cmnd.proto = DMA_PROTO;
else
atapi_cmnd.proto = PIO_DATA_IN_PROTO;
@@ -190,7 +190,7 @@ static int ps3rom_atapi_request(struct ps3_storage_device *dev,
break;
case DMA_TO_DEVICE:
- if (cmd->request_bufflen >= CD_FRAMESIZE)
+ if (scsi_bufflen(cmd) >= CD_FRAMESIZE)
atapi_cmnd.proto = DMA_PROTO;
else
atapi_cmnd.proto = PIO_DATA_OUT_PROTO;
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 54d8bdf8685..3aeb68bcb7a 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -2775,7 +2775,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
struct device_reg __iomem *reg = ha->iobase;
struct scsi_cmnd *cmd = sp->cmd;
cmd_a64_entry_t *pkt;
- struct scatterlist *sg = NULL;
+ struct scatterlist *sg = NULL, *s;
__le32 *dword_ptr;
dma_addr_t dma_handle;
int status = 0;
@@ -2889,13 +2889,16 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
* Load data segments.
*/
if (seg_cnt) { /* If data transfer. */
+ int remseg = seg_cnt;
/* Setup packet address segment pointer. */
dword_ptr = (u32 *)&pkt->dseg_0_address;
if (cmd->use_sg) { /* If scatter gather */
/* Load command entry data segments. */
- for (cnt = 0; cnt < 2 && seg_cnt; cnt++, seg_cnt--) {
- dma_handle = sg_dma_address(sg);
+ for_each_sg(sg, s, seg_cnt, cnt) {
+ if (cnt == 2)
+ break;
+ dma_handle = sg_dma_address(s);
#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
if (ha->flags.use_pci_vchannel)
sn_pci_set_vchan(ha->pdev,
@@ -2906,12 +2909,12 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
cpu_to_le32(pci_dma_lo32(dma_handle));
*dword_ptr++ =
cpu_to_le32(pci_dma_hi32(dma_handle));
- *dword_ptr++ = cpu_to_le32(sg_dma_len(sg));
- sg++;
+ *dword_ptr++ = cpu_to_le32(sg_dma_len(s));
dprintk(3, "S/G Segment phys_addr=%x %x, len=0x%x\n",
cpu_to_le32(pci_dma_hi32(dma_handle)),
cpu_to_le32(pci_dma_lo32(dma_handle)),
- cpu_to_le32(sg_dma_len(sg)));
+ cpu_to_le32(sg_dma_len(sg_next(s))));
+ remseg--;
}
dprintk(5, "qla1280_64bit_start_scsi: Scatter/gather "
"command packet data - b %i, t %i, l %i \n",
@@ -2926,7 +2929,9 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
dprintk(3, "S/G Building Continuation...seg_cnt=0x%x "
"remains\n", seg_cnt);
- while (seg_cnt > 0) {
+ while (remseg > 0) {
+ /* Update sg start */
+ sg = s;
/* Adjust ring index. */
ha->req_ring_index++;
if (ha->req_ring_index == REQUEST_ENTRY_CNT) {
@@ -2952,9 +2957,10 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
(u32 *)&((struct cont_a64_entry *) pkt)->dseg_0_address;
/* Load continuation entry data segments. */
- for (cnt = 0; cnt < 5 && seg_cnt;
- cnt++, seg_cnt--) {
- dma_handle = sg_dma_address(sg);
+ for_each_sg(sg, s, remseg, cnt) {
+ if (cnt == 5)
+ break;
+ dma_handle = sg_dma_address(s);
#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
if (ha->flags.use_pci_vchannel)
sn_pci_set_vchan(ha->pdev,
@@ -2966,13 +2972,13 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
*dword_ptr++ =
cpu_to_le32(pci_dma_hi32(dma_handle));
*dword_ptr++ =
- cpu_to_le32(sg_dma_len(sg));
+ cpu_to_le32(sg_dma_len(s));
dprintk(3, "S/G Segment Cont. phys_addr=%x %x, len=0x%x\n",
cpu_to_le32(pci_dma_hi32(dma_handle)),
cpu_to_le32(pci_dma_lo32(dma_handle)),
- cpu_to_le32(sg_dma_len(sg)));
- sg++;
+ cpu_to_le32(sg_dma_len(s)));
}
+ remseg -= cnt;
dprintk(5, "qla1280_64bit_start_scsi: "
"continuation packet data - b %i, t "
"%i, l %i \n", SCSI_BUS_32(cmd),
@@ -3062,7 +3068,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
struct device_reg __iomem *reg = ha->iobase;
struct scsi_cmnd *cmd = sp->cmd;
struct cmd_entry *pkt;
- struct scatterlist *sg = NULL;
+ struct scatterlist *sg = NULL, *s;
__le32 *dword_ptr;
int status = 0;
int cnt;
@@ -3188,6 +3194,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
* Load data segments.
*/
if (seg_cnt) {
+ int remseg = seg_cnt;
/* Setup packet address segment pointer. */
dword_ptr = &pkt->dseg_0_address;
@@ -3196,22 +3203,25 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
qla1280_dump_buffer(1, (char *)sg, 4 * 16);
/* Load command entry data segments. */
- for (cnt = 0; cnt < 4 && seg_cnt; cnt++, seg_cnt--) {
+ for_each_sg(sg, s, seg_cnt, cnt) {
+ if (cnt == 4)
+ break;
*dword_ptr++ =
- cpu_to_le32(pci_dma_lo32(sg_dma_address(sg)));
- *dword_ptr++ =
- cpu_to_le32(sg_dma_len(sg));
+ cpu_to_le32(pci_dma_lo32(sg_dma_address(s)));
+ *dword_ptr++ = cpu_to_le32(sg_dma_len(s));
dprintk(3, "S/G Segment phys_addr=0x%lx, len=0x%x\n",
- (pci_dma_lo32(sg_dma_address(sg))),
- (sg_dma_len(sg)));
- sg++;
+ (pci_dma_lo32(sg_dma_address(s))),
+ (sg_dma_len(s)));
+ remseg--;
}
/*
* Build continuation packets.
*/
dprintk(3, "S/G Building Continuation"
"...seg_cnt=0x%x remains\n", seg_cnt);
- while (seg_cnt > 0) {
+ while (remseg > 0) {
+ /* Continue from end point */
+ sg = s;
/* Adjust ring index. */
ha->req_ring_index++;
if (ha->req_ring_index == REQUEST_ENTRY_CNT) {
@@ -3239,19 +3249,20 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
&((struct cont_entry *) pkt)->dseg_0_address;
/* Load continuation entry data segments. */
- for (cnt = 0; cnt < 7 && seg_cnt;
- cnt++, seg_cnt--) {
+ for_each_sg(sg, s, remseg, cnt) {
+ if (cnt == 7)
+ break;
*dword_ptr++ =
- cpu_to_le32(pci_dma_lo32(sg_dma_address(sg)));
+ cpu_to_le32(pci_dma_lo32(sg_dma_address(s)));
*dword_ptr++ =
- cpu_to_le32(sg_dma_len(sg));
+ cpu_to_le32(sg_dma_len(s));
dprintk(1,
"S/G Segment Cont. phys_addr=0x%x, "
"len=0x%x\n",
- cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))),
- cpu_to_le32(sg_dma_len(sg)));
- sg++;
+ cpu_to_le32(pci_dma_lo32(sg_dma_address(s))),
+ cpu_to_le32(sg_dma_len(s)));
}
+ remseg -= cnt;
dprintk(5, "qla1280_32bit_start_scsi: "
"continuation packet data - "
"scsi(%i:%i:%i)\n", SCSI_BUS_32(cmd),
@@ -4086,7 +4097,7 @@ __qla1280_print_scsi_cmd(struct scsi_cmnd *cmd)
} */
printk(" tag=%d, transfersize=0x%x \n",
cmd->tag, cmd->transfersize);
- printk(" Pid=%li, SP=0x%p\n", cmd->pid, CMD_SP(cmd));
+ printk(" Pid=%li, SP=0x%p\n", cmd->serial_number, CMD_SP(cmd));
printk(" underflow size = 0x%x, direction=0x%x\n",
cmd->underflow, cmd->sc_data_direction);
}
@@ -4248,6 +4259,7 @@ static struct scsi_host_template qla1280_driver_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
@@ -4298,7 +4310,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
printk(KERN_WARNING "scsi(%li): Unable to set a "
"suitable DMA mask - aborting\n", ha->host_no);
error = -ENODEV;
- goto error_free_irq;
+ goto error_put_host;
}
} else
dprintk(2, "scsi(%li): 64 Bit PCI Addressing Enabled\n",
@@ -4308,7 +4320,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
printk(KERN_WARNING "scsi(%li): Unable to set a "
"suitable DMA mask - aborting\n", ha->host_no);
error = -ENODEV;
- goto error_free_irq;
+ goto error_put_host;
}
#endif
diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h
index 59915fb7030..ff2c363ead2 100644
--- a/drivers/scsi/qla1280.h
+++ b/drivers/scsi/qla1280.h
@@ -91,8 +91,8 @@
#define INVALID_HANDLE (MAX_OUTSTANDING_COMMANDS + 2)
/* ISP request and response entry counts (37-65535) */
-#define REQUEST_ENTRY_CNT 256 /* Number of request entries. */
-#define RESPONSE_ENTRY_CNT 16 /* Number of response entries. */
+#define REQUEST_ENTRY_CNT 255 /* Number of request entries. */
+#define RESPONSE_ENTRY_CNT 63 /* Number of response entries. */
/*
* SCSI Request Block structure (sp) that is placed
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 0f2a9f5d801..fb388b8c07c 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -18,7 +18,7 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
char *rbuf = (char *)ha->fw_dump;
@@ -39,7 +39,7 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
int reading;
@@ -89,7 +89,7 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
int size = ha->nvram_size;
char *nvram_cache = ha->nvram;
@@ -112,9 +112,8 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
- unsigned long flags;
uint16_t cnt;
if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size)
@@ -144,11 +143,9 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj,
}
/* Write NVRAM. */
- spin_lock_irqsave(&ha->hardware_lock, flags);
ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
- ha->isp_ops->read_nvram(ha, (uint8_t *)&ha->nvram, ha->nvram_base,
+ ha->isp_ops->read_nvram(ha, (uint8_t *)ha->nvram, ha->nvram_base,
count);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
@@ -170,15 +167,15 @@ qla2x00_sysfs_read_optrom(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
if (ha->optrom_state != QLA_SREADING)
return 0;
- if (off > ha->optrom_size)
+ if (off > ha->optrom_region_size)
return 0;
- if (off + count > ha->optrom_size)
- count = ha->optrom_size - off;
+ if (off + count > ha->optrom_region_size)
+ count = ha->optrom_region_size - off;
memcpy(buf, &ha->optrom_buffer[off], count);
@@ -190,15 +187,15 @@ qla2x00_sysfs_write_optrom(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
if (ha->optrom_state != QLA_SWRITING)
return -EINVAL;
- if (off > ha->optrom_size)
+ if (off > ha->optrom_region_size)
return -ERANGE;
- if (off + count > ha->optrom_size)
- count = ha->optrom_size - off;
+ if (off + count > ha->optrom_region_size)
+ count = ha->optrom_region_size - off;
memcpy(&ha->optrom_buffer[off], buf, count);
@@ -220,14 +217,18 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
- int val;
+ uint32_t start = 0;
+ uint32_t size = ha->optrom_size;
+ int val, valid;
if (off)
return 0;
- if (sscanf(buf, "%d", &val) != 1)
+ if (sscanf(buf, "%d:%x:%x", &val, &start, &size) < 1)
+ return -EINVAL;
+ if (start > ha->optrom_size)
return -EINVAL;
switch (val) {
@@ -237,6 +238,11 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
break;
ha->optrom_state = QLA_SWAITING;
+
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "Freeing flash region allocation -- 0x%x bytes.\n",
+ ha->optrom_region_size));
+
vfree(ha->optrom_buffer);
ha->optrom_buffer = NULL;
break;
@@ -244,44 +250,107 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
if (ha->optrom_state != QLA_SWAITING)
break;
+ if (start & 0xfff) {
+ qla_printk(KERN_WARNING, ha,
+ "Invalid start region 0x%x/0x%x.\n", start, size);
+ return -EINVAL;
+ }
+
+ ha->optrom_region_start = start;
+ ha->optrom_region_size = start + size > ha->optrom_size ?
+ ha->optrom_size - start : size;
+
ha->optrom_state = QLA_SREADING;
- ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size);
+ ha->optrom_buffer = vmalloc(ha->optrom_region_size);
if (ha->optrom_buffer == NULL) {
qla_printk(KERN_WARNING, ha,
"Unable to allocate memory for optrom retrieval "
- "(%x).\n", ha->optrom_size);
+ "(%x).\n", ha->optrom_region_size);
ha->optrom_state = QLA_SWAITING;
return count;
}
- memset(ha->optrom_buffer, 0, ha->optrom_size);
- ha->isp_ops->read_optrom(ha, ha->optrom_buffer, 0,
- ha->optrom_size);
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "Reading flash region -- 0x%x/0x%x.\n",
+ ha->optrom_region_start, ha->optrom_region_size));
+
+ memset(ha->optrom_buffer, 0, ha->optrom_region_size);
+ ha->isp_ops->read_optrom(ha, ha->optrom_buffer,
+ ha->optrom_region_start, ha->optrom_region_size);
break;
case 2:
if (ha->optrom_state != QLA_SWAITING)
break;
+ /*
+ * We need to be more restrictive on which FLASH regions are
+ * allowed to be updated via user-space. Regions accessible
+ * via this method include:
+ *
+ * ISP21xx/ISP22xx/ISP23xx type boards:
+ *
+ * 0x000000 -> 0x020000 -- Boot code.
+ *
+ * ISP2322/ISP24xx type boards:
+ *
+ * 0x000000 -> 0x07ffff -- Boot code.
+ * 0x080000 -> 0x0fffff -- Firmware.
+ *
+ * ISP25xx type boards:
+ *
+ * 0x000000 -> 0x07ffff -- Boot code.
+ * 0x080000 -> 0x0fffff -- Firmware.
+ * 0x120000 -> 0x12ffff -- VPD and HBA parameters.
+ */
+ valid = 0;
+ if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
+ valid = 1;
+ else if (start == (FA_BOOT_CODE_ADDR*4) ||
+ start == (FA_RISC_CODE_ADDR*4))
+ valid = 1;
+ else if (IS_QLA25XX(ha) && start == (FA_VPD_NVRAM_ADDR*4))
+ valid = 1;
+ if (!valid) {
+ qla_printk(KERN_WARNING, ha,
+ "Invalid start region 0x%x/0x%x.\n", start, size);
+ return -EINVAL;
+ }
+
+ ha->optrom_region_start = start;
+ ha->optrom_region_size = start + size > ha->optrom_size ?
+ ha->optrom_size - start : size;
+
ha->optrom_state = QLA_SWRITING;
- ha->optrom_buffer = (uint8_t *)vmalloc(ha->optrom_size);
+ ha->optrom_buffer = vmalloc(ha->optrom_region_size);
if (ha->optrom_buffer == NULL) {
qla_printk(KERN_WARNING, ha,
"Unable to allocate memory for optrom update "
- "(%x).\n", ha->optrom_size);
+ "(%x).\n", ha->optrom_region_size);
ha->optrom_state = QLA_SWAITING;
return count;
}
- memset(ha->optrom_buffer, 0, ha->optrom_size);
+
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "Staging flash region write -- 0x%x/0x%x.\n",
+ ha->optrom_region_start, ha->optrom_region_size));
+
+ memset(ha->optrom_buffer, 0, ha->optrom_region_size);
break;
case 3:
if (ha->optrom_state != QLA_SWRITING)
break;
- ha->isp_ops->write_optrom(ha, ha->optrom_buffer, 0,
- ha->optrom_size);
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "Writing flash region -- 0x%x/0x%x.\n",
+ ha->optrom_region_start, ha->optrom_region_size));
+
+ ha->isp_ops->write_optrom(ha, ha->optrom_buffer,
+ ha->optrom_region_start, ha->optrom_region_size);
break;
+ default:
+ count = -EINVAL;
}
return count;
}
@@ -300,7 +369,7 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
int size = ha->vpd_size;
char *vpd_cache = ha->vpd;
@@ -323,18 +392,15 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
- unsigned long flags;
if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size)
return 0;
/* Write NVRAM. */
- spin_lock_irqsave(&ha->hardware_lock, flags);
ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count);
ha->isp_ops->read_nvram(ha, (uint8_t *)ha->vpd, ha->vpd_base, count);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
return count;
}
@@ -354,7 +420,7 @@ qla2x00_sysfs_read_sfp(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
uint16_t iter, addr, offset;
int rval;
@@ -459,7 +525,7 @@ qla2x00_drvr_version_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_fw_version_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
char fw_str[30];
return snprintf(buf, PAGE_SIZE, "%s\n",
@@ -469,9 +535,12 @@ qla2x00_fw_version_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_serial_num_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
uint32_t sn;
+ if (IS_FWI2_CAPABLE(ha))
+ return snprintf(buf, PAGE_SIZE, "\n");
+
sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
sn % 100000);
@@ -480,14 +549,14 @@ qla2x00_serial_num_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_isp_name_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "ISP%04X\n", ha->pdev->device);
}
static ssize_t
qla2x00_isp_id_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
ha->product_id[0], ha->product_id[1], ha->product_id[2],
ha->product_id[3]);
@@ -496,14 +565,14 @@ qla2x00_isp_id_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_model_name_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_number);
}
static ssize_t
qla2x00_model_desc_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%s\n",
ha->model_desc ? ha->model_desc: "");
}
@@ -511,7 +580,7 @@ qla2x00_model_desc_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_pci_info_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
char pci_info[30];
return snprintf(buf, PAGE_SIZE, "%s\n",
@@ -521,7 +590,7 @@ qla2x00_pci_info_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_state_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
int len = 0;
if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
@@ -559,7 +628,7 @@ qla2x00_state_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_zio_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
int len = 0;
switch (ha->zio_mode) {
@@ -576,7 +645,7 @@ qla2x00_zio_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_zio_store(struct class_device *cdev, const char *buf, size_t count)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
int val = 0;
uint16_t zio_mode;
@@ -602,7 +671,7 @@ qla2x00_zio_store(struct class_device *cdev, const char *buf, size_t count)
static ssize_t
qla2x00_zio_timer_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%d us\n", ha->zio_timer * 100);
}
@@ -611,7 +680,7 @@ static ssize_t
qla2x00_zio_timer_store(struct class_device *cdev, const char *buf,
size_t count)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
int val = 0;
uint16_t zio_timer;
@@ -629,7 +698,7 @@ qla2x00_zio_timer_store(struct class_device *cdev, const char *buf,
static ssize_t
qla2x00_beacon_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
int len = 0;
if (ha->beacon_blink_led)
@@ -643,7 +712,7 @@ static ssize_t
qla2x00_beacon_store(struct class_device *cdev, const char *buf,
size_t count)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
int val = 0;
int rval;
@@ -673,7 +742,7 @@ qla2x00_beacon_store(struct class_device *cdev, const char *buf,
static ssize_t
qla2x00_optrom_bios_version_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1],
ha->bios_revision[0]);
@@ -682,7 +751,7 @@ qla2x00_optrom_bios_version_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_optrom_efi_version_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1],
ha->efi_revision[0]);
@@ -691,7 +760,7 @@ qla2x00_optrom_efi_version_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_optrom_fcode_version_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1],
ha->fcode_revision[0]);
@@ -700,7 +769,7 @@ qla2x00_optrom_fcode_version_show(struct class_device *cdev, char *buf)
static ssize_t
qla2x00_optrom_fw_version_show(struct class_device *cdev, char *buf)
{
- scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+ scsi_qla_host_t *ha = shost_priv(class_to_shost(cdev));
return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n",
ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2],
@@ -757,7 +826,7 @@ struct class_device_attribute *qla2x00_host_attrs[] = {
static void
qla2x00_get_host_port_id(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
fc_host_port_id(shost) = ha->d_id.b.domain << 16 |
ha->d_id.b.area << 8 | ha->d_id.b.al_pa;
@@ -766,7 +835,7 @@ qla2x00_get_host_port_id(struct Scsi_Host *shost)
static void
qla2x00_get_host_speed(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
uint32_t speed = 0;
switch (ha->link_data_rate) {
@@ -786,7 +855,7 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
static void
qla2x00_get_host_port_type(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
uint32_t port_type = FC_PORTTYPE_UNKNOWN;
switch (ha->current_topology) {
@@ -810,7 +879,7 @@ static void
qla2x00_get_starget_node_name(struct scsi_target *starget)
{
struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
- scsi_qla_host_t *ha = to_qla_host(host);
+ scsi_qla_host_t *ha = shost_priv(host);
fc_port_t *fcport;
u64 node_name = 0;
@@ -828,7 +897,7 @@ static void
qla2x00_get_starget_port_name(struct scsi_target *starget)
{
struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
- scsi_qla_host_t *ha = to_qla_host(host);
+ scsi_qla_host_t *ha = shost_priv(host);
fc_port_t *fcport;
u64 port_name = 0;
@@ -846,7 +915,7 @@ static void
qla2x00_get_starget_port_id(struct scsi_target *starget)
{
struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
- scsi_qla_host_t *ha = to_qla_host(host);
+ scsi_qla_host_t *ha = shost_priv(host);
fc_port_t *fcport;
uint32_t port_id = ~0U;
@@ -865,7 +934,7 @@ static void
qla2x00_get_rport_loss_tmo(struct fc_rport *rport)
{
struct Scsi_Host *host = rport_to_shost(rport);
- scsi_qla_host_t *ha = to_qla_host(host);
+ scsi_qla_host_t *ha = shost_priv(host);
rport->dev_loss_tmo = ha->port_down_retry_count + 5;
}
@@ -874,7 +943,7 @@ static void
qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
{
struct Scsi_Host *host = rport_to_shost(rport);
- scsi_qla_host_t *ha = to_qla_host(host);
+ scsi_qla_host_t *ha = shost_priv(host);
if (timeout)
ha->port_down_retry_count = timeout;
@@ -887,7 +956,7 @@ qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
static int
qla2x00_issue_lip(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
set_bit(LOOP_RESET_NEEDED, &ha->dpc_flags);
return 0;
@@ -896,7 +965,7 @@ qla2x00_issue_lip(struct Scsi_Host *shost)
static struct fc_host_statistics *
qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
int rval;
uint16_t mb_stat[1];
link_stat_t stat_buf;
@@ -934,7 +1003,7 @@ done:
static void
qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
qla2x00_get_sym_node_name(ha, fc_host_symbolic_name(shost));
}
@@ -942,7 +1011,7 @@ qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
static void
qla2x00_set_host_system_hostname(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
}
@@ -950,7 +1019,7 @@ qla2x00_set_host_system_hostname(struct Scsi_Host *shost)
static void
qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
u64 node_name;
if (ha->device_flags & SWITCH_FOUND)
@@ -964,7 +1033,7 @@ qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
static void
qla2x00_get_host_port_state(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = to_qla_host(shost);
+ scsi_qla_host_t *ha = shost_priv(shost);
if (!ha->flags.online)
fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
@@ -978,7 +1047,7 @@ static int
qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
{
int ret = 0;
- scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
scsi_qla_host_t *vha;
ret = qla24xx_vport_create_req_sanity_check(fc_vport);
@@ -1047,7 +1116,7 @@ vport_create_failed_2:
int
qla24xx_vport_delete(struct fc_vport *fc_vport)
{
- scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
scsi_qla_host_t *vha = fc_vport->dd_data;
qla24xx_disable_vp(vha);
@@ -1178,6 +1247,6 @@ qla2x00_init_host_attr(scsi_qla_host_t *ha)
fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name);
fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name);
fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
- fc_host_max_npiv_vports(ha->host) = MAX_NUM_VPORT_FABRIC;
+ fc_host_max_npiv_vports(ha->host) = ha->max_npiv_vports;;
fc_host_npiv_vports_inuse(ha->host) = ha->cur_vport_count;
}
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index c6680348b64..eaa04dabcdf 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -38,7 +38,7 @@ qla2xxx_copy_queues(scsi_qla_host_t *ha, void *ptr)
}
static int
-qla2xxx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
+qla24xx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
uint32_t cram_size, uint32_t *ext_mem, void **nxt)
{
int rval;
@@ -152,6 +152,103 @@ qla2xxx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
return rval;
}
+static uint32_t *
+qla24xx_read_window(struct device_reg_24xx __iomem *reg, uint32_t iobase,
+ uint32_t count, uint32_t *buf)
+{
+ uint32_t __iomem *dmp_reg;
+
+ WRT_REG_DWORD(&reg->iobase_addr, iobase);
+ dmp_reg = &reg->iobase_window;
+ while (count--)
+ *buf++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ return buf;
+}
+
+static inline int
+qla24xx_pause_risc(struct device_reg_24xx __iomem *reg)
+{
+ int rval = QLA_SUCCESS;
+ uint32_t cnt;
+
+ if (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE)
+ return rval;
+
+ WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
+ for (cnt = 30000; (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
+ rval == QLA_SUCCESS; cnt--) {
+ if (cnt)
+ udelay(100);
+ else
+ rval = QLA_FUNCTION_TIMEOUT;
+ }
+
+ return rval;
+}
+
+static int
+qla24xx_soft_reset(scsi_qla_host_t *ha)
+{
+ int rval = QLA_SUCCESS;
+ uint32_t cnt;
+ uint16_t mb0, wd;
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+ /* Reset RISC. */
+ WRT_REG_DWORD(&reg->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
+ for (cnt = 0; cnt < 30000; cnt++) {
+ if ((RD_REG_DWORD(&reg->ctrl_status) & CSRX_DMA_ACTIVE) == 0)
+ break;
+
+ udelay(10);
+ }
+
+ WRT_REG_DWORD(&reg->ctrl_status,
+ CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
+ pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
+
+ udelay(100);
+ /* Wait for firmware to complete NVRAM accesses. */
+ mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+ for (cnt = 10000 ; cnt && mb0; cnt--) {
+ udelay(5);
+ mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+ barrier();
+ }
+
+ /* Wait for soft-reset to complete. */
+ for (cnt = 0; cnt < 30000; cnt++) {
+ if ((RD_REG_DWORD(&reg->ctrl_status) &
+ CSRX_ISP_SOFT_RESET) == 0)
+ break;
+
+ udelay(10);
+ }
+ WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
+ RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
+
+ for (cnt = 30000; RD_REG_WORD(&reg->mailbox0) != 0 &&
+ rval == QLA_SUCCESS; cnt--) {
+ if (cnt)
+ udelay(100);
+ else
+ rval = QLA_FUNCTION_TIMEOUT;
+ }
+
+ return rval;
+}
+
+static inline void
+qla2xxx_read_window(struct device_reg_2xxx __iomem *reg, uint32_t count,
+ uint16_t *buf)
+{
+ uint16_t __iomem *dmp_reg = &reg->u.isp2300.fb_cmd;
+
+ while (count--)
+ *buf++ = htons(RD_REG_WORD(dmp_reg++));
+}
+
/**
* qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
* @ha: HA context
@@ -214,88 +311,61 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
}
if (rval == QLA_SUCCESS) {
- dmp_reg = (uint16_t __iomem *)(reg + 0);
+ dmp_reg = &reg->flash_address;
for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10);
+ dmp_reg = &reg->u.isp2300.req_q_in;
for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++)
fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x40);
+ dmp_reg = &reg->u.isp2300.mailbox0;
for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x40);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->resp_dma_reg) / 2; cnt++)
- fw->resp_dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 32, fw->resp_dma_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x50);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++)
- fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 48, fw->dma_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x00);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0);
+ dmp_reg = &reg->risc_hw;
for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2000);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++)
- fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp0_reg);
WRT_REG_WORD(&reg->pcr, 0x2200);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++)
- fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp1_reg);
WRT_REG_WORD(&reg->pcr, 0x2400);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++)
- fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp2_reg);
WRT_REG_WORD(&reg->pcr, 0x2600);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++)
- fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp3_reg);
WRT_REG_WORD(&reg->pcr, 0x2800);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++)
- fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp4_reg);
WRT_REG_WORD(&reg->pcr, 0x2A00);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++)
- fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp5_reg);
WRT_REG_WORD(&reg->pcr, 0x2C00);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++)
- fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp6_reg);
WRT_REG_WORD(&reg->pcr, 0x2E00);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++)
- fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp7_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x10);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++)
- fw->frame_buf_hdw_reg[cnt] =
- htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 64, fw->frame_buf_hdw_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x20);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++)
- fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 64, fw->fpm_b0_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x30);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++)
- fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 64, fw->fpm_b1_reg);
/* Reset RISC. */
WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
@@ -567,83 +637,59 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
rval = QLA_FUNCTION_TIMEOUT;
}
if (rval == QLA_SUCCESS) {
- dmp_reg = (uint16_t __iomem *)(reg + 0);
+ dmp_reg = &reg->flash_address;
for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10);
+ dmp_reg = &reg->u.isp2100.mailbox0;
for (cnt = 0; cnt < ha->mbx_count; cnt++) {
- if (cnt == 8) {
- dmp_reg = (uint16_t __iomem *)
- ((uint8_t __iomem *)reg + 0xe0);
- }
+ if (cnt == 8)
+ dmp_reg = &reg->u_end.isp2200.mailbox8;
+
fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
}
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x20);
+ dmp_reg = &reg->u.isp2100.unused_2[0];
for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++)
fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x00);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0);
+ dmp_reg = &reg->risc_hw;
for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2000);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++)
- fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp0_reg);
WRT_REG_WORD(&reg->pcr, 0x2100);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++)
- fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp1_reg);
WRT_REG_WORD(&reg->pcr, 0x2200);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++)
- fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp2_reg);
WRT_REG_WORD(&reg->pcr, 0x2300);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++)
- fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp3_reg);
WRT_REG_WORD(&reg->pcr, 0x2400);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++)
- fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp4_reg);
WRT_REG_WORD(&reg->pcr, 0x2500);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++)
- fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp5_reg);
WRT_REG_WORD(&reg->pcr, 0x2600);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++)
- fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp6_reg);
WRT_REG_WORD(&reg->pcr, 0x2700);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++)
- fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->risc_gp7_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x10);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++)
- fw->frame_buf_hdw_reg[cnt] =
- htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 16, fw->frame_buf_hdw_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x20);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++)
- fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 64, fw->fpm_b0_reg);
WRT_REG_WORD(&reg->ctrl_status, 0x30);
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
- for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++)
- fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
+ qla2xxx_read_window(reg, 64, fw->fpm_b1_reg);
/* Reset the ISP. */
WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
@@ -750,7 +796,6 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
int rval;
uint32_t cnt;
uint32_t risc_address;
- uint16_t mb0, wd;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
uint32_t __iomem *dmp_reg;
@@ -782,547 +827,198 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
fw = &ha->fw_dump->isp.isp24;
qla2xxx_prep_dump(ha, ha->fw_dump);
- rval = QLA_SUCCESS;
fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
/* Pause RISC. */
- if ((RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0) {
- WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET |
- HCCRX_CLR_HOST_INT);
- RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
- WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
- for (cnt = 30000;
- (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
- rval == QLA_SUCCESS; cnt--) {
- if (cnt)
- udelay(100);
- else
- rval = QLA_FUNCTION_TIMEOUT;
- }
- }
-
- if (rval == QLA_SUCCESS) {
- /* Host interface registers. */
- dmp_reg = (uint32_t __iomem *)(reg + 0);
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Disable interrupts. */
- WRT_REG_DWORD(&reg->ictrl, 0);
- RD_REG_DWORD(&reg->ictrl);
-
- /* Shadow registers. */
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
- RD_REG_DWORD(&reg->iobase_addr);
- WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
- fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
- fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
- fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
- fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
- fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
- fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
- fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- /* Mailbox registers. */
- mbx_reg = &reg->mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
-
- /* Transfer sequence registers. */
- iter_reg = fw->xseq_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++)
- fw->xseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
- fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Receive sequence registers. */
- iter_reg = fw->rseq_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++)
- fw->rseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
- fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
- fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Command DMA registers. */
- WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
- fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Queues. */
- iter_reg = fw->req0_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->resp0_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->req1_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Transmit DMA registers. */
- iter_reg = fw->xmt0_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt1_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt2_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt3_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt4_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
- fw->xmt_data_dma_reg[cnt] =
- htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Receive DMA registers. */
- iter_reg = fw->rcvt0_data_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->rcvt1_data_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* RISC registers. */
- iter_reg = fw->risc_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Local memory controller registers. */
- iter_reg = fw->lmc_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Fibre Protocol Module registers. */
- iter_reg = fw->fpm_hdw_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Frame Buffer registers. */
- iter_reg = fw->fb_hdw_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Reset RISC. */
- WRT_REG_DWORD(&reg->ctrl_status,
- CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
- for (cnt = 0; cnt < 30000; cnt++) {
- if ((RD_REG_DWORD(&reg->ctrl_status) &
- CSRX_DMA_ACTIVE) == 0)
- break;
-
- udelay(10);
- }
-
- WRT_REG_DWORD(&reg->ctrl_status,
- CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
- pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
-
- udelay(100);
- /* Wait for firmware to complete NVRAM accesses. */
- mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
- for (cnt = 10000 ; cnt && mb0; cnt--) {
- udelay(5);
- mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
- barrier();
- }
-
- /* Wait for soft-reset to complete. */
- for (cnt = 0; cnt < 30000; cnt++) {
- if ((RD_REG_DWORD(&reg->ctrl_status) &
- CSRX_ISP_SOFT_RESET) == 0)
- break;
-
- udelay(10);
- }
- WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
- RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
- }
-
- for (cnt = 30000; RD_REG_WORD(&reg->mailbox0) != 0 &&
- rval == QLA_SUCCESS; cnt--) {
- if (cnt)
- udelay(100);
- else
- rval = QLA_FUNCTION_TIMEOUT;
- }
-
- if (rval == QLA_SUCCESS)
- rval = qla2xxx_dump_memory(ha, fw->code_ram,
- sizeof(fw->code_ram), fw->ext_mem, &nxt);
-
- if (rval == QLA_SUCCESS) {
- nxt = qla2xxx_copy_queues(ha, nxt);
- if (ha->eft)
- memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
- }
-
+ rval = qla24xx_pause_risc(reg);
+ if (rval != QLA_SUCCESS)
+ goto qla24xx_fw_dump_failed_0;
+
+ /* Host interface registers. */
+ dmp_reg = &reg->flash_addr;
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Disable interrupts. */
+ WRT_REG_DWORD(&reg->ictrl, 0);
+ RD_REG_DWORD(&reg->ictrl);
+
+ /* Shadow registers. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+ RD_REG_DWORD(&reg->iobase_addr);
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+ fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+ fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+ fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+ fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+ fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+ fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+ fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ /* Mailbox registers. */
+ mbx_reg = &reg->mailbox0;
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+
+ /* Transfer sequence registers. */
+ iter_reg = fw->xseq_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg);
+ qla24xx_read_window(reg, 0xBF70, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0xBFE0, 16, fw->xseq_0_reg);
+ qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg);
+
+ /* Receive sequence registers. */
+ iter_reg = fw->rseq_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg);
+ qla24xx_read_window(reg, 0xFF70, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0xFFD0, 16, fw->rseq_0_reg);
+ qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg);
+ qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg);
+
+ /* Command DMA registers. */
+ qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg);
+
+ /* Queues. */
+ iter_reg = fw->req0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->resp0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->req1_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Transmit DMA registers. */
+ iter_reg = fw->xmt0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7610, 16, iter_reg);
+
+ iter_reg = fw->xmt1_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7630, 16, iter_reg);
+
+ iter_reg = fw->xmt2_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7650, 16, iter_reg);
+
+ iter_reg = fw->xmt3_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7670, 16, iter_reg);
+
+ iter_reg = fw->xmt4_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7690, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg);
+
+ /* Receive DMA registers. */
+ iter_reg = fw->rcvt0_data_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7710, 16, iter_reg);
+
+ iter_reg = fw->rcvt1_data_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7730, 16, iter_reg);
+
+ /* RISC registers. */
+ iter_reg = fw->risc_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg);
+ qla24xx_read_window(reg, 0x0F70, 16, iter_reg);
+
+ /* Local memory controller registers. */
+ iter_reg = fw->lmc_reg;
+ iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg);
+ qla24xx_read_window(reg, 0x3060, 16, iter_reg);
+
+ /* Fibre Protocol Module registers. */
+ iter_reg = fw->fpm_hdw_reg;
+ iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg);
+ qla24xx_read_window(reg, 0x40B0, 16, iter_reg);
+
+ /* Frame Buffer registers. */
+ iter_reg = fw->fb_hdw_reg;
+ iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg);
+ qla24xx_read_window(reg, 0x61B0, 16, iter_reg);
+
+ rval = qla24xx_soft_reset(ha);
+ if (rval != QLA_SUCCESS)
+ goto qla24xx_fw_dump_failed_0;
+
+ rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
+ fw->ext_mem, &nxt);
+ if (rval != QLA_SUCCESS)
+ goto qla24xx_fw_dump_failed_0;
+
+ nxt = qla2xxx_copy_queues(ha, nxt);
+ if (ha->eft)
+ memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
+
+qla24xx_fw_dump_failed_0:
if (rval != QLA_SUCCESS) {
qla_printk(KERN_WARNING, ha,
"Failed to dump firmware (%x)!!!\n", rval);
@@ -1346,7 +1042,6 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
int rval;
uint32_t cnt;
uint32_t risc_address;
- uint16_t mb0, wd;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
uint32_t __iomem *dmp_reg;
@@ -1377,655 +1072,260 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
}
fw = &ha->fw_dump->isp.isp25;
qla2xxx_prep_dump(ha, ha->fw_dump);
+ ha->fw_dump->version = __constant_htonl(2);
- rval = QLA_SUCCESS;
fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
/* Pause RISC. */
- if ((RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0) {
- WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET |
- HCCRX_CLR_HOST_INT);
- RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
- WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
- for (cnt = 30000;
- (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
- rval == QLA_SUCCESS; cnt--) {
- if (cnt)
- udelay(100);
- else
- rval = QLA_FUNCTION_TIMEOUT;
- }
- }
-
- if (rval == QLA_SUCCESS) {
- /* Host interface registers. */
- dmp_reg = (uint32_t __iomem *)(reg + 0);
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Disable interrupts. */
- WRT_REG_DWORD(&reg->ictrl, 0);
- RD_REG_DWORD(&reg->ictrl);
-
- /* Shadow registers. */
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
- RD_REG_DWORD(&reg->iobase_addr);
- WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
- fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
- fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
- fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
- fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
- fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
- fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
- fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0700000);
- fw->shadow_reg[7] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0800000);
- fw->shadow_reg[8] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0900000);
- fw->shadow_reg[9] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- WRT_REG_DWORD(&reg->iobase_select, 0xB0A00000);
- fw->shadow_reg[10] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
-
- /* RISC I/O register. */
- WRT_REG_DWORD(&reg->iobase_addr, 0x0010);
- RD_REG_DWORD(&reg->iobase_addr);
- fw->risc_io_reg = htonl(RD_REG_DWORD(&reg->iobase_window));
-
- /* Mailbox registers. */
- mbx_reg = &reg->mailbox0;
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
-
- /* Transfer sequence registers. */
- iter_reg = fw->xseq_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xseq_0_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xBFC0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBFD0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
- fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Receive sequence registers. */
- iter_reg = fw->rseq_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->rseq_0_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFC0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
- fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
- fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Auxiliary sequence registers. */
- iter_reg = fw->aseq_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xB000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB050);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB060);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB070);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->aseq_0_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0xB0C0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB0D0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB0E0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->aseq_1_reg) / 4; cnt++)
- fw->aseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0xB0F0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->aseq_2_reg) / 4; cnt++)
- fw->aseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Command DMA registers. */
- WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
- fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Queues. */
- iter_reg = fw->req0_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->resp0_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->req1_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- dmp_reg = &reg->iobase_q;
- for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Transmit DMA registers. */
- iter_reg = fw->xmt0_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt1_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt2_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt3_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->xmt4_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
- fw->xmt_data_dma_reg[cnt] =
- htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Receive DMA registers. */
- iter_reg = fw->rcvt0_data_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- iter_reg = fw->rcvt1_data_dma_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* RISC registers. */
- iter_reg = fw->risc_gp_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Local memory controller registers. */
- iter_reg = fw->lmc_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x3070);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Fibre Protocol Module registers. */
- iter_reg = fw->fpm_hdw_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Frame Buffer registers. */
- iter_reg = fw->fb_hdw_reg;
- WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- WRT_REG_DWORD(&reg->iobase_addr, 0x6F00);
- dmp_reg = &reg->iobase_window;
- for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
-
- /* Reset RISC. */
- WRT_REG_DWORD(&reg->ctrl_status,
- CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
- for (cnt = 0; cnt < 30000; cnt++) {
- if ((RD_REG_DWORD(&reg->ctrl_status) &
- CSRX_DMA_ACTIVE) == 0)
- break;
-
- udelay(10);
- }
-
- WRT_REG_DWORD(&reg->ctrl_status,
- CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
- pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
-
- udelay(100);
- /* Wait for firmware to complete NVRAM accesses. */
- mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
- for (cnt = 10000 ; cnt && mb0; cnt--) {
- udelay(5);
- mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
- barrier();
- }
-
- /* Wait for soft-reset to complete. */
- for (cnt = 0; cnt < 30000; cnt++) {
- if ((RD_REG_DWORD(&reg->ctrl_status) &
- CSRX_ISP_SOFT_RESET) == 0)
- break;
-
- udelay(10);
- }
- WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
- RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
- }
-
- for (cnt = 30000; RD_REG_WORD(&reg->mailbox0) != 0 &&
- rval == QLA_SUCCESS; cnt--) {
- if (cnt)
- udelay(100);
- else
- rval = QLA_FUNCTION_TIMEOUT;
- }
-
- if (rval == QLA_SUCCESS)
- rval = qla2xxx_dump_memory(ha, fw->code_ram,
- sizeof(fw->code_ram), fw->ext_mem, &nxt);
-
- if (rval == QLA_SUCCESS) {
- nxt = qla2xxx_copy_queues(ha, nxt);
- if (ha->eft)
- memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
- }
-
+ rval = qla24xx_pause_risc(reg);
+ if (rval != QLA_SUCCESS)
+ goto qla25xx_fw_dump_failed_0;
+
+ /* Host/Risc registers. */
+ iter_reg = fw->host_risc_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7000, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7010, 16, iter_reg);
+
+ /* PCIe registers. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);
+ RD_REG_DWORD(&reg->iobase_addr);
+ WRT_REG_DWORD(&reg->iobase_window, 0x01);
+ dmp_reg = &reg->iobase_c4;
+ fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++));
+ fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++));
+ fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
+ fw->pcie_regs[3] = htonl(RD_REG_DWORD(&reg->iobase_window));
+ WRT_REG_DWORD(&reg->iobase_window, 0x00);
+ RD_REG_DWORD(&reg->iobase_window);
+
+ /* Host interface registers. */
+ dmp_reg = &reg->flash_addr;
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Disable interrupts. */
+ WRT_REG_DWORD(&reg->ictrl, 0);
+ RD_REG_DWORD(&reg->ictrl);
+
+ /* Shadow registers. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+ RD_REG_DWORD(&reg->iobase_addr);
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+ fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+ fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+ fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+ fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+ fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+ fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+ fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0700000);
+ fw->shadow_reg[7] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0800000);
+ fw->shadow_reg[8] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0900000);
+ fw->shadow_reg[9] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0A00000);
+ fw->shadow_reg[10] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ /* RISC I/O register. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0010);
+ fw->risc_io_reg = htonl(RD_REG_DWORD(&reg->iobase_window));
+
+ /* Mailbox registers. */
+ mbx_reg = &reg->mailbox0;
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+
+ /* Transfer sequence registers. */
+ iter_reg = fw->xseq_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg);
+ qla24xx_read_window(reg, 0xBF70, 16, iter_reg);
+
+ iter_reg = fw->xseq_0_reg;
+ iter_reg = qla24xx_read_window(reg, 0xBFC0, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBFD0, 16, iter_reg);
+ qla24xx_read_window(reg, 0xBFE0, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg);
+
+ /* Receive sequence registers. */
+ iter_reg = fw->rseq_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg);
+ qla24xx_read_window(reg, 0xFF70, 16, iter_reg);
+
+ iter_reg = fw->rseq_0_reg;
+ iter_reg = qla24xx_read_window(reg, 0xFFC0, 16, iter_reg);
+ qla24xx_read_window(reg, 0xFFD0, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg);
+ qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg);
+
+ /* Auxiliary sequence registers. */
+ iter_reg = fw->aseq_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0xB000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB050, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB060, 16, iter_reg);
+ qla24xx_read_window(reg, 0xB070, 16, iter_reg);
+
+ iter_reg = fw->aseq_0_reg;
+ iter_reg = qla24xx_read_window(reg, 0xB0C0, 16, iter_reg);
+ qla24xx_read_window(reg, 0xB0D0, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0xB0E0, 16, fw->aseq_1_reg);
+ qla24xx_read_window(reg, 0xB0F0, 16, fw->aseq_2_reg);
+
+ /* Command DMA registers. */
+ qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg);
+
+ /* Queues. */
+ iter_reg = fw->req0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->resp0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->req1_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Transmit DMA registers. */
+ iter_reg = fw->xmt0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7610, 16, iter_reg);
+
+ iter_reg = fw->xmt1_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7630, 16, iter_reg);
+
+ iter_reg = fw->xmt2_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7650, 16, iter_reg);
+
+ iter_reg = fw->xmt3_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7670, 16, iter_reg);
+
+ iter_reg = fw->xmt4_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7690, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg);
+
+ /* Receive DMA registers. */
+ iter_reg = fw->rcvt0_data_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7710, 16, iter_reg);
+
+ iter_reg = fw->rcvt1_data_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7730, 16, iter_reg);
+
+ /* RISC registers. */
+ iter_reg = fw->risc_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg);
+ qla24xx_read_window(reg, 0x0F70, 16, iter_reg);
+
+ /* Local memory controller registers. */
+ iter_reg = fw->lmc_reg;
+ iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3060, 16, iter_reg);
+ qla24xx_read_window(reg, 0x3070, 16, iter_reg);
+
+ /* Fibre Protocol Module registers. */
+ iter_reg = fw->fpm_hdw_reg;
+ iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg);
+ qla24xx_read_window(reg, 0x40B0, 16, iter_reg);
+
+ /* Frame Buffer registers. */
+ iter_reg = fw->fb_hdw_reg;
+ iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg);
+ qla24xx_read_window(reg, 0x6F00, 16, iter_reg);
+
+ rval = qla24xx_soft_reset(ha);
+ if (rval != QLA_SUCCESS)
+ goto qla25xx_fw_dump_failed_0;
+
+ rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
+ fw->ext_mem, &nxt);
+ if (rval != QLA_SUCCESS)
+ goto qla25xx_fw_dump_failed_0;
+
+ nxt = qla2xxx_copy_queues(ha, nxt);
+ if (ha->eft)
+ memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
+
+qla25xx_fw_dump_failed_0:
if (rval != QLA_SUCCESS) {
qla_printk(KERN_WARNING, ha,
"Failed to dump firmware (%x)!!!\n", rval);
@@ -2102,7 +1402,7 @@ qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd)
struct scsi_qla_host *ha;
srb_t *sp;
- ha = (struct scsi_qla_host *)cmd->device->host->hostdata;
+ ha = shost_priv(cmd->device->host);
sp = (srb_t *) cmd->SCp.ptr;
printk("SCSI Command @=0x%p, Handle=0x%p\n", cmd, cmd->host_scribble);
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index cca4b0d8253..a50ecf0b7c8 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -215,6 +215,8 @@ struct qla24xx_fw_dump {
struct qla25xx_fw_dump {
uint32_t host_status;
+ uint32_t host_risc_reg[32];
+ uint32_t pcie_regs[4];
uint32_t host_reg[32];
uint32_t shadow_reg[11];
uint32_t risc_io_reg;
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index c1964866a42..04e8cbca4c0 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -23,6 +23,7 @@
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/firmware.h>
+#include <linux/aer.h>
#include <asm/semaphore.h>
#include <scsi/scsi.h>
@@ -184,8 +185,6 @@
* SCSI Request Block
*/
typedef struct srb {
- struct list_head list;
-
struct scsi_qla_host *ha; /* HA the SP is queued on */
struct fc_port *fcport;
@@ -316,7 +315,9 @@ struct device_reg_2xxx {
} u;
uint16_t fpm_diag_config;
- uint16_t unused_5[0x6]; /* Gap */
+ uint16_t unused_5[0x4]; /* Gap */
+ uint16_t risc_hw;
+ uint16_t unused_5_1; /* Gap */
uint16_t pcr; /* Processor Control Register. */
uint16_t unused_6[0x5]; /* Gap */
uint16_t mctr; /* Memory Configuration and Timing. */
@@ -1702,7 +1703,7 @@ struct ct_fdmi_hba_attributes {
/*
* Port attribute types.
*/
-#define FDMI_PORT_ATTR_COUNT 5
+#define FDMI_PORT_ATTR_COUNT 6
#define FDMI_PORT_FC4_TYPES 1
#define FDMI_PORT_SUPPORT_SPEED 2
#define FDMI_PORT_CURRENT_SPEED 3
@@ -2270,6 +2271,7 @@ typedef struct scsi_qla_host {
spinlock_t hardware_lock ____cacheline_aligned;
+ int bars;
device_reg_t __iomem *iobase; /* Base I/O address */
unsigned long pio_address;
unsigned long pio_length;
@@ -2476,6 +2478,8 @@ typedef struct scsi_qla_host {
#define QLA_SWAITING 0
#define QLA_SREADING 1
#define QLA_SWRITING 2
+ uint32_t optrom_region_start;
+ uint32_t optrom_region_size;
/* PCI expansion ROM image information. */
#define ROM_CODE_TYPE_BIOS 0
@@ -2529,7 +2533,7 @@ typedef struct scsi_qla_host {
#define VP_ERR_FAB_NORESOURCES 3
#define VP_ERR_FAB_LOGOUT 4
#define VP_ERR_ADAP_NORESOURCES 5
- int max_npiv_vports; /* 63 or 125 per topoloty */
+ uint16_t max_npiv_vports; /* 63 or 125 per topoloty */
int cur_vport_count;
} scsi_qla_host_t;
@@ -2542,8 +2546,6 @@ typedef struct scsi_qla_host {
test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || \
atomic_read(&ha->loop_state) == LOOP_DOWN)
-#define to_qla_host(x) ((scsi_qla_host_t *) (x)->hostdata)
-
#define qla_printk(level, ha, format, arg...) \
dev_printk(level , &((ha)->pdev->dev) , format , ## arg)
diff --git a/drivers/scsi/qla2xxx/qla_devtbl.h b/drivers/scsi/qla2xxx/qla_devtbl.h
index dd435410dfa..d78d35e681a 100644
--- a/drivers/scsi/qla2xxx/qla_devtbl.h
+++ b/drivers/scsi/qla2xxx/qla_devtbl.h
@@ -1,4 +1,4 @@
-#define QLA_MODEL_NAMES 0x57
+#define QLA_MODEL_NAMES 0x5C
/*
* Adapter model names and descriptions.
@@ -91,4 +91,9 @@ static char *qla2x00_model_name[QLA_MODEL_NAMES*2] = {
" ", " ", /* 0x154 */
"QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x155 */
"QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x156 */
+ " ", " ", /* 0x157 */
+ " ", " ", /* 0x158 */
+ " ", " ", /* 0x159 */
+ " ", " ", /* 0x15a */
+ "QME2472", "Dell BS PCI-Express to 4Gb FC, Dual Channel", /* 0x15b */
};
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 99fe49618d6..25364b1aaf1 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -779,6 +779,8 @@ struct device_reg_24xx {
#define FA_NVRAM_VPD_SIZE 0x200
#define FA_NVRAM_VPD0_ADDR 0x00
#define FA_NVRAM_VPD1_ADDR 0x100
+
+#define FA_BOOT_CODE_ADDR 0x00000
/*
* RISC code begins at offset 512KB
* within flash. Consisting of two
@@ -940,7 +942,9 @@ struct device_reg_24xx {
uint16_t mailbox31;
uint32_t iobase_window;
- uint32_t unused_4[8]; /* Gap. */
+ uint32_t iobase_c4;
+ uint32_t iobase_c8;
+ uint32_t unused_4_1[6]; /* Gap. */
uint32_t iobase_q;
uint32_t unused_5[2]; /* Gap. */
uint32_t iobase_select;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index aa1e4115228..09cb2a90805 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -134,6 +134,9 @@ extern int
qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
extern int
+qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
+
+extern int
qla2x00_execute_fw(scsi_qla_host_t *, uint32_t);
extern void
@@ -212,8 +215,8 @@ extern int
qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *);
extern int
-qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *, uint16_t *,
- uint16_t *);
+qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *,
+ uint16_t *, uint16_t *, uint16_t *);
extern int
qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
@@ -302,6 +305,8 @@ extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
uint32_t, uint32_t);
extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
uint32_t, uint32_t);
+extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
+ uint32_t, uint32_t);
extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *);
extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index a7e23583f89..eb0784c9ff8 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1517,7 +1517,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
/* Attributes */
ct_req->req.rpa.attrs.count =
- __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT);
+ __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT - 1);
entries = ct_req->req.rpa.port_name;
/* FC4 types. */
@@ -1600,7 +1600,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
/* OS device name. */
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME);
- sprintf(eiter->a.os_dev_name, "/proc/scsi/qla2xxx/%ld", ha->host_no);
+ strcpy(eiter->a.os_dev_name, QLA2XXX_DRIVER_NAME);
alen = strlen(eiter->a.os_dev_name);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
@@ -1611,6 +1611,8 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
/* Hostname. */
if (strlen(fc_host_system_hostname(ha->host))) {
+ ct_req->req.rpa.attrs.count =
+ __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT);
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_HOST_NAME);
snprintf(eiter->a.host_name, sizeof(eiter->a.host_name),
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 1a058ec9bd0..191dafd89be 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -849,7 +849,8 @@ qla2x00_resize_request_q(scsi_qla_host_t *ha)
return;
/* Retrieve IOCB counts available to the firmware. */
- rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt);
+ rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt,
+ &ha->max_npiv_vports);
if (rval)
return;
/* No point in continuing if current settings are sufficient. */
@@ -916,9 +917,15 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
&ha->fw_attributes, &ha->fw_memory_size);
qla2x00_resize_request_q(ha);
ha->flags.npiv_supported = 0;
- if (IS_QLA24XX(ha) &&
- (ha->fw_attributes & BIT_2))
+ if ((IS_QLA24XX(ha) || IS_QLA25XX(ha)) &&
+ (ha->fw_attributes & BIT_2)) {
ha->flags.npiv_supported = 1;
+ if ((!ha->max_npiv_vports) ||
+ ((ha->max_npiv_vports + 1) %
+ MAX_MULTI_ID_FABRIC))
+ ha->max_npiv_vports =
+ MAX_NUM_VPORT_FABRIC;
+ }
if (ql2xallocfwdump)
qla2x00_alloc_fw_dump(ha);
@@ -1155,8 +1162,7 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
- mid_init_cb->count = MAX_NUM_VPORT_FABRIC;
- ha->max_npiv_vports = MAX_NUM_VPORT_FABRIC;
+ mid_init_cb->count = ha->max_npiv_vports;
rval = qla2x00_init_firmware(ha, ha->init_cb_size);
if (rval) {
@@ -1786,12 +1792,11 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
{
fc_port_t *fcport;
- fcport = kmalloc(sizeof(fc_port_t), flags);
- if (fcport == NULL)
- return (fcport);
+ fcport = kzalloc(sizeof(fc_port_t), flags);
+ if (!fcport)
+ return NULL;
/* Setup fcport template structure. */
- memset(fcport, 0, sizeof (fc_port_t));
fcport->ha = ha;
fcport->vp_idx = ha->vp_idx;
fcport->port_type = FCT_UNKNOWN;
@@ -1801,7 +1806,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
fcport->supported_classes = FC_COS_UNSPECIFIED;
spin_lock_init(&fcport->rport_lock);
- return (fcport);
+ return fcport;
}
/*
@@ -2127,15 +2132,9 @@ qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
if (!IS_IIDMA_CAPABLE(ha))
return;
- if (fcport->fp_speed == PORT_SPEED_UNKNOWN) {
- DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- "
- "unsupported FM port operating speed.\n",
- ha->host_no, fcport->port_name[0], fcport->port_name[1],
- fcport->port_name[2], fcport->port_name[3],
- fcport->port_name[4], fcport->port_name[5],
- fcport->port_name[6], fcport->port_name[7]));
+ if (fcport->fp_speed == PORT_SPEED_UNKNOWN ||
+ fcport->fp_speed > ha->link_data_rate)
return;
- }
rval = qla2x00_set_idma_speed(ha, fcport->loop_id, fcport->fp_speed,
mb);
@@ -2473,13 +2472,12 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
rval = QLA_SUCCESS;
/* Try GID_PT to get device list, else GAN. */
- swl = kmalloc(sizeof(sw_info_t) * MAX_FIBRE_DEVICES, GFP_ATOMIC);
- if (swl == NULL) {
+ swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_ATOMIC);
+ if (!swl) {
/*EMPTY*/
DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
"on GA_NXT\n", ha->host_no));
} else {
- memset(swl, 0, sizeof(sw_info_t) * MAX_FIBRE_DEVICES);
if (qla2x00_gid_pt(ha, swl) != QLA_SUCCESS) {
kfree(swl);
swl = NULL;
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 3a5e78cb6b3..024c662ec34 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -308,7 +308,7 @@ qla2x00_start_scsi(srb_t *sp)
handle++;
if (handle == MAX_OUTSTANDING_COMMANDS)
handle = 1;
- if (ha->outstanding_cmds[handle] == 0)
+ if (!ha->outstanding_cmds[handle])
break;
}
if (index == MAX_OUTSTANDING_COMMANDS)
@@ -525,7 +525,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha)
/* Check for pending interrupts. */
/* During init we issue marker directly */
- if (!ha->marker_needed)
+ if (!ha->marker_needed && !ha->flags.init_done)
qla2x00_poll(ha);
spin_lock_irq(&ha->hardware_lock);
@@ -711,7 +711,7 @@ qla24xx_start_scsi(srb_t *sp)
handle++;
if (handle == MAX_OUTSTANDING_COMMANDS)
handle = 1;
- if (ha->outstanding_cmds[handle] == 0)
+ if (!ha->outstanding_cmds[handle])
break;
}
if (index == MAX_OUTSTANDING_COMMANDS)
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index eecae9905ec..1104bd2eed4 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -6,6 +6,7 @@
*/
#include "qla_def.h"
+#include <linux/delay.h>
#include <scsi/scsi_tcq.h>
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
@@ -34,6 +35,7 @@ qla2100_intr_handler(int irq, void *dev_id)
int status;
unsigned long flags;
unsigned long iter;
+ uint16_t hccr;
uint16_t mb[4];
ha = (scsi_qla_host_t *) dev_id;
@@ -48,7 +50,23 @@ qla2100_intr_handler(int irq, void *dev_id)
spin_lock_irqsave(&ha->hardware_lock, flags);
for (iter = 50; iter--; ) {
- if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
+ hccr = RD_REG_WORD(&reg->hccr);
+ if (hccr & HCCR_RISC_PAUSE) {
+ if (pci_channel_offline(ha->pdev))
+ break;
+
+ /*
+ * Issue a "HARD" reset in order for the RISC interrupt
+ * bit to be cleared. Schedule a big hammmer to get
+ * out of the RISC PAUSED state.
+ */
+ WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
+ RD_REG_WORD(&reg->hccr);
+
+ ha->isp_ops->fw_dump(ha, 1);
+ set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+ break;
+ } else if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
break;
if (RD_REG_WORD(&reg->semaphore) & BIT_0) {
@@ -127,6 +145,9 @@ qla2300_intr_handler(int irq, void *dev_id)
for (iter = 50; iter--; ) {
stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
if (stat & HSR_RISC_PAUSED) {
+ if (pci_channel_offline(ha->pdev))
+ break;
+
hccr = RD_REG_WORD(&reg->hccr);
if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
qla_printk(KERN_INFO, ha, "Parity error -- "
@@ -991,8 +1012,14 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
case CS_DATA_UNDERRUN:
resid = resid_len;
/* Use F/W calculated residual length. */
- if (IS_FWI2_CAPABLE(ha))
+ if (IS_FWI2_CAPABLE(ha)) {
+ if (scsi_status & SS_RESIDUAL_UNDER &&
+ resid != fw_resid_len) {
+ scsi_status &= ~SS_RESIDUAL_UNDER;
+ lscsi_status = 0;
+ }
resid = fw_resid_len;
+ }
if (scsi_status & SS_RESIDUAL_UNDER) {
scsi_set_resid(cp, resid);
@@ -1464,6 +1491,52 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha)
WRT_REG_DWORD(&reg->rsp_q_out, ha->rsp_ring_index);
}
+static void
+qla2xxx_check_risc_status(scsi_qla_host_t *ha)
+{
+ int rval;
+ uint32_t cnt;
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+ if (!IS_QLA25XX(ha))
+ return;
+
+ rval = QLA_SUCCESS;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);
+ RD_REG_DWORD(&reg->iobase_addr);
+ WRT_REG_DWORD(&reg->iobase_window, 0x0001);
+ for (cnt = 10000; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
+ rval == QLA_SUCCESS; cnt--) {
+ if (cnt) {
+ WRT_REG_DWORD(&reg->iobase_window, 0x0001);
+ udelay(10);
+ } else
+ rval = QLA_FUNCTION_TIMEOUT;
+ }
+ if (rval == QLA_SUCCESS)
+ goto next_test;
+
+ WRT_REG_DWORD(&reg->iobase_window, 0x0003);
+ for (cnt = 100; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
+ rval == QLA_SUCCESS; cnt--) {
+ if (cnt) {
+ WRT_REG_DWORD(&reg->iobase_window, 0x0003);
+ udelay(10);
+ } else
+ rval = QLA_FUNCTION_TIMEOUT;
+ }
+ if (rval != QLA_SUCCESS)
+ goto done;
+
+next_test:
+ if (RD_REG_DWORD(&reg->iobase_c8) & BIT_3)
+ qla_printk(KERN_INFO, ha, "Additional code -- 0x55AA.\n");
+
+done:
+ WRT_REG_DWORD(&reg->iobase_window, 0x0000);
+ RD_REG_DWORD(&reg->iobase_window);
+}
+
/**
* qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
* @irq:
@@ -1499,10 +1572,16 @@ qla24xx_intr_handler(int irq, void *dev_id)
for (iter = 50; iter--; ) {
stat = RD_REG_DWORD(&reg->host_status);
if (stat & HSRX_RISC_PAUSED) {
+ if (pci_channel_offline(ha->pdev))
+ break;
+
hccr = RD_REG_DWORD(&reg->hccr);
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
"Dumping firmware!\n", hccr);
+
+ qla2xxx_check_risc_status(ha);
+
ha->isp_ops->fw_dump(ha, 1);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
@@ -1606,7 +1685,6 @@ qla24xx_msix_rsp_q(int irq, void *dev_id)
qla24xx_process_response_queue(ha);
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
- RD_REG_DWORD_RELAXED(&reg->hccr);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -1620,7 +1698,6 @@ qla24xx_msix_default(int irq, void *dev_id)
struct device_reg_24xx __iomem *reg;
int status;
unsigned long flags;
- unsigned long iter;
uint32_t stat;
uint32_t hccr;
uint16_t mb[4];
@@ -1630,13 +1707,19 @@ qla24xx_msix_default(int irq, void *dev_id)
status = 0;
spin_lock_irqsave(&ha->hardware_lock, flags);
- for (iter = 50; iter--; ) {
+ do {
stat = RD_REG_DWORD(&reg->host_status);
if (stat & HSRX_RISC_PAUSED) {
+ if (pci_channel_offline(ha->pdev))
+ break;
+
hccr = RD_REG_DWORD(&reg->hccr);
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
"Dumping firmware!\n", hccr);
+
+ qla2xxx_check_risc_status(ha);
+
ha->isp_ops->fw_dump(ha, 1);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
@@ -1669,8 +1752,7 @@ qla24xx_msix_default(int irq, void *dev_id)
break;
}
WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
- RD_REG_DWORD_RELAXED(&reg->hccr);
- }
+ } while (0);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index d3746ec80a8..ccd662a6f5d 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -252,7 +252,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
/* Clean up */
ha->mcp = NULL;
- if (!abort_active) {
+ if (abort_active || !io_lock_on) {
DEBUG11(printk("%s(%ld): checking for additional resp "
"interrupt.\n", __func__, ha->host_no));
@@ -391,7 +391,8 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr)
mcp->mb[1] = MSW(risc_addr);
mcp->mb[2] = LSW(risc_addr);
mcp->mb[3] = 0;
- mcp->out_mb |= MBX_3|MBX_2|MBX_1;
+ mcp->mb[4] = 0;
+ mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1;
mcp->in_mb |= MBX_1;
} else {
mcp->mb[1] = LSW(risc_addr);
@@ -1919,7 +1920,8 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma,
*/
int
qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
- uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt, uint16_t *orig_iocb_cnt)
+ uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt,
+ uint16_t *orig_iocb_cnt, uint16_t *max_npiv_vports)
{
int rval;
mbx_cmd_t mc;
@@ -1929,7 +1931,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
mcp->mb[0] = MBC_GET_RESOURCE_COUNTS;
mcp->out_mb = MBX_0;
- mcp->in_mb = MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
mcp->tov = 30;
mcp->flags = 0;
rval = qla2x00_mailbox_command(ha, mcp);
@@ -1940,9 +1942,9 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
ha->host_no, mcp->mb[0]));
} else {
DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x "
- "mb7=%x mb10=%x.\n", __func__, ha->host_no,
+ "mb7=%x mb10=%x mb11=%x.\n", __func__, ha->host_no,
mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[6], mcp->mb[7],
- mcp->mb[10]));
+ mcp->mb[10], mcp->mb[11]));
if (cur_xchg_cnt)
*cur_xchg_cnt = mcp->mb[3];
@@ -1952,6 +1954,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
*cur_iocb_cnt = mcp->mb[7];
if (orig_iocb_cnt)
*orig_iocb_cnt = mcp->mb[10];
+ if (max_npiv_vports)
+ *max_npiv_vports = mcp->mb[11];
}
return (rval);
@@ -2980,3 +2984,51 @@ qla2x00_send_change_request(scsi_qla_host_t *ha, uint16_t format,
return rval;
}
+
+int
+qla2x00_dump_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t addr,
+ uint32_t size)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ if (MSW(addr) || IS_FWI2_CAPABLE(ha)) {
+ mcp->mb[0] = MBC_DUMP_RISC_RAM_EXTENDED;
+ mcp->mb[8] = MSW(addr);
+ mcp->out_mb = MBX_8|MBX_0;
+ } else {
+ mcp->mb[0] = MBC_DUMP_RISC_RAM;
+ mcp->out_mb = MBX_0;
+ }
+ mcp->mb[1] = LSW(addr);
+ mcp->mb[2] = MSW(req_dma);
+ mcp->mb[3] = LSW(req_dma);
+ mcp->mb[6] = MSW(MSD(req_dma));
+ mcp->mb[7] = LSW(MSD(req_dma));
+ mcp->out_mb |= MBX_7|MBX_6|MBX_3|MBX_2|MBX_1;
+ if (IS_FWI2_CAPABLE(ha)) {
+ mcp->mb[4] = MSW(size);
+ mcp->mb[5] = LSW(size);
+ mcp->out_mb |= MBX_5|MBX_4;
+ } else {
+ mcp->mb[4] = LSW(size);
+ mcp->out_mb |= MBX_4;
+ }
+
+ mcp->in_mb = MBX_0;
+ mcp->tov = 30;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
+ ha->host_no, rval, mcp->mb[0]));
+ } else {
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+ }
+
+ return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 54dc415d8b5..821ee74aadc 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -104,7 +104,7 @@ qla24xx_find_vhost_by_name(scsi_qla_host_t *ha, uint8_t *port_name)
*
* Context:
*/
-void
+static void
qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
{
fc_port_t *fcport;
@@ -179,37 +179,7 @@ enable_failed:
return 1;
}
-/**
- * qla24xx_modify_vport() - Modifies the virtual fabric port's configuration
- * @ha: HA context
- * @vp: pointer to buffer of virtual port parameters.
- * @ret_code: return error code:
- *
- * Returns the virtual port id, or MAX_VSAN_ID, if couldn't create.
- */
-uint32_t
-qla24xx_modify_vhba(scsi_qla_host_t *ha, vport_params_t *vp, uint32_t *vp_id)
-{
- scsi_qla_host_t *vha;
-
- vha = qla24xx_find_vhost_by_name(ha, vp->port_name);
- if (!vha) {
- *vp_id = MAX_NUM_VPORT_LOOP;
- return VP_RET_CODE_WWPN;
- }
-
- if (qla24xx_enable_vp(vha)) {
- scsi_host_put(vha->host);
- qla2x00_mem_free(vha);
- *vp_id = MAX_NUM_VPORT_LOOP;
- return VP_RET_CODE_RESOURCES;
- }
-
- *vp_id = vha->vp_idx;
- return VP_RET_CODE_OK;
-}
-
-void
+static void
qla24xx_configure_vp(scsi_qla_host_t *vha)
{
struct fc_vport *fc_vport;
@@ -363,7 +333,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *ha)
int
qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
{
- scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
scsi_qla_host_t *vha;
uint8_t port_name[WWN_SIZE];
@@ -397,7 +367,7 @@ qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
scsi_qla_host_t *
qla24xx_create_vhost(struct fc_vport *fc_vport)
{
- scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
scsi_qla_host_t *vha;
struct Scsi_Host *host;
@@ -409,7 +379,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
return(NULL);
}
- vha = (scsi_qla_host_t *)host->hostdata;
+ vha = shost_priv(host);
/* clone the parent hba */
memcpy(vha, ha, sizeof (scsi_qla_host_t));
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index acca898ce0a..a5bcf1f390b 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -132,6 +132,7 @@ struct scsi_host_template qla2x00_driver_template = {
.this_id = -1,
.cmd_per_lun = 3,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.sg_tablesize = SG_ALL,
/*
@@ -163,6 +164,7 @@ struct scsi_host_template qla24xx_driver_template = {
.this_id = -1,
.cmd_per_lun = 3,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.sg_tablesize = SG_ALL,
.max_sectors = 0xFFFF,
@@ -379,12 +381,17 @@ qla2x00_get_new_sp(scsi_qla_host_t *ha, fc_port_t *fcport,
static int
qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
- scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
srb_t *sp;
int rval;
+ if (unlikely(pci_channel_offline(ha->pdev))) {
+ cmd->result = DID_REQUEUE << 16;
+ goto qc_fail_command;
+ }
+
rval = fc_remote_port_chkready(rport);
if (rval) {
cmd->result = rval;
@@ -440,13 +447,18 @@ qc_fail_command:
static int
qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
- scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
srb_t *sp;
int rval;
scsi_qla_host_t *pha = to_qla_parent(ha);
+ if (unlikely(pci_channel_offline(ha->pdev))) {
+ cmd->result = DID_REQUEUE << 16;
+ goto qc24_fail_command;
+ }
+
rval = fc_remote_port_chkready(rport);
if (rval) {
cmd->result = rval;
@@ -653,7 +665,7 @@ qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
static int
qla2xxx_eh_abort(struct scsi_cmnd *cmd)
{
- scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
srb_t *sp;
int ret, i;
unsigned int id, lun;
@@ -793,7 +805,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
static int
qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
{
- scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
int ret = FAILED;
unsigned int id, lun;
@@ -922,7 +934,7 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
static int
qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
{
- scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
scsi_qla_host_t *pha = to_qla_parent(ha);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
int ret = FAILED;
@@ -982,7 +994,7 @@ eh_bus_reset_done:
static int
qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
{
- scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
int ret = FAILED;
unsigned int id, lun;
@@ -1132,7 +1144,7 @@ qla2xxx_slave_alloc(struct scsi_device *sdev)
static int
qla2xxx_slave_configure(struct scsi_device *sdev)
{
- scsi_qla_host_t *ha = to_qla_host(sdev->host);
+ scsi_qla_host_t *ha = shost_priv(sdev->host);
struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
if (sdev->tagged_supported)
@@ -1384,7 +1396,7 @@ static struct isp_operations qla25xx_isp_ops = {
.beacon_on = qla24xx_beacon_on,
.beacon_off = qla24xx_beacon_off,
.beacon_blink = qla24xx_beacon_blink,
- .read_optrom = qla24xx_read_optrom_data,
+ .read_optrom = qla25xx_read_optrom_data,
.write_optrom = qla24xx_write_optrom_data,
.get_flash_version = qla24xx_get_flash_version,
};
@@ -1470,6 +1482,17 @@ qla2x00_iospace_config(scsi_qla_host_t *ha)
unsigned long pio, pio_len, pio_flags;
unsigned long mmio, mmio_len, mmio_flags;
+ if (pci_request_selected_regions(ha->pdev, ha->bars,
+ QLA2XXX_DRIVER_NAME)) {
+ qla_printk(KERN_WARNING, ha,
+ "Failed to reserve PIO/MMIO regions (%s)\n",
+ pci_name(ha->pdev));
+
+ goto iospace_error_exit;
+ }
+ if (!(ha->bars & 1))
+ goto skip_pio;
+
/* We only need PIO for Flash operations on ISP2312 v2 chips. */
pio = pci_resource_start(ha->pdev, 0);
pio_len = pci_resource_len(ha->pdev, 0);
@@ -1487,7 +1510,10 @@ qla2x00_iospace_config(scsi_qla_host_t *ha)
pci_name(ha->pdev));
pio = 0;
}
+ ha->pio_address = pio;
+ ha->pio_length = pio_len;
+skip_pio:
/* Use MMIO operations for all accesses. */
mmio = pci_resource_start(ha->pdev, 1);
mmio_len = pci_resource_len(ha->pdev, 1);
@@ -1506,16 +1532,6 @@ qla2x00_iospace_config(scsi_qla_host_t *ha)
goto iospace_error_exit;
}
- if (pci_request_regions(ha->pdev, QLA2XXX_DRIVER_NAME)) {
- qla_printk(KERN_WARNING, ha,
- "Failed to reserve PIO/MMIO regions (%s)\n",
- pci_name(ha->pdev));
-
- goto iospace_error_exit;
- }
-
- ha->pio_address = pio;
- ha->pio_length = pio_len;
ha->iobase = ioremap(mmio, MIN_IOBASE_LEN);
if (!ha->iobase) {
qla_printk(KERN_ERR, ha,
@@ -1533,7 +1549,7 @@ iospace_error_exit:
static void
qla2xxx_scan_start(struct Scsi_Host *shost)
{
- scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+ scsi_qla_host_t *ha = shost_priv(shost);
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
@@ -1543,7 +1559,7 @@ qla2xxx_scan_start(struct Scsi_Host *shost)
static int
qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
{
- scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
+ scsi_qla_host_t *ha = shost_priv(shost);
if (!ha->host)
return 1;
@@ -1567,17 +1583,26 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
char pci_info[30];
char fw_str[30];
struct scsi_host_template *sht;
+ int bars;
- if (pci_enable_device(pdev))
- goto probe_out;
-
+ bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO);
sht = &qla2x00_driver_template;
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 ||
- pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532)
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) {
+ bars = pci_select_bars(pdev, IORESOURCE_MEM);
sht = &qla24xx_driver_template;
+ }
+
+ if (pci_enable_device_bars(pdev, bars))
+ goto probe_out;
+
+ if (pci_find_aer_capability(pdev))
+ if (pci_enable_pcie_error_reporting(pdev))
+ goto probe_out;
+
host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t));
if (host == NULL) {
printk(KERN_WARNING
@@ -1586,7 +1611,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* Clear our data area */
- ha = (scsi_qla_host_t *)host->hostdata;
+ ha = shost_priv(host);
memset(ha, 0, sizeof(scsi_qla_host_t));
ha->pdev = pdev;
@@ -1594,6 +1619,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->host_no = host->host_no;
sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no);
ha->parent = NULL;
+ ha->bars = bars;
/* Set ISP-type information. */
qla2x00_set_isp_flags(ha);
@@ -1864,7 +1890,7 @@ qla2x00_free_device(scsi_qla_host_t *ha)
/* release io space registers */
if (ha->iobase)
iounmap(ha->iobase);
- pci_release_regions(ha->pdev);
+ pci_release_selected_regions(ha->pdev, ha->bars);
}
static inline void
@@ -2423,7 +2449,6 @@ qla2x00_do_dpc(void *data)
if (atomic_read(&fcport->state) != FCS_ONLINE &&
fcport->login_retry) {
- fcport->login_retry--;
if (fcport->flags & FCF_FABRIC_DEVICE) {
if (fcport->flags &
FCF_TAPE_PRESENT)
@@ -2439,6 +2464,7 @@ qla2x00_do_dpc(void *data)
qla2x00_local_device_login(
ha, fcport);
+ fcport->login_retry--;
if (status == QLA_SUCCESS) {
fcport->old_loop_id = fcport->loop_id;
@@ -2456,6 +2482,8 @@ qla2x00_do_dpc(void *data)
} else {
fcport->login_retry = 0;
}
+ if (fcport->login_retry == 0)
+ fcport->loop_id = FC_NO_LOOP_ID;
}
if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
break;
@@ -2814,6 +2842,105 @@ qla2x00_release_firmware(void)
up(&qla_fw_lock);
}
+static pci_ers_result_t
+qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+ switch (state) {
+ case pci_channel_io_normal:
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ case pci_channel_io_frozen:
+ pci_disable_device(pdev);
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ qla2x00_remove_one(pdev);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t
+qla2xxx_pci_mmio_enabled(struct pci_dev *pdev)
+{
+ int risc_paused = 0;
+ uint32_t stat;
+ unsigned long flags;
+ scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+ struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+ struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ if (IS_QLA2100(ha) || IS_QLA2200(ha)){
+ stat = RD_REG_DWORD(&reg->hccr);
+ if (stat & HCCR_RISC_PAUSE)
+ risc_paused = 1;
+ } else if (IS_QLA23XX(ha)) {
+ stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
+ if (stat & HSR_RISC_PAUSED)
+ risc_paused = 1;
+ } else if (IS_FWI2_CAPABLE(ha)) {
+ stat = RD_REG_DWORD(&reg24->host_status);
+ if (stat & HSRX_RISC_PAUSED)
+ risc_paused = 1;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if (risc_paused) {
+ qla_printk(KERN_INFO, ha, "RISC paused -- mmio_enabled, "
+ "Dumping firmware!\n");
+ ha->isp_ops->fw_dump(ha, 0);
+
+ return PCI_ERS_RESULT_NEED_RESET;
+ } else
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+static pci_ers_result_t
+qla2xxx_pci_slot_reset(struct pci_dev *pdev)
+{
+ pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT;
+ scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+
+ if (pci_enable_device_bars(pdev, ha->bars)) {
+ qla_printk(KERN_WARNING, ha,
+ "Can't re-enable PCI device after reset.\n");
+
+ return ret;
+ }
+ pci_set_master(pdev);
+
+ if (ha->isp_ops->pci_config(ha))
+ return ret;
+
+ set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+ if (qla2x00_abort_isp(ha)== QLA_SUCCESS)
+ ret = PCI_ERS_RESULT_RECOVERED;
+ clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+
+ return ret;
+}
+
+static void
+qla2xxx_pci_resume(struct pci_dev *pdev)
+{
+ scsi_qla_host_t *ha = pci_get_drvdata(pdev);
+ int ret;
+
+ ret = qla2x00_wait_for_hba_online(ha);
+ if (ret != QLA_SUCCESS) {
+ qla_printk(KERN_ERR, ha,
+ "the device failed to resume I/O "
+ "from slot/link_reset");
+ }
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+}
+
+static struct pci_error_handlers qla2xxx_err_handler = {
+ .error_detected = qla2xxx_pci_error_detected,
+ .mmio_enabled = qla2xxx_pci_mmio_enabled,
+ .slot_reset = qla2xxx_pci_slot_reset,
+ .resume = qla2xxx_pci_resume,
+};
+
static struct pci_device_id qla2xxx_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) },
@@ -2839,6 +2966,7 @@ static struct pci_driver qla2xxx_pci_driver = {
.id_table = qla2xxx_pci_tbl,
.probe = qla2x00_probe_one,
.remove = __devexit_p(qla2x00_remove_one),
+ .err_handler = &qla2xxx_err_handler,
};
/**
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index a925a3f179f..ad2fa01bd23 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -7,6 +7,7 @@
#include "qla_def.h"
#include <linux/delay.h>
+#include <linux/vmalloc.h>
#include <asm/uaccess.h>
static uint16_t qla2x00_nvram_request(scsi_qla_host_t *, uint32_t);
@@ -425,6 +426,9 @@ qla2x00_set_nvram_protection(scsi_qla_host_t *ha, int stat)
/* Flash Manipulation Routines */
/*****************************************************************************/
+#define OPTROM_BURST_SIZE 0x1000
+#define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4)
+
static inline uint32_t
flash_conf_to_access_addr(uint32_t faddr)
{
@@ -544,41 +548,59 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
uint32_t dwords)
{
int ret;
- uint32_t liter;
- uint32_t sec_mask, rest_addr, conf_addr, sec_end_mask;
+ uint32_t liter, miter;
+ uint32_t sec_mask, rest_addr, conf_addr;
uint32_t fdata, findex ;
uint8_t man_id, flash_id;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ dma_addr_t optrom_dma;
+ void *optrom = NULL;
+ uint32_t *s, *d;
ret = QLA_SUCCESS;
+ /* Prepare burst-capable write on supported ISPs. */
+ if (IS_QLA25XX(ha) && !(faddr & 0xfff) &&
+ dwords > OPTROM_BURST_DWORDS) {
+ optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+ &optrom_dma, GFP_KERNEL);
+ if (!optrom) {
+ qla_printk(KERN_DEBUG, ha,
+ "Unable to allocate memory for optrom burst write "
+ "(%x KB).\n", OPTROM_BURST_SIZE / 1024);
+ }
+ }
+
qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);
DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__,
ha->host_no, man_id, flash_id));
- sec_end_mask = 0;
conf_addr = flash_conf_to_access_addr(0x03d8);
switch (man_id) {
case 0xbf: /* STT flash. */
- rest_addr = 0x1fff;
- sec_mask = 0x3e000;
+ if (flash_id == 0x8e) {
+ rest_addr = 0x3fff;
+ sec_mask = 0x7c000;
+ } else {
+ rest_addr = 0x1fff;
+ sec_mask = 0x7e000;
+ }
if (flash_id == 0x80)
conf_addr = flash_conf_to_access_addr(0x0352);
break;
case 0x13: /* ST M25P80. */
rest_addr = 0x3fff;
- sec_mask = 0x3c000;
+ sec_mask = 0x7c000;
break;
case 0x1f: // Atmel 26DF081A
- rest_addr = 0x0fff;
- sec_mask = 0xff000;
- sec_end_mask = 0x003ff;
+ rest_addr = 0x3fff;
+ sec_mask = 0x7c000;
conf_addr = flash_conf_to_access_addr(0x0320);
break;
default:
/* Default to 64 kb sector size. */
rest_addr = 0x3fff;
- sec_mask = 0x3c000;
+ sec_mask = 0x7c000;
break;
}
@@ -592,56 +614,81 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
/* Some flash parts need an additional zero-write to clear bits.*/
qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);
- do { /* Loop once to provide quick error exit. */
- for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
- if (man_id == 0x1f) {
- findex = faddr << 2;
- fdata = findex & sec_mask;
- } else {
- findex = faddr;
- fdata = (findex & sec_mask) << 2;
- }
+ for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
+ if (man_id == 0x1f) {
+ findex = faddr << 2;
+ fdata = findex & sec_mask;
+ } else {
+ findex = faddr;
+ fdata = (findex & sec_mask) << 2;
+ }
- /* Are we at the beginning of a sector? */
- if ((findex & rest_addr) == 0) {
- /*
- * Do sector unprotect at 4K boundry for Atmel
- * part.
- */
- if (man_id == 0x1f)
- qla24xx_write_flash_dword(ha,
- flash_conf_to_access_addr(0x0339),
- (fdata & 0xff00) | ((fdata << 16) &
- 0xff0000) | ((fdata >> 16) & 0xff));
- ret = qla24xx_write_flash_dword(ha, conf_addr,
- (fdata & 0xff00) |((fdata << 16) &
+ /* Are we at the beginning of a sector? */
+ if ((findex & rest_addr) == 0) {
+ /* Do sector unprotect at 4K boundry for Atmel part. */
+ if (man_id == 0x1f)
+ qla24xx_write_flash_dword(ha,
+ flash_conf_to_access_addr(0x0339),
+ (fdata & 0xff00) | ((fdata << 16) &
0xff0000) | ((fdata >> 16) & 0xff));
- if (ret != QLA_SUCCESS) {
- DEBUG9(printk("%s(%ld) Unable to flash "
- "sector: address=%x.\n", __func__,
- ha->host_no, faddr));
- break;
- }
+ ret = qla24xx_write_flash_dword(ha, conf_addr,
+ (fdata & 0xff00) |((fdata << 16) &
+ 0xff0000) | ((fdata >> 16) & 0xff));
+ if (ret != QLA_SUCCESS) {
+ DEBUG9(printk("%s(%ld) Unable to flash "
+ "sector: address=%x.\n", __func__,
+ ha->host_no, faddr));
+ break;
}
- ret = qla24xx_write_flash_dword(ha,
+ }
+
+ /* Go with burst-write. */
+ if (optrom && (liter + OPTROM_BURST_DWORDS) <= dwords) {
+ /* Copy data to DMA'ble buffer. */
+ for (miter = 0, s = optrom, d = dwptr;
+ miter < OPTROM_BURST_DWORDS; miter++, s++, d++)
+ *s = cpu_to_le32(*d);
+
+ ret = qla2x00_load_ram(ha, optrom_dma,
flash_data_to_access_addr(faddr),
- cpu_to_le32(*dwptr));
+ OPTROM_BURST_DWORDS);
if (ret != QLA_SUCCESS) {
- DEBUG9(printk("%s(%ld) Unable to program flash "
- "address=%x data=%x.\n", __func__,
- ha->host_no, faddr, *dwptr));
- break;
+ qla_printk(KERN_WARNING, ha,
+ "Unable to burst-write optrom segment "
+ "(%x/%x/%llx).\n", ret,
+ flash_data_to_access_addr(faddr),
+ (unsigned long long)optrom_dma);
+ qla_printk(KERN_WARNING, ha,
+ "Reverting to slow-write.\n");
+
+ dma_free_coherent(&ha->pdev->dev,
+ OPTROM_BURST_SIZE, optrom, optrom_dma);
+ optrom = NULL;
+ } else {
+ liter += OPTROM_BURST_DWORDS - 1;
+ faddr += OPTROM_BURST_DWORDS - 1;
+ dwptr += OPTROM_BURST_DWORDS - 1;
+ continue;
}
+ }
- /* Do sector protect at 4K boundry for Atmel part. */
- if (man_id == 0x1f &&
- ((faddr & sec_end_mask) == 0x3ff))
- qla24xx_write_flash_dword(ha,
- flash_conf_to_access_addr(0x0336),
- (fdata & 0xff00) | ((fdata << 16) &
- 0xff0000) | ((fdata >> 16) & 0xff));
+ ret = qla24xx_write_flash_dword(ha,
+ flash_data_to_access_addr(faddr), cpu_to_le32(*dwptr));
+ if (ret != QLA_SUCCESS) {
+ DEBUG9(printk("%s(%ld) Unable to program flash "
+ "address=%x data=%x.\n", __func__,
+ ha->host_no, faddr, *dwptr));
+ break;
}
- } while (0);
+
+ /* Do sector protect at 4K boundry for Atmel part. */
+ if (man_id == 0x1f &&
+ ((faddr & rest_addr) == rest_addr))
+ qla24xx_write_flash_dword(ha,
+ flash_conf_to_access_addr(0x0336),
+ (fdata & 0xff00) | ((fdata << 16) &
+ 0xff0000) | ((fdata >> 16) & 0xff));
+ }
/* Enable flash write-protection. */
qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c);
@@ -651,6 +698,10 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr,
RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */
+ if (optrom)
+ dma_free_coherent(&ha->pdev->dev,
+ OPTROM_BURST_SIZE, optrom, optrom_dma);
+
return ret;
}
@@ -695,9 +746,11 @@ qla2x00_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
int ret, stat;
uint32_t i;
uint16_t *wptr;
+ unsigned long flags;
ret = QLA_SUCCESS;
+ spin_lock_irqsave(&ha->hardware_lock, flags);
qla2x00_lock_nvram_access(ha);
/* Disable NVRAM write-protection. */
@@ -714,6 +767,7 @@ qla2x00_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
qla2x00_set_nvram_protection(ha, stat);
qla2x00_unlock_nvram_access(ha);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
return ret;
}
@@ -726,9 +780,11 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
uint32_t i;
uint32_t *dwptr;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ unsigned long flags;
ret = QLA_SUCCESS;
+ spin_lock_irqsave(&ha->hardware_lock, flags);
/* Enable flash write. */
WRT_REG_DWORD(&reg->ctrl_status,
RD_REG_DWORD(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
@@ -762,6 +818,7 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
WRT_REG_DWORD(&reg->ctrl_status,
RD_REG_DWORD(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
return ret;
}
@@ -786,8 +843,20 @@ int
qla25xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
uint32_t bytes)
{
- return qla24xx_write_flash_data(ha, (uint32_t *)buf,
- FA_VPD_NVRAM_ADDR | naddr, bytes >> 2);
+#define RMW_BUFFER_SIZE (64 * 1024)
+ uint8_t *dbuf;
+
+ dbuf = vmalloc(RMW_BUFFER_SIZE);
+ if (!dbuf)
+ return QLA_MEMORY_ALLOC_FAILED;
+ ha->isp_ops->read_optrom(ha, dbuf, FA_VPD_NVRAM_ADDR << 2,
+ RMW_BUFFER_SIZE);
+ memcpy(dbuf + (naddr << 2), buf, bytes);
+ ha->isp_ops->write_optrom(ha, dbuf, FA_VPD_NVRAM_ADDR << 2,
+ RMW_BUFFER_SIZE);
+ vfree(dbuf);
+
+ return QLA_SUCCESS;
}
static inline void
@@ -1728,7 +1797,6 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
{
/* Suspend HBA. */
scsi_block_requests(ha->host);
- ha->isp_ops->disable_intrs(ha);
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
/* Go with read. */
@@ -1736,7 +1804,6 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
/* Resume HBA. */
clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
- ha->isp_ops->enable_intrs(ha);
scsi_unblock_requests(ha->host);
return buf;
@@ -1750,7 +1817,6 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
/* Suspend HBA. */
scsi_block_requests(ha->host);
- ha->isp_ops->disable_intrs(ha);
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
/* Go with write. */
@@ -1767,6 +1833,71 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
return rval;
}
+uint8_t *
+qla25xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
+ uint32_t offset, uint32_t length)
+{
+ int rval;
+ dma_addr_t optrom_dma;
+ void *optrom;
+ uint8_t *pbuf;
+ uint32_t faddr, left, burst;
+
+ if (offset & 0xfff)
+ goto slow_read;
+ if (length < OPTROM_BURST_SIZE)
+ goto slow_read;
+
+ optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+ &optrom_dma, GFP_KERNEL);
+ if (!optrom) {
+ qla_printk(KERN_DEBUG, ha,
+ "Unable to allocate memory for optrom burst read "
+ "(%x KB).\n", OPTROM_BURST_SIZE / 1024);
+
+ goto slow_read;
+ }
+
+ pbuf = buf;
+ faddr = offset >> 2;
+ left = length >> 2;
+ burst = OPTROM_BURST_DWORDS;
+ while (left != 0) {
+ if (burst > left)
+ burst = left;
+
+ rval = qla2x00_dump_ram(ha, optrom_dma,
+ flash_data_to_access_addr(faddr), burst);
+ if (rval) {
+ qla_printk(KERN_WARNING, ha,
+ "Unable to burst-read optrom segment "
+ "(%x/%x/%llx).\n", rval,
+ flash_data_to_access_addr(faddr),
+ (unsigned long long)optrom_dma);
+ qla_printk(KERN_WARNING, ha,
+ "Reverting to slow-read.\n");
+
+ dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
+ optrom, optrom_dma);
+ goto slow_read;
+ }
+
+ memcpy(pbuf, optrom, burst * 4);
+
+ left -= burst;
+ faddr += burst;
+ pbuf += burst * 4;
+ }
+
+ dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
+ optrom_dma);
+
+ return buf;
+
+slow_read:
+ return qla24xx_read_optrom_data(ha, buf, offset, length);
+}
+
/**
* qla2x00_get_fcode_version() - Determine an FCODE image's version.
* @ha: HA context
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 18095b9b76f..ae6f7a2fb19 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.02.00-k3"
+#define QLA2XXX_VERSION "8.02.00-k5"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 2
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index 9bb3d1d2a92..fe415ec8565 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -671,7 +671,7 @@ struct continuation_t1_entry {
#define ET_CONTINUE ET_CONT_T1
/* Marker entry structure*/
-struct marker_entry {
+struct qla4_marker_entry {
struct qla4_header hdr; /* 00-03 */
uint32_t system_defined; /* 04-07 */
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 1e29f51d596..d692c713416 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -1006,7 +1006,7 @@ int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a)
* qla4xxx_start_firmware - starts qla4xxx firmware
* @ha: Pointer to host adapter structure.
*
- * This routine performs the neccessary steps to start the firmware for
+ * This routine performs the necessary steps to start the firmware for
* the QLA4010 adapter.
**/
static int qla4xxx_start_firmware(struct scsi_qla_host *ha)
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index 5006ecb3ef5..e4461b5d767 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -69,7 +69,7 @@ static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
static int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
struct ddb_entry *ddb_entry, int lun)
{
- struct marker_entry *marker_entry;
+ struct qla4_marker_entry *marker_entry;
unsigned long flags = 0;
uint8_t status = QLA_SUCCESS;
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index b1d565c12c5..89460d27c68 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -94,6 +94,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
.this_id = -1,
.cmd_per_lun = 3,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.sg_tablesize = SG_ALL,
.max_sectors = 0xFFFF,
@@ -1285,7 +1286,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
ret = scsi_init_shared_tag_map(host, MAX_SRBS);
if (ret) {
- dev_warn(&ha->pdev->dev, "scsi_init_shared_tag_map failed");
+ dev_warn(&ha->pdev->dev, "scsi_init_shared_tag_map failed\n");
goto probe_failed;
}
diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
index 94baca840ef..1769f965eed 100644
--- a/drivers/scsi/qlogicfas.c
+++ b/drivers/scsi/qlogicfas.c
@@ -166,6 +166,7 @@ static int qlogicfas_release(struct Scsi_Host *shost)
{
struct qlogicfas408_priv *priv = get_priv_by_host(shost);
+ scsi_remove_host(shost);
if (shost->irq) {
qlogicfas408_disable_ints(priv);
free_irq(shost->irq, shost);
@@ -174,7 +175,6 @@ static int qlogicfas_release(struct Scsi_Host *shost)
free_dma(shost->dma_channel);
if (shost->io_port && shost->n_io_port)
release_region(shost->io_port, shost->n_io_port);
- scsi_remove_host(shost);
scsi_host_put(shost);
return 0;
@@ -197,6 +197,7 @@ static struct scsi_host_template qlogicfas_driver_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = DISABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
static __init int qlogicfas_init(void)
diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c
index 2bfbf26c00e..de7b3bc2cbc 100644
--- a/drivers/scsi/qlogicfas408.c
+++ b/drivers/scsi/qlogicfas408.c
@@ -317,7 +317,7 @@ static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
return ((priv->qabort == 1 ?
DID_ABORT : DID_RESET) << 16);
}
- buf = page_address(sg->page) + sg->offset;
+ buf = sg_virt(sg);
if (ql_pdma(priv, phase, buf, sg->length))
break;
}
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 594887205b0..7a2e7986b03 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -310,8 +310,6 @@ static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti)
}
qpti->dev_param[i].device_enable = 1;
}
- /* this is very important to set! */
- qpti->sbits = 1 << qpti->scsi_id;
}
static int qlogicpti_reset_hardware(struct Scsi_Host *host)
@@ -870,7 +868,7 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
struct qlogicpti *qpti, u_int in_ptr, u_int out_ptr)
{
struct dataseg *ds;
- struct scatterlist *sg;
+ struct scatterlist *sg, *s;
int i, n;
if (Cmnd->use_sg) {
@@ -886,11 +884,12 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
n = sg_count;
if (n > 4)
n = 4;
- for (i = 0; i < n; i++, sg++) {
- ds[i].d_base = sg_dma_address(sg);
- ds[i].d_count = sg_dma_len(sg);
+ for_each_sg(sg, s, n, i) {
+ ds[i].d_base = sg_dma_address(s);
+ ds[i].d_count = sg_dma_len(s);
}
sg_count -= 4;
+ sg = s;
while (sg_count > 0) {
struct Continuation_Entry *cont;
@@ -909,9 +908,9 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
n = sg_count;
if (n > 7)
n = 7;
- for (i = 0; i < n; i++, sg++) {
- ds[i].d_base = sg_dma_address(sg);
- ds[i].d_count = sg_dma_len(sg);
+ for_each_sg(sg, s, n, i) {
+ ds[i].d_base = sg_dma_address(s);
+ ds[i].d_count = sg_dma_len(s);
}
sg_count -= n;
}
@@ -951,153 +950,35 @@ static inline void update_can_queue(struct Scsi_Host *host, u_int in_ptr, u_int
host->sg_tablesize = QLOGICPTI_MAX_SG(num_free);
}
-static unsigned int scsi_rbuf_get(struct scsi_cmnd *cmd, unsigned char **buf_out)
+static int qlogicpti_slave_configure(struct scsi_device *sdev)
{
- unsigned char *buf;
- unsigned int buflen;
-
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ struct qlogicpti *qpti = shost_priv(sdev->host);
+ int tgt = sdev->id;
+ u_short param[6];
- sg = (struct scatterlist *) cmd->request_buffer;
- buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- buflen = sg->length;
+ /* tags handled in midlayer */
+ /* enable sync mode? */
+ if (sdev->sdtr) {
+ qpti->dev_param[tgt].device_flags |= 0x10;
} else {
- buf = cmd->request_buffer;
- buflen = cmd->request_bufflen;
+ qpti->dev_param[tgt].synchronous_offset = 0;
+ qpti->dev_param[tgt].synchronous_period = 0;
}
-
- *buf_out = buf;
- return buflen;
-}
-
-static void scsi_rbuf_put(struct scsi_cmnd *cmd, unsigned char *buf)
-{
- if (cmd->use_sg) {
- struct scatterlist *sg;
-
- sg = (struct scatterlist *) cmd->request_buffer;
- kunmap_atomic(buf - sg->offset, KM_IRQ0);
- }
-}
-
-/*
- * Until we scan the entire bus with inquiries, go throught this fella...
- */
-static void ourdone(struct scsi_cmnd *Cmnd)
-{
- struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->device->host->hostdata;
- int tgt = Cmnd->device->id;
- void (*done) (struct scsi_cmnd *);
-
- /* This grot added by DaveM, blame him for ugliness.
- * The issue is that in the 2.3.x driver we use the
- * host_scribble portion of the scsi command as a
- * completion linked list at interrupt service time,
- * so we have to store the done function pointer elsewhere.
- */
- done = (void (*)(struct scsi_cmnd *))
- (((unsigned long) Cmnd->SCp.Message)
-#ifdef __sparc_v9__
- | ((unsigned long) Cmnd->SCp.Status << 32UL)
-#endif
- );
-
- if ((qpti->sbits & (1 << tgt)) == 0) {
- int ok = host_byte(Cmnd->result) == DID_OK;
- if (Cmnd->cmnd[0] == 0x12 && ok) {
- unsigned char *iqd;
- unsigned int iqd_len;
-
- iqd_len = scsi_rbuf_get(Cmnd, &iqd);
-
- /* tags handled in midlayer */
- /* enable sync mode? */
- if (iqd[7] & 0x10) {
- qpti->dev_param[tgt].device_flags |= 0x10;
- } else {
- qpti->dev_param[tgt].synchronous_offset = 0;
- qpti->dev_param[tgt].synchronous_period = 0;
- }
- /* are we wide capable? */
- if (iqd[7] & 0x20) {
- qpti->dev_param[tgt].device_flags |= 0x20;
- }
-
- scsi_rbuf_put(Cmnd, iqd);
-
- qpti->sbits |= (1 << tgt);
- } else if (!ok) {
- qpti->sbits |= (1 << tgt);
- }
- }
- done(Cmnd);
-}
-
-static int qlogicpti_queuecommand(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *));
-
-static int qlogicpti_queuecommand_slow(struct scsi_cmnd *Cmnd,
- void (*done)(struct scsi_cmnd *))
-{
- struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->device->host->hostdata;
-
- /*
- * done checking this host adapter?
- * If not, then rewrite the command
- * to finish through ourdone so we
- * can peek at Inquiry data results.
- */
- if (qpti->sbits && qpti->sbits != 0xffff) {
- /* See above about in ourdone this ugliness... */
- Cmnd->SCp.Message = ((unsigned long)done) & 0xffffffff;
-#ifdef CONFIG_SPARC64
- Cmnd->SCp.Status = ((unsigned long)done >> 32UL) & 0xffffffff;
-#endif
- return qlogicpti_queuecommand(Cmnd, ourdone);
- }
-
- /*
- * We've peeked at all targets for this bus- time
- * to set parameters for devices for real now.
- */
- if (qpti->sbits == 0xffff) {
- int i;
- for(i = 0; i < MAX_TARGETS; i++) {
- u_short param[6];
- param[0] = MBOX_SET_TARGET_PARAMS;
- param[1] = (i << 8);
- param[2] = (qpti->dev_param[i].device_flags << 8);
- if (qpti->dev_param[i].device_flags & 0x10) {
- param[3] = (qpti->dev_param[i].synchronous_offset << 8) |
- qpti->dev_param[i].synchronous_period;
- } else {
- param[3] = 0;
- }
- (void) qlogicpti_mbox_command(qpti, param, 0);
- }
- /*
- * set to zero so any traverse through ourdone
- * doesn't start the whole process again,
- */
- qpti->sbits = 0;
- }
-
- /* check to see if we're done with all adapters... */
- for (qpti = qptichain; qpti != NULL; qpti = qpti->next) {
- if (qpti->sbits) {
- break;
- }
+ /* are we wide capable? */
+ if (sdev->wdtr)
+ qpti->dev_param[tgt].device_flags |= 0x20;
+
+ param[0] = MBOX_SET_TARGET_PARAMS;
+ param[1] = (tgt << 8);
+ param[2] = (qpti->dev_param[tgt].device_flags << 8);
+ if (qpti->dev_param[tgt].device_flags & 0x10) {
+ param[3] = (qpti->dev_param[tgt].synchronous_offset << 8) |
+ qpti->dev_param[tgt].synchronous_period;
+ } else {
+ param[3] = 0;
}
-
- /*
- * if we hit the end of the chain w/o finding adapters still
- * capability-configuring, then we're done with all adapters
- * and can rock on..
- */
- if (qpti == NULL)
- Cmnd->device->host->hostt->queuecommand = qlogicpti_queuecommand;
-
- return qlogicpti_queuecommand(Cmnd, done);
+ qlogicpti_mbox_command(qpti, param, 0);
+ return 0;
}
/*
@@ -1390,7 +1271,8 @@ static struct scsi_host_template qpti_template = {
.module = THIS_MODULE,
.name = "qlogicpti",
.info = qlogicpti_info,
- .queuecommand = qlogicpti_queuecommand_slow,
+ .queuecommand = qlogicpti_queuecommand,
+ .slave_configure = qlogicpti_slave_configure,
.eh_abort_handler = qlogicpti_abort,
.eh_bus_reset_handler = qlogicpti_reset,
.can_queue = QLOGICPTI_REQ_QUEUE_LEN,
diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h
index 6cd1c0771d2..ef6da2df584 100644
--- a/drivers/scsi/qlogicpti.h
+++ b/drivers/scsi/qlogicpti.h
@@ -380,8 +380,7 @@ struct qlogicpti {
unsigned char swsreg;
unsigned int
gotirq : 1, /* this instance got an irq */
- is_pti : 1, /* Non-zero if this is a PTI board. */
- sbits : 16; /* syncmode known bits */
+ is_pti : 1; /* Non-zero if this is a PTI board. */
};
/* How to twiddle them bits... */
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index a5de1a829a7..19294882245 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -59,6 +59,7 @@
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
@@ -367,9 +368,8 @@ void scsi_log_send(struct scsi_cmnd *cmd)
scsi_print_command(cmd);
if (level > 3) {
printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
- " done = 0x%p, queuecommand 0x%p\n",
+ " queuecommand 0x%p\n",
scsi_sglist(cmd), scsi_bufflen(cmd),
- cmd->done,
cmd->device->host->hostt->queuecommand);
}
@@ -442,7 +442,7 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
#endif
/*
- * Assign a serial number and pid to the request for error recovery
+ * Assign a serial number to the 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)
@@ -450,10 +450,6 @@ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd
cmd->serial_number = host->cmd_serial_number++;
if (cmd->serial_number == 0)
cmd->serial_number = host->cmd_serial_number++;
-
- cmd->pid = host->cmd_pid++;
- if (cmd->pid == 0)
- cmd->pid = host->cmd_pid++;
}
/*
@@ -658,6 +654,12 @@ void __scsi_done(struct scsi_cmnd *cmd)
blk_complete_request(rq);
}
+/* Move this to a header if it becomes more generally useful */
+static struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
+{
+ return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
+}
+
/*
* Function: scsi_finish_command
*
@@ -669,6 +671,8 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
{
struct scsi_device *sdev = cmd->device;
struct Scsi_Host *shost = sdev->host;
+ struct scsi_driver *drv;
+ unsigned int good_bytes;
scsi_device_unbusy(sdev);
@@ -694,7 +698,13 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
"Notifying upper driver of completion "
"(result %x)\n", cmd->result));
- cmd->done(cmd);
+ good_bytes = cmd->request_bufflen;
+ if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
+ drv = scsi_cmd_to_driver(cmd);
+ if (drv->done)
+ good_bytes = drv->done(cmd);
+ }
+ scsi_io_completion(cmd, good_bytes);
}
EXPORT_SYMBOL(scsi_finish_command);
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 4947dfe625a..46cae5a212d 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -38,6 +38,7 @@
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#include <linux/moduleparam.h>
+#include <linux/scatterlist.h>
#include <linux/blkdev.h>
#include "scsi.h"
@@ -600,7 +601,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
int k, req_len, act_len, len, active;
void * kaddr;
void * kaddr_off;
- struct scatterlist * sgpnt;
+ struct scatterlist * sg;
if (0 == scp->request_bufflen)
return 0;
@@ -619,16 +620,16 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
scp->resid = req_len - act_len;
return 0;
}
- sgpnt = (struct scatterlist *)scp->request_buffer;
active = 1;
- for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) {
+ req_len = act_len = 0;
+ scsi_for_each_sg(scp, sg, scp->use_sg, k) {
if (active) {
kaddr = (unsigned char *)
- kmap_atomic(sgpnt->page, KM_USER0);
+ kmap_atomic(sg_page(sg), KM_USER0);
if (NULL == kaddr)
return (DID_ERROR << 16);
- kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
- len = sgpnt->length;
+ kaddr_off = (unsigned char *)kaddr + sg->offset;
+ len = sg->length;
if ((req_len + len) > arr_len) {
active = 0;
len = arr_len - req_len;
@@ -637,7 +638,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
kunmap_atomic(kaddr, KM_USER0);
act_len += len;
}
- req_len += sgpnt->length;
+ req_len += sg->length;
}
if (scp->resid)
scp->resid -= act_len;
@@ -653,7 +654,7 @@ static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
int k, req_len, len, fin;
void * kaddr;
void * kaddr_off;
- struct scatterlist * sgpnt;
+ struct scatterlist * sg;
if (0 == scp->request_bufflen)
return 0;
@@ -668,13 +669,14 @@ static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
memcpy(arr, scp->request_buffer, len);
return len;
}
- sgpnt = (struct scatterlist *)scp->request_buffer;
- for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) {
- kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0);
+ sg = scsi_sglist(scp);
+ req_len = fin = 0;
+ for (k = 0; k < scp->use_sg; ++k, sg = sg_next(sg)) {
+ kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
if (NULL == kaddr)
return -1;
- kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
- len = sgpnt->length;
+ kaddr_off = (unsigned char *)kaddr + sg->offset;
+ len = sg->length;
if ((req_len + len) > max_arr_len) {
len = max_arr_len - req_len;
fin = 1;
@@ -683,7 +685,7 @@ static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
kunmap_atomic(kaddr, KM_USER0);
if (fin)
return req_len + len;
- req_len += sgpnt->length;
+ req_len += sg->length;
}
return req_len;
}
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index e2ea739e33d..348cc5a6e3c 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -214,6 +214,7 @@ static struct {
{"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"Promise", "", NULL, BLIST_SPARSELUN},
+ {"QUANTUM", "XP34301", "1071", BLIST_NOTQ},
{"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
{"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN},
{"SEAGATE", "ST34555N", "0930", BLIST_NOTQ}, /* Chokes on tagged INQUIRY */
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 8a525abda30..ebaca4ca4a1 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -24,7 +24,6 @@
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
-#include <linux/scatterlist.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -37,6 +36,7 @@
#include "scsi_priv.h"
#include "scsi_logging.h"
+#include "scsi_transport_api.h"
#define SENSE_TIMEOUT (10*HZ)
@@ -589,39 +589,23 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
}
/**
- * scsi_send_eh_cmnd - submit a scsi command as part of error recory
+ * scsi_eh_prep_cmnd - Save a scsi command info as part of error recory
* @scmd: SCSI command structure to hijack
- * @cmnd: CDB to send
+ * @ses: structure to save restore information
+ * @cmnd: CDB to send. Can be NULL if no new cmnd is needed
* @cmnd_size: size in bytes of @cmnd
- * @timeout: timeout for this request
- * @copy_sense: request sense data if set to 1
- *
- * This function is used to send a scsi command down to a target device
- * as part of the error recovery process. If @copy_sense is 0 the command
- * sent must be one that does not transfer any data. If @copy_sense is 1
- * the command must be REQUEST_SENSE and this functions copies out the
- * sense buffer it got into @scmd->sense_buffer.
+ * @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored)
*
- * Return value:
- * SUCCESS or FAILED or NEEDS_RETRY
+ * This function is used to save a scsi command information before re-execution
+ * as part of the error recovery process. If @sense_bytes is 0 the command
+ * sent must be one that does not transfer any data. If @sense_bytes != 0
+ * @cmnd is ignored and this functions sets up a REQUEST_SENSE command
+ * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer.
**/
-static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
- int cmnd_size, int timeout, int copy_sense)
+void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
+ unsigned char *cmnd, int cmnd_size, unsigned sense_bytes)
{
struct scsi_device *sdev = scmd->device;
- struct Scsi_Host *shost = sdev->host;
- int old_result = scmd->result;
- DECLARE_COMPLETION_ONSTACK(done);
- unsigned long timeleft;
- unsigned long flags;
- struct scatterlist sgl;
- unsigned char old_cmnd[MAX_COMMAND_SIZE];
- enum dma_data_direction old_data_direction;
- unsigned short old_use_sg;
- unsigned char old_cmd_len;
- unsigned old_bufflen;
- void *old_buffer;
- int rtn;
/*
* We need saved copies of a number of fields - this is because
@@ -630,35 +614,42 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
* we will need to restore these values prior to running the actual
* command.
*/
- old_buffer = scmd->request_buffer;
- old_bufflen = scmd->request_bufflen;
- memcpy(old_cmnd, scmd->cmnd, sizeof(scmd->cmnd));
- old_data_direction = scmd->sc_data_direction;
- old_cmd_len = scmd->cmd_len;
- old_use_sg = scmd->use_sg;
-
- memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
- memcpy(scmd->cmnd, cmnd, cmnd_size);
-
- if (copy_sense) {
- sg_init_one(&sgl, scmd->sense_buffer,
- sizeof(scmd->sense_buffer));
-
+ ses->cmd_len = scmd->cmd_len;
+ memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd));
+ ses->data_direction = scmd->sc_data_direction;
+ ses->bufflen = scmd->request_bufflen;
+ ses->buffer = scmd->request_buffer;
+ ses->use_sg = scmd->use_sg;
+ ses->resid = scmd->resid;
+ ses->result = scmd->result;
+
+ if (sense_bytes) {
+ scmd->request_bufflen = min_t(unsigned,
+ sizeof(scmd->sense_buffer), sense_bytes);
+ sg_init_one(&ses->sense_sgl, scmd->sense_buffer,
+ scmd->request_bufflen);
+ scmd->request_buffer = &ses->sense_sgl;
scmd->sc_data_direction = DMA_FROM_DEVICE;
- scmd->request_bufflen = sgl.length;
- scmd->request_buffer = &sgl;
scmd->use_sg = 1;
+ memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+ scmd->cmnd[0] = REQUEST_SENSE;
+ scmd->cmnd[4] = scmd->request_bufflen;
+ scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
} else {
scmd->request_buffer = NULL;
scmd->request_bufflen = 0;
scmd->sc_data_direction = DMA_NONE;
scmd->use_sg = 0;
+ if (cmnd) {
+ memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+ memcpy(scmd->cmnd, cmnd, cmnd_size);
+ scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
+ }
}
scmd->underflow = 0;
- scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
- if (sdev->scsi_level <= SCSI_2)
+ if (sdev->scsi_level <= SCSI_2 && sdev->scsi_level != SCSI_UNKNOWN)
scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) |
(sdev->lun << 5 & 0xe0);
@@ -667,7 +658,58 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
* untransferred sense data should be interpreted as being zero.
*/
memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+}
+EXPORT_SYMBOL(scsi_eh_prep_cmnd);
+
+/**
+ * scsi_eh_restore_cmnd - Restore a scsi command info as part of error recory
+ * @scmd: SCSI command structure to restore
+ * @ses: saved information from a coresponding call to scsi_prep_eh_cmnd
+ *
+ * Undo any damage done by above scsi_prep_eh_cmnd().
+ **/
+void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
+{
+ /*
+ * Restore original data
+ */
+ scmd->cmd_len = ses->cmd_len;
+ memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd));
+ scmd->sc_data_direction = ses->data_direction;
+ scmd->request_bufflen = ses->bufflen;
+ scmd->request_buffer = ses->buffer;
+ scmd->use_sg = ses->use_sg;
+ scmd->resid = ses->resid;
+ scmd->result = ses->result;
+}
+EXPORT_SYMBOL(scsi_eh_restore_cmnd);
+/**
+ * scsi_send_eh_cmnd - submit a scsi command as part of error recory
+ * @scmd: SCSI command structure to hijack
+ * @cmnd: CDB to send
+ * @cmnd_size: size in bytes of @cmnd
+ * @timeout: timeout for this request
+ * @sense_bytes: size of sense data to copy or 0
+ *
+ * This function is used to send a scsi command down to a target device
+ * as part of the error recovery process. See also scsi_eh_prep_cmnd() above.
+ *
+ * Return value:
+ * SUCCESS or FAILED or NEEDS_RETRY
+ **/
+static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
+ int cmnd_size, int timeout, unsigned sense_bytes)
+{
+ struct scsi_device *sdev = scmd->device;
+ 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);
@@ -711,17 +753,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
rtn = FAILED;
}
-
- /*
- * Restore original data
- */
- scmd->request_buffer = old_buffer;
- scmd->request_bufflen = old_bufflen;
- memcpy(scmd->cmnd, old_cmnd, sizeof(scmd->cmnd));
- scmd->sc_data_direction = old_data_direction;
- scmd->cmd_len = old_cmd_len;
- scmd->use_sg = old_use_sg;
- scmd->result = old_result;
+ scsi_eh_restore_cmnd(scmd, &ses);
return rtn;
}
@@ -736,10 +768,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
**/
static int scsi_request_sense(struct scsi_cmnd *scmd)
{
- static unsigned char generic_sense[6] =
- {REQUEST_SENSE, 0, 0, 0, 252, 0};
-
- return scsi_send_eh_cmnd(scmd, generic_sense, 6, SENSE_TIMEOUT, 1);
+ return scsi_send_eh_cmnd(scmd, NULL, 0, SENSE_TIMEOUT, ~0);
}
/**
@@ -1136,9 +1165,8 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q,
struct scsi_cmnd *scmd, *next;
list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
- sdev_printk(KERN_INFO, scmd->device,
- "scsi: Device offlined - not"
- " ready after error recovery\n");
+ sdev_printk(KERN_INFO, scmd->device, "Device offlined - "
+ "not ready after error recovery\n");
scsi_device_set_state(scmd->device, SDEV_OFFLINE);
if (scmd->eh_eflags & SCSI_EH_CANCEL_CMD) {
/*
@@ -1671,7 +1699,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
scmd->scsi_done = scsi_reset_provider_done_command;
- scmd->done = NULL;
scmd->request_buffer = NULL;
scmd->request_bufflen = 0;
@@ -1681,12 +1708,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
init_timer(&scmd->eh_timeout);
- /*
- * Sometimes the command can get back into the timer chain,
- * so use the pid as an identifier.
- */
- scmd->pid = 0;
-
spin_lock_irqsave(shost->host_lock, flags);
shost->tmf_in_progress = 1;
spin_unlock_irqrestore(shost->host_lock, flags);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index a417a6ff9f9..0e81e4cf887 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -17,6 +17,7 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/hardirq.h>
+#include <linux/scatterlist.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -33,35 +34,34 @@
#define SG_MEMPOOL_NR ARRAY_SIZE(scsi_sg_pools)
#define SG_MEMPOOL_SIZE 2
+/*
+ * The maximum number of SG segments that we will put inside a scatterlist
+ * (unless chaining is used). Should ideally fit inside a single page, to
+ * avoid a higher order allocation.
+ */
+#define SCSI_MAX_SG_SEGMENTS 128
+
struct scsi_host_sg_pool {
size_t size;
- char *name;
+ char *name;
struct kmem_cache *slab;
mempool_t *pool;
};
-#if (SCSI_MAX_PHYS_SEGMENTS < 32)
-#error SCSI_MAX_PHYS_SEGMENTS is too small
-#endif
-
-#define SP(x) { x, "sgpool-" #x }
+#define SP(x) { x, "sgpool-" #x }
static struct scsi_host_sg_pool scsi_sg_pools[] = {
SP(8),
SP(16),
+#if (SCSI_MAX_SG_SEGMENTS > 16)
SP(32),
-#if (SCSI_MAX_PHYS_SEGMENTS > 32)
+#if (SCSI_MAX_SG_SEGMENTS > 32)
SP(64),
-#if (SCSI_MAX_PHYS_SEGMENTS > 64)
+#if (SCSI_MAX_SG_SEGMENTS > 64)
SP(128),
-#if (SCSI_MAX_PHYS_SEGMENTS > 128)
- SP(256),
-#if (SCSI_MAX_PHYS_SEGMENTS > 256)
-#error SCSI_MAX_PHYS_SEGMENTS is too large
-#endif
#endif
#endif
#endif
-};
+};
#undef SP
static void scsi_run_queue(struct request_queue *q);
@@ -263,25 +263,12 @@ static int scsi_merge_bio(struct request *rq, struct bio *bio)
bio->bi_rw |= (1 << BIO_RW);
blk_queue_bounce(q, &bio);
- if (!rq->bio)
- blk_rq_bio_prep(q, rq, bio);
- else if (!ll_back_merge_fn(q, rq, bio))
- return -EINVAL;
- else {
- rq->biotail->bi_next = bio;
- rq->biotail = bio;
- }
-
- return 0;
+ return blk_rq_append_bio(q, rq, bio);
}
-static int scsi_bi_endio(struct bio *bio, unsigned int bytes_done, int error)
+static void scsi_bi_endio(struct bio *bio, int error)
{
- if (bio->bi_size)
- return 1;
-
bio_put(bio);
- return 0;
}
/**
@@ -301,19 +288,26 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
{
struct request_queue *q = rq->q;
int nr_pages = (bufflen + sgl[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
- unsigned int data_len = 0, len, bytes, off;
+ unsigned int data_len = bufflen, len, bytes, off;
+ struct scatterlist *sg;
struct page *page;
struct bio *bio = NULL;
int i, err, nr_vecs = 0;
- for (i = 0; i < nsegs; i++) {
- page = sgl[i].page;
- off = sgl[i].offset;
- len = sgl[i].length;
- data_len += len;
+ for_each_sg(sgl, sg, nsegs, i) {
+ page = sg_page(sg);
+ off = sg->offset;
+ len = sg->length;
+ data_len += len;
- while (len > 0) {
+ while (len > 0 && data_len > 0) {
+ /*
+ * sg sends a scatterlist that is larger than
+ * the data_len it wants transferred for certain
+ * IO sizes
+ */
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);
@@ -337,7 +331,7 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
if (bio->bi_vcnt >= nr_vecs) {
err = scsi_merge_bio(rq, bio);
if (err) {
- bio_endio(bio, bio->bi_size, 0);
+ bio_endio(bio, 0);
goto free_bios;
}
bio = NULL;
@@ -345,12 +339,13 @@ static int scsi_req_map_sg(struct request *rq, struct scatterlist *sgl,
page++;
len -= bytes;
+ data_len -=bytes;
off = 0;
}
}
rq->buffer = rq->data = NULL;
- rq->data_len = data_len;
+ rq->data_len = bufflen;
return 0;
free_bios:
@@ -359,7 +354,7 @@ free_bios:
/*
* call endio instead of bio_put incase it was bounced
*/
- bio_endio(bio, bio->bi_size, 0);
+ bio_endio(bio, 0);
}
return err;
@@ -443,6 +438,7 @@ EXPORT_SYMBOL_GPL(scsi_execute_async);
static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
{
cmd->serial_number = 0;
+ cmd->resid = 0;
memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
if (cmd->cmd_len == 0)
cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
@@ -701,56 +697,177 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
return NULL;
}
-struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
-{
- struct scsi_host_sg_pool *sgp;
- struct scatterlist *sgl;
+/*
+ * Like SCSI_MAX_SG_SEGMENTS, but for archs that have sg chaining. This limit
+ * is totally arbitrary, a setting of 2048 will get you at least 8mb ios.
+ */
+#define SCSI_MAX_SG_CHAIN_SEGMENTS 2048
- BUG_ON(!cmd->use_sg);
+static inline unsigned int scsi_sgtable_index(unsigned short nents)
+{
+ unsigned int index;
- switch (cmd->use_sg) {
+ switch (nents) {
case 1 ... 8:
- cmd->sglist_len = 0;
+ index = 0;
break;
case 9 ... 16:
- cmd->sglist_len = 1;
+ index = 1;
break;
+#if (SCSI_MAX_SG_SEGMENTS > 16)
case 17 ... 32:
- cmd->sglist_len = 2;
+ index = 2;
break;
-#if (SCSI_MAX_PHYS_SEGMENTS > 32)
+#if (SCSI_MAX_SG_SEGMENTS > 32)
case 33 ... 64:
- cmd->sglist_len = 3;
+ index = 3;
break;
-#if (SCSI_MAX_PHYS_SEGMENTS > 64)
+#if (SCSI_MAX_SG_SEGMENTS > 64)
case 65 ... 128:
- cmd->sglist_len = 4;
- break;
-#if (SCSI_MAX_PHYS_SEGMENTS > 128)
- case 129 ... 256:
- cmd->sglist_len = 5;
+ index = 4;
break;
#endif
#endif
#endif
default:
- return NULL;
+ printk(KERN_ERR "scsi: bad segment count=%d\n", nents);
+ BUG();
}
- sgp = scsi_sg_pools + cmd->sglist_len;
- sgl = mempool_alloc(sgp->pool, gfp_mask);
- return sgl;
+ return index;
+}
+
+struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+{
+ struct scsi_host_sg_pool *sgp;
+ struct scatterlist *sgl, *prev, *ret;
+ unsigned int index;
+ int this, left;
+
+ BUG_ON(!cmd->use_sg);
+
+ left = cmd->use_sg;
+ ret = prev = NULL;
+ do {
+ this = left;
+ if (this > SCSI_MAX_SG_SEGMENTS) {
+ this = SCSI_MAX_SG_SEGMENTS - 1;
+ index = SG_MEMPOOL_NR - 1;
+ } else
+ index = scsi_sgtable_index(this);
+
+ left -= this;
+
+ sgp = scsi_sg_pools + index;
+
+ sgl = mempool_alloc(sgp->pool, gfp_mask);
+ if (unlikely(!sgl))
+ goto enomem;
+
+ sg_init_table(sgl, sgp->size);
+
+ /*
+ * first loop through, set initial index and return value
+ */
+ if (!ret)
+ ret = sgl;
+
+ /*
+ * chain previous sglist, if any. we know the previous
+ * sglist must be the biggest one, or we would not have
+ * ended up doing another loop.
+ */
+ if (prev)
+ sg_chain(prev, SCSI_MAX_SG_SEGMENTS, sgl);
+
+ /*
+ * if we have nothing left, mark the last segment as
+ * end-of-list
+ */
+ if (!left)
+ sg_mark_end(&sgl[this - 1]);
+
+ /*
+ * don't allow subsequent mempool allocs to sleep, it would
+ * violate the mempool principle.
+ */
+ gfp_mask &= ~__GFP_WAIT;
+ gfp_mask |= __GFP_HIGH;
+ prev = sgl;
+ } while (left);
+
+ /*
+ * ->use_sg may get modified after dma mapping has potentially
+ * shrunk the number of segments, so keep a copy of it for free.
+ */
+ cmd->__use_sg = cmd->use_sg;
+ return ret;
+enomem:
+ if (ret) {
+ /*
+ * Free entries chained off ret. Since we were trying to
+ * allocate another sglist, we know that all entries are of
+ * the max size.
+ */
+ sgp = scsi_sg_pools + SG_MEMPOOL_NR - 1;
+ prev = ret;
+ ret = &ret[SCSI_MAX_SG_SEGMENTS - 1];
+
+ while ((sgl = sg_chain_ptr(ret)) != NULL) {
+ ret = &sgl[SCSI_MAX_SG_SEGMENTS - 1];
+ mempool_free(sgl, sgp->pool);
+ }
+
+ mempool_free(prev, sgp->pool);
+ }
+ return NULL;
}
EXPORT_SYMBOL(scsi_alloc_sgtable);
-void scsi_free_sgtable(struct scatterlist *sgl, int index)
+void scsi_free_sgtable(struct scsi_cmnd *cmd)
{
+ struct scatterlist *sgl = cmd->request_buffer;
struct scsi_host_sg_pool *sgp;
- BUG_ON(index >= SG_MEMPOOL_NR);
+ /*
+ * if this is the biggest size sglist, check if we have
+ * chained parts we need to free
+ */
+ if (cmd->__use_sg > SCSI_MAX_SG_SEGMENTS) {
+ unsigned short this, left;
+ struct scatterlist *next;
+ unsigned int index;
+
+ left = cmd->__use_sg - (SCSI_MAX_SG_SEGMENTS - 1);
+ next = sg_chain_ptr(&sgl[SCSI_MAX_SG_SEGMENTS - 1]);
+ while (left && next) {
+ sgl = next;
+ this = left;
+ if (this > SCSI_MAX_SG_SEGMENTS) {
+ this = SCSI_MAX_SG_SEGMENTS - 1;
+ index = SG_MEMPOOL_NR - 1;
+ } else
+ index = scsi_sgtable_index(this);
+
+ left -= this;
+
+ sgp = scsi_sg_pools + index;
+
+ if (left)
+ next = sg_chain_ptr(&sgl[sgp->size - 1]);
+
+ mempool_free(sgl, sgp->pool);
+ }
+
+ /*
+ * Restore original, will be freed below
+ */
+ sgl = cmd->request_buffer;
+ sgp = scsi_sg_pools + SG_MEMPOOL_NR - 1;
+ } else
+ sgp = scsi_sg_pools + scsi_sgtable_index(cmd->__use_sg);
- sgp = scsi_sg_pools + index;
mempool_free(sgl, sgp->pool);
}
@@ -776,7 +893,7 @@ EXPORT_SYMBOL(scsi_free_sgtable);
static void scsi_release_buffers(struct scsi_cmnd *cmd)
{
if (cmd->use_sg)
- scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
+ scsi_free_sgtable(cmd);
/*
* Zero these out. They now point to freed memory, and it is
@@ -937,11 +1054,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
break;
}
}
- if (!(req->cmd_flags & REQ_QUIET)) {
- scmd_printk(KERN_INFO, cmd,
- "Device not ready: ");
- scsi_print_sense_hdr("", &sshdr);
- }
+ if (!(req->cmd_flags & REQ_QUIET))
+ scsi_cmd_print_sense_hdr(cmd,
+ "Device not ready",
+ &sshdr);
+
scsi_end_request(cmd, 0, this_count, 1);
return;
case VOLUME_OVERFLOW:
@@ -975,7 +1092,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
}
scsi_end_request(cmd, 0, this_count, !result);
}
-EXPORT_SYMBOL(scsi_io_completion);
/*
* Function: scsi_init_io()
@@ -991,7 +1107,6 @@ EXPORT_SYMBOL(scsi_io_completion);
static int scsi_init_io(struct scsi_cmnd *cmd)
{
struct request *req = cmd->request;
- struct scatterlist *sgpnt;
int count;
/*
@@ -1004,14 +1119,13 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
/*
* If sg table allocation fails, requeue request later.
*/
- sgpnt = scsi_alloc_sgtable(cmd, GFP_ATOMIC);
- if (unlikely(!sgpnt)) {
+ cmd->request_buffer = scsi_alloc_sgtable(cmd, GFP_ATOMIC);
+ if (unlikely(!cmd->request_buffer)) {
scsi_unprep_request(req);
return BLKPREP_DEFER;
}
req->buffer = NULL;
- cmd->request_buffer = (char *) sgpnt;
if (blk_pc_request(req))
cmd->request_bufflen = req->data_len;
else
@@ -1032,9 +1146,6 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
req->current_nr_sectors);
- /* release the command and kill it */
- scsi_release_buffers(cmd);
- scsi_put_command(cmd);
return BLKPREP_KILL;
}
@@ -1059,21 +1170,13 @@ static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
return cmd;
}
-static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
-{
- BUG_ON(!blk_pc_request(cmd->request));
- /*
- * This will complete the whole command with uptodate=1 so
- * as far as the block layer is concerned the command completed
- * successfully. Since this is a REQ_BLOCK_PC command the
- * caller should check the request's errors value
- */
- scsi_io_completion(cmd, cmd->request_bufflen);
-}
-
-static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
+int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
{
struct scsi_cmnd *cmd;
+ int ret = scsi_prep_state_check(sdev, req);
+
+ if (ret != BLKPREP_OK)
+ return ret;
cmd = scsi_get_cmd_from_req(sdev, req);
if (unlikely(!cmd))
@@ -1116,21 +1219,22 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
cmd->transfersize = req->data_len;
cmd->allowed = req->retries;
cmd->timeout_per_command = req->timeout;
- cmd->done = scsi_blk_pc_done;
return BLKPREP_OK;
}
+EXPORT_SYMBOL(scsi_setup_blk_pc_cmnd);
/*
* Setup a REQ_TYPE_FS command. These are simple read/write request
* from filesystems that still need to be translated to SCSI CDBs from
* the ULD.
*/
-static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
+int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
{
struct scsi_cmnd *cmd;
- struct scsi_driver *drv;
- int ret;
+ int ret = scsi_prep_state_check(sdev, req);
+ if (ret != BLKPREP_OK)
+ return ret;
/*
* Filesystem requests must transfer data.
*/
@@ -1140,26 +1244,12 @@ static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req)
if (unlikely(!cmd))
return BLKPREP_DEFER;
- ret = scsi_init_io(cmd);
- if (unlikely(ret))
- return ret;
-
- /*
- * Initialize the actual SCSI command for this request.
- */
- drv = *(struct scsi_driver **)req->rq_disk->private_data;
- if (unlikely(!drv->init_command(cmd))) {
- scsi_release_buffers(cmd);
- scsi_put_command(cmd);
- return BLKPREP_KILL;
- }
-
- return BLKPREP_OK;
+ return scsi_init_io(cmd);
}
+EXPORT_SYMBOL(scsi_setup_fs_cmnd);
-static int scsi_prep_fn(struct request_queue *q, struct request *req)
+int scsi_prep_state_check(struct scsi_device *sdev, struct request *req)
{
- struct scsi_device *sdev = q->queuedata;
int ret = BLKPREP_OK;
/*
@@ -1205,35 +1295,25 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
ret = BLKPREP_KILL;
break;
}
-
- if (ret != BLKPREP_OK)
- goto out;
}
+ return ret;
+}
+EXPORT_SYMBOL(scsi_prep_state_check);
- switch (req->cmd_type) {
- case REQ_TYPE_BLOCK_PC:
- ret = scsi_setup_blk_pc_cmnd(sdev, req);
- break;
- case REQ_TYPE_FS:
- ret = scsi_setup_fs_cmnd(sdev, req);
- break;
- default:
- /*
- * All other command types are not supported.
- *
- * Note that these days the SCSI subsystem does not use
- * REQ_TYPE_SPECIAL requests anymore. These are only used
- * (directly or via blk_insert_request) by non-SCSI drivers.
- */
- blk_dump_rq_flags(req, "SCSI bad req");
- ret = BLKPREP_KILL;
- break;
- }
+int scsi_prep_return(struct request_queue *q, struct request *req, int ret)
+{
+ struct scsi_device *sdev = q->queuedata;
- out:
switch (ret) {
case BLKPREP_KILL:
req->errors = DID_NO_CONNECT << 16;
+ /* release the command and kill it */
+ if (req->special) {
+ struct scsi_cmnd *cmd = req->special;
+ scsi_release_buffers(cmd);
+ scsi_put_command(cmd);
+ req->special = NULL;
+ }
break;
case BLKPREP_DEFER:
/*
@@ -1250,6 +1330,17 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
return ret;
}
+EXPORT_SYMBOL(scsi_prep_return);
+
+static int scsi_prep_fn(struct request_queue *q, struct request *req)
+{
+ struct scsi_device *sdev = q->queuedata;
+ int ret = BLKPREP_KILL;
+
+ if (req->cmd_type == REQ_TYPE_BLOCK_PC)
+ ret = scsi_setup_blk_pc_cmnd(sdev, req);
+ return scsi_prep_return(q, req, ret);
+}
/*
* scsi_dev_queue_ready: if we can send requests to sdev, return 1 else
@@ -1559,8 +1650,25 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost,
if (!q)
return NULL;
+ /*
+ * this limit is imposed by hardware restrictions
+ */
blk_queue_max_hw_segments(q, shost->sg_tablesize);
- blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS);
+
+ /*
+ * In the future, sg chaining support will be mandatory and this
+ * ifdef can then go away. Right now we don't have all archs
+ * converted, so better keep it safe.
+ */
+#ifdef ARCH_HAS_SG_CHAIN
+ if (shost->use_sg_chaining)
+ blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS);
+ else
+ blk_queue_max_phys_segments(q, SCSI_MAX_SG_SEGMENTS);
+#else
+ blk_queue_max_phys_segments(q, SCSI_MAX_SG_SEGMENTS);
+#endif
+
blk_queue_max_sectors(q, shost->max_sectors);
blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
blk_queue_segment_boundary(q, shost->dma_boundary);
@@ -2007,6 +2115,142 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
EXPORT_SYMBOL(scsi_device_set_state);
/**
+ * sdev_evt_emit - emit a single SCSI device uevent
+ * @sdev: associated SCSI device
+ * @evt: event to emit
+ *
+ * Send a single uevent (scsi_event) to the associated scsi_device.
+ */
+static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt)
+{
+ int idx = 0;
+ char *envp[3];
+
+ switch (evt->evt_type) {
+ case SDEV_EVT_MEDIA_CHANGE:
+ envp[idx++] = "SDEV_MEDIA_CHANGE=1";
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
+
+ envp[idx++] = NULL;
+
+ kobject_uevent_env(&sdev->sdev_gendev.kobj, KOBJ_CHANGE, envp);
+}
+
+/**
+ * sdev_evt_thread - send a uevent for each scsi event
+ * @work: work struct for scsi_device
+ *
+ * Dispatch queued events to their associated scsi_device kobjects
+ * as uevents.
+ */
+void scsi_evt_thread(struct work_struct *work)
+{
+ struct scsi_device *sdev;
+ LIST_HEAD(event_list);
+
+ sdev = container_of(work, struct scsi_device, event_work);
+
+ while (1) {
+ struct scsi_event *evt;
+ struct list_head *this, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sdev->list_lock, flags);
+ list_splice_init(&sdev->event_list, &event_list);
+ spin_unlock_irqrestore(&sdev->list_lock, flags);
+
+ if (list_empty(&event_list))
+ break;
+
+ list_for_each_safe(this, tmp, &event_list) {
+ evt = list_entry(this, struct scsi_event, node);
+ list_del(&evt->node);
+ scsi_evt_emit(sdev, evt);
+ kfree(evt);
+ }
+ }
+}
+
+/**
+ * sdev_evt_send - send asserted event to uevent thread
+ * @sdev: scsi_device event occurred on
+ * @evt: event to send
+ *
+ * Assert scsi device event asynchronously.
+ */
+void sdev_evt_send(struct scsi_device *sdev, struct scsi_event *evt)
+{
+ unsigned long flags;
+
+ if (!test_bit(evt->evt_type, sdev->supported_events)) {
+ kfree(evt);
+ return;
+ }
+
+ spin_lock_irqsave(&sdev->list_lock, flags);
+ list_add_tail(&evt->node, &sdev->event_list);
+ schedule_work(&sdev->event_work);
+ spin_unlock_irqrestore(&sdev->list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(sdev_evt_send);
+
+/**
+ * sdev_evt_alloc - allocate a new scsi event
+ * @evt_type: type of event to allocate
+ * @gfpflags: GFP flags for allocation
+ *
+ * Allocates and returns a new scsi_event.
+ */
+struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type,
+ gfp_t gfpflags)
+{
+ struct scsi_event *evt = kzalloc(sizeof(struct scsi_event), gfpflags);
+ if (!evt)
+ return NULL;
+
+ evt->evt_type = evt_type;
+ INIT_LIST_HEAD(&evt->node);
+
+ /* evt_type-specific initialization, if any */
+ switch (evt_type) {
+ case SDEV_EVT_MEDIA_CHANGE:
+ default:
+ /* do nothing */
+ break;
+ }
+
+ return evt;
+}
+EXPORT_SYMBOL_GPL(sdev_evt_alloc);
+
+/**
+ * sdev_evt_send_simple - send asserted event to uevent thread
+ * @sdev: scsi_device event occurred on
+ * @evt_type: type of event to send
+ * @gfpflags: GFP flags for allocation
+ *
+ * Assert scsi device event asynchronously, given an event type.
+ */
+void sdev_evt_send_simple(struct scsi_device *sdev,
+ enum scsi_device_event evt_type, gfp_t gfpflags)
+{
+ struct scsi_event *evt = sdev_evt_alloc(evt_type, gfpflags);
+ if (!evt) {
+ sdev_printk(KERN_ERR, sdev, "event %d eaten due to OOM\n",
+ evt_type);
+ return;
+ }
+
+ sdev_evt_send(sdev, evt);
+}
+EXPORT_SYMBOL_GPL(sdev_evt_send_simple);
+
+/**
* scsi_device_quiesce - Block user issued commands.
* @sdev: scsi device to quiesce.
*
@@ -2223,18 +2467,19 @@ EXPORT_SYMBOL_GPL(scsi_target_unblock);
*
* Returns virtual address of the start of the mapped page
*/
-void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
+void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count,
size_t *offset, size_t *len)
{
int i;
size_t sg_len = 0, len_complete = 0;
+ struct scatterlist *sg;
struct page *page;
WARN_ON(!irqs_disabled());
- for (i = 0; i < sg_count; i++) {
+ for_each_sg(sgl, sg, sg_count, i) {
len_complete = sg_len; /* Complete sg-entries */
- sg_len += sg[i].length;
+ sg_len += sg->length;
if (sg_len > *offset)
break;
}
@@ -2248,10 +2493,10 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
}
/* Offset starting from the beginning of first page in this sg-entry */
- *offset = *offset - len_complete + sg[i].offset;
+ *offset = *offset - len_complete + sg->offset;
/* Assumption: contiguous pages can be accessed as "page + i" */
- page = nth_page(sg[i].page, (*offset >> PAGE_SHIFT));
+ page = nth_page(sg_page(sg), (*offset >> PAGE_SHIFT));
*offset &= ~PAGE_MASK;
/* Bytes in this sg-entry from *offset to the end of the page */
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index 4bf9aa547c7..40579edca10 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -64,7 +64,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) {
err = -EBADMSG;
- goto next_msg;
+ return;
}
hdr = NLMSG_DATA(nlh);
@@ -99,27 +99,6 @@ next_msg:
/**
- * scsi_nl_rcv_msg -
- * Receive handler for a socket. Extracts a received message buffer from
- * the socket, and starts message processing.
- *
- * @sk: socket
- * @len: unused
- *
- **/
-static void
-scsi_nl_rcv(struct sock *sk, int len)
-{
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
- scsi_nl_rcv_msg(skb);
- kfree_skb(skb);
- }
-}
-
-
-/**
* scsi_nl_rcv_event -
* Event handler for a netlink socket.
*
@@ -167,8 +146,8 @@ scsi_netlink_init(void)
return;
}
- scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT,
- SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL,
+ scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT,
+ SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL,
THIS_MODULE);
if (!scsi_nl_sock) {
printk(KERN_ERR "%s: register of recieve handler failed\n",
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index ee8efe849bf..eff00595189 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -68,6 +68,7 @@ extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
extern void scsi_device_unbusy(struct scsi_device *sdev);
extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
extern void scsi_next_command(struct scsi_cmnd *cmd);
+extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
extern void scsi_run_host_queues(struct Scsi_Host *shost);
extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
extern void scsi_free_queue(struct request_queue *q);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index a86e62f4b3b..40ea71cd2ca 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -85,7 +85,7 @@ static unsigned int max_scsi_luns = MAX_SCSI_LUNS;
static unsigned int max_scsi_luns = 1;
#endif
-module_param_named(max_luns, max_scsi_luns, int, S_IRUGO|S_IWUSR);
+module_param_named(max_luns, max_scsi_luns, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(max_luns,
"last scsi LUN (should be between 1 and 2^32-1)");
@@ -109,18 +109,19 @@ MODULE_PARM_DESC(scan, "sync, async or none");
*/
static unsigned int max_scsi_report_luns = 511;
-module_param_named(max_report_luns, max_scsi_report_luns, int, S_IRUGO|S_IWUSR);
+module_param_named(max_report_luns, max_scsi_report_luns, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(max_report_luns,
"REPORT LUNS maximum number of LUNS received (should be"
" between 1 and 16384)");
static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ+3;
-module_param_named(inq_timeout, scsi_inq_timeout, int, S_IRUGO|S_IWUSR);
+module_param_named(inq_timeout, scsi_inq_timeout, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(inq_timeout,
"Timeout (in seconds) waiting for devices to answer INQUIRY."
" Default is 5. Some non-compliant devices need more.");
+/* This lock protects only this list */
static DEFINE_SPINLOCK(async_scan_lock);
static LIST_HEAD(scanning_hosts);
@@ -235,6 +236,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
struct scsi_device *sdev;
int display_failure_msg = 1, ret;
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ extern void scsi_evt_thread(struct work_struct *work);
sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size,
GFP_ATOMIC);
@@ -253,7 +255,9 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
INIT_LIST_HEAD(&sdev->same_target_siblings);
INIT_LIST_HEAD(&sdev->cmd_list);
INIT_LIST_HEAD(&sdev->starved_entry);
+ INIT_LIST_HEAD(&sdev->event_list);
spin_lock_init(&sdev->list_lock);
+ INIT_WORK(&sdev->event_work, scsi_evt_thread);
sdev->sdev_gendev.parent = get_device(&starget->dev);
sdev->sdev_target = starget;
@@ -1466,14 +1470,14 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
if (strncmp(scsi_scan_type, "none", 4) == 0)
return ERR_PTR(-ENODEV);
- if (!shost->async_scan)
- scsi_complete_async_scans();
-
starget = scsi_alloc_target(parent, channel, id);
if (!starget)
return ERR_PTR(-ENOMEM);
mutex_lock(&shost->scan_mutex);
+ if (!shost->async_scan)
+ scsi_complete_async_scans();
+
if (scsi_host_scan_allowed(shost))
scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
mutex_unlock(&shost->scan_mutex);
@@ -1586,10 +1590,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel,
if (strncmp(scsi_scan_type, "none", 4) == 0)
return;
+ mutex_lock(&shost->scan_mutex);
if (!shost->async_scan)
scsi_complete_async_scans();
- mutex_lock(&shost->scan_mutex);
if (scsi_host_scan_allowed(shost))
__scsi_scan_target(parent, channel, id, lun, rescan);
mutex_unlock(&shost->scan_mutex);
@@ -1634,15 +1638,15 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
"%s: <%u:%u:%u>\n",
__FUNCTION__, channel, id, lun));
- if (!shost->async_scan)
- scsi_complete_async_scans();
-
if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
return -EINVAL;
mutex_lock(&shost->scan_mutex);
+ if (!shost->async_scan)
+ scsi_complete_async_scans();
+
if (scsi_host_scan_allowed(shost)) {
if (channel == SCAN_WILD_CARD)
for (channel = 0; channel <= shost->max_channel;
@@ -1661,7 +1665,8 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
{
struct scsi_device *sdev;
shost_for_each_device(sdev, shost) {
- if (scsi_sysfs_add_sdev(sdev) != 0)
+ if (!scsi_host_scan_allowed(shost) ||
+ scsi_sysfs_add_sdev(sdev) != 0)
scsi_destroy_sdev(sdev);
}
}
@@ -1679,6 +1684,7 @@ static void scsi_sysfs_add_devices(struct Scsi_Host *shost)
static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
{
struct async_scan_data *data;
+ unsigned long flags;
if (strncmp(scsi_scan_type, "sync", 4) == 0)
return NULL;
@@ -1698,8 +1704,13 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
goto err;
init_completion(&data->prev_finished);
- spin_lock(&async_scan_lock);
+ mutex_lock(&shost->scan_mutex);
+ spin_lock_irqsave(shost->host_lock, flags);
shost->async_scan = 1;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ mutex_unlock(&shost->scan_mutex);
+
+ spin_lock(&async_scan_lock);
if (list_empty(&scanning_hosts))
complete(&data->prev_finished);
list_add_tail(&data->list, &scanning_hosts);
@@ -1723,11 +1734,15 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
static void scsi_finish_async_scan(struct async_scan_data *data)
{
struct Scsi_Host *shost;
+ unsigned long flags;
if (!data)
return;
shost = data->shost;
+
+ mutex_lock(&shost->scan_mutex);
+
if (!shost->async_scan) {
printk("%s called twice for host %d", __FUNCTION__,
shost->host_no);
@@ -1739,8 +1754,13 @@ static void scsi_finish_async_scan(struct async_scan_data *data)
scsi_sysfs_add_devices(shost);
- spin_lock(&async_scan_lock);
+ spin_lock_irqsave(shost->host_lock, flags);
shost->async_scan = 0;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ mutex_unlock(&shost->scan_mutex);
+
+ spin_lock(&async_scan_lock);
list_del(&data->list);
if (!list_empty(&scanning_hosts)) {
struct async_scan_data *next = list_entry(scanning_hosts.next,
@@ -1782,6 +1802,7 @@ static int do_scan_async(void *_data)
**/
void scsi_scan_host(struct Scsi_Host *shost)
{
+ struct task_struct *p;
struct async_scan_data *data;
if (strncmp(scsi_scan_type, "none", 4) == 0)
@@ -1793,7 +1814,9 @@ void scsi_scan_host(struct Scsi_Host *shost)
return;
}
- kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
+ p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
+ if (unlikely(IS_ERR(p)))
+ do_scan_async(data);
}
EXPORT_SYMBOL(scsi_scan_host);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 34cdce6738a..f374fdcb681 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -190,6 +190,48 @@ show_shost_state(struct class_device *class_dev, char *buf)
static CLASS_DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state);
+static ssize_t
+show_shost_mode(unsigned int mode, char *buf)
+{
+ ssize_t len = 0;
+
+ if (mode & MODE_INITIATOR)
+ len = sprintf(buf, "%s", "Initiator");
+
+ if (mode & MODE_TARGET)
+ len += sprintf(buf + len, "%s%s", len ? ", " : "", "Target");
+
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+static ssize_t show_shost_supported_mode(struct class_device *class_dev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(class_dev);
+ unsigned int supported_mode = shost->hostt->supported_mode;
+
+ if (supported_mode == MODE_UNKNOWN)
+ /* by default this should be initiator */
+ supported_mode = MODE_INITIATOR;
+
+ return show_shost_mode(supported_mode, buf);
+}
+
+static CLASS_DEVICE_ATTR(supported_mode, S_IRUGO | S_IWUSR, show_shost_supported_mode, NULL);
+
+static ssize_t show_shost_active_mode(struct class_device *class_dev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(class_dev);
+
+ if (shost->active_mode == MODE_UNKNOWN)
+ return snprintf(buf, 20, "unknown\n");
+ else
+ return show_shost_mode(shost->active_mode, buf);
+}
+
+static CLASS_DEVICE_ATTR(active_mode, S_IRUGO | S_IWUSR, show_shost_active_mode, NULL);
+
shost_rd_attr(unique_id, "%u\n");
shost_rd_attr(host_busy, "%hu\n");
shost_rd_attr(cmd_per_lun, "%hd\n");
@@ -208,6 +250,8 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
&class_device_attr_proc_name,
&class_device_attr_scan,
&class_device_attr_state,
+ &class_device_attr_supported_mode,
+ &class_device_attr_active_mode,
NULL
};
@@ -224,6 +268,7 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
struct scsi_device *sdev;
struct device *parent;
struct scsi_target *starget;
+ struct list_head *this, *tmp;
unsigned long flags;
sdev = container_of(work, struct scsi_device, ew.work);
@@ -238,6 +283,16 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
list_del(&sdev->starved_entry);
spin_unlock_irqrestore(sdev->host->host_lock, flags);
+ cancel_work_sync(&sdev->event_work);
+
+ list_for_each_safe(this, tmp, &sdev->event_list) {
+ struct scsi_event *evt;
+
+ evt = list_entry(this, struct scsi_event, node);
+ list_del(&evt->node);
+ kfree(evt);
+ }
+
if (sdev->request_queue) {
sdev->request_queue->queuedata = NULL;
/* user context needed to free queue */
@@ -277,16 +332,11 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
}
-static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct scsi_device *sdev = to_scsi_device(dev);
- int i = 0;
- int length = 0;
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
- envp[i] = NULL;
+ add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
return 0;
}
@@ -575,25 +625,68 @@ sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL);
+#define DECLARE_EVT_SHOW(name, Cap_name) \
+static ssize_t \
+sdev_show_evt_##name(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct scsi_device *sdev = to_scsi_device(dev); \
+ int val = test_bit(SDEV_EVT_##Cap_name, sdev->supported_events);\
+ return snprintf(buf, 20, "%d\n", val); \
+}
+
+#define DECLARE_EVT_STORE(name, Cap_name) \
+static ssize_t \
+sdev_store_evt_##name(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct scsi_device *sdev = to_scsi_device(dev); \
+ int val = simple_strtoul(buf, NULL, 0); \
+ if (val == 0) \
+ clear_bit(SDEV_EVT_##Cap_name, sdev->supported_events); \
+ else if (val == 1) \
+ set_bit(SDEV_EVT_##Cap_name, sdev->supported_events); \
+ else \
+ return -EINVAL; \
+ return count; \
+}
+
+#define DECLARE_EVT(name, Cap_name) \
+ DECLARE_EVT_SHOW(name, Cap_name) \
+ DECLARE_EVT_STORE(name, Cap_name) \
+ static DEVICE_ATTR(evt_##name, S_IRUGO, sdev_show_evt_##name, \
+ sdev_store_evt_##name);
+#define REF_EVT(name) &dev_attr_evt_##name.attr
+
+DECLARE_EVT(media_change, MEDIA_CHANGE)
+
/* Default template for device attributes. May NOT be modified */
-static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
- &dev_attr_device_blocked,
- &dev_attr_queue_depth,
- &dev_attr_queue_type,
- &dev_attr_type,
- &dev_attr_scsi_level,
- &dev_attr_vendor,
- &dev_attr_model,
- &dev_attr_rev,
- &dev_attr_rescan,
- &dev_attr_delete,
- &dev_attr_state,
- &dev_attr_timeout,
- &dev_attr_iocounterbits,
- &dev_attr_iorequest_cnt,
- &dev_attr_iodone_cnt,
- &dev_attr_ioerr_cnt,
- &dev_attr_modalias,
+static struct attribute *scsi_sdev_attrs[] = {
+ &dev_attr_device_blocked.attr,
+ &dev_attr_type.attr,
+ &dev_attr_scsi_level.attr,
+ &dev_attr_vendor.attr,
+ &dev_attr_model.attr,
+ &dev_attr_rev.attr,
+ &dev_attr_rescan.attr,
+ &dev_attr_delete.attr,
+ &dev_attr_state.attr,
+ &dev_attr_timeout.attr,
+ &dev_attr_iocounterbits.attr,
+ &dev_attr_iorequest_cnt.attr,
+ &dev_attr_iodone_cnt.attr,
+ &dev_attr_ioerr_cnt.attr,
+ &dev_attr_modalias.attr,
+ REF_EVT(media_change),
+ NULL
+};
+
+static struct attribute_group scsi_sdev_attr_group = {
+ .attrs = scsi_sdev_attrs,
+};
+
+static struct attribute_group *scsi_sdev_attr_groups[] = {
+ &scsi_sdev_attr_group,
NULL
};
@@ -655,56 +748,6 @@ static struct device_attribute sdev_attr_queue_type_rw =
__ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
sdev_store_queue_type_rw);
-static struct device_attribute *attr_changed_internally(
- struct Scsi_Host *shost,
- struct device_attribute * attr)
-{
- if (!strcmp("queue_depth", attr->attr.name)
- && shost->hostt->change_queue_depth)
- return &sdev_attr_queue_depth_rw;
- else if (!strcmp("queue_type", attr->attr.name)
- && shost->hostt->change_queue_type)
- return &sdev_attr_queue_type_rw;
- return attr;
-}
-
-
-static struct device_attribute *attr_overridden(
- struct device_attribute **attrs,
- struct device_attribute *attr)
-{
- int i;
-
- if (!attrs)
- return NULL;
- for (i = 0; attrs[i]; i++)
- if (!strcmp(attrs[i]->attr.name, attr->attr.name))
- return attrs[i];
- return NULL;
-}
-
-static int attr_add(struct device *dev, struct device_attribute *attr)
-{
- struct device_attribute *base_attr;
-
- /*
- * Spare the caller from having to copy things it's not interested in.
- */
- base_attr = attr_overridden(scsi_sysfs_sdev_attrs, attr);
- if (base_attr) {
- /* extend permissions */
- attr->attr.mode |= base_attr->attr.mode;
-
- /* override null show/store with default */
- if (!attr->show)
- attr->show = base_attr->show;
- if (!attr->store)
- attr->store = base_attr->store;
- }
-
- return device_create_file(dev, attr);
-}
-
/**
* scsi_sysfs_add_sdev - add scsi device to sysfs
* @sdev: scsi_device to add
@@ -736,6 +779,24 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
* released by the sdev_class .release */
get_device(&sdev->sdev_gendev);
+ /* create queue files, which may be writable, depending on the host */
+ if (sdev->host->hostt->change_queue_depth)
+ error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_depth_rw);
+ else
+ error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth);
+ if (error) {
+ __scsi_remove_device(sdev);
+ goto out;
+ }
+ if (sdev->host->hostt->change_queue_type)
+ error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw);
+ else
+ error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type);
+ if (error) {
+ __scsi_remove_device(sdev);
+ goto out;
+ }
+
error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL);
if (error)
@@ -746,9 +807,10 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
* nothing went wrong */
error = 0;
+ /* add additional host specific attributes */
if (sdev->host->hostt->sdev_attrs) {
for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
- error = attr_add(&sdev->sdev_gendev,
+ error = device_create_file(&sdev->sdev_gendev,
sdev->host->hostt->sdev_attrs[i]);
if (error) {
__scsi_remove_device(sdev);
@@ -756,20 +818,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
}
}
}
-
- for (i = 0; scsi_sysfs_sdev_attrs[i]; i++) {
- if (!attr_overridden(sdev->host->hostt->sdev_attrs,
- scsi_sysfs_sdev_attrs[i])) {
- struct device_attribute * attr =
- attr_changed_internally(sdev->host,
- scsi_sysfs_sdev_attrs[i]);
- error = device_create_file(&sdev->sdev_gendev, attr);
- if (error) {
- __scsi_remove_device(sdev);
- goto out;
- }
- }
- }
transport_add_device(&sdev->sdev_gendev);
out:
@@ -956,6 +1004,12 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost)
return 0;
}
+static struct device_type scsi_dev_type = {
+ .name = "scsi_device",
+ .release = scsi_device_dev_release,
+ .groups = scsi_sdev_attr_groups,
+};
+
void scsi_sysfs_device_initialize(struct scsi_device *sdev)
{
unsigned long flags;
@@ -964,7 +1018,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
device_initialize(&sdev->sdev_gendev);
sdev->sdev_gendev.bus = &scsi_bus_type;
- sdev->sdev_gendev.release = scsi_device_dev_release;
+ sdev->sdev_gendev.type = &scsi_dev_type;
sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d",
sdev->host->host_no, sdev->channel, sdev->id,
sdev->lun);
@@ -985,7 +1039,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
int scsi_is_sdev_device(const struct device *dev)
{
- return dev->release == scsi_device_dev_release;
+ return dev->type == &scsi_dev_type;
}
EXPORT_SYMBOL(scsi_is_sdev_device);
diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
index ca22ddf8174..9815a1a2db2 100644
--- a/drivers/scsi/scsi_tgt_if.c
+++ b/drivers/scsi/scsi_tgt_if.c
@@ -102,7 +102,8 @@ static int tgt_uspace_send_event(u32 type, struct tgt_event *p)
return 0;
}
-int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 tag)
+int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 itn_id,
+ struct scsi_lun *lun, u64 tag)
{
struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
struct tgt_event ev;
@@ -110,6 +111,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 ta
memset(&ev, 0, sizeof(ev));
ev.p.cmd_req.host_no = shost->host_no;
+ ev.p.cmd_req.itn_id = itn_id;
ev.p.cmd_req.data_len = cmd->request_bufflen;
memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb));
memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun));
@@ -127,7 +129,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun, u64 ta
return err;
}
-int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag)
+int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 itn_id, u64 tag)
{
struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
struct tgt_event ev;
@@ -135,6 +137,7 @@ int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag)
memset(&ev, 0, sizeof(ev));
ev.p.cmd_done.host_no = shost->host_no;
+ ev.p.cmd_done.itn_id = itn_id;
ev.p.cmd_done.tag = tag;
ev.p.cmd_done.result = cmd->result;
@@ -149,14 +152,15 @@ int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag)
return err;
}
-int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
- struct scsi_lun *scsilun, void *data)
+int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 itn_id, int function,
+ u64 tag, struct scsi_lun *scsilun, void *data)
{
struct tgt_event ev;
int err;
memset(&ev, 0, sizeof(ev));
ev.p.tsk_mgmt_req.host_no = host_no;
+ ev.p.tsk_mgmt_req.itn_id = itn_id;
ev.p.tsk_mgmt_req.function = function;
ev.p.tsk_mgmt_req.tag = tag;
memcpy(ev.p.tsk_mgmt_req.lun, scsilun, sizeof(ev.p.tsk_mgmt_req.lun));
@@ -172,6 +176,29 @@ int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
return err;
}
+int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 itn_id,
+ int function, char *initiator_id)
+{
+ struct tgt_event ev;
+ int err;
+
+ memset(&ev, 0, sizeof(ev));
+ ev.p.it_nexus_req.host_no = host_no;
+ ev.p.it_nexus_req.function = function;
+ ev.p.it_nexus_req.itn_id = itn_id;
+ if (initiator_id)
+ strncpy(ev.p.it_nexus_req.initiator_id, initiator_id,
+ sizeof(ev.p.it_nexus_req.initiator_id));
+
+ dprintk("%d %x %llx\n", host_no, function, (unsigned long long)itn_id);
+
+ err = tgt_uspace_send_event(TGT_KEVENT_IT_NEXUS_REQ, &ev);
+ if (err)
+ eprintk("tx buf is full, could not send\n");
+
+ return err;
+}
+
static int event_recv_msg(struct tgt_event *ev)
{
int err = 0;
@@ -179,6 +206,7 @@ static int event_recv_msg(struct tgt_event *ev)
switch (ev->hdr.type) {
case TGT_UEVENT_CMD_RSP:
err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no,
+ ev->p.cmd_rsp.itn_id,
ev->p.cmd_rsp.result,
ev->p.cmd_rsp.tag,
ev->p.cmd_rsp.uaddr,
@@ -189,9 +217,15 @@ static int event_recv_msg(struct tgt_event *ev)
break;
case TGT_UEVENT_TSK_MGMT_RSP:
err = scsi_tgt_kspace_tsk_mgmt(ev->p.tsk_mgmt_rsp.host_no,
+ ev->p.tsk_mgmt_rsp.itn_id,
ev->p.tsk_mgmt_rsp.mid,
ev->p.tsk_mgmt_rsp.result);
break;
+ case TGT_UEVENT_IT_NEXUS_RSP:
+ err = scsi_tgt_kspace_it_nexus_rsp(ev->p.it_nexus_rsp.host_no,
+ ev->p.it_nexus_rsp.itn_id,
+ ev->p.it_nexus_rsp.result);
+ break;
default:
eprintk("unknown type %d\n", ev->hdr.type);
err = -EINVAL;
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 371b69c110b..a91761c3645 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -27,6 +27,7 @@
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
#include <scsi/scsi_tgt.h>
#include "scsi_tgt_priv.h"
@@ -46,6 +47,7 @@ struct scsi_tgt_cmd {
struct list_head hash_list;
struct request *rq;
+ u64 itn_id;
u64 tag;
};
@@ -185,12 +187,13 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work)
}
static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd,
- u64 tag)
+ u64 itn_id, u64 tag)
{
struct scsi_tgt_queuedata *qdata = rq->q->queuedata;
unsigned long flags;
struct list_head *head;
+ tcmd->itn_id = itn_id;
tcmd->tag = tag;
tcmd->bio = NULL;
INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy);
@@ -234,7 +237,7 @@ int scsi_tgt_alloc_queue(struct Scsi_Host *shost)
* command as is recvd to userspace. uspace can then make
* sure we do not overload the HBA
*/
- q->nr_requests = shost->hostt->can_queue;
+ q->nr_requests = shost->can_queue;
/*
* We currently only support software LLDs so this does
* not matter for now. Do we need this for the cards we support?
@@ -301,14 +304,14 @@ EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host);
* @scsilun: scsi lun
* @tag: unique value to identify this command for tmf
*/
-int scsi_tgt_queue_command(struct scsi_cmnd *cmd, struct scsi_lun *scsilun,
- u64 tag)
+int scsi_tgt_queue_command(struct scsi_cmnd *cmd, u64 itn_id,
+ struct scsi_lun *scsilun, u64 tag)
{
struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
int err;
- init_scsi_tgt_cmd(cmd->request, tcmd, tag);
- err = scsi_tgt_uspace_send_cmd(cmd, scsilun, tag);
+ init_scsi_tgt_cmd(cmd->request, tcmd, itn_id, tag);
+ err = scsi_tgt_uspace_send_cmd(cmd, itn_id, scsilun, tag);
if (err)
cmd_hashlist_del(cmd);
@@ -326,10 +329,10 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
- scsi_tgt_uspace_send_status(cmd, tcmd->tag);
+ scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag);
if (cmd->request_buffer)
- scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
+ scsi_free_sgtable(cmd);
queue_work(scsi_tgtd, &tcmd->work);
}
@@ -370,7 +373,7 @@ static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
}
eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg);
- scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
+ scsi_free_sgtable(cmd);
return -EINVAL;
}
@@ -459,7 +462,7 @@ static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag)
return rq;
}
-int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
+int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag,
unsigned long uaddr, u32 len, unsigned long sense_uaddr,
u32 sense_len, u8 rw)
{
@@ -541,21 +544,22 @@ done:
return err;
}
-int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, int function, u64 tag,
- struct scsi_lun *scsilun, void *data)
+int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, u64 itn_id,
+ int function, u64 tag, struct scsi_lun *scsilun,
+ void *data)
{
int err;
/* TODO: need to retry if this fails. */
- err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, function,
- tag, scsilun, data);
+ err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, itn_id,
+ function, tag, scsilun, data);
if (err < 0)
eprintk("The task management request lost!\n");
return err;
}
EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request);
-int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result)
+int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 itn_id, u64 mid, int result)
{
struct Scsi_Host *shost;
int err = -EINVAL;
@@ -573,7 +577,60 @@ int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result)
goto done;
}
- err = shost->hostt->tsk_mgmt_response(mid, result);
+ err = shost->transportt->tsk_mgmt_response(shost, itn_id, mid, result);
+done:
+ scsi_host_put(shost);
+ return err;
+}
+
+int scsi_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+ char *initiator)
+{
+ int err;
+
+ /* TODO: need to retry if this fails. */
+ err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, itn_id, 0,
+ initiator);
+ if (err < 0)
+ eprintk("The i_t_neuxs request lost, %d %llx!\n",
+ shost->host_no, (unsigned long long)itn_id);
+ return err;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_create);
+
+int scsi_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+ int err;
+
+ /* TODO: need to retry if this fails. */
+ err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no,
+ itn_id, 1, NULL);
+ if (err < 0)
+ eprintk("The i_t_neuxs request lost, %d %llx!\n",
+ shost->host_no, (unsigned long long)itn_id);
+ return err;
+}
+EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_destroy);
+
+int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result)
+{
+ struct Scsi_Host *shost;
+ int err = -EINVAL;
+
+ dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid);
+
+ shost = scsi_host_lookup(host_no);
+ if (IS_ERR(shost)) {
+ printk(KERN_ERR "Could not find host no %d\n", host_no);
+ return err;
+ }
+
+ if (!shost->uspace_req_q) {
+ printk(KERN_ERR "Not target scsi host %d\n", host_no);
+ goto done;
+ }
+
+ err = shost->transportt->it_nexus_response(shost, itn_id, result);
done:
scsi_host_put(shost);
return err;
diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h
index e9e6db1c417..cb92888948f 100644
--- a/drivers/scsi/scsi_tgt_priv.h
+++ b/drivers/scsi/scsi_tgt_priv.h
@@ -15,12 +15,18 @@ do { \
extern void scsi_tgt_if_exit(void);
extern int scsi_tgt_if_init(void);
-extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun,
- u64 tag);
-extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag);
-extern int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
- unsigned long uaddr, u32 len, unsigned long sense_uaddr,
- u32 sense_len, u8 rw);
-extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
+extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 it_nexus_id,
+ struct scsi_lun *lun, u64 tag);
+extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 it_nexus_id,
+ u64 tag);
+extern int scsi_tgt_kspace_exec(int host_no, u64 it_nexus_id, int result, u64 tag,
+ unsigned long uaddr, u32 len,
+ unsigned long sense_uaddr, u32 sense_len, u8 rw);
+extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 it_nexus_id,
+ int function, u64 tag,
struct scsi_lun *scsilun, void *data);
-extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result);
+extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 it_nexus_id,
+ u64 mid, int result);
+extern int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 it_nexus_id,
+ int function, char *initiator);
+extern int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 it_nexus_id, int result);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 47057254850..7a7cfe583b2 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -36,6 +36,7 @@
#include <net/netlink.h>
#include <scsi/scsi_netlink_fc.h>
#include "scsi_priv.h"
+#include "scsi_transport_fc_internal.h"
static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
static void fc_vport_sched_delete(struct work_struct *work);
@@ -473,7 +474,7 @@ static DECLARE_TRANSPORT_CLASS(fc_vport_class,
*/
static unsigned int fc_dev_loss_tmo = 60; /* seconds */
-module_param_named(dev_loss_tmo, fc_dev_loss_tmo, int, S_IRUGO|S_IWUSR);
+module_param_named(dev_loss_tmo, fc_dev_loss_tmo, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(dev_loss_tmo,
"Maximum number of seconds that the FC transport should"
" insulate the loss of a remote port. Once this value is"
@@ -1956,6 +1957,19 @@ static int fc_user_scan(struct Scsi_Host *shost, uint channel,
return 0;
}
+static int fc_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id,
+ int result)
+{
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ return i->f->tsk_mgmt_response(shost, nexus, tm_id, result);
+}
+
+static int fc_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
+{
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ return i->f->it_nexus_response(shost, nexus, result);
+}
+
struct scsi_transport_template *
fc_attach_transport(struct fc_function_template *ft)
{
@@ -1999,6 +2013,10 @@ fc_attach_transport(struct fc_function_template *ft)
i->t.user_scan = fc_user_scan;
+ /* target-mode drivers' functions */
+ i->t.tsk_mgmt_response = fc_tsk_mgmt_response;
+ i->t.it_nexus_response = fc_it_nexus_response;
+
/*
* Setup SCSI Target Attributes.
*/
@@ -2756,6 +2774,10 @@ fc_remote_port_delete(struct fc_rport *rport)
spin_unlock_irqrestore(shost->host_lock, flags);
+ if (rport->roles & FC_PORT_ROLE_FCP_INITIATOR &&
+ shost->active_mode & MODE_TARGET)
+ fc_tgt_it_nexus_destroy(shost, (unsigned long)rport);
+
scsi_target_block(&rport->dev);
/* see if we need to kill io faster than waiting for device loss */
@@ -2796,6 +2818,7 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
unsigned long flags;
int create = 0;
+ int ret;
spin_lock_irqsave(shost->host_lock, flags);
if (roles & FC_PORT_ROLE_FCP_TARGET) {
@@ -2804,6 +2827,12 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
create = 1;
} else if (!(rport->roles & FC_PORT_ROLE_FCP_TARGET))
create = 1;
+ } else if (shost->active_mode & MODE_TARGET) {
+ ret = fc_tgt_it_nexus_create(shost, (unsigned long)rport,
+ (char *)&rport->node_name);
+ if (ret)
+ printk(KERN_ERR "FC Remore Port tgt nexus failed %d\n",
+ ret);
}
rport->roles = roles;
@@ -2988,10 +3017,12 @@ fc_scsi_scan_rport(struct work_struct *work)
struct fc_rport *rport =
container_of(work, struct fc_rport, scan_work);
struct Scsi_Host *shost = rport_to_shost(rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
unsigned long flags;
if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
- (rport->roles & FC_PORT_ROLE_FCP_TARGET)) {
+ (rport->roles & FC_PORT_ROLE_FCP_TARGET) &&
+ !(i->f->disable_target_scan)) {
scsi_scan_target(&rport->dev, rport->channel,
rport->scsi_target_id, SCAN_WILD_CARD, 1);
}
diff --git a/drivers/scsi/scsi_transport_fc_internal.h b/drivers/scsi/scsi_transport_fc_internal.h
new file mode 100644
index 00000000000..e7bfbe751c1
--- /dev/null
+++ b/drivers/scsi/scsi_transport_fc_internal.h
@@ -0,0 +1,26 @@
+#include <scsi/scsi_tgt.h>
+
+#ifdef CONFIG_SCSI_FC_TGT_ATTRS
+static inline int fc_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+ char *initiator)
+{
+ return scsi_tgt_it_nexus_create(shost, itn_id, initiator);
+}
+
+static inline int fc_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+ return scsi_tgt_it_nexus_destroy(shost, itn_id);
+}
+#else
+static inline int fc_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+ char *initiator)
+{
+ return 0;
+}
+
+static inline int fc_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+ return 0;
+}
+
+#endif
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 34c1860a259..5428d15f23c 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1097,61 +1097,49 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
}
/*
- * Get message from skb (based on rtnetlink_rcv_skb). Each message is
- * processed by iscsi_if_recv_msg. Malformed skbs with wrong lengths or
- * invalid creds are discarded silently.
+ * Get message from skb. Each message is processed by iscsi_if_recv_msg.
+ * Malformed skbs with wrong lengths or invalid creds are not processed.
*/
static void
-iscsi_if_rx(struct sock *sk, int len)
+iscsi_if_rx(struct sk_buff *skb)
{
- struct sk_buff *skb;
-
mutex_lock(&rx_queue_mutex);
- while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
- if (NETLINK_CREDS(skb)->uid) {
- skb_pull(skb, skb->len);
- goto free_skb;
+ while (skb->len >= NLMSG_SPACE(0)) {
+ int err;
+ uint32_t rlen;
+ struct nlmsghdr *nlh;
+ struct iscsi_uevent *ev;
+
+ nlh = nlmsg_hdr(skb);
+ if (nlh->nlmsg_len < sizeof(*nlh) ||
+ skb->len < nlh->nlmsg_len) {
+ break;
}
- while (skb->len >= NLMSG_SPACE(0)) {
- int err;
- uint32_t rlen;
- struct nlmsghdr *nlh;
- struct iscsi_uevent *ev;
+ ev = NLMSG_DATA(nlh);
+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+ if (rlen > skb->len)
+ rlen = skb->len;
- nlh = nlmsg_hdr(skb);
- if (nlh->nlmsg_len < sizeof(*nlh) ||
- skb->len < nlh->nlmsg_len) {
- break;
- }
-
- ev = NLMSG_DATA(nlh);
- rlen = NLMSG_ALIGN(nlh->nlmsg_len);
- if (rlen > skb->len)
- rlen = skb->len;
-
- err = iscsi_if_recv_msg(skb, nlh);
- if (err) {
- ev->type = ISCSI_KEVENT_IF_ERROR;
- ev->iferror = err;
- }
- do {
- /*
- * special case for GET_STATS:
- * on success - sending reply and stats from
- * inside of if_recv_msg(),
- * on error - fall through.
- */
- if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
- break;
- err = iscsi_if_send_reply(
- NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
- nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
- } while (err < 0 && err != -ECONNREFUSED);
- skb_pull(skb, rlen);
+ err = iscsi_if_recv_msg(skb, nlh);
+ if (err) {
+ ev->type = ISCSI_KEVENT_IF_ERROR;
+ ev->iferror = err;
}
-free_skb:
- kfree_skb(skb);
+ do {
+ /*
+ * special case for GET_STATS:
+ * on success - sending reply and stats from
+ * inside of if_recv_msg(),
+ * on error - fall through.
+ */
+ if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
+ break;
+ err = iscsi_if_send_reply(
+ NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
+ nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
+ } while (err < 0 && err != -ECONNREFUSED);
+ skb_pull(skb, rlen);
}
mutex_unlock(&rx_queue_mutex);
}
@@ -1523,7 +1511,7 @@ static __init int iscsi_transport_init(void)
if (err)
goto unregister_conn_class;
- nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx, NULL,
+ nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, NULL,
THIS_MODULE);
if (!nls) {
err = -ENOBUFS;
diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c
new file mode 100644
index 00000000000..44a340bd937
--- /dev/null
+++ b/drivers/scsi/scsi_transport_srp.c
@@ -0,0 +1,381 @@
+/*
+ * SCSI RDMA (SRP) transport class
+ *
+ * Copyright (C) 2007 FUJITA Tomonori <tomof@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_srp.h>
+#include "scsi_transport_srp_internal.h"
+
+struct srp_host_attrs {
+ atomic_t next_port_id;
+};
+#define to_srp_host_attrs(host) ((struct srp_host_attrs *)(host)->shost_data)
+
+#define SRP_HOST_ATTRS 0
+#define SRP_RPORT_ATTRS 2
+
+struct srp_internal {
+ struct scsi_transport_template t;
+ struct srp_function_template *f;
+
+ struct class_device_attribute *host_attrs[SRP_HOST_ATTRS + 1];
+
+ struct class_device_attribute *rport_attrs[SRP_RPORT_ATTRS + 1];
+ struct class_device_attribute private_rport_attrs[SRP_RPORT_ATTRS];
+ struct transport_container rport_attr_cont;
+};
+
+#define to_srp_internal(tmpl) container_of(tmpl, struct srp_internal, t)
+
+#define dev_to_rport(d) container_of(d, struct srp_rport, dev)
+#define transport_class_to_srp_rport(cdev) dev_to_rport((cdev)->dev)
+
+static int srp_host_setup(struct transport_container *tc, struct device *dev,
+ struct class_device *cdev)
+{
+ struct Scsi_Host *shost = dev_to_shost(dev);
+ struct srp_host_attrs *srp_host = to_srp_host_attrs(shost);
+
+ atomic_set(&srp_host->next_port_id, 0);
+ return 0;
+}
+
+static DECLARE_TRANSPORT_CLASS(srp_host_class, "srp_host", srp_host_setup,
+ NULL, NULL);
+
+static DECLARE_TRANSPORT_CLASS(srp_rport_class, "srp_remote_ports",
+ NULL, NULL, NULL);
+
+#define SETUP_TEMPLATE(attrb, field, perm, test, ro_test, ro_perm) \
+ i->private_##attrb[count] = class_device_attr_##field; \
+ i->private_##attrb[count].attr.mode = perm; \
+ if (ro_test) { \
+ i->private_##attrb[count].attr.mode = ro_perm; \
+ i->private_##attrb[count].store = NULL; \
+ } \
+ i->attrb[count] = &i->private_##attrb[count]; \
+ if (test) \
+ count++
+
+#define SETUP_RPORT_ATTRIBUTE_RD(field) \
+ SETUP_TEMPLATE(rport_attrs, field, S_IRUGO, 1, 0, 0)
+
+#define SETUP_RPORT_ATTRIBUTE_RW(field) \
+ SETUP_TEMPLATE(rport_attrs, field, S_IRUGO | S_IWUSR, \
+ 1, 1, S_IRUGO)
+
+#define SRP_PID(p) \
+ (p)->port_id[0], (p)->port_id[1], (p)->port_id[2], (p)->port_id[3], \
+ (p)->port_id[4], (p)->port_id[5], (p)->port_id[6], (p)->port_id[7], \
+ (p)->port_id[8], (p)->port_id[9], (p)->port_id[10], (p)->port_id[11], \
+ (p)->port_id[12], (p)->port_id[13], (p)->port_id[14], (p)->port_id[15]
+
+#define SRP_PID_FMT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:" \
+ "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
+
+static ssize_t
+show_srp_rport_id(struct class_device *cdev, char *buf)
+{
+ struct srp_rport *rport = transport_class_to_srp_rport(cdev);
+ return sprintf(buf, SRP_PID_FMT "\n", SRP_PID(rport));
+}
+
+static CLASS_DEVICE_ATTR(port_id, S_IRUGO, show_srp_rport_id, NULL);
+
+static const struct {
+ u32 value;
+ char *name;
+} srp_rport_role_names[] = {
+ {SRP_RPORT_ROLE_INITIATOR, "SRP Initiator"},
+ {SRP_RPORT_ROLE_TARGET, "SRP Target"},
+};
+
+static ssize_t
+show_srp_rport_roles(struct class_device *cdev, char *buf)
+{
+ struct srp_rport *rport = transport_class_to_srp_rport(cdev);
+ int i;
+ char *name = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(srp_rport_role_names); i++)
+ if (srp_rport_role_names[i].value == rport->roles) {
+ name = srp_rport_role_names[i].name;
+ break;
+ }
+ return sprintf(buf, "%s\n", name ? : "unknown");
+}
+
+static CLASS_DEVICE_ATTR(roles, S_IRUGO, show_srp_rport_roles, NULL);
+
+static void srp_rport_release(struct device *dev)
+{
+ struct srp_rport *rport = dev_to_rport(dev);
+
+ put_device(dev->parent);
+ kfree(rport);
+}
+
+static int scsi_is_srp_rport(const struct device *dev)
+{
+ return dev->release == srp_rport_release;
+}
+
+static int srp_rport_match(struct attribute_container *cont,
+ struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct srp_internal *i;
+
+ if (!scsi_is_srp_rport(dev))
+ return 0;
+
+ shost = dev_to_shost(dev->parent);
+ if (!shost->transportt)
+ return 0;
+ if (shost->transportt->host_attrs.ac.class != &srp_host_class.class)
+ return 0;
+
+ i = to_srp_internal(shost->transportt);
+ return &i->rport_attr_cont.ac == cont;
+}
+
+static int srp_host_match(struct attribute_container *cont, struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct srp_internal *i;
+
+ if (!scsi_is_host_device(dev))
+ return 0;
+
+ shost = dev_to_shost(dev);
+ if (!shost->transportt)
+ return 0;
+ if (shost->transportt->host_attrs.ac.class != &srp_host_class.class)
+ return 0;
+
+ i = to_srp_internal(shost->transportt);
+ return &i->t.host_attrs.ac == cont;
+}
+
+/**
+ * srp_rport_add - add a SRP remote port to the device hierarchy
+ *
+ * @shost: scsi host the remote port is connected to.
+ * @ids: The port id for the remote port.
+ *
+ * publishes a port to the rest of the system
+ */
+struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
+ struct srp_rport_identifiers *ids)
+{
+ struct srp_rport *rport;
+ struct device *parent = &shost->shost_gendev;
+ int id, ret;
+
+ rport = kzalloc(sizeof(*rport), GFP_KERNEL);
+ if (!rport)
+ return ERR_PTR(-ENOMEM);
+
+ device_initialize(&rport->dev);
+
+ rport->dev.parent = get_device(parent);
+ rport->dev.release = srp_rport_release;
+
+ memcpy(rport->port_id, ids->port_id, sizeof(rport->port_id));
+ rport->roles = ids->roles;
+
+ id = atomic_inc_return(&to_srp_host_attrs(shost)->next_port_id);
+ sprintf(rport->dev.bus_id, "port-%d:%d", shost->host_no, id);
+
+ transport_setup_device(&rport->dev);
+
+ ret = device_add(&rport->dev);
+ if (ret) {
+ transport_destroy_device(&rport->dev);
+ put_device(&rport->dev);
+ return ERR_PTR(ret);
+ }
+
+ if (shost->active_mode & MODE_TARGET &&
+ ids->roles == SRP_RPORT_ROLE_INITIATOR) {
+ ret = srp_tgt_it_nexus_create(shost, (unsigned long)rport,
+ rport->port_id);
+ if (ret) {
+ device_del(&rport->dev);
+ transport_destroy_device(&rport->dev);
+ put_device(&rport->dev);
+ return ERR_PTR(ret);
+ }
+ }
+
+ transport_add_device(&rport->dev);
+ transport_configure_device(&rport->dev);
+
+ return rport;
+}
+EXPORT_SYMBOL_GPL(srp_rport_add);
+
+/**
+ * srp_rport_del -- remove a SRP remote port
+ * @port: SRP remote port to remove
+ *
+ * Removes the specified SRP remote port.
+ */
+void srp_rport_del(struct srp_rport *rport)
+{
+ struct device *dev = &rport->dev;
+ struct Scsi_Host *shost = dev_to_shost(dev->parent);
+
+ if (shost->active_mode & MODE_TARGET &&
+ rport->roles == SRP_RPORT_ROLE_INITIATOR)
+ srp_tgt_it_nexus_destroy(shost, (unsigned long)rport);
+
+ transport_remove_device(dev);
+ device_del(dev);
+ transport_destroy_device(dev);
+ put_device(dev);
+}
+EXPORT_SYMBOL_GPL(srp_rport_del);
+
+static int do_srp_rport_del(struct device *dev, void *data)
+{
+ srp_rport_del(dev_to_rport(dev));
+ return 0;
+}
+
+/**
+ * srp_remove_host -- tear down a Scsi_Host's SRP data structures
+ * @shost: Scsi Host that is torn down
+ *
+ * Removes all SRP remote ports for a given Scsi_Host.
+ * Must be called just before scsi_remove_host for SRP HBAs.
+ */
+void srp_remove_host(struct Scsi_Host *shost)
+{
+ device_for_each_child(&shost->shost_gendev, NULL, do_srp_rport_del);
+}
+EXPORT_SYMBOL_GPL(srp_remove_host);
+
+static int srp_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id,
+ int result)
+{
+ struct srp_internal *i = to_srp_internal(shost->transportt);
+ return i->f->tsk_mgmt_response(shost, nexus, tm_id, result);
+}
+
+static int srp_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
+{
+ struct srp_internal *i = to_srp_internal(shost->transportt);
+ return i->f->it_nexus_response(shost, nexus, result);
+}
+
+/**
+ * srp_attach_transport -- instantiate SRP transport template
+ * @ft: SRP transport class function template
+ */
+struct scsi_transport_template *
+srp_attach_transport(struct srp_function_template *ft)
+{
+ int count;
+ struct srp_internal *i;
+
+ i = kzalloc(sizeof(*i), GFP_KERNEL);
+ if (!i)
+ return NULL;
+
+ i->t.tsk_mgmt_response = srp_tsk_mgmt_response;
+ i->t.it_nexus_response = srp_it_nexus_response;
+
+ i->t.host_size = sizeof(struct srp_host_attrs);
+ i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+ i->t.host_attrs.ac.class = &srp_host_class.class;
+ i->t.host_attrs.ac.match = srp_host_match;
+ i->host_attrs[0] = NULL;
+ transport_container_register(&i->t.host_attrs);
+
+ i->rport_attr_cont.ac.attrs = &i->rport_attrs[0];
+ i->rport_attr_cont.ac.class = &srp_rport_class.class;
+ i->rport_attr_cont.ac.match = srp_rport_match;
+ transport_container_register(&i->rport_attr_cont);
+
+ count = 0;
+ SETUP_RPORT_ATTRIBUTE_RD(port_id);
+ SETUP_RPORT_ATTRIBUTE_RD(roles);
+ i->rport_attrs[count] = NULL;
+
+ i->f = ft;
+
+ return &i->t;
+}
+EXPORT_SYMBOL_GPL(srp_attach_transport);
+
+/**
+ * srp_release_transport -- release SRP transport template instance
+ * @t: transport template instance
+ */
+void srp_release_transport(struct scsi_transport_template *t)
+{
+ struct srp_internal *i = to_srp_internal(t);
+
+ transport_container_unregister(&i->t.host_attrs);
+ transport_container_unregister(&i->rport_attr_cont);
+
+ kfree(i);
+}
+EXPORT_SYMBOL_GPL(srp_release_transport);
+
+static __init int srp_transport_init(void)
+{
+ int ret;
+
+ ret = transport_class_register(&srp_host_class);
+ if (ret)
+ return ret;
+ ret = transport_class_register(&srp_rport_class);
+ if (ret)
+ goto unregister_host_class;
+
+ return 0;
+unregister_host_class:
+ transport_class_unregister(&srp_host_class);
+ return ret;
+}
+
+static void __exit srp_transport_exit(void)
+{
+ transport_class_unregister(&srp_host_class);
+ transport_class_unregister(&srp_rport_class);
+}
+
+MODULE_AUTHOR("FUJITA Tomonori");
+MODULE_DESCRIPTION("SRP Transport Attributes");
+MODULE_LICENSE("GPL");
+
+module_init(srp_transport_init);
+module_exit(srp_transport_exit);
diff --git a/drivers/scsi/scsi_transport_srp_internal.h b/drivers/scsi/scsi_transport_srp_internal.h
new file mode 100644
index 00000000000..8a79747f9f3
--- /dev/null
+++ b/drivers/scsi/scsi_transport_srp_internal.h
@@ -0,0 +1,25 @@
+#include <scsi/scsi_tgt.h>
+
+#ifdef CONFIG_SCSI_SRP_TGT_ATTRS
+static inline int srp_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+ char *initiator)
+{
+ return scsi_tgt_it_nexus_create(shost, itn_id, initiator);
+}
+
+static inline int srp_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+ return scsi_tgt_it_nexus_destroy(shost, itn_id);
+}
+
+#else
+static inline int srp_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id,
+ char *initiator)
+{
+ return 0;
+}
+static inline int srp_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id)
+{
+ return 0;
+}
+#endif
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 2c6116fd457..a69b155f39a 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -86,6 +86,19 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK);
MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD);
MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
+static int sd_revalidate_disk(struct gendisk *);
+static int sd_probe(struct device *);
+static int sd_remove(struct device *);
+static void sd_shutdown(struct device *);
+static int sd_suspend(struct device *, pm_message_t state);
+static int sd_resume(struct device *);
+static void sd_rescan(struct device *);
+static int sd_done(struct scsi_cmnd *);
+static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
+static void scsi_disk_release(struct class_device *cdev);
+static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
+static void sd_print_result(struct scsi_disk *, int);
+
static DEFINE_IDR(sd_index_idr);
static DEFINE_SPINLOCK(sd_index_lock);
@@ -240,7 +253,7 @@ static struct scsi_driver sd_template = {
.shutdown = sd_shutdown,
},
.rescan = sd_rescan,
- .init_command = sd_init_command,
+ .done = sd_done,
};
/*
@@ -331,14 +344,31 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
*
* Returns 1 if successful and 0 if error (or cannot be done now).
**/
-static int sd_init_command(struct scsi_cmnd * SCpnt)
+static int sd_prep_fn(struct request_queue *q, struct request *rq)
{
- struct scsi_device *sdp = SCpnt->device;
- struct request *rq = SCpnt->request;
+ struct scsi_cmnd *SCpnt;
+ struct scsi_device *sdp = q->queuedata;
struct gendisk *disk = rq->rq_disk;
sector_t block = rq->sector;
- unsigned int this_count = SCpnt->request_bufflen >> 9;
+ unsigned int this_count = rq->nr_sectors;
unsigned int timeout = sdp->timeout;
+ int ret;
+
+ if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
+ ret = scsi_setup_blk_pc_cmnd(sdp, rq);
+ goto out;
+ } else if (rq->cmd_type != REQ_TYPE_FS) {
+ ret = BLKPREP_KILL;
+ goto out;
+ }
+ ret = scsi_setup_fs_cmnd(sdp, rq);
+ if (ret != BLKPREP_OK)
+ goto out;
+ SCpnt = rq->special;
+
+ /* from here on until we're complete, any goto out
+ * is used for a killable error condition */
+ ret = BLKPREP_KILL;
SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
"sd_init_command: block=%llu, "
@@ -353,7 +383,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
rq->nr_sectors));
SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
"Retry with 0x%p\n", SCpnt));
- return 0;
+ goto out;
}
if (sdp->changed) {
@@ -362,8 +392,9 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
* the changed bit has been reset
*/
/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
- return 0;
+ goto out;
}
+
SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
(unsigned long long)block));
@@ -382,7 +413,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
if ((block & 1) || (rq->nr_sectors & 1)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
- return 0;
+ goto out;
} else {
block = block >> 1;
this_count = this_count >> 1;
@@ -392,7 +423,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
if ((block & 3) || (rq->nr_sectors & 3)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
- return 0;
+ goto out;
} else {
block = block >> 2;
this_count = this_count >> 2;
@@ -402,7 +433,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
if ((block & 7) || (rq->nr_sectors & 7)) {
scmd_printk(KERN_ERR, SCpnt,
"Bad block number requested\n");
- return 0;
+ goto out;
} else {
block = block >> 3;
this_count = this_count >> 3;
@@ -410,7 +441,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
}
if (rq_data_dir(rq) == WRITE) {
if (!sdp->writeable) {
- return 0;
+ goto out;
}
SCpnt->cmnd[0] = WRITE_6;
SCpnt->sc_data_direction = DMA_TO_DEVICE;
@@ -419,7 +450,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->sc_data_direction = DMA_FROM_DEVICE;
} else {
scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags);
- return 0;
+ goto out;
}
SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
@@ -470,7 +501,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
*/
scmd_printk(KERN_ERR, SCpnt,
"FUA write on READ/WRITE(6) drive\n");
- return 0;
+ goto out;
}
SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f);
@@ -492,16 +523,12 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->timeout_per_command = timeout;
/*
- * This is the completion routine we use. This is matched in terms
- * of capability to this function.
- */
- SCpnt->done = sd_rw_intr;
-
- /*
* This indicates that the command is ready from our end to be
* queued.
*/
- return 1;
+ ret = BLKPREP_OK;
+ out:
+ return scsi_prep_return(q, rq, ret);
}
/**
@@ -649,7 +676,7 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
* success as well). Returns a negated errno value in case of error.
*
* Note: most ioctls are forward onto the block subsystem or further
- * down in the scsi subsytem.
+ * down in the scsi subsystem.
**/
static int sd_ioctl(struct inode * inode, struct file * filp,
unsigned int cmd, unsigned long arg)
@@ -799,27 +826,6 @@ static int sd_sync_cache(struct scsi_disk *sdkp)
return 0;
}
-static int sd_issue_flush(struct request_queue *q, struct gendisk *disk,
- sector_t *error_sector)
-{
- int ret = 0;
- struct scsi_device *sdp = q->queuedata;
- struct scsi_disk *sdkp;
-
- if (sdp->sdev_state != SDEV_RUNNING)
- return -ENXIO;
-
- sdkp = scsi_disk_get_from_dev(&sdp->sdev_gendev);
-
- if (!sdkp)
- return -ENODEV;
-
- if (sdkp->WCE)
- ret = sd_sync_cache(sdkp);
- scsi_disk_put(sdkp);
- return ret;
-}
-
static void sd_prepare_flush(struct request_queue *q, struct request *rq)
{
memset(rq->cmd, 0, sizeof(rq->cmd));
@@ -889,13 +895,13 @@ static struct block_device_operations sd_fops = {
};
/**
- * sd_rw_intr - bottom half handler: called when the lower level
+ * sd_done - bottom half handler: called when the lower level
* driver has completed (successfully or otherwise) a scsi command.
* @SCpnt: mid-level's per command structure.
*
* Note: potentially run from within an ISR. Must not block.
**/
-static void sd_rw_intr(struct scsi_cmnd * SCpnt)
+static int sd_done(struct scsi_cmnd *SCpnt)
{
int result = SCpnt->result;
unsigned int xfer_size = SCpnt->request_bufflen;
@@ -916,7 +922,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
SCSI_LOG_HLCOMPLETE(1, scsi_print_result(SCpnt));
if (sense_valid) {
SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt,
- "sd_rw_intr: sb[respc,sk,asc,"
+ "sd_done: sb[respc,sk,asc,"
"ascq]=%x,%x,%x,%x\n",
sshdr.response_code,
sshdr.sense_key, sshdr.asc,
@@ -988,7 +994,7 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
break;
}
out:
- scsi_io_completion(SCpnt, good_bytes);
+ return good_bytes;
}
static int media_not_present(struct scsi_disk *sdkp,
@@ -1669,7 +1675,7 @@ static int sd_probe(struct device *dev)
sd_revalidate_disk(gd);
- blk_queue_issue_flush_fn(sdp->request_queue, sd_issue_flush);
+ blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
gd->driverfs_dev = &sdp->sdev_gendev;
gd->flags = GENHD_FL_DRIVERFS;
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index ce80fa9ad81..b11324479b5 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -999,14 +999,14 @@ connect_loop:
for (i = 0; i < nobuffs; ++i)
printk("scsi%d : buffer %d address = %p length = %d\n",
hostno, i,
- page_address(buffer[i].page) + buffer[i].offset,
+ sg_virt(&buffer[i]),
buffer[i].length);
}
#endif
buffer = (struct scatterlist *) SCint->request_buffer;
len = buffer->length;
- data = page_address(buffer->page) + buffer->offset;
+ data = sg_virt(buffer);
} else {
DPRINTK (DEBUG_SG, "scsi%d : scatter gather not requested.\n", hostno);
buffer = NULL;
@@ -1239,7 +1239,7 @@ connect_loop:
--nobuffs;
++buffer;
len = buffer->length;
- data = page_address(buffer->page) + buffer->offset;
+ data = sg_virt(buffer);
DPRINTK (DEBUG_SG,
"scsi%d : next scatter-gather buffer len = %d address = %08x\n",
hostno, len, data);
@@ -1396,7 +1396,7 @@ connect_loop:
--nobuffs;
++buffer;
len = buffer->length;
- data = page_address(buffer->page) + buffer->offset;
+ data = sg_virt(buffer);
DPRINTK (DEBUG_SG, "scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data);
}
break;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 85d38940a6c..f1871ea0404 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -43,6 +43,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#include <linux/poll.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
+#include <linux/idr.h>
#include <linux/seq_file.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
@@ -99,12 +100,11 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ;
#define SG_SECTOR_SZ 512
#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
-#define SG_DEV_ARR_LUMP 32 /* amount to over allocate sg_dev_arr by */
-
static int sg_add(struct class_device *, struct class_interface *);
static void sg_remove(struct class_device *, struct class_interface *);
-static DEFINE_RWLOCK(sg_dev_arr_lock); /* Also used to lock
+static DEFINE_IDR(sg_index_idr);
+static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock
file descriptor list for device */
static struct class_interface sg_interface = {
@@ -114,7 +114,7 @@ static struct class_interface sg_interface = {
typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */
unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */
- unsigned short sglist_len; /* size of malloc'd scatter-gather list ++ */
+ unsigned sglist_len; /* size of malloc'd scatter-gather list ++ */
unsigned bufflen; /* Size of (aggregate) data buffer */
unsigned b_malloc_len; /* actual len malloc'ed in buffer */
struct scatterlist *buffer;/* scatter list */
@@ -162,6 +162,7 @@ typedef struct sg_device { /* holds the state of each scsi generic device */
struct scsi_device *device;
wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */
int sg_tablesize; /* adapter's max scatter-gather table size */
+ u32 index; /* device index number */
Sg_fd *headfp; /* first open fd belonging to this device */
volatile char detached; /* 0->attached, 1->detached pending removal */
volatile char exclude; /* opened for exclusive access */
@@ -209,10 +210,6 @@ static Sg_device *sg_get_dev(int dev);
static int sg_last_dev(void);
#endif
-static Sg_device **sg_dev_arr = NULL;
-static int sg_dev_max;
-static int sg_nr_dev;
-
#define SZ_SG_HEADER sizeof(struct sg_header)
#define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
#define SZ_SG_IOVEC sizeof(sg_iovec_t)
@@ -1168,11 +1165,11 @@ sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type)
sg = rsv_schp->buffer;
sa = vma->vm_start;
for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
- ++k, ++sg) {
+ ++k, sg = sg_next(sg)) {
len = vma->vm_end - sa;
len = (len < sg->length) ? len : sg->length;
if (offset < len) {
- page = virt_to_page(page_address(sg->page) + offset);
+ page = virt_to_page(page_address(sg_page(sg)) + offset);
get_page(page); /* increment page count */
break;
}
@@ -1212,7 +1209,7 @@ sg_mmap(struct file *filp, struct vm_area_struct *vma)
sa = vma->vm_start;
sg = rsv_schp->buffer;
for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
- ++k, ++sg) {
+ ++k, sg = sg_next(sg)) {
len = vma->vm_end - sa;
len = (len < sg->length) ? len : sg->length;
sa += len;
@@ -1331,40 +1328,35 @@ static struct class *sg_sysfs_class;
static int sg_sysfs_valid = 0;
-static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
+static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
{
struct request_queue *q = scsidp->request_queue;
Sg_device *sdp;
unsigned long iflags;
- void *old_sg_dev_arr = NULL;
- int k, error;
+ int error;
+ u32 k;
sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL);
if (!sdp) {
printk(KERN_WARNING "kmalloc Sg_device failure\n");
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
+ }
+ error = -ENOMEM;
+ if (!idr_pre_get(&sg_index_idr, GFP_KERNEL)) {
+ printk(KERN_WARNING "idr expansion Sg_device failure\n");
+ goto out;
}
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
- if (unlikely(sg_nr_dev >= sg_dev_max)) { /* try to resize */
- Sg_device **tmp_da;
- int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP;
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-
- tmp_da = kzalloc(tmp_dev_max * sizeof(Sg_device *), GFP_KERNEL);
- if (unlikely(!tmp_da))
- goto expand_failed;
+ write_lock_irqsave(&sg_index_lock, iflags);
+ error = idr_get_new(&sg_index_idr, sdp, &k);
+ write_unlock_irqrestore(&sg_index_lock, iflags);
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
- memcpy(tmp_da, sg_dev_arr, sg_dev_max * sizeof(Sg_device *));
- old_sg_dev_arr = sg_dev_arr;
- sg_dev_arr = tmp_da;
- sg_dev_max = tmp_dev_max;
+ if (error) {
+ printk(KERN_WARNING "idr allocation Sg_device failure: %d\n",
+ error);
+ goto out;
}
- for (k = 0; k < sg_dev_max; k++)
- if (!sg_dev_arr[k])
- break;
if (unlikely(k >= SG_MAX_DEVS))
goto overflow;
@@ -1375,25 +1367,17 @@ static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
sdp->device = scsidp;
init_waitqueue_head(&sdp->o_excl_wait);
sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments);
+ sdp->index = k;
- sg_nr_dev++;
- sg_dev_arr[k] = sdp;
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
- error = k;
-
+ error = 0;
out:
- if (error < 0)
+ if (error) {
kfree(sdp);
- kfree(old_sg_dev_arr);
- return error;
-
- expand_failed:
- printk(KERN_WARNING "sg_alloc: device array cannot be resized\n");
- error = -ENOMEM;
- goto out;
+ return ERR_PTR(error);
+ }
+ return sdp;
overflow:
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
sdev_printk(KERN_WARNING, scsidp,
"Unable to attach sg device type=%d, minor "
"number exceeds %d\n", scsidp->type, SG_MAX_DEVS - 1);
@@ -1408,7 +1392,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
struct gendisk *disk;
Sg_device *sdp = NULL;
struct cdev * cdev = NULL;
- int error, k;
+ int error;
unsigned long iflags;
disk = alloc_disk(1);
@@ -1427,15 +1411,15 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
cdev->owner = THIS_MODULE;
cdev->ops = &sg_fops;
- error = sg_alloc(disk, scsidp);
- if (error < 0) {
+ sdp = sg_alloc(disk, scsidp);
+ if (IS_ERR(sdp)) {
printk(KERN_WARNING "sg_alloc failed\n");
+ error = PTR_ERR(sdp);
goto out;
}
- k = error;
- sdp = sg_dev_arr[k];
- error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1);
+ class_set_devdata(cl_dev, sdp);
+ error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1);
if (error)
goto cdev_add_err;
@@ -1444,8 +1428,8 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
struct class_device * sg_class_member;
sg_class_member = class_device_create(sg_sysfs_class, NULL,
- MKDEV(SCSI_GENERIC_MAJOR, k),
- cl_dev->dev, "%s",
+ MKDEV(SCSI_GENERIC_MAJOR, sdp->index),
+ cl_dev->dev, "%s",
disk->disk_name);
if (IS_ERR(sg_class_member))
printk(KERN_WARNING "sg_add: "
@@ -1455,21 +1439,21 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
&sg_class_member->kobj, "generic");
if (error)
printk(KERN_ERR "sg_add: unable to make symlink "
- "'generic' back to sg%d\n", k);
+ "'generic' back to sg%d\n", sdp->index);
} else
- printk(KERN_WARNING "sg_add: sg_sys INvalid\n");
+ printk(KERN_WARNING "sg_add: sg_sys Invalid\n");
sdev_printk(KERN_NOTICE, scsidp,
- "Attached scsi generic sg%d type %d\n", k,scsidp->type);
+ "Attached scsi generic sg%d type %d\n", sdp->index,
+ scsidp->type);
return 0;
cdev_add_err:
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
- kfree(sg_dev_arr[k]);
- sg_dev_arr[k] = NULL;
- sg_nr_dev--;
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+ write_lock_irqsave(&sg_index_lock, iflags);
+ idr_remove(&sg_index_idr, sdp->index);
+ write_unlock_irqrestore(&sg_index_lock, iflags);
+ kfree(sdp);
out:
put_disk(disk);
@@ -1482,64 +1466,56 @@ static void
sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf)
{
struct scsi_device *scsidp = to_scsi_device(cl_dev->dev);
- Sg_device *sdp = NULL;
+ Sg_device *sdp = class_get_devdata(cl_dev);
unsigned long iflags;
Sg_fd *sfp;
Sg_fd *tsfp;
Sg_request *srp;
Sg_request *tsrp;
- int k, delay;
+ int delay;
- if (NULL == sg_dev_arr)
+ if (!sdp)
return;
+
delay = 0;
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
- for (k = 0; k < sg_dev_max; k++) {
- sdp = sg_dev_arr[k];
- if ((NULL == sdp) || (sdp->device != scsidp))
- continue; /* dirty but lowers nesting */
- if (sdp->headfp) {
- sdp->detached = 1;
- for (sfp = sdp->headfp; sfp; sfp = tsfp) {
- tsfp = sfp->nextfp;
- for (srp = sfp->headrp; srp; srp = tsrp) {
- tsrp = srp->nextrp;
- if (sfp->closed || (0 == sg_srp_done(srp, sfp)))
- sg_finish_rem_req(srp);
- }
- if (sfp->closed) {
- scsi_device_put(sdp->device);
- __sg_remove_sfp(sdp, sfp);
- } else {
- delay = 1;
- wake_up_interruptible(&sfp->read_wait);
- kill_fasync(&sfp->async_qp, SIGPOLL,
- POLL_HUP);
- }
+ write_lock_irqsave(&sg_index_lock, iflags);
+ if (sdp->headfp) {
+ sdp->detached = 1;
+ for (sfp = sdp->headfp; sfp; sfp = tsfp) {
+ tsfp = sfp->nextfp;
+ for (srp = sfp->headrp; srp; srp = tsrp) {
+ tsrp = srp->nextrp;
+ if (sfp->closed || (0 == sg_srp_done(srp, sfp)))
+ sg_finish_rem_req(srp);
}
- SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", k));
- if (NULL == sdp->headfp) {
- sg_dev_arr[k] = NULL;
+ if (sfp->closed) {
+ scsi_device_put(sdp->device);
+ __sg_remove_sfp(sdp, sfp);
+ } else {
+ delay = 1;
+ wake_up_interruptible(&sfp->read_wait);
+ kill_fasync(&sfp->async_qp, SIGPOLL,
+ POLL_HUP);
}
- } else { /* nothing active, simple case */
- SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", k));
- sg_dev_arr[k] = NULL;
}
- sg_nr_dev--;
- break;
- }
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-
- if (sdp) {
- sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
- class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, k));
- cdev_del(sdp->cdev);
- sdp->cdev = NULL;
- put_disk(sdp->disk);
- sdp->disk = NULL;
- if (NULL == sdp->headfp)
- kfree((char *) sdp);
- }
+ SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", sdp->index));
+ if (NULL == sdp->headfp) {
+ idr_remove(&sg_index_idr, sdp->index);
+ }
+ } else { /* nothing active, simple case */
+ SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", sdp->index));
+ idr_remove(&sg_index_idr, sdp->index);
+ }
+ write_unlock_irqrestore(&sg_index_lock, iflags);
+
+ sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
+ class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index));
+ cdev_del(sdp->cdev);
+ sdp->cdev = NULL;
+ put_disk(sdp->disk);
+ sdp->disk = NULL;
+ if (NULL == sdp->headfp)
+ kfree(sdp);
if (delay)
msleep(10); /* dirty detach so delay device destruction */
@@ -1609,9 +1585,7 @@ exit_sg(void)
sg_sysfs_valid = 0;
unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
SG_MAX_DEVS);
- kfree((char *)sg_dev_arr);
- sg_dev_arr = NULL;
- sg_dev_max = 0;
+ idr_destroy(&sg_index_idr);
}
static int
@@ -1678,6 +1652,7 @@ sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, int tablesize)
schp->buffer = kzalloc(sg_bufflen, gfp_flags);
if (!schp->buffer)
return -ENOMEM;
+ sg_init_table(schp->buffer, tablesize);
schp->sglist_len = sg_bufflen;
return tablesize; /* number of scat_gath elements allocated */
}
@@ -1743,16 +1718,12 @@ st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages,
goto out_unlock; */
}
- sgl[0].page = pages[0];
- sgl[0].offset = uaddr & ~PAGE_MASK;
+ sg_set_page(sgl, pages[0], 0, uaddr & ~PAGE_MASK);
if (nr_pages > 1) {
sgl[0].length = PAGE_SIZE - sgl[0].offset;
count -= sgl[0].length;
- for (i=1; i < nr_pages ; i++) {
- sgl[i].page = pages[i];
- sgl[i].length = count < PAGE_SIZE ? count : PAGE_SIZE;
- count -= PAGE_SIZE;
- }
+ for (i=1; i < nr_pages ; i++)
+ sg_set_page(&sgl[i], pages[i], count < PAGE_SIZE ? count : PAGE_SIZE, 0);
}
else {
sgl[0].length = count;
@@ -1780,7 +1751,7 @@ st_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages,
int i;
for (i=0; i < nr_pages; i++) {
- struct page *page = sgl[i].page;
+ struct page *page = sg_page(&sgl[i]);
if (dirtied)
SetPageDirty(page);
@@ -1866,7 +1837,7 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
}
for (k = 0, sg = schp->buffer, rem_sz = blk_size;
(rem_sz > 0) && (k < mx_sc_elems);
- ++k, rem_sz -= ret_sz, ++sg) {
+ ++k, rem_sz -= ret_sz, sg = sg_next(sg)) {
num = (rem_sz > scatter_elem_sz_prev) ?
scatter_elem_sz_prev : rem_sz;
@@ -1880,8 +1851,7 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
scatter_elem_sz_prev = ret_sz;
}
}
- sg->page = p;
- sg->length = (ret_sz > num) ? num : ret_sz;
+ sg_set_page(sg, p, (ret_sz > num) ? num : ret_sz, 0);
SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k=%d, num=%d, "
"ret_sz=%d\n", k, num, ret_sz));
@@ -1933,14 +1903,14 @@ sg_write_xfer(Sg_request * srp)
onum = 1;
ksglen = sg->length;
- p = page_address(sg->page);
+ p = page_address(sg_page(sg));
for (j = 0, k = 0; j < onum; ++j) {
res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
if (res)
return res;
- for (; p; ++sg, ksglen = sg->length,
- p = page_address(sg->page)) {
+ for (; p; sg = sg_next(sg), ksglen = sg->length,
+ p = page_address(sg_page(sg))) {
if (usglen <= 0)
break;
if (ksglen > usglen) {
@@ -2017,12 +1987,12 @@ sg_remove_scat(Sg_scatter_hold * schp)
} else {
int k;
- for (k = 0; (k < schp->k_use_sg) && sg->page;
- ++k, ++sg) {
+ for (k = 0; (k < schp->k_use_sg) && sg_page(sg);
+ ++k, sg = sg_next(sg)) {
SCSI_LOG_TIMEOUT(5, printk(
"sg_remove_scat: k=%d, pg=0x%p, len=%d\n",
- k, sg->page, sg->length));
- sg_page_free(sg->page, sg->length);
+ k, sg_page(sg), sg->length));
+ sg_page_free(sg_page(sg), sg->length);
}
}
kfree(schp->buffer);
@@ -2064,15 +2034,15 @@ sg_read_xfer(Sg_request * srp)
} else
onum = 1;
- p = page_address(sg->page);
+ p = page_address(sg_page(sg));
ksglen = sg->length;
for (j = 0, k = 0; j < onum; ++j) {
res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
if (res)
return res;
- for (; p; ++sg, ksglen = sg->length,
- p = page_address(sg->page)) {
+ for (; p; sg = sg_next(sg), ksglen = sg->length,
+ p = page_address(sg_page(sg))) {
if (usglen <= 0)
break;
if (ksglen > usglen) {
@@ -2118,15 +2088,15 @@ sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer)
if ((!outp) || (num_read_xfer <= 0))
return 0;
- for (k = 0; (k < schp->k_use_sg) && sg->page; ++k, ++sg) {
+ for (k = 0; (k < schp->k_use_sg) && sg_page(sg); ++k, sg = sg_next(sg)) {
num = sg->length;
if (num > num_read_xfer) {
- if (__copy_to_user(outp, page_address(sg->page),
+ if (__copy_to_user(outp, page_address(sg_page(sg)),
num_read_xfer))
return -EFAULT;
break;
} else {
- if (__copy_to_user(outp, page_address(sg->page),
+ if (__copy_to_user(outp, page_address(sg_page(sg)),
num))
return -EFAULT;
num_read_xfer -= num;
@@ -2168,7 +2138,7 @@ sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size));
rem = size;
- for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sg) {
+ for (k = 0; k < rsv_schp->k_use_sg; ++k, sg = sg_next(sg)) {
num = sg->length;
if (rem <= num) {
sfp->save_scat_len = num;
@@ -2331,10 +2301,10 @@ sg_get_nth_sfp(Sg_device * sdp, int nth)
unsigned long iflags;
int k;
- read_lock_irqsave(&sg_dev_arr_lock, iflags);
+ read_lock_irqsave(&sg_index_lock, iflags);
for (k = 0, resp = sdp->headfp; resp && (k < nth);
++k, resp = resp->nextfp) ;
- read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+ read_unlock_irqrestore(&sg_index_lock, iflags);
return resp;
}
#endif
@@ -2361,7 +2331,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
sfp->cmd_q = SG_DEF_COMMAND_Q;
sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
sfp->parentdp = sdp;
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
+ write_lock_irqsave(&sg_index_lock, iflags);
if (!sdp->headfp)
sdp->headfp = sfp;
else { /* add to tail of existing list */
@@ -2370,7 +2340,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
pfp = pfp->nextfp;
pfp->nextfp = sfp;
}
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+ write_unlock_irqrestore(&sg_index_lock, iflags);
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
if (unlikely(sg_big_buff != def_reserved_size))
sg_big_buff = def_reserved_size;
@@ -2431,22 +2401,14 @@ sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
if (0 == dirty) {
unsigned long iflags;
- write_lock_irqsave(&sg_dev_arr_lock, iflags);
+ write_lock_irqsave(&sg_index_lock, iflags);
__sg_remove_sfp(sdp, sfp);
if (sdp->detached && (NULL == sdp->headfp)) {
- int k, maxd;
-
- maxd = sg_dev_max;
- for (k = 0; k < maxd; ++k) {
- if (sdp == sg_dev_arr[k])
- break;
- }
- if (k < maxd)
- sg_dev_arr[k] = NULL;
- kfree((char *) sdp);
+ idr_remove(&sg_index_idr, sdp->index);
+ kfree(sdp);
res = 1;
}
- write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+ write_unlock_irqrestore(&sg_index_lock, iflags);
} else {
/* MOD_INC's to inhibit unloading sg and associated adapter driver */
/* only bump the access_count if we actually succeeded in
@@ -2546,16 +2508,25 @@ sg_allow_access(unsigned char opcode, char dev_type)
#ifdef CONFIG_SCSI_PROC_FS
static int
+sg_idr_max_id(int id, void *p, void *data)
+{
+ int *k = data;
+
+ if (*k < id)
+ *k = id;
+
+ return 0;
+}
+
+static int
sg_last_dev(void)
{
- int k;
+ int k = 0;
unsigned long iflags;
- read_lock_irqsave(&sg_dev_arr_lock, iflags);
- for (k = sg_dev_max - 1; k >= 0; --k)
- if (sg_dev_arr[k] && sg_dev_arr[k]->device)
- break;
- read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+ read_lock_irqsave(&sg_index_lock, iflags);
+ idr_for_each(&sg_index_idr, sg_idr_max_id, &k);
+ read_unlock_irqrestore(&sg_index_lock, iflags);
return k + 1; /* origin 1 */
}
#endif
@@ -2563,15 +2534,13 @@ sg_last_dev(void)
static Sg_device *
sg_get_dev(int dev)
{
- Sg_device *sdp = NULL;
+ Sg_device *sdp;
unsigned long iflags;
- if (sg_dev_arr && (dev >= 0)) {
- read_lock_irqsave(&sg_dev_arr_lock, iflags);
- if (dev < sg_dev_max)
- sdp = sg_dev_arr[dev];
- read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
- }
+ read_lock_irqsave(&sg_index_lock, iflags);
+ sdp = idr_find(&sg_index_idr, dev);
+ read_unlock_irqrestore(&sg_index_lock, iflags);
+
return sdp;
}
@@ -2805,8 +2774,6 @@ static void * dev_seq_start(struct seq_file *s, loff_t *pos)
if (! it)
return NULL;
- if (NULL == sg_dev_arr)
- return NULL;
it->index = *pos;
it->max = sg_last_dev();
if (it->index >= it->max)
@@ -2942,8 +2909,8 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
Sg_device *sdp;
if (it && (0 == it->index)) {
- seq_printf(s, "dev_max(currently)=%d max_active_device=%d "
- "(origin 1)\n", sg_dev_max, (int)it->max);
+ seq_printf(s, "max_active_device=%d(origin 1)\n",
+ (int)it->max);
seq_printf(s, " def_reserved_size=%d\n", sg_big_buff);
}
sdp = it ? sg_get_dev(it->index) : NULL;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 902eb11ffe8..c6199903114 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -78,7 +78,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM);
static int sr_probe(struct device *);
static int sr_remove(struct device *);
-static int sr_init_command(struct scsi_cmnd *);
+static int sr_done(struct scsi_cmnd *);
static struct scsi_driver sr_template = {
.owner = THIS_MODULE,
@@ -87,7 +87,7 @@ static struct scsi_driver sr_template = {
.probe = sr_probe,
.remove = sr_remove,
},
- .init_command = sr_init_command,
+ .done = sr_done,
};
static unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG];
@@ -210,12 +210,12 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot)
}
/*
- * rw_intr is the interrupt routine for the device driver.
+ * sr_done is the interrupt routine for the device driver.
*
- * It will be notified on the end of a SCSI read / write, and will take on
+ * It will be notified on the end of a SCSI read / write, and will take one
* of several actions based on success or failure.
*/
-static void rw_intr(struct scsi_cmnd * SCpnt)
+static int sr_done(struct scsi_cmnd *SCpnt)
{
int result = SCpnt->result;
int this_count = SCpnt->request_bufflen;
@@ -288,27 +288,42 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
}
}
- /*
- * This calls the generic completion function, now that we know
- * how many actual sectors finished, and how many sectors we need
- * to say have failed.
- */
- scsi_io_completion(SCpnt, good_bytes);
+ return good_bytes;
}
-static int sr_init_command(struct scsi_cmnd * SCpnt)
+static int sr_prep_fn(struct request_queue *q, struct request *rq)
{
int block=0, this_count, s_size, timeout = SR_TIMEOUT;
- struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
+ struct scsi_cd *cd;
+ struct scsi_cmnd *SCpnt;
+ struct scsi_device *sdp = q->queuedata;
+ int ret;
+
+ if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
+ ret = scsi_setup_blk_pc_cmnd(sdp, rq);
+ goto out;
+ } else if (rq->cmd_type != REQ_TYPE_FS) {
+ ret = BLKPREP_KILL;
+ goto out;
+ }
+ ret = scsi_setup_fs_cmnd(sdp, rq);
+ if (ret != BLKPREP_OK)
+ goto out;
+ SCpnt = rq->special;
+ cd = scsi_cd(rq->rq_disk);
+
+ /* from here on until we're complete, any goto out
+ * is used for a killable error condition */
+ ret = BLKPREP_KILL;
SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n",
cd->disk->disk_name, block));
if (!cd->device || !scsi_device_online(cd->device)) {
SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n",
- SCpnt->request->nr_sectors));
+ rq->nr_sectors));
SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
- return 0;
+ goto out;
}
if (cd->device->changed) {
@@ -316,7 +331,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
* quietly refuse to do anything to a changed disc until the
* changed bit has been reset
*/
- return 0;
+ goto out;
}
/*
@@ -333,21 +348,21 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
if (s_size != 512 && s_size != 1024 && s_size != 2048) {
scmd_printk(KERN_ERR, SCpnt, "bad sector size %d\n", s_size);
- return 0;
+ goto out;
}
- if (rq_data_dir(SCpnt->request) == WRITE) {
+ if (rq_data_dir(rq) == WRITE) {
if (!cd->device->writeable)
- return 0;
+ goto out;
SCpnt->cmnd[0] = WRITE_10;
SCpnt->sc_data_direction = DMA_TO_DEVICE;
cd->cdi.media_written = 1;
- } else if (rq_data_dir(SCpnt->request) == READ) {
+ } else if (rq_data_dir(rq) == READ) {
SCpnt->cmnd[0] = READ_10;
SCpnt->sc_data_direction = DMA_FROM_DEVICE;
} else {
- blk_dump_rq_flags(SCpnt->request, "Unknown sr command");
- return 0;
+ blk_dump_rq_flags(rq, "Unknown sr command");
+ goto out;
}
{
@@ -368,10 +383,10 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
/*
* request doesn't start on hw block boundary, add scatter pads
*/
- if (((unsigned int)SCpnt->request->sector % (s_size >> 9)) ||
+ if (((unsigned int)rq->sector % (s_size >> 9)) ||
(SCpnt->request_bufflen % s_size)) {
scmd_printk(KERN_NOTICE, SCpnt, "unaligned transfer\n");
- return 0;
+ goto out;
}
this_count = (SCpnt->request_bufflen >> 9) / (s_size >> 9);
@@ -379,12 +394,12 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
cd->cdi.name,
- (rq_data_dir(SCpnt->request) == WRITE) ?
+ (rq_data_dir(rq) == WRITE) ?
"writing" : "reading",
- this_count, SCpnt->request->nr_sectors));
+ this_count, rq->nr_sectors));
SCpnt->cmnd[1] = 0;
- block = (unsigned int)SCpnt->request->sector / (s_size >> 9);
+ block = (unsigned int)rq->sector / (s_size >> 9);
if (this_count > 0xffff) {
this_count = 0xffff;
@@ -410,16 +425,12 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
SCpnt->timeout_per_command = timeout;
/*
- * This is the completion routine we use. This is matched in terms
- * of capability to this function.
- */
- SCpnt->done = rw_intr;
-
- /*
* This indicates that the command is ready from our end to be
* queued.
*/
- return 1;
+ ret = BLKPREP_OK;
+ out:
+ return scsi_prep_return(q, rq, ret);
}
static int sr_block_open(struct inode *inode, struct file *file)
@@ -590,6 +601,7 @@ static int sr_probe(struct device *dev)
/* FIXME: need to handle a get_capabilities failure properly ?? */
get_capabilities(cd);
+ blk_queue_prep_rq(sdev->request_queue, sr_prep_fn);
sr_vendor_init(cd);
disk->driverfs_dev = &sdev->sdev_gendev;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 73c44cbdea4..98dfd6ea209 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -3797,13 +3797,11 @@ static void buf_to_sg(struct st_buffer *STbp, unsigned int length)
sg = &(STbp->sg[0]);
frp = STbp->frp;
for (i=count=0; count < length; i++) {
- sg[i].page = frp[i].page;
if (length - count > frp[i].length)
- sg[i].length = frp[i].length;
+ sg_set_page(&sg[i], frp[i].page, frp[i].length, 0);
else
- sg[i].length = length - count;
+ sg_set_page(&sg[i], frp[i].page, length - count, 0);
count += sg[i].length;
- sg[i].offset = 0;
}
STbp->sg_segs = i;
STbp->frp_sg_current = length;
@@ -4446,15 +4444,13 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa
}
/* Populate the scatter/gather list */
- sgl[0].page = pages[0];
- sgl[0].offset = uaddr & ~PAGE_MASK;
+ sg_set_page(&sgl[0], pages[0], 0, uaddr & ~PAGE_MASK);
if (nr_pages > 1) {
sgl[0].length = PAGE_SIZE - sgl[0].offset;
count -= sgl[0].length;
for (i=1; i < nr_pages ; i++) {
- sgl[i].offset = 0;
- sgl[i].page = pages[i];
- sgl[i].length = count < PAGE_SIZE ? count : PAGE_SIZE;
+ sg_set_page(&sgl[i], pages[i],
+ count < PAGE_SIZE ? count : PAGE_SIZE, 0);;
count -= PAGE_SIZE;
}
}
@@ -4483,7 +4479,7 @@ static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_p
int i;
for (i=0; i < nr_pages; i++) {
- struct page *page = sgl[i].page;
+ struct page *page = sg_page(&sgl[i]);
if (dirtied)
SetPageDirty(page);
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 72f6d801535..e3fab3a6aed 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -1123,6 +1123,7 @@ static struct scsi_host_template driver_template = {
.this_id = -1,
.sg_tablesize = ST_MAX_SG,
.cmd_per_lun = ST_CMD_PER_LUN,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
static int stex_set_dma_mask(struct pci_dev * pdev)
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 98e3fe10c1d..2dcde373b20 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -272,8 +272,7 @@ static struct scsi_host_template *the_template = NULL;
#define HOSTNO instance->host_no
#define H_NO(cmd) (cmd)->device->host->host_no
-#define SGADDR(buffer) (void *)(((unsigned long)page_address((buffer)->page)) + \
- (buffer)->offset)
+#define SGADDR(buffer) (void *)(((unsigned long)sg_virt(((buffer)))))
#ifdef SUPPORT_TAGS
@@ -1596,7 +1595,7 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd,
* IO while SEL is true. But again, there are some disks out the in the
* world that do that nevertheless. (Somebody claimed that this announces
* reselection capability of the target.) So we better skip that test and
- * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
+ * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
*/
while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) &
@@ -2055,7 +2054,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
+ cmd->scsi_done(cmd);
return;
#endif
case PHASE_DATAIN:
@@ -2115,7 +2114,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
sink = 1;
do_abort(instance);
cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
+ cmd->scsi_done(cmd);
/* XXX - need to source or sink data here, as appropriate */
} else {
#ifdef REAL_DMA
@@ -2254,25 +2253,21 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
#ifdef AUTOSENSE
+ if ((cmd->cmnd[0] == REQUEST_SENSE) &&
+ hostdata->ses.cmd_len) {
+ scsi_eh_restore_cmnd(cmd, &hostdata->ses);
+ hostdata->ses.cmd_len = 0 ;
+ }
+
if ((cmd->cmnd[0] != REQUEST_SENSE) &&
(status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+ scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
ASEN_PRINTK("scsi%d: performing request sense\n",
HOSTNO);
- cmd->cmnd[0] = REQUEST_SENSE;
- cmd->cmnd[1] &= 0xe0;
- cmd->cmnd[2] = 0;
- cmd->cmnd[3] = 0;
- cmd->cmnd[4] = sizeof(cmd->sense_buffer);
- cmd->cmnd[5] = 0;
- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
- cmd->use_sg = 0;
/* this is initialized from initialize_SCp
cmd->SCp.buffer = NULL;
cmd->SCp.buffers_residual = 0;
*/
- cmd->request_buffer = (char *) cmd->sense_buffer;
- cmd->request_bufflen = sizeof(cmd->sense_buffer);
local_irq_save(flags);
LIST(cmd,hostdata->issue_queue);
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index 80fb3f88af2..1bc41907a03 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -332,8 +332,8 @@ static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
struct scatterlist *sg = sp->SCp.buffer;
while (sz >= 0) {
- sg[sz].dma_address = dvma_map((unsigned long)page_address(sg[sz].page) +
- sg[sz].offset, sg[sz].length);
+ sg[sz].dma_address = dvma_map((unsigned long)sg_virt(&sg[sz]),
+ sg[sz].length);
sz--;
}
sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dma_address);
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index 92bfaeafe30..90cee94d952 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -196,7 +196,7 @@ static unsigned int sym53c416_base_3[2] = {0,0};
#define MAXHOSTS 4
-#define SG_ADDRESS(buffer) ((char *) (page_address((buffer)->page)+(buffer)->offset))
+#define SG_ADDRESS(buffer) ((char *) sg_virt((buffer)))
enum phases
{
@@ -854,5 +854,6 @@ static struct scsi_host_template driver_template = {
.cmd_per_lun = 1,
.unchecked_isa_dma = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
#include "scsi_module.c"
diff --git a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
index 7519728dfc3..62d29cfac9e 100644
--- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h
+++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
@@ -127,7 +127,6 @@ struct sym_driver_setup {
u_char settle_delay;
u_char use_nvram;
u_long excludes[8];
- char tag_ctrl[100];
};
#define SYM_SETUP_MAX_TAG sym_driver_setup.max_tag
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw.c b/drivers/scsi/sym53c8xx_2/sym_fw.c
index 9916a2a2255..190770bdc19 100644
--- a/drivers/scsi/sym53c8xx_2/sym_fw.c
+++ b/drivers/scsi/sym53c8xx_2/sym_fw.c
@@ -104,8 +104,9 @@ static struct sym_fwz_ofs sym_fw2z_ofs = {
* Patch routine for firmware #1.
*/
static void
-sym_fw1_patch(struct sym_hcb *np)
+sym_fw1_patch(struct Scsi_Host *shost)
{
+ struct sym_hcb *np = sym_get_hcb(shost);
struct sym_fw1a_scr *scripta0;
struct sym_fw1b_scr *scriptb0;
@@ -145,8 +146,11 @@ sym_fw1_patch(struct sym_hcb *np)
* Patch routine for firmware #2.
*/
static void
-sym_fw2_patch(struct sym_hcb *np)
+sym_fw2_patch(struct Scsi_Host *shost)
{
+ struct sym_data *sym_data = shost_priv(shost);
+ struct pci_dev *pdev = sym_data->pdev;
+ struct sym_hcb *np = sym_data->ncb;
struct sym_fw2a_scr *scripta0;
struct sym_fw2b_scr *scriptb0;
@@ -167,7 +171,7 @@ sym_fw2_patch(struct sym_hcb *np)
* Remove useless 64 bit DMA specific SCRIPTS,
* when this feature is not available.
*/
- if (!np->use_dac) {
+ if (!use_dac(np)) {
scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP);
scripta0->is_dmap_dirty[1] = 0;
scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP);
@@ -205,14 +209,14 @@ sym_fw2_patch(struct sym_hcb *np)
* Remove a couple of work-arounds specific to C1010 if
* they are not desirable. See `sym_fw2.h' for more details.
*/
- if (!(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 &&
- np->revision_id < 0x1 &&
+ if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_66 &&
+ pdev->revision < 0x1 &&
np->pciclk_khz < 60000)) {
scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP);
scripta0->datao_phase[1] = cpu_to_scr(0);
}
- if (!(np->device_id == PCI_DEVICE_ID_LSI_53C1010_33 &&
- /* np->revision_id < 0xff */ 1)) {
+ if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 /* &&
+ pdev->revision < 0xff */)) {
scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP);
scripta0->sel_done[1] = cpu_to_scr(0);
}
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw.h b/drivers/scsi/sym53c8xx_2/sym_fw.h
index 66ec35beab5..ae7e0f9e93f 100644
--- a/drivers/scsi/sym53c8xx_2/sym_fw.h
+++ b/drivers/scsi/sym53c8xx_2/sym_fw.h
@@ -143,7 +143,7 @@ struct sym_fw {
*z_ofs; /* Useful offsets in script Z */
/* Setup and patch methods for this firmware */
void (*setup)(struct sym_hcb *, struct sym_fw *);
- void (*patch)(struct sym_hcb *);
+ void (*patch)(struct Scsi_Host *);
};
/*
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw2.h b/drivers/scsi/sym53c8xx_2/sym_fw2.h
index 6e5b952312e..ae1fb179b88 100644
--- a/drivers/scsi/sym53c8xx_2/sym_fw2.h
+++ b/drivers/scsi/sym53c8xx_2/sym_fw2.h
@@ -1781,7 +1781,7 @@ static struct SYM_FWB_SCR SYM_FWB_SCR = {
* While testing with bogus QUANTUM drives, the C1010
* sometimes raised a spurious phase mismatch with
* WSR and the CHMOV(1) triggered another PM.
- * Waiting explicitely for the PHASE seemed to avoid
+ * Waiting explicitly for the PHASE seemed to avoid
* the nested phase mismatch. Btw, this didn't happen
* using my IBM drives.
*/
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 3db22325ea2..0f74aba5b23 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -39,7 +39,6 @@
*/
#include <linux/ctype.h>
#include <linux/init.h>
-#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
@@ -54,16 +53,12 @@
#define NAME53C "sym53c"
#define NAME53C8XX "sym53c8xx"
-#define IRQ_FMT "%d"
-#define IRQ_PRM(x) (x)
-
struct sym_driver_setup sym_driver_setup = SYM_LINUX_DRIVER_SETUP;
unsigned int sym_debug_flags = 0;
static char *excl_string;
static char *safe_string;
module_param_named(cmd_per_lun, sym_driver_setup.max_tag, ushort, 0);
-module_param_string(tag_ctrl, sym_driver_setup.tag_ctrl, 100, 0);
module_param_named(burst, sym_driver_setup.burst_order, byte, 0);
module_param_named(led, sym_driver_setup.scsi_led, byte, 0);
module_param_named(diff, sym_driver_setup.scsi_diff, byte, 0);
@@ -78,7 +73,6 @@ module_param_named(excl, excl_string, charp, 0);
module_param_named(safe, safe_string, charp, 0);
MODULE_PARM_DESC(cmd_per_lun, "The maximum number of tags to use by default");
-MODULE_PARM_DESC(tag_ctrl, "More detailed control over tags per LUN");
MODULE_PARM_DESC(burst, "Maximum burst. 0 to disable, 255 to read from registers");
MODULE_PARM_DESC(led, "Set to 1 to enable LED support");
MODULE_PARM_DESC(diff, "0 for no differential mode, 1 for BIOS, 2 for always, 3 for not GPIO3");
@@ -134,56 +128,26 @@ static struct scsi_transport_template *sym2_transport_template = NULL;
* Driver private area in the SCSI command structure.
*/
struct sym_ucmd { /* Override the SCSI pointer structure */
- dma_addr_t data_mapping;
- unsigned char data_mapped;
- unsigned char to_do; /* For error handling */
- void (*old_done)(struct scsi_cmnd *); /* For error handling */
- struct completion *eh_done; /* For error handling */
+ struct completion *eh_done; /* SCSI error handling */
};
#define SYM_UCMD_PTR(cmd) ((struct sym_ucmd *)(&(cmd)->SCp))
#define SYM_SOFTC_PTR(cmd) sym_get_hcb(cmd->device->host)
-static void __unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
- if (SYM_UCMD_PTR(cmd)->data_mapped)
- scsi_dma_unmap(cmd);
-
- SYM_UCMD_PTR(cmd)->data_mapped = 0;
-}
-
-static int __map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
- int use_sg;
-
- use_sg = scsi_dma_map(cmd);
- if (use_sg > 0) {
- SYM_UCMD_PTR(cmd)->data_mapped = 2;
- SYM_UCMD_PTR(cmd)->data_mapping = use_sg;
- }
-
- return use_sg;
-}
-
-#define unmap_scsi_data(np, cmd) \
- __unmap_scsi_data(np->s.device, cmd)
-#define map_scsi_sg_data(np, cmd) \
- __map_scsi_sg_data(np->s.device, cmd)
/*
* Complete a pending CAM CCB.
*/
void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *cmd)
{
- unmap_scsi_data(np, cmd);
- cmd->scsi_done(cmd);
-}
+ struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
+ BUILD_BUG_ON(sizeof(struct scsi_pointer) < sizeof(struct sym_ucmd));
-static void sym_xpt_done2(struct sym_hcb *np, struct scsi_cmnd *cmd, int cam_status)
-{
- sym_set_cam_status(cmd, cam_status);
- sym_xpt_done(np, cmd);
-}
+ if (ucmd->eh_done)
+ complete(ucmd->eh_done);
+ scsi_dma_unmap(cmd);
+ cmd->scsi_done(cmd);
+}
/*
* Tell the SCSI layer about a BUS RESET.
@@ -199,14 +163,6 @@ void sym_xpt_async_bus_reset(struct sym_hcb *np)
}
/*
- * Tell the SCSI layer about a BUS DEVICE RESET message sent.
- */
-void sym_xpt_async_sent_bdr(struct sym_hcb *np, int target)
-{
- printf_notice("%s: TARGET %d has been reset.\n", sym_name(np), target);
-}
-
-/*
* Choose the more appropriate CAM status if
* the IO encountered an extended error.
*/
@@ -307,14 +263,14 @@ static int sym_scatter(struct sym_hcb *np, struct sym_ccb *cp, struct scsi_cmnd
cp->data_len = 0;
- use_sg = map_scsi_sg_data(np, cmd);
+ use_sg = scsi_dma_map(cmd);
if (use_sg > 0) {
struct scatterlist *sg;
struct sym_tcb *tp = &np->target[cp->target];
struct sym_tblmove *data;
if (use_sg > SYM_CONF_MAX_SG) {
- unmap_scsi_data(np, cmd);
+ scsi_dma_unmap(cmd);
return -1;
}
@@ -351,15 +307,6 @@ static int sym_queue_command(struct sym_hcb *np, struct scsi_cmnd *cmd)
int order;
/*
- * Minimal checkings, so that we will not
- * go outside our tables.
- */
- if (sdev->id == np->myaddr) {
- sym_xpt_done2(np, cmd, DID_NO_CONNECT);
- return 0;
- }
-
- /*
* Retrieve the target descriptor.
*/
tp = &np->target[sdev->id];
@@ -433,7 +380,7 @@ int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct s
*/
switch (dir) {
case DMA_BIDIRECTIONAL:
- printk("%s: got DMA_BIDIRECTIONAL command", sym_name(np));
+ scmd_printk(KERN_INFO, cmd, "got DMA_BIDIRECTIONAL command");
sym_set_cam_status(cmd, DID_ERROR);
goto out_abort;
case DMA_TO_DEVICE:
@@ -542,14 +489,16 @@ static void sym_timer(struct sym_hcb *np)
/*
* PCI BUS error handler.
*/
-void sym_log_bus_error(struct sym_hcb *np)
+void sym_log_bus_error(struct Scsi_Host *shost)
{
- u_short pci_sts;
- pci_read_config_word(np->s.device, PCI_STATUS, &pci_sts);
+ struct sym_data *sym_data = shost_priv(shost);
+ struct pci_dev *pdev = sym_data->pdev;
+ unsigned short pci_sts;
+ pci_read_config_word(pdev, PCI_STATUS, &pci_sts);
if (pci_sts & 0xf900) {
- pci_write_config_word(np->s.device, PCI_STATUS, pci_sts);
- printf("%s: PCI STATUS = 0x%04x\n",
- sym_name(np), pci_sts & 0xf900);
+ pci_write_config_word(pdev, PCI_STATUS, pci_sts);
+ shost_printk(KERN_WARNING, shost,
+ "PCI bus error: status = 0x%04x\n", pci_sts & 0xf900);
}
}
@@ -564,7 +513,7 @@ static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
struct sym_ucmd *ucp = SYM_UCMD_PTR(cmd);
int sts = 0;
- cmd->scsi_done = done;
+ cmd->scsi_done = done;
memset(ucp, 0, sizeof(*ucp));
/*
@@ -593,18 +542,23 @@ static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
*/
static irqreturn_t sym53c8xx_intr(int irq, void *dev_id)
{
- unsigned long flags;
- struct sym_hcb *np = (struct sym_hcb *)dev_id;
+ struct Scsi_Host *shost = dev_id;
+ struct sym_data *sym_data = shost_priv(shost);
+ irqreturn_t result;
+
+ /* Avoid spinloop trying to handle interrupts on frozen device */
+ if (pci_channel_offline(sym_data->pdev))
+ return IRQ_NONE;
if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("[");
- spin_lock_irqsave(np->s.host->host_lock, flags);
- sym_interrupt(np);
- spin_unlock_irqrestore(np->s.host->host_lock, flags);
+ spin_lock(shost->host_lock);
+ result = sym_interrupt(shost);
+ spin_unlock(shost->host_lock);
if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("]\n");
- return IRQ_HANDLED;
+ return result;
}
/*
@@ -630,59 +584,61 @@ static void sym53c8xx_timer(unsigned long npref)
#define SYM_EH_HOST_RESET 3
/*
- * What we will do regarding the involved SCSI command.
- */
-#define SYM_EH_DO_IGNORE 0
-#define SYM_EH_DO_WAIT 2
-
-/*
- * scsi_done() alias when error recovery is in progress.
- */
-static void sym_eh_done(struct scsi_cmnd *cmd)
-{
- struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
- BUILD_BUG_ON(sizeof(struct scsi_pointer) < sizeof(struct sym_ucmd));
-
- cmd->scsi_done = ucmd->old_done;
-
- if (ucmd->to_do == SYM_EH_DO_WAIT)
- complete(ucmd->eh_done);
-}
-
-/*
* Generic method for our eh processing.
* The 'op' argument tells what we have to do.
*/
static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
{
- struct sym_hcb *np = SYM_SOFTC_PTR(cmd);
struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
- struct Scsi_Host *host = cmd->device->host;
+ struct Scsi_Host *shost = cmd->device->host;
+ struct sym_data *sym_data = shost_priv(shost);
+ struct pci_dev *pdev = sym_data->pdev;
+ struct sym_hcb *np = sym_data->ncb;
SYM_QUEHEAD *qp;
- int to_do = SYM_EH_DO_IGNORE;
+ int cmd_queued = 0;
int sts = -1;
struct completion eh_done;
- dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname);
+ scmd_printk(KERN_WARNING, cmd, "%s operation started\n", opname);
+
+ /* We may be in an error condition because the PCI bus
+ * went down. In this case, we need to wait until the
+ * PCI bus is reset, the card is reset, and only then
+ * proceed with the scsi error recovery. There's no
+ * point in hurrying; take a leisurely wait.
+ */
+#define WAIT_FOR_PCI_RECOVERY 35
+ if (pci_channel_offline(pdev)) {
+ struct completion *io_reset;
+ int finished_reset = 0;
+ init_completion(&eh_done);
+ spin_lock_irq(shost->host_lock);
+ /* Make sure we didn't race */
+ if (pci_channel_offline(pdev)) {
+ if (!sym_data->io_reset)
+ sym_data->io_reset = &eh_done;
+ io_reset = sym_data->io_reset;
+ } else {
+ finished_reset = 1;
+ }
+ spin_unlock_irq(shost->host_lock);
+ if (!finished_reset)
+ finished_reset = wait_for_completion_timeout(io_reset,
+ WAIT_FOR_PCI_RECOVERY*HZ);
+ if (!finished_reset)
+ return SCSI_FAILED;
+ }
- spin_lock_irq(host->host_lock);
+ spin_lock_irq(shost->host_lock);
/* This one is queued in some place -> to wait for completion */
FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
if (cp->cmd == cmd) {
- to_do = SYM_EH_DO_WAIT;
+ cmd_queued = 1;
break;
}
}
- if (to_do == SYM_EH_DO_WAIT) {
- init_completion(&eh_done);
- ucmd->old_done = cmd->scsi_done;
- ucmd->eh_done = &eh_done;
- wmb();
- cmd->scsi_done = sym_eh_done;
- }
-
/* Try to proceed the operation we have been asked for */
sts = -1;
switch(op) {
@@ -698,7 +654,7 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
break;
case SYM_EH_HOST_RESET:
sym_reset_scsi_bus(np, 0);
- sym_start_up (np, 1);
+ sym_start_up(shost, 1);
sts = 0;
break;
default:
@@ -706,21 +662,21 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
}
/* On error, restore everything and cross fingers :) */
- if (sts) {
- cmd->scsi_done = ucmd->old_done;
- to_do = SYM_EH_DO_IGNORE;
- }
-
- ucmd->to_do = to_do;
- spin_unlock_irq(host->host_lock);
+ if (sts)
+ cmd_queued = 0;
- if (to_do == SYM_EH_DO_WAIT) {
+ if (cmd_queued) {
+ init_completion(&eh_done);
+ ucmd->eh_done = &eh_done;
+ spin_unlock_irq(shost->host_lock);
if (!wait_for_completion_timeout(&eh_done, 5*HZ)) {
- ucmd->to_do = SYM_EH_DO_IGNORE;
- wmb();
+ ucmd->eh_done = NULL;
sts = -2;
}
+ } else {
+ spin_unlock_irq(shost->host_lock);
}
+
dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname,
sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed");
return sts ? SCSI_FAILED : SCSI_SUCCESS;
@@ -775,59 +731,6 @@ static void sym_tune_dev_queuing(struct sym_tcb *tp, int lun, u_short reqtags)
}
}
-/*
- * Linux select queue depths function
- */
-#define DEF_DEPTH (sym_driver_setup.max_tag)
-#define ALL_TARGETS -2
-#define NO_TARGET -1
-#define ALL_LUNS -2
-#define NO_LUN -1
-
-static int device_queue_depth(struct sym_hcb *np, int target, int lun)
-{
- int c, h, t, u, v;
- char *p = sym_driver_setup.tag_ctrl;
- char *ep;
-
- h = -1;
- t = NO_TARGET;
- u = NO_LUN;
- while ((c = *p++) != 0) {
- v = simple_strtoul(p, &ep, 0);
- switch(c) {
- case '/':
- ++h;
- t = ALL_TARGETS;
- u = ALL_LUNS;
- break;
- case 't':
- if (t != target)
- t = (target == v) ? v : NO_TARGET;
- u = ALL_LUNS;
- break;
- case 'u':
- if (u != lun)
- u = (lun == v) ? v : NO_LUN;
- break;
- case 'q':
- if (h == np->s.unit &&
- (t == ALL_TARGETS || t == target) &&
- (u == ALL_LUNS || u == lun))
- return v;
- break;
- case '-':
- t = ALL_TARGETS;
- u = ALL_LUNS;
- break;
- default:
- break;
- }
- p = ep;
- }
- return DEF_DEPTH;
-}
-
static int sym53c8xx_slave_alloc(struct scsi_device *sdev)
{
struct sym_hcb *np = sym_get_hcb(sdev->host);
@@ -892,21 +795,16 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev)
* Use at least 2.
* Donnot use more than our maximum.
*/
- reqtags = device_queue_depth(np, sdev->id, sdev->lun);
+ reqtags = sym_driver_setup.max_tag;
if (reqtags > tp->usrtags)
reqtags = tp->usrtags;
if (!sdev->tagged_supported)
reqtags = 0;
-#if 1 /* Avoid to locally queue commands for no good reasons */
if (reqtags > SYM_CONF_MAX_TAG)
reqtags = SYM_CONF_MAX_TAG;
- depth_to_use = (reqtags ? reqtags : 2);
-#else
- depth_to_use = (reqtags ? SYM_CONF_MAX_TAG : 2);
-#endif
+ depth_to_use = reqtags ? reqtags : 2;
scsi_adjust_queue_depth(sdev,
- (sdev->tagged_supported ?
- MSG_SIMPLE_TAG : 0),
+ sdev->tagged_supported ? MSG_SIMPLE_TAG : 0,
depth_to_use);
lp->s.scdev_depth = depth_to_use;
sym_tune_dev_queuing(tp, sdev->lun, reqtags);
@@ -1089,8 +987,9 @@ static int is_keyword(char *ptr, int len, char *verb)
* Parse a control command
*/
-static int sym_user_command(struct sym_hcb *np, char *buffer, int length)
+static int sym_user_command(struct Scsi_Host *shost, char *buffer, int length)
{
+ struct sym_hcb *np = sym_get_hcb(shost);
char *ptr = buffer;
int len = length;
struct sym_usrcmd cmd, *uc = &cmd;
@@ -1217,9 +1116,9 @@ printk("sym_user_command: data=%ld\n", uc->data);
else {
unsigned long flags;
- spin_lock_irqsave(np->s.host->host_lock, flags);
- sym_exec_user_command (np, uc);
- spin_unlock_irqrestore(np->s.host->host_lock, flags);
+ spin_lock_irqsave(shost->host_lock, flags);
+ sym_exec_user_command(np, uc);
+ spin_unlock_irqrestore(shost->host_lock, flags);
}
return length;
}
@@ -1275,8 +1174,11 @@ static int copy_info(struct info_str *info, char *fmt, ...)
/*
* Copy formatted information into the input buffer.
*/
-static int sym_host_info(struct sym_hcb *np, char *ptr, off_t offset, int len)
+static int sym_host_info(struct Scsi_Host *shost, char *ptr, off_t offset, int len)
{
+ struct sym_data *sym_data = shost_priv(shost);
+ struct pci_dev *pdev = sym_data->pdev;
+ struct sym_hcb *np = sym_data->ncb;
struct info_str info;
info.buffer = ptr;
@@ -1285,10 +1187,10 @@ static int sym_host_info(struct sym_hcb *np, char *ptr, off_t offset, int len)
info.pos = 0;
copy_info(&info, "Chip " NAME53C "%s, device id 0x%x, "
- "revision id 0x%x\n",
- np->s.chip_name, np->device_id, np->revision_id);
- copy_info(&info, "At PCI address %s, IRQ " IRQ_FMT "\n",
- pci_name(np->s.device), IRQ_PRM(np->s.irq));
+ "revision id 0x%x\n", np->s.chip_name,
+ pdev->device, pdev->revision);
+ copy_info(&info, "At PCI address %s, IRQ %u\n",
+ pci_name(pdev), pdev->irq);
copy_info(&info, "Min. period factor %d, %s SCSI BUS%s\n",
(int) (np->minsync_dt ? np->minsync_dt : np->minsync),
np->maxwide ? "Wide" : "Narrow",
@@ -1307,15 +1209,14 @@ static int sym_host_info(struct sym_hcb *np, char *ptr, off_t offset, int len)
* - func = 0 means read (returns adapter infos)
* - func = 1 means write (not yet merget from sym53c8xx)
*/
-static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer,
+static int sym53c8xx_proc_info(struct Scsi_Host *shost, char *buffer,
char **start, off_t offset, int length, int func)
{
- struct sym_hcb *np = sym_get_hcb(host);
int retv;
if (func) {
#ifdef SYM_LINUX_USER_COMMAND_SUPPORT
- retv = sym_user_command(np, buffer, length);
+ retv = sym_user_command(shost, buffer, length);
#else
retv = -EINVAL;
#endif
@@ -1323,7 +1224,7 @@ static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer,
if (start)
*start = buffer;
#ifdef SYM_LINUX_USER_INFO_SUPPORT
- retv = sym_host_info(np, buffer, offset, length);
+ retv = sym_host_info(shost, buffer, offset, length);
#else
retv = -EINVAL;
#endif
@@ -1341,8 +1242,8 @@ static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev)
/*
* Free O/S specific resources.
*/
- if (np->s.irq)
- free_irq(np->s.irq, np);
+ if (pdev->irq)
+ free_irq(pdev->irq, np);
if (np->s.ioaddr)
pci_iounmap(pdev, np->s.ioaddr);
if (np->s.ramaddr)
@@ -1356,31 +1257,6 @@ static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev)
}
/*
- * Ask/tell the system about DMA addressing.
- */
-static int sym_setup_bus_dma_mask(struct sym_hcb *np)
-{
-#if SYM_CONF_DMA_ADDRESSING_MODE > 0
-#if SYM_CONF_DMA_ADDRESSING_MODE == 1
-#define DMA_DAC_MASK DMA_40BIT_MASK
-#elif SYM_CONF_DMA_ADDRESSING_MODE == 2
-#define DMA_DAC_MASK DMA_64BIT_MASK
-#endif
- if ((np->features & FE_DAC) &&
- !pci_set_dma_mask(np->s.device, DMA_DAC_MASK)) {
- np->use_dac = 1;
- return 0;
- }
-#endif
-
- if (!pci_set_dma_mask(np->s.device, DMA_32BIT_MASK))
- return 0;
-
- printf_warning("%s: No suitable DMA available\n", sym_name(np));
- return -1;
-}
-
-/*
* Host attach and initialisations.
*
* Allocate host data and ncb structure.
@@ -1392,32 +1268,28 @@ static int sym_setup_bus_dma_mask(struct sym_hcb *np)
static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
int unit, struct sym_device *dev)
{
- struct host_data *host_data;
+ struct sym_data *sym_data;
struct sym_hcb *np = NULL;
- struct Scsi_Host *instance = NULL;
+ struct Scsi_Host *shost;
struct pci_dev *pdev = dev->pdev;
unsigned long flags;
struct sym_fw *fw;
- printk(KERN_INFO
- "sym%d: <%s> rev 0x%x at pci %s irq " IRQ_FMT "\n",
- unit, dev->chip.name, dev->chip.revision_id,
- pci_name(pdev), IRQ_PRM(pdev->irq));
+ printk(KERN_INFO "sym%d: <%s> rev 0x%x at pci %s irq %u\n",
+ unit, dev->chip.name, pdev->revision, pci_name(pdev),
+ pdev->irq);
/*
* Get the firmware for this chip.
*/
fw = sym_find_firmware(&dev->chip);
if (!fw)
- goto attach_failed;
+ return NULL;
- /*
- * Allocate host_data structure
- */
- instance = scsi_host_alloc(tpnt, sizeof(*host_data));
- if (!instance)
- goto attach_failed;
- host_data = (struct host_data *) instance->hostdata;
+ shost = scsi_host_alloc(tpnt, sizeof(*sym_data));
+ if (!shost)
+ return NULL;
+ sym_data = shost_priv(shost);
/*
* Allocate immediately the host control block,
@@ -1428,22 +1300,19 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
np = __sym_calloc_dma(&pdev->dev, sizeof(*np), "HCB");
if (!np)
goto attach_failed;
- np->s.device = pdev;
np->bus_dmat = &pdev->dev; /* Result in 1 DMA pool per HBA */
- host_data->ncb = np;
- np->s.host = instance;
+ sym_data->ncb = np;
+ sym_data->pdev = pdev;
+ np->s.host = shost;
- pci_set_drvdata(pdev, np);
+ pci_set_drvdata(pdev, shost);
/*
* Copy some useful infos to the HCB.
*/
np->hcb_ba = vtobus(np);
np->verbose = sym_driver_setup.verbose;
- np->s.device = pdev;
np->s.unit = unit;
- np->device_id = dev->chip.device_id;
- np->revision_id = dev->chip.revision_id;
np->features = dev->chip.features;
np->clock_divn = dev->chip.nr_divisor;
np->maxoffs = dev->chip.offset_max;
@@ -1456,8 +1325,13 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
strlcpy(np->s.chip_name, dev->chip.name, sizeof(np->s.chip_name));
sprintf(np->s.inst_name, "sym%d", np->s.unit);
- if (sym_setup_bus_dma_mask(np))
+ if ((SYM_CONF_DMA_ADDRESSING_MODE > 0) && (np->features & FE_DAC) &&
+ !pci_set_dma_mask(pdev, DMA_DAC_MASK)) {
+ set_dac(np);
+ } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+ printf_warning("%s: No suitable DMA available\n", sym_name(np));
goto attach_failed;
+ }
/*
* Try to map the controller chip to
@@ -1466,19 +1340,16 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
np->mmio_ba = (u32)dev->mmio_base;
np->s.ioaddr = dev->s.ioaddr;
np->s.ramaddr = dev->s.ramaddr;
- np->s.io_ws = (np->features & FE_IO256) ? 256 : 128;
/*
* Map on-chip RAM if present and supported.
*/
if (!(np->features & FE_RAM))
dev->ram_base = 0;
- if (dev->ram_base) {
+ if (dev->ram_base)
np->ram_ba = (u32)dev->ram_base;
- np->ram_ws = (np->features & FE_RAM8K) ? 8192 : 4096;
- }
- if (sym_hcb_attach(instance, fw, dev->nvram))
+ if (sym_hcb_attach(shost, fw, dev->nvram))
goto attach_failed;
/*
@@ -1486,25 +1357,25 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
* If we synchonize the C code with SCRIPTS on interrupt,
* we do not want to share the INTR line at all.
*/
- if (request_irq(pdev->irq, sym53c8xx_intr, IRQF_SHARED, NAME53C8XX, np)) {
- printf_err("%s: request irq %d failure\n",
+ if (request_irq(pdev->irq, sym53c8xx_intr, IRQF_SHARED, NAME53C8XX,
+ shost)) {
+ printf_err("%s: request irq %u failure\n",
sym_name(np), pdev->irq);
goto attach_failed;
}
- np->s.irq = pdev->irq;
/*
* After SCSI devices have been opened, we cannot
* reset the bus safely, so we do it here.
*/
- spin_lock_irqsave(instance->host_lock, flags);
+ spin_lock_irqsave(shost->host_lock, flags);
if (sym_reset_scsi_bus(np, 0))
goto reset_failed;
/*
* Start the SCRIPTS.
*/
- sym_start_up (np, 1);
+ sym_start_up(shost, 1);
/*
* Start the timer daemon
@@ -1519,33 +1390,37 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
* Fill Linux host instance structure
* and return success.
*/
- instance->max_channel = 0;
- instance->this_id = np->myaddr;
- instance->max_id = np->maxwide ? 16 : 8;
- instance->max_lun = SYM_CONF_MAX_LUN;
- instance->unique_id = pci_resource_start(pdev, 0);
- instance->cmd_per_lun = SYM_CONF_MAX_TAG;
- instance->can_queue = (SYM_CONF_MAX_START-2);
- instance->sg_tablesize = SYM_CONF_MAX_SG;
- instance->max_cmd_len = 16;
+ shost->max_channel = 0;
+ shost->this_id = np->myaddr;
+ shost->max_id = np->maxwide ? 16 : 8;
+ shost->max_lun = SYM_CONF_MAX_LUN;
+ shost->unique_id = pci_resource_start(pdev, 0);
+ shost->cmd_per_lun = SYM_CONF_MAX_TAG;
+ shost->can_queue = (SYM_CONF_MAX_START-2);
+ shost->sg_tablesize = SYM_CONF_MAX_SG;
+ shost->max_cmd_len = 16;
BUG_ON(sym2_transport_template == NULL);
- instance->transportt = sym2_transport_template;
+ shost->transportt = sym2_transport_template;
+
+ /* 53c896 rev 1 errata: DMA may not cross 16MB boundary */
+ if (pdev->device == PCI_DEVICE_ID_NCR_53C896 && pdev->revision < 2)
+ shost->dma_boundary = 0xFFFFFF;
- spin_unlock_irqrestore(instance->host_lock, flags);
+ spin_unlock_irqrestore(shost->host_lock, flags);
- return instance;
+ return shost;
reset_failed:
printf_err("%s: FATAL ERROR: CHECK SCSI BUS - CABLES, "
"TERMINATION, DEVICE POWER etc.!\n", sym_name(np));
- spin_unlock_irqrestore(instance->host_lock, flags);
+ spin_unlock_irqrestore(shost->host_lock, flags);
attach_failed:
- if (!instance)
+ if (!shost)
return NULL;
printf_info("%s: giving up ...\n", sym_name(np));
if (np)
sym_free_resources(np, pdev);
- scsi_host_put(instance);
+ scsi_host_put(shost);
return NULL;
}
@@ -1558,7 +1433,6 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
static void __devinit sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp)
{
devp->nvram = nvp;
- devp->device_id = devp->chip.device_id;
nvp->type = 0;
sym_read_nvram(devp, nvp);
@@ -1573,7 +1447,6 @@ static int __devinit sym_check_supported(struct sym_device *device)
{
struct sym_chip *chip;
struct pci_dev *pdev = device->pdev;
- u_char revision;
unsigned long io_port = pci_resource_start(pdev, 0);
int i;
@@ -1593,14 +1466,12 @@ static int __devinit sym_check_supported(struct sym_device *device)
* to our device structure so we can make it match the actual device
* and options.
*/
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
- chip = sym_lookup_chip_table(pdev->device, revision);
+ chip = sym_lookup_chip_table(pdev->device, pdev->revision);
if (!chip) {
dev_info(&pdev->dev, "device not supported\n");
return -ENODEV;
}
memcpy(&device->chip, chip, sizeof(device->chip));
- device->chip.revision_id = revision;
return 0;
}
@@ -1641,7 +1512,7 @@ static int __devinit sym_set_workarounds(struct sym_device *device)
* We must ensure the chip will use WRITE AND INVALIDATE.
* The revision number limit is for now arbitrary.
*/
- if (pdev->device == PCI_DEVICE_ID_NCR_53C896 && chip->revision_id < 0x4) {
+ if (pdev->device == PCI_DEVICE_ID_NCR_53C896 && pdev->revision < 0x4) {
chip->features |= (FE_WRIE | FE_CLSE);
}
@@ -1769,8 +1640,9 @@ static void sym_config_pqs(struct pci_dev *pdev, struct sym_device *sym_dev)
* Detach the host.
* We have to free resources and halt the NCR chip.
*/
-static int sym_detach(struct sym_hcb *np, struct pci_dev *pdev)
+static int sym_detach(struct Scsi_Host *shost, struct pci_dev *pdev)
{
+ struct sym_hcb *np = sym_get_hcb(shost);
printk("%s: detaching ...\n", sym_name(np));
del_timer_sync(&np->s.timer);
@@ -1808,6 +1680,7 @@ static struct scsi_host_template sym2_template = {
.eh_host_reset_handler = sym53c8xx_eh_host_reset_handler,
.this_id = 7,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
.max_sectors = 0xFFFF,
#ifdef SYM_LINUX_PROC_INFO_SUPPORT
.proc_info = sym53c8xx_proc_info,
@@ -1822,7 +1695,7 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
{
struct sym_device sym_dev;
struct sym_nvram nvram;
- struct Scsi_Host *instance;
+ struct Scsi_Host *shost;
memset(&sym_dev, 0, sizeof(sym_dev));
memset(&nvram, 0, sizeof(nvram));
@@ -1849,13 +1722,13 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
sym_get_nvram(&sym_dev, &nvram);
- instance = sym_attach(&sym2_template, attach_count, &sym_dev);
- if (!instance)
+ shost = sym_attach(&sym2_template, attach_count, &sym_dev);
+ if (!shost)
goto free;
- if (scsi_add_host(instance, &pdev->dev))
+ if (scsi_add_host(shost, &pdev->dev))
goto detach;
- scsi_scan_host(instance);
+ scsi_scan_host(shost);
attach_count++;
@@ -1873,20 +1746,143 @@ static int __devinit sym2_probe(struct pci_dev *pdev,
static void __devexit sym2_remove(struct pci_dev *pdev)
{
- struct sym_hcb *np = pci_get_drvdata(pdev);
- struct Scsi_Host *host = np->s.host;
-
- scsi_remove_host(host);
- scsi_host_put(host);
-
- sym_detach(np, pdev);
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ scsi_remove_host(shost);
+ scsi_host_put(shost);
+ sym_detach(shost, pdev);
pci_release_regions(pdev);
pci_disable_device(pdev);
attach_count--;
}
+/**
+ * sym2_io_error_detected() - called when PCI error is detected
+ * @pdev: pointer to PCI device
+ * @state: current state of the PCI slot
+ */
+static pci_ers_result_t sym2_io_error_detected(struct pci_dev *pdev,
+ enum pci_channel_state state)
+{
+ /* If slot is permanently frozen, turn everything off */
+ if (state == pci_channel_io_perm_failure) {
+ sym2_remove(pdev);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ disable_irq(pdev->irq);
+ pci_disable_device(pdev);
+
+ /* Request that MMIO be enabled, so register dump can be taken. */
+ return PCI_ERS_RESULT_CAN_RECOVER;
+}
+
+/**
+ * sym2_io_slot_dump - Enable MMIO and dump debug registers
+ * @pdev: pointer to PCI device
+ */
+static pci_ers_result_t sym2_io_slot_dump(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+
+ sym_dump_registers(shost);
+
+ /* Request a slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * sym2_reset_workarounds - hardware-specific work-arounds
+ *
+ * This routine is similar to sym_set_workarounds(), except
+ * that, at this point, we already know that the device was
+ * succesfully intialized 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)
+{
+ u_short status_reg;
+ struct sym_chip *chip;
+
+ chip = sym_lookup_chip_table(pdev->device, pdev->revision);
+
+ /* Work around for errant bit in 895A, in a fashion
+ * similar to what is done in sym_set_workarounds().
+ */
+ pci_read_config_word(pdev, PCI_STATUS, &status_reg);
+ if (!(chip->features & FE_66MHZ) && (status_reg & PCI_STATUS_66MHZ)) {
+ status_reg = PCI_STATUS_66MHZ;
+ pci_write_config_word(pdev, PCI_STATUS, status_reg);
+ pci_read_config_word(pdev, PCI_STATUS, &status_reg);
+ }
+}
+
+/**
+ * sym2_io_slot_reset() - called when the pci bus has been reset.
+ * @pdev: pointer to PCI device
+ *
+ * Restart the card from scratch.
+ */
+static pci_ers_result_t sym2_io_slot_reset(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct sym_hcb *np = sym_get_hcb(shost);
+
+ printk(KERN_INFO "%s: recovering from a PCI slot reset\n",
+ sym_name(np));
+
+ if (pci_enable_device(pdev)) {
+ printk(KERN_ERR "%s: Unable to enable after PCI reset\n",
+ sym_name(np));
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ pci_set_master(pdev);
+ enable_irq(pdev->irq);
+
+ /* If the chip can do Memory Write Invalidate, enable it */
+ if (np->features & FE_WRIE) {
+ if (pci_set_mwi(pdev))
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ /* Perform work-arounds, analogous to sym_set_workarounds() */
+ sym2_reset_workarounds(pdev);
+
+ /* Perform host reset only on one instance of the card */
+ if (PCI_FUNC(pdev->devfn) == 0) {
+ if (sym_reset_scsi_bus(np, 0)) {
+ printk(KERN_ERR "%s: Unable to reset scsi host\n",
+ sym_name(np));
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ sym_start_up(shost, 1);
+ }
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * sym2_io_resume() - resume normal ops after PCI reset
+ * @pdev: pointer to PCI device
+ *
+ * Called when the error recovery driver tells us that its
+ * OK to resume normal operation. Use completion to allow
+ * halted scsi ops to resume.
+ */
+static void sym2_io_resume(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct sym_data *sym_data = shost_priv(shost);
+
+ spin_lock_irq(shost->host_lock);
+ if (sym_data->io_reset)
+ complete_all(sym_data->io_reset);
+ sym_data->io_reset = NULL;
+ spin_unlock_irq(shost->host_lock);
+}
+
static void sym2_get_signalling(struct Scsi_Host *shost)
{
struct sym_hcb *np = sym_get_hcb(shost);
@@ -2049,11 +2045,19 @@ static struct pci_device_id sym2_id_table[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, sym2_id_table);
+static struct pci_error_handlers sym2_err_handler = {
+ .error_detected = sym2_io_error_detected,
+ .mmio_enabled = sym2_io_slot_dump,
+ .slot_reset = sym2_io_slot_reset,
+ .resume = sym2_io_resume,
+};
+
static struct pci_driver sym2_driver = {
.name = NAME53C8XX,
.id_table = sym2_id_table,
.probe = sym2_probe,
.remove = __devexit_p(sym2_remove),
+ .err_handler = &sym2_err_handler,
};
static int __init sym2_init(void)
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h
index 0f097ba4f71..567fbe0b4f0 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.h
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.h
@@ -40,7 +40,9 @@
#ifndef SYM_GLUE_H
#define SYM_GLUE_H
+#include <linux/completion.h>
#include <linux/delay.h>
+#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/string.h>
@@ -177,14 +179,11 @@ struct sym_shcb {
int unit;
char inst_name[16];
char chip_name[8];
- struct pci_dev *device;
struct Scsi_Host *host;
void __iomem * ioaddr; /* MMIO kernel io address */
void __iomem * ramaddr; /* RAM kernel io address */
- u_short io_ws; /* IO window size */
- int irq; /* IRQ number */
struct timer_list timer; /* Timer handler link header */
u_long lasttime;
@@ -212,20 +211,21 @@ struct sym_device {
} s;
struct sym_chip chip;
struct sym_nvram *nvram;
- u_short device_id;
u_char host_id;
};
/*
* Driver host data structure.
*/
-struct host_data {
+struct sym_data {
struct sym_hcb *ncb;
+ struct completion *io_reset; /* PCI error handling */
+ struct pci_dev *pdev;
};
static inline struct sym_hcb * sym_get_hcb(struct Scsi_Host *host)
{
- return ((struct host_data *)host->hostdata)->ncb;
+ return ((struct sym_data *)host->hostdata)->ncb;
}
#include "sym_fw.h"
@@ -263,8 +263,8 @@ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *ccb);
#define sym_print_addr(cmd, arg...) dev_info(&cmd->device->sdev_gendev , ## arg)
void sym_xpt_async_bus_reset(struct sym_hcb *np);
-void sym_xpt_async_sent_bdr(struct sym_hcb *np, int target);
int sym_setup_data_and_start (struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp);
-void sym_log_bus_error(struct sym_hcb *np);
+void sym_log_bus_error(struct Scsi_Host *);
+void sym_dump_registers(struct Scsi_Host *);
#endif /* SYM_GLUE_H */
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
index 21cd4c7f528..463f119f20e 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c
@@ -52,7 +52,7 @@
* Needed function prototypes.
*/
static void sym_int_ma (struct sym_hcb *np);
-static void sym_int_sir (struct sym_hcb *np);
+static void sym_int_sir(struct sym_hcb *);
static struct sym_ccb *sym_alloc_ccb(struct sym_hcb *np);
static struct sym_ccb *sym_ccb_from_dsa(struct sym_hcb *np, u32 dsa);
static void sym_alloc_lcb_tags (struct sym_hcb *np, u_char tn, u_char ln);
@@ -684,6 +684,8 @@ static void sym_set_bus_mode(struct sym_hcb *np, struct sym_nvram *nvram)
*/
static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram)
{
+ struct sym_data *sym_data = shost_priv(shost);
+ struct pci_dev *pdev = sym_data->pdev;
u_char burst_max;
u32 period;
int i;
@@ -778,19 +780,12 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru
* 64 bit addressing (895A/896/1010) ?
*/
if (np->features & FE_DAC) {
-#if SYM_CONF_DMA_ADDRESSING_MODE == 0
- np->rv_ccntl1 |= (DDAC);
-#elif SYM_CONF_DMA_ADDRESSING_MODE == 1
- if (!np->use_dac)
- np->rv_ccntl1 |= (DDAC);
- else
- np->rv_ccntl1 |= (XTIMOD | EXTIBMV);
-#elif SYM_CONF_DMA_ADDRESSING_MODE == 2
- if (!np->use_dac)
- np->rv_ccntl1 |= (DDAC);
- else
- np->rv_ccntl1 |= (0 | EXTIBMV);
-#endif
+ if (!use_dac(np))
+ np->rv_ccntl1 |= (DDAC);
+ else if (SYM_CONF_DMA_ADDRESSING_MODE == 1)
+ np->rv_ccntl1 |= (XTIMOD | EXTIBMV);
+ else if (SYM_CONF_DMA_ADDRESSING_MODE == 2)
+ np->rv_ccntl1 |= (0 | EXTIBMV);
}
/*
@@ -804,8 +799,8 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru
* In dual channel mode, contention occurs if internal cycles
* are used. Disable internal cycles.
*/
- if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_33 &&
- np->revision_id < 0x1)
+ if (pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 &&
+ pdev->revision < 0x1)
np->rv_ccntl0 |= DILS;
/*
@@ -828,10 +823,10 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru
* this driver. The generic ncr driver that does not use
* LOAD/STORE instructions does not need this work-around.
*/
- if ((np->device_id == PCI_DEVICE_ID_NCR_53C810 &&
- np->revision_id >= 0x10 && np->revision_id <= 0x11) ||
- (np->device_id == PCI_DEVICE_ID_NCR_53C860 &&
- np->revision_id <= 0x1))
+ if ((pdev->device == PCI_DEVICE_ID_NCR_53C810 &&
+ pdev->revision >= 0x10 && pdev->revision <= 0x11) ||
+ (pdev->device == PCI_DEVICE_ID_NCR_53C860 &&
+ pdev->revision <= 0x1))
np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP);
/*
@@ -897,7 +892,7 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru
if ((SYM_SETUP_SCSI_LED ||
(nvram->type == SYM_SYMBIOS_NVRAM ||
(nvram->type == SYM_TEKRAM_NVRAM &&
- np->device_id == PCI_DEVICE_ID_NCR_53C895))) &&
+ pdev->device == PCI_DEVICE_ID_NCR_53C895))) &&
!(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01))
np->features |= FE_LED0;
@@ -1135,8 +1130,9 @@ restart_test:
* First 24 register of the chip:
* r0..rf
*/
-static void sym_log_hard_error(struct sym_hcb *np, u_short sist, u_char dstat)
+static void sym_log_hard_error(struct Scsi_Host *shost, u_short sist, u_char dstat)
{
+ struct sym_hcb *np = sym_get_hcb(shost);
u32 dsp;
int script_ofs;
int script_size;
@@ -1180,16 +1176,27 @@ static void sym_log_hard_error(struct sym_hcb *np, u_short sist, u_char dstat)
scr_to_cpu((int) *(u32 *)(script_base + script_ofs)));
}
- printf ("%s: regdump:", sym_name(np));
- for (i=0; i<24;i++)
- printf (" %02x", (unsigned)INB_OFF(np, i));
- printf (".\n");
+ printf("%s: regdump:", sym_name(np));
+ for (i = 0; i < 24; i++)
+ printf(" %02x", (unsigned)INB_OFF(np, i));
+ printf(".\n");
/*
* PCI BUS error.
*/
if (dstat & (MDPE|BF))
- sym_log_bus_error(np);
+ sym_log_bus_error(shost);
+}
+
+void sym_dump_registers(struct Scsi_Host *shost)
+{
+ struct sym_hcb *np = sym_get_hcb(shost);
+ u_short sist;
+ u_char dstat;
+
+ sist = INW(np, nc_sist);
+ dstat = INB(np, nc_dstat);
+ sym_log_hard_error(shost, sist, dstat);
}
static struct sym_chip sym_dev_table[] = {
@@ -1312,7 +1319,7 @@ int sym_lookup_dmap(struct sym_hcb *np, u32 h, int s)
{
int i;
- if (!np->use_dac)
+ if (!use_dac(np))
goto weird;
/* Look up existing mappings */
@@ -1519,7 +1526,8 @@ void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp)
np->squeueput = qidx;
if (DEBUG_FLAGS & DEBUG_QUEUE)
- printf ("%s: queuepos=%d.\n", sym_name (np), np->squeueput);
+ scmd_printk(KERN_DEBUG, cp->cmd, "queuepos=%d\n",
+ np->squeueput);
/*
* Script processor may be waiting for reselect.
@@ -1696,8 +1704,11 @@ static void sym_flush_busy_queue (struct sym_hcb *np, int cam_status)
* 1: SCSI BUS RESET delivered or received.
* 2: SCSI BUS MODE changed.
*/
-void sym_start_up (struct sym_hcb *np, int reason)
+void sym_start_up(struct Scsi_Host *shost, int reason)
{
+ struct sym_data *sym_data = shost_priv(shost);
+ struct pci_dev *pdev = sym_data->pdev;
+ struct sym_hcb *np = sym_data->ncb;
int i;
u32 phys;
@@ -1746,7 +1757,7 @@ void sym_start_up (struct sym_hcb *np, int reason)
* This also let point to first position the start
* and done queue pointers used from SCRIPTS.
*/
- np->fw_patch(np);
+ np->fw_patch(shost);
/*
* Wakeup all pending jobs.
@@ -1788,7 +1799,7 @@ void sym_start_up (struct sym_hcb *np, int reason)
/*
* For now, disable AIP generation on C1010-66.
*/
- if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)
+ if (pdev->device == PCI_DEVICE_ID_LSI_53C1010_66)
OUTB(np, nc_aipcntl1, DISAIP);
/*
@@ -1798,8 +1809,8 @@ void sym_start_up (struct sym_hcb *np, int reason)
* that from SCRIPTS for each selection/reselection, but
* I just don't want. :)
*/
- if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_33 &&
- np->revision_id < 1)
+ if (pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 &&
+ pdev->revision < 1)
OUTB(np, nc_stest1, INB(np, nc_stest1) | 0x30);
/*
@@ -1807,9 +1818,9 @@ void sym_start_up (struct sym_hcb *np, int reason)
* Disable overlapped arbitration for some dual function devices,
* regardless revision id (kind of post-chip-design feature. ;-))
*/
- if (np->device_id == PCI_DEVICE_ID_NCR_53C875)
+ if (pdev->device == PCI_DEVICE_ID_NCR_53C875)
OUTB(np, nc_ctest0, (1<<5));
- else if (np->device_id == PCI_DEVICE_ID_NCR_53C896)
+ else if (pdev->device == PCI_DEVICE_ID_NCR_53C896)
np->rv_ccntl0 |= DPR;
/*
@@ -1827,7 +1838,7 @@ void sym_start_up (struct sym_hcb *np, int reason)
* Set up scratch C and DRS IO registers to map the 32 bit
* DMA address range our data structures are located in.
*/
- if (np->use_dac) {
+ if (use_dac(np)) {
np->dmap_bah[0] = 0; /* ??? */
OUTL(np, nc_scrx[0], np->dmap_bah[0]);
OUTL(np, nc_drs, np->dmap_bah[0]);
@@ -1900,7 +1911,7 @@ void sym_start_up (struct sym_hcb *np, int reason)
if (sym_verbose >= 2)
printf("%s: Downloading SCSI SCRIPTS.\n", sym_name(np));
memcpy_toio(np->s.ramaddr, np->scripta0, np->scripta_sz);
- if (np->ram_ws == 8192) {
+ if (np->features & FE_RAM8K) {
memcpy_toio(np->s.ramaddr + 4096, np->scriptb0, np->scriptb_sz);
phys = scr_to_cpu(np->scr_ram_seg);
OUTL(np, nc_mmws, phys);
@@ -2214,8 +2225,9 @@ static void sym_int_udc (struct sym_hcb *np)
* mode to eight bit asynchronous, etc...
* So, just reinitializing all except chip should be enough.
*/
-static void sym_int_sbmc (struct sym_hcb *np)
+static void sym_int_sbmc(struct Scsi_Host *shost)
{
+ struct sym_hcb *np = sym_get_hcb(shost);
u_char scsi_mode = INB(np, nc_stest4) & SMODE;
/*
@@ -2228,7 +2240,7 @@ static void sym_int_sbmc (struct sym_hcb *np)
* Should suspend command processing for a few seconds and
* reinitialize all except the chip.
*/
- sym_start_up (np, 2);
+ sym_start_up(shost, 2);
}
/*
@@ -2756,8 +2768,11 @@ reset_all:
* Use at your own decision and risk.
*/
-void sym_interrupt (struct sym_hcb *np)
+irqreturn_t sym_interrupt(struct Scsi_Host *shost)
{
+ struct sym_data *sym_data = shost_priv(shost);
+ struct sym_hcb *np = sym_data->ncb;
+ struct pci_dev *pdev = sym_data->pdev;
u_char istat, istatc;
u_char dstat;
u_short sist;
@@ -2782,7 +2797,7 @@ void sym_interrupt (struct sym_hcb *np)
}
if (!(istat & (SIP|DIP)))
- return;
+ return (istat & INTF) ? IRQ_HANDLED : IRQ_NONE;
#if 0 /* We should never get this one */
if (istat & CABRT)
@@ -2809,6 +2824,13 @@ void sym_interrupt (struct sym_hcb *np)
dstat |= INB(np, nc_dstat);
istatc = INB(np, nc_istat);
istat |= istatc;
+
+ /* Prevent deadlock waiting on a condition that may
+ * never clear. */
+ if (unlikely(sist == 0xffff && dstat == 0xff)) {
+ if (pci_channel_offline(pdev))
+ return IRQ_NONE;
+ }
} while (istatc & (SIP|DIP));
if (DEBUG_FLAGS & DEBUG_TINY)
@@ -2842,10 +2864,10 @@ void sym_interrupt (struct sym_hcb *np)
!(dstat & (MDPE|BF|ABRT|IID))) {
if (sist & PAR) sym_int_par (np, sist);
else if (sist & MA) sym_int_ma (np);
- else if (dstat & SIR) sym_int_sir (np);
+ else if (dstat & SIR) sym_int_sir(np);
else if (dstat & SSI) OUTONB_STD();
else goto unknown_int;
- return;
+ return IRQ_HANDLED;
}
/*
@@ -2861,8 +2883,8 @@ void sym_interrupt (struct sym_hcb *np)
*/
if (sist & RST) {
printf("%s: SCSI BUS reset detected.\n", sym_name(np));
- sym_start_up (np, 1);
- return;
+ sym_start_up(shost, 1);
+ return IRQ_HANDLED;
}
OUTB(np, nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */
@@ -2870,11 +2892,11 @@ void sym_interrupt (struct sym_hcb *np)
if (!(sist & (GEN|HTH|SGE)) &&
!(dstat & (MDPE|BF|ABRT|IID))) {
- if (sist & SBMC) sym_int_sbmc (np);
+ if (sist & SBMC) sym_int_sbmc(shost);
else if (sist & STO) sym_int_sto (np);
else if (sist & UDC) sym_int_udc (np);
else goto unknown_int;
- return;
+ return IRQ_HANDLED;
}
/*
@@ -2884,12 +2906,12 @@ void sym_interrupt (struct sym_hcb *np)
* Reset everything.
*/
- sym_log_hard_error(np, sist, dstat);
+ sym_log_hard_error(shost, sist, dstat);
if ((sist & (GEN|HTH|SGE)) ||
(dstat & (MDPE|BF|ABRT|IID))) {
sym_start_reset(np);
- return;
+ return IRQ_HANDLED;
}
unknown_int:
@@ -2900,6 +2922,7 @@ unknown_int:
printf( "%s: unknown interrupt(s) ignored, "
"ISTAT=0x%x DSTAT=0x%x SIST=0x%x\n",
sym_name(np), istat, dstat, sist);
+ return IRQ_NONE;
}
/*
@@ -3520,7 +3543,8 @@ static void sym_sir_task_recovery(struct sym_hcb *np, int num)
* If we sent a BDR, make upper layer aware of that.
*/
if (np->abrt_msg[0] == M_RESET)
- sym_xpt_async_sent_bdr(np, target);
+ starget_printk(KERN_NOTICE, starget,
+ "has been reset\n");
break;
}
@@ -4304,7 +4328,7 @@ static void sym_nego_rejected(struct sym_hcb *np, struct sym_tcb *tp, struct sym
/*
* chip exception handler for programmed interrupts.
*/
-static void sym_int_sir (struct sym_hcb *np)
+static void sym_int_sir(struct sym_hcb *np)
{
u_char num = INB(np, nc_dsps);
u32 dsa = INL(np, nc_dsa);
@@ -4343,31 +4367,30 @@ static void sym_int_sir (struct sym_hcb *np)
return;
/*
* The device didn't go to MSG OUT phase after having
- * been selected with ATN. We donnot want to handle
- * that.
+ * been selected with ATN. We do not want to handle that.
*/
case SIR_SEL_ATN_NO_MSG_OUT:
- printf ("%s:%d: No MSG OUT phase after selection with ATN.\n",
- sym_name (np), target);
+ scmd_printk(KERN_WARNING, cp->cmd,
+ "No MSG OUT phase after selection with ATN\n");
goto out_stuck;
/*
* The device didn't switch to MSG IN phase after
- * having reseleted the initiator.
+ * having reselected the initiator.
*/
case SIR_RESEL_NO_MSG_IN:
- printf ("%s:%d: No MSG IN phase after reselection.\n",
- sym_name (np), target);
+ scmd_printk(KERN_WARNING, cp->cmd,
+ "No MSG IN phase after reselection\n");
goto out_stuck;
/*
* After reselection, the device sent a message that wasn't
* an IDENTIFY.
*/
case SIR_RESEL_NO_IDENTIFY:
- printf ("%s:%d: No IDENTIFY after reselection.\n",
- sym_name (np), target);
+ scmd_printk(KERN_WARNING, cp->cmd,
+ "No IDENTIFY after reselection\n");
goto out_stuck;
/*
- * The device reselected a LUN we donnot know about.
+ * The device reselected a LUN we do not know about.
*/
case SIR_RESEL_BAD_LUN:
np->msgout[0] = M_RESET;
@@ -4380,8 +4403,7 @@ static void sym_int_sir (struct sym_hcb *np)
np->msgout[0] = M_ABORT;
goto out;
/*
- * The device reselected for a tagged nexus that we donnot
- * have.
+ * The device reselected for a tagged nexus that we do not have.
*/
case SIR_RESEL_BAD_I_T_L_Q:
np->msgout[0] = M_ABORT_TAG;
@@ -4393,8 +4415,8 @@ static void sym_int_sir (struct sym_hcb *np)
case SIR_RESEL_ABORTED:
np->lastmsg = np->msgout[0];
np->msgout[0] = M_NOOP;
- printf ("%s:%d: message %x sent on bad reselection.\n",
- sym_name (np), target, np->lastmsg);
+ scmd_printk(KERN_WARNING, cp->cmd,
+ "message %x sent on bad reselection\n", np->lastmsg);
goto out;
/*
* The SCRIPTS let us know that a message has been
@@ -5578,16 +5600,13 @@ int sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram
np->scriptz_ba = vtobus(np->scriptz0);
if (np->ram_ba) {
- np->scripta_ba = np->ram_ba;
+ np->scripta_ba = np->ram_ba;
if (np->features & FE_RAM8K) {
- np->ram_ws = 8192;
np->scriptb_ba = np->scripta_ba + 4096;
#if 0 /* May get useful for 64 BIT PCI addressing */
np->scr_ram_seg = cpu_to_scr(np->scripta_ba >> 32);
#endif
}
- else
- np->ram_ws = 4096;
}
/*
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h
index 79ab6a17703..ad078805e62 100644
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.h
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h
@@ -883,10 +883,7 @@ struct sym_hcb {
* Physical bus addresses of the chip.
*/
u32 mmio_ba; /* MMIO 32 bit BUS address */
- int mmio_ws; /* MMIO Window size */
-
u32 ram_ba; /* RAM 32 bit BUS address */
- int ram_ws; /* RAM window size */
/*
* SCRIPTS virtual and physical bus addresses.
@@ -912,14 +909,12 @@ struct sym_hcb {
struct sym_fwb_ba fwb_bas; /* Useful SCRIPTB bus addresses */
struct sym_fwz_ba fwz_bas; /* Useful SCRIPTZ bus addresses */
void (*fw_setup)(struct sym_hcb *np, struct sym_fw *fw);
- void (*fw_patch)(struct sym_hcb *np);
+ void (*fw_patch)(struct Scsi_Host *);
char *fw_name;
/*
* General controller parameters and configuration.
*/
- u_short device_id; /* PCI device id */
- u_char revision_id; /* PCI device revision id */
u_int features; /* Chip features map */
u_char myaddr; /* SCSI id of the adapter */
u_char maxburst; /* log base 2 of dwords burst */
@@ -1031,6 +1026,14 @@ struct sym_hcb {
#endif
};
+#if SYM_CONF_DMA_ADDRESSING_MODE == 0
+#define use_dac(np) 0
+#define set_dac(np) do { } while (0)
+#else
+#define use_dac(np) (np)->use_dac
+#define set_dac(np) (np)->use_dac = 1
+#endif
+
#define HCB_BA(np, lbl) (np->hcb_ba + offsetof(struct sym_hcb, lbl))
@@ -1052,8 +1055,8 @@ void sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn);
#else
void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp);
#endif
-void sym_start_up(struct sym_hcb *np, int reason);
-void sym_interrupt(struct sym_hcb *np);
+void sym_start_up(struct Scsi_Host *, int reason);
+irqreturn_t sym_interrupt(struct Scsi_Host *);
int sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int task);
struct sym_ccb *sym_get_ccb(struct sym_hcb *np, struct scsi_cmnd *cmd, u_char tag_order);
void sym_free_ccb(struct sym_hcb *np, struct sym_ccb *cp);
@@ -1073,18 +1076,21 @@ int sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram
*/
#if SYM_CONF_DMA_ADDRESSING_MODE == 0
+#define DMA_DAC_MASK DMA_32BIT_MASK
#define sym_build_sge(np, data, badd, len) \
do { \
(data)->addr = cpu_to_scr(badd); \
(data)->size = cpu_to_scr(len); \
} while (0)
#elif SYM_CONF_DMA_ADDRESSING_MODE == 1
+#define DMA_DAC_MASK DMA_40BIT_MASK
#define sym_build_sge(np, data, badd, len) \
do { \
(data)->addr = cpu_to_scr(badd); \
(data)->size = cpu_to_scr((((badd) >> 8) & 0xff000000) + len); \
} while (0)
#elif SYM_CONF_DMA_ADDRESSING_MODE == 2
+#define DMA_DAC_MASK DMA_64BIT_MASK
int sym_lookup_dmap(struct sym_hcb *np, u32 h, int s);
static __inline void
sym_build_sge(struct sym_hcb *np, struct sym_tblmove *data, u64 badd, int len)
diff --git a/drivers/scsi/sym53c8xx_2/sym_nvram.c b/drivers/scsi/sym53c8xx_2/sym_nvram.c
index 15d69298ab6..5662fbb3ff6 100644
--- a/drivers/scsi/sym53c8xx_2/sym_nvram.c
+++ b/drivers/scsi/sym53c8xx_2/sym_nvram.c
@@ -696,7 +696,7 @@ static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram)
u_short csum;
int x;
- switch (np->device_id) {
+ switch (np->pdev->device) {
case PCI_DEVICE_ID_NCR_53C885:
case PCI_DEVICE_ID_NCR_53C895:
case PCI_DEVICE_ID_NCR_53C896:
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 5db1520f8ba..44193049c4a 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -430,10 +430,7 @@ static __inline__ void dc390_Going_remove (struct dc390_dcb* pDCB, struct dc390_
static struct scatterlist* dc390_sg_build_single(struct scatterlist *sg, void *addr, unsigned int length)
{
- memset(sg, 0, sizeof(struct scatterlist));
- sg->page = virt_to_page(addr);
- sg->length = length;
- sg->offset = (unsigned long)addr & ~PAGE_MASK;
+ sg_init_one(sg, addr, length);
return sg;
}
@@ -567,12 +564,12 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr
pDCB->TagMask |= 1 << tag[1];
pSRB->TagNumber = tag[1];
DC390_write8(ScsiFifo, tag[1]);
- DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for Cmd %li (SRB %p), block tag %02x\n", scmd->pid, pSRB, tag[1]));
+ DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for Cmd %li (SRB %p), block tag %02x\n", scmd->serial_number, pSRB, tag[1]));
cmd = SEL_W_ATN3;
} else {
/* No TagQ */
//no_tag:
- DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", disc_allowed ? "" : "o", scmd->pid, pSRB));
+ DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", disc_allowed ? "" : "o", scmd->serial_number, pSRB));
}
pSRB->SRBState = SRB_START_;
@@ -623,7 +620,7 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr
{
dc390_freetag (pDCB, pSRB);
DEBUG0(printk ("DC390: Interrupt during Start SCSI (pid %li, target %02i-%02i)\n",
- scmd->pid, scmd->device->id, scmd->device->lun));
+ scmd->serial_number, scmd->device->id, scmd->device->lun));
pSRB->SRBState = SRB_READY;
//DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
pACB->SelLost++;
@@ -1708,7 +1705,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
status = pSRB->TargetStatus;
DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\
- pSRB, pcmd->pid));
+ pSRB, pcmd->serial_number));
if(pSRB->SRBFlag & AUTO_REQSENSE)
{ /* Last command was a Request Sense */
pSRB->SRBFlag &= ~AUTO_REQSENSE;
@@ -1729,7 +1726,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
} else {
SET_RES_DRV(pcmd->result, DRIVER_SENSE);
//pSRB->ScsiCmdLen = (u8) (pSRB->Segment1[0] >> 8);
- DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
+ DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->serial_number, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
pSRB->TotalXferredLen = 0;
SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
}
@@ -1749,7 +1746,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
else if (status == SAM_STAT_TASK_SET_FULL)
{
scsi_track_queue_full(pcmd->device, pDCB->GoingSRBCnt - 1);
- DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
+ DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->serial_number, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
pSRB->TotalXferredLen = 0;
SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
}
@@ -1803,7 +1800,7 @@ cmd_done:
/* Add to free list */
dc390_Free_insert (pACB, pSRB);
- DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->pid));
+ DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->serial_number));
pcmd->scsi_done (pcmd);
return;
@@ -1998,7 +1995,7 @@ static int DC390_abort(struct scsi_cmnd *cmd)
struct dc390_dcb *pDCB = (struct dc390_dcb*) cmd->device->hostdata;
scmd_printk(KERN_WARNING, cmd,
- "DC390: Abort command (pid %li)\n", cmd->pid);
+ "DC390: Abort command (pid %li)\n", cmd->serial_number);
/* abort() is too stupid for already sent commands at the moment.
* If it's called we are in trouble anyway, so let's dump some info
@@ -2006,7 +2003,7 @@ static int DC390_abort(struct scsi_cmnd *cmd)
dc390_dumpinfo(pACB, pDCB, NULL);
pDCB->DCBFlag |= ABORT_DEV_;
- printk(KERN_INFO "DC390: Aborted pid %li\n", cmd->pid);
+ printk(KERN_INFO "DC390: Aborted pid %li\n", cmd->serial_number);
return FAILED;
}
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 9e8232a1f16..7edd6ceb13b 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -450,7 +450,8 @@ static struct scsi_host_template driver_template = {
.slave_configure = u14_34f_slave_configure,
.this_id = 7,
.unchecked_isa_dma = 1,
- .use_clustering = ENABLE_CLUSTERING
+ .use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD)
@@ -1254,7 +1255,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs
if (SCpnt->host_scribble)
panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
- BN(j), SCpnt->pid, SCpnt);
+ BN(j), SCpnt->serial_number, SCpnt);
/* i is the mailbox number, look for the first free mailbox
starting from last_cp_used */
@@ -1285,7 +1286,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs
if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
BN(j), i, SCpnt->device->channel, SCpnt->device->id,
- SCpnt->device->lun, SCpnt->pid);
+ SCpnt->device->lun, SCpnt->serial_number);
cpp->opcode = OP_SCSI;
cpp->channel = SCpnt->device->channel;
@@ -1312,7 +1313,7 @@ static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scs
unmap_dma(i, j);
SCpnt->host_scribble = NULL;
scmd_printk(KERN_INFO, SCpnt,
- "qcomm, pid %ld, adapter busy.\n", SCpnt->pid);
+ "qcomm, pid %ld, adapter busy.\n", SCpnt->serial_number);
return 1;
}
@@ -1333,13 +1334,13 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
if (SCarg->host_scribble == NULL) {
scmd_printk(KERN_INFO, SCarg, "abort, pid %ld inactive.\n",
- SCarg->pid);
+ SCarg->serial_number);
return SUCCESS;
}
i = *(unsigned int *)SCarg->host_scribble;
scmd_printk(KERN_INFO, SCarg, "abort, mbox %d, pid %ld.\n",
- i, SCarg->pid);
+ i, SCarg->serial_number);
if (i >= sh[j]->can_queue)
panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
@@ -1383,7 +1384,7 @@ static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
SCarg->host_scribble = NULL;
HD(j)->cp_stat[i] = FREE;
printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
- BN(j), i, SCarg->pid);
+ BN(j), i, SCarg->serial_number);
SCarg->scsi_done(SCarg);
return SUCCESS;
}
@@ -1397,12 +1398,12 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
struct scsi_cmnd *SCpnt;
j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number;
- scmd_printk(KERN_INFO, SCarg, "reset, enter, pid %ld.\n", SCarg->pid);
+ scmd_printk(KERN_INFO, SCarg, "reset, enter, pid %ld.\n", SCarg->serial_number);
spin_lock_irq(sh[j]->host_lock);
if (SCarg->host_scribble == NULL)
- printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
+ printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->serial_number);
if (HD(j)->in_reset) {
printk("%s: reset, exit, already in reset.\n", BN(j));
@@ -1440,13 +1441,13 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
HD(j)->cp_stat[i] = ABORTING;
printk("%s: reset, mbox %d aborting, pid %ld.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->serial_number);
}
else {
HD(j)->cp_stat[i] = IN_RESET;
printk("%s: reset, mbox %d in reset, pid %ld.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->serial_number);
}
if (SCpnt->host_scribble == NULL)
@@ -1495,7 +1496,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
HD(j)->cp_stat[i] = LOCKED;
printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->serial_number);
}
else if (HD(j)->cp_stat[i] == ABORTING) {
@@ -1508,7 +1509,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
HD(j)->cp_stat[i] = FREE;
printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->serial_number);
}
else
@@ -1522,7 +1523,7 @@ static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
HD(j)->in_reset = FALSE;
do_trace = FALSE;
- if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->pid);
+ if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->serial_number);
else printk("%s: reset, exit.\n", BN(j));
spin_unlock_irq(sh[j]->host_lock);
@@ -1639,7 +1640,7 @@ static int reorder(unsigned int j, unsigned long cursec,
if (!input_only) for (n = 0; n < n_ready; n++) {
k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
- ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->pid;
+ ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->serial_number;
if (!n) continue;
@@ -1666,7 +1667,7 @@ static int reorder(unsigned int j, unsigned long cursec,
printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"\
" cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
(ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
- SCpnt->lun, SCpnt->pid, k, flushcount, n_ready,
+ SCpnt->lun, SCpnt->serial_number, k, flushcount, n_ready,
SCpnt->request->sector, SCpnt->request->nr_sectors, cursec,
YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
YESNO(overlap), cpp->xdir);
@@ -1703,7 +1704,7 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec, unsigned in
scmd_printk(KERN_INFO, SCpnt,
"%s, pid %ld, mbox %d, adapter"
" busy, will abort.\n", (ihdlr ? "ihdlr" : "qcomm"),
- SCpnt->pid, k);
+ SCpnt->serial_number, k);
HD(j)->cp_stat[k] = ABORTING;
continue;
}
@@ -1787,11 +1788,11 @@ static irqreturn_t ihdlr(int irq, unsigned int j) {
if (SCpnt->host_scribble == NULL)
panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i,
- SCpnt->pid, SCpnt);
+ SCpnt->serial_number, SCpnt);
if (*(unsigned int *)SCpnt->host_scribble != i)
panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
- BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
+ BN(j), i, SCpnt->serial_number, *(unsigned int *)SCpnt->host_scribble);
sync_dma(i, j);
@@ -1835,12 +1836,12 @@ static irqreturn_t ihdlr(int irq, unsigned int j) {
(SCpnt->sense_buffer[2] & 0xf) == NOT_READY)))
scmd_printk(KERN_INFO, SCpnt,
"ihdlr, pid %ld, target_status 0x%x, sense key 0x%x.\n",
- SCpnt->pid, spp->target_status,
+ SCpnt->serial_number, spp->target_status,
SCpnt->sense_buffer[2]);
HD(j)->target_to[scmd_id(SCpnt)][scmd_channel(SCpnt)] = 0;
- if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
+ if (HD(j)->last_retried_pid == SCpnt->serial_number) HD(j)->retries = 0;
break;
case ASST: /* Selection Time Out */
@@ -1877,7 +1878,7 @@ static irqreturn_t ihdlr(int irq, unsigned int j) {
#endif
HD(j)->retries++;
- HD(j)->last_retried_pid = SCpnt->pid;
+ HD(j)->last_retried_pid = SCpnt->serial_number;
}
else
status = DID_ERROR << 16;
@@ -1907,7 +1908,7 @@ static irqreturn_t ihdlr(int irq, unsigned int j) {
#endif
scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"\
" pid %ld, reg 0x%x, count %d.\n",
- i, spp->adapter_status, spp->target_status, SCpnt->pid,
+ i, spp->adapter_status, spp->target_status, SCpnt->serial_number,
reg, HD(j)->iocount);
unmap_dma(i, j);
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index c08235d5afc..6d1f0edd798 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -681,7 +681,7 @@ static inline void build_sg_list(struct mscp *mscp, struct scsi_cmnd *SCpnt)
max = scsi_sg_count(SCpnt);
scsi_for_each_sg(SCpnt, sg, max, i) {
- mscp->sglist[i].address = isa_page_to_bus(sg->page) + sg->offset;
+ mscp->sglist[i].address = isa_page_to_bus(sg_page(sg)) + sg->offset;
mscp->sglist[i].num_bytes = sg->length;
transfer_length += sg->length;
}
@@ -1197,5 +1197,6 @@ static struct scsi_host_template driver_template = {
.cmd_per_lun = ULTRASTOR_MAX_CMDS_PER_LUN,
.unchecked_isa_dma = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
#include "scsi_module.c"
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index b92ff047af3..fdbb92d1f72 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -381,7 +381,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata;
DB(DB_QUEUE_COMMAND,
- printk("Q-%d-%02x-%ld( ", cmd->device->id, cmd->cmnd[0], cmd->pid))
+ printk("Q-%d-%02x-%ld( ", cmd->device->id, cmd->cmnd[0], cmd->serial_number))
/* Set up a few fields in the scsi_cmnd structure for our own use:
* - host_scribble is the pointer to the next cmd in the input queue
@@ -410,8 +410,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
if (cmd->use_sg) {
cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
- cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
- cmd->SCp.buffer->offset;
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
cmd->SCp.this_residual = cmd->SCp.buffer->length;
} else {
cmd->SCp.buffer = NULL;
@@ -463,7 +462,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
wd33c93_execute(cmd->device->host);
- DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->pid))
+ DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->serial_number))
spin_unlock_irq(&hostdata->lock);
return 0;
@@ -686,7 +685,7 @@ wd33c93_execute(struct Scsi_Host *instance)
*/
DB(DB_EXECUTE,
- printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->pid))
+ printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->serial_number))
}
static void
@@ -745,8 +744,7 @@ transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd,
++cmd->SCp.buffer;
--cmd->SCp.buffers_residual;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
- cmd->SCp.buffer->offset;
+ cmd->SCp.ptr = sg_virt(cmd->SCp.buffer);
}
if (!cmd->SCp.this_residual) /* avoid bogus setups */
return;
@@ -963,7 +961,7 @@ wd33c93_intr(struct Scsi_Host *instance)
case CSR_XFER_DONE | PHS_COMMAND:
case CSR_UNEXP | PHS_COMMAND:
case CSR_SRV_REQ | PHS_COMMAND:
- DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid))
+ DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number))
transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR,
hostdata);
hostdata->state = S_CONNECTED;
@@ -1007,7 +1005,7 @@ wd33c93_intr(struct Scsi_Host *instance)
switch (msg) {
case COMMAND_COMPLETE:
- DB(DB_INTR, printk("CCMP-%ld", cmd->pid))
+ DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number))
write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
hostdata->state = S_PRE_CMP_DISC;
break;
@@ -1174,7 +1172,7 @@ wd33c93_intr(struct Scsi_Host *instance)
write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
if (phs == 0x60) {
- DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid))
+ DB(DB_INTR, printk("SX-DONE-%ld", cmd->serial_number))
cmd->SCp.Message = COMMAND_COMPLETE;
lun = read_wd33c93(regs, WD_TARGET_LUN);
DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))
@@ -1201,7 +1199,7 @@ wd33c93_intr(struct Scsi_Host *instance)
} else {
printk
("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",
- asr, sr, phs, cmd->pid);
+ asr, sr, phs, cmd->serial_number);
spin_unlock_irqrestore(&hostdata->lock, flags);
}
break;
@@ -1266,7 +1264,7 @@ wd33c93_intr(struct Scsi_Host *instance)
spin_unlock_irqrestore(&hostdata->lock, flags);
return;
}
- DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid))
+ DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->serial_number))
hostdata->connected = NULL;
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
hostdata->state = S_UNCONNECTED;
@@ -1292,7 +1290,7 @@ wd33c93_intr(struct Scsi_Host *instance)
*/
write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
- DB(DB_INTR, printk("DISC-%ld", cmd->pid))
+ DB(DB_INTR, printk("DISC-%ld", cmd->serial_number))
if (cmd == NULL) {
printk(" - Already disconnected! ");
hostdata->state = S_UNCONNECTED;
@@ -1491,7 +1489,7 @@ wd33c93_intr(struct Scsi_Host *instance)
} else
hostdata->state = S_CONNECTED;
- DB(DB_INTR, printk("-%ld", cmd->pid))
+ DB(DB_INTR, printk("-%ld", cmd->serial_number))
spin_unlock_irqrestore(&hostdata->lock, flags);
break;
@@ -1638,7 +1636,7 @@ wd33c93_abort(struct scsi_cmnd * cmd)
cmd->result = DID_ABORT << 16;
printk
("scsi%d: Abort - removing command %ld from input_Q. ",
- instance->host_no, cmd->pid);
+ instance->host_no, cmd->serial_number);
enable_irq(cmd->device->host->irq);
cmd->scsi_done(cmd);
return SUCCESS;
@@ -1663,7 +1661,7 @@ wd33c93_abort(struct scsi_cmnd * cmd)
unsigned long timeout;
printk("scsi%d: Aborting connected command %ld - ",
- instance->host_no, cmd->pid);
+ instance->host_no, cmd->serial_number);
printk("stopping DMA - ");
if (hostdata->dma == D_DMA_RUNNING) {
@@ -1730,7 +1728,7 @@ wd33c93_abort(struct scsi_cmnd * cmd)
if (tmp == cmd) {
printk
("scsi%d: Abort - command %ld found on disconnected_Q - ",
- instance->host_no, cmd->pid);
+ instance->host_no, cmd->serial_number);
printk("Abort SNOOZE. ");
enable_irq(cmd->device->host->irq);
return FAILED;
@@ -2184,7 +2182,7 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
if (hd->connected) {
cmd = (struct scsi_cmnd *) hd->connected;
sprintf(tbuf, " %ld-%d:%d(%02x)",
- cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
}
}
@@ -2193,7 +2191,7 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
cmd = (struct scsi_cmnd *) hd->input_Q;
while (cmd) {
sprintf(tbuf, " %ld-%d:%d(%02x)",
- cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
cmd = (struct scsi_cmnd *) cmd->host_scribble;
}
@@ -2203,7 +2201,7 @@ wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off
cmd = (struct scsi_cmnd *) hd->disconnected_Q;
while (cmd) {
sprintf(tbuf, " %ld-%d:%d(%02x)",
- cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
cmd = (struct scsi_cmnd *) cmd->host_scribble;
}
diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h
index 61ffb860dac..00123f2383d 100644
--- a/drivers/scsi/wd33c93.h
+++ b/drivers/scsi/wd33c93.h
@@ -155,7 +155,7 @@
#define WD33C93_FS_12_15 OWNID_FS_12
#define WD33C93_FS_16_20 OWNID_FS_16
- /* pass input-clock explicitely. accepted mhz values are 8-10,12-20 */
+ /* pass input-clock explicitly. accepted mhz values are 8-10,12-20 */
#define WD33C93_FS_MHZ(mhz) (mhz)
/* Control register */
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index d6fd4259c56..03cd44f231d 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1123,7 +1123,7 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
any2scsi(scb->maxlen, nseg * sizeof(Sgb));
scsi_for_each_sg(SCpnt, sg, nseg, i) {
- any2scsi(sgb[i].ptr, isa_page_to_bus(sg->page) + sg->offset);
+ any2scsi(sgb[i].ptr, isa_page_to_bus(sg_page(sg)) + sg->offset);
any2scsi(sgb[i].len, sg->length);
}
} else {
@@ -1671,6 +1671,7 @@ static struct scsi_host_template driver_template = {
.cmd_per_lun = 1,
.unchecked_isa_dma = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .use_sg_chaining = ENABLE_SG_CHAINING,
};
#include "scsi_module.c"
diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c
index c822debc266..ac67394c737 100644
--- a/drivers/scsi/zorro7xx.c
+++ b/drivers/scsi/zorro7xx.c
@@ -69,7 +69,7 @@ static struct zorro_device_id zorro7xx_zorro_tbl[] __devinitdata = {
static int __devinit zorro7xx_init_one(struct zorro_dev *z,
const struct zorro_device_id *ent)
{
- struct Scsi_Host * host = NULL;
+ struct Scsi_Host *host;
struct NCR_700_Host_Parameters *hostdata;
struct zorro_driver_data *zdd;
unsigned long board, ioaddr;
@@ -89,14 +89,12 @@ static int __devinit zorro7xx_init_one(struct zorro_dev *z,
return -EBUSY;
}
- hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
- if (hostdata == NULL) {
+ hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (!hostdata) {
printk(KERN_ERR "zorro7xx: Failed to allocate host data\n");
goto out_release;
}
- memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
-
/* Fill in the required pieces of hostdata */
if (ioaddr > 0x01000000)
hostdata->base = ioremap(ioaddr, zorro_resource_len(z));
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
index 4d4c9f01be8..1f16de71996 100644
--- a/drivers/serial/8250_early.c
+++ b/drivers/serial/8250_early.c
@@ -76,7 +76,7 @@ static void __init wait_for_xmitr(struct uart_port *port)
}
}
-static void __init putc(struct uart_port *port, int c)
+static void __init serial_putc(struct uart_port *port, int c)
{
wait_for_xmitr(port);
serial_out(port, UART_TX, c);
@@ -91,7 +91,7 @@ static void __init early_serial8250_write(struct console *console, const char *s
ier = serial_in(port, UART_IER);
serial_out(port, UART_IER, 0);
- uart_console_write(port, s, count, putc);
+ uart_console_write(port, s, count, serial_putc);
/* Wait for transmitter to become empty and restore the IER */
wait_for_xmitr(port);
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 1ea1ed82c35..ceb03c9e749 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -1036,6 +1036,7 @@ enum pci_board_num_t {
pbn_b0_2_115200,
pbn_b0_4_115200,
pbn_b0_5_115200,
+ pbn_b0_8_115200,
pbn_b0_1_921600,
pbn_b0_2_921600,
@@ -1172,6 +1173,12 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.base_baud = 115200,
.uart_offset = 8,
},
+ [pbn_b0_8_115200] = {
+ .flags = FL_BASE0,
+ .num_ports = 8,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
[pbn_b0_1_921600] = {
.flags = FL_BASE0,
@@ -1979,6 +1986,7 @@ static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
static int pciserial_resume_one(struct pci_dev *dev)
{
+ int err;
struct serial_private *priv = pci_get_drvdata(dev);
pci_set_power_state(dev, PCI_D0);
@@ -1988,7 +1996,9 @@ static int pciserial_resume_one(struct pci_dev *dev)
/*
* The device may have been disabled. Re-enable it.
*/
- pci_enable_device(dev);
+ err = pci_enable_device(dev);
+ if (err)
+ return err;
pciserial_resume_ports(priv);
}
@@ -2566,6 +2576,119 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8,
0, 0, pbn_b2_8_921600 },
+
+ /*
+ * Mainpine series cards: Fairly standard layout but fools
+ * parts of the autodetect in some cases and uses otherwise
+ * unmatched communications subclasses in the PCI Express case
+ */
+
+ { /* RockForceDUO */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0200,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceQUATRO */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0300,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceDUO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0400,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceQUATRO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0500,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForce+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0600,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForce+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0700,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceOCTO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0800,
+ 0, 0, pbn_b0_8_115200 },
+ { /* RockForceDUO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0C00,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceQUARTRO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x0D00,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceOCTO+ */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x1D00,
+ 0, 0, pbn_b0_8_115200 },
+ { /* RockForceD1 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2000,
+ 0, 0, pbn_b0_1_115200 },
+ { /* RockForceF1 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2100,
+ 0, 0, pbn_b0_1_115200 },
+ { /* RockForceD2 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2200,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceF2 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2300,
+ 0, 0, pbn_b0_2_115200 },
+ { /* RockForceD4 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2400,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceF4 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2500,
+ 0, 0, pbn_b0_4_115200 },
+ { /* RockForceD8 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2600,
+ 0, 0, pbn_b0_8_115200 },
+ { /* RockForceF8 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x2700,
+ 0, 0, pbn_b0_8_115200 },
+ { /* IQ Express D1 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3000,
+ 0, 0, pbn_b0_1_115200 },
+ { /* IQ Express F1 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3100,
+ 0, 0, pbn_b0_1_115200 },
+ { /* IQ Express D2 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3200,
+ 0, 0, pbn_b0_2_115200 },
+ { /* IQ Express F2 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3300,
+ 0, 0, pbn_b0_2_115200 },
+ { /* IQ Express D4 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3400,
+ 0, 0, pbn_b0_4_115200 },
+ { /* IQ Express F4 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3500,
+ 0, 0, pbn_b0_4_115200 },
+ { /* IQ Express D8 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3C00,
+ 0, 0, pbn_b0_8_115200 },
+ { /* IQ Express F8 */
+ PCI_VENDOR_ID_MAINPINE, PCI_DEVICE_ID_MAINPINE_PBRIDGE,
+ PCI_VENDOR_ID_MAINPINE, 0x3D00,
+ 0, 0, pbn_b0_8_115200 },
+
+
/*
* PA Semi PA6T-1682M on-chip UART
*/
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index 301c8c0be9d..1de098e7549 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -69,6 +69,8 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "CTL3001", 0 },
/* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
{ "CTL3011", 0 },
+ /* Davicom ISA 33.6K Modem */
+ { "DAV0336", 0 },
/* Creative */
/* Creative Modem Blaster Flash56 DI5601-1 */
{ "DMB1032", 0 },
@@ -327,6 +329,8 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "WACF004", 0 },
{ "WACF005", 0 },
{ "WACF006", 0 },
+ { "WACF007", 0 },
+ { "WACF008", 0 },
/* Compaq touchscreen */
{ "FPI2002", 0 },
/* Fujitsu Stylistic touchscreens */
@@ -343,6 +347,11 @@ static const struct pnp_device_id pnp_dev_table[] = {
/* Fujitsu Wacom Tablet PC devices */
{ "FUJ02E5", 0 },
{ "FUJ02E6", 0 },
+ /*
+ * LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in
+ * disguise)
+ */
+ { "LTS0001", 0 },
/* Rockwell's (PORALiNK) 33600 INT PNP */
{ "WCI0003", 0 },
/* Unkown PnP modems */
@@ -430,7 +439,8 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
}
memset(&port, 0, sizeof(struct uart_port));
- port.irq = pnp_irq(dev, 0);
+ if (pnp_irq_valid(dev, 0))
+ port.irq = pnp_irq(dev, 0);
if (pnp_port_valid(dev, 0)) {
port.iobase = pnp_port_start(dev, 0);
port.iotype = UPIO_PORT;
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 81b52b7cca2..ed438bc7e98 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -62,11 +62,11 @@ config SERIAL_8250_CONSOLE
kernel will automatically use the first serial line, /dev/ttyS0, as
system console.
- you can set that using a kernel command line option such as
+ You can set that using a kernel command line option such as
"console=uart8250,io,0x3f8,9600n8"
"console=uart8250,mmio,0xff5e0000,115200n8".
- and it will switch to normal serial console when correponding port is
- ready.
+ and it will switch to normal serial console when the corresponding
+ port is ready.
"earlycon=uart8250,io,0x3f8,9600n8"
"earlycon=uart8250,mmio,0xff5e0000,115200n8".
it will not only setup early console.
@@ -624,7 +624,7 @@ choice
config SERIAL_BFIN_DMA
bool "DMA mode"
- depends on DMA_UNCACHED_1M && !KGDB_UART
+ depends on !DMA_UNCACHED_NONE && !KGDB_UART
help
This driver works under DMA mode. If this option is selected, the
blackfin simple dma driver is also enabled.
@@ -986,6 +986,31 @@ config SERIAL_PMACZILOG
PowerMac machines.
Say Y or M if you want to be able to these serial ports.
+config SERIAL_PMACZILOG_TTYS
+ bool "Use ttySn device nodes for Zilog z85c30"
+ depends on SERIAL_PMACZILOG
+ help
+ The pmac_zilog driver for the z85C30 chip on many powermacs
+ historically used the device numbers for /dev/ttySn. The
+ 8250 serial port driver also uses these numbers, which means
+ the two drivers being unable to coexist; you could not use
+ both z85C30 and 8250 type ports at the same time.
+
+ If this option is not selected, the pmac_zilog driver will
+ use the device numbers allocated for /dev/ttyPZn. This allows
+ the pmac_zilog and 8250 drivers to co-exist, but may cause
+ existing userspace setups to break. Programs that need to
+ access the built-in serial ports on powermacs will need to
+ be reconfigured to use /dev/ttyPZn instead of /dev/ttySn.
+
+ If you enable this option, any z85c30 ports in the system will
+ be registered as ttyS0 onwards as in the past, and you will be
+ unable to use the 8250 module for PCMCIA or other 16C550-style
+ UARTs.
+
+ Say N unless you need the z85c30 ports on your powermac
+ to appear as /dev/ttySn.
+
config SERIAL_PMACZILOG_CONSOLE
bool "Console on PowerMac z85c30 serial port"
depends on SERIAL_PMACZILOG=y
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 72229df9dc1..40604a09292 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -263,15 +263,15 @@ static unsigned int pl01x_get_mctrl(struct uart_port *port)
unsigned int result = 0;
unsigned int status = readw(uap->port.membase + UART01x_FR);
-#define BIT(uartbit, tiocmbit) \
+#define TIOCMBIT(uartbit, tiocmbit) \
if (status & uartbit) \
result |= tiocmbit
- BIT(UART01x_FR_DCD, TIOCM_CAR);
- BIT(UART01x_FR_DSR, TIOCM_DSR);
- BIT(UART01x_FR_CTS, TIOCM_CTS);
- BIT(UART011_FR_RI, TIOCM_RNG);
-#undef BIT
+ TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
+ TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR);
+ TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS);
+ TIOCMBIT(UART011_FR_RI, TIOCM_RNG);
+#undef TIOCMBIT
return result;
}
@@ -282,18 +282,18 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
cr = readw(uap->port.membase + UART011_CR);
-#define BIT(tiocmbit, uartbit) \
+#define TIOCMBIT(tiocmbit, uartbit) \
if (mctrl & tiocmbit) \
cr |= uartbit; \
else \
cr &= ~uartbit
- BIT(TIOCM_RTS, UART011_CR_RTS);
- BIT(TIOCM_DTR, UART011_CR_DTR);
- BIT(TIOCM_OUT1, UART011_CR_OUT1);
- BIT(TIOCM_OUT2, UART011_CR_OUT2);
- BIT(TIOCM_LOOP, UART011_CR_LBE);
-#undef BIT
+ TIOCMBIT(TIOCM_RTS, UART011_CR_RTS);
+ TIOCMBIT(TIOCM_DTR, UART011_CR_DTR);
+ TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1);
+ TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2);
+ TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE);
+#undef TIOCMBIT
writew(cr, uap->port.membase + UART011_CR);
}
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 4d6b3c56d20..111da57f533 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -204,8 +204,6 @@ static u_int atmel_get_mctrl(struct uart_port *port)
*/
static void atmel_stop_tx(struct uart_port *port)
{
- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
-
UART_PUT_IDR(port, ATMEL_US_TXRDY);
}
@@ -214,8 +212,6 @@ static void atmel_stop_tx(struct uart_port *port)
*/
static void atmel_start_tx(struct uart_port *port)
{
- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
-
UART_PUT_IER(port, ATMEL_US_TXRDY);
}
@@ -224,8 +220,6 @@ static void atmel_start_tx(struct uart_port *port)
*/
static void atmel_stop_rx(struct uart_port *port)
{
- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
-
UART_PUT_IDR(port, ATMEL_US_RXRDY);
}
@@ -409,7 +403,6 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
*/
static int atmel_startup(struct uart_port *port)
{
- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
int retval;
/*
@@ -456,8 +449,6 @@ static int atmel_startup(struct uart_port *port)
*/
static void atmel_shutdown(struct uart_port *port)
{
- struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
-
/*
* Disable all interrupts, port and break condition.
*/
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 66c92bc36f3..6f475b60986 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -86,10 +86,8 @@ static void bfin_serial_stop_tx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-#ifdef CONFIG_BF54x
while (!(UART_GET_LSR(uart) & TEMT))
continue;
-#endif
#ifdef CONFIG_SERIAL_BFIN_DMA
disable_dma(uart->tx_dma_channel);
@@ -128,8 +126,8 @@ static void bfin_serial_start_tx(struct uart_port *port)
ier = UART_GET_IER(uart);
ier |= ETBEI;
UART_PUT_IER(uart, ier);
- bfin_serial_tx_chars(uart);
#endif
+ bfin_serial_tx_chars(uart);
#endif
}
@@ -139,18 +137,21 @@ static void bfin_serial_start_tx(struct uart_port *port)
static void bfin_serial_stop_rx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+#ifdef CONFIG_KGDB_UART
+ if (uart->port.line != CONFIG_KGDB_UART_PORT) {
+#endif
#ifdef CONFIG_BF54x
UART_CLEAR_IER(uart, ERBFI);
#else
unsigned short ier;
ier = UART_GET_IER(uart);
-#ifdef CONFIG_KGDB_UART
- if (uart->port.line != CONFIG_KGDB_UART_PORT)
-#endif
ier &= ~ERBFI;
UART_PUT_IER(uart, ier);
#endif
+#ifdef CONFIG_KGDB_UART
+ }
+#endif
}
/*
@@ -173,12 +174,15 @@ void kgdb_put_debug_char(int chr)
uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
while (!(UART_GET_LSR(uart) & THRE)) {
- __builtin_bfin_ssync();
+ SSYNC();
}
+
+#ifndef CONFIG_BF54x
UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
- __builtin_bfin_ssync();
+ SSYNC();
+#endif
UART_PUT_CHAR(uart, (unsigned char)chr);
- __builtin_bfin_ssync();
+ SSYNC();
}
int kgdb_get_debug_char(void)
@@ -192,12 +196,14 @@ int kgdb_get_debug_char(void)
uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
while(!(UART_GET_LSR(uart) & DR)) {
- __builtin_bfin_ssync();
+ SSYNC();
}
+#ifndef CONFIG_BF54x
UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
- __builtin_bfin_ssync();
+ SSYNC();
+#endif
chr = UART_GET_CHAR(uart);
- __builtin_bfin_ssync();
+ SSYNC();
return chr;
}
@@ -225,12 +231,10 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
{
struct tty_struct *tty = uart->port.info->tty;
unsigned int status, ch, flg;
+ static int in_break = 0;
#ifdef CONFIG_KGDB_UART
struct pt_regs *regs = get_irq_regs();
#endif
-#ifdef BF533_FAMILY
- static int in_break = 0;
-#endif
status = UART_GET_LSR(uart);
ch = UART_GET_CHAR(uart);
@@ -256,29 +260,30 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
}
}
#endif
-
-#ifdef BF533_FAMILY
- /* The BF533 family of processors have a nice misbehavior where
- * they continuously generate characters for a "single" break.
- * We have to basically ignore this flood until the "next" valid
- * character comes across. All other Blackfin families operate
- * properly though.
- */
- if (in_break) {
- if (ch != 0) {
- in_break = 0;
- ch = UART_GET_CHAR(uart);
- if (bfin_revid() < 5)
+
+ if (ANOMALY_05000230) {
+ /* The BF533 family of processors have a nice misbehavior where
+ * they continuously generate characters for a "single" break.
+ * We have to basically ignore this flood until the "next" valid
+ * character comes across. All other Blackfin families operate
+ * properly though.
+ * Note: While Anomaly 05000230 does not directly address this,
+ * the changes that went in for it also fixed this issue.
+ */
+ if (in_break) {
+ if (ch != 0) {
+ in_break = 0;
+ ch = UART_GET_CHAR(uart);
+ if (bfin_revid() < 5)
+ return;
+ } else
return;
- } else
- return;
+ }
}
-#endif
if (status & BI) {
-#ifdef BF533_FAMILY
- in_break = 1;
-#endif
+ if (ANOMALY_05000230)
+ in_break = 1;
uart->port.icount.brk++;
if (uart_handle_break(&uart->port))
goto ignore_char;
@@ -697,17 +702,19 @@ static int bfin_serial_startup(struct uart_port *port)
uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
add_timer(&(uart->rx_dma_timer));
#else
+ if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
+ "BFIN_UART_RX", uart)) {
# ifdef CONFIG_KGDB_UART
- if (uart->port.line != CONFIG_KGDB_UART_PORT && request_irq
-# else
- if (request_irq
+ if (uart->port.line != CONFIG_KGDB_UART_PORT) {
# endif
- (uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
- "BFIN_UART_RX", uart)) {
printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
return -EBUSY;
+# ifdef CONFIG_KGDB_UART
+ }
+# endif
}
+
if (request_irq
(uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED,
"BFIN_UART_TX", uart)) {
@@ -962,30 +969,6 @@ static void __init bfin_serial_init_ports(void)
}
#ifdef CONFIG_SERIAL_BFIN_CONSOLE
-static void bfin_serial_console_putchar(struct uart_port *port, int ch)
-{
- struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
- while (!(UART_GET_LSR(uart) & THRE))
- barrier();
- UART_PUT_CHAR(uart, ch);
- SSYNC();
-}
-
-/*
- * Interrupts are disabled on entering
- */
-static void
-bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
-{
- struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
- int flags = 0;
-
- spin_lock_irqsave(&uart->port.lock, flags);
- uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
- spin_unlock_irqrestore(&uart->port.lock, flags);
-
-}
-
/*
* If the port was already initialised (eg, by a boot loader),
* try to determine the current setup.
@@ -1038,19 +1021,25 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
}
pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
}
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+static struct uart_driver bfin_serial_reg;
static int __init
bfin_serial_console_setup(struct console *co, char *options)
{
struct bfin_serial_port *uart;
+# ifdef CONFIG_SERIAL_BFIN_CONSOLE
int baud = 57600;
int bits = 8;
int parity = 'n';
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+# ifdef CONFIG_SERIAL_BFIN_CTSRTS
int flow = 'r';
-#else
+# else
int flow = 'n';
-#endif
+# endif
+# endif
/*
* Check whether an invalid uart number has been specified, and
@@ -1061,15 +1050,45 @@ bfin_serial_console_setup(struct console *co, char *options)
co->index = 0;
uart = &bfin_serial_ports[co->index];
+# ifdef CONFIG_SERIAL_BFIN_CONSOLE
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
bfin_serial_console_get_options(uart, &baud, &parity, &bits);
return uart_set_options(&uart->port, co, baud, parity, bits, flow);
+# else
+ return 0;
+# endif
+}
+#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
+ defined (CONFIG_EARLY_PRINTK) */
+
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+static void bfin_serial_console_putchar(struct uart_port *port, int ch)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ while (!(UART_GET_LSR(uart) & THRE))
+ barrier();
+ UART_PUT_CHAR(uart, ch);
+ SSYNC();
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
+ int flags = 0;
+
+ spin_lock_irqsave(&uart->port.lock, flags);
+ uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+
}
-static struct uart_driver bfin_serial_reg;
static struct console bfin_serial_console = {
.name = BFIN_SERIAL_NAME,
.write = bfin_serial_console_write,
@@ -1095,7 +1114,64 @@ console_initcall(bfin_serial_rs_console_init);
#define BFIN_SERIAL_CONSOLE &bfin_serial_console
#else
#define BFIN_SERIAL_CONSOLE NULL
-#endif
+#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
+
+
+#ifdef CONFIG_EARLY_PRINTK
+static __init void early_serial_putc(struct uart_port *port, int ch)
+{
+ unsigned timeout = 0xffff;
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+ while ((!(UART_GET_LSR(uart) & THRE)) && --timeout)
+ cpu_relax();
+ UART_PUT_CHAR(uart, ch);
+}
+
+static __init void early_serial_write(struct console *con, const char *s,
+ unsigned int n)
+{
+ struct bfin_serial_port *uart = &bfin_serial_ports[con->index];
+ unsigned int i;
+
+ for (i = 0; i < n; i++, s++) {
+ if (*s == '\n')
+ early_serial_putc(&uart->port, '\r');
+ early_serial_putc(&uart->port, *s);
+ }
+}
+
+static struct __init console bfin_early_serial_console = {
+ .name = "early_BFuart",
+ .write = early_serial_write,
+ .device = uart_console_device,
+ .flags = CON_PRINTBUFFER,
+ .setup = bfin_serial_console_setup,
+ .index = -1,
+ .data = &bfin_serial_reg,
+};
+
+struct console __init *bfin_earlyserial_init(unsigned int port,
+ unsigned int cflag)
+{
+ struct bfin_serial_port *uart;
+ struct ktermios t;
+
+ if (port == -1 || port >= nr_ports)
+ port = 0;
+ bfin_serial_init_ports();
+ bfin_early_serial_console.index = port;
+ uart = &bfin_serial_ports[port];
+ t.c_cflag = cflag;
+ t.c_iflag = 0;
+ t.c_oflag = 0;
+ t.c_lflag = ICANON;
+ t.c_line = port;
+ bfin_serial_set_termios(&uart->port, &t, &t);
+ return &bfin_early_serial_console;
+}
+
+#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
static struct uart_driver bfin_serial_reg = {
.owner = THIS_MODULE,
@@ -1182,7 +1258,7 @@ static int __init bfin_serial_init(void)
int ret;
#ifdef CONFIG_KGDB_UART
struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
- struct termios t;
+ struct ktermios t;
#endif
pr_info("Serial: Blackfin serial driver\n");
@@ -1199,11 +1275,15 @@ static int __init bfin_serial_init(void)
}
#ifdef CONFIG_KGDB_UART
if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) {
- request_irq(uart->port.irq, bfin_serial_int,
+ request_irq(uart->port.irq, bfin_serial_rx_int,
IRQF_DISABLED, "BFIN_UART_RX", uart);
pr_info("Request irq for kgdb uart port\n");
+#ifdef CONFIG_BF54x
+ UART_SET_IER(uart, ERBFI);
+#else
UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);
- __builtin_bfin_ssync();
+#endif
+ SSYNC();
t.c_cflag = CS8|B57600;
t.c_iflag = 0;
t.c_oflag = 0;
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
index a8f894c7819..32b9737759c 100644
--- a/drivers/serial/cpm_uart/cpm_uart.h
+++ b/drivers/serial/cpm_uart/cpm_uart.h
@@ -56,21 +56,21 @@ struct uart_cpm_port {
u16 rx_fifosize;
u16 tx_nrfifos;
u16 tx_fifosize;
- smc_t *smcp;
- smc_uart_t *smcup;
- scc_t *sccp;
- scc_uart_t *sccup;
- volatile cbd_t *rx_bd_base;
- volatile cbd_t *rx_cur;
- volatile cbd_t *tx_bd_base;
- volatile cbd_t *tx_cur;
+ smc_t __iomem *smcp;
+ smc_uart_t __iomem *smcup;
+ scc_t __iomem *sccp;
+ scc_uart_t __iomem *sccup;
+ cbd_t __iomem *rx_bd_base;
+ cbd_t __iomem *rx_cur;
+ cbd_t __iomem *tx_bd_base;
+ cbd_t __iomem *tx_cur;
unsigned char *tx_buf;
unsigned char *rx_buf;
u32 flags;
void (*set_lineif)(struct uart_cpm_port *);
u8 brg;
uint dp_addr;
- void *mem_addr;
+ void *mem_addr;
dma_addr_t dma_addr;
u32 mem_size;
/* helpers */
@@ -80,14 +80,18 @@ struct uart_cpm_port {
int is_portb;
/* wait on close if needed */
int wait_closing;
+ /* value to combine with opcode to form cpm command */
+ u32 command;
};
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
extern int cpm_uart_port_map[UART_NR];
+#endif
extern int cpm_uart_nr;
extern struct uart_cpm_port cpm_uart_ports[UART_NR];
/* these are located in their respective files */
-void cpm_line_cr_cmd(int line, int cmd);
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd);
int cpm_uart_init_portdesc(void);
int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con);
void cpm_uart_freebuf(struct uart_cpm_port *pinfo);
@@ -102,34 +106,36 @@ void scc4_lineif(struct uart_cpm_port *pinfo);
/*
virtual to phys transtalion
*/
-static inline unsigned long cpu2cpm_addr(void* addr, struct uart_cpm_port *pinfo)
+static inline unsigned long cpu2cpm_addr(void *addr,
+ struct uart_cpm_port *pinfo)
{
int offset;
u32 val = (u32)addr;
+ u32 mem = (u32)pinfo->mem_addr;
/* sane check */
- if (likely((val >= (u32)pinfo->mem_addr)) &&
- (val<((u32)pinfo->mem_addr + pinfo->mem_size))) {
- offset = val - (u32)pinfo->mem_addr;
- return pinfo->dma_addr+offset;
+ if (likely(val >= mem && val < mem + pinfo->mem_size)) {
+ offset = val - mem;
+ return pinfo->dma_addr + offset;
}
/* something nasty happened */
BUG();
return 0;
}
-static inline void *cpm2cpu_addr(unsigned long addr, struct uart_cpm_port *pinfo)
+static inline void *cpm2cpu_addr(unsigned long addr,
+ struct uart_cpm_port *pinfo)
{
int offset;
u32 val = addr;
+ u32 dma = (u32)pinfo->dma_addr;
/* sane check */
- if (likely((val >= pinfo->dma_addr) &&
- (val<(pinfo->dma_addr + pinfo->mem_size)))) {
- offset = val - (u32)pinfo->dma_addr;
- return (void*)(pinfo->mem_addr+offset);
+ if (likely(val >= dma && val < dma + pinfo->mem_size)) {
+ offset = val - dma;
+ return pinfo->mem_addr + offset;
}
/* something nasty happened */
BUG();
- return 0;
+ return NULL;
}
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index cefde58dbad..b5e4478de0e 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -10,7 +10,7 @@
* Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
* Pantelis Antoniou (panto@intracom.gr) (CPM1)
*
- * Copyright (C) 2004 Freescale Semiconductor, Inc.
+ * Copyright (C) 2004, 2007 Freescale Semiconductor, Inc.
* (C) 2004 Intracom, S.A.
* (C) 2005-2006 MontaVista Software, Inc.
* Vitaly Bordug <vbordug@ru.mvista.com>
@@ -47,6 +47,11 @@
#include <asm/irq.h>
#include <asm/delay.h>
#include <asm/fs_pd.h>
+#include <asm/udbg.h>
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
#if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -57,12 +62,6 @@
#include "cpm_uart.h"
-/***********************************************************************/
-
-/* Track which ports are configured as uarts */
-int cpm_uart_port_map[UART_NR];
-/* How many ports did we config as uarts */
-int cpm_uart_nr = 0;
/**************************************************************/
@@ -73,6 +72,11 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo);
/**************************************************************/
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
+/* Track which ports are configured as uarts */
+int cpm_uart_port_map[UART_NR];
+/* How many ports did we config as uarts */
+int cpm_uart_nr;
/* Place-holder for board-specific stuff */
struct platform_device* __attribute__ ((weak)) __init
@@ -119,6 +123,7 @@ static int cpm_uart_id2nr(int id)
/* not found or invalid argument */
return -1;
}
+#endif
/*
* Check, if transmit buffers are processed
@@ -126,14 +131,14 @@ static int cpm_uart_id2nr(int id)
static unsigned int cpm_uart_tx_empty(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile cbd_t *bdp = pinfo->tx_bd_base;
+ cbd_t __iomem *bdp = pinfo->tx_bd_base;
int ret = 0;
while (1) {
- if (bdp->cbd_sc & BD_SC_READY)
+ if (in_be16(&bdp->cbd_sc) & BD_SC_READY)
break;
- if (bdp->cbd_sc & BD_SC_WRAP) {
+ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) {
ret = TIOCSER_TEMT;
break;
}
@@ -162,15 +167,15 @@ static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
static void cpm_uart_stop_tx(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile smc_t *smcp = pinfo->smcp;
- volatile scc_t *sccp = pinfo->sccp;
+ smc_t __iomem *smcp = pinfo->smcp;
+ scc_t __iomem *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:stop tx\n", port->line);
if (IS_SMC(pinfo))
- smcp->smc_smcm &= ~SMCM_TX;
+ clrbits8(&smcp->smc_smcm, SMCM_TX);
else
- sccp->scc_sccm &= ~UART_SCCM_TX;
+ clrbits16(&sccp->scc_sccm, UART_SCCM_TX);
}
/*
@@ -179,24 +184,24 @@ static void cpm_uart_stop_tx(struct uart_port *port)
static void cpm_uart_start_tx(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile smc_t *smcp = pinfo->smcp;
- volatile scc_t *sccp = pinfo->sccp;
+ smc_t __iomem *smcp = pinfo->smcp;
+ scc_t __iomem *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:start tx\n", port->line);
if (IS_SMC(pinfo)) {
- if (smcp->smc_smcm & SMCM_TX)
+ if (in_8(&smcp->smc_smcm) & SMCM_TX)
return;
} else {
- if (sccp->scc_sccm & UART_SCCM_TX)
+ if (in_be16(&sccp->scc_sccm) & UART_SCCM_TX)
return;
}
if (cpm_uart_tx_pump(port) != 0) {
if (IS_SMC(pinfo)) {
- smcp->smc_smcm |= SMCM_TX;
+ setbits8(&smcp->smc_smcm, SMCM_TX);
} else {
- sccp->scc_sccm |= UART_SCCM_TX;
+ setbits16(&sccp->scc_sccm, UART_SCCM_TX);
}
}
}
@@ -207,15 +212,15 @@ static void cpm_uart_start_tx(struct uart_port *port)
static void cpm_uart_stop_rx(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile smc_t *smcp = pinfo->smcp;
- volatile scc_t *sccp = pinfo->sccp;
+ smc_t __iomem *smcp = pinfo->smcp;
+ scc_t __iomem *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:stop rx\n", port->line);
if (IS_SMC(pinfo))
- smcp->smc_smcm &= ~SMCM_RX;
+ clrbits8(&smcp->smc_smcm, SMCM_RX);
else
- sccp->scc_sccm &= ~UART_SCCM_RX;
+ clrbits16(&sccp->scc_sccm, UART_SCCM_RX);
}
/*
@@ -232,15 +237,14 @@ static void cpm_uart_enable_ms(struct uart_port *port)
static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- int line = pinfo - cpm_uart_ports;
pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line,
break_state);
if (break_state)
- cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
else
- cpm_line_cr_cmd(line, CPM_CR_RESTART_TX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
}
/*
@@ -259,10 +263,11 @@ static void cpm_uart_int_tx(struct uart_port *port)
static void cpm_uart_int_rx(struct uart_port *port)
{
int i;
- unsigned char ch, *cp;
+ unsigned char ch;
+ u8 *cp;
struct tty_struct *tty = port->info->tty;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile cbd_t *bdp;
+ cbd_t __iomem *bdp;
u16 status;
unsigned int flg;
@@ -274,13 +279,13 @@ static void cpm_uart_int_rx(struct uart_port *port)
bdp = pinfo->rx_cur;
for (;;) {
/* get status */
- status = bdp->cbd_sc;
+ status = in_be16(&bdp->cbd_sc);
/* If this one is empty, return happy */
if (status & BD_SC_EMPTY)
break;
/* get number of characters, and check spce in flip-buffer */
- i = bdp->cbd_datlen;
+ i = in_be16(&bdp->cbd_datlen);
/* If we have not enough room in tty flip buffer, then we try
* later, which will be the next rx-interrupt or a timeout
@@ -291,7 +296,7 @@ static void cpm_uart_int_rx(struct uart_port *port)
}
/* get pointer */
- cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
+ cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
/* loop through the buffer */
while (i-- > 0) {
@@ -311,10 +316,11 @@ static void cpm_uart_int_rx(struct uart_port *port)
} /* End while (i--) */
/* This BD is ready to be used again. Clear status. get next */
- bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID);
- bdp->cbd_sc |= BD_SC_EMPTY;
+ clrbits16(&bdp->cbd_sc, BD_SC_BR | BD_SC_FR | BD_SC_PR |
+ BD_SC_OV | BD_SC_ID);
+ setbits16(&bdp->cbd_sc, BD_SC_EMPTY);
- if (bdp->cbd_sc & BD_SC_WRAP)
+ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
bdp = pinfo->rx_bd_base;
else
bdp++;
@@ -322,7 +328,7 @@ static void cpm_uart_int_rx(struct uart_port *port)
} /* End for (;;) */
/* Write back buffer pointer */
- pinfo->rx_cur = (volatile cbd_t *) bdp;
+ pinfo->rx_cur = bdp;
/* activate BH processing */
tty_flip_buffer_push(tty);
@@ -376,14 +382,14 @@ static irqreturn_t cpm_uart_int(int irq, void *data)
u8 events;
struct uart_port *port = (struct uart_port *)data;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile smc_t *smcp = pinfo->smcp;
- volatile scc_t *sccp = pinfo->sccp;
+ smc_t __iomem *smcp = pinfo->smcp;
+ scc_t __iomem *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:IRQ\n", port->line);
if (IS_SMC(pinfo)) {
- events = smcp->smc_smce;
- smcp->smc_smce = events;
+ events = in_8(&smcp->smc_smce);
+ out_8(&smcp->smc_smce, events);
if (events & SMCM_BRKE)
uart_handle_break(port);
if (events & SMCM_RX)
@@ -391,8 +397,8 @@ static irqreturn_t cpm_uart_int(int irq, void *data)
if (events & SMCM_TX)
cpm_uart_int_tx(port);
} else {
- events = sccp->scc_scce;
- sccp->scc_scce = events;
+ events = in_be16(&sccp->scc_scce);
+ out_be16(&sccp->scc_scce, events);
if (events & UART_SCCM_BRKE)
uart_handle_break(port);
if (events & UART_SCCM_RX)
@@ -407,7 +413,6 @@ static int cpm_uart_startup(struct uart_port *port)
{
int retval;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- int line = pinfo - cpm_uart_ports;
pr_debug("CPM uart[%d]:startup\n", port->line);
@@ -418,15 +423,15 @@ static int cpm_uart_startup(struct uart_port *port)
/* Startup rx-int */
if (IS_SMC(pinfo)) {
- pinfo->smcp->smc_smcm |= SMCM_RX;
- pinfo->smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
+ setbits8(&pinfo->smcp->smc_smcm, SMCM_RX);
+ setbits16(&pinfo->smcp->smc_smcmr, (SMCMR_REN | SMCMR_TEN));
} else {
- pinfo->sccp->scc_sccm |= UART_SCCM_RX;
- pinfo->sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+ setbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
+ setbits32(&pinfo->sccp->scc_gsmrl, (SCC_GSMRL_ENR | SCC_GSMRL_ENT));
}
if (!(pinfo->flags & FLAG_CONSOLE))
- cpm_line_cr_cmd(line,CPM_CR_INIT_TRX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
return 0;
}
@@ -442,7 +447,6 @@ inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo)
static void cpm_uart_shutdown(struct uart_port *port)
{
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- int line = pinfo - cpm_uart_ports;
pr_debug("CPM uart[%d]:shutdown\n", port->line);
@@ -462,20 +466,20 @@ static void cpm_uart_shutdown(struct uart_port *port)
/* Stop uarts */
if (IS_SMC(pinfo)) {
- volatile smc_t *smcp = pinfo->smcp;
- smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
- smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
+ smc_t __iomem *smcp = pinfo->smcp;
+ clrbits16(&smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
+ clrbits8(&smcp->smc_smcm, SMCM_RX | SMCM_TX);
} else {
- volatile scc_t *sccp = pinfo->sccp;
- sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
+ scc_t __iomem *sccp = pinfo->sccp;
+ clrbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+ clrbits16(&sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
}
/* Shut them really down and reinit buffer descriptors */
if (IS_SMC(pinfo))
- cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
else
- cpm_line_cr_cmd(line, CPM_CR_GRA_STOP_TX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX);
cpm_uart_initbd(pinfo);
}
@@ -490,8 +494,8 @@ static void cpm_uart_set_termios(struct uart_port *port,
u16 cval, scval, prev_mode;
int bits, sbits;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
- volatile smc_t *smcp = pinfo->smcp;
- volatile scc_t *sccp = pinfo->sccp;
+ smc_t __iomem *smcp = pinfo->smcp;
+ scc_t __iomem *sccp = pinfo->sccp;
pr_debug("CPM uart[%d]:set_termios\n", port->line);
@@ -586,16 +590,15 @@ static void cpm_uart_set_termios(struct uart_port *port,
* enables, because we want to put them back if they were
* present.
*/
- prev_mode = smcp->smc_smcmr;
- smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART;
- smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
+ prev_mode = in_be16(&smcp->smc_smcmr);
+ out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval | SMCMR_SM_UART);
+ setbits16(&smcp->smc_smcmr, (prev_mode & (SMCMR_REN | SMCMR_TEN)));
} else {
- sccp->scc_psmr = (sbits << 12) | scval;
+ out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
}
cpm_set_brg(pinfo->brg - 1, baud);
spin_unlock_irqrestore(&port->lock, flags);
-
}
static const char *cpm_uart_type(struct uart_port *port)
@@ -629,8 +632,8 @@ static int cpm_uart_verify_port(struct uart_port *port,
*/
static int cpm_uart_tx_pump(struct uart_port *port)
{
- volatile cbd_t *bdp;
- unsigned char *p;
+ cbd_t __iomem *bdp;
+ u8 *p;
int count;
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
struct circ_buf *xmit = &port->info->xmit;
@@ -640,13 +643,14 @@ static int cpm_uart_tx_pump(struct uart_port *port)
/* Pick next descriptor and fill from buffer */
bdp = pinfo->tx_cur;
- p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
+ p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
*p++ = port->x_char;
- bdp->cbd_datlen = 1;
- bdp->cbd_sc |= BD_SC_READY;
+
+ out_be16(&bdp->cbd_datlen, 1);
+ setbits16(&bdp->cbd_sc, BD_SC_READY);
/* Get next BD. */
- if (bdp->cbd_sc & BD_SC_WRAP)
+ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
bdp = pinfo->tx_bd_base;
else
bdp++;
@@ -665,9 +669,10 @@ static int cpm_uart_tx_pump(struct uart_port *port)
/* Pick next descriptor and fill from buffer */
bdp = pinfo->tx_cur;
- while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) {
+ while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) &&
+ xmit->tail != xmit->head) {
count = 0;
- p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
+ p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
while (count < pinfo->tx_fifosize) {
*p++ = xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@@ -676,11 +681,10 @@ static int cpm_uart_tx_pump(struct uart_port *port)
if (xmit->head == xmit->tail)
break;
}
- bdp->cbd_datlen = count;
- bdp->cbd_sc |= BD_SC_READY;
- eieio();
+ out_be16(&bdp->cbd_datlen, count);
+ setbits16(&bdp->cbd_sc, BD_SC_READY);
/* Get next BD. */
- if (bdp->cbd_sc & BD_SC_WRAP)
+ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
bdp = pinfo->tx_bd_base;
else
bdp++;
@@ -705,7 +709,7 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
{
int i;
u8 *mem_addr;
- volatile cbd_t *bdp;
+ cbd_t __iomem *bdp;
pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line);
@@ -716,13 +720,13 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
mem_addr = pinfo->mem_addr;
bdp = pinfo->rx_cur = pinfo->rx_bd_base;
for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) {
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
- bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
+ out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+ out_be16(&bdp->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
mem_addr += pinfo->rx_fifosize;
}
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
- bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
+ out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+ out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT);
/* Set the physical address of the host memory
* buffers in the buffer descriptors, and the
@@ -731,20 +735,19 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo)
mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize);
bdp = pinfo->tx_cur = pinfo->tx_bd_base;
for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) {
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
- bdp->cbd_sc = BD_SC_INTRPT;
+ out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+ out_be16(&bdp->cbd_sc, BD_SC_INTRPT);
mem_addr += pinfo->tx_fifosize;
}
- bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
- bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT;
+ out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+ out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_INTRPT);
}
static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
{
- int line = pinfo - cpm_uart_ports;
- volatile scc_t *scp;
- volatile scc_uart_t *sup;
+ scc_t __iomem *scp;
+ scc_uart_t __iomem *sup;
pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line);
@@ -752,8 +755,10 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
sup = pinfo->sccup;
/* Store address */
- pinfo->sccup->scc_genscc.scc_rbase = (unsigned char *)pinfo->rx_bd_base - DPRAM_BASE;
- pinfo->sccup->scc_genscc.scc_tbase = (unsigned char *)pinfo->tx_bd_base - DPRAM_BASE;
+ out_be16(&pinfo->sccup->scc_genscc.scc_rbase,
+ (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
+ out_be16(&pinfo->sccup->scc_genscc.scc_tbase,
+ (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
/* Set up the uart parameters in the
* parameter ram.
@@ -761,51 +766,50 @@ static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
cpm_set_scc_fcr(sup);
- sup->scc_genscc.scc_mrblr = pinfo->rx_fifosize;
- sup->scc_maxidl = pinfo->rx_fifosize;
- sup->scc_brkcr = 1;
- sup->scc_parec = 0;
- sup->scc_frmec = 0;
- sup->scc_nosec = 0;
- sup->scc_brkec = 0;
- sup->scc_uaddr1 = 0;
- sup->scc_uaddr2 = 0;
- sup->scc_toseq = 0;
- sup->scc_char1 = 0x8000;
- sup->scc_char2 = 0x8000;
- sup->scc_char3 = 0x8000;
- sup->scc_char4 = 0x8000;
- sup->scc_char5 = 0x8000;
- sup->scc_char6 = 0x8000;
- sup->scc_char7 = 0x8000;
- sup->scc_char8 = 0x8000;
- sup->scc_rccm = 0xc0ff;
+ out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
+ out_be16(&sup->scc_maxidl, pinfo->rx_fifosize);
+ out_be16(&sup->scc_brkcr, 1);
+ out_be16(&sup->scc_parec, 0);
+ out_be16(&sup->scc_frmec, 0);
+ out_be16(&sup->scc_nosec, 0);
+ out_be16(&sup->scc_brkec, 0);
+ out_be16(&sup->scc_uaddr1, 0);
+ out_be16(&sup->scc_uaddr2, 0);
+ out_be16(&sup->scc_toseq, 0);
+ out_be16(&sup->scc_char1, 0x8000);
+ out_be16(&sup->scc_char2, 0x8000);
+ out_be16(&sup->scc_char3, 0x8000);
+ out_be16(&sup->scc_char4, 0x8000);
+ out_be16(&sup->scc_char5, 0x8000);
+ out_be16(&sup->scc_char6, 0x8000);
+ out_be16(&sup->scc_char7, 0x8000);
+ out_be16(&sup->scc_char8, 0x8000);
+ out_be16(&sup->scc_rccm, 0xc0ff);
/* Send the CPM an initialize command.
*/
- cpm_line_cr_cmd(line, CPM_CR_INIT_TRX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
/* Set UART mode, 8 bit, no parity, one stop.
* Enable receive and transmit.
*/
- scp->scc_gsmrh = 0;
- scp->scc_gsmrl =
- (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+ out_be32(&scp->scc_gsmrh, 0);
+ out_be32(&scp->scc_gsmrl,
+ SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
/* Enable rx interrupts and clear all pending events. */
- scp->scc_sccm = 0;
- scp->scc_scce = 0xffff;
- scp->scc_dsr = 0x7e7e;
- scp->scc_psmr = 0x3000;
+ out_be16(&scp->scc_sccm, 0);
+ out_be16(&scp->scc_scce, 0xffff);
+ out_be16(&scp->scc_dsr, 0x7e7e);
+ out_be16(&scp->scc_psmr, 0x3000);
- scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+ setbits32(&scp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
{
- int line = pinfo - cpm_uart_ports;
- volatile smc_t *sp;
- volatile smc_uart_t *up;
+ smc_t __iomem *sp;
+ smc_uart_t __iomem *up;
pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line);
@@ -813,19 +817,21 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
up = pinfo->smcup;
/* Store address */
- pinfo->smcup->smc_rbase = (u_char *)pinfo->rx_bd_base - DPRAM_BASE;
- pinfo->smcup->smc_tbase = (u_char *)pinfo->tx_bd_base - DPRAM_BASE;
+ out_be16(&pinfo->smcup->smc_rbase,
+ (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
+ out_be16(&pinfo->smcup->smc_tbase,
+ (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
/*
* In case SMC1 is being relocated...
*/
#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
- up->smc_rbptr = pinfo->smcup->smc_rbase;
- up->smc_tbptr = pinfo->smcup->smc_tbase;
- up->smc_rstate = 0;
- up->smc_tstate = 0;
- up->smc_brkcr = 1; /* number of break chars */
- up->smc_brkec = 0;
+ out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase));
+ out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase));
+ out_be32(&up->smc_rstate, 0);
+ out_be32(&up->smc_tstate, 0);
+ out_be16(&up->smc_brkcr, 1); /* number of break chars */
+ out_be16(&up->smc_brkec, 0);
#endif
/* Set up the uart parameters in the
@@ -834,24 +840,24 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
cpm_set_smc_fcr(up);
/* Using idle charater time requires some additional tuning. */
- up->smc_mrblr = pinfo->rx_fifosize;
- up->smc_maxidl = pinfo->rx_fifosize;
- up->smc_brklen = 0;
- up->smc_brkec = 0;
- up->smc_brkcr = 1;
+ out_be16(&up->smc_mrblr, pinfo->rx_fifosize);
+ out_be16(&up->smc_maxidl, pinfo->rx_fifosize);
+ out_be16(&up->smc_brklen, 0);
+ out_be16(&up->smc_brkec, 0);
+ out_be16(&up->smc_brkcr, 1);
- cpm_line_cr_cmd(line, CPM_CR_INIT_TRX);
+ cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
/* Set UART mode, 8 bit, no parity, one stop.
* Enable receive and transmit.
*/
- sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+ out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART);
/* Enable only rx interrupts clear all pending events. */
- sp->smc_smcm = 0;
- sp->smc_smce = 0xff;
+ out_8(&sp->smc_smcm, 0);
+ out_8(&sp->smc_smce, 0xff);
- sp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
+ setbits16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
}
/*
@@ -869,11 +875,11 @@ static int cpm_uart_request_port(struct uart_port *port)
return 0;
if (IS_SMC(pinfo)) {
- pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
- pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+ clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
+ clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
} else {
- pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
- pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+ clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
+ clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
ret = cpm_uart_allocbuf(pinfo, 0);
@@ -929,6 +935,86 @@ static struct uart_ops cpm_uart_pops = {
.verify_port = cpm_uart_verify_port,
};
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+struct uart_cpm_port cpm_uart_ports[UART_NR];
+
+static int cpm_uart_init_port(struct device_node *np,
+ struct uart_cpm_port *pinfo)
+{
+ const u32 *data;
+ void __iomem *mem, *pram;
+ int len;
+ int ret;
+
+ data = of_get_property(np, "fsl,cpm-brg", &len);
+ if (!data || len != 4) {
+ printk(KERN_ERR "CPM UART %s has no/invalid "
+ "fsl,cpm-brg property.\n", np->name);
+ return -EINVAL;
+ }
+ pinfo->brg = *data;
+
+ data = of_get_property(np, "fsl,cpm-command", &len);
+ if (!data || len != 4) {
+ printk(KERN_ERR "CPM UART %s has no/invalid "
+ "fsl,cpm-command property.\n", np->name);
+ return -EINVAL;
+ }
+ pinfo->command = *data;
+
+ mem = of_iomap(np, 0);
+ if (!mem)
+ return -ENOMEM;
+
+ pram = of_iomap(np, 1);
+ if (!pram) {
+ ret = -ENOMEM;
+ goto out_mem;
+ }
+
+ if (of_device_is_compatible(np, "fsl,cpm1-scc-uart") ||
+ of_device_is_compatible(np, "fsl,cpm2-scc-uart")) {
+ pinfo->sccp = mem;
+ pinfo->sccup = pram;
+ } else if (of_device_is_compatible(np, "fsl,cpm1-smc-uart") ||
+ of_device_is_compatible(np, "fsl,cpm2-smc-uart")) {
+ pinfo->flags |= FLAG_SMC;
+ pinfo->smcp = mem;
+ pinfo->smcup = pram;
+ } else {
+ ret = -ENODEV;
+ goto out_pram;
+ }
+
+ pinfo->tx_nrfifos = TX_NUM_FIFO;
+ pinfo->tx_fifosize = TX_BUF_SIZE;
+ pinfo->rx_nrfifos = RX_NUM_FIFO;
+ pinfo->rx_fifosize = RX_BUF_SIZE;
+
+ pinfo->port.uartclk = ppc_proc_freq;
+ pinfo->port.mapbase = (unsigned long)mem;
+ pinfo->port.type = PORT_CPM;
+ pinfo->port.ops = &cpm_uart_pops,
+ pinfo->port.iotype = UPIO_MEM;
+ spin_lock_init(&pinfo->port.lock);
+
+ pinfo->port.irq = of_irq_to_resource(np, 0, NULL);
+ if (pinfo->port.irq == NO_IRQ) {
+ ret = -EINVAL;
+ goto out_pram;
+ }
+
+ return cpm_uart_request_port(&pinfo->port);
+
+out_pram:
+ iounmap(pram);
+out_mem:
+ iounmap(mem);
+ return ret;
+}
+
+#else
+
struct uart_cpm_port cpm_uart_ports[UART_NR] = {
[UART_SMC1] = {
.port = {
@@ -1072,6 +1158,7 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con)
return 0;
}
+#endif
#ifdef CONFIG_SERIAL_CPM_CONSOLE
/*
@@ -1083,11 +1170,15 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con)
static void cpm_uart_console_write(struct console *co, const char *s,
u_int count)
{
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index];
+#else
struct uart_cpm_port *pinfo =
&cpm_uart_ports[cpm_uart_port_map[co->index]];
+#endif
unsigned int i;
- volatile cbd_t *bdp, *bdbase;
- volatile unsigned char *cp;
+ cbd_t __iomem *bdp, *bdbase;
+ unsigned char *cp;
/* Get the address of the host memory buffer.
*/
@@ -1105,37 +1196,36 @@ static void cpm_uart_console_write(struct console *co, const char *s,
* Ready indicates output is ready, and xmt is doing
* that, not that it is ready for us to send.
*/
- while ((bdp->cbd_sc & BD_SC_READY) != 0)
+ while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
;
/* Send the character out.
* If the buffer address is in the CPM DPRAM, don't
* convert it.
*/
- cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
-
+ cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
*cp = *s;
- bdp->cbd_datlen = 1;
- bdp->cbd_sc |= BD_SC_READY;
+ out_be16(&bdp->cbd_datlen, 1);
+ setbits16(&bdp->cbd_sc, BD_SC_READY);
- if (bdp->cbd_sc & BD_SC_WRAP)
+ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
bdp = bdbase;
else
bdp++;
/* if a LF, also do CR... */
if (*s == 10) {
- while ((bdp->cbd_sc & BD_SC_READY) != 0)
+ while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
;
- cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
-
+ cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
*cp = 13;
- bdp->cbd_datlen = 1;
- bdp->cbd_sc |= BD_SC_READY;
- if (bdp->cbd_sc & BD_SC_WRAP)
+ out_be16(&bdp->cbd_datlen, 1);
+ setbits16(&bdp->cbd_sc, BD_SC_READY);
+
+ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
bdp = bdbase;
else
bdp++;
@@ -1146,22 +1236,56 @@ static void cpm_uart_console_write(struct console *co, const char *s,
* Finally, Wait for transmitter & holding register to empty
* and restore the IER
*/
- while ((bdp->cbd_sc & BD_SC_READY) != 0)
+ while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
;
- pinfo->tx_cur = (volatile cbd_t *) bdp;
+ pinfo->tx_cur = bdp;
}
static int __init cpm_uart_console_setup(struct console *co, char *options)
{
- struct uart_port *port;
- struct uart_cpm_port *pinfo;
int baud = 38400;
int bits = 8;
int parity = 'n';
int flow = 'n';
int ret;
+ struct uart_cpm_port *pinfo;
+ struct uart_port *port;
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct device_node *np = NULL;
+ int i = 0;
+
+ if (co->index >= UART_NR) {
+ printk(KERN_ERR "cpm_uart: console index %d too high\n",
+ co->index);
+ return -ENODEV;
+ }
+
+ do {
+ np = of_find_node_by_type(np, "serial");
+ if (!np)
+ return -ENODEV;
+
+ if (!of_device_is_compatible(np, "fsl,cpm1-smc-uart") &&
+ !of_device_is_compatible(np, "fsl,cpm1-scc-uart") &&
+ !of_device_is_compatible(np, "fsl,cpm2-smc-uart") &&
+ !of_device_is_compatible(np, "fsl,cpm2-scc-uart"))
+ i--;
+ } while (i++ != co->index);
+
+ pinfo = &cpm_uart_ports[co->index];
+
+ pinfo->flags |= FLAG_CONSOLE;
+ port = &pinfo->port;
+
+ ret = cpm_uart_init_port(np, pinfo);
+ of_node_put(np);
+ if (ret)
+ return ret;
+
+#else
struct fs_uart_platform_info *pdata;
struct platform_device* pdev = early_uart_get_pdev(co->index);
@@ -1188,6 +1312,7 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
}
pinfo->flags |= FLAG_CONSOLE;
+#endif
if (options) {
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -1196,12 +1321,18 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
baud = 9600;
}
+#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
+ udbg_putc = NULL;
+#endif
+
+ cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
+
if (IS_SMC(pinfo)) {
- pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
- pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+ clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
+ clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
} else {
- pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
- pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+ clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
+ clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}
ret = cpm_uart_allocbuf(pinfo, 1);
@@ -1217,6 +1348,7 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
cpm_uart_init_scc(pinfo);
uart_set_options(port, co, baud, parity, bits, flow);
+ cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
return 0;
}
@@ -1232,7 +1364,7 @@ static struct console cpm_scc_uart_console = {
.data = &cpm_reg,
};
-int __init cpm_uart_console_init(void)
+static int __init cpm_uart_console_init(void)
{
register_console(&cpm_scc_uart_console);
return 0;
@@ -1252,7 +1384,81 @@ static struct uart_driver cpm_reg = {
.major = SERIAL_CPM_MAJOR,
.minor = SERIAL_CPM_MINOR,
.cons = CPM_UART_CONSOLE,
+ .nr = UART_NR,
};
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static int probe_index;
+
+static int __devinit cpm_uart_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ int index = probe_index++;
+ struct uart_cpm_port *pinfo = &cpm_uart_ports[index];
+ int ret;
+
+ pinfo->port.line = index;
+
+ if (index >= UART_NR)
+ return -ENODEV;
+
+ dev_set_drvdata(&ofdev->dev, pinfo);
+
+ ret = cpm_uart_init_port(ofdev->node, pinfo);
+ if (ret)
+ return ret;
+
+ return uart_add_one_port(&cpm_reg, &pinfo->port);
+}
+
+static int __devexit cpm_uart_remove(struct of_device *ofdev)
+{
+ struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev);
+ return uart_remove_one_port(&cpm_reg, &pinfo->port);
+}
+
+static struct of_device_id cpm_uart_match[] = {
+ {
+ .compatible = "fsl,cpm1-smc-uart",
+ },
+ {
+ .compatible = "fsl,cpm1-scc-uart",
+ },
+ {
+ .compatible = "fsl,cpm2-smc-uart",
+ },
+ {
+ .compatible = "fsl,cpm2-scc-uart",
+ },
+ {}
+};
+
+static struct of_platform_driver cpm_uart_driver = {
+ .name = "cpm_uart",
+ .match_table = cpm_uart_match,
+ .probe = cpm_uart_probe,
+ .remove = cpm_uart_remove,
+ };
+
+static int __init cpm_uart_init(void)
+{
+ int ret = uart_register_driver(&cpm_reg);
+ if (ret)
+ return ret;
+
+ ret = of_register_platform_driver(&cpm_uart_driver);
+ if (ret)
+ uart_unregister_driver(&cpm_reg);
+
+ return ret;
+}
+
+static void __exit cpm_uart_exit(void)
+{
+ of_unregister_platform_driver(&cpm_uart_driver);
+ uart_unregister_driver(&cpm_reg);
+}
+#else
static int cpm_uart_drv_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -1380,6 +1586,7 @@ static void __exit cpm_uart_exit(void)
driver_unregister(&cpm_smc_uart_driver);
uart_unregister_driver(&cpm_reg);
}
+#endif
module_init(cpm_uart_init);
module_exit(cpm_uart_exit);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 8c6324ed020..52fb044bb79 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -49,9 +49,20 @@
/**************************************************************/
-void cpm_line_cr_cmd(int line, int cmd)
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
+{
+ u16 __iomem *cpcr = &cpmp->cp_cpcr;
+
+ out_be16(cpcr, port->command | (cmd << 8) | CPM_CR_FLG);
+ while (in_be16(cpcr) & CPM_CR_FLG)
+ ;
+}
+#else
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
{
ushort val;
+ int line = port - cpm_uart_ports;
volatile cpm8xx_t *cp = cpmp;
switch (line) {
@@ -114,6 +125,7 @@ void scc4_lineif(struct uart_cpm_port *pinfo)
/* XXX SCC4: insert port configuration here */
pinfo->brg = 4;
}
+#endif
/*
* Allocate DP-Ram and memory buffers. We need to allocate a transmit and
@@ -167,7 +179,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
* pinfo->rx_fifosize);
- pinfo->rx_bd_base = (volatile cbd_t *)dp_mem;
+ pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem;
pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
return 0;
@@ -184,6 +196,7 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
cpm_dpfree(pinfo->dp_addr);
}
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
/* Setup any dynamic params in the uart desc */
int cpm_uart_init_portdesc(void)
{
@@ -279,3 +292,4 @@ int cpm_uart_init_portdesc(void)
#endif
return 0;
}
+#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
index 2a6477834c3..9b5465fb0bb 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
@@ -13,30 +13,32 @@
#include <asm/commproc.h>
/* defines for IRQs */
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
#define SMC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC1)
#define SMC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SMC2)
#define SCC1_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC1)
#define SCC2_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC2)
#define SCC3_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC3)
#define SCC4_IRQ (CPM_IRQ_OFFSET + CPMVEC_SCC4)
+#endif
static inline void cpm_set_brg(int brg, int baud)
{
cpm_setbrg(brg, baud);
}
-static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup)
+static inline void cpm_set_scc_fcr(scc_uart_t __iomem * sup)
{
- sup->scc_genscc.scc_rfcr = SMC_EB;
- sup->scc_genscc.scc_tfcr = SMC_EB;
+ out_8(&sup->scc_genscc.scc_rfcr, SMC_EB);
+ out_8(&sup->scc_genscc.scc_tfcr, SMC_EB);
}
-static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
+static inline void cpm_set_smc_fcr(smc_uart_t __iomem * up)
{
- up->smc_rfcr = SMC_EB;
- up->smc_tfcr = SMC_EB;
+ out_8(&up->smc_rfcr, SMC_EB);
+ out_8(&up->smc_tfcr, SMC_EB);
}
-#define DPRAM_BASE ((unsigned char *)cpm_dpram_addr(0))
+#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0))
#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index 7b61d805ebe..882dbc17d59 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -49,9 +49,22 @@
/**************************************************************/
-void cpm_line_cr_cmd(int line, int cmd)
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
+{
+ cpm_cpm2_t __iomem *cp = cpm2_map(im_cpm);
+
+ out_be32(&cp->cp_cpcr, port->command | cmd | CPM_CR_FLG);
+ while (in_be32(&cp->cp_cpcr) & CPM_CR_FLG)
+ ;
+
+ cpm2_unmap(cp);
+}
+#else
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
{
ulong val;
+ int line = port - cpm_uart_ports;
volatile cpm_cpm2_t *cp = cpm2_map(im_cpm);
@@ -211,6 +224,7 @@ void scc4_lineif(struct uart_cpm_port *pinfo)
cpm2_unmap(cpmux);
cpm2_unmap(io);
}
+#endif
/*
* Allocate DP-Ram and memory buffers. We need to allocate a transmit and
@@ -221,7 +235,7 @@ void scc4_lineif(struct uart_cpm_port *pinfo)
int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
{
int dpmemsz, memsz;
- u8 *dp_mem;
+ u8 __iomem *dp_mem;
unsigned long dp_offset;
u8 *mem_addr;
dma_addr_t dma_addr = 0;
@@ -264,7 +278,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
* pinfo->rx_fifosize);
- pinfo->rx_bd_base = (volatile cbd_t *)dp_mem;
+ pinfo->rx_bd_base = (cbd_t __iomem *)dp_mem;
pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
return 0;
@@ -275,12 +289,13 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos *
- pinfo->tx_fifosize), pinfo->mem_addr,
+ pinfo->tx_fifosize), (void __force *)pinfo->mem_addr,
pinfo->dma_addr);
cpm_dpfree(pinfo->dp_addr);
}
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
/* Setup any dynamic params in the uart desc */
int cpm_uart_init_portdesc(void)
{
@@ -386,3 +401,4 @@ int cpm_uart_init_portdesc(void)
return 0;
}
+#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
index 1b3219f56c8..40006a7dce4 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
@@ -13,30 +13,32 @@
#include <asm/cpm2.h>
/* defines for IRQs */
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
#define SMC1_IRQ SIU_INT_SMC1
#define SMC2_IRQ SIU_INT_SMC2
#define SCC1_IRQ SIU_INT_SCC1
#define SCC2_IRQ SIU_INT_SCC2
#define SCC3_IRQ SIU_INT_SCC3
#define SCC4_IRQ SIU_INT_SCC4
+#endif
static inline void cpm_set_brg(int brg, int baud)
{
cpm_setbrg(brg, baud);
}
-static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup)
+static inline void cpm_set_scc_fcr(scc_uart_t __iomem *sup)
{
- sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB;
- sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB;
+ out_8(&sup->scc_genscc.scc_rfcr, CPMFCR_GBL | CPMFCR_EB);
+ out_8(&sup->scc_genscc.scc_tfcr, CPMFCR_GBL | CPMFCR_EB);
}
-static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
+static inline void cpm_set_smc_fcr(smc_uart_t __iomem *up)
{
- up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB;
- up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB;
+ out_8(&up->smc_rfcr, CPMFCR_GBL | CPMFCR_EB);
+ out_8(&up->smc_tfcr, CPMFCR_GBL | CPMFCR_EB);
}
-#define DPRAM_BASE ((unsigned char *)cpm_dpram_addr(0))
+#define DPRAM_BASE ((u8 __iomem __force *)cpm_dpram_addr(0))
#endif
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index 312bef6bd58..a4e23cf4790 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -1,426 +1,10 @@
-/* $Id: serial.c,v 1.25 2004/09/29 10:33:49 starvik Exp $
- *
+/*
* Serial port driver for the ETRAX 100LX chip
*
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Axis Communications AB
+ * Copyright (C) 1998-2007 Axis Communications AB
*
* Many, many authors. Based once upon a time on serial.c for 16x50.
*
- * $Log: serial.c,v $
- * Revision 1.25 2004/09/29 10:33:49 starvik
- * Resolved a dealock when printing debug from kernel.
- *
- * Revision 1.24 2004/08/27 23:25:59 johana
- * rs_set_termios() must call change_speed() if c_iflag has changed or
- * automatic XOFF handling will be enabled and transmitter will stop
- * if 0x13 is received.
- *
- * Revision 1.23 2004/08/24 06:57:13 starvik
- * More whitespace cleanup
- *
- * Revision 1.22 2004/08/24 06:12:20 starvik
- * Whitespace cleanup
- *
- * Revision 1.20 2004/05/24 12:00:20 starvik
- * Big merge of stuff from Linux 2.4 (e.g. manual mode for the serial port).
- *
- * Revision 1.19 2004/05/17 13:12:15 starvik
- * Kernel console hook
- * Big merge from Linux 2.4 still pending.
- *
- * Revision 1.18 2003/10/28 07:18:30 starvik
- * Compiles with debug info
- *
- * Revision 1.17 2003/07/04 08:27:37 starvik
- * Merge of Linux 2.5.74
- *
- * Revision 1.16 2003/06/13 10:05:19 johana
- * Help the user to avoid trouble by:
- * Forcing mixed mode for status/control lines if not all pins are used.
- *
- * Revision 1.15 2003/06/13 09:43:01 johana
- * Merged in the following changes from os/linux/arch/cris/drivers/serial.c
- * + some minor changes to reduce diff.
- *
- * Revision 1.49 2003/05/30 11:31:54 johana
- * Merged in change-branch--serial9bit that adds CMSPAR support for sticky
- * parity (mark/space)
- *
- * Revision 1.48 2003/05/30 11:03:57 johana
- * Implemented rs_send_xchar() by disabling the DMA and writing manually.
- * Added e100_disable_txdma_channel() and e100_enable_txdma_channel().
- * Fixed rs_throttle() and rs_unthrottle() to properly call rs_send_xchar
- * instead of setting info->x_char and check the CRTSCTS flag before
- * controlling the rts pin.
- *
- * Revision 1.14 2003/04/09 08:12:44 pkj
- * Corrected typo changes made upstream.
- *
- * Revision 1.13 2003/04/09 05:20:47 starvik
- * Merge of Linux 2.5.67
- *
- * Revision 1.11 2003/01/22 06:48:37 starvik
- * Fixed warnings issued by GCC 3.2.1
- *
- * Revision 1.9 2002/12/13 09:07:47 starvik
- * Alert user that RX_TIMEOUT_TICKS==0 doesn't work
- *
- * Revision 1.8 2002/12/11 13:13:57 starvik
- * Added arch/ to v10 specific includes
- * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
- *
- * Revision 1.7 2002/12/06 07:13:57 starvik
- * Corrected work queue stuff
- * Removed CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
- *
- * Revision 1.6 2002/11/21 07:17:46 starvik
- * Change static inline to extern inline where otherwise outlined with gcc-3.2
- *
- * Revision 1.5 2002/11/14 15:59:49 starvik
- * Linux 2.5 port of the latest serial driver from 2.4. The work queue stuff
- * probably doesn't work yet.
- *
- * Revision 1.42 2002/11/05 09:08:47 johana
- * Better implementation of rs_stop() and rs_start() that uses the XOFF
- * register to start/stop transmission.
- * change_speed() also initilises XOFF register correctly so that
- * auto_xoff is enabled when IXON flag is set by user.
- * This gives fast XOFF response times.
- *
- * Revision 1.41 2002/11/04 18:40:57 johana
- * Implemented rs_stop() and rs_start().
- * Simple tests using hwtestserial indicates that this should be enough
- * to make it work.
- *
- * Revision 1.40 2002/10/14 05:33:18 starvik
- * RS-485 uses fast timers even if SERIAL_FAST_TIMER is disabled
- *
- * Revision 1.39 2002/09/30 21:00:57 johana
- * Support for CONFIG_ETRAX_SERx_DTR_RI_DSR_CD_MIXED where the status and
- * control pins can be mixed between PA and PB.
- * If no serial port uses MIXED old solution is used
- * (saves a few bytes and cycles).
- * control_pins struct uses masks instead of bit numbers.
- * Corrected dummy values and polarity in line_info() so
- * /proc/tty/driver/serial is now correct.
- * (the E100_xxx_GET() macros is really active low - perhaps not obvious)
- *
- * Revision 1.38 2002/08/23 11:01:36 starvik
- * Check that serial port is enabled in all interrupt handlers to avoid
- * restarts of DMA channels not assigned to serial ports
- *
- * Revision 1.37 2002/08/13 13:02:37 bjornw
- * Removed some warnings because of unused code
- *
- * Revision 1.36 2002/08/08 12:50:01 starvik
- * Serial interrupt is shared with synchronous serial port driver
- *
- * Revision 1.35 2002/06/03 10:40:49 starvik
- * Increased RS-485 RTS toggle timer to 2 characters
- *
- * Revision 1.34 2002/05/28 18:59:36 johana
- * Whitespace and comment fixing to be more like etrax100ser.c 1.71.
- *
- * Revision 1.33 2002/05/28 17:55:43 johana
- * RS-485 uses FAST_TIMER if enabled, and starts a short (one char time)
- * timer from tranismit_chars (interrupt context).
- * The timer toggles RTS in interrupt context when expired giving minimum
- * latencies.
- *
- * Revision 1.32 2002/05/22 13:58:00 johana
- * Renamed rs_write() to raw_write() and made it inline.
- * New rs_write() handles RS-485 if configured and enabled
- * (moved code from e100_write_rs485()).
- * RS-485 ioctl's uses copy_from_user() instead of verify_area().
- *
- * Revision 1.31 2002/04/22 11:20:03 johana
- * Updated copyright years.
- *
- * Revision 1.30 2002/04/22 09:39:12 johana
- * RS-485 support compiles.
- *
- * Revision 1.29 2002/01/14 16:10:01 pkj
- * Allocate the receive buffers dynamically. The static 4kB buffer was
- * too small for the peaks. This means that we can get rid of the extra
- * buffer and the copying to it. It also means we require less memory
- * under normal operations, but can use more when needed (there is a
- * cap at 64kB for safety reasons). If there is no memory available
- * we panic(), and die a horrible death...
- *
- * Revision 1.28 2001/12/18 15:04:53 johana
- * Cleaned up write_rs485() - now it works correctly without padding extra
- * char.
- * Added sane default initialisation of rs485.
- * Added #ifdef around dummy variables.
- *
- * Revision 1.27 2001/11/29 17:00:41 pkj
- * 2kB seems to be too small a buffer when using 921600 bps,
- * so increase it to 4kB (this was already done for the elinux
- * version of the serial driver).
- *
- * Revision 1.26 2001/11/19 14:20:41 pkj
- * Minor changes to comments and unused code.
- *
- * Revision 1.25 2001/11/12 20:03:43 pkj
- * Fixed compiler warnings.
- *
- * Revision 1.24 2001/11/12 15:10:05 pkj
- * Total redesign of the receiving part of the serial driver.
- * Uses eight chained descriptors to write to a 4kB buffer.
- * This data is then serialised into a 2kB buffer. From there it
- * is copied into the TTY's flip buffers when they become available.
- * A lot of copying, and the sizes of the buffers might need to be
- * tweaked, but all in all it should work better than the previous
- * version, without the need to modify the TTY code in any way.
- * Also note that erroneous bytes are now correctly marked in the
- * flag buffers (instead of always marking the first byte).
- *
- * Revision 1.23 2001/10/30 17:53:26 pkj
- * * Set info->uses_dma to 0 when a port is closed.
- * * Mark the timer1 interrupt as a fast one (SA_INTERRUPT).
- * * Call start_flush_timer() in start_receive() if
- * CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is defined.
- *
- * Revision 1.22 2001/10/30 17:44:03 pkj
- * Use %lu for received and transmitted counters in line_info().
- *
- * Revision 1.21 2001/10/30 17:40:34 pkj
- * Clean-up. The only change to functionality is that
- * CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS(=5) is used instead of
- * MAX_FLUSH_TIME(=8).
- *
- * Revision 1.20 2001/10/30 15:24:49 johana
- * Added char_time stuff from 2.0 driver.
- *
- * Revision 1.19 2001/10/30 15:23:03 johana
- * Merged with 1.13.2 branch + fixed indentation
- * and changed CONFIG_ETRAX100_XYS to CONFIG_ETRAX_XYZ
- *
- * Revision 1.18 2001/09/24 09:27:22 pkj
- * Completed ext_baud_table[] in cflag_to_baud() and cflag_to_etrax_baud().
- *
- * Revision 1.17 2001/08/24 11:32:49 ronny
- * More fixes for the CONFIG_ETRAX_SERIAL_PORT0 define.
- *
- * Revision 1.16 2001/08/24 07:56:22 ronny
- * Added config ifdefs around ser0 irq requests.
- *
- * Revision 1.15 2001/08/16 09:10:31 bjarne
- * serial.c - corrected the initialization of rs_table, the wrong defines
- * where used.
- * Corrected a test in timed_flush_handler.
- * Changed configured to enabled.
- * serial.h - Changed configured to enabled.
- *
- * Revision 1.14 2001/08/15 07:31:23 bjarne
- * Introduced two new members to the e100_serial struct.
- * configured - Will be set to 1 if the port has been configured in .config
- * uses_dma - Should be set to 1 if the port uses DMA. Currently it is set
- * to 1
- * when a port is opened. This is used to limit the DMA interrupt
- * routines to only manipulate DMA channels actually used by the
- * serial driver.
- *
- * Revision 1.13.2.2 2001/10/17 13:57:13 starvik
- * Receiver was broken by the break fixes
- *
- * Revision 1.13.2.1 2001/07/20 13:57:39 ronny
- * Merge with new stuff from etrax100ser.c. Works but haven't checked stuff
- * like break handling.
- *
- * Revision 1.13 2001/05/09 12:40:31 johana
- * Use DMA_NBR and IRQ_NBR defines from dma.h and irq.h
- *
- * Revision 1.12 2001/04/19 12:23:07 bjornw
- * CONFIG_RS485 -> CONFIG_ETRAX_RS485
- *
- * Revision 1.11 2001/04/05 14:29:48 markusl
- * Updated according to review remarks i.e.
- * -Use correct types in port structure to avoid compiler warnings
- * -Try to use IO_* macros whenever possible
- * -Open should never return -EBUSY
- *
- * Revision 1.10 2001/03/05 13:14:07 bjornw
- * Another spelling fix
- *
- * Revision 1.9 2001/02/23 13:46:38 bjornw
- * Spellling check
- *
- * Revision 1.8 2001/01/23 14:56:35 markusl
- * Made use of ser1 optional
- * Needed by USB
- *
- * Revision 1.7 2001/01/19 16:14:48 perf
- * Added kernel options for serial ports 234.
- * Changed option names from CONFIG_ETRAX100_XYZ to CONFIG_ETRAX_XYZ.
- *
- * Revision 1.6 2000/11/22 16:36:09 bjornw
- * Please marketing by using the correct case when spelling Etrax.
- *
- * Revision 1.5 2000/11/21 16:43:37 bjornw
- * Fixed so it compiles under CONFIG_SVINTO_SIM
- *
- * Revision 1.4 2000/11/15 17:34:12 bjornw
- * Added a timeout timer for flushing input channels. The interrupt-based
- * fast flush system should be easy to merge with this later (works the same
- * way, only with an irq instead of a system timer_list)
- *
- * Revision 1.3 2000/11/13 17:19:57 bjornw
- * * Incredibly, this almost complete rewrite of serial.c worked (at least
- * for output) the first time.
- *
- * Items worth noticing:
- *
- * No Etrax100 port 1 workarounds (does only compile on 2.4 anyway now)
- * RS485 is not ported (why can't it be done in userspace as on x86 ?)
- * Statistics done through async_icount - if any more stats are needed,
- * that's the place to put them or in an arch-dep version of it.
- * timeout_interrupt and the other fast timeout stuff not ported yet
- * There be dragons in this 3k+ line driver
- *
- * Revision 1.2 2000/11/10 16:50:28 bjornw
- * First shot at a 2.4 port, does not compile totally yet
- *
- * Revision 1.1 2000/11/10 16:47:32 bjornw
- * Added verbatim copy of rev 1.49 etrax100ser.c from elinux
- *
- * Revision 1.49 2000/10/30 15:47:14 tobiasa
- * Changed version number.
- *
- * Revision 1.48 2000/10/25 11:02:43 johana
- * Changed %ul to %lu in printf's
- *
- * Revision 1.47 2000/10/18 15:06:53 pkj
- * Compile correctly with CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST and
- * CONFIG_ETRAX_SERIAL_PROC_ENTRY together.
- * Some clean-up of the /proc/serial file.
- *
- * Revision 1.46 2000/10/16 12:59:40 johana
- * Added CONFIG_ETRAX_SERIAL_PROC_ENTRY for statistics and debug info.
- *
- * Revision 1.45 2000/10/13 17:10:59 pkj
- * Do not flush DMAs while flipping TTY buffers.
- *
- * Revision 1.44 2000/10/13 16:34:29 pkj
- * Added a delay in ser_interrupt() for 2.3ms when an error is detected.
- * We do not know why this delay is required yet, but without it the
- * irmaflash program does not work (this was the program that needed
- * the ser_interrupt() to be needed in the first place). This should not
- * affect normal use of the serial ports.
- *
- * Revision 1.43 2000/10/13 16:30:44 pkj
- * New version of the fast flush of serial buffers code. This time
- * it is localized to the serial driver and uses a fast timer to
- * do the work.
- *
- * Revision 1.42 2000/10/13 14:54:26 bennyo
- * Fix for switching RTS when using rs485
- *
- * Revision 1.41 2000/10/12 11:43:44 pkj
- * Cleaned up a number of comments.
- *
- * Revision 1.40 2000/10/10 11:58:39 johana
- * Made RS485 support generic for all ports.
- * Toggle rts in interrupt if no delay wanted.
- * WARNING: No true transmitter empty check??
- * Set d_wait bit when sending data so interrupt is delayed until
- * fifo flushed. (Fix tcdrain() problem)
- *
- * Revision 1.39 2000/10/04 16:08:02 bjornw
- * * Use virt_to_phys etc. for DMA addresses
- * * Removed CONFIG_FLUSH_DMA_FAST hacks
- * * Indentation fix
- *
- * Revision 1.38 2000/10/02 12:27:10 mattias
- * * added variable used when using fast flush on serial dma.
- * (CONFIG_FLUSH_DMA_FAST)
- *
- * Revision 1.37 2000/09/27 09:44:24 pkj
- * Uncomment definition of SERIAL_HANDLE_EARLY_ERRORS.
- *
- * Revision 1.36 2000/09/20 13:12:52 johana
- * Support for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS:
- * Number of timer ticks between flush of receive fifo (1 tick = 10ms).
- * Try 0-3 for low latency applications. Approx 5 for high load
- * applications (e.g. PPP). Maybe this should be more adaptive some day...
- *
- * Revision 1.35 2000/09/20 10:36:08 johana
- * Typo in get_lsr_info()
- *
- * Revision 1.34 2000/09/20 10:29:59 johana
- * Let rs_chars_in_buffer() check fifo content as well.
- * get_lsr_info() might work now (not tested).
- * Easier to change the port to debug.
- *
- * Revision 1.33 2000/09/13 07:52:11 torbjore
- * Support RS485
- *
- * Revision 1.32 2000/08/31 14:45:37 bjornw
- * After sending a break we need to reset the transmit DMA channel
- *
- * Revision 1.31 2000/06/21 12:13:29 johana
- * Fixed wait for all chars sent when closing port.
- * (Used to always take 1 second!)
- * Added shadows for directions of status/ctrl signals.
- *
- * Revision 1.30 2000/05/29 16:27:55 bjornw
- * Simulator ifdef moved a bit
- *
- * Revision 1.29 2000/05/09 09:40:30 mattias
- * * Added description of dma registers used in timeout_interrupt
- * * Removed old code
- *
- * Revision 1.28 2000/05/08 16:38:58 mattias
- * * Bugfix for flushing fifo in timeout_interrupt
- * Problem occurs when bluetooth stack waits for a small number of bytes
- * containing an event acknowledging free buffers in bluetooth HW
- * As before, data was stuck in fifo until more data came on uart and
- * flushed it up to the stack.
- *
- * Revision 1.27 2000/05/02 09:52:28 jonasd
- * Added fix for peculiar etrax behaviour when eop is forced on an empty
- * fifo. This is used when flashing the IRMA chip. Disabled by default.
- *
- * Revision 1.26 2000/03/29 15:32:02 bjornw
- * 2.0.34 updates
- *
- * Revision 1.25 2000/02/16 16:59:36 bjornw
- * * Receive DMA directly into the flip-buffer, eliminating an intermediary
- * receive buffer and a memcpy. Will avoid some overruns.
- * * Error message on debug port if an overrun or flip buffer overrun occurs.
- * * Just use the first byte in the flag flip buffer for errors.
- * * Check for timeout on the serial ports only each 5/100 s, not 1/100.
- *
- * Revision 1.24 2000/02/09 18:02:28 bjornw
- * * Clear serial errors (overrun, framing, parity) correctly. Before, the
- * receiver would get stuck if an error occurred and we did not restart
- * the input DMA.
- * * Cosmetics (indentation, some code made into inlines)
- * * Some more debug options
- * * Actually shut down the serial port (DMA irq, DMA reset, receiver stop)
- * when the last open is closed. Corresponding fixes in startup().
- * * rs_close() "tx FIFO wait" code moved into right place, bug & -> && fixed
- * and make a special case out of port 1 (R_DMA_CHx_STATUS is broken for that)
- * * e100_disable_rx/enable_rx just disables/enables the receiver, not RTS
- *
- * Revision 1.23 2000/01/24 17:46:19 johana
- * Wait for flush of DMA/FIFO when closing port.
- *
- * Revision 1.22 2000/01/20 18:10:23 johana
- * Added TIOCMGET ioctl to return modem status.
- * Implemented modem status/control that works with the extra signals
- * (DTR, DSR, RI,CD) as well.
- * 3 different modes supported:
- * ser0 on PB (Bundy), ser1 on PB (Lisa) and ser2 on PA (Bundy)
- * Fixed DEF_TX value that caused the serial transmitter pin (txd) to go to 0 when
- * closing the last filehandle, NASTY!.
- * Added break generation, not tested though!
- * Use IRQF_SHARED when request_irq() for ser2 and ser3 (shared with) par0 and par1.
- * You can't use them at the same time (yet..), but you can hopefully switch
- * between ser2/par0, ser3/par1 with the same kernel config.
- * Replaced some magic constants with defines
- *
- *
*/
static char *serial_version = "$Revision: 1.25 $";
@@ -442,11 +26,12 @@ static char *serial_version = "$Revision: 1.25 $";
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
+#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/dma.h>
#include <asm/system.h>
-#include <asm/bitops.h>
#include <linux/delay.h>
#include <asm/arch/svinto.h>
@@ -454,8 +39,9 @@ static char *serial_version = "$Revision: 1.25 $";
/* non-arch dependent serial structures are in linux/serial.h */
#include <linux/serial.h>
/* while we keep our own stuff (struct e100_serial) in a local .h file */
-#include "serial.h"
+#include "crisv10.h"
#include <asm/fasttimer.h>
+#include <asm/arch/io_interface_mux.h>
#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
#ifndef CONFIG_ETRAX_FAST_TIMER
@@ -504,16 +90,6 @@ struct tty_driver *serial_driver;
from eLinux */
#define SERIAL_HANDLE_EARLY_ERRORS
-/* Defined and used in n_tty.c, but we need it here as well */
-#define TTY_THRESHOLD_THROTTLE 128
-
-/* Due to buffersizes and threshold values, our SERIAL_DESCR_BUF_SIZE
- * must not be to high or flow control won't work if we leave it to the tty
- * layer so we have our own throttling in flush_to_flip
- * TTY_FLIPBUF_SIZE=512,
- * TTY_THRESHOLD_THROTTLE/UNTHROTTLE=128
- * BUF_SIZE can't be > 128
- */
/* Currently 16 descriptors x 128 bytes = 2048 bytes */
#define SERIAL_DESCR_BUF_SIZE 256
@@ -586,13 +162,13 @@ unsigned long timer_data_to_ns(unsigned long timer_data);
static void change_speed(struct e100_serial *info);
static void rs_throttle(struct tty_struct * tty);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-static int rs_write(struct tty_struct * tty, int from_user,
- const unsigned char *buf, int count);
+static int rs_write(struct tty_struct *tty,
+ const unsigned char *buf, int count);
#ifdef CONFIG_ETRAX_RS485
-static int e100_write_rs485(struct tty_struct * tty, int from_user,
- const unsigned char *buf, int count);
+static int e100_write_rs485(struct tty_struct *tty,
+ const unsigned char *buf, int count);
#endif
-static int get_lsr_info(struct e100_serial * info, unsigned int *value);
+static int get_lsr_info(struct e100_serial *info, unsigned int *value);
#define DEF_BAUD 115200 /* 115.2 kbit/s */
@@ -677,20 +253,39 @@ static struct e100_serial rs_table[] = {
.rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX,
.iseteop = 2,
+ .dma_owner = dma_ser0,
+ .io_if = if_serial_0,
#ifdef CONFIG_ETRAX_SERIAL_PORT0
.enabled = 1,
#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
.dma_out_enabled = 1,
+ .dma_out_nbr = SER0_TX_DMA_NBR,
+ .dma_out_irq_nbr = SER0_DMA_TX_IRQ_NBR,
+ .dma_out_irq_flags = IRQF_DISABLED,
+ .dma_out_irq_description = "serial 0 dma tr",
#else
.dma_out_enabled = 0,
+ .dma_out_nbr = UINT_MAX,
+ .dma_out_irq_nbr = 0,
+ .dma_out_irq_flags = 0,
+ .dma_out_irq_description = NULL,
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
.dma_in_enabled = 1,
+ .dma_in_nbr = SER0_RX_DMA_NBR,
+ .dma_in_irq_nbr = SER0_DMA_RX_IRQ_NBR,
+ .dma_in_irq_flags = IRQF_DISABLED,
+ .dma_in_irq_description = "serial 0 dma rec",
#else
- .dma_in_enabled = 0
+ .dma_in_enabled = 0,
+ .dma_in_nbr = UINT_MAX,
+ .dma_in_irq_nbr = 0,
+ .dma_in_irq_flags = 0,
+ .dma_in_irq_description = NULL,
#endif
#else
.enabled = 0,
+ .io_if_description = NULL,
.dma_out_enabled = 0,
.dma_in_enabled = 0
#endif
@@ -712,20 +307,42 @@ static struct e100_serial rs_table[] = {
.rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX,
.iseteop = 3,
+ .dma_owner = dma_ser1,
+ .io_if = if_serial_1,
#ifdef CONFIG_ETRAX_SERIAL_PORT1
.enabled = 1,
+ .io_if_description = "ser1",
#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
.dma_out_enabled = 1,
+ .dma_out_nbr = SER1_TX_DMA_NBR,
+ .dma_out_irq_nbr = SER1_DMA_TX_IRQ_NBR,
+ .dma_out_irq_flags = IRQF_DISABLED,
+ .dma_out_irq_description = "serial 1 dma tr",
#else
.dma_out_enabled = 0,
+ .dma_out_nbr = UINT_MAX,
+ .dma_out_irq_nbr = 0,
+ .dma_out_irq_flags = 0,
+ .dma_out_irq_description = NULL,
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
.dma_in_enabled = 1,
+ .dma_in_nbr = SER1_RX_DMA_NBR,
+ .dma_in_irq_nbr = SER1_DMA_RX_IRQ_NBR,
+ .dma_in_irq_flags = IRQF_DISABLED,
+ .dma_in_irq_description = "serial 1 dma rec",
#else
- .dma_in_enabled = 0
+ .dma_in_enabled = 0,
+ .dma_in_enabled = 0,
+ .dma_in_nbr = UINT_MAX,
+ .dma_in_irq_nbr = 0,
+ .dma_in_irq_flags = 0,
+ .dma_in_irq_description = NULL,
#endif
#else
.enabled = 0,
+ .io_if_description = NULL,
+ .dma_in_irq_nbr = 0,
.dma_out_enabled = 0,
.dma_in_enabled = 0
#endif
@@ -746,20 +363,40 @@ static struct e100_serial rs_table[] = {
.rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX,
.iseteop = 0,
+ .dma_owner = dma_ser2,
+ .io_if = if_serial_2,
#ifdef CONFIG_ETRAX_SERIAL_PORT2
.enabled = 1,
+ .io_if_description = "ser2",
#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
.dma_out_enabled = 1,
+ .dma_out_nbr = SER2_TX_DMA_NBR,
+ .dma_out_irq_nbr = SER2_DMA_TX_IRQ_NBR,
+ .dma_out_irq_flags = IRQF_DISABLED,
+ .dma_out_irq_description = "serial 2 dma tr",
#else
.dma_out_enabled = 0,
+ .dma_out_nbr = UINT_MAX,
+ .dma_out_irq_nbr = 0,
+ .dma_out_irq_flags = 0,
+ .dma_out_irq_description = NULL,
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
.dma_in_enabled = 1,
+ .dma_in_nbr = SER2_RX_DMA_NBR,
+ .dma_in_irq_nbr = SER2_DMA_RX_IRQ_NBR,
+ .dma_in_irq_flags = IRQF_DISABLED,
+ .dma_in_irq_description = "serial 2 dma rec",
#else
- .dma_in_enabled = 0
+ .dma_in_enabled = 0,
+ .dma_in_nbr = UINT_MAX,
+ .dma_in_irq_nbr = 0,
+ .dma_in_irq_flags = 0,
+ .dma_in_irq_description = NULL,
#endif
#else
.enabled = 0,
+ .io_if_description = NULL,
.dma_out_enabled = 0,
.dma_in_enabled = 0
#endif
@@ -780,20 +417,40 @@ static struct e100_serial rs_table[] = {
.rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX,
.iseteop = 1,
+ .dma_owner = dma_ser3,
+ .io_if = if_serial_3,
#ifdef CONFIG_ETRAX_SERIAL_PORT3
.enabled = 1,
+ .io_if_description = "ser3",
#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
.dma_out_enabled = 1,
+ .dma_out_nbr = SER3_TX_DMA_NBR,
+ .dma_out_irq_nbr = SER3_DMA_TX_IRQ_NBR,
+ .dma_out_irq_flags = IRQF_DISABLED,
+ .dma_out_irq_description = "serial 3 dma tr",
#else
.dma_out_enabled = 0,
+ .dma_out_nbr = UINT_MAX,
+ .dma_out_irq_nbr = 0,
+ .dma_out_irq_flags = 0,
+ .dma_out_irq_description = NULL,
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
.dma_in_enabled = 1,
+ .dma_in_nbr = SER3_RX_DMA_NBR,
+ .dma_in_irq_nbr = SER3_DMA_RX_IRQ_NBR,
+ .dma_in_irq_flags = IRQF_DISABLED,
+ .dma_in_irq_description = "serial 3 dma rec",
#else
- .dma_in_enabled = 0
+ .dma_in_enabled = 0,
+ .dma_in_nbr = UINT_MAX,
+ .dma_in_irq_nbr = 0,
+ .dma_in_irq_flags = 0,
+ .dma_in_irq_description = NULL
#endif
#else
.enabled = 0,
+ .io_if_description = NULL,
.dma_out_enabled = 0,
.dma_in_enabled = 0
#endif
@@ -1414,12 +1071,11 @@ e100_dtr(struct e100_serial *info, int set)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
*e100_modem_pins[info->line].dtr_shadow &= ~mask;
*e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask);
*e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow;
- restore_flags(flags);
+ local_irq_restore(flags);
}
#ifdef SERIAL_DEBUG_IO
@@ -1438,12 +1094,11 @@ e100_rts(struct e100_serial *info, int set)
{
#ifndef CONFIG_SVINTO_SIM
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
info->rx_ctrl &= ~E100_RTS_MASK;
info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */
info->port[REG_REC_CTRL] = info->rx_ctrl;
- restore_flags(flags);
+ local_irq_restore(flags);
#ifdef SERIAL_DEBUG_IO
printk("ser%i rts %i\n", info->line, set);
#endif
@@ -1461,12 +1116,11 @@ e100_ri_out(struct e100_serial *info, int set)
unsigned char mask = e100_modem_pins[info->line].ri_mask;
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
*e100_modem_pins[info->line].ri_shadow &= ~mask;
*e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask);
*e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow;
- restore_flags(flags);
+ local_irq_restore(flags);
}
#endif
}
@@ -1479,12 +1133,11 @@ e100_cd_out(struct e100_serial *info, int set)
unsigned char mask = e100_modem_pins[info->line].cd_mask;
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
*e100_modem_pins[info->line].cd_shadow &= ~mask;
*e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask);
*e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow;
- restore_flags(flags);
+ local_irq_restore(flags);
}
#endif
}
@@ -1558,8 +1211,7 @@ static void e100_disable_txdma_channel(struct e100_serial *info)
/* Disable output DMA channel for the serial port in question
* ( set to something other then serialX)
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line));
if (info->line == 0) {
if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) ==
@@ -1587,7 +1239,7 @@ static void e100_disable_txdma_channel(struct e100_serial *info)
}
}
*R_GEN_CONFIG = genconfig_shadow;
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -1595,8 +1247,7 @@ static void e100_enable_txdma_channel(struct e100_serial *info)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line));
/* Enable output DMA channel for the serial port in question */
if (info->line == 0) {
@@ -1613,7 +1264,7 @@ static void e100_enable_txdma_channel(struct e100_serial *info)
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3);
}
*R_GEN_CONFIG = genconfig_shadow;
- restore_flags(flags);
+ local_irq_restore(flags);
}
static void e100_disable_rxdma_channel(struct e100_serial *info)
@@ -1623,8 +1274,7 @@ static void e100_disable_rxdma_channel(struct e100_serial *info)
/* Disable input DMA channel for the serial port in question
* ( set to something other then serialX)
*/
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (info->line == 0) {
if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) ==
IO_STATE(R_GEN_CONFIG, dma7, serial0)) {
@@ -1651,7 +1301,7 @@ static void e100_disable_rxdma_channel(struct e100_serial *info)
}
}
*R_GEN_CONFIG = genconfig_shadow;
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -1659,8 +1309,7 @@ static void e100_enable_rxdma_channel(struct e100_serial *info)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* Enable input DMA channel for the serial port in question */
if (info->line == 0) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma7);
@@ -1676,7 +1325,7 @@ static void e100_enable_rxdma_channel(struct e100_serial *info)
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3);
}
*R_GEN_CONFIG = genconfig_shadow;
- restore_flags(flags);
+ local_irq_restore(flags);
}
#ifdef SERIAL_HANDLE_EARLY_ERRORS
@@ -1783,7 +1432,7 @@ e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r)
}
static int
-e100_write_rs485(struct tty_struct *tty, int from_user,
+e100_write_rs485(struct tty_struct *tty,
const unsigned char *buf, int count)
{
struct e100_serial * info = (struct e100_serial *)tty->driver_data;
@@ -1796,7 +1445,7 @@ e100_write_rs485(struct tty_struct *tty, int from_user,
*/
info->rs485.enabled = 1;
/* rs_write now deals with RS485 if enabled */
- count = rs_write(tty, from_user, buf, count);
+ count = rs_write(tty, buf, count);
info->rs485.enabled = old_enabled;
return count;
}
@@ -1834,7 +1483,7 @@ rs_stop(struct tty_struct *tty)
unsigned long flags;
unsigned long xoff;
- save_flags(flags); cli();
+ local_irq_save(flags);
DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n",
CIRC_CNT(info->xmit.head,
info->xmit.tail,SERIAL_XMIT_SIZE)));
@@ -1846,7 +1495,7 @@ rs_stop(struct tty_struct *tty)
}
*((unsigned long *)&info->port[REG_XOFF]) = xoff;
- restore_flags(flags);
+ local_irq_restore(flags);
}
}
@@ -1858,7 +1507,7 @@ rs_start(struct tty_struct *tty)
unsigned long flags;
unsigned long xoff;
- save_flags(flags); cli();
+ local_irq_save(flags);
DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n",
CIRC_CNT(info->xmit.head,
info->xmit.tail,SERIAL_XMIT_SIZE)));
@@ -1873,7 +1522,7 @@ rs_start(struct tty_struct *tty)
info->xmit.head != info->xmit.tail && info->xmit.buf)
e100_enable_serial_tx_ready_irq(info);
- restore_flags(flags);
+ local_irq_restore(flags);
}
}
@@ -2053,8 +1702,7 @@ static int serial_fast_timer_expired = 0;
static void flush_timeout_function(unsigned long data);
#define START_FLUSH_FAST_TIMER_TIME(info, string, usec) {\
unsigned long timer_flags; \
- save_flags(timer_flags); \
- cli(); \
+ local_irq_save(timer_flags); \
if (fast_timers[info->line].function == NULL) { \
serial_fast_timer_started++; \
TIMERD(DEBUG_LOG(info->line, "start_timer %i ", info->line)); \
@@ -2068,7 +1716,7 @@ static void flush_timeout_function(unsigned long data);
else { \
TIMERD(DEBUG_LOG(info->line, "timer %i already running\n", info->line)); \
} \
- restore_flags(timer_flags); \
+ local_irq_restore(timer_flags); \
}
#define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec)
@@ -2097,8 +1745,7 @@ append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (!info->first_recv_buffer)
info->first_recv_buffer = buffer;
@@ -2111,7 +1758,7 @@ append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer)
if (info->recv_cnt > info->max_recv_cnt)
info->max_recv_cnt = info->recv_cnt;
- restore_flags(flags);
+ local_irq_restore(flags);
}
static int
@@ -2131,11 +1778,7 @@ add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char fl
info->icount.rx++;
} else {
struct tty_struct *tty = info->tty;
- *tty->flip.char_buf_ptr = data;
- *tty->flip.flag_buf_ptr = flag;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
+ tty_insert_flip_char(tty, data, flag);
info->icount.rx++;
}
@@ -2320,7 +1963,6 @@ start_receive(struct e100_serial *info)
*/
return;
#endif
- info->tty->flip.count = 0;
if (info->uses_dma_in) {
/* reset the input dma channel to be sure it works */
@@ -2482,70 +2124,21 @@ static void flush_to_flip_buffer(struct e100_serial *info)
{
struct tty_struct *tty;
struct etrax_recv_buffer *buffer;
- unsigned int length;
unsigned long flags;
- int max_flip_size;
- if (!info->first_recv_buffer)
- return;
-
- save_flags(flags);
- cli();
+ local_irq_save(flags);
+ tty = info->tty;
- if (!(tty = info->tty)) {
- restore_flags(flags);
+ if (!tty) {
+ local_irq_restore(flags);
return;
}
- length = tty->flip.count;
- /* Don't flip more than the ldisc has room for.
- * The return value from ldisc.receive_room(tty) - might not be up to
- * date, the previous flip of up to TTY_FLIPBUF_SIZE might be on the
- * processed and not accounted for yet.
- * Since we use DMA, 1 SERIAL_DESCR_BUF_SIZE could be on the way.
- * Lets buffer data here and let flow control take care of it.
- * Since we normally flip large chunks, the ldisc don't react
- * with throttle until too late if we flip to much.
- */
- max_flip_size = tty->ldisc.receive_room(tty);
- if (max_flip_size < 0)
- max_flip_size = 0;
- if (max_flip_size <= (TTY_FLIPBUF_SIZE + /* Maybe not accounted for */
- length + info->recv_cnt + /* We have this queued */
- 2*SERIAL_DESCR_BUF_SIZE + /* This could be on the way */
- TTY_THRESHOLD_THROTTLE)) { /* Some slack */
- /* check TTY_THROTTLED first so it indicates our state */
- if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) {
- DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles room %lu\n", max_flip_size));
- rs_throttle(tty);
- }
-#if 0
- else if (max_flip_size <= (TTY_FLIPBUF_SIZE + /* Maybe not accounted for */
- length + info->recv_cnt + /* We have this queued */
- SERIAL_DESCR_BUF_SIZE + /* This could be on the way */
- TTY_THRESHOLD_THROTTLE)) { /* Some slack */
- DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles again! %lu\n", max_flip_size));
- rs_throttle(tty);
- }
-#endif
- }
-
- if (max_flip_size > TTY_FLIPBUF_SIZE)
- max_flip_size = TTY_FLIPBUF_SIZE;
-
- while ((buffer = info->first_recv_buffer) && length < max_flip_size) {
+ while ((buffer = info->first_recv_buffer) != NULL) {
unsigned int count = buffer->length;
- if (length + count > max_flip_size)
- count = max_flip_size - length;
-
- memcpy(tty->flip.char_buf_ptr + length, buffer->buffer, count);
- memset(tty->flip.flag_buf_ptr + length, TTY_NORMAL, count);
- tty->flip.flag_buf_ptr[length] = buffer->error;
-
- length += count;
+ tty_insert_flip_string(tty, buffer->buffer, count);
info->recv_cnt -= count;
- DFLIP(DEBUG_LOG(info->line,"flip: %i\n", length));
if (count == buffer->length) {
info->first_recv_buffer = buffer->next;
@@ -2560,26 +2153,9 @@ static void flush_to_flip_buffer(struct e100_serial *info)
if (!info->first_recv_buffer)
info->last_recv_buffer = NULL;
- tty->flip.count = length;
- DFLIP(if (tty->ldisc.chars_in_buffer(tty) > 3500) {
- DEBUG_LOG(info->line, "ldisc %lu\n",
- tty->ldisc.chars_in_buffer(tty));
- DEBUG_LOG(info->line, "flip.count %lu\n",
- tty->flip.count);
- }
- );
- restore_flags(flags);
-
- DFLIP(
- if (1) {
- DEBUG_LOG(info->line, "*** rxtot %i\n", info->icount.rx);
- DEBUG_LOG(info->line, "ldisc %lu\n", tty->ldisc.chars_in_buffer(tty));
- DEBUG_LOG(info->line, "room %lu\n", tty->ldisc.receive_room(tty));
- }
+ local_irq_restore(flags);
- );
-
- /* this includes a check for low-latency */
+ /* This includes a check for low-latency */
tty_flip_buffer_push(tty);
}
@@ -2722,21 +2298,7 @@ struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
printk("!NO TTY!\n");
return info;
}
- if (tty->flip.count >= TTY_FLIPBUF_SIZE - TTY_THRESHOLD_THROTTLE) {
- /* check TTY_THROTTLED first so it indicates our state */
- if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) {
- DFLOW(DEBUG_LOG(info->line, "rs_throttle flip.count: %i\n", tty->flip.count));
- rs_throttle(tty);
- }
- }
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
- DEBUG_LOG(info->line, "force FLIP! %i\n", tty->flip.count);
- tty->flip.work.func((void *) tty);
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
- DEBUG_LOG(info->line, "FLIP FULL! %i\n", tty->flip.count);
- return info; /* if TTY_DONT_FLIP is set */
- }
- }
+
/* Read data and status at the same time */
data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]);
more_data:
@@ -2789,27 +2351,26 @@ more_data:
DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
info->errorcode = ERRCODE_INSERT_BREAK;
} else {
+ unsigned char data = IO_EXTRACT(R_SERIAL0_READ,
+ data_in, data_read);
+ char flag = TTY_NORMAL;
if (info->errorcode == ERRCODE_INSERT_BREAK) {
- info->icount.brk++;
- *tty->flip.char_buf_ptr = 0;
- *tty->flip.flag_buf_ptr = TTY_BREAK;
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
+ struct tty_struct *tty = info->tty;
+ tty_insert_flip_char(tty, 0, flag);
info->icount.rx++;
}
- *tty->flip.char_buf_ptr = IO_EXTRACT(R_SERIAL0_READ, data_in, data_read);
if (data_read & IO_MASK(R_SERIAL0_READ, par_err)) {
info->icount.parity++;
- *tty->flip.flag_buf_ptr = TTY_PARITY;
+ flag = TTY_PARITY;
} else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) {
info->icount.overrun++;
- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+ flag = TTY_OVERRUN;
} else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) {
info->icount.frame++;
- *tty->flip.flag_buf_ptr = TTY_FRAME;
+ flag = TTY_FRAME;
}
+ tty_insert_flip_char(tty, data, flag);
info->errorcode = 0;
}
info->break_detected_cnt = 0;
@@ -2825,16 +2386,14 @@ more_data:
log_int(rdpc(), 0, 0);
}
);
- *tty->flip.char_buf_ptr = IO_EXTRACT(R_SERIAL0_READ, data_in, data_read);
- *tty->flip.flag_buf_ptr = 0;
+ tty_insert_flip_char(tty,
+ IO_EXTRACT(R_SERIAL0_READ, data_in, data_read),
+ TTY_NORMAL);
} else {
DEBUG_LOG(info->line, "ser_rx int but no data_avail %08lX\n", data_read);
}
- tty->flip.flag_buf_ptr++;
- tty->flip.char_buf_ptr++;
- tty->flip.count++;
info->icount.rx++;
data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]);
if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
@@ -2972,7 +2531,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info)
if (info->x_char) {
unsigned char rstat;
DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char));
- save_flags(flags); cli();
+ local_irq_save(flags);
rstat = info->port[REG_STATUS];
DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
@@ -2981,7 +2540,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info)
info->x_char = 0;
/* We must enable since it is disabled in ser_interrupt */
e100_enable_serial_tx_ready_irq(info);
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
if (info->uses_dma_out) {
@@ -2989,7 +2548,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info)
int i;
/* We only use normal tx interrupt when sending x_char */
DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0));
- save_flags(flags); cli();
+ local_irq_save(flags);
rstat = info->port[REG_STATUS];
DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
e100_disable_serial_tx_ready_irq(info);
@@ -3002,7 +2561,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info)
nop();
*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue);
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
/* Normal char-by-char interrupt */
@@ -3016,7 +2575,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info)
}
DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail]));
/* Send a byte, rs485 timing is critical so turn of ints */
- save_flags(flags); cli();
+ local_irq_save(flags);
info->port[REG_TR_DATA] = info->xmit.buf[info->xmit.tail];
info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
info->icount.tx++;
@@ -3040,7 +2599,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info)
/* We must enable since it is disabled in ser_interrupt */
e100_enable_serial_tx_ready_irq(info);
}
- restore_flags(flags);
+ local_irq_restore(flags);
if (CIRC_CNT(info->xmit.head,
info->xmit.tail,
@@ -3065,7 +2624,7 @@ ser_interrupt(int irq, void *dev_id)
int handled = 0;
static volatile unsigned long reentered_ready_mask = 0;
- save_flags(flags); cli();
+ local_irq_save(flags);
irq_mask1_rd = *R_IRQ_MASK1_RD;
/* First handle all rx interrupts with ints disabled */
info = rs_table;
@@ -3110,7 +2669,7 @@ ser_interrupt(int irq, void *dev_id)
/* Unblock the serial interrupt */
*R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
- sti();
+ local_irq_enable();
ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */
info = rs_table;
for (i = 0; i < NR_PORTS; i++) {
@@ -3123,11 +2682,11 @@ ser_interrupt(int irq, void *dev_id)
ready_mask <<= 2;
}
/* handle_ser_tx_interrupt enables tr_ready interrupts */
- cli();
+ local_irq_disable();
/* Handle reentered TX interrupt */
irq_mask1_rd = reentered_ready_mask;
}
- cli();
+ local_irq_disable();
tx_started = 0;
} else {
unsigned long ready_mask;
@@ -3143,7 +2702,7 @@ ser_interrupt(int irq, void *dev_id)
}
}
- restore_flags(flags);
+ local_irq_restore(flags);
return IRQ_RETVAL(handled);
} /* ser_interrupt */
#endif
@@ -3164,11 +2723,13 @@ ser_interrupt(int irq, void *dev_id)
* them using rs_sched_event(), and they get done here.
*/
static void
-do_softint(void *private_)
+do_softint(struct work_struct *work)
{
- struct e100_serial *info = (struct e100_serial *) private_;
+ struct e100_serial *info;
struct tty_struct *tty;
+ info = container_of(work, struct e100_serial, work);
+
tty = info->tty;
if (!tty)
return;
@@ -3188,13 +2749,12 @@ startup(struct e100_serial * info)
if (!xmit_page)
return -ENOMEM;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* if it was already initialized, skip this */
if (info->flags & ASYNC_INITIALIZED) {
- restore_flags(flags);
+ local_irq_restore(flags);
free_page(xmit_page);
return 0;
}
@@ -3320,7 +2880,7 @@ startup(struct e100_serial * info)
info->flags |= ASYNC_INITIALIZED;
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
@@ -3371,8 +2931,7 @@ shutdown(struct e100_serial * info)
info->irq);
#endif
- save_flags(flags);
- cli(); /* Disable interrupts */
+ local_irq_save(flags);
if (info->xmit.buf) {
free_page((unsigned long)info->xmit.buf);
@@ -3396,7 +2955,7 @@ shutdown(struct e100_serial * info)
set_bit(TTY_IO_ERROR, &info->tty->flags);
info->flags &= ~ASYNC_INITIALIZED;
- restore_flags(flags);
+ local_irq_restore(flags);
}
@@ -3454,7 +3013,6 @@ change_speed(struct e100_serial *info)
DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8));
info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8;
}
- }
#endif
else
{
@@ -3488,8 +3046,7 @@ change_speed(struct e100_serial *info)
#ifndef CONFIG_SVINTO_SIM
/* start with default settings and then fill in changes */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* 8 bit, no/even parity */
info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) |
IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) |
@@ -3553,7 +3110,7 @@ change_speed(struct e100_serial *info)
}
*((unsigned long *)&info->port[REG_XOFF]) = xoff;
- restore_flags(flags);
+ local_irq_restore(flags);
#endif /* !CONFIG_SVINTO_SIM */
update_char_time(info);
@@ -3581,13 +3138,12 @@ rs_flush_chars(struct tty_struct *tty)
/* this protection might not exactly be necessary here */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
start_transmit(info);
- restore_flags(flags);
+ local_irq_restore(flags);
}
-static int rs_raw_write(struct tty_struct * tty, int from_user,
+static int rs_raw_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
int c, ret = 0;
@@ -3610,53 +3166,19 @@ static int rs_raw_write(struct tty_struct * tty, int from_user,
SIMCOUT(buf, count);
return count;
#endif
- save_flags(flags);
+ local_save_flags(flags);
DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
- /* the cli/restore_flags pairs below are needed because the
- * DMA interrupt handler moves the info->xmit values. the memcpy
- * needs to be in the critical region unfortunately, because we
- * need to read xmit values, memcpy, write xmit values in one
- * atomic operation... this could perhaps be avoided by more clever
- * design.
+ /* The local_irq_disable/restore_flags pairs below are needed
+ * because the DMA interrupt handler moves the info->xmit values.
+ * the memcpy needs to be in the critical region unfortunately,
+ * because we need to read xmit values, memcpy, write xmit values
+ * in one atomic operation... this could perhaps be avoided by
+ * more clever design.
*/
- if (from_user) {
- mutex_lock(&tmp_buf_mutex);
- while (1) {
- int c1;
- c = CIRC_SPACE_TO_END(info->xmit.head,
- info->xmit.tail,
- SERIAL_XMIT_SIZE);
- if (count < c)
- c = count;
- if (c <= 0)
- break;
-
- c -= copy_from_user(tmp_buf, buf, c);
- if (!c) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- cli();
- c1 = CIRC_SPACE_TO_END(info->xmit.head,
- info->xmit.tail,
- SERIAL_XMIT_SIZE);
- if (c1 < c)
- c = c1;
- memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
- info->xmit.head = ((info->xmit.head + c) &
- (SERIAL_XMIT_SIZE-1));
- restore_flags(flags);
- buf += c;
- count -= c;
- ret += c;
- }
- mutex_unlock(&tmp_buf_mutex);
- } else {
- cli();
+ local_irq_disable();
while (count) {
c = CIRC_SPACE_TO_END(info->xmit.head,
info->xmit.tail,
@@ -3674,8 +3196,7 @@ static int rs_raw_write(struct tty_struct * tty, int from_user,
count -= c;
ret += c;
}
- restore_flags(flags);
- }
+ local_irq_restore(flags);
/* enable transmitter if not running, unless the tty is stopped
* this does not need IRQ protection since if tr_running == 0
@@ -3694,7 +3215,7 @@ static int rs_raw_write(struct tty_struct * tty, int from_user,
} /* raw_raw_write() */
static int
-rs_write(struct tty_struct * tty, int from_user,
+rs_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
#if defined(CONFIG_ETRAX_RS485)
@@ -3721,7 +3242,7 @@ rs_write(struct tty_struct * tty, int from_user,
}
#endif /* CONFIG_ETRAX_RS485 */
- count = rs_raw_write(tty, from_user, buf, count);
+ count = rs_raw_write(tty, buf, count);
#if defined(CONFIG_ETRAX_RS485)
if (info->rs485.enabled)
@@ -3789,10 +3310,9 @@ rs_flush_buffer(struct tty_struct *tty)
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
unsigned long flags;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
info->xmit.head = info->xmit.tail = 0;
- restore_flags(flags);
+ local_irq_restore(flags);
tty_wakeup(tty);
}
@@ -3810,7 +3330,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
unsigned long flags;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (info->uses_dma_out) {
/* Put the DMA on hold and disable the channel */
*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold);
@@ -3827,7 +3347,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
DFLOW(DEBUG_LOG(info->line, "rs_send_xchar 0x%02X\n", ch));
info->x_char = ch;
e100_enable_serial_tx_ready_irq(info);
- restore_flags(flags);
+ local_irq_restore(flags);
}
/*
@@ -4039,21 +3559,61 @@ char *get_control_state_str(int MLines, char *s)
}
#endif
+static void
+rs_break(struct tty_struct *tty, int break_state)
+{
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+ unsigned long flags;
+
+ if (!info->port)
+ return;
+
+ local_irq_save(flags);
+ if (break_state == -1) {
+ /* Go to manual mode and set the txd pin to 0 */
+ /* Clear bit 7 (txd) and 6 (tr_enable) */
+ info->tx_ctrl &= 0x3F;
+ } else {
+ /* Set bit 7 (txd) and 6 (tr_enable) */
+ info->tx_ctrl |= (0x80 | 0x40);
+ }
+ info->port[REG_TR_CTRL] = info->tx_ctrl;
+ local_irq_restore(flags);
+}
+
static int
-get_modem_info(struct e100_serial * info, unsigned int *value)
+rs_tiocmset(struct tty_struct *tty, struct file *file,
+ unsigned int set, unsigned int clear)
{
- unsigned int result;
- /* Polarity isn't verified */
-#if 0 /*def SERIAL_DEBUG_IO */
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
- printk("get_modem_info: RTS: %i DTR: %i CD: %i RI: %i DSR: %i CTS: %i\n",
- E100_RTS_GET(info),
- E100_DTR_GET(info),
- E100_CD_GET(info),
- E100_RI_GET(info),
- E100_DSR_GET(info),
- E100_CTS_GET(info));
-#endif
+ if (clear & TIOCM_RTS)
+ e100_rts(info, 0);
+ if (clear & TIOCM_DTR)
+ e100_dtr(info, 0);
+ /* Handle FEMALE behaviour */
+ if (clear & TIOCM_RI)
+ e100_ri_out(info, 0);
+ if (clear & TIOCM_CD)
+ e100_cd_out(info, 0);
+
+ if (set & TIOCM_RTS)
+ e100_rts(info, 1);
+ if (set & TIOCM_DTR)
+ e100_dtr(info, 1);
+ /* Handle FEMALE behaviour */
+ if (set & TIOCM_RI)
+ e100_ri_out(info, 1);
+ if (set & TIOCM_CD)
+ e100_cd_out(info, 1);
+ return 0;
+}
+
+static int
+rs_tiocmget(struct tty_struct *tty, struct file *file)
+{
+ struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+ unsigned int result;
result =
(!E100_RTS_GET(info) ? TIOCM_RTS : 0)
@@ -4064,95 +3624,20 @@ get_modem_info(struct e100_serial * info, unsigned int *value)
| (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
#ifdef SERIAL_DEBUG_IO
- printk("e100ser: modem state: %i 0x%08X\n", result, result);
+ printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n",
+ info->line, result, result);
{
char s[100];
get_control_state_str(result, s);
- printk("state: %s\n", s);
+ printk(KERN_DEBUG "state: %s\n", s);
}
#endif
- if (copy_to_user(value, &result, sizeof(int)))
- return -EFAULT;
- return 0;
-}
-
-
-static int
-set_modem_info(struct e100_serial * info, unsigned int cmd,
- unsigned int *value)
-{
- unsigned int arg;
+ return result;
- if (copy_from_user(&arg, value, sizeof(int)))
- return -EFAULT;
-
- switch (cmd) {
- case TIOCMBIS:
- if (arg & TIOCM_RTS) {
- e100_rts(info, 1);
- }
- if (arg & TIOCM_DTR) {
- e100_dtr(info, 1);
- }
- /* Handle FEMALE behaviour */
- if (arg & TIOCM_RI) {
- e100_ri_out(info, 1);
- }
- if (arg & TIOCM_CD) {
- e100_cd_out(info, 1);
- }
- break;
- case TIOCMBIC:
- if (arg & TIOCM_RTS) {
- e100_rts(info, 0);
- }
- if (arg & TIOCM_DTR) {
- e100_dtr(info, 0);
- }
- /* Handle FEMALE behaviour */
- if (arg & TIOCM_RI) {
- e100_ri_out(info, 0);
- }
- if (arg & TIOCM_CD) {
- e100_cd_out(info, 0);
- }
- break;
- case TIOCMSET:
- e100_rts(info, arg & TIOCM_RTS);
- e100_dtr(info, arg & TIOCM_DTR);
- /* Handle FEMALE behaviour */
- e100_ri_out(info, arg & TIOCM_RI);
- e100_cd_out(info, arg & TIOCM_CD);
- break;
- default:
- return -EINVAL;
- }
- return 0;
}
-static void
-rs_break(struct tty_struct *tty, int break_state)
-{
- struct e100_serial * info = (struct e100_serial *)tty->driver_data;
- unsigned long flags;
-
- if (!info->port)
- return;
-
- save_flags(flags);
- cli();
- if (break_state == -1) {
- /* Go to manual mode and set the txd pin to 0 */
- info->tx_ctrl &= 0x3F; /* Clear bit 7 (txd) and 6 (tr_enable) */
- } else {
- info->tx_ctrl |= (0x80 | 0x40); /* Set bit 7 (txd) and 6 (tr_enable) */
- }
- info->port[REG_TR_CTRL] = info->tx_ctrl;
- restore_flags(flags);
-}
-
static int
rs_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
@@ -4167,49 +3652,45 @@ rs_ioctl(struct tty_struct *tty, struct file * file,
}
switch (cmd) {
- case TIOCMGET:
- return get_modem_info(info, (unsigned int *) arg);
- case TIOCMBIS:
- case TIOCMBIC:
- case TIOCMSET:
- return set_modem_info(info, cmd, (unsigned int *) arg);
- case TIOCGSERIAL:
- return get_serial_info(info,
- (struct serial_struct *) arg);
- case TIOCSSERIAL:
- return set_serial_info(info,
- (struct serial_struct *) arg);
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info(info, (unsigned int *) arg);
-
- case TIOCSERGSTRUCT:
- if (copy_to_user((struct e100_serial *) arg,
- info, sizeof(struct e100_serial)))
- return -EFAULT;
- return 0;
+ case TIOCGSERIAL:
+ return get_serial_info(info,
+ (struct serial_struct *) arg);
+ case TIOCSSERIAL:
+ return set_serial_info(info,
+ (struct serial_struct *) arg);
+ case TIOCSERGETLSR: /* Get line status register */
+ return get_lsr_info(info, (unsigned int *) arg);
+
+ case TIOCSERGSTRUCT:
+ if (copy_to_user((struct e100_serial *) arg,
+ info, sizeof(struct e100_serial)))
+ return -EFAULT;
+ return 0;
#if defined(CONFIG_ETRAX_RS485)
- case TIOCSERSETRS485:
- {
- struct rs485_control rs485ctrl;
- if (copy_from_user(&rs485ctrl, (struct rs485_control*)arg, sizeof(rs485ctrl)))
- return -EFAULT;
+ case TIOCSERSETRS485:
+ {
+ struct rs485_control rs485ctrl;
+ if (copy_from_user(&rs485ctrl, (struct rs485_control *)arg,
+ sizeof(rs485ctrl)))
+ return -EFAULT;
- return e100_enable_rs485(tty, &rs485ctrl);
- }
+ return e100_enable_rs485(tty, &rs485ctrl);
+ }
- case TIOCSERWRRS485:
- {
- struct rs485_write rs485wr;
- if (copy_from_user(&rs485wr, (struct rs485_write*)arg, sizeof(rs485wr)))
- return -EFAULT;
+ case TIOCSERWRRS485:
+ {
+ struct rs485_write rs485wr;
+ if (copy_from_user(&rs485wr, (struct rs485_write *)arg,
+ sizeof(rs485wr)))
+ return -EFAULT;
- return e100_write_rs485(tty, 1, rs485wr.outc, rs485wr.outc_size);
- }
+ return e100_write_rs485(tty, rs485wr.outc, rs485wr.outc_size);
+ }
#endif
- default:
- return -ENOIOCTLCMD;
+ default:
+ return -ENOIOCTLCMD;
}
return 0;
}
@@ -4234,46 +3715,6 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
}
-/* In debugport.c - register a console write function that uses the normal
- * serial driver
- */
-typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len);
-
-extern debugport_write_function debug_write_function;
-
-static int rs_debug_write_function(int i, const char *buf, unsigned int len)
-{
- int cnt;
- int written = 0;
- struct tty_struct *tty;
- static int recurse_cnt = 0;
-
- tty = rs_table[i].tty;
- if (tty) {
- unsigned long flags;
- if (recurse_cnt > 5) /* We skip this debug output */
- return 1;
-
- local_irq_save(flags);
- recurse_cnt++;
- local_irq_restore(flags);
- do {
- cnt = rs_write(tty, 0, buf + written, len);
- if (cnt >= 0) {
- written += cnt;
- buf += cnt;
- len -= cnt;
- } else
- len = cnt;
- } while(len > 0);
- local_irq_save(flags);
- recurse_cnt--;
- local_irq_restore(flags);
- return 1;
- }
- return 0;
-}
-
/*
* ------------------------------------------------------------
* rs_close()
@@ -4295,11 +3736,10 @@ rs_close(struct tty_struct *tty, struct file * filp)
/* interrupts are disabled for this entire function */
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (tty_hung_up_p(filp)) {
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
@@ -4326,7 +3766,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
info->count = 0;
}
if (info->count) {
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
info->flags |= ASYNC_CLOSING;
@@ -4380,7 +3820,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
}
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&info->close_wait);
- restore_flags(flags);
+ local_irq_restore(flags);
/* port closed */
@@ -4402,6 +3842,28 @@ rs_close(struct tty_struct *tty, struct file * filp)
#endif
}
#endif
+
+ /*
+ * Release any allocated DMA irq's.
+ */
+ if (info->dma_in_enabled) {
+ free_irq(info->dma_in_irq_nbr, info);
+ cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description);
+ info->uses_dma_in = 0;
+#ifdef SERIAL_DEBUG_OPEN
+ printk(KERN_DEBUG "DMA irq '%s' freed\n",
+ info->dma_in_irq_description);
+#endif
+ }
+ if (info->dma_out_enabled) {
+ free_irq(info->dma_out_irq_nbr, info);
+ cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description);
+ info->uses_dma_out = 0;
+#ifdef SERIAL_DEBUG_OPEN
+ printk(KERN_DEBUG "DMA irq '%s' freed\n",
+ info->dma_out_irq_description);
+#endif
+ }
}
/*
@@ -4476,8 +3938,8 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
+ wait_event_interruptible(info->close_wait,
+ !(info->flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
if (info->flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
@@ -4515,21 +3977,19 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
printk("block_til_ready before block: ttyS%d, count = %d\n",
info->line, info->count);
#endif
- save_flags(flags);
- cli();
+ local_irq_save(flags);
if (!tty_hung_up_p(filp)) {
extra_count++;
info->count--;
}
- restore_flags(flags);
+ local_irq_restore(flags);
info->blocked_open++;
while (1) {
- save_flags(flags);
- cli();
+ local_irq_save(flags);
/* assert RTS and DTR */
e100_rts(info, 1);
e100_dtr(info, 1);
- restore_flags(flags);
+ local_irq_restore(flags);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(info->flags & ASYNC_INITIALIZED)) {
@@ -4571,6 +4031,19 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
return 0;
}
+static void
+deinit_port(struct e100_serial *info)
+{
+ if (info->dma_out_enabled) {
+ cris_free_dma(info->dma_out_nbr, info->dma_out_irq_description);
+ free_irq(info->dma_out_irq_nbr, info);
+ }
+ if (info->dma_in_enabled) {
+ cris_free_dma(info->dma_in_nbr, info->dma_in_irq_description);
+ free_irq(info->dma_in_irq_nbr, info);
+ }
+}
+
/*
* This routine is called whenever a serial port is opened.
* It performs the serial-specific initialization for the tty structure.
@@ -4581,9 +4054,9 @@ rs_open(struct tty_struct *tty, struct file * filp)
struct e100_serial *info;
int retval, line;
unsigned long page;
+ int allocated_resources = 0;
/* find which port we want to open */
-
line = tty->index;
if (line < 0 || line >= NR_PORTS)
@@ -4623,8 +4096,8 @@ rs_open(struct tty_struct *tty, struct file * filp)
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
+ wait_event_interruptible(info->close_wait,
+ !(info->flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
return ((info->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
@@ -4634,12 +4107,85 @@ rs_open(struct tty_struct *tty, struct file * filp)
}
/*
+ * If DMA is enabled try to allocate the irq's.
+ */
+ if (info->count == 1) {
+ allocated_resources = 1;
+ if (info->dma_in_enabled) {
+ if (request_irq(info->dma_in_irq_nbr,
+ rec_interrupt,
+ info->dma_in_irq_flags,
+ info->dma_in_irq_description,
+ info)) {
+ printk(KERN_WARNING "DMA irq '%s' busy; "
+ "falling back to non-DMA mode\n",
+ info->dma_in_irq_description);
+ /* Make sure we never try to use DMA in */
+ /* for the port again. */
+ info->dma_in_enabled = 0;
+ } else if (cris_request_dma(info->dma_in_nbr,
+ info->dma_in_irq_description,
+ DMA_VERBOSE_ON_ERROR,
+ info->dma_owner)) {
+ free_irq(info->dma_in_irq_nbr, info);
+ printk(KERN_WARNING "DMA '%s' busy; "
+ "falling back to non-DMA mode\n",
+ info->dma_in_irq_description);
+ /* Make sure we never try to use DMA in */
+ /* for the port again. */
+ info->dma_in_enabled = 0;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ else
+ printk(KERN_DEBUG "DMA irq '%s' allocated\n",
+ info->dma_in_irq_description);
+#endif
+ }
+ if (info->dma_out_enabled) {
+ if (request_irq(info->dma_out_irq_nbr,
+ tr_interrupt,
+ info->dma_out_irq_flags,
+ info->dma_out_irq_description,
+ info)) {
+ printk(KERN_WARNING "DMA irq '%s' busy; "
+ "falling back to non-DMA mode\n",
+ info->dma_out_irq_description);
+ /* Make sure we never try to use DMA out */
+ /* for the port again. */
+ info->dma_out_enabled = 0;
+ } else if (cris_request_dma(info->dma_out_nbr,
+ info->dma_out_irq_description,
+ DMA_VERBOSE_ON_ERROR,
+ info->dma_owner)) {
+ free_irq(info->dma_out_irq_nbr, info);
+ printk(KERN_WARNING "DMA '%s' busy; "
+ "falling back to non-DMA mode\n",
+ info->dma_out_irq_description);
+ /* Make sure we never try to use DMA out */
+ /* for the port again. */
+ info->dma_out_enabled = 0;
+ }
+#ifdef SERIAL_DEBUG_OPEN
+ else
+ printk(KERN_DEBUG "DMA irq '%s' allocated\n",
+ info->dma_out_irq_description);
+#endif
+ }
+ }
+
+ /*
* Start up the serial port
*/
retval = startup(info);
- if (retval)
+ if (retval) {
+ if (allocated_resources)
+ deinit_port(info);
+
+ /* FIXME Decrease count info->count here too? */
return retval;
+ }
+
retval = block_til_ready(tty, filp, info);
if (retval) {
@@ -4647,6 +4193,9 @@ rs_open(struct tty_struct *tty, struct file * filp)
printk("rs_open returning after block_til_ready with %d\n",
retval);
#endif
+ if (allocated_resources)
+ deinit_port(info);
+
return retval;
}
@@ -4836,6 +4385,8 @@ static const struct tty_operations rs_ops = {
.send_xchar = rs_send_xchar,
.wait_until_sent = rs_wait_until_sent,
.read_proc = rs_read_proc,
+ .tiocmget = rs_tiocmget,
+ .tiocmset = rs_tiocmset
};
static int __init
@@ -4853,9 +4404,27 @@ rs_init(void)
/* Setup the timed flush handler system */
#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER)
- init_timer(&flush_timer);
- flush_timer.function = timed_flush_handler;
- mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS);
+ setup_timer(&flush_timer, timed_flush_handler, 0);
+ mod_timer(&flush_timer, jiffies + 5);
+#endif
+
+#if defined(CONFIG_ETRAX_RS485)
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+ if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit,
+ rs485_pa_bit)) {
+ printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
+ "RS485 pin\n");
+ return -EBUSY;
+ }
+#endif
+#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
+ if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit,
+ rs485_port_g_bit)) {
+ printk(KERN_CRIT "ETRAX100LX serial: Could not allocate "
+ "RS485 pin\n");
+ return -EBUSY;
+ }
+#endif
#endif
/* Initialize the tty_driver structure */
@@ -4882,6 +4451,16 @@ rs_init(void)
/* do some initializing for the separate ports */
for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
+ if (info->enabled) {
+ if (cris_request_io_interface(info->io_if,
+ info->io_if_description)) {
+ printk(KERN_CRIT "ETRAX100LX async serial: "
+ "Could not allocate IO pins for "
+ "%s, port %d\n",
+ info->io_if_description, i);
+ info->enabled = 0;
+ }
+ }
info->uses_dma_in = 0;
info->uses_dma_out = 0;
info->line = i;
@@ -4915,7 +4494,7 @@ rs_init(void)
info->rs485.delay_rts_before_send = 0;
info->rs485.enabled = 0;
#endif
- INIT_WORK(&info->work, do_softint, info);
+ INIT_WORK(&info->work, do_softint);
if (info->enabled) {
printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n",
@@ -4933,64 +4512,17 @@ rs_init(void)
#endif
#ifndef CONFIG_SVINTO_SIM
+#ifndef CONFIG_ETRAX_KGDB
/* Not needed in simulator. May only complicate stuff. */
/* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
- if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, IRQF_SHARED | IRQF_DISABLED, "serial ", NULL))
- panic("irq8");
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT0
-#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
- if (request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, IRQF_DISABLED, "serial 0 dma tr", NULL))
- panic("irq22");
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
- if (request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, IRQF_DISABLED, "serial 0 dma rec", NULL))
- panic("irq23");
-#endif
-#endif
-
-#ifdef CONFIG_ETRAX_SERIAL_PORT1
-#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
- if (request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, IRQF_DISABLED, "serial 1 dma tr", NULL))
- panic("irq24");
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
- if (request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, IRQF_DISABLED, "serial 1 dma rec", NULL))
- panic("irq25");
-#endif
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT2
- /* DMA Shared with par0 (and SCSI0 and ATA) */
-#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
- if (request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, IRQF_SHARED | IRQF_DISABLED, "serial 2 dma tr", NULL))
- panic("irq18");
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
- if (request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, IRQF_SHARED | IRQF_DISABLED, "serial 2 dma rec", NULL))
- panic("irq19");
-#endif
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT3
- /* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */
-#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
- if (request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, IRQF_SHARED | IRQF_DISABLED, "serial 3 dma tr", NULL))
- panic("irq20");
-#endif
-#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
- if (request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, IRQF_SHARED | IRQF_DISABLED, "serial 3 dma rec", NULL))
- panic("irq21");
-#endif
-#endif
+ if (request_irq(SERIAL_IRQ_NBR, ser_interrupt,
+ IRQF_SHARED | IRQF_DISABLED, "serial ", driver))
+ panic("%s: Failed to request irq8", __FUNCTION__);
-#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
- if (request_irq(TIMER1_IRQ_NBR, timeout_interrupt, IRQF_SHARED | IRQF_DISABLED,
- "fast serial dma timeout", NULL)) {
- printk(KERN_CRIT "err: timer1 irq\n");
- }
#endif
#endif /* CONFIG_SVINTO_SIM */
- debug_write_function = rs_debug_write_function;
+
return 0;
}
diff --git a/drivers/serial/crisv10.h b/drivers/serial/crisv10.h
new file mode 100644
index 00000000000..ccd0f32b737
--- /dev/null
+++ b/drivers/serial/crisv10.h
@@ -0,0 +1,146 @@
+/*
+ * serial.h: Arch-dep definitions for the Etrax100 serial driver.
+ *
+ * Copyright (C) 1998-2007 Axis Communications AB
+ */
+
+#ifndef _ETRAX_SERIAL_H
+#define _ETRAX_SERIAL_H
+
+#include <linux/circ_buf.h>
+#include <asm/termios.h>
+#include <asm/dma.h>
+#include <asm/arch/io_interface_mux.h>
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+#define SERIAL_RECV_DESCRIPTORS 8
+
+struct etrax_recv_buffer {
+ struct etrax_recv_buffer *next;
+ unsigned short length;
+ unsigned char error;
+ unsigned char pad;
+
+ unsigned char buffer[0];
+};
+
+struct e100_serial {
+ int baud;
+ volatile u8 *port; /* R_SERIALx_CTRL */
+ u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */
+
+ /* Output registers */
+ volatile u8 *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
+ volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST */
+ volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD */
+ const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS */
+
+ /* Input registers */
+ volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
+ volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST */
+ volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */
+ volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */
+
+ int flags; /* defined in tty.h */
+
+ u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
+ u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
+ u8 iseteop; /* bit number for R_SET_EOP for the input dma */
+ int enabled; /* Set to 1 if the port is enabled in HW config */
+
+ u8 dma_out_enabled; /* Set to 1 if DMA should be used */
+ u8 dma_in_enabled; /* Set to 1 if DMA should be used */
+
+ /* end of fields defined in rs_table[] in .c-file */
+ int dma_owner;
+ unsigned int dma_in_nbr;
+ unsigned int dma_out_nbr;
+ unsigned int dma_in_irq_nbr;
+ unsigned int dma_out_irq_nbr;
+ unsigned long dma_in_irq_flags;
+ unsigned long dma_out_irq_flags;
+ char *dma_in_irq_description;
+ char *dma_out_irq_description;
+
+ enum cris_io_interface io_if;
+ char *io_if_description;
+
+ u8 uses_dma_in; /* Set to 1 if DMA is used */
+ u8 uses_dma_out; /* Set to 1 if DMA is used */
+ u8 forced_eop; /* a fifo eop has been forced */
+ int baud_base; /* For special baudrates */
+ int custom_divisor; /* For special baudrates */
+ struct etrax_dma_descr tr_descr;
+ struct etrax_dma_descr rec_descr[SERIAL_RECV_DESCRIPTORS];
+ int cur_rec_descr;
+
+ volatile int tr_running; /* 1 if output is running */
+
+ struct tty_struct *tty;
+ int read_status_mask;
+ int ignore_status_mask;
+ int x_char; /* xon/xoff character */
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
+ unsigned long event;
+ unsigned long last_active;
+ int line;
+ int type; /* PORT_ETRAX */
+ int count; /* # of fd on device */
+ int blocked_open; /* # of blocked opens */
+ struct circ_buf xmit;
+ struct etrax_recv_buffer *first_recv_buffer;
+ struct etrax_recv_buffer *last_recv_buffer;
+ unsigned int recv_cnt;
+ unsigned int max_recv_cnt;
+
+ struct work_struct work;
+ struct async_icount icount; /* error-statistics etc.*/
+ struct ktermios normal_termios;
+ struct ktermios callout_termios;
+ wait_queue_head_t open_wait;
+ wait_queue_head_t close_wait;
+
+ unsigned long char_time_usec; /* The time for 1 char, in usecs */
+ unsigned long flush_time_usec; /* How often we should flush */
+ unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */
+ unsigned long last_tx_active; /* Last tx time in jiffies */
+ unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */
+ unsigned long last_rx_active; /* Last rx time in jiffies */
+
+ int break_detected_cnt;
+ int errorcode;
+
+#ifdef CONFIG_ETRAX_RS485
+ struct rs485_control rs485; /* RS-485 support */
+#endif
+};
+
+/* this PORT is not in the standard serial.h. it's not actually used for
+ * anything since we only have one type of async serial-port anyway in this
+ * system.
+ */
+
+#define PORT_ETRAX 1
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP 0
+
+#endif /* __KERNEL__ */
+
+#endif /* !_ETRAX_SERIAL_H */
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index 281f23a371b..94ec6637250 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -500,13 +500,11 @@ void jsm_input(struct jsm_channel *ch)
{
struct jsm_board *bd;
struct tty_struct *tp;
- struct tty_ldisc *ld;
u32 rmask;
u16 head;
u16 tail;
int data_len;
unsigned long lock_flags;
- int flip_len = 0;
int len = 0;
int n = 0;
int s = 0;
@@ -574,45 +572,13 @@ void jsm_input(struct jsm_channel *ch)
jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start 2\n");
- /*
- * If the rxbuf is empty and we are not throttled, put as much
- * as we can directly into the linux TTY buffer.
- *
- */
- flip_len = TTY_FLIPBUF_SIZE;
-
- len = min(data_len, flip_len);
- len = min(len, (N_TTY_BUF_SIZE - 1) - tp->read_cnt);
- ld = tty_ldisc_ref(tp);
-
- /*
- * If we were unable to get a reference to the ld,
- * don't flush our buffer, and act like the ld doesn't
- * have any space to put the data right now.
- */
- if (!ld) {
- len = 0;
- } else {
- /*
- * If ld doesn't have a pointer to a receive_buf function,
- * flush the data, then act like the ld doesn't have any
- * space to put the data right now.
- */
- if (!ld->receive_buf) {
- ch->ch_r_head = ch->ch_r_tail;
- len = 0;
- }
- }
-
- if (len <= 0) {
+ if (data_len <= 0) {
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
- if (ld)
- tty_ldisc_deref(ld);
return;
}
- len = tty_buffer_request_room(tp, len);
+ len = tty_buffer_request_room(tp, data_len);
n = len;
/*
@@ -647,7 +613,7 @@ void jsm_input(struct jsm_channel *ch)
else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE)
tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME);
else
- tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL);
+ tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL);
}
} else {
tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ;
@@ -666,9 +632,6 @@ void jsm_input(struct jsm_channel *ch)
/* Tell the tty layer its okay to "eat" the data now */
tty_flip_buffer_push(tp);
- if (ld)
- tty_ldisc_deref(ld);
-
jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
}
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
index 6e09c8b395e..348ee2c19b5 100644
--- a/drivers/serial/m32r_sio.c
+++ b/drivers/serial/m32r_sio.c
@@ -539,7 +539,7 @@ static void serial_do_unlink(struct irq_info *i, struct uart_sio_port *up)
static int serial_link_irq_chain(struct uart_sio_port *up)
{
struct irq_info *i = irq_lists + up->port.irq;
- int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
+ int ret, irq_flags = 0;
spin_lock_irq(&i->lock);
diff --git a/drivers/serial/m32r_sio.h b/drivers/serial/m32r_sio.h
index 849f1b2c253..e9b7e11793b 100644
--- a/drivers/serial/m32r_sio.h
+++ b/drivers/serial/m32r_sio.h
@@ -46,9 +46,3 @@ struct old_serial_port {
#define PROBE_ANY (~0)
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
-
-#ifdef CONFIG_SERIAL_SIO_SHARE_IRQ
-#define M32R_SIO_SHARE_IRQS 1
-#else
-#define M32R_SIO_SHARE_IRQS 0
-#endif
diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c
new file mode 100644
index 00000000000..a7d4360ea7d
--- /dev/null
+++ b/drivers/serial/mcf.c
@@ -0,0 +1,653 @@
+/****************************************************************************/
+
+/*
+ * mcf.c -- Freescale ColdFire UART driver
+ *
+ * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/nettel.h>
+
+/****************************************************************************/
+
+/*
+ * Some boards implement the DTR/DCD lines using GPIO lines, most
+ * don't. Dummy out the access macros for those that don't. Those
+ * that do should define these macros somewhere in there board
+ * specific inlude files.
+ */
+#if !defined(mcf_getppdcd)
+#define mcf_getppdcd(p) (1)
+#endif
+#if !defined(mcf_getppdtr)
+#define mcf_getppdtr(p) (1)
+#endif
+#if !defined(mcf_setppdtr)
+#define mcf_setppdtr(p, v) do { } while (0)
+#endif
+
+/****************************************************************************/
+
+/*
+ * Local per-uart structure.
+ */
+struct mcf_uart {
+ struct uart_port port;
+ unsigned int sigs; /* Local copy of line sigs */
+ unsigned char imr; /* Local IMR mirror */
+};
+
+/****************************************************************************/
+
+static unsigned int mcf_tx_empty(struct uart_port *port)
+{
+ return (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXEMPTY) ?
+ TIOCSER_TEMT : 0;
+}
+
+/****************************************************************************/
+
+static unsigned int mcf_get_mctrl(struct uart_port *port)
+{
+ struct mcf_uart *pp = (struct mcf_uart *) port;
+ unsigned long flags;
+ unsigned int sigs;
+
+ spin_lock_irqsave(&port->lock, flags);
+ sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ?
+ 0 : TIOCM_CTS;
+ sigs |= (pp->sigs & TIOCM_RTS);
+ sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0);
+ sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0);
+ spin_unlock_irqrestore(&port->lock, flags);
+ return sigs;
+}
+
+/****************************************************************************/
+
+static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
+{
+ struct mcf_uart *pp = (struct mcf_uart *) port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ pp->sigs = sigs;
+ mcf_setppdtr(port->line, (sigs & TIOCM_DTR));
+ if (sigs & TIOCM_RTS)
+ writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
+ else
+ writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_start_tx(struct uart_port *port)
+{
+ struct mcf_uart *pp = (struct mcf_uart *) port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ pp->imr |= MCFUART_UIR_TXREADY;
+ writeb(pp->imr, port->membase + MCFUART_UIMR);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_stop_tx(struct uart_port *port)
+{
+ struct mcf_uart *pp = (struct mcf_uart *) port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ pp->imr &= ~MCFUART_UIR_TXREADY;
+ writeb(pp->imr, port->membase + MCFUART_UIMR);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_stop_rx(struct uart_port *port)
+{
+ struct mcf_uart *pp = (struct mcf_uart *) port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ pp->imr &= ~MCFUART_UIR_RXREADY;
+ writeb(pp->imr, port->membase + MCFUART_UIMR);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_break_ctl(struct uart_port *port, int break_state)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+ if (break_state == -1)
+ writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR);
+ else
+ writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_enable_ms(struct uart_port *port)
+{
+}
+
+/****************************************************************************/
+
+static int mcf_startup(struct uart_port *port)
+{
+ struct mcf_uart *pp = (struct mcf_uart *) port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Reset UART, get it into known state... */
+ writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+ writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+
+ /* Enable the UART transmitter and receiver */
+ writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
+ port->membase + MCFUART_UCR);
+
+ /* Enable RX interrupts now */
+ pp->imr = MCFUART_UIR_RXREADY;
+ writeb(pp->imr, port->membase + MCFUART_UIMR);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return 0;
+}
+
+/****************************************************************************/
+
+static void mcf_shutdown(struct uart_port *port)
+{
+ struct mcf_uart *pp = (struct mcf_uart *) port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* Disable all interrupts now */
+ pp->imr = 0;
+ writeb(pp->imr, port->membase + MCFUART_UIMR);
+
+ /* Disable UART transmitter and receiver */
+ writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+ writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned long flags;
+ unsigned int baud, baudclk;
+ unsigned char mr1, mr2;
+
+ baud = uart_get_baud_rate(port, termios, old, 0, 230400);
+ baudclk = ((MCF_BUSCLK / baud) + 16) / 32;
+
+ mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
+ mr2 = 0;
+
+ switch (termios->c_cflag & CSIZE) {
+ case CS5: mr1 |= MCFUART_MR1_CS5; break;
+ case CS6: mr1 |= MCFUART_MR1_CS6; break;
+ case CS7: mr1 |= MCFUART_MR1_CS7; break;
+ case CS8:
+ default: mr1 |= MCFUART_MR1_CS8; break;
+ }
+
+ if (termios->c_cflag & PARENB) {
+ if (termios->c_cflag & CMSPAR) {
+ if (termios->c_cflag & PARODD)
+ mr1 |= MCFUART_MR1_PARITYMARK;
+ else
+ mr1 |= MCFUART_MR1_PARITYSPACE;
+ } else {
+ if (termios->c_cflag & PARODD)
+ mr1 |= MCFUART_MR1_PARITYODD;
+ else
+ mr1 |= MCFUART_MR1_PARITYEVEN;
+ }
+ } else {
+ mr1 |= MCFUART_MR1_PARITYNONE;
+ }
+
+ if (termios->c_cflag & CSTOPB)
+ mr2 |= MCFUART_MR2_STOP2;
+ else
+ mr2 |= MCFUART_MR2_STOP1;
+
+ if (termios->c_cflag & CRTSCTS) {
+ mr1 |= MCFUART_MR1_RXRTS;
+ mr2 |= MCFUART_MR2_TXCTS;
+ }
+
+ spin_lock_irqsave(&port->lock, flags);
+ writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
+ writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
+ writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR);
+ writeb(mr1, port->membase + MCFUART_UMR);
+ writeb(mr2, port->membase + MCFUART_UMR);
+ writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1);
+ writeb((baudclk & 0xff), port->membase + MCFUART_UBG2);
+ writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER,
+ port->membase + MCFUART_UCSR);
+ writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
+ port->membase + MCFUART_UCR);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/****************************************************************************/
+
+static void mcf_rx_chars(struct mcf_uart *pp)
+{
+ struct uart_port *port = (struct uart_port *) pp;
+ unsigned char status, ch, flag;
+
+ while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) {
+ ch = readb(port->membase + MCFUART_URB);
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (status & MCFUART_USR_RXERR) {
+ writeb(MCFUART_UCR_CMDRESETERR,
+ port->membase + MCFUART_UCR);
+
+ if (status & MCFUART_USR_RXBREAK) {
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ continue;
+ } else if (status & MCFUART_USR_RXPARITY) {
+ port->icount.parity++;
+ } else if (status & MCFUART_USR_RXOVERRUN) {
+ port->icount.overrun++;
+ } else if (status & MCFUART_USR_RXFRAMING) {
+ port->icount.frame++;
+ }
+
+ status &= port->read_status_mask;
+
+ if (status & MCFUART_USR_RXBREAK)
+ flag = TTY_BREAK;
+ else if (status & MCFUART_USR_RXPARITY)
+ flag = TTY_PARITY;
+ else if (status & MCFUART_USR_RXFRAMING)
+ flag = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(port, ch))
+ continue;
+ uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
+ }
+
+ tty_flip_buffer_push(port->info->tty);
+}
+
+/****************************************************************************/
+
+static void mcf_tx_chars(struct mcf_uart *pp)
+{
+ struct uart_port *port = (struct uart_port *) pp;
+ struct circ_buf *xmit = &port->info->xmit;
+
+ if (port->x_char) {
+ /* Send special char - probably flow control */
+ writeb(port->x_char, port->membase + MCFUART_UTB);
+ port->x_char = 0;
+ port->icount.tx++;
+ return;
+ }
+
+ while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
+ if (xmit->head == xmit->tail)
+ break;
+ writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
+ 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 (xmit->head == xmit->tail) {
+ pp->imr &= ~MCFUART_UIR_TXREADY;
+ writeb(pp->imr, port->membase + MCFUART_UIMR);
+ }
+}
+
+/****************************************************************************/
+
+static irqreturn_t mcf_interrupt(int irq, void *data)
+{
+ struct uart_port *port = data;
+ struct mcf_uart *pp = (struct mcf_uart *) port;
+ unsigned int isr;
+
+ isr = readb(port->membase + MCFUART_UISR) & pp->imr;
+ if (isr & MCFUART_UIR_RXREADY)
+ mcf_rx_chars(pp);
+ if (isr & MCFUART_UIR_TXREADY)
+ mcf_tx_chars(pp);
+ return IRQ_HANDLED;
+}
+
+/****************************************************************************/
+
+static void mcf_config_port(struct uart_port *port, int flags)
+{
+ port->type = PORT_MCF;
+
+ /* Clear mask, so no surprise interrupts. */
+ writeb(0, port->membase + MCFUART_UIMR);
+
+ if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port))
+ printk(KERN_ERR "MCF: unable to attach ColdFire UART %d "
+ "interrupt vector=%d\n", port->line, port->irq);
+}
+
+/****************************************************************************/
+
+static const char *mcf_type(struct uart_port *port)
+{
+ return (port->type == PORT_MCF) ? "ColdFire UART" : NULL;
+}
+
+/****************************************************************************/
+
+static int mcf_request_port(struct uart_port *port)
+{
+ /* UARTs always present */
+ return 0;
+}
+
+/****************************************************************************/
+
+static void mcf_release_port(struct uart_port *port)
+{
+ /* Nothing to release... */
+}
+
+/****************************************************************************/
+
+static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF))
+ return -EINVAL;
+ return 0;
+}
+
+/****************************************************************************/
+
+/*
+ * Define the basic serial functions we support.
+ */
+static struct uart_ops mcf_uart_ops = {
+ .tx_empty = mcf_tx_empty,
+ .get_mctrl = mcf_get_mctrl,
+ .set_mctrl = mcf_set_mctrl,
+ .start_tx = mcf_start_tx,
+ .stop_tx = mcf_stop_tx,
+ .stop_rx = mcf_stop_rx,
+ .enable_ms = mcf_enable_ms,
+ .break_ctl = mcf_break_ctl,
+ .startup = mcf_startup,
+ .shutdown = mcf_shutdown,
+ .set_termios = mcf_set_termios,
+ .type = mcf_type,
+ .request_port = mcf_request_port,
+ .release_port = mcf_release_port,
+ .config_port = mcf_config_port,
+ .verify_port = mcf_verify_port,
+};
+
+static struct mcf_uart mcf_ports[3];
+
+#define MCF_MAXPORTS (sizeof(mcf_ports) / sizeof(struct mcf_uart))
+
+/****************************************************************************/
+#if defined(CONFIG_SERIAL_MCF_CONSOLE)
+/****************************************************************************/
+
+int __init early_mcf_setup(struct mcf_platform_uart *platp)
+{
+ struct uart_port *port;
+ int i;
+
+ for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
+ port = &mcf_ports[i].port;
+
+ port->line = i;
+ port->type = PORT_MCF;
+ port->mapbase = platp[i].mapbase;
+ port->membase = (platp[i].membase) ? platp[i].membase :
+ (unsigned char __iomem *) port->mapbase;
+ port->iotype = SERIAL_IO_MEM;
+ port->irq = platp[i].irq;
+ port->uartclk = MCF_BUSCLK;
+ port->flags = ASYNC_BOOT_AUTOCONF;
+ port->ops = &mcf_uart_ops;
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+
+static void mcf_console_putc(struct console *co, const char c)
+{
+ struct uart_port *port = &(mcf_ports + co->index)->port;
+ int i;
+
+ for (i = 0; (i < 0x10000); i++) {
+ if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
+ break;
+ }
+ writeb(c, port->membase + MCFUART_UTB);
+ for (i = 0; (i < 0x10000); i++) {
+ if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
+ break;
+ }
+}
+
+/****************************************************************************/
+
+static void mcf_console_write(struct console *co, const char *s, unsigned int count)
+{
+ for (; (count); count--, s++) {
+ mcf_console_putc(co, *s);
+ if (*s == '\n')
+ mcf_console_putc(co, '\r');
+ }
+}
+
+/****************************************************************************/
+
+static int __init mcf_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = CONFIG_SERIAL_MCF_BAUDRATE;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if ((co->index >= 0) && (co->index <= MCF_MAXPORTS))
+ co->index = 0;
+ port = &mcf_ports[co->index].port;
+ if (port->membase == 0)
+ return -ENODEV;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+/****************************************************************************/
+
+static struct uart_driver mcf_driver;
+
+static struct console mcf_console = {
+ .name = "ttyS",
+ .write = mcf_console_write,
+ .device = uart_console_device,
+ .setup = mcf_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &mcf_driver,
+};
+
+static int __init mcf_console_init(void)
+{
+ register_console(&mcf_console);
+ return 0;
+}
+
+console_initcall(mcf_console_init);
+
+#define MCF_CONSOLE &mcf_console
+
+/****************************************************************************/
+#else
+/****************************************************************************/
+
+#define MCF_CONSOLE NULL
+
+/****************************************************************************/
+#endif /* CONFIG_MCF_CONSOLE */
+/****************************************************************************/
+
+/*
+ * Define the mcf UART driver structure.
+ */
+static struct uart_driver mcf_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "mcf",
+ .dev_name = "ttyS",
+ .major = TTY_MAJOR,
+ .minor = 64,
+ .nr = MCF_MAXPORTS,
+ .cons = MCF_CONSOLE,
+};
+
+/****************************************************************************/
+
+static int __devinit mcf_probe(struct platform_device *pdev)
+{
+ struct mcf_platform_uart *platp = pdev->dev.platform_data;
+ struct uart_port *port;
+ int i;
+
+ for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
+ port = &mcf_ports[i].port;
+
+ port->line = i;
+ port->type = PORT_MCF;
+ port->mapbase = platp[i].mapbase;
+ port->membase = (platp[i].membase) ? platp[i].membase :
+ (unsigned char __iomem *) platp[i].mapbase;
+ port->iotype = SERIAL_IO_MEM;
+ port->irq = platp[i].irq;
+ port->uartclk = MCF_BUSCLK;
+ port->ops = &mcf_uart_ops;
+ port->flags = ASYNC_BOOT_AUTOCONF;
+
+ uart_add_one_port(&mcf_driver, port);
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+
+static int mcf_remove(struct platform_device *pdev)
+{
+ struct uart_port *port;
+ int i;
+
+ for (i = 0; (i < MCF_MAXPORTS); i++) {
+ port = &mcf_ports[i].port;
+ if (port)
+ uart_remove_one_port(&mcf_driver, port);
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+
+static struct platform_driver mcf_platform_driver = {
+ .probe = mcf_probe,
+ .remove = __devexit_p(mcf_remove),
+ .driver = {
+ .name = "mcfuart",
+ .owner = THIS_MODULE,
+ },
+};
+
+/****************************************************************************/
+
+static int __init mcf_init(void)
+{
+ int rc;
+
+ printk("ColdFire internal UART serial driver\n");
+
+ rc = uart_register_driver(&mcf_driver);
+ if (rc)
+ return rc;
+ rc = platform_driver_register(&mcf_platform_driver);
+ if (rc)
+ return rc;
+ return 0;
+}
+
+/****************************************************************************/
+
+static void __exit mcf_exit(void)
+{
+ platform_driver_unregister(&mcf_platform_driver);
+ uart_unregister_driver(&mcf_driver);
+}
+
+/****************************************************************************/
+
+module_init(mcf_init);
+module_exit(mcf_exit);
+
+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
+MODULE_DESCRIPTION("Freescale ColdFire UART driver");
+MODULE_LICENSE("GPL");
+
+/****************************************************************************/
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 35f8b86cc78..ec36ad78d2f 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -756,8 +756,8 @@ mpc52xx_console_setup(struct console *co, char *options)
if (port->membase == NULL)
return -EINVAL;
- pr_debug("mpc52xx-psc uart at %lx, mapped to %p, irq=%x, freq=%i\n",
- port->mapbase, port->membase, port->irq, port->uartclk);
+ pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n",
+ (void*)port->mapbase, port->membase, port->irq, port->uartclk);
/* Setup the port parameters accoding to options */
if (options)
@@ -974,8 +974,8 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
port->mapbase = res.start;
port->irq = irq_of_parse_and_map(op->node, 0);
- dev_dbg(&op->dev, "mpc52xx-psc uart at %lx, irq=%x, freq=%i\n",
- port->mapbase, port->irq, port->uartclk);
+ dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
+ (void*)port->mapbase, port->irq, port->uartclk);
if ((port->irq==NO_IRQ) || !port->mapbase) {
printk(KERN_ERR "Could not allocate resources for PSC\n");
@@ -1051,7 +1051,7 @@ mpc52xx_uart_of_assign(struct device_node *np, int idx)
/* If the slot is already occupied, then swap slots */
if (mpc52xx_uart_nodes[idx] && (free_idx != -1))
mpc52xx_uart_nodes[free_idx] = mpc52xx_uart_nodes[idx];
- mpc52xx_uart_nodes[i] = np;
+ mpc52xx_uart_nodes[idx] = np;
}
static void
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 0fa9f676176..794bd0f50d7 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -88,6 +88,16 @@ MODULE_LICENSE("GPL");
#define PWRDBG(fmt, arg...) printk(KERN_DEBUG fmt , ## arg)
+#ifdef CONFIG_SERIAL_PMACZILOG_TTYS
+#define PMACZILOG_MAJOR TTY_MAJOR
+#define PMACZILOG_MINOR 64
+#define PMACZILOG_NAME "ttyS"
+#else
+#define PMACZILOG_MAJOR 204
+#define PMACZILOG_MINOR 192
+#define PMACZILOG_NAME "ttyPZ"
+#endif
+
/*
* For the sake of early serial console, we can do a pre-probe
@@ -99,9 +109,10 @@ static DEFINE_MUTEX(pmz_irq_mutex);
static struct uart_driver pmz_uart_reg = {
.owner = THIS_MODULE,
- .driver_name = "ttyS",
- .dev_name = "ttyS",
- .major = TTY_MAJOR,
+ .driver_name = PMACZILOG_NAME,
+ .dev_name = PMACZILOG_NAME,
+ .major = PMACZILOG_MAJOR,
+ .minor = PMACZILOG_MINOR,
};
@@ -1587,7 +1598,7 @@ static int pmz_suspend(struct macio_dev *mdev, pm_message_t pm_state)
if (pm_state.event == mdev->ofdev.dev.power.power_state.event)
return 0;
- pmz_debug("suspend, switching to state %d\n", pm_state);
+ pmz_debug("suspend, switching to state %d\n", pm_state.event);
state = pmz_uart_reg.state + uap->port.line;
@@ -1778,7 +1789,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c
static int __init pmz_console_setup(struct console *co, char *options);
static struct console pmz_console = {
- .name = "ttyS",
+ .name = PMACZILOG_NAME,
.write = pmz_console_write,
.device = uart_console_device,
.setup = pmz_console_setup,
@@ -1802,7 +1813,6 @@ static int __init pmz_register(void)
pmz_uart_reg.nr = pmz_ports_count;
pmz_uart_reg.cons = PMACZILOG_CONSOLE;
- pmz_uart_reg.minor = 64;
/*
* Register this driver with the serial core
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index e9c6cb391a2..af3a011b2b2 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -42,6 +42,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
+#include <linux/clk.h>
#include <asm/io.h>
#include <asm/hardware.h>
@@ -55,7 +56,7 @@ struct uart_pxa_port {
unsigned char lcr;
unsigned char mcr;
unsigned int lsr_break_flag;
- unsigned int cken;
+ struct clk *clk;
char *name;
};
@@ -351,6 +352,8 @@ static int serial_pxa_startup(struct uart_port *port)
else
up->mcr = 0;
+ up->port.uartclk = clk_get_rate(up->clk);
+
/*
* Allocate the IRQ
*/
@@ -546,9 +549,11 @@ serial_pxa_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- pxa_set_cken(up->cken, !state);
+
if (!state)
- udelay(1);
+ clk_enable(up->clk);
+ else
+ clk_disable(up->clk);
}
static void serial_pxa_release_port(struct uart_port *port)
@@ -582,7 +587,7 @@ serial_pxa_type(struct uart_port *port)
#ifdef CONFIG_SERIAL_PXA_CONSOLE
-static struct uart_pxa_port serial_pxa_ports[];
+static struct uart_pxa_port *serial_pxa_ports[4];
static struct uart_driver serial_pxa_reg;
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
@@ -632,9 +637,11 @@ static void serial_pxa_console_putchar(struct uart_port *port, int ch)
static void
serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
{
- struct uart_pxa_port *up = &serial_pxa_ports[co->index];
+ struct uart_pxa_port *up = serial_pxa_ports[co->index];
unsigned int ier;
+ clk_enable(up->clk);
+
/*
* First save the IER then disable the interrupts
*/
@@ -649,6 +656,8 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
*/
wait_for_xmitr(up);
serial_out(up, UART_IER, ier);
+
+ clk_disable(up->clk);
}
static int __init
@@ -662,7 +671,9 @@ serial_pxa_console_setup(struct console *co, char *options)
if (co->index == -1 || co->index >= serial_pxa_reg.nr)
co->index = 0;
- up = &serial_pxa_ports[co->index];
+ up = serial_pxa_ports[co->index];
+ if (!up)
+ return -ENODEV;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -680,15 +691,6 @@ static struct console serial_pxa_console = {
.data = &serial_pxa_reg,
};
-static int __init
-serial_pxa_console_init(void)
-{
- register_console(&serial_pxa_console);
- return 0;
-}
-
-console_initcall(serial_pxa_console_init);
-
#define PXA_CONSOLE &serial_pxa_console
#else
#define PXA_CONSOLE NULL
@@ -714,73 +716,13 @@ struct uart_ops serial_pxa_pops = {
.verify_port = serial_pxa_verify_port,
};
-static struct uart_pxa_port serial_pxa_ports[] = {
- { /* FFUART */
- .name = "FFUART",
- .cken = CKEN_FFUART,
- .port = {
- .type = PORT_PXA,
- .iotype = UPIO_MEM,
- .membase = (void *)&FFUART,
- .mapbase = __PREG(FFUART),
- .irq = IRQ_FFUART,
- .uartclk = 921600 * 16,
- .fifosize = 64,
- .ops = &serial_pxa_pops,
- .line = 0,
- },
- }, { /* BTUART */
- .name = "BTUART",
- .cken = CKEN_BTUART,
- .port = {
- .type = PORT_PXA,
- .iotype = UPIO_MEM,
- .membase = (void *)&BTUART,
- .mapbase = __PREG(BTUART),
- .irq = IRQ_BTUART,
- .uartclk = 921600 * 16,
- .fifosize = 64,
- .ops = &serial_pxa_pops,
- .line = 1,
- },
- }, { /* STUART */
- .name = "STUART",
- .cken = CKEN_STUART,
- .port = {
- .type = PORT_PXA,
- .iotype = UPIO_MEM,
- .membase = (void *)&STUART,
- .mapbase = __PREG(STUART),
- .irq = IRQ_STUART,
- .uartclk = 921600 * 16,
- .fifosize = 64,
- .ops = &serial_pxa_pops,
- .line = 2,
- },
- }, { /* HWUART */
- .name = "HWUART",
- .cken = CKEN_HWUART,
- .port = {
- .type = PORT_PXA,
- .iotype = UPIO_MEM,
- .membase = (void *)&HWUART,
- .mapbase = __PREG(HWUART),
- .irq = IRQ_HWUART,
- .uartclk = 921600 * 16,
- .fifosize = 64,
- .ops = &serial_pxa_pops,
- .line = 3,
- },
- }
-};
-
static struct uart_driver serial_pxa_reg = {
.owner = THIS_MODULE,
.driver_name = "PXA serial",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
- .nr = ARRAY_SIZE(serial_pxa_ports),
+ .nr = 4,
.cons = PXA_CONSOLE,
};
@@ -806,10 +748,68 @@ static int serial_pxa_resume(struct platform_device *dev)
static int serial_pxa_probe(struct platform_device *dev)
{
- serial_pxa_ports[dev->id].port.dev = &dev->dev;
- uart_add_one_port(&serial_pxa_reg, &serial_pxa_ports[dev->id].port);
- platform_set_drvdata(dev, &serial_pxa_ports[dev->id]);
+ struct uart_pxa_port *sport;
+ struct resource *mmres, *irqres;
+ int ret;
+
+ mmres = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0);
+ if (!mmres || !irqres)
+ return -ENODEV;
+
+ sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL);
+ if (!sport)
+ return -ENOMEM;
+
+ sport->clk = clk_get(&dev->dev, "UARTCLK");
+ if (IS_ERR(sport->clk)) {
+ ret = PTR_ERR(sport->clk);
+ goto err_free;
+ }
+
+ sport->port.type = PORT_PXA;
+ sport->port.iotype = UPIO_MEM;
+ sport->port.mapbase = mmres->start;
+ sport->port.irq = irqres->start;
+ sport->port.fifosize = 64;
+ sport->port.ops = &serial_pxa_pops;
+ sport->port.line = dev->id;
+ sport->port.dev = &dev->dev;
+ sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
+ sport->port.uartclk = clk_get_rate(sport->clk);
+
+ /*
+ * Is it worth keeping this?
+ */
+ if (mmres->start == __PREG(FFUART))
+ sport->name = "FFUART";
+ else if (mmres->start == __PREG(BTUART))
+ sport->name = "BTUART";
+ else if (mmres->start == __PREG(STUART))
+ sport->name = "STUART";
+ else if (mmres->start == __PREG(HWUART))
+ sport->name = "HWUART";
+ else
+ sport->name = "???";
+
+ sport->port.membase = ioremap(mmres->start, mmres->end - mmres->start + 1);
+ if (!sport->port.membase) {
+ ret = -ENOMEM;
+ goto err_clk;
+ }
+
+ serial_pxa_ports[dev->id] = sport;
+
+ uart_add_one_port(&serial_pxa_reg, &sport->port);
+ platform_set_drvdata(dev, sport);
+
return 0;
+
+ err_clk:
+ clk_put(sport->clk);
+ err_free:
+ kfree(sport);
+ return ret;
}
static int serial_pxa_remove(struct platform_device *dev)
@@ -818,8 +818,9 @@ static int serial_pxa_remove(struct platform_device *dev)
platform_set_drvdata(dev, NULL);
- if (sport)
- uart_remove_one_port(&serial_pxa_reg, &sport->port);
+ uart_remove_one_port(&serial_pxa_reg, &sport->port);
+ clk_put(sport->clk);
+ kfree(sport);
return 0;
}
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 3f26c4b2f32..e773c8e1496 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -20,8 +20,8 @@
* - S3C2410 and S3C2440 serial support
* - Power Management support
* - Fix console via IrDA devices
- * - SysReq (Herbert Pötzl)
- * - Break character handling (Herbert Pötzl)
+ * - SysReq (Herbert Pötzl)
+ * - Break character handling (Herbert Pötzl)
* - spin-lock initialisation (Dimitry Andric)
* - added clock control
* - updated init code to use platform_device info
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index a055f58f342..3bb5d241dd4 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1875,6 +1875,7 @@ uart_set_options(struct uart_port *port, struct console *co,
int baud, int parity, int bits, int flow)
{
struct ktermios termios;
+ static struct ktermios dummy;
int i;
/*
@@ -1920,7 +1921,7 @@ uart_set_options(struct uart_port *port, struct console *co,
*/
port->mctrl |= TIOCM_DTR;
- port->ops->set_termios(port, &termios, NULL);
+ port->ops->set_termios(port, &termios, &dummy);
co->cflag = termios.c_cflag;
return 0;
@@ -1938,18 +1939,41 @@ static void uart_change_pm(struct uart_state *state, int pm_state)
}
}
+struct uart_match {
+ struct uart_port *port;
+ struct uart_driver *driver;
+};
+
+static int serial_match_port(struct device *dev, void *data)
+{
+ struct uart_match *match = data;
+ dev_t devt = MKDEV(match->driver->major, match->driver->minor) + match->port->line;
+
+ return dev->devt == devt; /* Actually, only one tty per port */
+}
+
int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
{
struct uart_state *state = drv->state + port->line;
+ struct device *tty_dev;
+ struct uart_match match = {port, drv};
mutex_lock(&state->mutex);
-#ifdef CONFIG_DISABLE_CONSOLE_SUSPEND
- if (uart_console(port)) {
+ if (!console_suspend_enabled && uart_console(port)) {
+ /* we're going to avoid suspending serial console */
mutex_unlock(&state->mutex);
return 0;
}
-#endif
+
+ tty_dev = device_find_child(port->dev, &match, serial_match_port);
+ if (device_may_wakeup(tty_dev)) {
+ enable_irq_wake(port->irq);
+ put_device(tty_dev);
+ mutex_unlock(&state->mutex);
+ return 0;
+ }
+ port->suspended = 1;
if (state->info && state->info->flags & UIF_INITIALIZED) {
const struct uart_ops *ops = port->ops;
@@ -1992,12 +2016,18 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
mutex_lock(&state->mutex);
-#ifdef CONFIG_DISABLE_CONSOLE_SUSPEND
- if (uart_console(port)) {
+ if (!console_suspend_enabled && uart_console(port)) {
+ /* no need to resume serial console, it wasn't suspended */
mutex_unlock(&state->mutex);
return 0;
}
-#endif
+
+ if (!port->suspended) {
+ disable_irq_wake(port->irq);
+ mutex_unlock(&state->mutex);
+ return 0;
+ }
+ port->suspended = 0;
uart_change_pm(state, 0);
@@ -2127,6 +2157,14 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
spin_unlock_irqrestore(&port->lock, flags);
/*
+ * If this driver supports console, and it hasn't been
+ * successfully registered yet, try to re-register it.
+ * It may be that the port was not available.
+ */
+ if (port->cons && !(port->cons->flags & CON_ENABLED))
+ register_console(port->cons);
+
+ /*
* Power down all ports by default, except the
* console if we have one.
*/
@@ -2270,6 +2308,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
{
struct uart_state *state;
int ret = 0;
+ struct device *tty_dev;
BUG_ON(in_interrupt());
@@ -2286,6 +2325,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
}
state->port = port;
+ state->pm_state = -1;
port->cons = drv->cons;
port->info = state->info;
@@ -2305,16 +2345,13 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this ports parameters.
*/
- tty_register_device(drv->tty_driver, port->line, port->dev);
-
- /*
- * If this driver supports console, and it hasn't been
- * successfully registered yet, try to re-register it.
- * It may be that the port was not available.
- */
- if (port->type != PORT_UNKNOWN &&
- port->cons && !(port->cons->flags & CON_ENABLED))
- register_console(port->cons);
+ tty_dev = tty_register_device(drv->tty_driver, port->line, port->dev);
+ if (likely(!IS_ERR(tty_dev))) {
+ device_can_wakeup(tty_dev) = 1;
+ device_set_wakeup_enable(tty_dev, 0);
+ } else
+ printk(KERN_ERR "Cannot register tty device on line %d\n",
+ port->line);
/*
* Ensure UPF_DEAD is not set.
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 7c8d78fbbbf..d8b660061c1 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -345,7 +345,7 @@ static int serial_probe(struct pcmcia_device *link)
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts1 = 8;
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->conf.Attributes = CONF_ENABLE_IRQ;
if (do_sound) {
@@ -911,6 +911,7 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"),
PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "3CXEM556.cis"),
PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "3CXEM556.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */
PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0x0710, "SW_7xx_SER.cis"), /* Sierra Wireless AC710/AC750 GPRS Network Adapter R1 */
PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */
PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index 0930e2a8551..7ad21925869 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -25,19 +25,15 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
-#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
-#include <linux/mutex.h>
#include <asm/io.h>
-static char *serial_version = "1.10";
+static char *serial_version = "1.11";
static char *serial_name = "TX39/49 Serial driver";
#define PASS_LIMIT 256
@@ -68,8 +64,6 @@ static char *serial_name = "TX39/49 Serial driver";
*/
#define UART_NR CONFIG_SERIAL_TXX9_NR_UARTS
-#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
-
struct uart_txx9_port {
struct uart_port port;
/* No additional info for now */
@@ -663,7 +657,15 @@ static void
serial_txx9_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
- if (state == 0)
+ /*
+ * If oldstate was -1 this is called from
+ * uart_configure_port(). In this case do not initialize the
+ * port now, because the port was already initialized (for
+ * non-console port) or should not be initialized here (for
+ * console port). If we initialized the port here we lose
+ * serial console settings.
+ */
+ if (state == 0 && oldstate != -1)
serial_txx9_initialize(port);
}
@@ -756,21 +758,6 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags)
serial_txx9_initialize(port);
}
-static int
-serial_txx9_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
- unsigned long new_port = ser->port;
- if (HIGH_BITS_OFFSET)
- new_port += (unsigned long)ser->port_high << HIGH_BITS_OFFSET;
- if (ser->type != port->type ||
- ser->irq != port->irq ||
- ser->io_type != port->iotype ||
- new_port != port->iobase ||
- (unsigned long)ser->iomem_base != port->mapbase)
- return -EINVAL;
- return 0;
-}
-
static const char *
serial_txx9_type(struct uart_port *port)
{
@@ -794,7 +781,6 @@ static struct uart_ops serial_txx9_pops = {
.release_port = serial_txx9_release_port,
.request_port = serial_txx9_request_port,
.config_port = serial_txx9_config_port,
- .verify_port = serial_txx9_verify_port,
};
static struct uart_txx9_port serial_txx9_ports[UART_NR];
@@ -950,7 +936,8 @@ int __init early_serial_txx9_setup(struct uart_port *port)
serial_txx9_ports[port->line].port = *port;
serial_txx9_ports[port->line].port.ops = &serial_txx9_pops;
- serial_txx9_ports[port->line].port.flags |= UPF_BOOT_AUTOCONF;
+ serial_txx9_ports[port->line].port.flags |=
+ UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
return 0;
}
@@ -995,7 +982,8 @@ static int __devinit serial_txx9_register_port(struct uart_port *port)
uart->port.irq = port->irq;
uart->port.uartclk = port->uartclk;
uart->port.iotype = port->iotype;
- uart->port.flags = port->flags | UPF_BOOT_AUTOCONF;
+ uart->port.flags = port->flags
+ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
uart->port.mapbase = port->mapbase;
if (port->dev)
uart->port.dev = port->dev;
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 053fca41b08..73440e26834 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -4,6 +4,7 @@
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
*
* Copyright (C) 2002 - 2006 Paul Mundt
+ * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Jul 2007).
*
* based off of the old drivers/char/sh-sci.c by:
*
@@ -301,6 +302,38 @@ static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag)
}
sci_out(port, SCFCR, fcr_val);
}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
+static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+{
+ unsigned int fcr_val = 0;
+ unsigned short data;
+
+ if (cflag & CRTSCTS) {
+ /* enable RTS/CTS */
+ if (port->mapbase == 0xa4430000) { /* SCIF0 */
+ /* Clear PTCR bit 9-2; enable all scif pins but sck */
+ data = ctrl_inw(PORT_PTCR);
+ ctrl_outw((data & 0xfc03), PORT_PTCR);
+ } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+ /* Clear PVCR bit 9-2 */
+ data = ctrl_inw(PORT_PVCR);
+ ctrl_outw((data & 0xfc03), PORT_PVCR);
+ }
+ fcr_val |= SCFCR_MCE;
+ } else {
+ if (port->mapbase == 0xa4430000) { /* SCIF0 */
+ /* Clear PTCR bit 5-2; enable only tx and rx */
+ data = ctrl_inw(PORT_PTCR);
+ ctrl_outw((data & 0xffc3), PORT_PTCR);
+ } else if (port->mapbase == 0xa4438000) { /* SCIF1 */
+ /* Clear PVCR bit 5-2 */
+ data = ctrl_inw(PORT_PVCR);
+ ctrl_outw((data & 0xffc3), PORT_PVCR);
+ }
+ }
+ sci_out(port, SCFCR, fcr_val);
+}
+
#elif defined(CONFIG_CPU_SH3)
/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
@@ -1276,7 +1309,7 @@ static int __init sci_console_init(void)
console_initcall(sci_console_init);
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
-#ifdef CONFIG_SH_KGDB
+#ifdef CONFIG_SH_KGDB_CONSOLE
/*
* FIXME: Most of this can go away.. at the moment, we rely on
* arch/sh/kernel/setup.c to do the command line parsing for kgdb, though
@@ -1334,9 +1367,7 @@ int __init kgdb_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
-#endif /* CONFIG_SH_KGDB */
-#ifdef CONFIG_SH_KGDB_CONSOLE
static struct console kgdb_console = {
.name = "ttySC",
.device = uart_console_device,
@@ -1432,7 +1463,7 @@ static int __devinit sci_probe(struct platform_device *dev)
#ifdef CONFIG_CPU_FREQ
cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
- dev_info(&dev->dev, "sci: CPU frequency notifier registered\n");
+ dev_info(&dev->dev, "CPU frequency notifier registered\n");
#endif
#ifdef CONFIG_SH_STANDARD_BIOS
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index cf75466ebf5..d24621ce799 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -10,19 +10,19 @@
* Modified to support SH7300(SH-Mobile) SCIF. Takashi Kusuda (Jun 2003).
* Modified to support H8/300 Series Yoshinori Sato (Feb 2004).
* Removed SH7300 support (Jul 2007).
+ * Modified to support SH7720 SCIF. Markus Brunner, Mark Jonas (Aug 2007).
*/
#include <linux/serial_core.h>
#include <asm/io.h>
-#if defined(__H8300H__) || defined(__H8300S__)
#include <asm/gpio.h>
+
#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
#include <asm/regs306x.h>
#endif
#if defined(CONFIG_H8S2678)
#include <asm/regs267x.h>
#endif
-#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7707) || \
@@ -46,6 +46,10 @@
*/
# define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0
# define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
+# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCIF_ONLY
+#define SCIF_ORER 0x0200 /* overrun error bit */
#elif defined(CONFIG_SH_RTS7751R2D)
# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
@@ -73,7 +77,6 @@
# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
# define SCSPTR0 0xA4400000 /* 16 bit SCIF */
-# define SCI_NPORTS 2
# define SCIF_ORER 0x0001 /* overrun error bit */
# define PACR 0xa4050100
# define PBCR 0xa4050102
@@ -98,12 +101,6 @@
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
-# define SCSPTR1 0xffe00020 /* 16 bit SCIF */
-# 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 */
-# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
# include <asm/hardware.h>
# define SCIF_BASE_ADDR 0x01030000
@@ -112,8 +109,7 @@
# 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 */
+# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0, TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
@@ -217,7 +213,8 @@
#define SCIF_RDF 0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
#define SCIF_DR 0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
#define SCIF_ORER 0x0200
#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
#define SCIF_RFDC_MASK 0x007f
@@ -254,7 +251,8 @@
# define SCxSR_FER(port) SCIF_FER
# define SCxSR_PER(port) SCIF_PER
# define SCxSR_BRK(port) SCIF_BRK
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
# define SCxSR_RDxF_CLEAR(port) (sci_in(port,SCxSR)&0xfffc)
# define SCxSR_ERROR_CLEAR(port) (sci_in(port,SCxSR)&0xfd73)
# define SCxSR_TDxE_CLEAR(port) (sci_in(port,SCxSR)&0xffdf)
@@ -362,7 +360,8 @@
CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
#define SCIF_FNS(name, scif_offset, scif_size) \
CPU_SCIF_FNS(name, scif_offset, scif_size)
#else
@@ -388,7 +387,8 @@
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
SCIF_FNS(SCSMR, 0x00, 16)
SCIF_FNS(SCBRR, 0x04, 8)
@@ -510,7 +510,15 @@ static inline void set_sh771x_scif_pfc(struct uart_port *port)
return;
}
}
-
+#elif defined(CONFIG_CPU_SUBTYPE_SH7720)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+ if (port->mapbase == 0xa4430000)
+ return sci_in(port, SCxSR) & 0x0003 ? 1 : 0;
+ else if (port->mapbase == 0xa4438000)
+ return sci_in(port, SCxSR) & 0x0003 ? 1 : 0;
+ return 1;
+}
#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
defined(CONFIG_CPU_SUBTYPE_SH7751) || \
defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
@@ -561,15 +569,6 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inb(SCPDR0) & 0x0001 ? 1 : 0; /* SCIF0 */
return 1;
}
-#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
-static inline int sci_rxd_in(struct uart_port *port)
-{
- if (port->mapbase == 0xffe00000)
- return ctrl_inw(SCSPTR1)&0x0001 ? 1 : 0; /* SCIF */
- else
- return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
-
-}
#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
static inline int sci_rxd_in(struct uart_port *port)
{
@@ -653,6 +652,7 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
if (port->mapbase == 0xffc60000)
return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+ return 1;
}
#endif
@@ -691,7 +691,8 @@ static inline int sci_rxd_in(struct uart_port *port)
#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \
defined(CONFIG_CPU_SUBTYPE_SH7785)
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7720)
#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
#elif defined(__H8300H__) || defined(__H8300S__)
#define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1)
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index f5051cf1a0c..a85f2d31a68 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -1,7 +1,8 @@
/*
* uartlite.c: Serial driver for Xilinx uartlite serial controller
*
- * Peter Korsgaard <jacmet@sunsite.dk>
+ * Copyright (C) 2006 Peter Korsgaard <jacmet@sunsite.dk>
+ * Copyright (C) 2007 Secret Lab Technologies Ltd.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
@@ -17,14 +18,23 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <asm/io.h>
+#if defined(CONFIG_OF)
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#endif
+#define ULITE_NAME "ttyUL"
#define ULITE_MAJOR 204
#define ULITE_MINOR 187
#define ULITE_NR_UARTS 4
-/* For register details see datasheet:
- http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
-*/
+/* ---------------------------------------------------------------------
+ * Register definitions
+ *
+ * For register details see datasheet:
+ * http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
+ */
+
#define ULITE_RX 0x00
#define ULITE_TX 0x04
#define ULITE_STATUS 0x08
@@ -46,7 +56,11 @@
#define ULITE_CONTROL_IE 0x10
-static struct uart_port ports[ULITE_NR_UARTS];
+static struct uart_port ulite_ports[ULITE_NR_UARTS];
+
+/* ---------------------------------------------------------------------
+ * Core UART driver operations
+ */
static int ulite_receive(struct uart_port *port, int stat)
{
@@ -307,16 +321,22 @@ static struct uart_ops ulite_ops = {
.verify_port = ulite_verify_port
};
+/* ---------------------------------------------------------------------
+ * Console driver operations
+ */
+
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
static void ulite_console_wait_tx(struct uart_port *port)
{
int i;
+ u8 val;
- /* wait up to 10ms for the character(s) to be sent */
- for (i = 0; i < 10000; i++) {
- if (readb(port->membase + ULITE_STATUS) & ULITE_STATUS_TXEMPTY)
+ /* Spin waiting for TX fifo to have space available */
+ for (i = 0; i < 100000; i++) {
+ val = readb(port->membase + ULITE_STATUS);
+ if ((val & ULITE_STATUS_TXFULL) == 0)
break;
- udelay(1);
+ cpu_relax();
}
}
@@ -329,7 +349,7 @@ static void ulite_console_putchar(struct uart_port *port, int ch)
static void ulite_console_write(struct console *co, const char *s,
unsigned int count)
{
- struct uart_port *port = &ports[co->index];
+ struct uart_port *port = &ulite_ports[co->index];
unsigned long flags;
unsigned int ier;
int locked = 1;
@@ -355,6 +375,31 @@ static void ulite_console_write(struct console *co, const char *s,
spin_unlock_irqrestore(&port->lock, flags);
}
+#if defined(CONFIG_OF)
+static inline void __init ulite_console_of_find_device(int id)
+{
+ struct device_node *np;
+ struct resource res;
+ const unsigned int *of_id;
+ int rc;
+
+ for_each_compatible_node(np, NULL, "xilinx,uartlite") {
+ of_id = of_get_property(np, "port-number", NULL);
+ if ((!of_id) || (*of_id != id))
+ continue;
+
+ rc = of_address_to_resource(np, 0, &res);
+ if (rc)
+ continue;
+
+ ulite_ports[id].mapbase = res.start;
+ return;
+ }
+}
+#else /* CONFIG_OF */
+static inline void __init ulite_console_of_find_device(int id) { /* do nothing */ }
+#endif /* CONFIG_OF */
+
static int __init ulite_console_setup(struct console *co, char *options)
{
struct uart_port *port;
@@ -366,11 +411,23 @@ static int __init ulite_console_setup(struct console *co, char *options)
if (co->index < 0 || co->index >= ULITE_NR_UARTS)
return -EINVAL;
- port = &ports[co->index];
+ port = &ulite_ports[co->index];
- /* not initialized yet? */
- if (!port->membase)
+ /* Check if it is an OF device */
+ if (!port->mapbase)
+ ulite_console_of_find_device(co->index);
+
+ /* Do we have a device now? */
+ if (!port->mapbase) {
+ pr_debug("console on ttyUL%i not present\n", co->index);
return -ENODEV;
+ }
+
+ /* not initialized yet? */
+ if (!port->membase) {
+ if (ulite_request_port(port))
+ return -ENODEV;
+ }
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -381,7 +438,7 @@ static int __init ulite_console_setup(struct console *co, char *options)
static struct uart_driver ulite_uart_driver;
static struct console ulite_console = {
- .name = "ttyUL",
+ .name = ULITE_NAME,
.write = ulite_console_write,
.device = uart_console_device,
.setup = ulite_console_setup,
@@ -403,7 +460,7 @@ console_initcall(ulite_console_init);
static struct uart_driver ulite_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "uartlite",
- .dev_name = "ttyUL",
+ .dev_name = ULITE_NAME,
.major = ULITE_MAJOR,
.minor = ULITE_MINOR,
.nr = ULITE_NR_UARTS,
@@ -412,59 +469,111 @@ static struct uart_driver ulite_uart_driver = {
#endif
};
-static int __devinit ulite_probe(struct platform_device *pdev)
+/* ---------------------------------------------------------------------
+ * Port assignment functions (mapping devices to uart_port structures)
+ */
+
+/** ulite_assign: register a uartlite device with the driver
+ *
+ * @dev: pointer to device structure
+ * @id: requested id number. Pass -1 for automatic port assignment
+ * @base: base address of uartlite registers
+ * @irq: irq number for uartlite
+ *
+ * Returns: 0 on success, <0 otherwise
+ */
+static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq)
{
- struct resource *res, *res2;
struct uart_port *port;
+ int rc;
- if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS)
+ /* if id = -1; then scan for a free id and use that */
+ if (id < 0) {
+ for (id = 0; id < ULITE_NR_UARTS; id++)
+ if (ulite_ports[id].mapbase == 0)
+ break;
+ }
+ if (id < 0 || id >= ULITE_NR_UARTS) {
+ dev_err(dev, "%s%i too large\n", ULITE_NAME, id);
return -EINVAL;
+ }
- if (ports[pdev->id].membase)
+ if ((ulite_ports[id].mapbase) && (ulite_ports[id].mapbase != base)) {
+ dev_err(dev, "cannot assign to %s%i; it is already in use\n",
+ ULITE_NAME, id);
return -EBUSY;
+ }
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
+ port = &ulite_ports[id];
- res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res2)
- return -ENODEV;
+ spin_lock_init(&port->lock);
+ port->fifosize = 16;
+ port->regshift = 2;
+ port->iotype = UPIO_MEM;
+ port->iobase = 1; /* mark port in use */
+ port->mapbase = base;
+ port->membase = NULL;
+ port->ops = &ulite_ops;
+ port->irq = irq;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->dev = dev;
+ port->type = PORT_UNKNOWN;
+ port->line = id;
+
+ dev_set_drvdata(dev, port);
+
+ /* Register the port */
+ rc = uart_add_one_port(&ulite_uart_driver, port);
+ if (rc) {
+ dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc);
+ port->mapbase = 0;
+ dev_set_drvdata(dev, NULL);
+ return rc;
+ }
- port = &ports[pdev->id];
+ return 0;
+}
- port->fifosize = 16;
- port->regshift = 2;
- port->iotype = UPIO_MEM;
- port->iobase = 1; /* mark port in use */
- port->mapbase = res->start;
- port->membase = NULL;
- port->ops = &ulite_ops;
- port->irq = res2->start;
- port->flags = UPF_BOOT_AUTOCONF;
- port->dev = &pdev->dev;
- port->type = PORT_UNKNOWN;
- port->line = pdev->id;
+/** ulite_release: register a uartlite device with the driver
+ *
+ * @dev: pointer to device structure
+ */
+static int __devinit ulite_release(struct device *dev)
+{
+ struct uart_port *port = dev_get_drvdata(dev);
+ int rc = 0;
- uart_add_one_port(&ulite_uart_driver, port);
- platform_set_drvdata(pdev, port);
+ if (port) {
+ rc = uart_remove_one_port(&ulite_uart_driver, port);
+ dev_set_drvdata(dev, NULL);
+ port->mapbase = 0;
+ }
- return 0;
+ return rc;
}
-static int ulite_remove(struct platform_device *pdev)
+/* ---------------------------------------------------------------------
+ * Platform bus binding
+ */
+
+static int __devinit ulite_probe(struct platform_device *pdev)
{
- struct uart_port *port = platform_get_drvdata(pdev);
+ struct resource *res, *res2;
- platform_set_drvdata(pdev, NULL);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
- if (port)
- uart_remove_one_port(&ulite_uart_driver, port);
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res2)
+ return -ENODEV;
- /* mark port as free */
- port->membase = NULL;
+ return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start);
+}
- return 0;
+static int ulite_remove(struct platform_device *pdev)
+{
+ return ulite_release(&pdev->dev);
}
static struct platform_driver ulite_platform_driver = {
@@ -476,24 +585,109 @@ static struct platform_driver ulite_platform_driver = {
},
};
+/* ---------------------------------------------------------------------
+ * OF bus bindings
+ */
+#if defined(CONFIG_OF)
+static int __devinit
+ulite_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct resource res;
+ const unsigned int *id;
+ int irq, rc;
+
+ dev_dbg(&op->dev, "%s(%p, %p)\n", __FUNCTION__, op, match);
+
+ rc = of_address_to_resource(op->node, 0, &res);
+ if (rc) {
+ dev_err(&op->dev, "invalid address\n");
+ return rc;
+ }
+
+ irq = irq_of_parse_and_map(op->node, 0);
+
+ id = of_get_property(op->node, "port-number", NULL);
+
+ return ulite_assign(&op->dev, id ? *id : -1, res.start+3, irq);
+}
+
+static int __devexit ulite_of_remove(struct of_device *op)
+{
+ return ulite_release(&op->dev);
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id __devinit ulite_of_match[] = {
+ { .type = "serial", .compatible = "xilinx,uartlite", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ulite_of_match);
+
+static struct of_platform_driver ulite_of_driver = {
+ .owner = THIS_MODULE,
+ .name = "uartlite",
+ .match_table = ulite_of_match,
+ .probe = ulite_of_probe,
+ .remove = __devexit_p(ulite_of_remove),
+ .driver = {
+ .name = "uartlite",
+ },
+};
+
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __init ulite_of_register(void)
+{
+ pr_debug("uartlite: calling of_register_platform_driver()\n");
+ return of_register_platform_driver(&ulite_of_driver);
+}
+
+static inline void __exit ulite_of_unregister(void)
+{
+ of_unregister_platform_driver(&ulite_of_driver);
+}
+#else /* CONFIG_OF */
+/* CONFIG_OF not enabled; do nothing helpers */
+static inline int __init ulite_of_register(void) { return 0; }
+static inline void __exit ulite_of_unregister(void) { }
+#endif /* CONFIG_OF */
+
+/* ---------------------------------------------------------------------
+ * Module setup/teardown
+ */
+
int __init ulite_init(void)
{
int ret;
+ pr_debug("uartlite: calling uart_register_driver()\n");
ret = uart_register_driver(&ulite_uart_driver);
if (ret)
- return ret;
+ goto err_uart;
+ ret = ulite_of_register();
+ if (ret)
+ goto err_of;
+
+ pr_debug("uartlite: calling platform_driver_register()\n");
ret = platform_driver_register(&ulite_platform_driver);
if (ret)
- uart_unregister_driver(&ulite_uart_driver);
+ goto err_plat;
+ return 0;
+
+err_plat:
+ ulite_of_unregister();
+err_of:
+ uart_unregister_driver(&ulite_uart_driver);
+err_uart:
+ printk(KERN_ERR "registering uartlite driver failed: err=%i", ret);
return ret;
}
void __exit ulite_exit(void)
{
platform_driver_unregister(&ulite_platform_driver);
+ ulite_of_unregister();
uart_unregister_driver(&ulite_uart_driver);
}
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
index 8a143894e33..a96f4a8cfeb 100644
--- a/drivers/sh/Makefile
+++ b/drivers/sh/Makefile
@@ -2,5 +2,5 @@
# Makefile for the SuperH specific drivers.
#
-obj-$(CONFIG_SUPERHYWAY) += superhyway/
-
+obj-$(CONFIG_SUPERHYWAY) += superhyway/
+obj-$(CONFIG_MAPLE) += maple/
diff --git a/drivers/sh/maple/Makefile b/drivers/sh/maple/Makefile
new file mode 100644
index 00000000000..65dfeeb610e
--- /dev/null
+++ b/drivers/sh/maple/Makefile
@@ -0,0 +1,3 @@
+# Makefile for Maple Bus
+
+obj-$(CONFIG_MAPLE) := maple.o
diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c
new file mode 100644
index 00000000000..e52a6296ca4
--- /dev/null
+++ b/drivers/sh/maple/maple.c
@@ -0,0 +1,734 @@
+/*
+ * Core maple bus functionality
+ *
+ * Copyright (C) 2007 Adrian McMenamin
+ *
+ * Based on 2.4 code by:
+ *
+ * Copyright (C) 2000-2001 YAEGASHI Takeshi
+ * Copyright (C) 2001 M. R. Brown
+ * Copyright (C) 2001 Paul Mundt
+ *
+ * and others.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/maple.h>
+#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/mach/dma.h>
+#include <asm/mach/sysasic.h>
+#include <asm/mach/maple.h>
+
+MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, M.R. Brown, Adrian McMenamin");
+MODULE_DESCRIPTION("Maple bus driver for Dreamcast");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{{SEGA, Dreamcast/Maple}}");
+
+static void maple_dma_handler(struct work_struct *work);
+static void maple_vblank_handler(struct work_struct *work);
+
+static DECLARE_WORK(maple_dma_process, maple_dma_handler);
+static DECLARE_WORK(maple_vblank_process, maple_vblank_handler);
+
+static LIST_HEAD(maple_waitq);
+static LIST_HEAD(maple_sentq);
+
+static DEFINE_MUTEX(maple_list_lock);
+
+static struct maple_driver maple_dummy_driver;
+static struct device maple_bus;
+static int subdevice_map[MAPLE_PORTS];
+static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr;
+static unsigned long maple_pnp_time;
+static int started, scanning, liststatus;
+static struct kmem_cache *maple_queue_cache;
+
+struct maple_device_specify {
+ int port;
+ int unit;
+};
+
+/**
+ * maple_driver_register - register a device driver
+ * automatically makes the driver bus a maple bus
+ * @drv: the driver to be registered
+ */
+int maple_driver_register(struct device_driver *drv)
+{
+ if (!drv)
+ return -EINVAL;
+ drv->bus = &maple_bus_type;
+ return driver_register(drv);
+}
+EXPORT_SYMBOL_GPL(maple_driver_register);
+
+/* set hardware registers to enable next round of dma */
+static void maplebus_dma_reset(void)
+{
+ ctrl_outl(MAPLE_MAGIC, MAPLE_RESET);
+ /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */
+ ctrl_outl(1, MAPLE_TRIGTYPE);
+ ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED);
+ ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR);
+ ctrl_outl(1, MAPLE_ENABLE);
+}
+
+/**
+ * maple_getcond_callback - setup handling MAPLE_COMMAND_GETCOND
+ * @dev: device responding
+ * @callback: handler callback
+ * @interval: interval in jiffies between callbacks
+ * @function: the function code for the device
+ */
+void maple_getcond_callback(struct maple_device *dev,
+ void (*callback) (struct mapleq * mq),
+ unsigned long interval, unsigned long function)
+{
+ dev->callback = callback;
+ dev->interval = interval;
+ dev->function = cpu_to_be32(function);
+ dev->when = jiffies;
+}
+EXPORT_SYMBOL_GPL(maple_getcond_callback);
+
+static int maple_dma_done(void)
+{
+ return (ctrl_inl(MAPLE_STATE) & 1) == 0;
+}
+
+static void maple_release_device(struct device *dev)
+{
+ if (dev->type) {
+ kfree(dev->type->name);
+ kfree(dev->type);
+ }
+}
+
+/**
+ * maple_add_packet - add a single instruction to the queue
+ * @mq: instruction to add to waiting queue
+ */
+void maple_add_packet(struct mapleq *mq)
+{
+ mutex_lock(&maple_list_lock);
+ list_add(&mq->list, &maple_waitq);
+ mutex_unlock(&maple_list_lock);
+}
+EXPORT_SYMBOL_GPL(maple_add_packet);
+
+static struct mapleq *maple_allocq(struct maple_device *dev)
+{
+ struct mapleq *mq;
+
+ mq = kmalloc(sizeof(*mq), GFP_KERNEL);
+ if (!mq)
+ return NULL;
+
+ mq->dev = dev;
+ mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL);
+ mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp);
+ if (!mq->recvbuf) {
+ kfree(mq);
+ return NULL;
+ }
+
+ return mq;
+}
+
+static struct maple_device *maple_alloc_dev(int port, int unit)
+{
+ struct maple_device *dev;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ dev->port = port;
+ dev->unit = unit;
+ dev->mq = maple_allocq(dev);
+
+ if (!dev->mq) {
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+static void maple_free_dev(struct maple_device *mdev)
+{
+ if (!mdev)
+ return;
+ if (mdev->mq) {
+ kmem_cache_free(maple_queue_cache, mdev->mq->recvbufdcsp);
+ kfree(mdev->mq);
+ }
+ kfree(mdev);
+}
+
+/* process the command queue into a maple command block
+ * terminating command has bit 32 of first long set to 0
+ */
+static void maple_build_block(struct mapleq *mq)
+{
+ int port, unit, from, to, len;
+ unsigned long *lsendbuf = mq->sendbuf;
+
+ port = mq->dev->port & 3;
+ unit = mq->dev->unit;
+ len = mq->length;
+ from = port << 6;
+ to = (port << 6) | (unit > 0 ? (1 << (unit - 1)) & 0x1f : 0x20);
+
+ *maple_lastptr &= 0x7fffffff;
+ maple_lastptr = maple_sendptr;
+
+ *maple_sendptr++ = (port << 16) | len | 0x80000000;
+ *maple_sendptr++ = PHYSADDR(mq->recvbuf);
+ *maple_sendptr++ =
+ mq->command | (to << 8) | (from << 16) | (len << 24);
+
+ while (len-- > 0)
+ *maple_sendptr++ = *lsendbuf++;
+}
+
+/* build up command queue */
+static void maple_send(void)
+{
+ int i;
+ int maple_packets;
+ struct mapleq *mq, *nmq;
+
+ if (!list_empty(&maple_sentq))
+ return;
+ if (list_empty(&maple_waitq) || !maple_dma_done())
+ return;
+ maple_packets = 0;
+ maple_sendptr = maple_lastptr = maple_sendbuf;
+ list_for_each_entry_safe(mq, nmq, &maple_waitq, list) {
+ maple_build_block(mq);
+ list_move(&mq->list, &maple_sentq);
+ if (maple_packets++ > MAPLE_MAXPACKETS)
+ break;
+ }
+ if (maple_packets > 0) {
+ for (i = 0; i < (1 << MAPLE_DMA_PAGES); i++)
+ dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ }
+}
+
+static int attach_matching_maple_driver(struct device_driver *driver,
+ void *devptr)
+{
+ struct maple_driver *maple_drv;
+ struct maple_device *mdev;
+
+ mdev = devptr;
+ maple_drv = to_maple_driver(driver);
+ if (mdev->devinfo.function & be32_to_cpu(maple_drv->function)) {
+ if (maple_drv->connect(mdev) == 0) {
+ mdev->driver = maple_drv;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void maple_detach_driver(struct maple_device *mdev)
+{
+ if (!mdev)
+ return;
+ if (mdev->driver) {
+ if (mdev->driver->disconnect)
+ mdev->driver->disconnect(mdev);
+ }
+ mdev->driver = NULL;
+ if (mdev->registered) {
+ maple_release_device(&mdev->dev);
+ device_unregister(&mdev->dev);
+ }
+ mdev->registered = 0;
+ maple_free_dev(mdev);
+}
+
+/* process initial MAPLE_COMMAND_DEVINFO for each device or port */
+static void maple_attach_driver(struct maple_device *dev)
+{
+ char *p;
+
+ char *recvbuf;
+ unsigned long function;
+ int matched, retval;
+
+ recvbuf = dev->mq->recvbuf;
+ memcpy(&dev->devinfo, recvbuf + 4, sizeof(dev->devinfo));
+ memcpy(dev->product_name, dev->devinfo.product_name, 30);
+ memcpy(dev->product_licence, dev->devinfo.product_licence, 60);
+ dev->product_name[30] = '\0';
+ dev->product_licence[60] = '\0';
+
+ for (p = dev->product_name + 29; dev->product_name <= p; p--)
+ if (*p == ' ')
+ *p = '\0';
+ else
+ break;
+
+ for (p = dev->product_licence + 59; dev->product_licence <= p; p--)
+ if (*p == ' ')
+ *p = '\0';
+ else
+ break;
+
+ function = be32_to_cpu(dev->devinfo.function);
+
+ if (function > 0x200) {
+ /* Do this silently - as not a real device */
+ function = 0;
+ dev->driver = &maple_dummy_driver;
+ sprintf(dev->dev.bus_id, "%d:0.port", dev->port);
+ } else {
+ printk(KERN_INFO
+ "Maple bus at (%d, %d): Connected function 0x%lX\n",
+ dev->port, dev->unit, function);
+
+ matched =
+ bus_for_each_drv(&maple_bus_type, NULL, dev,
+ attach_matching_maple_driver);
+
+ if (matched == 0) {
+ /* Driver does not exist yet */
+ printk(KERN_INFO
+ "No maple driver found for this device\n");
+ dev->driver = &maple_dummy_driver;
+ }
+
+ sprintf(dev->dev.bus_id, "%d:0%d.%lX", dev->port,
+ dev->unit, function);
+ }
+ dev->function = function;
+ dev->dev.bus = &maple_bus_type;
+ dev->dev.parent = &maple_bus;
+ dev->dev.release = &maple_release_device;
+ retval = device_register(&dev->dev);
+ if (retval) {
+ printk(KERN_INFO
+ "Maple bus: Attempt to register device (%x, %x) failed.\n",
+ dev->port, dev->unit);
+ maple_free_dev(dev);
+ }
+ dev->registered = 1;
+}
+
+/*
+ * if device has been registered for the given
+ * port and unit then return 1 - allows identification
+ * of which devices need to be attached or detached
+ */
+static int detach_maple_device(struct device *device, void *portptr)
+{
+ struct maple_device_specify *ds;
+ struct maple_device *mdev;
+
+ ds = portptr;
+ mdev = to_maple_dev(device);
+ if (mdev->port == ds->port && mdev->unit == ds->unit)
+ return 1;
+ return 0;
+}
+
+static int setup_maple_commands(struct device *device, void *ignored)
+{
+ struct maple_device *maple_dev = to_maple_dev(device);
+
+ if ((maple_dev->interval > 0)
+ && time_after(jiffies, maple_dev->when)) {
+ maple_dev->when = jiffies + maple_dev->interval;
+ maple_dev->mq->command = MAPLE_COMMAND_GETCOND;
+ maple_dev->mq->sendbuf = &maple_dev->function;
+ maple_dev->mq->length = 1;
+ maple_add_packet(maple_dev->mq);
+ liststatus++;
+ } else {
+ if (time_after(jiffies, maple_pnp_time)) {
+ maple_dev->mq->command = MAPLE_COMMAND_DEVINFO;
+ maple_dev->mq->length = 0;
+ maple_add_packet(maple_dev->mq);
+ liststatus++;
+ }
+ }
+
+ return 0;
+}
+
+/* VBLANK bottom half - implemented via workqueue */
+static void maple_vblank_handler(struct work_struct *work)
+{
+ if (!maple_dma_done())
+ return;
+ if (!list_empty(&maple_sentq))
+ return;
+ ctrl_outl(0, MAPLE_ENABLE);
+ liststatus = 0;
+ bus_for_each_dev(&maple_bus_type, NULL, NULL,
+ setup_maple_commands);
+ if (time_after(jiffies, maple_pnp_time))
+ maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL;
+ if (liststatus && list_empty(&maple_sentq)) {
+ INIT_LIST_HEAD(&maple_sentq);
+ maple_send();
+ }
+ maplebus_dma_reset();
+}
+
+/* handle devices added via hotplugs - placing them on queue for DEVINFO*/
+static void maple_map_subunits(struct maple_device *mdev, int submask)
+{
+ int retval, k, devcheck;
+ struct maple_device *mdev_add;
+ struct maple_device_specify ds;
+
+ for (k = 0; k < 5; k++) {
+ ds.port = mdev->port;
+ ds.unit = k + 1;
+ retval =
+ bus_for_each_dev(&maple_bus_type, NULL, &ds,
+ detach_maple_device);
+ if (retval) {
+ submask = submask >> 1;
+ continue;
+ }
+ devcheck = submask & 0x01;
+ if (devcheck) {
+ mdev_add = maple_alloc_dev(mdev->port, k + 1);
+ if (!mdev_add)
+ return;
+ mdev_add->mq->command = MAPLE_COMMAND_DEVINFO;
+ mdev_add->mq->length = 0;
+ maple_add_packet(mdev_add->mq);
+ scanning = 1;
+ }
+ submask = submask >> 1;
+ }
+}
+
+/* mark a device as removed */
+static void maple_clean_submap(struct maple_device *mdev)
+{
+ int killbit;
+
+ killbit = (mdev->unit > 0 ? (1 << (mdev->unit - 1)) & 0x1f : 0x20);
+ killbit = ~killbit;
+ killbit &= 0xFF;
+ subdevice_map[mdev->port] = subdevice_map[mdev->port] & killbit;
+}
+
+/* handle empty port or hotplug removal */
+static void maple_response_none(struct maple_device *mdev,
+ struct mapleq *mq)
+{
+ if (mdev->unit != 0) {
+ list_del(&mq->list);
+ maple_clean_submap(mdev);
+ printk(KERN_INFO
+ "Maple bus device detaching at (%d, %d)\n",
+ mdev->port, mdev->unit);
+ maple_detach_driver(mdev);
+ return;
+ }
+ if (!started) {
+ printk(KERN_INFO "No maple devices attached to port %d\n",
+ mdev->port);
+ return;
+ }
+ maple_clean_submap(mdev);
+}
+
+/* preprocess hotplugs or scans */
+static void maple_response_devinfo(struct maple_device *mdev,
+ char *recvbuf)
+{
+ char submask;
+ if ((!started) || (scanning == 2)) {
+ maple_attach_driver(mdev);
+ return;
+ }
+ if (mdev->unit == 0) {
+ submask = recvbuf[2] & 0x1F;
+ if (submask ^ subdevice_map[mdev->port]) {
+ maple_map_subunits(mdev, submask);
+ subdevice_map[mdev->port] = submask;
+ }
+ }
+}
+
+/* maple dma end bottom half - implemented via workqueue */
+static void maple_dma_handler(struct work_struct *work)
+{
+ struct mapleq *mq, *nmq;
+ struct maple_device *dev;
+ char *recvbuf;
+ enum maple_code code;
+
+ if (!maple_dma_done())
+ return;
+ ctrl_outl(0, MAPLE_ENABLE);
+ if (!list_empty(&maple_sentq)) {
+ list_for_each_entry_safe(mq, nmq, &maple_sentq, list) {
+ recvbuf = mq->recvbuf;
+ code = recvbuf[0];
+ dev = mq->dev;
+ switch (code) {
+ case MAPLE_RESPONSE_NONE:
+ maple_response_none(dev, mq);
+ break;
+
+ case MAPLE_RESPONSE_DEVINFO:
+ maple_response_devinfo(dev, recvbuf);
+ break;
+
+ case MAPLE_RESPONSE_DATATRF:
+ if (dev->callback)
+ dev->callback(mq);
+ break;
+
+ case MAPLE_RESPONSE_FILEERR:
+ case MAPLE_RESPONSE_AGAIN:
+ case MAPLE_RESPONSE_BADCMD:
+ case MAPLE_RESPONSE_BADFUNC:
+ printk(KERN_DEBUG
+ "Maple non-fatal error 0x%X\n",
+ code);
+ break;
+
+ case MAPLE_RESPONSE_ALLINFO:
+ printk(KERN_DEBUG
+ "Maple - extended device information not supported\n");
+ break;
+
+ case MAPLE_RESPONSE_OK:
+ break;
+
+ default:
+ break;
+ }
+ }
+ INIT_LIST_HEAD(&maple_sentq);
+ if (scanning == 1) {
+ maple_send();
+ scanning = 2;
+ } else
+ scanning = 0;
+
+ if (started == 0)
+ started = 1;
+ }
+ maplebus_dma_reset();
+}
+
+static irqreturn_t maplebus_dma_interrupt(int irq, void *dev_id)
+{
+ /* Load everything into the bottom half */
+ schedule_work(&maple_dma_process);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id)
+{
+ schedule_work(&maple_vblank_process);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction maple_dma_irq = {
+ .name = "maple bus DMA handler",
+ .handler = maplebus_dma_interrupt,
+ .flags = IRQF_SHARED,
+};
+
+static struct irqaction maple_vblank_irq = {
+ .name = "maple bus VBLANK handler",
+ .handler = maplebus_vblank_interrupt,
+ .flags = IRQF_SHARED,
+};
+
+static int maple_set_dma_interrupt_handler(void)
+{
+ return setup_irq(HW_EVENT_MAPLE_DMA, &maple_dma_irq);
+}
+
+static int maple_set_vblank_interrupt_handler(void)
+{
+ return setup_irq(HW_EVENT_VSYNC, &maple_vblank_irq);
+}
+
+static int maple_get_dma_buffer(void)
+{
+ maple_sendbuf =
+ (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO,
+ MAPLE_DMA_PAGES);
+ if (!maple_sendbuf)
+ return -ENOMEM;
+ return 0;
+}
+
+static int match_maple_bus_driver(struct device *devptr,
+ struct device_driver *drvptr)
+{
+ struct maple_driver *maple_drv;
+ struct maple_device *maple_dev;
+
+ maple_drv = container_of(drvptr, struct maple_driver, drv);
+ maple_dev = container_of(devptr, struct maple_device, dev);
+ /* Trap empty port case */
+ if (maple_dev->devinfo.function == 0xFFFFFFFF)
+ return 0;
+ else if (maple_dev->devinfo.function &
+ be32_to_cpu(maple_drv->function))
+ return 1;
+ return 0;
+}
+
+static int maple_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ return 0;
+}
+
+static void maple_bus_release(struct device *dev)
+{
+}
+
+static struct maple_driver maple_dummy_driver = {
+ .drv = {
+ .name = "maple_dummy_driver",
+ .bus = &maple_bus_type,
+ },
+};
+
+struct bus_type maple_bus_type = {
+ .name = "maple",
+ .match = match_maple_bus_driver,
+ .uevent = maple_bus_uevent,
+};
+EXPORT_SYMBOL_GPL(maple_bus_type);
+
+static struct device maple_bus = {
+ .bus_id = "maple",
+ .release = maple_bus_release,
+};
+
+static int __init maple_bus_init(void)
+{
+ int retval, i;
+ struct maple_device *mdev[MAPLE_PORTS];
+ ctrl_outl(0, MAPLE_STATE);
+
+ retval = device_register(&maple_bus);
+ if (retval)
+ goto cleanup;
+
+ retval = bus_register(&maple_bus_type);
+ if (retval)
+ goto cleanup_device;
+
+ retval = driver_register(&maple_dummy_driver.drv);
+
+ if (retval)
+ goto cleanup_bus;
+
+ /* allocate memory for maple bus dma */
+ retval = maple_get_dma_buffer();
+ if (retval) {
+ printk(KERN_INFO
+ "Maple bus: Failed to allocate Maple DMA buffers\n");
+ goto cleanup_basic;
+ }
+
+ /* set up DMA interrupt handler */
+ retval = maple_set_dma_interrupt_handler();
+ if (retval) {
+ printk(KERN_INFO
+ "Maple bus: Failed to grab maple DMA IRQ\n");
+ goto cleanup_dma;
+ }
+
+ /* set up VBLANK interrupt handler */
+ retval = maple_set_vblank_interrupt_handler();
+ if (retval) {
+ printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n");
+ goto cleanup_irq;
+ }
+
+ maple_queue_cache =
+ kmem_cache_create("maple_queue_cache", 0x400, 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+
+ if (!maple_queue_cache)
+ goto cleanup_bothirqs;
+
+ /* setup maple ports */
+ for (i = 0; i < MAPLE_PORTS; i++) {
+ mdev[i] = maple_alloc_dev(i, 0);
+ if (!mdev[i]) {
+ while (i-- > 0)
+ maple_free_dev(mdev[i]);
+ goto cleanup_cache;
+ }
+ mdev[i]->registered = 0;
+ mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO;
+ mdev[i]->mq->length = 0;
+ maple_attach_driver(mdev[i]);
+ maple_add_packet(mdev[i]->mq);
+ subdevice_map[i] = 0;
+ }
+
+ /* setup maplebus hardware */
+ maplebus_dma_reset();
+
+ /* initial detection */
+ maple_send();
+
+ maple_pnp_time = jiffies;
+
+ printk(KERN_INFO "Maple bus core now registered.\n");
+
+ return 0;
+
+cleanup_cache:
+ kmem_cache_destroy(maple_queue_cache);
+
+cleanup_bothirqs:
+ free_irq(HW_EVENT_VSYNC, 0);
+
+cleanup_irq:
+ free_irq(HW_EVENT_MAPLE_DMA, 0);
+
+cleanup_dma:
+ free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES);
+
+cleanup_basic:
+ driver_unregister(&maple_dummy_driver.drv);
+
+cleanup_bus:
+ bus_unregister(&maple_bus_type);
+
+cleanup_device:
+ device_unregister(&maple_bus);
+
+cleanup:
+ printk(KERN_INFO "Maple bus registration failed\n");
+ return retval;
+}
+subsys_initcall(maple_bus_init);
diff --git a/drivers/sh/superhyway/superhyway.c b/drivers/sh/superhyway/superhyway.c
index 7d873b3b051..4d0282b821b 100644
--- a/drivers/sh/superhyway/superhyway.c
+++ b/drivers/sh/superhyway/superhyway.c
@@ -107,16 +107,17 @@ int superhyway_add_devices(struct superhyway_bus *bus,
static int __init superhyway_init(void)
{
struct superhyway_bus *bus;
- int ret = 0;
+ int ret;
- device_register(&superhyway_bus_device);
+ ret = device_register(&superhyway_bus_device);
+ if (unlikely(ret))
+ return ret;
for (bus = superhyway_channels; bus->ops; bus++)
ret |= superhyway_scan_bus(bus);
return ret;
}
-
postcore_initcall(superhyway_init);
static const struct superhyway_device_id *
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index b91571122da..a77ede598d3 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -124,16 +124,17 @@ config SPI_MPC52xx_PSC
Controller in master SPI mode.
config SPI_MPC83xx
- tristate "Freescale MPC83xx SPI controller"
- depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL
+ tristate "Freescale MPC83xx/QUICC Engine SPI controller"
+ depends on SPI_MASTER && (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL
select SPI_BITBANG
help
- This enables using the Freescale MPC83xx SPI controller in master
- mode.
+ This enables using the Freescale MPC83xx and QUICC Engine SPI
+ controllers in master mode.
Note, this driver uniquely supports the SPI controller on the MPC83xx
- family of PowerPC processors. The MPC83xx uses a simple set of shift
- registers for data (opposed to the CPM based descriptor model).
+ family of PowerPC processors, plus processors with QUICC Engine
+ technology. This driver uses a simple set of shift registers for data
+ (opposed to the CPM based descriptor model).
config SPI_OMAP_UWIRE
tristate "OMAP1 MicroWire"
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index b0469749310..0d342dcdd30 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -211,7 +211,7 @@ static void atmel_spi_next_message(struct spi_master *master)
msg = list_entry(as->queue.next, struct spi_message, queue);
spi = msg->spi;
- dev_dbg(master->cdev.dev, "start message %p for %s\n",
+ dev_dbg(master->dev.parent, "start message %p for %s\n",
msg, spi->dev.bus_id);
/* select chip if it's not still active */
@@ -266,10 +266,10 @@ static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
struct spi_transfer *xfer)
{
if (xfer->tx_dma != INVALID_DMA_ADDRESS)
- dma_unmap_single(master->cdev.dev, xfer->tx_dma,
+ dma_unmap_single(master->dev.parent, xfer->tx_dma,
xfer->len, DMA_TO_DEVICE);
if (xfer->rx_dma != INVALID_DMA_ADDRESS)
- dma_unmap_single(master->cdev.dev, xfer->rx_dma,
+ dma_unmap_single(master->dev.parent, xfer->rx_dma,
xfer->len, DMA_FROM_DEVICE);
}
@@ -285,7 +285,7 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
list_del(&msg->queue);
msg->status = status;
- dev_dbg(master->cdev.dev,
+ dev_dbg(master->dev.parent,
"xfer complete: %u bytes transferred\n",
msg->actual_length);
@@ -348,7 +348,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
if (xfer->delay_usecs)
udelay(xfer->delay_usecs);
- dev_warn(master->cdev.dev, "fifo overrun (%u/%u remaining)\n",
+ dev_warn(master->dev.parent, "fifo overrun (%u/%u remaining)\n",
spi_readl(as, TCR), spi_readl(as, RCR));
/*
@@ -363,7 +363,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
if (spi_readl(as, SR) & SPI_BIT(TXEMPTY))
break;
if (!timeout)
- dev_warn(master->cdev.dev,
+ dev_warn(master->dev.parent,
"timeout waiting for TXEMPTY");
while (spi_readl(as, SR) & SPI_BIT(RDRF))
spi_readl(as, RDR);
@@ -526,7 +526,7 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
struct atmel_spi *as;
struct spi_transfer *xfer;
unsigned long flags;
- struct device *controller = spi->master->cdev.dev;
+ struct device *controller = spi->master->dev.parent;
as = spi_master_get_devdata(spi->master);
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
index d2a4b2bdb07..7051e6c5edc 100644
--- a/drivers/spi/mpc52xx_psc_spi.c
+++ b/drivers/spi/mpc52xx_psc_spi.c
@@ -181,7 +181,7 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,
}
- /* enable interupts and wait for wake up
+ /* enable interrupts and wait for wake up
* if just one byte is expected the Rx FIFO genererates no
* FFULL interrupt, so activate the RxRDY interrupt
*/
@@ -503,7 +503,7 @@ static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
INIT_LIST_HEAD(&mps->queue);
mps->workqueue = create_singlethread_workqueue(
- master->cdev.dev->bus_id);
+ master->dev.parent->bus_id);
if (mps->workqueue == NULL) {
ret = -EBUSY;
goto free_irq;
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index 6b357cdb9ea..3cdab131c4a 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -645,7 +645,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
clk_enable(mcspi->ick);
clk_enable(mcspi->fck);
- ret = omap2_mcspi_setup_transfer(spi, NULL);
+ ret = omap2_mcspi_setup_transfer(spi, NULL);
clk_disable(mcspi->fck);
clk_disable(mcspi->ick);
@@ -693,7 +693,6 @@ static void omap2_mcspi_work(struct work_struct *work)
struct spi_device *spi;
struct spi_transfer *t = NULL;
int cs_active = 0;
- struct omap2_mcspi_device_config *conf;
struct omap2_mcspi_cs *cs;
int par_override = 0;
int status = 0;
@@ -706,7 +705,6 @@ static void omap2_mcspi_work(struct work_struct *work)
spin_unlock_irq(&mcspi->lock);
spi = m->spi;
- conf = spi->controller_data;
cs = spi->controller_state;
omap2_mcspi_set_enable(spi, 1);
diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c
index d275c615a73..8245b5153f3 100644
--- a/drivers/spi/omap_uwire.c
+++ b/drivers/spi/omap_uwire.c
@@ -481,7 +481,7 @@ static void uwire_off(struct uwire_spi *uwire)
spi_master_put(uwire->bitbang.master);
}
-static int uwire_probe(struct platform_device *pdev)
+static int __init uwire_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct uwire_spi *uwire;
@@ -525,7 +525,7 @@ static int uwire_probe(struct platform_device *pdev)
return status;
}
-static int uwire_remove(struct platform_device *pdev)
+static int __exit uwire_remove(struct platform_device *pdev)
{
struct uwire_spi *uwire = dev_get_drvdata(&pdev->dev);
int status;
@@ -543,8 +543,7 @@ static struct platform_driver uwire_driver = {
.bus = &platform_bus_type,
.owner = THIS_MODULE,
},
- .probe = uwire_probe,
- .remove = uwire_remove,
+ .remove = __exit_p(uwire_remove),
// suspend ... unuse ck
// resume ... use ck
};
@@ -566,7 +565,7 @@ static int __init omap_uwire_init(void)
omap_writel(val | 0x00AAA000, OMAP730_IO_CONF_9);
}
- return platform_driver_register(&uwire_driver);
+ return platform_driver_probe(&uwire_driver, uwire_probe);
}
static void __exit omap_uwire_exit(void)
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index e51311b2da0..5f3d808cbc2 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -26,7 +26,6 @@
#include <linux/dma-mapping.h>
#include <linux/spi/spi.h>
#include <linux/workqueue.h>
-#include <linux/errno.h>
#include <linux/delay.h>
#include <asm/io.h>
@@ -1230,7 +1229,7 @@ static void cleanup(struct spi_device *spi)
kfree(chip);
}
-static int init_queue(struct driver_data *drv_data)
+static int __init init_queue(struct driver_data *drv_data)
{
INIT_LIST_HEAD(&drv_data->queue);
spin_lock_init(&drv_data->lock);
@@ -1243,7 +1242,7 @@ static int init_queue(struct driver_data *drv_data)
INIT_WORK(&drv_data->pump_messages, pump_messages);
drv_data->workqueue = create_singlethread_workqueue(
- drv_data->master->cdev.dev->bus_id);
+ drv_data->master->dev.parent->bus_id);
if (drv_data->workqueue == NULL)
return -EBUSY;
@@ -1318,7 +1317,7 @@ static int destroy_queue(struct driver_data *drv_data)
return 0;
}
-static int pxa2xx_spi_probe(struct platform_device *pdev)
+static int __init pxa2xx_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct pxa2xx_spi_master *platform_info;
@@ -1622,8 +1621,7 @@ static struct platform_driver driver = {
.bus = &platform_bus_type,
.owner = THIS_MODULE,
},
- .probe = pxa2xx_spi_probe,
- .remove = __devexit_p(pxa2xx_spi_remove),
+ .remove = pxa2xx_spi_remove,
.shutdown = pxa2xx_spi_shutdown,
.suspend = pxa2xx_spi_suspend,
.resume = pxa2xx_spi_resume,
@@ -1631,9 +1629,7 @@ static struct platform_driver driver = {
static int __init pxa2xx_spi_init(void)
{
- platform_driver_register(&driver);
-
- return 0;
+ return platform_driver_probe(&driver, pxa2xx_spi_probe);
}
module_init(pxa2xx_spi_init);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index e84d2159794..b31f4431849 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -67,14 +67,11 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0;
}
-static int spi_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
{
const struct spi_device *spi = to_spi_device(dev);
- envp[0] = buffer;
- snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias);
- envp[1] = NULL;
+ add_uevent_var(env, "MODALIAS=%s", spi->modalias);
return 0;
}
@@ -207,7 +204,7 @@ struct spi_device *spi_new_device(struct spi_master *master,
struct spi_board_info *chip)
{
struct spi_device *proxy;
- struct device *dev = master->cdev.dev;
+ struct device *dev = master->dev.parent;
int status;
/* NOTE: caller did any chip->bus_num checks necessary.
@@ -242,7 +239,7 @@ struct spi_device *spi_new_device(struct spi_master *master,
proxy->modalias = chip->modalias;
snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,
- "%s.%u", master->cdev.class_id,
+ "%s.%u", master->dev.bus_id,
chip->chip_select);
proxy->dev.parent = dev;
proxy->dev.bus = &spi_bus_type;
@@ -341,18 +338,18 @@ static void scan_boardinfo(struct spi_master *master)
/*-------------------------------------------------------------------------*/
-static void spi_master_release(struct class_device *cdev)
+static void spi_master_release(struct device *dev)
{
struct spi_master *master;
- master = container_of(cdev, struct spi_master, cdev);
+ master = container_of(dev, struct spi_master, dev);
kfree(master);
}
static struct class spi_master_class = {
.name = "spi_master",
.owner = THIS_MODULE,
- .release = spi_master_release,
+ .dev_release = spi_master_release,
};
@@ -360,7 +357,7 @@ static struct class spi_master_class = {
* spi_alloc_master - allocate SPI master controller
* @dev: the controller, possibly using the platform_bus
* @size: how much zeroed driver-private data to allocate; the pointer to this
- * memory is in the class_data field of the returned class_device,
+ * memory is in the driver_data field of the returned device,
* accessible with spi_master_get_devdata().
* Context: can sleep
*
@@ -386,9 +383,9 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
if (!master)
return NULL;
- class_device_initialize(&master->cdev);
- master->cdev.class = &spi_master_class;
- master->cdev.dev = get_device(dev);
+ device_initialize(&master->dev);
+ master->dev.class = &spi_master_class;
+ master->dev.parent = get_device(dev);
spi_master_set_devdata(master, &master[1]);
return master;
@@ -418,7 +415,7 @@ EXPORT_SYMBOL_GPL(spi_alloc_master);
int spi_register_master(struct spi_master *master)
{
static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
- struct device *dev = master->cdev.dev;
+ struct device *dev = master->dev.parent;
int status = -ENODEV;
int dynamic = 0;
@@ -443,12 +440,12 @@ int spi_register_master(struct spi_master *master)
/* register the device, then userspace will see it.
* registration fails if the bus ID is in use.
*/
- snprintf(master->cdev.class_id, sizeof master->cdev.class_id,
+ snprintf(master->dev.bus_id, sizeof master->dev.bus_id,
"spi%u", master->bus_num);
- status = class_device_add(&master->cdev);
+ status = device_add(&master->dev);
if (status < 0)
goto done;
- dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id,
+ dev_dbg(dev, "registered master %s%s\n", master->dev.bus_id,
dynamic ? " (dynamic)" : "");
/* populate children from any spi device tables */
@@ -460,10 +457,11 @@ done:
EXPORT_SYMBOL_GPL(spi_register_master);
-static int __unregister(struct device *dev, void *unused)
+static int __unregister(struct device *dev, void *master_dev)
{
/* note: before about 2.6.14-rc1 this would corrupt memory: */
- spi_unregister_device(to_spi_device(dev));
+ if (dev != master_dev)
+ spi_unregister_device(to_spi_device(dev));
return 0;
}
@@ -481,8 +479,9 @@ void spi_unregister_master(struct spi_master *master)
{
int dummy;
- dummy = device_for_each_child(master->cdev.dev, NULL, __unregister);
- class_device_unregister(&master->cdev);
+ dummy = device_for_each_child(master->dev.parent, &master->dev,
+ __unregister);
+ device_unregister(&master->dev);
}
EXPORT_SYMBOL_GPL(spi_unregister_master);
@@ -498,13 +497,13 @@ EXPORT_SYMBOL_GPL(spi_unregister_master);
*/
struct spi_master *spi_busnum_to_master(u16 bus_num)
{
- struct class_device *cdev;
+ struct device *dev;
struct spi_master *master = NULL;
struct spi_master *m;
down(&spi_master_class.sem);
- list_for_each_entry(cdev, &spi_master_class.children, node) {
- m = container_of(cdev, struct spi_master, cdev);
+ list_for_each_entry(dev, &spi_master_class.children, node) {
+ m = container_of(dev, struct spi_master, dev);
if (m->bus_num == bus_num) {
master = spi_master_get(m);
break;
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index f540ed77a10..2ef11bb70b2 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -39,7 +39,6 @@
#include <linux/dma-mapping.h>
#include <linux/spi/spi.h>
#include <linux/workqueue.h>
-#include <linux/errno.h>
#include <linux/delay.h>
#include <asm/io.h>
@@ -1071,7 +1070,7 @@ static int setup(struct spi_device *spi)
return -ENODEV;
}
- dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d,",
+ dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n",
spi->modalias, chip->width, chip->enable_dma);
dev_dbg(&spi->dev, "ctl_reg is 0x%x, flag_reg is 0x%x\n",
chip->ctl_reg, chip->flag);
@@ -1107,7 +1106,7 @@ static inline int init_queue(struct driver_data *drv_data)
/* init messages workqueue */
INIT_WORK(&drv_data->pump_messages, pump_messages);
drv_data->workqueue =
- create_singlethread_workqueue(drv_data->master->cdev.dev->bus_id);
+ create_singlethread_workqueue(drv_data->master->dev.parent->bus_id);
if (drv_data->workqueue == NULL)
return -EBUSY;
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
index 0c85c984ccb..81639c6be1c 100644
--- a/drivers/spi/spi_bitbang.c
+++ b/drivers/spi/spi_bitbang.c
@@ -472,7 +472,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
/* this task is the only thing to touch the SPI bits */
bitbang->busy = 0;
bitbang->workqueue = create_singlethread_workqueue(
- bitbang->master->cdev.dev->bus_id);
+ bitbang->master->dev.parent->bus_id);
if (bitbang->workqueue == NULL) {
status = -EBUSY;
goto err1;
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index bd9177f51de..7686ba34430 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -1194,7 +1194,7 @@ static int setup(struct spi_device *spi)
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
if (!chip) {
dev_err(&spi->dev,
- "setup - cannot allocate controller state");
+ "setup - cannot allocate controller state\n");
return -ENOMEM;
}
chip->control = SPI_DEFAULT_CONTROL;
@@ -1206,7 +1206,7 @@ static int setup(struct spi_device *spi)
if (!chip_info) {
dev_err(&spi->dev,
"setup - "
- "cannot allocate controller data");
+ "cannot allocate controller data\n");
status = -ENOMEM;
goto err_first_setup;
}
@@ -1361,7 +1361,7 @@ static void cleanup(struct spi_device *spi)
kfree(spi_get_ctldata(spi));
}
-static int init_queue(struct driver_data *drv_data)
+static int __init init_queue(struct driver_data *drv_data)
{
INIT_LIST_HEAD(&drv_data->queue);
spin_lock_init(&drv_data->lock);
@@ -1374,7 +1374,7 @@ static int init_queue(struct driver_data *drv_data)
INIT_WORK(&drv_data->work, pump_messages);
drv_data->workqueue = create_singlethread_workqueue(
- drv_data->master->cdev.dev->bus_id);
+ drv_data->master->dev.parent->bus_id);
if (drv_data->workqueue == NULL)
return -EBUSY;
@@ -1444,7 +1444,7 @@ static int destroy_queue(struct driver_data *drv_data)
return 0;
}
-static int spi_imx_probe(struct platform_device *pdev)
+static int __init spi_imx_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct spi_imx_master *platform_info;
@@ -1622,7 +1622,7 @@ err_no_mem:
return status;
}
-static int __devexit spi_imx_remove(struct platform_device *pdev)
+static int __exit spi_imx_remove(struct platform_device *pdev)
{
struct driver_data *drv_data = platform_get_drvdata(pdev);
int irq;
@@ -1739,8 +1739,7 @@ static struct platform_driver driver = {
.bus = &platform_bus_type,
.owner = THIS_MODULE,
},
- .probe = spi_imx_probe,
- .remove = __devexit_p(spi_imx_remove),
+ .remove = __exit_p(spi_imx_remove),
.shutdown = spi_imx_shutdown,
.suspend = spi_imx_suspend,
.resume = spi_imx_resume,
@@ -1748,7 +1747,7 @@ static struct platform_driver driver = {
static int __init spi_imx_init(void)
{
- return platform_driver_register(&driver);
+ return platform_driver_probe(&driver, spi_imx_probe);
}
module_init(spi_imx_init);
diff --git a/drivers/spi/spi_lm70llp.c b/drivers/spi/spi_lm70llp.c
index 4ea68ac1611..39d8d8ad65c 100644
--- a/drivers/spi/spi_lm70llp.c
+++ b/drivers/spi/spi_lm70llp.c
@@ -82,7 +82,7 @@ struct spi_lm70llp {
struct pardevice *pd;
struct spi_device *spidev_lm70;
struct spi_board_info info;
- struct class_device *cdev;
+ //struct device *dev;
};
/* REVISIT : ugly global ; provides "exclusive open" facility */
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index 32cda77b31c..4580b9cf625 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -511,7 +511,7 @@ err:
return ret;
}
-static int __devexit mpc83xx_spi_remove(struct platform_device *dev)
+static int __exit mpc83xx_spi_remove(struct platform_device *dev)
{
struct mpc83xx_spi *mpc83xx_spi;
struct spi_master *master;
@@ -529,8 +529,7 @@ static int __devexit mpc83xx_spi_remove(struct platform_device *dev)
MODULE_ALIAS("mpc83xx_spi"); /* for platform bus hotplug */
static struct platform_driver mpc83xx_spi_driver = {
- .probe = mpc83xx_spi_probe,
- .remove = __devexit_p(mpc83xx_spi_remove),
+ .remove = __exit_p(mpc83xx_spi_remove),
.driver = {
.name = "mpc83xx_spi",
},
@@ -538,7 +537,7 @@ static struct platform_driver mpc83xx_spi_driver = {
static int __init mpc83xx_spi_init(void)
{
- return platform_driver_register(&mpc83xx_spi_driver);
+ return platform_driver_probe(&mpc83xx_spi_driver, mpc83xx_spi_probe);
}
static void __exit mpc83xx_spi_exit(void)
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index e9b683f7d7b..89d6685a5ca 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -233,7 +233,7 @@ static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
return IRQ_HANDLED;
}
-static int s3c24xx_spi_probe(struct platform_device *pdev)
+static int __init s3c24xx_spi_probe(struct platform_device *pdev)
{
struct s3c24xx_spi *hw;
struct spi_master *master;
@@ -382,7 +382,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
return err;
}
-static int s3c24xx_spi_remove(struct platform_device *dev)
+static int __exit s3c24xx_spi_remove(struct platform_device *dev)
{
struct s3c24xx_spi *hw = platform_get_drvdata(dev);
@@ -429,8 +429,7 @@ static int s3c24xx_spi_resume(struct platform_device *pdev)
MODULE_ALIAS("s3c2410_spi"); /* for platform bus hotplug */
static struct platform_driver s3c24xx_spidrv = {
- .probe = s3c24xx_spi_probe,
- .remove = s3c24xx_spi_remove,
+ .remove = __exit_p(s3c24xx_spi_remove),
.suspend = s3c24xx_spi_suspend,
.resume = s3c24xx_spi_resume,
.driver = {
@@ -441,7 +440,7 @@ static struct platform_driver s3c24xx_spidrv = {
static int __init s3c24xx_spi_init(void)
{
- return platform_driver_register(&s3c24xx_spidrv);
+ return platform_driver_probe(&s3c24xx_spidrv, s3c24xx_spi_probe);
}
static void __exit s3c24xx_spi_exit(void)
diff --git a/drivers/spi/spi_txx9.c b/drivers/spi/spi_txx9.c
index b7f4bb239ea..363ac8e6882 100644
--- a/drivers/spi/spi_txx9.c
+++ b/drivers/spi/spi_txx9.c
@@ -24,6 +24,7 @@
#include <linux/spi/spi.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/io.h>
#include <asm/gpio.h>
@@ -74,7 +75,6 @@ struct txx9spi {
struct list_head queue;
wait_queue_head_t waitq;
void __iomem *membase;
- int irq;
int baseclk;
struct clk *clk;
u32 max_speed_hz, min_speed_hz;
@@ -350,12 +350,12 @@ static int __init txx9spi_probe(struct platform_device *dev)
struct resource *res;
int ret = -ENODEV;
u32 mcr;
+ int irq;
master = spi_alloc_master(&dev->dev, sizeof(*c));
if (!master)
return ret;
c = spi_master_get_devdata(master);
- c->irq = -1;
platform_set_drvdata(dev, master);
INIT_WORK(&c->work, txx9spi_work);
@@ -381,32 +381,36 @@ static int __init txx9spi_probe(struct platform_device *dev)
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res)
- goto exit;
- c->membase = ioremap(res->start, res->end - res->start + 1);
+ goto exit_busy;
+ if (!devm_request_mem_region(&dev->dev,
+ res->start, res->end - res->start + 1,
+ "spi_txx9"))
+ goto exit_busy;
+ c->membase = devm_ioremap(&dev->dev,
+ res->start, res->end - res->start + 1);
if (!c->membase)
- goto exit;
+ goto exit_busy;
/* enter config mode */
mcr = txx9spi_rd(c, TXx9_SPMCR);
mcr &= ~(TXx9_SPMCR_OPMODE | TXx9_SPMCR_SPSTP | TXx9_SPMCR_BCLR);
txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, TXx9_SPMCR);
- c->irq = platform_get_irq(dev, 0);
- if (c->irq < 0)
- goto exit;
- ret = request_irq(c->irq, txx9spi_interrupt, 0, dev->name, c);
- if (ret) {
- c->irq = -1;
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0)
+ goto exit_busy;
+ ret = devm_request_irq(&dev->dev, irq, txx9spi_interrupt, 0,
+ "spi_txx9", c);
+ if (ret)
goto exit;
- }
- c->workqueue = create_singlethread_workqueue(master->cdev.dev->bus_id);
+ c->workqueue = create_singlethread_workqueue(master->dev.parent->bus_id);
if (!c->workqueue)
- goto exit;
+ goto exit_busy;
c->last_chipselect = -1;
dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n",
- (unsigned long long)res->start, c->irq,
+ (unsigned long long)res->start, irq,
(c->baseclk + 500000) / 1000000);
master->bus_num = dev->id;
@@ -418,13 +422,11 @@ static int __init txx9spi_probe(struct platform_device *dev)
if (ret)
goto exit;
return 0;
+exit_busy:
+ ret = -EBUSY;
exit:
if (c->workqueue)
destroy_workqueue(c->workqueue);
- if (c->irq >= 0)
- free_irq(c->irq, c);
- if (c->membase)
- iounmap(c->membase);
if (c->clk) {
clk_disable(c->clk);
clk_put(c->clk);
@@ -442,8 +444,6 @@ static int __exit txx9spi_remove(struct platform_device *dev)
spi_unregister_master(master);
platform_set_drvdata(dev, NULL);
destroy_workqueue(c->workqueue);
- free_irq(c->irq, c);
- iounmap(c->membase);
clk_disable(c->clk);
clk_put(c->clk);
spi_master_put(master);
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index c55459c592b..b3518ca9f04 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -184,14 +184,14 @@ static int spidev_message(struct spidev_data *spidev,
if (u_tmp->rx_buf) {
k_tmp->rx_buf = buf;
if (!access_ok(VERIFY_WRITE, (u8 __user *)
- (ptrdiff_t) u_tmp->rx_buf,
+ (uintptr_t) u_tmp->rx_buf,
u_tmp->len))
goto done;
}
if (u_tmp->tx_buf) {
k_tmp->tx_buf = buf;
if (copy_from_user(buf, (const u8 __user *)
- (ptrdiff_t) u_tmp->tx_buf,
+ (uintptr_t) u_tmp->tx_buf,
u_tmp->len))
goto done;
}
@@ -224,7 +224,7 @@ static int spidev_message(struct spidev_data *spidev,
for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
if (u_tmp->rx_buf) {
if (__copy_to_user((u8 __user *)
- (ptrdiff_t) u_tmp->rx_buf, buf,
+ (uintptr_t) u_tmp->rx_buf, buf,
u_tmp->len)) {
status = -EFAULT;
goto done;
diff --git a/drivers/spi/tle62x0.c b/drivers/spi/tle62x0.c
index 6da58ca48b3..455991fbe28 100644
--- a/drivers/spi/tle62x0.c
+++ b/drivers/spi/tle62x0.c
@@ -107,8 +107,11 @@ static ssize_t tle62x0_status_show(struct device *dev,
mutex_lock(&st->lock);
ret = tle62x0_read(st);
-
dev_dbg(dev, "tle62x0_read() returned %d\n", ret);
+ if (ret < 0) {
+ mutex_unlock(&st->lock);
+ return ret;
+ }
for (ptr = 0; ptr < (st->nr_gpio * 2)/8; ptr += 1) {
fault <<= 8;
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig
new file mode 100644
index 00000000000..d976660cb7f
--- /dev/null
+++ b/drivers/ssb/Kconfig
@@ -0,0 +1,117 @@
+menu "Sonics Silicon Backplane"
+
+config SSB_POSSIBLE
+ bool
+ depends on HAS_IOMEM
+ default y
+
+config SSB
+ tristate "Sonics Silicon Backplane support"
+ depends on SSB_POSSIBLE
+ help
+ Support for the Sonics Silicon Backplane bus.
+ You only need to enable this option, if you are
+ configuring a kernel for an embedded system with
+ this bus.
+ It will be auto-selected if needed in other
+ environments.
+
+ The module will be called ssb.
+
+ If unsure, say N.
+
+config SSB_PCIHOST_POSSIBLE
+ bool
+ depends on SSB && (PCI = y || PCI = SSB)
+ default y
+
+config SSB_PCIHOST
+ bool "Support for SSB on PCI-bus host"
+ depends on SSB_PCIHOST_POSSIBLE
+ default y
+ help
+ Support for a Sonics Silicon Backplane on top
+ of a PCI device.
+
+ If unsure, say Y
+
+config SSB_PCMCIAHOST_POSSIBLE
+ bool
+ depends on SSB && (PCMCIA = y || PCMCIA = SSB) && EXPERIMENTAL
+ default y
+
+config SSB_PCMCIAHOST
+ bool "Support for SSB on PCMCIA-bus host (EXPERIMENTAL)"
+ depends on SSB_PCMCIAHOST_POSSIBLE
+ help
+ Support for a Sonics Silicon Backplane on top
+ of a PCMCIA device.
+
+ If unsure, say N
+
+config SSB_SILENT
+ bool "No SSB kernel messages"
+ depends on SSB && EMBEDDED
+ help
+ This option turns off all Sonics Silicon Backplane printks.
+ Note that you won't be able to identify problems, once
+ messages are turned off.
+ This might only be desired for production kernels on
+ embedded devices to reduce the kernel size.
+
+ Say N
+
+config SSB_DEBUG
+ bool "SSB debugging"
+ depends on SSB && !SSB_SILENT
+ help
+ This turns on additional runtime checks and debugging
+ messages. Turn this on for SSB troubleshooting.
+
+ If unsure, say N
+
+config SSB_SERIAL
+ bool
+ depends on SSB
+ # ChipCommon and ExtIf serial support routines.
+
+config SSB_DRIVER_PCICORE_POSSIBLE
+ bool
+ depends on SSB_PCIHOST
+ default y
+
+config SSB_DRIVER_PCICORE
+ bool "SSB PCI core driver"
+ depends on SSB_DRIVER_PCICORE_POSSIBLE
+ help
+ Driver for the Sonics Silicon Backplane attached
+ Broadcom PCI core.
+
+ If unsure, say Y
+
+config SSB_PCICORE_HOSTMODE
+ bool "Hostmode support for SSB PCI core (EXPERIMENTAL)"
+ depends on SSB_DRIVER_PCICORE && SSB_DRIVER_MIPS && EXPERIMENTAL
+ help
+ PCIcore hostmode operation (external PCI bus).
+
+config SSB_DRIVER_MIPS
+ bool "SSB Broadcom MIPS core driver (EXPERIMENTAL)"
+ depends on SSB && MIPS && EXPERIMENTAL
+ select SSB_SERIAL
+ help
+ Driver for the Sonics Silicon Backplane attached
+ Broadcom MIPS core.
+
+ If unsure, say N
+
+config SSB_DRIVER_EXTIF
+ bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)"
+ depends on SSB_DRIVER_MIPS && EXPERIMENTAL
+ help
+ Driver for the Sonics Silicon Backplane attached
+ Broadcom EXTIF core.
+
+ If unsure, say N
+
+endmenu
diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile
new file mode 100644
index 00000000000..7be39759580
--- /dev/null
+++ b/drivers/ssb/Makefile
@@ -0,0 +1,18 @@
+# core
+ssb-y += main.o scan.o
+
+# host support
+ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o
+ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o
+
+# built-in drivers
+ssb-y += driver_chipcommon.o
+ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o
+ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o
+ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o
+
+# b43 pci-ssb-bridge driver
+# Not strictly a part of SSB, but kept here for convenience
+ssb-$(CONFIG_SSB_PCIHOST) += b43_pci_bridge.o
+
+obj-$(CONFIG_SSB) += ssb.o
diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c
new file mode 100644
index 00000000000..f145d8a4cfd
--- /dev/null
+++ b/drivers/ssb/b43_pci_bridge.c
@@ -0,0 +1,48 @@
+/*
+ * Broadcom 43xx PCI-SSB bridge module
+ *
+ * This technically is a seperate PCI driver module, but
+ * because of its small size we include it in the SSB core
+ * instead of creating a standalone module.
+ *
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/pci.h>
+#include <linux/ssb/ssb.h>
+
+#include "ssb_private.h"
+
+
+static const struct pci_device_id b43_pci_bridge_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4301) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4307) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
+
+static struct pci_driver b43_pci_bridge_driver = {
+ .name = "b43-pci-bridge",
+ .id_table = b43_pci_bridge_tbl,
+};
+
+
+int __init b43_pci_ssb_bridge_init(void)
+{
+ return ssb_pcihost_register(&b43_pci_bridge_driver);
+}
+
+void __exit b43_pci_ssb_bridge_exit(void)
+{
+ ssb_pcihost_unregister(&b43_pci_bridge_driver);
+}
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
new file mode 100644
index 00000000000..6fbf1c53b6f
--- /dev/null
+++ b/drivers/ssb/driver_chipcommon.c
@@ -0,0 +1,445 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom ChipCommon core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/pci.h>
+
+#include "ssb_private.h"
+
+
+/* Clock sources */
+enum ssb_clksrc {
+ /* PCI clock */
+ SSB_CHIPCO_CLKSRC_PCI,
+ /* Crystal slow clock oscillator */
+ SSB_CHIPCO_CLKSRC_XTALOS,
+ /* Low power oscillator */
+ SSB_CHIPCO_CLKSRC_LOPWROS,
+};
+
+
+static inline u32 chipco_read32(struct ssb_chipcommon *cc,
+ u16 offset)
+{
+ return ssb_read32(cc->dev, offset);
+}
+
+static inline void chipco_write32(struct ssb_chipcommon *cc,
+ u16 offset,
+ u32 value)
+{
+ ssb_write32(cc->dev, offset, value);
+}
+
+static inline void chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset,
+ u32 mask, u32 value)
+{
+ value &= mask;
+ value |= chipco_read32(cc, offset) & ~mask;
+ chipco_write32(cc, offset, value);
+}
+
+void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
+ enum ssb_clkmode mode)
+{
+ struct ssb_device *ccdev = cc->dev;
+ struct ssb_bus *bus;
+ u32 tmp;
+
+ if (!ccdev)
+ return;
+ bus = ccdev->bus;
+ /* chipcommon cores prior to rev6 don't support dynamic clock control */
+ if (ccdev->id.revision < 6)
+ return;
+ /* chipcommon cores rev10 are a whole new ball game */
+ if (ccdev->id.revision >= 10)
+ return;
+ if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
+ return;
+
+ switch (mode) {
+ case SSB_CLKMODE_SLOW:
+ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+ tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW;
+ chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+ break;
+ case SSB_CLKMODE_FAST:
+ ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */
+ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
+ tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL;
+ chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+ break;
+ case SSB_CLKMODE_DYNAMIC:
+ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
+ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL;
+ tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
+ if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL)
+ tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
+ chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+
+ /* for dynamic control, we have to release our xtal_pu "force on" */
+ if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL)
+ ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0);
+ break;
+ default:
+ SSB_WARN_ON(1);
+ }
+}
+
+/* Get the Slow Clock Source */
+static enum ssb_clksrc chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc)
+{
+ struct ssb_bus *bus = cc->dev->bus;
+ u32 uninitialized_var(tmp);
+
+ if (cc->dev->id.revision < 6) {
+ if (bus->bustype == SSB_BUSTYPE_SSB ||
+ bus->bustype == SSB_BUSTYPE_PCMCIA)
+ return SSB_CHIPCO_CLKSRC_XTALOS;
+ if (bus->bustype == SSB_BUSTYPE_PCI) {
+ pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &tmp);
+ if (tmp & 0x10)
+ return SSB_CHIPCO_CLKSRC_PCI;
+ return SSB_CHIPCO_CLKSRC_XTALOS;
+ }
+ }
+ if (cc->dev->id.revision < 10) {
+ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+ tmp &= 0x7;
+ if (tmp == 0)
+ return SSB_CHIPCO_CLKSRC_LOPWROS;
+ if (tmp == 1)
+ return SSB_CHIPCO_CLKSRC_XTALOS;
+ if (tmp == 2)
+ return SSB_CHIPCO_CLKSRC_PCI;
+ }
+
+ return SSB_CHIPCO_CLKSRC_XTALOS;
+}
+
+/* Get maximum or minimum (depending on get_max flag) slowclock frequency. */
+static int chipco_pctl_clockfreqlimit(struct ssb_chipcommon *cc, int get_max)
+{
+ int uninitialized_var(limit);
+ enum ssb_clksrc clocksrc;
+ int divisor = 1;
+ u32 tmp;
+
+ clocksrc = chipco_pctl_get_slowclksrc(cc);
+ if (cc->dev->id.revision < 6) {
+ switch (clocksrc) {
+ case SSB_CHIPCO_CLKSRC_PCI:
+ divisor = 64;
+ break;
+ case SSB_CHIPCO_CLKSRC_XTALOS:
+ divisor = 32;
+ break;
+ default:
+ SSB_WARN_ON(1);
+ }
+ } else if (cc->dev->id.revision < 10) {
+ switch (clocksrc) {
+ case SSB_CHIPCO_CLKSRC_LOPWROS:
+ break;
+ case SSB_CHIPCO_CLKSRC_XTALOS:
+ case SSB_CHIPCO_CLKSRC_PCI:
+ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+ divisor = (tmp >> 16) + 1;
+ divisor *= 4;
+ break;
+ }
+ } else {
+ tmp = chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL);
+ divisor = (tmp >> 16) + 1;
+ divisor *= 4;
+ }
+
+ switch (clocksrc) {
+ case SSB_CHIPCO_CLKSRC_LOPWROS:
+ if (get_max)
+ limit = 43000;
+ else
+ limit = 25000;
+ break;
+ case SSB_CHIPCO_CLKSRC_XTALOS:
+ if (get_max)
+ limit = 20200000;
+ else
+ limit = 19800000;
+ break;
+ case SSB_CHIPCO_CLKSRC_PCI:
+ if (get_max)
+ limit = 34000000;
+ else
+ limit = 25000000;
+ break;
+ }
+ limit /= divisor;
+
+ return limit;
+}
+
+static void chipco_powercontrol_init(struct ssb_chipcommon *cc)
+{
+ struct ssb_bus *bus = cc->dev->bus;
+
+ if (bus->chip_id == 0x4321) {
+ if (bus->chip_rev == 0)
+ chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0x3A4);
+ else if (bus->chip_rev == 1)
+ chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0xA4);
+ }
+
+ if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
+ return;
+
+ if (cc->dev->id.revision >= 10) {
+ /* Set Idle Power clock rate to 1Mhz */
+ chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL,
+ (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) &
+ 0x0000FFFF) | 0x00040000);
+ } else {
+ int maxfreq;
+
+ maxfreq = chipco_pctl_clockfreqlimit(cc, 1);
+ chipco_write32(cc, SSB_CHIPCO_PLLONDELAY,
+ (maxfreq * 150 + 999999) / 1000000);
+ chipco_write32(cc, SSB_CHIPCO_FREFSELDELAY,
+ (maxfreq * 15 + 999999) / 1000000);
+ }
+}
+
+static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
+{
+ struct ssb_bus *bus = cc->dev->bus;
+ int minfreq;
+ unsigned int tmp;
+ u32 pll_on_delay;
+
+ if (bus->bustype != SSB_BUSTYPE_PCI)
+ return;
+ if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
+ return;
+
+ minfreq = chipco_pctl_clockfreqlimit(cc, 0);
+ pll_on_delay = chipco_read32(cc, SSB_CHIPCO_PLLONDELAY);
+ tmp = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
+ SSB_WARN_ON(tmp & ~0xFFFF);
+
+ cc->fast_pwrup_delay = tmp;
+}
+
+void ssb_chipcommon_init(struct ssb_chipcommon *cc)
+{
+ if (!cc->dev)
+ return; /* We don't have a ChipCommon */
+ chipco_powercontrol_init(cc);
+ ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
+ calc_fast_powerup_delay(cc);
+}
+
+void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state)
+{
+ if (!cc->dev)
+ return;
+ ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW);
+}
+
+void ssb_chipco_resume(struct ssb_chipcommon *cc)
+{
+ if (!cc->dev)
+ return;
+ chipco_powercontrol_init(cc);
+ ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
+}
+
+/* Get the processor clock */
+void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
+ u32 *plltype, u32 *n, u32 *m)
+{
+ *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
+ *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
+ switch (*plltype) {
+ case SSB_PLLTYPE_2:
+ case SSB_PLLTYPE_4:
+ case SSB_PLLTYPE_6:
+ case SSB_PLLTYPE_7:
+ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS);
+ break;
+ case SSB_PLLTYPE_3:
+ /* 5350 uses m2 to control mips */
+ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2);
+ break;
+ default:
+ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB);
+ break;
+ }
+}
+
+/* Get the bus clock */
+void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
+ u32 *plltype, u32 *n, u32 *m)
+{
+ *n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
+ *plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
+ switch (*plltype) {
+ case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
+ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS);
+ break;
+ case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+ if (cc->dev->bus->chip_id != 0x5365) {
+ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2);
+ break;
+ }
+ /* Fallthough */
+ default:
+ *m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB);
+ }
+}
+
+void ssb_chipco_timing_init(struct ssb_chipcommon *cc,
+ unsigned long ns)
+{
+ struct ssb_device *dev = cc->dev;
+ struct ssb_bus *bus = dev->bus;
+ u32 tmp;
+
+ /* set register for external IO to control LED. */
+ chipco_write32(cc, SSB_CHIPCO_PROG_CFG, 0x11);
+ tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */
+ tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 40ns */
+ tmp |= DIV_ROUND_UP(240, ns); /* Waitcount-0 = 240ns */
+ chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */
+
+ /* Set timing for the flash */
+ tmp = DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_3_SHIFT; /* Waitcount-3 = 10nS */
+ tmp |= DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_1_SHIFT; /* Waitcount-1 = 10nS */
+ tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120nS */
+ if ((bus->chip_id == 0x5365) ||
+ (dev->id.revision < 9))
+ chipco_write32(cc, SSB_CHIPCO_FLASH_WAITCNT, tmp);
+ if ((bus->chip_id == 0x5365) ||
+ (dev->id.revision < 9) ||
+ ((bus->chip_id == 0x5350) && (bus->chip_rev == 0)))
+ chipco_write32(cc, SSB_CHIPCO_PCMCIA_MEMWAIT, tmp);
+
+ if (bus->chip_id == 0x5350) {
+ /* Enable EXTIF */
+ tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */
+ tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; /* Waitcount-2 = 20ns */
+ tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 100ns */
+ tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120ns */
+ chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */
+ }
+}
+
+/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
+void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks)
+{
+ /* instant NMI */
+ chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks);
+}
+
+u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask)
+{
+ return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask;
+}
+
+void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
+{
+ chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
+}
+
+void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
+{
+ chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
+}
+
+#ifdef CONFIG_SSB_SERIAL
+int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
+ struct ssb_serial_port *ports)
+{
+ struct ssb_bus *bus = cc->dev->bus;
+ int nr_ports = 0;
+ u32 plltype;
+ unsigned int irq;
+ u32 baud_base, div;
+ u32 i, n;
+
+ plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
+ irq = ssb_mips_irq(cc->dev);
+
+ if (plltype == SSB_PLLTYPE_1) {
+ /* PLL clock */
+ baud_base = ssb_calc_clock_rate(plltype,
+ chipco_read32(cc, SSB_CHIPCO_CLOCK_N),
+ chipco_read32(cc, SSB_CHIPCO_CLOCK_M2));
+ div = 1;
+ } else {
+ if (cc->dev->id.revision >= 11) {
+ /* Fixed ALP clock */
+ baud_base = 20000000;
+ div = 1;
+ /* Set the override bit so we don't divide it */
+ chipco_write32(cc, SSB_CHIPCO_CORECTL,
+ SSB_CHIPCO_CORECTL_UARTCLK0);
+ } else if (cc->dev->id.revision >= 3) {
+ /* Internal backplane clock */
+ baud_base = ssb_clockspeed(bus);
+ div = chipco_read32(cc, SSB_CHIPCO_CLKDIV)
+ & SSB_CHIPCO_CLKDIV_UART;
+ } else {
+ /* Fixed internal backplane clock */
+ baud_base = 88000000;
+ div = 48;
+ }
+
+ /* Clock source depends on strapping if UartClkOverride is unset */
+ if ((cc->dev->id.revision > 0) &&
+ !(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) {
+ if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) ==
+ SSB_CHIPCO_CAP_UARTCLK_INT) {
+ /* Internal divided backplane clock */
+ baud_base /= div;
+ } else {
+ /* Assume external clock of 1.8432 MHz */
+ baud_base = 1843200;
+ }
+ }
+ }
+
+ /* Determine the registers of the UARTs */
+ n = (cc->capabilities & SSB_CHIPCO_CAP_NRUART);
+ for (i = 0; i < n; i++) {
+ void __iomem *cc_mmio;
+ void __iomem *uart_regs;
+
+ cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE);
+ uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA;
+ /* Offset changed at after rev 0 */
+ if (cc->dev->id.revision == 0)
+ uart_regs += (i * 8);
+ else
+ uart_regs += (i * 256);
+
+ nr_ports++;
+ ports[i].regs = uart_regs;
+ ports[i].irq = irq;
+ ports[i].baud_base = baud_base;
+ ports[i].reg_shift = 0;
+ }
+
+ return nr_ports;
+}
+#endif /* CONFIG_SSB_SERIAL */
diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c
new file mode 100644
index 00000000000..fe55eb8b038
--- /dev/null
+++ b/drivers/ssb/driver_extif.c
@@ -0,0 +1,129 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom EXTIF core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
+ * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+
+#include "ssb_private.h"
+
+
+static inline u32 extif_read32(struct ssb_extif *extif, u16 offset)
+{
+ return ssb_read32(extif->dev, offset);
+}
+
+static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value)
+{
+ ssb_write32(extif->dev, offset, value);
+}
+
+static inline void extif_write32_masked(struct ssb_extif *extif, u16 offset,
+ u32 mask, u32 value)
+{
+ value &= mask;
+ value |= extif_read32(extif, offset) & ~mask;
+ extif_write32(extif, offset, value);
+}
+
+#ifdef CONFIG_SSB_SERIAL
+static bool serial_exists(u8 *regs)
+{
+ u8 save_mcr, msr = 0;
+
+ if (regs) {
+ save_mcr = regs[UART_MCR];
+ regs[UART_MCR] = (UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_RTS);
+ msr = regs[UART_MSR] & (UART_MSR_DCD | UART_MSR_RI
+ | UART_MSR_CTS | UART_MSR_DSR);
+ regs[UART_MCR] = save_mcr;
+ }
+ return (msr == (UART_MSR_DCD | UART_MSR_CTS));
+}
+
+int ssb_extif_serial_init(struct ssb_extif *extif, struct ssb_serial_port *ports)
+{
+ u32 i, nr_ports = 0;
+
+ /* Disable GPIO interrupt initially */
+ extif_write32(extif, SSB_EXTIF_GPIO_INTPOL, 0);
+ extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 0);
+
+ for (i = 0; i < 2; i++) {
+ void __iomem *uart_regs;
+
+ uart_regs = ioremap_nocache(SSB_EUART, 16);
+ if (uart_regs) {
+ uart_regs += (i * 8);
+
+ if (serial_exists(uart_regs) && ports) {
+ extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 2);
+
+ nr_ports++;
+ ports[i].regs = uart_regs;
+ ports[i].irq = 2;
+ ports[i].baud_base = 13500000;
+ ports[i].reg_shift = 0;
+ }
+ iounmap(uart_regs);
+ }
+ }
+ return nr_ports;
+}
+#endif /* CONFIG_SSB_SERIAL */
+
+void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns)
+{
+ u32 tmp;
+
+ /* Initialize extif so we can get to the LEDs and external UART */
+ extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN);
+
+ /* Set timing for the flash */
+ tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT;
+ tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT;
+ tmp |= DIV_ROUND_UP(120, ns);
+ extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp);
+
+ /* Set programmable interface timing for external uart */
+ tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT;
+ tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT;
+ tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT;
+ tmp |= DIV_ROUND_UP(120, ns);
+ extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp);
+}
+
+void ssb_extif_get_clockcontrol(struct ssb_extif *extif,
+ u32 *pll_type, u32 *n, u32 *m)
+{
+ *pll_type = SSB_PLLTYPE_1;
+ *n = extif_read32(extif, SSB_EXTIF_CLOCK_N);
+ *m = extif_read32(extif, SSB_EXTIF_CLOCK_SB);
+}
+
+u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
+{
+ return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask;
+}
+
+void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
+{
+ return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
+ mask, value);
+}
+
+void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
+{
+ return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
+ mask, value);
+}
+
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c
new file mode 100644
index 00000000000..3d3dd32bf3a
--- /dev/null
+++ b/drivers/ssb/driver_mipscore.c
@@ -0,0 +1,224 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom MIPS core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+
+#include "ssb_private.h"
+
+
+static inline u32 mips_read32(struct ssb_mipscore *mcore,
+ u16 offset)
+{
+ return ssb_read32(mcore->dev, offset);
+}
+
+static inline void mips_write32(struct ssb_mipscore *mcore,
+ u16 offset,
+ u32 value)
+{
+ ssb_write32(mcore->dev, offset, value);
+}
+
+static const u32 ipsflag_irq_mask[] = {
+ 0,
+ SSB_IPSFLAG_IRQ1,
+ SSB_IPSFLAG_IRQ2,
+ SSB_IPSFLAG_IRQ3,
+ SSB_IPSFLAG_IRQ4,
+};
+
+static const u32 ipsflag_irq_shift[] = {
+ 0,
+ SSB_IPSFLAG_IRQ1_SHIFT,
+ SSB_IPSFLAG_IRQ2_SHIFT,
+ SSB_IPSFLAG_IRQ3_SHIFT,
+ SSB_IPSFLAG_IRQ4_SHIFT,
+};
+
+static inline u32 ssb_irqflag(struct ssb_device *dev)
+{
+ return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
+}
+
+/* Get the MIPS IRQ assignment for a specified device.
+ * If unassigned, 0 is returned.
+ */
+unsigned int ssb_mips_irq(struct ssb_device *dev)
+{
+ struct ssb_bus *bus = dev->bus;
+ u32 irqflag;
+ u32 ipsflag;
+ u32 tmp;
+ unsigned int irq;
+
+ irqflag = ssb_irqflag(dev);
+ ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
+ for (irq = 1; irq <= 4; irq++) {
+ tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
+ if (tmp == irqflag)
+ break;
+ }
+ if (irq == 5)
+ irq = 0;
+
+ return irq;
+}
+
+static void clear_irq(struct ssb_bus *bus, unsigned int irq)
+{
+ struct ssb_device *dev = bus->mipscore.dev;
+
+ /* Clear the IRQ in the MIPScore backplane registers */
+ if (irq == 0) {
+ ssb_write32(dev, SSB_INTVEC, 0);
+ } else {
+ ssb_write32(dev, SSB_IPSFLAG,
+ ssb_read32(dev, SSB_IPSFLAG) |
+ ipsflag_irq_mask[irq]);
+ }
+}
+
+static void set_irq(struct ssb_device *dev, unsigned int irq)
+{
+ unsigned int oldirq = ssb_mips_irq(dev);
+ struct ssb_bus *bus = dev->bus;
+ struct ssb_device *mdev = bus->mipscore.dev;
+ u32 irqflag = ssb_irqflag(dev);
+
+ dev->irq = irq + 2;
+
+ ssb_dprintk(KERN_INFO PFX
+ "set_irq: core 0x%04x, irq %d => %d\n",
+ dev->id.coreid, oldirq, irq);
+ /* clear the old irq */
+ if (oldirq == 0)
+ ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
+ else
+ clear_irq(bus, oldirq);
+
+ /* assign the new one */
+ if (irq == 0)
+ ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
+
+ irqflag <<= ipsflag_irq_shift[irq];
+ irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]);
+ ssb_write32(mdev, SSB_IPSFLAG, irqflag);
+}
+
+static void ssb_mips_serial_init(struct ssb_mipscore *mcore)
+{
+ struct ssb_bus *bus = mcore->dev->bus;
+
+ if (bus->extif.dev)
+ mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports);
+ else if (bus->chipco.dev)
+ mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
+ else
+ mcore->nr_serial_ports = 0;
+}
+
+static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
+{
+ struct ssb_bus *bus = mcore->dev->bus;
+
+ mcore->flash_buswidth = 2;
+ if (bus->chipco.dev) {
+ mcore->flash_window = 0x1c000000;
+ mcore->flash_window_size = 0x02000000;
+ if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
+ & SSB_CHIPCO_CFG_DS16) == 0)
+ mcore->flash_buswidth = 1;
+ } else {
+ mcore->flash_window = 0x1fc00000;
+ mcore->flash_window_size = 0x00400000;
+ }
+}
+
+u32 ssb_cpu_clock(struct ssb_mipscore *mcore)
+{
+ struct ssb_bus *bus = mcore->dev->bus;
+ u32 pll_type, n, m, rate = 0;
+
+ if (bus->extif.dev) {
+ ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
+ } else if (bus->chipco.dev) {
+ ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
+ } else
+ return 0;
+
+ if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
+ rate = 200000000;
+ } else {
+ rate = ssb_calc_clock_rate(pll_type, n, m);
+ }
+
+ if (pll_type == SSB_PLLTYPE_6) {
+ rate *= 2;
+ }
+
+ return rate;
+}
+
+void ssb_mipscore_init(struct ssb_mipscore *mcore)
+{
+ struct ssb_bus *bus;
+ struct ssb_device *dev;
+ unsigned long hz, ns;
+ unsigned int irq, i;
+
+ if (!mcore->dev)
+ return; /* We don't have a MIPS core */
+
+ ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n");
+
+ bus = mcore->dev->bus;
+ hz = ssb_clockspeed(bus);
+ if (!hz)
+ hz = 100000000;
+ ns = 1000000000 / hz;
+
+ if (bus->extif.dev)
+ ssb_extif_timing_init(&bus->extif, ns);
+ else if (bus->chipco.dev)
+ ssb_chipco_timing_init(&bus->chipco, ns);
+
+ /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
+ for (irq = 2, i = 0; i < bus->nr_devices; i++) {
+ dev = &(bus->devices[i]);
+ dev->irq = ssb_mips_irq(dev) + 2;
+ switch (dev->id.coreid) {
+ case SSB_DEV_USB11_HOST:
+ /* shouldn't need a separate irq line for non-4710, most of them have a proper
+ * external usb controller on the pci */
+ if ((bus->chip_id == 0x4710) && (irq <= 4)) {
+ set_irq(dev, irq++);
+ break;
+ }
+ /* fallthrough */
+ case SSB_DEV_PCI:
+ case SSB_DEV_ETHERNET:
+ case SSB_DEV_80211:
+ case SSB_DEV_USB20_HOST:
+ /* These devices get their own IRQ line if available, the rest goes on IRQ0 */
+ if (irq <= 4) {
+ set_irq(dev, irq++);
+ break;
+ }
+ }
+ }
+
+ ssb_mips_serial_init(mcore);
+ ssb_mips_flash_detect(mcore);
+}
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
new file mode 100644
index 00000000000..2faaa906d5d
--- /dev/null
+++ b/drivers/ssb/driver_pcicore.c
@@ -0,0 +1,576 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom PCI-core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "ssb_private.h"
+
+
+static inline
+u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset)
+{
+ return ssb_read32(pc->dev, offset);
+}
+
+static inline
+void pcicore_write32(struct ssb_pcicore *pc, u16 offset, u32 value)
+{
+ ssb_write32(pc->dev, offset, value);
+}
+
+/**************************************************
+ * Code for hostmode operation.
+ **************************************************/
+
+#ifdef CONFIG_SSB_PCICORE_HOSTMODE
+
+#include <asm/paccess.h>
+/* Probe a 32bit value on the bus and catch bus exceptions.
+ * Returns nonzero on a bus exception.
+ * This is MIPS specific */
+#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr)))
+
+/* Assume one-hot slot wiring */
+#define SSB_PCI_SLOT_MAX 16
+
+/* Global lock is OK, as we won't have more than one extpci anyway. */
+static DEFINE_SPINLOCK(cfgspace_lock);
+/* Core to access the external PCI config space. Can only have one. */
+static struct ssb_pcicore *extpci_core;
+
+static u32 ssb_pcicore_pcibus_iobase = 0x100;
+static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA;
+
+int pcibios_plat_dev_init(struct pci_dev *d)
+{
+ struct resource *res;
+ int pos, size;
+ u32 *base;
+
+ ssb_printk(KERN_INFO "PCI: Fixing up device %s\n",
+ pci_name(d));
+
+ /* Fix up resource bases */
+ for (pos = 0; pos < 6; pos++) {
+ res = &d->resource[pos];
+ if (res->flags & IORESOURCE_IO)
+ base = &ssb_pcicore_pcibus_iobase;
+ else
+ base = &ssb_pcicore_pcibus_membase;
+ if (res->end) {
+ size = res->end - res->start + 1;
+ if (*base & (size - 1))
+ *base = (*base + size) & ~(size - 1);
+ res->start = *base;
+ res->end = res->start + size - 1;
+ *base += size;
+ pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
+ }
+ /* Fix up PCI bridge BAR0 only */
+ if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0)
+ break;
+ }
+ /* Fix up interrupt lines */
+ d->irq = ssb_mips_irq(extpci_core->dev) + 2;
+ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
+
+ return 0;
+}
+
+static void __init ssb_fixup_pcibridge(struct pci_dev *dev)
+{
+ if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
+ return;
+
+ ssb_printk(KERN_INFO "PCI: fixing up bridge\n");
+
+ /* Enable PCI bridge bus mastering and memory space */
+ pci_set_master(dev);
+ pcibios_enable_device(dev, ~0);
+
+ /* Enable PCI bridge BAR1 prefetch and burst */
+ pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
+
+ /* Make sure our latency is high enough to handle the devices behind us */
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge);
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return ssb_mips_irq(extpci_core->dev) + 2;
+}
+
+static u32 get_cfgspace_addr(struct ssb_pcicore *pc,
+ unsigned int bus, unsigned int dev,
+ unsigned int func, unsigned int off)
+{
+ u32 addr = 0;
+ u32 tmp;
+
+ if (unlikely(pc->cardbusmode && dev > 1))
+ goto out;
+ if (bus == 0) {
+ /* Type 0 transaction */
+ if (unlikely(dev >= SSB_PCI_SLOT_MAX))
+ goto out;
+ /* Slide the window */
+ tmp = SSB_PCICORE_SBTOPCI_CFG0;
+ tmp |= ((1 << (dev + 16)) & SSB_PCICORE_SBTOPCI1_MASK);
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, tmp);
+ /* Calculate the address */
+ addr = SSB_PCI_CFG;
+ addr |= ((1 << (dev + 16)) & ~SSB_PCICORE_SBTOPCI1_MASK);
+ addr |= (func << 8);
+ addr |= (off & ~3);
+ } else {
+ /* Type 1 transaction */
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI1,
+ SSB_PCICORE_SBTOPCI_CFG1);
+ /* Calculate the address */
+ addr = SSB_PCI_CFG;
+ addr |= (bus << 16);
+ addr |= (dev << 11);
+ addr |= (func << 8);
+ addr |= (off & ~3);
+ }
+out:
+ return addr;
+}
+
+static int ssb_extpci_read_config(struct ssb_pcicore *pc,
+ unsigned int bus, unsigned int dev,
+ unsigned int func, unsigned int off,
+ void *buf, int len)
+{
+ int err = -EINVAL;
+ u32 addr, val;
+ void __iomem *mmio;
+
+ SSB_WARN_ON(!pc->hostmode);
+ if (unlikely(len != 1 && len != 2 && len != 4))
+ goto out;
+ addr = get_cfgspace_addr(pc, bus, dev, func, off);
+ if (unlikely(!addr))
+ goto out;
+ err = -ENOMEM;
+ mmio = ioremap_nocache(addr, len);
+ if (!mmio)
+ goto out;
+
+ if (mips_busprobe32(val, mmio)) {
+ val = 0xffffffff;
+ goto unmap;
+ }
+
+ val = readl(mmio);
+ val >>= (8 * (off & 3));
+
+ switch (len) {
+ case 1:
+ *((u8 *)buf) = (u8)val;
+ break;
+ case 2:
+ *((u16 *)buf) = (u16)val;
+ break;
+ case 4:
+ *((u32 *)buf) = (u32)val;
+ break;
+ }
+ err = 0;
+unmap:
+ iounmap(mmio);
+out:
+ return err;
+}
+
+static int ssb_extpci_write_config(struct ssb_pcicore *pc,
+ unsigned int bus, unsigned int dev,
+ unsigned int func, unsigned int off,
+ const void *buf, int len)
+{
+ int err = -EINVAL;
+ u32 addr, val = 0;
+ void __iomem *mmio;
+
+ SSB_WARN_ON(!pc->hostmode);
+ if (unlikely(len != 1 && len != 2 && len != 4))
+ goto out;
+ addr = get_cfgspace_addr(pc, bus, dev, func, off);
+ if (unlikely(!addr))
+ goto out;
+ err = -ENOMEM;
+ mmio = ioremap_nocache(addr, len);
+ if (!mmio)
+ goto out;
+
+ if (mips_busprobe32(val, mmio)) {
+ val = 0xffffffff;
+ goto unmap;
+ }
+
+ switch (len) {
+ case 1:
+ val = readl(mmio);
+ val &= ~(0xFF << (8 * (off & 3)));
+ val |= *((const u8 *)buf) << (8 * (off & 3));
+ break;
+ case 2:
+ val = readl(mmio);
+ val &= ~(0xFFFF << (8 * (off & 3)));
+ val |= *((const u16 *)buf) << (8 * (off & 3));
+ break;
+ case 4:
+ val = *((const u32 *)buf);
+ break;
+ }
+ writel(val, mmio);
+
+ err = 0;
+unmap:
+ iounmap(mmio);
+out:
+ return err;
+}
+
+static int ssb_pcicore_read_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 *val)
+{
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&cfgspace_lock, flags);
+ err = ssb_extpci_read_config(extpci_core, bus->number, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), reg, val, size);
+ spin_unlock_irqrestore(&cfgspace_lock, flags);
+
+ return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static int ssb_pcicore_write_config(struct pci_bus *bus, unsigned int devfn,
+ int reg, int size, u32 val)
+{
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&cfgspace_lock, flags);
+ err = ssb_extpci_write_config(extpci_core, bus->number, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), reg, &val, size);
+ spin_unlock_irqrestore(&cfgspace_lock, flags);
+
+ return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops ssb_pcicore_pciops = {
+ .read = ssb_pcicore_read_config,
+ .write = ssb_pcicore_write_config,
+};
+
+static struct resource ssb_pcicore_mem_resource = {
+ .name = "SSB PCIcore external memory",
+ .start = SSB_PCI_DMA,
+ .end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource ssb_pcicore_io_resource = {
+ .name = "SSB PCIcore external I/O",
+ .start = 0x100,
+ .end = 0x7FF,
+ .flags = IORESOURCE_IO,
+};
+
+static struct pci_controller ssb_pcicore_controller = {
+ .pci_ops = &ssb_pcicore_pciops,
+ .io_resource = &ssb_pcicore_io_resource,
+ .mem_resource = &ssb_pcicore_mem_resource,
+ .mem_offset = 0x24000000,
+};
+
+static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
+{
+ u32 val;
+
+ if (WARN_ON(extpci_core))
+ return;
+ extpci_core = pc;
+
+ ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n");
+ /* Reset devices on the external PCI bus */
+ val = SSB_PCICORE_CTL_RST_OE;
+ val |= SSB_PCICORE_CTL_CLK_OE;
+ pcicore_write32(pc, SSB_PCICORE_CTL, val);
+ val |= SSB_PCICORE_CTL_CLK; /* Clock on */
+ pcicore_write32(pc, SSB_PCICORE_CTL, val);
+ udelay(150); /* Assertion time demanded by the PCI standard */
+ val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */
+ pcicore_write32(pc, SSB_PCICORE_CTL, val);
+ val = SSB_PCICORE_ARBCTL_INTERN;
+ pcicore_write32(pc, SSB_PCICORE_ARBCTL, val);
+ udelay(1); /* Assertion time demanded by the PCI standard */
+
+ /*TODO cardbus mode */
+
+ /* 64MB I/O window */
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI0,
+ SSB_PCICORE_SBTOPCI_IO);
+ /* 64MB config space */
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI1,
+ SSB_PCICORE_SBTOPCI_CFG0);
+ /* 1GB memory window */
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI2,
+ SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA);
+
+ /* Enable PCI bridge BAR0 prefetch and burst */
+ val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2);
+ /* Clear error conditions */
+ val = 0;
+ ssb_extpci_write_config(pc, 0, 0, 0, PCI_STATUS, &val, 2);
+
+ /* Enable PCI interrupts */
+ pcicore_write32(pc, SSB_PCICORE_IMASK,
+ SSB_PCICORE_IMASK_INTA);
+
+ /* Ok, ready to run, register it to the system.
+ * The following needs change, if we want to port hostmode
+ * to non-MIPS platform. */
+ set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000));
+ /* Give some time to the PCI controller to configure itself with the new
+ * values. Not waiting at this point causes crashes of the machine. */
+ mdelay(10);
+ register_pci_controller(&ssb_pcicore_controller);
+}
+
+static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
+{
+ struct ssb_bus *bus = pc->dev->bus;
+ u16 chipid_top;
+ u32 tmp;
+
+ chipid_top = (bus->chip_id & 0xFF00);
+ if (chipid_top != 0x4700 &&
+ chipid_top != 0x5300)
+ return 0;
+
+ if (bus->sprom.r1.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
+ return 0;
+
+ /* The 200-pin BCM4712 package does not bond out PCI. Even when
+ * PCI is bonded out, some boards may leave the pins floating. */
+ if (bus->chip_id == 0x4712) {
+ if (bus->chip_package == SSB_CHIPPACK_BCM4712S)
+ return 0;
+ if (bus->chip_package == SSB_CHIPPACK_BCM4712M)
+ return 0;
+ }
+ if (bus->chip_id == 0x5350)
+ return 0;
+
+ return !mips_busprobe32(tmp, (bus->mmio + (pc->dev->core_index * SSB_CORE_SIZE)));
+}
+#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
+
+
+/**************************************************
+ * Generic and Clientmode operation code.
+ **************************************************/
+
+static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
+{
+ /* Disable PCI interrupts. */
+ ssb_write32(pc->dev, SSB_INTVEC, 0);
+}
+
+void ssb_pcicore_init(struct ssb_pcicore *pc)
+{
+ struct ssb_device *dev = pc->dev;
+ struct ssb_bus *bus;
+
+ if (!dev)
+ return;
+ bus = dev->bus;
+ if (!ssb_device_is_enabled(dev))
+ ssb_device_enable(dev, 0);
+
+#ifdef CONFIG_SSB_PCICORE_HOSTMODE
+ pc->hostmode = pcicore_is_in_hostmode(pc);
+ if (pc->hostmode)
+ ssb_pcicore_init_hostmode(pc);
+#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
+ if (!pc->hostmode)
+ ssb_pcicore_init_clientmode(pc);
+}
+
+static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address)
+{
+ pcicore_write32(pc, 0x130, address);
+ return pcicore_read32(pc, 0x134);
+}
+
+static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data)
+{
+ pcicore_write32(pc, 0x130, address);
+ pcicore_write32(pc, 0x134, data);
+}
+
+static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
+ u8 address, u16 data)
+{
+ const u16 mdio_control = 0x128;
+ const u16 mdio_data = 0x12C;
+ u32 v;
+ int i;
+
+ v = 0x80; /* Enable Preamble Sequence */
+ v |= 0x2; /* MDIO Clock Divisor */
+ pcicore_write32(pc, mdio_control, v);
+
+ v = (1 << 30); /* Start of Transaction */
+ v |= (1 << 28); /* Write Transaction */
+ v |= (1 << 17); /* Turnaround */
+ v |= (u32)device << 22;
+ v |= (u32)address << 18;
+ v |= data;
+ pcicore_write32(pc, mdio_data, v);
+ /* Wait for the device to complete the transaction */
+ udelay(10);
+ for (i = 0; i < 10; i++) {
+ v = pcicore_read32(pc, mdio_control);
+ if (v & 0x100 /* Trans complete */)
+ break;
+ msleep(1);
+ }
+ pcicore_write32(pc, mdio_control, 0);
+}
+
+static void ssb_broadcast_value(struct ssb_device *dev,
+ u32 address, u32 data)
+{
+ /* This is used for both, PCI and ChipCommon core, so be careful. */
+ BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
+ BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
+
+ ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address);
+ ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */
+ ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data);
+ ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */
+}
+
+static void ssb_commit_settings(struct ssb_bus *bus)
+{
+ struct ssb_device *dev;
+
+ dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
+ if (WARN_ON(!dev))
+ return;
+ /* This forces an update of the cached registers. */
+ ssb_broadcast_value(dev, 0xFD8, 0);
+}
+
+int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
+ struct ssb_device *dev)
+{
+ struct ssb_device *pdev = pc->dev;
+ struct ssb_bus *bus;
+ int err = 0;
+ u32 tmp;
+
+ might_sleep();
+
+ if (!pdev)
+ goto out;
+ bus = pdev->bus;
+
+ /* Enable interrupts for this device. */
+ if (bus->host_pci &&
+ ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE))) {
+ u32 coremask;
+
+ /* Calculate the "coremask" for the device. */
+ coremask = (1 << dev->core_index);
+
+ err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp);
+ if (err)
+ goto out;
+ tmp |= coremask << 8;
+ err = pci_write_config_dword(bus->host_pci, SSB_PCI_IRQMASK, tmp);
+ if (err)
+ goto out;
+ } else {
+ u32 intvec;
+
+ intvec = ssb_read32(pdev, SSB_INTVEC);
+ if ((bus->chip_id & 0xFF00) == 0x4400) {
+ /* Workaround: On the BCM44XX the BPFLAG routing
+ * bit is wrong. Use a hardcoded constant. */
+ intvec |= 0x00000002;
+ } else {
+ tmp = ssb_read32(dev, SSB_TPSFLAG);
+ tmp &= SSB_TPSFLAG_BPFLAG;
+ intvec |= tmp;
+ }
+ ssb_write32(pdev, SSB_INTVEC, intvec);
+ }
+
+ /* Setup PCIcore operation. */
+ if (pc->setup_done)
+ goto out;
+ if (pdev->id.coreid == SSB_DEV_PCI) {
+ tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
+ tmp |= SSB_PCICORE_SBTOPCI_PREF;
+ tmp |= SSB_PCICORE_SBTOPCI_BURST;
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
+
+ if (pdev->id.revision < 5) {
+ tmp = ssb_read32(pdev, SSB_IMCFGLO);
+ tmp &= ~SSB_IMCFGLO_SERTO;
+ tmp |= 2;
+ tmp &= ~SSB_IMCFGLO_REQTO;
+ tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT;
+ ssb_write32(pdev, SSB_IMCFGLO, tmp);
+ ssb_commit_settings(bus);
+ } else if (pdev->id.revision >= 11) {
+ tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
+ tmp |= SSB_PCICORE_SBTOPCI_MRM;
+ pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
+ }
+ } else {
+ WARN_ON(pdev->id.coreid != SSB_DEV_PCIE);
+ //TODO: Better make defines for all these magic PCIE values.
+ if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) {
+ /* TLP Workaround register. */
+ tmp = ssb_pcie_read(pc, 0x4);
+ tmp |= 0x8;
+ ssb_pcie_write(pc, 0x4, tmp);
+ }
+ if (pdev->id.revision == 0) {
+ const u8 serdes_rx_device = 0x1F;
+
+ ssb_pcie_mdio_write(pc, serdes_rx_device,
+ 2 /* Timer */, 0x8128);
+ ssb_pcie_mdio_write(pc, serdes_rx_device,
+ 6 /* CDR */, 0x0100);
+ ssb_pcie_mdio_write(pc, serdes_rx_device,
+ 7 /* CDR BW */, 0x1466);
+ } else if (pdev->id.revision == 1) {
+ /* DLLP Link Control register. */
+ tmp = ssb_pcie_read(pc, 0x100);
+ tmp |= 0x40;
+ ssb_pcie_write(pc, 0x100, tmp);
+ }
+ }
+ pc->setup_done = 1;
+out:
+ return err;
+}
+EXPORT_SYMBOL(ssb_pcicore_dev_irqvecs_enable);
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
new file mode 100644
index 00000000000..85a20546e82
--- /dev/null
+++ b/drivers/ssb/main.c
@@ -0,0 +1,1161 @@
+/*
+ * Sonics Silicon Backplane
+ * Subsystem core
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "ssb_private.h"
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+
+MODULE_DESCRIPTION("Sonics Silicon Backplane driver");
+MODULE_LICENSE("GPL");
+
+
+/* Temporary list of yet-to-be-attached buses */
+static LIST_HEAD(attach_queue);
+/* List if running buses */
+static LIST_HEAD(buses);
+/* Software ID counter */
+static unsigned int next_busnumber;
+/* buses_mutes locks the two buslists and the next_busnumber.
+ * Don't lock this directly, but use ssb_buses_[un]lock() below. */
+static DEFINE_MUTEX(buses_mutex);
+
+/* There are differences in the codeflow, if the bus is
+ * initialized from early boot, as various needed services
+ * are not available early. This is a mechanism to delay
+ * these initializations to after early boot has finished.
+ * It's also used to avoid mutex locking, as that's not
+ * available and needed early. */
+static bool ssb_is_early_boot = 1;
+
+static void ssb_buses_lock(void);
+static void ssb_buses_unlock(void);
+
+
+#ifdef CONFIG_SSB_PCIHOST
+struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev)
+{
+ struct ssb_bus *bus;
+
+ ssb_buses_lock();
+ list_for_each_entry(bus, &buses, list) {
+ if (bus->bustype == SSB_BUSTYPE_PCI &&
+ bus->host_pci == pdev)
+ goto found;
+ }
+ bus = NULL;
+found:
+ ssb_buses_unlock();
+
+ return bus;
+}
+#endif /* CONFIG_SSB_PCIHOST */
+
+static struct ssb_device *ssb_device_get(struct ssb_device *dev)
+{
+ if (dev)
+ get_device(dev->dev);
+ return dev;
+}
+
+static void ssb_device_put(struct ssb_device *dev)
+{
+ if (dev)
+ put_device(dev->dev);
+}
+
+static int ssb_bus_resume(struct ssb_bus *bus)
+{
+ int err;
+
+ ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
+ err = ssb_pcmcia_init(bus);
+ if (err) {
+ /* No need to disable XTAL, as we don't have one on PCMCIA. */
+ return err;
+ }
+ ssb_chipco_resume(&bus->chipco);
+
+ return 0;
+}
+
+static int ssb_device_resume(struct device *dev)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ struct ssb_driver *ssb_drv;
+ struct ssb_bus *bus;
+ int err = 0;
+
+ bus = ssb_dev->bus;
+ if (bus->suspend_cnt == bus->nr_devices) {
+ err = ssb_bus_resume(bus);
+ if (err)
+ return err;
+ }
+ bus->suspend_cnt--;
+ if (dev->driver) {
+ ssb_drv = drv_to_ssb_drv(dev->driver);
+ if (ssb_drv && ssb_drv->resume)
+ err = ssb_drv->resume(ssb_dev);
+ if (err)
+ goto out;
+ }
+out:
+ return err;
+}
+
+static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state)
+{
+ ssb_chipco_suspend(&bus->chipco, state);
+ ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
+
+ /* Reset HW state information in memory, so that HW is
+ * completely reinitialized on resume. */
+ bus->mapped_device = NULL;
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ bus->pcicore.setup_done = 0;
+#endif
+#ifdef CONFIG_SSB_DEBUG
+ bus->powered_up = 0;
+#endif
+}
+
+static int ssb_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ struct ssb_driver *ssb_drv;
+ struct ssb_bus *bus;
+ int err = 0;
+
+ if (dev->driver) {
+ ssb_drv = drv_to_ssb_drv(dev->driver);
+ if (ssb_drv && ssb_drv->suspend)
+ err = ssb_drv->suspend(ssb_dev, state);
+ if (err)
+ goto out;
+ }
+
+ bus = ssb_dev->bus;
+ bus->suspend_cnt++;
+ if (bus->suspend_cnt == bus->nr_devices) {
+ /* All devices suspended. Shutdown the bus. */
+ ssb_bus_suspend(bus, state);
+ }
+
+out:
+ return err;
+}
+
+#ifdef CONFIG_SSB_PCIHOST
+int ssb_devices_freeze(struct ssb_bus *bus)
+{
+ struct ssb_device *dev;
+ struct ssb_driver *drv;
+ int err = 0;
+ int i;
+ pm_message_t state = PMSG_FREEZE;
+
+ /* First check that we are capable to freeze all devices. */
+ for (i = 0; i < bus->nr_devices; i++) {
+ dev = &(bus->devices[i]);
+ if (!dev->dev ||
+ !dev->dev->driver ||
+ !device_is_registered(dev->dev))
+ continue;
+ drv = drv_to_ssb_drv(dev->dev->driver);
+ if (!drv)
+ continue;
+ if (!drv->suspend) {
+ /* Nope, can't suspend this one. */
+ return -EOPNOTSUPP;
+ }
+ }
+ /* Now suspend all devices */
+ for (i = 0; i < bus->nr_devices; i++) {
+ dev = &(bus->devices[i]);
+ if (!dev->dev ||
+ !dev->dev->driver ||
+ !device_is_registered(dev->dev))
+ continue;
+ drv = drv_to_ssb_drv(dev->dev->driver);
+ if (!drv)
+ continue;
+ err = drv->suspend(dev, state);
+ if (err) {
+ ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n",
+ dev->dev->bus_id);
+ goto err_unwind;
+ }
+ }
+
+ return 0;
+err_unwind:
+ for (i--; i >= 0; i--) {
+ dev = &(bus->devices[i]);
+ if (!dev->dev ||
+ !dev->dev->driver ||
+ !device_is_registered(dev->dev))
+ continue;
+ drv = drv_to_ssb_drv(dev->dev->driver);
+ if (!drv)
+ continue;
+ if (drv->resume)
+ drv->resume(dev);
+ }
+ return err;
+}
+
+int ssb_devices_thaw(struct ssb_bus *bus)
+{
+ struct ssb_device *dev;
+ struct ssb_driver *drv;
+ int err;
+ int i;
+
+ for (i = 0; i < bus->nr_devices; i++) {
+ dev = &(bus->devices[i]);
+ if (!dev->dev ||
+ !dev->dev->driver ||
+ !device_is_registered(dev->dev))
+ continue;
+ drv = drv_to_ssb_drv(dev->dev->driver);
+ if (!drv)
+ continue;
+ if (SSB_WARN_ON(!drv->resume))
+ continue;
+ err = drv->resume(dev);
+ if (err) {
+ ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n",
+ dev->dev->bus_id);
+ }
+ }
+
+ return 0;
+}
+#endif /* CONFIG_SSB_PCIHOST */
+
+static void ssb_device_shutdown(struct device *dev)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ struct ssb_driver *ssb_drv;
+
+ if (!dev->driver)
+ return;
+ ssb_drv = drv_to_ssb_drv(dev->driver);
+ if (ssb_drv && ssb_drv->shutdown)
+ ssb_drv->shutdown(ssb_dev);
+}
+
+static int ssb_device_remove(struct device *dev)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver);
+
+ if (ssb_drv && ssb_drv->remove)
+ ssb_drv->remove(ssb_dev);
+ ssb_device_put(ssb_dev);
+
+ return 0;
+}
+
+static int ssb_device_probe(struct device *dev)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver);
+ int err = 0;
+
+ ssb_device_get(ssb_dev);
+ if (ssb_drv && ssb_drv->probe)
+ err = ssb_drv->probe(ssb_dev, &ssb_dev->id);
+ if (err)
+ ssb_device_put(ssb_dev);
+
+ return err;
+}
+
+static int ssb_match_devid(const struct ssb_device_id *tabid,
+ const struct ssb_device_id *devid)
+{
+ if ((tabid->vendor != devid->vendor) &&
+ tabid->vendor != SSB_ANY_VENDOR)
+ return 0;
+ if ((tabid->coreid != devid->coreid) &&
+ tabid->coreid != SSB_ANY_ID)
+ return 0;
+ if ((tabid->revision != devid->revision) &&
+ tabid->revision != SSB_ANY_REV)
+ return 0;
+ return 1;
+}
+
+static int ssb_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+ struct ssb_driver *ssb_drv = drv_to_ssb_drv(drv);
+ const struct ssb_device_id *id;
+
+ for (id = ssb_drv->id_table;
+ id->vendor || id->coreid || id->revision;
+ id++) {
+ if (ssb_match_devid(id, &ssb_dev->id))
+ return 1; /* found */
+ }
+
+ return 0;
+}
+
+static int ssb_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+
+ if (!dev)
+ return -ENODEV;
+
+ return add_uevent_var(env,
+ "MODALIAS=ssb:v%04Xid%04Xrev%02X",
+ ssb_dev->id.vendor, ssb_dev->id.coreid,
+ ssb_dev->id.revision);
+}
+
+static struct bus_type ssb_bustype = {
+ .name = "ssb",
+ .match = ssb_bus_match,
+ .probe = ssb_device_probe,
+ .remove = ssb_device_remove,
+ .shutdown = ssb_device_shutdown,
+ .suspend = ssb_device_suspend,
+ .resume = ssb_device_resume,
+ .uevent = ssb_device_uevent,
+};
+
+static void ssb_buses_lock(void)
+{
+ /* See the comment at the ssb_is_early_boot definition */
+ if (!ssb_is_early_boot)
+ mutex_lock(&buses_mutex);
+}
+
+static void ssb_buses_unlock(void)
+{
+ /* See the comment at the ssb_is_early_boot definition */
+ if (!ssb_is_early_boot)
+ mutex_unlock(&buses_mutex);
+}
+
+static void ssb_devices_unregister(struct ssb_bus *bus)
+{
+ struct ssb_device *sdev;
+ int i;
+
+ for (i = bus->nr_devices - 1; i >= 0; i--) {
+ sdev = &(bus->devices[i]);
+ if (sdev->dev)
+ device_unregister(sdev->dev);
+ }
+}
+
+void ssb_bus_unregister(struct ssb_bus *bus)
+{
+ ssb_buses_lock();
+ ssb_devices_unregister(bus);
+ list_del(&bus->list);
+ ssb_buses_unlock();
+
+ /* ssb_pcmcia_exit(bus); */
+ ssb_pci_exit(bus);
+ ssb_iounmap(bus);
+}
+EXPORT_SYMBOL(ssb_bus_unregister);
+
+static void ssb_release_dev(struct device *dev)
+{
+ struct __ssb_dev_wrapper *devwrap;
+
+ devwrap = container_of(dev, struct __ssb_dev_wrapper, dev);
+ kfree(devwrap);
+}
+
+static int ssb_devices_register(struct ssb_bus *bus)
+{
+ struct ssb_device *sdev;
+ struct device *dev;
+ struct __ssb_dev_wrapper *devwrap;
+ int i, err = 0;
+ int dev_idx = 0;
+
+ for (i = 0; i < bus->nr_devices; i++) {
+ sdev = &(bus->devices[i]);
+
+ /* We don't register SSB-system devices to the kernel,
+ * as the drivers for them are built into SSB. */
+ switch (sdev->id.coreid) {
+ case SSB_DEV_CHIPCOMMON:
+ case SSB_DEV_PCI:
+ case SSB_DEV_PCIE:
+ case SSB_DEV_PCMCIA:
+ case SSB_DEV_MIPS:
+ case SSB_DEV_MIPS_3302:
+ case SSB_DEV_EXTIF:
+ continue;
+ }
+
+ devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL);
+ if (!devwrap) {
+ ssb_printk(KERN_ERR PFX
+ "Could not allocate device\n");
+ err = -ENOMEM;
+ goto error;
+ }
+ dev = &devwrap->dev;
+ devwrap->sdev = sdev;
+
+ dev->release = ssb_release_dev;
+ dev->bus = &ssb_bustype;
+ snprintf(dev->bus_id, sizeof(dev->bus_id),
+ "ssb%u:%d", bus->busnumber, dev_idx);
+
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_PCI:
+#ifdef CONFIG_SSB_PCIHOST
+ sdev->irq = bus->host_pci->irq;
+ dev->parent = &bus->host_pci->dev;
+#endif
+ break;
+ case SSB_BUSTYPE_PCMCIA:
+#ifdef CONFIG_SSB_PCMCIAHOST
+ sdev->irq = bus->host_pcmcia->irq.AssignedIRQ;
+ dev->parent = &bus->host_pcmcia->dev;
+#endif
+ break;
+ case SSB_BUSTYPE_SSB:
+ break;
+ }
+
+ sdev->dev = dev;
+ err = device_register(dev);
+ if (err) {
+ ssb_printk(KERN_ERR PFX
+ "Could not register %s\n",
+ dev->bus_id);
+ /* Set dev to NULL to not unregister
+ * dev on error unwinding. */
+ sdev->dev = NULL;
+ kfree(devwrap);
+ goto error;
+ }
+ dev_idx++;
+ }
+
+ return 0;
+error:
+ /* Unwind the already registered devices. */
+ ssb_devices_unregister(bus);
+ return err;
+}
+
+/* Needs ssb_buses_lock() */
+static int ssb_attach_queued_buses(void)
+{
+ struct ssb_bus *bus, *n;
+ int err = 0;
+ int drop_them_all = 0;
+
+ list_for_each_entry_safe(bus, n, &attach_queue, list) {
+ if (drop_them_all) {
+ list_del(&bus->list);
+ continue;
+ }
+ /* Can't init the PCIcore in ssb_bus_register(), as that
+ * is too early in boot for embedded systems
+ * (no udelay() available). So do it here in attach stage.
+ */
+ err = ssb_bus_powerup(bus, 0);
+ if (err)
+ goto error;
+ ssb_pcicore_init(&bus->pcicore);
+ ssb_bus_may_powerdown(bus);
+
+ err = ssb_devices_register(bus);
+error:
+ if (err) {
+ drop_them_all = 1;
+ list_del(&bus->list);
+ continue;
+ }
+ list_move_tail(&bus->list, &buses);
+ }
+
+ return err;
+}
+
+static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ return readw(bus->mmio + offset);
+}
+
+static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ return readl(bus->mmio + offset);
+}
+
+static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ writew(value, bus->mmio + offset);
+}
+
+static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ offset += dev->core_index * SSB_CORE_SIZE;
+ writel(value, bus->mmio + offset);
+}
+
+/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
+static const struct ssb_bus_ops ssb_ssb_ops = {
+ .read16 = ssb_ssb_read16,
+ .read32 = ssb_ssb_read32,
+ .write16 = ssb_ssb_write16,
+ .write32 = ssb_ssb_write32,
+};
+
+static int ssb_fetch_invariants(struct ssb_bus *bus,
+ ssb_invariants_func_t get_invariants)
+{
+ struct ssb_init_invariants iv;
+ int err;
+
+ memset(&iv, 0, sizeof(iv));
+ err = get_invariants(bus, &iv);
+ if (err)
+ goto out;
+ memcpy(&bus->boardinfo, &iv.boardinfo, sizeof(iv.boardinfo));
+ memcpy(&bus->sprom, &iv.sprom, sizeof(iv.sprom));
+out:
+ return err;
+}
+
+static int ssb_bus_register(struct ssb_bus *bus,
+ ssb_invariants_func_t get_invariants,
+ unsigned long baseaddr)
+{
+ int err;
+
+ spin_lock_init(&bus->bar_lock);
+ INIT_LIST_HEAD(&bus->list);
+
+ /* Powerup the bus */
+ err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
+ if (err)
+ goto out;
+ ssb_buses_lock();
+ bus->busnumber = next_busnumber;
+ /* Scan for devices (cores) */
+ err = ssb_bus_scan(bus, baseaddr);
+ if (err)
+ goto err_disable_xtal;
+
+ /* Init PCI-host device (if any) */
+ err = ssb_pci_init(bus);
+ if (err)
+ goto err_unmap;
+ /* Init PCMCIA-host device (if any) */
+ err = ssb_pcmcia_init(bus);
+ if (err)
+ goto err_pci_exit;
+
+ /* Initialize basic system devices (if available) */
+ err = ssb_bus_powerup(bus, 0);
+ if (err)
+ goto err_pcmcia_exit;
+ ssb_chipcommon_init(&bus->chipco);
+ ssb_mipscore_init(&bus->mipscore);
+ err = ssb_fetch_invariants(bus, get_invariants);
+ if (err) {
+ ssb_bus_may_powerdown(bus);
+ goto err_pcmcia_exit;
+ }
+ ssb_bus_may_powerdown(bus);
+
+ /* Queue it for attach.
+ * See the comment at the ssb_is_early_boot definition. */
+ list_add_tail(&bus->list, &attach_queue);
+ if (!ssb_is_early_boot) {
+ /* This is not early boot, so we must attach the bus now */
+ err = ssb_attach_queued_buses();
+ if (err)
+ goto err_dequeue;
+ }
+ next_busnumber++;
+ ssb_buses_unlock();
+
+out:
+ return err;
+
+err_dequeue:
+ list_del(&bus->list);
+err_pcmcia_exit:
+/* ssb_pcmcia_exit(bus); */
+err_pci_exit:
+ ssb_pci_exit(bus);
+err_unmap:
+ ssb_iounmap(bus);
+err_disable_xtal:
+ ssb_buses_unlock();
+ ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
+ return err;
+}
+
+#ifdef CONFIG_SSB_PCIHOST
+int ssb_bus_pcibus_register(struct ssb_bus *bus,
+ struct pci_dev *host_pci)
+{
+ int err;
+
+ bus->bustype = SSB_BUSTYPE_PCI;
+ bus->host_pci = host_pci;
+ bus->ops = &ssb_pci_ops;
+
+ err = ssb_bus_register(bus, ssb_pci_get_invariants, 0);
+ if (!err) {
+ ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
+ "PCI device %s\n", host_pci->dev.bus_id);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(ssb_bus_pcibus_register);
+#endif /* CONFIG_SSB_PCIHOST */
+
+#ifdef CONFIG_SSB_PCMCIAHOST
+int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
+ struct pcmcia_device *pcmcia_dev,
+ unsigned long baseaddr)
+{
+ int err;
+
+ bus->bustype = SSB_BUSTYPE_PCMCIA;
+ bus->host_pcmcia = pcmcia_dev;
+ bus->ops = &ssb_pcmcia_ops;
+
+ err = ssb_bus_register(bus, ssb_pcmcia_get_invariants, baseaddr);
+ if (!err) {
+ ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
+ "PCMCIA device %s\n", pcmcia_dev->devname);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(ssb_bus_pcmciabus_register);
+#endif /* CONFIG_SSB_PCMCIAHOST */
+
+int ssb_bus_ssbbus_register(struct ssb_bus *bus,
+ unsigned long baseaddr,
+ ssb_invariants_func_t get_invariants)
+{
+ int err;
+
+ bus->bustype = SSB_BUSTYPE_SSB;
+ bus->ops = &ssb_ssb_ops;
+
+ err = ssb_bus_register(bus, get_invariants, baseaddr);
+ if (!err) {
+ ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found at "
+ "address 0x%08lX\n", baseaddr);
+ }
+
+ return err;
+}
+
+int __ssb_driver_register(struct ssb_driver *drv, struct module *owner)
+{
+ drv->drv.name = drv->name;
+ drv->drv.bus = &ssb_bustype;
+ drv->drv.owner = owner;
+
+ return driver_register(&drv->drv);
+}
+EXPORT_SYMBOL(__ssb_driver_register);
+
+void ssb_driver_unregister(struct ssb_driver *drv)
+{
+ driver_unregister(&drv->drv);
+}
+EXPORT_SYMBOL(ssb_driver_unregister);
+
+void ssb_set_devtypedata(struct ssb_device *dev, void *data)
+{
+ struct ssb_bus *bus = dev->bus;
+ struct ssb_device *ent;
+ int i;
+
+ for (i = 0; i < bus->nr_devices; i++) {
+ ent = &(bus->devices[i]);
+ if (ent->id.vendor != dev->id.vendor)
+ continue;
+ if (ent->id.coreid != dev->id.coreid)
+ continue;
+
+ ent->devtypedata = data;
+ }
+}
+EXPORT_SYMBOL(ssb_set_devtypedata);
+
+static u32 clkfactor_f6_resolve(u32 v)
+{
+ /* map the magic values */
+ switch (v) {
+ case SSB_CHIPCO_CLK_F6_2:
+ return 2;
+ case SSB_CHIPCO_CLK_F6_3:
+ return 3;
+ case SSB_CHIPCO_CLK_F6_4:
+ return 4;
+ case SSB_CHIPCO_CLK_F6_5:
+ return 5;
+ case SSB_CHIPCO_CLK_F6_6:
+ return 6;
+ case SSB_CHIPCO_CLK_F6_7:
+ return 7;
+ }
+ return 0;
+}
+
+/* Calculate the speed the backplane would run at a given set of clockcontrol values */
+u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m)
+{
+ u32 n1, n2, clock, m1, m2, m3, mc;
+
+ n1 = (n & SSB_CHIPCO_CLK_N1);
+ n2 = ((n & SSB_CHIPCO_CLK_N2) >> SSB_CHIPCO_CLK_N2_SHIFT);
+
+ switch (plltype) {
+ case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
+ if (m & SSB_CHIPCO_CLK_T6_MMASK)
+ return SSB_CHIPCO_CLK_T6_M0;
+ return SSB_CHIPCO_CLK_T6_M1;
+ case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
+ case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+ case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
+ case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */
+ n1 = clkfactor_f6_resolve(n1);
+ n2 += SSB_CHIPCO_CLK_F5_BIAS;
+ break;
+ case SSB_PLLTYPE_2: /* 48Mhz, 4 dividers */
+ n1 += SSB_CHIPCO_CLK_T2_BIAS;
+ n2 += SSB_CHIPCO_CLK_T2_BIAS;
+ SSB_WARN_ON(!((n1 >= 2) && (n1 <= 7)));
+ SSB_WARN_ON(!((n2 >= 5) && (n2 <= 23)));
+ break;
+ case SSB_PLLTYPE_5: /* 25Mhz, 4 dividers */
+ return 100000000;
+ default:
+ SSB_WARN_ON(1);
+ }
+
+ switch (plltype) {
+ case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+ case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */
+ clock = SSB_CHIPCO_CLK_BASE2 * n1 * n2;
+ break;
+ default:
+ clock = SSB_CHIPCO_CLK_BASE1 * n1 * n2;
+ }
+ if (!clock)
+ return 0;
+
+ m1 = (m & SSB_CHIPCO_CLK_M1);
+ m2 = ((m & SSB_CHIPCO_CLK_M2) >> SSB_CHIPCO_CLK_M2_SHIFT);
+ m3 = ((m & SSB_CHIPCO_CLK_M3) >> SSB_CHIPCO_CLK_M3_SHIFT);
+ mc = ((m & SSB_CHIPCO_CLK_MC) >> SSB_CHIPCO_CLK_MC_SHIFT);
+
+ switch (plltype) {
+ case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
+ case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+ case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
+ case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */
+ m1 = clkfactor_f6_resolve(m1);
+ if ((plltype == SSB_PLLTYPE_1) ||
+ (plltype == SSB_PLLTYPE_3))
+ m2 += SSB_CHIPCO_CLK_F5_BIAS;
+ else
+ m2 = clkfactor_f6_resolve(m2);
+ m3 = clkfactor_f6_resolve(m3);
+
+ switch (mc) {
+ case SSB_CHIPCO_CLK_MC_BYPASS:
+ return clock;
+ case SSB_CHIPCO_CLK_MC_M1:
+ return (clock / m1);
+ case SSB_CHIPCO_CLK_MC_M1M2:
+ return (clock / (m1 * m2));
+ case SSB_CHIPCO_CLK_MC_M1M2M3:
+ return (clock / (m1 * m2 * m3));
+ case SSB_CHIPCO_CLK_MC_M1M3:
+ return (clock / (m1 * m3));
+ }
+ return 0;
+ case SSB_PLLTYPE_2:
+ m1 += SSB_CHIPCO_CLK_T2_BIAS;
+ m2 += SSB_CHIPCO_CLK_T2M2_BIAS;
+ m3 += SSB_CHIPCO_CLK_T2_BIAS;
+ SSB_WARN_ON(!((m1 >= 2) && (m1 <= 7)));
+ SSB_WARN_ON(!((m2 >= 3) && (m2 <= 10)));
+ SSB_WARN_ON(!((m3 >= 2) && (m3 <= 7)));
+
+ if (!(mc & SSB_CHIPCO_CLK_T2MC_M1BYP))
+ clock /= m1;
+ if (!(mc & SSB_CHIPCO_CLK_T2MC_M2BYP))
+ clock /= m2;
+ if (!(mc & SSB_CHIPCO_CLK_T2MC_M3BYP))
+ clock /= m3;
+ return clock;
+ default:
+ SSB_WARN_ON(1);
+ }
+ return 0;
+}
+
+/* Get the current speed the backplane is running at */
+u32 ssb_clockspeed(struct ssb_bus *bus)
+{
+ u32 rate;
+ u32 plltype;
+ u32 clkctl_n, clkctl_m;
+
+ if (ssb_extif_available(&bus->extif))
+ ssb_extif_get_clockcontrol(&bus->extif, &plltype,
+ &clkctl_n, &clkctl_m);
+ else if (bus->chipco.dev)
+ ssb_chipco_get_clockcontrol(&bus->chipco, &plltype,
+ &clkctl_n, &clkctl_m);
+ else
+ return 0;
+
+ if (bus->chip_id == 0x5365) {
+ rate = 100000000;
+ } else {
+ rate = ssb_calc_clock_rate(plltype, clkctl_n, clkctl_m);
+ if (plltype == SSB_PLLTYPE_3) /* 25Mhz, 2 dividers */
+ rate /= 2;
+ }
+
+ return rate;
+}
+EXPORT_SYMBOL(ssb_clockspeed);
+
+static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev)
+{
+ /* The REJECT bit changed position in TMSLOW between
+ * Backplane revisions. */
+ switch (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV) {
+ case SSB_IDLOW_SSBREV_22:
+ return SSB_TMSLOW_REJECT_22;
+ case SSB_IDLOW_SSBREV_23:
+ return SSB_TMSLOW_REJECT_23;
+ default:
+ WARN_ON(1);
+ }
+ return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23);
+}
+
+int ssb_device_is_enabled(struct ssb_device *dev)
+{
+ u32 val;
+ u32 reject;
+
+ reject = ssb_tmslow_reject_bitmask(dev);
+ val = ssb_read32(dev, SSB_TMSLOW);
+ val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | reject;
+
+ return (val == SSB_TMSLOW_CLOCK);
+}
+EXPORT_SYMBOL(ssb_device_is_enabled);
+
+static void ssb_flush_tmslow(struct ssb_device *dev)
+{
+ /* Make _really_ sure the device has finished the TMSLOW
+ * register write transaction, as we risk running into
+ * a machine check exception otherwise.
+ * Do this by reading the register back to commit the
+ * PCI write and delay an additional usec for the device
+ * to react to the change. */
+ ssb_read32(dev, SSB_TMSLOW);
+ udelay(1);
+}
+
+void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags)
+{
+ u32 val;
+
+ ssb_device_disable(dev, core_specific_flags);
+ ssb_write32(dev, SSB_TMSLOW,
+ SSB_TMSLOW_RESET | SSB_TMSLOW_CLOCK |
+ SSB_TMSLOW_FGC | core_specific_flags);
+ ssb_flush_tmslow(dev);
+
+ /* Clear SERR if set. This is a hw bug workaround. */
+ if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_SERR)
+ ssb_write32(dev, SSB_TMSHIGH, 0);
+
+ val = ssb_read32(dev, SSB_IMSTATE);
+ if (val & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) {
+ val &= ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO);
+ ssb_write32(dev, SSB_IMSTATE, val);
+ }
+
+ ssb_write32(dev, SSB_TMSLOW,
+ SSB_TMSLOW_CLOCK | SSB_TMSLOW_FGC |
+ core_specific_flags);
+ ssb_flush_tmslow(dev);
+
+ ssb_write32(dev, SSB_TMSLOW, SSB_TMSLOW_CLOCK |
+ core_specific_flags);
+ ssb_flush_tmslow(dev);
+}
+EXPORT_SYMBOL(ssb_device_enable);
+
+/* Wait for a bit in a register to get set or unset.
+ * timeout is in units of ten-microseconds */
+static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask,
+ int timeout, int set)
+{
+ int i;
+ u32 val;
+
+ for (i = 0; i < timeout; i++) {
+ val = ssb_read32(dev, reg);
+ if (set) {
+ if (val & bitmask)
+ return 0;
+ } else {
+ if (!(val & bitmask))
+ return 0;
+ }
+ udelay(10);
+ }
+ printk(KERN_ERR PFX "Timeout waiting for bitmask %08X on "
+ "register %04X to %s.\n",
+ bitmask, reg, (set ? "set" : "clear"));
+
+ return -ETIMEDOUT;
+}
+
+void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
+{
+ u32 reject;
+
+ if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET)
+ return;
+
+ reject = ssb_tmslow_reject_bitmask(dev);
+ ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
+ ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1);
+ ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
+ ssb_write32(dev, SSB_TMSLOW,
+ SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+ reject | SSB_TMSLOW_RESET |
+ core_specific_flags);
+ ssb_flush_tmslow(dev);
+
+ ssb_write32(dev, SSB_TMSLOW,
+ reject | SSB_TMSLOW_RESET |
+ core_specific_flags);
+ ssb_flush_tmslow(dev);
+}
+EXPORT_SYMBOL(ssb_device_disable);
+
+u32 ssb_dma_translation(struct ssb_device *dev)
+{
+ switch (dev->bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ return 0;
+ case SSB_BUSTYPE_PCI:
+ case SSB_BUSTYPE_PCMCIA:
+ return SSB_PCI_DMA;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(ssb_dma_translation);
+
+int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask)
+{
+ struct device *dev = ssb_dev->dev;
+
+#ifdef CONFIG_SSB_PCIHOST
+ if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI &&
+ !dma_supported(dev, mask))
+ return -EIO;
+#endif
+ dev->coherent_dma_mask = mask;
+ dev->dma_mask = &dev->coherent_dma_mask;
+
+ return 0;
+}
+EXPORT_SYMBOL(ssb_dma_set_mask);
+
+int ssb_bus_may_powerdown(struct ssb_bus *bus)
+{
+ struct ssb_chipcommon *cc;
+ int err = 0;
+
+ /* On buses where more than one core may be working
+ * at a time, we must not powerdown stuff if there are
+ * still cores that may want to run. */
+ if (bus->bustype == SSB_BUSTYPE_SSB)
+ goto out;
+
+ cc = &bus->chipco;
+ ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW);
+ err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
+ if (err)
+ goto error;
+out:
+#ifdef CONFIG_SSB_DEBUG
+ bus->powered_up = 0;
+#endif
+ return err;
+error:
+ ssb_printk(KERN_ERR PFX "Bus powerdown failed\n");
+ goto out;
+}
+EXPORT_SYMBOL(ssb_bus_may_powerdown);
+
+int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
+{
+ struct ssb_chipcommon *cc;
+ int err;
+ enum ssb_clkmode mode;
+
+ err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
+ if (err)
+ goto error;
+ cc = &bus->chipco;
+ mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
+ ssb_chipco_set_clockmode(cc, mode);
+
+#ifdef CONFIG_SSB_DEBUG
+ bus->powered_up = 1;
+#endif
+ return 0;
+error:
+ ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
+ return err;
+}
+EXPORT_SYMBOL(ssb_bus_powerup);
+
+u32 ssb_admatch_base(u32 adm)
+{
+ u32 base = 0;
+
+ switch (adm & SSB_ADM_TYPE) {
+ case SSB_ADM_TYPE0:
+ base = (adm & SSB_ADM_BASE0);
+ break;
+ case SSB_ADM_TYPE1:
+ SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */
+ base = (adm & SSB_ADM_BASE1);
+ break;
+ case SSB_ADM_TYPE2:
+ SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */
+ base = (adm & SSB_ADM_BASE2);
+ break;
+ default:
+ SSB_WARN_ON(1);
+ }
+
+ return base;
+}
+EXPORT_SYMBOL(ssb_admatch_base);
+
+u32 ssb_admatch_size(u32 adm)
+{
+ u32 size = 0;
+
+ switch (adm & SSB_ADM_TYPE) {
+ case SSB_ADM_TYPE0:
+ size = ((adm & SSB_ADM_SZ0) >> SSB_ADM_SZ0_SHIFT);
+ break;
+ case SSB_ADM_TYPE1:
+ SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */
+ size = ((adm & SSB_ADM_SZ1) >> SSB_ADM_SZ1_SHIFT);
+ break;
+ case SSB_ADM_TYPE2:
+ SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */
+ size = ((adm & SSB_ADM_SZ2) >> SSB_ADM_SZ2_SHIFT);
+ break;
+ default:
+ SSB_WARN_ON(1);
+ }
+ size = (1 << (size + 1));
+
+ return size;
+}
+EXPORT_SYMBOL(ssb_admatch_size);
+
+static int __init ssb_modinit(void)
+{
+ int err;
+
+ /* See the comment at the ssb_is_early_boot definition */
+ ssb_is_early_boot = 0;
+ err = bus_register(&ssb_bustype);
+ if (err)
+ return err;
+
+ /* Maybe we already registered some buses at early boot.
+ * Check for this and attach them
+ */
+ ssb_buses_lock();
+ err = ssb_attach_queued_buses();
+ ssb_buses_unlock();
+ if (err)
+ bus_unregister(&ssb_bustype);
+
+ err = b43_pci_ssb_bridge_init();
+ if (err) {
+ ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge "
+ "initialization failed");
+ /* don't fail SSB init because of this */
+ err = 0;
+ }
+
+ return err;
+}
+/* ssb must be initialized after PCI but before the ssb drivers.
+ * That means we must use some initcall between subsys_initcall
+ * and device_initcall. */
+fs_initcall(ssb_modinit);
+
+static void __exit ssb_modexit(void)
+{
+ b43_pci_ssb_bridge_exit();
+ bus_unregister(&ssb_bustype);
+}
+module_exit(ssb_modexit)
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
new file mode 100644
index 00000000000..0ab095c6581
--- /dev/null
+++ b/drivers/ssb/pci.c
@@ -0,0 +1,740 @@
+/*
+ * Sonics Silicon Backplane PCI-Hostbus related functions.
+ *
+ * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
+ * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+ * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+ * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ *
+ * Derived from the Broadcom 4400 device driver.
+ * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "ssb_private.h"
+
+
+/* Define the following to 1 to enable a printk on each coreswitch. */
+#define SSB_VERBOSE_PCICORESWITCH_DEBUG 0
+
+
+/* Lowlevel coreswitching */
+int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
+{
+ int err;
+ int attempts = 0;
+ u32 cur_core;
+
+ while (1) {
+ err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN,
+ (coreidx * SSB_CORE_SIZE)
+ + SSB_ENUM_BASE);
+ if (err)
+ goto error;
+ err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN,
+ &cur_core);
+ if (err)
+ goto error;
+ cur_core = (cur_core - SSB_ENUM_BASE)
+ / SSB_CORE_SIZE;
+ if (cur_core == coreidx)
+ break;
+
+ if (attempts++ > SSB_BAR0_MAX_RETRIES)
+ goto error;
+ udelay(10);
+ }
+ return 0;
+error:
+ ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
+ return -ENODEV;
+}
+
+int ssb_pci_switch_core(struct ssb_bus *bus,
+ struct ssb_device *dev)
+{
+ int err;
+ unsigned long flags;
+
+#if SSB_VERBOSE_PCICORESWITCH_DEBUG
+ ssb_printk(KERN_INFO PFX
+ "Switching to %s core, index %d\n",
+ ssb_core_name(dev->id.coreid),
+ dev->core_index);
+#endif
+
+ spin_lock_irqsave(&bus->bar_lock, flags);
+ err = ssb_pci_switch_coreidx(bus, dev->core_index);
+ if (!err)
+ bus->mapped_device = dev;
+ spin_unlock_irqrestore(&bus->bar_lock, flags);
+
+ return err;
+}
+
+/* Enable/disable the on board crystal oscillator and/or PLL. */
+int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
+{
+ int err;
+ u32 in, out, outenable;
+ u16 pci_status;
+
+ if (bus->bustype != SSB_BUSTYPE_PCI)
+ return 0;
+
+ err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
+ if (err)
+ goto err_pci;
+ err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
+ if (err)
+ goto err_pci;
+ err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
+ if (err)
+ goto err_pci;
+
+ outenable |= what;
+
+ if (turn_on) {
+ /* Avoid glitching the clock if GPRS is already using it.
+ * We can't actually read the state of the PLLPD so we infer it
+ * by the value of XTAL_PU which *is* readable via gpioin.
+ */
+ if (!(in & SSB_GPIO_XTAL)) {
+ if (what & SSB_GPIO_XTAL) {
+ /* Turn the crystal on */
+ out |= SSB_GPIO_XTAL;
+ if (what & SSB_GPIO_PLL)
+ out |= SSB_GPIO_PLL;
+ err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
+ if (err)
+ goto err_pci;
+ err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
+ outenable);
+ if (err)
+ goto err_pci;
+ msleep(1);
+ }
+ if (what & SSB_GPIO_PLL) {
+ /* Turn the PLL on */
+ out &= ~SSB_GPIO_PLL;
+ err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
+ if (err)
+ goto err_pci;
+ msleep(5);
+ }
+ }
+
+ err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
+ if (err)
+ goto err_pci;
+ pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
+ err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
+ if (err)
+ goto err_pci;
+ } else {
+ if (what & SSB_GPIO_XTAL) {
+ /* Turn the crystal off */
+ out &= ~SSB_GPIO_XTAL;
+ }
+ if (what & SSB_GPIO_PLL) {
+ /* Turn the PLL off */
+ out |= SSB_GPIO_PLL;
+ }
+ err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
+ if (err)
+ goto err_pci;
+ err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
+ if (err)
+ goto err_pci;
+ }
+
+out:
+ return err;
+
+err_pci:
+ printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n");
+ err = -EBUSY;
+ goto out;
+}
+
+/* Get the word-offset for a SSB_SPROM_XXX define. */
+#define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16))
+/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
+#define SPEX(_outvar, _offset, _mask, _shift) \
+ out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
+
+static inline u8 ssb_crc8(u8 crc, u8 data)
+{
+ /* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
+ static const u8 t[] = {
+ 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
+ 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
+ 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
+ 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
+ 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
+ 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
+ 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
+ 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
+ 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
+ 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
+ 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
+ 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
+ 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
+ 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
+ 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
+ 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
+ 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
+ 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
+ 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
+ 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
+ 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
+ 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
+ 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
+ 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
+ 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
+ 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
+ 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
+ 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
+ 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
+ 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
+ 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
+ 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
+ };
+ return t[crc ^ data];
+}
+
+static u8 ssb_sprom_crc(const u16 *sprom)
+{
+ int word;
+ u8 crc = 0xFF;
+
+ for (word = 0; word < SSB_SPROMSIZE_WORDS - 1; word++) {
+ crc = ssb_crc8(crc, sprom[word] & 0x00FF);
+ crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
+ }
+ crc = ssb_crc8(crc, sprom[SPOFF(SSB_SPROM_REVISION)] & 0x00FF);
+ crc ^= 0xFF;
+
+ return crc;
+}
+
+static int sprom_check_crc(const u16 *sprom)
+{
+ u8 crc;
+ u8 expected_crc;
+ u16 tmp;
+
+ crc = ssb_sprom_crc(sprom);
+ tmp = sprom[SPOFF(SSB_SPROM_REVISION)] & SSB_SPROM_REVISION_CRC;
+ expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
+ if (crc != expected_crc)
+ return -EPROTO;
+
+ return 0;
+}
+
+static void sprom_do_read(struct ssb_bus *bus, u16 *sprom)
+{
+ int i;
+
+ for (i = 0; i < SSB_SPROMSIZE_WORDS; i++)
+ sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2));
+}
+
+static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
+{
+ struct pci_dev *pdev = bus->host_pci;
+ int i, err;
+ u32 spromctl;
+
+ ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
+ err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
+ if (err)
+ goto err_ctlreg;
+ spromctl |= SSB_SPROMCTL_WE;
+ err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
+ if (err)
+ goto err_ctlreg;
+ ssb_printk(KERN_NOTICE PFX "[ 0%%");
+ msleep(500);
+ for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
+ if (i == SSB_SPROMSIZE_WORDS / 4)
+ ssb_printk("25%%");
+ else if (i == SSB_SPROMSIZE_WORDS / 2)
+ ssb_printk("50%%");
+ else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3)
+ ssb_printk("75%%");
+ else if (i % 2)
+ ssb_printk(".");
+ writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2));
+ mmiowb();
+ msleep(20);
+ }
+ err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
+ if (err)
+ goto err_ctlreg;
+ spromctl &= ~SSB_SPROMCTL_WE;
+ err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
+ if (err)
+ goto err_ctlreg;
+ msleep(500);
+ ssb_printk("100%% ]\n");
+ ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
+
+ return 0;
+err_ctlreg:
+ ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
+ return err;
+}
+
+static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
+{
+ int i;
+ u16 v;
+
+ SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0);
+ SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0);
+ SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0);
+ for (i = 0; i < 3; i++) {
+ v = in[SPOFF(SSB_SPROM1_IL0MAC) + i];
+ *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
+ }
+ for (i = 0; i < 3; i++) {
+ v = in[SPOFF(SSB_SPROM1_ET0MAC) + i];
+ *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
+ }
+ for (i = 0; i < 3; i++) {
+ v = in[SPOFF(SSB_SPROM1_ET1MAC) + i];
+ *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
+ }
+ SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
+ SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
+ SSB_SPROM1_ETHPHY_ET1A_SHIFT);
+ SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
+ SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
+ SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
+ SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
+ SSB_SPROM1_BINF_CCODE_SHIFT);
+ SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
+ SSB_SPROM1_BINF_ANTA_SHIFT);
+ SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
+ SSB_SPROM1_BINF_ANTBG_SHIFT);
+ SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
+ SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
+ SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
+ SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
+ SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
+ SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
+ SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
+ SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
+ SSB_SPROM1_GPIOA_P1_SHIFT);
+ SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
+ SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
+ SSB_SPROM1_GPIOB_P3_SHIFT);
+ SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
+ SSB_SPROM1_MAXPWR_A_SHIFT);
+ SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
+ SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
+ SSB_SPROM1_ITSSI_A_SHIFT);
+ SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
+ SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
+ SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0);
+ SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG,
+ SSB_SPROM1_AGAIN_BG_SHIFT);
+ for (i = 0; i < 4; i++) {
+ v = in[SPOFF(SSB_SPROM1_OEM) + i];
+ *(((__le16 *)out->oem) + i) = cpu_to_le16(v);
+ }
+}
+
+static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in)
+{
+ int i;
+ u16 v;
+
+ SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
+ SPEX(maxpwr_a_hi, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
+ SPEX(maxpwr_a_lo, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
+ SSB_SPROM2_MAXP_A_LO_SHIFT);
+ SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
+ SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
+ SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
+ SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
+ SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
+ SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
+ SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
+ for (i = 0; i < 4; i++) {
+ v = in[SPOFF(SSB_SPROM2_CCODE) + i];
+ *(((__le16 *)out->country_str) + i) = cpu_to_le16(v);
+ }
+}
+
+static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in)
+{
+ out->ofdmapo = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8;
+ out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8;
+ out->ofdmapo <<= 16;
+ out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8;
+ out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8;
+
+ out->ofdmalpo = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8;
+ out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8;
+ out->ofdmalpo <<= 16;
+ out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8;
+ out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8;
+
+ out->ofdmahpo = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8;
+ out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8;
+ out->ofdmahpo <<= 16;
+ out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8;
+ out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8;
+
+ SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON,
+ SSB_SPROM3_GPIOLDC_ON_SHIFT);
+ SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF,
+ SSB_SPROM3_GPIOLDC_OFF_SHIFT);
+ SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0);
+ SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M,
+ SSB_SPROM3_CCKPO_2M_SHIFT);
+ SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M,
+ SSB_SPROM3_CCKPO_55M_SHIFT);
+ SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M,
+ SSB_SPROM3_CCKPO_11M_SHIFT);
+
+ out->ofdmgpo = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8;
+ out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8;
+ out->ofdmgpo <<= 16;
+ out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8;
+ out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8;
+}
+
+static int sprom_extract(struct ssb_bus *bus,
+ struct ssb_sprom *out, const u16 *in)
+{
+ memset(out, 0, sizeof(*out));
+
+ SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0);
+ SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC,
+ SSB_SPROM_REVISION_CRC_SHIFT);
+
+ if ((bus->chip_id & 0xFF00) == 0x4400) {
+ /* Workaround: The BCM44XX chip has a stupid revision
+ * number stored in the SPROM.
+ * Always extract r1. */
+ sprom_extract_r1(&out->r1, in);
+ } else {
+ if (out->revision == 0)
+ goto unsupported;
+ if (out->revision >= 1 && out->revision <= 3)
+ sprom_extract_r1(&out->r1, in);
+ if (out->revision >= 2 && out->revision <= 3)
+ sprom_extract_r2(&out->r2, in);
+ if (out->revision == 3)
+ sprom_extract_r3(&out->r3, in);
+ if (out->revision >= 4)
+ goto unsupported;
+ }
+
+ return 0;
+unsupported:
+ ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d "
+ "detected. Will extract v1\n", out->revision);
+ sprom_extract_r1(&out->r1, in);
+ return 0;
+}
+
+static int ssb_pci_sprom_get(struct ssb_bus *bus,
+ struct ssb_sprom *sprom)
+{
+ int err = -ENOMEM;
+ u16 *buf;
+
+ buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+ if (!buf)
+ goto out;
+ sprom_do_read(bus, buf);
+ err = sprom_check_crc(buf);
+ if (err) {
+ ssb_printk(KERN_WARNING PFX
+ "WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
+ }
+ err = sprom_extract(bus, sprom, buf);
+
+ kfree(buf);
+out:
+ return err;
+}
+
+static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
+ struct ssb_boardinfo *bi)
+{
+ pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
+ &bi->vendor);
+ pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
+ &bi->type);
+ pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
+ &bi->rev);
+}
+
+int ssb_pci_get_invariants(struct ssb_bus *bus,
+ struct ssb_init_invariants *iv)
+{
+ int err;
+
+ err = ssb_pci_sprom_get(bus, &iv->sprom);
+ if (err)
+ goto out;
+ ssb_pci_get_boardinfo(bus, &iv->boardinfo);
+
+out:
+ return err;
+}
+
+#ifdef CONFIG_SSB_DEBUG
+static int ssb_pci_assert_buspower(struct ssb_bus *bus)
+{
+ if (likely(bus->powered_up))
+ return 0;
+
+ printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "
+ "while accessing PCI MMIO space\n");
+ if (bus->power_warn_count <= 10) {
+ bus->power_warn_count++;
+ dump_stack();
+ }
+
+ return -ENODEV;
+}
+#else /* DEBUG */
+static inline int ssb_pci_assert_buspower(struct ssb_bus *bus)
+{
+ return 0;
+}
+#endif /* DEBUG */
+
+static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return 0xFFFF;
+ if (unlikely(bus->mapped_device != dev)) {
+ if (unlikely(ssb_pci_switch_core(bus, dev)))
+ return 0xFFFF;
+ }
+ return ioread16(bus->mmio + offset);
+}
+
+static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return 0xFFFFFFFF;
+ if (unlikely(bus->mapped_device != dev)) {
+ if (unlikely(ssb_pci_switch_core(bus, dev)))
+ return 0xFFFFFFFF;
+ }
+ return ioread32(bus->mmio + offset);
+}
+
+static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return;
+ if (unlikely(bus->mapped_device != dev)) {
+ if (unlikely(ssb_pci_switch_core(bus, dev)))
+ return;
+ }
+ iowrite16(value, bus->mmio + offset);
+}
+
+static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return;
+ if (unlikely(bus->mapped_device != dev)) {
+ if (unlikely(ssb_pci_switch_core(bus, dev)))
+ return;
+ }
+ iowrite32(value, bus->mmio + offset);
+}
+
+/* Not "static", as it's used in main.c */
+const struct ssb_bus_ops ssb_pci_ops = {
+ .read16 = ssb_pci_read16,
+ .read32 = ssb_pci_read32,
+ .write16 = ssb_pci_write16,
+ .write32 = ssb_pci_write32,
+};
+
+static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len)
+{
+ int i, pos = 0;
+
+ for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
+ pos += snprintf(buf + pos, buf_len - pos - 1,
+ "%04X", swab16(sprom[i]) & 0xFFFF);
+ }
+ pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
+
+ return pos + 1;
+}
+
+static int hex2sprom(u16 *sprom, const char *dump, size_t len)
+{
+ char tmp[5] = { 0 };
+ int cnt = 0;
+ unsigned long parsed;
+
+ if (len < SSB_SPROMSIZE_BYTES * 2)
+ return -EINVAL;
+
+ while (cnt < SSB_SPROMSIZE_WORDS) {
+ memcpy(tmp, dump, 4);
+ dump += 4;
+ parsed = simple_strtoul(tmp, NULL, 16);
+ sprom[cnt++] = swab16((u16)parsed);
+ }
+
+ return 0;
+}
+
+static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
+ struct ssb_bus *bus;
+ u16 *sprom;
+ int err = -ENODEV;
+ ssize_t count = 0;
+
+ bus = ssb_pci_dev_to_bus(pdev);
+ if (!bus)
+ goto out;
+ err = -ENOMEM;
+ sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+ if (!sprom)
+ goto out;
+
+ /* Use interruptible locking, as the SPROM write might
+ * be holding the lock for several seconds. So allow userspace
+ * to cancel operation. */
+ err = -ERESTARTSYS;
+ if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
+ goto out_kfree;
+ sprom_do_read(bus, sprom);
+ mutex_unlock(&bus->pci_sprom_mutex);
+
+ count = sprom2hex(sprom, buf, PAGE_SIZE);
+ err = 0;
+
+out_kfree:
+ kfree(sprom);
+out:
+ return err ? err : count;
+}
+
+static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
+ struct ssb_bus *bus;
+ u16 *sprom;
+ int res = 0, err = -ENODEV;
+
+ bus = ssb_pci_dev_to_bus(pdev);
+ if (!bus)
+ goto out;
+ err = -ENOMEM;
+ sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+ if (!sprom)
+ goto out;
+ err = hex2sprom(sprom, buf, count);
+ if (err) {
+ err = -EINVAL;
+ goto out_kfree;
+ }
+ err = sprom_check_crc(sprom);
+ if (err) {
+ err = -EINVAL;
+ goto out_kfree;
+ }
+
+ /* Use interruptible locking, as the SPROM write might
+ * be holding the lock for several seconds. So allow userspace
+ * to cancel operation. */
+ err = -ERESTARTSYS;
+ if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
+ goto out_kfree;
+ err = ssb_devices_freeze(bus);
+ if (err == -EOPNOTSUPP) {
+ ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
+ "No suspend support. Is CONFIG_PM enabled?\n");
+ goto out_unlock;
+ }
+ if (err) {
+ ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
+ goto out_unlock;
+ }
+ res = sprom_do_write(bus, sprom);
+ err = ssb_devices_thaw(bus);
+ if (err)
+ ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
+out_unlock:
+ mutex_unlock(&bus->pci_sprom_mutex);
+out_kfree:
+ kfree(sprom);
+out:
+ if (res)
+ return res;
+ return err ? err : count;
+}
+
+static DEVICE_ATTR(ssb_sprom, 0600,
+ ssb_pci_attr_sprom_show,
+ ssb_pci_attr_sprom_store);
+
+void ssb_pci_exit(struct ssb_bus *bus)
+{
+ struct pci_dev *pdev;
+
+ if (bus->bustype != SSB_BUSTYPE_PCI)
+ return;
+
+ pdev = bus->host_pci;
+ device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
+}
+
+int ssb_pci_init(struct ssb_bus *bus)
+{
+ struct pci_dev *pdev;
+ int err;
+
+ if (bus->bustype != SSB_BUSTYPE_PCI)
+ return 0;
+
+ pdev = bus->host_pci;
+ mutex_init(&bus->pci_sprom_mutex);
+ err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
+ if (err)
+ goto out;
+
+out:
+ return err;
+}
diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c
new file mode 100644
index 00000000000..82a10abef64
--- /dev/null
+++ b/drivers/ssb/pcihost_wrapper.c
@@ -0,0 +1,104 @@
+/*
+ * Sonics Silicon Backplane
+ * PCI Hostdevice wrapper
+ *
+ * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
+ * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/pci.h>
+#include <linux/ssb/ssb.h>
+
+
+#ifdef CONFIG_PM
+static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state)
+{
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+
+ return 0;
+}
+
+static int ssb_pcihost_resume(struct pci_dev *dev)
+{
+ int err;
+
+ pci_set_power_state(dev, 0);
+ err = pci_enable_device(dev);
+ if (err)
+ return err;
+ pci_restore_state(dev);
+
+ return 0;
+}
+#else /* CONFIG_PM */
+# define ssb_pcihost_suspend NULL
+# define ssb_pcihost_resume NULL
+#endif /* CONFIG_PM */
+
+static int ssb_pcihost_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct ssb_bus *ssb;
+ int err = -ENOMEM;
+ const char *name;
+
+ ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
+ if (!ssb)
+ goto out;
+ err = pci_enable_device(dev);
+ if (err)
+ goto err_kfree_ssb;
+ name = dev->dev.bus_id;
+ if (dev->driver && dev->driver->name)
+ name = dev->driver->name;
+ err = pci_request_regions(dev, name);
+ if (err)
+ goto err_pci_disable;
+ pci_set_master(dev);
+
+ err = ssb_bus_pcibus_register(ssb, dev);
+ if (err)
+ goto err_pci_release_regions;
+
+ pci_set_drvdata(dev, ssb);
+
+out:
+ return err;
+
+err_pci_release_regions:
+ pci_release_regions(dev);
+err_pci_disable:
+ pci_disable_device(dev);
+err_kfree_ssb:
+ kfree(ssb);
+ return err;
+}
+
+static void ssb_pcihost_remove(struct pci_dev *dev)
+{
+ struct ssb_bus *ssb = pci_get_drvdata(dev);
+
+ ssb_bus_unregister(ssb);
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+ kfree(ssb);
+ pci_set_drvdata(dev, NULL);
+}
+
+int ssb_pcihost_register(struct pci_driver *driver)
+{
+ driver->probe = ssb_pcihost_probe;
+ driver->remove = ssb_pcihost_remove;
+ driver->suspend = ssb_pcihost_suspend;
+ driver->resume = ssb_pcihost_resume;
+
+ return pci_register_driver(driver);
+}
+EXPORT_SYMBOL(ssb_pcihost_register);
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
new file mode 100644
index 00000000000..bb44a76b3eb
--- /dev/null
+++ b/drivers/ssb/pcmcia.c
@@ -0,0 +1,272 @@
+/*
+ * Sonics Silicon Backplane
+ * PCMCIA-Hostbus related functions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include "ssb_private.h"
+
+
+/* Define the following to 1 to enable a printk on each coreswitch. */
+#define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 0
+
+
+int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
+ u8 coreidx)
+{
+ struct pcmcia_device *pdev = bus->host_pcmcia;
+ int err;
+ int attempts = 0;
+ u32 cur_core;
+ conf_reg_t reg;
+ u32 addr;
+ u32 read_addr;
+
+ addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
+ while (1) {
+ reg.Action = CS_WRITE;
+ reg.Offset = 0x2E;
+ reg.Value = (addr & 0x0000F000) >> 12;
+ err = pcmcia_access_configuration_register(pdev, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+ reg.Offset = 0x30;
+ reg.Value = (addr & 0x00FF0000) >> 16;
+ err = pcmcia_access_configuration_register(pdev, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+ reg.Offset = 0x32;
+ reg.Value = (addr & 0xFF000000) >> 24;
+ err = pcmcia_access_configuration_register(pdev, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+
+ read_addr = 0;
+
+ reg.Action = CS_READ;
+ reg.Offset = 0x2E;
+ err = pcmcia_access_configuration_register(pdev, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+ read_addr |= ((u32)(reg.Value & 0x0F)) << 12;
+ reg.Offset = 0x30;
+ err = pcmcia_access_configuration_register(pdev, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+ read_addr |= ((u32)reg.Value) << 16;
+ reg.Offset = 0x32;
+ err = pcmcia_access_configuration_register(pdev, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+ read_addr |= ((u32)reg.Value) << 24;
+
+ cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE;
+ if (cur_core == coreidx)
+ break;
+
+ if (attempts++ > SSB_BAR0_MAX_RETRIES)
+ goto error;
+ udelay(10);
+ }
+
+ return 0;
+error:
+ ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
+ return -ENODEV;
+}
+
+int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+ struct ssb_device *dev)
+{
+ int err;
+ unsigned long flags;
+
+#if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
+ ssb_printk(KERN_INFO PFX
+ "Switching to %s core, index %d\n",
+ ssb_core_name(dev->id.coreid),
+ dev->core_index);
+#endif
+
+ spin_lock_irqsave(&bus->bar_lock, flags);
+ err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
+ if (!err)
+ bus->mapped_device = dev;
+ spin_unlock_irqrestore(&bus->bar_lock, flags);
+
+ return err;
+}
+
+int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
+{
+ int attempts = 0;
+ unsigned long flags;
+ conf_reg_t reg;
+ int res, err = 0;
+
+ SSB_WARN_ON((seg != 0) && (seg != 1));
+ reg.Offset = 0x34;
+ reg.Function = 0;
+ spin_lock_irqsave(&bus->bar_lock, flags);
+ while (1) {
+ reg.Action = CS_WRITE;
+ reg.Value = seg;
+ res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+ if (unlikely(res != CS_SUCCESS))
+ goto error;
+ reg.Value = 0xFF;
+ reg.Action = CS_READ;
+ res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+ if (unlikely(res != CS_SUCCESS))
+ goto error;
+
+ if (reg.Value == seg)
+ break;
+
+ if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES))
+ goto error;
+ udelay(10);
+ }
+ bus->mapped_pcmcia_seg = seg;
+out_unlock:
+ spin_unlock_irqrestore(&bus->bar_lock, flags);
+ return err;
+error:
+ ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
+ err = -ENODEV;
+ goto out_unlock;
+}
+
+static int select_core_and_segment(struct ssb_device *dev,
+ u16 *offset)
+{
+ struct ssb_bus *bus = dev->bus;
+ int err;
+ u8 need_segment;
+
+ if (*offset >= 0x800) {
+ *offset -= 0x800;
+ need_segment = 1;
+ } else
+ need_segment = 0;
+
+ if (unlikely(dev != bus->mapped_device)) {
+ err = ssb_pcmcia_switch_core(bus, dev);
+ if (unlikely(err))
+ return err;
+ }
+ if (unlikely(need_segment != bus->mapped_pcmcia_seg)) {
+ err = ssb_pcmcia_switch_segment(bus, need_segment);
+ if (unlikely(err))
+ return err;
+ }
+
+ return 0;
+}
+
+static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(select_core_and_segment(dev, &offset)))
+ return 0xFFFF;
+
+ return readw(bus->mmio + offset);
+}
+
+static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
+{
+ struct ssb_bus *bus = dev->bus;
+ u32 lo, hi;
+
+ if (unlikely(select_core_and_segment(dev, &offset)))
+ return 0xFFFFFFFF;
+ lo = readw(bus->mmio + offset);
+ hi = readw(bus->mmio + offset + 2);
+
+ return (lo | (hi << 16));
+}
+
+static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(select_core_and_segment(dev, &offset)))
+ return;
+ writew(value, bus->mmio + offset);
+}
+
+static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
+{
+ struct ssb_bus *bus = dev->bus;
+
+ if (unlikely(select_core_and_segment(dev, &offset)))
+ return;
+ writeb((value & 0xFF000000) >> 24, bus->mmio + offset + 3);
+ writeb((value & 0x00FF0000) >> 16, bus->mmio + offset + 2);
+ writeb((value & 0x0000FF00) >> 8, bus->mmio + offset + 1);
+ writeb((value & 0x000000FF) >> 0, bus->mmio + offset + 0);
+}
+
+/* Not "static", as it's used in main.c */
+const struct ssb_bus_ops ssb_pcmcia_ops = {
+ .read16 = ssb_pcmcia_read16,
+ .read32 = ssb_pcmcia_read32,
+ .write16 = ssb_pcmcia_write16,
+ .write32 = ssb_pcmcia_write32,
+};
+
+int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
+ struct ssb_init_invariants *iv)
+{
+ //TODO
+ return 0;
+}
+
+int ssb_pcmcia_init(struct ssb_bus *bus)
+{
+ conf_reg_t reg;
+ int err;
+
+ if (bus->bustype != SSB_BUSTYPE_PCMCIA)
+ return 0;
+
+ /* Switch segment to a known state and sync
+ * bus->mapped_pcmcia_seg with hardware state. */
+ ssb_pcmcia_switch_segment(bus, 0);
+
+ /* Init IRQ routing */
+ reg.Action = CS_READ;
+ reg.Function = 0;
+ if (bus->chip_id == 0x4306)
+ reg.Offset = 0x00;
+ else
+ reg.Offset = 0x80;
+ err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+ reg.Action = CS_WRITE;
+ reg.Value |= 0x04 | 0x01;
+ err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+ if (err != CS_SUCCESS)
+ goto error;
+
+ return 0;
+error:
+ return -ENODEV;
+}
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
new file mode 100644
index 00000000000..96258c60919
--- /dev/null
+++ b/drivers/ssb/scan.c
@@ -0,0 +1,413 @@
+/*
+ * Sonics Silicon Backplane
+ * Bus scanning
+ *
+ * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
+ * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+ * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+ * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include "ssb_private.h"
+
+
+const char *ssb_core_name(u16 coreid)
+{
+ switch (coreid) {
+ case SSB_DEV_CHIPCOMMON:
+ return "ChipCommon";
+ case SSB_DEV_ILINE20:
+ return "ILine 20";
+ case SSB_DEV_SDRAM:
+ return "SDRAM";
+ case SSB_DEV_PCI:
+ return "PCI";
+ case SSB_DEV_MIPS:
+ return "MIPS";
+ case SSB_DEV_ETHERNET:
+ return "Fast Ethernet";
+ case SSB_DEV_V90:
+ return "V90";
+ case SSB_DEV_USB11_HOSTDEV:
+ return "USB 1.1 Hostdev";
+ case SSB_DEV_ADSL:
+ return "ADSL";
+ case SSB_DEV_ILINE100:
+ return "ILine 100";
+ case SSB_DEV_IPSEC:
+ return "IPSEC";
+ case SSB_DEV_PCMCIA:
+ return "PCMCIA";
+ case SSB_DEV_INTERNAL_MEM:
+ return "Internal Memory";
+ case SSB_DEV_MEMC_SDRAM:
+ return "MEMC SDRAM";
+ case SSB_DEV_EXTIF:
+ return "EXTIF";
+ case SSB_DEV_80211:
+ return "IEEE 802.11";
+ case SSB_DEV_MIPS_3302:
+ return "MIPS 3302";
+ case SSB_DEV_USB11_HOST:
+ return "USB 1.1 Host";
+ case SSB_DEV_USB11_DEV:
+ return "USB 1.1 Device";
+ case SSB_DEV_USB20_HOST:
+ return "USB 2.0 Host";
+ case SSB_DEV_USB20_DEV:
+ return "USB 2.0 Device";
+ case SSB_DEV_SDIO_HOST:
+ return "SDIO Host";
+ case SSB_DEV_ROBOSWITCH:
+ return "Roboswitch";
+ case SSB_DEV_PARA_ATA:
+ return "PATA";
+ case SSB_DEV_SATA_XORDMA:
+ return "SATA XOR-DMA";
+ case SSB_DEV_ETHERNET_GBIT:
+ return "GBit Ethernet";
+ case SSB_DEV_PCIE:
+ return "PCI-E";
+ case SSB_DEV_MIMO_PHY:
+ return "MIMO PHY";
+ case SSB_DEV_SRAM_CTRLR:
+ return "SRAM Controller";
+ case SSB_DEV_MINI_MACPHY:
+ return "Mini MACPHY";
+ case SSB_DEV_ARM_1176:
+ return "ARM 1176";
+ case SSB_DEV_ARM_7TDMI:
+ return "ARM 7TDMI";
+ }
+ return "UNKNOWN";
+}
+
+static u16 pcidev_to_chipid(struct pci_dev *pci_dev)
+{
+ u16 chipid_fallback = 0;
+
+ switch (pci_dev->device) {
+ case 0x4301:
+ chipid_fallback = 0x4301;
+ break;
+ case 0x4305 ... 0x4307:
+ chipid_fallback = 0x4307;
+ break;
+ case 0x4403:
+ chipid_fallback = 0x4402;
+ break;
+ case 0x4610 ... 0x4615:
+ chipid_fallback = 0x4610;
+ break;
+ case 0x4710 ... 0x4715:
+ chipid_fallback = 0x4710;
+ break;
+ case 0x4320 ... 0x4325:
+ chipid_fallback = 0x4309;
+ break;
+ case PCI_DEVICE_ID_BCM4401:
+ case PCI_DEVICE_ID_BCM4401B0:
+ case PCI_DEVICE_ID_BCM4401B1:
+ chipid_fallback = 0x4401;
+ break;
+ default:
+ ssb_printk(KERN_ERR PFX
+ "PCI-ID not in fallback list\n");
+ }
+
+ return chipid_fallback;
+}
+
+static u8 chipid_to_nrcores(u16 chipid)
+{
+ switch (chipid) {
+ case 0x5365:
+ return 7;
+ case 0x4306:
+ return 6;
+ case 0x4310:
+ return 8;
+ case 0x4307:
+ case 0x4301:
+ return 5;
+ case 0x4401:
+ case 0x4402:
+ return 3;
+ case 0x4710:
+ case 0x4610:
+ case 0x4704:
+ return 9;
+ default:
+ ssb_printk(KERN_ERR PFX
+ "CHIPID not in nrcores fallback list\n");
+ }
+
+ return 1;
+}
+
+static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx,
+ u16 offset)
+{
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ offset += current_coreidx * SSB_CORE_SIZE;
+ break;
+ case SSB_BUSTYPE_PCI:
+ break;
+ case SSB_BUSTYPE_PCMCIA:
+ if (offset >= 0x800) {
+ ssb_pcmcia_switch_segment(bus, 1);
+ offset -= 0x800;
+ } else
+ ssb_pcmcia_switch_segment(bus, 0);
+ break;
+ }
+ return readl(bus->mmio + offset);
+}
+
+static int scan_switchcore(struct ssb_bus *bus, u8 coreidx)
+{
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ break;
+ case SSB_BUSTYPE_PCI:
+ return ssb_pci_switch_coreidx(bus, coreidx);
+ case SSB_BUSTYPE_PCMCIA:
+ return ssb_pcmcia_switch_coreidx(bus, coreidx);
+ }
+ return 0;
+}
+
+void ssb_iounmap(struct ssb_bus *bus)
+{
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ case SSB_BUSTYPE_PCMCIA:
+ iounmap(bus->mmio);
+ break;
+ case SSB_BUSTYPE_PCI:
+#ifdef CONFIG_SSB_PCIHOST
+ pci_iounmap(bus->host_pci, bus->mmio);
+#else
+ SSB_BUG_ON(1); /* Can't reach this code. */
+#endif
+ break;
+ }
+ bus->mmio = NULL;
+ bus->mapped_device = NULL;
+}
+
+static void __iomem *ssb_ioremap(struct ssb_bus *bus,
+ unsigned long baseaddr)
+{
+ void __iomem *mmio = NULL;
+
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ /* Only map the first core for now. */
+ /* fallthrough... */
+ case SSB_BUSTYPE_PCMCIA:
+ mmio = ioremap(baseaddr, SSB_CORE_SIZE);
+ break;
+ case SSB_BUSTYPE_PCI:
+#ifdef CONFIG_SSB_PCIHOST
+ mmio = pci_iomap(bus->host_pci, 0, ~0UL);
+#else
+ SSB_BUG_ON(1); /* Can't reach this code. */
+#endif
+ break;
+ }
+
+ return mmio;
+}
+
+static int we_support_multiple_80211_cores(struct ssb_bus *bus)
+{
+ /* More than one 802.11 core is only supported by special chips.
+ * There are chips with two 802.11 cores, but with dangling
+ * pins on the second core. Be careful and reject them here.
+ */
+
+#ifdef CONFIG_SSB_PCIHOST
+ if (bus->bustype == SSB_BUSTYPE_PCI) {
+ if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
+ bus->host_pci->device == 0x4324)
+ return 1;
+ }
+#endif /* CONFIG_SSB_PCIHOST */
+ return 0;
+}
+
+int ssb_bus_scan(struct ssb_bus *bus,
+ unsigned long baseaddr)
+{
+ int err = -ENOMEM;
+ void __iomem *mmio;
+ u32 idhi, cc, rev, tmp;
+ int dev_i, i;
+ struct ssb_device *dev;
+ int nr_80211_cores = 0;
+
+ mmio = ssb_ioremap(bus, baseaddr);
+ if (!mmio)
+ goto out;
+ bus->mmio = mmio;
+
+ err = scan_switchcore(bus, 0); /* Switch to first core */
+ if (err)
+ goto err_unmap;
+
+ idhi = scan_read32(bus, 0, SSB_IDHIGH);
+ cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
+ rev = (idhi & SSB_IDHIGH_RCLO);
+ rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
+
+ bus->nr_devices = 0;
+ if (cc == SSB_DEV_CHIPCOMMON) {
+ tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID);
+
+ bus->chip_id = (tmp & SSB_CHIPCO_IDMASK);
+ bus->chip_rev = (tmp & SSB_CHIPCO_REVMASK) >>
+ SSB_CHIPCO_REVSHIFT;
+ bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >>
+ SSB_CHIPCO_PACKSHIFT;
+ if (rev >= 4) {
+ bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >>
+ SSB_CHIPCO_NRCORESSHIFT;
+ }
+ tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP);
+ bus->chipco.capabilities = tmp;
+ } else {
+ if (bus->bustype == SSB_BUSTYPE_PCI) {
+ bus->chip_id = pcidev_to_chipid(bus->host_pci);
+ pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
+ &bus->chip_rev);
+ bus->chip_package = 0;
+ } else {
+ bus->chip_id = 0x4710;
+ bus->chip_rev = 0;
+ bus->chip_package = 0;
+ }
+ }
+ if (!bus->nr_devices)
+ bus->nr_devices = chipid_to_nrcores(bus->chip_id);
+ if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
+ ssb_printk(KERN_ERR PFX
+ "More than %d ssb cores found (%d)\n",
+ SSB_MAX_NR_CORES, bus->nr_devices);
+ goto err_unmap;
+ }
+ if (bus->bustype == SSB_BUSTYPE_SSB) {
+ /* Now that we know the number of cores,
+ * remap the whole IO space for all cores.
+ */
+ err = -ENOMEM;
+ iounmap(mmio);
+ mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices);
+ if (!mmio)
+ goto out;
+ bus->mmio = mmio;
+ }
+
+ /* Fetch basic information about each core/device */
+ for (i = 0, dev_i = 0; i < bus->nr_devices; i++) {
+ err = scan_switchcore(bus, i);
+ if (err)
+ goto err_unmap;
+ dev = &(bus->devices[dev_i]);
+
+ idhi = scan_read32(bus, i, SSB_IDHIGH);
+ dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
+ dev->id.revision = (idhi & SSB_IDHIGH_RCLO);
+ dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
+ dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT;
+ dev->core_index = i;
+ dev->bus = bus;
+ dev->ops = bus->ops;
+
+ ssb_dprintk(KERN_INFO PFX
+ "Core %d found: %s "
+ "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
+ i, ssb_core_name(dev->id.coreid),
+ dev->id.coreid, dev->id.revision, dev->id.vendor);
+
+ switch (dev->id.coreid) {
+ case SSB_DEV_80211:
+ nr_80211_cores++;
+ if (nr_80211_cores > 1) {
+ if (!we_support_multiple_80211_cores(bus)) {
+ ssb_dprintk(KERN_INFO PFX "Ignoring additional "
+ "802.11 core\n");
+ continue;
+ }
+ }
+ break;
+ case SSB_DEV_EXTIF:
+#ifdef CONFIG_SSB_DRIVER_EXTIF
+ if (bus->extif.dev) {
+ ssb_printk(KERN_WARNING PFX
+ "WARNING: Multiple EXTIFs found\n");
+ break;
+ }
+ bus->extif.dev = dev;
+#endif /* CONFIG_SSB_DRIVER_EXTIF */
+ break;
+ case SSB_DEV_CHIPCOMMON:
+ if (bus->chipco.dev) {
+ ssb_printk(KERN_WARNING PFX
+ "WARNING: Multiple ChipCommon found\n");
+ break;
+ }
+ bus->chipco.dev = dev;
+ break;
+ case SSB_DEV_MIPS:
+ case SSB_DEV_MIPS_3302:
+#ifdef CONFIG_SSB_DRIVER_MIPS
+ if (bus->mipscore.dev) {
+ ssb_printk(KERN_WARNING PFX
+ "WARNING: Multiple MIPS cores found\n");
+ break;
+ }
+ bus->mipscore.dev = dev;
+#endif /* CONFIG_SSB_DRIVER_MIPS */
+ break;
+ case SSB_DEV_PCI:
+ case SSB_DEV_PCIE:
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ if (bus->pcicore.dev) {
+ ssb_printk(KERN_WARNING PFX
+ "WARNING: Multiple PCI(E) cores found\n");
+ break;
+ }
+ bus->pcicore.dev = dev;
+#endif /* CONFIG_SSB_DRIVER_PCICORE */
+ break;
+ default:
+ break;
+ }
+
+ dev_i++;
+ }
+ bus->nr_devices = dev_i;
+
+ err = 0;
+out:
+ return err;
+err_unmap:
+ ssb_iounmap(bus);
+ goto out;
+}
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
new file mode 100644
index 00000000000..a789364264a
--- /dev/null
+++ b/drivers/ssb/ssb_private.h
@@ -0,0 +1,136 @@
+#ifndef LINUX_SSB_PRIVATE_H_
+#define LINUX_SSB_PRIVATE_H_
+
+#include <linux/ssb/ssb.h>
+#include <linux/types.h>
+
+
+#define PFX "ssb: "
+
+#ifdef CONFIG_SSB_SILENT
+# define ssb_printk(fmt, x...) do { /* nothing */ } while (0)
+#else
+# define ssb_printk printk
+#endif /* CONFIG_SSB_SILENT */
+
+/* dprintk: Debugging printk; vanishes for non-debug compilation */
+#ifdef CONFIG_SSB_DEBUG
+# define ssb_dprintk(fmt, x...) ssb_printk(fmt , ##x)
+#else
+# define ssb_dprintk(fmt, x...) do { /* nothing */ } while (0)
+#endif
+
+#ifdef CONFIG_SSB_DEBUG
+# define SSB_WARN_ON(x) WARN_ON(x)
+# define SSB_BUG_ON(x) BUG_ON(x)
+#else
+static inline int __ssb_do_nothing(int x) { return x; }
+# define SSB_WARN_ON(x) __ssb_do_nothing(unlikely(!!(x)))
+# define SSB_BUG_ON(x) __ssb_do_nothing(unlikely(!!(x)))
+#endif
+
+
+/* pci.c */
+#ifdef CONFIG_SSB_PCIHOST
+extern int ssb_pci_switch_core(struct ssb_bus *bus,
+ struct ssb_device *dev);
+extern int ssb_pci_switch_coreidx(struct ssb_bus *bus,
+ u8 coreidx);
+extern int ssb_pci_xtal(struct ssb_bus *bus, u32 what,
+ int turn_on);
+extern int ssb_pci_get_invariants(struct ssb_bus *bus,
+ struct ssb_init_invariants *iv);
+extern void ssb_pci_exit(struct ssb_bus *bus);
+extern int ssb_pci_init(struct ssb_bus *bus);
+extern const struct ssb_bus_ops ssb_pci_ops;
+
+#else /* CONFIG_SSB_PCIHOST */
+
+static inline int ssb_pci_switch_core(struct ssb_bus *bus,
+ struct ssb_device *dev)
+{
+ return 0;
+}
+static inline int ssb_pci_switch_coreidx(struct ssb_bus *bus,
+ u8 coreidx)
+{
+ return 0;
+}
+static inline int ssb_pci_xtal(struct ssb_bus *bus, u32 what,
+ int turn_on)
+{
+ return 0;
+}
+static inline void ssb_pci_exit(struct ssb_bus *bus)
+{
+}
+static inline int ssb_pci_init(struct ssb_bus *bus)
+{
+ return 0;
+}
+#endif /* CONFIG_SSB_PCIHOST */
+
+
+/* pcmcia.c */
+#ifdef CONFIG_SSB_PCMCIAHOST
+extern int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+ struct ssb_device *dev);
+extern int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
+ u8 coreidx);
+extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
+ u8 seg);
+extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
+ struct ssb_init_invariants *iv);
+extern int ssb_pcmcia_init(struct ssb_bus *bus);
+extern const struct ssb_bus_ops ssb_pcmcia_ops;
+#else /* CONFIG_SSB_PCMCIAHOST */
+static inline int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+ struct ssb_device *dev)
+{
+ return 0;
+}
+static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
+ u8 coreidx)
+{
+ return 0;
+}
+static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
+ u8 seg)
+{
+ return 0;
+}
+static inline int ssb_pcmcia_init(struct ssb_bus *bus)
+{
+ return 0;
+}
+#endif /* CONFIG_SSB_PCMCIAHOST */
+
+
+/* scan.c */
+extern const char *ssb_core_name(u16 coreid);
+extern int ssb_bus_scan(struct ssb_bus *bus,
+ unsigned long baseaddr);
+extern void ssb_iounmap(struct ssb_bus *ssb);
+
+
+/* core.c */
+extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m);
+extern int ssb_devices_freeze(struct ssb_bus *bus);
+extern int ssb_devices_thaw(struct ssb_bus *bus);
+extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev);
+
+/* b43_pci_bridge.c */
+#ifdef CONFIG_SSB_PCIHOST
+extern int __init b43_pci_ssb_bridge_init(void);
+extern void __exit b43_pci_ssb_bridge_exit(void);
+#else /* CONFIG_SSB_PCIHOST */
+static inline int b43_pci_ssb_bridge_init(void)
+{
+ return 0;
+}
+static inline void b43_pci_ssb_bridge_exit(void)
+{
+}
+#endif /* CONFIG_SSB_PCIHOST */
+
+#endif /* LINUX_SSB_PRIVATE_H_ */
diff --git a/drivers/tc/.gitignore b/drivers/tc/.gitignore
deleted file mode 100644
index acc0e1e6a65..00000000000
--- a/drivers/tc/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-lk201-map.c
diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile
index c899246bd36..623b2106322 100644
--- a/drivers/tc/Makefile
+++ b/drivers/tc/Makefile
@@ -5,18 +5,3 @@
# Object file lists.
obj-$(CONFIG_TC) += tc.o tc-driver.o
-obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
-
-$(obj)/lk201-map.o: $(obj)/lk201-map.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)/lk201-map.c: $(obj)/%.c: $(src)/%.map
- loadkeys --mktable $< > $@
-
-endif
diff --git a/drivers/tc/lk201-map.c_shipped b/drivers/tc/lk201-map.c_shipped
deleted file mode 100644
index a9df8f5bf62..00000000000
--- a/drivers/tc/lk201-map.c_shipped
+++ /dev/null
@@ -1,265 +0,0 @@
-
-/* Do not edit this file! It was automatically generated by */
-/* loadkeys --mktable defkeymap.map > defkeymap.c */
-
-#include <linux/types.h>
-#include <linux/keyboard.h>
-#include <linux/kd.h>
-
-u_short plain_map[NR_KEYS] = {
- 0xf200, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106,
- 0xf107, 0xf108, 0xf109, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf11b,
- 0xf11c, 0xf110, 0xf111, 0xf112, 0xf113, 0xf060, 0xf031, 0xf032,
- 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 0xf038, 0xf039, 0xf030,
- 0xf02d, 0xf03d, 0xf07f, 0xf114, 0xf115, 0xf116, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf009, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74,
- 0xfb79, 0xfb75, 0xfb69, 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201,
- 0xf117, 0xf118, 0xf119, 0xf307, 0xf308, 0xf309, 0xf30b, 0xf702,
- 0xf207, 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a,
- 0xfb6b, 0xfb6c, 0xf03b, 0xf027, 0xf05c, 0xf603, 0xf304, 0xf305,
- 0xf306, 0xf200, 0xf700, 0xf03e, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
- 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf601,
- 0xf600, 0xf602, 0xf301, 0xf302, 0xf303, 0xf30e, 0xf200, 0xf703,
- 0xf020, 0xf200, 0xf200, 0xf300, 0xf310, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short shift_map[NR_KEYS] = {
- 0xf200, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106,
- 0xf107, 0xf108, 0xf109, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf203,
- 0xf11c, 0xf110, 0xf111, 0xf112, 0xf113, 0xf07e, 0xf021, 0xf040,
- 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026, 0xf02a, 0xf028, 0xf029,
- 0xf05f, 0xf02b, 0xf07f, 0xf114, 0xf115, 0xf116, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf009, 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54,
- 0xfb59, 0xfb55, 0xfb49, 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201,
- 0xf117, 0xf20b, 0xf20a, 0xf307, 0xf308, 0xf309, 0xf30b, 0xf702,
- 0xf207, 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a,
- 0xfb4b, 0xfb4c, 0xf03a, 0xf022, 0xf07c, 0xf603, 0xf304, 0xf305,
- 0xf306, 0xf200, 0xf700, 0xf03c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56,
- 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf200, 0xf601,
- 0xf600, 0xf602, 0xf301, 0xf302, 0xf303, 0xf30e, 0xf200, 0xf703,
- 0xf020, 0xf200, 0xf200, 0xf300, 0xf310, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short altgr_map[NR_KEYS] = {
- 0xf200, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106,
- 0xf107, 0xf108, 0xf109, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf202,
- 0xf11c, 0xf110, 0xf111, 0xf112, 0xf113, 0xf200, 0xf200, 0xf040,
- 0xf200, 0xf024, 0xf200, 0xf200, 0xf07b, 0xf05b, 0xf05d, 0xf07d,
- 0xf05c, 0xf200, 0xf200, 0xf114, 0xf115, 0xf116, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74,
- 0xfb79, 0xfb75, 0xfb69, 0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201,
- 0xf117, 0xf118, 0xf119, 0xf911, 0xf912, 0xf913, 0xf30b, 0xf702,
- 0xf207, 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb67, 0xfb68, 0xfb6a,
- 0xfb6b, 0xfb6c, 0xf200, 0xf200, 0xf200, 0xf603, 0xf90e, 0xf90f,
- 0xf910, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xf916, 0xfb76,
- 0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf601,
- 0xf600, 0xf602, 0xf90b, 0xf90c, 0xf90d, 0xf30e, 0xf200, 0xf703,
- 0xf200, 0xf200, 0xf200, 0xf90a, 0xf310, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short ctrl_map[NR_KEYS] = {
- 0xf200, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106,
- 0xf107, 0xf108, 0xf109, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf204,
- 0xf11c, 0xf110, 0xf111, 0xf112, 0xf113, 0xf81b, 0xf200, 0xf000,
- 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, 0xf07f, 0xf200, 0xf200,
- 0xf01f, 0xf200, 0xf008, 0xf114, 0xf115, 0xf116, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014,
- 0xf019, 0xf015, 0xf009, 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201,
- 0xf117, 0xf118, 0xf119, 0xf307, 0xf308, 0xf309, 0xf30b, 0xf702,
- 0xf207, 0xf001, 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a,
- 0xf00b, 0xf00c, 0xf200, 0xf007, 0xf01c, 0xf603, 0xf304, 0xf305,
- 0xf306, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
- 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf200, 0xf601,
- 0xf600, 0xf602, 0xf301, 0xf302, 0xf303, 0xf30e, 0xf200, 0xf703,
- 0xf000, 0xf200, 0xf200, 0xf300, 0xf310, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short shift_ctrl_map[NR_KEYS] = {
- 0xf200, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106,
- 0xf107, 0xf108, 0xf109, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf200,
- 0xf11c, 0xf110, 0xf111, 0xf112, 0xf113, 0xf200, 0xf200, 0xf000,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf01f, 0xf200, 0xf200, 0xf114, 0xf115, 0xf116, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014,
- 0xf019, 0xf015, 0xf009, 0xf00f, 0xf010, 0xf200, 0xf200, 0xf201,
- 0xf117, 0xf118, 0xf119, 0xf307, 0xf308, 0xf309, 0xf30b, 0xf702,
- 0xf207, 0xf001, 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a,
- 0xf00b, 0xf00c, 0xf200, 0xf200, 0xf200, 0xf603, 0xf304, 0xf305,
- 0xf306, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
- 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf601,
- 0xf600, 0xf602, 0xf301, 0xf302, 0xf303, 0xf30e, 0xf200, 0xf703,
- 0xf200, 0xf200, 0xf200, 0xf300, 0xf310, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short alt_map[NR_KEYS] = {
- 0xf200, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506,
- 0xf507, 0xf508, 0xf509, 0xf50a, 0xf50b, 0xf50c, 0xf50d, 0xf200,
- 0xf11c, 0xf510, 0xf511, 0xf512, 0xf513, 0xf01b, 0xf831, 0xf832,
- 0xf833, 0xf834, 0xf835, 0xf836, 0xf837, 0xf838, 0xf839, 0xf830,
- 0xf82d, 0xf83d, 0xf87f, 0xf114, 0xf115, 0xf116, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf809, 0xf871, 0xf877, 0xf865, 0xf872, 0xf874,
- 0xf879, 0xf875, 0xf869, 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d,
- 0xf117, 0xf118, 0xf119, 0xf907, 0xf908, 0xf909, 0xf30b, 0xf702,
- 0xf207, 0xf861, 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a,
- 0xf86b, 0xf86c, 0xf83b, 0xf827, 0xf85c, 0xf603, 0xf904, 0xf905,
- 0xf906, 0xf200, 0xf700, 0xf200, 0xf87a, 0xf878, 0xf863, 0xf876,
- 0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf210,
- 0xf600, 0xf211, 0xf901, 0xf902, 0xf903, 0xf30e, 0xf200, 0xf703,
- 0xf820, 0xf200, 0xf200, 0xf900, 0xf310, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-static u_short ctrl_alt_map[NR_KEYS] = {
- 0xf200, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506,
- 0xf507, 0xf508, 0xf509, 0xf50a, 0xf50b, 0xf50c, 0xf50d, 0xf200,
- 0xf11c, 0xf510, 0xf511, 0xf512, 0xf513, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf114, 0xf115, 0xf20c, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf811, 0xf817, 0xf805, 0xf812, 0xf814,
- 0xf819, 0xf815, 0xf809, 0xf80f, 0xf810, 0xf200, 0xf200, 0xf201,
- 0xf117, 0xf118, 0xf119, 0xf307, 0xf308, 0xf309, 0xf30b, 0xf702,
- 0xf207, 0xf801, 0xf813, 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a,
- 0xf80b, 0xf80c, 0xf200, 0xf200, 0xf200, 0xf603, 0xf304, 0xf305,
- 0xf306, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816,
- 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf601,
- 0xf600, 0xf602, 0xf301, 0xf302, 0xf303, 0xf30e, 0xf200, 0xf703,
- 0xf200, 0xf200, 0xf200, 0xf300, 0xf20c, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-ushort *key_maps[MAX_NR_KEYMAPS] = {
- plain_map, shift_map, altgr_map, 0,
- ctrl_map, shift_ctrl_map, 0, 0,
- alt_map, 0, 0, 0,
- ctrl_alt_map, 0
-};
-
-unsigned int keymap_count = 7;
-
-
-/*
- * Philosophy: most people do not define more strings, but they who do
- * often want quite a lot of string space. So, we statically allocate
- * the default and allocate dynamically in chunks of 512 bytes.
- */
-
-char func_buf[] = {
- '\033', '[', '[', 'A', 0,
- '\033', '[', '[', 'B', 0,
- '\033', '[', '[', 'C', 0,
- '\033', '[', '[', 'D', 0,
- '\033', '[', '[', 'E', 0,
- '\033', '[', '1', '7', '~', 0,
- '\033', '[', '1', '8', '~', 0,
- '\033', '[', '1', '9', '~', 0,
- '\033', '[', '2', '0', '~', 0,
- '\033', '[', '2', '1', '~', 0,
- '\033', '[', '2', '3', '~', 0,
- '\033', '[', '2', '4', '~', 0,
- '\033', '[', '2', '5', '~', 0,
- '\033', '[', '2', '6', '~', 0,
- '\033', '[', '2', '8', '~', 0,
- '\033', '[', '2', '9', '~', 0,
- '\033', '[', '3', '1', '~', 0,
- '\033', '[', '3', '2', '~', 0,
- '\033', '[', '3', '3', '~', 0,
- '\033', '[', '3', '4', '~', 0,
- '\033', '[', '1', '~', 0,
- '\033', '[', '2', '~', 0,
- '\033', '[', '3', '~', 0,
- '\033', '[', '4', '~', 0,
- '\033', '[', '5', '~', 0,
- '\033', '[', '6', '~', 0,
- '\033', '[', 'M', 0,
- '\033', '[', 'P', 0,
-};
-
-
-char *funcbufptr = func_buf;
-int funcbufsize = sizeof(func_buf);
-int funcbufleft = 0; /* space left */
-
-char *func_table[MAX_NR_FUNC] = {
- func_buf + 0,
- func_buf + 5,
- func_buf + 10,
- func_buf + 15,
- func_buf + 20,
- func_buf + 25,
- func_buf + 31,
- func_buf + 37,
- func_buf + 43,
- func_buf + 49,
- func_buf + 55,
- func_buf + 61,
- func_buf + 67,
- func_buf + 73,
- func_buf + 79,
- func_buf + 85,
- func_buf + 91,
- func_buf + 97,
- func_buf + 103,
- func_buf + 109,
- func_buf + 115,
- func_buf + 120,
- func_buf + 125,
- func_buf + 130,
- func_buf + 135,
- func_buf + 140,
- func_buf + 145,
- 0,
- 0,
- func_buf + 149,
- 0,
-};
-
-struct kbdiacr accent_table[MAX_DIACR] = {
- {'`', 'A', 'À'}, {'`', 'a', 'à'},
- {'\'', 'A', 'Á'}, {'\'', 'a', 'á'},
- {'^', 'A', 'Â'}, {'^', 'a', 'â'},
- {'~', 'A', 'Ã'}, {'~', 'a', 'ã'},
- {'"', 'A', 'Ä'}, {'"', 'a', 'ä'},
- {'O', 'A', 'Å'}, {'o', 'a', 'å'},
- {'0', 'A', 'Å'}, {'0', 'a', 'å'},
- {'A', 'A', 'Å'}, {'a', 'a', 'å'},
- {'A', 'E', 'Æ'}, {'a', 'e', 'æ'},
- {',', 'C', 'Ç'}, {',', 'c', 'ç'},
- {'`', 'E', 'È'}, {'`', 'e', 'è'},
- {'\'', 'E', 'É'}, {'\'', 'e', 'é'},
- {'^', 'E', 'Ê'}, {'^', 'e', 'ê'},
- {'"', 'E', 'Ë'}, {'"', 'e', 'ë'},
- {'`', 'I', 'Ì'}, {'`', 'i', 'ì'},
- {'\'', 'I', 'Í'}, {'\'', 'i', 'í'},
- {'^', 'I', 'Î'}, {'^', 'i', 'î'},
- {'"', 'I', 'Ï'}, {'"', 'i', 'ï'},
- {'-', 'D', 'Ð'}, {'-', 'd', 'ð'},
- {'~', 'N', 'Ñ'}, {'~', 'n', 'ñ'},
- {'`', 'O', 'Ò'}, {'`', 'o', 'ò'},
- {'\'', 'O', 'Ó'}, {'\'', 'o', 'ó'},
- {'^', 'O', 'Ô'}, {'^', 'o', 'ô'},
- {'~', 'O', 'Õ'}, {'~', 'o', 'õ'},
- {'"', 'O', 'Ö'}, {'"', 'o', 'ö'},
- {'/', 'O', 'Ø'}, {'/', 'o', 'ø'},
- {'`', 'U', 'Ù'}, {'`', 'u', 'ù'},
- {'\'', 'U', 'Ú'}, {'\'', 'u', 'ú'},
- {'^', 'U', 'Û'}, {'^', 'u', 'û'},
- {'"', 'U', 'Ü'}, {'"', 'u', 'ü'},
- {'\'', 'Y', 'Ý'}, {'\'', 'y', 'ý'},
- {'T', 'H', 'Þ'}, {'t', 'h', 'þ'},
- {'s', 's', 'ß'}, {'"', 'y', 'ÿ'},
- {'s', 'z', 'ß'}, {'i', 'j', 'ÿ'},
-};
-
-unsigned int accent_table_size = 68;
diff --git a/drivers/tc/lk201-map.map b/drivers/tc/lk201-map.map
deleted file mode 100644
index 2c636b4b782..00000000000
--- a/drivers/tc/lk201-map.map
+++ /dev/null
@@ -1,356 +0,0 @@
-# Default kernel keymap. This uses 7 modifier combinations.
-keymaps 0-2,4-5,8,12
-# Change the above line into
-# keymaps 0-2,4-6,8,12
-# in case you want the entries
-# altgr control keycode 83 = Boot
-# altgr control keycode 111 = Boot
-# below.
-#
-# In fact AltGr is used very little, and one more keymap can
-# be saved by mapping AltGr to Alt (and adapting a few entries):
-# keycode 100 = Alt
-#
-keycode 0x15 = grave tilde
- alt keycode 0x15 = Escape
- control keycode 0x15 = Meta_Escape
-keycode 0x16 = one exclam
- alt keycode 0x16 = Meta_one
-keycode 0x17 = two at at
- control keycode 0x17 = nul
- shift control keycode 0x17 = nul
- alt keycode 0x17 = Meta_two
-keycode 0x18 = three numbersign
- control keycode 0x18 = Escape
- alt keycode 0x18 = Meta_three
-keycode 0x19 = four dollar dollar
- control keycode 0x19 = Control_backslash
- alt keycode 0x19 = Meta_four
-keycode 0x1a = five percent
- control keycode 0x1a = Control_bracketright
- alt keycode 0x1a = Meta_five
-keycode 0x1b = six asciicircum
- control keycode 0x1b = Control_asciicircum
- alt keycode 0x1b = Meta_six
-keycode 0x1c = seven ampersand braceleft
- control keycode 0x1c = Control_underscore
- alt keycode 0x1c = Meta_seven
-keycode 0x1d = eight asterisk bracketleft
- control keycode 0x1d = Delete
- alt keycode 0x1d = Meta_eight
-keycode 0x1e = nine parenleft bracketright
- alt keycode 0x1e = Meta_nine
-keycode 0x1f = zero parenright braceright
- alt keycode 0x1f = Meta_zero
-keycode 0x20 = minus underscore backslash
- control keycode 0x20 = Control_underscore
- shift control keycode 0x20 = Control_underscore
- alt keycode 0x20 = Meta_minus
-keycode 0x21 = equal plus
- alt keycode 0x21 = Meta_equal
-keycode 0x22 = Delete Delete
- control keycode 0x22 = BackSpace
- alt keycode 0x22 = Meta_Delete
-keycode 0x2a = Tab Tab
- alt keycode 0x2a = Meta_Tab
-keycode 0x2b = q
-keycode 0x2c = w
-keycode 0x2d = e
- altgr keycode 0x2d = Hex_E
-keycode 0x2e = r
-keycode 0x2f = t
-keycode 0x30 = y
-keycode 0x31 = u
-keycode 0x32 = i
-keycode 0x33 = o
-keycode 0x34 = p
-keycode 0x35 = bracketleft braceleft
- control keycode 0x35 = Escape
- alt keycode 0x35 = Meta_bracketleft
-keycode 0x36 = bracketright braceright asciitilde
- control keycode 0x36 = Control_bracketright
- alt keycode 0x36 = Meta_bracketright
-keycode 0x37 = Return
- alt keycode 0x37 = Meta_Control_m
-keycode 0x3f = Control
-keycode 0x41 = a
- altgr keycode 0x41 = Hex_A
-keycode 0x42 = s
-keycode 0x43 = d
- altgr keycode 0x43 = Hex_D
-keycode 0x44 = f
- altgr keycode 0x44 = Hex_F
-keycode 0x45 = g
-keycode 0x46 = h
-keycode 0x47 = j
-keycode 0x48 = k
-keycode 0x49 = l
-keycode 0x4a = semicolon colon
- alt keycode 0x4a = Meta_semicolon
-keycode 0x4b = apostrophe quotedbl
- control keycode 0x4b = Control_g
- alt keycode 0x4b = Meta_apostrophe
-# keycode 41 = grave asciitilde
-# control keycode 41 = nul
-# alt keycode 41 = Meta_grave
-keycode 0x52 = Shift
-keycode 0x4c = backslash bar
- control keycode 0x4c = Control_backslash
- alt keycode 0x4c = Meta_backslash
-keycode 0x53 = greater less
-keycode 0x54 = z
-keycode 0x55 = x
-keycode 0x56 = c
- altgr keycode 0x56 = Hex_C
-keycode 0x57 = v
-keycode 0x58 = b
- altgr keycode 0x58 = Hex_B
-keycode 0x59 = n
-keycode 0x5a = m
-keycode 0x5b = comma less
- alt keycode 0x5b = Meta_comma
-keycode 0x5c = period greater
- control keycode 0x5c = Compose
- alt keycode 0x5c = Meta_period
-keycode 0x5d = slash question
- control keycode 0x5d = Delete
- alt keycode 0x5d = Meta_slash
-
-keycode 0x67 = Alt
-keycode 0x68 = space space
- control keycode 0x68 = nul
- alt keycode 0x68 = Meta_space
-keycode 0x40 = Caps_Lock
-keycode 0x01 = F1
- control keycode 0x01 = F1
- alt keycode 0x01 = Console_1
- control alt keycode 0x01 = Console_1
-keycode 0x02 = F2
- control keycode 0x02 = F2
- alt keycode 0x02 = Console_2
- control alt keycode 0x02 = Console_2
-keycode 0x03 = F3
- control keycode 0x03 = F3
- alt keycode 0x03 = Console_3
- control alt keycode 0x03 = Console_3
-keycode 0x04 = F4
- control keycode 0x04 = F4
- alt keycode 0x04 = Console_4
- control alt keycode 0x04 = Console_4
-keycode 0x05 = F5
- control keycode 0x05 = F5
- alt keycode 0x05 = Console_5
- control alt keycode 0x05 = Console_5
-keycode 0x06 = F6
- control keycode 0x06 = F6
- alt keycode 0x06 = Console_6
- control alt keycode 0x06 = Console_6
-keycode 0x07 = F7
- control keycode 0x07 = F7
- alt keycode 0x07 = Console_7
- control alt keycode 0x07 = Console_7
-keycode 0x08 = F8
- control keycode 0x08 = F8
- alt keycode 0x08 = Console_8
- control alt keycode 0x08 = Console_8
-keycode 0x09 = F9
- control keycode 0x09 = F9
- alt keycode 0x09 = Console_9
- control alt keycode 0x09 = Console_9
-keycode 0x0a = F10
- control keycode 0x0a = F10
- alt keycode 0x0a = Console_10
- control alt keycode 0x0a = Console_10
-keycode 0x0b = F11
- control keycode 0x0b = F11
- alt keycode 0x0b = Console_11
- control alt keycode 0x0b = Console_11
-keycode 0x0c = F12
- control keycode 0x0c = F12
- alt keycode 0x0c = Console_12
- control alt keycode 0x0c = Console_12
-keycode 0x0d = F13
- control keycode 0x0d = F13
- alt keycode 0x0d = Console_13
- control alt keycode 0x0d = Console_13
-keycode 0x0e = F14
- control keycode 0x0e = F14
- alt keycode 0x0e = Console_14
- control alt keycode 0x0e = Console_14
-
-keycode 0x11 = F17
- control keycode 0x11 = F17
- alt keycode 0x11 = Console_17
- control alt keycode 0x11 = Console_17
-keycode 0x12 = F18
- control keycode 0x12 = F18
- alt keycode 0x12 = Console_18
- control alt keycode 0x12 = Console_18
-keycode 0x13 = F19
- control keycode 0x13 = F19
- alt keycode 0x13 = Console_19
- control alt keycode 0x13 = Console_19
-keycode 0x14 = F20
- control keycode 0x14 = F20
- alt keycode 0x14 = Console_20
- control alt keycode 0x14 = Console_20
-
-
-keycode 0x3b = KP_7
- alt keycode 0x3b = Ascii_7
- altgr keycode 0x3b = Hex_7
-keycode 0x3c = KP_8
- alt keycode 0x3c = Ascii_8
- altgr keycode 0x3c = Hex_8
-keycode 0x3d = KP_9
- alt keycode 0x3d = Ascii_9
- altgr keycode 0x3d = Hex_9
-keycode 0x3e = KP_Subtract
-keycode 0x4e = KP_4
- alt keycode 0x4e = Ascii_4
- altgr keycode 0x4e = Hex_4
-keycode 0x4f = KP_5
- alt keycode 0x4f = Ascii_5
- altgr keycode 0x4f = Hex_5
-keycode 0x50 = KP_6
- alt keycode 0x50 = Ascii_6
- altgr keycode 0x50 = Hex_6
-keycode 0x62 = KP_1
- alt keycode 0x62 = Ascii_1
- altgr keycode 0x62 = Hex_1
-keycode 0x63 = KP_2
- alt keycode 0x63 = Ascii_2
- altgr keycode 0x63 = Hex_2
-keycode 0x64 = KP_3
- alt keycode 0x64 = Ascii_3
- altgr keycode 0x64 = Hex_3
-keycode 0x6b = KP_0
- alt keycode 0x6b = Ascii_0
- altgr keycode 0x6b = Hex_0
-keycode 0x6c = KP_Period
-# altgr control keycode 0x6c = Boot
- control alt keycode 0x6c = Boot
-keycode 0x65 = KP_Enter
-
-keycode 0x3f = Control
-
-# keycode 100 = AltGr
-
-keycode 0x23 = Find
-keycode 0x4d = Up
-keycode 0x39 = Prior
- shift keycode 0x39 = Scroll_Backward
-keycode 0x5f = Left
- alt keycode 0x5f = Decr_Console
-keycode 0x61 = Right
- alt keycode 0x61 = Incr_Console
-keycode 0x38 = Select
-keycode 0x60 = Down
-keycode 0x3a = Next
- shift keycode 0x3a = Scroll_Forward
-keycode 0x24 = Insert
-keycode 0x25 = Remove
-# altgr control keycode 0x25 = Boot
- control alt keycode 0x25 = Boot
-
-keycode 0x0f = Help Show_Memory Show_Registers
- control keycode 0x0f = Show_State
-
-keycode 0x10 = Do
-
-string F1 = "\033[[A"
-string F2 = "\033[[B"
-string F3 = "\033[[C"
-string F4 = "\033[[D"
-string F5 = "\033[[E"
-string F6 = "\033[17~"
-string F7 = "\033[18~"
-string F8 = "\033[19~"
-string F9 = "\033[20~"
-string F10 = "\033[21~"
-string F11 = "\033[23~"
-string F12 = "\033[24~"
-string F13 = "\033[25~"
-string F14 = "\033[26~"
-string F15 = "\033[28~"
-string F16 = "\033[29~"
-string F17 = "\033[31~"
-string F18 = "\033[32~"
-string F19 = "\033[33~"
-string F20 = "\033[34~"
-string Find = "\033[1~"
-string Insert = "\033[2~"
-string Remove = "\033[3~"
-string Select = "\033[4~"
-string Prior = "\033[5~"
-string Next = "\033[6~"
-string Macro = "\033[M"
-string Pause = "\033[P"
-compose '`' 'A' to 'À'
-compose '`' 'a' to 'à'
-compose '\'' 'A' to 'Á'
-compose '\'' 'a' to 'á'
-compose '^' 'A' to 'Â'
-compose '^' 'a' to 'â'
-compose '~' 'A' to 'Ã'
-compose '~' 'a' to 'ã'
-compose '"' 'A' to 'Ä'
-compose '"' 'a' to 'ä'
-compose 'O' 'A' to 'Å'
-compose 'o' 'a' to 'å'
-compose '0' 'A' to 'Å'
-compose '0' 'a' to 'å'
-compose 'A' 'A' to 'Å'
-compose 'a' 'a' to 'å'
-compose 'A' 'E' to 'Æ'
-compose 'a' 'e' to 'æ'
-compose ',' 'C' to 'Ç'
-compose ',' 'c' to 'ç'
-compose '`' 'E' to 'È'
-compose '`' 'e' to 'è'
-compose '\'' 'E' to 'É'
-compose '\'' 'e' to 'é'
-compose '^' 'E' to 'Ê'
-compose '^' 'e' to 'ê'
-compose '"' 'E' to 'Ë'
-compose '"' 'e' to 'ë'
-compose '`' 'I' to 'Ì'
-compose '`' 'i' to 'ì'
-compose '\'' 'I' to 'Í'
-compose '\'' 'i' to 'í'
-compose '^' 'I' to 'Î'
-compose '^' 'i' to 'î'
-compose '"' 'I' to 'Ï'
-compose '"' 'i' to 'ï'
-compose '-' 'D' to 'Ð'
-compose '-' 'd' to 'ð'
-compose '~' 'N' to 'Ñ'
-compose '~' 'n' to 'ñ'
-compose '`' 'O' to 'Ò'
-compose '`' 'o' to 'ò'
-compose '\'' 'O' to 'Ó'
-compose '\'' 'o' to 'ó'
-compose '^' 'O' to 'Ô'
-compose '^' 'o' to 'ô'
-compose '~' 'O' to 'Õ'
-compose '~' 'o' to 'õ'
-compose '"' 'O' to 'Ö'
-compose '"' 'o' to 'ö'
-compose '/' 'O' to 'Ø'
-compose '/' 'o' to 'ø'
-compose '`' 'U' to 'Ù'
-compose '`' 'u' to 'ù'
-compose '\'' 'U' to 'Ú'
-compose '\'' 'u' to 'ú'
-compose '^' 'U' to 'Û'
-compose '^' 'u' to 'û'
-compose '"' 'U' to 'Ü'
-compose '"' 'u' to 'ü'
-compose '\'' 'Y' to 'Ý'
-compose '\'' 'y' to 'ý'
-compose 'T' 'H' to 'Þ'
-compose 't' 'h' to 'þ'
-compose 's' 's' to 'ß'
-compose '"' 'y' to 'ÿ'
-compose 's' 'z' to 'ß'
-compose 'i' 'j' to 'ÿ'
diff --git a/drivers/tc/lk201-remap.c b/drivers/tc/lk201-remap.c
deleted file mode 100644
index d39098c2720..00000000000
--- a/drivers/tc/lk201-remap.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Keyboard mappings for DEC LK201/401/501 keyboards
- *
- * 17.05.99 Michael Engel (engel@unix-ag.org)
- *
- * DEC US keyboards generate keycodes in the range 0x55 - 0xfb
- *
- * This conflicts with Linux scancode conventions which define
- * 0x00-0x7f as "normal" and 0x80-0xff as "shifted" scancodes, so we
- * have to remap the keycodes to 0x00-0x7f with the scancodeRemap
- * array. The generated scancode is simply the number of the key counted
- * from the left upper to the right lower corner of the keyboard ...
- *
- * These scancodes are then being remapped (I hope ;-)) with the
- * lk501*map[] arrays which define scancode -> Linux code mapping
- *
- * Oh man is this horrible ;-)
- *
- * Scancodes with dual labels exist for keyboards as follows:
- *
- * code: left label / right label
- *
- * 0x73: LKx01, LK421 / LK443, LK444
- * 0x74: LKx01, LK421 / LK443, LK444
- * 0x7c: LKx01, LK421 / LK443, LK444
- * 0x8a: LKx01, LK421 / LK443, LK444
- * 0x8b: LKx01, LK421 / LK443, LK444
- * 0x8c: LKx01, LK421 / LK443, LK444
- * 0x8d: LKx01, LK421 / LK443, LK444
- * 0x8e: LKx01, LK421 / LK443, LK444
- * 0x8f: LKx01, LK421 / LK443, LK444
- * 0x9c: LKx01, LK421 / LK443, LK444
- * 0xa1: LKx01, LK421 / LK443, LK444
- * 0xa2: LKx01, LK421 / LK443, LK444
- * 0xa3: LKx01, LK421 / LK443, LK444
- * 0xa4: LKx01, LK421 / LK443, LK444
- * 0xad: LK421 / LK443, LK444
- * 0xc9: LKx01, LK421, LK443 / LK444
- * 0xf7: LKx01, LK443 / LK444
- */
-
-unsigned char scancodeRemap[256] = {
-/* ----- */
-/* 0 */ 0, 0, 0, 0,
-/* ----- */
-/* 4 */ 0, 0, 0, 0,
-/* ----- */
-/* 8 */ 0, 0, 0, 0,
-/* ----- */
-/* c */ 0, 0, 0, 0,
-/* ----- */
-/* 10 */ 0, 0, 0, 0,
-/* ----- */
-/* 14 */ 0, 0, 0, 0,
-/* ----- */
-/* 18 */ 0, 0, 0, 0,
-/* ----- */
-/* 1c */ 0, 0, 0, 0,
-/* ----- */
-/* 20 */ 0, 0, 0, 0,
-/* ----- */
-/* 24 */ 0, 0, 0, 0,
-/* ----- */
-/* 28 */ 0, 0, 0, 0,
-/* ----- */
-/* 2c */ 0, 0, 0, 0,
-/* ----- */
-/* 30 */ 0, 0, 0, 0,
-/* ----- */
-/* 34 */ 0, 0, 0, 0,
-/* ----- */
-/* 38 */ 0, 0, 0, 0,
-/* ----- */
-/* 3c */ 0, 0, 0, 0,
-/* ----- */
-/* 40 */ 0, 0, 0, 0,
-/* ----- */
-/* 44 */ 0, 0, 0, 0,
-/* ----- */
-/* 48 */ 0, 0, 0, 0,
-/* ----- */
-/* 4c */ 0, 0, 0, 0,
-/* ----- */
-/* 50 */ 0, 0, 0, 0,
-/* ----- ESC F1 F2 */
-/* 54 */ 0, 0, 0x01, 0x02,
-/* ----- F3 F4 F5 */
-/* 58 */ 0x03, 0x04, 0x05, 0,
-/* ----- */
-/* 5c */ 0, 0, 0, 0,
-/* ----- */
-/* 60 */ 0, 0, 0, 0,
-/* ----- F6 F7 F8 F9 */
-/* 64 */ 0x06, 0x07, 0x08, 0x09,
-/* ----- F10 */
-/* 68 */ 0x0a, 0, 0, 0,
-/* ----- */
-/* 6c */ 0, 0, 0, 0,
-/* ----- F11 F12 F13/PRNT SCRN */
-/* 70 */ 0, 0x0b, 0x0c, 0x0d,
-/* ----- F14/SCRL LCK */
-/* 74 */ 0x0e, 0, 0, 0,
-/* ----- */
-/* 78 */ 0, 0, 0, 0,
-/* ----- HELP/PAUSE DO */
-/* 7c */ 0x0f, 0x10, 0, 0,
-/* ----- F17 F18 F19 F20 */
-/* 80 */ 0x11, 0x12, 0x13, 0x14,
-/* ----- */
-/* 84 */ 0, 0, 0, 0,
-/* ----- FIND/INSERT INSERT/HOME */
-/* 88 */ 0, 0, 0x23, 0x24,
-/* ----- REMOVE/PG UP SELECT/DELETE PREVIOUS/END NEXT/PG DN */
-/* 8c */ 0x25, 0x38, 0x39, 0x3a,
-/* ----- KP 0 */
-/* 90 */ 0, 0, 0x6b, 0,
-/* ----- KP . KP ENTER KP 1 KP 2 */
-/* 94 */ 0x6c, 0x65, 0x62, 0x63,
-/* ----- KP 3 KP 4 KP 5 KP 6 */
-/* 98 */ 0x64, 0x4e, 0x4f, 0x50,
-/* ----- KP ,/KP + KP 7 KP 8 KP 9 */
-/* 9c */ 0x51, 0x3b, 0x3c, 0x3d,
-/* ----- KP - KP F1/NUM LCK KP F2/KP / KP F3/KP * */
-/* a0 */ 0x3e, 0x26, 0x27, 0x28,
-/* ----- KP F4/KP - LEFT */
-/* a4 */ 0x29, 0, 0, 0x5f,
-/* ----- RIGHT DOWN UP SHIFT Rt */
-/* a8 */ 0x61, 0x60, 0x4d, 0x5e,
-/* ----- ALT COMP Rt/CTRL Rt SHIFT CONTROL */
-/* ac */ 0, 0, 0x52, 0x3f,
-/* ----- CAPS COMPOSE ALT Rt */
-/* b0 */ 0x40, 0x67, 0, 0,
-/* ----- */
-/* b4 */ 0, 0, 0, 0,
-/* ----- */
-/* b8 */ 0, 0, 0, 0,
-/* ----- BKSP RET TAB ` */
-/* bc */ 0x22, 0x37, 0x2a, 0x15,
-/* ----- 1 q a z */
-/* c0 */ 0x16, 0x2b, 0x41, 0x54,
-/* ----- 2 w s */
-/* c4 */ 0, 0x17, 0x2c, 0x42,
-/* ----- x </\\ 3 */
-/* c8 */ 0x55, 0x53, 0, 0x18,
-/* ----- e d c */
-/* cc */ 0x2d, 0x43, 0x56, 0,
-/* ----- 4 r f v */
-/* d0 */ 0x19, 0x2e, 0x44, 0x57,
-/* ----- SPACE 5 t */
-/* d4 */ 0x68, 0, 0x1a, 0x2f,
-/* ----- g b 6 */
-/* d8 */ 0x45, 0x58, 0, 0x1b,
-/* ----- y h n */
-/* dc */ 0x30, 0x46, 0x59, 0,
-/* ----- 7 u j m */
-/* e0 */ 0x1c, 0x31, 0x47, 0x5a,
-/* ----- 8 i k */
-/* e4 */ 0, 0x1d, 0x32, 0x48,
-/* ----- , 9 o */
-/* e8 */ 0x5b, 0, 0x1e, 0x33,
-/* ----- l . 0 */
-/* ec */ 0x49, 0x5c, 0, 0x1f,
-/* ----- p ; / */
-/* f0 */ 0x34, 0, 0x4a, 0x5d,
-/* ----- = ] \\/\' */
-/* f4 */ 0, 0x21, 0x36, 0x4c,
-/* ----- - [ \' */
-/* f8 */ 0, 0x20, 0x35, 0x4b,
-/* ----- */
-/* fc */ 0, 0, 0, 0,
-};
-
diff --git a/drivers/tc/lk201.c b/drivers/tc/lk201.c
deleted file mode 100644
index a90c255f079..00000000000
--- a/drivers/tc/lk201.c
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1999-2002 Harald Koerfgen <hkoerfg@web.de>
- * Copyright (C) 2001, 2002, 2003, 2004 Maciej W. Rozycki
- */
-
-
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/kbd_ll.h>
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-
-#include <asm/keyboard.h>
-#include <asm/dec/tc.h>
-#include <asm/dec/machtype.h>
-#include <asm/dec/serial.h>
-
-#include "lk201.h"
-
-/*
- * Only handle DECstations that have an LK201 interface.
- * Maxine uses LK501 at the Access.Bus and various DECsystems
- * have no keyboard interface at all.
- */
-#define LK_IFACE (mips_machtype == MACH_DS23100 || \
- mips_machtype == MACH_DS5000_200 || \
- mips_machtype == MACH_DS5000_1XX || \
- mips_machtype == MACH_DS5000_2X0)
-/*
- * These use the Z8530 SCC. Others use the DZ11.
- */
-#define LK_IFACE_ZS (mips_machtype == MACH_DS5000_1XX || \
- mips_machtype == MACH_DS5000_2X0)
-
-/* Simple translation table for the SysRq keys */
-
-#ifdef CONFIG_MAGIC_SYSRQ
-/*
- * Actually no translation at all, at least until we figure out
- * how to define SysRq for LK201 and friends. --macro
- */
-unsigned char lk201_sysrq_xlate[128];
-unsigned char *kbd_sysrq_xlate = lk201_sysrq_xlate;
-
-unsigned char kbd_sysrq_key = -1;
-#endif
-
-#define KEYB_LINE 3
-
-static int __init lk201_init(void *);
-static void __init lk201_info(void *);
-static void lk201_rx_char(unsigned char, unsigned char);
-
-static struct dec_serial_hook lk201_hook = {
- .init_channel = lk201_init,
- .init_info = lk201_info,
- .rx_char = NULL,
- .poll_rx_char = NULL,
- .poll_tx_char = NULL,
- .cflags = B4800 | CS8 | CSTOPB | CLOCAL,
-};
-
-/*
- * This is used during keyboard initialisation
- */
-static unsigned char lk201_reset_string[] = {
- LK_CMD_SET_DEFAULTS,
- LK_CMD_MODE(LK_MODE_RPT_DOWN, 1),
- LK_CMD_MODE(LK_MODE_RPT_DOWN, 2),
- LK_CMD_MODE(LK_MODE_RPT_DOWN, 3),
- LK_CMD_MODE(LK_MODE_RPT_DOWN, 4),
- LK_CMD_MODE(LK_MODE_DOWN_UP, 5),
- LK_CMD_MODE(LK_MODE_DOWN_UP, 6),
- LK_CMD_MODE(LK_MODE_RPT_DOWN, 7),
- LK_CMD_MODE(LK_MODE_RPT_DOWN, 8),
- LK_CMD_MODE(LK_MODE_RPT_DOWN, 9),
- LK_CMD_MODE(LK_MODE_RPT_DOWN, 10),
- LK_CMD_MODE(LK_MODE_RPT_DOWN, 11),
- LK_CMD_MODE(LK_MODE_RPT_DOWN, 12),
- LK_CMD_MODE(LK_MODE_DOWN, 13),
- LK_CMD_MODE(LK_MODE_RPT_DOWN, 14),
- LK_CMD_DIS_KEYCLK,
- LK_CMD_ENB_BELL, LK_PARAM_VOLUME(4),
-};
-
-static void *lk201_handle;
-
-static int lk201_send(unsigned char ch)
-{
- if (lk201_hook.poll_tx_char(lk201_handle, ch)) {
- printk(KERN_ERR "lk201: transmit timeout\n");
- return -EIO;
- }
- return 0;
-}
-
-static inline int lk201_get_id(void)
-{
- return lk201_send(LK_CMD_REQ_ID);
-}
-
-static int lk201_reset(void)
-{
- int i, r;
-
- for (i = 0; i < sizeof(lk201_reset_string); i++) {
- r = lk201_send(lk201_reset_string[i]);
- if (r < 0)
- return r;
- }
- return 0;
-}
-
-static void lk201_report(unsigned char id[6])
-{
- char *report = "lk201: keyboard attached, ";
-
- switch (id[2]) {
- case LK_STAT_PWRUP_OK:
- printk(KERN_INFO "%sself-test OK\n", report);
- break;
- case LK_STAT_PWRUP_KDOWN:
- /* The keyboard will resend the power-up ID
- after all keys are released, so we don't
- bother handling the error specially. Still
- there may be a short-circuit inside.
- */
- printk(KERN_ERR "%skey down (stuck?), code: 0x%02x\n",
- report, id[3]);
- break;
- case LK_STAT_PWRUP_ERROR:
- printk(KERN_ERR "%sself-test failure\n", report);
- break;
- default:
- printk(KERN_ERR "%sunknown error: 0x%02x\n",
- report, id[2]);
- }
-}
-
-static void lk201_id(unsigned char id[6])
-{
- /*
- * Report whether there is an LK201 or an LK401
- * The LK401 has ALT keys...
- */
- switch (id[4]) {
- case 1:
- printk(KERN_INFO "lk201: LK201 detected\n");
- break;
- case 2:
- printk(KERN_INFO "lk201: LK401 detected\n");
- break;
- case 3:
- printk(KERN_INFO "lk201: LK443 detected\n");
- break;
- case 4:
- printk(KERN_INFO "lk201: LK421 detected\n");
- break;
- default:
- printk(KERN_WARNING
- "lk201: unknown keyboard detected, ID %d\n", id[4]);
- printk(KERN_WARNING "lk201: ... please report to "
- "<linux-mips@linux-mips.org>\n");
- }
-}
-
-#define DEFAULT_KEYB_REP_DELAY (250/5) /* [5ms] */
-#define DEFAULT_KEYB_REP_RATE 30 /* [cps] */
-
-static struct kbd_repeat kbdrate = {
- DEFAULT_KEYB_REP_DELAY,
- DEFAULT_KEYB_REP_RATE
-};
-
-static void parse_kbd_rate(struct kbd_repeat *r)
-{
- if (r->delay <= 0)
- r->delay = kbdrate.delay;
- if (r->rate <= 0)
- r->rate = kbdrate.rate;
-
- if (r->delay < 5)
- r->delay = 5;
- if (r->delay > 630)
- r->delay = 630;
- if (r->rate < 12)
- r->rate = 12;
- if (r->rate > 127)
- r->rate = 127;
- if (r->rate == 125)
- r->rate = 124;
-}
-
-static int write_kbd_rate(struct kbd_repeat *rep)
-{
- int delay, rate;
- int i;
-
- delay = rep->delay / 5;
- rate = rep->rate;
- for (i = 0; i < 4; i++) {
- if (lk201_hook.poll_tx_char(lk201_handle,
- LK_CMD_RPT_RATE(i)))
- return 1;
- if (lk201_hook.poll_tx_char(lk201_handle,
- LK_PARAM_DELAY(delay)))
- return 1;
- if (lk201_hook.poll_tx_char(lk201_handle,
- LK_PARAM_RATE(rate)))
- return 1;
- }
- return 0;
-}
-
-static int lk201_kbd_rate(struct kbd_repeat *rep)
-{
- if (rep == NULL)
- return -EINVAL;
-
- parse_kbd_rate(rep);
-
- if (write_kbd_rate(rep)) {
- memcpy(rep, &kbdrate, sizeof(struct kbd_repeat));
- return -EIO;
- }
-
- memcpy(&kbdrate, rep, sizeof(struct kbd_repeat));
-
- return 0;
-}
-
-static void lk201_kd_mksound(unsigned int hz, unsigned int ticks)
-{
- if (!ticks)
- return;
-
- /*
- * Can't set frequency and we "approximate"
- * duration by volume. ;-)
- */
- ticks /= HZ / 32;
- if (ticks > 7)
- ticks = 7;
- ticks = 7 - ticks;
-
- if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_ENB_BELL))
- return;
- if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_VOLUME(ticks)))
- return;
- if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_BELL))
- return;
-}
-
-void kbd_leds(unsigned char leds)
-{
- unsigned char l = 0;
-
- if (!lk201_handle) /* FIXME */
- return;
-
- /* FIXME -- Only Hold and Lock LEDs for now. --macro */
- if (leds & LED_SCR)
- l |= LK_LED_HOLD;
- if (leds & LED_CAP)
- l |= LK_LED_LOCK;
-
- if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_LEDS_ON))
- return;
- if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_LED_MASK(l)))
- return;
- if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_LEDS_OFF))
- return;
- if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_LED_MASK(~l)))
- return;
-}
-
-int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
-{
- return -EINVAL;
-}
-
-int kbd_getkeycode(unsigned int scancode)
-{
- return -EINVAL;
-}
-
-int kbd_translate(unsigned char scancode, unsigned char *keycode,
- char raw_mode)
-{
- *keycode = scancode;
- return 1;
-}
-
-char kbd_unexpected_up(unsigned char keycode)
-{
- return 0x80;
-}
-
-static void lk201_rx_char(unsigned char ch, unsigned char fl)
-{
- static unsigned char id[6];
- static int id_i;
-
- static int shift_state = 0;
- static int prev_scancode;
- unsigned char c = scancodeRemap[ch];
-
- if (fl != TTY_NORMAL && fl != TTY_OVERRUN) {
- printk(KERN_ERR "lk201: keyboard receive error: 0x%02x\n", fl);
- return;
- }
-
- /* Assume this is a power-up ID. */
- if (ch == LK_STAT_PWRUP_ID && !id_i) {
- id[id_i++] = ch;
- return;
- }
-
- /* Handle the power-up sequence. */
- if (id_i) {
- id[id_i++] = ch;
- if (id_i == 4) {
- /* OK, the power-up concluded. */
- lk201_report(id);
- if (id[2] == LK_STAT_PWRUP_OK)
- lk201_get_id();
- else {
- id_i = 0;
- printk(KERN_ERR "lk201: keyboard power-up "
- "error, skipping initialization\n");
- }
- } else if (id_i == 6) {
- /* We got the ID; report it and start operation. */
- id_i = 0;
- lk201_id(id);
- lk201_reset();
- }
- return;
- }
-
- /* Everything else is a scancode/status response. */
- id_i = 0;
- switch (ch) {
- case LK_STAT_RESUME_ERR:
- case LK_STAT_ERROR:
- case LK_STAT_INHIBIT_ACK:
- case LK_STAT_TEST_ACK:
- case LK_STAT_MODE_KEYDOWN:
- case LK_STAT_MODE_ACK:
- break;
- case LK_KEY_LOCK:
- shift_state ^= LK_LOCK;
- handle_scancode(c, (shift_state & LK_LOCK) ? 1 : 0);
- break;
- case LK_KEY_SHIFT:
- shift_state ^= LK_SHIFT;
- handle_scancode(c, (shift_state & LK_SHIFT) ? 1 : 0);
- break;
- case LK_KEY_CTRL:
- shift_state ^= LK_CTRL;
- handle_scancode(c, (shift_state & LK_CTRL) ? 1 : 0);
- break;
- case LK_KEY_COMP:
- shift_state ^= LK_COMP;
- handle_scancode(c, (shift_state & LK_COMP) ? 1 : 0);
- break;
- case LK_KEY_RELEASE:
- if (shift_state & LK_SHIFT)
- handle_scancode(scancodeRemap[LK_KEY_SHIFT], 0);
- if (shift_state & LK_CTRL)
- handle_scancode(scancodeRemap[LK_KEY_CTRL], 0);
- if (shift_state & LK_COMP)
- handle_scancode(scancodeRemap[LK_KEY_COMP], 0);
- if (shift_state & LK_LOCK)
- handle_scancode(scancodeRemap[LK_KEY_LOCK], 0);
- shift_state = 0;
- break;
- case LK_KEY_REPEAT:
- handle_scancode(prev_scancode, 1);
- break;
- default:
- prev_scancode = c;
- handle_scancode(c, 1);
- break;
- }
- tasklet_schedule(&keyboard_tasklet);
-}
-
-static void __init lk201_info(void *handle)
-{
-}
-
-static int __init lk201_init(void *handle)
-{
- /* First install handlers. */
- lk201_handle = handle;
- kbd_rate = lk201_kbd_rate;
- kd_mksound = lk201_kd_mksound;
-
- lk201_hook.rx_char = lk201_rx_char;
-
- /* Then just issue a reset -- the handlers will do the rest. */
- lk201_send(LK_CMD_POWER_UP);
-
- return 0;
-}
-
-void __init kbd_init_hw(void)
-{
- /* Maxine uses LK501 at the Access.Bus. */
- if (!LK_IFACE)
- return;
-
- printk(KERN_INFO "lk201: DECstation LK keyboard driver v0.05.\n");
-
- if (LK_IFACE_ZS) {
- /*
- * kbd_init_hw() is being called before
- * rs_init() so just register the kbd hook
- * and let zs_init do the rest :-)
- */
- if (!register_dec_serial_hook(KEYB_LINE, &lk201_hook))
- unregister_dec_serial_hook(KEYB_LINE);
- } else {
- /*
- * TODO: modify dz.c to allow similar hooks
- * for LK201 handling on DS2100, DS3100, and DS5000/200
- */
- printk(KERN_ERR "lk201: support for DZ11 not yet ready.\n");
- }
-}
diff --git a/drivers/tc/lk201.h b/drivers/tc/lk201.h
deleted file mode 100644
index 99f3203c41b..00000000000
--- a/drivers/tc/lk201.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Commands to the keyboard processor
- */
-
-#define LK_PARAM 0x80 /* start/end parameter list */
-
-#define LK_CMD_RESUME 0x8b /* resume transmission to the host */
-#define LK_CMD_INHIBIT 0x89 /* stop transmission to the host */
-#define LK_CMD_LEDS_ON 0x13 /* light LEDs */
- /* 1st param: led bitmask */
-#define LK_CMD_LEDS_OFF 0x11 /* turn off LEDs */
- /* 1st param: led bitmask */
-#define LK_CMD_DIS_KEYCLK 0x99 /* disable the keyclick */
-#define LK_CMD_ENB_KEYCLK 0x1b /* enable the keyclick */
- /* 1st param: volume */
-#define LK_CMD_DIS_CTLCLK 0xb9 /* disable the Ctrl keyclick */
-#define LK_CMD_ENB_CTLCLK 0xbb /* enable the Ctrl keyclick */
-#define LK_CMD_SOUND_CLK 0x9f /* emit a keyclick */
-#define LK_CMD_DIS_BELL 0xa1 /* disable the bell */
-#define LK_CMD_ENB_BELL 0x23 /* enable the bell */
- /* 1st param: volume */
-#define LK_CMD_BELL 0xa7 /* emit a bell */
-#define LK_CMD_TMP_NORPT 0xd1 /* disable typematic */
- /* for the currently pressed key */
-#define LK_CMD_ENB_RPT 0xe3 /* enable typematic */
- /* for RPT_DOWN groups */
-#define LK_CMD_DIS_RPT 0xe1 /* disable typematic */
- /* for RPT_DOWN groups */
-#define LK_CMD_RPT_TO_DOWN 0xd9 /* set RPT_DOWN groups to DOWN */
-#define LK_CMD_REQ_ID 0xab /* request the keyboard ID */
-#define LK_CMD_POWER_UP 0xfd /* init power-up sequence */
-#define LK_CMD_TEST_MODE 0xcb /* enter the factory test mode */
-#define LK_CMD_TEST_EXIT 0x80 /* exit the factory test mode */
-#define LK_CMD_SET_DEFAULTS 0xd3 /* set power-up defaults */
-
-#define LK_CMD_MODE(m,div) (LK_PARAM|(((div)&0xf)<<3)|(((m)&0x3)<<1))
- /* select the repeat mode */
- /* for the selected key group */
-#define LK_CMD_MODE_AR(m,div) ((((div)&0xf)<<3)|(((m)&0x3)<<1))
- /* select the repeat mode */
- /* and the repeat register */
- /* for the selected key group */
- /* 1st param: register number */
-#define LK_CMD_RPT_RATE(r) (0x78|(((r)&0x3)<<1))
- /* set the delay and repeat rate */
- /* for the selected repeat register */
- /* 1st param: initial delay */
- /* 2nd param: repeat rate */
-
-/* there are 4 leds, represent them in the low 4 bits of a byte */
-#define LK_PARAM_LED_MASK(ledbmap) (LK_PARAM|((ledbmap)&0xf))
-#define LK_LED_WAIT 0x1 /* Wait LED */
-#define LK_LED_COMP 0x2 /* Compose LED */
-#define LK_LED_LOCK 0x4 /* Lock LED */
-#define LK_LED_HOLD 0x8 /* Hold Screen LED */
-
-/* max volume is 0, lowest is 0x7 */
-#define LK_PARAM_VOLUME(v) (LK_PARAM|((v)&0x7))
-
-/* mode set command details, div is a key group number */
-#define LK_MODE_DOWN 0x0 /* make only */
-#define LK_MODE_RPT_DOWN 0x1 /* make and typematic */
-#define LK_MODE_DOWN_UP 0x3 /* make and release */
-
-/* there are 4 repeat registers */
-#define LK_PARAM_AR(r) (LK_PARAM|((v)&0x3))
-
-/*
- * Mappings between key groups and keycodes are as follows:
- *
- * 1: 0xbf - 0xff -- alphanumeric,
- * 2: 0x91 - 0xa5 -- numeric keypad,
- * 3: 0xbc -- Backspace,
- * 4: 0xbd - 0xbe -- Tab, Return,
- * 5: 0xb0 - 0xb2 -- Lock, Compose Character,
- * 6: 0xad - 0xaf -- Ctrl, Shift,
- * 7: 0xa6 - 0xa8 -- Left Arrow, Right Arrow,
- * 8: 0xa9 - 0xac -- Up Arrow, Down Arrow, Right Shift,
- * 9: 0x88 - 0x90 -- editor keypad,
- * 10: 0x56 - 0x62 -- F1 - F5,
- * 11: 0x63 - 0x6e -- F6 - F10,
- * 12: 0x6f - 0x7a -- F11 - F14,
- * 13: 0x7b - 0x7d -- Help, Do,
- * 14: 0x7e - 0x87 -- F17 - F20.
- *
- * Notes:
- * 1. Codes in the 0x00 - 0x40 range are reserved.
- * 2. The assignment of the 0x41 - 0x55 range is undiscovered, probably 10.
- */
-
-/* delay is 5 - 630 ms; 0x00 and 0x7f are reserved */
-#define LK_PARAM_DELAY(t) ((t)&0x7f)
-
-/* rate is 12 - 127 Hz; 0x00 - 0x0b and 0x7d (power-up!) are reserved */
-#define LK_PARAM_RATE(r) (LK_PARAM|((r)&0x7f))
-
-#define LK_SHIFT 1<<0
-#define LK_CTRL 1<<1
-#define LK_LOCK 1<<2
-#define LK_COMP 1<<3
-
-#define LK_KEY_SHIFT 0xae
-#define LK_KEY_CTRL 0xaf
-#define LK_KEY_LOCK 0xb0
-#define LK_KEY_COMP 0xb1
-
-#define LK_KEY_RELEASE 0xb3 /* all keys released */
-#define LK_KEY_REPEAT 0xb4 /* repeat the last key */
-
-/* status responses */
-#define LK_STAT_RESUME_ERR 0xb5 /* keystrokes lost while inhibited */
-#define LK_STAT_ERROR 0xb6 /* an invalid command received */
-#define LK_STAT_INHIBIT_ACK 0xb7 /* transmission inhibited */
-#define LK_STAT_TEST_ACK 0xb8 /* the factory test mode entered */
-#define LK_STAT_MODE_KEYDOWN 0xb9 /* a key is down on a change */
- /* to the DOWN_UP mode; */
- /* the keycode follows */
-#define LK_STAT_MODE_ACK 0xba /* the mode command succeeded */
-
-#define LK_STAT_PWRUP_ID 0x01 /* the power-up response start mark */
-#define LK_STAT_PWRUP_OK 0x00 /* the power-up self test OK */
-#define LK_STAT_PWRUP_KDOWN 0x3d /* a key was down during the test */
-#define LK_STAT_PWRUP_ERROR 0x3e /* keyboard self test failure */
-
-extern unsigned char scancodeRemap[256];
diff --git a/drivers/telephony/Kconfig b/drivers/telephony/Kconfig
index 5f98f673f1b..b5f78b6ed2b 100644
--- a/drivers/telephony/Kconfig
+++ b/drivers/telephony/Kconfig
@@ -19,7 +19,7 @@ if PHONE
config PHONE_IXJ
tristate "QuickNet Internet LineJack/PhoneJack support"
- depends ISA || PCI
+ depends on ISA || PCI
---help---
Say M if you have a telephony card manufactured by Quicknet
Technologies, Inc. These include the Internet PhoneJACK and
diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c
index 4d8c2a5b329..bcea8d9b718 100644
--- a/drivers/telephony/phonedev.c
+++ b/drivers/telephony/phonedev.c
@@ -120,9 +120,8 @@ int phone_register_device(struct phone_device *p, int unit)
void phone_unregister_device(struct phone_device *pfd)
{
mutex_lock(&phone_lock);
- if (phone_device[pfd->minor] != pfd)
- panic("phone: bad unregister");
- phone_device[pfd->minor] = NULL;
+ if (likely(phone_device[pfd->minor] == pfd))
+ phone_device[pfd->minor] = NULL;
mutex_unlock(&phone_lock);
}
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index ac49b15fa76..516a6400db4 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -28,27 +28,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
-obj-$(CONFIG_USB_ADUTUX) += misc/
-obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
-obj-$(CONFIG_USB_AUERSWALD) += misc/
-obj-$(CONFIG_USB_BERRY_CHARGE) += misc/
-obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
-obj-$(CONFIG_USB_CYTHERM) += misc/
-obj-$(CONFIG_USB_EMI26) += misc/
-obj-$(CONFIG_USB_EMI62) += misc/
-obj-$(CONFIG_USB_FTDI_ELAN) += misc/
-obj-$(CONFIG_USB_IDMOUSE) += misc/
-obj-$(CONFIG_USB_LCD) += misc/
-obj-$(CONFIG_USB_LD) += misc/
-obj-$(CONFIG_USB_LED) += misc/
-obj-$(CONFIG_USB_LEGOTOWER) += misc/
-obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
-obj-$(CONFIG_USB_RIO500) += misc/
-obj-$(CONFIG_USB_SISUSBVGA) += misc/
-obj-$(CONFIG_USB_TEST) += misc/
-obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
-obj-$(CONFIG_USB_USS720) += misc/
-obj-$(CONFIG_USB_IOWARRIOR) += misc/
+obj-$(CONFIG_USB) += misc/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index a73e714288e..a51eeedc18d 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -482,7 +482,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
- dbg("too big transfer requested");
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n",
+ wbuflen, rbuflen);
ret = -ENOMEM;
goto fail;
}
@@ -493,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
init_completion(&instance->rcv_done);
ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
if (ret < 0) {
- dbg("submitting read urb for cm %#x failed", cm);
- ret = ret;
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n",
+ cm, ret);
goto fail;
}
@@ -510,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
init_completion(&instance->snd_done);
ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
if (ret < 0) {
- dbg("submitting write urb for cm %#x failed", cm);
- ret = ret;
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n",
+ cm, ret);
goto fail;
}
ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
if (ret < 0) {
- dbg("sending cm %#x failed", cm);
- ret = ret;
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret);
goto fail;
}
ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
if (ret < 0) {
- dbg("receiving cm %#x failed", cm);
- ret = ret;
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret);
goto fail;
}
if (actlen % CMD_PACKET_SIZE || !actlen) {
- dbg("response is not a positive multiple of %d: %#x",
- CMD_PACKET_SIZE, actlen);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n",
+ cm, actlen);
ret = -EIO;
goto fail;
}
@@ -538,12 +543,16 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
/* check the return status and copy the data to the output buffer, if needed */
for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
if (rbuf[offb] != cm) {
- dbg("wrong cm %#x in response", rbuf[offb]);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n",
+ rbuf[offb], cm);
ret = -EIO;
goto fail;
}
if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
- dbg("response failed: %#x", rbuf[offb + 1]);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "response to cm %#x failed: %#x\n",
+ cm, rbuf[offb + 1]);
ret = -EIO;
goto fail;
}
@@ -582,14 +591,18 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
for (offb = 0; offb < len; ) {
int l = le32_to_cpu(buf[offb++]);
if (l > stride || l > (len - offb) / 2) {
- dbg("wrong data length %#x in response", l);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
+ cm, l);
ret = -EIO;
goto cleanup;
}
while (l--) {
offd = le32_to_cpu(buf[offb++]);
if (offd >= size) {
- dbg("wrong index %#x in response", offd);
+ if (printk_ratelimit())
+ usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n",
+ offd, cm);
ret = -EIO;
goto cleanup;
}
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index eb0615abff6..7d27c9cf3c4 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -88,7 +88,7 @@ static const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = {
static unsigned int BMaxDSL = DEFAULT_B_MAX_DSL;
static unsigned char ModemMode = DEFAULT_MODEM_MODE;
static unsigned char ModemOption[MODEM_OPTION_LENGTH];
-static int num_ModemOption;
+static unsigned int num_ModemOption;
module_param(altsetting, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(altsetting,
@@ -251,7 +251,6 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
{
unsigned char *buffer;
struct usbatm_data *usbatm = instance->usbatm;
- struct usb_interface *intf;
struct usb_device *usb_dev = usbatm->usb_dev;
int actual_length;
int ret = 0;
@@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
goto out;
}
- if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
+ if (!usb_ifnum_to_if(usb_dev, 2)) {
ret = -ENODEV;
usb_dbg(usbatm, "%s: interface not found!\n", __func__);
goto out_free;
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 29807d048b0..389c5b164eb 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -2,7 +2,8 @@
* Copyright (c) 2003, 2004
* Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
*
- * Copyright (c) 2005 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl>
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -107,18 +108,51 @@
#define uea_info(usb_dev, format,args...) \
dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args)
-struct uea_cmvs {
+struct intr_pkt;
+
+/* cmv's from firmware */
+struct uea_cmvs_v1 {
u32 address;
u16 offset;
u32 data;
} __attribute__ ((packed));
+struct uea_cmvs_v2 {
+ u32 group;
+ u32 address;
+ u32 offset;
+ u32 data;
+} __attribute__ ((packed));
+
+/* information about currently processed cmv */
+struct cmv_dsc_e1 {
+ u8 function;
+ u16 idx;
+ u32 address;
+ u16 offset;
+};
+
+struct cmv_dsc_e4 {
+ u16 function;
+ u16 offset;
+ u16 address;
+ u16 group;
+};
+
+union cmv_dsc {
+ struct cmv_dsc_e1 e1;
+ struct cmv_dsc_e4 e4;
+};
+
struct uea_softc {
struct usb_device *usb_dev;
struct usbatm_data *usbatm;
int modem_index;
unsigned int driver_info;
+ int annex;
+#define ANNEXA 0
+#define ANNEXB 1
int booting;
int reset;
@@ -127,20 +161,23 @@ struct uea_softc {
struct task_struct *kthread;
u32 data;
- wait_queue_head_t cmv_ack_wait;
+ u32 data1;
+
int cmv_ack;
+ union cmv_dsc cmv_dsc;
struct work_struct task;
+ struct workqueue_struct *work_q;
u16 pageno;
u16 ovl;
const struct firmware *dsp_firm;
struct urb *urb_int;
- u8 cmv_function;
- u16 cmv_idx;
- u32 cmv_address;
- u16 cmv_offset;
+ void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *);
+ void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *);
+ int (*stat) (struct uea_softc *);
+ int (*send_cmvs) (struct uea_softc *);
/* keep in sync with eaglectl */
struct uea_stats {
@@ -174,10 +211,34 @@ struct uea_softc {
#define ELSA_PID_PSTFIRM 0x3350
#define ELSA_PID_PREFIRM 0x3351
+#define ELSA_PID_A_PREFIRM 0x3352
+#define ELSA_PID_A_PSTFIRM 0x3353
+#define ELSA_PID_B_PREFIRM 0x3362
+#define ELSA_PID_B_PSTFIRM 0x3363
+
/*
- * Sagem USB IDs
+ * Devolo IDs : pots if (pid & 0x10)
*/
-#define EAGLE_VID 0x1110
+#define DEVOLO_VID 0x1039
+#define DEVOLO_EAGLE_I_A_PID_PSTFIRM 0x2110
+#define DEVOLO_EAGLE_I_A_PID_PREFIRM 0x2111
+
+#define DEVOLO_EAGLE_I_B_PID_PSTFIRM 0x2100
+#define DEVOLO_EAGLE_I_B_PID_PREFIRM 0x2101
+
+#define DEVOLO_EAGLE_II_A_PID_PSTFIRM 0x2130
+#define DEVOLO_EAGLE_II_A_PID_PREFIRM 0x2131
+
+#define DEVOLO_EAGLE_II_B_PID_PSTFIRM 0x2120
+#define DEVOLO_EAGLE_II_B_PID_PREFIRM 0x2121
+
+/*
+ * Reference design USB IDs
+ */
+#define ANALOG_VID 0x1110
+#define ADI930_PID_PREFIRM 0x9001
+#define ADI930_PID_PSTFIRM 0x9000
+
#define EAGLE_I_PID_PREFIRM 0x9010 /* Eagle I */
#define EAGLE_I_PID_PSTFIRM 0x900F /* Eagle I */
@@ -187,12 +248,12 @@ struct uea_softc {
#define EAGLE_II_PID_PREFIRM 0x9022 /* Eagle II */
#define EAGLE_II_PID_PSTFIRM 0x9021 /* Eagle II */
-/*
- * Eagle III Pid
- */
#define EAGLE_III_PID_PREFIRM 0x9032 /* Eagle III */
#define EAGLE_III_PID_PSTFIRM 0x9031 /* Eagle III */
+#define EAGLE_IV_PID_PREFIRM 0x9042 /* Eagle IV */
+#define EAGLE_IV_PID_PSTFIRM 0x9041 /* Eagle IV */
+
/*
* USR USB IDs
*/
@@ -208,11 +269,15 @@ struct uea_softc {
#define PREFIRM 0
#define PSTFIRM (1<<7)
+#define AUTO_ANNEX_A (1<<8)
+#define AUTO_ANNEX_B (1<<9)
+
enum {
ADI930 = 0,
EAGLE_I,
EAGLE_II,
- EAGLE_III
+ EAGLE_III,
+ EAGLE_IV
};
/* macros for both struct usb_device_id and struct uea_softc */
@@ -221,15 +286,18 @@ enum {
#define UEA_CHIP_VERSION(x) \
((x)->driver_info & 0xf)
-#define IS_ISDN(usb_dev) \
- (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80)
+#define IS_ISDN(x) \
+ ((x)->annex & ANNEXB)
#define INS_TO_USBDEV(ins) ins->usb_dev
#define GET_STATUS(data) \
((data >> 8) & 0xf)
+
#define IS_OPERATIONAL(sc) \
- (GET_STATUS(sc->stats.phy.state) == 2)
+ ((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \
+ (GET_STATUS(sc->stats.phy.state) == 2) : \
+ (sc->stats.phy.state == 7))
/*
* Set of macros to handle unaligned data in the firmware blob.
@@ -259,7 +327,8 @@ enum {
#define UEA_INTR_PIPE 0x04
#define UEA_ISO_DATA_PIPE 0x08
-#define UEA_SET_BLOCK 0x0001
+#define UEA_E1_SET_BLOCK 0x0001
+#define UEA_E4_SET_BLOCK 0x002c
#define UEA_SET_MODE 0x0003
#define UEA_SET_2183_DATA 0x0004
#define UEA_SET_TIMEOUT 0x0011
@@ -275,71 +344,179 @@ enum {
#define UEA_MPTX_MAILBOX (0x3fd6 | 0x4000)
#define UEA_MPRX_MAILBOX (0x3fdf | 0x4000)
-/* structure describing a block within a DSP page */
-struct block_info {
+/* block information in eagle4 dsp firmware */
+struct block_index {
+ __le32 PageOffset;
+ __le32 NotLastBlock;
+ __le32 dummy;
+ __le32 PageSize;
+ __le32 PageAddress;
+ __le16 dummy1;
+ __le16 PageNumber;
+} __attribute__ ((packed));
+
+#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000)
+#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4)
+
+#define E4_L1_STRING_HEADER 0x10
+#define E4_MAX_PAGE_NUMBER 0x58
+#define E4_NO_SWAPPAGE_HEADERS 0x31
+
+/* l1_code is eagle4 dsp firmware format */
+struct l1_code {
+ u8 string_header[E4_L1_STRING_HEADER];
+ u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
+ struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
+ u8 code [0];
+} __attribute__ ((packed));
+
+/* structures describing a block within a DSP page */
+struct block_info_e1 {
__le16 wHdr;
-#define UEA_BIHDR 0xabcd
__le16 wAddress;
__le16 wSize;
__le16 wOvlOffset;
__le16 wOvl; /* overlay */
__le16 wLast;
} __attribute__ ((packed));
-#define BLOCK_INFO_SIZE 12
+#define E1_BLOCK_INFO_SIZE 12
+
+struct block_info_e4 {
+ __be16 wHdr;
+ __u8 bBootPage;
+ __u8 bPageNumber;
+ __be32 dwSize;
+ __be32 dwAddress;
+ __be16 wReserved;
+} __attribute__ ((packed));
+#define E4_BLOCK_INFO_SIZE 14
-/* structure representing a CMV (Configuration and Management Variable) */
-struct cmv {
- __le16 wPreamble;
-#define PREAMBLE 0x535c
- __u8 bDirection;
-#define MODEMTOHOST 0x01
-#define HOSTTOMODEM 0x10
- __u8 bFunction;
-#define FUNCTION_TYPE(f) ((f) >> 4)
-#define MEMACCESS 0x1
-#define ADSLDIRECTIVE 0x7
+#define UEA_BIHDR 0xabcd
+#define UEA_RESERVED 0xffff
+
+/* constants describing cmv type */
+#define E1_PREAMBLE 0x535c
+#define E1_MODEMTOHOST 0x01
+#define E1_HOSTTOMODEM 0x10
+
+#define E1_MEMACCESS 0x1
+#define E1_ADSLDIRECTIVE 0x7
+#define E1_FUNCTION_TYPE(f) ((f) >> 4)
+#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f)
+
+#define E4_MEMACCESS 0
+#define E4_ADSLDIRECTIVE 0xf
+#define E4_FUNCTION_TYPE(f) ((f) >> 8)
+#define E4_FUNCTION_SIZE(f) ((f) & 0x0f)
+#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f)
-#define FUNCTION_SUBTYPE(f) ((f) & 0x0f)
/* for MEMACCESS */
-#define REQUESTREAD 0x0
-#define REQUESTWRITE 0x1
-#define REPLYREAD 0x2
-#define REPLYWRITE 0x3
+#define E1_REQUESTREAD 0x0
+#define E1_REQUESTWRITE 0x1
+#define E1_REPLYREAD 0x2
+#define E1_REPLYWRITE 0x3
+
+#define E4_REQUESTREAD 0x0
+#define E4_REQUESTWRITE 0x4
+#define E4_REPLYREAD (E4_REQUESTREAD | 1)
+#define E4_REPLYWRITE (E4_REQUESTWRITE | 1)
+
/* for ADSLDIRECTIVE */
-#define KERNELREADY 0x0
-#define MODEMREADY 0x1
+#define E1_KERNELREADY 0x0
+#define E1_MODEMREADY 0x1
-#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
- __le16 wIndex;
- __le32 dwSymbolicAddress;
-#define MAKESA(a, b, c, d) \
+#define E4_KERNELREADY 0x0
+#define E4_MODEMREADY 0x1
+
+#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
+#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf))
+
+#define E1_MAKESA(a, b, c, d) \
(((c) & 0xff) << 24 | \
((d) & 0xff) << 16 | \
((a) & 0xff) << 8 | \
((b) & 0xff))
-#define GETSA1(a) ((a >> 8) & 0xff)
-#define GETSA2(a) (a & 0xff)
-#define GETSA3(a) ((a >> 24) & 0xff)
-#define GETSA4(a) ((a >> 16) & 0xff)
-
-#define SA_CNTL MAKESA('C', 'N', 'T', 'L')
-#define SA_DIAG MAKESA('D', 'I', 'A', 'G')
-#define SA_INFO MAKESA('I', 'N', 'F', 'O')
-#define SA_OPTN MAKESA('O', 'P', 'T', 'N')
-#define SA_RATE MAKESA('R', 'A', 'T', 'E')
-#define SA_STAT MAKESA('S', 'T', 'A', 'T')
+
+#define E1_GETSA1(a) ((a >> 8) & 0xff)
+#define E1_GETSA2(a) (a & 0xff)
+#define E1_GETSA3(a) ((a >> 24) & 0xff)
+#define E1_GETSA4(a) ((a >> 16) & 0xff)
+
+#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L')
+#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G')
+#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O')
+#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N')
+#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E')
+#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T')
+
+#define E4_SA_CNTL 1
+#define E4_SA_STAT 2
+#define E4_SA_INFO 3
+#define E4_SA_TEST 4
+#define E4_SA_OPTN 5
+#define E4_SA_RATE 6
+#define E4_SA_DIAG 7
+#define E4_SA_CNFG 8
+
+/* structures representing a CMV (Configuration and Management Variable) */
+struct cmv_e1 {
+ __le16 wPreamble;
+ __u8 bDirection;
+ __u8 bFunction;
+ __le16 wIndex;
+ __le32 dwSymbolicAddress;
__le16 wOffsetAddress;
__le32 dwData;
} __attribute__ ((packed));
-#define CMV_SIZE 16
-/* structure representing swap information */
-struct swap_info {
+struct cmv_e4 {
+ __be16 wGroup;
+ __be16 wFunction;
+ __be16 wOffset;
+ __be16 wAddress;
+ __be32 dwData [6];
+} __attribute__ ((packed));
+
+/* structures representing swap information */
+struct swap_info_e1 {
__u8 bSwapPageNo;
__u8 bOvl; /* overlay */
} __attribute__ ((packed));
-/* structure representing interrupt data */
+struct swap_info_e4 {
+ __u8 bSwapPageNo;
+} __attribute__ ((packed));
+
+/* structures representing interrupt data */
+#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo
+#define e1_bOvl u.e1.s1.swapinfo.bOvl
+#define e4_bSwapPageNo u.e4.s1.swapinfo.bSwapPageNo
+
+#define INT_LOADSWAPPAGE 0x0001
+#define INT_INCOMINGCMV 0x0002
+
+union intr_data_e1 {
+ struct {
+ struct swap_info_e1 swapinfo;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s1;
+ struct {
+ struct cmv_e1 cmv;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
+union intr_data_e4 {
+ struct {
+ struct swap_info_e4 swapinfo;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s1;
+ struct {
+ struct cmv_e4 cmv;
+ __le16 wDataSize;
+ } __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
struct intr_pkt {
__u8 bType;
__u8 bNotification;
@@ -347,43 +524,48 @@ struct intr_pkt {
__le16 wIndex;
__le16 wLength;
__le16 wInterrupt;
-#define INT_LOADSWAPPAGE 0x0001
-#define INT_INCOMINGCMV 0x0002
union {
- struct {
- struct swap_info swapinfo;
- __le16 wDataSize;
- } __attribute__ ((packed)) s1;
-
- struct {
- struct cmv cmv;
- __le16 wDataSize;
- } __attribute__ ((packed)) s2;
- } __attribute__ ((packed)) u;
-#define bSwapPageNo u.s1.swapinfo.bSwapPageNo
-#define bOvl u.s1.swapinfo.bOvl
+ union intr_data_e1 e1;
+ union intr_data_e4 e4;
+ } u;
} __attribute__ ((packed));
-#define INTR_PKT_SIZE 28
+
+#define E1_INTR_PKT_SIZE 28
+#define E4_INTR_PKT_SIZE 64
static struct usb_driver uea_driver;
static DEFINE_MUTEX(uea_mutex);
-static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"};
+static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};
static int modem_index;
static unsigned int debug;
-static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1};
+static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};
static int sync_wait[NB_MODEM];
static char *cmv_file[NB_MODEM];
+static int annex[NB_MODEM];
module_param(debug, uint, 0644);
MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)");
-module_param_array(use_iso, bool, NULL, 0644);
-MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic");
+module_param_array(altsetting, uint, NULL, 0644);
+MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, "
+ "1=isoc slowest, ... , 8=isoc fastest (default)");
module_param_array(sync_wait, bool, NULL, 0644);
MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM");
module_param_array(cmv_file, charp, NULL, 0644);
MODULE_PARM_DESC(cmv_file,
"file name with configuration and management variables");
+module_param_array(annex, uint, NULL, 0644);
+MODULE_PARM_DESC(annex,
+ "manually set annex a/b (0=auto, 1=annex a, 2=annex b)");
+
+#define uea_wait(sc, cond, timeo) \
+({ \
+ int _r = wait_event_interruptible_timeout(sc->sync_q, \
+ (cond) || kthread_should_stop(), timeo); \
+ if (kthread_should_stop()) \
+ _r = -ENODEV; \
+ _r; \
+})
#define UPDATE_ATM_STAT(type, val) \
do { \
@@ -519,6 +701,9 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
case EAGLE_III:
fw_name = FW_DIR "eagleIII.fw";
break;
+ case EAGLE_IV:
+ fw_name = FW_DIR "eagleIV.fw";
+ break;
}
ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware);
@@ -537,7 +722,7 @@ static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
/*
* Make sure that the DSP code provided is safe to use.
*/
-static int check_dsp(u8 *dsp, unsigned int len)
+static int check_dsp_e1(u8 *dsp, unsigned int len)
{
u8 pagecount, blockcount;
u16 blocksize;
@@ -588,6 +773,51 @@ static int check_dsp(u8 *dsp, unsigned int len)
return 0;
}
+static int check_dsp_e4(u8 *dsp, int len)
+{
+ int i;
+ struct l1_code *p = (struct l1_code *) dsp;
+ unsigned int sum = p->code - dsp;
+
+ if (len < sum)
+ return 1;
+
+ if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 &&
+ strcmp("STRATIPHY ANEXB", p->string_header) != 0)
+ return 1;
+
+ for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) {
+ struct block_index *blockidx;
+ u8 blockno = p->page_number_to_block_index[i];
+ if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+ continue;
+
+ do {
+ u64 l;
+
+ if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+ return 1;
+
+ blockidx = &p->page_header[blockno++];
+ if ((u8 *)(blockidx + 1) - dsp >= len)
+ return 1;
+
+ if (le16_to_cpu(blockidx->PageNumber) != i)
+ return 1;
+
+ l = E4_PAGE_BYTES(blockidx->PageSize);
+ sum += l;
+ l += le32_to_cpu(blockidx->PageOffset);
+ if (l > len)
+ return 1;
+
+ /* zero is zero regardless endianes */
+ } while (blockidx->NotLastBlock);
+ }
+
+ return (sum == len) ? 0 : 1;
+}
+
/*
* send data to the idma pipe
* */
@@ -624,13 +854,18 @@ static int request_dsp(struct uea_softc *sc)
int ret;
char *dsp_name;
- if (UEA_CHIP_VERSION(sc) == ADI930) {
- if (IS_ISDN(sc->usb_dev))
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+ if (IS_ISDN(sc))
+ dsp_name = FW_DIR "DSP4i.bin";
+ else
+ dsp_name = FW_DIR "DSP4p.bin";
+ } else if (UEA_CHIP_VERSION(sc) == ADI930) {
+ if (IS_ISDN(sc))
dsp_name = FW_DIR "DSP9i.bin";
else
dsp_name = FW_DIR "DSP9p.bin";
} else {
- if (IS_ISDN(sc->usb_dev))
+ if (IS_ISDN(sc))
dsp_name = FW_DIR "DSPei.bin";
else
dsp_name = FW_DIR "DSPep.bin";
@@ -640,11 +875,16 @@ static int request_dsp(struct uea_softc *sc)
if (ret < 0) {
uea_err(INS_TO_USBDEV(sc),
"requesting firmware %s failed with error %d\n",
- dsp_name, ret);
+ dsp_name, ret);
return ret;
}
- if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) {
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+ ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size);
+ else
+ ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size);
+
+ if (ret) {
uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
dsp_name);
release_firmware(sc->dsp_firm);
@@ -658,12 +898,12 @@ static int request_dsp(struct uea_softc *sc)
/*
* The uea_load_page() function must be called within a process context
*/
-static void uea_load_page(struct work_struct *work)
+static void uea_load_page_e1(struct work_struct *work)
{
struct uea_softc *sc = container_of(work, struct uea_softc, task);
u16 pageno = sc->pageno;
u16 ovl = sc->ovl;
- struct block_info bi;
+ struct block_info_e1 bi;
u8 *p;
u8 pagecount, blockcount;
@@ -716,7 +956,7 @@ static void uea_load_page(struct work_struct *work)
bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0);
/* send block info through the IDMA pipe */
- if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE))
+ if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE))
goto bad2;
/* send block data through the IDMA pipe */
@@ -735,17 +975,114 @@ bad1:
uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
}
+static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot)
+{
+ struct block_info_e4 bi;
+ struct block_index *blockidx;
+ struct l1_code *p = (struct l1_code *) sc->dsp_firm->data;
+ u8 blockno = p->page_number_to_block_index[pageno];
+
+ bi.wHdr = cpu_to_be16(UEA_BIHDR);
+ bi.bBootPage = boot;
+ bi.bPageNumber = pageno;
+ bi.wReserved = cpu_to_be16(UEA_RESERVED);
+
+ do {
+ u8 *blockoffset;
+ unsigned int blocksize;
+
+ blockidx = &p->page_header[blockno];
+ blocksize = E4_PAGE_BYTES(blockidx->PageSize);
+ blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset);
+
+ bi.dwSize = cpu_to_be32(blocksize);
+ bi.dwAddress = swab32(blockidx->PageAddress);
+
+ uea_dbg(INS_TO_USBDEV(sc),
+ "sending block %u for DSP page %u size %u adress %x\n",
+ blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
+
+ /* send block info through the IDMA pipe */
+ if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+ goto bad;
+
+ /* send block data through the IDMA pipe */
+ if (uea_idma_write(sc, blockoffset, blocksize))
+ goto bad;
+
+ blockno++;
+ } while (blockidx->NotLastBlock);
+
+ return;
+
+bad:
+ uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno);
+ return;
+}
+
+static void uea_load_page_e4(struct work_struct *work)
+{
+ struct uea_softc *sc = container_of(work, struct uea_softc, task);
+ u8 pageno = sc->pageno;
+ int i;
+ struct block_info_e4 bi;
+ struct l1_code *p;
+
+ uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno);
+
+ /* reload firmware when reboot start and it's loaded already */
+ if (pageno == 0 && sc->dsp_firm) {
+ release_firmware(sc->dsp_firm);
+ sc->dsp_firm = NULL;
+ }
+
+ if (sc->dsp_firm == NULL && request_dsp(sc) < 0)
+ return;
+
+ p = (struct l1_code *) sc->dsp_firm->data;
+ if (pageno >= p->page_header[0].PageNumber) {
+ uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
+ return;
+ }
+
+ if (pageno != 0) {
+ __uea_load_page_e4(sc, pageno, 0);
+ return;
+ }
+
+ uea_dbg(INS_TO_USBDEV(sc),
+ "sending Main DSP page %u\n", p->page_header[0].PageNumber);
+
+ for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) {
+ if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize))
+ __uea_load_page_e4(sc, i, 1);
+ }
+
+ uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n");
+
+ bi.wHdr = cpu_to_be16(UEA_BIHDR);
+ bi.bBootPage = 0;
+ bi.bPageNumber = 0xff;
+ bi.wReserved = cpu_to_be16(UEA_RESERVED);
+ bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize));
+ bi.dwAddress = swab32(p->page_header[0].PageAddress);
+
+ /* send block info through the IDMA pipe */
+ if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+ uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n");
+}
+
static inline void wake_up_cmv_ack(struct uea_softc *sc)
{
BUG_ON(sc->cmv_ack);
sc->cmv_ack = 1;
- wake_up(&sc->cmv_ack_wait);
+ wake_up(&sc->sync_q);
}
static inline int wait_cmv_ack(struct uea_softc *sc)
{
- int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
- sc->cmv_ack, ACK_TIMEOUT);
+ int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT);
+
sc->cmv_ack = 0;
uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n",
@@ -792,33 +1129,68 @@ static int uea_request(struct uea_softc *sc,
return 0;
}
-static int uea_cmv(struct uea_softc *sc,
+static int uea_cmv_e1(struct uea_softc *sc,
u8 function, u32 address, u16 offset, u32 data)
{
- struct cmv cmv;
+ struct cmv_e1 cmv;
int ret;
uea_enters(INS_TO_USBDEV(sc));
uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, "
"offset : 0x%04x, data : 0x%08x\n",
- FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function),
- GETSA1(address), GETSA2(address), GETSA3(address),
- GETSA4(address), offset, data);
+ E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function),
+ E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address),
+ E1_GETSA4(address), offset, data);
+
/* we send a request, but we expect a reply */
- sc->cmv_function = function | 0x2;
- sc->cmv_idx++;
- sc->cmv_address = address;
- sc->cmv_offset = offset;
+ sc->cmv_dsc.e1.function = function | 0x2;
+ sc->cmv_dsc.e1.idx++;
+ sc->cmv_dsc.e1.address = address;
+ sc->cmv_dsc.e1.offset = offset;
- cmv.wPreamble = cpu_to_le16(PREAMBLE);
- cmv.bDirection = HOSTTOMODEM;
+ cmv.wPreamble = cpu_to_le16(E1_PREAMBLE);
+ cmv.bDirection = E1_HOSTTOMODEM;
cmv.bFunction = function;
- cmv.wIndex = cpu_to_le16(sc->cmv_idx);
+ cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx);
put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress);
cmv.wOffsetAddress = cpu_to_le16(offset);
put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData);
- ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv);
+ ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
+ if (ret < 0)
+ return ret;
+ ret = wait_cmv_ack(sc);
+ uea_leaves(INS_TO_USBDEV(sc));
+ return ret;
+}
+
+static int uea_cmv_e4(struct uea_softc *sc,
+ u16 function, u16 group, u16 address, u16 offset, u32 data)
+{
+ struct cmv_e4 cmv;
+ int ret;
+
+ uea_enters(INS_TO_USBDEV(sc));
+ memset(&cmv, 0, sizeof(cmv));
+
+ uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, "
+ "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n",
+ E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function),
+ group, address, offset, data);
+
+ /* we send a request, but we expect a reply */
+ sc->cmv_dsc.e4.function = function | (0x1 << 4);
+ sc->cmv_dsc.e4.offset = offset;
+ sc->cmv_dsc.e4.address = address;
+ sc->cmv_dsc.e4.group = group;
+
+ cmv.wFunction = cpu_to_be16(function);
+ cmv.wGroup = cpu_to_be16(group);
+ cmv.wAddress = cpu_to_be16(address);
+ cmv.wOffset = cpu_to_be16(offset);
+ cmv.dwData[0] = cpu_to_be32(data);
+
+ ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
if (ret < 0)
return ret;
ret = wait_cmv_ack(sc);
@@ -826,10 +1198,10 @@ static int uea_cmv(struct uea_softc *sc,
return ret;
}
-static inline int uea_read_cmv(struct uea_softc *sc,
+static inline int uea_read_cmv_e1(struct uea_softc *sc,
u32 address, u16 offset, u32 *data)
{
- int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD),
+ int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD),
address, offset, 0);
if (ret < 0)
uea_err(INS_TO_USBDEV(sc),
@@ -840,10 +1212,27 @@ static inline int uea_read_cmv(struct uea_softc *sc,
return ret;
}
-static inline int uea_write_cmv(struct uea_softc *sc,
+static inline int uea_read_cmv_e4(struct uea_softc *sc,
+ u8 size, u16 group, u16 address, u16 offset, u32 *data)
+{
+ int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size),
+ group, address, offset, 0);
+ if (ret < 0)
+ uea_err(INS_TO_USBDEV(sc),
+ "reading cmv failed with error %d\n", ret);
+ else {
+ *data = sc->data;
+ /* size is in 16-bit word quantities */
+ if (size > 2)
+ *(data + 1) = sc->data1;
+ }
+ return ret;
+}
+
+static inline int uea_write_cmv_e1(struct uea_softc *sc,
u32 address, u16 offset, u32 data)
{
- int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE),
+ int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE),
address, offset, data);
if (ret < 0)
uea_err(INS_TO_USBDEV(sc),
@@ -852,12 +1241,48 @@ static inline int uea_write_cmv(struct uea_softc *sc,
return ret;
}
+static inline int uea_write_cmv_e4(struct uea_softc *sc,
+ u8 size, u16 group, u16 address, u16 offset, u32 data)
+{
+ int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size),
+ group, address, offset, data);
+ if (ret < 0)
+ uea_err(INS_TO_USBDEV(sc),
+ "writing cmv failed with error %d\n", ret);
+
+ return ret;
+}
+
+static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate)
+{
+ int ret;
+ u16 timeout;
+
+ /* in bulk mode the modem have problem with high rate
+ * changing internal timing could improve things, but the
+ * value is misterious.
+ * ADI930 don't support it (-EPIPE error).
+ */
+
+ if (UEA_CHIP_VERSION(sc) == ADI930 ||
+ altsetting[sc->modem_index] > 0 ||
+ sc->stats.phy.dsrate == dsrate)
+ return;
+
+ /* Original timming (1Mbit/s) from ADI (used in windows driver) */
+ timeout = (dsrate <= 1024*1024) ? 0 : 1;
+ ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
+ uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n",
+ timeout, ret < 0 ? " failed" : "");
+
+}
+
/*
* Monitor the modem and update the stat
* return 0 if everything is ok
* return < 0 if an error occurs (-EAGAIN reboot needed)
*/
-static int uea_stat(struct uea_softc *sc)
+static int uea_stat_e1(struct uea_softc *sc)
{
u32 data;
int ret;
@@ -865,7 +1290,7 @@ static int uea_stat(struct uea_softc *sc)
uea_enters(INS_TO_USBDEV(sc));
data = sc->stats.phy.state;
- ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state);
+ ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state);
if (ret < 0)
return ret;
@@ -885,7 +1310,7 @@ static int uea_stat(struct uea_softc *sc)
case 3: /* fail ... */
uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
- " (may be try other cmv/dsp)\n");
+ " (may be try other cmv/dsp)\n");
return -EAGAIN;
case 4 ... 6: /* test state */
@@ -923,7 +1348,7 @@ static int uea_stat(struct uea_softc *sc)
/* wake up processes waiting for synchronization */
wake_up(&sc->sync_q);
- ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags);
if (ret < 0)
return ret;
sc->stats.phy.mflags |= sc->stats.phy.flags;
@@ -937,105 +1362,223 @@ static int uea_stat(struct uea_softc *sc)
return 0;
}
- ret = uea_read_cmv(sc, SA_RATE, 0, &data);
+ ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data);
if (ret < 0)
return ret;
- /* in bulk mode the modem have problem with high rate
- * changing internal timing could improve things, but the
- * value is misterious.
- * ADI930 don't support it (-EPIPE error).
- */
- if (UEA_CHIP_VERSION(sc) != ADI930
- && !use_iso[sc->modem_index]
- && sc->stats.phy.dsrate != (data >> 16) * 32) {
- /* Original timming from ADI(used in windows driver)
- * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits
- */
- u16 timeout = (data <= 0x20ffff) ? 0 : 1;
- ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
- uea_info(INS_TO_USBDEV(sc),
- "setting new timeout %d%s\n", timeout,
- ret < 0?" failed":"");
- }
+ uea_set_bulk_timeout(sc, (data >> 16) * 32);
sc->stats.phy.dsrate = (data >> 16) * 32;
sc->stats.phy.usrate = (data & 0xffff) * 32;
UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
- ret = uea_read_cmv(sc, SA_DIAG, 23, &data);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data);
if (ret < 0)
return ret;
sc->stats.phy.dsattenuation = (data & 0xff) / 2;
- ret = uea_read_cmv(sc, SA_DIAG, 47, &data);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data);
if (ret < 0)
return ret;
sc->stats.phy.usattenuation = (data & 0xff) / 2;
- ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc);
if (ret < 0)
return ret;
/* only for atu-c */
- ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr);
if (ret < 0)
return ret;
/* only for atu-c */
- ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr);
+ ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco);
+ ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco);
if (ret < 0)
return ret;
- ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe);
+ ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe);
if (ret < 0)
return ret;
return 0;
}
-static int request_cmvs(struct uea_softc *sc,
- struct uea_cmvs **cmvs, const struct firmware **fw)
+static int uea_stat_e4(struct uea_softc *sc)
{
- int ret, size;
- u8 *data;
+ u32 data;
+ u32 tmp_arr[2];
+ int ret;
+
+ uea_enters(INS_TO_USBDEV(sc));
+ data = sc->stats.phy.state;
+
+ /* XXX only need to be done before operationnal... */
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state);
+ if (ret < 0)
+ return ret;
+
+ switch (sc->stats.phy.state) {
+ case 0x0: /* not yet synchronized */
+ case 0x1:
+ case 0x3:
+ case 0x4:
+ uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n");
+ return 0;
+ case 0x5: /* initialization */
+ case 0x6:
+ case 0x9:
+ case 0xa:
+ uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n");
+ return 0;
+ case 0x2: /* fail ... */
+ uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
+ " (may be try other cmv/dsp)\n");
+ return -EAGAIN;
+ case 0x7: /* operational */
+ break;
+ default:
+ uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state);
+ return 0;
+ }
+
+ if (data != 7) {
+ uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL);
+ uea_info(INS_TO_USBDEV(sc), "modem operational\n");
+
+ /* release the dsp firmware as it is not needed until
+ * the next failure
+ */
+ if (sc->dsp_firm) {
+ release_firmware(sc->dsp_firm);
+ sc->dsp_firm = NULL;
+ }
+ }
+
+ /* always update it as atm layer could not be init when we switch to
+ * operational state
+ */
+ UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND);
+
+ /* wake up processes waiting for synchronization */
+ wake_up(&sc->sync_q);
+
+ /* TODO improve this state machine :
+ * we need some CMV info : what they do and their unit
+ * we should find the equivalent of eagle3- CMV
+ */
+ /* check flags */
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.mflags |= sc->stats.phy.flags;
+
+ /* in case of a flags ( for example delineation LOSS (& 0x10)),
+ * we check the status again in order to detect the failure earlier
+ */
+ if (sc->stats.phy.flags) {
+ uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n",
+ sc->stats.phy.flags);
+ if (sc->stats.phy.flags & 1) //delineation LOSS
+ return -EAGAIN;
+ if (sc->stats.phy.flags & 0x4000) //Reset Flag
+ return -EAGAIN;
+ return 0;
+ }
+
+ /* rate data may be in upper or lower half of 64 bit word, strange */
+ ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr);
+ if (ret < 0)
+ return ret;
+ data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+ sc->stats.phy.usrate = data / 1000;
+
+ ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr);
+ if (ret < 0)
+ return ret;
+ data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+ uea_set_bulk_timeout(sc, data / 1000);
+ sc->stats.phy.dsrate = data / 1000;
+ UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
+
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.dsattenuation = data / 10;
+
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.usattenuation = data / 10;
+
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.dsmargin = data / 2;
+
+ ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data);
+ if (ret < 0)
+ return ret;
+ sc->stats.phy.usmargin = data / 10;
+
+ return 0;
+}
+
+static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
+{
+ char file_arr[] = "CMVxy.bin";
char *file;
- char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+ /* set proper name corresponding modem version and line type */
if (cmv_file[sc->modem_index] == NULL) {
if (UEA_CHIP_VERSION(sc) == ADI930)
- file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin";
+ file_arr[3] = '9';
+ else if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+ file_arr[3] = '4';
else
- file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin";
+ file_arr[3] = 'e';
+
+ file_arr[4] = IS_ISDN(sc) ? 'i' : 'p';
+ file = file_arr;
} else
file = cmv_file[sc->modem_index];
strcpy(cmv_name, FW_DIR);
- strlcat(cmv_name, file, sizeof(cmv_name));
+ strlcat(cmv_name, file, FIRMWARE_NAME_MAX);
+ if (ver == 2)
+ strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX);
+}
+
+static int request_cmvs_old(struct uea_softc *sc,
+ void **cmvs, const struct firmware **fw)
+{
+ int ret, size;
+ u8 *data;
+ char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+ cmvs_file_name(sc, cmv_name, 1);
ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
if (ret < 0) {
uea_err(INS_TO_USBDEV(sc),
@@ -1045,16 +1588,197 @@ static int request_cmvs(struct uea_softc *sc,
}
data = (u8 *) (*fw)->data;
- size = *data * sizeof(struct uea_cmvs) + 1;
- if (size != (*fw)->size) {
- uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
- cmv_name);
- release_firmware(*fw);
- return -EILSEQ;
+ size = (*fw)->size;
+ if (size < 1)
+ goto err_fw_corrupted;
+
+ if (size != *data * sizeof(struct uea_cmvs_v1) + 1)
+ goto err_fw_corrupted;
+
+ *cmvs = (void *)(data + 1);
+ return *data;
+
+err_fw_corrupted:
+ uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+ release_firmware(*fw);
+ return -EILSEQ;
+}
+
+static int request_cmvs(struct uea_softc *sc,
+ void **cmvs, const struct firmware **fw, int *ver)
+{
+ int ret, size;
+ u32 crc;
+ u8 *data;
+ char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+
+ cmvs_file_name(sc, cmv_name, 2);
+ ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
+ if (ret < 0) {
+ /* if caller can handle old version, try to provide it */
+ if (*ver == 1) {
+ uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, "
+ "try to get older cmvs\n", cmv_name);
+ return request_cmvs_old(sc, cmvs, fw);
+ }
+ uea_err(INS_TO_USBDEV(sc),
+ "requesting firmware %s failed with error %d\n",
+ cmv_name, ret);
+ return ret;
+ }
+
+ size = (*fw)->size;
+ data = (u8 *) (*fw)->data;
+ if (size < 4 || strncmp(data, "cmv2", 4) != 0) {
+ if (*ver == 1) {
+ uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, "
+ "try to get older cmvs\n", cmv_name);
+ release_firmware(*fw);
+ return request_cmvs_old(sc, cmvs, fw);
+ }
+ goto err_fw_corrupted;
}
- *cmvs = (struct uea_cmvs *)(data + 1);
+ *ver = 2;
+
+ data += 4;
+ size -= 4;
+ if (size < 5)
+ goto err_fw_corrupted;
+
+ crc = FW_GET_LONG(data);
+ data += 4;
+ size -= 4;
+ if (crc32_be(0, data, size) != crc)
+ goto err_fw_corrupted;
+
+ if (size != *data * sizeof(struct uea_cmvs_v2) + 1)
+ goto err_fw_corrupted;
+
+ *cmvs = (void *) (data + 1);
return *data;
+
+err_fw_corrupted:
+ uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+ release_firmware(*fw);
+ return -EILSEQ;
+}
+
+static int uea_send_cmvs_e1(struct uea_softc *sc)
+{
+ int i, ret, len;
+ void *cmvs_ptr;
+ const struct firmware *cmvs_fw;
+ int ver = 1; // we can handle v1 cmv firmware version;
+
+ /* Enter in R-IDLE (cmv) until instructed otherwise */
+ ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Dump firmware version */
+ ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid);
+ if (ret < 0)
+ return ret;
+ uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+ sc->stats.phy.firmid);
+
+ /* get options */
+ ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+ if (ret < 0)
+ return ret;
+
+ /* send options */
+ if (ver == 1) {
+ struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr;
+
+ uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, "
+ "please update your firmware\n");
+
+ for (i = 0; i < len; i++) {
+ ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address),
+ FW_GET_WORD(&cmvs_v1[i].offset),
+ FW_GET_LONG(&cmvs_v1[i].data));
+ if (ret < 0)
+ goto out;
+ }
+ } else if (ver == 2) {
+ struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
+
+ for (i = 0; i < len; i++) {
+ ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address),
+ (u16) FW_GET_LONG(&cmvs_v2[i].offset),
+ FW_GET_LONG(&cmvs_v2[i].data));
+ if (ret < 0)
+ goto out;
+ }
+ } else {
+ /* This realy should not happen */
+ uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+ goto out;
+ }
+
+ /* Enter in R-ACT-REQ */
+ ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2);
+ uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+ uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+ release_firmware(cmvs_fw);
+ return ret;
+}
+
+static int uea_send_cmvs_e4(struct uea_softc *sc)
+{
+ int i, ret, len;
+ void *cmvs_ptr;
+ const struct firmware *cmvs_fw;
+ int ver = 2; // we can only handle v2 cmv firmware version;
+
+ /* Enter in R-IDLE (cmv) until instructed otherwise */
+ ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Dump firmware version */
+ /* XXX don't read the 3th byte as it is always 6 */
+ ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid);
+ if (ret < 0)
+ return ret;
+ uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+ sc->stats.phy.firmid);
+
+
+ /* get options */
+ ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+ if (ret < 0)
+ return ret;
+
+ /* send options */
+ if (ver == 2) {
+ struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
+
+ for (i = 0; i < len; i++) {
+ ret = uea_write_cmv_e4(sc, 1,
+ FW_GET_LONG(&cmvs_v2[i].group),
+ FW_GET_LONG(&cmvs_v2[i].address),
+ FW_GET_LONG(&cmvs_v2[i].offset),
+ FW_GET_LONG(&cmvs_v2[i].data));
+ if (ret < 0)
+ goto out;
+ }
+ } else {
+ /* This realy should not happen */
+ uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+ goto out;
+ }
+
+ /* Enter in R-ACT-REQ */
+ ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2);
+ uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+ uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+ release_firmware(cmvs_fw);
+ return ret;
}
/* Start boot post firmware modem:
@@ -1066,9 +1790,7 @@ static int request_cmvs(struct uea_softc *sc,
static int uea_start_reset(struct uea_softc *sc)
{
u16 zero = 0; /* ;-) */
- int i, len, ret;
- struct uea_cmvs *cmvs;
- const struct firmware *cmvs_fw;
+ int ret;
uea_enters(INS_TO_USBDEV(sc));
uea_info(INS_TO_USBDEV(sc), "(re)booting started\n");
@@ -1093,25 +1815,36 @@ static int uea_start_reset(struct uea_softc *sc)
uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL);
/* original driver use 200ms, but windows driver use 100ms */
- msleep(100);
+ ret = uea_wait(sc, 0, msecs_to_jiffies(100));
+ if (ret < 0)
+ return ret;
/* leave reset mode */
uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL);
- /* clear tx and rx mailboxes */
- uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
- uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
- uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+ if (UEA_CHIP_VERSION(sc) != EAGLE_IV) {
+ /* clear tx and rx mailboxes */
+ uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
+ uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
+ uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+ }
+
+ ret = uea_wait(sc, 0, msecs_to_jiffies(1000));
+ if (ret < 0)
+ return ret;
+
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+ sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1);
+ else
+ sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY);
- msleep(1000);
- sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY);
/* demask interrupt */
sc->booting = 0;
/* start loading DSP */
sc->pageno = 0;
sc->ovl = 0;
- schedule_work(&sc->task);
+ queue_work(sc->work_q, &sc->task);
/* wait for modem ready CMV */
ret = wait_cmv_ack(sc);
@@ -1120,38 +1853,10 @@ static int uea_start_reset(struct uea_softc *sc)
uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n");
- /* Enter in R-IDLE (cmv) until instructed otherwise */
- ret = uea_write_cmv(sc, SA_CNTL, 0, 1);
- if (ret < 0)
- return ret;
-
- /* Dump firmware version */
- ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
+ ret = sc->send_cmvs(sc);
if (ret < 0)
return ret;
- uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
- sc->stats.phy.firmid);
- /* get options */
- ret = len = request_cmvs(sc, &cmvs, &cmvs_fw);
- if (ret < 0)
- return ret;
-
- /* send options */
- for (i = 0; i < len; i++) {
- ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address),
- FW_GET_WORD(&cmvs[i].offset),
- FW_GET_LONG(&cmvs[i].data));
- if (ret < 0)
- goto out;
- }
- /* Enter in R-ACT-REQ */
- ret = uea_write_cmv(sc, SA_CNTL, 0, 2);
- uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
- uea_info(INS_TO_USBDEV(sc), "Modem started, "
- "waiting synchronization\n");
-out:
- release_firmware(cmvs_fw);
sc->reset = 0;
uea_leaves(INS_TO_USBDEV(sc));
return ret;
@@ -1174,12 +1879,10 @@ static int uea_kthread(void *data)
if (ret < 0 || sc->reset)
ret = uea_start_reset(sc);
if (!ret)
- ret = uea_stat(sc);
+ ret = sc->stat(sc);
if (ret != -EAGAIN)
- msleep_interruptible(1000);
- if (try_to_freeze())
- uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
- "please unplug/replug your modem\n");
+ uea_wait(sc, 0, msecs_to_jiffies(1000));
+ try_to_freeze();
}
uea_leaves(INS_TO_USBDEV(sc));
return ret;
@@ -1234,7 +1937,6 @@ static int load_XILINX_firmware(struct uea_softc *sc)
if (ret < 0)
uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret);
-
err1:
release_firmware(fw_entry);
err0:
@@ -1243,40 +1945,41 @@ err0:
}
/* The modem send us an ack. First with check if it right */
-static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
+static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
{
+ struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1;
+ struct cmv_e1 *cmv = &intr->u.e1.s2.cmv;
+
uea_enters(INS_TO_USBDEV(sc));
- if (le16_to_cpu(cmv->wPreamble) != PREAMBLE)
+ if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE)
goto bad1;
- if (cmv->bDirection != MODEMTOHOST)
+ if (cmv->bDirection != E1_MODEMTOHOST)
goto bad1;
/* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to
* the first MEMACESS cmv. Ignore it...
*/
- if (cmv->bFunction != sc->cmv_function) {
+ if (cmv->bFunction != dsc->function) {
if (UEA_CHIP_VERSION(sc) == ADI930
- && cmv->bFunction == MAKEFUNCTION(2, 2)) {
- cmv->wIndex = cpu_to_le16(sc->cmv_idx);
- put_unaligned(cpu_to_le32(sc->cmv_address), &cmv->dwSymbolicAddress);
- cmv->wOffsetAddress = cpu_to_le16(sc->cmv_offset);
- }
- else
+ && cmv->bFunction == E1_MAKEFUNCTION(2, 2)) {
+ cmv->wIndex = cpu_to_le16(dsc->idx);
+ put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress);
+ cmv->wOffsetAddress = cpu_to_le16(dsc->offset);
+ } else
goto bad2;
}
- if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) {
+ if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) {
wake_up_cmv_ack(sc);
uea_leaves(INS_TO_USBDEV(sc));
return;
}
/* in case of MEMACCESS */
- if (le16_to_cpu(cmv->wIndex) != sc->cmv_idx ||
- le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) !=
- sc->cmv_address
- || le16_to_cpu(cmv->wOffsetAddress) != sc->cmv_offset)
+ if (le16_to_cpu(cmv->wIndex) != dsc->idx ||
+ le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address ||
+ le16_to_cpu(cmv->wOffsetAddress) != dsc->offset)
goto bad2;
sc->data = le32_to_cpu(get_unaligned(&cmv->dwData));
@@ -1289,8 +1992,8 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
bad2:
uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
"Function : %d, Subfunction : %d\n",
- FUNCTION_TYPE(cmv->bFunction),
- FUNCTION_SUBTYPE(cmv->bFunction));
+ E1_FUNCTION_TYPE(cmv->bFunction),
+ E1_FUNCTION_SUBTYPE(cmv->bFunction));
uea_leaves(INS_TO_USBDEV(sc));
return;
@@ -1301,6 +2004,61 @@ bad1:
uea_leaves(INS_TO_USBDEV(sc));
}
+/* The modem send us an ack. First with check if it right */
+static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+ struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4;
+ struct cmv_e4 *cmv = &intr->u.e4.s2.cmv;
+
+ uea_enters(INS_TO_USBDEV(sc));
+ uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n",
+ be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction),
+ be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress),
+ be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1]));
+
+ if (be16_to_cpu(cmv->wFunction) != dsc->function)
+ goto bad2;
+
+ if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) {
+ wake_up_cmv_ack(sc);
+ uea_leaves(INS_TO_USBDEV(sc));
+ return;
+ }
+
+ /* in case of MEMACCESS */
+ if (be16_to_cpu(cmv->wOffset) != dsc->offset ||
+ be16_to_cpu(cmv->wGroup) != dsc->group ||
+ be16_to_cpu(cmv->wAddress) != dsc->address)
+ goto bad2;
+
+ sc->data = be32_to_cpu(cmv->dwData[0]);
+ sc->data1 = be32_to_cpu(cmv->dwData[1]);
+ wake_up_cmv_ack(sc);
+ uea_leaves(INS_TO_USBDEV(sc));
+ return;
+
+bad2:
+ uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
+ "Function : %d, Subfunction : %d\n",
+ E4_FUNCTION_TYPE(cmv->wFunction),
+ E4_FUNCTION_SUBTYPE(cmv->wFunction));
+ uea_leaves(INS_TO_USBDEV(sc));
+ return;
+}
+
+static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr)
+{
+ sc->pageno = intr->e1_bSwapPageNo;
+ sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4;
+ queue_work(sc->work_q, &sc->task);
+}
+
+static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+ sc->pageno = intr->e4_bSwapPageNo;
+ queue_work(sc->work_q, &sc->task);
+}
+
/*
* interrupt handler
*/
@@ -1326,13 +2084,11 @@ static void uea_intr(struct urb *urb)
switch (le16_to_cpu(intr->wInterrupt)) {
case INT_LOADSWAPPAGE:
- sc->pageno = intr->bSwapPageNo;
- sc->ovl = intr->bOvl >> 4 | intr->bOvl << 4;
- schedule_work(&sc->task);
+ sc->schedule_load_page(sc, intr);
break;
case INT_INCOMINGCMV:
- uea_dispatch_cmv(sc, &intr->u.s2.cmv);
+ sc->dispatch_cmv(sc, intr);
break;
default:
@@ -1349,35 +2105,55 @@ resubmit:
*/
static int uea_boot(struct uea_softc *sc)
{
- int ret;
+ int ret, size;
struct intr_pkt *intr;
uea_enters(INS_TO_USBDEV(sc));
- INIT_WORK(&sc->task, uea_load_page);
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+ size = E4_INTR_PKT_SIZE;
+ sc->dispatch_cmv = uea_dispatch_cmv_e4;
+ sc->schedule_load_page = uea_schedule_load_page_e4;
+ sc->stat = uea_stat_e4;
+ sc->send_cmvs = uea_send_cmvs_e4;
+ INIT_WORK(&sc->task, uea_load_page_e4);
+ } else {
+ size = E1_INTR_PKT_SIZE;
+ sc->dispatch_cmv = uea_dispatch_cmv_e1;
+ sc->schedule_load_page = uea_schedule_load_page_e1;
+ sc->stat = uea_stat_e1;
+ sc->send_cmvs = uea_send_cmvs_e1;
+ INIT_WORK(&sc->task, uea_load_page_e1);
+ }
+
init_waitqueue_head(&sc->sync_q);
- init_waitqueue_head(&sc->cmv_ack_wait);
+
+ sc->work_q = create_workqueue("ueagle-dsp");
+ if (!sc->work_q) {
+ uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n");
+ uea_leaves(INS_TO_USBDEV(sc));
+ return -ENOMEM;
+ }
if (UEA_CHIP_VERSION(sc) == ADI930)
load_XILINX_firmware(sc);
- intr = kmalloc(INTR_PKT_SIZE, GFP_KERNEL);
+ intr = kmalloc(size, GFP_KERNEL);
if (!intr) {
uea_err(INS_TO_USBDEV(sc),
"cannot allocate interrupt package\n");
- uea_leaves(INS_TO_USBDEV(sc));
- return -ENOMEM;
+ goto err0;
}
sc->urb_int = usb_alloc_urb(0, GFP_KERNEL);
if (!sc->urb_int) {
uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n");
- goto err;
+ goto err1;
}
usb_fill_int_urb(sc->urb_int, sc->usb_dev,
usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE),
- intr, INTR_PKT_SIZE, uea_intr, sc,
+ intr, size, uea_intr, sc,
sc->usb_dev->actconfig->interface[0]->altsetting[0].
endpoint[0].desc.bInterval);
@@ -1385,7 +2161,7 @@ static int uea_boot(struct uea_softc *sc)
if (ret < 0) {
uea_err(INS_TO_USBDEV(sc),
"urb submition failed with error %d\n", ret);
- goto err;
+ goto err1;
}
sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm");
@@ -1399,10 +2175,12 @@ static int uea_boot(struct uea_softc *sc)
err2:
usb_kill_urb(sc->urb_int);
-err:
+err1:
usb_free_urb(sc->urb_int);
sc->urb_int = NULL;
kfree(intr);
+err0:
+ destroy_workqueue(sc->work_q);
uea_leaves(INS_TO_USBDEV(sc));
return -ENOMEM;
}
@@ -1417,15 +2195,15 @@ static void uea_stop(struct uea_softc *sc)
ret = kthread_stop(sc->kthread);
uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret);
- /* stop any pending boot process */
- flush_scheduled_work();
-
uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL);
usb_kill_urb(sc->urb_int);
kfree(sc->urb_int->transfer_buffer);
usb_free_urb(sc->urb_int);
+ /* stop any pending boot process, when no one can schedule work */
+ destroy_workqueue(sc->work_q);
+
if (sc->dsp_firm)
release_firmware(sc->dsp_firm);
uea_leaves(INS_TO_USBDEV(sc));
@@ -1487,6 +2265,7 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
char *buf)
{
int ret = -ENODEV;
+ int modem_state;
struct uea_softc *sc;
mutex_lock(&uea_mutex);
@@ -1494,7 +2273,34 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
if (!sc)
goto out;
- switch (GET_STATUS(sc->stats.phy.state)) {
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+ switch (sc->stats.phy.state) {
+ case 0x0: /* not yet synchronized */
+ case 0x1:
+ case 0x3:
+ case 0x4:
+ modem_state = 0;
+ break;
+ case 0x5: /* initialization */
+ case 0x6:
+ case 0x9:
+ case 0xa:
+ modem_state = 1;
+ break;
+ case 0x7: /* operational */
+ modem_state = 2;
+ break;
+ case 0x2: /* fail ... */
+ modem_state = 3;
+ break;
+ default: /* unknown */
+ modem_state = 4;
+ break;
+ }
+ } else
+ modem_state = GET_STATUS(sc->stats.phy.state);
+
+ switch (modem_state) {
case 0:
ret = sprintf(buf, "Modem is booting\n");
break;
@@ -1504,9 +2310,12 @@ static ssize_t read_human_status(struct device *dev, struct device_attribute *at
case 2:
ret = sprintf(buf, "Modem is operational\n");
break;
- default:
+ case 3:
ret = sprintf(buf, "Modem synchronization failed\n");
break;
+ default:
+ ret = sprintf(buf, "Modem state is unknown\n");
+ break;
}
out:
mutex_unlock(&uea_mutex);
@@ -1520,18 +2329,26 @@ static ssize_t read_delin(struct device *dev, struct device_attribute *attr,
{
int ret = -ENODEV;
struct uea_softc *sc;
+ char *delin = "GOOD";
mutex_lock(&uea_mutex);
sc = dev_to_uea(dev);
if (!sc)
goto out;
- if (sc->stats.phy.flags & 0x0C00)
- ret = sprintf(buf, "ERROR\n");
- else if (sc->stats.phy.flags & 0x0030)
- ret = sprintf(buf, "LOSS\n");
- else
- ret = sprintf(buf, "GOOD\n");
+ if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+ if (sc->stats.phy.flags & 0x4000)
+ delin = "RESET";
+ else if (sc->stats.phy.flags & 0x0001)
+ delin = "LOSS";
+ } else {
+ if (sc->stats.phy.flags & 0x0C00)
+ delin = "ERROR";
+ else if (sc->stats.phy.flags & 0x0030)
+ delin = "LOSS";
+ }
+
+ ret = sprintf(buf, "%s\n", delin);
out:
mutex_unlock(&uea_mutex);
return ret;
@@ -1662,6 +2479,7 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
struct usb_device *usb = interface_to_usbdev(intf);
struct uea_softc *sc;
int ret, ifnum = intf->altsetting->desc.bInterfaceNumber;
+ unsigned int alt;
uea_enters(usb);
@@ -1696,22 +2514,29 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0;
sc->driver_info = id->driver_info;
- /* ADI930 don't support iso */
- if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) {
- int i;
-
- /* try set fastest alternate for inbound traffic interface */
- for (i = FASTEST_ISO_INTF; i > 0; i--)
- if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0)
- break;
+ /* first try to use module parameter */
+ if (annex[sc->modem_index] == 1)
+ sc->annex = ANNEXA;
+ else if (annex[sc->modem_index] == 2)
+ sc->annex = ANNEXB;
+ /* try to autodetect annex */
+ else if (sc->driver_info & AUTO_ANNEX_A)
+ sc->annex = ANNEXA;
+ else if (sc->driver_info & AUTO_ANNEX_B)
+ sc->annex = ANNEXB;
+ else
+ sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA;
- if (i > 0) {
- uea_dbg(usb, "set alternate %d for 2 interface\n", i);
+ alt = altsetting[sc->modem_index];
+ /* ADI930 don't support iso */
+ if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) {
+ if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) {
+ uea_dbg(usb, "set alternate %u for 2 interface\n", alt);
uea_info(usb, "using iso mode\n");
usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ;
} else {
- uea_err(usb, "setting any alternate failed for "
- "2 interface, using bulk mode\n");
+ uea_err(usb, "setting alternate %u failed for "
+ "2 interface, using bulk mode\n", alt);
}
}
@@ -1757,10 +2582,11 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct usb_device *usb = interface_to_usbdev(intf);
uea_enters(usb);
- uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n",
- le16_to_cpu(usb->descriptor.idVendor),
- le16_to_cpu(usb->descriptor.idProduct),
- chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots");
+ uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n",
+ le16_to_cpu(usb->descriptor.idVendor),
+ le16_to_cpu(usb->descriptor.idProduct),
+ le16_to_cpu(usb->descriptor.bcdDevice),
+ chip_name[UEA_CHIP_VERSION(id)]);
usb_reset_device(usb);
@@ -1793,24 +2619,40 @@ static void uea_disconnect(struct usb_interface *intf)
* List of supported VID/PID
*/
static const struct usb_device_id uea_ids[] = {
+ {USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM), .driver_info = ADI930 | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM), .driver_info = EAGLE_IV | PREFIRM},
+ {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM), .driver_info = EAGLE_IV | PSTFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
+ {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B},
{USB_DEVICE(ELSA_VID, ELSA_PID_PREFIRM), .driver_info = ADI930 | PREFIRM},
{USB_DEVICE(ELSA_VID, ELSA_PID_PSTFIRM), .driver_info = ADI930 | PSTFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_I_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_II_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PREFIRM), .driver_info = EAGLE_II | PREFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_IIC_PID_PSTFIRM), .driver_info = EAGLE_II | PSTFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PREFIRM), .driver_info = EAGLE_III | PREFIRM},
- {USB_DEVICE(EAGLE_VID, EAGLE_III_PID_PSTFIRM), .driver_info = EAGLE_III | PSTFIRM},
+ {USB_DEVICE(ELSA_VID, ELSA_PID_A_PREFIRM), .driver_info = ADI930 | PREFIRM},
+ {USB_DEVICE(ELSA_VID, ELSA_PID_A_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A},
+ {USB_DEVICE(ELSA_VID, ELSA_PID_B_PREFIRM), .driver_info = ADI930 | PREFIRM},
+ {USB_DEVICE(ELSA_VID, ELSA_PID_B_PSTFIRM), .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B},
{USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
{USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), .driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
{USB_DEVICE(USR_VID, HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
{USB_DEVICE(USR_VID, HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
- {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+ {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
{}
};
diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c
index 70125c6d3be..8472543eee8 100644
--- a/drivers/usb/atm/xusbatm.c
+++ b/drivers/usb/atm/xusbatm.c
@@ -29,7 +29,7 @@
#define XUSBATM_PARM(name, type, parmtype, desc) \
static type name[XUSBATM_DRIVERS_MAX]; \
- static int num_##name; \
+ static unsigned int num_##name; \
module_param_array(name, parmtype, &num_##name, 0444); \
MODULE_PARM_DESC(name, desc)
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index f51e22490ed..912d97aaf9b 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -332,7 +332,7 @@ static void acm_read_bulk(struct urb *urb)
return;
if (status)
- dev_dbg(&acm->data->dev, "bulk rx status %d", status);
+ dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);
buf = rcv->buffer;
buf->size = urb->actual_length;
@@ -831,13 +831,13 @@ static int acm_probe (struct usb_interface *intf,
/* normal probing*/
if (!buffer) {
- err("Wierd descriptor references\n");
+ err("Weird descriptor references\n");
return -EINVAL;
}
if (!buflen) {
if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
- dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint");
+ dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n");
buflen = intf->cur_altsetting->endpoint->extralen;
buffer = intf->cur_altsetting->endpoint->extra;
} else {
@@ -887,24 +887,24 @@ next_desc:
if (!union_header) {
if (call_interface_num > 0) {
- dev_dbg(&intf->dev,"No union descriptor, using call management descriptor");
+ dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n");
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
control_interface = intf;
} else {
- dev_dbg(&intf->dev,"No union descriptor, giving up");
+ dev_dbg(&intf->dev,"No union descriptor, giving up\n");
return -ENODEV;
}
} else {
control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
if (!control_interface || !data_interface) {
- dev_dbg(&intf->dev,"no interfaces");
+ dev_dbg(&intf->dev,"no interfaces\n");
return -ENODEV;
}
}
if (data_interface_num != call_interface_num)
- dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.");
+ dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n");
skip_normal_probe:
@@ -912,7 +912,7 @@ skip_normal_probe:
if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
struct usb_interface *t;
- dev_dbg(&intf->dev,"Your device has switched interfaces.");
+ dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
t = control_interface;
control_interface = data_interface;
@@ -927,7 +927,7 @@ skip_normal_probe:
return -ENODEV;
if (usb_interface_claimed(data_interface)) { /* valid in this context */
- dev_dbg(&intf->dev,"The data interface isn't available");
+ dev_dbg(&intf->dev,"The data interface isn't available\n");
return -EBUSY;
}
@@ -944,7 +944,7 @@ skip_normal_probe:
if (!usb_endpoint_dir_in(epread)) {
/* descriptors are swapped */
struct usb_endpoint_descriptor *t;
- dev_dbg(&intf->dev,"The data interface has switched endpoints");
+ dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
t = epread;
epread = epwrite;
@@ -959,7 +959,7 @@ skip_normal_probe:
}
if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
- dev_dbg(&intf->dev, "out of memory (acm kzalloc)");
+ dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
goto alloc_fail;
}
@@ -985,26 +985,26 @@ skip_normal_probe:
buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
if (!buf) {
- dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)");
+ dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
goto alloc_fail2;
}
acm->ctrl_buffer = buf;
if (acm_write_buffers_alloc(acm) < 0) {
- dev_dbg(&intf->dev, "out of memory (write buffer alloc)");
+ dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
goto alloc_fail4;
}
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->ctrlurb) {
- dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)");
+ dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
goto alloc_fail5;
}
for (i = 0; i < num_rx_buf; i++) {
struct acm_ru *rcv = &(acm->ru[i]);
if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
- dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)");
+ dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n");
goto alloc_fail7;
}
@@ -1015,13 +1015,13 @@ skip_normal_probe:
struct acm_rb *buf = &(acm->rb[i]);
if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
- dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)");
+ dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
goto alloc_fail7;
}
}
acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->writeurb) {
- dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)");
+ dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n");
goto alloc_fail7;
}
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 5192cd9356d..ad632f2d6f9 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -28,6 +28,7 @@
* v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
* v0.13 - alloc space for statusbuf (<status> not on stack);
* use usb_buffer_alloc() for read buf & write buf;
+ * none - Maintained in Linux kernel after v0.13
*/
/*
@@ -69,7 +70,6 @@
#define USBLP_DEVICE_ID_SIZE 1024
/* ioctls: */
-#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */
#define IOCNR_GET_DEVICE_ID 1
#define IOCNR_GET_PROTOCOLS 2
#define IOCNR_SET_PROTOCOL 3
@@ -115,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
#define USBLP_MINORS 16
#define USBLP_MINOR_BASE 0
-#define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */
+#define USBLP_CTL_TIMEOUT 5000 /* 5 seconds */
#define USBLP_FIRST_PROTOCOL 1
#define USBLP_LAST_PROTOCOL 3
@@ -159,10 +159,12 @@ struct usblp {
int wstatus; /* bytes written or error */
int rstatus; /* bytes ready or error */
unsigned int quirks; /* quirks flags */
+ unsigned int flags; /* mode flags */
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
unsigned char bidir; /* interface is bidirectional */
unsigned char sleeping; /* interface is suspended */
+ unsigned char no_paper; /* Paper Out happened */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
/* first 2 bytes are (big-endian) length */
};
@@ -259,7 +261,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
retval = usb_control_msg(usblp->dev,
dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
- request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
+ request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
request, !!dir, recip, value, index, len, retval);
return retval < 0 ? retval : 0;
@@ -325,13 +327,11 @@ static void usblp_bulk_write(struct urb *urb)
usblp->wstatus = status;
else
usblp->wstatus = urb->actual_length;
+ usblp->no_paper = 0;
usblp->wcomplete = 1;
wake_up(&usblp->wwait);
spin_unlock(&usblp->lock);
- /* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */
- kfree(urb->transfer_buffer);
- urb->transfer_buffer = NULL; /* Not refcounted, so to be safe... */
usb_free_urb(urb);
}
@@ -346,16 +346,17 @@ static int usblp_check_status(struct usblp *usblp, int err)
unsigned char status, newerr = 0;
int error;
- error = usblp_read_status (usblp, usblp->statusbuf);
- if (error < 0) {
+ mutex_lock(&usblp->mut);
+ if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
+ mutex_unlock(&usblp->mut);
if (printk_ratelimit())
printk(KERN_ERR
"usblp%d: error %d reading printer status\n",
usblp->minor, error);
return 0;
}
-
status = *usblp->statusbuf;
+ mutex_unlock(&usblp->mut);
if (~status & LP_PERRORP)
newerr = 3;
@@ -411,18 +412,10 @@ static int usblp_open(struct inode *inode, struct file *file)
goto out;
/*
- * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
- * This is #if 0-ed because we *don't* want to fail an open
- * just because the printer is off-line.
+ * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
+ * - We do not want persistent state which close(2) does not clear
+ * - It is not used anyway, according to CUPS people
*/
-#if 0
- if ((retval = usblp_check_status(usblp, 0))) {
- retval = retval > 1 ? -EIO : -ENOSPC;
- goto out;
- }
-#else
- retval = 0;
-#endif
retval = usb_autopm_get_interface(intf);
if (retval < 0)
@@ -463,6 +456,8 @@ static int usblp_release(struct inode *inode, struct file *file)
{
struct usblp *usblp = file->private_data;
+ usblp->flags &= ~LP_ABORT;
+
mutex_lock (&usblp_mutex);
usblp->used = 0;
if (usblp->present) {
@@ -485,8 +480,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
poll_wait(file, &usblp->rwait, wait);
poll_wait(file, &usblp->wwait, wait);
spin_lock_irqsave(&usblp->lock, flags);
- ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM)
- | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
+ ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) |
+ ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0);
spin_unlock_irqrestore(&usblp->lock, flags);
return ret;
}
@@ -675,6 +670,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
+ case LPABORT:
+ if (arg)
+ usblp->flags |= LP_ABORT;
+ else
+ usblp->flags &= ~LP_ABORT;
+ break;
+
default:
retval = -ENOTTY;
}
@@ -684,10 +686,30 @@ done:
return retval;
}
+static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
+{
+ struct urb *urb;
+ char *writebuf;
+
+ if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL)
+ return NULL;
+ if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
+ kfree(writebuf);
+ return NULL;
+ }
+
+ usb_fill_bulk_urb(urb, usblp->dev,
+ usb_sndbulkpipe(usblp->dev,
+ usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
+ writebuf, transfer_length, usblp_bulk_write, usblp);
+ urb->transfer_flags |= URB_FREE_BUFFER;
+
+ return urb;
+}
+
static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
- char *writebuf;
struct urb *writeurb;
int rv;
int transfer_length;
@@ -708,17 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
transfer_length = USBLP_BUF_SIZE;
rv = -ENOMEM;
- if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
- goto raise_buf;
- if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
+ if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL)
goto raise_urb;
- usb_fill_bulk_urb(writeurb, usblp->dev,
- usb_sndbulkpipe(usblp->dev,
- usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
- writebuf, transfer_length, usblp_bulk_write, usblp);
usb_anchor_urb(writeurb, &usblp->urbs);
- if (copy_from_user(writebuf,
+ if (copy_from_user(writeurb->transfer_buffer,
buffer + writecount, transfer_length)) {
rv = -EFAULT;
goto raise_badaddr;
@@ -730,6 +746,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
usblp->wstatus = 0;
spin_lock_irq(&usblp->lock);
+ usblp->no_paper = 0;
usblp->wcomplete = 1;
wake_up(&usblp->wwait);
spin_unlock_irq(&usblp->lock);
@@ -747,12 +764,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
/* Presume that it's going to complete well. */
writecount += transfer_length;
}
+ if (rv == -ENOSPC) {
+ spin_lock_irq(&usblp->lock);
+ usblp->no_paper = 1; /* Mark for poll(2) */
+ spin_unlock_irq(&usblp->lock);
+ writecount += transfer_length;
+ }
/* Leave URB dangling, to be cleaned on close. */
goto collect_error;
}
if (usblp->wstatus < 0) {
- usblp_check_status(usblp, 0);
rv = -EIO;
goto collect_error;
}
@@ -771,8 +793,6 @@ raise_badaddr:
usb_unanchor_urb(writeurb);
usb_free_urb(writeurb);
raise_urb:
- kfree(writebuf);
-raise_buf:
raise_wait:
collect_error: /* Out of raise sequence */
mutex_unlock(&usblp->wmut);
@@ -838,32 +858,36 @@ done:
* when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
* select(2) or poll(2) to wait for the buffer to drain before closing.
* Alternatively, set blocking mode with fcntl and issue a zero-size write.
- *
- * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot
- * to check the return code for timeout expiration, so it had no effect.
- * Apparently, it was intended to check for error conditons, such as out
- * of paper. It is going to return when we settle things with CUPS. XXX
*/
static int usblp_wwait(struct usblp *usblp, int nonblock)
{
DECLARE_WAITQUEUE(waita, current);
int rc;
+ int err = 0;
add_wait_queue(&usblp->wwait, &waita);
for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
if (mutex_lock_interruptible(&usblp->mut)) {
rc = -EINTR;
break;
}
- set_current_state(TASK_INTERRUPTIBLE);
- if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
- mutex_unlock(&usblp->mut);
- break;
- }
+ rc = usblp_wtest(usblp, nonblock);
mutex_unlock(&usblp->mut);
- if (rc == 0)
+ if (rc <= 0)
break;
- schedule();
+
+ if (usblp->flags & LP_ABORT) {
+ if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
+ err = usblp_check_status(usblp, err);
+ if (err == 1) { /* Paper out */
+ rc = -ENOSPC;
+ break;
+ }
+ }
+ } else {
+ schedule();
+ }
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&usblp->wwait, &waita);
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index ead2475406b..28d4972f7ad 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -11,7 +11,6 @@
#include <linux/device.h>
#include <linux/mm.h>
#include <asm/io.h>
-#include <asm/scatterlist.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/usb.h>
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index cb69aa1e02e..1a8edcee7f3 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -507,18 +507,30 @@ void usb_destroy_configuration(struct usb_device *dev)
}
-// hub-only!! ... and only in reset path, or usb_new_device()
-// (used by real hubs and virtual root hubs)
+/*
+ * Get the USB config descriptors, cache and parse'em
+ *
+ * hub-only!! ... and only in reset path, or usb_new_device()
+ * (used by real hubs and virtual root hubs)
+ *
+ * NOTE: if this is a WUSB device and is not authorized, we skip the
+ * whole thing. A non-authorized USB device has no
+ * configurations.
+ */
int usb_get_configuration(struct usb_device *dev)
{
struct device *ddev = &dev->dev;
int ncfg = dev->descriptor.bNumConfigurations;
- int result = -ENOMEM;
+ int result = 0;
unsigned int cfgno, length;
unsigned char *buffer;
unsigned char *bigbuffer;
struct usb_config_descriptor *desc;
+ cfgno = 0;
+ if (dev->authorized == 0) /* Not really an error */
+ goto out_not_authorized;
+ result = -ENOMEM;
if (ncfg > USB_MAXCONFIG) {
dev_warn(ddev, "too many configurations: %d, "
"using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
@@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev)
goto err2;
desc = (struct usb_config_descriptor *)buffer;
- for (cfgno = 0; cfgno < ncfg; cfgno++) {
+ result = 0;
+ for (; cfgno < ncfg; cfgno++) {
/* We grab just the first descriptor so we know how long
* the whole configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
buffer, USB_DT_CONFIG_SIZE);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
- "descriptor/%s\n", cfgno, "start");
+ "descriptor/%s: %d\n", cfgno, "start", result);
dev_err(ddev, "chopping to %d config(s)\n", cfgno);
dev->descriptor.bNumConfigurations = cfgno;
break;
@@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev)
err:
kfree(buffer);
+out_not_authorized:
dev->descriptor.bNumConfigurations = cfgno;
err2:
if (result == -ENOMEM)
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 927a181120a..1f4f6d02fe2 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -71,6 +71,7 @@ struct async {
void __user *userbuffer;
void __user *userurb;
struct urb *urb;
+ int status;
u32 secid;
};
@@ -289,10 +290,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
if (!usbfs_snoop)
return;
- if (urb->pipe & USB_DIR_IN)
- dev_info(&urb->dev->dev, "direction=IN\n");
- else
- dev_info(&urb->dev->dev, "direction=OUT\n");
+ dev_info(&urb->dev->dev, "direction=%s\n",
+ usb_urb_dir_in(urb) ? "IN" : "OUT");
dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
urb->transfer_buffer_length);
@@ -312,9 +311,10 @@ static void async_completed(struct urb *urb)
spin_lock(&ps->lock);
list_move_tail(&as->asynclist, &ps->async_completed);
spin_unlock(&ps->lock);
+ as->status = urb->status;
if (as->signr) {
sinfo.si_signo = as->signr;
- sinfo.si_errno = as->urb->status;
+ sinfo.si_errno = as->status;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb;
kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
@@ -460,7 +460,7 @@ static int checkintf(struct dev_state *ps, unsigned int ifnum)
return 0;
/* if not yet claimed, claim it for the driver */
dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim interface %u before use\n",
- current->pid, current->comm, ifnum);
+ task_pid_nr(current), current->comm, ifnum);
return claimintf(ps, ifnum);
}
@@ -910,6 +910,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
struct usb_ctrlrequest *dr = NULL;
unsigned int u, totlen, isofrmlen;
int ret, ifnum = -1;
+ int is_in;
if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
URB_NO_FSBR|URB_ZERO_PACKET))
@@ -924,16 +925,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
if ((ret = checkintf(ps, ifnum)))
return ret;
}
- if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0)
- ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
- else
- ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+ if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
+ is_in = 1;
+ ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+ } else {
+ is_in = 0;
+ ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+ }
if (!ep)
return -ENOENT;
switch(uurb->type) {
case USBDEVFS_URB_TYPE_CONTROL:
- if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_CONTROL)
+ if (!usb_endpoint_xfer_control(&ep->desc))
return -EINVAL;
/* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
@@ -952,23 +955,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
kfree(dr);
return ret;
}
- uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
uurb->number_of_packets = 0;
uurb->buffer_length = le16_to_cpup(&dr->wLength);
uurb->buffer += 8;
- if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) {
+ if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
+ is_in = 1;
+ uurb->endpoint |= USB_DIR_IN;
+ } else {
+ is_in = 0;
+ uurb->endpoint &= ~USB_DIR_IN;
+ }
+ if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+ uurb->buffer, uurb->buffer_length)) {
kfree(dr);
return -EFAULT;
}
snoop(&ps->dev->dev, "control urb: bRequest=%02x "
"bRrequestType=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
- dr->bRequest, dr->bRequestType, dr->wValue,
- dr->wIndex, dr->wLength);
+ dr->bRequest, dr->bRequestType,
+ __le16_to_cpup(&dr->wValue),
+ __le16_to_cpup(&dr->wIndex),
+ __le16_to_cpup(&dr->wLength));
break;
case USBDEVFS_URB_TYPE_BULK:
- switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ switch (usb_endpoint_type(&ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_ISOC:
return -EINVAL;
@@ -977,7 +989,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
uurb->number_of_packets = 0;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
- if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+ if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+ uurb->buffer, uurb->buffer_length))
return -EFAULT;
snoop(&ps->dev->dev, "bulk urb\n");
break;
@@ -986,8 +999,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
/* arbitrary limit */
if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
return -EINVAL;
- if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_ISOC)
+ if (!usb_endpoint_xfer_isoc(&ep->desc))
return -EINVAL;
isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
@@ -1014,12 +1026,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
case USBDEVFS_URB_TYPE_INTERRUPT:
uurb->number_of_packets = 0;
- if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_INT)
+ if (!usb_endpoint_xfer_int(&ep->desc))
return -EINVAL;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
- if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+ if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+ uurb->buffer, uurb->buffer_length))
return -EFAULT;
snoop(&ps->dev->dev, "interrupt urb\n");
break;
@@ -1039,8 +1051,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -ENOMEM;
}
as->urb->dev = ps->dev;
- as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
- as->urb->transfer_flags = uurb->flags;
+ as->urb->pipe = (uurb->type << 30) |
+ __create_pipe(ps->dev, uurb->endpoint & 0xf) |
+ (uurb->endpoint & USB_DIR_IN);
+ as->urb->transfer_flags = uurb->flags |
+ (is_in ? URB_DIR_IN : URB_DIR_OUT);
as->urb->transfer_buffer_length = uurb->buffer_length;
as->urb->setup_packet = (unsigned char*)dr;
as->urb->start_frame = uurb->start_frame;
@@ -1070,13 +1085,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->uid = current->uid;
as->euid = current->euid;
security_task_getsecid(current, &as->secid);
- if (!(uurb->endpoint & USB_DIR_IN)) {
- if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
+ if (!is_in) {
+ if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
+ as->urb->transfer_buffer_length)) {
free_async(as);
return -EFAULT;
}
}
- snoop(&as->urb->dev->dev, "submit urb\n");
snoop_urb(as->urb, as->userurb);
async_newpending(as);
if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
@@ -1119,14 +1134,14 @@ static int processcompl(struct async *as, void __user * __user *arg)
if (as->userbuffer)
if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
return -EFAULT;
- if (put_user(urb->status, &userurb->status))
+ if (put_user(as->status, &userurb->status))
return -EFAULT;
if (put_user(urb->actual_length, &userurb->actual_length))
return -EFAULT;
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
- if (usb_pipeisoc(urb->pipe)) {
+ if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))
@@ -1233,14 +1248,14 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
if (as->userbuffer)
if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
return -EFAULT;
- if (put_user(urb->status, &userurb->status))
+ if (put_user(as->status, &userurb->status))
return -EFAULT;
if (put_user(urb->actual_length, &userurb->actual_length))
return -EFAULT;
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
- if (usb_pipeisoc(urb->pipe)) {
+ if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))
@@ -1576,6 +1591,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai
}
const struct file_operations usbdev_file_operations = {
+ .owner = THIS_MODULE,
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
@@ -1625,10 +1641,7 @@ static struct notifier_block usbdev_nb = {
};
#endif
-static struct cdev usb_device_cdev = {
- .kobj = {.name = "usb_device", },
- .owner = THIS_MODULE,
-};
+static struct cdev usb_device_cdev;
int __init usb_devio_init(void)
{
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 63b1243a913..8586817698a 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -202,6 +202,11 @@ static int usb_probe_interface(struct device *dev)
intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf);
+ if (udev->authorized == 0) {
+ dev_err(&intf->dev, "Device is not authorized for usage\n");
+ return -ENODEV;
+ }
+
id = usb_match_id(intf, driver->id_table);
if (!id)
id = usb_match_dynamic_id(intf, driver);
@@ -576,12 +581,9 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
}
#ifdef CONFIG_HOTPLUG
-static int usb_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct usb_device *usb_dev;
- int i = 0;
- int length = 0;
if (!dev)
return -ENODEV;
@@ -610,51 +612,39 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp,
* all the device descriptors we don't tell them about. Or
* act as usermode drivers.
*/
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVICE=/proc/bus/usb/%03d/%03d",
+ if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
usb_dev->bus->busnum, usb_dev->devnum))
return -ENOMEM;
#endif
/* per-device configurations are common */
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PRODUCT=%x/%x/%x",
+ if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
le16_to_cpu(usb_dev->descriptor.bcdDevice)))
return -ENOMEM;
/* class-based driver binding models */
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "TYPE=%d/%d/%d",
+ if (add_uevent_var(env, "TYPE=%d/%d/%d",
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
usb_dev->descriptor.bDeviceProtocol))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "BUSNUM=%03d",
+ if (add_uevent_var(env, "BUSNUM=%03d",
usb_dev->bus->busnum))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVNUM=%03d",
+ if (add_uevent_var(env, "DEVNUM=%03d",
usb_dev->devnum))
return -ENOMEM;
- envp[i] = NULL;
return 0;
}
#else
-static int usb_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
@@ -945,11 +935,11 @@ done:
#ifdef CONFIG_USB_SUSPEND
/* Internal routine to check whether we may autosuspend a device. */
-static int autosuspend_check(struct usb_device *udev)
+static int autosuspend_check(struct usb_device *udev, int reschedule)
{
int i;
struct usb_interface *intf;
- unsigned long suspend_time;
+ unsigned long suspend_time, j;
/* For autosuspend, fail fast if anything is in use or autosuspend
* is disabled. Also fail if any interfaces require remote wakeup
@@ -991,20 +981,20 @@ static int autosuspend_check(struct usb_device *udev)
}
/* If everything is okay but the device hasn't been idle for long
- * enough, queue a delayed autosuspend request.
+ * enough, queue a delayed autosuspend request. If the device
+ * _has_ been idle for long enough and the reschedule flag is set,
+ * likewise queue a delayed (1 second) autosuspend request.
*/
- if (time_after(suspend_time, jiffies)) {
+ j = jiffies;
+ if (time_before(j, suspend_time))
+ reschedule = 1;
+ else
+ suspend_time = j + HZ;
+ if (reschedule) {
if (!timer_pending(&udev->autosuspend.timer)) {
-
- /* The value of jiffies may change between the
- * time_after() comparison above and the subtraction
- * below. That's okay; the system behaves sanely
- * when a timer is registered for the present moment
- * or for the past.
- */
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
- round_jiffies_relative(suspend_time - jiffies));
- }
+ round_jiffies_relative(suspend_time - j));
+ }
return -EAGAIN;
}
return 0;
@@ -1012,7 +1002,7 @@ static int autosuspend_check(struct usb_device *udev)
#else
-static inline int autosuspend_check(struct usb_device *udev)
+static inline int autosuspend_check(struct usb_device *udev, int reschedule)
{
return 0;
}
@@ -1069,7 +1059,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
if (udev->auto_pm) {
- status = autosuspend_check(udev);
+ status = autosuspend_check(udev, 0);
if (status < 0)
goto done;
}
@@ -1083,15 +1073,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
break;
}
}
- if (status == 0) {
-
- /* Non-root devices don't need to do anything for FREEZE
- * or PRETHAW. */
- if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
- msg.event == PM_EVENT_PRETHAW))
- goto done;
+ if (status == 0)
status = usb_suspend_device(udev, msg);
- }
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
@@ -1102,12 +1085,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
/* Try another autosuspend when the interfaces aren't busy */
if (udev->auto_pm)
- autosuspend_check(udev);
+ autosuspend_check(udev, status == -EBUSY);
- /* If the suspend succeeded, propagate it up the tree */
+ /* If the suspend succeeded then prevent any more URB submissions,
+ * flush any outstanding URBs, and propagate the suspend up the tree.
+ */
} else {
cancel_delayed_work(&udev->autosuspend);
- if (parent)
+ udev->can_submit = 0;
+ for (i = 0; i < 16; ++i) {
+ usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
+ usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
+ }
+
+ /* If this is just a FREEZE or a PRETHAW, udev might
+ * not really be suspended. Only true suspends get
+ * propagated up the device tree.
+ */
+ if (parent && udev->state == USB_STATE_SUSPENDED)
usb_autosuspend_device(parent);
}
@@ -1156,6 +1151,7 @@ static int usb_resume_both(struct usb_device *udev)
status = -ENODEV;
goto done;
}
+ udev->can_submit = 1;
/* Propagate the resume up the tree, if necessary */
if (udev->state == USB_STATE_SUSPENDED) {
@@ -1529,9 +1525,21 @@ int usb_external_resume_device(struct usb_device *udev)
static int usb_suspend(struct device *dev, pm_message_t message)
{
+ struct usb_device *udev;
+
if (!is_usb_device(dev)) /* Ignore PM for interfaces */
return 0;
- return usb_external_suspend_device(to_usb_device(dev), message);
+ udev = to_usb_device(dev);
+
+ /* If udev is already suspended, we can skip this suspend and
+ * we should also skip the upcoming system resume. */
+ if (udev->state == USB_STATE_SUSPENDED) {
+ udev->skip_sys_resume = 1;
+ return 0;
+ }
+
+ udev->skip_sys_resume = 0;
+ return usb_external_suspend_device(udev, message);
}
static int usb_resume(struct device *dev)
@@ -1542,13 +1550,14 @@ static int usb_resume(struct device *dev)
return 0;
udev = to_usb_device(dev);
- /* If autoresume is disabled then we also want to prevent resume
- * during system wakeup. However, a "persistent-device" reset-resume
- * after power loss counts as a wakeup event. So allow a
- * reset-resume to occur if remote wakeup is enabled. */
- if (udev->autoresume_disabled) {
+ /* If udev->skip_sys_resume is set then udev was already suspended
+ * when the system suspend started, so we don't want to resume
+ * udev during this system wakeup. However a reset-resume counts
+ * as a wakeup event, so allow a reset-resume to occur if remote
+ * wakeup is enabled. */
+ if (udev->skip_sys_resume) {
if (!(udev->reset_resume && udev->do_remote_wakeup))
- return -EPERM;
+ return -EHOSTUNREACH;
}
return usb_external_resume_device(udev);
}
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index e0ec7045e86..99e5a68a3f1 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -267,7 +267,6 @@ static void ep_device_release(struct device *dev)
{
struct ep_device *ep_dev = to_ep_device(dev);
- dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
endpoint_free_minor(ep_dev);
kfree(ep_dev);
}
@@ -292,7 +291,7 @@ int usb_create_ep_files(struct device *parent,
retval = endpoint_get_minor(ep_dev);
if (retval) {
- dev_err(parent, "can not allocate minor number for %s",
+ dev_err(parent, "can not allocate minor number for %s\n",
ep_dev->dev.bus_id);
goto error_register;
}
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index b2fc2b11525..c1cb94e9f24 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc)
&& desc->bInterfaceProtocol == 1;
}
-static int choose_configuration(struct usb_device *udev)
+int usb_choose_configuration(struct usb_device *udev)
{
int i;
int num_configs;
@@ -161,17 +161,20 @@ static int generic_probe(struct usb_device *udev)
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
- c = choose_configuration(udev);
- if (c >= 0) {
- err = usb_set_configuration(udev, c);
- if (err) {
- dev_err(&udev->dev, "can't set config #%d, error %d\n",
+ if (udev->authorized == 0)
+ dev_err(&udev->dev, "Device is not authorized for usage\n");
+ else {
+ c = usb_choose_configuration(udev);
+ if (c >= 0) {
+ err = usb_set_configuration(udev, c);
+ if (err) {
+ dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
- /* This need not be fatal. The user can try to
- * set other configurations. */
+ /* This need not be fatal. The user can try to
+ * set other configurations. */
+ }
}
}
-
/* USB device state == configured ... usable */
usb_notify_add_device(udev);
@@ -203,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
*/
if (!udev->parent)
rc = hcd_bus_suspend(udev);
+
+ /* Non-root devices don't need to do anything for FREEZE or PRETHAW */
+ else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+ rc = 0;
else
rc = usb_port_suspend(udev);
+
return rc;
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 42ef1d5f6c8..fea8256a18d 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -30,7 +30,6 @@
#include <linux/utsname.h>
#include <linux/mm.h>
#include <asm/io.h>
-#include <asm/scatterlist.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/mutex.h>
@@ -356,10 +355,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
const u8 *bufp = tbuf;
int len = 0;
int patch_wakeup = 0;
- unsigned long flags;
- int status = 0;
+ int status;
int n;
+ might_sleep();
+
+ spin_lock_irq(&hcd_root_hub_lock);
+ status = usb_hcd_link_urb_to_ep(hcd, urb);
+ spin_unlock_irq(&hcd_root_hub_lock);
+ if (status)
+ return status;
+ urb->hcpriv = hcd; /* Indicate it's queued */
+
cmd = (struct usb_ctrlrequest *) urb->setup_packet;
typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
wValue = le16_to_cpu (cmd->wValue);
@@ -523,13 +530,18 @@ error:
}
/* any errors get returned through the urb completion */
- local_irq_save (flags);
- spin_lock (&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = status;
- spin_unlock (&urb->lock);
- usb_hcd_giveback_urb (hcd, urb);
- local_irq_restore (flags);
+ spin_lock_irq(&hcd_root_hub_lock);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+ /* This peculiar use of spinlocks echoes what real HC drivers do.
+ * Avoiding calls to local_irq_disable/enable makes the code
+ * RT-friendly.
+ */
+ spin_unlock(&hcd_root_hub_lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&hcd_root_hub_lock);
+
+ spin_unlock_irq(&hcd_root_hub_lock);
return 0;
}
@@ -559,31 +571,23 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
if (length > 0) {
/* try to complete the status urb */
- local_irq_save (flags);
- spin_lock(&hcd_root_hub_lock);
+ spin_lock_irqsave(&hcd_root_hub_lock, flags);
urb = hcd->status_urb;
if (urb) {
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS) {
- hcd->poll_pending = 0;
- hcd->status_urb = NULL;
- urb->status = 0;
- urb->hcpriv = NULL;
- urb->actual_length = length;
- memcpy(urb->transfer_buffer, buffer, length);
- } else /* urb has been unlinked */
- length = 0;
- spin_unlock(&urb->lock);
- } else
- length = 0;
- spin_unlock(&hcd_root_hub_lock);
+ hcd->poll_pending = 0;
+ hcd->status_urb = NULL;
+ urb->actual_length = length;
+ memcpy(urb->transfer_buffer, buffer, length);
- /* local irqs are always blocked in completions */
- if (length > 0)
- usb_hcd_giveback_urb (hcd, urb);
- else
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock(&hcd_root_hub_lock);
+ usb_hcd_giveback_urb(hcd, urb, 0);
+ spin_lock(&hcd_root_hub_lock);
+ } else {
+ length = 0;
hcd->poll_pending = 1;
- local_irq_restore (flags);
+ }
+ spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
}
/* The USB 2.0 spec says 256 ms. This is close enough and won't
@@ -611,33 +615,35 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
int len = 1 + (urb->dev->maxchild / 8);
spin_lock_irqsave (&hcd_root_hub_lock, flags);
- if (urb->status != -EINPROGRESS) /* already unlinked */
- retval = urb->status;
- else if (hcd->status_urb || urb->transfer_buffer_length < len) {
+ if (hcd->status_urb || urb->transfer_buffer_length < len) {
dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
retval = -EINVAL;
- } else {
- hcd->status_urb = urb;
- urb->hcpriv = hcd; /* indicate it's queued */
+ goto done;
+ }
- if (!hcd->uses_new_polling)
- mod_timer (&hcd->rh_timer,
- (jiffies/(HZ/4) + 1) * (HZ/4));
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval)
+ goto done;
- /* If a status change has already occurred, report it ASAP */
- else if (hcd->poll_pending)
- mod_timer (&hcd->rh_timer, jiffies);
- retval = 0;
- }
+ hcd->status_urb = urb;
+ urb->hcpriv = hcd; /* indicate it's queued */
+ if (!hcd->uses_new_polling)
+ mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
+
+ /* If a status change has already occurred, report it ASAP */
+ else if (hcd->poll_pending)
+ mod_timer(&hcd->rh_timer, jiffies);
+ retval = 0;
+ done:
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
return retval;
}
static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
{
- if (usb_pipeint (urb->pipe))
+ if (usb_endpoint_xfer_int(&urb->ep->desc))
return rh_queue_status (hcd, urb);
- if (usb_pipecontrol (urb->pipe))
+ if (usb_endpoint_xfer_control(&urb->ep->desc))
return rh_call_control (hcd, urb);
return -EINVAL;
}
@@ -647,32 +653,96 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
/* Unlinks of root-hub control URBs are legal, but they don't do anything
* since these URBs always execute synchronously.
*/
-static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&hcd_root_hub_lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
- if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
+ if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */
; /* Do nothing */
} else { /* Status URB */
if (!hcd->uses_new_polling)
del_timer (&hcd->rh_timer);
- local_irq_save (flags);
- spin_lock (&hcd_root_hub_lock);
if (urb == hcd->status_urb) {
hcd->status_urb = NULL;
- urb->hcpriv = NULL;
- } else
- urb = NULL; /* wasn't fully queued */
- spin_unlock (&hcd_root_hub_lock);
- if (urb)
- usb_hcd_giveback_urb (hcd, urb);
- local_irq_restore (flags);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+ spin_unlock(&hcd_root_hub_lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&hcd_root_hub_lock);
+ }
}
+ done:
+ spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
+ return rc;
+}
- return 0;
+
+
+/*
+ * Show & store the current value of authorized_default
+ */
+static ssize_t usb_host_authorized_default_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *rh_usb_dev = to_usb_device(dev);
+ struct usb_bus *usb_bus = rh_usb_dev->bus;
+ struct usb_hcd *usb_hcd;
+
+ if (usb_bus == NULL) /* FIXME: not sure if this case is possible */
+ return -ENODEV;
+ usb_hcd = bus_to_hcd(usb_bus);
+ return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
+}
+
+static ssize_t usb_host_authorized_default_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ unsigned val;
+ struct usb_device *rh_usb_dev = to_usb_device(dev);
+ struct usb_bus *usb_bus = rh_usb_dev->bus;
+ struct usb_hcd *usb_hcd;
+
+ if (usb_bus == NULL) /* FIXME: not sure if this case is possible */
+ return -ENODEV;
+ usb_hcd = bus_to_hcd(usb_bus);
+ result = sscanf(buf, "%u\n", &val);
+ if (result == 1) {
+ usb_hcd->authorized_default = val? 1 : 0;
+ result = size;
+ }
+ else
+ result = -EINVAL;
+ return result;
}
+static DEVICE_ATTR(authorized_default, 0644,
+ usb_host_authorized_default_show,
+ usb_host_authorized_default_store);
+
+
+/* Group all the USB bus attributes */
+static struct attribute *usb_bus_attrs[] = {
+ &dev_attr_authorized_default.attr,
+ NULL,
+};
+
+static struct attribute_group usb_bus_attr_group = {
+ .name = NULL, /* we want them in the same directory */
+ .attrs = usb_bus_attrs,
+};
+
+
+
/*-------------------------------------------------------------------------*/
static struct class *usb_host_class;
@@ -726,27 +796,23 @@ static void usb_bus_init (struct usb_bus *bus)
*/
static int usb_register_bus(struct usb_bus *bus)
{
+ int result = -E2BIG;
int busnum;
mutex_lock(&usb_bus_list_lock);
busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
- if (busnum < USB_MAXBUS) {
- set_bit (busnum, busmap.busmap);
- bus->busnum = busnum;
- } else {
+ if (busnum >= USB_MAXBUS) {
printk (KERN_ERR "%s: too many buses\n", usbcore_name);
- mutex_unlock(&usb_bus_list_lock);
- return -E2BIG;
+ goto error_find_busnum;
}
-
+ set_bit (busnum, busmap.busmap);
+ bus->busnum = busnum;
bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
- bus->controller, "usb_host%d", busnum);
- if (IS_ERR(bus->class_dev)) {
- clear_bit(busnum, busmap.busmap);
- mutex_unlock(&usb_bus_list_lock);
- return PTR_ERR(bus->class_dev);
- }
-
+ bus->controller, "usb_host%d",
+ busnum);
+ result = PTR_ERR(bus->class_dev);
+ if (IS_ERR(bus->class_dev))
+ goto error_create_class_dev;
class_set_devdata(bus->class_dev, bus);
/* Add it to the local list of buses */
@@ -755,8 +821,15 @@ static int usb_register_bus(struct usb_bus *bus)
usb_notify_add_bus(bus);
- dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
+ dev_info (bus->controller, "new USB bus registered, assigned bus "
+ "number %d\n", bus->busnum);
return 0;
+
+error_create_class_dev:
+ clear_bit(busnum, busmap.busmap);
+error_find_busnum:
+ mutex_unlock(&usb_bus_list_lock);
+ return result;
}
/**
@@ -908,103 +981,145 @@ EXPORT_SYMBOL (usb_calc_bus_time);
/*-------------------------------------------------------------------------*/
-static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
+/**
+ * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being submitted
+ *
+ * Host controller drivers should call this routine in their enqueue()
+ * method. The HCD's private spinlock must be held and interrupts must
+ * be disabled. The actions carried out here are required for URB
+ * submission, as well as for endpoint shutdown and for usb_kill_urb.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the enqueue() method must fail). If no error occurs but enqueue() fails
+ * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
+ * the private spinlock and returning.
+ */
+int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
{
- unsigned long flags;
+ int rc = 0;
- /* clear all state linking urb to this dev (and hcd) */
- spin_lock_irqsave(&hcd_urb_list_lock, flags);
- list_del_init (&urb->urb_list);
- spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
+ spin_lock(&hcd_urb_list_lock);
- if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
- if (usb_pipecontrol (urb->pipe)
- && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
- dma_unmap_single (hcd->self.controller, urb->setup_dma,
- sizeof (struct usb_ctrlrequest),
- DMA_TO_DEVICE);
- if (urb->transfer_buffer_length != 0
- && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
- dma_unmap_single (hcd->self.controller,
- urb->transfer_dma,
- urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
- ? DMA_FROM_DEVICE
- : DMA_TO_DEVICE);
+ /* Check that the URB isn't being killed */
+ if (unlikely(urb->reject)) {
+ rc = -EPERM;
+ goto done;
}
-}
-
-/* may be called in any context with a valid urb->dev usecount
- * caller surrenders "ownership" of urb
- * expects usb_submit_urb() to have sanity checked and conditioned all
- * inputs in the urb
- */
-int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
-{
- int status;
- struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
- struct usb_host_endpoint *ep;
- unsigned long flags;
- if (!hcd)
- return -ENODEV;
+ if (unlikely(!urb->ep->enabled)) {
+ rc = -ENOENT;
+ goto done;
+ }
- usbmon_urb_submit(&hcd->self, urb);
+ if (unlikely(!urb->dev->can_submit)) {
+ rc = -EHOSTUNREACH;
+ goto done;
+ }
/*
- * Atomically queue the urb, first to our records, then to the HCD.
- * Access to urb->status is controlled by urb->lock ... changes on
- * i/o completion (normal or fault) or unlinking.
+ * Check the host controller's state and add the URB to the
+ * endpoint's queue.
*/
-
- // FIXME: verify that quiescing hc works right (RH cleans up)
-
- spin_lock_irqsave(&hcd_urb_list_lock, flags);
- ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
- [usb_pipeendpoint(urb->pipe)];
- if (unlikely (!ep))
- status = -ENOENT;
- else if (unlikely (urb->reject))
- status = -EPERM;
- else switch (hcd->state) {
+ switch (hcd->state) {
case HC_STATE_RUNNING:
case HC_STATE_RESUMING:
- list_add_tail (&urb->urb_list, &ep->urb_list);
- status = 0;
+ urb->unlinked = 0;
+ list_add_tail(&urb->urb_list, &urb->ep->urb_list);
break;
default:
- status = -ESHUTDOWN;
- break;
+ rc = -ESHUTDOWN;
+ goto done;
}
- spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
- if (status) {
- INIT_LIST_HEAD (&urb->urb_list);
- usbmon_urb_submit_error(&hcd->self, urb, status);
- return status;
+ done:
+ spin_unlock(&hcd_urb_list_lock);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
+
+/**
+ * usb_hcd_check_unlink_urb - check whether an URB may be unlinked
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being checked for unlinkability
+ * @status: error code to store in @urb if the unlink succeeds
+ *
+ * Host controller drivers should call this routine in their dequeue()
+ * method. The HCD's private spinlock must be held and interrupts must
+ * be disabled. The actions carried out here are required for making
+ * sure than an unlink is valid.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the dequeue() method must fail). The possible error codes are:
+ *
+ * -EIDRM: @urb was not submitted or has already completed.
+ * The completion function may not have been called yet.
+ *
+ * -EBUSY: @urb has already been unlinked.
+ */
+int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+ int status)
+{
+ struct list_head *tmp;
+
+ /* insist the urb is still queued */
+ list_for_each(tmp, &urb->ep->urb_list) {
+ if (tmp == &urb->urb_list)
+ break;
}
+ if (tmp != &urb->urb_list)
+ return -EIDRM;
- /* increment urb's reference count as part of giving it to the HCD
- * (which now controls it). HCD guarantees that it either returns
- * an error or calls giveback(), but not both.
+ /* Any status except -EINPROGRESS means something already started to
+ * unlink this URB from the hardware. So there's no more work to do.
*/
- urb = usb_get_urb (urb);
- atomic_inc (&urb->use_count);
-
- if (is_root_hub(urb->dev)) {
- /* NOTE: requirement on hub callers (usbfs and the hub
- * driver, for now) that URBs' urb->transfer_buffer be
- * valid and usb_buffer_{sync,unmap}() not be needed, since
- * they could clobber root hub response data.
- */
- status = rh_urb_enqueue (hcd, urb);
- goto done;
+ if (urb->unlinked)
+ return -EBUSY;
+ urb->unlinked = status;
+
+ /* IRQ setup can easily be broken so that USB controllers
+ * never get completion IRQs ... maybe even the ones we need to
+ * finish unlinking the initial failed usb_set_address()
+ * or device descriptor fetch.
+ */
+ if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+ !is_root_hub(urb->dev)) {
+ dev_warn(hcd->self.controller, "Unlink after no-IRQ? "
+ "Controller is probably using the wrong IRQ.\n");
+ set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
}
- /* lower level hcd code should use *_dma exclusively,
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
+
+/**
+ * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being unlinked
+ *
+ * Host controller drivers should call this routine before calling
+ * usb_hcd_giveback_urb(). The HCD's private spinlock must be held and
+ * interrupts must be disabled. The actions carried out here are required
+ * for URB completion.
+ */
+void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
+{
+ /* clear all state linking urb to this dev (and hcd) */
+ spin_lock(&hcd_urb_list_lock);
+ list_del_init(&urb->urb_list);
+ spin_unlock(&hcd_urb_list_lock);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
+
+static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ /* Map the URB's buffers for DMA access.
+ * Lower level HCD code should use *_dma exclusively,
* unless it uses pio or talks to another transport.
*/
- if (hcd->self.uses_dma) {
- if (usb_pipecontrol (urb->pipe)
+ if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+ if (usb_endpoint_xfer_control(&urb->ep->desc)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
urb->setup_dma = dma_map_single (
hcd->self.controller,
@@ -1017,20 +1132,75 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
hcd->self.controller,
urb->transfer_buffer,
urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
+ usb_urb_dir_in(urb)
? DMA_FROM_DEVICE
: DMA_TO_DEVICE);
}
+}
- status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
-done:
- if (unlikely (status)) {
- urb_unlink(hcd, urb);
- atomic_dec (&urb->use_count);
- if (urb->reject)
- wake_up (&usb_kill_urb_queue);
+static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+ if (usb_endpoint_xfer_control(&urb->ep->desc)
+ && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+ dma_unmap_single(hcd->self.controller, urb->setup_dma,
+ sizeof(struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ if (urb->transfer_buffer_length != 0
+ && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+ dma_unmap_single(hcd->self.controller,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ usb_urb_dir_in(urb)
+ ? DMA_FROM_DEVICE
+ : DMA_TO_DEVICE);
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called in any context with a valid urb->dev usecount
+ * caller surrenders "ownership" of urb
+ * expects usb_submit_urb() to have sanity checked and conditioned all
+ * inputs in the urb
+ */
+int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+{
+ int status;
+ struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
+
+ /* increment urb's reference count as part of giving it to the HCD
+ * (which will control it). HCD guarantees that it either returns
+ * an error or calls giveback(), but not both.
+ */
+ usb_get_urb(urb);
+ atomic_inc(&urb->use_count);
+ atomic_inc(&urb->dev->urbnum);
+ usbmon_urb_submit(&hcd->self, urb);
+
+ /* NOTE requirements on root-hub callers (usbfs and the hub
+ * driver, for now): URBs' urb->transfer_buffer must be
+ * valid and usb_buffer_{sync,unmap}() not be needed, since
+ * they could clobber root hub response data. Also, control
+ * URBs must be submitted in process context with interrupts
+ * enabled.
+ */
+ map_urb_for_dma(hcd, urb);
+ if (is_root_hub(urb->dev))
+ status = rh_urb_enqueue(hcd, urb);
+ else
+ status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
+
+ if (unlikely(status)) {
usbmon_urb_submit_error(&hcd->self, urb, status);
- usb_put_urb (urb);
+ unmap_urb_for_dma(hcd, urb);
+ urb->hcpriv = NULL;
+ INIT_LIST_HEAD(&urb->urb_list);
+ atomic_dec(&urb->use_count);
+ atomic_dec(&urb->dev->urbnum);
+ if (urb->reject)
+ wake_up(&usb_kill_urb_queue);
+ usb_put_urb(urb);
}
return status;
}
@@ -1042,24 +1212,19 @@ done:
* soon as practical. we've already set up the urb's return status,
* but we can't know if the callback completed already.
*/
-static int
-unlink1 (struct usb_hcd *hcd, struct urb *urb)
+static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
{
int value;
if (is_root_hub(urb->dev))
- value = usb_rh_urb_dequeue (hcd, urb);
+ value = usb_rh_urb_dequeue(hcd, urb, status);
else {
/* The only reason an HCD might fail this call is if
* it has not yet fully queued the urb to begin with.
* Such failures should be harmless. */
- value = hcd->driver->urb_dequeue (hcd, urb);
+ value = hcd->driver->urb_dequeue(hcd, urb, status);
}
-
- if (value != 0)
- dev_dbg (hcd->self.controller, "dequeue %p --> %d\n",
- urb, value);
return value;
}
@@ -1071,88 +1236,17 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
*/
int usb_hcd_unlink_urb (struct urb *urb, int status)
{
- struct usb_host_endpoint *ep;
- struct usb_hcd *hcd = NULL;
- struct device *sys = NULL;
- unsigned long flags;
- struct list_head *tmp;
- int retval;
-
- if (!urb)
- return -EINVAL;
- if (!urb->dev || !urb->dev->bus)
- return -ENODEV;
- ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
- [usb_pipeendpoint(urb->pipe)];
- if (!ep)
- return -ENODEV;
-
- /*
- * we contend for urb->status with the hcd core,
- * which changes it while returning the urb.
- *
- * Caller guaranteed that the urb pointer hasn't been freed, and
- * that it was submitted. But as a rule it can't know whether or
- * not it's already been unlinked ... so we respect the reversed
- * lock sequence needed for the usb_hcd_giveback_urb() code paths
- * (urb lock, then hcd_urb_list_lock) in case some other CPU is now
- * unlinking it.
- */
- spin_lock_irqsave (&urb->lock, flags);
- spin_lock(&hcd_urb_list_lock);
+ struct usb_hcd *hcd;
+ int retval;
- sys = &urb->dev->dev;
hcd = bus_to_hcd(urb->dev->bus);
- if (hcd == NULL) {
- retval = -ENODEV;
- goto done;
- }
+ retval = unlink1(hcd, urb, status);
- /* insist the urb is still queued */
- list_for_each(tmp, &ep->urb_list) {
- if (tmp == &urb->urb_list)
- break;
- }
- if (tmp != &urb->urb_list) {
- retval = -EIDRM;
- goto done;
- }
-
- /* Any status except -EINPROGRESS means something already started to
- * unlink this URB from the hardware. So there's no more work to do.
- */
- if (urb->status != -EINPROGRESS) {
- retval = -EBUSY;
- goto done;
- }
-
- /* IRQ setup can easily be broken so that USB controllers
- * never get completion IRQs ... maybe even the ones we need to
- * finish unlinking the initial failed usb_set_address()
- * or device descriptor fetch.
- */
- if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
- !is_root_hub(urb->dev)) {
- dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
- "Controller is probably using the wrong IRQ.\n");
- set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
- }
-
- urb->status = status;
-
- spin_unlock(&hcd_urb_list_lock);
- spin_unlock_irqrestore (&urb->lock, flags);
-
- retval = unlink1 (hcd, urb);
if (retval == 0)
retval = -EINPROGRESS;
- return retval;
-
-done:
- spin_unlock(&hcd_urb_list_lock);
- spin_unlock_irqrestore (&urb->lock, flags);
- if (retval != -EIDRM && sys && sys->driver)
- dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
+ else if (retval != -EIDRM && retval != -EBUSY)
+ dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
+ urb, retval);
return retval;
}
@@ -1162,6 +1256,7 @@ done:
* usb_hcd_giveback_urb - return URB from HCD to device driver
* @hcd: host controller returning the URB
* @urb: urb being returned to the USB device driver.
+ * @status: completion status code for the URB.
* Context: in_interrupt()
*
* This hands the URB from HCD to its USB device driver, using its
@@ -1169,14 +1264,27 @@ done:
* (and is done using urb->hcpriv). It also released all HCD locks;
* the device driver won't cause problems if it frees, modifies,
* or resubmits this URB.
+ *
+ * If @urb was unlinked, the value of @status will be overridden by
+ * @urb->unlinked. Erroneous short transfers are detected in case
+ * the HCD hasn't checked for them.
*/
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
{
- urb_unlink(hcd, urb);
- usbmon_urb_complete (&hcd->self, urb);
+ urb->hcpriv = NULL;
+ if (unlikely(urb->unlinked))
+ status = urb->unlinked;
+ else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+ urb->actual_length < urb->transfer_buffer_length &&
+ !status))
+ status = -EREMOTEIO;
+
+ unmap_urb_for_dma(hcd, urb);
+ usbmon_urb_complete(&hcd->self, urb, status);
usb_unanchor_urb(urb);
/* pass ownership to the completion handler */
+ urb->status = status;
urb->complete (urb);
atomic_dec (&urb->use_count);
if (unlikely (urb->reject))
@@ -1187,78 +1295,61 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb);
/*-------------------------------------------------------------------------*/
-/* disables the endpoint: cancels any pending urbs, then synchronizes with
- * the hcd to make sure all endpoint state is gone from hardware, and then
- * waits until the endpoint's queue is completely drained. use for
- * set_configuration, set_interface, driver removal, physical disconnect.
- *
- * example: a qh stored in ep->hcpriv, holding state related to endpoint
- * type, maxpacket size, toggle, halt status, and scheduling.
+/* Cancel all URBs pending on this endpoint and wait for the endpoint's
+ * queue to drain completely. The caller must first insure that no more
+ * URBs can be submitted for this endpoint.
*/
-void usb_hcd_endpoint_disable (struct usb_device *udev,
+void usb_hcd_flush_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
struct usb_hcd *hcd;
struct urb *urb;
+ if (!ep)
+ return;
+ might_sleep();
hcd = bus_to_hcd(udev->bus);
- local_irq_disable ();
- /* ep is already gone from udev->ep_{in,out}[]; no more submits */
+ /* No more submits can occur */
rescan:
- spin_lock(&hcd_urb_list_lock);
+ spin_lock_irq(&hcd_urb_list_lock);
list_for_each_entry (urb, &ep->urb_list, urb_list) {
- int tmp;
+ int is_in;
- /* the urb may already have been unlinked */
- if (urb->status != -EINPROGRESS)
+ if (urb->unlinked)
continue;
usb_get_urb (urb);
+ is_in = usb_urb_dir_in(urb);
spin_unlock(&hcd_urb_list_lock);
- spin_lock (&urb->lock);
- tmp = urb->status;
- if (tmp == -EINPROGRESS)
- urb->status = -ESHUTDOWN;
- spin_unlock (&urb->lock);
-
- /* kick hcd unless it's already returning this */
- if (tmp == -EINPROGRESS) {
- tmp = urb->pipe;
- unlink1 (hcd, urb);
- dev_dbg (hcd->self.controller,
- "shutdown urb %p pipe %08x ep%d%s%s\n",
- urb, tmp, usb_pipeendpoint (tmp),
- (tmp & USB_DIR_IN) ? "in" : "out",
- ({ char *s; \
- switch (usb_pipetype (tmp)) { \
- case PIPE_CONTROL: s = ""; break; \
- case PIPE_BULK: s = "-bulk"; break; \
- case PIPE_INTERRUPT: s = "-intr"; break; \
- default: s = "-iso"; break; \
- }; s;}));
- }
+ /* kick hcd */
+ unlink1(hcd, urb, -ESHUTDOWN);
+ dev_dbg (hcd->self.controller,
+ "shutdown urb %p ep%d%s%s\n",
+ urb, usb_endpoint_num(&ep->desc),
+ is_in ? "in" : "out",
+ ({ char *s;
+
+ switch (usb_endpoint_type(&ep->desc)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ s = ""; break;
+ case USB_ENDPOINT_XFER_BULK:
+ s = "-bulk"; break;
+ case USB_ENDPOINT_XFER_INT:
+ s = "-intr"; break;
+ default:
+ s = "-iso"; break;
+ };
+ s;
+ }));
usb_put_urb (urb);
/* list contents may have changed */
goto rescan;
}
- spin_unlock(&hcd_urb_list_lock);
- local_irq_enable ();
-
- /* synchronize with the hardware, so old configuration state
- * clears out immediately (and will be freed).
- */
- might_sleep ();
- if (hcd->driver->endpoint_disable)
- hcd->driver->endpoint_disable (hcd, ep);
+ spin_unlock_irq(&hcd_urb_list_lock);
- /* Wait until the endpoint queue is completely empty. Most HCDs
- * will have done this already in their endpoint_disable method,
- * but some might not. And there could be root-hub control URBs
- * still pending since they aren't affected by the HCDs'
- * endpoint_disable methods.
- */
+ /* Wait until the endpoint queue is completely empty */
while (!list_empty (&ep->urb_list)) {
spin_lock_irq(&hcd_urb_list_lock);
@@ -1278,6 +1369,25 @@ rescan:
}
}
+/* Disables the endpoint: synchronizes with the hcd to make sure all
+ * endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
+ * have been called previously. Use for set_configuration, set_interface,
+ * driver removal, physical disconnect.
+ *
+ * example: a qh stored in ep->hcpriv, holding state related to endpoint
+ * type, maxpacket size, toggle, halt status, and scheduling.
+ */
+void usb_hcd_disable_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep)
+{
+ struct usb_hcd *hcd;
+
+ might_sleep();
+ hcd = bus_to_hcd(udev->bus);
+ if (hcd->driver->endpoint_disable)
+ hcd->driver->endpoint_disable(hcd, ep);
+}
+
/*-------------------------------------------------------------------------*/
/* called in any context */
@@ -1525,7 +1635,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
hcd->driver = driver;
hcd->product_desc = (driver->product_desc) ? driver->product_desc :
"USB Host Controller";
-
return hcd;
}
EXPORT_SYMBOL (usb_create_hcd);
@@ -1570,6 +1679,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
+ hcd->authorized_default = hcd->wireless? 0 : 1;
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
/* HC is in reset state, but accessible. Now do the one-time init,
@@ -1646,10 +1756,20 @@ int usb_add_hcd(struct usb_hcd *hcd,
if ((retval = register_root_hub(hcd)) != 0)
goto err_register_root_hub;
+ retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
+ if (retval < 0) {
+ printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
+ retval);
+ goto error_create_attr_group;
+ }
if (hcd->uses_new_polling && hcd->poll_rh)
usb_hcd_poll_rh_status(hcd);
return retval;
+error_create_attr_group:
+ mutex_lock(&usb_bus_list_lock);
+ usb_disconnect(&hcd->self.root_hub);
+ mutex_unlock(&usb_bus_list_lock);
err_register_root_hub:
hcd->driver->stop(hcd);
err_hcd_driver_start:
@@ -1691,6 +1811,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
cancel_work_sync(&hcd->wakeup_work);
#endif
+ sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
mutex_lock(&usb_bus_list_lock);
usb_disconnect(&hcd->self.root_hub);
mutex_unlock(&usb_bus_list_lock);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index b5ebb73c233..98e24194a4a 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -19,6 +19,8 @@
#ifdef __KERNEL__
+#include <linux/rwsem.h>
+
/* This file contains declarations of usbcore internals that are mostly
* used or exposed by Host Controller Drivers.
*/
@@ -51,6 +53,12 @@
*
* Since "struct usb_bus" is so thin, you can't share much code in it.
* This framework is a layer over that, and should be more sharable.
+ *
+ * @authorized_default: Specifies if new devices are authorized to
+ * connect by default or they require explicit
+ * user space authorization; this bit is settable
+ * through /sys/class/usb_host/X/authorized_default.
+ * For the rest is RO, so we don't lock to r/w it.
*/
/*-------------------------------------------------------------------------*/
@@ -90,6 +98,7 @@ struct usb_hcd {
unsigned poll_rh:1; /* poll for rh status? */
unsigned poll_pending:1; /* status has changed? */
unsigned wireless:1; /* Wireless USB HCD */
+ unsigned authorized_default:1;
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
@@ -182,11 +191,10 @@ struct hc_driver {
int (*get_frame_number) (struct usb_hcd *hcd);
/* manage i/o requests, device state */
- int (*urb_enqueue) (struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
- struct urb *urb,
- gfp_t mem_flags);
- int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
+ int (*urb_enqueue)(struct usb_hcd *hcd,
+ struct urb *urb, gfp_t mem_flags);
+ int (*urb_dequeue)(struct usb_hcd *hcd,
+ struct urb *urb, int status);
/* hw synch, freeing endpoint resources that urb_dequeue can't */
void (*endpoint_disable)(struct usb_hcd *hcd,
@@ -204,10 +212,18 @@ struct hc_driver {
/* Needed only if port-change IRQs are level-triggered */
};
+extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
+extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+ int status);
+extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
+
extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
extern int usb_hcd_unlink_urb (struct urb *urb, int status);
-extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
-extern void usb_hcd_endpoint_disable (struct usb_device *udev,
+extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
+ int status);
+extern void usb_hcd_flush_endpoint(struct usb_device *udev,
+ struct usb_host_endpoint *ep);
+extern void usb_hcd_disable_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
extern int usb_hcd_get_frame_number (struct usb_device *udev);
@@ -402,7 +418,7 @@ static inline void usbfs_cleanup(void) { }
struct usb_mon_operations {
void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
- void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
+ void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status);
/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
};
@@ -421,10 +437,11 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
(*mon_ops->urb_submit_error)(bus, urb, error);
}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+ int status)
{
if (bus->monitored)
- (*mon_ops->urb_complete)(bus, urb);
+ (*mon_ops->urb_complete)(bus, urb, status);
}
int usb_mon_register(struct usb_mon_operations *ops);
@@ -435,7 +452,8 @@ void usb_mon_deregister(void);
static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
int error) {}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+ int status) {}
#endif /* CONFIG_USB_MON */
@@ -454,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
: (in_interrupt () ? "in_interrupt" : "can sleep"))
-#endif /* __KERNEL__ */
+/* This rwsem is for use only by the hub driver and ehci-hcd.
+ * Nobody else should touch it.
+ */
+extern struct rw_semaphore ehci_cf_port_reset_rwsem;
+#endif /* __KERNEL__ */
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index f7b337feb3e..036c3dea855 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes,
"try the other device initialization scheme if the "
"first one fails");
+/* Mutual exclusion for EHCI CF initialization. This interferes with
+ * port reset on some companion controllers.
+ */
+DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
+EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
+
static inline char *portspeed(int portstatus)
{
@@ -347,11 +353,11 @@ void usb_kick_khubd(struct usb_device *hdev)
static void hub_irq(struct urb *urb)
{
struct usb_hub *hub = urb->context;
- int status;
+ int status = urb->status;
int i;
unsigned long bits;
- switch (urb->status) {
+ switch (status) {
case -ENOENT: /* synchronous unlink */
case -ECONNRESET: /* async unlink */
case -ESHUTDOWN: /* hardware going away */
@@ -359,10 +365,10 @@ static void hub_irq(struct urb *urb)
default: /* presumably an error */
/* Cause a hub reset after 10 consecutive errors */
- dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status);
+ dev_dbg (hub->intfdev, "transfer --> %d\n", status);
if ((++hub->nerrors < 10) || hub->error)
goto resubmit;
- hub->error = urb->status;
+ hub->error = status;
/* FALL THROUGH */
/* let khubd handle things */
@@ -1220,54 +1226,14 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
#endif
/**
- * usb_new_device - perform initial device setup (usbcore-internal)
+ * usb_configure_device_otg - FIXME (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
- * This is called with devices which have been enumerated, but not yet
- * configured. The device descriptor is available, but not descriptors
- * for any device configuration. The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * It will return if the device is configured properly or not. Zero if
- * the interface was registered with the driver core; else a negative
- * errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
+ * Do configuration for On-The-Go devices
*/
-int usb_new_device(struct usb_device *udev)
+static int usb_configure_device_otg(struct usb_device *udev)
{
- int err;
-
- /* Determine quirks */
- usb_detect_quirks(udev);
-
- err = usb_get_configuration(udev);
- if (err < 0) {
- dev_err(&udev->dev, "can't read configurations, error %d\n",
- err);
- goto fail;
- }
-
- /* read the standard strings and cache them if present */
- udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
- udev->manufacturer = usb_cache_string(udev,
- udev->descriptor.iManufacturer);
- udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
-
- /* Tell the world! */
- dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
- "SerialNumber=%d\n",
- udev->descriptor.iManufacturer,
- udev->descriptor.iProduct,
- udev->descriptor.iSerialNumber);
- show_string(udev, "Product", udev->product);
- show_string(udev, "Manufacturer", udev->manufacturer);
- show_string(udev, "SerialNumber", udev->serial);
+ int err = 0;
#ifdef CONFIG_USB_OTG
/*
@@ -1329,8 +1295,82 @@ int usb_new_device(struct usb_device *udev)
err = -ENOTSUPP;
goto fail;
}
+fail:
#endif
+ return err;
+}
+
+
+/**
+ * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is only called by usb_new_device() and usb_authorize_device()
+ * and FIXME -- all comments that apply to them apply here wrt to
+ * environment.
+ *
+ * If the device is WUSB and not authorized, we don't attempt to read
+ * the string descriptors, as they will be errored out by the device
+ * until it has been authorized.
+ */
+static int usb_configure_device(struct usb_device *udev)
+{
+ int err;
+
+ if (udev->config == NULL) {
+ err = usb_get_configuration(udev);
+ if (err < 0) {
+ dev_err(&udev->dev, "can't read configurations, error %d\n",
+ err);
+ goto fail;
+ }
+ }
+ if (udev->wusb == 1 && udev->authorized == 0) {
+ udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ }
+ else {
+ /* read the standard strings and cache them if present */
+ udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+ udev->manufacturer = usb_cache_string(udev,
+ udev->descriptor.iManufacturer);
+ udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
+ }
+ err = usb_configure_device_otg(udev);
+fail:
+ return err;
+}
+
+
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured. The device descriptor is available, but not descriptors
+ * for any device configuration. The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub). The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not. Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
+{
+ int err;
+ usb_detect_quirks(udev); /* Determine quirks */
+ err = usb_configure_device(udev); /* detect & probe dev/intfs */
+ if (err < 0)
+ goto fail;
/* export the usbdev device-node for libusb */
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
@@ -1346,19 +1386,110 @@ int usb_new_device(struct usb_device *udev)
err = device_add(&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
- if (udev->parent)
- usb_autosuspend_device(udev->parent);
goto fail;
}
-exit:
+ /* Tell the world! */
+ dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
+ "SerialNumber=%d\n",
+ udev->descriptor.iManufacturer,
+ udev->descriptor.iProduct,
+ udev->descriptor.iSerialNumber);
+ show_string(udev, "Product", udev->product);
+ show_string(udev, "Manufacturer", udev->manufacturer);
+ show_string(udev, "SerialNumber", udev->serial);
return err;
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
- goto exit;
+ return err;
}
+
+/**
+ * usb_deauthorize_device - deauthorize a device (usbcore-internal)
+ * @usb_dev: USB device
+ *
+ * Move the USB device to a very basic state where interfaces are disabled
+ * and the device is in fact unconfigured and unusable.
+ *
+ * We share a lock (that we have) with device_del(), so we need to
+ * defer its call.
+ */
+int usb_deauthorize_device(struct usb_device *usb_dev)
+{
+ unsigned cnt;
+ usb_lock_device(usb_dev);
+ if (usb_dev->authorized == 0)
+ goto out_unauthorized;
+ usb_dev->authorized = 0;
+ usb_set_configuration(usb_dev, -1);
+ usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+ kfree(usb_dev->config);
+ usb_dev->config = NULL;
+ for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
+ kfree(usb_dev->rawdescriptors[cnt]);
+ usb_dev->descriptor.bNumConfigurations = 0;
+ kfree(usb_dev->rawdescriptors);
+out_unauthorized:
+ usb_unlock_device(usb_dev);
+ return 0;
+}
+
+
+int usb_authorize_device(struct usb_device *usb_dev)
+{
+ int result = 0, c;
+ usb_lock_device(usb_dev);
+ if (usb_dev->authorized == 1)
+ goto out_authorized;
+ kfree(usb_dev->product);
+ usb_dev->product = NULL;
+ kfree(usb_dev->manufacturer);
+ usb_dev->manufacturer = NULL;
+ kfree(usb_dev->serial);
+ usb_dev->serial = NULL;
+ result = usb_autoresume_device(usb_dev);
+ if (result < 0) {
+ dev_err(&usb_dev->dev,
+ "can't autoresume for authorization: %d\n", result);
+ goto error_autoresume;
+ }
+ result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
+ if (result < 0) {
+ dev_err(&usb_dev->dev, "can't re-read device descriptor for "
+ "authorization: %d\n", result);
+ goto error_device_descriptor;
+ }
+ usb_dev->authorized = 1;
+ result = usb_configure_device(usb_dev);
+ if (result < 0)
+ goto error_configure;
+ /* Choose and set the configuration. This registers the interfaces
+ * with the driver core and lets interface drivers bind to them.
+ */
+ c = usb_choose_configuration(usb_dev);
+ if (c >= 0) {
+ result = usb_set_configuration(usb_dev, c);
+ if (result) {
+ dev_err(&usb_dev->dev,
+ "can't set config #%d, error %d\n", c, result);
+ /* This need not be fatal. The user can try to
+ * set other configurations. */
+ }
+ }
+ dev_info(&usb_dev->dev, "authorized to connect\n");
+error_configure:
+error_device_descriptor:
+error_autoresume:
+out_authorized:
+ usb_unlock_device(usb_dev); // complements locktree
+ return result;
+}
+
+
static int hub_port_status(struct usb_hub *hub, int port1,
u16 *status, u16 *change)
{
@@ -1460,6 +1591,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
{
int i, status;
+ /* Block EHCI CF initialization during the port reset.
+ * Some companion controllers don't like it when they mix.
+ */
+ down_read(&ehci_cf_port_reset_rwsem);
+
/* Reset the port */
for (i = 0; i < PORT_RESET_TRIES; i++) {
status = set_port_feature(hub->hdev,
@@ -1481,6 +1617,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
case 0:
/* TRSTRCY = 10 ms; plus some extra */
msleep(10 + 40);
+ udev->devnum = 0; /* Device now at address 0 */
/* FALL THROUGH */
case -ENOTCONN:
case -ENODEV:
@@ -1490,7 +1627,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
usb_set_device_state(udev, status
? USB_STATE_NOTATTACHED
: USB_STATE_DEFAULT);
- return status;
+ goto done;
}
dev_dbg (hub->intfdev,
@@ -1503,6 +1640,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
"Cannot enable port %i. Maybe the USB cable is bad?\n",
port1);
+ done:
+ up_read(&ehci_cf_port_reset_rwsem);
return status;
}
@@ -1833,14 +1972,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_device *udev;
udev = hdev->children [port1-1];
- if (udev && msg.event == PM_EVENT_SUSPEND &&
-#ifdef CONFIG_USB_SUSPEND
- udev->state != USB_STATE_SUSPENDED
-#else
- udev->dev.power.power_state.event
- == PM_EVENT_ON
-#endif
- ) {
+ if (udev && udev->can_submit) {
if (!hdev->auto_pm)
dev_dbg(&intf->dev, "port %d nyet suspended\n",
port1);
@@ -1999,26 +2131,27 @@ static void ep0_reinit(struct usb_device *udev)
{
usb_disable_endpoint(udev, 0 + USB_DIR_IN);
usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
- udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;
+ usb_enable_endpoint(udev, &udev->ep0);
}
#define usb_sndaddr0pipe() (PIPE_CONTROL << 30)
#define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN)
-static int hub_set_address(struct usb_device *udev)
+static int hub_set_address(struct usb_device *udev, int devnum)
{
int retval;
- if (udev->devnum == 0)
+ if (devnum <= 1)
return -EINVAL;
if (udev->state == USB_STATE_ADDRESS)
return 0;
if (udev->state != USB_STATE_DEFAULT)
return -EINVAL;
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
- USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
+ USB_REQ_SET_ADDRESS, 0, devnum, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval == 0) {
+ udev->devnum = devnum; /* Device now using proper address */
usb_set_device_state(udev, USB_STATE_ADDRESS);
ep0_reinit(udev);
}
@@ -2045,6 +2178,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
char *speed, *type;
+ int devnum = udev->devnum;
/* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5)
@@ -2074,7 +2208,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}
oldspeed = udev->speed;
-
+
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
* For Wireless USB devices, ep0 max packet is always 512 (tho
@@ -2115,7 +2249,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
dev_info (&udev->dev,
"%s %s speed %sUSB device using %s and address %d\n",
(udev->config) ? "reset" : "new", speed, type,
- udev->bus->controller->driver->name, udev->devnum);
+ udev->bus->controller->driver->name, devnum);
/* Set up TT records, if needed */
if (hdev->tt) {
@@ -2202,7 +2336,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
}
for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
- retval = hub_set_address(udev);
+ retval = hub_set_address(udev, devnum);
if (retval >= 0)
break;
msleep(200);
@@ -2210,7 +2344,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval < 0) {
dev_err(&udev->dev,
"device not accepting address %d, error %d\n",
- udev->devnum, retval);
+ devnum, retval);
goto fail;
}
@@ -2263,8 +2397,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = 0;
fail:
- if (retval)
+ if (retval) {
hub_port_disable(hub, port1, 0);
+ udev->devnum = devnum; /* for disconnect processing */
+ }
mutex_unlock(&usb_address0_mutex);
return retval;
}
@@ -2699,9 +2835,9 @@ static void hub_events(void)
clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
if (hubstatus & HUB_STATUS_LOCAL_POWER)
/* FIXME: Is this always true? */
- hub->limited_power = 0;
- else
hub->limited_power = 1;
+ else
+ hub->limited_power = 0;
}
if (hubchange & HUB_CHANGE_OVERCURRENT) {
dev_dbg (hub_dev, "overcurrent change\n");
@@ -2734,10 +2870,9 @@ static int hub_thread(void *__unused)
set_freezable();
do {
hub_events();
- wait_event_interruptible(khubd_wait,
+ wait_event_freezable(khubd_wait,
!list_empty(&hub_event_list) ||
kthread_should_stop());
- try_to_freeze();
} while (!kthread_should_stop() || !list_empty(&hub_event_list));
pr_debug("%s: khubd exiting\n", usbcore_name);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index d8f7b089a8f..316a746e008 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -11,9 +11,9 @@
#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/device.h>
+#include <linux/scatterlist.h>
#include <linux/usb/quirks.h>
#include <asm/byteorder.h>
-#include <asm/scatterlist.h>
#include "hcd.h" /* for usbcore internals */
#include "usb.h"
@@ -59,8 +59,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
dev_dbg(&urb->dev->dev,
"%s timed out on ep%d%s len=%d/%d\n",
current->comm,
- usb_pipeendpoint(urb->pipe),
- usb_pipein(urb->pipe) ? "in" : "out",
+ usb_endpoint_num(&urb->ep->desc),
+ usb_urb_dir_in(urb) ? "in" : "out",
urb->actual_length,
urb->transfer_buffer_length);
} else
@@ -250,7 +250,8 @@ static void sg_clean (struct usb_sg_request *io)
io->urbs = NULL;
}
if (io->dev->dev.dma_mask != NULL)
- usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
+ usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe),
+ io->sg, io->nents);
io->dev = NULL;
}
@@ -278,8 +279,8 @@ static void sg_complete (struct urb *urb)
dev_err (io->dev->bus->controller,
"dev %s ep%d%s scatterlist error %d/%d\n",
io->dev->devpath,
- usb_pipeendpoint (urb->pipe),
- usb_pipein (urb->pipe) ? "in" : "out",
+ usb_endpoint_num(&urb->ep->desc),
+ usb_urb_dir_in(urb) ? "in" : "out",
status, io->status);
// BUG ();
}
@@ -379,7 +380,8 @@ int usb_sg_init (
*/
dma = (dev->dev.dma_mask != NULL);
if (dma)
- io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
+ io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
+ sg, nents);
else
io->entries = nents;
@@ -432,16 +434,14 @@ int usb_sg_init (
if (dma) {
io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
len = sg_dma_len (sg + i);
-#if defined(CONFIG_HIGHMEM) || defined(CONFIG_IOMMU)
+#if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU)
io->urbs[i]->transfer_buffer = NULL;
#else
- io->urbs[i]->transfer_buffer =
- page_address(sg[i].page) + sg[i].offset;
+ io->urbs[i]->transfer_buffer = sg_virt(&sg[i]);
#endif
} else {
/* hc may use _only_ transfer_buffer */
- io->urbs [i]->transfer_buffer =
- page_address (sg [i].page) + sg [i].offset;
+ io->urbs [i]->transfer_buffer = sg_virt(&sg[i]);
len = sg [i].length;
}
@@ -1013,8 +1013,11 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
ep = dev->ep_in[epnum];
dev->ep_in[epnum] = NULL;
}
- if (ep && dev->bus)
- usb_hcd_endpoint_disable(dev, ep);
+ if (ep) {
+ ep->enabled = 0;
+ usb_hcd_flush_endpoint(dev, ep);
+ usb_hcd_disable_endpoint(dev, ep);
+ }
}
/**
@@ -1096,23 +1099,21 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
* Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
* For control endpoints, both the input and output sides are handled.
*/
-static void
-usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
+void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
{
- unsigned int epaddr = ep->desc.bEndpointAddress;
- unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
- int is_control;
+ int epnum = usb_endpoint_num(&ep->desc);
+ int is_out = usb_endpoint_dir_out(&ep->desc);
+ int is_control = usb_endpoint_xfer_control(&ep->desc);
- is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_CONTROL);
- if (usb_endpoint_out(epaddr) || is_control) {
+ if (is_out || is_control) {
usb_settoggle(dev, epnum, 1, 0);
dev->ep_out[epnum] = ep;
}
- if (!usb_endpoint_out(epaddr) || is_control) {
+ if (!is_out || is_control) {
usb_settoggle(dev, epnum, 0, 0);
dev->ep_in[epnum] = ep;
}
+ ep->enabled = 1;
}
/*
@@ -1171,6 +1172,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
struct usb_host_interface *alt;
int ret;
int manual = 0;
+ int changed;
if (dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
@@ -1210,7 +1212,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
*/
/* prevent submissions using previous endpoint settings */
- if (device_is_registered(&iface->dev))
+ changed = (iface->cur_altsetting != alt);
+ if (changed && device_is_registered(&iface->dev))
usb_remove_sysfs_intf_files(iface);
usb_disable_interface(dev, iface);
@@ -1247,7 +1250,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
* (Likewise, EP0 never "halts" on well designed devices.)
*/
usb_enable_interface(dev, iface);
- if (device_is_registered(&iface->dev))
+ if (changed && device_is_registered(&iface->dev))
usb_create_sysfs_intf_files(iface);
return 0;
@@ -1328,7 +1331,7 @@ int usb_reset_configuration(struct usb_device *dev)
return 0;
}
-void usb_release_interface(struct device *dev)
+static void usb_release_interface(struct device *dev)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_interface_cache *intfc =
@@ -1339,14 +1342,11 @@ void usb_release_interface(struct device *dev)
}
#ifdef CONFIG_HOTPLUG
-static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct usb_device *usb_dev;
struct usb_interface *intf;
struct usb_host_interface *alt;
- int i = 0;
- int length = 0;
if (!dev)
return -ENODEV;
@@ -1359,39 +1359,30 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
alt = intf->cur_altsetting;
#ifdef CONFIG_USB_DEVICEFS
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVICE=/proc/bus/usb/%03d/%03d",
+ if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
usb_dev->bus->busnum, usb_dev->devnum))
return -ENOMEM;
#endif
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PRODUCT=%x/%x/%x",
+ if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
le16_to_cpu(usb_dev->descriptor.bcdDevice)))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "TYPE=%d/%d/%d",
+ if (add_uevent_var(env, "TYPE=%d/%d/%d",
usb_dev->descriptor.bDeviceClass,
usb_dev->descriptor.bDeviceSubClass,
usb_dev->descriptor.bDeviceProtocol))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "INTERFACE=%d/%d/%d",
+ if (add_uevent_var(env, "INTERFACE=%d/%d/%d",
alt->desc.bInterfaceClass,
alt->desc.bInterfaceSubClass,
alt->desc.bInterfaceProtocol))
return -ENOMEM;
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
+ if (add_uevent_var(env,
"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
le16_to_cpu(usb_dev->descriptor.idVendor),
le16_to_cpu(usb_dev->descriptor.idProduct),
@@ -1404,14 +1395,12 @@ static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
alt->desc.bInterfaceProtocol))
return -ENOMEM;
- envp[i] = NULL;
return 0;
}
#else
-static int usb_if_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return -ENODEV;
}
@@ -1481,6 +1470,9 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
* channels are available independently; and choosing between open
* standard device protocols (like CDC) or proprietary ones.
*
+ * Note that a non-authorized device (dev->authorized == 0) will only
+ * be put in unconfigured mode.
+ *
* Note that USB has an additional level of device configurability,
* associated with interfaces. That configurability is accessed using
* usb_set_interface().
@@ -1502,7 +1494,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
struct usb_interface **new_interfaces = NULL;
int n, nintf;
- if (configuration == -1)
+ if (dev->authorized == 0 || configuration == -1)
configuration = 0;
else {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
@@ -1532,7 +1524,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),
GFP_KERNEL);
if (!new_interfaces) {
- dev_err(&dev->dev, "Out of memory");
+ dev_err(&dev->dev, "Out of memory\n");
return -ENOMEM;
}
@@ -1541,7 +1533,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
sizeof(struct usb_interface),
GFP_KERNEL);
if (!new_interfaces[n]) {
- dev_err(&dev->dev, "Out of memory");
+ dev_err(&dev->dev, "Out of memory\n");
ret = -ENOMEM;
free_interfaces:
while (--n >= 0)
@@ -1649,7 +1641,13 @@ free_interfaces:
intf->dev.bus_id, ret);
continue;
}
- usb_create_sysfs_intf_files (intf);
+
+ /* The driver's probe method can call usb_set_interface(),
+ * which would mean the interface's sysfs files are already
+ * created. Just in case, we'll remove them first.
+ */
+ usb_remove_sysfs_intf_files(intf);
+ usb_create_sysfs_intf_files(intf);
}
usb_autosuspend_device(dev);
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index ebf3dc20110..d42c561c75f 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -32,52 +32,6 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
/* HP 5300/5370C scanner */
{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
- /* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */
- { USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* SGS Thomson Microelectronics 4in1 card reader */
- { USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */
- { USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Benq S2W 3300U */
- { USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Canon, Inc. CanoScan N1240U/LiDE30 */
- { USB_DEVICE(0x04a9, 0x220e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Canon, Inc. CanoScan N650U/N656U */
- { USB_DEVICE(0x04a9, 0x2206), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Canon, Inc. CanoScan 1220U */
- { USB_DEVICE(0x04a9, 0x2207), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Canon, Inc. CanoScan N670U/N676U/LiDE 20 */
- { USB_DEVICE(0x04a9, 0x220d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* old Cannon scanner */
- { USB_DEVICE(0x04a9, 0x2220), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Seiko Epson Corp. Perfection 1200 */
- { USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Seiko Epson Corp. Perfection 660 */
- { USB_DEVICE(0x04b8, 0x0114), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Epson Perfection 1260 Photo */
- { USB_DEVICE(0x04b8, 0x011d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Seiko Epson Corp - Perfection 1670 */
- { USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* EPSON Perfection 2480 */
- { USB_DEVICE(0x04b8, 0x0121), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Seiko Epson Corp.*/
- { USB_DEVICE(0x04b8, 0x0122), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Samsung ML-2010 printer */
- { USB_DEVICE(0x04e8, 0x326c), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Samsung ML-2510 Series printer */
- { USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Elsa MicroLink 56k (V.250) */
- { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Ultima Electronics Corp.*/
- { USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* Genesys USB-to-IDE */
- { USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* USB Graphical LCD - EEH Datalink GmbH */
- { USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* INTEL VALUE SSD */
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -85,44 +39,15 @@ static const struct usb_device_id usb_quirk_list[] = {
/* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
- /* Agfa Snapscan1212u */
- { USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Seagate RSS LLC */
- { USB_DEVICE(0x0bc2, 0x3000), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- /* Umax [hex] Astra 3400U */
- { USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
/* Philips PSC805 audio device */
{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
- /* Alcor multi-card reader */
- { USB_DEVICE(0x058f, 0x6366), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* Canon EOS 5D in PC Connection mode */
- { USB_DEVICE(0x04a9, 0x3101), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* RIM Blackberry */
- { USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- { USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
- { USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
- /* Apple iPhone */
- { USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
/* SKYMEDI USB_DRIVE */
{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
{ } /* terminating entry must be last */
};
-static void usb_autosuspend_quirk(struct usb_device *udev)
-{
-#ifdef CONFIG_USB_SUSPEND
- /* disable autosuspend, but allow the user to re-enable it via sysfs */
- udev->autosuspend_disabled = 1;
-#endif
-}
-
static const struct usb_device_id *find_id(struct usb_device *udev)
{
const struct usb_device_id *id = usb_quirk_list;
@@ -149,13 +74,9 @@ void usb_detect_quirks(struct usb_device *udev)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks);
- /* do any special quirk handling here if needed */
- if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
- usb_autosuspend_quirk(udev);
-
/* By default, disable autosuspend for all non-hubs */
#ifdef CONFIG_USB_SUSPEND
if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
- udev->autosuspend_delay = -1;
+ udev->autosuspend_disabled = 1;
#endif
}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 2ab222be8fd..b04afd06e50 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -169,6 +169,16 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
+static ssize_t
+show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev;
+
+ udev = to_usb_device(dev);
+ return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
+}
+static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
+
#if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
static const char power_group[] = "power";
@@ -413,6 +423,44 @@ usb_descriptor_attr(bDeviceProtocol, "%02x\n")
usb_descriptor_attr(bNumConfigurations, "%d\n")
usb_descriptor_attr(bMaxPacketSize0, "%d\n")
+
+
+/* show if the device is authorized (1) or not (0) */
+static ssize_t usb_dev_authorized_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_device *usb_dev = to_usb_device(dev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
+}
+
+
+/*
+ * Authorize a device to be used in the system
+ *
+ * Writing a 0 deauthorizes the device, writing a 1 authorizes it.
+ */
+static ssize_t usb_dev_authorized_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ ssize_t result;
+ struct usb_device *usb_dev = to_usb_device(dev);
+ unsigned val;
+ result = sscanf(buf, "%u\n", &val);
+ if (result != 1)
+ result = -EINVAL;
+ else if (val == 0)
+ result = usb_deauthorize_device(usb_dev);
+ else
+ result = usb_authorize_device(usb_dev);
+ return result < 0? result : size;
+}
+
+static DEVICE_ATTR(authorized, 0644,
+ usb_dev_authorized_show, usb_dev_authorized_store);
+
+
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
&dev_attr_configuration.attr,
@@ -420,6 +468,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_bConfigurationValue.attr,
&dev_attr_bmAttributes.attr,
&dev_attr_bMaxPower.attr,
+ &dev_attr_urbnum.attr,
/* device attributes */
&dev_attr_idVendor.attr,
&dev_attr_idProduct.attr,
@@ -435,6 +484,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_version.attr,
&dev_attr_maxchild.attr,
&dev_attr_quirks.attr,
+ &dev_attr_authorized.attr,
NULL,
};
static struct attribute_group dev_attr_grp = {
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index be630228461..d05ead20081 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -3,6 +3,7 @@
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/log2.h>
#include <linux/usb.h>
#include <linux/wait.h>
#include "hcd.h"
@@ -38,7 +39,6 @@ void usb_init_urb(struct urb *urb)
if (urb) {
memset(urb, 0, sizeof(*urb));
kref_init(&urb->kref);
- spin_lock_init(&urb->lock);
INIT_LIST_HEAD(&urb->anchor_list);
}
}
@@ -277,44 +277,58 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
*/
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
- int pipe, temp, max;
- struct usb_device *dev;
- int is_out;
+ int xfertype, max;
+ struct usb_device *dev;
+ struct usb_host_endpoint *ep;
+ int is_out;
if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
- if (!(dev = urb->dev) ||
- (dev->state < USB_STATE_DEFAULT) ||
- (!dev->bus) || (dev->devnum <= 0))
+ if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
return -ENODEV;
- if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
- || dev->state == USB_STATE_SUSPENDED)
- return -EHOSTUNREACH;
+ /* For now, get the endpoint from the pipe. Eventually drivers
+ * will be required to set urb->ep directly and we will eliminate
+ * urb->pipe.
+ */
+ ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
+ [usb_pipeendpoint(urb->pipe)];
+ if (!ep)
+ return -ENOENT;
+
+ urb->ep = ep;
urb->status = -EINPROGRESS;
urb->actual_length = 0;
/* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/
- pipe = urb->pipe;
- temp = usb_pipetype(pipe);
- is_out = usb_pipeout(pipe);
+ xfertype = usb_endpoint_type(&ep->desc);
+ if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
+ struct usb_ctrlrequest *setup =
+ (struct usb_ctrlrequest *) urb->setup_packet;
+
+ if (!setup)
+ return -ENOEXEC;
+ is_out = !(setup->bRequestType & USB_DIR_IN) ||
+ !setup->wLength;
+ } else {
+ is_out = usb_endpoint_dir_out(&ep->desc);
+ }
- if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
- return -ENODEV;
+ /* Cache the direction for later use */
+ urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
+ (is_out ? URB_DIR_OUT : URB_DIR_IN);
- /* FIXME there should be a sharable lock protecting us against
- * config/altsetting changes and disconnects, kicking in here.
- * (here == before maxpacket, and eventually endpoint type,
- * checks get made.)
- */
+ if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
+ dev->state < USB_STATE_CONFIGURED)
+ return -ENODEV;
- max = usb_maxpacket(dev, pipe, is_out);
+ max = le16_to_cpu(ep->desc.wMaxPacketSize);
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
- usb_pipeendpoint(pipe), is_out ? "out" : "in",
+ usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
__FUNCTION__, max);
return -EMSGSIZE;
}
@@ -323,7 +337,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* but drivers only control those sizes for ISO.
* while we're checking, initialize return status.
*/
- if (temp == PIPE_ISOCHRONOUS) {
+ if (xfertype == USB_ENDPOINT_XFER_ISOC) {
int n, len;
/* "high bandwidth" mode, 1-3 packets/uframe? */
@@ -358,20 +372,20 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
/* enforce simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
- URB_NO_INTERRUPT);
- switch (temp) {
- case PIPE_BULK:
+ URB_NO_INTERRUPT | URB_DIR_MASK | URB_FREE_BUFFER);
+ switch (xfertype) {
+ case USB_ENDPOINT_XFER_BULK:
if (is_out)
allowed |= URB_ZERO_PACKET;
/* FALLTHROUGH */
- case PIPE_CONTROL:
+ case USB_ENDPOINT_XFER_CONTROL:
allowed |= URB_NO_FSBR; /* only affects UHCI */
/* FALLTHROUGH */
default: /* all non-iso endpoints */
if (!is_out)
allowed |= URB_SHORT_NOT_OK;
break;
- case PIPE_ISOCHRONOUS:
+ case USB_ENDPOINT_XFER_ISOC:
allowed |= URB_ISO_ASAP;
break;
}
@@ -393,9 +407,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* supports different values... this uses EHCI/UHCI defaults (and
* EHCI can use smaller non-default values).
*/
- switch (temp) {
- case PIPE_ISOCHRONOUS:
- case PIPE_INTERRUPT:
+ switch (xfertype) {
+ case USB_ENDPOINT_XFER_ISOC:
+ case USB_ENDPOINT_XFER_INT:
/* too small? */
if (urb->interval <= 0)
return -EINVAL;
@@ -405,29 +419,27 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
// NOTE usb handles 2^15
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
- temp = 1024 * 8;
+ max = 1024 * 8;
break;
case USB_SPEED_FULL: /* units are frames/msec */
case USB_SPEED_LOW:
- if (temp == PIPE_INTERRUPT) {
+ if (xfertype == USB_ENDPOINT_XFER_INT) {
if (urb->interval > 255)
return -EINVAL;
// NOTE ohci only handles up to 32
- temp = 128;
+ max = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
// NOTE usb and ohci handle up to 2^15
- temp = 1024;
+ max = 1024;
}
break;
default:
return -EINVAL;
}
- /* power of two? */
- while (temp > urb->interval)
- temp >>= 1;
- urb->interval = temp;
+ /* Round down to a power of 2, no more than max */
+ urb->interval = min(max, 1 << ilog2(urb->interval));
}
return usb_hcd_submit_urb(urb, mem_flags);
@@ -496,8 +508,10 @@ int usb_unlink_urb(struct urb *urb)
{
if (!urb)
return -EINVAL;
- if (!(urb->dev && urb->dev->bus))
+ if (!urb->dev)
return -ENODEV;
+ if (!urb->ep)
+ return -EIDRM;
return usb_hcd_unlink_urb(urb, -ECONNRESET);
}
@@ -523,19 +537,21 @@ int usb_unlink_urb(struct urb *urb)
*/
void usb_kill_urb(struct urb *urb)
{
+ static DEFINE_MUTEX(reject_mutex);
+
might_sleep();
- if (!(urb && urb->dev && urb->dev->bus))
+ if (!(urb && urb->dev && urb->ep))
return;
- spin_lock_irq(&urb->lock);
+ mutex_lock(&reject_mutex);
++urb->reject;
- spin_unlock_irq(&urb->lock);
+ mutex_unlock(&reject_mutex);
usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
- spin_lock_irq(&urb->lock);
+ mutex_lock(&reject_mutex);
--urb->reject;
- spin_unlock_irq(&urb->lock);
+ mutex_unlock(&reject_mutex);
}
/**
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 0fee5c66fd6..c4a6f1095b8 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -36,7 +36,7 @@
#include <linux/workqueue.h>
#include <asm/io.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
@@ -223,6 +223,15 @@ static void ksuspend_usb_cleanup(void)
#endif /* CONFIG_PM */
+
+/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
+static unsigned usb_bus_is_wusb(struct usb_bus *bus)
+{
+ struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self);
+ return hcd->wireless;
+}
+
+
/**
* usb_alloc_dev - usb device constructor (usbcore-internal)
* @parent: hub to which device is connected; null to allocate a root hub
@@ -239,6 +248,8 @@ struct usb_device *
usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
{
struct usb_device *dev;
+ struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
+ unsigned root_hub = 0;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
@@ -255,12 +266,14 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->dev.dma_mask = bus->controller->dma_mask;
set_dev_node(&dev->dev, dev_to_node(bus->controller));
dev->state = USB_STATE_ATTACHED;
+ atomic_set(&dev->urbnum, 0);
INIT_LIST_HEAD(&dev->ep0.urb_list);
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
/* ep0 maxpacket comes later, from device descriptor */
- dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
+ usb_enable_endpoint(dev, &dev->ep0);
+ dev->can_submit = 1;
/* Save readable and stable topology id, distinguishing devices
* by location for diagnostics, tools, driver model, etc. The
@@ -275,6 +288,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->dev.parent = bus->controller;
sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
+ root_hub = 1;
} else {
/* match any labeling on the hubs; it's one-based */
if (parent->devpath[0] == '0')
@@ -301,6 +315,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
#endif
+ if (root_hub) /* Root hub always ok [and always wired] */
+ dev->authorized = 1;
+ else {
+ dev->authorized = usb_hcd->authorized_default;
+ dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
+ }
return dev;
}
@@ -748,7 +768,7 @@ void usb_buffer_unmap(struct urb *urb)
/**
* usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
* @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
* @sg: the scatterlist to map
* @nents: the number of entries in the scatterlist
*
@@ -771,14 +791,13 @@ void usb_buffer_unmap(struct urb *urb)
*
* Reverse the effect of this call with usb_buffer_unmap_sg().
*/
-int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int nents)
{
struct usb_bus *bus;
struct device *controller;
if (!dev
- || usb_pipecontrol(pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
@@ -786,7 +805,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
// FIXME generic api broken like pci, can't report errors
return dma_map_sg(controller, sg, nents,
- usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* XXX DISABLED, no users currently. If you wish to re-enable this
@@ -799,14 +818,14 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
/**
* usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
* @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
* @sg: the scatterlist to synchronize
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Use this when you are re-using a scatterlist's data buffers for
* another USB request.
*/
-void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
@@ -819,20 +838,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
return;
dma_sync_sg(controller, sg, n_hw_ents,
- usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
#endif
/**
* usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
* @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
* @sg: the scatterlist to unmap
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Reverses the effect of usb_buffer_map_sg().
*/
-void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
@@ -845,7 +864,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
return;
dma_unmap_sg(controller, sg, n_hw_ents,
- usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* format to disable USB on kernel command line is: nousb */
@@ -963,7 +982,6 @@ EXPORT_SYMBOL(usb_altnum_to_altsetting);
EXPORT_SYMBOL(__usb_get_extra_descriptor);
-EXPORT_SYMBOL(usb_find_device);
EXPORT_SYMBOL(usb_get_current_frame_number);
EXPORT_SYMBOL(usb_buffer_alloc);
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index ad5fa0338f4..c52626c51f7 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -8,17 +8,22 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *
struct usb_device *udev);
extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
+extern void usb_enable_endpoint(struct usb_device *dev,
+ struct usb_host_endpoint *ep);
extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
extern void usb_disable_interface (struct usb_device *dev,
struct usb_interface *intf);
extern void usb_release_interface_cache(struct kref *ref);
extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
+extern int usb_deauthorize_device (struct usb_device *);
+extern int usb_authorize_device (struct usb_device *);
extern void usb_detect_quirks(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size);
extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
+extern int usb_choose_configuration(struct usb_device *udev);
extern void usb_kick_khubd(struct usb_device *dev);
extern int usb_match_device(struct usb_device *dev,
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 767aed5b4be..f81d08d6538 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -67,6 +67,17 @@ config USB_GADGET_DEBUG_FILES
driver on a new board. Enable these files by choosing "Y"
here. If in doubt, or to conserve kernel memory, say "N".
+config USB_GADGET_DEBUG_FS
+ boolean "Debugging information files in debugfs"
+ depends on USB_GADGET && DEBUG_FS
+ help
+ Some of the drivers in the "gadget" framework can expose
+ debugging information in files under /sys/kernel/debug/.
+ The information in these files may help when you're
+ troubleshooting or bringing up a driver on a new board.
+ Enable these files by choosing "Y" here. If in doubt, or
+ to conserve kernel memory, say "N".
+
config USB_GADGET_SELECTED
boolean
@@ -103,6 +114,20 @@ config USB_AMD5536UDC
default USB_GADGET
select USB_GADGET_SELECTED
+config USB_GADGET_ATMEL_USBA
+ boolean "Atmel USBA"
+ select USB_GADGET_DUALSPEED
+ depends on AVR32
+ help
+ USBA is the integrated high-speed USB Device controller on
+ the AT32AP700x processors from Atmel.
+
+config USB_ATMEL_USBA
+ tristate
+ depends on USB_GADGET_ATMEL_USBA
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_FSL_USB2
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on MPC834x || PPC_MPC831x
@@ -228,7 +253,6 @@ config USB_LH7A40X
default USB_GADGET
select USB_GADGET_SELECTED
-
config USB_GADGET_OMAP
boolean "OMAP USB Device Controller"
depends on ARCH_OMAP
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 1bc0f03550c..904e57bf611 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
obj-$(CONFIG_USB_AT91) += at91_udc.o
+obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 714156ca8fe..c72e9620bf8 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -69,7 +69,7 @@
/* gadget stack */
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
/* udc specific */
#include "amd5536udc.h"
@@ -3244,7 +3244,6 @@ static int udc_pci_probe(
retval = -ENOMEM;
goto finished;
}
- memset(dev, 0, sizeof(struct udc));
/* pci setup */
if (pci_enable_device(pdev) < 0) {
@@ -3286,14 +3285,12 @@ static int udc_pci_probe(
pci_set_drvdata(pdev, dev);
- /* chip revision */
- dev->chiprev = 0;
+ /* chip revision for Hs AMD5536 */
+ dev->chiprev = pdev->revision;
pci_set_master(pdev);
- pci_set_mwi(pdev);
+ pci_try_set_mwi(pdev);
- /* chip rev for Hs AMD5536 */
- pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
/* init dma pools */
if (use_dma) {
retval = init_dma_pools(dev);
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 63d7d656869..a6adf7e0f6f 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -38,7 +38,7 @@
#include <linux/proc_fs.h>
#include <linux/clk.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/hardware.h>
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
new file mode 100644
index 00000000000..4fb5ff46957
--- /dev/null
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -0,0 +1,2077 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/delay.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/board.h>
+
+#include "atmel_usba_udc.h"
+
+
+static struct usba_udc the_udc;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+static int queue_dbg_open(struct inode *inode, struct file *file)
+{
+ struct usba_ep *ep = inode->i_private;
+ struct usba_request *req, *req_copy;
+ struct list_head *queue_data;
+
+ queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL);
+ if (!queue_data)
+ return -ENOMEM;
+ INIT_LIST_HEAD(queue_data);
+
+ spin_lock_irq(&ep->udc->lock);
+ list_for_each_entry(req, &ep->queue, queue) {
+ req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC);
+ if (!req_copy)
+ goto fail;
+ memcpy(req_copy, req, sizeof(*req_copy));
+ list_add_tail(&req_copy->queue, queue_data);
+ }
+ spin_unlock_irq(&ep->udc->lock);
+
+ file->private_data = queue_data;
+ return 0;
+
+fail:
+ spin_unlock_irq(&ep->udc->lock);
+ list_for_each_entry_safe(req, req_copy, queue_data, queue) {
+ list_del(&req->queue);
+ kfree(req);
+ }
+ kfree(queue_data);
+ return -ENOMEM;
+}
+
+/*
+ * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0
+ *
+ * b: buffer address
+ * l: buffer length
+ * I/i: interrupt/no interrupt
+ * Z/z: zero/no zero
+ * S/s: short ok/short not ok
+ * s: status
+ * n: nr_packets
+ * F/f: submitted/not submitted to FIFO
+ * D/d: using/not using DMA
+ * L/l: last transaction/not last transaction
+ */
+static ssize_t queue_dbg_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct list_head *queue = file->private_data;
+ struct usba_request *req, *tmp_req;
+ size_t len, remaining, actual = 0;
+ char tmpbuf[38];
+
+ if (!access_ok(VERIFY_WRITE, buf, nbytes))
+ return -EFAULT;
+
+ mutex_lock(&file->f_dentry->d_inode->i_mutex);
+ list_for_each_entry_safe(req, tmp_req, queue, queue) {
+ len = snprintf(tmpbuf, sizeof(tmpbuf),
+ "%8p %08x %c%c%c %5d %c%c%c\n",
+ req->req.buf, req->req.length,
+ req->req.no_interrupt ? 'i' : 'I',
+ req->req.zero ? 'Z' : 'z',
+ req->req.short_not_ok ? 's' : 'S',
+ req->req.status,
+ req->submitted ? 'F' : 'f',
+ req->using_dma ? 'D' : 'd',
+ req->last_transaction ? 'L' : 'l');
+ len = min(len, sizeof(tmpbuf));
+ if (len > nbytes)
+ break;
+
+ list_del(&req->queue);
+ kfree(req);
+
+ remaining = __copy_to_user(buf, tmpbuf, len);
+ actual += len - remaining;
+ if (remaining)
+ break;
+
+ nbytes -= len;
+ buf += len;
+ }
+ mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+
+ return actual;
+}
+
+static int queue_dbg_release(struct inode *inode, struct file *file)
+{
+ struct list_head *queue_data = file->private_data;
+ struct usba_request *req, *tmp_req;
+
+ list_for_each_entry_safe(req, tmp_req, queue_data, queue) {
+ list_del(&req->queue);
+ kfree(req);
+ }
+ kfree(queue_data);
+ return 0;
+}
+
+static int regs_dbg_open(struct inode *inode, struct file *file)
+{
+ struct usba_udc *udc;
+ unsigned int i;
+ u32 *data;
+ int ret = -ENOMEM;
+
+ mutex_lock(&inode->i_mutex);
+ udc = inode->i_private;
+ data = kmalloc(inode->i_size, GFP_KERNEL);
+ if (!data)
+ goto out;
+
+ spin_lock_irq(&udc->lock);
+ for (i = 0; i < inode->i_size / 4; i++)
+ data[i] = __raw_readl(udc->regs + i * 4);
+ spin_unlock_irq(&udc->lock);
+
+ file->private_data = data;
+ ret = 0;
+
+out:
+ mutex_unlock(&inode->i_mutex);
+
+ return ret;
+}
+
+static ssize_t regs_dbg_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ int ret;
+
+ mutex_lock(&inode->i_mutex);
+ ret = simple_read_from_buffer(buf, nbytes, ppos,
+ file->private_data,
+ file->f_dentry->d_inode->i_size);
+ mutex_unlock(&inode->i_mutex);
+
+ return ret;
+}
+
+static int regs_dbg_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+const struct file_operations queue_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = queue_dbg_open,
+ .llseek = no_llseek,
+ .read = queue_dbg_read,
+ .release = queue_dbg_release,
+};
+
+const struct file_operations regs_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = regs_dbg_open,
+ .llseek = generic_file_llseek,
+ .read = regs_dbg_read,
+ .release = regs_dbg_release,
+};
+
+static void usba_ep_init_debugfs(struct usba_udc *udc,
+ struct usba_ep *ep)
+{
+ struct dentry *ep_root;
+
+ ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root);
+ if (!ep_root)
+ goto err_root;
+ ep->debugfs_dir = ep_root;
+
+ ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root,
+ ep, &queue_dbg_fops);
+ if (!ep->debugfs_queue)
+ goto err_queue;
+
+ if (ep->can_dma) {
+ ep->debugfs_dma_status
+ = debugfs_create_u32("dma_status", 0400, ep_root,
+ &ep->last_dma_status);
+ if (!ep->debugfs_dma_status)
+ goto err_dma_status;
+ }
+ if (ep_is_control(ep)) {
+ ep->debugfs_state
+ = debugfs_create_u32("state", 0400, ep_root,
+ &ep->state);
+ if (!ep->debugfs_state)
+ goto err_state;
+ }
+
+ return;
+
+err_state:
+ if (ep->can_dma)
+ debugfs_remove(ep->debugfs_dma_status);
+err_dma_status:
+ debugfs_remove(ep->debugfs_queue);
+err_queue:
+ debugfs_remove(ep_root);
+err_root:
+ dev_err(&ep->udc->pdev->dev,
+ "failed to create debugfs directory for %s\n", ep->ep.name);
+}
+
+static void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+ debugfs_remove(ep->debugfs_queue);
+ debugfs_remove(ep->debugfs_dma_status);
+ debugfs_remove(ep->debugfs_state);
+ debugfs_remove(ep->debugfs_dir);
+ ep->debugfs_dma_status = NULL;
+ ep->debugfs_dir = NULL;
+}
+
+static void usba_init_debugfs(struct usba_udc *udc)
+{
+ struct dentry *root, *regs;
+ struct resource *regs_resource;
+
+ root = debugfs_create_dir(udc->gadget.name, NULL);
+ if (IS_ERR(root) || !root)
+ goto err_root;
+ udc->debugfs_root = root;
+
+ regs = debugfs_create_file("regs", 0400, root, udc, &regs_dbg_fops);
+ if (!regs)
+ goto err_regs;
+
+ regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,
+ CTRL_IOMEM_ID);
+ regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1;
+ udc->debugfs_regs = regs;
+
+ usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0));
+
+ return;
+
+err_regs:
+ debugfs_remove(root);
+err_root:
+ udc->debugfs_root = NULL;
+ dev_err(&udc->pdev->dev, "debugfs is not available\n");
+}
+
+static void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+ usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0));
+ debugfs_remove(udc->debugfs_regs);
+ debugfs_remove(udc->debugfs_root);
+ udc->debugfs_regs = NULL;
+ udc->debugfs_root = NULL;
+}
+#else
+static inline void usba_ep_init_debugfs(struct usba_udc *udc,
+ struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_init_debugfs(struct usba_udc *udc)
+{
+
+}
+
+static inline void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+
+}
+#endif
+
+static int vbus_is_present(struct usba_udc *udc)
+{
+ if (udc->vbus_pin != -1)
+ return gpio_get_value(udc->vbus_pin);
+
+ /* No Vbus detection: Assume always present */
+ return 1;
+}
+
+static void copy_to_fifo(void __iomem *fifo, const void *buf, int len)
+{
+ unsigned long tmp;
+
+ DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len);
+ for (; len > 0; len -= 4, buf += 4, fifo += 4) {
+ tmp = *(unsigned long *)buf;
+ if (len >= 4) {
+ DBG(DBG_FIFO, " -> %08lx\n", tmp);
+ __raw_writel(tmp, fifo);
+ } else {
+ do {
+ DBG(DBG_FIFO, " -> %02lx\n", tmp >> 24);
+ __raw_writeb(tmp >> 24, fifo);
+ fifo++;
+ tmp <<= 8;
+ } while (--len);
+ break;
+ }
+ }
+}
+
+static void copy_from_fifo(void *buf, void __iomem *fifo, int len)
+{
+ union {
+ unsigned long *w;
+ unsigned char *b;
+ } p;
+ unsigned long tmp;
+
+ DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len);
+ for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) {
+ if (len >= 4) {
+ tmp = __raw_readl(fifo);
+ *p.w = tmp;
+ DBG(DBG_FIFO, " -> %08lx\n", tmp);
+ } else {
+ do {
+ tmp = __raw_readb(fifo);
+ *p.b = tmp;
+ DBG(DBG_FIFO, " -> %02lx\n", tmp);
+ fifo++, p.b++;
+ } while (--len);
+ }
+ }
+}
+
+static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
+{
+ unsigned int transaction_len;
+
+ transaction_len = req->req.length - req->req.actual;
+ req->last_transaction = 1;
+ if (transaction_len > ep->ep.maxpacket) {
+ transaction_len = ep->ep.maxpacket;
+ req->last_transaction = 0;
+ } else if (transaction_len == ep->ep.maxpacket && req->req.zero)
+ req->last_transaction = 0;
+
+ DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n",
+ ep->ep.name, req, transaction_len,
+ req->last_transaction ? ", done" : "");
+
+ copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len);
+ usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+ req->req.actual += transaction_len;
+}
+
+static void submit_request(struct usba_ep *ep, struct usba_request *req)
+{
+ DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n",
+ ep->ep.name, req, req->req.length);
+
+ req->req.actual = 0;
+ req->submitted = 1;
+
+ if (req->using_dma) {
+ if (req->req.length == 0) {
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+ return;
+ }
+
+ if (req->req.zero)
+ usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET);
+ else
+ usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET);
+
+ usba_dma_writel(ep, ADDRESS, req->req.dma);
+ usba_dma_writel(ep, CONTROL, req->ctrl);
+ } else {
+ next_fifo_transaction(ep, req);
+ if (req->last_transaction) {
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+ } else {
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+ }
+ }
+}
+
+static void submit_next_request(struct usba_ep *ep)
+{
+ struct usba_request *req;
+
+ if (list_empty(&ep->queue)) {
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY);
+ return;
+ }
+
+ req = list_entry(ep->queue.next, struct usba_request, queue);
+ if (!req->submitted)
+ submit_request(ep, req);
+}
+
+static void send_status(struct usba_udc *udc, struct usba_ep *ep)
+{
+ ep->state = STATUS_STAGE_IN;
+ usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+}
+
+static void receive_data(struct usba_ep *ep)
+{
+ struct usba_udc *udc = ep->udc;
+ struct usba_request *req;
+ unsigned long status;
+ unsigned int bytecount, nr_busy;
+ int is_complete = 0;
+
+ status = usba_ep_readl(ep, STA);
+ nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+ DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy);
+
+ while (nr_busy > 0) {
+ if (list_empty(&ep->queue)) {
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+ break;
+ }
+ req = list_entry(ep->queue.next,
+ struct usba_request, queue);
+
+ bytecount = USBA_BFEXT(BYTE_COUNT, status);
+
+ if (status & (1 << 31))
+ is_complete = 1;
+ if (req->req.actual + bytecount >= req->req.length) {
+ is_complete = 1;
+ bytecount = req->req.length - req->req.actual;
+ }
+
+ copy_from_fifo(req->req.buf + req->req.actual,
+ ep->fifo, bytecount);
+ req->req.actual += bytecount;
+
+ usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+
+ if (is_complete) {
+ DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name);
+ req->req.status = 0;
+ list_del_init(&req->queue);
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+ spin_unlock(&udc->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&udc->lock);
+ }
+
+ status = usba_ep_readl(ep, STA);
+ nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+ if (is_complete && ep_is_control(ep)) {
+ send_status(udc, ep);
+ break;
+ }
+ }
+}
+
+static void
+request_complete(struct usba_ep *ep, struct usba_request *req, int status)
+{
+ struct usba_udc *udc = ep->udc;
+
+ WARN_ON(!list_empty(&req->queue));
+
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+
+ if (req->mapped) {
+ dma_unmap_single(
+ &udc->pdev->dev, req->req.dma, req->req.length,
+ ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ }
+
+ DBG(DBG_GADGET | DBG_REQ,
+ "%s: req %p complete: status %d, actual %u\n",
+ ep->ep.name, req, req->req.status, req->req.actual);
+
+ spin_unlock(&udc->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&udc->lock);
+}
+
+static void
+request_complete_list(struct usba_ep *ep, struct list_head *list, int status)
+{
+ struct usba_request *req, *tmp_req;
+
+ list_for_each_entry_safe(req, tmp_req, list, queue) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, status);
+ }
+}
+
+static int
+usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ unsigned long flags, ept_cfg, maxpacket;
+ unsigned int nr_trans;
+
+ DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
+
+ maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+
+ if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
+ || ep->index == 0
+ || desc->bDescriptorType != USB_DT_ENDPOINT
+ || maxpacket == 0
+ || maxpacket > ep->fifo_size) {
+ DBG(DBG_ERR, "ep_enable: Invalid argument");
+ return -EINVAL;
+ }
+
+ ep->is_isoc = 0;
+ ep->is_in = 0;
+
+ if (maxpacket <= 8)
+ ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8);
+ else
+ /* LSB is bit 1, not 0 */
+ ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3);
+
+ DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
+ ep->ep.name, ept_cfg, maxpacket);
+
+ if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+ ep->is_in = 1;
+ ept_cfg |= USBA_EPT_DIR_IN;
+ }
+
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL);
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (!ep->can_isoc) {
+ DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n",
+ ep->ep.name);
+ return -EINVAL;
+ }
+
+ /*
+ * Bits 11:12 specify number of _additional_
+ * transactions per microframe.
+ */
+ nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
+ if (nr_trans > 3)
+ return -EINVAL;
+
+ ep->is_isoc = 1;
+ ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO);
+
+ /*
+ * Do triple-buffering on high-bandwidth iso endpoints.
+ */
+ if (nr_trans > 1 && ep->nr_banks == 3)
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE);
+ else
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+ ept_cfg |= USBA_BF(NB_TRANS, nr_trans);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK);
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT);
+ ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+ break;
+ }
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+
+ if (ep->desc) {
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ DBG(DBG_ERR, "ep%d already enabled\n", ep->index);
+ return -EBUSY;
+ }
+
+ ep->desc = desc;
+ ep->ep.maxpacket = maxpacket;
+
+ usba_ep_writel(ep, CFG, ept_cfg);
+ usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+
+ if (ep->can_dma) {
+ u32 ctrl;
+
+ usba_writel(udc, INT_ENB,
+ (usba_readl(udc, INT_ENB)
+ | USBA_BF(EPT_INT, 1 << ep->index)
+ | USBA_BF(DMA_INT, 1 << ep->index)));
+ ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
+ usba_ep_writel(ep, CTL_ENB, ctrl);
+ } else {
+ usba_writel(udc, INT_ENB,
+ (usba_readl(udc, INT_ENB)
+ | USBA_BF(EPT_INT, 1 << ep->index)));
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
+ (unsigned long)usba_ep_readl(ep, CFG));
+ DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
+ (unsigned long)usba_readl(udc, INT_ENB));
+
+ return 0;
+}
+
+static int usba_ep_disable(struct usb_ep *_ep)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ LIST_HEAD(req_list);
+ unsigned long flags;
+
+ DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (!ep->desc) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name);
+ return -EINVAL;
+ }
+ ep->desc = NULL;
+
+ list_splice_init(&ep->queue, &req_list);
+ if (ep->can_dma) {
+ usba_dma_writel(ep, CONTROL, 0);
+ usba_dma_writel(ep, ADDRESS, 0);
+ usba_dma_readl(ep, STATUS);
+ }
+ usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
+ usba_writel(udc, INT_ENB,
+ usba_readl(udc, INT_ENB)
+ & ~USBA_BF(EPT_INT, 1 << ep->index));
+
+ request_complete_list(ep, &req_list, -ESHUTDOWN);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static struct usb_request *
+usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+ struct usba_request *req;
+
+ DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags);
+
+ req = kzalloc(sizeof(*req), gfp_flags);
+ if (!req)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+ req->req.dma = DMA_ADDR_INVALID;
+
+ return &req->req;
+}
+
+static void
+usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct usba_request *req = to_usba_req(_req);
+
+ DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req);
+
+ kfree(req);
+}
+
+static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
+ struct usba_request *req, gfp_t gfp_flags)
+{
+ unsigned long flags;
+ int ret;
+
+ DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n",
+ ep->ep.name, req->req.length, req->req.dma,
+ req->req.zero ? 'Z' : 'z',
+ req->req.short_not_ok ? 'S' : 's',
+ req->req.no_interrupt ? 'I' : 'i');
+
+ if (req->req.length > 0x10000) {
+ /* Lengths from 0 to 65536 (inclusive) are supported */
+ DBG(DBG_ERR, "invalid request length %u\n", req->req.length);
+ return -EINVAL;
+ }
+
+ req->using_dma = 1;
+
+ if (req->req.dma == DMA_ADDR_INVALID) {
+ req->req.dma = dma_map_single(
+ &udc->pdev->dev, req->req.buf, req->req.length,
+ ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(
+ &udc->pdev->dev, req->req.dma, req->req.length,
+ ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->mapped = 0;
+ }
+
+ req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
+ | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
+ | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
+
+ if (ep->is_in)
+ req->ctrl |= USBA_DMA_END_BUF_EN;
+
+ /*
+ * Add this request to the queue and submit for DMA if
+ * possible. Check if we're still alive first -- we may have
+ * received a reset since last time we checked.
+ */
+ ret = -ESHUTDOWN;
+ spin_lock_irqsave(&udc->lock, flags);
+ if (ep->desc) {
+ if (list_empty(&ep->queue))
+ submit_request(ep, req);
+
+ list_add_tail(&req->queue, &ep->queue);
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return ret;
+}
+
+static int
+usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+ struct usba_request *req = to_usba_req(_req);
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ unsigned long flags;
+ int ret;
+
+ DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",
+ ep->ep.name, req, _req->length);
+
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc)
+ return -ESHUTDOWN;
+
+ req->submitted = 0;
+ req->using_dma = 0;
+ req->last_transaction = 0;
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ if (ep->can_dma)
+ return queue_dma(udc, ep, req, gfp_flags);
+
+ /* May have received a reset since last time we checked */
+ ret = -ESHUTDOWN;
+ spin_lock_irqsave(&udc->lock, flags);
+ if (ep->desc) {
+ list_add_tail(&req->queue, &ep->queue);
+
+ if (ep->is_in || (ep_is_control(ep)
+ && (ep->state == DATA_STAGE_IN
+ || ep->state == STATUS_STAGE_IN)))
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+ else
+ usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return ret;
+}
+
+static void
+usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status)
+{
+ req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status);
+}
+
+static int stop_dma(struct usba_ep *ep, u32 *pstatus)
+{
+ unsigned int timeout;
+ u32 status;
+
+ /*
+ * Stop the DMA controller. When writing both CH_EN
+ * and LINK to 0, the other bits are not affected.
+ */
+ usba_dma_writel(ep, CONTROL, 0);
+
+ /* Wait for the FIFO to empty */
+ for (timeout = 40; timeout; --timeout) {
+ status = usba_dma_readl(ep, STATUS);
+ if (!(status & USBA_DMA_CH_EN))
+ break;
+ udelay(1);
+ }
+
+ if (pstatus)
+ *pstatus = status;
+
+ if (timeout == 0) {
+ dev_err(&ep->udc->pdev->dev,
+ "%s: timed out waiting for DMA FIFO to empty\n",
+ ep->ep.name);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ struct usba_request *req = to_usba_req(_req);
+ unsigned long flags;
+ u32 status;
+
+ DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n",
+ ep->ep.name, req);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (req->using_dma) {
+ /*
+ * If this request is currently being transferred,
+ * stop the DMA controller and reset the FIFO.
+ */
+ if (ep->queue.next == &req->queue) {
+ status = usba_dma_readl(ep, STATUS);
+ if (status & USBA_DMA_CH_EN)
+ stop_dma(ep, &status);
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ ep->last_dma_status = status;
+#endif
+
+ usba_writel(udc, EPT_RST, 1 << ep->index);
+
+ usba_update_req(ep, req, status);
+ }
+ }
+
+ /*
+ * Errors should stop the queue from advancing until the
+ * completion function returns.
+ */
+ list_del_init(&req->queue);
+
+ request_complete(ep, req, -ECONNRESET);
+
+ /* Process the next request if any */
+ submit_next_request(ep);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static int usba_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+ unsigned long flags;
+ int ret = 0;
+
+ DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,
+ value ? "set" : "clear");
+
+ if (!ep->desc) {
+ DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",
+ ep->ep.name);
+ return -ENODEV;
+ }
+ if (ep->is_isoc) {
+ DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n",
+ ep->ep.name);
+ return -ENOTTY;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /*
+ * We can't halt IN endpoints while there are still data to be
+ * transferred
+ */
+ if (!list_empty(&ep->queue)
+ || ((value && ep->is_in && (usba_ep_readl(ep, STA)
+ & USBA_BF(BUSY_BANKS, -1L))))) {
+ ret = -EAGAIN;
+ } else {
+ if (value)
+ usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+ else
+ usba_ep_writel(ep, CLR_STA,
+ USBA_FORCE_STALL | USBA_TOGGLE_CLR);
+ usba_ep_readl(ep, STA);
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return ret;
+}
+
+static int usba_ep_fifo_status(struct usb_ep *_ep)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+
+ return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+}
+
+static void usba_ep_fifo_flush(struct usb_ep *_ep)
+{
+ struct usba_ep *ep = to_usba_ep(_ep);
+ struct usba_udc *udc = ep->udc;
+
+ usba_writel(udc, EPT_RST, 1 << ep->index);
+}
+
+static const struct usb_ep_ops usba_ep_ops = {
+ .enable = usba_ep_enable,
+ .disable = usba_ep_disable,
+ .alloc_request = usba_ep_alloc_request,
+ .free_request = usba_ep_free_request,
+ .queue = usba_ep_queue,
+ .dequeue = usba_ep_dequeue,
+ .set_halt = usba_ep_set_halt,
+ .fifo_status = usba_ep_fifo_status,
+ .fifo_flush = usba_ep_fifo_flush,
+};
+
+static int usba_udc_get_frame(struct usb_gadget *gadget)
+{
+ struct usba_udc *udc = to_usba_udc(gadget);
+
+ return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM));
+}
+
+static int usba_udc_wakeup(struct usb_gadget *gadget)
+{
+ struct usba_udc *udc = to_usba_udc(gadget);
+ unsigned long flags;
+ u32 ctrl;
+ int ret = -EINVAL;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
+ ctrl = usba_readl(udc, CTRL);
+ usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP);
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return ret;
+}
+
+static int
+usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+ struct usba_udc *udc = to_usba_udc(gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (is_selfpowered)
+ udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
+ else
+ udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static const struct usb_gadget_ops usba_udc_ops = {
+ .get_frame = usba_udc_get_frame,
+ .wakeup = usba_udc_wakeup,
+ .set_selfpowered = usba_udc_set_selfpowered,
+};
+
+#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \
+{ \
+ .ep = { \
+ .ops = &usba_ep_ops, \
+ .name = nam, \
+ .maxpacket = maxpkt, \
+ }, \
+ .udc = &the_udc, \
+ .queue = LIST_HEAD_INIT(usba_ep[idx].queue), \
+ .fifo_size = maxpkt, \
+ .nr_banks = maxbk, \
+ .index = idx, \
+ .can_dma = dma, \
+ .can_isoc = isoc, \
+}
+
+static struct usba_ep usba_ep[] = {
+ EP("ep0", 0, 64, 1, 0, 0),
+ EP("ep1in-bulk", 1, 512, 2, 1, 1),
+ EP("ep2out-bulk", 2, 512, 2, 1, 1),
+ EP("ep3in-int", 3, 64, 3, 1, 0),
+ EP("ep4out-int", 4, 64, 3, 1, 0),
+ EP("ep5in-iso", 5, 1024, 3, 1, 1),
+ EP("ep6out-iso", 6, 1024, 3, 1, 1),
+};
+#undef EP
+
+static struct usb_endpoint_descriptor usba_ep0_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = __constant_cpu_to_le16(64),
+ /* FIXME: I have no idea what to put here */
+ .bInterval = 1,
+};
+
+static void nop_release(struct device *dev)
+{
+
+}
+
+static struct usba_udc the_udc = {
+ .gadget = {
+ .ops = &usba_udc_ops,
+ .ep0 = &usba_ep[0].ep,
+ .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list),
+ .is_dualspeed = 1,
+ .name = "atmel_usba_udc",
+ .dev = {
+ .bus_id = "gadget",
+ .release = nop_release,
+ },
+ },
+
+ .lock = SPIN_LOCK_UNLOCKED,
+};
+
+/*
+ * Called with interrupts disabled and udc->lock held.
+ */
+static void reset_all_endpoints(struct usba_udc *udc)
+{
+ struct usba_ep *ep;
+ struct usba_request *req, *tmp_req;
+
+ usba_writel(udc, EPT_RST, ~0UL);
+
+ ep = to_usba_ep(udc->gadget.ep0);
+ list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, -ECONNRESET);
+ }
+
+ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+ if (ep->desc) {
+ spin_unlock(&udc->lock);
+ usba_ep_disable(&ep->ep);
+ spin_lock(&udc->lock);
+ }
+ }
+}
+
+static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)
+{
+ struct usba_ep *ep;
+
+ if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+ return to_usba_ep(udc->gadget.ep0);
+
+ list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
+ u8 bEndpointAddress;
+
+ if (!ep->desc)
+ continue;
+ bEndpointAddress = ep->desc->bEndpointAddress;
+ if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+ continue;
+ if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
+ == (wIndex & USB_ENDPOINT_NUMBER_MASK))
+ return ep;
+ }
+
+ return NULL;
+}
+
+/* Called with interrupts disabled and udc->lock held */
+static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep)
+{
+ usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+ ep->state = WAIT_FOR_SETUP;
+}
+
+static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep)
+{
+ if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL)
+ return 1;
+ return 0;
+}
+
+static inline void set_address(struct usba_udc *udc, unsigned int addr)
+{
+ u32 regval;
+
+ DBG(DBG_BUS, "setting address %u...\n", addr);
+ regval = usba_readl(udc, CTRL);
+ regval = USBA_BFINS(DEV_ADDR, addr, regval);
+ usba_writel(udc, CTRL, regval);
+}
+
+static int do_test_mode(struct usba_udc *udc)
+{
+ static const char test_packet_buffer[] = {
+ /* JKJKJKJK * 9 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* JJKKJJKK * 8 */
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ /* JJKKJJKK * 8 */
+ 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+ /* JJJJJJJKKKKKKK * 8 */
+ 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ /* JJJJJJJK * 8 */
+ 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD,
+ /* {JKKKKKKK * 10}, JK */
+ 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E
+ };
+ struct usba_ep *ep;
+ struct device *dev = &udc->pdev->dev;
+ int test_mode;
+
+ test_mode = udc->test_mode;
+
+ /* Start from a clean slate */
+ reset_all_endpoints(udc);
+
+ switch (test_mode) {
+ case 0x0100:
+ /* Test_J */
+ usba_writel(udc, TST, USBA_TST_J_MODE);
+ dev_info(dev, "Entering Test_J mode...\n");
+ break;
+ case 0x0200:
+ /* Test_K */
+ usba_writel(udc, TST, USBA_TST_K_MODE);
+ dev_info(dev, "Entering Test_K mode...\n");
+ break;
+ case 0x0300:
+ /*
+ * Test_SE0_NAK: Force high-speed mode and set up ep0
+ * for Bulk IN transfers
+ */
+ ep = &usba_ep[0];
+ usba_writel(udc, TST,
+ USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH));
+ usba_ep_writel(ep, CFG,
+ USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+ | USBA_EPT_DIR_IN
+ | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+ | USBA_BF(BK_NUMBER, 1));
+ if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+ set_protocol_stall(udc, ep);
+ dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n");
+ } else {
+ usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+ dev_info(dev, "Entering Test_SE0_NAK mode...\n");
+ }
+ break;
+ case 0x0400:
+ /* Test_Packet */
+ ep = &usba_ep[0];
+ usba_ep_writel(ep, CFG,
+ USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+ | USBA_EPT_DIR_IN
+ | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+ | USBA_BF(BK_NUMBER, 1));
+ if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+ set_protocol_stall(udc, ep);
+ dev_err(dev, "Test_Packet: ep0 not mapped\n");
+ } else {
+ usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+ usba_writel(udc, TST, USBA_TST_PKT_MODE);
+ copy_to_fifo(ep->fifo, test_packet_buffer,
+ sizeof(test_packet_buffer));
+ usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+ dev_info(dev, "Entering Test_Packet mode...\n");
+ }
+ break;
+ default:
+ dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Avoid overly long expressions */
+static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq)
+{
+ if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
+ return true;
+ return false;
+}
+
+static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq)
+{
+ if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE))
+ return true;
+ return false;
+}
+
+static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq)
+{
+ if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT))
+ return true;
+ return false;
+}
+
+static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
+ struct usb_ctrlrequest *crq)
+{
+ int retval = 0;;
+
+ switch (crq->bRequest) {
+ case USB_REQ_GET_STATUS: {
+ u16 status;
+
+ if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) {
+ status = cpu_to_le16(udc->devstatus);
+ } else if (crq->bRequestType
+ == (USB_DIR_IN | USB_RECIP_INTERFACE)) {
+ status = __constant_cpu_to_le16(0);
+ } else if (crq->bRequestType
+ == (USB_DIR_IN | USB_RECIP_ENDPOINT)) {
+ struct usba_ep *target;
+
+ target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+ if (!target)
+ goto stall;
+
+ status = 0;
+ if (is_stalled(udc, target))
+ status |= __constant_cpu_to_le16(1);
+ } else
+ goto delegate;
+
+ /* Write directly to the FIFO. No queueing is done. */
+ if (crq->wLength != __constant_cpu_to_le16(sizeof(status)))
+ goto stall;
+ ep->state = DATA_STAGE_IN;
+ __raw_writew(status, ep->fifo);
+ usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+ break;
+ }
+
+ case USB_REQ_CLEAR_FEATURE: {
+ if (crq->bRequestType == USB_RECIP_DEVICE) {
+ if (feature_is_dev_remote_wakeup(crq))
+ udc->devstatus
+ &= ~(1 << USB_DEVICE_REMOTE_WAKEUP);
+ else
+ /* Can't CLEAR_FEATURE TEST_MODE */
+ goto stall;
+ } else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+ struct usba_ep *target;
+
+ if (crq->wLength != __constant_cpu_to_le16(0)
+ || !feature_is_ep_halt(crq))
+ goto stall;
+ target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+ if (!target)
+ goto stall;
+
+ usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL);
+ if (target->index != 0)
+ usba_ep_writel(target, CLR_STA,
+ USBA_TOGGLE_CLR);
+ } else {
+ goto delegate;
+ }
+
+ send_status(udc, ep);
+ break;
+ }
+
+ case USB_REQ_SET_FEATURE: {
+ if (crq->bRequestType == USB_RECIP_DEVICE) {
+ if (feature_is_dev_test_mode(crq)) {
+ send_status(udc, ep);
+ ep->state = STATUS_STAGE_TEST;
+ udc->test_mode = le16_to_cpu(crq->wIndex);
+ return 0;
+ } else if (feature_is_dev_remote_wakeup(crq)) {
+ udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP;
+ } else {
+ goto stall;
+ }
+ } else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+ struct usba_ep *target;
+
+ if (crq->wLength != __constant_cpu_to_le16(0)
+ || !feature_is_ep_halt(crq))
+ goto stall;
+
+ target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+ if (!target)
+ goto stall;
+
+ usba_ep_writel(target, SET_STA, USBA_FORCE_STALL);
+ } else
+ goto delegate;
+
+ send_status(udc, ep);
+ break;
+ }
+
+ case USB_REQ_SET_ADDRESS:
+ if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+ goto delegate;
+
+ set_address(udc, le16_to_cpu(crq->wValue));
+ send_status(udc, ep);
+ ep->state = STATUS_STAGE_ADDR;
+ break;
+
+ default:
+delegate:
+ spin_unlock(&udc->lock);
+ retval = udc->driver->setup(&udc->gadget, crq);
+ spin_lock(&udc->lock);
+ }
+
+ return retval;
+
+stall:
+ printk(KERN_ERR
+ "udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
+ "halting endpoint...\n",
+ ep->ep.name, crq->bRequestType, crq->bRequest,
+ le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
+ le16_to_cpu(crq->wLength));
+ set_protocol_stall(udc, ep);
+ return -1;
+}
+
+static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+ struct usba_request *req;
+ u32 epstatus;
+ u32 epctrl;
+
+restart:
+ epstatus = usba_ep_readl(ep, STA);
+ epctrl = usba_ep_readl(ep, CTL);
+
+ DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n",
+ ep->ep.name, ep->state, epstatus, epctrl);
+
+ req = NULL;
+ if (!list_empty(&ep->queue))
+ req = list_entry(ep->queue.next,
+ struct usba_request, queue);
+
+ if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+ if (req->submitted)
+ next_fifo_transaction(ep, req);
+ else
+ submit_request(ep, req);
+
+ if (req->last_transaction) {
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+ usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+ }
+ goto restart;
+ }
+ if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
+ usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);
+
+ switch (ep->state) {
+ case DATA_STAGE_IN:
+ usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ ep->state = STATUS_STAGE_OUT;
+ break;
+ case STATUS_STAGE_ADDR:
+ /* Activate our new address */
+ usba_writel(udc, CTRL, (usba_readl(udc, CTRL)
+ | USBA_FADDR_EN));
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ ep->state = WAIT_FOR_SETUP;
+ break;
+ case STATUS_STAGE_IN:
+ if (req) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, 0);
+ submit_next_request(ep);
+ }
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ ep->state = WAIT_FOR_SETUP;
+ break;
+ case STATUS_STAGE_TEST:
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+ ep->state = WAIT_FOR_SETUP;
+ if (do_test_mode(udc))
+ set_protocol_stall(udc, ep);
+ break;
+ default:
+ printk(KERN_ERR
+ "udc: %s: TXCOMP: Invalid endpoint state %d, "
+ "halting endpoint...\n",
+ ep->ep.name, ep->state);
+ set_protocol_stall(udc, ep);
+ break;
+ }
+
+ goto restart;
+ }
+ if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+ switch (ep->state) {
+ case STATUS_STAGE_OUT:
+ usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+
+ if (req) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, 0);
+ }
+ ep->state = WAIT_FOR_SETUP;
+ break;
+
+ case DATA_STAGE_OUT:
+ receive_data(ep);
+ break;
+
+ default:
+ usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+ printk(KERN_ERR
+ "udc: %s: RXRDY: Invalid endpoint state %d, "
+ "halting endpoint...\n",
+ ep->ep.name, ep->state);
+ set_protocol_stall(udc, ep);
+ break;
+ }
+
+ goto restart;
+ }
+ if (epstatus & USBA_RX_SETUP) {
+ union {
+ struct usb_ctrlrequest crq;
+ unsigned long data[2];
+ } crq;
+ unsigned int pkt_len;
+ int ret;
+
+ if (ep->state != WAIT_FOR_SETUP) {
+ /*
+ * Didn't expect a SETUP packet at this
+ * point. Clean up any pending requests (which
+ * may be successful).
+ */
+ int status = -EPROTO;
+
+ /*
+ * RXRDY and TXCOMP are dropped when SETUP
+ * packets arrive. Just pretend we received
+ * the status packet.
+ */
+ if (ep->state == STATUS_STAGE_OUT
+ || ep->state == STATUS_STAGE_IN) {
+ usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+ status = 0;
+ }
+
+ if (req) {
+ list_del_init(&req->queue);
+ request_complete(ep, req, status);
+ }
+ }
+
+ pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+ DBG(DBG_HW, "Packet length: %u\n", pkt_len);
+ if (pkt_len != sizeof(crq)) {
+ printk(KERN_WARNING "udc: Invalid packet length %u "
+ "(expected %lu)\n", pkt_len, sizeof(crq));
+ set_protocol_stall(udc, ep);
+ return;
+ }
+
+ DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo);
+ copy_from_fifo(crq.data, ep->fifo, sizeof(crq));
+
+ /* Free up one bank in the FIFO so that we can
+ * generate or receive a reply right away. */
+ usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);
+
+ /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n",
+ ep->state, crq.crq.bRequestType,
+ crq.crq.bRequest); */
+
+ if (crq.crq.bRequestType & USB_DIR_IN) {
+ /*
+ * The USB 2.0 spec states that "if wLength is
+ * zero, there is no data transfer phase."
+ * However, testusb #14 seems to actually
+ * expect a data phase even if wLength = 0...
+ */
+ ep->state = DATA_STAGE_IN;
+ } else {
+ if (crq.crq.wLength != __constant_cpu_to_le16(0))
+ ep->state = DATA_STAGE_OUT;
+ else
+ ep->state = STATUS_STAGE_IN;
+ }
+
+ ret = -1;
+ if (ep->index == 0)
+ ret = handle_ep0_setup(udc, ep, &crq.crq);
+ else {
+ spin_unlock(&udc->lock);
+ ret = udc->driver->setup(&udc->gadget, &crq.crq);
+ spin_lock(&udc->lock);
+ }
+
+ DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n",
+ crq.crq.bRequestType, crq.crq.bRequest,
+ le16_to_cpu(crq.crq.wLength), ep->state, ret);
+
+ if (ret < 0) {
+ /* Let the host know that we failed */
+ set_protocol_stall(udc, ep);
+ }
+ }
+}
+
+static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+ struct usba_request *req;
+ u32 epstatus;
+ u32 epctrl;
+
+ epstatus = usba_ep_readl(ep, STA);
+ epctrl = usba_ep_readl(ep, CTL);
+
+ DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus);
+
+ while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+ DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name);
+
+ if (list_empty(&ep->queue)) {
+ dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n");
+ usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+ return;
+ }
+
+ req = list_entry(ep->queue.next, struct usba_request, queue);
+
+ if (req->using_dma) {
+ /* Send a zero-length packet */
+ usba_ep_writel(ep, SET_STA,
+ USBA_TX_PK_RDY);
+ usba_ep_writel(ep, CTL_DIS,
+ USBA_TX_PK_RDY);
+ list_del_init(&req->queue);
+ submit_next_request(ep);
+ request_complete(ep, req, 0);
+ } else {
+ if (req->submitted)
+ next_fifo_transaction(ep, req);
+ else
+ submit_request(ep, req);
+
+ if (req->last_transaction) {
+ list_del_init(&req->queue);
+ submit_next_request(ep);
+ request_complete(ep, req, 0);
+ }
+ }
+
+ epstatus = usba_ep_readl(ep, STA);
+ epctrl = usba_ep_readl(ep, CTL);
+ }
+ if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+ DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name);
+ receive_data(ep);
+ usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+ }
+}
+
+static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+ struct usba_request *req;
+ u32 status, control, pending;
+
+ status = usba_dma_readl(ep, STATUS);
+ control = usba_dma_readl(ep, CONTROL);
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ ep->last_dma_status = status;
+#endif
+ pending = status & control;
+ DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control);
+
+ if (status & USBA_DMA_CH_EN) {
+ dev_err(&udc->pdev->dev,
+ "DMA_CH_EN is set after transfer is finished!\n");
+ dev_err(&udc->pdev->dev,
+ "status=%#08x, pending=%#08x, control=%#08x\n",
+ status, pending, control);
+
+ /*
+ * try to pretend nothing happened. We might have to
+ * do something here...
+ */
+ }
+
+ if (list_empty(&ep->queue))
+ /* Might happen if a reset comes along at the right moment */
+ return;
+
+ if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) {
+ req = list_entry(ep->queue.next, struct usba_request, queue);
+ usba_update_req(ep, req, status);
+
+ list_del_init(&req->queue);
+ submit_next_request(ep);
+ request_complete(ep, req, 0);
+ }
+}
+
+static irqreturn_t usba_udc_irq(int irq, void *devid)
+{
+ struct usba_udc *udc = devid;
+ u32 status;
+ u32 dma_status;
+ u32 ep_status;
+
+ spin_lock(&udc->lock);
+
+ status = usba_readl(udc, INT_STA);
+ DBG(DBG_INT, "irq, status=%#08x\n", status);
+
+ if (status & USBA_DET_SUSPEND) {
+ usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+ DBG(DBG_BUS, "Suspend detected\n");
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN
+ && udc->driver && udc->driver->suspend) {
+ spin_unlock(&udc->lock);
+ udc->driver->suspend(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+ }
+
+ if (status & USBA_WAKE_UP) {
+ usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+ DBG(DBG_BUS, "Wake Up CPU detected\n");
+ }
+
+ if (status & USBA_END_OF_RESUME) {
+ usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+ DBG(DBG_BUS, "Resume detected\n");
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN
+ && udc->driver && udc->driver->resume) {
+ spin_unlock(&udc->lock);
+ udc->driver->resume(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+ }
+
+ dma_status = USBA_BFEXT(DMA_INT, status);
+ if (dma_status) {
+ int i;
+
+ for (i = 1; i < USBA_NR_ENDPOINTS; i++)
+ if (dma_status & (1 << i))
+ usba_dma_irq(udc, &usba_ep[i]);
+ }
+
+ ep_status = USBA_BFEXT(EPT_INT, status);
+ if (ep_status) {
+ int i;
+
+ for (i = 0; i < USBA_NR_ENDPOINTS; i++)
+ if (ep_status & (1 << i)) {
+ if (ep_is_control(&usba_ep[i]))
+ usba_control_irq(udc, &usba_ep[i]);
+ else
+ usba_ep_irq(udc, &usba_ep[i]);
+ }
+ }
+
+ if (status & USBA_END_OF_RESET) {
+ struct usba_ep *ep0;
+
+ usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+ reset_all_endpoints(udc);
+
+ if (status & USBA_HIGH_SPEED) {
+ DBG(DBG_BUS, "High-speed bus reset detected\n");
+ udc->gadget.speed = USB_SPEED_HIGH;
+ } else {
+ DBG(DBG_BUS, "Full-speed bus reset detected\n");
+ udc->gadget.speed = USB_SPEED_FULL;
+ }
+
+ ep0 = &usba_ep[0];
+ ep0->desc = &usba_ep0_desc;
+ ep0->state = WAIT_FOR_SETUP;
+ usba_ep_writel(ep0, CFG,
+ (USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
+ | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL)
+ | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
+ usba_ep_writel(ep0, CTL_ENB,
+ USBA_EPT_ENABLE | USBA_RX_SETUP);
+ usba_writel(udc, INT_ENB,
+ (usba_readl(udc, INT_ENB)
+ | USBA_BF(EPT_INT, 1)
+ | USBA_DET_SUSPEND
+ | USBA_END_OF_RESUME));
+
+ if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
+ dev_warn(&udc->pdev->dev,
+ "WARNING: EP0 configuration is invalid!\n");
+ }
+
+ spin_unlock(&udc->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t usba_vbus_irq(int irq, void *devid)
+{
+ struct usba_udc *udc = devid;
+ int vbus;
+
+ /* debounce */
+ udelay(10);
+
+ spin_lock(&udc->lock);
+
+ /* May happen if Vbus pin toggles during probe() */
+ if (!udc->driver)
+ goto out;
+
+ vbus = gpio_get_value(udc->vbus_pin);
+ if (vbus != udc->vbus_prev) {
+ if (vbus) {
+ usba_writel(udc, CTRL, USBA_EN_USBA);
+ usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+ } else {
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ reset_all_endpoints(udc);
+ usba_writel(udc, CTRL, 0);
+ spin_unlock(&udc->lock);
+ udc->driver->disconnect(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+ udc->vbus_prev = vbus;
+ }
+
+out:
+ spin_unlock(&udc->lock);
+
+ return IRQ_HANDLED;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct usba_udc *udc = &the_udc;
+ unsigned long flags;
+ int ret;
+
+ if (!udc->pdev)
+ return -ENODEV;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (udc->driver) {
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return -EBUSY;
+ }
+
+ udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ clk_enable(udc->pclk);
+ clk_enable(udc->hclk);
+
+ ret = driver->bind(&udc->gadget);
+ if (ret) {
+ DBG(DBG_ERR, "Could not bind to driver %s: error %d\n",
+ driver->driver.name, ret);
+ goto err_driver_bind;
+ }
+
+ DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
+
+ udc->vbus_prev = 0;
+ if (udc->vbus_pin != -1)
+ enable_irq(gpio_to_irq(udc->vbus_pin));
+
+ /* If Vbus is present, enable the controller and wait for reset */
+ spin_lock_irqsave(&udc->lock, flags);
+ if (vbus_is_present(udc) && udc->vbus_prev == 0) {
+ usba_writel(udc, CTRL, USBA_EN_USBA);
+ usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+
+err_driver_bind:
+ udc->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ return ret;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct usba_udc *udc = &the_udc;
+ unsigned long flags;
+
+ if (!udc->pdev)
+ return -ENODEV;
+ if (driver != udc->driver)
+ return -EINVAL;
+
+ if (udc->vbus_pin != -1)
+ disable_irq(gpio_to_irq(udc->vbus_pin));
+
+ spin_lock_irqsave(&udc->lock, flags);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ reset_all_endpoints(udc);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ /* This will also disable the DP pullup */
+ usba_writel(udc, CTRL, 0);
+
+ driver->unbind(&udc->gadget);
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
+
+ clk_disable(udc->hclk);
+ clk_disable(udc->pclk);
+
+ DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static int __init usba_udc_probe(struct platform_device *pdev)
+{
+ struct usba_platform_data *pdata = pdev->dev.platform_data;
+ struct resource *regs, *fifo;
+ struct clk *pclk, *hclk;
+ struct usba_udc *udc = &the_udc;
+ int irq, ret, i;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
+ fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
+ if (!regs || !fifo)
+ return -ENXIO;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ pclk = clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(pclk))
+ return PTR_ERR(pclk);
+ hclk = clk_get(&pdev->dev, "hclk");
+ if (IS_ERR(hclk)) {
+ ret = PTR_ERR(hclk);
+ goto err_get_hclk;
+ }
+
+ udc->pdev = pdev;
+ udc->pclk = pclk;
+ udc->hclk = hclk;
+ udc->vbus_pin = -1;
+
+ ret = -ENOMEM;
+ udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!udc->regs) {
+ dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
+ goto err_map_regs;
+ }
+ dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
+ (unsigned long)regs->start, udc->regs);
+ udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1);
+ if (!udc->fifo) {
+ dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
+ goto err_map_fifo;
+ }
+ dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
+ (unsigned long)fifo->start, udc->fifo);
+
+ device_initialize(&udc->gadget.dev);
+ udc->gadget.dev.parent = &pdev->dev;
+ udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+ platform_set_drvdata(pdev, udc);
+
+ /* Make sure we start from a clean slate */
+ clk_enable(pclk);
+ usba_writel(udc, CTRL, 0);
+ clk_disable(pclk);
+
+ INIT_LIST_HEAD(&usba_ep[0].ep.ep_list);
+ usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
+ usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
+ usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
+ for (i = 1; i < ARRAY_SIZE(usba_ep); i++) {
+ struct usba_ep *ep = &usba_ep[i];
+
+ ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+ ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+ ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+ }
+
+ ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n",
+ irq, ret);
+ goto err_request_irq;
+ }
+ udc->irq = irq;
+
+ ret = device_add(&udc->gadget.dev);
+ if (ret) {
+ dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
+ goto err_device_add;
+ }
+
+ if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) {
+ if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
+ udc->vbus_pin = pdata->vbus_pin;
+
+ ret = request_irq(gpio_to_irq(udc->vbus_pin),
+ usba_vbus_irq, 0,
+ "atmel_usba_udc", udc);
+ if (ret) {
+ gpio_free(udc->vbus_pin);
+ udc->vbus_pin = -1;
+ dev_warn(&udc->pdev->dev,
+ "failed to request vbus irq; "
+ "assuming always on\n");
+ } else {
+ disable_irq(gpio_to_irq(udc->vbus_pin));
+ }
+ }
+ }
+
+ usba_init_debugfs(udc);
+ for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+ usba_ep_init_debugfs(udc, &usba_ep[i]);
+
+ return 0;
+
+err_device_add:
+ free_irq(irq, udc);
+err_request_irq:
+ iounmap(udc->fifo);
+err_map_fifo:
+ iounmap(udc->regs);
+err_map_regs:
+ clk_put(hclk);
+err_get_hclk:
+ clk_put(pclk);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return ret;
+}
+
+static int __exit usba_udc_remove(struct platform_device *pdev)
+{
+ struct usba_udc *udc;
+ int i;
+
+ udc = platform_get_drvdata(pdev);
+
+ for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+ usba_ep_cleanup_debugfs(&usba_ep[i]);
+ usba_cleanup_debugfs(udc);
+
+ if (udc->vbus_pin != -1)
+ gpio_free(udc->vbus_pin);
+
+ free_irq(udc->irq, udc);
+ iounmap(udc->fifo);
+ iounmap(udc->regs);
+ clk_put(udc->hclk);
+ clk_put(udc->pclk);
+
+ device_unregister(&udc->gadget.dev);
+
+ return 0;
+}
+
+static struct platform_driver udc_driver = {
+ .remove = __exit_p(usba_udc_remove),
+ .driver = {
+ .name = "atmel_usba_udc",
+ },
+};
+
+static int __init udc_init(void)
+{
+ return platform_driver_probe(&udc_driver, usba_udc_probe);
+}
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION("Atmel USBA UDC driver");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
new file mode 100644
index 00000000000..a68304e31a6
--- /dev/null
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -0,0 +1,352 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_USB_GADGET_USBA_UDC_H__
+#define __LINUX_USB_GADGET_USBA_UDC_H__
+
+/* USB register offsets */
+#define USBA_CTRL 0x0000
+#define USBA_FNUM 0x0004
+#define USBA_INT_ENB 0x0010
+#define USBA_INT_STA 0x0014
+#define USBA_INT_CLR 0x0018
+#define USBA_EPT_RST 0x001c
+#define USBA_TST 0x00e0
+
+/* USB endpoint register offsets */
+#define USBA_EPT_CFG 0x0000
+#define USBA_EPT_CTL_ENB 0x0004
+#define USBA_EPT_CTL_DIS 0x0008
+#define USBA_EPT_CTL 0x000c
+#define USBA_EPT_SET_STA 0x0014
+#define USBA_EPT_CLR_STA 0x0018
+#define USBA_EPT_STA 0x001c
+
+/* USB DMA register offsets */
+#define USBA_DMA_NXT_DSC 0x0000
+#define USBA_DMA_ADDRESS 0x0004
+#define USBA_DMA_CONTROL 0x0008
+#define USBA_DMA_STATUS 0x000c
+
+/* Bitfields in CTRL */
+#define USBA_DEV_ADDR_OFFSET 0
+#define USBA_DEV_ADDR_SIZE 7
+#define USBA_FADDR_EN (1 << 7)
+#define USBA_EN_USBA (1 << 8)
+#define USBA_DETACH (1 << 9)
+#define USBA_REMOTE_WAKE_UP (1 << 10)
+
+/* Bitfields in FNUM */
+#define USBA_MICRO_FRAME_NUM_OFFSET 0
+#define USBA_MICRO_FRAME_NUM_SIZE 3
+#define USBA_FRAME_NUMBER_OFFSET 3
+#define USBA_FRAME_NUMBER_SIZE 11
+#define USBA_FRAME_NUM_ERROR (1 << 31)
+
+/* Bitfields in INT_ENB/INT_STA/INT_CLR */
+#define USBA_HIGH_SPEED (1 << 0)
+#define USBA_DET_SUSPEND (1 << 1)
+#define USBA_MICRO_SOF (1 << 2)
+#define USBA_SOF (1 << 3)
+#define USBA_END_OF_RESET (1 << 4)
+#define USBA_WAKE_UP (1 << 5)
+#define USBA_END_OF_RESUME (1 << 6)
+#define USBA_UPSTREAM_RESUME (1 << 7)
+#define USBA_EPT_INT_OFFSET 8
+#define USBA_EPT_INT_SIZE 16
+#define USBA_DMA_INT_OFFSET 24
+#define USBA_DMA_INT_SIZE 8
+
+/* Bitfields in EPT_RST */
+#define USBA_RST_OFFSET 0
+#define USBA_RST_SIZE 16
+
+/* Bitfields in USBA_TST */
+#define USBA_SPEED_CFG_OFFSET 0
+#define USBA_SPEED_CFG_SIZE 2
+#define USBA_TST_J_MODE (1 << 2)
+#define USBA_TST_K_MODE (1 << 3)
+#define USBA_TST_PKT_MODE (1 << 4)
+#define USBA_OPMODE2 (1 << 5)
+
+/* Bitfields in EPT_CFG */
+#define USBA_EPT_SIZE_OFFSET 0
+#define USBA_EPT_SIZE_SIZE 3
+#define USBA_EPT_DIR_IN (1 << 3)
+#define USBA_EPT_TYPE_OFFSET 4
+#define USBA_EPT_TYPE_SIZE 2
+#define USBA_BK_NUMBER_OFFSET 6
+#define USBA_BK_NUMBER_SIZE 2
+#define USBA_NB_TRANS_OFFSET 8
+#define USBA_NB_TRANS_SIZE 2
+#define USBA_EPT_MAPPED (1 << 31)
+
+/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */
+#define USBA_EPT_ENABLE (1 << 0)
+#define USBA_AUTO_VALID (1 << 1)
+#define USBA_INTDIS_DMA (1 << 3)
+#define USBA_NYET_DIS (1 << 4)
+#define USBA_DATAX_RX (1 << 6)
+#define USBA_MDATA_RX (1 << 7)
+/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */
+#define USBA_BUSY_BANK_IE (1 << 18)
+
+/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */
+#define USBA_FORCE_STALL (1 << 5)
+#define USBA_TOGGLE_CLR (1 << 6)
+#define USBA_TOGGLE_SEQ_OFFSET 6
+#define USBA_TOGGLE_SEQ_SIZE 2
+#define USBA_ERR_OVFLW (1 << 8)
+#define USBA_RX_BK_RDY (1 << 9)
+#define USBA_KILL_BANK (1 << 9)
+#define USBA_TX_COMPLETE (1 << 10)
+#define USBA_TX_PK_RDY (1 << 11)
+#define USBA_ISO_ERR_TRANS (1 << 11)
+#define USBA_RX_SETUP (1 << 12)
+#define USBA_ISO_ERR_FLOW (1 << 12)
+#define USBA_STALL_SENT (1 << 13)
+#define USBA_ISO_ERR_CRC (1 << 13)
+#define USBA_ISO_ERR_NBTRANS (1 << 13)
+#define USBA_NAK_IN (1 << 14)
+#define USBA_ISO_ERR_FLUSH (1 << 14)
+#define USBA_NAK_OUT (1 << 15)
+#define USBA_CURRENT_BANK_OFFSET 16
+#define USBA_CURRENT_BANK_SIZE 2
+#define USBA_BUSY_BANKS_OFFSET 18
+#define USBA_BUSY_BANKS_SIZE 2
+#define USBA_BYTE_COUNT_OFFSET 20
+#define USBA_BYTE_COUNT_SIZE 11
+#define USBA_SHORT_PACKET (1 << 31)
+
+/* Bitfields in DMA_CONTROL */
+#define USBA_DMA_CH_EN (1 << 0)
+#define USBA_DMA_LINK (1 << 1)
+#define USBA_DMA_END_TR_EN (1 << 2)
+#define USBA_DMA_END_BUF_EN (1 << 3)
+#define USBA_DMA_END_TR_IE (1 << 4)
+#define USBA_DMA_END_BUF_IE (1 << 5)
+#define USBA_DMA_DESC_LOAD_IE (1 << 6)
+#define USBA_DMA_BURST_LOCK (1 << 7)
+#define USBA_DMA_BUF_LEN_OFFSET 16
+#define USBA_DMA_BUF_LEN_SIZE 16
+
+/* Bitfields in DMA_STATUS */
+#define USBA_DMA_CH_ACTIVE (1 << 1)
+#define USBA_DMA_END_TR_ST (1 << 4)
+#define USBA_DMA_END_BUF_ST (1 << 5)
+#define USBA_DMA_DESC_LOAD_ST (1 << 6)
+
+/* Constants for SPEED_CFG */
+#define USBA_SPEED_CFG_NORMAL 0
+#define USBA_SPEED_CFG_FORCE_HIGH 2
+#define USBA_SPEED_CFG_FORCE_FULL 3
+
+/* Constants for EPT_SIZE */
+#define USBA_EPT_SIZE_8 0
+#define USBA_EPT_SIZE_16 1
+#define USBA_EPT_SIZE_32 2
+#define USBA_EPT_SIZE_64 3
+#define USBA_EPT_SIZE_128 4
+#define USBA_EPT_SIZE_256 5
+#define USBA_EPT_SIZE_512 6
+#define USBA_EPT_SIZE_1024 7
+
+/* Constants for EPT_TYPE */
+#define USBA_EPT_TYPE_CONTROL 0
+#define USBA_EPT_TYPE_ISO 1
+#define USBA_EPT_TYPE_BULK 2
+#define USBA_EPT_TYPE_INT 3
+
+/* Constants for BK_NUMBER */
+#define USBA_BK_NUMBER_ZERO 0
+#define USBA_BK_NUMBER_ONE 1
+#define USBA_BK_NUMBER_DOUBLE 2
+#define USBA_BK_NUMBER_TRIPLE 3
+
+/* Bit manipulation macros */
+#define USBA_BF(name, value) \
+ (((value) & ((1 << USBA_##name##_SIZE) - 1)) \
+ << USBA_##name##_OFFSET)
+#define USBA_BFEXT(name, value) \
+ (((value) >> USBA_##name##_OFFSET) \
+ & ((1 << USBA_##name##_SIZE) - 1))
+#define USBA_BFINS(name, value, old) \
+ (((old) & ~(((1 << USBA_##name##_SIZE) - 1) \
+ << USBA_##name##_OFFSET)) \
+ | USBA_BF(name, value))
+
+/* Register access macros */
+#define usba_readl(udc, reg) \
+ __raw_readl((udc)->regs + USBA_##reg)
+#define usba_writel(udc, reg, value) \
+ __raw_writel((value), (udc)->regs + USBA_##reg)
+#define usba_ep_readl(ep, reg) \
+ __raw_readl((ep)->ep_regs + USBA_EPT_##reg)
+#define usba_ep_writel(ep, reg, value) \
+ __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
+#define usba_dma_readl(ep, reg) \
+ __raw_readl((ep)->dma_regs + USBA_DMA_##reg)
+#define usba_dma_writel(ep, reg, value) \
+ __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
+
+/* Calculate base address for a given endpoint or DMA controller */
+#define USBA_EPT_BASE(x) (0x100 + (x) * 0x20)
+#define USBA_DMA_BASE(x) (0x300 + (x) * 0x10)
+#define USBA_FIFO_BASE(x) ((x) << 16)
+
+/* Synth parameters */
+#define USBA_NR_ENDPOINTS 7
+
+#define EP0_FIFO_SIZE 64
+#define EP0_EPT_SIZE USBA_EPT_SIZE_64
+#define EP0_NR_BANKS 1
+
+/*
+ * REVISIT: Try to eliminate this value. Can we rely on req->mapped to
+ * provide this information?
+ */
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#define FIFO_IOMEM_ID 0
+#define CTRL_IOMEM_ID 1
+
+#ifdef DEBUG
+#define DBG_ERR 0x0001 /* report all error returns */
+#define DBG_HW 0x0002 /* debug hardware initialization */
+#define DBG_GADGET 0x0004 /* calls to/from gadget driver */
+#define DBG_INT 0x0008 /* interrupts */
+#define DBG_BUS 0x0010 /* report changes in bus state */
+#define DBG_QUEUE 0x0020 /* debug request queue processing */
+#define DBG_FIFO 0x0040 /* debug FIFO contents */
+#define DBG_DMA 0x0080 /* debug DMA handling */
+#define DBG_REQ 0x0100 /* print out queued request length */
+#define DBG_ALL 0xffff
+#define DBG_NONE 0x0000
+
+#define DEBUG_LEVEL (DBG_ERR)
+#define DBG(level, fmt, ...) \
+ do { \
+ if ((level) & DEBUG_LEVEL) \
+ printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \
+ } while (0)
+#else
+#define DBG(level, fmt...)
+#endif
+
+enum usba_ctrl_state {
+ WAIT_FOR_SETUP,
+ DATA_STAGE_IN,
+ DATA_STAGE_OUT,
+ STATUS_STAGE_IN,
+ STATUS_STAGE_OUT,
+ STATUS_STAGE_ADDR,
+ STATUS_STAGE_TEST,
+};
+/*
+ EP_STATE_IDLE,
+ EP_STATE_SETUP,
+ EP_STATE_IN_DATA,
+ EP_STATE_OUT_DATA,
+ EP_STATE_SET_ADDR_STATUS,
+ EP_STATE_RX_STATUS,
+ EP_STATE_TX_STATUS,
+ EP_STATE_HALT,
+*/
+
+struct usba_dma_desc {
+ dma_addr_t next;
+ dma_addr_t addr;
+ u32 ctrl;
+};
+
+struct usba_ep {
+ int state;
+ void __iomem *ep_regs;
+ void __iomem *dma_regs;
+ void __iomem *fifo;
+ struct usb_ep ep;
+ struct usba_udc *udc;
+
+ struct list_head queue;
+ const struct usb_endpoint_descriptor *desc;
+
+ u16 fifo_size;
+ u8 nr_banks;
+ u8 index;
+ unsigned int can_dma:1;
+ unsigned int can_isoc:1;
+ unsigned int is_isoc:1;
+ unsigned int is_in:1;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ u32 last_dma_status;
+ struct dentry *debugfs_dir;
+ struct dentry *debugfs_queue;
+ struct dentry *debugfs_dma_status;
+ struct dentry *debugfs_state;
+#endif
+};
+
+struct usba_request {
+ struct usb_request req;
+ struct list_head queue;
+
+ u32 ctrl;
+
+ unsigned int submitted:1;
+ unsigned int last_transaction:1;
+ unsigned int using_dma:1;
+ unsigned int mapped:1;
+};
+
+struct usba_udc {
+ /* Protect hw registers from concurrent modifications */
+ spinlock_t lock;
+
+ void __iomem *regs;
+ void __iomem *fifo;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct platform_device *pdev;
+ int irq;
+ int vbus_pin;
+ struct clk *pclk;
+ struct clk *hclk;
+
+ u16 devstatus;
+
+ u16 test_mode;
+ int vbus_prev;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ struct dentry *debugfs_root;
+ struct dentry *debugfs_regs;
+#endif
+};
+
+static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
+{
+ return container_of(ep, struct usba_ep, ep);
+}
+
+static inline struct usba_request *to_usba_req(struct usb_request *req)
+{
+ return container_of(req, struct usba_request, req);
+}
+
+static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget)
+{
+ return container_of(gadget, struct usba_udc, gadget);
+}
+
+#define ep_is_control(ep) ((ep)->index == 0)
+#define ep_is_idle(ep) ((ep)->state == EP_STATE_IDLE)
+
+#endif /* __LINUX_USB_GADGET_USBA_UDC_H */
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index c6760aee1e5..a4e54b2743f 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -25,7 +25,7 @@
#include <linux/device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
/**
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index d008d1360a7..9db2482bdfa 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -46,7 +46,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -962,13 +962,13 @@ static struct platform_driver dummy_udc_driver = {
static int dummy_urb_enqueue (
struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
struct dummy *dum;
struct urbp *urbp;
unsigned long flags;
+ int rc;
if (!urb->transfer_buffer && urb->transfer_buffer_length)
return -EINVAL;
@@ -980,6 +980,11 @@ static int dummy_urb_enqueue (
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
+ rc = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (rc) {
+ kfree(urbp);
+ goto done;
+ }
if (!dum->udev) {
dum->udev = urb->dev;
@@ -996,36 +1001,35 @@ static int dummy_urb_enqueue (
if (!timer_pending (&dum->timer))
mod_timer (&dum->timer, jiffies + 1);
- spin_unlock_irqrestore (&dum->lock, flags);
- return 0;
+ done:
+ spin_unlock_irqrestore(&dum->lock, flags);
+ return rc;
}
-static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct dummy *dum;
unsigned long flags;
+ int rc;
/* giveback happens automatically in timer callback,
* so make sure the callback happens */
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
- if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
+
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
+ !list_empty(&dum->urbp_list))
mod_timer (&dum->timer, jiffies);
- spin_unlock_irqrestore (&dum->lock, flags);
- return 0;
-}
-static void maybe_set_status (struct urb *urb, int status)
-{
- spin_lock (&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = status;
- spin_unlock (&urb->lock);
+ spin_unlock_irqrestore (&dum->lock, flags);
+ return rc;
}
/* transfer up to a frame's worth; caller must own lock */
static int
-transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
+transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
+ int *status)
{
struct dummy_request *req;
@@ -1088,24 +1092,20 @@ top:
*
* partially filling a buffer optionally blocks queue advances
* (so completion handlers can clean up the queue) but we don't
- * need to emulate such data-in-flight. so we only show part
- * of the URB_SHORT_NOT_OK effect: completion status.
+ * need to emulate such data-in-flight.
*/
if (is_short) {
if (host_len == dev_len) {
req->req.status = 0;
- maybe_set_status (urb, 0);
+ *status = 0;
} else if (to_host) {
req->req.status = 0;
if (dev_len > host_len)
- maybe_set_status (urb, -EOVERFLOW);
+ *status = -EOVERFLOW;
else
- maybe_set_status (urb,
- (urb->transfer_flags
- & URB_SHORT_NOT_OK)
- ? -EREMOTEIO : 0);
+ *status = 0;
} else if (!to_host) {
- maybe_set_status (urb, 0);
+ *status = 0;
if (host_len > dev_len)
req->req.status = -EOVERFLOW;
else
@@ -1119,9 +1119,8 @@ top:
req->req.status = 0;
if (urb->transfer_buffer_length == urb->actual_length
&& !(urb->transfer_flags
- & URB_ZERO_PACKET)) {
- maybe_set_status (urb, 0);
- }
+ & URB_ZERO_PACKET))
+ *status = 0;
}
/* device side completion --> continuable */
@@ -1137,7 +1136,7 @@ top:
}
/* host side completion --> terminate */
- if (urb->status != -EINPROGRESS)
+ if (*status != -EINPROGRESS)
break;
/* rescan to continue with any other queued i/o */
@@ -1248,12 +1247,12 @@ restart:
u8 address;
struct dummy_ep *ep = NULL;
int type;
+ int status = -EINPROGRESS;
urb = urbp->urb;
- if (urb->status != -EINPROGRESS) {
- /* likely it was just unlinked */
+ if (urb->unlinked)
goto return_urb;
- } else if (dum->rh_state != DUMMY_RH_RUNNING)
+ else if (dum->rh_state != DUMMY_RH_RUNNING)
continue;
type = usb_pipetype (urb->pipe);
@@ -1274,7 +1273,7 @@ restart:
dev_dbg (dummy_dev(dum),
"no ep configured for urb %p\n",
urb);
- maybe_set_status (urb, -EPROTO);
+ status = -EPROTO;
goto return_urb;
}
@@ -1289,7 +1288,7 @@ restart:
/* NOTE: must not be iso! */
dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
ep->ep.name, urb);
- maybe_set_status (urb, -EPIPE);
+ status = -EPIPE;
goto return_urb;
}
/* FIXME make sure both ends agree on maxpacket */
@@ -1307,7 +1306,7 @@ restart:
w_value = le16_to_cpu(setup.wValue);
if (le16_to_cpu(setup.wLength) !=
urb->transfer_buffer_length) {
- maybe_set_status (urb, -EOVERFLOW);
+ status = -EOVERFLOW;
goto return_urb;
}
@@ -1337,7 +1336,7 @@ restart:
if (setup.bRequestType != Dev_Request)
break;
dum->address = w_value;
- maybe_set_status (urb, 0);
+ status = 0;
dev_dbg (udc_dev(dum), "set_address = %d\n",
w_value);
value = 0;
@@ -1364,7 +1363,7 @@ restart:
if (value == 0) {
dum->devstatus |=
(1 << w_value);
- maybe_set_status (urb, 0);
+ status = 0;
}
} else if (setup.bRequestType == Ep_Request) {
@@ -1376,7 +1375,7 @@ restart:
}
ep2->halted = 1;
value = 0;
- maybe_set_status (urb, 0);
+ status = 0;
}
break;
case USB_REQ_CLEAR_FEATURE:
@@ -1386,7 +1385,7 @@ restart:
dum->devstatus &= ~(1 <<
USB_DEVICE_REMOTE_WAKEUP);
value = 0;
- maybe_set_status (urb, 0);
+ status = 0;
break;
default:
value = -EOPNOTSUPP;
@@ -1401,7 +1400,7 @@ restart:
}
ep2->halted = 0;
value = 0;
- maybe_set_status (urb, 0);
+ status = 0;
}
break;
case USB_REQ_GET_STATUS:
@@ -1438,7 +1437,7 @@ restart:
urb->actual_length = min (2,
urb->transfer_buffer_length);
value = 0;
- maybe_set_status (urb, 0);
+ status = 0;
}
break;
}
@@ -1465,7 +1464,7 @@ restart:
dev_dbg (udc_dev(dum),
"setup --> %d\n",
value);
- maybe_set_status (urb, -EPIPE);
+ status = -EPIPE;
urb->actual_length = 0;
}
@@ -1482,7 +1481,7 @@ restart:
* report random errors, to debug drivers.
*/
limit = max (limit, periodic_bytes (dum, ep));
- maybe_set_status (urb, -ENOSYS);
+ status = -ENOSYS;
break;
case PIPE_INTERRUPT:
@@ -1496,23 +1495,23 @@ restart:
default:
treat_control_like_bulk:
ep->last_io = jiffies;
- total = transfer (dum, urb, ep, limit);
+ total = transfer(dum, urb, ep, limit, &status);
break;
}
/* incomplete transfer? */
- if (urb->status == -EINPROGRESS)
+ if (status == -EINPROGRESS)
continue;
return_urb:
- urb->hcpriv = NULL;
list_del (&urbp->urbp_list);
kfree (urbp);
if (ep)
ep->already_seen = ep->setup_stage = 0;
+ usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
spin_unlock (&dum->lock);
- usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
+ usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
spin_lock (&dum->lock);
goto restart;
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 3aa46cfa66b..f9d07108bc3 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -28,7 +28,7 @@
#include <linux/string.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 593e23507b1..9e732bff9df 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -19,40 +19,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+/* #define VERBOSE_DEBUG */
-// #define DEBUG 1
-// #define VERBOSE
-
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
#include <linux/utsname.h>
#include <linux/device.h>
-#include <linux/moduleparam.h>
#include <linux/ctype.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
-
-#include <linux/random.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
@@ -356,15 +334,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR);
#define qlen(gadget) \
(DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
-/* also defer IRQs on highspeed TX */
-#define TX_DELAY qmult
-
static inline int BITRATE(struct usb_gadget *g)
{
return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
}
#else /* full speed (low speed doesn't do bulk) */
+
+#define qmult 1
+
#define DEVSPEED USB_SPEED_FULL
#define qlen(gadget) DEFAULT_QLEN
@@ -390,7 +368,7 @@ static inline int BITRATE(struct usb_gadget *g)
do { } while (0)
#endif /* DEBUG */
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
#define VDEBUG DEBUG
#else
#define VDEBUG(dev,fmt,args...) \
@@ -830,8 +808,6 @@ static const struct usb_descriptor_header *fs_rndis_function [] = {
};
#endif
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
/*
* usb 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@@ -934,18 +910,15 @@ static const struct usb_descriptor_header *hs_rndis_function [] = {
/* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
-
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) (((void)(g)), (fs))
-
-static inline void __init hs_subset_descriptors(void)
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *fs)
{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
}
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
/*-------------------------------------------------------------------------*/
@@ -989,22 +962,19 @@ static struct usb_gadget_strings stringtab = {
* complications: class descriptors, and an altsetting.
*/
static int
-config_buf (enum usb_device_speed speed,
- u8 *buf, u8 type,
- unsigned index, int is_otg)
+config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg)
{
int len;
const struct usb_config_descriptor *config;
const struct usb_descriptor_header **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- int hs = (speed == USB_SPEED_HIGH);
+ int hs = 0;
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- hs = !hs;
+ if (gadget_is_dualspeed(g)) {
+ hs = (g->speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
+ }
#define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function)
-#else
-#define which_fn(t) (fs_ ## t ## _function)
-#endif
if (index >= device_desc.bNumConfigurations)
return -EINVAL;
@@ -1217,7 +1187,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags)
if (number)
eth_reset_config (dev);
usb_gadget_vbus_draw(dev->gadget,
- dev->gadget->is_otg ? 8 : 100);
+ gadget_is_otg(dev->gadget) ? 8 : 100);
} else {
char *speed;
unsigned power;
@@ -1399,24 +1369,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min (wLength, (u16) sizeof device_desc);
memcpy (req->buf, &device_desc, value);
break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
value = min (wLength, (u16) sizeof dev_qualifier);
memcpy (req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
- value = config_buf (gadget->speed, req->buf,
+ value = config_buf(gadget, req->buf,
wValue >> 8,
wValue & 0xff,
- gadget->is_otg);
+ gadget_is_otg(gadget));
if (value >= 0)
value = min (wLength, (u16) value);
break;
@@ -1585,12 +1553,12 @@ done_set_intf:
&& rndis_control_intf.bInterfaceNumber
== wIndex) {
u8 *buf;
+ u32 n;
/* return the result */
- buf = rndis_get_next_response (dev->rndis_config,
- &value);
+ buf = rndis_get_next_response(dev->rndis_config, &n);
if (buf) {
- memcpy (req->buf, buf, value);
+ memcpy(req->buf, buf, n);
req->complete = rndis_response_complete;
rndis_free_response(dev->rndis_config, buf);
}
@@ -1989,8 +1957,20 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
}
spin_lock_irqsave(&dev->req_lock, flags);
+ /*
+ * this freelist can be empty if an interrupt triggered disconnect()
+ * and reconfigured the gadget (shutting down this queue) after the
+ * network stack decided to xmit but before we got the spinlock.
+ */
+ if (list_empty(&dev->tx_reqs)) {
+ spin_unlock_irqrestore(&dev->req_lock, flags);
+ return 1;
+ }
+
req = container_of (dev->tx_reqs.next, struct usb_request, list);
list_del (&req->list);
+
+ /* temporarily stop TX queue when the freelist empties */
if (list_empty (&dev->tx_reqs))
netif_stop_queue (net);
spin_unlock_irqrestore(&dev->req_lock, flags);
@@ -2026,12 +2006,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
req->length = length;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
/* throttle highspeed IRQ rate back slightly */
- req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
- ? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
- : 0;
-#endif
+ if (gadget_is_dualspeed(dev->gadget))
+ req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+ ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+ : 0;
retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
switch (retval) {
@@ -2188,8 +2167,7 @@ static int eth_stop (struct net_device *net)
}
if (rndis_active(dev)) {
- rndis_set_param_medium (dev->rndis_config,
- NDIS_MEDIUM_802_3, 0);
+ rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0);
(void) rndis_signal_disconnect (dev->rndis_config);
}
@@ -2443,26 +2421,28 @@ autoconf_fail:
if (rndis)
device_desc.bNumConfigurations = 2;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (rndis)
- dev_qualifier.bNumConfigurations = 2;
- else if (!cdc)
- dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+ if (gadget_is_dualspeed(gadget)) {
+ if (rndis)
+ dev_qualifier.bNumConfigurations = 2;
+ else if (!cdc)
+ dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
- /* assumes ep0 uses the same value for both speeds ... */
- dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+ /* assumes ep0 uses the same value for both speeds ... */
+ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
- /* and that all endpoints are dual-speed */
- hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
- hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
+ /* and that all endpoints are dual-speed */
+ hs_source_desc.bEndpointAddress =
+ fs_source_desc.bEndpointAddress;
+ hs_sink_desc.bEndpointAddress =
+ fs_sink_desc.bEndpointAddress;
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
- if (status_ep)
- hs_status_desc.bEndpointAddress =
- fs_status_desc.bEndpointAddress;
+ if (status_ep)
+ hs_status_desc.bEndpointAddress =
+ fs_status_desc.bEndpointAddress;
#endif
-#endif /* DUALSPEED */
+ }
- if (gadget->is_otg) {
+ if (gadget_is_otg(gadget)) {
otg_descriptor.bmAttributes |= USB_OTG_HNP,
eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
eth_config.bMaxPower = 4;
@@ -2484,7 +2464,6 @@ autoconf_fail:
/* network device setup */
dev->net = net;
- SET_MODULE_OWNER (net);
strcpy (net->name, "usb%d");
dev->cdc = cdc;
dev->zlp = zlp;
@@ -2599,12 +2578,11 @@ fail0:
if (rndis_set_param_dev (dev->rndis_config, dev->net,
&dev->stats, &dev->cdc_filter))
goto fail0;
- if (rndis_set_param_vendor (dev->rndis_config, vendorID,
- manufacturer))
+ if (rndis_set_param_vendor(dev->rndis_config, vendorID,
+ manufacturer))
goto fail0;
- if (rndis_set_param_medium (dev->rndis_config,
- NDIS_MEDIUM_802_3,
- 0))
+ if (rndis_set_param_medium(dev->rndis_config,
+ NDIS_MEDIUM_802_3, 0))
goto fail0;
INFO (dev, "RNDIS ready\n");
}
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 965ad7bec7b..1d174dcb3ac 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1,7 +1,7 @@
/*
* file_storage.c -- File-backed USB Storage Gadget, for USB development
*
- * Copyright (C) 2003-2005 Alan Stern
+ * Copyright (C) 2003-2007 Alan Stern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -217,17 +217,11 @@
*/
-#undef DEBUG
-#undef VERBOSE
-#undef DUMP_MSGS
-
+/* #define VERBOSE_DEBUG */
+/* #define DUMP_MSGS */
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <linux/bitops.h>
#include <linux/blkdev.h>
-#include <linux/compiler.h>
#include <linux/completion.h>
#include <linux/dcache.h>
#include <linux/delay.h>
@@ -235,18 +229,10 @@
#include <linux/fcntl.h>
#include <linux/file.h>
#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/kthread.h>
#include <linux/limits.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pagemap.h>
#include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@@ -254,7 +240,7 @@
#include <linux/utsname.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
@@ -263,7 +249,7 @@
#define DRIVER_DESC "File-backed Storage Gadget"
#define DRIVER_NAME "g_file_storage"
-#define DRIVER_VERSION "28 November 2005"
+#define DRIVER_VERSION "7 August 2007"
static const char longname[] = DRIVER_DESC;
static const char shortname[] = DRIVER_NAME;
@@ -289,57 +275,48 @@ MODULE_LICENSE("Dual BSD/GPL");
/*-------------------------------------------------------------------------*/
-#define xprintk(f,level,fmt,args...) \
- dev_printk(level , &(f)->gadget->dev , fmt , ## args)
-#define yprintk(l,level,fmt,args...) \
- dev_printk(level , &(l)->dev , fmt , ## args)
-
#ifdef DEBUG
-#define DBG(fsg,fmt,args...) \
- xprintk(fsg , KERN_DEBUG , fmt , ## args)
#define LDBG(lun,fmt,args...) \
- yprintk(lun , KERN_DEBUG , fmt , ## args)
+ dev_dbg(&(lun)->dev , fmt , ## args)
#define MDBG(fmt,args...) \
printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
#else
-#define DBG(fsg,fmt,args...) \
- do { } while (0)
#define LDBG(lun,fmt,args...) \
do { } while (0)
#define MDBG(fmt,args...) \
do { } while (0)
-#undef VERBOSE
+#undef VERBOSE_DEBUG
#undef DUMP_MSGS
#endif /* DEBUG */
-#ifdef VERBOSE
-#define VDBG DBG
+#ifdef VERBOSE_DEBUG
#define VLDBG LDBG
#else
-#define VDBG(fsg,fmt,args...) \
- do { } while (0)
#define VLDBG(lun,fmt,args...) \
do { } while (0)
-#endif /* VERBOSE */
+#endif /* VERBOSE_DEBUG */
-#define ERROR(fsg,fmt,args...) \
- xprintk(fsg , KERN_ERR , fmt , ## args)
#define LERROR(lun,fmt,args...) \
- yprintk(lun , KERN_ERR , fmt , ## args)
-
-#define WARN(fsg,fmt,args...) \
- xprintk(fsg , KERN_WARNING , fmt , ## args)
+ dev_err(&(lun)->dev , fmt , ## args)
#define LWARN(lun,fmt,args...) \
- yprintk(lun , KERN_WARNING , fmt , ## args)
-
-#define INFO(fsg,fmt,args...) \
- xprintk(fsg , KERN_INFO , fmt , ## args)
+ dev_warn(&(lun)->dev , fmt , ## args)
#define LINFO(lun,fmt,args...) \
- yprintk(lun , KERN_INFO , fmt , ## args)
+ dev_info(&(lun)->dev , fmt , ## args)
#define MINFO(fmt,args...) \
printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
+#define DBG(d, fmt, args...) \
+ dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+ dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+ dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+ dev_info(&(d)->gadget->dev , fmt , ## args)
+
/*-------------------------------------------------------------------------*/
@@ -350,8 +327,8 @@ MODULE_LICENSE("Dual BSD/GPL");
static struct {
char *file[MAX_LUNS];
int ro[MAX_LUNS];
- int num_filenames;
- int num_ros;
+ unsigned int num_filenames;
+ unsigned int num_ros;
unsigned int nluns;
int removable;
@@ -578,7 +555,7 @@ struct lun {
#define backing_file_is_open(curlun) ((curlun)->filp != NULL)
-static inline struct lun *dev_to_lun(struct device *dev)
+static struct lun *dev_to_lun(struct device *dev)
{
return container_of(dev, struct lun, dev);
}
@@ -711,13 +688,13 @@ struct fsg_dev {
typedef void (*fsg_routine_t)(struct fsg_dev *);
-static int inline exception_in_progress(struct fsg_dev *fsg)
+static int exception_in_progress(struct fsg_dev *fsg)
{
return (fsg->state > FSG_STATE_IDLE);
}
/* Make bulk-out requests be divisible by the maxpacket size */
-static void inline set_bulk_out_req_length(struct fsg_dev *fsg,
+static void set_bulk_out_req_length(struct fsg_dev *fsg,
struct fsg_buffhd *bh, unsigned int length)
{
unsigned int rem;
@@ -743,50 +720,36 @@ static void close_all_backing_files(struct fsg_dev *fsg);
static void dump_msg(struct fsg_dev *fsg, const char *label,
const u8 *buf, unsigned int length)
{
- unsigned int start, num, i;
- char line[52], *p;
-
- if (length >= 512)
- return;
- DBG(fsg, "%s, length %u:\n", label, length);
-
- start = 0;
- while (length > 0) {
- num = min(length, 16u);
- p = line;
- for (i = 0; i < num; ++i) {
- if (i == 8)
- *p++ = ' ';
- sprintf(p, " %02x", buf[i]);
- p += 3;
- }
- *p = 0;
- printk(KERN_DEBUG "%6x: %s\n", start, line);
- buf += num;
- start += num;
- length -= num;
+ if (length < 512) {
+ DBG(fsg, "%s, length %u:\n", label, length);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,
+ 16, 1, buf, length, 0);
}
}
-static void inline dump_cdb(struct fsg_dev *fsg)
+static void dump_cdb(struct fsg_dev *fsg)
{}
#else
-static void inline dump_msg(struct fsg_dev *fsg, const char *label,
+static void dump_msg(struct fsg_dev *fsg, const char *label,
const u8 *buf, unsigned int length)
{}
-static void inline dump_cdb(struct fsg_dev *fsg)
-{
- int i;
- char cmdbuf[3*MAX_COMMAND_SIZE + 1];
+#ifdef VERBOSE_DEBUG
- for (i = 0; i < fsg->cmnd_size; ++i)
- sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]);
- VDBG(fsg, "SCSI CDB: %s\n", cmdbuf);
+static void dump_cdb(struct fsg_dev *fsg)
+{
+ print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,
+ 16, 1, fsg->cmnd, fsg->cmnd_size, 0);
}
+#else
+
+static void dump_cdb(struct fsg_dev *fsg)
+{}
+
+#endif /* VERBOSE_DEBUG */
#endif /* DUMP_MSGS */
@@ -809,24 +772,24 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
/* Routines for unaligned data access */
-static u16 inline get_be16(u8 *buf)
+static u16 get_be16(u8 *buf)
{
return ((u16) buf[0] << 8) | ((u16) buf[1]);
}
-static u32 inline get_be32(u8 *buf)
+static u32 get_be32(u8 *buf)
{
return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) |
((u32) buf[2] << 8) | ((u32) buf[3]);
}
-static void inline put_be16(u8 *buf, u16 val)
+static void put_be16(u8 *buf, u16 val)
{
buf[0] = val >> 8;
buf[1] = val;
}
-static void inline put_be32(u8 *buf, u32 val)
+static void put_be32(u8 *buf, u32 val)
{
buf[0] = val >> 24;
buf[1] = val >> 16;
@@ -950,8 +913,6 @@ static const struct usb_descriptor_header *fs_function[] = {
#define FS_FUNCTION_PRE_EP_ENTRIES 2
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
/*
* USB 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@@ -1014,14 +975,14 @@ static const struct usb_descriptor_header *hs_function[] = {
#define HS_FUNCTION_PRE_EP_ENTRIES 2
/* Maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs))
-
-#else
-
-/* If there's no high speed support, always use the full-speed descriptor. */
-#define ep_desc(g,fs,hs) fs
-
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+static struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+ struct usb_endpoint_descriptor *hs)
+{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
+}
/* The CBI specification limits the serial string to 12 uppercase hexadecimal
@@ -1053,26 +1014,22 @@ static struct usb_gadget_strings stringtab = {
static int populate_config_buf(struct usb_gadget *gadget,
u8 *buf, u8 type, unsigned index)
{
-#ifdef CONFIG_USB_GADGET_DUALSPEED
enum usb_device_speed speed = gadget->speed;
-#endif
int len;
const struct usb_descriptor_header **function;
if (index > 0)
return -EINVAL;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (type == USB_DT_OTHER_SPEED_CONFIG)
+ if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
- if (speed == USB_SPEED_HIGH)
+ if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH)
function = hs_function;
else
-#endif
function = fs_function;
/* for now, don't advertise srp-only devices */
- if (!gadget->is_otg)
+ if (!gadget_is_otg(gadget))
function++;
len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
@@ -1394,10 +1351,9 @@ static int standard_setup_req(struct fsg_dev *fsg,
value = sizeof device_desc;
memcpy(req->buf, &device_desc, value);
break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
VDBG(fsg, "get device qualifier\n");
- if (!fsg->gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(fsg->gadget))
break;
value = sizeof dev_qualifier;
memcpy(req->buf, &dev_qualifier, value);
@@ -1405,15 +1361,12 @@ static int standard_setup_req(struct fsg_dev *fsg,
case USB_DT_OTHER_SPEED_CONFIG:
VDBG(fsg, "get other-speed config descriptor\n");
- if (!fsg->gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(fsg->gadget))
break;
goto get_config;
-#endif
case USB_DT_CONFIG:
VDBG(fsg, "get configuration descriptor\n");
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- get_config:
-#endif
+get_config:
value = populate_config_buf(fsg->gadget,
req->buf,
w_value >> 8,
@@ -1646,7 +1599,8 @@ static int do_read(struct fsg_dev *fsg)
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
@@ -1885,7 +1839,8 @@ static int do_write(struct fsg_dev *fsg)
}
/* Wait for something to happen */
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
@@ -2369,7 +2324,8 @@ static int pad_with_zeros(struct fsg_dev *fsg)
/* Wait for the next buffer to be free */
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
@@ -2429,7 +2385,8 @@ static int throw_away_data(struct fsg_dev *fsg)
}
/* Otherwise wait for something to happen */
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
return 0;
@@ -2551,7 +2508,8 @@ static int send_status(struct fsg_dev *fsg)
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
}
@@ -2771,9 +2729,10 @@ static int do_scsi_command(struct fsg_dev *fsg)
/* Wait for the next buffer to become available for data or status */
bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
- }
+ }
fsg->phase_error = 0;
fsg->short_packet_received = 0;
@@ -3005,7 +2964,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
/* Is the CBW meaningful? */
if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
- cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) {
+ cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
"cmdlen %u\n",
cbw->Lun, cbw->Flags, cbw->Length);
@@ -3045,9 +3004,10 @@ static int get_next_command(struct fsg_dev *fsg)
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
- }
+ }
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
@@ -3061,9 +3021,10 @@ static int get_next_command(struct fsg_dev *fsg)
/* Wait for the CBW to arrive */
while (bh->state != BUF_STATE_FULL) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
- }
+ }
smp_rmb();
rc = received_cbw(fsg, bh);
bh->state = BUF_STATE_EMPTY;
@@ -3072,9 +3033,10 @@ static int get_next_command(struct fsg_dev *fsg)
/* Wait for the next command to arrive */
while (fsg->cbbuf_cmnd_size == 0) {
- if ((rc = sleep_thread(fsg)) != 0)
+ rc = sleep_thread(fsg);
+ if (rc)
return rc;
- }
+ }
/* Is the previous status interrupt request still busy?
* The host is allowed to skip reading the status,
@@ -3595,7 +3557,8 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
return sprintf(buf, "%d\n", curlun->ro);
}
-static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_file(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = dev_get_drvdata(dev);
@@ -3604,8 +3567,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
down_read(&fsg->filesem);
if (backing_file_is_open(curlun)) { // Get the complete pathname
- p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt,
- buf, PAGE_SIZE - 1);
+ p = d_path(curlun->filp->f_path.dentry,
+ curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1);
if (IS_ERR(p))
rc = PTR_ERR(p);
else {
@@ -3623,7 +3586,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
}
-static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_ro(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
ssize_t rc = count;
struct lun *curlun = dev_to_lun(dev);
@@ -3647,7 +3611,8 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
return rc;
}
-static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_file(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = dev_get_drvdata(dev);
@@ -3859,7 +3824,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
/* Find out how many LUNs there should be */
i = mod_data.nluns;
if (i == 0)
- i = max(mod_data.num_filenames, 1);
+ i = max(mod_data.num_filenames, 1u);
if (i > MAX_LUNS) {
ERROR(fsg, "invalid number of LUNs: %d\n", i);
rc = -EINVAL;
@@ -3944,21 +3909,23 @@ static int __init fsg_bind(struct usb_gadget *gadget)
intf_desc.bInterfaceProtocol = mod_data.transport_type;
fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+ if (gadget_is_dualspeed(gadget)) {
+ hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
- /* Assume ep0 uses the same maxpacket value for both speeds */
- dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
+ /* Assume ep0 uses the same maxpacket value for both speeds */
+ dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
- /* Assume that all endpoint addresses are the same for both speeds */
- hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress;
- hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress;
- hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress;
-#endif
+ /* Assume endpoint addresses are the same for both speeds */
+ hs_bulk_in_desc.bEndpointAddress =
+ fs_bulk_in_desc.bEndpointAddress;
+ hs_bulk_out_desc.bEndpointAddress =
+ fs_bulk_out_desc.bEndpointAddress;
+ hs_intr_in_desc.bEndpointAddress =
+ fs_intr_in_desc.bEndpointAddress;
+ }
- if (gadget->is_otg) {
+ if (gadget_is_otg(gadget))
otg_desc.bmAttributes |= USB_OTG_HNP;
- }
rc = -ENOMEM;
@@ -4039,7 +4006,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
DBG(fsg, "removable=%d, stall=%d, buflen=%u\n",
mod_data.removable, mod_data.can_stall,
mod_data.buflen);
- DBG(fsg, "I/O thread pid: %d\n", fsg->thread_task->pid);
+ DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
set_bit(REGISTERED, &fsg->atomic_bitflags);
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index d57bcfbc08a..9bb7f64a85c 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -35,7 +35,7 @@
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
@@ -1090,14 +1090,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
*/
static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
{
-#ifdef CONFIG_USB_OTG
struct fsl_udc *udc;
udc = container_of(gadget, struct fsl_udc, gadget);
-
if (udc->transceiver)
return otg_set_power(udc->transceiver, mA);
-#endif
return -ENOTSUPP;
}
@@ -1120,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
return 0;
}
-/* defined in usb_gadget.h */
+/* defined in gadget.h */
static struct usb_gadget_ops fsl_gadget_ops = {
.get_frame = fsl_get_frame,
.wakeup = fsl_wakeup,
@@ -1321,7 +1318,7 @@ static void setup_received_irq(struct fsl_udc *udc,
| USB_TYPE_STANDARD)) {
/* Note: The driver has not include OTG support yet.
* This will be set when OTG support is added */
- if (!udc->gadget.is_otg)
+ if (!gadget_is_otg(udc->gadget))
break;
else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
udc->gadget.b_hnp_enable = 1;
@@ -1330,6 +1327,8 @@ static void setup_received_irq(struct fsl_udc *udc,
else if (setup->bRequest ==
USB_DEVICE_A_ALT_HNP_SUPPORT)
udc->gadget.a_alt_hnp_support = 1;
+ else
+ break;
rc = 0;
} else
break;
@@ -1840,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
if (!driver || driver != udc_controller->driver || !driver->unbind)
return -EINVAL;
-#ifdef CONFIG_USB_OTG
if (udc_controller->transceiver)
(void)otg_set_peripheral(udc_controller->transceiver, 0);
-#endif
/* stop DR, disable intr */
dr_controller_stop(udc_controller);
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 1c5aa49d743..0689189550b 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -18,17 +18,11 @@
* http://www.usb.org/developers/devclass_docs/midi10.pdf
*/
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
#include <linux/utsname.h>
#include <linux/device.h>
-#include <linux/moduleparam.h>
#include <sound/driver.h>
#include <sound/core.h>
@@ -36,7 +30,7 @@
#include <sound/rawmidi.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <linux/usb/audio.h>
#include <linux/usb/midi.h>
@@ -139,30 +133,16 @@ struct gmidi_device {
static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
-#define xprintk(d,level,fmt,args...) \
- dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
- xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG DBG
-#else
-#define VDBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
- xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
- xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
- xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+ dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+ dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+ dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+ dev_info(&(d)->gadget->dev , fmt , ## args)
static unsigned buflen = 256;
@@ -425,7 +405,7 @@ static int config_buf(struct usb_gadget *gadget,
return len;
}
-static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length)
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
{
struct usb_request *req;
@@ -455,7 +435,7 @@ static const uint8_t gmidi_cin_length[] = {
* Receives a chunk of MIDI data.
*/
static void gmidi_read_data(struct usb_ep *ep, int cable,
- uint8_t* data, int length)
+ uint8_t *data, int length)
{
struct gmidi_device *dev = ep->driver_data;
/* cable is ignored, because for now we only have one. */
@@ -541,7 +521,7 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
{
int err = 0;
struct usb_request *req;
- struct usb_ep* ep;
+ struct usb_ep *ep;
unsigned i;
err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
@@ -628,7 +608,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
if (gadget_is_sa1100(gadget) && dev->config) {
/* tx fifo is full, but we can't clear it...*/
- INFO(dev, "can't change configurations\n");
+ ERROR(dev, "can't change configurations\n");
return -ESPIPE;
}
gmidi_reset_config(dev);
@@ -843,7 +823,7 @@ static void gmidi_disconnect(struct usb_gadget *gadget)
static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
{
struct gmidi_device *dev = get_gadget_data(gadget);
- struct snd_card* card;
+ struct snd_card *card;
DBG(dev, "unbind\n");
@@ -867,12 +847,12 @@ static int gmidi_snd_free(struct snd_device *device)
return 0;
}
-static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
+static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0,
uint8_t p1, uint8_t p2, uint8_t p3)
{
unsigned length = req->length;
+ u8 *buf = (u8 *)req->buf + length;
- uint8_t* buf = (uint8_t*)req->buf + length;
buf[0] = p0;
buf[1] = p1;
buf[2] = p2;
@@ -883,8 +863,8 @@ static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
/*
* Converts MIDI commands to USB MIDI packets.
*/
-static void gmidi_transmit_byte(struct usb_request* req,
- struct gmidi_in_port* port, uint8_t b)
+static void gmidi_transmit_byte(struct usb_request *req,
+ struct gmidi_in_port *port, uint8_t b)
{
uint8_t p0 = port->cable;
@@ -981,10 +961,10 @@ static void gmidi_transmit_byte(struct usb_request* req,
}
}
-static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
+static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req)
{
- struct usb_ep* ep = dev->in_ep;
- struct gmidi_in_port* port = &dev->in_port;
+ struct usb_ep *ep = dev->in_ep;
+ struct gmidi_in_port *port = &dev->in_port;
if (!ep) {
return;
@@ -1020,14 +1000,14 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
static void gmidi_in_tasklet(unsigned long data)
{
- struct gmidi_device* dev = (struct gmidi_device*)data;
+ struct gmidi_device *dev = (struct gmidi_device *)data;
gmidi_transmit(dev, NULL);
}
static int gmidi_in_open(struct snd_rawmidi_substream *substream)
{
- struct gmidi_device* dev = substream->rmidi->private_data;
+ struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_in_open\n");
dev->in_substream = substream;
@@ -1037,13 +1017,15 @@ static int gmidi_in_open(struct snd_rawmidi_substream *substream)
static int gmidi_in_close(struct snd_rawmidi_substream *substream)
{
+ struct gmidi_device *dev = substream->rmidi->private_data;
+
VDBG(dev, "gmidi_in_close\n");
return 0;
}
static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
{
- struct gmidi_device* dev = substream->rmidi->private_data;
+ struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_in_trigger %d\n", up);
dev->in_port.active = up;
@@ -1054,7 +1036,7 @@ static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
static int gmidi_out_open(struct snd_rawmidi_substream *substream)
{
- struct gmidi_device* dev = substream->rmidi->private_data;
+ struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_out_open\n");
dev->out_substream = substream;
@@ -1063,13 +1045,15 @@ static int gmidi_out_open(struct snd_rawmidi_substream *substream)
static int gmidi_out_close(struct snd_rawmidi_substream *substream)
{
+ struct gmidi_device *dev = substream->rmidi->private_data;
+
VDBG(dev, "gmidi_out_close\n");
return 0;
}
static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
{
- struct gmidi_device* dev = substream->rmidi->private_data;
+ struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_out_trigger %d\n", up);
if (up) {
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 349b8166f34..2ec9d196a8c 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -37,7 +37,7 @@
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 173004f60fe..47ef8bd58a0 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -20,8 +20,7 @@
*/
-// #define DEBUG /* data to help fault diagnosis */
-// #define VERBOSE /* extra debug messages (success too) */
+/* #define VERBOSE_DEBUG */
#include <linux/init.h>
#include <linux/module.h>
@@ -38,7 +37,7 @@
#include <linux/moduleparam.h>
#include <linux/usb/gadgetfs.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
/*
@@ -253,7 +252,7 @@ static const char *CHIP;
do { } while (0)
#endif /* DEBUG */
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
#define VDEBUG DBG
#else
#define VDEBUG(dev,fmt,args...) \
@@ -1010,11 +1009,12 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
/* assume that was SET_CONFIGURATION */
if (dev->current_config) {
unsigned power;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (dev->gadget->speed == USB_SPEED_HIGH)
+
+ if (gadget_is_dualspeed(dev->gadget)
+ && (dev->gadget->speed
+ == USB_SPEED_HIGH))
power = dev->hs_config->bMaxPower;
else
-#endif
power = dev->config->bMaxPower;
usb_gadget_vbus_draw(dev->gadget, 2 * power);
}
@@ -1355,24 +1355,21 @@ static int
config_buf (struct dev_data *dev, u8 type, unsigned index)
{
int len;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- int hs;
-#endif
+ int hs = 0;
/* only one configuration */
if (index > 0)
return -EINVAL;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- hs = (dev->gadget->speed == USB_SPEED_HIGH);
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- hs = !hs;
+ if (gadget_is_dualspeed(dev->gadget)) {
+ hs = (dev->gadget->speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
+ }
if (hs) {
dev->req->buf = dev->hs_config;
len = le16_to_cpu(dev->hs_config->wTotalLength);
- } else
-#endif
- {
+ } else {
dev->req->buf = dev->config;
len = le16_to_cpu(dev->config->wTotalLength);
}
@@ -1393,13 +1390,13 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
spin_lock (&dev->lock);
dev->setup_abort = 0;
if (dev->state == STATE_DEV_UNCONNECTED) {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == NULL) {
+ if (gadget_is_dualspeed(gadget)
+ && gadget->speed == USB_SPEED_HIGH
+ && dev->hs_config == NULL) {
spin_unlock(&dev->lock);
ERROR (dev, "no high speed config??\n");
return -EINVAL;
}
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
dev->state = STATE_DEV_CONNECTED;
dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
@@ -1469,13 +1466,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
// user mode expected to disable endpoints
} else {
u8 config, power;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (gadget->speed == USB_SPEED_HIGH) {
+
+ if (gadget_is_dualspeed(gadget)
+ && gadget->speed == USB_SPEED_HIGH) {
config = dev->hs_config->bConfigurationValue;
power = dev->hs_config->bMaxPower;
- } else
-#endif
- {
+ } else {
config = dev->config->bConfigurationValue;
power = dev->config->bMaxPower;
}
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
index e78c2ddc1f8..367b75c0b25 100644
--- a/drivers/usb/gadget/lh7a40x_udc.c
+++ b/drivers/usb/gadget/lh7a40x_udc.c
@@ -1272,7 +1272,7 @@ static int lh7a40x_set_halt(struct usb_ep *_ep, int value)
/*
* Attempts to halt IN endpoints will fail (returning -EAGAIN)
* if any transfer requests are still queued, or if the controller
- * FIFO still holds bytes that the host hasn’t collected.
+ * FIFO still holds bytes that the host hasn't collected.
*/
spin_unlock_irqrestore(&ep->dev->lock, flags);
DEBUG
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
index b3fe197e1ee..1ecfd6366b9 100644
--- a/drivers/usb/gadget/lh7a40x_udc.h
+++ b/drivers/usb/gadget/lh7a40x_udc.h
@@ -50,7 +50,7 @@
#include <asm/hardware.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
/*
* Memory map
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 4b27d12f049..ebc5536aa27 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -27,7 +27,7 @@
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "m66592-udc.h"
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index c3d364ecd4f..d5d473f8144 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -62,7 +62,7 @@
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 9b0f0925ddd..87c4f50dfb6 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -38,7 +38,7 @@
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
@@ -1241,19 +1241,15 @@ static void pullup_enable(struct omap_udc *udc)
udc->gadget.dev.parent->power.power_state = PMSG_ON;
udc->gadget.dev.power.power_state = PMSG_ON;
UDC_SYSCON1_REG |= UDC_PULLUP_EN;
-#ifndef CONFIG_USB_OTG
- if (!cpu_is_omap15xx())
+ if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
OTG_CTRL_REG |= OTG_BSESSVLD;
-#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
}
static void pullup_disable(struct omap_udc *udc)
{
-#ifndef CONFIG_USB_OTG
- if (!cpu_is_omap15xx())
+ if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
OTG_CTRL_REG &= ~OTG_BSESSVLD;
-#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
}
@@ -1390,7 +1386,7 @@ static void update_otg(struct omap_udc *udc)
{
u16 devstat;
- if (!udc->gadget.is_otg)
+ if (!gadget_is_otg(udc->gadget))
return;
if (OTG_CTRL_REG & OTG_ID)
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index 1407ad1c812..3173b39f0bf 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -43,6 +43,8 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <asm/byteorder.h>
#include <asm/dma.h>
@@ -54,7 +56,7 @@
#include <asm/hardware.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/mach/udc_pxa2xx.h>
@@ -1157,7 +1159,7 @@ static void udc_disable(struct pxa2xx_udc *dev)
#ifdef CONFIG_ARCH_PXA
/* Disable clock for USB device */
- pxa_set_cken(CKEN_USB, 0);
+ clk_disable(dev->clk);
#endif
ep0_idle (dev);
@@ -1202,8 +1204,7 @@ static void udc_enable (struct pxa2xx_udc *dev)
#ifdef CONFIG_ARCH_PXA
/* Enable clock for USB device */
- pxa_set_cken(CKEN_USB, 1);
- udelay(5);
+ clk_enable(dev->clk);
#endif
/* try to clear these bits before we enable the udc */
@@ -2137,6 +2138,14 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
if (irq < 0)
return -ENODEV;
+#ifdef CONFIG_ARCH_PXA
+ dev->clk = clk_get(&pdev->dev, "UDCCLK");
+ if (IS_ERR(dev->clk)) {
+ retval = PTR_ERR(dev->clk);
+ goto err_clk;
+ }
+#endif
+
pr_debug("%s: IRQ %d%s%s\n", driver_name, irq,
dev->has_cfr ? "" : " (!cfr)",
SIZE_STR "(pio)"
@@ -2152,11 +2161,10 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev,
"can't get vbus gpio %d, err: %d\n",
dev->mach->gpio_vbus, retval);
- return -EBUSY;
+ goto err_gpio_vbus;
}
gpio_direction_input(dev->mach->gpio_vbus);
vbus_irq = gpio_to_irq(dev->mach->gpio_vbus);
- set_irq_type(vbus_irq, IRQT_BOTHEDGE);
} else
vbus_irq = 0;
@@ -2166,9 +2174,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev,
"can't get pullup gpio %d, err: %d\n",
dev->mach->gpio_pullup, retval);
- if (dev->mach->gpio_vbus)
- gpio_free(dev->mach->gpio_vbus);
- return -EBUSY;
+ goto err_gpio_pullup;
}
gpio_direction_output(dev->mach->gpio_pullup, 0);
}
@@ -2195,11 +2201,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
if (retval != 0) {
printk(KERN_ERR "%s: can't get irq %d, err %d\n",
driver_name, irq, retval);
- if (dev->mach->gpio_pullup)
- gpio_free(dev->mach->gpio_pullup);
- if (dev->mach->gpio_vbus)
- gpio_free(dev->mach->gpio_vbus);
- return -EBUSY;
+ goto err_irq1;
}
dev->got_irq = 1;
@@ -2213,12 +2215,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
printk(KERN_ERR "%s: can't get irq %i, err %d\n",
driver_name, LUBBOCK_USB_DISC_IRQ, retval);
lubbock_fail0:
- free_irq(irq, dev);
- if (dev->mach->gpio_pullup)
- gpio_free(dev->mach->gpio_pullup);
- if (dev->mach->gpio_vbus)
- gpio_free(dev->mach->gpio_vbus);
- return -EBUSY;
+ goto err_irq_lub;
}
retval = request_irq(LUBBOCK_USB_IRQ,
lubbock_vbus_irq,
@@ -2234,22 +2231,37 @@ lubbock_fail0:
#endif
if (vbus_irq) {
retval = request_irq(vbus_irq, udc_vbus_irq,
- IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
+ IRQF_DISABLED | IRQF_SAMPLE_RANDOM |
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
driver_name, dev);
if (retval != 0) {
printk(KERN_ERR "%s: can't get irq %i, err %d\n",
driver_name, vbus_irq, retval);
- free_irq(irq, dev);
- if (dev->mach->gpio_pullup)
- gpio_free(dev->mach->gpio_pullup);
- if (dev->mach->gpio_vbus)
- gpio_free(dev->mach->gpio_vbus);
- return -EBUSY;
+ goto err_vbus_irq;
}
}
create_proc_files();
return 0;
+
+ err_vbus_irq:
+#ifdef CONFIG_ARCH_LUBBOCK
+ free_irq(LUBBOCK_USB_DISC_IRQ, dev);
+ err_irq_lub:
+#endif
+ free_irq(irq, dev);
+ err_irq1:
+ if (dev->mach->gpio_pullup)
+ gpio_free(dev->mach->gpio_pullup);
+ err_gpio_pullup:
+ if (dev->mach->gpio_vbus)
+ gpio_free(dev->mach->gpio_vbus);
+ err_gpio_vbus:
+#ifdef CONFIG_ARCH_PXA
+ clk_put(dev->clk);
+ err_clk:
+#endif
+ return retval;
}
static void pxa2xx_udc_shutdown(struct platform_device *_dev)
@@ -2284,6 +2296,10 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
if (dev->mach->gpio_pullup)
gpio_free(dev->mach->gpio_pullup);
+#ifdef CONFIG_ARCH_PXA
+ clk_put(dev->clk);
+#endif
+
platform_set_drvdata(pdev, NULL);
the_controller = NULL;
return 0;
diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
index 0e5d0e6fb0e..1db46d70577 100644
--- a/drivers/usb/gadget/pxa2xx_udc.h
+++ b/drivers/usb/gadget/pxa2xx_udc.h
@@ -125,6 +125,7 @@ struct pxa2xx_udc {
struct timer_list timer;
struct device *dev;
+ struct clk *clk;
struct pxa2xx_udc_mach_info *mach;
u64 dma_mask;
struct pxa2xx_ep ep [PXA_UDC_NUM_ENDPOINTS];
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 0be80c635c4..e3e90f8a75e 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -42,7 +42,7 @@
#include <linux/seq_file.h>
#include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index ce4d2e09633..f5738eb8e76 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -17,34 +17,15 @@
*
*/
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
#include <linux/utsname.h>
-#include <linux/wait.h>
-#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <linux/mutex.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/uaccess.h>
#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
@@ -89,30 +70,29 @@
#define GS_DEFAULT_PARITY USB_CDC_NO_PARITY
#define GS_DEFAULT_CHAR_FORMAT USB_CDC_1_STOP_BITS
-/* select highspeed/fullspeed, hiding highspeed if not configured */
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs))
-#else
-#define GS_SPEED_SELECT(is_hs,hs,fs) (fs)
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+/* maxpacket and other transfer characteristics vary by speed. */
+static inline struct usb_endpoint_descriptor *
+choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *fs)
+{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
+}
+
/* debug settings */
-#ifdef GS_DEBUG
+#ifdef DEBUG
static int debug = 1;
+#else
+#define debug 0
+#endif
#define gs_debug(format, arg...) \
do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
#define gs_debug_level(level, format, arg...) \
do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
-#else
-
-#define gs_debug(format, arg...) \
- do { } while(0)
-#define gs_debug_level(level, format, arg...) \
- do { } while(0)
-
-#endif /* GS_DEBUG */
/* Thanks to NetChip Technologies for donating this product ID.
*
@@ -147,10 +127,10 @@ struct gs_req_entry {
/* the port structure holds info for each port, one for each minor number */
struct gs_port {
- struct gs_dev *port_dev; /* pointer to device struct */
+ struct gs_dev *port_dev; /* pointer to device struct */
struct tty_struct *port_tty; /* pointer to tty struct */
spinlock_t port_lock;
- int port_num;
+ int port_num;
int port_open_count;
int port_in_use; /* open/close in progress */
wait_queue_head_t port_write_wait;/* waiting to write */
@@ -188,7 +168,7 @@ static void __exit gs_module_exit(void);
/* tty driver */
static int gs_open(struct tty_struct *tty, struct file *file);
static void gs_close(struct tty_struct *tty, struct file *file);
-static int gs_write(struct tty_struct *tty,
+static int gs_write(struct tty_struct *tty,
const unsigned char *buf, int count);
static void gs_put_char(struct tty_struct *tty, unsigned char ch);
static void gs_flush_chars(struct tty_struct *tty);
@@ -222,7 +202,7 @@ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
static void gs_disconnect(struct usb_gadget *gadget);
static int gs_set_config(struct gs_dev *dev, unsigned config);
static void gs_reset_config(struct gs_dev *dev);
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
u8 type, unsigned int index, int is_otg);
static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
@@ -415,18 +395,18 @@ static const struct usb_cdc_header_desc gs_header_desc = {
};
static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
- .bLength = sizeof(gs_call_mgmt_descriptor),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
- .bmCapabilities = 0,
- .bDataInterface = 1, /* index of data interface */
+ .bLength = sizeof(gs_call_mgmt_descriptor),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
+ .bmCapabilities = 0,
+ .bDataInterface = 1, /* index of data interface */
};
static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
- .bLength = sizeof(gs_acm_descriptor),
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = USB_CDC_ACM_TYPE,
- .bmCapabilities = 0,
+ .bLength = sizeof(gs_acm_descriptor),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_ACM_TYPE,
+ .bmCapabilities = 0,
};
static const struct usb_cdc_union_desc gs_union_desc = {
@@ -436,7 +416,7 @@ static const struct usb_cdc_union_desc gs_union_desc = {
.bMasterInterface0 = 0, /* index of control interface */
.bSlaveInterface0 = 1, /* index of data interface */
};
-
+
static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -482,7 +462,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
NULL,
};
-#ifdef CONFIG_USB_GADGET_DUALSPEED
static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -536,15 +515,13 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
NULL,
};
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-
/* Module */
MODULE_DESCRIPTION(GS_LONG_NAME);
MODULE_AUTHOR("Al Borchers");
MODULE_LICENSE("GPL");
-#ifdef GS_DEBUG
+#ifdef DEBUG
module_param(debug, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
#endif
@@ -915,7 +892,8 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
return;
}
- gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2));
+ gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
+ port->port_num, tty, ch, __builtin_return_address(0));
spin_lock_irqsave(&port->port_lock, flags);
@@ -1116,7 +1094,11 @@ static int gs_send(struct gs_dev *dev)
len = gs_send_packet(dev, req->buf, ep->maxpacket);
if (len > 0) {
-gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
+ gs_debug_level(3, "gs_send: len=%d, 0x%2.2x "
+ "0x%2.2x 0x%2.2x ...\n", len,
+ *((unsigned char *)req->buf),
+ *((unsigned char *)req->buf+1),
+ *((unsigned char *)req->buf+2));
list_del(&req_entry->re_entry);
req->length = len;
spin_unlock_irqrestore(&dev->dev_lock, flags);
@@ -1269,7 +1251,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
switch(req->status) {
case 0:
- /* normal completion */
+ /* normal completion */
gs_recv_packet(dev, req->buf, req->actual);
requeue:
req->length = ep->maxpacket;
@@ -1406,23 +1388,24 @@ static int __init gs_bind(struct usb_gadget *gadget)
? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- gs_qualifier_desc.bDeviceClass = use_acm
- ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
- /* assume ep0 uses the same packet size for both speeds */
- gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0;
- /* assume endpoints are dual-speed */
- gs_highspeed_notify_desc.bEndpointAddress =
- gs_fullspeed_notify_desc.bEndpointAddress;
- gs_highspeed_in_desc.bEndpointAddress =
- gs_fullspeed_in_desc.bEndpointAddress;
- gs_highspeed_out_desc.bEndpointAddress =
- gs_fullspeed_out_desc.bEndpointAddress;
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+ if (gadget_is_dualspeed(gadget)) {
+ gs_qualifier_desc.bDeviceClass = use_acm
+ ? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
+ /* assume ep0 uses the same packet size for both speeds */
+ gs_qualifier_desc.bMaxPacketSize0 =
+ gs_device_desc.bMaxPacketSize0;
+ /* assume endpoints are dual-speed */
+ gs_highspeed_notify_desc.bEndpointAddress =
+ gs_fullspeed_notify_desc.bEndpointAddress;
+ gs_highspeed_in_desc.bEndpointAddress =
+ gs_fullspeed_in_desc.bEndpointAddress;
+ gs_highspeed_out_desc.bEndpointAddress =
+ gs_fullspeed_out_desc.bEndpointAddress;
+ }
usb_gadget_set_selfpowered(gadget);
- if (gadget->is_otg) {
+ if (gadget_is_otg(gadget)) {
gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1487,6 +1470,12 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
dev->dev_ctrl_req = NULL;
}
gs_free_ports(dev);
+ if (dev->dev_notify_ep)
+ usb_ep_disable(dev->dev_notify_ep);
+ if (dev->dev_in_ep)
+ usb_ep_disable(dev->dev_in_ep);
+ if (dev->dev_out_ep)
+ usb_ep_disable(dev->dev_out_ep);
kfree(dev);
set_gadget_data(gadget, NULL);
}
@@ -1570,9 +1559,8 @@ static int gs_setup_standard(struct usb_gadget *gadget,
memcpy(req->buf, &gs_device_desc, ret);
break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
ret = min(wLength,
(u16)sizeof(struct usb_qualifier_descriptor));
@@ -1580,14 +1568,13 @@ static int gs_setup_standard(struct usb_gadget *gadget,
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
/* fall through */
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
- ret = gs_build_config_buf(req->buf, gadget->speed,
+ ret = gs_build_config_buf(req->buf, gadget,
wValue >> 8, wValue & 0xff,
- gadget->is_otg);
+ gadget_is_otg(gadget));
if (ret >= 0)
ret = min(wLength, (u16)ret);
break;
@@ -1827,8 +1814,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
if (EP_NOTIFY_NAME
&& strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
- ep_desc = GS_SPEED_SELECT(
- gadget->speed == USB_SPEED_HIGH,
+ ep_desc = choose_ep_desc(gadget,
&gs_highspeed_notify_desc,
&gs_fullspeed_notify_desc);
ret = usb_ep_enable(ep,ep_desc);
@@ -1844,9 +1830,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
}
else if (strcmp(ep->name, EP_IN_NAME) == 0) {
- ep_desc = GS_SPEED_SELECT(
- gadget->speed == USB_SPEED_HIGH,
- &gs_highspeed_in_desc,
+ ep_desc = choose_ep_desc(gadget,
+ &gs_highspeed_in_desc,
&gs_fullspeed_in_desc);
ret = usb_ep_enable(ep,ep_desc);
if (ret == 0) {
@@ -1861,8 +1846,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
}
else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
- ep_desc = GS_SPEED_SELECT(
- gadget->speed == USB_SPEED_HIGH,
+ ep_desc = choose_ep_desc(gadget,
&gs_highspeed_out_desc,
&gs_fullspeed_out_desc);
ret = usb_ep_enable(ep,ep_desc);
@@ -1981,11 +1965,11 @@ static void gs_reset_config(struct gs_dev *dev)
* Builds the config descriptors in the given buffer and returns the
* length, or a negative error number.
*/
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
u8 type, unsigned int index, int is_otg)
{
int len;
- int high_speed;
+ int high_speed = 0;
const struct usb_config_descriptor *config_desc;
const struct usb_descriptor_header **function;
@@ -1993,20 +1977,22 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
return -EINVAL;
/* other speed switches high and full speed */
- high_speed = (speed == USB_SPEED_HIGH);
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- high_speed = !high_speed;
+ if (gadget_is_dualspeed(g)) {
+ high_speed = (g->speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ high_speed = !high_speed;
+ }
if (use_acm) {
config_desc = &gs_acm_config_desc;
- function = GS_SPEED_SELECT(high_speed,
- gs_acm_highspeed_function,
- gs_acm_fullspeed_function);
+ function = high_speed
+ ? gs_acm_highspeed_function
+ : gs_acm_fullspeed_function;
} else {
config_desc = &gs_bulk_config_desc;
- function = GS_SPEED_SELECT(high_speed,
- gs_bulk_highspeed_function,
- gs_bulk_fullspeed_function);
+ function = high_speed
+ ? gs_bulk_highspeed_function
+ : gs_bulk_fullspeed_function;
}
/* for now, don't advertise srp-only devices */
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index 3459ea6c6c0..878e428a0ec 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -15,7 +15,7 @@
#include <linux/init.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index fcfe869acb9..fcde5d9c87d 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -1,38 +1,22 @@
/*
* zero.c -- Gadget Zero, for USB development
*
- * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003-2007 David Brownell
* All rights reserved.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation, either version 2 of that License or (at your option) any
- * later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -57,40 +41,28 @@
* Many drivers will only have one configuration, letting them be much
* simpler if they also don't support high speed operation (like this
* driver does).
+ *
+ * Why is *this* driver using two configurations, rather than setting up
+ * two interfaces with different functions? To help verify that multiple
+ * configuration infrastucture is working correctly; also, so that it can
+ * work with low capability USB controllers without four bulk endpoints.
*/
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
#include <linux/utsname.h>
#include <linux/device.h>
-#include <linux/moduleparam.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
#include "gadget_chips.h"
/*-------------------------------------------------------------------------*/
-#define DRIVER_VERSION "St Patrick's Day 2004"
+#define DRIVER_VERSION "Lughnasadh, 2007"
static const char shortname [] = "zero";
static const char longname [] = "Gadget Zero";
@@ -131,30 +103,16 @@ struct zero_dev {
struct timer_list resume;
};
-#define xprintk(d,level,fmt,args...) \
- dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
- xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG DBG
-#else
-#define VDBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
- xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
- xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
- xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+ dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+ dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+ dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+ dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+ dev_info(&(d)->gadget->dev , fmt , ## args)
/*-------------------------------------------------------------------------*/
@@ -326,8 +284,6 @@ static const struct usb_descriptor_header *fs_loopback_function [] = {
NULL,
};
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
/*
* usb 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@@ -383,17 +339,20 @@ static const struct usb_descriptor_header *hs_loopback_function [] = {
};
/* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *fs)
+{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
+}
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) fs
+static char manufacturer[50];
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+/* default serial number takes at least two packets */
+static char serial[] = "0123456789.0123456789.0123456789";
-static char manufacturer [50];
-static char serial [40];
/* static strings, in UTF-8 */
static struct usb_string strings [] = {
@@ -435,30 +394,29 @@ config_buf (struct usb_gadget *gadget,
int is_source_sink;
int len;
const struct usb_descriptor_header **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- int hs = (gadget->speed == USB_SPEED_HIGH);
-#endif
+ int hs = 0;
/* two configurations will always be index 0 and index 1 */
if (index > 1)
return -EINVAL;
is_source_sink = loopdefault ? (index == 1) : (index == 0);
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- hs = !hs;
+ if (gadget_is_dualspeed(gadget)) {
+ hs = (gadget->speed == USB_SPEED_HIGH);
+ if (type == USB_DT_OTHER_SPEED_CONFIG)
+ hs = !hs;
+ }
if (hs)
function = is_source_sink
? hs_source_sink_function
: hs_loopback_function;
else
-#endif
function = is_source_sink
? fs_source_sink_function
: fs_loopback_function;
/* for now, don't advertise srp-only devices */
- if (!gadget->is_otg)
+ if (!gadget_is_otg(gadget))
function++;
len = usb_gadget_config_buf (is_source_sink
@@ -498,6 +456,19 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
/*-------------------------------------------------------------------------*/
+/*
+ * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals,
+ * this just sinks bulk packets OUT to the peripheral and sources them IN
+ * to the host, optionally with specific data patterns.
+ *
+ * In terms of control messaging, this supports all the standard requests
+ * plus two that support control-OUT tests.
+ *
+ * Note that because this doesn't queue more than one request at a time,
+ * some other function must be used to test queueing logic. The network
+ * link (g_ether) is probably the best option for that.
+ */
+
/* optionally require specific source/sink data patterns */
static int
@@ -534,12 +505,7 @@ check_read_data (
return 0;
}
-static void
-reinit_write_data (
- struct zero_dev *dev,
- struct usb_ep *ep,
- struct usb_request *req
-)
+static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
{
unsigned i;
u8 *buf = req->buf;
@@ -566,16 +532,16 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
switch (status) {
- case 0: /* normal completion? */
+ case 0: /* normal completion? */
if (ep == dev->out_ep) {
check_read_data (dev, ep, req);
memset (req->buf, 0x55, req->length);
} else
- reinit_write_data (dev, ep, req);
+ reinit_write_data(ep, req);
break;
/* this endpoint is normally active while we're configured */
- case -ECONNABORTED: /* hardware forced ep reset */
+ case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
@@ -607,8 +573,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
}
}
-static struct usb_request *
-source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
+static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
{
struct usb_request *req;
int status;
@@ -621,11 +586,11 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
req->complete = source_sink_complete;
if (strcmp (ep->name, EP_IN_NAME) == 0)
- reinit_write_data (ep->driver_data, ep, req);
+ reinit_write_data(ep, req);
else
memset (req->buf, 0x55, req->length);
- status = usb_ep_queue (ep, req, gfp_flags);
+ status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status) {
struct zero_dev *dev = ep->driver_data;
@@ -637,8 +602,7 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
return req;
}
-static int
-set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_source_sink_config(struct zero_dev *dev)
{
int result = 0;
struct usb_ep *ep;
@@ -653,8 +617,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
result = usb_ep_enable (ep, d);
if (result == 0) {
ep->driver_data = dev;
- if (source_sink_start_ep(ep, gfp_flags)
- != NULL) {
+ if (source_sink_start_ep(ep) != NULL) {
dev->in_ep = ep;
continue;
}
@@ -668,8 +631,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
result = usb_ep_enable (ep, d);
if (result == 0) {
ep->driver_data = dev;
- if (source_sink_start_ep(ep, gfp_flags)
- != NULL) {
+ if (source_sink_start_ep(ep) != NULL) {
dev->out_ep = ep;
continue;
}
@@ -701,7 +663,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
switch (status) {
- case 0: /* normal completion? */
+ case 0: /* normal completion? */
if (ep == dev->out_ep) {
/* loop this OUT packet back IN to the host */
req->zero = (req->actual < req->length);
@@ -735,7 +697,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
* rely on the hardware driver to clean up on disconnect or
* endpoint disable.
*/
- case -ECONNABORTED: /* hardware forced ep reset */
+ case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
free_ep_req (ep, req);
@@ -743,8 +705,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
}
}
-static int
-set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_loopback_config(struct zero_dev *dev)
{
int result = 0;
struct usb_ep *ep;
@@ -844,8 +805,7 @@ static void zero_reset_config (struct zero_dev *dev)
* code can do, perhaps by disallowing more than one configuration or
* by limiting configuration choices (like the pxa2xx).
*/
-static int
-zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
+static int zero_set_config(struct zero_dev *dev, unsigned number)
{
int result = 0;
struct usb_gadget *gadget = dev->gadget;
@@ -855,17 +815,17 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
if (gadget_is_sa1100 (gadget) && dev->config) {
/* tx fifo is full, but we can't clear it...*/
- INFO (dev, "can't change configurations\n");
+ ERROR(dev, "can't change configurations\n");
return -ESPIPE;
}
zero_reset_config (dev);
switch (number) {
case CONFIG_SOURCE_SINK:
- result = set_source_sink_config (dev, gfp_flags);
+ result = set_source_sink_config(dev);
break;
case CONFIG_LOOPBACK:
- result = set_loopback_config (dev, gfp_flags);
+ result = set_loopback_config(dev);
break;
default:
result = -EINVAL;
@@ -885,7 +845,7 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break;
case USB_SPEED_HIGH: speed = "high"; break;
- default: speed = "?"; break;
+ default: speed = "?"; break;
}
dev->config = number;
@@ -938,19 +898,17 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min (w_length, (u16) sizeof device_desc);
memcpy (req->buf, &device_desc, value);
break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
value = min (w_length, (u16) sizeof dev_qualifier);
memcpy (req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget->is_dualspeed)
+ if (!gadget_is_dualspeed(gadget))
break;
// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
value = config_buf (gadget, req->buf,
w_value >> 8,
@@ -984,7 +942,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
else
VDBG (dev, "HNP inactive\n");
spin_lock (&dev->lock);
- value = zero_set_config (dev, w_value, GFP_ATOMIC);
+ value = zero_set_config(dev, w_value);
spin_unlock (&dev->lock);
break;
case USB_REQ_GET_CONFIGURATION:
@@ -1013,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
* use this "reset the config" shortcut.
*/
zero_reset_config (dev);
- zero_set_config (dev, config, GFP_ATOMIC);
+ zero_set_config(dev, config);
value = 0;
}
spin_unlock (&dev->lock);
@@ -1163,7 +1121,7 @@ autoconf_fail:
}
EP_IN_NAME = ep->name;
ep->driver_data = ep; /* claim */
-
+
ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
if (!ep)
goto autoconf_fail;
@@ -1207,16 +1165,18 @@ autoconf_fail:
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- /* assume ep0 uses the same value for both speeds ... */
- dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+ if (gadget_is_dualspeed(gadget)) {
+ /* assume ep0 uses the same value for both speeds ... */
+ dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
- /* and that all endpoints are dual-speed */
- hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
- hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
-#endif
+ /* and that all endpoints are dual-speed */
+ hs_source_desc.bEndpointAddress =
+ fs_source_desc.bEndpointAddress;
+ hs_sink_desc.bEndpointAddress =
+ fs_sink_desc.bEndpointAddress;
+ }
- if (gadget->is_otg) {
+ if (gadget_is_otg(gadget)) {
otg_descriptor.bmAttributes |= USB_OTG_HNP,
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1294,23 +1254,18 @@ static struct usb_gadget_driver zero_driver = {
.suspend = zero_suspend,
.resume = zero_resume,
- .driver = {
+ .driver = {
.name = (char *) shortname,
.owner = THIS_MODULE,
},
};
-MODULE_AUTHOR ("David Brownell");
-MODULE_LICENSE ("Dual BSD/GPL");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
static int __init init (void)
{
- /* a real value would likely come through some id prom
- * or module option. this one takes at least two packets.
- */
- strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial);
-
return usb_gadget_register_driver (&zero_driver);
}
module_init (init);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 565d6ef4c4c..177e78ed241 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI
Enables support for PCI-bus plug-in USB controller cards.
If unsure, say Y.
+config USB_OHCI_HCD_SSB
+ bool "OHCI support for Broadcom SSB OHCI core"
+ depends on USB_OHCI_HCD && (SSB = y || SSB = CONFIG_USB_OHCI_HCD) && EXPERIMENTAL
+ default n
+ ---help---
+ Support for the Sonics Silicon Backplane (SSB) attached
+ Broadcom USB OHCI core.
+
+ This device is present in some embedded devices with
+ Broadcom based SSB bus.
+
+ If unsure, say N.
+
config USB_OHCI_BIG_ENDIAN_DESC
bool
depends on USB_OHCI_HCD
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index b1d19268cb2..766ef68a0b4 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -220,10 +220,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
-#ifdef CONFIG_PM
- .hub_suspend = ehci_hub_suspend,
- .hub_resume = ehci_hub_resume,
-#endif
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 35cdba10411..c1514442883 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -570,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd)
* are explicitly handed to companion controller(s), so no TT is
* involved with the root hub. (Except where one is integrated,
* and there's no companion controller unless maybe for USB OTG.)
+ *
+ * Turning on the CF flag will transfer ownership of all ports
+ * from the companions to the EHCI controller. If any of the
+ * companions are in the middle of a port reset at the time, it
+ * could cause trouble. Write-locking ehci_cf_port_reset_rwsem
+ * guarantees that no resets are in progress.
*/
+ down_write(&ehci_cf_port_reset_rwsem);
hcd->state = HC_STATE_RUNNING;
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+ up_write(&ehci_cf_port_reset_rwsem);
temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info (ehci,
@@ -719,7 +727,6 @@ dead:
*/
static int ehci_urb_enqueue (
struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
@@ -734,12 +741,12 @@ static int ehci_urb_enqueue (
default:
if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;
- return submit_async (ehci, ep, urb, &qtd_list, mem_flags);
+ return submit_async(ehci, urb, &qtd_list, mem_flags);
case PIPE_INTERRUPT:
if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;
- return intr_submit (ehci, ep, urb, &qtd_list, mem_flags);
+ return intr_submit(ehci, urb, &qtd_list, mem_flags);
case PIPE_ISOCHRONOUS:
if (urb->dev->speed == USB_SPEED_HIGH)
@@ -777,13 +784,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
* completions normally happen asynchronously
*/
-static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct ehci_qh *qh;
unsigned long flags;
+ int rc;
spin_lock_irqsave (&ehci->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
switch (usb_pipetype (urb->pipe)) {
// case PIPE_CONTROL:
// case PIPE_BULK:
@@ -838,7 +850,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
}
done:
spin_unlock_irqrestore (&ehci->lock, flags);
- return 0;
+ return rc;
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 0dcb4164dc8..735db4aec83 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -451,7 +451,7 @@ ehci_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/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index a7816e392a8..ad0d4965f2f 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -58,8 +58,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
if (!retval)
ehci_dbg(ehci, "MWI active\n");
- ehci_port_power(ehci, 0);
-
return 0;
}
@@ -156,8 +154,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
break;
}
- if (ehci_is_TDI(ehci))
- ehci_reset(ehci);
+ ehci_reset(ehci);
/* at least the Genesys GL880S needs fixup here */
temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c
index 4f99b0eb27b..452d4b1bc85 100644
--- a/drivers/usb/host/ehci-ppc-soc.c
+++ b/drivers/usb/host/ehci-ppc-soc.c
@@ -160,10 +160,8 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = {
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
-#ifdef CONFIG_PM
- .hub_suspend = ehci_hub_suspend,
- .hub_resume = ehci_hub_resume,
-#endif
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
};
static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index 829fe649a98..03a6b2f4e6e 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -47,7 +47,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
if (result)
return result;
- ehci_port_power(ehci, 0);
+ ehci_reset(ehci);
return result;
}
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 140bfa423e0..b10f39c047e 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -139,63 +139,65 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
-static void qtd_copy_status (
+static int qtd_copy_status (
struct ehci_hcd *ehci,
struct urb *urb,
size_t length,
u32 token
)
{
+ int status = -EINPROGRESS;
+
/* count IN/OUT bytes, not SETUP (even short packets) */
if (likely (QTD_PID (token) != 2))
urb->actual_length += length - QTD_LENGTH (token);
/* don't modify error codes */
- if (unlikely (urb->status != -EINPROGRESS))
- return;
+ if (unlikely(urb->unlinked))
+ return status;
/* force cleanup after short read; not always an error */
if (unlikely (IS_SHORT_READ (token)))
- urb->status = -EREMOTEIO;
+ status = -EREMOTEIO;
/* serious "can't proceed" faults reported by the hardware */
if (token & QTD_STS_HALT) {
if (token & QTD_STS_BABBLE) {
/* FIXME "must" disable babbling device's port too */
- urb->status = -EOVERFLOW;
+ status = -EOVERFLOW;
} else if (token & QTD_STS_MMF) {
/* fs/ls interrupt xfer missed the complete-split */
- urb->status = -EPROTO;
+ status = -EPROTO;
} else if (token & QTD_STS_DBE) {
- urb->status = (QTD_PID (token) == 1) /* IN ? */
+ status = (QTD_PID (token) == 1) /* IN ? */
? -ENOSR /* hc couldn't read data */
: -ECOMM; /* hc couldn't write data */
} else if (token & QTD_STS_XACT) {
/* timeout, bad crc, wrong PID, etc; retried */
if (QTD_CERR (token))
- urb->status = -EPIPE;
+ status = -EPIPE;
else {
ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
urb->dev->devpath,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out");
- urb->status = -EPROTO;
+ status = -EPROTO;
}
/* CERR nonzero + no errors + halt --> stall */
} else if (QTD_CERR (token))
- urb->status = -EPIPE;
+ status = -EPIPE;
else /* unknown */
- urb->status = -EPROTO;
+ status = -EPROTO;
ehci_vdbg (ehci,
"dev%d ep%d%s qtd token %08x --> status %d\n",
usb_pipedevice (urb->pipe),
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
- token, urb->status);
+ token, status);
/* if async CSPLIT failed, try cleaning out the TT buffer */
- if (urb->status != -EPIPE
+ if (status != -EPIPE
&& urb->dev->tt && !usb_pipeint (urb->pipe)
&& ((token & QTD_STS_MMF) != 0
|| QTD_CERR(token) == 0)
@@ -212,10 +214,12 @@ static void qtd_copy_status (
usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
}
}
+
+ return status;
}
static void
-ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
+ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
__releases(ehci->lock)
__acquires(ehci->lock)
{
@@ -231,25 +235,13 @@ __acquires(ehci->lock)
qh_put (qh);
}
- spin_lock (&urb->lock);
- urb->hcpriv = NULL;
- switch (urb->status) {
- case -EINPROGRESS: /* success */
- urb->status = 0;
- default: /* fault */
- COUNT (ehci->stats.complete);
- break;
- case -EREMOTEIO: /* fault or normal */
- if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
- urb->status = 0;
- COUNT (ehci->stats.complete);
- break;
- case -ECONNRESET: /* canceled */
- case -ENOENT:
- COUNT (ehci->stats.unlink);
- break;
+ if (unlikely(urb->unlinked)) {
+ COUNT(ehci->stats.unlink);
+ } else {
+ if (likely(status == -EINPROGRESS))
+ status = 0;
+ COUNT(ehci->stats.complete);
}
- spin_unlock (&urb->lock);
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
@@ -257,13 +249,14 @@ __acquires(ehci->lock)
__FUNCTION__, urb->dev->devpath, urb,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
- urb->status,
+ status,
urb->actual_length, urb->transfer_buffer_length);
#endif
/* complete() can reenter this HCD */
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
spin_unlock (&ehci->lock);
- usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb);
+ usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
spin_lock (&ehci->lock);
}
@@ -283,6 +276,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
struct ehci_qtd *last = NULL, *end = qh->dummy;
struct list_head *entry, *tmp;
+ int last_status = -EINPROGRESS;
int stopped;
unsigned count = 0;
int do_status = 0;
@@ -311,6 +305,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
struct ehci_qtd *qtd;
struct urb *urb;
u32 token = 0;
+ int qtd_status;
qtd = list_entry (entry, struct ehci_qtd, qtd_list);
urb = qtd->urb;
@@ -318,11 +313,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* clean up any state from previous QTD ...*/
if (last) {
if (likely (last->urb != urb)) {
- ehci_urb_done (ehci, last->urb);
+ ehci_urb_done(ehci, last->urb, last_status);
count++;
}
ehci_qtd_free (ehci, last);
last = NULL;
+ last_status = -EINPROGRESS;
}
/* ignore urbs submitted during completions we reported */
@@ -358,13 +354,14 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
stopped = 1;
if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
- urb->status = -ESHUTDOWN;
+ last_status = -ESHUTDOWN;
/* ignore active urbs unless some previous qtd
* for the urb faulted (including short read) or
* its urb was canceled. we may patch qh or qtds.
*/
- if (likely (urb->status == -EINPROGRESS))
+ if (likely(last_status == -EINPROGRESS &&
+ !urb->unlinked))
continue;
/* issue status after short control reads */
@@ -392,11 +389,14 @@ halt:
}
/* remove it from the queue */
- spin_lock (&urb->lock);
- qtd_copy_status (ehci, urb, qtd->length, token);
- do_status = (urb->status == -EREMOTEIO)
- && usb_pipecontrol (urb->pipe);
- spin_unlock (&urb->lock);
+ qtd_status = qtd_copy_status(ehci, urb, qtd->length, token);
+ if (unlikely(qtd_status == -EREMOTEIO)) {
+ do_status = (!urb->unlinked &&
+ usb_pipecontrol(urb->pipe));
+ qtd_status = 0;
+ }
+ if (likely(last_status == -EINPROGRESS))
+ last_status = qtd_status;
if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
last = list_entry (qtd->qtd_list.prev,
@@ -409,7 +409,7 @@ halt:
/* last urb's completion might still need calling */
if (likely (last != NULL)) {
- ehci_urb_done (ehci, last->urb);
+ ehci_urb_done(ehci, last->urb, last_status);
count++;
ehci_qtd_free (ehci, last);
}
@@ -913,7 +913,6 @@ static struct ehci_qh *qh_append_tds (
static int
submit_async (
struct ehci_hcd *ehci,
- struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
gfp_t mem_flags
@@ -922,10 +921,10 @@ submit_async (
int epnum;
unsigned long flags;
struct ehci_qh *qh = NULL;
- int rc = 0;
+ int rc;
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
- epnum = ep->desc.bEndpointAddress;
+ epnum = urb->ep->desc.bEndpointAddress;
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
@@ -933,7 +932,7 @@ submit_async (
__FUNCTION__, urb->dev->devpath, urb,
epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
urb->transfer_buffer_length,
- qtd, ep->hcpriv);
+ qtd, urb->ep->hcpriv);
#endif
spin_lock_irqsave (&ehci->lock, flags);
@@ -942,9 +941,13 @@ submit_async (
rc = -ESHUTDOWN;
goto done;
}
+ rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+ if (unlikely(rc))
+ goto done;
- qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+ qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
if (unlikely(qh == NULL)) {
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
rc = -ENOMEM;
goto done;
}
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index e682f2342ef..80d99bce2b3 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -797,7 +797,6 @@ done:
static int intr_submit (
struct ehci_hcd *ehci,
- struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
gfp_t mem_flags
@@ -805,23 +804,26 @@ static int intr_submit (
unsigned epnum;
unsigned long flags;
struct ehci_qh *qh;
- int status = 0;
+ int status;
struct list_head empty;
/* get endpoint and transfer/schedule data */
- epnum = ep->desc.bEndpointAddress;
+ epnum = urb->ep->desc.bEndpointAddress;
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
- goto done;
+ goto done_not_linked;
}
+ status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+ if (unlikely(status))
+ goto done_not_linked;
/* get qh and force any scheduling errors */
INIT_LIST_HEAD (&empty);
- qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
+ qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv);
if (qh == NULL) {
status = -ENOMEM;
goto done;
@@ -832,13 +834,16 @@ static int intr_submit (
}
/* then queue the urb's tds to the qh */
- qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+ qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
BUG_ON (qh == NULL);
/* ... update usbfs periodic stats */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
done:
+ if (unlikely(status))
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
if (status)
qtd_list_free (ehci, urb, qtd_list);
@@ -1622,7 +1627,7 @@ itd_complete (
/* give urb back to the driver ... can be out-of-order */
dev = urb->dev;
- ehci_urb_done (ehci, urb);
+ ehci_urb_done(ehci, urb, 0);
urb = NULL;
/* defer stopping schedule; completion can submit */
@@ -1686,12 +1691,19 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
- &ehci_to_hcd(ehci)->flags)))
+ &ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
- else
- status = iso_stream_schedule (ehci, urb, stream);
+ goto done_not_linked;
+ }
+ status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+ if (unlikely(status))
+ goto done_not_linked;
+ status = iso_stream_schedule(ehci, urb, stream);
if (likely (status == 0))
itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+ else
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
done:
@@ -1988,7 +2000,7 @@ sitd_complete (
/* give urb back to the driver */
dev = urb->dev;
- ehci_urb_done (ehci, urb);
+ ehci_urb_done(ehci, urb, 0);
urb = NULL;
/* defer stopping schedule; completion can submit */
@@ -2049,12 +2061,19 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
- &ehci_to_hcd(ehci)->flags)))
+ &ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
- else
- status = iso_stream_schedule (ehci, urb, stream);
+ goto done_not_linked;
+ }
+ status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+ if (unlikely(status))
+ goto done_not_linked;
+ status = iso_stream_schedule(ehci, urb, stream);
if (status == 0)
sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+ else
+ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
done:
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 5c851a36de7..c27417f5b9d 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -277,12 +277,11 @@ static void preproc_atl_queue(struct isp116x *isp116x)
processed urbs.
*/
static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
- struct urb *urb)
+ struct urb *urb, int status)
__releases(isp116x->lock) __acquires(isp116x->lock)
{
unsigned i;
- urb->hcpriv = NULL;
ep->error_count = 0;
if (usb_pipecontrol(urb->pipe))
@@ -290,8 +289,9 @@ __releases(isp116x->lock) __acquires(isp116x->lock)
urb_dbg(urb, "Finish");
+ usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb);
spin_unlock(&isp116x->lock);
- usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
+ usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status);
spin_lock(&isp116x->lock);
/* take idle endpoints out of the schedule */
@@ -445,12 +445,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
if (PTD_GET_ACTIVE(ptd)
|| (cc != TD_CC_NOERROR && cc < 0x0E))
break;
- if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
- urb->actual_length <
- urb->transfer_buffer_length)
- status = -EREMOTEIO;
- else
- status = 0;
+ status = 0;
ep->nextpid = 0;
break;
default:
@@ -458,14 +453,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
}
done:
- if (status != -EINPROGRESS) {
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = status;
- spin_unlock(&urb->lock);
- }
- if (urb->status != -EINPROGRESS)
- finish_request(isp116x, ep, urb);
+ if (status != -EINPROGRESS || urb->unlinked)
+ finish_request(isp116x, ep, urb, status);
}
}
@@ -673,7 +662,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load)
/*-----------------------------------------------------------------*/
static int isp116x_urb_enqueue(struct usb_hcd *hcd,
- struct usb_host_endpoint *hep, struct urb *urb,
+ struct urb *urb,
gfp_t mem_flags)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
@@ -682,6 +671,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
int is_out = !usb_pipein(pipe);
int type = usb_pipetype(pipe);
int epnum = usb_pipeendpoint(pipe);
+ struct usb_host_endpoint *hep = urb->ep;
struct isp116x_ep *ep = NULL;
unsigned long flags;
int i;
@@ -705,7 +695,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
if (!HC_IS_RUNNING(hcd->state)) {
kfree(ep);
ret = -ENODEV;
- goto fail;
+ goto fail_not_linked;
+ }
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret) {
+ kfree(ep);
+ goto fail_not_linked;
}
if (hep->hcpriv)
@@ -808,16 +803,13 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
}
}
- /* in case of unlink-during-submit */
- if (urb->status != -EINPROGRESS) {
- finish_request(isp116x, ep, urb);
- ret = 0;
- goto fail;
- }
urb->hcpriv = hep;
start_atl_transfers(isp116x);
fail:
+ if (ret)
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ fail_not_linked:
spin_unlock_irqrestore(&isp116x->lock, flags);
return ret;
}
@@ -825,20 +817,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
/*
Dequeue URBs.
*/
-static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
struct usb_host_endpoint *hep;
struct isp116x_ep *ep, *ep_act;
unsigned long flags;
+ int rc;
spin_lock_irqsave(&isp116x->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
hep = urb->hcpriv;
- /* URB already unlinked (or never linked)? */
- if (!hep) {
- spin_unlock_irqrestore(&isp116x->lock, flags);
- return 0;
- }
ep = hep->hcpriv;
WARN_ON(hep != ep->hep);
@@ -855,10 +848,10 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
}
if (urb)
- finish_request(isp116x, ep, urb);
-
+ finish_request(isp116x, ep, urb, status);
+ done:
spin_unlock_irqrestore(&isp116x->lock, flags);
- return 0;
+ return rc;
}
static void isp116x_endpoint_disable(struct usb_hcd *hcd,
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index f61c6cdd06f..ebab5ce8f5c 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -24,7 +24,7 @@
* small: 0) header + data packets 1) just header
*/
static void __maybe_unused
-urb_print (struct urb * urb, char * str, int small)
+urb_print(struct urb * urb, char * str, int small, int status)
{
unsigned int pipe= urb->pipe;
@@ -34,7 +34,7 @@ urb_print (struct urb * urb, char * str, int small)
}
#ifndef OHCI_VERBOSE_DEBUG
- if (urb->status != 0)
+ if (status != 0)
#endif
dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
str,
@@ -46,7 +46,7 @@ urb_print (struct urb * urb, char * str, int small)
urb->transfer_flags,
urb->actual_length,
urb->transfer_buffer_length,
- urb->status);
+ status);
#ifdef OHCI_VERBOSE_DEBUG
if (!small) {
@@ -66,7 +66,7 @@ urb_print (struct urb * urb, char * str, int small)
urb->transfer_buffer_length: urb->actual_length;
for (i = 0; i < 16 && i < len; i++)
printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
- printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+ printk ("%s stat:%d\n", i < len? "...": "", status);
}
}
#endif
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 6edf4097d2d..704f33fdd2f 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -80,8 +80,10 @@ static const char hcd_name [] = "ohci_hcd";
static void ohci_dump (struct ohci_hcd *ohci, int verbose);
static int ohci_init (struct ohci_hcd *ohci);
static void ohci_stop (struct usb_hcd *hcd);
+
+#if defined(CONFIG_PM) || defined(CONFIG_PCI)
static int ohci_restart (struct ohci_hcd *ohci);
-static void ohci_quirk_nec_worker (struct work_struct *work);
+#endif
#include "ohci-hub.c"
#include "ohci-dbg.c"
@@ -118,7 +120,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
*/
static int ohci_urb_enqueue (
struct usb_hcd *hcd,
- struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
@@ -131,11 +132,11 @@ static int ohci_urb_enqueue (
int retval = 0;
#ifdef OHCI_VERBOSE_DEBUG
- urb_print (urb, "SUB", usb_pipein (pipe));
+ urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS);
#endif
/* every endpoint has a ed, locate and maybe (re)initialize it */
- if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
+ if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
return -ENOMEM;
/* for the private part of the URB we need the number of TDs (size) */
@@ -200,22 +201,17 @@ static int ohci_urb_enqueue (
retval = -ENODEV;
goto fail;
}
-
- /* in case of unlink-during-submit */
- spin_lock (&urb->lock);
- if (urb->status != -EINPROGRESS) {
- spin_unlock (&urb->lock);
- urb->hcpriv = urb_priv;
- finish_urb (ohci, urb);
- retval = 0;
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval)
goto fail;
- }
/* schedule the ed if needed */
if (ed->state == ED_IDLE) {
retval = ed_schedule (ohci, ed);
- if (retval < 0)
- goto fail0;
+ if (retval < 0) {
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ goto fail;
+ }
if (ed->type == PIPE_ISOCHRONOUS) {
u16 frame = ohci_frame_no(ohci);
@@ -239,8 +235,6 @@ static int ohci_urb_enqueue (
urb->hcpriv = urb_priv;
td_submit_urb (ohci, urb);
-fail0:
- spin_unlock (&urb->lock);
fail:
if (retval)
urb_free_priv (ohci, urb_priv);
@@ -249,22 +243,26 @@ fail:
}
/*
- * decouple the URB from the HC queues (TDs, urb_priv); it's
- * already marked using urb->status. reporting is always done
+ * decouple the URB from the HC queues (TDs, urb_priv).
+ * reporting is always done
* asynchronously, and we might be dealing with an urb that's
* partially transferred, or an ED with other urbs being unlinked.
*/
-static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags;
+ int rc;
#ifdef OHCI_VERBOSE_DEBUG
- urb_print (urb, "UNLINK", 1);
+ urb_print(urb, "UNLINK", 1, status);
#endif
spin_lock_irqsave (&ohci->lock, flags);
- if (HC_IS_RUNNING(hcd->state)) {
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc) {
+ ; /* Do nothing */
+ } else if (HC_IS_RUNNING(hcd->state)) {
urb_priv_t *urb_priv;
/* Unless an IRQ completed the unlink while it was being
@@ -282,10 +280,10 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
* any more ... just clean up every urb's memory.
*/
if (urb->hcpriv)
- finish_urb (ohci, urb);
+ finish_urb(ohci, urb, status);
}
spin_unlock_irqrestore (&ohci->lock, flags);
- return 0;
+ return rc;
}
/*-------------------------------------------------------------------------*/
@@ -314,6 +312,8 @@ rescan:
if (!HC_IS_RUNNING (hcd->state)) {
sanitize:
ed->state = ED_IDLE;
+ if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+ ohci->eds_scheduled--;
finish_unlinks (ohci, 0);
}
@@ -321,7 +321,12 @@ sanitize:
case ED_UNLINK: /* wait for hw to finish? */
/* major IRQ delivery trouble loses INTR_SF too... */
if (limit-- == 0) {
- ohci_warn (ohci, "IRQ INTR_SF lossage\n");
+ ohci_warn(ohci, "ED unlink timeout\n");
+ if (quirk_zfmicro(ohci)) {
+ ohci_warn(ohci, "Attempting ZF TD recovery\n");
+ ohci->ed_to_check = ed;
+ ohci->zf_delay = 2;
+ }
goto sanitize;
}
spin_unlock_irqrestore (&ohci->lock, flags);
@@ -379,6 +384,93 @@ ohci_shutdown (struct usb_hcd *hcd)
(void) ohci_readl (ohci, &ohci->regs->control);
}
+static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
+{
+ return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0
+ && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK)
+ == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK)
+ && !list_empty(&ed->td_list);
+}
+
+/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes
+ * an interrupt TD but neglects to add it to the donelist. On systems with
+ * this chipset, we need to periodically check the state of the queues to look
+ * for such "lost" TDs.
+ */
+static void unlink_watchdog_func(unsigned long _ohci)
+{
+ unsigned long flags;
+ unsigned max;
+ unsigned seen_count = 0;
+ unsigned i;
+ struct ed **seen = NULL;
+ struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci;
+
+ spin_lock_irqsave(&ohci->lock, flags);
+ max = ohci->eds_scheduled;
+ if (!max)
+ goto done;
+
+ if (ohci->ed_to_check)
+ goto out;
+
+ seen = kcalloc(max, sizeof *seen, GFP_ATOMIC);
+ if (!seen)
+ goto out;
+
+ for (i = 0; i < NUM_INTS; i++) {
+ struct ed *ed = ohci->periodic[i];
+
+ while (ed) {
+ unsigned temp;
+
+ /* scan this branch of the periodic schedule tree */
+ for (temp = 0; temp < seen_count; temp++) {
+ if (seen[temp] == ed) {
+ /* we've checked it and what's after */
+ ed = NULL;
+ break;
+ }
+ }
+ if (!ed)
+ break;
+ seen[seen_count++] = ed;
+ if (!check_ed(ohci, ed)) {
+ ed = ed->ed_next;
+ continue;
+ }
+
+ /* HC's TD list is empty, but HCD sees at least one
+ * TD that's not been sent through the donelist.
+ */
+ ohci->ed_to_check = ed;
+ ohci->zf_delay = 2;
+
+ /* The HC may wait until the next frame to report the
+ * TD as done through the donelist and INTR_WDH. (We
+ * just *assume* it's not a multi-TD interrupt URB;
+ * those could defer the IRQ more than one frame, using
+ * DI...) Check again after the next INTR_SF.
+ */
+ ohci_writel(ohci, OHCI_INTR_SF,
+ &ohci->regs->intrstatus);
+ ohci_writel(ohci, OHCI_INTR_SF,
+ &ohci->regs->intrenable);
+
+ /* flush those writes */
+ (void) ohci_readl(ohci, &ohci->regs->control);
+
+ goto out;
+ }
+ }
+out:
+ kfree(seen);
+ if (ohci->eds_scheduled)
+ mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
+done:
+ spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
/*-------------------------------------------------------------------------*
* HC functions
*-------------------------------------------------------------------------*/
@@ -616,6 +708,15 @@ retry:
mdelay ((temp >> 23) & 0x1fe);
hcd->state = HC_STATE_RUNNING;
+ if (quirk_zfmicro(ohci)) {
+ /* Create timer to watch for bad queue state on ZF Micro */
+ setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func,
+ (unsigned long) ohci);
+
+ ohci->eds_scheduled = 0;
+ ohci->ed_to_check = NULL;
+ }
+
ohci_dump (ohci, 1);
return 0;
@@ -629,10 +730,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct ohci_regs __iomem *regs = ohci->regs;
- int ints;
+ int ints;
/* we can eliminate a (slow) ohci_readl()
- if _only_ WDH caused this irq */
+ * if _only_ WDH caused this irq
+ */
if ((ohci->hcca->done_head != 0)
&& ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
& 0x01)) {
@@ -651,7 +753,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
if (ints & OHCI_INTR_UE) {
// e.g. due to PCI Master/Target Abort
- if (ohci->flags & OHCI_QUIRK_NEC) {
+ if (quirk_nec(ohci)) {
/* Workaround for a silicon bug in some NEC chips used
* in Apple's PowerBooks. Adapted from Darwin code.
*/
@@ -713,6 +815,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
}
+ if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
+ spin_lock(&ohci->lock);
+ if (ohci->ed_to_check) {
+ struct ed *ed = ohci->ed_to_check;
+
+ if (check_ed(ohci, ed)) {
+ /* HC thinks the TD list is empty; HCD knows
+ * at least one TD is outstanding
+ */
+ if (--ohci->zf_delay == 0) {
+ struct td *td = list_entry(
+ ed->td_list.next,
+ struct td, td_list);
+ ohci_warn(ohci,
+ "Reclaiming orphan TD %p\n",
+ td);
+ takeback_td(ohci, td);
+ ohci->ed_to_check = NULL;
+ }
+ } else
+ ohci->ed_to_check = NULL;
+ }
+ spin_unlock(&ohci->lock);
+ }
+
/* could track INTR_SO to reduce available PCI/... bandwidth */
/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
@@ -721,7 +848,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
spin_lock (&ohci->lock);
if (ohci->ed_rm_list)
finish_unlinks (ohci, ohci_frame_no(ohci));
- if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
+ if ((ints & OHCI_INTR_SF) != 0
+ && !ohci->ed_rm_list
+ && !ohci->ed_to_check
&& HC_IS_RUNNING(hcd->state))
ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
spin_unlock (&ohci->lock);
@@ -751,6 +880,9 @@ static void ohci_stop (struct usb_hcd *hcd)
free_irq(hcd->irq, hcd);
hcd->irq = -1;
+ if (quirk_zfmicro(ohci))
+ del_timer(&ohci->unlink_watchdog);
+
remove_debug_files (ohci);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
@@ -764,6 +896,8 @@ static void ohci_stop (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
+#if defined(CONFIG_PM) || defined(CONFIG_PCI)
+
/* must not be called from interrupt context */
static int ohci_restart (struct ohci_hcd *ohci)
{
@@ -798,9 +932,8 @@ static int ohci_restart (struct ohci_hcd *ohci)
ed, ed->state);
}
- spin_lock (&urb->lock);
- urb->status = -ESHUTDOWN;
- spin_unlock (&urb->lock);
+ if (!urb->unlinked)
+ urb->unlinked = -ESHUTDOWN;
}
finish_unlinks (ohci, 0);
spin_unlock_irq(&ohci->lock);
@@ -826,26 +959,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
return 0;
}
-/*-------------------------------------------------------------------------*/
-
-/* NEC workaround */
-static void ohci_quirk_nec_worker(struct work_struct *work)
-{
- struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
- int status;
-
- status = ohci_init(ohci);
- if (status != 0) {
- ohci_err(ohci, "Restarting NEC controller failed "
- "in ohci_init, %d\n", status);
- return;
- }
-
- status = ohci_restart(ohci);
- if (status != 0)
- ohci_err(ohci, "Restarting NEC controller failed "
- "in ohci_restart, %d\n", status);
-}
+#endif
/*-------------------------------------------------------------------------*/
@@ -926,11 +1040,17 @@ MODULE_LICENSE ("GPL");
#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver
#endif
+#ifdef CONFIG_USB_OHCI_HCD_SSB
+#include "ohci-ssb.c"
+#define SSB_OHCI_DRIVER ssb_ohci_driver
+#endif
+
#if !defined(PCI_DRIVER) && \
!defined(PLATFORM_DRIVER) && \
!defined(OF_PLATFORM_DRIVER) && \
!defined(SA1111_DRIVER) && \
- !defined(PS3_SYSTEM_BUS_DRIVER)
+ !defined(PS3_SYSTEM_BUS_DRIVER) && \
+ !defined(SSB_OHCI_DRIVER)
#error "missing bus glue for ohci-hcd"
#endif
@@ -975,10 +1095,20 @@ static int __init ohci_hcd_mod_init(void)
goto error_pci;
#endif
+#ifdef SSB_OHCI_DRIVER
+ retval = ssb_driver_register(&SSB_OHCI_DRIVER);
+ if (retval)
+ goto error_ssb;
+#endif
+
return retval;
/* Error path */
+#ifdef SSB_OHCI_DRIVER
+ error_ssb:
+#endif
#ifdef PCI_DRIVER
+ pci_unregister_driver(&PCI_DRIVER);
error_pci:
#endif
#ifdef SA1111_DRIVER
@@ -1003,6 +1133,9 @@ module_init(ohci_hcd_mod_init);
static void __exit ohci_hcd_mod_exit(void)
{
+#ifdef SSB_OHCI_DRIVER
+ ssb_driver_unregister(&SSB_OHCI_DRIVER);
+#endif
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
#endif
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index 450c7b460c5..2f20d3dc895 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
ohci->next_statechange = jiffies;
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
- INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index a5e2eb85d07..d0360f65ebd 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -84,7 +84,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci->flags |= OHCI_QUIRK_ZFMICRO;
- ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+ ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n");
return 0;
}
@@ -113,11 +113,31 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
/* Check for NEC chip and apply quirk for allegedly lost interrupts.
*/
+
+static void ohci_quirk_nec_worker(struct work_struct *work)
+{
+ struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
+ int status;
+
+ status = ohci_init(ohci);
+ if (status != 0) {
+ ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+ "ohci_init", status);
+ return;
+ }
+
+ status = ohci_restart(ohci);
+ if (status != 0)
+ ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+ "ohci_restart", status);
+}
+
static int ohci_quirk_nec(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci->flags |= OHCI_QUIRK_NEC;
+ INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker);
ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
return 0;
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index c43b66acd4d..0a742692015 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -134,8 +134,11 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
}
ohci = hcd_to_ohci(hcd);
- if (is_bigendian)
+ if (is_bigendian) {
ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+ if (of_device_is_compatible(dn, "mpc5200-ohci"))
+ ohci->flags |= OHCI_QUIRK_FRAME_NO;
+ }
ohci_hcd_init(ohci);
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 1a2e1777ca6..f95be1896b0 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -73,6 +73,11 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
ohci = hcd_to_ohci(hcd);
ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+#ifdef CONFIG_PPC_MPC52xx
+ /* MPC52xx doesn't need frame_no shift */
+ ohci->flags |= OHCI_QUIRK_FRAME_NO;
+#endif
ohci_hcd_init(ohci);
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 830a3fe8615..51817322232 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -36,29 +36,15 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
* PRECONDITION: ohci lock held, irqs blocked.
*/
static void
-finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status)
__releases(ohci->lock)
__acquires(ohci->lock)
{
// ASSERT (urb->hcpriv != 0);
urb_free_priv (ohci, urb->hcpriv);
- urb->hcpriv = NULL;
-
- spin_lock (&urb->lock);
- if (likely (urb->status == -EINPROGRESS))
- urb->status = 0;
- /* report short control reads right even though the data TD always
- * has TD_R set. (much simpler, but creates the 1-td limit.)
- */
- if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK)
- && unlikely (usb_pipecontrol (urb->pipe))
- && urb->actual_length < urb->transfer_buffer_length
- && usb_pipein (urb->pipe)
- && urb->status == 0) {
- urb->status = -EREMOTEIO;
- }
- spin_unlock (&urb->lock);
+ if (likely(status == -EINPROGRESS))
+ status = 0;
switch (usb_pipetype (urb->pipe)) {
case PIPE_ISOCHRONOUS:
@@ -70,12 +56,13 @@ __acquires(ohci->lock)
}
#ifdef OHCI_VERBOSE_DEBUG
- urb_print (urb, "RET", usb_pipeout (urb->pipe));
+ urb_print(urb, "RET", usb_pipeout (urb->pipe), status);
#endif
/* urb->complete() can reenter this HCD */
+ usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb);
spin_unlock (&ohci->lock);
- usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
+ usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status);
spin_lock (&ohci->lock);
/* stop periodic dma if it's not needed */
@@ -179,6 +166,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
ed->ed_prev = NULL;
ed->ed_next = NULL;
ed->hwNextED = 0;
+ if (quirk_zfmicro(ohci)
+ && (ed->type == PIPE_INTERRUPT)
+ && !(ohci->eds_scheduled++))
+ mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
wmb ();
/* we care about rm_list when setting CLE/BLE in case the HC was at
@@ -708,19 +699,18 @@ static void td_submit_urb (
* Done List handling functions
*-------------------------------------------------------------------------*/
-/* calculate transfer length/status and update the urb
- * PRECONDITION: irqsafe (only for urb->status locking)
- */
-static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
+/* calculate transfer length/status and update the urb */
+static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td)
{
u32 tdINFO = hc32_to_cpup (ohci, &td->hwINFO);
int cc = 0;
+ int status = -EINPROGRESS;
list_del (&td->td_list);
/* ISO ... drivers see per-TD length/status */
if (tdINFO & TD_ISO) {
- u16 tdPSW = ohci_hwPSW (ohci, td, 0);
+ u16 tdPSW = ohci_hwPSW(ohci, td, 0);
int dlen = 0;
/* NOTE: assumes FC in tdINFO == 0, and that
@@ -729,7 +719,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
cc = (tdPSW >> 12) & 0xF;
if (tdINFO & TD_CC) /* hc didn't touch? */
- return;
+ return status;
if (usb_pipeout (urb->pipe))
dlen = urb->iso_frame_desc [td->index].length;
@@ -762,12 +752,8 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
if (cc == TD_DATAUNDERRUN
&& !(urb->transfer_flags & URB_SHORT_NOT_OK))
cc = TD_CC_NOERROR;
- if (cc != TD_CC_NOERROR && cc < 0x0E) {
- spin_lock (&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = cc_to_error [cc];
- spin_unlock (&urb->lock);
- }
+ if (cc != TD_CC_NOERROR && cc < 0x0E)
+ status = cc_to_error[cc];
/* count all non-empty packets except control SETUP packet */
if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
@@ -786,14 +772,15 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
urb->actual_length,
urb->transfer_buffer_length);
}
+ return status;
}
/*-------------------------------------------------------------------------*/
-static inline struct td *
-ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
+static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc)
{
struct urb *urb = td->urb;
+ urb_priv_t *urb_priv = urb->hcpriv;
struct ed *ed = td->ed;
struct list_head *tmp = td->td_list.next;
__hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
@@ -805,13 +792,12 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
wmb ();
ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
- /* put any later tds from this urb onto the donelist, after 'td',
- * order won't matter here: no errors, and nothing was transferred.
- * also patch the ed so it looks as if those tds completed normally.
+ /* Get rid of all later tds from this urb. We don't have
+ * to be careful: no errors and nothing was transferred.
+ * Also patch the ed so it looks as if those tds completed normally.
*/
while (tmp != &ed->td_list) {
struct td *next;
- __hc32 info;
next = list_entry (tmp, struct td, td_list);
tmp = next->td_list.next;
@@ -826,14 +812,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
* then we need to leave the control STATUS packet queued
* and clear ED_SKIP.
*/
- info = next->hwINFO;
- info |= cpu_to_hc32 (ohci, TD_DONE);
- info &= ~cpu_to_hc32 (ohci, TD_CC);
- next->hwINFO = info;
-
- next->next_dl_td = rev;
- rev = next;
+ list_del(&next->td_list);
+ urb_priv->td_cnt++;
ed->hwHeadP = next->hwNextTD | toggle;
}
@@ -859,8 +840,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
hc32_to_cpu (ohci, td->hwINFO),
cc, cc_to_error [cc]);
}
-
- return rev;
}
/* replies to the request have to be on a FIFO basis so
@@ -897,7 +876,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
*/
if (cc != TD_CC_NOERROR
&& (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
- td_rev = ed_halted (ohci, td, cc, td_rev);
+ ed_halted(ohci, td, cc);
td->next_dl_td = td_rev;
td_rev = td;
@@ -940,8 +919,12 @@ skip_ed:
TD_MASK;
/* INTR_WDH may need to clean up first */
- if (td->td_dma != head)
- goto skip_ed;
+ if (td->td_dma != head) {
+ if (ed == ohci->ed_to_check)
+ ohci->ed_to_check = NULL;
+ else
+ goto skip_ed;
+ }
}
}
@@ -974,7 +957,7 @@ rescan_this:
urb = td->urb;
urb_priv = td->urb->hcpriv;
- if (urb->status == -EINPROGRESS) {
+ if (!urb->unlinked) {
prev = &td->hwNextTD;
continue;
}
@@ -990,7 +973,7 @@ rescan_this:
/* if URB is done, clean up */
if (urb_priv->td_cnt == urb_priv->length) {
modified = completed = 1;
- finish_urb (ohci, urb);
+ finish_urb(ohci, urb, 0);
}
}
if (completed && !list_empty (&ed->td_list))
@@ -998,6 +981,8 @@ rescan_this:
/* ED's now officially unlinked, hc doesn't see */
ed->state = ED_IDLE;
+ if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+ ohci->eds_scheduled--;
ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
ed->hwNextED = 0;
wmb ();
@@ -1021,7 +1006,7 @@ rescan_this:
if (ohci->ed_controltail) {
command |= OHCI_CLF;
- if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+ if (quirk_zfmicro(ohci))
mdelay(1);
if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
control |= OHCI_CTRL_CLE;
@@ -1031,7 +1016,7 @@ rescan_this:
}
if (ohci->ed_bulktail) {
command |= OHCI_BLF;
- if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+ if (quirk_zfmicro(ohci))
mdelay(1);
if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
control |= OHCI_CTRL_BLE;
@@ -1043,13 +1028,13 @@ rescan_this:
/* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
if (control) {
ohci->hc_control |= control;
- if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+ if (quirk_zfmicro(ohci))
mdelay(1);
ohci_writel (ohci, ohci->hc_control,
&ohci->regs->control);
}
if (command) {
- if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+ if (quirk_zfmicro(ohci))
mdelay(1);
ohci_writel (ohci, command, &ohci->regs->cmdstatus);
}
@@ -1061,11 +1046,60 @@ rescan_this:
/*-------------------------------------------------------------------------*/
/*
+ * Used to take back a TD from the host controller. This would normally be
+ * called from within dl_done_list, however it may be called directly if the
+ * HC no longer sees the TD and it has not appeared on the donelist (after
+ * two frames). This bug has been observed on ZF Micro systems.
+ */
+static void takeback_td(struct ohci_hcd *ohci, struct td *td)
+{
+ struct urb *urb = td->urb;
+ urb_priv_t *urb_priv = urb->hcpriv;
+ struct ed *ed = td->ed;
+ int status;
+
+ /* update URB's length and status from TD */
+ status = td_done(ohci, urb, td);
+ urb_priv->td_cnt++;
+
+ /* If all this urb's TDs are done, call complete() */
+ if (urb_priv->td_cnt == urb_priv->length)
+ finish_urb(ohci, urb, status);
+
+ /* clean schedule: unlink EDs that are no longer busy */
+ if (list_empty(&ed->td_list)) {
+ if (ed->state == ED_OPER)
+ start_ed_unlink(ohci, ed);
+
+ /* ... reenabling halted EDs only after fault cleanup */
+ } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE))
+ == cpu_to_hc32(ohci, ED_SKIP)) {
+ td = list_entry(ed->td_list.next, struct td, td_list);
+ if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) {
+ ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP);
+ /* ... hc may need waking-up */
+ switch (ed->type) {
+ case PIPE_CONTROL:
+ ohci_writel(ohci, OHCI_CLF,
+ &ohci->regs->cmdstatus);
+ break;
+ case PIPE_BULK:
+ ohci_writel(ohci, OHCI_BLF,
+ &ohci->regs->cmdstatus);
+ break;
+ }
+ }
+ }
+}
+
+/*
* Process normal completions (error or success) and clean the schedules.
*
* This is the main path for handing urbs back to drivers. The only other
- * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
- * scanning the (re-reversed) donelist as this does.
+ * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
+ * instead of scanning the (re-reversed) donelist as this does. There's
+ * an abnormal path too, handling a quirk in some Compaq silicon: URBs
+ * with TDs that appear to be orphaned are directly reclaimed.
*/
static void
dl_done_list (struct ohci_hcd *ohci)
@@ -1074,44 +1108,7 @@ dl_done_list (struct ohci_hcd *ohci)
while (td) {
struct td *td_next = td->next_dl_td;
- struct urb *urb = td->urb;
- urb_priv_t *urb_priv = urb->hcpriv;
- struct ed *ed = td->ed;
-
- /* update URB's length and status from TD */
- td_done (ohci, urb, td);
- urb_priv->td_cnt++;
-
- /* If all this urb's TDs are done, call complete() */
- if (urb_priv->td_cnt == urb_priv->length)
- finish_urb (ohci, urb);
-
- /* clean schedule: unlink EDs that are no longer busy */
- if (list_empty (&ed->td_list)) {
- if (ed->state == ED_OPER)
- start_ed_unlink (ohci, ed);
-
- /* ... reenabling halted EDs only after fault cleanup */
- } else if ((ed->hwINFO & cpu_to_hc32 (ohci,
- ED_SKIP | ED_DEQUEUE))
- == cpu_to_hc32 (ohci, ED_SKIP)) {
- td = list_entry (ed->td_list.next, struct td, td_list);
- if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
- ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
- /* ... hc may need waking-up */
- switch (ed->type) {
- case PIPE_CONTROL:
- ohci_writel (ohci, OHCI_CLF,
- &ohci->regs->cmdstatus);
- break;
- case PIPE_BULK:
- ohci_writel (ohci, OHCI_BLF,
- &ohci->regs->cmdstatus);
- break;
- }
- }
- }
-
+ takeback_td(ohci, td);
td = td_next;
}
}
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index 6829814b7aa..44b79e8a6e2 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -358,7 +358,7 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- dev_err(&dev->dev, "request_mem_region failed");
+ dev_err(&dev->dev, "request_mem_region failed\n");
retval = -EBUSY;
goto err_put;
}
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
new file mode 100644
index 00000000000..fe70e72340d
--- /dev/null
+++ b/drivers/usb/host/ohci-ssb.c
@@ -0,0 +1,249 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom USB-core OHCI driver
+ *
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/ssb/ssb.h>
+
+
+#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29)
+
+struct ssb_ohci_device {
+ struct ohci_hcd ohci; /* _must_ be at the beginning. */
+
+ u32 enable_flags;
+};
+
+static inline
+struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
+{
+ return (struct ssb_ohci_device *)(hcd->hcd_priv);
+}
+
+
+static int ssb_ohci_reset(struct usb_hcd *hcd)
+{
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+ struct ohci_hcd *ohci = &ohcidev->ohci;
+ int err;
+
+ ohci_hcd_init(ohci);
+ err = ohci_init(ohci);
+
+ return err;
+}
+
+static int ssb_ohci_start(struct usb_hcd *hcd)
+{
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+ struct ohci_hcd *ohci = &ohcidev->ohci;
+ int err;
+
+ err = ohci_run(ohci);
+ if (err < 0) {
+ ohci_err(ohci, "can't start\n");
+ ohci_stop(hcd);
+ }
+
+ return err;
+}
+
+#ifdef CONFIG_PM
+static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
+{
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+ struct ohci_hcd *ohci = &ohcidev->ohci;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ohci->lock, flags);
+
+ ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+ ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */
+
+ /* make sure snapshot being resumed re-enumerates everything */
+ if (message.event == PM_EVENT_PRETHAW)
+ ohci_usb_reset(ohci);
+
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ spin_unlock_irqrestore(&ohci->lock, flags);
+ return 0;
+}
+
+static int ssb_ohci_hcd_resume(struct usb_hcd *hcd)
+{
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ usb_hcd_resume_root_hub(hcd);
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct hc_driver ssb_ohci_hc_driver = {
+ .description = "ssb-usb-ohci",
+ .product_desc = "SSB OHCI Controller",
+ .hcd_priv_size = sizeof(struct ssb_ohci_device),
+
+ .irq = ohci_irq,
+ .flags = HCD_MEMORY | HCD_USB11,
+
+ .reset = ssb_ohci_reset,
+ .start = ssb_ohci_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+#ifdef CONFIG_PM
+ .suspend = ssb_ohci_hcd_suspend,
+ .resume = ssb_ohci_hcd_resume,
+#endif
+
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ .get_frame_number = ohci_get_frame,
+
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+
+ .start_port_reset = ohci_start_port_reset,
+};
+
+static void ssb_ohci_detach(struct ssb_device *dev)
+{
+ struct usb_hcd *hcd = ssb_get_drvdata(dev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ usb_put_hcd(hcd);
+ ssb_device_disable(dev, 0);
+}
+
+static int ssb_ohci_attach(struct ssb_device *dev)
+{
+ struct ssb_ohci_device *ohcidev;
+ struct usb_hcd *hcd;
+ int err = -ENOMEM;
+ u32 tmp, flags = 0;
+
+ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
+ flags |= SSB_OHCI_TMSLOW_HOSTMODE;
+
+ ssb_device_enable(dev, flags);
+
+ hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
+ dev->dev->bus_id);
+ if (!hcd)
+ goto err_dev_disable;
+ ohcidev = hcd_to_ssb_ohci(hcd);
+ ohcidev->enable_flags = flags;
+
+ tmp = ssb_read32(dev, SSB_ADMATCH0);
+ hcd->rsrc_start = ssb_admatch_base(tmp);
+ hcd->rsrc_len = ssb_admatch_size(tmp);
+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs)
+ goto err_put_hcd;
+ err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
+ if (err)
+ goto err_iounmap;
+
+ ssb_set_drvdata(dev, hcd);
+
+ return err;
+
+err_iounmap:
+ iounmap(hcd->regs);
+err_put_hcd:
+ usb_put_hcd(hcd);
+err_dev_disable:
+ ssb_device_disable(dev, flags);
+ return err;
+}
+
+static int ssb_ohci_probe(struct ssb_device *dev,
+ const struct ssb_device_id *id)
+{
+ int err;
+ u16 chipid_top;
+
+ /* USBcores are only connected on embedded devices. */
+ chipid_top = (dev->bus->chip_id & 0xFF00);
+ if (chipid_top != 0x4700 && chipid_top != 0x5300)
+ return -ENODEV;
+
+ /* TODO: Probably need checks here; is the core connected? */
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ /* We currently always attach SSB_DEV_USB11_HOSTDEV
+ * as HOST OHCI. If we want to attach it as Client device,
+ * we must branch here and call into the (yet to
+ * be written) Client mode driver. Same for remove(). */
+
+ err = ssb_ohci_attach(dev);
+
+ return err;
+}
+
+static void ssb_ohci_remove(struct ssb_device *dev)
+{
+ ssb_ohci_detach(dev);
+}
+
+#ifdef CONFIG_PM
+
+static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
+{
+ ssb_device_disable(dev, 0);
+
+ return 0;
+}
+
+static int ssb_ohci_resume(struct ssb_device *dev)
+{
+ struct usb_hcd *hcd = ssb_get_drvdata(dev);
+ struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+
+ ssb_device_enable(dev, ohcidev->enable_flags);
+
+ return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ssb_ohci_suspend NULL
+#define ssb_ohci_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct ssb_device_id ssb_ohci_table[] = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
+ SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
+
+static struct ssb_driver ssb_ohci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ssb_ohci_table,
+ .probe = ssb_ohci_probe,
+ .remove = ssb_ohci_remove,
+ .suspend = ssb_ohci_suspend,
+ .resume = ssb_ohci_resume,
+};
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 4ada43cf138..47c5c66a282 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -398,11 +398,38 @@ struct ohci_hcd {
#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */
#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/
#define OHCI_QUIRK_NEC 0x40 /* lost interrupts */
+#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */
// there are also chip quirks/bugs in init logic
struct work_struct nec_work; /* Worker for NEC quirk */
+
+ /* Needed for ZF Micro quirk */
+ struct timer_list unlink_watchdog;
+ unsigned eds_scheduled;
+ struct ed *ed_to_check;
+ unsigned zf_delay;
};
+#ifdef CONFIG_PCI
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+ return ohci->flags & OHCI_QUIRK_NEC;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+ return ohci->flags & OHCI_QUIRK_ZFMICRO;
+}
+#else
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+ return 0;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+ return 0;
+}
+#endif
+
/* convert between an hcd pointer and the corresponding ohci_hcd */
static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd)
{
@@ -607,15 +634,12 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
* hardware handles 16 bit reads. That creates a different confusion on
* some big-endian SOC implementations. Same thing happens with PSW access.
- *
- * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
- * to arch/powerpc
*/
-#ifdef CONFIG_STB03xxx
-#define OHCI_BE_FRAME_NO_SHIFT 16
+#ifdef CONFIG_PPC_MPC52xx
+#define big_endian_frame_no_quirk(ohci) (ohci->flags & OHCI_QUIRK_FRAME_NO)
#else
-#define OHCI_BE_FRAME_NO_SHIFT 0
+#define big_endian_frame_no_quirk(ohci) 0
#endif
static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
@@ -623,7 +647,8 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
u32 tmp;
if (big_endian_desc(ohci)) {
tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
- tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+ if (!big_endian_frame_no_quirk(ohci))
+ tmp >>= 16;
} else
tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 40a1de4c256..ae8ec4474eb 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -782,10 +782,12 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
kfree(td);
if (urb) {
- urb->status = -ENODEV;
- urb->hcpriv = NULL;
+ usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
+ urb);
+
spin_unlock(&r8a66597->lock);
- usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb);
+ usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb,
+ -ENODEV);
spin_lock(&r8a66597->lock);
}
break;
@@ -832,7 +834,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
info.pipenum = get_empty_pipenum(r8a66597, ep);
info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
- info.maxpacket = ep->wMaxPacketSize;
+ info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
info.type = get_r8a66597_type(ep->bmAttributes
& USB_ENDPOINT_XFERTYPE_MASK);
info.bufnum = get_bufnum(info.pipenum);
@@ -923,7 +925,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597,
r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
for (i = 0; i < 4; i++) {
- r8a66597_write(r8a66597, p[i], setup_addr);
+ r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr);
setup_addr += 2;
}
r8a66597_write(r8a66597, SUREQ, DCPCTR);
@@ -1032,6 +1034,15 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
pipe_start(r8a66597, td->pipe);
}
+static int is_set_address(unsigned char *setup_packet)
+{
+ if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) &&
+ setup_packet[1] == USB_REQ_SET_ADDRESS)
+ return 1;
+ else
+ return 0;
+}
+
/* this function must be called with interrupt disabled */
static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
{
@@ -1039,7 +1050,7 @@ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
switch (td->type) {
case USB_PID_SETUP:
- if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) {
+ if (is_set_address(td->urb->setup_packet)) {
td->set_address = 1;
td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
td->urb);
@@ -1106,8 +1117,9 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
}
/* this function must be called with interrupt disabled */
-static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
- u16 pipenum, struct urb *urb)
+static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
+ u16 pipenum, struct urb *urb, int status)
+__releases(r8a66597->lock) __acquires(r8a66597->lock)
{
int restart = 0;
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
@@ -1115,7 +1127,7 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
r8a66597->timeout_map &= ~(1 << pipenum);
if (likely(td)) {
- if (td->set_address && urb->status != 0)
+ if (td->set_address && (status != 0 || urb->unlinked))
r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
pipe_toggle_save(r8a66597, td->pipe, urb);
@@ -1130,9 +1142,9 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
if (usb_pipeisoc(urb->pipe))
urb->start_frame = r8a66597_get_frame(hcd);
- urb->hcpriv = NULL;
+ usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
spin_unlock(&r8a66597->lock);
- usb_hcd_giveback_urb(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
spin_lock(&r8a66597->lock);
}
@@ -1146,14 +1158,6 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
}
}
-/* this function must be called with interrupt disabled */
-static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
- u16 pipenum, struct urb *urb)
-__releases(r8a66597->lock) __acquires(r8a66597->lock)
-{
- done(r8a66597, td, pipenum, urb);
-}
-
static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
{
u16 tmp;
@@ -1162,6 +1166,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
struct urb *urb;
int finish = 0;
+ int status = 0;
if (unlikely(!td))
return;
@@ -1170,17 +1175,15 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
fifo_change_from_pipe(r8a66597, td->pipe);
tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
if (unlikely((tmp & FRDY) == 0)) {
- urb->status = -EPIPE;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
err("in fifo not ready (%d)", pipenum);
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, td->urb, -EPIPE);
return;
}
/* prepare parameters */
rcv_len = tmp & DTLN;
- bufsize = td->maxpacket;
if (usb_pipeisoc(urb->pipe)) {
buf = (u16 *)(urb->transfer_buffer +
urb->iso_frame_desc[td->iso_cnt].offset);
@@ -1189,29 +1192,31 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
buf = (void *)urb->transfer_buffer + urb->actual_length;
urb_len = urb->transfer_buffer_length - urb->actual_length;
}
- if (rcv_len < bufsize)
- size = min(rcv_len, urb_len);
- else
- size = min(bufsize, urb_len);
+ bufsize = min(urb_len, (int) td->maxpacket);
+ if (rcv_len <= bufsize) {
+ size = rcv_len;
+ } else {
+ size = bufsize;
+ status = -EOVERFLOW;
+ finish = 1;
+ }
/* update parameters */
urb->actual_length += size;
if (rcv_len == 0)
td->zero_packet = 1;
- if ((size % td->maxpacket) > 0) {
+ if (rcv_len < bufsize) {
td->short_packet = 1;
- if (urb->transfer_buffer_length != urb->actual_length &&
- urb->transfer_flags & URB_SHORT_NOT_OK)
- td->urb->status = -EREMOTEIO;
}
if (usb_pipeisoc(urb->pipe)) {
urb->iso_frame_desc[td->iso_cnt].actual_length = size;
- urb->iso_frame_desc[td->iso_cnt].status = 0;
+ urb->iso_frame_desc[td->iso_cnt].status = status;
td->iso_cnt++;
+ finish = 0;
}
/* check transfer finish */
- if (check_transfer_finish(td, urb)) {
+ if (finish || check_transfer_finish(td, urb)) {
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
finish = 1;
@@ -1226,11 +1231,8 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
buf, size);
}
- if (finish && pipenum != 0) {
- if (td->urb->status == -EINPROGRESS)
- td->urb->status = 0;
- finish_request(r8a66597, td, pipenum, urb);
- }
+ if (finish && pipenum != 0)
+ finish_request(r8a66597, td, pipenum, urb, status);
}
static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
@@ -1248,11 +1250,10 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
fifo_change_from_pipe(r8a66597, td->pipe);
tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
if (unlikely((tmp & FRDY) == 0)) {
- urb->status = -EPIPE;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
err("out write fifo not ready. (%d)", pipenum);
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, urb, -EPIPE);
return;
}
@@ -1297,7 +1298,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
}
-static void check_next_phase(struct r8a66597 *r8a66597)
+static void check_next_phase(struct r8a66597 *r8a66597, int status)
{
struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
struct urb *urb;
@@ -1310,49 +1311,41 @@ static void check_next_phase(struct r8a66597 *r8a66597)
switch (td->type) {
case USB_PID_IN:
case USB_PID_OUT:
- if (urb->status != -EINPROGRESS) {
- finish = 1;
- break;
- }
if (check_transfer_finish(td, urb))
td->type = USB_PID_ACK;
break;
case USB_PID_SETUP:
- if (urb->status != -EINPROGRESS)
- finish = 1;
- else if (urb->transfer_buffer_length == urb->actual_length) {
+ if (urb->transfer_buffer_length == urb->actual_length)
td->type = USB_PID_ACK;
- urb->status = 0;
- } else if (usb_pipeout(urb->pipe))
+ else if (usb_pipeout(urb->pipe))
td->type = USB_PID_OUT;
else
td->type = USB_PID_IN;
break;
case USB_PID_ACK:
finish = 1;
- if (urb->status == -EINPROGRESS)
- urb->status = 0;
break;
}
- if (finish)
- finish_request(r8a66597, td, 0, urb);
+ if (finish || status != 0 || urb->unlinked)
+ finish_request(r8a66597, td, 0, urb, status);
else
start_transfer(r8a66597, td);
}
-static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
+static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
{
struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
- if (td && td->urb) {
+ if (td) {
u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
if (pid == PID_NAK)
- td->urb->status = -ECONNRESET;
+ return -ECONNRESET;
else
- td->urb->status = -EPIPE;
+ return -EPIPE;
}
+ return 0;
}
static void irq_pipe_ready(struct r8a66597 *r8a66597)
@@ -1371,7 +1364,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597)
packet_read(r8a66597, 0);
else
pipe_irq_disable(r8a66597, 0);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, 0);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1405,7 +1398,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
td = r8a66597_get_td(r8a66597, 0);
if (td && td->type != USB_PID_OUT)
disable_irq_empty(r8a66597, 0);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, 0);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1420,9 +1413,8 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
if ((tmp & INBUFM) == 0) {
disable_irq_empty(r8a66597, pipenum);
pipe_irq_disable(r8a66597, pipenum);
- if (td->urb->status == -EINPROGRESS)
- td->urb->status = 0;
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, td->urb,
+ 0);
}
}
}
@@ -1433,15 +1425,16 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
u16 check;
u16 pipenum;
u16 mask;
+ int status;
mask = r8a66597_read(r8a66597, NRDYSTS)
& r8a66597_read(r8a66597, NRDYENB);
r8a66597_write(r8a66597, ~mask, NRDYSTS);
if (mask & NRDY0) {
cfifo_change(r8a66597, 0);
- set_urb_error(r8a66597, 0);
+ status = get_urb_error(r8a66597, 0);
pipe_irq_disable(r8a66597, 0);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, status);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1452,10 +1445,10 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
if (unlikely(!td))
continue;
- set_urb_error(r8a66597, pipenum);
+ status = get_urb_error(r8a66597, pipenum);
pipe_irq_disable(r8a66597, pipenum);
pipe_stop(r8a66597, td->pipe);
- finish_request(r8a66597, td, pipenum, td->urb);
+ finish_request(r8a66597, td, pipenum, td->urb, status);
}
}
}
@@ -1475,6 +1468,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
u16 intsts0, intsts1, intsts2;
u16 intenb0, intenb1, intenb2;
u16 mask0, mask1, mask2;
+ int status;
spin_lock(&r8a66597->lock);
@@ -1518,12 +1512,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
}
if (mask1 & SIGN) {
r8a66597_write(r8a66597, ~SIGN, INTSTS1);
- set_urb_error(r8a66597, 0);
- check_next_phase(r8a66597);
+ status = get_urb_error(r8a66597, 0);
+ check_next_phase(r8a66597, status);
}
if (mask1 & SACK) {
r8a66597_write(r8a66597, ~SACK, INTSTS1);
- check_next_phase(r8a66597);
+ check_next_phase(r8a66597, 0);
}
}
if (mask0) {
@@ -1722,21 +1716,25 @@ static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
}
static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
- struct usb_host_endpoint *hep,
struct urb *urb,
gfp_t mem_flags)
{
+ struct usb_host_endpoint *hep = urb->ep;
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
struct r8a66597_td *td = NULL;
- int ret = 0, request = 0;
+ int ret, request = 0;
unsigned long flags;
spin_lock_irqsave(&r8a66597->lock, flags);
if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
ret = -ENODEV;
- goto error;
+ goto error_not_linked;
}
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto error_not_linked;
+
if (!hep->hcpriv) {
hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
GFP_ATOMIC);
@@ -1761,15 +1759,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
request = 1;
list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
-
- spin_lock(&urb->lock);
- if (urb->status != -EINPROGRESS) {
- spin_unlock(&urb->lock);
- ret = -EPIPE;
- goto error;
- }
urb->hcpriv = td;
- spin_unlock(&urb->lock);
if (request) {
ret = start_transfer(r8a66597, td);
@@ -1781,26 +1771,36 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
set_td_timer(r8a66597, td);
error:
+ if (ret)
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+error_not_linked:
spin_unlock_irqrestore(&r8a66597->lock, flags);
return ret;
}
-static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
{
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
struct r8a66597_td *td;
unsigned long flags;
+ int rc;
spin_lock_irqsave(&r8a66597->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
if (urb->hcpriv) {
td = urb->hcpriv;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, td->pipenum);
disable_irq_empty(r8a66597, td->pipenum);
- done(r8a66597, td, td->pipenum, urb);
+ finish_request(r8a66597, td, td->pipenum, urb, status);
}
+ done:
spin_unlock_irqrestore(&r8a66597->lock, flags);
- return 0;
+ return rc;
}
static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
@@ -1830,7 +1830,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
td = r8a66597_get_td(r8a66597, pipenum);
if (td)
urb = td->urb;
- done(r8a66597, td, pipenum, urb);
+ finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN);
kfree(hep->hcpriv);
hep->hcpriv = NULL;
spin_unlock_irqrestore(&r8a66597->lock, flags);
@@ -2027,7 +2027,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case GetPortStatus:
if (wIndex > R8A66597_MAX_ROOT_HUB)
goto error;
- *(u32 *)buf = rh->port;
+ *(u32 *)buf = cpu_to_le32(rh->port);
break;
case SetPortFeature:
if (wIndex > R8A66597_MAX_ROOT_HUB)
@@ -2126,8 +2126,8 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
del_timer_sync(&r8a66597->rh_timer);
- iounmap((void *)r8a66597->reg);
usb_remove_hcd(hcd);
+ iounmap((void *)r8a66597->reg);
usb_put_hcd(hcd);
return 0;
}
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 4cfa3ff2c99..ba370c56172 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -435,14 +435,9 @@ static void finish_request(
if (usb_pipecontrol(urb->pipe))
ep->nextpid = USB_PID_SETUP;
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = status;
- urb->hcpriv = NULL;
- spin_unlock(&urb->lock);
-
+ usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb);
spin_unlock(&sl811->lock);
- usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb);
+ usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status);
spin_lock(&sl811->lock);
/* leave active endpoints in the schedule */
@@ -538,35 +533,21 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
bank + SL11H_XFERCNTREG);
if (len > ep->length) {
len = ep->length;
- urb->status = -EOVERFLOW;
+ urbstat = -EOVERFLOW;
}
urb->actual_length += len;
sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0),
buf, len);
usb_dotoggle(udev, ep->epnum, 0);
- if (urb->actual_length == urb->transfer_buffer_length)
- urbstat = 0;
- else if (len < ep->maxpacket) {
- if (urb->transfer_flags & URB_SHORT_NOT_OK)
- urbstat = -EREMOTEIO;
+ if (urbstat == -EINPROGRESS &&
+ (len < ep->maxpacket ||
+ urb->actual_length ==
+ urb->transfer_buffer_length)) {
+ if (usb_pipecontrol(urb->pipe))
+ ep->nextpid = USB_PID_ACK;
else
urbstat = 0;
}
- if (usb_pipecontrol(urb->pipe)
- && (urbstat == -EREMOTEIO
- || urbstat == 0)) {
-
- /* NOTE if the status stage STALLs (why?),
- * this reports the wrong urb status.
- */
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS)
- urb->status = urbstat;
- spin_unlock(&urb->lock);
-
- urb = NULL;
- ep->nextpid = USB_PID_ACK;
- }
break;
case USB_PID_SETUP:
// PACKET("...ACK/setup_%02x qh%p\n", bank, ep);
@@ -605,7 +586,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
bank, status, ep, urbstat);
}
- if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS))
+ if (urbstat != -EINPROGRESS || urb->unlinked)
finish_request(sl811, ep, urb, urbstat);
}
@@ -807,7 +788,6 @@ static int balance(struct sl811 *sl811, u16 period, u16 load)
static int sl811h_urb_enqueue(
struct usb_hcd *hcd,
- struct usb_host_endpoint *hep,
struct urb *urb,
gfp_t mem_flags
) {
@@ -820,7 +800,8 @@ static int sl811h_urb_enqueue(
struct sl811h_ep *ep = NULL;
unsigned long flags;
int i;
- int retval = 0;
+ int retval;
+ struct usb_host_endpoint *hep = urb->ep;
#ifdef DISABLE_ISO
if (type == PIPE_ISOCHRONOUS)
@@ -838,7 +819,12 @@ static int sl811h_urb_enqueue(
|| !HC_IS_RUNNING(hcd->state)) {
retval = -ENODEV;
kfree(ep);
- goto fail;
+ goto fail_not_linked;
+ }
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval) {
+ kfree(ep);
+ goto fail_not_linked;
}
if (hep->hcpriv) {
@@ -951,37 +937,31 @@ static int sl811h_urb_enqueue(
sofirq_on(sl811);
}
- /* in case of unlink-during-submit */
- spin_lock(&urb->lock);
- if (urb->status != -EINPROGRESS) {
- spin_unlock(&urb->lock);
- finish_request(sl811, ep, urb, 0);
- retval = 0;
- goto fail;
- }
urb->hcpriv = hep;
- spin_unlock(&urb->lock);
-
start_transfer(sl811);
sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
fail:
+ if (retval)
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+fail_not_linked:
spin_unlock_irqrestore(&sl811->lock, flags);
return retval;
}
-static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct sl811 *sl811 = hcd_to_sl811(hcd);
struct usb_host_endpoint *hep;
unsigned long flags;
struct sl811h_ep *ep;
- int retval = 0;
+ int retval;
spin_lock_irqsave(&sl811->lock, flags);
- hep = urb->hcpriv;
- if (!hep)
+ retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (retval)
goto fail;
+ hep = urb->hcpriv;
ep = hep->hcpriv;
if (ep) {
/* finish right away if this urb can't be active ...
@@ -1029,8 +1009,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
(sl811->active_a == ep) ? "A" : "B");
} else
-fail:
retval = -EINVAL;
+ fail:
spin_unlock_irqrestore(&sl811->lock, flags);
return retval;
}
@@ -1576,7 +1556,7 @@ sl811h_start(struct usb_hcd *hcd)
hcd->power_budget = sl811->board->power * 2;
}
- /* enable power and interupts */
+ /* enable power and interrupts */
port_power(sl811, 1);
return 0;
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index b88eb3c62c0..ac283b09a63 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -51,7 +51,6 @@
#include <linux/usb.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
-#include <linux/pci_ids.h>
#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -184,7 +183,7 @@ struct u132_ring {
struct u132 {
struct kref kref;
struct list_head u132_list;
- struct semaphore sw_lock;
+ struct mutex sw_lock;
struct semaphore scheduler_lock;
struct u132_platform_data *board;
struct platform_device *platform_dev;
@@ -493,20 +492,20 @@ static void u132_hcd_monitor_work(struct work_struct *work)
return;
} else {
int retval;
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
retval = read_roothub_info(u132);
if (retval) {
struct usb_hcd *hcd = u132_to_hcd(u132);
u132_disable(u132);
u132->going = 1;
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
usb_hc_died(hcd);
ftdi_elan_gone_away(u132->platform_dev);
u132_monitor_put_kref(u132);
return;
} else {
u132_monitor_requeue_work(u132, 500);
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return;
}
}
@@ -519,9 +518,8 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
unsigned long irqs;
struct usb_hcd *hcd = u132_to_hcd(u132);
urb->error_count = 0;
- urb->status = status;
- urb->hcpriv = NULL;
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
endp->queue_next += 1;
if (ENDP_QUEUE_SIZE > --endp->queue_size) {
endp->active = 0;
@@ -543,7 +541,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
u132_ring_queue_work(u132, ring, 0);
up(&u132->scheduler_lock);
u132_endp_put_kref(u132, endp);
- usb_hcd_giveback_urb(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
return;
}
@@ -559,9 +557,8 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
unsigned long irqs;
struct usb_hcd *hcd = u132_to_hcd(u132);
urb->error_count = 0;
- urb->status = status;
- urb->hcpriv = NULL;
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
endp->queue_next += 1;
if (ENDP_QUEUE_SIZE > --endp->queue_size) {
endp->active = 0;
@@ -576,7 +573,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
endp->active = 0;
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
kfree(urbq);
- } usb_hcd_giveback_urb(hcd, urb);
+ } usb_hcd_giveback_urb(hcd, urb, status);
return;
}
@@ -646,12 +643,12 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer + urb->actual_length;
u8 *b = buf;
@@ -717,10 +714,10 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -745,12 +742,12 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
urb->actual_length += len;
endp->toggle_bits = toggle_bits;
@@ -769,10 +766,10 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -798,12 +795,12 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer + urb->actual_length;
u8 *b = buf;
@@ -872,10 +869,10 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -899,20 +896,20 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -937,12 +934,12 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer;
u8 *b = buf;
@@ -981,10 +978,10 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1008,20 +1005,20 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1046,12 +1043,12 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
if (usb_pipein(urb->pipe)) {
int retval;
struct u132_ring *ring = endp->ring;
@@ -1078,10 +1075,10 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1107,22 +1104,22 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
u132->addr[0].address = 0;
endp->usb_addr = udev->usb_addr;
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1146,12 +1143,12 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
int retval;
struct u132_ring *ring = endp->ring;
up(&u132->scheduler_lock);
@@ -1163,10 +1160,10 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
u132_hcd_giveback_urb(u132, endp, urb, retval);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1190,20 +1187,20 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1228,12 +1225,12 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
int retval;
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer;
@@ -1252,10 +1249,10 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, retval);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1280,12 +1277,12 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
- } else if (urb->status == -EINPROGRESS) {
+ } else if (!urb->unlinked) {
int retval;
struct u132_ring *ring = endp->ring;
up(&u132->scheduler_lock);
@@ -1297,10 +1294,10 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, retval);
return;
} else {
- dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
- "s=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+ "unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
- u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@@ -1805,10 +1802,10 @@ static void u132_hcd_stop(struct usb_hcd *hcd)
dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
"ed\n", hcd);
} else {
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
msleep(100);
u132_power(u132, 0);
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
}
}
@@ -1830,7 +1827,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
(pdev->dev.platform_data))->vendor;
u16 device = ((struct u132_platform_data *)
(pdev->dev.platform_data))->device;
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
msleep(10);
if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
u132->flags = OHCI_QUIRK_AMD756;
@@ -1845,7 +1842,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
u132->going = 1;
}
msleep(100);
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return retval;
} else {
dev_err(&u132->platform_dev->dev, "platform_device missing\n");
@@ -1865,32 +1862,44 @@ static int u132_hcd_reset(struct usb_hcd *hcd)
return -ESHUTDOWN;
} else {
int retval;
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
retval = u132_init(u132);
if (retval) {
u132_disable(u132);
u132->going = 1;
}
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return retval;
}
}
static int create_endpoint_and_queue_int(struct u132 *u132,
- struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+ struct u132_udev *udev, struct urb *urb,
struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
gfp_t mem_flags)
{
struct u132_ring *ring;
unsigned long irqs;
- u8 endp_number = ++u132->num_endpoints;
- struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
- kmalloc(sizeof(struct u132_endp), mem_flags);
+ int rc;
+ u8 endp_number;
+ struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
if (!endp) {
return -ENOMEM;
}
+
+ spin_lock_init(&endp->queue_lock.slock);
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+ if (rc) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(endp);
+ return rc;
+ }
+
+ endp_number = ++u132->num_endpoints;
+ urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- spin_lock_init(&endp->queue_lock.slock);
INIT_LIST_HEAD(&endp->urb_more);
ring = endp->ring = &u132->ring[0];
if (ring->curr_endp) {
@@ -1906,7 +1915,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
endp->delayed = 0;
endp->endp_number = endp_number;
endp->u132 = u132;
- endp->hep = hep;
+ endp->hep = urb->ep;
endp->pipetype = usb_pipetype(urb->pipe);
u132_endp_init_kref(u132, endp);
if (usb_pipein(urb->pipe)) {
@@ -1925,7 +1934,6 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
u132_udev_get_kref(u132, udev);
}
urb->hcpriv = u132;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->delayed = 1;
endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
endp->udev_number = address;
@@ -1940,8 +1948,8 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
return 0;
}
-static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
- struct usb_host_endpoint *hep, struct urb *urb,
+static int queue_int_on_old_endpoint(struct u132 *u132,
+ struct u132_udev *udev, struct urb *urb,
struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
u8 usb_endp, u8 address)
{
@@ -1965,21 +1973,33 @@ static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
}
static int create_endpoint_and_queue_bulk(struct u132 *u132,
- struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+ struct u132_udev *udev, struct urb *urb,
struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
gfp_t mem_flags)
{
int ring_number;
struct u132_ring *ring;
unsigned long irqs;
- u8 endp_number = ++u132->num_endpoints;
- struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
- kmalloc(sizeof(struct u132_endp), mem_flags);
+ int rc;
+ u8 endp_number;
+ struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
if (!endp) {
return -ENOMEM;
}
+
+ spin_lock_init(&endp->queue_lock.slock);
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+ if (rc) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(endp);
+ return rc;
+ }
+
+ endp_number = ++u132->num_endpoints;
+ urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- spin_lock_init(&endp->queue_lock.slock);
INIT_LIST_HEAD(&endp->urb_more);
endp->dequeueing = 0;
endp->edset_flush = 0;
@@ -1987,7 +2007,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
endp->delayed = 0;
endp->endp_number = endp_number;
endp->u132 = u132;
- endp->hep = hep;
+ endp->hep = urb->ep;
endp->pipetype = usb_pipetype(urb->pipe);
u132_endp_init_kref(u132, endp);
if (usb_pipein(urb->pipe)) {
@@ -2016,7 +2036,6 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
}
ring->length += 1;
urb->hcpriv = u132;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->udev_number = address;
endp->usb_addr = usb_addr;
endp->usb_endp = usb_endp;
@@ -2030,7 +2049,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
}
static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
- struct usb_host_endpoint *hep, struct urb *urb,
+ struct urb *urb,
struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
u8 usb_endp, u8 address)
{
@@ -2052,19 +2071,32 @@ static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
}
static int create_endpoint_and_queue_control(struct u132 *u132,
- struct usb_host_endpoint *hep, struct urb *urb,
+ struct urb *urb,
struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
gfp_t mem_flags)
{
struct u132_ring *ring;
- u8 endp_number = ++u132->num_endpoints;
- struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
- kmalloc(sizeof(struct u132_endp), mem_flags);
+ unsigned long irqs;
+ int rc;
+ u8 endp_number;
+ struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
if (!endp) {
return -ENOMEM;
}
+
+ spin_lock_init(&endp->queue_lock.slock);
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+ if (rc) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(endp);
+ return rc;
+ }
+
+ endp_number = ++u132->num_endpoints;
+ urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
- spin_lock_init(&endp->queue_lock.slock);
INIT_LIST_HEAD(&endp->urb_more);
ring = endp->ring = &u132->ring[0];
if (ring->curr_endp) {
@@ -2080,11 +2112,10 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
endp->delayed = 0;
endp->endp_number = endp_number;
endp->u132 = u132;
- endp->hep = hep;
+ endp->hep = urb->ep;
u132_endp_init_kref(u132, endp);
u132_endp_get_kref(u132, endp);
if (usb_addr == 0) {
- unsigned long irqs;
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
endp->udev_number = address;
@@ -2098,7 +2129,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
udev->endp_number_in[usb_endp] = endp_number;
udev->endp_number_out[usb_endp] = endp_number;
urb->hcpriv = u132;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->queue_size = 1;
endp->queue_last = 0;
endp->queue_next = 0;
@@ -2107,7 +2137,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
u132_endp_queue_work(u132, endp, 0);
return 0;
} else { /*(usb_addr > 0) */
- unsigned long irqs;
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
endp->udev_number = address;
@@ -2121,7 +2150,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
udev->endp_number_in[usb_endp] = endp_number;
udev->endp_number_out[usb_endp] = endp_number;
urb->hcpriv = u132;
- spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->queue_size = 1;
endp->queue_last = 0;
endp->queue_next = 0;
@@ -2133,7 +2161,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
}
static int queue_control_on_old_endpoint(struct u132 *u132,
- struct usb_host_endpoint *hep, struct urb *urb,
+ struct urb *urb,
struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
u8 usb_endp)
{
@@ -2233,8 +2261,8 @@ static int queue_control_on_old_endpoint(struct u132 *u132,
}
}
-static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
- struct urb *urb, gfp_t mem_flags)
+static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
{
struct u132 *u132 = hcd_to_u132(hcd);
if (irqs_disabled()) {
@@ -2249,8 +2277,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
, u132->going);
return -ENODEV;
} else if (u132->going > 0) {
- dev_err(&u132->platform_dev->dev, "device is being removed urb="
- "%p status=%d\n", urb, urb->status);
+ dev_err(&u132->platform_dev->dev, "device is being removed "
+ "urb=%p\n", urb);
return -ESHUTDOWN;
} else {
u8 usb_addr = usb_pipedevice(urb->pipe);
@@ -2259,16 +2287,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
- struct u132_endp *endp = hep->hcpriv;
+ struct u132_endp *endp = urb->ep->hcpriv;
urb->actual_length = 0;
if (endp) {
unsigned long irqs;
int retval;
spin_lock_irqsave(&endp->queue_lock.slock,
irqs);
- retval = queue_int_on_old_endpoint(u132, udev,
- hep, urb, usb_dev, endp, usb_addr,
- usb_endp, address);
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval == 0) {
+ retval = queue_int_on_old_endpoint(
+ u132, udev, urb,
+ usb_dev, endp,
+ usb_addr, usb_endp,
+ address);
+ if (retval)
+ usb_hcd_unlink_urb_from_ep(
+ hcd, urb);
+ }
spin_unlock_irqrestore(&endp->queue_lock.slock,
irqs);
if (retval) {
@@ -2283,8 +2319,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
return -EINVAL;
} else { /*(endp == NULL) */
return create_endpoint_and_queue_int(u132, udev,
- hep, urb, usb_dev, usb_addr, usb_endp,
- address, mem_flags);
+ urb, usb_dev, usb_addr,
+ usb_endp, address, mem_flags);
}
} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
dev_err(&u132->platform_dev->dev, "the hardware does no"
@@ -2293,16 +2329,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
- struct u132_endp *endp = hep->hcpriv;
+ struct u132_endp *endp = urb->ep->hcpriv;
urb->actual_length = 0;
if (endp) {
unsigned long irqs;
int retval;
spin_lock_irqsave(&endp->queue_lock.slock,
irqs);
- retval = queue_bulk_on_old_endpoint(u132, udev,
- hep, urb, usb_dev, endp, usb_addr,
- usb_endp, address);
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval == 0) {
+ retval = queue_bulk_on_old_endpoint(
+ u132, udev, urb,
+ usb_dev, endp,
+ usb_addr, usb_endp,
+ address);
+ if (retval)
+ usb_hcd_unlink_urb_from_ep(
+ hcd, urb);
+ }
spin_unlock_irqrestore(&endp->queue_lock.slock,
irqs);
if (retval) {
@@ -2315,10 +2359,10 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
return -EINVAL;
} else
return create_endpoint_and_queue_bulk(u132,
- udev, hep, urb, usb_dev, usb_addr,
+ udev, urb, usb_dev, usb_addr,
usb_endp, address, mem_flags);
} else {
- struct u132_endp *endp = hep->hcpriv;
+ struct u132_endp *endp = urb->ep->hcpriv;
u16 urb_size = 8;
u8 *b = urb->setup_packet;
int i = 0;
@@ -2341,9 +2385,16 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
int retval;
spin_lock_irqsave(&endp->queue_lock.slock,
irqs);
- retval = queue_control_on_old_endpoint(u132,
- hep, urb, usb_dev, endp, usb_addr,
- usb_endp);
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval == 0) {
+ retval = queue_control_on_old_endpoint(
+ u132, urb, usb_dev,
+ endp, usb_addr,
+ usb_endp);
+ if (retval)
+ usb_hcd_unlink_urb_from_ep(
+ hcd, urb);
+ }
spin_unlock_irqrestore(&endp->queue_lock.slock,
irqs);
if (retval) {
@@ -2356,7 +2407,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
return -EINVAL;
} else
return create_endpoint_and_queue_control(u132,
- hep, urb, usb_dev, usb_addr, usb_endp,
+ urb, usb_dev, usb_addr, usb_endp,
mem_flags);
}
}
@@ -2375,8 +2426,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
list_del(scan);
endp->queue_size -= 1;
urb->error_count = 0;
- urb->hcpriv = NULL;
- usb_hcd_giveback_urb(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, 0);
return 0;
} else
continue;
@@ -2391,10 +2441,17 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
}
static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
- struct urb *urb)
+ struct urb *urb, int status)
{
unsigned long irqs;
+ int rc;
+
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
+ if (rc) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ return rc;
+ }
if (endp->queue_size == 0) {
dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
"=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
@@ -2410,11 +2467,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
endp->edset_flush = 1;
u132_endp_queue_work(u132, endp, 0);
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- urb->hcpriv = NULL;
return 0;
} else {
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
- u132_hcd_abandon_urb(u132, endp, urb, urb->status);
+ u132_hcd_abandon_urb(u132, endp, urb, status);
return 0;
}
} else {
@@ -2439,6 +2495,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
}
if (urb_slot) {
struct usb_hcd *hcd = u132_to_hcd(u132);
+
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
endp->queue_size -= 1;
if (list_empty(&endp->urb_more)) {
spin_unlock_irqrestore(&endp->queue_lock.slock,
@@ -2453,8 +2511,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
irqs);
kfree(urbq);
} urb->error_count = 0;
- urb->hcpriv = NULL;
- usb_hcd_giveback_urb(hcd, urb);
+ usb_hcd_giveback_urb(hcd, urb, status);
return 0;
} else if (list_empty(&endp->urb_more)) {
dev_err(&u132->platform_dev->dev, "urb=%p not found in "
@@ -2468,7 +2525,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
return -EINVAL;
} else {
- int retval = dequeue_from_overflow_chain(u132, endp,
+ int retval;
+
+ usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
+ retval = dequeue_from_overflow_chain(u132, endp,
urb);
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
return retval;
@@ -2476,7 +2536,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
}
}
-static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct u132 *u132 = hcd_to_u132(hcd);
if (u132->going > 2) {
@@ -2491,11 +2551,11 @@ static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
if (usb_pipein(urb->pipe)) {
u8 endp_number = udev->endp_number_in[usb_endp];
struct u132_endp *endp = u132->endp[endp_number - 1];
- return u132_endp_urb_dequeue(u132, endp, urb);
+ return u132_endp_urb_dequeue(u132, endp, urb, status);
} else {
u8 endp_number = udev->endp_number_out[usb_endp];
struct u132_endp *endp = u132->endp[endp_number - 1];
- return u132_endp_urb_dequeue(u132, endp, urb);
+ return u132_endp_urb_dequeue(u132, endp, urb, status);
}
}
}
@@ -2805,7 +2865,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
return -ESHUTDOWN;
} else {
int retval = 0;
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
switch (typeReq) {
case ClearHubFeature:
switch (wValue) {
@@ -2868,7 +2928,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
stall:retval = -EPIPE;
break;
}
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return retval;
}
}
@@ -3004,7 +3064,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
dev_err(&u132->platform_dev->dev, "removing device u132"
".%d\n", u132->sequence_num);
msleep(100);
- down(&u132->sw_lock);
+ mutex_lock(&u132->sw_lock);
u132_monitor_cancel_work(u132);
while (rings-- > 0) {
struct u132_ring *ring = &u132->ring[rings];
@@ -3017,7 +3077,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
u132->going += 1;
printk(KERN_INFO "removing device u132.%d\n",
u132->sequence_num);
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
usb_remove_hcd(hcd);
u132_u132_put_kref(u132);
return 0;
@@ -3037,7 +3097,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
u132->platform_dev = pdev;
u132->power = 0;
u132->reset = 0;
- init_MUTEX(&u132->sw_lock);
+ mutex_init(&u132->sw_lock);
init_MUTEX(&u132->scheduler_lock);
while (rings-- > 0) {
struct u132_ring *ring = &u132->ring[rings];
@@ -3047,7 +3107,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
ring->curr_endp = NULL;
INIT_DELAYED_WORK(&ring->scheduler,
u132_hcd_ring_work_scheduler);
- } down(&u132->sw_lock);
+ } mutex_lock(&u132->sw_lock);
INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
while (ports-- > 0) {
struct u132_port *port = &u132->port[ports];
@@ -3077,7 +3137,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
while (endps-- > 0) {
u132->endp[endps] = NULL;
}
- up(&u132->sw_lock);
+ mutex_unlock(&u132->sw_lock);
return;
}
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 1497371583b..20cc58b9780 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -120,8 +120,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
- if (urbp->urb->status != -EINPROGRESS)
- out += sprintf(out, " Status=%d", urbp->urb->status);
+ if (urbp->urb->unlinked)
+ out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
out += sprintf(out, "\n");
i = nactive = ninactive = 0;
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 805e5fc5f5d..4db17f75f4f 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -237,7 +237,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
static int remote_wakeup_is_broken(struct uhci_hcd *uhci)
{
int port;
- char *sys_info;
+ const char *sys_info;
static char bad_Asus_board[] = "A7V8X";
/* One of Asus's motherboards has a bug which causes it to
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 1b3d23406ac..340d6ed3e6e 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -146,7 +146,6 @@ struct uhci_qh {
short phase; /* Between 0 and period-1 */
short load; /* Periodic time requirement, in us */
unsigned int iso_frame; /* Frame # for iso_packet_desc */
- int iso_status; /* Status for Isochronous URBs */
int state; /* QH_STATE_xxx; see above */
int type; /* Queue type (control, bulk, etc) */
@@ -457,21 +456,6 @@ struct urb_priv {
};
-/*
- * Locking in uhci.c
- *
- * Almost everything relating to the hardware schedule and processing
- * of URBs is protected by uhci->lock. urb->status is protected by
- * urb->lock; that's the one exception.
- *
- * To prevent deadlocks, never lock uhci->lock while holding urb->lock.
- * The safe order of locking is:
- *
- * #1 uhci->lock
- * #2 urb->lock
- */
-
-
/* Some special IDs */
#define PCI_VENDOR_ID_GENESYS 0x17a0
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 3bb908ca38e..60379b17bbc 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -757,7 +757,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
uhci_free_td(uhci, td);
}
- urbp->urb->hcpriv = NULL;
kmem_cache_free(uhci_up_cachep, urbp);
}
@@ -1272,7 +1271,8 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
} else if (qh->period != urb->interval) {
return -EINVAL; /* Can't change the period */
- } else { /* Pick up where the last URB leaves off */
+ } else {
+ /* Find the next unused frame */
if (list_empty(&qh->queue)) {
frame = qh->iso_frame;
} else {
@@ -1284,10 +1284,18 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
lurb->number_of_packets *
lurb->interval;
}
- if (urb->transfer_flags & URB_ISO_ASAP)
- urb->start_frame = frame;
- else if (urb->start_frame != frame)
- return -EINVAL;
+ if (urb->transfer_flags & URB_ISO_ASAP) {
+ /* Skip some frames if necessary to insure
+ * the start frame is in the future.
+ */
+ uhci_get_current_frame_number(uhci);
+ if (uhci_frame_before_eq(frame, uhci->frame_number)) {
+ frame = uhci->frame_number + 1;
+ frame += ((qh->phase - frame) &
+ (qh->period - 1));
+ }
+ } /* Otherwise pick up where the last URB leaves off */
+ urb->start_frame = frame;
}
/* Make sure we won't have to go too far into the future */
@@ -1324,7 +1332,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
if (list_empty(&qh->queue)) {
qh->iso_packet_desc = &urb->iso_frame_desc[0];
qh->iso_frame = urb->start_frame;
- qh->iso_status = 0;
}
qh->skel = SKEL_ISO;
@@ -1361,22 +1368,18 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
qh->iso_packet_desc->actual_length = actlength;
qh->iso_packet_desc->status = status;
}
-
- if (status) {
+ if (status)
urb->error_count++;
- qh->iso_status = status;
- }
uhci_remove_td_from_urbp(td);
uhci_free_td(uhci, td);
qh->iso_frame += qh->period;
++qh->iso_packet_desc;
}
- return qh->iso_status;
+ return 0;
}
static int uhci_urb_enqueue(struct usb_hcd *hcd,
- struct usb_host_endpoint *hep,
struct urb *urb, gfp_t mem_flags)
{
int ret;
@@ -1387,19 +1390,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
spin_lock_irqsave(&uhci->lock, flags);
- ret = urb->status;
- if (ret != -EINPROGRESS) /* URB already unlinked! */
- goto done;
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto done_not_linked;
ret = -ENOMEM;
urbp = uhci_alloc_urb_priv(uhci, urb);
if (!urbp)
goto done;
- if (hep->hcpriv)
- qh = (struct uhci_qh *) hep->hcpriv;
+ if (urb->ep->hcpriv)
+ qh = urb->ep->hcpriv;
else {
- qh = uhci_alloc_qh(uhci, urb->dev, hep);
+ qh = uhci_alloc_qh(uhci, urb->dev, urb->ep);
if (!qh)
goto err_no_qh;
}
@@ -1440,27 +1443,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
err_submit_failed:
if (qh->state == QH_STATE_IDLE)
uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */
-
err_no_qh:
uhci_free_urb_priv(uhci, urbp);
-
done:
+ if (ret)
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+done_not_linked:
spin_unlock_irqrestore(&uhci->lock, flags);
return ret;
}
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags;
- struct urb_priv *urbp;
struct uhci_qh *qh;
+ int rc;
spin_lock_irqsave(&uhci->lock, flags);
- urbp = urb->hcpriv;
- if (!urbp) /* URB was never linked! */
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
goto done;
- qh = urbp->qh;
+
+ qh = ((struct urb_priv *) urb->hcpriv)->qh;
/* Remove Isochronous TDs from the frame list ASAP */
if (qh->type == USB_ENDPOINT_XFER_ISOC) {
@@ -1477,14 +1482,14 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
done:
spin_unlock_irqrestore(&uhci->lock, flags);
- return 0;
+ return rc;
}
/*
* Finish unlinking an URB and give it back
*/
static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
- struct urb *urb)
+ struct urb *urb, int status)
__releases(uhci->lock)
__acquires(uhci->lock)
{
@@ -1497,13 +1502,6 @@ __acquires(uhci->lock)
* unlinked first. Regardless, don't confuse people with a
* negative length. */
urb->actual_length = max(urb->actual_length, 0);
-
- /* Report erroneous short transfers */
- if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
- urb->actual_length <
- urb->transfer_buffer_length &&
- urb->status == 0))
- urb->status = -EREMOTEIO;
}
/* When giving back the first URB in an Isochronous queue,
@@ -1516,7 +1514,6 @@ __acquires(uhci->lock)
qh->iso_packet_desc = &nurb->iso_frame_desc[0];
qh->iso_frame = nurb->start_frame;
- qh->iso_status = 0;
}
/* Take the URB off the QH's queue. If the queue is now empty,
@@ -1529,9 +1526,10 @@ __acquires(uhci->lock)
}
uhci_free_urb_priv(uhci, urbp);
+ usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb);
spin_unlock(&uhci->lock);
- usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
+ usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status);
spin_lock(&uhci->lock);
/* If the queue is now empty, we can unlink the QH and give up its
@@ -1567,24 +1565,17 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
if (status == -EINPROGRESS)
break;
- spin_lock(&urb->lock);
- if (urb->status == -EINPROGRESS) /* Not dequeued */
- urb->status = status;
- else
- status = ECONNRESET; /* Not -ECONNRESET */
- spin_unlock(&urb->lock);
-
/* Dequeued but completed URBs can't be given back unless
* the QH is stopped or has finished unlinking. */
- if (status == ECONNRESET) {
+ if (urb->unlinked) {
if (QH_FINISHED_UNLINKING(qh))
qh->is_stopped = 1;
else if (!qh->is_stopped)
return;
}
- uhci_giveback_urb(uhci, qh, urb);
- if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC)
+ uhci_giveback_urb(uhci, qh, urb, status);
+ if (status < 0)
break;
}
@@ -1599,7 +1590,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
restart:
list_for_each_entry(urbp, &qh->queue, node) {
urb = urbp->urb;
- if (urb->status != -EINPROGRESS) {
+ if (urb->unlinked) {
/* Fix up the TD links and save the toggles for
* non-Isochronous queues. For Isochronous queues,
@@ -1608,7 +1599,7 @@ restart:
qh->is_stopped = 0;
return;
}
- uhci_giveback_urb(uhci, qh, urb);
+ uhci_giveback_urb(uhci, qh, urb, 0);
goto restart;
}
}
diff --git a/drivers/usb/image/Kconfig b/drivers/usb/image/Kconfig
index 95ce703110d..7595dfb38e3 100644
--- a/drivers/usb/image/Kconfig
+++ b/drivers/usb/image/Kconfig
@@ -1,5 +1,5 @@
#
-# USB Imageing devices configuration
+# USB Imaging devices configuration
#
comment "USB Imaging devices"
depends on USB
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 768b2c11a23..91e999c9f68 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -446,7 +446,8 @@ static void mts_data_done( struct urb* transfer )
MTS_INT_INIT();
if ( context->data_length != transfer->actual_length ) {
- context->srb->resid = context->data_length - transfer->actual_length;
+ scsi_set_resid(context->srb, context->data_length -
+ transfer->actual_length);
} else if ( unlikely(status) ) {
context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
}
@@ -490,7 +491,8 @@ static void mts_command_done( struct urb *transfer )
context->data_pipe,
context->data,
context->data_length,
- context->srb->use_sg > 1 ? mts_do_sg : mts_data_done);
+ scsi_sg_count(context->srb) > 1 ?
+ mts_do_sg : mts_data_done);
} else {
mts_get_status(transfer);
}
@@ -505,21 +507,22 @@ static void mts_do_sg (struct urb* transfer)
int status = transfer->status;
MTS_INT_INIT();
- MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
+ MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,
+ scsi_sg_count(context->srb));
if (unlikely(status)) {
context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
mts_transfer_cleanup(transfer);
}
- sg = context->srb->request_buffer;
+ sg = scsi_sglist(context->srb);
context->fragment++;
mts_int_submit_urb(transfer,
context->data_pipe,
- page_address(sg[context->fragment].page) +
- sg[context->fragment].offset,
+ sg_virt(&sg[context->fragment]),
sg[context->fragment].length,
- context->fragment + 1 == context->srb->use_sg ? mts_data_done : mts_do_sg);
+ context->fragment + 1 == scsi_sg_count(context->srb) ?
+ mts_data_done : mts_do_sg);
return;
}
@@ -547,21 +550,13 @@ mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc)
desc->context.srb = srb;
desc->context.fragment = 0;
- if (!srb->use_sg) {
- if ( !srb->request_bufflen ){
- desc->context.data = NULL;
- desc->context.data_length = 0;
- return;
- } else {
- desc->context.data = srb->request_buffer;
- desc->context.data_length = srb->request_bufflen;
- MTS_DEBUG("length = %d or %d\n",
- srb->request_bufflen, srb->bufflen);
- }
+ if (!scsi_bufflen(srb)) {
+ desc->context.data = NULL;
+ desc->context.data_length = 0;
+ return;
} else {
- MTS_DEBUG("Using scatter/gather\n");
- sg = srb->request_buffer;
- desc->context.data = page_address(sg[0].page) + sg[0].offset;
+ sg = scsi_sglist(srb);
+ desc->context.data = sg_virt(&sg[0]);
desc->context.data_length = sg[0].length;
}
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index e9fdbc8997b..c567aa7a41e 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -188,7 +188,8 @@ static void adu_interrupt_in_callback(struct urb *urb)
spin_lock(&dev->buflock);
if (status != 0) {
- if ((status != -ENOENT) && (status != -ECONNRESET)) {
+ if ((status != -ENOENT) && (status != -ECONNRESET) &&
+ (status != -ESHUTDOWN)) {
dbg(1," %s : nonzero status received: %d",
__FUNCTION__, status);
}
@@ -804,7 +805,7 @@ static int adu_probe(struct usb_interface *interface,
dev->minor = interface->minor;
/* let the user know what node this device is now attached to */
- dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d",
+ dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d\n",
udev->descriptor.idProduct, dev->serial_number,
(dev->minor - ADU_MINOR_BASE));
exit:
@@ -850,7 +851,7 @@ static void adu_disconnect(struct usb_interface *interface)
mutex_unlock(&dev->mtx);
}
- dev_info(&interface->dev, "ADU device adutux%d now disconnected",
+ dev_info(&interface->dev, "ADU device adutux%d now disconnected\n",
(minor - ADU_MINOR_BASE));
dbg(2," %s : leave", __FUNCTION__);
diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c
index 92c1d2768df..24e2dc3148a 100644
--- a/drivers/usb/misc/berry_charge.c
+++ b/drivers/usb/misc/berry_charge.c
@@ -71,7 +71,7 @@ static int magic_charge(struct usb_device *udev)
if (retval != 2) {
dev_err(&udev->dev, "First magic command failed: %d.\n",
retval);
- return retval;
+ goto exit;
}
dbg(&udev->dev, "Sending second magic command\n");
@@ -80,7 +80,7 @@ static int magic_charge(struct usb_device *udev)
if (retval != 0) {
dev_err(&udev->dev, "Second magic command failed: %d.\n",
retval);
- return retval;
+ goto exit;
}
dbg(&udev->dev, "Calling set_configuration\n");
@@ -88,6 +88,8 @@ static int magic_charge(struct usb_device *udev)
if (retval)
dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
+exit:
+ kfree(dummy_buffer);
return retval;
}
@@ -112,6 +114,7 @@ static int magic_dual_mode(struct usb_device *udev)
if (retval)
dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
+ kfree(dummy_buffer);
return retval;
}
diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c
index 04e87acd6e4..1cd9e7eba93 100644
--- a/drivers/usb/misc/cytherm.c
+++ b/drivers/usb/misc/cytherm.c
@@ -118,7 +118,7 @@ static ssize_t set_brightness(struct device *dev, struct device_attribute *attr,
cytherm->brightness, buffer, 8);
if (retval)
dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval);
- /* Inform µC that we have changed the brightness setting */
+ /* Inform µC that we have changed the brightness setting */
retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS_SEM,
0x01, buffer, 8);
if (retval)
@@ -399,7 +399,6 @@ static void cytherm_disconnect(struct usb_interface *interface)
struct usb_cytherm *dev;
dev = usb_get_intfdata (interface);
- usb_set_intfdata (interface, NULL);
device_remove_file(&interface->dev, &dev_attr_brightness);
device_remove_file(&interface->dev, &dev_attr_temp);
@@ -407,6 +406,9 @@ static void cytherm_disconnect(struct usb_interface *interface)
device_remove_file(&interface->dev, &dev_attr_port0);
device_remove_file(&interface->dev, &dev_attr_port1);
+ /* first remove the files, then NULL the pointer */
+ usb_set_intfdata (interface, NULL);
+
usb_put_dev(dev->udev);
kfree(dev);
diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c
index 5c0a26cbd12..4a09b87bdd2 100644
--- a/drivers/usb/misc/emi26.c
+++ b/drivers/usb/misc/emi26.c
@@ -1,7 +1,7 @@
/*
* Emagic EMI 2|6 usb audio interface firmware loader.
* Copyright (C) 2002
- * Tapio Laxström (tapio.laxstrom@iptime.fi)
+ * Tapio Laxström (tapio.laxstrom@iptime.fi)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, as published by
@@ -114,6 +114,10 @@ static int emi26_load_firmware (struct usb_device *dev)
/* De-assert reset (let the CPU run) */
err = emi26_set_reset(dev,0);
+ if (err < 0) {
+ err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ goto wraperr;
+ }
msleep(250); /* let device settle */
/* 2. We upload the FPGA firmware into the EMI
@@ -249,7 +253,7 @@ static void __exit emi26_exit (void)
module_init(emi26_init);
module_exit(emi26_exit);
-MODULE_AUTHOR("tapio laxström");
+MODULE_AUTHOR("Tapio Laxström");
MODULE_DESCRIPTION("Emagic EMI 2|6 firmware loader.");
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c
index 23153eac0df..d1362415922 100644
--- a/drivers/usb/misc/emi62.c
+++ b/drivers/usb/misc/emi62.c
@@ -1,7 +1,7 @@
/*
* Emagic EMI 2|6 usb audio interface firmware loader.
* Copyright (C) 2002
- * Tapio Laxström (tapio.laxstrom@iptime.fi)
+ * Tapio Laxström (tapio.laxstrom@iptime.fi)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, as published by
@@ -123,6 +123,10 @@ static int emi62_load_firmware (struct usb_device *dev)
/* De-assert reset (let the CPU run) */
err = emi62_set_reset(dev,0);
+ if (err < 0) {
+ err("%s - error loading firmware: error = %d", __FUNCTION__, err);
+ goto wraperr;
+ }
msleep(250); /* let device settle */
/* 2. We upload the FPGA firmware into the EMI
@@ -292,7 +296,7 @@ static void __exit emi62_exit (void)
module_init(emi62_init);
module_exit(emi62_exit);
-MODULE_AUTHOR("tapio laxström");
+MODULE_AUTHOR("Tapio Laxström");
MODULE_DESCRIPTION("Emagic EMI 6|2m firmware loader.");
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 538b535e955..148b7fe639b 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -147,7 +147,7 @@ struct u132_target {
/* Structure to hold all of our device specific stuff*/
struct usb_ftdi {
struct list_head ftdi_list;
- struct semaphore u132_lock;
+ struct mutex u132_lock;
int command_next;
int command_head;
struct u132_command command[COMMAND_SIZE];
@@ -330,39 +330,39 @@ static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi)
static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi)
{
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
while (ftdi->respond_next > ftdi->respond_head) {
struct u132_respond *respond = &ftdi->respond[RESPOND_MASK &
ftdi->respond_head++];
*respond->result = -ESHUTDOWN;
*respond->value = 0;
complete(&respond->wait_completion);
- } up(&ftdi->u132_lock);
+ } mutex_unlock(&ftdi->u132_lock);
}
static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi)
{
int ed_number = 4;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
while (ed_number-- > 0) {
struct u132_target *target = &ftdi->target[ed_number];
if (target->active == 1) {
target->condition_code = TD_DEVNOTRESP;
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
ftdi_elan_do_callback(ftdi, target, NULL, 0);
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
}
}
ftdi->recieved = 0;
ftdi->expected = 4;
ftdi->ed_found = 0;
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
}
static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi)
{
int ed_number = 4;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
while (ed_number-- > 0) {
struct u132_target *target = &ftdi->target[ed_number];
target->abandoning = 1;
@@ -382,9 +382,9 @@ static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi)
ftdi->command_next += 1;
ftdi_elan_kick_command_queue(ftdi);
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
goto wait_1;
}
}
@@ -404,9 +404,9 @@ static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi)
ftdi->command_next += 1;
ftdi_elan_kick_command_queue(ftdi);
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
goto wait_2;
}
}
@@ -414,13 +414,13 @@ static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi)
ftdi->recieved = 0;
ftdi->expected = 4;
ftdi->ed_found = 0;
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
}
static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi)
{
int ed_number = 4;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
while (ed_number-- > 0) {
struct u132_target *target = &ftdi->target[ed_number];
target->abandoning = 1;
@@ -440,9 +440,9 @@ static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi)
ftdi->command_next += 1;
ftdi_elan_kick_command_queue(ftdi);
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
goto wait;
}
}
@@ -450,7 +450,7 @@ static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi)
ftdi->recieved = 0;
ftdi->expected = 4;
ftdi->ed_found = 0;
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
}
static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi)
@@ -886,14 +886,14 @@ static char *have_ed_set_response(struct usb_ftdi *ftdi,
char *b)
{
int payload = (ed_length >> 0) & 0x07FF;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
target->actual = 0;
target->non_null = (ed_length >> 15) & 0x0001;
target->repeat_number = (ed_length >> 11) & 0x000F;
if (ed_type == 0x02) {
if (payload == 0 || target->abandoning > 0) {
target->abandoning = 0;
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
payload);
ftdi->recieved = 0;
@@ -903,13 +903,13 @@ static char *have_ed_set_response(struct usb_ftdi *ftdi,
} else {
ftdi->expected = 4 + payload;
ftdi->ed_found = 1;
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
return b;
}
} else if (ed_type == 0x03) {
if (payload == 0 || target->abandoning > 0) {
target->abandoning = 0;
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
payload);
ftdi->recieved = 0;
@@ -919,12 +919,12 @@ static char *have_ed_set_response(struct usb_ftdi *ftdi,
} else {
ftdi->expected = 4 + payload;
ftdi->ed_found = 1;
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
return b;
}
} else if (ed_type == 0x01) {
target->abandoning = 0;
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
payload);
ftdi->recieved = 0;
@@ -933,7 +933,7 @@ static char *have_ed_set_response(struct usb_ftdi *ftdi,
return ftdi->response;
} else {
target->abandoning = 0;
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
payload);
ftdi->recieved = 0;
@@ -947,12 +947,12 @@ static char *have_ed_get_response(struct usb_ftdi *ftdi,
struct u132_target *target, u16 ed_length, int ed_number, int ed_type,
char *b)
{
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
target->condition_code = TD_DEVNOTRESP;
target->actual = (ed_length >> 0) & 0x01FF;
target->non_null = (ed_length >> 15) & 0x0001;
target->repeat_number = (ed_length >> 11) & 0x000F;
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
if (target->active)
ftdi_elan_do_callback(ftdi, target, NULL, 0);
target->abandoning = 0;
@@ -1278,7 +1278,7 @@ static int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data)
return -ENODEV;
} else {
int command_size;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
command_size = ftdi->command_next - ftdi->command_head;
if (command_size < COMMAND_SIZE) {
struct u132_command *command = &ftdi->command[
@@ -1292,10 +1292,10 @@ static int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data)
command->buffer = &command->value;
ftdi->command_next += 1;
ftdi_elan_kick_command_queue(ftdi);
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
return 0;
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
goto wait;
}
@@ -1310,7 +1310,7 @@ static int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset,
return -ENODEV;
} else {
int command_size;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
command_size = ftdi->command_next - ftdi->command_head;
if (command_size < COMMAND_SIZE) {
struct u132_command *command = &ftdi->command[
@@ -1324,10 +1324,10 @@ static int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset,
command->buffer = &command->value;
ftdi->command_next += 1;
ftdi_elan_kick_command_queue(ftdi);
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
return 0;
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
goto wait;
}
@@ -1342,7 +1342,7 @@ static int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset,
return -ENODEV;
} else {
int command_size;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
command_size = ftdi->command_next - ftdi->command_head;
if (command_size < COMMAND_SIZE) {
struct u132_command *command = &ftdi->command[
@@ -1356,10 +1356,10 @@ static int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset,
command->buffer = &command->value;
ftdi->command_next += 1;
ftdi_elan_kick_command_queue(ftdi);
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
return 0;
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
goto wait;
}
@@ -1382,7 +1382,7 @@ static int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data)
} else {
int command_size;
int respond_size;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
command_size = ftdi->command_next - ftdi->command_head;
respond_size = ftdi->respond_next - ftdi->respond_head;
if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
@@ -1405,11 +1405,11 @@ static int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data)
ftdi->command_next += 1;
ftdi->respond_next += 1;
ftdi_elan_kick_command_queue(ftdi);
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
wait_for_completion(&respond->wait_completion);
return result;
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
goto wait;
}
@@ -1425,7 +1425,7 @@ static int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset,
} else {
int command_size;
int respond_size;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
command_size = ftdi->command_next - ftdi->command_head;
respond_size = ftdi->respond_next - ftdi->respond_head;
if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
@@ -1449,11 +1449,11 @@ static int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset,
ftdi->command_next += 1;
ftdi->respond_next += 1;
ftdi_elan_kick_command_queue(ftdi);
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
wait_for_completion(&respond->wait_completion);
return result;
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
goto wait;
}
@@ -1469,7 +1469,7 @@ static int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset,
} else {
int command_size;
int respond_size;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
command_size = ftdi->command_next - ftdi->command_head;
respond_size = ftdi->respond_next - ftdi->respond_head;
if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
@@ -1493,11 +1493,11 @@ static int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset,
ftdi->command_next += 1;
ftdi->respond_next += 1;
ftdi_elan_kick_command_queue(ftdi);
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
wait_for_completion(&respond->wait_completion);
return result;
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
goto wait;
}
@@ -1529,7 +1529,7 @@ static int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number,
return -ENODEV;
} else {
int command_size;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
command_size = ftdi->command_next - ftdi->command_head;
if (command_size < COMMAND_SIZE) {
struct u132_target *target = &ftdi->target[ed];
@@ -1550,10 +1550,10 @@ static int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number,
target->active = 1;
ftdi->command_next += 1;
ftdi_elan_kick_command_queue(ftdi);
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
return 0;
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
goto wait;
}
@@ -1586,7 +1586,7 @@ static int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number,
return -ENODEV;
} else {
int command_size;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
command_size = ftdi->command_next - ftdi->command_head;
if (command_size < COMMAND_SIZE) {
struct u132_target *target = &ftdi->target[ed];
@@ -1615,10 +1615,10 @@ static int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number,
target->active = 1;
ftdi->command_next += 1;
ftdi_elan_kick_command_queue(ftdi);
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
return 0;
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
goto wait;
}
@@ -1651,7 +1651,7 @@ static int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number,
return -ENODEV;
} else {
int command_size;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
command_size = ftdi->command_next - ftdi->command_head;
if (command_size < COMMAND_SIZE) {
struct u132_target *target = &ftdi->target[ed];
@@ -1672,10 +1672,10 @@ static int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number,
target->active = 1;
ftdi->command_next += 1;
ftdi_elan_kick_command_queue(ftdi);
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
return 0;
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
goto wait;
}
@@ -1708,7 +1708,7 @@ static int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number,
return -ENODEV;
} else {
int command_size;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
command_size = ftdi->command_next - ftdi->command_head;
if (command_size < COMMAND_SIZE) {
u8 *b;
@@ -1751,10 +1751,10 @@ static int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number,
target->active = 1;
ftdi->command_next += 1;
ftdi_elan_kick_command_queue(ftdi);
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
return 0;
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
goto wait;
}
@@ -1787,7 +1787,7 @@ static int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number,
return -ENODEV;
} else {
int command_size;
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
command_size = ftdi->command_next - ftdi->command_head;
if (command_size < COMMAND_SIZE) {
int remaining_length = urb->transfer_buffer_length -
@@ -1816,10 +1816,10 @@ static int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number,
target->active = 1;
ftdi->command_next += 1;
ftdi_elan_kick_command_queue(ftdi);
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
return 0;
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
goto wait;
}
@@ -1849,9 +1849,9 @@ static int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number,
return -ENODEV;
} else {
struct u132_target *target = &ftdi->target[ed];
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
if (target->abandoning > 0) {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
return 0;
} else {
target->abandoning = 1;
@@ -1873,13 +1873,13 @@ static int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number,
ftdi->command_next += 1;
ftdi_elan_kick_command_queue(ftdi);
} else {
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
msleep(100);
- down(&ftdi->u132_lock);
+ mutex_lock(&ftdi->u132_lock);
goto wait_1;
}
}
- up(&ftdi->u132_lock);
+ mutex_unlock(&ftdi->u132_lock);
return 0;
}
}
@@ -2777,12 +2777,14 @@ static int ftdi_elan_probe(struct usb_interface *interface,
size_t buffer_size;
int i;
int retval = -ENOMEM;
- struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
- if (ftdi == NULL) {
+ struct usb_ftdi *ftdi;
+
+ ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
+ if (!ftdi) {
printk(KERN_ERR "Out of memory\n");
return -ENOMEM;
}
- memset(ftdi, 0x00, sizeof(struct usb_ftdi));
+
mutex_lock(&ftdi_module_lock);
list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
ftdi->sequence_num = ++ftdi_instances;
@@ -2791,7 +2793,7 @@ static int ftdi_elan_probe(struct usb_interface *interface,
init_MUTEX(&ftdi->sw_lock);
ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
ftdi->interface = interface;
- init_MUTEX(&ftdi->u132_lock);
+ mutex_init(&ftdi->u132_lock);
ftdi->expected = 4;
iface_desc = interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index e6fd024024f..4bcf7fb4e5d 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -66,6 +66,7 @@ static struct usb_device_id idmouse_table[] = {
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000)
MODULE_DEVICE_TABLE(usb, idmouse_table);
+static DEFINE_MUTEX(open_disc_mutex);
/* structure to hold all of our device specific stuff */
struct usb_idmouse {
@@ -80,7 +81,7 @@ struct usb_idmouse {
int open; /* if the port is open or not */
int present; /* if the device is not disconnected */
- struct semaphore sem; /* locks this structure */
+ struct mutex lock; /* locks this structure */
};
@@ -213,13 +214,17 @@ static int idmouse_open(struct inode *inode, struct file *file)
if (!interface)
return -ENODEV;
+ mutex_lock(&open_disc_mutex);
/* get the device information block from the interface */
dev = usb_get_intfdata(interface);
- if (!dev)
+ if (!dev) {
+ mutex_unlock(&open_disc_mutex);
return -ENODEV;
+ }
/* lock this device */
- down(&dev->sem);
+ mutex_lock(&dev->lock);
+ mutex_unlock(&open_disc_mutex);
/* check if already open */
if (dev->open) {
@@ -245,7 +250,7 @@ static int idmouse_open(struct inode *inode, struct file *file)
error:
/* unlock this device */
- up(&dev->sem);
+ mutex_unlock(&dev->lock);
return result;
}
@@ -258,12 +263,14 @@ static int idmouse_release(struct inode *inode, struct file *file)
if (dev == NULL)
return -ENODEV;
+ mutex_lock(&open_disc_mutex);
/* lock our device */
- down(&dev->sem);
+ mutex_lock(&dev->lock);
/* are we really open? */
if (dev->open <= 0) {
- up(&dev->sem);
+ mutex_unlock(&dev->lock);
+ mutex_unlock(&open_disc_mutex);
return -ENODEV;
}
@@ -271,10 +278,12 @@ static int idmouse_release(struct inode *inode, struct file *file)
if (!dev->present) {
/* the device was unplugged before the file was released */
- up(&dev->sem);
+ mutex_unlock(&dev->lock);
+ mutex_unlock(&open_disc_mutex);
idmouse_delete(dev);
} else {
- up(&dev->sem);
+ mutex_unlock(&dev->lock);
+ mutex_unlock(&open_disc_mutex);
}
return 0;
}
@@ -286,18 +295,18 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count
int result;
/* lock this object */
- down(&dev->sem);
+ mutex_lock(&dev->lock);
/* verify that the device wasn't unplugged */
if (!dev->present) {
- up(&dev->sem);
+ mutex_unlock(&dev->lock);
return -ENODEV;
}
result = simple_read_from_buffer(buffer, count, ppos,
dev->bulk_in_buffer, IMGSIZE);
/* unlock the device */
- up(&dev->sem);
+ mutex_unlock(&dev->lock);
return result;
}
@@ -320,7 +329,7 @@ static int idmouse_probe(struct usb_interface *interface,
if (dev == NULL)
return -ENOMEM;
- init_MUTEX(&dev->sem);
+ mutex_init(&dev->lock);
dev->udev = udev;
dev->interface = interface;
@@ -372,24 +381,26 @@ static void idmouse_disconnect(struct usb_interface *interface)
/* get device structure */
dev = usb_get_intfdata(interface);
- usb_set_intfdata(interface, NULL);
/* give back our minor */
usb_deregister_dev(interface, &idmouse_class);
- /* lock it */
- down(&dev->sem);
+ mutex_lock(&open_disc_mutex);
+ usb_set_intfdata(interface, NULL);
+ /* lock the device */
+ mutex_lock(&dev->lock);
+ mutex_unlock(&open_disc_mutex);
/* prevent device read, write and ioctl */
dev->present = 0;
/* if the device is opened, idmouse_release will clean this up */
if (!dev->open) {
- up(&dev->sem);
+ mutex_unlock(&dev->lock);
idmouse_delete(dev);
} else {
/* unlock */
- up(&dev->sem);
+ mutex_unlock(&dev->lock);
}
info("%s disconnected", DRIVER_DESC);
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 46d9f27ec17..764696ff1e8 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -66,6 +66,7 @@ module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "debug=1 enables debugging messages");
static struct usb_driver iowarrior_driver;
+static DEFINE_MUTEX(iowarrior_open_disc_lock);
/*--------------*/
/* data */
@@ -216,7 +217,7 @@ static void iowarrior_callback(struct urb *urb)
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d",
+ dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d\n",
__FUNCTION__, retval);
}
@@ -351,7 +352,7 @@ static ssize_t iowarrior_write(struct file *file,
mutex_lock(&dev->mutex);
/* verify that the device wasn't unplugged */
- if (dev == NULL || !dev->present) {
+ if (!dev->present) {
retval = -ENODEV;
goto exit;
}
@@ -451,7 +452,7 @@ static ssize_t iowarrior_write(struct file *file,
break;
default:
/* what do we have here ? An unsupported Product-ID ? */
- dev_err(&dev->interface->dev, "%s - not supported for product=0x%x",
+ dev_err(&dev->interface->dev, "%s - not supported for product=0x%x\n",
__FUNCTION__, dev->product_id);
retval = -EFAULT;
goto exit;
@@ -526,7 +527,7 @@ static int iowarrior_ioctl(struct inode *inode, struct file *file,
} else {
retval = -EINVAL;
dev_err(&dev->interface->dev,
- "ioctl 'IOW_WRITE' is not supported for product=0x%x.",
+ "ioctl 'IOW_WRITE' is not supported for product=0x%x.\n",
dev->product_id);
}
break;
@@ -608,11 +609,15 @@ static int iowarrior_open(struct inode *inode, struct file *file)
return -ENODEV;
}
+ mutex_lock(&iowarrior_open_disc_lock);
dev = usb_get_intfdata(interface);
- if (!dev)
+ if (!dev) {
+ mutex_unlock(&iowarrior_open_disc_lock);
return -ENODEV;
+ }
mutex_lock(&dev->mutex);
+ mutex_unlock(&iowarrior_open_disc_lock);
/* Only one process can open each device, no sharing. */
if (dev->opened) {
@@ -752,7 +757,7 @@ static int iowarrior_probe(struct usb_interface *interface,
/* allocate memory for our device state and intialize it */
dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL);
if (dev == NULL) {
- dev_err(&interface->dev, "Out of memory");
+ dev_err(&interface->dev, "Out of memory\n");
return retval;
}
@@ -866,6 +871,7 @@ static void iowarrior_disconnect(struct usb_interface *interface)
int minor;
dev = usb_get_intfdata(interface);
+ mutex_lock(&iowarrior_open_disc_lock);
usb_set_intfdata(interface, NULL);
minor = dev->minor;
@@ -879,6 +885,7 @@ static void iowarrior_disconnect(struct usb_interface *interface)
dev->present = 0;
mutex_unlock(&dev->mutex);
+ mutex_unlock(&iowarrior_open_disc_lock);
if (dev->opened) {
/* There is a process that holds a filedescriptor to the device ,
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 561970b889a..aab320085eb 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -198,6 +198,7 @@ static struct usb_device_id tower_table [] = {
};
MODULE_DEVICE_TABLE (usb, tower_table);
+static DEFINE_MUTEX(open_disc_mutex);
#define LEGO_USB_TOWER_MINOR_BASE 160
@@ -350,25 +351,31 @@ static int tower_open (struct inode *inode, struct file *file)
goto exit;
}
+ mutex_lock(&open_disc_mutex);
dev = usb_get_intfdata(interface);
if (!dev) {
+ mutex_unlock(&open_disc_mutex);
retval = -ENODEV;
goto exit;
}
/* lock this device */
if (down_interruptible (&dev->sem)) {
+ mutex_unlock(&open_disc_mutex);
retval = -ERESTARTSYS;
goto exit;
}
+
/* allow opening only once */
if (dev->open_count) {
+ mutex_unlock(&open_disc_mutex);
retval = -EBUSY;
goto unlock_exit;
}
dev->open_count = 1;
+ mutex_unlock(&open_disc_mutex);
/* reset the tower */
result = usb_control_msg (dev->udev,
@@ -437,9 +444,10 @@ static int tower_release (struct inode *inode, struct file *file)
if (dev == NULL) {
dbg(1, "%s: object is NULL", __FUNCTION__);
retval = -ENODEV;
- goto exit;
+ goto exit_nolock;
}
+ mutex_lock(&open_disc_mutex);
if (down_interruptible (&dev->sem)) {
retval = -ERESTARTSYS;
goto exit;
@@ -468,6 +476,8 @@ unlock_exit:
up (&dev->sem);
exit:
+ mutex_unlock(&open_disc_mutex);
+exit_nolock:
dbg(2, "%s: leave, return value %d", __FUNCTION__, retval);
return retval;
}
@@ -989,6 +999,7 @@ static void tower_disconnect (struct usb_interface *interface)
dbg(2, "%s: enter", __FUNCTION__);
dev = usb_get_intfdata (interface);
+ mutex_lock(&open_disc_mutex);
usb_set_intfdata (interface, NULL);
minor = dev->minor;
@@ -997,6 +1008,7 @@ static void tower_disconnect (struct usb_interface *interface)
usb_deregister_dev (interface, &tower_class);
down (&dev->sem);
+ mutex_unlock(&open_disc_mutex);
/* if the device is not opened, then we clean up right now */
if (!dev->open_count) {
diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c
index df0ebcdb9d6..2ad09b1f484 100644
--- a/drivers/usb/misc/phidgetmotorcontrol.c
+++ b/drivers/usb/misc/phidgetmotorcontrol.c
@@ -155,7 +155,7 @@ resubmit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
dev_err(&mc->intf->dev,
- "can't resubmit intr, %s-%s/motorcontrol0, retval %d",
+ "can't resubmit intr, %s-%s/motorcontrol0, retval %d\n",
mc->udev->bus->bus_name,
mc->udev->devpath, retval);
}
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 88f6abe7362..330c18e390b 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -118,10 +118,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
mutex_lock(&(rio->lock));
/* Sanity check to make sure rio is connected, powered, etc */
- if ( rio == NULL ||
- rio->present == 0 ||
- rio->rio_dev == NULL )
- {
+ if (rio->present == 0 || rio->rio_dev == NULL) {
retval = -ENODEV;
goto err_out;
}
@@ -280,10 +277,7 @@ write_rio(struct file *file, const char __user *buffer,
if (intr)
return -EINTR;
/* Sanity check to make sure rio is connected, powered, etc */
- if ( rio == NULL ||
- rio->present == 0 ||
- rio->rio_dev == NULL )
- {
+ if (rio->present == 0 || rio->rio_dev == NULL) {
mutex_unlock(&(rio->lock));
return -ENODEV;
}
@@ -369,10 +363,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
if (intr)
return -EINTR;
/* Sanity check to make sure rio is connected, powered, etc */
- if ( rio == NULL ||
- rio->present == 0 ||
- rio->rio_dev == NULL )
- {
+ if (rio->present == 0 || rio->rio_dev == NULL) {
mutex_unlock(&(rio->lock));
return -ENODEV;
}
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index b64ca91d9b0..9244d067cec 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -32,7 +32,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -962,12 +962,12 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
packet.address = 0x00000194;
packet.data = addr;
ret = sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
+ &packet, 0);
packet.header = 0x001f;
packet.address = 0x00000190;
packet.data = (length & ~3);
ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
+ &packet, 0);
if (sisusb->flagb0 != 0x16) {
packet.header = 0x001f;
packet.address = 0x00000180;
@@ -1003,23 +1003,17 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
if (ret) {
msgcount++;
if (msgcount < 500)
- printk(KERN_ERR
- "sisusbvga[%d]: Wrote %zd of "
- "%d bytes, error %d\n",
- sisusb->minor, *bytes_written,
- length, ret);
+ dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n",
+ *bytes_written, length, ret);
else if (msgcount == 500)
- printk(KERN_ERR
- "sisusbvga[%d]: Too many errors"
- ", logging stopped\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n");
}
addr += (*bytes_written);
length -= (*bytes_written);
}
if (ret)
- break;
+ break;
}
@@ -1261,51 +1255,10 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
addr += 4;
length -= 4;
}
-#if 0 /* That does not work, as EP 2 is an OUT EP! */
- default:
- CLEARPACKET(&packet);
- packet.header = 0x001f;
- packet.address = 0x000001a0;
- packet.data = 0x00000006;
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- packet.header = 0x001f;
- packet.address = 0x000001b0;
- packet.data = (length & ~3) | 0x40000000;
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- packet.header = 0x001f;
- packet.address = 0x000001b4;
- packet.data = addr;
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- packet.header = 0x001f;
- packet.address = 0x000001a4;
- packet.data = 0x00000001;
- ret |= sisusb_send_bridge_packet(sisusb, 10,
- &packet, 0);
- if (userbuffer) {
- ret |= sisusb_recv_bulk_msg(sisusb,
- SISUSB_EP_GFX_BULK_IN,
- (length & ~3),
- NULL, userbuffer,
- bytes_read, 0);
- if (!ret) userbuffer += (*bytes_read);
- } else {
- ret |= sisusb_recv_bulk_msg(sisusb,
- SISUSB_EP_GFX_BULK_IN,
- (length & ~3),
- kernbuffer, NULL,
- bytes_read, 0);
- if (!ret) kernbuffer += (*bytes_read);
- }
- addr += (*bytes_read);
- length -= (*bytes_read);
-#endif
}
if (ret)
- break;
+ break;
}
return ret;
@@ -1401,22 +1354,6 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
}
-#if 0
-
-int
-sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
-{
- return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-int
-sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
-{
- return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-#endif /* 0 */
-
int
sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
u32 dest, int length, size_t *bytes_written)
@@ -1446,10 +1383,10 @@ sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
for(i = 1; i <= 7; i++) {
- printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
+ dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i);
sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
for(j = 0; j < i; j++) {
- printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
+ dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]);
}
}
}
@@ -1533,9 +1470,9 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
#define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
#define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
#define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
#define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
static int
sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
@@ -2008,7 +1945,7 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
SETIREG(SISSR, 0x26, 0x00);
}
- SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
+ SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
return ret;
}
@@ -2168,17 +2105,12 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
if (ramtype <= 1) {
ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
if (iret) {
- printk(KERN_ERR "sisusbvga[%d]: RAM size "
- "detection failed, "
- "assuming 8MB video RAM\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n");
ret |= SETIREG(SISSR,0x14,0x31);
/* TODO */
}
} else {
- printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
- "assuming 8MB video RAM\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n");
ret |= SETIREG(SISSR,0x14,0x31);
/* *** TODO *** */
}
@@ -2249,8 +2181,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
break;
}
- printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
- sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
+ dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1,
ramtypetext2[ramtype], bw);
}
@@ -2509,11 +2440,8 @@ sisusb_open(struct inode *inode, struct file *file)
struct usb_interface *interface;
int subminor = iminor(inode);
- if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
- printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
- subminor);
+ if (!(interface = usb_find_interface(&sisusb_driver, subminor)))
return -ENODEV;
- }
if (!(sisusb = usb_get_intfdata(interface)))
return -ENODEV;
@@ -2534,18 +2462,12 @@ sisusb_open(struct inode *inode, struct file *file)
if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
if (sisusb_init_gfxdevice(sisusb, 0)) {
mutex_unlock(&sisusb->lock);
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to initialize "
- "device\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
return -EIO;
}
} else {
mutex_unlock(&sisusb->lock);
- printk(KERN_ERR
- "sisusbvga[%d]: Device not attached to "
- "USB 2.0 hub\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
return -EIO;
}
}
@@ -2586,7 +2508,6 @@ static int
sisusb_release(struct inode *inode, struct file *file)
{
struct sisusb_usb_data *sisusb;
- int myminor;
if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
return -ENODEV;
@@ -2599,8 +2520,6 @@ sisusb_release(struct inode *inode, struct file *file)
sisusb_kill_all_busy(sisusb);
}
- myminor = sisusb->minor;
-
sisusb->isopen = 0;
file->private_data = NULL;
@@ -2942,7 +2861,7 @@ static int
sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
unsigned long arg)
{
- int retval, port, length;
+ int retval, port, length;
u32 address;
/* All our commands require the device
@@ -3065,12 +2984,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
static int
sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
+ unsigned long arg)
{
struct sisusb_usb_data *sisusb;
struct sisusb_info x;
struct sisusb_command y;
- int retval = 0;
+ int retval = 0;
u32 __user *argp = (u32 __user *)arg;
if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
@@ -3095,7 +3014,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case SISUSB_GET_CONFIG:
- x.sisusb_id = SISUSB_ID;
+ x.sisusb_id = SISUSB_ID;
x.sisusb_version = SISUSB_VERSION;
x.sisusb_revision = SISUSB_REVISION;
x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
@@ -3164,7 +3083,7 @@ static const struct file_operations usb_sisusb_fops = {
.release = sisusb_release,
.read = sisusb_read,
.write = sisusb_write,
- .llseek = sisusb_lseek,
+ .llseek = sisusb_lseek,
#ifdef SISUSB_NEW_CONFIG_COMPAT
.compat_ioctl = sisusb_compat_ioctl,
#endif
@@ -3183,17 +3102,13 @@ static int sisusb_probe(struct usb_interface *intf,
struct usb_device *dev = interface_to_usbdev(intf);
struct sisusb_usb_data *sisusb;
int retval = 0, i;
- const char *memfail =
- KERN_ERR
- "sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
- printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
+ dev_info(&dev->dev, "USB2VGA dongle found at address %d\n",
dev->devnum);
/* Allocate memory for our private */
if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
- printk(KERN_ERR
- "sisusb: Failed to allocate memory for private data\n");
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n");
return -ENOMEM;
}
kref_init(&sisusb->kref);
@@ -3202,8 +3117,7 @@ static int sisusb_probe(struct usb_interface *intf,
/* Register device */
if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
- printk(KERN_ERR
- "sisusb: Failed to get a minor for device %d\n",
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n",
dev->devnum);
retval = -ENODEV;
goto error_1;
@@ -3221,7 +3135,7 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->ibufsize = SISUSB_IBUF_SIZE;
if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
GFP_KERNEL, &sisusb->transfer_dma_in))) {
- printk(memfail, "input", sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer");
retval = -ENOMEM;
goto error_2;
}
@@ -3233,7 +3147,7 @@ static int sisusb_probe(struct usb_interface *intf,
GFP_KERNEL,
&sisusb->transfer_dma_out[i]))) {
if (i == 0) {
- printk(memfail, "output", sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
retval = -ENOMEM;
goto error_3;
}
@@ -3245,9 +3159,7 @@ static int sisusb_probe(struct usb_interface *intf,
/* Allocate URBs */
if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to allocate URBs\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
retval = -ENOMEM;
goto error_3;
}
@@ -3255,9 +3167,7 @@ static int sisusb_probe(struct usb_interface *intf,
for (i = 0; i < sisusb->numobufs; i++) {
if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to allocate URBs\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
retval = -ENOMEM;
goto error_4;
}
@@ -3266,15 +3176,12 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->urbstatus[i] = 0;
}
- printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
- sisusb->minor, sisusb->numobufs);
+ dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs);
#ifdef INCL_SISUSB_CON
/* Allocate our SiS_Pr */
if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to allocate SiS_Pr\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n");
}
#endif
@@ -3296,10 +3203,7 @@ static int sisusb_probe(struct usb_interface *intf,
ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
if (ret)
- printk(KERN_ERR
- "sisusbvga[%d]: Error registering ioctl32 "
- "translations\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n");
else
sisusb->ioctl32registered = 1;
}
@@ -3315,23 +3219,17 @@ static int sisusb_probe(struct usb_interface *intf,
initscreen = 0;
#endif
if (sisusb_init_gfxdevice(sisusb, initscreen))
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to early "
- "initialize device\n",
- sisusb->minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n");
} else
- printk(KERN_INFO
- "sisusbvga[%d]: Not attached to USB 2.0 hub, "
- "deferring init\n",
- sisusb->minor);
+ dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n");
sisusb->ready = 1;
#ifdef SISUSBENDIANTEST
- printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
+ dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n");
sisusb_testreadwrite(sisusb);
- printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
+ dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n");
#endif
#ifdef INCL_SISUSB_CON
@@ -3354,7 +3252,6 @@ error_1:
static void sisusb_disconnect(struct usb_interface *intf)
{
struct sisusb_usb_data *sisusb;
- int minor;
/* This should *not* happen */
if (!(sisusb = usb_get_intfdata(intf)))
@@ -3364,8 +3261,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
sisusb_console_exit(sisusb);
#endif
- minor = sisusb->minor;
-
usb_deregister_dev(intf, &usb_sisusb_class);
mutex_lock(&sisusb->lock);
@@ -3384,10 +3279,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
if (ret) {
- printk(KERN_ERR
- "sisusbvga[%d]: Error unregistering "
- "ioctl32 translations\n",
- minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n");
}
}
#endif
@@ -3400,7 +3292,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
/* decrement our usage count */
kref_put(&sisusb->kref, sisusb_delete);
- printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
+ dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
}
static struct usb_device_id sisusb_table [] = {
@@ -3424,22 +3316,12 @@ static struct usb_driver sisusb_driver = {
static int __init usb_sisusb_init(void)
{
- int retval;
#ifdef INCL_SISUSB_CON
sisusb_init_concode();
#endif
- if (!(retval = usb_register(&sisusb_driver))) {
-
- printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
- SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
- printk(KERN_INFO
- "sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
-
- }
-
- return retval;
+ return usb_register(&sisusb_driver);
}
static void __exit usb_sisusb_exit(void)
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
index 8e1120a6480..d2d7872cd02 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.h
+++ b/drivers/usb/misc/sisusbvga/sisusb.h
@@ -8,29 +8,29 @@
*
* Otherwise, the following license terms apply:
*
- * * Redistribution and use in source and binary forms, with or without
- * * modification, are permitted provided that the following conditions
- * * are met:
- * * 1) Redistributions of source code must retain the above copyright
- * * notice, this list of conditions and the following disclaimer.
- * * 2) Redistributions in binary form must reproduce the above copyright
- * * notice, this list of conditions and the following disclaimer in the
- * * documentation and/or other materials provided with the distribution.
- * * 3) The name of the author may not be used to endorse or promote products
- * * derived from this software without specific prior written permission.
- * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
- * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1) Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2) Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3) The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -44,16 +44,14 @@
#include <linux/mutex.h>
/* For older kernels, support for text consoles is by default
- * off. To ensable text console support, change the following:
+ * off. To enable text console support, change the following:
*/
-#if 0
-#define CONFIG_USB_SISUSBVGA_CON
-#endif
+/* #define CONFIG_USB_SISUSBVGA_CON */
/* Version Information */
#define SISUSB_VERSION 0
-#define SISUSB_REVISION 0
+#define SISUSB_REVISION 0
#define SISUSB_PATCHLEVEL 8
/* Include console and mode switching code? */
@@ -74,7 +72,7 @@
#define SISUSB_IBUF_SIZE 0x01000
#define SISUSB_OBUF_SIZE 0x10000 /* fixed */
-#define NUMOBUFS 8 /* max number of output buffers/output URBs */
+#define NUMOBUFS 8 /* max number of output buffers/output URBs */
/* About endianness:
*
@@ -93,7 +91,7 @@
*/
#ifdef __BIG_ENDIAN
-#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \
do { \
p->header = cpu_to_le16(p->header); \
p->address = cpu_to_le32(p->address); \
@@ -105,7 +103,7 @@
struct sisusb_usb_data;
-struct sisusb_urb_context { /* urb->context for outbound bulk URBs */
+struct sisusb_urb_context { /* urb->context for outbound bulk URBs */
struct sisusb_usb_data *sisusb;
int urbindex;
int *actual_length;
@@ -116,16 +114,16 @@ struct sisusb_usb_data {
struct usb_interface *interface;
struct kref kref;
wait_queue_head_t wait_q; /* for syncind and timeouts */
- struct mutex lock; /* general race avoidance */
- unsigned int ifnum; /* interface number of the USB device */
- int minor; /* minor (for logging clarity) */
- int isopen; /* !=0 if open */
- int present; /* !=0 if device is present on the bus */
- int ready; /* !=0 if device is ready for userland */
+ struct mutex lock; /* general race avoidance */
+ unsigned int ifnum; /* interface number of the USB device */
+ int minor; /* minor (for logging clarity) */
+ int isopen; /* !=0 if open */
+ int present; /* !=0 if device is present on the bus */
+ int ready; /* !=0 if device is ready for userland */
#ifdef SISUSB_OLD_CONFIG_COMPAT
int ioctl32registered;
#endif
- int numobufs; /* number of obufs = number of out urbs */
+ int numobufs; /* number of obufs = number of out urbs */
char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */
int obufsize, ibufsize;
dma_addr_t transfer_dma_out[NUMOBUFS];
@@ -136,13 +134,13 @@ struct sisusb_usb_data {
unsigned char completein;
struct sisusb_urb_context urbout_context[NUMOBUFS];
unsigned long flagb0;
- unsigned long vrambase; /* framebuffer base */
- unsigned int vramsize; /* framebuffer size (bytes) */
+ unsigned long vrambase; /* framebuffer base */
+ unsigned int vramsize; /* framebuffer size (bytes) */
unsigned long mmiobase;
unsigned int mmiosize;
unsigned long ioportbase;
- unsigned char devinit; /* device initialized? */
- unsigned char gfxinit; /* graphics core initialized? */
+ unsigned char devinit; /* device initialized? */
+ unsigned char gfxinit; /* graphics core initialized? */
unsigned short chipid, chipvendor;
unsigned short chiprevision;
#ifdef INCL_SISUSB_CON
@@ -152,7 +150,7 @@ struct sisusb_usb_data {
int haveconsole, con_first, con_last;
int havethisconsole[MAX_NR_CONSOLES];
int textmodedestroyed;
- unsigned int sisusb_num_columns; /* real number, not vt's idea */
+ unsigned int sisusb_num_columns; /* real number, not vt's idea */
int cur_start_addr, con_rolled_over;
int sisusb_cursor_loc, bad_cursor_pos;
int sisusb_cursor_size_from;
@@ -197,7 +195,7 @@ struct sisusb_packet {
unsigned short header;
u32 address;
u32 data;
-} __attribute__((__packed__));
+} __attribute__ ((__packed__));
#define CLEARPACKET(packet) memset(packet, 0, 10)
@@ -265,36 +263,36 @@ struct sisusb_packet {
/* Structure argument for SISUSB_GET_INFO ioctl */
struct sisusb_info {
- __u32 sisusb_id; /* for identifying sisusb */
-#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */
- __u8 sisusb_version;
- __u8 sisusb_revision;
- __u8 sisusb_patchlevel;
- __u8 sisusb_gfxinit; /* graphics core initialized? */
+ __u32 sisusb_id; /* for identifying sisusb */
+#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */
+ __u8 sisusb_version;
+ __u8 sisusb_revision;
+ __u8 sisusb_patchlevel;
+ __u8 sisusb_gfxinit; /* graphics core initialized? */
- __u32 sisusb_vrambase;
- __u32 sisusb_mmiobase;
- __u32 sisusb_iobase;
- __u32 sisusb_pcibase;
+ __u32 sisusb_vrambase;
+ __u32 sisusb_mmiobase;
+ __u32 sisusb_iobase;
+ __u32 sisusb_pcibase;
- __u32 sisusb_vramsize; /* framebuffer size in bytes */
+ __u32 sisusb_vramsize; /* framebuffer size in bytes */
- __u32 sisusb_minor;
+ __u32 sisusb_minor;
- __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */
+ __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */
- __u32 sisusb_conactive; /* != 0 if console driver active */
+ __u32 sisusb_conactive; /* != 0 if console driver active */
- __u8 sisusb_reserved[28]; /* for future use */
+ __u8 sisusb_reserved[28]; /* for future use */
};
struct sisusb_command {
- __u8 operation; /* see below */
- __u8 data0; /* operation dependent */
- __u8 data1; /* operation dependent */
- __u8 data2; /* operation dependent */
- __u32 data3; /* operation dependent */
- __u32 data4; /* for future use */
+ __u8 operation; /* see below */
+ __u8 data0; /* operation dependent */
+ __u8 data1; /* operation dependent */
+ __u8 data2; /* operation dependent */
+ __u32 data3; /* operation dependent */
+ __u32 data4; /* for future use */
};
#define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */
@@ -306,7 +304,7 @@ struct sisusb_command {
#define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */
-#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
+#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
#define SUCMD_SETMODE 0x09 /* Set a display mode (data3 = SiS mode) */
#define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */
@@ -315,6 +313,4 @@ struct sisusb_command {
#define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32)
#define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info)
-
#endif /* SISUSB_H */
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 8d0edc867f3..b624320df90 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -52,6 +52,7 @@
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/fs.h>
+#include <linux/usb.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
@@ -373,14 +374,6 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
return;
/* sisusb->lock is down */
-
- /* Don't need to put the character into buffer ourselves,
- * because the vt does this BEFORE calling us.
- */
-#if 0
- sisusbcon_writew(ch, SISUSB_VADDR(x, y));
-#endif
-
if (sisusb_is_inactive(c, sisusb)) {
mutex_unlock(&sisusb->lock);
return;
@@ -490,10 +483,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
struct sisusb_usb_data *sisusb;
ssize_t written;
int cols, length;
-#if 0
- u16 *src, *dest;
- int i;
-#endif
if (width <= 0 || height <= 0)
return;
@@ -505,41 +494,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
cols = sisusb->sisusb_num_columns;
- /* Don't need to move data outselves, because
- * vt does this BEFORE calling us.
- * This is only used by vt's insert/deletechar.
- */
-#if 0
- if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) {
-
- sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy),
- height * width * 2);
-
- } else if (dy < sy || (dy == sy && dx < sx)) {
-
- src = SISUSB_VADDR(sx, sy);
- dest = SISUSB_VADDR(dx, dy);
-
- for (i = height; i > 0; i--) {
- sisusbcon_memmovew(dest, src, width * 2);
- src += cols;
- dest += cols;
- }
-
- } else {
-
- src = SISUSB_VADDR(sx, sy + height - 1);
- dest = SISUSB_VADDR(dx, dy + height - 1);
-
- for (i = height; i > 0; i--) {
- sisusbcon_memmovew(dest, src, width * 2);
- src -= cols;
- dest -= cols;
- }
-
- }
-#endif
-
if (sisusb_is_inactive(c, sisusb)) {
mutex_unlock(&sisusb->lock);
return;
@@ -584,7 +538,7 @@ sisusbcon_switch(struct vc_data *c)
*/
if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
mutex_unlock(&sisusb->lock);
- printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
+ dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n");
return 0;
}
@@ -1088,7 +1042,8 @@ sisusbcon_set_origin(struct vc_data *c)
/* Interface routine */
static int
-sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows)
+sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows,
+ unsigned int user)
{
struct sisusb_usb_data *sisusb;
int fh;
@@ -1475,7 +1430,7 @@ static const struct consw sisusb_dummy_con = {
int
sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
{
- int i, ret, minor = sisusb->minor;
+ int i, ret;
mutex_lock(&sisusb->lock);
@@ -1508,9 +1463,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
/* Set up text mode (and upload default font) */
if (sisusb_reset_text_mode(sisusb, 1)) {
mutex_unlock(&sisusb->lock);
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to set up text mode\n",
- minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n");
return 1;
}
@@ -1531,9 +1484,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
/* Allocate screen buffer */
if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
mutex_unlock(&sisusb->lock);
- printk(KERN_ERR
- "sisusbvga[%d]: Failed to allocate screen buffer\n",
- minor);
+ dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n");
return 1;
}
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c
index 9b30f896281..273de5d0934 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.c
@@ -32,7 +32,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -55,109 +55,18 @@
/* POINTER INITIALIZATION */
/*********************************************/
-static void
-SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
+static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
{
- SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
- SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
-
- SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
- SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
- SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
- SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
-
- SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
-}
-
-/*********************************************/
-/* HELPER: Get ModeID */
-/*********************************************/
+ SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
+ SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
-#if 0
-unsigned short
-SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
-{
- unsigned short ModeIndex = 0;
-
- switch (HDisplay)
- {
- case 320:
- if (VDisplay == 200)
- ModeIndex = ModeIndex_320x200[Depth];
- else if (VDisplay == 240)
- ModeIndex = ModeIndex_320x240[Depth];
- break;
- case 400:
- if (VDisplay == 300)
- ModeIndex = ModeIndex_400x300[Depth];
- break;
- case 512:
- if (VDisplay == 384)
- ModeIndex = ModeIndex_512x384[Depth];
- break;
- case 640:
- if (VDisplay == 480)
- ModeIndex = ModeIndex_640x480[Depth];
- else if (VDisplay == 400)
- ModeIndex = ModeIndex_640x400[Depth];
- break;
- case 720:
- if (VDisplay == 480)
- ModeIndex = ModeIndex_720x480[Depth];
- else if (VDisplay == 576)
- ModeIndex = ModeIndex_720x576[Depth];
- break;
- case 768:
- if (VDisplay == 576)
- ModeIndex = ModeIndex_768x576[Depth];
- break;
- case 800:
- if (VDisplay == 600)
- ModeIndex = ModeIndex_800x600[Depth];
- else if (VDisplay == 480)
- ModeIndex = ModeIndex_800x480[Depth];
- break;
- case 848:
- if (VDisplay == 480)
- ModeIndex = ModeIndex_848x480[Depth];
- break;
- case 856:
- if (VDisplay == 480)
- ModeIndex = ModeIndex_856x480[Depth];
- break;
- case 960:
- if (VDisplay == 540)
- ModeIndex = ModeIndex_960x540[Depth];
- else if (VDisplay == 600)
- ModeIndex = ModeIndex_960x600[Depth];
- break;
- case 1024:
- if (VDisplay == 576)
- ModeIndex = ModeIndex_1024x576[Depth];
- else if (VDisplay == 768)
- ModeIndex = ModeIndex_1024x768[Depth];
- break;
- case 1152:
- if (VDisplay == 864)
- ModeIndex = ModeIndex_1152x864[Depth];
- break;
- case 1280:
- switch (VDisplay) {
- case 720:
- ModeIndex = ModeIndex_1280x720[Depth];
- break;
- case 768:
- ModeIndex = ModeIndex_1280x768[Depth];
- break;
- case 1024:
- ModeIndex = ModeIndex_1280x1024[Depth];
- break;
- }
- }
+ SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
+ SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
+ SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
+ SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
- return ModeIndex;
+ SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
}
-#endif /* 0 */
/*********************************************/
/* HELPER: SetReg, GetReg */
@@ -165,21 +74,20 @@ SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
static void
SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short index, unsigned short data)
+ unsigned short index, unsigned short data)
{
sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
}
static void
SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short data)
+ unsigned short data)
{
sisusb_setreg(SiS_Pr->sisusb, port, data);
}
static unsigned char
-SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short index)
+SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index)
{
u8 data;
@@ -200,22 +108,22 @@ SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port)
static void
SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short index, unsigned short DataAND,
- unsigned short DataOR)
+ unsigned short index, unsigned short DataAND,
+ unsigned short DataOR)
{
sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
}
static void
SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
- unsigned short index, unsigned short DataAND)
+ unsigned short index, unsigned short DataAND)
{
sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
}
static void
-SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
- unsigned short index, unsigned short DataOR)
+SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port,
+ unsigned short index, unsigned short DataOR)
{
sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
}
@@ -224,8 +132,7 @@ SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
/* HELPER: DisplayOn, DisplayOff */
/*********************************************/
-static void
-SiS_DisplayOn(struct SiS_Private *SiS_Pr)
+static void SiS_DisplayOn(struct SiS_Private *SiS_Pr)
{
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
}
@@ -234,8 +141,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr)
/* HELPER: Init Port Addresses */
/*********************************************/
-static void
-SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
+static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
{
SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
@@ -258,8 +164,7 @@ SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
/* HELPER: GetSysFlags */
/*********************************************/
-static void
-SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
+static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
{
SiS_Pr->SiS_MyCR63 = 0x63;
}
@@ -268,8 +173,7 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
/* HELPER: Init PCI & Engines */
/*********************************************/
-static void
-SiSInitPCIetc(struct SiS_Private *SiS_Pr)
+static void SiSInitPCIetc(struct SiS_Private *SiS_Pr)
{
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
/* - Enable 2D (0x40)
@@ -285,8 +189,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr)
/* HELPER: SET SEGMENT REGISTERS */
/*********************************************/
-static void
-SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
{
unsigned short temp;
@@ -299,8 +202,7 @@ SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
}
-static void
-SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
{
unsigned short temp;
@@ -313,15 +215,13 @@ SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
}
-static void
-SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
{
SiS_SetSegRegLower(SiS_Pr, value);
SiS_SetSegRegUpper(SiS_Pr, value);
}
-static void
-SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
{
SiS_SetSegmentReg(SiS_Pr, 0);
}
@@ -337,14 +237,12 @@ SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
SiS_SetSegmentReg(SiS_Pr, value);
}
-static void
-SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
{
SiS_SetSegmentRegOver(SiS_Pr, 0);
}
-static void
-SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
{
SiS_ResetSegmentReg(SiS_Pr);
SiS_ResetSegmentRegOver(SiS_Pr);
@@ -356,7 +254,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
static int
SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
- unsigned short *ModeIdIndex)
+ unsigned short *ModeIdIndex)
{
if ((*ModeNo) <= 0x13) {
@@ -367,12 +265,14 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
} else {
- for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
+ for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
- if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo))
+ if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+ (*ModeNo))
break;
- if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+ if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+ 0xFF)
return 0;
}
@@ -385,8 +285,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
/* HELPER: ENABLE CRT1 */
/*********************************************/
-static void
-SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
+static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
{
/* Enable CRT1 gating */
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
@@ -398,9 +297,9 @@ SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
static unsigned short
SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex)
+ unsigned short ModeIdIndex)
{
- static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
+ static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
unsigned short modeflag;
short index;
@@ -411,7 +310,8 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
}
index = (modeflag & ModeTypeMask) - ModeEGA;
- if (index < 0) index = 0;
+ if (index < 0)
+ index = 0;
return ColorDepth[index];
}
@@ -421,7 +321,7 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static unsigned short
SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex, unsigned short rrti)
+ unsigned short ModeIdIndex, unsigned short rrti)
{
unsigned short xres, temp, colordepth, infoflag;
@@ -458,8 +358,8 @@ SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
- for(i = 2; i <= 4; i++) {
- SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
+ for (i = 2; i <= 4; i++) {
+ SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1];
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
}
}
@@ -488,7 +388,7 @@ SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
- for(i = 0; i <= 0x18; i++) {
+ for (i = 0; i <= 0x18; i++) {
CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
}
@@ -504,7 +404,7 @@ SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
unsigned char ARdata;
unsigned short i;
- for(i = 0; i <= 0x13; i++) {
+ for (i = 0; i <= 0x13; i++) {
ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
@@ -529,7 +429,7 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
unsigned char GRdata;
unsigned short i;
- for(i = 0; i <= 0x08; i++) {
+ for (i = 0; i <= 0x08; i++) {
GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
}
@@ -544,12 +444,11 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
/* CLEAR EXTENDED REGISTERS */
/*********************************************/
-static void
-SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
int i;
- for(i = 0x0A; i <= 0x0E; i++) {
+ for (i = 0x0A; i <= 0x0E; i++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
}
@@ -562,15 +461,16 @@ SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
static unsigned short
SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex)
+ unsigned short ModeIdIndex)
{
unsigned short rrti, i, index, temp;
if (ModeNo <= 0x13)
return 0xFFFF;
- index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
- if (index > 0) index--;
+ index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
+ if (index > 0)
+ index--;
rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
@@ -580,13 +480,14 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
break;
- temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
+ temp =
+ SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
if (temp < SiS_Pr->SiS_ModeType)
break;
i++;
index--;
- } while(index != 0xFFFF);
+ } while (index != 0xFFFF);
i--;
@@ -597,8 +498,7 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
/* SYNC */
/*********************************************/
-static void
-SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
+static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
{
unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
sync &= 0xC0;
@@ -612,39 +512,40 @@ SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
static void
SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex, unsigned short rrti)
+ unsigned short ModeIdIndex, unsigned short rrti)
{
- unsigned char index;
+ unsigned char index;
unsigned short temp, i, j, modeflag;
- SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f);
+ SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
- for(i = 0,j = 0; i <= 7; i++, j++) {
+ for (i = 0, j = 0; i <= 7; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
- SiS_Pr->SiS_CRT1Table[index].CR[i]);
+ SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
- for(j = 0x10; i <= 10; i++, j++) {
+ for (j = 0x10; i <= 10; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
- SiS_Pr->SiS_CRT1Table[index].CR[i]);
+ SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
- for(j = 0x15; i <= 12; i++, j++) {
+ for (j = 0x15; i <= 12; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
- SiS_Pr->SiS_CRT1Table[index].CR[i]);
+ SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
- for(j = 0x0A; i <= 15; i++, j++) {
+ for (j = 0x0A; i <= 15; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
- SiS_Pr->SiS_CRT1Table[index].CR[i]);
+ SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
- SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp);
+ SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp);
temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
- if (modeflag & DoubleScanMode) temp |= 0x80;
+ if (modeflag & DoubleScanMode)
+ temp |= 0x80;
SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
if (SiS_Pr->SiS_ModeType > ModeVGA)
@@ -659,10 +560,10 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex, unsigned short rrti)
+ unsigned short ModeIdIndex, unsigned short rrti)
{
unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
- unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+ unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
unsigned short temp;
temp = (du >> 8) & 0x0f;
@@ -670,11 +571,13 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
- if (infoflag & InterlaceMode) du >>= 1;
+ if (infoflag & InterlaceMode)
+ du >>= 1;
du <<= 5;
temp = (du >> 8) & 0xff;
- if (du & 0xff) temp++;
+ if (du & 0xff)
+ temp++;
temp++;
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
}
@@ -685,17 +588,17 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short rrti)
+ unsigned short rrti)
{
unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
- SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF);
+ SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF);
- SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka);
- SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb);
- SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01);
+ SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka);
+ SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb);
+ SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01);
}
/*********************************************/
@@ -704,7 +607,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short mi)
+ unsigned short mi)
{
unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
@@ -729,7 +632,7 @@ SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short rrti)
+ unsigned short rrti)
{
unsigned short data = 0, VCLK = 0, index = 0;
@@ -738,7 +641,8 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
}
- if (VCLK >= 166) data |= 0x0c;
+ if (VCLK >= 166)
+ data |= 0x0c;
SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
if (VCLK >= 166)
@@ -758,7 +662,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex, unsigned short rrti)
+ unsigned short ModeIdIndex, unsigned short rrti)
{
unsigned short data, infoflag = 0, modeflag;
@@ -778,17 +682,22 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
data |= 0x02;
data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
}
- if (infoflag & InterlaceMode) data |= 0x20;
+ if (infoflag & InterlaceMode)
+ data |= 0x20;
}
SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
data = 0;
if (infoflag & InterlaceMode) {
/* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
- unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
- ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3;
- unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
- ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5;
+ unsigned short hrs =
+ (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
+ ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2))
+ - 3;
+ unsigned short hto =
+ (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
+ ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8))
+ + 5;
data = hrs - (hto >> 1) + 3;
}
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
@@ -829,20 +738,26 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
- unsigned short shiftflag, unsigned short dl, unsigned short ah,
- unsigned short al, unsigned short dh)
+ unsigned short shiftflag, unsigned short dl, unsigned short ah,
+ unsigned short al, unsigned short dh)
{
unsigned short d1, d2, d3;
switch (dl) {
- case 0:
- d1 = dh; d2 = ah; d3 = al;
- break;
- case 1:
- d1 = ah; d2 = al; d3 = dh;
- break;
- default:
- d1 = al; d2 = dh; d3 = ah;
+ case 0:
+ d1 = dh;
+ d2 = ah;
+ d3 = al;
+ break;
+ case 1:
+ d1 = ah;
+ d2 = al;
+ d3 = dh;
+ break;
+ default:
+ d1 = al;
+ d2 = dh;
+ d3 = ah;
}
SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
@@ -850,7 +765,8 @@ SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
}
static void
-SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi)
+SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+ unsigned short mi)
{
unsigned short data, data2, time, i, j, k, m, n, o;
unsigned short si, di, bx, sf;
@@ -884,41 +800,45 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
- for(i = 0; i < j; i++) {
+ for (i = 0; i < j; i++) {
data = table[i];
- for(k = 0; k < 3; k++) {
+ for (k = 0; k < 3; k++) {
data2 = 0;
- if (data & 0x01) data2 += 0x2A;
- if (data & 0x02) data2 += 0x15;
+ if (data & 0x01)
+ data2 += 0x2A;
+ if (data & 0x02)
+ data2 += 0x15;
SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
data >>= 2;
}
}
if (time == 256) {
- for(i = 16; i < 32; i++) {
+ for (i = 16; i < 32; i++) {
data = table[i] << sf;
- for(k = 0; k < 3; k++)
+ for (k = 0; k < 3; k++)
SiS_SetRegByte(SiS_Pr, DACData, data);
}
si = 32;
- for(m = 0; m < 9; m++) {
+ for (m = 0; m < 9; m++) {
di = si;
bx = si + 4;
- for(n = 0; n < 3; n++) {
- for(o = 0; o < 5; o++) {
+ for (n = 0; n < 3; n++) {
+ for (o = 0; o < 5; o++) {
SiS_WriteDAC(SiS_Pr, DACData, sf, n,
- table[di], table[bx], table[si]);
+ table[di], table[bx],
+ table[si]);
si++;
}
si -= 2;
- for(o = 0; o < 3; o++) {
+ for (o = 0; o < 3; o++) {
SiS_WriteDAC(SiS_Pr, DACData, sf, n,
- table[di], table[si], table[bx]);
+ table[di], table[si],
+ table[bx]);
si--;
}
}
- si += 5;
+ si += 5;
}
}
}
@@ -929,7 +849,7 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
static void
SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
- unsigned short ModeIdIndex)
+ unsigned short ModeIdIndex)
{
unsigned short StandTableIndex, rrti;
@@ -970,11 +890,10 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
/* SiSSetMode() */
/*********************************************/
-int
-SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
unsigned short ModeIdIndex;
- unsigned long BaseAddr = SiS_Pr->IOAddress;
+ unsigned long BaseAddr = SiS_Pr->IOAddress;
SiSUSB_InitPtr(SiS_Pr);
SiSUSBRegInit(SiS_Pr, BaseAddr);
@@ -990,7 +909,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
ModeNo &= 0x7f;
SiS_Pr->SiS_ModeType =
- SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
+ SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
SiS_Pr->SiS_SetFlag = LowModeTests;
@@ -1008,8 +927,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
return 1;
}
-int
-SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
{
unsigned short ModeNo = 0;
int i;
@@ -1041,7 +959,3 @@ SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
}
#endif /* INCL_SISUSB_CON */
-
-
-
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h
index 864bc0e9659..c46ce42d448 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.h
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.h
@@ -46,7 +46,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -76,21 +76,21 @@
#define CRT2Mode 0x0800
#define HalfDCLK 0x1000
#define NoSupportSimuTV 0x2000
-#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */
+#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */
#define DoubleScanMode 0x8000
/* Infoflag */
#define SupportTV 0x0008
#define SupportTV1024 0x0800
-#define SupportCHTV 0x0800
-#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */
+#define SupportCHTV 0x0800
+#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */
#define SupportHiVision 0x0010
#define SupportYPbPr750p 0x1000
#define SupportLCD 0x0020
#define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */
-#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */
-#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */
-#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */
+#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */
+#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */
+#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */
#define InterlaceMode 0x0080
#define SyncPP 0x0000
#define SyncPN 0x4000
@@ -129,7 +129,7 @@
#define SIS_RI_856x480 19
#define SIS_RI_1280x768 20
#define SIS_RI_1400x1050 21
-#define SIS_RI_1152x864 22 /* Up to here SiS conforming */
+#define SIS_RI_1152x864 22 /* Up to here SiS conforming */
#define SIS_RI_848x480 23
#define SIS_RI_1360x768 24
#define SIS_RI_1024x600 25
@@ -147,691 +147,691 @@
#define SIS_CRT2_PORT_04 0x04 - 0x30
/* Mode numbers */
-static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f};
-static const unsigned short ModeIndex_320x240[] = {0x50, 0x56, 0x00, 0x53};
-static const unsigned short ModeIndex_400x300[] = {0x51, 0x57, 0x00, 0x54};
-static const unsigned short ModeIndex_512x384[] = {0x52, 0x58, 0x00, 0x5c};
-static const unsigned short ModeIndex_640x400[] = {0x2f, 0x5d, 0x00, 0x5e};
-static const unsigned short ModeIndex_640x480[] = {0x2e, 0x44, 0x00, 0x62};
-static const unsigned short ModeIndex_720x480[] = {0x31, 0x33, 0x00, 0x35};
-static const unsigned short ModeIndex_720x576[] = {0x32, 0x34, 0x00, 0x36};
-static const unsigned short ModeIndex_768x576[] = {0x5f, 0x60, 0x00, 0x61};
-static const unsigned short ModeIndex_800x480[] = {0x70, 0x7a, 0x00, 0x76};
-static const unsigned short ModeIndex_800x600[] = {0x30, 0x47, 0x00, 0x63};
-static const unsigned short ModeIndex_848x480[] = {0x39, 0x3b, 0x00, 0x3e};
-static const unsigned short ModeIndex_856x480[] = {0x3f, 0x42, 0x00, 0x45};
-static const unsigned short ModeIndex_960x540[] = {0x1d, 0x1e, 0x00, 0x1f};
-static const unsigned short ModeIndex_960x600[] = {0x20, 0x21, 0x00, 0x22};
-static const unsigned short ModeIndex_1024x768[] = {0x38, 0x4a, 0x00, 0x64};
-static const unsigned short ModeIndex_1024x576[] = {0x71, 0x74, 0x00, 0x77};
-static const unsigned short ModeIndex_1152x864[] = {0x29, 0x2a, 0x00, 0x2b};
-static const unsigned short ModeIndex_1280x720[] = {0x79, 0x75, 0x00, 0x78};
-static const unsigned short ModeIndex_1280x768[] = {0x23, 0x24, 0x00, 0x25};
-static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65};
+static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f };
+static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 };
+static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 };
+static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c };
+static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e };
+static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 };
+static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 };
+static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 };
+static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 };
+static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 };
+static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 };
+static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e };
+static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 };
+static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f };
+static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 };
+static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 };
+static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 };
+static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b };
+static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 };
+static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 };
+static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 };
-static const unsigned char SiS_MDA_DAC[] =
-{
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
- 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F
+static const unsigned char SiS_MDA_DAC[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
};
-static const unsigned char SiS_CGA_DAC[] =
-{
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_CGA_DAC[] = {
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
};
-static const unsigned char SiS_EGA_DAC[] =
-{
- 0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
- 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
- 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
- 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
- 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
- 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
- 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_EGA_DAC[] = {
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
+ 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
+ 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
+ 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
+ 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
+ 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
+ 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
};
-static const unsigned char SiS_VGA_DAC[] =
-{
- 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
- 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
- 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
- 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
- 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
- 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
- 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
- 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
- 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
- 0x0B,0x0C,0x0D,0x0F,0x10
+static const unsigned char SiS_VGA_DAC[] = {
+ 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+ 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+ 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18,
+ 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F,
+ 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F,
+ 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00,
+ 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18,
+ 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04,
+ 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
+ 0x0B, 0x0C, 0x0D, 0x0F, 0x10
};
-static const struct SiS_St SiSUSB_SModeIDTable[] =
-{
- {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40},
- {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+static const struct SiS_St SiSUSB_SModeIDTable[] = {
+ {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40},
+ {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
-static const struct SiS_StResInfo_S SiSUSB_StResInfo[] =
-{
- { 640,400},
- { 640,350},
- { 720,400},
- { 720,350},
- { 640,480}
+static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = {
+ {640, 400},
+ {640, 350},
+ {720, 400},
+ {720, 350},
+ {640, 480}
};
-static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] =
-{
- { 320, 200, 8, 8}, /* 0x00 */
- { 320, 240, 8, 8}, /* 0x01 */
- { 320, 400, 8, 8}, /* 0x02 */
- { 400, 300, 8, 8}, /* 0x03 */
- { 512, 384, 8, 8}, /* 0x04 */
- { 640, 400, 8,16}, /* 0x05 */
- { 640, 480, 8,16}, /* 0x06 */
- { 800, 600, 8,16}, /* 0x07 */
- { 1024, 768, 8,16}, /* 0x08 */
- { 1280,1024, 8,16}, /* 0x09 */
- { 1600,1200, 8,16}, /* 0x0a */
- { 1920,1440, 8,16}, /* 0x0b */
- { 2048,1536, 8,16}, /* 0x0c */
- { 720, 480, 8,16}, /* 0x0d */
- { 720, 576, 8,16}, /* 0x0e */
- { 1280, 960, 8,16}, /* 0x0f */
- { 800, 480, 8,16}, /* 0x10 */
- { 1024, 576, 8,16}, /* 0x11 */
- { 1280, 720, 8,16}, /* 0x12 */
- { 856, 480, 8,16}, /* 0x13 */
- { 1280, 768, 8,16}, /* 0x14 */
- { 1400,1050, 8,16}, /* 0x15 */
- { 1152, 864, 8,16}, /* 0x16 */
- { 848, 480, 8,16}, /* 0x17 */
- { 1360, 768, 8,16}, /* 0x18 */
- { 1024, 600, 8,16}, /* 0x19 */
- { 1152, 768, 8,16}, /* 0x1a */
- { 768, 576, 8,16}, /* 0x1b */
- { 1360,1024, 8,16}, /* 0x1c */
- { 1680,1050, 8,16}, /* 0x1d */
- { 1280, 800, 8,16}, /* 0x1e */
- { 1920,1080, 8,16}, /* 0x1f */
- { 960, 540, 8,16}, /* 0x20 */
- { 960, 600, 8,16} /* 0x21 */
+static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = {
+ {320, 200, 8, 8}, /* 0x00 */
+ {320, 240, 8, 8}, /* 0x01 */
+ {320, 400, 8, 8}, /* 0x02 */
+ {400, 300, 8, 8}, /* 0x03 */
+ {512, 384, 8, 8}, /* 0x04 */
+ {640, 400, 8, 16}, /* 0x05 */
+ {640, 480, 8, 16}, /* 0x06 */
+ {800, 600, 8, 16}, /* 0x07 */
+ {1024, 768, 8, 16}, /* 0x08 */
+ {1280, 1024, 8, 16}, /* 0x09 */
+ {1600, 1200, 8, 16}, /* 0x0a */
+ {1920, 1440, 8, 16}, /* 0x0b */
+ {2048, 1536, 8, 16}, /* 0x0c */
+ {720, 480, 8, 16}, /* 0x0d */
+ {720, 576, 8, 16}, /* 0x0e */
+ {1280, 960, 8, 16}, /* 0x0f */
+ {800, 480, 8, 16}, /* 0x10 */
+ {1024, 576, 8, 16}, /* 0x11 */
+ {1280, 720, 8, 16}, /* 0x12 */
+ {856, 480, 8, 16}, /* 0x13 */
+ {1280, 768, 8, 16}, /* 0x14 */
+ {1400, 1050, 8, 16}, /* 0x15 */
+ {1152, 864, 8, 16}, /* 0x16 */
+ {848, 480, 8, 16}, /* 0x17 */
+ {1360, 768, 8, 16}, /* 0x18 */
+ {1024, 600, 8, 16}, /* 0x19 */
+ {1152, 768, 8, 16}, /* 0x1a */
+ {768, 576, 8, 16}, /* 0x1b */
+ {1360, 1024, 8, 16}, /* 0x1c */
+ {1680, 1050, 8, 16}, /* 0x1d */
+ {1280, 800, 8, 16}, /* 0x1e */
+ {1920, 1080, 8, 16}, /* 0x1f */
+ {960, 540, 8, 16}, /* 0x20 */
+ {960, 600, 8, 16} /* 0x21 */
};
-static const struct SiS_StandTable SiSUSB_StandTable[] =
-{
+static const struct SiS_StandTable SiSUSB_StandTable[] = {
/* MD_3_400 - mode 0x03 - 400 */
{
- 0x50,0x18,0x10,0x1000,
- { 0x00,0x03,0x00,0x02 },
- 0x67,
- { 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
- 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
- 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
- 0xff },
- { 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
- 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
- 0x0c,0x00,0x0f,0x08 },
- { 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff }
- },
+ 0x50, 0x18, 0x10, 0x1000,
+ {0x00, 0x03, 0x00, 0x02},
+ 0x67,
+ {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+ 0xff},
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x0c, 0x00, 0x0f, 0x08},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff}
+ },
/* Generic for VGA and higher */
{
- 0x00,0x00,0x00,0x0000,
- { 0x01,0x0f,0x00,0x0e },
- 0x23,
- { 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
- 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
- 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
- 0xff },
- { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
- 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
- 0x01,0x00,0x00,0x00 },
- { 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff }
- }
+ 0x00, 0x00, 0x00, 0x0000,
+ {0x01, 0x0f, 0x00, 0x0e},
+ 0x23,
+ {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
+ 0xff},
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x01, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff}
+ }
};
-static const struct SiS_Ext SiSUSB_EModeIDTable[] =
-{
- {0x2e,0x0a1b,0x0101,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */
- {0x2f,0x0a1b,0x0100,SIS_RI_640x400, 0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */
- {0x30,0x2a1b,0x0103,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */
- {0x31,0x4a1b,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */
- {0x32,0x4a1b,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */
- {0x33,0x4a1d,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */
- {0x34,0x6a1d,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */
- {0x35,0x4a1f,0x0000,SIS_RI_720x480, 0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */
- {0x36,0x6a1f,0x0000,SIS_RI_720x576, 0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */
- {0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */
- {0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */
- {0x41,0x9a1d,0x010e,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */
- {0x44,0x0a1d,0x0111,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */
- {0x47,0x2a1d,0x0114,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */
- {0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */
- {0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */
- {0x50,0x9a1b,0x0132,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8 */
- {0x51,0xba1b,0x0133,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8 */
- {0x52,0xba1b,0x0134,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8 */
- {0x56,0x9a1d,0x0135,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */
- {0x57,0xba1d,0x0136,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */
- {0x58,0xba1d,0x0137,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */
- {0x59,0x9a1b,0x0138,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8 */
- {0x5c,0xba1f,0x0000,SIS_RI_512x384, 0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */
- {0x5d,0x0a1d,0x0139,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */
- {0x5e,0x0a1f,0x0000,SIS_RI_640x400, 0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */
- {0x62,0x0a3f,0x013a,SIS_RI_640x480, 0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */
- {0x63,0x2a3f,0x013b,SIS_RI_800x600, 0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */
- {0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */
- {0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */
- {0x70,0x6a1b,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */
- {0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */
- {0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */
- {0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */
- {0x76,0x6a1f,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */
- {0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */
- {0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */
- {0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */
- {0x7a,0x6a1d,0x0000,SIS_RI_800x480, 0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */
- {0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */
- {0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */
- {0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */
- {0x39,0x6a1b,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */
- {0x3b,0x6a3d,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1},
- {0x3e,0x6a7f,0x0000,SIS_RI_848x480, 0x00,0x00,0x00,0x00,0x28,-1},
- {0x3f,0x6a1b,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */
- {0x42,0x6a3d,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1},
- {0x45,0x6a7f,0x0000,SIS_RI_856x480, 0x00,0x00,0x00,0x00,0x2a,-1},
- {0x4f,0x9a1f,0x0000,SIS_RI_320x200, 0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */
- {0x53,0x9a1f,0x0000,SIS_RI_320x240, 0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */
- {0x54,0xba1f,0x0000,SIS_RI_400x300, 0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */
- {0x5f,0x6a1b,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */
- {0x60,0x6a1d,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1},
- {0x61,0x6a3f,0x0000,SIS_RI_768x576, 0x00,0x00,0x06,0x06,0x2c,-1},
- {0x1d,0x6a1b,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */
- {0x1e,0x6a3d,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1},
- {0x1f,0x6a7f,0x0000,SIS_RI_960x540, 0x00,0x00,0x00,0x00,0x2d,-1},
- {0x20,0x6a1b,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */
- {0x21,0x6a3d,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1},
- {0x22,0x6a7f,0x0000,SIS_RI_960x600, 0x00,0x00,0x00,0x00,0x2e,-1},
- {0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */
- {0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
- {0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
- {0xff,0x0000,0x0000,0, 0x00,0x00,0x00,0x00,0x00,-1}
+static const struct SiS_Ext SiSUSB_EModeIDTable[] = {
+ {0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x8 */
+ {0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0}, /* 640x400x8 */
+ {0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x8 */
+ {0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x8 */
+ {0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x8 */
+ {0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x16 */
+ {0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x16 */
+ {0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x32 */
+ {0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x32 */
+ {0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x8 */
+ {0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x8 */
+ {0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x16 */
+ {0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x16 */
+ {0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x16 */
+ {0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x16 */
+ {0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x16 */
+ {0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x8 */
+ {0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x8 */
+ {0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x8 */
+ {0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x16 */
+ {0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x16 */
+ {0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x16 */
+ {0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x8 */
+ {0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x32 */
+ {0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x16 */
+ {0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x32 */
+ {0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x32 */
+ {0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x32 */
+ {0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x32 */
+ {0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x32 */
+ {0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x8 */
+ {0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x8 */
+ {0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x16 */
+ {0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x16 */
+ {0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x32 */
+ {0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x32 */
+ {0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x32 */
+ {0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x8 */
+ {0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x16 */
+ {0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x8 */
+ {0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x16 */
+ {0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x32 */
+ {0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1}, /* 848x480 */
+ {0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+ -1},
+ {0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+ -1},
+ {0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1}, /* 856x480 */
+ {0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+ -1},
+ {0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+ -1},
+ {0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x32 */
+ {0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x32 */
+ {0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x32 */
+ {0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1}, /* 768x576 */
+ {0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+ -1},
+ {0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+ -1},
+ {0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1}, /* 960x540 */
+ {0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+ -1},
+ {0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+ -1},
+ {0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1}, /* 960x600 */
+ {0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+ -1},
+ {0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+ -1},
+ {0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1}, /* 1152x864 */
+ {0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+ -1},
+ {0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+ -1},
+ {0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1}
};
-static const struct SiS_Ext2 SiSUSB_RefIndex[] =
-{
- {0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */
- {0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */
- {0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */
- {0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */
- {0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */
- {0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */
- {0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */
- {0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */
- {0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */
- {0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */
- {0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */
- {0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */
- {0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */
- {0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */
- {0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */
- {0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */
- {0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */
- {0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */
- {0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */
- {0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */
- {0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */
- {0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */
- {0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */
- {0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */
- {0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */
- {0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */
- {0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */
- {0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */
- {0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */
- {0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */
- {0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */
- {0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */
- {0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */
- {0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */
- {0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */
- {0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */
- {0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */
- {0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */
- {0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */
- {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */
- {0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */
- {0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */
- {0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */
- {0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */
- {0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */
- {0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */
- {0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */
- {0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */
- {0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */
- {0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */
- {0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */
- {0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */
- {0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */
- {0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */
- {0xffff,0x00,0x00,0x00,0x00,0x00, 0, 0, 0, 0x00, 0x00}
+static const struct SiS_Ext2 SiSUSB_RefIndex[] = {
+ {0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */
+ {0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */
+ {0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */
+ {0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */
+ {0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */
+ {0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */
+ {0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */
+ {0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */
+ {0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */
+ {0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */
+ {0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */
+ {0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */
+ {0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */
+ {0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */
+ {0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */
+ {0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */
+ {0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */
+ {0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */
+ {0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */
+ {0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */
+ {0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */
+ {0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */
+ {0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */
+ {0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */
+ {0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */
+ {0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */
+ {0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */
+ {0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */
+ {0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */
+ {0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */
+ {0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */
+ {0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */
+ {0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */
+ {0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */
+ {0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */
+ {0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */
+ {0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */
+ {0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */
+ {0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */
+ {0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */
+ {0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */
+ {0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */
+ {0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */
+ {0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */
+ {0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */
+ {0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */
+ {0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */
+ {0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00}, /* 0x2f */
+ {0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x30 */
+ {0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x31 */
+ {0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x32 */
+ {0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */
+ {0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */
+ {0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */
+ {0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00}
};
-static const struct SiS_CRT1Table SiSUSB_CRT1Table[] =
-{
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
- 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
- 0x00}}, /* 0x0 */
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
- 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
- 0x00}}, /* 0x1 */
- {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
- 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
- 0x01}}, /* 0x2 */
- {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
- 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
- 0x01}}, /* 0x3 */
- {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
- 0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
- 0x00}}, /* 0x4 */
- {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
- 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
- 0x00}}, /* 0x5 */
- {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e,
- 0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01,
- 0x00}}, /* 0x6 */
- {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
- 0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
- 0x00}}, /* 0x7 */
- {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
- 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
- 0x00}}, /* 0x8 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
- 0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
- 0x61}}, /* 0x9 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
- 0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
- 0x61}}, /* 0xa */
- {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
- 0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05,
- 0x61}}, /* 0xb */
- {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
- 0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01,
- 0x00}}, /* 0xc */
- {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
- 0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
- 0x01}}, /* 0xd */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
- 0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
- 0x01}}, /* 0xe */
- {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
- 0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
- 0x01}}, /* 0xf */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
- 0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
- 0x01}}, /* 0x10 */
- {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
- 0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
- 0x01}}, /* 0x11 */
- {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
- 0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
- 0x61}}, /* 0x12 */
- {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
- 0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
- 0x61}}, /* 0x13 */
- {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
- 0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
- 0x61}}, /* 0x14 */
- {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
- 0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
- 0x00}}, /* 0x15 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
- 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
- 0x01}}, /* 0x16 */
- {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
- 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
- 0x01}}, /* 0x17 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
- 0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
- 0x01}}, /* 0x18 */
- {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
- 0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
- 0x01}}, /* 0x19 */
- {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
- 0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
- 0x62}}, /* 0x1a */
- {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
- 0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
- 0x62}}, /* 0x1b */
- {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
- 0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
- 0x00}}, /* 0x1c */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
- 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
- 0x01}}, /* 0x1d */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
- 0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
- 0x01}}, /* 0x1e */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
- 0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
- 0x01}}, /* 0x1f */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x20 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x21 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x22 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x23 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x24 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x25 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
- 0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
- 0x00}}, /* 0x26 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
- 0x00}}, /* 0x27 */
- {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
- 0x63}}, /* 0x28 */
- {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
- 0x63}}, /* 0x29 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
- 0x00}}, /* 0x2a */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
- 0x00}}, /* 0x2b */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
- 0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
- 0x00}}, /* 0x2c */
- {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
- 0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
- 0x44}}, /* 0x2d */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
- 0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
- 0x44}}, /* 0x2e */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
- 0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
- 0x44}}, /* 0x2f */
- {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
- 0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
- 0x44}}, /* 0x30 */
- {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
- 0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
- 0x00}}, /* 0x31 */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
- 0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
- 0x01}}, /* 0x32 */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
- 0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
- 0x01}}, /* 0x33 */
- {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
- 0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
- 0x01}}, /* 0x34 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
- 0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
- 0x01}}, /* 0x35 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
- 0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
- 0x01}}, /* 0x36 */
- {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,
- 0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
- 0x01}}, /* 0x37 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
- 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
- 0x01}}, /* 0x38 */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
- 0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
- 0x01}}, /* 0x39 */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
- 0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
- 0x01}}, /* 0x3a */
- {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff,
- 0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07,
- 0x01}}, /* 0x3b */
- {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
- 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
- 0x00}}, /* 0x3c */
- {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0,
- 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
- 0x41}}, /* 0x3d */
- {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,
- 0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
- 0x00}}, /* 0x3e */
- {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
- 0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
- 0x00}}, /* 0x3f */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,
- 0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
- 0x01}}, /* 0x40 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
- 0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
- 0x01}}, /* 0x41 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5,
- 0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07,
- 0x01}}, /* 0x42 */
- {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10,
- 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03,
- 0x00}}, /* 0x43 */
- {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef,
- 0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07,
- 0x01}}, /* 0x44 */
- {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15,
- 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
- 0x00}}, /* 0x45 */
- {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E,
- 0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06,
- 0x00}}, /* 0x46 */
- {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15,
- 0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
- 0x00}}, /* 0x47 */
- {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E,
- 0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
- 0x00}}, /* 0x48 */
- {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd,
- 0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03,
- 0x01}}, /* 0x49 */
- {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff,
- 0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03,
- 0x01}}, /* 0x4a */
- {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10,
- 0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03,
- 0x00}}, /* 0x4b */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff,
- 0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
- 0x01}}, /* 0x4c */
- {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0,
- 0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
- 0x41}},
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
- 0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
- 0x00}}, /* 0x4e */
- {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff,
- 0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07,
- 0x21}}, /* 0x4f */
- {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10,
- 0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c,
- 0x20}}, /* 0x50 */
- {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0,
- 0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00,
- 0x61}}, /* 0x51 */
- {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0,
- 0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02,
- 0x41}}, /* 0x52 */
- {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0,
- 0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02,
- 0x01}}, /* 0x53 */
- {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff,
- 0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07,
- 0x41}} /* 0x54 */
+static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = {
+ {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
+ 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00,
+ 0x00}}, /* 0x0 */
+ {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+ 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+ 0x00}}, /* 0x1 */
+ {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0,
+ 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05,
+ 0x01}}, /* 0x2 */
+ {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5,
+ 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01,
+ 0x01}}, /* 0x3 */
+ {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+ 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05,
+ 0x00}}, /* 0x4 */
+ {{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e,
+ 0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05,
+ 0x00}}, /* 0x5 */
+ {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e,
+ 0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01,
+ 0x00}}, /* 0x6 */
+ {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f,
+ 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01,
+ 0x00}}, /* 0x7 */
+ {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f,
+ 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+ 0x00}}, /* 0x8 */
+ {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f,
+ 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+ 0x61}}, /* 0x9 */
+ {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e,
+ 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05,
+ 0x61}}, /* 0xa */
+ {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e,
+ 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05,
+ 0x61}}, /* 0xb */
+ {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f,
+ 0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01,
+ 0x00}}, /* 0xc */
+ {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0,
+ 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05,
+ 0x01}}, /* 0xd */
+ {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0,
+ 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06,
+ 0x01}}, /* 0xe */
+ {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0,
+ 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06,
+ 0x01}}, /* 0xf */
+ {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06,
+ 0x01}}, /* 0x10 */
+ {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06,
+ 0x01}}, /* 0x11 */
+ {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06,
+ 0x61}}, /* 0x12 */
+ {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06,
+ 0x61}}, /* 0x13 */
+ {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0,
+ 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06,
+ 0x61}}, /* 0x14 */
+ {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f,
+ 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02,
+ 0x00}}, /* 0x15 */
+ {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+ 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x16 */
+ {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5,
+ 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x17 */
+ {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5,
+ 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x18 */
+ {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5,
+ 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x19 */
+ {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5,
+ 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02,
+ 0x62}}, /* 0x1a */
+ {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5,
+ 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02,
+ 0x62}}, /* 0x1b */
+ {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba,
+ 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03,
+ 0x00}}, /* 0x1c */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a,
+ 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+ 0x01}}, /* 0x1d */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a,
+ 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+ 0x01}}, /* 0x1e */
+ {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a,
+ 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07,
+ 0x01}}, /* 0x1f */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x20 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x21 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x22 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x23 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x24 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x25 */
+ {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+ 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+ 0x00}}, /* 0x26 */
+ {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+ 0x00}}, /* 0x27 */
+ {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05,
+ 0x63}}, /* 0x28 */
+ {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05,
+ 0x63}}, /* 0x29 */
+ {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+ 0x00}}, /* 0x2a */
+ {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+ 0x00}}, /* 0x2b */
+ {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+ 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+ 0x00}}, /* 0x2c */
+ {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba,
+ 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05,
+ 0x44}}, /* 0x2d */
+ {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba,
+ 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05,
+ 0x44}}, /* 0x2e */
+ {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba,
+ 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05,
+ 0x44}}, /* 0x2f */
+ {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba,
+ 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05,
+ 0x44}}, /* 0x30 */
+ {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba,
+ 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05,
+ 0x00}}, /* 0x31 */
+ {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba,
+ 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06,
+ 0x01}}, /* 0x32 */
+ {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba,
+ 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06,
+ 0x01}}, /* 0x33 */
+ {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba,
+ 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06,
+ 0x01}}, /* 0x34 */
+ {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1,
+ 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02,
+ 0x01}}, /* 0x35 */
+ {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1,
+ 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02,
+ 0x01}}, /* 0x36 */
+ {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1,
+ 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02,
+ 0x01}}, /* 0x37 */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4,
+ 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+ 0x01}}, /* 0x38 */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4,
+ 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+ 0x01}}, /* 0x39 */
+ {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4,
+ 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07,
+ 0x01}}, /* 0x3a */
+ {{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff,
+ 0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07,
+ 0x01}}, /* 0x3b */
+ {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e,
+ 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05,
+ 0x00}}, /* 0x3c */
+ {{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0,
+ 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+ 0x41}}, /* 0x3d */
+ {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15,
+ 0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02,
+ 0x00}}, /* 0x3e */
+ {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e,
+ 0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02,
+ 0x00}}, /* 0x3f */
+ {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1,
+ 0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02,
+ 0x01}}, /* 0x40 */
+ {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+ 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+ 0x01}}, /* 0x41 */
+ {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5,
+ 0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07,
+ 0x01}}, /* 0x42 */
+ {{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10,
+ 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03,
+ 0x00}}, /* 0x43 */
+ {{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef,
+ 0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07,
+ 0x01}}, /* 0x44 */
+ {{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+ 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+ 0x00}}, /* 0x45 */
+ {{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E,
+ 0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06,
+ 0x00}}, /* 0x46 */
+ {{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+ 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+ 0x00}}, /* 0x47 */
+ {{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E,
+ 0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02,
+ 0x00}}, /* 0x48 */
+ {{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd,
+ 0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03,
+ 0x01}}, /* 0x49 */
+ {{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff,
+ 0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03,
+ 0x01}}, /* 0x4a */
+ {{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10,
+ 0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03,
+ 0x00}}, /* 0x4b */
+ {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff,
+ 0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07,
+ 0x01}}, /* 0x4c */
+ {{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0,
+ 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+ 0x41}},
+ {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+ 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+ 0x00}}, /* 0x4e */
+ {{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff,
+ 0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07,
+ 0x21}}, /* 0x4f */
+ {{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10,
+ 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c,
+ 0x20}}, /* 0x50 */
+ {{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0,
+ 0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00,
+ 0x61}}, /* 0x51 */
+ {{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0,
+ 0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02,
+ 0x41}}, /* 0x52 */
+ {{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0,
+ 0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02,
+ 0x01}}, /* 0x53 */
+ {{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff,
+ 0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07,
+ 0x41}} /* 0x54 */
};
-static const struct SiS_VCLKData SiSUSB_VCLKData[] =
-{
- { 0x1b,0xe1, 25}, /* 0x00 */
- { 0x4e,0xe4, 28}, /* 0x01 */
- { 0x57,0xe4, 31}, /* 0x02 */
- { 0xc3,0xc8, 36}, /* 0x03 */
- { 0x42,0xe2, 40}, /* 0x04 */
- { 0xfe,0xcd, 43}, /* 0x05 */
- { 0x5d,0xc4, 44}, /* 0x06 */
- { 0x52,0xe2, 49}, /* 0x07 */
- { 0x53,0xe2, 50}, /* 0x08 */
- { 0x74,0x67, 52}, /* 0x09 */
- { 0x6d,0x66, 56}, /* 0x0a */
- { 0x5a,0x64, 65}, /* 0x0b */
- { 0x46,0x44, 67}, /* 0x0c */
- { 0xb1,0x46, 68}, /* 0x0d */
- { 0xd3,0x4a, 72}, /* 0x0e */
- { 0x29,0x61, 75}, /* 0x0f */
- { 0x6e,0x46, 76}, /* 0x10 */
- { 0x2b,0x61, 78}, /* 0x11 */
- { 0x31,0x42, 79}, /* 0x12 */
- { 0xab,0x44, 83}, /* 0x13 */
- { 0x46,0x25, 84}, /* 0x14 */
- { 0x78,0x29, 86}, /* 0x15 */
- { 0x62,0x44, 94}, /* 0x16 */
- { 0x2b,0x41,104}, /* 0x17 */
- { 0x3a,0x23,105}, /* 0x18 */
- { 0x70,0x44,108}, /* 0x19 */
- { 0x3c,0x23,109}, /* 0x1a */
- { 0x5e,0x43,113}, /* 0x1b */
- { 0xbc,0x44,116}, /* 0x1c */
- { 0xe0,0x46,132}, /* 0x1d */
- { 0x54,0x42,135}, /* 0x1e */
- { 0xea,0x2a,139}, /* 0x1f */
- { 0x41,0x22,157}, /* 0x20 */
- { 0x70,0x24,162}, /* 0x21 */
- { 0x30,0x21,175}, /* 0x22 */
- { 0x4e,0x22,189}, /* 0x23 */
- { 0xde,0x26,194}, /* 0x24 */
- { 0x62,0x06,202}, /* 0x25 */
- { 0x3f,0x03,229}, /* 0x26 */
- { 0xb8,0x06,234}, /* 0x27 */
- { 0x34,0x02,253}, /* 0x28 */
- { 0x58,0x04,255}, /* 0x29 */
- { 0x24,0x01,265}, /* 0x2a */
- { 0x9b,0x02,267}, /* 0x2b */
- { 0x70,0x05,270}, /* 0x2c */
- { 0x25,0x01,272}, /* 0x2d */
- { 0x9c,0x02,277}, /* 0x2e */
- { 0x27,0x01,286}, /* 0x2f */
- { 0x3c,0x02,291}, /* 0x30 */
- { 0xef,0x0a,292}, /* 0x31 */
- { 0xf6,0x0a,310}, /* 0x32 */
- { 0x95,0x01,315}, /* 0x33 */
- { 0xf0,0x09,324}, /* 0x34 */
- { 0xfe,0x0a,331}, /* 0x35 */
- { 0xf3,0x09,332}, /* 0x36 */
- { 0xea,0x08,340}, /* 0x37 */
- { 0xe8,0x07,376}, /* 0x38 */
- { 0xde,0x06,389}, /* 0x39 */
- { 0x52,0x2a, 54}, /* 0x3a 301 TV */
- { 0x52,0x6a, 27}, /* 0x3b 301 TV */
- { 0x62,0x24, 70}, /* 0x3c 301 TV */
- { 0x62,0x64, 70}, /* 0x3d 301 TV */
- { 0xa8,0x4c, 30}, /* 0x3e 301 TV */
- { 0x20,0x26, 33}, /* 0x3f 301 TV */
- { 0x31,0xc2, 39}, /* 0x40 */
- { 0x60,0x36, 30}, /* 0x41 Chrontel */
- { 0x40,0x4a, 28}, /* 0x42 Chrontel */
- { 0x9f,0x46, 44}, /* 0x43 Chrontel */
- { 0x97,0x2c, 26}, /* 0x44 */
- { 0x44,0xe4, 25}, /* 0x45 Chrontel */
- { 0x7e,0x32, 47}, /* 0x46 Chrontel */
- { 0x8a,0x24, 31}, /* 0x47 Chrontel */
- { 0x97,0x2c, 26}, /* 0x48 Chrontel */
- { 0xce,0x3c, 39}, /* 0x49 */
- { 0x52,0x4a, 36}, /* 0x4a Chrontel */
- { 0x34,0x61, 95}, /* 0x4b */
- { 0x78,0x27,108}, /* 0x4c - was 102 */
- { 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
- { 0x41,0x4e, 21}, /* 0x4e */
- { 0xa1,0x4a, 29}, /* 0x4f Chrontel */
- { 0x19,0x42, 42}, /* 0x50 */
- { 0x54,0x46, 58}, /* 0x51 Chrontel */
- { 0x25,0x42, 61}, /* 0x52 */
- { 0x44,0x44, 66}, /* 0x53 Chrontel */
- { 0x3a,0x62, 70}, /* 0x54 Chrontel */
- { 0x62,0xc6, 34}, /* 0x55 848x480-60 */
- { 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */
- { 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */
- { 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
- { 0x52,0x07,149}, /* 0x59 1280x960-85 */
- { 0x56,0x07,156}, /* 0x5a 1400x1050-75 */
- { 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */
- { 0x45,0x25, 83}, /* 0x5c 1280x800 */
- { 0x70,0x0a,147}, /* 0x5d 1680x1050 */
- { 0x70,0x24,162}, /* 0x5e 1600x1200 */
- { 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */
- { 0x63,0x46, 68}, /* 0x60 1280x768_2 */
- { 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */
- { 0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */
- { 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
- { 0x70,0x28, 90}, /* 0x64 1152x864@60 */
- { 0x41,0xc4, 32}, /* 0x65 848x480@60 */
- { 0x5c,0xc6, 32}, /* 0x66 856x480@60 */
- { 0x76,0xe7, 27}, /* 0x67 720x480@60 */
- { 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */
- { 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
- { 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */
- { 0xe3,0x56, 41}, /* 0x6b 960x600@60 */
- { 0x45,0x25, 83}, /* 0x6c 1280x800 */
- { 0x70,0x28, 90}, /* 0x6d 1152x864@60 */
- { 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */
- { 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */
- { 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */
- { 0x2b,0xc2, 35} /* 0x71 768@576@60 */
+static const struct SiS_VCLKData SiSUSB_VCLKData[] = {
+ {0x1b, 0xe1, 25}, /* 0x00 */
+ {0x4e, 0xe4, 28}, /* 0x01 */
+ {0x57, 0xe4, 31}, /* 0x02 */
+ {0xc3, 0xc8, 36}, /* 0x03 */
+ {0x42, 0xe2, 40}, /* 0x04 */
+ {0xfe, 0xcd, 43}, /* 0x05 */
+ {0x5d, 0xc4, 44}, /* 0x06 */
+ {0x52, 0xe2, 49}, /* 0x07 */
+ {0x53, 0xe2, 50}, /* 0x08 */
+ {0x74, 0x67, 52}, /* 0x09 */
+ {0x6d, 0x66, 56}, /* 0x0a */
+ {0x5a, 0x64, 65}, /* 0x0b */
+ {0x46, 0x44, 67}, /* 0x0c */
+ {0xb1, 0x46, 68}, /* 0x0d */
+ {0xd3, 0x4a, 72}, /* 0x0e */
+ {0x29, 0x61, 75}, /* 0x0f */
+ {0x6e, 0x46, 76}, /* 0x10 */
+ {0x2b, 0x61, 78}, /* 0x11 */
+ {0x31, 0x42, 79}, /* 0x12 */
+ {0xab, 0x44, 83}, /* 0x13 */
+ {0x46, 0x25, 84}, /* 0x14 */
+ {0x78, 0x29, 86}, /* 0x15 */
+ {0x62, 0x44, 94}, /* 0x16 */
+ {0x2b, 0x41, 104}, /* 0x17 */
+ {0x3a, 0x23, 105}, /* 0x18 */
+ {0x70, 0x44, 108}, /* 0x19 */
+ {0x3c, 0x23, 109}, /* 0x1a */
+ {0x5e, 0x43, 113}, /* 0x1b */
+ {0xbc, 0x44, 116}, /* 0x1c */
+ {0xe0, 0x46, 132}, /* 0x1d */
+ {0x54, 0x42, 135}, /* 0x1e */
+ {0xea, 0x2a, 139}, /* 0x1f */
+ {0x41, 0x22, 157}, /* 0x20 */
+ {0x70, 0x24, 162}, /* 0x21 */
+ {0x30, 0x21, 175}, /* 0x22 */
+ {0x4e, 0x22, 189}, /* 0x23 */
+ {0xde, 0x26, 194}, /* 0x24 */
+ {0x62, 0x06, 202}, /* 0x25 */
+ {0x3f, 0x03, 229}, /* 0x26 */
+ {0xb8, 0x06, 234}, /* 0x27 */
+ {0x34, 0x02, 253}, /* 0x28 */
+ {0x58, 0x04, 255}, /* 0x29 */
+ {0x24, 0x01, 265}, /* 0x2a */
+ {0x9b, 0x02, 267}, /* 0x2b */
+ {0x70, 0x05, 270}, /* 0x2c */
+ {0x25, 0x01, 272}, /* 0x2d */
+ {0x9c, 0x02, 277}, /* 0x2e */
+ {0x27, 0x01, 286}, /* 0x2f */
+ {0x3c, 0x02, 291}, /* 0x30 */
+ {0xef, 0x0a, 292}, /* 0x31 */
+ {0xf6, 0x0a, 310}, /* 0x32 */
+ {0x95, 0x01, 315}, /* 0x33 */
+ {0xf0, 0x09, 324}, /* 0x34 */
+ {0xfe, 0x0a, 331}, /* 0x35 */
+ {0xf3, 0x09, 332}, /* 0x36 */
+ {0xea, 0x08, 340}, /* 0x37 */
+ {0xe8, 0x07, 376}, /* 0x38 */
+ {0xde, 0x06, 389}, /* 0x39 */
+ {0x52, 0x2a, 54}, /* 0x3a 301 TV */
+ {0x52, 0x6a, 27}, /* 0x3b 301 TV */
+ {0x62, 0x24, 70}, /* 0x3c 301 TV */
+ {0x62, 0x64, 70}, /* 0x3d 301 TV */
+ {0xa8, 0x4c, 30}, /* 0x3e 301 TV */
+ {0x20, 0x26, 33}, /* 0x3f 301 TV */
+ {0x31, 0xc2, 39}, /* 0x40 */
+ {0x60, 0x36, 30}, /* 0x41 Chrontel */
+ {0x40, 0x4a, 28}, /* 0x42 Chrontel */
+ {0x9f, 0x46, 44}, /* 0x43 Chrontel */
+ {0x97, 0x2c, 26}, /* 0x44 */
+ {0x44, 0xe4, 25}, /* 0x45 Chrontel */
+ {0x7e, 0x32, 47}, /* 0x46 Chrontel */
+ {0x8a, 0x24, 31}, /* 0x47 Chrontel */
+ {0x97, 0x2c, 26}, /* 0x48 Chrontel */
+ {0xce, 0x3c, 39}, /* 0x49 */
+ {0x52, 0x4a, 36}, /* 0x4a Chrontel */
+ {0x34, 0x61, 95}, /* 0x4b */
+ {0x78, 0x27, 108}, /* 0x4c - was 102 */
+ {0x66, 0x43, 123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
+ {0x41, 0x4e, 21}, /* 0x4e */
+ {0xa1, 0x4a, 29}, /* 0x4f Chrontel */
+ {0x19, 0x42, 42}, /* 0x50 */
+ {0x54, 0x46, 58}, /* 0x51 Chrontel */
+ {0x25, 0x42, 61}, /* 0x52 */
+ {0x44, 0x44, 66}, /* 0x53 Chrontel */
+ {0x3a, 0x62, 70}, /* 0x54 Chrontel */
+ {0x62, 0xc6, 34}, /* 0x55 848x480-60 */
+ {0x6a, 0xc6, 37}, /* 0x56 848x480-75 - TEMP */
+ {0xbf, 0xc8, 35}, /* 0x57 856x480-38i,60 */
+ {0x30, 0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
+ {0x52, 0x07, 149}, /* 0x59 1280x960-85 */
+ {0x56, 0x07, 156}, /* 0x5a 1400x1050-75 */
+ {0x70, 0x29, 81}, /* 0x5b 1280x768 LCD */
+ {0x45, 0x25, 83}, /* 0x5c 1280x800 */
+ {0x70, 0x0a, 147}, /* 0x5d 1680x1050 */
+ {0x70, 0x24, 162}, /* 0x5e 1600x1200 */
+ {0x5a, 0x64, 65}, /* 0x5f 1280x720 - temp */
+ {0x63, 0x46, 68}, /* 0x60 1280x768_2 */
+ {0x31, 0x42, 79}, /* 0x61 1280x768_3 - temp */
+ {0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */
+ {0x5a, 0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
+ {0x70, 0x28, 90}, /* 0x64 1152x864@60 */
+ {0x41, 0xc4, 32}, /* 0x65 848x480@60 */
+ {0x5c, 0xc6, 32}, /* 0x66 856x480@60 */
+ {0x76, 0xe7, 27}, /* 0x67 720x480@60 */
+ {0x5f, 0xc6, 33}, /* 0x68 720/768x576@60 */
+ {0x52, 0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
+ {0x7c, 0x6b, 38}, /* 0x6a 960x540@60 */
+ {0xe3, 0x56, 41}, /* 0x6b 960x600@60 */
+ {0x45, 0x25, 83}, /* 0x6c 1280x800 */
+ {0x70, 0x28, 90}, /* 0x6d 1152x864@60 */
+ {0x15, 0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */
+ {0x5f, 0xc6, 33}, /* 0x6f 720x576@60 */
+ {0x37, 0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */
+ {0x2b, 0xc2, 35} /* 0x71 768@576@60 */
};
-int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
-int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
-extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
-extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
-extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
- u8 index, u8 data);
-extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
- u8 index, u8 *data);
-extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
- u8 idx, u8 myand, u8 myor);
-extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
- u8 index, u8 myor);
-extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
- u8 idx, u8 myand);
+extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
+extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data);
+extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
+ u8 index, u8 data);
+extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
+ u8 index, u8 * data);
+extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
+ u8 idx, u8 myand, u8 myor);
+extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
+ u8 index, u8 myor);
+extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
+ u8 idx, u8 myand);
void sisusb_delete(struct kref *kref);
int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
-int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
+int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data);
int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
- u32 dest, int length, size_t *bytes_written);
+ u32 dest, int length, size_t * bytes_written);
int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
- u8 *arg, int cmapsz, int ch512, int dorecalc,
+ u8 * arg, int cmapsz, int ch512, int dorecalc,
struct vc_data *c, int fh, int uplock);
void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
@@ -839,4 +839,3 @@ void sisusb_console_exit(struct sisusb_usb_data *sisusb);
void sisusb_init_concode(void);
#endif
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h
index f325ecb29a6..1c4240e802c 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_struct.h
+++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h
@@ -44,7 +44,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@@ -52,85 +52,78 @@
#define _SISUSB_STRUCT_H_
struct SiS_St {
- unsigned char St_ModeID;
- unsigned short St_ModeFlag;
- unsigned char St_StTableIndex;
- unsigned char St_CRT2CRTC;
- unsigned char St_ResInfo;
- unsigned char VB_StTVFlickerIndex;
- unsigned char VB_StTVEdgeIndex;
- unsigned char VB_StTVYFilterIndex;
- unsigned char St_PDC;
+ unsigned char St_ModeID;
+ unsigned short St_ModeFlag;
+ unsigned char St_StTableIndex;
+ unsigned char St_CRT2CRTC;
+ unsigned char St_ResInfo;
+ unsigned char VB_StTVFlickerIndex;
+ unsigned char VB_StTVEdgeIndex;
+ unsigned char VB_StTVYFilterIndex;
+ unsigned char St_PDC;
};
-struct SiS_StandTable
-{
- unsigned char CRT_COLS;
- unsigned char ROWS;
- unsigned char CHAR_HEIGHT;
- unsigned short CRT_LEN;
- unsigned char SR[4];
- unsigned char MISC;
- unsigned char CRTC[0x19];
- unsigned char ATTR[0x14];
- unsigned char GRC[9];
+struct SiS_StandTable {
+ unsigned char CRT_COLS;
+ unsigned char ROWS;
+ unsigned char CHAR_HEIGHT;
+ unsigned short CRT_LEN;
+ unsigned char SR[4];
+ unsigned char MISC;
+ unsigned char CRTC[0x19];
+ unsigned char ATTR[0x14];
+ unsigned char GRC[9];
};
struct SiS_StResInfo_S {
- unsigned short HTotal;
- unsigned short VTotal;
+ unsigned short HTotal;
+ unsigned short VTotal;
};
-struct SiS_Ext
-{
- unsigned char Ext_ModeID;
- unsigned short Ext_ModeFlag;
- unsigned short Ext_VESAID;
- unsigned char Ext_RESINFO;
- unsigned char VB_ExtTVFlickerIndex;
- unsigned char VB_ExtTVEdgeIndex;
- unsigned char VB_ExtTVYFilterIndex;
- unsigned char VB_ExtTVYFilterIndexROM661;
- unsigned char REFindex;
- char ROMMODEIDX661;
+struct SiS_Ext {
+ unsigned char Ext_ModeID;
+ unsigned short Ext_ModeFlag;
+ unsigned short Ext_VESAID;
+ unsigned char Ext_RESINFO;
+ unsigned char VB_ExtTVFlickerIndex;
+ unsigned char VB_ExtTVEdgeIndex;
+ unsigned char VB_ExtTVYFilterIndex;
+ unsigned char VB_ExtTVYFilterIndexROM661;
+ unsigned char REFindex;
+ char ROMMODEIDX661;
};
-struct SiS_Ext2
-{
- unsigned short Ext_InfoFlag;
- unsigned char Ext_CRT1CRTC;
- unsigned char Ext_CRTVCLK;
- unsigned char Ext_CRT2CRTC;
- unsigned char Ext_CRT2CRTC_NS;
- unsigned char ModeID;
- unsigned short XRes;
- unsigned short YRes;
- unsigned char Ext_PDC;
- unsigned char Ext_FakeCRT2CRTC;
- unsigned char Ext_FakeCRT2Clk;
+struct SiS_Ext2 {
+ unsigned short Ext_InfoFlag;
+ unsigned char Ext_CRT1CRTC;
+ unsigned char Ext_CRTVCLK;
+ unsigned char Ext_CRT2CRTC;
+ unsigned char Ext_CRT2CRTC_NS;
+ unsigned char ModeID;
+ unsigned short XRes;
+ unsigned short YRes;
+ unsigned char Ext_PDC;
+ unsigned char Ext_FakeCRT2CRTC;
+ unsigned char Ext_FakeCRT2Clk;
};
-struct SiS_CRT1Table
-{
- unsigned char CR[17];
+struct SiS_CRT1Table {
+ unsigned char CR[17];
};
-struct SiS_VCLKData
-{
- unsigned char SR2B,SR2C;
- unsigned short CLOCK;
+struct SiS_VCLKData {
+ unsigned char SR2B, SR2C;
+ unsigned short CLOCK;
};
-struct SiS_ModeResInfo
-{
- unsigned short HTotal;
- unsigned short VTotal;
- unsigned char XChar;
- unsigned char YChar;
+struct SiS_ModeResInfo {
+ unsigned short HTotal;
+ unsigned short VTotal;
+ unsigned char XChar;
+ unsigned char YChar;
};
-struct SiS_Private
-{
+struct SiS_Private {
void *sisusb;
unsigned long IOAddress;
@@ -151,19 +144,18 @@ struct SiS_Private
unsigned long SiS_P3da;
unsigned long SiS_Part1Port;
- unsigned char SiS_MyCR63;
- unsigned short SiS_CRT1Mode;
- unsigned short SiS_ModeType;
- unsigned short SiS_SetFlag;
-
- const struct SiS_StandTable *SiS_StandTable;
- const struct SiS_St *SiS_SModeIDTable;
- const struct SiS_Ext *SiS_EModeIDTable;
- const struct SiS_Ext2 *SiS_RefIndex;
- const struct SiS_CRT1Table *SiS_CRT1Table;
- const struct SiS_VCLKData *SiS_VCLKData;
- const struct SiS_ModeResInfo *SiS_ModeResInfo;
+ unsigned char SiS_MyCR63;
+ unsigned short SiS_CRT1Mode;
+ unsigned short SiS_ModeType;
+ unsigned short SiS_SetFlag;
+
+ const struct SiS_StandTable *SiS_StandTable;
+ const struct SiS_St *SiS_SModeIDTable;
+ const struct SiS_Ext *SiS_EModeIDTable;
+ const struct SiS_Ext2 *SiS_RefIndex;
+ const struct SiS_CRT1Table *SiS_CRT1Table;
+ const struct SiS_VCLKData *SiS_VCLKData;
+ const struct SiS_ModeResInfo *SiS_ModeResInfo;
};
#endif
-
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 71984203271..20777d01db6 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/errno.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
@@ -34,6 +35,8 @@ static struct usb_device_id id_table [] = {
};
MODULE_DEVICE_TABLE (usb, id_table);
+static DEFINE_MUTEX(open_disc_mutex);
+
struct usb_lcd {
struct usb_device * udev; /* init: probe_lcd */
@@ -79,12 +82,16 @@ static int lcd_open(struct inode *inode, struct file *file)
return -ENODEV;
}
+ mutex_lock(&open_disc_mutex);
dev = usb_get_intfdata(interface);
- if (!dev)
+ if (!dev) {
+ mutex_unlock(&open_disc_mutex);
return -ENODEV;
+ }
/* increment our usage count for the device */
kref_get(&dev->kref);
+ mutex_unlock(&open_disc_mutex);
/* grab a power reference */
r = usb_autopm_get_interface(interface);
@@ -393,8 +400,10 @@ static void lcd_disconnect(struct usb_interface *interface)
struct usb_lcd *dev;
int minor = interface->minor;
+ mutex_lock(&open_disc_mutex);
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
+ mutex_unlock(&open_disc_mutex);
/* give back our minor */
usb_deregister_dev(interface, &lcd_class);
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index e901d31e051..ea316214648 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -360,9 +360,9 @@ static void free_sglist (struct scatterlist *sg, int nents)
if (!sg)
return;
for (i = 0; i < nents; i++) {
- if (!sg [i].page)
+ if (!sg_page(&sg[i]))
continue;
- kfree (page_address (sg [i].page) + sg [i].offset);
+ kfree (sg_virt(&sg[i]));
}
kfree (sg);
}
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 2734fe2b9c4..f1255b0a182 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -128,7 +128,7 @@ static void async_complete(struct urb *urb)
#endif
/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
if (rq->reg[2] & rq->reg[1] & 0x10 && pp)
- parport_generic_irq(0, pp);
+ parport_generic_irq(pp);
}
complete(&rq->compl);
kref_put(&rq->ref_count, destroy_async);
@@ -337,7 +337,7 @@ static int uss720_irq(int usbstatus, void *buffer, int len, void *dev_id)
memcpy(priv->reg, buffer, 4);
/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
if (priv->reg[2] & priv->reg[1] & 0x10)
- parport_generic_irq(0, pp);
+ parport_generic_irq(pp);
return 1;
}
#endif
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index c03dfd7a9d3..f06e4e2b49d 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -172,6 +172,10 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0)
+static unsigned char xfer_to_pipe[4] = {
+ PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+};
+
static struct class *mon_bin_class;
static dev_t mon_bin_dev0;
static struct cdev mon_bin_cdev;
@@ -354,13 +358,9 @@ static inline char mon_bin_get_setup(unsigned char *setupb,
const struct urb *urb, char ev_type)
{
- if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+ if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S')
return '-';
- if (urb->dev->bus->uses_dma &&
- (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
- return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
- }
if (urb->setup_packet == NULL)
return 'Z';
@@ -386,13 +386,15 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp,
}
static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
- char ev_type)
+ char ev_type, int status)
{
+ const struct usb_endpoint_descriptor *epd = &urb->ep->desc;
unsigned long flags;
struct timeval ts;
unsigned int urb_length;
unsigned int offset;
unsigned int length;
+ unsigned char dir;
struct mon_bin_hdr *ep;
char data_tag = 0;
@@ -410,16 +412,19 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
if (length >= rp->b_size/5)
length = rp->b_size/5;
- if (usb_pipein(urb->pipe)) {
+ if (usb_urb_dir_in(urb)) {
if (ev_type == 'S') {
length = 0;
data_tag = '<';
}
+ /* Cannot rely on endpoint number in case of control ep.0 */
+ dir = USB_DIR_IN;
} else {
if (ev_type == 'C') {
length = 0;
data_tag = '>';
}
+ dir = 0;
}
if (rp->mmap_active)
@@ -440,15 +445,14 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
*/
memset(ep, 0, PKT_SIZE);
ep->type = ev_type;
- ep->xfer_type = usb_pipetype(urb->pipe);
- /* We use the fact that usb_pipein() returns 0x80 */
- ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
- ep->devnum = usb_pipedevice(urb->pipe);
+ ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)];
+ ep->epnum = dir | usb_endpoint_num(epd);
+ ep->devnum = urb->dev->devnum;
ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->ts_sec = ts.tv_sec;
ep->ts_usec = ts.tv_usec;
- ep->status = urb->status;
+ ep->status = status;
ep->len_urb = urb_length;
ep->len_cap = length;
@@ -471,13 +475,13 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
static void mon_bin_submit(void *data, struct urb *urb)
{
struct mon_reader_bin *rp = data;
- mon_bin_event(rp, urb, 'S');
+ mon_bin_event(rp, urb, 'S', -EINPROGRESS);
}
-static void mon_bin_complete(void *data, struct urb *urb)
+static void mon_bin_complete(void *data, struct urb *urb, int status)
{
struct mon_reader_bin *rp = data;
- mon_bin_event(rp, urb, 'C');
+ mon_bin_event(rp, urb, 'C', status);
}
static void mon_bin_error(void *data, struct urb *urb, int error)
@@ -500,10 +504,10 @@ static void mon_bin_error(void *data, struct urb *urb, int error)
memset(ep, 0, PKT_SIZE);
ep->type = 'E';
- ep->xfer_type = usb_pipetype(urb->pipe);
- /* We use the fact that usb_pipein() returns 0x80 */
- ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
- ep->devnum = usb_pipedevice(urb->pipe);
+ ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)];
+ ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0;
+ ep->epnum |= usb_endpoint_num(&urb->ep->desc);
+ ep->devnum = urb->dev->devnum;
ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->status = error;
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index ce61d8b0fd8..b371ffd39d3 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -129,7 +129,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
/*
*/
-static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
+static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb,
+ int status)
{
unsigned long flags;
struct list_head *pos;
@@ -139,28 +140,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
mbus->cnt_events++;
list_for_each (pos, &mbus->r_list) {
r = list_entry(pos, struct mon_reader, r_link);
- r->rnf_complete(r->r_data, urb);
+ r->rnf_complete(r->r_data, urb, status);
}
spin_unlock_irqrestore(&mbus->lock, flags);
}
-static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status)
{
struct mon_bus *mbus;
- mbus = ubus->mon_bus;
- if (mbus == NULL) {
- /*
- * This should not happen.
- * At this point we do not even know the bus number...
- */
- printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n",
- urb->pipe);
- return;
- }
-
- mon_bus_complete(mbus, urb);
- mon_bus_complete(&mon_bus0, urb);
+ if ((mbus = ubus->mon_bus) != NULL)
+ mon_bus_complete(mbus, urb, status);
+ mon_bus_complete(&mon_bus0, urb, status);
}
/* int (*unlink_urb) (struct urb *urb, int status); */
@@ -170,7 +161,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb)
*/
static void mon_stop(struct mon_bus *mbus)
{
- struct usb_bus *ubus = mbus->u_bus;
+ struct usb_bus *ubus;
struct list_head *p;
if (mbus == &mon_bus0) {
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 8f27a9e1c36..5e3e4e9b6c7 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -50,10 +50,13 @@ struct mon_iso_desc {
struct mon_event_text {
struct list_head e_link;
int type; /* submit, complete, etc. */
- unsigned int pipe; /* Pipe */
unsigned long id; /* From pointer, most of the time */
unsigned int tstamp;
int busnum;
+ char devnum;
+ char epnum;
+ char is_in;
+ char xfertype;
int length; /* Depends on type: xfer length or act length */
int status;
int interval;
@@ -84,7 +87,7 @@ struct mon_reader_text {
static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */
-static void mon_text_ctor(void *, struct kmem_cache *, unsigned long);
+static void mon_text_ctor(struct kmem_cache *, void *);
struct mon_text_ptr {
int cnt, limit;
@@ -121,13 +124,9 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
struct urb *urb, char ev_type, struct mon_bus *mbus)
{
- if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+ if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S')
return '-';
- if (urb->dev->bus->uses_dma &&
- (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
- return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
- }
if (urb->setup_packet == NULL)
return 'Z'; /* '0' would be not as pretty. */
@@ -138,14 +137,12 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
int len, char ev_type, struct mon_bus *mbus)
{
- int pipe = urb->pipe;
-
if (len <= 0)
return 'L';
if (len >= DATA_MAX)
len = DATA_MAX;
- if (usb_pipein(pipe)) {
+ if (ep->is_in) {
if (ev_type != 'C')
return '<';
} else {
@@ -186,7 +183,7 @@ static inline unsigned int mon_get_timestamp(void)
}
static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
- char ev_type)
+ char ev_type, int status)
{
struct mon_event_text *ep;
unsigned int stamp;
@@ -203,24 +200,28 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
}
ep->type = ev_type;
- ep->pipe = urb->pipe;
ep->id = (unsigned long) urb;
ep->busnum = urb->dev->bus->busnum;
+ ep->devnum = urb->dev->devnum;
+ ep->epnum = usb_endpoint_num(&urb->ep->desc);
+ ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+ ep->is_in = usb_urb_dir_in(urb);
ep->tstamp = stamp;
ep->length = (ev_type == 'S') ?
urb->transfer_buffer_length : urb->actual_length;
/* Collecting status makes debugging sense for submits, too */
- ep->status = urb->status;
+ ep->status = status;
- if (usb_pipeint(urb->pipe)) {
+ if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
ep->interval = urb->interval;
- } else if (usb_pipeisoc(urb->pipe)) {
+ } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
ep->interval = urb->interval;
ep->start_frame = urb->start_frame;
ep->error_count = urb->error_count;
}
ep->numdesc = urb->number_of_packets;
- if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) {
+ if (ep->xfertype == USB_ENDPOINT_XFER_ISOC &&
+ urb->number_of_packets > 0) {
if ((ndesc = urb->number_of_packets) > ISODESC_MAX)
ndesc = ISODESC_MAX;
fp = urb->iso_frame_desc;
@@ -247,13 +248,13 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
static void mon_text_submit(void *data, struct urb *urb)
{
struct mon_reader_text *rp = data;
- mon_text_event(rp, urb, 'S');
+ mon_text_event(rp, urb, 'S', -EINPROGRESS);
}
-static void mon_text_complete(void *data, struct urb *urb)
+static void mon_text_complete(void *data, struct urb *urb, int status)
{
struct mon_reader_text *rp = data;
- mon_text_event(rp, urb, 'C');
+ mon_text_event(rp, urb, 'C', status);
}
static void mon_text_error(void *data, struct urb *urb, int error)
@@ -268,9 +269,12 @@ static void mon_text_error(void *data, struct urb *urb, int error)
}
ep->type = 'E';
- ep->pipe = urb->pipe;
ep->id = (unsigned long) urb;
ep->busnum = 0;
+ ep->devnum = urb->dev->devnum;
+ ep->epnum = usb_endpoint_num(&urb->ep->desc);
+ ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+ ep->is_in = usb_urb_dir_in(urb);
ep->tstamp = 0;
ep->length = 0;
ep->status = error;
@@ -413,10 +417,10 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf,
mon_text_read_head_u(rp, &ptr, ep);
if (ep->type == 'E') {
mon_text_read_statset(rp, &ptr, ep);
- } else if (usb_pipeisoc(ep->pipe)) {
+ } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
mon_text_read_isostat(rp, &ptr, ep);
mon_text_read_isodesc(rp, &ptr, ep);
- } else if (usb_pipeint(ep->pipe)) {
+ } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
mon_text_read_intstat(rp, &ptr, ep);
} else {
mon_text_read_statset(rp, &ptr, ep);
@@ -468,18 +472,17 @@ static void mon_text_read_head_t(struct mon_reader_text *rp,
{
char udir, utype;
- udir = usb_pipein(ep->pipe) ? 'i' : 'o';
- switch (usb_pipetype(ep->pipe)) {
- case PIPE_ISOCHRONOUS: utype = 'Z'; break;
- case PIPE_INTERRUPT: utype = 'I'; break;
- case PIPE_CONTROL: utype = 'C'; break;
+ udir = (ep->is_in ? 'i' : 'o');
+ switch (ep->xfertype) {
+ case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break;
+ case USB_ENDPOINT_XFER_INT: utype = 'I'; break;
+ case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
default: /* PIPE_BULK */ utype = 'B';
}
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
"%lx %u %c %c%c:%03u:%02u",
ep->id, ep->tstamp, ep->type,
- utype, udir,
- usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+ utype, udir, ep->devnum, ep->epnum);
}
static void mon_text_read_head_u(struct mon_reader_text *rp,
@@ -487,18 +490,17 @@ static void mon_text_read_head_u(struct mon_reader_text *rp,
{
char udir, utype;
- udir = usb_pipein(ep->pipe) ? 'i' : 'o';
- switch (usb_pipetype(ep->pipe)) {
- case PIPE_ISOCHRONOUS: utype = 'Z'; break;
- case PIPE_INTERRUPT: utype = 'I'; break;
- case PIPE_CONTROL: utype = 'C'; break;
+ udir = (ep->is_in ? 'i' : 'o');
+ switch (ep->xfertype) {
+ case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break;
+ case USB_ENDPOINT_XFER_INT: utype = 'I'; break;
+ case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
default: /* PIPE_BULK */ utype = 'B';
}
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
"%lx %u %c %c%c:%d:%03u:%u",
ep->id, ep->tstamp, ep->type,
- utype, udir,
- ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+ utype, udir, ep->busnum, ep->devnum, ep->epnum);
}
static void mon_text_read_statset(struct mon_reader_text *rp,
@@ -718,7 +720,7 @@ void mon_text_del(struct mon_bus *mbus)
/*
* Slab interface: constructor.
*/
-static void mon_text_ctor(void *mem, struct kmem_cache *slab, unsigned long sflags)
+static void mon_text_ctor(struct kmem_cache *slab, void *mem)
{
/*
* Nothing to initialize. No, really!
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index f68ad6d99ad..f5d84ff8c10 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -46,7 +46,7 @@ struct mon_reader {
void (*rnf_submit)(void *data, struct urb *urb);
void (*rnf_error)(void *data, struct urb *urb, int error);
- void (*rnf_complete)(void *data, struct urb *urb);
+ void (*rnf_complete)(void *data, struct urb *urb, int status);
};
void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
diff --git a/drivers/usb/serial/ChangeLog.history b/drivers/usb/serial/ChangeLog.history
index 52c4f7bd7a8..c1b279939bb 100644
--- a/drivers/usb/serial/ChangeLog.history
+++ b/drivers/usb/serial/ChangeLog.history
@@ -400,7 +400,7 @@ visor.c Change Log comments:
(11/11/2001) gkh
Added support for the m125 devices, and added check to prevent oopses
- for Clié devices that lie about the number of ports they have.
+ for Clié devices that lie about the number of ports they have.
(08/30/2001) gkh
Added support for the Clie devices, both the 3.5 and 4.0 os versions.
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 43d6db696f9..4a86696e6c7 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -92,6 +92,16 @@ config USB_SERIAL_BELKIN
To compile this driver as a module, choose M here: the
module will be called belkin_sa.
+config USB_SERIAL_CH341
+ tristate "USB Winchiphead CH341 Single Port Serial Driver"
+ depends on USB_SERIAL
+ help
+ Say Y here if you want to use a Winchiphead CH341 single port
+ USB to serial adapter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ch341.
+
config USB_SERIAL_WHITEHEAT
tristate "USB ConnectTech WhiteHEAT Serial Driver"
depends on USB_SERIAL
@@ -517,7 +527,7 @@ config USB_SERIAL_CYBERJACK
depends on USB_SERIAL && EXPERIMENTAL
---help---
Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard
- reader. This is an interface to ISO 7816 compatible contactbased
+ reader. This is an interface to ISO 7816 compatible contact-based
chipcards, e.g. GSM SIMs.
To compile this driver as a module, choose M here: the
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 07a976eca6b..d6fb384e52b 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o
obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o
obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
+obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o
obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o
obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o
obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index c9fd486c1c7..ddfee918000 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -161,7 +161,8 @@ static void ark3116_set_termios(struct usb_serial_port *port,
{
struct usb_serial *serial = port->serial;
struct ark3116_private *priv = usb_get_serial_port_data(port);
- unsigned int cflag = port->tty->termios->c_cflag;
+ struct ktermios *termios = port->tty->termios;
+ unsigned int cflag = termios->c_cflag;
unsigned long flags;
int baud;
int ark3116_baud;
@@ -172,21 +173,19 @@ static void ark3116_set_termios(struct usb_serial_port *port,
dbg("%s - port %d", __FUNCTION__, port->number);
- if (!port->tty || !port->tty->termios) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
-
spin_lock_irqsave(&priv->lock, flags);
if (!priv->termios_initialized) {
*(port->tty->termios) = tty_std_termios;
port->tty->termios->c_cflag = B9600 | CS8
| CREAD | HUPCL | CLOCAL;
+ termios->c_ispeed = 9600;
+ termios->c_ospeed = 9600;
priv->termios_initialized = 1;
}
spin_unlock_irqrestore(&priv->lock, flags);
- cflag = port->tty->termios->c_cflag;
+ cflag = termios->c_cflag;
+ termios->c_cflag &= ~(CMSPAR|CRTSCTS);
buf = kmalloc(1, GFP_KERNEL);
if (!buf) {
@@ -259,9 +258,13 @@ static void ark3116_set_termios(struct usb_serial_port *port,
case 115200:
case 230400:
case 460800:
+ /* Report the resulting rate back to the caller */
+ tty_encode_baud_rate(port->tty, baud, baud);
break;
/* set 9600 as default (if given baudrate is invalid for example) */
default:
+ tty_encode_baud_rate(port->tty, 9600, 9600);
+ case 0:
baud = 9600;
}
@@ -307,6 +310,7 @@ static void ark3116_set_termios(struct usb_serial_port *port,
/* TEST ARK3116_SND(154, 0xFE, 0x40, 0xFFFF, 0x0006); */
kfree(buf);
+
return;
}
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index a47a24f8820..0b14aea8ebd 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -36,6 +36,16 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *dr
return 0;
}
+static ssize_t show_port_number(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_serial_port *port = to_usb_serial_port(dev);
+
+ return sprintf(buf, "%d\n", port->number - port->serial->minor);
+}
+
+static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL);
+
static int usb_serial_device_probe (struct device *dev)
{
struct usb_serial_driver *driver;
@@ -62,6 +72,10 @@ static int usb_serial_device_probe (struct device *dev)
goto exit;
}
+ retval = device_create_file(dev, &dev_attr_port_number);
+ if (retval)
+ goto exit;
+
minor = port->number;
tty_register_device (usb_serial_tty_driver, minor, dev);
dev_info(&port->serial->dev->dev,
@@ -84,6 +98,8 @@ static int usb_serial_device_remove (struct device *dev)
return -ENODEV;
}
+ device_remove_file(&port->dev, &dev_attr_port_number);
+
driver = port->serial->type;
if (driver->port_remove) {
if (!try_module_get(driver->driver.owner)) {
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
new file mode 100644
index 00000000000..42582d49b69
--- /dev/null
+++ b/drivers/usb/serial/ch341.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk>
+ *
+ * ch341.c implements a serial port driver for the Winchiphead CH341.
+ *
+ * The CH341 device can be used to implement an RS232 asynchronous
+ * serial port, an IEEE-1284 parallel printer port or a memory-like
+ * interface. In all cases the CH341 supports an I2C interface as well.
+ * This driver only supports the asynchronous serial interface.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/serial.h>
+
+#define DEFAULT_BAUD_RATE 2400
+#define DEFAULT_TIMEOUT 1000
+
+static int debug;
+
+static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x4348, 0x5523) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct ch341_private {
+ unsigned baud_rate;
+ u8 dtr;
+ u8 rts;
+};
+
+static int ch341_control_out(struct usb_device *dev, u8 request,
+ u16 value, u16 index)
+{
+ int r;
+ dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40,
+ (int)request, (int)value, (int)index);
+
+ r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ value, index, NULL, 0, DEFAULT_TIMEOUT);
+
+ return r;
+}
+
+static int ch341_control_in(struct usb_device *dev,
+ u8 request, u16 value, u16 index,
+ char *buf, unsigned bufsize)
+{
+ int r;
+ dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40,
+ (int)request, (int)value, (int)index, buf, (int)bufsize);
+
+ r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ value, index, buf, bufsize, DEFAULT_TIMEOUT);
+ return r;
+}
+
+static int ch341_set_baudrate(struct usb_device *dev,
+ struct ch341_private *priv)
+{
+ short a, b;
+ int r;
+
+ dbg("ch341_set_baudrate(%d)", priv->baud_rate);
+ switch (priv->baud_rate) {
+ case 2400:
+ a = 0xd901;
+ b = 0x0038;
+ break;
+ case 4800:
+ a = 0x6402;
+ b = 0x001f;
+ break;
+ case 9600:
+ a = 0xb202;
+ b = 0x0013;
+ break;
+ case 19200:
+ a = 0xd902;
+ b = 0x000d;
+ break;
+ case 38400:
+ a = 0x6403;
+ b = 0x000a;
+ break;
+ case 115200:
+ a = 0xcc03;
+ b = 0x0008;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ r = ch341_control_out(dev, 0x9a, 0x1312, a);
+ if (!r)
+ r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
+
+ return r;
+}
+
+static int ch341_set_handshake(struct usb_device *dev,
+ struct ch341_private *priv)
+{
+ dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts);
+ return ch341_control_out(dev, 0xa4,
+ ~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0);
+}
+
+static int ch341_get_status(struct usb_device *dev)
+{
+ char *buffer;
+ int r;
+ const unsigned size = 8;
+
+ dbg("ch341_get_status()");
+
+ buffer = kmalloc(size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
+ if ( r < 0)
+ goto out;
+
+ /* Not having the datasheet for the CH341, we ignore the bytes returned
+ * from the device. Return error if the device did not respond in time.
+ */
+ r = 0;
+
+out: kfree(buffer);
+ return r;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
+{
+ char *buffer;
+ int r;
+ const unsigned size = 8;
+
+ dbg("ch341_configure()");
+
+ buffer = kmalloc(size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ /* expect two bytes 0x27 0x00 */
+ r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size);
+ if (r < 0)
+ goto out;
+
+ r = ch341_control_out(dev, 0xa1, 0, 0);
+ if (r < 0)
+ goto out;
+
+ r = ch341_set_baudrate(dev, priv);
+ if (r < 0)
+ goto out;
+
+ /* expect two bytes 0x56 0x00 */
+ r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size);
+ if (r < 0)
+ goto out;
+
+ r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050);
+ if (r < 0)
+ goto out;
+
+ /* expect 0xff 0xee */
+ r = ch341_get_status(dev);
+ if (r < 0)
+ goto out;
+
+ r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a);
+ if (r < 0)
+ goto out;
+
+ r = ch341_set_baudrate(dev, priv);
+ if (r < 0)
+ goto out;
+
+ r = ch341_set_handshake(dev, priv);
+ if (r < 0)
+ goto out;
+
+ /* expect 0x9f 0xee */
+ r = ch341_get_status(dev);
+
+out: kfree(buffer);
+ return r;
+}
+
+/* allocate private data */
+static int ch341_attach(struct usb_serial *serial)
+{
+ struct ch341_private *priv;
+ int r;
+
+ dbg("ch341_attach()");
+
+ /* private data */
+ priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->baud_rate = DEFAULT_BAUD_RATE;
+ priv->dtr = 1;
+ priv->rts = 1;
+
+ r = ch341_configure(serial->dev, priv);
+ if (r < 0)
+ goto error;
+
+ usb_set_serial_port_data(serial->port[0], priv);
+ return 0;
+
+error: kfree(priv);
+ return r;
+}
+
+/* open this device, set default parameters */
+static int ch341_open(struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+ struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
+ int r;
+
+ dbg("ch341_open()");
+
+ priv->baud_rate = DEFAULT_BAUD_RATE;
+ priv->dtr = 1;
+ priv->rts = 1;
+
+ r = ch341_configure(serial->dev, priv);
+ if (r)
+ goto out;
+
+ r = ch341_set_handshake(serial->dev, priv);
+ if (r)
+ goto out;
+
+ r = ch341_set_baudrate(serial->dev, priv);
+ if (r)
+ goto out;
+
+ r = usb_serial_generic_open(port, filp);
+
+out: return r;
+}
+
+/* Old_termios contains the original termios settings and
+ * tty->termios contains the new setting to be used.
+ */
+static void ch341_set_termios(struct usb_serial_port *port,
+ struct ktermios *old_termios)
+{
+ struct ch341_private *priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty = port->tty;
+ unsigned baud_rate;
+
+ dbg("ch341_set_termios()");
+
+ baud_rate = tty_get_baud_rate(tty);
+
+ switch (baud_rate) {
+ case 2400:
+ case 4800:
+ case 9600:
+ case 19200:
+ case 38400:
+ case 115200:
+ priv->baud_rate = baud_rate;
+ break;
+ default:
+ dbg("Rate %d not supported, using %d",
+ baud_rate, DEFAULT_BAUD_RATE);
+ priv->baud_rate = DEFAULT_BAUD_RATE;
+ }
+
+ ch341_set_baudrate(port->serial->dev, priv);
+
+ /* Unimplemented:
+ * (cflag & CSIZE) : data bits [5, 8]
+ * (cflag & PARENB) : parity {NONE, EVEN, ODD}
+ * (cflag & CSTOPB) : stop bits [1, 2]
+ */
+
+ /* Copy back the old hardware settings */
+ tty_termios_copy_hw(tty->termios, old_termios);
+ /* And re-encode with the new baud */
+ tty_encode_baud_rate(tty, baud_rate, baud_rate);
+}
+
+static struct usb_driver ch341_driver = {
+ .name = "ch341",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
+static struct usb_serial_driver ch341_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ch341-uart",
+ },
+ .id_table = id_table,
+ .usb_driver = &ch341_driver,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = ch341_open,
+ .set_termios = ch341_set_termios,
+ .attach = ch341_attach,
+};
+
+static int __init ch341_init(void)
+{
+ int retval;
+
+ retval = usb_serial_register(&ch341_device);
+ if (retval)
+ return retval;
+ retval = usb_register(&ch341_driver);
+ if (retval)
+ usb_serial_deregister(&ch341_device);
+ return retval;
+}
+
+static void __exit ch341_exit(void)
+{
+ usb_deregister(&ch341_driver);
+ usb_serial_deregister(&ch341_device);
+}
+
+module_init(ch341_init);
+module_exit(ch341_exit);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* EOF ch341.c */
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 9386e216d68..0362654d3b5 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -164,6 +164,7 @@ static int usb_console_setup(struct console *co, char *options)
}
if (serial->type->set_termios) {
+ struct ktermios dummy;
/* build up a fake tty structure so that the open call has something
* to look at to get the cflag value */
tty = kzalloc(sizeof(*tty), GFP_KERNEL);
@@ -177,12 +178,13 @@ static int usb_console_setup(struct console *co, char *options)
kfree (tty);
return -ENOMEM;
}
+ memset(&dummy, 0, sizeof(struct ktermios));
termios->c_cflag = cflag;
tty->termios = termios;
port->tty = tty;
/* set up the initial termios settings */
- serial->type->set_termios(port, NULL);
+ serial->type->set_termios(port, &dummy);
port->tty = NULL;
kfree (termios);
kfree (tty);
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 33f6ee50b8d..3a83cb4c4bc 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -53,6 +53,7 @@ static void cp2101_shutdown(struct usb_serial*);
static int debug;
static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
@@ -360,7 +361,6 @@ static void cp2101_get_termios (struct usb_serial_port *port)
dbg("%s - no tty structures", __FUNCTION__);
return;
}
- cflag = port->tty->termios->c_cflag;
cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2);
/* Convert to baudrate */
@@ -368,40 +368,9 @@ static void cp2101_get_termios (struct usb_serial_port *port)
baud = BAUD_RATE_GEN_FREQ / baud;
dbg("%s - baud rate = %d", __FUNCTION__, baud);
- cflag &= ~CBAUD;
- switch (baud) {
- /*
- * The baud rates which are commented out below
- * appear to be supported by the device
- * but are non-standard
- */
- case 600: cflag |= B600; break;
- case 1200: cflag |= B1200; break;
- case 1800: cflag |= B1800; break;
- case 2400: cflag |= B2400; break;
- case 4800: cflag |= B4800; break;
- /*case 7200: cflag |= B7200; break;*/
- case 9600: cflag |= B9600; break;
- /*case 14400: cflag |= B14400; break;*/
- case 19200: cflag |= B19200; break;
- /*case 28800: cflag |= B28800; break;*/
- case 38400: cflag |= B38400; break;
- /*case 55854: cflag |= B55054; break;*/
- case 57600: cflag |= B57600; break;
- case 115200: cflag |= B115200; break;
- /*case 127117: cflag |= B127117; break;*/
- case 230400: cflag |= B230400; break;
- case 460800: cflag |= B460800; break;
- case 921600: cflag |= B921600; break;
- /*case 3686400: cflag |= B3686400; break;*/
- default:
- dbg("%s - Baud rate is not supported, "
- "using 9600 baud", __FUNCTION__);
- cflag |= B9600;
- cp2101_set_config_single(port, CP2101_BAUDRATE,
- (BAUD_RATE_GEN_FREQ/9600));
- break;
- }
+
+ tty_encode_baud_rate(port->tty, baud, baud);
+ cflag = port->tty->termios->c_cflag;
cp2101_get_config(port, CP2101_BITS, &bits, 2);
cflag &= ~CSIZE;
@@ -515,16 +484,18 @@ static void cp2101_get_termios (struct usb_serial_port *port)
static void cp2101_set_termios (struct usb_serial_port *port,
struct ktermios *old_termios)
{
- unsigned int cflag, old_cflag=0;
+ unsigned int cflag, old_cflag;
int baud=0, bits;
unsigned int modem_ctl[4];
dbg("%s - port %d", __FUNCTION__, port->number);
- if ((!port->tty) || (!port->tty->termios)) {
+ if (!port->tty || !port->tty->termios) {
dbg("%s - no tty structures", __FUNCTION__);
return;
}
+ port->tty->termios->c_cflag &= ~CMSPAR;
+
cflag = port->tty->termios->c_cflag;
old_cflag = old_termios->c_cflag;
baud = tty_get_baud_rate(port->tty);
@@ -562,11 +533,15 @@ static void cp2101_set_termios (struct usb_serial_port *port,
dbg("%s - Setting baud rate to %d baud", __FUNCTION__,
baud);
if (cp2101_set_config_single(port, CP2101_BAUDRATE,
- (BAUD_RATE_GEN_FREQ / baud)))
+ (BAUD_RATE_GEN_FREQ / baud))) {
dev_err(&port->dev, "Baud rate requested not "
"supported by device\n");
+ baud = tty_termios_baud_rate(old_termios);
+ }
}
}
+ /* Report back the resulting baud rate */
+ tty_encode_baud_rate(port->tty, baud, baud);
/* If the number of data bits is to be updated */
if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index dab2e66d111..ae410c4678e 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -973,6 +973,8 @@ static void digi_set_termios(struct usb_serial_port *port,
}
}
/* set parity */
+ tty->termios->c_cflag &= ~CMSPAR;
+
if ((cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD))) {
if (cflag&PARENB) {
if (cflag&PARODD)
@@ -1054,15 +1056,15 @@ static void digi_set_termios(struct usb_serial_port *port,
}
/* set output flow control */
- if ((iflag&IXON) != (old_iflag&IXON)
- || (cflag&CRTSCTS) != (old_cflag&CRTSCTS)) {
+ if ((iflag & IXON) != (old_iflag & IXON)
+ || (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
arg = 0;
- if (iflag&IXON)
+ if (iflag & IXON)
arg |= DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
else
arg &= ~DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
- if (cflag&CRTSCTS) {
+ if (cflag & CRTSCTS) {
arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS;
} else {
arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS;
@@ -1076,8 +1078,8 @@ static void digi_set_termios(struct usb_serial_port *port,
}
/* set receive enable/disable */
- if ((cflag&CREAD) != (old_cflag&CREAD)) {
- if (cflag&CREAD)
+ if ((cflag & CREAD) != (old_cflag & CREAD)) {
+ if (cflag & CREAD)
arg = DIGI_ENABLE;
else
arg = DIGI_DISABLE;
@@ -1089,7 +1091,7 @@ static void digi_set_termios(struct usb_serial_port *port,
}
if ((ret = digi_write_oob_command(port, buf, i, 1)) != 0)
dbg("digi_set_termios: write oob failed, ret=%d", ret);
-
+ tty_encode_baud_rate(tty, baud, baud);
}
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 050fcc996f5..a5c8e1e17ea 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -449,14 +449,9 @@ static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsign
static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
-
+ struct ktermios *termios = port->tty->termios;
dbg("%s - port %d", __FUNCTION__, port->number);
- if ((!port->tty) || (!port->tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
-
/*
* The empeg-car player wants these particular tty settings.
* You could, for example, change the baud rate, however the
@@ -466,7 +461,7 @@ static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *ol
*
* The default requirements for this device are:
*/
- port->tty->termios->c_iflag
+ termios->c_iflag
&= ~(IGNBRK /* disable ignore break */
| BRKINT /* disable break causes interrupt */
| PARMRK /* disable mark parity errors */
@@ -476,24 +471,23 @@ static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *ol
| ICRNL /* disable translate CR to NL */
| IXON); /* disable enable XON/XOFF flow control */
- port->tty->termios->c_oflag
+ termios->c_oflag
&= ~OPOST; /* disable postprocess output characters */
- port->tty->termios->c_lflag
+ termios->c_lflag
&= ~(ECHO /* disable echo input characters */
| ECHONL /* disable echo new line */
| ICANON /* disable erase, kill, werase, and rprnt special characters */
| ISIG /* disable interrupt, quit, and suspend special characters */
| IEXTEN); /* disable non-POSIX special characters */
- port->tty->termios->c_cflag
+ termios->c_cflag
&= ~(CSIZE /* no size */
| PARENB /* disable parity bit */
| CBAUD); /* clear current baud rate */
- port->tty->termios->c_cflag
- |= (CS8 /* character size 8 bits */
- | B115200); /* baud rate 115200 */
+ termios->c_cflag
+ |= CS8; /* character size 8 bits */
/*
* Force low_latency on; otherwise the pushes are scheduled;
@@ -501,8 +495,7 @@ static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *ol
* on the floor. We don't want to drop bytes on the floor. :)
*/
port->tty->low_latency = 1;
-
- return;
+ tty_encode_baud_rate(port->tty, 115200, 115200);
}
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 2d045857b18..c40e77dccf8 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -83,7 +83,7 @@
*
* (18/Jun/2003) Ian Abbott
* Added Device ID of the USB relais from Rudolf Gugler (backported from
- * Philipp Gühring's patch for 2.5.x kernel).
+ * Philipp Gühring's patch for 2.5.x kernel).
* Moved read transfer buffer reallocation into startup function.
* Free existing write urb and transfer buffer in startup function.
* Only use urbs in write urb pool that were successfully allocated.
@@ -294,7 +294,7 @@ struct ftdi_private {
__u16 interface; /* FT2232C port interface (0 for FT232/245) */
- int force_baud; /* if non-zero, force the baud rate to this value */
+ speed_t force_baud; /* if non-zero, force the baud rate to this value */
int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */
spinlock_t tx_lock; /* spinlock for transmit state */
@@ -878,6 +878,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
if (div_value == 0) {
dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud);
div_value = ftdi_sio_b9600;
+ baud = 9600;
div_okay = 0;
}
break;
@@ -886,6 +887,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
div_value = ftdi_232am_baud_to_divisor(baud);
} else {
dbg("%s - Baud rate too high!", __FUNCTION__);
+ baud = 9600;
div_value = ftdi_232am_baud_to_divisor(9600);
div_okay = 0;
}
@@ -899,6 +901,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
dbg("%s - Baud rate too high!", __FUNCTION__);
div_value = ftdi_232bm_baud_to_divisor(9600);
div_okay = 0;
+ baud = 9600;
}
break;
} /* priv->chip_type */
@@ -909,6 +912,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
ftdi_chip_name[priv->chip_type]);
}
+ tty_encode_baud_rate(port->tty, baud, baud);
return(div_value);
}
@@ -1071,7 +1075,7 @@ static ssize_t show_latency_timer(struct device *dev, struct device_attribute *a
(char*) &latency, 1, WDR_TIMEOUT);
if (rv < 0) {
- dev_err(dev, "Unable to read latency timer: %i", rv);
+ dev_err(dev, "Unable to read latency timer: %i\n", rv);
return -EIO;
}
return sprintf(buf, "%i\n", latency);
@@ -1098,7 +1102,7 @@ static ssize_t store_latency_timer(struct device *dev, struct device_attribute *
buf, 0, WDR_TIMEOUT);
if (rv < 0) {
- dev_err(dev, "Unable to write latency timer: %i", rv);
+ dev_err(dev, "Unable to write latency timer: %i\n", rv);
return -EIO;
}
@@ -1169,7 +1173,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
/* XXX see create_sysfs_attrs */
if (priv->chip_type != SIO) {
device_remove_file(&port->dev, &dev_attr_event_char);
- if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
+ if (priv->chip_type == FT232BM ||
+ priv->chip_type == FT2232C ||
+ priv->chip_type == FT232RL) {
device_remove_file(&port->dev, &dev_attr_latency_timer);
}
}
@@ -1261,7 +1267,7 @@ static void ftdi_USB_UIRT_setup (struct ftdi_private *priv)
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 77;
- priv->force_baud = B38400;
+ priv->force_baud = 38400;
} /* ftdi_USB_UIRT_setup */
/* Setup for the HE-TIRA1 device, which requires hardwired
@@ -1272,7 +1278,7 @@ static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv)
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 240;
- priv->force_baud = B38400;
+ priv->force_baud = 38400;
priv->force_rtscts = 1;
} /* ftdi_HE_TIRA1_setup */
@@ -1361,7 +1367,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
/* ftdi_set_termios will send usb control messages */
if (port->tty)
- ftdi_set_termios(port, NULL);
+ ftdi_set_termios(port, port->tty->termios);
/* FIXME: Flow control might be enabled, so it should be checked -
we have no control of defaults! */
@@ -1931,32 +1937,33 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{ /* ftdi_termios */
struct usb_device *dev = port->serial->dev;
- unsigned int cflag = port->tty->termios->c_cflag;
struct ftdi_private *priv = usb_get_serial_port_data(port);
+ struct ktermios *termios = port->tty->termios;
+ unsigned int cflag = termios->c_cflag;
__u16 urb_value; /* will hold the new flags */
char buf[1]; /* Perhaps I should dynamically alloc this? */
// Added for xon/xoff support
- unsigned int iflag = port->tty->termios->c_iflag;
+ unsigned int iflag = termios->c_iflag;
unsigned char vstop;
unsigned char vstart;
dbg("%s", __FUNCTION__);
/* Force baud rate if this device requires it, unless it is set to B0. */
- if (priv->force_baud && ((port->tty->termios->c_cflag & CBAUD) != B0)) {
+ if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) {
dbg("%s: forcing baud rate for this device", __FUNCTION__);
- port->tty->termios->c_cflag &= ~CBAUD;
- port->tty->termios->c_cflag |= priv->force_baud;
+ tty_encode_baud_rate(port->tty, priv->force_baud,
+ priv->force_baud);
}
/* Force RTS-CTS if this device requires it. */
if (priv->force_rtscts) {
dbg("%s: forcing rtscts for this device", __FUNCTION__);
- port->tty->termios->c_cflag |= CRTSCTS;
+ termios->c_cflag |= CRTSCTS;
}
- cflag = port->tty->termios->c_cflag;
+ cflag = termios->c_cflag;
/* FIXME -For this cut I don't care if the line is really changing or
not - so just do the change regardless - should be able to
@@ -1967,6 +1974,8 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old
/* Set number of data bits, parity, stop bits */
+ termios->c_cflag &= ~CMSPAR;
+
urb_value = 0;
urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
FTDI_SIO_SET_DATA_STOP_BITS_1);
@@ -2046,8 +2055,8 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old
// Set the vstart and vstop -- could have been done up above where
// a lot of other dereferencing is done but that would be very
// inefficient as vstart and vstop are not always needed
- vstart=port->tty->termios->c_cc[VSTART];
- vstop=port->tty->termios->c_cc[VSTOP];
+ vstart = termios->c_cc[VSTART];
+ vstop = termios->c_cc[VSTOP];
urb_value=(vstop << 8) | (vstart);
if (usb_control_msg(dev,
@@ -2102,6 +2111,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
case FT8U232AM:
case FT232BM:
case FT2232C:
+ case FT232RL:
/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
format as the data returned from the in point */
if ((ret = usb_control_msg(port->serial->dev,
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index b57b90ae9f9..b51cbb0eaa0 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -17,7 +17,7 @@
* Bill Ryder - bryder@sgi.com formerly of Silicon Graphics, Inc.- wrote the
* FTDI_SIO implementation.
*
- * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais
+ * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais
* from Rudolf Gugler
*
*/
@@ -44,7 +44,7 @@
#define FTDI_ACTZWAVE_PID 0xF2D0
-/* www.starting-point-systems.com µChameleon device */
+/* www.starting-point-systems.com µChameleon device */
#define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */
/* www.irtrans.de device */
@@ -419,7 +419,7 @@
/*
* Teratronik product ids.
- * Submitted by O. Wölfelschneider.
+ * Submitted by O. Wölfelschneider.
*/
#define FTDI_TERATRONIK_VCP_PID 0xEC88 /* Teratronik device (preferring VCP driver on windows) */
#define FTDI_TERATRONIK_D2XX_PID 0xEC89 /* Teratronik device (preferring D2XX driver on windows) */
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 4092f6dc9ef..b5194dc7d3b 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -24,26 +24,6 @@ static struct usb_device_id id_table [] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static int funsoft_ioctl(struct usb_serial_port *port, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct ktermios t;
-
- dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd);
-
- if (cmd == TCSETSF) {
- if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg))
- return -EFAULT;
-
- dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__,
- t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
-
- if (!(t.c_lflag & ICANON))
- return -EINVAL;
- }
- return -ENOIOCTLCMD;
-}
-
static struct usb_driver funsoft_driver = {
.name = "funsoft",
.probe = usb_serial_probe,
@@ -63,7 +43,6 @@ static struct usb_serial_driver funsoft_device = {
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
- .ioctl = funsoft_ioctl,
};
static int __init funsoft_init(void)
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 88a2c7dce33..9eb4a65ee4d 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -208,14 +208,15 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
- spin_lock_bh(&port->lock);
+ unsigned long flags;
+ spin_lock_irqsave(&port->lock, flags);
if (port->write_urb_busy) {
- spin_unlock_bh(&port->lock);
+ spin_unlock_irqrestore(&port->lock, flags);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
- spin_unlock_bh(&port->lock);
+ spin_unlock_irqrestore(&port->lock, flags);
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 2ecb1d2a034..a5d2e115e16 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -1503,22 +1503,16 @@ static void edge_unthrottle (struct usb_serial_port *port)
*****************************************************************************/
static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
+ /* FIXME: This function appears unused ?? */
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
struct tty_struct *tty = port->tty;
unsigned int cflag;
- if (!port->tty || !port->tty->termios) {
- dbg ("%s - no tty or termios", __FUNCTION__);
- return;
- }
-
cflag = tty->termios->c_cflag;
dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
tty->termios->c_cflag, tty->termios->c_iflag);
- if (old_termios) {
- dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
- old_termios->c_cflag, old_termios->c_iflag);
- }
+ dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+ old_termios->c_cflag, old_termios->c_iflag);
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -2653,7 +2647,11 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
dbg("%s - baud rate = %d", __FUNCTION__, baud);
status = send_cmd_write_baud_rate (edge_port, baud);
-
+ if (status == -1) {
+ /* Speed change was not possible - put back the old speed */
+ baud = tty_termios_baud_rate(old_termios);
+ tty_encode_baud_rate(tty, baud, baud);
+ }
return;
}
@@ -2882,7 +2880,7 @@ static int edge_startup (struct usb_serial *serial)
(edge_serial->product_info.NumPorts != serial->num_ports)) {
dev_warn(&serial->dev->dev, "Device Reported %d serial ports "
"vs. core thinking we have %d ports, email "
- "greg@kroah.com this information.",
+ "greg@kroah.com this information.\n",
edge_serial->product_info.NumPorts,
serial->num_ports);
}
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 6a3a704b584..9b38a08ac83 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -256,6 +256,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */
{ USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
{ USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */
+ { USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */
{ USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
@@ -305,7 +306,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(0x0930, 0x0705) }, /* TOSHIBA Pocket PC e310 */
{ USB_DEVICE(0x0930, 0x0706) }, /* TOSHIBA Pocket PC e740 */
{ USB_DEVICE(0x0930, 0x0707) }, /* TOSHIBA Pocket PC e330 Series */
- { USB_DEVICE(0x0930, 0x0708) }, /* TOSHIBA Pocket PC e350 Series */
+ { USB_DEVICE(0x0930, 0x0708) }, /* TOSHIBA Pocket PC e350 Series */
{ USB_DEVICE(0x0930, 0x0709) }, /* TOSHIBA Pocket PC e750 Series */
{ USB_DEVICE(0x0930, 0x070A) }, /* TOSHIBA Pocket PC e400 Series */
{ USB_DEVICE(0x0930, 0x070B) }, /* TOSHIBA Pocket PC e800 Series */
@@ -487,7 +488,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(0x0BF8, 0x1001) }, /* Fujitsu Siemens Computers USB Sync */
{ USB_DEVICE(0x0C44, 0x03A2) }, /* Motorola iDEN Smartphone */
{ USB_DEVICE(0x0C8E, 0x6000) }, /* Cesscom Luxian Series */
- { USB_DEVICE(0x0CAD, 0x9001) }, /* Motorola PowerPad Pocket PC Device */
+ { USB_DEVICE(0x0CAD, 0x9001) }, /* Motorola PowerPad Pocket PC Device */
{ USB_DEVICE(0x0F4E, 0x0200) }, /* Freedom Scientific USB Sync */
{ USB_DEVICE(0x0F98, 0x0201) }, /* Cyberbank USB Sync */
{ USB_DEVICE(0x0FB8, 0x3001) }, /* Wistron USB Sync */
@@ -646,11 +647,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
kfree(port->bulk_out_buffer);
port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
if (port->bulk_in_buffer == NULL) {
+ port->bulk_out_buffer = NULL; /* prevent double free */
goto enomem;
}
port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
if (port->bulk_out_buffer == NULL) {
kfree(port->bulk_in_buffer);
+ port->bulk_in_buffer = NULL;
goto enomem;
}
port->read_urb->transfer_buffer = port->bulk_in_buffer;
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 1b94daa6158..cbe5530f3db 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -227,7 +227,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
0,
100000);
if (result < 0)
- dev_err(&port->dev, "Init of modem failed (error = %d)", result);
+ dev_err(&port->dev, "Init of modem failed (error = %d)\n", result);
/* reset the bulk pipes */
usb_clear_halt(dev, usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress));
@@ -255,7 +255,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
0,
100000);
if (result < 0)
- dev_err(&port->dev, "Enabling bulk RxRead failed (error = %d)", result);
+ dev_err(&port->dev, "Enabling bulk RxRead failed (error = %d)\n", result);
/*--4: setup the initial flowcontrol */
dbg("%s:setting init flowcontrol (%s)",__FUNCTION__,buf_flow_init);
@@ -268,7 +268,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
0x10,
200000);
if (result < 0)
- dev_err(&port->dev, "initial flowcontrol failed (error = %d)", result);
+ dev_err(&port->dev, "initial flowcontrol failed (error = %d)\n", result);
/*--5: raise the dtr */
@@ -282,7 +282,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
0,
200000);
if (result < 0)
- dev_err(&port->dev, "setting dtr failed (error = %d)", result);
+ dev_err(&port->dev, "setting dtr failed (error = %d)\n", result);
/*--6: raise the rts */
dbg("%s:raising rts",__FUNCTION__);
@@ -295,7 +295,7 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp)
0,
200000);
if (result < 0)
- dev_err(&port->dev, "setting dtr failed (error = %d)", result);
+ dev_err(&port->dev, "setting dtr failed (error = %d)\n", result);
kfree(buf_flow_init);
return 0;
@@ -322,7 +322,7 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp)
0,
200000);
if (result < 0)
- dev_err(&port->dev, "dropping dtr failed (error = %d)", result);
+ dev_err(&port->dev, "dropping dtr failed (error = %d)\n", result);
/*--2: drop the rts */
dbg("%s:dropping rts",__FUNCTION__);
@@ -334,7 +334,7 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp)
0,
200000);
if (result < 0)
- dev_err(&port->dev, "dropping rts failed (error = %d)", result);
+ dev_err(&port->dev, "dropping rts failed (error = %d)\n", result);
/*--3: purge */
@@ -347,7 +347,7 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp)
0,
200000);
if (result < 0)
- dev_err(&port->dev, "purge failed (error = %d)", result);
+ dev_err(&port->dev, "purge failed (error = %d)\n", result);
/* send RXBULK_off (tell modem to stop transmitting bulk data on rx chan) */
@@ -361,7 +361,7 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp)
100000);
if (result < 0)
- dev_err(&port->dev, "Disabling bulk RxRead failed (error = %d)", result);
+ dev_err(&port->dev, "Disabling bulk RxRead failed (error = %d)\n", result);
/* shutdown any in-flight urbs that we know about */
usb_kill_urb(port->read_urb);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 5ab6a0c5ac5..6b803ab9854 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -504,11 +504,6 @@ static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_t
dbg("%s - port %d", __FUNCTION__, port->number);
- if ((!port->tty) || (!port->tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
-
baud = tty_get_baud_rate(port->tty);
/*
@@ -531,8 +526,6 @@ static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_t
default:
ir_baud = SPEED_9600;
baud = 9600;
- /* And once the new tty stuff is all done we need to
- call back to correct the baud bits */
}
if (xbof == -1)
@@ -562,6 +555,10 @@ static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_t
result = usb_submit_urb (port->write_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
+
+ /* Only speed changes are supported */
+ tty_termios_copy_hw(port->tty->termios, old_termios);
+ tty_encode_baud_rate(port->tty, baud, baud);
}
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index f2a6fce5de1..1f7ab15df36 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -278,29 +278,35 @@ static void keyspan_set_termios (struct usb_serial_port *port,
struct keyspan_port_private *p_priv;
const struct keyspan_device_details *d_details;
unsigned int cflag;
+ struct tty_struct *tty = port->tty;
dbg("%s", __FUNCTION__);
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
- cflag = port->tty->termios->c_cflag;
+ cflag = tty->termios->c_cflag;
device_port = port->number - port->serial->minor;
/* Baud rate calculation takes baud rate as an integer
so other rates can be generated if desired. */
- baud_rate = tty_get_baud_rate(port->tty);
+ baud_rate = tty_get_baud_rate(tty);
/* If no match or invalid, don't change */
- if (baud_rate >= 0
- && d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
+ if (d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
/* FIXME - more to do here to ensure rate changes cleanly */
+ /* FIXME - calcuate exact rate from divisor ? */
p_priv->baud = baud_rate;
- }
+ } else
+ baud_rate = tty_termios_baud_rate(old_termios);
+ tty_encode_baud_rate(tty, baud_rate, baud_rate);
/* set CTS/RTS handshake etc. */
p_priv->cflag = cflag;
p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none;
+ /* Mark/Space not supported */
+ tty->termios->c_cflag &= ~CMSPAR;
+
keyspan_send_setup(port, 0);
}
@@ -1209,20 +1215,18 @@ static int keyspan_chars_in_buffer (struct usb_serial_port *port)
static int keyspan_open (struct usb_serial_port *port, struct file *filp)
{
- struct keyspan_port_private *p_priv;
- struct keyspan_serial_private *s_priv;
- struct usb_serial *serial = port->serial;
+ struct keyspan_port_private *p_priv;
+ struct keyspan_serial_private *s_priv;
+ struct usb_serial *serial = port->serial;
const struct keyspan_device_details *d_details;
int i, err;
- int baud_rate, device_port;
struct urb *urb;
- unsigned int cflag;
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
-
- dbg("%s - port%d.", __FUNCTION__, port->number);
+
+ dbg("%s - port%d.", __FUNCTION__, port->number);
/* Set some sane defaults */
p_priv->rts_state = 1;
@@ -1243,7 +1247,7 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
urb->dev = serial->dev;
/* make sure endpoint data toggle is synchronized with the device */
-
+
usb_clear_halt(urb->dev, urb->pipe);
if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) {
@@ -1259,30 +1263,6 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0); */
}
- /* get the terminal config for the setup message now so we don't
- * need to send 2 of them */
-
- cflag = port->tty->termios->c_cflag;
- device_port = port->number - port->serial->minor;
-
- /* Baud rate calculation takes baud rate as an integer
- so other rates can be generated if desired. */
- baud_rate = tty_get_baud_rate(port->tty);
- /* If no match or invalid, leave as default */
- if (baud_rate >= 0
- && d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
- NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
- p_priv->baud = baud_rate;
- }
-
- /* set CTS/RTS handshake etc. */
- p_priv->cflag = cflag;
- p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none;
-
- keyspan_send_setup(port, 1);
- //mdelay(100);
- //keyspan_set_termios(port, NULL);
-
return (0);
}
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 5a4127e62c4..90e3216abd1 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -728,24 +728,32 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
#endif
}
- switch(cflag & CBAUD) {
- case B0: /* handled below */
+ switch(tty_get_baud_rate(port->tty)) {
+ case 0: /* handled below */
break;
- case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200;
+ case 1200:
+ priv->cfg.baudrate = kl5kusb105a_sio_b1200;
break;
- case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400;
+ case 2400:
+ priv->cfg.baudrate = kl5kusb105a_sio_b2400;
break;
- case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800;
+ case 4800:
+ priv->cfg.baudrate = kl5kusb105a_sio_b4800;
break;
- case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+ case 9600:
+ priv->cfg.baudrate = kl5kusb105a_sio_b9600;
break;
- case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200;
+ case 19200:
+ priv->cfg.baudrate = kl5kusb105a_sio_b19200;
break;
- case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400;
+ case 38400:
+ priv->cfg.baudrate = kl5kusb105a_sio_b38400;
break;
- case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600;
+ case 57600:
+ priv->cfg.baudrate = kl5kusb105a_sio_b57600;
break;
- case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200;
+ case 115200:
+ priv->cfg.baudrate = kl5kusb105a_sio_b115200;
break;
default:
err("KLSI USB->Serial converter:"
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 02a86dbc0e9..aee450246bf 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -82,6 +82,7 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear);
static void kobil_read_int_callback( struct urb *urb );
static void kobil_write_callback( struct urb *purb );
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old);
static struct usb_device_id id_table [] = {
@@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = {
.attach = kobil_startup,
.shutdown = kobil_shutdown,
.ioctl = kobil_ioctl,
+ .set_termios = kobil_set_termios,
.tiocmget = kobil_tiocmget,
.tiocmset = kobil_tiocmset,
.open = kobil_open,
@@ -137,7 +139,6 @@ struct kobil_private {
int cur_pos; // index of the next char to send in buf
__u16 device_type;
int line_state;
- struct ktermios internal_termios;
};
@@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial)
static int kobil_open (struct usb_serial_port *port, struct file *filp)
{
- int i, result = 0;
+ int result = 0;
struct kobil_private *priv;
unsigned char *transfer_buffer;
int transfer_buffer_length = 8;
@@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
- // set up internal termios structure
- priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
- priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
- priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
- priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
-
- for (i=0; i<NCCS; i++) {
- priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
- }
-
// allocate memory for transfer buffer
transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
if (! transfer_buffer) {
@@ -607,102 +598,82 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
return (result < 0) ? result : 0;
}
-
-static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
- unsigned int cmd, unsigned long arg)
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old)
{
struct kobil_private * priv;
int result;
unsigned short urb_val = 0;
- unsigned char *transfer_buffer;
- int transfer_buffer_length = 8;
- char *settings;
- void __user *user_arg = (void __user *)arg;
+ int c_cflag = port->tty->termios->c_cflag;
+ speed_t speed;
+ void * settings;
priv = usb_get_serial_port_data(port);
- if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
+ if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
// This device doesn't support ioctl calls
- return 0;
- }
-
- switch (cmd) {
- case TCGETS: // 0x5401
- if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) {
- dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
- return -EFAULT;
- }
- if (kernel_termios_to_user_termios((struct ktermios __user *)arg,
- &priv->internal_termios))
- return -EFAULT;
- return 0;
-
- case TCSETS: // 0x5402
- if (!(port->tty->termios)) {
- dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
- return -ENOTTY;
- }
- if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) {
- dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
- return -EFAULT;
- }
- if (user_termios_to_kernel_termios(&priv->internal_termios,
- (struct ktermios __user *)arg))
- return -EFAULT;
-
- settings = kzalloc(50, GFP_KERNEL);
- if (! settings) {
- return -ENOBUFS;
- }
+ return;
- switch (priv->internal_termios.c_cflag & CBAUD) {
- case B1200:
+ switch (speed = tty_get_baud_rate(port->tty)) {
+ case 1200:
urb_val = SUSBCR_SBR_1200;
- strcat(settings, "1200 ");
break;
- case B9600:
default:
+ speed = 9600;
+ case 9600:
urb_val = SUSBCR_SBR_9600;
- strcat(settings, "9600 ");
break;
- }
+ }
+ urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
+
+ settings = kzalloc(50, GFP_KERNEL);
+ if (! settings)
+ return;
- urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
- strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit ");
+ sprintf(settings, "%d ", speed);
- if (priv->internal_termios.c_cflag & PARENB) {
- if (priv->internal_termios.c_cflag & PARODD) {
- urb_val |= SUSBCR_SPASB_OddParity;
- strcat(settings, "Odd Parity");
- } else {
- urb_val |= SUSBCR_SPASB_EvenParity;
- strcat(settings, "Even Parity");
- }
+ if (c_cflag & PARENB) {
+ if (c_cflag & PARODD) {
+ urb_val |= SUSBCR_SPASB_OddParity;
+ strcat(settings, "Odd Parity");
} else {
- urb_val |= SUSBCR_SPASB_NoParity;
- strcat(settings, "No Parity");
+ urb_val |= SUSBCR_SPASB_EvenParity;
+ strcat(settings, "Even Parity");
}
- dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings );
+ } else {
+ urb_val |= SUSBCR_SPASB_NoParity;
+ strcat(settings, "No Parity");
+ }
+ port->tty->termios->c_cflag &= ~CMSPAR;
+ tty_encode_baud_rate(port->tty, speed, speed);
+
+ result = usb_control_msg( port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0 ),
+ SUSBCRequest_SetBaudRateParityAndStopBits,
+ USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+ urb_val,
+ 0,
+ settings,
+ 0,
+ KOBIL_TIMEOUT
+ );
+ kfree(settings);
+}
- result = usb_control_msg( port->serial->dev,
- usb_rcvctrlpipe(port->serial->dev, 0 ),
- SUSBCRequest_SetBaudRateParityAndStopBits,
- USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
- urb_val,
- 0,
- settings,
- 0,
- KOBIL_TIMEOUT
- );
+static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct kobil_private * priv = usb_get_serial_port_data(port);
+ unsigned char *transfer_buffer;
+ int transfer_buffer_length = 8;
+ int result;
- dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
- kfree(settings);
+ if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
+ // This device doesn't support ioctl calls
return 0;
+ switch (cmd) {
case TCFLSH: // 0x540B
transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
- if (! transfer_buffer) {
+ if (! transfer_buffer)
return -ENOBUFS;
- }
result = usb_control_msg( port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0 ),
@@ -716,15 +687,13 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
);
dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
-
kfree(transfer_buffer);
- return ((result < 0) ? -EFAULT : 0);
-
+ return (result < 0) ? -EFAULT : 0;
+ default:
+ return -ENOIOCTLCMD;
}
- return -ENOIOCTLCMD;
}
-
static int __init kobil_init (void)
{
int retval;
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index e08c9bb403d..0dc99f75bb0 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -206,20 +206,20 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value
}
} else {
switch (value) {
- case 300: break;
- case 600: break;
- case 1200: break;
- case 2400: break;
- case 4800: break;
- case 9600: break;
- case 19200: break;
- case 38400: break;
- case 57600: break;
- case 115200: break;
- default:
- err("MCT USB-RS232: unsupported baudrate request 0x%x,"
- " using default of B9600", value);
- value = 9600;
+ case 300: break;
+ case 600: break;
+ case 1200: break;
+ case 2400: break;
+ case 4800: break;
+ case 9600: break;
+ case 19200: break;
+ case 38400: break;
+ case 57600: break;
+ case 115200: break;
+ default:
+ err("MCT USB-RS232: unsupported baudrate request 0x%x,"
+ " using default of B9600", value);
+ value = 9600;
}
return 115200/value;
}
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 01e811becec..e02c198016b 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -478,7 +478,7 @@ static int mos7720_open(struct usb_serial_port *port, struct file * filp)
response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL);
if (response)
dev_err(&port->dev,
- "%s - Error %d submitting control urb",
+ "%s - Error %d submitting control urb\n",
__FUNCTION__, response);
}
@@ -492,7 +492,7 @@ static int mos7720_open(struct usb_serial_port *port, struct file * filp)
response = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (response)
dev_err(&port->dev,
- "%s - Error %d submitting read urb", __FUNCTION__, response);
+ "%s - Error %d submitting read urb\n", __FUNCTION__, response);
/* initialize our icount structure */
memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount));
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index f76480f1455..a5ced7e08cb 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1977,11 +1977,6 @@ static void mos7840_change_port_settings(struct moschip_port *mos7840_port,
tty = mos7840_port->port->tty;
- if ((!tty) || (!tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
-
dbg("%s", "Entering .......... \n");
lData = LCR_BITS_8;
@@ -2151,11 +2146,6 @@ static void mos7840_set_termios(struct usb_serial_port *port,
tty = port->tty;
- if (!port->tty || !port->tty->termios) {
- dbg("%s - no tty or termios", __FUNCTION__);
- return;
- }
-
if (!mos7840_port->open) {
dbg("%s - port not opened", __FUNCTION__);
return;
@@ -2165,19 +2155,10 @@ static void mos7840_set_termios(struct usb_serial_port *port,
cflag = tty->termios->c_cflag;
- if (!cflag) {
- dbg("%s %s\n", __FUNCTION__, "cflag is NULL");
- return;
- }
-
dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
-
- if (old_termios) {
- dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
- old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
- }
-
+ dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+ old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
dbg("%s - port %d", __FUNCTION__, port->number);
/* change the port settings to the new ones specified */
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index a18659e0700..4590124cf88 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -172,6 +172,8 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2110) }, /* Novatel Merlin ES620 / Merlin ES720 / Ovation U720 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2130) }, /* Novatel Merlin ES620 SM Bus */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2410) }, /* Novatel EU740 */
+ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x4100) }, /* Novatel U727 */
+ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x4400) }, /* Novatel MC950 */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8114) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite EV620 CDMA/EV-DO */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8115) }, /* Dell Wireless 5500 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8116) }, /* Dell Wireless 5505 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */
@@ -311,7 +313,8 @@ static void option_set_termios(struct usb_serial_port *port,
struct ktermios *old_termios)
{
dbg("%s", __FUNCTION__);
-
+ /* Doesn't support option setting */
+ tty_termios_copy_hw(port->tty->termios, old_termios);
option_send_setup(port);
}
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 64f3f66a7a3..eea226ae37b 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -256,7 +256,7 @@ static void setup_line(struct work_struct *work)
100);
if (result != OTI6858_CTRL_PKT_SIZE) {
- dev_err(&port->dev, "%s(): error reading status", __FUNCTION__);
+ dev_err(&port->dev, "%s(): error reading status\n", __FUNCTION__);
kfree(new_setup);
/* we will try again */
schedule_delayed_work(&priv->delayed_setup_work, msecs_to_jiffies(2));
@@ -1144,7 +1144,7 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
if (size == 0)
return NULL;
- pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+ pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
if (pb == NULL)
return NULL;
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index f9f85f56f0d..2cd3f1d4b68 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -56,6 +56,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
+ { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
@@ -73,6 +74,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
+ { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
@@ -469,16 +471,13 @@ static void pl2303_set_termios(struct usb_serial_port *port,
dbg("%s - port %d", __FUNCTION__, port->number);
- if ((!port->tty) || (!port->tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
-
spin_lock_irqsave(&priv->lock, flags);
if (!priv->termios_initialized) {
*(port->tty->termios) = tty_std_termios;
port->tty->termios->c_cflag = B9600 | CS8 | CREAD |
HUPCL | CLOCAL;
+ port->tty->termios->c_ispeed = 9600;
+ port->tty->termios->c_ospeed = 9600;
priv->termios_initialized = 1;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -595,6 +594,10 @@ static void pl2303_set_termios(struct usb_serial_port *port,
dbg ("0x40:0x1:0x0:0x0 %d", i);
}
+ /* FIXME: Need to read back resulting baud rate */
+ if (baud)
+ tty_encode_baud_rate(port->tty, baud, baud);
+
kfree(buf);
}
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index f9a71d0c102..ed603e3decd 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -20,6 +20,7 @@
#define IODATA_VENDOR_ID 0x04bb
#define IODATA_PRODUCT_ID 0x0a03
+#define IODATA_PRODUCT_ID_RSAQ5 0x0a0e
#define ELCOM_VENDOR_ID 0x056e
#define ELCOM_PRODUCT_ID 0x5003
@@ -59,6 +60,7 @@
#define SIEMENS_PRODUCT_ID_SX1 0x0001
#define SIEMENS_PRODUCT_ID_X65 0x0003
#define SIEMENS_PRODUCT_ID_X75 0x0004
+#define SIEMENS_PRODUCT_ID_EF81 0x0005
#define SYNTECH_VENDOR_ID 0x0745
#define SYNTECH_PRODUCT_ID 0x0001
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 51669b7622b..4e6dcc199be 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -90,18 +90,12 @@ MODULE_AUTHOR (DRIVER_AUTHOR);
MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_LICENSE("GPL");
-#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT)
-#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT"
-#endif
-
-#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR)
static __u16 vendor; // no default
static __u16 product; // no default
module_param(vendor, ushort, 0);
MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)");
module_param(product, ushort, 0);
MODULE_PARM_DESC(product, "User specified USB idProduct (required)");
-#endif
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
@@ -145,11 +139,6 @@ static struct usb_device_id id_table[] = {
{MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie
{MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Collie
{MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, // Sharp tmp
-#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR)
- {MY_USB_DEVICE
- (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS,
- LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
-#endif
// extra null entry for module
// vendor/produc parameters
{MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 0bb8de4cc52..833f6e1e372 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -48,7 +48,7 @@ enum devicetype {
static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
{
int result;
- dev_dbg(&udev->dev, "%s", "SET POWER STATE");
+ dev_dbg(&udev->dev, "%s", "SET POWER STATE\n");
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x00, /* __u8 request */
0x40, /* __u8 request type */
@@ -63,7 +63,7 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode)
{
int result;
- dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH");
+ dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH\n");
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
SWIMS_USB_REQUEST_SetMode, /* __u8 request */
SWIMS_USB_REQUEST_TYPE_SetMode, /* __u8 request type */
@@ -224,7 +224,7 @@ static void sierra_set_termios(struct usb_serial_port *port,
struct ktermios *old_termios)
{
dbg("%s", __FUNCTION__);
-
+ tty_termios_copy_hw(port->tty->termios, old_termios);
sierra_send_setup(port);
}
@@ -397,7 +397,7 @@ static void sierra_indat_callback(struct urb *urb)
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
dev_err(&port->dev, "resubmit read urb failed."
- "(%d)", err);
+ "(%d)\n", err);
}
}
return;
@@ -525,7 +525,7 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
result = usb_submit_urb(urb, GFP_KERNEL);
if (result) {
- dev_err(&port->dev, "submit urb %d failed (%d) %d",
+ dev_err(&port->dev, "submit urb %d failed (%d) %d\n",
i, result, urb->transfer_buffer_length);
}
}
@@ -538,7 +538,7 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
if (port->interrupt_in_urb) {
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result)
- dev_err(&port->dev, "submit irq_in urb failed %d",
+ dev_err(&port->dev, "submit irq_in urb failed %d\n",
result);
}
return 0;
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index f98626ae75f..1f0149495fb 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -214,13 +214,13 @@ static int debug;
static int low_latency = TI_DEFAULT_LOW_LATENCY;
static int closing_wait = TI_DEFAULT_CLOSING_WAIT;
static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT];
-static int vendor_3410_count;
+static unsigned int vendor_3410_count;
static ushort product_3410[TI_EXTRA_VID_PID_COUNT];
-static int product_3410_count;
+static unsigned int product_3410_count;
static ushort vendor_5052[TI_EXTRA_VID_PID_COUNT];
-static int vendor_5052_count;
+static unsigned int vendor_5052_count;
static ushort product_5052[TI_EXTRA_VID_PID_COUNT];
-static int product_5052_count;
+static unsigned int product_5052_count;
/* supported devices */
/* the array dimension is the number of default entries plus */
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 9bf01a5efc8..497e29a700c 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -429,6 +429,8 @@ static void serial_set_termios (struct tty_struct *tty, struct ktermios * old)
/* pass on to the driver specific version of this function if it is available */
if (port->serial->type->set_termios)
port->serial->type->set_termios(port, old);
+ else
+ tty_termios_copy_hw(tty->termios, old);
}
static void serial_break (struct tty_struct *tty, int break_state)
@@ -578,6 +580,17 @@ static void kill_traffic(struct usb_serial_port *port)
{
usb_kill_urb(port->read_urb);
usb_kill_urb(port->write_urb);
+ /*
+ * This is tricky.
+ * Some drivers submit the read_urb in the
+ * handler for the write_urb or vice versa
+ * this order determines the order in which
+ * usb_kill_urb() must be used to reliably
+ * kill the URBs. As it is unknown here,
+ * both orders must be used in turn.
+ * The call below is not redundant.
+ */
+ usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_out_urb);
}
@@ -651,16 +664,14 @@ exit:
static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
{
- struct list_head *p;
const struct usb_device_id *id;
- struct usb_serial_driver *t;
+ struct usb_serial_driver *drv;
/* Check if the usb id matches a known device */
- list_for_each(p, &usb_serial_driver_list) {
- t = list_entry(p, struct usb_serial_driver, driver_list);
- id = get_iface_id(t, iface);
+ list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
+ id = get_iface_id(drv, iface);
if (id)
- return t;
+ return drv;
}
return NULL;
@@ -800,9 +811,6 @@ int usb_serial_probe(struct usb_interface *interface,
/* END HORRIBLE HACK FOR PL2303 */
#endif
- /* found all that we need */
- dev_info(&interface->dev, "%s converter detected\n", type->description);
-
#ifdef CONFIG_USB_SERIAL_GENERIC
if (type == &usb_serial_generic_device) {
num_ports = num_bulk_out;
@@ -836,6 +844,24 @@ int usb_serial_probe(struct usb_interface *interface,
serial->num_interrupt_in = num_interrupt_in;
serial->num_interrupt_out = num_interrupt_out;
+ /* check that the device meets the driver's requirements */
+ if ((type->num_interrupt_in != NUM_DONT_CARE &&
+ type->num_interrupt_in != num_interrupt_in)
+ || (type->num_interrupt_out != NUM_DONT_CARE &&
+ type->num_interrupt_out != num_interrupt_out)
+ || (type->num_bulk_in != NUM_DONT_CARE &&
+ type->num_bulk_in != num_bulk_in)
+ || (type->num_bulk_out != NUM_DONT_CARE &&
+ type->num_bulk_out != num_bulk_out)) {
+ dbg("wrong number of endpoints");
+ kfree(serial);
+ return -EIO;
+ }
+
+ /* found all that we need */
+ dev_info(&interface->dev, "%s converter detected\n",
+ type->description);
+
/* create our ports, we need as many as the max endpoints */
/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
max_endpoints = max(num_bulk_in, num_bulk_out);
@@ -1097,7 +1123,9 @@ int usb_serial_resume(struct usb_interface *intf)
{
struct usb_serial *serial = usb_get_intfdata(intf);
- return serial->type->resume(serial);
+ if (serial->type->resume)
+ return serial->type->resume(serial);
+ return 0;
}
EXPORT_SYMBOL(usb_serial_resume);
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 30e08c0bcdc..7ee087fed91 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -46,7 +46,6 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id
static int visor_calc_num_ports(struct usb_serial *serial);
static void visor_shutdown (struct usb_serial *serial);
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
static void visor_write_bulk_callback (struct urb *urb);
static void visor_read_bulk_callback (struct urb *urb);
static void visor_read_int_callback (struct urb *urb);
@@ -203,7 +202,6 @@ static struct usb_serial_driver handspring_device = {
.calc_num_ports = visor_calc_num_ports,
.shutdown = visor_shutdown,
.ioctl = visor_ioctl,
- .set_termios = visor_set_termios,
.write = visor_write,
.write_room = visor_write_room,
.chars_in_buffer = visor_chars_in_buffer,
@@ -234,7 +232,6 @@ static struct usb_serial_driver clie_5_device = {
.calc_num_ports = visor_calc_num_ports,
.shutdown = visor_shutdown,
.ioctl = visor_ioctl,
- .set_termios = visor_set_termios,
.write = visor_write,
.write_room = visor_write_room,
.chars_in_buffer = visor_chars_in_buffer,
@@ -262,7 +259,6 @@ static struct usb_serial_driver clie_3_5_device = {
.unthrottle = visor_unthrottle,
.attach = clie_3_5_startup,
.ioctl = visor_ioctl,
- .set_termios = visor_set_termios,
.write = visor_write,
.write_room = visor_write_room,
.chars_in_buffer = visor_chars_in_buffer,
@@ -936,66 +932,6 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign
return -ENOIOCTLCMD;
}
-
-/* This function is all nice and good, but we don't change anything based on it :) */
-static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
-{
- unsigned int cflag;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if ((!port->tty) || (!port->tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
-
- cflag = port->tty->termios->c_cflag;
-
- /* get the byte size */
- switch (cflag & CSIZE) {
- case CS5: dbg("%s - data bits = 5", __FUNCTION__); break;
- case CS6: dbg("%s - data bits = 6", __FUNCTION__); break;
- case CS7: dbg("%s - data bits = 7", __FUNCTION__); break;
- default:
- case CS8: dbg("%s - data bits = 8", __FUNCTION__); break;
- }
-
- /* determine the parity */
- if (cflag & PARENB)
- if (cflag & PARODD)
- dbg("%s - parity = odd", __FUNCTION__);
- else
- dbg("%s - parity = even", __FUNCTION__);
- else
- dbg("%s - parity = none", __FUNCTION__);
-
- /* figure out the stop bits requested */
- if (cflag & CSTOPB)
- dbg("%s - stop bits = 2", __FUNCTION__);
- else
- dbg("%s - stop bits = 1", __FUNCTION__);
-
-
- /* figure out the flow control settings */
- if (cflag & CRTSCTS)
- dbg("%s - RTS/CTS is enabled", __FUNCTION__);
- else
- dbg("%s - RTS/CTS is disabled", __FUNCTION__);
-
- /* determine software flow control */
- if (I_IXOFF(port->tty))
- dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x",
- __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty));
- else
- dbg("%s - XON/XOFF is disabled", __FUNCTION__);
-
- /* get the baud rate wanted */
- dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty));
-
- return;
-}
-
-
static int __init visor_init (void)
{
int i, retval;
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index cc8b44c0871..ee5dd8b5a71 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -885,16 +885,7 @@ static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, un
static void whiteheat_set_termios(struct usb_serial_port *port, struct ktermios *old_termios)
{
dbg("%s -port %d", __FUNCTION__, port->number);
-
- if ((!port->tty) || (!port->tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
- goto exit;
- }
-
firm_setup_port(port);
-
-exit:
- return;
}
@@ -1244,6 +1235,8 @@ static int firm_setup_port(struct usb_serial_port *port) {
port_settings.baud = tty_get_baud_rate(port->tty);
dbg("%s - baud rate = %d", __FUNCTION__, port_settings.baud);
+ /* fixme: should set validated settings */
+ tty_encode_baud_rate(port->tty, port_settings.baud, port_settings.baud);
/* handle any settings that aren't specified in the tty structure */
port_settings.lloop = 0;
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index fe2c4cd53f5..7e53333be01 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -48,7 +48,6 @@ config USB_STORAGE_FREECOM
config USB_STORAGE_ISD200
bool "ISD-200 USB/ATA Bridge support"
depends on USB_STORAGE
- depends on BLK_DEV_IDE=y || BLK_DEV_IDE=USB_STORAGE
---help---
Say Y here if you want to use USB Mass Store devices based
on the In-Systems Design ISD-200 USB/ATA bridge.
diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c
index 4d3cbb12b71..8d3711a7ff0 100644
--- a/drivers/usb/storage/alauda.c
+++ b/drivers/usb/storage/alauda.c
@@ -798,12 +798,13 @@ static int alauda_read_data(struct us_data *us, unsigned long address,
{
unsigned char *buffer;
u16 lba, max_lba;
- unsigned int page, len, index, offset;
+ unsigned int page, len, offset;
unsigned int blockshift = MEDIA_INFO(us).blockshift;
unsigned int pageshift = MEDIA_INFO(us).pageshift;
unsigned int blocksize = MEDIA_INFO(us).blocksize;
unsigned int pagesize = MEDIA_INFO(us).pagesize;
unsigned int uzonesize = MEDIA_INFO(us).uzonesize;
+ struct scatterlist *sg;
int result;
/*
@@ -827,7 +828,8 @@ static int alauda_read_data(struct us_data *us, unsigned long address,
max_lba = MEDIA_INFO(us).capacity >> (blockshift + pageshift);
result = USB_STOR_TRANSPORT_GOOD;
- index = offset = 0;
+ offset = 0;
+ sg = NULL;
while (sectors > 0) {
unsigned int zone = lba / uzonesize; /* integer division */
@@ -873,7 +875,7 @@ static int alauda_read_data(struct us_data *us, unsigned long address,
/* Store the data in the transfer buffer */
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &index, &offset, TO_XFER_BUF);
+ &sg, &offset, TO_XFER_BUF);
page = 0;
lba++;
@@ -891,11 +893,12 @@ static int alauda_write_data(struct us_data *us, unsigned long address,
unsigned int sectors)
{
unsigned char *buffer, *blockbuffer;
- unsigned int page, len, index, offset;
+ unsigned int page, len, offset;
unsigned int blockshift = MEDIA_INFO(us).blockshift;
unsigned int pageshift = MEDIA_INFO(us).pageshift;
unsigned int blocksize = MEDIA_INFO(us).blocksize;
unsigned int pagesize = MEDIA_INFO(us).pagesize;
+ struct scatterlist *sg;
u16 lba, max_lba;
int result;
@@ -929,7 +932,8 @@ static int alauda_write_data(struct us_data *us, unsigned long address,
max_lba = MEDIA_INFO(us).capacity >> (pageshift + blockshift);
result = USB_STOR_TRANSPORT_GOOD;
- index = offset = 0;
+ offset = 0;
+ sg = NULL;
while (sectors > 0) {
/* Write as many sectors as possible in this block */
@@ -946,7 +950,7 @@ static int alauda_write_data(struct us_data *us, unsigned long address,
/* Get the data from the transfer buffer */
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &index, &offset, FROM_XFER_BUF);
+ &sg, &offset, FROM_XFER_BUF);
result = alauda_write_lba(us, lba, page, pages, buffer,
blockbuffer);
diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
index c87ad1bae1d..579e9f52053 100644
--- a/drivers/usb/storage/datafab.c
+++ b/drivers/usb/storage/datafab.c
@@ -98,7 +98,8 @@ static int datafab_read_data(struct us_data *us,
unsigned char thistime;
unsigned int totallen, alloclen;
int len, result;
- unsigned int sg_idx = 0, sg_offset = 0;
+ unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
// we're working in LBA mode. according to the ATA spec,
// we can support up to 28-bit addressing. I don't know if Datafab
@@ -155,7 +156,7 @@ static int datafab_read_data(struct us_data *us,
// Store the data in the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &sg_idx, &sg_offset, TO_XFER_BUF);
+ &sg, &sg_offset, TO_XFER_BUF);
sector += thistime;
totallen -= len;
@@ -181,7 +182,8 @@ static int datafab_write_data(struct us_data *us,
unsigned char thistime;
unsigned int totallen, alloclen;
int len, result;
- unsigned int sg_idx = 0, sg_offset = 0;
+ unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
// we're working in LBA mode. according to the ATA spec,
// we can support up to 28-bit addressing. I don't know if Datafab
@@ -217,7 +219,7 @@ static int datafab_write_data(struct us_data *us,
// Get the data from the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &sg_idx, &sg_offset, FROM_XFER_BUF);
+ &sg, &sg_offset, FROM_XFER_BUF);
command[0] = 0;
command[1] = thistime;
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index 3a41740cad9..ee5b42aa536 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -90,3 +90,17 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
return (res ? -1 : 0);
}
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us)
+{
+ int result;
+
+ us->iobuf[0] = 0x1;
+ result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+ USB_REQ_SET_FEATURE,
+ USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+ 0x01, 0x0, us->iobuf, 0x1, 1000);
+ US_DEBUGP("usb_control_msg performing result is %d\n", result);
+ return (result ? 0 : -1);
+}
diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h
index e2967a4d48a..ad3ffd4236c 100644
--- a/drivers/usb/storage/initializers.h
+++ b/drivers/usb/storage/initializers.h
@@ -47,3 +47,6 @@ int usb_stor_euscsi_init(struct us_data *us);
/* This function is required to activate all four slots on the UCR-61S2B
* flash reader */
int usb_stor_ucr61s2b_init(struct us_data *us);
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us);
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index 6831dca93c1..49ba6c0ff1e 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -3,7 +3,7 @@
* $Id: isd200.c,v 1.16 2002/04/22 03:39:43 mdharm Exp $
*
* Current development and maintenance:
- * (C) 2001-2002 Björn Stenberg (bjorn@haxx.se)
+ * (C) 2001-2002 Björn Stenberg (bjorn@haxx.se)
*
* Developed with the assistance of:
* (C) 2002 Alan Stern <stern@rowland.org>
@@ -977,6 +977,109 @@ static int isd200_manual_enum(struct us_data *us)
return(retStatus);
}
+/*
+ * We are the last non IDE user of the legacy IDE ident structures
+ * and we thus want to keep a private copy of this function so the
+ * driver can be used without the obsolete drivers/ide layer
+ */
+
+static void isd200_fix_driveid (struct hd_driveid *id)
+{
+#ifndef __LITTLE_ENDIAN
+# ifdef __BIG_ENDIAN
+ int i;
+ u16 *stringcast;
+
+ id->config = __le16_to_cpu(id->config);
+ id->cyls = __le16_to_cpu(id->cyls);
+ id->reserved2 = __le16_to_cpu(id->reserved2);
+ id->heads = __le16_to_cpu(id->heads);
+ id->track_bytes = __le16_to_cpu(id->track_bytes);
+ id->sector_bytes = __le16_to_cpu(id->sector_bytes);
+ id->sectors = __le16_to_cpu(id->sectors);
+ id->vendor0 = __le16_to_cpu(id->vendor0);
+ id->vendor1 = __le16_to_cpu(id->vendor1);
+ id->vendor2 = __le16_to_cpu(id->vendor2);
+ stringcast = (u16 *)&id->serial_no[0];
+ for (i = 0; i < (20/2); i++)
+ stringcast[i] = __le16_to_cpu(stringcast[i]);
+ id->buf_type = __le16_to_cpu(id->buf_type);
+ id->buf_size = __le16_to_cpu(id->buf_size);
+ id->ecc_bytes = __le16_to_cpu(id->ecc_bytes);
+ stringcast = (u16 *)&id->fw_rev[0];
+ for (i = 0; i < (8/2); i++)
+ stringcast[i] = __le16_to_cpu(stringcast[i]);
+ stringcast = (u16 *)&id->model[0];
+ for (i = 0; i < (40/2); i++)
+ stringcast[i] = __le16_to_cpu(stringcast[i]);
+ id->dword_io = __le16_to_cpu(id->dword_io);
+ id->reserved50 = __le16_to_cpu(id->reserved50);
+ id->field_valid = __le16_to_cpu(id->field_valid);
+ id->cur_cyls = __le16_to_cpu(id->cur_cyls);
+ id->cur_heads = __le16_to_cpu(id->cur_heads);
+ id->cur_sectors = __le16_to_cpu(id->cur_sectors);
+ id->cur_capacity0 = __le16_to_cpu(id->cur_capacity0);
+ id->cur_capacity1 = __le16_to_cpu(id->cur_capacity1);
+ id->lba_capacity = __le32_to_cpu(id->lba_capacity);
+ id->dma_1word = __le16_to_cpu(id->dma_1word);
+ id->dma_mword = __le16_to_cpu(id->dma_mword);
+ id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+ id->eide_dma_min = __le16_to_cpu(id->eide_dma_min);
+ id->eide_dma_time = __le16_to_cpu(id->eide_dma_time);
+ id->eide_pio = __le16_to_cpu(id->eide_pio);
+ id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+ for (i = 0; i < 2; ++i)
+ id->words69_70[i] = __le16_to_cpu(id->words69_70[i]);
+ for (i = 0; i < 4; ++i)
+ id->words71_74[i] = __le16_to_cpu(id->words71_74[i]);
+ id->queue_depth = __le16_to_cpu(id->queue_depth);
+ for (i = 0; i < 4; ++i)
+ id->words76_79[i] = __le16_to_cpu(id->words76_79[i]);
+ id->major_rev_num = __le16_to_cpu(id->major_rev_num);
+ id->minor_rev_num = __le16_to_cpu(id->minor_rev_num);
+ id->command_set_1 = __le16_to_cpu(id->command_set_1);
+ id->command_set_2 = __le16_to_cpu(id->command_set_2);
+ id->cfsse = __le16_to_cpu(id->cfsse);
+ id->cfs_enable_1 = __le16_to_cpu(id->cfs_enable_1);
+ id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2);
+ id->csf_default = __le16_to_cpu(id->csf_default);
+ id->dma_ultra = __le16_to_cpu(id->dma_ultra);
+ id->trseuc = __le16_to_cpu(id->trseuc);
+ id->trsEuc = __le16_to_cpu(id->trsEuc);
+ id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues);
+ id->mprc = __le16_to_cpu(id->mprc);
+ id->hw_config = __le16_to_cpu(id->hw_config);
+ id->acoustic = __le16_to_cpu(id->acoustic);
+ id->msrqs = __le16_to_cpu(id->msrqs);
+ id->sxfert = __le16_to_cpu(id->sxfert);
+ id->sal = __le16_to_cpu(id->sal);
+ id->spg = __le32_to_cpu(id->spg);
+ id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2);
+ for (i = 0; i < 22; i++)
+ id->words104_125[i] = __le16_to_cpu(id->words104_125[i]);
+ id->last_lun = __le16_to_cpu(id->last_lun);
+ id->word127 = __le16_to_cpu(id->word127);
+ id->dlf = __le16_to_cpu(id->dlf);
+ id->csfo = __le16_to_cpu(id->csfo);
+ for (i = 0; i < 26; i++)
+ id->words130_155[i] = __le16_to_cpu(id->words130_155[i]);
+ id->word156 = __le16_to_cpu(id->word156);
+ for (i = 0; i < 3; i++)
+ id->words157_159[i] = __le16_to_cpu(id->words157_159[i]);
+ id->cfa_power = __le16_to_cpu(id->cfa_power);
+ for (i = 0; i < 14; i++)
+ id->words161_175[i] = __le16_to_cpu(id->words161_175[i]);
+ for (i = 0; i < 31; i++)
+ id->words176_205[i] = __le16_to_cpu(id->words176_205[i]);
+ for (i = 0; i < 48; i++)
+ id->words206_254[i] = __le16_to_cpu(id->words206_254[i]);
+ id->integrity_word = __le16_to_cpu(id->integrity_word);
+# else
+# error "Please fix <asm/byteorder.h>"
+# endif
+#endif
+}
+
/**************************************************************************
* isd200_get_inquiry_data
@@ -1018,7 +1121,7 @@ static int isd200_get_inquiry_data( struct us_data *us )
int i;
__be16 *src;
__u16 *dest;
- ide_fix_driveid(id);
+ isd200_fix_driveid(id);
US_DEBUGP(" Identify Data Structure:\n");
US_DEBUGP(" config = 0x%x\n", id->config);
diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
index 003fcf54588..61097cbb158 100644
--- a/drivers/usb/storage/jumpshot.c
+++ b/drivers/usb/storage/jumpshot.c
@@ -119,7 +119,8 @@ static int jumpshot_read_data(struct us_data *us,
unsigned char thistime;
unsigned int totallen, alloclen;
int len, result;
- unsigned int sg_idx = 0, sg_offset = 0;
+ unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
// we're working in LBA mode. according to the ATA spec,
// we can support up to 28-bit addressing. I don't know if Jumpshot
@@ -170,7 +171,7 @@ static int jumpshot_read_data(struct us_data *us,
// Store the data in the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &sg_idx, &sg_offset, TO_XFER_BUF);
+ &sg, &sg_offset, TO_XFER_BUF);
sector += thistime;
totallen -= len;
@@ -195,7 +196,8 @@ static int jumpshot_write_data(struct us_data *us,
unsigned char thistime;
unsigned int totallen, alloclen;
int len, result, waitcount;
- unsigned int sg_idx = 0, sg_offset = 0;
+ unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
// we're working in LBA mode. according to the ATA spec,
// we can support up to 28-bit addressing. I don't know if Jumpshot
@@ -225,7 +227,7 @@ static int jumpshot_write_data(struct us_data *us,
// Get the data from the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &sg_idx, &sg_offset, FROM_XFER_BUF);
+ &sg, &sg_offset, FROM_XFER_BUF);
command[0] = 0;
command[1] = thistime;
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
index 06d1107dbd4..55b952084f0 100644
--- a/drivers/usb/storage/libusual.c
+++ b/drivers/usb/storage/libusual.c
@@ -30,7 +30,7 @@ static atomic_t usu_bias = ATOMIC_INIT(USB_US_DEFAULT_BIAS);
#define BIAS_NAME_SIZE (sizeof("usb-storage"))
static const char *bias_names[3] = { "none", "usb-storage", "ub" };
-static DECLARE_MUTEX_LOCKED(usu_init_notify);
+static struct semaphore usu_init_notify;
static DECLARE_COMPLETION(usu_end_notify);
static atomic_t total_threads = ATOMIC_INIT(0);
@@ -204,6 +204,8 @@ static int __init usb_usual_init(void)
{
int rc;
+ sema_init(&usu_init_notify, 0);
+
rc = usb_register(&usu_driver);
up(&usu_init_notify);
return rc;
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index 9ad30428d2d..889622baac2 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -157,7 +157,7 @@ void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
* pick up from where this one left off. */
unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
- unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index,
+ unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr,
unsigned int *offset, enum xfer_buf_dir dir)
{
unsigned int cnt;
@@ -184,17 +184,18 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
* located in high memory -- then kmap() will map it to a temporary
* position in the kernel's virtual address space. */
} else {
- struct scatterlist *sg =
- (struct scatterlist *) srb->request_buffer
- + *index;
+ struct scatterlist *sg = *sgptr;
+
+ if (!sg)
+ sg = (struct scatterlist *) srb->request_buffer;
/* This loop handles a single s-g list entry, which may
* include multiple pages. Find the initial page structure
* and the starting offset within the page, and update
* the *offset and *index values for the next loop. */
cnt = 0;
- while (cnt < buflen && *index < srb->use_sg) {
- struct page *page = sg->page +
+ while (cnt < buflen) {
+ struct page *page = sg_page(sg) +
((sg->offset + *offset) >> PAGE_SHIFT);
unsigned int poff =
(sg->offset + *offset) & (PAGE_SIZE-1);
@@ -209,8 +210,7 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
/* Transfer continues to next s-g entry */
*offset = 0;
- ++*index;
- ++sg;
+ sg = sg_next(sg);
}
/* Transfer the data for all the pages in this
@@ -234,6 +234,7 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
sglen -= plen;
}
}
+ *sgptr = sg;
}
/* Return the amount actually transferred */
@@ -245,9 +246,10 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
void usb_stor_set_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb)
{
- unsigned int index = 0, offset = 0;
+ unsigned int offset = 0;
+ struct scatterlist *sg = NULL;
- usb_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset,
+ usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
TO_XFER_BUF);
if (buflen < srb->request_bufflen)
srb->resid = srb->request_bufflen - buflen;
diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h
index 845bed4b803..8737a36891c 100644
--- a/drivers/usb/storage/protocol.h
+++ b/drivers/usb/storage/protocol.h
@@ -52,7 +52,7 @@ extern void usb_stor_transparent_scsi_command(struct scsi_cmnd*,
enum xfer_buf_dir {TO_XFER_BUF, FROM_XFER_BUF};
extern unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
- unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index,
+ unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **,
unsigned int *offset, enum xfer_buf_dir dir);
extern void usb_stor_set_xfer_buf(unsigned char *buffer,
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index b2ed2a3e6fc..b12202c5da2 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -705,7 +705,8 @@ sddr09_read_data(struct us_data *us,
unsigned char *buffer;
unsigned int lba, maxlba, pba;
unsigned int page, pages;
- unsigned int len, index, offset;
+ unsigned int len, offset;
+ struct scatterlist *sg;
int result;
// Figure out the initial LBA and page
@@ -730,7 +731,8 @@ sddr09_read_data(struct us_data *us,
// contiguous LBA's. Another exercise left to the student.
result = 0;
- index = offset = 0;
+ offset = 0;
+ sg = NULL;
while (sectors > 0) {
@@ -777,7 +779,7 @@ sddr09_read_data(struct us_data *us,
// Store the data in the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &index, &offset, TO_XFER_BUF);
+ &sg, &offset, TO_XFER_BUF);
page = 0;
lba++;
@@ -931,7 +933,8 @@ sddr09_write_data(struct us_data *us,
unsigned int pagelen, blocklen;
unsigned char *blockbuffer;
unsigned char *buffer;
- unsigned int len, index, offset;
+ unsigned int len, offset;
+ struct scatterlist *sg;
int result;
// Figure out the initial LBA and page
@@ -968,7 +971,8 @@ sddr09_write_data(struct us_data *us,
}
result = 0;
- index = offset = 0;
+ offset = 0;
+ sg = NULL;
while (sectors > 0) {
@@ -987,7 +991,7 @@ sddr09_write_data(struct us_data *us,
// Get the data from the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &index, &offset, FROM_XFER_BUF);
+ &sg, &offset, FROM_XFER_BUF);
result = sddr09_write_lba(us, lba, page, pages,
buffer, blockbuffer);
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
index 0b1b5b59ca7..d43a3415e12 100644
--- a/drivers/usb/storage/sddr55.c
+++ b/drivers/usb/storage/sddr55.c
@@ -167,7 +167,8 @@ static int sddr55_read_data(struct us_data *us,
unsigned long address;
unsigned short pages;
- unsigned int len, index, offset;
+ unsigned int len, offset;
+ struct scatterlist *sg;
// Since we only read in one block at a time, we have to create
// a bounce buffer and move the data a piece at a time between the
@@ -178,7 +179,8 @@ static int sddr55_read_data(struct us_data *us,
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR; /* out of memory */
- index = offset = 0;
+ offset = 0;
+ sg = NULL;
while (sectors>0) {
@@ -255,7 +257,7 @@ static int sddr55_read_data(struct us_data *us,
// Store the data in the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &index, &offset, TO_XFER_BUF);
+ &sg, &offset, TO_XFER_BUF);
page = 0;
lba++;
@@ -287,7 +289,8 @@ static int sddr55_write_data(struct us_data *us,
unsigned short pages;
int i;
- unsigned int len, index, offset;
+ unsigned int len, offset;
+ struct scatterlist *sg;
/* check if we are allowed to write */
if (info->read_only || info->force_read_only) {
@@ -304,7 +307,8 @@ static int sddr55_write_data(struct us_data *us,
buffer = kmalloc(len, GFP_NOIO);
if (buffer == NULL)
return USB_STOR_TRANSPORT_ERROR;
- index = offset = 0;
+ offset = 0;
+ sg = NULL;
while (sectors > 0) {
@@ -322,7 +326,7 @@ static int sddr55_write_data(struct us_data *us,
// Get the data from the transfer buffer
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &index, &offset, FROM_XFER_BUF);
+ &sg, &offset, FROM_XFER_BUF);
US_DEBUGP("Write %02X pages, to PBA %04X"
" (LBA %04X) page %02X\n",
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index 5e27297c017..cb22a9ad169 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -190,9 +190,6 @@ static int usbat_check_status(struct us_data *us)
unsigned char *reply = us->iobuf;
int rc;
- if (!us)
- return USB_STOR_TRANSPORT_ERROR;
-
rc = usbat_get_status(us, reply);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_FAILED;
@@ -996,7 +993,8 @@ static int usbat_flash_read_data(struct us_data *us,
unsigned char thistime;
unsigned int totallen, alloclen;
int len, result;
- unsigned int sg_idx = 0, sg_offset = 0;
+ unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
result = usbat_flash_check_media(us, info);
if (result != USB_STOR_TRANSPORT_GOOD)
@@ -1050,7 +1048,7 @@ static int usbat_flash_read_data(struct us_data *us,
/* Store the data in the transfer buffer */
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &sg_idx, &sg_offset, TO_XFER_BUF);
+ &sg, &sg_offset, TO_XFER_BUF);
sector += thistime;
totallen -= len;
@@ -1086,7 +1084,8 @@ static int usbat_flash_write_data(struct us_data *us,
unsigned char thistime;
unsigned int totallen, alloclen;
int len, result;
- unsigned int sg_idx = 0, sg_offset = 0;
+ unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
result = usbat_flash_check_media(us, info);
if (result != USB_STOR_TRANSPORT_GOOD)
@@ -1125,7 +1124,7 @@ static int usbat_flash_write_data(struct us_data *us,
/* Get the data from the transfer buffer */
usb_stor_access_xfer_buf(buffer, len, us->srb,
- &sg_idx, &sg_offset, FROM_XFER_BUF);
+ &sg, &sg_offset, FROM_XFER_BUF);
/* ATA command 0x30 (WRITE SECTORS) */
usbat_pack_ata_sector_cmd(command, thistime, sector, 0x30);
@@ -1165,8 +1164,8 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
unsigned char *buffer;
unsigned int len;
unsigned int sector;
- unsigned int sg_segment = 0;
unsigned int sg_offset = 0;
+ struct scatterlist *sg = NULL;
US_DEBUGP("handle_read10: transfersize %d\n",
srb->transfersize);
@@ -1223,9 +1222,6 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
sector |= short_pack(data[7+5], data[7+4]);
transferred = 0;
- sg_segment = 0; /* for keeping track of where we are in */
- sg_offset = 0; /* the scatter/gather list */
-
while (transferred != srb->request_bufflen) {
if (len > srb->request_bufflen - transferred)
@@ -1258,7 +1254,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us,
/* Store the data in the transfer buffer */
usb_stor_access_xfer_buf(buffer, len, srb,
- &sg_segment, &sg_offset, TO_XFER_BUF);
+ &sg, &sg_offset, TO_XFER_BUF);
/* Update the amount transferred and the sector number */
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 323293a3e61..c646750ccc3 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -50,7 +50,7 @@
#include <linux/slab.h>
#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include "usb.h"
@@ -580,25 +580,11 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* Now, if we need to do the auto-sense, let's do it */
if (need_auto_sense) {
int temp_result;
- void* old_request_buffer;
- unsigned short old_sg;
- unsigned old_request_bufflen;
- unsigned char old_sc_data_direction;
- unsigned char old_cmd_len;
- unsigned char old_cmnd[MAX_COMMAND_SIZE];
- int old_resid;
+ struct scsi_eh_save ses;
US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
- /* save the old command */
- memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
- old_cmd_len = srb->cmd_len;
-
- /* set the command and the LUN */
- memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
- srb->cmnd[0] = REQUEST_SENSE;
- srb->cmnd[1] = old_cmnd[1] & 0xE0;
- srb->cmnd[4] = 18;
+ scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE);
/* FIXME: we must do the protocol translation here */
if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
@@ -606,36 +592,12 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
else
srb->cmd_len = 12;
- /* set the transfer direction */
- old_sc_data_direction = srb->sc_data_direction;
- srb->sc_data_direction = DMA_FROM_DEVICE;
-
- /* use the new buffer we have */
- old_request_buffer = srb->request_buffer;
- srb->request_buffer = us->sensebuf;
-
- /* set the buffer length for transfer */
- old_request_bufflen = srb->request_bufflen;
- srb->request_bufflen = US_SENSE_SIZE;
-
- /* set up for no scatter-gather use */
- old_sg = srb->use_sg;
- srb->use_sg = 0;
-
/* issue the auto-sense command */
- old_resid = srb->resid;
srb->resid = 0;
temp_result = us->transport(us->srb, us);
/* let's clean up right away */
- memcpy(srb->sense_buffer, us->sensebuf, US_SENSE_SIZE);
- srb->resid = old_resid;
- srb->request_buffer = old_request_buffer;
- srb->request_bufflen = old_request_bufflen;
- srb->use_sg = old_sg;
- srb->sc_data_direction = old_sc_data_direction;
- srb->cmd_len = old_cmd_len;
- memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
+ scsi_eh_restore_cmnd(srb, &ses);
if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
US_DEBUGP("-- auto-sense aborted\n");
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index c6b78ba815e..22ab2380367 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -198,7 +198,7 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100,
US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
/* Reported by Bardur Arantsson <bardur@scientician.net> */
-UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370,
+UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0610,
"Nokia",
"6131",
US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -341,6 +341,13 @@ UNUSUAL_DEV( 0x04b0, 0x040d, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY),
+/* Reported by Graber and Mike Pagano <mpagano-kernel@mpagano.com> */
+UNUSUAL_DEV( 0x04b0, 0x040f, 0x0200, 0x0200,
+ "NIKON",
+ "NIKON DSC D200",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
/* Reported by Emil Larsson <emil@swip.net> */
UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0101,
"NIKON",
@@ -355,6 +362,20 @@ UNUSUAL_DEV( 0x04b0, 0x0413, 0x0110, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY),
+/* Reported by Paul Check <paul@openstreet.com> */
+UNUSUAL_DEV( 0x04b0, 0x0415, 0x0100, 0x0100,
+ "NIKON",
+ "NIKON DSC D2Xs",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
+/* Reported by Shan Destromp (shansan@gmail.com) */
+UNUSUAL_DEV( 0x04b0, 0x0417, 0x0100, 0x0100,
+ "NIKON",
+ "NIKON DSC D40X",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
/* BENQ DC5330
* Reported by Manuel Fombuena <mfombuena@ya.com> and
* Frank Copeland <fjc@thingy.apana.org.au> */
@@ -386,7 +407,7 @@ UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210,
"FinePix 1400Zoom",
US_SC_UFI, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY | US_FL_SINGLE_LUN),
-/* Reported by Peter Wächtler <pwaechtler@loewe-komp.de>
+/* Reported by Peter Wächtler <pwaechtler@loewe-komp.de>
* The device needs the flags only.
*/
UNUSUAL_DEV( 0x04ce, 0x0002, 0x0074, 0x0074,
@@ -1463,6 +1484,17 @@ UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by fangxiaozhi <fangxiaozhi60675@huawei.com>
+ * and by linlei <linlei83@huawei.com>
+ * Patch reworked by Johann Wilhelm <johann.wilhelm@student.tugraz.at>
+ * This brings the HUAWEI E220 devices into multi-port mode
+ */
+UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000,
+ "HUAWEI MOBILE",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+ 0),
+
/* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
UNUSUAL_DEV( 0x132b, 0x000b, 0x0001, 0x0001,
"Minolta",
@@ -1519,7 +1551,7 @@ UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999,
US_FL_GO_SLOW ),
/*
- * David Härdeman <david@2gen.com>
+ * David Härdeman <david@2gen.com>
* The key makes the SCSI stack print confusing (but harmless) messages
*/
UNUSUAL_DEV( 0x4146, 0xba01, 0x0100, 0x0100,
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 59181667066..ac6114eea0c 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -907,12 +907,9 @@ static int usb_stor_scan_thread(void * __us)
if (delay_use > 0) {
printk(KERN_DEBUG "usb-storage: waiting for device "
"to settle before scanning\n");
-retry:
- wait_event_interruptible_timeout(us->delay_wait,
+ wait_event_freezable_timeout(us->delay_wait,
test_bit(US_FLIDX_DISCONNECTING, &us->flags),
delay_use * HZ);
- if (try_to_freeze())
- goto retry;
}
/* If the device is still connected, perform the scanning */
@@ -960,6 +957,10 @@ static int storage_probe(struct usb_interface *intf,
return -ENOMEM;
}
+ /*
+ * Allow 16-byte CDBs and thus > 2TB
+ */
+ host->max_cmd_len = 16;
us = host_to_us(host);
memset(us, 0, sizeof(struct us_data));
mutex_init(&(us->dev_mutex));
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 8de11deb5d1..c815a40e167 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -125,6 +125,7 @@ static int skel_open(struct inode *inode, struct file *file)
/* save our object in the file's private structure */
file->private_data = dev;
+ mutex_unlock(&dev->io_mutex);
exit:
return retval;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 5216c11d4de..7d86e9eae91 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -5,8 +5,9 @@
menu "Graphics support"
depends on HAS_IOMEM
-source "drivers/video/backlight/Kconfig"
-source "drivers/video/display/Kconfig"
+source "drivers/char/agp/Kconfig"
+
+source "drivers/char/drm/Kconfig"
config VGASTATE
tristate
@@ -14,12 +15,11 @@ config VGASTATE
config VIDEO_OUTPUT_CONTROL
tristate "Lowlevel video output switch controls"
- default m
help
This framework adds support for low-level control of the video
output switch.
-config FB
+menuconfig FB
tristate "Support for frame buffer devices"
---help---
The frame buffer device provides an abstraction for the graphics
@@ -103,6 +103,15 @@ config FB_CFB_IMAGEBLIT
blitting. This is used by drivers that don't provide their own
(accelerated) version.
+config FB_CFB_REV_PIXELS_IN_BYTE
+ bool
+ depends on FB
+ default n
+ ---help---
+ Allow generic frame-buffer functions to work on displays with 1, 2
+ and 4 bits per pixel depths which has opposite order of pixels in
+ byte order to bytes in long order.
+
config FB_SYS_FILLRECT
tristate
depends on FB
@@ -494,7 +503,7 @@ config FB_VALKYRIE
config FB_CT65550
bool "Chips 65550 display support"
- depends on (FB = y) && PPC32
+ depends on (FB = y) && PPC32 && PCI
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -535,6 +544,15 @@ config FB_VGA16
To compile this driver as a module, choose M here: the
module will be called vga16fb.
+config FB_BF54X_LQ043
+ tristate "SHARP LQ043 TFT LCD (BF548 EZKIT)"
+ depends on FB && (BF54x)
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This is the framebuffer device driver for a SHARP LQ043T1DG01 TFT LCD
+
config FB_STI
tristate "HP STI frame buffer device support"
depends on FB && PARISC
@@ -592,6 +610,24 @@ config FB_TGA
Say Y if you have one of those.
+config FB_UVESA
+ tristate "Userspace VESA VGA graphics support"
+ depends on FB && CONNECTOR
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_MODE_HELPERS
+ help
+ This is the frame buffer driver for generic VBE 2.0 compliant
+ graphic cards. It can also take advantage of VBE 3.0 features,
+ such as refresh rate adjustment.
+
+ This driver generally provides more features than vesafb but
+ requires a userspace helper application called 'v86d'. See
+ <file:Documentation/fb/uvesafb.txt> for more information.
+
+ If unsure, say N.
+
config FB_VESA
bool "VESA VGA graphics support"
depends on (FB = y) && X86
@@ -625,7 +661,7 @@ config FB_HECUBA
help
This enables support for the Hecuba board. This driver was tested
with an E-Ink 800x600 display and x86 SBCs through a 16 bit GPIO
- interface (8 bit data, 4 bit control). If you anticpate using
+ interface (8 bit data, 4 bit control). If you anticipate using
this driver, say Y or M; otherwise say N. You must specify the
GPIO IO address to be used for setting control and data.
@@ -779,7 +815,7 @@ config FB_XVR500
help
This is the framebuffer device for the Sun XVR-500 and similar
graphics cards based upon the 3DLABS Wildcat chipset. The driver
- only works on sparc64 systems where the system firwmare has
+ only works on sparc64 systems where the system firmware has
mostly initialized the card already. It is treated as a
completely dumb framebuffer device.
@@ -792,7 +828,7 @@ config FB_XVR2500
help
This is the framebuffer device for the Sun XVR-2500 and similar
graphics cards based upon the 3DLABS Wildcat chipset. The driver
- only works on sparc64 systems where the system firwmare has
+ only works on sparc64 systems where the system firmware has
mostly initialized the card already. It is treated as a
completely dumb framebuffer device.
@@ -1473,7 +1509,7 @@ config FB_VOODOO1
WARNING: Do not use any application that uses the 3D engine
(namely glide) while using this driver.
- Please read the <file:Documentation/fb/README-sstfb.txt> for supported
+ Please read the <file:Documentation/fb/sstfb.txt> for supported
options and other important info support.
config FB_VT8623
@@ -1625,7 +1661,7 @@ config FB_PMAG_BA
config FB_PMAGB_B
tristate "PMAGB-B TURBOchannel framebuffer support"
- depends on TC
+ depends on FB && TC
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1771,7 +1807,7 @@ config FB_SM501
This driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want). The
module will be called sm501fb. If you want to compile it as a module,
- say M here and read <file:Documentation/modules.txt>.
+ say M here and read <file:Documentation/kbuild/modules.txt>.
If unsure, say N.
@@ -1793,7 +1829,7 @@ config FB_PNX4008_DUM_RGB
config FB_IBM_GXT4500
tristate "Framebuffer support for IBM GXT4500P adaptor"
- depends on PPC
+ depends on FB && PPC
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1833,10 +1869,6 @@ config FB_XILINX
framebuffer. ML300 carries a 640*480 LCD display on the board,
ML403 uses a standard DB15 VGA connector.
-if ARCH_OMAP
- source "drivers/video/omap/Kconfig"
-endif
-
config FB_VIRTUAL
tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
depends on FB
@@ -1860,6 +1892,11 @@ config FB_VIRTUAL
If unsure, say N.
+source "drivers/video/omap/Kconfig"
+
+source "drivers/video/backlight/Kconfig"
+source "drivers/video/display/Kconfig"
+
if VT
source "drivers/video/console/Kconfig"
endif
@@ -1869,4 +1906,3 @@ if FB || SGI_NEWPORT_CONSOLE
endif
endmenu
-
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 06eec7b182b..59d6c45a910 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -115,10 +115,12 @@ obj-$(CONFIG_FB_XILINX) += xilinxfb.o
obj-$(CONFIG_FB_OMAP) += omap/
# Platform or fallback drivers go here
+obj-$(CONFIG_FB_UVESA) += uvesafb.o
obj-$(CONFIG_FB_VESA) += vesafb.o
obj-$(CONFIG_FB_IMAC) += imacfb.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o
obj-$(CONFIG_FB_OF) += offb.o
+obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 1a849b870bc..4c9ec3f58c5 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -52,7 +52,7 @@
#include <linux/init.h>
#include <linux/ioport.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
@@ -112,7 +112,7 @@
+----------+---------------------------------------------+----------+-------+
| | ^ | | |
| | |upper_margin | | |
- | | ¥ | | |
+ | | v | | |
+----------###############################################----------+-------+
| # ^ # | |
| # | # | |
@@ -133,15 +133,15 @@
| # | # | |
| # | # | |
| # | # | |
- | # ¥ # | |
+ | # v # | |
+----------###############################################----------+-------+
| | ^ | | |
| | |lower_margin | | |
- | | ¥ | | |
+ | | v | | |
+----------+---------------------------------------------+----------+-------+
| | ^ | | |
| | |vsync_len | | |
- | | ¥ | | |
+ | | v | | |
+----------+---------------------------------------------+----------+-------+
@@ -325,7 +325,7 @@
CCIR -> PAL
-----------
- - a scanline is 64 µs long, of which 52.48 µs are visible. This is about
+ - a scanline is 64 µs long, of which 52.48 µs are visible. This is about
736 visible 70 ns pixels per line.
- we have 625 scanlines, of which 575 are visible (interlaced); after
rounding this becomes 576.
@@ -333,7 +333,7 @@
RETMA -> NTSC
-------------
- - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about
+ - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about
736 visible 70 ns pixels per line.
- we have 525 scanlines, of which 485 are visible (interlaced); after
rounding this becomes 484.
@@ -802,7 +802,7 @@ static u_short ecs_palette[32];
static u_short do_vmode_full = 0; /* Change the Video Mode */
static u_short do_vmode_pan = 0; /* Update the Video Mode */
-static short do_blank = 0; /* (Un)Blank the Screen (±1) */
+static short do_blank = 0; /* (Un)Blank the Screen (±1) */
static u_short do_cursor = 0; /* Move the Cursor */
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index db15baca3f7..c3431691c9f 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -48,7 +48,7 @@
#include <linux/arcfb.h>
#include <linux/platform_device.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#define floor8(a) (a&(~0x07))
#define floorXres(a,xres) (a&(~(xres - 1)))
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index 0038a0541c7..5d4fbaa53a6 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -58,7 +58,7 @@
#include <linux/interrupt.h>
#include <asm/setup.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/io.h>
diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h
index dca2eb8f2dd..3e9d28bcd9f 100644
--- a/drivers/video/aty/ati_ids.h
+++ b/drivers/video/aty/ati_ids.h
@@ -188,6 +188,7 @@
#define PCI_CHIP_MACH64VT 0x5654
#define PCI_CHIP_MACH64VU 0x5655
#define PCI_CHIP_MACH64VV 0x5656
+#define PCI_CHIP_RC410_5A62 0x5A62
#define PCI_CHIP_RS300_5834 0x5834
#define PCI_CHIP_RS300_5835 0x5835
#define PCI_CHIP_RS300_5836 0x5836
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index cfcbe37d2d7..cbd3308b669 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -56,7 +56,7 @@
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
index dc62f8e282b..7691e73823d 100644
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -126,6 +126,7 @@ union aty_pll {
*/
struct atyfb_par {
+ u32 pseudo_palette[16];
struct { u8 red, green, blue; } palette[256];
const struct aty_dac_ops *dac_ops;
const struct aty_pll_ops *pll_ops;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index bc6f0096aa0..d775eb6590b 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -26,7 +26,7 @@
* Anthony Tong <atong@uiuc.edu>
*
* Generic LCD support written by Daniel Mantione, ported from 2.4.20 by Alex Kern
- * Many Thanks to Ville Syrjälä for patches and fixing nasting 16 bit color bug.
+ * Many Thanks to Ville Syrjälä for patches and fixing nasting 16 bit color bug.
*
* 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
@@ -68,7 +68,7 @@
#include <linux/backlight.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <video/mach64.h>
#include "atyfb.h"
@@ -541,8 +541,6 @@ static char ram_off[] __devinitdata = "OFF";
#endif /* CONFIG_FB_ATY_CT */
-static u32 pseudo_palette[16];
-
#ifdef CONFIG_FB_ATY_GX
static char *aty_gx_ram[8] __devinitdata = {
ram_dram, ram_vram, ram_vram, ram_dram,
@@ -2577,7 +2575,7 @@ static int __devinit aty_init(struct fb_info *info)
#endif
info->fbops = &atyfb_ops;
- info->pseudo_palette = pseudo_palette;
+ info->pseudo_palette = par->pseudo_palette;
info->flags = FBINFO_DEFAULT |
FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_FILLRECT |
diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c
index fe2c6ad01a8..faf95da8fcb 100644
--- a/drivers/video/aty/mach64_cursor.c
+++ b/drivers/video/aty/mach64_cursor.c
@@ -8,7 +8,6 @@
#include <linux/string.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
#ifdef __sparc__
#include <asm/fbio.h>
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 4b747bdaeea..1e32b3d13f2 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -69,7 +69,7 @@
#include <linux/device.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#ifdef CONFIG_PPC_OF
@@ -145,6 +145,8 @@ static struct pci_device_id radeonfb_pci_table[] = {
/* 9000/Pro */
CHIP_DEF(PCI_CHIP_RV250_If, RV250, CHIP_HAS_CRTC2),
CHIP_DEF(PCI_CHIP_RV250_Ig, RV250, CHIP_HAS_CRTC2),
+
+ CHIP_DEF(PCI_CHIP_RC410_5A62, RC410, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
/* Mobility 9100 IGP (U3) */
CHIP_DEF(PCI_CHIP_RS300_5835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
CHIP_DEF(PCI_CHIP_RS350_7835, RS300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
@@ -1999,6 +2001,7 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo)
if ((rinfo->family == CHIP_FAMILY_RS100) ||
(rinfo->family == CHIP_FAMILY_RS200) ||
(rinfo->family == CHIP_FAMILY_RS300) ||
+ (rinfo->family == CHIP_FAMILY_RC410) ||
(rinfo->family == CHIP_FAMILY_RS480) ) {
u32 tom = INREG(NB_TOM);
tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index be1d57bf9dc..83ee3e75386 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -27,8 +27,6 @@
#include "ati_ids.h"
-static void radeon_reinitialize_M10(struct radeonfb_info *rinfo);
-
/*
* Workarounds for bugs in PC laptops:
* - enable D2 sleep in some IBM Thinkpads
@@ -39,6 +37,8 @@ static void radeon_reinitialize_M10(struct radeonfb_info *rinfo);
*/
#if defined(CONFIG_PM) && defined(CONFIG_X86)
+static void radeon_reinitialize_M10(struct radeonfb_info *rinfo);
+
struct radeon_device_id {
const char *ident; /* (arbitrary) Name */
const unsigned short subsystem_vendor; /* Subsystem Vendor ID */
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index 7c922c7b460..5eac1ce52e7 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -48,6 +48,7 @@ enum radeon_family {
CHIP_FAMILY_RV350,
CHIP_FAMILY_RV380, /* RV370/RV380/M22/M24 */
CHIP_FAMILY_R420, /* R420/R423/M18 */
+ CHIP_FAMILY_RC410,
CHIP_FAMILY_RS480,
CHIP_FAMILY_LAST,
};
@@ -66,7 +67,8 @@ enum radeon_family {
((rinfo)->family == CHIP_FAMILY_R350) || \
((rinfo)->family == CHIP_FAMILY_RV380) || \
((rinfo)->family == CHIP_FAMILY_R420) || \
- ((rinfo)->family == CHIP_FAMILY_RS480) )
+ ((rinfo)->family == CHIP_FAMILY_RC410) || \
+ ((rinfo)->family == CHIP_FAMILY_RS480))
/*
* Chip flags
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index 832e4613673..62bd4441b5e 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -457,7 +457,7 @@ static struct fb_ops au1100fb_ops =
/* AU1100 LCD controller device driver */
-int au1100fb_drv_probe(struct device *dev)
+static int __init au1100fb_drv_probe(struct device *dev)
{
struct au1100fb_device *fbdev = NULL;
struct resource *regs_res;
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 2580f5fa248..9609a6c676b 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -24,6 +24,18 @@ config LCD_CLASS_DEVICE
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
+config LCD_LTV350QV
+ tristate "Samsung LTV350QV LCD Panel"
+ depends on LCD_CLASS_DEVICE && SPI_MASTER
+ default n
+ help
+ If you have a Samsung LTV350QV LCD panel, say y to include a
+ power control driver for it. The panel starts up in power
+ off state, so you need this driver in order to see any
+ output.
+
+ The LTV350QV panel is present on all ATSTK1000 boards.
+
#
# Backlight
#
@@ -39,12 +51,13 @@ config BACKLIGHT_CLASS_DEVICE
select the proper drivers which depend on this option.
config BACKLIGHT_CORGI
- tristate "Sharp Corgi Backlight Driver (SL Series)"
- depends on BACKLIGHT_CLASS_DEVICE && PXA_SHARPSL
- default y
+ tristate "Generic (aka Sharp Corgi) Backlight Driver"
+ depends on BACKLIGHT_CLASS_DEVICE
+ default n
help
- If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the
- backlight driver.
+ Say y to enable the generic platform backlight driver previously
+ known as the Corgi backlight driver. If you have a Sharp Zaurus
+ SL-C7xx, SL-Cxx00 or SL-6000x say y. Most users can say n.
config BACKLIGHT_LOCOMO
tristate "Sharp LOCOMO LCD/Backlight Driver"
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index c6e2266f63e..965a78b1811 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -1,6 +1,8 @@
# Backlight & LCD drivers
obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o
+obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o
+
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o
obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index b26de8cf311..4840fe217e4 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -164,7 +164,7 @@ static ssize_t backlight_show_actual_brightness(struct device *dev,
return rc;
}
-struct class *backlight_class;
+static struct class *backlight_class;
static void bl_device_release(struct device *dev)
{
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
index ce00e18a4e5..4d4d037e3ec 100644
--- a/drivers/video/backlight/corgi_bl.c
+++ b/drivers/video/backlight/corgi_bl.c
@@ -18,13 +18,11 @@
#include <linux/mutex.h>
#include <linux/fb.h>
#include <linux/backlight.h>
-#include <asm/arch/sharpsl.h>
-#include <asm/hardware/sharpsl_pm.h>
static int corgibl_intensity;
static struct backlight_properties corgibl_data;
static struct backlight_device *corgi_backlight_device;
-static struct corgibl_machinfo *bl_machinfo;
+static struct generic_bl_info *bl_machinfo;
static unsigned long corgibl_flags;
#define CORGIBL_SUSPENDED 0x01
@@ -32,7 +30,6 @@ static unsigned long corgibl_flags;
static int corgibl_send_intensity(struct backlight_device *bd)
{
- void (*corgi_kick_batt)(void);
int intensity = bd->props.brightness;
if (bd->props.power != FB_BLANK_UNBLANK)
@@ -48,11 +45,8 @@ static int corgibl_send_intensity(struct backlight_device *bd)
corgibl_intensity = intensity;
- corgi_kick_batt = symbol_get(sharpsl_battery_kick);
- if (corgi_kick_batt) {
- corgi_kick_batt();
- symbol_put(sharpsl_battery_kick);
- }
+ if (bl_machinfo->kick_battery)
+ bl_machinfo->kick_battery();
return 0;
}
@@ -107,13 +101,17 @@ static struct backlight_ops corgibl_ops = {
static int corgibl_probe(struct platform_device *pdev)
{
- struct corgibl_machinfo *machinfo = pdev->dev.platform_data;
+ struct generic_bl_info *machinfo = pdev->dev.platform_data;
+ const char *name = "generic-bl";
bl_machinfo = machinfo;
if (!machinfo->limit_mask)
machinfo->limit_mask = -1;
- corgi_backlight_device = backlight_device_register ("corgi-bl",
+ if (machinfo->name)
+ name = machinfo->name;
+
+ corgi_backlight_device = backlight_device_register (name,
&pdev->dev, NULL, &corgibl_ops);
if (IS_ERR (corgi_backlight_device))
return PTR_ERR (corgi_backlight_device);
@@ -149,7 +147,7 @@ static struct platform_driver corgibl_driver = {
.suspend = corgibl_suspend,
.resume = corgibl_resume,
.driver = {
- .name = "corgi-bl",
+ .name = "generic-bl",
},
};
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
index b7904da51b2..26add889860 100644
--- a/drivers/video/backlight/cr_bllcd.c
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -36,7 +36,6 @@
#include <linux/backlight.h>
#include <linux/lcd.h>
#include <linux/pci.h>
-#include <asm/uaccess.h>
/* The LVDS- and panel power controls sits on the
* GPIO port of the ISA bridge.
@@ -171,13 +170,11 @@ static struct lcd_ops cr_lcd_ops = {
static int cr_backlight_probe(struct platform_device *pdev)
{
+ struct backlight_device *bdp;
+ struct lcd_device *ldp;
struct cr_panel *crp;
u8 dev_en;
- crp = kzalloc(sizeof(*crp), GFP_KERNEL);
- if (crp == NULL)
- return -ENOMEM;
-
lpc_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
CRVML_DEVICE_LPC, NULL);
if (!lpc_dev) {
@@ -193,27 +190,34 @@ static int cr_backlight_probe(struct platform_device *pdev)
return -ENODEV;
}
- crp->cr_backlight_device = backlight_device_register("cr-backlight",
- &pdev->dev, NULL,
- &cr_backlight_ops);
- if (IS_ERR(crp->cr_backlight_device)) {
+ bdp = backlight_device_register("cr-backlight",
+ &pdev->dev, NULL, &cr_backlight_ops);
+ if (IS_ERR(bdp)) {
pci_dev_put(lpc_dev);
- return PTR_ERR(crp->cr_backlight_device);
+ return PTR_ERR(bdp);
}
- crp->cr_lcd_device = lcd_device_register("cr-lcd",
- &pdev->dev, NULL,
- &cr_lcd_ops);
-
- if (IS_ERR(crp->cr_lcd_device)) {
+ ldp = lcd_device_register("cr-lcd", &pdev->dev, NULL, &cr_lcd_ops);
+ if (IS_ERR(ldp)) {
+ backlight_device_unregister(bdp);
pci_dev_put(lpc_dev);
- return PTR_ERR(crp->cr_backlight_device);
+ return PTR_ERR(bdp);
}
pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR,
&gpio_bar);
gpio_bar &= ~0x3F;
+ crp = kzalloc(sizeof(*crp), GFP_KERNEL);
+ if (!crp) {
+ lcd_device_unregister(ldp);
+ backlight_device_unregister(bdp);
+ pci_dev_put(lpc_dev);
+ return -ENOMEM;
+ }
+
+ crp->cr_backlight_device = bdp;
+ crp->cr_lcd_device = ldp;
crp->cr_backlight_device->props.power = FB_BLANK_UNBLANK;
crp->cr_backlight_device->props.brightness = 0;
crp->cr_backlight_device->props.max_brightness = 0;
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index 0899fccbd57..fbea2bd129c 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -125,8 +125,8 @@ static int hp680bl_remove(struct platform_device *pdev)
{
struct backlight_device *bd = platform_get_drvdata(pdev);
- hp680bl_data.brightness = 0;
- hp680bl_data.power = 0;
+ bd->props.brightness = 0;
+ bd->props.power = 0;
hp680bl_send_intensity(bd);
backlight_device_unregister(bd);
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 6f652c65fae..299fd318dd4 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -149,7 +149,7 @@ static ssize_t lcd_show_max_contrast(struct device *dev,
return sprintf(buf, "%d\n", ld->props.max_contrast);
}
-struct class *lcd_class;
+static struct class *lcd_class;
static void lcd_device_release(struct device *dev)
{
diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c
new file mode 100644
index 00000000000..2eb206bf73e
--- /dev/null
+++ b/drivers/video/backlight/ltv350qv.c
@@ -0,0 +1,330 @@
+/*
+ * Power control for Samsung LTV350QV Quarter VGA LCD Panel
+ *
+ * Copyright (C) 2006, 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/lcd.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "ltv350qv.h"
+
+#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
+
+struct ltv350qv {
+ struct spi_device *spi;
+ u8 *buffer;
+ int power;
+ struct lcd_device *ld;
+};
+
+/*
+ * The power-on and power-off sequences are taken from the
+ * LTV350QV-F04 data sheet from Samsung. The register definitions are
+ * taken from the S6F2002 command list also from Samsung. Both
+ * documents are distributed with the AVR32 Linux BSP CD from Atmel.
+ *
+ * There's still some voodoo going on here, but it's a lot better than
+ * in the first incarnation of the driver where all we had was the raw
+ * numbers from the initialization sequence.
+ */
+static int ltv350qv_write_reg(struct ltv350qv *lcd, u8 reg, u16 val)
+{
+ struct spi_message msg;
+ struct spi_transfer index_xfer = {
+ .len = 3,
+ .cs_change = 1,
+ };
+ struct spi_transfer value_xfer = {
+ .len = 3,
+ };
+
+ spi_message_init(&msg);
+
+ /* register index */
+ lcd->buffer[0] = LTV_OPC_INDEX;
+ lcd->buffer[1] = 0x00;
+ lcd->buffer[2] = reg & 0x7f;
+ index_xfer.tx_buf = lcd->buffer;
+ spi_message_add_tail(&index_xfer, &msg);
+
+ /* register value */
+ lcd->buffer[4] = LTV_OPC_DATA;
+ lcd->buffer[5] = val >> 8;
+ lcd->buffer[6] = val;
+ value_xfer.tx_buf = lcd->buffer + 4;
+ spi_message_add_tail(&value_xfer, &msg);
+
+ return spi_sync(lcd->spi, &msg);
+}
+
+/* The comments are taken straight from the data sheet */
+static int ltv350qv_power_on(struct ltv350qv *lcd)
+{
+ int ret;
+
+ /* Power On Reset Display off State */
+ if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, 0x0000))
+ goto err;
+ msleep(15);
+
+ /* Power Setting Function 1 */
+ if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE))
+ goto err;
+ if (ltv350qv_write_reg(lcd, LTV_PWRCTL2, LTV_VCOML_ENABLE))
+ goto err_power1;
+
+ /* Power Setting Function 2 */
+ if (ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+ LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5)
+ | LTV_SUPPLY_CURRENT(5)))
+ goto err_power2;
+
+ msleep(55);
+
+ /* Instruction Setting */
+ ret = ltv350qv_write_reg(lcd, LTV_IFCTL,
+ LTV_NMD | LTV_REV | LTV_NL(0x1d));
+ ret |= ltv350qv_write_reg(lcd, LTV_DATACTL,
+ LTV_DS_SAME | LTV_CHS_480
+ | LTV_DF_RGB | LTV_RGB_BGR);
+ ret |= ltv350qv_write_reg(lcd, LTV_ENTRY_MODE,
+ LTV_VSPL_ACTIVE_LOW
+ | LTV_HSPL_ACTIVE_LOW
+ | LTV_DPL_SAMPLE_RISING
+ | LTV_EPL_ACTIVE_LOW
+ | LTV_SS_RIGHT_TO_LEFT);
+ ret |= ltv350qv_write_reg(lcd, LTV_GATECTL1, LTV_CLW(3));
+ ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
+ LTV_NW_INV_1LINE | LTV_FWI(3));
+ ret |= ltv350qv_write_reg(lcd, LTV_VBP, 0x000a);
+ ret |= ltv350qv_write_reg(lcd, LTV_HBP, 0x0021);
+ ret |= ltv350qv_write_reg(lcd, LTV_SOTCTL, LTV_SDT(3) | LTV_EQ(0));
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(0), 0x0103);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(1), 0x0301);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(2), 0x1f0f);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(3), 0x1f0f);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(4), 0x0707);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(5), 0x0307);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(6), 0x0707);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(7), 0x0000);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(8), 0x0004);
+ ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(9), 0x0000);
+ if (ret)
+ goto err_settings;
+
+ /* Wait more than 2 frames */
+ msleep(20);
+
+ /* Display On Sequence */
+ ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+ LTV_VCOM_DISABLE | LTV_VCOMOUT_ENABLE
+ | LTV_POWER_ON | LTV_DRIVE_CURRENT(5)
+ | LTV_SUPPLY_CURRENT(5));
+ ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
+ LTV_NW_INV_1LINE | LTV_DSC | LTV_FWI(3));
+ if (ret)
+ goto err_disp_on;
+
+ /* Display should now be ON. Phew. */
+ return 0;
+
+err_disp_on:
+ /*
+ * Try to recover. Error handling probably isn't very useful
+ * at this point, just make a best effort to switch the panel
+ * off.
+ */
+ ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+ LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5)
+ | LTV_SUPPLY_CURRENT(5));
+ ltv350qv_write_reg(lcd, LTV_GATECTL2,
+ LTV_NW_INV_1LINE | LTV_FWI(3));
+err_settings:
+err_power2:
+err_power1:
+ ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000);
+ msleep(1);
+err:
+ ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE);
+ return -EIO;
+}
+
+static int ltv350qv_power_off(struct ltv350qv *lcd)
+{
+ int ret;
+
+ /* Display Off Sequence */
+ ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+ LTV_VCOM_DISABLE
+ | LTV_DRIVE_CURRENT(5)
+ | LTV_SUPPLY_CURRENT(5));
+ ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
+ LTV_NW_INV_1LINE | LTV_FWI(3));
+
+ /* Power down setting 1 */
+ ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000);
+
+ /* Wait at least 1 ms */
+ msleep(1);
+
+ /* Power down setting 2 */
+ ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE);
+
+ /*
+ * No point in trying to recover here. If we can't switch the
+ * panel off, what are we supposed to do other than inform the
+ * user about the failure?
+ */
+ if (ret)
+ return -EIO;
+
+ /* Display power should now be OFF */
+ return 0;
+}
+
+static int ltv350qv_power(struct ltv350qv *lcd, int power)
+{
+ int ret = 0;
+
+ if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
+ ret = ltv350qv_power_on(lcd);
+ else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
+ ret = ltv350qv_power_off(lcd);
+
+ if (!ret)
+ lcd->power = power;
+
+ return ret;
+}
+
+static int ltv350qv_set_power(struct lcd_device *ld, int power)
+{
+ struct ltv350qv *lcd = lcd_get_data(ld);
+
+ return ltv350qv_power(lcd, power);
+}
+
+static int ltv350qv_get_power(struct lcd_device *ld)
+{
+ struct ltv350qv *lcd = lcd_get_data(ld);
+
+ return lcd->power;
+}
+
+static struct lcd_ops ltv_ops = {
+ .get_power = ltv350qv_get_power,
+ .set_power = ltv350qv_set_power,
+};
+
+static int __devinit ltv350qv_probe(struct spi_device *spi)
+{
+ struct ltv350qv *lcd;
+ struct lcd_device *ld;
+ int ret;
+
+ lcd = kzalloc(sizeof(struct ltv350qv), GFP_KERNEL);
+ if (!lcd)
+ return -ENOMEM;
+
+ lcd->spi = spi;
+ lcd->power = FB_BLANK_POWERDOWN;
+ lcd->buffer = kzalloc(8, GFP_KERNEL);
+
+ ld = lcd_device_register("ltv350qv", &spi->dev, lcd, &ltv_ops);
+ if (IS_ERR(ld)) {
+ ret = PTR_ERR(ld);
+ goto out_free_lcd;
+ }
+ lcd->ld = ld;
+
+ ret = ltv350qv_power(lcd, FB_BLANK_UNBLANK);
+ if (ret)
+ goto out_unregister;
+
+ dev_set_drvdata(&spi->dev, lcd);
+
+ return 0;
+
+out_unregister:
+ lcd_device_unregister(ld);
+out_free_lcd:
+ kfree(lcd);
+ return ret;
+}
+
+static int __devexit ltv350qv_remove(struct spi_device *spi)
+{
+ struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+ ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
+ lcd_device_unregister(lcd->ld);
+ kfree(lcd);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ltv350qv_suspend(struct spi_device *spi, pm_message_t state)
+{
+ struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+ return ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static int ltv350qv_resume(struct spi_device *spi)
+{
+ struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+ return ltv350qv_power(lcd, FB_BLANK_UNBLANK);
+}
+#else
+#define ltv350qv_suspend NULL
+#define ltv350qv_resume NULL
+#endif
+
+/* Power down all displays on reboot, poweroff or halt */
+static void ltv350qv_shutdown(struct spi_device *spi)
+{
+ struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+ ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static struct spi_driver ltv350qv_driver = {
+ .driver = {
+ .name = "ltv350qv",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+
+ .probe = ltv350qv_probe,
+ .remove = __devexit_p(ltv350qv_remove),
+ .shutdown = ltv350qv_shutdown,
+ .suspend = ltv350qv_suspend,
+ .resume = ltv350qv_resume,
+};
+
+static int __init ltv350qv_init(void)
+{
+ return spi_register_driver(&ltv350qv_driver);
+}
+
+static void __exit ltv350qv_exit(void)
+{
+ spi_unregister_driver(&ltv350qv_driver);
+}
+module_init(ltv350qv_init);
+module_exit(ltv350qv_exit);
+
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_DESCRIPTION("Samsung LTV350QV LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/ltv350qv.h b/drivers/video/backlight/ltv350qv.h
new file mode 100644
index 00000000000..189112e3fc7
--- /dev/null
+++ b/drivers/video/backlight/ltv350qv.h
@@ -0,0 +1,95 @@
+/*
+ * Register definitions for Samsung LTV350QV Quarter VGA LCD Panel
+ *
+ * Copyright (C) 2006, 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LTV350QV_H
+#define __LTV350QV_H
+
+#define LTV_OPC_INDEX 0x74
+#define LTV_OPC_DATA 0x76
+
+#define LTV_ID 0x00 /* ID Read */
+#define LTV_IFCTL 0x01 /* Display Interface Control */
+#define LTV_DATACTL 0x02 /* Display Data Control */
+#define LTV_ENTRY_MODE 0x03 /* Entry Mode */
+#define LTV_GATECTL1 0x04 /* Gate Control 1 */
+#define LTV_GATECTL2 0x05 /* Gate Control 2 */
+#define LTV_VBP 0x06 /* Vertical Back Porch */
+#define LTV_HBP 0x07 /* Horizontal Back Porch */
+#define LTV_SOTCTL 0x08 /* Source Output Timing Control */
+#define LTV_PWRCTL1 0x09 /* Power Control 1 */
+#define LTV_PWRCTL2 0x0a /* Power Control 2 */
+#define LTV_GAMMA(x) (0x10 + (x)) /* Gamma control */
+
+/* Bit definitions for LTV_IFCTL */
+#define LTV_IM (1 << 15)
+#define LTV_NMD (1 << 14)
+#define LTV_SSMD (1 << 13)
+#define LTV_REV (1 << 7)
+#define LTV_NL(x) (((x) & 0x001f) << 0)
+
+/* Bit definitions for LTV_DATACTL */
+#define LTV_DS_SAME (0 << 12)
+#define LTV_DS_D_TO_S (1 << 12)
+#define LTV_DS_S_TO_D (2 << 12)
+#define LTV_CHS_384 (0 << 9)
+#define LTV_CHS_480 (1 << 9)
+#define LTV_CHS_492 (2 << 9)
+#define LTV_DF_RGB (0 << 6)
+#define LTV_DF_RGBX (1 << 6)
+#define LTV_DF_XRGB (2 << 6)
+#define LTV_RGB_RGB (0 << 2)
+#define LTV_RGB_BGR (1 << 2)
+#define LTV_RGB_GRB (2 << 2)
+#define LTV_RGB_RBG (3 << 2)
+
+/* Bit definitions for LTV_ENTRY_MODE */
+#define LTV_VSPL_ACTIVE_LOW (0 << 15)
+#define LTV_VSPL_ACTIVE_HIGH (1 << 15)
+#define LTV_HSPL_ACTIVE_LOW (0 << 14)
+#define LTV_HSPL_ACTIVE_HIGH (1 << 14)
+#define LTV_DPL_SAMPLE_RISING (0 << 13)
+#define LTV_DPL_SAMPLE_FALLING (1 << 13)
+#define LTV_EPL_ACTIVE_LOW (0 << 12)
+#define LTV_EPL_ACTIVE_HIGH (1 << 12)
+#define LTV_SS_LEFT_TO_RIGHT (0 << 8)
+#define LTV_SS_RIGHT_TO_LEFT (1 << 8)
+#define LTV_STB (1 << 1)
+
+/* Bit definitions for LTV_GATECTL1 */
+#define LTV_CLW(x) (((x) & 0x0007) << 12)
+#define LTV_GAON (1 << 5)
+#define LTV_SDR (1 << 3)
+
+/* Bit definitions for LTV_GATECTL2 */
+#define LTV_NW_INV_FRAME (0 << 14)
+#define LTV_NW_INV_1LINE (1 << 14)
+#define LTV_NW_INV_2LINE (2 << 14)
+#define LTV_DSC (1 << 12)
+#define LTV_GIF (1 << 8)
+#define LTV_FHN (1 << 7)
+#define LTV_FTI(x) (((x) & 0x0003) << 4)
+#define LTV_FWI(x) (((x) & 0x0003) << 0)
+
+/* Bit definitions for LTV_SOTCTL */
+#define LTV_SDT(x) (((x) & 0x0007) << 10)
+#define LTV_EQ(x) (((x) & 0x0007) << 2)
+
+/* Bit definitions for LTV_PWRCTL1 */
+#define LTV_VCOM_DISABLE (1 << 14)
+#define LTV_VCOMOUT_ENABLE (1 << 11)
+#define LTV_POWER_ON (1 << 9)
+#define LTV_DRIVE_CURRENT(x) (((x) & 0x0007) << 4) /* 0=off, 5=max */
+#define LTV_SUPPLY_CURRENT(x) (((x) & 0x0007) << 0) /* 0=off, 5=max */
+
+/* Bit definitions for LTV_PWRCTL2 */
+#define LTV_VCOML_ENABLE (1 << 13)
+#define LTV_VCOML_VOLTAGE(x) (((x) & 0x001f) << 8) /* 0=1V, 31=-1V */
+#define LTV_VCOMH_VOLTAGE(x) (((x) & 0x001f) << 0) /* 0=3V, 31=4.5V */
+
+#endif /* __LTV350QV_H */
diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c
index 836ab4df0ef..15fb4d58b5b 100644
--- a/drivers/video/backlight/progear_bl.c
+++ b/drivers/video/backlight/progear_bl.c
@@ -23,7 +23,6 @@
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/pci.h>
-#include <asm/uaccess.h>
#define PMU_LPCR 0xB0
#define SB_MPS1 0x61
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
new file mode 100644
index 00000000000..74d11c31898
--- /dev/null
+++ b/drivers/video/bf54x-lq043fb.c
@@ -0,0 +1,786 @@
+/*
+ * File: drivers/video/bf54x-lq043.c
+ * Based on:
+ * Author: Michael Hennerich <hennerich@blackfin.uclinux.org>
+ *
+ * Created:
+ * Description: ADSP-BF54x Framebufer driver
+ *
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/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 <linux/timer.h>
+#include <linux/device.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+#include <asm/dpmc.h>
+#include <asm/dma-mapping.h>
+#include <asm/dma.h>
+#include <asm/gpio.h>
+#include <asm/portmux.h>
+
+#include <asm/mach/bf54x-lq043.h>
+
+#define NO_BL_SUPPORT
+
+#define DRIVER_NAME "bf54x-lq043"
+static char driver_name[] = DRIVER_NAME;
+
+#define BFIN_LCD_NBR_PALETTE_ENTRIES 256
+
+#define EPPI0_18 {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, P_PPI0_D16, P_PPI0_D17, 0}
+
+#define EPPI0_24 {P_PPI0_D18, P_PPI0_D19, P_PPI0_D20, P_PPI0_D21, P_PPI0_D22, P_PPI0_D23, 0}
+
+struct bfin_bf54xfb_info {
+ struct fb_info *fb;
+ struct device *dev;
+
+ struct bfin_bf54xfb_mach_info *mach_info;
+
+ unsigned char *fb_buffer; /* RGB Buffer */
+
+ dma_addr_t dma_handle;
+ int lq043_mmap;
+ int lq043_open_cnt;
+ int irq;
+ spinlock_t lock; /* lock */
+};
+
+static int nocursor;
+module_param(nocursor, int, 0644);
+MODULE_PARM_DESC(nocursor, "cursor enable/disable");
+
+static int outp_rgb666;
+module_param(outp_rgb666, int, 0);
+MODULE_PARM_DESC(outp_rgb666, "Output 18-bit RGB666");
+
+#define LCD_X_RES 480 /*Horizontal Resolution */
+#define LCD_Y_RES 272 /* Vertical Resolution */
+
+#define LCD_BPP 24 /* Bit Per Pixel */
+#define DMA_BUS_SIZE 32
+
+/* -- Horizontal synchronizing --
+ *
+ * Timing characteristics taken from the SHARP LQ043T1DG01 datasheet
+ * (LCY-W-06602A Page 9 of 22)
+ *
+ * Clock Frequency 1/Tc Min 7.83 Typ 9.00 Max 9.26 MHz
+ *
+ * Period TH - 525 - Clock
+ * Pulse width THp - 41 - Clock
+ * Horizontal period THd - 480 - Clock
+ * Back porch THb - 2 - Clock
+ * Front porch THf - 2 - Clock
+ *
+ * -- Vertical synchronizing --
+ * Period TV - 286 - Line
+ * Pulse width TVp - 10 - Line
+ * Vertical period TVd - 272 - Line
+ * Back porch TVb - 2 - Line
+ * Front porch TVf - 2 - Line
+ */
+
+#define LCD_CLK (8*1000*1000) /* 8MHz */
+
+/* # active data to transfer after Horizontal Delay clock */
+#define EPPI_HCOUNT LCD_X_RES
+
+/* # active lines to transfer after Vertical Delay clock */
+#define EPPI_VCOUNT LCD_Y_RES
+
+/* Samples per Line = 480 (active data) + 45 (padding) */
+#define EPPI_LINE 525
+
+/* Lines per Frame = 272 (active data) + 14 (padding) */
+#define EPPI_FRAME 286
+
+/* FS1 (Hsync) Width (Typical)*/
+#define EPPI_FS1W_HBL 41
+
+/* FS1 (Hsync) Period (Typical) */
+#define EPPI_FS1P_AVPL EPPI_LINE
+
+/* Horizontal Delay clock after assertion of Hsync (Typical) */
+#define EPPI_HDELAY 43
+
+/* FS2 (Vsync) Width = FS1 (Hsync) Period * 10 */
+#define EPPI_FS2W_LVB (EPPI_LINE * 10)
+
+ /* FS2 (Vsync) Period = FS1 (Hsync) Period * Lines per Frame */
+#define EPPI_FS2P_LAVF (EPPI_LINE * EPPI_FRAME)
+
+/* Vertical Delay after assertion of Vsync (2 Lines) */
+#define EPPI_VDELAY 12
+
+#define EPPI_CLIP 0xFF00FF00
+
+/* EPPI Control register configuration value for RGB out
+ * - EPPI as Output
+ * GP 2 frame sync mode,
+ * Internal Clock generation disabled, Internal FS generation enabled,
+ * Receives samples on EPPI_CLK raising edge, Transmits samples on EPPI_CLK falling edge,
+ * FS1 & FS2 are active high,
+ * DLEN = 6 (24 bits for RGB888 out) or 5 (18 bits for RGB666 out)
+ * DMA Unpacking disabled when RGB Formating is enabled, otherwise DMA unpacking enabled
+ * Swapping Enabled,
+ * One (DMA) Channel Mode,
+ * RGB Formatting Enabled for RGB666 output, disabled for RGB888 output
+ * Regular watermark - when FIFO is 100% full,
+ * Urgent watermark - when FIFO is 75% full
+ */
+
+#define EPPI_CONTROL (0x20136E2E | SWAPEN)
+
+static inline u16 get_eppi_clkdiv(u32 target_ppi_clk)
+{
+ u32 sclk = get_sclk();
+
+ /* EPPI_CLK = (SCLK) / (2 * (EPPI_CLKDIV[15:0] + 1)) */
+
+ return (((sclk / target_ppi_clk) / 2) - 1);
+}
+
+static void config_ppi(struct bfin_bf54xfb_info *fbi)
+{
+
+ u16 eppi_clkdiv = get_eppi_clkdiv(LCD_CLK);
+
+ bfin_write_EPPI0_FS1W_HBL(EPPI_FS1W_HBL);
+ bfin_write_EPPI0_FS1P_AVPL(EPPI_FS1P_AVPL);
+ bfin_write_EPPI0_FS2W_LVB(EPPI_FS2W_LVB);
+ bfin_write_EPPI0_FS2P_LAVF(EPPI_FS2P_LAVF);
+ bfin_write_EPPI0_CLIP(EPPI_CLIP);
+
+ bfin_write_EPPI0_FRAME(EPPI_FRAME);
+ bfin_write_EPPI0_LINE(EPPI_LINE);
+
+ bfin_write_EPPI0_HCOUNT(EPPI_HCOUNT);
+ bfin_write_EPPI0_HDELAY(EPPI_HDELAY);
+ bfin_write_EPPI0_VCOUNT(EPPI_VCOUNT);
+ bfin_write_EPPI0_VDELAY(EPPI_VDELAY);
+
+ bfin_write_EPPI0_CLKDIV(eppi_clkdiv);
+
+/*
+ * DLEN = 6 (24 bits for RGB888 out) or 5 (18 bits for RGB666 out)
+ * RGB Formatting Enabled for RGB666 output, disabled for RGB888 output
+ */
+ if (outp_rgb666)
+ bfin_write_EPPI0_CONTROL((EPPI_CONTROL & ~DLENGTH) | DLEN_18 |
+ RGB_FMT_EN);
+ else
+ bfin_write_EPPI0_CONTROL(((EPPI_CONTROL & ~DLENGTH) | DLEN_24) &
+ ~RGB_FMT_EN);
+
+
+}
+
+static int config_dma(struct bfin_bf54xfb_info *fbi)
+{
+
+ set_dma_config(CH_EPPI0,
+ set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO,
+ INTR_DISABLE, DIMENSION_2D,
+ DATA_SIZE_32));
+ set_dma_x_count(CH_EPPI0, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE);
+ set_dma_x_modify(CH_EPPI0, DMA_BUS_SIZE / 8);
+ set_dma_y_count(CH_EPPI0, LCD_Y_RES);
+ set_dma_y_modify(CH_EPPI0, DMA_BUS_SIZE / 8);
+ set_dma_start_addr(CH_EPPI0, (unsigned long)fbi->fb_buffer);
+
+ return 0;
+}
+
+static int request_ports(struct bfin_bf54xfb_info *fbi)
+{
+
+ u16 eppi_req_18[] = EPPI0_18;
+ u16 disp = fbi->mach_info->disp;
+
+ if (gpio_request(disp, NULL)) {
+ printk(KERN_ERR "Requesting GPIO %d faild\n", disp);
+ return -EFAULT;
+ }
+
+ if (peripheral_request_list(eppi_req_18, DRIVER_NAME)) {
+ printk(KERN_ERR "Requesting Peripherals faild\n");
+ gpio_free(disp);
+ return -EFAULT;
+ }
+
+ if (!outp_rgb666) {
+
+ u16 eppi_req_24[] = EPPI0_24;
+
+ if (peripheral_request_list(eppi_req_24, DRIVER_NAME)) {
+ printk(KERN_ERR "Requesting Peripherals faild\n");
+ peripheral_free_list(eppi_req_18);
+ gpio_free(disp);
+ return -EFAULT;
+ }
+ }
+
+ gpio_direction_output(disp);
+ gpio_set_value(disp, 1);
+
+ return 0;
+}
+
+static void free_ports(struct bfin_bf54xfb_info *fbi)
+{
+
+ u16 eppi_req_18[] = EPPI0_18;
+
+ gpio_free(fbi->mach_info->disp);
+
+ peripheral_free_list(eppi_req_18);
+
+ if (!outp_rgb666) {
+ u16 eppi_req_24[] = EPPI0_24;
+ peripheral_free_list(eppi_req_24);
+ }
+}
+
+static int bfin_bf54x_fb_open(struct fb_info *info, int user)
+{
+ struct bfin_bf54xfb_info *fbi = info->par;
+
+ spin_lock(&fbi->lock);
+ fbi->lq043_open_cnt++;
+
+ if (fbi->lq043_open_cnt <= 1) {
+
+ bfin_write_EPPI0_CONTROL(0);
+ SSYNC();
+
+ config_dma(fbi);
+ config_ppi(fbi);
+
+ /* start dma */
+ enable_dma(CH_EPPI0);
+ bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() | EPPI_EN);
+ }
+
+ spin_unlock(&fbi->lock);
+
+ return 0;
+}
+
+static int bfin_bf54x_fb_release(struct fb_info *info, int user)
+{
+ struct bfin_bf54xfb_info *fbi = info->par;
+
+ spin_lock(&fbi->lock);
+
+ fbi->lq043_open_cnt--;
+ fbi->lq043_mmap = 0;
+
+ if (fbi->lq043_open_cnt <= 0) {
+
+ bfin_write_EPPI0_CONTROL(0);
+ SSYNC();
+ disable_dma(CH_EPPI0);
+ memset(fbi->fb_buffer, 0, info->fix.smem_len);
+ }
+
+ spin_unlock(&fbi->lock);
+
+ return 0;
+}
+
+static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+
+ if (var->bits_per_pixel != LCD_BPP) {
+ pr_debug("%s: depth not supported: %u BPP\n", __FUNCTION__,
+ 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",
+ __FUNCTION__, 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",
+ __FUNCTION__, var->yres_virtual);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int bfin_bf54x_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+
+ struct bfin_bf54xfb_info *fbi = info->par;
+
+ if (fbi->lq043_mmap)
+ return -1;
+
+ spin_lock(&fbi->lock);
+ fbi->lq043_mmap = 1;
+ spin_unlock(&fbi->lock);
+
+ vma->vm_start = (unsigned long)(fbi->fb_buffer);
+
+ vma->vm_end = vma->vm_start + info->fix.smem_len;
+ /* For those who don't understand how mmap works, go read
+ * Documentation/nommu-mmap.txt.
+ * For those that do, you will know that the VM_MAYSHARE flag
+ * must be set in the vma->vm_flags structure on noMMU
+ * Other flags can be set, and are documented in
+ * include/linux/mm.h
+ */
+ vma->vm_flags |= VM_MAYSHARE;
+
+ return 0;
+}
+
+int bfin_bf54x_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_bf54x_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 &= 0xFFFFFF;
+
+ ((u32 *) (info->pseudo_palette))[regno] = value;
+
+ }
+
+ return 0;
+}
+
+static struct fb_ops bfin_bf54x_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = bfin_bf54x_fb_open,
+ .fb_release = bfin_bf54x_fb_release,
+ .fb_check_var = bfin_bf54x_fb_check_var,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_mmap = bfin_bf54x_fb_mmap,
+ .fb_cursor = bfin_bf54x_fb_cursor,
+ .fb_setcolreg = bfin_bf54x_fb_setcolreg,
+};
+
+#ifndef NO_BL_SUPPORT
+static int bl_get_brightness(struct backlight_device *bd)
+{
+ return 0;
+}
+
+static struct backlight_ops bfin_lq043fb_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 0;
+}
+
+static int bfin_lcd_set_contrast(struct lcd_device *dev, int contrast)
+{
+
+ return 0;
+}
+
+static int bfin_lcd_check_fb(struct fb_info *fi)
+{
+ if (!fi || (fi == &bfin_bf54x_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;
+#endif
+
+static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
+{
+
+ /*struct bfin_bf54xfb_info *info = (struct bfin_bf54xfb_info *)dev_id;*/
+
+ u16 status = bfin_read_EPPI0_STATUS();
+
+ bfin_write_EPPI0_STATUS(0xFFFF);
+
+ if (status) {
+ bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() & ~EPPI_EN);
+ disable_dma(CH_EPPI0);
+
+ /* start dma */
+ enable_dma(CH_EPPI0);
+ bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() | EPPI_EN);
+ bfin_write_EPPI0_STATUS(0xFFFF);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __init bfin_bf54x_probe(struct platform_device *pdev)
+{
+ struct bfin_bf54xfb_info *info;
+ struct fb_info *fbinfo;
+ int ret;
+
+ printk(KERN_INFO DRIVER_NAME ": FrameBuffer initializing...\n");
+
+ if (request_dma(CH_EPPI0, "CH_EPPI0") < 0) {
+ printk(KERN_ERR DRIVER_NAME
+ ": couldn't request CH_EPPI0 DMA\n");
+ ret = -EFAULT;
+ goto out1;
+ }
+
+ fbinfo =
+ framebuffer_alloc(sizeof(struct bfin_bf54xfb_info), &pdev->dev);
+ if (!fbinfo) {
+ ret = -ENOMEM;
+ goto out2;
+ }
+
+ info = fbinfo->par;
+ info->fb = fbinfo;
+ info->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, fbinfo);
+
+ strcpy(fbinfo->fix.id, driver_name);
+
+ info->mach_info = pdev->dev.platform_data;
+
+ if (info->mach_info == NULL) {
+ dev_err(&pdev->dev,
+ "no platform data for lcd, cannot attach\n");
+ ret = -EINVAL;
+ goto out3;
+ }
+
+ fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
+ fbinfo->fix.type_aux = 0;
+ fbinfo->fix.xpanstep = 0;
+ fbinfo->fix.ypanstep = 0;
+ fbinfo->fix.ywrapstep = 0;
+ fbinfo->fix.accel = FB_ACCEL_NONE;
+ fbinfo->fix.visual = FB_VISUAL_TRUECOLOR;
+
+ fbinfo->var.nonstd = 0;
+ fbinfo->var.activate = FB_ACTIVATE_NOW;
+ fbinfo->var.height = info->mach_info->height;
+ fbinfo->var.width = info->mach_info->width;
+ fbinfo->var.accel_flags = 0;
+ fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
+
+ fbinfo->fbops = &bfin_bf54x_fb_ops;
+ fbinfo->flags = FBINFO_FLAG_DEFAULT;
+
+ fbinfo->var.xres = info->mach_info->xres.defval;
+ fbinfo->var.xres_virtual = info->mach_info->xres.defval;
+ fbinfo->var.yres = info->mach_info->yres.defval;
+ fbinfo->var.yres_virtual = info->mach_info->yres.defval;
+ fbinfo->var.bits_per_pixel = info->mach_info->bpp.defval;
+
+ fbinfo->var.upper_margin = 0;
+ fbinfo->var.lower_margin = 0;
+ fbinfo->var.vsync_len = 0;
+
+ fbinfo->var.left_margin = 0;
+ fbinfo->var.right_margin = 0;
+ fbinfo->var.hsync_len = 0;
+
+ fbinfo->var.red.offset = 16;
+ fbinfo->var.green.offset = 8;
+ fbinfo->var.blue.offset = 0;
+ fbinfo->var.transp.offset = 0;
+ fbinfo->var.red.length = 8;
+ fbinfo->var.green.length = 8;
+ fbinfo->var.blue.length = 8;
+ fbinfo->var.transp.length = 0;
+ fbinfo->fix.smem_len = info->mach_info->xres.max *
+ info->mach_info->yres.max * info->mach_info->bpp.max / 8;
+
+ fbinfo->fix.line_length = fbinfo->var.xres_virtual *
+ fbinfo->var.bits_per_pixel / 8;
+
+ info->fb_buffer =
+ dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle,
+ GFP_KERNEL);
+
+ if (NULL == info->fb_buffer) {
+ printk(KERN_ERR DRIVER_NAME
+ ": couldn't allocate dma buffer.\n");
+ ret = -ENOMEM;
+ goto out3;
+ }
+
+ memset(info->fb_buffer, 0, fbinfo->fix.smem_len);
+
+ fbinfo->screen_base = (void *)info->fb_buffer;
+ fbinfo->fix.smem_start = (int)info->fb_buffer;
+
+ fbinfo->fbops = &bfin_bf54x_fb_ops;
+
+ fbinfo->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+ if (!fbinfo->pseudo_palette) {
+ printk(KERN_ERR DRIVER_NAME
+ "Fail to allocate pseudo_palette\n");
+
+ ret = -ENOMEM;
+ goto out4;
+ }
+
+ memset(fbinfo->pseudo_palette, 0, sizeof(u32) * 16);
+
+ if (fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0)
+ < 0) {
+ printk(KERN_ERR DRIVER_NAME
+ "Fail to allocate colormap (%d entries)\n",
+ BFIN_LCD_NBR_PALETTE_ENTRIES);
+ ret = -EFAULT;
+ goto out5;
+ }
+
+ if (request_ports(info)) {
+ printk(KERN_ERR DRIVER_NAME ": couldn't request gpio port.\n");
+ ret = -EFAULT;
+ goto out6;
+ }
+
+ info->irq = platform_get_irq(pdev, 0);
+ if (info->irq < 0) {
+ ret = -EINVAL;
+ goto out7;
+ }
+
+ if (request_irq(info->irq, (void *)bfin_bf54x_irq_error, IRQF_DISABLED,
+ "PPI ERROR", info) < 0) {
+ printk(KERN_ERR DRIVER_NAME
+ ": unable to request PPI ERROR IRQ\n");
+ ret = -EFAULT;
+ goto out7;
+ }
+
+ if (register_framebuffer(fbinfo) < 0) {
+ printk(KERN_ERR DRIVER_NAME
+ ": unable to register framebuffer.\n");
+ ret = -EINVAL;
+ goto out8;
+ }
+#ifndef NO_BL_SUPPORT
+ bl_dev =
+ backlight_device_register("bf54x-bl", NULL, NULL,
+ &bfin_lq043fb_bl_ops);
+ bl_dev->props.max_brightness = 255;
+
+ lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops);
+ lcd_dev->props.max_contrast = 255, printk(KERN_INFO "Done.\n");
+#endif
+
+ return 0;
+
+out8:
+ free_irq(info->irq, info);
+out7:
+ free_ports(info);
+out6:
+ fb_dealloc_cmap(&fbinfo->cmap);
+out5:
+ kfree(fbinfo->pseudo_palette);
+out4:
+ dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
+ info->dma_handle);
+out3:
+ framebuffer_release(fbinfo);
+out2:
+ free_dma(CH_EPPI0);
+out1:
+ platform_set_drvdata(pdev, NULL);
+
+ return ret;
+}
+
+static int bfin_bf54x_remove(struct platform_device *pdev)
+{
+
+ struct fb_info *fbinfo = platform_get_drvdata(pdev);
+ struct bfin_bf54xfb_info *info = fbinfo->par;
+
+ free_dma(CH_EPPI0);
+ free_irq(info->irq, info);
+
+ if (info->fb_buffer != NULL)
+ dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
+ info->dma_handle);
+
+ kfree(fbinfo->pseudo_palette);
+ fb_dealloc_cmap(&fbinfo->cmap);
+
+#ifndef NO_BL_SUPPORT
+ lcd_device_unregister(lcd_dev);
+ backlight_device_unregister(bl_dev);
+#endif
+
+ unregister_framebuffer(fbinfo);
+
+ free_ports(info);
+
+ printk(KERN_INFO DRIVER_NAME ": Unregister LCD driver.\n");
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin_bf54x_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct fb_info *fbinfo = platform_get_drvdata(pdev);
+ struct bfin_bf54xfb_info *info = fbinfo->par;
+
+ bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() & ~EPPI_EN);
+ disable_dma(CH_EPPI0);
+ bfin_write_EPPI0_STATUS(0xFFFF);
+
+ return 0;
+}
+
+static int bfin_bf54x_resume(struct platform_device *pdev)
+{
+ struct fb_info *fbinfo = platform_get_drvdata(pdev);
+ struct bfin_bf54xfb_info *info = fbinfo->par;
+
+ enable_dma(CH_EPPI0);
+ bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() | EPPI_EN);
+
+ return 0;
+}
+#else
+#define bfin_bf54x_suspend NULL
+#define bfin_bf54x_resume NULL
+#endif
+
+static struct platform_driver bfin_bf54x_driver = {
+ .probe = bfin_bf54x_probe,
+ .remove = bfin_bf54x_remove,
+ .suspend = bfin_bf54x_suspend,
+ .resume = bfin_bf54x_resume,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __devinit bfin_bf54x_driver_init(void)
+{
+ return platform_driver_register(&bfin_bf54x_driver);
+}
+
+static void __exit bfin_bf54x_driver_cleanup(void)
+{
+ platform_driver_unregister(&bfin_bf54x_driver);
+}
+
+MODULE_DESCRIPTION("Blackfin BF54x TFT LCD Driver");
+MODULE_LICENSE("GPL");
+
+module_init(bfin_bf54x_driver_init);
+module_exit(bfin_bf54x_driver_cleanup);
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
index 032210f45be..b07e419b12d 100644
--- a/drivers/video/cfbcopyarea.c
+++ b/drivers/video/cfbcopyarea.c
@@ -45,14 +45,14 @@
static void
bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
- int src_idx, int bits, unsigned n)
+ int src_idx, int bits, unsigned n, u32 bswapmask)
{
unsigned long first, last;
int const shift = dst_idx-src_idx;
int left, right;
- first = FB_SHIFT_HIGH(~0UL, dst_idx);
- last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+ first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
+ last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
if (!shift) {
// Same alignment for source and dest
@@ -94,29 +94,34 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst);
}
} else {
+ /* Different alignment for source and dest */
unsigned long d0, d1;
int m;
- // Different alignment for source and dest
right = shift & (bits - 1);
left = -shift & (bits - 1);
+ bswapmask &= shift;
if (dst_idx+n <= bits) {
// Single destination word
if (last)
first &= last;
+ d0 = FB_READL(src);
+ d0 = fb_rev_pixels_in_long(d0, bswapmask);
if (shift > 0) {
// Single source word
- FB_WRITEL( comp( FB_READL(src) >> right, FB_READL(dst), first), dst);
+ d0 >>= right;
} else if (src_idx+n <= bits) {
// Single source word
- FB_WRITEL( comp(FB_READL(src) << left, FB_READL(dst), first), dst);
+ d0 <<= left;;
} else {
// 2 source words
- d0 = FB_READL(src++);
- d1 = FB_READL(src);
- FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst);
+ d1 = FB_READL(src + 1);
+ d1 = fb_rev_pixels_in_long(d1, bswapmask);
+ d0 = d0<<left | d1>>right;
}
+ d0 = fb_rev_pixels_in_long(d0, bswapmask);
+ FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
} else {
// Multiple destination words
/** We must always remember the last value read, because in case
@@ -125,25 +130,31 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
overlap with the current long from SRC. We store this value in
'd0'. */
d0 = FB_READL(src++);
+ d0 = fb_rev_pixels_in_long(d0, bswapmask);
// Leading bits
if (shift > 0) {
// Single source word
- FB_WRITEL( comp(d0 >> right, FB_READL(dst), first), dst);
+ d1 = d0;
+ d0 >>= right;
dst++;
n -= bits - dst_idx;
} else {
// 2 source words
d1 = FB_READL(src++);
- FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), first), dst);
- d0 = d1;
+ d1 = fb_rev_pixels_in_long(d1, bswapmask);
+
+ d0 = d0<<left | d1>>right;
dst++;
n -= bits - dst_idx;
}
+ d0 = fb_rev_pixels_in_long(d0, bswapmask);
+ FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
+ d0 = d1;
// Main chunk
m = n % bits;
n /= bits;
- while (n >= 4) {
+ while ((n >= 4) && !bswapmask) {
d1 = FB_READL(src++);
FB_WRITEL(d0 << left | d1 >> right, dst++);
d0 = d1;
@@ -160,7 +171,10 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
}
while (n--) {
d1 = FB_READL(src++);
- FB_WRITEL(d0 << left | d1 >> right, dst++);
+ d1 = fb_rev_pixels_in_long(d1, bswapmask);
+ d0 = d0 << left | d1 >> right;
+ d0 = fb_rev_pixels_in_long(d0, bswapmask);
+ FB_WRITEL(d0, dst++);
d0 = d1;
}
@@ -168,12 +182,16 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
if (last) {
if (m <= right) {
// Single source word
- FB_WRITEL( comp(d0 << left, FB_READL(dst), last), dst);
+ d0 <<= left;
} else {
// 2 source words
d1 = FB_READL(src);
- FB_WRITEL( comp(d0<<left | d1>>right, FB_READL(dst), last), dst);
+ d1 = fb_rev_pixels_in_long(d1,
+ bswapmask);
+ d0 = d0<<left | d1>>right;
}
+ d0 = fb_rev_pixels_in_long(d0, bswapmask);
+ FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
}
}
}
@@ -185,7 +203,7 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
static void
bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src,
- int src_idx, int bits, unsigned n)
+ int src_idx, int bits, unsigned n, u32 bswapmask)
{
unsigned long first, last;
int shift;
@@ -203,8 +221,8 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
shift = dst_idx-src_idx;
- first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx);
- last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits)));
+ first = fb_shifted_pixels_mask_long(bits - 1 - dst_idx, bswapmask);
+ last = ~fb_shifted_pixels_mask_long(bits - 1 - ((dst_idx-n) % bits), bswapmask);
if (!shift) {
// Same alignment for source and dest
@@ -247,24 +265,32 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
}
} else {
// Different alignment for source and dest
+ unsigned long d0, d1;
+ int m;
int const left = -shift & (bits-1);
int const right = shift & (bits-1);
+ bswapmask &= shift;
if ((unsigned long)dst_idx+1 >= n) {
// Single destination word
if (last)
first &= last;
+ d0 = FB_READL(src);
if (shift < 0) {
// Single source word
- FB_WRITEL( comp( FB_READL(src)<<left, FB_READL(dst), first), dst);
+ d0 <<= left;
} else if (1+(unsigned long)src_idx >= n) {
// Single source word
- FB_WRITEL( comp( FB_READL(src)>>right, FB_READL(dst), first), dst);
+ d0 >>= right;
} else {
// 2 source words
- FB_WRITEL( comp( (FB_READL(src)>>right | FB_READL(src-1)<<left), FB_READL(dst), first), dst);
+ d1 = FB_READL(src - 1);
+ d1 = fb_rev_pixels_in_long(d1, bswapmask);
+ d0 = d0>>right | d1<<left;
}
+ d0 = fb_rev_pixels_in_long(d0, bswapmask);
+ FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
} else {
// Multiple destination words
/** We must always remember the last value read, because in case
@@ -272,27 +298,30 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
1bpp), we always collect one full long for DST and that might
overlap with the current long from SRC. We store this value in
'd0'. */
- unsigned long d0, d1;
- int m;
d0 = FB_READL(src--);
+ d0 = fb_rev_pixels_in_long(d0, bswapmask);
// Leading bits
if (shift < 0) {
// Single source word
- FB_WRITEL( comp( (d0 << left), FB_READL(dst), first), dst);
+ d1 = d0;
+ d0 <<= left;
} else {
// 2 source words
d1 = FB_READL(src--);
- FB_WRITEL( comp( (d0>>right | d1<<left), FB_READL(dst), first), dst);
- d0 = d1;
+ d1 = fb_rev_pixels_in_long(d1, bswapmask);
+ d0 = d0>>right | d1<<left;
}
+ d0 = fb_rev_pixels_in_long(d0, bswapmask);
+ FB_WRITEL(comp(d0, FB_READL(dst), first), dst);
+ d0 = d1;
dst--;
n -= dst_idx+1;
// Main chunk
m = n % bits;
n /= bits;
- while (n >= 4) {
+ while ((n >= 4) && !bswapmask) {
d1 = FB_READL(src--);
FB_WRITEL(d0 >> right | d1 << left, dst--);
d0 = d1;
@@ -309,7 +338,10 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
}
while (n--) {
d1 = FB_READL(src--);
- FB_WRITEL(d0 >> right | d1 << left, dst--);
+ d1 = fb_rev_pixels_in_long(d1, bswapmask);
+ d0 = d0 >> right | d1 << left;
+ d0 = fb_rev_pixels_in_long(d0, bswapmask);
+ FB_WRITEL(d0, dst--);
d0 = d1;
}
@@ -317,12 +349,16 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
if (last) {
if (m <= left) {
// Single source word
- FB_WRITEL( comp(d0 >> right, FB_READL(dst), last), dst);
+ d0 >>= right;
} else {
// 2 source words
d1 = FB_READL(src);
- FB_WRITEL( comp(d0>>right | d1<<left, FB_READL(dst), last), dst);
+ d1 = fb_rev_pixels_in_long(d1,
+ bswapmask);
+ d0 = d0>>right | d1<<left;
}
+ d0 = fb_rev_pixels_in_long(d0, bswapmask);
+ FB_WRITEL(comp(d0, FB_READL(dst), last), dst);
}
}
}
@@ -336,6 +372,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
unsigned long __iomem *dst = NULL, *src = NULL;
int bits = BITS_PER_LONG, bytes = bits >> 3;
int dst_idx = 0, src_idx = 0, rev_copy = 0;
+ u32 bswapmask = fb_compute_bswapmask(p);
if (p->state != FBINFO_STATE_RUNNING)
return;
@@ -368,7 +405,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
src += src_idx >> (ffs(bits) - 1);
src_idx &= (bytes - 1);
bitcpy_rev(dst, dst_idx, src, src_idx, bits,
- width*p->var.bits_per_pixel);
+ width*p->var.bits_per_pixel, bswapmask);
}
} else {
while (height--) {
@@ -377,7 +414,7 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
src += src_idx >> (ffs(bits) - 1);
src_idx &= (bytes - 1);
bitcpy(dst, dst_idx, src, src_idx, bits,
- width*p->var.bits_per_pixel);
+ width*p->var.bits_per_pixel, bswapmask);
dst_idx += bits_per_line;
src_idx += bits_per_line;
}
diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
index 71623b4f8ca..23d70a12e4d 100644
--- a/drivers/video/cfbfillrect.c
+++ b/drivers/video/cfbfillrect.c
@@ -36,15 +36,16 @@
*/
static void
-bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
+bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
+ unsigned n, int bits, u32 bswapmask)
{
unsigned long first, last;
if (!n)
return;
- first = FB_SHIFT_HIGH(~0UL, dst_idx);
- last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+ first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
+ last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
if (dst_idx+n <= bits) {
// Single word
@@ -146,7 +147,8 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
* Aligned pattern invert using 32/64-bit memory accesses
*/
static void
-bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsigned n, int bits)
+bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
+ unsigned n, int bits, u32 bswapmask)
{
unsigned long val = pat, dat;
unsigned long first, last;
@@ -154,8 +156,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
if (!n)
return;
- first = FB_SHIFT_HIGH(~0UL, dst_idx);
- last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+ first = fb_shifted_pixels_mask_long(dst_idx, bswapmask);
+ last = ~fb_shifted_pixels_mask_long((dst_idx+n) % bits, bswapmask);
if (dst_idx+n <= bits) {
// Single word
@@ -303,8 +305,10 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
if (p->fbops->fb_sync)
p->fbops->fb_sync(p);
if (!left) {
+ u32 bswapmask = fb_compute_bswapmask(p);
void (*fill_op32)(unsigned long __iomem *dst, int dst_idx,
- unsigned long pat, unsigned n, int bits) = NULL;
+ unsigned long pat, unsigned n, int bits,
+ u32 bswapmask) = NULL;
switch (rect->rop) {
case ROP_XOR:
@@ -321,7 +325,7 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
while (height--) {
dst += dst_idx >> (ffs(bits) - 1);
dst_idx &= (bits - 1);
- fill_op32(dst, dst_idx, pat, width*bpp, bits);
+ fill_op32(dst, dst_idx, pat, width*bpp, bits, bswapmask);
dst_idx += p->fix.line_length*8;
}
} else {
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
index 261004473c8..f598907b42a 100644
--- a/drivers/video/cfbimgblt.c
+++ b/drivers/video/cfbimgblt.c
@@ -33,6 +33,7 @@
#include <linux/string.h>
#include <linux/fb.h>
#include <asm/types.h>
+#include "fb_draw.h"
#define DEBUG
@@ -87,6 +88,7 @@ static inline void color_imageblit(const struct fb_image *image,
u32 null_bits = 32 - bpp;
u32 *palette = (u32 *) p->pseudo_palette;
const u8 *src = image->data;
+ u32 bswapmask = fb_compute_bswapmask(p);
dst2 = (u32 __iomem *) dst1;
for (i = image->height; i--; ) {
@@ -96,7 +98,7 @@ static inline void color_imageblit(const struct fb_image *image,
val = 0;
if (start_index) {
- u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, start_index));
+ u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask);
val = FB_READL(dst) & start_mask;
shift = start_index;
}
@@ -107,7 +109,7 @@ static inline void color_imageblit(const struct fb_image *image,
else
color = *src;
color <<= FB_LEFT_POS(bpp);
- val |= FB_SHIFT_HIGH(color, shift);
+ val |= FB_SHIFT_HIGH(color, shift ^ bswapmask);
if (shift >= null_bits) {
FB_WRITEL(val, dst++);
@@ -119,7 +121,7 @@ static inline void color_imageblit(const struct fb_image *image,
src++;
}
if (shift) {
- u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
+ u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask);
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
}
@@ -147,7 +149,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
u32 spitch = (image->width+7)/8;
const u8 *src = image->data, *s;
u32 i, j, l;
-
+ u32 bswapmask = fb_compute_bswapmask(p);
+
dst2 = (u32 __iomem *) dst1;
fgcolor <<= FB_LEFT_POS(bpp);
bgcolor <<= FB_LEFT_POS(bpp);
@@ -161,7 +164,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
/* write leading bits */
if (start_index) {
- u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index));
+ u32 start_mask = ~fb_shifted_pixels_mask_u32(start_index, bswapmask);
val = FB_READL(dst) & start_mask;
shift = start_index;
}
@@ -169,7 +172,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
while (j--) {
l--;
color = (*s & (1 << l)) ? fgcolor : bgcolor;
- val |= FB_SHIFT_HIGH(color, shift);
+ val |= FB_SHIFT_HIGH(color, shift ^ bswapmask);
/* Did the bitshift spill bits to the next long? */
if (shift >= null_bits) {
@@ -184,7 +187,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
/* write trailing bits */
if (shift) {
- u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
+ u32 end_mask = fb_shifted_pixels_mask_u32(shift, bswapmask);
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
}
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index ee9046db9c7..549891d76ef 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -19,7 +19,6 @@
#include <linux/mm.h>
#include <asm/io.h>
-#include <asm/prom.h>
#include <asm/of_device.h>
#include <asm/fbio.h>
@@ -38,6 +37,7 @@ static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *);
static int cg6_sync(struct fb_info *);
static int cg6_mmap(struct fb_info *, struct vm_area_struct *);
static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long);
+static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
/*
* Frame buffer operations
@@ -48,7 +48,7 @@ static struct fb_ops cg6_ops = {
.fb_setcolreg = cg6_setcolreg,
.fb_blank = cg6_blank,
.fb_fillrect = cg6_fillrect,
- .fb_copyarea = cfb_copyarea,
+ .fb_copyarea = cg6_copyarea,
.fb_imageblit = cg6_imageblit,
.fb_sync = cg6_sync,
.fb_mmap = cg6_mmap,
@@ -65,41 +65,41 @@ static struct fb_ops cg6_ops = {
* The FBC could be the frame buffer control
* The FHC could is the frame buffer hardware control.
*/
-#define CG6_ROM_OFFSET 0x0UL
-#define CG6_BROOKTREE_OFFSET 0x200000UL
-#define CG6_DHC_OFFSET 0x240000UL
-#define CG6_ALT_OFFSET 0x280000UL
-#define CG6_FHC_OFFSET 0x300000UL
-#define CG6_THC_OFFSET 0x301000UL
-#define CG6_FBC_OFFSET 0x700000UL
-#define CG6_TEC_OFFSET 0x701000UL
-#define CG6_RAM_OFFSET 0x800000UL
+#define CG6_ROM_OFFSET 0x0UL
+#define CG6_BROOKTREE_OFFSET 0x200000UL
+#define CG6_DHC_OFFSET 0x240000UL
+#define CG6_ALT_OFFSET 0x280000UL
+#define CG6_FHC_OFFSET 0x300000UL
+#define CG6_THC_OFFSET 0x301000UL
+#define CG6_FBC_OFFSET 0x700000UL
+#define CG6_TEC_OFFSET 0x701000UL
+#define CG6_RAM_OFFSET 0x800000UL
/* FHC definitions */
-#define CG6_FHC_FBID_SHIFT 24
-#define CG6_FHC_FBID_MASK 255
-#define CG6_FHC_REV_SHIFT 20
-#define CG6_FHC_REV_MASK 15
-#define CG6_FHC_FROP_DISABLE (1 << 19)
-#define CG6_FHC_ROW_DISABLE (1 << 18)
-#define CG6_FHC_SRC_DISABLE (1 << 17)
-#define CG6_FHC_DST_DISABLE (1 << 16)
-#define CG6_FHC_RESET (1 << 15)
-#define CG6_FHC_LITTLE_ENDIAN (1 << 13)
-#define CG6_FHC_RES_MASK (3 << 11)
-#define CG6_FHC_1024 (0 << 11)
-#define CG6_FHC_1152 (1 << 11)
-#define CG6_FHC_1280 (2 << 11)
-#define CG6_FHC_1600 (3 << 11)
-#define CG6_FHC_CPU_MASK (3 << 9)
-#define CG6_FHC_CPU_SPARC (0 << 9)
-#define CG6_FHC_CPU_68020 (1 << 9)
-#define CG6_FHC_CPU_386 (2 << 9)
-#define CG6_FHC_TEST (1 << 8)
-#define CG6_FHC_TEST_X_SHIFT 4
-#define CG6_FHC_TEST_X_MASK 15
-#define CG6_FHC_TEST_Y_SHIFT 0
-#define CG6_FHC_TEST_Y_MASK 15
+#define CG6_FHC_FBID_SHIFT 24
+#define CG6_FHC_FBID_MASK 255
+#define CG6_FHC_REV_SHIFT 20
+#define CG6_FHC_REV_MASK 15
+#define CG6_FHC_FROP_DISABLE (1 << 19)
+#define CG6_FHC_ROW_DISABLE (1 << 18)
+#define CG6_FHC_SRC_DISABLE (1 << 17)
+#define CG6_FHC_DST_DISABLE (1 << 16)
+#define CG6_FHC_RESET (1 << 15)
+#define CG6_FHC_LITTLE_ENDIAN (1 << 13)
+#define CG6_FHC_RES_MASK (3 << 11)
+#define CG6_FHC_1024 (0 << 11)
+#define CG6_FHC_1152 (1 << 11)
+#define CG6_FHC_1280 (2 << 11)
+#define CG6_FHC_1600 (3 << 11)
+#define CG6_FHC_CPU_MASK (3 << 9)
+#define CG6_FHC_CPU_SPARC (0 << 9)
+#define CG6_FHC_CPU_68020 (1 << 9)
+#define CG6_FHC_CPU_386 (2 << 9)
+#define CG6_FHC_TEST (1 << 8)
+#define CG6_FHC_TEST_X_SHIFT 4
+#define CG6_FHC_TEST_X_MASK 15
+#define CG6_FHC_TEST_Y_SHIFT 0
+#define CG6_FHC_TEST_Y_MASK 15
/* FBC mode definitions */
#define CG6_FBC_BLIT_IGNORE 0x00000000
@@ -150,17 +150,17 @@ static struct fb_ops cg6_ops = {
#define CG6_FBC_INDEX_MASK 0x00000030
/* THC definitions */
-#define CG6_THC_MISC_REV_SHIFT 16
-#define CG6_THC_MISC_REV_MASK 15
-#define CG6_THC_MISC_RESET (1 << 12)
-#define CG6_THC_MISC_VIDEO (1 << 10)
-#define CG6_THC_MISC_SYNC (1 << 9)
-#define CG6_THC_MISC_VSYNC (1 << 8)
-#define CG6_THC_MISC_SYNC_ENAB (1 << 7)
-#define CG6_THC_MISC_CURS_RES (1 << 6)
-#define CG6_THC_MISC_INT_ENAB (1 << 5)
-#define CG6_THC_MISC_INT (1 << 4)
-#define CG6_THC_MISC_INIT 0x9f
+#define CG6_THC_MISC_REV_SHIFT 16
+#define CG6_THC_MISC_REV_MASK 15
+#define CG6_THC_MISC_RESET (1 << 12)
+#define CG6_THC_MISC_VIDEO (1 << 10)
+#define CG6_THC_MISC_SYNC (1 << 9)
+#define CG6_THC_MISC_VSYNC (1 << 8)
+#define CG6_THC_MISC_SYNC_ENAB (1 << 7)
+#define CG6_THC_MISC_CURS_RES (1 << 6)
+#define CG6_THC_MISC_INT_ENAB (1 << 5)
+#define CG6_THC_MISC_INT (1 << 4)
+#define CG6_THC_MISC_INIT 0x9f
/* The contents are unknown */
struct cg6_tec {
@@ -170,25 +170,25 @@ struct cg6_tec {
};
struct cg6_thc {
- u32 thc_pad0[512];
- u32 thc_hs; /* hsync timing */
- u32 thc_hsdvs;
- u32 thc_hd;
- u32 thc_vs; /* vsync timing */
- u32 thc_vd;
- u32 thc_refresh;
- u32 thc_misc;
- u32 thc_pad1[56];
- u32 thc_cursxy; /* cursor x,y position (16 bits each) */
- u32 thc_cursmask[32]; /* cursor mask bits */
- u32 thc_cursbits[32]; /* what to show where mask enabled */
+ u32 thc_pad0[512];
+ u32 thc_hs; /* hsync timing */
+ u32 thc_hsdvs;
+ u32 thc_hd;
+ u32 thc_vs; /* vsync timing */
+ u32 thc_vd;
+ u32 thc_refresh;
+ u32 thc_misc;
+ u32 thc_pad1[56];
+ u32 thc_cursxy; /* cursor x,y position (16 bits each) */
+ u32 thc_cursmask[32]; /* cursor mask bits */
+ u32 thc_cursbits[32]; /* what to show where mask enabled */
};
struct cg6_fbc {
u32 xxx0[1];
u32 mode;
u32 clip;
- u32 xxx1[1];
+ u32 xxx1[1];
u32 s;
u32 draw;
u32 blit;
@@ -243,10 +243,10 @@ struct cg6_fbc {
};
struct bt_regs {
- u32 addr;
- u32 color_map;
- u32 control;
- u32 cursor;
+ u32 addr;
+ u32 color_map;
+ u32 control;
+ u32 cursor;
};
struct cg6_par {
@@ -267,7 +267,7 @@ struct cg6_par {
static int cg6_sync(struct fb_info *info)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
struct cg6_fbc __iomem *fbc = par->fbc;
int limit = 10000;
@@ -281,24 +281,24 @@ static int cg6_sync(struct fb_info *info)
}
/**
- * cg6_fillrect - REQUIRED function. Can use generic routines if
- * non acclerated hardware and packed pixel based.
- * Draws a rectangle on the screen.
+ * cg6_fillrect - Draws a rectangle on the screen.
*
- * @info: frame buffer structure that represents a single frame buffer
- * @rect: structure defining the rectagle and operation.
+ * @info: frame buffer structure that represents a single frame buffer
+ * @rect: structure defining the rectagle and operation.
*/
static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
struct cg6_fbc __iomem *fbc = par->fbc;
unsigned long flags;
s32 val;
- /* XXX doesn't handle ROP_XOR */
+ /* CG6 doesn't handle ROP_XOR */
spin_lock_irqsave(&par->lock, flags);
+
cg6_sync(info);
+
sbus_writel(rect->color, &fbc->fg);
sbus_writel(~(u32)0, &fbc->pixelm);
sbus_writel(0xea80ff00, &fbc->alu);
@@ -316,16 +316,56 @@ static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
}
/**
- * cg6_imageblit - REQUIRED function. Can use generic routines if
- * non acclerated hardware and packed pixel based.
- * Copies a image from system memory to the screen.
+ * cg6_copyarea - Copies one area of the screen to another area.
+ *
+ * @info: frame buffer structure that represents a single frame buffer
+ * @area: Structure providing the data to copy the framebuffer contents
+ * from one region to another.
+ *
+ * This drawing operation copies a rectangular area from one area of the
+ * screen to another area.
+ */
+static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+ struct cg6_par *par = (struct cg6_par *)info->par;
+ struct cg6_fbc __iomem *fbc = par->fbc;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&par->lock, flags);
+
+ cg6_sync(info);
+
+ sbus_writel(0xff, &fbc->fg);
+ sbus_writel(0x00, &fbc->bg);
+ sbus_writel(~0, &fbc->pixelm);
+ sbus_writel(0xe880cccc, &fbc->alu);
+ sbus_writel(0, &fbc->s);
+ sbus_writel(0, &fbc->clip);
+
+ sbus_writel(area->sy, &fbc->y0);
+ sbus_writel(area->sx, &fbc->x0);
+ sbus_writel(area->sy + area->height - 1, &fbc->y1);
+ sbus_writel(area->sx + area->width - 1, &fbc->x1);
+ sbus_writel(area->dy, &fbc->y2);
+ sbus_writel(area->dx, &fbc->x2);
+ sbus_writel(area->dy + area->height - 1, &fbc->y3);
+ sbus_writel(area->dx + area->width - 1, &fbc->x3);
+ do {
+ i = sbus_readl(&fbc->blit);
+ } while (i < 0 && (i & 0x20000000));
+ spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ * cg6_imageblit - Copies a image from system memory to the screen.
*
- * @info: frame buffer structure that represents a single frame buffer
- * @image: structure defining the image.
+ * @info: frame buffer structure that represents a single frame buffer
+ * @image: structure defining the image.
*/
static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
struct cg6_fbc __iomem *fbc = par->fbc;
const u8 *data = image->data;
unsigned long flags;
@@ -363,7 +403,7 @@ static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
sbus_writel(y, &fbc->y0);
sbus_writel(x, &fbc->x0);
sbus_writel(x + 32 - 1, &fbc->x1);
-
+
val = ((u32)data[0] << 24) |
((u32)data[1] << 16) |
((u32)data[2] << 8) |
@@ -404,19 +444,20 @@ static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
}
/**
- * cg6_setcolreg - Optional function. Sets a color register.
- * @regno: boolean, 0 copy local, 1 get_user() function
- * @red: frame buffer colormap structure
- * @green: The green value which can be up to 16 bits wide
- * @blue: The blue value which can be up to 16 bits wide.
- * @transp: If supported the alpha value which can be up to 16 bits wide.
- * @info: frame buffer info structure
+ * cg6_setcolreg - Sets a color register.
+ *
+ * @regno: boolean, 0 copy local, 1 get_user() function
+ * @red: frame buffer colormap structure
+ * @green: The green value which can be up to 16 bits wide
+ * @blue: The blue value which can be up to 16 bits wide.
+ * @transp: If supported the alpha value which can be up to 16 bits wide.
+ * @info: frame buffer info structure
*/
static int cg6_setcolreg(unsigned regno,
unsigned red, unsigned green, unsigned blue,
unsigned transp, struct fb_info *info)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
struct bt_regs __iomem *bt = par->bt;
unsigned long flags;
@@ -440,25 +481,24 @@ static int cg6_setcolreg(unsigned regno,
}
/**
- * cg6_blank - Optional function. Blanks the display.
- * @blank_mode: the blank mode we want.
- * @info: frame buffer structure that represents a single frame buffer
+ * cg6_blank - Blanks the display.
+ *
+ * @blank_mode: the blank mode we want.
+ * @info: frame buffer structure that represents a single frame buffer
*/
-static int
-cg6_blank(int blank, struct fb_info *info)
+static int cg6_blank(int blank, struct fb_info *info)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
struct cg6_thc __iomem *thc = par->thc;
unsigned long flags;
u32 val;
spin_lock_irqsave(&par->lock, flags);
+ val = sbus_readl(&thc->thc_misc);
switch (blank) {
case FB_BLANK_UNBLANK: /* Unblanking */
- val = sbus_readl(&thc->thc_misc);
val |= CG6_THC_MISC_VIDEO;
- sbus_writel(val, &thc->thc_misc);
par->flags &= ~CG6_FLAG_BLANKED;
break;
@@ -466,13 +506,12 @@ cg6_blank(int blank, struct fb_info *info)
case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
case FB_BLANK_POWERDOWN: /* Poweroff */
- val = sbus_readl(&thc->thc_misc);
val &= ~CG6_THC_MISC_VIDEO;
- sbus_writel(val, &thc->thc_misc);
par->flags |= CG6_FLAG_BLANKED;
break;
}
+ sbus_writel(val, &thc->thc_misc);
spin_unlock_irqrestore(&par->lock, flags);
return 0;
@@ -533,7 +572,7 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma)
static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
return sbusfb_ioctl_helper(cmd, arg, info,
FBTYPE_SUNFAST_COLOR, 8, par->fbsize);
@@ -543,15 +582,14 @@ static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
* Initialisation
*/
-static void
-cg6_init_fix(struct fb_info *info, int linebytes)
+static void __devinit cg6_init_fix(struct fb_info *info, int linebytes)
{
struct cg6_par *par = (struct cg6_par *)info->par;
const char *cg6_cpu_name, *cg6_card_name;
u32 conf;
conf = sbus_readl(par->fhc);
- switch(conf & CG6_FHC_CPU_MASK) {
+ switch (conf & CG6_FHC_CPU_MASK) {
case CG6_FHC_CPU_SPARC:
cg6_cpu_name = "sparc";
break;
@@ -563,21 +601,19 @@ cg6_init_fix(struct fb_info *info, int linebytes)
break;
};
if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
- if (par->fbsize <= 0x100000) {
+ if (par->fbsize <= 0x100000)
cg6_card_name = "TGX";
- } else {
+ else
cg6_card_name = "TGX+";
- }
} else {
- if (par->fbsize <= 0x100000) {
+ if (par->fbsize <= 0x100000)
cg6_card_name = "GX";
- } else {
+ else
cg6_card_name = "GX+";
- }
}
sprintf(info->fix.id, "%s %s", cg6_card_name, cg6_cpu_name);
- info->fix.id[sizeof(info->fix.id)-1] = 0;
+ info->fix.id[sizeof(info->fix.id) - 1] = 0;
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
@@ -588,28 +624,28 @@ cg6_init_fix(struct fb_info *info, int linebytes)
}
/* Initialize Brooktree DAC */
-static void cg6_bt_init(struct cg6_par *par)
+static void __devinit cg6_bt_init(struct cg6_par *par)
{
struct bt_regs __iomem *bt = par->bt;
- sbus_writel(0x04 << 24, &bt->addr); /* color planes */
+ sbus_writel(0x04 << 24, &bt->addr); /* color planes */
sbus_writel(0xff << 24, &bt->control);
sbus_writel(0x05 << 24, &bt->addr);
sbus_writel(0x00 << 24, &bt->control);
- sbus_writel(0x06 << 24, &bt->addr); /* overlay plane */
+ sbus_writel(0x06 << 24, &bt->addr); /* overlay plane */
sbus_writel(0x73 << 24, &bt->control);
sbus_writel(0x07 << 24, &bt->addr);
sbus_writel(0x00 << 24, &bt->control);
}
-static void cg6_chip_init(struct fb_info *info)
+static void __devinit cg6_chip_init(struct fb_info *info)
{
- struct cg6_par *par = (struct cg6_par *) info->par;
+ struct cg6_par *par = (struct cg6_par *)info->par;
struct cg6_tec __iomem *tec = par->tec;
struct cg6_fbc __iomem *fbc = par->fbc;
u32 rev, conf, mode;
int i;
-
+
/* Turn off stuff in the Transform Engine. */
sbus_writel(0, &tec->tec_matrix);
sbus_writel(0, &tec->tec_clip);
@@ -635,13 +671,13 @@ static void cg6_chip_init(struct fb_info *info)
i = sbus_readl(&fbc->s);
} while (i & 0x10000000);
mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
- CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
- CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
- CG6_FBC_BDISP_MASK);
+ CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
+ CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
+ CG6_FBC_BDISP_MASK);
mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
- CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
- CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
- CG6_FBC_BDISP_0);
+ CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
+ CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
+ CG6_FBC_BDISP_0);
sbus_writel(mode, &fbc->mode);
sbus_writel(0, &fbc->clip);
@@ -671,7 +707,8 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
}
-static int __devinit cg6_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit cg6_probe(struct of_device *op,
+ const struct of_device_id *match)
{
struct device_node *dp = op->node;
struct fb_info *info;
@@ -705,22 +742,23 @@ static int __devinit cg6_probe(struct of_device *op, const struct of_device_id *
par->fbsize *= 4;
par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
- 4096, "cgsix fbc");
+ 4096, "cgsix fbc");
par->tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET,
- sizeof(struct cg6_tec), "cgsix tec");
+ sizeof(struct cg6_tec), "cgsix tec");
par->thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET,
- sizeof(struct cg6_thc), "cgsix thc");
+ sizeof(struct cg6_thc), "cgsix thc");
par->bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET,
- sizeof(struct bt_regs), "cgsix dac");
+ sizeof(struct bt_regs), "cgsix dac");
par->fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET,
- sizeof(u32), "cgsix fhc");
+ sizeof(u32), "cgsix fhc");
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
- FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
+ FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
+ FBINFO_READS_FAST;
info->fbops = &cg6_ops;
- info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
- par->fbsize, "cgsix ram");
+ info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
+ par->fbsize, "cgsix ram");
if (!par->fbc || !par->tec || !par->thc ||
!par->bt || !par->fhc || !info->screen_base)
goto out_unmap_regs;
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index 8269d704ab2..f7e2d5add83 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -45,7 +45,6 @@
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
-#include <linux/selection.h>
#include <asm/pgtable.h>
#ifdef CONFIG_ZORRO
@@ -59,14 +58,13 @@
#endif
#ifdef CONFIG_PPC_PREP
#include <asm/machdep.h>
-#define isPReP (machine_is(prep))
+#define isPReP machine_is(prep)
#else
#define isPReP 0
#endif
-#include "video/vga.h"
-#include "video/cirrus.h"
-
+#include <video/vga.h>
+#include <video/cirrus.h>
/*****************************************************************
*
@@ -82,7 +80,8 @@
/* debug output */
#ifdef CIRRUSFB_DEBUG
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#define DPRINTK(fmt, args...) \
+ printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#else
#define DPRINTK(fmt, args...)
#endif
@@ -90,19 +89,15 @@
/* debugging assertions */
#ifndef CIRRUSFB_NDEBUG
#define assert(expr) \
- if(!(expr)) { \
- printk( "Assertion failed! %s,%s,%s,line=%d\n",\
- #expr,__FILE__,__FUNCTION__,__LINE__); \
- }
+ if (!(expr)) { \
+ printk("Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr, __FILE__, __FUNCTION__, __LINE__); \
+ }
#else
#define assert(expr)
#endif
-#define MB_ (1024*1024)
-#define KB_ (1024)
-
-#define MAX_NUM_BOARDS 7
-
+#define MB_ (1024 * 1024)
/*****************************************************************
*
@@ -111,7 +106,7 @@
*/
/* board types */
-typedef enum {
+enum cirrus_board {
BT_NONE = 0,
BT_SD64,
BT_PICCOLO,
@@ -121,13 +116,12 @@ typedef enum {
BT_ALPINE, /* GD543x/4x */
BT_GD5480,
BT_LAGUNA, /* GD546x */
-} cirrusfb_board_t;
-
+};
/*
* per-board-type information, used for enumerating and abstracting
* chip-specific information
- * NOTE: MUST be in the same order as cirrusfb_board_t in order to
+ * NOTE: MUST be in the same order as enum cirrus_board in order to
* use direct indexing on this array
* NOTE: '__initdata' cannot be used as some of this info
* is required at runtime. Maybe separate into an init-only and
@@ -139,7 +133,8 @@ static const struct cirrusfb_board_info_rec {
/* for 1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */
bool init_sr07 : 1; /* init SR07 during init_vgachip() */
bool init_sr1f : 1; /* write SR1F during init_vgachip() */
- bool scrn_start_bit19 : 1; /* construct bit 19 of screen start address */
+ /* construct bit 19 of screen start address */
+ bool scrn_start_bit19 : 1;
/* initial SR07 value, then for each mode */
unsigned char sr07;
@@ -261,30 +256,28 @@ static const struct cirrusfb_board_info_rec {
}
};
-
#ifdef CONFIG_PCI
#define CHIP(id, btype) \
{ PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) }
static struct pci_device_id cirrusfb_pci_table[] = {
- CHIP( PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE ),
- CHIP( PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE ),
- CHIP( PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE ),
- CHIP( PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE ), /* GD-5440 is same id */
- CHIP( PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE ),
- CHIP( PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE ),
- CHIP( PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480 ), /* MacPicasso likely */
- CHIP( PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4 ), /* Picasso 4 is 5446 */
- CHIP( PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA ), /* CL Laguna */
- CHIP( PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA ), /* CL Laguna 3D */
- CHIP( PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA ), /* CL Laguna 3DA*/
+ CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE),
+ CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE),
+ CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE),
+ CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */
+ CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE),
+ CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE),
+ CHIP(PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480), /* MacPicasso likely */
+ CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */
+ CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */
+ CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */
+ CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA), /* CL Laguna 3DA*/
{ 0, }
};
MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
#undef CHIP
#endif /* CONFIG_PCI */
-
#ifdef CONFIG_ZORRO
static const struct zorro_device_id cirrusfb_zorro_table[] = {
{
@@ -294,7 +287,7 @@ static const struct zorro_device_id cirrusfb_zorro_table[] = {
.id = ZORRO_PROD_HELFRICH_PICCOLO_RAM,
.driver_data = BT_PICCOLO,
}, {
- .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
+ .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
.driver_data = BT_PICASSO,
}, {
.id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
@@ -333,12 +326,7 @@ static const struct {
};
#endif /* CONFIG_ZORRO */
-
struct cirrusfb_regs {
- __u32 line_length; /* in BYTES! */
- __u32 visual;
- __u32 type;
-
long freq;
long nom;
long den;
@@ -364,37 +352,23 @@ struct cirrusfb_regs {
long VertBlankEnd;
};
-
-
#ifdef CIRRUSFB_DEBUG
-typedef enum {
- CRT,
- SEQ
-} cirrusfb_dbg_reg_class_t;
-#endif /* CIRRUSFB_DEBUG */
-
-
-
+enum cirrusfb_dbg_reg_class {
+ CRT,
+ SEQ
+};
+#endif /* CIRRUSFB_DEBUG */
/* info about board */
struct cirrusfb_info {
- struct fb_info *info;
-
- u8 __iomem *fbmem;
u8 __iomem *regbase;
- u8 __iomem *mem;
- unsigned long size;
- cirrusfb_board_t btype;
+ enum cirrus_board btype;
unsigned char SFR; /* Shadow of special function register */
- unsigned long fbmem_phys;
- unsigned long fbregs_phys;
-
struct cirrusfb_regs currentmode;
int blank_mode;
u32 pseudo_palette[16];
- struct { u8 red, green, blue, pad; } palette[256];
#ifdef CONFIG_ZORRO
struct zorro_dev *zdev;
@@ -402,12 +376,11 @@ struct cirrusfb_info {
#ifdef CONFIG_PCI
struct pci_dev *pdev;
#endif
- void (*unmap)(struct cirrusfb_info *cinfo);
+ void (*unmap)(struct fb_info *info);
};
-
static unsigned cirrusfb_def_mode = 1;
-static int noaccel = 0;
+static int noaccel;
/*
* Predefined Video Modes
@@ -441,7 +414,7 @@ static const struct {
.lower_margin = 8,
.hsync_len = 96,
.vsync_len = 4,
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.vmode = FB_VMODE_NONINTERLACED
}
}, {
@@ -502,27 +475,29 @@ static const struct {
/****************************************************************************/
/**** BEGIN PROTOTYPES ******************************************************/
-
/*--- Interface used by the world ------------------------------------------*/
-static int cirrusfb_init (void);
+static int cirrusfb_init(void);
#ifndef MODULE
-static int cirrusfb_setup (char *options);
+static int cirrusfb_setup(char *options);
#endif
-static int cirrusfb_open (struct fb_info *info, int user);
-static int cirrusfb_release (struct fb_info *info, int user);
-static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *info);
-static int cirrusfb_check_var (struct fb_var_screeninfo *var,
- struct fb_info *info);
-static int cirrusfb_set_par (struct fb_info *info);
-static int cirrusfb_pan_display (struct fb_var_screeninfo *var,
- struct fb_info *info);
-static int cirrusfb_blank (int blank_mode, struct fb_info *info);
-static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region);
-static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
-static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image);
+static int cirrusfb_open(struct fb_info *info, int user);
+static int cirrusfb_release(struct fb_info *info, int user);
+static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info);
+static int cirrusfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info);
+static int cirrusfb_set_par(struct fb_info *info);
+static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info);
+static int cirrusfb_blank(int blank_mode, struct fb_info *info);
+static void cirrusfb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *region);
+static void cirrusfb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area);
+static void cirrusfb_imageblit(struct fb_info *info,
+ const struct fb_image *image);
/* function table of the above functions */
static struct fb_ops cirrusfb_ops = {
@@ -540,68 +515,68 @@ static struct fb_ops cirrusfb_ops = {
};
/*--- Hardware Specific Routines -------------------------------------------*/
-static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
+static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
struct cirrusfb_regs *regs,
- const struct fb_info *info);
+ struct fb_info *info);
/*--- Internal routines ----------------------------------------------------*/
-static void init_vgachip (struct cirrusfb_info *cinfo);
-static void switch_monitor (struct cirrusfb_info *cinfo, int on);
-static void WGen (const struct cirrusfb_info *cinfo,
- int regnum, unsigned char val);
-static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum);
-static void AttrOn (const struct cirrusfb_info *cinfo);
-static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val);
-static void WSFR (struct cirrusfb_info *cinfo, unsigned char val);
-static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val);
-static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
- unsigned char green,
- unsigned char blue);
+static void init_vgachip(struct fb_info *info);
+static void switch_monitor(struct cirrusfb_info *cinfo, int on);
+static void WGen(const struct cirrusfb_info *cinfo,
+ int regnum, unsigned char val);
+static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum);
+static void AttrOn(const struct cirrusfb_info *cinfo);
+static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val);
+static void WSFR(struct cirrusfb_info *cinfo, unsigned char val);
+static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val);
+static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum,
+ unsigned char red, unsigned char green, unsigned char blue);
#if 0
-static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
- unsigned char *green,
- unsigned char *blue);
+static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum,
+ unsigned char *red, unsigned char *green,
+ unsigned char *blue);
#endif
-static void cirrusfb_WaitBLT (u8 __iomem *regbase);
-static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel,
- u_short curx, u_short cury,
- u_short destx, u_short desty,
- u_short width, u_short height,
- u_short line_length);
-static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel,
- u_short x, u_short y,
- u_short width, u_short height,
- u_char color, u_short line_length);
-
-static void bestclock (long freq, long *best,
- long *nom, long *den,
- long *div, long maxfreq);
+static void cirrusfb_WaitBLT(u8 __iomem *regbase);
+static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
+ u_short curx, u_short cury,
+ u_short destx, u_short desty,
+ u_short width, u_short height,
+ u_short line_length);
+static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
+ u_short x, u_short y,
+ u_short width, u_short height,
+ u_char color, u_short line_length);
+
+static void bestclock(long freq, long *best,
+ long *nom, long *den,
+ long *div, long maxfreq);
#ifdef CIRRUSFB_DEBUG
-static void cirrusfb_dump (void);
-static void cirrusfb_dbg_reg_dump (caddr_t regbase);
-static void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...);
-static void cirrusfb_dbg_print_byte (const char *name, unsigned char val);
+static void cirrusfb_dump(void);
+static void cirrusfb_dbg_reg_dump(caddr_t regbase);
+static void cirrusfb_dbg_print_regs(caddr_t regbase,
+ enum cirrusfb_dbg_reg_class reg_class, ...);
+static void cirrusfb_dbg_print_byte(const char *name, unsigned char val);
#endif /* CIRRUSFB_DEBUG */
/*** END PROTOTYPES ********************************************************/
/*****************************************************************************/
/*** BEGIN Interface Used by the World ***************************************/
-static int opencount = 0;
+static int opencount;
/*--- Open /dev/fbx ---------------------------------------------------------*/
-static int cirrusfb_open (struct fb_info *info, int user)
+static int cirrusfb_open(struct fb_info *info, int user)
{
if (opencount++ == 0)
- switch_monitor (info->par, 1);
+ switch_monitor(info->par, 1);
return 0;
}
/*--- Close /dev/fbx --------------------------------------------------------*/
-static int cirrusfb_release (struct fb_info *info, int user)
+static int cirrusfb_release(struct fb_info *info, int user)
{
if (--opencount == 0)
- switch_monitor (info->par, 0);
+ switch_monitor(info->par, 0);
return 0;
}
@@ -610,11 +585,11 @@ static int cirrusfb_release (struct fb_info *info, int user)
/**** BEGIN Hardware specific Routines **************************************/
/* Get a good MCLK value */
-static long cirrusfb_get_mclk (long freq, int bpp, long *div)
+static long cirrusfb_get_mclk(long freq, int bpp, long *div)
{
long mclk;
- assert (div != NULL);
+ assert(div != NULL);
/* Calculate MCLK, in case VCLK is high enough to require > 50MHz.
* Assume a 64-bit data path for now. The formula is:
@@ -624,23 +599,23 @@ static long cirrusfb_get_mclk (long freq, int bpp, long *div)
mclk = (mclk * 12) / 10;
if (mclk < 50000)
mclk = 50000;
- DPRINTK ("Use MCLK of %ld kHz\n", mclk);
+ DPRINTK("Use MCLK of %ld kHz\n", mclk);
/* Calculate value for SR1F. Multiply by 2 so we can round up. */
mclk = ((mclk * 16) / 14318);
mclk = (mclk + 1) / 2;
- DPRINTK ("Set SR1F[5:0] to 0x%lx\n", mclk);
+ DPRINTK("Set SR1F[5:0] to 0x%lx\n", mclk);
/* Determine if we should use MCLK instead of VCLK, and if so, what we
* should divide it by to get VCLK */
switch (freq) {
case 24751 ... 25249:
*div = 2;
- DPRINTK ("Using VCLK = MCLK/2\n");
+ DPRINTK("Using VCLK = MCLK/2\n");
break;
case 49501 ... 50499:
*div = 1;
- DPRINTK ("Using VCLK = MCLK\n");
+ DPRINTK("Using VCLK = MCLK\n");
break;
default:
*div = 0;
@@ -653,7 +628,6 @@ static long cirrusfb_get_mclk (long freq, int bpp, long *div)
static int cirrusfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
- struct cirrusfb_info *cinfo = info->par;
int nom, den; /* translyting from pixels->bytes */
int yres, i;
static struct { int xres, yres; } modes[] =
@@ -665,63 +639,55 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
{ -1, -1 } };
switch (var->bits_per_pixel) {
- case 0 ... 1:
- var->bits_per_pixel = 1;
+ case 1:
nom = 4;
den = 8;
break; /* 8 pixel per byte, only 1/4th of mem usable */
- case 2 ... 8:
- var->bits_per_pixel = 8;
- nom = 1;
+ case 8:
+ case 16:
+ case 24:
+ case 32:
+ nom = var->bits_per_pixel / 8;
den = 1;
break; /* 1 pixel == 1 byte */
- case 9 ... 16:
- var->bits_per_pixel = 16;
- nom = 2;
- den = 1;
- break; /* 2 bytes per pixel */
- case 17 ... 24:
- var->bits_per_pixel = 24;
- nom = 3;
- den = 1;
- break; /* 3 bytes per pixel */
- case 25 ... 32:
- var->bits_per_pixel = 32;
- nom = 4;
- den = 1;
- break; /* 4 bytes per pixel */
default:
- printk ("cirrusfb: mode %dx%dx%d rejected...color depth not supported.\n",
+ printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
+ "color depth not supported.\n",
var->xres, var->yres, var->bits_per_pixel);
- DPRINTK ("EXIT - EINVAL error\n");
+ DPRINTK("EXIT - EINVAL error\n");
return -EINVAL;
}
- if (var->xres * nom / den * var->yres > cinfo->size) {
- printk ("cirrusfb: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
+ if (var->xres * nom / den * var->yres > info->screen_size) {
+ printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
+ "resolution too high to fit into video memory!\n",
var->xres, var->yres, var->bits_per_pixel);
- DPRINTK ("EXIT - EINVAL error\n");
+ DPRINTK("EXIT - EINVAL error\n");
return -EINVAL;
}
/* use highest possible virtual resolution */
if (var->xres_virtual == -1 &&
var->yres_virtual == -1) {
- printk ("cirrusfb: using maximum available virtual resolution\n");
+ printk(KERN_INFO
+ "cirrusfb: using maximum available virtual resolution\n");
for (i = 0; modes[i].xres != -1; i++) {
- if (modes[i].xres * nom / den * modes[i].yres < cinfo->size / 2)
+ int size = modes[i].xres * nom / den * modes[i].yres;
+ if (size < info->screen_size / 2)
break;
}
if (modes[i].xres == -1) {
- printk ("cirrusfb: could not find a virtual resolution that fits into video memory!!\n");
- DPRINTK ("EXIT - EINVAL error\n");
+ printk(KERN_ERR "cirrusfb: could not find a virtual "
+ "resolution that fits into video memory!!\n");
+ DPRINTK("EXIT - EINVAL error\n");
return -EINVAL;
}
var->xres_virtual = modes[i].xres;
var->yres_virtual = modes[i].yres;
- printk ("cirrusfb: virtual resolution set to maximum of %dx%d\n",
- var->xres_virtual, var->yres_virtual);
+ printk(KERN_INFO "cirrusfb: virtual resolution set to "
+ "maximum of %dx%d\n", var->xres_virtual,
+ var->yres_virtual);
}
if (var->xres_virtual < var->xres)
@@ -744,23 +710,19 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
case 1:
var->red.offset = 0;
var->red.length = 1;
- var->green.offset = 0;
- var->green.length = 1;
- var->blue.offset = 0;
- var->blue.length = 1;
+ var->green = var->red;
+ var->blue = var->red;
break;
case 8:
var->red.offset = 0;
var->red.length = 6;
- var->green.offset = 0;
- var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 6;
+ var->green = var->red;
+ var->blue = var->red;
break;
case 16:
- if(isPReP) {
+ if (isPReP) {
var->red.offset = 2;
var->green.offset = -3;
var->blue.offset = 8;
@@ -775,22 +737,8 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
break;
case 24:
- if(isPReP) {
- var->red.offset = 8;
- var->green.offset = 16;
- var->blue.offset = 24;
- } else {
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
- }
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- break;
-
case 32:
- if(isPReP) {
+ if (isPReP) {
var->red.offset = 8;
var->green.offset = 16;
var->blue.offset = 24;
@@ -825,54 +773,42 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
yres = (yres + 1) / 2;
if (yres >= 1280) {
- printk (KERN_WARNING "cirrusfb: ERROR: VerticalTotal >= 1280; special treatment required! (TODO)\n");
- DPRINTK ("EXIT - EINVAL error\n");
+ printk(KERN_ERR "cirrusfb: ERROR: VerticalTotal >= 1280; "
+ "special treatment required! (TODO)\n");
+ DPRINTK("EXIT - EINVAL error\n");
return -EINVAL;
}
return 0;
}
-static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
+static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
struct cirrusfb_regs *regs,
- const struct fb_info *info)
+ struct fb_info *info)
{
long freq;
long maxclock;
- int maxclockidx = 0;
+ int maxclockidx = var->bits_per_pixel >> 3;
struct cirrusfb_info *cinfo = info->par;
int xres, hfront, hsync, hback;
int yres, vfront, vsync, vback;
- switch(var->bits_per_pixel) {
+ switch (var->bits_per_pixel) {
case 1:
- regs->line_length = var->xres_virtual / 8;
- regs->visual = FB_VISUAL_MONO10;
- maxclockidx = 0;
+ info->fix.line_length = var->xres_virtual / 8;
+ info->fix.visual = FB_VISUAL_MONO10;
break;
case 8:
- regs->line_length = var->xres_virtual;
- regs->visual = FB_VISUAL_PSEUDOCOLOR;
- maxclockidx = 1;
+ info->fix.line_length = var->xres_virtual;
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
break;
case 16:
- regs->line_length = var->xres_virtual * 2;
- regs->visual = FB_VISUAL_DIRECTCOLOR;
- maxclockidx = 2;
- break;
-
case 24:
- regs->line_length = var->xres_virtual * 3;
- regs->visual = FB_VISUAL_DIRECTCOLOR;
- maxclockidx = 3;
- break;
-
case 32:
- regs->line_length = var->xres_virtual * 4;
- regs->visual = FB_VISUAL_DIRECTCOLOR;
- maxclockidx = 4;
+ info->fix.line_length = var->xres_virtual * maxclockidx;
+ info->fix.visual = FB_VISUAL_DIRECTCOLOR;
break;
default:
@@ -882,12 +818,12 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
break;
}
- regs->type = FB_TYPE_PACKED_PIXELS;
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
/* convert from ps to kHz */
- freq = 1000000000 / var->pixclock;
+ freq = PICOS2KHZ(var->pixclock);
- DPRINTK ("desired pixclock: %ld kHz\n", freq);
+ DPRINTK("desired pixclock: %ld kHz\n", freq);
maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
regs->multiplexing = 0;
@@ -902,8 +838,9 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
break;
default:
- printk (KERN_WARNING "cirrusfb: ERROR: Frequency greater than maxclock (%ld kHz)\n", maxclock);
- DPRINTK ("EXIT - return -EINVAL\n");
+ printk(KERN_ERR "cirrusfb: Frequency greater "
+ "than maxclock (%ld kHz)\n", maxclock);
+ DPRINTK("EXIT - return -EINVAL\n");
return -EINVAL;
}
}
@@ -914,14 +851,16 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
case 16:
case 32:
if (regs->HorizRes <= 800)
- freq /= 2; /* Xbh has this type of clock for 32-bit */
+ /* Xbh has this type of clock for 32-bit */
+ freq /= 2;
break;
}
#endif
- bestclock (freq, &regs->freq, &regs->nom, &regs->den, &regs->div,
- maxclock);
- regs->mclk = cirrusfb_get_mclk (freq, var->bits_per_pixel, &regs->divMCLK);
+ bestclock(freq, &regs->freq, &regs->nom, &regs->den, &regs->div,
+ maxclock);
+ regs->mclk = cirrusfb_get_mclk(freq, var->bits_per_pixel,
+ &regs->divMCLK);
xres = var->xres;
hfront = var->right_margin;
@@ -948,7 +887,8 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
regs->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5;
regs->HorizDispEnd = xres / 8 - 1;
regs->HorizBlankStart = xres / 8;
- regs->HorizBlankEnd = regs->HorizTotal + 5; /* does not count with "-5" */
+ /* does not count with "-5" */
+ regs->HorizBlankEnd = regs->HorizTotal + 5;
regs->HorizSyncStart = (xres + hfront) / 8 + 1;
regs->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1;
@@ -976,23 +916,23 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
return 0;
}
-
-static void cirrusfb_set_mclk (const struct cirrusfb_info *cinfo, int val, int div)
+static void cirrusfb_set_mclk(const struct cirrusfb_info *cinfo, int val,
+ int div)
{
- assert (cinfo != NULL);
+ assert(cinfo != NULL);
if (div == 2) {
/* VCLK = MCLK/2 */
- unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E);
- vga_wseq (cinfo->regbase, CL_SEQR1E, old | 0x1);
- vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
+ unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E);
+ vga_wseq(cinfo->regbase, CL_SEQR1E, old | 0x1);
+ vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
} else if (div == 1) {
/* VCLK = MCLK */
- unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E);
- vga_wseq (cinfo->regbase, CL_SEQR1E, old & ~0x1);
- vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
+ unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E);
+ vga_wseq(cinfo->regbase, CL_SEQR1E, old & ~0x1);
+ vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
} else {
- vga_wseq (cinfo->regbase, CL_SEQR1F, val & 0x3f);
+ vga_wseq(cinfo->regbase, CL_SEQR1F, val & 0x3f);
}
}
@@ -1001,7 +941,7 @@ static void cirrusfb_set_mclk (const struct cirrusfb_info *cinfo, int val, int d
actually writes the values for a new video mode into the hardware,
**************************************************************************/
-static int cirrusfb_set_par_foo (struct fb_info *info)
+static int cirrusfb_set_par_foo(struct fb_info *info)
{
struct cirrusfb_info *cinfo = info->par;
struct fb_var_screeninfo *var = &info->var;
@@ -1011,15 +951,15 @@ static int cirrusfb_set_par_foo (struct fb_info *info)
int offset = 0, err;
const struct cirrusfb_board_info_rec *bi;
- DPRINTK ("ENTER\n");
- DPRINTK ("Requested mode: %dx%dx%d\n",
+ DPRINTK("ENTER\n");
+ DPRINTK("Requested mode: %dx%dx%d\n",
var->xres, var->yres, var->bits_per_pixel);
- DPRINTK ("pixclock: %d\n", var->pixclock);
+ DPRINTK("pixclock: %d\n", var->pixclock);
- init_vgachip (cinfo);
+ init_vgachip(info);
err = cirrusfb_decode_var(var, &regs, info);
- if(err) {
+ if (err) {
/* should never happen */
DPRINTK("mode change aborted. invalid var.\n");
return -EINVAL;
@@ -1027,34 +967,35 @@ static int cirrusfb_set_par_foo (struct fb_info *info)
bi = &cirrusfb_board_info[cinfo->btype];
-
/* unlock register VGA_CRTC_H_TOTAL..CRT7 */
- vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */
+ vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */
/* if debugging is enabled, all parameters get output before writing */
- DPRINTK ("CRT0: %ld\n", regs.HorizTotal);
- vga_wcrt (regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal);
+ DPRINTK("CRT0: %ld\n", regs.HorizTotal);
+ vga_wcrt(regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal);
- DPRINTK ("CRT1: %ld\n", regs.HorizDispEnd);
- vga_wcrt (regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd);
+ DPRINTK("CRT1: %ld\n", regs.HorizDispEnd);
+ vga_wcrt(regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd);
- DPRINTK ("CRT2: %ld\n", regs.HorizBlankStart);
- vga_wcrt (regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart);
+ DPRINTK("CRT2: %ld\n", regs.HorizBlankStart);
+ vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart);
- DPRINTK ("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32); /* + 128: Compatible read */
- vga_wcrt (regbase, VGA_CRTC_H_BLANK_END, 128 + (regs.HorizBlankEnd % 32));
+ /* + 128: Compatible read */
+ DPRINTK("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32);
+ vga_wcrt(regbase, VGA_CRTC_H_BLANK_END,
+ 128 + (regs.HorizBlankEnd % 32));
- DPRINTK ("CRT4: %ld\n", regs.HorizSyncStart);
- vga_wcrt (regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart);
+ DPRINTK("CRT4: %ld\n", regs.HorizSyncStart);
+ vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart);
tmp = regs.HorizSyncEnd % 32;
if (regs.HorizBlankEnd & 32)
tmp += 128;
- DPRINTK ("CRT5: %d\n", tmp);
- vga_wcrt (regbase, VGA_CRTC_H_SYNC_END, tmp);
+ DPRINTK("CRT5: %d\n", tmp);
+ vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp);
- DPRINTK ("CRT6: %ld\n", regs.VertTotal & 0xff);
- vga_wcrt (regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff));
+ DPRINTK("CRT6: %ld\n", regs.VertTotal & 0xff);
+ vga_wcrt(regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff));
tmp = 16; /* LineCompare bit #9 */
if (regs.VertTotal & 256)
@@ -1071,34 +1012,34 @@ static int cirrusfb_set_par_foo (struct fb_info *info)
tmp |= 64;
if (regs.VertSyncStart & 512)
tmp |= 128;
- DPRINTK ("CRT7: %d\n", tmp);
- vga_wcrt (regbase, VGA_CRTC_OVERFLOW, tmp);
+ DPRINTK("CRT7: %d\n", tmp);
+ vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp);
tmp = 0x40; /* LineCompare bit #8 */
if (regs.VertBlankStart & 512)
tmp |= 0x20;
if (var->vmode & FB_VMODE_DOUBLE)
tmp |= 0x80;
- DPRINTK ("CRT9: %d\n", tmp);
- vga_wcrt (regbase, VGA_CRTC_MAX_SCAN, tmp);
+ DPRINTK("CRT9: %d\n", tmp);
+ vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp);
- DPRINTK ("CRT10: %ld\n", regs.VertSyncStart & 0xff);
- vga_wcrt (regbase, VGA_CRTC_V_SYNC_START, (regs.VertSyncStart & 0xff));
+ DPRINTK("CRT10: %ld\n", regs.VertSyncStart & 0xff);
+ vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, regs.VertSyncStart & 0xff);
- DPRINTK ("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16);
- vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, (regs.VertSyncEnd % 16 + 64 + 32));
+ DPRINTK("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16);
+ vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, regs.VertSyncEnd % 16 + 64 + 32);
- DPRINTK ("CRT12: %ld\n", regs.VertDispEnd & 0xff);
- vga_wcrt (regbase, VGA_CRTC_V_DISP_END, (regs.VertDispEnd & 0xff));
+ DPRINTK("CRT12: %ld\n", regs.VertDispEnd & 0xff);
+ vga_wcrt(regbase, VGA_CRTC_V_DISP_END, regs.VertDispEnd & 0xff);
- DPRINTK ("CRT15: %ld\n", regs.VertBlankStart & 0xff);
- vga_wcrt (regbase, VGA_CRTC_V_BLANK_START, (regs.VertBlankStart & 0xff));
+ DPRINTK("CRT15: %ld\n", regs.VertBlankStart & 0xff);
+ vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, regs.VertBlankStart & 0xff);
- DPRINTK ("CRT16: %ld\n", regs.VertBlankEnd & 0xff);
- vga_wcrt (regbase, VGA_CRTC_V_BLANK_END, (regs.VertBlankEnd & 0xff));
+ DPRINTK("CRT16: %ld\n", regs.VertBlankEnd & 0xff);
+ vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, regs.VertBlankEnd & 0xff);
- DPRINTK ("CRT18: 0xff\n");
- vga_wcrt (regbase, VGA_CRTC_LINE_COMPARE, 0xff);
+ DPRINTK("CRT18: 0xff\n");
+ vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff);
tmp = 0;
if (var->vmode & FB_VMODE_INTERLACED)
@@ -1112,57 +1053,63 @@ static int cirrusfb_set_par_foo (struct fb_info *info)
if (regs.VertBlankEnd & 512)
tmp |= 128;
- DPRINTK ("CRT1a: %d\n", tmp);
- vga_wcrt (regbase, CL_CRT1A, tmp);
+ DPRINTK("CRT1a: %d\n", tmp);
+ vga_wcrt(regbase, CL_CRT1A, tmp);
/* set VCLK0 */
/* hardware RefClock: 14.31818 MHz */
/* formula: VClk = (OSC * N) / (D * (1+P)) */
/* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
- vga_wseq (regbase, CL_SEQRB, regs.nom);
+ vga_wseq(regbase, CL_SEQRB, regs.nom);
tmp = regs.den << 1;
if (regs.div != 0)
tmp |= 1;
+ /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
if ((cinfo->btype == BT_SD64) ||
(cinfo->btype == BT_ALPINE) ||
(cinfo->btype == BT_GD5480))
- tmp |= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
+ tmp |= 0x80;
- DPRINTK ("CL_SEQR1B: %ld\n", (long) tmp);
- vga_wseq (regbase, CL_SEQR1B, tmp);
+ DPRINTK("CL_SEQR1B: %ld\n", (long) tmp);
+ vga_wseq(regbase, CL_SEQR1B, tmp);
if (regs.VertRes >= 1024)
/* 1280x1024 */
- vga_wcrt (regbase, VGA_CRTC_MODE, 0xc7);
+ vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7);
else
/* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
* address wrap, no compat. */
- vga_wcrt (regbase, VGA_CRTC_MODE, 0xc3);
+ vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3);
-/* HAEH? vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20); * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */
+/* HAEH? vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);
+ * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */
/* don't know if it would hurt to also program this if no interlaced */
/* mode is used, but I feel better this way.. :-) */
if (var->vmode & FB_VMODE_INTERLACED)
- vga_wcrt (regbase, VGA_CRTC_REGS, regs.HorizTotal / 2);
+ vga_wcrt(regbase, VGA_CRTC_REGS, regs.HorizTotal / 2);
else
- vga_wcrt (regbase, VGA_CRTC_REGS, 0x00); /* interlace control */
+ vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */
- vga_wseq (regbase, VGA_SEQ_CHARACTER_MAP, 0);
+ vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0);
/* adjust horizontal/vertical sync type (low/high) */
- tmp = 0x03; /* enable display memory & CRTC I/O address for color mode */
+ /* enable display memory & CRTC I/O address for color mode */
+ tmp = 0x03;
if (var->sync & FB_SYNC_HOR_HIGH_ACT)
tmp |= 0x40;
if (var->sync & FB_SYNC_VERT_HIGH_ACT)
tmp |= 0x80;
- WGen (cinfo, VGA_MIS_W, tmp);
+ WGen(cinfo, VGA_MIS_W, tmp);
- vga_wcrt (regbase, VGA_CRTC_PRESET_ROW, 0); /* Screen A Preset Row-Scan register */
- vga_wcrt (regbase, VGA_CRTC_CURSOR_START, 0); /* text cursor on and start line */
- vga_wcrt (regbase, VGA_CRTC_CURSOR_END, 31); /* text cursor end line */
+ /* Screen A Preset Row-Scan register */
+ vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0);
+ /* text cursor on and start line */
+ vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0);
+ /* text cursor end line */
+ vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 31);
/******************************************************
*
@@ -1172,8 +1119,8 @@ static int cirrusfb_set_par_foo (struct fb_info *info)
/* programming for different color depths */
if (var->bits_per_pixel == 1) {
- DPRINTK ("cirrusfb: preparing for 1 bit deep display\n");
- vga_wgfx (regbase, VGA_GFX_MODE, 0); /* mode register */
+ DPRINTK("cirrusfb: preparing for 1 bit deep display\n");
+ vga_wgfx(regbase, VGA_GFX_MODE, 0); /* mode register */
/* SR07 */
switch (cinfo->btype) {
@@ -1184,71 +1131,77 @@ static int cirrusfb_set_par_foo (struct fb_info *info)
case BT_PICASSO4:
case BT_ALPINE:
case BT_GD5480:
- DPRINTK (" (for GD54xx)\n");
- vga_wseq (regbase, CL_SEQR7,
+ DPRINTK(" (for GD54xx)\n");
+ vga_wseq(regbase, CL_SEQR7,
regs.multiplexing ?
bi->sr07_1bpp_mux : bi->sr07_1bpp);
break;
case BT_LAGUNA:
- DPRINTK (" (for GD546x)\n");
- vga_wseq (regbase, CL_SEQR7,
- vga_rseq (regbase, CL_SEQR7) & ~0x01);
+ DPRINTK(" (for GD546x)\n");
+ vga_wseq(regbase, CL_SEQR7,
+ vga_rseq(regbase, CL_SEQR7) & ~0x01);
break;
default:
- printk (KERN_WARNING "cirrusfb: unknown Board\n");
+ printk(KERN_WARNING "cirrusfb: unknown Board\n");
break;
}
/* Extended Sequencer Mode */
switch (cinfo->btype) {
case BT_SD64:
- /* setting the SEQRF on SD64 is not necessary (only during init) */
- DPRINTK ("(for SD64)\n");
- vga_wseq (regbase, CL_SEQR1F, 0x1a); /* MCLK select */
+ /* setting the SEQRF on SD64 is not necessary
+ * (only during init)
+ */
+ DPRINTK("(for SD64)\n");
+ /* MCLK select */
+ vga_wseq(regbase, CL_SEQR1F, 0x1a);
break;
case BT_PICCOLO:
- DPRINTK ("(for Piccolo)\n");
-/* ### ueberall 0x22? */
- vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */
- vga_wseq (regbase, CL_SEQRF, 0xb0); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */
+ case BT_SPECTRUM:
+ DPRINTK("(for Piccolo/Spectrum)\n");
+ /* ### ueberall 0x22? */
+ /* ##vorher 1c MCLK select */
+ vga_wseq(regbase, CL_SEQR1F, 0x22);
+ /* evtl d0 bei 1 bit? avoid FIFO underruns..? */
+ vga_wseq(regbase, CL_SEQRF, 0xb0);
break;
case BT_PICASSO:
- DPRINTK ("(for Picasso)\n");
- vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 22 MCLK select */
- vga_wseq (regbase, CL_SEQRF, 0xd0); /* ## vorher d0 avoid FIFO underruns..? */
- break;
-
- case BT_SPECTRUM:
- DPRINTK ("(for Spectrum)\n");
-/* ### ueberall 0x22? */
- vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */
- vga_wseq (regbase, CL_SEQRF, 0xb0); /* evtl d0? avoid FIFO underruns..? */
+ DPRINTK("(for Picasso)\n");
+ /* ##vorher 22 MCLK select */
+ vga_wseq(regbase, CL_SEQR1F, 0x22);
+ /* ## vorher d0 avoid FIFO underruns..? */
+ vga_wseq(regbase, CL_SEQRF, 0xd0);
break;
case BT_PICASSO4:
case BT_ALPINE:
case BT_GD5480:
case BT_LAGUNA:
- DPRINTK (" (for GD54xx)\n");
+ DPRINTK(" (for GD54xx)\n");
/* do nothing */
break;
default:
- printk (KERN_WARNING "cirrusfb: unknown Board\n");
+ printk(KERN_WARNING "cirrusfb: unknown Board\n");
break;
}
- WGen (cinfo, VGA_PEL_MSK, 0x01); /* pixel mask: pass-through for first plane */
+ /* pixel mask: pass-through for first plane */
+ WGen(cinfo, VGA_PEL_MSK, 0x01);
if (regs.multiplexing)
- WHDR (cinfo, 0x4a); /* hidden dac reg: 1280x1024 */
+ /* hidden dac reg: 1280x1024 */
+ WHDR(cinfo, 0x4a);
else
- WHDR (cinfo, 0); /* hidden dac: nothing */
- vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x06); /* memory mode: odd/even, ext. memory */
- vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0x01); /* plane mask: only write to first plane */
+ /* hidden dac: nothing */
+ WHDR(cinfo, 0);
+ /* memory mode: odd/even, ext. memory */
+ vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06);
+ /* plane mask: only write to first plane */
+ vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01);
offset = var->xres_virtual / 16;
}
@@ -1259,7 +1212,7 @@ static int cirrusfb_set_par_foo (struct fb_info *info)
*/
else if (var->bits_per_pixel == 8) {
- DPRINTK ("cirrusfb: preparing for 8 bit deep display\n");
+ DPRINTK("cirrusfb: preparing for 8 bit deep display\n");
switch (cinfo->btype) {
case BT_SD64:
case BT_PICCOLO:
@@ -1268,75 +1221,77 @@ static int cirrusfb_set_par_foo (struct fb_info *info)
case BT_PICASSO4:
case BT_ALPINE:
case BT_GD5480:
- DPRINTK (" (for GD54xx)\n");
- vga_wseq (regbase, CL_SEQR7,
+ DPRINTK(" (for GD54xx)\n");
+ vga_wseq(regbase, CL_SEQR7,
regs.multiplexing ?
bi->sr07_8bpp_mux : bi->sr07_8bpp);
break;
case BT_LAGUNA:
- DPRINTK (" (for GD546x)\n");
- vga_wseq (regbase, CL_SEQR7,
- vga_rseq (regbase, CL_SEQR7) | 0x01);
+ DPRINTK(" (for GD546x)\n");
+ vga_wseq(regbase, CL_SEQR7,
+ vga_rseq(regbase, CL_SEQR7) | 0x01);
break;
default:
- printk (KERN_WARNING "cirrusfb: unknown Board\n");
+ printk(KERN_WARNING "cirrusfb: unknown Board\n");
break;
}
switch (cinfo->btype) {
case BT_SD64:
- vga_wseq (regbase, CL_SEQR1F, 0x1d); /* MCLK select */
+ /* MCLK select */
+ vga_wseq(regbase, CL_SEQR1F, 0x1d);
break;
case BT_PICCOLO:
- vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
- vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
- break;
-
case BT_PICASSO:
- vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
- vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
- break;
-
case BT_SPECTRUM:
- vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
- vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
+ /* ### vorher 1c MCLK select */
+ vga_wseq(regbase, CL_SEQR1F, 0x22);
+ /* Fast Page-Mode writes */
+ vga_wseq(regbase, CL_SEQRF, 0xb0);
break;
case BT_PICASSO4:
#ifdef CONFIG_ZORRO
- vga_wseq (regbase, CL_SEQRF, 0xb8); /* ### INCOMPLETE!! */
+ /* ### INCOMPLETE!! */
+ vga_wseq(regbase, CL_SEQRF, 0xb8);
#endif
-/* vga_wseq (regbase, CL_SEQR1F, 0x1c); */
+/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */
break;
case BT_ALPINE:
- DPRINTK (" (for GD543x)\n");
- cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK);
+ DPRINTK(" (for GD543x)\n");
+ cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
/* We already set SRF and SR1F */
break;
case BT_GD5480:
case BT_LAGUNA:
- DPRINTK (" (for GD54xx)\n");
+ DPRINTK(" (for GD54xx)\n");
/* do nothing */
break;
default:
- printk (KERN_WARNING "cirrusfb: unknown Board\n");
+ printk(KERN_WARNING "cirrusfb: unknown Board\n");
break;
}
- vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
- WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
+ /* mode register: 256 color mode */
+ vga_wgfx(regbase, VGA_GFX_MODE, 64);
+ /* pixel mask: pass-through all planes */
+ WGen(cinfo, VGA_PEL_MSK, 0xff);
if (regs.multiplexing)
- WHDR (cinfo, 0x4a); /* hidden dac reg: 1280x1024 */
+ /* hidden dac reg: 1280x1024 */
+ WHDR(cinfo, 0x4a);
else
- WHDR (cinfo, 0); /* hidden dac: nothing */
- vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
- vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
+ /* hidden dac: nothing */
+ WHDR(cinfo, 0);
+ /* memory mode: chain4, ext. memory */
+ vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
+ /* plane mask: enable writing to all 4 planes */
+ vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
offset = var->xres_virtual / 8;
}
@@ -1347,72 +1302,77 @@ static int cirrusfb_set_par_foo (struct fb_info *info)
*/
else if (var->bits_per_pixel == 16) {
- DPRINTK ("cirrusfb: preparing for 16 bit deep display\n");
+ DPRINTK("cirrusfb: preparing for 16 bit deep display\n");
switch (cinfo->btype) {
case BT_SD64:
- vga_wseq (regbase, CL_SEQR7, 0xf7); /* Extended Sequencer Mode: 256c col. mode */
- vga_wseq (regbase, CL_SEQR1F, 0x1e); /* MCLK select */
+ /* Extended Sequencer Mode: 256c col. mode */
+ vga_wseq(regbase, CL_SEQR7, 0xf7);
+ /* MCLK select */
+ vga_wseq(regbase, CL_SEQR1F, 0x1e);
break;
case BT_PICCOLO:
- vga_wseq (regbase, CL_SEQR7, 0x87);
- vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
- vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
+ case BT_SPECTRUM:
+ vga_wseq(regbase, CL_SEQR7, 0x87);
+ /* Fast Page-Mode writes */
+ vga_wseq(regbase, CL_SEQRF, 0xb0);
+ /* MCLK select */
+ vga_wseq(regbase, CL_SEQR1F, 0x22);
break;
case BT_PICASSO:
- vga_wseq (regbase, CL_SEQR7, 0x27);
- vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
- vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
- break;
-
- case BT_SPECTRUM:
- vga_wseq (regbase, CL_SEQR7, 0x87);
- vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
- vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
+ vga_wseq(regbase, CL_SEQR7, 0x27);
+ /* Fast Page-Mode writes */
+ vga_wseq(regbase, CL_SEQRF, 0xb0);
+ /* MCLK select */
+ vga_wseq(regbase, CL_SEQR1F, 0x22);
break;
case BT_PICASSO4:
- vga_wseq (regbase, CL_SEQR7, 0x27);
-/* vga_wseq (regbase, CL_SEQR1F, 0x1c); */
+ vga_wseq(regbase, CL_SEQR7, 0x27);
+/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */
break;
case BT_ALPINE:
- DPRINTK (" (for GD543x)\n");
+ DPRINTK(" (for GD543x)\n");
if (regs.HorizRes >= 1024)
- vga_wseq (regbase, CL_SEQR7, 0xa7);
+ vga_wseq(regbase, CL_SEQR7, 0xa7);
else
- vga_wseq (regbase, CL_SEQR7, 0xa3);
- cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK);
+ vga_wseq(regbase, CL_SEQR7, 0xa3);
+ cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
break;
case BT_GD5480:
- DPRINTK (" (for GD5480)\n");
- vga_wseq (regbase, CL_SEQR7, 0x17);
+ DPRINTK(" (for GD5480)\n");
+ vga_wseq(regbase, CL_SEQR7, 0x17);
/* We already set SRF and SR1F */
break;
case BT_LAGUNA:
- DPRINTK (" (for GD546x)\n");
- vga_wseq (regbase, CL_SEQR7,
- vga_rseq (regbase, CL_SEQR7) & ~0x01);
+ DPRINTK(" (for GD546x)\n");
+ vga_wseq(regbase, CL_SEQR7,
+ vga_rseq(regbase, CL_SEQR7) & ~0x01);
break;
default:
- printk (KERN_WARNING "CIRRUSFB: unknown Board\n");
+ printk(KERN_WARNING "CIRRUSFB: unknown Board\n");
break;
}
- vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
- WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
+ /* mode register: 256 color mode */
+ vga_wgfx(regbase, VGA_GFX_MODE, 64);
+ /* pixel mask: pass-through all planes */
+ WGen(cinfo, VGA_PEL_MSK, 0xff);
#ifdef CONFIG_PCI
- WHDR (cinfo, 0xc0); /* Copy Xbh */
+ WHDR(cinfo, 0xc0); /* Copy Xbh */
#elif defined(CONFIG_ZORRO)
/* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
- WHDR (cinfo, 0xa0); /* hidden dac reg: nothing special */
+ WHDR(cinfo, 0xa0); /* hidden dac reg: nothing special */
#endif
- vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
- vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
+ /* memory mode: chain4, ext. memory */
+ vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
+ /* plane mask: enable writing to all 4 planes */
+ vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
offset = var->xres_virtual / 4;
}
@@ -1423,64 +1383,70 @@ static int cirrusfb_set_par_foo (struct fb_info *info)
*/
else if (var->bits_per_pixel == 32) {
- DPRINTK ("cirrusfb: preparing for 24/32 bit deep display\n");
+ DPRINTK("cirrusfb: preparing for 24/32 bit deep display\n");
switch (cinfo->btype) {
case BT_SD64:
- vga_wseq (regbase, CL_SEQR7, 0xf9); /* Extended Sequencer Mode: 256c col. mode */
- vga_wseq (regbase, CL_SEQR1F, 0x1e); /* MCLK select */
+ /* Extended Sequencer Mode: 256c col. mode */
+ vga_wseq(regbase, CL_SEQR7, 0xf9);
+ /* MCLK select */
+ vga_wseq(regbase, CL_SEQR1F, 0x1e);
break;
case BT_PICCOLO:
- vga_wseq (regbase, CL_SEQR7, 0x85);
- vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
- vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
+ case BT_SPECTRUM:
+ vga_wseq(regbase, CL_SEQR7, 0x85);
+ /* Fast Page-Mode writes */
+ vga_wseq(regbase, CL_SEQRF, 0xb0);
+ /* MCLK select */
+ vga_wseq(regbase, CL_SEQR1F, 0x22);
break;
case BT_PICASSO:
- vga_wseq (regbase, CL_SEQR7, 0x25);
- vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
- vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
- break;
-
- case BT_SPECTRUM:
- vga_wseq (regbase, CL_SEQR7, 0x85);
- vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
- vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
+ vga_wseq(regbase, CL_SEQR7, 0x25);
+ /* Fast Page-Mode writes */
+ vga_wseq(regbase, CL_SEQRF, 0xb0);
+ /* MCLK select */
+ vga_wseq(regbase, CL_SEQR1F, 0x22);
break;
case BT_PICASSO4:
- vga_wseq (regbase, CL_SEQR7, 0x25);
-/* vga_wseq (regbase, CL_SEQR1F, 0x1c); */
+ vga_wseq(regbase, CL_SEQR7, 0x25);
+/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */
break;
case BT_ALPINE:
- DPRINTK (" (for GD543x)\n");
- vga_wseq (regbase, CL_SEQR7, 0xa9);
- cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK);
+ DPRINTK(" (for GD543x)\n");
+ vga_wseq(regbase, CL_SEQR7, 0xa9);
+ cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
break;
case BT_GD5480:
- DPRINTK (" (for GD5480)\n");
- vga_wseq (regbase, CL_SEQR7, 0x19);
+ DPRINTK(" (for GD5480)\n");
+ vga_wseq(regbase, CL_SEQR7, 0x19);
/* We already set SRF and SR1F */
break;
case BT_LAGUNA:
- DPRINTK (" (for GD546x)\n");
- vga_wseq (regbase, CL_SEQR7,
- vga_rseq (regbase, CL_SEQR7) & ~0x01);
+ DPRINTK(" (for GD546x)\n");
+ vga_wseq(regbase, CL_SEQR7,
+ vga_rseq(regbase, CL_SEQR7) & ~0x01);
break;
default:
- printk (KERN_WARNING "cirrusfb: unknown Board\n");
+ printk(KERN_WARNING "cirrusfb: unknown Board\n");
break;
}
- vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
- WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
- WHDR (cinfo, 0xc5); /* hidden dac reg: 8-8-8 mode (24 or 32) */
- vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
- vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
+ /* mode register: 256 color mode */
+ vga_wgfx(regbase, VGA_GFX_MODE, 64);
+ /* pixel mask: pass-through all planes */
+ WGen(cinfo, VGA_PEL_MSK, 0xff);
+ /* hidden dac reg: 8-8-8 mode (24 or 32) */
+ WHDR(cinfo, 0xc5);
+ /* memory mode: chain4, ext. memory */
+ vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
+ /* plane mask: enable writing to all 4 planes */
+ vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff);
offset = var->xres_virtual / 4;
}
@@ -1490,48 +1456,67 @@ static int cirrusfb_set_par_foo (struct fb_info *info)
*
*/
- else {
- printk (KERN_ERR "cirrusfb: What's this?? requested color depth == %d.\n",
+ else
+ printk(KERN_ERR "cirrusfb: What's this?? "
+ " requested color depth == %d.\n",
var->bits_per_pixel);
- }
- vga_wcrt (regbase, VGA_CRTC_OFFSET, offset & 0xff);
+ vga_wcrt(regbase, VGA_CRTC_OFFSET, offset & 0xff);
tmp = 0x22;
if (offset & 0x100)
tmp |= 0x10; /* offset overflow bit */
- vga_wcrt (regbase, CL_CRT1B, tmp); /* screen start addr #16-18, fastpagemode cycles */
+ /* screen start addr #16-18, fastpagemode cycles */
+ vga_wcrt(regbase, CL_CRT1B, tmp);
if (cinfo->btype == BT_SD64 ||
cinfo->btype == BT_PICASSO4 ||
cinfo->btype == BT_ALPINE ||
cinfo->btype == BT_GD5480)
- vga_wcrt (regbase, CL_CRT1D, 0x00); /* screen start address bit 19 */
-
- vga_wcrt (regbase, VGA_CRTC_CURSOR_HI, 0); /* text cursor location high */
- vga_wcrt (regbase, VGA_CRTC_CURSOR_LO, 0); /* text cursor location low */
- vga_wcrt (regbase, VGA_CRTC_UNDERLINE, 0); /* underline row scanline = at very bottom */
-
- vga_wattr (regbase, VGA_ATC_MODE, 1); /* controller mode */
- vga_wattr (regbase, VGA_ATC_OVERSCAN, 0); /* overscan (border) color */
- vga_wattr (regbase, VGA_ATC_PLANE_ENABLE, 15); /* color plane enable */
- vga_wattr (regbase, CL_AR33, 0); /* pixel panning */
- vga_wattr (regbase, VGA_ATC_COLOR_PAGE, 0); /* color select */
+ /* screen start address bit 19 */
+ vga_wcrt(regbase, CL_CRT1D, 0x00);
+
+ /* text cursor location high */
+ vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0);
+ /* text cursor location low */
+ vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0);
+ /* underline row scanline = at very bottom */
+ vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0);
+
+ /* controller mode */
+ vga_wattr(regbase, VGA_ATC_MODE, 1);
+ /* overscan (border) color */
+ vga_wattr(regbase, VGA_ATC_OVERSCAN, 0);
+ /* color plane enable */
+ vga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 15);
+ /* pixel panning */
+ vga_wattr(regbase, CL_AR33, 0);
+ /* color select */
+ vga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0);
/* [ EGS: SetOffset(); ] */
/* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
- AttrOn (cinfo);
-
- vga_wgfx (regbase, VGA_GFX_SR_VALUE, 0); /* set/reset register */
- vga_wgfx (regbase, VGA_GFX_SR_ENABLE, 0); /* set/reset enable */
- vga_wgfx (regbase, VGA_GFX_COMPARE_VALUE, 0); /* color compare */
- vga_wgfx (regbase, VGA_GFX_DATA_ROTATE, 0); /* data rotate */
- vga_wgfx (regbase, VGA_GFX_PLANE_READ, 0); /* read map select */
- vga_wgfx (regbase, VGA_GFX_MISC, 1); /* miscellaneous register */
- vga_wgfx (regbase, VGA_GFX_COMPARE_MASK, 15); /* color don't care */
- vga_wgfx (regbase, VGA_GFX_BIT_MASK, 255); /* bit mask */
-
- vga_wseq (regbase, CL_SEQR12, 0x0); /* graphics cursor attributes: nothing special */
+ AttrOn(cinfo);
+
+ /* set/reset register */
+ vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0);
+ /* set/reset enable */
+ vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0);
+ /* color compare */
+ vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0);
+ /* data rotate */
+ vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0);
+ /* read map select */
+ vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0);
+ /* miscellaneous register */
+ vga_wgfx(regbase, VGA_GFX_MISC, 1);
+ /* color don't care */
+ vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 15);
+ /* bit mask */
+ vga_wgfx(regbase, VGA_GFX_BIT_MASK, 255);
+
+ /* graphics cursor attributes: nothing special */
+ vga_wseq(regbase, CL_SEQR12, 0x0);
/* finally, turn on everything - turn off "FullBandwidth" bit */
/* also, set "DotClock%2" bit where requested */
@@ -1542,36 +1527,33 @@ static int cirrusfb_set_par_foo (struct fb_info *info)
tmp |= 0x08;
*/
- vga_wseq (regbase, VGA_SEQ_CLOCK_MODE, tmp);
- DPRINTK ("CL_SEQR1: %d\n", tmp);
+ vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp);
+ DPRINTK("CL_SEQR1: %d\n", tmp);
cinfo->currentmode = regs;
- info->fix.type = regs.type;
- info->fix.visual = regs.visual;
- info->fix.line_length = regs.line_length;
/* pan to requested offset */
- cirrusfb_pan_display (var, info);
+ cirrusfb_pan_display(var, info);
#ifdef CIRRUSFB_DEBUG
- cirrusfb_dump ();
+ cirrusfb_dump();
#endif
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
return 0;
}
/* for some reason incomprehensible to me, cirrusfb requires that you write
* the registers twice for the settings to take..grr. -dte */
-static int cirrusfb_set_par (struct fb_info *info)
+static int cirrusfb_set_par(struct fb_info *info)
{
- cirrusfb_set_par_foo (info);
- return cirrusfb_set_par_foo (info);
+ cirrusfb_set_par_foo(info);
+ return cirrusfb_set_par_foo(info);
}
-static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *info)
+static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
{
struct cirrusfb_info *cinfo = info->par;
@@ -1584,34 +1566,18 @@ static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
green >>= (16 - info->var.green.length);
blue >>= (16 - info->var.blue.length);
- if (regno>=16)
+ if (regno >= 16)
return 1;
v = (red << info->var.red.offset) |
(green << info->var.green.offset) |
(blue << info->var.blue.offset);
- switch (info->var.bits_per_pixel) {
- case 8:
- cinfo->pseudo_palette[regno] = v;
- break;
- case 16:
- cinfo->pseudo_palette[regno] = v;
- break;
- case 24:
- case 32:
- cinfo->pseudo_palette[regno] = v;
- break;
- }
+ cinfo->pseudo_palette[regno] = v;
return 0;
}
- cinfo->palette[regno].red = red;
- cinfo->palette[regno].green = green;
- cinfo->palette[regno].blue = blue;
-
- if (info->var.bits_per_pixel == 8) {
- WClut (cinfo, regno, red >> 10, green >> 10, blue >> 10);
- }
+ if (info->var.bits_per_pixel == 8)
+ WClut(cinfo, regno, red >> 10, green >> 10, blue >> 10);
return 0;
@@ -1622,8 +1588,8 @@ static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
performs display panning - provided hardware permits this
**************************************************************************/
-static int cirrusfb_pan_display (struct fb_var_screeninfo *var,
- struct fb_info *info)
+static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
int xoffset = 0;
int yoffset = 0;
@@ -1631,8 +1597,8 @@ static int cirrusfb_pan_display (struct fb_var_screeninfo *var,
unsigned char tmp = 0, tmp2 = 0, xpix;
struct cirrusfb_info *cinfo = info->par;
- DPRINTK ("ENTER\n");
- DPRINTK ("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset);
+ DPRINTK("ENTER\n");
+ DPRINTK("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset);
/* no range checks for xoffset and yoffset, */
/* as fb_pan_display has already done this */
@@ -1645,7 +1611,7 @@ static int cirrusfb_pan_display (struct fb_var_screeninfo *var,
xoffset = var->xoffset * info->var.bits_per_pixel / 8;
yoffset = var->yoffset;
- base = yoffset * cinfo->currentmode.line_length + xoffset;
+ base = yoffset * info->fix.line_length + xoffset;
if (info->var.bits_per_pixel == 1) {
/* base is already correct */
@@ -1655,11 +1621,13 @@ static int cirrusfb_pan_display (struct fb_var_screeninfo *var,
xpix = (unsigned char) ((xoffset % 4) * 2);
}
- cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */
+ cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */
/* lower 8 + 8 bits of screen start address */
- vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, (unsigned char) (base & 0xff));
- vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, (unsigned char) (base >> 8));
+ vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO,
+ (unsigned char) (base & 0xff));
+ vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI,
+ (unsigned char) (base >> 8));
/* construct bits 16, 17 and 18 of screen start address */
if (base & 0x10000)
@@ -1669,50 +1637,49 @@ static int cirrusfb_pan_display (struct fb_var_screeninfo *var,
if (base & 0x40000)
tmp |= 0x08;
- tmp2 = (vga_rcrt (cinfo->regbase, CL_CRT1B) & 0xf2) | tmp; /* 0xf2 is %11110010, exclude tmp bits */
- vga_wcrt (cinfo->regbase, CL_CRT1B, tmp2);
+ /* 0xf2 is %11110010, exclude tmp bits */
+ tmp2 = (vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2) | tmp;
+ vga_wcrt(cinfo->regbase, CL_CRT1B, tmp2);
/* construct bit 19 of screen start address */
- if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) {
- tmp2 = 0;
- if (base & 0x80000)
- tmp2 = 0x80;
- vga_wcrt (cinfo->regbase, CL_CRT1D, tmp2);
- }
+ if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19)
+ vga_wcrt(cinfo->regbase, CL_CRT1D, (base >> 12) & 0x80);
- /* write pixel panning value to AR33; this does not quite work in 8bpp */
- /* ### Piccolo..? Will this work? */
+ /* write pixel panning value to AR33; this does not quite work in 8bpp
+ *
+ * ### Piccolo..? Will this work?
+ */
if (info->var.bits_per_pixel == 1)
- vga_wattr (cinfo->regbase, CL_AR33, xpix);
+ vga_wattr(cinfo->regbase, CL_AR33, xpix);
- cirrusfb_WaitBLT (cinfo->regbase);
+ cirrusfb_WaitBLT(cinfo->regbase);
- DPRINTK ("EXIT\n");
- return (0);
+ DPRINTK("EXIT\n");
+ return 0;
}
-
-static int cirrusfb_blank (int blank_mode, struct fb_info *info)
+static int cirrusfb_blank(int blank_mode, struct fb_info *info)
{
/*
- * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
- * then the caller blanks by setting the CLUT (Color Look Up Table) to all
- * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
- * to e.g. a video mode which doesn't support it. Implements VESA suspend
- * and powerdown modes on hardware that supports disabling hsync/vsync:
- * blank_mode == 2: suspend vsync
- * blank_mode == 3: suspend hsync
- * blank_mode == 4: powerdown
+ * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
+ * then the caller blanks by setting the CLUT (Color Look Up Table)
+ * to all black. Return 0 if blanking succeeded, != 0 if un-/blanking
+ * failed due to e.g. a video mode which doesn't support it.
+ * Implements VESA suspend and powerdown modes on hardware that
+ * supports disabling hsync/vsync:
+ * blank_mode == 2: suspend vsync
+ * blank_mode == 3: suspend hsync
+ * blank_mode == 4: powerdown
*/
unsigned char val;
struct cirrusfb_info *cinfo = info->par;
int current_mode = cinfo->blank_mode;
- DPRINTK ("ENTER, blank mode = %d\n", blank_mode);
+ DPRINTK("ENTER, blank mode = %d\n", blank_mode);
if (info->state != FBINFO_STATE_RUNNING ||
current_mode == blank_mode) {
- DPRINTK ("EXIT, returning 0\n");
+ DPRINTK("EXIT, returning 0\n");
return 0;
}
@@ -1720,17 +1687,19 @@ static int cirrusfb_blank (int blank_mode, struct fb_info *info)
if (current_mode == FB_BLANK_NORMAL ||
current_mode == FB_BLANK_UNBLANK) {
/* unblank the screen */
- val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE);
- vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf); /* clear "FullBandwidth" bit */
+ val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE);
+ /* clear "FullBandwidth" bit */
+ vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf);
/* and undo VESA suspend trickery */
- vga_wgfx (cinfo->regbase, CL_GRE, 0x00);
+ vga_wgfx(cinfo->regbase, CL_GRE, 0x00);
}
/* set new */
- if(blank_mode > FB_BLANK_NORMAL) {
+ if (blank_mode > FB_BLANK_NORMAL) {
/* blank the screen */
- val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE);
- vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20); /* set "FullBandwidth" bit */
+ val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE);
+ /* set "FullBandwidth" bit */
+ vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20);
}
switch (blank_mode) {
@@ -1738,21 +1707,21 @@ static int cirrusfb_blank (int blank_mode, struct fb_info *info)
case FB_BLANK_NORMAL:
break;
case FB_BLANK_VSYNC_SUSPEND:
- vga_wgfx (cinfo->regbase, CL_GRE, 0x04);
+ vga_wgfx(cinfo->regbase, CL_GRE, 0x04);
break;
case FB_BLANK_HSYNC_SUSPEND:
- vga_wgfx (cinfo->regbase, CL_GRE, 0x02);
+ vga_wgfx(cinfo->regbase, CL_GRE, 0x02);
break;
case FB_BLANK_POWERDOWN:
- vga_wgfx (cinfo->regbase, CL_GRE, 0x06);
+ vga_wgfx(cinfo->regbase, CL_GRE, 0x06);
break;
default:
- DPRINTK ("EXIT, returning 1\n");
+ DPRINTK("EXIT, returning 1\n");
return 1;
}
cinfo->blank_mode = blank_mode;
- DPRINTK ("EXIT, returning 0\n");
+ DPRINTK("EXIT, returning 0\n");
/* Let fbcon do a soft blank for us */
return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
@@ -1761,45 +1730,51 @@ static int cirrusfb_blank (int blank_mode, struct fb_info *info)
/****************************************************************************/
/**** BEGIN Internal Routines ***********************************************/
-static void init_vgachip (struct cirrusfb_info *cinfo)
+static void init_vgachip(struct fb_info *info)
{
+ struct cirrusfb_info *cinfo = info->par;
const struct cirrusfb_board_info_rec *bi;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- assert (cinfo != NULL);
+ assert(cinfo != NULL);
bi = &cirrusfb_board_info[cinfo->btype];
/* reset board globally */
switch (cinfo->btype) {
case BT_PICCOLO:
- WSFR (cinfo, 0x01);
- udelay (500);
- WSFR (cinfo, 0x51);
- udelay (500);
+ WSFR(cinfo, 0x01);
+ udelay(500);
+ WSFR(cinfo, 0x51);
+ udelay(500);
break;
case BT_PICASSO:
- WSFR2 (cinfo, 0xff);
- udelay (500);
+ WSFR2(cinfo, 0xff);
+ udelay(500);
break;
case BT_SD64:
case BT_SPECTRUM:
- WSFR (cinfo, 0x1f);
- udelay (500);
- WSFR (cinfo, 0x4f);
- udelay (500);
+ WSFR(cinfo, 0x1f);
+ udelay(500);
+ WSFR(cinfo, 0x4f);
+ udelay(500);
break;
case BT_PICASSO4:
- vga_wcrt (cinfo->regbase, CL_CRT51, 0x00); /* disable flickerfixer */
- mdelay (100);
- vga_wgfx (cinfo->regbase, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */
- vga_wgfx (cinfo->regbase, CL_GR33, 0x00); /* put blitter into 542x compat */
- vga_wgfx (cinfo->regbase, CL_GR31, 0x00); /* mode */
+ /* disable flickerfixer */
+ vga_wcrt(cinfo->regbase, CL_CRT51, 0x00);
+ mdelay(100);
+ /* from Klaus' NetBSD driver: */
+ vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
+ /* put blitter into 542x compat */
+ vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
+ /* mode */
+ vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
break;
case BT_GD5480:
- vga_wgfx (cinfo->regbase, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */
+ /* from Klaus' NetBSD driver: */
+ vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
break;
case BT_ALPINE:
@@ -1807,153 +1782,208 @@ static void init_vgachip (struct cirrusfb_info *cinfo)
break;
default:
- printk (KERN_ERR "cirrusfb: Warning: Unknown board type\n");
+ printk(KERN_ERR "cirrusfb: Warning: Unknown board type\n");
break;
}
- assert (cinfo->size > 0); /* make sure RAM size set by this point */
+ /* make sure RAM size set by this point */
+ assert(info->screen_size > 0);
/* the P4 is not fully initialized here; I rely on it having been */
/* inited under AmigaOS already, which seems to work just fine */
- /* (Klaus advised to do it this way) */
+ /* (Klaus advised to do it this way) */
if (cinfo->btype != BT_PICASSO4) {
- WGen (cinfo, CL_VSSM, 0x10); /* EGS: 0x16 */
- WGen (cinfo, CL_POS102, 0x01);
- WGen (cinfo, CL_VSSM, 0x08); /* EGS: 0x0e */
+ WGen(cinfo, CL_VSSM, 0x10); /* EGS: 0x16 */
+ WGen(cinfo, CL_POS102, 0x01);
+ WGen(cinfo, CL_VSSM, 0x08); /* EGS: 0x0e */
if (cinfo->btype != BT_SD64)
- WGen (cinfo, CL_VSSM2, 0x01);
+ WGen(cinfo, CL_VSSM2, 0x01);
- vga_wseq (cinfo->regbase, CL_SEQR0, 0x03); /* reset sequencer logic */
+ /* reset sequencer logic */
+ vga_wseq(cinfo->regbase, CL_SEQR0, 0x03);
- vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21); /* FullBandwidth (video off) and 8/9 dot clock */
- WGen (cinfo, VGA_MIS_W, 0xc1); /* polarity (-/-), disable access to display memory, VGA_CRTC_START_HI base address: color */
+ /* FullBandwidth (video off) and 8/9 dot clock */
+ vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21);
+ /* polarity (-/-), disable access to display memory,
+ * VGA_CRTC_START_HI base address: color
+ */
+ WGen(cinfo, VGA_MIS_W, 0xc1);
-/* vga_wgfx (cinfo->regbase, CL_GRA, 0xce); "magic cookie" - doesn't make any sense to me.. */
- vga_wseq (cinfo->regbase, CL_SEQR6, 0x12); /* unlock all extension registers */
+ /* "magic cookie" - doesn't make any sense to me.. */
+/* vga_wgfx(cinfo->regbase, CL_GRA, 0xce); */
+ /* unlock all extension registers */
+ vga_wseq(cinfo->regbase, CL_SEQR6, 0x12);
- vga_wgfx (cinfo->regbase, CL_GR31, 0x04); /* reset blitter */
+ /* reset blitter */
+ vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
switch (cinfo->btype) {
case BT_GD5480:
- vga_wseq (cinfo->regbase, CL_SEQRF, 0x98);
+ vga_wseq(cinfo->regbase, CL_SEQRF, 0x98);
break;
case BT_ALPINE:
break;
case BT_SD64:
- vga_wseq (cinfo->regbase, CL_SEQRF, 0xb8);
+ vga_wseq(cinfo->regbase, CL_SEQRF, 0xb8);
break;
default:
- vga_wseq (cinfo->regbase, CL_SEQR16, 0x0f);
- vga_wseq (cinfo->regbase, CL_SEQRF, 0xb0);
+ vga_wseq(cinfo->regbase, CL_SEQR16, 0x0f);
+ vga_wseq(cinfo->regbase, CL_SEQRF, 0xb0);
break;
}
}
- vga_wseq (cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: nothing */
- vga_wseq (cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00); /* character map select: doesn't even matter in gx mode */
- vga_wseq (cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e); /* memory mode: chain-4, no odd/even, ext. memory */
+ /* plane mask: nothing */
+ vga_wseq(cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff);
+ /* character map select: doesn't even matter in gx mode */
+ vga_wseq(cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00);
+ /* memory mode: chain-4, no odd/even, ext. memory */
+ vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e);
/* controller-internal base address of video memory */
if (bi->init_sr07)
- vga_wseq (cinfo->regbase, CL_SEQR7, bi->sr07);
+ vga_wseq(cinfo->regbase, CL_SEQR7, bi->sr07);
- /* vga_wseq (cinfo->regbase, CL_SEQR8, 0x00); *//* EEPROM control: shouldn't be necessary to write to this at all.. */
+ /* vga_wseq(cinfo->regbase, CL_SEQR8, 0x00); */
+ /* EEPROM control: shouldn't be necessary to write to this at all.. */
- vga_wseq (cinfo->regbase, CL_SEQR10, 0x00); /* graphics cursor X position (incomplete; position gives rem. 3 bits */
- vga_wseq (cinfo->regbase, CL_SEQR11, 0x00); /* graphics cursor Y position (..."... ) */
- vga_wseq (cinfo->regbase, CL_SEQR12, 0x00); /* graphics cursor attributes */
- vga_wseq (cinfo->regbase, CL_SEQR13, 0x00); /* graphics cursor pattern address */
+ /* graphics cursor X position (incomplete; position gives rem. 3 bits */
+ vga_wseq(cinfo->regbase, CL_SEQR10, 0x00);
+ /* graphics cursor Y position (..."... ) */
+ vga_wseq(cinfo->regbase, CL_SEQR11, 0x00);
+ /* graphics cursor attributes */
+ vga_wseq(cinfo->regbase, CL_SEQR12, 0x00);
+ /* graphics cursor pattern address */
+ vga_wseq(cinfo->regbase, CL_SEQR13, 0x00);
/* writing these on a P4 might give problems.. */
if (cinfo->btype != BT_PICASSO4) {
- vga_wseq (cinfo->regbase, CL_SEQR17, 0x00); /* configuration readback and ext. color */
- vga_wseq (cinfo->regbase, CL_SEQR18, 0x02); /* signature generator */
+ /* configuration readback and ext. color */
+ vga_wseq(cinfo->regbase, CL_SEQR17, 0x00);
+ /* signature generator */
+ vga_wseq(cinfo->regbase, CL_SEQR18, 0x02);
}
/* MCLK select etc. */
if (bi->init_sr1f)
- vga_wseq (cinfo->regbase, CL_SEQR1F, bi->sr1f);
-
- vga_wcrt (cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00); /* Screen A preset row scan: none */
- vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20); /* Text cursor start: disable text cursor */
- vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00); /* Text cursor end: - */
- vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, 0x00); /* Screen start address high: 0 */
- vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, 0x00); /* Screen start address low: 0 */
- vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00); /* text cursor location high: 0 */
- vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00); /* text cursor location low: 0 */
-
- vga_wcrt (cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00); /* Underline Row scanline: - */
- vga_wcrt (cinfo->regbase, VGA_CRTC_MODE, 0xc3); /* mode control: timing enable, byte mode, no compat modes */
- vga_wcrt (cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00); /* Line Compare: not needed */
+ vga_wseq(cinfo->regbase, CL_SEQR1F, bi->sr1f);
+
+ /* Screen A preset row scan: none */
+ vga_wcrt(cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00);
+ /* Text cursor start: disable text cursor */
+ vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20);
+ /* Text cursor end: - */
+ vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00);
+ /* Screen start address high: 0 */
+ vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, 0x00);
+ /* Screen start address low: 0 */
+ vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, 0x00);
+ /* text cursor location high: 0 */
+ vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00);
+ /* text cursor location low: 0 */
+ vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00);
+
+ /* Underline Row scanline: - */
+ vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00);
+ /* mode control: timing enable, byte mode, no compat modes */
+ vga_wcrt(cinfo->regbase, VGA_CRTC_MODE, 0xc3);
+ /* Line Compare: not needed */
+ vga_wcrt(cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00);
/* ### add 0x40 for text modes with > 30 MHz pixclock */
- vga_wcrt (cinfo->regbase, CL_CRT1B, 0x02); /* ext. display controls: ext.adr. wrap */
-
- vga_wgfx (cinfo->regbase, VGA_GFX_SR_VALUE, 0x00); /* Set/Reset registes: - */
- vga_wgfx (cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00); /* Set/Reset enable: - */
- vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00); /* Color Compare: - */
- vga_wgfx (cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00); /* Data Rotate: - */
- vga_wgfx (cinfo->regbase, VGA_GFX_PLANE_READ, 0x00); /* Read Map Select: - */
- vga_wgfx (cinfo->regbase, VGA_GFX_MODE, 0x00); /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
- vga_wgfx (cinfo->regbase, VGA_GFX_MISC, 0x01); /* Miscellaneous: memory map base address, graphics mode */
- vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f); /* Color Don't care: involve all planes */
- vga_wgfx (cinfo->regbase, VGA_GFX_BIT_MASK, 0xff); /* Bit Mask: no mask at all */
+ /* ext. display controls: ext.adr. wrap */
+ vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02);
+
+ /* Set/Reset registes: - */
+ vga_wgfx(cinfo->regbase, VGA_GFX_SR_VALUE, 0x00);
+ /* Set/Reset enable: - */
+ vga_wgfx(cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00);
+ /* Color Compare: - */
+ vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00);
+ /* Data Rotate: - */
+ vga_wgfx(cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00);
+ /* Read Map Select: - */
+ vga_wgfx(cinfo->regbase, VGA_GFX_PLANE_READ, 0x00);
+ /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
+ vga_wgfx(cinfo->regbase, VGA_GFX_MODE, 0x00);
+ /* Miscellaneous: memory map base address, graphics mode */
+ vga_wgfx(cinfo->regbase, VGA_GFX_MISC, 0x01);
+ /* Color Don't care: involve all planes */
+ vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f);
+ /* Bit Mask: no mask at all */
+ vga_wgfx(cinfo->regbase, VGA_GFX_BIT_MASK, 0xff);
if (cinfo->btype == BT_ALPINE)
- vga_wgfx (cinfo->regbase, CL_GRB, 0x20); /* (5434 can't have bit 3 set for bitblt) */
+ /* (5434 can't have bit 3 set for bitblt) */
+ vga_wgfx(cinfo->regbase, CL_GRB, 0x20);
else
- vga_wgfx (cinfo->regbase, CL_GRB, 0x28); /* Graphics controller mode extensions: finer granularity, 8byte data latches */
-
- vga_wgfx (cinfo->regbase, CL_GRC, 0xff); /* Color Key compare: - */
- vga_wgfx (cinfo->regbase, CL_GRD, 0x00); /* Color Key compare mask: - */
- vga_wgfx (cinfo->regbase, CL_GRE, 0x00); /* Miscellaneous control: - */
- /* vga_wgfx (cinfo->regbase, CL_GR10, 0x00); *//* Background color byte 1: - */
-/* vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */
-
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTE0, 0x00); /* Attribute Controller palette registers: "identity mapping" */
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTE1, 0x01);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTE2, 0x02);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTE3, 0x03);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTE4, 0x04);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTE5, 0x05);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTE6, 0x06);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTE7, 0x07);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTE8, 0x08);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTE9, 0x09);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTEA, 0x0a);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTEB, 0x0b);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTEC, 0x0c);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTED, 0x0d);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTEE, 0x0e);
- vga_wattr (cinfo->regbase, VGA_ATC_PALETTEF, 0x0f);
-
- vga_wattr (cinfo->regbase, VGA_ATC_MODE, 0x01); /* Attribute Controller mode: graphics mode */
- vga_wattr (cinfo->regbase, VGA_ATC_OVERSCAN, 0x00); /* Overscan color reg.: reg. 0 */
- vga_wattr (cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f); /* Color Plane enable: Enable all 4 planes */
-/* ### vga_wattr (cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */
- vga_wattr (cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00); /* Color Select: - */
-
- WGen (cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */
+ /* Graphics controller mode extensions: finer granularity,
+ * 8byte data latches
+ */
+ vga_wgfx(cinfo->regbase, CL_GRB, 0x28);
+
+ vga_wgfx(cinfo->regbase, CL_GRC, 0xff); /* Color Key compare: - */
+ vga_wgfx(cinfo->regbase, CL_GRD, 0x00); /* Color Key compare mask: - */
+ vga_wgfx(cinfo->regbase, CL_GRE, 0x00); /* Miscellaneous control: - */
+ /* Background color byte 1: - */
+ /* vga_wgfx (cinfo->regbase, CL_GR10, 0x00); */
+ /* vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */
+
+ /* Attribute Controller palette registers: "identity mapping" */
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTE0, 0x00);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTE1, 0x01);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTE2, 0x02);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTE3, 0x03);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTE4, 0x04);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTE5, 0x05);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTE6, 0x06);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTE7, 0x07);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTE8, 0x08);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTE9, 0x09);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTEA, 0x0a);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTEB, 0x0b);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTEC, 0x0c);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTED, 0x0d);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTEE, 0x0e);
+ vga_wattr(cinfo->regbase, VGA_ATC_PALETTEF, 0x0f);
+
+ /* Attribute Controller mode: graphics mode */
+ vga_wattr(cinfo->regbase, VGA_ATC_MODE, 0x01);
+ /* Overscan color reg.: reg. 0 */
+ vga_wattr(cinfo->regbase, VGA_ATC_OVERSCAN, 0x00);
+ /* Color Plane enable: Enable all 4 planes */
+ vga_wattr(cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f);
+/* ### vga_wattr(cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */
+ /* Color Select: - */
+ vga_wattr(cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00);
+
+ WGen(cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */
if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480)
- WGen (cinfo, VGA_MIS_W, 0xc3); /* polarity (-/-), enable display mem, VGA_CRTC_START_HI i/o base = color */
+ /* polarity (-/-), enable display mem,
+ * VGA_CRTC_START_HI i/o base = color
+ */
+ WGen(cinfo, VGA_MIS_W, 0xc3);
- vga_wgfx (cinfo->regbase, CL_GR31, 0x04); /* BLT Start/status: Blitter reset */
- vga_wgfx (cinfo->regbase, CL_GR31, 0x00); /* - " - : "end-of-reset" */
+ /* BLT Start/status: Blitter reset */
+ vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
+ /* - " - : "end-of-reset" */
+ vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
/* misc... */
- WHDR (cinfo, 0); /* Hidden DAC register: - */
+ WHDR(cinfo, 0); /* Hidden DAC register: - */
- printk (KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n", cinfo->size);
- DPRINTK ("EXIT\n");
+ printk(KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n",
+ info->screen_size);
+ DPRINTK("EXIT\n");
return;
}
-static void switch_monitor (struct cirrusfb_info *cinfo, int on)
+static void switch_monitor(struct cirrusfb_info *cinfo, int on)
{
#ifdef CONFIG_ZORRO /* only works on Zorro boards */
static int IsOn = 0; /* XXX not ok for multiple boards */
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
if (cinfo->btype == BT_PICASSO4)
return; /* nothing to switch */
@@ -1963,77 +1993,56 @@ static void switch_monitor (struct cirrusfb_info *cinfo, int on)
return; /* nothing to switch */
if (cinfo->btype == BT_PICASSO) {
if ((on && !IsOn) || (!on && IsOn))
- WSFR (cinfo, 0xff);
+ WSFR(cinfo, 0xff);
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
return;
}
if (on) {
switch (cinfo->btype) {
case BT_SD64:
- WSFR (cinfo, cinfo->SFR | 0x21);
+ WSFR(cinfo, cinfo->SFR | 0x21);
break;
case BT_PICCOLO:
- WSFR (cinfo, cinfo->SFR | 0x28);
+ WSFR(cinfo, cinfo->SFR | 0x28);
break;
case BT_SPECTRUM:
- WSFR (cinfo, 0x6f);
+ WSFR(cinfo, 0x6f);
break;
default: /* do nothing */ break;
}
} else {
switch (cinfo->btype) {
case BT_SD64:
- WSFR (cinfo, cinfo->SFR & 0xde);
+ WSFR(cinfo, cinfo->SFR & 0xde);
break;
case BT_PICCOLO:
- WSFR (cinfo, cinfo->SFR & 0xd7);
+ WSFR(cinfo, cinfo->SFR & 0xd7);
break;
case BT_SPECTRUM:
- WSFR (cinfo, 0x4f);
+ WSFR(cinfo, 0x4f);
break;
default: /* do nothing */ break;
}
}
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
#endif /* CONFIG_ZORRO */
}
-
/******************************************/
/* Linux 2.6-style accelerated functions */
/******************************************/
-static void cirrusfb_prim_fillrect(struct cirrusfb_info *cinfo,
- const struct fb_fillrect *region)
-{
- int m; /* bytes per pixel */
- u32 color = (cinfo->info->fix.visual == FB_VISUAL_TRUECOLOR) ?
- cinfo->pseudo_palette[region->color] : region->color;
-
- if(cinfo->info->var.bits_per_pixel == 1) {
- cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel,
- region->dx / 8, region->dy,
- region->width / 8, region->height,
- color,
- cinfo->currentmode.line_length);
- } else {
- m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8;
- cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel,
- region->dx * m, region->dy,
- region->width * m, region->height,
- color,
- cinfo->currentmode.line_length);
- }
- return;
-}
-
-static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region)
+static void cirrusfb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *region)
{
- struct cirrusfb_info *cinfo = info->par;
struct fb_fillrect modded;
int vxres, vyres;
+ struct cirrusfb_info *cinfo = info->par;
+ int m = info->var.bits_per_pixel;
+ u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
+ cinfo->pseudo_palette[region->color] : region->color;
if (info->state != FBINFO_STATE_RUNNING)
return;
@@ -2047,49 +2056,30 @@ static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *r
memcpy(&modded, region, sizeof(struct fb_fillrect));
- if(!modded.width || !modded.height ||
+ if (!modded.width || !modded.height ||
modded.dx >= vxres || modded.dy >= vyres)
return;
- if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx;
- if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
-
- cirrusfb_prim_fillrect(cinfo, &modded);
-}
-
-static void cirrusfb_prim_copyarea(struct cirrusfb_info *cinfo,
- const struct fb_copyarea *area)
-{
- int m; /* bytes per pixel */
- if(cinfo->info->var.bits_per_pixel == 1) {
- cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel,
- area->sx / 8, area->sy,
- area->dx / 8, area->dy,
- area->width / 8, area->height,
- cinfo->currentmode.line_length);
- } else {
- m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8;
- cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel,
- area->sx * m, area->sy,
- area->dx * m, area->dy,
- area->width * m, area->height,
- cinfo->currentmode.line_length);
- }
- return;
+ if (modded.dx + modded.width > vxres)
+ modded.width = vxres - modded.dx;
+ if (modded.dy + modded.height > vyres)
+ modded.height = vyres - modded.dy;
+
+ cirrusfb_RectFill(cinfo->regbase,
+ info->var.bits_per_pixel,
+ (region->dx * m) / 8, region->dy,
+ (region->width * m) / 8, region->height,
+ color,
+ info->fix.line_length);
}
-
-static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+static void cirrusfb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
{
- struct cirrusfb_info *cinfo = info->par;
struct fb_copyarea modded;
u32 vxres, vyres;
- modded.sx = area->sx;
- modded.sy = area->sy;
- modded.dx = area->dx;
- modded.dy = area->dy;
- modded.width = area->width;
- modded.height = area->height;
+ struct cirrusfb_info *cinfo = info->par;
+ int m = info->var.bits_per_pixel;
if (info->state != FBINFO_STATE_RUNNING)
return;
@@ -2100,90 +2090,106 @@ static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *ar
vxres = info->var.xres_virtual;
vyres = info->var.yres_virtual;
+ memcpy(&modded, area, sizeof(struct fb_copyarea));
- if(!modded.width || !modded.height ||
+ if (!modded.width || !modded.height ||
modded.sx >= vxres || modded.sy >= vyres ||
modded.dx >= vxres || modded.dy >= vyres)
return;
- if(modded.sx + modded.width > vxres) modded.width = vxres - modded.sx;
- if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx;
- if(modded.sy + modded.height > vyres) modded.height = vyres - modded.sy;
- if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
+ if (modded.sx + modded.width > vxres)
+ modded.width = vxres - modded.sx;
+ if (modded.dx + modded.width > vxres)
+ modded.width = vxres - modded.dx;
+ if (modded.sy + modded.height > vyres)
+ modded.height = vyres - modded.sy;
+ if (modded.dy + modded.height > vyres)
+ modded.height = vyres - modded.dy;
+
+ cirrusfb_BitBLT(cinfo->regbase, info->var.bits_per_pixel,
+ (area->sx * m) / 8, area->sy,
+ (area->dx * m) / 8, area->dy,
+ (area->width * m) / 8, area->height,
+ info->fix.line_length);
- cirrusfb_prim_copyarea(cinfo, &modded);
}
-static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image)
+static void cirrusfb_imageblit(struct fb_info *info,
+ const struct fb_image *image)
{
struct cirrusfb_info *cinfo = info->par;
- cirrusfb_WaitBLT(cinfo->regbase);
+ cirrusfb_WaitBLT(cinfo->regbase);
cfb_imageblit(info, image);
}
-
#ifdef CONFIG_PPC_PREP
#define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000)
#define PREP_IO_BASE ((volatile unsigned char *) 0x80000000)
-static void get_prep_addrs (unsigned long *display, unsigned long *registers)
+static void get_prep_addrs(unsigned long *display, unsigned long *registers)
{
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
*display = PREP_VIDEO_BASE;
*registers = (unsigned long) PREP_IO_BASE;
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
#endif /* CONFIG_PPC_PREP */
-
#ifdef CONFIG_PCI
-static int release_io_ports = 0;
+static int release_io_ports;
/* Pulled the logic from XFree86 Cirrus driver to get the memory size,
* based on the DRAM bandwidth bit and DRAM bank switching bit. This
* works with 1MB, 2MB and 4MB configurations (which the Motorola boards
* seem to have. */
-static unsigned int cirrusfb_get_memsize (u8 __iomem *regbase)
+static unsigned int cirrusfb_get_memsize(u8 __iomem *regbase)
{
unsigned long mem;
unsigned char SRF;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- SRF = vga_rseq (regbase, CL_SEQRF);
+ SRF = vga_rseq(regbase, CL_SEQRF);
switch ((SRF & 0x18)) {
- case 0x08: mem = 512 * 1024; break;
- case 0x10: mem = 1024 * 1024; break;
- /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
- * on the 5430. */
- case 0x18: mem = 2048 * 1024; break;
- default: printk ("CLgenfb: Unknown memory size!\n");
+ case 0x08:
+ mem = 512 * 1024;
+ break;
+ case 0x10:
+ mem = 1024 * 1024;
+ break;
+ /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
+ * on the 5430.
+ */
+ case 0x18:
+ mem = 2048 * 1024;
+ break;
+ default:
+ printk(KERN_WARNING "CLgenfb: Unknown memory size!\n");
mem = 1024 * 1024;
}
- if (SRF & 0x80) {
- /* If DRAM bank switching is enabled, there must be twice as much
- * memory installed. (4MB on the 5434) */
+ if (SRF & 0x80)
+ /* If DRAM bank switching is enabled, there must be twice as much
+ * memory installed. (4MB on the 5434)
+ */
mem *= 2;
- }
+
/* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
return mem;
}
-
-
-static void get_pci_addrs (const struct pci_dev *pdev,
- unsigned long *display, unsigned long *registers)
+static void get_pci_addrs(const struct pci_dev *pdev,
+ unsigned long *display, unsigned long *registers)
{
- assert (pdev != NULL);
- assert (display != NULL);
- assert (registers != NULL);
+ assert(pdev != NULL);
+ assert(display != NULL);
+ assert(registers != NULL);
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
*display = 0;
*registers = 0;
@@ -2198,51 +2204,48 @@ static void get_pci_addrs (const struct pci_dev *pdev,
*registers = pci_resource_start(pdev, 1);
}
- assert (*display != 0);
+ assert(*display != 0);
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
-
-static void cirrusfb_pci_unmap (struct cirrusfb_info *cinfo)
+static void cirrusfb_pci_unmap(struct fb_info *info)
{
+ struct cirrusfb_info *cinfo = info->par;
struct pci_dev *pdev = cinfo->pdev;
- iounmap(cinfo->fbmem);
+ iounmap(info->screen_base);
#if 0 /* if system didn't claim this region, we would... */
release_mem_region(0xA0000, 65535);
#endif
if (release_io_ports)
release_region(0x3C0, 32);
pci_release_regions(pdev);
- framebuffer_release(cinfo->info);
}
#endif /* CONFIG_PCI */
-
#ifdef CONFIG_ZORRO
-static void __devexit cirrusfb_zorro_unmap (struct cirrusfb_info *cinfo)
+static void __devexit cirrusfb_zorro_unmap(struct fb_info *info)
{
+ struct cirrusfb_info *cinfo = info->par;
zorro_release_device(cinfo->zdev);
if (cinfo->btype == BT_PICASSO4) {
cinfo->regbase -= 0x600000;
- iounmap ((void *)cinfo->regbase);
- iounmap ((void *)cinfo->fbmem);
+ iounmap((void *)cinfo->regbase);
+ iounmap(info->screen_base);
} else {
if (zorro_resource_start(cinfo->zdev) > 0x01000000)
- iounmap ((void *)cinfo->fbmem);
+ iounmap(info->screen_base);
}
- framebuffer_release(cinfo->info);
}
#endif /* CONFIG_ZORRO */
-static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo)
+static int cirrusfb_set_fbinfo(struct fb_info *info)
{
- struct fb_info *info = cinfo->info;
+ struct cirrusfb_info *cinfo = info->par;
struct fb_var_screeninfo *var = &info->var;
- info->par = cinfo;
info->pseudo_palette = cinfo->pseudo_palette;
info->flags = FBINFO_DEFAULT
| FBINFO_HWACCEL_XPAN
@@ -2252,7 +2255,6 @@ static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo)
if (noaccel)
info->flags |= FBINFO_HWACCEL_DISABLED;
info->fbops = &cirrusfb_ops;
- info->screen_base = cinfo->fbmem;
if (cinfo->btype == BT_GD5480) {
if (var->bits_per_pixel == 16)
info->screen_base += 1 * MB_;
@@ -2266,18 +2268,15 @@ static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo)
/* monochrome: only 1 memory plane */
/* 8 bit and above: Use whole memory area */
- info->fix.smem_start = cinfo->fbmem_phys;
- info->fix.smem_len = (var->bits_per_pixel == 1) ? cinfo->size / 4 : cinfo->size;
- info->fix.type = cinfo->currentmode.type;
+ info->fix.smem_len = info->screen_size;
+ if (var->bits_per_pixel == 1)
+ info->fix.smem_len /= 4;
info->fix.type_aux = 0;
- info->fix.visual = cinfo->currentmode.visual;
info->fix.xpanstep = 1;
info->fix.ypanstep = 1;
info->fix.ywrapstep = 0;
- info->fix.line_length = cinfo->currentmode.line_length;
/* FIXME: map region at 0xB8000 if available, fill in here */
- info->fix.mmio_start = cinfo->fbregs_phys;
info->fix.mmio_len = 0;
info->fix.accel = FB_ACCEL_NONE;
@@ -2286,23 +2285,23 @@ static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo)
return 0;
}
-static int cirrusfb_register(struct cirrusfb_info *cinfo)
+static int cirrusfb_register(struct fb_info *info)
{
- struct fb_info *info;
+ struct cirrusfb_info *cinfo = info->par;
int err;
- cirrusfb_board_t btype;
+ enum cirrus_board btype;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- printk (KERN_INFO "cirrusfb: Driver for Cirrus Logic based graphic boards, v" CIRRUSFB_VERSION "\n");
+ printk(KERN_INFO "cirrusfb: Driver for Cirrus Logic based "
+ "graphic boards, v" CIRRUSFB_VERSION "\n");
- info = cinfo->info;
btype = cinfo->btype;
/* sanity checks */
- assert (btype != BT_NONE);
+ assert(btype != BT_NONE);
- DPRINTK ("cirrusfb: (RAM start set to: 0x%p)\n", cinfo->fbmem);
+ DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", info->screen_base);
/* Make pretend we've set the var so our structures are in a "good" */
/* state, even though we haven't written the mode to the hw yet... */
@@ -2317,47 +2316,49 @@ static int cirrusfb_register(struct cirrusfb_info *cinfo)
}
/* set all the vital stuff */
- cirrusfb_set_fbinfo(cinfo);
+ cirrusfb_set_fbinfo(info);
err = register_framebuffer(info);
if (err < 0) {
- printk (KERN_ERR "cirrusfb: could not register fb device; err = %d!\n", err);
+ printk(KERN_ERR "cirrusfb: could not register "
+ "fb device; err = %d!\n", err);
goto err_dealloc_cmap;
}
- DPRINTK ("EXIT, returning 0\n");
+ DPRINTK("EXIT, returning 0\n");
return 0;
err_dealloc_cmap:
fb_dealloc_cmap(&info->cmap);
err_unmap_cirrusfb:
- cinfo->unmap(cinfo);
+ cinfo->unmap(info);
+ framebuffer_release(info);
return err;
}
-static void __devexit cirrusfb_cleanup (struct fb_info *info)
+static void __devexit cirrusfb_cleanup(struct fb_info *info)
{
struct cirrusfb_info *cinfo = info->par;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- switch_monitor (cinfo, 0);
+ switch_monitor(cinfo, 0);
- unregister_framebuffer (info);
- fb_dealloc_cmap (&info->cmap);
- printk ("Framebuffer unregistered\n");
- cinfo->unmap(cinfo);
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+ printk("Framebuffer unregistered\n");
+ cinfo->unmap(info);
+ framebuffer_release(info);
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
-
#ifdef CONFIG_PCI
-static int cirrusfb_pci_register (struct pci_dev *pdev,
+static int cirrusfb_pci_register(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct cirrusfb_info *cinfo;
struct fb_info *info;
- cirrusfb_board_t btype;
+ enum cirrus_board btype;
unsigned long board_addr, board_size;
int ret;
@@ -2375,35 +2376,37 @@ static int cirrusfb_pci_register (struct pci_dev *pdev,
}
cinfo = info->par;
- cinfo->info = info;
cinfo->pdev = pdev;
- cinfo->btype = btype = (cirrusfb_board_t) ent->driver_data;
+ cinfo->btype = btype = (enum cirrus_board) ent->driver_data;
- DPRINTK (" Found PCI device, base address 0 is 0x%lx, btype set to %d\n",
+ DPRINTK(" Found PCI device, base address 0 is 0x%x, btype set to %d\n",
pdev->resource[0].start, btype);
- DPRINTK (" base address 1 is 0x%lx\n", pdev->resource[1].start);
+ DPRINTK(" base address 1 is 0x%x\n", pdev->resource[1].start);
- if(isPReP) {
- pci_write_config_dword (pdev, PCI_BASE_ADDRESS_0, 0x00000000);
+ if (isPReP) {
+ pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, 0x00000000);
#ifdef CONFIG_PPC_PREP
- get_prep_addrs (&board_addr, &cinfo->fbregs_phys);
+ get_prep_addrs(&board_addr, &info->fix.mmio_start);
#endif
- /* PReP dies if we ioremap the IO registers, but it works w/out... */
- cinfo->regbase = (char __iomem *) cinfo->fbregs_phys;
+ /* PReP dies if we ioremap the IO registers, but it works w/out... */
+ cinfo->regbase = (char __iomem *) info->fix.mmio_start;
} else {
- DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n");
- get_pci_addrs (pdev, &board_addr, &cinfo->fbregs_phys);
- cinfo->regbase = NULL; /* FIXME: this forces VGA. alternatives? */
+ DPRINTK("Attempt to get PCI info for Cirrus Graphics Card\n");
+ get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start);
+ /* FIXME: this forces VGA. alternatives? */
+ cinfo->regbase = NULL;
}
- DPRINTK ("Board address: 0x%lx, register address: 0x%lx\n", board_addr, cinfo->fbregs_phys);
+ DPRINTK("Board address: 0x%lx, register address: 0x%lx\n",
+ board_addr, info->fix.mmio_start);
board_size = (btype == BT_GD5480) ?
- 32 * MB_ : cirrusfb_get_memsize (cinfo->regbase);
+ 32 * MB_ : cirrusfb_get_memsize(cinfo->regbase);
ret = pci_request_regions(pdev, "cirrusfb");
- if (ret <0) {
- printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n",
+ if (ret < 0) {
+ printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, "
+ "abort\n",
board_addr);
goto err_release_fb;
}
@@ -2419,23 +2422,24 @@ static int cirrusfb_pci_register (struct pci_dev *pdev,
if (request_region(0x3C0, 32, "cirrusfb"))
release_io_ports = 1;
- cinfo->fbmem = ioremap(board_addr, board_size);
- if (!cinfo->fbmem) {
+ info->screen_base = ioremap(board_addr, board_size);
+ if (!info->screen_base) {
ret = -EIO;
goto err_release_legacy;
}
- cinfo->fbmem_phys = board_addr;
- cinfo->size = board_size;
+ info->fix.smem_start = board_addr;
+ info->screen_size = board_size;
cinfo->unmap = cirrusfb_pci_unmap;
- printk (" RAM (%lu kB) at 0xx%lx, ", cinfo->size / KB_, board_addr);
- printk ("Cirrus Logic chipset on PCI bus\n");
+ printk(KERN_INFO " RAM (%lu kB) at 0xx%lx, ",
+ info->screen_size >> 10, board_addr);
+ printk(KERN_INFO "Cirrus Logic chipset on PCI bus\n");
pci_set_drvdata(pdev, info);
- ret = cirrusfb_register(cinfo);
+ ret = cirrusfb_register(info);
if (ret)
- iounmap(cinfo->fbmem);
+ iounmap(info->screen_base);
return ret;
err_release_legacy:
@@ -2453,14 +2457,14 @@ err_out:
return ret;
}
-static void __devexit cirrusfb_pci_unregister (struct pci_dev *pdev)
+static void __devexit cirrusfb_pci_unregister(struct pci_dev *pdev)
{
struct fb_info *info = pci_get_drvdata(pdev);
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- cirrusfb_cleanup (info);
+ cirrusfb_cleanup(info);
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
static struct pci_driver cirrusfb_pci_driver = {
@@ -2477,14 +2481,13 @@ static struct pci_driver cirrusfb_pci_driver = {
};
#endif /* CONFIG_PCI */
-
#ifdef CONFIG_ZORRO
static int cirrusfb_zorro_register(struct zorro_dev *z,
const struct zorro_device_id *ent)
{
struct cirrusfb_info *cinfo;
struct fb_info *info;
- cirrusfb_board_t btype;
+ enum cirrus_board btype;
struct zorro_dev *z2 = NULL;
unsigned long board_addr, board_size, size;
int ret;
@@ -2498,83 +2501,85 @@ static int cirrusfb_zorro_register(struct zorro_dev *z,
info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
if (!info) {
- printk (KERN_ERR "cirrusfb: could not allocate memory\n");
+ printk(KERN_ERR "cirrusfb: could not allocate memory\n");
ret = -ENOMEM;
goto err_out;
}
cinfo = info->par;
- cinfo->info = info;
cinfo->btype = btype;
- assert (z > 0);
- assert (z2 >= 0);
- assert (btype != BT_NONE);
+ assert(z);
+ assert(btype != BT_NONE);
cinfo->zdev = z;
board_addr = zorro_resource_start(z);
board_size = zorro_resource_len(z);
- cinfo->size = size;
+ info->screen_size = size;
if (!zorro_request_device(z, "cirrusfb")) {
- printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n",
+ printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, "
+ "abort\n",
board_addr);
ret = -EBUSY;
goto err_release_fb;
}
- printk (" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr);
+ printk(" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr);
ret = -EIO;
if (btype == BT_PICASSO4) {
- printk (" REG at $%lx\n", board_addr + 0x600000);
+ printk(KERN_INFO " REG at $%lx\n", board_addr + 0x600000);
/* To be precise, for the P4 this is not the */
/* begin of the board, but the begin of RAM. */
/* for P4, map in its address space in 2 chunks (### TEST! ) */
/* (note the ugly hardcoded 16M number) */
- cinfo->regbase = ioremap (board_addr, 16777216);
+ cinfo->regbase = ioremap(board_addr, 16777216);
if (!cinfo->regbase)
goto err_release_region;
- DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase);
+ DPRINTK("cirrusfb: Virtual address for board set to: $%p\n",
+ cinfo->regbase);
cinfo->regbase += 0x600000;
- cinfo->fbregs_phys = board_addr + 0x600000;
+ info->fix.mmio_start = board_addr + 0x600000;
- cinfo->fbmem_phys = board_addr + 16777216;
- cinfo->fbmem = ioremap (cinfo->fbmem_phys, 16777216);
- if (!cinfo->fbmem)
+ info->fix.smem_start = board_addr + 16777216;
+ info->screen_base = ioremap(info->fix.smem_start, 16777216);
+ if (!info->screen_base)
goto err_unmap_regbase;
} else {
- printk (" REG at $%lx\n", (unsigned long) z2->resource.start);
+ printk(KERN_INFO " REG at $%lx\n",
+ (unsigned long) z2->resource.start);
- cinfo->fbmem_phys = board_addr;
+ info->fix.smem_start = board_addr;
if (board_addr > 0x01000000)
- cinfo->fbmem = ioremap (board_addr, board_size);
+ info->screen_base = ioremap(board_addr, board_size);
else
- cinfo->fbmem = (caddr_t) ZTWO_VADDR (board_addr);
- if (!cinfo->fbmem)
+ info->screen_base = (caddr_t) ZTWO_VADDR(board_addr);
+ if (!info->screen_base)
goto err_release_region;
/* set address for REG area of board */
- cinfo->regbase = (caddr_t) ZTWO_VADDR (z2->resource.start);
- cinfo->fbregs_phys = z2->resource.start;
+ cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start);
+ info->fix.mmio_start = z2->resource.start;
- DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase);
+ DPRINTK("cirrusfb: Virtual address for board set to: $%p\n",
+ cinfo->regbase);
}
cinfo->unmap = cirrusfb_zorro_unmap;
- printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
+ printk(KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
zorro_set_drvdata(z, info);
- ret = cirrusfb_register(cinfo);
+ ret = cirrusfb_register(info);
if (ret) {
if (btype == BT_PICASSO4) {
- iounmap(cinfo->fbmem);
+ iounmap(info->screen_base);
iounmap(cinfo->regbase - 0x600000);
} else if (board_addr > 0x01000000)
- iounmap(cinfo->fbmem);
+ iounmap(info->screen_base);
}
return ret;
@@ -2592,11 +2597,11 @@ err_out:
void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
{
struct fb_info *info = zorro_get_drvdata(z);
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- cirrusfb_cleanup (info);
+ cirrusfb_cleanup(info);
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
static struct zorro_driver cirrusfb_zorro_driver = {
@@ -2628,26 +2633,24 @@ static int __init cirrusfb_init(void)
return error;
}
-
-
#ifndef MODULE
static int __init cirrusfb_setup(char *options) {
char *this_opt, s[32];
int i;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
if (!options || !*options)
return 0;
- while ((this_opt = strsep (&options, ",")) != NULL) {
+ while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt) continue;
DPRINTK("cirrusfb_setup: option '%s'\n", this_opt);
for (i = 0; i < NUM_TOTAL_MODES; i++) {
- sprintf (s, "mode:%s", cirrusfb_predefined[i].name);
- if (strcmp (this_opt, s) == 0)
+ sprintf(s, "mode:%s", cirrusfb_predefined[i].name);
+ if (strcmp(this_opt, s) == 0)
cirrusfb_def_mode = i;
}
if (!strcmp(this_opt, "noaccel"))
@@ -2657,7 +2660,6 @@ static int __init cirrusfb_setup(char *options) {
}
#endif
-
/*
* Modularization
*/
@@ -2666,7 +2668,7 @@ MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
MODULE_LICENSE("GPL");
-static void __exit cirrusfb_exit (void)
+static void __exit cirrusfb_exit(void)
{
#ifdef CONFIG_PCI
pci_unregister_driver(&cirrusfb_pci_driver);
@@ -2682,66 +2684,67 @@ module_init(cirrusfb_init);
module_exit(cirrusfb_exit);
#endif
-
/**********************************************************************/
/* about the following functions - I have used the same names for the */
/* functions as Markus Wild did in his Retina driver for NetBSD as */
/* they just made sense for this purpose. Apart from that, I wrote */
-/* these functions myself. */
+/* these functions myself. */
/**********************************************************************/
/*** WGen() - write into one of the external/general registers ***/
-static void WGen (const struct cirrusfb_info *cinfo,
+static void WGen(const struct cirrusfb_info *cinfo,
int regnum, unsigned char val)
{
unsigned long regofs = 0;
if (cinfo->btype == BT_PICASSO) {
/* Picasso II specific hack */
-/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
+/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
+ regnum == CL_VSSM2) */
if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
regofs = 0xfff;
}
- vga_w (cinfo->regbase, regofs + regnum, val);
+ vga_w(cinfo->regbase, regofs + regnum, val);
}
/*** RGen() - read out one of the external/general registers ***/
-static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum)
+static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum)
{
unsigned long regofs = 0;
if (cinfo->btype == BT_PICASSO) {
/* Picasso II specific hack */
-/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
+/* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
+ regnum == CL_VSSM2) */
if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
regofs = 0xfff;
}
- return vga_r (cinfo->regbase, regofs + regnum);
+ return vga_r(cinfo->regbase, regofs + regnum);
}
/*** AttrOn() - turn on VideoEnable for Attribute controller ***/
-static void AttrOn (const struct cirrusfb_info *cinfo)
+static void AttrOn(const struct cirrusfb_info *cinfo)
{
- assert (cinfo != NULL);
+ assert(cinfo != NULL);
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
- if (vga_rcrt (cinfo->regbase, CL_CRT24) & 0x80) {
+ if (vga_rcrt(cinfo->regbase, CL_CRT24) & 0x80) {
/* if we're just in "write value" mode, write back the */
/* same value as before to not modify anything */
- vga_w (cinfo->regbase, VGA_ATT_IW,
- vga_r (cinfo->regbase, VGA_ATT_R));
+ vga_w(cinfo->regbase, VGA_ATT_IW,
+ vga_r(cinfo->regbase, VGA_ATT_R));
}
/* turn on video bit */
-/* vga_w (cinfo->regbase, VGA_ATT_IW, 0x20); */
- vga_w (cinfo->regbase, VGA_ATT_IW, 0x33);
+/* vga_w(cinfo->regbase, VGA_ATT_IW, 0x20); */
+ vga_w(cinfo->regbase, VGA_ATT_IW, 0x33);
/* dummy write on Reg0 to be on "write index" mode next time */
- vga_w (cinfo->regbase, VGA_ATT_IW, 0x00);
+ vga_w(cinfo->regbase, VGA_ATT_IW, 0x00);
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
/*** WHDR() - write into the Hidden DAC register ***/
@@ -2750,119 +2753,115 @@ static void AttrOn (const struct cirrusfb_info *cinfo)
* registers of their functional group) here is a specialized routine for
* accessing the HDR
*/
-static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val)
+static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val)
{
unsigned char dummy;
if (cinfo->btype == BT_PICASSO) {
/* Klaus' hint for correct access to HDR on some boards */
/* first write 0 to pixel mask (3c6) */
- WGen (cinfo, VGA_PEL_MSK, 0x00);
- udelay (200);
+ WGen(cinfo, VGA_PEL_MSK, 0x00);
+ udelay(200);
/* next read dummy from pixel address (3c8) */
- dummy = RGen (cinfo, VGA_PEL_IW);
- udelay (200);
+ dummy = RGen(cinfo, VGA_PEL_IW);
+ udelay(200);
}
/* now do the usual stuff to access the HDR */
- dummy = RGen (cinfo, VGA_PEL_MSK);
- udelay (200);
- dummy = RGen (cinfo, VGA_PEL_MSK);
- udelay (200);
- dummy = RGen (cinfo, VGA_PEL_MSK);
- udelay (200);
- dummy = RGen (cinfo, VGA_PEL_MSK);
- udelay (200);
+ dummy = RGen(cinfo, VGA_PEL_MSK);
+ udelay(200);
+ dummy = RGen(cinfo, VGA_PEL_MSK);
+ udelay(200);
+ dummy = RGen(cinfo, VGA_PEL_MSK);
+ udelay(200);
+ dummy = RGen(cinfo, VGA_PEL_MSK);
+ udelay(200);
- WGen (cinfo, VGA_PEL_MSK, val);
- udelay (200);
+ WGen(cinfo, VGA_PEL_MSK, val);
+ udelay(200);
if (cinfo->btype == BT_PICASSO) {
/* now first reset HDR access counter */
- dummy = RGen (cinfo, VGA_PEL_IW);
- udelay (200);
+ dummy = RGen(cinfo, VGA_PEL_IW);
+ udelay(200);
/* and at the end, restore the mask value */
/* ## is this mask always 0xff? */
- WGen (cinfo, VGA_PEL_MSK, 0xff);
- udelay (200);
+ WGen(cinfo, VGA_PEL_MSK, 0xff);
+ udelay(200);
}
}
-
/*** WSFR() - write to the "special function register" (SFR) ***/
-static void WSFR (struct cirrusfb_info *cinfo, unsigned char val)
+static void WSFR(struct cirrusfb_info *cinfo, unsigned char val)
{
#ifdef CONFIG_ZORRO
- assert (cinfo->regbase != NULL);
+ assert(cinfo->regbase != NULL);
cinfo->SFR = val;
- z_writeb (val, cinfo->regbase + 0x8000);
+ z_writeb(val, cinfo->regbase + 0x8000);
#endif
}
/* The Picasso has a second register for switching the monitor bit */
-static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val)
+static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val)
{
#ifdef CONFIG_ZORRO
/* writing an arbitrary value to this one causes the monitor switcher */
/* to flip to Amiga display */
- assert (cinfo->regbase != NULL);
+ assert(cinfo->regbase != NULL);
cinfo->SFR = val;
- z_writeb (val, cinfo->regbase + 0x9000);
+ z_writeb(val, cinfo->regbase + 0x9000);
#endif
}
-
/*** WClut - set CLUT entry (range: 0..63) ***/
-static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
+static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
unsigned char green, unsigned char blue)
{
unsigned int data = VGA_PEL_D;
/* address write mode register is not translated.. */
- vga_w (cinfo->regbase, VGA_PEL_IW, regnum);
+ vga_w(cinfo->regbase, VGA_PEL_IW, regnum);
if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
/* but DAC data register IS, at least for Picasso II */
if (cinfo->btype == BT_PICASSO)
data += 0xfff;
- vga_w (cinfo->regbase, data, red);
- vga_w (cinfo->regbase, data, green);
- vga_w (cinfo->regbase, data, blue);
+ vga_w(cinfo->regbase, data, red);
+ vga_w(cinfo->regbase, data, green);
+ vga_w(cinfo->regbase, data, blue);
} else {
- vga_w (cinfo->regbase, data, blue);
- vga_w (cinfo->regbase, data, green);
- vga_w (cinfo->regbase, data, red);
+ vga_w(cinfo->regbase, data, blue);
+ vga_w(cinfo->regbase, data, green);
+ vga_w(cinfo->regbase, data, red);
}
}
-
#if 0
/*** RClut - read CLUT entry (range 0..63) ***/
-static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
+static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
unsigned char *green, unsigned char *blue)
{
unsigned int data = VGA_PEL_D;
- vga_w (cinfo->regbase, VGA_PEL_IR, regnum);
+ vga_w(cinfo->regbase, VGA_PEL_IR, regnum);
if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
if (cinfo->btype == BT_PICASSO)
data += 0xfff;
- *red = vga_r (cinfo->regbase, data);
- *green = vga_r (cinfo->regbase, data);
- *blue = vga_r (cinfo->regbase, data);
+ *red = vga_r(cinfo->regbase, data);
+ *green = vga_r(cinfo->regbase, data);
+ *blue = vga_r(cinfo->regbase, data);
} else {
- *blue = vga_r (cinfo->regbase, data);
- *green = vga_r (cinfo->regbase, data);
- *red = vga_r (cinfo->regbase, data);
+ *blue = vga_r(cinfo->regbase, data);
+ *green = vga_r(cinfo->regbase, data);
+ *red = vga_r(cinfo->regbase, data);
}
}
#endif
-
/*******************************************************************
cirrusfb_WaitBLT()
@@ -2870,10 +2869,10 @@ static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned c
*********************************************************************/
/* FIXME: use interrupts instead */
-static void cirrusfb_WaitBLT (u8 __iomem *regbase)
+static void cirrusfb_WaitBLT(u8 __iomem *regbase)
{
/* now busy-wait until we're done */
- while (vga_rgfx (regbase, CL_GR31) & 0x08)
+ while (vga_rgfx(regbase, CL_GR31) & 0x08)
/* do nothing */ ;
}
@@ -2883,15 +2882,17 @@ static void cirrusfb_WaitBLT (u8 __iomem *regbase)
perform accelerated "scrolling"
********************************************************************/
-static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel,
- u_short curx, u_short cury, u_short destx, u_short desty,
- u_short width, u_short height, u_short line_length)
+static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
+ u_short curx, u_short cury,
+ u_short destx, u_short desty,
+ u_short width, u_short height,
+ u_short line_length)
{
u_short nwidth, nheight;
u_long nsrc, ndest;
u_char bltmode;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
nwidth = width - 1;
nheight = height - 1;
@@ -2911,9 +2912,13 @@ static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel,
nsrc = (cury * line_length) + curx;
ndest = (desty * line_length) + destx;
} else {
- /* this means start addresses are at the end, counting backwards */
- nsrc = cury * line_length + curx + nheight * line_length + nwidth;
- ndest = desty * line_length + destx + nheight * line_length + nwidth;
+ /* this means start addresses are at the end,
+ * counting backwards
+ */
+ nsrc = cury * line_length + curx +
+ nheight * line_length + nwidth;
+ ndest = desty * line_length + destx +
+ nheight * line_length + nwidth;
}
/*
@@ -2929,52 +2934,65 @@ static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel,
start/stop
*/
- cirrusfb_WaitBLT(regbase);
+ cirrusfb_WaitBLT(regbase);
/* pitch: set to line_length */
- vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */
- vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */
- vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */
- vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */
+ /* dest pitch low */
+ vga_wgfx(regbase, CL_GR24, line_length & 0xff);
+ /* dest pitch hi */
+ vga_wgfx(regbase, CL_GR25, line_length >> 8);
+ /* source pitch low */
+ vga_wgfx(regbase, CL_GR26, line_length & 0xff);
+ /* source pitch hi */
+ vga_wgfx(regbase, CL_GR27, line_length >> 8);
/* BLT width: actual number of pixels - 1 */
- vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */
- vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */
+ /* BLT width low */
+ vga_wgfx(regbase, CL_GR20, nwidth & 0xff);
+ /* BLT width hi */
+ vga_wgfx(regbase, CL_GR21, nwidth >> 8);
/* BLT height: actual number of lines -1 */
- vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */
- vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */
+ /* BLT height low */
+ vga_wgfx(regbase, CL_GR22, nheight & 0xff);
+ /* BLT width hi */
+ vga_wgfx(regbase, CL_GR23, nheight >> 8);
/* BLT destination */
- vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */
- vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */
- vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */
+ /* BLT dest low */
+ vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff));
+ /* BLT dest mid */
+ vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8));
+ /* BLT dest hi */
+ vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16));
/* BLT source */
- vga_wgfx (regbase, CL_GR2C, (u_char) (nsrc & 0xff)); /* BLT src low */
- vga_wgfx (regbase, CL_GR2D, (u_char) (nsrc >> 8)); /* BLT src mid */
- vga_wgfx (regbase, CL_GR2E, (u_char) (nsrc >> 16)); /* BLT src hi */
+ /* BLT src low */
+ vga_wgfx(regbase, CL_GR2C, (u_char) (nsrc & 0xff));
+ /* BLT src mid */
+ vga_wgfx(regbase, CL_GR2D, (u_char) (nsrc >> 8));
+ /* BLT src hi */
+ vga_wgfx(regbase, CL_GR2E, (u_char) (nsrc >> 16));
/* BLT mode */
- vga_wgfx (regbase, CL_GR30, bltmode); /* BLT mode */
+ vga_wgfx(regbase, CL_GR30, bltmode); /* BLT mode */
/* BLT ROP: SrcCopy */
- vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */
+ vga_wgfx(regbase, CL_GR32, 0x0d); /* BLT ROP */
/* and finally: GO! */
- vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */
+ vga_wgfx(regbase, CL_GR31, 0x02); /* BLT Start/status */
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
-
/*******************************************************************
cirrusfb_RectFill()
perform accelerated rectangle fill
********************************************************************/
-static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel,
+static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
u_short x, u_short y, u_short width, u_short height,
u_char color, u_short line_length)
{
@@ -2982,93 +3000,95 @@ static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel,
u_long ndest;
u_char op;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
nwidth = width - 1;
nheight = height - 1;
ndest = (y * line_length) + x;
- cirrusfb_WaitBLT(regbase);
+ cirrusfb_WaitBLT(regbase);
/* pitch: set to line_length */
- vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */
- vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */
- vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */
- vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */
+ vga_wgfx(regbase, CL_GR24, line_length & 0xff); /* dest pitch low */
+ vga_wgfx(regbase, CL_GR25, line_length >> 8); /* dest pitch hi */
+ vga_wgfx(regbase, CL_GR26, line_length & 0xff); /* source pitch low */
+ vga_wgfx(regbase, CL_GR27, line_length >> 8); /* source pitch hi */
/* BLT width: actual number of pixels - 1 */
- vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */
- vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */
+ vga_wgfx(regbase, CL_GR20, nwidth & 0xff); /* BLT width low */
+ vga_wgfx(regbase, CL_GR21, nwidth >> 8); /* BLT width hi */
/* BLT height: actual number of lines -1 */
- vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */
- vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */
+ vga_wgfx(regbase, CL_GR22, nheight & 0xff); /* BLT height low */
+ vga_wgfx(regbase, CL_GR23, nheight >> 8); /* BLT width hi */
/* BLT destination */
- vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */
- vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */
- vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */
+ /* BLT dest low */
+ vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff));
+ /* BLT dest mid */
+ vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8));
+ /* BLT dest hi */
+ vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16));
/* BLT source: set to 0 (is a dummy here anyway) */
- vga_wgfx (regbase, CL_GR2C, 0x00); /* BLT src low */
- vga_wgfx (regbase, CL_GR2D, 0x00); /* BLT src mid */
- vga_wgfx (regbase, CL_GR2E, 0x00); /* BLT src hi */
+ vga_wgfx(regbase, CL_GR2C, 0x00); /* BLT src low */
+ vga_wgfx(regbase, CL_GR2D, 0x00); /* BLT src mid */
+ vga_wgfx(regbase, CL_GR2E, 0x00); /* BLT src hi */
/* This is a ColorExpand Blt, using the */
/* same color for foreground and background */
- vga_wgfx (regbase, VGA_GFX_SR_VALUE, color); /* foreground color */
- vga_wgfx (regbase, VGA_GFX_SR_ENABLE, color); /* background color */
+ vga_wgfx(regbase, VGA_GFX_SR_VALUE, color); /* foreground color */
+ vga_wgfx(regbase, VGA_GFX_SR_ENABLE, color); /* background color */
op = 0xc0;
if (bits_per_pixel == 16) {
- vga_wgfx (regbase, CL_GR10, color); /* foreground color */
- vga_wgfx (regbase, CL_GR11, color); /* background color */
+ vga_wgfx(regbase, CL_GR10, color); /* foreground color */
+ vga_wgfx(regbase, CL_GR11, color); /* background color */
op = 0x50;
op = 0xd0;
} else if (bits_per_pixel == 32) {
- vga_wgfx (regbase, CL_GR10, color); /* foreground color */
- vga_wgfx (regbase, CL_GR11, color); /* background color */
- vga_wgfx (regbase, CL_GR12, color); /* foreground color */
- vga_wgfx (regbase, CL_GR13, color); /* background color */
- vga_wgfx (regbase, CL_GR14, 0); /* foreground color */
- vga_wgfx (regbase, CL_GR15, 0); /* background color */
+ vga_wgfx(regbase, CL_GR10, color); /* foreground color */
+ vga_wgfx(regbase, CL_GR11, color); /* background color */
+ vga_wgfx(regbase, CL_GR12, color); /* foreground color */
+ vga_wgfx(regbase, CL_GR13, color); /* background color */
+ vga_wgfx(regbase, CL_GR14, 0); /* foreground color */
+ vga_wgfx(regbase, CL_GR15, 0); /* background color */
op = 0x50;
op = 0xf0;
}
/* BLT mode: color expand, Enable 8x8 copy (faster?) */
- vga_wgfx (regbase, CL_GR30, op); /* BLT mode */
+ vga_wgfx(regbase, CL_GR30, op); /* BLT mode */
/* BLT ROP: SrcCopy */
- vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */
+ vga_wgfx(regbase, CL_GR32, 0x0d); /* BLT ROP */
/* and finally: GO! */
- vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */
+ vga_wgfx(regbase, CL_GR31, 0x02); /* BLT Start/status */
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
-
/**************************************************************************
* bestclock() - determine closest possible clock lower(?) than the
* desired pixel clock
**************************************************************************/
-static void bestclock (long freq, long *best, long *nom,
+static void bestclock(long freq, long *best, long *nom,
long *den, long *div, long maxfreq)
{
long n, h, d, f;
- assert (best != NULL);
- assert (nom != NULL);
- assert (den != NULL);
- assert (div != NULL);
- assert (maxfreq > 0);
+ assert(best != NULL);
+ assert(nom != NULL);
+ assert(den != NULL);
+ assert(div != NULL);
+ assert(maxfreq > 0);
*nom = 0;
*den = 0;
*div = 0;
- DPRINTK ("ENTER\n");
+ DPRINTK("ENTER\n");
if (freq < 8000)
freq = 8000;
@@ -3085,7 +3105,7 @@ static void bestclock (long freq, long *best, long *nom,
if (d > 31)
d = (d / 2) * 2;
h = (14318 * n) / d;
- if (abs (h - freq) < abs (*best - freq)) {
+ if (abs(h - freq) < abs(*best - freq)) {
*best = h;
*nom = n;
if (d < 32) {
@@ -3102,7 +3122,7 @@ static void bestclock (long freq, long *best, long *nom,
if (d > 31)
d = (d / 2) * 2;
h = (14318 * n) / d;
- if (abs (h - freq) < abs (*best - freq)) {
+ if (abs(h - freq) < abs(*best - freq)) {
*best = h;
*nom = n;
if (d < 32) {
@@ -3116,14 +3136,13 @@ static void bestclock (long freq, long *best, long *nom,
}
}
- DPRINTK ("Best possible values for given frequency:\n");
- DPRINTK (" best: %ld kHz nom: %ld den: %ld div: %ld\n",
- freq, *nom, *den, *div);
+ DPRINTK("Best possible values for given frequency:\n");
+ DPRINTK(" best: %ld kHz nom: %ld den: %ld div: %ld\n",
+ freq, *nom, *den, *div);
- DPRINTK ("EXIT\n");
+ DPRINTK("EXIT\n");
}
-
/* -------------------------------------------------------------------------
*
* debugging functions
@@ -3145,21 +3164,20 @@ static void bestclock (long freq, long *best, long *nom,
*/
static
-void cirrusfb_dbg_print_byte (const char *name, unsigned char val)
+void cirrusfb_dbg_print_byte(const char *name, unsigned char val)
{
- DPRINTK ("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n",
- name, val,
- val & 0x80 ? '1' : '0',
- val & 0x40 ? '1' : '0',
- val & 0x20 ? '1' : '0',
- val & 0x10 ? '1' : '0',
- val & 0x08 ? '1' : '0',
- val & 0x04 ? '1' : '0',
- val & 0x02 ? '1' : '0',
- val & 0x01 ? '1' : '0');
+ DPRINTK("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n",
+ name, val,
+ val & 0x80 ? '1' : '0',
+ val & 0x40 ? '1' : '0',
+ val & 0x20 ? '1' : '0',
+ val & 0x10 ? '1' : '0',
+ val & 0x08 ? '1' : '0',
+ val & 0x04 ? '1' : '0',
+ val & 0x02 ? '1' : '0',
+ val & 0x01 ? '1' : '0');
}
-
/**
* cirrusfb_dbg_print_regs
* @base: If using newmmio, the newmmio base address, otherwise %NULL
@@ -3172,25 +3190,26 @@ void cirrusfb_dbg_print_byte (const char *name, unsigned char val)
*/
static
-void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...)
+void cirrusfb_dbg_print_regs(caddr_t regbase,
+ enum cirrusfb_dbg_reg_class reg_class, ...)
{
va_list list;
unsigned char val = 0;
unsigned reg;
char *name;
- va_start (list, reg_class);
+ va_start(list, reg_class);
- name = va_arg (list, char *);
+ name = va_arg(list, char *);
while (name != NULL) {
- reg = va_arg (list, int);
+ reg = va_arg(list, int);
switch (reg_class) {
case CRT:
- val = vga_rcrt (regbase, (unsigned char) reg);
+ val = vga_rcrt(regbase, (unsigned char) reg);
break;
case SEQ:
- val = vga_rseq (regbase, (unsigned char) reg);
+ val = vga_rseq(regbase, (unsigned char) reg);
break;
default:
/* should never occur */
@@ -3198,15 +3217,14 @@ void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_clas
break;
}
- cirrusfb_dbg_print_byte (name, val);
+ cirrusfb_dbg_print_byte(name, val);
- name = va_arg (list, char *);
+ name = va_arg(list, char *);
}
- va_end (list);
+ va_end(list);
}
-
/**
* cirrusfb_dump
* @cirrusfbinfo:
@@ -3214,13 +3232,11 @@ void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_clas
* DESCRIPTION:
*/
-static
-void cirrusfb_dump (void)
+static void cirrusfb_dump(void)
{
- cirrusfb_dbg_reg_dump (NULL);
+ cirrusfb_dbg_reg_dump(NULL);
}
-
/**
* cirrusfb_dbg_reg_dump
* @base: If using newmmio, the newmmio base address, otherwise %NULL
@@ -3232,11 +3248,11 @@ void cirrusfb_dump (void)
*/
static
-void cirrusfb_dbg_reg_dump (caddr_t regbase)
+void cirrusfb_dbg_reg_dump(caddr_t regbase)
{
- DPRINTK ("CIRRUSFB VGA CRTC register dump:\n");
+ DPRINTK("CIRRUSFB VGA CRTC register dump:\n");
- cirrusfb_dbg_print_regs (regbase, CRT,
+ cirrusfb_dbg_print_regs(regbase, CRT,
"CR00", 0x00,
"CR01", 0x01,
"CR02", 0x02,
@@ -3286,11 +3302,11 @@ void cirrusfb_dbg_reg_dump (caddr_t regbase)
"CR3F", 0x3F,
NULL);
- DPRINTK ("\n");
+ DPRINTK("\n");
- DPRINTK ("CIRRUSFB VGA SEQ register dump:\n");
+ DPRINTK("CIRRUSFB VGA SEQ register dump:\n");
- cirrusfb_dbg_print_regs (regbase, SEQ,
+ cirrusfb_dbg_print_regs(regbase, SEQ,
"SR00", 0x00,
"SR01", 0x01,
"SR02", 0x02,
@@ -3319,7 +3335,7 @@ void cirrusfb_dbg_reg_dump (caddr_t regbase)
"SR1F", 0x1F,
NULL);
- DPRINTK ("\n");
+ DPRINTK("\n");
}
#endif /* CIRRUSFB_DEBUG */
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
index dea6579941b..17b5267f44d 100644
--- a/drivers/video/clps711xfb.c
+++ b/drivers/video/clps711xfb.c
@@ -29,7 +29,7 @@
#include <asm/hardware.h>
#include <asm/mach-types.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/hardware/clps7111.h>
#include <asm/arch/syspld.h>
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index a22ccf9485a..267422f6625 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -27,7 +27,7 @@ config VGACON_SOFT_SCROLLBACK
The scrollback buffer of the standard VGA console is located in
the VGA RAM. The size of this RAM is fixed and is quite small.
If you require a larger scrollback buffer, this can be placed in
- System RAM which is dynamically allocated during intialization.
+ System RAM which is dynamically allocated during initialization.
Placing the scrollback buffer in System RAM will slightly slow
down the console.
diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c
index d9315d99445..b63860f7bea 100644
--- a/drivers/video/console/dummycon.c
+++ b/drivers/video/console/dummycon.c
@@ -18,8 +18,8 @@
*/
#if defined(__arm__)
-#define DUMMY_COLUMNS ORIG_VIDEO_COLS
-#define DUMMY_ROWS ORIG_VIDEO_LINES
+#define DUMMY_COLUMNS screen_info.orig_video_cols
+#define DUMMY_ROWS screen_info.orig_video_lines
#elif defined(__hppa__)
/* set by Kconfig. Use 80x25 for 640x480 and 160x64 for 1280x1024 */
#define DUMMY_COLUMNS CONFIG_DUMMY_CONSOLE_COLUMNS
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index e58c87b3e3a..0f32f4a00b2 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -78,7 +78,6 @@
#include <asm/fb.h>
#include <asm/irq.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
#ifdef CONFIG_ATARI
#include <asm/atariints.h>
#endif
@@ -2169,7 +2168,7 @@ static __inline__ void updatescrollmode(struct display *p,
}
static int fbcon_resize(struct vc_data *vc, unsigned int width,
- unsigned int height)
+ unsigned int height, unsigned int user)
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct fbcon_ops *ops = info->fbcon_par;
@@ -2406,7 +2405,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
update_screen(vc);
}
- if (fbcon_is_inactive(vc, info) ||
+ if (mode_switch || fbcon_is_inactive(vc, info) ||
ops->blank_state != FB_BLANK_UNBLANK)
fbcon_del_cursor_timer(info);
else
diff --git a/drivers/video/console/font_10x18.c b/drivers/video/console/font_10x18.c
index e6aa0eab5bb..6be72bb218e 100644
--- a/drivers/video/console/font_10x18.c
+++ b/drivers/video/console/font_10x18.c
@@ -5133,14 +5133,14 @@ static const unsigned char fontdata_10x18[FONTDATAMAX] = {
const struct font_desc font_10x18 = {
- FONT10x18_IDX,
- "10x18",
- 10,
- 18,
- fontdata_10x18,
+ .idx = FONT10x18_IDX,
+ .name = "10x18",
+ .width = 10,
+ .height = 18,
+ .data = fontdata_10x18,
#ifdef __sparc__
- 5
+ .pref = 5,
#else
- -1
+ .pref = -1,
#endif
};
diff --git a/drivers/video/console/font_6x11.c b/drivers/video/console/font_6x11.c
index 89976cd9749..46e86e67aa6 100644
--- a/drivers/video/console/font_6x11.c
+++ b/drivers/video/console/font_6x11.c
@@ -3342,10 +3342,11 @@ static const unsigned char fontdata_6x11[FONTDATAMAX] = {
const struct font_desc font_vga_6x11 = {
- VGA6x11_IDX,
- "ProFont6x11",
- 6,
- 11,
- fontdata_6x11,
- -2000 /* Try avoiding this font if possible unless on MAC */
+ .idx = VGA6x11_IDX,
+ .name = "ProFont6x11",
+ .width = 6,
+ .height = 11,
+ .data = fontdata_6x11,
+ /* Try avoiding this font if possible unless on MAC */
+ .pref = -2000,
};
diff --git a/drivers/video/console/font_7x14.c b/drivers/video/console/font_7x14.c
index bbf11664739..3b7dbf9c060 100644
--- a/drivers/video/console/font_7x14.c
+++ b/drivers/video/console/font_7x14.c
@@ -4109,10 +4109,10 @@ static const unsigned char fontdata_7x14[FONTDATAMAX] = {
const struct font_desc font_7x14 = {
- FONT7x14_IDX,
- "7x14",
- 7,
- 14,
- fontdata_7x14,
- 0
+ .idx = FONT7x14_IDX,
+ .name = "7x14",
+ .width = 7,
+ .height = 14,
+ .data = fontdata_7x14,
+ .pref = 0,
};
diff --git a/drivers/video/console/font_8x16.c b/drivers/video/console/font_8x16.c
index 74fe86f28ff..00a0c67a5c7 100644
--- a/drivers/video/console/font_8x16.c
+++ b/drivers/video/console/font_8x16.c
@@ -5,6 +5,7 @@
/**********************************************/
#include <linux/font.h>
+#include <linux/module.h>
#define FONTDATAMAX 4096
@@ -4622,10 +4623,11 @@ static const unsigned char fontdata_8x16[FONTDATAMAX] = {
const struct font_desc font_vga_8x16 = {
- VGA8x16_IDX,
- "VGA8x16",
- 8,
- 16,
- fontdata_8x16,
- 0
+ .idx = VGA8x16_IDX,
+ .name = "VGA8x16",
+ .width = 8,
+ .height = 16,
+ .data = fontdata_8x16,
+ .pref = 0,
};
+EXPORT_SYMBOL(font_vga_8x16);
diff --git a/drivers/video/console/font_8x8.c b/drivers/video/console/font_8x8.c
index 26199f8ee90..9f56efe2cee 100644
--- a/drivers/video/console/font_8x8.c
+++ b/drivers/video/console/font_8x8.c
@@ -2574,10 +2574,10 @@ static const unsigned char fontdata_8x8[FONTDATAMAX] = {
const struct font_desc font_vga_8x8 = {
- VGA8x8_IDX,
- "VGA8x8",
- 8,
- 8,
- fontdata_8x8,
- 0
+ .idx = VGA8x8_IDX,
+ .name = "VGA8x8",
+ .width = 8,
+ .height = 8,
+ .data = fontdata_8x8,
+ .pref = 0,
};
diff --git a/drivers/video/console/font_acorn_8x8.c b/drivers/video/console/font_acorn_8x8.c
index 40f3d4eeb19..639e31ae110 100644
--- a/drivers/video/console/font_acorn_8x8.c
+++ b/drivers/video/console/font_acorn_8x8.c
@@ -262,14 +262,14 @@ static const unsigned char acorndata_8x8[] = {
};
const struct font_desc font_acorn_8x8 = {
- ACORN8x8_IDX,
- "Acorn8x8",
- 8,
- 8,
- acorndata_8x8,
+ .idx = ACORN8x8_IDX,
+ .name = "Acorn8x8",
+ .width = 8,
+ .height = 8,
+ .data = acorndata_8x8,
#ifdef CONFIG_ARCH_ACORN
- 20
+ .pref = 20,
#else
- 0
+ .pref = 0,
#endif
};
diff --git a/drivers/video/console/font_mini_4x6.c b/drivers/video/console/font_mini_4x6.c
index d818234fdf1..a19a7f33133 100644
--- a/drivers/video/console/font_mini_4x6.c
+++ b/drivers/video/console/font_mini_4x6.c
@@ -2148,11 +2148,11 @@ static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = {
};
const struct font_desc font_mini_4x6 = {
- MINI4x6_IDX,
- "MINI4x6",
- 4,
- 6,
- fontdata_mini_4x6,
- 3
+ .idx = MINI4x6_IDX,
+ .name = "MINI4x6",
+ .width = 4,
+ .height = 6,
+ .data = fontdata_mini_4x6,
+ .pref = 3,
};
diff --git a/drivers/video/console/font_pearl_8x8.c b/drivers/video/console/font_pearl_8x8.c
index e646c88f55c..dc6ad539ca4 100644
--- a/drivers/video/console/font_pearl_8x8.c
+++ b/drivers/video/console/font_pearl_8x8.c
@@ -2578,10 +2578,10 @@ static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = {
};
const struct font_desc font_pearl_8x8 = {
- PEARL8x8_IDX,
- "PEARL8x8",
- 8,
- 8,
- fontdata_pearl8x8,
- 2
+ .idx = PEARL8x8_IDX,
+ .name = "PEARL8x8",
+ .width = 8,
+ .height = 8,
+ .data = fontdata_pearl8x8,
+ .pref = 2,
};
diff --git a/drivers/video/console/font_sun12x22.c b/drivers/video/console/font_sun12x22.c
index ab5eb93407b..d3643853c33 100644
--- a/drivers/video/console/font_sun12x22.c
+++ b/drivers/video/console/font_sun12x22.c
@@ -6152,14 +6152,14 @@ static const unsigned char fontdata_sun12x22[FONTDATAMAX] = {
const struct font_desc font_sun_12x22 = {
- SUN12x22_IDX,
- "SUN12x22",
- 12,
- 22,
- fontdata_sun12x22,
+ .idx = SUN12x22_IDX,
+ .name = "SUN12x22",
+ .width = 12,
+ .height = 22,
+ .data = fontdata_sun12x22,
#ifdef __sparc__
- 5
+ .pref = 5,
#else
- -1
+ .pref = -1,
#endif
};
diff --git a/drivers/video/console/font_sun8x16.c b/drivers/video/console/font_sun8x16.c
index 41f910f5529..5abf290c6eb 100644
--- a/drivers/video/console/font_sun8x16.c
+++ b/drivers/video/console/font_sun8x16.c
@@ -262,14 +262,14 @@ static const unsigned char fontdata_sun8x16[FONTDATAMAX] = {
};
const struct font_desc font_sun_8x16 = {
- SUN8x16_IDX,
- "SUN8x16",
- 8,
- 16,
- fontdata_sun8x16,
+ .idx = SUN8x16_IDX,
+ .name = "SUN8x16",
+ .width = 8,
+ .height = 16,
+ .data = fontdata_sun8x16,
#ifdef __sparc__
- 10
+ .pref = 10,
#else
- -1
+ .pref = -1,
#endif
};
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index dda0586ab3f..d31b203bf65 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -98,14 +98,19 @@ static inline void newport_init_cmap(void)
}
}
-static void newport_show_logo(void)
+static const struct linux_logo *newport_show_logo(void)
{
#ifdef CONFIG_LOGO_SGI_CLUT224
const struct linux_logo *logo = fb_find_logo(8);
- const unsigned char *clut = logo->clut;
- const unsigned char *data = logo->data;
+ const unsigned char *clut;
+ const unsigned char *data;
unsigned long i;
+ if (!logo)
+ return NULL;
+ clut = logo->clut;
+ data = logo->data;
+
for (i = 0; i < logo->clutsize; i++) {
newport_bfwait(npregs);
newport_cmap_setaddr(npregs, i + 0x20);
@@ -123,6 +128,8 @@ static void newport_show_logo(void)
for (i = 0; i < logo->width*logo->height; i++)
npregs->go.hostrw0 = *data++ << 24;
+
+ return logo;
#endif /* CONFIG_LOGO_SGI_CLUT224 */
}
@@ -465,9 +472,10 @@ static int newport_switch(struct vc_data *vc)
npregs->cset.topscan = 0x3ff;
if (!logo_drawn) {
- newport_show_logo();
- logo_drawn = 1;
- logo_active = 1;
+ if (newport_show_logo()) {
+ logo_drawn = 1;
+ logo_active = 1;
+ }
}
return 1;
diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c
index 03cfb7ac573..25f835bf3d7 100644
--- a/drivers/video/console/softcursor.c
+++ b/drivers/video/console/softcursor.c
@@ -15,7 +15,6 @@
#include <linux/fb.h>
#include <linux/slab.h>
-#include <asm/uaccess.h>
#include <asm/io.h>
#include "fbcon.h"
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index d18b73aafa0..f65bcd314d5 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -362,7 +362,7 @@ static const char *vgacon_startup(void)
u16 saved1, saved2;
volatile u16 *p;
- if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB) {
+ if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB) {
no_vga:
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
@@ -372,29 +372,30 @@ static const char *vgacon_startup(void)
#endif
}
- /* SCREEN_INFO initialized? */
- if ((ORIG_VIDEO_MODE == 0) &&
- (ORIG_VIDEO_LINES == 0) &&
- (ORIG_VIDEO_COLS == 0))
+ /* boot_params.screen_info initialized? */
+ if ((screen_info.orig_video_mode == 0) &&
+ (screen_info.orig_video_lines == 0) &&
+ (screen_info.orig_video_cols == 0))
goto no_vga;
/* VGA16 modes are not handled by VGACON */
- if ((ORIG_VIDEO_MODE == 0x0D) || /* 320x200/4 */
- (ORIG_VIDEO_MODE == 0x0E) || /* 640x200/4 */
- (ORIG_VIDEO_MODE == 0x10) || /* 640x350/4 */
- (ORIG_VIDEO_MODE == 0x12) || /* 640x480/4 */
- (ORIG_VIDEO_MODE == 0x6A)) /* 800x600/4, 0x6A is very common */
+ if ((screen_info.orig_video_mode == 0x0D) || /* 320x200/4 */
+ (screen_info.orig_video_mode == 0x0E) || /* 640x200/4 */
+ (screen_info.orig_video_mode == 0x10) || /* 640x350/4 */
+ (screen_info.orig_video_mode == 0x12) || /* 640x480/4 */
+ (screen_info.orig_video_mode == 0x6A)) /* 800x600/4 (VESA) */
goto no_vga;
- vga_video_num_lines = ORIG_VIDEO_LINES;
- vga_video_num_columns = ORIG_VIDEO_COLS;
+ vga_video_num_lines = screen_info.orig_video_lines;
+ vga_video_num_columns = screen_info.orig_video_cols;
state.vgabase = NULL;
- if (ORIG_VIDEO_MODE == 7) { /* Is this a monochrome display? */
+ if (screen_info.orig_video_mode == 7) {
+ /* Monochrome display */
vga_vram_base = 0xb0000;
vga_video_port_reg = VGA_CRT_IM;
vga_video_port_val = VGA_CRT_DM;
- if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
+ if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
static struct resource ega_console_resource =
{ .name = "ega", .start = 0x3B0, .end = 0x3BF };
vga_video_type = VIDEO_TYPE_EGAM;
@@ -422,12 +423,12 @@ static const char *vgacon_startup(void)
vga_vram_base = 0xb8000;
vga_video_port_reg = VGA_CRT_IC;
vga_video_port_val = VGA_CRT_DC;
- if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
+ if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) {
int i;
vga_vram_size = 0x8000;
- if (!ORIG_VIDEO_ISVGA) {
+ if (!screen_info.orig_video_isVGA) {
static struct resource ega_console_resource
= { .name = "ega", .start = 0x3C0, .end = 0x3DF };
vga_video_type = VIDEO_TYPE_EGAC;
@@ -521,14 +522,14 @@ static const char *vgacon_startup(void)
|| vga_video_type == VIDEO_TYPE_VGAC
|| vga_video_type == VIDEO_TYPE_EGAM) {
vga_hardscroll_enabled = vga_hardscroll_user_enable;
- vga_default_font_height = ORIG_VIDEO_POINTS;
- vga_video_font_height = ORIG_VIDEO_POINTS;
+ vga_default_font_height = screen_info.orig_video_points;
+ vga_video_font_height = screen_info.orig_video_points;
/* This may be suboptimal but is a safe bet - go with it */
vga_scan_lines =
vga_video_font_height * vga_video_num_lines;
}
- vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH;
+ vgacon_xres = screen_info.orig_video_cols * VGA_FONTWIDTH;
vgacon_yres = vga_scan_lines;
if (!vga_init_done) {
@@ -798,7 +799,7 @@ static int vgacon_switch(struct vc_data *c)
{
int x = c->vc_cols * VGA_FONTWIDTH;
int y = c->vc_rows * c->vc_font.height;
- int rows = ORIG_VIDEO_LINES * vga_default_font_height/
+ int rows = screen_info.orig_video_lines * vga_default_font_height/
c->vc_font.height;
/*
* We need to save screen size here as it's the only way
@@ -818,7 +819,7 @@ static int vgacon_switch(struct vc_data *c)
if ((vgacon_xres != x || vgacon_yres != y) &&
(!(vga_video_num_columns % 2) &&
- vga_video_num_columns <= ORIG_VIDEO_COLS &&
+ vga_video_num_columns <= screen_info.orig_video_cols &&
vga_video_num_lines <= rows))
vgacon_doresize(c, c->vc_cols, c->vc_rows);
}
@@ -1278,13 +1279,14 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font)
#endif
static int vgacon_resize(struct vc_data *c, unsigned int width,
- unsigned int height)
+ unsigned int height, unsigned int user)
{
- if (width % 2 || width > ORIG_VIDEO_COLS ||
- height > (ORIG_VIDEO_LINES * vga_default_font_height)/
+ if (width % 2 || width > screen_info.orig_video_cols ||
+ height > (screen_info.orig_video_lines * vga_default_font_height)/
c->vc_font.height)
- /* let svgatextmode tinker with video timings */
- return 0;
+ /* let svgatextmode tinker with video timings and
+ return success */
+ return (user) ? 0 : -EINVAL;
if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */
vgacon_doresize(c, width, height);
@@ -1312,8 +1314,8 @@ static void vgacon_save_screen(struct vc_data *c)
* console initialization routines.
*/
vga_bootup_console = 1;
- c->vc_x = ORIG_X;
- c->vc_y = ORIG_Y;
+ c->vc_x = screen_info.orig_x;
+ c->vc_y = screen_info.orig_y;
}
/* We can't copy in more then the size of the video buffer,
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index 30ede6e8830..d0e4cb61826 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -50,7 +50,6 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
#ifdef __arm__
#include <asm/mach-types.h>
@@ -63,7 +62,7 @@ struct cfb_info {
struct display_switch *dispsw;
struct display *display;
struct pci_dev *dev;
- unsigned char __iomem *region;
+ unsigned char __iomem *region;
unsigned char __iomem *regs;
u_int id;
int func_use_count;
@@ -98,11 +97,11 @@ MODULE_PARM_DESC(default_font, "Default font name");
/*
* Our access methods.
*/
-#define cyber2000fb_writel(val,reg,cfb) writel(val, (cfb)->regs + (reg))
-#define cyber2000fb_writew(val,reg,cfb) writew(val, (cfb)->regs + (reg))
-#define cyber2000fb_writeb(val,reg,cfb) writeb(val, (cfb)->regs + (reg))
+#define cyber2000fb_writel(val, reg, cfb) writel(val, (cfb)->regs + (reg))
+#define cyber2000fb_writew(val, reg, cfb) writew(val, (cfb)->regs + (reg))
+#define cyber2000fb_writeb(val, reg, cfb) writeb(val, (cfb)->regs + (reg))
-#define cyber2000fb_readb(reg,cfb) readb((cfb)->regs + (reg))
+#define cyber2000fb_readb(reg, cfb) readb((cfb)->regs + (reg))
static inline void
cyber2000_crtcw(unsigned int reg, unsigned int val, struct cfb_info *cfb)
@@ -222,12 +221,8 @@ cyber2000fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
static void
cyber2000fb_imageblit(struct fb_info *info, const struct fb_image *image)
{
-// struct cfb_info *cfb = (struct cfb_info *)info;
-
-// if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
- cfb_imageblit(info, image);
- return;
-// }
+ cfb_imageblit(info, image);
+ return;
}
static int cyber2000fb_sync(struct fb_info *info)
@@ -278,12 +273,12 @@ cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
/*
* Pseudocolour:
- * 8 8
+ * 8 8
* pixel --/--+--/--> red lut --> red dac
- * | 8
- * +--/--> green lut --> green dac
- * | 8
- * +--/--> blue lut --> blue dac
+ * | 8
+ * +--/--> green lut --> green dac
+ * | 8
+ * +--/--> blue lut --> blue dac
*/
case FB_VISUAL_PSEUDOCOLOR:
if (regno >= NR_PALETTE)
@@ -293,9 +288,9 @@ cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
green >>= 8;
blue >>= 8;
- cfb->palette[regno].red = red;
+ cfb->palette[regno].red = red;
cfb->palette[regno].green = green;
- cfb->palette[regno].blue = blue;
+ cfb->palette[regno].blue = blue;
cyber2000fb_writeb(regno, 0x3c8, cfb);
cyber2000fb_writeb(red, 0x3c9, cfb);
@@ -305,12 +300,12 @@ cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
/*
* Direct colour:
- * n rl
- * pixel --/--+--/--> red lut --> red dac
- * | gl
- * +--/--> green lut --> green dac
- * | bl
- * +--/--> blue lut --> blue dac
+ * n rl
+ * pixel --/--+--/--> red lut --> red dac
+ * | gl
+ * +--/--> green lut --> green dac
+ * | bl
+ * +--/--> blue lut --> blue dac
* n = bpp, rl = red length, gl = green length, bl = blue length
*/
case FB_VISUAL_DIRECTCOLOR:
@@ -326,9 +321,11 @@ cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
* to the high 6 bits of the LUT.
*/
cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
- cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb);
+ cyber2000fb_writeb(cfb->palette[regno >> 1].red,
+ 0x3c9, cfb);
cyber2000fb_writeb(green, 0x3c9, cfb);
- cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb);
+ cyber2000fb_writeb(cfb->palette[regno >> 1].blue,
+ 0x3c9, cfb);
green = cfb->palette[regno << 3].green;
@@ -336,9 +333,9 @@ cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
}
if (var->green.length >= 5 && regno < 32) {
- cfb->palette[regno << 3].red = red;
+ cfb->palette[regno << 3].red = red;
cfb->palette[regno << 3].green = green;
- cfb->palette[regno << 3].blue = blue;
+ cfb->palette[regno << 3].blue = blue;
/*
* The 5 bits of each colour component are
@@ -352,9 +349,9 @@ cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
}
if (var->green.length == 4 && regno < 16) {
- cfb->palette[regno << 4].red = red;
+ cfb->palette[regno << 4].red = red;
cfb->palette[regno << 4].green = green;
- cfb->palette[regno << 4].blue = blue;
+ cfb->palette[regno << 4].blue = blue;
/*
* The 5 bits of each colour component are
@@ -378,12 +375,12 @@ cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
/*
* True colour:
- * n rl
- * pixel --/--+--/--> red dac
- * | gl
- * +--/--> green dac
- * | bl
- * +--/--> blue dac
+ * n rl
+ * pixel --/--+--/--> red dac
+ * | gl
+ * +--/--> green dac
+ * | bl
+ * +--/--> blue dac
* n = bpp, rl = red length, gl = green length, bl = blue length
*/
case FB_VISUAL_TRUECOLOR:
@@ -495,9 +492,9 @@ static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
/* PLL registers */
cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb);
- cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb);
+ cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb);
cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb);
- cyber2000_grphw(EXT_MCLK_DIV, cfb->mclk_div, cfb);
+ cyber2000_grphw(EXT_MCLK_DIV, cfb->mclk_div, cfb);
cyber2000_grphw(0x90, 0x01, cfb);
cyber2000_grphw(0xb9, 0x80, cfb);
cyber2000_grphw(0xb9, 0x00, cfb);
@@ -516,8 +513,8 @@ static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
/*
* Set up accelerator registers
*/
- cyber2000fb_writew(hw->width, CO_REG_SRC_WIDTH, cfb);
- cyber2000fb_writew(hw->width, CO_REG_DEST_WIDTH, cfb);
+ cyber2000fb_writew(hw->width, CO_REG_SRC_WIDTH, cfb);
+ cyber2000fb_writew(hw->width, CO_REG_DEST_WIDTH, cfb);
cyber2000fb_writeb(hw->co_pixfmt, CO_REG_PIXFMT, cfb);
}
@@ -550,15 +547,15 @@ cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
{
u_int Htotal, Hblankend, Hsyncend;
u_int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
-#define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
+#define ENCODE_BIT(v, b1, m, b2) ((((v) >> (b1)) & (m)) << (b2))
hw->crtc[13] = hw->pitch;
hw->crtc[17] = 0xe3;
hw->crtc[14] = 0;
hw->crtc[8] = 0;
- Htotal = var->xres + var->right_margin +
- var->hsync_len + var->left_margin;
+ Htotal = var->xres + var->right_margin +
+ var->hsync_len + var->left_margin;
if (Htotal > 2080)
return -EINVAL;
@@ -568,15 +565,15 @@ cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
hw->crtc[2] = var->xres >> 3;
hw->crtc[4] = (var->xres + var->right_margin) >> 3;
- Hblankend = (Htotal - 4*8) >> 3;
+ Hblankend = (Htotal - 4 * 8) >> 3;
- hw->crtc[3] = BIT(Hblankend, 0, 0x1f, 0) |
- BIT(1, 0, 0x01, 7);
+ hw->crtc[3] = ENCODE_BIT(Hblankend, 0, 0x1f, 0) |
+ ENCODE_BIT(1, 0, 0x01, 7);
Hsyncend = (var->xres + var->right_margin + var->hsync_len) >> 3;
- hw->crtc[5] = BIT(Hsyncend, 0, 0x1f, 0) |
- BIT(Hblankend, 5, 0x01, 7);
+ hw->crtc[5] = ENCODE_BIT(Hsyncend, 0, 0x1f, 0) |
+ ENCODE_BIT(Hblankend, 5, 0x01, 7);
Vdispend = var->yres - 1;
Vsyncstart = var->yres + var->lower_margin;
@@ -591,20 +588,20 @@ cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
Vblankend = Vtotal - 10;
hw->crtc[6] = Vtotal;
- hw->crtc[7] = BIT(Vtotal, 8, 0x01, 0) |
- BIT(Vdispend, 8, 0x01, 1) |
- BIT(Vsyncstart, 8, 0x01, 2) |
- BIT(Vblankstart,8, 0x01, 3) |
- BIT(1, 0, 0x01, 4) |
- BIT(Vtotal, 9, 0x01, 5) |
- BIT(Vdispend, 9, 0x01, 6) |
- BIT(Vsyncstart, 9, 0x01, 7);
- hw->crtc[9] = BIT(0, 0, 0x1f, 0) |
- BIT(Vblankstart,9, 0x01, 5) |
- BIT(1, 0, 0x01, 6);
+ hw->crtc[7] = ENCODE_BIT(Vtotal, 8, 0x01, 0) |
+ ENCODE_BIT(Vdispend, 8, 0x01, 1) |
+ ENCODE_BIT(Vsyncstart, 8, 0x01, 2) |
+ ENCODE_BIT(Vblankstart, 8, 0x01, 3) |
+ ENCODE_BIT(1, 0, 0x01, 4) |
+ ENCODE_BIT(Vtotal, 9, 0x01, 5) |
+ ENCODE_BIT(Vdispend, 9, 0x01, 6) |
+ ENCODE_BIT(Vsyncstart, 9, 0x01, 7);
+ hw->crtc[9] = ENCODE_BIT(0, 0, 0x1f, 0) |
+ ENCODE_BIT(Vblankstart, 9, 0x01, 5) |
+ ENCODE_BIT(1, 0, 0x01, 6);
hw->crtc[10] = Vsyncstart;
- hw->crtc[11] = BIT(Vsyncend, 0, 0x0f, 0) |
- BIT(1, 0, 0x01, 7);
+ hw->crtc[11] = ENCODE_BIT(Vsyncend, 0, 0x0f, 0) |
+ ENCODE_BIT(1, 0, 0x01, 7);
hw->crtc[12] = Vdispend;
hw->crtc[15] = Vblankstart;
hw->crtc[16] = Vblankend;
@@ -616,10 +613,10 @@ cyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb,
* 4=LINECOMP:10 5-IVIDEO 6=FIXCNT
*/
hw->crtc_ofl =
- BIT(Vtotal, 10, 0x01, 0) |
- BIT(Vdispend, 10, 0x01, 1) |
- BIT(Vsyncstart, 10, 0x01, 2) |
- BIT(Vblankstart,10, 0x01, 3) |
+ ENCODE_BIT(Vtotal, 10, 0x01, 0) |
+ ENCODE_BIT(Vdispend, 10, 0x01, 1) |
+ ENCODE_BIT(Vsyncstart, 10, 0x01, 2) |
+ ENCODE_BIT(Vblankstart, 10, 0x01, 3) |
EXT_CRT_VRTOFL_LINECOMP10;
/* woody: set the interlaced bit... */
@@ -751,11 +748,11 @@ cyber2000fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
switch (var->bits_per_pixel) {
case 8: /* PSEUDOCOLOUR, 256 */
- var->transp.offset = 0;
- var->transp.length = 0;
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 0;
@@ -767,8 +764,6 @@ cyber2000fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
case 16:/* DIRECTCOLOUR, 64k or 32k */
switch (var->green.length) {
case 6: /* RGB565, 64k */
- var->transp.offset = 0;
- var->transp.length = 0;
var->red.offset = 11;
var->red.length = 5;
var->green.offset = 5;
@@ -779,8 +774,6 @@ cyber2000fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
default:
case 5: /* RGB555, 32k */
- var->transp.offset = 0;
- var->transp.length = 0;
var->red.offset = 10;
var->red.length = 5;
var->green.offset = 5;
@@ -803,8 +796,6 @@ cyber2000fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
break;
case 24:/* TRUECOLOUR, 16m */
- var->transp.offset = 0;
- var->transp.length = 0;
var->red.offset = 16;
var->red.length = 8;
var->green.offset = 8;
@@ -831,7 +822,7 @@ cyber2000fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
mem = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8);
if (mem > cfb->fb.fix.smem_len)
var->yres_virtual = cfb->fb.fix.smem_len * 8 /
- (var->bits_per_pixel * var->xres_virtual);
+ (var->bits_per_pixel * var->xres_virtual);
if (var->yres > var->yres_virtual)
var->yres = var->yres_virtual;
@@ -883,6 +874,8 @@ static int cyber2000fb_set_par(struct fb_info *info)
default:
BUG();
}
+ break;
+
case 24:/* TRUECOLOUR, 16m */
hw.co_pixfmt = CO_PIXFMT_24BPP;
hw.width *= 3;
@@ -922,7 +915,7 @@ static int cyber2000fb_set_par(struct fb_info *info)
hw.fetch <<= 1;
hw.fetch += 1;
- cfb->fb.fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+ cfb->fb.fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
/*
* Same here - if the size of the video mode exceeds the
@@ -953,7 +946,6 @@ static int cyber2000fb_set_par(struct fb_info *info)
return 0;
}
-
/*
* Pan or Wrap the Display
*/
@@ -1003,15 +995,15 @@ static int cyber2000fb_blank(int blank, struct fb_info *info)
switch (blank) {
case FB_BLANK_POWERDOWN: /* powerdown - both sync lines down */
sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_0;
- break;
+ break;
case FB_BLANK_HSYNC_SUSPEND: /* hsync off */
sync = EXT_SYNC_CTL_VS_NORMAL | EXT_SYNC_CTL_HS_0;
- break;
+ break;
case FB_BLANK_VSYNC_SUSPEND: /* vsync off */
sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_NORMAL;
break;
- case FB_BLANK_NORMAL: /* soft blank */
- default: /* unblank */
+ case FB_BLANK_NORMAL: /* soft blank */
+ default: /* unblank */
break;
}
@@ -1019,7 +1011,8 @@ static int cyber2000fb_blank(int blank, struct fb_info *info)
if (blank <= 1) {
/* turn on ramdacs */
- cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
+ cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS |
+ RAMDAC_RAMPWRDN);
cyber2000fb_write_ramdac_ctrl(cfb);
}
@@ -1044,7 +1037,8 @@ static int cyber2000fb_blank(int blank, struct fb_info *info)
if (blank >= 2) {
/* turn off ramdacs */
- cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN;
+ cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS |
+ RAMDAC_RAMPWRDN;
cyber2000fb_write_ramdac_ctrl(cfb);
}
@@ -1069,7 +1063,7 @@ static struct fb_ops cyber2000fb_ops = {
* of this driver. It is here solely at the moment to support the other
* CyberPro modules external to this driver.
*/
-static struct cfb_info *int_cfb_info;
+static struct cfb_info *int_cfb_info;
/*
* Enable access to the extended registers
@@ -1086,6 +1080,7 @@ void cyber2000fb_enable_extregs(struct cfb_info *cfb)
cyber2000_grphw(EXT_FUNC_CTL, old, cfb);
}
}
+EXPORT_SYMBOL(cyber2000fb_enable_extregs);
/*
* Disable access to the extended registers
@@ -1105,11 +1100,13 @@ void cyber2000fb_disable_extregs(struct cfb_info *cfb)
else
cfb->func_use_count -= 1;
}
+EXPORT_SYMBOL(cyber2000fb_disable_extregs);
void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var)
{
memcpy(var, &cfb->fb.var, sizeof(struct fb_var_screeninfo));
}
+EXPORT_SYMBOL(cyber2000fb_get_fb_var);
/*
* Attach a capture/tv driver to the core CyberX0X0 driver.
@@ -1123,13 +1120,15 @@ int cyber2000fb_attach(struct cyberpro_info *info, int idx)
info->fb_size = int_cfb_info->fb.fix.smem_len;
info->enable_extregs = cyber2000fb_enable_extregs;
info->disable_extregs = cyber2000fb_disable_extregs;
- info->info = int_cfb_info;
+ info->info = int_cfb_info;
- strlcpy(info->dev_name, int_cfb_info->fb.fix.id, sizeof(info->dev_name));
+ strlcpy(info->dev_name, int_cfb_info->fb.fix.id,
+ sizeof(info->dev_name));
}
return int_cfb_info != NULL;
}
+EXPORT_SYMBOL(cyber2000fb_attach);
/*
* Detach a capture/tv driver from the core CyberX0X0 driver.
@@ -1137,12 +1136,7 @@ int cyber2000fb_attach(struct cyberpro_info *info, int idx)
void cyber2000fb_detach(int idx)
{
}
-
-EXPORT_SYMBOL(cyber2000fb_attach);
EXPORT_SYMBOL(cyber2000fb_detach);
-EXPORT_SYMBOL(cyber2000fb_enable_extregs);
-EXPORT_SYMBOL(cyber2000fb_disable_extregs);
-EXPORT_SYMBOL(cyber2000fb_get_fb_var);
/*
* These parameters give
@@ -1206,7 +1200,7 @@ static void cyberpro_init_hw(struct cfb_info *cfb)
int i;
for (i = 0; i < sizeof(igs_regs); i += 2)
- cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb);
+ cyber2000_grphw(igs_regs[i], igs_regs[i + 1], cfb);
if (cfb->id == ID_CYBERPRO_5000) {
unsigned char val;
@@ -1216,8 +1210,8 @@ static void cyberpro_init_hw(struct cfb_info *cfb)
}
}
-static struct cfb_info * __devinit
-cyberpro_alloc_fb_info(unsigned int id, char *name)
+static struct cfb_info __devinit *cyberpro_alloc_fb_info(unsigned int id,
+ char *name)
{
struct cfb_info *cfb;
@@ -1229,9 +1223,9 @@ cyberpro_alloc_fb_info(unsigned int id, char *name)
cfb->id = id;
if (id == ID_CYBERPRO_5000)
- cfb->ref_ps = 40690; // 24.576 MHz
+ cfb->ref_ps = 40690; /* 24.576 MHz */
else
- cfb->ref_ps = 69842; // 14.31818 MHz (69841?)
+ cfb->ref_ps = 69842; /* 14.31818 MHz (69841?) */
cfb->divisors[0] = 1;
cfb->divisors[1] = 2;
@@ -1283,8 +1277,7 @@ cyberpro_alloc_fb_info(unsigned int id, char *name)
return cfb;
}
-static void
-cyberpro_free_fb_info(struct cfb_info *cfb)
+static void cyberpro_free_fb_info(struct cfb_info *cfb)
{
if (cfb) {
/*
@@ -1301,8 +1294,7 @@ cyberpro_free_fb_info(struct cfb_info *cfb)
* video=cyber2000:font:fontname
*/
#ifndef MODULE
-static int
-cyber2000fb_setup(char *options)
+static int cyber2000fb_setup(char *options)
{
char *opt;
@@ -1316,7 +1308,8 @@ cyber2000fb_setup(char *options)
if (strncmp(opt, "font:", 5) == 0) {
static char default_font_storage[40];
- strlcpy(default_font_storage, opt + 5, sizeof(default_font_storage));
+ strlcpy(default_font_storage, opt + 5,
+ sizeof(default_font_storage));
default_font = default_font_storage;
continue;
}
@@ -1355,10 +1348,18 @@ static int __devinit cyberpro_common_probe(struct cfb_info *cfb)
* Determine the size of the memory.
*/
switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) {
- case MEM_CTL2_SIZE_4MB: smem_size = 0x00400000; break;
- case MEM_CTL2_SIZE_2MB: smem_size = 0x00200000; break;
- case MEM_CTL2_SIZE_1MB: smem_size = 0x00100000; break;
- default: smem_size = 0x00100000; break;
+ case MEM_CTL2_SIZE_4MB:
+ smem_size = 0x00400000;
+ break;
+ case MEM_CTL2_SIZE_2MB:
+ smem_size = 0x00200000;
+ break;
+ case MEM_CTL2_SIZE_1MB:
+ smem_size = 0x00100000;
+ break;
+ default:
+ smem_size = 0x00100000;
+ break;
}
cfb->fb.fix.smem_len = smem_size;
@@ -1367,8 +1368,8 @@ static int __devinit cyberpro_common_probe(struct cfb_info *cfb)
err = -EINVAL;
if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0,
- &cyber2000fb_default_mode, 8)) {
- printk("%s: no valid mode found\n", cfb->fb.fix.id);
+ &cyber2000fb_default_mode, 8)) {
+ printk(KERN_ERR "%s: no valid mode found\n", cfb->fb.fix.id);
goto failed;
}
@@ -1378,7 +1379,7 @@ static int __devinit cyberpro_common_probe(struct cfb_info *cfb)
if (cfb->fb.var.yres_virtual < cfb->fb.var.yres)
cfb->fb.var.yres_virtual = cfb->fb.var.yres;
-// fb_set_var(&cfb->fb.var, -1, &cfb->fb);
+/* fb_set_var(&cfb->fb.var, -1, &cfb->fb); */
/*
* Calculate the hsync and vsync frequencies. Note that
@@ -1426,20 +1427,20 @@ static void cyberpro_common_resume(struct cfb_info *cfb)
#include <asm/arch/hardware.h>
-static int __devinit
-cyberpro_vl_probe(void)
+static int __devinit cyberpro_vl_probe(void)
{
struct cfb_info *cfb;
int err = -ENOMEM;
- if (!request_mem_region(FB_START,FB_SIZE,"CyberPro2010")) return err;
+ if (!request_mem_region(FB_START, FB_SIZE, "CyberPro2010"))
+ return err;
cfb = cyberpro_alloc_fb_info(ID_CYBERPRO_2010, "CyberPro2010");
if (!cfb)
goto failed_release;
cfb->dev = NULL;
- cfb->region = ioremap(FB_START,FB_SIZE);
+ cfb->region = ioremap(FB_START, FB_SIZE);
if (!cfb->region)
goto failed_ioremap;
@@ -1476,7 +1477,7 @@ failed:
failed_ioremap:
cyberpro_free_fb_info(cfb);
failed_release:
- release_mem_region(FB_START,FB_SIZE);
+ release_mem_region(FB_START, FB_SIZE);
return err;
}
@@ -1539,7 +1540,8 @@ static int cyberpro_pci_enable_mmio(struct cfb_info *cfb)
* Allow the CyberPro to accept PCI burst accesses
*/
if (cfb->id == ID_CYBERPRO_2010) {
- printk(KERN_INFO "%s: NOT enabling PCI bursts\n", cfb->fb.fix.id);
+ printk(KERN_INFO "%s: NOT enabling PCI bursts\n",
+ cfb->fb.fix.id);
} else {
val = cyber2000_grphr(EXT_BUS_CTL, cfb);
if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) {
@@ -1689,9 +1691,10 @@ static int cyberpro_pci_resume(struct pci_dev *dev)
}
static struct pci_device_id cyberpro_pci_table[] = {
-// Not yet
-// { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
-// PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 },
+/* Not yet
+ * { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
+ * PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 },
+ */
{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 },
{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
@@ -1701,7 +1704,7 @@ static struct pci_device_id cyberpro_pci_table[] = {
{ 0, }
};
-MODULE_DEVICE_TABLE(pci,cyberpro_pci_table);
+MODULE_DEVICE_TABLE(pci, cyberpro_pci_table);
static struct pci_driver cyberpro_driver = {
.name = "CyberPro",
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
index 33be46ccb54..cc2810ef5de 100644
--- a/drivers/video/epson1355fb.c
+++ b/drivers/video/epson1355fb.c
@@ -57,7 +57,7 @@
#include <asm/types.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <video/epson1355.h>
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index 1a8643f053d..a0c5d9d90d7 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -19,7 +19,6 @@
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/list.h>
-#include <asm/uaccess.h>
/* to support deferred IO */
#include <linux/rmap.h>
diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h
index c5c45203833..cdafbe14ef1 100644
--- a/drivers/video/fb_draw.h
+++ b/drivers/video/fb_draw.h
@@ -2,6 +2,7 @@
#define _FB_DRAW_H
#include <asm/types.h>
+#include <linux/fb.h>
/*
* Compose two values, using a bitmask as decision value
@@ -69,4 +70,97 @@ pixel_to_pat( u32 bpp, u32 pixel)
}
}
#endif
+
+#ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE
+#if BITS_PER_LONG == 64
+#define REV_PIXELS_MASK1 0x5555555555555555ul
+#define REV_PIXELS_MASK2 0x3333333333333333ul
+#define REV_PIXELS_MASK4 0x0f0f0f0f0f0f0f0ful
+#else
+#define REV_PIXELS_MASK1 0x55555555ul
+#define REV_PIXELS_MASK2 0x33333333ul
+#define REV_PIXELS_MASK4 0x0f0f0f0ful
+#endif
+
+static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
+ u32 bswapmask)
+{
+ if (bswapmask & 1)
+ val = comp(val >> 1, val << 1, REV_PIXELS_MASK1);
+ if (bswapmask & 2)
+ val = comp(val >> 2, val << 2, REV_PIXELS_MASK2);
+ if (bswapmask & 3)
+ val = comp(val >> 4, val << 4, REV_PIXELS_MASK4);
+}
+
+static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask)
+{
+ u32 mask;
+
+ if (!bswapmask) {
+ mask = FB_SHIFT_HIGH(~(u32)0, index);
+ } else {
+ mask = 0xff << FB_LEFT_POS(8);
+ mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask;
+ mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask));
+#if defined(__i386__) || defined(__x86_64__)
+ /* Shift argument is limited to 0 - 31 on x86 based CPU's */
+ if(index + bswapmask < 32)
+#endif
+ mask |= FB_SHIFT_HIGH(~(u32)0,
+ (index + bswapmask) & ~(bswapmask));
+ }
+ return mask;
+}
+
+static inline unsigned long fb_shifted_pixels_mask_long(u32 index, u32 bswapmask)
+{
+ unsigned long mask;
+
+ if (!bswapmask) {
+ mask = FB_SHIFT_HIGH(~0UL, index);
+ } else {
+ mask = 0xff << FB_LEFT_POS(8);
+ mask = FB_SHIFT_LOW(mask, index & (bswapmask)) & mask;
+ mask = FB_SHIFT_HIGH(mask, index & ~(bswapmask));
+#if defined(__i386__) || defined(__x86_64__)
+ /* Shift argument is limited to 0 - 31 on x86 based CPU's */
+ if(index + bswapmask < BITS_PER_LONG)
+#endif
+ mask |= FB_SHIFT_HIGH(~0UL,
+ (index + bswapmask) & ~(bswapmask));
+ }
+ return mask;
+}
+
+
+static inline u32 fb_compute_bswapmask(struct fb_info *info)
+{
+ u32 bswapmask = 0;
+ unsigned bpp = info->var.bits_per_pixel;
+
+ if ((bpp < 8) && (info->var.nonstd & FB_NONSTD_REV_PIX_IN_B)) {
+ /*
+ * Reversed order of pixel layout in bytes
+ * works only for 1, 2 and 4 bpp
+ */
+ bswapmask = 7 - bpp + 1;
+ }
+ return bswapmask;
+}
+
+#else /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */
+
+static inline unsigned long fb_rev_pixels_in_long(unsigned long val,
+ u32 bswapmask)
+{
+ return val;
+}
+
+#define fb_shifted_pixels_mask_u32(i, b) FB_SHIFT_HIGH(~(u32)0, (i))
+#define fb_shifted_pixels_mask_long(i, b) FB_SHIFT_HIGH(~0UL, (i))
+#define fb_compute_bswapmask(...) 0
+
+#endif /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */
+
#endif /* FB_DRAW_H */
diff --git a/drivers/video/fb_sys_fops.c b/drivers/video/fb_sys_fops.c
index cf2538d669c..ff275d7f3ea 100644
--- a/drivers/video/fb_sys_fops.c
+++ b/drivers/video/fb_sys_fops.c
@@ -11,7 +11,7 @@
*/
#include <linux/fb.h>
#include <linux/module.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count,
loff_t *ppos)
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
index 148108afdd5..91b78e69150 100644
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -15,8 +15,7 @@
#include <linux/module.h>
#include <linux/fb.h>
#include <linux/slab.h>
-
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
static u16 red2[] __read_mostly = {
0x0000, 0xaaaa
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 07402720470..1194f5e060e 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1567,8 +1567,6 @@ int fb_new_modelist(struct fb_info *info)
static char *video_options[FB_MAX] __read_mostly;
static int ofonly __read_mostly;
-extern const char *global_mode_option;
-
/**
* fb_get_options - get kernel boot parameters
* @name: framebuffer name as it would appear in
@@ -1636,7 +1634,7 @@ static int __init video_setup(char *options)
}
if (!global && !strstr(options, "fb:")) {
- global_mode_option = options;
+ fb_mode_option = options;
global = 1;
}
@@ -1663,7 +1661,6 @@ EXPORT_SYMBOL(register_framebuffer);
EXPORT_SYMBOL(unregister_framebuffer);
EXPORT_SYMBOL(num_registered_fb);
EXPORT_SYMBOL(registered_fb);
-EXPORT_SYMBOL(fb_prepare_logo);
EXPORT_SYMBOL(fb_show_logo);
EXPORT_SYMBOL(fb_set_var);
EXPORT_SYMBOL(fb_blank);
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 438b9411905..4ba9c089441 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -591,7 +591,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
{
struct fb_videomode *mode, *m;
unsigned char *block;
- int num = 0, i;
+ int num = 0, i, first = 1;
mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
if (mode == NULL)
@@ -608,8 +608,6 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
DPRINTK(" Detailed Timings\n");
block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
- int first = 1;
-
if (!(block[0] == 0x00 && block[1] == 0x00)) {
get_detailed_timing(block, &mode[num]);
if (first) {
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 4b520b57391..d7e24889650 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -171,17 +171,17 @@ static struct fb_ops ffb_ops = {
#define FFB_PPC_CS_VAR 0x000002
#define FFB_PPC_CS_CONST 0x000003
-#define FFB_ROP_NEW 0x83
-#define FFB_ROP_OLD 0x85
-#define FFB_ROP_NEW_XOR_OLD 0x86
-
-#define FFB_UCSR_FIFO_MASK 0x00000fff
-#define FFB_UCSR_FB_BUSY 0x01000000
-#define FFB_UCSR_RP_BUSY 0x02000000
-#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
-#define FFB_UCSR_READ_ERR 0x40000000
-#define FFB_UCSR_FIFO_OVFL 0x80000000
-#define FFB_UCSR_ALL_ERRORS (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
+#define FFB_ROP_NEW 0x83
+#define FFB_ROP_OLD 0x85
+#define FFB_ROP_NEW_XOR_OLD 0x86
+
+#define FFB_UCSR_FIFO_MASK 0x00000fff
+#define FFB_UCSR_FB_BUSY 0x01000000
+#define FFB_UCSR_RP_BUSY 0x02000000
+#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
+#define FFB_UCSR_READ_ERR 0x40000000
+#define FFB_UCSR_FIFO_OVFL 0x80000000
+#define FFB_UCSR_ALL_ERRORS (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
struct ffb_fbc {
/* Next vertex registers */
@@ -197,7 +197,7 @@ struct ffb_fbc {
u32 ryf;
u32 rxf;
u32 xxx3[2];
-
+
u32 dmyf;
u32 dmxf;
u32 xxx4[2];
@@ -211,13 +211,13 @@ struct ffb_fbc {
u32 bh;
u32 bw;
u32 xxx6[2];
-
+
u32 xxx7[32];
-
+
/* Setup unit vertex state register */
u32 suvtx;
u32 xxx8[63];
-
+
/* Control registers */
u32 ppc;
u32 wid;
@@ -235,7 +235,7 @@ struct ffb_fbc {
u32 dcsb;
u32 dczf;
u32 dczb;
-
+
u32 xxx9;
u32 blendc;
u32 blendc1;
@@ -252,7 +252,7 @@ struct ffb_fbc {
u32 fbcfg1;
u32 fbcfg2;
u32 fbcfg3;
-
+
u32 ppcfg;
u32 pick;
u32 fillmode;
@@ -269,7 +269,7 @@ struct ffb_fbc {
u32 clip2max;
u32 clip3min;
u32 clip3max;
-
+
/* New 3dRAM III support regs */
u32 rawblend2;
u32 rawpreblend;
@@ -287,7 +287,7 @@ struct ffb_fbc {
u32 rawcmp;
u32 rawwac;
u32 fbramid;
-
+
u32 drawop;
u32 xxx10[2];
u32 fontlpat;
@@ -302,7 +302,7 @@ struct ffb_fbc {
u32 stencil;
u32 stencilctl;
- u32 xxx13[4];
+ u32 xxx13[4];
u32 dcss1;
u32 dcss2;
u32 dcss3;
@@ -315,17 +315,17 @@ struct ffb_fbc {
u32 dcd3;
u32 dcd4;
u32 xxx15;
-
+
u32 pattern[32];
-
+
u32 xxx16[256];
-
+
u32 devid;
u32 xxx17[63];
-
+
u32 ucsr;
u32 xxx18[31];
-
+
u32 mer;
};
@@ -336,20 +336,20 @@ struct ffb_dac {
u32 value2;
};
-#define FFB_DAC_UCTRL 0x1001 /* User Control */
-#define FFB_DAC_UCTRL_MANREV 0x00000f00 /* 4-bit Manufacturing Revision */
-#define FFB_DAC_UCTRL_MANREV_SHIFT 8
-#define FFB_DAC_TGEN 0x6000 /* Timing Generator */
-#define FFB_DAC_TGEN_VIDE 0x00000001 /* Video Enable */
-#define FFB_DAC_DID 0x8000 /* Device Identification */
-#define FFB_DAC_DID_PNUM 0x0ffff000 /* Device Part Number */
-#define FFB_DAC_DID_PNUM_SHIFT 12
-#define FFB_DAC_DID_REV 0xf0000000 /* Device Revision */
-#define FFB_DAC_DID_REV_SHIFT 28
+#define FFB_DAC_UCTRL 0x1001 /* User Control */
+#define FFB_DAC_UCTRL_MANREV 0x00000f00 /* 4-bit Manufacturing Revision */
+#define FFB_DAC_UCTRL_MANREV_SHIFT 8
+#define FFB_DAC_TGEN 0x6000 /* Timing Generator */
+#define FFB_DAC_TGEN_VIDE 0x00000001 /* Video Enable */
+#define FFB_DAC_DID 0x8000 /* Device Identification */
+#define FFB_DAC_DID_PNUM 0x0ffff000 /* Device Part Number */
+#define FFB_DAC_DID_PNUM_SHIFT 12
+#define FFB_DAC_DID_REV 0xf0000000 /* Device Revision */
+#define FFB_DAC_DID_REV_SHIFT 28
#define FFB_DAC_CUR_CTRL 0x100
-#define FFB_DAC_CUR_CTRL_P0 0x00000001
-#define FFB_DAC_CUR_CTRL_P1 0x00000002
+#define FFB_DAC_CUR_CTRL_P0 0x00000001
+#define FFB_DAC_CUR_CTRL_P1 0x00000002
struct ffb_par {
spinlock_t lock;
@@ -382,7 +382,9 @@ static void FFBFifo(struct ffb_par *par, int n)
if (cache - n < 0) {
fbc = par->fbc;
- do { cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK) - 8;
+ do {
+ cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK);
+ cache -= 8;
} while (cache - n < 0);
}
par->fifo_cache = cache - n;
@@ -401,12 +403,12 @@ static void FFBWait(struct ffb_par *par)
upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
}
udelay(10);
- } while(--limit > 0);
+ } while (--limit > 0);
}
static int ffb_sync(struct fb_info *p)
{
- struct ffb_par *par = (struct ffb_par *) p->par;
+ struct ffb_par *par = (struct ffb_par *)p->par;
FFBWait(par);
return 0;
@@ -431,8 +433,8 @@ static void ffb_switch_from_graph(struct ffb_par *par)
FFBWait(par);
par->fifo_cache = 0;
FFBFifo(par, 7);
- upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE|
- FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST,
+ upa_writel(FFB_PPC_VCE_DISABLE | FFB_PPC_TBE_OPAQUE |
+ FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST,
&fbc->ppc);
upa_writel(0x2000707f, &fbc->fbc);
upa_writel(par->rop_cache, &fbc->rop);
@@ -455,7 +457,7 @@ static void ffb_switch_from_graph(struct ffb_par *par)
static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{
- struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_par *par = (struct ffb_par *)info->par;
/* We just use this to catch switches out of
* graphics mode.
@@ -468,16 +470,14 @@ static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
}
/**
- * ffb_fillrect - REQUIRED function. Can use generic routines if
- * non acclerated hardware and packed pixel based.
- * Draws a rectangle on the screen.
+ * ffb_fillrect - Draws a rectangle on the screen.
*
- * @info: frame buffer structure that represents a single frame buffer
- * @rect: structure defining the rectagle and operation.
+ * @info: frame buffer structure that represents a single frame buffer
+ * @rect: structure defining the rectagle and operation.
*/
static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
- struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_par *par = (struct ffb_par *)info->par;
struct ffb_fbc __iomem *fbc = par->fbc;
unsigned long flags;
u32 fg;
@@ -494,9 +494,9 @@ static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
par->fg_cache = fg;
}
- ffb_rop(par, (rect->rop == ROP_COPY ?
- FFB_ROP_NEW :
- FFB_ROP_NEW_XOR_OLD));
+ ffb_rop(par, rect->rop == ROP_COPY ?
+ FFB_ROP_NEW :
+ FFB_ROP_NEW_XOR_OLD);
FFBFifo(par, 5);
upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);
@@ -509,18 +509,15 @@ static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
}
/**
- * ffb_copyarea - REQUIRED function. Can use generic routines if
- * non acclerated hardware and packed pixel based.
- * Copies on area of the screen to another area.
+ * ffb_copyarea - Copies on area of the screen to another area.
*
- * @info: frame buffer structure that represents a single frame buffer
- * @area: structure defining the source and destination.
+ * @info: frame buffer structure that represents a single frame buffer
+ * @area: structure defining the source and destination.
*/
-static void
-ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+static void ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
- struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_par *par = (struct ffb_par *)info->par;
struct ffb_fbc __iomem *fbc = par->fbc;
unsigned long flags;
@@ -547,16 +544,14 @@ ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
}
/**
- * ffb_imageblit - REQUIRED function. Can use generic routines if
- * non acclerated hardware and packed pixel based.
- * Copies a image from system memory to the screen.
+ * ffb_imageblit - Copies a image from system memory to the screen.
*
- * @info: frame buffer structure that represents a single frame buffer
- * @image: structure defining the image.
+ * @info: frame buffer structure that represents a single frame buffer
+ * @image: structure defining the image.
*/
static void ffb_imageblit(struct fb_info *info, const struct fb_image *image)
{
- struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_par *par = (struct ffb_par *)info->par;
struct ffb_fbc __iomem *fbc = par->fbc;
const u8 *data = image->data;
unsigned long flags;
@@ -644,13 +639,14 @@ static void ffb_fixup_var_rgb(struct fb_var_screeninfo *var)
}
/**
- * ffb_setcolreg - Optional function. Sets a color register.
- * @regno: boolean, 0 copy local, 1 get_user() function
- * @red: frame buffer colormap structure
- * @green: The green value which can be up to 16 bits wide
- * @blue: The blue value which can be up to 16 bits wide.
- * @transp: If supported the alpha value which can be up to 16 bits wide.
- * @info: frame buffer info structure
+ * ffb_setcolreg - Sets a color register.
+ *
+ * @regno: boolean, 0 copy local, 1 get_user() function
+ * @red: frame buffer colormap structure
+ * @green: The green value which can be up to 16 bits wide
+ * @blue: The blue value which can be up to 16 bits wide.
+ * @transp: If supported the alpha value which can be up to 16 bits wide.
+ * @info: frame buffer info structure
*/
static int ffb_setcolreg(unsigned regno,
unsigned red, unsigned green, unsigned blue,
@@ -672,14 +668,13 @@ static int ffb_setcolreg(unsigned regno,
}
/**
- * ffb_blank - Optional function. Blanks the display.
- * @blank_mode: the blank mode we want.
- * @info: frame buffer structure that represents a single frame buffer
+ * ffb_blank - Optional function. Blanks the display.
+ * @blank_mode: the blank mode we want.
+ * @info: frame buffer structure that represents a single frame buffer
*/
-static int
-ffb_blank(int blank, struct fb_info *info)
+static int ffb_blank(int blank, struct fb_info *info)
{
- struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_par *par = (struct ffb_par *)info->par;
struct ffb_dac __iomem *dac = par->dac;
unsigned long flags;
u32 val;
@@ -867,7 +862,7 @@ static int ffb_mmap(struct fb_info *info, struct vm_area_struct *vma)
static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
{
- struct ffb_par *par = (struct ffb_par *) info->par;
+ struct ffb_par *par = (struct ffb_par *)info->par;
return sbusfb_ioctl_helper(cmd, arg, info,
FBTYPE_CREATOR, 24, par->fbsize);
@@ -877,8 +872,7 @@ static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
* Initialisation
*/
-static void
-ffb_init_fix(struct fb_info *info)
+static void ffb_init_fix(struct fb_info *info)
{
struct ffb_par *par = (struct ffb_par *)info->par;
const char *ffb_type_name;
@@ -902,7 +896,8 @@ ffb_init_fix(struct fb_info *info)
info->fix.accel = FB_ACCEL_SUN_CREATOR;
}
-static int __devinit ffb_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit ffb_probe(struct of_device *op,
+ const struct of_device_id *match)
{
struct device_node *dp = op->node;
struct ffb_fbc __iomem *fbc;
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index b9b572b293d..2e552d5bbb5 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -183,8 +183,8 @@ static struct fb_videomode default_mode_LCD __initdata = {
.vmode = FB_VMODE_NONINTERLACED,
};
-struct fb_videomode *default_mode = &default_mode_CRT;
-struct fb_var_screeninfo *default_var = &default_var_CRT;
+struct fb_videomode *default_mode __initdata = &default_mode_CRT;
+struct fb_var_screeninfo *default_var __initdata = &default_var_CRT;
static int flat_panel_enabled = 0;
diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h
index 6c227f9592a..ca13c48d19b 100644
--- a/drivers/video/geode/lxfb.h
+++ b/drivers/video/geode/lxfb.h
@@ -33,7 +33,7 @@ void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int,
#define MSR_LX_GLD_CONFIG 0x48002001
#define MSR_LX_GLCP_DOTPLL 0x4c000015
-#define MSR_LX_DF_PADSEL 0x48000011
+#define MSR_LX_DF_PADSEL 0x48002011
#define MSR_LX_DC_SPARE 0x80000011
#define MSR_LX_DF_GLCONFIG 0x48002001
diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c
index 5e30b40c8c0..583185fd7c9 100644
--- a/drivers/video/geode/lxfb_core.c
+++ b/drivers/video/geode/lxfb_core.c
@@ -566,12 +566,7 @@ static int __init lxfb_setup(char *options)
if (!options || !*options)
return 0;
- while (1) {
- char *opt = strsep(&options, ",");
-
- if (opt == NULL)
- break;
-
+ while ((opt = strsep(&options, ",")) != NULL) {
if (!*opt)
continue;
diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c
index 7f3f18d0671..febf09c6349 100644
--- a/drivers/video/geode/video_gx.c
+++ b/drivers/video/geode/video_gx.c
@@ -127,7 +127,7 @@ static void gx_set_dclk_frequency(struct fb_info *info)
int timeout = 1000;
/* Rev. 1 Geode GXs use a 14 MHz reference clock instead of 48 MHz. */
- if (cpu_data->x86_mask == 1) {
+ if (cpu_data(0).x86_mask == 1) {
pll_table = gx_pll_table_14MHz;
pll_table_len = ARRAY_SIZE(gx_pll_table_14MHz);
} else {
diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c
index 23a6bcc3e3c..e92337bef50 100644
--- a/drivers/video/gxt4500.c
+++ b/drivers/video/gxt4500.c
@@ -636,7 +636,7 @@ static int __devinit gxt4500_probe(struct pci_dev *pdev,
info = framebuffer_alloc(sizeof(struct gxt4500_par), &pdev->dev);
if (!info) {
- dev_err(&pdev->dev, "gxt4500: cannot alloc FB info record");
+ dev_err(&pdev->dev, "gxt4500: cannot alloc FB info record\n");
goto err_free_fb;
}
par = info->par;
diff --git a/drivers/video/hecubafb.c b/drivers/video/hecubafb.c
index abfcb50364c..94e0df8a6f6 100644
--- a/drivers/video/hecubafb.c
+++ b/drivers/video/hecubafb.c
@@ -45,7 +45,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/list.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
/* Apollo controller specific defines */
#define APOLLO_START_NEW_IMG 0xA0
diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c
index 18ea4a54910..6455fd2a39f 100644
--- a/drivers/video/imacfb.c
+++ b/drivers/video/imacfb.c
@@ -58,7 +58,7 @@ static int model = M_UNKNOWN;
static int manual_height;
static int manual_width;
-static int set_system(struct dmi_system_id *id)
+static int set_system(const struct dmi_system_id *id)
{
printk(KERN_INFO "imacfb: %s detected - set system to %ld\n",
id->ident, (long)id->driver_data);
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
index 94f4511023d..3ab91bf2157 100644
--- a/drivers/video/imsttfb.c
+++ b/drivers/video/imsttfb.c
@@ -29,7 +29,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#if defined(CONFIG_PPC)
#include <linux/nvram.h>
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index a1258989859..11609552a38 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -34,7 +34,6 @@
#include <asm/hardware.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
#include <asm/arch/imxfb.h>
/*
@@ -467,7 +466,7 @@ static int __init imxfb_init_fbinfo(struct device *dev)
info->var.vmode = FB_VMODE_NONINTERLACED;
info->fbops = &imxfb_ops;
- info->flags = FBINFO_FLAG_DEFAULT;
+ info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST;
fbi->rgb[RGB_16] = &def_rgb_16;
fbi->rgb[RGB_8] = &def_rgb_8;
@@ -480,6 +479,7 @@ static int __init imxfb_init_fbinfo(struct device *dev)
info->var.yres_virtual = inf->yres;
fbi->max_bpp = inf->bpp;
info->var.bits_per_pixel = inf->bpp;
+ info->var.nonstd = inf->nonstd;
info->var.pixclock = inf->pixclock;
info->var.hsync_len = inf->hsync_len;
info->var.left_margin = inf->left_margin;
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index 6148300fadd..2fe3f7def53 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -231,8 +231,8 @@ struct intelfb_hwstate {
struct intelfb_heap_data {
u32 physical;
u8 __iomem *virtual;
- u32 offset; // in GATT pages
- u32 size; // in bytes
+ u32 offset; /* in GATT pages */
+ u32 size; /* in bytes */
};
#ifdef CONFIG_FB_INTEL_I2C
@@ -270,9 +270,9 @@ struct intelfb_info {
struct intelfb_hwstate save_state;
/* agpgart structs */
- struct agp_memory *gtt_fb_mem; // use all stolen memory or vram
- struct agp_memory *gtt_ring_mem; // ring buffer
- struct agp_memory *gtt_cursor_mem; // hw cursor
+ struct agp_memory *gtt_fb_mem; /* use all stolen memory or vram */
+ struct agp_memory *gtt_ring_mem; /* ring buffer */
+ struct agp_memory *gtt_cursor_mem; /* hw cursor */
/* use a gart reserved fb mem */
u8 fbmem_gart;
@@ -346,7 +346,7 @@ struct intelfb_info {
/* driver registered */
int registered;
-
+
/* index into plls */
int pll_index;
@@ -355,7 +355,10 @@ struct intelfb_info {
struct intelfb_output_rec output[MAX_OUTPUTS];
};
-#define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM))
+#define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G) || \
+ ((dinfo)->chipset == INTEL_915GM) || \
+ ((dinfo)->chipset == INTEL_945G) || \
+ ((dinfo)->chipset==INTEL_945GM))
#ifndef FBIO_WAITFORVSYNC
#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c
index 61e4c8759b2..94c08bb5acf 100644
--- a/drivers/video/intelfb/intelfb_i2c.c
+++ b/drivers/video/intelfb/intelfb_i2c.c
@@ -58,7 +58,8 @@ static void intelfb_gpio_setscl(void *data, int state)
struct intelfb_info *dinfo = chan->dinfo;
u32 val;
- OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK);
+ OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) |
+ SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK);
val = INREG(chan->reg);
}
@@ -68,7 +69,8 @@ static void intelfb_gpio_setsda(void *data, int state)
struct intelfb_info *dinfo = chan->dinfo;
u32 val;
- OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK);
+ OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) |
+ SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK);
val = INREG(chan->reg);
}
@@ -97,26 +99,26 @@ static int intelfb_gpio_getsda(void *data)
}
static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo,
- struct intelfb_i2c_chan *chan,
- const u32 reg, const char *name)
+ struct intelfb_i2c_chan *chan,
+ const u32 reg, const char *name)
{
int rc;
- chan->dinfo = dinfo;
- chan->reg = reg;
+ chan->dinfo = dinfo;
+ chan->reg = reg;
snprintf(chan->adapter.name, sizeof(chan->adapter.name),
"intelfb %s", name);
- chan->adapter.owner = THIS_MODULE;
- chan->adapter.id = I2C_HW_B_INTELFB;
+ chan->adapter.owner = THIS_MODULE;
+ chan->adapter.id = I2C_HW_B_INTELFB;
chan->adapter.algo_data = &chan->algo;
chan->adapter.dev.parent = &chan->dinfo->pdev->dev;
- chan->algo.setsda = intelfb_gpio_setsda;
- chan->algo.setscl = intelfb_gpio_setscl;
- chan->algo.getsda = intelfb_gpio_getsda;
- chan->algo.getscl = intelfb_gpio_getscl;
- chan->algo.udelay = 40;
- chan->algo.timeout = 20;
- chan->algo.data = chan;
+ chan->algo.setsda = intelfb_gpio_setsda;
+ chan->algo.setscl = intelfb_gpio_setscl;
+ chan->algo.getsda = intelfb_gpio_getsda;
+ chan->algo.getscl = intelfb_gpio_getscl;
+ chan->algo.udelay = 40;
+ chan->algo.timeout = 20;
+ chan->algo.data = chan;
i2c_set_adapdata(&chan->adapter, chan);
@@ -142,40 +144,44 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo)
dinfo->output[i].type = INTELFB_OUTPUT_ANALOG;
/* setup the DDC bus for analog output */
- intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA, "CRTDDC_A");
+ intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA,
+ "CRTDDC_A");
i++;
- /* need to add the output busses for each device
- - this function is very incomplete
- - i915GM has LVDS and TVOUT for example
- */
- switch(dinfo->chipset) {
+ /* need to add the output busses for each device
+ - this function is very incomplete
+ - i915GM has LVDS and TVOUT for example
+ */
+ switch(dinfo->chipset) {
case INTEL_830M:
case INTEL_845G:
case INTEL_855GM:
case INTEL_865G:
dinfo->output[i].type = INTELFB_OUTPUT_DVO;
- intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOD, "DVODDC_D");
- intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "DVOI2C_E");
+ intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus,
+ GPIOD, "DVODDC_D");
+ intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus,
+ GPIOE, "DVOI2C_E");
i++;
break;
case INTEL_915G:
case INTEL_915GM:
- /* has some LVDS + tv-out */
+ /* has some LVDS + tv-out */
case INTEL_945G:
case INTEL_945GM:
/* SDVO ports have a single control bus - 2 devices */
dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
- intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "SDVOCTRL_E");
+ intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus,
+ GPIOE, "SDVOCTRL_E");
/* TODO: initialize the SDVO */
-// I830SDVOInit(pScrn, i, DVOB);
+ /* I830SDVOInit(pScrn, i, DVOB); */
i++;
/* set up SDVOC */
dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
dinfo->output[i].i2c_bus = dinfo->output[i - 1].i2c_bus;
/* TODO: initialize the SDVO */
-// I830SDVOInit(pScrn, i, DVOC);
+ /* I830SDVOInit(pScrn, i, DVOC); */
i++;
break;
}
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index b75eda84858..481d58f7535 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -4,7 +4,7 @@
* Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/
* 945G/945GM integrated graphics chips.
*
- * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
+ * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
* 2004 Sylvain Meyer
* 2006 David Airlie
*
@@ -99,13 +99,6 @@
* Add vram option to reserve more memory than stolen by BIOS
* Fix intelfbhw_pan_display typo
* Add __initdata annotations
- *
- * TODO:
- *
- *
- * Wish List:
- *
- *
*/
#include <linux/module.h>
@@ -222,8 +215,8 @@ static struct pci_driver intelfb_driver = {
/* Module description/parameters */
MODULE_AUTHOR("David Dawes <dawes@tungstengraphics.com>, "
"Sylvain Meyer <sylvain.meyer@worldonline.fr>");
-MODULE_DESCRIPTION(
- "Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS " chipsets");
+MODULE_DESCRIPTION("Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS
+ " chipsets");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DEVICE_TABLE(pci, intelfb_pci_table);
@@ -271,8 +264,7 @@ MODULE_PARM_DESC(mode,
#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name) + 1, NULL, 0)
#define OPT_STRVAL(opt, name) (opt + strlen(name))
-static __inline__ char *
-get_opt_string(const char *this_opt, const char *name)
+static __inline__ char * get_opt_string(const char *this_opt, const char *name)
{
const char *p;
int i;
@@ -290,8 +282,8 @@ get_opt_string(const char *this_opt, const char *name)
return ret;
}
-static __inline__ int
-get_opt_int(const char *this_opt, const char *name, int *ret)
+static __inline__ int get_opt_int(const char *this_opt, const char *name,
+ int *ret)
{
if (!ret)
return 0;
@@ -303,8 +295,8 @@ get_opt_int(const char *this_opt, const char *name, int *ret)
return 1;
}
-static __inline__ int
-get_opt_bool(const char *this_opt, const char *name, int *ret)
+static __inline__ int get_opt_bool(const char *this_opt, const char *name,
+ int *ret)
{
if (!ret)
return 0;
@@ -324,8 +316,7 @@ get_opt_bool(const char *this_opt, const char *name, int *ret)
return 1;
}
-static int __init
-intelfb_setup(char *options)
+static int __init intelfb_setup(char *options)
{
char *this_opt;
@@ -355,7 +346,7 @@ intelfb_setup(char *options)
continue;
if (get_opt_bool(this_opt, "accel", &accel))
;
- else if (get_opt_int(this_opt, "vram", &vram))
+ else if (get_opt_int(this_opt, "vram", &vram))
;
else if (get_opt_bool(this_opt, "hwcursor", &hwcursor))
;
@@ -376,8 +367,7 @@ intelfb_setup(char *options)
#endif
-static int __init
-intelfb_init(void)
+static int __init intelfb_init(void)
{
#ifndef MODULE
char *option = NULL;
@@ -401,8 +391,7 @@ intelfb_init(void)
return pci_register_driver(&intelfb_driver);
}
-static void __exit
-intelfb_exit(void)
+static void __exit intelfb_exit(void)
{
DBG_MSG("intelfb_exit\n");
pci_unregister_driver(&intelfb_driver);
@@ -428,8 +417,8 @@ static inline void __devinit set_mtrr(struct intelfb_info *dinfo)
}
static inline void unset_mtrr(struct intelfb_info *dinfo)
{
- if (dinfo->has_mtrr)
- mtrr_del(dinfo->mtrr_reg, dinfo->aperture.physical,
+ if (dinfo->has_mtrr)
+ mtrr_del(dinfo->mtrr_reg, dinfo->aperture.physical,
dinfo->aperture.size);
}
#else
@@ -442,8 +431,7 @@ static inline void unset_mtrr(struct intelfb_info *dinfo)
* driver init / cleanup *
***************************************************************/
-static void
-cleanup(struct intelfb_info *dinfo)
+static void cleanup(struct intelfb_info *dinfo)
{
DBG_MSG("cleanup\n");
@@ -499,8 +487,8 @@ cleanup(struct intelfb_info *dinfo)
} while (0)
-static int __devinit
-intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit intelfb_pci_register(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct fb_info *info;
struct intelfb_info *dinfo;
@@ -510,8 +498,8 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
int agp_memtype;
const char *s;
struct agp_bridge_data *bridge;
- int aperture_bar = 0;
- int mmio_bar = 1;
+ int aperture_bar = 0;
+ int mmio_bar = 1;
int offset;
DBG_MSG("intelfb_pci_register\n");
@@ -637,9 +625,8 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
dinfo->ring.size = RINGBUFFER_SIZE;
dinfo->ring_tail_mask = dinfo->ring.size - 1;
}
- if (dinfo->hwcursor) {
+ if (dinfo->hwcursor)
dinfo->cursor.size = HW_CURSOR_SIZE;
- }
/* Use agpgart to manage the GATT */
if (!(bridge = agp_backend_acquire(pdev))) {
@@ -662,18 +649,15 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
offset = ROUND_UP_TO_PAGE(MB(voffset))/GTT_PAGE_SIZE;
/* set the mem offsets - set them after the already used pages */
- if (dinfo->accel) {
+ if (dinfo->accel)
dinfo->ring.offset = offset + gtt_info.current_memory;
- }
- if (dinfo->hwcursor) {
+ if (dinfo->hwcursor)
dinfo->cursor.offset = offset +
+ gtt_info.current_memory + (dinfo->ring.size >> 12);
- }
- if (dinfo->fbmem_gart) {
+ if (dinfo->fbmem_gart)
dinfo->fb.offset = offset +
+ gtt_info.current_memory + (dinfo->ring.size >> 12)
+ (dinfo->cursor.size >> 12);
- }
/* Allocate memories (which aren't stolen) */
/* Map the fb and MMIO regions */
@@ -689,7 +673,7 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
dinfo->mmio_base =
(u8 __iomem *)ioremap_nocache(dinfo->mmio_base_phys,
- INTEL_REG_SIZE);
+ INTEL_REG_SIZE);
if (!dinfo->mmio_base) {
ERR_MSG("Cannot remap MMIO region.\n");
cleanup(dinfo);
@@ -820,7 +804,8 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
if (bailearly == 1)
bailout(dinfo);
- if (FIXED_MODE(dinfo) && ORIG_VIDEO_ISVGA != VIDEO_TYPE_VLFB) {
+ if (FIXED_MODE(dinfo) &&
+ screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) {
ERR_MSG("Video mode must be programmed at boot time.\n");
cleanup(dinfo);
return -ENODEV;
@@ -831,16 +816,14 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Initialise dinfo and related data. */
/* If an initial mode was programmed at boot time, get its details. */
- if (ORIG_VIDEO_ISVGA == VIDEO_TYPE_VLFB)
+ if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB)
get_initial_mode(dinfo);
if (bailearly == 3)
bailout(dinfo);
- if (FIXED_MODE(dinfo)) {
- /* remap fb address */
+ if (FIXED_MODE(dinfo)) /* remap fb address */
update_dinfo(dinfo, &dinfo->initial_var);
- }
if (bailearly == 4)
bailout(dinfo);
@@ -939,8 +922,7 @@ intelfb_pci_unregister(struct pci_dev *pdev)
* helper functions *
***************************************************************/
-int __inline__
-intelfb_var_to_depth(const struct fb_var_screeninfo *var)
+int __inline__ intelfb_var_to_depth(const struct fb_var_screeninfo *var)
{
DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n",
var->bits_per_pixel, var->green.length);
@@ -956,8 +938,7 @@ intelfb_var_to_depth(const struct fb_var_screeninfo *var)
}
-static __inline__ int
-var_to_refresh(const struct fb_var_screeninfo *var)
+static __inline__ int var_to_refresh(const struct fb_var_screeninfo *var)
{
int xtot = var->xres + var->left_margin + var->right_margin +
var->hsync_len;
@@ -971,8 +952,7 @@ var_to_refresh(const struct fb_var_screeninfo *var)
* Various intialisation functions *
***************************************************************/
-static void __devinit
-get_initial_mode(struct intelfb_info *dinfo)
+static void __devinit get_initial_mode(struct intelfb_info *dinfo)
{
struct fb_var_screeninfo *var;
int xtot, ytot;
@@ -1039,8 +1019,7 @@ get_initial_mode(struct intelfb_info *dinfo)
}
}
-static int __devinit
-intelfb_init_var(struct intelfb_info *dinfo)
+static int __devinit intelfb_init_var(struct intelfb_info *dinfo)
{
struct fb_var_screeninfo *var;
int msrc = 0;
@@ -1087,10 +1066,9 @@ intelfb_init_var(struct intelfb_info *dinfo)
}
- if (!msrc) {
+ if (!msrc)
msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE,
NULL, 0, NULL, 0);
- }
}
if (!msrc) {
@@ -1122,8 +1100,7 @@ intelfb_init_var(struct intelfb_info *dinfo)
return 0;
}
-static int __devinit
-intelfb_set_fbinfo(struct intelfb_info *dinfo)
+static int __devinit intelfb_set_fbinfo(struct intelfb_info *dinfo)
{
struct fb_info *info = dinfo->info;
@@ -1159,8 +1136,8 @@ intelfb_set_fbinfo(struct intelfb_info *dinfo)
}
/* Update dinfo to match the active video mode. */
-static void
-update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var)
+static void update_dinfo(struct intelfb_info *dinfo,
+ struct fb_var_screeninfo *var)
{
DBG_MSG("update_dinfo\n");
@@ -1208,36 +1185,32 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var)
* fbdev interface *
***************************************************************/
-static int
-intelfb_open(struct fb_info *info, int user)
+static int intelfb_open(struct fb_info *info, int user)
{
struct intelfb_info *dinfo = GET_DINFO(info);
- if (user) {
+ if (user)
dinfo->open++;
- }
return 0;
}
-static int
-intelfb_release(struct fb_info *info, int user)
+static int intelfb_release(struct fb_info *info, int user)
{
struct intelfb_info *dinfo = GET_DINFO(info);
if (user) {
dinfo->open--;
msleep(1);
- if (!dinfo->open) {
+ if (!dinfo->open)
intelfbhw_disable_irq(dinfo);
- }
}
return 0;
}
-static int
-intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+static int intelfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
int change_var = 0;
struct fb_var_screeninfo v;
@@ -1271,15 +1244,15 @@ intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
}
/* Check for a supported bpp. */
- if (v.bits_per_pixel <= 8) {
+ if (v.bits_per_pixel <= 8)
v.bits_per_pixel = 8;
- } else if (v.bits_per_pixel <= 16) {
+ else if (v.bits_per_pixel <= 16) {
if (v.bits_per_pixel == 16)
v.green.length = 6;
v.bits_per_pixel = 16;
- } else if (v.bits_per_pixel <= 32) {
+ } else if (v.bits_per_pixel <= 32)
v.bits_per_pixel = 32;
- } else
+ else
return -EINVAL;
change_var = ((info->var.xres != var->xres) ||
@@ -1361,10 +1334,9 @@ intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
return 0;
}
-static int
-intelfb_set_par(struct fb_info *info)
+static int intelfb_set_par(struct fb_info *info)
{
- struct intelfb_hwstate *hw;
+ struct intelfb_hwstate *hw;
struct intelfb_info *dinfo = GET_DINFO(info);
if (FIXED_MODE(dinfo)) {
@@ -1372,9 +1344,9 @@ intelfb_set_par(struct fb_info *info)
return -EINVAL;
}
- hw = kmalloc(sizeof(*hw), GFP_ATOMIC);
- if (!hw)
- return -ENOMEM;
+ hw = kmalloc(sizeof(*hw), GFP_ATOMIC);
+ if (!hw)
+ return -ENOMEM;
DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres,
info->var.yres, info->var.bits_per_pixel);
@@ -1384,15 +1356,15 @@ intelfb_set_par(struct fb_info *info)
if (ACCEL(dinfo, info))
intelfbhw_2d_stop(dinfo);
- memcpy(hw, &dinfo->save_state, sizeof(*hw));
- if (intelfbhw_mode_to_hw(dinfo, hw, &info->var))
- goto invalid_mode;
- if (intelfbhw_program_mode(dinfo, hw, 0))
- goto invalid_mode;
+ memcpy(hw, &dinfo->save_state, sizeof(*hw));
+ if (intelfbhw_mode_to_hw(dinfo, hw, &info->var))
+ goto invalid_mode;
+ if (intelfbhw_program_mode(dinfo, hw, 0))
+ goto invalid_mode;
#if REGDUMP > 0
- intelfbhw_read_hw_state(dinfo, hw, 0);
- intelfbhw_print_hw_state(dinfo, hw);
+ intelfbhw_read_hw_state(dinfo, hw, 0);
+ intelfbhw_print_hw_state(dinfo, hw);
#endif
update_dinfo(dinfo, &info->var);
@@ -1408,9 +1380,9 @@ intelfb_set_par(struct fb_info *info)
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
FBINFO_HWACCEL_IMAGEBLIT;
- } else {
+ } else
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
- }
+
kfree(hw);
return 0;
invalid_mode:
@@ -1418,9 +1390,9 @@ invalid_mode:
return -EINVAL;
}
-static int
-intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp, struct fb_info *info)
+static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
{
struct intelfb_info *dinfo = GET_DINFO(info);
@@ -1463,23 +1435,22 @@ intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
return 0;
}
-static int
-intelfb_blank(int blank, struct fb_info *info)
+static int intelfb_blank(int blank, struct fb_info *info)
{
intelfbhw_do_blank(blank, info);
return 0;
}
-static int
-intelfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+static int intelfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
intelfbhw_pan_display(var, info);
return 0;
}
/* When/if we have our own ioctls. */
-static int
-intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+static int intelfb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
{
int retval = 0;
struct intelfb_info *dinfo = GET_DINFO(info);
@@ -1499,8 +1470,8 @@ intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
return retval;
}
-static void
-intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect)
+static void intelfb_fillrect (struct fb_info *info,
+ const struct fb_fillrect *rect)
{
struct intelfb_info *dinfo = GET_DINFO(info);
u32 rop, color;
@@ -1514,7 +1485,7 @@ intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect)
if (rect->rop == ROP_COPY)
rop = PAT_ROP_GXCOPY;
- else // ROP_XOR
+ else /* ROP_XOR */
rop = PAT_ROP_GXXOR;
if (dinfo->depth != 8)
@@ -1528,8 +1499,8 @@ intelfb_fillrect (struct fb_info *info, const struct fb_fillrect *rect)
rop);
}
-static void
-intelfb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
+static void intelfb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *region)
{
struct intelfb_info *dinfo = GET_DINFO(info);
@@ -1545,8 +1516,8 @@ intelfb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
dinfo->pitch, info->var.bits_per_pixel);
}
-static void
-intelfb_imageblit(struct fb_info *info, const struct fb_image *image)
+static void intelfb_imageblit(struct fb_info *info,
+ const struct fb_image *image)
{
struct intelfb_info *dinfo = GET_DINFO(info);
u32 fgcolor, bgcolor;
@@ -1574,8 +1545,7 @@ intelfb_imageblit(struct fb_info *info, const struct fb_image *image)
return cfb_imageblit(info, image);
}
-static int
-intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+static int intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
struct intelfb_info *dinfo = GET_DINFO(info);
u32 physical;
@@ -1689,8 +1659,7 @@ intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
return 0;
}
-static int
-intelfb_sync(struct fb_info *info)
+static int intelfb_sync(struct fb_info *info)
{
struct intelfb_info *dinfo = GET_DINFO(info);
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 6a47682d861..5f6fb7d2c40 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -3,7 +3,7 @@
*
* Linux framebuffer driver for Intel(R) 865G integrated graphics chips.
*
- * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
+ * Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
* 2004 Sylvain Meyer
*
* This driver consists of two parts. The first part (intelfbdrv.c) provides
@@ -56,17 +56,16 @@ static struct pll_min_max plls[PLLS_MAX] = {
6, 16, 3, 16,
4, 128, 0, 31,
930000, 1400000, 165000, 48000,
- 4, 2 }, //I8xx
+ 4, 2 }, /* I8xx */
{ 75, 120, 10, 20,
5, 9, 4, 7,
5, 80, 1, 8,
1400000, 2800000, 200000, 96000,
- 10, 5 } //I9xx
+ 10, 5 } /* I9xx */
};
-int
-intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
+int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
{
u32 tmp;
if (!pdev || !dinfo)
@@ -149,9 +148,8 @@ intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
}
}
-int
-intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
- int *stolen_size)
+int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
+ int *stolen_size)
{
struct pci_dev *bridge_dev;
u16 tmp;
@@ -254,8 +252,7 @@ intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
}
}
-int
-intelfbhw_check_non_crt(struct intelfb_info *dinfo)
+int intelfbhw_check_non_crt(struct intelfb_info *dinfo)
{
int dvo = 0;
@@ -271,8 +268,7 @@ intelfbhw_check_non_crt(struct intelfb_info *dinfo)
return dvo;
}
-const char *
-intelfbhw_dvo_to_string(int dvo)
+const char * intelfbhw_dvo_to_string(int dvo)
{
if (dvo & DVOA_PORT)
return "DVO port A";
@@ -287,9 +283,8 @@ intelfbhw_dvo_to_string(int dvo)
}
-int
-intelfbhw_validate_mode(struct intelfb_info *dinfo,
- struct fb_var_screeninfo *var)
+int intelfbhw_validate_mode(struct intelfb_info *dinfo,
+ struct fb_var_screeninfo *var)
{
int bytes_per_pixel;
int tmp;
@@ -322,17 +317,26 @@ intelfbhw_validate_mode(struct intelfb_info *dinfo,
var->yres, VACTIVE_MASK + 1);
return 1;
}
-
- /* Check for interlaced/doublescan modes. */
- if (var->vmode & FB_VMODE_INTERLACED) {
- WRN_MSG("Mode is interlaced.\n");
+ if (var->xres < 4) {
+ WRN_MSG("X resolution too small (%d vs 4).\n", var->xres);
+ return 1;
+ }
+ if (var->yres < 4) {
+ WRN_MSG("Y resolution too small (%d vs 4).\n", var->yres);
return 1;
}
+
+ /* Check for doublescan modes. */
if (var->vmode & FB_VMODE_DOUBLE) {
WRN_MSG("Mode is double-scan.\n");
return 1;
}
+ if ((var->vmode & FB_VMODE_INTERLACED) && (var->yres & 1)) {
+ WRN_MSG("Odd number of lines in interlaced mode\n");
+ return 1;
+ }
+
/* Check if clock is OK. */
tmp = 1000000000 / var->pixclock;
if (tmp < MIN_CLOCK) {
@@ -349,8 +353,7 @@ intelfbhw_validate_mode(struct intelfb_info *dinfo,
return 0;
}
-int
-intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+int intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct intelfb_info *dinfo = GET_DINFO(info);
u32 offset, xoffset, yoffset;
@@ -372,9 +375,10 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
offset += dinfo->fb.offset << 12;
dinfo->vsync.pan_offset = offset;
- if ((var->activate & FB_ACTIVATE_VBL) && !intelfbhw_enable_irq(dinfo, 0)) {
+ if ((var->activate & FB_ACTIVATE_VBL) &&
+ !intelfbhw_enable_irq(dinfo))
dinfo->vsync.pan_display = 1;
- } else {
+ else {
dinfo->vsync.pan_display = 0;
OUTREG(DSPABASE, offset);
}
@@ -383,8 +387,7 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
}
/* Blank the screen. */
-void
-intelfbhw_do_blank(int blank, struct fb_info *info)
+void intelfbhw_do_blank(int blank, struct fb_info *info)
{
struct intelfb_info *dinfo = GET_DINFO(info);
u32 tmp;
@@ -409,11 +412,10 @@ intelfbhw_do_blank(int blank, struct fb_info *info)
DBG_MSG("cursor_on is %d\n", dinfo->cursor_on);
#endif
if (dinfo->cursor_on) {
- if (blank) {
+ if (blank)
intelfbhw_cursor_hide(dinfo);
- } else {
+ else
intelfbhw_cursor_show(dinfo);
- }
dinfo->cursor_on = 1;
}
dinfo->cursor_blanked = blank;
@@ -441,19 +443,18 @@ intelfbhw_do_blank(int blank, struct fb_info *info)
}
-void
-intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
- unsigned red, unsigned green, unsigned blue,
- unsigned transp)
+void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
+ unsigned red, unsigned green, unsigned blue,
+ unsigned transp)
{
+ u32 palette_reg = (dinfo->pipe == PIPE_A) ?
+ PALETTE_A : PALETTE_B;
+
#if VERBOSE > 0
DBG_MSG("intelfbhw_setcolreg: %d: (%d, %d, %d)\n",
regno, red, green, blue);
#endif
- u32 palette_reg = (dinfo->pipe == PIPE_A) ?
- PALETTE_A : PALETTE_B;
-
OUTREG(palette_reg + (regno << 2),
(red << PALETTE_8_RED_SHIFT) |
(green << PALETTE_8_GREEN_SHIFT) |
@@ -461,9 +462,8 @@ intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
}
-int
-intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
- int flag)
+int intelfbhw_read_hw_state(struct intelfb_info *dinfo,
+ struct intelfb_hwstate *hw, int flag)
{
int i;
@@ -610,7 +610,8 @@ static int calc_vclock3(int index, int m, int n, int p)
return plls[index].ref_clk * m / n / p;
}
-static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvds)
+static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2,
+ int lvds)
{
struct pll_min_max *pll = &plls[index];
u32 m, vco, p;
@@ -619,17 +620,16 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvd
n += 2;
vco = pll->ref_clk * m / n;
- if (index == PLLS_I8xx) {
+ if (index == PLLS_I8xx)
p = ((p1 + 2) * (1 << (p2 + 1)));
- } else {
+ else
p = ((p1) * (p2 ? 5 : 10));
- }
return vco / p;
}
#if REGDUMP
-static void
-intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
+static void intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll,
+ int *o_p1, int *o_p2)
{
int p1, p2;
@@ -638,7 +638,7 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
p1 = 1;
else
p1 = (dpll >> DPLL_P1_SHIFT) & 0xff;
-
+
p1 = ffs(p1);
p2 = (dpll >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK;
@@ -656,8 +656,8 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
#endif
-void
-intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
+void intelfbhw_print_hw_state(struct intelfb_info *dinfo,
+ struct intelfb_hwstate *hw)
{
#if REGDUMP
int i, m1, m2, n, p1, p2;
@@ -670,7 +670,7 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
printk("hw state dump start\n");
printk(" VGA0_DIVISOR: 0x%08x\n", hw->vga0_divisor);
printk(" VGA1_DIVISOR: 0x%08x\n", hw->vga1_divisor);
- printk(" VGAPD: 0x%08x\n", hw->vga_pd);
+ printk(" VGAPD: 0x%08x\n", hw->vga_pd);
n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
@@ -689,7 +689,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2);
printk(" VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2);
- printk(" VGA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
+ printk(" VGA1: clock is %d\n",
+ calc_vclock(index, m1, m2, n, p1, p2, 0));
printk(" DPLL_A: 0x%08x\n", hw->dpll_a);
printk(" DPLL_B: 0x%08x\n", hw->dpll_b);
@@ -706,7 +707,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
printk(" PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2);
- printk(" PLLA0: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
+ printk(" PLLA0: clock is %d\n",
+ calc_vclock(index, m1, m2, n, p1, p2, 0));
n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
@@ -716,7 +718,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
printk(" PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
m1, m2, n, p1, p2);
- printk(" PLLA1: clock is %d\n", calc_vclock(index, m1, m2, n, p1, p2, 0));
+ printk(" PLLA1: clock is %d\n",
+ calc_vclock(index, m1, m2, n, p1, p2, 0));
#if 0
printk(" PALETTE_A:\n");
@@ -821,8 +824,8 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
/* Split the M parameter into M1 and M2. */
-static int
-splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2)
+static int splitm(int index, unsigned int m, unsigned int *retm1,
+ unsigned int *retm2)
{
int m1, m2;
int testm;
@@ -843,8 +846,8 @@ splitm(int index, unsigned int m, unsigned int *retm1, unsigned int *retm2)
}
/* Split the P parameter into P1 and P2. */
-static int
-splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
+static int splitp(int index, unsigned int p, unsigned int *retp1,
+ unsigned int *retp2)
{
int p1, p2;
struct pll_min_max *pll = &plls[index];
@@ -878,9 +881,8 @@ splitp(int index, unsigned int p, unsigned int *retp1, unsigned int *retp2)
}
}
-static int
-calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1,
- u32 *retp2, u32 *retclock)
+static int calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2,
+ u32 *retn, u32 *retp1, u32 *retp2, u32 *retclock)
{
u32 m1, m2, n, p1, p2, n1, testm;
u32 f_vco, p, p_best = 0, m, f_out = 0;
@@ -975,8 +977,8 @@ calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *re
return 0;
}
-static __inline__ int
-check_overflow(u32 value, u32 limit, const char *description)
+static __inline__ int check_overflow(u32 value, u32 limit,
+ const char *description)
{
if (value > limit) {
WRN_MSG("%s value %d exceeds limit %d\n",
@@ -987,9 +989,9 @@ check_overflow(u32 value, u32 limit, const char *description)
}
/* It is assumed that hw is filled in with the initial state information. */
-int
-intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
- struct fb_var_screeninfo *var)
+int intelfbhw_mode_to_hw(struct intelfb_info *dinfo,
+ struct intelfb_hwstate *hw,
+ struct fb_var_screeninfo *var)
{
int pipe = PIPE_A;
u32 *dpll, *fp0, *fp1;
@@ -1093,9 +1095,8 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
if (IS_I9XX(dinfo)) {
*dpll |= (p2 << DPLL_I9XX_P2_SHIFT);
*dpll |= (1 << (p1 - 1)) << DPLL_P1_SHIFT;
- } else {
+ } else
*dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
- }
*fp0 = (n << FP_N_DIVISOR_SHIFT) |
(m1 << FP_M1_DIVISOR_SHIFT) |
@@ -1139,6 +1140,8 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
hblank_end);
vactive = var->yres;
+ if (var->vmode & FB_VMODE_INTERLACED)
+ vactive--; /* the chip adds 2 halflines automatically */
vsync_start = vactive + var->lower_margin;
vsync_end = vsync_start + var->vsync_len;
vtotal = vsync_end + var->upper_margin;
@@ -1220,19 +1223,24 @@ intelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
/* Set the palette to 8-bit mode. */
*pipe_conf &= ~PIPECONF_GAMMA;
+
+ if (var->vmode & FB_VMODE_INTERLACED)
+ *pipe_conf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+ else
+ *pipe_conf &= ~PIPECONF_INTERLACE_MASK;
+
return 0;
}
/* Program a (non-VGA) video mode. */
-int
-intelfbhw_program_mode(struct intelfb_info *dinfo,
- const struct intelfb_hwstate *hw, int blank)
+int intelfbhw_program_mode(struct intelfb_info *dinfo,
+ const struct intelfb_hwstate *hw, int blank)
{
int pipe = PIPE_A;
u32 tmp;
const u32 *dpll, *fp0, *fp1, *pipe_conf;
const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss;
- u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg;
+ u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg, pipe_stat_reg;
u32 hsync_reg, htotal_reg, hblank_reg;
u32 vsync_reg, vtotal_reg, vblank_reg;
u32 src_size_reg;
@@ -1273,6 +1281,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
fp0_reg = FPB0;
fp1_reg = FPB1;
pipe_conf_reg = PIPEBCONF;
+ pipe_stat_reg = PIPEBSTAT;
hsync_reg = HSYNC_B;
htotal_reg = HTOTAL_B;
hblank_reg = HBLANK_B;
@@ -1296,6 +1305,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
fp0_reg = FPA0;
fp1_reg = FPA1;
pipe_conf_reg = PIPEACONF;
+ pipe_stat_reg = PIPEASTAT;
hsync_reg = HSYNC_A;
htotal_reg = HTOTAL_A;
hblank_reg = HBLANK_A;
@@ -1312,8 +1322,8 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
count = 0;
do {
- tmp_val[count%3] = INREG(0x70000);
- if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1]==tmp_val[2]))
+ tmp_val[count % 3] = INREG(PIPEA_DSL);
+ if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1] == tmp_val[2]))
break;
count++;
udelay(1);
@@ -1322,7 +1332,7 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
tmp &= ~PIPECONF_ENABLE;
OUTREG(pipe_conf_reg, tmp);
}
- } while(count < 2000);
+ } while (count < 2000);
OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);
@@ -1382,6 +1392,17 @@ intelfbhw_program_mode(struct intelfb_info *dinfo,
OUTREG(vtotal_reg, *vt);
OUTREG(src_size_reg, *ss);
+ switch (dinfo->info->var.vmode & (FB_VMODE_INTERLACED |
+ FB_VMODE_ODD_FLD_FIRST)) {
+ case FB_VMODE_INTERLACED | FB_VMODE_ODD_FLD_FIRST:
+ OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_ODD_EN);
+ break;
+ case FB_VMODE_INTERLACED: /* even lines first */
+ OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_EVEN_EN);
+ break;
+ default: /* non-interlaced */
+ OUTREG(pipe_stat_reg, 0xFFFF); /* clear all status bits only */
+ }
/* Enable pipe */
OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
@@ -1446,8 +1467,7 @@ static u32 get_ring_space(struct intelfb_info *dinfo)
return ring_space;
}
-static int
-wait_ring(struct intelfb_info *dinfo, int n)
+static int wait_ring(struct intelfb_info *dinfo, int n)
{
int i = 0;
unsigned long end;
@@ -1489,16 +1509,15 @@ wait_ring(struct intelfb_info *dinfo, int n)
return i;
}
-static void
-do_flush(struct intelfb_info *dinfo) {
+static void do_flush(struct intelfb_info *dinfo)
+{
START_RING(2);
OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE);
OUT_RING(MI_NOOP);
ADVANCE_RING();
}
-void
-intelfbhw_do_sync(struct intelfb_info *dinfo)
+void intelfbhw_do_sync(struct intelfb_info *dinfo)
{
#if VERBOSE > 0
DBG_MSG("intelfbhw_do_sync\n");
@@ -1517,8 +1536,7 @@ intelfbhw_do_sync(struct intelfb_info *dinfo)
dinfo->ring_space = dinfo->ring.size - RING_MIN_FREE;
}
-static void
-refresh_ring(struct intelfb_info *dinfo)
+static void refresh_ring(struct intelfb_info *dinfo)
{
#if VERBOSE > 0
DBG_MSG("refresh_ring\n");
@@ -1529,8 +1547,7 @@ refresh_ring(struct intelfb_info *dinfo)
dinfo->ring_space = get_ring_space(dinfo);
}
-static void
-reset_state(struct intelfb_info *dinfo)
+static void reset_state(struct intelfb_info *dinfo)
{
int i;
u32 tmp;
@@ -1560,12 +1577,11 @@ reset_state(struct intelfb_info *dinfo)
}
/* Stop the 2D engine, and turn off the ring buffer. */
-void
-intelfbhw_2d_stop(struct intelfb_info *dinfo)
+void intelfbhw_2d_stop(struct intelfb_info *dinfo)
{
#if VERBOSE > 0
- DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", dinfo->accel,
- dinfo->ring_active);
+ DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n",
+ dinfo->accel, dinfo->ring_active);
#endif
if (!dinfo->accel)
@@ -1580,8 +1596,7 @@ intelfbhw_2d_stop(struct intelfb_info *dinfo)
* It is assumed that the graphics engine has been stopped by previously
* calling intelfb_2d_stop().
*/
-void
-intelfbhw_2d_start(struct intelfb_info *dinfo)
+void intelfbhw_2d_start(struct intelfb_info *dinfo)
{
#if VERBOSE > 0
DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n",
@@ -1605,9 +1620,8 @@ intelfbhw_2d_start(struct intelfb_info *dinfo)
}
/* 2D fillrect (solid fill or invert) */
-void
-intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, u32 h,
- u32 color, u32 pitch, u32 bpp, u32 rop)
+void intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w,
+ u32 h, u32 color, u32 pitch, u32 bpp, u32 rop)
{
u32 br00, br09, br13, br14, br16;
@@ -1696,9 +1710,9 @@ intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury,
ADVANCE_RING();
}
-int
-intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w,
- u32 h, const u8* cdat, u32 x, u32 y, u32 pitch, u32 bpp)
+int intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w,
+ u32 h, const u8* cdat, u32 x, u32 y, u32 pitch,
+ u32 bpp)
{
int nbytes, ndwords, pad, tmp;
u32 br00, br09, br13, br18, br19, br22, br23;
@@ -1785,8 +1799,7 @@ intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w,
}
/* HW cursor functions. */
-void
-intelfbhw_cursor_init(struct intelfb_info *dinfo)
+void intelfbhw_cursor_init(struct intelfb_info *dinfo)
{
u32 tmp;
@@ -1817,8 +1830,7 @@ intelfbhw_cursor_init(struct intelfb_info *dinfo)
}
}
-void
-intelfbhw_cursor_hide(struct intelfb_info *dinfo)
+void intelfbhw_cursor_hide(struct intelfb_info *dinfo)
{
u32 tmp;
@@ -1843,8 +1855,7 @@ intelfbhw_cursor_hide(struct intelfb_info *dinfo)
}
}
-void
-intelfbhw_cursor_show(struct intelfb_info *dinfo)
+void intelfbhw_cursor_show(struct intelfb_info *dinfo)
{
u32 tmp;
@@ -1873,8 +1884,7 @@ intelfbhw_cursor_show(struct intelfb_info *dinfo)
}
}
-void
-intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
+void intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
{
u32 tmp;
@@ -1892,13 +1902,11 @@ intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
OUTREG(CURSOR_A_POSITION, tmp);
- if (IS_I9XX(dinfo)) {
+ if (IS_I9XX(dinfo))
OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
- }
}
-void
-intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg)
+void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg)
{
#if VERBOSE > 0
DBG_MSG("intelfbhw_cursor_setcolor\n");
@@ -1910,9 +1918,8 @@ intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg)
OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK);
}
-void
-intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height,
- u8 *data)
+void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height,
+ u8 *data)
{
u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual;
int i, j, w = width / 8;
@@ -1940,8 +1947,8 @@ intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height,
}
}
-void
-intelfbhw_cursor_reset(struct intelfb_info *dinfo) {
+void intelfbhw_cursor_reset(struct intelfb_info *dinfo)
+{
u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual;
int i, j;
@@ -1961,72 +1968,72 @@ intelfbhw_cursor_reset(struct intelfb_info *dinfo) {
}
}
-static irqreturn_t
-intelfbhw_irq(int irq, void *dev_id) {
- int handled = 0;
+static irqreturn_t intelfbhw_irq(int irq, void *dev_id)
+{
u16 tmp;
struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
spin_lock(&dinfo->int_lock);
tmp = INREG16(IIR);
- tmp &= VSYNC_PIPE_A_INTERRUPT;
+ if (dinfo->info->var.vmode & FB_VMODE_INTERLACED)
+ tmp &= PIPE_A_EVENT_INTERRUPT;
+ else
+ tmp &= VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */
if (tmp == 0) {
spin_unlock(&dinfo->int_lock);
- return IRQ_RETVAL(handled);
+ return IRQ_RETVAL(0); /* not us */
}
- OUTREG16(IIR, tmp);
+ /* clear status bits 0-15 ASAP and don't touch bits 16-31 */
+ OUTREG(PIPEASTAT, INREG(PIPEASTAT));
- if (tmp & VSYNC_PIPE_A_INTERRUPT) {
- dinfo->vsync.count++;
- if (dinfo->vsync.pan_display) {
- dinfo->vsync.pan_display = 0;
- OUTREG(DSPABASE, dinfo->vsync.pan_offset);
- }
- wake_up_interruptible(&dinfo->vsync.wait);
- handled = 1;
+ OUTREG16(IIR, tmp);
+ if (dinfo->vsync.pan_display) {
+ dinfo->vsync.pan_display = 0;
+ OUTREG(DSPABASE, dinfo->vsync.pan_offset);
}
+ dinfo->vsync.count++;
+ wake_up_interruptible(&dinfo->vsync.wait);
+
spin_unlock(&dinfo->int_lock);
- return IRQ_RETVAL(handled);
+ return IRQ_RETVAL(1);
}
-int
-intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) {
-
+int intelfbhw_enable_irq(struct intelfb_info *dinfo)
+{
+ u16 tmp;
if (!test_and_set_bit(0, &dinfo->irq_flags)) {
if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED,
- "intelfb", dinfo)) {
+ "intelfb", dinfo)) {
clear_bit(0, &dinfo->irq_flags);
return -EINVAL;
}
spin_lock_irq(&dinfo->int_lock);
- OUTREG16(HWSTAM, 0xfffe);
- OUTREG16(IMR, 0x0);
- OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT);
- spin_unlock_irq(&dinfo->int_lock);
- } else if (reenable) {
- u16 ier;
-
+ OUTREG16(HWSTAM, 0xfffe); /* i830 DRM uses ffff */
+ OUTREG16(IMR, 0);
+ } else
spin_lock_irq(&dinfo->int_lock);
- ier = INREG16(IER);
- if ((ier & VSYNC_PIPE_A_INTERRUPT)) {
- DBG_MSG("someone disabled the IRQ [%08X]\n", ier);
- OUTREG(IER, VSYNC_PIPE_A_INTERRUPT);
- }
- spin_unlock_irq(&dinfo->int_lock);
+
+ if (dinfo->info->var.vmode & FB_VMODE_INTERLACED)
+ tmp = PIPE_A_EVENT_INTERRUPT;
+ else
+ tmp = VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */
+ if (tmp != INREG16(IER)) {
+ DBG_MSG("changing IER to 0x%X\n", tmp);
+ OUTREG16(IER, tmp);
}
+
+ spin_unlock_irq(&dinfo->int_lock);
return 0;
}
-void
-intelfbhw_disable_irq(struct intelfb_info *dinfo) {
- u16 tmp;
-
+void intelfbhw_disable_irq(struct intelfb_info *dinfo)
+{
if (test_and_clear_bit(0, &dinfo->irq_flags)) {
if (dinfo->vsync.pan_display) {
dinfo->vsync.pan_display = 0;
@@ -2037,16 +2044,15 @@ intelfbhw_disable_irq(struct intelfb_info *dinfo) {
OUTREG16(IMR, 0xffff);
OUTREG16(IER, 0x0);
- tmp = INREG16(IIR);
- OUTREG16(IIR, tmp);
+ OUTREG16(IIR, INREG16(IIR)); /* clear IRQ requests */
spin_unlock_irq(&dinfo->int_lock);
free_irq(dinfo->pdev->irq, dinfo);
}
}
-int
-intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) {
+int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe)
+{
struct intelfb_vsync *vsync;
unsigned int count;
int ret;
@@ -2059,18 +2065,16 @@ intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) {
return -ENODEV;
}
- ret = intelfbhw_enable_irq(dinfo, 0);
- if (ret) {
+ ret = intelfbhw_enable_irq(dinfo);
+ if (ret)
return ret;
- }
count = vsync->count;
- ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ/10);
- if (ret < 0) {
+ ret = wait_event_interruptible_timeout(vsync->wait,
+ count != vsync->count, HZ / 10);
+ if (ret < 0)
return ret;
- }
if (ret == 0) {
- intelfbhw_enable_irq(dinfo, 1);
DBG_MSG("wait_for_vsync timed out!\n");
return -ETIMEDOUT;
}
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
index 8c54ba8fbdd..0b076bac321 100644
--- a/drivers/video/intelfb/intelfbhw.h
+++ b/drivers/video/intelfb/intelfbhw.h
@@ -83,7 +83,7 @@
*/
#define RING_MIN_FREE 64
-#define IPEHR 0x2088
+#define IPEHR 0x2088
#define INSTDONE 0x2090
#define PRI_RING_EMPTY 1
@@ -93,7 +93,7 @@
#define IIR 0x20A4
#define IMR 0x20A8
#define VSYNC_PIPE_A_INTERRUPT (1 << 7)
-#define PIPE_A_EVENT_INTERRUPT (1 << 4)
+#define PIPE_A_EVENT_INTERRUPT (1 << 6)
#define VSYNC_PIPE_B_INTERRUPT (1 << 5)
#define PIPE_B_EVENT_INTERRUPT (1 << 4)
#define HOST_PORT_EVENT_INTERRUPT (1 << 3)
@@ -128,9 +128,9 @@
#define GPIOA 0x5010
#define GPIOB 0x5014
-#define GPIOC 0x5018 // this may be external DDC on i830
-#define GPIOD 0x501C // this is DVO DDC
-#define GPIOE 0x5020 // this is DVO i2C
+#define GPIOC 0x5018 /* this may be external DDC on i830 */
+#define GPIOD 0x501C /* this is DVO DDC */
+#define GPIOE 0x5020 /* this is DVO i2C */
#define GPIOF 0x5024
/* PLL registers */
@@ -269,15 +269,20 @@
#define PORT_ENABLE (1 << 31)
#define PORT_PIPE_SELECT_SHIFT 30
#define PORT_TV_FLAGS_MASK 0xFF
-#define PORT_TV_FLAGS 0xC4 // ripped from my BIOS
- // to understand and correct
+#define PORT_TV_FLAGS 0xC4 /* ripped from my BIOS
+ to understand and correct */
#define DVOA_SRCDIM 0x61124
#define DVOB_SRCDIM 0x61144
#define DVOC_SRCDIM 0x61164
+#define PIPEA_DSL 0x70000
+#define PIPEB_DSL 0x71000
#define PIPEACONF 0x70008
#define PIPEBCONF 0x71008
+#define PIPEASTAT 0x70024 /* bits 0-15 are "write 1 to clear" */
+#define PIPEBSTAT 0x71024
+
#define PIPECONF_ENABLE (1 << 31)
#define PIPECONF_DISABLE 0
#define PIPECONF_DOUBLE_WIDE (1 << 30)
@@ -286,6 +291,35 @@
#define PIPECONF_UNLOCKED 0
#define PIPECONF_GAMMA (1 << 24)
#define PIPECONF_PALETTE 0
+#define PIPECONF_PROGRESSIVE (0 << 21)
+#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21)
+#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
+#define PIPECONF_INTERLACE_MASK (7 << 21)
+
+/* enable bits, write 1 to enable */
+#define PIPESTAT_FIFO_UNDERRUN (1 << 31)
+#define PIPESTAT_CRC_ERROR_EN (1 << 29)
+#define PIPESTAT_CRC_DONE_EN (1 << 28)
+#define PIPESTAT_HOTPLUG_EN (1 << 26)
+#define PIPESTAT_VERTICAL_SYNC_EN (1 << 25)
+#define PIPESTAT_DISPLINE_COMP_EN (1 << 24)
+#define PIPESTAT_FLD_EVT_ODD_EN (1 << 21)
+#define PIPESTAT_FLD_EVT_EVEN_EN (1 << 20)
+#define PIPESTAT_TV_HOTPLUG_EN (1 << 18)
+#define PIPESTAT_VBLANK_EN (1 << 17)
+#define PIPESTAT_OVL_UPDATE_EN (1 << 16)
+/* status bits, write 1 to clear */
+#define PIPESTAT_HOTPLUG_STATE (1 << 15)
+#define PIPESTAT_CRC_ERROR (1 << 13)
+#define PIPESTAT_CRC_DONE (1 << 12)
+#define PIPESTAT_HOTPLUG (1 << 10)
+#define PIPESTAT_VSYNC (1 << 9)
+#define PIPESTAT_DISPLINE_COMP (1 << 8)
+#define PIPESTAT_FLD_EVT_ODD (1 << 5)
+#define PIPESTAT_FLD_EVT_EVEN (1 << 4)
+#define PIPESTAT_TV_HOTPLUG (1 << 2)
+#define PIPESTAT_VBLANK (1 << 1)
+#define PIPESTAT_OVL_UPDATE (1 << 0)
#define DISPARB 0x70030
#define DISPARB_AEND_MASK 0x1ff
@@ -365,7 +399,7 @@
#define DISPPLANE_8BPP (0x2<<26)
#define DISPPLANE_15_16BPP (0x4<<26)
#define DISPPLANE_16BPP (0x5<<26)
-#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26)
+#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26)
#define DISPPLANE_32BPP (0x7<<26)
#define DISPPLANE_STEREO_ENABLE (1<<25)
#define DISPPLANE_STEREO_DISABLE 0
@@ -567,7 +601,7 @@ extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg,
extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width,
int height, u8 *data);
extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo);
-extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable);
+extern int intelfbhw_enable_irq(struct intelfb_info *dinfo);
extern void intelfbhw_disable_irq(struct intelfb_info *dinfo);
extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe);
diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c
index 1c557990739..acb9370fdb1 100644
--- a/drivers/video/kyro/fbdev.c
+++ b/drivers/video/kyro/fbdev.c
@@ -21,7 +21,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index 2b0f799aa8d..fc72684aae5 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -34,6 +34,10 @@ extern const struct linux_logo logo_superh_vga16;
extern const struct linux_logo logo_superh_clut224;
extern const struct linux_logo logo_m32r_clut224;
+static int nologo;
+module_param(nologo, bool, 0);
+MODULE_PARM_DESC(nologo, "Disables startup logo");
+
/* logo's are marked __initdata. Use __init_refok to tell
* modpost that it is intended that this function uses data
* marked __initdata.
@@ -42,6 +46,9 @@ const struct linux_logo * __init_refok fb_find_logo(int depth)
{
const struct linux_logo *logo = NULL;
+ if (nologo)
+ return NULL;
+
if (depth >= 1) {
#ifdef CONFIG_LOGO_LINUX_MONO
/* Generic Linux logo */
@@ -71,10 +78,7 @@ const struct linux_logo * __init_refok fb_find_logo(int depth)
#endif
#ifdef CONFIG_LOGO_DEC_CLUT224
/* DEC Linux logo on MIPS/MIPS64 or ALPHA */
-#ifndef CONFIG_ALPHA
- if (mips_machgroup == MACH_GROUP_DEC)
-#endif
- logo = &logo_dec_clut224;
+ logo = &logo_dec_clut224;
#endif
#ifdef CONFIG_LOGO_MAC_CLUT224
/* Macintosh Linux logo on m68k */
@@ -87,10 +91,7 @@ const struct linux_logo * __init_refok fb_find_logo(int depth)
#endif
#ifdef CONFIG_LOGO_SGI_CLUT224
/* SGI Linux logo on MIPS/MIPS64 and VISWS */
-#ifndef CONFIG_X86_VISWS
- if (mips_machgroup == MACH_GROUP_SGI)
-#endif
- logo = &logo_sgi_clut224;
+ logo = &logo_sgi_clut224;
#endif
#ifdef CONFIG_LOGO_SUN_CLUT224
/* Sun Linux logo */
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index 86ca7b17900..b25972ac6ee 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -113,7 +113,7 @@
#include "matroxfb_g450.h"
#include <linux/matroxfb.h>
#include <linux/interrupt.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#ifdef CONFIG_PPC_PMAC
#include <asm/machdep.h>
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
index 4b3344e0369..a6ab5b6a58d 100644
--- a/drivers/video/matrox/matroxfb_crtc2.c
+++ b/drivers/video/matrox/matroxfb_crtc2.c
@@ -15,7 +15,7 @@
#include "matroxfb_misc.h"
#include "matroxfb_DAC1064.h"
#include <linux/matroxfb.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
/* **************************************************** */
diff --git a/drivers/video/matrox/matroxfb_g450.c b/drivers/video/matrox/matroxfb_g450.c
index 4d610b405d4..6209a761f67 100644
--- a/drivers/video/matrox/matroxfb_g450.c
+++ b/drivers/video/matrox/matroxfb_g450.c
@@ -17,7 +17,6 @@
#include "matroxfb_DAC1064.h"
#include "g450_pll.h"
#include <linux/matroxfb.h>
-#include <asm/uaccess.h>
#include <asm/div64.h>
#include "matroxfb_g450.h"
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
index de0d755f901..49cd53e46c0 100644
--- a/drivers/video/matrox/matroxfb_maven.c
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -18,7 +18,6 @@
#include <linux/i2c.h>
#include <linux/matroxfb.h>
#include <asm/div64.h>
-#include <asm/uaccess.h>
#define MAVEN_I2CID (0x1B)
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c
index 980d5f62390..80cd117ca65 100644
--- a/drivers/video/mbx/mbxfb.c
+++ b/drivers/video/mbx/mbxfb.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/video/mbx/mbxfb.c
*
- * Copyright (C) 2006 8D Technologies inc
+ * Copyright (C) 2006-2007 8D Technologies inc
* Raphael Assenat <raph@8d.com>
* - Added video overlay support
* - Various improvements
@@ -334,8 +334,8 @@ static int mbxfb_blank(int blank, struct fb_info *info)
static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
{
- u32 vsctrl, vbbase, vscadr, vsadr;
- u32 sssize, spoctrl, svctrl, shctrl;
+ u32 vsctrl, vscadr, vsadr;
+ u32 sssize, spoctrl, shctrl;
u32 vubase, vvbase;
u32 vovrclk;
@@ -349,13 +349,11 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
vscadr = readl(VSCADR);
vubase = readl(VUBASE);
vvbase = readl(VVBASE);
+ shctrl = readl(SHCTRL);
spoctrl = readl(SPOCTRL);
sssize = readl(SSSIZE);
-
- vbbase = Vbbase_Glalpha(set->alpha);
-
vsctrl &= ~( FMsk(VSCTRL_VSWIDTH) |
FMsk(VSCTRL_VSHEIGHT) |
FMsk(VSCTRL_VPIXFMT) |
@@ -364,38 +362,41 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
vsctrl |= Vsctrl_Width(set->width) | Vsctrl_Height(set->height) |
VSCTRL_CSC_EN;
- vscadr &= ~(VSCADR_STR_EN | VSCADR_COLKEY_EN | VSCADR_COLKEYSRC |
- FMsk(VSCADR_BLEND_M) | FMsk(VSCADR_BLEND_POS) |
- FMsk(VSCADR_VBASE_ADR) );
+ vscadr &= ~(VSCADR_STR_EN | FMsk(VSCADR_VBASE_ADR) );
vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR));
vvbase &= ~(FMsk(VVBASE_VBASE_ADR));
- switch (set->fmt)
- {
- case MBXFB_FMT_YUV12:
- vsctrl |= VSCTRL_VPIXFMT_YUV12;
+ switch (set->fmt) {
+ case MBXFB_FMT_YUV16:
+ vsctrl |= VSCTRL_VPIXFMT_YUV12;
- set->Y_stride = ((set->width) + 0xf ) & ~0xf;
+ set->Y_stride = ((set->width) + 0xf ) & ~0xf;
+ break;
+ case MBXFB_FMT_YUV12:
+ vsctrl |= VSCTRL_VPIXFMT_YUV12;
+ set->Y_stride = ((set->width) + 0xf ) & ~0xf;
+ vubase |= VUBASE_UVHALFSTR;
+
+ break;
+ case MBXFB_FMT_UY0VY1:
+ vsctrl |= VSCTRL_VPIXFMT_UY0VY1;
+ set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
+ break;
+ case MBXFB_FMT_VY0UY1:
+ vsctrl |= VSCTRL_VPIXFMT_VY0UY1;
+ set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
+ break;
+ case MBXFB_FMT_Y0UY1V:
+ vsctrl |= VSCTRL_VPIXFMT_Y0UY1V;
+ set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
+ break;
+ case MBXFB_FMT_Y0VY1U:
+ vsctrl |= VSCTRL_VPIXFMT_Y0VY1U;
+ set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
break;
- case MBXFB_FMT_UY0VY1:
- vsctrl |= VSCTRL_VPIXFMT_UY0VY1;
- set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
- break;
- case MBXFB_FMT_VY0UY1:
- vsctrl |= VSCTRL_VPIXFMT_VY0UY1;
- set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
- break;
- case MBXFB_FMT_Y0UY1V:
- vsctrl |= VSCTRL_VPIXFMT_Y0UY1V;
- set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
- break;
- case MBXFB_FMT_Y0VY1U:
- vsctrl |= VSCTRL_VPIXFMT_Y0VY1U;
- set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
- break;
- default:
- return -EINVAL;
+ default:
+ return -EINVAL;
}
/* VSCTRL has the bits which sets the Video Pixel Format.
@@ -417,8 +418,7 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
(0x60000 + set->mem_offset + set->V_offset)>>3);
- vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_GLOB |
- Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4);
+ vscadr |= Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4);
if (set->enable)
vscadr |= VSCADR_STR_EN;
@@ -433,9 +433,8 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
spoctrl &= ~(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP |
SPOCTRL_HV_SC_OR | SPOCTRL_VS_UR_C |
- FMsk(SPOCTRL_VORDER) | FMsk(SPOCTRL_VPITCH));
- spoctrl = Spoctrl_Vpitch((set->height<<11)/set->scaled_height)
- | SPOCTRL_VORDER_2TAP;
+ FMsk(SPOCTRL_VPITCH));
+ spoctrl |= Spoctrl_Vpitch((set->height<<11)/set->scaled_height);
/* Bypass horiz/vert scaler when same size */
if (set->scaled_width == set->width)
@@ -443,14 +442,11 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
if (set->scaled_height == set->height)
spoctrl |= SPOCTRL_V_SC_BP;
- svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10);
-
- shctrl = Shctrl_Hinitial(4<<11)
- | Shctrl_Hpitch((set->width<<11)/set->scaled_width);
+ shctrl &= ~(FMsk(SHCTRL_HPITCH) | SHCTRL_HDECIM);
+ shctrl |= Shctrl_Hpitch((set->width<<11)/set->scaled_width);
/* Video plane registers */
write_reg(vsctrl, VSCTRL);
- write_reg(vbbase, VBBASE);
write_reg(vscadr, VSCADR);
write_reg(vubase, VUBASE);
write_reg(vvbase, VVBASE);
@@ -459,28 +455,8 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
/* Video scaler registers */
write_reg(sssize, SSSIZE);
write_reg(spoctrl, SPOCTRL);
- write_reg(svctrl, SVCTRL);
write_reg(shctrl, SHCTRL);
- /* RAPH: Using those coefficients, the scaled
- * image is quite blurry. I dont know how
- * to improve them ; The chip documentation
- * was not helpful.. */
- write_reg(0x21212121, VSCOEFF0);
- write_reg(0x21212121, VSCOEFF1);
- write_reg(0x21212121, VSCOEFF2);
- write_reg(0x21212121, VSCOEFF3);
- write_reg(0x21212121, VSCOEFF4);
- write_reg(0x00000000, HSCOEFF0);
- write_reg(0x00000000, HSCOEFF1);
- write_reg(0x00000000, HSCOEFF2);
- write_reg(0x03020201, HSCOEFF3);
- write_reg(0x09070604, HSCOEFF4);
- write_reg(0x0f0e0c0a, HSCOEFF5);
- write_reg(0x15141211, HSCOEFF6);
- write_reg(0x19181716, HSCOEFF7);
- write_reg(0x00000019, HSCOEFF8);
-
/* Clock */
if (set->enable)
vovrclk |= 1;
@@ -492,27 +468,206 @@ static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
return 0;
}
+static int mbxfb_ioctl_planeorder(struct mbxfb_planeorder *porder)
+{
+ unsigned long gscadr, vscadr;
+
+ if (porder->bottom == porder->top)
+ return -EINVAL;
+
+ gscadr = readl(GSCADR);
+ vscadr = readl(VSCADR);
+
+ gscadr &= ~(FMsk(GSCADR_BLEND_POS));
+ vscadr &= ~(FMsk(VSCADR_BLEND_POS));
+
+ switch (porder->bottom) {
+ case MBXFB_PLANE_GRAPHICS:
+ gscadr |= GSCADR_BLEND_GFX;
+ break;
+ case MBXFB_PLANE_VIDEO:
+ vscadr |= VSCADR_BLEND_GFX;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (porder->top) {
+ case MBXFB_PLANE_GRAPHICS:
+ gscadr |= GSCADR_BLEND_VID;
+ break;
+ case MBXFB_PLANE_VIDEO:
+ vscadr |= GSCADR_BLEND_VID;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ write_reg_dly(vscadr, VSCADR);
+ write_reg_dly(gscadr, GSCADR);
+
+ return 0;
+
+}
+
+static int mbxfb_ioctl_alphactl(struct mbxfb_alphaCtl *alpha)
+{
+ unsigned long vscadr, vbbase, vcmsk;
+ unsigned long gscadr, gbbase, gdrctrl;
+
+ vbbase = Vbbase_Glalpha(alpha->overlay_global_alpha) |
+ Vbbase_Colkey(alpha->overlay_colorkey);
+
+ gbbase = Gbbase_Glalpha(alpha->graphics_global_alpha) |
+ Gbbase_Colkey(alpha->graphics_colorkey);
+
+ vcmsk = readl(VCMSK);
+ vcmsk &= ~(FMsk(VCMSK_COLKEY_M));
+ vcmsk |= Vcmsk_colkey_m(alpha->overlay_colorkey_mask);
+
+ gdrctrl = readl(GDRCTRL);
+ gdrctrl &= ~(FMsk(GDRCTRL_COLKEYM));
+ gdrctrl |= Gdrctrl_Colkeym(alpha->graphics_colorkey_mask);
+
+ vscadr = readl(VSCADR);
+ vscadr &= ~(FMsk(VSCADR_BLEND_M) | VSCADR_COLKEYSRC | VSCADR_COLKEY_EN);
+
+ gscadr = readl(GSCADR);
+ gscadr &= ~(FMsk(GSCADR_BLEND_M) | GSCADR_COLKEY_EN | GSCADR_COLKEYSRC);
+
+ switch (alpha->overlay_colorkey_mode) {
+ case MBXFB_COLORKEY_DISABLED:
+ break;
+ case MBXFB_COLORKEY_PREVIOUS:
+ vscadr |= VSCADR_COLKEY_EN;
+ break;
+ case MBXFB_COLORKEY_CURRENT:
+ vscadr |= VSCADR_COLKEY_EN | VSCADR_COLKEYSRC;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (alpha->overlay_blend_mode) {
+ case MBXFB_ALPHABLEND_NONE:
+ vscadr |= VSCADR_BLEND_NONE;
+ break;
+ case MBXFB_ALPHABLEND_GLOBAL:
+ vscadr |= VSCADR_BLEND_GLOB;
+ break;
+ case MBXFB_ALPHABLEND_PIXEL:
+ vscadr |= VSCADR_BLEND_PIX;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (alpha->graphics_colorkey_mode) {
+ case MBXFB_COLORKEY_DISABLED:
+ break;
+ case MBXFB_COLORKEY_PREVIOUS:
+ gscadr |= GSCADR_COLKEY_EN;
+ break;
+ case MBXFB_COLORKEY_CURRENT:
+ gscadr |= GSCADR_COLKEY_EN | GSCADR_COLKEYSRC;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (alpha->graphics_blend_mode) {
+ case MBXFB_ALPHABLEND_NONE:
+ gscadr |= GSCADR_BLEND_NONE;
+ break;
+ case MBXFB_ALPHABLEND_GLOBAL:
+ gscadr |= GSCADR_BLEND_GLOB;
+ break;
+ case MBXFB_ALPHABLEND_PIXEL:
+ gscadr |= GSCADR_BLEND_PIX;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ write_reg_dly(vbbase, VBBASE);
+ write_reg_dly(gbbase, GBBASE);
+ write_reg_dly(vcmsk, VCMSK);
+ write_reg_dly(gdrctrl, GDRCTRL);
+ write_reg_dly(gscadr, GSCADR);
+ write_reg_dly(vscadr, VSCADR);
+
+ return 0;
+}
+
static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
- struct mbxfb_overlaySetup setup;
+ struct mbxfb_overlaySetup setup;
+ struct mbxfb_planeorder porder;
+ struct mbxfb_alphaCtl alpha;
+ struct mbxfb_reg reg;
int res;
+ __u32 tmp;
- if (cmd == MBXFB_IOCX_OVERLAY)
+ switch (cmd)
{
- if (copy_from_user(&setup, (void __user*)arg,
- sizeof(struct mbxfb_overlaySetup)))
+ case MBXFB_IOCX_OVERLAY:
+ if (copy_from_user(&setup, (void __user*)arg,
+ sizeof(struct mbxfb_overlaySetup)))
+ return -EFAULT;
+
+ res = mbxfb_setupOverlay(&setup);
+ if (res)
+ return res;
+
+ if (copy_to_user((void __user*)arg, &setup,
+ sizeof(struct mbxfb_overlaySetup)))
+ return -EFAULT;
+
+ return 0;
+
+ case MBXFB_IOCS_PLANEORDER:
+ if (copy_from_user(&porder, (void __user*)arg,
+ sizeof(struct mbxfb_planeorder)))
return -EFAULT;
- res = mbxfb_setupOverlay(&setup);
- if (res)
- return res;
+ return mbxfb_ioctl_planeorder(&porder);
- if (copy_to_user((void __user*)arg, &setup,
- sizeof(struct mbxfb_overlaySetup)))
+ case MBXFB_IOCS_ALPHA:
+ if (copy_from_user(&alpha, (void __user*)arg,
+ sizeof(struct mbxfb_alphaCtl)))
return -EFAULT;
- return 0;
+ return mbxfb_ioctl_alphactl(&alpha);
+
+ case MBXFB_IOCS_REG:
+ if (copy_from_user(&reg, (void __user*)arg,
+ sizeof(struct mbxfb_reg)))
+ return -EFAULT;
+
+ if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */
+ return -EINVAL;
+
+ tmp = readl(virt_base_2700 + reg.addr);
+ tmp &= ~reg.mask;
+ tmp |= reg.val & reg.mask;
+ writel(tmp, virt_base_2700 + reg.addr);
+
+ return 0;
+ case MBXFB_IOCX_REG:
+ if (copy_from_user(&reg, (void __user*)arg,
+ sizeof(struct mbxfb_reg)))
+ return -EFAULT;
+
+ if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */
+ return -EINVAL;
+ reg.val = readl(virt_base_2700 + reg.addr);
+
+ if (copy_to_user((void __user*)arg, &reg,
+ sizeof(struct mbxfb_reg)))
+ return -EFAULT;
+
+ return 0;
}
return -EINVAL;
}
@@ -558,7 +713,6 @@ static void __devinit setup_memc(struct fb_info *fbi)
LMTYPE);
/* enable memory controller */
write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
-
/* perform dummy reads */
for ( i = 0; i < 16; i++ ) {
tmp = readl(fbi->screen_base);
@@ -588,8 +742,8 @@ static void enable_clocks(struct fb_info *fbi)
write_reg_dly(0x00000000, VOVRCLK);
write_reg_dly(PIXCLK_EN, PIXCLK);
write_reg_dly(MEMCLK_EN, MEMCLK);
- write_reg_dly(0x00000006, M24CLK);
- write_reg_dly(0x00000006, MBXCLK);
+ write_reg_dly(0x00000001, M24CLK);
+ write_reg_dly(0x00000001, MBXCLK);
write_reg_dly(SDCLK_EN, SDCLK);
write_reg_dly(0x00000001, PIXCLKDIV);
}
@@ -597,6 +751,7 @@ static void enable_clocks(struct fb_info *fbi)
static void __devinit setup_graphics(struct fb_info *fbi)
{
unsigned long gsctrl;
+ unsigned long vscadr;
gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) |
Gsctrl_Height(fbi->var.yres);
@@ -620,6 +775,11 @@ static void __devinit setup_graphics(struct fb_info *fbi)
write_reg_dly(0x00ffffff, GDRCTRL);
write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR);
write_reg_dly(0x00000000, GPLUT);
+
+ vscadr = readl(VSCADR);
+ vscadr &= ~(FMsk(VSCADR_BLEND_POS) | FMsk(VSCADR_BLEND_M));
+ vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_NONE;
+ write_reg_dly(vscadr, VSCADR);
}
static void __devinit setup_display(struct fb_info *fbi)
@@ -638,13 +798,47 @@ static void __devinit setup_display(struct fb_info *fbi)
static void __devinit enable_controller(struct fb_info *fbi)
{
+ u32 svctrl, shctrl;
+
write_reg_dly(SYSRST_RST, SYSRST);
+ /* setup a timeout, raise drive strength */
+ write_reg_dly(0xffffff0c, SYSCFG);
enable_clocks(fbi);
setup_memc(fbi);
setup_graphics(fbi);
setup_display(fbi);
+
+ shctrl = readl(SHCTRL);
+ shctrl &= ~(FMsk(SHCTRL_HINITIAL));
+ shctrl |= Shctrl_Hinitial(4<<11);
+ writel(shctrl, SHCTRL);
+
+ svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10);
+ writel(svctrl, SVCTRL);
+
+ writel(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | SPOCTRL_VORDER_4TAP
+ , SPOCTRL);
+
+ /* Those coefficients are good for scaling up. For scaling
+ * down, the application has to calculate them. */
+ write_reg(0xff000100, VSCOEFF0);
+ write_reg(0xfdfcfdfe, VSCOEFF1);
+ write_reg(0x170d0500, VSCOEFF2);
+ write_reg(0x3d372d22, VSCOEFF3);
+ write_reg(0x00000040, VSCOEFF4);
+
+ write_reg(0xff010100, HSCOEFF0);
+ write_reg(0x00000000, HSCOEFF1);
+ write_reg(0x02010000, HSCOEFF2);
+ write_reg(0x01020302, HSCOEFF3);
+ write_reg(0xf9fbfe00, HSCOEFF4);
+ write_reg(0xfbf7f6f7, HSCOEFF5);
+ write_reg(0x1c110700, HSCOEFF6);
+ write_reg(0x3e393127, HSCOEFF7);
+ write_reg(0x00000040, HSCOEFF8);
+
}
#ifdef CONFIG_PM
diff --git a/drivers/video/mbx/reg_bits.h b/drivers/video/mbx/reg_bits.h
index 9a24fb0c7d4..5f14b4befd7 100644
--- a/drivers/video/mbx/reg_bits.h
+++ b/drivers/video/mbx/reg_bits.h
@@ -215,7 +215,7 @@
/* GSCADR graphics stream control address register fields */
#define GSCADR_STR_EN (1 << 31)
#define GSCADR_COLKEY_EN (1 << 30)
-#define GSCADR_COLKEYSCR (1 << 29)
+#define GSCADR_COLKEYSRC (1 << 29)
#define GSCADR_BLEND_M Fld(2,27)
#define GSCADR_BLEND_NONE ((0x0) << FShft(GSCADR_BLEND_M))
#define GSCADR_BLEND_INV ((0x1) << FShft(GSCADR_BLEND_M))
@@ -303,6 +303,67 @@
#define VSADR_YSTART Fld(11,0)
#define Vsadr_Ystart(x) ((x) << FShft(VSADR_YSTART))
+/* VSCTRL - Video Surface Control Register */
+#define VSCTRL_VPIXFMT Fld(4,27)
+#define VSCTRL_VPIXFMT_YUV12 ((0x9) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_VPIXFMT_UY0VY1 ((0xc) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_VPIXFMT_VY0UY1 ((0xd) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_VPIXFMT_Y0UY1V ((0xe) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_VPIXFMT_Y0VY1U ((0xf) << FShft(VSCTRL_VPIXFMT))
+#define VSCTRL_GAMMA_EN (1 << 26)
+#define VSCTRL_CSC_EN (1 << 25)
+#define VSCTRL_COSITED (1 << 22)
+#define VSCTRL_VSWIDTH Fld(11,11)
+#define Vsctrl_Width(Pixels) /* Video Width [1-2048] */ \
+ (((Pixels) - 1) << FShft(VSCTRL_VSWIDTH))
+#define VSCTRL_VSHEIGHT Fld(11,0)
+#define Vsctrl_Height(Pixels) /* Video Height [1-2048] */ \
+ (((Pixels) - 1) << FShft(VSCTRL_VSHEIGHT))
+
+/* VBBASE - Video Blending Base Register */
+#define VBBASE_GLALPHA Fld(8,24)
+#define Vbbase_Glalpha(x) ((x) << FShft(VBBASE_GLALPHA))
+
+#define VBBASE_COLKEY Fld(24,0)
+#define Vbbase_Colkey(x) ((x) << FShft(VBBASE_COLKEY))
+
+/* VCMSK - Video Color Key Mask Register */
+#define VCMSK_COLKEY_M Fld(24,0)
+#define Vcmsk_colkey_m(x) ((x) << FShft(VCMSK_COLKEY_M))
+
+/* VSCADR - Video Stream Control Rddress Register */
+#define VSCADR_STR_EN (1 << 31)
+#define VSCADR_COLKEY_EN (1 << 30)
+#define VSCADR_COLKEYSRC (1 << 29)
+#define VSCADR_BLEND_M Fld(2,27)
+#define VSCADR_BLEND_NONE ((0x0) << FShft(VSCADR_BLEND_M))
+#define VSCADR_BLEND_INV ((0x1) << FShft(VSCADR_BLEND_M))
+#define VSCADR_BLEND_GLOB ((0x2) << FShft(VSCADR_BLEND_M))
+#define VSCADR_BLEND_PIX ((0x3) << FShft(VSCADR_BLEND_M))
+#define VSCADR_BLEND_POS Fld(2,24)
+#define VSCADR_BLEND_GFX ((0x0) << FShft(VSCADR_BLEND_POS))
+#define VSCADR_BLEND_VID ((0x1) << FShft(VSCADR_BLEND_POS))
+#define VSCADR_BLEND_CUR ((0x2) << FShft(VSCADR_BLEND_POS))
+#define VSCADR_VBASE_ADR Fld(23,0)
+#define Vscadr_Vbase_Adr(x) ((x) << FShft(VSCADR_VBASE_ADR))
+
+/* VUBASE - Video U Base Register */
+#define VUBASE_UVHALFSTR (1 << 31)
+#define VUBASE_UBASE_ADR Fld(24,0)
+#define Vubase_Ubase_Adr(x) ((x) << FShft(VUBASE_UBASE_ADR))
+
+/* VVBASE - Video V Base Register */
+#define VVBASE_VBASE_ADR Fld(24,0)
+#define Vvbase_Vbase_Adr(x) ((x) << FShft(VVBASE_VBASE_ADR))
+
+/* VSADR - Video Stride Address Register */
+#define VSADR_SRCSTRIDE Fld(10,22)
+#define Vsadr_Srcstride(x) ((x) << FShft(VSADR_SRCSTRIDE))
+#define VSADR_XSTART Fld(11,11)
+#define Vsadr_Xstart(x) ((x) << FShft(VSADR_XSTART))
+#define VSADR_YSTART Fld(11,0)
+#define Vsadr_Ystart(x) ((x) << FShft(VSADR_YSTART))
+
/* HCCTRL - Hardware Cursor Register fields */
#define HCCTRL_CUR_EN (1 << 31)
#define HCCTRL_COLKEY_EN (1 << 29)
@@ -479,6 +540,30 @@
#define DINTRE_HBLNK1_EN (1 << 1)
#define DINTRE_HBLNK0_EN (1 << 0)
+/* DINTRS - Display Interrupt Status Register */
+#define DINTRS_CUR_OR_S (1 << 18)
+#define DINTRS_STR2_OR_S (1 << 17)
+#define DINTRS_STR1_OR_S (1 << 16)
+#define DINTRS_CUR_UR_S (1 << 6)
+#define DINTRS_STR2_UR_S (1 << 5)
+#define DINTRS_STR1_UR_S (1 << 4)
+#define DINTRS_VEVENT1_S (1 << 3)
+#define DINTRS_VEVENT0_S (1 << 2)
+#define DINTRS_HBLNK1_S (1 << 1)
+#define DINTRS_HBLNK0_S (1 << 0)
+
+/* DINTRE - Display Interrupt Enable Register */
+#define DINTRE_CUR_OR_EN (1 << 18)
+#define DINTRE_STR2_OR_EN (1 << 17)
+#define DINTRE_STR1_OR_EN (1 << 16)
+#define DINTRE_CUR_UR_EN (1 << 6)
+#define DINTRE_STR2_UR_EN (1 << 5)
+#define DINTRE_STR1_UR_EN (1 << 4)
+#define DINTRE_VEVENT1_EN (1 << 3)
+#define DINTRE_VEVENT0_EN (1 << 2)
+#define DINTRE_HBLNK1_EN (1 << 1)
+#define DINTRE_HBLNK0_EN (1 << 0)
+
/* DLSTS - display load status register */
#define DLSTS_RLD_ADONE (1 << 23)
diff --git a/drivers/video/mbx/regs.h b/drivers/video/mbx/regs.h
index a7c63d865aa..063099d4883 100644
--- a/drivers/video/mbx/regs.h
+++ b/drivers/video/mbx/regs.h
@@ -30,7 +30,7 @@
#define VOVRCLK __REG_2700G(0x00000044)
#define PIXCLK __REG_2700G(0x00000048)
#define MEMCLK __REG_2700G(0x0000004c)
-#define M24CLK __REG_2700G(0x00000054)
+#define M24CLK __REG_2700G(0x00000050)
#define MBXCLK __REG_2700G(0x00000054)
#define SDCLK __REG_2700G(0x00000058)
#define PIXCLKDIV __REG_2700G(0x0000005c)
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 3741ad72940..8d81ef019c6 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -27,7 +27,7 @@
#define DPRINTK(fmt, args...)
#endif
-const char *global_mode_option;
+const char *fb_mode_option;
/*
* Standard video mode definitions (taken from XFree86)
@@ -72,7 +72,7 @@ static const struct fb_videomode modedb[] = {
0, FB_VMODE_NONINTERLACED
}, {
/* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */
- NULL, 69, 1152, 864, 15384, 96, 16, 110, 1, 216, 10,
+ NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10,
0, FB_VMODE_INTERLACED
}, {
/* 800x600 @ 72 Hz, 48.0 kHz hsync */
@@ -120,11 +120,11 @@ static const struct fb_videomode modedb[] = {
0, FB_VMODE_NONINTERLACED
}, {
/* 1400x1050 @ 60Hz, 63.9 kHz hsync */
- NULL, 68, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3,
+ 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, 9271, 120, 56, 13, 0, 112, 3,
+ 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*/
@@ -253,7 +253,7 @@ static const struct fb_videomode modedb[] = {
FB_VMODE_NONINTERLACED
}, {
/* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */
- NULL, 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6,
+ 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 */
@@ -306,7 +306,7 @@ const struct fb_videomode vesa_modes[] = {
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 12 1024x768i-43 VESA */
- { NULL, 53, 1024, 768, 22271, 56, 8, 41, 0, 176, 8,
+ { NULL, 43, 1024, 768, 22271, 56, 8, 41, 0, 176, 8,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_INTERLACED, FB_MODE_IS_VESA },
/* 13 1024x768-60 VESA */
@@ -383,7 +383,7 @@ const struct fb_videomode vesa_modes[] = {
{ NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
/* 33 1920x1440-75 VESA */
- { NULL, 60, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
+ { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
};
EXPORT_SYMBOL(vesa_modes);
@@ -510,7 +510,9 @@ int fb_find_mode(struct fb_var_screeninfo *var,
default_bpp = 8;
/* Did the user specify a video mode? */
- if (mode_option || (mode_option = global_mode_option)) {
+ if (!mode_option)
+ mode_option = fb_mode_option;
+ if (mode_option) {
const char *name = mode_option;
unsigned int namelen = strlen(name);
int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
@@ -606,26 +608,43 @@ done:
DPRINTK("Trying specified video mode%s %ix%i\n",
refresh_specified ? "" : " (ignoring refresh rate)", xres, yres);
- diff = refresh;
+ if (!refresh_specified) {
+ /*
+ * If the caller has provided a custom mode database and a
+ * valid monspecs structure, we look for the mode with the
+ * highest refresh rate. Otherwise we play it safe it and
+ * try to find a mode with a refresh rate closest to the
+ * standard 60 Hz.
+ */
+ if (db != modedb &&
+ info->monspecs.vfmin && info->monspecs.vfmax &&
+ info->monspecs.hfmin && info->monspecs.hfmax &&
+ info->monspecs.dclkmax) {
+ refresh = 1000;
+ } else {
+ refresh = 60;
+ }
+ }
+
+ diff = -1;
best = -1;
for (i = 0; i < dbsize; i++) {
- if (name_matches(db[i], name, namelen) ||
- (res_specified && res_matches(db[i], xres, yres))) {
- if(!fb_try_mode(var, info, &db[i], bpp)) {
- if(!refresh_specified || db[i].refresh == refresh)
- return 1;
- else {
- if(diff > abs(db[i].refresh - refresh)) {
- diff = abs(db[i].refresh - refresh);
- best = i;
- }
+ if ((name_matches(db[i], name, namelen) ||
+ (res_specified && res_matches(db[i], xres, yres))) &&
+ !fb_try_mode(var, info, &db[i], bpp)) {
+ if (refresh_specified && db[i].refresh == refresh) {
+ return 1;
+ } else {
+ if (abs(db[i].refresh - refresh) < diff) {
+ diff = abs(db[i].refresh - refresh);
+ best = i;
}
}
}
}
if (best != -1) {
fb_try_mode(var, info, &db[best], bpp);
- return 2;
+ return (refresh_specified) ? 2 : 1;
}
diff = xres + yres;
@@ -938,6 +957,7 @@ void fb_destroy_modelist(struct list_head *head)
kfree(pos);
}
}
+EXPORT_SYMBOL_GPL(fb_destroy_modelist);
/**
* fb_videomode_to_modelist: convert mode array to mode list
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index 731d7a5c5aa..4b6a99b5be0 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -72,7 +72,6 @@
#include <asm/irq.h>
#include <asm/pgtable.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c
index afe4567e1ff..6fd7cb8f9b8 100644
--- a/drivers/video/nvidia/nv_i2c.c
+++ b/drivers/video/nvidia/nv_i2c.c
@@ -125,11 +125,13 @@ void nvidia_create_i2c_busses(struct nvidia_par *par)
par->chan[1].par = par;
par->chan[2].par = par;
- par->chan[0].ddc_base = 0x36;
- nvidia_setup_i2c_bus(&par->chan[0], "nvidia #0", I2C_CLASS_HWMON);
+ par->chan[0].ddc_base = (par->reverse_i2c) ? 0x36 : 0x3e;
+ nvidia_setup_i2c_bus(&par->chan[0], "nvidia #0",
+ (par->reverse_i2c) ? I2C_CLASS_HWMON : 0);
- par->chan[1].ddc_base = 0x3e;
- nvidia_setup_i2c_bus(&par->chan[1], "nvidia #1", 0);
+ par->chan[1].ddc_base = (par->reverse_i2c) ? 0x3e : 0x36;
+ nvidia_setup_i2c_bus(&par->chan[1], "nvidia #1",
+ (par->reverse_i2c) ? 0 : I2C_CLASS_HWMON);
par->chan[2].ddc_base = 0x50;
nvidia_setup_i2c_bus(&par->chan[2], "nvidia #2", 0);
diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h
index 2fdf77ec39f..f132aab8c5d 100644
--- a/drivers/video/nvidia/nv_type.h
+++ b/drivers/video/nvidia/nv_type.h
@@ -135,6 +135,7 @@ struct nvidia_par {
int paneltweak;
int LVDS;
int pm_state;
+ int reverse_i2c;
u32 crtcSync_read;
u32 fpSyncs;
u32 dmaPut;
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index a7fe214f0f7..30e14eb1f51 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -79,6 +79,7 @@ static int noscale __devinitdata = 0;
static int paneltweak __devinitdata = 0;
static int vram __devinitdata = 0;
static int bpp __devinitdata = 8;
+static int reverse_i2c __devinitdata;
#ifdef CONFIG_MTRR
static int nomtrr __devinitdata = 0;
#endif
@@ -1305,6 +1306,7 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
par->CRTCnumber = forceCRTC;
par->FpScale = (!noscale);
par->paneltweak = paneltweak;
+ par->reverse_i2c = reverse_i2c;
/* enable IO and mem if not already done */
pci_read_config_word(pd, PCI_COMMAND, &cmd);
@@ -1486,6 +1488,8 @@ static int __devinit nvidiafb_setup(char *options)
noaccel = 1;
} else if (!strncmp(this_opt, "noscale", 7)) {
noscale = 1;
+ } else if (!strncmp(this_opt, "reverse_i2c", 11)) {
+ reverse_i2c = 1;
} else if (!strncmp(this_opt, "paneltweak:", 11)) {
paneltweak = simple_strtoul(this_opt+11, NULL, 0);
} else if (!strncmp(this_opt, "vram:", 5)) {
@@ -1582,6 +1586,8 @@ MODULE_PARM_DESC(mode_option, "Specify initial video mode");
module_param(bpp, int, 0);
MODULE_PARM_DESC(bpp, "pixel width in bits"
"(default=8)");
+module_param(reverse_i2c, int, 0);
+MODULE_PARM_DESC(reverse_i2c, "reverse port assignment of the i2c bus");
#ifdef CONFIG_MTRR
module_param(nomtrr, bool, 0);
MODULE_PARM_DESC(nomtrr, "Disables MTRR support (0 or 1=disabled) "
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
index 7f4d25b8a18..44408850e2e 100644
--- a/drivers/video/omap/Kconfig
+++ b/drivers/video/omap/Kconfig
@@ -1,6 +1,6 @@
config FB_OMAP
tristate "OMAP frame buffer support (EXPERIMENTAL)"
- depends on FB
+ depends on FB && ARCH_OMAP
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -8,7 +8,7 @@ config FB_OMAP
Frame buffer driver for OMAP based boards.
config FB_OMAP_BOOTLOADER_INIT
- bool "Check bootloader initializaion"
+ bool "Check bootloader initialization"
depends on FB_OMAP
help
Say Y here if you want to enable checking if the bootloader has
diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c
index e682940a97a..4d8ad9cd0e1 100644
--- a/drivers/video/omap/blizzard.c
+++ b/drivers/video/omap/blizzard.c
@@ -225,7 +225,7 @@ static void blizzard_restart_sdram(void)
while (!(blizzard_read_reg(BLIZZARD_MEM_BANK0_STATUS) & 0x01)) {
if (time_after(jiffies, tmo)) {
dev_err(blizzard.fbdev->dev,
- "s1d1374x: SDRAM not ready");
+ "s1d1374x: SDRAM not ready\n");
break;
}
msleep(1);
diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c
index f4c23434de6..ab32ceb0617 100644
--- a/drivers/video/omap/dispc.c
+++ b/drivers/video/omap/dispc.c
@@ -880,19 +880,19 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
static int get_dss_clocks(void)
{
if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) {
- dev_err(dispc.fbdev->dev, "can't get dss_ick");
+ dev_err(dispc.fbdev->dev, "can't get dss_ick\n");
return PTR_ERR(dispc.dss_ick);
}
if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) {
- dev_err(dispc.fbdev->dev, "can't get dss1_fck");
+ dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
clk_put(dispc.dss_ick);
return PTR_ERR(dispc.dss1_fck);
}
if (IS_ERR((dispc.dss_54m_fck =
clk_get(dispc.fbdev->dev, "dss_54m_fck")))) {
- dev_err(dispc.fbdev->dev, "can't get dss_54m_fck");
+ dev_err(dispc.fbdev->dev, "can't get dss_54m_fck\n");
clk_put(dispc.dss_ick);
clk_put(dispc.dss1_fck);
return PTR_ERR(dispc.dss_54m_fck);
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c
index dc48e02f215..1e642b7a20f 100644
--- a/drivers/video/omap/hwa742.c
+++ b/drivers/video/omap/hwa742.c
@@ -508,7 +508,7 @@ int hwa742_update_window_async(struct fb_info *fbi,
if (unlikely(win->format &
~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE |
OMAPFB_FORMAT_FLAG_TEARSYNC | OMAPFB_FORMAT_FLAG_FORCE_VSYNC))) {
- dev_dbg(hwa742.fbdev->dev, "invalid window flag");
+ dev_dbg(hwa742.fbdev->dev, "invalid window flag\n");
r = -EINVAL;
goto out;
}
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c
index 51807b4e26d..c604d935c18 100644
--- a/drivers/video/omap/lcd_h3.c
+++ b/drivers/video/omap/lcd_h3.c
@@ -28,8 +28,6 @@
#define MODULE_NAME "omapfb-lcd_h3"
-#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
-
static int h3_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
{
return 0;
@@ -48,7 +46,7 @@ static int h3_panel_enable(struct lcd_panel *panel)
if (!r)
r = tps65010_set_gpio_out_value(GPIO2, HIGH);
if (r)
- pr_err("Unable to turn on LCD panel\n");
+ pr_err(MODULE_NAME ": Unable to turn on LCD panel\n");
return r;
}
@@ -62,7 +60,7 @@ static void h3_panel_disable(struct lcd_panel *panel)
if (!r)
tps65010_set_gpio_out_value(GPIO2, LOW);
if (r)
- pr_err("Unable to turn off LCD panel\n");
+ pr_err(MODULE_NAME ": Unable to turn off LCD panel\n");
}
static unsigned long h3_panel_get_caps(struct lcd_panel *panel)
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c
index 95604ca4330..5ef119c813e 100644
--- a/drivers/video/omap/lcd_inn1610.c
+++ b/drivers/video/omap/lcd_inn1610.c
@@ -27,20 +27,18 @@
#define MODULE_NAME "omapfb-lcd_h3"
-#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
-
static int innovator1610_panel_init(struct lcd_panel *panel,
struct omapfb_device *fbdev)
{
int r = 0;
if (omap_request_gpio(14)) {
- pr_err("can't request GPIO 14\n");
+ pr_err(MODULE_NAME ": can't request GPIO 14\n");
r = -1;
goto exit;
}
if (omap_request_gpio(15)) {
- pr_err("can't request GPIO 15\n");
+ pr_err(MODULE_NAME ": can't request GPIO 15\n");
omap_free_gpio(14);
r = -1;
goto exit;
diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c
index 2b4269813b2..789cfd23c36 100644
--- a/drivers/video/omap/rfbi.c
+++ b/drivers/video/omap/rfbi.c
@@ -84,12 +84,12 @@ static inline u32 rfbi_read_reg(int idx)
static int rfbi_get_clocks(void)
{
if (IS_ERR((rfbi.dss_ick = clk_get(rfbi.fbdev->dev, "dss_ick")))) {
- dev_err(rfbi.fbdev->dev, "can't get dss_ick");
+ dev_err(rfbi.fbdev->dev, "can't get dss_ick\n");
return PTR_ERR(rfbi.dss_ick);
}
if (IS_ERR((rfbi.dss1_fck = clk_get(rfbi.fbdev->dev, "dss1_fck")))) {
- dev_err(rfbi.fbdev->dev, "can't get dss1_fck");
+ dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n");
clk_put(rfbi.dss_ick);
return PTR_ERR(rfbi.dss1_fck);
}
diff --git a/drivers/video/output.c b/drivers/video/output.c
index 1473f2c892d..f2df5519c9c 100644
--- a/drivers/video/output.c
+++ b/drivers/video/output.c
@@ -31,7 +31,8 @@ MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
-static ssize_t video_output_show_state(struct class_device *dev,char *buf)
+static ssize_t video_output_show_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
ssize_t ret_size = 0;
struct output_device *od = to_output_device(dev);
@@ -40,8 +41,9 @@ static ssize_t video_output_show_state(struct class_device *dev,char *buf)
return ret_size;
}
-static ssize_t video_output_store_state(struct class_device *dev,
- const char *buf,size_t count)
+static ssize_t video_output_store_state(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,size_t count)
{
char *endp;
struct output_device *od = to_output_device(dev);
@@ -60,21 +62,22 @@ static ssize_t video_output_store_state(struct class_device *dev,
return count;
}
-static void video_output_class_release(struct class_device *dev)
+static void video_output_release(struct device *dev)
{
struct output_device *od = to_output_device(dev);
kfree(od);
}
-static struct class_device_attribute video_output_attributes[] = {
+static struct device_attribute video_output_attributes[] = {
__ATTR(state, 0644, video_output_show_state, video_output_store_state),
__ATTR_NULL,
};
+
static struct class video_output_class = {
.name = "video_output",
- .release = video_output_class_release,
- .class_dev_attrs = video_output_attributes,
+ .dev_release = video_output_release,
+ .dev_attrs = video_output_attributes,
};
struct output_device *video_output_register(const char *name,
@@ -91,11 +94,11 @@ struct output_device *video_output_register(const char *name,
goto error_return;
}
new_dev->props = op;
- new_dev->class_dev.class = &video_output_class;
- new_dev->class_dev.dev = dev;
- strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN);
- class_set_devdata(&new_dev->class_dev,devdata);
- ret_code = class_device_register(&new_dev->class_dev);
+ new_dev->dev.class = &video_output_class;
+ new_dev->dev.parent = dev;
+ strlcpy(new_dev->dev.bus_id,name, BUS_ID_SIZE);
+ dev_set_drvdata(&new_dev->dev, devdata);
+ ret_code = device_register(&new_dev->dev);
if (ret_code) {
kfree(new_dev);
goto error_return;
@@ -111,7 +114,7 @@ void video_output_unregister(struct output_device *dev)
{
if (!dev)
return;
- class_device_unregister(&dev->class_dev);
+ device_unregister(&dev->dev);
}
EXPORT_SYMBOL(video_output_unregister);
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 8503e733a17..cbe71a5338d 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -17,6 +17,8 @@
* more details.
*/
+#undef DEBUG
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -535,33 +537,35 @@ static int __devinit platinumfb_probe(struct of_device* odev,
volatile __u8 *fbuffer;
int bank0, bank1, bank2, bank3, rc;
- printk(KERN_INFO "platinumfb: Found Apple Platinum video hardware\n");
+ dev_info(&odev->dev, "Found Apple Platinum video hardware\n");
info = framebuffer_alloc(sizeof(*pinfo), &odev->dev);
- if (info == NULL)
+ if (info == NULL) {
+ dev_err(&odev->dev, "Failed to allocate fbdev !\n");
return -ENOMEM;
+ }
pinfo = info->par;
if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) ||
of_address_to_resource(dp, 1, &pinfo->rsrc_fb)) {
- printk(KERN_ERR "platinumfb: Can't get resources\n");
- framebuffer_release(info);
- return -ENXIO;
- }
- if (!request_mem_region(pinfo->rsrc_reg.start,
- pinfo->rsrc_reg.start -
- pinfo->rsrc_reg.end + 1,
- "platinumfb registers")) {
+ dev_err(&odev->dev, "Can't get resources\n");
framebuffer_release(info);
return -ENXIO;
}
+ dev_dbg(&odev->dev, " registers : 0x%llx...0x%llx\n",
+ (unsigned long long)pinfo->rsrc_reg.start,
+ (unsigned long long)pinfo->rsrc_reg.end);
+ dev_dbg(&odev->dev, " framebuffer: 0x%llx...0x%llx\n",
+ (unsigned long long)pinfo->rsrc_fb.start,
+ (unsigned long long)pinfo->rsrc_fb.end);
+
+ /* Do not try to request register space, they overlap with the
+ * northbridge and that can fail. Only request framebuffer
+ */
if (!request_mem_region(pinfo->rsrc_fb.start,
- pinfo->rsrc_fb.start
- - pinfo->rsrc_fb.end + 1,
+ pinfo->rsrc_fb.end - pinfo->rsrc_fb.start + 1,
"platinumfb framebuffer")) {
- release_mem_region(pinfo->rsrc_reg.start,
- pinfo->rsrc_reg.end -
- pinfo->rsrc_reg.start + 1);
+ printk(KERN_ERR "platinumfb: Can't request framebuffer !\n");
framebuffer_release(info);
return -ENXIO;
}
@@ -600,7 +604,8 @@ static int __devinit platinumfb_probe(struct of_device* odev,
bank2 = fbuffer[0x200000] == 0x56;
bank3 = fbuffer[0x300000] == 0x78;
pinfo->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
- printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n", (int) (pinfo->total_vram / 1024 / 1024),
+ printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n",
+ (unsigned int) (pinfo->total_vram / 1024 / 1024),
bank3, bank2, bank1, bank0);
/*
@@ -644,16 +649,15 @@ static int __devexit platinumfb_remove(struct of_device* odev)
unregister_framebuffer (info);
/* Unmap frame buffer and registers */
+ iounmap(pinfo->frame_buffer);
+ iounmap(pinfo->platinum_regs);
+ iounmap(pinfo->cmap_regs);
+
release_mem_region(pinfo->rsrc_fb.start,
pinfo->rsrc_fb.end -
pinfo->rsrc_fb.start + 1);
- release_mem_region(pinfo->rsrc_reg.start,
- pinfo->rsrc_reg.end -
- pinfo->rsrc_reg.start + 1);
- iounmap(pinfo->frame_buffer);
- iounmap(pinfo->platinum_regs);
+
release_mem_region(pinfo->cmap_regs_phys, 0x1000);
- iounmap(pinfo->cmap_regs);
framebuffer_release(info);
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index 10c0cc6e93f..5591dfb22b1 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -11,7 +11,7 @@
* and additional input from James Simmon's port of Hannu Mallat's tdfx
* driver.
*
- * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I
+ * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I
* have no access to other pm2fb implementations. Sparc (and thus
* hopefully other big-endian) devices now work, thanks to a lot of
* testing work by Ron Murray. I have no access to CVision hardware,
@@ -38,6 +38,9 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
#include <video/permedia2.h>
#include <video/cvisionppc.h>
@@ -52,15 +55,19 @@
#undef PM2FB_MASTER_DEBUG
#ifdef PM2FB_MASTER_DEBUG
-#define DPRINTK(a,b...) printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)
+#define DPRINTK(a, b...) \
+ printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)
#else
-#define DPRINTK(a,b...)
+#define DPRINTK(a, b...)
#endif
+#define PM2_PIXMAP_SIZE (1600 * 4)
+
/*
* Driver data
*/
-static char *mode __devinitdata = NULL;
+static int hwcursor = 1;
+static char *mode __devinitdata;
/*
* The XFree GLINT driver will (I think to implement hardware cursor
@@ -73,6 +80,11 @@ static char *mode __devinitdata = NULL;
*/
static int lowhsync;
static int lowvsync;
+static int noaccel __devinitdata;
+/* mtrr option */
+#ifdef CONFIG_MTRR
+static int nomtrr __devinitdata;
+#endif
/*
* The hardware state of the graphics card that isn't part of the
@@ -88,6 +100,7 @@ struct pm2fb_par
u32 mem_control; /* MemControl reg at probe */
u32 boot_address; /* BootAddress reg at probe */
u32 palette[16];
+ int mtrr_handle;
};
/*
@@ -135,60 +148,39 @@ static struct fb_var_screeninfo pm2fb_var __devinitdata = {
* Utility functions
*/
-static inline u32 RD32(unsigned char __iomem *base, s32 off)
-{
- return fb_readl(base + off);
-}
-
-static inline void WR32(unsigned char __iomem *base, s32 off, u32 v)
+static inline u32 pm2_RD(struct pm2fb_par *p, s32 off)
{
- fb_writel(v, base + off);
+ return fb_readl(p->v_regs + off);
}
-static inline u32 pm2_RD(struct pm2fb_par* p, s32 off)
+static inline void pm2_WR(struct pm2fb_par *p, s32 off, u32 v)
{
- return RD32(p->v_regs, off);
+ fb_writel(v, p->v_regs + off);
}
-static inline void pm2_WR(struct pm2fb_par* p, s32 off, u32 v)
+static inline u32 pm2_RDAC_RD(struct pm2fb_par *p, s32 idx)
{
- WR32(p->v_regs, off, v);
+ pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
+ mb();
+ return pm2_RD(p, PM2R_RD_INDEXED_DATA);
}
-static inline u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx)
+static inline u32 pm2v_RDAC_RD(struct pm2fb_par *p, s32 idx)
{
- int index = PM2R_RD_INDEXED_DATA;
- switch (p->type) {
- case PM2_TYPE_PERMEDIA2:
- pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
- break;
- case PM2_TYPE_PERMEDIA2V:
- pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
- index = PM2VR_RD_INDEXED_DATA;
- break;
- }
+ pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
mb();
- return pm2_RD(p, index);
+ return pm2_RD(p, PM2VR_RD_INDEXED_DATA);
}
-static inline void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v)
+static inline void pm2_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v)
{
- int index = PM2R_RD_INDEXED_DATA;
- switch (p->type) {
- case PM2_TYPE_PERMEDIA2:
- pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
- break;
- case PM2_TYPE_PERMEDIA2V:
- pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
- index = PM2VR_RD_INDEXED_DATA;
- break;
- }
+ pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
wmb();
- pm2_WR(p, index, v);
+ pm2_WR(p, PM2R_RD_INDEXED_DATA, v);
wmb();
}
-static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v)
+static inline void pm2v_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v)
{
pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
wmb();
@@ -199,10 +191,10 @@ static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v)
#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
#define WAIT_FIFO(p, a)
#else
-static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a)
+static inline void WAIT_FIFO(struct pm2fb_par *p, u32 a)
{
- while( pm2_RD(p, PM2R_IN_FIFO_SPACE) < a );
- mb();
+ while (pm2_RD(p, PM2R_IN_FIFO_SPACE) < a)
+ cpu_relax();
}
#endif
@@ -238,7 +230,7 @@ static u32 partprod(u32 xres)
for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++)
;
- if ( pp_table[i].width == 0 )
+ if (pp_table[i].width == 0)
DPRINTK("invalid width %u\n", xres);
return pp_table[i].pp;
}
@@ -246,25 +238,22 @@ static u32 partprod(u32 xres)
static u32 to3264(u32 timing, int bpp, int is64)
{
switch (bpp) {
+ case 24:
+ timing *= 3;
case 8:
- timing >>= 2 + is64;
- break;
+ timing >>= 1;
case 16:
- timing >>= 1 + is64;
- break;
- case 24:
- timing = (timing * 3) >> (2 + is64);
- break;
+ timing >>= 1;
case 32:
- if (is64)
- timing >>= 1;
break;
}
+ if (is64)
+ timing >>= 1;
return timing;
}
-static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
- unsigned char* pp)
+static void pm2_mnp(u32 clk, unsigned char *mm, unsigned char *nn,
+ unsigned char *pp)
{
unsigned char m;
unsigned char n;
@@ -278,13 +267,13 @@ static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
for (m = 2; m; m++) {
f = PM2_REFERENCE_CLOCK * m / n;
if (f >= 150000 && f <= 300000) {
- for ( p = 0; p < 5; p++, f >>= 1) {
- curr = ( clk > f ) ? clk - f : f - clk;
- if ( curr < delta ) {
- delta=curr;
- *mm=m;
- *nn=n;
- *pp=p;
+ for (p = 0; p < 5; p++, f >>= 1) {
+ curr = (clk > f) ? clk - f : f - clk;
+ if (curr < delta) {
+ delta = curr;
+ *mm = m;
+ *nn = n;
+ *pp = p;
}
}
}
@@ -292,8 +281,8 @@ static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
}
}
-static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
- unsigned char* pp)
+static void pm2v_mnp(u32 clk, unsigned char *mm, unsigned char *nn,
+ unsigned char *pp)
{
unsigned char m;
unsigned char n;
@@ -302,23 +291,24 @@ static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
s32 delta = 1000;
*mm = *nn = *pp = 0;
- for ( m = 1; m < 128; m++) {
+ for (m = 1; m < 128; m++) {
for (n = 2 * m + 1; n; n++) {
- for ( p = 0; p < 2; p++) {
- f = ( PM2_REFERENCE_CLOCK >> ( p + 1 )) * n / m;
- if ( clk > f - delta && clk < f + delta ) {
- delta = ( clk > f ) ? clk - f : f - clk;
- *mm=m;
- *nn=n;
- *pp=p;
+ for (p = 0; p < 2; p++) {
+ f = (PM2_REFERENCE_CLOCK >> (p + 1)) * n / m;
+ if (clk > f - delta && clk < f + delta) {
+ delta = (clk > f) ? clk - f : f - clk;
+ *mm = m;
+ *nn = n;
+ *pp = p;
}
}
}
}
}
-static void clear_palette(struct pm2fb_par* p) {
- int i=256;
+static void clear_palette(struct pm2fb_par *p)
+{
+ int i = 256;
WAIT_FIFO(p, 1);
pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
@@ -331,14 +321,14 @@ static void clear_palette(struct pm2fb_par* p) {
}
}
-static void reset_card(struct pm2fb_par* p)
+static void reset_card(struct pm2fb_par *p)
{
if (p->type == PM2_TYPE_PERMEDIA2V)
pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
pm2_WR(p, PM2R_RESET_STATUS, 0);
mb();
while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET)
- ;
+ cpu_relax();
mb();
#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
DPRINTK("FIFO disconnect enabled\n");
@@ -354,11 +344,11 @@ static void reset_card(struct pm2fb_par* p)
pm2_WR(p, PM2R_MEM_CONFIG, p->mem_config);
}
-static void reset_config(struct pm2fb_par* p)
+static void reset_config(struct pm2fb_par *p)
{
- WAIT_FIFO(p, 52);
+ WAIT_FIFO(p, 53);
pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG) &
- ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED));
+ ~(PM2F_VGA_ENABLE | PM2F_VGA_FIXED));
pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
pm2_WR(p, PM2R_FIFO_CONTROL, 0);
@@ -393,31 +383,32 @@ static void reset_config(struct pm2fb_par* p)
pm2_WR(p, PM2R_STATISTICS_MODE, 0);
pm2_WR(p, PM2R_SCISSOR_MODE, 0);
pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
+ pm2_WR(p, PM2R_RD_PIXEL_MASK, 0xff);
switch (p->type) {
case PM2_TYPE_PERMEDIA2:
pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
+ pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
+ pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
+ pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
+ pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
+ pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
break;
case PM2_TYPE_PERMEDIA2V:
pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */
break;
}
- pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
- pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
- pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
- pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
- pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
}
-static void set_aperture(struct pm2fb_par* p, u32 depth)
+static void set_aperture(struct pm2fb_par *p, u32 depth)
{
/*
* The hardware is little-endian. When used in big-endian
* hosts, the on-chip aperture settings are used where
* possible to translate from host to card byte order.
*/
- WAIT_FIFO(p, 4);
+ WAIT_FIFO(p, 2);
#ifdef __LITTLE_ENDIAN
pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD);
#else
@@ -440,11 +431,11 @@ static void set_aperture(struct pm2fb_par* p, u32 depth)
}
#endif
- // We don't use aperture two, so this may be superflous
+ /* We don't use aperture two, so this may be superflous */
pm2_WR(p, PM2R_APERTURE_TWO, PM2F_APERTURE_STANDARD);
}
-static void set_color(struct pm2fb_par* p, unsigned char regno,
+static void set_color(struct pm2fb_par *p, unsigned char regno,
unsigned char r, unsigned char g, unsigned char b)
{
WAIT_FIFO(p, 4);
@@ -457,7 +448,7 @@ static void set_color(struct pm2fb_par* p, unsigned char regno,
pm2_WR(p, PM2R_RD_PALETTE_DATA, b);
}
-static void set_memclock(struct pm2fb_par* par, u32 clk)
+static void set_memclock(struct pm2fb_par *par, u32 clk)
{
int i;
unsigned char m, n, p;
@@ -465,7 +456,7 @@ static void set_memclock(struct pm2fb_par* par, u32 clk)
switch (par->type) {
case PM2_TYPE_PERMEDIA2V:
pm2v_mnp(clk/2, &m, &n, &p);
- WAIT_FIFO(par, 8);
+ WAIT_FIFO(par, 12);
pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8);
pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0);
pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m);
@@ -473,10 +464,9 @@ static void set_memclock(struct pm2fb_par* par, u32 clk)
pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p);
pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1);
rmb();
- for (i = 256;
- i && !(pm2_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2);
- i--)
- ;
+ for (i = 256; i; i--)
+ if (pm2v_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2)
+ break;
pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
break;
case PM2_TYPE_PERMEDIA2:
@@ -488,15 +478,14 @@ static void set_memclock(struct pm2fb_par* par, u32 clk)
pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p);
pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS);
rmb();
- for (i = 256;
- i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED);
- i--)
- ;
+ for (i = 256; i; i--)
+ if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED)
+ break;
break;
}
}
-static void set_pixclock(struct pm2fb_par* par, u32 clk)
+static void set_pixclock(struct pm2fb_par *par, u32 clk)
{
int i;
unsigned char m, n, p;
@@ -504,17 +493,16 @@ static void set_pixclock(struct pm2fb_par* par, u32 clk)
switch (par->type) {
case PM2_TYPE_PERMEDIA2:
pm2_mnp(clk, &m, &n, &p);
- WAIT_FIFO(par, 8);
+ WAIT_FIFO(par, 10);
pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0);
pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m);
pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n);
pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS);
rmb();
- for (i = 256;
- i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED);
- i--)
- ;
+ for (i = 256; i; i--)
+ if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED)
+ break;
break;
case PM2_TYPE_PERMEDIA2V:
pm2v_mnp(clk/2, &m, &n, &p);
@@ -528,11 +516,10 @@ static void set_pixclock(struct pm2fb_par* par, u32 clk)
}
}
-static void set_video(struct pm2fb_par* p, u32 video) {
+static void set_video(struct pm2fb_par *p, u32 video)
+{
u32 tmp;
- u32 vsync;
-
- vsync = video;
+ u32 vsync = video;
DPRINTK("video = 0x%x\n", video);
@@ -542,10 +529,10 @@ static void set_video(struct pm2fb_par* p, u32 video) {
* driver may well. So always set +hsync/+vsync and then set
* the RAMDAC to invert the sync if necessary.
*/
- vsync &= ~(PM2F_HSYNC_MASK|PM2F_VSYNC_MASK);
- vsync |= PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH;
+ vsync &= ~(PM2F_HSYNC_MASK | PM2F_VSYNC_MASK);
+ vsync |= PM2F_HSYNC_ACT_HIGH | PM2F_VSYNC_ACT_HIGH;
- WAIT_FIFO(p, 5);
+ WAIT_FIFO(p, 3);
pm2_WR(p, PM2R_VIDEO_CONTROL, vsync);
switch (p->type) {
@@ -564,16 +551,11 @@ static void set_video(struct pm2fb_par* p, u32 video) {
if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
tmp |= 4; /* invert vsync */
pm2v_RDAC_WR(p, PM2VI_RD_SYNC_CONTROL, tmp);
- pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1);
break;
}
}
/*
- *
- */
-
-/**
* pm2fb_check_var - Optional function. Validates a var passed in.
* @var: frame buffer variable screen structure
* @info: frame buffer structure that represents a single frame buffer
@@ -594,15 +576,22 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
}
if (var->xres != var->xres_virtual) {
- DPRINTK("virtual x resolution != physical x resolution not supported\n");
+ DPRINTK("virtual x resolution != "
+ "physical x resolution not supported\n");
return -EINVAL;
}
if (var->yres > var->yres_virtual) {
- DPRINTK("virtual y resolution < physical y resolution not possible\n");
+ DPRINTK("virtual y resolution < "
+ "physical y resolution not possible\n");
return -EINVAL;
}
+ /* permedia cannot blit over 2048 */
+ if (var->yres_virtual > 2047) {
+ var->yres_virtual = 2047;
+ }
+
if (var->xoffset) {
DPRINTK("xoffset not supported\n");
return -EINVAL;
@@ -614,7 +603,7 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
}
var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
- lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
+ lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
if (var->xres < 320 || var->xres > 1600) {
DPRINTK("width not supported: %u\n", var->xres);
@@ -633,15 +622,18 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
}
if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) {
- DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock));
+ DPRINTK("pixclock too high (%ldKHz)\n",
+ PICOS2KHZ(var->pixclock));
return -EINVAL;
}
var->transp.offset = 0;
var->transp.length = 0;
- switch(var->bits_per_pixel) {
+ switch (var->bits_per_pixel) {
case 8:
- var->red.length = var->green.length = var->blue.length = 8;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
break;
case 16:
var->red.offset = 11;
@@ -657,7 +649,9 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->red.offset = 16;
var->green.offset = 8;
var->blue.offset = 0;
- var->red.length = var->green.length = var->blue.length = 8;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
break;
case 24:
#ifdef __BIG_ENDIAN
@@ -668,10 +662,13 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->blue.offset = 0;
#endif
var->green.offset = 8;
- var->red.length = var->green.length = var->blue.length = 8;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
break;
}
- var->height = var->width = -1;
+ var->height = -1;
+ var->width = -1;
var->accel_flags = 0; /* Can't mmap if this is on */
@@ -691,7 +688,9 @@ static int pm2fb_set_par(struct fb_info *info)
{
struct pm2fb_par *par = info->par;
u32 pixclock;
- u32 width, height, depth;
+ u32 width = (info->var.xres_virtual + 7) & ~7;
+ u32 height = info->var.yres_virtual;
+ u32 depth = (info->var.bits_per_pixel + 7) & ~7;
u32 hsstart, hsend, hbend, htotal;
u32 vsstart, vsend, vbend, vtotal;
u32 stride;
@@ -701,22 +700,19 @@ static int pm2fb_set_par(struct fb_info *info)
u32 txtmap = 0;
u32 pixsize = 0;
u32 clrformat = 0;
- u32 xres;
+ u32 misc = 1; /* 8-bit DAC */
+ u32 xres = (info->var.xres + 31) & ~31;
int data64;
reset_card(par);
reset_config(par);
clear_palette(par);
- if ( par->memclock )
+ if (par->memclock)
set_memclock(par, par->memclock);
- width = (info->var.xres_virtual + 7) & ~7;
- height = info->var.yres_virtual;
- depth = (info->var.bits_per_pixel + 7) & ~7;
depth = (depth > 32) ? 32 : depth;
data64 = depth > 8 || par->type == PM2_TYPE_PERMEDIA2V;
- xres = (info->var.xres + 31) & ~31;
pixclock = PICOS2KHZ(info->var.pixclock);
if (pixclock > PM2_MAX_PIXCLOCK) {
DPRINTK("pixclock too high (%uKHz)\n", pixclock);
@@ -731,7 +727,8 @@ static int pm2fb_set_par(struct fb_info *info)
? info->var.lower_margin - 1
: 0; /* FIXME! */
vsend = info->var.lower_margin + info->var.vsync_len - 1;
- vbend = info->var.lower_margin + info->var.vsync_len + info->var.upper_margin;
+ vbend = info->var.lower_margin + info->var.vsync_len +
+ info->var.upper_margin;
vtotal = info->var.yres + vbend - 1;
stride = to3264(width, depth, 1);
base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1);
@@ -744,25 +741,25 @@ static int pm2fb_set_par(struct fb_info *info)
video |= PM2F_HSYNC_ACT_LOW;
} else
video |= PM2F_HSYNC_ACT_HIGH;
- }
- else
+ } else
video |= PM2F_HSYNC_ACT_LOW;
+
if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) {
if (lowvsync) {
DPRINTK("ignoring +vsync, using -vsync.\n");
video |= PM2F_VSYNC_ACT_LOW;
} else
video |= PM2F_VSYNC_ACT_HIGH;
- }
- else
+ } else
video |= PM2F_VSYNC_ACT_LOW;
- if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) {
+
+ if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
DPRINTK("interlaced not supported\n");
return -EINVAL;
}
- if ((info->var.vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE)
+ if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
video |= PM2F_LINE_DOUBLE;
- if ((info->var.activate & FB_ACTIVATE_MASK)==FB_ACTIVATE_NOW)
+ if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
video |= PM2F_VIDEO_ENABLE;
par->video = video;
@@ -783,12 +780,10 @@ static int pm2fb_set_par(struct fb_info *info)
mb();
WAIT_FIFO(par, 19);
- pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL,
- ( depth == 8 ) ? 0 : PM2F_COLOR_KEY_TEST_OFF);
switch (depth) {
case 8:
pm2_WR(par, PM2R_FB_READ_PIXEL, 0);
- clrformat = 0x0e;
+ clrformat = 0x2e;
break;
case 16:
pm2_WR(par, PM2R_FB_READ_PIXEL, 1);
@@ -796,6 +791,7 @@ static int pm2fb_set_par(struct fb_info *info)
txtmap = PM2F_TEXTEL_SIZE_16;
pixsize = 1;
clrformat = 0x70;
+ misc |= 8;
break;
case 32:
pm2_WR(par, PM2R_FB_READ_PIXEL, 2);
@@ -803,6 +799,7 @@ static int pm2fb_set_par(struct fb_info *info)
txtmap = PM2F_TEXTEL_SIZE_32;
pixsize = 2;
clrformat = 0x20;
+ misc |= 8;
break;
case 24:
pm2_WR(par, PM2R_FB_READ_PIXEL, 4);
@@ -810,6 +807,7 @@ static int pm2fb_set_par(struct fb_info *info)
txtmap = PM2F_TEXTEL_SIZE_24;
pixsize = 4;
clrformat = 0x20;
+ misc |= 8;
break;
}
pm2_WR(par, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE);
@@ -834,14 +832,19 @@ static int pm2fb_set_par(struct fb_info *info)
pm2_WR(par, PM2R_SCREEN_BASE, base);
wmb();
set_video(par, video);
- WAIT_FIFO(par, 4);
+ WAIT_FIFO(par, 10);
switch (par->type) {
case PM2_TYPE_PERMEDIA2:
pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, clrmode);
+ pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL,
+ (depth == 8) ? 0 : PM2F_COLOR_KEY_TEST_OFF);
break;
case PM2_TYPE_PERMEDIA2V:
+ pm2v_RDAC_WR(par, PM2VI_RD_DAC_CONTROL, 0);
pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize);
pm2v_RDAC_WR(par, PM2VI_RD_COLOR_FORMAT, clrformat);
+ pm2v_RDAC_WR(par, PM2VI_RD_MISC_CONTROL, misc);
+ pm2v_RDAC_WR(par, PM2VI_RD_OVERLAY_KEY, 0);
break;
}
set_pixclock(par, pixclock);
@@ -872,16 +875,15 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
struct pm2fb_par *par = info->par;
if (regno >= info->cmap.len) /* no. of hw registers */
- return 1;
+ return -EINVAL;
/*
* Program hardware... do anything you want with transp
*/
/* grayscale works only partially under directcolor */
- if (info->var.grayscale) {
- /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ if (info->var.grayscale)
red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
- }
/* Directcolor:
* var->{color}.offset contains start of bitfield
@@ -931,7 +933,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
u32 v;
if (regno >= 16)
- return 1;
+ return -EINVAL;
v = (red << info->var.red.offset) |
(green << info->var.green.offset) |
@@ -948,8 +950,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
break;
}
return 0;
- }
- else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
+ } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
set_color(par, regno, red, green, blue);
return 0;
@@ -972,11 +973,9 @@ static int pm2fb_pan_display(struct fb_var_screeninfo *var,
{
struct pm2fb_par *p = info->par;
u32 base;
- u32 depth;
- u32 xres;
+ u32 depth = (var->bits_per_pixel + 7) & ~7;
+ u32 xres = (var->xres + 31) & ~31;
- xres = (var->xres + 31) & ~31;
- depth = (var->bits_per_pixel + 7) & ~7;
depth = (depth > 32) ? 32 : depth;
base = to3264(var->yoffset * xres + var->xoffset, depth, 1);
WAIT_FIFO(p, 1);
@@ -1018,15 +1017,15 @@ static int pm2fb_blank(int blank_mode, struct fb_info *info)
break;
case FB_BLANK_VSYNC_SUSPEND:
/* VSync: Off */
- video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW );
+ video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW);
break;
case FB_BLANK_HSYNC_SUSPEND:
/* HSync: Off */
- video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW );
+ video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW);
break;
case FB_BLANK_POWERDOWN:
/* HSync: Off, VSync: Off */
- video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK| PM2F_BLANK_LOW);
+ video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK | PM2F_BLANK_LOW);
break;
}
set_video(par, video);
@@ -1042,48 +1041,20 @@ static int pm2fb_sync(struct fb_info *info)
mb();
do {
while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0)
- udelay(10);
- rmb();
+ cpu_relax();
} while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
return 0;
}
-/*
- * block operation. copy=0: rectangle fill, copy=1: rectangle copy.
- */
-static void pm2fb_block_op(struct fb_info* info, int copy,
- s32 xsrc, s32 ysrc,
- s32 x, s32 y, s32 w, s32 h,
- u32 color) {
- struct pm2fb_par *par = info->par;
-
- if (!w || !h)
- return;
- WAIT_FIFO(par, 5);
- pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE |
- PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
- if (copy)
- pm2_WR(par, PM2R_FB_SOURCE_DELTA,
- ((ysrc-y) & 0xfff) << 16 | ((xsrc-x) & 0xfff));
- else
- pm2_WR(par, PM2R_FB_BLOCK_COLOR, color);
- pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (y << 16) | x);
- pm2_WR(par, PM2R_RECTANGLE_SIZE, (h << 16) | w);
- wmb();
- pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE |
- (x<xsrc ? PM2F_INCREASE_X : 0) |
- (y<ysrc ? PM2F_INCREASE_Y : 0) |
- (copy ? 0 : PM2F_RENDER_FASTFILL));
-}
-
-static void pm2fb_fillrect (struct fb_info *info,
+static void pm2fb_fillrect(struct fb_info *info,
const struct fb_fillrect *region)
{
+ struct pm2fb_par *par = info->par;
struct fb_fillrect modded;
int vxres, vyres;
u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
- ((u32*)info->pseudo_palette)[region->color] : region->color;
+ ((u32 *)info->pseudo_palette)[region->color] : region->color;
if (info->state != FBINFO_STATE_RUNNING)
return;
@@ -1098,31 +1069,46 @@ static void pm2fb_fillrect (struct fb_info *info,
memcpy(&modded, region, sizeof(struct fb_fillrect));
- if(!modded.width || !modded.height ||
- modded.dx >= vxres || modded.dy >= vyres)
+ if (!modded.width || !modded.height ||
+ modded.dx >= vxres || modded.dy >= vyres)
return;
- if(modded.dx + modded.width > vxres)
+ if (modded.dx + modded.width > vxres)
modded.width = vxres - modded.dx;
- if(modded.dy + modded.height > vyres)
+ if (modded.dy + modded.height > vyres)
modded.height = vyres - modded.dy;
- if(info->var.bits_per_pixel == 8)
+ if (info->var.bits_per_pixel == 8)
color |= color << 8;
- if(info->var.bits_per_pixel <= 16)
+ if (info->var.bits_per_pixel <= 16)
color |= color << 16;
- if(info->var.bits_per_pixel != 24)
- pm2fb_block_op(info, 0, 0, 0,
- modded.dx, modded.dy,
- modded.width, modded.height, color);
- else
- cfb_fillrect(info, region);
+ WAIT_FIFO(par, 3);
+ pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE);
+ pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx);
+ pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width);
+ if (info->var.bits_per_pixel != 24) {
+ WAIT_FIFO(par, 2);
+ pm2_WR(par, PM2R_FB_BLOCK_COLOR, color);
+ wmb();
+ pm2_WR(par, PM2R_RENDER,
+ PM2F_RENDER_RECTANGLE | PM2F_RENDER_FASTFILL);
+ } else {
+ WAIT_FIFO(par, 4);
+ pm2_WR(par, PM2R_COLOR_DDA_MODE, 1);
+ pm2_WR(par, PM2R_CONSTANT_COLOR, color);
+ wmb();
+ pm2_WR(par, PM2R_RENDER,
+ PM2F_RENDER_RECTANGLE |
+ PM2F_INCREASE_X | PM2F_INCREASE_Y );
+ pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
+ }
}
static void pm2fb_copyarea(struct fb_info *info,
const struct fb_copyarea *area)
{
+ struct pm2fb_par *par = info->par;
struct fb_copyarea modded;
u32 vxres, vyres;
@@ -1138,23 +1124,359 @@ static void pm2fb_copyarea(struct fb_info *info,
vxres = info->var.xres_virtual;
vyres = info->var.yres_virtual;
- if(!modded.width || !modded.height ||
- modded.sx >= vxres || modded.sy >= vyres ||
- modded.dx >= vxres || modded.dy >= vyres)
+ if (!modded.width || !modded.height ||
+ modded.sx >= vxres || modded.sy >= vyres ||
+ modded.dx >= vxres || modded.dy >= vyres)
return;
- if(modded.sx + modded.width > vxres)
+ if (modded.sx + modded.width > vxres)
modded.width = vxres - modded.sx;
- if(modded.dx + modded.width > vxres)
+ if (modded.dx + modded.width > vxres)
modded.width = vxres - modded.dx;
- if(modded.sy + modded.height > vyres)
+ if (modded.sy + modded.height > vyres)
modded.height = vyres - modded.sy;
- if(modded.dy + modded.height > vyres)
+ if (modded.dy + modded.height > vyres)
modded.height = vyres - modded.dy;
- pm2fb_block_op(info, 1, modded.sx, modded.sy,
- modded.dx, modded.dy,
- modded.width, modded.height, 0);
+ WAIT_FIFO(par, 5);
+ pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE |
+ PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
+ pm2_WR(par, PM2R_FB_SOURCE_DELTA,
+ ((modded.sy - modded.dy) & 0xfff) << 16 |
+ ((modded.sx - modded.dx) & 0xfff));
+ pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx);
+ pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width);
+ wmb();
+ pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE |
+ (modded.dx < modded.sx ? PM2F_INCREASE_X : 0) |
+ (modded.dy < modded.sy ? PM2F_INCREASE_Y : 0));
+}
+
+static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ struct pm2fb_par *par = info->par;
+ u32 height = image->height;
+ u32 fgx, bgx;
+ const u32 *src = (const u32 *)image->data;
+ u32 xres = (info->var.xres + 31) & ~31;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
+ if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1) {
+ cfb_imageblit(info, image);
+ return;
+ }
+ switch (info->fix.visual) {
+ case FB_VISUAL_PSEUDOCOLOR:
+ fgx = image->fg_color;
+ bgx = image->bg_color;
+ break;
+ case FB_VISUAL_TRUECOLOR:
+ default:
+ fgx = par->palette[image->fg_color];
+ bgx = par->palette[image->bg_color];
+ break;
+ }
+ if (info->var.bits_per_pixel == 8) {
+ fgx |= fgx << 8;
+ bgx |= bgx << 8;
+ }
+ if (info->var.bits_per_pixel <= 16) {
+ fgx |= fgx << 16;
+ bgx |= bgx << 16;
+ }
+
+ WAIT_FIFO(par, 13);
+ pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres));
+ pm2_WR(par, PM2R_SCISSOR_MIN_XY,
+ ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff));
+ pm2_WR(par, PM2R_SCISSOR_MAX_XY,
+ (((image->dy + image->height) & 0x0fff) << 16) |
+ ((image->dx + image->width) & 0x0fff));
+ pm2_WR(par, PM2R_SCISSOR_MODE, 1);
+ /* GXcopy & UNIT_ENABLE */
+ pm2_WR(par, PM2R_LOGICAL_OP_MODE, (0x3 << 1) | 1);
+ pm2_WR(par, PM2R_RECTANGLE_ORIGIN,
+ ((image->dy & 0xfff) << 16) | (image->dx & 0x0fff));
+ pm2_WR(par, PM2R_RECTANGLE_SIZE,
+ ((image->height & 0x0fff) << 16) |
+ ((image->width) & 0x0fff));
+ if (info->var.bits_per_pixel == 24) {
+ pm2_WR(par, PM2R_COLOR_DDA_MODE, 1);
+ /* clear area */
+ pm2_WR(par, PM2R_CONSTANT_COLOR, bgx);
+ pm2_WR(par, PM2R_RENDER,
+ PM2F_RENDER_RECTANGLE |
+ PM2F_INCREASE_X | PM2F_INCREASE_Y);
+ /* BitMapPackEachScanline & invert bits and byte order*/
+ /* force background */
+ pm2_WR(par, PM2R_RASTERIZER_MODE, (1 << 9) | 1 | (3 << 7));
+ pm2_WR(par, PM2R_CONSTANT_COLOR, fgx);
+ pm2_WR(par, PM2R_RENDER,
+ PM2F_RENDER_RECTANGLE |
+ PM2F_INCREASE_X | PM2F_INCREASE_Y |
+ PM2F_RENDER_SYNC_ON_BIT_MASK);
+ } else {
+ pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
+ /* clear area */
+ pm2_WR(par, PM2R_FB_BLOCK_COLOR, bgx);
+ pm2_WR(par, PM2R_RENDER,
+ PM2F_RENDER_RECTANGLE |
+ PM2F_RENDER_FASTFILL |
+ PM2F_INCREASE_X | PM2F_INCREASE_Y);
+ /* invert bits and byte order*/
+ pm2_WR(par, PM2R_RASTERIZER_MODE, 1 | (3 << 7));
+ pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx);
+ pm2_WR(par, PM2R_RENDER,
+ PM2F_RENDER_RECTANGLE |
+ PM2F_INCREASE_X | PM2F_INCREASE_Y |
+ PM2F_RENDER_FASTFILL |
+ PM2F_RENDER_SYNC_ON_BIT_MASK);
+ }
+
+ while (height--) {
+ int width = ((image->width + 7) >> 3)
+ + info->pixmap.scan_align - 1;
+ width >>= 2;
+ WAIT_FIFO(par, width);
+ while (width--) {
+ pm2_WR(par, PM2R_BIT_MASK_PATTERN, *src);
+ src++;
+ }
+ }
+ WAIT_FIFO(par, 3);
+ pm2_WR(par, PM2R_RASTERIZER_MODE, 0);
+ pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
+ pm2_WR(par, PM2R_SCISSOR_MODE, 0);
+}
+
+/*
+ * Hardware cursor support.
+ */
+static const u8 cursor_bits_lookup[16] = {
+ 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
+ 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
+};
+
+static int pm2vfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ struct pm2fb_par *par = info->par;
+ u8 mode = PM2F_CURSORMODE_TYPE_X;
+ int x = cursor->image.dx - info->var.xoffset;
+ int y = cursor->image.dy - info->var.yoffset;
+
+ if (cursor->enable)
+ mode |= PM2F_CURSORMODE_CURSOR_ENABLE;
+
+ pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_MODE, mode);
+
+ if (!cursor->enable)
+ x = 2047; /* push it outside display */
+ pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
+ pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0xf);
+ pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_LOW, y & 0xff);
+ pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HIGH, (y >> 8) & 0xf);
+
+ /*
+ * If the cursor is not be changed this means either we want the
+ * current cursor state (if enable is set) or we want to query what
+ * we can do with the cursor (if enable is not set)
+ */
+ if (!cursor->set)
+ return 0;
+
+ if (cursor->set & FB_CUR_SETHOT) {
+ pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HOT,
+ cursor->hot.x & 0x3f);
+ pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HOT,
+ cursor->hot.y & 0x3f);
+ }
+
+ if (cursor->set & FB_CUR_SETCMAP) {
+ u32 fg_idx = cursor->image.fg_color;
+ u32 bg_idx = cursor->image.bg_color;
+ struct fb_cmap cmap = info->cmap;
+
+ /* the X11 driver says one should use these color registers */
+ pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8);
+ pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 0,
+ cmap.red[bg_idx] >> 8 );
+ pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 1,
+ cmap.green[bg_idx] >> 8 );
+ pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 2,
+ cmap.blue[bg_idx] >> 8 );
+
+ pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 3,
+ cmap.red[fg_idx] >> 8 );
+ pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 4,
+ cmap.green[fg_idx] >> 8 );
+ pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 5,
+ cmap.blue[fg_idx] >> 8 );
+ pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
+ }
+
+ if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
+ u8 *bitmap = (u8 *)cursor->image.data;
+ u8 *mask = (u8 *)cursor->mask;
+ int i;
+ int pos = PM2VI_RD_CURSOR_PATTERN;
+
+ for (i = 0; i < cursor->image.height; i++) {
+ int j = (cursor->image.width + 7) >> 3;
+ int k = 8 - j;
+
+ pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8);
+
+ for (; j > 0; j--) {
+ u8 data = *bitmap ^ *mask;
+
+ if (cursor->rop == ROP_COPY)
+ data = *mask & *bitmap;
+ /* Upper 4 bits of bitmap data */
+ pm2v_RDAC_WR(par, pos++,
+ cursor_bits_lookup[data >> 4] |
+ (cursor_bits_lookup[*mask >> 4] << 1));
+ /* Lower 4 bits of bitmap */
+ pm2v_RDAC_WR(par, pos++,
+ cursor_bits_lookup[data & 0xf] |
+ (cursor_bits_lookup[*mask & 0xf] << 1));
+ bitmap++;
+ mask++;
+ }
+ for (; k > 0; k--) {
+ pm2v_RDAC_WR(par, pos++, 0);
+ pm2v_RDAC_WR(par, pos++, 0);
+ }
+ }
+
+ while (pos < (1024 + PM2VI_RD_CURSOR_PATTERN)) {
+ pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8);
+ pm2v_RDAC_WR(par, pos++, 0);
+ }
+
+ pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
+ }
+ return 0;
+}
+
+static int pm2fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ struct pm2fb_par *par = info->par;
+ u8 mode;
+
+ if (!hwcursor)
+ return -EINVAL; /* just to force soft_cursor() call */
+
+ /* Too large of a cursor or wrong bpp :-( */
+ if (cursor->image.width > 64 ||
+ cursor->image.height > 64 ||
+ cursor->image.depth > 1)
+ return -EINVAL;
+
+ if (par->type == PM2_TYPE_PERMEDIA2V)
+ return pm2vfb_cursor(info, cursor);
+
+ mode = 0x40;
+ if (cursor->enable)
+ mode = 0x43;
+
+ pm2_RDAC_WR(par, PM2I_RD_CURSOR_CONTROL, mode);
+
+ /*
+ * If the cursor is not be changed this means either we want the
+ * current cursor state (if enable is set) or we want to query what
+ * we can do with the cursor (if enable is not set)
+ */
+ if (!cursor->set)
+ return 0;
+
+ if (cursor->set & FB_CUR_SETPOS) {
+ int x = cursor->image.dx - info->var.xoffset + 63;
+ int y = cursor->image.dy - info->var.yoffset + 63;
+
+ WAIT_FIFO(par, 4);
+ pm2_WR(par, PM2R_RD_CURSOR_X_LSB, x & 0xff);
+ pm2_WR(par, PM2R_RD_CURSOR_X_MSB, (x >> 8) & 0x7);
+ pm2_WR(par, PM2R_RD_CURSOR_Y_LSB, y & 0xff);
+ pm2_WR(par, PM2R_RD_CURSOR_Y_MSB, (y >> 8) & 0x7);
+ }
+
+ if (cursor->set & FB_CUR_SETCMAP) {
+ u32 fg_idx = cursor->image.fg_color;
+ u32 bg_idx = cursor->image.bg_color;
+
+ WAIT_FIFO(par, 7);
+ pm2_WR(par, PM2R_RD_CURSOR_COLOR_ADDRESS, 1);
+ pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
+ info->cmap.red[bg_idx] >> 8);
+ pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
+ info->cmap.green[bg_idx] >> 8);
+ pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
+ info->cmap.blue[bg_idx] >> 8);
+
+ pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
+ info->cmap.red[fg_idx] >> 8);
+ pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
+ info->cmap.green[fg_idx] >> 8);
+ pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
+ info->cmap.blue[fg_idx] >> 8);
+ }
+
+ if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
+ u8 *bitmap = (u8 *)cursor->image.data;
+ u8 *mask = (u8 *)cursor->mask;
+ int i;
+
+ WAIT_FIFO(par, 1);
+ pm2_WR(par, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
+
+ for (i = 0; i < cursor->image.height; i++) {
+ int j = (cursor->image.width + 7) >> 3;
+ int k = 8 - j;
+
+ WAIT_FIFO(par, 8);
+ for (; j > 0; j--) {
+ u8 data = *bitmap ^ *mask;
+
+ if (cursor->rop == ROP_COPY)
+ data = *mask & *bitmap;
+ /* bitmap data */
+ pm2_WR(par, PM2R_RD_CURSOR_DATA, data);
+ bitmap++;
+ mask++;
+ }
+ for (; k > 0; k--)
+ pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
+ }
+ for (; i < 64; i++) {
+ int j = 8;
+ WAIT_FIFO(par, 8);
+ while (j-- > 0)
+ pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
+ }
+
+ mask = (u8 *)cursor->mask;
+ for (i = 0; i < cursor->image.height; i++) {
+ int j = (cursor->image.width + 7) >> 3;
+ int k = 8 - j;
+
+ WAIT_FIFO(par, 8);
+ for (; j > 0; j--) {
+ /* mask */
+ pm2_WR(par, PM2R_RD_CURSOR_DATA, *mask);
+ mask++;
+ }
+ for (; k > 0; k--)
+ pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
+ }
+ for (; i < 64; i++) {
+ int j = 8;
+ WAIT_FIFO(par, 8);
+ while (j-- > 0)
+ pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
+ }
+ }
+ return 0;
}
/* ------------ Hardware Independent Functions ------------ */
@@ -1172,8 +1494,9 @@ static struct fb_ops pm2fb_ops = {
.fb_pan_display = pm2fb_pan_display,
.fb_fillrect = pm2fb_fillrect,
.fb_copyarea = pm2fb_copyarea,
- .fb_imageblit = cfb_imageblit,
+ .fb_imageblit = pm2fb_imageblit,
.fb_sync = pm2fb_sync,
+ .fb_cursor = pm2fb_cursor,
};
/*
@@ -1194,16 +1517,17 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
{
struct pm2fb_par *default_par;
struct fb_info *info;
- int err, err_retval = -ENXIO;
+ int err;
+ int retval = -ENXIO;
err = pci_enable_device(pdev);
- if ( err ) {
+ if (err) {
printk(KERN_WARNING "pm2fb: Can't enable pdev: %d\n", err);
return err;
}
info = framebuffer_alloc(sizeof(struct pm2fb_par), &pdev->dev);
- if ( !info )
+ if (!info)
return -ENOMEM;
default_par = info->par;
@@ -1236,14 +1560,14 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start);
/* Registers - request region and map it. */
- if ( !request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len,
- "pm2fb regbase") ) {
+ if (!request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len,
+ "pm2fb regbase")) {
printk(KERN_WARNING "pm2fb: Can't reserve regbase.\n");
goto err_exit_neither;
}
default_par->v_regs =
ioremap_nocache(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
- if ( !default_par->v_regs ) {
+ if (!default_par->v_regs) {
printk(KERN_WARNING "pm2fb: Can't remap %s register area.\n",
pm2fb_fix.id);
release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
@@ -1258,72 +1582,101 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
default_par->mem_control, default_par->boot_address,
default_par->mem_config);
- if(default_par->mem_control == 0 &&
+ if (default_par->mem_control == 0 &&
default_par->boot_address == 0x31 &&
default_par->mem_config == 0x259fffff) {
default_par->memclock = CVPPC_MEMCLOCK;
- default_par->mem_control=0;
- default_par->boot_address=0x20;
- default_par->mem_config=0xe6002021;
+ default_par->mem_control = 0;
+ default_par->boot_address = 0x20;
+ default_par->mem_config = 0xe6002021;
if (pdev->subsystem_vendor == 0x1048 &&
pdev->subsystem_device == 0x0a31) {
- DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n",
+ DPRINTK("subsystem_vendor: %04x, "
+ "subsystem_device: %04x\n",
pdev->subsystem_vendor, pdev->subsystem_device);
- DPRINTK("We have not been initialized by VGA BIOS "
- "and are running on an Elsa Winner 2000 Office\n");
+ DPRINTK("We have not been initialized by VGA BIOS and "
+ "are running on an Elsa Winner 2000 Office\n");
DPRINTK("Initializing card timings manually...\n");
- default_par->memclock=70000;
+ default_par->memclock = 100000;
}
if (pdev->subsystem_vendor == 0x3d3d &&
pdev->subsystem_device == 0x0100) {
- DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n",
+ DPRINTK("subsystem_vendor: %04x, "
+ "subsystem_device: %04x\n",
pdev->subsystem_vendor, pdev->subsystem_device);
- DPRINTK("We have not been initialized by VGA BIOS "
- "and are running on an 3dlabs reference board\n");
+ DPRINTK("We have not been initialized by VGA BIOS and "
+ "are running on an 3dlabs reference board\n");
DPRINTK("Initializing card timings manually...\n");
- default_par->memclock=74894;
+ default_par->memclock = 74894;
}
}
/* Now work out how big lfb is going to be. */
- switch(default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
+ switch (default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
case PM2F_MEM_BANKS_1:
- pm2fb_fix.smem_len=0x200000;
+ pm2fb_fix.smem_len = 0x200000;
break;
case PM2F_MEM_BANKS_2:
- pm2fb_fix.smem_len=0x400000;
+ pm2fb_fix.smem_len = 0x400000;
break;
case PM2F_MEM_BANKS_3:
- pm2fb_fix.smem_len=0x600000;
+ pm2fb_fix.smem_len = 0x600000;
break;
case PM2F_MEM_BANKS_4:
- pm2fb_fix.smem_len=0x800000;
+ pm2fb_fix.smem_len = 0x800000;
break;
}
pm2fb_fix.smem_start = pci_resource_start(pdev, 1);
/* Linear frame buffer - request region and map it. */
- if ( !request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len,
- "pm2fb smem") ) {
+ if (!request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len,
+ "pm2fb smem")) {
printk(KERN_WARNING "pm2fb: Can't reserve smem.\n");
goto err_exit_mmio;
}
info->screen_base =
ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
- if ( !info->screen_base ) {
+ if (!info->screen_base) {
printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n");
release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
goto err_exit_mmio;
}
+#ifdef CONFIG_MTRR
+ default_par->mtrr_handle = -1;
+ if (!nomtrr)
+ default_par->mtrr_handle =
+ mtrr_add(pm2fb_fix.smem_start,
+ pm2fb_fix.smem_len,
+ MTRR_TYPE_WRCOMB, 1);
+#endif
+
info->fbops = &pm2fb_ops;
info->fix = pm2fb_fix;
info->pseudo_palette = default_par->palette;
info->flags = FBINFO_DEFAULT |
FBINFO_HWACCEL_YPAN |
FBINFO_HWACCEL_COPYAREA |
+ FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_FILLRECT;
+ info->pixmap.addr = kmalloc(PM2_PIXMAP_SIZE, GFP_KERNEL);
+ if (!info->pixmap.addr) {
+ retval = -ENOMEM;
+ goto err_exit_pixmap;
+ }
+ info->pixmap.size = PM2_PIXMAP_SIZE;
+ info->pixmap.buf_align = 4;
+ info->pixmap.scan_align = 4;
+ info->pixmap.access_align = 32;
+ info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
+ if (noaccel) {
+ printk(KERN_DEBUG "disabling acceleration\n");
+ info->flags |= FBINFO_HWACCEL_DISABLED;
+ info->pixmap.scan_align = 1;
+ }
+
if (!mode)
mode = "640x480@60";
@@ -1350,6 +1703,8 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
err_exit_all:
fb_dealloc_cmap(&info->cmap);
err_exit_both:
+ kfree(info->pixmap.addr);
+ err_exit_pixmap:
iounmap(info->screen_base);
release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
err_exit_mmio:
@@ -1357,7 +1712,7 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
err_exit_neither:
framebuffer_release(info);
- return err_retval;
+ return retval;
}
/**
@@ -1369,34 +1724,34 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
*/
static void __devexit pm2fb_remove(struct pci_dev *pdev)
{
- struct fb_info* info = pci_get_drvdata(pdev);
- struct fb_fix_screeninfo* fix = &info->fix;
+ struct fb_info *info = pci_get_drvdata(pdev);
+ struct fb_fix_screeninfo *fix = &info->fix;
struct pm2fb_par *par = info->par;
unregister_framebuffer(info);
+#ifdef CONFIG_MTRR
+ if (par->mtrr_handle >= 0)
+ mtrr_del(par->mtrr_handle, info->fix.smem_start,
+ info->fix.smem_len);
+#endif /* CONFIG_MTRR */
iounmap(info->screen_base);
release_mem_region(fix->smem_start, fix->smem_len);
iounmap(par->v_regs);
release_mem_region(fix->mmio_start, fix->mmio_len);
pci_set_drvdata(pdev, NULL);
+ kfree(info->pixmap.addr);
kfree(info);
}
static struct pci_device_id pm2fb_id_table[] = {
{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020,
- PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
- 0xff0000, 0 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2,
- PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
- 0xff0000, 0 },
- { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
- PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
- 0xff0000, 0 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NOT_DEFINED_VGA << 8,
- 0xff00, 0 },
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0, }
};
@@ -1418,7 +1773,7 @@ MODULE_DEVICE_TABLE(pci, pm2fb_id_table);
*/
static int __init pm2fb_setup(char *options)
{
- char* this_opt;
+ char *this_opt;
if (!options || !*options)
return 0;
@@ -1426,13 +1781,20 @@ static int __init pm2fb_setup(char *options)
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt)
continue;
- if(!strcmp(this_opt, "lowhsync")) {
+ if (!strcmp(this_opt, "lowhsync"))
lowhsync = 1;
- } else if(!strcmp(this_opt, "lowvsync")) {
+ else if (!strcmp(this_opt, "lowvsync"))
lowvsync = 1;
- } else {
+ else if (!strncmp(this_opt, "hwcursor=", 9))
+ hwcursor = simple_strtoul(this_opt + 9, NULL, 0);
+#ifdef CONFIG_MTRR
+ else if (!strncmp(this_opt, "nomtrr", 6))
+ nomtrr = 1;
+#endif
+ else if (!strncmp(this_opt, "noaccel", 7))
+ noaccel = 1;
+ else
mode = this_opt;
- }
}
return 0;
}
@@ -1474,6 +1836,15 @@ module_param(lowhsync, bool, 0);
MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode");
module_param(lowvsync, bool, 0);
MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode");
+module_param(noaccel, bool, 0);
+MODULE_PARM_DESC(noaccel, "Disable acceleration");
+module_param(hwcursor, int, 0644);
+MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
+ "(1=enable, 0=disable, default=1)");
+#ifdef CONFIG_MTRR
+module_param(nomtrr, bool, 0);
+MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
+#endif
MODULE_AUTHOR("Jim Hague <jim.hague@acm.org>");
MODULE_DESCRIPTION("Permedia2 framebuffer device driver");
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index 5b3f54c0918..070659992c1 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -32,6 +32,9 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
#include <video/pm3fb.h>
@@ -41,15 +44,25 @@
#undef PM3FB_MASTER_DEBUG
#ifdef PM3FB_MASTER_DEBUG
-#define DPRINTK(a,b...) printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b)
+#define DPRINTK(a, b...) \
+ printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b)
#else
-#define DPRINTK(a,b...)
+#define DPRINTK(a, b...)
#endif
+#define PM3_PIXMAP_SIZE (2048 * 4)
+
/*
* Driver data
*/
+static int hwcursor = 1;
static char *mode_option __devinitdata;
+static int noaccel __devinitdata;
+
+/* mtrr option */
+#ifdef CONFIG_MTRR
+static int nomtrr __devinitdata;
+#endif
/*
* This structure defines the hardware state of the graphics card. Normally
@@ -61,8 +74,9 @@ static char *mode_option __devinitdata;
struct pm3_par {
unsigned char __iomem *v_regs;/* virtual address of p_regs */
u32 video; /* video flags before blanking */
- u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */
+ u32 base; /* screen base in 128 bits unit */
u32 palette[16];
+ int mtrr_handle;
};
/*
@@ -96,7 +110,8 @@ static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
static inline void PM3_WAIT(struct pm3_par *par, u32 n)
{
- while (PM3_READ_REG(par, PM3InFIFOSpace) < n);
+ while (PM3_READ_REG(par, PM3InFIFOSpace) < n)
+ cpu_relax();
}
static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v)
@@ -133,7 +148,7 @@ static void pm3fb_clear_colormap(struct pm3_par *par,
}
-/* Calculating various clock parameter */
+/* Calculating various clock parameters */
static void pm3fb_calculate_clock(unsigned long reqclock,
unsigned char *prescale,
unsigned char *feedback,
@@ -164,7 +179,7 @@ static void pm3fb_calculate_clock(unsigned long reqclock,
static inline int pm3fb_depth(const struct fb_var_screeninfo *var)
{
- if ( var->bits_per_pixel == 16 )
+ if (var->bits_per_pixel == 16)
return var->red.length + var->green.length
+ var->blue.length;
@@ -195,8 +210,8 @@ static int pm3fb_sync(struct fb_info *info)
PM3_WRITE_REG(par, PM3Sync, 0);
mb();
do {
- while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0);
- rmb();
+ while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0)
+ cpu_relax();
} while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag);
return 0;
@@ -276,15 +291,22 @@ static void pm3fb_init_engine(struct fb_info *info)
PM3_WAIT(par, 2);
{
- unsigned long rm = 1;
+ /* invert bits in bitmask */
+ unsigned long rm = 1 | (3 << 7);
switch (info->var.bits_per_pixel) {
case 8:
PM3_WRITE_REG(par, PM3PixelSize,
PM3PixelSize_GLOBAL_8BIT);
+#ifdef __BIG_ENDIAN
+ rm |= 3 << 15;
+#endif
break;
case 16:
PM3_WRITE_REG(par, PM3PixelSize,
PM3PixelSize_GLOBAL_16BIT);
+#ifdef __BIG_ENDIAN
+ rm |= 2 << 15;
+#endif
break;
case 32:
PM3_WRITE_REG(par, PM3PixelSize,
@@ -342,7 +364,7 @@ static void pm3fb_init_engine(struct fb_info *info)
PM3_WRITE_REG(par, PM3dXDom, 0x0);
PM3_WRITE_REG(par, PM3dXSub, 0x0);
- PM3_WRITE_REG(par, PM3dY, (1 << 16));
+ PM3_WRITE_REG(par, PM3dY, 1 << 16);
PM3_WRITE_REG(par, PM3StartXDom, 0x0);
PM3_WRITE_REG(par, PM3StartXSub, 0x0);
PM3_WRITE_REG(par, PM3StartY, 0x0);
@@ -357,71 +379,350 @@ static void pm3fb_init_engine(struct fb_info *info)
pm3fb_sync(info);
}
-static void pm3fb_fillrect (struct fb_info *info,
+static void pm3fb_fillrect(struct fb_info *info,
const struct fb_fillrect *region)
{
struct pm3_par *par = info->par;
struct fb_fillrect modded;
int vxres, vyres;
+ int rop;
u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
- ((u32*)info->pseudo_palette)[region->color] : region->color;
+ ((u32 *)info->pseudo_palette)[region->color] : region->color;
if (info->state != FBINFO_STATE_RUNNING)
return;
- if ((info->flags & FBINFO_HWACCEL_DISABLED) ||
- region->rop != ROP_COPY ) {
+ if (info->flags & FBINFO_HWACCEL_DISABLED) {
cfb_fillrect(info, region);
return;
}
+ if (region->rop == ROP_COPY )
+ rop = PM3Config2D_ForegroundROP(0x3); /* GXcopy */
+ else
+ rop = PM3Config2D_ForegroundROP(0x6) | /* GXxor */
+ PM3Config2D_FBDestReadEnable;
vxres = info->var.xres_virtual;
vyres = info->var.yres_virtual;
memcpy(&modded, region, sizeof(struct fb_fillrect));
- if(!modded.width || !modded.height ||
- modded.dx >= vxres || modded.dy >= vyres)
+ if (!modded.width || !modded.height ||
+ modded.dx >= vxres || modded.dy >= vyres)
return;
- if(modded.dx + modded.width > vxres)
+ if (modded.dx + modded.width > vxres)
modded.width = vxres - modded.dx;
- if(modded.dy + modded.height > vyres)
+ if (modded.dy + modded.height > vyres)
modded.height = vyres - modded.dy;
- if(info->var.bits_per_pixel == 8)
+ if (info->var.bits_per_pixel == 8)
color |= color << 8;
- if(info->var.bits_per_pixel <= 16)
+ if (info->var.bits_per_pixel <= 16)
color |= color << 16;
PM3_WAIT(par, 4);
-
+ /* ROP Ox3 is GXcopy */
PM3_WRITE_REG(par, PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
+ PM3Config2D_UseConstantSource |
+ PM3Config2D_ForegroundROPEnable |
+ rop |
+ PM3Config2D_FBWriteEnable);
PM3_WRITE_REG(par, PM3ForegroundColor, color);
PM3_WRITE_REG(par, PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(modded.dx)) |
- (PM3RectanglePosition_YOffset(modded.dy)));
+ PM3RectanglePosition_XOffset(modded.dx) |
+ PM3RectanglePosition_YOffset(modded.dy));
PM3_WRITE_REG(par, PM3Render2D,
PM3Render2D_XPositive |
PM3Render2D_YPositive |
PM3Render2D_Operation_Normal |
PM3Render2D_SpanOperation |
- (PM3Render2D_Width(modded.width)) |
- (PM3Render2D_Height(modded.height)));
+ PM3Render2D_Width(modded.width) |
+ PM3Render2D_Height(modded.height));
+}
+
+static void pm3fb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ struct pm3_par *par = info->par;
+ struct fb_copyarea modded;
+ u32 vxres, vyres;
+ int x_align, o_x, o_y;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
+ if (info->flags & FBINFO_HWACCEL_DISABLED) {
+ cfb_copyarea(info, area);
+ return;
+ }
+
+ memcpy(&modded, area, sizeof(struct fb_copyarea));
+
+ vxres = info->var.xres_virtual;
+ vyres = info->var.yres_virtual;
+
+ if (!modded.width || !modded.height ||
+ modded.sx >= vxres || modded.sy >= vyres ||
+ modded.dx >= vxres || modded.dy >= vyres)
+ return;
+
+ if (modded.sx + modded.width > vxres)
+ modded.width = vxres - modded.sx;
+ if (modded.dx + modded.width > vxres)
+ modded.width = vxres - modded.dx;
+ if (modded.sy + modded.height > vyres)
+ modded.height = vyres - modded.sy;
+ if (modded.dy + modded.height > vyres)
+ modded.height = vyres - modded.dy;
+
+ o_x = modded.sx - modded.dx; /*(sx > dx ) ? (sx - dx) : (dx - sx); */
+ o_y = modded.sy - modded.dy; /*(sy > dy ) ? (sy - dy) : (dy - sy); */
+
+ x_align = (modded.sx & 0x1f);
+
+ PM3_WAIT(par, 6);
+
+ PM3_WRITE_REG(par, PM3Config2D,
+ PM3Config2D_UserScissorEnable |
+ PM3Config2D_ForegroundROPEnable |
+ PM3Config2D_Blocking |
+ PM3Config2D_ForegroundROP(0x3) | /* Ox3 is GXcopy */
+ PM3Config2D_FBWriteEnable);
+
+ PM3_WRITE_REG(par, PM3ScissorMinXY,
+ ((modded.dy & 0x0fff) << 16) | (modded.dx & 0x0fff));
+ PM3_WRITE_REG(par, PM3ScissorMaxXY,
+ (((modded.dy + modded.height) & 0x0fff) << 16) |
+ ((modded.dx + modded.width) & 0x0fff));
+
+ PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset,
+ PM3FBSourceReadBufferOffset_XOffset(o_x) |
+ PM3FBSourceReadBufferOffset_YOffset(o_y));
+
+ PM3_WRITE_REG(par, PM3RectanglePosition,
+ PM3RectanglePosition_XOffset(modded.dx - x_align) |
+ PM3RectanglePosition_YOffset(modded.dy));
+
+ PM3_WRITE_REG(par, PM3Render2D,
+ ((modded.sx > modded.dx) ? PM3Render2D_XPositive : 0) |
+ ((modded.sy > modded.dy) ? PM3Render2D_YPositive : 0) |
+ PM3Render2D_Operation_Normal |
+ PM3Render2D_SpanOperation |
+ PM3Render2D_FBSourceReadEnable |
+ PM3Render2D_Width(modded.width + x_align) |
+ PM3Render2D_Height(modded.height));
+}
+
+static void pm3fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ struct pm3_par *par = info->par;
+ u32 height = image->height;
+ u32 fgx, bgx;
+ const u32 *src = (const u32 *)image->data;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
+ if (info->flags & FBINFO_HWACCEL_DISABLED) {
+ cfb_imageblit(info, image);
+ return;
+ }
+ switch (info->fix.visual) {
+ case FB_VISUAL_PSEUDOCOLOR:
+ fgx = image->fg_color;
+ bgx = image->bg_color;
+ break;
+ case FB_VISUAL_TRUECOLOR:
+ default:
+ fgx = par->palette[image->fg_color];
+ bgx = par->palette[image->bg_color];
+ break;
+ }
+ if (image->depth != 1)
+ return cfb_imageblit(info, image);
+
+ if (info->var.bits_per_pixel == 8) {
+ fgx |= fgx << 8;
+ bgx |= bgx << 8;
+ }
+ if (info->var.bits_per_pixel <= 16) {
+ fgx |= fgx << 16;
+ bgx |= bgx << 16;
+ }
+
+ PM3_WAIT(par, 7);
+
+ PM3_WRITE_REG(par, PM3ForegroundColor, fgx);
+ PM3_WRITE_REG(par, PM3BackgroundColor, bgx);
+
+ /* ROP Ox3 is GXcopy */
+ PM3_WRITE_REG(par, PM3Config2D,
+ PM3Config2D_UserScissorEnable |
+ PM3Config2D_UseConstantSource |
+ PM3Config2D_ForegroundROPEnable |
+ PM3Config2D_ForegroundROP(0x3) |
+ PM3Config2D_OpaqueSpan |
+ PM3Config2D_FBWriteEnable);
+ PM3_WRITE_REG(par, PM3ScissorMinXY,
+ ((image->dy & 0x0fff) << 16) | (image->dx & 0x0fff));
+ PM3_WRITE_REG(par, PM3ScissorMaxXY,
+ (((image->dy + image->height) & 0x0fff) << 16) |
+ ((image->dx + image->width) & 0x0fff));
+ PM3_WRITE_REG(par, PM3RectanglePosition,
+ PM3RectanglePosition_XOffset(image->dx) |
+ PM3RectanglePosition_YOffset(image->dy));
+ PM3_WRITE_REG(par, PM3Render2D,
+ PM3Render2D_XPositive |
+ PM3Render2D_YPositive |
+ PM3Render2D_Operation_SyncOnBitMask |
+ PM3Render2D_SpanOperation |
+ PM3Render2D_Width(image->width) |
+ PM3Render2D_Height(image->height));
+
+
+ while (height--) {
+ int width = ((image->width + 7) >> 3)
+ + info->pixmap.scan_align - 1;
+ width >>= 2;
+
+ while (width >= PM3_FIFO_SIZE) {
+ int i = PM3_FIFO_SIZE - 1;
+
+ PM3_WAIT(par, PM3_FIFO_SIZE);
+ while (i--) {
+ PM3_WRITE_REG(par, PM3BitMaskPattern, *src);
+ src++;
+ }
+ width -= PM3_FIFO_SIZE - 1;
+ }
+
+ PM3_WAIT(par, width + 1);
+ while (width--) {
+ PM3_WRITE_REG(par, PM3BitMaskPattern, *src);
+ src++;
+ }
+ }
}
/* end of acceleration functions */
+/*
+ * Hardware Cursor support.
+ */
+static const u8 cursor_bits_lookup[16] = {
+ 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
+ 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
+};
+
+static int pm3fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ struct pm3_par *par = info->par;
+ u8 mode;
+
+ if (!hwcursor)
+ return -EINVAL; /* just to force soft_cursor() call */
+
+ /* Too large of a cursor or wrong bpp :-( */
+ if (cursor->image.width > 64 ||
+ cursor->image.height > 64 ||
+ cursor->image.depth > 1)
+ return -EINVAL;
+
+ mode = PM3RD_CursorMode_TYPE_X;
+ if (cursor->enable)
+ mode |= PM3RD_CursorMode_CURSOR_ENABLE;
+
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, mode);
+
+ /*
+ * If the cursor is not be changed this means either we want the
+ * current cursor state (if enable is set) or we want to query what
+ * we can do with the cursor (if enable is not set)
+ */
+ if (!cursor->set)
+ return 0;
+
+ if (cursor->set & FB_CUR_SETPOS) {
+ int x = cursor->image.dx - info->var.xoffset;
+ int y = cursor->image.dy - info->var.yoffset;
+
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorXLow, x & 0xff);
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorXHigh, (x >> 8) & 0xf);
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorYLow, y & 0xff);
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorYHigh, (y >> 8) & 0xf);
+ }
+
+ if (cursor->set & FB_CUR_SETHOT) {
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotX,
+ cursor->hot.x & 0x3f);
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotY,
+ cursor->hot.y & 0x3f);
+ }
+
+ if (cursor->set & FB_CUR_SETCMAP) {
+ u32 fg_idx = cursor->image.fg_color;
+ u32 bg_idx = cursor->image.bg_color;
+ struct fb_cmap cmap = info->cmap;
+
+ /* the X11 driver says one should use these color registers */
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(39),
+ cmap.red[fg_idx] >> 8 );
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(40),
+ cmap.green[fg_idx] >> 8 );
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(41),
+ cmap.blue[fg_idx] >> 8 );
+
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(42),
+ cmap.red[bg_idx] >> 8 );
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(43),
+ cmap.green[bg_idx] >> 8 );
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(44),
+ cmap.blue[bg_idx] >> 8 );
+ }
+
+ if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
+ u8 *bitmap = (u8 *)cursor->image.data;
+ u8 *mask = (u8 *)cursor->mask;
+ int i;
+ int pos = PM3RD_CursorPattern(0);
+
+ for (i = 0; i < cursor->image.height; i++) {
+ int j = (cursor->image.width + 7) >> 3;
+ int k = 8 - j;
+
+ for (; j > 0; j--) {
+ u8 data = *bitmap ^ *mask;
+
+ if (cursor->rop == ROP_COPY)
+ data = *mask & *bitmap;
+ /* Upper 4 bits of bitmap data */
+ PM3_WRITE_DAC_REG(par, pos++,
+ cursor_bits_lookup[data >> 4] |
+ (cursor_bits_lookup[*mask >> 4] << 1));
+ /* Lower 4 bits of bitmap */
+ PM3_WRITE_DAC_REG(par, pos++,
+ cursor_bits_lookup[data & 0xf] |
+ (cursor_bits_lookup[*mask & 0xf] << 1));
+ bitmap++;
+ mask++;
+ }
+ for (; k > 0; k--) {
+ PM3_WRITE_DAC_REG(par, pos++, 0);
+ PM3_WRITE_DAC_REG(par, pos++, 0);
+ }
+ }
+ while (pos < PM3RD_CursorPattern(1024))
+ PM3_WRITE_DAC_REG(par, pos++, 0);
+ }
+ return 0;
+}
+
/* write the mode to registers */
static void pm3fb_write_mode(struct fb_info *info)
{
struct pm3_par *par = info->par;
- char tempsync = 0x00, tempmisc = 0x00;
+ char tempsync = 0x00;
+ char tempmisc = 0x00;
const u32 hsstart = info->var.right_margin;
const u32 hsend = hsstart + info->var.hsync_len;
const u32 hbend = hsend + info->var.left_margin;
@@ -618,47 +919,57 @@ static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
unsigned bpp = var->red.length + var->green.length
+ var->blue.length + var->transp.length;
- if ( bpp != var->bits_per_pixel ) {
+ if (bpp != var->bits_per_pixel) {
/* set predefined mode for bits_per_pixel settings */
- switch(var->bits_per_pixel) {
+ switch (var->bits_per_pixel) {
case 8:
- var->red.length = var->green.length = var->blue.length = 8;
- var->red.offset = var->green.offset = var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->red.offset = 0;
+ var->green.offset = 0;
+ var->blue.offset = 0;
var->transp.offset = 0;
var->transp.length = 0;
break;
case 16:
- var->red.length = var->blue.length = 5;
+ var->red.length = 5;
+ var->blue.length = 5;
var->green.length = 6;
var->transp.length = 0;
break;
case 32:
- var->red.length = var->green.length = var->blue.length = 8;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
var->transp.length = 8;
break;
default:
- DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
+ DPRINTK("depth not supported: %u\n",
+ var->bits_per_pixel);
return -EINVAL;
}
}
/* it is assumed BGRA order */
- if (var->bits_per_pixel > 8 )
- {
+ if (var->bits_per_pixel > 8 ) {
var->blue.offset = 0;
var->green.offset = var->blue.length;
var->red.offset = var->green.offset + var->green.length;
var->transp.offset = var->red.offset + var->red.length;
}
- var->height = var->width = -1;
+ var->height = -1;
+ var->width = -1;
if (var->xres != var->xres_virtual) {
- DPRINTK("virtual x resolution != physical x resolution not supported\n");
+ DPRINTK("virtual x resolution != "
+ "physical x resolution not supported\n");
return -EINVAL;
}
if (var->yres > var->yres_virtual) {
- DPRINTK("virtual y resolution < physical y resolution not possible\n");
+ DPRINTK("virtual y resolution < "
+ "physical y resolution not possible\n");
return -EINVAL;
}
@@ -673,7 +984,7 @@ static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
}
var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */
- lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
+ lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
if (var->xres < 200 || var->xres > 2048) {
DPRINTK("width not supported: %u\n", var->xres);
@@ -692,7 +1003,8 @@ static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
}
if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) {
- DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock));
+ DPRINTK("pixclock too high (%ldKHz)\n",
+ PICOS2KHZ(var->pixclock));
return -EINVAL;
}
@@ -709,7 +1021,7 @@ static int pm3fb_set_par(struct fb_info *info)
const u32 xres = (info->var.xres + 31) & ~31;
const unsigned bpp = info->var.bits_per_pixel;
- par->base = pm3fb_shift_bpp(bpp,(info->var.yoffset * xres)
+ par->base = pm3fb_shift_bpp(bpp, (info->var.yoffset * xres)
+ info->var.xoffset);
par->video = 0;
@@ -725,15 +1037,12 @@ static int pm3fb_set_par(struct fb_info *info)
if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
par->video |= PM3VideoControl_LINE_DOUBLE_ON;
- else
- par->video |= PM3VideoControl_LINE_DOUBLE_OFF;
if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
par->video |= PM3VideoControl_ENABLE;
- else {
- par->video |= PM3VideoControl_DISABLE;
+ else
DPRINTK("PM3Video disabled\n");
- }
+
switch (bpp) {
case 8:
par->video |= PM3VideoControl_PIXELSIZE_8BIT;
@@ -751,13 +1060,11 @@ static int pm3fb_set_par(struct fb_info *info)
info->fix.visual =
(bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
- info->fix.line_length = ((info->var.xres_virtual + 7) & ~7)
- * bpp / 8;
+ info->fix.line_length = ((info->var.xres_virtual + 7) >> 3) * bpp;
/* pm3fb_clear_memory(info, 0);*/
pm3fb_clear_colormap(par, 0, 0, 0);
- PM3_WRITE_DAC_REG(par, PM3RD_CursorMode,
- PM3RD_CursorMode_CURSOR_DISABLE);
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 0);
pm3fb_init_engine(info);
pm3fb_write_mode(info);
return 0;
@@ -773,10 +1080,9 @@ static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
return -EINVAL;
/* grayscale works only partially under directcolor */
- if (info->var.grayscale) {
- /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ if (info->var.grayscale)
red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
- }
/* Directcolor:
* var->{color}.offset contains start of bitfield
@@ -790,8 +1096,8 @@ static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
*
* Pseudocolor:
* var->{color}.offset is 0
- * var->{color}.length contains width of DAC or the number of unique
- * colors available (color depth)
+ * var->{color}.length contains width of DAC or the number
+ * of unique colors available (color depth)
* pseudo_palette is not used
* RAMDAC[X] is programmed to (red, green, blue)
* color depth = var->{color}.length
@@ -801,7 +1107,7 @@ static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
* This is the point where the color is converted to something that
* is acceptable by the hardware.
*/
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
red = CNVT_TOHW(red, info->var.red.length);
green = CNVT_TOHW(green, info->var.green.length);
blue = CNVT_TOHW(blue, info->var.blue.length);
@@ -825,12 +1131,11 @@ static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
break;
case 16:
case 32:
- ((u32*)(info->pseudo_palette))[regno] = v;
+ ((u32 *)(info->pseudo_palette))[regno] = v;
break;
}
return 0;
- }
- else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
+ } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
pm3fb_set_color(par, regno, red, green, blue);
return 0;
@@ -871,7 +1176,7 @@ static int pm3fb_blank(int blank_mode, struct fb_info *info)
video |= PM3VideoControl_ENABLE;
break;
case FB_BLANK_NORMAL:
- video &= ~(PM3VideoControl_ENABLE);
+ video &= ~PM3VideoControl_ENABLE;
break;
case FB_BLANK_HSYNC_SUSPEND:
video &= ~(PM3VideoControl_HSYNC_MASK |
@@ -892,7 +1197,7 @@ static int pm3fb_blank(int blank_mode, struct fb_info *info)
}
PM3_WAIT(par, 1);
- PM3_WRITE_REG(par,PM3VideoControl, video);
+ PM3_WRITE_REG(par, PM3VideoControl, video);
return 0;
}
@@ -907,10 +1212,11 @@ static struct fb_ops pm3fb_ops = {
.fb_setcolreg = pm3fb_setcolreg,
.fb_pan_display = pm3fb_pan_display,
.fb_fillrect = pm3fb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
+ .fb_copyarea = pm3fb_copyarea,
+ .fb_imageblit = pm3fb_imageblit,
.fb_blank = pm3fb_blank,
.fb_sync = pm3fb_sync,
+ .fb_cursor = pm3fb_cursor,
};
/* ------------------------------------------------------------------------- */
@@ -923,7 +1229,8 @@ static struct fb_ops pm3fb_ops = {
/* the pm3fb_fix.smem_start is also set */
static unsigned long pm3fb_size_memory(struct pm3_par *par)
{
- unsigned long memsize = 0, tempBypass, i, temp1, temp2;
+ unsigned long memsize = 0;
+ unsigned long tempBypass, i, temp1, temp2;
unsigned char __iomem *screen_mem;
pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */
@@ -951,7 +1258,9 @@ static unsigned long pm3fb_size_memory(struct pm3_par *par)
PM3_WAIT(par, 1);
PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF);
- /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */
+ /* pm3 split up memory, replicates, and do a lot of
+ * nasty stuff IMHO ;-)
+ */
for (i = 0; i < 32; i++) {
fb_writel(i * 0x00345678,
(screen_mem + (i * 1048576)));
@@ -1008,8 +1317,9 @@ static int __devinit pm3fb_probe(struct pci_dev *dev,
{
struct fb_info *info;
struct pm3_par *par;
- struct device* device = &dev->dev; /* for pci drivers */
- int err, retval = -ENXIO;
+ struct device *device = &dev->dev; /* for pci drivers */
+ int err;
+ int retval = -ENXIO;
err = pci_enable_device(dev);
if (err) {
@@ -1031,6 +1341,10 @@ static int __devinit pm3fb_probe(struct pci_dev *dev,
*/
pm3fb_fix.mmio_start = pci_resource_start(dev, 0);
pm3fb_fix.mmio_len = PM3_REGS_SIZE;
+#if defined(__BIG_ENDIAN)
+ pm3fb_fix.mmio_start += PM3_REGS_SIZE;
+ DPRINTK("Adjusting register base for big-endian.\n");
+#endif
/* Registers - request region and map it. */
if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len,
@@ -1047,15 +1361,10 @@ static int __devinit pm3fb_probe(struct pci_dev *dev,
goto err_exit_neither;
}
-#if defined(__BIG_ENDIAN)
- pm3fb_fix.mmio_start += PM3_REGS_SIZE;
- DPRINTK("Adjusting register base for big-endian.\n");
-#endif
/* Linear frame buffer - request region and map it. */
pm3fb_fix.smem_start = pci_resource_start(dev, 1);
pm3fb_fix.smem_len = pm3fb_size_memory(par);
- if (!pm3fb_fix.smem_len)
- {
+ if (!pm3fb_fix.smem_len) {
printk(KERN_WARNING "pm3fb: Can't find memory on board.\n");
goto err_exit_mmio;
}
@@ -1073,6 +1382,12 @@ static int __devinit pm3fb_probe(struct pci_dev *dev,
}
info->screen_size = pm3fb_fix.smem_len;
+#ifdef CONFIG_MTRR
+ if (!nomtrr)
+ par->mtrr_handle = mtrr_add(pm3fb_fix.smem_start,
+ pm3fb_fix.smem_len,
+ MTRR_TYPE_WRCOMB, 1);
+#endif
info->fbops = &pm3fb_ops;
par->video = PM3_READ_REG(par, PM3VideoControl);
@@ -1080,7 +1395,26 @@ static int __devinit pm3fb_probe(struct pci_dev *dev,
info->fix = pm3fb_fix;
info->pseudo_palette = par->palette;
info->flags = FBINFO_DEFAULT |
- FBINFO_HWACCEL_FILLRECT;/* | FBINFO_HWACCEL_YPAN;*/
+ FBINFO_HWACCEL_XPAN |
+ FBINFO_HWACCEL_YPAN |
+ FBINFO_HWACCEL_COPYAREA |
+ FBINFO_HWACCEL_IMAGEBLIT |
+ FBINFO_HWACCEL_FILLRECT;
+
+ if (noaccel) {
+ printk(KERN_DEBUG "disabling acceleration\n");
+ info->flags |= FBINFO_HWACCEL_DISABLED;
+ }
+ info->pixmap.addr = kmalloc(PM3_PIXMAP_SIZE, GFP_KERNEL);
+ if (!info->pixmap.addr) {
+ retval = -ENOMEM;
+ goto err_exit_pixmap;
+ }
+ info->pixmap.size = PM3_PIXMAP_SIZE;
+ info->pixmap.buf_align = 4;
+ info->pixmap.scan_align = 4;
+ info->pixmap.access_align = 32;
+ info->pixmap.flags = FB_PIXMAP_SYSTEM;
/*
* This should give a reasonable default video mode. The following is
@@ -1118,6 +1452,8 @@ static int __devinit pm3fb_probe(struct pci_dev *dev,
err_exit_all:
fb_dealloc_cmap(&info->cmap);
err_exit_both:
+ kfree(info->pixmap.addr);
+ err_exit_pixmap:
iounmap(info->screen_base);
release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
err_exit_mmio:
@@ -1142,12 +1478,18 @@ static void __devexit pm3fb_remove(struct pci_dev *dev)
unregister_framebuffer(info);
fb_dealloc_cmap(&info->cmap);
+#ifdef CONFIG_MTRR
+ if (par->mtrr_handle >= 0)
+ mtrr_del(par->mtrr_handle, info->fix.smem_start,
+ info->fix.smem_len);
+#endif /* CONFIG_MTRR */
iounmap(info->screen_base);
release_mem_region(fix->smem_start, fix->smem_len);
iounmap(par->v_regs);
release_mem_region(fix->mmio_start, fix->mmio_len);
pci_set_drvdata(dev, NULL);
+ kfree(info->pixmap.addr);
framebuffer_release(info);
}
}
@@ -1168,21 +1510,76 @@ static struct pci_driver pm3fb_driver = {
MODULE_DEVICE_TABLE(pci, pm3fb_id_table);
+#ifndef MODULE
+ /*
+ * Setup
+ */
+
+/*
+ * Only necessary if your driver takes special options,
+ * otherwise we fall back on the generic fb_setup().
+ */
+static int __init pm3fb_setup(char *options)
+{
+ char *this_opt;
+
+ /* Parse user speficied options (`video=pm3fb:') */
+ if (!options || !*options)
+ return 0;
+
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ if (!*this_opt)
+ continue;
+ else if (!strncmp(this_opt, "noaccel", 7))
+ noaccel = 1;
+ else if (!strncmp(this_opt, "hwcursor=", 9))
+ hwcursor = simple_strtoul(this_opt + 9, NULL, 0);
+#ifdef CONFIG_MTRR
+ else if (!strncmp(this_opt, "nomtrr", 6))
+ nomtrr = 1;
+#endif
+ else
+ mode_option = this_opt;
+ }
+ return 0;
+}
+#endif /* MODULE */
+
static int __init pm3fb_init(void)
{
+ /*
+ * For kernel boot options (in 'video=pm3fb:<options>' format)
+ */
#ifndef MODULE
- if (fb_get_options("pm3fb", NULL))
+ char *option = NULL;
+
+ if (fb_get_options("pm3fb", &option))
return -ENODEV;
+ pm3fb_setup(option);
#endif
+
return pci_register_driver(&pm3fb_driver);
}
+#ifdef MODULE
static void __exit pm3fb_exit(void)
{
pci_unregister_driver(&pm3fb_driver);
}
-module_init(pm3fb_init);
module_exit(pm3fb_exit);
+#endif
+module_init(pm3fb_init);
+
+module_param(noaccel, bool, 0);
+MODULE_PARM_DESC(noaccel, "Disable acceleration");
+module_param(hwcursor, int, 0644);
+MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
+ "(1=enable, 0=disable, default=1)");
+#ifdef CONFIG_MTRR
+module_param(nomtrr, bool, 0);
+MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
+#endif
+MODULE_DESCRIPTION("Permedia3 framebuffer device driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
index 264d37243fa..3a3f80f6521 100644
--- a/drivers/video/pmag-ba-fb.c
+++ b/drivers/video/pmag-ba-fb.c
@@ -147,16 +147,23 @@ static int __init pmagbafb_probe(struct device *dev)
resource_size_t start, len;
struct fb_info *info;
struct pmagbafb_par *par;
+ int err;
info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev);
- if (!info)
+ if (!info) {
+ printk(KERN_ERR "%s: Cannot allocate memory\n", dev->bus_id);
return -ENOMEM;
+ }
par = info->par;
dev_set_drvdata(dev, info);
- if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+ printk(KERN_ERR "%s: Cannot allocate color map\n",
+ dev->bus_id);
+ err = -ENOMEM;
goto err_alloc;
+ }
info->fbops = &pmagbafb_ops;
info->fix = pmagbafb_fix;
@@ -166,28 +173,41 @@ static int __init pmagbafb_probe(struct device *dev)
/* Request the I/O MEM resource. */
start = tdev->resource.start;
len = tdev->resource.end - start + 1;
- if (!request_mem_region(start, len, dev->bus_id))
+ if (!request_mem_region(start, len, dev->bus_id)) {
+ printk(KERN_ERR "%s: Cannot reserve FB region\n", dev->bus_id);
+ err = -EBUSY;
goto err_cmap;
+ }
/* MMIO mapping setup. */
info->fix.mmio_start = start;
par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
- if (!par->mmio)
+ if (!par->mmio) {
+ printk(KERN_ERR "%s: Cannot map MMIO\n", dev->bus_id);
+ err = -ENOMEM;
goto err_resource;
+ }
par->dac = par->mmio + PMAG_BA_BT459;
/* Frame buffer mapping setup. */
info->fix.smem_start = start + PMAG_BA_FBMEM;
info->screen_base = ioremap_nocache(info->fix.smem_start,
info->fix.smem_len);
- if (!info->screen_base)
+ if (!info->screen_base) {
+ printk(KERN_ERR "%s: Cannot map FB\n", dev->bus_id);
+ err = -ENOMEM;
goto err_mmio_map;
+ }
info->screen_size = info->fix.smem_len;
pmagbafb_erase_cursor(info);
- if (register_framebuffer(info) < 0)
+ err = register_framebuffer(info);
+ if (err < 0) {
+ printk(KERN_ERR "%s: Cannot register framebuffer\n",
+ dev->bus_id);
goto err_smem_map;
+ }
get_device(dev);
@@ -211,7 +231,7 @@ err_cmap:
err_alloc:
framebuffer_release(info);
- return -ENXIO;
+ return err;
}
static int __exit pmagbafb_remove(struct device *dev)
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
index 7a0ce7d5af6..9b80597241b 100644
--- a/drivers/video/pmagb-b-fb.c
+++ b/drivers/video/pmagb-b-fb.c
@@ -254,16 +254,23 @@ static int __init pmagbbfb_probe(struct device *dev)
struct pmagbbfb_par *par;
char freq0[12], freq1[12];
u32 vid_base;
+ int err;
info = framebuffer_alloc(sizeof(struct pmagbbfb_par), dev);
- if (!info)
+ if (!info) {
+ printk(KERN_ERR "%s: Cannot allocate memory\n", dev->bus_id);
return -ENOMEM;
+ }
par = info->par;
dev_set_drvdata(dev, info);
- if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+ printk(KERN_ERR "%s: Cannot allocate color map\n",
+ dev->bus_id);
+ err = -ENOMEM;
goto err_alloc;
+ }
info->fbops = &pmagbbfb_ops;
info->fix = pmagbbfb_fix;
@@ -273,22 +280,31 @@ static int __init pmagbbfb_probe(struct device *dev)
/* Request the I/O MEM resource. */
start = tdev->resource.start;
len = tdev->resource.end - start + 1;
- if (!request_mem_region(start, len, dev->bus_id))
+ if (!request_mem_region(start, len, dev->bus_id)) {
+ printk(KERN_ERR "%s: Cannot reserve FB region\n", dev->bus_id);
+ err = -EBUSY;
goto err_cmap;
+ }
/* MMIO mapping setup. */
info->fix.mmio_start = start;
par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
- if (!par->mmio)
+ if (!par->mmio) {
+ printk(KERN_ERR "%s: Cannot map MMIO\n", dev->bus_id);
+ err = -ENOMEM;
goto err_resource;
+ }
par->sfb = par->mmio + PMAGB_B_SFB;
par->dac = par->mmio + PMAGB_B_BT459;
/* Frame buffer mapping setup. */
info->fix.smem_start = start + PMAGB_B_FBMEM;
par->smem = ioremap_nocache(info->fix.smem_start, info->fix.smem_len);
- if (!par->smem)
+ if (!par->smem) {
+ printk(KERN_ERR "%s: Cannot map FB\n", dev->bus_id);
+ err = -ENOMEM;
goto err_mmio_map;
+ }
vid_base = sfb_read(par, SFB_REG_VID_BASE);
info->screen_base = (void __iomem *)par->smem + vid_base * 0x1000;
info->screen_size = info->fix.smem_len - 2 * vid_base * 0x1000;
@@ -297,8 +313,12 @@ static int __init pmagbbfb_probe(struct device *dev)
pmagbbfb_screen_setup(info);
pmagbbfb_osc_setup(info);
- if (register_framebuffer(info) < 0)
+ err = register_framebuffer(info);
+ if (err < 0) {
+ printk(KERN_ERR "%s: Cannot register framebuffer\n",
+ dev->bus_id);
goto err_smem_map;
+ }
get_device(dev);
@@ -330,7 +350,7 @@ err_cmap:
err_alloc:
framebuffer_release(info);
- return -ENXIO;
+ return err;
}
static int __exit pmagbbfb_remove(struct device *dev)
diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c
index f29e66e2d77..685761a0732 100644
--- a/drivers/video/pnx4008/pnxrgbfb.c
+++ b/drivers/video/pnx4008/pnxrgbfb.c
@@ -26,7 +26,6 @@
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <asm/uaccess.h>
#include "sdum.h"
#include "fbcommon.h"
diff --git a/drivers/video/pnx4008/sdum.h b/drivers/video/pnx4008/sdum.h
index e8c5dcdd881..189c3d64138 100644
--- a/drivers/video/pnx4008/sdum.h
+++ b/drivers/video/pnx4008/sdum.h
@@ -77,9 +77,6 @@
#define CONF_DIRTYDETECTION_OFF (0x600)
#define CONF_DIRTYDETECTION_ON (0x601)
-/* Set the corresponding bit. */
-#define BIT(n) (0x1U << (n))
-
struct dumchannel_uf {
int channelnr;
u32 *dirty;
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 646ec823c16..75836aa8319 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -22,22 +22,14 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/console.h>
#include <linux/ioctl.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
-
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/fb.h>
#include <linux/init.h>
-#include <asm/time.h>
#include <asm/abs_addr.h>
#include <asm/lv1call.h>
@@ -48,12 +40,6 @@
#define DEVICE_NAME "ps3fb"
-#ifdef PS3FB_DEBUG
-#define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101
#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102
#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600
@@ -66,8 +52,10 @@
#define L1GPU_DISPLAY_SYNC_VSYNC 2
#define DDR_SIZE (0) /* used no ddr */
-#define GPU_OFFSET (64 * 1024)
+#define GPU_CMD_BUF_SIZE (64 * 1024)
#define GPU_IOIF (0x0d000000UL)
+#define GPU_ALIGN_UP(x) _ALIGN_UP((x), 64)
+#define GPU_MAX_LINE_LENGTH (65536 - 64)
#define PS3FB_FULL_MODE_BIT 0x80
@@ -131,13 +119,12 @@ struct ps3fb_priv {
u64 context_handle, memory_handle;
void *xdr_ea;
+ size_t xdr_size;
struct gpu_driver_info *dinfo;
- u32 res_index;
u64 vblank_count; /* frame count */
wait_queue_head_t wait_vsync;
- u32 num_frames; /* num of frame buffers */
atomic_t ext_flip; /* on/off flip with vsync */
atomic_t f_count; /* fb_open count */
int is_blanked;
@@ -146,6 +133,18 @@ struct ps3fb_priv {
};
static struct ps3fb_priv ps3fb;
+struct ps3fb_par {
+ u32 pseudo_palette[16];
+ int mode_id, new_mode_id;
+ int res_index;
+ unsigned int num_frames; /* num of frame buffers */
+ unsigned int width;
+ unsigned int height;
+ unsigned long full_offset; /* start of fullscreen DDR fb */
+ unsigned long fb_offset; /* start of actual DDR fb */
+ unsigned long pan_offset;
+};
+
struct ps3fb_res_table {
u32 xres;
u32 yres;
@@ -294,29 +293,31 @@ static const struct fb_videomode ps3fb_modedb[] = {
#define Y_OFF(i) (ps3fb_res[i].yoff) /* top/bottom margin (pixel) */
#define WIDTH(i) (ps3fb_res[i].xres) /* width of FB */
#define HEIGHT(i) (ps3fb_res[i].yres) /* height of FB */
-#define BPP 4 /* number of bytes per pixel */
-#define VP_OFF(i) (WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP)
-#define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET)
+#define BPP 4 /* number of bytes per pixel */
+
+/* Start of the virtual frame buffer (relative to fullscreen ) */
+#define VP_OFF(i) ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP)
+
static int ps3fb_mode;
module_param(ps3fb_mode, int, 0);
static char *mode_option __devinitdata;
-static int ps3fb_get_res_table(u32 xres, u32 yres)
+static int ps3fb_get_res_table(u32 xres, u32 yres, int mode)
{
int full_mode;
unsigned int i;
u32 x, y, f;
- full_mode = (ps3fb_mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0;
+ full_mode = (mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0;
for (i = 0;; i++) {
x = ps3fb_res[i].xres;
y = ps3fb_res[i].yres;
f = ps3fb_res[i].type;
if (!x) {
- DPRINTK("ERROR: ps3fb_get_res_table()\n");
+ pr_debug("ERROR: ps3fb_get_res_table()\n");
return -1;
}
@@ -335,7 +336,7 @@ static int ps3fb_get_res_table(u32 xres, u32 yres)
}
static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var,
- u32 *line_length)
+ u32 *ddr_line_length, u32 *xdr_line_length)
{
unsigned int i, mode;
@@ -350,31 +351,41 @@ static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var,
var->upper_margin == ps3fb_modedb[i].upper_margin &&
var->lower_margin == ps3fb_modedb[i].lower_margin &&
var->sync == ps3fb_modedb[i].sync &&
- (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode) {
- /* Cropped broadcast modes use the full line_length */
- *line_length =
- ps3fb_modedb[i < 10 ? i + 13 : i].xres * 4;
- /* Full broadcast modes have the full mode bit set */
- mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1;
-
- DPRINTK("ps3fb_find_mode: mode %u\n", mode);
- return mode;
- }
+ (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode)
+ goto found;
- DPRINTK("ps3fb_find_mode: mode not found\n");
+ pr_debug("ps3fb_find_mode: mode not found\n");
return 0;
+found:
+ /* Cropped broadcast modes use the full line length */
+ *ddr_line_length = ps3fb_modedb[i < 10 ? i + 13 : i].xres * BPP;
+
+ if (ps3_compare_firmware_version(1, 9, 0) >= 0) {
+ *xdr_line_length = GPU_ALIGN_UP(max(var->xres,
+ var->xres_virtual) * BPP);
+ if (*xdr_line_length > GPU_MAX_LINE_LENGTH)
+ *xdr_line_length = GPU_MAX_LINE_LENGTH;
+ } else
+ *xdr_line_length = *ddr_line_length;
+
+ /* Full broadcast modes have the full mode bit set */
+ mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1;
+
+ pr_debug("ps3fb_find_mode: mode %u\n", mode);
+
+ return mode;
}
-static const struct fb_videomode *ps3fb_default_mode(void)
+static const struct fb_videomode *ps3fb_default_mode(int id)
{
- u32 mode = ps3fb_mode & PS3AV_MODE_MASK;
+ u32 mode = id & PS3AV_MODE_MASK;
u32 flags;
if (mode < 1 || mode > 13)
return NULL;
- flags = ps3fb_mode & ~PS3AV_MODE_MASK;
+ flags = id & ~PS3AV_MODE_MASK;
if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) {
/* Full broadcast mode */
@@ -384,55 +395,77 @@ static const struct fb_videomode *ps3fb_default_mode(void)
return &ps3fb_modedb[mode - 1];
}
-static int ps3fb_sync(u32 frame)
+static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
+ u64 dst_offset, u64 src_offset, u32 width,
+ u32 height, u32 dst_line_length,
+ u32 src_line_length)
{
- int i, status;
- u32 xres, yres;
- u64 fb_ioif, offset;
-
- i = ps3fb.res_index;
- xres = ps3fb_res[i].xres;
- yres = ps3fb_res[i].yres;
+ int status;
+ u64 line_length;
- if (frame > ps3fb.num_frames - 1) {
- printk(KERN_WARNING "%s: invalid frame number (%u)\n",
- __func__, frame);
- return -EINVAL;
- }
- offset = xres * yres * BPP * frame;
+ line_length = dst_line_length;
+ if (src_line_length != dst_line_length)
+ line_length |= (u64)src_line_length << 32;
- fb_ioif = GPU_IOIF + FB_OFF(i) + offset;
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
- offset, fb_ioif,
+ dst_offset, GPU_IOIF + src_offset,
L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
- (xres << 16) | yres,
- xres * BPP); /* line_length */
+ (width << 16) | height,
+ line_length);
if (status)
- printk(KERN_ERR
- "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
- __func__, status);
+ dev_err(dev,
+ "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
+ __func__, status);
#ifdef HEAD_A
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
- 0, offset, 0, 0);
+ 0, frame_offset, 0, 0);
if (status)
- printk(KERN_ERR
- "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
- __func__, status);
+ dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+ __func__, status);
#endif
#ifdef HEAD_B
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
- 1, offset, 0, 0);
+ 1, frame_offset, 0, 0);
if (status)
- printk(KERN_ERR
- "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
- __func__, status);
+ dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+ __func__, status);
#endif
- return 0;
}
+static int ps3fb_sync(struct fb_info *info, u32 frame)
+{
+ struct ps3fb_par *par = info->par;
+ int i, error = 0;
+ u32 ddr_line_length, xdr_line_length;
+ u64 ddr_base, xdr_base;
+
+ acquire_console_sem();
+
+ if (frame > par->num_frames - 1) {
+ dev_dbg(info->device, "%s: invalid frame number (%u)\n",
+ __func__, frame);
+ error = -EINVAL;
+ goto out;
+ }
+
+ i = par->res_index;
+ xdr_line_length = info->fix.line_length;
+ ddr_line_length = ps3fb_res[i].xres * BPP;
+ xdr_base = frame * info->var.yres_virtual * xdr_line_length;
+ ddr_base = frame * ps3fb_res[i].yres * ddr_line_length;
+
+ ps3fb_sync_image(info->device, ddr_base + par->full_offset,
+ ddr_base + par->fb_offset, xdr_base + par->pan_offset,
+ par->width, par->height, ddr_line_length,
+ xdr_line_length);
+
+out:
+ release_console_sem();
+ return error;
+}
static int ps3fb_open(struct fb_info *info, int user)
{
@@ -445,7 +478,7 @@ static int ps3fb_release(struct fb_info *info, int user)
if (atomic_dec_and_test(&ps3fb.f_count)) {
if (atomic_read(&ps3fb.ext_flip)) {
atomic_set(&ps3fb.ext_flip, 0);
- ps3fb_sync(0); /* single buffer */
+ ps3fb_sync(info, 0); /* single buffer */
}
}
return 0;
@@ -461,39 +494,37 @@ static int ps3fb_release(struct fb_info *info, int user)
static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
- u32 line_length;
+ u32 xdr_line_length, ddr_line_length;
int mode;
- int i;
- DPRINTK("var->xres:%u info->var.xres:%u\n", var->xres, info->var.xres);
- DPRINTK("var->yres:%u info->var.yres:%u\n", var->yres, info->var.yres);
+ dev_dbg(info->device, "var->xres:%u info->var.xres:%u\n", var->xres,
+ info->var.xres);
+ dev_dbg(info->device, "var->yres:%u info->var.yres:%u\n", var->yres,
+ info->var.yres);
/* FIXME For now we do exact matches only */
- mode = ps3fb_find_mode(var, &line_length);
+ mode = ps3fb_find_mode(var, &ddr_line_length, &xdr_line_length);
if (!mode)
return -EINVAL;
- /*
- * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
- * as FB_VMODE_SMOOTH_XPAN is only used internally
- */
+ /* Virtual screen */
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
- if (var->vmode & FB_VMODE_CONUPDATE) {
- var->vmode |= FB_VMODE_YWRAP;
- var->xoffset = info->var.xoffset;
- var->yoffset = info->var.yoffset;
+ if (var->xres_virtual > xdr_line_length / BPP) {
+ dev_dbg(info->device,
+ "Horizontal virtual screen size too large\n");
+ return -EINVAL;
}
- /* Virtual screen and panning are not supported */
- if (var->xres_virtual > var->xres || var->yres_virtual > var->yres ||
- var->xoffset || var->yoffset) {
- DPRINTK("Virtual screen and panning are not supported\n");
+ if (var->xoffset + var->xres > var->xres_virtual ||
+ var->yoffset + var->yres > var->yres_virtual) {
+ dev_dbg(info->device, "panning out-of-range\n");
return -EINVAL;
}
- var->xres_virtual = var->xres;
- var->yres_virtual = var->yres;
-
/* We support ARGB8888 only */
if (var->bits_per_pixel > 32 || var->grayscale ||
var->red.offset > 16 || var->green.offset > 8 ||
@@ -502,7 +533,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->blue.length > 8 || var->transp.length > 8 ||
var->red.msb_right || var->green.msb_right ||
var->blue.msb_right || var->transp.msb_right || var->nonstd) {
- DPRINTK("We support ARGB8888 only\n");
+ dev_dbg(info->device, "We support ARGB8888 only\n");
return -EINVAL;
}
@@ -522,14 +553,13 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
/* Rotation is not supported */
if (var->rotate) {
- DPRINTK("Rotation is not supported\n");
+ dev_dbg(info->device, "Rotation is not supported\n");
return -EINVAL;
}
/* Memory limit */
- i = ps3fb_get_res_table(var->xres, var->yres);
- if (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP > ps3fb_videomemory.size) {
- DPRINTK("Not enough memory\n");
+ if (var->yres_virtual * xdr_line_length > ps3fb.xdr_size) {
+ dev_dbg(info->device, "Not enough memory\n");
return -ENOMEM;
}
@@ -545,36 +575,69 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
static int ps3fb_set_par(struct fb_info *info)
{
- unsigned int mode;
+ struct ps3fb_par *par = info->par;
+ unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines;
int i;
unsigned long offset;
- static int first = 1;
+ u64 dst;
- DPRINTK("xres:%d xv:%d yres:%d yv:%d clock:%d\n",
+ dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n",
info->var.xres, info->var.xres_virtual,
info->var.yres, info->var.yres_virtual, info->var.pixclock);
- i = ps3fb_get_res_table(info->var.xres, info->var.yres);
- ps3fb.res_index = i;
- mode = ps3fb_find_mode(&info->var, &info->fix.line_length);
+ mode = ps3fb_find_mode(&info->var, &ddr_line_length, &xdr_line_length);
if (!mode)
return -EINVAL;
- offset = FB_OFF(i) + VP_OFF(i);
- info->fix.smem_len = ps3fb_videomemory.size - offset;
- info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
- memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
+ i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode);
+ par->res_index = i;
+
+ info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
+ info->fix.smem_len = ps3fb.xdr_size;
+ info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
+ info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
+ info->fix.line_length = xdr_line_length;
+
+ info->screen_base = (char __iomem *)ps3fb.xdr_ea;
- ps3fb.num_frames = ps3fb_videomemory.size/
- (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP);
+ par->num_frames = ps3fb.xdr_size /
+ max(ps3fb_res[i].yres * ddr_line_length,
+ info->var.yres_virtual * xdr_line_length);
/* Keep the special bits we cannot set using fb_var_screeninfo */
- ps3fb_mode = (ps3fb_mode & ~PS3AV_MODE_MASK) | mode;
+ par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode;
+
+ par->width = info->var.xres;
+ par->height = info->var.yres;
+ offset = VP_OFF(i);
+ par->fb_offset = GPU_ALIGN_UP(offset);
+ par->full_offset = par->fb_offset - offset;
+ par->pan_offset = info->var.yoffset * xdr_line_length +
+ info->var.xoffset * BPP;
+
+ if (par->new_mode_id != par->mode_id) {
+ if (ps3av_set_video_mode(par->new_mode_id)) {
+ par->new_mode_id = par->mode_id;
+ return -EINVAL;
+ }
+ par->mode_id = par->new_mode_id;
+ }
- if (ps3av_set_video_mode(ps3fb_mode, first))
- return -EINVAL;
+ /* Clear XDR frame buffer memory */
+ memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size);
+
+ /* Clear DDR frame buffer memory */
+ lines = ps3fb_res[i].yres * par->num_frames;
+ if (par->full_offset)
+ lines++;
+ maxlines = ps3fb.xdr_size / ddr_line_length;
+ for (dst = 0; lines; dst += maxlines * ddr_line_length) {
+ unsigned int l = min(lines, maxlines);
+ ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l,
+ ddr_line_length, ddr_line_length);
+ lines -= l;
+ }
- first = 0;
return 0;
}
@@ -601,6 +664,16 @@ static int ps3fb_setcolreg(unsigned int regno, unsigned int red,
return 0;
}
+static int ps3fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct ps3fb_par *par = info->par;
+
+ par->pan_offset = var->yoffset * info->fix.line_length +
+ var->xoffset * BPP;
+ return 0;
+}
+
/*
* As we have a virtual frame buffer, we need our own mmap function
*/
@@ -608,24 +681,19 @@ static int ps3fb_setcolreg(unsigned int regno, unsigned int red,
static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
unsigned long size, offset;
- int i;
-
- i = ps3fb_get_res_table(info->var.xres, info->var.yres);
- if (i == -1)
- return -EINVAL;
size = vma->vm_end - vma->vm_start;
offset = vma->vm_pgoff << PAGE_SHIFT;
if (offset + size > info->fix.smem_len)
return -EINVAL;
- offset += info->fix.smem_start + FB_OFF(i) + VP_OFF(i);
+ offset += info->fix.smem_start;
if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
size, vma->vm_page_prot))
return -EAGAIN;
- printk(KERN_DEBUG "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n", offset,
- vma->vm_start);
+ dev_dbg(info->device, "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n",
+ offset, vma->vm_start);
return 0;
}
@@ -637,7 +705,7 @@ static int ps3fb_blank(int blank, struct fb_info *info)
{
int retval;
- DPRINTK("%s: blank:%d\n", __func__, blank);
+ dev_dbg(info->device, "%s: blank:%d\n", __func__, blank);
switch (blank) {
case FB_BLANK_POWERDOWN:
case FB_BLANK_HSYNC_SUSPEND:
@@ -659,12 +727,12 @@ static int ps3fb_blank(int blank, struct fb_info *info)
static int ps3fb_get_vblank(struct fb_vblank *vblank)
{
- memset(vblank, 0, sizeof(&vblank));
+ memset(vblank, 0, sizeof(*vblank));
vblank->flags = FB_VBLANK_HAVE_VSYNC;
return 0;
}
-int ps3fb_wait_for_vsync(u32 crtc)
+static int ps3fb_wait_for_vsync(u32 crtc)
{
int ret;
u64 count;
@@ -679,9 +747,7 @@ int ps3fb_wait_for_vsync(u32 crtc)
return 0;
}
-EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync);
-
-void ps3fb_flip_ctl(int on, void *data)
+static void ps3fb_flip_ctl(int on, void *data)
{
struct ps3fb_priv *priv = data;
if (on)
@@ -699,14 +765,14 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
- u32 val, old_mode;
+ u32 val;
int retval = -EFAULT;
switch (cmd) {
case FBIOGET_VBLANK:
{
struct fb_vblank vblank;
- DPRINTK("FBIOGET_VBLANK:\n");
+ dev_dbg(info->device, "FBIOGET_VBLANK:\n");
retval = ps3fb_get_vblank(&vblank);
if (retval)
break;
@@ -719,7 +785,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
case FBIO_WAITFORVSYNC:
{
u32 crt;
- DPRINTK("FBIO_WAITFORVSYNC:\n");
+ dev_dbg(info->device, "FBIO_WAITFORVSYNC:\n");
if (get_user(crt, (u32 __user *) arg))
break;
@@ -729,6 +795,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
case PS3FB_IOCTL_SETMODE:
{
+ struct ps3fb_par *par = info->par;
const struct fb_videomode *mode;
struct fb_var_screeninfo var;
@@ -736,15 +803,13 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
break;
if (!(val & PS3AV_MODE_MASK)) {
- u32 id = ps3av_get_auto_mode(0);
+ u32 id = ps3av_get_auto_mode();
if (id > 0)
val = (val & ~PS3AV_MODE_MASK) | id;
}
- DPRINTK("PS3FB_IOCTL_SETMODE:%x\n", val);
+ dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val);
retval = -EINVAL;
- old_mode = ps3fb_mode;
- ps3fb_mode = val;
- mode = ps3fb_default_mode();
+ mode = ps3fb_default_mode(val);
if (mode) {
var = info->var;
fb_videomode_to_var(&var, mode);
@@ -752,45 +817,44 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
info->flags |= FBINFO_MISC_USEREVENT;
/* Force, in case only special bits changed */
var.activate |= FB_ACTIVATE_FORCE;
+ par->new_mode_id = val;
retval = fb_set_var(info, &var);
info->flags &= ~FBINFO_MISC_USEREVENT;
release_console_sem();
}
- if (retval)
- ps3fb_mode = old_mode;
break;
}
case PS3FB_IOCTL_GETMODE:
val = ps3av_get_mode();
- DPRINTK("PS3FB_IOCTL_GETMODE:%x\n", val);
+ dev_dbg(info->device, "PS3FB_IOCTL_GETMODE:%x\n", val);
if (!copy_to_user(argp, &val, sizeof(val)))
retval = 0;
break;
case PS3FB_IOCTL_SCREENINFO:
{
+ struct ps3fb_par *par = info->par;
struct ps3fb_ioctl_res res;
- int i = ps3fb.res_index;
- DPRINTK("PS3FB_IOCTL_SCREENINFO:\n");
- res.xres = ps3fb_res[i].xres;
- res.yres = ps3fb_res[i].yres;
- res.xoff = ps3fb_res[i].xoff;
- res.yoff = ps3fb_res[i].yoff;
- res.num_frames = ps3fb.num_frames;
+ dev_dbg(info->device, "PS3FB_IOCTL_SCREENINFO:\n");
+ res.xres = info->fix.line_length / BPP;
+ res.yres = info->var.yres_virtual;
+ res.xoff = (res.xres - info->var.xres) / 2;
+ res.yoff = (res.yres - info->var.yres) / 2;
+ res.num_frames = par->num_frames;
if (!copy_to_user(argp, &res, sizeof(res)))
retval = 0;
break;
}
case PS3FB_IOCTL_ON:
- DPRINTK("PS3FB_IOCTL_ON:\n");
+ dev_dbg(info->device, "PS3FB_IOCTL_ON:\n");
atomic_inc(&ps3fb.ext_flip);
retval = 0;
break;
case PS3FB_IOCTL_OFF:
- DPRINTK("PS3FB_IOCTL_OFF:\n");
+ dev_dbg(info->device, "PS3FB_IOCTL_OFF:\n");
atomic_dec_if_positive(&ps3fb.ext_flip);
retval = 0;
break;
@@ -799,8 +863,8 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
if (copy_from_user(&val, argp, sizeof(val)))
break;
- DPRINTK("PS3FB_IOCTL_FSEL:%d\n", val);
- retval = ps3fb_sync(val);
+ dev_dbg(info->device, "PS3FB_IOCTL_FSEL:%d\n", val);
+ retval = ps3fb_sync(info, val);
break;
default:
@@ -812,13 +876,15 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
static int ps3fbd(void *arg)
{
+ struct fb_info *info = arg;
+
set_freezable();
while (!kthread_should_stop()) {
try_to_freeze();
set_current_state(TASK_INTERRUPTIBLE);
if (ps3fb.is_kicked) {
ps3fb.is_kicked = 0;
- ps3fb_sync(0); /* single buffer */
+ ps3fb_sync(info, 0); /* single buffer */
}
schedule();
}
@@ -827,14 +893,15 @@ static int ps3fbd(void *arg)
static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
{
+ struct device *dev = ptr;
u64 v1;
int status;
struct display_head *head = &ps3fb.dinfo->display_head[1];
status = lv1_gpu_context_intr(ps3fb.context_handle, &v1);
if (status) {
- printk(KERN_ERR "%s: lv1_gpu_context_intr failed: %d\n",
- __func__, status);
+ dev_err(dev, "%s: lv1_gpu_context_intr failed: %d\n", __func__,
+ status);
return IRQ_NONE;
}
@@ -854,35 +921,35 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo,
- struct ps3_system_bus_device *dev)
+ struct device *dev)
{
int error;
- DPRINTK("version_driver:%x\n", dinfo->version_driver);
- DPRINTK("irq outlet:%x\n", dinfo->irq.irq_outlet);
- DPRINTK("version_gpu:%x memory_size:%x ch:%x core_freq:%d mem_freq:%d\n",
+ dev_dbg(dev, "version_driver:%x\n", dinfo->version_driver);
+ dev_dbg(dev, "irq outlet:%x\n", dinfo->irq.irq_outlet);
+ dev_dbg(dev,
+ "version_gpu: %x memory_size: %x ch: %x core_freq: %d "
+ "mem_freq:%d\n",
dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel,
dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000);
if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
- printk(KERN_ERR "%s: version_driver err:%x\n", __func__,
- dinfo->version_driver);
+ dev_err(dev, "%s: version_driver err:%x\n", __func__,
+ dinfo->version_driver);
return -EINVAL;
}
error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
&ps3fb.irq_no);
if (error) {
- printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __func__,
- error);
+ dev_err(dev, "%s: ps3_alloc_irq failed %d\n", __func__, error);
return error;
}
error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
DEVICE_NAME, dev);
if (error) {
- printk(KERN_ERR "%s: request_irq failed %d\n", __func__,
- error);
+ dev_err(dev, "%s: request_irq failed %d\n", __func__, error);
ps3_irq_plug_destroy(ps3fb.irq_no);
return error;
}
@@ -892,29 +959,31 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo,
return 0;
}
-static int ps3fb_xdr_settings(u64 xdr_lpar)
+static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev)
{
int status;
status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF,
xdr_lpar, ps3fb_videomemory.size, 0);
if (status) {
- printk(KERN_ERR "%s: lv1_gpu_context_iomap failed: %d\n",
- __func__, status);
+ dev_err(dev, "%s: lv1_gpu_context_iomap failed: %d\n",
+ __func__, status);
return -ENXIO;
}
- DPRINTK("video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
+ dev_dbg(dev,
+ "video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
ps3fb_videomemory.address, ps3fb.xdr_ea, GPU_IOIF, xdr_lpar,
virt_to_abs(ps3fb.xdr_ea), ps3fb_videomemory.size);
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
- xdr_lpar, ps3fb_videomemory.size,
- GPU_IOIF, 0);
+ xdr_lpar + ps3fb.xdr_size,
+ GPU_CMD_BUF_SIZE,
+ GPU_IOIF + ps3fb.xdr_size, 0);
if (status) {
- printk(KERN_ERR
- "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
- __func__, status);
+ dev_err(dev,
+ "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
+ __func__, status);
return -ENXIO;
}
return 0;
@@ -928,6 +997,7 @@ static struct fb_ops ps3fb_ops = {
.fb_check_var = ps3fb_check_var,
.fb_set_par = ps3fb_set_par,
.fb_setcolreg = ps3fb_setcolreg,
+ .fb_pan_display = ps3fb_pan_display,
.fb_fillrect = sys_fillrect,
.fb_copyarea = sys_copyarea,
.fb_imageblit = sys_imageblit,
@@ -944,7 +1014,7 @@ static struct fb_fix_screeninfo ps3fb_fix __initdata = {
.accel = FB_ACCEL_NONE,
};
-static int ps3fb_set_sync(void)
+static int ps3fb_set_sync(struct device *dev)
{
int status;
@@ -953,8 +1023,10 @@ static int ps3fb_set_sync(void)
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
if (status) {
- printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC "
- "failed: %d\n", __func__, status);
+ dev_err(dev,
+ "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: "
+ "%d\n",
+ __func__, status);
return -1;
}
#endif
@@ -964,8 +1036,10 @@ static int ps3fb_set_sync(void)
1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
if (status) {
- printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE "
- "failed: %d\n", __func__, status);
+ dev_err(dev,
+ "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: "
+ "%d\n",
+ __func__, status);
return -1;
}
#endif
@@ -975,6 +1049,7 @@ static int ps3fb_set_sync(void)
static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
{
struct fb_info *info;
+ struct ps3fb_par *par;
int retval = -ENOMEM;
u32 xres, yres;
u64 ddr_lpar = 0;
@@ -983,98 +1058,106 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
u64 lpar_reports = 0;
u64 lpar_reports_size = 0;
u64 xdr_lpar;
- int status;
- unsigned long offset;
+ int status, res_index;
struct task_struct *task;
status = ps3_open_hv_device(dev);
if (status) {
- printk(KERN_ERR "%s: ps3_open_hv_device failed\n", __func__);
+ dev_err(&dev->core, "%s: ps3_open_hv_device failed\n",
+ __func__);
goto err;
}
if (!ps3fb_mode)
ps3fb_mode = ps3av_get_mode();
- DPRINTK("ps3av_mode:%d\n", ps3fb_mode);
+ dev_dbg(&dev->core, "ps3av_mode:%d\n", ps3fb_mode);
if (ps3fb_mode > 0 &&
!ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
- ps3fb.res_index = ps3fb_get_res_table(xres, yres);
- DPRINTK("res_index:%d\n", ps3fb.res_index);
+ res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode);
+ dev_dbg(&dev->core, "res_index:%d\n", res_index);
} else
- ps3fb.res_index = GPU_RES_INDEX;
+ res_index = GPU_RES_INDEX;
atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
init_waitqueue_head(&ps3fb.wait_vsync);
- ps3fb.num_frames = 1;
- ps3fb_set_sync();
+ ps3fb_set_sync(&dev->core);
/* get gpu context handle */
status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0,
&ps3fb.memory_handle, &ddr_lpar);
if (status) {
- printk(KERN_ERR "%s: lv1_gpu_memory_allocate failed: %d\n",
- __func__, status);
+ dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n",
+ __func__, status);
goto err;
}
- DPRINTK("ddr:lpar:0x%lx\n", ddr_lpar);
+ dev_dbg(&dev->core, "ddr:lpar:0x%lx\n", ddr_lpar);
status = lv1_gpu_context_allocate(ps3fb.memory_handle, 0,
&ps3fb.context_handle,
&lpar_dma_control, &lpar_driver_info,
&lpar_reports, &lpar_reports_size);
if (status) {
- printk(KERN_ERR "%s: lv1_gpu_context_attribute failed: %d\n",
- __func__, status);
+ dev_err(&dev->core,
+ "%s: lv1_gpu_context_attribute failed: %d\n", __func__,
+ status);
goto err_gpu_memory_free;
}
/* vsync interrupt */
ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024);
if (!ps3fb.dinfo) {
- printk(KERN_ERR "%s: ioremap failed\n", __func__);
+ dev_err(&dev->core, "%s: ioremap failed\n", __func__);
goto err_gpu_context_free;
}
- retval = ps3fb_vsync_settings(ps3fb.dinfo, dev);
+ retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core);
if (retval)
goto err_iounmap_dinfo;
- /* xdr frame buffer */
+ /* XDR frame buffer */
ps3fb.xdr_ea = ps3fb_videomemory.address;
xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb.xdr_ea));
- retval = ps3fb_xdr_settings(xdr_lpar);
+
+ /* Clear memory to prevent kernel info leakage into userspace */
+ memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
+
+ /* The GPU command buffer is at the end of video memory */
+ ps3fb.xdr_size = ps3fb_videomemory.size - GPU_CMD_BUF_SIZE;
+
+ retval = ps3fb_xdr_settings(xdr_lpar, &dev->core);
if (retval)
goto err_free_irq;
- /*
- * ps3fb must clear memory to prevent kernel info
- * leakage into userspace
- */
- memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
- info = framebuffer_alloc(sizeof(u32) * 16, &dev->core);
+ info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
if (!info)
goto err_free_irq;
- offset = FB_OFF(ps3fb.res_index) + VP_OFF(ps3fb.res_index);
- info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
+ par = info->par;
+ par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */
+ par->new_mode_id = ps3fb_mode;
+ par->res_index = res_index;
+ par->num_frames = 1;
+
+ info->screen_base = (char __iomem *)ps3fb.xdr_ea;
info->fbops = &ps3fb_ops;
info->fix = ps3fb_fix;
info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
- info->fix.smem_len = ps3fb_videomemory.size - offset;
- info->pseudo_palette = info->par;
- info->par = NULL;
- info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST;
+ info->fix.smem_len = ps3fb.xdr_size;
+ info->pseudo_palette = par->pseudo_palette;
+ info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
+ FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
retval = fb_alloc_cmap(&info->cmap, 256, 0);
if (retval < 0)
goto err_framebuffer_release;
if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb,
- ARRAY_SIZE(ps3fb_modedb), ps3fb_default_mode(), 32)) {
+ ARRAY_SIZE(ps3fb_modedb),
+ ps3fb_default_mode(par->new_mode_id), 32)) {
retval = -EINVAL;
goto err_fb_dealloc;
}
@@ -1088,9 +1171,9 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
dev->core.driver_data = info;
- printk(KERN_INFO
- "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n",
- info->node, ps3fb_videomemory.size >> 10);
+ dev_info(info->device, "%s %s, using %lu KiB of video memory\n",
+ dev_driver_string(info->dev), info->dev->bus_id,
+ ps3fb.xdr_size >> 10);
task = kthread_run(ps3fbd, info, DEVICE_NAME);
if (IS_ERR(task)) {
@@ -1127,7 +1210,7 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
int status;
struct fb_info *info = dev->core.driver_data;
- DPRINTK(" -> %s:%d\n", __func__, __LINE__);
+ dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
ps3fb_flip_ctl(0, &ps3fb); /* flip off */
ps3fb.dinfo->irq.mask = 0;
@@ -1152,14 +1235,16 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
status = lv1_gpu_context_free(ps3fb.context_handle);
if (status)
- DPRINTK("lv1_gpu_context_free failed: %d\n", status);
+ dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n",
+ status);
status = lv1_gpu_memory_free(ps3fb.memory_handle);
if (status)
- DPRINTK("lv1_gpu_memory_free failed: %d\n", status);
+ dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n",
+ status);
ps3_close_hv_device(dev);
- DPRINTK(" <- %s:%d\n", __func__, __LINE__);
+ dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
return 0;
}
@@ -1212,9 +1297,9 @@ static int __init ps3fb_init(void)
static void __exit ps3fb_exit(void)
{
- DPRINTK(" -> %s:%d\n", __func__, __LINE__);
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
ps3_system_bus_driver_unregister(&ps3fb_driver);
- DPRINTK(" <- %s:%d\n", __func__, __LINE__);
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
}
module_init(ps3fb_init);
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index 7d6c29800d1..6a3d0b57489 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -72,7 +72,7 @@
#endif
#ifdef CONFIG_SH_STORE_QUEUES
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/cpu/sq.h>
#endif
@@ -667,6 +667,8 @@ static int pvr2_init_cable(void)
related */
if (cable_type == CT_COMPOSITE)
fb_writel(3 << 8, VOUTC);
+ else if (cable_type == CT_RGB)
+ fb_writel(1 << 9, VOUTC);
else
fb_writel(0, VOUTC);
@@ -890,7 +892,7 @@ static int __init pvr2fb_dc_init(void)
pvr2_fix.mmio_start = 0xa05f8000; /* registers start here */
pvr2_fix.mmio_len = 0x2000;
- if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0,
+ if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, IRQF_SHARED,
"pvr2 VBL handler", fb_info)) {
return -EBUSY;
}
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index a280a52f8ef..10f912df2da 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -37,11 +37,12 @@
#include <linux/cpufreq.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/uaccess.h>
#include <asm/div64.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/bitfield.h>
@@ -106,20 +107,38 @@ pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
u_int trans, struct fb_info *info)
{
struct pxafb_info *fbi = (struct pxafb_info *)info;
- u_int val, ret = 1;
+ u_int val;
- if (regno < fbi->palette_size) {
- if (fbi->fb.var.grayscale) {
- val = ((blue >> 8) & 0x00ff);
- } else {
- val = ((red >> 0) & 0xf800);
- val |= ((green >> 5) & 0x07e0);
- val |= ((blue >> 11) & 0x001f);
- }
+ if (regno >= fbi->palette_size)
+ return 1;
+
+ if (fbi->fb.var.grayscale) {
+ fbi->palette_cpu[regno] = ((blue >> 8) & 0x00ff);
+ return 0;
+ }
+
+ switch (fbi->lccr4 & LCCR4_PAL_FOR_MASK) {
+ case LCCR4_PAL_FOR_0:
+ val = ((red >> 0) & 0xf800);
+ val |= ((green >> 5) & 0x07e0);
+ val |= ((blue >> 11) & 0x001f);
fbi->palette_cpu[regno] = val;
- ret = 0;
+ break;
+ case LCCR4_PAL_FOR_1:
+ val = ((red << 8) & 0x00f80000);
+ val |= ((green >> 0) & 0x0000fc00);
+ val |= ((blue >> 8) & 0x000000f8);
+ ((u32*)(fbi->palette_cpu))[regno] = val;
+ break;
+ case LCCR4_PAL_FOR_2:
+ val = ((red << 8) & 0x00fc0000);
+ val |= ((green >> 0) & 0x0000fc00);
+ val |= ((blue >> 8) & 0x000000fc);
+ ((u32*)(fbi->palette_cpu))[regno] = val;
+ break;
}
- return ret;
+
+ return 0;
}
static int
@@ -361,7 +380,10 @@ static int pxafb_set_par(struct fb_info *info)
else
fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
- palette_mem_size = fbi->palette_size * sizeof(u16);
+ if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
+ palette_mem_size = fbi->palette_size * sizeof(u16);
+ else
+ palette_mem_size = fbi->palette_size * sizeof(u32);
pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size);
@@ -506,15 +528,15 @@ static struct fb_ops pxafb_ops = {
*
* Factoring the 10^4 and 10^-12 out gives 10^-8 == 1 / 100000000 as used below.
*/
-static inline unsigned int get_pcd(unsigned int pixclock)
+static inline unsigned int get_pcd(struct pxafb_info *fbi, unsigned int pixclock)
{
unsigned long long pcd;
/* FIXME: Need to take into account Double Pixel Clock mode
- * (DPC) bit? or perhaps set it based on the various clock
- * speeds */
-
- pcd = (unsigned long long)get_lcdclk_frequency_10khz() * pixclock;
+ * (DPC) bit? or perhaps set it based on the various clock
+ * speeds */
+ pcd = (unsigned long long)(clk_get_rate(fbi->clk) / 10000);
+ pcd *= pixclock;
do_div(pcd, 100000000 * 2);
/* no need for this, since we should subtract 1 anyway. they cancel */
/* pcd += 1; */ /* make up for integer math truncations */
@@ -523,19 +545,21 @@ static inline unsigned int get_pcd(unsigned int pixclock)
/*
* Some touchscreens need hsync information from the video driver to
- * function correctly. We export it here.
+ * function correctly. We export it here. Note that 'hsync_time' and
+ * the value returned from pxafb_get_hsync_time() is the *reciprocal*
+ * of the hsync period in seconds.
*/
static inline void set_hsync_time(struct pxafb_info *fbi, unsigned int pcd)
{
- unsigned long long htime;
+ unsigned long htime;
if ((pcd == 0) || (fbi->fb.var.hsync_len == 0)) {
fbi->hsync_time=0;
return;
}
- htime = (unsigned long long)get_lcdclk_frequency_10khz() * 10000;
- do_div(htime, pcd * fbi->fb.var.hsync_len);
+ htime = clk_get_rate(fbi->clk) / (pcd * fbi->fb.var.hsync_len);
+
fbi->hsync_time = htime;
}
@@ -560,7 +584,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *
{
struct pxafb_lcd_reg new_regs;
u_long flags;
- u_int lines_per_panel, pcd = get_pcd(var->pixclock);
+ u_int lines_per_panel, pcd = get_pcd(fbi, var->pixclock);
pr_debug("pxafb: Configuring PXA LCD\n");
@@ -676,7 +700,13 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *
fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma;
fbi->dmadesc_palette_cpu->fidr = 0;
- fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL;
+ if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
+ fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size *
+ sizeof(u16);
+ else
+ fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size *
+ sizeof(u32);
+ fbi->dmadesc_palette_cpu->ldcmd |= LDCMD_PAL;
if (var->bits_per_pixel == 16) {
/* palette shouldn't be loaded in true-color mode */
@@ -715,6 +745,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *
fbi->reg_lccr1 = new_regs.lccr1;
fbi->reg_lccr2 = new_regs.lccr2;
fbi->reg_lccr3 = new_regs.lccr3;
+ fbi->reg_lccr4 = LCCR4 & (~LCCR4_PAL_FOR_MASK);
+ fbi->reg_lccr4 |= (fbi->lccr4 & LCCR4_PAL_FOR_MASK);
set_hsync_time(fbi, pcd);
local_irq_restore(flags);
@@ -803,7 +835,7 @@ static void pxafb_enable_controller(struct pxafb_info *fbi)
pr_debug("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3);
/* enable LCD controller clock */
- pxa_set_cken(CKEN_LCD, 1);
+ clk_enable(fbi->clk);
/* Sequence from 11.7.10 */
LCCR3 = fbi->reg_lccr3;
@@ -821,6 +853,7 @@ static void pxafb_enable_controller(struct pxafb_info *fbi)
pr_debug("LCCR1 0x%08x\n", (unsigned int) LCCR1);
pr_debug("LCCR2 0x%08x\n", (unsigned int) LCCR2);
pr_debug("LCCR3 0x%08x\n", (unsigned int) LCCR3);
+ pr_debug("LCCR4 0x%08x\n", (unsigned int) LCCR4);
}
static void pxafb_disable_controller(struct pxafb_info *fbi)
@@ -840,7 +873,7 @@ static void pxafb_disable_controller(struct pxafb_info *fbi)
remove_wait_queue(&fbi->ctrlr_wait, &wait);
/* disable LCD controller clock */
- pxa_set_cken(CKEN_LCD, 0);
+ clk_disable(fbi->clk);
}
/*
@@ -994,7 +1027,7 @@ pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
break;
case CPUFREQ_POSTCHANGE:
- pcd = get_pcd(fbi->fb.var.pixclock);
+ pcd = get_pcd(fbi, fbi->fb.var.pixclock);
set_hsync_time(fbi, pcd);
fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
@@ -1090,10 +1123,13 @@ static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
* dma_writecombine_mmap)
*/
fbi->fb.fix.smem_start = fbi->screen_dma;
-
fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;
- palette_mem_size = fbi->palette_size * sizeof(u16);
+ if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
+ palette_mem_size = fbi->palette_size * sizeof(u16);
+ else
+ palette_mem_size = fbi->palette_size * sizeof(u32);
+
pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size);
fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
@@ -1119,6 +1155,12 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
memset(fbi, 0, sizeof(struct pxafb_info));
fbi->dev = dev;
+ fbi->clk = clk_get(dev, "LCDCLK");
+ if (IS_ERR(fbi->clk)) {
+ kfree(fbi);
+ return NULL;
+ }
+
strcpy(fbi->fb.fix.id, PXA_NAME);
fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
@@ -1150,6 +1192,7 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
fbi->lccr0 = inf->lccr0;
fbi->lccr3 = inf->lccr3;
+ fbi->lccr4 = inf->lccr4;
fbi->state = C_STARTUP;
fbi->task_state = (u_char)-1;
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h
index 7499a1c4bf7..d920b8a14c3 100644
--- a/drivers/video/pxafb.h
+++ b/drivers/video/pxafb.h
@@ -40,6 +40,7 @@ struct pxafb_dma_descriptor {
struct pxafb_info {
struct fb_info fb;
struct device *dev;
+ struct clk *clk;
/*
* These are the addresses we mapped
@@ -70,6 +71,7 @@ struct pxafb_info {
u_int lccr0;
u_int lccr3;
+ u_int lccr4;
u_int cmap_inverse:1,
cmap_static:1,
unused:30;
@@ -78,6 +80,7 @@ struct pxafb_info {
u_int reg_lccr1;
u_int reg_lccr2;
u_int reg_lccr3;
+ u_int reg_lccr4;
unsigned long hsync_time;
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
index a5333c19078..b829dc7c5ed 100644
--- a/drivers/video/s1d13xxxfb.c
+++ b/drivers/video/s1d13xxxfb.c
@@ -540,7 +540,7 @@ s1d13xxxfb_probe(struct platform_device *pdev)
int ret = 0;
u8 revision;
- dbg("probe called: device is %p\n", dev);
+ dbg("probe called: device is %p\n", pdev);
printk(KERN_INFO "Epson S1D13XXX FB Driver\n");
@@ -753,8 +753,11 @@ static struct platform_driver s1d13xxxfb_driver = {
static int __init
s1d13xxxfb_init(void)
{
+
+#ifndef MODULE
if (fb_get_options("s1d13xxxfb", NULL))
return -ENODEV;
+#endif
return platform_driver_register(&s1d13xxxfb_driver);
}
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 8a4c6470d79..5857ccf5f6b 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -20,7 +20,7 @@
*
* 2004-12-04: Arnaud Patard <arnaud.patard@rtp-net.org>
* - Added the possibility to set on or off the
- * debugging mesaages
+ * debugging messages
* - Replaced 0 and 1 by on or off when reading the
* /sys files
*
@@ -31,8 +31,8 @@
* - add pixel clock divisor control
*
* 2004-11-11: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - Removed the use of currcon as it no more exist
- * - Added LCD power sysfs interface
+ * - Removed the use of currcon as it no more exists
+ * - Added LCD power sysfs interface
*
* 2004-11-03: Ben Dooks <ben-linux@fluff.org>
* - minor cleanups
@@ -49,14 +49,14 @@
* - Suppress command line options
*
* 2004-09-15: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - code cleanup
+ * - code cleanup
*
* 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org>
- * - Renamed from h1940fb.c to s3c2410fb.c
- * - Add support for different devices
- * - Backlight support
+ * - Renamed from h1940fb.c to s3c2410fb.c
+ * - Add support for different devices
+ * - Backlight support
*
- * 2004-09-05: Herbert Pötzl <herbert@13thfloor.at>
+ * 2004-09-05: Herbert Pötzl <herbert@13thfloor.at>
* - added clock (de-)allocation code
* - added fixem fbmem option
*
@@ -64,7 +64,7 @@
* - code cleanup
* - added a forgotten return in h1940fb_init
*
- * 2004-07-19: Herbert Pötzl <herbert@13thfloor.at>
+ * 2004-07-19: Herbert Pötzl <herbert@13thfloor.at>
* - code cleanup and extended debugging
*
* 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org>
@@ -82,13 +82,10 @@
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
#include <asm/div64.h>
#include <asm/mach/map.h>
@@ -102,14 +99,11 @@
#include "s3c2410fb.h"
-
-static struct s3c2410fb_mach_info *mach_info;
-
/* Debugging stuff */
#ifdef CONFIG_FB_S3C2410_DEBUG
-static int debug = 1;
+static int debug = 1;
#else
-static int debug = 0;
+static int debug = 0;
#endif
#define dprintk(msg...) if (debug) { printk(KERN_DEBUG "s3c2410fb: " msg); }
@@ -119,48 +113,48 @@ static int debug = 0;
/* s3c2410fb_set_lcdaddr
*
* initialise lcd controller address pointers
-*/
-
-static void s3c2410fb_set_lcdaddr(struct s3c2410fb_info *fbi)
+ */
+static void s3c2410fb_set_lcdaddr(struct fb_info *info)
{
- struct fb_var_screeninfo *var = &fbi->fb->var;
unsigned long saddr1, saddr2, saddr3;
+ struct s3c2410fb_info *fbi = info->par;
+ void __iomem *regs = fbi->io;
- saddr1 = fbi->fb->fix.smem_start >> 1;
- saddr2 = fbi->fb->fix.smem_start;
- saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8;
- saddr2>>= 1;
+ saddr1 = info->fix.smem_start >> 1;
+ saddr2 = info->fix.smem_start;
+ saddr2 += info->fix.line_length * info->var.yres;
+ saddr2 >>= 1;
- saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((var->xres * var->bits_per_pixel / 16) & 0x3ff);
+ saddr3 = S3C2410_OFFSIZE(0) |
+ S3C2410_PAGEWIDTH((info->fix.line_length / 2) & 0x3ff);
dprintk("LCDSADDR1 = 0x%08lx\n", saddr1);
dprintk("LCDSADDR2 = 0x%08lx\n", saddr2);
dprintk("LCDSADDR3 = 0x%08lx\n", saddr3);
- writel(saddr1, S3C2410_LCDSADDR1);
- writel(saddr2, S3C2410_LCDSADDR2);
- writel(saddr3, S3C2410_LCDSADDR3);
+ writel(saddr1, regs + S3C2410_LCDSADDR1);
+ writel(saddr2, regs + S3C2410_LCDSADDR2);
+ writel(saddr3, regs + S3C2410_LCDSADDR3);
}
/* s3c2410fb_calc_pixclk()
*
* calculate divisor for clk->pixclk
-*/
-
+ */
static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi,
unsigned long pixclk)
{
unsigned long clk = clk_get_rate(fbi->clk);
unsigned long long div;
- /* pixclk is in picoseoncds, our clock is in Hz
+ /* pixclk is in picoseconds, our clock is in Hz
*
* Hz -> picoseconds is / 10^-12
*/
div = (unsigned long long)clk * pixclk;
- do_div(div,1000000UL);
- do_div(div,1000000UL);
+ div >>= 12; /* div / 2^12 */
+ do_div(div, 625 * 625UL * 625); /* div / 5^12 */
dprintk("pixclk %ld, divisor is %ld\n", pixclk, (long)div);
return div;
@@ -176,246 +170,278 @@ static int s3c2410fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct s3c2410fb_info *fbi = info->par;
+ struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;
+ struct s3c2410fb_display *display = NULL;
+ struct s3c2410fb_display *default_display = mach_info->displays +
+ mach_info->default_display;
+ int type = default_display->type;
+ unsigned i;
dprintk("check_var(var=%p, info=%p)\n", var, info);
/* validate x/y resolution */
+ /* choose default mode if possible */
+ if (var->yres == default_display->yres &&
+ var->xres == default_display->xres &&
+ var->bits_per_pixel == default_display->bpp)
+ display = default_display;
+ else
+ for (i = 0; i < mach_info->num_displays; i++)
+ if (type == mach_info->displays[i].type &&
+ var->yres == mach_info->displays[i].yres &&
+ var->xres == mach_info->displays[i].xres &&
+ var->bits_per_pixel == mach_info->displays[i].bpp) {
+ display = mach_info->displays + i;
+ break;
+ }
- if (var->yres > fbi->mach_info->yres.max)
- var->yres = fbi->mach_info->yres.max;
- else if (var->yres < fbi->mach_info->yres.min)
- var->yres = fbi->mach_info->yres.min;
-
- if (var->xres > fbi->mach_info->xres.max)
- var->yres = fbi->mach_info->xres.max;
- else if (var->xres < fbi->mach_info->xres.min)
- var->xres = fbi->mach_info->xres.min;
-
- /* validate bpp */
-
- if (var->bits_per_pixel > fbi->mach_info->bpp.max)
- var->bits_per_pixel = fbi->mach_info->bpp.max;
- else if (var->bits_per_pixel < fbi->mach_info->bpp.min)
- var->bits_per_pixel = fbi->mach_info->bpp.min;
+ if (!display) {
+ dprintk("wrong resolution or depth %dx%d at %d bpp\n",
+ var->xres, var->yres, var->bits_per_pixel);
+ return -EINVAL;
+ }
+ /* it is always the size as the display */
+ var->xres_virtual = display->xres;
+ var->yres_virtual = display->yres;
+ var->height = display->height;
+ var->width = display->width;
+
+ /* copy lcd settings */
+ var->pixclock = display->pixclock;
+ var->left_margin = display->left_margin;
+ var->right_margin = display->right_margin;
+ var->upper_margin = display->upper_margin;
+ var->lower_margin = display->lower_margin;
+ var->vsync_len = display->vsync_len;
+ var->hsync_len = display->hsync_len;
+
+ fbi->regs.lcdcon5 = display->lcdcon5;
+ /* set display type */
+ fbi->regs.lcdcon1 = display->type;
+
+ var->transp.offset = 0;
+ var->transp.length = 0;
/* set r/g/b positions */
switch (var->bits_per_pixel) {
- case 1:
- case 2:
- case 4:
- var->red.offset = 0;
- var->red.length = var->bits_per_pixel;
- var->green = var->red;
- var->blue = var->red;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case 8:
- if ( fbi->mach_info->type != S3C2410_LCDCON1_TFT ) {
- /* 8 bpp 332 */
- var->red.length = 3;
- var->red.offset = 5;
- var->green.length = 3;
- var->green.offset = 2;
- var->blue.length = 2;
- var->blue.offset = 0;
- var->transp.length = 0;
- } else {
- var->red.offset = 0;
- var->red.length = var->bits_per_pixel;
- var->green = var->red;
- var->blue = var->red;
- var->transp.offset = 0;
- var->transp.length = 0;
- }
- break;
- case 12:
- /* 12 bpp 444 */
- var->red.length = 4;
- var->red.offset = 8;
- var->green.length = 4;
- var->green.offset = 4;
- var->blue.length = 4;
+ case 1:
+ case 2:
+ case 4:
+ var->red.offset = 0;
+ var->red.length = var->bits_per_pixel;
+ var->green = var->red;
+ var->blue = var->red;
+ break;
+ case 8:
+ if (display->type != S3C2410_LCDCON1_TFT) {
+ /* 8 bpp 332 */
+ var->red.length = 3;
+ var->red.offset = 5;
+ var->green.length = 3;
+ var->green.offset = 2;
+ var->blue.length = 2;
var->blue.offset = 0;
- var->transp.length = 0;
- break;
-
- default:
- case 16:
- if (fbi->regs.lcdcon5 & S3C2410_LCDCON5_FRM565 ) {
- /* 16 bpp, 565 format */
- var->red.offset = 11;
- var->green.offset = 5;
- var->blue.offset = 0;
- var->red.length = 5;
- var->green.length = 6;
- var->blue.length = 5;
- var->transp.length = 0;
- } else {
- /* 16 bpp, 5551 format */
- var->red.offset = 11;
- var->green.offset = 6;
- var->blue.offset = 1;
- var->red.length = 5;
- var->green.length = 5;
- var->blue.length = 5;
- var->transp.length = 0;
- }
- break;
- case 24:
- /* 24 bpp 888 */
+ } else {
+ var->red.offset = 0;
var->red.length = 8;
- var->red.offset = 16;
- var->green.length = 8;
- var->green.offset = 8;
- var->blue.length = 8;
- var->blue.offset = 0;
- var->transp.length = 0;
- break;
-
+ var->green = var->red;
+ var->blue = var->red;
+ }
+ break;
+ case 12:
+ /* 12 bpp 444 */
+ var->red.length = 4;
+ var->red.offset = 8;
+ var->green.length = 4;
+ var->green.offset = 4;
+ var->blue.length = 4;
+ var->blue.offset = 0;
+ break;
+ default:
+ case 16:
+ if (display->lcdcon5 & S3C2410_LCDCON5_FRM565) {
+ /* 16 bpp, 565 format */
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ } else {
+ /* 16 bpp, 5551 format */
+ var->red.offset = 11;
+ var->green.offset = 6;
+ var->blue.offset = 1;
+ var->red.length = 5;
+ var->green.length = 5;
+ var->blue.length = 5;
+ }
+ break;
+ case 32:
+ /* 24 bpp 888 and 8 dummy */
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ break;
}
return 0;
}
-
-/* s3c2410fb_activate_var
+/* s3c2410fb_calculate_stn_lcd_regs
*
- * activate (set) the controller from the given framebuffer
- * information
-*/
-
-static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi,
- struct fb_var_screeninfo *var)
+ * calculate register values from var settings
+ */
+static void s3c2410fb_calculate_stn_lcd_regs(const struct fb_info *info,
+ struct s3c2410fb_hw *regs)
{
- int hs;
+ const struct s3c2410fb_info *fbi = info->par;
+ const struct fb_var_screeninfo *var = &info->var;
+ int type = regs->lcdcon1 & ~S3C2410_LCDCON1_TFT;
+ int hs = var->xres >> 2;
+ unsigned wdly = (var->left_margin >> 4) - 1;
+ unsigned wlh = (var->hsync_len >> 4) - 1;
- fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_MODEMASK;
- fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_TFT;
+ if (type != S3C2410_LCDCON1_STN4)
+ hs >>= 1;
- dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres);
- dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres);
- dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel);
+ switch (var->bits_per_pixel) {
+ case 1:
+ regs->lcdcon1 |= S3C2410_LCDCON1_STN1BPP;
+ break;
+ case 2:
+ regs->lcdcon1 |= S3C2410_LCDCON1_STN2GREY;
+ break;
+ case 4:
+ regs->lcdcon1 |= S3C2410_LCDCON1_STN4GREY;
+ break;
+ case 8:
+ regs->lcdcon1 |= S3C2410_LCDCON1_STN8BPP;
+ hs *= 3;
+ break;
+ case 12:
+ regs->lcdcon1 |= S3C2410_LCDCON1_STN12BPP;
+ hs *= 3;
+ break;
- fbi->regs.lcdcon1 |= fbi->mach_info->type;
-
- if (fbi->mach_info->type == S3C2410_LCDCON1_TFT)
- switch (var->bits_per_pixel) {
- case 1:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
- break;
- case 2:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
- break;
- case 4:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
- break;
- case 8:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
- break;
- case 16:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
- break;
-
- default:
- /* invalid pixel depth */
- dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel);
- }
- else
- switch (var->bits_per_pixel) {
- case 1:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN1BPP;
- break;
- case 2:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN2GREY;
- break;
- case 4:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN4GREY;
- break;
- case 8:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN8BPP;
- break;
- case 12:
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_STN12BPP;
- break;
-
- default:
- /* invalid pixel depth */
- dev_err(fbi->dev, "invalid bpp %d\n", var->bits_per_pixel);
- }
+ default:
+ /* invalid pixel depth */
+ dev_err(fbi->dev, "invalid bpp %d\n",
+ var->bits_per_pixel);
+ }
+ /* update X/Y info */
+ dprintk("setting horz: lft=%d, rt=%d, sync=%d\n",
+ var->left_margin, var->right_margin, var->hsync_len);
- /* check to see if we need to update sync/borders */
+ regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1);
- if (!fbi->mach_info->fixed_syncs) {
- dprintk("setting vert: up=%d, low=%d, sync=%d\n",
- var->upper_margin, var->lower_margin,
- var->vsync_len);
+ if (wdly > 3)
+ wdly = 3;
- dprintk("setting horz: lft=%d, rt=%d, sync=%d\n",
- var->left_margin, var->right_margin,
- var->hsync_len);
+ if (wlh > 3)
+ wlh = 3;
- fbi->regs.lcdcon2 =
- S3C2410_LCDCON2_VBPD(var->upper_margin - 1) |
- S3C2410_LCDCON2_VFPD(var->lower_margin - 1) |
- S3C2410_LCDCON2_VSPW(var->vsync_len - 1);
+ regs->lcdcon3 = S3C2410_LCDCON3_WDLY(wdly) |
+ S3C2410_LCDCON3_LINEBLANK(var->right_margin / 8) |
+ S3C2410_LCDCON3_HOZVAL(hs - 1);
- fbi->regs.lcdcon3 =
- S3C2410_LCDCON3_HBPD(var->right_margin - 1) |
- S3C2410_LCDCON3_HFPD(var->left_margin - 1);
+ regs->lcdcon4 = S3C2410_LCDCON4_WLH(wlh);
+}
- fbi->regs.lcdcon4 &= ~S3C2410_LCDCON4_HSPW(0xff);
- fbi->regs.lcdcon4 |= S3C2410_LCDCON4_HSPW(var->hsync_len - 1);
- }
+/* s3c2410fb_calculate_tft_lcd_regs
+ *
+ * calculate register values from var settings
+ */
+static void s3c2410fb_calculate_tft_lcd_regs(const struct fb_info *info,
+ struct s3c2410fb_hw *regs)
+{
+ const struct s3c2410fb_info *fbi = info->par;
+ const struct fb_var_screeninfo *var = &info->var;
+ switch (var->bits_per_pixel) {
+ case 1:
+ regs->lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
+ break;
+ case 2:
+ regs->lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
+ break;
+ case 4:
+ regs->lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
+ break;
+ case 8:
+ regs->lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
+ regs->lcdcon5 |= S3C2410_LCDCON5_BSWP |
+ S3C2410_LCDCON5_FRM565;
+ regs->lcdcon5 &= ~S3C2410_LCDCON5_HWSWP;
+ break;
+ case 16:
+ regs->lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
+ regs->lcdcon5 &= ~S3C2410_LCDCON5_BSWP;
+ regs->lcdcon5 |= S3C2410_LCDCON5_HWSWP;
+ break;
+ case 32:
+ regs->lcdcon1 |= S3C2410_LCDCON1_TFT24BPP;
+ regs->lcdcon5 &= ~(S3C2410_LCDCON5_BSWP |
+ S3C2410_LCDCON5_HWSWP |
+ S3C2410_LCDCON5_BPP24BL);
+ break;
+ default:
+ /* invalid pixel depth */
+ dev_err(fbi->dev, "invalid bpp %d\n",
+ var->bits_per_pixel);
+ }
/* update X/Y info */
+ dprintk("setting vert: up=%d, low=%d, sync=%d\n",
+ var->upper_margin, var->lower_margin, var->vsync_len);
- fbi->regs.lcdcon2 &= ~S3C2410_LCDCON2_LINEVAL(0x3ff);
- fbi->regs.lcdcon2 |= S3C2410_LCDCON2_LINEVAL(var->yres - 1);
-
- switch(fbi->mach_info->type) {
- case S3C2410_LCDCON1_DSCAN4:
- case S3C2410_LCDCON1_STN8:
- hs = var->xres / 8;
- break;
- case S3C2410_LCDCON1_STN4:
- hs = var->xres / 4;
- break;
- default:
- case S3C2410_LCDCON1_TFT:
- hs = var->xres;
- break;
-
- }
+ dprintk("setting horz: lft=%d, rt=%d, sync=%d\n",
+ var->left_margin, var->right_margin, var->hsync_len);
- /* Special cases : STN color displays */
- if ( ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN8BPP) \
- || ((fbi->regs.lcdcon1 & S3C2410_LCDCON1_MODEMASK) == S3C2410_LCDCON1_STN12BPP) ) {
- hs = hs * 3;
- }
+ regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1) |
+ S3C2410_LCDCON2_VBPD(var->upper_margin - 1) |
+ S3C2410_LCDCON2_VFPD(var->lower_margin - 1) |
+ S3C2410_LCDCON2_VSPW(var->vsync_len - 1);
+ regs->lcdcon3 = S3C2410_LCDCON3_HBPD(var->right_margin - 1) |
+ S3C2410_LCDCON3_HFPD(var->left_margin - 1) |
+ S3C2410_LCDCON3_HOZVAL(var->xres - 1);
- fbi->regs.lcdcon3 &= ~S3C2410_LCDCON3_HOZVAL(0x7ff);
- fbi->regs.lcdcon3 |= S3C2410_LCDCON3_HOZVAL(hs - 1);
+ regs->lcdcon4 = S3C2410_LCDCON4_HSPW(var->hsync_len - 1);
+}
- if (var->pixclock > 0) {
- int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock);
+/* s3c2410fb_activate_var
+ *
+ * activate (set) the controller from the given framebuffer
+ * information
+ */
+static void s3c2410fb_activate_var(struct fb_info *info)
+{
+ struct s3c2410fb_info *fbi = info->par;
+ void __iomem *regs = fbi->io;
+ int type = fbi->regs.lcdcon1 & S3C2410_LCDCON1_TFT;
+ struct fb_var_screeninfo *var = &info->var;
+ int clkdiv = s3c2410fb_calc_pixclk(fbi, var->pixclock) / 2;
- if (fbi->mach_info->type == S3C2410_LCDCON1_TFT) {
- clkdiv = (clkdiv / 2) -1;
- if (clkdiv < 0)
- clkdiv = 0;
- }
- else {
- clkdiv = (clkdiv / 2);
- if (clkdiv < 2)
- clkdiv = 2;
- }
+ dprintk("%s: var->xres = %d\n", __FUNCTION__, var->xres);
+ dprintk("%s: var->yres = %d\n", __FUNCTION__, var->yres);
+ dprintk("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel);
- fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_CLKVAL(0x3ff);
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv);
+ if (type == S3C2410_LCDCON1_TFT) {
+ s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs);
+ --clkdiv;
+ if (clkdiv < 0)
+ clkdiv = 0;
+ } else {
+ s3c2410fb_calculate_stn_lcd_regs(info, &fbi->regs);
+ if (clkdiv < 2)
+ clkdiv = 2;
}
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv);
+
/* write new registers */
dprintk("new register set:\n");
@@ -425,47 +451,48 @@ static void s3c2410fb_activate_var(struct s3c2410fb_info *fbi,
dprintk("lcdcon[4] = 0x%08lx\n", fbi->regs.lcdcon4);
dprintk("lcdcon[5] = 0x%08lx\n", fbi->regs.lcdcon5);
- writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
- writel(fbi->regs.lcdcon2, S3C2410_LCDCON2);
- writel(fbi->regs.lcdcon3, S3C2410_LCDCON3);
- writel(fbi->regs.lcdcon4, S3C2410_LCDCON4);
- writel(fbi->regs.lcdcon5, S3C2410_LCDCON5);
+ writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID,
+ regs + S3C2410_LCDCON1);
+ writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2);
+ writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3);
+ writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4);
+ writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5);
/* set lcd address pointers */
- s3c2410fb_set_lcdaddr(fbi);
+ s3c2410fb_set_lcdaddr(info);
- writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
+ fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID,
+ writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);
}
-
/*
- * s3c2410fb_set_par - Optional function. Alters the hardware state.
+ * s3c2410fb_set_par - Alters the hardware state.
* @info: frame buffer structure that represents a single frame buffer
*
*/
static int s3c2410fb_set_par(struct fb_info *info)
{
- struct s3c2410fb_info *fbi = info->par;
struct fb_var_screeninfo *var = &info->var;
- switch (var->bits_per_pixel)
- {
- case 16:
- fbi->fb->fix.visual = FB_VISUAL_TRUECOLOR;
- break;
- case 1:
- fbi->fb->fix.visual = FB_VISUAL_MONO01;
- break;
- default:
- fbi->fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
- break;
+ switch (var->bits_per_pixel) {
+ case 32:
+ case 16:
+ case 12:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ break;
+ case 1:
+ info->fix.visual = FB_VISUAL_MONO01;
+ break;
+ default:
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
}
- fbi->fb->fix.line_length = (var->width*var->bits_per_pixel)/8;
+ info->fix.line_length = (var->width * var->bits_per_pixel) / 8;
/* activate this new configuration */
- s3c2410fb_activate_var(fbi, var);
+ s3c2410fb_activate_var(info);
return 0;
}
@@ -493,7 +520,8 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi,
}
/* from pxafb.c */
-static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
+static inline unsigned int chan_to_field(unsigned int chan,
+ struct fb_bitfield *bf)
{
chan &= 0xffff;
chan >>= 16 - bf->length;
@@ -505,20 +533,22 @@ static int s3c2410fb_setcolreg(unsigned regno,
unsigned transp, struct fb_info *info)
{
struct s3c2410fb_info *fbi = info->par;
+ void __iomem *regs = fbi->io;
unsigned int val;
- /* dprintk("setcol: regno=%d, rgb=%d,%d,%d\n", regno, red, green, blue); */
+ /* dprintk("setcol: regno=%d, rgb=%d,%d,%d\n",
+ regno, red, green, blue); */
- switch (fbi->fb->fix.visual) {
+ switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
- /* true-colour, use pseuo-palette */
+ /* true-colour, use pseudo-palette */
if (regno < 16) {
- u32 *pal = fbi->fb->pseudo_palette;
+ 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);
+ val = chan_to_field(red, &info->var.red);
+ val |= chan_to_field(green, &info->var.green);
+ val |= chan_to_field(blue, &info->var.blue);
pal[regno] = val;
}
@@ -528,25 +558,24 @@ static int s3c2410fb_setcolreg(unsigned regno,
if (regno < 256) {
/* currently assume RGB 5-6-5 mode */
- val = ((red >> 0) & 0xf800);
- val |= ((green >> 5) & 0x07e0);
- val |= ((blue >> 11) & 0x001f);
+ val = (red >> 0) & 0xf800;
+ val |= (green >> 5) & 0x07e0;
+ val |= (blue >> 11) & 0x001f;
- writel(val, S3C2410_TFTPAL(regno));
+ writel(val, regs + S3C2410_TFTPAL(regno));
schedule_palette_update(fbi, regno, val);
}
break;
default:
- return 1; /* unknown type */
+ return 1; /* unknown type */
}
return 0;
}
-
-/**
+/*
* s3c2410fb_blank
* @blank_mode: the blank mode we want.
* @info: frame buffer structure that represents a single frame buffer
@@ -564,31 +593,31 @@ static int s3c2410fb_setcolreg(unsigned regno,
*/
static int s3c2410fb_blank(int blank_mode, struct fb_info *info)
{
- dprintk("blank(mode=%d, info=%p)\n", blank_mode, info);
+ struct s3c2410fb_info *fbi = info->par;
+ void __iomem *regs = fbi->io;
- if (mach_info == NULL)
- return -EINVAL;
+ dprintk("blank(mode=%d, info=%p)\n", blank_mode, info);
if (blank_mode == FB_BLANK_UNBLANK)
- writel(0x0, S3C2410_TPAL);
+ writel(0x0, regs + S3C2410_TPAL);
else {
dprintk("setting TPAL to output 0x000000\n");
- writel(S3C2410_TPAL_EN, S3C2410_TPAL);
+ writel(S3C2410_TPAL_EN, regs + S3C2410_TPAL);
}
return 0;
}
-static int s3c2410fb_debug_show(struct device *dev, struct device_attribute *attr, char *buf)
+static int s3c2410fb_debug_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", debug ? "on" : "off");
}
-static int s3c2410fb_debug_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t len)
-{
- if (mach_info == NULL)
- return -EINVAL;
+static int s3c2410fb_debug_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
if (len < 1)
return -EINVAL;
@@ -607,10 +636,7 @@ static int s3c2410fb_debug_store(struct device *dev, struct device_attribute *at
return len;
}
-
-static DEVICE_ATTR(debug, 0666,
- s3c2410fb_debug_show,
- s3c2410fb_debug_store);
+static DEVICE_ATTR(debug, 0666, s3c2410fb_debug_show, s3c2410fb_debug_store);
static struct fb_ops s3c2410fb_ops = {
.owner = THIS_MODULE,
@@ -623,7 +649,6 @@ static struct fb_ops s3c2410fb_ops = {
.fb_imageblit = cfb_imageblit,
};
-
/*
* s3c2410fb_map_video_memory():
* Allocates the DRAM memory for the frame buffer. This buffer is
@@ -632,36 +657,38 @@ static struct fb_ops s3c2410fb_ops = {
* cache. Once this area is remapped, all virtual memory
* access to the video memory should occur at the new region.
*/
-static int __init s3c2410fb_map_video_memory(struct s3c2410fb_info *fbi)
+static int __init s3c2410fb_map_video_memory(struct fb_info *info)
{
- dprintk("map_video_memory(fbi=%p)\n", fbi);
+ struct s3c2410fb_info *fbi = info->par;
+ dma_addr_t map_dma;
+ unsigned map_size = PAGE_ALIGN(info->fix.smem_len);
- fbi->map_size = PAGE_ALIGN(fbi->fb->fix.smem_len + PAGE_SIZE);
- fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
- &fbi->map_dma, GFP_KERNEL);
+ dprintk("map_video_memory(fbi=%p)\n", fbi);
- fbi->map_size = fbi->fb->fix.smem_len;
+ info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,
+ &map_dma, GFP_KERNEL);
- if (fbi->map_cpu) {
+ if (info->screen_base) {
/* prevent initial garbage on screen */
dprintk("map_video_memory: clear %p:%08x\n",
- fbi->map_cpu, fbi->map_size);
- memset(fbi->map_cpu, 0xf0, fbi->map_size);
+ info->screen_base, map_size);
+ memset(info->screen_base, 0xf0, map_size);
- fbi->screen_dma = fbi->map_dma;
- fbi->fb->screen_base = fbi->map_cpu;
- fbi->fb->fix.smem_start = fbi->screen_dma;
+ info->fix.smem_start = map_dma;
- dprintk("map_video_memory: dma=%08x cpu=%p size=%08x\n",
- fbi->map_dma, fbi->map_cpu, fbi->fb->fix.smem_len);
+ dprintk("map_video_memory: dma=%08lx cpu=%p size=%08x\n",
+ info->fix.smem_start, info->screen_base, map_size);
}
- return fbi->map_cpu ? 0 : -ENOMEM;
+ return info->screen_base ? 0 : -ENOMEM;
}
-static inline void s3c2410fb_unmap_video_memory(struct s3c2410fb_info *fbi)
+static inline void s3c2410fb_unmap_video_memory(struct fb_info *info)
{
- dma_free_writecombine(fbi->dev,fbi->map_size,fbi->map_cpu, fbi->map_dma);
+ struct s3c2410fb_info *fbi = info->par;
+
+ dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
+ info->screen_base, info->fix.smem_start);
}
static inline void modify_gpio(void __iomem *reg,
@@ -673,13 +700,13 @@ static inline void modify_gpio(void __iomem *reg,
writel(tmp | set, reg);
}
-
/*
* s3c2410fb_init_registers - Initialise all LCD-related registers
*/
-
-static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi)
+static int s3c2410fb_init_registers(struct fb_info *info)
{
+ struct s3c2410fb_info *fbi = info->par;
+ struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;
unsigned long flags;
void __iomem *regs = fbi->io;
@@ -696,14 +723,6 @@ static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi)
local_irq_restore(flags);
- writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);
- writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2);
- writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3);
- writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4);
- writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5);
-
- s3c2410fb_set_lcdaddr(fbi);
-
dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel);
writel(mach_info->lpcsel, regs + S3C2410_LPCSEL);
@@ -712,22 +731,19 @@ static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi)
/* ensure temporary palette disabled */
writel(0x00, regs + S3C2410_TPAL);
- /* Enable video by setting the ENVID bit to 1 */
- fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID;
- writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);
return 0;
}
static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)
{
unsigned int i;
- unsigned long ent;
void __iomem *regs = fbi->io;
fbi->palette_ready = 0;
for (i = 0; i < 256; i++) {
- if ((ent = fbi->palette_buffer[i]) == PALETTE_BUFF_CLEAR)
+ unsigned long ent = fbi->palette_buffer[i];
+ if (ent == PALETTE_BUFF_CLEAR)
continue;
writel(ent, regs + S3C2410_TFTPAL(i));
@@ -761,13 +777,14 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static char driver_name[]="s3c2410fb";
+static char driver_name[] = "s3c2410fb";
static int __init s3c2410fb_probe(struct platform_device *pdev)
{
struct s3c2410fb_info *info;
- struct fb_info *fbinfo;
- struct s3c2410fb_hw *mregs;
+ struct s3c2410fb_display *display;
+ struct fb_info *fbinfo;
+ struct s3c2410fb_mach_info *mach_info;
struct resource *res;
int ret;
int irq;
@@ -777,11 +794,12 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
mach_info = pdev->dev.platform_data;
if (mach_info == NULL) {
- dev_err(&pdev->dev,"no platform data for lcd, cannot attach\n");
+ dev_err(&pdev->dev,
+ "no platform data for lcd, cannot attach\n");
return -EINVAL;
}
- mregs = &mach_info->regs;
+ display = mach_info->displays + mach_info->default_display;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -790,22 +808,22 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
}
fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);
- if (!fbinfo) {
+ if (!fbinfo)
return -ENOMEM;
- }
+
+ platform_set_drvdata(pdev, fbinfo);
info = fbinfo->par;
- info->fb = fbinfo;
info->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
- dev_err(&pdev->dev, "failed to get memory registersn");
+ dev_err(&pdev->dev, "failed to get memory registers\n");
ret = -ENXIO;
goto dealloc_fb;
}
- size = (res->end - res->start)+1;
+ size = (res->end - res->start) + 1;
info->mem = request_mem_region(res->start, size, pdev->name);
if (info->mem == NULL) {
dev_err(&pdev->dev, "failed to get memory region\n");
@@ -820,21 +838,14 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
goto release_mem;
}
- platform_set_drvdata(pdev, fbinfo);
-
dprintk("devinit\n");
strcpy(fbinfo->fix.id, driver_name);
- memcpy(&info->regs, &mach_info->regs, sizeof(info->regs));
-
- /* Stop the video and unset ENVID if set */
- info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
+ /* Stop the video */
lcdcon1 = readl(info->io + S3C2410_LCDCON1);
writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);
- info->mach_info = pdev->dev.platform_data;
-
fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
fbinfo->fix.type_aux = 0;
fbinfo->fix.xpanstep = 0;
@@ -844,8 +855,6 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
fbinfo->var.nonstd = 0;
fbinfo->var.activate = FB_ACTIVATE_NOW;
- fbinfo->var.height = mach_info->height;
- fbinfo->var.width = mach_info->width;
fbinfo->var.accel_flags = 0;
fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
@@ -853,32 +862,6 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
fbinfo->flags = FBINFO_FLAG_DEFAULT;
fbinfo->pseudo_palette = &info->pseudo_pal;
- fbinfo->var.xres = mach_info->xres.defval;
- fbinfo->var.xres_virtual = mach_info->xres.defval;
- fbinfo->var.yres = mach_info->yres.defval;
- fbinfo->var.yres_virtual = mach_info->yres.defval;
- fbinfo->var.bits_per_pixel = mach_info->bpp.defval;
-
- fbinfo->var.upper_margin = S3C2410_LCDCON2_GET_VBPD(mregs->lcdcon2) + 1;
- fbinfo->var.lower_margin = S3C2410_LCDCON2_GET_VFPD(mregs->lcdcon2) + 1;
- fbinfo->var.vsync_len = S3C2410_LCDCON2_GET_VSPW(mregs->lcdcon2) + 1;
-
- fbinfo->var.left_margin = S3C2410_LCDCON3_GET_HFPD(mregs->lcdcon3) + 1;
- fbinfo->var.right_margin = S3C2410_LCDCON3_GET_HBPD(mregs->lcdcon3) + 1;
- fbinfo->var.hsync_len = S3C2410_LCDCON4_GET_HSPW(mregs->lcdcon4) + 1;
-
- fbinfo->var.red.offset = 11;
- fbinfo->var.green.offset = 5;
- fbinfo->var.blue.offset = 0;
- fbinfo->var.transp.offset = 0;
- fbinfo->var.red.length = 5;
- fbinfo->var.green.length = 6;
- fbinfo->var.blue.length = 5;
- fbinfo->var.transp.length = 0;
- fbinfo->fix.smem_len = mach_info->xres.max *
- mach_info->yres.max *
- mach_info->bpp.max / 8;
-
for (i = 0; i < 256; i++)
info->palette_buffer[i] = PALETTE_BUFF_CLEAR;
@@ -901,23 +884,39 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
msleep(1);
+ /* find maximum required memory size for display */
+ for (i = 0; i < mach_info->num_displays; i++) {
+ unsigned long smem_len = mach_info->displays[i].xres;
+
+ smem_len *= mach_info->displays[i].yres;
+ smem_len *= mach_info->displays[i].bpp;
+ smem_len >>= 3;
+ if (fbinfo->fix.smem_len < smem_len)
+ fbinfo->fix.smem_len = smem_len;
+ }
+
/* Initialize video memory */
- ret = s3c2410fb_map_video_memory(info);
+ ret = s3c2410fb_map_video_memory(fbinfo);
if (ret) {
- printk( KERN_ERR "Failed to allocate video RAM: %d\n", ret);
+ printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);
ret = -ENOMEM;
goto release_clock;
}
dprintk("got video memory\n");
- ret = s3c2410fb_init_registers(info);
+ fbinfo->var.xres = display->xres;
+ fbinfo->var.yres = display->yres;
+ fbinfo->var.bits_per_pixel = display->bpp;
+
+ s3c2410fb_init_registers(fbinfo);
- ret = s3c2410fb_check_var(&fbinfo->var, fbinfo);
+ s3c2410fb_check_var(&fbinfo->var, fbinfo);
ret = register_framebuffer(fbinfo);
if (ret < 0) {
- printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret);
+ printk(KERN_ERR "Failed to register framebuffer device: %d\n",
+ ret);
goto free_video_memory;
}
@@ -930,18 +929,19 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
return 0;
free_video_memory:
- s3c2410fb_unmap_video_memory(info);
+ s3c2410fb_unmap_video_memory(fbinfo);
release_clock:
clk_disable(info->clk);
clk_put(info->clk);
release_irq:
- free_irq(irq,info);
+ free_irq(irq, info);
release_regs:
iounmap(info->io);
release_mem:
release_resource(info->mem);
kfree(info->mem);
dealloc_fb:
+ platform_set_drvdata(pdev, NULL);
framebuffer_release(fbinfo);
return ret;
}
@@ -949,8 +949,7 @@ dealloc_fb:
/* s3c2410fb_stop_lcd
*
* shutdown the lcd controller
-*/
-
+ */
static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi)
{
unsigned long flags;
@@ -968,28 +967,33 @@ static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi)
*/
static int s3c2410fb_remove(struct platform_device *pdev)
{
- struct fb_info *fbinfo = platform_get_drvdata(pdev);
+ struct fb_info *fbinfo = platform_get_drvdata(pdev);
struct s3c2410fb_info *info = fbinfo->par;
int irq;
+ unregister_framebuffer(fbinfo);
+
s3c2410fb_stop_lcd(info);
msleep(1);
- s3c2410fb_unmap_video_memory(info);
+ s3c2410fb_unmap_video_memory(fbinfo);
- if (info->clk) {
- clk_disable(info->clk);
- clk_put(info->clk);
- info->clk = NULL;
+ if (info->clk) {
+ clk_disable(info->clk);
+ clk_put(info->clk);
+ info->clk = NULL;
}
irq = platform_get_irq(pdev, 0);
- free_irq(irq,info);
+ free_irq(irq, info);
+
+ iounmap(info->io);
release_resource(info->mem);
kfree(info->mem);
- iounmap(info->io);
- unregister_framebuffer(fbinfo);
+
+ platform_set_drvdata(pdev, NULL);
+ framebuffer_release(fbinfo);
return 0;
}
@@ -997,7 +1001,6 @@ static int s3c2410fb_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
/* suspend and resume support for the lcd controller */
-
static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state)
{
struct fb_info *fbinfo = platform_get_drvdata(dev);
@@ -1044,7 +1047,7 @@ static struct platform_driver s3c2410fb_driver = {
},
};
-int __devinit s3c2410fb_init(void)
+int __init s3c2410fb_init(void)
{
return platform_driver_register(&s3c2410fb_driver);
}
@@ -1054,10 +1057,10 @@ static void __exit s3c2410fb_cleanup(void)
platform_driver_unregister(&s3c2410fb_driver);
}
-
module_init(s3c2410fb_init);
module_exit(s3c2410fb_cleanup);
-MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, Ben Dooks <ben-linux@fluff.org>");
+MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, "
+ "Ben Dooks <ben-linux@fluff.org>");
MODULE_DESCRIPTION("Framebuffer driver for the s3c2410");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h
index 17c7915b7ac..6ce5dc26c5f 100644
--- a/drivers/video/s3c2410fb.h
+++ b/drivers/video/s3c2410fb.h
@@ -16,7 +16,7 @@
*
* 2004-09-07: Arnaud Patard <arnaud.patard@rtp-net.org>
* - Renamed from h1940fb.h to s3c2410fb.h
- * - Chenged h1940 to s3c2410
+ * - Changed h1940 to s3c2410
*
* 2004-07-15: Arnaud Patard <arnaud.patard@rtp-net.org>
* - First version
@@ -26,25 +26,14 @@
#define __S3C2410FB_H
struct s3c2410fb_info {
- struct fb_info *fb;
struct device *dev;
struct clk *clk;
struct resource *mem;
void __iomem *io;
- struct s3c2410fb_mach_info *mach_info;
-
- /* raw memory addresses */
- dma_addr_t map_dma; /* physical */
- u_char * map_cpu; /* virtual */
- u_int map_size;
-
struct s3c2410fb_hw regs;
- /* addresses of pieces placed in raw buffer */
- u_char * screen_cpu; /* virtual address of buffer */
- dma_addr_t screen_dma; /* physical address of buffer */
unsigned int palette_ready;
/* keep these registers in case we need to re-write palette */
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c
index d11735895a0..7d53bc23b9c 100644
--- a/drivers/video/s3fb.c
+++ b/drivers/video/s3fb.c
@@ -400,11 +400,17 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct s3fb_info *par = info->par;
int rv, mem, step;
+ u16 m, n, r;
/* Find appropriate format */
rv = svga_match_format (s3fb_formats, var, NULL);
- if ((rv < 0) || ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6)))
- { /* 24bpp on VIRGE VX, 32bpp on others */
+
+ /* 32bpp mode is not supported on VIRGE VX,
+ 24bpp is not supported on others */
+ if ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6))
+ rv = -EINVAL;
+
+ if (rv < 0) {
printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node);
return rv;
}
@@ -422,20 +428,26 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
/* Check whether have enough memory */
mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
- if (mem > info->screen_size)
- {
+ if (mem > info->screen_size) {
printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n",
info->node, mem >> 10, (unsigned int) (info->screen_size >> 10));
return -EINVAL;
}
rv = svga_check_timings (&s3_timing_regs, var, info->node);
- if (rv < 0)
- {
+ if (rv < 0) {
printk(KERN_ERR "fb%d: invalid timings requested\n", info->node);
return rv;
}
+ rv = svga_compute_pll(&s3_pll, PICOS2KHZ(var->pixclock), &m, &n, &r,
+ info->node);
+ if (rv < 0) {
+ printk(KERN_ERR "fb%d: invalid pixclock value requested\n",
+ info->node);
+ return rv;
+ }
+
return 0;
}
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index 5d2a4a4b731..ab2b2110478 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -178,7 +178,6 @@
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/mach-types.h>
-#include <asm/uaccess.h>
#include <asm/arch/assabet.h>
#include <asm/arch/shannon.h>
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index b855f4a34af..37b135d5d12 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -57,7 +57,6 @@
#include <asm/irq.h>
#include <asm/pgtable.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index e8ccace0125..37bd24b8d83 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -58,7 +58,7 @@
#include <linux/capability.h>
#include <linux/fs.h>
#include <linux/types.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/io.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
@@ -1248,7 +1248,6 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in
if(found_mode) {
ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
ivideo->sisfb_mode_idx, ivideo->currentvbflags);
- ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
} else {
ivideo->sisfb_mode_idx = -1;
}
@@ -1260,6 +1259,8 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in
return -EINVAL;
}
+ ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
+
if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
ivideo->refresh_rate = 60;
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
index 64779e70408..62321458f71 100644
--- a/drivers/video/skeletonfb.c
+++ b/drivers/video/skeletonfb.c
@@ -780,7 +780,7 @@ static int __devinit xxxfb_probe(struct pci_dev *dev,
*
* NOTE: This field is currently unused.
*/
- info->pixmap.scan_align = 32;
+ info->pixmap.access_align = 32;
/***************************** End optional stage ***************************/
/*
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index c86df126f93..1be95a68d69 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -28,6 +28,7 @@
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/console.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -62,6 +63,8 @@ struct sm501fb_info {
struct resource *regs_res; /* registers resource */
struct sm501_platdata_fb *pdata; /* our platform data */
+ unsigned long pm_crt_ctrl; /* pm: crt ctrl save */
+
int irq;
int swap_endian; /* set to swap rgb=>bgr */
void __iomem *regs; /* remapped registers */
@@ -774,6 +777,11 @@ static int sm501fb_set_par_pnl(struct fb_info *info)
writel(control, fbi->regs + SM501_DC_PANEL_CONTROL);
sm501fb_sync_regs(fbi);
+ /* ensure the panel interface is not tristated at this point */
+
+ sm501_modify_reg(fbi->dev->parent, SM501_SYSTEM_CONTROL,
+ 0, SM501_SYSCTRL_PANEL_TRISTATE);
+
/* power the panel up */
sm501fb_panel_power(fbi, 1);
return 0;
@@ -1687,19 +1695,25 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info,
goto err_nocursor;
}
+ dev_dbg(info->dev, "suspending screen to %p\n", par->store_fb);
+ dev_dbg(info->dev, "suspending cursor to %p\n", par->store_cursor);
+
memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size);
memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size);
-
/* blank the relevant interface to ensure unit power minimised */
(par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi);
+ acquire_console_sem();
+ fb_set_suspend(fbi, 1);
+ release_console_sem();
+
return 0;
err_nocursor:
vfree(par->store_fb);
+ par->store_fb = NULL;
return -ENOMEM;
-
}
static void sm501fb_resume_fb(struct sm501fb_info *info,
@@ -1717,8 +1731,20 @@ static void sm501fb_resume_fb(struct sm501fb_info *info,
/* restore the data */
- memcpy_toio(par->screen.k_addr, par->store_fb, par->screen.size);
- memcpy_toio(par->cursor.k_addr, par->store_cursor, par->cursor.size);
+ dev_dbg(info->dev, "restoring screen from %p\n", par->store_fb);
+ dev_dbg(info->dev, "restoring cursor from %p\n", par->store_cursor);
+
+ if (par->store_fb)
+ memcpy_toio(par->screen.k_addr, par->store_fb,
+ par->screen.size);
+
+ if (par->store_cursor)
+ memcpy_toio(par->cursor.k_addr, par->store_cursor,
+ par->cursor.size);
+
+ acquire_console_sem();
+ fb_set_suspend(fbi, 0);
+ release_console_sem();
vfree(par->store_fb);
vfree(par->store_cursor);
@@ -1731,6 +1757,9 @@ static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state)
{
struct sm501fb_info *info = platform_get_drvdata(pdev);
+ /* store crt control to resume with */
+ info->pm_crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+
sm501fb_suspend_fb(info, HEAD_CRT);
sm501fb_suspend_fb(info, HEAD_PANEL);
@@ -1740,12 +1769,24 @@ static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
+#define SM501_CRT_CTRL_SAVE (SM501_DC_CRT_CONTROL_TVP | \
+ SM501_DC_CRT_CONTROL_SEL)
+
+
static int sm501fb_resume(struct platform_device *pdev)
{
struct sm501fb_info *info = platform_get_drvdata(pdev);
+ unsigned long crt_ctrl;
sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 1);
+ /* restore the items we want to be saved for crt control */
+
+ crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL);
+ crt_ctrl &= ~SM501_CRT_CTRL_SAVE;
+ crt_ctrl |= info->pm_crt_ctrl & SM501_CRT_CTRL_SAVE;
+ writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL);
+
sm501fb_resume_fb(info, HEAD_CRT);
sm501fb_resume_fb(info, HEAD_PANEL);
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
index 5eff28ce4f4..97784f9c184 100644
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -88,7 +88,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <video/sstfb.h>
diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c
index 25df928d37d..9c710670157 100644
--- a/drivers/video/svgalib.c
+++ b/drivers/video/svgalib.c
@@ -598,9 +598,11 @@ void svga_set_timings(const struct svga_timing_regs *tm, struct fb_var_screeninf
/* ------------------------------------------------------------------------- */
-int svga_match_format(const struct svga_fb_format *frm, struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix)
+static inline int match_format(const struct svga_fb_format *frm,
+ struct fb_var_screeninfo *var)
{
int i = 0;
+ int stored = -EINVAL;
while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL)
{
@@ -609,25 +611,38 @@ int svga_match_format(const struct svga_fb_format *frm, struct fb_var_screeninfo
(var->green.length <= frm->green.length) &&
(var->blue.length <= frm->blue.length) &&
(var->transp.length <= frm->transp.length) &&
- (var->nonstd == frm->nonstd)) {
- var->bits_per_pixel = frm->bits_per_pixel;
- var->red = frm->red;
- var->green = frm->green;
- var->blue = frm->blue;
- var->transp = frm->transp;
- var->nonstd = frm->nonstd;
- if (fix != NULL) {
- fix->type = frm->type;
- fix->type_aux = frm->type_aux;
- fix->visual = frm->visual;
- fix->xpanstep = frm->xpanstep;
- }
+ (var->nonstd == frm->nonstd))
return i;
- }
+ if (var->bits_per_pixel == frm->bits_per_pixel)
+ stored = i;
i++;
frm++;
}
- return -EINVAL;
+ return stored;
+}
+
+int svga_match_format(const struct svga_fb_format *frm,
+ struct fb_var_screeninfo *var,
+ struct fb_fix_screeninfo *fix)
+{
+ int i = match_format(frm, var);
+
+ if (i >= 0) {
+ var->bits_per_pixel = frm[i].bits_per_pixel;
+ var->red = frm[i].red;
+ var->green = frm[i].green;
+ var->blue = frm[i].blue;
+ var->transp = frm[i].transp;
+ var->nonstd = frm[i].nonstd;
+ if (fix != NULL) {
+ fix->type = frm[i].type;
+ fix->type_aux = frm[i].type_aux;
+ fix->visual = frm[i].visual;
+ fix->xpanstep = frm[i].xpanstep;
+ }
+ }
+
+ return i;
}
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index 689ce0270b8..057bdd59380 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -4,13 +4,13 @@
*
* Author: Hannu Mallat <hmallat@cc.hut.fi>
*
- * Copyright © 1999 Hannu Mallat
+ * Copyright © 1999 Hannu Mallat
* All rights reserved
*
* Created : Thu Sep 23 18:17:43 1999, hmallat
* Last modified: Tue Nov 2 21:19:47 1999, hmallat
*
- * Lots of the information here comes from the Daryll Strauss' Banshee
+ * Lots of the information here comes from the Daryll Strauss' Banshee
* patches to the XF86 server, and the rest comes from the 3dfx
* Banshee specification. I'm very much indebted to Daryll for his
* work on the X server.
@@ -23,7 +23,7 @@
* behave very differently from the Voodoo3/4/5. For anyone wanting to
* use frame buffer on the Voodoo1/2, see the sstfb driver (which is
* located at http://www.sourceforge.net/projects/sstfb).
- *
+ *
* While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
* I do wish the next version is a bit more complete. Without the XF86
* patches I couldn't have gotten even this far... for instance, the
@@ -33,9 +33,8 @@
*
* The structure of this driver comes pretty much from the Permedia
* driver by Ilario Nardinocchi, which in turn is based on skeletonfb.
- *
+ *
* TODO:
- * - support for 16/32 bpp needs fixing (funky bootup penguin)
* - multihead support (basically need to support an array of fb_infos)
* - support other architectures (PPC, Alpha); does the fact that the VGA
* core can be accessed only thru I/O (not memory mapped) complicate
@@ -43,18 +42,18 @@
*
* Version history:
*
- * 0.1.4 (released 2002-05-28) ported over to new fbdev api by James Simmons
+ * 0.1.4 (released 2002-05-28) ported over to new fbdev api by James Simmons
*
- * 0.1.3 (released 1999-11-02) added Attila's panning support, code
- * reorg, hwcursor address page size alignment
- * (for mmaping both frame buffer and regs),
- * and my changes to get rid of hardcoded
- * VGA i/o register locations (uses PCI
- * configuration info now)
- * 0.1.2 (released 1999-10-19) added Attila Kesmarki's bug fixes and
- * improvements
- * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga.
- * 0.1.0 (released 1999-10-06) initial version
+ * 0.1.3 (released 1999-11-02) added Attila's panning support, code
+ * reorg, hwcursor address page size alignment
+ * (for mmaping both frame buffer and regs),
+ * and my changes to get rid of hardcoded
+ * VGA i/o register locations (uses PCI
+ * configuration info now)
+ * 0.1.2 (released 1999-10-19) added Attila Kesmarki's bug fixes and
+ * improvements
+ * 0.1.1 (released 1999-10-07) added Voodoo3 support by Harold Oga.
+ * 0.1.0 (released 1999-10-06) initial version
*
*/
@@ -64,24 +63,32 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
-#include <linux/nvram.h>
#include <asm/io.h>
-#include <linux/timer.h>
-#include <linux/spinlock.h>
#include <video/tdfx.h>
-#undef TDFXFB_DEBUG
-#ifdef TDFXFB_DEBUG
-#define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b)
+#define DPRINTK(a, b...) pr_debug("fb: %s: " a, __FUNCTION__ , ## b)
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
#else
-#define DPRINTK(a,b...)
-#endif
+/* duplicate asm/mtrr.h defines to work on archs without mtrr */
+#define MTRR_TYPE_WRCOMB 1
+
+static inline int mtrr_add(unsigned long base, unsigned long size,
+ unsigned int type, char increment)
+{
+ return -ENODEV;
+}
+static inline int mtrr_del(int reg, unsigned long base,
+ unsigned long size)
+{
+ return -ENODEV;
+}
+#endif
#define BANSHEE_MAX_PIXCLOCK 270000
#define VOODOO3_MAX_PIXCLOCK 300000
@@ -90,9 +97,9 @@
static struct fb_fix_screeninfo tdfx_fix __devinitdata = {
.id = "3Dfx",
.type = FB_TYPE_PACKED_PIXELS,
- .visual = FB_VISUAL_PSEUDOCOLOR,
+ .visual = FB_VISUAL_PSEUDOCOLOR,
.ypanstep = 1,
- .ywrapstep = 1,
+ .ywrapstep = 1,
.accel = FB_ACCEL_3DFX_BANSHEE
};
@@ -102,7 +109,7 @@ static struct fb_var_screeninfo tdfx_var __devinitdata = {
.yres = 480,
.xres_virtual = 640,
.yres_virtual = 1024,
- .bits_per_pixel =8,
+ .bits_per_pixel = 8,
.red = {0, 8, 0},
.blue = {0, 8, 0},
.green = {0, 8, 0},
@@ -142,103 +149,79 @@ static struct pci_device_id tdfxfb_id_table[] = {
static struct pci_driver tdfxfb_driver = {
.name = "tdfxfb",
- .id_table = tdfxfb_id_table,
- .probe = tdfxfb_probe,
- .remove = __devexit_p(tdfxfb_remove),
+ .id_table = tdfxfb_id_table,
+ .probe = tdfxfb_probe,
+ .remove = __devexit_p(tdfxfb_remove),
};
MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
/*
- * Frame buffer device API
+ * Driver data
*/
-static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb);
-static int tdfxfb_set_par(struct fb_info *info);
-static int tdfxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info);
-static int tdfxfb_blank(int blank, struct fb_info *info);
-static int tdfxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
-static int banshee_wait_idle(struct fb_info *info);
-#ifdef CONFIG_FB_3DFX_ACCEL
-static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
-static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
-static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image);
-#endif /* CONFIG_FB_3DFX_ACCEL */
-
-static struct fb_ops tdfxfb_ops = {
- .owner = THIS_MODULE,
- .fb_check_var = tdfxfb_check_var,
- .fb_set_par = tdfxfb_set_par,
- .fb_setcolreg = tdfxfb_setcolreg,
- .fb_blank = tdfxfb_blank,
- .fb_pan_display = tdfxfb_pan_display,
- .fb_sync = banshee_wait_idle,
-#ifdef CONFIG_FB_3DFX_ACCEL
- .fb_fillrect = tdfxfb_fillrect,
- .fb_copyarea = tdfxfb_copyarea,
- .fb_imageblit = tdfxfb_imageblit,
-#else
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
-#endif
-};
-
-/*
- * do_xxx: Hardware-specific functions
- */
-static u32 do_calc_pll(int freq, int *freq_out);
-static void do_write_regs(struct fb_info *info, struct banshee_reg *reg);
-static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short);
-
-/*
- * Driver data
- */
-static int nopan = 0;
-static int nowrap = 1; // not implemented (yet)
-static char *mode_option __devinitdata = NULL;
-
-/* -------------------------------------------------------------------------
- * Hardware-specific funcions
+static int nopan;
+static int nowrap = 1; /* not implemented (yet) */
+static int hwcursor = 1;
+static char *mode_option __devinitdata;
+/* mtrr option */
+static int nomtrr __devinitdata;
+
+/* -------------------------------------------------------------------------
+ * Hardware-specific funcions
* ------------------------------------------------------------------------- */
-#ifdef VGA_REG_IO
-static inline u8 vga_inb(struct tdfx_par *par, u32 reg) { return inb(reg); }
-
-static inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val) { outb(val, reg); }
-#else
-static inline u8 vga_inb(struct tdfx_par *par, u32 reg) {
- return inb(par->iobase + reg - 0x300);
+static inline u8 vga_inb(struct tdfx_par *par, u32 reg)
+{
+ return inb(par->iobase + reg - 0x300);
}
-static inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val) {
- outb(val, par->iobase + reg - 0x300);
+
+static inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val)
+{
+ outb(val, par->iobase + reg - 0x300);
}
-#endif
-static inline void gra_outb(struct tdfx_par *par, u32 idx, u8 val) {
- vga_outb(par, GRA_I, idx); vga_outb(par, GRA_D, val);
+static inline void gra_outb(struct tdfx_par *par, u32 idx, u8 val)
+{
+ vga_outb(par, GRA_I, idx);
+ wmb();
+ vga_outb(par, GRA_D, val);
+ wmb();
}
-static inline void seq_outb(struct tdfx_par *par, u32 idx, u8 val) {
- vga_outb(par, SEQ_I, idx); vga_outb(par, SEQ_D, val);
+static inline void seq_outb(struct tdfx_par *par, u32 idx, u8 val)
+{
+ vga_outb(par, SEQ_I, idx);
+ wmb();
+ vga_outb(par, SEQ_D, val);
+ wmb();
}
-static inline u8 seq_inb(struct tdfx_par *par, u32 idx) {
- vga_outb(par, SEQ_I, idx); return vga_inb(par, SEQ_D);
+static inline u8 seq_inb(struct tdfx_par *par, u32 idx)
+{
+ vga_outb(par, SEQ_I, idx);
+ mb();
+ return vga_inb(par, SEQ_D);
}
-static inline void crt_outb(struct tdfx_par *par, u32 idx, u8 val) {
- vga_outb(par, CRT_I, idx); vga_outb(par, CRT_D, val);
+static inline void crt_outb(struct tdfx_par *par, u32 idx, u8 val)
+{
+ vga_outb(par, CRT_I, idx);
+ wmb();
+ vga_outb(par, CRT_D, val);
+ wmb();
}
-static inline u8 crt_inb(struct tdfx_par *par, u32 idx) {
- vga_outb(par, CRT_I, idx); return vga_inb(par, CRT_D);
+static inline u8 crt_inb(struct tdfx_par *par, u32 idx)
+{
+ vga_outb(par, CRT_I, idx);
+ mb();
+ return vga_inb(par, CRT_D);
}
-static inline void att_outb(struct tdfx_par *par, u32 idx, u8 val)
+static inline void att_outb(struct tdfx_par *par, u32 idx, u8 val)
{
unsigned char tmp;
-
+
tmp = vga_inb(par, IS1_R);
vga_outb(par, ATT_IW, idx);
vga_outb(par, ATT_IW, val);
@@ -267,10 +250,11 @@ static inline void vga_enable_video(struct tdfx_par *par)
static inline void vga_enable_palette(struct tdfx_par *par)
{
vga_inb(par, IS1_R);
+ mb();
vga_outb(par, ATT_IW, 0x20);
}
-static inline u32 tdfx_inl(struct tdfx_par *par, unsigned int reg)
+static inline u32 tdfx_inl(struct tdfx_par *par, unsigned int reg)
{
return readl(par->regbase_virt + reg);
}
@@ -284,9 +268,10 @@ static inline void banshee_make_room(struct tdfx_par *par, int size)
{
/* Note: The Voodoo3's onboard FIFO has 32 slots. This loop
* won't quit if you ask for more. */
- while((tdfx_inl(par, STATUS) & 0x1f) < size-1);
+ while ((tdfx_inl(par, STATUS) & 0x1f) < size - 1)
+ cpu_relax();
}
-
+
static int banshee_wait_idle(struct fb_info *info)
{
struct tdfx_par *par = info->par;
@@ -295,28 +280,31 @@ static int banshee_wait_idle(struct fb_info *info)
banshee_make_room(par, 1);
tdfx_outl(par, COMMAND_3D, COMMAND_3D_NOP);
- while(1) {
- i = (tdfx_inl(par, STATUS) & STATUS_BUSY) ? 0 : i + 1;
- if(i == 3) break;
- }
+ do {
+ if ((tdfx_inl(par, STATUS) & STATUS_BUSY) == 0)
+ i++;
+ } while (i < 3);
+
return 0;
}
/*
- * Set the color of a palette entry in 8bpp mode
+ * Set the color of a palette entry in 8bpp mode
*/
static inline void do_setpalentry(struct tdfx_par *par, unsigned regno, u32 c)
-{
+{
banshee_make_room(par, 2);
tdfx_outl(par, DACADDR, regno);
+ /* read after write makes it working */
+ tdfx_inl(par, DACADDR);
tdfx_outl(par, DACDATA, c);
}
-static u32 do_calc_pll(int freq, int* freq_out)
+static u32 do_calc_pll(int freq, int *freq_out)
{
int m, n, k, best_m, best_n, best_k, best_error;
int fref = 14318;
-
+
best_error = freq;
best_n = best_m = best_k = 0;
@@ -326,27 +314,28 @@ static u32 do_calc_pll(int freq, int* freq_out)
* Estimate value of n that produces target frequency
* with current m and k
*/
- int n_estimated = (freq * (m + 2) * (1 << k) / fref) - 2;
+ int n_estimated = ((freq * (m + 2) << k) / fref) - 2;
/* Search neighborhood of estimated n */
- for (n = max(0, n_estimated - 1);
- n <= min(255, n_estimated + 1); n++) {
+ for (n = max(0, n_estimated);
+ n <= min(255, n_estimated + 1);
+ n++) {
/*
* Calculate PLL freqency with current m, k and
* estimated n
*/
- int f = fref * (n + 2) / (m + 2) / (1 << k);
- int error = abs (f - freq);
+ int f = (fref * (n + 2) / (m + 2)) >> k;
+ int error = abs(f - freq);
/*
- * If this is the closest we've come to the
+ * If this is the closest we've come to the
* target frequency then remember n, m and k
*/
- if (error < best_error) {
+ if (error < best_error) {
best_error = error;
- best_n = n;
- best_m = m;
- best_k = k;
+ best_n = n;
+ best_m = m;
+ best_k = k;
}
}
}
@@ -355,12 +344,12 @@ static u32 do_calc_pll(int freq, int* freq_out)
n = best_n;
m = best_m;
k = best_k;
- *freq_out = fref*(n + 2)/(m + 2)/(1 << k);
+ *freq_out = (fref * (n + 2) / (m + 2)) >> k;
return (n << 8) | (m << 2) | k;
}
-static void do_write_regs(struct fb_info *info, struct banshee_reg* reg)
+static void do_write_regs(struct fb_info *info, struct banshee_reg *reg)
{
struct tdfx_par *par = info->par;
int i;
@@ -372,13 +361,13 @@ static void do_write_regs(struct fb_info *info, struct banshee_reg* reg)
crt_outb(par, 0x11, crt_inb(par, 0x11) & 0x7f); /* CRT unprotect */
banshee_make_room(par, 3);
- tdfx_outl(par, VGAINIT1, reg->vgainit1 & 0x001FFFFF);
- tdfx_outl(par, VIDPROCCFG, reg->vidcfg & ~0x00000001);
+ tdfx_outl(par, VGAINIT1, reg->vgainit1 & 0x001FFFFF);
+ tdfx_outl(par, VIDPROCCFG, reg->vidcfg & ~0x00000001);
#if 0
tdfx_outl(par, PLLCTRL1, reg->mempll);
tdfx_outl(par, PLLCTRL2, reg->gfxpll);
#endif
- tdfx_outl(par, PLLCTRL0, reg->vidpll);
+ tdfx_outl(par, PLLCTRL0, reg->vidpll);
vga_outb(par, MISC_W, reg->misc[0x00] | 0x01);
@@ -400,72 +389,65 @@ static void do_write_regs(struct fb_info *info, struct banshee_reg* reg)
vga_enable_palette(par);
vga_enable_video(par);
- banshee_make_room(par, 11);
- tdfx_outl(par, VGAINIT0, reg->vgainit0);
- tdfx_outl(par, DACMODE, reg->dacmode);
- tdfx_outl(par, VIDDESKSTRIDE, reg->stride);
- tdfx_outl(par, HWCURPATADDR, 0);
-
- tdfx_outl(par, VIDSCREENSIZE,reg->screensize);
- tdfx_outl(par, VIDDESKSTART, reg->startaddr);
- tdfx_outl(par, VIDPROCCFG, reg->vidcfg);
- tdfx_outl(par, VGAINIT1, reg->vgainit1);
- tdfx_outl(par, MISCINIT0, reg->miscinit0);
-
- banshee_make_room(par, 8);
- tdfx_outl(par, SRCBASE, reg->srcbase);
- tdfx_outl(par, DSTBASE, reg->dstbase);
- tdfx_outl(par, COMMANDEXTRA_2D, 0);
- tdfx_outl(par, CLIP0MIN, 0);
- tdfx_outl(par, CLIP0MAX, 0x0fff0fff);
- tdfx_outl(par, CLIP1MIN, 0);
- tdfx_outl(par, CLIP1MAX, 0x0fff0fff);
- tdfx_outl(par, SRCXY, 0);
+ banshee_make_room(par, 9);
+ tdfx_outl(par, VGAINIT0, reg->vgainit0);
+ tdfx_outl(par, DACMODE, reg->dacmode);
+ tdfx_outl(par, VIDDESKSTRIDE, reg->stride);
+ tdfx_outl(par, HWCURPATADDR, reg->curspataddr);
+
+ tdfx_outl(par, VIDSCREENSIZE, reg->screensize);
+ tdfx_outl(par, VIDDESKSTART, reg->startaddr);
+ tdfx_outl(par, VIDPROCCFG, reg->vidcfg);
+ tdfx_outl(par, VGAINIT1, reg->vgainit1);
+ tdfx_outl(par, MISCINIT0, reg->miscinit0);
+
+ banshee_make_room(par, 8);
+ tdfx_outl(par, SRCBASE, reg->startaddr);
+ tdfx_outl(par, DSTBASE, reg->startaddr);
+ tdfx_outl(par, COMMANDEXTRA_2D, 0);
+ tdfx_outl(par, CLIP0MIN, 0);
+ tdfx_outl(par, CLIP0MAX, 0x0fff0fff);
+ tdfx_outl(par, CLIP1MIN, 0);
+ tdfx_outl(par, CLIP1MAX, 0x0fff0fff);
+ tdfx_outl(par, SRCXY, 0);
banshee_wait_idle(info);
}
-static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id)
+static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id)
{
- u32 draminit0;
- u32 draminit1;
+ u32 draminit0 = tdfx_inl(par, DRAMINIT0);
+ u32 draminit1 = tdfx_inl(par, DRAMINIT1);
u32 miscinit1;
-
- int num_chips;
+ int num_chips = (draminit0 & DRAMINIT0_SGRAM_NUM) ? 8 : 4;
int chip_size; /* in MB */
- u32 lfbsize;
- int has_sgram;
+ int has_sgram = draminit1 & DRAMINIT1_MEM_SDRAM;
- draminit0 = tdfx_inl(par, DRAMINIT0);
- draminit1 = tdfx_inl(par, DRAMINIT1);
-
- num_chips = (draminit0 & DRAMINIT0_SGRAM_NUM) ? 8 : 4;
-
if (dev_id < PCI_DEVICE_ID_3DFX_VOODOO5) {
/* Banshee/Voodoo3 */
- has_sgram = draminit1 & DRAMINIT1_MEM_SDRAM;
- chip_size = has_sgram ? ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 2 : 1)
- : 2;
+ chip_size = 2;
+ if (has_sgram && (draminit0 & DRAMINIT0_SGRAM_TYPE))
+ chip_size = 1;
} else {
/* Voodoo4/5 */
has_sgram = 0;
- chip_size = 1 << ((draminit0 & DRAMINIT0_SGRAM_TYPE_MASK) >> DRAMINIT0_SGRAM_TYPE_SHIFT);
+ chip_size = draminit0 & DRAMINIT0_SGRAM_TYPE_MASK;
+ chip_size = 1 << (chip_size >> DRAMINIT0_SGRAM_TYPE_SHIFT);
}
- lfbsize = num_chips * chip_size * 1024 * 1024;
/* disable block writes for SDRAM */
miscinit1 = tdfx_inl(par, MISCINIT1);
miscinit1 |= has_sgram ? 0 : MISCINIT1_2DBLOCK_DIS;
miscinit1 |= MISCINIT1_CLUT_INV;
- banshee_make_room(par, 1);
+ banshee_make_room(par, 1);
tdfx_outl(par, MISCINIT1, miscinit1);
- return lfbsize;
+ return num_chips * chip_size * 1024l * 1024;
}
/* ------------------------------------------------------------------------- */
-static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info)
+static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct tdfx_par *par = info->par;
u32 lpitch;
@@ -486,103 +468,113 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info)
DPRINTK("xoffset not supported\n");
return -EINVAL;
}
+ var->yoffset = 0;
- /* Banshee doesn't support interlace, but Voodoo4/5 and probably Voodoo3 do. */
- /* no direct information about device id now? use max_pixclock for this... */
+ /*
+ * Banshee doesn't support interlace, but Voodoo4/5 and probably
+ * Voodoo3 do.
+ * no direct information about device id now?
+ * use max_pixclock for this...
+ */
if (((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) &&
- (par->max_pixclock < VOODOO3_MAX_PIXCLOCK)) {
+ (par->max_pixclock < VOODOO3_MAX_PIXCLOCK)) {
DPRINTK("interlace not supported\n");
return -EINVAL;
}
var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
- lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
-
+ lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
+
if (var->xres < 320 || var->xres > 2048) {
DPRINTK("width not supported: %u\n", var->xres);
return -EINVAL;
}
-
+
if (var->yres < 200 || var->yres > 2048) {
DPRINTK("height not supported: %u\n", var->yres);
return -EINVAL;
}
-
+
if (lpitch * var->yres_virtual > info->fix.smem_len) {
- var->yres_virtual = info->fix.smem_len/lpitch;
+ var->yres_virtual = info->fix.smem_len / lpitch;
if (var->yres_virtual < var->yres) {
DPRINTK("no memory for screen (%ux%ux%u)\n",
- var->xres, var->yres_virtual, var->bits_per_pixel);
+ var->xres, var->yres_virtual,
+ var->bits_per_pixel);
return -EINVAL;
}
}
-
+
if (PICOS2KHZ(var->pixclock) > par->max_pixclock) {
- DPRINTK("pixclock too high (%ldKHz)\n",PICOS2KHZ(var->pixclock));
+ DPRINTK("pixclock too high (%ldKHz)\n",
+ PICOS2KHZ(var->pixclock));
return -EINVAL;
}
- switch(var->bits_per_pixel) {
- case 8:
- var->red.length = var->green.length = var->blue.length = 8;
- break;
- case 16:
- var->red.offset = 11;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 5;
- break;
- case 24:
- var->red.offset=16;
- var->green.offset=8;
- var->blue.offset=0;
- var->red.length = var->green.length = var->blue.length = 8;
- case 32:
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
- var->red.length = var->green.length = var->blue.length = 8;
- break;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ switch (var->bits_per_pixel) {
+ case 8:
+ var->red.length = 8;
+ var->red.offset = 0;
+ var->green = var->red;
+ var->blue = var->red;
+ break;
+ case 16:
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ break;
+ case 32:
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ case 24:
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = var->green.length = var->blue.length = 8;
+ break;
}
- var->height = var->width = -1;
-
+ var->width = -1;
+ var->height = -1;
+
var->accel_flags = FB_ACCELF_TEXT;
-
- DPRINTK("Checking graphics mode at %dx%d depth %d\n", var->xres, var->yres, var->bits_per_pixel);
+
+ DPRINTK("Checking graphics mode at %dx%d depth %d\n",
+ var->xres, var->yres, var->bits_per_pixel);
return 0;
}
static int tdfxfb_set_par(struct fb_info *info)
{
struct tdfx_par *par = info->par;
- u32 hdispend, hsyncsta, hsyncend, htotal;
+ u32 hdispend = info->var.xres;
+ u32 hsyncsta = hdispend + info->var.right_margin;
+ u32 hsyncend = hsyncsta + info->var.hsync_len;
+ u32 htotal = hsyncend + info->var.left_margin;
u32 hd, hs, he, ht, hbs, hbe;
u32 vd, vs, ve, vt, vbs, vbe;
struct banshee_reg reg;
int fout, freq;
- u32 wd, cpp;
-
- par->baseline = 0;
-
+ u32 wd;
+ u32 cpp = (info->var.bits_per_pixel + 7) >> 3;
+
memset(&reg, 0, sizeof(reg));
- cpp = (info->var.bits_per_pixel + 7)/8;
-
- reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE | VIDCFG_CURS_X11 | ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) | (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
+
+ reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE |
+ VIDCFG_CURS_X11 |
+ ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
+ (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
/* PLL settings */
freq = PICOS2KHZ(info->var.pixclock);
- reg.dacmode = 0;
- reg.vidcfg &= ~VIDCFG_2X;
-
- hdispend = info->var.xres;
- hsyncsta = hdispend + info->var.right_margin;
- hsyncend = hsyncsta + info->var.hsync_len;
- htotal = hsyncend + info->var.left_margin;
+ reg.vidcfg &= ~VIDCFG_2X;
- if (freq > par->max_pixclock/2) {
+ if (freq > par->max_pixclock / 2) {
freq = freq > par->max_pixclock ? par->max_pixclock : freq;
reg.dacmode |= DACMODE_2X;
reg.vidcfg |= VIDCFG_2X;
@@ -591,8 +583,9 @@ static int tdfxfb_set_par(struct fb_info *info)
hsyncend >>= 1;
htotal >>= 1;
}
-
- hd = wd = (hdispend >> 3) - 1;
+
+ wd = (hdispend >> 3) - 1;
+ hd = wd;
hs = (hsyncsta >> 3) - 1;
he = (hsyncend >> 3) - 1;
ht = (htotal >> 3) - 1;
@@ -600,28 +593,30 @@ static int tdfxfb_set_par(struct fb_info *info)
hbe = ht;
if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
- vbs = vd = (info->var.yres << 1) - 1;
+ vd = (info->var.yres << 1) - 1;
vs = vd + (info->var.lower_margin << 1);
ve = vs + (info->var.vsync_len << 1);
- vbe = vt = ve + (info->var.upper_margin << 1) - 1;
+ vt = ve + (info->var.upper_margin << 1) - 1;
+ reg.screensize = info->var.xres | (info->var.yres << 13);
+ reg.vidcfg |= VIDCFG_HALF_MODE;
+ reg.crt[0x09] = 0x80;
} else {
- vbs = vd = info->var.yres - 1;
+ vd = info->var.yres - 1;
vs = vd + info->var.lower_margin;
ve = vs + info->var.vsync_len;
- vbe = vt = ve + info->var.upper_margin - 1;
+ vt = ve + info->var.upper_margin - 1;
+ reg.screensize = info->var.xres | (info->var.yres << 12);
+ reg.vidcfg &= ~VIDCFG_HALF_MODE;
}
-
+ vbs = vd;
+ vbe = vt;
+
/* this is all pretty standard VGA register stuffing */
- reg.misc[0x00] = 0x0f |
+ reg.misc[0x00] = 0x0f |
(info->var.xres < 400 ? 0xa0 :
info->var.xres < 480 ? 0x60 :
info->var.xres < 768 ? 0xe0 : 0x20);
-
- reg.gra[0x00] = 0x00;
- reg.gra[0x01] = 0x00;
- reg.gra[0x02] = 0x00;
- reg.gra[0x03] = 0x00;
- reg.gra[0x04] = 0x00;
+
reg.gra[0x05] = 0x40;
reg.gra[0x06] = 0x05;
reg.gra[0x07] = 0x0f;
@@ -644,10 +639,7 @@ static int tdfxfb_set_par(struct fb_info *info)
reg.att[0x0e] = 0x0e;
reg.att[0x0f] = 0x0f;
reg.att[0x10] = 0x41;
- reg.att[0x11] = 0x00;
reg.att[0x12] = 0x0f;
- reg.att[0x13] = 0x00;
- reg.att[0x14] = 0x00;
reg.seq[0x00] = 0x03;
reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
@@ -660,146 +652,133 @@ static int tdfxfb_set_par(struct fb_info *info)
reg.crt[0x02] = hbs;
reg.crt[0x03] = 0x80 | (hbe & 0x1f);
reg.crt[0x04] = hs;
- reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
+ reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
reg.crt[0x06] = vt;
reg.crt[0x07] = ((vs & 0x200) >> 2) |
((vd & 0x200) >> 3) |
((vt & 0x200) >> 4) | 0x10 |
((vbs & 0x100) >> 5) |
- ((vs & 0x100) >> 6) |
- ((vd & 0x100) >> 7) |
- ((vt & 0x100) >> 8);
- reg.crt[0x08] = 0x00;
- reg.crt[0x09] = 0x40 | ((vbs & 0x200) >> 4);
- reg.crt[0x0a] = 0x00;
- reg.crt[0x0b] = 0x00;
- reg.crt[0x0c] = 0x00;
- reg.crt[0x0d] = 0x00;
- reg.crt[0x0e] = 0x00;
- reg.crt[0x0f] = 0x00;
+ ((vs & 0x100) >> 6) |
+ ((vd & 0x100) >> 7) |
+ ((vt & 0x100) >> 8);
+ reg.crt[0x09] |= 0x40 | ((vbs & 0x200) >> 4);
reg.crt[0x10] = vs;
- reg.crt[0x11] = (ve & 0x0f) | 0x20;
+ reg.crt[0x11] = (ve & 0x0f) | 0x20;
reg.crt[0x12] = vd;
reg.crt[0x13] = wd;
- reg.crt[0x14] = 0x00;
reg.crt[0x15] = vbs;
- reg.crt[0x16] = vbe + 1;
+ reg.crt[0x16] = vbe + 1;
reg.crt[0x17] = 0xc3;
reg.crt[0x18] = 0xff;
-
+
/* Banshee's nonvga stuff */
- reg.ext[0x00] = (((ht & 0x100) >> 8) |
- ((hd & 0x100) >> 6) |
+ reg.ext[0x00] = (((ht & 0x100) >> 8) |
+ ((hd & 0x100) >> 6) |
((hbs & 0x100) >> 4) |
- ((hbe & 0x40) >> 1) |
- ((hs & 0x100) >> 2) |
- ((he & 0x20) << 2));
- reg.ext[0x01] = (((vt & 0x400) >> 10) |
- ((vd & 0x400) >> 8) |
- ((vbs & 0x400) >> 6) |
- ((vbe & 0x400) >> 4));
-
- reg.vgainit0 = VGAINIT0_8BIT_DAC |
+ ((hbe & 0x40) >> 1) |
+ ((hs & 0x100) >> 2) |
+ ((he & 0x20) << 2));
+ reg.ext[0x01] = (((vt & 0x400) >> 10) |
+ ((vd & 0x400) >> 8) |
+ ((vbs & 0x400) >> 6) |
+ ((vbe & 0x400) >> 4));
+
+ reg.vgainit0 = VGAINIT0_8BIT_DAC |
VGAINIT0_EXT_ENABLE |
VGAINIT0_WAKEUP_3C3 |
VGAINIT0_ALT_READBACK |
VGAINIT0_EXTSHIFTOUT;
reg.vgainit1 = tdfx_inl(par, VGAINIT1) & 0x1fffff;
+ if (hwcursor)
+ reg.curspataddr = info->fix.smem_len;
+
reg.cursloc = 0;
-
- reg.cursc0 = 0;
+
+ reg.cursc0 = 0;
reg.cursc1 = 0xffffff;
-
- reg.stride = info->var.xres * cpp;
- reg.startaddr = par->baseline * reg.stride;
- reg.srcbase = reg.startaddr;
- reg.dstbase = reg.startaddr;
- /* PLL settings */
- freq = PICOS2KHZ(info->var.pixclock);
+ reg.stride = info->var.xres * cpp;
+ reg.startaddr = info->var.yoffset * reg.stride
+ + info->var.xoffset * cpp;
- reg.dacmode &= ~DACMODE_2X;
- reg.vidcfg &= ~VIDCFG_2X;
- if (freq > par->max_pixclock/2) {
- freq = freq > par->max_pixclock ? par->max_pixclock : freq;
- reg.dacmode |= DACMODE_2X;
- reg.vidcfg |= VIDCFG_2X;
- }
reg.vidpll = do_calc_pll(freq, &fout);
#if 0
reg.mempll = do_calc_pll(..., &fout);
reg.gfxpll = do_calc_pll(..., &fout);
#endif
- if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
- reg.screensize = info->var.xres | (info->var.yres << 13);
- reg.vidcfg |= VIDCFG_HALF_MODE;
- reg.crt[0x09] |= 0x80;
- } else {
- reg.screensize = info->var.xres | (info->var.yres << 12);
- reg.vidcfg &= ~VIDCFG_HALF_MODE;
- }
if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
reg.vidcfg |= VIDCFG_INTERLACE;
reg.miscinit0 = tdfx_inl(par, MISCINIT0);
#if defined(__BIG_ENDIAN)
switch (info->var.bits_per_pixel) {
- case 8:
- case 24:
- reg.miscinit0 &= ~(1 << 30);
- reg.miscinit0 &= ~(1 << 31);
- break;
- case 16:
- reg.miscinit0 |= (1 << 30);
- reg.miscinit0 |= (1 << 31);
- break;
- case 32:
- reg.miscinit0 |= (1 << 30);
- reg.miscinit0 &= ~(1 << 31);
- break;
+ case 8:
+ case 24:
+ reg.miscinit0 &= ~(1 << 30);
+ reg.miscinit0 &= ~(1 << 31);
+ break;
+ case 16:
+ reg.miscinit0 |= (1 << 30);
+ reg.miscinit0 |= (1 << 31);
+ break;
+ case 32:
+ reg.miscinit0 |= (1 << 30);
+ reg.miscinit0 &= ~(1 << 31);
+ break;
}
-#endif
+#endif
do_write_regs(info, &reg);
/* Now change fb_fix_screeninfo according to changes in par */
- info->fix.line_length = info->var.xres * ((info->var.bits_per_pixel + 7)>>3);
- info->fix.visual = (info->var.bits_per_pixel == 8)
+ info->fix.line_length = reg.stride;
+ info->fix.visual = (info->var.bits_per_pixel == 8)
? FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_TRUECOLOR;
- DPRINTK("Graphics mode is now set at %dx%d depth %d\n", info->var.xres, info->var.yres, info->var.bits_per_pixel);
- return 0;
+ DPRINTK("Graphics mode is now set at %dx%d depth %d\n",
+ info->var.xres, info->var.yres, info->var.bits_per_pixel);
+ return 0;
}
/* A handy macro shamelessly pinched from matroxfb */
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
-static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue,unsigned transp,struct fb_info *info)
+static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
{
struct tdfx_par *par = info->par;
u32 rgbcol;
-
- if (regno >= info->cmap.len || regno > 255) return 1;
-
+
+ if (regno >= info->cmap.len || regno > 255)
+ return 1;
+
+ /* grayscale works only partially under directcolor */
+ if (info->var.grayscale) {
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ green = blue;
+ red = blue;
+ }
+
switch (info->fix.visual) {
case FB_VISUAL_PSEUDOCOLOR:
- rgbcol =(((u32)red & 0xff00) << 8) |
- (((u32)green & 0xff00) << 0) |
- (((u32)blue & 0xff00) >> 8);
+ rgbcol = (((u32)red & 0xff00) << 8) |
+ (((u32)green & 0xff00) << 0) |
+ (((u32)blue & 0xff00) >> 8);
do_setpalentry(par, regno, rgbcol);
break;
/* Truecolor has no hardware color palettes. */
case FB_VISUAL_TRUECOLOR:
if (regno < 16) {
- rgbcol = (CNVT_TOHW( red, info->var.red.length) <<
+ rgbcol = (CNVT_TOHW(red, info->var.red.length) <<
info->var.red.offset) |
- (CNVT_TOHW( green, info->var.green.length) <<
+ (CNVT_TOHW(green, info->var.green.length) <<
info->var.green.offset) |
- (CNVT_TOHW( blue, info->var.blue.length) <<
+ (CNVT_TOHW(blue, info->var.blue.length) <<
info->var.blue.offset) |
- (CNVT_TOHW( transp, info->var.transp.length) <<
+ (CNVT_TOHW(transp, info->var.transp.length) <<
info->var.transp.offset);
par->palette[regno] = rgbcol;
}
@@ -815,287 +794,325 @@ static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
static int tdfxfb_blank(int blank, struct fb_info *info)
-{
+{
struct tdfx_par *par = info->par;
- u32 dacmode, state = 0, vgablank = 0;
+ int vgablank = 1;
+ u32 dacmode = tdfx_inl(par, DACMODE);
- dacmode = tdfx_inl(par, DACMODE);
+ dacmode &= ~(BIT(1) | BIT(3));
switch (blank) {
- case FB_BLANK_UNBLANK: /* Screen: On; HSync: On, VSync: On */
- state = 0;
- vgablank = 0;
- break;
- case FB_BLANK_NORMAL: /* Screen: Off; HSync: On, VSync: On */
- state = 0;
- vgablank = 1;
- break;
- case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off; HSync: On, VSync: Off */
- state = BIT(3);
- vgablank = 1;
- break;
- case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off; HSync: Off, VSync: On */
- state = BIT(1);
- vgablank = 1;
- break;
- case FB_BLANK_POWERDOWN: /* Screen: Off; HSync: Off, VSync: Off */
- state = BIT(1) | BIT(3);
- vgablank = 1;
- break;
+ case FB_BLANK_UNBLANK: /* Screen: On; HSync: On, VSync: On */
+ vgablank = 0;
+ break;
+ case FB_BLANK_NORMAL: /* Screen: Off; HSync: On, VSync: On */
+ break;
+ case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off; HSync: On, VSync: Off */
+ dacmode |= BIT(3);
+ break;
+ case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off; HSync: Off, VSync: On */
+ dacmode |= BIT(1);
+ break;
+ case FB_BLANK_POWERDOWN: /* Screen: Off; HSync: Off, VSync: Off */
+ dacmode |= BIT(1) | BIT(3);
+ break;
}
- dacmode &= ~(BIT(1) | BIT(3));
- dacmode |= state;
- banshee_make_room(par, 1);
+ banshee_make_room(par, 1);
tdfx_outl(par, DACMODE, dacmode);
- if (vgablank)
+ if (vgablank)
vga_disable_video(par);
else
vga_enable_video(par);
return 0;
}
-/*
+/*
* Set the starting position of the visible screen to var->yoffset
- */
+ */
static int tdfxfb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info)
+ struct fb_info *info)
{
struct tdfx_par *par = info->par;
- u32 addr;
+ u32 addr = var->yoffset * info->fix.line_length;
if (nopan || var->xoffset || (var->yoffset > var->yres_virtual))
return -EINVAL;
if ((var->yoffset + var->yres > var->yres_virtual && nowrap))
return -EINVAL;
- addr = var->yoffset * info->fix.line_length;
banshee_make_room(par, 1);
tdfx_outl(par, VIDDESKSTART, addr);
-
+
info->var.xoffset = var->xoffset;
- info->var.yoffset = var->yoffset;
+ info->var.yoffset = var->yoffset;
return 0;
}
#ifdef CONFIG_FB_3DFX_ACCEL
/*
- * FillRect 2D command (solidfill or invert (via ROP_XOR))
+ * FillRect 2D command (solidfill or invert (via ROP_XOR))
*/
-static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+static void tdfxfb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
{
struct tdfx_par *par = info->par;
u32 bpp = info->var.bits_per_pixel;
u32 stride = info->fix.line_length;
- u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
+ u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
int tdfx_rop;
-
- if (rect->rop == ROP_COPY)
+ u32 dx = rect->dx;
+ u32 dy = rect->dy;
+ u32 dstbase = 0;
+
+ if (rect->rop == ROP_COPY)
tdfx_rop = TDFX_ROP_COPY;
- else
+ else
tdfx_rop = TDFX_ROP_XOR;
- banshee_make_room(par, 5);
- tdfx_outl(par, DSTFORMAT, fmt);
+ /* asume always rect->height < 4096 */
+ if (dy + rect->height > 4095) {
+ dstbase = stride * dy;
+ dy = 0;
+ }
+ /* asume always rect->width < 4096 */
+ if (dx + rect->width > 4095) {
+ dstbase += dx * bpp >> 3;
+ dx = 0;
+ }
+ banshee_make_room(par, 6);
+ tdfx_outl(par, DSTFORMAT, fmt);
if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
- tdfx_outl(par, COLORFORE, rect->color);
+ tdfx_outl(par, COLORFORE, rect->color);
} else { /* FB_VISUAL_TRUECOLOR */
tdfx_outl(par, COLORFORE, par->palette[rect->color]);
}
- tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24));
- tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16));
- tdfx_outl(par, LAUNCH_2D, rect->dx | (rect->dy << 16));
+ tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24));
+ tdfx_outl(par, DSTBASE, dstbase);
+ tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16));
+ tdfx_outl(par, LAUNCH_2D, dx | (dy << 16));
}
/*
- * Screen-to-Screen BitBlt 2D command (for the bmove fb op.)
+ * Screen-to-Screen BitBlt 2D command (for the bmove fb op.)
*/
-static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+static void tdfxfb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
{
struct tdfx_par *par = info->par;
- u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy;
+ u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy;
u32 bpp = info->var.bits_per_pixel;
u32 stride = info->fix.line_length;
u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24);
- u32 fmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
-
+ u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
+ u32 dstbase = 0;
+ u32 srcbase = 0;
+
+ /* asume always area->height < 4096 */
+ if (sy + area->height > 4095) {
+ srcbase = stride * sy;
+ sy = 0;
+ }
+ /* asume always area->width < 4096 */
+ if (sx + area->width > 4095) {
+ srcbase += sx * bpp >> 3;
+ sx = 0;
+ }
+ /* asume always area->height < 4096 */
+ if (dy + area->height > 4095) {
+ dstbase = stride * dy;
+ dy = 0;
+ }
+ /* asume always area->width < 4096 */
+ if (dx + area->width > 4095) {
+ dstbase += dx * bpp >> 3;
+ dx = 0;
+ }
+
if (area->sx <= area->dx) {
- //-X
+ /* -X */
blitcmd |= BIT(14);
sx += area->width - 1;
dx += area->width - 1;
}
if (area->sy <= area->dy) {
- //-Y
+ /* -Y */
blitcmd |= BIT(15);
sy += area->height - 1;
dy += area->height - 1;
}
-
- banshee_make_room(par, 6);
- tdfx_outl(par, SRCFORMAT, fmt);
- tdfx_outl(par, DSTFORMAT, fmt);
- tdfx_outl(par, COMMAND_2D, blitcmd);
- tdfx_outl(par, DSTSIZE, area->width | (area->height << 16));
- tdfx_outl(par, DSTXY, dx | (dy << 16));
- tdfx_outl(par, LAUNCH_2D, sx | (sy << 16));
+ banshee_make_room(par, 8);
+
+ tdfx_outl(par, SRCFORMAT, fmt);
+ tdfx_outl(par, DSTFORMAT, fmt);
+ tdfx_outl(par, COMMAND_2D, blitcmd);
+ tdfx_outl(par, DSTSIZE, area->width | (area->height << 16));
+ tdfx_outl(par, DSTXY, dx | (dy << 16));
+ tdfx_outl(par, SRCBASE, srcbase);
+ tdfx_outl(par, DSTBASE, dstbase);
+ tdfx_outl(par, LAUNCH_2D, sx | (sy << 16));
}
-static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image)
+static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct tdfx_par *par = info->par;
- int size = image->height * ((image->width * image->depth + 7)>>3);
+ int size = image->height * ((image->width * image->depth + 7) >> 3);
int fifo_free;
int i, stride = info->fix.line_length;
u32 bpp = info->var.bits_per_pixel;
- u32 dstfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
+ u32 dstfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
u8 *chardata = (u8 *) image->data;
u32 srcfmt;
+ u32 dx = image->dx;
+ u32 dy = image->dy;
+ u32 dstbase = 0;
if (image->depth != 1) {
- //banshee_make_room(par, 6 + ((size + 3) >> 2));
- //srcfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13) | 0x400000;
+#ifdef BROKEN_CODE
+ banshee_make_room(par, 6 + ((size + 3) >> 2));
+ srcfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13) |
+ 0x400000;
+#else
cfb_imageblit(info, image);
+#endif
return;
- } else {
- banshee_make_room(par, 8);
- switch (info->fix.visual) {
- case FB_VISUAL_PSEUDOCOLOR:
+ }
+ banshee_make_room(par, 9);
+ switch (info->fix.visual) {
+ case FB_VISUAL_PSEUDOCOLOR:
tdfx_outl(par, COLORFORE, image->fg_color);
tdfx_outl(par, COLORBACK, image->bg_color);
- break;
- case FB_VISUAL_TRUECOLOR:
- default:
- tdfx_outl(par, COLORFORE,
- par->palette[image->fg_color]);
- tdfx_outl(par, COLORBACK,
- par->palette[image->bg_color]);
- }
+ break;
+ case FB_VISUAL_TRUECOLOR:
+ default:
+ tdfx_outl(par, COLORFORE,
+ par->palette[image->fg_color]);
+ tdfx_outl(par, COLORBACK,
+ par->palette[image->bg_color]);
+ }
#ifdef __BIG_ENDIAN
- srcfmt = 0x400000 | BIT(20);
+ srcfmt = 0x400000 | BIT(20);
#else
- srcfmt = 0x400000;
+ srcfmt = 0x400000;
#endif
- }
+ /* asume always image->height < 4096 */
+ if (dy + image->height > 4095) {
+ dstbase = stride * dy;
+ dy = 0;
+ }
+ /* asume always image->width < 4096 */
+ if (dx + image->width > 4095) {
+ dstbase += dx * bpp >> 3;
+ dx = 0;
+ }
- tdfx_outl(par, SRCXY, 0);
- tdfx_outl(par, DSTXY, image->dx | (image->dy << 16));
- tdfx_outl(par, COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
- tdfx_outl(par, SRCFORMAT, srcfmt);
- tdfx_outl(par, DSTFORMAT, dstfmt);
- tdfx_outl(par, DSTSIZE, image->width | (image->height << 16));
+ tdfx_outl(par, DSTBASE, dstbase);
+ tdfx_outl(par, SRCXY, 0);
+ tdfx_outl(par, DSTXY, dx | (dy << 16));
+ tdfx_outl(par, COMMAND_2D,
+ COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
+ tdfx_outl(par, SRCFORMAT, srcfmt);
+ tdfx_outl(par, DSTFORMAT, dstfmt);
+ tdfx_outl(par, DSTSIZE, image->width | (image->height << 16));
/* A count of how many free FIFO entries we've requested.
* When this goes negative, we need to request more. */
fifo_free = 0;
- /* Send four bytes at a time of data */
- for (i = (size >> 2) ; i > 0; i--) {
- if(--fifo_free < 0) {
- fifo_free=31;
- banshee_make_room(par,fifo_free);
+ /* Send four bytes at a time of data */
+ for (i = (size >> 2); i > 0; i--) {
+ if (--fifo_free < 0) {
+ fifo_free = 31;
+ banshee_make_room(par, fifo_free);
}
- tdfx_outl(par, LAUNCH_2D,*(u32*)chardata);
- chardata += 4;
- }
-
- /* Send the leftovers now */
- banshee_make_room(par,3);
- i = size%4;
- switch (i) {
- case 0: break;
- case 1: tdfx_outl(par, LAUNCH_2D,*chardata); break;
- case 2: tdfx_outl(par, LAUNCH_2D,*(u16*)chardata); break;
- case 3: tdfx_outl(par, LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
+ tdfx_outl(par, LAUNCH_2D, *(u32 *)chardata);
+ chardata += 4;
+ }
+
+ /* Send the leftovers now */
+ banshee_make_room(par, 3);
+ switch (size % 4) {
+ case 0:
+ break;
+ case 1:
+ tdfx_outl(par, LAUNCH_2D, *chardata);
+ break;
+ case 2:
+ tdfx_outl(par, LAUNCH_2D, *(u16 *)chardata);
+ break;
+ case 3:
+ tdfx_outl(par, LAUNCH_2D,
+ *(u16 *)chardata | (chardata[3] << 24));
+ break;
}
}
#endif /* CONFIG_FB_3DFX_ACCEL */
-#ifdef TDFX_HARDWARE_CURSOR
static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
struct tdfx_par *par = info->par;
- unsigned long flags;
+ u32 vidcfg;
- /*
- * If the cursor is not be changed this means either we want the
- * current cursor state (if enable is set) or we want to query what
- * we can do with the cursor (if enable is not set)
- */
- if (!cursor->set) return 0;
+ if (!hwcursor)
+ return -EINVAL; /* just to force soft_cursor() call */
- /* Too large of a cursor :-( */
- if (cursor->image.width > 64 || cursor->image.height > 64)
- return -ENXIO;
+ /* Too large of a cursor or wrong bpp :-( */
+ if (cursor->image.width > 64 ||
+ cursor->image.height > 64 ||
+ cursor->image.depth > 1)
+ return -EINVAL;
- /*
- * If we are going to be changing things we should disable
- * the cursor first
- */
- if (info->cursor.enable) {
- spin_lock_irqsave(&par->DAClock, flags);
- info->cursor.enable = 0;
- del_timer(&(par->hwcursor.timer));
- tdfx_outl(par, VIDPROCCFG, par->hwcursor.disable);
- spin_unlock_irqrestore(&par->DAClock, flags);
- }
+ vidcfg = tdfx_inl(par, VIDPROCCFG);
+ if (cursor->enable)
+ tdfx_outl(par, VIDPROCCFG, vidcfg | VIDCFG_HWCURSOR_ENABLE);
+ else
+ tdfx_outl(par, VIDPROCCFG, vidcfg & ~VIDCFG_HWCURSOR_ENABLE);
- /* Disable the Cursor */
- if ((cursor->set && FB_CUR_SETCUR) && !cursor->enable)
+ /*
+ * If the cursor is not be changed this means either we want the
+ * current cursor state (if enable is set) or we want to query what
+ * we can do with the cursor (if enable is not set)
+ */
+ if (!cursor->set)
return 0;
/* fix cursor color - XFree86 forgets to restore it properly */
- if (cursor->set && FB_CUR_SETCMAP) {
- struct fb_cmap cmap = cursor->image.cmap;
+ if (cursor->set & FB_CUR_SETCMAP) {
+ struct fb_cmap cmap = info->cmap;
+ u32 bg_idx = cursor->image.bg_color;
+ u32 fg_idx = cursor->image.fg_color;
unsigned long bg_color, fg_color;
- cmap.len = 2; /* Voodoo 3+ only support 2 color cursors */
- fg_color = ((cmap.red[cmap.start] << 16) |
- (cmap.green[cmap.start] << 8) |
- (cmap.blue[cmap.start]));
- bg_color = ((cmap.red[cmap.start+1] << 16) |
- (cmap.green[cmap.start+1] << 8) |
- (cmap.blue[cmap.start+1]));
- fb_copy_cmap(&cmap, &info->cursor.image.cmap);
- spin_lock_irqsave(&par->DAClock, flags);
+ fg_color = (((u32)cmap.red[fg_idx] & 0xff00) << 8) |
+ (((u32)cmap.green[fg_idx] & 0xff00) << 0) |
+ (((u32)cmap.blue[fg_idx] & 0xff00) >> 8);
+ bg_color = (((u32)cmap.red[bg_idx] & 0xff00) << 8) |
+ (((u32)cmap.green[bg_idx] & 0xff00) << 0) |
+ (((u32)cmap.blue[bg_idx] & 0xff00) >> 8);
banshee_make_room(par, 2);
tdfx_outl(par, HWCURC0, bg_color);
tdfx_outl(par, HWCURC1, fg_color);
- spin_unlock_irqrestore(&par->DAClock, flags);
}
- if (cursor->set && FB_CUR_SETPOS) {
- int x, y;
+ if (cursor->set & FB_CUR_SETPOS) {
+ int x = cursor->image.dx;
+ int y = cursor->image.dy - info->var.yoffset;
- x = cursor->image.dx;
- y = cursor->image.dy;
- y -= info->var.yoffset;
- info->cursor.image.dx = x;
- info->cursor.image.dy = y;
x += 63;
y += 63;
- spin_lock_irqsave(&par->DAClock, flags);
banshee_make_room(par, 1);
tdfx_outl(par, HWCURLOC, (y << 16) + x);
- spin_unlock_irqrestore(&par->DAClock, flags);
}
-
- /* Not supported so we fake it */
- if (cursor->set && FB_CUR_SETHOT) {
- info->cursor.hot.x = cursor->hot.x;
- info->cursor.hot.y = cursor->hot.y;
- }
-
- if (cursor->set && FB_CUR_SETSHAPE) {
+ if (cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {
/*
- * Voodoo 3 and above cards use 2 monochrome cursor patterns.
+ * Voodoo 3 and above cards use 2 monochrome cursor patterns.
* The reason is so the card can fetch 8 words at a time
* and are stored on chip for use for the next 8 scanlines.
* This reduces the number of times for access to draw the
* cursor for each screen refresh.
* Each pattern is a bitmap of 64 bit wide and 64 bit high
- * (total of 8192 bits or 1024 Kbytes). The two patterns are
+ * (total of 8192 bits or 1024 bytes). The two patterns are
* stored in such a way that pattern 0 always resides in the
* lower half (least significant 64 bits) of a 128 bit word
* and pattern 1 the upper half. If you examine the data of
@@ -1106,50 +1123,54 @@ static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
* (128 bits) which is the maximum cursor width times two for
* the two monochrome patterns.
*/
- u8 *cursorbase = (u8 *) info->cursor.image.data;
- char *bitmap = (char *)cursor->image.data;
- char *mask = (char *) cursor->mask;
- int i, j, k, h = 0;
-
- for (i = 0; i < 64; i++) {
- if (i < cursor->image.height) {
- j = (cursor->image.width + 7) >> 3;
- k = 8 - j;
-
- for (;j > 0; j--) {
- /* Pattern 0. Copy the cursor bitmap to it */
- fb_writeb(*bitmap, cursorbase + h);
- bitmap++;
- /* Pattern 1. Copy the cursor mask to it */
- fb_writeb(*mask, cursorbase + h + 8);
- mask++;
- h++;
- }
- for (;k > 0; k--) {
- fb_writeb(0, cursorbase + h);
- fb_writeb(~0, cursorbase + h + 8);
- h++;
- }
- } else {
- fb_writel(0, cursorbase + h);
- fb_writel(0, cursorbase + h + 4);
- fb_writel(~0, cursorbase + h + 8);
- fb_writel(~0, cursorbase + h + 12);
- h += 16;
+ u8 __iomem *cursorbase = info->screen_base + info->fix.smem_len;
+ u8 *bitmap = (u8 *)cursor->image.data;
+ u8 *mask = (u8 *)cursor->mask;
+ int i;
+
+ fb_memset(cursorbase, 0, 1024);
+
+ for (i = 0; i < cursor->image.height; i++) {
+ int h = 0;
+ int j = (cursor->image.width + 7) >> 3;
+
+ for (; j > 0; j--) {
+ u8 data = *mask ^ *bitmap;
+ if (cursor->rop == ROP_COPY)
+ data = *mask & *bitmap;
+ /* Pattern 0. Copy the cursor mask to it */
+ fb_writeb(*mask, cursorbase + h);
+ mask++;
+ /* Pattern 1. Copy the cursor bitmap to it */
+ fb_writeb(data, cursorbase + h + 8);
+ bitmap++;
+ h++;
}
+ cursorbase += 16;
}
}
- /* Turn the cursor on */
- cursor->enable = 1;
- info->cursor = *cursor;
- mod_timer(&par->hwcursor.timer, jiffies+HZ/2);
- spin_lock_irqsave(&par->DAClock, flags);
- banshee_make_room(par, 1);
- tdfx_outl(par, VIDPROCCFG, par->hwcursor.enable);
- spin_unlock_irqrestore(&par->DAClock, flags);
return 0;
}
+
+static struct fb_ops tdfxfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = tdfxfb_check_var,
+ .fb_set_par = tdfxfb_set_par,
+ .fb_setcolreg = tdfxfb_setcolreg,
+ .fb_blank = tdfxfb_blank,
+ .fb_pan_display = tdfxfb_pan_display,
+ .fb_sync = banshee_wait_idle,
+ .fb_cursor = tdfxfb_cursor,
+#ifdef CONFIG_FB_3DFX_ACCEL
+ .fb_fillrect = tdfxfb_fillrect,
+ .fb_copyarea = tdfxfb_copyarea,
+ .fb_imageblit = tdfxfb_imageblit,
+#else
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
#endif
+};
/**
* tdfxfb_probe - Device Initializiation
@@ -1161,14 +1182,15 @@ static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
*
*/
static int __devinit tdfxfb_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
+ const struct pci_device_id *id)
{
struct tdfx_par *default_par;
struct fb_info *info;
int err, lpitch;
- if ((err = pci_enable_device(pdev))) {
- printk(KERN_WARNING "tdfxfb: Can't enable pdev: %d\n", err);
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR "tdfxfb: Can't enable pdev: %d\n", err);
return err;
}
@@ -1176,139 +1198,145 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
if (!info)
return -ENOMEM;
-
+
default_par = info->par;
-
+
/* Configure the default fb_fix_screeninfo first */
switch (pdev->device) {
- case PCI_DEVICE_ID_3DFX_BANSHEE:
- strcat(tdfx_fix.id, " Banshee");
- default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK;
- break;
- case PCI_DEVICE_ID_3DFX_VOODOO3:
- strcat(tdfx_fix.id, " Voodoo3");
- default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK;
- break;
- case PCI_DEVICE_ID_3DFX_VOODOO5:
- strcat(tdfx_fix.id, " Voodoo5");
- default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK;
- break;
+ case PCI_DEVICE_ID_3DFX_BANSHEE:
+ strcat(tdfx_fix.id, " Banshee");
+ default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK;
+ break;
+ case PCI_DEVICE_ID_3DFX_VOODOO3:
+ strcat(tdfx_fix.id, " Voodoo3");
+ default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK;
+ break;
+ case PCI_DEVICE_ID_3DFX_VOODOO5:
+ strcat(tdfx_fix.id, " Voodoo5");
+ default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK;
+ break;
}
tdfx_fix.mmio_start = pci_resource_start(pdev, 0);
tdfx_fix.mmio_len = pci_resource_len(pdev, 0);
- default_par->regbase_virt = ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len);
- if (!default_par->regbase_virt) {
- printk("fb: Can't remap %s register area.\n", tdfx_fix.id);
+ if (!request_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len,
+ "tdfx regbase")) {
+ printk(KERN_ERR "tdfxfb: Can't reserve regbase\n");
goto out_err;
}
-
- if (!request_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0), "tdfx regbase")) {
- printk(KERN_WARNING "tdfxfb: Can't reserve regbase\n");
- goto out_err;
- }
+
+ default_par->regbase_virt =
+ ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len);
+ if (!default_par->regbase_virt) {
+ printk(KERN_ERR "fb: Can't remap %s register area.\n",
+ tdfx_fix.id);
+ goto out_err_regbase;
+ }
tdfx_fix.smem_start = pci_resource_start(pdev, 1);
- if (!(tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device))) {
- printk("fb: Can't count %s memory.\n", tdfx_fix.id);
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- goto out_err;
+ tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device);
+ if (!tdfx_fix.smem_len) {
+ printk(KERN_ERR "fb: Can't count %s memory.\n", tdfx_fix.id);
+ goto out_err_regbase;
}
- if (!request_mem_region(pci_resource_start(pdev, 1),
- pci_resource_len(pdev, 1), "tdfx smem")) {
- printk(KERN_WARNING "tdfxfb: Can't reserve smem\n");
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- goto out_err;
+ if (!request_mem_region(tdfx_fix.smem_start,
+ pci_resource_len(pdev, 1), "tdfx smem")) {
+ printk(KERN_ERR "tdfxfb: Can't reserve smem\n");
+ goto out_err_regbase;
}
- info->screen_base = ioremap_nocache(tdfx_fix.smem_start,
+ info->screen_base = ioremap_nocache(tdfx_fix.smem_start,
tdfx_fix.smem_len);
if (!info->screen_base) {
- printk("fb: Can't remap %s framebuffer.\n", tdfx_fix.id);
- release_mem_region(pci_resource_start(pdev, 1),
- pci_resource_len(pdev, 1));
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- goto out_err;
+ printk(KERN_ERR "fb: Can't remap %s framebuffer.\n",
+ tdfx_fix.id);
+ goto out_err_screenbase;
}
default_par->iobase = pci_resource_start(pdev, 2);
-
+
if (!request_region(pci_resource_start(pdev, 2),
- pci_resource_len(pdev, 2), "tdfx iobase")) {
- printk(KERN_WARNING "tdfxfb: Can't reserve iobase\n");
- release_mem_region(pci_resource_start(pdev, 1),
- pci_resource_len(pdev, 1));
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- goto out_err;
+ pci_resource_len(pdev, 2), "tdfx iobase")) {
+ printk(KERN_ERR "tdfxfb: Can't reserve iobase\n");
+ goto out_err_screenbase;
}
- printk("fb: %s memory = %dK\n", tdfx_fix.id, tdfx_fix.smem_len >> 10);
+ printk(KERN_INFO "fb: %s memory = %dK\n", tdfx_fix.id,
+ tdfx_fix.smem_len >> 10);
+
+ default_par->mtrr_handle = -1;
+ if (!nomtrr)
+ default_par->mtrr_handle =
+ mtrr_add(tdfx_fix.smem_start, tdfx_fix.smem_len,
+ MTRR_TYPE_WRCOMB, 1);
tdfx_fix.ypanstep = nopan ? 0 : 1;
tdfx_fix.ywrapstep = nowrap ? 0 : 1;
-
+
info->fbops = &tdfxfb_ops;
- info->fix = tdfx_fix;
+ info->fix = tdfx_fix;
info->pseudo_palette = default_par->palette;
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
#ifdef CONFIG_FB_3DFX_ACCEL
- info->flags |= FBINFO_HWACCEL_FILLRECT |
- FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_IMAGEBLIT;
+ info->flags |= FBINFO_HWACCEL_FILLRECT |
+ FBINFO_HWACCEL_COPYAREA |
+ FBINFO_HWACCEL_IMAGEBLIT |
+ FBINFO_READS_FAST;
#endif
+ /* reserve 8192 bits for cursor */
+ /* the 2.4 driver says PAGE_MASK boundary is not enough for Voodoo4 */
+ if (hwcursor)
+ info->fix.smem_len = (info->fix.smem_len - 1024) &
+ (PAGE_MASK << 1);
if (!mode_option)
mode_option = "640x480@60";
-
- err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
+
+ err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
if (!err || err == 4)
info->var = tdfx_var;
/* maximize virtual vertical length */
lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3);
- info->var.yres_virtual = info->fix.smem_len/lpitch;
+ info->var.yres_virtual = info->fix.smem_len / lpitch;
if (info->var.yres_virtual < info->var.yres)
- goto out_err;
-
-#ifdef CONFIG_FB_3DFX_ACCEL
- /*
- * FIXME: Limit var->yres_virtual to 4096 because of screen artifacts
- * during scrolling. This is only present if 2D acceleration is
- * enabled.
- */
- if (info->var.yres_virtual > 4096)
- info->var.yres_virtual = 4096;
-#endif /* CONFIG_FB_3DFX_ACCEL */
+ goto out_err_iobase;
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
- printk(KERN_WARNING "tdfxfb: Can't allocate color map\n");
- goto out_err;
+ printk(KERN_ERR "tdfxfb: Can't allocate color map\n");
+ goto out_err_iobase;
}
if (register_framebuffer(info) < 0) {
- printk("tdfxfb: can't register framebuffer\n");
+ printk(KERN_ERR "tdfxfb: can't register framebuffer\n");
fb_dealloc_cmap(&info->cmap);
- goto out_err;
+ goto out_err_iobase;
}
/*
* Our driver data
*/
pci_set_drvdata(pdev, info);
- return 0;
+ return 0;
-out_err:
+out_err_iobase:
+ if (default_par->mtrr_handle >= 0)
+ mtrr_del(default_par->mtrr_handle, info->fix.smem_start,
+ info->fix.smem_len);
+ release_mem_region(pci_resource_start(pdev, 2),
+ pci_resource_len(pdev, 2));
+out_err_screenbase:
+ if (info->screen_base)
+ iounmap(info->screen_base);
+ release_mem_region(tdfx_fix.smem_start, pci_resource_len(pdev, 1));
+out_err_regbase:
/*
* Cleanup after anything that was remapped/allocated.
*/
if (default_par->regbase_virt)
iounmap(default_par->regbase_virt);
- if (info->screen_base)
- iounmap(info->screen_base);
+ release_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len);
+out_err:
framebuffer_release(info);
return -ENXIO;
}
@@ -1316,7 +1344,7 @@ out_err:
#ifndef MODULE
static void tdfxfb_setup(char *options)
{
- char* this_opt;
+ char *this_opt;
if (!options || !*options)
return;
@@ -1324,10 +1352,16 @@ static void tdfxfb_setup(char *options)
while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt)
continue;
- if(!strcmp(this_opt, "nopan")) {
+ if (!strcmp(this_opt, "nopan")) {
nopan = 1;
- } else if(!strcmp(this_opt, "nowrap")) {
+ } else if (!strcmp(this_opt, "nowrap")) {
nowrap = 1;
+ } else if (!strncmp(this_opt, "hwcursor=", 9)) {
+ hwcursor = simple_strtoul(this_opt + 9, NULL, 0);
+#ifdef CONFIG_MTRR
+ } else if (!strncmp(this_opt, "nomtrr", 6)) {
+ nomtrr = 1;
+#endif
} else {
mode_option = this_opt;
}
@@ -1350,6 +1384,9 @@ static void __devexit tdfxfb_remove(struct pci_dev *pdev)
struct tdfx_par *par = info->par;
unregister_framebuffer(info);
+ if (par->mtrr_handle >= 0)
+ mtrr_del(par->mtrr_handle, info->fix.smem_start,
+ info->fix.smem_len);
iounmap(par->regbase_virt);
iounmap(info->screen_base);
@@ -1374,17 +1411,25 @@ static int __init tdfxfb_init(void)
tdfxfb_setup(option);
#endif
- return pci_register_driver(&tdfxfb_driver);
+ return pci_register_driver(&tdfxfb_driver);
}
static void __exit tdfxfb_exit(void)
{
- pci_unregister_driver(&tdfxfb_driver);
+ pci_unregister_driver(&tdfxfb_driver);
}
MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>");
MODULE_DESCRIPTION("3Dfx framebuffer device driver");
MODULE_LICENSE("GPL");
-
+
+module_param(hwcursor, int, 0644);
+MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
+ "(1=enable, 0=disable, default=1)");
+#ifdef CONFIG_MTRR
+module_param(nomtrr, bool, 0);
+MODULE_PARM_DESC(nomtrr, "Disable MTRR support (default: enabled)");
+#endif
+
module_init(tdfxfb_init);
module_exit(tdfxfb_exit);
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index d292a37ec7d..680642c089c 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -5,7 +5,7 @@
* Copyright (C) 1997 Geert Uytterhoeven
* Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha
* Copyright (C) 2002 Richard Henderson
- * Copyright (C) 2006 Maciej W. Rozycki
+ * Copyright (C) 2006, 2007 Maciej W. Rozycki
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
@@ -13,6 +13,7 @@
*/
#include <linux/bitrev.h>
+#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/errno.h>
@@ -636,15 +637,6 @@ tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image)
is8bpp = info->var.bits_per_pixel == 8;
- /* For copies that aren't pixel expansion, there's little we
- can do better than the generic code. */
- /* ??? There is a DMA write mode; I wonder if that could be
- made to pull the data from the image buffer... */
- if (image->depth > 1) {
- cfb_imageblit(info, image);
- return;
- }
-
dx = image->dx;
dy = image->dy;
width = image->width;
@@ -654,6 +646,9 @@ tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image)
line_length = info->fix.line_length;
rincr = (width + 7) / 8;
+ /* A shift below cannot cope with. */
+ if (unlikely(width == 0))
+ return;
/* Crop the image to the screen. */
if (dx > vxres || dy > vyres)
return;
@@ -709,9 +704,10 @@ tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image)
unsigned long bwidth;
/* Handle common case of imaging a single character, in
- a font less than 32 pixels wide. */
+ a font less than or 32 pixels wide. */
- pixelmask = (1 << width) - 1;
+ /* Avoid a shift by 32; width > 0 implied. */
+ pixelmask = (2ul << (width - 1)) - 1;
pixelmask <<= shift;
__raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG);
wmb();
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
index c699864b6f4..70fb4ee2b42 100644
--- a/drivers/video/tridentfb.c
+++ b/drivers/video/tridentfb.c
@@ -1,18 +1,19 @@
/*
* Frame buffer driver for Trident Blade and Image series
*
- * Copyright 2001,2002 - Jani Monoses <jani@iv.ro>
+ * Copyright 2001, 2002 - Jani Monoses <jani@iv.ro>
*
*
* CREDITS:(in order of appearance)
- * skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video
- * Special thanks ;) to Mattia Crivellini <tia@mclink.it>
- * much inspired by the XFree86 4.x Trident driver sources by Alan Hourihane
- * the FreeVGA project
- * Francesco Salvestrini <salvestrini@users.sf.net> XP support,code,suggestions
+ * skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video
+ * Special thanks ;) to Mattia Crivellini <tia@mclink.it>
+ * much inspired by the XFree86 4.x Trident driver sources
+ * by Alan Hourihane the FreeVGA project
+ * Francesco Salvestrini <salvestrini@users.sf.net> XP support,
+ * code, suggestions
* TODO:
- * timing value tweaking so it looks good on every monitor in every mode
- * TGUI acceleration
+ * timing value tweaking so it looks good on every monitor in every mode
+ * TGUI acceleration
*/
#include <linux/module.h>
@@ -26,11 +27,11 @@
#define VERSION "0.7.8-NEWAPI"
struct tridentfb_par {
- int vclk; //in MHz
- void __iomem * io_virt; //iospace virtual memory address
+ int vclk; /* in MHz */
+ void __iomem *io_virt; /* iospace virtual memory address */
};
-static unsigned char eng_oper; //engine operation...
+static unsigned char eng_oper; /* engine operation... */
static struct fb_ops tridentfb_ops;
static struct tridentfb_par default_par;
@@ -39,11 +40,10 @@ static struct tridentfb_par default_par;
static struct fb_info fb_info;
static u32 pseudo_pal[16];
-
static struct fb_var_screeninfo default_var;
static struct fb_fix_screeninfo tridentfb_fix = {
- .id = "Trident",
+ .id = "Trident",
.type = FB_TYPE_PACKED_PIXELS,
.ypanstep = 1,
.visual = FB_VISUAL_PSEUDOCOLOR,
@@ -55,11 +55,10 @@ static int chip_id;
static int defaultaccel;
static int displaytype;
-
/* defaults which are normally overriden by user values */
/* video mode */
-static char * mode = "640x480";
+static char *mode = "640x480";
static int bpp = 8;
static int noaccel;
@@ -74,7 +73,6 @@ static int memsize;
static int memdiff;
static int nativex;
-
module_param(mode, charp, 0);
module_param(bpp, int, 0);
module_param(center, int, 0);
@@ -86,88 +84,85 @@ module_param(nativex, int, 0);
module_param(fp, int, 0);
module_param(crt, int, 0);
-
static int chip3D;
static int chipcyber;
static int is3Dchip(int id)
{
- return ((id == BLADE3D) || (id == CYBERBLADEE4) ||
- (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) ||
- (id == CYBER9397) || (id == CYBER9397DVD) ||
- (id == CYBER9520) || (id == CYBER9525DVD) ||
- (id == IMAGE975) || (id == IMAGE985) ||
- (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) ||
- (id == CYBERBLADEAi1) || (id == CYBERBLADEAi1D) ||
- (id == CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) ||
- (id == CYBERBLADEXPAi1));
+ return ((id == BLADE3D) || (id == CYBERBLADEE4) ||
+ (id == CYBERBLADEi7) || (id == CYBERBLADEi7D) ||
+ (id == CYBER9397) || (id == CYBER9397DVD) ||
+ (id == CYBER9520) || (id == CYBER9525DVD) ||
+ (id == IMAGE975) || (id == IMAGE985) ||
+ (id == CYBERBLADEi1) || (id == CYBERBLADEi1D) ||
+ (id == CYBERBLADEAi1) || (id == CYBERBLADEAi1D) ||
+ (id == CYBERBLADEXPm8) || (id == CYBERBLADEXPm16) ||
+ (id == CYBERBLADEXPAi1));
}
static int iscyber(int id)
{
switch (id) {
- case CYBER9388:
- case CYBER9382:
- case CYBER9385:
- case CYBER9397:
- case CYBER9397DVD:
- case CYBER9520:
- case CYBER9525DVD:
- case CYBERBLADEE4:
- case CYBERBLADEi7D:
- case CYBERBLADEi1:
- case CYBERBLADEi1D:
- case CYBERBLADEAi1:
- case CYBERBLADEAi1D:
- case CYBERBLADEXPAi1:
- return 1;
-
- case CYBER9320:
- case TGUI9660:
- case IMAGE975:
- case IMAGE985:
- case BLADE3D:
- case CYBERBLADEi7: /* VIA MPV4 integrated version */
+ case CYBER9388:
+ case CYBER9382:
+ case CYBER9385:
+ case CYBER9397:
+ case CYBER9397DVD:
+ case CYBER9520:
+ case CYBER9525DVD:
+ case CYBERBLADEE4:
+ case CYBERBLADEi7D:
+ case CYBERBLADEi1:
+ case CYBERBLADEi1D:
+ case CYBERBLADEAi1:
+ case CYBERBLADEAi1D:
+ case CYBERBLADEXPAi1:
+ return 1;
- default:
- /* case CYBERBLDAEXPm8: Strange */
- /* case CYBERBLDAEXPm16: Strange */
- return 0;
+ case CYBER9320:
+ case TGUI9660:
+ case IMAGE975:
+ case IMAGE985:
+ case BLADE3D:
+ case CYBERBLADEi7: /* VIA MPV4 integrated version */
+
+ default:
+ /* case CYBERBLDAEXPm8: Strange */
+ /* case CYBERBLDAEXPm16: Strange */
+ return 0;
}
}
-#define CRT 0x3D0 //CRTC registers offset for color display
+#define CRT 0x3D0 /* CRTC registers offset for color display */
#ifndef TRIDENT_MMIO
#define TRIDENT_MMIO 1
#endif
#if TRIDENT_MMIO
- #define t_outb(val,reg) writeb(val,((struct tridentfb_par *)(fb_info.par))->io_virt + reg)
+ #define t_outb(val, reg) writeb(val,((struct tridentfb_par *)(fb_info.par))->io_virt + reg)
#define t_inb(reg) readb(((struct tridentfb_par*)(fb_info.par))->io_virt + reg)
#else
- #define t_outb(val,reg) outb(val,reg)
+ #define t_outb(val, reg) outb(val, reg)
#define t_inb(reg) inb(reg)
#endif
static struct accel_switch {
- void (*init_accel)(int,int);
- void (*wait_engine)(void);
- void (*fill_rect)(__u32,__u32,__u32,__u32,__u32,__u32);
- void (*copy_rect)(__u32,__u32,__u32,__u32,__u32,__u32);
+ void (*init_accel) (int, int);
+ void (*wait_engine) (void);
+ void (*fill_rect) (u32, u32, u32, u32, u32, u32);
+ void (*copy_rect) (u32, u32, u32, u32, u32, u32);
} *acc;
-#define writemmr(r,v) writel(v, ((struct tridentfb_par *)fb_info.par)->io_virt + r)
+#define writemmr(r, v) writel(v, ((struct tridentfb_par *)fb_info.par)->io_virt + r)
#define readmmr(r) readl(((struct tridentfb_par *)fb_info.par)->io_virt + r)
-
-
/*
* Blade specific acceleration.
*/
-#define point(x,y) ((y)<<16|(x))
+#define point(x, y) ((y) << 16 | (x))
#define STA 0x2120
#define CMD 0x2144
#define ROP 0x2148
@@ -179,64 +174,71 @@ static struct accel_switch {
#define ROP_S 0xCC
-static void blade_init_accel(int pitch,int bpp)
+static void blade_init_accel(int pitch, int bpp)
{
- int v1 = (pitch>>3)<<20;
- int tmp = 0,v2;
+ int v1 = (pitch >> 3) << 20;
+ int tmp = 0, v2;
switch (bpp) {
- case 8:tmp = 0;break;
- case 15:tmp = 5;break;
- case 16:tmp = 1;break;
- case 24:
- case 32:tmp = 2;break;
+ case 8:
+ tmp = 0;
+ break;
+ case 15:
+ tmp = 5;
+ break;
+ case 16:
+ tmp = 1;
+ break;
+ case 24:
+ case 32:
+ tmp = 2;
+ break;
}
- v2 = v1 | (tmp<<29);
- writemmr(0x21C0,v2);
- writemmr(0x21C4,v2);
- writemmr(0x21B8,v2);
- writemmr(0x21BC,v2);
- writemmr(0x21D0,v1);
- writemmr(0x21D4,v1);
- writemmr(0x21C8,v1);
- writemmr(0x21CC,v1);
- writemmr(0x216C,0);
+ v2 = v1 | (tmp << 29);
+ writemmr(0x21C0, v2);
+ writemmr(0x21C4, v2);
+ writemmr(0x21B8, v2);
+ writemmr(0x21BC, v2);
+ writemmr(0x21D0, v1);
+ writemmr(0x21D4, v1);
+ writemmr(0x21C8, v1);
+ writemmr(0x21CC, v1);
+ writemmr(0x216C, 0);
}
static void blade_wait_engine(void)
{
- while(readmmr(STA) & 0xFA800000);
+ while (readmmr(STA) & 0xFA800000) ;
}
-static void blade_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop)
+static void blade_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
{
- writemmr(CLR,c);
- writemmr(ROP,rop ? 0x66:ROP_S);
- writemmr(CMD,0x20000000|1<<19|1<<4|2<<2);
+ writemmr(CLR, c);
+ writemmr(ROP, rop ? 0x66 : ROP_S);
+ writemmr(CMD, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
- writemmr(DR1,point(x,y));
- writemmr(DR2,point(x+w-1,y+h-1));
+ writemmr(DR1, point(x, y));
+ writemmr(DR2, point(x + w - 1, y + h - 1));
}
-static void blade_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h)
+static void blade_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
{
- __u32 s1,s2,d1,d2;
+ u32 s1, s2, d1, d2;
int direction = 2;
- s1 = point(x1,y1);
- s2 = point(x1+w-1,y1+h-1);
- d1 = point(x2,y2);
- d2 = point(x2+w-1,y2+h-1);
+ s1 = point(x1, y1);
+ s2 = point(x1 + w - 1, y1 + h - 1);
+ d1 = point(x2, y2);
+ d2 = point(x2 + w - 1, y2 + h - 1);
if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
- direction = 0;
-
+ direction = 0;
- writemmr(ROP,ROP_S);
- writemmr(CMD,0xE0000000|1<<19|1<<4|1<<2|direction);
+ writemmr(ROP, ROP_S);
+ writemmr(CMD, 0xE0000000 | 1 << 19 | 1 << 4 | 1 << 2 | direction);
- writemmr(SR1,direction?s2:s1);
- writemmr(SR2,direction?s1:s2);
- writemmr(DR1,direction?d2:d1);
- writemmr(DR2,direction?d1:d2);
+ writemmr(SR1, direction ? s2 : s1);
+ writemmr(SR2, direction ? s1 : s2);
+ writemmr(DR1, direction ? d2 : d1);
+ writemmr(DR2, direction ? d1 : d2);
}
static struct accel_switch accel_blade = {
@@ -246,51 +248,72 @@ static struct accel_switch accel_blade = {
blade_copy_rect,
};
-
/*
* BladeXP specific acceleration functions
*/
#define ROP_P 0xF0
-#define masked_point(x,y) ((y & 0xffff)<<16|(x & 0xffff))
+#define masked_point(x, y) ((y & 0xffff)<<16|(x & 0xffff))
-static void xp_init_accel(int pitch,int bpp)
+static void xp_init_accel(int pitch, int bpp)
{
- int tmp = 0,v1;
+ int tmp = 0, v1;
unsigned char x = 0;
switch (bpp) {
- case 8: x = 0; break;
- case 16: x = 1; break;
- case 24: x = 3; break;
- case 32: x = 2; break;
+ case 8:
+ x = 0;
+ break;
+ case 16:
+ x = 1;
+ break;
+ case 24:
+ x = 3;
+ break;
+ case 32:
+ x = 2;
+ break;
}
switch (pitch << (bpp >> 3)) {
- case 8192:
- case 512: x |= 0x00; break;
- case 1024: x |= 0x04; break;
- case 2048: x |= 0x08; break;
- case 4096: x |= 0x0C; break;
+ case 8192:
+ case 512:
+ x |= 0x00;
+ break;
+ case 1024:
+ x |= 0x04;
+ break;
+ case 2048:
+ x |= 0x08;
+ break;
+ case 4096:
+ x |= 0x0C;
+ break;
}
- t_outb(x,0x2125);
+ t_outb(x, 0x2125);
eng_oper = x | 0x40;
switch (bpp) {
- case 8: tmp = 18; break;
- case 15:
- case 16: tmp = 19; break;
- case 24:
- case 32: tmp = 20; break;
+ case 8:
+ tmp = 18;
+ break;
+ case 15:
+ case 16:
+ tmp = 19;
+ break;
+ case 24:
+ case 32:
+ tmp = 20;
+ break;
}
v1 = pitch << tmp;
- writemmr(0x2154,v1);
- writemmr(0x2150,v1);
- t_outb(3,0x2126);
+ writemmr(0x2154, v1);
+ writemmr(0x2150, v1);
+ t_outb(3, 0x2126);
}
static void xp_wait_engine(void)
@@ -318,24 +341,24 @@ static void xp_wait_engine(void)
}
}
-static void xp_fill_rect(__u32 x,__u32 y,__u32 w,__u32 h,__u32 c,__u32 rop)
+static void xp_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
{
- writemmr(0x2127,ROP_P);
- writemmr(0x2158,c);
- writemmr(0x2128,0x4000);
- writemmr(0x2140,masked_point(h,w));
- writemmr(0x2138,masked_point(y,x));
- t_outb(0x01,0x2124);
- t_outb(eng_oper,0x2125);
+ writemmr(0x2127, ROP_P);
+ writemmr(0x2158, c);
+ writemmr(0x2128, 0x4000);
+ writemmr(0x2140, masked_point(h, w));
+ writemmr(0x2138, masked_point(y, x));
+ t_outb(0x01, 0x2124);
+ t_outb(eng_oper, 0x2125);
}
-static void xp_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h)
+static void xp_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
{
int direction;
- __u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
+ u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
direction = 0x0004;
-
+
if ((x1 < x2) && (y1 == y2)) {
direction |= 0x0200;
x1_tmp = x1 + w - 1;
@@ -344,53 +367,60 @@ static void xp_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h)
x1_tmp = x1;
x2_tmp = x2;
}
-
+
if (y1 < y2) {
direction |= 0x0100;
y1_tmp = y1 + h - 1;
y2_tmp = y2 + h - 1;
- } else {
+ } else {
y1_tmp = y1;
y2_tmp = y2;
}
- writemmr(0x2128,direction);
- t_outb(ROP_S,0x2127);
- writemmr(0x213C,masked_point(y1_tmp,x1_tmp));
- writemmr(0x2138,masked_point(y2_tmp,x2_tmp));
- writemmr(0x2140,masked_point(h,w));
- t_outb(0x01,0x2124);
+ writemmr(0x2128, direction);
+ t_outb(ROP_S, 0x2127);
+ writemmr(0x213C, masked_point(y1_tmp, x1_tmp));
+ writemmr(0x2138, masked_point(y2_tmp, x2_tmp));
+ writemmr(0x2140, masked_point(h, w));
+ t_outb(0x01, 0x2124);
}
static struct accel_switch accel_xp = {
- xp_init_accel,
+ xp_init_accel,
xp_wait_engine,
xp_fill_rect,
xp_copy_rect,
};
-
/*
* Image specific acceleration functions
*/
-static void image_init_accel(int pitch,int bpp)
+static void image_init_accel(int pitch, int bpp)
{
int tmp = 0;
- switch (bpp) {
- case 8:tmp = 0;break;
- case 15:tmp = 5;break;
- case 16:tmp = 1;break;
- case 24:
- case 32:tmp = 2;break;
+ switch (bpp) {
+ case 8:
+ tmp = 0;
+ break;
+ case 15:
+ tmp = 5;
+ break;
+ case 16:
+ tmp = 1;
+ break;
+ case 24:
+ case 32:
+ tmp = 2;
+ break;
}
writemmr(0x2120, 0xF0000000);
- writemmr(0x2120, 0x40000000|tmp);
+ writemmr(0x2120, 0x40000000 | tmp);
writemmr(0x2120, 0x80000000);
writemmr(0x2144, 0x00000000);
writemmr(0x2148, 0x00000000);
writemmr(0x2150, 0x00000000);
writemmr(0x2154, 0x00000000);
- writemmr(0x2120, 0x60000000|(pitch<<16) |pitch);
+ writemmr(0x2120, 0x60000000 | (pitch << 16) | pitch);
writemmr(0x216C, 0x00000000);
writemmr(0x2170, 0x00000000);
writemmr(0x217C, 0x00000000);
@@ -400,44 +430,43 @@ static void image_init_accel(int pitch,int bpp)
static void image_wait_engine(void)
{
- while(readmmr(0x2164) & 0xF0000000);
+ while (readmmr(0x2164) & 0xF0000000) ;
}
-static void image_fill_rect(__u32 x, __u32 y, __u32 w, __u32 h, __u32 c, __u32 rop)
+static void image_fill_rect(u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
{
- writemmr(0x2120,0x80000000);
- writemmr(0x2120,0x90000000|ROP_S);
+ writemmr(0x2120, 0x80000000);
+ writemmr(0x2120, 0x90000000 | ROP_S);
- writemmr(0x2144,c);
+ writemmr(0x2144, c);
- writemmr(DR1,point(x,y));
- writemmr(DR2,point(x+w-1,y+h-1));
+ writemmr(DR1, point(x, y));
+ writemmr(DR2, point(x + w - 1, y + h - 1));
- writemmr(0x2124,0x80000000|3<<22|1<<10|1<<9);
+ writemmr(0x2124, 0x80000000 | 3 << 22 | 1 << 10 | 1 << 9);
}
-static void image_copy_rect(__u32 x1,__u32 y1,__u32 x2,__u32 y2,__u32 w,__u32 h)
+static void image_copy_rect(u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
{
- __u32 s1,s2,d1,d2;
+ u32 s1, s2, d1, d2;
int direction = 2;
- s1 = point(x1,y1);
- s2 = point(x1+w-1,y1+h-1);
- d1 = point(x2,y2);
- d2 = point(x2+w-1,y2+h-1);
-
- if ((y1 > y2) || ((y1 == y2) && (x1 >x2)))
- direction = 0;
-
- writemmr(0x2120,0x80000000);
- writemmr(0x2120,0x90000000|ROP_S);
-
- writemmr(SR1,direction?s2:s1);
- writemmr(SR2,direction?s1:s2);
- writemmr(DR1,direction?d2:d1);
- writemmr(DR2,direction?d1:d2);
- writemmr(0x2124,0x80000000|1<<22|1<<10|1<<7|direction);
-}
+ s1 = point(x1, y1);
+ s2 = point(x1 + w - 1, y1 + h - 1);
+ d1 = point(x2, y2);
+ d2 = point(x2 + w - 1, y2 + h - 1);
+ if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
+ direction = 0;
+
+ writemmr(0x2120, 0x80000000);
+ writemmr(0x2120, 0x90000000 | ROP_S);
+
+ writemmr(SR1, direction ? s2 : s1);
+ writemmr(SR2, direction ? s1 : s2);
+ writemmr(DR1, direction ? d2 : d1);
+ writemmr(DR2, direction ? d1 : d2);
+ writemmr(0x2124, 0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction);
+}
static struct accel_switch accel_image = {
image_init_accel,
@@ -450,30 +479,34 @@ static struct accel_switch accel_image = {
* Accel functions called by the upper layers
*/
#ifdef CONFIG_FB_TRIDENT_ACCEL
-static void tridentfb_fillrect(struct fb_info * info, const struct fb_fillrect *fr)
+static void tridentfb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *fr)
{
int bpp = info->var.bits_per_pixel;
int col = 0;
-
+
switch (bpp) {
- default:
- case 8: col |= fr->color;
- col |= col << 8;
- col |= col << 16;
- break;
- case 16: col = ((u32 *)(info->pseudo_palette))[fr->color];
-
- break;
- case 32: col = ((u32 *)(info->pseudo_palette))[fr->color];
- break;
- }
-
+ default:
+ case 8:
+ col |= fr->color;
+ col |= col << 8;
+ col |= col << 16;
+ break;
+ case 16:
+ col = ((u32 *)(info->pseudo_palette))[fr->color];
+ break;
+ case 32:
+ col = ((u32 *)(info->pseudo_palette))[fr->color];
+ break;
+ }
+
acc->fill_rect(fr->dx, fr->dy, fr->width, fr->height, col, fr->rop);
acc->wait_engine();
}
-static void tridentfb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
+static void tridentfb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *ca)
{
- acc->copy_rect(ca->sx,ca->sy,ca->dx,ca->dy,ca->width,ca->height);
+ acc->copy_rect(ca->sx, ca->sy, ca->dx, ca->dy, ca->width, ca->height);
acc->wait_engine();
}
#else /* !CONFIG_FB_TRIDENT_ACCEL */
@@ -488,14 +521,14 @@ static void tridentfb_copyarea(struct fb_info *info, const struct fb_copyarea *c
static inline unsigned char read3X4(int reg)
{
- struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par;
+ struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par;
writeb(reg, par->io_virt + CRT + 4);
- return readb( par->io_virt + CRT + 5);
+ return readb(par->io_virt + CRT + 5);
}
static inline void write3X4(int reg, unsigned char val)
{
- struct tridentfb_par * par = (struct tridentfb_par *)fb_info.par;
+ struct tridentfb_par *par = (struct tridentfb_par *)fb_info.par;
writeb(reg, par->io_virt + CRT + 4);
writeb(val, par->io_virt + CRT + 5);
}
@@ -520,7 +553,7 @@ static inline unsigned char read3CE(int reg)
static inline void writeAttr(int reg, unsigned char val)
{
- readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); //flip-flop to index
+ readb(((struct tridentfb_par *)fb_info.par)->io_virt + CRT + 0x0A); /* flip-flop to index */
t_outb(reg, 0x3C0);
t_outb(val, 0x3C0);
}
@@ -540,32 +573,41 @@ static inline void enable_mmio(void)
/* Unprotect registers */
outb(NewMode1, 0x3C4);
outb(0x80, 0x3C5);
-
+
/* Enable MMIO */
- outb(PCIReg, 0x3D4);
+ outb(PCIReg, 0x3D4);
outb(inb(0x3D5) | 0x01, 0x3D5);
}
-
#define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
/* Return flat panel's maximum x resolution */
static int __devinit get_nativex(void)
{
- int x,y,tmp;
+ int x, y, tmp;
if (nativex)
return nativex;
- tmp = (read3CE(VertStretch) >> 4) & 3;
+ tmp = (read3CE(VertStretch) >> 4) & 3;
switch (tmp) {
- case 0: x = 1280; y = 1024; break;
- case 2: x = 1024; y = 768; break;
- case 3: x = 800; y = 600; break;
- case 4: x = 1400; y = 1050; break;
- case 1:
- default:x = 640; y = 480; break;
+ case 0:
+ x = 1280; y = 1024;
+ break;
+ case 2:
+ x = 1024; y = 768;
+ break;
+ case 3:
+ x = 800; y = 600;
+ break;
+ case 4:
+ x = 1400; y = 1050;
+ break;
+ case 1:
+ default:
+ x = 640; y = 480;
+ break;
}
output("%dx%d flat panel found\n", x, y);
@@ -576,25 +618,26 @@ static int __devinit get_nativex(void)
static void set_lwidth(int width)
{
write3X4(Offset, width & 0xFF);
- write3X4(AddColReg, (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >>4));
+ write3X4(AddColReg,
+ (read3X4(AddColReg) & 0xCF) | ((width & 0x300) >> 4));
}
/* For resolutions smaller than FP resolution stretch */
static void screen_stretch(void)
{
- if (chip_id != CYBERBLADEXPAi1)
- write3CE(BiosReg,0);
- else
- write3CE(BiosReg,8);
- write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 1);
- write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 1);
+ if (chip_id != CYBERBLADEXPAi1)
+ write3CE(BiosReg, 0);
+ else
+ write3CE(BiosReg, 8);
+ write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 1);
+ write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 1);
}
/* For resolutions smaller than FP resolution center */
static void screen_center(void)
{
- write3CE(VertStretch,(read3CE(VertStretch) & 0x7C) | 0x80);
- write3CE(HorStretch,(read3CE(HorStretch) & 0x7C) | 0x80);
+ write3CE(VertStretch, (read3CE(VertStretch) & 0x7C) | 0x80);
+ write3CE(HorStretch, (read3CE(HorStretch) & 0x7C) | 0x80);
}
/* Address of first shown pixel in display memory */
@@ -602,40 +645,42 @@ static void set_screen_start(int base)
{
write3X4(StartAddrLow, base & 0xFF);
write3X4(StartAddrHigh, (base & 0xFF00) >> 8);
- write3X4(CRTCModuleTest, (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11));
- write3X4(CRTHiOrd, (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
+ write3X4(CRTCModuleTest,
+ (read3X4(CRTCModuleTest) & 0xDF) | ((base & 0x10000) >> 11));
+ write3X4(CRTHiOrd,
+ (read3X4(CRTHiOrd) & 0xF8) | ((base & 0xE0000) >> 17));
}
/* Use 20.12 fixed-point for NTSC value and frequency calculation */
-#define calc_freq(n,m,k) ( ((unsigned long)0xE517 * (n+8) / ((m+2)*(1<<k))) >> 12 )
+#define calc_freq(n, m, k) ( ((unsigned long)0xE517 * (n + 8) / ((m + 2) * (1 << k))) >> 12 )
/* Set dotclock frequency */
static void set_vclk(int freq)
{
- int m,n,k;
- int f,fi,d,di;
- unsigned char lo=0,hi=0;
+ int m, n, k;
+ int f, fi, d, di;
+ unsigned char lo = 0, hi = 0;
d = 20;
- for(k = 2;k>=0;k--)
- for(m = 0;m<63;m++)
- for(n = 0;n<128;n++) {
- fi = calc_freq(n,m,k);
- if ((di = abs(fi - freq)) < d) {
- d = di;
- f = fi;
- lo = n;
- hi = (k<<6) | m;
- }
- }
+ for (k = 2; k >= 0; k--)
+ for (m = 0; m < 63; m++)
+ for (n = 0; n < 128; n++) {
+ fi = calc_freq(n, m, k);
+ if ((di = abs(fi - freq)) < d) {
+ d = di;
+ f = fi;
+ lo = n;
+ hi = (k << 6) | m;
+ }
+ }
if (chip3D) {
- write3C4(ClockHigh,hi);
- write3C4(ClockLow,lo);
+ write3C4(ClockHigh, hi);
+ write3C4(ClockLow, lo);
} else {
- outb(lo,0x43C8);
- outb(hi,0x43C9);
+ outb(lo, 0x43C8);
+ outb(hi, 0x43C9);
}
- debug("VCLK = %X %X\n",hi,lo);
+ debug("VCLK = %X %X\n", hi, lo);
}
/* Set number of lines for flat panels*/
@@ -663,7 +708,7 @@ static unsigned int __devinit get_displaytype(void)
return DISPLAY_FP;
if (crt || !chipcyber)
return DISPLAY_CRT;
- return (read3CE(FPConfig) & 0x10)?DISPLAY_FP:DISPLAY_CRT;
+ return (read3CE(FPConfig) & 0x10) ? DISPLAY_FP : DISPLAY_CRT;
}
/* Try detecting the video memory size */
@@ -676,100 +721,136 @@ static unsigned int __devinit get_memsize(void)
if (memsize)
k = memsize * Kb;
else
- switch (chip_id) {
- case CYBER9525DVD: k = 2560 * Kb; break;
+ switch (chip_id) {
+ case CYBER9525DVD:
+ k = 2560 * Kb;
+ break;
default:
tmp = read3X4(SPR) & 0x0F;
switch (tmp) {
- case 0x01: k = 512; break;
- case 0x02: k = 6 * Mb; break; /* XP */
- case 0x03: k = 1 * Mb; break;
- case 0x04: k = 8 * Mb; break;
- case 0x06: k = 10 * Mb; break; /* XP */
- case 0x07: k = 2 * Mb; break;
- case 0x08: k = 12 * Mb; break; /* XP */
- case 0x0A: k = 14 * Mb; break; /* XP */
- case 0x0C: k = 16 * Mb; break; /* XP */
- case 0x0E: /* XP */
-
- tmp2 = read3C4(0xC1);
- switch (tmp2) {
- case 0x00: k = 20 * Mb; break;
- case 0x01: k = 24 * Mb; break;
- case 0x10: k = 28 * Mb; break;
- case 0x11: k = 32 * Mb; break;
- default: k = 1 * Mb; break;
- }
+ case 0x01:
+ k = 512;
+ break;
+ case 0x02:
+ k = 6 * Mb; /* XP */
+ break;
+ case 0x03:
+ k = 1 * Mb;
+ break;
+ case 0x04:
+ k = 8 * Mb;
+ break;
+ case 0x06:
+ k = 10 * Mb; /* XP */
+ break;
+ case 0x07:
+ k = 2 * Mb;
+ break;
+ case 0x08:
+ k = 12 * Mb; /* XP */
+ break;
+ case 0x0A:
+ k = 14 * Mb; /* XP */
+ break;
+ case 0x0C:
+ k = 16 * Mb; /* XP */
+ break;
+ case 0x0E: /* XP */
+
+ tmp2 = read3C4(0xC1);
+ switch (tmp2) {
+ case 0x00:
+ k = 20 * Mb;
+ break;
+ case 0x01:
+ k = 24 * Mb;
+ break;
+ case 0x10:
+ k = 28 * Mb;
+ break;
+ case 0x11:
+ k = 32 * Mb;
+ break;
+ default:
+ k = 1 * Mb;
+ break;
+ }
+ break;
+
+ case 0x0F:
+ k = 4 * Mb;
+ break;
+ default:
+ k = 1 * Mb;
break;
-
- case 0x0F: k = 4 * Mb; break;
- default: k = 1 * Mb;
}
- }
+ }
k -= memdiff * Kb;
- output("framebuffer size = %d Kb\n", k/Kb);
+ output("framebuffer size = %d Kb\n", k / Kb);
return k;
}
/* See if we can handle the video mode described in var */
-static int tridentfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+static int tridentfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
int bpp = var->bits_per_pixel;
debug("enter\n");
/* check color depth */
- if (bpp == 24 )
+ if (bpp == 24)
bpp = var->bits_per_pixel = 32;
- /* check whether resolution fits on panel and in memory*/
+ /* check whether resolution fits on panel and in memory */
if (flatpanel && nativex && var->xres > nativex)
return -EINVAL;
- if (var->xres * var->yres_virtual * bpp/8 > info->fix.smem_len)
+ if (var->xres * var->yres_virtual * bpp / 8 > info->fix.smem_len)
return -EINVAL;
switch (bpp) {
- case 8:
- var->red.offset = 0;
- var->green.offset = 0;
- var->blue.offset = 0;
- var->red.length = 6;
- var->green.length = 6;
- var->blue.length = 6;
- break;
- case 16:
- var->red.offset = 11;
- var->green.offset = 5;
- var->blue.offset = 0;
- var->red.length = 5;
- var->green.length = 6;
- var->blue.length = 5;
- break;
- case 32:
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- break;
- default:
- return -EINVAL;
+ case 8:
+ var->red.offset = 0;
+ var->green.offset = 0;
+ var->blue.offset = 0;
+ var->red.length = 6;
+ var->green.length = 6;
+ var->blue.length = 6;
+ break;
+ case 16:
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ break;
+ case 32:
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ break;
+ default:
+ return -EINVAL;
}
debug("exit\n");
return 0;
}
+
/* Pan the display */
static int tridentfb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info)
+ struct fb_info *info)
{
unsigned int offset;
debug("enter\n");
offset = (var->xoffset + (var->yoffset * var->xres))
- * var->bits_per_pixel/32;
+ * var->bits_per_pixel / 32;
info->var.xoffset = var->xoffset;
info->var.yoffset = var->yoffset;
set_screen_start(offset);
@@ -777,36 +858,38 @@ static int tridentfb_pan_display(struct fb_var_screeninfo *var,
return 0;
}
-#define shadowmode_on() write3CE(CyberControl,read3CE(CyberControl) | 0x81)
-#define shadowmode_off() write3CE(CyberControl,read3CE(CyberControl) & 0x7E)
+#define shadowmode_on() write3CE(CyberControl, read3CE(CyberControl) | 0x81)
+#define shadowmode_off() write3CE(CyberControl, read3CE(CyberControl) & 0x7E)
/* Set the hardware to the requested video mode */
static int tridentfb_set_par(struct fb_info *info)
{
- struct tridentfb_par * par = (struct tridentfb_par *)(info->par);
- u32 htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,
- vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
- struct fb_var_screeninfo *var = &info->var;
+ struct tridentfb_par *par = (struct tridentfb_par *)(info->par);
+ u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend;
+ u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend;
+ struct fb_var_screeninfo *var = &info->var;
int bpp = var->bits_per_pixel;
unsigned char tmp;
debug("enter\n");
- htotal = (var->xres + var->left_margin + var->right_margin + var->hsync_len)/8 - 10;
- hdispend = var->xres/8 - 1;
- hsyncstart = (var->xres + var->right_margin)/8;
- hsyncend = var->hsync_len/8;
+ hdispend = var->xres / 8 - 1;
+ hsyncstart = (var->xres + var->right_margin) / 8;
+ hsyncend = var->hsync_len / 8;
+ htotal =
+ (var->xres + var->left_margin + var->right_margin +
+ var->hsync_len) / 8 - 10;
hblankstart = hdispend + 1;
hblankend = htotal + 5;
- vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len - 2;
vdispend = var->yres - 1;
vsyncstart = var->yres + var->lower_margin;
vsyncend = var->vsync_len;
+ vtotal = var->upper_margin + vsyncstart + vsyncend - 2;
vblankstart = var->yres;
vblankend = vtotal + 2;
enable_mmio();
crtc_unlock();
- write3CE(CyberControl,8);
+ write3CE(CyberControl, 8);
if (flatpanel && var->xres < nativex) {
/*
@@ -814,18 +897,18 @@ static int tridentfb_set_par(struct fb_info *info)
* than requested resolution decide whether
* we stretch or center
*/
- t_outb(0xEB,0x3C2);
+ t_outb(0xEB, 0x3C2);
shadowmode_on();
- if (center)
+ if (center)
screen_center();
else if (stretch)
screen_stretch();
} else {
- t_outb(0x2B,0x3C2);
- write3CE(CyberControl,8);
+ t_outb(0x2B, 0x3C2);
+ write3CE(CyberControl, 8);
}
/* vertical timing values */
@@ -834,15 +917,15 @@ static int tridentfb_set_par(struct fb_info *info)
write3X4(CRTVSyncStart, vsyncstart & 0xFF);
write3X4(CRTVSyncEnd, (vsyncend & 0x0F));
write3X4(CRTVBlankStart, vblankstart & 0xFF);
- write3X4(CRTVBlankEnd, 0/*p->vblankend & 0xFF*/);
+ write3X4(CRTVBlankEnd, 0 /* p->vblankend & 0xFF */ );
/* horizontal timing values */
write3X4(CRTHTotal, htotal & 0xFF);
write3X4(CRTHDispEnd, hdispend & 0xFF);
write3X4(CRTHSyncStart, hsyncstart & 0xFF);
- write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20)<<2));
+ write3X4(CRTHSyncEnd, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
write3X4(CRTHBlankStart, hblankstart & 0xFF);
- write3X4(CRTHBlankEnd, 0/*(p->hblankend & 0x1F)*/);
+ write3X4(CRTHBlankEnd, 0 /* (p->hblankend & 0x1F) */ );
/* higher bits of vertical timing values */
tmp = 0x10;
@@ -856,7 +939,7 @@ static int tridentfb_set_par(struct fb_info *info)
if (vsyncstart & 0x200) tmp |= 0x80;
write3X4(CRTOverflow, tmp);
- tmp = read3X4(CRTHiOrd) | 0x08; //line compare bit 10
+ tmp = read3X4(CRTHiOrd) | 0x08; /* line compare bit 10 */
if (vtotal & 0x400) tmp |= 0x80;
if (vblankstart & 0x400) tmp |= 0x40;
if (vsyncstart & 0x400) tmp |= 0x20;
@@ -867,84 +950,100 @@ static int tridentfb_set_par(struct fb_info *info)
if (htotal & 0x800) tmp |= 0x800 >> 11;
if (hblankstart & 0x800) tmp |= 0x800 >> 7;
write3X4(HorizOverflow, tmp);
-
+
tmp = 0x40;
if (vblankstart & 0x200) tmp |= 0x20;
-//FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; //double scan for 200 line modes
+//FIXME if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80; /* double scan for 200 line modes */
write3X4(CRTMaxScanLine, tmp);
- write3X4(CRTLineCompare,0xFF);
- write3X4(CRTPRowScan,0);
- write3X4(CRTModeControl,0xC3);
+ write3X4(CRTLineCompare, 0xFF);
+ write3X4(CRTPRowScan, 0);
+ write3X4(CRTModeControl, 0xC3);
- write3X4(LinearAddReg,0x20); //enable linear addressing
+ write3X4(LinearAddReg, 0x20); /* enable linear addressing */
- tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84:0x80;
- write3X4(CRTCModuleTest,tmp); //enable access extended memory
+ tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80;
+ write3X4(CRTCModuleTest, tmp); /* enable access extended memory */
- write3X4(GraphEngReg, 0x80); //enable GE for text acceleration
+ write3X4(GraphEngReg, 0x80); /* enable GE for text acceleration */
-#ifdef CONFIG_FB_TRIDENT_ACCEL
- acc->init_accel(info->var.xres,bpp);
+#ifdef CONFIG_FB_TRIDENT_ACCEL
+ acc->init_accel(info->var.xres, bpp);
#endif
-
+
switch (bpp) {
- case 8: tmp = 0x00; break;
- case 16: tmp = 0x05; break;
- case 24: tmp = 0x29; break;
- case 32: tmp = 0x09;
+ case 8:
+ tmp = 0x00;
+ break;
+ case 16:
+ tmp = 0x05;
+ break;
+ case 24:
+ tmp = 0x29;
+ break;
+ case 32:
+ tmp = 0x09;
+ break;
}
write3X4(PixelBusReg, tmp);
tmp = 0x10;
if (chipcyber)
- tmp |= 0x20;
- write3X4(DRAMControl, tmp); //both IO,linear enable
+ tmp |= 0x20;
+ write3X4(DRAMControl, tmp); /* both IO, linear enable */
write3X4(InterfaceSel, read3X4(InterfaceSel) | 0x40);
- write3X4(Performance,0x92);
- write3X4(PCIReg,0x07); //MMIO & PCI read and write burst enable
+ write3X4(Performance, 0x92);
+ write3X4(PCIReg, 0x07); /* MMIO & PCI read and write burst enable */
/* convert from picoseconds to MHz */
- par->vclk = 1000000/info->var.pixclock;
+ par->vclk = 1000000 / info->var.pixclock;
if (bpp == 32)
- par->vclk *=2;
+ par->vclk *= 2;
set_vclk(par->vclk);
- write3C4(0,3);
- write3C4(1,1); //set char clock 8 dots wide
- write3C4(2,0x0F); //enable 4 maps because needed in chain4 mode
- write3C4(3,0);
- write3C4(4,0x0E); //memory mode enable bitmaps ??
+ write3C4(0, 3);
+ write3C4(1, 1); /* set char clock 8 dots wide */
+ write3C4(2, 0x0F); /* enable 4 maps because needed in chain4 mode */
+ write3C4(3, 0);
+ write3C4(4, 0x0E); /* memory mode enable bitmaps ?? */
- write3CE(MiscExtFunc,(bpp==32)?0x1A:0x12); //divide clock by 2 if 32bpp
- //chain4 mode display and CPU path
- write3CE(0x5,0x40); //no CGA compat,allow 256 col
- write3CE(0x6,0x05); //graphics mode
- write3CE(0x7,0x0F); //planes?
+ write3CE(MiscExtFunc, (bpp == 32) ? 0x1A : 0x12); /* divide clock by 2 if 32bpp */
+ /* chain4 mode display and CPU path */
+ write3CE(0x5, 0x40); /* no CGA compat, allow 256 col */
+ write3CE(0x6, 0x05); /* graphics mode */
+ write3CE(0x7, 0x0F); /* planes? */
if (chip_id == CYBERBLADEXPAi1) {
/* This fixes snow-effect in 32 bpp */
- write3X4(CRTHSyncStart,0x84);
+ write3X4(CRTHSyncStart, 0x84);
}
- writeAttr(0x10,0x41); //graphics mode and support 256 color modes
- writeAttr(0x12,0x0F); //planes
- writeAttr(0x13,0); //horizontal pel panning
+ writeAttr(0x10, 0x41); /* graphics mode and support 256 color modes */
+ writeAttr(0x12, 0x0F); /* planes */
+ writeAttr(0x13, 0); /* horizontal pel panning */
- //colors
- for(tmp = 0;tmp < 0x10;tmp++)
- writeAttr(tmp,tmp);
- readb(par->io_virt + CRT + 0x0A); //flip-flop to index
- t_outb(0x20, 0x3C0); //enable attr
+ /* colors */
+ for (tmp = 0; tmp < 0x10; tmp++)
+ writeAttr(tmp, tmp);
+ readb(par->io_virt + CRT + 0x0A); /* flip-flop to index */
+ t_outb(0x20, 0x3C0); /* enable attr */
switch (bpp) {
- case 8: tmp = 0;break; //256 colors
- case 15: tmp = 0x10;break;
- case 16: tmp = 0x30;break; //hicolor
- case 24: //truecolor
- case 32: tmp = 0xD0;break;
+ case 8:
+ tmp = 0;
+ break;
+ case 15:
+ tmp = 0x10;
+ break;
+ case 16:
+ tmp = 0x30;
+ break;
+ case 24:
+ case 32:
+ tmp = 0xD0;
+ break;
}
t_inb(0x3C8);
@@ -952,37 +1051,36 @@ static int tridentfb_set_par(struct fb_info *info)
t_inb(0x3C6);
t_inb(0x3C6);
t_inb(0x3C6);
- t_outb(tmp,0x3C6);
+ t_outb(tmp, 0x3C6);
t_inb(0x3C8);
if (flatpanel)
set_number_of_lines(info->var.yres);
- set_lwidth(info->var.xres * bpp/(4*16));
+ set_lwidth(info->var.xres * bpp / (4 * 16));
info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
- info->fix.line_length = info->var.xres * (bpp >> 3);
- info->cmap.len = (bpp == 8) ? 256: 16;
+ info->fix.line_length = info->var.xres * (bpp >> 3);
+ info->cmap.len = (bpp == 8) ? 256 : 16;
debug("exit\n");
return 0;
}
/* Set one color register */
static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *info)
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
{
int bpp = info->var.bits_per_pixel;
if (regno >= info->cmap.len)
return 1;
-
if (bpp == 8) {
- t_outb(0xFF,0x3C6);
- t_outb(regno,0x3C8);
+ t_outb(0xFF, 0x3C6);
+ t_outb(regno, 0x3C8);
- t_outb(red>>10,0x3C9);
- t_outb(green>>10,0x3C9);
- t_outb(blue>>10,0x3C9);
+ t_outb(red >> 10, 0x3C9);
+ t_outb(green >> 10, 0x3C9);
+ t_outb(blue >> 10, 0x3C9);
} else if (regno < 16) {
if (bpp == 16) { /* RGB 565 */
@@ -994,29 +1092,28 @@ static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
((u32 *)(info->pseudo_palette))[regno] = col;
} else if (bpp == 32) /* ARGB 8888 */
((u32*)info->pseudo_palette)[regno] =
- ((transp & 0xFF00) <<16) |
- ((red & 0xFF00) << 8) |
+ ((transp & 0xFF00) << 16) |
+ ((red & 0xFF00) << 8) |
((green & 0xFF00)) |
- ((blue & 0xFF00)>>8);
+ ((blue & 0xFF00) >> 8);
}
-// debug("exit\n");
+/* debug("exit\n"); */
return 0;
}
/* Try blanking the screen.For flat panels it does nothing */
static int tridentfb_blank(int blank_mode, struct fb_info *info)
{
- unsigned char PMCont,DPMSCont;
+ unsigned char PMCont, DPMSCont;
debug("enter\n");
if (flatpanel)
return 0;
- t_outb(0x04,0x83C8); /* Read DPMS Control */
+ t_outb(0x04, 0x83C8); /* Read DPMS Control */
PMCont = t_inb(0x83C6) & 0xFC;
DPMSCont = read3CE(PowerStatus) & 0xFC;
- switch (blank_mode)
- {
+ switch (blank_mode) {
case FB_BLANK_UNBLANK:
/* Screen: On, HSync: On, VSync: On */
case FB_BLANK_NORMAL:
@@ -1039,11 +1136,11 @@ static int tridentfb_blank(int blank_mode, struct fb_info *info)
PMCont |= 0x00;
DPMSCont |= 0x03;
break;
- }
+ }
- write3CE(PowerStatus,DPMSCont);
- t_outb(4,0x83C8);
- t_outb(PMCont,0x83C6);
+ write3CE(PowerStatus, DPMSCont);
+ t_outb(4, 0x83C8);
+ t_outb(PMCont, 0x83C6);
debug("exit\n");
@@ -1051,7 +1148,20 @@ static int tridentfb_blank(int blank_mode, struct fb_info *info)
return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
}
-static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_device_id * id)
+static struct fb_ops tridentfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = tridentfb_setcolreg,
+ .fb_pan_display = tridentfb_pan_display,
+ .fb_blank = tridentfb_blank,
+ .fb_check_var = tridentfb_check_var,
+ .fb_set_par = tridentfb_set_par,
+ .fb_fillrect = tridentfb_fillrect,
+ .fb_copyarea = tridentfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static int __devinit trident_pci_probe(struct pci_dev * dev,
+ const struct pci_device_id * id)
{
int err;
unsigned char revision;
@@ -1062,31 +1172,42 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de
chip_id = id->device;
- if(chip_id == CYBERBLADEi1)
+ if (chip_id == CYBERBLADEi1)
output("*** Please do use cyblafb, Cyberblade/i1 support "
"will soon be removed from tridentfb!\n");
/* If PCI id is 0x9660 then further detect chip type */
-
+
if (chip_id == TGUI9660) {
- outb(RevisionID,0x3C4);
- revision = inb(0x3C5);
-
+ outb(RevisionID, 0x3C4);
+ revision = inb(0x3C5);
+
switch (revision) {
- case 0x22:
- case 0x23: chip_id = CYBER9397;break;
- case 0x2A: chip_id = CYBER9397DVD;break;
- case 0x30:
- case 0x33:
- case 0x34:
- case 0x35:
- case 0x38:
- case 0x3A:
- case 0xB3: chip_id = CYBER9385;break;
- case 0x40 ... 0x43: chip_id = CYBER9382;break;
- case 0x4A: chip_id = CYBER9388;break;
- default:break;
+ case 0x22:
+ case 0x23:
+ chip_id = CYBER9397;
+ break;
+ case 0x2A:
+ chip_id = CYBER9397DVD;
+ break;
+ case 0x30:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x38:
+ case 0x3A:
+ case 0xB3:
+ chip_id = CYBER9385;
+ break;
+ case 0x40 ... 0x43:
+ chip_id = CYBER9382;
+ break;
+ case 0x4A:
+ chip_id = CYBER9388;
+ break;
+ default:
+ break;
}
}
@@ -1095,8 +1216,7 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de
if (is_xp(chip_id)) {
acc = &accel_xp;
- } else
- if (is_blade(chip_id)) {
+ } else if (is_blade(chip_id)) {
acc = &accel_blade;
} else {
acc = &accel_image;
@@ -1108,8 +1228,8 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de
fb_info.par = &default_par;
/* setup MMIO region */
- tridentfb_fix.mmio_start = pci_resource_start(dev,1);
- tridentfb_fix.mmio_len = chip3D ? 0x20000:0x10000;
+ tridentfb_fix.mmio_start = pci_resource_start(dev, 1);
+ tridentfb_fix.mmio_len = chip3D ? 0x20000 : 0x10000;
if (!request_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len, "tridentfb")) {
debug("request_region failed!\n");
@@ -1125,11 +1245,11 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de
}
enable_mmio();
-
+
/* setup framebuffer memory */
- tridentfb_fix.smem_start = pci_resource_start(dev,0);
+ tridentfb_fix.smem_start = pci_resource_start(dev, 0);
tridentfb_fix.smem_len = get_memsize();
-
+
if (!request_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len, "tridentfb")) {
debug("request_mem_region failed!\n");
err = -1;
@@ -1137,7 +1257,7 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de
}
fb_info.screen_base = ioremap_nocache(tridentfb_fix.smem_start,
- tridentfb_fix.smem_len);
+ tridentfb_fix.smem_len);
if (!fb_info.screen_base) {
release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
@@ -1147,13 +1267,13 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de
}
output("%s board found\n", pci_name(dev));
-#if 0
- output("Trident board found : mem = %X,io = %X, mem_v = %X, io_v = %X\n",
+#if 0
+ output("Trident board found : mem = %X, io = %X, mem_v = %X, io_v = %X\n",
tridentfb_fix.smem_start, tridentfb_fix.mmio_start, fb_info.screen_base, default_par.io_virt);
#endif
displaytype = get_displaytype();
- if(flatpanel)
+ if (flatpanel)
nativex = get_nativex();
fb_info.fix = tridentfb_fix;
@@ -1166,11 +1286,11 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de
#endif
fb_info.pseudo_palette = pseudo_pal;
- if (!fb_find_mode(&default_var,&fb_info,mode,NULL,0,NULL,bpp)) {
+ if (!fb_find_mode(&default_var, &fb_info, mode, NULL, 0, NULL, bpp)) {
err = -EINVAL;
goto out_unmap;
}
- fb_alloc_cmap(&fb_info.cmap,256,0);
+ fb_alloc_cmap(&fb_info.cmap, 256, 0);
if (defaultaccel && acc)
default_var.accel_flags |= FB_ACCELF_TEXT;
else
@@ -1184,8 +1304,8 @@ static int __devinit trident_pci_probe(struct pci_dev * dev, const struct pci_de
goto out_unmap;
}
output("fb%d: %s frame buffer device %dx%d-%dbpp\n",
- fb_info.node, fb_info.fix.id,default_var.xres,
- default_var.yres,default_var.bits_per_pixel);
+ fb_info.node, fb_info.fix.id, default_var.xres,
+ default_var.yres, default_var.bits_per_pixel);
return 0;
out_unmap:
@@ -1196,7 +1316,7 @@ out_unmap:
return err;
}
-static void __devexit trident_pci_remove(struct pci_dev * dev)
+static void __devexit trident_pci_remove(struct pci_dev *dev)
{
struct tridentfb_par *par = (struct tridentfb_par*)fb_info.par;
unregister_framebuffer(&fb_info);
@@ -1208,69 +1328,70 @@ static void __devexit trident_pci_remove(struct pci_dev * dev)
/* List of boards that we are trying to support */
static struct pci_device_id trident_devices[] = {
- {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
- {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID,PCI_ANY_ID,0,0,0},
+ {PCI_VENDOR_ID_TRIDENT, BLADE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi7D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBERBLADEi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBER9320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBER9388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBER9520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBER9525DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBER9397, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBER9397DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_TRIDENT, CYBERBLADEXPm16, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
-};
-
-MODULE_DEVICE_TABLE(pci,trident_devices);
+};
+
+MODULE_DEVICE_TABLE(pci, trident_devices);
static struct pci_driver tridentfb_pci_driver = {
- .name = "tridentfb",
- .id_table = trident_devices,
- .probe = trident_pci_probe,
- .remove = __devexit_p(trident_pci_remove)
+ .name = "tridentfb",
+ .id_table = trident_devices,
+ .probe = trident_pci_probe,
+ .remove = __devexit_p(trident_pci_remove)
};
/*
* Parse user specified options (`video=trident:')
* example:
- * video=trident:800x600,bpp=16,noaccel
+ * video=trident:800x600,bpp=16,noaccel
*/
#ifndef MODULE
static int tridentfb_setup(char *options)
{
- char * opt;
+ char *opt;
if (!options || !*options)
return 0;
- while((opt = strsep(&options,",")) != NULL ) {
- if (!*opt) continue;
- if (!strncmp(opt,"noaccel",7))
+ while ((opt = strsep(&options, ",")) != NULL) {
+ if (!*opt)
+ continue;
+ if (!strncmp(opt, "noaccel", 7))
noaccel = 1;
- else if (!strncmp(opt,"fp",2))
+ else if (!strncmp(opt, "fp", 2))
displaytype = DISPLAY_FP;
- else if (!strncmp(opt,"crt",3))
+ else if (!strncmp(opt, "crt", 3))
displaytype = DISPLAY_CRT;
- else if (!strncmp(opt,"bpp=",4))
- bpp = simple_strtoul(opt+4,NULL,0);
- else if (!strncmp(opt,"center",6))
+ else if (!strncmp(opt, "bpp=", 4))
+ bpp = simple_strtoul(opt + 4, NULL, 0);
+ else if (!strncmp(opt, "center", 6))
center = 1;
- else if (!strncmp(opt,"stretch",7))
+ else if (!strncmp(opt, "stretch", 7))
stretch = 1;
- else if (!strncmp(opt,"memsize=",8))
- memsize = simple_strtoul(opt+8,NULL,0);
- else if (!strncmp(opt,"memdiff=",8))
- memdiff = simple_strtoul(opt+8,NULL,0);
- else if (!strncmp(opt,"nativex=",8))
- nativex = simple_strtoul(opt+8,NULL,0);
+ else if (!strncmp(opt, "memsize=", 8))
+ memsize = simple_strtoul(opt + 8, NULL, 0);
+ else if (!strncmp(opt, "memdiff=", 8))
+ memdiff = simple_strtoul(opt + 8, NULL, 0);
+ else if (!strncmp(opt, "nativex=", 8))
+ nativex = simple_strtoul(opt + 8, NULL, 0);
else
mode = opt;
}
@@ -1296,18 +1417,6 @@ static void __exit tridentfb_exit(void)
pci_unregister_driver(&tridentfb_pci_driver);
}
-static struct fb_ops tridentfb_ops = {
- .owner = THIS_MODULE,
- .fb_setcolreg = tridentfb_setcolreg,
- .fb_pan_display = tridentfb_pan_display,
- .fb_blank = tridentfb_blank,
- .fb_check_var = tridentfb_check_var,
- .fb_set_par = tridentfb_set_par,
- .fb_fillrect = tridentfb_fillrect,
- .fb_copyarea= tridentfb_copyarea,
- .fb_imageblit = cfb_imageblit,
-};
-
module_init(tridentfb_init);
module_exit(tridentfb_exit);
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
new file mode 100644
index 00000000000..d1d6c0facd5
--- /dev/null
+++ b/drivers/video/uvesafb.c
@@ -0,0 +1,2068 @@
+/*
+ * A framebuffer driver for VBE 2.0+ compliant video cards
+ *
+ * (c) 2007 Michal Januszewski <spock@gentoo.org>
+ * Loosely based upon the vesafb driver.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+#include <linux/completion.h>
+#include <linux/connector.h>
+#include <linux/random.h>
+#include <linux/platform_device.h>
+#include <linux/limits.h>
+#include <linux/fb.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <video/edid.h>
+#include <video/uvesafb.h>
+#ifdef CONFIG_X86
+#include <video/vga.h>
+#endif
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+#include "edid.h"
+
+static struct cb_id uvesafb_cn_id = {
+ .idx = CN_IDX_V86D,
+ .val = CN_VAL_V86D_UVESAFB
+};
+static char v86d_path[PATH_MAX] = "/sbin/v86d";
+static char v86d_started; /* has v86d been started by uvesafb? */
+
+static struct fb_fix_screeninfo uvesafb_fix __devinitdata = {
+ .id = "VESA VGA",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .accel = FB_ACCEL_NONE,
+ .visual = FB_VISUAL_TRUECOLOR,
+};
+
+static int mtrr __devinitdata = 3; /* enable mtrr by default */
+static int blank __devinitdata = 1; /* enable blanking by default */
+static int ypan __devinitdata = 1; /* 0: scroll, 1: ypan, 2: ywrap */
+static int pmi_setpal __devinitdata = 1; /* use PMI for palette changes */
+static int nocrtc __devinitdata; /* ignore CRTC settings */
+static int noedid __devinitdata; /* don't try DDC transfers */
+static int vram_remap __devinitdata; /* set amt. of memory to be used */
+static int vram_total __devinitdata; /* set total amount of memory */
+static u16 maxclk __devinitdata; /* maximum pixel clock */
+static u16 maxvf __devinitdata; /* maximum vertical frequency */
+static u16 maxhf __devinitdata; /* maximum horizontal frequency */
+static u16 vbemode __devinitdata; /* force use of a specific VBE mode */
+static char *mode_option __devinitdata;
+
+static struct uvesafb_ktask *uvfb_tasks[UVESAFB_TASKS_MAX];
+static DEFINE_MUTEX(uvfb_lock);
+
+/*
+ * A handler for replies from userspace.
+ *
+ * Make sure each message passes consistency checks and if it does,
+ * find the kernel part of the task struct, copy the registers and
+ * the buffer contents and then complete the task.
+ */
+static void uvesafb_cn_callback(void *data)
+{
+ struct cn_msg *msg = data;
+ struct uvesafb_task *utask;
+ struct uvesafb_ktask *task;
+
+ if (msg->seq >= UVESAFB_TASKS_MAX)
+ return;
+
+ mutex_lock(&uvfb_lock);
+ task = uvfb_tasks[msg->seq];
+
+ if (!task || msg->ack != task->ack) {
+ mutex_unlock(&uvfb_lock);
+ return;
+ }
+
+ utask = (struct uvesafb_task *)msg->data;
+
+ /* Sanity checks for the buffer length. */
+ if (task->t.buf_len < utask->buf_len ||
+ utask->buf_len > msg->len - sizeof(*utask)) {
+ mutex_unlock(&uvfb_lock);
+ return;
+ }
+
+ uvfb_tasks[msg->seq] = NULL;
+ mutex_unlock(&uvfb_lock);
+
+ memcpy(&task->t, utask, sizeof(*utask));
+
+ if (task->t.buf_len && task->buf)
+ memcpy(task->buf, utask + 1, task->t.buf_len);
+
+ complete(task->done);
+ return;
+}
+
+static int uvesafb_helper_start(void)
+{
+ char *envp[] = {
+ "HOME=/",
+ "PATH=/sbin:/bin",
+ NULL,
+ };
+
+ char *argv[] = {
+ v86d_path,
+ NULL,
+ };
+
+ return call_usermodehelper(v86d_path, argv, envp, 1);
+}
+
+/*
+ * Execute a uvesafb task.
+ *
+ * Returns 0 if the task is executed successfully.
+ *
+ * A message sent to the userspace consists of the uvesafb_task
+ * struct and (optionally) a buffer. The uvesafb_task struct is
+ * a simplified version of uvesafb_ktask (its kernel counterpart)
+ * containing only the register values, flags and the length of
+ * the buffer.
+ *
+ * Each message is assigned a sequence number (increased linearly)
+ * and a random ack number. The sequence number is used as a key
+ * for the uvfb_tasks array which holds pointers to uvesafb_ktask
+ * structs for all requests.
+ */
+static int uvesafb_exec(struct uvesafb_ktask *task)
+{
+ static int seq;
+ struct cn_msg *m;
+ int err;
+ int len = sizeof(task->t) + task->t.buf_len;
+
+ /*
+ * Check whether the message isn't longer than the maximum
+ * allowed by connector.
+ */
+ if (sizeof(*m) + len > CONNECTOR_MAX_MSG_SIZE) {
+ printk(KERN_WARNING "uvesafb: message too long (%d), "
+ "can't execute task\n", (int)(sizeof(*m) + len));
+ return -E2BIG;
+ }
+
+ m = kzalloc(sizeof(*m) + len, GFP_KERNEL);
+ if (!m)
+ return -ENOMEM;
+
+ init_completion(task->done);
+
+ memcpy(&m->id, &uvesafb_cn_id, sizeof(m->id));
+ m->seq = seq;
+ m->len = len;
+ m->ack = random32();
+
+ /* uvesafb_task structure */
+ memcpy(m + 1, &task->t, sizeof(task->t));
+
+ /* Buffer */
+ memcpy((u8 *)(m + 1) + sizeof(task->t), task->buf, task->t.buf_len);
+
+ /*
+ * Save the message ack number so that we can find the kernel
+ * part of this task when a reply is received from userspace.
+ */
+ task->ack = m->ack;
+
+ mutex_lock(&uvfb_lock);
+
+ /* If all slots are taken -- bail out. */
+ if (uvfb_tasks[seq]) {
+ mutex_unlock(&uvfb_lock);
+ return -EBUSY;
+ }
+
+ /* Save a pointer to the kernel part of the task struct. */
+ uvfb_tasks[seq] = task;
+ mutex_unlock(&uvfb_lock);
+
+ err = cn_netlink_send(m, 0, gfp_any());
+ if (err == -ESRCH) {
+ /*
+ * Try to start the userspace helper if sending
+ * the request failed the first time.
+ */
+ err = uvesafb_helper_start();
+ if (err) {
+ printk(KERN_ERR "uvesafb: failed to execute %s\n",
+ v86d_path);
+ printk(KERN_ERR "uvesafb: make sure that the v86d "
+ "helper is installed and executable\n");
+ } else {
+ v86d_started = 1;
+ err = cn_netlink_send(m, 0, gfp_any());
+ }
+ }
+ kfree(m);
+
+ if (!err && !(task->t.flags & TF_EXIT))
+ err = !wait_for_completion_timeout(task->done,
+ msecs_to_jiffies(UVESAFB_TIMEOUT));
+
+ mutex_lock(&uvfb_lock);
+ uvfb_tasks[seq] = NULL;
+ mutex_unlock(&uvfb_lock);
+
+ seq++;
+ if (seq >= UVESAFB_TASKS_MAX)
+ seq = 0;
+
+ return err;
+}
+
+/*
+ * Free a uvesafb_ktask struct.
+ */
+static void uvesafb_free(struct uvesafb_ktask *task)
+{
+ if (task) {
+ if (task->done)
+ kfree(task->done);
+ kfree(task);
+ }
+}
+
+/*
+ * Prepare a uvesafb_ktask struct to be used again.
+ */
+static void uvesafb_reset(struct uvesafb_ktask *task)
+{
+ struct completion *cpl = task->done;
+
+ memset(task, 0, sizeof(*task));
+ task->done = cpl;
+}
+
+/*
+ * Allocate and prepare a uvesafb_ktask struct.
+ */
+static struct uvesafb_ktask *uvesafb_prep(void)
+{
+ struct uvesafb_ktask *task;
+
+ task = kzalloc(sizeof(*task), GFP_KERNEL);
+ if (task) {
+ task->done = kzalloc(sizeof(*task->done), GFP_KERNEL);
+ if (!task->done) {
+ kfree(task);
+ task = NULL;
+ }
+ }
+ return task;
+}
+
+static void uvesafb_setup_var(struct fb_var_screeninfo *var,
+ struct fb_info *info, struct vbe_mode_ib *mode)
+{
+ struct uvesafb_par *par = info->par;
+
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->sync = FB_SYNC_VERT_HIGH_ACT;
+
+ var->xres = mode->x_res;
+ var->yres = mode->y_res;
+ var->xres_virtual = mode->x_res;
+ var->yres_virtual = (par->ypan) ?
+ info->fix.smem_len / mode->bytes_per_scan_line :
+ mode->y_res;
+ var->xoffset = 0;
+ var->yoffset = 0;
+ var->bits_per_pixel = mode->bits_per_pixel;
+
+ if (var->bits_per_pixel == 15)
+ var->bits_per_pixel = 16;
+
+ if (var->bits_per_pixel > 8) {
+ var->red.offset = mode->red_off;
+ var->red.length = mode->red_len;
+ var->green.offset = mode->green_off;
+ var->green.length = mode->green_len;
+ var->blue.offset = mode->blue_off;
+ var->blue.length = mode->blue_len;
+ var->transp.offset = mode->rsvd_off;
+ var->transp.length = mode->rsvd_len;
+ } else {
+ var->red.offset = 0;
+ var->green.offset = 0;
+ var->blue.offset = 0;
+ var->transp.offset = 0;
+
+ /*
+ * We're assuming that we can switch the DAC to 8 bits. If
+ * this proves to be incorrect, we'll update the fields
+ * later in set_par().
+ */
+ if (par->vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC) {
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.length = 0;
+ } else {
+ var->red.length = 6;
+ var->green.length = 6;
+ var->blue.length = 6;
+ var->transp.length = 0;
+ }
+ }
+}
+
+static int uvesafb_vbe_find_mode(struct uvesafb_par *par,
+ int xres, int yres, int depth, unsigned char flags)
+{
+ int i, match = -1, h = 0, d = 0x7fffffff;
+
+ for (i = 0; i < par->vbe_modes_cnt; i++) {
+ h = abs(par->vbe_modes[i].x_res - xres) +
+ abs(par->vbe_modes[i].y_res - yres) +
+ abs(depth - par->vbe_modes[i].depth);
+
+ /*
+ * We have an exact match in terms of resolution
+ * and depth.
+ */
+ if (h == 0)
+ return i;
+
+ if (h < d || (h == d && par->vbe_modes[i].depth > depth)) {
+ d = h;
+ match = i;
+ }
+ }
+ i = 1;
+
+ if (flags & UVESAFB_EXACT_DEPTH &&
+ par->vbe_modes[match].depth != depth)
+ i = 0;
+
+ if (flags & UVESAFB_EXACT_RES && d > 24)
+ i = 0;
+
+ if (i != 0)
+ return match;
+ else
+ return -1;
+}
+
+static u8 *uvesafb_vbe_state_save(struct uvesafb_par *par)
+{
+ struct uvesafb_ktask *task;
+ u8 *state;
+ int err;
+
+ if (!par->vbe_state_size)
+ return NULL;
+
+ state = kmalloc(par->vbe_state_size, GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ task = uvesafb_prep();
+ if (!task) {
+ kfree(state);
+ return NULL;
+ }
+
+ task->t.regs.eax = 0x4f04;
+ task->t.regs.ecx = 0x000f;
+ task->t.regs.edx = 0x0001;
+ task->t.flags = TF_BUF_RET | TF_BUF_ESBX;
+ task->t.buf_len = par->vbe_state_size;
+ task->buf = state;
+ err = uvesafb_exec(task);
+
+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
+ printk(KERN_WARNING "uvesafb: VBE get state call "
+ "failed (eax=0x%x, err=%d)\n",
+ task->t.regs.eax, err);
+ kfree(state);
+ state = NULL;
+ }
+
+ uvesafb_free(task);
+ return state;
+}
+
+static void uvesafb_vbe_state_restore(struct uvesafb_par *par, u8 *state_buf)
+{
+ struct uvesafb_ktask *task;
+ int err;
+
+ if (!state_buf)
+ return;
+
+ task = uvesafb_prep();
+ if (!task)
+ return;
+
+ task->t.regs.eax = 0x4f04;
+ task->t.regs.ecx = 0x000f;
+ task->t.regs.edx = 0x0002;
+ task->t.buf_len = par->vbe_state_size;
+ task->t.flags = TF_BUF_ESBX;
+ task->buf = state_buf;
+
+ err = uvesafb_exec(task);
+ if (err || (task->t.regs.eax & 0xffff) != 0x004f)
+ printk(KERN_WARNING "uvesafb: VBE state restore call "
+ "failed (eax=0x%x, err=%d)\n",
+ task->t.regs.eax, err);
+
+ uvesafb_free(task);
+}
+
+static int __devinit uvesafb_vbe_getinfo(struct uvesafb_ktask *task,
+ struct uvesafb_par *par)
+{
+ int err;
+
+ task->t.regs.eax = 0x4f00;
+ task->t.flags = TF_VBEIB;
+ task->t.buf_len = sizeof(struct vbe_ib);
+ task->buf = &par->vbe_ib;
+ strncpy(par->vbe_ib.vbe_signature, "VBE2", 4);
+
+ err = uvesafb_exec(task);
+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
+ printk(KERN_ERR "uvesafb: Getting VBE info block failed "
+ "(eax=0x%x, err=%d)\n", (u32)task->t.regs.eax,
+ err);
+ return -EINVAL;
+ }
+
+ if (par->vbe_ib.vbe_version < 0x0200) {
+ printk(KERN_ERR "uvesafb: Sorry, pre-VBE 2.0 cards are "
+ "not supported.\n");
+ return -EINVAL;
+ }
+
+ if (!par->vbe_ib.mode_list_ptr) {
+ printk(KERN_ERR "uvesafb: Missing mode list!\n");
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "uvesafb: ");
+
+ /*
+ * Convert string pointers and the mode list pointer into
+ * usable addresses. Print informational messages about the
+ * video adapter and its vendor.
+ */
+ if (par->vbe_ib.oem_vendor_name_ptr)
+ printk("%s, ",
+ ((char *)task->buf) + par->vbe_ib.oem_vendor_name_ptr);
+
+ if (par->vbe_ib.oem_product_name_ptr)
+ printk("%s, ",
+ ((char *)task->buf) + par->vbe_ib.oem_product_name_ptr);
+
+ if (par->vbe_ib.oem_product_rev_ptr)
+ printk("%s, ",
+ ((char *)task->buf) + par->vbe_ib.oem_product_rev_ptr);
+
+ if (par->vbe_ib.oem_string_ptr)
+ printk("OEM: %s, ",
+ ((char *)task->buf) + par->vbe_ib.oem_string_ptr);
+
+ printk("VBE v%d.%d\n", ((par->vbe_ib.vbe_version & 0xff00) >> 8),
+ par->vbe_ib.vbe_version & 0xff);
+
+ return 0;
+}
+
+static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task,
+ struct uvesafb_par *par)
+{
+ int off = 0, err;
+ u16 *mode;
+
+ par->vbe_modes_cnt = 0;
+
+ /* Count available modes. */
+ mode = (u16 *) (((u8 *)&par->vbe_ib) + par->vbe_ib.mode_list_ptr);
+ while (*mode != 0xffff) {
+ par->vbe_modes_cnt++;
+ mode++;
+ }
+
+ par->vbe_modes = kzalloc(sizeof(struct vbe_mode_ib) *
+ par->vbe_modes_cnt, GFP_KERNEL);
+ if (!par->vbe_modes)
+ return -ENOMEM;
+
+ /* Get info about all available modes. */
+ mode = (u16 *) (((u8 *)&par->vbe_ib) + par->vbe_ib.mode_list_ptr);
+ while (*mode != 0xffff) {
+ struct vbe_mode_ib *mib;
+
+ uvesafb_reset(task);
+ task->t.regs.eax = 0x4f01;
+ task->t.regs.ecx = (u32) *mode;
+ task->t.flags = TF_BUF_RET | TF_BUF_ESDI;
+ task->t.buf_len = sizeof(struct vbe_mode_ib);
+ task->buf = par->vbe_modes + off;
+
+ err = uvesafb_exec(task);
+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
+ printk(KERN_ERR "uvesafb: Getting mode info block "
+ "for mode 0x%x failed (eax=0x%x, err=%d)\n",
+ *mode, (u32)task->t.regs.eax, err);
+ return -EINVAL;
+ }
+
+ mib = task->buf;
+ mib->mode_id = *mode;
+
+ /*
+ * We only want modes that are supported with the current
+ * hardware configuration, color, graphics and that have
+ * support for the LFB.
+ */
+ if ((mib->mode_attr & VBE_MODE_MASK) == VBE_MODE_MASK &&
+ mib->bits_per_pixel >= 8)
+ off++;
+ else
+ par->vbe_modes_cnt--;
+
+ mode++;
+ mib->depth = mib->red_len + mib->green_len + mib->blue_len;
+
+ /*
+ * Handle 8bpp modes and modes with broken color component
+ * lengths.
+ */
+ if (mib->depth == 0 || (mib->depth == 24 &&
+ mib->bits_per_pixel == 32))
+ mib->depth = mib->bits_per_pixel;
+ }
+
+ return 0;
+}
+
+/*
+ * The Protected Mode Interface is 32-bit x86 code, so we only run it on
+ * x86 and not x86_64.
+ */
+#ifdef CONFIG_X86_32
+static int __devinit uvesafb_vbe_getpmi(struct uvesafb_ktask *task,
+ struct uvesafb_par *par)
+{
+ int i, err;
+
+ uvesafb_reset(task);
+ task->t.regs.eax = 0x4f0a;
+ task->t.regs.ebx = 0x0;
+ err = uvesafb_exec(task);
+
+ if ((task->t.regs.eax & 0xffff) != 0x4f || task->t.regs.es < 0xc000) {
+ par->pmi_setpal = par->ypan = 0;
+ } else {
+ par->pmi_base = (u16 *)phys_to_virt(((u32)task->t.regs.es << 4)
+ + task->t.regs.edi);
+ par->pmi_start = (u8 *)par->pmi_base + par->pmi_base[1];
+ par->pmi_pal = (u8 *)par->pmi_base + par->pmi_base[2];
+ printk(KERN_INFO "uvesafb: protected mode interface info at "
+ "%04x:%04x\n",
+ (u16)task->t.regs.es, (u16)task->t.regs.edi);
+ printk(KERN_INFO "uvesafb: pmi: set display start = %p, "
+ "set palette = %p\n", par->pmi_start,
+ par->pmi_pal);
+
+ if (par->pmi_base[3]) {
+ printk(KERN_INFO "uvesafb: pmi: ports = ");
+ for (i = par->pmi_base[3]/2;
+ par->pmi_base[i] != 0xffff; i++)
+ printk("%x ", par->pmi_base[i]);
+ printk("\n");
+
+ if (par->pmi_base[i] != 0xffff) {
+ printk(KERN_INFO "uvesafb: can't handle memory"
+ " requests, pmi disabled\n");
+ par->ypan = par->pmi_setpal = 0;
+ }
+ }
+ }
+ return 0;
+}
+#endif /* CONFIG_X86_32 */
+
+/*
+ * Check whether a video mode is supported by the Video BIOS and is
+ * compatible with the monitor limits.
+ */
+static int __devinit uvesafb_is_valid_mode(struct fb_videomode *mode,
+ struct fb_info *info)
+{
+ if (info->monspecs.gtf) {
+ fb_videomode_to_var(&info->var, mode);
+ if (fb_validate_mode(&info->var, info))
+ return 0;
+ }
+
+ if (uvesafb_vbe_find_mode(info->par, mode->xres, mode->yres, 8,
+ UVESAFB_EXACT_RES) == -1)
+ return 0;
+
+ return 1;
+}
+
+static int __devinit uvesafb_vbe_getedid(struct uvesafb_ktask *task,
+ struct fb_info *info)
+{
+ struct uvesafb_par *par = info->par;
+ int err = 0;
+
+ if (noedid || par->vbe_ib.vbe_version < 0x0300)
+ return -EINVAL;
+
+ task->t.regs.eax = 0x4f15;
+ task->t.regs.ebx = 0;
+ task->t.regs.ecx = 0;
+ task->t.buf_len = 0;
+ task->t.flags = 0;
+
+ err = uvesafb_exec(task);
+
+ if ((task->t.regs.eax & 0xffff) != 0x004f || err)
+ return -EINVAL;
+
+ if ((task->t.regs.ebx & 0x3) == 3) {
+ printk(KERN_INFO "uvesafb: VBIOS/hardware supports both "
+ "DDC1 and DDC2 transfers\n");
+ } else if ((task->t.regs.ebx & 0x3) == 2) {
+ printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC2 "
+ "transfers\n");
+ } else if ((task->t.regs.ebx & 0x3) == 1) {
+ printk(KERN_INFO "uvesafb: VBIOS/hardware supports DDC1 "
+ "transfers\n");
+ } else {
+ printk(KERN_INFO "uvesafb: VBIOS/hardware doesn't support "
+ "DDC transfers\n");
+ return -EINVAL;
+ }
+
+ task->t.regs.eax = 0x4f15;
+ task->t.regs.ebx = 1;
+ task->t.regs.ecx = task->t.regs.edx = 0;
+ task->t.flags = TF_BUF_RET | TF_BUF_ESDI;
+ task->t.buf_len = EDID_LENGTH;
+ task->buf = kzalloc(EDID_LENGTH, GFP_KERNEL);
+
+ err = uvesafb_exec(task);
+
+ if ((task->t.regs.eax & 0xffff) == 0x004f && !err) {
+ fb_edid_to_monspecs(task->buf, &info->monspecs);
+
+ if (info->monspecs.vfmax && info->monspecs.hfmax) {
+ /*
+ * If the maximum pixel clock wasn't specified in
+ * the EDID block, set it to 300 MHz.
+ */
+ if (info->monspecs.dclkmax == 0)
+ info->monspecs.dclkmax = 300 * 1000000;
+ info->monspecs.gtf = 1;
+ }
+ } else {
+ err = -EINVAL;
+ }
+
+ kfree(task->buf);
+ return err;
+}
+
+static void __devinit uvesafb_vbe_getmonspecs(struct uvesafb_ktask *task,
+ struct fb_info *info)
+{
+ struct uvesafb_par *par = info->par;
+ int i;
+
+ memset(&info->monspecs, 0, sizeof(info->monspecs));
+
+ /*
+ * If we don't get all necessary data from the EDID block,
+ * mark it as incompatible with the GTF and set nocrtc so
+ * that we always use the default BIOS refresh rate.
+ */
+ if (uvesafb_vbe_getedid(task, info)) {
+ info->monspecs.gtf = 0;
+ par->nocrtc = 1;
+ }
+
+ /* Kernel command line overrides. */
+ if (maxclk)
+ info->monspecs.dclkmax = maxclk * 1000000;
+ if (maxvf)
+ info->monspecs.vfmax = maxvf;
+ if (maxhf)
+ info->monspecs.hfmax = maxhf * 1000;
+
+ /*
+ * In case DDC transfers are not supported, the user can provide
+ * monitor limits manually. Lower limits are set to "safe" values.
+ */
+ if (info->monspecs.gtf == 0 && maxclk && maxvf && maxhf) {
+ info->monspecs.dclkmin = 0;
+ info->monspecs.vfmin = 60;
+ info->monspecs.hfmin = 29000;
+ info->monspecs.gtf = 1;
+ par->nocrtc = 0;
+ }
+
+ if (info->monspecs.gtf)
+ printk(KERN_INFO
+ "uvesafb: monitor limits: vf = %d Hz, hf = %d kHz, "
+ "clk = %d MHz\n", info->monspecs.vfmax,
+ (int)(info->monspecs.hfmax / 1000),
+ (int)(info->monspecs.dclkmax / 1000000));
+ else
+ printk(KERN_INFO "uvesafb: no monitor limits have been set, "
+ "default refresh rate will be used\n");
+
+ /* Add VBE modes to the modelist. */
+ for (i = 0; i < par->vbe_modes_cnt; i++) {
+ struct fb_var_screeninfo var;
+ struct vbe_mode_ib *mode;
+ struct fb_videomode vmode;
+
+ mode = &par->vbe_modes[i];
+ memset(&var, 0, sizeof(var));
+
+ var.xres = mode->x_res;
+ var.yres = mode->y_res;
+
+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, &var, info);
+ fb_var_to_videomode(&vmode, &var);
+ fb_add_videomode(&vmode, &info->modelist);
+ }
+
+ /* Add valid VESA modes to our modelist. */
+ for (i = 0; i < VESA_MODEDB_SIZE; i++) {
+ if (uvesafb_is_valid_mode((struct fb_videomode *)
+ &vesa_modes[i], info))
+ fb_add_videomode(&vesa_modes[i], &info->modelist);
+ }
+
+ for (i = 0; i < info->monspecs.modedb_len; i++) {
+ if (uvesafb_is_valid_mode(&info->monspecs.modedb[i], info))
+ fb_add_videomode(&info->monspecs.modedb[i],
+ &info->modelist);
+ }
+
+ return;
+}
+
+static void __devinit uvesafb_vbe_getstatesize(struct uvesafb_ktask *task,
+ struct uvesafb_par *par)
+{
+ int err;
+
+ uvesafb_reset(task);
+
+ /*
+ * Get the VBE state buffer size. We want all available
+ * hardware state data (CL = 0x0f).
+ */
+ task->t.regs.eax = 0x4f04;
+ task->t.regs.ecx = 0x000f;
+ task->t.regs.edx = 0x0000;
+ task->t.flags = 0;
+
+ err = uvesafb_exec(task);
+
+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
+ printk(KERN_WARNING "uvesafb: VBE state buffer size "
+ "cannot be determined (eax=0x%x, err=%d)\n",
+ task->t.regs.eax, err);
+ par->vbe_state_size = 0;
+ return;
+ }
+
+ par->vbe_state_size = 64 * (task->t.regs.ebx & 0xffff);
+}
+
+static int __devinit uvesafb_vbe_init(struct fb_info *info)
+{
+ struct uvesafb_ktask *task = NULL;
+ struct uvesafb_par *par = info->par;
+ int err;
+
+ task = uvesafb_prep();
+ if (!task)
+ return -ENOMEM;
+
+ err = uvesafb_vbe_getinfo(task, par);
+ if (err)
+ goto out;
+
+ err = uvesafb_vbe_getmodes(task, par);
+ if (err)
+ goto out;
+
+ par->nocrtc = nocrtc;
+#ifdef CONFIG_X86_32
+ par->pmi_setpal = pmi_setpal;
+ par->ypan = ypan;
+
+ if (par->pmi_setpal || par->ypan)
+ uvesafb_vbe_getpmi(task, par);
+#else
+ /* The protected mode interface is not available on non-x86. */
+ par->pmi_setpal = par->ypan = 0;
+#endif
+
+ INIT_LIST_HEAD(&info->modelist);
+ uvesafb_vbe_getmonspecs(task, info);
+ uvesafb_vbe_getstatesize(task, par);
+
+out: uvesafb_free(task);
+ return err;
+}
+
+static int __devinit uvesafb_vbe_init_mode(struct fb_info *info)
+{
+ struct list_head *pos;
+ struct fb_modelist *modelist;
+ struct fb_videomode *mode;
+ struct uvesafb_par *par = info->par;
+ int i, modeid;
+
+ /* Has the user requested a specific VESA mode? */
+ if (vbemode) {
+ for (i = 0; i < par->vbe_modes_cnt; i++) {
+ if (par->vbe_modes[i].mode_id == vbemode) {
+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
+ &info->var, info);
+ /*
+ * With pixclock set to 0, the default BIOS
+ * timings will be used in set_par().
+ */
+ info->var.pixclock = 0;
+ modeid = i;
+ goto gotmode;
+ }
+ }
+ printk(KERN_INFO "uvesafb: requested VBE mode 0x%x is "
+ "unavailable\n", vbemode);
+ vbemode = 0;
+ }
+
+ /* Count the modes in the modelist */
+ i = 0;
+ list_for_each(pos, &info->modelist)
+ i++;
+
+ /*
+ * Convert the modelist into a modedb so that we can use it with
+ * fb_find_mode().
+ */
+ mode = kzalloc(i * sizeof(*mode), GFP_KERNEL);
+ if (mode) {
+ i = 0;
+ list_for_each(pos, &info->modelist) {
+ modelist = list_entry(pos, struct fb_modelist, list);
+ mode[i] = modelist->mode;
+ i++;
+ }
+
+ if (!mode_option)
+ mode_option = UVESAFB_DEFAULT_MODE;
+
+ i = fb_find_mode(&info->var, info, mode_option, mode, i,
+ NULL, 8);
+
+ kfree(mode);
+ }
+
+ /* fb_find_mode() failed */
+ if (i == 0 || i >= 3) {
+ info->var.xres = 640;
+ info->var.yres = 480;
+ mode = (struct fb_videomode *)
+ fb_find_best_mode(&info->var, &info->modelist);
+
+ if (mode) {
+ fb_videomode_to_var(&info->var, mode);
+ } else {
+ modeid = par->vbe_modes[0].mode_id;
+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
+ &info->var, info);
+ goto gotmode;
+ }
+ }
+
+ /* Look for a matching VBE mode. */
+ modeid = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres,
+ info->var.bits_per_pixel, UVESAFB_EXACT_RES);
+
+ if (modeid == -1)
+ return -EINVAL;
+
+gotmode:
+ uvesafb_setup_var(&info->var, info, &par->vbe_modes[modeid]);
+
+ /*
+ * If we are not VBE3.0+ compliant, we're done -- the BIOS will
+ * ignore our timings anyway.
+ */
+ if (par->vbe_ib.vbe_version < 0x0300 || par->nocrtc)
+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60,
+ &info->var, info);
+
+ return modeid;
+}
+
+static int uvesafb_setpalette(struct uvesafb_pal_entry *entries, int count,
+ int start, struct fb_info *info)
+{
+ struct uvesafb_ktask *task;
+#ifdef CONFIG_X86
+ struct uvesafb_par *par = info->par;
+ int i = par->mode_idx;
+#endif
+ int err = 0;
+
+ /*
+ * We support palette modifications for 8 bpp modes only, so
+ * there can never be more than 256 entries.
+ */
+ if (start + count > 256)
+ return -EINVAL;
+
+#ifdef CONFIG_X86
+ /* Use VGA registers if mode is VGA-compatible. */
+ if (i >= 0 && i < par->vbe_modes_cnt &&
+ par->vbe_modes[i].mode_attr & VBE_MODE_VGACOMPAT) {
+ for (i = 0; i < count; i++) {
+ outb_p(start + i, dac_reg);
+ outb_p(entries[i].red, dac_val);
+ outb_p(entries[i].green, dac_val);
+ outb_p(entries[i].blue, dac_val);
+ }
+ }
+#ifdef CONFIG_X86_32
+ else if (par->pmi_setpal) {
+ __asm__ __volatile__(
+ "call *(%%esi)"
+ : /* no return value */
+ : "a" (0x4f09), /* EAX */
+ "b" (0), /* EBX */
+ "c" (count), /* ECX */
+ "d" (start), /* EDX */
+ "D" (entries), /* EDI */
+ "S" (&par->pmi_pal)); /* ESI */
+ }
+#endif /* CONFIG_X86_32 */
+ else
+#endif /* CONFIG_X86 */
+ {
+ task = uvesafb_prep();
+ if (!task)
+ return -ENOMEM;
+
+ task->t.regs.eax = 0x4f09;
+ task->t.regs.ebx = 0x0;
+ task->t.regs.ecx = count;
+ task->t.regs.edx = start;
+ task->t.flags = TF_BUF_ESDI;
+ task->t.buf_len = sizeof(struct uvesafb_pal_entry) * count;
+ task->buf = entries;
+
+ err = uvesafb_exec(task);
+ if ((task->t.regs.eax & 0xffff) != 0x004f)
+ err = 1;
+
+ uvesafb_free(task);
+ }
+ return err;
+}
+
+static int uvesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ struct uvesafb_pal_entry entry;
+ int shift = 16 - info->var.green.length;
+ int err = 0;
+
+ if (regno >= info->cmap.len)
+ return -EINVAL;
+
+ if (info->var.bits_per_pixel == 8) {
+ entry.red = red >> shift;
+ entry.green = green >> shift;
+ entry.blue = blue >> shift;
+ entry.pad = 0;
+
+ err = uvesafb_setpalette(&entry, 1, regno, info);
+ } else if (regno < 16) {
+ switch (info->var.bits_per_pixel) {
+ case 16:
+ if (info->var.red.offset == 10) {
+ /* 1:5:5:5 */
+ ((u32 *) (info->pseudo_palette))[regno] =
+ ((red & 0xf800) >> 1) |
+ ((green & 0xf800) >> 6) |
+ ((blue & 0xf800) >> 11);
+ } else {
+ /* 0:5:6:5 */
+ ((u32 *) (info->pseudo_palette))[regno] =
+ ((red & 0xf800) ) |
+ ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11);
+ }
+ break;
+
+ case 24:
+ case 32:
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ ((u32 *)(info->pseudo_palette))[regno] =
+ (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset);
+ break;
+ }
+ }
+ return err;
+}
+
+static int uvesafb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+{
+ struct uvesafb_pal_entry *entries;
+ int shift = 16 - info->var.green.length;
+ int i, err = 0;
+
+ if (info->var.bits_per_pixel == 8) {
+ if (cmap->start + cmap->len > info->cmap.start +
+ info->cmap.len || cmap->start < info->cmap.start)
+ return -EINVAL;
+
+ entries = kmalloc(sizeof(*entries) * cmap->len, GFP_KERNEL);
+ if (!entries)
+ return -ENOMEM;
+
+ for (i = 0; i < cmap->len; i++) {
+ entries[i].red = cmap->red[i] >> shift;
+ entries[i].green = cmap->green[i] >> shift;
+ entries[i].blue = cmap->blue[i] >> shift;
+ entries[i].pad = 0;
+ }
+ err = uvesafb_setpalette(entries, cmap->len, cmap->start, info);
+ kfree(entries);
+ } else {
+ /*
+ * For modes with bpp > 8, we only set the pseudo palette in
+ * the fb_info struct. We rely on uvesafb_setcolreg to do all
+ * sanity checking.
+ */
+ for (i = 0; i < cmap->len; i++) {
+ err |= uvesafb_setcolreg(cmap->start + i, cmap->red[i],
+ cmap->green[i], cmap->blue[i],
+ 0, info);
+ }
+ }
+ return err;
+}
+
+static int uvesafb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+#ifdef CONFIG_X86_32
+ int offset;
+ struct uvesafb_par *par = info->par;
+
+ offset = (var->yoffset * info->fix.line_length + var->xoffset) / 4;
+
+ /*
+ * It turns out it's not the best idea to do panning via vm86,
+ * so we only allow it if we have a PMI.
+ */
+ if (par->pmi_start) {
+ __asm__ __volatile__(
+ "call *(%%edi)"
+ : /* no return value */
+ : "a" (0x4f07), /* EAX */
+ "b" (0), /* EBX */
+ "c" (offset), /* ECX */
+ "d" (offset >> 16), /* EDX */
+ "D" (&par->pmi_start)); /* EDI */
+ }
+#endif
+ return 0;
+}
+
+static int uvesafb_blank(int blank, struct fb_info *info)
+{
+ struct uvesafb_ktask *task;
+ int err = 1;
+#ifdef CONFIG_X86
+ struct uvesafb_par *par = info->par;
+
+ if (par->vbe_ib.capabilities & VBE_CAP_VGACOMPAT) {
+ int loop = 10000;
+ u8 seq = 0, crtc17 = 0;
+
+ if (blank == FB_BLANK_POWERDOWN) {
+ seq = 0x20;
+ crtc17 = 0x00;
+ err = 0;
+ } else {
+ seq = 0x00;
+ crtc17 = 0x80;
+ err = (blank == FB_BLANK_UNBLANK) ? 0 : -EINVAL;
+ }
+
+ vga_wseq(NULL, 0x00, 0x01);
+ seq |= vga_rseq(NULL, 0x01) & ~0x20;
+ vga_wseq(NULL, 0x00, seq);
+
+ crtc17 |= vga_rcrt(NULL, 0x17) & ~0x80;
+ while (loop--);
+ vga_wcrt(NULL, 0x17, crtc17);
+ vga_wseq(NULL, 0x00, 0x03);
+ } else
+#endif /* CONFIG_X86 */
+ {
+ task = uvesafb_prep();
+ if (!task)
+ return -ENOMEM;
+
+ task->t.regs.eax = 0x4f10;
+ switch (blank) {
+ case FB_BLANK_UNBLANK:
+ task->t.regs.ebx = 0x0001;
+ break;
+ case FB_BLANK_NORMAL:
+ task->t.regs.ebx = 0x0101; /* standby */
+ break;
+ case FB_BLANK_POWERDOWN:
+ task->t.regs.ebx = 0x0401; /* powerdown */
+ break;
+ default:
+ goto out;
+ }
+
+ err = uvesafb_exec(task);
+ if (err || (task->t.regs.eax & 0xffff) != 0x004f)
+ err = 1;
+out: uvesafb_free(task);
+ }
+ return err;
+}
+
+static int uvesafb_open(struct fb_info *info, int user)
+{
+ struct uvesafb_par *par = info->par;
+ int cnt = atomic_read(&par->ref_count);
+
+ if (!cnt && par->vbe_state_size)
+ par->vbe_state_orig = uvesafb_vbe_state_save(par);
+
+ atomic_inc(&par->ref_count);
+ return 0;
+}
+
+static int uvesafb_release(struct fb_info *info, int user)
+{
+ struct uvesafb_ktask *task = NULL;
+ struct uvesafb_par *par = info->par;
+ int cnt = atomic_read(&par->ref_count);
+
+ if (!cnt)
+ return -EINVAL;
+
+ if (cnt != 1)
+ goto out;
+
+ task = uvesafb_prep();
+ if (!task)
+ goto out;
+
+ /* First, try to set the standard 80x25 text mode. */
+ task->t.regs.eax = 0x0003;
+ uvesafb_exec(task);
+
+ /*
+ * Now try to restore whatever hardware state we might have
+ * saved when the fb device was first opened.
+ */
+ uvesafb_vbe_state_restore(par, par->vbe_state_orig);
+out:
+ atomic_dec(&par->ref_count);
+ if (task)
+ uvesafb_free(task);
+ return 0;
+}
+
+static int uvesafb_set_par(struct fb_info *info)
+{
+ struct uvesafb_par *par = info->par;
+ struct uvesafb_ktask *task = NULL;
+ struct vbe_crtc_ib *crtc = NULL;
+ struct vbe_mode_ib *mode = NULL;
+ int i, err = 0, depth = info->var.bits_per_pixel;
+
+ if (depth > 8 && depth != 32)
+ depth = info->var.red.length + info->var.green.length +
+ info->var.blue.length;
+
+ i = uvesafb_vbe_find_mode(par, info->var.xres, info->var.yres, depth,
+ UVESAFB_EXACT_RES | UVESAFB_EXACT_DEPTH);
+ if (i >= 0)
+ mode = &par->vbe_modes[i];
+ else
+ return -EINVAL;
+
+ task = uvesafb_prep();
+ if (!task)
+ return -ENOMEM;
+setmode:
+ task->t.regs.eax = 0x4f02;
+ task->t.regs.ebx = mode->mode_id | 0x4000; /* use LFB */
+
+ if (par->vbe_ib.vbe_version >= 0x0300 && !par->nocrtc &&
+ info->var.pixclock != 0) {
+ task->t.regs.ebx |= 0x0800; /* use CRTC data */
+ task->t.flags = TF_BUF_ESDI;
+ crtc = kzalloc(sizeof(struct vbe_crtc_ib), GFP_KERNEL);
+ if (!crtc) {
+ err = -ENOMEM;
+ goto out;
+ }
+ crtc->horiz_start = info->var.xres + info->var.right_margin;
+ crtc->horiz_end = crtc->horiz_start + info->var.hsync_len;
+ crtc->horiz_total = crtc->horiz_end + info->var.left_margin;
+
+ crtc->vert_start = info->var.yres + info->var.lower_margin;
+ crtc->vert_end = crtc->vert_start + info->var.vsync_len;
+ crtc->vert_total = crtc->vert_end + info->var.upper_margin;
+
+ crtc->pixel_clock = PICOS2KHZ(info->var.pixclock) * 1000;
+ crtc->refresh_rate = (u16)(100 * (crtc->pixel_clock /
+ (crtc->vert_total * crtc->horiz_total)));
+
+ if (info->var.vmode & FB_VMODE_DOUBLE)
+ crtc->flags |= 0x1;
+ if (info->var.vmode & FB_VMODE_INTERLACED)
+ crtc->flags |= 0x2;
+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+ crtc->flags |= 0x4;
+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+ crtc->flags |= 0x8;
+ memcpy(&par->crtc, crtc, sizeof(*crtc));
+ } else {
+ memset(&par->crtc, 0, sizeof(*crtc));
+ }
+
+ task->t.buf_len = sizeof(struct vbe_crtc_ib);
+ task->buf = &par->crtc;
+
+ err = uvesafb_exec(task);
+ if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
+ /*
+ * The mode switch might have failed because we tried to
+ * use our own timings. Try again with the default timings.
+ */
+ if (crtc != NULL) {
+ printk(KERN_WARNING "uvesafb: mode switch failed "
+ "(eax=0x%x, err=%d). Trying again with "
+ "default timings.\n", task->t.regs.eax, err);
+ uvesafb_reset(task);
+ kfree(crtc);
+ crtc = NULL;
+ info->var.pixclock = 0;
+ goto setmode;
+ } else {
+ printk(KERN_ERR "uvesafb: mode switch failed (eax="
+ "0x%x, err=%d)\n", task->t.regs.eax, err);
+ err = -EINVAL;
+ goto out;
+ }
+ }
+ par->mode_idx = i;
+
+ /* For 8bpp modes, always try to set the DAC to 8 bits. */
+ if (par->vbe_ib.capabilities & VBE_CAP_CAN_SWITCH_DAC &&
+ mode->bits_per_pixel <= 8) {
+ uvesafb_reset(task);
+ task->t.regs.eax = 0x4f08;
+ task->t.regs.ebx = 0x0800;
+
+ err = uvesafb_exec(task);
+ if (err || (task->t.regs.eax & 0xffff) != 0x004f ||
+ ((task->t.regs.ebx & 0xff00) >> 8) != 8) {
+ /*
+ * We've failed to set the DAC palette format -
+ * time to correct var.
+ */
+ info->var.red.length = 6;
+ info->var.green.length = 6;
+ info->var.blue.length = 6;
+ }
+ }
+
+ info->fix.visual = (info->var.bits_per_pixel == 8) ?
+ FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+ info->fix.line_length = mode->bytes_per_scan_line;
+
+out: if (crtc != NULL)
+ kfree(crtc);
+ uvesafb_free(task);
+
+ return err;
+}
+
+static void uvesafb_check_limits(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ const struct fb_videomode *mode;
+ struct uvesafb_par *par = info->par;
+
+ /*
+ * If pixclock is set to 0, then we're using default BIOS timings
+ * and thus don't have to perform any checks here.
+ */
+ if (!var->pixclock)
+ return;
+
+ if (par->vbe_ib.vbe_version < 0x0300) {
+ fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON, 60, var, info);
+ return;
+ }
+
+ if (!fb_validate_mode(var, info))
+ return;
+
+ mode = fb_find_best_mode(var, &info->modelist);
+ if (mode) {
+ if (mode->xres == var->xres && mode->yres == var->yres &&
+ !(mode->vmode & (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE))) {
+ fb_videomode_to_var(var, mode);
+ return;
+ }
+ }
+
+ if (info->monspecs.gtf && !fb_get_mode(FB_MAXTIMINGS, 0, var, info))
+ return;
+ /* Use default refresh rate */
+ var->pixclock = 0;
+}
+
+static int uvesafb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct uvesafb_par *par = info->par;
+ struct vbe_mode_ib *mode = NULL;
+ int match = -1;
+ int depth = var->red.length + var->green.length + var->blue.length;
+
+ /*
+ * Various apps will use bits_per_pixel to set the color depth,
+ * which is theoretically incorrect, but which we'll try to handle
+ * here.
+ */
+ if (depth == 0 || abs(depth - var->bits_per_pixel) >= 8)
+ depth = var->bits_per_pixel;
+
+ match = uvesafb_vbe_find_mode(par, var->xres, var->yres, depth,
+ UVESAFB_EXACT_RES);
+ if (match == -1)
+ return -EINVAL;
+
+ mode = &par->vbe_modes[match];
+ uvesafb_setup_var(var, info, mode);
+
+ /*
+ * Check whether we have remapped enough memory for this mode.
+ * We might be called at an early stage, when we haven't remapped
+ * any memory yet, in which case we simply skip the check.
+ */
+ if (var->yres * mode->bytes_per_scan_line > info->fix.smem_len
+ && info->fix.smem_len)
+ return -EINVAL;
+
+ if ((var->vmode & FB_VMODE_DOUBLE) &&
+ !(par->vbe_modes[match].mode_attr & 0x100))
+ var->vmode &= ~FB_VMODE_DOUBLE;
+
+ if ((var->vmode & FB_VMODE_INTERLACED) &&
+ !(par->vbe_modes[match].mode_attr & 0x200))
+ var->vmode &= ~FB_VMODE_INTERLACED;
+
+ uvesafb_check_limits(var, info);
+
+ var->xres_virtual = var->xres;
+ var->yres_virtual = (par->ypan) ?
+ info->fix.smem_len / mode->bytes_per_scan_line :
+ var->yres;
+ return 0;
+}
+
+static void uvesafb_save_state(struct fb_info *info)
+{
+ struct uvesafb_par *par = info->par;
+
+ if (par->vbe_state_saved)
+ kfree(par->vbe_state_saved);
+
+ par->vbe_state_saved = uvesafb_vbe_state_save(par);
+}
+
+static void uvesafb_restore_state(struct fb_info *info)
+{
+ struct uvesafb_par *par = info->par;
+
+ uvesafb_vbe_state_restore(par, par->vbe_state_saved);
+}
+
+static struct fb_ops uvesafb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = uvesafb_open,
+ .fb_release = uvesafb_release,
+ .fb_setcolreg = uvesafb_setcolreg,
+ .fb_setcmap = uvesafb_setcmap,
+ .fb_pan_display = uvesafb_pan_display,
+ .fb_blank = uvesafb_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_check_var = uvesafb_check_var,
+ .fb_set_par = uvesafb_set_par,
+ .fb_save_state = uvesafb_save_state,
+ .fb_restore_state = uvesafb_restore_state,
+};
+
+static void __devinit uvesafb_init_info(struct fb_info *info,
+ struct vbe_mode_ib *mode)
+{
+ unsigned int size_vmode;
+ unsigned int size_remap;
+ unsigned int size_total;
+ struct uvesafb_par *par = info->par;
+ int i, h;
+
+ info->pseudo_palette = ((u8 *)info->par + sizeof(struct uvesafb_par));
+ info->fix = uvesafb_fix;
+ info->fix.ypanstep = par->ypan ? 1 : 0;
+ info->fix.ywrapstep = (par->ypan > 1) ? 1 : 0;
+
+ /*
+ * If we were unable to get the state buffer size, disable
+ * functions for saving and restoring the hardware state.
+ */
+ if (par->vbe_state_size == 0) {
+ info->fbops->fb_save_state = NULL;
+ info->fbops->fb_restore_state = NULL;
+ }
+
+ /* Disable blanking if the user requested so. */
+ if (!blank)
+ info->fbops->fb_blank = NULL;
+
+ /*
+ * Find out how much IO memory is required for the mode with
+ * the highest resolution.
+ */
+ size_remap = 0;
+ for (i = 0; i < par->vbe_modes_cnt; i++) {
+ h = par->vbe_modes[i].bytes_per_scan_line *
+ par->vbe_modes[i].y_res;
+ if (h > size_remap)
+ size_remap = h;
+ }
+ size_remap *= 2;
+
+ /*
+ * size_vmode -- that is the amount of memory needed for the
+ * used video mode, i.e. the minimum amount of
+ * memory we need.
+ */
+ if (mode != NULL) {
+ size_vmode = info->var.yres * mode->bytes_per_scan_line;
+ } else {
+ size_vmode = info->var.yres * info->var.xres *
+ ((info->var.bits_per_pixel + 7) >> 3);
+ }
+
+ /*
+ * size_total -- all video memory we have. Used for mtrr
+ * entries, resource allocation and bounds
+ * checking.
+ */
+ size_total = par->vbe_ib.total_memory * 65536;
+ if (vram_total)
+ size_total = vram_total * 1024 * 1024;
+ if (size_total < size_vmode)
+ size_total = size_vmode;
+
+ /*
+ * size_remap -- the amount of video memory we are going to
+ * use for vesafb. With modern cards it is no
+ * option to simply use size_total as th
+ * wastes plenty of kernel address space.
+ */
+ if (vram_remap)
+ size_remap = vram_remap * 1024 * 1024;
+ if (size_remap < size_vmode)
+ size_remap = size_vmode;
+ if (size_remap > size_total)
+ size_remap = size_total;
+
+ info->fix.smem_len = size_remap;
+ info->fix.smem_start = mode->phys_base_ptr;
+
+ /*
+ * We have to set yres_virtual here because when setup_var() was
+ * called, smem_len wasn't defined yet.
+ */
+ info->var.yres_virtual = info->fix.smem_len /
+ mode->bytes_per_scan_line;
+
+ if (par->ypan && info->var.yres_virtual > info->var.yres) {
+ printk(KERN_INFO "uvesafb: scrolling: %s "
+ "using protected mode interface, "
+ "yres_virtual=%d\n",
+ (par->ypan > 1) ? "ywrap" : "ypan",
+ info->var.yres_virtual);
+ } else {
+ printk(KERN_INFO "uvesafb: scrolling: redraw\n");
+ info->var.yres_virtual = info->var.yres;
+ par->ypan = 0;
+ }
+
+ info->flags = FBINFO_FLAG_DEFAULT |
+ (par->ypan) ? FBINFO_HWACCEL_YPAN : 0;
+
+ if (!par->ypan)
+ info->fbops->fb_pan_display = NULL;
+}
+
+static void uvesafb_init_mtrr(struct fb_info *info)
+{
+#ifdef CONFIG_MTRR
+ if (mtrr && !(info->fix.smem_start & (PAGE_SIZE - 1))) {
+ int temp_size = info->fix.smem_len;
+ unsigned int type = 0;
+
+ switch (mtrr) {
+ case 1:
+ type = MTRR_TYPE_UNCACHABLE;
+ break;
+ case 2:
+ type = MTRR_TYPE_WRBACK;
+ break;
+ case 3:
+ type = MTRR_TYPE_WRCOMB;
+ break;
+ case 4:
+ type = MTRR_TYPE_WRTHROUGH;
+ break;
+ default:
+ type = 0;
+ break;
+ }
+
+ if (type) {
+ int rc;
+
+ /* Find the largest power-of-two */
+ while (temp_size & (temp_size - 1))
+ temp_size &= (temp_size - 1);
+
+ /* Try and find a power of two to add */
+ do {
+ rc = mtrr_add(info->fix.smem_start,
+ temp_size, type, 1);
+ temp_size >>= 1;
+ } while (temp_size >= PAGE_SIZE && rc == -EINVAL);
+ }
+ }
+#endif /* CONFIG_MTRR */
+}
+
+
+static ssize_t uvesafb_show_vbe_ver(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+ struct uvesafb_par *par = info->par;
+
+ return snprintf(buf, PAGE_SIZE, "%.4x\n", par->vbe_ib.vbe_version);
+}
+
+static DEVICE_ATTR(vbe_version, S_IRUGO, uvesafb_show_vbe_ver, NULL);
+
+static ssize_t uvesafb_show_vbe_modes(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+ struct uvesafb_par *par = info->par;
+ int ret = 0, i;
+
+ for (i = 0; i < par->vbe_modes_cnt && ret < PAGE_SIZE; i++) {
+ ret += snprintf(buf + ret, PAGE_SIZE - ret,
+ "%dx%d-%d, 0x%.4x\n",
+ par->vbe_modes[i].x_res, par->vbe_modes[i].y_res,
+ par->vbe_modes[i].depth, par->vbe_modes[i].mode_id);
+ }
+
+ return ret;
+}
+
+static DEVICE_ATTR(vbe_modes, S_IRUGO, uvesafb_show_vbe_modes, NULL);
+
+static ssize_t uvesafb_show_vendor(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+ struct uvesafb_par *par = info->par;
+
+ if (par->vbe_ib.oem_vendor_name_ptr)
+ return snprintf(buf, PAGE_SIZE, "%s\n", (char *)
+ (&par->vbe_ib) + par->vbe_ib.oem_vendor_name_ptr);
+ else
+ return 0;
+}
+
+static DEVICE_ATTR(oem_vendor, S_IRUGO, uvesafb_show_vendor, NULL);
+
+static ssize_t uvesafb_show_product_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+ struct uvesafb_par *par = info->par;
+
+ if (par->vbe_ib.oem_product_name_ptr)
+ return snprintf(buf, PAGE_SIZE, "%s\n", (char *)
+ (&par->vbe_ib) + par->vbe_ib.oem_product_name_ptr);
+ else
+ return 0;
+}
+
+static DEVICE_ATTR(oem_product_name, S_IRUGO, uvesafb_show_product_name, NULL);
+
+static ssize_t uvesafb_show_product_rev(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+ struct uvesafb_par *par = info->par;
+
+ if (par->vbe_ib.oem_product_rev_ptr)
+ return snprintf(buf, PAGE_SIZE, "%s\n", (char *)
+ (&par->vbe_ib) + par->vbe_ib.oem_product_rev_ptr);
+ else
+ return 0;
+}
+
+static DEVICE_ATTR(oem_product_rev, S_IRUGO, uvesafb_show_product_rev, NULL);
+
+static ssize_t uvesafb_show_oem_string(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+ struct uvesafb_par *par = info->par;
+
+ if (par->vbe_ib.oem_string_ptr)
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ (char *)(&par->vbe_ib) + par->vbe_ib.oem_string_ptr);
+ else
+ return 0;
+}
+
+static DEVICE_ATTR(oem_string, S_IRUGO, uvesafb_show_oem_string, NULL);
+
+static ssize_t uvesafb_show_nocrtc(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+ struct uvesafb_par *par = info->par;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", par->nocrtc);
+}
+
+static ssize_t uvesafb_store_nocrtc(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct fb_info *info = platform_get_drvdata(to_platform_device(dev));
+ struct uvesafb_par *par = info->par;
+
+ if (count > 0) {
+ if (buf[0] == '0')
+ par->nocrtc = 0;
+ else
+ par->nocrtc = 1;
+ }
+ return count;
+}
+
+static DEVICE_ATTR(nocrtc, S_IRUGO | S_IWUSR, uvesafb_show_nocrtc,
+ uvesafb_store_nocrtc);
+
+static struct attribute *uvesafb_dev_attrs[] = {
+ &dev_attr_vbe_version.attr,
+ &dev_attr_vbe_modes.attr,
+ &dev_attr_oem_vendor.attr,
+ &dev_attr_oem_product_name.attr,
+ &dev_attr_oem_product_rev.attr,
+ &dev_attr_oem_string.attr,
+ &dev_attr_nocrtc.attr,
+ NULL,
+};
+
+static struct attribute_group uvesafb_dev_attgrp = {
+ .name = NULL,
+ .attrs = uvesafb_dev_attrs,
+};
+
+static int __devinit uvesafb_probe(struct platform_device *dev)
+{
+ struct fb_info *info;
+ struct vbe_mode_ib *mode = NULL;
+ struct uvesafb_par *par;
+ int err = 0, i;
+
+ info = framebuffer_alloc(sizeof(*par) + sizeof(u32) * 256, &dev->dev);
+ if (!info)
+ return -ENOMEM;
+
+ par = info->par;
+
+ err = uvesafb_vbe_init(info);
+ if (err) {
+ printk(KERN_ERR "uvesafb: vbe_init() failed with %d\n", err);
+ goto out;
+ }
+
+ info->fbops = &uvesafb_ops;
+
+ i = uvesafb_vbe_init_mode(info);
+ if (i < 0) {
+ err = -EINVAL;
+ goto out;
+ } else {
+ mode = &par->vbe_modes[i];
+ }
+
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+ err = -ENXIO;
+ goto out;
+ }
+
+ uvesafb_init_info(info, mode);
+
+ if (!request_mem_region(info->fix.smem_start, info->fix.smem_len,
+ "uvesafb")) {
+ printk(KERN_ERR "uvesafb: cannot reserve video memory at "
+ "0x%lx\n", info->fix.smem_start);
+ err = -EIO;
+ goto out_mode;
+ }
+
+ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+
+ if (!info->screen_base) {
+ printk(KERN_ERR
+ "uvesafb: abort, cannot ioremap 0x%x bytes of video "
+ "memory at 0x%lx\n",
+ info->fix.smem_len, info->fix.smem_start);
+ err = -EIO;
+ goto out_mem;
+ }
+
+ if (!request_region(0x3c0, 32, "uvesafb")) {
+ printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n");
+ err = -EIO;
+ goto out_unmap;
+ }
+
+ uvesafb_init_mtrr(info);
+ platform_set_drvdata(dev, info);
+
+ if (register_framebuffer(info) < 0) {
+ printk(KERN_ERR
+ "uvesafb: failed to register framebuffer device\n");
+ err = -EINVAL;
+ goto out_reg;
+ }
+
+ printk(KERN_INFO "uvesafb: framebuffer at 0x%lx, mapped to 0x%p, "
+ "using %dk, total %dk\n", info->fix.smem_start,
+ info->screen_base, info->fix.smem_len/1024,
+ par->vbe_ib.total_memory * 64);
+ printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+ info->fix.id);
+
+ err = sysfs_create_group(&dev->dev.kobj, &uvesafb_dev_attgrp);
+ if (err != 0)
+ printk(KERN_WARNING "fb%d: failed to register attributes\n",
+ info->node);
+
+ return 0;
+
+out_reg:
+ release_region(0x3c0, 32);
+out_unmap:
+ iounmap(info->screen_base);
+out_mem:
+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
+out_mode:
+ if (!list_empty(&info->modelist))
+ fb_destroy_modelist(&info->modelist);
+ fb_destroy_modedb(info->monspecs.modedb);
+ fb_dealloc_cmap(&info->cmap);
+out:
+ if (par->vbe_modes)
+ kfree(par->vbe_modes);
+
+ framebuffer_release(info);
+ return err;
+}
+
+static int uvesafb_remove(struct platform_device *dev)
+{
+ struct fb_info *info = platform_get_drvdata(dev);
+
+ if (info) {
+ struct uvesafb_par *par = info->par;
+
+ sysfs_remove_group(&dev->dev.kobj, &uvesafb_dev_attgrp);
+ unregister_framebuffer(info);
+ release_region(0x3c0, 32);
+ iounmap(info->screen_base);
+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
+ fb_destroy_modedb(info->monspecs.modedb);
+ fb_dealloc_cmap(&info->cmap);
+
+ if (par) {
+ if (par->vbe_modes)
+ kfree(par->vbe_modes);
+ if (par->vbe_state_orig)
+ kfree(par->vbe_state_orig);
+ if (par->vbe_state_saved)
+ kfree(par->vbe_state_saved);
+ }
+
+ framebuffer_release(info);
+ }
+ return 0;
+}
+
+static struct platform_driver uvesafb_driver = {
+ .probe = uvesafb_probe,
+ .remove = uvesafb_remove,
+ .driver = {
+ .name = "uvesafb",
+ },
+};
+
+static struct platform_device *uvesafb_device;
+
+#ifndef MODULE
+static int __devinit uvesafb_setup(char *options)
+{
+ char *this_opt;
+
+ if (!options || !*options)
+ return 0;
+
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ if (!*this_opt) continue;
+
+ if (!strcmp(this_opt, "redraw"))
+ ypan = 0;
+ else if (!strcmp(this_opt, "ypan"))
+ ypan = 1;
+ else if (!strcmp(this_opt, "ywrap"))
+ ypan = 2;
+ else if (!strcmp(this_opt, "vgapal"))
+ pmi_setpal = 0;
+ else if (!strcmp(this_opt, "pmipal"))
+ pmi_setpal = 1;
+ else if (!strncmp(this_opt, "mtrr:", 5))
+ mtrr = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strcmp(this_opt, "nomtrr"))
+ mtrr = 0;
+ else if (!strcmp(this_opt, "nocrtc"))
+ nocrtc = 1;
+ else if (!strcmp(this_opt, "noedid"))
+ noedid = 1;
+ else if (!strcmp(this_opt, "noblank"))
+ blank = 0;
+ else if (!strncmp(this_opt, "vtotal:", 7))
+ vram_total = simple_strtoul(this_opt + 7, NULL, 0);
+ else if (!strncmp(this_opt, "vremap:", 7))
+ vram_remap = simple_strtoul(this_opt + 7, NULL, 0);
+ else if (!strncmp(this_opt, "maxhf:", 6))
+ maxhf = simple_strtoul(this_opt + 6, NULL, 0);
+ else if (!strncmp(this_opt, "maxvf:", 6))
+ maxvf = simple_strtoul(this_opt + 6, NULL, 0);
+ else if (!strncmp(this_opt, "maxclk:", 7))
+ maxclk = simple_strtoul(this_opt + 7, NULL, 0);
+ else if (!strncmp(this_opt, "vbemode:", 8))
+ vbemode = simple_strtoul(this_opt + 8, NULL, 0);
+ else if (this_opt[0] >= '0' && this_opt[0] <= '9') {
+ mode_option = this_opt;
+ } else {
+ printk(KERN_WARNING
+ "uvesafb: unrecognized option %s\n", this_opt);
+ }
+ }
+
+ return 0;
+}
+#endif /* !MODULE */
+
+static ssize_t show_v86d(struct device_driver *dev, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", v86d_path);
+}
+
+static ssize_t store_v86d(struct device_driver *dev, const char *buf,
+ size_t count)
+{
+ strncpy(v86d_path, buf, PATH_MAX);
+ return count;
+}
+
+static DRIVER_ATTR(v86d, S_IRUGO | S_IWUSR, show_v86d, store_v86d);
+
+static int __devinit uvesafb_init(void)
+{
+ int err;
+
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("uvesafb", &option))
+ return -ENODEV;
+ uvesafb_setup(option);
+#endif
+ err = cn_add_callback(&uvesafb_cn_id, "uvesafb", uvesafb_cn_callback);
+ if (err)
+ return err;
+
+ err = platform_driver_register(&uvesafb_driver);
+
+ if (!err) {
+ uvesafb_device = platform_device_alloc("uvesafb", 0);
+ if (uvesafb_device)
+ err = platform_device_add(uvesafb_device);
+ else
+ err = -ENOMEM;
+
+ if (err) {
+ platform_device_put(uvesafb_device);
+ platform_driver_unregister(&uvesafb_driver);
+ cn_del_callback(&uvesafb_cn_id);
+ return err;
+ }
+
+ err = driver_create_file(&uvesafb_driver.driver,
+ &driver_attr_v86d);
+ if (err) {
+ printk(KERN_WARNING "uvesafb: failed to register "
+ "attributes\n");
+ err = 0;
+ }
+ }
+ return err;
+}
+
+module_init(uvesafb_init);
+
+static void __devexit uvesafb_exit(void)
+{
+ struct uvesafb_ktask *task;
+
+ if (v86d_started) {
+ task = uvesafb_prep();
+ if (task) {
+ task->t.flags = TF_EXIT;
+ uvesafb_exec(task);
+ uvesafb_free(task);
+ }
+ }
+
+ cn_del_callback(&uvesafb_cn_id);
+ driver_remove_file(&uvesafb_driver.driver, &driver_attr_v86d);
+ platform_device_unregister(uvesafb_device);
+ platform_driver_unregister(&uvesafb_driver);
+}
+
+module_exit(uvesafb_exit);
+
+static inline int param_get_scroll(char *buffer, struct kernel_param *kp)
+{
+ return 0;
+}
+
+static inline int param_set_scroll(const char *val, struct kernel_param *kp)
+{
+ ypan = 0;
+
+ if (!strcmp(val, "redraw"))
+ ypan = 0;
+ else if (!strcmp(val, "ypan"))
+ ypan = 1;
+ else if (!strcmp(val, "ywrap"))
+ ypan = 2;
+
+ return 0;
+}
+
+#define param_check_scroll(name, p) __param_check(name, p, void);
+
+module_param_named(scroll, ypan, scroll, 0);
+MODULE_PARM_DESC(scroll,
+ "Scrolling mode, set to 'redraw', ''ypan' or 'ywrap'");
+module_param_named(vgapal, pmi_setpal, invbool, 0);
+MODULE_PARM_DESC(vgapal, "Set palette using VGA registers");
+module_param_named(pmipal, pmi_setpal, bool, 0);
+MODULE_PARM_DESC(pmipal, "Set palette using PMI calls");
+module_param(mtrr, uint, 0);
+MODULE_PARM_DESC(mtrr,
+ "Memory Type Range Registers setting. Use 0 to disable.");
+module_param(blank, bool, 0);
+MODULE_PARM_DESC(blank, "Enable hardware blanking");
+module_param(nocrtc, bool, 0);
+MODULE_PARM_DESC(nocrtc, "Ignore CRTC timings when setting modes");
+module_param(noedid, bool, 0);
+MODULE_PARM_DESC(noedid,
+ "Ignore EDID-provided monitor limits when setting modes");
+module_param(vram_remap, uint, 0);
+MODULE_PARM_DESC(vram_remap, "Set amount of video memory to be used [MiB]");
+module_param(vram_total, uint, 0);
+MODULE_PARM_DESC(vram_total, "Set total amount of video memoery [MiB]");
+module_param(maxclk, ushort, 0);
+MODULE_PARM_DESC(maxclk, "Maximum pixelclock [MHz], overrides EDID data");
+module_param(maxhf, ushort, 0);
+MODULE_PARM_DESC(maxhf,
+ "Maximum horizontal frequency [kHz], overrides EDID data");
+module_param(maxvf, ushort, 0);
+MODULE_PARM_DESC(maxvf,
+ "Maximum vertical frequency [Hz], overrides EDID data");
+module_param_named(mode, mode_option, charp, 0);
+MODULE_PARM_DESC(mode,
+ "Specify initial video mode as \"<xres>x<yres>[-<bpp>][@<refresh>]\"");
+module_param(vbemode, ushort, 0);
+MODULE_PARM_DESC(vbemode,
+ "VBE mode number to set, overrides the 'mode' option");
+module_param_string(v86d, v86d_path, PATH_MAX, 0660);
+MODULE_PARM_DESC(v86d, "Path to the v86d userspace helper.");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal Januszewski <spock@gentoo.org>");
+MODULE_DESCRIPTION("Framebuffer driver for VBE2.0+ compliant graphics boards");
+
diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c
index de531c90771..c31f549ebea 100644
--- a/drivers/video/vermilion/vermilion.c
+++ b/drivers/video/vermilion/vermilion.c
@@ -23,8 +23,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
- * Michel Dänzer <michel-at-tungstengraphics-dot-com>
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ * Michel Dänzer <michel-at-tungstengraphics-dot-com>
* Alan Hourihane <alanh-at-tungstengraphics-dot-com>
*/
@@ -39,7 +39,6 @@
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <linux/mmzone.h>
-#include <asm/uaccess.h>
/* #define VERMILION_DEBUG */
diff --git a/drivers/video/vermilion/vermilion.h b/drivers/video/vermilion/vermilion.h
index 1fc6695a49d..c4aba59d480 100644
--- a/drivers/video/vermilion/vermilion.h
+++ b/drivers/video/vermilion/vermilion.h
@@ -23,7 +23,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#ifndef _VERMILION_H_
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 64ee78c3c12..072638a9528 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -21,7 +21,6 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <asm/uaccess.h>
#include <linux/fb.h>
#include <linux/init.h>
@@ -38,6 +37,48 @@ static void *videomemory;
static u_long videomemorysize = VIDEOMEMSIZE;
module_param(videomemorysize, ulong, 0);
+/**********************************************************************
+ *
+ * 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);
+}
+
static struct fb_var_screeninfo vfb_default __initdata = {
.xres = 640,
.yres = 480,
@@ -372,7 +413,33 @@ static int vfb_pan_display(struct fb_var_screeninfo *var,
static int vfb_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
- return -EINVAL;
+ unsigned long start = vma->vm_start;
+ unsigned long size = vma->vm_end - vma->vm_start;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long page, pos;
+
+ if (offset + size > info->fix.smem_len) {
+ return -EINVAL;
+ }
+
+ pos = (unsigned long)info->fix.smem_start + offset;
+
+ while (size > 0) {
+ page = vmalloc_to_pfn((void *)pos);
+ if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
+ return -EAGAIN;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+
+ vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+ return 0;
+
}
#ifndef MODULE
@@ -407,7 +474,7 @@ static int __init vfb_probe(struct platform_device *dev)
/*
* For real video cards we use ioremap.
*/
- if (!(videomemory = vmalloc(videomemorysize)))
+ if (!(videomemory = rvmalloc(videomemorysize)))
return retval;
/*
@@ -430,6 +497,8 @@ static int __init vfb_probe(struct platform_device *dev)
if (!retval || (retval == 4))
info->var = vfb_default;
+ vfb_fix.smem_start = (unsigned long) videomemory;
+ vfb_fix.smem_len = videomemorysize;
info->fix = vfb_fix;
info->pseudo_palette = info->par;
info->par = NULL;
@@ -453,7 +522,7 @@ err2:
err1:
framebuffer_release(info);
err:
- vfree(videomemory);
+ rvfree(videomemory, videomemorysize);
return retval;
}
@@ -463,7 +532,7 @@ static int vfb_remove(struct platform_device *dev)
if (info) {
unregister_framebuffer(info);
- vfree(videomemory);
+ rvfree(videomemory, videomemorysize);
framebuffer_release(info);
}
return 0;
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 2a14d28c416..9b3c5923365 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -1364,7 +1364,7 @@ static int __init vga16fb_probe(struct platform_device *dev)
par = info->par;
mutex_init(&par->open_lock);
- par->isVGA = ORIG_VIDEO_ISVGA;
+ par->isVGA = screen_info.orig_video_isVGA;
par->palette_blanked = 0;
par->vesa_blanked = 0;
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 6ef9733a18d..e38d3b7c3ad 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -6,9 +6,12 @@
* Author: MontaVista Software, Inc.
* source@mvista.com
*
- * 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the
- * terms of the GNU General Public License version 2. This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
+ * 2002-2007 (c) MontaVista Software, Inc.
+ * 2007 (c) Secret Lab Technologies, Ltd.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
*/
/*
@@ -18,6 +21,7 @@
* Geert Uytterhoeven.
*/
+#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
@@ -28,9 +32,12 @@
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
-
+#if defined(CONFIG_OF)
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#endif
#include <asm/io.h>
-#include <syslib/virtex_devices.h>
+#include <linux/xilinxfb.h>
#define DRIVER_NAME "xilinxfb"
#define DRIVER_DESCRIPTION "Xilinx TFT LCD frame buffer driver"
@@ -63,12 +70,6 @@
*/
#define BYTES_PER_PIXEL 4
#define BITS_PER_PIXEL (BYTES_PER_PIXEL * 8)
-#define XRES 640
-#define YRES 480
-#define XRES_VIRTUAL 1024
-#define YRES_VIRTUAL YRES
-#define LINE_LENGTH (XRES_VIRTUAL * BYTES_PER_PIXEL)
-#define FB_SIZE (YRES_VIRTUAL * LINE_LENGTH)
#define RED_SHIFT 16
#define GREEN_SHIFT 8
@@ -77,23 +78,26 @@
#define PALETTE_ENTRIES_NO 16 /* passed to fb_alloc_cmap() */
/*
+ * Default xilinxfb configuration
+ */
+static struct xilinxfb_platform_data xilinx_fb_default_pdata = {
+ .xres = 640,
+ .yres = 480,
+ .xvirt = 1024,
+ .yvirt = 480,
+};
+
+/*
* Here are the default fb_fix_screeninfo and fb_var_screeninfo structures
*/
static struct fb_fix_screeninfo xilinx_fb_fix = {
.id = "Xilinx",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
- .smem_len = FB_SIZE,
- .line_length = LINE_LENGTH,
.accel = FB_ACCEL_NONE
};
static struct fb_var_screeninfo xilinx_fb_var = {
- .xres = XRES,
- .yres = YRES,
- .xres_virtual = XRES_VIRTUAL,
- .yres_virtual = YRES_VIRTUAL,
-
.bits_per_pixel = BITS_PER_PIXEL,
.red = { RED_SHIFT, 8, 0 },
@@ -111,8 +115,9 @@ struct xilinxfb_drvdata {
u32 regs_phys; /* phys. address of the control registers */
u32 __iomem *regs; /* virt. address of the control registers */
- unsigned char __iomem *fb_virt; /* virt. address of the frame buffer */
+ void *fb_virt; /* virt. address of the frame buffer */
dma_addr_t fb_phys; /* phys. address of the frame buffer */
+ int fb_alloced; /* Flag, was the fb memory alloced? */
u32 reg_ctrl_default;
@@ -195,130 +200,136 @@ static struct fb_ops xilinxfb_ops =
.fb_imageblit = cfb_imageblit,
};
-/* === The device driver === */
+/* ---------------------------------------------------------------------
+ * Bus independent setup/teardown
+ */
-static int
-xilinxfb_drv_probe(struct device *dev)
+static int xilinxfb_assign(struct device *dev, unsigned long physaddr,
+ struct xilinxfb_platform_data *pdata)
{
- struct platform_device *pdev;
- struct xilinxfb_platform_data *pdata;
struct xilinxfb_drvdata *drvdata;
- struct resource *regs_res;
- int retval;
-
- if (!dev)
- return -EINVAL;
-
- pdev = to_platform_device(dev);
- pdata = pdev->dev.platform_data;
+ int rc;
+ int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL;
+ /* Allocate the driver data region */
drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
if (!drvdata) {
- printk(KERN_ERR "Couldn't allocate device private record\n");
+ dev_err(dev, "Couldn't allocate device private record\n");
return -ENOMEM;
}
dev_set_drvdata(dev, drvdata);
/* Map the control registers in */
- regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) {
- printk(KERN_ERR "Couldn't get registers resource\n");
- retval = -EFAULT;
- goto failed1;
+ if (!request_mem_region(physaddr, 8, DRIVER_NAME)) {
+ dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
+ physaddr);
+ rc = -ENODEV;
+ goto err_region;
}
-
- if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) {
- printk(KERN_ERR
- "Couldn't lock memory region at 0x%08X\n",
- regs_res->start);
- retval = -EBUSY;
- goto failed1;
+ drvdata->regs_phys = physaddr;
+ drvdata->regs = ioremap(physaddr, 8);
+ if (!drvdata->regs) {
+ dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
+ physaddr);
+ rc = -ENODEV;
+ goto err_map;
}
- drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8);
- drvdata->regs_phys = regs_res->start;
/* Allocate the framebuffer memory */
- drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE),
- &drvdata->fb_phys, GFP_KERNEL);
+ if (pdata->fb_phys) {
+ drvdata->fb_phys = pdata->fb_phys;
+ drvdata->fb_virt = ioremap(pdata->fb_phys, fbsize);
+ } else {
+ drvdata->fb_alloced = 1;
+ drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize),
+ &drvdata->fb_phys, GFP_KERNEL);
+ }
+
if (!drvdata->fb_virt) {
- printk(KERN_ERR "Could not allocate frame buffer memory\n");
- retval = -ENOMEM;
- goto failed2;
+ dev_err(dev, "Could not allocate frame buffer memory\n");
+ rc = -ENOMEM;
+ goto err_fbmem;
}
/* Clear (turn to black) the framebuffer */
- memset_io((void *) drvdata->fb_virt, 0, FB_SIZE);
+ memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize);
/* Tell the hardware where the frame buffer is */
xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
/* Turn on the display */
drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
- if (pdata && pdata->rotate_screen)
+ if (pdata->rotate_screen)
drvdata->reg_ctrl_default |= REG_CTRL_ROTATE;
xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
/* Fill struct fb_info */
drvdata->info.device = dev;
- drvdata->info.screen_base = drvdata->fb_virt;
+ drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt;
drvdata->info.fbops = &xilinxfb_ops;
drvdata->info.fix = xilinx_fb_fix;
drvdata->info.fix.smem_start = drvdata->fb_phys;
- drvdata->info.pseudo_palette = drvdata->pseudo_palette;
-
- if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) {
- printk(KERN_ERR "Fail to allocate colormap (%d entries)\n",
- PALETTE_ENTRIES_NO);
- retval = -EFAULT;
- goto failed3;
- }
+ drvdata->info.fix.smem_len = fbsize;
+ drvdata->info.fix.line_length = pdata->xvirt * BYTES_PER_PIXEL;
+ drvdata->info.pseudo_palette = drvdata->pseudo_palette;
drvdata->info.flags = FBINFO_DEFAULT;
- if (pdata) {
- xilinx_fb_var.height = pdata->screen_height_mm;
- xilinx_fb_var.width = pdata->screen_width_mm;
- }
drvdata->info.var = xilinx_fb_var;
+ drvdata->info.var.height = pdata->screen_height_mm;
+ drvdata->info.var.width = pdata->screen_width_mm;
+ drvdata->info.var.xres = pdata->xres;
+ drvdata->info.var.yres = pdata->yres;
+ drvdata->info.var.xres_virtual = pdata->xvirt;
+ drvdata->info.var.yres_virtual = pdata->yvirt;
+
+ /* Allocate a colour map */
+ rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0);
+ if (rc) {
+ dev_err(dev, "Fail to allocate colormap (%d entries)\n",
+ PALETTE_ENTRIES_NO);
+ goto err_cmap;
+ }
/* Register new frame buffer */
- if (register_framebuffer(&drvdata->info) < 0) {
- printk(KERN_ERR "Could not register frame buffer\n");
- retval = -EINVAL;
- goto failed4;
+ rc = register_framebuffer(&drvdata->info);
+ if (rc) {
+ dev_err(dev, "Could not register frame buffer\n");
+ goto err_regfb;
}
+ /* Put a banner in the log (for DEBUG) */
+ dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs);
+ dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n",
+ (void*)drvdata->fb_phys, drvdata->fb_virt, fbsize);
+
return 0; /* success */
-failed4:
+err_regfb:
fb_dealloc_cmap(&drvdata->info.cmap);
-failed3:
- dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt,
- drvdata->fb_phys);
-
+err_cmap:
+ if (drvdata->fb_alloced)
+ dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt,
+ drvdata->fb_phys);
/* Turn off the display */
xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
+
+err_fbmem:
iounmap(drvdata->regs);
-failed2:
- release_mem_region(regs_res->start, 8);
+err_map:
+ release_mem_region(physaddr, 8);
-failed1:
+err_region:
kfree(drvdata);
dev_set_drvdata(dev, NULL);
- return retval;
+ return rc;
}
-static int
-xilinxfb_drv_remove(struct device *dev)
+static int xilinxfb_release(struct device *dev)
{
- struct xilinxfb_drvdata *drvdata;
-
- if (!dev)
- return -ENODEV;
-
- drvdata = (struct xilinxfb_drvdata *) dev_get_drvdata(dev);
+ struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev);
#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info);
@@ -328,8 +339,9 @@ xilinxfb_drv_remove(struct device *dev)
fb_dealloc_cmap(&drvdata->info.cmap);
- dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt,
- drvdata->fb_phys);
+ if (drvdata->fb_alloced)
+ dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len),
+ drvdata->fb_virt, drvdata->fb_phys);
/* Turn off the display */
xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
@@ -343,29 +355,168 @@ xilinxfb_drv_remove(struct device *dev)
return 0;
}
+/* ---------------------------------------------------------------------
+ * Platform bus binding
+ */
+
+static int
+xilinxfb_platform_probe(struct platform_device *pdev)
+{
+ struct xilinxfb_platform_data *pdata;
+ struct resource *res;
-static struct device_driver xilinxfb_driver = {
- .name = DRIVER_NAME,
- .bus = &platform_bus_type,
+ /* Find the registers address */
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Couldn't get registers resource\n");
+ return -ENODEV;
+ }
- .probe = xilinxfb_drv_probe,
- .remove = xilinxfb_drv_remove
+ /* If a pdata structure is provided, then extract the parameters */
+ pdata = &xilinx_fb_default_pdata;
+ if (pdev->dev.platform_data) {
+ pdata = pdev->dev.platform_data;
+ if (!pdata->xres)
+ pdata->xres = xilinx_fb_default_pdata.xres;
+ if (!pdata->yres)
+ pdata->yres = xilinx_fb_default_pdata.yres;
+ if (!pdata->xvirt)
+ pdata->xvirt = xilinx_fb_default_pdata.xvirt;
+ if (!pdata->yvirt)
+ pdata->yvirt = xilinx_fb_default_pdata.yvirt;
+ }
+
+ return xilinxfb_assign(&pdev->dev, res->start, pdata);
+}
+
+static int
+xilinxfb_platform_remove(struct platform_device *pdev)
+{
+ return xilinxfb_release(&pdev->dev);
+}
+
+
+static struct platform_driver xilinxfb_platform_driver = {
+ .probe = xilinxfb_platform_probe,
+ .remove = xilinxfb_platform_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+};
+
+/* ---------------------------------------------------------------------
+ * OF bus binding
+ */
+
+#if defined(CONFIG_OF)
+static int __devinit
+xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct resource res;
+ const u32 *prop;
+ struct xilinxfb_platform_data pdata;
+ int size, rc;
+
+ /* Copy with the default pdata (not a ptr reference!) */
+ pdata = xilinx_fb_default_pdata;
+
+ dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match);
+
+ rc = of_address_to_resource(op->node, 0, &res);
+ if (rc) {
+ dev_err(&op->dev, "invalid address\n");
+ return rc;
+ }
+
+ prop = of_get_property(op->node, "phys-size", &size);
+ if ((prop) && (size >= sizeof(u32)*2)) {
+ pdata.screen_width_mm = prop[0];
+ pdata.screen_height_mm = prop[1];
+ }
+
+ prop = of_get_property(op->node, "resolution", &size);
+ if ((prop) && (size >= sizeof(u32)*2)) {
+ pdata.xres = prop[0];
+ pdata.yres = prop[1];
+ }
+
+ prop = of_get_property(op->node, "virtual-resolution", &size);
+ if ((prop) && (size >= sizeof(u32)*2)) {
+ pdata.xvirt = prop[0];
+ pdata.yvirt = prop[1];
+ }
+
+ if (of_find_property(op->node, "rotate-display", NULL))
+ pdata.rotate_screen = 1;
+
+ return xilinxfb_assign(&op->dev, res.start, &pdata);
+}
+
+static int __devexit xilinxfb_of_remove(struct of_device *op)
+{
+ return xilinxfb_release(&op->dev);
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id __devinit xilinxfb_of_match[] = {
+ { .compatible = "xilinx,ml300-fb", },
+ {},
};
+MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
+
+static struct of_platform_driver xilinxfb_of_driver = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .match_table = xilinxfb_of_match,
+ .probe = xilinxfb_of_probe,
+ .remove = __devexit_p(xilinxfb_of_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __init xilinxfb_of_register(void)
+{
+ pr_debug("xilinxfb: calling of_register_platform_driver()\n");
+ return of_register_platform_driver(&xilinxfb_of_driver);
+}
+
+static inline void __exit xilinxfb_of_unregister(void)
+{
+ of_unregister_platform_driver(&xilinxfb_of_driver);
+}
+#else /* CONFIG_OF */
+/* CONFIG_OF not enabled; do nothing helpers */
+static inline int __init xilinxfb_of_register(void) { return 0; }
+static inline void __exit xilinxfb_of_unregister(void) { }
+#endif /* CONFIG_OF */
+
+/* ---------------------------------------------------------------------
+ * Module setup and teardown
+ */
static int __init
xilinxfb_init(void)
{
- /*
- * No kernel boot options used,
- * so we just need to register the driver
- */
- return driver_register(&xilinxfb_driver);
+ int rc;
+ rc = xilinxfb_of_register();
+ if (rc)
+ return rc;
+
+ rc = platform_driver_register(&xilinxfb_platform_driver);
+ if (rc)
+ xilinxfb_of_unregister();
+
+ return rc;
}
static void __exit
xilinxfb_cleanup(void)
{
- driver_unregister(&xilinxfb_driver);
+ platform_driver_unregister(&xilinxfb_platform_driver);
+ xilinxfb_of_unregister();
}
module_init(xilinxfb_init);
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
new file mode 100644
index 00000000000..9e33fc4da87
--- /dev/null
+++ b/drivers/virtio/Kconfig
@@ -0,0 +1,8 @@
+# Virtio always gets selected by whoever wants it.
+config VIRTIO
+ bool
+
+# Similarly the virtio ring implementation.
+config VIRTIO_RING
+ bool
+ depends on VIRTIO
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
new file mode 100644
index 00000000000..f70e40971dd
--- /dev/null
+++ b/drivers/virtio/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VIRTIO) += virtio.o
+obj-$(CONFIG_VIRTIO_RING) += virtio_ring.o
diff --git a/drivers/virtio/config.c b/drivers/virtio/config.c
new file mode 100644
index 00000000000..983d482fba4
--- /dev/null
+++ b/drivers/virtio/config.c
@@ -0,0 +1,13 @@
+/* Configuration space parsing helpers for virtio.
+ *
+ * The configuration is [type][len][... len bytes ...] fields.
+ *
+ * Copyright 2007 Rusty Russell, IBM Corporation.
+ * GPL v2 or later.
+ */
+#include <linux/err.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/bug.h>
+#include <asm/system.h>
+
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
new file mode 100644
index 00000000000..15d7787dea8
--- /dev/null
+++ b/drivers/virtio/virtio.c
@@ -0,0 +1,189 @@
+#include <linux/virtio.h>
+#include <linux/spinlock.h>
+#include <linux/virtio_config.h>
+
+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);
+}
+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);
+}
+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));
+}
+static ssize_t modalias_show(struct device *_d,
+ struct device_attribute *attr, char *buf)
+{
+ struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+
+ return sprintf(buf, "virtio:d%08Xv%08X\n",
+ dev->id.device, dev->id.vendor);
+}
+static struct device_attribute virtio_dev_attrs[] = {
+ __ATTR_RO(device),
+ __ATTR_RO(vendor),
+ __ATTR_RO(status),
+ __ATTR_RO(modalias),
+ __ATTR_NULL
+};
+
+static inline int virtio_id_match(const struct virtio_device *dev,
+ const struct virtio_device_id *id)
+{
+ if (id->device != dev->id.device)
+ return 0;
+
+ return id->vendor == VIRTIO_DEV_ANY_ID || id->vendor != dev->id.vendor;
+}
+
+/* This looks through all the IDs a driver claims to support. If any of them
+ * match, we return 1 and the kernel will call virtio_dev_probe(). */
+static int virtio_dev_match(struct device *_dv, struct device_driver *_dr)
+{
+ unsigned int i;
+ struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
+ const struct virtio_device_id *ids;
+
+ ids = container_of(_dr, struct virtio_driver, driver)->id_table;
+ for (i = 0; ids[i].device; i++)
+ if (virtio_id_match(dev, &ids[i]))
+ return 1;
+ return 0;
+}
+
+static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env)
+{
+ struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
+
+ return add_uevent_var(env, "MODALIAS=virtio:d%08Xv%08X",
+ dev->id.device, dev->id.vendor);
+}
+
+static struct bus_type virtio_bus = {
+ .name = "virtio",
+ .match = virtio_dev_match,
+ .dev_attrs = virtio_dev_attrs,
+ .uevent = virtio_uevent,
+};
+
+static void add_status(struct virtio_device *dev, unsigned status)
+{
+ dev->config->set_status(dev, dev->config->get_status(dev) | status);
+}
+
+static int virtio_dev_probe(struct device *_d)
+{
+ int err;
+ struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
+ struct virtio_driver *drv = container_of(dev->dev.driver,
+ struct virtio_driver, driver);
+
+ add_status(dev, VIRTIO_CONFIG_S_DRIVER);
+ err = drv->probe(dev);
+ if (err)
+ add_status(dev, VIRTIO_CONFIG_S_FAILED);
+ else
+ add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
+ return err;
+}
+
+int register_virtio_driver(struct virtio_driver *driver)
+{
+ driver->driver.bus = &virtio_bus;
+ driver->driver.probe = virtio_dev_probe;
+ return driver_register(&driver->driver);
+}
+EXPORT_SYMBOL_GPL(register_virtio_driver);
+
+void unregister_virtio_driver(struct virtio_driver *driver)
+{
+ driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL_GPL(unregister_virtio_driver);
+
+int register_virtio_device(struct virtio_device *dev)
+{
+ int err;
+
+ dev->dev.bus = &virtio_bus;
+ sprintf(dev->dev.bus_id, "%u", dev->index);
+
+ /* Acknowledge that we've seen the device. */
+ add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
+
+ /* device_register() causes the bus infrastructure to look for a
+ * matching driver. */
+ err = device_register(&dev->dev);
+ if (err)
+ add_status(dev, VIRTIO_CONFIG_S_FAILED);
+ return err;
+}
+EXPORT_SYMBOL_GPL(register_virtio_device);
+
+void unregister_virtio_device(struct virtio_device *dev)
+{
+ device_unregister(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(unregister_virtio_device);
+
+int __virtio_config_val(struct virtio_device *vdev,
+ u8 type, void *val, size_t size)
+{
+ void *token;
+ unsigned int len;
+
+ token = vdev->config->find(vdev, type, &len);
+ if (!token)
+ return -ENOENT;
+
+ if (len != size)
+ return -EIO;
+
+ vdev->config->get(vdev, token, val, size);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__virtio_config_val);
+
+int virtio_use_bit(struct virtio_device *vdev,
+ void *token, unsigned int len, unsigned int bitnum)
+{
+ unsigned long bits[16];
+
+ /* This makes it convenient to pass-through find() results. */
+ if (!token)
+ return 0;
+
+ /* bit not in range of this bitfield? */
+ if (bitnum * 8 >= len / 2)
+ return 0;
+
+ /* Giant feature bitfields are silly. */
+ BUG_ON(len > sizeof(bits));
+ vdev->config->get(vdev, token, bits, len);
+
+ if (!test_bit(bitnum, bits))
+ return 0;
+
+ /* Set acknowledge bit, and write it back. */
+ set_bit(bitnum + len * 8 / 2, bits);
+ vdev->config->set(vdev, token, bits, len);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(virtio_use_bit);
+
+static int virtio_init(void)
+{
+ if (bus_register(&virtio_bus) != 0)
+ panic("virtio bus registration failed");
+ return 0;
+}
+core_initcall(virtio_init);
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
new file mode 100644
index 00000000000..1dc04b6684e
--- /dev/null
+++ b/drivers/virtio/virtio_ring.c
@@ -0,0 +1,319 @@
+/* Virtio ring implementation.
+ *
+ * Copyright 2007 Rusty Russell IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/virtio.h>
+#include <linux/virtio_ring.h>
+#include <linux/device.h>
+
+#ifdef DEBUG
+/* For development, we want to crash whenever the ring is screwed. */
+#define BAD_RING(vq, fmt...) \
+ do { dev_err(&vq->vq.vdev->dev, fmt); BUG(); } while(0)
+#define START_USE(vq) \
+ do { if ((vq)->in_use) panic("in_use = %i\n", (vq)->in_use); (vq)->in_use = __LINE__; mb(); } while(0)
+#define END_USE(vq) \
+ do { BUG_ON(!(vq)->in_use); (vq)->in_use = 0; mb(); } while(0)
+#else
+#define BAD_RING(vq, fmt...) \
+ do { dev_err(&vq->vq.vdev->dev, fmt); (vq)->broken = true; } while(0)
+#define START_USE(vq)
+#define END_USE(vq)
+#endif
+
+struct vring_virtqueue
+{
+ struct virtqueue vq;
+
+ /* Actual memory layout for this queue */
+ struct vring vring;
+
+ /* Other side has made a mess, don't try any more. */
+ bool broken;
+
+ /* Number of free buffers */
+ unsigned int num_free;
+ /* Head of free buffer list. */
+ unsigned int free_head;
+ /* Number we've added since last sync. */
+ unsigned int num_added;
+
+ /* Last used index we've seen. */
+ u16 last_used_idx;
+
+ /* How to notify other side. FIXME: commonalize hcalls! */
+ void (*notify)(struct virtqueue *vq);
+
+#ifdef DEBUG
+ /* They're supposed to lock for us. */
+ unsigned int in_use;
+#endif
+
+ /* Tokens for callbacks. */
+ void *data[];
+};
+
+#define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq)
+
+static int vring_add_buf(struct virtqueue *_vq,
+ struct scatterlist sg[],
+ unsigned int out,
+ unsigned int in,
+ void *data)
+{
+ struct vring_virtqueue *vq = to_vvq(_vq);
+ unsigned int i, avail, head, uninitialized_var(prev);
+
+ BUG_ON(data == NULL);
+ BUG_ON(out + in > vq->vring.num);
+ BUG_ON(out + in == 0);
+
+ START_USE(vq);
+
+ if (vq->num_free < out + in) {
+ pr_debug("Can't add buf len %i - avail = %i\n",
+ out + in, vq->num_free);
+ END_USE(vq);
+ return -ENOSPC;
+ }
+
+ /* We're about to use some buffers from the free list. */
+ vq->num_free -= out + in;
+
+ head = vq->free_head;
+ for (i = vq->free_head; out; i = vq->vring.desc[i].next, out--) {
+ vq->vring.desc[i].flags = VRING_DESC_F_NEXT;
+ vq->vring.desc[i].addr = (page_to_pfn(sg_page(sg))<<PAGE_SHIFT)
+ + sg->offset;
+ vq->vring.desc[i].len = sg->length;
+ prev = i;
+ sg++;
+ }
+ for (; in; i = vq->vring.desc[i].next, in--) {
+ vq->vring.desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
+ vq->vring.desc[i].addr = (page_to_pfn(sg_page(sg))<<PAGE_SHIFT)
+ + sg->offset;
+ vq->vring.desc[i].len = sg->length;
+ prev = i;
+ sg++;
+ }
+ /* Last one doesn't continue. */
+ vq->vring.desc[prev].flags &= ~VRING_DESC_F_NEXT;
+
+ /* Update free pointer */
+ vq->free_head = i;
+
+ /* Set token. */
+ vq->data[head] = data;
+
+ /* Put entry in available array (but don't update avail->idx until they
+ * do sync). FIXME: avoid modulus here? */
+ avail = (vq->vring.avail->idx + vq->num_added++) % vq->vring.num;
+ vq->vring.avail->ring[avail] = head;
+
+ pr_debug("Added buffer head %i to %p\n", head, vq);
+ END_USE(vq);
+ return 0;
+}
+
+static void vring_kick(struct virtqueue *_vq)
+{
+ struct vring_virtqueue *vq = to_vvq(_vq);
+ START_USE(vq);
+ /* Descriptors and available array need to be set before we expose the
+ * new available array entries. */
+ wmb();
+
+ vq->vring.avail->idx += vq->num_added;
+ vq->num_added = 0;
+
+ /* Need to update avail index before checking if we should notify */
+ mb();
+
+ if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
+ /* Prod other side to tell it about changes. */
+ vq->notify(&vq->vq);
+
+ END_USE(vq);
+}
+
+static void detach_buf(struct vring_virtqueue *vq, unsigned int head)
+{
+ unsigned int i;
+
+ /* Clear data ptr. */
+ vq->data[head] = NULL;
+
+ /* Put back on free list: find end */
+ i = head;
+ while (vq->vring.desc[i].flags & VRING_DESC_F_NEXT) {
+ i = vq->vring.desc[i].next;
+ vq->num_free++;
+ }
+
+ vq->vring.desc[i].next = vq->free_head;
+ vq->free_head = head;
+ /* Plus final descriptor */
+ vq->num_free++;
+}
+
+/* FIXME: We need to tell other side about removal, to synchronize. */
+static void vring_shutdown(struct virtqueue *_vq)
+{
+ struct vring_virtqueue *vq = to_vvq(_vq);
+ unsigned int i;
+
+ for (i = 0; i < vq->vring.num; i++)
+ detach_buf(vq, i);
+}
+
+static inline bool more_used(const struct vring_virtqueue *vq)
+{
+ return vq->last_used_idx != vq->vring.used->idx;
+}
+
+static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
+{
+ struct vring_virtqueue *vq = to_vvq(_vq);
+ void *ret;
+ unsigned int i;
+
+ START_USE(vq);
+
+ if (!more_used(vq)) {
+ pr_debug("No more buffers in queue\n");
+ END_USE(vq);
+ return NULL;
+ }
+
+ i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id;
+ *len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len;
+
+ if (unlikely(i >= vq->vring.num)) {
+ BAD_RING(vq, "id %u out of range\n", i);
+ return NULL;
+ }
+ if (unlikely(!vq->data[i])) {
+ BAD_RING(vq, "id %u is not a head!\n", i);
+ return NULL;
+ }
+
+ /* detach_buf clears data, so grab it now. */
+ ret = vq->data[i];
+ detach_buf(vq, i);
+ vq->last_used_idx++;
+ END_USE(vq);
+ return ret;
+}
+
+static bool vring_restart(struct virtqueue *_vq)
+{
+ struct vring_virtqueue *vq = to_vvq(_vq);
+
+ START_USE(vq);
+ BUG_ON(!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT));
+
+ /* We optimistically turn back on interrupts, then check if there was
+ * more to do. */
+ vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
+ mb();
+ if (unlikely(more_used(vq))) {
+ vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+ END_USE(vq);
+ return false;
+ }
+
+ END_USE(vq);
+ return true;
+}
+
+irqreturn_t vring_interrupt(int irq, void *_vq)
+{
+ struct vring_virtqueue *vq = to_vvq(_vq);
+
+ if (!more_used(vq)) {
+ pr_debug("virtqueue interrupt with no work for %p\n", vq);
+ return IRQ_NONE;
+ }
+
+ if (unlikely(vq->broken))
+ return IRQ_HANDLED;
+
+ pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback);
+ if (vq->vq.callback && !vq->vq.callback(&vq->vq))
+ vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+
+ return IRQ_HANDLED;
+}
+
+static struct virtqueue_ops vring_vq_ops = {
+ .add_buf = vring_add_buf,
+ .get_buf = vring_get_buf,
+ .kick = vring_kick,
+ .restart = vring_restart,
+ .shutdown = vring_shutdown,
+};
+
+struct virtqueue *vring_new_virtqueue(unsigned int num,
+ struct virtio_device *vdev,
+ void *pages,
+ void (*notify)(struct virtqueue *),
+ bool (*callback)(struct virtqueue *))
+{
+ struct vring_virtqueue *vq;
+ unsigned int i;
+
+ /* We assume num is a power of 2. */
+ if (num & (num - 1)) {
+ dev_warn(&vdev->dev, "Bad virtqueue length %u\n", num);
+ return NULL;
+ }
+
+ vq = kmalloc(sizeof(*vq) + sizeof(void *)*num, GFP_KERNEL);
+ if (!vq)
+ return NULL;
+
+ vring_init(&vq->vring, num, pages, PAGE_SIZE);
+ vq->vq.callback = callback;
+ vq->vq.vdev = vdev;
+ vq->vq.vq_ops = &vring_vq_ops;
+ vq->notify = notify;
+ vq->broken = false;
+ vq->last_used_idx = 0;
+ vq->num_added = 0;
+#ifdef DEBUG
+ vq->in_use = false;
+#endif
+
+ /* No callback? Tell other side not to bother us. */
+ if (!callback)
+ vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+
+ /* Put everything in free lists. */
+ vq->num_free = num;
+ vq->free_head = 0;
+ for (i = 0; i < num-1; i++)
+ vq->vring.desc[i].next = i+1;
+
+ return &vq->vq;
+}
+
+void vring_del_virtqueue(struct virtqueue *vq)
+{
+ kfree(to_vvq(vq));
+}
+
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
index 6854fd6b971..9adbb4f9047 100644
--- a/drivers/w1/Kconfig
+++ b/drivers/w1/Kconfig
@@ -17,7 +17,8 @@ config W1_CON
bool "Userspace communication over connector"
default y
--- help ---
- This allows to communicate with userspace using connector [Documentation/connector].
+ This allows to communicate with userspace using connector. For more
+ information see <file:Documentation/connector/connector.txt>.
There are three types of messages between w1 core and userspace:
1. Events. They are generated each time new master or slave device found
either due to automatic or requested search.
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c
index 4b696641ce3..5747997f8d7 100644
--- a/drivers/w1/masters/ds1wm.c
+++ b/drivers/w1/masters/ds1wm.c
@@ -307,7 +307,7 @@ static void ds1wm_search(void *data, u8 search_type,
rom_id |= (unsigned long long) r << (i * 4);
}
- dev_dbg(&ds1wm_data->pdev->dev, "found 0x%08llX", rom_id);
+ dev_dbg(&ds1wm_data->pdev->dev, "found 0x%08llX\n", rom_id);
ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA);
ds1wm_reset(ds1wm_data);
diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c
index 299e274d241..b63b5e044a4 100644
--- a/drivers/w1/masters/ds2490.c
+++ b/drivers/w1/masters/ds2490.c
@@ -233,7 +233,7 @@ static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
{
int count, err;
- memset(st, 0, sizeof(st));
+ memset(st, 0, sizeof(*st));
count = 0;
err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_STATUS]), buf, size, &count, 100);
diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c
index d356da5709f..1550431ccb6 100644
--- a/drivers/w1/masters/matrox_w1.c
+++ b/drivers/w1/masters/matrox_w1.c
@@ -33,7 +33,6 @@
#include <linux/slab.h>
#include <linux/pci_ids.h>
#include <linux/pci.h>
-#include <linux/timer.h>
#include "../w1.h"
#include "../w1_int.h"
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index a593f900eff..070217322c9 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -197,7 +197,7 @@ static struct w1_family w1_default_family = {
.fops = &w1_default_fops,
};
-static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env);
static struct bus_type w1_bus_type = {
.name = "w1",
@@ -396,13 +396,12 @@ static void w1_destroy_master_attributes(struct w1_master *master)
}
#ifdef CONFIG_HOTPLUG
-static int w1_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct w1_master *md = NULL;
struct w1_slave *sl = NULL;
char *event_owner, *name;
- int err, cur_index=0, cur_len=0;
+ int err;
if (dev->driver == &w1_master_driver) {
md = container_of(dev, struct w1_master, dev);
@@ -423,23 +422,19 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp,
if (dev->driver != &w1_slave_driver || !sl)
return 0;
- err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
- &cur_len, "W1_FID=%02X", sl->reg_num.family);
+ err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family);
if (err)
return err;
- err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
- &cur_len, "W1_SLAVE_ID=%024LX",
- (unsigned long long)sl->reg_num.id);
- envp[cur_index] = NULL;
+ err = add_uevent_var(env, "W1_SLAVE_ID=%024LX",
+ (unsigned long long)sl->reg_num.id);
if (err)
return err;
return 0;
};
#else
-static int w1_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
{
return 0;
}
diff --git a/drivers/char/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 37bddc1802d..2792bc1a726 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -15,8 +15,8 @@ menuconfig WATCHDOG
implementation entirely in software (which can sometimes fail to
reboot the machine) and a driver for hardware watchdog boards, which
are more robust and can also keep track of the temperature inside
- your computer. For details, read <file:Documentation/watchdog/watchdog.txt>
- in the kernel source.
+ your computer. For details, read
+ <file:Documentation/watchdog/watchdog-api.txt> in the kernel source.
The watchdog is usually used together with the watchdog daemon
which is available from
@@ -343,11 +343,12 @@ config IBMASR
module will be called ibmasr.
config WAFER_WDT
- tristate "ICP Wafer 5823 Single Board Computer Watchdog"
+ tristate "ICP Single Board Computer Watchdog Timer"
depends on X86
help
- This is a driver for the hardware watchdog on the ICP Wafer 5823
- Single Board Computer (and probably other similar models).
+ This is a driver for the hardware watchdog on the ICP Single
+ Board Computer. This driver is working on (at least) the following
+ IPC SBC's: Wafer 5823, Rocky 4783, Rocky 3703 and Rocky 3782.
To compile this driver as a module, choose M here: the
module will be called wafer5823wdt.
@@ -609,6 +610,12 @@ config WDT_RM9K_GPI
To compile this driver as a module, choose M here: the
module will be called rm9k_wdt.
+config AR7_WDT
+ tristate "TI AR7 Watchdog Timer"
+ depends on AR7
+ help
+ Hardware driver for the TI AR7 Watchdog Timer.
+
# PARISC Architecture
# POWERPC Architecture
diff --git a/drivers/char/watchdog/Makefile b/drivers/watchdog/Makefile
index 389f8b14ccc..7d9e5734f8b 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -90,6 +90,7 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
obj-$(CONFIG_INDYDOG) += indydog.o
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
+obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
# PARISC Architecture
diff --git a/drivers/char/watchdog/acquirewdt.c b/drivers/watchdog/acquirewdt.c
index 85269c365a1..85269c365a1 100644
--- a/drivers/char/watchdog/acquirewdt.c
+++ b/drivers/watchdog/acquirewdt.c
diff --git a/drivers/char/watchdog/advantechwdt.c b/drivers/watchdog/advantechwdt.c
index 8121cc24734..8121cc24734 100644
--- a/drivers/char/watchdog/advantechwdt.c
+++ b/drivers/watchdog/advantechwdt.c
diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
index c404fc69e7e..b481cc0e32e 100644
--- a/drivers/char/watchdog/alim1535_wdt.c
+++ b/drivers/watchdog/alim1535_wdt.c
@@ -31,7 +31,7 @@ static unsigned long ali_is_open;
static char ali_expect_release;
static struct pci_dev *ali_pci;
static u32 ali_timeout_bits; /* stores the computed timeout */
-static spinlock_t ali_lock; /* Guards the hardware */
+static DEFINE_SPINLOCK(ali_lock); /* Guards the hardware */
/* module parameters */
static int timeout = WATCHDOG_TIMEOUT;
@@ -398,8 +398,6 @@ static int __init watchdog_init(void)
{
int ret;
- spin_lock_init(&ali_lock);
-
/* Check whether or not the hardware watchdog is there */
if (ali_find_watchdog() != 0) {
return -ENODEV;
diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
index 67aed9f8c36..67aed9f8c36 100644
--- a/drivers/char/watchdog/alim7101_wdt.c
+++ b/drivers/watchdog/alim7101_wdt.c
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
new file mode 100644
index 00000000000..cdaab8c3d3d
--- /dev/null
+++ b/drivers/watchdog/ar7_wdt.c
@@ -0,0 +1,349 @@
+/*
+ * drivers/watchdog/ar7_wdt.c
+ *
+ * Copyright (C) 2007 Nicolas Thill <nico@openwrt.org>
+ * Copyright (c) 2005 Enrik Berkhan <Enrik.Berkhan@akk.org>
+ *
+ * Some code taken from:
+ * National Semiconductor SCx200 Watchdog support
+ * Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <asm/addrspace.h>
+#include <asm/ar7/ar7.h>
+
+#define DRVNAME "ar7_wdt"
+#define LONGNAME "TI AR7 Watchdog Timer"
+
+MODULE_AUTHOR("Nicolas Thill <nico@openwrt.org>");
+MODULE_DESCRIPTION(LONGNAME);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+static int margin = 60;
+module_param(margin, int, 0);
+MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
+
+#define READ_REG(x) readl((void __iomem *)&(x))
+#define WRITE_REG(x, v) writel((v), (void __iomem *)&(x))
+
+struct ar7_wdt {
+ u32 kick_lock;
+ u32 kick;
+ u32 change_lock;
+ u32 change;
+ u32 disable_lock;
+ u32 disable;
+ u32 prescale_lock;
+ u32 prescale;
+};
+
+static struct semaphore open_semaphore;
+static unsigned expect_close;
+
+/* XXX currently fixed, allows max margin ~68.72 secs */
+#define prescale_value 0xffff
+
+/* Offset of the WDT registers */
+static unsigned long ar7_regs_wdt;
+/* Pointer to the remapped WDT IO space */
+static struct ar7_wdt *ar7_wdt;
+static void ar7_wdt_get_regs(void)
+{
+ u16 chip_id = ar7_chip_id();
+ switch (chip_id) {
+ case AR7_CHIP_7100:
+ case AR7_CHIP_7200:
+ ar7_regs_wdt = AR7_REGS_WDT;
+ break;
+ default:
+ ar7_regs_wdt = UR8_REGS_WDT;
+ break;
+ }
+}
+
+
+static void ar7_wdt_kick(u32 value)
+{
+ WRITE_REG(ar7_wdt->kick_lock, 0x5555);
+ if ((READ_REG(ar7_wdt->kick_lock) & 3) == 1) {
+ WRITE_REG(ar7_wdt->kick_lock, 0xaaaa);
+ if ((READ_REG(ar7_wdt->kick_lock) & 3) == 3) {
+ WRITE_REG(ar7_wdt->kick, value);
+ return;
+ }
+ }
+ printk(KERN_ERR DRVNAME ": failed to unlock WDT kick reg\n");
+}
+
+static void ar7_wdt_prescale(u32 value)
+{
+ WRITE_REG(ar7_wdt->prescale_lock, 0x5a5a);
+ if ((READ_REG(ar7_wdt->prescale_lock) & 3) == 1) {
+ WRITE_REG(ar7_wdt->prescale_lock, 0xa5a5);
+ if ((READ_REG(ar7_wdt->prescale_lock) & 3) == 3) {
+ WRITE_REG(ar7_wdt->prescale, value);
+ return;
+ }
+ }
+ printk(KERN_ERR DRVNAME ": failed to unlock WDT prescale reg\n");
+}
+
+static void ar7_wdt_change(u32 value)
+{
+ WRITE_REG(ar7_wdt->change_lock, 0x6666);
+ if ((READ_REG(ar7_wdt->change_lock) & 3) == 1) {
+ WRITE_REG(ar7_wdt->change_lock, 0xbbbb);
+ if ((READ_REG(ar7_wdt->change_lock) & 3) == 3) {
+ WRITE_REG(ar7_wdt->change, value);
+ return;
+ }
+ }
+ printk(KERN_ERR DRVNAME ": failed to unlock WDT change reg\n");
+}
+
+static void ar7_wdt_disable(u32 value)
+{
+ WRITE_REG(ar7_wdt->disable_lock, 0x7777);
+ if ((READ_REG(ar7_wdt->disable_lock) & 3) == 1) {
+ WRITE_REG(ar7_wdt->disable_lock, 0xcccc);
+ if ((READ_REG(ar7_wdt->disable_lock) & 3) == 2) {
+ WRITE_REG(ar7_wdt->disable_lock, 0xdddd);
+ if ((READ_REG(ar7_wdt->disable_lock) & 3) == 3) {
+ WRITE_REG(ar7_wdt->disable, value);
+ return;
+ }
+ }
+ }
+ printk(KERN_ERR DRVNAME ": failed to unlock WDT disable reg\n");
+}
+
+static void ar7_wdt_update_margin(int new_margin)
+{
+ u32 change;
+
+ change = new_margin * (ar7_vbus_freq() / prescale_value);
+ if (change < 1) change = 1;
+ if (change > 0xffff) change = 0xffff;
+ ar7_wdt_change(change);
+ margin = change * prescale_value / ar7_vbus_freq();
+ printk(KERN_INFO DRVNAME
+ ": timer margin %d seconds (prescale %d, change %d, freq %d)\n",
+ margin, prescale_value, change, ar7_vbus_freq());
+}
+
+static void ar7_wdt_enable_wdt(void)
+{
+ printk(KERN_DEBUG DRVNAME ": enabling watchdog timer\n");
+ ar7_wdt_disable(1);
+ ar7_wdt_kick(1);
+}
+
+static void ar7_wdt_disable_wdt(void)
+{
+ printk(KERN_DEBUG DRVNAME ": disabling watchdog timer\n");
+ ar7_wdt_disable(0);
+}
+
+static int ar7_wdt_open(struct inode *inode, struct file *file)
+{
+ /* only allow one at a time */
+ if (down_trylock(&open_semaphore))
+ return -EBUSY;
+ ar7_wdt_enable_wdt();
+ expect_close = 0;
+
+ return nonseekable_open(inode, file);
+}
+
+static int ar7_wdt_release(struct inode *inode, struct file *file)
+{
+ if (!expect_close)
+ printk(KERN_WARNING DRVNAME
+ ": watchdog device closed unexpectedly,"
+ "will not disable the watchdog timer\n");
+ else if (!nowayout)
+ ar7_wdt_disable_wdt();
+
+ up(&open_semaphore);
+
+ return 0;
+}
+
+static int ar7_wdt_notify_sys(struct notifier_block *this,
+ unsigned long code, void *unused)
+{
+ if (code == SYS_HALT || code == SYS_POWER_OFF)
+ if (!nowayout)
+ ar7_wdt_disable_wdt();
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block ar7_wdt_notifier = {
+ .notifier_call = ar7_wdt_notify_sys
+};
+
+static ssize_t ar7_wdt_write(struct file *file, const char *data,
+ size_t len, loff_t *ppos)
+{
+ /* check for a magic close character */
+ if (len) {
+ size_t i;
+
+ ar7_wdt_kick(1);
+
+ expect_close = 0;
+ for (i = 0; i < len; ++i) {
+ char c;
+ if (get_user(c, data+i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_close = 1;
+ }
+
+ }
+ return len;
+}
+
+static int ar7_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ static struct watchdog_info ident = {
+ .identity = LONGNAME,
+ .firmware_version = 1,
+ .options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING),
+ };
+ int new_margin;
+
+ switch (cmd) {
+ default:
+ return -ENOTTY;
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user((struct watchdog_info *)arg, &ident,
+ sizeof(ident)))
+ return -EFAULT;
+ return 0;
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ if (put_user(0, (int *)arg))
+ return -EFAULT;
+ return 0;
+ case WDIOC_KEEPALIVE:
+ ar7_wdt_kick(1);
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_margin, (int *)arg))
+ return -EFAULT;
+ if (new_margin < 1)
+ return -EINVAL;
+
+ ar7_wdt_update_margin(new_margin);
+ ar7_wdt_kick(1);
+
+ case WDIOC_GETTIMEOUT:
+ if (put_user(margin, (int *)arg))
+ return -EFAULT;
+ return 0;
+ }
+}
+
+static struct file_operations ar7_wdt_fops = {
+ .owner = THIS_MODULE,
+ .write = ar7_wdt_write,
+ .ioctl = ar7_wdt_ioctl,
+ .open = ar7_wdt_open,
+ .release = ar7_wdt_release,
+};
+
+static struct miscdevice ar7_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &ar7_wdt_fops,
+};
+
+static int __init ar7_wdt_init(void)
+{
+ int rc;
+
+ ar7_wdt_get_regs();
+
+ if (!request_mem_region(ar7_regs_wdt, sizeof(struct ar7_wdt),
+ LONGNAME)) {
+ printk(KERN_WARNING DRVNAME ": watchdog I/O region busy\n");
+ return -EBUSY;
+ }
+
+ ar7_wdt = (struct ar7_wdt *)
+ ioremap(ar7_regs_wdt, sizeof(struct ar7_wdt));
+
+ ar7_wdt_disable_wdt();
+ ar7_wdt_prescale(prescale_value);
+ ar7_wdt_update_margin(margin);
+
+ sema_init(&open_semaphore, 1);
+
+ rc = register_reboot_notifier(&ar7_wdt_notifier);
+ if (rc) {
+ printk(KERN_ERR DRVNAME
+ ": unable to register reboot notifier\n");
+ goto out_alloc;
+ }
+
+ rc = misc_register(&ar7_wdt_miscdev);
+ if (rc) {
+ printk(KERN_ERR DRVNAME ": unable to register misc device\n");
+ goto out_register;
+ }
+ goto out;
+
+out_register:
+ unregister_reboot_notifier(&ar7_wdt_notifier);
+out_alloc:
+ iounmap(ar7_wdt);
+ release_mem_region(ar7_regs_wdt, sizeof(struct ar7_wdt));
+out:
+ return rc;
+}
+
+static void __exit ar7_wdt_cleanup(void)
+{
+ misc_deregister(&ar7_wdt_miscdev);
+ unregister_reboot_notifier(&ar7_wdt_notifier);
+ iounmap(ar7_wdt);
+ release_mem_region(ar7_regs_wdt, sizeof(struct ar7_wdt));
+}
+
+module_init(ar7_wdt_init);
+module_exit(ar7_wdt_cleanup);
diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/watchdog/at32ap700x_wdt.c
index 54a516169d0..54a516169d0 100644
--- a/drivers/char/watchdog/at32ap700x_wdt.c
+++ b/drivers/watchdog/at32ap700x_wdt.c
diff --git a/drivers/char/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c
index 38bd3737259..a684b1e8737 100644
--- a/drivers/char/watchdog/at91rm9200_wdt.c
+++ b/drivers/watchdog/at91rm9200_wdt.c
@@ -9,6 +9,7 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
@@ -19,7 +20,6 @@
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/watchdog.h>
-#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/arch/at91_st.h>
diff --git a/drivers/char/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
index 309d27913fc..309d27913fc 100644
--- a/drivers/char/watchdog/bfin_wdt.c
+++ b/drivers/watchdog/bfin_wdt.c
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index d362f5bf658..d362f5bf658 100644
--- a/drivers/char/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c
index 5941ca601a3..5941ca601a3 100644
--- a/drivers/char/watchdog/cpu5wdt.c
+++ b/drivers/watchdog/cpu5wdt.c
diff --git a/drivers/char/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c
index 19db5302ba6..a61cbd48dc0 100644
--- a/drivers/char/watchdog/davinci_wdt.c
+++ b/drivers/watchdog/davinci_wdt.c
@@ -61,7 +61,7 @@
static int heartbeat = DEFAULT_HEARTBEAT;
-static spinlock_t io_lock;
+static DEFINE_SPINLOCK(io_lock);
static unsigned long wdt_status;
#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
@@ -200,8 +200,6 @@ static int davinci_wdt_probe(struct platform_device *pdev)
int ret = 0, size;
struct resource *res;
- spin_lock_init(&io_lock);
-
if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
heartbeat = DEFAULT_HEARTBEAT;
@@ -262,7 +260,7 @@ static int __init davinci_wdt_init(void)
static void __exit davinci_wdt_exit(void)
{
- return platform_driver_unregister(&platform_wdt_driver);
+ platform_driver_unregister(&platform_wdt_driver);
}
module_init(davinci_wdt_init);
diff --git a/drivers/char/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c
index 0e4787a0bb8..0e4787a0bb8 100644
--- a/drivers/char/watchdog/ep93xx_wdt.c
+++ b/drivers/watchdog/ep93xx_wdt.c
diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c
index b14e9d1f164..b14e9d1f164 100644
--- a/drivers/char/watchdog/eurotechwdt.c
+++ b/drivers/watchdog/eurotechwdt.c
diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c
index c5982502c03..ca44fd9b19b 100644
--- a/drivers/char/watchdog/i6300esb.c
+++ b/drivers/watchdog/i6300esb.c
@@ -2,7 +2,7 @@
* i6300esb: Watchdog timer driver for Intel 6300ESB chipset
*
* (c) Copyright 2004 Google Inc.
- * (c) Copyright 2005 David Härdeman <david@2gen.com>
+ * (c) Copyright 2005 David Härdeman <david@2gen.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -19,7 +19,7 @@
* Initial version 0.01
* 2004YYZZ Ross Biro
* Version 0.02
- * 20050210 David Härdeman <david@2gen.com>
+ * 20050210 David Härdeman <david@2gen.com>
* Ported driver to kernel 2.6
*/
@@ -77,7 +77,7 @@
/* internal variables */
static void __iomem *BASEADDR;
-static spinlock_t esb_lock; /* Guards the hardware */
+static DEFINE_SPINLOCK(esb_lock); /* Guards the hardware */
static unsigned long timer_alive;
static struct pci_dev *esb_pci;
static unsigned short triggered; /* The status of the watchdog upon boot */
@@ -456,8 +456,6 @@ static int __init watchdog_init (void)
{
int ret;
- spin_lock_init(&esb_lock);
-
/* Check whether or not the hardware watchdog is there */
if (!esb_getdevice () || esb_pci == NULL)
return -ENODEV;
@@ -521,7 +519,7 @@ static void __exit watchdog_cleanup (void)
module_init(watchdog_init);
module_exit(watchdog_cleanup);
-MODULE_AUTHOR("Ross Biro and David Härdeman");
+MODULE_AUTHOR("Ross Biro and David Härdeman");
MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/iTCO_vendor_support.c b/drivers/watchdog/iTCO_vendor_support.c
index 41508399009..cafc465f2ae 100644
--- a/drivers/char/watchdog/iTCO_vendor_support.c
+++ b/drivers/watchdog/iTCO_vendor_support.c
@@ -115,7 +115,7 @@ static void supermicro_old_pre_keepalive(unsigned long acpibase)
* For P4DPx:
* BIOS setup -> Advanced -> I/O Device Configuration -> Watch Dog
* This setting enables or disables Watchdog function. When enabled, the
- * default watchdog timer is set to be 5 minutes (about 4’35â€). It is
+ * default watchdog timer is set to be 5 minutes (about 4m35s). It is
* enough to load and run the OS. The application (service or driver) has
* to take over the control once OS is running up and before watchdog
* expires.
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index cd5a565bc3a..a0e6809e369 100644
--- a/drivers/char/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -35,10 +35,12 @@
* 82801GDH (ICH7DH) : document number 307013-002, 307014-009,
* 82801GBM (ICH7-M) : document number 307013-002, 307014-009,
* 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009,
- * 82801HB (ICH8) : document number 313056-002, 313057-004,
- * 82801HR (ICH8R) : document number 313056-002, 313057-004,
- * 82801HH (ICH8DH) : document number 313056-002, 313057-004,
- * 82801HO (ICH8DO) : document number 313056-002, 313057-004,
+ * 82801HB (ICH8) : document number 313056-003, 313057-009,
+ * 82801HR (ICH8R) : document number 313056-003, 313057-009,
+ * 82801HBM (ICH8M) : document number 313056-003, 313057-009,
+ * 82801HH (ICH8DH) : document number 313056-003, 313057-009,
+ * 82801HO (ICH8DO) : document number 313056-003, 313057-009,
+ * 82801HEM (ICH8M-E) : document number 313056-003, 313057-009,
* 82801IB (ICH9) : document number 316972-001, 316973-001,
* 82801IR (ICH9R) : document number 316972-001, 316973-001,
* 82801IH (ICH9DH) : document number 316972-001, 316973-001,
@@ -95,8 +97,10 @@ enum iTCO_chipsets {
TCO_ICH7M, /* ICH7-M */
TCO_ICH7MDH, /* ICH7-M DH */
TCO_ICH8, /* ICH8 & ICH8R */
+ TCO_ICH8ME, /* ICH8M-E */
TCO_ICH8DH, /* ICH8DH */
TCO_ICH8DO, /* ICH8DO */
+ TCO_ICH8M, /* ICH8M */
TCO_ICH9, /* ICH9 */
TCO_ICH9R, /* ICH9R */
TCO_ICH9DH, /* ICH9DH */
@@ -125,8 +129,10 @@ static struct {
{"ICH7-M", 2},
{"ICH7-M DH", 2},
{"ICH8 or ICH8R", 2},
+ {"ICH8M-E", 2},
{"ICH8DH", 2},
{"ICH8DO", 2},
+ {"ICH8M", 2},
{"ICH9", 2},
{"ICH9R", 2},
{"ICH9DH", 2},
@@ -134,6 +140,15 @@ static struct {
{NULL,0}
};
+#define ITCO_PCI_DEVICE(dev, data) \
+ .vendor = PCI_VENDOR_ID_INTEL, \
+ .device = dev, \
+ .subvendor = PCI_ANY_ID, \
+ .subdevice = PCI_ANY_ID, \
+ .class = 0, \
+ .class_mask = 0, \
+ .driver_data = data
+
/*
* This data only exists for exporting the supported PCI ids
* via MODULE_DEVICE_TABLE. We do not actually register a
@@ -141,45 +156,47 @@ static struct {
* functions that probably will be registered by other drivers.
*/
static struct pci_device_id iTCO_wdt_pci_tbl[] = {
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH0 },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2 },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2M },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3 },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3M },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4 },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4M },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_CICH },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH5 },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_6300ESB },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6 },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6M },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6W },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO },
- { PCI_VENDOR_ID_INTEL, 0x2918, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9 },
- { PCI_VENDOR_ID_INTEL, 0x2916, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9R },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9DH },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x2671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x2672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x2673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x2674, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x2675, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x2676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x2677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x2678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x2679, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x267a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x267b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x267c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x267d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x267e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
- { PCI_VENDOR_ID_INTEL, 0x267f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0, TCO_ICH )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0, TCO_ICH0 )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0, TCO_ICH2 )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10, TCO_ICH2M )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0, TCO_ICH3 )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12, TCO_ICH3M )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0, TCO_ICH4 )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12, TCO_ICH4M )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0, TCO_CICH )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0, TCO_ICH5 )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1, TCO_6300ESB)},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0, TCO_ICH6 )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1, TCO_ICH6M )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2, TCO_ICH6W )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0, TCO_ICH7 )},
+ { 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(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8 )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1, TCO_ICH8ME )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4, TCO_ICH8M )},
+ { ITCO_PCI_DEVICE(0x2918, TCO_ICH9 )},
+ { ITCO_PCI_DEVICE(0x2916, TCO_ICH9R )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2, TCO_ICH9DH )},
+ { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x2671, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x2672, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x2673, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x2674, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x2675, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x2676, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x2677, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x2678, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x2679, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x267a, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x267b, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x267c, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x267d, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x267e, TCO_631XESB)},
+ { ITCO_PCI_DEVICE(0x267f, TCO_631XESB)},
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl);
@@ -300,6 +317,7 @@ static int iTCO_wdt_start(void)
/* disable chipset's NO_REBOOT bit */
if (iTCO_wdt_unset_NO_REBOOT_bit()) {
+ spin_unlock(&iTCO_wdt_private.io_lock);
printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
return -EIO;
}
@@ -590,7 +608,7 @@ static struct miscdevice iTCO_wdt_miscdev = {
* Init & exit routines
*/
-static int iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent, struct platform_device *dev)
+static int __devinit iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent, struct platform_device *dev)
{
int ret;
u32 base_address;
@@ -694,7 +712,7 @@ out:
return ret;
}
-static void iTCO_wdt_cleanup(void)
+static void __devexit iTCO_wdt_cleanup(void)
{
/* Stop the timer before we leave */
if (!nowayout)
@@ -709,7 +727,7 @@ static void iTCO_wdt_cleanup(void)
iTCO_wdt_private.ACPIBASE = 0;
}
-static int iTCO_wdt_probe(struct platform_device *dev)
+static int __devinit iTCO_wdt_probe(struct platform_device *dev)
{
int found = 0;
struct pci_dev *pdev = NULL;
@@ -735,7 +753,7 @@ static int iTCO_wdt_probe(struct platform_device *dev)
return 0;
}
-static int iTCO_wdt_remove(struct platform_device *dev)
+static int __devexit iTCO_wdt_remove(struct platform_device *dev)
{
if (iTCO_wdt_private.ACPIBASE)
iTCO_wdt_cleanup();
@@ -753,7 +771,7 @@ static void iTCO_wdt_shutdown(struct platform_device *dev)
static struct platform_driver iTCO_wdt_driver = {
.probe = iTCO_wdt_probe,
- .remove = iTCO_wdt_remove,
+ .remove = __devexit_p(iTCO_wdt_remove),
.shutdown = iTCO_wdt_shutdown,
.suspend = iTCO_wdt_suspend,
.resume = iTCO_wdt_resume,
diff --git a/drivers/char/watchdog/ib700wdt.c b/drivers/watchdog/ib700wdt.c
index c3a60f52ccb..4b89f401691 100644
--- a/drivers/char/watchdog/ib700wdt.c
+++ b/drivers/watchdog/ib700wdt.c
@@ -48,7 +48,7 @@
static struct platform_device *ibwdt_platform_device;
static unsigned long ibwdt_is_open;
-static spinlock_t ibwdt_lock;
+static DEFINE_SPINLOCK(ibwdt_lock);
static char expect_close;
/* Module information */
@@ -308,8 +308,6 @@ static int __devinit ibwdt_probe(struct platform_device *dev)
{
int res;
- spin_lock_init(&ibwdt_lock);
-
#if WDT_START != WDT_STOP
if (!request_region(WDT_STOP, 1, "IB700 WDT")) {
printk (KERN_ERR PFX "STOP method I/O %X is not available.\n", WDT_STOP);
diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/watchdog/ibmasr.c
index 94155f6136c..94155f6136c 100644
--- a/drivers/char/watchdog/ibmasr.c
+++ b/drivers/watchdog/ibmasr.c
diff --git a/drivers/char/watchdog/indydog.c b/drivers/watchdog/indydog.c
index 788245bdaa7..788245bdaa7 100644
--- a/drivers/char/watchdog/indydog.c
+++ b/drivers/watchdog/indydog.c
diff --git a/drivers/char/watchdog/iop_wdt.c b/drivers/watchdog/iop_wdt.c
index bbbd91af754..bbbd91af754 100644
--- a/drivers/char/watchdog/iop_wdt.c
+++ b/drivers/watchdog/iop_wdt.c
diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/watchdog/ixp2000_wdt.c
index dc7548dcaf3..dc7548dcaf3 100644
--- a/drivers/char/watchdog/ixp2000_wdt.c
+++ b/drivers/watchdog/ixp2000_wdt.c
diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/watchdog/ixp4xx_wdt.c
index 5864bb865cf..5864bb865cf 100644
--- a/drivers/char/watchdog/ixp4xx_wdt.c
+++ b/drivers/watchdog/ixp4xx_wdt.c
diff --git a/drivers/char/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c
index 7150fb945ea..e3a29c30230 100644
--- a/drivers/char/watchdog/ks8695_wdt.c
+++ b/drivers/watchdog/ks8695_wdt.c
@@ -8,6 +8,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
@@ -18,7 +19,6 @@
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/watchdog.h>
-#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/arch/regs-timer.h>
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/watchdog/machzwd.c
index 6d35bb112a5..e6e07b4575e 100644
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/watchdog/machzwd.c
@@ -123,8 +123,8 @@ static void zf_ping(unsigned long data);
static int zf_action = GEN_RESET;
static unsigned long zf_is_open;
static char zf_expect_close;
-static spinlock_t zf_lock;
-static spinlock_t zf_port_lock;
+static DEFINE_SPINLOCK(zf_lock);
+static DEFINE_SPINLOCK(zf_port_lock);
static DEFINE_TIMER(zf_timer, zf_ping, 0, 0);
static unsigned long next_heartbeat = 0;
@@ -438,9 +438,6 @@ static int __init zf_init(void)
zf_show_action(action);
- spin_lock_init(&zf_lock);
- spin_lock_init(&zf_port_lock);
-
if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){
printk(KERN_ERR "cannot reserve I/O ports at %d\n",
ZF_IOBASE);
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/watchdog/mixcomwd.c
index 1adf1d56027..1adf1d56027 100644
--- a/drivers/char/watchdog/mixcomwd.c
+++ b/drivers/watchdog/mixcomwd.c
diff --git a/drivers/char/watchdog/mpc5200_wdt.c b/drivers/watchdog/mpc5200_wdt.c
index 564143d4061..11f6a111e75 100644
--- a/drivers/char/watchdog/mpc5200_wdt.c
+++ b/drivers/watchdog/mpc5200_wdt.c
@@ -81,7 +81,7 @@ static int mpc5200_wdt_stop(struct mpc5200_wdt *wdt)
/* file operations */
-static ssize_t mpc5200_wdt_write(struct file *file, const char *data,
+static ssize_t mpc5200_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
struct mpc5200_wdt *wdt = file->private_data;
@@ -176,6 +176,8 @@ static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *ma
has_wdt = of_get_property(op->node, "has-wdt", NULL);
if (!has_wdt)
+ has_wdt = of_get_property(op->node, "fsl,has-wdt", NULL);
+ if (!has_wdt)
return -ENODEV;
wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
@@ -254,6 +256,7 @@ static int mpc5200_wdt_shutdown(struct of_device *op)
static struct of_device_id mpc5200_wdt_match[] = {
{ .compatible = "mpc5200-gpt", },
+ { .compatible = "fsl,mpc5200-gpt", },
{},
};
static struct of_platform_driver mpc5200_wdt_driver = {
diff --git a/drivers/char/watchdog/mpc83xx_wdt.c b/drivers/watchdog/mpc83xx_wdt.c
index a0bf95fb976..6369f569517 100644
--- a/drivers/char/watchdog/mpc83xx_wdt.c
+++ b/drivers/watchdog/mpc83xx_wdt.c
@@ -56,7 +56,7 @@ static int prescale = 1;
static unsigned int timeout_sec;
static unsigned long wdt_is_open;
-static spinlock_t wdt_spinlock;
+static DEFINE_SPINLOCK(wdt_spinlock);
static void mpc83xx_wdt_keepalive(void)
{
@@ -185,9 +185,6 @@ static int __devinit mpc83xx_wdt_probe(struct platform_device *dev)
printk(KERN_INFO "WDT driver for MPC83xx initialized. "
"mode:%s timeout=%d (%d seconds)\n",
reset ? "reset":"interrupt", timeout, timeout_sec);
-
- spin_lock_init(&wdt_spinlock);
-
return 0;
err_unmap:
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/watchdog/mpc8xx_wdt.c
index 85b5734403a..85b5734403a 100644
--- a/drivers/char/watchdog/mpc8xx_wdt.c
+++ b/drivers/watchdog/mpc8xx_wdt.c
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c
index 0d2b2773541..0d2b2773541 100644
--- a/drivers/char/watchdog/mpcore_wdt.c
+++ b/drivers/watchdog/mpcore_wdt.c
diff --git a/drivers/char/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
index dcfd401a7ad..dcfd401a7ad 100644
--- a/drivers/char/watchdog/mtx-1_wdt.c
+++ b/drivers/watchdog/mtx-1_wdt.c
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/watchdog/mv64x60_wdt.c
index 0365c317f7e..0365c317f7e 100644
--- a/drivers/char/watchdog/mv64x60_wdt.c
+++ b/drivers/watchdog/mv64x60_wdt.c
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 719b066f73c..635ca454f56 100644
--- a/drivers/char/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -39,11 +39,11 @@
#include <linux/platform_device.h>
#include <linux/moduleparam.h>
#include <linux/clk.h>
+#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/hardware.h>
-#include <asm/bitops.h>
#include <asm/arch/prcm.h>
diff --git a/drivers/char/watchdog/omap_wdt.h b/drivers/watchdog/omap_wdt.h
index 52a532a5114..52a532a5114 100644
--- a/drivers/char/watchdog/omap_wdt.h
+++ b/drivers/watchdog/omap_wdt.h
diff --git a/drivers/char/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c
index 3d3deae0d64..15e4f8887a9 100644
--- a/drivers/char/watchdog/pc87413_wdt.c
+++ b/drivers/watchdog/pc87413_wdt.c
@@ -61,7 +61,7 @@ static unsigned long timer_enabled = 0; /* is the timer enabled? */
static char expect_close; /* is the close expected? */
-static spinlock_t io_lock; /* to guard the watchdog from io races */
+static DEFINE_SPINLOCK(io_lock);/* to guard the watchdog from io races */
static int nowayout = WATCHDOG_NOWAYOUT;
@@ -561,8 +561,6 @@ static int __init pc87413_init(void)
{
int ret;
- spin_lock_init(&io_lock);
-
printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n", WDT_INDEX_IO_PORT);
/* request_region(io, 2, "pc87413"); */
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/watchdog/pcwd.c
index 7b41434fac8..7b41434fac8 100644
--- a/drivers/char/watchdog/pcwd.c
+++ b/drivers/watchdog/pcwd.c
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c
index 61a89e95964..61a89e95964 100644
--- a/drivers/char/watchdog/pcwd_pci.c
+++ b/drivers/watchdog/pcwd_pci.c
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c
index 0f3fd6c9c35..0f3fd6c9c35 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/watchdog/pcwd_usb.c
diff --git a/drivers/char/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index 22f8873dd09..b04aa096a10 100644
--- a/drivers/char/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -80,7 +80,7 @@
static int nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = DEFAULT_HEARTBEAT;
-static spinlock_t io_lock;
+static DEFINE_SPINLOCK(io_lock);
static unsigned long wdt_status;
#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
@@ -254,8 +254,6 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
int ret = 0, size;
struct resource *res;
- spin_lock_init(&io_lock);
-
if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
heartbeat = DEFAULT_HEARTBEAT;
@@ -335,7 +333,7 @@ static int __init pnx4008_wdt_init(void)
static void __exit pnx4008_wdt_exit(void)
{
- return platform_driver_unregister(&platform_wdt_driver);
+ platform_driver_unregister(&platform_wdt_driver);
}
module_init(pnx4008_wdt_init);
diff --git a/drivers/char/watchdog/rm9k_wdt.c b/drivers/watchdog/rm9k_wdt.c
index 5c921e47156..5c921e47156 100644
--- a/drivers/char/watchdog/rm9k_wdt.c
+++ b/drivers/watchdog/rm9k_wdt.c
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 5d1c15f83d2..5d1c15f83d2 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/watchdog/sa1100_wdt.c
index 3475f47aaa4..34a2b3b8180 100644
--- a/drivers/char/watchdog/sa1100_wdt.c
+++ b/drivers/watchdog/sa1100_wdt.c
@@ -25,13 +25,13 @@
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/init.h>
+#include <linux/bitops.h>
#ifdef CONFIG_ARCH_PXA
#include <asm/arch/pxa-regs.h>
#endif
#include <asm/hardware.h>
-#include <asm/bitops.h>
#include <asm/uaccess.h>
#define OSCR_FREQ CLOCK_TICK_RATE
diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/watchdog/sbc60xxwdt.c
index e4f3cb6090b..e4f3cb6090b 100644
--- a/drivers/char/watchdog/sbc60xxwdt.c
+++ b/drivers/watchdog/sbc60xxwdt.c
diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/watchdog/sbc8360.c
index 285d8528953..2ee2677f364 100644
--- a/drivers/char/watchdog/sbc8360.c
+++ b/drivers/watchdog/sbc8360.c
@@ -54,7 +54,7 @@
#include <asm/system.h>
static unsigned long sbc8360_is_open;
-static spinlock_t sbc8360_lock;
+static DEFINE_SPINLOCK(sbc8360_lock);
static char expect_close;
#define PFX "sbc8360: "
@@ -359,7 +359,6 @@ static int __init sbc8360_init(void)
goto out_noreboot;
}
- spin_lock_init(&sbc8360_lock);
res = misc_register(&sbc8360_miscdev);
if (res) {
printk(KERN_ERR PFX "failed to register misc device\n");
diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/watchdog/sbc_epx_c3.c
index 82cbd8809a6..82cbd8809a6 100644
--- a/drivers/char/watchdog/sbc_epx_c3.c
+++ b/drivers/watchdog/sbc_epx_c3.c
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/watchdog/sc1200wdt.c
index 9670d47190d..32ccd7c89c7 100644
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/watchdog/sc1200wdt.c
@@ -74,7 +74,7 @@ static int io = -1;
static int io_len = 2; /* for non plug and play */
static struct semaphore open_sem;
static char expect_close;
-static spinlock_t sc1200wdt_lock; /* io port access serialisation */
+static DEFINE_SPINLOCK(sc1200wdt_lock); /* io port access serialisation */
#if defined CONFIG_PNP
static int isapnp = 1;
@@ -375,7 +375,6 @@ static int __init sc1200wdt_init(void)
printk("%s\n", banner);
- spin_lock_init(&sc1200wdt_lock);
sema_init(&open_sem, 1);
#if defined CONFIG_PNP
diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/watchdog/sc520_wdt.c
index e8594c64d1e..2847324a2be 100644
--- a/drivers/char/watchdog/sc520_wdt.c
+++ b/drivers/watchdog/sc520_wdt.c
@@ -125,7 +125,7 @@ static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
static unsigned long next_heartbeat;
static unsigned long wdt_is_open;
static char wdt_expect_close;
-static spinlock_t wdt_spinlock;
+static DEFINE_SPINLOCK(wdt_spinlock);
/*
* Whack the dog
@@ -383,8 +383,6 @@ static int __init sc520_wdt_init(void)
{
int rc = -EBUSY;
- spin_lock_init(&wdt_spinlock);
-
/* Check that the timeout value is within it's range ; if not reset to the default */
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/watchdog/scx200_wdt.c
index d4fd0fa2f17..d4fd0fa2f17 100644
--- a/drivers/char/watchdog/scx200_wdt.c
+++ b/drivers/watchdog/scx200_wdt.c
diff --git a/drivers/char/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index cecbedd473a..cecbedd473a 100644
--- a/drivers/char/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
diff --git a/drivers/char/watchdog/smsc37b787_wdt.c b/drivers/watchdog/smsc37b787_wdt.c
index d3cb0a76602..5d2b5ba6141 100644
--- a/drivers/char/watchdog/smsc37b787_wdt.c
+++ b/drivers/watchdog/smsc37b787_wdt.c
@@ -83,7 +83,7 @@ static unsigned long timer_enabled = 0; /* is the timer enabled? */
static char expect_close; /* is the close expected? */
-static spinlock_t io_lock; /* to guard the watchdog from io races */
+static DEFINE_SPINLOCK(io_lock);/* to guard the watchdog from io races */
static int nowayout = WATCHDOG_NOWAYOUT;
@@ -540,8 +540,6 @@ static int __init wb_smsc_wdt_init(void)
{
int ret;
- spin_lock_init(&io_lock);
-
printk("SMsC 37B787 watchdog component driver " VERSION " initialising...\n");
if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) {
diff --git a/drivers/char/watchdog/softdog.c b/drivers/watchdog/softdog.c
index 9c369490924..9c369490924 100644
--- a/drivers/char/watchdog/softdog.c
+++ b/drivers/watchdog/softdog.c
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index df33b3b5a53..386492821fc 100644
--- a/drivers/char/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -48,7 +48,7 @@
static unsigned long wdt_is_open;
static char expect_close;
-static spinlock_t io_lock;
+static DEFINE_SPINLOCK(io_lock);
/* You must set this - there is no sane way to probe for this board. */
static int wdt_io = 0x2E;
@@ -328,8 +328,6 @@ wdt_init(void)
{
int ret;
- spin_lock_init(&io_lock);
-
printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG Super I/O chip initialising.\n");
if (wdt_set_heartbeat(timeout)) {
diff --git a/drivers/char/watchdog/w83697hf_wdt.c b/drivers/watchdog/w83697hf_wdt.c
index d9e821d08de..c622a0e6c9a 100644
--- a/drivers/char/watchdog/w83697hf_wdt.c
+++ b/drivers/watchdog/w83697hf_wdt.c
@@ -8,7 +8,7 @@
* which is based on wdt.c.
* Original copyright messages:
*
- * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
+ * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
*
* (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
*
@@ -47,7 +47,7 @@
static unsigned long wdt_is_open;
static char expect_close;
-static spinlock_t io_lock;
+static DEFINE_SPINLOCK(io_lock);
/* You must set this - there is no sane way to probe for this board. */
static int wdt_io = 0x2e;
@@ -376,8 +376,6 @@ wdt_init(void)
{
int ret, i, found = 0;
- spin_lock_init(&io_lock);
-
printk (KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n");
if (wdt_io == 0) {
diff --git a/drivers/char/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c
index 3c88fe18f4f..bcc9d48955d 100644
--- a/drivers/char/watchdog/w83877f_wdt.c
+++ b/drivers/watchdog/w83877f_wdt.c
@@ -94,7 +94,7 @@ static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
static unsigned long next_heartbeat;
static unsigned long wdt_is_open;
static char wdt_expect_close;
-static spinlock_t wdt_spinlock;
+static DEFINE_SPINLOCK(wdt_spinlock);
/*
* Whack the dog
@@ -350,8 +350,6 @@ static int __init w83877f_wdt_init(void)
{
int rc = -EBUSY;
- spin_lock_init(&wdt_spinlock);
-
if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
{
timeout = WATCHDOG_TIMEOUT;
diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c
index 15796844289..b475529d247 100644
--- a/drivers/char/watchdog/w83977f_wdt.c
+++ b/drivers/watchdog/w83977f_wdt.c
@@ -50,7 +50,7 @@ static int timeoutW; /* timeout in watchdog counter units */
static unsigned long timer_alive;
static int testmode;
static char expect_close;
-static spinlock_t spinlock;
+static DEFINE_SPINLOCK(spinlock);
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (15..7635), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
@@ -476,8 +476,6 @@ static int __init w83977f_wdt_init(void)
printk(KERN_INFO PFX DRIVER_VERSION);
- spin_lock_init(&spinlock);
-
/*
* Check that the timeout value is within it's range ;
* if not reset to the default
diff --git a/drivers/char/watchdog/wafer5823wdt.c b/drivers/watchdog/wafer5823wdt.c
index 950905d3c39..9e368091f79 100644
--- a/drivers/char/watchdog/wafer5823wdt.c
+++ b/drivers/watchdog/wafer5823wdt.c
@@ -45,7 +45,7 @@
static unsigned long wafwdt_is_open;
static char expect_close;
-static spinlock_t wafwdt_lock;
+static DEFINE_SPINLOCK(wafwdt_lock);
/*
* You must set these - there is no sane way to probe for this board.
@@ -252,8 +252,6 @@ static int __init wafwdt_init(void)
printk(KERN_INFO "WDT driver for Wafer 5823 single board computer initialising.\n");
- spin_lock_init(&wafwdt_lock);
-
if (timeout < 1 || timeout > 255) {
timeout = WD_TIMO;
printk (KERN_INFO PFX "timeout value must be 1<=x<=255, using %d\n",
diff --git a/drivers/char/watchdog/wd501p.h b/drivers/watchdog/wd501p.h
index a4504f40394..a4504f40394 100644
--- a/drivers/char/watchdog/wd501p.h
+++ b/drivers/watchdog/wd501p.h
diff --git a/drivers/char/watchdog/wdrtas.c b/drivers/watchdog/wdrtas.c
index 1d64e277567..1d64e277567 100644
--- a/drivers/char/watchdog/wdrtas.c
+++ b/drivers/watchdog/wdrtas.c
diff --git a/drivers/char/watchdog/wdt.c b/drivers/watchdog/wdt.c
index 0a3de6a0244..53d0bb410df 100644
--- a/drivers/char/watchdog/wdt.c
+++ b/drivers/watchdog/wdt.c
@@ -253,7 +253,7 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
printk(KERN_CRIT "Possible fan fault.\n");
}
#endif /* CONFIG_WDT_501 */
- if (!(status & WDC_SR_WCCR))
+ if (!(status & WDC_SR_WCCR)) {
#ifdef SOFTWARE_REBOOT
#ifdef ONLY_TESTING
printk(KERN_CRIT "Would Reboot.\n");
@@ -264,6 +264,7 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id)
#else
printk(KERN_CRIT "Reset in 5ms.\n");
#endif
+ }
return IRQ_HANDLED;
}
diff --git a/drivers/char/watchdog/wdt285.c b/drivers/watchdog/wdt285.c
index e4cf661dc89..e4cf661dc89 100644
--- a/drivers/char/watchdog/wdt285.c
+++ b/drivers/watchdog/wdt285.c
diff --git a/drivers/char/watchdog/wdt977.c b/drivers/watchdog/wdt977.c
index 7d300ff7ab0..9b7f6b6edef 100644
--- a/drivers/char/watchdog/wdt977.c
+++ b/drivers/watchdog/wdt977.c
@@ -59,7 +59,7 @@ static int timeoutM; /* timeout in minutes */
static unsigned long timer_alive;
static int testmode;
static char expect_close;
-static spinlock_t spinlock;
+static DEFINE_SPINLOCK(spinlock);
module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
@@ -448,8 +448,6 @@ static int __init wd977_init(void)
printk(KERN_INFO PFX DRIVER_VERSION);
- spin_lock_init(&spinlock);
-
/* Check that the timeout value is within it's range ; if not reset to the default */
if (wdt977_set_timeout(timeout))
{
diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index 6baf4ae42c9..1355608683e 100644
--- a/drivers/char/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -74,7 +74,7 @@
static int dev_count;
static struct semaphore open_sem;
-static spinlock_t wdtpci_lock;
+static DEFINE_SPINLOCK(wdtpci_lock);
static char expect_close;
static int io;
@@ -298,7 +298,7 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
printk(KERN_CRIT PFX "Possible fan fault.\n");
}
#endif /* CONFIG_WDT_501_PCI */
- if (!(status&WDC_SR_WCCR))
+ if (!(status&WDC_SR_WCCR)) {
#ifdef SOFTWARE_REBOOT
#ifdef ONLY_TESTING
printk(KERN_CRIT PFX "Would Reboot.\n");
@@ -309,6 +309,7 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
#else
printk(KERN_CRIT PFX "Reset in 5ms.\n");
#endif
+ }
return IRQ_HANDLED;
}
@@ -606,7 +607,6 @@ static int __devinit wdtpci_init_one (struct pci_dev *dev,
}
sema_init(&open_sem, 1);
- spin_lock_init(&wdtpci_lock);
irq = dev->irq;
io = pci_resource_start (dev, 2);
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 0b769f7c4a4..4750de316ad 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -185,13 +185,14 @@ static void otherend_changed(struct xenbus_watch *watch,
if (!dev->otherend ||
strncmp(dev->otherend, vec[XS_WATCH_PATH],
strlen(dev->otherend))) {
- dev_dbg(&dev->dev, "Ignoring watch at %s", vec[XS_WATCH_PATH]);
+ dev_dbg(&dev->dev, "Ignoring watch at %s\n",
+ vec[XS_WATCH_PATH]);
return;
}
state = xenbus_read_driver_state(dev->otherend);
- dev_dbg(&dev->dev, "state is %d, (%s), %s, %s",
+ dev_dbg(&dev->dev, "state is %d, (%s), %s, %s\n",
state, xenbus_strstate(state), dev->otherend_watch.node,
vec[XS_WATCH_PATH]);
diff --git a/drivers/zorro/zorro.ids b/drivers/zorro/zorro.ids
index 5bd4b05d4c4..560fef2a7b1 100644
--- a/drivers/zorro/zorro.ids
+++ b/drivers/zorro/zorro.ids
@@ -295,7 +295,7 @@
0100 RH 800C [HD Controller]
0200 RH 800C [RAM Expansion]
0861 Kato
-# The Rainbow II and III are actually made by Ingenieurbüro Helfrich
+# The Rainbow II and III are actually made by Ingenieurbüro Helfrich
2000 Rainbow II [Graphics Card]
2100 Rainbow III [Graphics Card]
8000 Melody MPEG [Audio Card]